From 611498e8d277d6e15613b611bf81dad46c4aecb7 Mon Sep 17 00:00:00 2001 From: Martin Fuchs Date: Sun, 31 Jul 2005 12:11:56 +0000 Subject: [PATCH] set svn:eol-style to native svn path=/trunk/; revision=16920 --- reactos/apps/utils/binpatch/patch.c | 1230 +- reactos/apps/utils/net/tracert/tracert.c | 1312 +- reactos/apps/utils/net/tracert/tracert.h | 160 +- reactos/apps/utils/winetest/port.h | 938 +- reactos/apps/utils/winetest/resource.h | 106 +- reactos/apps/utils/winetest/util.c | 236 +- reactos/apps/utils/winetest/winetest.h | 122 +- reactos/drivers/fs/vfat/fastio.c | 798 +- .../drivers/usb/miniport/usbehci/usbehci.c | 82 +- .../drivers/usb/miniport/usbehci/usbehci.h | 88 +- .../drivers/usb/miniport/usbohci/usbohci.c | 82 +- .../drivers/usb/miniport/usbohci/usbohci.h | 88 +- .../drivers/usb/miniport/usbuhci/usbuhci.c | 86 +- .../drivers/usb/miniport/usbuhci/usbuhci.h | 76 +- reactos/drivers/usb/usbd/test.c | 66 +- reactos/drivers/usb/usbd/usbd.c | 918 +- reactos/drivers/usb/usbhub/usbhub.c | 76 +- reactos/drivers/usb/usbhub/usbhub.h | 20 +- reactos/drivers/usb/usbport/usbport.h | 260 +- reactos/drivers/video/videoprt/agp.c | 1132 +- reactos/drivers/video/videoprt/ddc.c | 454 +- reactos/hal/halx86/include/ioapic.h | 202 +- reactos/hal/halx86/mp/ioapic.c | 1400 +- reactos/hal/halx86/mp/mpconfig.c | 1286 +- reactos/include/ccros.h | 36 +- reactos/include/drivers/diskdump/diskdump.h | 62 +- reactos/include/libs/fslib/vfatxlib.h | 48 +- reactos/include/libs/pseh/native.h | 484 +- reactos/include/libs/pseh/prettybased.h | 598 +- reactos/include/ndk/arch/ketypes.h | 54 +- reactos/include/ndk/arch/mmtypes.h | 36 +- reactos/include/ndk/asm.h | 388 +- reactos/include/ndk/i386/floatsave.h | 22 +- reactos/include/ndk/i386/ketypes.h | 1030 +- reactos/include/ndk/i386/mmtypes.h | 24 +- reactos/include/ndk/i386/segment.h | 28 +- reactos/include/ndk/sysguid.h | 110 +- reactos/include/ndk/umtypes.h | 2860 +- reactos/include/ndk/zwfuncs.h | 8106 ++--- reactos/include/reactos/helper.h | 236 +- reactos/include/services/services.h | 48 +- reactos/include/subsys/lsass/lsasrv.h | 16 +- reactos/include/wine/list.h | 330 +- reactos/lib/cabinet/cabextract.c | 5308 +-- reactos/lib/cabinet/cabinet.h | 1280 +- reactos/lib/cabinet/cabinet_main.c | 270 +- reactos/lib/cabinet/fci.c | 5328 +-- reactos/lib/cabinet/fdi.c | 5678 ++-- reactos/lib/comctl32/animate.c | 1954 +- reactos/lib/comctl32/comboex.c | 4596 +-- reactos/lib/comctl32/comctl32.h | 504 +- reactos/lib/comctl32/comctl32undoc.c | 5146 +-- reactos/lib/comctl32/commctrl.c | 3016 +- reactos/lib/comctl32/datetime.c | 2696 +- reactos/lib/comctl32/draglist.c | 682 +- reactos/lib/comctl32/flatsb.c | 580 +- reactos/lib/comctl32/header.c | 3698 +-- reactos/lib/comctl32/hotkey.c | 1122 +- reactos/lib/comctl32/imagelist.c | 5724 ++-- reactos/lib/comctl32/imagelist.h | 156 +- reactos/lib/comctl32/ipaddress.c | 1226 +- reactos/lib/comctl32/listview.c | 19332 +++++------ reactos/lib/comctl32/monthcal.c | 4048 +-- reactos/lib/comctl32/nativefont.c | 268 +- reactos/lib/comctl32/pager.c | 2764 +- reactos/lib/comctl32/progress.c | 1362 +- reactos/lib/comctl32/propsheet.c | 7444 ++--- reactos/lib/comctl32/rebar.c | 9486 +++--- reactos/lib/comctl32/smoothscroll.c | 262 +- reactos/lib/comctl32/status.c | 2620 +- reactos/lib/comctl32/string.c | 1702 +- reactos/lib/comctl32/syslink.c | 3380 +- reactos/lib/comctl32/tab.c | 6448 ++-- reactos/lib/comctl32/toolbar.c | 14732 ++++----- reactos/lib/comctl32/tooltips.c | 5678 ++-- reactos/lib/comctl32/trackbar.c | 3654 +- reactos/lib/comctl32/treeview.c | 11480 +++---- reactos/lib/comctl32/updown.c | 2030 +- reactos/lib/comdlg32/cdlg.h | 464 +- reactos/lib/comdlg32/cdlg16.h | 310 +- reactos/lib/comdlg32/cdlg32.c | 364 +- reactos/lib/comdlg32/colordlg.c | 2686 +- reactos/lib/comdlg32/colordlg16.c | 952 +- reactos/lib/comdlg32/filedlg.c | 7652 ++--- reactos/lib/comdlg32/filedlg16.c | 1030 +- reactos/lib/comdlg32/filedlg31.c | 1864 +- reactos/lib/comdlg32/filedlg31.h | 136 +- reactos/lib/comdlg32/filedlgbrowser.c | 2014 +- reactos/lib/comdlg32/filedlgbrowser.h | 330 +- reactos/lib/comdlg32/filetitle.c | 228 +- reactos/lib/comdlg32/finddlg.c | 992 +- reactos/lib/comdlg32/finddlg32.c | 1114 +- reactos/lib/comdlg32/fontdlg.c | 2434 +- reactos/lib/comdlg32/fontdlg16.c | 746 +- reactos/lib/comdlg32/printdlg.c | 6320 ++-- reactos/lib/comdlg32/printdlg.h | 204 +- reactos/lib/comdlg32/printdlg16.c | 1188 +- reactos/lib/cpl/liccpa/liccpa.c | 254 +- reactos/lib/cpl/liccpa/liccpa.h | 32 +- reactos/lib/cpl/liccpa/resource.h | 36 +- reactos/lib/crt/include/internal/math.h | 20 +- reactos/lib/crt/include/internal/mbstring.h | 40 +- reactos/lib/crt/precomp.h | 2 +- reactos/lib/crt/process/wprocess.c | 8 +- reactos/lib/crt/signal/xcptinfo.c | 18 +- reactos/lib/crt/stdio/fputws.c | 10 +- reactos/lib/crt/stdio/fwprintf.c | 8 +- reactos/lib/crt/stdio/putwchar.c | 8 +- reactos/lib/crt/stdio/swprintf.c | 120 +- reactos/lib/crt/stdio/ungetwc.c | 8 +- reactos/lib/crt/stdio/vswprintf.c | 8 +- reactos/lib/crt/stdio/vwprintf.c | 10 +- reactos/lib/crt/stdio/wfopen.c | 8 +- reactos/lib/crt/stdio/wfreopen.c | 12 +- reactos/lib/crt/stdio/wfsopen.c | 10 +- reactos/lib/crt/stdio/wpopen.c | 10 +- reactos/lib/crt/stdio/wprintf.c | 10 +- reactos/lib/crt/stdio/wremove.c | 8 +- reactos/lib/crt/stdlib/wtol.c | 12 +- reactos/lib/crt/sys_stat/systime.c | 140 +- reactos/lib/crt/wine/scanf.c | 422 +- reactos/lib/crt/wine/scanf.h | 1120 +- reactos/lib/crtdll/dllmain.c | 594 +- reactos/lib/ddraw/ddraw_hal.c | 684 +- reactos/lib/ddraw/ddraw_private.h | 964 +- reactos/lib/ddraw/ddraw_user.c | 4 +- reactos/lib/ddraw/rosddraw.h | 70 +- reactos/lib/dinput/data_formats.c | 604 +- reactos/lib/dinput/device.c | 1768 +- reactos/lib/dinput/device_private.h | 472 +- reactos/lib/dinput/dinput_main.c | 1512 +- reactos/lib/dinput/dinput_private.h | 116 +- reactos/lib/dinput/joystick_linux.c | 3400 +- reactos/lib/dinput/joystick_linuxinput.c | 2198 +- reactos/lib/dinput/keyboard.c | 1716 +- reactos/lib/dinput/mouse.c | 2594 +- reactos/lib/dinput/regsvr.c | 1116 +- reactos/lib/dinput8/dinput8_main.c | 166 +- .../lib/freetype/include/freetype/ftbitmap.h | 412 +- .../lib/freetype/include/freetype/ftotval.h | 340 +- .../include/freetype/internal/ftvalid.h | 296 +- .../freetype/internal/services/svotval.h | 106 +- reactos/lib/freetype/src/autofit/afangles.h | 14 +- reactos/lib/freetype/src/autofit/aferrors.h | 80 +- reactos/lib/freetype/src/base/ftbitmap.c | 1232 +- reactos/lib/freetype/src/base/ftotval.c | 144 +- reactos/lib/freetype/src/otvalid/otvalid.c | 60 +- reactos/lib/freetype/src/otvalid/otvalid.h | 144 +- reactos/lib/freetype/src/otvalid/otvbase.c | 636 +- reactos/lib/freetype/src/otvalid/otvcommn.c | 2110 +- reactos/lib/freetype/src/otvalid/otvcommn.h | 884 +- reactos/lib/freetype/src/otvalid/otverror.h | 86 +- reactos/lib/freetype/src/otvalid/otvgdef.c | 438 +- reactos/lib/freetype/src/otvalid/otvgpos.c | 2026 +- reactos/lib/freetype/src/otvalid/otvgpos.h | 72 +- reactos/lib/freetype/src/otvalid/otvgsub.c | 1168 +- reactos/lib/freetype/src/otvalid/otvjstf.c | 516 +- reactos/lib/freetype/src/otvalid/otvmod.c | 476 +- reactos/lib/freetype/src/otvalid/otvmod.h | 78 +- reactos/lib/freetype/src/raster/ftmisc.h | 166 +- reactos/lib/freetype/src/sfnt/ttcmap.c | 4428 +-- reactos/lib/freetype/src/sfnt/ttcmap.h | 162 +- reactos/lib/freetype/src/sfnt/ttkern.c | 982 +- reactos/lib/freetype/src/sfnt/ttkern.h | 112 +- reactos/lib/freetype/src/sfnt/ttsbit0.c | 1934 +- reactos/lib/freetype/src/sfnt/ttsbit0.h | 14 +- reactos/lib/fslib/vfatxlib/fatx.c | 854 +- reactos/lib/fslib/vfatxlib/vfatxlib.c | 386 +- reactos/lib/fslib/vfatxlib/vfatxlib.h | 88 +- reactos/lib/gdi32/objects/bitmap.c | 118 +- reactos/lib/gdi32/objects/brush.c | 254 +- reactos/lib/gdi32/objects/utils.c | 770 +- reactos/lib/icmp/icmp_main.c | 1028 +- reactos/lib/icmp/ip.h | 390 +- reactos/lib/icmp/ip_icmp.h | 372 +- reactos/lib/intrlck/intrlck.c | 418 +- reactos/lib/kbdes/kbdes.c | 1078 +- reactos/lib/kbdru/kbdru.c | 812 +- reactos/lib/lsasrv/lsaport.c | 356 +- reactos/lib/lsasrv/lsasrv.c | 48 +- reactos/lib/mpr/auth.c | 190 +- reactos/lib/mpr/mpr_main.c | 200 +- reactos/lib/mpr/mprres.h | 64 +- reactos/lib/mpr/multinet.c | 162 +- reactos/lib/mpr/nps.c | 426 +- reactos/lib/mpr/pwcache.c | 638 +- reactos/lib/mpr/wnet.c | 4076 +-- reactos/lib/mpr/wnetpriv.h | 54 +- reactos/lib/msi/cond.tab.c | 4062 +-- reactos/lib/msi/create.c | 498 +- reactos/lib/msi/distinct.c | 584 +- reactos/lib/msi/handle.c | 518 +- reactos/lib/msi/insert.c | 584 +- reactos/lib/msi/msi.c | 3444 +- reactos/lib/msi/msipriv.h | 846 +- reactos/lib/msi/msiquery.c | 1416 +- reactos/lib/msi/order.c | 676 +- reactos/lib/msi/package.c | 1804 +- reactos/lib/msi/query.h | 276 +- reactos/lib/msi/record.c | 1526 +- reactos/lib/msi/regsvr.c | 1248 +- reactos/lib/msi/select.c | 582 +- reactos/lib/msi/sql.tab.c | 4296 +-- reactos/lib/msi/string.c | 916 +- reactos/lib/msi/suminfo.c | 1506 +- reactos/lib/msi/table.c | 2834 +- reactos/lib/msi/tokenize.c | 800 +- reactos/lib/msi/update.c | 478 +- reactos/lib/msi/where.c | 962 +- reactos/lib/ntdll/rtl/secobj.c | 194 +- reactos/lib/ntdll/stdio/scanf.h | 1120 +- reactos/lib/ole32/antimoniker.c | 1224 +- reactos/lib/ole32/bindctx.c | 1150 +- reactos/lib/ole32/clipboard.c | 3580 +- reactos/lib/ole32/compobj.c | 5374 +-- reactos/lib/ole32/compobj_private.h | 518 +- reactos/lib/ole32/compositemoniker.c | 3396 +- reactos/lib/ole32/datacache.c | 3604 +- reactos/lib/ole32/dcom.h | 1030 +- reactos/lib/ole32/defaulthandler.c | 3364 +- reactos/lib/ole32/errorinfo.c | 1040 +- reactos/lib/ole32/filemoniker.c | 2860 +- reactos/lib/ole32/ftmarshal.c | 492 +- reactos/lib/ole32/git.c | 814 +- reactos/lib/ole32/hglobalstream.c | 1514 +- reactos/lib/ole32/ifs.c | 1398 +- reactos/lib/ole32/ifs.h | 300 +- reactos/lib/ole32/itemmoniker.c | 2186 +- reactos/lib/ole32/marshal.c | 3300 +- reactos/lib/ole32/memlockbytes.c | 1238 +- reactos/lib/ole32/memlockbytes16.c | 1156 +- reactos/lib/ole32/moniker.c | 2290 +- reactos/lib/ole32/moniker.h | 34 +- reactos/lib/ole32/ole16.c | 1026 +- reactos/lib/ole32/ole2.c | 5506 +-- reactos/lib/ole32/ole2_16.c | 308 +- reactos/lib/ole32/ole2impl.c | 606 +- reactos/lib/ole32/ole2nls.c | 272 +- reactos/lib/ole32/ole2stubs.c | 332 +- reactos/lib/ole32/ole32_main.c | 220 +- reactos/lib/ole32/oleobj.c | 1412 +- reactos/lib/ole32/oleproxy.c | 1986 +- reactos/lib/ole32/olestd.h | 112 +- reactos/lib/ole32/regsvr.c | 996 +- reactos/lib/ole32/rpc.c | 1768 +- reactos/lib/ole32/stg_bigblockfile.c | 1752 +- reactos/lib/ole32/stg_stream.c | 1800 +- reactos/lib/ole32/storage.c | 4062 +-- reactos/lib/ole32/storage32.c | 15314 ++++----- reactos/lib/ole32/storage32.h | 1390 +- reactos/lib/ole32/stubmanager.c | 1484 +- reactos/lib/oleaut32/connpt.c | 1256 +- reactos/lib/oleaut32/connpt.h | 48 +- reactos/lib/oleaut32/cursoricon.h | 178 +- reactos/lib/oleaut32/dispatch.c | 914 +- reactos/lib/oleaut32/hash.c | 1288 +- reactos/lib/oleaut32/oaidl_p.c | 27562 ++++++++-------- reactos/lib/oleaut32/ole2disp.c | 498 +- reactos/lib/oleaut32/ole2disp.h | 84 +- reactos/lib/oleaut32/oleaut.c | 1464 +- reactos/lib/oleaut32/olefont.c | 4298 +-- reactos/lib/oleaut32/olepicture.c | 4478 +-- reactos/lib/oleaut32/regsvr.c | 1862 +- reactos/lib/oleaut32/resource.h | 92 +- reactos/lib/oleaut32/safearray.c | 3468 +- reactos/lib/oleaut32/stubs.c | 132 +- reactos/lib/oleaut32/tmarshal.c | 4544 +-- reactos/lib/oleaut32/tmarshal.h | 48 +- reactos/lib/oleaut32/typelib.c | 11936 +++---- reactos/lib/oleaut32/typelib.h | 1200 +- reactos/lib/oleaut32/typelib16.c | 358 +- reactos/lib/oleaut32/typelib2.c | 7826 ++--- reactos/lib/oleaut32/usrmarshal.c | 2362 +- reactos/lib/oleaut32/varformat.c | 4814 +-- reactos/lib/oleaut32/variant.c | 9122 ++--- reactos/lib/oleaut32/variant.h | 870 +- reactos/lib/oleaut32/vartype.c | 13116 ++++---- reactos/lib/oledlg/insobjdlg.c | 1256 +- reactos/lib/oledlg/oledlg_main.c | 618 +- reactos/lib/oledlg/resource.h | 80 +- reactos/lib/olepro32/olepro32stubs.c | 136 +- reactos/lib/richedit/richedit.c | 212 +- reactos/lib/rpcrt4/cproxy.c | 684 +- reactos/lib/rpcrt4/cpsf.c | 526 +- reactos/lib/rpcrt4/cpsf.h | 88 +- reactos/lib/rpcrt4/cstub.c | 338 +- reactos/lib/rpcrt4/ndr_marshall.c | 4302 +-- reactos/lib/rpcrt4/ndr_midl.c | 592 +- reactos/lib/rpcrt4/ndr_misc.h | 106 +- reactos/lib/rpcrt4/ndr_ole.c | 700 +- reactos/lib/rpcrt4/ndr_stubless.c | 212 +- reactos/lib/rpcrt4/rpc_binding.c | 2310 +- reactos/lib/rpcrt4/rpc_binding.h | 172 +- reactos/lib/rpcrt4/rpc_defs.h | 366 +- reactos/lib/rpcrt4/rpc_epmap.c | 494 +- reactos/lib/rpcrt4/rpc_message.c | 1310 +- reactos/lib/rpcrt4/rpc_message.h | 76 +- reactos/lib/rpcrt4/rpc_misc.h | 56 +- reactos/lib/rpcrt4/rpc_server.c | 2122 +- reactos/lib/rpcrt4/rpc_server.h | 94 +- reactos/lib/rpcrt4/rpcrt4_main.c | 1642 +- reactos/lib/rpcrt4/rpcss_np_client.c | 310 +- reactos/lib/rpcrt4/rpcss_np_client.h | 52 +- reactos/lib/rtl/qsort.c | 532 +- reactos/lib/setupapi/rpc_private.h | 62 +- reactos/lib/shdocvw/classinfo.c | 332 +- reactos/lib/shdocvw/events.c | 416 +- reactos/lib/shdocvw/factory.c | 234 +- reactos/lib/shdocvw/misc.c | 198 +- reactos/lib/shdocvw/oleobject.c | 1216 +- reactos/lib/shdocvw/persist.c | 388 +- reactos/lib/shdocvw/regsvr.c | 1102 +- reactos/lib/shdocvw/shdocvw.h | 400 +- reactos/lib/shdocvw/shdocvw_main.c | 1152 +- reactos/lib/shdocvw/webbrowser.c | 556 +- reactos/lib/shell32/authors.c | 2 +- reactos/lib/shlwapi/assoc.c | 1412 +- reactos/lib/shlwapi/clist.c | 910 +- reactos/lib/shlwapi/istream.c | 1344 +- reactos/lib/shlwapi/msgbox.c | 592 +- reactos/lib/shlwapi/ordinal.c | 8592 ++--- reactos/lib/shlwapi/path.c | 8276 ++--- reactos/lib/shlwapi/reg.c | 4876 +-- reactos/lib/shlwapi/regstream.c | 1096 +- reactos/lib/shlwapi/resource.h | 58 +- reactos/lib/shlwapi/shlwapi_main.c | 260 +- reactos/lib/shlwapi/stopwatch.c | 452 +- reactos/lib/shlwapi/string.c | 5402 +-- reactos/lib/shlwapi/thread.c | 964 +- reactos/lib/shlwapi/url.c | 4670 +-- reactos/lib/shlwapi/wsprintf.c | 1062 +- reactos/lib/smdll/query.c | 212 +- reactos/lib/string/strpbrk.c | 108 +- reactos/lib/urlmon/regsvr.c | 1106 +- reactos/lib/urlmon/sec_mgr.c | 962 +- reactos/lib/urlmon/umon.c | 3474 +- reactos/lib/urlmon/urlmon_main.c | 714 +- reactos/lib/urlmon/urlmon_main.h | 106 +- reactos/lib/wdmguid/wdmguid.c | 20 +- reactos/lib/winmm/driver.c | 1146 +- reactos/lib/winmm/joystick.c | 630 +- reactos/lib/winmm/lolvldrv.c | 1684 +- reactos/lib/winmm/mci.c | 4838 +-- reactos/lib/winmm/message16.c | 7056 ++-- reactos/lib/winmm/midimap/midimap.c | 1130 +- reactos/lib/winmm/mmio.c | 2774 +- reactos/lib/winmm/mmsystem.c | 6432 ++-- reactos/lib/winmm/playsound.c | 1052 +- reactos/lib/winmm/sound16.c | 368 +- reactos/lib/winmm/time.c | 950 +- reactos/lib/winmm/wavemap/wavemap.c | 2452 +- reactos/lib/winmm/winemm.h | 634 +- reactos/lib/winmm/winemm16.h | 118 +- reactos/lib/winmm/winmm.c | 5692 ++-- reactos/lib/winsta/main.c | 100 +- reactos/lib/winsta/misc.c | 24 +- reactos/lib/winsta/server.c | 42 +- reactos/lib/winsta/winsta.h | 14 +- reactos/lib/winsta/ws.c | 160 +- reactos/ntoskrnl/mm/process.c | 1092 +- reactos/ntoskrnl/ps/notify.c | 4 +- reactos/services/umpnpmgr/umpnpmgr.c | 876 +- reactos/subsys/ntvdm/resource.h | 12 +- reactos/subsys/system/expand/resource.h | 16 +- reactos/subsys/system/ibrowser/ibrowser.cpp | 1100 +- reactos/subsys/system/ibrowser/ibrowser.h | 462 +- .../subsys/system/ibrowser/ibrowser_intres.h | 104 +- .../subsys/system/ibrowser/utility/comutil.h | 642 +- reactos/subsys/system/regsvr32/resource.h | 26 +- .../subsys/system/reporterror/reporterror.c | 1250 +- .../subsys/system/reporterror/reporterror.h | 112 +- reactos/subsys/system/rundll32/resource.h | 14 +- reactos/subsys/system/services/rpcserver.c | 1386 +- reactos/subsys/system/sm/resource.h | 54 +- reactos/subsys/system/sm/sm.c | 610 +- reactos/subsys/system/userinit/resource.h | 24 +- reactos/subsys/win32k/eng/window.c | 756 +- reactos/tools/tools-check.c | 64 +- reactos/tools/widl/client.c | 3914 +-- reactos/tools/widl/lex.yy.c | 9452 +++--- reactos/tools/widl/port/mkstemps.c | 276 +- reactos/tools/widl/server.c | 4184 +-- reactos/tools/widl/winglue.h | 458 +- reactos/tools/widl/y.tab.c | 7958 ++--- reactos/tools/widl/y.tab.h | 618 +- reactos/w32api/include/ddk/kbdmou.h | 182 +- reactos/w32api/include/ddk/ntnls.h | 104 +- reactos/w32api/include/evntrace.h | 86 +- reactos/w32api/include/winnls32.h | 148 +- 389 files changed, 308607 insertions(+), 308607 deletions(-) diff --git a/reactos/apps/utils/binpatch/patch.c b/reactos/apps/utils/binpatch/patch.c index 93ae7488501..902ac5b622d 100644 --- a/reactos/apps/utils/binpatch/patch.c +++ b/reactos/apps/utils/binpatch/patch.c @@ -1,615 +1,615 @@ -#include -#include -#include -#include -#include -#include - -/** DEFINES *******************************************************************/ - -#define PATCH_BUFFER_SIZE 4096 /* Maximum size of a patch */ -#define PATCH_BUFFER_MAGIC "\xde\xad\xbe\xef MaGiC MaRk " -#define SIZEOF_PATCH_BUFFER_MAGIC (sizeof (PATCH_BUFFER_MAGIC) - 1) - -/** TYPES *********************************************************************/ - -typedef struct _PatchedByte -{ - int offset; /*!< File offset of the patched byte. */ - unsigned char expected; /*!< Expected (original) value of the byte. */ - unsigned char patched; /*!< Patched (new) value for the byte. */ -} PatchedByte; - -typedef struct _PatchedFile -{ - const char *name; /*!< Name of the file to be patched. */ - int fileSize; /*!< Size of the file in bytes. */ - int patchCount; /*!< Number of patches for the file. */ - PatchedByte *patches; /*!< Patches for the file. */ -} PatchedFile; - -typedef struct _Patch -{ - const char *name; /*!< Name of the patch. */ - int fileCount; /*!< Number of files in the patch. */ - PatchedFile *files; /*!< Files for the patch. */ -} Patch; - -/** FUNCTION PROTOTYPES *******************************************************/ - -static void printUsage(); - -/** GLOBALS *******************************************************************/ - -static Patch m_patch = { NULL, 0, NULL }; -static int m_argc = 0; -static char **m_argv = NULL; - -/* patch buffer where we put the patch info into */ -static unsigned char m_patchBuffer[SIZEOF_PATCH_BUFFER_MAGIC + PATCH_BUFFER_SIZE] = - PATCH_BUFFER_MAGIC; - -/** HELPER FUNCTIONS **********************************************************/ - -static void * -loadFile(const char *fileName, int *fileSize_) -{ - FILE *f; - struct stat sb; - int fileSize; - void *p; - - /* Open the file */ - f = fopen(fileName, "rb"); - if (f == NULL) - { - printf("Couldn't open file %s for reading!\n", fileName); - return NULL; - } - - /* Get file size */ - if (fstat(fileno(f), &sb) < 0) - { - fclose(f); - printf("Couldn't get size of file %s!\n", fileName); - return NULL; - } - fileSize = sb.st_size; - - /* Load file */ - p = malloc(fileSize); - if (p == NULL) - { - fclose(f); - printf("Couldn't allocate %d bytes for file %s!\n", fileSize, fileName); - return NULL; - } - - if (fread(p, fileSize, 1, f) != 1) - { - fclose(f); - free(p); - printf("Couldn't read file %s into memory!\n", fileName); - return NULL; - } - - /* Close file */ - fclose(f); - - *fileSize_ = fileSize; - return p; -} - - -static int -saveFile(const char *fileName, void *file, int fileSize) -{ - FILE *f; - - /* Open the file */ - f = fopen(fileName, "wb"); - if (f == NULL) - { - printf("Couldn't open file %s for writing!\n", fileName); - return -1; - } - - /* Write file */ - if (fwrite(file, fileSize, 1, f) != 1) - { - fclose(f); - printf("Couldn't write file %s!\n", fileName); - return -1; - } - - /* Close file */ - fclose(f); - return 0; -} - - -static int -compareFiles( - PatchedFile *patchedFile, - const char *originalFileName) -{ - const char *patchedFileName = patchedFile->name; - unsigned char *origChunk, *patchedChunk; - int origSize, patchedSize, i, patchCount; - PatchedByte *patches = NULL; - int patchesArrayCount = 0; - - /* Load both files */ - origChunk = loadFile(originalFileName, &origSize); - if (origChunk == NULL) - return -1; - patchedChunk = loadFile(patchedFileName, &patchedSize); - if (patchedChunk == NULL) - { - free(origChunk); - return -1; - } - if (origSize != patchedSize) - { - free(origChunk); - free(patchedChunk); - printf("File size of %s and %s differs (%d != %d)\n", - originalFileName, patchedFileName, - origSize, patchedSize); - return -1; - } - - /* Compare the files and record any differences */ - printf("Comparing %s to %s", originalFileName, patchedFileName); - for (i = 0, patchCount = 0; i < origSize; i++) - { - if (origChunk[i] != patchedChunk[i]) - { - patchCount++; - - /* Resize patches array if needed */ - if (patchesArrayCount < patchCount) - { - PatchedByte *newPatches; - newPatches = realloc(patches, patchCount * sizeof (PatchedByte)); - if (newPatches == NULL) - { - if (patches != NULL) - free(patches); - free(origChunk); - free(patchedChunk); - printf("\nOut of memory (tried to allocated %d bytes)\n", - patchCount * sizeof (PatchedByte)); - return -1; - } - patches = newPatches; - } - - /* Fill in patch info */ - patches[patchCount - 1].offset = i; - patches[patchCount - 1].expected = origChunk[i]; - patches[patchCount - 1].patched = patchedChunk[i]; - } - if ((i % (origSize / 40)) == 0) - printf("."); - } - printf(" %d changed bytes found.\n", patchCount); - - /* Unload the files */ - free(origChunk); - free(patchedChunk); - - /* Save patch info */ - patchedFile->fileSize = patchedSize; - patchedFile->patchCount = patchCount; - patchedFile->patches = patches; - - return 0; -} - - -static int -outputPatch(const char *outputFileName) -{ - unsigned char *patchExe, *patchBuffer; - int i, size, patchExeSize, patchSize, stringSize, stringOffset, patchOffset; - Patch *patch; - PatchedFile *files; - - printf("Putting patch into %s...\n", outputFileName); - - /* Calculate size of the patch */ - patchSize = sizeof (Patch) + sizeof (PatchedFile) * m_patch.fileCount; - stringSize = strlen(m_patch.name) + 1; - for (i = 0; i < m_patch.fileCount; i++) - { - stringSize += strlen(m_patch.files[i].name) + 1; - patchSize += sizeof (PatchedByte) * m_patch.files[i].patchCount; - } - if ((stringSize + patchSize) > PATCH_BUFFER_SIZE) - { - printf("Patch is too big - %d bytes maximum, %d bytes needed\n", - PATCH_BUFFER_SIZE, stringSize + patchSize); - return -1; - } - - /* Load patch.exe file into memory... */ - patchExe = loadFile(m_argv[0], &patchExeSize); - if (patchExe == NULL) - { - return -1; - } - - /* Try to find the magic mark for the patch buffer */ - for (i = 0; i < (patchExeSize - SIZEOF_PATCH_BUFFER_MAGIC); i++) - { - if (memcmp(patchExe + i, m_patchBuffer, SIZEOF_PATCH_BUFFER_MAGIC) == 0) - { - patchBuffer = patchExe + i + SIZEOF_PATCH_BUFFER_MAGIC; - - break; - } - } - if (!(i < (patchExeSize - SIZEOF_PATCH_BUFFER_MAGIC))) - { - free(patchExe); - printf("Couldn't find patch buffer magic in file %s - this shouldn't happen!!!\n", m_argv[0]); - return -1; - } - - /* Pack patch together and replace string pointers by offsets */ - patch = (Patch *)patchBuffer; - files = (PatchedFile *)(patchBuffer + sizeof (Patch)); - patchOffset = sizeof (Patch) + sizeof (PatchedFile) * m_patch.fileCount; - stringOffset = patchSize; - - patch->fileCount = m_patch.fileCount; - patch->files = (PatchedFile *)sizeof (Patch); - - patch->name = (const char *)stringOffset; - strcpy(patchBuffer + stringOffset, m_patch.name); - stringOffset += strlen(m_patch.name) + 1; - - for (i = 0; i < m_patch.fileCount; i++) - { - files[i].fileSize = m_patch.files[i].fileSize; - files[i].patchCount = m_patch.files[i].patchCount; - - files[i].name = (const char *)stringOffset; - strcpy(patchBuffer + stringOffset, m_patch.files[i].name); - stringOffset += strlen(m_patch.files[i].name) + 1; - - size = files[i].patchCount * sizeof (PatchedByte); - files[i].patches = (PatchedByte *)patchOffset; - memcpy(patchBuffer + patchOffset, m_patch.files[i].patches, size); - patchOffset += size; - } - size = patchSize + stringSize; - memset(patchBuffer + size, 0, PATCH_BUFFER_SIZE - size); - - /* Save file */ - if (saveFile(outputFileName, patchExe, patchExeSize) < 0) - { - free(patchExe); - return -1; - } - free(patchExe); - - printf("Patch saved!\n"); - return 0; -} - - -static int -loadPatch() -{ - char *p; - Patch *patch; - int i; - - p = m_patchBuffer + SIZEOF_PATCH_BUFFER_MAGIC; - patch = (Patch *)p; - - if (patch->name == NULL) - { - return -1; - } - - m_patch.name = p + (int)patch->name; - m_patch.fileCount = patch->fileCount; - m_patch.files = (PatchedFile *)(p + (int)patch->files); - - for (i = 0; i < m_patch.fileCount; i++) - { - m_patch.files[i].name = p + (int)m_patch.files[i].name; - m_patch.files[i].patches = (PatchedByte *)(p + (int)m_patch.files[i].patches); - } - - printf("Patch %s loaded...\n", m_patch.name); - return 0; -} - - -/** MAIN FUNCTIONS ************************************************************/ - -static int -createPatch() -{ - int i, status; - const char *outputFileName; - - /* Check argument count */ - if (m_argc < 6 || (m_argc % 2) != 0) - { - printUsage(); - return -1; - } - - outputFileName = m_argv[3]; - m_patch.name = m_argv[2]; - - /* Allocate PatchedFiles array */ - m_patch.fileCount = (m_argc - 4) / 2; - m_patch.files = malloc(m_patch.fileCount * sizeof (PatchedFile)); - if (m_patch.files == NULL) - { - printf("Out of memory!\n"); - return -1; - } - memset(m_patch.files, 0, m_patch.fileCount * sizeof (PatchedFile)); - - /* Compare original to patched files and fill m_patch.files array */ - for (i = 0; i < m_patch.fileCount; i++) - { - m_patch.files[i].name = m_argv[4 + (i * 2) + 1]; - status = compareFiles(m_patch.files + i, m_argv[4 + (i * 2) + 0]); - if (status < 0) - { - for (i = 0; i < m_patch.fileCount; i++) - { - if (m_patch.files[i].patches != NULL) - free(m_patch.files[i].patches); - } - free(m_patch.files); - m_patch.files = NULL; - m_patch.fileCount = 0; - return status; - } - } - - /* Output patch */ - return outputPatch(outputFileName); -} - - -static int -applyPatch() -{ - int c, i, j, fileSize, makeBackup; - unsigned char *file; - char *p; - const char *fileName; - char buffer[MAX_PATH]; - - - if (m_argc > 1 && strcmp(m_argv[1], "-d") != 0) - { - printUsage(); - return -1; - } - - /* Load patch */ - if (loadPatch() < 0) - { - printf("This executable doesn't contain a patch, use -c to create one.\n"); - return -1; - } - - if (m_argc > 1) - { - /* Dump patch */ - printf("Patch name: %s\n", m_patch.name); - printf("File count: %d\n", m_patch.fileCount); - for (i = 0; i < m_patch.fileCount; i++) - { - printf("----------------------\n" - "File name: %s\n" - "File size: %d bytes\n", - m_patch.files[i].name, m_patch.files[i].fileSize); - printf("Patch count: %d\n", m_patch.files[i].patchCount); - for (j = 0; j < m_patch.files[i].patchCount; j++) - { - printf(" Offset 0x%x 0x%02x -> 0x%02x\n", - m_patch.files[i].patches[j].offset, - m_patch.files[i].patches[j].expected, - m_patch.files[i].patches[j].patched); - } - } - } - else - { - /* Apply patch */ - printf("Applying patch...\n"); - for (i = 0; i < m_patch.fileCount; i++) - { - /* Load original file */ - fileName = m_patch.files[i].name; -applyPatch_retry_file: - file = loadFile(fileName, &fileSize); - if (file == NULL) - { - printf("File %s not found! ", fileName); -applyPatch_file_open_error: - printf("(S)kip, (R)etry, (A)bort, (M)anually enter filename"); - do - { - c = getch(); - } - while (c != 's' && c != 'r' && c != 'a' && c != 'm'); - printf("\n"); - if (c == 's') - { - continue; - } - else if (c == 'r') - { - goto applyPatch_retry_file; - } - else if (c == 'a') - { - return 0; - } - else if (c == 'm') - { - if (fgets(buffer, sizeof (buffer), stdin) == NULL) - { - printf("fgets() failed!\n"); - return -1; - } - p = strchr(buffer, '\r'); - if (p != NULL) - *p = '\0'; - p = strchr(buffer, '\n'); - if (p != NULL) - *p = '\0'; - - fileName = buffer; - goto applyPatch_retry_file; - } - } - - /* Check file size */ - if (fileSize != m_patch.files[i].fileSize) - { - free(file); - printf("File %s has unexpected filesize of %d bytes (%d bytes expected)\n", - fileName, fileSize, m_patch.files[i].fileSize); - if (fileName != m_patch.files[i].name) /* manually entered filename */ - { - goto applyPatch_file_open_error; - } - return -1; - } - - /* Ask for backup */ - printf("Do you want to make a backup of %s? (Y)es, (N)o, (A)bort", fileName); - do - { - c = getch(); - } - while (c != 'y' && c != 'n' && c != 'a'); - printf("\n"); - if (c == 'y') - { - char buffer[MAX_PATH]; - snprintf(buffer, MAX_PATH, "%s.bak", fileName); - buffer[MAX_PATH-1] = '\0'; - makeBackup = 1; - if (access(buffer, 0) >= 0) /* file exists */ - { - printf("File %s already exists, overwrite? (Y)es, (N)o, (A)bort", buffer); - do - { - c = getch(); - } - while (c != 'y' && c != 'n' && c != 'a'); - printf("\n"); - if (c == 'n') - makeBackup = 0; - else if (c == 'a') - { - free(file); - return 0; - } - } - if (makeBackup && saveFile(buffer, file, fileSize) < 0) - { - free(file); - return -1; - } - } - else if (c == 'a') - { - free(file); - return 0; - } - - /* Patch file */ - for (j = 0; j < m_patch.files[i].patchCount; j++) - { - int offset = m_patch.files[i].patches[j].offset; - if (file[offset] != m_patch.files[i].patches[j].expected) - { - printf("Unexpected value in file %s at offset 0x%x: expected = 0x%02x, found = 0x%02x\n", - fileName, offset, m_patch.files[i].patches[j].expected, file[offset]); - free(file); - return -1; - } - file[offset] = m_patch.files[i].patches[j].patched; - } - - /* Save file */ - if (saveFile(fileName, file, fileSize) < 0) - { - free(file); - return -1; - } - free(file); - } - - printf("Patch applied sucessfully!\n"); - } - - return 0; -} - - -static void -printUsage() -{ - printf("Usage:\n" - "%s -c - Create patch\n" - "%s -d - Dump patch\n" - "%s - Apply patch\n" - "\n" - "A patch can be created like this:\n" - "%s -c \"patch name\" output.exe file1.orig file1.patched[ file2.orig file2.patched[ ...]]\n", - m_argv[0], m_argv[0], m_argv[0], m_argv[0]); -} - - -int -main( - int argc, - char *argv[]) -{ - m_argc = argc; - m_argv = argv; - - if (argc >= 2 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)) - { - printUsage(); - return 0; - } - else if (argc >= 2 && argv[1][0] == '-') - { - if (strcmp(argv[1], "-c") == 0) - { - return createPatch(); - } - else if (strcmp(argv[1], "-d") == 0) - { - return applyPatch(); - } - else - { - printf("Unknown option: %s\n" - "Use -h for help.\n", - argv[1]); - return -1; - } - } - - return applyPatch(); -} - +#include +#include +#include +#include +#include +#include + +/** DEFINES *******************************************************************/ + +#define PATCH_BUFFER_SIZE 4096 /* Maximum size of a patch */ +#define PATCH_BUFFER_MAGIC "\xde\xad\xbe\xef MaGiC MaRk " +#define SIZEOF_PATCH_BUFFER_MAGIC (sizeof (PATCH_BUFFER_MAGIC) - 1) + +/** TYPES *********************************************************************/ + +typedef struct _PatchedByte +{ + int offset; /*!< File offset of the patched byte. */ + unsigned char expected; /*!< Expected (original) value of the byte. */ + unsigned char patched; /*!< Patched (new) value for the byte. */ +} PatchedByte; + +typedef struct _PatchedFile +{ + const char *name; /*!< Name of the file to be patched. */ + int fileSize; /*!< Size of the file in bytes. */ + int patchCount; /*!< Number of patches for the file. */ + PatchedByte *patches; /*!< Patches for the file. */ +} PatchedFile; + +typedef struct _Patch +{ + const char *name; /*!< Name of the patch. */ + int fileCount; /*!< Number of files in the patch. */ + PatchedFile *files; /*!< Files for the patch. */ +} Patch; + +/** FUNCTION PROTOTYPES *******************************************************/ + +static void printUsage(); + +/** GLOBALS *******************************************************************/ + +static Patch m_patch = { NULL, 0, NULL }; +static int m_argc = 0; +static char **m_argv = NULL; + +/* patch buffer where we put the patch info into */ +static unsigned char m_patchBuffer[SIZEOF_PATCH_BUFFER_MAGIC + PATCH_BUFFER_SIZE] = + PATCH_BUFFER_MAGIC; + +/** HELPER FUNCTIONS **********************************************************/ + +static void * +loadFile(const char *fileName, int *fileSize_) +{ + FILE *f; + struct stat sb; + int fileSize; + void *p; + + /* Open the file */ + f = fopen(fileName, "rb"); + if (f == NULL) + { + printf("Couldn't open file %s for reading!\n", fileName); + return NULL; + } + + /* Get file size */ + if (fstat(fileno(f), &sb) < 0) + { + fclose(f); + printf("Couldn't get size of file %s!\n", fileName); + return NULL; + } + fileSize = sb.st_size; + + /* Load file */ + p = malloc(fileSize); + if (p == NULL) + { + fclose(f); + printf("Couldn't allocate %d bytes for file %s!\n", fileSize, fileName); + return NULL; + } + + if (fread(p, fileSize, 1, f) != 1) + { + fclose(f); + free(p); + printf("Couldn't read file %s into memory!\n", fileName); + return NULL; + } + + /* Close file */ + fclose(f); + + *fileSize_ = fileSize; + return p; +} + + +static int +saveFile(const char *fileName, void *file, int fileSize) +{ + FILE *f; + + /* Open the file */ + f = fopen(fileName, "wb"); + if (f == NULL) + { + printf("Couldn't open file %s for writing!\n", fileName); + return -1; + } + + /* Write file */ + if (fwrite(file, fileSize, 1, f) != 1) + { + fclose(f); + printf("Couldn't write file %s!\n", fileName); + return -1; + } + + /* Close file */ + fclose(f); + return 0; +} + + +static int +compareFiles( + PatchedFile *patchedFile, + const char *originalFileName) +{ + const char *patchedFileName = patchedFile->name; + unsigned char *origChunk, *patchedChunk; + int origSize, patchedSize, i, patchCount; + PatchedByte *patches = NULL; + int patchesArrayCount = 0; + + /* Load both files */ + origChunk = loadFile(originalFileName, &origSize); + if (origChunk == NULL) + return -1; + patchedChunk = loadFile(patchedFileName, &patchedSize); + if (patchedChunk == NULL) + { + free(origChunk); + return -1; + } + if (origSize != patchedSize) + { + free(origChunk); + free(patchedChunk); + printf("File size of %s and %s differs (%d != %d)\n", + originalFileName, patchedFileName, + origSize, patchedSize); + return -1; + } + + /* Compare the files and record any differences */ + printf("Comparing %s to %s", originalFileName, patchedFileName); + for (i = 0, patchCount = 0; i < origSize; i++) + { + if (origChunk[i] != patchedChunk[i]) + { + patchCount++; + + /* Resize patches array if needed */ + if (patchesArrayCount < patchCount) + { + PatchedByte *newPatches; + newPatches = realloc(patches, patchCount * sizeof (PatchedByte)); + if (newPatches == NULL) + { + if (patches != NULL) + free(patches); + free(origChunk); + free(patchedChunk); + printf("\nOut of memory (tried to allocated %d bytes)\n", + patchCount * sizeof (PatchedByte)); + return -1; + } + patches = newPatches; + } + + /* Fill in patch info */ + patches[patchCount - 1].offset = i; + patches[patchCount - 1].expected = origChunk[i]; + patches[patchCount - 1].patched = patchedChunk[i]; + } + if ((i % (origSize / 40)) == 0) + printf("."); + } + printf(" %d changed bytes found.\n", patchCount); + + /* Unload the files */ + free(origChunk); + free(patchedChunk); + + /* Save patch info */ + patchedFile->fileSize = patchedSize; + patchedFile->patchCount = patchCount; + patchedFile->patches = patches; + + return 0; +} + + +static int +outputPatch(const char *outputFileName) +{ + unsigned char *patchExe, *patchBuffer; + int i, size, patchExeSize, patchSize, stringSize, stringOffset, patchOffset; + Patch *patch; + PatchedFile *files; + + printf("Putting patch into %s...\n", outputFileName); + + /* Calculate size of the patch */ + patchSize = sizeof (Patch) + sizeof (PatchedFile) * m_patch.fileCount; + stringSize = strlen(m_patch.name) + 1; + for (i = 0; i < m_patch.fileCount; i++) + { + stringSize += strlen(m_patch.files[i].name) + 1; + patchSize += sizeof (PatchedByte) * m_patch.files[i].patchCount; + } + if ((stringSize + patchSize) > PATCH_BUFFER_SIZE) + { + printf("Patch is too big - %d bytes maximum, %d bytes needed\n", + PATCH_BUFFER_SIZE, stringSize + patchSize); + return -1; + } + + /* Load patch.exe file into memory... */ + patchExe = loadFile(m_argv[0], &patchExeSize); + if (patchExe == NULL) + { + return -1; + } + + /* Try to find the magic mark for the patch buffer */ + for (i = 0; i < (patchExeSize - SIZEOF_PATCH_BUFFER_MAGIC); i++) + { + if (memcmp(patchExe + i, m_patchBuffer, SIZEOF_PATCH_BUFFER_MAGIC) == 0) + { + patchBuffer = patchExe + i + SIZEOF_PATCH_BUFFER_MAGIC; + + break; + } + } + if (!(i < (patchExeSize - SIZEOF_PATCH_BUFFER_MAGIC))) + { + free(patchExe); + printf("Couldn't find patch buffer magic in file %s - this shouldn't happen!!!\n", m_argv[0]); + return -1; + } + + /* Pack patch together and replace string pointers by offsets */ + patch = (Patch *)patchBuffer; + files = (PatchedFile *)(patchBuffer + sizeof (Patch)); + patchOffset = sizeof (Patch) + sizeof (PatchedFile) * m_patch.fileCount; + stringOffset = patchSize; + + patch->fileCount = m_patch.fileCount; + patch->files = (PatchedFile *)sizeof (Patch); + + patch->name = (const char *)stringOffset; + strcpy(patchBuffer + stringOffset, m_patch.name); + stringOffset += strlen(m_patch.name) + 1; + + for (i = 0; i < m_patch.fileCount; i++) + { + files[i].fileSize = m_patch.files[i].fileSize; + files[i].patchCount = m_patch.files[i].patchCount; + + files[i].name = (const char *)stringOffset; + strcpy(patchBuffer + stringOffset, m_patch.files[i].name); + stringOffset += strlen(m_patch.files[i].name) + 1; + + size = files[i].patchCount * sizeof (PatchedByte); + files[i].patches = (PatchedByte *)patchOffset; + memcpy(patchBuffer + patchOffset, m_patch.files[i].patches, size); + patchOffset += size; + } + size = patchSize + stringSize; + memset(patchBuffer + size, 0, PATCH_BUFFER_SIZE - size); + + /* Save file */ + if (saveFile(outputFileName, patchExe, patchExeSize) < 0) + { + free(patchExe); + return -1; + } + free(patchExe); + + printf("Patch saved!\n"); + return 0; +} + + +static int +loadPatch() +{ + char *p; + Patch *patch; + int i; + + p = m_patchBuffer + SIZEOF_PATCH_BUFFER_MAGIC; + patch = (Patch *)p; + + if (patch->name == NULL) + { + return -1; + } + + m_patch.name = p + (int)patch->name; + m_patch.fileCount = patch->fileCount; + m_patch.files = (PatchedFile *)(p + (int)patch->files); + + for (i = 0; i < m_patch.fileCount; i++) + { + m_patch.files[i].name = p + (int)m_patch.files[i].name; + m_patch.files[i].patches = (PatchedByte *)(p + (int)m_patch.files[i].patches); + } + + printf("Patch %s loaded...\n", m_patch.name); + return 0; +} + + +/** MAIN FUNCTIONS ************************************************************/ + +static int +createPatch() +{ + int i, status; + const char *outputFileName; + + /* Check argument count */ + if (m_argc < 6 || (m_argc % 2) != 0) + { + printUsage(); + return -1; + } + + outputFileName = m_argv[3]; + m_patch.name = m_argv[2]; + + /* Allocate PatchedFiles array */ + m_patch.fileCount = (m_argc - 4) / 2; + m_patch.files = malloc(m_patch.fileCount * sizeof (PatchedFile)); + if (m_patch.files == NULL) + { + printf("Out of memory!\n"); + return -1; + } + memset(m_patch.files, 0, m_patch.fileCount * sizeof (PatchedFile)); + + /* Compare original to patched files and fill m_patch.files array */ + for (i = 0; i < m_patch.fileCount; i++) + { + m_patch.files[i].name = m_argv[4 + (i * 2) + 1]; + status = compareFiles(m_patch.files + i, m_argv[4 + (i * 2) + 0]); + if (status < 0) + { + for (i = 0; i < m_patch.fileCount; i++) + { + if (m_patch.files[i].patches != NULL) + free(m_patch.files[i].patches); + } + free(m_patch.files); + m_patch.files = NULL; + m_patch.fileCount = 0; + return status; + } + } + + /* Output patch */ + return outputPatch(outputFileName); +} + + +static int +applyPatch() +{ + int c, i, j, fileSize, makeBackup; + unsigned char *file; + char *p; + const char *fileName; + char buffer[MAX_PATH]; + + + if (m_argc > 1 && strcmp(m_argv[1], "-d") != 0) + { + printUsage(); + return -1; + } + + /* Load patch */ + if (loadPatch() < 0) + { + printf("This executable doesn't contain a patch, use -c to create one.\n"); + return -1; + } + + if (m_argc > 1) + { + /* Dump patch */ + printf("Patch name: %s\n", m_patch.name); + printf("File count: %d\n", m_patch.fileCount); + for (i = 0; i < m_patch.fileCount; i++) + { + printf("----------------------\n" + "File name: %s\n" + "File size: %d bytes\n", + m_patch.files[i].name, m_patch.files[i].fileSize); + printf("Patch count: %d\n", m_patch.files[i].patchCount); + for (j = 0; j < m_patch.files[i].patchCount; j++) + { + printf(" Offset 0x%x 0x%02x -> 0x%02x\n", + m_patch.files[i].patches[j].offset, + m_patch.files[i].patches[j].expected, + m_patch.files[i].patches[j].patched); + } + } + } + else + { + /* Apply patch */ + printf("Applying patch...\n"); + for (i = 0; i < m_patch.fileCount; i++) + { + /* Load original file */ + fileName = m_patch.files[i].name; +applyPatch_retry_file: + file = loadFile(fileName, &fileSize); + if (file == NULL) + { + printf("File %s not found! ", fileName); +applyPatch_file_open_error: + printf("(S)kip, (R)etry, (A)bort, (M)anually enter filename"); + do + { + c = getch(); + } + while (c != 's' && c != 'r' && c != 'a' && c != 'm'); + printf("\n"); + if (c == 's') + { + continue; + } + else if (c == 'r') + { + goto applyPatch_retry_file; + } + else if (c == 'a') + { + return 0; + } + else if (c == 'm') + { + if (fgets(buffer, sizeof (buffer), stdin) == NULL) + { + printf("fgets() failed!\n"); + return -1; + } + p = strchr(buffer, '\r'); + if (p != NULL) + *p = '\0'; + p = strchr(buffer, '\n'); + if (p != NULL) + *p = '\0'; + + fileName = buffer; + goto applyPatch_retry_file; + } + } + + /* Check file size */ + if (fileSize != m_patch.files[i].fileSize) + { + free(file); + printf("File %s has unexpected filesize of %d bytes (%d bytes expected)\n", + fileName, fileSize, m_patch.files[i].fileSize); + if (fileName != m_patch.files[i].name) /* manually entered filename */ + { + goto applyPatch_file_open_error; + } + return -1; + } + + /* Ask for backup */ + printf("Do you want to make a backup of %s? (Y)es, (N)o, (A)bort", fileName); + do + { + c = getch(); + } + while (c != 'y' && c != 'n' && c != 'a'); + printf("\n"); + if (c == 'y') + { + char buffer[MAX_PATH]; + snprintf(buffer, MAX_PATH, "%s.bak", fileName); + buffer[MAX_PATH-1] = '\0'; + makeBackup = 1; + if (access(buffer, 0) >= 0) /* file exists */ + { + printf("File %s already exists, overwrite? (Y)es, (N)o, (A)bort", buffer); + do + { + c = getch(); + } + while (c != 'y' && c != 'n' && c != 'a'); + printf("\n"); + if (c == 'n') + makeBackup = 0; + else if (c == 'a') + { + free(file); + return 0; + } + } + if (makeBackup && saveFile(buffer, file, fileSize) < 0) + { + free(file); + return -1; + } + } + else if (c == 'a') + { + free(file); + return 0; + } + + /* Patch file */ + for (j = 0; j < m_patch.files[i].patchCount; j++) + { + int offset = m_patch.files[i].patches[j].offset; + if (file[offset] != m_patch.files[i].patches[j].expected) + { + printf("Unexpected value in file %s at offset 0x%x: expected = 0x%02x, found = 0x%02x\n", + fileName, offset, m_patch.files[i].patches[j].expected, file[offset]); + free(file); + return -1; + } + file[offset] = m_patch.files[i].patches[j].patched; + } + + /* Save file */ + if (saveFile(fileName, file, fileSize) < 0) + { + free(file); + return -1; + } + free(file); + } + + printf("Patch applied sucessfully!\n"); + } + + return 0; +} + + +static void +printUsage() +{ + printf("Usage:\n" + "%s -c - Create patch\n" + "%s -d - Dump patch\n" + "%s - Apply patch\n" + "\n" + "A patch can be created like this:\n" + "%s -c \"patch name\" output.exe file1.orig file1.patched[ file2.orig file2.patched[ ...]]\n", + m_argv[0], m_argv[0], m_argv[0], m_argv[0]); +} + + +int +main( + int argc, + char *argv[]) +{ + m_argc = argc; + m_argv = argv; + + if (argc >= 2 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)) + { + printUsage(); + return 0; + } + else if (argc >= 2 && argv[1][0] == '-') + { + if (strcmp(argv[1], "-c") == 0) + { + return createPatch(); + } + else if (strcmp(argv[1], "-d") == 0) + { + return applyPatch(); + } + else + { + printf("Unknown option: %s\n" + "Use -h for help.\n", + argv[1]); + return -1; + } + } + + return applyPatch(); +} + diff --git a/reactos/apps/utils/net/tracert/tracert.c b/reactos/apps/utils/net/tracert/tracert.c index b85c267f841..0143392582d 100644 --- a/reactos/apps/utils/net/tracert/tracert.c +++ b/reactos/apps/utils/net/tracert/tracert.c @@ -1,656 +1,656 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS traceroute utility - * FILE: apps/utils/net/tracert/tracert.c - * PURPOSE: trace a packets route through a network - * PROGRAMMERS: Ged Murphy (gedmurphy@gmail.com) - * REVISIONS: - * GM 03/05/05 Created - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include "tracert.h" - -#define WIN32_LEAN_AND_MEAN - -#ifdef DBG -#undef DBG -#endif - -/* - * globals - */ -SOCKET icmpSock; // socket descriptor -SOCKADDR_IN source, dest; // source and destination address info -ECHO_REPLY_HEADER sendpacket; // ICMP echo packet -IPv4_HEADER recvpacket; // return reveive packet - -BOOL bUsePerformanceCounter; // whether to use the high res performance counter -LARGE_INTEGER TicksPerMs; // number of millisecs in relation to proc freq -LARGE_INTEGER TicksPerUs; // number of microsecs in relation to proc freq -LONGLONG lTimeStart; // send packet, timer start -LONGLONG lTimeEnd; // receive packet, timer end - -CHAR cHostname[256]; // target hostname -CHAR cDestIP[18]; // target IP - - -/* - * command line options - */ -BOOL bResolveAddresses = TRUE; // -d MS ping defaults to true. -INT iMaxHops = 30; // -h Max number of hops before trace ends -INT iHostList; // -j @UNIMPLEMENTED@ -INT iTimeOut = 2000; // -w time before packet times out - - - - -/* - * - * Parse command line parameters and set any options - * - */ -BOOL ParseCmdline(int argc, char* argv[]) -{ - int i; - - if (argc < 2) - { - Usage(); - return FALSE; - } - - for (i = 1; i < argc; i++) { - if (argv[i][0] == '-') { - switch (argv[i][1]) { - case 'd': bResolveAddresses = FALSE; - break; - case 'h': sscanf(argv[i+1], "%d", &iMaxHops); - break; - case 'l': break; /* @unimplemented@ */ - case 'w': sscanf(argv[i+1], "%d", &iTimeOut); - break; - default: - _tprintf(_T("%s is not a valid option.\n"), argv[i]); - Usage(); - return FALSE; - } - } else { - /* copy target address */ - strncpy(cHostname, argv[i], 255); - - } - } - - return TRUE; -} - - - -/* - * - * Driver function, controls the traceroute program - * - */ -INT Driver(VOID) { - - INT i; - INT iHopCount = 1; // hop counter. default max is 30 - INT iSeqNum = 0; // initialise packet sequence number - INT iTTL = 1; // set initial packet TTL to 1 - BOOL bFoundTarget = FALSE; // Have we reached our destination yet - BOOL bAwaitPacket; // indicates whether we have recieved a good packet - INT iDecRes; // DecodeResponse return value - INT iRecieveReturn; // RecieveReturn return value - INT iNameInfoRet; // getnameinfo return value - INT iPacketSize = PACKET_SIZE; // packet size - WORD wHeaderLen; // header length - PECHO_REPLY_HEADER icmphdr; - - - //temps for getting host name - CHAR cHost[256]; - CHAR cServ[256]; - CHAR *ip; - - /* setup winsock */ - WSADATA wsaData; - - /* check for winsock 2 */ - if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { -#ifdef DBG - _tprintf(_T("WSAStartup failed.\n")); -#endif /* DBG */ - exit(1); - } - - SetupTimingMethod(); - - /* setup target info */ - ResolveHostname(); - - /* print standard tracing info to screen */ - _tprintf(_T("\nTracing route to %s [%s]\n"), cHostname, cDestIP); - _tprintf(_T("over a maximum of %d hop"), iMaxHops); - iMaxHops > 1 ? _tprintf(_T("s:\n\n")) : _tprintf(_T(":\n\n")); - - /* run until we hit either max hops, or we recieve 3 echo replys */ - while ((iHopCount <= iMaxHops) && (bFoundTarget != TRUE)) { - _tprintf(_T("%3d "), iHopCount); - /* run 3 pings for each hop */ - for (i=0; i<3; i++) { - if (Setup(iTTL) != TRUE) { -#ifdef DBG - _tprintf(_T("error in Setup()\n")); -#endif /* DBG */ - WSACleanup(); - exit(1); - } - PreparePacket(iPacketSize, iSeqNum); - if (SendPacket(iPacketSize) != SOCKET_ERROR) { - /* loop until we get a good packet */ - bAwaitPacket = TRUE; - while (bAwaitPacket) { - /* Receive replies until we either get a successful - * read, or a fatal error occurs. */ - if ((iRecieveReturn = ReceivePacket(iPacketSize)) < 0) { - /* check the sequence number in the packet - * if it's bad, complain and wait for another packet - * , otherwise break */ - wHeaderLen = recvpacket.h_len * 4; - icmphdr = (ECHO_REPLY_HEADER *)((char*)&recvpacket + wHeaderLen); - if (icmphdr->icmpheader.seq != iSeqNum) { - _tprintf(_T("bad sequence number!\n")); - continue; - } else { - break; - } - } - - /* if RecievePacket timed out we don't bother decoding */ - if (iRecieveReturn != 1) { - iDecRes = DecodeResponse(iPacketSize, iSeqNum); - - switch (iDecRes) { - case 0 : bAwaitPacket = FALSE; /* time exceeded */ - break; - case 1 : bAwaitPacket = FALSE; /* echo reply */ - break; - case 2 : bAwaitPacket = FALSE; /* destination unreachable */ - break; -#ifdef DBG - case -1 : - _tprintf(_T("recieved foreign packet\n")); - break; - case -2 : - _tprintf(_T("error in DecodeResponse\n")); - break; - case -3 : - _tprintf(_T("unknown ICMP packet\n")); - break; -#endif /* DBG */ - default : break; - } - } else { - /* packet timed out. Don't wait for it again */ - bAwaitPacket = FALSE; - } - } - } - - iSeqNum++; - _tprintf(_T(" ")); - } - - if(bResolveAddresses) { - /* gethostbyaddr() and getnameinfo() are - * unimplemented in ROS at present. - * Alex has advised he will be implementing gethostbyaddr - * but as it's depricieted and getnameinfo is much nicer, - * I've used that for the time being for testing in Windows*/ - - //ip = inet_addr(inet_ntoa(source.sin_addr)); - //host = gethostbyaddr((char *)&ip, 4, 0); - - ip = inet_ntoa(source.sin_addr); - - iNameInfoRet = getnameinfo((SOCKADDR *)&source, - sizeof(SOCKADDR), - cHost, - 256, - cServ, - 256, - NI_NUMERICSERV); - if (iNameInfoRet == 0) { - /* if IP address resolved to a hostname, - * print the IP address after it */ - if (lstrcmpA(cHost, ip) != 0) { - _tprintf(_T("%s [%s]"), cHost, ip); - } else { - _tprintf(_T("%s"), cHost); - } - } else { - _tprintf(_T("error: %d"), WSAGetLastError()); -#ifdef DBG - _tprintf(_T(" getnameinfo failed: %d"), iNameInfoRet); -#endif /* DBG */ - } - - } else { - _tprintf(_T("%s"), inet_ntoa(source.sin_addr)); - } - _tprintf(_T("\n")); - - /* check if we've arrived at the target */ - if (strcmp(cDestIP, inet_ntoa(source.sin_addr)) == 0) { - bFoundTarget = TRUE; - } else { - iTTL++; - iHopCount++; - Sleep(500); - } - } - _tprintf(_T("\nTrace complete.\n")); - WSACleanup(); - - return 0; -} - -/* - * Establish if performance counters are available and - * set up timing figures in relation to processor frequency. - * If performance counters are not available, we'll be using - * gettickcount, so set the figures to 1 - * - */ -VOID SetupTimingMethod(VOID) -{ - LARGE_INTEGER PerformanceCounterFrequency; - - /* check if performance counters are available */ - bUsePerformanceCounter = QueryPerformanceFrequency(&PerformanceCounterFrequency); - if (bUsePerformanceCounter) { - /* restrict execution to first processor on SMP systems */ - if (SetThreadAffinityMask(GetCurrentThread(), 1) == 0) { - bUsePerformanceCounter = FALSE; - } - - TicksPerMs.QuadPart = PerformanceCounterFrequency.QuadPart / 1000; - TicksPerUs.QuadPart = PerformanceCounterFrequency.QuadPart / 1000000; - } - - if (!bUsePerformanceCounter) { - TicksPerMs.QuadPart = 1; - TicksPerUs.QuadPart = 1; - } -} - - -/* - * - * Check for a hostname or dotted deciamal for our target. - * If we have a hostname, resolve to an IP and store it, else - * just store the target IP address. Also set up other key - * SOCKADDR_IN members needed for the connection. - * - */ -VOID ResolveHostname(VOID) -{ - HOSTENT *hp; - ULONG addr; - - memset(&dest, 0, sizeof(dest)); - - addr = inet_addr(cHostname); - /* if address is not a dotted decimal */ - if (addr == INADDR_NONE) { - hp = gethostbyname(cHostname); - if (hp != 0) { - memcpy(&dest.sin_addr, hp->h_addr, hp->h_length); - //dest.sin_addr = *((struct in_addr *)hp->h_addr); - dest.sin_family = hp->h_addrtype; - } else { - _tprintf(_T("Unable to resolve target system name %s.\n"), cHostname); - WSACleanup(); - exit(1); - } - } else { - dest.sin_addr.s_addr = addr; - dest.sin_family = AF_INET; - } - /* copy destination IP address into a string */ - strcpy(cDestIP, inet_ntoa(dest.sin_addr)); -} - - - -/* - * - * Create our socket which will be used for sending and recieving, - * Socket Type is raw, Protocol is ICMP. Also set the TTL value which will be - * set in the outgoing IP packet. - * - */ -INT Setup(INT iTTL) -{ - INT iSockRet; - - /* create raw socket */ - icmpSock = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, 0, 0, 0); - if (icmpSock == INVALID_SOCKET) { - _tprintf(_T("Could not create socket : %d.\n"), WSAGetLastError()); - if (WSAGetLastError() == WSAEACCES) { - _tprintf(_T("\n\nYou must be an administrator to run this program!\n\n")); - WSACleanup(); - exit(1); - } - return FALSE; - } - - /* setup for TTL */ - iSockRet = setsockopt(icmpSock, IPPROTO_IP, IP_TTL, (const char *)&iTTL, sizeof(iTTL)); - if (iSockRet == SOCKET_ERROR) { - _tprintf(_T("TTL setsockopt failed : %d. \n"), WSAGetLastError()); - return FALSE; - } - - return TRUE; -} - - - -/* - * Prepare the ICMP echo request packet for sending. - * Calculate the packet checksum - * - */ -VOID PreparePacket(INT iPacketSize, INT iSeqNum) -{ - /* assemble ICMP echo request packet */ - sendpacket.icmpheader.type = ECHO_REQUEST; - sendpacket.icmpheader.code = 0; - sendpacket.icmpheader.checksum = 0; - sendpacket.icmpheader.id = (USHORT)GetCurrentProcessId(); - sendpacket.icmpheader.seq = iSeqNum; - - /* calculate checksum of packet */ - sendpacket.icmpheader.checksum = CheckSum((PUSHORT)&sendpacket, sizeof(ICMP_HEADER) + iPacketSize); -} - - - -/* - * - * Get the system time and send the ICMP packet to the destination - * address. - * - */ -INT SendPacket(INT datasize) -{ - INT iSockRet; - INT iPacketSize; - - iPacketSize = sizeof(ECHO_REPLY_HEADER) + datasize; - -#ifdef DBG - _tprintf(_T("\nsending packet of %d bytes\n"), iPacketSize); -#endif /* DBG */ - - /* get time packet was sent */ - lTimeStart = GetTime(); - - iSockRet = sendto(icmpSock, //socket - (char *)&sendpacket, //buffer - iPacketSize, //size of buffer - 0, //flags - (SOCKADDR *)&dest, //destination - sizeof(dest)); //address length - - if (iSockRet == SOCKET_ERROR) { - if (WSAGetLastError() == WSAEACCES) { - _tprintf(_T("\n\nYou must be an administrator to run this program!\n\n")); - exit(1); - WSACleanup(); - } else { -#ifdef DBG - _tprintf(_T("sendto failed %d\n"), WSAGetLastError()); -#endif /* DBG */ - return FALSE; - } - } -#ifdef DBG - _tprintf(_T("sent %d bytes\n"), iSockRet); -#endif /* DBG */ - - /* return number of bytes sent */ - return iSockRet; -} - - - -/* - * - * Set up a timeout value and put the socket in a select poll. - * Wait until we recieve an IPv4 reply packet in reply to the ICMP - * echo request packet and get the time the packet was recieved. - * If we don't recieve a packet, do some checking to establish why. - * - */ -INT ReceivePacket(INT datasize) -{ - TIMEVAL timeVal; - FD_SET readFDS; - int iSockRet = 0, iSelRet; - int iFromLen; - int iPacketSize; - - /* allow for a larger recv buffer to store ICMP TTL - * exceed, IP header and orginal ICMP request */ - iPacketSize = MAX_REC_SIZE + datasize; - - iFromLen = sizeof(source); - -#ifdef DBG - _tprintf(_T("receiving packet. Available buffer, %d bytes\n"), iPacketSize); -#endif /* DBG */ - - /* monitor icmpSock for incomming connections */ - FD_ZERO(&readFDS); - FD_SET(icmpSock, &readFDS); - - /* set timeout values */ - timeVal.tv_sec = iTimeOut / 1000; - timeVal.tv_usec = iTimeOut % 1000; - - iSelRet = select(0, &readFDS, NULL, NULL, &timeVal); - - if ((iSelRet != SOCKET_ERROR) && (iSelRet != 0)) { - iSockRet = recvfrom(icmpSock, //socket - (char *)&recvpacket, //buffer - iPacketSize, //size of buffer - 0, //flags - (SOCKADDR *)&source, //source address - &iFromLen); //pointer to address length - /* get time packet was recieved */ - lTimeEnd = GetTime(); - /* if socket timed out */ - } else if (iSelRet == 0) { - _tprintf(_T(" * ")); - return 1; - } else if (iSelRet == SOCKET_ERROR) { - _tprintf(_T("select() failed in sendPacket() %d\n"), WSAGetLastError()); - return -1; - } - - - if (iSockRet == SOCKET_ERROR) { - _tprintf(_T("recvfrom failed: %d\n"), WSAGetLastError()); - return -2; - } -#ifdef DBG - else { - _tprintf(_T("reveived %d bytes\n"), iSockRet); - } -#endif /* DBG */ - - return 0; -} - - - -/* - * - * Cast the IPv4 packet to an echo reply and to a TTL exceed. - * Check the 'type' field to establish what was recieved, and - * ensure the packet is related to the originating process. - * It all is well, print the time taken for the round trip. - * - */ -INT DecodeResponse(INT iPacketSize, INT iSeqNum) -{ - unsigned short header_len = recvpacket.h_len * 4; - /* cast the recieved packet into an ECHO reply and a TTL Exceed so we can check the ID*/ - ECHO_REPLY_HEADER *IcmpHdr = (ECHO_REPLY_HEADER *)((char*)&recvpacket + header_len); - TTL_EXCEED_HEADER *TTLExceedHdr = (TTL_EXCEED_HEADER *)((char *)&recvpacket + header_len); - - /* Make sure the reply is ok */ - if (iPacketSize < header_len + ICMP_MIN_SIZE) { - _tprintf(_T("too few bytes from %s\n"), inet_ntoa(dest.sin_addr)); - return -2; - } - - switch (IcmpHdr->icmpheader.type) { - case TTL_EXCEEDED : - if (TTLExceedHdr->OrigIcmpHeader.id != (USHORT)GetCurrentProcessId()) { - /* FIXME */ - /* we've picked up a packet not related to this process - * probably from another local program. We ignore it */ -#ifdef DGB - _tprintf(_T("header id, process id %d"), TTLExceedHdr->OrigIcmpHeader.id, GetCurrentProcessId()); -#endif /* DBG */ - //_tprintf(_T("oops "); - return -1; - } - _tprintf(_T("%3Ld ms"), (lTimeEnd - lTimeStart) / TicksPerMs.QuadPart); - return 0; - case ECHO_REPLY : - if (IcmpHdr->icmpheader.id != (USHORT)GetCurrentProcessId()) { - /* FIXME */ - /* we've picked up a packet not related to this process - * probably from another local program. We ignore it */ -#ifdef DGB - _tprintf(_T("\nPicked up wrong packet. icmpheader.id = %d and process id = %d"), IcmpHdr->icmpheader.id, GetCurrentProcessId()); -#endif /* DBG */ - //_tprintf(_T("oops "); - return -1; - } - _tprintf(_T("%3Ld ms"), (lTimeEnd - lTimeStart) / TicksPerMs.QuadPart); - return 1; - case DEST_UNREACHABLE : - _tprintf(_T(" * ")); - return 2; - default : - /* unknown ICMP packet */ - return -3; - } -} - - -/* - * - * Get the system time using preformance counters if available, - * otherwise fall back to GetTickCount() - * - */ - -LONG GetTime(VOID) -{ - LARGE_INTEGER Time; - - if (bUsePerformanceCounter) { - if (QueryPerformanceCounter(&Time) == 0) { - Time.u.LowPart = (DWORD)GetTickCount(); - Time.u.HighPart = 0; - return (LONGLONG)Time.u.LowPart; - } - } else { - Time.u.LowPart = (DWORD)GetTickCount(); - Time.u.HighPart = 0; - return (LONGLONG)Time.u.LowPart; - } - return Time.QuadPart; -} - - -/* - * - * Calculate packet checksum. - * - */ -WORD CheckSum(PUSHORT data, UINT size) -{ - DWORD dwSum = 0; - - while (size > 1) { - dwSum += *data++; - size -= sizeof(USHORT); - } - - if (size) - dwSum += *(UCHAR*)data; - - dwSum = (dwSum >> 16) + (dwSum & 0xFFFF); - dwSum += (dwSum >> 16); - - return (USHORT)(~dwSum); -} - - -/* - * - * print program usage to screen - * - */ -VOID Usage(VOID) -{ - _tprintf(_T("\nUsage: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name\n\n")); - _tprintf(_T("Options:\n")); - _tprintf(_T(" -d Do not resolve addresses to hostnames.\n")); - _tprintf(_T(" -h maximum_hops Maximum number of hops to search for target.\n")); - _tprintf(_T(" -j host-list Loose source route along host-list.\n")); - _tprintf(_T(" -w timeout Wait timeout milliseconds for each reply.\n\n")); - - /* temp notes to stop user questions until getnameinfo/gethostbyaddr and getsockopt are implemented */ - _tprintf(_T("NOTES\n-----\n" - "- Setting TTL values is not currently supported in ReactOS, so the trace will\n" - " jump straight to the destination. This feature will be implemented soon.\n" - "- Host info is not currently available in ReactOS and will fail with strange\n" - " results. Use -d to force it not to resolve IP's.\n" - "- For testing purposes, all should work as normal in a Windows environment\n\n")); -} - - - -/* - * - * Program entry point - * - */ -int main(int argc, char* argv[]) -{ - if (!ParseCmdline(argc, _argv)) return -1; - - Driver(); - - return 0; -} +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS traceroute utility + * FILE: apps/utils/net/tracert/tracert.c + * PURPOSE: trace a packets route through a network + * PROGRAMMERS: Ged Murphy (gedmurphy@gmail.com) + * REVISIONS: + * GM 03/05/05 Created + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include "tracert.h" + +#define WIN32_LEAN_AND_MEAN + +#ifdef DBG +#undef DBG +#endif + +/* + * globals + */ +SOCKET icmpSock; // socket descriptor +SOCKADDR_IN source, dest; // source and destination address info +ECHO_REPLY_HEADER sendpacket; // ICMP echo packet +IPv4_HEADER recvpacket; // return reveive packet + +BOOL bUsePerformanceCounter; // whether to use the high res performance counter +LARGE_INTEGER TicksPerMs; // number of millisecs in relation to proc freq +LARGE_INTEGER TicksPerUs; // number of microsecs in relation to proc freq +LONGLONG lTimeStart; // send packet, timer start +LONGLONG lTimeEnd; // receive packet, timer end + +CHAR cHostname[256]; // target hostname +CHAR cDestIP[18]; // target IP + + +/* + * command line options + */ +BOOL bResolveAddresses = TRUE; // -d MS ping defaults to true. +INT iMaxHops = 30; // -h Max number of hops before trace ends +INT iHostList; // -j @UNIMPLEMENTED@ +INT iTimeOut = 2000; // -w time before packet times out + + + + +/* + * + * Parse command line parameters and set any options + * + */ +BOOL ParseCmdline(int argc, char* argv[]) +{ + int i; + + if (argc < 2) + { + Usage(); + return FALSE; + } + + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-') { + switch (argv[i][1]) { + case 'd': bResolveAddresses = FALSE; + break; + case 'h': sscanf(argv[i+1], "%d", &iMaxHops); + break; + case 'l': break; /* @unimplemented@ */ + case 'w': sscanf(argv[i+1], "%d", &iTimeOut); + break; + default: + _tprintf(_T("%s is not a valid option.\n"), argv[i]); + Usage(); + return FALSE; + } + } else { + /* copy target address */ + strncpy(cHostname, argv[i], 255); + + } + } + + return TRUE; +} + + + +/* + * + * Driver function, controls the traceroute program + * + */ +INT Driver(VOID) { + + INT i; + INT iHopCount = 1; // hop counter. default max is 30 + INT iSeqNum = 0; // initialise packet sequence number + INT iTTL = 1; // set initial packet TTL to 1 + BOOL bFoundTarget = FALSE; // Have we reached our destination yet + BOOL bAwaitPacket; // indicates whether we have recieved a good packet + INT iDecRes; // DecodeResponse return value + INT iRecieveReturn; // RecieveReturn return value + INT iNameInfoRet; // getnameinfo return value + INT iPacketSize = PACKET_SIZE; // packet size + WORD wHeaderLen; // header length + PECHO_REPLY_HEADER icmphdr; + + + //temps for getting host name + CHAR cHost[256]; + CHAR cServ[256]; + CHAR *ip; + + /* setup winsock */ + WSADATA wsaData; + + /* check for winsock 2 */ + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { +#ifdef DBG + _tprintf(_T("WSAStartup failed.\n")); +#endif /* DBG */ + exit(1); + } + + SetupTimingMethod(); + + /* setup target info */ + ResolveHostname(); + + /* print standard tracing info to screen */ + _tprintf(_T("\nTracing route to %s [%s]\n"), cHostname, cDestIP); + _tprintf(_T("over a maximum of %d hop"), iMaxHops); + iMaxHops > 1 ? _tprintf(_T("s:\n\n")) : _tprintf(_T(":\n\n")); + + /* run until we hit either max hops, or we recieve 3 echo replys */ + while ((iHopCount <= iMaxHops) && (bFoundTarget != TRUE)) { + _tprintf(_T("%3d "), iHopCount); + /* run 3 pings for each hop */ + for (i=0; i<3; i++) { + if (Setup(iTTL) != TRUE) { +#ifdef DBG + _tprintf(_T("error in Setup()\n")); +#endif /* DBG */ + WSACleanup(); + exit(1); + } + PreparePacket(iPacketSize, iSeqNum); + if (SendPacket(iPacketSize) != SOCKET_ERROR) { + /* loop until we get a good packet */ + bAwaitPacket = TRUE; + while (bAwaitPacket) { + /* Receive replies until we either get a successful + * read, or a fatal error occurs. */ + if ((iRecieveReturn = ReceivePacket(iPacketSize)) < 0) { + /* check the sequence number in the packet + * if it's bad, complain and wait for another packet + * , otherwise break */ + wHeaderLen = recvpacket.h_len * 4; + icmphdr = (ECHO_REPLY_HEADER *)((char*)&recvpacket + wHeaderLen); + if (icmphdr->icmpheader.seq != iSeqNum) { + _tprintf(_T("bad sequence number!\n")); + continue; + } else { + break; + } + } + + /* if RecievePacket timed out we don't bother decoding */ + if (iRecieveReturn != 1) { + iDecRes = DecodeResponse(iPacketSize, iSeqNum); + + switch (iDecRes) { + case 0 : bAwaitPacket = FALSE; /* time exceeded */ + break; + case 1 : bAwaitPacket = FALSE; /* echo reply */ + break; + case 2 : bAwaitPacket = FALSE; /* destination unreachable */ + break; +#ifdef DBG + case -1 : + _tprintf(_T("recieved foreign packet\n")); + break; + case -2 : + _tprintf(_T("error in DecodeResponse\n")); + break; + case -3 : + _tprintf(_T("unknown ICMP packet\n")); + break; +#endif /* DBG */ + default : break; + } + } else { + /* packet timed out. Don't wait for it again */ + bAwaitPacket = FALSE; + } + } + } + + iSeqNum++; + _tprintf(_T(" ")); + } + + if(bResolveAddresses) { + /* gethostbyaddr() and getnameinfo() are + * unimplemented in ROS at present. + * Alex has advised he will be implementing gethostbyaddr + * but as it's depricieted and getnameinfo is much nicer, + * I've used that for the time being for testing in Windows*/ + + //ip = inet_addr(inet_ntoa(source.sin_addr)); + //host = gethostbyaddr((char *)&ip, 4, 0); + + ip = inet_ntoa(source.sin_addr); + + iNameInfoRet = getnameinfo((SOCKADDR *)&source, + sizeof(SOCKADDR), + cHost, + 256, + cServ, + 256, + NI_NUMERICSERV); + if (iNameInfoRet == 0) { + /* if IP address resolved to a hostname, + * print the IP address after it */ + if (lstrcmpA(cHost, ip) != 0) { + _tprintf(_T("%s [%s]"), cHost, ip); + } else { + _tprintf(_T("%s"), cHost); + } + } else { + _tprintf(_T("error: %d"), WSAGetLastError()); +#ifdef DBG + _tprintf(_T(" getnameinfo failed: %d"), iNameInfoRet); +#endif /* DBG */ + } + + } else { + _tprintf(_T("%s"), inet_ntoa(source.sin_addr)); + } + _tprintf(_T("\n")); + + /* check if we've arrived at the target */ + if (strcmp(cDestIP, inet_ntoa(source.sin_addr)) == 0) { + bFoundTarget = TRUE; + } else { + iTTL++; + iHopCount++; + Sleep(500); + } + } + _tprintf(_T("\nTrace complete.\n")); + WSACleanup(); + + return 0; +} + +/* + * Establish if performance counters are available and + * set up timing figures in relation to processor frequency. + * If performance counters are not available, we'll be using + * gettickcount, so set the figures to 1 + * + */ +VOID SetupTimingMethod(VOID) +{ + LARGE_INTEGER PerformanceCounterFrequency; + + /* check if performance counters are available */ + bUsePerformanceCounter = QueryPerformanceFrequency(&PerformanceCounterFrequency); + if (bUsePerformanceCounter) { + /* restrict execution to first processor on SMP systems */ + if (SetThreadAffinityMask(GetCurrentThread(), 1) == 0) { + bUsePerformanceCounter = FALSE; + } + + TicksPerMs.QuadPart = PerformanceCounterFrequency.QuadPart / 1000; + TicksPerUs.QuadPart = PerformanceCounterFrequency.QuadPart / 1000000; + } + + if (!bUsePerformanceCounter) { + TicksPerMs.QuadPart = 1; + TicksPerUs.QuadPart = 1; + } +} + + +/* + * + * Check for a hostname or dotted deciamal for our target. + * If we have a hostname, resolve to an IP and store it, else + * just store the target IP address. Also set up other key + * SOCKADDR_IN members needed for the connection. + * + */ +VOID ResolveHostname(VOID) +{ + HOSTENT *hp; + ULONG addr; + + memset(&dest, 0, sizeof(dest)); + + addr = inet_addr(cHostname); + /* if address is not a dotted decimal */ + if (addr == INADDR_NONE) { + hp = gethostbyname(cHostname); + if (hp != 0) { + memcpy(&dest.sin_addr, hp->h_addr, hp->h_length); + //dest.sin_addr = *((struct in_addr *)hp->h_addr); + dest.sin_family = hp->h_addrtype; + } else { + _tprintf(_T("Unable to resolve target system name %s.\n"), cHostname); + WSACleanup(); + exit(1); + } + } else { + dest.sin_addr.s_addr = addr; + dest.sin_family = AF_INET; + } + /* copy destination IP address into a string */ + strcpy(cDestIP, inet_ntoa(dest.sin_addr)); +} + + + +/* + * + * Create our socket which will be used for sending and recieving, + * Socket Type is raw, Protocol is ICMP. Also set the TTL value which will be + * set in the outgoing IP packet. + * + */ +INT Setup(INT iTTL) +{ + INT iSockRet; + + /* create raw socket */ + icmpSock = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, 0, 0, 0); + if (icmpSock == INVALID_SOCKET) { + _tprintf(_T("Could not create socket : %d.\n"), WSAGetLastError()); + if (WSAGetLastError() == WSAEACCES) { + _tprintf(_T("\n\nYou must be an administrator to run this program!\n\n")); + WSACleanup(); + exit(1); + } + return FALSE; + } + + /* setup for TTL */ + iSockRet = setsockopt(icmpSock, IPPROTO_IP, IP_TTL, (const char *)&iTTL, sizeof(iTTL)); + if (iSockRet == SOCKET_ERROR) { + _tprintf(_T("TTL setsockopt failed : %d. \n"), WSAGetLastError()); + return FALSE; + } + + return TRUE; +} + + + +/* + * Prepare the ICMP echo request packet for sending. + * Calculate the packet checksum + * + */ +VOID PreparePacket(INT iPacketSize, INT iSeqNum) +{ + /* assemble ICMP echo request packet */ + sendpacket.icmpheader.type = ECHO_REQUEST; + sendpacket.icmpheader.code = 0; + sendpacket.icmpheader.checksum = 0; + sendpacket.icmpheader.id = (USHORT)GetCurrentProcessId(); + sendpacket.icmpheader.seq = iSeqNum; + + /* calculate checksum of packet */ + sendpacket.icmpheader.checksum = CheckSum((PUSHORT)&sendpacket, sizeof(ICMP_HEADER) + iPacketSize); +} + + + +/* + * + * Get the system time and send the ICMP packet to the destination + * address. + * + */ +INT SendPacket(INT datasize) +{ + INT iSockRet; + INT iPacketSize; + + iPacketSize = sizeof(ECHO_REPLY_HEADER) + datasize; + +#ifdef DBG + _tprintf(_T("\nsending packet of %d bytes\n"), iPacketSize); +#endif /* DBG */ + + /* get time packet was sent */ + lTimeStart = GetTime(); + + iSockRet = sendto(icmpSock, //socket + (char *)&sendpacket, //buffer + iPacketSize, //size of buffer + 0, //flags + (SOCKADDR *)&dest, //destination + sizeof(dest)); //address length + + if (iSockRet == SOCKET_ERROR) { + if (WSAGetLastError() == WSAEACCES) { + _tprintf(_T("\n\nYou must be an administrator to run this program!\n\n")); + exit(1); + WSACleanup(); + } else { +#ifdef DBG + _tprintf(_T("sendto failed %d\n"), WSAGetLastError()); +#endif /* DBG */ + return FALSE; + } + } +#ifdef DBG + _tprintf(_T("sent %d bytes\n"), iSockRet); +#endif /* DBG */ + + /* return number of bytes sent */ + return iSockRet; +} + + + +/* + * + * Set up a timeout value and put the socket in a select poll. + * Wait until we recieve an IPv4 reply packet in reply to the ICMP + * echo request packet and get the time the packet was recieved. + * If we don't recieve a packet, do some checking to establish why. + * + */ +INT ReceivePacket(INT datasize) +{ + TIMEVAL timeVal; + FD_SET readFDS; + int iSockRet = 0, iSelRet; + int iFromLen; + int iPacketSize; + + /* allow for a larger recv buffer to store ICMP TTL + * exceed, IP header and orginal ICMP request */ + iPacketSize = MAX_REC_SIZE + datasize; + + iFromLen = sizeof(source); + +#ifdef DBG + _tprintf(_T("receiving packet. Available buffer, %d bytes\n"), iPacketSize); +#endif /* DBG */ + + /* monitor icmpSock for incomming connections */ + FD_ZERO(&readFDS); + FD_SET(icmpSock, &readFDS); + + /* set timeout values */ + timeVal.tv_sec = iTimeOut / 1000; + timeVal.tv_usec = iTimeOut % 1000; + + iSelRet = select(0, &readFDS, NULL, NULL, &timeVal); + + if ((iSelRet != SOCKET_ERROR) && (iSelRet != 0)) { + iSockRet = recvfrom(icmpSock, //socket + (char *)&recvpacket, //buffer + iPacketSize, //size of buffer + 0, //flags + (SOCKADDR *)&source, //source address + &iFromLen); //pointer to address length + /* get time packet was recieved */ + lTimeEnd = GetTime(); + /* if socket timed out */ + } else if (iSelRet == 0) { + _tprintf(_T(" * ")); + return 1; + } else if (iSelRet == SOCKET_ERROR) { + _tprintf(_T("select() failed in sendPacket() %d\n"), WSAGetLastError()); + return -1; + } + + + if (iSockRet == SOCKET_ERROR) { + _tprintf(_T("recvfrom failed: %d\n"), WSAGetLastError()); + return -2; + } +#ifdef DBG + else { + _tprintf(_T("reveived %d bytes\n"), iSockRet); + } +#endif /* DBG */ + + return 0; +} + + + +/* + * + * Cast the IPv4 packet to an echo reply and to a TTL exceed. + * Check the 'type' field to establish what was recieved, and + * ensure the packet is related to the originating process. + * It all is well, print the time taken for the round trip. + * + */ +INT DecodeResponse(INT iPacketSize, INT iSeqNum) +{ + unsigned short header_len = recvpacket.h_len * 4; + /* cast the recieved packet into an ECHO reply and a TTL Exceed so we can check the ID*/ + ECHO_REPLY_HEADER *IcmpHdr = (ECHO_REPLY_HEADER *)((char*)&recvpacket + header_len); + TTL_EXCEED_HEADER *TTLExceedHdr = (TTL_EXCEED_HEADER *)((char *)&recvpacket + header_len); + + /* Make sure the reply is ok */ + if (iPacketSize < header_len + ICMP_MIN_SIZE) { + _tprintf(_T("too few bytes from %s\n"), inet_ntoa(dest.sin_addr)); + return -2; + } + + switch (IcmpHdr->icmpheader.type) { + case TTL_EXCEEDED : + if (TTLExceedHdr->OrigIcmpHeader.id != (USHORT)GetCurrentProcessId()) { + /* FIXME */ + /* we've picked up a packet not related to this process + * probably from another local program. We ignore it */ +#ifdef DGB + _tprintf(_T("header id, process id %d"), TTLExceedHdr->OrigIcmpHeader.id, GetCurrentProcessId()); +#endif /* DBG */ + //_tprintf(_T("oops "); + return -1; + } + _tprintf(_T("%3Ld ms"), (lTimeEnd - lTimeStart) / TicksPerMs.QuadPart); + return 0; + case ECHO_REPLY : + if (IcmpHdr->icmpheader.id != (USHORT)GetCurrentProcessId()) { + /* FIXME */ + /* we've picked up a packet not related to this process + * probably from another local program. We ignore it */ +#ifdef DGB + _tprintf(_T("\nPicked up wrong packet. icmpheader.id = %d and process id = %d"), IcmpHdr->icmpheader.id, GetCurrentProcessId()); +#endif /* DBG */ + //_tprintf(_T("oops "); + return -1; + } + _tprintf(_T("%3Ld ms"), (lTimeEnd - lTimeStart) / TicksPerMs.QuadPart); + return 1; + case DEST_UNREACHABLE : + _tprintf(_T(" * ")); + return 2; + default : + /* unknown ICMP packet */ + return -3; + } +} + + +/* + * + * Get the system time using preformance counters if available, + * otherwise fall back to GetTickCount() + * + */ + +LONG GetTime(VOID) +{ + LARGE_INTEGER Time; + + if (bUsePerformanceCounter) { + if (QueryPerformanceCounter(&Time) == 0) { + Time.u.LowPart = (DWORD)GetTickCount(); + Time.u.HighPart = 0; + return (LONGLONG)Time.u.LowPart; + } + } else { + Time.u.LowPart = (DWORD)GetTickCount(); + Time.u.HighPart = 0; + return (LONGLONG)Time.u.LowPart; + } + return Time.QuadPart; +} + + +/* + * + * Calculate packet checksum. + * + */ +WORD CheckSum(PUSHORT data, UINT size) +{ + DWORD dwSum = 0; + + while (size > 1) { + dwSum += *data++; + size -= sizeof(USHORT); + } + + if (size) + dwSum += *(UCHAR*)data; + + dwSum = (dwSum >> 16) + (dwSum & 0xFFFF); + dwSum += (dwSum >> 16); + + return (USHORT)(~dwSum); +} + + +/* + * + * print program usage to screen + * + */ +VOID Usage(VOID) +{ + _tprintf(_T("\nUsage: tracert [-d] [-h maximum_hops] [-j host-list] [-w timeout] target_name\n\n")); + _tprintf(_T("Options:\n")); + _tprintf(_T(" -d Do not resolve addresses to hostnames.\n")); + _tprintf(_T(" -h maximum_hops Maximum number of hops to search for target.\n")); + _tprintf(_T(" -j host-list Loose source route along host-list.\n")); + _tprintf(_T(" -w timeout Wait timeout milliseconds for each reply.\n\n")); + + /* temp notes to stop user questions until getnameinfo/gethostbyaddr and getsockopt are implemented */ + _tprintf(_T("NOTES\n-----\n" + "- Setting TTL values is not currently supported in ReactOS, so the trace will\n" + " jump straight to the destination. This feature will be implemented soon.\n" + "- Host info is not currently available in ReactOS and will fail with strange\n" + " results. Use -d to force it not to resolve IP's.\n" + "- For testing purposes, all should work as normal in a Windows environment\n\n")); +} + + + +/* + * + * Program entry point + * + */ +int main(int argc, char* argv[]) +{ + if (!ParseCmdline(argc, _argv)) return -1; + + Driver(); + + return 0; +} diff --git a/reactos/apps/utils/net/tracert/tracert.h b/reactos/apps/utils/net/tracert/tracert.h index 1fc27e9fc42..4ac7ea62436 100644 --- a/reactos/apps/utils/net/tracert/tracert.h +++ b/reactos/apps/utils/net/tracert/tracert.h @@ -1,80 +1,80 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS traceroute utility - * FILE: apps/utils/net/tracert/tracert.h - * PURPOSE: trace a packets route through a network - * PROGRAMMERS: Ged Murphy (gedmurphy@gmail.com) - * REVISIONS: - * GM 03/05/05 Created - */ - -#define ECHO_REPLY 0 -#define DEST_UNREACHABLE 3 -#define ECHO_REQUEST 8 -#define TTL_EXCEEDED 11 - -#define ICMP_MIN_SIZE 8 -#define ICMP_MAX_SIZE 65535 -#define PACKET_SIZE 32 -/* we need this for packets which have the 'dont fragment' - * bit set, as they can get quite large otherwise - * (I've seen some reach 182 bytes */ -#define MAX_REC_SIZE 200 - -/* pack the structures */ -#pragma pack(1) - -/* IPv4 Header, 20 bytes */ -typedef struct IPv4Header { - BYTE h_len:4; - BYTE version:4; - BYTE tos; - USHORT length; - USHORT id; - USHORT flag_frag; - BYTE ttl; - BYTE proto; - USHORT checksum; - ULONG source; - ULONG dest; -} IPv4_HEADER, *PIPv4_HEADER; - -/* ICMP Header, 8 bytes */ -typedef struct ICMPHeader { - BYTE type; - BYTE code; - USHORT checksum; - USHORT id; // not used in time exceeded - USHORT seq; // not used in time exceeded -} ICMP_HEADER, *PICMP_HEADER; - -/* ICMP Echo Reply Header, 12 bytes */ -typedef struct EchoReplyHeader { - struct ICMPHeader icmpheader; - struct timeval timestamp; -} ECHO_REPLY_HEADER, *PECHO_REPLY_HEADER; - -/* ICMP Echo Reply Header, 12 bytes */ -typedef struct TTLExceedHeader { - struct ICMPHeader icmpheader; - struct IPv4Header ipheader; - struct ICMPHeader OrigIcmpHeader; -} TTL_EXCEED_HEADER, *PTTL_EXCEED_HEADER; - -/* return to normal */ -#pragma pack() - - -/* function definitions */ -//BOOL ParseCmdline(int argc, char* argv[]); -INT Driver(void); -INT Setup(INT ttl); -VOID SetupTimingMethod(void); -VOID ResolveHostname(void); -VOID PreparePacket(INT packetSize, INT seqNum); -INT SendPacket(INT datasize); -INT ReceivePacket(INT datasize); -INT DecodeResponse(INT packetSize, INT seqNum); -LONG GetTime(void); -WORD CheckSum(PUSHORT data, UINT size); -VOID Usage(void); +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS traceroute utility + * FILE: apps/utils/net/tracert/tracert.h + * PURPOSE: trace a packets route through a network + * PROGRAMMERS: Ged Murphy (gedmurphy@gmail.com) + * REVISIONS: + * GM 03/05/05 Created + */ + +#define ECHO_REPLY 0 +#define DEST_UNREACHABLE 3 +#define ECHO_REQUEST 8 +#define TTL_EXCEEDED 11 + +#define ICMP_MIN_SIZE 8 +#define ICMP_MAX_SIZE 65535 +#define PACKET_SIZE 32 +/* we need this for packets which have the 'dont fragment' + * bit set, as they can get quite large otherwise + * (I've seen some reach 182 bytes */ +#define MAX_REC_SIZE 200 + +/* pack the structures */ +#pragma pack(1) + +/* IPv4 Header, 20 bytes */ +typedef struct IPv4Header { + BYTE h_len:4; + BYTE version:4; + BYTE tos; + USHORT length; + USHORT id; + USHORT flag_frag; + BYTE ttl; + BYTE proto; + USHORT checksum; + ULONG source; + ULONG dest; +} IPv4_HEADER, *PIPv4_HEADER; + +/* ICMP Header, 8 bytes */ +typedef struct ICMPHeader { + BYTE type; + BYTE code; + USHORT checksum; + USHORT id; // not used in time exceeded + USHORT seq; // not used in time exceeded +} ICMP_HEADER, *PICMP_HEADER; + +/* ICMP Echo Reply Header, 12 bytes */ +typedef struct EchoReplyHeader { + struct ICMPHeader icmpheader; + struct timeval timestamp; +} ECHO_REPLY_HEADER, *PECHO_REPLY_HEADER; + +/* ICMP Echo Reply Header, 12 bytes */ +typedef struct TTLExceedHeader { + struct ICMPHeader icmpheader; + struct IPv4Header ipheader; + struct ICMPHeader OrigIcmpHeader; +} TTL_EXCEED_HEADER, *PTTL_EXCEED_HEADER; + +/* return to normal */ +#pragma pack() + + +/* function definitions */ +//BOOL ParseCmdline(int argc, char* argv[]); +INT Driver(void); +INT Setup(INT ttl); +VOID SetupTimingMethod(void); +VOID ResolveHostname(void); +VOID PreparePacket(INT packetSize, INT seqNum); +INT SendPacket(INT datasize); +INT ReceivePacket(INT datasize); +INT DecodeResponse(INT packetSize, INT seqNum); +LONG GetTime(void); +WORD CheckSum(PUSHORT data, UINT size); +VOID Usage(void); diff --git a/reactos/apps/utils/winetest/port.h b/reactos/apps/utils/winetest/port.h index 57a7a87fc47..5b3d8581f74 100644 --- a/reactos/apps/utils/winetest/port.h +++ b/reactos/apps/utils/winetest/port.h @@ -1,469 +1,469 @@ -/* - * Wine porting definitions - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_WINE_PORT_H -#define __WINE_WINE_PORT_H - -#ifndef __WINE_CONFIG_H -# error You must include config.h to use this header -#endif - -#define _GNU_SOURCE /* for pread/pwrite */ -#include -#include -#include -#include -#ifdef HAVE_DIRECT_H -# include -#endif -#ifdef HAVE_IO_H -# include -#endif -#ifdef HAVE_PROCESS_H -# include -#endif -#include -#ifdef HAVE_UNISTD_H -# include -#endif - - -/**************************************************************** - * Type definitions - */ - -#ifndef HAVE_MODE_T -typedef int mode_t; -#endif -#ifndef HAVE_OFF_T -typedef long off_t; -#endif -#ifndef HAVE_PID_T -typedef int pid_t; -#endif -#ifndef HAVE_SIZE_T -typedef unsigned int size_t; -#endif -#ifndef HAVE_SSIZE_T -typedef int ssize_t; -#endif -#ifndef HAVE_FSBLKCNT_T -typedef unsigned long fsblkcnt_t; -#endif -#ifndef HAVE_FSFILCNT_T -typedef unsigned long fsfilcnt_t; -#endif - -#ifndef HAVE_STRUCT_STATVFS_F_BLOCKS -struct statvfs -{ - unsigned long f_bsize; - unsigned long f_frsize; - fsblkcnt_t f_blocks; - fsblkcnt_t f_bfree; - fsblkcnt_t f_bavail; - fsfilcnt_t f_files; - fsfilcnt_t f_ffree; - fsfilcnt_t f_favail; - unsigned long f_fsid; - unsigned long f_flag; - unsigned long f_namemax; -}; -#endif /* HAVE_STRUCT_STATVFS_F_BLOCKS */ - - -/**************************************************************** - * Macro definitions - */ - -#ifdef HAVE_DLFCN_H -#include -#else -#define RTLD_LAZY 0x001 -#define RTLD_NOW 0x002 -#define RTLD_GLOBAL 0x100 -#endif - -#if !defined(HAVE_FTRUNCATE) && defined(HAVE_CHSIZE) -#define ftruncate chsize -#endif - -#if !defined(HAVE_POPEN) && defined(HAVE__POPEN) -#define popen _popen -#endif - -#if !defined(HAVE_PCLOSE) && defined(HAVE__PCLOSE) -#define pclose _pclose -#endif - -#if !defined(HAVE_SNPRINTF) && defined(HAVE__SNPRINTF) -#define snprintf _snprintf -#endif - -#if !defined(HAVE_VSNPRINTF) && defined(HAVE__VSNPRINTF) -#define vsnprintf _vsnprintf -#endif - -#ifndef S_ISLNK -# define S_ISLNK(mod) (0) -#endif - -#ifndef S_ISSOCK -# define S_ISSOCK(mod) (0) -#endif - -#ifndef S_ISDIR -# define S_ISDIR(mod) (((mod) & _S_IFMT) == _S_IFDIR) -#endif - -#ifndef S_ISCHR -# define S_ISCHR(mod) (((mod) & _S_IFMT) == _S_IFCHR) -#endif - -#ifndef S_ISFIFO -# define S_ISFIFO(mod) (((mod) & _S_IFMT) == _S_IFIFO) -#endif - -#ifndef S_ISREG -# define S_ISREG(mod) (((mod) & _S_IFMT) == _S_IFREG) -#endif - -#ifndef S_IWUSR -# define S_IWUSR 0 -#endif - -/* So we open files in 64 bit access mode on Linux */ -#ifndef O_LARGEFILE -# define O_LARGEFILE 0 -#endif - -#ifndef O_NONBLOCK -# define O_NONBLOCK 0 -#endif - -#ifndef O_BINARY -# define O_BINARY 0 -#endif - -#if !defined(S_IXUSR) && defined(S_IEXEC) -# define S_IXUSR S_IEXEC -#endif -#if !defined(S_IXGRP) && defined(S_IEXEC) -# define S_IXGRP S_IEXEC -#endif -#if !defined(S_IXOTH) && defined(S_IEXEC) -# define S_IXOTH S_IEXEC -#endif - - -/**************************************************************** - * Constants - */ - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -#ifndef M_PI_2 -#define M_PI_2 1.570796326794896619 -#endif - - -/* Macros to define assembler functions somewhat portably */ - -#if defined(__GNUC__) && !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(__APPLE__) -# define __ASM_GLOBAL_FUNC(name,code) \ - __asm__( ".text\n\t" \ - ".align 4\n\t" \ - ".globl " __ASM_NAME(#name) "\n\t" \ - __ASM_FUNC(#name) "\n" \ - __ASM_NAME(#name) ":\n\t" \ - code \ - "\n\t.previous" ); -#else /* defined(__GNUC__) && !defined(__MINGW32__) && !defined(__APPLE__) */ -# define __ASM_GLOBAL_FUNC(name,code) \ - void __asm_dummy_##name(void) { \ - asm( ".align 4\n\t" \ - ".globl " __ASM_NAME(#name) "\n\t" \ - __ASM_FUNC(#name) "\n" \ - __ASM_NAME(#name) ":\n\t" \ - code ); \ - } -#endif /* __GNUC__ */ - - -/* Constructor functions */ - -#ifdef __GNUC__ -# define DECL_GLOBAL_CONSTRUCTOR(func) \ - static void func(void) __attribute__((constructor)); \ - static void func(void) -#elif defined(__i386__) -# define DECL_GLOBAL_CONSTRUCTOR(func) \ - static void __dummy_init_##func(void) { \ - asm(".section .init,\"ax\"\n\t" \ - "call " #func "\n\t" \ - ".previous"); } \ - static void func(void) -#elif defined(__sparc__) -# define DECL_GLOBAL_CONSTRUCTOR(func) \ - static void __dummy_init_##func(void) { \ - asm("\t.section \".init\",#alloc,#execinstr\n" \ - "\tcall " #func "\n" \ - "\tnop\n" \ - "\t.section \".text\",#alloc,#execinstr\n" ); } \ - static void func(void) -#else -# error You must define the DECL_GLOBAL_CONSTRUCTOR macro for your platform -#endif - - -/* Register functions */ - -#ifdef __i386__ -#define DEFINE_REGS_ENTRYPOINT( name, fn, args, pop_args ) \ - __ASM_GLOBAL_FUNC( name, \ - "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t" \ - ".long " __ASM_NAME(#fn) "\n\t" \ - ".byte " #args "," #pop_args ) -/* FIXME: add support for other CPUs */ -#endif /* __i386__ */ - - -/**************************************************************** - * Function definitions (only when using libwine_port) - */ - -#ifndef NO_LIBWINE_PORT - -#ifndef HAVE_FSTATVFS -int fstatvfs( int fd, struct statvfs *buf ); -#endif - -#ifndef HAVE_GETOPT_LONG -extern char *optarg; -extern int optind; -extern int opterr; -extern int optopt; -struct option; - -#ifndef HAVE_STRUCT_OPTION_NAME -struct option -{ - const char *name; - int has_arg; - int *flag; - int val; -}; -#endif - -extern int getopt_long (int ___argc, char *const *___argv, - const char *__shortopts, - const struct option *__longopts, int *__longind); -extern int getopt_long_only (int ___argc, char *const *___argv, - const char *__shortopts, - const struct option *__longopts, int *__longind); -#endif /* HAVE_GETOPT_LONG */ - -#ifndef HAVE_FFS -int ffs( int x ); -#endif - -#ifndef HAVE_FUTIMES -struct timeval; -int futimes(int fd, const struct timeval tv[2]); -#endif - -#ifndef HAVE_GETPAGESIZE -size_t getpagesize(void); -#endif /* HAVE_GETPAGESIZE */ - -#ifndef HAVE_GETTID -pid_t gettid(void); -#endif /* HAVE_GETTID */ - -#ifndef HAVE_LSTAT -int lstat(const char *file_name, struct stat *buf); -#endif /* HAVE_LSTAT */ - -#ifndef HAVE_MEMMOVE -void *memmove(void *dest, const void *src, size_t len); -#endif /* !defined(HAVE_MEMMOVE) */ - -#ifndef HAVE_PREAD -ssize_t pread( int fd, void *buf, size_t count, off_t offset ); -#endif /* HAVE_PREAD */ - -#ifndef HAVE_PWRITE -ssize_t pwrite( int fd, const void *buf, size_t count, off_t offset ); -#endif /* HAVE_PWRITE */ - -#ifndef HAVE_READLINK -int readlink( const char *path, char *buf, size_t size ); -#endif /* HAVE_READLINK */ - -#ifndef HAVE_SIGSETJMP -# include -typedef jmp_buf sigjmp_buf; -int sigsetjmp( sigjmp_buf buf, int savesigs ); -void siglongjmp( sigjmp_buf buf, int val ); -#endif /* HAVE_SIGSETJMP */ - -#ifndef HAVE_STATVFS -int statvfs( const char *path, struct statvfs *buf ); -#endif - -#ifndef HAVE_STRNCASECMP -# ifndef HAVE__STRNICMP -int strncasecmp(const char *str1, const char *str2, size_t n); -# else -# define strncasecmp _strnicmp -# endif -#endif /* !defined(HAVE_STRNCASECMP) */ - -#ifndef HAVE_STRERROR -const char *strerror(int err); -#endif /* !defined(HAVE_STRERROR) */ - -#ifndef HAVE_STRCASECMP -# ifndef HAVE__STRICMP -int strcasecmp(const char *str1, const char *str2); -# else -# define strcasecmp _stricmp -# endif -#endif /* !defined(HAVE_STRCASECMP) */ - -#ifndef HAVE_USLEEP -int usleep (unsigned int useconds); -#endif /* !defined(HAVE_USLEEP) */ - -#ifdef __i386__ -static inline void *memcpy_unaligned( void *dst, const void *src, size_t size ) -{ - return memcpy( dst, src, size ); -} -#else -extern void *memcpy_unaligned( void *dst, const void *src, size_t size ); -#endif /* __i386__ */ - -extern int mkstemps(char *template, int suffix_len); - -/* Process creation flags */ -#ifndef _P_WAIT -# define _P_WAIT 0 -# define _P_NOWAIT 1 -# define _P_OVERLAY 2 -# define _P_NOWAITO 3 -# define _P_DETACH 4 -#endif -#ifndef HAVE_SPAWNVP -extern int spawnvp(int mode, const char *cmdname, const char * const argv[]); -#endif - -/* Interlocked functions */ - -#if defined(__i386__) && defined(__GNUC__) - -extern inline long interlocked_cmpxchg( long *dest, long xchg, long compare ); -extern inline void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare ); -extern inline long interlocked_xchg( long *dest, long val ); -extern inline void *interlocked_xchg_ptr( void **dest, void *val ); -extern inline long interlocked_xchg_add( long *dest, long incr ); - -extern inline long interlocked_cmpxchg( long *dest, long xchg, long compare ) -{ - long ret; - __asm__ __volatile__( "lock; cmpxchgl %2,(%1)" - : "=a" (ret) : "r" (dest), "r" (xchg), "0" (compare) : "memory" ); - return ret; -} - -extern inline void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare ) -{ - void *ret; - __asm__ __volatile__( "lock; cmpxchgl %2,(%1)" - : "=a" (ret) : "r" (dest), "r" (xchg), "0" (compare) : "memory" ); - return ret; -} - -extern inline long interlocked_xchg( long *dest, long val ) -{ - long ret; - __asm__ __volatile__( "lock; xchgl %0,(%1)" - : "=r" (ret) : "r" (dest), "0" (val) : "memory" ); - return ret; -} - -extern inline void *interlocked_xchg_ptr( void **dest, void *val ) -{ - void *ret; - __asm__ __volatile__( "lock; xchgl %0,(%1)" - : "=r" (ret) : "r" (dest), "0" (val) : "memory" ); - return ret; -} - -extern inline long interlocked_xchg_add( long *dest, long incr ) -{ - long ret; - __asm__ __volatile__( "lock; xaddl %0,(%1)" - : "=r" (ret) : "r" (dest), "0" (incr) : "memory" ); - return ret; -} - -#else /* __i386___ && __GNUC__ */ - -extern long interlocked_cmpxchg( long *dest, long xchg, long compare ); -extern void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare ); -extern long interlocked_xchg( long *dest, long val ); -extern void *interlocked_xchg_ptr( void **dest, void *val ); -extern long interlocked_xchg_add( long *dest, long incr ); - -#endif /* __i386___ && __GNUC__ */ - -#else /* NO_LIBWINE_PORT */ - -#define __WINE_NOT_PORTABLE(func) func##_is_not_portable func##_is_not_portable - -#define ffs __WINE_NOT_PORTABLE(ffs) -#define fstatvfs __WINE_NOT_PORTABLE(fstatvfs) -#define futimes __WINE_NOT_PORTABLE(futimes) -#define getopt_long __WINE_NOT_PORTABLE(getopt_long) -#define getopt_long_only __WINE_NOT_PORTABLE(getopt_long_only) -#define getpagesize __WINE_NOT_PORTABLE(getpagesize) -#define interlocked_cmpxchg __WINE_NOT_PORTABLE(interlocked_cmpxchg) -#define interlocked_cmpxchg_ptr __WINE_NOT_PORTABLE(interlocked_cmpxchg_ptr) -#define interlocked_xchg __WINE_NOT_PORTABLE(interlocked_xchg) -#define interlocked_xchg_ptr __WINE_NOT_PORTABLE(interlocked_xchg_ptr) -#define interlocked_xchg_add __WINE_NOT_PORTABLE(interlocked_xchg_add) -#define lstat __WINE_NOT_PORTABLE(lstat) -#define memcpy_unaligned __WINE_NOT_PORTABLE(memcpy_unaligned) -#define memmove __WINE_NOT_PORTABLE(memmove) -#define pread __WINE_NOT_PORTABLE(pread) -#define pwrite __WINE_NOT_PORTABLE(pwrite) -#define spawnvp __WINE_NOT_PORTABLE(spawnvp) -#define statvfs __WINE_NOT_PORTABLE(statvfs) -#define strcasecmp __WINE_NOT_PORTABLE(strcasecmp) -#define strerror __WINE_NOT_PORTABLE(strerror) -#define strncasecmp __WINE_NOT_PORTABLE(strncasecmp) -#define usleep __WINE_NOT_PORTABLE(usleep) - -#endif /* NO_LIBWINE_PORT */ - -#endif /* !defined(__WINE_WINE_PORT_H) */ +/* + * Wine porting definitions + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_WINE_PORT_H +#define __WINE_WINE_PORT_H + +#ifndef __WINE_CONFIG_H +# error You must include config.h to use this header +#endif + +#define _GNU_SOURCE /* for pread/pwrite */ +#include +#include +#include +#include +#ifdef HAVE_DIRECT_H +# include +#endif +#ifdef HAVE_IO_H +# include +#endif +#ifdef HAVE_PROCESS_H +# include +#endif +#include +#ifdef HAVE_UNISTD_H +# include +#endif + + +/**************************************************************** + * Type definitions + */ + +#ifndef HAVE_MODE_T +typedef int mode_t; +#endif +#ifndef HAVE_OFF_T +typedef long off_t; +#endif +#ifndef HAVE_PID_T +typedef int pid_t; +#endif +#ifndef HAVE_SIZE_T +typedef unsigned int size_t; +#endif +#ifndef HAVE_SSIZE_T +typedef int ssize_t; +#endif +#ifndef HAVE_FSBLKCNT_T +typedef unsigned long fsblkcnt_t; +#endif +#ifndef HAVE_FSFILCNT_T +typedef unsigned long fsfilcnt_t; +#endif + +#ifndef HAVE_STRUCT_STATVFS_F_BLOCKS +struct statvfs +{ + unsigned long f_bsize; + unsigned long f_frsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsfilcnt_t f_favail; + unsigned long f_fsid; + unsigned long f_flag; + unsigned long f_namemax; +}; +#endif /* HAVE_STRUCT_STATVFS_F_BLOCKS */ + + +/**************************************************************** + * Macro definitions + */ + +#ifdef HAVE_DLFCN_H +#include +#else +#define RTLD_LAZY 0x001 +#define RTLD_NOW 0x002 +#define RTLD_GLOBAL 0x100 +#endif + +#if !defined(HAVE_FTRUNCATE) && defined(HAVE_CHSIZE) +#define ftruncate chsize +#endif + +#if !defined(HAVE_POPEN) && defined(HAVE__POPEN) +#define popen _popen +#endif + +#if !defined(HAVE_PCLOSE) && defined(HAVE__PCLOSE) +#define pclose _pclose +#endif + +#if !defined(HAVE_SNPRINTF) && defined(HAVE__SNPRINTF) +#define snprintf _snprintf +#endif + +#if !defined(HAVE_VSNPRINTF) && defined(HAVE__VSNPRINTF) +#define vsnprintf _vsnprintf +#endif + +#ifndef S_ISLNK +# define S_ISLNK(mod) (0) +#endif + +#ifndef S_ISSOCK +# define S_ISSOCK(mod) (0) +#endif + +#ifndef S_ISDIR +# define S_ISDIR(mod) (((mod) & _S_IFMT) == _S_IFDIR) +#endif + +#ifndef S_ISCHR +# define S_ISCHR(mod) (((mod) & _S_IFMT) == _S_IFCHR) +#endif + +#ifndef S_ISFIFO +# define S_ISFIFO(mod) (((mod) & _S_IFMT) == _S_IFIFO) +#endif + +#ifndef S_ISREG +# define S_ISREG(mod) (((mod) & _S_IFMT) == _S_IFREG) +#endif + +#ifndef S_IWUSR +# define S_IWUSR 0 +#endif + +/* So we open files in 64 bit access mode on Linux */ +#ifndef O_LARGEFILE +# define O_LARGEFILE 0 +#endif + +#ifndef O_NONBLOCK +# define O_NONBLOCK 0 +#endif + +#ifndef O_BINARY +# define O_BINARY 0 +#endif + +#if !defined(S_IXUSR) && defined(S_IEXEC) +# define S_IXUSR S_IEXEC +#endif +#if !defined(S_IXGRP) && defined(S_IEXEC) +# define S_IXGRP S_IEXEC +#endif +#if !defined(S_IXOTH) && defined(S_IEXEC) +# define S_IXOTH S_IEXEC +#endif + + +/**************************************************************** + * Constants + */ + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#ifndef M_PI_2 +#define M_PI_2 1.570796326794896619 +#endif + + +/* Macros to define assembler functions somewhat portably */ + +#if defined(__GNUC__) && !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(__APPLE__) +# define __ASM_GLOBAL_FUNC(name,code) \ + __asm__( ".text\n\t" \ + ".align 4\n\t" \ + ".globl " __ASM_NAME(#name) "\n\t" \ + __ASM_FUNC(#name) "\n" \ + __ASM_NAME(#name) ":\n\t" \ + code \ + "\n\t.previous" ); +#else /* defined(__GNUC__) && !defined(__MINGW32__) && !defined(__APPLE__) */ +# define __ASM_GLOBAL_FUNC(name,code) \ + void __asm_dummy_##name(void) { \ + asm( ".align 4\n\t" \ + ".globl " __ASM_NAME(#name) "\n\t" \ + __ASM_FUNC(#name) "\n" \ + __ASM_NAME(#name) ":\n\t" \ + code ); \ + } +#endif /* __GNUC__ */ + + +/* Constructor functions */ + +#ifdef __GNUC__ +# define DECL_GLOBAL_CONSTRUCTOR(func) \ + static void func(void) __attribute__((constructor)); \ + static void func(void) +#elif defined(__i386__) +# define DECL_GLOBAL_CONSTRUCTOR(func) \ + static void __dummy_init_##func(void) { \ + asm(".section .init,\"ax\"\n\t" \ + "call " #func "\n\t" \ + ".previous"); } \ + static void func(void) +#elif defined(__sparc__) +# define DECL_GLOBAL_CONSTRUCTOR(func) \ + static void __dummy_init_##func(void) { \ + asm("\t.section \".init\",#alloc,#execinstr\n" \ + "\tcall " #func "\n" \ + "\tnop\n" \ + "\t.section \".text\",#alloc,#execinstr\n" ); } \ + static void func(void) +#else +# error You must define the DECL_GLOBAL_CONSTRUCTOR macro for your platform +#endif + + +/* Register functions */ + +#ifdef __i386__ +#define DEFINE_REGS_ENTRYPOINT( name, fn, args, pop_args ) \ + __ASM_GLOBAL_FUNC( name, \ + "call " __ASM_NAME("__wine_call_from_32_regs") "\n\t" \ + ".long " __ASM_NAME(#fn) "\n\t" \ + ".byte " #args "," #pop_args ) +/* FIXME: add support for other CPUs */ +#endif /* __i386__ */ + + +/**************************************************************** + * Function definitions (only when using libwine_port) + */ + +#ifndef NO_LIBWINE_PORT + +#ifndef HAVE_FSTATVFS +int fstatvfs( int fd, struct statvfs *buf ); +#endif + +#ifndef HAVE_GETOPT_LONG +extern char *optarg; +extern int optind; +extern int opterr; +extern int optopt; +struct option; + +#ifndef HAVE_STRUCT_OPTION_NAME +struct option +{ + const char *name; + int has_arg; + int *flag; + int val; +}; +#endif + +extern int getopt_long (int ___argc, char *const *___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind); +extern int getopt_long_only (int ___argc, char *const *___argv, + const char *__shortopts, + const struct option *__longopts, int *__longind); +#endif /* HAVE_GETOPT_LONG */ + +#ifndef HAVE_FFS +int ffs( int x ); +#endif + +#ifndef HAVE_FUTIMES +struct timeval; +int futimes(int fd, const struct timeval tv[2]); +#endif + +#ifndef HAVE_GETPAGESIZE +size_t getpagesize(void); +#endif /* HAVE_GETPAGESIZE */ + +#ifndef HAVE_GETTID +pid_t gettid(void); +#endif /* HAVE_GETTID */ + +#ifndef HAVE_LSTAT +int lstat(const char *file_name, struct stat *buf); +#endif /* HAVE_LSTAT */ + +#ifndef HAVE_MEMMOVE +void *memmove(void *dest, const void *src, size_t len); +#endif /* !defined(HAVE_MEMMOVE) */ + +#ifndef HAVE_PREAD +ssize_t pread( int fd, void *buf, size_t count, off_t offset ); +#endif /* HAVE_PREAD */ + +#ifndef HAVE_PWRITE +ssize_t pwrite( int fd, const void *buf, size_t count, off_t offset ); +#endif /* HAVE_PWRITE */ + +#ifndef HAVE_READLINK +int readlink( const char *path, char *buf, size_t size ); +#endif /* HAVE_READLINK */ + +#ifndef HAVE_SIGSETJMP +# include +typedef jmp_buf sigjmp_buf; +int sigsetjmp( sigjmp_buf buf, int savesigs ); +void siglongjmp( sigjmp_buf buf, int val ); +#endif /* HAVE_SIGSETJMP */ + +#ifndef HAVE_STATVFS +int statvfs( const char *path, struct statvfs *buf ); +#endif + +#ifndef HAVE_STRNCASECMP +# ifndef HAVE__STRNICMP +int strncasecmp(const char *str1, const char *str2, size_t n); +# else +# define strncasecmp _strnicmp +# endif +#endif /* !defined(HAVE_STRNCASECMP) */ + +#ifndef HAVE_STRERROR +const char *strerror(int err); +#endif /* !defined(HAVE_STRERROR) */ + +#ifndef HAVE_STRCASECMP +# ifndef HAVE__STRICMP +int strcasecmp(const char *str1, const char *str2); +# else +# define strcasecmp _stricmp +# endif +#endif /* !defined(HAVE_STRCASECMP) */ + +#ifndef HAVE_USLEEP +int usleep (unsigned int useconds); +#endif /* !defined(HAVE_USLEEP) */ + +#ifdef __i386__ +static inline void *memcpy_unaligned( void *dst, const void *src, size_t size ) +{ + return memcpy( dst, src, size ); +} +#else +extern void *memcpy_unaligned( void *dst, const void *src, size_t size ); +#endif /* __i386__ */ + +extern int mkstemps(char *template, int suffix_len); + +/* Process creation flags */ +#ifndef _P_WAIT +# define _P_WAIT 0 +# define _P_NOWAIT 1 +# define _P_OVERLAY 2 +# define _P_NOWAITO 3 +# define _P_DETACH 4 +#endif +#ifndef HAVE_SPAWNVP +extern int spawnvp(int mode, const char *cmdname, const char * const argv[]); +#endif + +/* Interlocked functions */ + +#if defined(__i386__) && defined(__GNUC__) + +extern inline long interlocked_cmpxchg( long *dest, long xchg, long compare ); +extern inline void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare ); +extern inline long interlocked_xchg( long *dest, long val ); +extern inline void *interlocked_xchg_ptr( void **dest, void *val ); +extern inline long interlocked_xchg_add( long *dest, long incr ); + +extern inline long interlocked_cmpxchg( long *dest, long xchg, long compare ) +{ + long ret; + __asm__ __volatile__( "lock; cmpxchgl %2,(%1)" + : "=a" (ret) : "r" (dest), "r" (xchg), "0" (compare) : "memory" ); + return ret; +} + +extern inline void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare ) +{ + void *ret; + __asm__ __volatile__( "lock; cmpxchgl %2,(%1)" + : "=a" (ret) : "r" (dest), "r" (xchg), "0" (compare) : "memory" ); + return ret; +} + +extern inline long interlocked_xchg( long *dest, long val ) +{ + long ret; + __asm__ __volatile__( "lock; xchgl %0,(%1)" + : "=r" (ret) : "r" (dest), "0" (val) : "memory" ); + return ret; +} + +extern inline void *interlocked_xchg_ptr( void **dest, void *val ) +{ + void *ret; + __asm__ __volatile__( "lock; xchgl %0,(%1)" + : "=r" (ret) : "r" (dest), "0" (val) : "memory" ); + return ret; +} + +extern inline long interlocked_xchg_add( long *dest, long incr ) +{ + long ret; + __asm__ __volatile__( "lock; xaddl %0,(%1)" + : "=r" (ret) : "r" (dest), "0" (incr) : "memory" ); + return ret; +} + +#else /* __i386___ && __GNUC__ */ + +extern long interlocked_cmpxchg( long *dest, long xchg, long compare ); +extern void *interlocked_cmpxchg_ptr( void **dest, void *xchg, void *compare ); +extern long interlocked_xchg( long *dest, long val ); +extern void *interlocked_xchg_ptr( void **dest, void *val ); +extern long interlocked_xchg_add( long *dest, long incr ); + +#endif /* __i386___ && __GNUC__ */ + +#else /* NO_LIBWINE_PORT */ + +#define __WINE_NOT_PORTABLE(func) func##_is_not_portable func##_is_not_portable + +#define ffs __WINE_NOT_PORTABLE(ffs) +#define fstatvfs __WINE_NOT_PORTABLE(fstatvfs) +#define futimes __WINE_NOT_PORTABLE(futimes) +#define getopt_long __WINE_NOT_PORTABLE(getopt_long) +#define getopt_long_only __WINE_NOT_PORTABLE(getopt_long_only) +#define getpagesize __WINE_NOT_PORTABLE(getpagesize) +#define interlocked_cmpxchg __WINE_NOT_PORTABLE(interlocked_cmpxchg) +#define interlocked_cmpxchg_ptr __WINE_NOT_PORTABLE(interlocked_cmpxchg_ptr) +#define interlocked_xchg __WINE_NOT_PORTABLE(interlocked_xchg) +#define interlocked_xchg_ptr __WINE_NOT_PORTABLE(interlocked_xchg_ptr) +#define interlocked_xchg_add __WINE_NOT_PORTABLE(interlocked_xchg_add) +#define lstat __WINE_NOT_PORTABLE(lstat) +#define memcpy_unaligned __WINE_NOT_PORTABLE(memcpy_unaligned) +#define memmove __WINE_NOT_PORTABLE(memmove) +#define pread __WINE_NOT_PORTABLE(pread) +#define pwrite __WINE_NOT_PORTABLE(pwrite) +#define spawnvp __WINE_NOT_PORTABLE(spawnvp) +#define statvfs __WINE_NOT_PORTABLE(statvfs) +#define strcasecmp __WINE_NOT_PORTABLE(strcasecmp) +#define strerror __WINE_NOT_PORTABLE(strerror) +#define strncasecmp __WINE_NOT_PORTABLE(strncasecmp) +#define usleep __WINE_NOT_PORTABLE(usleep) + +#endif /* NO_LIBWINE_PORT */ + +#endif /* !defined(__WINE_WINE_PORT_H) */ diff --git a/reactos/apps/utils/winetest/resource.h b/reactos/apps/utils/winetest/resource.h index 0c6a5af3fa4..1c81e6bbc86 100644 --- a/reactos/apps/utils/winetest/resource.h +++ b/reactos/apps/utils/winetest/resource.h @@ -1,53 +1,53 @@ -/* - * Resource definitions - * - * Copyright 2004 Ferenc Wagner - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define IDI_WINE 1 - -#define IDD_STATUS 100 -#define IDD_ABOUT 101 - -#define IDC_ST0 1000 -#define IDC_PB0 1001 -#define IDC_ST1 1002 -#define IDC_PB1 1003 -#define IDC_ST2 1004 -#define IDC_PB2 1005 - -#define IDC_DIR 2000 -#define IDC_OUT 2001 - -#define IDC_SB 3000 - -#define IDC_EDIT 4000 -#define IDC_ABOUT 4001 - -/* Resource types */ - -#define TESTRES 1000 -#define STRINGRES 1001 - -/* String resources */ - -#define WINE_BUILD 10000 -#define BUILD_INFO 10001 -#define TESTS_URL 10002 - -/* Revision info strings start from this index: */ -#define REV_INFO 30000 +/* + * Resource definitions + * + * Copyright 2004 Ferenc Wagner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define IDI_WINE 1 + +#define IDD_STATUS 100 +#define IDD_ABOUT 101 + +#define IDC_ST0 1000 +#define IDC_PB0 1001 +#define IDC_ST1 1002 +#define IDC_PB1 1003 +#define IDC_ST2 1004 +#define IDC_PB2 1005 + +#define IDC_DIR 2000 +#define IDC_OUT 2001 + +#define IDC_SB 3000 + +#define IDC_EDIT 4000 +#define IDC_ABOUT 4001 + +/* Resource types */ + +#define TESTRES 1000 +#define STRINGRES 1001 + +/* String resources */ + +#define WINE_BUILD 10000 +#define BUILD_INFO 10001 +#define TESTS_URL 10002 + +/* Revision info strings start from this index: */ +#define REV_INFO 30000 diff --git a/reactos/apps/utils/winetest/util.c b/reactos/apps/utils/winetest/util.c index bd75e5f4011..d09b90bcc51 100644 --- a/reactos/apps/utils/winetest/util.c +++ b/reactos/apps/utils/winetest/util.c @@ -1,118 +1,118 @@ -/* - * Utility functions. - * - * Copyright 2003 Dimitrie O. Paun - * Copyright 2003 Ferenc Wagner - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include - -#include "winetest.h" - -void *xmalloc (size_t len) -{ - void *p = malloc (len); - - if (!p) report (R_FATAL, "Out of memory."); - return p; -} - -void *xrealloc (void *op, size_t len) -{ - void *p = realloc (op, len); - - if (!p) report (R_FATAL, "Out of memory."); - return p; -} - -char *vstrfmtmake (size_t *lenp, const char *fmt, va_list ap) -{ - size_t size = 1000; - char *p, *q; - int n; - - p = malloc (size); - if (!p) return NULL; - while (1) { - n = vsnprintf (p, size, fmt, ap); - if (n < 0) size *= 2; /* Windows */ - else if ((unsigned)n >= size) size = n+1; /* glibc */ - else break; - q = realloc (p, size); - if (!q) { - free (p); - return NULL; - } - p = q; - } - if (lenp) *lenp = n; - return p; -} - -char *vstrmake (size_t *lenp, va_list ap) -{ - const char *fmt; - - fmt = va_arg (ap, const char*); - return vstrfmtmake (lenp, fmt, ap); -} - -char *strmake (size_t *lenp, ...) -{ - va_list ap; - char *p; - - va_start (ap, lenp); - p = vstrmake (lenp, ap); - if (!p) report (R_FATAL, "Out of memory."); - va_end (ap); - return p; -} - -void xprintf (const char *fmt, ...) -{ - va_list ap; - size_t size; - ssize_t written; - char *buffer, *head; - - va_start (ap, fmt); - buffer = vstrfmtmake (&size, fmt, ap); - head = buffer; - va_end (ap); - while ((written = write (1, head, size)) != size) { - if (written == -1) - report (R_FATAL, "Can't write logs: %d", errno); - head += written; - size -= written; - } - free (buffer); -} - -const char * -badtagchar (const char *tag) -{ - while (*tag) - if (('a'<=*tag && *tag<='z') || - ('A'<=*tag && *tag<='Z') || - ('0'<=*tag && *tag<='9') || - *tag=='-' || *tag=='.') - tag++; - else return tag; - return NULL; -} +/* + * Utility functions. + * + * Copyright 2003 Dimitrie O. Paun + * Copyright 2003 Ferenc Wagner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#include "winetest.h" + +void *xmalloc (size_t len) +{ + void *p = malloc (len); + + if (!p) report (R_FATAL, "Out of memory."); + return p; +} + +void *xrealloc (void *op, size_t len) +{ + void *p = realloc (op, len); + + if (!p) report (R_FATAL, "Out of memory."); + return p; +} + +char *vstrfmtmake (size_t *lenp, const char *fmt, va_list ap) +{ + size_t size = 1000; + char *p, *q; + int n; + + p = malloc (size); + if (!p) return NULL; + while (1) { + n = vsnprintf (p, size, fmt, ap); + if (n < 0) size *= 2; /* Windows */ + else if ((unsigned)n >= size) size = n+1; /* glibc */ + else break; + q = realloc (p, size); + if (!q) { + free (p); + return NULL; + } + p = q; + } + if (lenp) *lenp = n; + return p; +} + +char *vstrmake (size_t *lenp, va_list ap) +{ + const char *fmt; + + fmt = va_arg (ap, const char*); + return vstrfmtmake (lenp, fmt, ap); +} + +char *strmake (size_t *lenp, ...) +{ + va_list ap; + char *p; + + va_start (ap, lenp); + p = vstrmake (lenp, ap); + if (!p) report (R_FATAL, "Out of memory."); + va_end (ap); + return p; +} + +void xprintf (const char *fmt, ...) +{ + va_list ap; + size_t size; + ssize_t written; + char *buffer, *head; + + va_start (ap, fmt); + buffer = vstrfmtmake (&size, fmt, ap); + head = buffer; + va_end (ap); + while ((written = write (1, head, size)) != size) { + if (written == -1) + report (R_FATAL, "Can't write logs: %d", errno); + head += written; + size -= written; + } + free (buffer); +} + +const char * +badtagchar (const char *tag) +{ + while (*tag) + if (('a'<=*tag && *tag<='z') || + ('A'<=*tag && *tag<='Z') || + ('0'<=*tag && *tag<='9') || + *tag=='-' || *tag=='.') + tag++; + else return tag; + return NULL; +} diff --git a/reactos/apps/utils/winetest/winetest.h b/reactos/apps/utils/winetest/winetest.h index ba9a70d437d..97ea097df21 100644 --- a/reactos/apps/utils/winetest/winetest.h +++ b/reactos/apps/utils/winetest/winetest.h @@ -1,61 +1,61 @@ -/* - * winetest definitions - * - * Copyright 2003 Dimitrie O. Paun - * Copyright 2003 Ferenc Wagner - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINETESTS_H -#define __WINETESTS_H - -#include -#include -#include - -void fatal (const char* msg); -void warning (const char* msg); -void *xmalloc (size_t len); -void *xrealloc (void *op, size_t len); -void xprintf (const char *fmt, ...); -char *vstrmake (size_t *lenp, va_list ap); -char *strmake (size_t *lenp, ...); -const char *badtagchar (const char *tag); - -int send_file (const char *name); - -/* GUI definitions */ - -#include - -enum report_type { - R_STATUS = 0, - R_PROGRESS, - R_STEP, - R_DELTA, - R_DIR, - R_OUT, - R_WARNING, - R_ERROR, - R_FATAL, - R_ASK, - R_TEXTMODE, - R_QUIET -}; - -int report (enum report_type t, ...); - -#endif /* __WINETESTS_H */ +/* + * winetest definitions + * + * Copyright 2003 Dimitrie O. Paun + * Copyright 2003 Ferenc Wagner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINETESTS_H +#define __WINETESTS_H + +#include +#include +#include + +void fatal (const char* msg); +void warning (const char* msg); +void *xmalloc (size_t len); +void *xrealloc (void *op, size_t len); +void xprintf (const char *fmt, ...); +char *vstrmake (size_t *lenp, va_list ap); +char *strmake (size_t *lenp, ...); +const char *badtagchar (const char *tag); + +int send_file (const char *name); + +/* GUI definitions */ + +#include + +enum report_type { + R_STATUS = 0, + R_PROGRESS, + R_STEP, + R_DELTA, + R_DIR, + R_OUT, + R_WARNING, + R_ERROR, + R_FATAL, + R_ASK, + R_TEXTMODE, + R_QUIET +}; + +int report (enum report_type t, ...); + +#endif /* __WINETESTS_H */ diff --git a/reactos/drivers/fs/vfat/fastio.c b/reactos/drivers/fs/vfat/fastio.c index 6d7b0010734..0262502250f 100644 --- a/reactos/drivers/fs/vfat/fastio.c +++ b/reactos/drivers/fs/vfat/fastio.c @@ -1,399 +1,399 @@ -/* $Id$ - * - * - * FILE: drivers/fs/vfat/fastio.c - * PURPOSE: Fast IO routines. - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * PROGRAMMER: Herve Poussineau (reactos@poussine.freesurf.fr) - * Hartmut Birr - */ - -#define NDEBUG -#include "vfat.h" - -BOOLEAN STDCALL -VfatFastIoCheckIfPossible(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN ULONG Lenght, - IN BOOLEAN Wait, - IN ULONG LockKey, - IN BOOLEAN CheckForReadOperation, - OUT PIO_STATUS_BLOCK IoStatus, - IN PDEVICE_OBJECT DeviceObject) -{ - /* Prevent all Fast I/O requests */ - DPRINT("VfatFastIoCheckIfPossible(): returning FALSE.\n"); - return FALSE; -} - -BOOLEAN STDCALL -VfatFastIoRead(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN ULONG Length, - IN BOOLEAN Wait, - IN ULONG LockKey, - OUT PVOID Buffer, - OUT PIO_STATUS_BLOCK IoStatus, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatFastIoRead()\n"); - return FALSE; -} - -BOOLEAN STDCALL -VfatFastIoWrite(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN ULONG Length, - IN BOOLEAN Wait, - IN ULONG LockKey, - OUT PVOID Buffer, - OUT PIO_STATUS_BLOCK IoStatus, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatFastIoWrite()\n"); - return FALSE; -} - -BOOLEAN STDCALL -VfatFastIoQueryBasicInfo(IN PFILE_OBJECT FileObject, - IN BOOLEAN Wait, - OUT PFILE_BASIC_INFORMATION Buffer, - OUT PIO_STATUS_BLOCK IoStatus, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatFastIoQueryBasicInfo()\n"); - return FALSE; -} - -BOOLEAN STDCALL -VfatFastIoQueryStandardInfo(IN PFILE_OBJECT FileObject, - IN BOOLEAN Wait, - OUT PFILE_STANDARD_INFORMATION Buffer, - OUT PIO_STATUS_BLOCK IoStatus, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatFastIoQueryStandardInfo\n"); - return FALSE; -} - -BOOLEAN STDCALL -VfatFastIoLock(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN PLARGE_INTEGER Length, - PEPROCESS ProcessId, - ULONG Key, - BOOLEAN FailImmediately, - BOOLEAN ExclusiveLock, - OUT PIO_STATUS_BLOCK IoStatus, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatFastIoLock\n"); - return FALSE; -} - -BOOLEAN STDCALL -VfatFastIoUnlockSingle(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN PLARGE_INTEGER Length, - PEPROCESS ProcessId, - ULONG Key, - OUT PIO_STATUS_BLOCK IoStatus, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatFastIoUnlockSingle\n"); - return FALSE; -} - -BOOLEAN STDCALL -VfatFastIoUnlockAll(IN PFILE_OBJECT FileObject, - PEPROCESS ProcessId, - OUT PIO_STATUS_BLOCK IoStatus, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatFastIoUnlockAll\n"); - return FALSE; -} - -BOOLEAN STDCALL -VfatFastIoUnlockAllByKey(IN PFILE_OBJECT FileObject, - PEPROCESS ProcessId, - ULONG Key, - OUT PIO_STATUS_BLOCK IoStatus, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatFastIoUnlockAllByKey\n"); - return FALSE; -} - -BOOLEAN STDCALL -VfatFastIoDeviceControl(IN PFILE_OBJECT FileObject, - IN BOOLEAN Wait, - IN PVOID InputBuffer OPTIONAL, - IN ULONG InputBufferLength, - OUT PVOID OutputBuffer OPTIONAL, - IN ULONG OutputBufferLength, - IN ULONG IoControlCode, - OUT PIO_STATUS_BLOCK IoStatus, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatFastIoDeviceControl\n"); - return FALSE; -} - -VOID STDCALL -VfatAcquireFileForNtCreateSection(IN PFILE_OBJECT FileObject) -{ - DPRINT("VfatAcquireFileForNtCreateSection\n"); -} - -VOID STDCALL -VfatReleaseFileForNtCreateSection(IN PFILE_OBJECT FileObject) -{ - DPRINT("VfatReleaseFileForNtCreateSection\n"); -} - -VOID STDCALL -VfatFastIoDetachDevice(IN PDEVICE_OBJECT SourceDevice, - IN PDEVICE_OBJECT TargetDevice) -{ - DPRINT("VfatFastIoDetachDevice\n"); -} - -BOOLEAN STDCALL -VfatFastIoQueryNetworkOpenInfo(IN PFILE_OBJECT FileObject, - IN BOOLEAN Wait, - OUT PFILE_NETWORK_OPEN_INFORMATION Buffer, - OUT PIO_STATUS_BLOCK IoStatus, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatFastIoQueryNetworkOpenInfo\n"); - return FALSE; -} - -NTSTATUS STDCALL -VfatAcquireForModWrite(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER EndingOffset, - OUT PERESOURCE* ResourceToRelease, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatAcquireForModWrite\n"); - return STATUS_UNSUCCESSFUL; -} - -BOOLEAN STDCALL -VfatMdlRead(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN ULONG Length, - IN ULONG LockKey, - OUT PMDL* MdlChain, - OUT PIO_STATUS_BLOCK IoStatus, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatMdlRead\n"); - return FALSE; -} - -BOOLEAN STDCALL -VfatMdlReadComplete(IN PFILE_OBJECT FileObject, - IN PMDL MdlChain, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatMdlReadComplete\n"); - return FALSE; -} - -BOOLEAN STDCALL -VfatPrepareMdlWrite(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN ULONG Length, - IN ULONG LockKey, - OUT PMDL* MdlChain, - OUT PIO_STATUS_BLOCK IoStatus, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatPrepareMdlWrite\n"); - return FALSE; -} - -BOOLEAN STDCALL -VfatMdlWriteComplete(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN PMDL MdlChain, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatMdlWriteComplete\n"); - return FALSE; -} - -BOOLEAN STDCALL -VfatFastIoReadCompressed(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN ULONG Length, - IN ULONG LockKey, - OUT PVOID Buffer, - OUT PMDL* MdlChain, - OUT PIO_STATUS_BLOCK IoStatus, - OUT PCOMPRESSED_DATA_INFO CompressedDataInfo, - IN ULONG CompressedDataInfoLength, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatFastIoReadCompressed\n"); - return FALSE; -} - -BOOLEAN STDCALL -VfatFastIoWriteCompressed(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN ULONG Length, - IN ULONG LockKey, - IN PVOID Buffer, - OUT PMDL* MdlChain, - OUT PIO_STATUS_BLOCK IoStatus, - IN PCOMPRESSED_DATA_INFO CompressedDataInfo, - IN ULONG CompressedDataInfoLength, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatFastIoWriteCompressed\n"); - return FALSE; -} - -BOOLEAN STDCALL -VfatMdlReadCompleteCompressed(IN PFILE_OBJECT FileObject, - IN PMDL MdlChain, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatMdlReadCompleteCompressed\n"); - return FALSE; -} - -BOOLEAN STDCALL -VfatMdlWriteCompleteCompressed(IN PFILE_OBJECT FileObject, - IN PLARGE_INTEGER FileOffset, - IN PMDL MdlChain, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatMdlWriteCompleteCompressed\n"); - return FALSE; -} - -BOOLEAN STDCALL -VfatFastIoQueryOpen(IN PIRP Irp, - OUT PFILE_NETWORK_OPEN_INFORMATION NetworkInformation, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatFastIoQueryOpen\n"); - return FALSE; -} - -NTSTATUS STDCALL -VfatReleaseForModWrite(IN PFILE_OBJECT FileObject, - IN PERESOURCE ResourceToRelease, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatReleaseForModWrite\n"); - return STATUS_UNSUCCESSFUL; -} - -NTSTATUS STDCALL -VfatAcquireForCcFlush(IN PFILE_OBJECT FileObject, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatAcquireForCcFlush\n"); - return STATUS_UNSUCCESSFUL; -} - -NTSTATUS STDCALL -VfatReleaseForCcFlush(IN PFILE_OBJECT FileObject, - IN PDEVICE_OBJECT DeviceObject) -{ - DPRINT("VfatReleaseForCcFlush\n"); - return STATUS_UNSUCCESSFUL; -} - -BOOLEAN STDCALL -VfatAcquireForLazyWrite(IN PVOID Context, - IN BOOLEAN Wait) -{ - PVFATFCB Fcb = (PVFATFCB)Context; - ASSERT(Fcb); - DPRINT("VfatAcquireForLazyWrite(): Fcb %p\n", Fcb); - - if (!ExAcquireResourceExclusiveLite(&(Fcb->MainResource), Wait)) - { - DPRINT("VfatAcquireForLazyWrite(): ExReleaseResourceLite failed.\n"); - return FALSE; - } - return TRUE; -} - -VOID STDCALL -VfatReleaseFromLazyWrite(IN PVOID Context) -{ - PVFATFCB Fcb = (PVFATFCB)Context; - ASSERT(Fcb); - DPRINT("VfatReleaseFromLazyWrite(): Fcb %p\n", Fcb); - - ExReleaseResourceLite(&(Fcb->MainResource)); -} - -BOOLEAN STDCALL -VfatAcquireForReadAhead(IN PVOID Context, - IN BOOLEAN Wait) -{ - PVFATFCB Fcb = (PVFATFCB)Context; - ASSERT(Fcb); - DPRINT("VfatAcquireForReadAhead(): Fcb %p\n", Fcb); - - if (!ExAcquireResourceExclusiveLite(&(Fcb->MainResource), Wait)) - { - DPRINT("VfatAcquireForReadAhead(): ExReleaseResourceLite failed.\n"); - return FALSE; - } - return TRUE; -} - -VOID STDCALL -VfatReleaseFromReadAhead(IN PVOID Context) -{ - PVFATFCB Fcb = (PVFATFCB)Context; - ASSERT(Fcb); - DPRINT("VfatReleaseFromReadAhead(): Fcb %p\n", Fcb); - - ExReleaseResourceLite(&(Fcb->MainResource)); -} - -VOID -VfatInitFastIoRoutines(PFAST_IO_DISPATCH FastIoDispatch) -{ - FastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH); - FastIoDispatch->FastIoCheckIfPossible = VfatFastIoCheckIfPossible; - FastIoDispatch->FastIoRead = VfatFastIoRead; - FastIoDispatch->FastIoWrite = VfatFastIoWrite; - FastIoDispatch->FastIoQueryBasicInfo = VfatFastIoQueryBasicInfo; - FastIoDispatch->FastIoQueryStandardInfo = VfatFastIoQueryStandardInfo; - FastIoDispatch->FastIoLock = VfatFastIoLock; - FastIoDispatch->FastIoUnlockSingle = VfatFastIoUnlockSingle; - FastIoDispatch->FastIoUnlockAll = VfatFastIoUnlockAll; - FastIoDispatch->FastIoUnlockAllByKey = VfatFastIoUnlockAllByKey; - FastIoDispatch->FastIoDeviceControl = VfatFastIoDeviceControl; - FastIoDispatch->AcquireFileForNtCreateSection = VfatAcquireFileForNtCreateSection; - FastIoDispatch->ReleaseFileForNtCreateSection = VfatReleaseFileForNtCreateSection; - FastIoDispatch->FastIoDetachDevice = VfatFastIoDetachDevice; - FastIoDispatch->FastIoQueryNetworkOpenInfo = VfatFastIoQueryNetworkOpenInfo; - FastIoDispatch->AcquireForModWrite = VfatAcquireForModWrite; - FastIoDispatch->MdlRead = VfatMdlRead; - FastIoDispatch->MdlReadComplete = VfatMdlReadComplete; - FastIoDispatch->PrepareMdlWrite = VfatPrepareMdlWrite; - FastIoDispatch->MdlWriteComplete = VfatMdlWriteComplete; - FastIoDispatch->FastIoReadCompressed = VfatFastIoReadCompressed; - FastIoDispatch->FastIoWriteCompressed = VfatFastIoWriteCompressed; - FastIoDispatch->MdlReadCompleteCompressed = VfatMdlReadCompleteCompressed; - FastIoDispatch->MdlWriteCompleteCompressed = VfatMdlWriteCompleteCompressed; - FastIoDispatch->FastIoQueryOpen = VfatFastIoQueryOpen; - FastIoDispatch->ReleaseForModWrite = VfatReleaseForModWrite; - FastIoDispatch->AcquireForCcFlush = VfatAcquireForCcFlush; - FastIoDispatch->ReleaseForCcFlush = VfatReleaseForCcFlush; -} - - +/* $Id$ + * + * + * FILE: drivers/fs/vfat/fastio.c + * PURPOSE: Fast IO routines. + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * PROGRAMMER: Herve Poussineau (reactos@poussine.freesurf.fr) + * Hartmut Birr + */ + +#define NDEBUG +#include "vfat.h" + +BOOLEAN STDCALL +VfatFastIoCheckIfPossible(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Lenght, + IN BOOLEAN Wait, + IN ULONG LockKey, + IN BOOLEAN CheckForReadOperation, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + /* Prevent all Fast I/O requests */ + DPRINT("VfatFastIoCheckIfPossible(): returning FALSE.\n"); + return FALSE; +} + +BOOLEAN STDCALL +VfatFastIoRead(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN ULONG LockKey, + OUT PVOID Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoRead()\n"); + return FALSE; +} + +BOOLEAN STDCALL +VfatFastIoWrite(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN BOOLEAN Wait, + IN ULONG LockKey, + OUT PVOID Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoWrite()\n"); + return FALSE; +} + +BOOLEAN STDCALL +VfatFastIoQueryBasicInfo(IN PFILE_OBJECT FileObject, + IN BOOLEAN Wait, + OUT PFILE_BASIC_INFORMATION Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoQueryBasicInfo()\n"); + return FALSE; +} + +BOOLEAN STDCALL +VfatFastIoQueryStandardInfo(IN PFILE_OBJECT FileObject, + IN BOOLEAN Wait, + OUT PFILE_STANDARD_INFORMATION Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoQueryStandardInfo\n"); + return FALSE; +} + +BOOLEAN STDCALL +VfatFastIoLock(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PLARGE_INTEGER Length, + PEPROCESS ProcessId, + ULONG Key, + BOOLEAN FailImmediately, + BOOLEAN ExclusiveLock, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoLock\n"); + return FALSE; +} + +BOOLEAN STDCALL +VfatFastIoUnlockSingle(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PLARGE_INTEGER Length, + PEPROCESS ProcessId, + ULONG Key, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoUnlockSingle\n"); + return FALSE; +} + +BOOLEAN STDCALL +VfatFastIoUnlockAll(IN PFILE_OBJECT FileObject, + PEPROCESS ProcessId, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoUnlockAll\n"); + return FALSE; +} + +BOOLEAN STDCALL +VfatFastIoUnlockAllByKey(IN PFILE_OBJECT FileObject, + PEPROCESS ProcessId, + ULONG Key, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoUnlockAllByKey\n"); + return FALSE; +} + +BOOLEAN STDCALL +VfatFastIoDeviceControl(IN PFILE_OBJECT FileObject, + IN BOOLEAN Wait, + IN PVOID InputBuffer OPTIONAL, + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer OPTIONAL, + IN ULONG OutputBufferLength, + IN ULONG IoControlCode, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoDeviceControl\n"); + return FALSE; +} + +VOID STDCALL +VfatAcquireFileForNtCreateSection(IN PFILE_OBJECT FileObject) +{ + DPRINT("VfatAcquireFileForNtCreateSection\n"); +} + +VOID STDCALL +VfatReleaseFileForNtCreateSection(IN PFILE_OBJECT FileObject) +{ + DPRINT("VfatReleaseFileForNtCreateSection\n"); +} + +VOID STDCALL +VfatFastIoDetachDevice(IN PDEVICE_OBJECT SourceDevice, + IN PDEVICE_OBJECT TargetDevice) +{ + DPRINT("VfatFastIoDetachDevice\n"); +} + +BOOLEAN STDCALL +VfatFastIoQueryNetworkOpenInfo(IN PFILE_OBJECT FileObject, + IN BOOLEAN Wait, + OUT PFILE_NETWORK_OPEN_INFORMATION Buffer, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoQueryNetworkOpenInfo\n"); + return FALSE; +} + +NTSTATUS STDCALL +VfatAcquireForModWrite(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER EndingOffset, + OUT PERESOURCE* ResourceToRelease, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatAcquireForModWrite\n"); + return STATUS_UNSUCCESSFUL; +} + +BOOLEAN STDCALL +VfatMdlRead(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG LockKey, + OUT PMDL* MdlChain, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatMdlRead\n"); + return FALSE; +} + +BOOLEAN STDCALL +VfatMdlReadComplete(IN PFILE_OBJECT FileObject, + IN PMDL MdlChain, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatMdlReadComplete\n"); + return FALSE; +} + +BOOLEAN STDCALL +VfatPrepareMdlWrite(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG LockKey, + OUT PMDL* MdlChain, + OUT PIO_STATUS_BLOCK IoStatus, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatPrepareMdlWrite\n"); + return FALSE; +} + +BOOLEAN STDCALL +VfatMdlWriteComplete(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PMDL MdlChain, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatMdlWriteComplete\n"); + return FALSE; +} + +BOOLEAN STDCALL +VfatFastIoReadCompressed(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG LockKey, + OUT PVOID Buffer, + OUT PMDL* MdlChain, + OUT PIO_STATUS_BLOCK IoStatus, + OUT PCOMPRESSED_DATA_INFO CompressedDataInfo, + IN ULONG CompressedDataInfoLength, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoReadCompressed\n"); + return FALSE; +} + +BOOLEAN STDCALL +VfatFastIoWriteCompressed(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN ULONG Length, + IN ULONG LockKey, + IN PVOID Buffer, + OUT PMDL* MdlChain, + OUT PIO_STATUS_BLOCK IoStatus, + IN PCOMPRESSED_DATA_INFO CompressedDataInfo, + IN ULONG CompressedDataInfoLength, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoWriteCompressed\n"); + return FALSE; +} + +BOOLEAN STDCALL +VfatMdlReadCompleteCompressed(IN PFILE_OBJECT FileObject, + IN PMDL MdlChain, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatMdlReadCompleteCompressed\n"); + return FALSE; +} + +BOOLEAN STDCALL +VfatMdlWriteCompleteCompressed(IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER FileOffset, + IN PMDL MdlChain, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatMdlWriteCompleteCompressed\n"); + return FALSE; +} + +BOOLEAN STDCALL +VfatFastIoQueryOpen(IN PIRP Irp, + OUT PFILE_NETWORK_OPEN_INFORMATION NetworkInformation, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatFastIoQueryOpen\n"); + return FALSE; +} + +NTSTATUS STDCALL +VfatReleaseForModWrite(IN PFILE_OBJECT FileObject, + IN PERESOURCE ResourceToRelease, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatReleaseForModWrite\n"); + return STATUS_UNSUCCESSFUL; +} + +NTSTATUS STDCALL +VfatAcquireForCcFlush(IN PFILE_OBJECT FileObject, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatAcquireForCcFlush\n"); + return STATUS_UNSUCCESSFUL; +} + +NTSTATUS STDCALL +VfatReleaseForCcFlush(IN PFILE_OBJECT FileObject, + IN PDEVICE_OBJECT DeviceObject) +{ + DPRINT("VfatReleaseForCcFlush\n"); + return STATUS_UNSUCCESSFUL; +} + +BOOLEAN STDCALL +VfatAcquireForLazyWrite(IN PVOID Context, + IN BOOLEAN Wait) +{ + PVFATFCB Fcb = (PVFATFCB)Context; + ASSERT(Fcb); + DPRINT("VfatAcquireForLazyWrite(): Fcb %p\n", Fcb); + + if (!ExAcquireResourceExclusiveLite(&(Fcb->MainResource), Wait)) + { + DPRINT("VfatAcquireForLazyWrite(): ExReleaseResourceLite failed.\n"); + return FALSE; + } + return TRUE; +} + +VOID STDCALL +VfatReleaseFromLazyWrite(IN PVOID Context) +{ + PVFATFCB Fcb = (PVFATFCB)Context; + ASSERT(Fcb); + DPRINT("VfatReleaseFromLazyWrite(): Fcb %p\n", Fcb); + + ExReleaseResourceLite(&(Fcb->MainResource)); +} + +BOOLEAN STDCALL +VfatAcquireForReadAhead(IN PVOID Context, + IN BOOLEAN Wait) +{ + PVFATFCB Fcb = (PVFATFCB)Context; + ASSERT(Fcb); + DPRINT("VfatAcquireForReadAhead(): Fcb %p\n", Fcb); + + if (!ExAcquireResourceExclusiveLite(&(Fcb->MainResource), Wait)) + { + DPRINT("VfatAcquireForReadAhead(): ExReleaseResourceLite failed.\n"); + return FALSE; + } + return TRUE; +} + +VOID STDCALL +VfatReleaseFromReadAhead(IN PVOID Context) +{ + PVFATFCB Fcb = (PVFATFCB)Context; + ASSERT(Fcb); + DPRINT("VfatReleaseFromReadAhead(): Fcb %p\n", Fcb); + + ExReleaseResourceLite(&(Fcb->MainResource)); +} + +VOID +VfatInitFastIoRoutines(PFAST_IO_DISPATCH FastIoDispatch) +{ + FastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH); + FastIoDispatch->FastIoCheckIfPossible = VfatFastIoCheckIfPossible; + FastIoDispatch->FastIoRead = VfatFastIoRead; + FastIoDispatch->FastIoWrite = VfatFastIoWrite; + FastIoDispatch->FastIoQueryBasicInfo = VfatFastIoQueryBasicInfo; + FastIoDispatch->FastIoQueryStandardInfo = VfatFastIoQueryStandardInfo; + FastIoDispatch->FastIoLock = VfatFastIoLock; + FastIoDispatch->FastIoUnlockSingle = VfatFastIoUnlockSingle; + FastIoDispatch->FastIoUnlockAll = VfatFastIoUnlockAll; + FastIoDispatch->FastIoUnlockAllByKey = VfatFastIoUnlockAllByKey; + FastIoDispatch->FastIoDeviceControl = VfatFastIoDeviceControl; + FastIoDispatch->AcquireFileForNtCreateSection = VfatAcquireFileForNtCreateSection; + FastIoDispatch->ReleaseFileForNtCreateSection = VfatReleaseFileForNtCreateSection; + FastIoDispatch->FastIoDetachDevice = VfatFastIoDetachDevice; + FastIoDispatch->FastIoQueryNetworkOpenInfo = VfatFastIoQueryNetworkOpenInfo; + FastIoDispatch->AcquireForModWrite = VfatAcquireForModWrite; + FastIoDispatch->MdlRead = VfatMdlRead; + FastIoDispatch->MdlReadComplete = VfatMdlReadComplete; + FastIoDispatch->PrepareMdlWrite = VfatPrepareMdlWrite; + FastIoDispatch->MdlWriteComplete = VfatMdlWriteComplete; + FastIoDispatch->FastIoReadCompressed = VfatFastIoReadCompressed; + FastIoDispatch->FastIoWriteCompressed = VfatFastIoWriteCompressed; + FastIoDispatch->MdlReadCompleteCompressed = VfatMdlReadCompleteCompressed; + FastIoDispatch->MdlWriteCompleteCompressed = VfatMdlWriteCompleteCompressed; + FastIoDispatch->FastIoQueryOpen = VfatFastIoQueryOpen; + FastIoDispatch->ReleaseForModWrite = VfatReleaseForModWrite; + FastIoDispatch->AcquireForCcFlush = VfatAcquireForCcFlush; + FastIoDispatch->ReleaseForCcFlush = VfatReleaseForCcFlush; +} + + diff --git a/reactos/drivers/usb/miniport/usbehci/usbehci.c b/reactos/drivers/usb/miniport/usbehci/usbehci.c index 9289968a2db..ee9d1d6c13f 100644 --- a/reactos/drivers/usb/miniport/usbehci/usbehci.c +++ b/reactos/drivers/usb/miniport/usbehci/usbehci.c @@ -1,41 +1,41 @@ -/* - * ReactOS USB EHCI miniport driver - * Copyright (C) 2004 Mark Tempel - * - * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -/* INCLUDES *******************************************************************/ - -#include "usbehci.h" -#include "../../usbport/usbport.h" - -/* PUBLIC AND PRIVATE FUNCTIONS ***********************************************/ - -NTSTATUS STDCALL -DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) -{ - PUSB_CONTROLLER_INTERFACE ControllerInterface; - - USBPORT_AllocateUsbControllerInterface(&ControllerInterface); - - /* - * Set up the list of callbacks here. - * TODO TODO TODO - */ - - return USBPORT_RegisterUSBPortDriver(DriverObject, 0, ControllerInterface); -} +/* + * ReactOS USB EHCI miniport driver + * Copyright (C) 2004 Mark Tempel + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +/* INCLUDES *******************************************************************/ + +#include "usbehci.h" +#include "../../usbport/usbport.h" + +/* PUBLIC AND PRIVATE FUNCTIONS ***********************************************/ + +NTSTATUS STDCALL +DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) +{ + PUSB_CONTROLLER_INTERFACE ControllerInterface; + + USBPORT_AllocateUsbControllerInterface(&ControllerInterface); + + /* + * Set up the list of callbacks here. + * TODO TODO TODO + */ + + return USBPORT_RegisterUSBPortDriver(DriverObject, 0, ControllerInterface); +} diff --git a/reactos/drivers/usb/miniport/usbehci/usbehci.h b/reactos/drivers/usb/miniport/usbehci/usbehci.h index ef601bc8ccc..9a01dfbaa74 100644 --- a/reactos/drivers/usb/miniport/usbehci/usbehci.h +++ b/reactos/drivers/usb/miniport/usbehci/usbehci.h @@ -1,44 +1,44 @@ -/* - * ReactOS USB EHCI miniport driver - * - * Copyright (C) 2004 Mark Tempel - * - * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef USBEHCI_H -#define USBEHCI_H - -/* INCLUDES *******************************************************************/ - -#include "stddef.h" -#include "windef.h" -//#include - -#ifdef DBG -#define DPRINT(arg) DbgPrint arg; -#else -#define DPRINT(arg) -#endif - -// Export funcs here -/* -BOOL FASTCALL -VBESetColorRegisters( - PVBE_DEVICE_EXTENSION DeviceExtension, - PVIDEO_CLUT ColorLookUpTable, - PSTATUS_BLOCK StatusBlock); -*/ -#endif /* USBEHCI_H */ +/* + * ReactOS USB EHCI miniport driver + * + * Copyright (C) 2004 Mark Tempel + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef USBEHCI_H +#define USBEHCI_H + +/* INCLUDES *******************************************************************/ + +#include "stddef.h" +#include "windef.h" +//#include + +#ifdef DBG +#define DPRINT(arg) DbgPrint arg; +#else +#define DPRINT(arg) +#endif + +// Export funcs here +/* +BOOL FASTCALL +VBESetColorRegisters( + PVBE_DEVICE_EXTENSION DeviceExtension, + PVIDEO_CLUT ColorLookUpTable, + PSTATUS_BLOCK StatusBlock); +*/ +#endif /* USBEHCI_H */ diff --git a/reactos/drivers/usb/miniport/usbohci/usbohci.c b/reactos/drivers/usb/miniport/usbohci/usbohci.c index f8faf8991ca..d81e03cbac5 100644 --- a/reactos/drivers/usb/miniport/usbohci/usbohci.c +++ b/reactos/drivers/usb/miniport/usbohci/usbohci.c @@ -1,41 +1,41 @@ -/* - * ReactOS USB OpenHCI miniport driver - * Copyright (C) 2004 Mark Tempel - * - * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -/* INCLUDES *******************************************************************/ - -#include "usbohci.h" -#include "../../usbport/usbport.h" - -/* PUBLIC AND PRIVATE FUNCTIONS ***********************************************/ - -NTSTATUS STDCALL -DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) -{ - PUSB_CONTROLLER_INTERFACE ControllerInterface; - - USBPORT_AllocateUsbControllerInterface(&ControllerInterface); - - /* - * Set up the list of callbacks here. - * TODO TODO TODO - */ - - return USBPORT_RegisterUSBPortDriver(DriverObject, 0, ControllerInterface); -} +/* + * ReactOS USB OpenHCI miniport driver + * Copyright (C) 2004 Mark Tempel + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +/* INCLUDES *******************************************************************/ + +#include "usbohci.h" +#include "../../usbport/usbport.h" + +/* PUBLIC AND PRIVATE FUNCTIONS ***********************************************/ + +NTSTATUS STDCALL +DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) +{ + PUSB_CONTROLLER_INTERFACE ControllerInterface; + + USBPORT_AllocateUsbControllerInterface(&ControllerInterface); + + /* + * Set up the list of callbacks here. + * TODO TODO TODO + */ + + return USBPORT_RegisterUSBPortDriver(DriverObject, 0, ControllerInterface); +} diff --git a/reactos/drivers/usb/miniport/usbohci/usbohci.h b/reactos/drivers/usb/miniport/usbohci/usbohci.h index 21325b823fa..277c1233349 100644 --- a/reactos/drivers/usb/miniport/usbohci/usbohci.h +++ b/reactos/drivers/usb/miniport/usbohci/usbohci.h @@ -1,44 +1,44 @@ -/* - * ReactOS USB OpenHCI miniport driver - * - * Copyright (C) 2004 Mark Tempel - * - * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef USBOHCI_H -#define USBOHCI_H - -/* INCLUDES *******************************************************************/ - -#include "stddef.h" -#include "windef.h" -//#include - -#ifdef DBG -#define DPRINT(arg) DbgPrint arg; -#else -#define DPRINT(arg) -#endif - -// Export funcs here -/* -BOOL FASTCALL -VBESetColorRegisters( - PVBE_DEVICE_EXTENSION DeviceExtension, - PVIDEO_CLUT ColorLookUpTable, - PSTATUS_BLOCK StatusBlock); -*/ -#endif /* USBOHCI_H */ +/* + * ReactOS USB OpenHCI miniport driver + * + * Copyright (C) 2004 Mark Tempel + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef USBOHCI_H +#define USBOHCI_H + +/* INCLUDES *******************************************************************/ + +#include "stddef.h" +#include "windef.h" +//#include + +#ifdef DBG +#define DPRINT(arg) DbgPrint arg; +#else +#define DPRINT(arg) +#endif + +// Export funcs here +/* +BOOL FASTCALL +VBESetColorRegisters( + PVBE_DEVICE_EXTENSION DeviceExtension, + PVIDEO_CLUT ColorLookUpTable, + PSTATUS_BLOCK StatusBlock); +*/ +#endif /* USBOHCI_H */ diff --git a/reactos/drivers/usb/miniport/usbuhci/usbuhci.c b/reactos/drivers/usb/miniport/usbuhci/usbuhci.c index 7f057121a5d..00f76fc5bdc 100644 --- a/reactos/drivers/usb/miniport/usbuhci/usbuhci.c +++ b/reactos/drivers/usb/miniport/usbuhci/usbuhci.c @@ -1,43 +1,43 @@ -/* - * ReactOS USB UHCI miniport driver - * Copyright (C) 2004 Mark Tempel - * - * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -/* INCLUDES *******************************************************************/ - -#include "usbuhci.h" -#include "../../usbport/usbport.h" -#include -/* PUBLIC AND PRIVATE FUNCTIONS ***********************************************/ - -NTSTATUS STDCALL -DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) -{ - //return STATUS_SUCCESS; - //DPRINT1("USBUHCI.SYS DriverEntry\n"); - PUSB_CONTROLLER_INTERFACE ControllerInterface; - - USBPORT_AllocateUsbControllerInterface(&ControllerInterface); - - /* - * Set up the list of callbacks here. - * TODO TODO TODO - */ - - return USBPORT_RegisterUSBPortDriver(DriverObject, 0, ControllerInterface); -} +/* + * ReactOS USB UHCI miniport driver + * Copyright (C) 2004 Mark Tempel + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +/* INCLUDES *******************************************************************/ + +#include "usbuhci.h" +#include "../../usbport/usbport.h" +#include +/* PUBLIC AND PRIVATE FUNCTIONS ***********************************************/ + +NTSTATUS STDCALL +DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) +{ + //return STATUS_SUCCESS; + //DPRINT1("USBUHCI.SYS DriverEntry\n"); + PUSB_CONTROLLER_INTERFACE ControllerInterface; + + USBPORT_AllocateUsbControllerInterface(&ControllerInterface); + + /* + * Set up the list of callbacks here. + * TODO TODO TODO + */ + + return USBPORT_RegisterUSBPortDriver(DriverObject, 0, ControllerInterface); +} diff --git a/reactos/drivers/usb/miniport/usbuhci/usbuhci.h b/reactos/drivers/usb/miniport/usbuhci/usbuhci.h index b5fdde3aea2..3e68e0f14ba 100644 --- a/reactos/drivers/usb/miniport/usbuhci/usbuhci.h +++ b/reactos/drivers/usb/miniport/usbuhci/usbuhci.h @@ -1,38 +1,38 @@ -/* - * ReactOS USB UHCI miniport driver - * - * Copyright (C) 2004 Mark Tempel - * - * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef USBUHCI_H -#define USBUHCI_H - -/* INCLUDES *******************************************************************/ - -#include "stddef.h" -#include "windef.h" -//#include - -// Export funcs here -/* -BOOL FASTCALL -VBESetColorRegisters( - PVBE_DEVICE_EXTENSION DeviceExtension, - PVIDEO_CLUT ColorLookUpTable, - PSTATUS_BLOCK StatusBlock); -*/ -#endif /* USBUHCI_H */ +/* + * ReactOS USB UHCI miniport driver + * + * Copyright (C) 2004 Mark Tempel + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef USBUHCI_H +#define USBUHCI_H + +/* INCLUDES *******************************************************************/ + +#include "stddef.h" +#include "windef.h" +//#include + +// Export funcs here +/* +BOOL FASTCALL +VBESetColorRegisters( + PVBE_DEVICE_EXTENSION DeviceExtension, + PVIDEO_CLUT ColorLookUpTable, + PSTATUS_BLOCK StatusBlock); +*/ +#endif /* USBUHCI_H */ diff --git a/reactos/drivers/usb/usbd/test.c b/reactos/drivers/usb/usbd/test.c index 193a9200ba1..85fe0cbe2dc 100644 --- a/reactos/drivers/usb/usbd/test.c +++ b/reactos/drivers/usb/usbd/test.c @@ -1,33 +1,33 @@ -#include -#include -#include - -typedef ULONG STDCALL -(*USBD_GetInterfaceLengthTYPE)( - PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor, - PUCHAR BufferEnd - ); - -int main() -{ - HMODULE Lib; - USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; - USBD_GetInterfaceLengthTYPE USBD_GetInterfaceLength; - - InterfaceDescriptor.bLength = 10; - InterfaceDescriptor.bNumEndpoints = 2; - InterfaceDescriptor.bDescriptorType = /*USB_INTERFACE_DESCRIPTOR_TYPE*/2; - InterfaceDescriptor.iInterface = 0x1; - - Lib = LoadLibraryEx("usbd.sys", NULL, DONT_RESOLVE_DLL_REFERENCES); - USBD_GetInterfaceLength = (USBD_GetInterfaceLengthTYPE)GetProcAddress(Lib, "USBD_GetInterfaceLength"); - printf("%X\n", USBD_GetInterfaceLength(&InterfaceDescriptor, (PUCHAR)((DWORD)&InterfaceDescriptor + sizeof(InterfaceDescriptor)))); - FreeLibrary(Lib); - - Lib = LoadLibraryEx("usbd.ms", NULL, DONT_RESOLVE_DLL_REFERENCES); - USBD_GetInterfaceLength = (USBD_GetInterfaceLengthTYPE)GetProcAddress(Lib, "USBD_GetInterfaceLength"); - printf("%X\n", USBD_GetInterfaceLength(&InterfaceDescriptor, (PUCHAR)((DWORD)&InterfaceDescriptor + sizeof(InterfaceDescriptor)))); - FreeLibrary(Lib); - return 0; -} - +#include +#include +#include + +typedef ULONG STDCALL +(*USBD_GetInterfaceLengthTYPE)( + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor, + PUCHAR BufferEnd + ); + +int main() +{ + HMODULE Lib; + USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + USBD_GetInterfaceLengthTYPE USBD_GetInterfaceLength; + + InterfaceDescriptor.bLength = 10; + InterfaceDescriptor.bNumEndpoints = 2; + InterfaceDescriptor.bDescriptorType = /*USB_INTERFACE_DESCRIPTOR_TYPE*/2; + InterfaceDescriptor.iInterface = 0x1; + + Lib = LoadLibraryEx("usbd.sys", NULL, DONT_RESOLVE_DLL_REFERENCES); + USBD_GetInterfaceLength = (USBD_GetInterfaceLengthTYPE)GetProcAddress(Lib, "USBD_GetInterfaceLength"); + printf("%X\n", USBD_GetInterfaceLength(&InterfaceDescriptor, (PUCHAR)((DWORD)&InterfaceDescriptor + sizeof(InterfaceDescriptor)))); + FreeLibrary(Lib); + + Lib = LoadLibraryEx("usbd.ms", NULL, DONT_RESOLVE_DLL_REFERENCES); + USBD_GetInterfaceLength = (USBD_GetInterfaceLengthTYPE)GetProcAddress(Lib, "USBD_GetInterfaceLength"); + printf("%X\n", USBD_GetInterfaceLength(&InterfaceDescriptor, (PUCHAR)((DWORD)&InterfaceDescriptor + sizeof(InterfaceDescriptor)))); + FreeLibrary(Lib); + return 0; +} + diff --git a/reactos/drivers/usb/usbd/usbd.c b/reactos/drivers/usb/usbd/usbd.c index d33d67fd0b4..6aae920560c 100644 --- a/reactos/drivers/usb/usbd/usbd.c +++ b/reactos/drivers/usb/usbd/usbd.c @@ -1,459 +1,459 @@ -/* - * Universal Serial Bus Driver/Helper Library - * - * Written by Filip Navara - * - * Notes: - * This driver was obsoleted in Windows XP and most functions - * became pure stubs. But some of them were retained for backward - * compatibilty with existing drivers. - * - * Preserved functions: - * - * USBD_Debug_GetHeap (implemented) - * USBD_Debug_RetHeap (implemented) - * USBD_CalculateUsbBandwidth (implemented, tested) - * USBD_CreateConfigurationRequestEx (implemented) - * USBD_CreateConfigurationRequest - * USBD_GetInterfaceLength (implemented) - * USBD_ParseConfigurationDescriptorEx - * USBD_ParseDescriptors - * USBD_GetPdoRegistryParameters (implemented) - */ - -#include -#include -#ifndef PLUGPLAY_REGKEY_DRIVER -#define PLUGPLAY_REGKEY_DRIVER 2 -#endif -typedef struct _USBD_INTERFACE_LIST_ENTRY { - PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor; - PUSBD_INTERFACE_INFORMATION Interface; -} USBD_INTERFACE_LIST_ENTRY, *PUSBD_INTERFACE_LIST_ENTRY; - -NTSTATUS STDCALL -DriverEntry(PDRIVER_OBJECT DriverObject, - PUNICODE_STRING RegistryPath) -{ - return STATUS_SUCCESS; -} - -/* - * @implemented - */ -DWORD STDCALL -DllInitialize(DWORD Unknown) -{ - return 0; -} - -/* - * @implemented - */ -DWORD STDCALL -DllUnload(VOID) -{ - return 0; -} - -/* - * @implemented - */ -PVOID STDCALL -USBD_Debug_GetHeap(DWORD Unknown1, POOL_TYPE PoolType, ULONG NumberOfBytes, - ULONG Tag) -{ - return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag); -} - -/* - * @implemented - */ -VOID STDCALL -USBD_Debug_RetHeap(PVOID Heap, DWORD Unknown2, DWORD Unknown3) -{ - ExFreePool(Heap); -} - -/* - * @implemented - */ -VOID STDCALL -USBD_Debug_LogEntry(PCHAR Name, ULONG_PTR Info1, ULONG_PTR Info2, - ULONG_PTR Info3) -{ -} - -/* - * @implemented - */ -PVOID STDCALL -USBD_AllocateDeviceName(DWORD Unknown) -{ - return NULL; -} - -/* - * @implemented - */ -DWORD STDCALL -USBD_CalculateUsbBandwidth( - ULONG MaxPacketSize, - UCHAR EndpointType, - BOOLEAN LowSpeed - ) -{ - DWORD OverheadTable[] = { - 0x00, /* UsbdPipeTypeControl */ - 0x09, /* UsbdPipeTypeIsochronous */ - 0x00, /* UsbdPipeTypeBulk */ - 0x0d /* UsbdPipeTypeInterrupt */ - }; - DWORD Result; - - if (OverheadTable[EndpointType] != 0) - { - Result = ((MaxPacketSize + OverheadTable[EndpointType]) * 8 * 7) / 6; - if (LowSpeed) - return Result << 3; - return Result; - } - return 0; -} - -/* - * @implemented - */ -DWORD STDCALL -USBD_Dispatch(DWORD Unknown1, DWORD Unknown2, DWORD Unknown3, DWORD Unknown4) -{ - return 1; -} - -/* - * @implemented - */ -VOID STDCALL -USBD_FreeDeviceMutex(PVOID Unknown) -{ -} - -/* - * @implemented - */ -VOID STDCALL -USBD_FreeDeviceName(PVOID Unknown) -{ -} - -/* - * @implemented - */ -VOID STDCALL -USBD_WaitDeviceMutex(PVOID Unknown) -{ -} - -/* - * @implemented - */ -DWORD STDCALL -USBD_GetSuspendPowerState(DWORD Unknown1) -{ - return 0; -} - -/* - * @implemented - */ -NTSTATUS STDCALL -USBD_InitializeDevice(DWORD Unknown1, DWORD Unknown2, DWORD Unknown3, - DWORD Unknown4, DWORD Unknown5, DWORD Unknown6) -{ - return STATUS_NOT_SUPPORTED; -} - -/* - * @implemented - */ -NTSTATUS STDCALL -USBD_RegisterHostController(DWORD Unknown1, DWORD Unknown2, DWORD Unknown3, - DWORD Unknown4, DWORD Unknown5, DWORD Unknown6, DWORD Unknown7, - DWORD Unknown8, DWORD Unknown9, DWORD Unknown10) -{ - return STATUS_NOT_SUPPORTED; -} - -/* - * @implemented - */ -NTSTATUS STDCALL -USBD_GetDeviceInformation(DWORD Unknown1, DWORD Unknown2, DWORD Unknown3) -{ - return STATUS_NOT_SUPPORTED; -} - -/* - * @implemented - */ -NTSTATUS STDCALL -USBD_CreateDevice(DWORD Unknown1, DWORD Unknown2, DWORD Unknown3, - DWORD Unknown4, DWORD Unknown5) -{ - return STATUS_NOT_SUPPORTED; -} - -/* - * @implemented - */ -NTSTATUS STDCALL -USBD_RemoveDevice(DWORD Unknown1, DWORD Unknown2, DWORD Unknown3) -{ - return STATUS_NOT_SUPPORTED; -} - -/* - * @implemented - */ -VOID STDCALL -USBD_CompleteRequest(DWORD Unknown1, DWORD Unknown2) -{ -} - -/* - * @implemented - */ -VOID STDCALL -USBD_RegisterHcFilter( - PDEVICE_OBJECT DeviceObject, - PDEVICE_OBJECT FilterDeviceObject - ) -{ -} - -/* - * @implemented - */ -VOID STDCALL -USBD_SetSuspendPowerState(DWORD Unknown1, DWORD Unknown2) -{ -} - -/* - * @implemented - */ -NTSTATUS STDCALL -USBD_MakePdoName(DWORD Unknown1, DWORD Unknown2) -{ - return STATUS_NOT_SUPPORTED; -} - -/* - * @implemented - */ -NTSTATUS STDCALL -USBD_QueryBusTime( - PDEVICE_OBJECT RootHubPdo, - PULONG CurrentFrame - ) -{ - return STATUS_NOT_SUPPORTED; -} - -/* - * @implemented - */ -VOID STDCALL -USBD_GetUSBDIVersion( - PUSBD_VERSION_INFORMATION Version - ) -{ - if (Version != NULL) - { - Version->USBDI_Version = USBDI_VERSION; - Version->Supported_USB_Version = 0x100; - } -} - -/* - * @implemented - */ -NTSTATUS STDCALL -USBD_RestoreDevice(DWORD Unknown1, DWORD Unknown2, DWORD Unknown3) -{ - return STATUS_NOT_SUPPORTED; -} - -/* - * @implemented - */ -VOID STDCALL -USBD_RegisterHcDeviceCapabilities(DWORD Unknown1, DWORD Unknown2, - DWORD Unknown3) -{ -} - -/* - * @implemented - * FIXME: Test - */ -PURB -STDCALL -USBD_CreateConfigurationRequestEx( - PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, - PUSBD_INTERFACE_LIST_ENTRY InterfaceList - ) -{ - PURB Urb; - DWORD UrbSize; - DWORD InterfaceCount; - - for (InterfaceCount = 0; - InterfaceList[InterfaceCount].InterfaceDescriptor != NULL; - ++InterfaceCount) - ; - /* Include the NULL entry */ - ++InterfaceCount; - - UrbSize = sizeof(Urb->UrbSelectConfiguration) + - (InterfaceCount * sizeof(PUSBD_INTERFACE_LIST_ENTRY)); - Urb = ExAllocatePool(NonPagedPool, UrbSize); - Urb->UrbSelectConfiguration.Hdr.Function = - URB_FUNCTION_SELECT_CONFIGURATION; - Urb->UrbSelectConfiguration.Hdr.Length = - sizeof(Urb->UrbSelectConfiguration); - Urb->UrbSelectConfiguration.ConfigurationDescriptor = - ConfigurationDescriptor; - memcpy((PVOID)&Urb->UrbSelectConfiguration.Interface, (PVOID)InterfaceList, - InterfaceCount * sizeof(PUSBD_INTERFACE_LIST_ENTRY)); - - return Urb; -} - -/* - * @unimplemented - */ -PURB STDCALL -USBD_CreateConfigurationRequest( - PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, - PUSHORT Size - ) -{ - return NULL; -} - -/* - * @unimplemented - */ -ULONG STDCALL -USBD_GetInterfaceLength( - PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor, - PUCHAR BufferEnd - ) -{ - ULONG_PTR Current; - PUSB_INTERFACE_DESCRIPTOR CurrentDescriptor = InterfaceDescriptor; - DWORD Length = CurrentDescriptor->bLength; - - // USB_ENDPOINT_DESCRIPTOR_TYPE - if (CurrentDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE) - { - for (Current = (ULONG_PTR)CurrentDescriptor; - Current < (ULONG_PTR)BufferEnd; - Current += CurrentDescriptor->bLength) - CurrentDescriptor = (PUSB_INTERFACE_DESCRIPTOR)Current; - Length += CurrentDescriptor->bLength; - - } - return Length; -} - -/* - * @unimplemented - */ -PUSB_INTERFACE_DESCRIPTOR STDCALL -USBD_ParseConfigurationDescriptorEx( - PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, - PVOID StartPosition, - LONG InterfaceNumber, - LONG AlternateSetting, - LONG InterfaceClass, - LONG InterfaceSubClass, - LONG InterfaceProtocol - ) -{ - return NULL; -} - -/* - * @implemented - */ -PUSB_INTERFACE_DESCRIPTOR STDCALL -USBD_ParseConfigurationDescriptor( - PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, - UCHAR InterfaceNumber, - UCHAR AlternateSetting - ) -{ - return USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, - (PVOID)ConfigurationDescriptor, InterfaceNumber, AlternateSetting, - -1, -1, -1); -} - -/* - * @unimplemented - */ -PUSB_COMMON_DESCRIPTOR STDCALL -USBD_ParseDescriptors( - PVOID DescriptorBuffer, - ULONG TotalLength, - PVOID StartPosition, - LONG DescriptorType - ) -{ - return NULL; -} - -/* - * @implemented - */ -DWORD STDCALL -USBD_GetPdoRegistryParameter( - PDEVICE_OBJECT PhysicalDeviceObject, - PVOID Parameter, - ULONG ParameterLength, - PWCHAR KeyName, - ULONG KeyNameLength - ) -{ - NTSTATUS Status; - HANDLE DevInstRegKey; - - Status = IoOpenDeviceRegistryKey(PhysicalDeviceObject, - PLUGPLAY_REGKEY_DRIVER, STANDARD_RIGHTS_ALL, &DevInstRegKey); - if (NT_SUCCESS(Status)) - { - PKEY_VALUE_FULL_INFORMATION FullInfo; - UNICODE_STRING ValueName; - ULONG Length; - - RtlInitUnicodeString(&ValueName, KeyName); - Length = ParameterLength + KeyNameLength + sizeof(KEY_VALUE_FULL_INFORMATION); - FullInfo = ExAllocatePool(PagedPool, Length); - if (FullInfo) - { - Status = ZwQueryValueKey(DevInstRegKey, &ValueName, - KeyValueFullInformation, FullInfo, Length, &Length); - if (NT_SUCCESS(Status)) - { - RtlCopyMemory(Parameter, - ((PUCHAR)FullInfo) + FullInfo->DataOffset, - ParameterLength /*FullInfo->DataLength*/); - } - ExFreePool(FullInfo); - } else - Status = STATUS_NO_MEMORY; - ZwClose(DevInstRegKey); - } - return Status; -} +/* + * Universal Serial Bus Driver/Helper Library + * + * Written by Filip Navara + * + * Notes: + * This driver was obsoleted in Windows XP and most functions + * became pure stubs. But some of them were retained for backward + * compatibilty with existing drivers. + * + * Preserved functions: + * + * USBD_Debug_GetHeap (implemented) + * USBD_Debug_RetHeap (implemented) + * USBD_CalculateUsbBandwidth (implemented, tested) + * USBD_CreateConfigurationRequestEx (implemented) + * USBD_CreateConfigurationRequest + * USBD_GetInterfaceLength (implemented) + * USBD_ParseConfigurationDescriptorEx + * USBD_ParseDescriptors + * USBD_GetPdoRegistryParameters (implemented) + */ + +#include +#include +#ifndef PLUGPLAY_REGKEY_DRIVER +#define PLUGPLAY_REGKEY_DRIVER 2 +#endif +typedef struct _USBD_INTERFACE_LIST_ENTRY { + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + PUSBD_INTERFACE_INFORMATION Interface; +} USBD_INTERFACE_LIST_ENTRY, *PUSBD_INTERFACE_LIST_ENTRY; + +NTSTATUS STDCALL +DriverEntry(PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath) +{ + return STATUS_SUCCESS; +} + +/* + * @implemented + */ +DWORD STDCALL +DllInitialize(DWORD Unknown) +{ + return 0; +} + +/* + * @implemented + */ +DWORD STDCALL +DllUnload(VOID) +{ + return 0; +} + +/* + * @implemented + */ +PVOID STDCALL +USBD_Debug_GetHeap(DWORD Unknown1, POOL_TYPE PoolType, ULONG NumberOfBytes, + ULONG Tag) +{ + return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag); +} + +/* + * @implemented + */ +VOID STDCALL +USBD_Debug_RetHeap(PVOID Heap, DWORD Unknown2, DWORD Unknown3) +{ + ExFreePool(Heap); +} + +/* + * @implemented + */ +VOID STDCALL +USBD_Debug_LogEntry(PCHAR Name, ULONG_PTR Info1, ULONG_PTR Info2, + ULONG_PTR Info3) +{ +} + +/* + * @implemented + */ +PVOID STDCALL +USBD_AllocateDeviceName(DWORD Unknown) +{ + return NULL; +} + +/* + * @implemented + */ +DWORD STDCALL +USBD_CalculateUsbBandwidth( + ULONG MaxPacketSize, + UCHAR EndpointType, + BOOLEAN LowSpeed + ) +{ + DWORD OverheadTable[] = { + 0x00, /* UsbdPipeTypeControl */ + 0x09, /* UsbdPipeTypeIsochronous */ + 0x00, /* UsbdPipeTypeBulk */ + 0x0d /* UsbdPipeTypeInterrupt */ + }; + DWORD Result; + + if (OverheadTable[EndpointType] != 0) + { + Result = ((MaxPacketSize + OverheadTable[EndpointType]) * 8 * 7) / 6; + if (LowSpeed) + return Result << 3; + return Result; + } + return 0; +} + +/* + * @implemented + */ +DWORD STDCALL +USBD_Dispatch(DWORD Unknown1, DWORD Unknown2, DWORD Unknown3, DWORD Unknown4) +{ + return 1; +} + +/* + * @implemented + */ +VOID STDCALL +USBD_FreeDeviceMutex(PVOID Unknown) +{ +} + +/* + * @implemented + */ +VOID STDCALL +USBD_FreeDeviceName(PVOID Unknown) +{ +} + +/* + * @implemented + */ +VOID STDCALL +USBD_WaitDeviceMutex(PVOID Unknown) +{ +} + +/* + * @implemented + */ +DWORD STDCALL +USBD_GetSuspendPowerState(DWORD Unknown1) +{ + return 0; +} + +/* + * @implemented + */ +NTSTATUS STDCALL +USBD_InitializeDevice(DWORD Unknown1, DWORD Unknown2, DWORD Unknown3, + DWORD Unknown4, DWORD Unknown5, DWORD Unknown6) +{ + return STATUS_NOT_SUPPORTED; +} + +/* + * @implemented + */ +NTSTATUS STDCALL +USBD_RegisterHostController(DWORD Unknown1, DWORD Unknown2, DWORD Unknown3, + DWORD Unknown4, DWORD Unknown5, DWORD Unknown6, DWORD Unknown7, + DWORD Unknown8, DWORD Unknown9, DWORD Unknown10) +{ + return STATUS_NOT_SUPPORTED; +} + +/* + * @implemented + */ +NTSTATUS STDCALL +USBD_GetDeviceInformation(DWORD Unknown1, DWORD Unknown2, DWORD Unknown3) +{ + return STATUS_NOT_SUPPORTED; +} + +/* + * @implemented + */ +NTSTATUS STDCALL +USBD_CreateDevice(DWORD Unknown1, DWORD Unknown2, DWORD Unknown3, + DWORD Unknown4, DWORD Unknown5) +{ + return STATUS_NOT_SUPPORTED; +} + +/* + * @implemented + */ +NTSTATUS STDCALL +USBD_RemoveDevice(DWORD Unknown1, DWORD Unknown2, DWORD Unknown3) +{ + return STATUS_NOT_SUPPORTED; +} + +/* + * @implemented + */ +VOID STDCALL +USBD_CompleteRequest(DWORD Unknown1, DWORD Unknown2) +{ +} + +/* + * @implemented + */ +VOID STDCALL +USBD_RegisterHcFilter( + PDEVICE_OBJECT DeviceObject, + PDEVICE_OBJECT FilterDeviceObject + ) +{ +} + +/* + * @implemented + */ +VOID STDCALL +USBD_SetSuspendPowerState(DWORD Unknown1, DWORD Unknown2) +{ +} + +/* + * @implemented + */ +NTSTATUS STDCALL +USBD_MakePdoName(DWORD Unknown1, DWORD Unknown2) +{ + return STATUS_NOT_SUPPORTED; +} + +/* + * @implemented + */ +NTSTATUS STDCALL +USBD_QueryBusTime( + PDEVICE_OBJECT RootHubPdo, + PULONG CurrentFrame + ) +{ + return STATUS_NOT_SUPPORTED; +} + +/* + * @implemented + */ +VOID STDCALL +USBD_GetUSBDIVersion( + PUSBD_VERSION_INFORMATION Version + ) +{ + if (Version != NULL) + { + Version->USBDI_Version = USBDI_VERSION; + Version->Supported_USB_Version = 0x100; + } +} + +/* + * @implemented + */ +NTSTATUS STDCALL +USBD_RestoreDevice(DWORD Unknown1, DWORD Unknown2, DWORD Unknown3) +{ + return STATUS_NOT_SUPPORTED; +} + +/* + * @implemented + */ +VOID STDCALL +USBD_RegisterHcDeviceCapabilities(DWORD Unknown1, DWORD Unknown2, + DWORD Unknown3) +{ +} + +/* + * @implemented + * FIXME: Test + */ +PURB +STDCALL +USBD_CreateConfigurationRequestEx( + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, + PUSBD_INTERFACE_LIST_ENTRY InterfaceList + ) +{ + PURB Urb; + DWORD UrbSize; + DWORD InterfaceCount; + + for (InterfaceCount = 0; + InterfaceList[InterfaceCount].InterfaceDescriptor != NULL; + ++InterfaceCount) + ; + /* Include the NULL entry */ + ++InterfaceCount; + + UrbSize = sizeof(Urb->UrbSelectConfiguration) + + (InterfaceCount * sizeof(PUSBD_INTERFACE_LIST_ENTRY)); + Urb = ExAllocatePool(NonPagedPool, UrbSize); + Urb->UrbSelectConfiguration.Hdr.Function = + URB_FUNCTION_SELECT_CONFIGURATION; + Urb->UrbSelectConfiguration.Hdr.Length = + sizeof(Urb->UrbSelectConfiguration); + Urb->UrbSelectConfiguration.ConfigurationDescriptor = + ConfigurationDescriptor; + memcpy((PVOID)&Urb->UrbSelectConfiguration.Interface, (PVOID)InterfaceList, + InterfaceCount * sizeof(PUSBD_INTERFACE_LIST_ENTRY)); + + return Urb; +} + +/* + * @unimplemented + */ +PURB STDCALL +USBD_CreateConfigurationRequest( + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, + PUSHORT Size + ) +{ + return NULL; +} + +/* + * @unimplemented + */ +ULONG STDCALL +USBD_GetInterfaceLength( + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor, + PUCHAR BufferEnd + ) +{ + ULONG_PTR Current; + PUSB_INTERFACE_DESCRIPTOR CurrentDescriptor = InterfaceDescriptor; + DWORD Length = CurrentDescriptor->bLength; + + // USB_ENDPOINT_DESCRIPTOR_TYPE + if (CurrentDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE) + { + for (Current = (ULONG_PTR)CurrentDescriptor; + Current < (ULONG_PTR)BufferEnd; + Current += CurrentDescriptor->bLength) + CurrentDescriptor = (PUSB_INTERFACE_DESCRIPTOR)Current; + Length += CurrentDescriptor->bLength; + + } + return Length; +} + +/* + * @unimplemented + */ +PUSB_INTERFACE_DESCRIPTOR STDCALL +USBD_ParseConfigurationDescriptorEx( + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, + PVOID StartPosition, + LONG InterfaceNumber, + LONG AlternateSetting, + LONG InterfaceClass, + LONG InterfaceSubClass, + LONG InterfaceProtocol + ) +{ + return NULL; +} + +/* + * @implemented + */ +PUSB_INTERFACE_DESCRIPTOR STDCALL +USBD_ParseConfigurationDescriptor( + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, + UCHAR InterfaceNumber, + UCHAR AlternateSetting + ) +{ + return USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, + (PVOID)ConfigurationDescriptor, InterfaceNumber, AlternateSetting, + -1, -1, -1); +} + +/* + * @unimplemented + */ +PUSB_COMMON_DESCRIPTOR STDCALL +USBD_ParseDescriptors( + PVOID DescriptorBuffer, + ULONG TotalLength, + PVOID StartPosition, + LONG DescriptorType + ) +{ + return NULL; +} + +/* + * @implemented + */ +DWORD STDCALL +USBD_GetPdoRegistryParameter( + PDEVICE_OBJECT PhysicalDeviceObject, + PVOID Parameter, + ULONG ParameterLength, + PWCHAR KeyName, + ULONG KeyNameLength + ) +{ + NTSTATUS Status; + HANDLE DevInstRegKey; + + Status = IoOpenDeviceRegistryKey(PhysicalDeviceObject, + PLUGPLAY_REGKEY_DRIVER, STANDARD_RIGHTS_ALL, &DevInstRegKey); + if (NT_SUCCESS(Status)) + { + PKEY_VALUE_FULL_INFORMATION FullInfo; + UNICODE_STRING ValueName; + ULONG Length; + + RtlInitUnicodeString(&ValueName, KeyName); + Length = ParameterLength + KeyNameLength + sizeof(KEY_VALUE_FULL_INFORMATION); + FullInfo = ExAllocatePool(PagedPool, Length); + if (FullInfo) + { + Status = ZwQueryValueKey(DevInstRegKey, &ValueName, + KeyValueFullInformation, FullInfo, Length, &Length); + if (NT_SUCCESS(Status)) + { + RtlCopyMemory(Parameter, + ((PUCHAR)FullInfo) + FullInfo->DataOffset, + ParameterLength /*FullInfo->DataLength*/); + } + ExFreePool(FullInfo); + } else + Status = STATUS_NO_MEMORY; + ZwClose(DevInstRegKey); + } + return Status; +} diff --git a/reactos/drivers/usb/usbhub/usbhub.c b/reactos/drivers/usb/usbhub/usbhub.c index 561f0568a9b..0fa00dfa4a3 100644 --- a/reactos/drivers/usb/usbhub/usbhub.c +++ b/reactos/drivers/usb/usbhub/usbhub.c @@ -1,38 +1,38 @@ -/* - * ReactOS USB hub driver - * Copyright (C) 2004 Aleksey Bragin - * (C) 2005 Mark Tempel - * - * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -/* INCLUDES *******************************************************************/ -#include -#include -#include -#include "../usbport/usbport.h" - -/* PUBLIC AND PRIVATE FUNCTIONS ***********************************************/ - -/* - * Standard DriverEntry method. - */ -NTSTATUS STDCALL -DriverEntry(IN PVOID Context1, IN PVOID Context2) -{ - return STATUS_SUCCESS; -} - +/* + * ReactOS USB hub driver + * Copyright (C) 2004 Aleksey Bragin + * (C) 2005 Mark Tempel + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +/* INCLUDES *******************************************************************/ +#include +#include +#include +#include "../usbport/usbport.h" + +/* PUBLIC AND PRIVATE FUNCTIONS ***********************************************/ + +/* + * Standard DriverEntry method. + */ +NTSTATUS STDCALL +DriverEntry(IN PVOID Context1, IN PVOID Context2) +{ + return STATUS_SUCCESS; +} + diff --git a/reactos/drivers/usb/usbhub/usbhub.h b/reactos/drivers/usb/usbhub/usbhub.h index 01a26a42a1c..8dbe83721ab 100644 --- a/reactos/drivers/usb/usbhub/usbhub.h +++ b/reactos/drivers/usb/usbhub/usbhub.h @@ -1,10 +1,10 @@ -/* - * Declarations for undocumented usbport.sys calls - * - * Written by Mark Tempel - */ - -#ifndef _USBHUB_H -#define _USBHUB_H - -#endif /* _USBHUB_H */ +/* + * Declarations for undocumented usbport.sys calls + * + * Written by Mark Tempel + */ + +#ifndef _USBHUB_H +#define _USBHUB_H + +#endif /* _USBHUB_H */ diff --git a/reactos/drivers/usb/usbport/usbport.h b/reactos/drivers/usb/usbport/usbport.h index 36cfc509be0..f62ec43098e 100644 --- a/reactos/drivers/usb/usbport/usbport.h +++ b/reactos/drivers/usb/usbport/usbport.h @@ -1,130 +1,130 @@ -/* - * Declarations for undocumented usbport.sys calls - * - * Written by Filip Navara - * Updates by Mark Tempel - */ - -#ifndef _USBPORT_H -#define _USBPORT_H - -#define USB_CONTROLLER_INTERFACE_TAG 0x001E1E10 - -/**** B E G I N M S I N T E R N A L P R O T O C O L ****/ -typedef DWORD (*POPEN_ENDPOINT)( - DWORD Unknown1, - DWORD Unknown2, - DWORD Unknown3 -); - -typedef NTSTATUS (*PPOKE_ENDPOINT)( - DWORD Unknown1, - DWORD Unknown2, - DWORD Unknown3 -); - -typedef DWORD (*PQUERY_ENDPOINT_REQUIREMENTS)( - DWORD Unknown1, - DWORD Unknown2, - DWORD Unknown3 -); - -typedef VOID (*PCLOSE_ENDPOINT)( - DWORD Unknown1, - DWORD Unknown2 -); - - - -typedef struct { - DWORD Unknown1; /* 2 (UHCI), 3 (EHCI) */ - DWORD Unknown2; /* 2C3 (UHCI), 95 (EHCI) */ - DWORD Unknown3; /* 2EE0 (UHCI), 61A80 (EHCI) */ - DWORD Unknown4; /* - */ - DWORD Unknown5; /* 164 (UHCI), 178 (EHCI) */ - DWORD Unknown6; /* 8C (UHCI), A0 (EHCI) */ - DWORD Unknown7; /* 1C (UHCI), 30 (EHCI) */ /* Offset: 118 */ - DWORD Unknown8; /* - */ - DWORD Unknown9; /* - */ - DWORD Unknown10; /* 2280 (UHCI), 2C800 (EHCI) */ /* Offset: 124 */ - POPEN_ENDPOINT OpenEndpoint; - PPOKE_ENDPOINT PokeEndpoint; - PQUERY_ENDPOINT_REQUIREMENTS QueryEndpointRequirements; - PCLOSE_ENDPOINT CloseEndpoint; - PVOID StartController; /* P00010A1C (2) */ /* Offset: 138 */ - PVOID StopController; /* P00010952 */ /* Offset: 13C */ - PVOID SuspendController; /* P00011584 */ /* Offset: 140 */ - PVOID ResumeController; /* P0001164C */ /* Offset: 144 */ - PVOID InterruptService; /* P00013C72 */ /* Offset: 148 */ - PVOID InterruptDpc; /* P00013D8E */ /* Offset: 14C */ - PVOID SubmitTransfer; /* P00011010 */ /* Offset: 150 */ - PVOID IsochTransfer; /* P000136E8 */ /* Offset: 154 */ - PVOID AbortTransfer; /* P00011092 */ /* Offset: 158 */ - PVOID GetEndpointState; /* P00010F48 */ /* Offset: 15C */ - PVOID SetEndpointState; /* P00010EFA */ /* Offset: 160 */ - PVOID PollEndpoint; /* P00010D32 */ /* Offset: 164 */ - PVOID CheckController; /* P00011794 */ /* Offset: 168 */ - PVOID Get32BitFrameNumber; /* P00010F86 */ /* Offset: 16C */ - PVOID InterruptNextSOF; /* P00013F56 */ /* Offset: 170 */ - PVOID EnableInterrupts; /* P00013ED0 */ /* Offset: 174 */ - PVOID DisableInterrupts; /* P00013E18 */ /* Offset: 178 */ - PVOID PollController; /* P00010FF2 */ /* Offset: 17C */ - PVOID SetEndpointDataToggle; /* P000110E6 */ /* Offset: 180 */ - PVOID GetEndpointStatus; /* P00010ECE */ /* Offset: 184 */ - PVOID SetEndpointStatus; /* P00010E52 */ /* Offset: 188 */ - DWORD Unknown36; /* - */ - PVOID RHGetRootHubData; /* P00011AC6 */ /* Offset: 190 */ - PVOID RHGetStatus; /* P00011B1A */ /* Offset: 194 */ - PVOID RHGetPortStatus; /* P00011BBA */ /* Offset: 198 */ - PVOID RHGetHubStatus; /* P00011B28 */ /* Offset: 19C */ - PVOID RHSetFeaturePortReset; /* P00011F84 */ /* Offset: 1A0 */ - PVOID RHSetFeaturePortPower; /* P00011BB4 */ /* Offset: 1A4 */ - PVOID RHSetFeaturePortEnable; /* P00011BA2 */ /* Offset: 1A8 */ - PVOID RHSetFeaturePortSuspend; /* P00011FF8 */ /* Offset: 1AC */ - PVOID RHClearFeaturePortEnable; /* P00011B90 */ /* Offset: 1B0 */ - PVOID RHClearFeaturePortPower; /* P00011BB4 */ /* Offset: 1B4 */ - PVOID RHClearFeaturePortSuspend; /* P0001210E */ /* Offset: 1B8 */ - PVOID RHClearFeaturePortEnableChange; /* P00012236 */ /* Offset: 1BC */ - PVOID RHClearFeaturePortConnectChange; /* P000121DE */ /* Offset: 1C0 */ - PVOID RHClearFeaturePortResetChange; /* P00012284 */ /* Offset: 1C4 */ - PVOID RHClearFeaturePortSuspendChange; /* P0001229C */ /* Offset: 1C8 */ - PVOID RHClearFeaturePortOvercurrentChange; /* P000122B4 */ /* Offset: 1CC */ - PVOID RHDisableIrq; /* P00013F52 */ /* Offset: 1D0 */ - PVOID RHDisableIrq2; /* P00013F52 */ /* Offset: 1D4 */ - PVOID StartSendOnePacket; /* P00011144 */ /* Offset: 1D8 */ - PVOID EndSendOnePacket; /* P000119B6 */ /* Offset: 1DC */ - PVOID PassThru; /* P000110E0 */ /* Offset: 1E0 */ - DWORD Unknown58[17]; /* - */ - PVOID FlushInterrupts; /* P00013EA0 */ /* Offset: 228 */ - /* ... */ -} USB_CONTROLLER_INTERFACE, *PUSB_CONTROLLER_INTERFACE; -/**** E N D M S I N T E R N A L P R O T O C O L ****/ - -/* - * With this call USB miniport driver registers itself with usbport.sys - * - * Unknown1 - Could be 0x64 or 0xC8. (0x9A also ?) - * Unknown2 - Pointer to structure which contains function entry points - */ -NTSTATUS STDCALL -USBPORT_RegisterUSBPortDriver(PDRIVER_OBJECT DriverObject, DWORD Unknown1, - PUSB_CONTROLLER_INTERFACE Interface); - -/* - * This function always returns 0x10000001 in Windows XP SP1 - */ -NTSTATUS STDCALL -USBPORT_GetHciMn(VOID); - -/* - * This method is provided for miniports to use to allocate their USB_CONTROLLER_INTERFACEs. - */ -NTSTATUS STDCALL -USBPORT_AllocateUsbControllerInterface(OUT PUSB_CONTROLLER_INTERFACE *pControllerInterface); - -/* - * We can't have an allocate without a free. - */ -NTSTATUS STDCALL -USBPORT_FreeUsbControllerInterface(IN PUSB_CONTROLLER_INTERFACE ControllerInterface); -#endif /* _USBPORT_H */ +/* + * Declarations for undocumented usbport.sys calls + * + * Written by Filip Navara + * Updates by Mark Tempel + */ + +#ifndef _USBPORT_H +#define _USBPORT_H + +#define USB_CONTROLLER_INTERFACE_TAG 0x001E1E10 + +/**** B E G I N M S I N T E R N A L P R O T O C O L ****/ +typedef DWORD (*POPEN_ENDPOINT)( + DWORD Unknown1, + DWORD Unknown2, + DWORD Unknown3 +); + +typedef NTSTATUS (*PPOKE_ENDPOINT)( + DWORD Unknown1, + DWORD Unknown2, + DWORD Unknown3 +); + +typedef DWORD (*PQUERY_ENDPOINT_REQUIREMENTS)( + DWORD Unknown1, + DWORD Unknown2, + DWORD Unknown3 +); + +typedef VOID (*PCLOSE_ENDPOINT)( + DWORD Unknown1, + DWORD Unknown2 +); + + + +typedef struct { + DWORD Unknown1; /* 2 (UHCI), 3 (EHCI) */ + DWORD Unknown2; /* 2C3 (UHCI), 95 (EHCI) */ + DWORD Unknown3; /* 2EE0 (UHCI), 61A80 (EHCI) */ + DWORD Unknown4; /* - */ + DWORD Unknown5; /* 164 (UHCI), 178 (EHCI) */ + DWORD Unknown6; /* 8C (UHCI), A0 (EHCI) */ + DWORD Unknown7; /* 1C (UHCI), 30 (EHCI) */ /* Offset: 118 */ + DWORD Unknown8; /* - */ + DWORD Unknown9; /* - */ + DWORD Unknown10; /* 2280 (UHCI), 2C800 (EHCI) */ /* Offset: 124 */ + POPEN_ENDPOINT OpenEndpoint; + PPOKE_ENDPOINT PokeEndpoint; + PQUERY_ENDPOINT_REQUIREMENTS QueryEndpointRequirements; + PCLOSE_ENDPOINT CloseEndpoint; + PVOID StartController; /* P00010A1C (2) */ /* Offset: 138 */ + PVOID StopController; /* P00010952 */ /* Offset: 13C */ + PVOID SuspendController; /* P00011584 */ /* Offset: 140 */ + PVOID ResumeController; /* P0001164C */ /* Offset: 144 */ + PVOID InterruptService; /* P00013C72 */ /* Offset: 148 */ + PVOID InterruptDpc; /* P00013D8E */ /* Offset: 14C */ + PVOID SubmitTransfer; /* P00011010 */ /* Offset: 150 */ + PVOID IsochTransfer; /* P000136E8 */ /* Offset: 154 */ + PVOID AbortTransfer; /* P00011092 */ /* Offset: 158 */ + PVOID GetEndpointState; /* P00010F48 */ /* Offset: 15C */ + PVOID SetEndpointState; /* P00010EFA */ /* Offset: 160 */ + PVOID PollEndpoint; /* P00010D32 */ /* Offset: 164 */ + PVOID CheckController; /* P00011794 */ /* Offset: 168 */ + PVOID Get32BitFrameNumber; /* P00010F86 */ /* Offset: 16C */ + PVOID InterruptNextSOF; /* P00013F56 */ /* Offset: 170 */ + PVOID EnableInterrupts; /* P00013ED0 */ /* Offset: 174 */ + PVOID DisableInterrupts; /* P00013E18 */ /* Offset: 178 */ + PVOID PollController; /* P00010FF2 */ /* Offset: 17C */ + PVOID SetEndpointDataToggle; /* P000110E6 */ /* Offset: 180 */ + PVOID GetEndpointStatus; /* P00010ECE */ /* Offset: 184 */ + PVOID SetEndpointStatus; /* P00010E52 */ /* Offset: 188 */ + DWORD Unknown36; /* - */ + PVOID RHGetRootHubData; /* P00011AC6 */ /* Offset: 190 */ + PVOID RHGetStatus; /* P00011B1A */ /* Offset: 194 */ + PVOID RHGetPortStatus; /* P00011BBA */ /* Offset: 198 */ + PVOID RHGetHubStatus; /* P00011B28 */ /* Offset: 19C */ + PVOID RHSetFeaturePortReset; /* P00011F84 */ /* Offset: 1A0 */ + PVOID RHSetFeaturePortPower; /* P00011BB4 */ /* Offset: 1A4 */ + PVOID RHSetFeaturePortEnable; /* P00011BA2 */ /* Offset: 1A8 */ + PVOID RHSetFeaturePortSuspend; /* P00011FF8 */ /* Offset: 1AC */ + PVOID RHClearFeaturePortEnable; /* P00011B90 */ /* Offset: 1B0 */ + PVOID RHClearFeaturePortPower; /* P00011BB4 */ /* Offset: 1B4 */ + PVOID RHClearFeaturePortSuspend; /* P0001210E */ /* Offset: 1B8 */ + PVOID RHClearFeaturePortEnableChange; /* P00012236 */ /* Offset: 1BC */ + PVOID RHClearFeaturePortConnectChange; /* P000121DE */ /* Offset: 1C0 */ + PVOID RHClearFeaturePortResetChange; /* P00012284 */ /* Offset: 1C4 */ + PVOID RHClearFeaturePortSuspendChange; /* P0001229C */ /* Offset: 1C8 */ + PVOID RHClearFeaturePortOvercurrentChange; /* P000122B4 */ /* Offset: 1CC */ + PVOID RHDisableIrq; /* P00013F52 */ /* Offset: 1D0 */ + PVOID RHDisableIrq2; /* P00013F52 */ /* Offset: 1D4 */ + PVOID StartSendOnePacket; /* P00011144 */ /* Offset: 1D8 */ + PVOID EndSendOnePacket; /* P000119B6 */ /* Offset: 1DC */ + PVOID PassThru; /* P000110E0 */ /* Offset: 1E0 */ + DWORD Unknown58[17]; /* - */ + PVOID FlushInterrupts; /* P00013EA0 */ /* Offset: 228 */ + /* ... */ +} USB_CONTROLLER_INTERFACE, *PUSB_CONTROLLER_INTERFACE; +/**** E N D M S I N T E R N A L P R O T O C O L ****/ + +/* + * With this call USB miniport driver registers itself with usbport.sys + * + * Unknown1 - Could be 0x64 or 0xC8. (0x9A also ?) + * Unknown2 - Pointer to structure which contains function entry points + */ +NTSTATUS STDCALL +USBPORT_RegisterUSBPortDriver(PDRIVER_OBJECT DriverObject, DWORD Unknown1, + PUSB_CONTROLLER_INTERFACE Interface); + +/* + * This function always returns 0x10000001 in Windows XP SP1 + */ +NTSTATUS STDCALL +USBPORT_GetHciMn(VOID); + +/* + * This method is provided for miniports to use to allocate their USB_CONTROLLER_INTERFACEs. + */ +NTSTATUS STDCALL +USBPORT_AllocateUsbControllerInterface(OUT PUSB_CONTROLLER_INTERFACE *pControllerInterface); + +/* + * We can't have an allocate without a free. + */ +NTSTATUS STDCALL +USBPORT_FreeUsbControllerInterface(IN PUSB_CONTROLLER_INTERFACE ControllerInterface); +#endif /* _USBPORT_H */ diff --git a/reactos/drivers/video/videoprt/agp.c b/reactos/drivers/video/videoprt/agp.c index a40d96bcb09..58fe3db83c0 100644 --- a/reactos/drivers/video/videoprt/agp.c +++ b/reactos/drivers/video/videoprt/agp.c @@ -1,566 +1,566 @@ -/* - * VideoPort driver - * - * Copyright (C) 2002, 2003, 2004 ReactOS Team - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; see the file COPYING.LIB. - * If not, write to the Free Software Foundation, - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Id$ - */ - -#include "videoprt.h" -#include -#include - -/* PRIVATE FUNCTIONS **********************************************************/ - -STATIC NTSTATUS -IopInitiatePnpIrp( - PDEVICE_OBJECT DeviceObject, - PIO_STATUS_BLOCK IoStatusBlock, - ULONG MinorFunction, - PIO_STACK_LOCATION Stack OPTIONAL) -{ - PDEVICE_OBJECT TopDeviceObject; - PIO_STACK_LOCATION IrpSp; - NTSTATUS Status; - KEVENT Event; - PIRP Irp; - - /* Always call the top of the device stack */ - TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject); - - KeInitializeEvent( - &Event, - NotificationEvent, - FALSE); - - Irp = IoBuildSynchronousFsdRequest( - IRP_MJ_PNP, - TopDeviceObject, - NULL, - 0, - NULL, - &Event, - IoStatusBlock); - - /* PNP IRPs are always initialized with a status code of - STATUS_NOT_IMPLEMENTED */ - Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; - Irp->IoStatus.Information = 0; - - IrpSp = IoGetNextIrpStackLocation(Irp); - IrpSp->MinorFunction = MinorFunction; - - if (Stack) - { - RtlMoveMemory( - &IrpSp->Parameters, - &Stack->Parameters, - sizeof(Stack->Parameters)); - } - - Status = IoCallDriver(TopDeviceObject, Irp); - if (Status == STATUS_PENDING) - { - KeWaitForSingleObject( - &Event, - Executive, - KernelMode, - FALSE, - NULL); - Status = IoStatusBlock->Status; - } - - ObDereferenceObject(TopDeviceObject); - - return Status; -} - - -BOOLEAN STDCALL -IntAgpCommitPhysical( - IN PVOID HwDeviceExtension, - IN PVOID PhysicalContext, - IN ULONG Pages, - IN ULONG Offset) -{ - PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; - PAGP_BUS_INTERFACE_STANDARD AgpBusInterface; - PHYSICAL_ADDRESS MappingAddr = {{0}}; - PVIDEO_PORT_AGP_MAPPING AgpMapping; - NTSTATUS Status; - - DPRINT("AgpCommitPhysical - PhysicalContext: 0x%x Pages: %d, Offset: 0x%x\n", - PhysicalContext, Pages, Offset); - - DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); - AgpBusInterface = &DeviceExtension->AgpInterface; - AgpMapping = (PVIDEO_PORT_AGP_MAPPING)PhysicalContext; - - Status = AgpBusInterface->CommitMemory(AgpBusInterface->AgpContext, - AgpMapping->MapHandle, Pages, Offset, - NULL, &MappingAddr); - - if (!NT_SUCCESS(Status)) - { - DPRINT1("Warning: AgpBusInterface->CommitMemory failed (Status = 0x%x)\n", - Status); - } - return NT_SUCCESS(Status); -} - -VOID STDCALL -IntAgpFreePhysical( - IN PVOID HwDeviceExtension, - IN PVOID PhysicalContext, - IN ULONG Pages, - IN ULONG Offset) -{ - PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; - PAGP_BUS_INTERFACE_STANDARD AgpBusInterface; - PVIDEO_PORT_AGP_MAPPING AgpMapping; - NTSTATUS Status; - - DPRINT("AgpFreePhysical - PhysicalContext: 0x%x Pages: %d, Offset: 0x%x\n", - PhysicalContext, Pages, Offset); - - DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); - AgpBusInterface = &DeviceExtension->AgpInterface; - AgpMapping = (PVIDEO_PORT_AGP_MAPPING)PhysicalContext; - - Status = AgpBusInterface->FreeMemory(AgpBusInterface->AgpContext, - AgpMapping->MapHandle, Pages, Offset); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Warning: AgpBusInterface->FreeMemory failed (Status = 0x%x)\n", - Status); - } -} - -VOID STDCALL -IntAgpReleasePhysical( - IN PVOID HwDeviceExtension, - IN PVOID PhysicalContext) -{ - PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; - PAGP_BUS_INTERFACE_STANDARD AgpBusInterface; - PVIDEO_PORT_AGP_MAPPING AgpMapping; - NTSTATUS Status; - - DPRINT("AgpReleasePhysical - PhysicalContext: 0x%x\n", PhysicalContext); - - DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); - AgpBusInterface = &DeviceExtension->AgpInterface; - AgpMapping = (PVIDEO_PORT_AGP_MAPPING)PhysicalContext; - - /* Release memory */ - Status = AgpBusInterface->ReleaseMemory(AgpBusInterface->AgpContext, - AgpMapping->MapHandle); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Warning: AgpBusInterface->ReleaseMemory failed (Status = 0x%x)\n", - Status); - } - - /* Free resources */ - ExFreePool(AgpMapping); -} - -PHYSICAL_ADDRESS STDCALL -IntAgpReservePhysical( - IN PVOID HwDeviceExtension, - IN ULONG Pages, - IN VIDEO_PORT_CACHE_TYPE Caching, - OUT PVOID *PhysicalContext) -{ - PHYSICAL_ADDRESS ZeroAddress = {{0}}; - PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; - PAGP_BUS_INTERFACE_STANDARD AgpBusInterface; - MEMORY_CACHING_TYPE MemCachingType; - PVIDEO_PORT_AGP_MAPPING AgpMapping; - NTSTATUS Status; - - DPRINT("AgpReservePhysical - Pages: %d, Caching: 0x%x\n", Pages, Caching); - - DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); - AgpBusInterface = &DeviceExtension->AgpInterface; - - /* Translate memory caching type */ - if (Caching == VpNonCached) - MemCachingType = MmNonCached; - else if (Caching == VpCached) - MemCachingType = MmCached; - else if (Caching == VpWriteCombined) - MemCachingType = MmWriteCombined; - else - { - DPRINT1("Invalid caching type %d!\n", Caching); - return ZeroAddress; - } - - /* Allocate an AGP mapping structure */ - AgpMapping = ExAllocatePoolWithTag(PagedPool, - sizeof(VIDEO_PORT_AGP_MAPPING), - TAG_VIDEO_PORT); - if (AgpMapping == NULL) - { - DPRINT1("Out of memory! Couldn't allocate AGP mapping structure!\n"); - return ZeroAddress; - } - RtlZeroMemory(AgpMapping, sizeof(VIDEO_PORT_AGP_MAPPING)); - - /* Reserve memory for the AGP bus */ - Status = AgpBusInterface->ReserveMemory(AgpBusInterface->AgpContext, - Pages, - MemCachingType, - &AgpMapping->MapHandle, - &AgpMapping->PhysicalAddress); - if (!NT_SUCCESS(Status) || AgpMapping->MapHandle == NULL) - { - ExFreePool(AgpMapping); - DPRINT1("Warning: AgpBusInterface->ReserveMemory failed (Status = 0x%x)\n", - Status); - return ZeroAddress; - } - - /* Fill the rest of the AGP mapping */ - AgpMapping->NumberOfPages = Pages; - - *PhysicalContext = (PVOID)AgpMapping; - return AgpMapping->PhysicalAddress; -} - - -PVOID STDCALL -IntAgpCommitVirtual( - IN PVOID HwDeviceExtension, - IN PVOID VirtualContext, - IN ULONG Pages, - IN ULONG Offset) -{ - PVIDEO_PORT_AGP_VIRTUAL_MAPPING VirtualMapping; - PVOID BaseAddress = NULL; - NTSTATUS Status; - - DPRINT("AgpCommitVirtual - VirtualContext: 0x%x Pages: %d, Offset: 0x%x\n", - VirtualContext, Pages, Offset); - - VirtualMapping = (PVIDEO_PORT_AGP_VIRTUAL_MAPPING)VirtualContext; - - /* I think the NT API provides no way of reserving a part of the address space - * and setting it up to map into a specified range of physical memory later. - * This means that we will have to release some of the reserved virtual memory - * and map the physical memory into it using MapViewOfSection. - * - * - blight (2004-12-21) - */ - - if (VirtualMapping->ProcessHandle == NULL) - { - /* FIXME: not implemented */ - } - else /* ProcessHandle != NULL */ - { - /* Release some virtual memory */ - ULONG Size = Pages * PAGE_SIZE; - ULONG OffsetInBytes = Offset * PAGE_SIZE; - BaseAddress = (PVOID)((ULONG_PTR)VirtualMapping->MappedAddress + - OffsetInBytes); - PHYSICAL_ADDRESS PhysicalAddress = VirtualMapping->AgpMapping->PhysicalAddress; - PhysicalAddress.QuadPart += OffsetInBytes; - - Status = ZwFreeVirtualMemory(VirtualMapping->ProcessHandle, - &BaseAddress, - &Size, MEM_RELEASE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Warning: ZwFreeVirtualMemory() failed: Status = 0x%x\n", Status); - return NULL; - } - ASSERT(Size == Pages * PAGE_SIZE); - ASSERT(BaseAddress == (PVOID)((ULONG_PTR)VirtualMapping->MappedAddress + - OffsetInBytes)); - - /* Map the physical memory into the released virtual memory area */ - Status = IntVideoPortMapPhysicalMemory(VirtualMapping->ProcessHandle, - PhysicalAddress, - Size, - PAGE_READWRITE, - &BaseAddress); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Warning: IntVideoPortMapPhysicalMemory() failed: Status = 0x%x\n", Status); - /* Reserve the released virtual memory area again */ - Status = ZwAllocateVirtualMemory(VirtualMapping->ProcessHandle, - &BaseAddress, 0, &Size, MEM_RESERVE, - PAGE_NOACCESS); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Warning: ZwAllocateVirtualMemory() failed: Status = 0x%x\n", Status); - /* FIXME: What to do now?? */ - ASSERT(0); - return NULL; - } - ASSERT(Size == Pages * PAGE_SIZE); - ASSERT(BaseAddress == (PVOID)((ULONG_PTR)VirtualMapping->MappedAddress + - OffsetInBytes)); - return NULL; - } - ASSERT(BaseAddress == (PVOID)((ULONG_PTR)VirtualMapping->MappedAddress + - OffsetInBytes)); - } - - return BaseAddress; -} - -VOID STDCALL -IntAgpFreeVirtual( - IN PVOID HwDeviceExtension, - IN PVOID VirtualContext, - IN ULONG Pages, - IN ULONG Offset) -{ - PVIDEO_PORT_AGP_VIRTUAL_MAPPING VirtualMapping; - PVOID BaseAddress = NULL; - NTSTATUS Status; - - DPRINT("AgpFreeVirtual - VirtualContext: 0x%x Pages: %d, Offset: 0x%x\n", - VirtualContext, Pages, Offset); - - VirtualMapping = (PVIDEO_PORT_AGP_VIRTUAL_MAPPING)VirtualContext; - - if (VirtualMapping->ProcessHandle == NULL) - { - /* FIXME: not implemented */ - } - else /* ProcessHandle != NULL */ - { - /* Unmap the section view */ - ULONG Size = Pages * PAGE_SIZE; - ULONG OffsetInBytes = Offset * PAGE_SIZE; - BaseAddress = (PVOID)((ULONG_PTR)VirtualMapping->MappedAddress + - OffsetInBytes); - - Status = ZwUnmapViewOfSection(VirtualMapping->ProcessHandle, BaseAddress); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Warning: ZwUnmapViewOfSection() failed: Status = 0x%x\n", Status); - /* FIXME: What to do now?? */ - ASSERT(0); - return; - } - - /* And reserve the virtual memory area again */ - Status = ZwAllocateVirtualMemory(VirtualMapping->ProcessHandle, - &BaseAddress, 0, &Size, MEM_RESERVE, - PAGE_NOACCESS); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Warning: ZwAllocateVirtualMemory() failed: Status = 0x%x\n", Status); - /* FIXME: What to do now?? */ - ASSERT(0); - return; - } - ASSERT(Size == Pages * PAGE_SIZE); - ASSERT(BaseAddress == (PVOID)((ULONG_PTR)VirtualMapping->MappedAddress + - OffsetInBytes)); - } -} - -VOID STDCALL -IntAgpReleaseVirtual( - IN PVOID HwDeviceExtension, - IN PVOID VirtualContext) -{ - PVIDEO_PORT_AGP_VIRTUAL_MAPPING VirtualMapping; - NTSTATUS Status; - - DPRINT("AgpReleaseVirtual - VirtualContext: 0x%x\n", VirtualContext); - - VirtualMapping = (PVIDEO_PORT_AGP_VIRTUAL_MAPPING)VirtualContext; - - /* Release the virtual memory */ - if (VirtualMapping->ProcessHandle == NULL) - { - /* FIXME: not implemented */ - } - else /* ProcessHandle != NULL */ - { - /* Release the allocated virtual memory */ - ULONG Size = VirtualMapping->AgpMapping->NumberOfPages * PAGE_SIZE; - Status = ZwFreeVirtualMemory(VirtualMapping->ProcessHandle, - &VirtualMapping->MappedAddress, - &Size, MEM_RELEASE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Warning: ZwFreeVirtualMemory() failed: Status = 0x%x\n", Status); - } - } - - /* Free resources */ - ExFreePool(VirtualMapping); -} - -PVOID STDCALL -IntAgpReserveVirtual( - IN PVOID HwDeviceExtension, - IN HANDLE ProcessHandle, - IN PVOID PhysicalContext, - OUT PVOID *VirtualContext) -{ - PVIDEO_PORT_AGP_MAPPING AgpMapping; - PVIDEO_PORT_AGP_VIRTUAL_MAPPING VirtualMapping; - PVOID MappedAddress; - NTSTATUS Status; - - DPRINT("AgpReserveVirtual - ProcessHandle: 0x%x PhysicalContext: 0x%x\n", - ProcessHandle, PhysicalContext); - - AgpMapping = (PVIDEO_PORT_AGP_MAPPING)PhysicalContext; - - /* Allocate an AGP virtual mapping structure */ - VirtualMapping = ExAllocatePoolWithTag(PagedPool, - sizeof(VIDEO_PORT_AGP_VIRTUAL_MAPPING), - TAG_VIDEO_PORT); - if (VirtualMapping == NULL) - { - DPRINT1("Out of memory! Couldn't allocate AGP virtual mapping structure!\n"); - return NULL; - } - RtlZeroMemory(VirtualMapping, sizeof(VIDEO_PORT_AGP_VIRTUAL_MAPPING)); - - /* Reserve a virtual memory area for the physical pages. */ - if (ProcessHandle == NULL) - { - /* FIXME: What to do in this case? */ - ExFreePool(VirtualMapping); - return NULL; - } - else /* ProcessHandle != NULL */ - { - /* Reserve memory for usermode */ - ULONG Size = AgpMapping->NumberOfPages * PAGE_SIZE; - MappedAddress = NULL; - Status = ZwAllocateVirtualMemory(ProcessHandle, &MappedAddress, 0, &Size, - MEM_RESERVE, PAGE_NOACCESS); - if (!NT_SUCCESS(Status)) - { - ExFreePool(VirtualMapping); - DPRINT("ZwAllocateVirtualMemory() failed: Status = 0x%x\n", Status); - return NULL; - } - } - - /* Fill the AGP virtual mapping */ - VirtualMapping->AgpMapping = AgpMapping; - VirtualMapping->ProcessHandle = ProcessHandle; - VirtualMapping->MappedAddress = MappedAddress; - - *VirtualContext = (PVOID)VirtualMapping; - return MappedAddress; -} - - -BOOLEAN STDCALL -IntAgpSetRate( - IN PVOID HwDeviceExtension, - IN ULONG Rate) -{ - PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; - PAGP_BUS_INTERFACE_STANDARD AgpBusInterface; - - DPRINT("AgpSetRate - Rate: %d\n", Rate); - - DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); - AgpBusInterface = &DeviceExtension->AgpInterface; - - return NT_SUCCESS(AgpBusInterface->SetRate(AgpBusInterface->AgpContext, Rate)); -} - - -NTSTATUS STDCALL -IntAgpGetInterface( - IN PVOID HwDeviceExtension, - IN OUT PINTERFACE Interface) -{ - IO_STATUS_BLOCK IoStatusBlock; - IO_STACK_LOCATION IoStack; - NTSTATUS Status; - PVIDEO_PORT_AGP_INTERFACE_2 AgpInterface; - PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; - PAGP_BUS_INTERFACE_STANDARD AgpBusInterface; - - DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); - AgpBusInterface = &DeviceExtension->AgpInterface; - AgpInterface = (PVIDEO_PORT_AGP_INTERFACE_2)Interface; - - ASSERT((Interface->Version == VIDEO_PORT_AGP_INTERFACE_VERSION_2 && - Interface->Size >= sizeof(VIDEO_PORT_AGP_INTERFACE_2)) || - (Interface->Version == VIDEO_PORT_AGP_INTERFACE_VERSION_1 && - Interface->Size >= sizeof(VIDEO_PORT_AGP_INTERFACE))); - - if (DeviceExtension->NextDeviceObject == NULL) - { - DPRINT("DeviceExtension->NextDeviceObject is NULL!\n"); - return STATUS_UNSUCCESSFUL; - } - - /* Query the interface from the AGP bus driver */ - if (DeviceExtension->AgpInterface.Size == 0) - { - AgpBusInterface->Size = sizeof(AGP_BUS_INTERFACE_STANDARD); - if (Interface->Version == VIDEO_PORT_AGP_INTERFACE_VERSION_1) - AgpBusInterface->Version = AGP_BUS_INTERFACE_V1; - else /* if (InterfaceVersion == VIDEO_PORT_AGP_INTERFACE_VERSION_2) */ - AgpBusInterface->Version = AGP_BUS_INTERFACE_V2; - IoStack.Parameters.QueryInterface.Size = AgpBusInterface->Size; - IoStack.Parameters.QueryInterface.Version = AgpBusInterface->Version; - IoStack.Parameters.QueryInterface.Interface = (PINTERFACE)AgpBusInterface; - IoStack.Parameters.QueryInterface.InterfaceType = - &GUID_AGP_TARGET_BUS_INTERFACE_STANDARD; - Status = IopInitiatePnpIrp(DeviceExtension->NextDeviceObject, - &IoStatusBlock, IRP_MN_QUERY_INTERFACE, &IoStack); - if (!NT_SUCCESS(Status)) - { - DPRINT("IopInitiatePnpIrp() failed! (Status 0x%x)\n", Status); - return Status; - } - DPRINT("Got AGP driver interface!\n"); - } - - /* FIXME: Not sure if we should wrap the reference/dereference functions */ - AgpInterface->Context = AgpBusInterface->AgpContext; - AgpInterface->InterfaceReference = AgpBusInterface->InterfaceReference; - AgpInterface->InterfaceDereference = AgpBusInterface->InterfaceDereference; - AgpInterface->AgpReservePhysical = IntAgpReservePhysical; - AgpInterface->AgpReleasePhysical = IntAgpReleasePhysical; - AgpInterface->AgpCommitPhysical = IntAgpCommitPhysical; - AgpInterface->AgpFreePhysical = IntAgpFreePhysical; - AgpInterface->AgpReserveVirtual = IntAgpReserveVirtual; - AgpInterface->AgpReleaseVirtual = IntAgpReleaseVirtual; - AgpInterface->AgpCommitVirtual = IntAgpCommitVirtual; - AgpInterface->AgpFreeVirtual = IntAgpFreeVirtual; - AgpInterface->AgpAllocationLimit = 0x1000000; /* FIXME: using 16 MB for now */ - - if (AgpInterface->Version >= VIDEO_PORT_AGP_INTERFACE_VERSION_2) - { - AgpInterface->AgpSetRate = IntAgpSetRate; - } - - return STATUS_SUCCESS; -} - +/* + * VideoPort driver + * + * Copyright (C) 2002, 2003, 2004 ReactOS Team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; see the file COPYING.LIB. + * If not, write to the Free Software Foundation, + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#include "videoprt.h" +#include +#include + +/* PRIVATE FUNCTIONS **********************************************************/ + +STATIC NTSTATUS +IopInitiatePnpIrp( + PDEVICE_OBJECT DeviceObject, + PIO_STATUS_BLOCK IoStatusBlock, + ULONG MinorFunction, + PIO_STACK_LOCATION Stack OPTIONAL) +{ + PDEVICE_OBJECT TopDeviceObject; + PIO_STACK_LOCATION IrpSp; + NTSTATUS Status; + KEVENT Event; + PIRP Irp; + + /* Always call the top of the device stack */ + TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject); + + KeInitializeEvent( + &Event, + NotificationEvent, + FALSE); + + Irp = IoBuildSynchronousFsdRequest( + IRP_MJ_PNP, + TopDeviceObject, + NULL, + 0, + NULL, + &Event, + IoStatusBlock); + + /* PNP IRPs are always initialized with a status code of + STATUS_NOT_IMPLEMENTED */ + Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED; + Irp->IoStatus.Information = 0; + + IrpSp = IoGetNextIrpStackLocation(Irp); + IrpSp->MinorFunction = MinorFunction; + + if (Stack) + { + RtlMoveMemory( + &IrpSp->Parameters, + &Stack->Parameters, + sizeof(Stack->Parameters)); + } + + Status = IoCallDriver(TopDeviceObject, Irp); + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject( + &Event, + Executive, + KernelMode, + FALSE, + NULL); + Status = IoStatusBlock->Status; + } + + ObDereferenceObject(TopDeviceObject); + + return Status; +} + + +BOOLEAN STDCALL +IntAgpCommitPhysical( + IN PVOID HwDeviceExtension, + IN PVOID PhysicalContext, + IN ULONG Pages, + IN ULONG Offset) +{ + PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; + PAGP_BUS_INTERFACE_STANDARD AgpBusInterface; + PHYSICAL_ADDRESS MappingAddr = {{0}}; + PVIDEO_PORT_AGP_MAPPING AgpMapping; + NTSTATUS Status; + + DPRINT("AgpCommitPhysical - PhysicalContext: 0x%x Pages: %d, Offset: 0x%x\n", + PhysicalContext, Pages, Offset); + + DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); + AgpBusInterface = &DeviceExtension->AgpInterface; + AgpMapping = (PVIDEO_PORT_AGP_MAPPING)PhysicalContext; + + Status = AgpBusInterface->CommitMemory(AgpBusInterface->AgpContext, + AgpMapping->MapHandle, Pages, Offset, + NULL, &MappingAddr); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("Warning: AgpBusInterface->CommitMemory failed (Status = 0x%x)\n", + Status); + } + return NT_SUCCESS(Status); +} + +VOID STDCALL +IntAgpFreePhysical( + IN PVOID HwDeviceExtension, + IN PVOID PhysicalContext, + IN ULONG Pages, + IN ULONG Offset) +{ + PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; + PAGP_BUS_INTERFACE_STANDARD AgpBusInterface; + PVIDEO_PORT_AGP_MAPPING AgpMapping; + NTSTATUS Status; + + DPRINT("AgpFreePhysical - PhysicalContext: 0x%x Pages: %d, Offset: 0x%x\n", + PhysicalContext, Pages, Offset); + + DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); + AgpBusInterface = &DeviceExtension->AgpInterface; + AgpMapping = (PVIDEO_PORT_AGP_MAPPING)PhysicalContext; + + Status = AgpBusInterface->FreeMemory(AgpBusInterface->AgpContext, + AgpMapping->MapHandle, Pages, Offset); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Warning: AgpBusInterface->FreeMemory failed (Status = 0x%x)\n", + Status); + } +} + +VOID STDCALL +IntAgpReleasePhysical( + IN PVOID HwDeviceExtension, + IN PVOID PhysicalContext) +{ + PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; + PAGP_BUS_INTERFACE_STANDARD AgpBusInterface; + PVIDEO_PORT_AGP_MAPPING AgpMapping; + NTSTATUS Status; + + DPRINT("AgpReleasePhysical - PhysicalContext: 0x%x\n", PhysicalContext); + + DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); + AgpBusInterface = &DeviceExtension->AgpInterface; + AgpMapping = (PVIDEO_PORT_AGP_MAPPING)PhysicalContext; + + /* Release memory */ + Status = AgpBusInterface->ReleaseMemory(AgpBusInterface->AgpContext, + AgpMapping->MapHandle); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Warning: AgpBusInterface->ReleaseMemory failed (Status = 0x%x)\n", + Status); + } + + /* Free resources */ + ExFreePool(AgpMapping); +} + +PHYSICAL_ADDRESS STDCALL +IntAgpReservePhysical( + IN PVOID HwDeviceExtension, + IN ULONG Pages, + IN VIDEO_PORT_CACHE_TYPE Caching, + OUT PVOID *PhysicalContext) +{ + PHYSICAL_ADDRESS ZeroAddress = {{0}}; + PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; + PAGP_BUS_INTERFACE_STANDARD AgpBusInterface; + MEMORY_CACHING_TYPE MemCachingType; + PVIDEO_PORT_AGP_MAPPING AgpMapping; + NTSTATUS Status; + + DPRINT("AgpReservePhysical - Pages: %d, Caching: 0x%x\n", Pages, Caching); + + DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); + AgpBusInterface = &DeviceExtension->AgpInterface; + + /* Translate memory caching type */ + if (Caching == VpNonCached) + MemCachingType = MmNonCached; + else if (Caching == VpCached) + MemCachingType = MmCached; + else if (Caching == VpWriteCombined) + MemCachingType = MmWriteCombined; + else + { + DPRINT1("Invalid caching type %d!\n", Caching); + return ZeroAddress; + } + + /* Allocate an AGP mapping structure */ + AgpMapping = ExAllocatePoolWithTag(PagedPool, + sizeof(VIDEO_PORT_AGP_MAPPING), + TAG_VIDEO_PORT); + if (AgpMapping == NULL) + { + DPRINT1("Out of memory! Couldn't allocate AGP mapping structure!\n"); + return ZeroAddress; + } + RtlZeroMemory(AgpMapping, sizeof(VIDEO_PORT_AGP_MAPPING)); + + /* Reserve memory for the AGP bus */ + Status = AgpBusInterface->ReserveMemory(AgpBusInterface->AgpContext, + Pages, + MemCachingType, + &AgpMapping->MapHandle, + &AgpMapping->PhysicalAddress); + if (!NT_SUCCESS(Status) || AgpMapping->MapHandle == NULL) + { + ExFreePool(AgpMapping); + DPRINT1("Warning: AgpBusInterface->ReserveMemory failed (Status = 0x%x)\n", + Status); + return ZeroAddress; + } + + /* Fill the rest of the AGP mapping */ + AgpMapping->NumberOfPages = Pages; + + *PhysicalContext = (PVOID)AgpMapping; + return AgpMapping->PhysicalAddress; +} + + +PVOID STDCALL +IntAgpCommitVirtual( + IN PVOID HwDeviceExtension, + IN PVOID VirtualContext, + IN ULONG Pages, + IN ULONG Offset) +{ + PVIDEO_PORT_AGP_VIRTUAL_MAPPING VirtualMapping; + PVOID BaseAddress = NULL; + NTSTATUS Status; + + DPRINT("AgpCommitVirtual - VirtualContext: 0x%x Pages: %d, Offset: 0x%x\n", + VirtualContext, Pages, Offset); + + VirtualMapping = (PVIDEO_PORT_AGP_VIRTUAL_MAPPING)VirtualContext; + + /* I think the NT API provides no way of reserving a part of the address space + * and setting it up to map into a specified range of physical memory later. + * This means that we will have to release some of the reserved virtual memory + * and map the physical memory into it using MapViewOfSection. + * + * - blight (2004-12-21) + */ + + if (VirtualMapping->ProcessHandle == NULL) + { + /* FIXME: not implemented */ + } + else /* ProcessHandle != NULL */ + { + /* Release some virtual memory */ + ULONG Size = Pages * PAGE_SIZE; + ULONG OffsetInBytes = Offset * PAGE_SIZE; + BaseAddress = (PVOID)((ULONG_PTR)VirtualMapping->MappedAddress + + OffsetInBytes); + PHYSICAL_ADDRESS PhysicalAddress = VirtualMapping->AgpMapping->PhysicalAddress; + PhysicalAddress.QuadPart += OffsetInBytes; + + Status = ZwFreeVirtualMemory(VirtualMapping->ProcessHandle, + &BaseAddress, + &Size, MEM_RELEASE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Warning: ZwFreeVirtualMemory() failed: Status = 0x%x\n", Status); + return NULL; + } + ASSERT(Size == Pages * PAGE_SIZE); + ASSERT(BaseAddress == (PVOID)((ULONG_PTR)VirtualMapping->MappedAddress + + OffsetInBytes)); + + /* Map the physical memory into the released virtual memory area */ + Status = IntVideoPortMapPhysicalMemory(VirtualMapping->ProcessHandle, + PhysicalAddress, + Size, + PAGE_READWRITE, + &BaseAddress); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Warning: IntVideoPortMapPhysicalMemory() failed: Status = 0x%x\n", Status); + /* Reserve the released virtual memory area again */ + Status = ZwAllocateVirtualMemory(VirtualMapping->ProcessHandle, + &BaseAddress, 0, &Size, MEM_RESERVE, + PAGE_NOACCESS); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Warning: ZwAllocateVirtualMemory() failed: Status = 0x%x\n", Status); + /* FIXME: What to do now?? */ + ASSERT(0); + return NULL; + } + ASSERT(Size == Pages * PAGE_SIZE); + ASSERT(BaseAddress == (PVOID)((ULONG_PTR)VirtualMapping->MappedAddress + + OffsetInBytes)); + return NULL; + } + ASSERT(BaseAddress == (PVOID)((ULONG_PTR)VirtualMapping->MappedAddress + + OffsetInBytes)); + } + + return BaseAddress; +} + +VOID STDCALL +IntAgpFreeVirtual( + IN PVOID HwDeviceExtension, + IN PVOID VirtualContext, + IN ULONG Pages, + IN ULONG Offset) +{ + PVIDEO_PORT_AGP_VIRTUAL_MAPPING VirtualMapping; + PVOID BaseAddress = NULL; + NTSTATUS Status; + + DPRINT("AgpFreeVirtual - VirtualContext: 0x%x Pages: %d, Offset: 0x%x\n", + VirtualContext, Pages, Offset); + + VirtualMapping = (PVIDEO_PORT_AGP_VIRTUAL_MAPPING)VirtualContext; + + if (VirtualMapping->ProcessHandle == NULL) + { + /* FIXME: not implemented */ + } + else /* ProcessHandle != NULL */ + { + /* Unmap the section view */ + ULONG Size = Pages * PAGE_SIZE; + ULONG OffsetInBytes = Offset * PAGE_SIZE; + BaseAddress = (PVOID)((ULONG_PTR)VirtualMapping->MappedAddress + + OffsetInBytes); + + Status = ZwUnmapViewOfSection(VirtualMapping->ProcessHandle, BaseAddress); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Warning: ZwUnmapViewOfSection() failed: Status = 0x%x\n", Status); + /* FIXME: What to do now?? */ + ASSERT(0); + return; + } + + /* And reserve the virtual memory area again */ + Status = ZwAllocateVirtualMemory(VirtualMapping->ProcessHandle, + &BaseAddress, 0, &Size, MEM_RESERVE, + PAGE_NOACCESS); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Warning: ZwAllocateVirtualMemory() failed: Status = 0x%x\n", Status); + /* FIXME: What to do now?? */ + ASSERT(0); + return; + } + ASSERT(Size == Pages * PAGE_SIZE); + ASSERT(BaseAddress == (PVOID)((ULONG_PTR)VirtualMapping->MappedAddress + + OffsetInBytes)); + } +} + +VOID STDCALL +IntAgpReleaseVirtual( + IN PVOID HwDeviceExtension, + IN PVOID VirtualContext) +{ + PVIDEO_PORT_AGP_VIRTUAL_MAPPING VirtualMapping; + NTSTATUS Status; + + DPRINT("AgpReleaseVirtual - VirtualContext: 0x%x\n", VirtualContext); + + VirtualMapping = (PVIDEO_PORT_AGP_VIRTUAL_MAPPING)VirtualContext; + + /* Release the virtual memory */ + if (VirtualMapping->ProcessHandle == NULL) + { + /* FIXME: not implemented */ + } + else /* ProcessHandle != NULL */ + { + /* Release the allocated virtual memory */ + ULONG Size = VirtualMapping->AgpMapping->NumberOfPages * PAGE_SIZE; + Status = ZwFreeVirtualMemory(VirtualMapping->ProcessHandle, + &VirtualMapping->MappedAddress, + &Size, MEM_RELEASE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Warning: ZwFreeVirtualMemory() failed: Status = 0x%x\n", Status); + } + } + + /* Free resources */ + ExFreePool(VirtualMapping); +} + +PVOID STDCALL +IntAgpReserveVirtual( + IN PVOID HwDeviceExtension, + IN HANDLE ProcessHandle, + IN PVOID PhysicalContext, + OUT PVOID *VirtualContext) +{ + PVIDEO_PORT_AGP_MAPPING AgpMapping; + PVIDEO_PORT_AGP_VIRTUAL_MAPPING VirtualMapping; + PVOID MappedAddress; + NTSTATUS Status; + + DPRINT("AgpReserveVirtual - ProcessHandle: 0x%x PhysicalContext: 0x%x\n", + ProcessHandle, PhysicalContext); + + AgpMapping = (PVIDEO_PORT_AGP_MAPPING)PhysicalContext; + + /* Allocate an AGP virtual mapping structure */ + VirtualMapping = ExAllocatePoolWithTag(PagedPool, + sizeof(VIDEO_PORT_AGP_VIRTUAL_MAPPING), + TAG_VIDEO_PORT); + if (VirtualMapping == NULL) + { + DPRINT1("Out of memory! Couldn't allocate AGP virtual mapping structure!\n"); + return NULL; + } + RtlZeroMemory(VirtualMapping, sizeof(VIDEO_PORT_AGP_VIRTUAL_MAPPING)); + + /* Reserve a virtual memory area for the physical pages. */ + if (ProcessHandle == NULL) + { + /* FIXME: What to do in this case? */ + ExFreePool(VirtualMapping); + return NULL; + } + else /* ProcessHandle != NULL */ + { + /* Reserve memory for usermode */ + ULONG Size = AgpMapping->NumberOfPages * PAGE_SIZE; + MappedAddress = NULL; + Status = ZwAllocateVirtualMemory(ProcessHandle, &MappedAddress, 0, &Size, + MEM_RESERVE, PAGE_NOACCESS); + if (!NT_SUCCESS(Status)) + { + ExFreePool(VirtualMapping); + DPRINT("ZwAllocateVirtualMemory() failed: Status = 0x%x\n", Status); + return NULL; + } + } + + /* Fill the AGP virtual mapping */ + VirtualMapping->AgpMapping = AgpMapping; + VirtualMapping->ProcessHandle = ProcessHandle; + VirtualMapping->MappedAddress = MappedAddress; + + *VirtualContext = (PVOID)VirtualMapping; + return MappedAddress; +} + + +BOOLEAN STDCALL +IntAgpSetRate( + IN PVOID HwDeviceExtension, + IN ULONG Rate) +{ + PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; + PAGP_BUS_INTERFACE_STANDARD AgpBusInterface; + + DPRINT("AgpSetRate - Rate: %d\n", Rate); + + DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); + AgpBusInterface = &DeviceExtension->AgpInterface; + + return NT_SUCCESS(AgpBusInterface->SetRate(AgpBusInterface->AgpContext, Rate)); +} + + +NTSTATUS STDCALL +IntAgpGetInterface( + IN PVOID HwDeviceExtension, + IN OUT PINTERFACE Interface) +{ + IO_STATUS_BLOCK IoStatusBlock; + IO_STACK_LOCATION IoStack; + NTSTATUS Status; + PVIDEO_PORT_AGP_INTERFACE_2 AgpInterface; + PVIDEO_PORT_DEVICE_EXTENSION DeviceExtension; + PAGP_BUS_INTERFACE_STANDARD AgpBusInterface; + + DeviceExtension = VIDEO_PORT_GET_DEVICE_EXTENSION(HwDeviceExtension); + AgpBusInterface = &DeviceExtension->AgpInterface; + AgpInterface = (PVIDEO_PORT_AGP_INTERFACE_2)Interface; + + ASSERT((Interface->Version == VIDEO_PORT_AGP_INTERFACE_VERSION_2 && + Interface->Size >= sizeof(VIDEO_PORT_AGP_INTERFACE_2)) || + (Interface->Version == VIDEO_PORT_AGP_INTERFACE_VERSION_1 && + Interface->Size >= sizeof(VIDEO_PORT_AGP_INTERFACE))); + + if (DeviceExtension->NextDeviceObject == NULL) + { + DPRINT("DeviceExtension->NextDeviceObject is NULL!\n"); + return STATUS_UNSUCCESSFUL; + } + + /* Query the interface from the AGP bus driver */ + if (DeviceExtension->AgpInterface.Size == 0) + { + AgpBusInterface->Size = sizeof(AGP_BUS_INTERFACE_STANDARD); + if (Interface->Version == VIDEO_PORT_AGP_INTERFACE_VERSION_1) + AgpBusInterface->Version = AGP_BUS_INTERFACE_V1; + else /* if (InterfaceVersion == VIDEO_PORT_AGP_INTERFACE_VERSION_2) */ + AgpBusInterface->Version = AGP_BUS_INTERFACE_V2; + IoStack.Parameters.QueryInterface.Size = AgpBusInterface->Size; + IoStack.Parameters.QueryInterface.Version = AgpBusInterface->Version; + IoStack.Parameters.QueryInterface.Interface = (PINTERFACE)AgpBusInterface; + IoStack.Parameters.QueryInterface.InterfaceType = + &GUID_AGP_TARGET_BUS_INTERFACE_STANDARD; + Status = IopInitiatePnpIrp(DeviceExtension->NextDeviceObject, + &IoStatusBlock, IRP_MN_QUERY_INTERFACE, &IoStack); + if (!NT_SUCCESS(Status)) + { + DPRINT("IopInitiatePnpIrp() failed! (Status 0x%x)\n", Status); + return Status; + } + DPRINT("Got AGP driver interface!\n"); + } + + /* FIXME: Not sure if we should wrap the reference/dereference functions */ + AgpInterface->Context = AgpBusInterface->AgpContext; + AgpInterface->InterfaceReference = AgpBusInterface->InterfaceReference; + AgpInterface->InterfaceDereference = AgpBusInterface->InterfaceDereference; + AgpInterface->AgpReservePhysical = IntAgpReservePhysical; + AgpInterface->AgpReleasePhysical = IntAgpReleasePhysical; + AgpInterface->AgpCommitPhysical = IntAgpCommitPhysical; + AgpInterface->AgpFreePhysical = IntAgpFreePhysical; + AgpInterface->AgpReserveVirtual = IntAgpReserveVirtual; + AgpInterface->AgpReleaseVirtual = IntAgpReleaseVirtual; + AgpInterface->AgpCommitVirtual = IntAgpCommitVirtual; + AgpInterface->AgpFreeVirtual = IntAgpFreeVirtual; + AgpInterface->AgpAllocationLimit = 0x1000000; /* FIXME: using 16 MB for now */ + + if (AgpInterface->Version >= VIDEO_PORT_AGP_INTERFACE_VERSION_2) + { + AgpInterface->AgpSetRate = IntAgpSetRate; + } + + return STATUS_SUCCESS; +} + diff --git a/reactos/drivers/video/videoprt/ddc.c b/reactos/drivers/video/videoprt/ddc.c index c200c3a827f..da4283ec650 100644 --- a/reactos/drivers/video/videoprt/ddc.c +++ b/reactos/drivers/video/videoprt/ddc.c @@ -1,227 +1,227 @@ -/* - * VideoPort driver - * - * Copyright (C) 2002, 2003, 2004 ReactOS Team - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; see the file COPYING.LIB. - * If not, write to the Free Software Foundation, - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * $Id$ - */ - -#include "videoprt.h" - -#define DDC_EEPROM_ADDRESS 0xA0 - -/* PRIVATE FUNCTIONS **********************************************************/ - -#define LOW 0 -#define HIGH 1 -#define WRITE 0 -#define READ 1 -#define READ_SDA() (i2c->ReadDataLine(HwDeviceExtension)) -#define READ_SCL() (i2c->ReadClockLine(HwDeviceExtension)) -#define WRITE_SDA(state) (i2c->WriteDataLine(HwDeviceExtension, state)) -#define WRITE_SCL(state) (i2c->WriteClockLine(HwDeviceExtension, state)) - -STATIC LARGE_INTEGER HalfPeriodDelay = { { 70LL } }; -#define DELAY_HALF() KeDelayExecutionThread(KernelMode, FALSE, &HalfPeriodDelay) - - -STATIC BOOL -I2CWrite(PVOID HwDeviceExtension, PI2C_CALLBACKS i2c, UCHAR Data) -{ - UCHAR Bit; - BOOL Ack; - - /* transmit data */ - for (Bit = (1 << 7); Bit != 0; Bit >>= 1) - { - WRITE_SCL(LOW); - WRITE_SDA((Data & Bit) ? HIGH : LOW); - DELAY_HALF(); - WRITE_SCL(HIGH); - DELAY_HALF(); - } - - /* get ack */ - WRITE_SCL(LOW); - WRITE_SDA(HIGH); - DELAY_HALF(); - WRITE_SCL(HIGH); - do - { - DELAY_HALF(); - } - while (READ_SCL() != HIGH); - Ack = (READ_SDA() == LOW); - DELAY_HALF(); - - DPRINT("I2CWrite: %s\n", Ack ? "Ack" : "Nak"); - return Ack; -} - - -STATIC UCHAR -I2CRead(PVOID HwDeviceExtension, PI2C_CALLBACKS i2c, BOOL Ack) -{ - INT Bit = 0x80; - UCHAR Data = 0; - - /* pull down SCL and release SDA */ - WRITE_SCL(LOW); - WRITE_SDA(HIGH); - - /* read byte */ - for (Bit = (1 << 7); Bit != 0; Bit >>= 1) - { - WRITE_SCL(LOW); - DELAY_HALF(); - WRITE_SCL(HIGH); - DELAY_HALF(); - if (READ_SDA() == HIGH) - Data |= Bit; - } - - /* send ack/nak */ - WRITE_SCL(LOW); - WRITE_SDA(Ack ? LOW : HIGH); - DELAY_HALF(); - WRITE_SCL(HIGH); - do - { - DELAY_HALF(); - } - while (READ_SCL() != HIGH); - - return Data; -} - - -STATIC VOID -I2CStop(PVOID HwDeviceExtension, PI2C_CALLBACKS i2c) -{ - WRITE_SCL(LOW); - WRITE_SDA(LOW); - DELAY_HALF(); - WRITE_SCL(HIGH); - DELAY_HALF(); - WRITE_SDA(HIGH); -} - - -STATIC BOOL -I2CStart(PVOID HwDeviceExtension, PI2C_CALLBACKS i2c, UCHAR Address) -{ - /* make sure the bus is free */ - if (READ_SDA() == LOW || READ_SCL() == LOW) - { - DPRINT1("I2CStart: Bus is not free!\n"); - return FALSE; - } - - /* send address */ - WRITE_SDA(LOW); - DELAY_HALF(); - if (!I2CWrite(HwDeviceExtension, i2c, Address)) - { - /* ??release the bus?? */ - I2CStop(HwDeviceExtension, i2c); - DPRINT1("I2CStart: Device not found (Address = 0x%x)\n", Address); - return FALSE; - } - - DPRINT("I2CStart: SUCCESS!\n"); - return TRUE; -} - - -STATIC BOOL -I2CRepStart(PVOID HwDeviceExtension, PI2C_CALLBACKS i2c, UCHAR Address) -{ - /* setup lines for repeated start condition */ - WRITE_SCL(LOW); - DELAY_HALF(); - WRITE_SDA(HIGH); - DELAY_HALF(); - WRITE_SCL(HIGH); - DELAY_HALF(); - - return I2CStart(HwDeviceExtension, i2c, Address); -} - -/* PUBLIC FUNCTIONS ***********************************************************/ - -/* - * @implemented - */ - -BOOLEAN STDCALL -VideoPortDDCMonitorHelper( - PVOID HwDeviceExtension, - PVOID I2CFunctions, - PUCHAR pEdidBuffer, - ULONG EdidBufferSize - ) -{ - PDDC_CONTROL ddc = (PDDC_CONTROL)I2CFunctions; - PI2C_CALLBACKS i2c = &ddc->I2CCallbacks; - INT Count, i; - PUCHAR pBuffer = (PUCHAR)pEdidBuffer; - BOOL Ack; - - DPRINT("VideoPortDDCMonitorHelper()\n"); - - ASSERT_IRQL(PASSIVE_LEVEL); - if (ddc->Size != sizeof (ddc)) - { - DPRINT("ddc->Size != %d (%d)\n", sizeof (ddc), ddc->Size); - return FALSE; - } - - /* select eeprom */ - if (!I2CStart(HwDeviceExtension, i2c, DDC_EEPROM_ADDRESS | WRITE)) - return FALSE; - /* set address */ - if (!I2CWrite(HwDeviceExtension, i2c, 0x00)) - return FALSE; - /* change into read mode */ - if (!I2CRepStart(HwDeviceExtension, i2c, DDC_EEPROM_ADDRESS | READ)) - return FALSE; - /* read eeprom */ - RtlZeroMemory(pEdidBuffer, EdidBufferSize); - Count = min(128, EdidBufferSize); - for (i = 0; i < Count; i++) - { - Ack = ((i + 1) < Count); - pBuffer[i] = I2CRead(HwDeviceExtension, i2c, Ack); - } - I2CStop(HwDeviceExtension, i2c); - - /* check EDID header */ - if (pBuffer[0] != 0x00 || pBuffer[1] != 0xff || - pBuffer[2] != 0xff || pBuffer[3] != 0xff || - pBuffer[4] != 0xff || pBuffer[5] != 0xff || - pBuffer[6] != 0xff || pBuffer[7] != 0x00) - { - DPRINT1("VideoPortDDCMonitorHelper(): Invalid EDID header!\n"); - return FALSE; - } - - DPRINT("VideoPortDDCMonitorHelper(): EDID version %d rev. %d\n", pBuffer[18], pBuffer[19]); - DPRINT("VideoPortDDCMonitorHelper() - SUCCESS!\n"); - return TRUE; -} - +/* + * VideoPort driver + * + * Copyright (C) 2002, 2003, 2004 ReactOS Team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; see the file COPYING.LIB. + * If not, write to the Free Software Foundation, + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Id$ + */ + +#include "videoprt.h" + +#define DDC_EEPROM_ADDRESS 0xA0 + +/* PRIVATE FUNCTIONS **********************************************************/ + +#define LOW 0 +#define HIGH 1 +#define WRITE 0 +#define READ 1 +#define READ_SDA() (i2c->ReadDataLine(HwDeviceExtension)) +#define READ_SCL() (i2c->ReadClockLine(HwDeviceExtension)) +#define WRITE_SDA(state) (i2c->WriteDataLine(HwDeviceExtension, state)) +#define WRITE_SCL(state) (i2c->WriteClockLine(HwDeviceExtension, state)) + +STATIC LARGE_INTEGER HalfPeriodDelay = { { 70LL } }; +#define DELAY_HALF() KeDelayExecutionThread(KernelMode, FALSE, &HalfPeriodDelay) + + +STATIC BOOL +I2CWrite(PVOID HwDeviceExtension, PI2C_CALLBACKS i2c, UCHAR Data) +{ + UCHAR Bit; + BOOL Ack; + + /* transmit data */ + for (Bit = (1 << 7); Bit != 0; Bit >>= 1) + { + WRITE_SCL(LOW); + WRITE_SDA((Data & Bit) ? HIGH : LOW); + DELAY_HALF(); + WRITE_SCL(HIGH); + DELAY_HALF(); + } + + /* get ack */ + WRITE_SCL(LOW); + WRITE_SDA(HIGH); + DELAY_HALF(); + WRITE_SCL(HIGH); + do + { + DELAY_HALF(); + } + while (READ_SCL() != HIGH); + Ack = (READ_SDA() == LOW); + DELAY_HALF(); + + DPRINT("I2CWrite: %s\n", Ack ? "Ack" : "Nak"); + return Ack; +} + + +STATIC UCHAR +I2CRead(PVOID HwDeviceExtension, PI2C_CALLBACKS i2c, BOOL Ack) +{ + INT Bit = 0x80; + UCHAR Data = 0; + + /* pull down SCL and release SDA */ + WRITE_SCL(LOW); + WRITE_SDA(HIGH); + + /* read byte */ + for (Bit = (1 << 7); Bit != 0; Bit >>= 1) + { + WRITE_SCL(LOW); + DELAY_HALF(); + WRITE_SCL(HIGH); + DELAY_HALF(); + if (READ_SDA() == HIGH) + Data |= Bit; + } + + /* send ack/nak */ + WRITE_SCL(LOW); + WRITE_SDA(Ack ? LOW : HIGH); + DELAY_HALF(); + WRITE_SCL(HIGH); + do + { + DELAY_HALF(); + } + while (READ_SCL() != HIGH); + + return Data; +} + + +STATIC VOID +I2CStop(PVOID HwDeviceExtension, PI2C_CALLBACKS i2c) +{ + WRITE_SCL(LOW); + WRITE_SDA(LOW); + DELAY_HALF(); + WRITE_SCL(HIGH); + DELAY_HALF(); + WRITE_SDA(HIGH); +} + + +STATIC BOOL +I2CStart(PVOID HwDeviceExtension, PI2C_CALLBACKS i2c, UCHAR Address) +{ + /* make sure the bus is free */ + if (READ_SDA() == LOW || READ_SCL() == LOW) + { + DPRINT1("I2CStart: Bus is not free!\n"); + return FALSE; + } + + /* send address */ + WRITE_SDA(LOW); + DELAY_HALF(); + if (!I2CWrite(HwDeviceExtension, i2c, Address)) + { + /* ??release the bus?? */ + I2CStop(HwDeviceExtension, i2c); + DPRINT1("I2CStart: Device not found (Address = 0x%x)\n", Address); + return FALSE; + } + + DPRINT("I2CStart: SUCCESS!\n"); + return TRUE; +} + + +STATIC BOOL +I2CRepStart(PVOID HwDeviceExtension, PI2C_CALLBACKS i2c, UCHAR Address) +{ + /* setup lines for repeated start condition */ + WRITE_SCL(LOW); + DELAY_HALF(); + WRITE_SDA(HIGH); + DELAY_HALF(); + WRITE_SCL(HIGH); + DELAY_HALF(); + + return I2CStart(HwDeviceExtension, i2c, Address); +} + +/* PUBLIC FUNCTIONS ***********************************************************/ + +/* + * @implemented + */ + +BOOLEAN STDCALL +VideoPortDDCMonitorHelper( + PVOID HwDeviceExtension, + PVOID I2CFunctions, + PUCHAR pEdidBuffer, + ULONG EdidBufferSize + ) +{ + PDDC_CONTROL ddc = (PDDC_CONTROL)I2CFunctions; + PI2C_CALLBACKS i2c = &ddc->I2CCallbacks; + INT Count, i; + PUCHAR pBuffer = (PUCHAR)pEdidBuffer; + BOOL Ack; + + DPRINT("VideoPortDDCMonitorHelper()\n"); + + ASSERT_IRQL(PASSIVE_LEVEL); + if (ddc->Size != sizeof (ddc)) + { + DPRINT("ddc->Size != %d (%d)\n", sizeof (ddc), ddc->Size); + return FALSE; + } + + /* select eeprom */ + if (!I2CStart(HwDeviceExtension, i2c, DDC_EEPROM_ADDRESS | WRITE)) + return FALSE; + /* set address */ + if (!I2CWrite(HwDeviceExtension, i2c, 0x00)) + return FALSE; + /* change into read mode */ + if (!I2CRepStart(HwDeviceExtension, i2c, DDC_EEPROM_ADDRESS | READ)) + return FALSE; + /* read eeprom */ + RtlZeroMemory(pEdidBuffer, EdidBufferSize); + Count = min(128, EdidBufferSize); + for (i = 0; i < Count; i++) + { + Ack = ((i + 1) < Count); + pBuffer[i] = I2CRead(HwDeviceExtension, i2c, Ack); + } + I2CStop(HwDeviceExtension, i2c); + + /* check EDID header */ + if (pBuffer[0] != 0x00 || pBuffer[1] != 0xff || + pBuffer[2] != 0xff || pBuffer[3] != 0xff || + pBuffer[4] != 0xff || pBuffer[5] != 0xff || + pBuffer[6] != 0xff || pBuffer[7] != 0x00) + { + DPRINT1("VideoPortDDCMonitorHelper(): Invalid EDID header!\n"); + return FALSE; + } + + DPRINT("VideoPortDDCMonitorHelper(): EDID version %d rev. %d\n", pBuffer[18], pBuffer[19]); + DPRINT("VideoPortDDCMonitorHelper() - SUCCESS!\n"); + return TRUE; +} + diff --git a/reactos/hal/halx86/include/ioapic.h b/reactos/hal/halx86/include/ioapic.h index 540f3411d14..f2ede453e64 100644 --- a/reactos/hal/halx86/include/ioapic.h +++ b/reactos/hal/halx86/include/ioapic.h @@ -1,101 +1,101 @@ -/* - * - */ - -#ifndef __INTERNAL_HAL_IOAPIC_H -#define __INTERNAL_HAL_IOAPIC_H - -/* I/O APIC Register Address Map */ -#define IOAPIC_IOREGSEL 0x0000 /* I/O Register Select (index) (R/W) */ -#define IOAPIC_IOWIN 0x0010 /* I/O window (data) (R/W) */ - -#define IOAPIC_ID 0x0000 /* IO APIC ID (R/W) */ -#define IOAPIC_VER 0x0001 /* IO APIC Version (R) */ -#define IOAPIC_ARB 0x0002 /* IO APIC Arbitration ID (R) */ -#define IOAPIC_REDTBL 0x0010 /* Redirection Table (0-23 64-bit registers) (R/W) */ - -#define IOAPIC_ID_MASK (0xF << 24) -#define GET_IOAPIC_ID(x) (((x) & IOAPIC_ID_MASK) >> 24) -#define SET_IOAPIC_ID(x) ((x) << 24) - -#define IOAPIC_VER_MASK (0xFF) -#define GET_IOAPIC_VERSION(x) (((x) & IOAPIC_VER_MASK)) -#define IOAPIC_MRE_MASK (0xFF << 16) /* Maximum Redirection Entry */ -#define GET_IOAPIC_MRE(x) (((x) & IOAPIC_MRE_MASK) >> 16) - -#define IOAPIC_ARB_MASK (0xF << 24) -#define GET_IOAPIC_ARB(x) (((x) & IOAPIC_ARB_MASK) >> 24) - -#define IOAPIC_TBL_DELMOD (0x7 << 10) /* Delivery Mode (see APIC_DM_*) */ -#define IOAPIC_TBL_DM (0x1 << 11) /* Destination Mode */ -#define IOAPIC_TBL_DS (0x1 << 12) /* Delivery Status */ -#define IOAPIC_TBL_INTPOL (0x1 << 13) /* Interrupt Input Pin Polarity */ -#define IOAPIC_TBL_RIRR (0x1 << 14) /* Remote IRR */ -#define IOAPIC_TBL_TM (0x1 << 15) /* Trigger Mode */ -#define IOAPIC_TBL_IM (0x1 << 16) /* Interrupt Mask */ -#define IOAPIC_TBL_DF0 (0xF << 56) /* Destination Field (physical mode) */ -#define IOAPIC_TBL_DF1 (0xFF<< 56) /* Destination Field (logical mode) */ -#define IOAPIC_TBL_VECTOR (0xFF << 0) /* Vector (10h - FEh) */ - -typedef struct _IOAPIC_ROUTE_ENTRY { - ULONG vector : 8, - delivery_mode : 3, /* 000: FIXED - * 001: lowest priority - * 111: ExtINT - */ - dest_mode : 1, /* 0: physical, 1: logical */ - delivery_status : 1, - polarity : 1, - irr : 1, - trigger : 1, /* 0: edge, 1: level */ - mask : 1, /* 0: enabled, 1: disabled */ - __reserved_2 : 15; - - union { - struct { - ULONG __reserved_1 : 24, - physical_dest : 4, - __reserved_2 : 4; - } physical; - struct { - ULONG __reserved_1 : 24, - logical_dest : 8; - } logical; - } dest; -} __attribute__ ((packed)) IOAPIC_ROUTE_ENTRY, *PIOAPIC_ROUTE_ENTRY; - -typedef struct _IOAPIC_INFO -{ - ULONG ApicId; /* APIC ID */ - ULONG ApicVersion; /* APIC version */ - ULONG ApicAddress; /* APIC address */ - ULONG EntryCount; /* Number of redirection entries */ -} IOAPIC_INFO, *PIOAPIC_INFO; - -#define IOAPIC_DEFAULT_BASE 0xFEC00000 /* Default I/O APIC Base Register Address */ - -extern ULONG IRQCount; /* Number of IRQs */ -extern UCHAR BUSMap[MAX_BUS]; /* Map of all buses in the system */ -extern UCHAR PCIBUSMap[MAX_BUS]; /* Map of all PCI buses in the system */ -extern IOAPIC_INFO IOAPICMap[MAX_IOAPIC]; /* Map of all I/O APICs in the system */ -extern ULONG IOAPICCount; /* Number of I/O APICs in the system */ -extern ULONG APICMode; /* APIC mode at startup */ -extern MP_CONFIGURATION_INTSRC IRQMap[MAX_IRQ_SOURCE]; /* Map of all IRQs */ - -VOID IOAPICSetupIrqs(VOID); -VOID IOAPICEnable(VOID); -VOID IOAPICSetupIds(VOID); -VOID IOAPICMaskIrq(ULONG Irq); -VOID IOAPICUnmaskIrq(ULONG Irq); - -VOID HaliReconfigurePciInterrupts(VOID); - -/* For debugging */ -VOID IOAPICDump(VOID); - -#endif - - - -/* EOF */ - +/* + * + */ + +#ifndef __INTERNAL_HAL_IOAPIC_H +#define __INTERNAL_HAL_IOAPIC_H + +/* I/O APIC Register Address Map */ +#define IOAPIC_IOREGSEL 0x0000 /* I/O Register Select (index) (R/W) */ +#define IOAPIC_IOWIN 0x0010 /* I/O window (data) (R/W) */ + +#define IOAPIC_ID 0x0000 /* IO APIC ID (R/W) */ +#define IOAPIC_VER 0x0001 /* IO APIC Version (R) */ +#define IOAPIC_ARB 0x0002 /* IO APIC Arbitration ID (R) */ +#define IOAPIC_REDTBL 0x0010 /* Redirection Table (0-23 64-bit registers) (R/W) */ + +#define IOAPIC_ID_MASK (0xF << 24) +#define GET_IOAPIC_ID(x) (((x) & IOAPIC_ID_MASK) >> 24) +#define SET_IOAPIC_ID(x) ((x) << 24) + +#define IOAPIC_VER_MASK (0xFF) +#define GET_IOAPIC_VERSION(x) (((x) & IOAPIC_VER_MASK)) +#define IOAPIC_MRE_MASK (0xFF << 16) /* Maximum Redirection Entry */ +#define GET_IOAPIC_MRE(x) (((x) & IOAPIC_MRE_MASK) >> 16) + +#define IOAPIC_ARB_MASK (0xF << 24) +#define GET_IOAPIC_ARB(x) (((x) & IOAPIC_ARB_MASK) >> 24) + +#define IOAPIC_TBL_DELMOD (0x7 << 10) /* Delivery Mode (see APIC_DM_*) */ +#define IOAPIC_TBL_DM (0x1 << 11) /* Destination Mode */ +#define IOAPIC_TBL_DS (0x1 << 12) /* Delivery Status */ +#define IOAPIC_TBL_INTPOL (0x1 << 13) /* Interrupt Input Pin Polarity */ +#define IOAPIC_TBL_RIRR (0x1 << 14) /* Remote IRR */ +#define IOAPIC_TBL_TM (0x1 << 15) /* Trigger Mode */ +#define IOAPIC_TBL_IM (0x1 << 16) /* Interrupt Mask */ +#define IOAPIC_TBL_DF0 (0xF << 56) /* Destination Field (physical mode) */ +#define IOAPIC_TBL_DF1 (0xFF<< 56) /* Destination Field (logical mode) */ +#define IOAPIC_TBL_VECTOR (0xFF << 0) /* Vector (10h - FEh) */ + +typedef struct _IOAPIC_ROUTE_ENTRY { + ULONG vector : 8, + delivery_mode : 3, /* 000: FIXED + * 001: lowest priority + * 111: ExtINT + */ + dest_mode : 1, /* 0: physical, 1: logical */ + delivery_status : 1, + polarity : 1, + irr : 1, + trigger : 1, /* 0: edge, 1: level */ + mask : 1, /* 0: enabled, 1: disabled */ + __reserved_2 : 15; + + union { + struct { + ULONG __reserved_1 : 24, + physical_dest : 4, + __reserved_2 : 4; + } physical; + struct { + ULONG __reserved_1 : 24, + logical_dest : 8; + } logical; + } dest; +} __attribute__ ((packed)) IOAPIC_ROUTE_ENTRY, *PIOAPIC_ROUTE_ENTRY; + +typedef struct _IOAPIC_INFO +{ + ULONG ApicId; /* APIC ID */ + ULONG ApicVersion; /* APIC version */ + ULONG ApicAddress; /* APIC address */ + ULONG EntryCount; /* Number of redirection entries */ +} IOAPIC_INFO, *PIOAPIC_INFO; + +#define IOAPIC_DEFAULT_BASE 0xFEC00000 /* Default I/O APIC Base Register Address */ + +extern ULONG IRQCount; /* Number of IRQs */ +extern UCHAR BUSMap[MAX_BUS]; /* Map of all buses in the system */ +extern UCHAR PCIBUSMap[MAX_BUS]; /* Map of all PCI buses in the system */ +extern IOAPIC_INFO IOAPICMap[MAX_IOAPIC]; /* Map of all I/O APICs in the system */ +extern ULONG IOAPICCount; /* Number of I/O APICs in the system */ +extern ULONG APICMode; /* APIC mode at startup */ +extern MP_CONFIGURATION_INTSRC IRQMap[MAX_IRQ_SOURCE]; /* Map of all IRQs */ + +VOID IOAPICSetupIrqs(VOID); +VOID IOAPICEnable(VOID); +VOID IOAPICSetupIds(VOID); +VOID IOAPICMaskIrq(ULONG Irq); +VOID IOAPICUnmaskIrq(ULONG Irq); + +VOID HaliReconfigurePciInterrupts(VOID); + +/* For debugging */ +VOID IOAPICDump(VOID); + +#endif + + + +/* EOF */ + diff --git a/reactos/hal/halx86/mp/ioapic.c b/reactos/hal/halx86/mp/ioapic.c index ac331e167f3..34dbb6cdf51 100644 --- a/reactos/hal/halx86/mp/ioapic.c +++ b/reactos/hal/halx86/mp/ioapic.c @@ -1,700 +1,700 @@ -/* $Id$ - * - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: hal/halx86/generic/ioapic.c - * PURPOSE: - * PROGRAMMER: - */ - -/* INCLUDES *****************************************************************/ - -#include -#define NDEBUG -#include - -/* GLOBALS *****************************************************************/ - -MP_CONFIGURATION_INTSRC IRQMap[MAX_IRQ_SOURCE]; /* Map of all IRQs */ -ULONG IRQCount = 0; /* Number of IRQs */ -ULONG IrqApicMap[MAX_IRQ_SOURCE]; - -UCHAR BUSMap[MAX_BUS]; /* Map of all buses in the system */ -UCHAR PCIBUSMap[MAX_BUS]; /* Map of all PCI buses in the system */ - -IOAPIC_INFO IOAPICMap[MAX_IOAPIC]; /* Map of all I/O APICs in the system */ -ULONG IOAPICCount; /* Number of I/O APICs in the system */ - -ULONG IRQVectorMap[MAX_IRQ_SOURCE]; /* IRQ to vector map */ - -/* EISA interrupts are always polarity zero and can be edge or level - * trigger depending on the ELCR value. If an interrupt is listed as - * EISA conforming in the MP table, that means its trigger type must - * be read in from the ELCR */ - -#define default_EISA_trigger(idx) (EISA_ELCR(IRQMap[idx].SrcBusIrq)) -#define default_EISA_polarity(idx) (0) - -/* ISA interrupts are always polarity zero edge triggered, - * when listed as conforming in the MP table. */ - -#define default_ISA_trigger(idx) (0) -#define default_ISA_polarity(idx) (0) - -/* PCI interrupts are always polarity one level triggered, - * when listed as conforming in the MP table. */ - -#define default_PCI_trigger(idx) (1) -#define default_PCI_polarity(idx) (1) - -/* MCA interrupts are always polarity zero level triggered, - * when listed as conforming in the MP table. */ - -#define default_MCA_trigger(idx) (1) -#define default_MCA_polarity(idx) (0) - -/***************************************************************************/ - -extern VOID Disable8259AIrq(ULONG irq); -ULONG IOAPICRead(ULONG Apic, ULONG Offset); -VOID IOAPICWrite(ULONG Apic, ULONG Offset, ULONG Value); - -/* FUNCTIONS ***************************************************************/ - -/* - * EISA Edge/Level control register, ELCR - */ -static ULONG EISA_ELCR(ULONG irq) -{ - if (irq < 16) - { - PUCHAR port = (PUCHAR)(0x4d0 + (irq >> 3)); - return (READ_PORT_UCHAR(port) >> (irq & 7)) & 1; - } - DPRINT("Broken MPtable reports ISA irq %d\n", irq); - return 0; -} - -static ULONG -IRQPolarity(ULONG idx) -{ - ULONG bus = IRQMap[idx].SrcBusId; - ULONG polarity; - - /* - * Determine IRQ line polarity (high active or low active): - */ - switch (IRQMap[idx].IrqFlag & 3) - { - case 0: /* conforms, ie. bus-type dependent polarity */ - { - switch (BUSMap[bus]) - { - case MP_BUS_ISA: /* ISA pin */ - polarity = default_ISA_polarity(idx); - break; - - case MP_BUS_EISA: /* EISA pin */ - polarity = default_EISA_polarity(idx); - break; - - case MP_BUS_PCI: /* PCI pin */ - polarity = default_PCI_polarity(idx); - break; - - case MP_BUS_MCA: /* MCA pin */ - polarity = default_MCA_polarity(idx); - break; - - default: - DPRINT("Broken BIOS!!\n"); - polarity = 1; - } - } - break; - - case 1: /* high active */ - polarity = 0; - break; - - case 2: /* reserved */ - DPRINT("Broken BIOS!!\n"); - polarity = 1; - break; - - case 3: /* low active */ - polarity = 1; - break; - - default: /* invalid */ - DPRINT("Broken BIOS!!\n"); - polarity = 1; - } - return polarity; -} - -static ULONG -IRQTrigger(ULONG idx) -{ - ULONG bus = IRQMap[idx].SrcBusId; - ULONG trigger; - - /* - * Determine IRQ trigger mode (edge or level sensitive): - */ - switch ((IRQMap[idx].IrqFlag >> 2) & 3) - { - case 0: /* conforms, ie. bus-type dependent */ - { - switch (BUSMap[bus]) - { - case MP_BUS_ISA: /* ISA pin */ - trigger = default_ISA_trigger(idx); - break; - - case MP_BUS_EISA: /* EISA pin */ - trigger = default_EISA_trigger(idx); - break; - - case MP_BUS_PCI: /* PCI pin */ - trigger = default_PCI_trigger(idx); - break; - - case MP_BUS_MCA: /* MCA pin */ - trigger = default_MCA_trigger(idx); - break; - - default: - DPRINT("Broken BIOS!!\n"); - trigger = 1; - } - } - break; - - case 1: /* edge */ - trigger = 0; - break; - - case 2: /* reserved */ - DPRINT("Broken BIOS!!\n"); - trigger = 1; - break; - - case 3: /* level */ - trigger = 1; - break; - - default: /* invalid */ - DPRINT("Broken BIOS!!\n"); - trigger = 0; - } - return trigger; -} - -static ULONG -Pin2Irq(ULONG idx, - ULONG apic, - ULONG pin) -{ - ULONG irq, i; - ULONG bus = IRQMap[idx].SrcBusId; - - /* - * Debugging check, we are in big trouble if this message pops up! - */ - if (IRQMap[idx].DstApicInt != pin) - { - DPRINT("broken BIOS or MPTABLE parser, ayiee!!\n"); - } - - switch (BUSMap[bus]) - { - case MP_BUS_ISA: /* ISA pin */ - case MP_BUS_EISA: - case MP_BUS_MCA: - irq = IRQMap[idx].SrcBusIrq; - break; - - case MP_BUS_PCI: /* PCI pin */ - /* - * PCI IRQs are mapped in order - */ - i = irq = 0; - while (i < apic) - { - irq += IOAPICMap[i++].EntryCount; - } - irq += pin; - break; - - default: - DPRINT("Unknown bus type %d.\n",bus); - irq = 0; - } - return irq; -} - -static ULONG -AssignIrqVector(ULONG irq) -{ -#if 0 - static ULONG current_vector = FIRST_DEVICE_VECTOR, vector_offset = 0; -#endif - ULONG vector; - /* There may already have been assigned a vector for this IRQ */ - vector = IRQVectorMap[irq]; - if (vector > 0) - { - return vector; - } -#if 0 - if (current_vector > FIRST_SYSTEM_VECTOR) - { - vector_offset++; - current_vector = FIRST_DEVICE_VECTOR + vector_offset; - } - else if (current_vector == FIRST_SYSTEM_VECTOR) - { - DPRINT1("Ran out of interrupt sources!"); - KEBUGCHECK(0); - } - - vector = current_vector; - IRQVectorMap[irq] = vector; - current_vector += 8; - return vector; -#else - vector = IRQ2VECTOR(irq); - IRQVectorMap[irq] = vector; - return vector; -#endif -} - -/* - * Find the IRQ entry number of a certain pin. - */ -static ULONG -IOAPICGetIrqEntry(ULONG apic, - ULONG pin, - ULONG type) -{ - ULONG i; - - for (i = 0; i < IRQCount; i++) - { - if (IRQMap[i].IrqType == type && - (IRQMap[i].DstApicId == IOAPICMap[apic].ApicId || IRQMap[i].DstApicId == MP_APIC_ALL) && - IRQMap[i].DstApicInt == pin) - { - return i; - } - } - return -1; -} - - -VOID -IOAPICSetupIrqs(VOID) -{ - IOAPIC_ROUTE_ENTRY entry; - ULONG apic, pin, idx, irq, first_notcon = 1, vector, trigger; - - DPRINT("Init IO_APIC IRQs\n"); - - /* Setup IRQ to vector translation map */ - memset(&IRQVectorMap, 0, sizeof(IRQVectorMap)); - - for (apic = 0; apic < IOAPICCount; apic++) - { - for (pin = 0; pin < IOAPICMap[apic].EntryCount; pin++) - { - /* - * add it to the IO-APIC irq-routing table - */ - memset(&entry,0,sizeof(entry)); - - entry.delivery_mode = (APIC_DM_LOWEST >> 8); - entry.dest_mode = 1; /* logical delivery */ - entry.mask = 1; /* disable IRQ */ - entry.dest.logical.logical_dest = 0; - - idx = IOAPICGetIrqEntry(apic,pin,INT_VECTORED); - if (idx == (ULONG)-1) - { - if (first_notcon) - { - DPRINT(" IO-APIC (apicid-pin) %d-%d\n", IOAPICMap[apic].ApicId, pin); - first_notcon = 0; - } - else - { - DPRINT(", %d-%d\n", IOAPICMap[apic].ApicId, pin); - } - continue; - } - - trigger = IRQTrigger(idx); - entry.polarity = IRQPolarity(idx); - - if (trigger) - { - entry.trigger = 1; - } - - irq = Pin2Irq(idx, apic, pin); - - vector = AssignIrqVector(irq); - entry.vector = vector; - - DPRINT("vector 0x%.08x assigned to irq 0x%.02x\n", vector, irq); - - if (irq == 0) - { - /* Mask timer IRQ */ - entry.mask = 1; - } - - if ((apic == 0) && (irq < 16)) - { - Disable8259AIrq(irq); - } - IOAPICWrite(apic, IOAPIC_REDTBL+2*pin+1, *(((PULONG)&entry)+1)); - IOAPICWrite(apic, IOAPIC_REDTBL+2*pin, *(((PULONG)&entry)+0)); - - IrqApicMap[irq] = apic; - - DPRINT("Vector %x, Pin %x, Irq %x\n", vector, pin, irq); - } - } -} - -static VOID -IOAPICClearPin(ULONG Apic, ULONG Pin) -{ - IOAPIC_ROUTE_ENTRY Entry; - - DPRINT("IOAPICClearPin(Apic %d, Pin %d\n", Apic, Pin); - /* - * Disable it in the IO-APIC irq-routing table - */ - memset(&Entry, 0, sizeof(Entry)); - Entry.mask = 1; - - IOAPICWrite(Apic, IOAPIC_REDTBL + 2 * Pin, *(((PULONG)&Entry) + 0)); - IOAPICWrite(Apic, IOAPIC_REDTBL + 1 + 2 * Pin, *(((PULONG)&Entry) + 1)); -} - -static VOID -IOAPICClear(ULONG Apic) -{ - ULONG Pin; - - for (Pin = 0; Pin < /*IOAPICMap[Apic].EntryCount*/24; Pin++) - { - IOAPICClearPin(Apic, Pin); - } -} - -static VOID -IOAPICClearAll(VOID) -{ - ULONG Apic; - - for (Apic = 0; Apic < IOAPICCount; Apic++) - { - IOAPICClear(Apic); - } -} - -VOID -IOAPICEnable(VOID) -{ - ULONG i, tmp; - - /* Setup IRQ to vector translation map */ - memset(&IRQVectorMap, 0, sizeof(IRQVectorMap)); - - /* - * The number of IO-APIC IRQ registers (== #pins): - */ - for (i = 0; i < IOAPICCount; i++) - { - tmp = IOAPICRead(i, IOAPIC_VER); - IOAPICMap[i].EntryCount = GET_IOAPIC_MRE(tmp) + 1; - } - - /* - * Do not trust the IO-APIC being empty at bootup - */ - IOAPICClearAll(); -} - -VOID -IOAPICSetupIds(VOID) -{ - ULONG tmp, apic, i; - UCHAR old_id; - - /* - * Set the IOAPIC ID to the value stored in the MPC table. - */ - for (apic = 0; apic < IOAPICCount; apic++) - { - - /* Read the register 0 value */ - tmp = IOAPICRead(apic, IOAPIC_ID); - - old_id = IOAPICMap[apic].ApicId; - - if (IOAPICMap[apic].ApicId >= 0xf) - { - DPRINT1("BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n", - apic, IOAPICMap[apic].ApicId); - DPRINT1("... fixing up to %d. (tell your hw vendor)\n", - GET_IOAPIC_ID(tmp)); - IOAPICMap[apic].ApicId = GET_IOAPIC_ID(tmp); - } - - /* - * We need to adjust the IRQ routing table - * if the ID changed. - */ - if (old_id != IOAPICMap[apic].ApicId) - { - for (i = 0; i < IRQCount; i++) - { - if (IRQMap[i].DstApicId == old_id) - { - IRQMap[i].DstApicId = IOAPICMap[apic].ApicId; - } - } - } - - /* - * Read the right value from the MPC table and - * write it into the ID register. - */ - DPRINT("Changing IO-APIC physical APIC ID to %d\n", - IOAPICMap[apic].ApicId); - - tmp &= ~IOAPIC_ID_MASK; - tmp |= SET_IOAPIC_ID(IOAPICMap[apic].ApicId); - - IOAPICWrite(apic, IOAPIC_ID, tmp); - - /* - * Sanity check - */ - tmp = IOAPICRead(apic, 0); - if (GET_IOAPIC_ID(tmp) != IOAPICMap[apic].ApicId) - { - DPRINT1("Could not set I/O APIC ID!\n"); - KEBUGCHECK(0); - } - } -} - -/* This is performance critical and should probably be done in assembler */ -VOID IOAPICMaskIrq(ULONG Irq) -{ - IOAPIC_ROUTE_ENTRY Entry; - ULONG Apic = IrqApicMap[Irq]; - - *(((PULONG)&Entry)+0) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq); - *(((PULONG)&Entry)+1) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq+1); - Entry.dest.logical.logical_dest &= ~(1 << KeGetCurrentProcessorNumber()); - if (Entry.dest.logical.logical_dest == 0) - { - Entry.mask = 1; - } - IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq+1, *(((PULONG)&Entry)+1)); - IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq, *(((PULONG)&Entry)+0)); -} - -/* This is performance critical and should probably be done in assembler */ -VOID IOAPICUnmaskIrq(ULONG Irq) -{ - IOAPIC_ROUTE_ENTRY Entry; - ULONG Apic = IrqApicMap[Irq]; - - *(((PULONG)&Entry)+0) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq); - *(((PULONG)&Entry)+1) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq+1); - Entry.dest.logical.logical_dest |= 1 << KeGetCurrentProcessorNumber(); - Entry.mask = 0; - IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq+1, *(((PULONG)&Entry)+1)); - IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq, *(((PULONG)&Entry)+0)); -} - -VOID IOAPICDump(VOID) -{ - ULONG apic, i; - ULONG reg0, reg1, reg2=0; - - DbgPrint("Number of MP IRQ sources: %d.\n", IRQCount); - for (i = 0; i < IOAPICCount; i++) - { - DbgPrint("Number of IO-APIC #%d registers: %d.\n", - IOAPICMap[i].ApicId, - IOAPICMap[i].EntryCount); - } - - /* - * We are a bit conservative about what we expect. We have to - * know about every hardware change ASAP. - */ - DbgPrint("Testing the IO APIC.......................\n"); - - for (apic = 0; apic < IOAPICCount; apic++) - { - reg0 = IOAPICRead(apic, IOAPIC_ID); - reg1 = IOAPICRead(apic, IOAPIC_VER); - if (GET_IOAPIC_VERSION(reg1) >= 0x10) - { - reg2 = IOAPICRead(apic, IOAPIC_ARB); - } - - DbgPrint("\n"); - DbgPrint("IO APIC #%d......\n", IOAPICMap[apic].ApicId); - DbgPrint(".... register #00: %08X\n", reg0); - DbgPrint("....... : physical APIC id: %02X\n", GET_IOAPIC_ID(reg0)); - if (reg0 & 0xF0FFFFFF) - { - DbgPrint(" WARNING: Unexpected IO-APIC\n"); - } - - DbgPrint(".... register #01: %08X\n", reg1); - i = GET_IOAPIC_MRE(reg1); - - DbgPrint("....... : max redirection entries: %04X\n", i); - if ((i != 0x0f) && /* older (Neptune) boards */ - (i != 0x17) && /* typical ISA+PCI boards */ - (i != 0x1b) && /* Compaq Proliant boards */ - (i != 0x1f) && /* dual Xeon boards */ - (i != 0x22) && /* bigger Xeon boards */ - (i != 0x2E) && - (i != 0x3F)) - { - DbgPrint(" WARNING: Unexpected IO-APIC\n"); - } - - i = GET_IOAPIC_VERSION(reg1); - DbgPrint("....... : IO APIC version: %04X\n", i); - if ((i != 0x01) && /* 82489DX IO-APICs */ - (i != 0x10) && /* oldest IO-APICs */ - (i != 0x11) && /* Pentium/Pro IO-APICs */ - (i != 0x13)) /* Xeon IO-APICs */ - { - DbgPrint(" WARNING: Unexpected IO-APIC\n"); - } - - if (reg1 & 0xFF00FF00) - { - DbgPrint(" WARNING: Unexpected IO-APIC\n"); - } - - if (GET_IOAPIC_VERSION(reg1) >= 0x10) - { - DbgPrint(".... register #02: %08X\n", reg2); - DbgPrint("....... : arbitration: %02X\n", - GET_IOAPIC_ARB(reg2)); - if (reg2 & 0xF0FFFFFF) - { - DbgPrint(" WARNING: Unexpected IO-APIC\n"); - } - } - - DbgPrint(".... IRQ redirection table:\n"); - DbgPrint(" NR Log Phy Mask Trig IRR Pol" - " Stat Dest Deli Vect: \n"); - - for (i = 0; i <= GET_IOAPIC_MRE(reg1); i++) - { - IOAPIC_ROUTE_ENTRY entry; - - *(((PULONG)&entry)+0) = IOAPICRead(apic, 0x10+i*2); - *(((PULONG)&entry)+1) = IOAPICRead(apic, 0x11+i*2); - - DbgPrint(" %02x %03X %02X ", - i, - entry.dest.logical.logical_dest, - entry.dest.physical.physical_dest); - - DbgPrint("%C %C %1d %C %C %C %03X %02X\n", - (entry.mask == 0) ? 'U' : 'M', // Unmasked/masked - (entry.trigger == 0) ? 'E' : 'L', // Edge/level sensitive - entry.irr, - (entry.polarity == 0) ? 'H' : 'L', // Active high/active low - (entry.delivery_status == 0) ? 'I' : 'S', // Idle / send pending - (entry.dest_mode == 0) ? 'P' : 'L', // Physical logical - entry.delivery_mode, - entry.vector); - } - } - - DbgPrint(".................................... done.\n"); -} - -VOID -HaliReconfigurePciInterrupts(VOID) -{ - ULONG i; - - for (i = 0; i < IRQCount; i++) - { - if (BUSMap[IRQMap[i].SrcBusId] == MP_BUS_PCI) - { - DPRINT("%02x: IrqType %02x, IrqFlag %02x, SrcBusId %02x, SrcBusIrq %02x" - ", DstApicId %02x, DstApicInt %02x\n", - i, IRQMap[i].IrqType, IRQMap[i].IrqFlag, IRQMap[i].SrcBusId, - IRQMap[i].SrcBusIrq, IRQMap[i].DstApicId, IRQMap[i].DstApicInt); - - if(1 != HalSetBusDataByOffset(PCIConfiguration, - IRQMap[i].SrcBusId, - (IRQMap[i].SrcBusIrq >> 2) & 0x1f, - &IRQMap[i].DstApicInt, - 0x3c /*PCI_INTERRUPT_LINE*/, - 1)) - { - CHECKPOINT; - } - } - } -} - -VOID Disable8259AIrq(ULONG irq) -{ - ULONG tmp; - - if (irq >= 8) - { - tmp = READ_PORT_UCHAR((PUCHAR)0xA1); - tmp |= (1 << (irq - 8)); - WRITE_PORT_UCHAR((PUCHAR)0xA1, tmp); - } - else - { - tmp = READ_PORT_UCHAR((PUCHAR)0x21); - tmp |= (1 << irq); - WRITE_PORT_UCHAR((PUCHAR)0x21, tmp); - } -} - -ULONG IOAPICRead(ULONG Apic, ULONG Offset) -{ - PULONG Base; - - Base = (PULONG)IOAPICMap[Apic].ApicAddress; - *Base = Offset; - return *((PULONG)((ULONG)Base + IOAPIC_IOWIN)); -} - -VOID IOAPICWrite(ULONG Apic, ULONG Offset, ULONG Value) -{ - PULONG Base; - - Base = (PULONG)IOAPICMap[Apic].ApicAddress; - *Base = Offset; - *((PULONG)((ULONG)Base + IOAPIC_IOWIN)) = Value; -} - -/* EOF */ +/* $Id$ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: hal/halx86/generic/ioapic.c + * PURPOSE: + * PROGRAMMER: + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + +/* GLOBALS *****************************************************************/ + +MP_CONFIGURATION_INTSRC IRQMap[MAX_IRQ_SOURCE]; /* Map of all IRQs */ +ULONG IRQCount = 0; /* Number of IRQs */ +ULONG IrqApicMap[MAX_IRQ_SOURCE]; + +UCHAR BUSMap[MAX_BUS]; /* Map of all buses in the system */ +UCHAR PCIBUSMap[MAX_BUS]; /* Map of all PCI buses in the system */ + +IOAPIC_INFO IOAPICMap[MAX_IOAPIC]; /* Map of all I/O APICs in the system */ +ULONG IOAPICCount; /* Number of I/O APICs in the system */ + +ULONG IRQVectorMap[MAX_IRQ_SOURCE]; /* IRQ to vector map */ + +/* EISA interrupts are always polarity zero and can be edge or level + * trigger depending on the ELCR value. If an interrupt is listed as + * EISA conforming in the MP table, that means its trigger type must + * be read in from the ELCR */ + +#define default_EISA_trigger(idx) (EISA_ELCR(IRQMap[idx].SrcBusIrq)) +#define default_EISA_polarity(idx) (0) + +/* ISA interrupts are always polarity zero edge triggered, + * when listed as conforming in the MP table. */ + +#define default_ISA_trigger(idx) (0) +#define default_ISA_polarity(idx) (0) + +/* PCI interrupts are always polarity one level triggered, + * when listed as conforming in the MP table. */ + +#define default_PCI_trigger(idx) (1) +#define default_PCI_polarity(idx) (1) + +/* MCA interrupts are always polarity zero level triggered, + * when listed as conforming in the MP table. */ + +#define default_MCA_trigger(idx) (1) +#define default_MCA_polarity(idx) (0) + +/***************************************************************************/ + +extern VOID Disable8259AIrq(ULONG irq); +ULONG IOAPICRead(ULONG Apic, ULONG Offset); +VOID IOAPICWrite(ULONG Apic, ULONG Offset, ULONG Value); + +/* FUNCTIONS ***************************************************************/ + +/* + * EISA Edge/Level control register, ELCR + */ +static ULONG EISA_ELCR(ULONG irq) +{ + if (irq < 16) + { + PUCHAR port = (PUCHAR)(0x4d0 + (irq >> 3)); + return (READ_PORT_UCHAR(port) >> (irq & 7)) & 1; + } + DPRINT("Broken MPtable reports ISA irq %d\n", irq); + return 0; +} + +static ULONG +IRQPolarity(ULONG idx) +{ + ULONG bus = IRQMap[idx].SrcBusId; + ULONG polarity; + + /* + * Determine IRQ line polarity (high active or low active): + */ + switch (IRQMap[idx].IrqFlag & 3) + { + case 0: /* conforms, ie. bus-type dependent polarity */ + { + switch (BUSMap[bus]) + { + case MP_BUS_ISA: /* ISA pin */ + polarity = default_ISA_polarity(idx); + break; + + case MP_BUS_EISA: /* EISA pin */ + polarity = default_EISA_polarity(idx); + break; + + case MP_BUS_PCI: /* PCI pin */ + polarity = default_PCI_polarity(idx); + break; + + case MP_BUS_MCA: /* MCA pin */ + polarity = default_MCA_polarity(idx); + break; + + default: + DPRINT("Broken BIOS!!\n"); + polarity = 1; + } + } + break; + + case 1: /* high active */ + polarity = 0; + break; + + case 2: /* reserved */ + DPRINT("Broken BIOS!!\n"); + polarity = 1; + break; + + case 3: /* low active */ + polarity = 1; + break; + + default: /* invalid */ + DPRINT("Broken BIOS!!\n"); + polarity = 1; + } + return polarity; +} + +static ULONG +IRQTrigger(ULONG idx) +{ + ULONG bus = IRQMap[idx].SrcBusId; + ULONG trigger; + + /* + * Determine IRQ trigger mode (edge or level sensitive): + */ + switch ((IRQMap[idx].IrqFlag >> 2) & 3) + { + case 0: /* conforms, ie. bus-type dependent */ + { + switch (BUSMap[bus]) + { + case MP_BUS_ISA: /* ISA pin */ + trigger = default_ISA_trigger(idx); + break; + + case MP_BUS_EISA: /* EISA pin */ + trigger = default_EISA_trigger(idx); + break; + + case MP_BUS_PCI: /* PCI pin */ + trigger = default_PCI_trigger(idx); + break; + + case MP_BUS_MCA: /* MCA pin */ + trigger = default_MCA_trigger(idx); + break; + + default: + DPRINT("Broken BIOS!!\n"); + trigger = 1; + } + } + break; + + case 1: /* edge */ + trigger = 0; + break; + + case 2: /* reserved */ + DPRINT("Broken BIOS!!\n"); + trigger = 1; + break; + + case 3: /* level */ + trigger = 1; + break; + + default: /* invalid */ + DPRINT("Broken BIOS!!\n"); + trigger = 0; + } + return trigger; +} + +static ULONG +Pin2Irq(ULONG idx, + ULONG apic, + ULONG pin) +{ + ULONG irq, i; + ULONG bus = IRQMap[idx].SrcBusId; + + /* + * Debugging check, we are in big trouble if this message pops up! + */ + if (IRQMap[idx].DstApicInt != pin) + { + DPRINT("broken BIOS or MPTABLE parser, ayiee!!\n"); + } + + switch (BUSMap[bus]) + { + case MP_BUS_ISA: /* ISA pin */ + case MP_BUS_EISA: + case MP_BUS_MCA: + irq = IRQMap[idx].SrcBusIrq; + break; + + case MP_BUS_PCI: /* PCI pin */ + /* + * PCI IRQs are mapped in order + */ + i = irq = 0; + while (i < apic) + { + irq += IOAPICMap[i++].EntryCount; + } + irq += pin; + break; + + default: + DPRINT("Unknown bus type %d.\n",bus); + irq = 0; + } + return irq; +} + +static ULONG +AssignIrqVector(ULONG irq) +{ +#if 0 + static ULONG current_vector = FIRST_DEVICE_VECTOR, vector_offset = 0; +#endif + ULONG vector; + /* There may already have been assigned a vector for this IRQ */ + vector = IRQVectorMap[irq]; + if (vector > 0) + { + return vector; + } +#if 0 + if (current_vector > FIRST_SYSTEM_VECTOR) + { + vector_offset++; + current_vector = FIRST_DEVICE_VECTOR + vector_offset; + } + else if (current_vector == FIRST_SYSTEM_VECTOR) + { + DPRINT1("Ran out of interrupt sources!"); + KEBUGCHECK(0); + } + + vector = current_vector; + IRQVectorMap[irq] = vector; + current_vector += 8; + return vector; +#else + vector = IRQ2VECTOR(irq); + IRQVectorMap[irq] = vector; + return vector; +#endif +} + +/* + * Find the IRQ entry number of a certain pin. + */ +static ULONG +IOAPICGetIrqEntry(ULONG apic, + ULONG pin, + ULONG type) +{ + ULONG i; + + for (i = 0; i < IRQCount; i++) + { + if (IRQMap[i].IrqType == type && + (IRQMap[i].DstApicId == IOAPICMap[apic].ApicId || IRQMap[i].DstApicId == MP_APIC_ALL) && + IRQMap[i].DstApicInt == pin) + { + return i; + } + } + return -1; +} + + +VOID +IOAPICSetupIrqs(VOID) +{ + IOAPIC_ROUTE_ENTRY entry; + ULONG apic, pin, idx, irq, first_notcon = 1, vector, trigger; + + DPRINT("Init IO_APIC IRQs\n"); + + /* Setup IRQ to vector translation map */ + memset(&IRQVectorMap, 0, sizeof(IRQVectorMap)); + + for (apic = 0; apic < IOAPICCount; apic++) + { + for (pin = 0; pin < IOAPICMap[apic].EntryCount; pin++) + { + /* + * add it to the IO-APIC irq-routing table + */ + memset(&entry,0,sizeof(entry)); + + entry.delivery_mode = (APIC_DM_LOWEST >> 8); + entry.dest_mode = 1; /* logical delivery */ + entry.mask = 1; /* disable IRQ */ + entry.dest.logical.logical_dest = 0; + + idx = IOAPICGetIrqEntry(apic,pin,INT_VECTORED); + if (idx == (ULONG)-1) + { + if (first_notcon) + { + DPRINT(" IO-APIC (apicid-pin) %d-%d\n", IOAPICMap[apic].ApicId, pin); + first_notcon = 0; + } + else + { + DPRINT(", %d-%d\n", IOAPICMap[apic].ApicId, pin); + } + continue; + } + + trigger = IRQTrigger(idx); + entry.polarity = IRQPolarity(idx); + + if (trigger) + { + entry.trigger = 1; + } + + irq = Pin2Irq(idx, apic, pin); + + vector = AssignIrqVector(irq); + entry.vector = vector; + + DPRINT("vector 0x%.08x assigned to irq 0x%.02x\n", vector, irq); + + if (irq == 0) + { + /* Mask timer IRQ */ + entry.mask = 1; + } + + if ((apic == 0) && (irq < 16)) + { + Disable8259AIrq(irq); + } + IOAPICWrite(apic, IOAPIC_REDTBL+2*pin+1, *(((PULONG)&entry)+1)); + IOAPICWrite(apic, IOAPIC_REDTBL+2*pin, *(((PULONG)&entry)+0)); + + IrqApicMap[irq] = apic; + + DPRINT("Vector %x, Pin %x, Irq %x\n", vector, pin, irq); + } + } +} + +static VOID +IOAPICClearPin(ULONG Apic, ULONG Pin) +{ + IOAPIC_ROUTE_ENTRY Entry; + + DPRINT("IOAPICClearPin(Apic %d, Pin %d\n", Apic, Pin); + /* + * Disable it in the IO-APIC irq-routing table + */ + memset(&Entry, 0, sizeof(Entry)); + Entry.mask = 1; + + IOAPICWrite(Apic, IOAPIC_REDTBL + 2 * Pin, *(((PULONG)&Entry) + 0)); + IOAPICWrite(Apic, IOAPIC_REDTBL + 1 + 2 * Pin, *(((PULONG)&Entry) + 1)); +} + +static VOID +IOAPICClear(ULONG Apic) +{ + ULONG Pin; + + for (Pin = 0; Pin < /*IOAPICMap[Apic].EntryCount*/24; Pin++) + { + IOAPICClearPin(Apic, Pin); + } +} + +static VOID +IOAPICClearAll(VOID) +{ + ULONG Apic; + + for (Apic = 0; Apic < IOAPICCount; Apic++) + { + IOAPICClear(Apic); + } +} + +VOID +IOAPICEnable(VOID) +{ + ULONG i, tmp; + + /* Setup IRQ to vector translation map */ + memset(&IRQVectorMap, 0, sizeof(IRQVectorMap)); + + /* + * The number of IO-APIC IRQ registers (== #pins): + */ + for (i = 0; i < IOAPICCount; i++) + { + tmp = IOAPICRead(i, IOAPIC_VER); + IOAPICMap[i].EntryCount = GET_IOAPIC_MRE(tmp) + 1; + } + + /* + * Do not trust the IO-APIC being empty at bootup + */ + IOAPICClearAll(); +} + +VOID +IOAPICSetupIds(VOID) +{ + ULONG tmp, apic, i; + UCHAR old_id; + + /* + * Set the IOAPIC ID to the value stored in the MPC table. + */ + for (apic = 0; apic < IOAPICCount; apic++) + { + + /* Read the register 0 value */ + tmp = IOAPICRead(apic, IOAPIC_ID); + + old_id = IOAPICMap[apic].ApicId; + + if (IOAPICMap[apic].ApicId >= 0xf) + { + DPRINT1("BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n", + apic, IOAPICMap[apic].ApicId); + DPRINT1("... fixing up to %d. (tell your hw vendor)\n", + GET_IOAPIC_ID(tmp)); + IOAPICMap[apic].ApicId = GET_IOAPIC_ID(tmp); + } + + /* + * We need to adjust the IRQ routing table + * if the ID changed. + */ + if (old_id != IOAPICMap[apic].ApicId) + { + for (i = 0; i < IRQCount; i++) + { + if (IRQMap[i].DstApicId == old_id) + { + IRQMap[i].DstApicId = IOAPICMap[apic].ApicId; + } + } + } + + /* + * Read the right value from the MPC table and + * write it into the ID register. + */ + DPRINT("Changing IO-APIC physical APIC ID to %d\n", + IOAPICMap[apic].ApicId); + + tmp &= ~IOAPIC_ID_MASK; + tmp |= SET_IOAPIC_ID(IOAPICMap[apic].ApicId); + + IOAPICWrite(apic, IOAPIC_ID, tmp); + + /* + * Sanity check + */ + tmp = IOAPICRead(apic, 0); + if (GET_IOAPIC_ID(tmp) != IOAPICMap[apic].ApicId) + { + DPRINT1("Could not set I/O APIC ID!\n"); + KEBUGCHECK(0); + } + } +} + +/* This is performance critical and should probably be done in assembler */ +VOID IOAPICMaskIrq(ULONG Irq) +{ + IOAPIC_ROUTE_ENTRY Entry; + ULONG Apic = IrqApicMap[Irq]; + + *(((PULONG)&Entry)+0) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq); + *(((PULONG)&Entry)+1) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq+1); + Entry.dest.logical.logical_dest &= ~(1 << KeGetCurrentProcessorNumber()); + if (Entry.dest.logical.logical_dest == 0) + { + Entry.mask = 1; + } + IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq+1, *(((PULONG)&Entry)+1)); + IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq, *(((PULONG)&Entry)+0)); +} + +/* This is performance critical and should probably be done in assembler */ +VOID IOAPICUnmaskIrq(ULONG Irq) +{ + IOAPIC_ROUTE_ENTRY Entry; + ULONG Apic = IrqApicMap[Irq]; + + *(((PULONG)&Entry)+0) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq); + *(((PULONG)&Entry)+1) = IOAPICRead(Apic, IOAPIC_REDTBL+2*Irq+1); + Entry.dest.logical.logical_dest |= 1 << KeGetCurrentProcessorNumber(); + Entry.mask = 0; + IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq+1, *(((PULONG)&Entry)+1)); + IOAPICWrite(Apic, IOAPIC_REDTBL+2*Irq, *(((PULONG)&Entry)+0)); +} + +VOID IOAPICDump(VOID) +{ + ULONG apic, i; + ULONG reg0, reg1, reg2=0; + + DbgPrint("Number of MP IRQ sources: %d.\n", IRQCount); + for (i = 0; i < IOAPICCount; i++) + { + DbgPrint("Number of IO-APIC #%d registers: %d.\n", + IOAPICMap[i].ApicId, + IOAPICMap[i].EntryCount); + } + + /* + * We are a bit conservative about what we expect. We have to + * know about every hardware change ASAP. + */ + DbgPrint("Testing the IO APIC.......................\n"); + + for (apic = 0; apic < IOAPICCount; apic++) + { + reg0 = IOAPICRead(apic, IOAPIC_ID); + reg1 = IOAPICRead(apic, IOAPIC_VER); + if (GET_IOAPIC_VERSION(reg1) >= 0x10) + { + reg2 = IOAPICRead(apic, IOAPIC_ARB); + } + + DbgPrint("\n"); + DbgPrint("IO APIC #%d......\n", IOAPICMap[apic].ApicId); + DbgPrint(".... register #00: %08X\n", reg0); + DbgPrint("....... : physical APIC id: %02X\n", GET_IOAPIC_ID(reg0)); + if (reg0 & 0xF0FFFFFF) + { + DbgPrint(" WARNING: Unexpected IO-APIC\n"); + } + + DbgPrint(".... register #01: %08X\n", reg1); + i = GET_IOAPIC_MRE(reg1); + + DbgPrint("....... : max redirection entries: %04X\n", i); + if ((i != 0x0f) && /* older (Neptune) boards */ + (i != 0x17) && /* typical ISA+PCI boards */ + (i != 0x1b) && /* Compaq Proliant boards */ + (i != 0x1f) && /* dual Xeon boards */ + (i != 0x22) && /* bigger Xeon boards */ + (i != 0x2E) && + (i != 0x3F)) + { + DbgPrint(" WARNING: Unexpected IO-APIC\n"); + } + + i = GET_IOAPIC_VERSION(reg1); + DbgPrint("....... : IO APIC version: %04X\n", i); + if ((i != 0x01) && /* 82489DX IO-APICs */ + (i != 0x10) && /* oldest IO-APICs */ + (i != 0x11) && /* Pentium/Pro IO-APICs */ + (i != 0x13)) /* Xeon IO-APICs */ + { + DbgPrint(" WARNING: Unexpected IO-APIC\n"); + } + + if (reg1 & 0xFF00FF00) + { + DbgPrint(" WARNING: Unexpected IO-APIC\n"); + } + + if (GET_IOAPIC_VERSION(reg1) >= 0x10) + { + DbgPrint(".... register #02: %08X\n", reg2); + DbgPrint("....... : arbitration: %02X\n", + GET_IOAPIC_ARB(reg2)); + if (reg2 & 0xF0FFFFFF) + { + DbgPrint(" WARNING: Unexpected IO-APIC\n"); + } + } + + DbgPrint(".... IRQ redirection table:\n"); + DbgPrint(" NR Log Phy Mask Trig IRR Pol" + " Stat Dest Deli Vect: \n"); + + for (i = 0; i <= GET_IOAPIC_MRE(reg1); i++) + { + IOAPIC_ROUTE_ENTRY entry; + + *(((PULONG)&entry)+0) = IOAPICRead(apic, 0x10+i*2); + *(((PULONG)&entry)+1) = IOAPICRead(apic, 0x11+i*2); + + DbgPrint(" %02x %03X %02X ", + i, + entry.dest.logical.logical_dest, + entry.dest.physical.physical_dest); + + DbgPrint("%C %C %1d %C %C %C %03X %02X\n", + (entry.mask == 0) ? 'U' : 'M', // Unmasked/masked + (entry.trigger == 0) ? 'E' : 'L', // Edge/level sensitive + entry.irr, + (entry.polarity == 0) ? 'H' : 'L', // Active high/active low + (entry.delivery_status == 0) ? 'I' : 'S', // Idle / send pending + (entry.dest_mode == 0) ? 'P' : 'L', // Physical logical + entry.delivery_mode, + entry.vector); + } + } + + DbgPrint(".................................... done.\n"); +} + +VOID +HaliReconfigurePciInterrupts(VOID) +{ + ULONG i; + + for (i = 0; i < IRQCount; i++) + { + if (BUSMap[IRQMap[i].SrcBusId] == MP_BUS_PCI) + { + DPRINT("%02x: IrqType %02x, IrqFlag %02x, SrcBusId %02x, SrcBusIrq %02x" + ", DstApicId %02x, DstApicInt %02x\n", + i, IRQMap[i].IrqType, IRQMap[i].IrqFlag, IRQMap[i].SrcBusId, + IRQMap[i].SrcBusIrq, IRQMap[i].DstApicId, IRQMap[i].DstApicInt); + + if(1 != HalSetBusDataByOffset(PCIConfiguration, + IRQMap[i].SrcBusId, + (IRQMap[i].SrcBusIrq >> 2) & 0x1f, + &IRQMap[i].DstApicInt, + 0x3c /*PCI_INTERRUPT_LINE*/, + 1)) + { + CHECKPOINT; + } + } + } +} + +VOID Disable8259AIrq(ULONG irq) +{ + ULONG tmp; + + if (irq >= 8) + { + tmp = READ_PORT_UCHAR((PUCHAR)0xA1); + tmp |= (1 << (irq - 8)); + WRITE_PORT_UCHAR((PUCHAR)0xA1, tmp); + } + else + { + tmp = READ_PORT_UCHAR((PUCHAR)0x21); + tmp |= (1 << irq); + WRITE_PORT_UCHAR((PUCHAR)0x21, tmp); + } +} + +ULONG IOAPICRead(ULONG Apic, ULONG Offset) +{ + PULONG Base; + + Base = (PULONG)IOAPICMap[Apic].ApicAddress; + *Base = Offset; + return *((PULONG)((ULONG)Base + IOAPIC_IOWIN)); +} + +VOID IOAPICWrite(ULONG Apic, ULONG Offset, ULONG Value) +{ + PULONG Base; + + Base = (PULONG)IOAPICMap[Apic].ApicAddress; + *Base = Offset; + *((PULONG)((ULONG)Base + IOAPIC_IOWIN)) = Value; +} + +/* EOF */ diff --git a/reactos/hal/halx86/mp/mpconfig.c b/reactos/hal/halx86/mp/mpconfig.c index b10356e36a3..f14e50865aa 100644 --- a/reactos/hal/halx86/mp/mpconfig.c +++ b/reactos/hal/halx86/mp/mpconfig.c @@ -1,643 +1,643 @@ -/* $Id$ - * - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: hal/halx86/generic/mpconfig.c - * PURPOSE: - * PROGRAMMER: - */ - -/* INCLUDES *****************************************************************/ - -#include -#define NDEBUG -#include - -/* GLOBALS ******************************************************************/ - -MP_FLOATING_POINTER* Mpf = NULL; - -/* FUNCTIONS ****************************************************************/ - -static UCHAR -MPChecksum(PUCHAR Base, - ULONG Size) -/* - * Checksum an MP configuration block - */ -{ - UCHAR Sum = 0; - - while (Size--) - Sum += *Base++; - - return Sum; -} - -static VOID -HaliMPIntSrcInfo(PMP_CONFIGURATION_INTSRC m) -{ - DPRINT("Int: type %d, pol %d, trig %d, bus %d," - " IRQ %02x, APIC ID %x, APIC INT %02x\n", - m->IrqType, m->IrqFlag & 3, - (m->IrqFlag >> 2) & 3, m->SrcBusId, - m->SrcBusIrq, m->DstApicId, m->DstApicInt); - if (IRQCount > MAX_IRQ_SOURCE) - { - DPRINT1("Max # of irq sources exceeded!!\n"); - KEBUGCHECK(0); - } - - IRQMap[IRQCount] = *m; - IRQCount++; -} - -PCHAR -HaliMPFamily(ULONG Family, - ULONG Model) -{ - static CHAR str[64]; - static PCHAR CPUs[] = - { - "80486DX", "80486DX", - "80486SX", "80486DX/2 or 80487", - "80486SL", "Intel5X2(tm)", - "Unknown", "Unknown", - "80486DX/4" - }; - if (Family == 0x6) - return ("Pentium(tm) Pro"); - if (Family == 0x5) - return ("Pentium(tm)"); - if (Family == 0x0F && Model == 0x0F) - return("Special controller"); - if (Family == 0x0F && Model == 0x00) - return("Pentium 4(tm)"); - if (Family == 0x04 && Model < 9) - return CPUs[Model]; - sprintf(str, "Unknown CPU with family ID %ld and model ID %ld", Family, Model); - return str; -} - - -static VOID -HaliMPProcessorInfo(PMP_CONFIGURATION_PROCESSOR m) -{ - ULONG ver; - - if (!(m->CpuFlags & CPU_FLAG_ENABLED)) - return; - - DPRINT("Processor #%d %s APIC version %d\n", - m->ApicId, - HaliMPFamily((m->FeatureFlags & CPU_FAMILY_MASK) >> 8, - (m->FeatureFlags & CPU_MODEL_MASK) >> 4), - m->ApicVersion); - - if (m->FeatureFlags & (1 << 0)) - DPRINT(" Floating point unit present.\n"); - if (m->FeatureFlags & (1 << 7)) - DPRINT(" Machine Exception supported.\n"); - if (m->FeatureFlags & (1 << 8)) - DPRINT(" 64 bit compare & exchange supported.\n"); - if (m->FeatureFlags & (1 << 9)) - DPRINT(" Internal APIC present.\n"); - if (m->FeatureFlags & (1 << 11)) - DPRINT(" SEP present.\n"); - if (m->FeatureFlags & (1 << 12)) - DPRINT(" MTRR present.\n"); - if (m->FeatureFlags & (1 << 13)) - DPRINT(" PGE present.\n"); - if (m->FeatureFlags & (1 << 14)) - DPRINT(" MCA present.\n"); - if (m->FeatureFlags & (1 << 15)) - DPRINT(" CMOV present.\n"); - if (m->FeatureFlags & (1 << 16)) - DPRINT(" PAT present.\n"); - if (m->FeatureFlags & (1 << 17)) - DPRINT(" PSE present.\n"); - if (m->FeatureFlags & (1 << 18)) - DPRINT(" PSN present.\n"); - if (m->FeatureFlags & (1 << 19)) - DPRINT(" Cache Line Flush Instruction present.\n"); - /* 20 Reserved */ - if (m->FeatureFlags & (1 << 21)) - DPRINT(" Debug Trace and EMON Store present.\n"); - if (m->FeatureFlags & (1 << 22)) - DPRINT(" ACPI Thermal Throttle Registers present.\n"); - if (m->FeatureFlags & (1 << 23)) - DPRINT(" MMX present.\n"); - if (m->FeatureFlags & (1 << 24)) - DPRINT(" FXSR present.\n"); - if (m->FeatureFlags & (1 << 25)) - DPRINT(" XMM present.\n"); - if (m->FeatureFlags & (1 << 26)) - DPRINT(" Willamette New Instructions present.\n"); - if (m->FeatureFlags & (1 << 27)) - DPRINT(" Self Snoop present.\n"); - /* 28 Reserved */ - if (m->FeatureFlags & (1 << 29)) - DPRINT(" Thermal Monitor present.\n"); - /* 30, 31 Reserved */ - - CPUMap[CPUCount].APICId = m->ApicId; - - CPUMap[CPUCount].Flags = CPU_USABLE; - - if (m->CpuFlags & CPU_FLAG_BSP) - { - DPRINT(" Bootup CPU\n"); - CPUMap[CPUCount].Flags |= CPU_BSP; - BootCPU = m->ApicId; - } - - if (m->ApicId > MAX_CPU) - { - DPRINT("Processor #%d INVALID. (Max ID: %d).\n", m->ApicId, MAX_CPU); - return; - } - ver = m->ApicVersion; - - /* - * Validate version - */ - if (ver == 0x0) - { - DPRINT("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->ApicId); - ver = 0x10; - } -// ApicVersion[m->ApicId] = Ver; -// BiosCpuApicId[CPUCount] = m->ApicId; - CPUMap[CPUCount].APICVersion = ver; - - CPUCount++; -} - -static VOID -HaliMPBusInfo(PMP_CONFIGURATION_BUS m) -{ - static ULONG CurrentPCIBusId = 0; - - DPRINT("Bus #%d is %.*s\n", m->BusId, 6, m->BusType); - - if (strncmp(m->BusType, BUSTYPE_ISA, sizeof(BUSTYPE_ISA)-1) == 0) - { - BUSMap[m->BusId] = MP_BUS_ISA; - } - else if (strncmp(m->BusType, BUSTYPE_EISA, sizeof(BUSTYPE_EISA)-1) == 0) - { - BUSMap[m->BusId] = MP_BUS_EISA; - } - else if (strncmp(m->BusType, BUSTYPE_PCI, sizeof(BUSTYPE_PCI)-1) == 0) - { - BUSMap[m->BusId] = MP_BUS_PCI; - PCIBUSMap[m->BusId] = CurrentPCIBusId; - CurrentPCIBusId++; - } - else if (strncmp(m->BusType, BUSTYPE_MCA, sizeof(BUSTYPE_MCA)-1) == 0) - { - BUSMap[m->BusId] = MP_BUS_MCA; - } - else - { - DPRINT("Unknown bustype %.*s - ignoring\n", 6, m->BusType); - } -} - -static VOID -HaliMPIOApicInfo(PMP_CONFIGURATION_IOAPIC m) -{ - if (!(m->ApicFlags & CPU_FLAG_ENABLED)) - return; - - DPRINT("I/O APIC #%d Version %d at 0x%lX.\n", - m->ApicId, m->ApicVersion, m->ApicAddress); - if (IOAPICCount > MAX_IOAPIC) - { - DPRINT("Max # of I/O APICs (%d) exceeded (found %d).\n", - MAX_IOAPIC, IOAPICCount); - DPRINT1("Recompile with bigger MAX_IOAPIC!.\n"); - KEBUGCHECK(0); - } - - IOAPICMap[IOAPICCount].ApicId = m->ApicId; - IOAPICMap[IOAPICCount].ApicVersion = m->ApicVersion; - IOAPICMap[IOAPICCount].ApicAddress = m->ApicAddress; - IOAPICCount++; -} - - -static VOID -HaliMPIntLocalInfo(PMP_CONFIGURATION_INTLOCAL m) -{ - DPRINT("Lint: type %d, pol %d, trig %d, bus %d," - " IRQ %02x, APIC ID %x, APIC LINT %02x\n", - m->IrqType, m->SrcBusIrq & 3, - (m->SrcBusIrq >> 2) & 3, m->SrcBusId, - m->SrcBusIrq, m->DstApicId, m->DstApicLInt); - /* - * Well it seems all SMP boards in existence - * use ExtINT/LVT1 == LINT0 and - * NMI/LVT2 == LINT1 - the following check - * will show us if this assumptions is false. - * Until then we do not have to add baggage. - */ - if ((m->IrqType == INT_EXTINT) && (m->DstApicLInt != 0)) - { - DPRINT1("Invalid MP table!\n"); - KEBUGCHECK(0); - } - if ((m->IrqType == INT_NMI) && (m->DstApicLInt != 1)) - { - DPRINT1("Invalid MP table!\n"); - KEBUGCHECK(0); - } -} - - -static BOOLEAN -HaliReadMPConfigTable(PMP_CONFIGURATION_TABLE Table) -/* - PARAMETERS: - Table = Pointer to MP configuration table - */ -{ - PUCHAR Entry; - ULONG Count; - - if (Table->Signature != MPC_SIGNATURE) - { - PUCHAR pc = (PUCHAR)&Table->Signature; - - DPRINT1("Bad MP configuration block signature: %c%c%c%c\n", - pc[0], pc[1], pc[2], pc[3]); - KEBUGCHECKEX(0, pc[0], pc[1], pc[2], pc[3]); - return FALSE; - } - - if (MPChecksum((PUCHAR)Table, Table->Length)) - { - DPRINT1("Bad MP configuration block checksum\n"); - KEBUGCHECK(0); - return FALSE; - } - - if (Table->Specification != 0x01 && Table->Specification != 0x04) - { - DPRINT1("Bad MP configuration table version (%d)\n", - Table->Specification); - KEBUGCHECK(0); - return FALSE; - } - - if (Table->LocalAPICAddress != APIC_DEFAULT_BASE) - { - DPRINT1("APIC base address is at 0x%X. I cannot handle non-standard adresses\n", - Table->LocalAPICAddress); - KEBUGCHECK(0); - return FALSE; - } - - DPRINT("Oem: %.*s, ProductId: %.*s\n", 8, Table->Oem, 12, Table->ProductId); - DPRINT("APIC at: %08x\n", Table->LocalAPICAddress); - - - Entry = (PUCHAR)((ULONG_PTR)Table + sizeof(MP_CONFIGURATION_TABLE)); - Count = 0; - while (Count < (Table->Length - sizeof(MP_CONFIGURATION_TABLE))) - { - /* Switch on type */ - switch (*Entry) - { - case MPCTE_PROCESSOR: - { - HaliMPProcessorInfo((PMP_CONFIGURATION_PROCESSOR)Entry); - Entry += sizeof(MP_CONFIGURATION_PROCESSOR); - Count += sizeof(MP_CONFIGURATION_PROCESSOR); - break; - } - case MPCTE_BUS: - { - HaliMPBusInfo((PMP_CONFIGURATION_BUS)Entry); - Entry += sizeof(MP_CONFIGURATION_BUS); - Count += sizeof(MP_CONFIGURATION_BUS); - break; - } - case MPCTE_IOAPIC: - { - HaliMPIOApicInfo((PMP_CONFIGURATION_IOAPIC)Entry); - Entry += sizeof(MP_CONFIGURATION_IOAPIC); - Count += sizeof(MP_CONFIGURATION_IOAPIC); - break; - } - case MPCTE_INTSRC: - { - HaliMPIntSrcInfo((PMP_CONFIGURATION_INTSRC)Entry); - Entry += sizeof(MP_CONFIGURATION_INTSRC); - Count += sizeof(MP_CONFIGURATION_INTSRC); - break; - } - case MPCTE_LINTSRC: - { - HaliMPIntLocalInfo((PMP_CONFIGURATION_INTLOCAL)Entry); - Entry += sizeof(MP_CONFIGURATION_INTLOCAL); - Count += sizeof(MP_CONFIGURATION_INTLOCAL); - break; - } - default: - DPRINT1("Unknown entry in MPC table\n"); - KEBUGCHECK(0); - return FALSE; - } - } - return TRUE; -} - -static VOID -HaliConstructDefaultIOIrqMPTable(ULONG Type) -{ - MP_CONFIGURATION_INTSRC intsrc; - ULONG i; - - intsrc.Type = MPCTE_INTSRC; - intsrc.IrqFlag = 0; /* conforming */ - intsrc.SrcBusId = 0; - intsrc.DstApicId = IOAPICMap[0].ApicId; - - intsrc.IrqType = INT_VECTORED; - for (i = 0; i < 16; i++) { - switch (Type) { - case 2: - if (i == 0 || i == 13) - continue; /* IRQ0 & IRQ13 not connected */ - /* Fall through */ - default: - if (i == 2) - continue; /* IRQ2 is never connected */ - } - - intsrc.SrcBusIrq = i; - intsrc.DstApicInt = i ? i : 2; /* IRQ0 to INTIN2 */ - HaliMPIntSrcInfo(&intsrc); - } - - intsrc.IrqType = INT_EXTINT; - intsrc.SrcBusIrq = 0; - intsrc.DstApicInt = 0; /* 8259A to INTIN0 */ - HaliMPIntSrcInfo(&intsrc); -} - -static VOID -HaliConstructDefaultISAMPTable(ULONG Type) -{ - MP_CONFIGURATION_PROCESSOR processor; - MP_CONFIGURATION_BUS bus; - MP_CONFIGURATION_IOAPIC ioapic; - MP_CONFIGURATION_INTLOCAL lintsrc; - ULONG linttypes[2] = { INT_EXTINT, INT_NMI }; - ULONG i; - - /* - * 2 CPUs, numbered 0 & 1. - */ - processor.Type = MPCTE_PROCESSOR; - /* Either an integrated APIC or a discrete 82489DX. */ - processor.ApicVersion = Type > 4 ? 0x10 : 0x01; - processor.CpuFlags = CPU_FLAG_ENABLED | CPU_FLAG_BSP; - /* FIXME: Get this from the bootstrap processor */ - processor.CpuSignature = 0; - processor.FeatureFlags = 0; - processor.Reserved[0] = 0; - processor.Reserved[1] = 0; - for (i = 0; i < 2; i++) - { - processor.ApicId = i; - HaliMPProcessorInfo(&processor); - processor.CpuFlags &= ~CPU_FLAG_BSP; - } - - bus.Type = MPCTE_BUS; - bus.BusId = 0; - switch (Type) - { - default: - DPRINT("Unknown standard configuration %d\n", Type); - /* Fall through */ - case 1: - case 5: - memcpy(bus.BusType, "ISA ", 6); - break; - case 2: - case 6: - case 3: - memcpy(bus.BusType, "EISA ", 6); - break; - case 4: - case 7: - memcpy(bus.BusType, "MCA ", 6); - } - HaliMPBusInfo(&bus); - if (Type > 4) - { - bus.Type = MPCTE_BUS; - bus.BusId = 1; - memcpy(bus.BusType, "PCI ", 6); - HaliMPBusInfo(&bus); - } - - ioapic.Type = MPCTE_IOAPIC; - ioapic.ApicId = 2; - ioapic.ApicVersion = Type > 4 ? 0x10 : 0x01; - ioapic.ApicFlags = MP_IOAPIC_USABLE; - ioapic.ApicAddress = IOAPIC_DEFAULT_BASE; - HaliMPIOApicInfo(&ioapic); - - /* - * We set up most of the low 16 IO-APIC pins according to MPS rules. - */ - HaliConstructDefaultIOIrqMPTable(Type); - - lintsrc.Type = MPCTE_LINTSRC; - lintsrc.IrqType = 0; - lintsrc.IrqFlag = 0; /* conforming */ - lintsrc.SrcBusId = 0; - lintsrc.SrcBusIrq = 0; - lintsrc.DstApicId = MP_APIC_ALL; - for (i = 0; i < 2; i++) - { - lintsrc.IrqType = linttypes[i]; - lintsrc.DstApicLInt = i; - HaliMPIntLocalInfo(&lintsrc); - } -} - - -static BOOLEAN -HaliScanForMPConfigTable(ULONG Base, - ULONG Size) -{ -/* - PARAMETERS: - Base = Base address of region - Size = Length of region to check - RETURNS: - TRUE if a valid MP configuration table was found - */ - - PULONG bp = (PULONG)Base; - MP_FLOATING_POINTER* mpf; - UCHAR Checksum; - - while (Size > 0) - { - mpf = (MP_FLOATING_POINTER*)bp; - if (mpf->Signature == MPF_SIGNATURE) - { - Checksum = MPChecksum((PUCHAR)bp, 16); - DPRINT("Found MPF signature at %x, checksum %x\n", bp, Checksum); - if (Checksum == 0 && - mpf->Length == 1) - { - DPRINT("Intel MultiProcessor Specification v1.%d compliant system.\n", - mpf->Specification); - - if (mpf->Feature2 & FEATURE2_IMCRP) - { - DPRINT("Running in IMCR and PIC compatibility mode.\n"); - } - else - { - DPRINT("Running in Virtual Wire compatibility mode.\n"); - } - - - switch (mpf->Feature1) - { - case 0: - /* Non standard configuration */ - break; - case 1: - DPRINT("ISA\n"); - break; - case 2: - DPRINT("EISA with no IRQ8 chaining\n"); - break; - case 3: - DPRINT("EISA\n"); - break; - case 4: - DPRINT("MCA\n"); - break; - case 5: - DPRINT("ISA and PCI\n"); - break; - case 6: - DPRINT("EISA and PCI\n"); - break; - case 7: - DPRINT("MCA and PCI\n"); - break; - default: - DPRINT("Unknown standard configuration %d\n", mpf->Feature1); - return FALSE; - } - Mpf = mpf; - return TRUE; - } - } - bp += 4; - Size -= 16; - } - return FALSE; -} - -static BOOLEAN -HaliGetSmpConfig(VOID) -{ - if (Mpf == NULL) - { - return FALSE; - } - - if (Mpf->Feature2 & FEATURE2_IMCRP) - { - DPRINT("Running in IMCR and PIC compatibility mode.\n"); - APICMode = amPIC; - } - else - { - DPRINT("Running in Virtual Wire compatibility mode.\n"); - APICMode = amVWIRE; - } - - if (Mpf->Feature1 == 0 && Mpf->Address) - { - if(!HaliReadMPConfigTable((PMP_CONFIGURATION_TABLE)Mpf->Address)) - { - DPRINT("BIOS bug, MP table errors detected!...\n"); - DPRINT("... disabling SMP support. (tell your hw vendor)\n"); - return FALSE; - } - if (IRQCount == 0) - { - MP_CONFIGURATION_BUS bus; - - DPRINT("BIOS bug, no explicit IRQ entries, using default mptable. (tell your hw vendor)\n"); - - bus.BusId = 1; - memcpy(bus.BusType, "ISA ", 6); - HaliMPBusInfo(&bus); - HaliConstructDefaultIOIrqMPTable(bus.BusId); - } - - } - else if(Mpf->Feature1 != 0) - { - HaliConstructDefaultISAMPTable(Mpf->Feature1); - } - else - { - KEBUGCHECK(0); - } - return TRUE; -} - -BOOLEAN -HaliFindSmpConfig(VOID) -{ - /* - Scan the system memory for an MP configuration table - 1) Scan the first KB of system base memory - 2) Scan the last KB of system base memory - 3) Scan the BIOS ROM address space between 0F0000h and 0FFFFFh - 4) Scan the first KB from the Extended BIOS Data Area - */ - - if (!HaliScanForMPConfigTable(0x0, 0x400)) - { - if (!HaliScanForMPConfigTable(0x9FC00, 0x400)) - { - if (!HaliScanForMPConfigTable(0xF0000, 0x10000)) - { - if (!HaliScanForMPConfigTable(*((PUSHORT)0x040E) << 4, 0x400)) - { - DPRINT("No multiprocessor compliant system found.\n"); - return FALSE; - } - } - } - } - - if (HaliGetSmpConfig()) - { - return TRUE; - } - else - { - DPRINT("No MP config table found\n"); - return FALSE; - } - -} - -/* EOF */ +/* $Id$ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: hal/halx86/generic/mpconfig.c + * PURPOSE: + * PROGRAMMER: + */ + +/* INCLUDES *****************************************************************/ + +#include +#define NDEBUG +#include + +/* GLOBALS ******************************************************************/ + +MP_FLOATING_POINTER* Mpf = NULL; + +/* FUNCTIONS ****************************************************************/ + +static UCHAR +MPChecksum(PUCHAR Base, + ULONG Size) +/* + * Checksum an MP configuration block + */ +{ + UCHAR Sum = 0; + + while (Size--) + Sum += *Base++; + + return Sum; +} + +static VOID +HaliMPIntSrcInfo(PMP_CONFIGURATION_INTSRC m) +{ + DPRINT("Int: type %d, pol %d, trig %d, bus %d," + " IRQ %02x, APIC ID %x, APIC INT %02x\n", + m->IrqType, m->IrqFlag & 3, + (m->IrqFlag >> 2) & 3, m->SrcBusId, + m->SrcBusIrq, m->DstApicId, m->DstApicInt); + if (IRQCount > MAX_IRQ_SOURCE) + { + DPRINT1("Max # of irq sources exceeded!!\n"); + KEBUGCHECK(0); + } + + IRQMap[IRQCount] = *m; + IRQCount++; +} + +PCHAR +HaliMPFamily(ULONG Family, + ULONG Model) +{ + static CHAR str[64]; + static PCHAR CPUs[] = + { + "80486DX", "80486DX", + "80486SX", "80486DX/2 or 80487", + "80486SL", "Intel5X2(tm)", + "Unknown", "Unknown", + "80486DX/4" + }; + if (Family == 0x6) + return ("Pentium(tm) Pro"); + if (Family == 0x5) + return ("Pentium(tm)"); + if (Family == 0x0F && Model == 0x0F) + return("Special controller"); + if (Family == 0x0F && Model == 0x00) + return("Pentium 4(tm)"); + if (Family == 0x04 && Model < 9) + return CPUs[Model]; + sprintf(str, "Unknown CPU with family ID %ld and model ID %ld", Family, Model); + return str; +} + + +static VOID +HaliMPProcessorInfo(PMP_CONFIGURATION_PROCESSOR m) +{ + ULONG ver; + + if (!(m->CpuFlags & CPU_FLAG_ENABLED)) + return; + + DPRINT("Processor #%d %s APIC version %d\n", + m->ApicId, + HaliMPFamily((m->FeatureFlags & CPU_FAMILY_MASK) >> 8, + (m->FeatureFlags & CPU_MODEL_MASK) >> 4), + m->ApicVersion); + + if (m->FeatureFlags & (1 << 0)) + DPRINT(" Floating point unit present.\n"); + if (m->FeatureFlags & (1 << 7)) + DPRINT(" Machine Exception supported.\n"); + if (m->FeatureFlags & (1 << 8)) + DPRINT(" 64 bit compare & exchange supported.\n"); + if (m->FeatureFlags & (1 << 9)) + DPRINT(" Internal APIC present.\n"); + if (m->FeatureFlags & (1 << 11)) + DPRINT(" SEP present.\n"); + if (m->FeatureFlags & (1 << 12)) + DPRINT(" MTRR present.\n"); + if (m->FeatureFlags & (1 << 13)) + DPRINT(" PGE present.\n"); + if (m->FeatureFlags & (1 << 14)) + DPRINT(" MCA present.\n"); + if (m->FeatureFlags & (1 << 15)) + DPRINT(" CMOV present.\n"); + if (m->FeatureFlags & (1 << 16)) + DPRINT(" PAT present.\n"); + if (m->FeatureFlags & (1 << 17)) + DPRINT(" PSE present.\n"); + if (m->FeatureFlags & (1 << 18)) + DPRINT(" PSN present.\n"); + if (m->FeatureFlags & (1 << 19)) + DPRINT(" Cache Line Flush Instruction present.\n"); + /* 20 Reserved */ + if (m->FeatureFlags & (1 << 21)) + DPRINT(" Debug Trace and EMON Store present.\n"); + if (m->FeatureFlags & (1 << 22)) + DPRINT(" ACPI Thermal Throttle Registers present.\n"); + if (m->FeatureFlags & (1 << 23)) + DPRINT(" MMX present.\n"); + if (m->FeatureFlags & (1 << 24)) + DPRINT(" FXSR present.\n"); + if (m->FeatureFlags & (1 << 25)) + DPRINT(" XMM present.\n"); + if (m->FeatureFlags & (1 << 26)) + DPRINT(" Willamette New Instructions present.\n"); + if (m->FeatureFlags & (1 << 27)) + DPRINT(" Self Snoop present.\n"); + /* 28 Reserved */ + if (m->FeatureFlags & (1 << 29)) + DPRINT(" Thermal Monitor present.\n"); + /* 30, 31 Reserved */ + + CPUMap[CPUCount].APICId = m->ApicId; + + CPUMap[CPUCount].Flags = CPU_USABLE; + + if (m->CpuFlags & CPU_FLAG_BSP) + { + DPRINT(" Bootup CPU\n"); + CPUMap[CPUCount].Flags |= CPU_BSP; + BootCPU = m->ApicId; + } + + if (m->ApicId > MAX_CPU) + { + DPRINT("Processor #%d INVALID. (Max ID: %d).\n", m->ApicId, MAX_CPU); + return; + } + ver = m->ApicVersion; + + /* + * Validate version + */ + if (ver == 0x0) + { + DPRINT("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->ApicId); + ver = 0x10; + } +// ApicVersion[m->ApicId] = Ver; +// BiosCpuApicId[CPUCount] = m->ApicId; + CPUMap[CPUCount].APICVersion = ver; + + CPUCount++; +} + +static VOID +HaliMPBusInfo(PMP_CONFIGURATION_BUS m) +{ + static ULONG CurrentPCIBusId = 0; + + DPRINT("Bus #%d is %.*s\n", m->BusId, 6, m->BusType); + + if (strncmp(m->BusType, BUSTYPE_ISA, sizeof(BUSTYPE_ISA)-1) == 0) + { + BUSMap[m->BusId] = MP_BUS_ISA; + } + else if (strncmp(m->BusType, BUSTYPE_EISA, sizeof(BUSTYPE_EISA)-1) == 0) + { + BUSMap[m->BusId] = MP_BUS_EISA; + } + else if (strncmp(m->BusType, BUSTYPE_PCI, sizeof(BUSTYPE_PCI)-1) == 0) + { + BUSMap[m->BusId] = MP_BUS_PCI; + PCIBUSMap[m->BusId] = CurrentPCIBusId; + CurrentPCIBusId++; + } + else if (strncmp(m->BusType, BUSTYPE_MCA, sizeof(BUSTYPE_MCA)-1) == 0) + { + BUSMap[m->BusId] = MP_BUS_MCA; + } + else + { + DPRINT("Unknown bustype %.*s - ignoring\n", 6, m->BusType); + } +} + +static VOID +HaliMPIOApicInfo(PMP_CONFIGURATION_IOAPIC m) +{ + if (!(m->ApicFlags & CPU_FLAG_ENABLED)) + return; + + DPRINT("I/O APIC #%d Version %d at 0x%lX.\n", + m->ApicId, m->ApicVersion, m->ApicAddress); + if (IOAPICCount > MAX_IOAPIC) + { + DPRINT("Max # of I/O APICs (%d) exceeded (found %d).\n", + MAX_IOAPIC, IOAPICCount); + DPRINT1("Recompile with bigger MAX_IOAPIC!.\n"); + KEBUGCHECK(0); + } + + IOAPICMap[IOAPICCount].ApicId = m->ApicId; + IOAPICMap[IOAPICCount].ApicVersion = m->ApicVersion; + IOAPICMap[IOAPICCount].ApicAddress = m->ApicAddress; + IOAPICCount++; +} + + +static VOID +HaliMPIntLocalInfo(PMP_CONFIGURATION_INTLOCAL m) +{ + DPRINT("Lint: type %d, pol %d, trig %d, bus %d," + " IRQ %02x, APIC ID %x, APIC LINT %02x\n", + m->IrqType, m->SrcBusIrq & 3, + (m->SrcBusIrq >> 2) & 3, m->SrcBusId, + m->SrcBusIrq, m->DstApicId, m->DstApicLInt); + /* + * Well it seems all SMP boards in existence + * use ExtINT/LVT1 == LINT0 and + * NMI/LVT2 == LINT1 - the following check + * will show us if this assumptions is false. + * Until then we do not have to add baggage. + */ + if ((m->IrqType == INT_EXTINT) && (m->DstApicLInt != 0)) + { + DPRINT1("Invalid MP table!\n"); + KEBUGCHECK(0); + } + if ((m->IrqType == INT_NMI) && (m->DstApicLInt != 1)) + { + DPRINT1("Invalid MP table!\n"); + KEBUGCHECK(0); + } +} + + +static BOOLEAN +HaliReadMPConfigTable(PMP_CONFIGURATION_TABLE Table) +/* + PARAMETERS: + Table = Pointer to MP configuration table + */ +{ + PUCHAR Entry; + ULONG Count; + + if (Table->Signature != MPC_SIGNATURE) + { + PUCHAR pc = (PUCHAR)&Table->Signature; + + DPRINT1("Bad MP configuration block signature: %c%c%c%c\n", + pc[0], pc[1], pc[2], pc[3]); + KEBUGCHECKEX(0, pc[0], pc[1], pc[2], pc[3]); + return FALSE; + } + + if (MPChecksum((PUCHAR)Table, Table->Length)) + { + DPRINT1("Bad MP configuration block checksum\n"); + KEBUGCHECK(0); + return FALSE; + } + + if (Table->Specification != 0x01 && Table->Specification != 0x04) + { + DPRINT1("Bad MP configuration table version (%d)\n", + Table->Specification); + KEBUGCHECK(0); + return FALSE; + } + + if (Table->LocalAPICAddress != APIC_DEFAULT_BASE) + { + DPRINT1("APIC base address is at 0x%X. I cannot handle non-standard adresses\n", + Table->LocalAPICAddress); + KEBUGCHECK(0); + return FALSE; + } + + DPRINT("Oem: %.*s, ProductId: %.*s\n", 8, Table->Oem, 12, Table->ProductId); + DPRINT("APIC at: %08x\n", Table->LocalAPICAddress); + + + Entry = (PUCHAR)((ULONG_PTR)Table + sizeof(MP_CONFIGURATION_TABLE)); + Count = 0; + while (Count < (Table->Length - sizeof(MP_CONFIGURATION_TABLE))) + { + /* Switch on type */ + switch (*Entry) + { + case MPCTE_PROCESSOR: + { + HaliMPProcessorInfo((PMP_CONFIGURATION_PROCESSOR)Entry); + Entry += sizeof(MP_CONFIGURATION_PROCESSOR); + Count += sizeof(MP_CONFIGURATION_PROCESSOR); + break; + } + case MPCTE_BUS: + { + HaliMPBusInfo((PMP_CONFIGURATION_BUS)Entry); + Entry += sizeof(MP_CONFIGURATION_BUS); + Count += sizeof(MP_CONFIGURATION_BUS); + break; + } + case MPCTE_IOAPIC: + { + HaliMPIOApicInfo((PMP_CONFIGURATION_IOAPIC)Entry); + Entry += sizeof(MP_CONFIGURATION_IOAPIC); + Count += sizeof(MP_CONFIGURATION_IOAPIC); + break; + } + case MPCTE_INTSRC: + { + HaliMPIntSrcInfo((PMP_CONFIGURATION_INTSRC)Entry); + Entry += sizeof(MP_CONFIGURATION_INTSRC); + Count += sizeof(MP_CONFIGURATION_INTSRC); + break; + } + case MPCTE_LINTSRC: + { + HaliMPIntLocalInfo((PMP_CONFIGURATION_INTLOCAL)Entry); + Entry += sizeof(MP_CONFIGURATION_INTLOCAL); + Count += sizeof(MP_CONFIGURATION_INTLOCAL); + break; + } + default: + DPRINT1("Unknown entry in MPC table\n"); + KEBUGCHECK(0); + return FALSE; + } + } + return TRUE; +} + +static VOID +HaliConstructDefaultIOIrqMPTable(ULONG Type) +{ + MP_CONFIGURATION_INTSRC intsrc; + ULONG i; + + intsrc.Type = MPCTE_INTSRC; + intsrc.IrqFlag = 0; /* conforming */ + intsrc.SrcBusId = 0; + intsrc.DstApicId = IOAPICMap[0].ApicId; + + intsrc.IrqType = INT_VECTORED; + for (i = 0; i < 16; i++) { + switch (Type) { + case 2: + if (i == 0 || i == 13) + continue; /* IRQ0 & IRQ13 not connected */ + /* Fall through */ + default: + if (i == 2) + continue; /* IRQ2 is never connected */ + } + + intsrc.SrcBusIrq = i; + intsrc.DstApicInt = i ? i : 2; /* IRQ0 to INTIN2 */ + HaliMPIntSrcInfo(&intsrc); + } + + intsrc.IrqType = INT_EXTINT; + intsrc.SrcBusIrq = 0; + intsrc.DstApicInt = 0; /* 8259A to INTIN0 */ + HaliMPIntSrcInfo(&intsrc); +} + +static VOID +HaliConstructDefaultISAMPTable(ULONG Type) +{ + MP_CONFIGURATION_PROCESSOR processor; + MP_CONFIGURATION_BUS bus; + MP_CONFIGURATION_IOAPIC ioapic; + MP_CONFIGURATION_INTLOCAL lintsrc; + ULONG linttypes[2] = { INT_EXTINT, INT_NMI }; + ULONG i; + + /* + * 2 CPUs, numbered 0 & 1. + */ + processor.Type = MPCTE_PROCESSOR; + /* Either an integrated APIC or a discrete 82489DX. */ + processor.ApicVersion = Type > 4 ? 0x10 : 0x01; + processor.CpuFlags = CPU_FLAG_ENABLED | CPU_FLAG_BSP; + /* FIXME: Get this from the bootstrap processor */ + processor.CpuSignature = 0; + processor.FeatureFlags = 0; + processor.Reserved[0] = 0; + processor.Reserved[1] = 0; + for (i = 0; i < 2; i++) + { + processor.ApicId = i; + HaliMPProcessorInfo(&processor); + processor.CpuFlags &= ~CPU_FLAG_BSP; + } + + bus.Type = MPCTE_BUS; + bus.BusId = 0; + switch (Type) + { + default: + DPRINT("Unknown standard configuration %d\n", Type); + /* Fall through */ + case 1: + case 5: + memcpy(bus.BusType, "ISA ", 6); + break; + case 2: + case 6: + case 3: + memcpy(bus.BusType, "EISA ", 6); + break; + case 4: + case 7: + memcpy(bus.BusType, "MCA ", 6); + } + HaliMPBusInfo(&bus); + if (Type > 4) + { + bus.Type = MPCTE_BUS; + bus.BusId = 1; + memcpy(bus.BusType, "PCI ", 6); + HaliMPBusInfo(&bus); + } + + ioapic.Type = MPCTE_IOAPIC; + ioapic.ApicId = 2; + ioapic.ApicVersion = Type > 4 ? 0x10 : 0x01; + ioapic.ApicFlags = MP_IOAPIC_USABLE; + ioapic.ApicAddress = IOAPIC_DEFAULT_BASE; + HaliMPIOApicInfo(&ioapic); + + /* + * We set up most of the low 16 IO-APIC pins according to MPS rules. + */ + HaliConstructDefaultIOIrqMPTable(Type); + + lintsrc.Type = MPCTE_LINTSRC; + lintsrc.IrqType = 0; + lintsrc.IrqFlag = 0; /* conforming */ + lintsrc.SrcBusId = 0; + lintsrc.SrcBusIrq = 0; + lintsrc.DstApicId = MP_APIC_ALL; + for (i = 0; i < 2; i++) + { + lintsrc.IrqType = linttypes[i]; + lintsrc.DstApicLInt = i; + HaliMPIntLocalInfo(&lintsrc); + } +} + + +static BOOLEAN +HaliScanForMPConfigTable(ULONG Base, + ULONG Size) +{ +/* + PARAMETERS: + Base = Base address of region + Size = Length of region to check + RETURNS: + TRUE if a valid MP configuration table was found + */ + + PULONG bp = (PULONG)Base; + MP_FLOATING_POINTER* mpf; + UCHAR Checksum; + + while (Size > 0) + { + mpf = (MP_FLOATING_POINTER*)bp; + if (mpf->Signature == MPF_SIGNATURE) + { + Checksum = MPChecksum((PUCHAR)bp, 16); + DPRINT("Found MPF signature at %x, checksum %x\n", bp, Checksum); + if (Checksum == 0 && + mpf->Length == 1) + { + DPRINT("Intel MultiProcessor Specification v1.%d compliant system.\n", + mpf->Specification); + + if (mpf->Feature2 & FEATURE2_IMCRP) + { + DPRINT("Running in IMCR and PIC compatibility mode.\n"); + } + else + { + DPRINT("Running in Virtual Wire compatibility mode.\n"); + } + + + switch (mpf->Feature1) + { + case 0: + /* Non standard configuration */ + break; + case 1: + DPRINT("ISA\n"); + break; + case 2: + DPRINT("EISA with no IRQ8 chaining\n"); + break; + case 3: + DPRINT("EISA\n"); + break; + case 4: + DPRINT("MCA\n"); + break; + case 5: + DPRINT("ISA and PCI\n"); + break; + case 6: + DPRINT("EISA and PCI\n"); + break; + case 7: + DPRINT("MCA and PCI\n"); + break; + default: + DPRINT("Unknown standard configuration %d\n", mpf->Feature1); + return FALSE; + } + Mpf = mpf; + return TRUE; + } + } + bp += 4; + Size -= 16; + } + return FALSE; +} + +static BOOLEAN +HaliGetSmpConfig(VOID) +{ + if (Mpf == NULL) + { + return FALSE; + } + + if (Mpf->Feature2 & FEATURE2_IMCRP) + { + DPRINT("Running in IMCR and PIC compatibility mode.\n"); + APICMode = amPIC; + } + else + { + DPRINT("Running in Virtual Wire compatibility mode.\n"); + APICMode = amVWIRE; + } + + if (Mpf->Feature1 == 0 && Mpf->Address) + { + if(!HaliReadMPConfigTable((PMP_CONFIGURATION_TABLE)Mpf->Address)) + { + DPRINT("BIOS bug, MP table errors detected!...\n"); + DPRINT("... disabling SMP support. (tell your hw vendor)\n"); + return FALSE; + } + if (IRQCount == 0) + { + MP_CONFIGURATION_BUS bus; + + DPRINT("BIOS bug, no explicit IRQ entries, using default mptable. (tell your hw vendor)\n"); + + bus.BusId = 1; + memcpy(bus.BusType, "ISA ", 6); + HaliMPBusInfo(&bus); + HaliConstructDefaultIOIrqMPTable(bus.BusId); + } + + } + else if(Mpf->Feature1 != 0) + { + HaliConstructDefaultISAMPTable(Mpf->Feature1); + } + else + { + KEBUGCHECK(0); + } + return TRUE; +} + +BOOLEAN +HaliFindSmpConfig(VOID) +{ + /* + Scan the system memory for an MP configuration table + 1) Scan the first KB of system base memory + 2) Scan the last KB of system base memory + 3) Scan the BIOS ROM address space between 0F0000h and 0FFFFFh + 4) Scan the first KB from the Extended BIOS Data Area + */ + + if (!HaliScanForMPConfigTable(0x0, 0x400)) + { + if (!HaliScanForMPConfigTable(0x9FC00, 0x400)) + { + if (!HaliScanForMPConfigTable(0xF0000, 0x10000)) + { + if (!HaliScanForMPConfigTable(*((PUSHORT)0x040E) << 4, 0x400)) + { + DPRINT("No multiprocessor compliant system found.\n"); + return FALSE; + } + } + } + } + + if (HaliGetSmpConfig()) + { + return TRUE; + } + else + { + DPRINT("No MP config table found\n"); + return FALSE; + } + +} + +/* EOF */ diff --git a/reactos/include/ccros.h b/reactos/include/ccros.h index ed79aa49818..f07302a01ed 100644 --- a/reactos/include/ccros.h +++ b/reactos/include/ccros.h @@ -1,18 +1,18 @@ -#ifndef __INCLUDE_DDK_NTIFS_H -#define __INCLUDE_DDK_NTIFS_H - -NTSTATUS STDCALL -CcRosInitializeFileCache (PFILE_OBJECT FileObject, - ULONG CacheSegmentSize); -NTSTATUS STDCALL -CcRosReleaseFileCache (PFILE_OBJECT FileObject); - -#define FSCTL_ROS_QUERY_LCN_MAPPING \ - CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 63, METHOD_BUFFERED, FILE_ANY_ACCESS) - -typedef struct _ROS_QUERY_LCN_MAPPING -{ - LARGE_INTEGER LcnDiskOffset; -} ROS_QUERY_LCN_MAPPING, *PROS_QUERY_LCN_MAPPING; - -#endif /* __INCLUDE_DDK_NTIFS_H */ +#ifndef __INCLUDE_DDK_NTIFS_H +#define __INCLUDE_DDK_NTIFS_H + +NTSTATUS STDCALL +CcRosInitializeFileCache (PFILE_OBJECT FileObject, + ULONG CacheSegmentSize); +NTSTATUS STDCALL +CcRosReleaseFileCache (PFILE_OBJECT FileObject); + +#define FSCTL_ROS_QUERY_LCN_MAPPING \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 63, METHOD_BUFFERED, FILE_ANY_ACCESS) + +typedef struct _ROS_QUERY_LCN_MAPPING +{ + LARGE_INTEGER LcnDiskOffset; +} ROS_QUERY_LCN_MAPPING, *PROS_QUERY_LCN_MAPPING; + +#endif /* __INCLUDE_DDK_NTIFS_H */ diff --git a/reactos/include/drivers/diskdump/diskdump.h b/reactos/include/drivers/diskdump/diskdump.h index bb3f8b52027..1a686bc01a1 100644 --- a/reactos/include/drivers/diskdump/diskdump.h +++ b/reactos/include/drivers/diskdump/diskdump.h @@ -1,31 +1,31 @@ -#ifndef __DISKDUMP_H -#define __DISKDUMP_H - -#include -#include - -#define MM_CORE_DUMP_HEADER_MAGIC (0xdeafbead) -#define MM_CORE_DUMP_HEADER_VERSION (0x1) - -typedef struct _MM_CORE_DUMP_HEADER -{ - ULONG Magic; - ULONG Version; - ULONG Type; - KTRAP_FRAME TrapFrame; - ULONG BugCheckCode; - ULONG BugCheckParameters[4]; - PVOID FaultingStackBase; - ULONG FaultingStackSize; - ULONG PhysicalMemorySize; -} MM_CORE_DUMP_HEADER, *PMM_CORE_DUMP_HEADER; - -typedef struct MM_CORE_DUMP_FUNCTIONS -{ - NTSTATUS (STDCALL *DumpPrepare)(PDEVICE_OBJECT DeviceObject, PDUMP_POINTERS DumpPointers); - NTSTATUS (STDCALL *DumpInit)(VOID); - NTSTATUS (STDCALL *DumpWrite)(LARGE_INTEGER Address, PMDL Mdl); - NTSTATUS (STDCALL *DumpFinish)(VOID); -} MM_CORE_DUMP_FUNCTIONS, *PMM_CORE_DUMP_FUNCTIONS; - -#endif /* __DISKDUMP_H */ +#ifndef __DISKDUMP_H +#define __DISKDUMP_H + +#include +#include + +#define MM_CORE_DUMP_HEADER_MAGIC (0xdeafbead) +#define MM_CORE_DUMP_HEADER_VERSION (0x1) + +typedef struct _MM_CORE_DUMP_HEADER +{ + ULONG Magic; + ULONG Version; + ULONG Type; + KTRAP_FRAME TrapFrame; + ULONG BugCheckCode; + ULONG BugCheckParameters[4]; + PVOID FaultingStackBase; + ULONG FaultingStackSize; + ULONG PhysicalMemorySize; +} MM_CORE_DUMP_HEADER, *PMM_CORE_DUMP_HEADER; + +typedef struct MM_CORE_DUMP_FUNCTIONS +{ + NTSTATUS (STDCALL *DumpPrepare)(PDEVICE_OBJECT DeviceObject, PDUMP_POINTERS DumpPointers); + NTSTATUS (STDCALL *DumpInit)(VOID); + NTSTATUS (STDCALL *DumpWrite)(LARGE_INTEGER Address, PMDL Mdl); + NTSTATUS (STDCALL *DumpFinish)(VOID); +} MM_CORE_DUMP_FUNCTIONS, *PMM_CORE_DUMP_FUNCTIONS; + +#endif /* __DISKDUMP_H */ diff --git a/reactos/include/libs/fslib/vfatxlib.h b/reactos/include/libs/fslib/vfatxlib.h index 557513b5c16..0d67efe2891 100644 --- a/reactos/include/libs/fslib/vfatxlib.h +++ b/reactos/include/libs/fslib/vfatxlib.h @@ -1,24 +1,24 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS VFAT filesystem library - * FILE: include/fslib/vfatlib.h - * PURPOSE: Public definitions for vfat filesystem library - */ -#ifndef __VFATXLIB_H -#define __VFATXLIB_H - -#include - -NTSTATUS -VfatxInitialize (VOID); - -NTSTATUS -VfatxCleanup (VOID); - -NTSTATUS -VfatxFormat (PUNICODE_STRING DriveRoot, - ULONG MediaFlag, - BOOLEAN QuickFormat, - PFMIFSCALLBACK Callback); - -#endif /*__VFATLIB_H */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS VFAT filesystem library + * FILE: include/fslib/vfatlib.h + * PURPOSE: Public definitions for vfat filesystem library + */ +#ifndef __VFATXLIB_H +#define __VFATXLIB_H + +#include + +NTSTATUS +VfatxInitialize (VOID); + +NTSTATUS +VfatxCleanup (VOID); + +NTSTATUS +VfatxFormat (PUNICODE_STRING DriveRoot, + ULONG MediaFlag, + BOOLEAN QuickFormat, + PFMIFSCALLBACK Callback); + +#endif /*__VFATLIB_H */ diff --git a/reactos/include/libs/pseh/native.h b/reactos/include/libs/pseh/native.h index 1a2e9fcc5d2..30ccc33ffc4 100644 --- a/reactos/include/libs/pseh/native.h +++ b/reactos/include/libs/pseh/native.h @@ -1,242 +1,242 @@ -/* - Copyright (c) 2004/2005 KJK::Hyperion - - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is furnished to do - so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ - -#ifndef KJK_PSEH_NATIVE_H_ -#define KJK_PSEH_NATIVE_H_ - -#include -#include - -/* - Note: just define __inline to an empty symbol if your C compiler doesn't - support it -*/ -#ifdef __cplusplus -# ifndef __inline -# define __inline inline -# endif -#endif - -typedef long (__stdcall * _SEHFilter_t) -( - long, - struct _EXCEPTION_POINTERS *, - void * -); - -typedef void (__stdcall * _SEHFinally_t) -( - int, - void * -); - -static __inline long _SEHCallFilter -( - _SEHFilter_t _SEHFilter, - long _SEHExceptionCode, - struct _EXCEPTION_POINTERS * _SEHExceptionPointers, - void * _SEHPVLocals -) -{ - if(_SEHFilter == _SEH_STATIC_FILTER(_SEH_EXECUTE_HANDLER)) - return _SEH_EXECUTE_HANDLER; - else if(_SEHFilter == _SEH_STATIC_FILTER(_SEH_CONTINUE_SEARCH)) - return _SEH_CONTINUE_SEARCH; - else if(_SEHFilter == _SEH_STATIC_FILTER(_SEH_CONTINUE_EXECUTION)) - return _SEH_CONTINUE_EXECUTION; - else if(_SEHFilter) - return _SEHFilter(_SEHExceptionCode, _SEHExceptionPointers, _SEHPVLocals); - else - return _SEH_CONTINUE_SEARCH; -} - -static __inline void _SEHCallFinally -( - _SEHFinally_t _SEHFinally, - int _SEHAbnormalTermination, - void * _SEHPVLocals -) -{ - if(_SEHFinally) - (_SEHFinally)(_SEHAbnormalTermination, _SEHPVLocals); -} - -/* SHARED LOCALS */ -/* Access the locals for the current frame */ -#define _SEH_ACCESS_LOCALS(LOCALS_) \ - _SEH_LOCALS_TYPENAME(LOCALS_) * _SEHPLocals; \ - _SEHPLocals = _SEH_PVOID_CAST(_SEH_LOCALS_TYPENAME(LOCALS_) *, _SEHPVLocals); - -/* Access local variable VAR_ */ -#define _SEH_VAR(VAR_) _SEHPLocals->VAR_ - -/* FILTER FUNCTIONS */ -/* Declares a filter function's prototype */ -#define _SEH_FILTER(NAME_) \ - long __stdcall NAME_ \ - ( \ - long _SEHExceptionCode, \ - struct _EXCEPTION_POINTERS * _SEHExceptionPointers, \ - void * _SEHPVLocals \ - ) - -/* Declares a static filter */ -#define _SEH_STATIC_FILTER(ACTION_) ((_SEHFilter_t)((ACTION_) + 2)) - -/* Declares a PSEH filter wrapping a regular filter function */ -#define _SEH_WRAP_FILTER(WRAPPER_, NAME_) \ - static __inline _SEH_FILTER(WRAPPER_) \ - { \ - return (NAME_)(_SEHExceptionPointers); \ - } - -/* FINALLY FUNCTIONS */ -/* Declares a finally function's prototype */ -#define _SEH_FINALLYFUNC(NAME_) \ - void __stdcall NAME_ \ - ( \ - int _SEHAbnormalTermination, \ - void * _SEHPVLocals \ - ) - -/* Declares a PSEH finally function wrapping a regular function */ -#define _SEH_WRAP_FINALLY(WRAPPER_, NAME_) \ - _SEH_WRAP_FINALLY_ARGS(WRAPPER_, NAME_, ()) - -#define _SEH_WRAP_FINALLY_ARGS(WRAPPER_, NAME_, ARGS_) \ - static __inline _SEH_FINALLYFUNC(WRAPPER_) \ - { \ - NAME_ ARGS_; \ - } - -#define _SEH_WRAP_FINALLY_LOCALS_ARGS(WRAPPER_, LOCALS_, NAME_, ARGS_) \ - static __inline _SEH_FINALLYFUNC(WRAPPER_) \ - { \ - _SEH_ACCESS_LOCALS(LOCALS_); \ - NAME_ ARGS_; \ - } - -/* SAFE BLOCKS */ -#define _SEH_TRY_FINALLY(FINALLY_) \ - _SEH_TRY_FILTER_FINALLY \ - ( \ - _SEH_STATIC_FILTER(_SEH_CONTINUE_SEARCH), \ - (FINALLY_) \ - ) - -#define _SEH_END_FINALLY _SEH_HANDLE _SEH_END - -#define _SEH_TRY_FILTER(FILTER_) \ - _SEH_TRY_FILTER_FINALLY((FILTER_), NULL) - -#define _SEH_TRY_HANDLE_FINALLY(FINALLY_) \ - _SEH_TRY_FILTER_FINALLY \ - ( \ - _SEH_STATIC_FILTER(_SEH_EXECUTE_HANDLER), \ - (FINALLY_) \ - ) - -#define _SEH_TRY \ - _SEH_TRY_HANDLE_FINALLY(NULL) - -#define _SEH_CALL_FILTER(FILTER_) \ - _SEHCallFilter \ - ( \ - (FILTER_), \ - GetExceptionCode(), \ - GetExceptionPointers(), \ - _SEHPVLocals \ - ) - -#define _SEH_CALL_FINALLY(FINALLY_) \ - _SEHCallFinally((FINALLY_), (AbnormalTermination() != 0), _SEHPVLocals) - -#define _SEH_TRY_FILTER_FINALLY(FILTER_, FINALLY_) \ - __try \ - { \ - _SEHFinally_t _SEHFinally = (FINALLY_); \ - _SEHFilter_t _SEHFilter = (FILTER_); \ - void * _SEHPVLocals = &_SEHLocals; \ - (void)_SEHPVLocals; \ - \ - __try \ - { - -#define _SEH_HANDLE \ - } \ - __except(_SEH_CALL_FILTER(_SEHFilter)) \ - { \ - struct _EXCEPTION_POINTERS * _SEHExceptionPointers = GetExceptionPointers();\ - long _SEHExceptionCode = GetExceptionCode(); \ - -#define _SEH_END \ - } \ - } \ - __finally \ - { \ - _SEH_CALL_FINALLY(_SEHFinally); \ - } - -#define _SEH_LEAVE __leave - -#define _SEH_GetExceptionCode() (_SEHExceptionCode) -#define _SEH_GetExceptionPointers() (_SEHExceptionPointers) -#define _SEH_AbnormalTermination() (_SEHAbnormalTermination) - -/* New syntax */ - -#define _SEH2_TRY \ - { \ - void * _SEHPVLocals = &_SEHLocals; \ - (void)_SEHPVLocals; \ - \ - __try \ - { - -#define _SEH2_EXCEPT(FILTER_) \ - } \ - __except(_SEH_CALL_FILTER(FILTER_)) \ - { \ - struct _EXCEPTION_POINTERS * _SEHExceptionPointers = GetExceptionPointers();\ - long _SEHExceptionCode = GetExceptionCode(); \ - -#define _SEH2_FINALLY(FINALLY_) \ - } \ - __finally \ - { \ - _SEH_CALL_FINALLY(FINALLY_) - -#define _SEH2_END \ - } \ - } - -#define _SEH2_HANDLE _SEH2_EXCEPT(_SEH_STATIC_FILTER(_SEH_EXECUTE_HANDLER)) - -#define _SEH2_LEAVE _SEH_LEAVE - -#define _SEH2_GetExceptionCode _SEH_GetExceptionCode -#define _SEH2_GetExceptionPointers _SEH_GetExceptionPointers -#define _SEH2_AbnormalTermination _SEH_AbnormalTermination - -#endif - -/* EOF */ +/* + Copyright (c) 2004/2005 KJK::Hyperion + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#ifndef KJK_PSEH_NATIVE_H_ +#define KJK_PSEH_NATIVE_H_ + +#include +#include + +/* + Note: just define __inline to an empty symbol if your C compiler doesn't + support it +*/ +#ifdef __cplusplus +# ifndef __inline +# define __inline inline +# endif +#endif + +typedef long (__stdcall * _SEHFilter_t) +( + long, + struct _EXCEPTION_POINTERS *, + void * +); + +typedef void (__stdcall * _SEHFinally_t) +( + int, + void * +); + +static __inline long _SEHCallFilter +( + _SEHFilter_t _SEHFilter, + long _SEHExceptionCode, + struct _EXCEPTION_POINTERS * _SEHExceptionPointers, + void * _SEHPVLocals +) +{ + if(_SEHFilter == _SEH_STATIC_FILTER(_SEH_EXECUTE_HANDLER)) + return _SEH_EXECUTE_HANDLER; + else if(_SEHFilter == _SEH_STATIC_FILTER(_SEH_CONTINUE_SEARCH)) + return _SEH_CONTINUE_SEARCH; + else if(_SEHFilter == _SEH_STATIC_FILTER(_SEH_CONTINUE_EXECUTION)) + return _SEH_CONTINUE_EXECUTION; + else if(_SEHFilter) + return _SEHFilter(_SEHExceptionCode, _SEHExceptionPointers, _SEHPVLocals); + else + return _SEH_CONTINUE_SEARCH; +} + +static __inline void _SEHCallFinally +( + _SEHFinally_t _SEHFinally, + int _SEHAbnormalTermination, + void * _SEHPVLocals +) +{ + if(_SEHFinally) + (_SEHFinally)(_SEHAbnormalTermination, _SEHPVLocals); +} + +/* SHARED LOCALS */ +/* Access the locals for the current frame */ +#define _SEH_ACCESS_LOCALS(LOCALS_) \ + _SEH_LOCALS_TYPENAME(LOCALS_) * _SEHPLocals; \ + _SEHPLocals = _SEH_PVOID_CAST(_SEH_LOCALS_TYPENAME(LOCALS_) *, _SEHPVLocals); + +/* Access local variable VAR_ */ +#define _SEH_VAR(VAR_) _SEHPLocals->VAR_ + +/* FILTER FUNCTIONS */ +/* Declares a filter function's prototype */ +#define _SEH_FILTER(NAME_) \ + long __stdcall NAME_ \ + ( \ + long _SEHExceptionCode, \ + struct _EXCEPTION_POINTERS * _SEHExceptionPointers, \ + void * _SEHPVLocals \ + ) + +/* Declares a static filter */ +#define _SEH_STATIC_FILTER(ACTION_) ((_SEHFilter_t)((ACTION_) + 2)) + +/* Declares a PSEH filter wrapping a regular filter function */ +#define _SEH_WRAP_FILTER(WRAPPER_, NAME_) \ + static __inline _SEH_FILTER(WRAPPER_) \ + { \ + return (NAME_)(_SEHExceptionPointers); \ + } + +/* FINALLY FUNCTIONS */ +/* Declares a finally function's prototype */ +#define _SEH_FINALLYFUNC(NAME_) \ + void __stdcall NAME_ \ + ( \ + int _SEHAbnormalTermination, \ + void * _SEHPVLocals \ + ) + +/* Declares a PSEH finally function wrapping a regular function */ +#define _SEH_WRAP_FINALLY(WRAPPER_, NAME_) \ + _SEH_WRAP_FINALLY_ARGS(WRAPPER_, NAME_, ()) + +#define _SEH_WRAP_FINALLY_ARGS(WRAPPER_, NAME_, ARGS_) \ + static __inline _SEH_FINALLYFUNC(WRAPPER_) \ + { \ + NAME_ ARGS_; \ + } + +#define _SEH_WRAP_FINALLY_LOCALS_ARGS(WRAPPER_, LOCALS_, NAME_, ARGS_) \ + static __inline _SEH_FINALLYFUNC(WRAPPER_) \ + { \ + _SEH_ACCESS_LOCALS(LOCALS_); \ + NAME_ ARGS_; \ + } + +/* SAFE BLOCKS */ +#define _SEH_TRY_FINALLY(FINALLY_) \ + _SEH_TRY_FILTER_FINALLY \ + ( \ + _SEH_STATIC_FILTER(_SEH_CONTINUE_SEARCH), \ + (FINALLY_) \ + ) + +#define _SEH_END_FINALLY _SEH_HANDLE _SEH_END + +#define _SEH_TRY_FILTER(FILTER_) \ + _SEH_TRY_FILTER_FINALLY((FILTER_), NULL) + +#define _SEH_TRY_HANDLE_FINALLY(FINALLY_) \ + _SEH_TRY_FILTER_FINALLY \ + ( \ + _SEH_STATIC_FILTER(_SEH_EXECUTE_HANDLER), \ + (FINALLY_) \ + ) + +#define _SEH_TRY \ + _SEH_TRY_HANDLE_FINALLY(NULL) + +#define _SEH_CALL_FILTER(FILTER_) \ + _SEHCallFilter \ + ( \ + (FILTER_), \ + GetExceptionCode(), \ + GetExceptionPointers(), \ + _SEHPVLocals \ + ) + +#define _SEH_CALL_FINALLY(FINALLY_) \ + _SEHCallFinally((FINALLY_), (AbnormalTermination() != 0), _SEHPVLocals) + +#define _SEH_TRY_FILTER_FINALLY(FILTER_, FINALLY_) \ + __try \ + { \ + _SEHFinally_t _SEHFinally = (FINALLY_); \ + _SEHFilter_t _SEHFilter = (FILTER_); \ + void * _SEHPVLocals = &_SEHLocals; \ + (void)_SEHPVLocals; \ + \ + __try \ + { + +#define _SEH_HANDLE \ + } \ + __except(_SEH_CALL_FILTER(_SEHFilter)) \ + { \ + struct _EXCEPTION_POINTERS * _SEHExceptionPointers = GetExceptionPointers();\ + long _SEHExceptionCode = GetExceptionCode(); \ + +#define _SEH_END \ + } \ + } \ + __finally \ + { \ + _SEH_CALL_FINALLY(_SEHFinally); \ + } + +#define _SEH_LEAVE __leave + +#define _SEH_GetExceptionCode() (_SEHExceptionCode) +#define _SEH_GetExceptionPointers() (_SEHExceptionPointers) +#define _SEH_AbnormalTermination() (_SEHAbnormalTermination) + +/* New syntax */ + +#define _SEH2_TRY \ + { \ + void * _SEHPVLocals = &_SEHLocals; \ + (void)_SEHPVLocals; \ + \ + __try \ + { + +#define _SEH2_EXCEPT(FILTER_) \ + } \ + __except(_SEH_CALL_FILTER(FILTER_)) \ + { \ + struct _EXCEPTION_POINTERS * _SEHExceptionPointers = GetExceptionPointers();\ + long _SEHExceptionCode = GetExceptionCode(); \ + +#define _SEH2_FINALLY(FINALLY_) \ + } \ + __finally \ + { \ + _SEH_CALL_FINALLY(FINALLY_) + +#define _SEH2_END \ + } \ + } + +#define _SEH2_HANDLE _SEH2_EXCEPT(_SEH_STATIC_FILTER(_SEH_EXECUTE_HANDLER)) + +#define _SEH2_LEAVE _SEH_LEAVE + +#define _SEH2_GetExceptionCode _SEH_GetExceptionCode +#define _SEH2_GetExceptionPointers _SEH_GetExceptionPointers +#define _SEH2_AbnormalTermination _SEH_AbnormalTermination + +#endif + +/* EOF */ diff --git a/reactos/include/libs/pseh/prettybased.h b/reactos/include/libs/pseh/prettybased.h index 0991a3e40fa..e3345cfc016 100644 --- a/reactos/include/libs/pseh/prettybased.h +++ b/reactos/include/libs/pseh/prettybased.h @@ -1,299 +1,299 @@ -/* - Copyright (c) 2004 KJK::Hyperion - - Permission is hereby granted, free of charge, to any person obtaining a copy of - this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is furnished to do - so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. -*/ -/* -Pretty PSEH - -Made to be macro compatible with ms seh syntax and to be pretty, having the -finally block inline etc. Being pretty is not cheap. PPSEH has more -overhead than PSEH, thou mostly during exception/unwinding. Normal execution -only add the overhead of one setjmp, and only in the try/finally case. -PPSEH is probably much less portable than PSEH also..... - -ALERT!ALERT!ALERT!ALERT!ALERT!ALERT!ALERT!ALERT!ALERT!ALERT!ALERT!ALERT!ALERT! --must always use non-native NLG cause a special version of longjmp (which doesn't -restore esp) is needed - --compiler must use ebp as stack frame pointer, cause the finally block rely -on this to access external variables - --all external variables that are used in the except/finally block MUST be volatile -to prevent variables from being optimized into registers. -See: http://alphalinux.org/archives/axp-list/1998/February1998/0330.html - --you can't use return within a try/except/finally block - --you can't use __LEAVE within a (for/do/while) loop. it will only leave the loop -and not the try-block itself - - -USAGE: - -__TRY{ - __LEAVE; -} -__EXCEPT(_SEH_STATIC_FILTER(EXCEPTION_EXECUTE_HANDLER)){ -} -__ENDTRY; - - -__TRY{ -} -__FINALLY{ -} -__ENDTRY; - - -_SEH_FILTER(filter){ - return EXCEPTION_EXECUTE_HANDLER; -} -__TRY2{ -} -__EXCEPT2(filter){ -} -__FINALLY2{ -} -__ENDTRY2; - - - --Gunnar - -*/ - - -#ifndef KJK_PPSEH_FRAMEBASED_H_ -#define KJK_PPSEH_FRAMEBASED_H_ - -#include -#include -#include - -#ifndef offsetof -# include -#endif - -/* -Must always use non-native NLG since we need a special version of longjmp which does -not restore esp -*/ -#include - - -typedef struct __SEHFrame -{ - _SEHPortableFrame_t SEH_Header; - _SEHJmpBuf_t SEH_JmpBuf; - _SEHJmpBuf_t* SEH_JmpRetPtr; -} -_SEHFrame_t; - -/* - Note: just define __inline to an empty symbol if your C compiler doesn't - support it -*/ -#ifdef __cplusplus -# ifndef __inline -# define __inline inline -# endif -#endif - - -/* FILTER FUNCTIONS */ -/* Declares a filter function's prototype */ -#define _SEH_FILTER(NAME_) \ - long __stdcall NAME_ \ - ( \ - struct _EXCEPTION_POINTERS * _SEHExceptionPointers, \ - struct __SEHPortableFrame * _SEHPortableFrame \ - ) - - -/* Declares a static filter */ -#define _SEH_STATIC_FILTER(ACTION_) ((_SEHFilter_t)((ACTION_) + 2)) - - -static __declspec(noreturn) __inline void __stdcall _SEHCompilerSpecificHandler -( - _SEHPortableFrame_t * frame -) -{ - _SEHFrame_t * myframe; - myframe = (_SEHFrame_t *)(((char *)frame) - offsetof(_SEHFrame_t, SEH_Header)); - _SEHLongJmp(myframe->SEH_JmpBuf, 1); -} - - - -void __stdcall _FinallyPretty -( - struct __SEHPortableFrame * frame -) -{ - _SEHFrame_t * myframe; - _SEHJmpBuf_t jmpRetBuf; - - myframe = (_SEHFrame_t *)(((char *)frame) - offsetof(_SEHFrame_t, SEH_Header)); - - if(_SEHSetJmp(jmpRetBuf) == 0) - { - myframe->SEH_JmpRetPtr = &jmpRetBuf; - _SEHLongJmp_KeepEsp(myframe->SEH_JmpBuf, 2); - } -} - - - -#define ___EXCEPT_DUAL(filter) \ - } while(0); \ - \ - _SEHLeave(&_SEHFrame->SEH_Header); \ - } \ - else \ - { \ - _SEHHandlers.SH_Filter = (filter); \ - _SEHHandlers.SH_Finally = _FinallyPretty; \ - \ - if(_loop == 2 || (_ret = _SEHSetJmp(_SEHFrame->SEH_JmpBuf))) \ - { \ - if (_ret == 1) \ - { \ - _SEHLeave(&_SEHFrame->SEH_Header); \ - do \ - { - - - -#define ___FINALLY_DUAL \ - } while (0); \ - } \ - \ - do \ - { - - - -#define ___EXCEPT_SINGLE(filter) \ - } while(0); \ - \ - _SEHLeave(&_SEHFrame->SEH_Header); \ - break; \ - } \ - else \ - { \ - _SEHHandlers.SH_Filter = (filter); \ - _SEHHandlers.SH_Finally = (NULL); \ - \ - if(_SEHSetJmp(_SEHFrame->SEH_JmpBuf)) \ - { \ - _SEHLeave(&_SEHFrame->SEH_Header); \ - do \ - { - - - -#define ___TRY \ - do \ - { \ - int _loop =0; int _ret = 0; \ - static _SEHHandlers_t _SEHHandlers = \ - { \ - (NULL), \ - _SEHCompilerSpecificHandler, \ - (NULL) \ - }; \ - \ - _SEHFrame_t * _SEHFrame; \ - volatile _SEHPortableFrame_t * _SEHPortableFrame; \ - \ - _SEHFrame = _alloca(sizeof(_SEHFrame_t)); \ - _SEHFrame->SEH_Header.SPF_Handlers = &_SEHHandlers; \ - \ - _SEHPortableFrame = &_SEHFrame->SEH_Header; \ - (void)_SEHPortableFrame; \ - \ - for(;;_loop++) \ - if (_loop == 1) \ - { \ - _SEHEnter(&_SEHFrame->SEH_Header); \ - \ - do \ - { - - -#define ___FINALLY_SINGLE \ - } while(0); \ - \ - _SEHLeave(&_SEHFrame->SEH_Header); \ - } \ - else \ - { \ - _SEHHandlers.SH_Filter = _SEH_STATIC_FILTER(_SEH_CONTINUE_SEARCH); \ - _SEHHandlers.SH_Finally = _FinallyPretty; \ - \ - if(_loop == 2 || (_ret = _SEHSetJmp(_SEHFrame->SEH_JmpBuf))) \ - { \ - do \ - { - - - -#define ___ENDTRY \ - } while (0); \ - \ - if (_ret == 2) \ - { \ - _SEHLongJmp(*_SEHFrame->SEH_JmpRetPtr, 1); \ - } \ - break; \ - } \ - } \ - } while (0); - - - -#ifdef _MSC_VER - #define __TRY2 __try{__try - #define __EXCEPT2 __except - #define __FINALLY2 }__finally - #define __ENDTRY2 - #define __TRY __try - #define __EXCEPT __except - #define __FINALLY __finally - #define __ENDTRY - #define _SEH_STATIC_FILTER(ACTION_) (ACTION_) - #define __LEAVE __leave - #define __LEAVE2 __leave -#else - #define __TRY2 ___TRY - #define __EXCEPT2 ___EXCEPT_DUAL - #define __FINALLY2 ___FINALLY_DUAL - #define __ENDTRY2 __ENDTRY - #define __TRY ___TRY - #define __EXCEPT ___EXCEPT_SINGLE - #define __FINALLY ___FINALLY_SINGLE - #define __ENDTRY ___ENDTRY - #define __LEAVE break - #define __LEAVE2 break -#endif - - -#endif +/* + Copyright (c) 2004 KJK::Hyperion + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +/* +Pretty PSEH + +Made to be macro compatible with ms seh syntax and to be pretty, having the +finally block inline etc. Being pretty is not cheap. PPSEH has more +overhead than PSEH, thou mostly during exception/unwinding. Normal execution +only add the overhead of one setjmp, and only in the try/finally case. +PPSEH is probably much less portable than PSEH also..... + +ALERT!ALERT!ALERT!ALERT!ALERT!ALERT!ALERT!ALERT!ALERT!ALERT!ALERT!ALERT!ALERT! +-must always use non-native NLG cause a special version of longjmp (which doesn't +restore esp) is needed + +-compiler must use ebp as stack frame pointer, cause the finally block rely +on this to access external variables + +-all external variables that are used in the except/finally block MUST be volatile +to prevent variables from being optimized into registers. +See: http://alphalinux.org/archives/axp-list/1998/February1998/0330.html + +-you can't use return within a try/except/finally block + +-you can't use __LEAVE within a (for/do/while) loop. it will only leave the loop +and not the try-block itself + + +USAGE: + +__TRY{ + __LEAVE; +} +__EXCEPT(_SEH_STATIC_FILTER(EXCEPTION_EXECUTE_HANDLER)){ +} +__ENDTRY; + + +__TRY{ +} +__FINALLY{ +} +__ENDTRY; + + +_SEH_FILTER(filter){ + return EXCEPTION_EXECUTE_HANDLER; +} +__TRY2{ +} +__EXCEPT2(filter){ +} +__FINALLY2{ +} +__ENDTRY2; + + + +-Gunnar + +*/ + + +#ifndef KJK_PPSEH_FRAMEBASED_H_ +#define KJK_PPSEH_FRAMEBASED_H_ + +#include +#include +#include + +#ifndef offsetof +# include +#endif + +/* +Must always use non-native NLG since we need a special version of longjmp which does +not restore esp +*/ +#include + + +typedef struct __SEHFrame +{ + _SEHPortableFrame_t SEH_Header; + _SEHJmpBuf_t SEH_JmpBuf; + _SEHJmpBuf_t* SEH_JmpRetPtr; +} +_SEHFrame_t; + +/* + Note: just define __inline to an empty symbol if your C compiler doesn't + support it +*/ +#ifdef __cplusplus +# ifndef __inline +# define __inline inline +# endif +#endif + + +/* FILTER FUNCTIONS */ +/* Declares a filter function's prototype */ +#define _SEH_FILTER(NAME_) \ + long __stdcall NAME_ \ + ( \ + struct _EXCEPTION_POINTERS * _SEHExceptionPointers, \ + struct __SEHPortableFrame * _SEHPortableFrame \ + ) + + +/* Declares a static filter */ +#define _SEH_STATIC_FILTER(ACTION_) ((_SEHFilter_t)((ACTION_) + 2)) + + +static __declspec(noreturn) __inline void __stdcall _SEHCompilerSpecificHandler +( + _SEHPortableFrame_t * frame +) +{ + _SEHFrame_t * myframe; + myframe = (_SEHFrame_t *)(((char *)frame) - offsetof(_SEHFrame_t, SEH_Header)); + _SEHLongJmp(myframe->SEH_JmpBuf, 1); +} + + + +void __stdcall _FinallyPretty +( + struct __SEHPortableFrame * frame +) +{ + _SEHFrame_t * myframe; + _SEHJmpBuf_t jmpRetBuf; + + myframe = (_SEHFrame_t *)(((char *)frame) - offsetof(_SEHFrame_t, SEH_Header)); + + if(_SEHSetJmp(jmpRetBuf) == 0) + { + myframe->SEH_JmpRetPtr = &jmpRetBuf; + _SEHLongJmp_KeepEsp(myframe->SEH_JmpBuf, 2); + } +} + + + +#define ___EXCEPT_DUAL(filter) \ + } while(0); \ + \ + _SEHLeave(&_SEHFrame->SEH_Header); \ + } \ + else \ + { \ + _SEHHandlers.SH_Filter = (filter); \ + _SEHHandlers.SH_Finally = _FinallyPretty; \ + \ + if(_loop == 2 || (_ret = _SEHSetJmp(_SEHFrame->SEH_JmpBuf))) \ + { \ + if (_ret == 1) \ + { \ + _SEHLeave(&_SEHFrame->SEH_Header); \ + do \ + { + + + +#define ___FINALLY_DUAL \ + } while (0); \ + } \ + \ + do \ + { + + + +#define ___EXCEPT_SINGLE(filter) \ + } while(0); \ + \ + _SEHLeave(&_SEHFrame->SEH_Header); \ + break; \ + } \ + else \ + { \ + _SEHHandlers.SH_Filter = (filter); \ + _SEHHandlers.SH_Finally = (NULL); \ + \ + if(_SEHSetJmp(_SEHFrame->SEH_JmpBuf)) \ + { \ + _SEHLeave(&_SEHFrame->SEH_Header); \ + do \ + { + + + +#define ___TRY \ + do \ + { \ + int _loop =0; int _ret = 0; \ + static _SEHHandlers_t _SEHHandlers = \ + { \ + (NULL), \ + _SEHCompilerSpecificHandler, \ + (NULL) \ + }; \ + \ + _SEHFrame_t * _SEHFrame; \ + volatile _SEHPortableFrame_t * _SEHPortableFrame; \ + \ + _SEHFrame = _alloca(sizeof(_SEHFrame_t)); \ + _SEHFrame->SEH_Header.SPF_Handlers = &_SEHHandlers; \ + \ + _SEHPortableFrame = &_SEHFrame->SEH_Header; \ + (void)_SEHPortableFrame; \ + \ + for(;;_loop++) \ + if (_loop == 1) \ + { \ + _SEHEnter(&_SEHFrame->SEH_Header); \ + \ + do \ + { + + +#define ___FINALLY_SINGLE \ + } while(0); \ + \ + _SEHLeave(&_SEHFrame->SEH_Header); \ + } \ + else \ + { \ + _SEHHandlers.SH_Filter = _SEH_STATIC_FILTER(_SEH_CONTINUE_SEARCH); \ + _SEHHandlers.SH_Finally = _FinallyPretty; \ + \ + if(_loop == 2 || (_ret = _SEHSetJmp(_SEHFrame->SEH_JmpBuf))) \ + { \ + do \ + { + + + +#define ___ENDTRY \ + } while (0); \ + \ + if (_ret == 2) \ + { \ + _SEHLongJmp(*_SEHFrame->SEH_JmpRetPtr, 1); \ + } \ + break; \ + } \ + } \ + } while (0); + + + +#ifdef _MSC_VER + #define __TRY2 __try{__try + #define __EXCEPT2 __except + #define __FINALLY2 }__finally + #define __ENDTRY2 + #define __TRY __try + #define __EXCEPT __except + #define __FINALLY __finally + #define __ENDTRY + #define _SEH_STATIC_FILTER(ACTION_) (ACTION_) + #define __LEAVE __leave + #define __LEAVE2 __leave +#else + #define __TRY2 ___TRY + #define __EXCEPT2 ___EXCEPT_DUAL + #define __FINALLY2 ___FINALLY_DUAL + #define __ENDTRY2 __ENDTRY + #define __TRY ___TRY + #define __EXCEPT ___EXCEPT_SINGLE + #define __FINALLY ___FINALLY_SINGLE + #define __ENDTRY ___ENDTRY + #define __LEAVE break + #define __LEAVE2 break +#endif + + +#endif diff --git a/reactos/include/ndk/arch/ketypes.h b/reactos/include/ndk/arch/ketypes.h index aab299fe631..29ebd998da5 100644 --- a/reactos/include/ndk/arch/ketypes.h +++ b/reactos/include/ndk/arch/ketypes.h @@ -1,27 +1,27 @@ -/* - * PROJECT: ReactOS Native Headers - * FILE: include/ndk/arch/ketypes.h - * PURPOSE: Architecture-specific definitions for Kernel Types - * PROGRAMMER: Alex Ionescu (alex@relsoft.net) - * UPDATE HISTORY: - * Created 06/10/04 - */ -#ifndef _ARCH_KETYPES_H -#define _ARCH_KETYPES_H - -/* Shared structure needed by Arch-specific headers */ -typedef struct _KDPC_DATA -{ - LIST_ENTRY DpcListHead; - ULONG DpcLock; - ULONG DpcQueueDepth; - ULONG DpcCount; -} KDPC_DATA, *PKDPC_DATA; - -#ifdef _M_IX86 -#include -#else -#error "Unknown processor" -#endif - -#endif +/* + * PROJECT: ReactOS Native Headers + * FILE: include/ndk/arch/ketypes.h + * PURPOSE: Architecture-specific definitions for Kernel Types + * PROGRAMMER: Alex Ionescu (alex@relsoft.net) + * UPDATE HISTORY: + * Created 06/10/04 + */ +#ifndef _ARCH_KETYPES_H +#define _ARCH_KETYPES_H + +/* Shared structure needed by Arch-specific headers */ +typedef struct _KDPC_DATA +{ + LIST_ENTRY DpcListHead; + ULONG DpcLock; + ULONG DpcQueueDepth; + ULONG DpcCount; +} KDPC_DATA, *PKDPC_DATA; + +#ifdef _M_IX86 +#include +#else +#error "Unknown processor" +#endif + +#endif diff --git a/reactos/include/ndk/arch/mmtypes.h b/reactos/include/ndk/arch/mmtypes.h index 443406a4f42..ea8dc749a71 100644 --- a/reactos/include/ndk/arch/mmtypes.h +++ b/reactos/include/ndk/arch/mmtypes.h @@ -1,18 +1,18 @@ -/* - * PROJECT: ReactOS Native Headers - * FILE: include/ndk/arch/mmtypes.h - * PURPOSE: Architecture-specific definitions for Memory Manager Types - * PROGRAMMER: Alex Ionescu (alex@relsoft.net) - * UPDATE HISTORY: - * Created 06/10/04 - */ -#ifndef _ARCH_MMTYPES_H -#define _ARCH_MMTYPES_H - -#ifdef _M_IX86 -#include -#else -#error "Unknown processor" -#endif - -#endif +/* + * PROJECT: ReactOS Native Headers + * FILE: include/ndk/arch/mmtypes.h + * PURPOSE: Architecture-specific definitions for Memory Manager Types + * PROGRAMMER: Alex Ionescu (alex@relsoft.net) + * UPDATE HISTORY: + * Created 06/10/04 + */ +#ifndef _ARCH_MMTYPES_H +#define _ARCH_MMTYPES_H + +#ifdef _M_IX86 +#include +#else +#error "Unknown processor" +#endif + +#endif diff --git a/reactos/include/ndk/asm.h b/reactos/include/ndk/asm.h index f58ef92f872..756b5edbcb3 100644 --- a/reactos/include/ndk/asm.h +++ b/reactos/include/ndk/asm.h @@ -1,194 +1,194 @@ -/* - * PROJECT: ReactOS Native Headers - * FILE: include/ndk/asm.h - * PURPOSE: Defintions for Structures used in Assembly Code - * PROGRAMMER: Alex Ionescu (alex@relsoft.net) - * UPDATE HISTORY: - * Created 07/19/05 - */ -#ifndef _ASM_H -#define _ASM_H - -/* DEPENDENCIES **************************************************************/ - -/* EXPORTED DATA *************************************************************/ - -/* CONSTANTS *****************************************************************/ - -/* - * Definitions for the offsets of members in the KV86M_REGISTERS - */ -#define KV86M_REGISTERS_EBP 0x0 -#define KV86M_REGISTERS_EDI 0x4 -#define KV86M_REGISTERS_ESI 0x8 -#define KV86M_REGISTERS_EDX 0xC -#define KV86M_REGISTERS_ECX 0x10 -#define KV86M_REGISTERS_EBX 0x14 -#define KV86M_REGISTERS_EAX 0x18 -#define KV86M_REGISTERS_DS 0x1C -#define KV86M_REGISTERS_ES 0x20 -#define KV86M_REGISTERS_FS 0x24 -#define KV86M_REGISTERS_GS 0x28 -#define KV86M_REGISTERS_EIP 0x2C -#define KV86M_REGISTERS_CS 0x30 -#define KV86M_REGISTERS_EFLAGS 0x34 -#define KV86M_REGISTERS_ESP 0x38 -#define KV86M_REGISTERS_SS 0x3C - -#define TF_SAVED_EXCEPTION_STACK 0x8C -#define TF_REGS 0x90 -#define TF_ORIG_EBP 0x94 - -/* TSS Offsets */ -#define KTSS_ESP0 0x4 -#define KTSS_CR3 0x1C -#define KTSS_EFLAGS 0x24 -#define KTSS_IOMAPBASE 0x66 - -/* - * Defines for accessing KPCR and KTHREAD structure members - */ -#define KTHREAD_INITIAL_STACK 0x18 -#define KTHREAD_STACK_LIMIT 0x1C -#define KTHREAD_TEB 0x20 -#define KTHREAD_KERNEL_STACK 0x28 -#define KTHREAD_NPX_STATE 0x31 -#define KTHREAD_STATE 0x2D -#define KTHREAD_APCSTATE_PROCESS 0x34 + 0x10 -#define KTHREAD_PENDING_USER_APC 0x34 + 0x16 -#define KTHREAD_PENDING_KERNEL_APC 0x34 + 0x15 -#define KTHREAD_CONTEXT_SWITCHES 0x4C -#define KTHREAD_WAIT_IRQL 0x54 -#define KTHREAD_SERVICE_TABLE 0xDC -#define KTHREAD_PREVIOUS_MODE 0x137 -#define KTHREAD_TRAP_FRAME 0x128 -#define KTHREAD_CALLBACK_STACK 0x120 - -#define KPROCESS_DIRECTORY_TABLE_BASE 0x18 -#define KPROCESS_LDT_DESCRIPTOR0 0x20 -#define KPROCESS_LDT_DESCRIPTOR1 0x24 -#define KPROCESS_IOPM_OFFSET 0x30 - -#define KPCR_EXCEPTION_LIST 0x0 -#define KPCR_INITIAL_STACK 0x4 -#define KPCR_STACK_LIMIT 0x8 -#define KPCR_SELF 0x1C -#define KPCR_GDT 0x3C -#define KPCR_TSS 0x40 -#define KPCR_CURRENT_THREAD 0x124 -#define KPCR_NPX_THREAD 0x2F4 - -/* FPU Save Area Offsets */ -#define FN_CONTROL_WORD 0x0 -#define FN_STATUS_WORD 0x4 -#define FN_TAG_WORD 0x8 -#define FN_DATA_SELECTOR 0x18 -#define FN_CR0_NPX_STATE 0x20C -#define SIZEOF_FX_SAVE_AREA 528 - -/* Trap Frame Offsets */ -#define KTRAP_FRAME_DEBUGEBP 0x0 -#define KTRAP_FRAME_DEBUGEIP 0x4 -#define KTRAP_FRAME_DEBUGARGMARK 0x8 -#define KTRAP_FRAME_DEBUGPOINTER 0xC -#define KTRAP_FRAME_TEMPSS 0x10 -#define KTRAP_FRAME_TEMPESP 0x14 -#define KTRAP_FRAME_DR0 0x18 -#define KTRAP_FRAME_DR1 0x1C -#define KTRAP_FRAME_DR2 0x20 -#define KTRAP_FRAME_DR3 0x24 -#define KTRAP_FRAME_DR6 0x28 -#define KTRAP_FRAME_DR7 0x2C -#define KTRAP_FRAME_GS 0x30 -#define KTRAP_FRAME_RESERVED1 0x32 -#define KTRAP_FRAME_ES 0x34 -#define KTRAP_FRAME_RESERVED2 0x36 -#define KTRAP_FRAME_DS 0x38 -#define KTRAP_FRAME_RESERVED3 0x3A -#define KTRAP_FRAME_EDX 0x3C -#define KTRAP_FRAME_ECX 0x40 -#define KTRAP_FRAME_EAX 0x44 -#define KTRAP_FRAME_PREVIOUS_MODE 0x48 -#define KTRAP_FRAME_EXCEPTION_LIST 0x4C -#define KTRAP_FRAME_FS 0x50 -#define KTRAP_FRAME_RESERVED4 0x52 -#define KTRAP_FRAME_EDI 0x54 -#define KTRAP_FRAME_ESI 0x58 -#define KTRAP_FRAME_EBX 0x5C -#define KTRAP_FRAME_EBP 0x60 -#define KTRAP_FRAME_ERROR_CODE 0x64 -#define KTRAP_FRAME_EIP 0x68 -#define KTRAP_FRAME_CS 0x6C -#define KTRAP_FRAME_EFLAGS 0x70 -#define KTRAP_FRAME_ESP 0x74 -#define KTRAP_FRAME_SS 0x78 -#define KTRAP_FRAME_RESERVED5 0x7A -#define KTRAP_FRAME_V86_ES 0x7C -#define KTRAP_FRAME_RESERVED6 0x7E -#define KTRAP_FRAME_V86_DS 0x80 -#define KTRAP_FRAME_RESERVED7 0x82 -#define KTRAP_FRAME_V86_FS 0x84 -#define KTRAP_FRAME_RESERVED8 0x86 -#define KTRAP_FRAME_V86_GS 0x88 -#define KTRAP_FRAME_RESERVED9 0x8A -#define KTRAP_FRAME_SIZE 0x8C - -/* User Shared Data */ -#define KERNEL_USER_SHARED_DATA 0x7FFE0000 -#define KUSER_SHARED_PROCESSOR_FEATURES KERNEL_USER_SHARED_DATA + 0x274 -#define KUSER_SHARED_SYSCALL KERNEL_USER_SHARED_DATA + 0x300 -#define KUSER_SHARED_SYSCALL_RET KERNEL_USER_SHARED_DATA + 0x304 -#define PROCESSOR_FEATURE_FXSR KUSER_SHARED_PROCESSOR_FEATURES + 0x4 - -/* CONTEXT CONSTANTS */ -#define CONTEXT_FLAGS 0x0 -#define CONTEXT_DR6 0x14 -#define CONTEXT_FLOAT_SAVE 0x1C -#define CONTEXT_EDI 0x9C -#define CONTEXT_ESI 0xA0 -#define CONTEXT_EBX 0xA4 -#define CONTEXT_EDX 0xA8 -#define CONTEXT_ECX 0xAC -#define CONTEXT_EAX 0xB0 -#define CONTEXT_EBP 0xB4 -#define CONTEXT_EIP 0xB8 -#define CONTEXT_ESP 0xC4 -#define CONTEXT_FLOAT_SAVE_CONTROL_WORD CONTEXT_FLOAT_SAVE + FN_CONTROL_WORD -#define CONTEXT_FLOAT_SAVE_STATUS_WORD CONTEXT_FLOAT_SAVE + FN_STATUS_WORD -#define CONTEXT_FLOAT_SAVE_TAG_WORD CONTEXT_FLOAT_SAVE + FN_TAG_WORD - -/* TEB CONSTANTS */ -#define TEB_EXCEPTION_LIST 0x0 -#define TEB_STACK_BASE 0x4 -#define TEB_STACK_LIMIT 0x8 -#define TEB_FIBER_DATA 0x10 -#define TEB_ACTIVATION_CONTEXT_STACK_POINTER 0x1A8 -#define TEB_DEALLOCATION_STACK 0xE0C -#define TEB_GUARANTEED_STACK_BYTES 0xF78 -#define TEB_FLS_DATA 0xFB4 - -/* FIBER CONSTANTS */ -#define FIBER_PARAMETER 0x0 -#define FIBER_EXCEPTION_LIST 0x4 -#define FIBER_STACK_BASE 0x8 -#define FIBER_STACK_LIMIT 0xC -#define FIBER_DEALLOCATION_STACK 0x10 -#define FIBER_CONTEXT 0x14 -#define FIBER_GUARANTEED_STACK_BYTES 0x2E0 -#define FIBER_FLS_DATA 0x2E4 -#define FIBER_ACTIVATION_CONTEXT_STACK 0x2E8 -#define FIBER_CONTEXT_FLAGS FIBER_CONTEXT + CONTEXT_FLAGS -#define FIBER_CONTEXT_EAX FIBER_CONTEXT + CONTEXT_EAX -#define FIBER_CONTEXT_EBX FIBER_CONTEXT + CONTEXT_EBX -#define FIBER_CONTEXT_ECX FIBER_CONTEXT + CONTEXT_ECX -#define FIBER_CONTEXT_EDX FIBER_CONTEXT + CONTEXT_EDX -#define FIBER_CONTEXT_ESI FIBER_CONTEXT + CONTEXT_ESI -#define FIBER_CONTEXT_EDI FIBER_CONTEXT + CONTEXT_EDI -#define FIBER_CONTEXT_EBP FIBER_CONTEXT + CONTEXT_EBP -#define FIBER_CONTEXT_ESP FIBER_CONTEXT + CONTEXT_ESP -#define FIBER_CONTEXT_DR6 FIBER_CONTEXT + CONTEXT_DR6 -#define FIBER_CONTEXT_FLOAT_SAVE_STATUS_WORD FIBER_CONTEXT + CONTEXT_FLOAT_SAVE_STATUS_WORD -#define FIBER_CONTEXT_FLOAT_SAVE_CONTROL_WORD FIBER_CONTEXT + CONTEXT_FLOAT_SAVE_CONTROL_WORD -#define FIBER_CONTEXT_FLOAT_SAVE_TAG_WORD FIBER_CONTEXT + CONTEXT_FLOAT_SAVE_TAG_WORD -#endif - +/* + * PROJECT: ReactOS Native Headers + * FILE: include/ndk/asm.h + * PURPOSE: Defintions for Structures used in Assembly Code + * PROGRAMMER: Alex Ionescu (alex@relsoft.net) + * UPDATE HISTORY: + * Created 07/19/05 + */ +#ifndef _ASM_H +#define _ASM_H + +/* DEPENDENCIES **************************************************************/ + +/* EXPORTED DATA *************************************************************/ + +/* CONSTANTS *****************************************************************/ + +/* + * Definitions for the offsets of members in the KV86M_REGISTERS + */ +#define KV86M_REGISTERS_EBP 0x0 +#define KV86M_REGISTERS_EDI 0x4 +#define KV86M_REGISTERS_ESI 0x8 +#define KV86M_REGISTERS_EDX 0xC +#define KV86M_REGISTERS_ECX 0x10 +#define KV86M_REGISTERS_EBX 0x14 +#define KV86M_REGISTERS_EAX 0x18 +#define KV86M_REGISTERS_DS 0x1C +#define KV86M_REGISTERS_ES 0x20 +#define KV86M_REGISTERS_FS 0x24 +#define KV86M_REGISTERS_GS 0x28 +#define KV86M_REGISTERS_EIP 0x2C +#define KV86M_REGISTERS_CS 0x30 +#define KV86M_REGISTERS_EFLAGS 0x34 +#define KV86M_REGISTERS_ESP 0x38 +#define KV86M_REGISTERS_SS 0x3C + +#define TF_SAVED_EXCEPTION_STACK 0x8C +#define TF_REGS 0x90 +#define TF_ORIG_EBP 0x94 + +/* TSS Offsets */ +#define KTSS_ESP0 0x4 +#define KTSS_CR3 0x1C +#define KTSS_EFLAGS 0x24 +#define KTSS_IOMAPBASE 0x66 + +/* + * Defines for accessing KPCR and KTHREAD structure members + */ +#define KTHREAD_INITIAL_STACK 0x18 +#define KTHREAD_STACK_LIMIT 0x1C +#define KTHREAD_TEB 0x20 +#define KTHREAD_KERNEL_STACK 0x28 +#define KTHREAD_NPX_STATE 0x31 +#define KTHREAD_STATE 0x2D +#define KTHREAD_APCSTATE_PROCESS 0x34 + 0x10 +#define KTHREAD_PENDING_USER_APC 0x34 + 0x16 +#define KTHREAD_PENDING_KERNEL_APC 0x34 + 0x15 +#define KTHREAD_CONTEXT_SWITCHES 0x4C +#define KTHREAD_WAIT_IRQL 0x54 +#define KTHREAD_SERVICE_TABLE 0xDC +#define KTHREAD_PREVIOUS_MODE 0x137 +#define KTHREAD_TRAP_FRAME 0x128 +#define KTHREAD_CALLBACK_STACK 0x120 + +#define KPROCESS_DIRECTORY_TABLE_BASE 0x18 +#define KPROCESS_LDT_DESCRIPTOR0 0x20 +#define KPROCESS_LDT_DESCRIPTOR1 0x24 +#define KPROCESS_IOPM_OFFSET 0x30 + +#define KPCR_EXCEPTION_LIST 0x0 +#define KPCR_INITIAL_STACK 0x4 +#define KPCR_STACK_LIMIT 0x8 +#define KPCR_SELF 0x1C +#define KPCR_GDT 0x3C +#define KPCR_TSS 0x40 +#define KPCR_CURRENT_THREAD 0x124 +#define KPCR_NPX_THREAD 0x2F4 + +/* FPU Save Area Offsets */ +#define FN_CONTROL_WORD 0x0 +#define FN_STATUS_WORD 0x4 +#define FN_TAG_WORD 0x8 +#define FN_DATA_SELECTOR 0x18 +#define FN_CR0_NPX_STATE 0x20C +#define SIZEOF_FX_SAVE_AREA 528 + +/* Trap Frame Offsets */ +#define KTRAP_FRAME_DEBUGEBP 0x0 +#define KTRAP_FRAME_DEBUGEIP 0x4 +#define KTRAP_FRAME_DEBUGARGMARK 0x8 +#define KTRAP_FRAME_DEBUGPOINTER 0xC +#define KTRAP_FRAME_TEMPSS 0x10 +#define KTRAP_FRAME_TEMPESP 0x14 +#define KTRAP_FRAME_DR0 0x18 +#define KTRAP_FRAME_DR1 0x1C +#define KTRAP_FRAME_DR2 0x20 +#define KTRAP_FRAME_DR3 0x24 +#define KTRAP_FRAME_DR6 0x28 +#define KTRAP_FRAME_DR7 0x2C +#define KTRAP_FRAME_GS 0x30 +#define KTRAP_FRAME_RESERVED1 0x32 +#define KTRAP_FRAME_ES 0x34 +#define KTRAP_FRAME_RESERVED2 0x36 +#define KTRAP_FRAME_DS 0x38 +#define KTRAP_FRAME_RESERVED3 0x3A +#define KTRAP_FRAME_EDX 0x3C +#define KTRAP_FRAME_ECX 0x40 +#define KTRAP_FRAME_EAX 0x44 +#define KTRAP_FRAME_PREVIOUS_MODE 0x48 +#define KTRAP_FRAME_EXCEPTION_LIST 0x4C +#define KTRAP_FRAME_FS 0x50 +#define KTRAP_FRAME_RESERVED4 0x52 +#define KTRAP_FRAME_EDI 0x54 +#define KTRAP_FRAME_ESI 0x58 +#define KTRAP_FRAME_EBX 0x5C +#define KTRAP_FRAME_EBP 0x60 +#define KTRAP_FRAME_ERROR_CODE 0x64 +#define KTRAP_FRAME_EIP 0x68 +#define KTRAP_FRAME_CS 0x6C +#define KTRAP_FRAME_EFLAGS 0x70 +#define KTRAP_FRAME_ESP 0x74 +#define KTRAP_FRAME_SS 0x78 +#define KTRAP_FRAME_RESERVED5 0x7A +#define KTRAP_FRAME_V86_ES 0x7C +#define KTRAP_FRAME_RESERVED6 0x7E +#define KTRAP_FRAME_V86_DS 0x80 +#define KTRAP_FRAME_RESERVED7 0x82 +#define KTRAP_FRAME_V86_FS 0x84 +#define KTRAP_FRAME_RESERVED8 0x86 +#define KTRAP_FRAME_V86_GS 0x88 +#define KTRAP_FRAME_RESERVED9 0x8A +#define KTRAP_FRAME_SIZE 0x8C + +/* User Shared Data */ +#define KERNEL_USER_SHARED_DATA 0x7FFE0000 +#define KUSER_SHARED_PROCESSOR_FEATURES KERNEL_USER_SHARED_DATA + 0x274 +#define KUSER_SHARED_SYSCALL KERNEL_USER_SHARED_DATA + 0x300 +#define KUSER_SHARED_SYSCALL_RET KERNEL_USER_SHARED_DATA + 0x304 +#define PROCESSOR_FEATURE_FXSR KUSER_SHARED_PROCESSOR_FEATURES + 0x4 + +/* CONTEXT CONSTANTS */ +#define CONTEXT_FLAGS 0x0 +#define CONTEXT_DR6 0x14 +#define CONTEXT_FLOAT_SAVE 0x1C +#define CONTEXT_EDI 0x9C +#define CONTEXT_ESI 0xA0 +#define CONTEXT_EBX 0xA4 +#define CONTEXT_EDX 0xA8 +#define CONTEXT_ECX 0xAC +#define CONTEXT_EAX 0xB0 +#define CONTEXT_EBP 0xB4 +#define CONTEXT_EIP 0xB8 +#define CONTEXT_ESP 0xC4 +#define CONTEXT_FLOAT_SAVE_CONTROL_WORD CONTEXT_FLOAT_SAVE + FN_CONTROL_WORD +#define CONTEXT_FLOAT_SAVE_STATUS_WORD CONTEXT_FLOAT_SAVE + FN_STATUS_WORD +#define CONTEXT_FLOAT_SAVE_TAG_WORD CONTEXT_FLOAT_SAVE + FN_TAG_WORD + +/* TEB CONSTANTS */ +#define TEB_EXCEPTION_LIST 0x0 +#define TEB_STACK_BASE 0x4 +#define TEB_STACK_LIMIT 0x8 +#define TEB_FIBER_DATA 0x10 +#define TEB_ACTIVATION_CONTEXT_STACK_POINTER 0x1A8 +#define TEB_DEALLOCATION_STACK 0xE0C +#define TEB_GUARANTEED_STACK_BYTES 0xF78 +#define TEB_FLS_DATA 0xFB4 + +/* FIBER CONSTANTS */ +#define FIBER_PARAMETER 0x0 +#define FIBER_EXCEPTION_LIST 0x4 +#define FIBER_STACK_BASE 0x8 +#define FIBER_STACK_LIMIT 0xC +#define FIBER_DEALLOCATION_STACK 0x10 +#define FIBER_CONTEXT 0x14 +#define FIBER_GUARANTEED_STACK_BYTES 0x2E0 +#define FIBER_FLS_DATA 0x2E4 +#define FIBER_ACTIVATION_CONTEXT_STACK 0x2E8 +#define FIBER_CONTEXT_FLAGS FIBER_CONTEXT + CONTEXT_FLAGS +#define FIBER_CONTEXT_EAX FIBER_CONTEXT + CONTEXT_EAX +#define FIBER_CONTEXT_EBX FIBER_CONTEXT + CONTEXT_EBX +#define FIBER_CONTEXT_ECX FIBER_CONTEXT + CONTEXT_ECX +#define FIBER_CONTEXT_EDX FIBER_CONTEXT + CONTEXT_EDX +#define FIBER_CONTEXT_ESI FIBER_CONTEXT + CONTEXT_ESI +#define FIBER_CONTEXT_EDI FIBER_CONTEXT + CONTEXT_EDI +#define FIBER_CONTEXT_EBP FIBER_CONTEXT + CONTEXT_EBP +#define FIBER_CONTEXT_ESP FIBER_CONTEXT + CONTEXT_ESP +#define FIBER_CONTEXT_DR6 FIBER_CONTEXT + CONTEXT_DR6 +#define FIBER_CONTEXT_FLOAT_SAVE_STATUS_WORD FIBER_CONTEXT + CONTEXT_FLOAT_SAVE_STATUS_WORD +#define FIBER_CONTEXT_FLOAT_SAVE_CONTROL_WORD FIBER_CONTEXT + CONTEXT_FLOAT_SAVE_CONTROL_WORD +#define FIBER_CONTEXT_FLOAT_SAVE_TAG_WORD FIBER_CONTEXT + CONTEXT_FLOAT_SAVE_TAG_WORD +#endif + diff --git a/reactos/include/ndk/i386/floatsave.h b/reactos/include/ndk/i386/floatsave.h index f0f7f53f72e..833f1ffc423 100644 --- a/reactos/include/ndk/i386/floatsave.h +++ b/reactos/include/ndk/i386/floatsave.h @@ -1,11 +1,11 @@ -#ifndef _FLOATSAVE_H_ -#define _FLOATSAVE_H_ - -#define FLOAT_SAVE_CONTROL (0xFFFF037F) -#define FLOAT_SAVE_STATUS (0xFFFF0000) -#define FLOAT_SAVE_TAG (0xFFFFFFFF) -#define FLOAT_SAVE_DATA (0xFFFF0000) - -#endif /* __NAPI_I386_FLOATSAVE_H__ */ - -/* EOF */ +#ifndef _FLOATSAVE_H_ +#define _FLOATSAVE_H_ + +#define FLOAT_SAVE_CONTROL (0xFFFF037F) +#define FLOAT_SAVE_STATUS (0xFFFF0000) +#define FLOAT_SAVE_TAG (0xFFFFFFFF) +#define FLOAT_SAVE_DATA (0xFFFF0000) + +#endif /* __NAPI_I386_FLOATSAVE_H__ */ + +/* EOF */ diff --git a/reactos/include/ndk/i386/ketypes.h b/reactos/include/ndk/i386/ketypes.h index 70e2e4cc2a5..294337a0bb6 100644 --- a/reactos/include/ndk/i386/ketypes.h +++ b/reactos/include/ndk/i386/ketypes.h @@ -1,515 +1,515 @@ -/* - * PROJECT: ReactOS Native Headers - * FILE: include/ndk/i386/ketypes.h - * PURPOSE: I386-specific definitions for Kernel Types not defined in DDK/IFS - * PROGRAMMER: Alex Ionescu (alex@relsoft.net) - * UPDATE HISTORY: - * Created 06/10/04 - */ -#ifndef _I386_KETYPES_H -#define _I386_KETYPES_H - -/* DEPENDENCIES **************************************************************/ - -/* CONSTANTS *****************************************************************/ - -/* X86 80386 Segment Types */ -#define I386_TSS 0x9 -#define I386_ACTIVE_TSS 0xB -#define I386_CALL_GATE 0xC -#define I386_INTERRUPT_GATE 0xE -#define I386_TRAP_GATE 0xF - -/* EXPORTED DATA *************************************************************/ - -/* ENUMERATIONS **************************************************************/ - -/* TYPES *********************************************************************/ - -typedef struct _FNSAVE_FORMAT -{ - ULONG ControlWord; - ULONG StatusWord; - ULONG TagWord; - ULONG ErrorOffset; - ULONG ErrorSelector; - ULONG DataOffset; - ULONG DataSelector; - UCHAR RegisterArea[80]; -} FNSAVE_FORMAT, *PFNSAVE_FORMAT; - -typedef struct _FXSAVE_FORMAT -{ - USHORT ControlWord; - USHORT StatusWord; - USHORT TagWord; - USHORT ErrorOpcode; - ULONG ErrorOffset; - ULONG ErrorSelector; - ULONG DataOffset; - ULONG DataSelector; - ULONG MXCsr; - ULONG MXCsrMask; - UCHAR RegisterArea[128]; - UCHAR Reserved3[128]; - UCHAR Reserved4[224]; - UCHAR Align16Byte[8]; -} FXSAVE_FORMAT, *PFXSAVE_FORMAT; - -typedef struct _FX_SAVE_AREA -{ - union - { - FNSAVE_FORMAT FnArea; - FXSAVE_FORMAT FxArea; - } U; - ULONG NpxSavedCpu; - ULONG Cr0NpxState; -} FX_SAVE_AREA, *PFX_SAVE_AREA; - -typedef struct _KTRAP_FRAME -{ - PVOID DebugEbp; - PVOID DebugEip; - PVOID DebugArgMark; - PVOID DebugPointer; - PVOID TempCs; - PVOID TempEip; - ULONG Dr0; - ULONG Dr1; - ULONG Dr2; - ULONG Dr3; - ULONG Dr6; - ULONG Dr7; - USHORT Gs; - USHORT Reserved1; - USHORT Es; - USHORT Reserved2; - USHORT Ds; - USHORT Reserved3; - ULONG Edx; - ULONG Ecx; - ULONG Eax; - ULONG PreviousMode; - PVOID ExceptionList; - USHORT Fs; - USHORT Reserved4; - ULONG Edi; - ULONG Esi; - ULONG Ebx; - ULONG Ebp; - ULONG ErrorCode; - ULONG Eip; - ULONG Cs; - ULONG Eflags; - ULONG Esp; - USHORT Ss; - USHORT Reserved5; - USHORT V86_Es; - USHORT Reserved6; - USHORT V86_Ds; - USHORT Reserved7; - USHORT V86_Fs; - USHORT Reserved8; - USHORT V86_Gs; - USHORT Reserved9; -} KTRAP_FRAME, *PKTRAP_FRAME; - -typedef struct _LDT_ENTRY -{ - WORD LimitLow; - WORD BaseLow; - union - { - struct - { - BYTE BaseMid; - BYTE Flags1; - BYTE Flags2; - BYTE BaseHi; - } Bytes; - struct - { - DWORD BaseMid : 8; - DWORD Type : 5; - DWORD Dpl : 2; - DWORD Pres : 1; - DWORD LimitHi : 4; - DWORD Sys : 1; - DWORD Reserved_0 : 1; - DWORD Default_Big : 1; - DWORD Granularity : 1; - DWORD BaseHi : 8; - } Bits; - } HighWord; -} LDT_ENTRY, *PLDT_ENTRY, *LPLDT_ENTRY; - -typedef struct _KGDTENTRY -{ - USHORT LimitLow; - USHORT BaseLow; - union - { - struct - { - UCHAR BaseMid; - UCHAR Flags1; - UCHAR Flags2; - UCHAR BaseHi; - } Bytes; - struct - { - ULONG BaseMid : 8; - ULONG Type : 5; - ULONG Dpl : 2; - ULONG Pres : 1; - ULONG LimitHi : 4; - ULONG Sys : 1; - ULONG Reserved_0 : 1; - ULONG Default_Big : 1; - ULONG Granularity : 1; - ULONG BaseHi : 8; - } Bits; - } HighWord; -} KGDTENTRY, *PKGDTENTRY; - -typedef struct _KIDT_ACCESS -{ - union - { - struct - { - UCHAR Reserved; - UCHAR SegmentType:4; - UCHAR SystemSegmentFlag:1; - UCHAR Dpl:2; - UCHAR Present:1; - }; - USHORT Value; - }; -} KIDT_ACCESS, *PKIDT_ACCESS; - -typedef struct _KIDTENTRY -{ - USHORT Offset; - USHORT Selector; - USHORT Access; - USHORT ExtendedOffset; -} KIDTENTRY, *PKIDTENTRY; - -typedef struct _HARDWARE_PTE_X86 -{ - ULONG Valid : 1; - ULONG Write : 1; - ULONG Owner : 1; - ULONG WriteThrough : 1; - ULONG CacheDisable : 1; - ULONG Accessed : 1; - ULONG Dirty : 1; - ULONG LargePage : 1; - ULONG Global : 1; - ULONG CopyOnWrite : 1; - ULONG Prototype : 1; - ULONG reserved : 1; - ULONG PageFrameNumber : 20; -} HARDWARE_PTE_X86, *PHARDWARE_PTE_X86; - -typedef struct _DESCRIPTOR -{ - WORD Pad; - WORD Limit; - DWORD Base; -} KDESCRIPTOR, *PKDESCRIPTOR; - -typedef struct _KSPECIAL_REGISTERS -{ - DWORD Cr0; - DWORD Cr2; - DWORD Cr3; - DWORD Cr4; - DWORD KernelDr0; - DWORD KernelDr1; - DWORD KernelDr2; - DWORD KernelDr3; - DWORD KernelDr6; - DWORD KernelDr7; - KDESCRIPTOR Gdtr; - KDESCRIPTOR Idtr; - WORD Tr; - WORD Ldtr; - DWORD Reserved[6]; -} KSPECIAL_REGISTERS, *PKSPECIAL_REGISTERS; - -#pragma pack(push,4) - -typedef struct _KPROCESSOR_STATE -{ - PCONTEXT ContextFrame; - KSPECIAL_REGISTERS SpecialRegisters; -} KPROCESSOR_STATE; - -/* Processor Control Block */ -typedef struct _KPRCB -{ - USHORT MinorVersion; - USHORT MajorVersion; - struct _KTHREAD *CurrentThread; - struct _KTHREAD *NextThread; - struct _KTHREAD *IdleThread; - UCHAR Number; - UCHAR Reserved; - USHORT BuildType; - KAFFINITY SetMember; - UCHAR CpuType; - UCHAR CpuID; - USHORT CpuStep; - KPROCESSOR_STATE ProcessorState; - ULONG KernelReserved[16]; - ULONG HalReserved[16]; - UCHAR PrcbPad0[92]; - PVOID LockQueue[33]; // Used for Queued Spinlocks - struct _KTHREAD *NpxThread; - ULONG InterruptCount; - ULONG KernelTime; - ULONG UserTime; - ULONG DpcTime; - ULONG DebugDpcTime; - ULONG InterruptTime; - ULONG AdjustDpcThreshold; - ULONG PageColor; - UCHAR SkipTick; - UCHAR DebuggerSavedIRQL; - UCHAR Spare1[6]; - struct _KNODE *ParentNode; - ULONG MultiThreadProcessorSet; - struct _KPRCB *MultiThreadSetMaster; - ULONG ThreadStartCount[2]; - ULONG CcFastReadNoWait; - ULONG CcFastReadWait; - ULONG CcFastReadNotPossible; - ULONG CcCopyReadNoWait; - ULONG CcCopyReadWait; - ULONG CcCopyReadNoWaitMiss; - ULONG KeAlignmentFixupCount; - ULONG KeContextSwitches; - ULONG KeDcacheFlushCount; - ULONG KeExceptionDispatchCount; - ULONG KeFirstLevelTbFills; - ULONG KeFloatingEmulationCount; - ULONG KeIcacheFlushCount; - ULONG KeSecondLevelTbFills; - ULONG KeSystemCalls; - ULONG IoReadOperationCount; - ULONG IoWriteOperationCount; - ULONG IoOtherOperationCount; - LARGE_INTEGER IoReadTransferCount; - LARGE_INTEGER IoWriteTransferCount; - LARGE_INTEGER IoOtherTransferCount; - ULONG SpareCounter1[8]; - PP_LOOKASIDE_LIST PPLookasideList[16]; - PP_LOOKASIDE_LIST PPNPagedLookasideList[32]; - PP_LOOKASIDE_LIST PPPagedLookasideList[32]; - ULONG PacketBarrier; - ULONG ReverseStall; - PVOID IpiFrame; - UCHAR PrcbPad2[52]; - PVOID CurrentPacket[3]; - ULONG TargetSet; - ULONG_PTR WorkerRoutine; - ULONG IpiFrozen; - UCHAR PrcbPad3[40]; - ULONG RequestSummary; - struct _KPRCB *SignalDone; - UCHAR PrcbPad4[56]; - struct _KDPC_DATA DpcData[2]; - PVOID DpcStack; - ULONG MaximumDpcQueueDepth; - ULONG DpcRequestRate; - ULONG MinimumDpcRate; - UCHAR DpcInterruptRequested; - UCHAR DpcThreadRequested; - UCHAR DpcRoutineActive; - UCHAR DpcThreadActive; - ULONG PrcbLock; - ULONG DpcLastCount; - ULONG TimerHand; - ULONG TimerRequest; - PVOID DpcThread; - struct _KEVENT *DpcEvent; - UCHAR ThreadDpcEnable; - BOOLEAN QuantumEnd; - UCHAR PrcbPad50; - UCHAR IdleSchedule; - ULONG DpcSetEventRequest; - UCHAR PrcbPad5[18]; - LONG TickOffset; - struct _KDPC* CallDpc; - ULONG PrcbPad7[8]; - LIST_ENTRY WaitListHead; - ULONG ReadySummary; - ULONG SelectNextLast; - LIST_ENTRY DispatcherReadyListHead[32]; - SINGLE_LIST_ENTRY DeferredReadyListHead; - ULONG PrcbPad72[11]; - PVOID ChainedInterruptList; - LONG LookasideIrpFloat; - LONG MmPageFaultCount; - LONG MmCopyOnWriteCount; - LONG MmTransitionCount; - LONG MmCacheTransitionCount; - LONG MmDemandZeroCount; - LONG MmPageReadCount; - LONG MmPageReadIoCount; - LONG MmCacheReadCount; - LONG MmCacheIoCount; - LONG MmDirtyPagesWriteCount; - LONG MmDirtyWriteIoCount; - LONG MmMappedPagesWriteCount; - LONG MmMappedWriteIoCount; - ULONG SpareFields0[1]; - CHAR VendorString[13]; - UCHAR InitialApicId; - UCHAR LogicalProcessorsPerPhysicalProcessor; - ULONG MHz; - ULONG FeatureBits; - LARGE_INTEGER UpdateSignature; - LARGE_INTEGER IsrTime; - LARGE_INTEGER SpareField1; - FX_SAVE_AREA NpxSaveArea; - PROCESSOR_POWER_STATE PowerState; -} KPRCB, *PKPRCB; - -/* - * This is the complete, internal KPCR structure - */ -typedef struct _KIPCR -{ - KPCR_TIB Tib; /* 00 */ - struct _KPCR *Self; /* 1C */ - struct _KPRCB *Prcb; /* 20 */ - KIRQL Irql; /* 24 */ - ULONG IRR; /* 28 */ - ULONG IrrActive; /* 2C */ - ULONG IDR; /* 30 */ - PVOID KdVersionBlock; /* 34 */ - PUSHORT IDT; /* 38 */ - PUSHORT GDT; /* 3C */ - struct _KTSS *TSS; /* 40 */ - USHORT MajorVersion; /* 44 */ - USHORT MinorVersion; /* 46 */ - KAFFINITY SetMember; /* 48 */ - ULONG StallScaleFactor; /* 4C */ - UCHAR SparedUnused; /* 50 */ - UCHAR Number; /* 51 */ - UCHAR Reserved; /* 52 */ - UCHAR L2CacheAssociativity; /* 53 */ - ULONG VdmAlert; /* 54 */ - ULONG KernelReserved[14]; /* 58 */ - ULONG L2CacheSize; /* 90 */ - ULONG HalReserved[16]; /* 94 */ - ULONG InterruptMode; /* D4 */ - UCHAR KernelReserved2[0x48]; /* D8 */ - KPRCB PrcbData; /* 120 */ -} KIPCR, *PKIPCR; - -#pragma pack(pop) - -#include - -typedef struct _KTSSNOIOPM -{ - USHORT PreviousTask; - USHORT Reserved1; - ULONG Esp0; - USHORT Ss0; - USHORT Reserved2; - ULONG Esp1; - USHORT Ss1; - USHORT Reserved3; - ULONG Esp2; - USHORT Ss2; - USHORT Reserved4; - ULONG Cr3; - ULONG Eip; - ULONG Eflags; - ULONG Eax; - ULONG Ecx; - ULONG Edx; - ULONG Ebx; - ULONG Esp; - ULONG Ebp; - ULONG Esi; - ULONG Edi; - USHORT Es; - USHORT Reserved5; - USHORT Cs; - USHORT Reserved6; - USHORT Ss; - USHORT Reserved7; - USHORT Ds; - USHORT Reserved8; - USHORT Fs; - USHORT Reserved9; - USHORT Gs; - USHORT Reserved10; - USHORT Ldt; - USHORT Reserved11; - USHORT Trap; - USHORT IoMapBase; - /* no interrupt redirection map */ - UCHAR IoBitmap[1]; -} KTSSNOIOPM; - -typedef struct _KTSS -{ - USHORT PreviousTask; - USHORT Reserved1; - ULONG Esp0; - USHORT Ss0; - USHORT Reserved2; - ULONG Esp1; - USHORT Ss1; - USHORT Reserved3; - ULONG Esp2; - USHORT Ss2; - USHORT Reserved4; - ULONG Cr3; - ULONG Eip; - ULONG Eflags; - ULONG Eax; - ULONG Ecx; - ULONG Edx; - ULONG Ebx; - ULONG Esp; - ULONG Ebp; - ULONG Esi; - ULONG Edi; - USHORT Es; - USHORT Reserved5; - USHORT Cs; - USHORT Reserved6; - USHORT Ss; - USHORT Reserved7; - USHORT Ds; - USHORT Reserved8; - USHORT Fs; - USHORT Reserved9; - USHORT Gs; - USHORT Reserved10; - USHORT Ldt; - USHORT Reserved11; - USHORT Trap; - USHORT IoMapBase; - /* no interrupt redirection map */ - UCHAR IoBitmap[8193]; -} KTSS; - -#include - -/* i386 Doesn't have Exception Frames */ -typedef struct _KEXCEPTION_FRAME -{ - -} KEXCEPTION_FRAME, *PKEXCEPTION_FRAME; - -#endif +/* + * PROJECT: ReactOS Native Headers + * FILE: include/ndk/i386/ketypes.h + * PURPOSE: I386-specific definitions for Kernel Types not defined in DDK/IFS + * PROGRAMMER: Alex Ionescu (alex@relsoft.net) + * UPDATE HISTORY: + * Created 06/10/04 + */ +#ifndef _I386_KETYPES_H +#define _I386_KETYPES_H + +/* DEPENDENCIES **************************************************************/ + +/* CONSTANTS *****************************************************************/ + +/* X86 80386 Segment Types */ +#define I386_TSS 0x9 +#define I386_ACTIVE_TSS 0xB +#define I386_CALL_GATE 0xC +#define I386_INTERRUPT_GATE 0xE +#define I386_TRAP_GATE 0xF + +/* EXPORTED DATA *************************************************************/ + +/* ENUMERATIONS **************************************************************/ + +/* TYPES *********************************************************************/ + +typedef struct _FNSAVE_FORMAT +{ + ULONG ControlWord; + ULONG StatusWord; + ULONG TagWord; + ULONG ErrorOffset; + ULONG ErrorSelector; + ULONG DataOffset; + ULONG DataSelector; + UCHAR RegisterArea[80]; +} FNSAVE_FORMAT, *PFNSAVE_FORMAT; + +typedef struct _FXSAVE_FORMAT +{ + USHORT ControlWord; + USHORT StatusWord; + USHORT TagWord; + USHORT ErrorOpcode; + ULONG ErrorOffset; + ULONG ErrorSelector; + ULONG DataOffset; + ULONG DataSelector; + ULONG MXCsr; + ULONG MXCsrMask; + UCHAR RegisterArea[128]; + UCHAR Reserved3[128]; + UCHAR Reserved4[224]; + UCHAR Align16Byte[8]; +} FXSAVE_FORMAT, *PFXSAVE_FORMAT; + +typedef struct _FX_SAVE_AREA +{ + union + { + FNSAVE_FORMAT FnArea; + FXSAVE_FORMAT FxArea; + } U; + ULONG NpxSavedCpu; + ULONG Cr0NpxState; +} FX_SAVE_AREA, *PFX_SAVE_AREA; + +typedef struct _KTRAP_FRAME +{ + PVOID DebugEbp; + PVOID DebugEip; + PVOID DebugArgMark; + PVOID DebugPointer; + PVOID TempCs; + PVOID TempEip; + ULONG Dr0; + ULONG Dr1; + ULONG Dr2; + ULONG Dr3; + ULONG Dr6; + ULONG Dr7; + USHORT Gs; + USHORT Reserved1; + USHORT Es; + USHORT Reserved2; + USHORT Ds; + USHORT Reserved3; + ULONG Edx; + ULONG Ecx; + ULONG Eax; + ULONG PreviousMode; + PVOID ExceptionList; + USHORT Fs; + USHORT Reserved4; + ULONG Edi; + ULONG Esi; + ULONG Ebx; + ULONG Ebp; + ULONG ErrorCode; + ULONG Eip; + ULONG Cs; + ULONG Eflags; + ULONG Esp; + USHORT Ss; + USHORT Reserved5; + USHORT V86_Es; + USHORT Reserved6; + USHORT V86_Ds; + USHORT Reserved7; + USHORT V86_Fs; + USHORT Reserved8; + USHORT V86_Gs; + USHORT Reserved9; +} KTRAP_FRAME, *PKTRAP_FRAME; + +typedef struct _LDT_ENTRY +{ + WORD LimitLow; + WORD BaseLow; + union + { + struct + { + BYTE BaseMid; + BYTE Flags1; + BYTE Flags2; + BYTE BaseHi; + } Bytes; + struct + { + DWORD BaseMid : 8; + DWORD Type : 5; + DWORD Dpl : 2; + DWORD Pres : 1; + DWORD LimitHi : 4; + DWORD Sys : 1; + DWORD Reserved_0 : 1; + DWORD Default_Big : 1; + DWORD Granularity : 1; + DWORD BaseHi : 8; + } Bits; + } HighWord; +} LDT_ENTRY, *PLDT_ENTRY, *LPLDT_ENTRY; + +typedef struct _KGDTENTRY +{ + USHORT LimitLow; + USHORT BaseLow; + union + { + struct + { + UCHAR BaseMid; + UCHAR Flags1; + UCHAR Flags2; + UCHAR BaseHi; + } Bytes; + struct + { + ULONG BaseMid : 8; + ULONG Type : 5; + ULONG Dpl : 2; + ULONG Pres : 1; + ULONG LimitHi : 4; + ULONG Sys : 1; + ULONG Reserved_0 : 1; + ULONG Default_Big : 1; + ULONG Granularity : 1; + ULONG BaseHi : 8; + } Bits; + } HighWord; +} KGDTENTRY, *PKGDTENTRY; + +typedef struct _KIDT_ACCESS +{ + union + { + struct + { + UCHAR Reserved; + UCHAR SegmentType:4; + UCHAR SystemSegmentFlag:1; + UCHAR Dpl:2; + UCHAR Present:1; + }; + USHORT Value; + }; +} KIDT_ACCESS, *PKIDT_ACCESS; + +typedef struct _KIDTENTRY +{ + USHORT Offset; + USHORT Selector; + USHORT Access; + USHORT ExtendedOffset; +} KIDTENTRY, *PKIDTENTRY; + +typedef struct _HARDWARE_PTE_X86 +{ + ULONG Valid : 1; + ULONG Write : 1; + ULONG Owner : 1; + ULONG WriteThrough : 1; + ULONG CacheDisable : 1; + ULONG Accessed : 1; + ULONG Dirty : 1; + ULONG LargePage : 1; + ULONG Global : 1; + ULONG CopyOnWrite : 1; + ULONG Prototype : 1; + ULONG reserved : 1; + ULONG PageFrameNumber : 20; +} HARDWARE_PTE_X86, *PHARDWARE_PTE_X86; + +typedef struct _DESCRIPTOR +{ + WORD Pad; + WORD Limit; + DWORD Base; +} KDESCRIPTOR, *PKDESCRIPTOR; + +typedef struct _KSPECIAL_REGISTERS +{ + DWORD Cr0; + DWORD Cr2; + DWORD Cr3; + DWORD Cr4; + DWORD KernelDr0; + DWORD KernelDr1; + DWORD KernelDr2; + DWORD KernelDr3; + DWORD KernelDr6; + DWORD KernelDr7; + KDESCRIPTOR Gdtr; + KDESCRIPTOR Idtr; + WORD Tr; + WORD Ldtr; + DWORD Reserved[6]; +} KSPECIAL_REGISTERS, *PKSPECIAL_REGISTERS; + +#pragma pack(push,4) + +typedef struct _KPROCESSOR_STATE +{ + PCONTEXT ContextFrame; + KSPECIAL_REGISTERS SpecialRegisters; +} KPROCESSOR_STATE; + +/* Processor Control Block */ +typedef struct _KPRCB +{ + USHORT MinorVersion; + USHORT MajorVersion; + struct _KTHREAD *CurrentThread; + struct _KTHREAD *NextThread; + struct _KTHREAD *IdleThread; + UCHAR Number; + UCHAR Reserved; + USHORT BuildType; + KAFFINITY SetMember; + UCHAR CpuType; + UCHAR CpuID; + USHORT CpuStep; + KPROCESSOR_STATE ProcessorState; + ULONG KernelReserved[16]; + ULONG HalReserved[16]; + UCHAR PrcbPad0[92]; + PVOID LockQueue[33]; // Used for Queued Spinlocks + struct _KTHREAD *NpxThread; + ULONG InterruptCount; + ULONG KernelTime; + ULONG UserTime; + ULONG DpcTime; + ULONG DebugDpcTime; + ULONG InterruptTime; + ULONG AdjustDpcThreshold; + ULONG PageColor; + UCHAR SkipTick; + UCHAR DebuggerSavedIRQL; + UCHAR Spare1[6]; + struct _KNODE *ParentNode; + ULONG MultiThreadProcessorSet; + struct _KPRCB *MultiThreadSetMaster; + ULONG ThreadStartCount[2]; + ULONG CcFastReadNoWait; + ULONG CcFastReadWait; + ULONG CcFastReadNotPossible; + ULONG CcCopyReadNoWait; + ULONG CcCopyReadWait; + ULONG CcCopyReadNoWaitMiss; + ULONG KeAlignmentFixupCount; + ULONG KeContextSwitches; + ULONG KeDcacheFlushCount; + ULONG KeExceptionDispatchCount; + ULONG KeFirstLevelTbFills; + ULONG KeFloatingEmulationCount; + ULONG KeIcacheFlushCount; + ULONG KeSecondLevelTbFills; + ULONG KeSystemCalls; + ULONG IoReadOperationCount; + ULONG IoWriteOperationCount; + ULONG IoOtherOperationCount; + LARGE_INTEGER IoReadTransferCount; + LARGE_INTEGER IoWriteTransferCount; + LARGE_INTEGER IoOtherTransferCount; + ULONG SpareCounter1[8]; + PP_LOOKASIDE_LIST PPLookasideList[16]; + PP_LOOKASIDE_LIST PPNPagedLookasideList[32]; + PP_LOOKASIDE_LIST PPPagedLookasideList[32]; + ULONG PacketBarrier; + ULONG ReverseStall; + PVOID IpiFrame; + UCHAR PrcbPad2[52]; + PVOID CurrentPacket[3]; + ULONG TargetSet; + ULONG_PTR WorkerRoutine; + ULONG IpiFrozen; + UCHAR PrcbPad3[40]; + ULONG RequestSummary; + struct _KPRCB *SignalDone; + UCHAR PrcbPad4[56]; + struct _KDPC_DATA DpcData[2]; + PVOID DpcStack; + ULONG MaximumDpcQueueDepth; + ULONG DpcRequestRate; + ULONG MinimumDpcRate; + UCHAR DpcInterruptRequested; + UCHAR DpcThreadRequested; + UCHAR DpcRoutineActive; + UCHAR DpcThreadActive; + ULONG PrcbLock; + ULONG DpcLastCount; + ULONG TimerHand; + ULONG TimerRequest; + PVOID DpcThread; + struct _KEVENT *DpcEvent; + UCHAR ThreadDpcEnable; + BOOLEAN QuantumEnd; + UCHAR PrcbPad50; + UCHAR IdleSchedule; + ULONG DpcSetEventRequest; + UCHAR PrcbPad5[18]; + LONG TickOffset; + struct _KDPC* CallDpc; + ULONG PrcbPad7[8]; + LIST_ENTRY WaitListHead; + ULONG ReadySummary; + ULONG SelectNextLast; + LIST_ENTRY DispatcherReadyListHead[32]; + SINGLE_LIST_ENTRY DeferredReadyListHead; + ULONG PrcbPad72[11]; + PVOID ChainedInterruptList; + LONG LookasideIrpFloat; + LONG MmPageFaultCount; + LONG MmCopyOnWriteCount; + LONG MmTransitionCount; + LONG MmCacheTransitionCount; + LONG MmDemandZeroCount; + LONG MmPageReadCount; + LONG MmPageReadIoCount; + LONG MmCacheReadCount; + LONG MmCacheIoCount; + LONG MmDirtyPagesWriteCount; + LONG MmDirtyWriteIoCount; + LONG MmMappedPagesWriteCount; + LONG MmMappedWriteIoCount; + ULONG SpareFields0[1]; + CHAR VendorString[13]; + UCHAR InitialApicId; + UCHAR LogicalProcessorsPerPhysicalProcessor; + ULONG MHz; + ULONG FeatureBits; + LARGE_INTEGER UpdateSignature; + LARGE_INTEGER IsrTime; + LARGE_INTEGER SpareField1; + FX_SAVE_AREA NpxSaveArea; + PROCESSOR_POWER_STATE PowerState; +} KPRCB, *PKPRCB; + +/* + * This is the complete, internal KPCR structure + */ +typedef struct _KIPCR +{ + KPCR_TIB Tib; /* 00 */ + struct _KPCR *Self; /* 1C */ + struct _KPRCB *Prcb; /* 20 */ + KIRQL Irql; /* 24 */ + ULONG IRR; /* 28 */ + ULONG IrrActive; /* 2C */ + ULONG IDR; /* 30 */ + PVOID KdVersionBlock; /* 34 */ + PUSHORT IDT; /* 38 */ + PUSHORT GDT; /* 3C */ + struct _KTSS *TSS; /* 40 */ + USHORT MajorVersion; /* 44 */ + USHORT MinorVersion; /* 46 */ + KAFFINITY SetMember; /* 48 */ + ULONG StallScaleFactor; /* 4C */ + UCHAR SparedUnused; /* 50 */ + UCHAR Number; /* 51 */ + UCHAR Reserved; /* 52 */ + UCHAR L2CacheAssociativity; /* 53 */ + ULONG VdmAlert; /* 54 */ + ULONG KernelReserved[14]; /* 58 */ + ULONG L2CacheSize; /* 90 */ + ULONG HalReserved[16]; /* 94 */ + ULONG InterruptMode; /* D4 */ + UCHAR KernelReserved2[0x48]; /* D8 */ + KPRCB PrcbData; /* 120 */ +} KIPCR, *PKIPCR; + +#pragma pack(pop) + +#include + +typedef struct _KTSSNOIOPM +{ + USHORT PreviousTask; + USHORT Reserved1; + ULONG Esp0; + USHORT Ss0; + USHORT Reserved2; + ULONG Esp1; + USHORT Ss1; + USHORT Reserved3; + ULONG Esp2; + USHORT Ss2; + USHORT Reserved4; + ULONG Cr3; + ULONG Eip; + ULONG Eflags; + ULONG Eax; + ULONG Ecx; + ULONG Edx; + ULONG Ebx; + ULONG Esp; + ULONG Ebp; + ULONG Esi; + ULONG Edi; + USHORT Es; + USHORT Reserved5; + USHORT Cs; + USHORT Reserved6; + USHORT Ss; + USHORT Reserved7; + USHORT Ds; + USHORT Reserved8; + USHORT Fs; + USHORT Reserved9; + USHORT Gs; + USHORT Reserved10; + USHORT Ldt; + USHORT Reserved11; + USHORT Trap; + USHORT IoMapBase; + /* no interrupt redirection map */ + UCHAR IoBitmap[1]; +} KTSSNOIOPM; + +typedef struct _KTSS +{ + USHORT PreviousTask; + USHORT Reserved1; + ULONG Esp0; + USHORT Ss0; + USHORT Reserved2; + ULONG Esp1; + USHORT Ss1; + USHORT Reserved3; + ULONG Esp2; + USHORT Ss2; + USHORT Reserved4; + ULONG Cr3; + ULONG Eip; + ULONG Eflags; + ULONG Eax; + ULONG Ecx; + ULONG Edx; + ULONG Ebx; + ULONG Esp; + ULONG Ebp; + ULONG Esi; + ULONG Edi; + USHORT Es; + USHORT Reserved5; + USHORT Cs; + USHORT Reserved6; + USHORT Ss; + USHORT Reserved7; + USHORT Ds; + USHORT Reserved8; + USHORT Fs; + USHORT Reserved9; + USHORT Gs; + USHORT Reserved10; + USHORT Ldt; + USHORT Reserved11; + USHORT Trap; + USHORT IoMapBase; + /* no interrupt redirection map */ + UCHAR IoBitmap[8193]; +} KTSS; + +#include + +/* i386 Doesn't have Exception Frames */ +typedef struct _KEXCEPTION_FRAME +{ + +} KEXCEPTION_FRAME, *PKEXCEPTION_FRAME; + +#endif diff --git a/reactos/include/ndk/i386/mmtypes.h b/reactos/include/ndk/i386/mmtypes.h index 77196da1a1a..d39544a94b9 100644 --- a/reactos/include/ndk/i386/mmtypes.h +++ b/reactos/include/ndk/i386/mmtypes.h @@ -1,12 +1,12 @@ -/* - * PROJECT: ReactOS Native Headers - * FILE: include/ndk/i386/mmtypes.h - * PURPOSE: I386-specific definitions for Memory Manager Types not defined in DDK/IFS - * PROGRAMMER: Alex Ionescu (alex@relsoft.net) - * UPDATE HISTORY: - * Created 06/10/04 - */ -#ifndef _I386_MMTYPES_H -#define _I386_MMTYPES_H - -#endif +/* + * PROJECT: ReactOS Native Headers + * FILE: include/ndk/i386/mmtypes.h + * PURPOSE: I386-specific definitions for Memory Manager Types not defined in DDK/IFS + * PROGRAMMER: Alex Ionescu (alex@relsoft.net) + * UPDATE HISTORY: + * Created 06/10/04 + */ +#ifndef _I386_MMTYPES_H +#define _I386_MMTYPES_H + +#endif diff --git a/reactos/include/ndk/i386/segment.h b/reactos/include/ndk/i386/segment.h index 884c52837cc..85f2aee33d2 100644 --- a/reactos/include/ndk/i386/segment.h +++ b/reactos/include/ndk/i386/segment.h @@ -1,14 +1,14 @@ -#ifndef _ASM_SEGMENT_H -#define _ASM_SEGMENT_H - -#define KERNEL_CS (0x8) -#define KERNEL_DS (0x10) -#define USER_CS (0x18 + 0x3) -#define USER_DS (0x20 + 0x3) -#define TSS_SELECTOR (0x28) -#define PCR_SELECTOR (0x30) -#define TEB_SELECTOR (0x38 + 0x3) -#define LDT_SELECTOR (0x48) -#define TRAP_TSS_SELECTOR (0x50) - -#endif /* _ASM_SEGMENT_H */ +#ifndef _ASM_SEGMENT_H +#define _ASM_SEGMENT_H + +#define KERNEL_CS (0x8) +#define KERNEL_DS (0x10) +#define USER_CS (0x18 + 0x3) +#define USER_DS (0x20 + 0x3) +#define TSS_SELECTOR (0x28) +#define PCR_SELECTOR (0x30) +#define TEB_SELECTOR (0x38 + 0x3) +#define LDT_SELECTOR (0x48) +#define TRAP_TSS_SELECTOR (0x50) + +#endif /* _ASM_SEGMENT_H */ diff --git a/reactos/include/ndk/sysguid.h b/reactos/include/ndk/sysguid.h index 7ed5ffc3200..25f55d08be8 100644 --- a/reactos/include/ndk/sysguid.h +++ b/reactos/include/ndk/sysguid.h @@ -1,55 +1,55 @@ -/* - * PROJECT: ReactOS Native Headers - * FILE: include/ndk/sysguid.h - * PURPOSE: GUIDs not defined in DDK/IFS - * PROGRAMMER: Alex Ionescu (alex@relsoft.net) - * UPDATE HISTORY: - * Created 06/10/04 - */ - -#ifndef _SYSGUID_H -#define _SYSGUID_H - -DEFINE_GUID(GUID_DEVICE_STANDBY_VETOED, - 0x03B21C13, 0x18D6, 0x11D3, 0x97, 0xDB, 0x00, 0xA0, 0xC9, 0x40, 0x52, 0x2E); -DEFINE_GUID(GUID_DEVICE_KERNEL_INITIATED_EJECT, - 0x14689B54, 0x0703, 0x11D3, 0x97, 0xD2, 0x00, 0xA0, 0xC9, 0x40, 0x52, 0x2E); -DEFINE_GUID(GUID_DEVICE_THERMAL_ZONE, - 0x4AFA3D51, 0x74A7, 0x11D0, 0xBE, 0x5E, 0x00, 0xA0, 0xC9, 0x06, 0x28, 0x57); -DEFINE_GUID(GUID_DEVICE_SYS_BUTTON, - 0x4AFA3D53, 0x74A7, 0x11D0, 0xBE, 0x5E, 0x00, 0xA0, 0xC9, 0x06, 0x28, 0x57); -DEFINE_GUID(GUID_DEVICE_REMOVAL_VETOED, - 0x60DBD5FA, 0xDDD2, 0x11D2, 0x97, 0xB8, 0x00, 0xA0, 0xC9, 0x40, 0x52, 0x2E); -DEFINE_GUID(GUID_DEVICE_HIBERNATE_VETOED, - 0x61173AD9, 0x194F, 0x11D3, 0x97, 0xDC, 0x00, 0xA0, 0xC9, 0x40, 0x52, 0x2E); -DEFINE_GUID(GUID_DEVICE_BATTERY, - 0x72631E54, 0x78A4, 0x11D0, 0xBC, 0xF7, 0x00, 0xAA, 0x00, 0xB7, 0xB3, 0x2A); -DEFINE_GUID(GUID_DEVICE_SAFE_REMOVAL, - 0x8FBEF967, 0xD6C5, 0x11D2, 0x97, 0xB5, 0x00, 0xA0, 0xC9, 0x40, 0x52, 0x2E); - -DEFINE_GUID(GUID_DEVICE_ARRIVAL, - 0xCB3A4009, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); -DEFINE_GUID(GUID_DEVICE_ENUMERATED, - 0xCB3A400A, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); -DEFINE_GUID(GUID_DEVICE_ENUMERATE_REQUEST, - 0xCB3A400B, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); -DEFINE_GUID(GUID_DEVICE_START_REQUEST, - 0xCB3A400C, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); -DEFINE_GUID(GUID_DEVICE_REMOVE_PENDING, - 0xCB3A400D, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); -DEFINE_GUID(GUID_DEVICE_QUERY_AND_REMOVE, - 0xCB3A400E, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); -DEFINE_GUID(GUID_DEVICE_EJECT, - 0xCB3A400F, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); -DEFINE_GUID(GUID_DEVICE_NOOP, - 0xCB3A4010, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); -DEFINE_GUID(GUID_DEVICE_WARM_EJECT_VETOED, - 0xCBF4C1F9, 0x18D5, 0x11D3, 0x97, 0xDB, 0x00, 0xA0, 0xC9, 0x40, 0x52, 0x2E); -DEFINE_GUID(GUID_DEVICE_SURPRISE_REMOVAL, - 0xCE5AF000, 0x80DD, 0x11D2, 0xA8, 0x8D, 0x00, 0xA0, 0xC9, 0x69, 0x6B, 0x4B); -DEFINE_GUID(GUID_DEVICE_EJECT_VETOED, - 0xCF7B71E8, 0xD8FD, 0x11D2, 0x97, 0xB5, 0x00, 0xA0, 0xC9, 0x40, 0x52, 0x2E); -DEFINE_GUID(GUID_DEVICE_EVENT_RBC, - 0xD0744792, 0xA98E, 0x11D2, 0x91, 0x7A, 0x00, 0xA0, 0xC9, 0x06, 0x8F, 0xF3); - -#endif +/* + * PROJECT: ReactOS Native Headers + * FILE: include/ndk/sysguid.h + * PURPOSE: GUIDs not defined in DDK/IFS + * PROGRAMMER: Alex Ionescu (alex@relsoft.net) + * UPDATE HISTORY: + * Created 06/10/04 + */ + +#ifndef _SYSGUID_H +#define _SYSGUID_H + +DEFINE_GUID(GUID_DEVICE_STANDBY_VETOED, + 0x03B21C13, 0x18D6, 0x11D3, 0x97, 0xDB, 0x00, 0xA0, 0xC9, 0x40, 0x52, 0x2E); +DEFINE_GUID(GUID_DEVICE_KERNEL_INITIATED_EJECT, + 0x14689B54, 0x0703, 0x11D3, 0x97, 0xD2, 0x00, 0xA0, 0xC9, 0x40, 0x52, 0x2E); +DEFINE_GUID(GUID_DEVICE_THERMAL_ZONE, + 0x4AFA3D51, 0x74A7, 0x11D0, 0xBE, 0x5E, 0x00, 0xA0, 0xC9, 0x06, 0x28, 0x57); +DEFINE_GUID(GUID_DEVICE_SYS_BUTTON, + 0x4AFA3D53, 0x74A7, 0x11D0, 0xBE, 0x5E, 0x00, 0xA0, 0xC9, 0x06, 0x28, 0x57); +DEFINE_GUID(GUID_DEVICE_REMOVAL_VETOED, + 0x60DBD5FA, 0xDDD2, 0x11D2, 0x97, 0xB8, 0x00, 0xA0, 0xC9, 0x40, 0x52, 0x2E); +DEFINE_GUID(GUID_DEVICE_HIBERNATE_VETOED, + 0x61173AD9, 0x194F, 0x11D3, 0x97, 0xDC, 0x00, 0xA0, 0xC9, 0x40, 0x52, 0x2E); +DEFINE_GUID(GUID_DEVICE_BATTERY, + 0x72631E54, 0x78A4, 0x11D0, 0xBC, 0xF7, 0x00, 0xAA, 0x00, 0xB7, 0xB3, 0x2A); +DEFINE_GUID(GUID_DEVICE_SAFE_REMOVAL, + 0x8FBEF967, 0xD6C5, 0x11D2, 0x97, 0xB5, 0x00, 0xA0, 0xC9, 0x40, 0x52, 0x2E); + +DEFINE_GUID(GUID_DEVICE_ARRIVAL, + 0xCB3A4009, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); +DEFINE_GUID(GUID_DEVICE_ENUMERATED, + 0xCB3A400A, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); +DEFINE_GUID(GUID_DEVICE_ENUMERATE_REQUEST, + 0xCB3A400B, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); +DEFINE_GUID(GUID_DEVICE_START_REQUEST, + 0xCB3A400C, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); +DEFINE_GUID(GUID_DEVICE_REMOVE_PENDING, + 0xCB3A400D, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); +DEFINE_GUID(GUID_DEVICE_QUERY_AND_REMOVE, + 0xCB3A400E, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); +DEFINE_GUID(GUID_DEVICE_EJECT, + 0xCB3A400F, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); +DEFINE_GUID(GUID_DEVICE_NOOP, + 0xCB3A4010, 0x46F0, 0x11D0, 0xB0, 0x8F, 0x00, 0x60, 0x97, 0x13, 0x05, 0x3F); +DEFINE_GUID(GUID_DEVICE_WARM_EJECT_VETOED, + 0xCBF4C1F9, 0x18D5, 0x11D3, 0x97, 0xDB, 0x00, 0xA0, 0xC9, 0x40, 0x52, 0x2E); +DEFINE_GUID(GUID_DEVICE_SURPRISE_REMOVAL, + 0xCE5AF000, 0x80DD, 0x11D2, 0xA8, 0x8D, 0x00, 0xA0, 0xC9, 0x69, 0x6B, 0x4B); +DEFINE_GUID(GUID_DEVICE_EJECT_VETOED, + 0xCF7B71E8, 0xD8FD, 0x11D2, 0x97, 0xB5, 0x00, 0xA0, 0xC9, 0x40, 0x52, 0x2E); +DEFINE_GUID(GUID_DEVICE_EVENT_RBC, + 0xD0744792, 0xA98E, 0x11D2, 0x91, 0x7A, 0x00, 0xA0, 0xC9, 0x06, 0x8F, 0xF3); + +#endif diff --git a/reactos/include/ndk/umtypes.h b/reactos/include/ndk/umtypes.h index c70bd362e73..85c50968e9e 100644 --- a/reactos/include/ndk/umtypes.h +++ b/reactos/include/ndk/umtypes.h @@ -1,1430 +1,1430 @@ -/* - * PROJECT: ReactOS Native Headers - * FILE: include/ndk/umtypes.h - * PURPOSE: Definitions needed for Native Headers if target is not Kernel-Mode. - * PROGRAMMER: Alex Ionescu (alex@relsoft.net) - * UPDATE HISTORY: - * Created 06/10/04 - */ - -#ifndef _UMTYPES_H -#define _UMTYPES_H - -/* DEPENDENCIES **************************************************************/ -#include -#include -#include -#define STATIC static - -/* EXPORTED DATA *************************************************************/ - -/* CONSTANTS *****************************************************************/ - -/* NTAPI/NTOSAPI Define */ -#define NTAPI __stdcall -#define NTOSAPI -#define FASTCALL __fastcall -#define STDCALL __stdcall - -/* Definitions for Object Creation -- winternl.h */ -#define OBJ_INHERIT 2L -#define OBJ_PERMANENT 16L -#define OBJ_EXCLUSIVE 32L -#define OBJ_CASE_INSENSITIVE 64L -#define OBJ_OPENIF 128L -#define OBJ_OPENLINK 256L -#define OBJ_VALID_ATTRIBUTES 498L -#define InitializeObjectAttributes(p,n,a,r,s) { \ - (p)->Length = sizeof(OBJECT_ATTRIBUTES); \ - (p)->RootDirectory = (r); \ - (p)->Attributes = (a); \ - (p)->ObjectName = (n); \ - (p)->SecurityDescriptor = (s); \ - (p)->SecurityQualityOfService = NULL; \ -} - -/* Native API Return Value Macros */ -#define NT_SUCCESS(x) ((x)>=0) -#define NT_WARNING(x) ((ULONG)(x)>>30==2) -#define NT_ERROR(x) ((ULONG)(x)>>30==3) - -/* Object Access Rights FIXME: Some are in w32api's psdk..,is that normal ?*/ -#define DIRECTORY_QUERY (0x0001) -#define DIRECTORY_TRAVERSE (0x0002) -#define DIRECTORY_CREATE_OBJECT (0x0004) -#define DIRECTORY_CREATE_SUBDIRECTORY (0x0008) -#define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0xF) -#define EVENT_QUERY_STATE (0x0001) -#define SEMAPHORE_QUERY_STATE (0x0001) -#define SYMBOLIC_LINK_QUERY 0x0001 -#define SYMBOLIC_LINK_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x1) - -/* Duplication Flags */ -#define DUPLICATE_SAME_ATTRIBUTES 0x00000004 - -/* I/O Control Codes for communicating with Mailslots */ -#define FSCTL_MAILSLOT_PEEK \ - CTL_CODE(FILE_DEVICE_MAILSLOT, 0, METHOD_NEITHER, FILE_READ_DATA) - -/* I/O Control Codes for communicating with Pipes */ -#define FSCTL_PIPE_ASSIGN_EVENT \ - CTL_CODE(FILE_DEVICE_NAMED_PIPE, 0, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_PIPE_DISCONNECT \ - CTL_CODE(FILE_DEVICE_NAMED_PIPE, 1, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_PIPE_LISTEN \ - CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_PIPE_PEEK \ - CTL_CODE(FILE_DEVICE_NAMED_PIPE, 3, METHOD_BUFFERED, FILE_READ_DATA) -#define FSCTL_PIPE_QUERY_EVENT \ - CTL_CODE(FILE_DEVICE_NAMED_PIPE, 4, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_PIPE_TRANSCEIVE \ - CTL_CODE(FILE_DEVICE_NAMED_PIPE, 5, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA) -#define FSCTL_PIPE_WAIT \ - CTL_CODE(FILE_DEVICE_NAMED_PIPE, 6, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_PIPE_IMPERSONATE \ - CTL_CODE(FILE_DEVICE_NAMED_PIPE, 7, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_PIPE_SET_CLIENT_PROCESS \ - CTL_CODE(FILE_DEVICE_NAMED_PIPE, 8, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_PIPE_QUERY_CLIENT_PROCESS \ - CTL_CODE(FILE_DEVICE_NAMED_PIPE, 9, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define FSCTL_PIPE_INTERNAL_READ \ - CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2045, METHOD_BUFFERED, FILE_READ_DATA) -#define FSCTL_PIPE_INTERNAL_WRITE \ - CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2046, METHOD_BUFFERED, FILE_WRITE_DATA) -#define FSCTL_PIPE_INTERNAL_TRANSCEIVE \ - CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2047, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA) -#define FSCTL_PIPE_INTERNAL_READ_OVFLOW \ - CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2048, METHOD_BUFFERED, FILE_READ_DATA) - -/* I/O Control Codes for Communicating with Tapes */ -#define IOCTL_TAPE_ERASE \ - CTL_CODE(FILE_DEVICE_TAPE, 0, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_TAPE_PREPARE \ - CTL_CODE(FILE_DEVICE_TAPE, 1, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_TAPE_WRITE_MARKS \ - CTL_CODE(FILE_DEVICE_TAPE, 2, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_TAPE_GET_POSITION \ - CTL_CODE(FILE_DEVICE_TAPE, 3, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_TAPE_SET_POSITION \ - CTL_CODE(FILE_DEVICE_TAPE, 4, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_TAPE_GET_DRIVE_PARAMS \ - CTL_CODE(FILE_DEVICE_TAPE, 5, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_TAPE_SET_DRIVE_PARAMS \ - CTL_CODE(FILE_DEVICE_TAPE, 6, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_TAPE_GET_MEDIA_PARAMS \ - CTL_CODE(FILE_DEVICE_TAPE, 7, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_TAPE_SET_MEDIA_PARAMS \ - CTL_CODE(FILE_DEVICE_TAPE, 8, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_TAPE_GET_STATUS \ - CTL_CODE(FILE_DEVICE_TAPE, 9, METHOD_BUFFERED, FILE_READ_ACCESS) -#define IOCTL_TAPE_CREATE_PARTITION \ - CTL_CODE(FILE_DEVICE_TAPE, 10, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -/* Macros for current Process/Thread built-in 'special' ID */ -#define NtCurrentProcess() ( (HANDLE)(LONG_PTR) -1 ) -#define ZwCurrentProcess() NtCurrentProcess() -#define NtCurrentThread() ( (HANDLE)(LONG_PTR) -2 ) -#define ZwCurrentThread() NtCurrentThread() - -/* Kernel Shared Data Constants */ -#define PROCESSOR_FEATURE_MAX 64 -#define SharedUserData ((KUSER_SHARED_DATA * CONST) USER_SHARED_DATA) - -/* Paging Values on x86 */ -#define PAGE_SIZE 0x1000 -#define PAGE_SHIFT 12L - -/* Run-Time Library (RTL) Registry Constants */ -#define RTL_REGISTRY_ABSOLUTE 0 -#define RTL_REGISTRY_SERVICES 1 -#define RTL_REGISTRY_CONTROL 2 -#define RTL_REGISTRY_WINDOWS_NT 3 -#define RTL_REGISTRY_DEVICEMAP 4 -#define RTL_REGISTRY_USER 5 -#define RTL_REGISTRY_MAXIMUM 6 -#define RTL_REGISTRY_HANDLE 0x40000000 -#define RTL_REGISTRY_OPTIONAL 0x80000000 -#define RTL_QUERY_REGISTRY_SUBKEY 0x00000001 -#define RTL_QUERY_REGISTRY_TOPKEY 0x00000002 -#define RTL_QUERY_REGISTRY_REQUIRED 0x00000004 -#define RTL_QUERY_REGISTRY_NOVALUE 0x00000008 -#define RTL_QUERY_REGISTRY_NOEXPAND 0x00000010 -#define RTL_QUERY_REGISTRY_DIRECT 0x00000020 -#define RTL_QUERY_REGISTRY_DELETE 0x00000040 - -/* File Result Flags */ -#define FILE_SUPERSEDED 0x00000000 -#define FILE_OPENED 0x00000001 -#define FILE_CREATED 0x00000002 -#define FILE_OVERWRITTEN 0x00000003 -#define FILE_EXISTS 0x00000004 -#define FILE_DOES_NOT_EXIST 0x00000005 - -/* Pipe Flags */ -#define FILE_PIPE_BYTE_STREAM_MODE 0x00000000 -#define FILE_PIPE_MESSAGE_MODE 0x00000001 -#define FILE_PIPE_QUEUE_OPERATION 0x00000000 -#define FILE_PIPE_COMPLETE_OPERATION 0x00000001 -#define FILE_PIPE_INBOUND 0x00000000 -#define FILE_PIPE_OUTBOUND 0x00000001 -#define FILE_PIPE_FULL_DUPLEX 0x00000002 -#define FILE_PIPE_CLIENT_END 0x00000000 -#define FILE_PIPE_SERVER_END 0x00000001 - -/* File Attributes */ -#define FILE_ATTRIBUTE_VALID_FLAGS 0x00007fb7 -#define FILE_ATTRIBUTE_VALID_SET_FLAGS 0x000031a7 - -/* File Flags */ -#define FILE_SUPERSEDE 0x00000000 -#define FILE_OPEN 0x00000001 -#define FILE_CREATE 0x00000002 -#define FILE_OPEN_IF 0x00000003 -#define FILE_OVERWRITE 0x00000004 -#define FILE_OVERWRITE_IF 0x00000005 -#define FILE_MAXIMUM_DISPOSITION 0x00000005 - -/* File Types */ -#define FILE_DIRECTORY_FILE 0x00000001 -#define FILE_WRITE_THROUGH 0x00000002 -#define FILE_SEQUENTIAL_ONLY 0x00000004 -#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 -#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 -#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 -#define FILE_NON_DIRECTORY_FILE 0x00000040 -#define FILE_CREATE_TREE_CONNECTION 0x00000080 -#define FILE_COMPLETE_IF_OPLOCKED 0x00000100 -#define FILE_NO_EA_KNOWLEDGE 0x00000200 -#define FILE_OPEN_FOR_RECOVERY 0x00000400 -#define FILE_RANDOM_ACCESS 0x00000800 -#define FILE_DELETE_ON_CLOSE 0x00001000 -#define FILE_OPEN_BY_FILE_ID 0x00002000 -#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 -#define FILE_NO_COMPRESSION 0x00008000 -#define FILE_RESERVE_OPFILTER 0x00100000 -#define FILE_OPEN_REPARSE_POINT 0x00200000 -#define FILE_OPEN_NO_RECALL 0x00400000 -#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 - -/* Device Charactertics */ -#define FILE_REMOVABLE_MEDIA 0x00000001 -#define FILE_REMOTE_DEVICE 0x00000010 - -/* Version Constants */ -#define VER_MINORVERSION 0x0000001 -#define VER_MAJORVERSION 0x0000002 -#define VER_BUILDNUMBER 0x0000004 -#define VER_PLATFORMID 0x0000008 -#define VER_SERVICEPACKMINOR 0x0000010 -#define VER_SERVICEPACKMAJOR 0x0000020 -#define VER_SUITENAME 0x0000040 -#define VER_PRODUCT_TYPE 0x0000080 -#define VER_PLATFORM_WIN32s 0 -#define VER_PLATFORM_WIN32_WINDOWS 1 -#define VER_PLATFORM_WIN32_NT 2 -#define VER_EQUAL 1 -#define VER_GREATER 2 -#define VER_GREATER_EQUAL 3 -#define VER_LESS 4 -#define VER_LESS_EQUAL 5 -#define VER_AND 6 -#define VER_OR 7 -#define VER_CONDITION_MASK 7 -#define VER_NUM_BITS_PER_CONDITION_MASK 3 - -/* RTL String Hash Algorithms */ -#define HASH_STRING_ALGORITHM_DEFAULT 0 -#define HASH_STRING_ALGORITHM_X65599 1 -#define HASH_STRING_ALGORITHM_INVALID 0xffffffff - -/* List Macros */ -static __inline -VOID -InitializeListHead( - IN PLIST_ENTRY ListHead) -{ - ListHead->Flink = ListHead->Blink = ListHead; -} - -static __inline -VOID -InsertHeadList( - IN PLIST_ENTRY ListHead, - IN PLIST_ENTRY Entry) -{ - PLIST_ENTRY OldFlink; - OldFlink = ListHead->Flink; - Entry->Flink = OldFlink; - Entry->Blink = ListHead; - OldFlink->Blink = Entry; - ListHead->Flink = Entry; -} - -static __inline -VOID -InsertTailList( - IN PLIST_ENTRY ListHead, - IN PLIST_ENTRY Entry) -{ - PLIST_ENTRY OldBlink; - OldBlink = ListHead->Blink; - Entry->Flink = ListHead; - Entry->Blink = OldBlink; - OldBlink->Flink = Entry; - ListHead->Blink = Entry; -} - -#define IsListEmpty(ListHead) \ - ((ListHead)->Flink == (ListHead)) - -#define PopEntryList(ListHead) \ - (ListHead)->Next; \ - { \ - PSINGLE_LIST_ENTRY _FirstEntry; \ - _FirstEntry = (ListHead)->Next; \ - if (_FirstEntry != NULL) \ - (ListHead)->Next = _FirstEntry->Next; \ - } - -#define PushEntryList(_ListHead, _Entry) \ - (_Entry)->Next = (_ListHead)->Next; \ - (_ListHead)->Next = (_Entry); \ - -static __inline -BOOLEAN -RemoveEntryList( - IN PLIST_ENTRY Entry) -{ - PLIST_ENTRY OldFlink; - PLIST_ENTRY OldBlink; - - OldFlink = Entry->Flink; - OldBlink = Entry->Blink; - OldFlink->Blink = OldBlink; - OldBlink->Flink = OldFlink; - return (OldFlink == OldBlink); -} - -static __inline -PLIST_ENTRY -RemoveHeadList( - IN PLIST_ENTRY ListHead) -{ - PLIST_ENTRY Flink; - PLIST_ENTRY Entry; - - Entry = ListHead->Flink; - Flink = Entry->Flink; - ListHead->Flink = Flink; - Flink->Blink = ListHead; - return Entry; -} - -static __inline -PLIST_ENTRY -RemoveTailList( - IN PLIST_ENTRY ListHead) -{ - PLIST_ENTRY Blink; - PLIST_ENTRY Entry; - - Entry = ListHead->Blink; - Blink = Entry->Blink; - ListHead->Blink = Blink; - Blink->Flink = ListHead; - return Entry; -} - -#define IsFirstEntry(ListHead, Entry) \ - ((ListHead)->Flink == Entry) - -#define IsLastEntry(ListHead, Entry) \ - ((ListHead)->Blink == Entry) - -/* - * Constant String Macro - */ -#define RTL_CONSTANT_STRING(__SOURCE_STRING__) \ -{ \ - sizeof(__SOURCE_STRING__) - sizeof((__SOURCE_STRING__)[0]), \ - sizeof(__SOURCE_STRING__), \ - (__SOURCE_STRING__) \ -} - -/* ENUMERATIONS **************************************************************/ - -/* Kernel Shared Data Values */ -typedef enum _NT_PRODUCT_TYPE -{ - NtProductWinNt = 1, - NtProductLanManNt, - NtProductServer -} NT_PRODUCT_TYPE, *PNT_PRODUCT_TYPE; - -typedef enum _ALTERNATIVE_ARCHITECTURE_TYPE -{ - StandardDesign, - NEC98x86, - EndAlternatives -} ALTERNATIVE_ARCHITECTURE_TYPE; - -/* Run-Time Library (RTL) Enumerations */ -typedef enum _TABLE_SEARCH_RESULT -{ - TableEmptyTree, - TableFoundNode, - TableInsertAsLeft, - TableInsertAsRight -} TABLE_SEARCH_RESULT; - -typedef enum _RTL_GENERIC_COMPARE_RESULTS -{ - GenericLessThan, - GenericGreaterThan, - GenericEqual -} RTL_GENERIC_COMPARE_RESULTS; - -/* Kernel or Native Enumerations used by Native API */ -typedef enum _SECTION_INHERIT -{ - ViewShare = 1, - ViewUnmap = 2 -} SECTION_INHERIT; - -typedef enum _POOL_TYPE -{ - NonPagedPool, - PagedPool, - NonPagedPoolMustSucceed, - DontUseThisType, - NonPagedPoolCacheAligned, - PagedPoolCacheAligned, - NonPagedPoolCacheAlignedMustS, - MaxPoolType, - NonPagedPoolSession = 32, - PagedPoolSession, - NonPagedPoolMustSucceedSession, - DontUseThisTypeSession, - NonPagedPoolCacheAlignedSession, - PagedPoolCacheAlignedSession, - NonPagedPoolCacheAlignedMustSSession -} POOL_TYPE; - -typedef enum _EVENT_TYPE -{ - NotificationEvent, - SynchronizationEvent -} EVENT_TYPE; - -typedef enum _TIMER_TYPE -{ - NotificationTimer, - SynchronizationTimer -} TIMER_TYPE; - -typedef enum _WAIT_TYPE -{ - WaitAll, - WaitAny -} WAIT_TYPE; - -typedef enum _INTERFACE_TYPE -{ - InterfaceTypeUndefined = -1, - Internal, - Isa, - Eisa, - MicroChannel, - TurboChannel, - PCIBus, - VMEBus, - NuBus, - PCMCIABus, - CBus, - MPIBus, - MPSABus, - ProcessorInternal, - InternalPowerBus, - PNPISABus, - PNPBus, - MaximumInterfaceType -}INTERFACE_TYPE, *PINTERFACE_TYPE; - -typedef enum _MODE -{ - KernelMode, - UserMode, - MaximumMode -} MODE; - -typedef enum _KWAIT_REASON -{ - Executive, - FreePage, - PageIn, - PoolAllocation, - DelayExecution, - Suspended, - UserRequest, - WrExecutive, - WrFreePage, - WrPageIn, - WrPoolAllocation, - WrDelayExecution, - WrSuspended, - WrUserRequest, - WrEventPair, - WrQueue, - WrLpcReceive, - WrLpcReply, - WrVirtualMemory, - WrPageOut, - WrRendezvous, - Spare2, - WrGuardedMutex, - Spare4, - Spare5, - Spare6, - WrKernel, - WrResource, - WrPushLock, - WrMutex, - WrQuantumEnd, - WrDispatchInt, - WrPreempted, - WrYieldExecution, - MaximumWaitReason -} KWAIT_REASON; - -typedef enum _KPROFILE_SOURCE -{ - ProfileTime, - ProfileAlignmentFixup, - ProfileTotalIssues, - ProfilePipelineDry, - ProfileLoadInstructions, - ProfilePipelineFrozen, - ProfileBranchInstructions, - ProfileTotalNonissues, - ProfileDcacheMisses, - ProfileIcacheMisses, - ProfileCacheMisses, - ProfileBranchMispredictions, - ProfileStoreInstructions, - ProfileFpInstructions, - ProfileIntegerInstructions, - Profile2Issue, - Profile3Issue, - Profile4Issue, - ProfileSpecialInstructions, - ProfileTotalCycles, - ProfileIcacheIssues, - ProfileDcacheAccesses, - ProfileMemoryBarrierCycles, - ProfileLoadLinkedIssues, - ProfileMaximum -} KPROFILE_SOURCE; - -/**** Information Classes ****/ - -/* - * File - */ -typedef enum _FILE_INFORMATION_CLASS -{ - FileDirectoryInformation = 1, - FileFullDirectoryInformation, - FileBothDirectoryInformation, - FileBasicInformation, - FileStandardInformation, - FileInternalInformation, - FileEaInformation, - FileAccessInformation, - FileNameInformation, - FileRenameInformation, - FileLinkInformation, - FileNamesInformation, - FileDispositionInformation, - FilePositionInformation, - FileFullEaInformation, - FileModeInformation, - FileAlignmentInformation, - FileAllInformation, - FileAllocationInformation, - FileEndOfFileInformation, - FileAlternateNameInformation, - FileStreamInformation, - FilePipeInformation, - FilePipeLocalInformation, - FilePipeRemoteInformation, - FileMailslotQueryInformation, - FileMailslotSetInformation, - FileCompressionInformation, - FileObjectIdInformation, - FileCompletionInformation, - FileMoveClusterInformation, - FileQuotaInformation, - FileReparsePointInformation, - FileNetworkOpenInformation, - FileAttributeTagInformation, - FileTrackingInformation, - FileIdBothDirectoryInformation, - FileIdFullDirectoryInformation, - FileValidDataLengthInformation, - FileShortNameInformation, - FileMaximumInformation -} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; - -/* - * File System - */ -typedef enum _FSINFOCLASS -{ - FileFsVolumeInformation = 1, - FileFsLabelInformation, - FileFsSizeInformation, - FileFsDeviceInformation, - FileFsAttributeInformation, - FileFsControlInformation, - FileFsFullSizeInformation, - FileFsObjectIdInformation, - FileFsDriverPathInformation, - FileFsMaximumInformation -} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS; - -/* - * Registry Key - */ -typedef enum _KEY_INFORMATION_CLASS -{ - KeyBasicInformation, - KeyNodeInformation, - KeyFullInformation, - KeyNameInformation, - KeyCachedInformation, - KeyFlagsInformation -} KEY_INFORMATION_CLASS; - -/* - * Registry Key Value - */ -typedef enum _KEY_VALUE_INFORMATION_CLASS -{ - KeyValueBasicInformation, - KeyValueFullInformation, - KeyValuePartialInformation, - KeyValueFullInformationAlign64, - KeyValuePartialInformationAlign64 -} KEY_VALUE_INFORMATION_CLASS; - -/* - * Registry Key Set - */ -typedef enum _KEY_SET_INFORMATION_CLASS -{ - KeyWriteTimeInformation, - KeyUserFlagsInformation, - MaxKeySetInfoClass -} KEY_SET_INFORMATION_CLASS; - -/* - * Process - */ -typedef enum _PROCESSINFOCLASS -{ - ProcessBasicInformation, - ProcessQuotaLimits, - ProcessIoCounters, - ProcessVmCounters, - ProcessTimes, - ProcessBasePriority, - ProcessRaisePriority, - ProcessDebugPort, - ProcessExceptionPort, - ProcessAccessToken, - ProcessLdtInformation, - ProcessLdtSize, - ProcessDefaultHardErrorMode, - ProcessIoPortHandlers, - ProcessPooledUsageAndLimits, - ProcessWorkingSetWatch, - ProcessUserModeIOPL, - ProcessEnableAlignmentFaultFixup, - ProcessPriorityClass, - ProcessWx86Information, - ProcessHandleCount, - ProcessAffinityMask, - ProcessPriorityBoost, - ProcessDeviceMap, - ProcessSessionInformation, - ProcessForegroundInformation, - ProcessWow64Information, - ProcessImageFileName, - ProcessLUIDDeviceMapsEnabled, - ProcessBreakOnTermination, - ProcessDebugObjectHandle, - ProcessDebugFlags, - ProcessHandleTracing, - MaxProcessInfoClass -} PROCESSINFOCLASS; - -/* - * Thread - */ -typedef enum _THREADINFOCLASS -{ - ThreadBasicInformation, - ThreadTimes, - ThreadPriority, - ThreadBasePriority, - ThreadAffinityMask, - ThreadImpersonationToken, - ThreadDescriptorTableEntry, - ThreadEnableAlignmentFaultFixup, - ThreadEventPair_Reusable, - ThreadQuerySetWin32StartAddress, - ThreadZeroTlsCell, - ThreadPerformanceCount, - ThreadAmILastThread, - ThreadIdealProcessor, - ThreadPriorityBoost, - ThreadSetTlsArrayAddress, - ThreadIsIoPending, - ThreadHideFromDebugger, - ThreadBreakOnTermination, - MaxThreadInfoClass -} THREADINFOCLASS; - -/* TYPES *********************************************************************/ - -/* Basic Types that aren't defined in User-Mode Headers */ -typedef CONST int CINT; -typedef CONST char *PCSZ; -typedef short CSHORT; -typedef CSHORT *PCSHORT; -typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS; - -/* Kernel Types used by Native APIs */ -typedef LONG KPRIORITY; -typedef LONG NTSTATUS, *PNTSTATUS; -typedef UCHAR KIRQL, *PKIRQL; -typedef ULONG KAFFINITY, *PKAFFINITY; -typedef ULONG_PTR KSPIN_LOCK, *PKSPIN_LOCK; -typedef struct _PEB *PPEB; -typedef ULONG KPROCESSOR_MODE; -typedef struct _OBJECT_TYPE *POBJECT_TYPE; -struct _ETHREAD; -struct _CSR_API_MESSAGE; -typedef ULONG EXECUTION_STATE; - -/* Basic NT Types */ -#if !defined(_NTSECAPI_H) && !defined(_SUBAUTH_H) -typedef struct _UNICODE_STRING -{ - USHORT Length; - USHORT MaximumLength; - PWSTR Buffer; -} UNICODE_STRING, *PUNICODE_STRING; -typedef const UNICODE_STRING* PCUNICODE_STRING; - -typedef struct _STRING -{ - USHORT Length; - USHORT MaximumLength; - PCHAR Buffer; -} STRING, *PSTRING; - -typedef struct _OBJECT_ATTRIBUTES -{ - ULONG Length; - HANDLE RootDirectory; - PUNICODE_STRING ObjectName; - ULONG Attributes; - PVOID SecurityDescriptor; - PVOID SecurityQualityOfService; -} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; -#endif - -typedef STRING ANSI_STRING; -typedef PSTRING PANSI_STRING; -typedef STRING OEM_STRING; -typedef PSTRING POEM_STRING; - -typedef struct _IO_STATUS_BLOCK -{ - union - { - NTSTATUS Status; - PVOID Pointer; - }; - ULONG_PTR Information; -} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; - -typedef VOID -(NTAPI *PIO_APC_ROUTINE)( - IN PVOID ApcContext, - IN PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG Reserved); - -typedef VOID -(NTAPI *PKNORMAL_ROUTINE)( - IN PVOID NormalContext, - IN PVOID SystemArgument1, - IN PVOID SystemArgument2); - -typedef VOID -(NTAPI *PTIMER_APC_ROUTINE)( - IN PVOID TimerContext, - IN ULONG TimerLowValue, - IN LONG TimerHighValue); - -/* Kernel Types which are returned or used by Native API */ -typedef struct _OBJECT_NAME_INFORMATION -{ - UNICODE_STRING Name; -} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; - -typedef struct _IO_ERROR_LOG_PACKET -{ - UCHAR MajorFunctionCode; - UCHAR RetryCount; - USHORT DumpDataSize; - USHORT NumberOfStrings; - USHORT StringOffset; - USHORT EventCategory; - NTSTATUS ErrorCode; - ULONG UniqueErrorValue; - NTSTATUS FinalStatus; - ULONG SequenceNumber; - ULONG IoControlCode; - LARGE_INTEGER DeviceOffset; - ULONG DumpData[1]; -}IO_ERROR_LOG_PACKET, *PIO_ERROR_LOG_PACKET; - -typedef struct _IO_ERROR_LOG_MESSAGE -{ - USHORT Type; - USHORT Size; - USHORT DriverNameLength; - LARGE_INTEGER TimeStamp; - ULONG DriverNameOffset; - IO_ERROR_LOG_PACKET EntryData; -} IO_ERROR_LOG_MESSAGE, *PIO_ERROR_LOG_MESSAGE; - -typedef struct _CLIENT_ID -{ - HANDLE UniqueProcess; - HANDLE UniqueThread; -} CLIENT_ID, *PCLIENT_ID; - -typedef struct _KSYSTEM_TIME -{ - ULONG LowPart; - LONG High1Time; - LONG High2Time; -} KSYSTEM_TIME, *PKSYSTEM_TIME; - -typedef struct _TIME_FIELDS -{ - CSHORT Year; - CSHORT Month; - CSHORT Day; - CSHORT Hour; - CSHORT Minute; - CSHORT Second; - CSHORT Milliseconds; - CSHORT Weekday; -} TIME_FIELDS, *PTIME_FIELDS; - -typedef struct _VM_COUNTERS -{ - SIZE_T PeakVirtualSize; - SIZE_T VirtualSize; - ULONG PageFaultCount; - SIZE_T PeakWorkingSetSize; - SIZE_T WorkingSetSize; - SIZE_T QuotaPeakPagedPoolUsage; - SIZE_T QuotaPagedPoolUsage; - SIZE_T QuotaPeakNonPagedPoolUsage; - SIZE_T QuotaNonPagedPoolUsage; - SIZE_T PagefileUsage; - SIZE_T PeakPagefileUsage; -} VM_COUNTERS, *PVM_COUNTERS; - -typedef struct _VM_COUNTERS_EX -{ - SIZE_T PeakVirtualSize; - SIZE_T VirtualSize; - ULONG PageFaultCount; - SIZE_T PeakWorkingSetSize; - SIZE_T WorkingSetSize; - SIZE_T QuotaPeakPagedPoolUsage; - SIZE_T QuotaPagedPoolUsage; - SIZE_T QuotaPeakNonPagedPoolUsage; - SIZE_T QuotaNonPagedPoolUsage; - SIZE_T PagefileUsage; - SIZE_T PeakPagefileUsage; - SIZE_T PrivateUsage; -} VM_COUNTERS_EX, *PVM_COUNTERS_EX; - -/**** Information Types ****/ - -/* - * Registry Key Set - */ - -/* Class 0 */ -typedef struct _KEY_WRITE_TIME_INFORMATION -{ - LARGE_INTEGER LastWriteTime; -} KEY_WRITE_TIME_INFORMATION, *PKEY_WRITE_TIME_INFORMATION; - -/* Class 1 */ -typedef struct _KEY_USER_FLAGS_INFORMATION -{ - ULONG UserFlags; -} KEY_USER_FLAGS_INFORMATION, *PKEY_USER_FLAGS_INFORMATION; - -typedef struct _KEY_FULL_INFORMATION -{ - LARGE_INTEGER LastWriteTime; - ULONG TitleIndex; - ULONG ClassOffset; - ULONG ClassLength; - ULONG SubKeys; - ULONG MaxNameLen; - ULONG MaxClassLen; - ULONG Values; - ULONG MaxValueNameLen; - ULONG MaxValueDataLen; - WCHAR Class[1]; -} KEY_FULL_INFORMATION, *PKEY_FULL_INFORMATION; - -typedef struct _KEY_NODE_INFORMATION -{ - LARGE_INTEGER LastWriteTime; - ULONG TitleIndex; - ULONG ClassOffset; - ULONG ClassLength; - ULONG NameLength; - WCHAR Name[1]; -} KEY_NODE_INFORMATION, *PKEY_NODE_INFORMATION; - -/* - * File - */ - -/* Class 1 */ -typedef struct _FILE_BASIC_INFORMATION -{ - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - ULONG FileAttributes; -} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; - -/* Class 2 */ -typedef struct _FILE_STANDARD_INFORMATION -{ - LARGE_INTEGER AllocationSize; - LARGE_INTEGER EndOfFile; - ULONG NumberOfLinks; - BOOLEAN DeletePending; - BOOLEAN Directory; -} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION; - -typedef struct _FILE_NETWORK_OPEN_INFORMATION -{ - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER AllocationSize; - LARGE_INTEGER EndOfFile; - ULONG FileAttributes; -} FILE_NETWORK_OPEN_INFORMATION, *PFILE_NETWORK_OPEN_INFORMATION; - -typedef struct _FILE_EA_INFORMATION -{ - ULONG EaSize; -} FILE_EA_INFORMATION, *PFILE_EA_INFORMATION; - -typedef struct _FILE_COMPRESSION_INFORMATION -{ - LARGE_INTEGER CompressedFileSize; - USHORT CompressionFormat; - UCHAR CompressionUnitShift; - UCHAR ChunkShift; - UCHAR ClusterShift; - UCHAR Reserved[3]; -} FILE_COMPRESSION_INFORMATION, *PFILE_COMPRESSION_INFORMATION; - -typedef struct _FILE_POSITION_INFORMATION -{ - LARGE_INTEGER CurrentByteOffset; -} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION; - -typedef struct _FILE_DISPOSITION_INFORMATION -{ - BOOLEAN DeleteFile; -} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION; - -typedef struct _FILE_FULL_EA_INFORMATION -{ - ULONG NextEntryOffset; - UCHAR Flags; - UCHAR EaNameLength; - USHORT EaValueLength; - CHAR EaName[1]; -} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION; - -typedef struct _FILE_QUOTA_INFORMATION -{ - ULONG NextEntryOffset; - ULONG SidLength; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER QuotaUsed; - LARGE_INTEGER QuotaThreshold; - LARGE_INTEGER QuotaLimit; - SID Sid; -} FILE_QUOTA_INFORMATION, *PFILE_QUOTA_INFORMATION; - -typedef struct _FILE_INTERNAL_INFORMATION -{ - LARGE_INTEGER IndexNumber; -} FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION; - -typedef struct _FILE_RENAME_INFORMATION -{ - BOOLEAN ReplaceIfExists; - HANDLE RootDirectory; - ULONG FileNameLength; - WCHAR FileName[1]; -} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION; - -typedef struct _FILE_PIPE_INFORMATION -{ - ULONG ReadMode; - ULONG CompletionMode; -} FILE_PIPE_INFORMATION, *PFILE_PIPE_INFORMATION; - -typedef struct _FILE_PIPE_LOCAL_INFORMATION -{ - ULONG NamedPipeType; - ULONG NamedPipeConfiguration; - ULONG MaximumInstances; - ULONG CurrentInstances; - ULONG InboundQuota; - ULONG ReadDataAvailable; - ULONG OutboundQuota; - ULONG WriteQuotaAvailable; - ULONG NamedPipeState; - ULONG NamedPipeEnd; -} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION; - -typedef struct _FILE_PIPE_REMOTE_INFORMATION -{ - LARGE_INTEGER CollectDataTime; - ULONG MaximumCollectionCount; -} FILE_PIPE_REMOTE_INFORMATION, *PFILE_PIPE_REMOTE_INFORMATION; - -typedef struct _FILE_MAILSLOT_QUERY_INFORMATION -{ - ULONG MaximumMessageSize; - ULONG MailslotQuota; - ULONG NextMessageSize; - ULONG MessagesAvailable; - LARGE_INTEGER ReadTimeout; -} FILE_MAILSLOT_QUERY_INFORMATION, *PFILE_MAILSLOT_QUERY_INFORMATION; - -typedef struct _FILE_MAILSLOT_SET_INFORMATION -{ - LARGE_INTEGER ReadTimeout; -} FILE_MAILSLOT_SET_INFORMATION, *PFILE_MAILSLOT_SET_INFORMATION; - -typedef struct _FILE_BOTH_DIR_INFORMATION -{ - ULONG NextEntryOffset; - ULONG FileIndex; - LARGE_INTEGER CreationTime; - LARGE_INTEGER LastAccessTime; - LARGE_INTEGER LastWriteTime; - LARGE_INTEGER ChangeTime; - LARGE_INTEGER EndOfFile; - LARGE_INTEGER AllocationSize; - ULONG FileAttributes; - ULONG FileNameLength; - ULONG EaSize; - CCHAR ShortNameLength; - WCHAR ShortName[12]; - WCHAR FileName[1]; -} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; - -typedef struct _FILE_COMPLETION_INFORMATION -{ - HANDLE Port; - PVOID Key; -} FILE_COMPLETION_INFORMATION, *PFILE_COMPLETION_INFORMATION; - -typedef struct _FILE_LINK_INFORMATION -{ - BOOLEAN ReplaceIfExists; - HANDLE RootDirectory; - ULONG FileNameLength; - WCHAR FileName[1]; -} FILE_LINK_INFORMATION, *PFILE_LINK_INFORMATION; - -typedef struct _FILE_NAME_INFORMATION -{ - ULONG FileNameLength; - WCHAR FileName[1]; -} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION; - -typedef struct _FILE_ALLOCATION_INFORMATION -{ - LARGE_INTEGER AllocationSize; -} FILE_ALLOCATION_INFORMATION, *PFILE_ALLOCATION_INFORMATION; - -typedef struct _FILE_END_OF_FILE_INFORMATION -{ - LARGE_INTEGER EndOfFile; -} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION; - -typedef struct _FILE_VALID_DATA_LENGTH_INFORMATION -{ - LARGE_INTEGER ValidDataLength; -} FILE_VALID_DATA_LENGTH_INFORMATION, *PFILE_VALID_DATA_LENGTH_INFORMATION; - -/* - * File System - */ -typedef struct _FILE_FS_DEVICE_INFORMATION -{ - DEVICE_TYPE DeviceType; - ULONG Characteristics; -} FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION; - -typedef struct _FILE_FS_ATTRIBUTE_INFORMATION -{ - ULONG FileSystemAttributes; - ULONG MaximumComponentNameLength; - ULONG FileSystemNameLength; - WCHAR FileSystemName[1]; -} FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION; - -typedef struct _FILE_FS_SIZE_INFORMATION -{ - LARGE_INTEGER TotalAllocationUnits; - LARGE_INTEGER AvailableAllocationUnits; - ULONG SectorsPerAllocationUnit; - ULONG BytesPerSector; -} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION; - -typedef struct _FILE_FS_LABEL_INFORMATION -{ - ULONG VolumeLabelLength; - WCHAR VolumeLabel[1]; -} FILE_FS_LABEL_INFORMATION, *PFILE_FS_LABEL_INFORMATION; - -typedef struct _FILE_FS_VOLUME_INFORMATION -{ - LARGE_INTEGER VolumeCreationTime; - ULONG VolumeSerialNumber; - ULONG VolumeLabelLength; - BOOLEAN SupportsObjects; - WCHAR VolumeLabel[1]; -} FILE_FS_VOLUME_INFORMATION, *PFILE_FS_VOLUME_INFORMATION; - -/* - * Registry Key Value - */ - -/* Class 0 */ -typedef struct _KEY_VALUE_ENTRY -{ - PUNICODE_STRING ValueName; - ULONG DataLength; - ULONG DataOffset; - ULONG Type; -} KEY_VALUE_ENTRY, *PKEY_VALUE_ENTRY; - -/* Class 1 */ -typedef struct _KEY_VALUE_PARTIAL_INFORMATION -{ - ULONG TitleIndex; - ULONG Type; - ULONG DataLength; - UCHAR Data[1]; -} KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION; - -/* Class 2 */ -typedef struct _KEY_VALUE_BASIC_INFORMATION -{ - ULONG TitleIndex; - ULONG Type; - ULONG NameLength; - WCHAR Name[1]; -} KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION; - -/* Class 3 */ -typedef struct _KEY_VALUE_FULL_INFORMATION -{ - ULONG TitleIndex; - ULONG Type; - ULONG DataOffset; - ULONG DataLength; - ULONG NameLength; - WCHAR Name[1]; -} KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION; - -/* - * Registry Key - */ - -/* Class 0 */ -typedef struct _KEY_BASIC_INFORMATION -{ - LARGE_INTEGER LastWriteTime; - ULONG TitleIndex; - ULONG NameLength; - WCHAR Name[1]; -} KEY_BASIC_INFORMATION, *PKEY_BASIC_INFORMATION; - -/* File Pipe Structures for the FSCTLs */ -typedef struct _FILE_PIPE_WAIT_FOR_BUFFER -{ - LARGE_INTEGER Timeout; - ULONG NameLength; - BOOLEAN TimeoutSpecified; - WCHAR Name[1]; -} FILE_PIPE_WAIT_FOR_BUFFER, *PFILE_PIPE_WAIT_FOR_BUFFER; - -typedef struct _FILE_PIPE_PEEK_BUFFER -{ - ULONG NamedPipeState; - ULONG ReadDataAvailable; - ULONG NumberOfMessages; - ULONG MessageLength; - CHAR Data[1]; -} FILE_PIPE_PEEK_BUFFER, *PFILE_PIPE_PEEK_BUFFER; - -/* The Kerner/User Shared Data Structure */ -typedef struct _KUSER_SHARED_DATA -{ - ULONG TickCountLowDeprecated; - ULONG TickCountMultiplier; - volatile KSYSTEM_TIME InterruptTime; - volatile KSYSTEM_TIME SystemTime; - volatile KSYSTEM_TIME TimeZoneBias; - USHORT ImageNumberLow; - USHORT ImageNumberHigh; - WCHAR NtSystemRoot[260]; - ULONG MaxStackTraceDepth; - ULONG CryptoExponent; - ULONG TimeZoneId; - ULONG LargePageMinimum; - ULONG Reserved2[7]; - NT_PRODUCT_TYPE NtProductType; - BOOLEAN ProductTypeIsValid; - ULONG NtMajorVersion; - ULONG NtMinorVersion; - BOOLEAN ProcessorFeatures[PROCESSOR_FEATURE_MAX]; - ULONG Reserved1; - ULONG Reserved3; - volatile ULONG TimeSlip; - ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture; - LARGE_INTEGER SystemExpirationDate; - ULONG SuiteMask; - BOOLEAN KdDebuggerEnabled; - volatile ULONG ActiveConsoleId; - volatile ULONG DismountCount; - ULONG ComPlusPackage; - ULONG LastSystemRITEventTickCount; - ULONG NumberOfPhysicalPages; - BOOLEAN SafeBootMode; - ULONG TraceLogging; - ULONGLONG Fill0; - ULONGLONG SystemCall[4]; - union { - volatile KSYSTEM_TIME TickCount; - volatile ULONG64 TickCountQuad; - }; -} KUSER_SHARED_DATA, *PKUSER_SHARED_DATA; - -/* Run-Time Library (RTL) Types */ -typedef struct _RTL_BITMAP -{ - ULONG SizeOfBitMap; - PULONG Buffer; -} RTL_BITMAP, *PRTL_BITMAP; - -typedef struct _RTL_BITMAP_RUN -{ - ULONG StartingIndex; - ULONG NumberOfBits; -} RTL_BITMAP_RUN, *PRTL_BITMAP_RUN; - -typedef struct _COMPRESSED_DATA_INFO -{ - USHORT CompressionFormatAndEngine; - UCHAR CompressionUnitShift; - UCHAR ChunkShift; - UCHAR ClusterShift; - UCHAR Reserved; - USHORT NumberOfChunks; - ULONG CompressedChunkSizes[ANYSIZE_ARRAY]; -} COMPRESSED_DATA_INFO, *PCOMPRESSED_DATA_INFO; - -typedef struct _GENERATE_NAME_CONTEXT -{ - USHORT Checksum; - BOOLEAN CheckSumInserted; - UCHAR NameLength; - WCHAR NameBuffer[8]; - ULONG ExtensionLength; - WCHAR ExtensionBuffer[4]; - ULONG LastIndexValue; -} GENERATE_NAME_CONTEXT, *PGENERATE_NAME_CONTEXT; - -typedef struct _RTL_SPLAY_LINKS -{ - struct _RTL_SPLAY_LINKS *Parent; - struct _RTL_SPLAY_LINKS *LeftChild; - struct _RTL_SPLAY_LINKS *RightChild; -} RTL_SPLAY_LINKS, *PRTL_SPLAY_LINKS; - -struct _RTL_AVL_TABLE; -struct _RTL_GENERIC_TABLE; - -typedef NTSTATUS -(NTAPI *PRTL_AVL_MATCH_FUNCTION)( - struct _RTL_AVL_TABLE *Table, - PVOID UserData, - PVOID MatchData -); - -typedef RTL_GENERIC_COMPARE_RESULTS -(NTAPI *PRTL_AVL_COMPARE_ROUTINE) ( - struct _RTL_AVL_TABLE *Table, - PVOID FirstStruct, - PVOID SecondStruct -); - -typedef RTL_GENERIC_COMPARE_RESULTS -(NTAPI *PRTL_GENERIC_COMPARE_ROUTINE) ( - struct _RTL_GENERIC_TABLE *Table, - PVOID FirstStruct, - PVOID SecondStruct -); - -typedef PVOID -(NTAPI *PRTL_GENERIC_ALLOCATE_ROUTINE) ( - struct _RTL_GENERIC_TABLE *Table, - LONG ByteSize -); - -typedef VOID -(NTAPI *PRTL_GENERIC_FREE_ROUTINE) ( - struct _RTL_GENERIC_TABLE *Table, - PVOID Buffer -); - -typedef VOID -(NTAPI *PRTL_AVL_ALLOCATE_ROUTINE) ( - struct _RTL_AVL_TABLE *Table, - LONG ByteSize -); - -typedef VOID -(NTAPI *PRTL_AVL_FREE_ROUTINE) ( - struct _RTL_AVL_TABLE *Table, - PVOID Buffer -); - -typedef struct _RTL_GENERIC_TABLE -{ - PRTL_SPLAY_LINKS TableRoot; - LIST_ENTRY InsertOrderList; - PLIST_ENTRY OrderedPointer; - ULONG WhichOrderedElement; - ULONG NumberGenericTableElements; - PRTL_GENERIC_COMPARE_ROUTINE CompareRoutine; - PRTL_GENERIC_ALLOCATE_ROUTINE AllocateRoutine; - PRTL_GENERIC_FREE_ROUTINE FreeRoutine; - PVOID TableContext; -} RTL_GENERIC_TABLE, *PRTL_GENERIC_TABLE; - -typedef struct _RTL_BALANCED_LINKS -{ - struct _RTL_BALANCED_LINKS *Parent; - struct _RTL_BALANCED_LINKS *LeftChild; - struct _RTL_BALANCED_LINKS *RightChild; - CHAR Balance; - UCHAR Reserved[3]; -} RTL_BALANCED_LINKS, *PRTL_BALANCED_LINKS; - -typedef struct _RTL_AVL_TABLE -{ - RTL_BALANCED_LINKS BalancedRoot; - PVOID OrderedPointer; - ULONG WhichOrderedElement; - ULONG NumberGenericTableElements; - ULONG DepthOfTree; - PRTL_BALANCED_LINKS RestartKey; - ULONG DeleteCount; - PRTL_AVL_COMPARE_ROUTINE CompareRoutine; - PRTL_AVL_ALLOCATE_ROUTINE AllocateRoutine; - PRTL_AVL_FREE_ROUTINE FreeRoutine; - PVOID TableContext; -} RTL_AVL_TABLE, *PRTL_AVL_TABLE; - -typedef NTSTATUS -(NTAPI *PRTL_QUERY_REGISTRY_ROUTINE)( - IN PWSTR ValueName, - IN ULONG ValueType, - IN PVOID ValueData, - IN ULONG ValueLength, - IN PVOID Context, - IN PVOID EntryContext -); - -typedef struct _RTL_QUERY_REGISTRY_TABLE -{ - PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine; - ULONG Flags; - PWSTR Name; - PVOID EntryContext; - ULONG DefaultType; - PVOID DefaultData; - ULONG DefaultLength; -} RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE; - -typedef struct _UNICODE_PREFIX_TABLE_ENTRY -{ - CSHORT NodeTypeCode; - CSHORT NameLength; - struct _UNICODE_PREFIX_TABLE_ENTRY *NextPrefixTree; - struct _UNICODE_PREFIX_TABLE_ENTRY *CaseMatch; - RTL_SPLAY_LINKS Links; - PUNICODE_STRING Prefix; -} UNICODE_PREFIX_TABLE_ENTRY, *PUNICODE_PREFIX_TABLE_ENTRY; - -typedef struct _UNICODE_PREFIX_TABLE -{ - CSHORT NodeTypeCode; - CSHORT NameLength; - PUNICODE_PREFIX_TABLE_ENTRY NextPrefixTree; - PUNICODE_PREFIX_TABLE_ENTRY LastNextEntry; -} UNICODE_PREFIX_TABLE, *PUNICODE_PREFIX_TABLE; - -/* FIXME - need FAST_MUTEX and PHANDLE_TABLE for RTL_ATOM_TABLE in umode! */ -typedef void *FAST_MUTEX; -typedef void *PHANDLE_TABLE; - -typedef OSVERSIONINFOW RTL_OSVERSIONINFOW; -typedef LPOSVERSIONINFOW PRTL_OSVERSIONINFOW; -typedef OSVERSIONINFOEXW RTL_OSVERSIONINFOEXW; -typedef LPOSVERSIONINFOEXW PRTL_OSVERSIONINFOEXW; - -#endif +/* + * PROJECT: ReactOS Native Headers + * FILE: include/ndk/umtypes.h + * PURPOSE: Definitions needed for Native Headers if target is not Kernel-Mode. + * PROGRAMMER: Alex Ionescu (alex@relsoft.net) + * UPDATE HISTORY: + * Created 06/10/04 + */ + +#ifndef _UMTYPES_H +#define _UMTYPES_H + +/* DEPENDENCIES **************************************************************/ +#include +#include +#include +#define STATIC static + +/* EXPORTED DATA *************************************************************/ + +/* CONSTANTS *****************************************************************/ + +/* NTAPI/NTOSAPI Define */ +#define NTAPI __stdcall +#define NTOSAPI +#define FASTCALL __fastcall +#define STDCALL __stdcall + +/* Definitions for Object Creation -- winternl.h */ +#define OBJ_INHERIT 2L +#define OBJ_PERMANENT 16L +#define OBJ_EXCLUSIVE 32L +#define OBJ_CASE_INSENSITIVE 64L +#define OBJ_OPENIF 128L +#define OBJ_OPENLINK 256L +#define OBJ_VALID_ATTRIBUTES 498L +#define InitializeObjectAttributes(p,n,a,r,s) { \ + (p)->Length = sizeof(OBJECT_ATTRIBUTES); \ + (p)->RootDirectory = (r); \ + (p)->Attributes = (a); \ + (p)->ObjectName = (n); \ + (p)->SecurityDescriptor = (s); \ + (p)->SecurityQualityOfService = NULL; \ +} + +/* Native API Return Value Macros */ +#define NT_SUCCESS(x) ((x)>=0) +#define NT_WARNING(x) ((ULONG)(x)>>30==2) +#define NT_ERROR(x) ((ULONG)(x)>>30==3) + +/* Object Access Rights FIXME: Some are in w32api's psdk..,is that normal ?*/ +#define DIRECTORY_QUERY (0x0001) +#define DIRECTORY_TRAVERSE (0x0002) +#define DIRECTORY_CREATE_OBJECT (0x0004) +#define DIRECTORY_CREATE_SUBDIRECTORY (0x0008) +#define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0xF) +#define EVENT_QUERY_STATE (0x0001) +#define SEMAPHORE_QUERY_STATE (0x0001) +#define SYMBOLIC_LINK_QUERY 0x0001 +#define SYMBOLIC_LINK_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0x1) + +/* Duplication Flags */ +#define DUPLICATE_SAME_ATTRIBUTES 0x00000004 + +/* I/O Control Codes for communicating with Mailslots */ +#define FSCTL_MAILSLOT_PEEK \ + CTL_CODE(FILE_DEVICE_MAILSLOT, 0, METHOD_NEITHER, FILE_READ_DATA) + +/* I/O Control Codes for communicating with Pipes */ +#define FSCTL_PIPE_ASSIGN_EVENT \ + CTL_CODE(FILE_DEVICE_NAMED_PIPE, 0, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_DISCONNECT \ + CTL_CODE(FILE_DEVICE_NAMED_PIPE, 1, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_LISTEN \ + CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_PEEK \ + CTL_CODE(FILE_DEVICE_NAMED_PIPE, 3, METHOD_BUFFERED, FILE_READ_DATA) +#define FSCTL_PIPE_QUERY_EVENT \ + CTL_CODE(FILE_DEVICE_NAMED_PIPE, 4, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_TRANSCEIVE \ + CTL_CODE(FILE_DEVICE_NAMED_PIPE, 5, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA) +#define FSCTL_PIPE_WAIT \ + CTL_CODE(FILE_DEVICE_NAMED_PIPE, 6, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_IMPERSONATE \ + CTL_CODE(FILE_DEVICE_NAMED_PIPE, 7, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_SET_CLIENT_PROCESS \ + CTL_CODE(FILE_DEVICE_NAMED_PIPE, 8, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_QUERY_CLIENT_PROCESS \ + CTL_CODE(FILE_DEVICE_NAMED_PIPE, 9, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSCTL_PIPE_INTERNAL_READ \ + CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2045, METHOD_BUFFERED, FILE_READ_DATA) +#define FSCTL_PIPE_INTERNAL_WRITE \ + CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2046, METHOD_BUFFERED, FILE_WRITE_DATA) +#define FSCTL_PIPE_INTERNAL_TRANSCEIVE \ + CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2047, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA) +#define FSCTL_PIPE_INTERNAL_READ_OVFLOW \ + CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2048, METHOD_BUFFERED, FILE_READ_DATA) + +/* I/O Control Codes for Communicating with Tapes */ +#define IOCTL_TAPE_ERASE \ + CTL_CODE(FILE_DEVICE_TAPE, 0, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_TAPE_PREPARE \ + CTL_CODE(FILE_DEVICE_TAPE, 1, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_TAPE_WRITE_MARKS \ + CTL_CODE(FILE_DEVICE_TAPE, 2, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_TAPE_GET_POSITION \ + CTL_CODE(FILE_DEVICE_TAPE, 3, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_TAPE_SET_POSITION \ + CTL_CODE(FILE_DEVICE_TAPE, 4, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_TAPE_GET_DRIVE_PARAMS \ + CTL_CODE(FILE_DEVICE_TAPE, 5, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_TAPE_SET_DRIVE_PARAMS \ + CTL_CODE(FILE_DEVICE_TAPE, 6, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_TAPE_GET_MEDIA_PARAMS \ + CTL_CODE(FILE_DEVICE_TAPE, 7, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_TAPE_SET_MEDIA_PARAMS \ + CTL_CODE(FILE_DEVICE_TAPE, 8, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_TAPE_GET_STATUS \ + CTL_CODE(FILE_DEVICE_TAPE, 9, METHOD_BUFFERED, FILE_READ_ACCESS) +#define IOCTL_TAPE_CREATE_PARTITION \ + CTL_CODE(FILE_DEVICE_TAPE, 10, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +/* Macros for current Process/Thread built-in 'special' ID */ +#define NtCurrentProcess() ( (HANDLE)(LONG_PTR) -1 ) +#define ZwCurrentProcess() NtCurrentProcess() +#define NtCurrentThread() ( (HANDLE)(LONG_PTR) -2 ) +#define ZwCurrentThread() NtCurrentThread() + +/* Kernel Shared Data Constants */ +#define PROCESSOR_FEATURE_MAX 64 +#define SharedUserData ((KUSER_SHARED_DATA * CONST) USER_SHARED_DATA) + +/* Paging Values on x86 */ +#define PAGE_SIZE 0x1000 +#define PAGE_SHIFT 12L + +/* Run-Time Library (RTL) Registry Constants */ +#define RTL_REGISTRY_ABSOLUTE 0 +#define RTL_REGISTRY_SERVICES 1 +#define RTL_REGISTRY_CONTROL 2 +#define RTL_REGISTRY_WINDOWS_NT 3 +#define RTL_REGISTRY_DEVICEMAP 4 +#define RTL_REGISTRY_USER 5 +#define RTL_REGISTRY_MAXIMUM 6 +#define RTL_REGISTRY_HANDLE 0x40000000 +#define RTL_REGISTRY_OPTIONAL 0x80000000 +#define RTL_QUERY_REGISTRY_SUBKEY 0x00000001 +#define RTL_QUERY_REGISTRY_TOPKEY 0x00000002 +#define RTL_QUERY_REGISTRY_REQUIRED 0x00000004 +#define RTL_QUERY_REGISTRY_NOVALUE 0x00000008 +#define RTL_QUERY_REGISTRY_NOEXPAND 0x00000010 +#define RTL_QUERY_REGISTRY_DIRECT 0x00000020 +#define RTL_QUERY_REGISTRY_DELETE 0x00000040 + +/* File Result Flags */ +#define FILE_SUPERSEDED 0x00000000 +#define FILE_OPENED 0x00000001 +#define FILE_CREATED 0x00000002 +#define FILE_OVERWRITTEN 0x00000003 +#define FILE_EXISTS 0x00000004 +#define FILE_DOES_NOT_EXIST 0x00000005 + +/* Pipe Flags */ +#define FILE_PIPE_BYTE_STREAM_MODE 0x00000000 +#define FILE_PIPE_MESSAGE_MODE 0x00000001 +#define FILE_PIPE_QUEUE_OPERATION 0x00000000 +#define FILE_PIPE_COMPLETE_OPERATION 0x00000001 +#define FILE_PIPE_INBOUND 0x00000000 +#define FILE_PIPE_OUTBOUND 0x00000001 +#define FILE_PIPE_FULL_DUPLEX 0x00000002 +#define FILE_PIPE_CLIENT_END 0x00000000 +#define FILE_PIPE_SERVER_END 0x00000001 + +/* File Attributes */ +#define FILE_ATTRIBUTE_VALID_FLAGS 0x00007fb7 +#define FILE_ATTRIBUTE_VALID_SET_FLAGS 0x000031a7 + +/* File Flags */ +#define FILE_SUPERSEDE 0x00000000 +#define FILE_OPEN 0x00000001 +#define FILE_CREATE 0x00000002 +#define FILE_OPEN_IF 0x00000003 +#define FILE_OVERWRITE 0x00000004 +#define FILE_OVERWRITE_IF 0x00000005 +#define FILE_MAXIMUM_DISPOSITION 0x00000005 + +/* File Types */ +#define FILE_DIRECTORY_FILE 0x00000001 +#define FILE_WRITE_THROUGH 0x00000002 +#define FILE_SEQUENTIAL_ONLY 0x00000004 +#define FILE_NO_INTERMEDIATE_BUFFERING 0x00000008 +#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 +#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 +#define FILE_NON_DIRECTORY_FILE 0x00000040 +#define FILE_CREATE_TREE_CONNECTION 0x00000080 +#define FILE_COMPLETE_IF_OPLOCKED 0x00000100 +#define FILE_NO_EA_KNOWLEDGE 0x00000200 +#define FILE_OPEN_FOR_RECOVERY 0x00000400 +#define FILE_RANDOM_ACCESS 0x00000800 +#define FILE_DELETE_ON_CLOSE 0x00001000 +#define FILE_OPEN_BY_FILE_ID 0x00002000 +#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000 +#define FILE_NO_COMPRESSION 0x00008000 +#define FILE_RESERVE_OPFILTER 0x00100000 +#define FILE_OPEN_REPARSE_POINT 0x00200000 +#define FILE_OPEN_NO_RECALL 0x00400000 +#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000 + +/* Device Charactertics */ +#define FILE_REMOVABLE_MEDIA 0x00000001 +#define FILE_REMOTE_DEVICE 0x00000010 + +/* Version Constants */ +#define VER_MINORVERSION 0x0000001 +#define VER_MAJORVERSION 0x0000002 +#define VER_BUILDNUMBER 0x0000004 +#define VER_PLATFORMID 0x0000008 +#define VER_SERVICEPACKMINOR 0x0000010 +#define VER_SERVICEPACKMAJOR 0x0000020 +#define VER_SUITENAME 0x0000040 +#define VER_PRODUCT_TYPE 0x0000080 +#define VER_PLATFORM_WIN32s 0 +#define VER_PLATFORM_WIN32_WINDOWS 1 +#define VER_PLATFORM_WIN32_NT 2 +#define VER_EQUAL 1 +#define VER_GREATER 2 +#define VER_GREATER_EQUAL 3 +#define VER_LESS 4 +#define VER_LESS_EQUAL 5 +#define VER_AND 6 +#define VER_OR 7 +#define VER_CONDITION_MASK 7 +#define VER_NUM_BITS_PER_CONDITION_MASK 3 + +/* RTL String Hash Algorithms */ +#define HASH_STRING_ALGORITHM_DEFAULT 0 +#define HASH_STRING_ALGORITHM_X65599 1 +#define HASH_STRING_ALGORITHM_INVALID 0xffffffff + +/* List Macros */ +static __inline +VOID +InitializeListHead( + IN PLIST_ENTRY ListHead) +{ + ListHead->Flink = ListHead->Blink = ListHead; +} + +static __inline +VOID +InsertHeadList( + IN PLIST_ENTRY ListHead, + IN PLIST_ENTRY Entry) +{ + PLIST_ENTRY OldFlink; + OldFlink = ListHead->Flink; + Entry->Flink = OldFlink; + Entry->Blink = ListHead; + OldFlink->Blink = Entry; + ListHead->Flink = Entry; +} + +static __inline +VOID +InsertTailList( + IN PLIST_ENTRY ListHead, + IN PLIST_ENTRY Entry) +{ + PLIST_ENTRY OldBlink; + OldBlink = ListHead->Blink; + Entry->Flink = ListHead; + Entry->Blink = OldBlink; + OldBlink->Flink = Entry; + ListHead->Blink = Entry; +} + +#define IsListEmpty(ListHead) \ + ((ListHead)->Flink == (ListHead)) + +#define PopEntryList(ListHead) \ + (ListHead)->Next; \ + { \ + PSINGLE_LIST_ENTRY _FirstEntry; \ + _FirstEntry = (ListHead)->Next; \ + if (_FirstEntry != NULL) \ + (ListHead)->Next = _FirstEntry->Next; \ + } + +#define PushEntryList(_ListHead, _Entry) \ + (_Entry)->Next = (_ListHead)->Next; \ + (_ListHead)->Next = (_Entry); \ + +static __inline +BOOLEAN +RemoveEntryList( + IN PLIST_ENTRY Entry) +{ + PLIST_ENTRY OldFlink; + PLIST_ENTRY OldBlink; + + OldFlink = Entry->Flink; + OldBlink = Entry->Blink; + OldFlink->Blink = OldBlink; + OldBlink->Flink = OldFlink; + return (OldFlink == OldBlink); +} + +static __inline +PLIST_ENTRY +RemoveHeadList( + IN PLIST_ENTRY ListHead) +{ + PLIST_ENTRY Flink; + PLIST_ENTRY Entry; + + Entry = ListHead->Flink; + Flink = Entry->Flink; + ListHead->Flink = Flink; + Flink->Blink = ListHead; + return Entry; +} + +static __inline +PLIST_ENTRY +RemoveTailList( + IN PLIST_ENTRY ListHead) +{ + PLIST_ENTRY Blink; + PLIST_ENTRY Entry; + + Entry = ListHead->Blink; + Blink = Entry->Blink; + ListHead->Blink = Blink; + Blink->Flink = ListHead; + return Entry; +} + +#define IsFirstEntry(ListHead, Entry) \ + ((ListHead)->Flink == Entry) + +#define IsLastEntry(ListHead, Entry) \ + ((ListHead)->Blink == Entry) + +/* + * Constant String Macro + */ +#define RTL_CONSTANT_STRING(__SOURCE_STRING__) \ +{ \ + sizeof(__SOURCE_STRING__) - sizeof((__SOURCE_STRING__)[0]), \ + sizeof(__SOURCE_STRING__), \ + (__SOURCE_STRING__) \ +} + +/* ENUMERATIONS **************************************************************/ + +/* Kernel Shared Data Values */ +typedef enum _NT_PRODUCT_TYPE +{ + NtProductWinNt = 1, + NtProductLanManNt, + NtProductServer +} NT_PRODUCT_TYPE, *PNT_PRODUCT_TYPE; + +typedef enum _ALTERNATIVE_ARCHITECTURE_TYPE +{ + StandardDesign, + NEC98x86, + EndAlternatives +} ALTERNATIVE_ARCHITECTURE_TYPE; + +/* Run-Time Library (RTL) Enumerations */ +typedef enum _TABLE_SEARCH_RESULT +{ + TableEmptyTree, + TableFoundNode, + TableInsertAsLeft, + TableInsertAsRight +} TABLE_SEARCH_RESULT; + +typedef enum _RTL_GENERIC_COMPARE_RESULTS +{ + GenericLessThan, + GenericGreaterThan, + GenericEqual +} RTL_GENERIC_COMPARE_RESULTS; + +/* Kernel or Native Enumerations used by Native API */ +typedef enum _SECTION_INHERIT +{ + ViewShare = 1, + ViewUnmap = 2 +} SECTION_INHERIT; + +typedef enum _POOL_TYPE +{ + NonPagedPool, + PagedPool, + NonPagedPoolMustSucceed, + DontUseThisType, + NonPagedPoolCacheAligned, + PagedPoolCacheAligned, + NonPagedPoolCacheAlignedMustS, + MaxPoolType, + NonPagedPoolSession = 32, + PagedPoolSession, + NonPagedPoolMustSucceedSession, + DontUseThisTypeSession, + NonPagedPoolCacheAlignedSession, + PagedPoolCacheAlignedSession, + NonPagedPoolCacheAlignedMustSSession +} POOL_TYPE; + +typedef enum _EVENT_TYPE +{ + NotificationEvent, + SynchronizationEvent +} EVENT_TYPE; + +typedef enum _TIMER_TYPE +{ + NotificationTimer, + SynchronizationTimer +} TIMER_TYPE; + +typedef enum _WAIT_TYPE +{ + WaitAll, + WaitAny +} WAIT_TYPE; + +typedef enum _INTERFACE_TYPE +{ + InterfaceTypeUndefined = -1, + Internal, + Isa, + Eisa, + MicroChannel, + TurboChannel, + PCIBus, + VMEBus, + NuBus, + PCMCIABus, + CBus, + MPIBus, + MPSABus, + ProcessorInternal, + InternalPowerBus, + PNPISABus, + PNPBus, + MaximumInterfaceType +}INTERFACE_TYPE, *PINTERFACE_TYPE; + +typedef enum _MODE +{ + KernelMode, + UserMode, + MaximumMode +} MODE; + +typedef enum _KWAIT_REASON +{ + Executive, + FreePage, + PageIn, + PoolAllocation, + DelayExecution, + Suspended, + UserRequest, + WrExecutive, + WrFreePage, + WrPageIn, + WrPoolAllocation, + WrDelayExecution, + WrSuspended, + WrUserRequest, + WrEventPair, + WrQueue, + WrLpcReceive, + WrLpcReply, + WrVirtualMemory, + WrPageOut, + WrRendezvous, + Spare2, + WrGuardedMutex, + Spare4, + Spare5, + Spare6, + WrKernel, + WrResource, + WrPushLock, + WrMutex, + WrQuantumEnd, + WrDispatchInt, + WrPreempted, + WrYieldExecution, + MaximumWaitReason +} KWAIT_REASON; + +typedef enum _KPROFILE_SOURCE +{ + ProfileTime, + ProfileAlignmentFixup, + ProfileTotalIssues, + ProfilePipelineDry, + ProfileLoadInstructions, + ProfilePipelineFrozen, + ProfileBranchInstructions, + ProfileTotalNonissues, + ProfileDcacheMisses, + ProfileIcacheMisses, + ProfileCacheMisses, + ProfileBranchMispredictions, + ProfileStoreInstructions, + ProfileFpInstructions, + ProfileIntegerInstructions, + Profile2Issue, + Profile3Issue, + Profile4Issue, + ProfileSpecialInstructions, + ProfileTotalCycles, + ProfileIcacheIssues, + ProfileDcacheAccesses, + ProfileMemoryBarrierCycles, + ProfileLoadLinkedIssues, + ProfileMaximum +} KPROFILE_SOURCE; + +/**** Information Classes ****/ + +/* + * File + */ +typedef enum _FILE_INFORMATION_CLASS +{ + FileDirectoryInformation = 1, + FileFullDirectoryInformation, + FileBothDirectoryInformation, + FileBasicInformation, + FileStandardInformation, + FileInternalInformation, + FileEaInformation, + FileAccessInformation, + FileNameInformation, + FileRenameInformation, + FileLinkInformation, + FileNamesInformation, + FileDispositionInformation, + FilePositionInformation, + FileFullEaInformation, + FileModeInformation, + FileAlignmentInformation, + FileAllInformation, + FileAllocationInformation, + FileEndOfFileInformation, + FileAlternateNameInformation, + FileStreamInformation, + FilePipeInformation, + FilePipeLocalInformation, + FilePipeRemoteInformation, + FileMailslotQueryInformation, + FileMailslotSetInformation, + FileCompressionInformation, + FileObjectIdInformation, + FileCompletionInformation, + FileMoveClusterInformation, + FileQuotaInformation, + FileReparsePointInformation, + FileNetworkOpenInformation, + FileAttributeTagInformation, + FileTrackingInformation, + FileIdBothDirectoryInformation, + FileIdFullDirectoryInformation, + FileValidDataLengthInformation, + FileShortNameInformation, + FileMaximumInformation +} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; + +/* + * File System + */ +typedef enum _FSINFOCLASS +{ + FileFsVolumeInformation = 1, + FileFsLabelInformation, + FileFsSizeInformation, + FileFsDeviceInformation, + FileFsAttributeInformation, + FileFsControlInformation, + FileFsFullSizeInformation, + FileFsObjectIdInformation, + FileFsDriverPathInformation, + FileFsMaximumInformation +} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS; + +/* + * Registry Key + */ +typedef enum _KEY_INFORMATION_CLASS +{ + KeyBasicInformation, + KeyNodeInformation, + KeyFullInformation, + KeyNameInformation, + KeyCachedInformation, + KeyFlagsInformation +} KEY_INFORMATION_CLASS; + +/* + * Registry Key Value + */ +typedef enum _KEY_VALUE_INFORMATION_CLASS +{ + KeyValueBasicInformation, + KeyValueFullInformation, + KeyValuePartialInformation, + KeyValueFullInformationAlign64, + KeyValuePartialInformationAlign64 +} KEY_VALUE_INFORMATION_CLASS; + +/* + * Registry Key Set + */ +typedef enum _KEY_SET_INFORMATION_CLASS +{ + KeyWriteTimeInformation, + KeyUserFlagsInformation, + MaxKeySetInfoClass +} KEY_SET_INFORMATION_CLASS; + +/* + * Process + */ +typedef enum _PROCESSINFOCLASS +{ + ProcessBasicInformation, + ProcessQuotaLimits, + ProcessIoCounters, + ProcessVmCounters, + ProcessTimes, + ProcessBasePriority, + ProcessRaisePriority, + ProcessDebugPort, + ProcessExceptionPort, + ProcessAccessToken, + ProcessLdtInformation, + ProcessLdtSize, + ProcessDefaultHardErrorMode, + ProcessIoPortHandlers, + ProcessPooledUsageAndLimits, + ProcessWorkingSetWatch, + ProcessUserModeIOPL, + ProcessEnableAlignmentFaultFixup, + ProcessPriorityClass, + ProcessWx86Information, + ProcessHandleCount, + ProcessAffinityMask, + ProcessPriorityBoost, + ProcessDeviceMap, + ProcessSessionInformation, + ProcessForegroundInformation, + ProcessWow64Information, + ProcessImageFileName, + ProcessLUIDDeviceMapsEnabled, + ProcessBreakOnTermination, + ProcessDebugObjectHandle, + ProcessDebugFlags, + ProcessHandleTracing, + MaxProcessInfoClass +} PROCESSINFOCLASS; + +/* + * Thread + */ +typedef enum _THREADINFOCLASS +{ + ThreadBasicInformation, + ThreadTimes, + ThreadPriority, + ThreadBasePriority, + ThreadAffinityMask, + ThreadImpersonationToken, + ThreadDescriptorTableEntry, + ThreadEnableAlignmentFaultFixup, + ThreadEventPair_Reusable, + ThreadQuerySetWin32StartAddress, + ThreadZeroTlsCell, + ThreadPerformanceCount, + ThreadAmILastThread, + ThreadIdealProcessor, + ThreadPriorityBoost, + ThreadSetTlsArrayAddress, + ThreadIsIoPending, + ThreadHideFromDebugger, + ThreadBreakOnTermination, + MaxThreadInfoClass +} THREADINFOCLASS; + +/* TYPES *********************************************************************/ + +/* Basic Types that aren't defined in User-Mode Headers */ +typedef CONST int CINT; +typedef CONST char *PCSZ; +typedef short CSHORT; +typedef CSHORT *PCSHORT; +typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS; + +/* Kernel Types used by Native APIs */ +typedef LONG KPRIORITY; +typedef LONG NTSTATUS, *PNTSTATUS; +typedef UCHAR KIRQL, *PKIRQL; +typedef ULONG KAFFINITY, *PKAFFINITY; +typedef ULONG_PTR KSPIN_LOCK, *PKSPIN_LOCK; +typedef struct _PEB *PPEB; +typedef ULONG KPROCESSOR_MODE; +typedef struct _OBJECT_TYPE *POBJECT_TYPE; +struct _ETHREAD; +struct _CSR_API_MESSAGE; +typedef ULONG EXECUTION_STATE; + +/* Basic NT Types */ +#if !defined(_NTSECAPI_H) && !defined(_SUBAUTH_H) +typedef struct _UNICODE_STRING +{ + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} UNICODE_STRING, *PUNICODE_STRING; +typedef const UNICODE_STRING* PCUNICODE_STRING; + +typedef struct _STRING +{ + USHORT Length; + USHORT MaximumLength; + PCHAR Buffer; +} STRING, *PSTRING; + +typedef struct _OBJECT_ATTRIBUTES +{ + ULONG Length; + HANDLE RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; + PVOID SecurityQualityOfService; +} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; +#endif + +typedef STRING ANSI_STRING; +typedef PSTRING PANSI_STRING; +typedef STRING OEM_STRING; +typedef PSTRING POEM_STRING; + +typedef struct _IO_STATUS_BLOCK +{ + union + { + NTSTATUS Status; + PVOID Pointer; + }; + ULONG_PTR Information; +} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; + +typedef VOID +(NTAPI *PIO_APC_ROUTINE)( + IN PVOID ApcContext, + IN PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG Reserved); + +typedef VOID +(NTAPI *PKNORMAL_ROUTINE)( + IN PVOID NormalContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2); + +typedef VOID +(NTAPI *PTIMER_APC_ROUTINE)( + IN PVOID TimerContext, + IN ULONG TimerLowValue, + IN LONG TimerHighValue); + +/* Kernel Types which are returned or used by Native API */ +typedef struct _OBJECT_NAME_INFORMATION +{ + UNICODE_STRING Name; +} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; + +typedef struct _IO_ERROR_LOG_PACKET +{ + UCHAR MajorFunctionCode; + UCHAR RetryCount; + USHORT DumpDataSize; + USHORT NumberOfStrings; + USHORT StringOffset; + USHORT EventCategory; + NTSTATUS ErrorCode; + ULONG UniqueErrorValue; + NTSTATUS FinalStatus; + ULONG SequenceNumber; + ULONG IoControlCode; + LARGE_INTEGER DeviceOffset; + ULONG DumpData[1]; +}IO_ERROR_LOG_PACKET, *PIO_ERROR_LOG_PACKET; + +typedef struct _IO_ERROR_LOG_MESSAGE +{ + USHORT Type; + USHORT Size; + USHORT DriverNameLength; + LARGE_INTEGER TimeStamp; + ULONG DriverNameOffset; + IO_ERROR_LOG_PACKET EntryData; +} IO_ERROR_LOG_MESSAGE, *PIO_ERROR_LOG_MESSAGE; + +typedef struct _CLIENT_ID +{ + HANDLE UniqueProcess; + HANDLE UniqueThread; +} CLIENT_ID, *PCLIENT_ID; + +typedef struct _KSYSTEM_TIME +{ + ULONG LowPart; + LONG High1Time; + LONG High2Time; +} KSYSTEM_TIME, *PKSYSTEM_TIME; + +typedef struct _TIME_FIELDS +{ + CSHORT Year; + CSHORT Month; + CSHORT Day; + CSHORT Hour; + CSHORT Minute; + CSHORT Second; + CSHORT Milliseconds; + CSHORT Weekday; +} TIME_FIELDS, *PTIME_FIELDS; + +typedef struct _VM_COUNTERS +{ + SIZE_T PeakVirtualSize; + SIZE_T VirtualSize; + ULONG PageFaultCount; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; +} VM_COUNTERS, *PVM_COUNTERS; + +typedef struct _VM_COUNTERS_EX +{ + SIZE_T PeakVirtualSize; + SIZE_T VirtualSize; + ULONG PageFaultCount; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + SIZE_T QuotaPeakPagedPoolUsage; + SIZE_T QuotaPagedPoolUsage; + SIZE_T QuotaPeakNonPagedPoolUsage; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; + SIZE_T PrivateUsage; +} VM_COUNTERS_EX, *PVM_COUNTERS_EX; + +/**** Information Types ****/ + +/* + * Registry Key Set + */ + +/* Class 0 */ +typedef struct _KEY_WRITE_TIME_INFORMATION +{ + LARGE_INTEGER LastWriteTime; +} KEY_WRITE_TIME_INFORMATION, *PKEY_WRITE_TIME_INFORMATION; + +/* Class 1 */ +typedef struct _KEY_USER_FLAGS_INFORMATION +{ + ULONG UserFlags; +} KEY_USER_FLAGS_INFORMATION, *PKEY_USER_FLAGS_INFORMATION; + +typedef struct _KEY_FULL_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG ClassOffset; + ULONG ClassLength; + ULONG SubKeys; + ULONG MaxNameLen; + ULONG MaxClassLen; + ULONG Values; + ULONG MaxValueNameLen; + ULONG MaxValueDataLen; + WCHAR Class[1]; +} KEY_FULL_INFORMATION, *PKEY_FULL_INFORMATION; + +typedef struct _KEY_NODE_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG ClassOffset; + ULONG ClassLength; + ULONG NameLength; + WCHAR Name[1]; +} KEY_NODE_INFORMATION, *PKEY_NODE_INFORMATION; + +/* + * File + */ + +/* Class 1 */ +typedef struct _FILE_BASIC_INFORMATION +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + ULONG FileAttributes; +} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION; + +/* Class 2 */ +typedef struct _FILE_STANDARD_INFORMATION +{ + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG NumberOfLinks; + BOOLEAN DeletePending; + BOOLEAN Directory; +} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION; + +typedef struct _FILE_NETWORK_OPEN_INFORMATION +{ + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + ULONG FileAttributes; +} FILE_NETWORK_OPEN_INFORMATION, *PFILE_NETWORK_OPEN_INFORMATION; + +typedef struct _FILE_EA_INFORMATION +{ + ULONG EaSize; +} FILE_EA_INFORMATION, *PFILE_EA_INFORMATION; + +typedef struct _FILE_COMPRESSION_INFORMATION +{ + LARGE_INTEGER CompressedFileSize; + USHORT CompressionFormat; + UCHAR CompressionUnitShift; + UCHAR ChunkShift; + UCHAR ClusterShift; + UCHAR Reserved[3]; +} FILE_COMPRESSION_INFORMATION, *PFILE_COMPRESSION_INFORMATION; + +typedef struct _FILE_POSITION_INFORMATION +{ + LARGE_INTEGER CurrentByteOffset; +} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION; + +typedef struct _FILE_DISPOSITION_INFORMATION +{ + BOOLEAN DeleteFile; +} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION; + +typedef struct _FILE_FULL_EA_INFORMATION +{ + ULONG NextEntryOffset; + UCHAR Flags; + UCHAR EaNameLength; + USHORT EaValueLength; + CHAR EaName[1]; +} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION; + +typedef struct _FILE_QUOTA_INFORMATION +{ + ULONG NextEntryOffset; + ULONG SidLength; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER QuotaUsed; + LARGE_INTEGER QuotaThreshold; + LARGE_INTEGER QuotaLimit; + SID Sid; +} FILE_QUOTA_INFORMATION, *PFILE_QUOTA_INFORMATION; + +typedef struct _FILE_INTERNAL_INFORMATION +{ + LARGE_INTEGER IndexNumber; +} FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION; + +typedef struct _FILE_RENAME_INFORMATION +{ + BOOLEAN ReplaceIfExists; + HANDLE RootDirectory; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION; + +typedef struct _FILE_PIPE_INFORMATION +{ + ULONG ReadMode; + ULONG CompletionMode; +} FILE_PIPE_INFORMATION, *PFILE_PIPE_INFORMATION; + +typedef struct _FILE_PIPE_LOCAL_INFORMATION +{ + ULONG NamedPipeType; + ULONG NamedPipeConfiguration; + ULONG MaximumInstances; + ULONG CurrentInstances; + ULONG InboundQuota; + ULONG ReadDataAvailable; + ULONG OutboundQuota; + ULONG WriteQuotaAvailable; + ULONG NamedPipeState; + ULONG NamedPipeEnd; +} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION; + +typedef struct _FILE_PIPE_REMOTE_INFORMATION +{ + LARGE_INTEGER CollectDataTime; + ULONG MaximumCollectionCount; +} FILE_PIPE_REMOTE_INFORMATION, *PFILE_PIPE_REMOTE_INFORMATION; + +typedef struct _FILE_MAILSLOT_QUERY_INFORMATION +{ + ULONG MaximumMessageSize; + ULONG MailslotQuota; + ULONG NextMessageSize; + ULONG MessagesAvailable; + LARGE_INTEGER ReadTimeout; +} FILE_MAILSLOT_QUERY_INFORMATION, *PFILE_MAILSLOT_QUERY_INFORMATION; + +typedef struct _FILE_MAILSLOT_SET_INFORMATION +{ + LARGE_INTEGER ReadTimeout; +} FILE_MAILSLOT_SET_INFORMATION, *PFILE_MAILSLOT_SET_INFORMATION; + +typedef struct _FILE_BOTH_DIR_INFORMATION +{ + ULONG NextEntryOffset; + ULONG FileIndex; + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + LARGE_INTEGER EndOfFile; + LARGE_INTEGER AllocationSize; + ULONG FileAttributes; + ULONG FileNameLength; + ULONG EaSize; + CCHAR ShortNameLength; + WCHAR ShortName[12]; + WCHAR FileName[1]; +} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION; + +typedef struct _FILE_COMPLETION_INFORMATION +{ + HANDLE Port; + PVOID Key; +} FILE_COMPLETION_INFORMATION, *PFILE_COMPLETION_INFORMATION; + +typedef struct _FILE_LINK_INFORMATION +{ + BOOLEAN ReplaceIfExists; + HANDLE RootDirectory; + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_LINK_INFORMATION, *PFILE_LINK_INFORMATION; + +typedef struct _FILE_NAME_INFORMATION +{ + ULONG FileNameLength; + WCHAR FileName[1]; +} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION; + +typedef struct _FILE_ALLOCATION_INFORMATION +{ + LARGE_INTEGER AllocationSize; +} FILE_ALLOCATION_INFORMATION, *PFILE_ALLOCATION_INFORMATION; + +typedef struct _FILE_END_OF_FILE_INFORMATION +{ + LARGE_INTEGER EndOfFile; +} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION; + +typedef struct _FILE_VALID_DATA_LENGTH_INFORMATION +{ + LARGE_INTEGER ValidDataLength; +} FILE_VALID_DATA_LENGTH_INFORMATION, *PFILE_VALID_DATA_LENGTH_INFORMATION; + +/* + * File System + */ +typedef struct _FILE_FS_DEVICE_INFORMATION +{ + DEVICE_TYPE DeviceType; + ULONG Characteristics; +} FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION; + +typedef struct _FILE_FS_ATTRIBUTE_INFORMATION +{ + ULONG FileSystemAttributes; + ULONG MaximumComponentNameLength; + ULONG FileSystemNameLength; + WCHAR FileSystemName[1]; +} FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION; + +typedef struct _FILE_FS_SIZE_INFORMATION +{ + LARGE_INTEGER TotalAllocationUnits; + LARGE_INTEGER AvailableAllocationUnits; + ULONG SectorsPerAllocationUnit; + ULONG BytesPerSector; +} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION; + +typedef struct _FILE_FS_LABEL_INFORMATION +{ + ULONG VolumeLabelLength; + WCHAR VolumeLabel[1]; +} FILE_FS_LABEL_INFORMATION, *PFILE_FS_LABEL_INFORMATION; + +typedef struct _FILE_FS_VOLUME_INFORMATION +{ + LARGE_INTEGER VolumeCreationTime; + ULONG VolumeSerialNumber; + ULONG VolumeLabelLength; + BOOLEAN SupportsObjects; + WCHAR VolumeLabel[1]; +} FILE_FS_VOLUME_INFORMATION, *PFILE_FS_VOLUME_INFORMATION; + +/* + * Registry Key Value + */ + +/* Class 0 */ +typedef struct _KEY_VALUE_ENTRY +{ + PUNICODE_STRING ValueName; + ULONG DataLength; + ULONG DataOffset; + ULONG Type; +} KEY_VALUE_ENTRY, *PKEY_VALUE_ENTRY; + +/* Class 1 */ +typedef struct _KEY_VALUE_PARTIAL_INFORMATION +{ + ULONG TitleIndex; + ULONG Type; + ULONG DataLength; + UCHAR Data[1]; +} KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION; + +/* Class 2 */ +typedef struct _KEY_VALUE_BASIC_INFORMATION +{ + ULONG TitleIndex; + ULONG Type; + ULONG NameLength; + WCHAR Name[1]; +} KEY_VALUE_BASIC_INFORMATION, *PKEY_VALUE_BASIC_INFORMATION; + +/* Class 3 */ +typedef struct _KEY_VALUE_FULL_INFORMATION +{ + ULONG TitleIndex; + ULONG Type; + ULONG DataOffset; + ULONG DataLength; + ULONG NameLength; + WCHAR Name[1]; +} KEY_VALUE_FULL_INFORMATION, *PKEY_VALUE_FULL_INFORMATION; + +/* + * Registry Key + */ + +/* Class 0 */ +typedef struct _KEY_BASIC_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG NameLength; + WCHAR Name[1]; +} KEY_BASIC_INFORMATION, *PKEY_BASIC_INFORMATION; + +/* File Pipe Structures for the FSCTLs */ +typedef struct _FILE_PIPE_WAIT_FOR_BUFFER +{ + LARGE_INTEGER Timeout; + ULONG NameLength; + BOOLEAN TimeoutSpecified; + WCHAR Name[1]; +} FILE_PIPE_WAIT_FOR_BUFFER, *PFILE_PIPE_WAIT_FOR_BUFFER; + +typedef struct _FILE_PIPE_PEEK_BUFFER +{ + ULONG NamedPipeState; + ULONG ReadDataAvailable; + ULONG NumberOfMessages; + ULONG MessageLength; + CHAR Data[1]; +} FILE_PIPE_PEEK_BUFFER, *PFILE_PIPE_PEEK_BUFFER; + +/* The Kerner/User Shared Data Structure */ +typedef struct _KUSER_SHARED_DATA +{ + ULONG TickCountLowDeprecated; + ULONG TickCountMultiplier; + volatile KSYSTEM_TIME InterruptTime; + volatile KSYSTEM_TIME SystemTime; + volatile KSYSTEM_TIME TimeZoneBias; + USHORT ImageNumberLow; + USHORT ImageNumberHigh; + WCHAR NtSystemRoot[260]; + ULONG MaxStackTraceDepth; + ULONG CryptoExponent; + ULONG TimeZoneId; + ULONG LargePageMinimum; + ULONG Reserved2[7]; + NT_PRODUCT_TYPE NtProductType; + BOOLEAN ProductTypeIsValid; + ULONG NtMajorVersion; + ULONG NtMinorVersion; + BOOLEAN ProcessorFeatures[PROCESSOR_FEATURE_MAX]; + ULONG Reserved1; + ULONG Reserved3; + volatile ULONG TimeSlip; + ALTERNATIVE_ARCHITECTURE_TYPE AlternativeArchitecture; + LARGE_INTEGER SystemExpirationDate; + ULONG SuiteMask; + BOOLEAN KdDebuggerEnabled; + volatile ULONG ActiveConsoleId; + volatile ULONG DismountCount; + ULONG ComPlusPackage; + ULONG LastSystemRITEventTickCount; + ULONG NumberOfPhysicalPages; + BOOLEAN SafeBootMode; + ULONG TraceLogging; + ULONGLONG Fill0; + ULONGLONG SystemCall[4]; + union { + volatile KSYSTEM_TIME TickCount; + volatile ULONG64 TickCountQuad; + }; +} KUSER_SHARED_DATA, *PKUSER_SHARED_DATA; + +/* Run-Time Library (RTL) Types */ +typedef struct _RTL_BITMAP +{ + ULONG SizeOfBitMap; + PULONG Buffer; +} RTL_BITMAP, *PRTL_BITMAP; + +typedef struct _RTL_BITMAP_RUN +{ + ULONG StartingIndex; + ULONG NumberOfBits; +} RTL_BITMAP_RUN, *PRTL_BITMAP_RUN; + +typedef struct _COMPRESSED_DATA_INFO +{ + USHORT CompressionFormatAndEngine; + UCHAR CompressionUnitShift; + UCHAR ChunkShift; + UCHAR ClusterShift; + UCHAR Reserved; + USHORT NumberOfChunks; + ULONG CompressedChunkSizes[ANYSIZE_ARRAY]; +} COMPRESSED_DATA_INFO, *PCOMPRESSED_DATA_INFO; + +typedef struct _GENERATE_NAME_CONTEXT +{ + USHORT Checksum; + BOOLEAN CheckSumInserted; + UCHAR NameLength; + WCHAR NameBuffer[8]; + ULONG ExtensionLength; + WCHAR ExtensionBuffer[4]; + ULONG LastIndexValue; +} GENERATE_NAME_CONTEXT, *PGENERATE_NAME_CONTEXT; + +typedef struct _RTL_SPLAY_LINKS +{ + struct _RTL_SPLAY_LINKS *Parent; + struct _RTL_SPLAY_LINKS *LeftChild; + struct _RTL_SPLAY_LINKS *RightChild; +} RTL_SPLAY_LINKS, *PRTL_SPLAY_LINKS; + +struct _RTL_AVL_TABLE; +struct _RTL_GENERIC_TABLE; + +typedef NTSTATUS +(NTAPI *PRTL_AVL_MATCH_FUNCTION)( + struct _RTL_AVL_TABLE *Table, + PVOID UserData, + PVOID MatchData +); + +typedef RTL_GENERIC_COMPARE_RESULTS +(NTAPI *PRTL_AVL_COMPARE_ROUTINE) ( + struct _RTL_AVL_TABLE *Table, + PVOID FirstStruct, + PVOID SecondStruct +); + +typedef RTL_GENERIC_COMPARE_RESULTS +(NTAPI *PRTL_GENERIC_COMPARE_ROUTINE) ( + struct _RTL_GENERIC_TABLE *Table, + PVOID FirstStruct, + PVOID SecondStruct +); + +typedef PVOID +(NTAPI *PRTL_GENERIC_ALLOCATE_ROUTINE) ( + struct _RTL_GENERIC_TABLE *Table, + LONG ByteSize +); + +typedef VOID +(NTAPI *PRTL_GENERIC_FREE_ROUTINE) ( + struct _RTL_GENERIC_TABLE *Table, + PVOID Buffer +); + +typedef VOID +(NTAPI *PRTL_AVL_ALLOCATE_ROUTINE) ( + struct _RTL_AVL_TABLE *Table, + LONG ByteSize +); + +typedef VOID +(NTAPI *PRTL_AVL_FREE_ROUTINE) ( + struct _RTL_AVL_TABLE *Table, + PVOID Buffer +); + +typedef struct _RTL_GENERIC_TABLE +{ + PRTL_SPLAY_LINKS TableRoot; + LIST_ENTRY InsertOrderList; + PLIST_ENTRY OrderedPointer; + ULONG WhichOrderedElement; + ULONG NumberGenericTableElements; + PRTL_GENERIC_COMPARE_ROUTINE CompareRoutine; + PRTL_GENERIC_ALLOCATE_ROUTINE AllocateRoutine; + PRTL_GENERIC_FREE_ROUTINE FreeRoutine; + PVOID TableContext; +} RTL_GENERIC_TABLE, *PRTL_GENERIC_TABLE; + +typedef struct _RTL_BALANCED_LINKS +{ + struct _RTL_BALANCED_LINKS *Parent; + struct _RTL_BALANCED_LINKS *LeftChild; + struct _RTL_BALANCED_LINKS *RightChild; + CHAR Balance; + UCHAR Reserved[3]; +} RTL_BALANCED_LINKS, *PRTL_BALANCED_LINKS; + +typedef struct _RTL_AVL_TABLE +{ + RTL_BALANCED_LINKS BalancedRoot; + PVOID OrderedPointer; + ULONG WhichOrderedElement; + ULONG NumberGenericTableElements; + ULONG DepthOfTree; + PRTL_BALANCED_LINKS RestartKey; + ULONG DeleteCount; + PRTL_AVL_COMPARE_ROUTINE CompareRoutine; + PRTL_AVL_ALLOCATE_ROUTINE AllocateRoutine; + PRTL_AVL_FREE_ROUTINE FreeRoutine; + PVOID TableContext; +} RTL_AVL_TABLE, *PRTL_AVL_TABLE; + +typedef NTSTATUS +(NTAPI *PRTL_QUERY_REGISTRY_ROUTINE)( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext +); + +typedef struct _RTL_QUERY_REGISTRY_TABLE +{ + PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine; + ULONG Flags; + PWSTR Name; + PVOID EntryContext; + ULONG DefaultType; + PVOID DefaultData; + ULONG DefaultLength; +} RTL_QUERY_REGISTRY_TABLE, *PRTL_QUERY_REGISTRY_TABLE; + +typedef struct _UNICODE_PREFIX_TABLE_ENTRY +{ + CSHORT NodeTypeCode; + CSHORT NameLength; + struct _UNICODE_PREFIX_TABLE_ENTRY *NextPrefixTree; + struct _UNICODE_PREFIX_TABLE_ENTRY *CaseMatch; + RTL_SPLAY_LINKS Links; + PUNICODE_STRING Prefix; +} UNICODE_PREFIX_TABLE_ENTRY, *PUNICODE_PREFIX_TABLE_ENTRY; + +typedef struct _UNICODE_PREFIX_TABLE +{ + CSHORT NodeTypeCode; + CSHORT NameLength; + PUNICODE_PREFIX_TABLE_ENTRY NextPrefixTree; + PUNICODE_PREFIX_TABLE_ENTRY LastNextEntry; +} UNICODE_PREFIX_TABLE, *PUNICODE_PREFIX_TABLE; + +/* FIXME - need FAST_MUTEX and PHANDLE_TABLE for RTL_ATOM_TABLE in umode! */ +typedef void *FAST_MUTEX; +typedef void *PHANDLE_TABLE; + +typedef OSVERSIONINFOW RTL_OSVERSIONINFOW; +typedef LPOSVERSIONINFOW PRTL_OSVERSIONINFOW; +typedef OSVERSIONINFOEXW RTL_OSVERSIONINFOEXW; +typedef LPOSVERSIONINFOEXW PRTL_OSVERSIONINFOEXW; + +#endif diff --git a/reactos/include/ndk/zwfuncs.h b/reactos/include/ndk/zwfuncs.h index acb19cc2e57..d09c55d21ee 100644 --- a/reactos/include/ndk/zwfuncs.h +++ b/reactos/include/ndk/zwfuncs.h @@ -1,4053 +1,4053 @@ -/* - * PROJECT: ReactOS Native Headers - * FILE: include/ndk/zwfuncs.h - * PURPOSE: Defintions for Native Functions not defined in DDK/IFS - * PROGRAMMER: Alex Ionescu (alex@relsoft.net) - * UPDATE HISTORY: - * Created 06/10/04 - */ -#ifndef _ZWFUNCS_H -#define _ZWFUNCS_H - -/* DEPENDENCIES **************************************************************/ -#include "lpctypes.h" -#include "zwtypes.h" -#include "kdtypes.h" -#define _WMIKM_ -#include - -/* FUNCTION TYPES ************************************************************/ - -/* PROTOTYPES ****************************************************************/ - -NTSTATUS -STDCALL -NtAcceptConnectPort( - PHANDLE PortHandle, - HANDLE NamedPortHandle, - PLPC_MESSAGE ServerReply, - BOOLEAN AcceptIt, - PLPC_SECTION_WRITE WriteMap, - PLPC_SECTION_READ ReadMap -); - -NTSTATUS -STDCALL -NtAccessCheck( - IN PSECURITY_DESCRIPTOR SecurityDescriptor, - IN HANDLE ClientToken, - IN ACCESS_MASK DesiredAcces, - IN PGENERIC_MAPPING GenericMapping, - OUT PPRIVILEGE_SET PrivilegeSet, - OUT PULONG ReturnLength, - OUT PACCESS_MASK GrantedAccess, - OUT PNTSTATUS AccessStatus -); - -NTSTATUS -STDCALL -ZwAccessCheck( - IN PSECURITY_DESCRIPTOR SecurityDescriptor, - IN HANDLE ClientToken, - IN ACCESS_MASK DesiredAcces, - IN PGENERIC_MAPPING GenericMapping, - OUT PPRIVILEGE_SET PrivilegeSet, - OUT PULONG ReturnLength, - OUT PACCESS_MASK GrantedAccess, - OUT PNTSTATUS AccessStatus -); - -NTSTATUS -STDCALL -NtAccessCheckAndAuditAlarm( - IN PUNICODE_STRING SubsystemName, - IN PHANDLE ObjectHandle, - IN PUNICODE_STRING ObjectTypeName, - IN PUNICODE_STRING ObjectName, - IN PSECURITY_DESCRIPTOR SecurityDescriptor, - IN ACCESS_MASK DesiredAccess, - IN PGENERIC_MAPPING GenericMapping, - IN BOOLEAN ObjectCreation, - OUT PACCESS_MASK GrantedAccess, - OUT PNTSTATUS AccessStatus, - OUT PBOOLEAN GenerateOnClose -); - -NTSTATUS -STDCALL -NtAddAtom( - IN PWSTR AtomName, - IN ULONG AtomNameLength, - IN OUT PRTL_ATOM Atom -); - -NTSTATUS -STDCALL -ZwAddAtom( - IN PWSTR AtomName, - IN ULONG AtomNameLength, - IN OUT PRTL_ATOM Atom -); - -NTSTATUS -STDCALL -NtAddBootEntry( - IN PUNICODE_STRING EntryName, - IN PUNICODE_STRING EntryValue -); - -NTSTATUS -STDCALL -ZwAddBootEntry( - IN PUNICODE_STRING EntryName, - IN PUNICODE_STRING EntryValue -); - -NTSTATUS -STDCALL -NtAdjustGroupsToken( - IN HANDLE TokenHandle, - IN BOOLEAN ResetToDefault, - IN PTOKEN_GROUPS NewState, - IN ULONG BufferLength, - OUT PTOKEN_GROUPS PreviousState OPTIONAL, - OUT PULONG ReturnLength -); - -NTSTATUS -STDCALL -ZwAdjustGroupsToken( - IN HANDLE TokenHandle, - IN BOOLEAN ResetToDefault, - IN PTOKEN_GROUPS NewState, - IN ULONG BufferLength, - OUT PTOKEN_GROUPS PreviousState, - OUT PULONG ReturnLength -); - -NTSTATUS -STDCALL -NtAdjustPrivilegesToken( - IN HANDLE TokenHandle, - IN BOOLEAN DisableAllPrivileges, - IN PTOKEN_PRIVILEGES NewState, - IN ULONG BufferLength, - OUT PTOKEN_PRIVILEGES PreviousState, - OUT PULONG ReturnLength -); - -NTSTATUS -STDCALL -ZwAdjustPrivilegesToken( - IN HANDLE TokenHandle, - IN BOOLEAN DisableAllPrivileges, - IN PTOKEN_PRIVILEGES NewState, - IN ULONG BufferLength, - OUT PTOKEN_PRIVILEGES PreviousState, - OUT PULONG ReturnLength -); - -NTSTATUS -STDCALL -NtAlertResumeThread( - IN HANDLE ThreadHandle, - OUT PULONG SuspendCount -); - -NTSTATUS -STDCALL -ZwAlertResumeThread( - IN HANDLE ThreadHandle, - OUT PULONG SuspendCount -); - -NTSTATUS -STDCALL -NtAlertThread( - IN HANDLE ThreadHandle -); - -NTSTATUS -STDCALL -ZwAlertThread( - IN HANDLE ThreadHandle -); - -NTSTATUS -STDCALL -NtAllocateLocallyUniqueId( - OUT LUID *LocallyUniqueId -); - -NTSTATUS -STDCALL -ZwAllocateLocallyUniqueId( - OUT PLUID Luid -); - -NTSTATUS -STDCALL -NtAllocateUuids( - PULARGE_INTEGER Time, - PULONG Range, - PULONG Sequence, - PUCHAR Seed -); - -NTSTATUS -STDCALL -ZwAllocateUuids( - PULARGE_INTEGER Time, - PULONG Range, - PULONG Sequence, - PUCHAR Seed -); - -NTSTATUS -STDCALL -NtAllocateVirtualMemory( - IN HANDLE ProcessHandle, - IN OUT PVOID *BaseAddress, - IN ULONG ZeroBits, - IN OUT PULONG RegionSize, - IN ULONG AllocationType, - IN ULONG Protect -); - -NTSTATUS -STDCALL -ZwAllocateVirtualMemory( - IN HANDLE ProcessHandle, - IN OUT PVOID *BaseAddress, - IN ULONG ZeroBits, - IN OUT PULONG RegionSize, - IN ULONG AllocationType, - IN ULONG Protect -); - -NTSTATUS -STDCALL -NtAssignProcessToJobObject( - HANDLE JobHandle, - HANDLE ProcessHandle -); - -NTSTATUS -STDCALL -ZwAssignProcessToJobObject( - HANDLE JobHandle, - HANDLE ProcessHandle -); - -NTSTATUS -STDCALL -NtCallbackReturn( - PVOID Result, - ULONG ResultLength, - NTSTATUS Status -); - -NTSTATUS -STDCALL -ZwCallbackReturn( - PVOID Result, - ULONG ResultLength, - NTSTATUS Status -); - -NTSTATUS -STDCALL -NtCancelIoFile( - IN HANDLE FileHandle, - OUT PIO_STATUS_BLOCK IoStatusBlock -); - -NTSTATUS -STDCALL -ZwCancelIoFile( - IN HANDLE FileHandle, - OUT PIO_STATUS_BLOCK IoStatusBlock -); - -NTSTATUS -STDCALL -NtCancelTimer( - IN HANDLE TimerHandle, - OUT PBOOLEAN CurrentState OPTIONAL -); - -NTSTATUS -STDCALL -NtClearEvent( - IN HANDLE EventHandle -); - -NTSTATUS -STDCALL -ZwClearEvent( - IN HANDLE EventHandle -); - -NTSTATUS -STDCALL -NtCreateJobObject( - PHANDLE JobHandle, - ACCESS_MASK DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -ZwCreateJobObject( - PHANDLE JobHandle, - ACCESS_MASK DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -NtClose( - IN HANDLE Handle -); - -NTSTATUS -STDCALL -ZwClose( - IN HANDLE Handle -); - -NTSTATUS -STDCALL -NtCloseObjectAuditAlarm( - IN PUNICODE_STRING SubsystemName, - IN PVOID HandleId, - IN BOOLEAN GenerateOnClose -); - -NTSTATUS -STDCALL -ZwCloseObjectAuditAlarm( - IN PUNICODE_STRING SubsystemName, - IN PVOID HandleId, - IN BOOLEAN GenerateOnClose -); - -NTSTATUS -STDCALL -NtCompleteConnectPort( - HANDLE PortHandle -); - -NTSTATUS -STDCALL -ZwCompleteConnectPort( - HANDLE PortHandle -); - -NTSTATUS -STDCALL -NtConnectPort( - PHANDLE PortHandle, - PUNICODE_STRING PortName, - PSECURITY_QUALITY_OF_SERVICE SecurityQos, - PLPC_SECTION_WRITE SectionInfo, - PLPC_SECTION_READ MapInfo, - PULONG MaxMessageSize, - PVOID ConnectInfo, - PULONG ConnectInfoLength -); - -NTSTATUS -STDCALL -ZwConnectPort( - PHANDLE PortHandle, - PUNICODE_STRING PortName, - PSECURITY_QUALITY_OF_SERVICE SecurityQos, - PLPC_SECTION_WRITE SectionInfo, - PLPC_SECTION_READ MapInfo, - PULONG MaxMessageSize, - PVOID ConnectInfo, - PULONG ConnectInfoLength -); - -NTSTATUS -STDCALL -NtContinue( - IN PCONTEXT Context, - IN BOOLEAN TestAlert -); - -NTSTATUS -STDCALL -ZwContinue( - IN PCONTEXT Context, - IN CINT IrqLevel -); - -NTSTATUS -STDCALL -NtCreateDirectoryObject( - OUT PHANDLE DirectoryHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -ZwCreateDirectoryObject( - OUT PHANDLE DirectoryHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -NtCreateEvent( - OUT PHANDLE EventHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN EVENT_TYPE EventType, - IN BOOLEAN InitialState -); - -NTSTATUS -STDCALL -ZwCreateEvent( - OUT PHANDLE EventHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN EVENT_TYPE EventType, - IN BOOLEAN InitialState -); - -NTSTATUS -STDCALL -NtCreateEventPair( - OUT PHANDLE EventPairHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -ZwCreateEventPair( - OUT PHANDLE EventPairHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -NtCreateFile( - OUT PHANDLE FileHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN PLARGE_INTEGER AllocationSize OPTIONAL, - IN ULONG FileAttributes, - IN ULONG ShareAccess, - IN ULONG CreateDisposition, - IN ULONG CreateOptions, - IN PVOID EaBuffer OPTIONAL, - IN ULONG EaLength -); - -NTSTATUS -STDCALL -ZwCreateFile( - OUT PHANDLE FileHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN PLARGE_INTEGER AllocationSize OPTIONAL, - IN ULONG FileAttributes, - IN ULONG ShareAccess, - IN ULONG CreateDisposition, - IN ULONG CreateOptions, - IN PVOID EaBuffer OPTIONAL, - IN ULONG EaLength -); - -NTSTATUS -STDCALL -NtCreateIoCompletion( - OUT PHANDLE IoCompletionHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN ULONG NumberOfConcurrentThreads - ); - -NTSTATUS -STDCALL -ZwCreateIoCompletion( - OUT PHANDLE IoCompletionHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN ULONG NumberOfConcurrentThreads - ); - -NTSTATUS -STDCALL -NtCreateKey( - OUT PHANDLE KeyHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN ULONG TitleIndex, - IN PUNICODE_STRING Class OPTIONAL, - IN ULONG CreateOptions, - IN PULONG Disposition OPTIONAL -); - -NTSTATUS -STDCALL -ZwCreateKey( - OUT PHANDLE KeyHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN ULONG TitleIndex, - IN PUNICODE_STRING Class OPTIONAL, - IN ULONG CreateOptions, - IN PULONG Disposition OPTIONAL -); - -NTSTATUS -STDCALL -NtCreateMailslotFile( - OUT PHANDLE MailSlotFileHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG FileAttributes, - IN ULONG ShareAccess, - IN ULONG MaxMessageSize, - IN PLARGE_INTEGER TimeOut -); - -NTSTATUS -STDCALL -ZwCreateMailslotFile( - OUT PHANDLE MailSlotFileHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG FileAttributes, - IN ULONG ShareAccess, - IN ULONG MaxMessageSize, - IN PLARGE_INTEGER TimeOut -); - -NTSTATUS -STDCALL -NtCreateMutant( - OUT PHANDLE MutantHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN BOOLEAN InitialOwner -); - -NTSTATUS -STDCALL -ZwCreateMutant( - OUT PHANDLE MutantHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN BOOLEAN InitialOwner -); - -NTSTATUS -STDCALL -NtCreateNamedPipeFile( - OUT PHANDLE NamedPipeFileHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG ShareAccess, - IN ULONG CreateDisposition, - IN ULONG CreateOptions, - IN ULONG WriteModeMessage, - IN ULONG ReadModeMessage, - IN ULONG NonBlocking, - IN ULONG MaxInstances, - IN ULONG InBufferSize, - IN ULONG OutBufferSize, - IN PLARGE_INTEGER DefaultTimeOut -); - -NTSTATUS -STDCALL -ZwCreateNamedPipeFile( - OUT PHANDLE NamedPipeFileHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG ShareAccess, - IN ULONG CreateDisposition, - IN ULONG CreateOptions, - IN ULONG WriteModeMessage, - IN ULONG ReadModeMessage, - IN ULONG NonBlocking, - IN ULONG MaxInstances, - IN ULONG InBufferSize, - IN ULONG OutBufferSize, - IN PLARGE_INTEGER DefaultTimeOut -); - -NTSTATUS -STDCALL -NtCreatePagingFile( - IN PUNICODE_STRING FileName, - IN PLARGE_INTEGER InitialSize, - IN PLARGE_INTEGER MaxiumSize, - IN ULONG Reserved -); - -NTSTATUS -STDCALL -ZwCreatePagingFile( - IN PUNICODE_STRING FileName, - IN PLARGE_INTEGER InitialSize, - IN PLARGE_INTEGER MaxiumSize, - IN ULONG Reserved -); - -NTSTATUS -STDCALL -NtCreatePort( - PHANDLE PortHandle, - POBJECT_ATTRIBUTES ObjectAttributes, - ULONG MaxConnectInfoLength, - ULONG MaxDataLength, - ULONG NPMessageQueueSize OPTIONAL -); - -NTSTATUS -STDCALL -NtCreatePort( - PHANDLE PortHandle, - POBJECT_ATTRIBUTES ObjectAttributes, - ULONG MaxConnectInfoLength, - ULONG MaxDataLength, - ULONG NPMessageQueueSize OPTIONAL -); - -NTSTATUS -STDCALL -NtCreateProcess( - OUT PHANDLE ProcessHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - IN HANDLE ParentProcess, - IN BOOLEAN InheritObjectTable, - IN HANDLE SectionHandle OPTIONAL, - IN HANDLE DebugPort OPTIONAL, - IN HANDLE ExceptionPort OPTIONAL -); - -NTSTATUS -STDCALL -ZwCreateProcess( - OUT PHANDLE ProcessHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - IN HANDLE ParentProcess, - IN BOOLEAN InheritObjectTable, - IN HANDLE SectionHandle OPTIONAL, - IN HANDLE DebugPort OPTIONAL, - IN HANDLE ExceptionPort OPTIONAL -); - -NTSTATUS -STDCALL -NtCreateProfile( - OUT PHANDLE ProfileHandle, - IN HANDLE ProcessHandle, - IN PVOID ImageBase, - IN ULONG ImageSize, - IN ULONG Granularity, - OUT PVOID Buffer, - IN ULONG ProfilingSize, - IN KPROFILE_SOURCE Source, - IN KAFFINITY ProcessorMask -); - -NTSTATUS -STDCALL -ZwCreateProfile( - OUT PHANDLE ProfileHandle, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN ULONG ImageBase, - IN ULONG ImageSize, - IN ULONG Granularity, - OUT PVOID Buffer, - IN ULONG ProfilingSize, - IN ULONG ClockSource, - IN ULONG ProcessorMask -); - -NTSTATUS -STDCALL -NtCreateSection( - OUT PHANDLE SectionHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - IN PLARGE_INTEGER MaximumSize OPTIONAL, - IN ULONG SectionPageProtection OPTIONAL, - IN ULONG AllocationAttributes, - IN HANDLE FileHandle OPTIONAL -); - -NTSTATUS -STDCALL -ZwCreateSection( - OUT PHANDLE SectionHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - IN PLARGE_INTEGER MaximumSize OPTIONAL, - IN ULONG SectionPageProtection OPTIONAL, - IN ULONG AllocationAttributes, - IN HANDLE FileHandle OPTIONAL -); - -NTSTATUS -STDCALL -NtCreateSemaphore( - OUT PHANDLE SemaphoreHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - IN LONG InitialCount, - IN LONG MaximumCount -); - -NTSTATUS -STDCALL -ZwCreateSemaphore( - OUT PHANDLE SemaphoreHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - IN LONG InitialCount, - IN LONG MaximumCount -); - -NTSTATUS -STDCALL -NtCreateSymbolicLinkObject( - OUT PHANDLE SymbolicLinkHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN PUNICODE_STRING Name -); - -NTSTATUS -STDCALL -ZwCreateSymbolicLinkObject( - OUT PHANDLE SymbolicLinkHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN PUNICODE_STRING Name -); - -NTSTATUS -STDCALL -NtCreateThread( - OUT PHANDLE ThreadHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - IN HANDLE ProcessHandle, - OUT PCLIENT_ID ClientId, - IN PCONTEXT ThreadContext, - IN PINITIAL_TEB UserStack, - IN BOOLEAN CreateSuspended -); - -NTSTATUS -STDCALL -ZwCreateThread( - OUT PHANDLE ThreadHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - IN HANDLE ProcessHandle, - OUT PCLIENT_ID ClientId, - IN PCONTEXT ThreadContext, - IN PINITIAL_TEB UserStack, - IN BOOLEAN CreateSuspended -); - -NTSTATUS -STDCALL -NtCreateTimer( - OUT PHANDLE TimerHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - IN TIMER_TYPE TimerType -); - -NTSTATUS -STDCALL -ZwCreateTimer( - OUT PHANDLE TimerHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - IN TIMER_TYPE TimerType -); - -NTSTATUS -STDCALL -NtCreateToken( - OUT PHANDLE TokenHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN TOKEN_TYPE TokenType, - IN PLUID AuthenticationId, - IN PLARGE_INTEGER ExpirationTime, - IN PTOKEN_USER TokenUser, - IN PTOKEN_GROUPS TokenGroups, - IN PTOKEN_PRIVILEGES TokenPrivileges, - IN PTOKEN_OWNER TokenOwner, - IN PTOKEN_PRIMARY_GROUP TokenPrimaryGroup, - IN PTOKEN_DEFAULT_DACL TokenDefaultDacl, - IN PTOKEN_SOURCE TokenSource -); - -NTSTATUS -STDCALL -ZwCreateToken( - OUT PHANDLE TokenHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN TOKEN_TYPE TokenType, - IN PLUID AuthenticationId, - IN PLARGE_INTEGER ExpirationTime, - IN PTOKEN_USER TokenUser, - IN PTOKEN_GROUPS TokenGroups, - IN PTOKEN_PRIVILEGES TokenPrivileges, - IN PTOKEN_OWNER TokenOwner, - IN PTOKEN_PRIMARY_GROUP TokenPrimaryGroup, - IN PTOKEN_DEFAULT_DACL TokenDefaultDacl, - IN PTOKEN_SOURCE TokenSource -); - -NTSTATUS -STDCALL -NtCreateWaitablePort( - PHANDLE PortHandle, - POBJECT_ATTRIBUTES ObjectAttributes, - ULONG MaxConnectInfoLength, - ULONG MaxDataLength, - ULONG NPMessageQueueSize OPTIONAL -); - -NTSTATUS -STDCALL -ZwCreateWaitablePort( - PHANDLE PortHandle, - POBJECT_ATTRIBUTES ObjectAttributes, - ULONG MaxConnectInfoLength, - ULONG MaxDataLength, - ULONG NPMessageQueueSize OPTIONAL -); - -NTSTATUS -STDCALL -NtDelayExecution( - IN BOOLEAN Alertable, - IN LARGE_INTEGER *Interval -); - -NTSTATUS -STDCALL -ZwDelayExecution( - IN BOOLEAN Alertable, - IN LARGE_INTEGER *Interval -); - -NTSTATUS -STDCALL -NtDeleteAtom( - IN RTL_ATOM Atom -); - -NTSTATUS -STDCALL -ZwDeleteAtom( - IN RTL_ATOM Atom -); - -NTSTATUS -STDCALL -NtDeleteBootEntry( - IN PUNICODE_STRING EntryName, - IN PUNICODE_STRING EntryValue -); - -NTSTATUS -STDCALL -ZwDeleteBootEntry( - IN PUNICODE_STRING EntryName, - IN PUNICODE_STRING EntryValue -); - -NTSTATUS -STDCALL -NtDeleteFile( - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -ZwDeleteFile( - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -NtDeleteKey( - IN HANDLE KeyHandle -); - -NTSTATUS -STDCALL -ZwDeleteKey( - IN HANDLE KeyHandle -); - -NTSTATUS -STDCALL -NtDeleteObjectAuditAlarm( - IN PUNICODE_STRING SubsystemName, - IN PVOID HandleId, - IN BOOLEAN GenerateOnClose -); - -NTSTATUS -STDCALL -ZwDeleteObjectAuditAlarm( - IN PUNICODE_STRING SubsystemName, - IN PVOID HandleId, - IN BOOLEAN GenerateOnClose -); - -NTSTATUS -STDCALL -NtDeleteValueKey( - IN HANDLE KeyHandle, - IN PUNICODE_STRING ValueName -); - -NTSTATUS -STDCALL -ZwDeleteValueKey( - IN HANDLE KeyHandle, - IN PUNICODE_STRING ValueName -); - -NTSTATUS -STDCALL -NtDeviceIoControlFile( - IN HANDLE DeviceHandle, - IN HANDLE Event OPTIONAL, - IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, - IN PVOID UserApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG IoControlCode, - IN PVOID InputBuffer, - IN ULONG InputBufferSize, - OUT PVOID OutputBuffer, - IN ULONG OutputBufferSize -); - -NTSTATUS -STDCALL -ZwDeviceIoControlFile( - IN HANDLE DeviceHandle, - IN HANDLE Event OPTIONAL, - IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, - IN PVOID UserApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG IoControlCode, - IN PVOID InputBuffer, - IN ULONG InputBufferSize, - OUT PVOID OutputBuffer, - IN ULONG OutputBufferSize -); - -NTSTATUS -STDCALL -NtDisplayString( - IN PUNICODE_STRING DisplayString -); - -NTSTATUS -STDCALL -ZwDisplayString( - IN PUNICODE_STRING DisplayString -); - -NTSTATUS -STDCALL -NtDuplicateObject( - IN HANDLE SourceProcessHandle, - IN HANDLE SourceHandle, - IN HANDLE TargetProcessHandle, - OUT PHANDLE TargetHandle, - IN ACCESS_MASK DesiredAccess, - IN ULONG HandleAttributes, - IN ULONG Options -); - -NTSTATUS -STDCALL -ZwDuplicateObject( - IN HANDLE SourceProcessHandle, - IN HANDLE SourceHandle, - IN HANDLE TargetProcessHandle, - OUT PHANDLE TargetHandle, - IN ACCESS_MASK DesiredAccess, - IN ULONG HandleAttributes, - IN ULONG Options -); - -NTSTATUS -STDCALL -NtDuplicateToken( - IN HANDLE ExistingTokenHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, - IN BOOLEAN EffectiveOnly, - IN TOKEN_TYPE TokenType, - OUT PHANDLE NewTokenHandle -); - -NTSTATUS -STDCALL -NtEnumerateBootEntries( - IN ULONG Unknown1, - IN ULONG Unknown2 -); - -NTSTATUS -STDCALL -ZwEnumerateBootEntries( - IN ULONG Unknown1, - IN ULONG Unknown2 -); - -NTSTATUS -STDCALL -NtEnumerateKey( - IN HANDLE KeyHandle, - IN ULONG Index, - IN KEY_INFORMATION_CLASS KeyInformationClass, - OUT PVOID KeyInformation, - IN ULONG Length, - OUT PULONG ResultLength -); - -NTSTATUS -STDCALL -ZwEnumerateKey( - IN HANDLE KeyHandle, - IN ULONG Index, - IN KEY_INFORMATION_CLASS KeyInformationClass, - OUT PVOID KeyInformation, - IN ULONG Length, - OUT PULONG ResultLength -); - -NTSTATUS -STDCALL -NtEnumerateValueKey( - IN HANDLE KeyHandle, - IN ULONG Index, - IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, - OUT PVOID KeyValueInformation, - IN ULONG Length, - OUT PULONG ResultLength -); - -NTSTATUS -STDCALL -ZwEnumerateValueKey( - IN HANDLE KeyHandle, - IN ULONG Index, - IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, - OUT PVOID KeyValueInformation, - IN ULONG Length, - OUT PULONG ResultLength -); - -NTSTATUS -STDCALL -NtExtendSection( - IN HANDLE SectionHandle, - IN PLARGE_INTEGER NewMaximumSize -); - -NTSTATUS -STDCALL -ZwExtendSection( - IN HANDLE SectionHandle, - IN PLARGE_INTEGER NewMaximumSize -); - -NTSTATUS -STDCALL -NtFindAtom( - IN PWSTR AtomName, - IN ULONG AtomNameLength, - OUT PRTL_ATOM Atom OPTIONAL -); - -NTSTATUS -STDCALL -ZwFindAtom( - IN PWSTR AtomName, - IN ULONG AtomNameLength, - OUT PRTL_ATOM Atom OPTIONAL -); - -NTSTATUS -STDCALL -NtFlushBuffersFile( - IN HANDLE FileHandle, - OUT PIO_STATUS_BLOCK IoStatusBlock -); - -NTSTATUS -STDCALL -ZwFlushBuffersFile( - IN HANDLE FileHandle, - OUT PIO_STATUS_BLOCK IoStatusBlock -); - -NTSTATUS -STDCALL -NtFlushInstructionCache( - IN HANDLE ProcessHandle, - IN PVOID BaseAddress, - IN UINT NumberOfBytesToFlush -); - -NTSTATUS -STDCALL -NtFlushKey( - IN HANDLE KeyHandle -); - -NTSTATUS -STDCALL -ZwFlushKey( - IN HANDLE KeyHandle -); - -NTSTATUS -STDCALL -NtFlushVirtualMemory( - IN HANDLE ProcessHandle, - IN PVOID BaseAddress, - IN ULONG NumberOfBytesToFlush, - OUT PULONG NumberOfBytesFlushed OPTIONAL -); - -NTSTATUS -STDCALL -NtFlushWriteBuffer(VOID); - -NTSTATUS -STDCALL -ZwFlushWriteBuffer(VOID); - -NTSTATUS -STDCALL -NtFreeVirtualMemory( - IN HANDLE ProcessHandle, - IN PVOID *BaseAddress, - IN PULONG RegionSize, - IN ULONG FreeType -); - -NTSTATUS -STDCALL -ZwFreeVirtualMemory( - IN HANDLE ProcessHandle, - IN PVOID *BaseAddress, - IN PULONG RegionSize, - IN ULONG FreeType -); - -NTSTATUS -STDCALL -NtFsControlFile( - IN HANDLE DeviceHandle, - IN HANDLE Event OPTIONAL, - IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, - IN PVOID ApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG IoControlCode, - IN PVOID InputBuffer, - IN ULONG InputBufferSize, - OUT PVOID OutputBuffer, - IN ULONG OutputBufferSize -); - -NTSTATUS -STDCALL -ZwFsControlFile( - IN HANDLE DeviceHandle, - IN HANDLE Event OPTIONAL, - IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, - IN PVOID ApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG IoControlCode, - IN PVOID InputBuffer, - IN ULONG InputBufferSize, - OUT PVOID OutputBuffer, - IN ULONG OutputBufferSize -); - -NTSTATUS -STDCALL -NtGetContextThread( - IN HANDLE ThreadHandle, - OUT PCONTEXT Context -); - -NTSTATUS -STDCALL -ZwGetContextThread( - IN HANDLE ThreadHandle, - OUT PCONTEXT Context -); - -NTSTATUS -STDCALL -NtGetPlugPlayEvent( - IN ULONG Reserved1, - IN ULONG Reserved2, - OUT PPLUGPLAY_EVENT_BLOCK Buffer, - IN ULONG BufferSize -); - -ULONG -STDCALL -NtGetTickCount( - VOID -); - -ULONG -STDCALL -ZwGetTickCount( - VOID -); - -NTSTATUS -STDCALL -NtImpersonateClientOfPort( - HANDLE PortHandle, - PLPC_MESSAGE ClientMessage -); - -NTSTATUS -STDCALL -ZwImpersonateClientOfPort( - HANDLE PortHandle, - PLPC_MESSAGE ClientMessage -); - -NTSTATUS -STDCALL -NtImpersonateThread( - IN HANDLE ThreadHandle, - IN HANDLE ThreadToImpersonate, - IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService -); - -NTSTATUS -STDCALL -ZwImpersonateThread( - IN HANDLE ThreadHandle, - IN HANDLE ThreadToImpersonate, - IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService -); - -NTSTATUS -STDCALL -NtInitiatePowerAction( - POWER_ACTION SystemAction, - SYSTEM_POWER_STATE MinSystemState, - ULONG Flags, - BOOLEAN Asynchronous -); - -NTSTATUS -STDCALL -ZwInitiatePowerAction( - POWER_ACTION SystemAction, - SYSTEM_POWER_STATE MinSystemState, - ULONG Flags, - BOOLEAN Asynchronous -); - -NTSTATUS -STDCALL -NtInitializeRegistry( - BOOLEAN SetUpBoot -); - -NTSTATUS -STDCALL -ZwInitializeRegistry( - BOOLEAN SetUpBoot -); - -NTSTATUS -STDCALL -NtIsProcessInJob( - IN HANDLE ProcessHandle, - IN HANDLE JobHandle OPTIONAL -); - -NTSTATUS -STDCALL -ZwIsProcessInJob( - IN HANDLE ProcessHandle, - IN HANDLE JobHandle OPTIONAL -); - -NTSTATUS -STDCALL -NtListenPort(HANDLE PortHandle, - PLPC_MESSAGE LpcMessage -); - -NTSTATUS -STDCALL -ZwListenPort(HANDLE PortHandle, - PLPC_MESSAGE LpcMessage -); - -NTSTATUS -STDCALL -NtLoadDriver( - IN PUNICODE_STRING DriverServiceName -); - -NTSTATUS -STDCALL -ZwLoadDriver( - IN PUNICODE_STRING DriverServiceName -); - -NTSTATUS -STDCALL -NtLoadKey( - IN POBJECT_ATTRIBUTES KeyObjectAttributes, - IN POBJECT_ATTRIBUTES FileObjectAttributes -); - -NTSTATUS -STDCALL -ZwLoadKey( - IN POBJECT_ATTRIBUTES KeyObjectAttributes, - IN POBJECT_ATTRIBUTES FileObjectAttributes -); - -NTSTATUS -STDCALL -NtLoadKey2( - IN POBJECT_ATTRIBUTES KeyObjectAttributes, - IN POBJECT_ATTRIBUTES FileObjectAttributes, - IN ULONG Flags -); - -NTSTATUS -STDCALL -ZwLoadKey2( - IN POBJECT_ATTRIBUTES KeyObjectAttributes, - IN POBJECT_ATTRIBUTES FileObjectAttributes, - IN ULONG Flags -); - -NTSTATUS -STDCALL -NtLockFile( - IN HANDLE FileHandle, - IN HANDLE Event OPTIONAL, - IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, - IN PVOID ApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN PLARGE_INTEGER ByteOffset, - IN PLARGE_INTEGER Length, - IN PULONG Key, - IN BOOLEAN FailImmediatedly, - IN BOOLEAN ExclusiveLock -); - -NTSTATUS -STDCALL -ZwLockFile( - IN HANDLE FileHandle, - IN HANDLE Event OPTIONAL, - IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, - IN PVOID ApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN PLARGE_INTEGER ByteOffset, - IN PLARGE_INTEGER Length, - IN PULONG Key, - IN BOOLEAN FailImmediatedly, - IN BOOLEAN ExclusiveLock -); - -NTSTATUS -STDCALL -NtLockVirtualMemory( - HANDLE ProcessHandle, - PVOID BaseAddress, - ULONG NumberOfBytesToLock, - PULONG NumberOfBytesLocked -); - -NTSTATUS -STDCALL -ZwLockVirtualMemory( - HANDLE ProcessHandle, - PVOID BaseAddress, - ULONG NumberOfBytesToLock, - PULONG NumberOfBytesLocked -); - -NTSTATUS -STDCALL -NtMakePermanentObject( - IN HANDLE Object -); - -NTSTATUS -STDCALL -ZwMakePermanentObject( - IN HANDLE Object -); - -NTSTATUS -STDCALL -NtMakeTemporaryObject( - IN HANDLE Handle -); - -NTSTATUS -STDCALL -ZwMakeTemporaryObject( - IN HANDLE Handle -); - -NTSTATUS -STDCALL -NtMapViewOfSection( - IN HANDLE SectionHandle, - IN HANDLE ProcessHandle, - IN OUT PVOID *BaseAddress, - IN ULONG ZeroBits, - IN ULONG CommitSize, - IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, - IN OUT PULONG ViewSize, - IN SECTION_INHERIT InheritDisposition, - IN ULONG AllocationType, - IN ULONG AccessProtection -); - -NTSTATUS -STDCALL -ZwMapViewOfSection( - IN HANDLE SectionHandle, - IN HANDLE ProcessHandle, - IN OUT PVOID *BaseAddress, - IN ULONG ZeroBits, - IN ULONG CommitSize, - IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, - IN OUT PULONG ViewSize, - IN SECTION_INHERIT InheritDisposition, - IN ULONG AllocationType, - IN ULONG AccessProtection -); - -NTSTATUS -STDCALL -NtNotifyChangeDirectoryFile( - IN HANDLE FileHandle, - IN HANDLE Event OPTIONAL, - IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, - IN PVOID ApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PVOID Buffer, - IN ULONG BufferSize, - IN ULONG CompletionFilter, - IN BOOLEAN WatchTree -); - -NTSTATUS -STDCALL -ZwNotifyChangeDirectoryFile( - IN HANDLE FileHandle, - IN HANDLE Event OPTIONAL, - IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, - IN PVOID ApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PVOID Buffer, - IN ULONG BufferSize, - IN ULONG CompletionFilter, - IN BOOLEAN WatchTree -); - -NTSTATUS -STDCALL -NtNotifyChangeKey( - IN HANDLE KeyHandle, - IN HANDLE Event, - IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, - IN PVOID ApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG CompletionFilter, - IN BOOLEAN Asynchroneous, - OUT PVOID ChangeBuffer, - IN ULONG Length, - IN BOOLEAN WatchSubtree -); - -NTSTATUS -STDCALL -ZwNotifyChangeKey( - IN HANDLE KeyHandle, - IN HANDLE Event, - IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, - IN PVOID ApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG CompletionFilter, - IN BOOLEAN Asynchroneous, - OUT PVOID ChangeBuffer, - IN ULONG Length, - IN BOOLEAN WatchSubtree -); - -NTSTATUS -STDCALL -NtOpenDirectoryObject( - OUT PHANDLE FileHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -ZwOpenDirectoryObject( - OUT PHANDLE FileHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -NtOpenEvent( - OUT PHANDLE EventHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -ZwOpenEvent( - OUT PHANDLE EventHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -NtOpenEventPair( - OUT PHANDLE EventPairHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -ZwOpenEventPair( - OUT PHANDLE EventPairHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -NtOpenFile( - OUT PHANDLE FileHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG ShareAccess, - IN ULONG OpenOptions -); - -NTSTATUS -STDCALL -ZwOpenFile( - OUT PHANDLE FileHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN ULONG ShareAccess, - IN ULONG OpenOptions -); - -NTSTATUS -STDCALL -NtOpenIoCompletion( - OUT PHANDLE CompetionPort, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -ZwOpenIoCompletion( - OUT PHANDLE CompetionPort, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -NtOpenJobObject( - PHANDLE JobHandle, - ACCESS_MASK DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -ZwOpenJobObject( - PHANDLE JobHandle, - ACCESS_MASK DesiredAccess, - POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -NtOpenKey( - OUT PHANDLE KeyHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -ZwOpenKey( - OUT PHANDLE KeyHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -NtOpenMutant( - OUT PHANDLE MutantHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -ZwOpenMutant( - OUT PHANDLE MutantHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -NtOpenObjectAuditAlarm( - IN PUNICODE_STRING SubsystemName, - IN PVOID HandleId, - IN PUNICODE_STRING ObjectTypeName, - IN PUNICODE_STRING ObjectName, - IN PSECURITY_DESCRIPTOR SecurityDescriptor, - IN HANDLE ClientToken, - IN ULONG DesiredAccess, - IN ULONG GrantedAccess, - IN PPRIVILEGE_SET Privileges, - IN BOOLEAN ObjectCreation, - IN BOOLEAN AccessGranted, - OUT PBOOLEAN GenerateOnClose -); - -NTSTATUS -STDCALL -ZwOpenObjectAuditAlarm( - IN PUNICODE_STRING SubsystemName, - IN PVOID HandleId, - IN PUNICODE_STRING ObjectTypeName, - IN PUNICODE_STRING ObjectName, - IN PSECURITY_DESCRIPTOR SecurityDescriptor, - IN HANDLE ClientToken, - IN ULONG DesiredAccess, - IN ULONG GrantedAccess, - IN PPRIVILEGE_SET Privileges, - IN BOOLEAN ObjectCreation, - IN BOOLEAN AccessGranted, - OUT PBOOLEAN GenerateOnClose -); - -NTSTATUS -STDCALL -NtOpenProcess( - OUT PHANDLE ProcessHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN PCLIENT_ID ClientId -); - -NTSTATUS -STDCALL -ZwOpenProcess( - OUT PHANDLE ProcessHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN PCLIENT_ID ClientId -); - -NTSTATUS -STDCALL -NtOpenProcessToken( - IN HANDLE ProcessHandle, - IN ACCESS_MASK DesiredAccess, - OUT PHANDLE TokenHandle -); - -NTSTATUS -STDCALL -ZwOpenProcessToken( - IN HANDLE ProcessHandle, - IN ACCESS_MASK DesiredAccess, - OUT PHANDLE TokenHandle -); - -NTSTATUS -STDCALL -NtOpenProcessTokenEx( - IN HANDLE ProcessHandle, - IN ACCESS_MASK DesiredAccess, - IN ULONG HandleAttributes, - OUT PHANDLE TokenHandle -); - -NTSTATUS -STDCALL -ZwOpenProcessTokenEx( - IN HANDLE ProcessHandle, - IN ACCESS_MASK DesiredAccess, - IN ULONG HandleAttributes, - OUT PHANDLE TokenHandle -); - -NTSTATUS -STDCALL -NtOpenSection( - OUT PHANDLE SectionHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -ZwOpenSection( - OUT PHANDLE SectionHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -NtOpenSemaphore( - OUT PHANDLE SemaphoreHandle, - IN ACCESS_MASK DesiredAcces, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -ZwOpenSemaphore( - OUT PHANDLE SemaphoreHandle, - IN ACCESS_MASK DesiredAcces, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -NtOpenSymbolicLinkObject( - OUT PHANDLE SymbolicLinkHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -ZwOpenSymbolicLinkObject( - OUT PHANDLE SymbolicLinkHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -NtOpenThread( - OUT PHANDLE ThreadHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN PCLIENT_ID ClientId -); - -NTSTATUS -STDCALL -ZwOpenThread( - OUT PHANDLE ThreadHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN PCLIENT_ID ClientId -); - -NTSTATUS -STDCALL -NtOpenThreadToken( - IN HANDLE ThreadHandle, - IN ACCESS_MASK DesiredAccess, - IN BOOLEAN OpenAsSelf, - OUT PHANDLE TokenHandle -); - -NTSTATUS -STDCALL -ZwOpenThreadToken( - IN HANDLE ThreadHandle, - IN ACCESS_MASK DesiredAccess, - IN BOOLEAN OpenAsSelf, - OUT PHANDLE TokenHandle -); - -NTSTATUS -STDCALL -NtOpenThreadTokenEx( - IN HANDLE ThreadHandle, - IN ACCESS_MASK DesiredAccess, - IN BOOLEAN OpenAsSelf, - IN ULONG HandleAttributes, - OUT PHANDLE TokenHandle -); - -NTSTATUS -STDCALL -ZwOpenThreadTokenEx( - IN HANDLE ThreadHandle, - IN ACCESS_MASK DesiredAccess, - IN BOOLEAN OpenAsSelf, - IN ULONG HandleAttributes, - OUT PHANDLE TokenHandle -); - -NTSTATUS -STDCALL -NtOpenTimer( - OUT PHANDLE TimerHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); -NTSTATUS -STDCALL -ZwOpenTimer( - OUT PHANDLE TimerHandle, - IN ACCESS_MASK DesiredAccess, - IN POBJECT_ATTRIBUTES ObjectAttributes -); - -NTSTATUS -STDCALL -NtPlugPlayControl( - IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass, - IN OUT PVOID Buffer, - IN ULONG BufferSize -); - -NTSTATUS -STDCALL -NtPowerInformation( - POWER_INFORMATION_LEVEL PowerInformationLevel, - PVOID InputBuffer, - ULONG InputBufferLength, - PVOID OutputBuffer, - ULONG OutputBufferLength -); - -NTSTATUS -STDCALL -ZwPowerInformation( - POWER_INFORMATION_LEVEL PowerInformationLevel, - PVOID InputBuffer, - ULONG InputBufferLength, - PVOID OutputBuffer, - ULONG OutputBufferLength -); - -NTSTATUS -STDCALL -NtPrivilegeCheck( - IN HANDLE ClientToken, - IN PPRIVILEGE_SET RequiredPrivileges, - IN PBOOLEAN Result -); - -NTSTATUS -STDCALL -ZwPrivilegeCheck( - IN HANDLE ClientToken, - IN PPRIVILEGE_SET RequiredPrivileges, - IN PBOOLEAN Result -); - -NTSTATUS -STDCALL -NtPrivilegedServiceAuditAlarm( - IN PUNICODE_STRING SubsystemName, - IN PUNICODE_STRING ServiceName, - IN HANDLE ClientToken, - IN PPRIVILEGE_SET Privileges, - IN BOOLEAN AccessGranted -); - -NTSTATUS -STDCALL -ZwPrivilegedServiceAuditAlarm( - IN PUNICODE_STRING SubsystemName, - IN PUNICODE_STRING ServiceName, - IN HANDLE ClientToken, - IN PPRIVILEGE_SET Privileges, - IN BOOLEAN AccessGranted -); - -NTSTATUS -STDCALL -NtPrivilegeObjectAuditAlarm( - IN PUNICODE_STRING SubsystemName, - IN PVOID HandleId, - IN HANDLE ClientToken, - IN ULONG DesiredAccess, - IN PPRIVILEGE_SET Privileges, - IN BOOLEAN AccessGranted -); - -NTSTATUS -STDCALL -ZwPrivilegeObjectAuditAlarm( - IN PUNICODE_STRING SubsystemName, - IN PVOID HandleId, - IN HANDLE ClientToken, - IN ULONG DesiredAccess, - IN PPRIVILEGE_SET Privileges, - IN BOOLEAN AccessGranted -); - -NTSTATUS -STDCALL -NtProtectVirtualMemory( - IN HANDLE ProcessHandle, - IN PVOID *BaseAddress, - IN ULONG *NumberOfBytesToProtect, - IN ULONG NewAccessProtection, - OUT PULONG OldAccessProtection -); - -NTSTATUS -STDCALL -ZwProtectVirtualMemory( - IN HANDLE ProcessHandle, - IN PVOID *BaseAddress, - IN ULONG *NumberOfBytesToProtect, - IN ULONG NewAccessProtection, - OUT PULONG OldAccessProtection -); - -NTSTATUS -STDCALL -NtPulseEvent( - IN HANDLE EventHandle, - IN PLONG PulseCount OPTIONAL -); - -NTSTATUS -STDCALL -ZwPulseEvent( - IN HANDLE EventHandle, - IN PLONG PulseCount OPTIONAL -); - -NTSTATUS -STDCALL -NtQueryAttributesFile( - IN POBJECT_ATTRIBUTES ObjectAttributes, - OUT PFILE_BASIC_INFORMATION FileInformation -); - -NTSTATUS -STDCALL -ZwQueryAttributesFile( - IN POBJECT_ATTRIBUTES ObjectAttributes, - OUT PFILE_BASIC_INFORMATION FileInformation -); - - -NTSTATUS -STDCALL -NtQueryBootEntryOrder( - IN ULONG Unknown1, - IN ULONG Unknown2 -); - -NTSTATUS -STDCALL -ZwQueryBootEntryOrder( - IN ULONG Unknown1, - IN ULONG Unknown2 -); - -NTSTATUS -STDCALL -NtQueryBootOptions( - IN ULONG Unknown1, - IN ULONG Unknown2 -); - -NTSTATUS -STDCALL -ZwQueryBootOptions( - IN ULONG Unknown1, - IN ULONG Unknown2 -); -NTSTATUS -STDCALL -NtQueryDefaultLocale( - IN BOOLEAN UserProfile, - OUT PLCID DefaultLocaleId -); - -NTSTATUS -STDCALL -ZwQueryDefaultLocale( - IN BOOLEAN UserProfile, - OUT PLCID DefaultLocaleId -); - -NTSTATUS -STDCALL -NtQueryDefaultUILanguage( - PLANGID LanguageId -); - -NTSTATUS -STDCALL -ZwQueryDefaultUILanguage( - PLANGID LanguageId -); - -NTSTATUS -STDCALL -NtQueryDirectoryFile( - IN HANDLE FileHandle, - IN HANDLE Event OPTIONAL, - IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, - IN PVOID ApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PVOID FileInformation, - IN ULONG Length, - IN FILE_INFORMATION_CLASS FileInformationClass, - IN BOOLEAN ReturnSingleEntry, - IN PUNICODE_STRING FileName OPTIONAL, - IN BOOLEAN RestartScan -); - -NTSTATUS -STDCALL -ZwQueryDirectoryFile( - IN HANDLE FileHandle, - IN HANDLE Event OPTIONAL, - IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, - IN PVOID ApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PVOID FileInformation, - IN ULONG Length, - IN FILE_INFORMATION_CLASS FileInformationClass, - IN BOOLEAN ReturnSingleEntry, - IN PUNICODE_STRING FileName OPTIONAL, - IN BOOLEAN RestartScan -); - -NTSTATUS -STDCALL -NtQueryDirectoryObject( - IN HANDLE DirectoryHandle, - OUT PVOID Buffer, - IN ULONG BufferLength, - IN BOOLEAN ReturnSingleEntry, - IN BOOLEAN RestartScan, - IN OUT PULONG Context, - OUT PULONG ReturnLength OPTIONAL -); - -NTSTATUS -STDCALL -ZwQueryDirectoryObject( - IN HANDLE DirectoryHandle, - OUT PVOID Buffer, - IN ULONG BufferLength, - IN BOOLEAN ReturnSingleEntry, - IN BOOLEAN RestartScan, - IN OUT PULONG Context, - OUT PULONG ReturnLength OPTIONAL -); - -NTSTATUS -STDCALL -NtQueryEaFile( - IN HANDLE FileHandle, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PVOID Buffer, - IN ULONG Length, - IN BOOLEAN ReturnSingleEntry, - IN PVOID EaList OPTIONAL, - IN ULONG EaListLength, - IN PULONG EaIndex OPTIONAL, - IN BOOLEAN RestartScan -); - -NTSTATUS -STDCALL -ZwQueryEaFile( - IN HANDLE FileHandle, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PVOID Buffer, - IN ULONG Length, - IN BOOLEAN ReturnSingleEntry, - IN PVOID EaList OPTIONAL, - IN ULONG EaListLength, - IN PULONG EaIndex OPTIONAL, - IN BOOLEAN RestartScan -); - -NTSTATUS -STDCALL -NtQueryEvent( - IN HANDLE EventHandle, - IN EVENT_INFORMATION_CLASS EventInformationClass, - OUT PVOID EventInformation, - IN ULONG EventInformationLength, - OUT PULONG ReturnLength -); -NTSTATUS -STDCALL -ZwQueryEvent( - IN HANDLE EventHandle, - IN EVENT_INFORMATION_CLASS EventInformationClass, - OUT PVOID EventInformation, - IN ULONG EventInformationLength, - OUT PULONG ReturnLength -); - -NTSTATUS -STDCALL -NtQueryFullAttributesFile( - IN POBJECT_ATTRIBUTES ObjectAttributes, - OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation -); - -NTSTATUS -STDCALL -ZwQueryFullAttributesFile( - IN POBJECT_ATTRIBUTES ObjectAttributes, - OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation -); - -NTSTATUS -STDCALL -NtQueryInformationAtom( - IN RTL_ATOM Atom, - IN ATOM_INFORMATION_CLASS AtomInformationClass, - OUT PVOID AtomInformation, - IN ULONG AtomInformationLength, - OUT PULONG ReturnLength OPTIONAL -); - -NTSTATUS -STDCALL -ZwQueryInformationAtom( - IN RTL_ATOM Atom, - IN ATOM_INFORMATION_CLASS AtomInformationClass, - OUT PVOID AtomInformation, - IN ULONG AtomInformationLength, - OUT PULONG ReturnLength OPTIONAL -); - -NTSTATUS -STDCALL -NtQueryInformationFile( - IN HANDLE FileHandle, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PVOID FileInformation, - IN ULONG Length, - IN FILE_INFORMATION_CLASS FileInformationClass -); - -NTSTATUS -STDCALL -ZwQueryInformationFile( - HANDLE FileHandle, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID FileInformation, - ULONG Length, - FILE_INFORMATION_CLASS FileInformationClass -); - -NTSTATUS -STDCALL -NtQueryInformationJobObject( - HANDLE JobHandle, - JOBOBJECTINFOCLASS JobInformationClass, - PVOID JobInformation, - ULONG JobInformationLength, - PULONG ReturnLength -); - -NTSTATUS -STDCALL -ZwQueryInformationJobObject( - HANDLE JobHandle, - JOBOBJECTINFOCLASS JobInformationClass, - PVOID JobInformation, - ULONG JobInformationLength, - PULONG ReturnLength -); - -NTSTATUS -STDCALL -NtQueryInformationPort( - HANDLE PortHandle, - CINT PortInformationClass, - PVOID PortInformation, - ULONG PortInformationLength, - PULONG ReturnLength -); - -NTSTATUS -STDCALL -ZwQueryInformationPort( - HANDLE PortHandle, - CINT PortInformationClass, - PVOID PortInformation, - ULONG PortInformationLength, - PULONG ReturnLength -); - -#ifndef _NTDDK_ -NTSTATUS -STDCALL -NtQueryInformationProcess( - IN HANDLE ProcessHandle, - IN PROCESSINFOCLASS ProcessInformationClass, - OUT PVOID ProcessInformation, - IN ULONG ProcessInformationLength, - OUT PULONG ReturnLength OPTIONAL -); - -NTSTATUS -STDCALL -ZwQueryInformationProcess( - IN HANDLE ProcessHandle, - IN PROCESSINFOCLASS ProcessInformationClass, - OUT PVOID ProcessInformation, - IN ULONG ProcessInformationLength, - OUT PULONG ReturnLength OPTIONAL -); -#endif - -NTSTATUS -STDCALL -NtQueryInformationThread( - IN HANDLE ThreadHandle, - IN THREADINFOCLASS ThreadInformationClass, - OUT PVOID ThreadInformation, - IN ULONG ThreadInformationLength, - OUT PULONG ReturnLength -); - -NTSTATUS -STDCALL -ZwQueryInformationThread( - IN HANDLE ThreadHandle, - IN THREADINFOCLASS ThreadInformationClass, - OUT PVOID ThreadInformation, - IN ULONG ThreadInformationLength, - OUT PULONG ReturnLength -); - -NTSTATUS -STDCALL -NtQueryInformationToken( - IN HANDLE TokenHandle, - IN TOKEN_INFORMATION_CLASS TokenInformationClass, - OUT PVOID TokenInformation, - IN ULONG TokenInformationLength, - OUT PULONG ReturnLength -); - -NTSTATUS -STDCALL -ZwQueryInformationToken( - IN HANDLE TokenHandle, - IN TOKEN_INFORMATION_CLASS TokenInformationClass, - OUT PVOID TokenInformation, - IN ULONG TokenInformationLength, - OUT PULONG ReturnLength -); - -NTSTATUS -STDCALL -NtQueryInstallUILanguage( - PLANGID LanguageId -); - -NTSTATUS -STDCALL -ZwQueryInstallUILanguage( - PLANGID LanguageId -); - -NTSTATUS -STDCALL -NtQueryIntervalProfile( - IN KPROFILE_SOURCE ProfileSource, - OUT PULONG Interval -); - -NTSTATUS -STDCALL -ZwQueryIntervalProfile( - OUT PULONG Interval, - OUT KPROFILE_SOURCE ClockSource -); - -NTSTATUS -STDCALL -NtQueryIoCompletion( - IN HANDLE IoCompletionHandle, - IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass, - OUT PVOID IoCompletionInformation, - IN ULONG IoCompletionInformationLength, - OUT PULONG ResultLength OPTIONAL -); - -NTSTATUS -STDCALL -ZwQueryIoCompletion( - IN HANDLE IoCompletionHandle, - IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass, - OUT PVOID IoCompletionInformation, - IN ULONG IoCompletionInformationLength, - OUT PULONG ResultLength OPTIONAL -); - -NTSTATUS -STDCALL -NtQueryKey( - IN HANDLE KeyHandle, - IN KEY_INFORMATION_CLASS KeyInformationClass, - OUT PVOID KeyInformation, - IN ULONG Length, - OUT PULONG ResultLength -); - -NTSTATUS -STDCALL -ZwQueryKey( - IN HANDLE KeyHandle, - IN KEY_INFORMATION_CLASS KeyInformationClass, - OUT PVOID KeyInformation, - IN ULONG Length, - OUT PULONG ResultLength -); - -NTSTATUS -STDCALL -NtQueryQuotaInformationFile( - IN HANDLE FileHandle, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PVOID Buffer, - IN ULONG Length, - IN BOOLEAN ReturnSingleEntry, - IN PVOID SidList OPTIONAL, - IN ULONG SidListLength, - IN PSID StartSid OPTIONAL, - IN BOOLEAN RestartScan -); - -NTSTATUS -STDCALL -ZwQueryQuotaInformationFile( - IN HANDLE FileHandle, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PVOID Buffer, - IN ULONG Length, - IN BOOLEAN ReturnSingleEntry, - IN PVOID SidList OPTIONAL, - IN ULONG SidListLength, - IN PSID StartSid OPTIONAL, - IN BOOLEAN RestartScan -); - -NTSTATUS -STDCALL -NtQueryMultipleValueKey( - IN HANDLE KeyHandle, - IN OUT PKEY_VALUE_ENTRY ValueList, - IN ULONG NumberOfValues, - OUT PVOID Buffer, - IN OUT PULONG Length, - OUT PULONG ReturnLength -); - -NTSTATUS -STDCALL -ZwQueryMultipleValueKey( - IN HANDLE KeyHandle, - IN OUT PKEY_VALUE_ENTRY ValueList, - IN ULONG NumberOfValues, - OUT PVOID Buffer, - IN OUT PULONG Length, - OUT PULONG ReturnLength -); - -NTSTATUS -STDCALL -NtQueryMutant( - IN HANDLE MutantHandle, - IN MUTANT_INFORMATION_CLASS MutantInformationClass, - OUT PVOID MutantInformation, - IN ULONG Length, - OUT PULONG ResultLength -); - -NTSTATUS -STDCALL -ZwQueryMutant( - IN HANDLE MutantHandle, - IN MUTANT_INFORMATION_CLASS MutantInformationClass, - OUT PVOID MutantInformation, - IN ULONG Length, - OUT PULONG ResultLength -); - -NTSTATUS -STDCALL -NtQueryObject( - IN HANDLE ObjectHandle, - IN OBJECT_INFORMATION_CLASS ObjectInformationClass, - OUT PVOID ObjectInformation, - IN ULONG Length, - OUT PULONG ResultLength OPTIONAL -); - -NTSTATUS -STDCALL -ZwQueryObject( - IN HANDLE ObjectHandle, - IN OBJECT_INFORMATION_CLASS ObjectInformationClass, - OUT PVOID ObjectInformation, - IN ULONG Length, - OUT PULONG ResultLength OPTIONAL -); - -NTSTATUS -STDCALL -NtQueryPerformanceCounter( - IN PLARGE_INTEGER Counter, - IN PLARGE_INTEGER Frequency -); - -NTSTATUS -STDCALL -ZwQueryPerformanceCounter( - IN PLARGE_INTEGER Counter, - IN PLARGE_INTEGER Frequency -); - -NTSTATUS -STDCALL -NtQuerySection( - IN HANDLE SectionHandle, - IN SECTION_INFORMATION_CLASS SectionInformationClass, - OUT PVOID SectionInformation, - IN ULONG Length, - OUT PULONG ResultLength -); - -NTSTATUS -STDCALL -ZwQuerySection( - IN HANDLE SectionHandle, - IN SECTION_INFORMATION_CLASS SectionInformationClass, - OUT PVOID SectionInformation, - IN ULONG Length, - OUT PULONG ResultLength -); - -NTSTATUS -STDCALL -NtQuerySecurityObject( - IN HANDLE Handle, - IN SECURITY_INFORMATION SecurityInformation, - OUT PSECURITY_DESCRIPTOR SecurityDescriptor, - IN ULONG Length, - OUT PULONG ResultLength -); - -NTSTATUS -STDCALL -ZwQuerySecurityObject( - IN HANDLE Handle, - IN SECURITY_INFORMATION SecurityInformation, - OUT PSECURITY_DESCRIPTOR SecurityDescriptor, - IN ULONG Length, - OUT PULONG ResultLength -); - -NTSTATUS -STDCALL -NtQuerySemaphore( - IN HANDLE SemaphoreHandle, - IN SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass, - OUT PVOID SemaphoreInformation, - IN ULONG Length, - OUT PULONG ReturnLength -); - -NTSTATUS -STDCALL -ZwQuerySemaphore( - IN HANDLE SemaphoreHandle, - IN SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass, - OUT PVOID SemaphoreInformation, - IN ULONG Length, - OUT PULONG ReturnLength -); - -NTSTATUS -STDCALL -NtQuerySymbolicLinkObject( - IN HANDLE SymLinkObjHandle, - OUT PUNICODE_STRING LinkTarget, - OUT PULONG DataWritten OPTIONAL -); - -NTSTATUS -STDCALL -ZwQuerySymbolicLinkObject( - IN HANDLE SymLinkObjHandle, - OUT PUNICODE_STRING LinkName, - OUT PULONG DataWritten OPTIONAL -); - -NTSTATUS -STDCALL -NtQuerySystemEnvironmentValue( - IN PUNICODE_STRING Name, - OUT PWSTR Value, - ULONG Length, - PULONG ReturnLength -); - -NTSTATUS -STDCALL -ZwQuerySystemEnvironmentValue( - IN PUNICODE_STRING Name, - OUT PVOID Value, - ULONG Length, - PULONG ReturnLength -); - -NTSTATUS -STDCALL -NtQuerySystemInformation( - IN SYSTEM_INFORMATION_CLASS SystemInformationClass, - OUT PVOID SystemInformation, - IN ULONG Length, - OUT PULONG ResultLength -); - -NTSTATUS -STDCALL -ZwQuerySystemInformation( - IN SYSTEM_INFORMATION_CLASS SystemInformationClass, - OUT PVOID SystemInformation, - IN ULONG Length, - OUT PULONG ResultLength -); - -NTSTATUS -STDCALL -NtQuerySystemTime( - OUT PLARGE_INTEGER CurrentTime -); - -NTSTATUS -STDCALL -ZwQuerySystemTime( - OUT PLARGE_INTEGER CurrentTime -); - -NTSTATUS -STDCALL -NtQueryTimer( - IN HANDLE TimerHandle, - IN TIMER_INFORMATION_CLASS TimerInformationClass, - OUT PVOID TimerInformation, - IN ULONG Length, - OUT PULONG ResultLength -); - -NTSTATUS -STDCALL -ZwQueryTimer( - IN HANDLE TimerHandle, - IN TIMER_INFORMATION_CLASS TimerInformationClass, - OUT PVOID TimerInformation, - IN ULONG Length, - OUT PULONG ResultLength -); - -NTSTATUS -STDCALL -NtQueryTimerResolution( - OUT PULONG MinimumResolution, - OUT PULONG MaximumResolution, - OUT PULONG ActualResolution -); - -NTSTATUS -STDCALL -ZwQueryTimerResolution( - OUT PULONG MinimumResolution, - OUT PULONG MaximumResolution, - OUT PULONG ActualResolution -); - -NTSTATUS -STDCALL -NtQueryValueKey( - IN HANDLE KeyHandle, - IN PUNICODE_STRING ValueName, - IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, - OUT PVOID KeyValueInformation, - IN ULONG Length, - OUT PULONG ResultLength -); - -NTSTATUS -STDCALL -ZwQueryValueKey( - IN HANDLE KeyHandle, - IN PUNICODE_STRING ValueName, - IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, - OUT PVOID KeyValueInformation, - IN ULONG Length, - OUT PULONG ResultLength -); - -NTSTATUS -STDCALL -NtQueryVirtualMemory( - IN HANDLE ProcessHandle, - IN PVOID Address, - IN IN CINT VirtualMemoryInformationClass, - OUT PVOID VirtualMemoryInformation, - IN ULONG Length, - OUT PULONG ResultLength -); - -NTSTATUS -STDCALL -ZwQueryVirtualMemory( - IN HANDLE ProcessHandle, - IN PVOID Address, - IN IN CINT VirtualMemoryInformationClass, - OUT PVOID VirtualMemoryInformation, - IN ULONG Length, - OUT PULONG ResultLength -); - -NTSTATUS -STDCALL -NtQueryVolumeInformationFile( - IN HANDLE FileHandle, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PVOID FsInformation, - IN ULONG Length, - IN FS_INFORMATION_CLASS FsInformationClass -); - -NTSTATUS -STDCALL -ZwQueryVolumeInformationFile( - IN HANDLE FileHandle, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PVOID FsInformation, - IN ULONG Length, - IN FS_INFORMATION_CLASS FsInformationClass -); - -NTSTATUS -STDCALL -NtQueueApcThread( - HANDLE ThreadHandle, - PKNORMAL_ROUTINE ApcRoutine, - PVOID NormalContext, - PVOID SystemArgument1, - PVOID SystemArgument2 -); - -NTSTATUS -STDCALL -ZwQueueApcThread( - HANDLE ThreadHandle, - PKNORMAL_ROUTINE ApcRoutine, - PVOID NormalContext, - PVOID SystemArgument1, - PVOID SystemArgument2 -); - -NTSTATUS -STDCALL -NtRaiseException( - IN PEXCEPTION_RECORD ExceptionRecord, - IN PCONTEXT Context, - IN BOOLEAN SearchFrames -); - -NTSTATUS -STDCALL -ZwRaiseException( - IN PEXCEPTION_RECORD ExceptionRecord, - IN PCONTEXT Context, - IN BOOLEAN SearchFrames -); - -NTSTATUS -STDCALL -NtRaiseHardError( - IN NTSTATUS ErrorStatus, - IN ULONG NumberOfParameters, - IN PUNICODE_STRING UnicodeStringParameterMask OPTIONAL, - IN PVOID *Parameters, - IN HARDERROR_RESPONSE_OPTION ResponseOption, - OUT PHARDERROR_RESPONSE Response -); - -NTSTATUS -STDCALL -ZwRaiseHardError( - IN NTSTATUS ErrorStatus, - IN ULONG NumberOfParameters, - IN PUNICODE_STRING UnicodeStringParameterMask OPTIONAL, - IN PVOID *Parameters, - IN HARDERROR_RESPONSE_OPTION ResponseOption, - OUT PHARDERROR_RESPONSE Response -); - -NTSTATUS -STDCALL -NtReadFile( - IN HANDLE FileHandle, - IN HANDLE Event OPTIONAL, - IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, - IN PVOID UserApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PVOID Buffer, - IN ULONG BufferLength, - IN PLARGE_INTEGER ByteOffset OPTIONAL, - IN PULONG Key OPTIONAL -); - -NTSTATUS -STDCALL -ZwReadFile( - IN HANDLE FileHandle, - IN HANDLE Event OPTIONAL, - IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, - IN PVOID UserApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - OUT PVOID Buffer, - IN ULONG BufferLength, - IN PLARGE_INTEGER ByteOffset OPTIONAL, - IN PULONG Key OPTIONAL -); - -NTSTATUS -STDCALL -NtReadFileScatter( - IN HANDLE FileHandle, - IN HANDLE Event OPTIONAL, - IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, - IN PVOID UserApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK UserIoStatusBlock, - IN FILE_SEGMENT_ELEMENT BufferDescription[], - IN ULONG BufferLength, - IN PLARGE_INTEGER ByteOffset, - IN PULONG Key OPTIONAL -); - -NTSTATUS -STDCALL -ZwReadFileScatter( - IN HANDLE FileHandle, - IN HANDLE Event OPTIONAL, - IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, - IN PVOID UserApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK UserIoStatusBlock, - IN FILE_SEGMENT_ELEMENT BufferDescription[], - IN ULONG BufferLength, - IN PLARGE_INTEGER ByteOffset, - IN PULONG Key OPTIONAL -); - -NTSTATUS -STDCALL -NtReadRequestData( - HANDLE PortHandle, - PLPC_MESSAGE Message, - ULONG Index, - PVOID Buffer, - ULONG BufferLength, - PULONG ReturnLength -); - -NTSTATUS -STDCALL -ZwReadRequestData( - HANDLE PortHandle, - PLPC_MESSAGE Message, - ULONG Index, - PVOID Buffer, - ULONG BufferLength, - PULONG ReturnLength -); - -NTSTATUS -STDCALL -NtReadVirtualMemory( - IN HANDLE ProcessHandle, - IN PVOID BaseAddress, - OUT PVOID Buffer, - IN ULONG NumberOfBytesToRead, - OUT PULONG NumberOfBytesRead -); -NTSTATUS -STDCALL -ZwReadVirtualMemory( - IN HANDLE ProcessHandle, - IN PVOID BaseAddress, - OUT PVOID Buffer, - IN ULONG NumberOfBytesToRead, - OUT PULONG NumberOfBytesRead -); - -NTSTATUS -STDCALL -NtRegisterThreadTerminatePort( - HANDLE TerminationPort -); - -NTSTATUS -STDCALL -ZwRegisterThreadTerminatePort( - HANDLE TerminationPort -); - -NTSTATUS -STDCALL -NtReleaseMutant( - IN HANDLE MutantHandle, - IN PLONG ReleaseCount OPTIONAL -); - -NTSTATUS -STDCALL -ZwReleaseMutant( - IN HANDLE MutantHandle, - IN PLONG ReleaseCount OPTIONAL -); - -NTSTATUS -STDCALL -NtReleaseSemaphore( - IN HANDLE SemaphoreHandle, - IN LONG ReleaseCount, - OUT PLONG PreviousCount -); - -NTSTATUS -STDCALL -ZwReleaseSemaphore( - IN HANDLE SemaphoreHandle, - IN LONG ReleaseCount, - OUT PLONG PreviousCount -); - -NTSTATUS -STDCALL -NtRemoveIoCompletion( - IN HANDLE IoCompletionHandle, - OUT PVOID *CompletionKey, - OUT PVOID *CompletionContext, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN PLARGE_INTEGER Timeout OPTIONAL -); - -NTSTATUS -STDCALL -ZwRemoveIoCompletion( - IN HANDLE IoCompletionHandle, - OUT PVOID *CompletionKey, - OUT PVOID *CompletionContext, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN PLARGE_INTEGER Timeout OPTIONAL -); - -NTSTATUS -STDCALL -NtReplaceKey( - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN HANDLE Key, - IN POBJECT_ATTRIBUTES ReplacedObjectAttributes -); - -NTSTATUS -STDCALL -ZwReplaceKey( - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN HANDLE Key, - IN POBJECT_ATTRIBUTES ReplacedObjectAttributes -); - -NTSTATUS -STDCALL -NtReplyPort( - HANDLE PortHandle, - PLPC_MESSAGE LpcReply -); - -NTSTATUS -STDCALL -ZwReplyPort( - HANDLE PortHandle, - PLPC_MESSAGE LpcReply -); - -NTSTATUS -STDCALL -NtReplyWaitReceivePort( - HANDLE PortHandle, - PULONG PortId, - PLPC_MESSAGE MessageReply, - PLPC_MESSAGE MessageRequest -); - -NTSTATUS -STDCALL -ZwReplyWaitReceivePort( - HANDLE PortHandle, - PULONG PortId, - PLPC_MESSAGE MessageReply, - PLPC_MESSAGE MessageRequest -); - -NTSTATUS -STDCALL -NtReplyWaitReplyPort( - HANDLE PortHandle, - PLPC_MESSAGE ReplyMessage -); - -NTSTATUS -STDCALL -ZwReplyWaitReplyPort( - HANDLE PortHandle, - PLPC_MESSAGE ReplyMessage -); - -NTSTATUS -STDCALL -NtRequestPort( - HANDLE PortHandle, - PLPC_MESSAGE LpcMessage); - -NTSTATUS -STDCALL -ZwRequestPort( - HANDLE PortHandle, - PLPC_MESSAGE LpcMessage -); - -NTSTATUS -STDCALL -NtRequestWaitReplyPort( - HANDLE PortHandle, - PLPC_MESSAGE LpcReply, - PLPC_MESSAGE LpcRequest -); - -NTSTATUS -STDCALL -ZwRequestWaitReplyPort( - HANDLE PortHandle, - PLPC_MESSAGE LpcReply, - PLPC_MESSAGE LpcRequest -); - -NTSTATUS -STDCALL -NtResetEvent( - HANDLE EventHandle, - PLONG NumberOfWaitingThreads OPTIONAL -); - -NTSTATUS -STDCALL -ZwResetEvent( - HANDLE EventHandle, - PLONG NumberOfWaitingThreads OPTIONAL -); - -NTSTATUS -STDCALL -NtRestoreKey( - HANDLE KeyHandle, - HANDLE FileHandle, - ULONG RestoreFlags -); - -NTSTATUS -STDCALL -ZwRestoreKey( - HANDLE KeyHandle, - HANDLE FileHandle, - ULONG RestoreFlags -); - -NTSTATUS -STDCALL -NtResumeThread( - IN HANDLE ThreadHandle, - OUT PULONG SuspendCount -); - -NTSTATUS -STDCALL -ZwResumeThread( - IN HANDLE ThreadHandle, - OUT PULONG SuspendCount -); - -NTSTATUS -STDCALL -NtResumeProcess( - IN HANDLE ProcessHandle -); - -NTSTATUS -STDCALL -ZwResumeProcess( - IN HANDLE ProcessHandle -); - -NTSTATUS -STDCALL -NtSaveKey( - IN HANDLE KeyHandle, - IN HANDLE FileHandle -); -NTSTATUS -STDCALL -ZwSaveKey( - IN HANDLE KeyHandle, - IN HANDLE FileHandle -); - -NTSTATUS -STDCALL -NtSaveKeyEx( - IN HANDLE KeyHandle, - IN HANDLE FileHandle, - IN ULONG Flags -); - -NTSTATUS -STDCALL -ZwSaveKeyEx( - IN HANDLE KeyHandle, - IN HANDLE FileHandle, - IN ULONG Flags -); - -NTSTATUS -STDCALL -NtSetBootEntryOrder( - IN ULONG Unknown1, - IN ULONG Unknown2 -); - -NTSTATUS -STDCALL -ZwSetBootEntryOrder( - IN ULONG Unknown1, - IN ULONG Unknown2 -); - -NTSTATUS -STDCALL -NtSetBootOptions( - ULONG Unknown1, - ULONG Unknown2 -); - -NTSTATUS -STDCALL -ZwSetBootOptions( - ULONG Unknown1, - ULONG Unknown2 -); - -NTSTATUS -STDCALL -NtSetContextThread( - IN HANDLE ThreadHandle, - IN PCONTEXT Context -); -NTSTATUS -STDCALL -ZwSetContextThread( - IN HANDLE ThreadHandle, - IN PCONTEXT Context -); - -NTSTATUS -STDCALL -NtSetDefaultLocale( - IN BOOLEAN UserProfile, - IN LCID DefaultLocaleId -); - -NTSTATUS -STDCALL -ZwSetDefaultLocale( - IN BOOLEAN UserProfile, - IN LCID DefaultLocaleId -); - -NTSTATUS -STDCALL -NtSetDefaultUILanguage( - LANGID LanguageId -); - -NTSTATUS -STDCALL -ZwSetDefaultUILanguage( - LANGID LanguageId -); -NTSTATUS -STDCALL -NtSetDefaultHardErrorPort( - IN HANDLE PortHandle -); -NTSTATUS -STDCALL -ZwSetDefaultHardErrorPort( - IN HANDLE PortHandle -); - -NTSTATUS -STDCALL -NtSetEaFile( - IN HANDLE FileHandle, - IN PIO_STATUS_BLOCK IoStatusBlock, - PVOID EaBuffer, - ULONG EaBufferSize -); - -NTSTATUS -STDCALL -ZwSetEaFile( - IN HANDLE FileHandle, - IN PIO_STATUS_BLOCK IoStatusBlock, - PVOID EaBuffer, - ULONG EaBufferSize -); - -NTSTATUS -STDCALL -NtSetEvent( - IN HANDLE EventHandle, - OUT PLONG PreviousState OPTIONAL -); - -NTSTATUS -STDCALL -ZwSetEvent( - IN HANDLE EventHandle, - OUT PLONG PreviousState OPTIONAL -); - -NTSTATUS -STDCALL -NtSetHighEventPair( - IN HANDLE EventPairHandle -); - -NTSTATUS -STDCALL -ZwSetHighEventPair( - IN HANDLE EventPairHandle -); -NTSTATUS -STDCALL -NtSetHighWaitLowEventPair( - IN HANDLE EventPairHandle -); -NTSTATUS -STDCALL -ZwSetHighWaitLowEventPair( - IN HANDLE EventPairHandle -); - -NTSTATUS -STDCALL -NtSetInformationFile( - IN HANDLE FileHandle, - IN PIO_STATUS_BLOCK IoStatusBlock, - IN PVOID FileInformation, - IN ULONG Length, - IN FILE_INFORMATION_CLASS FileInformationClass -); - -NTSTATUS -STDCALL -ZwSetInformationFile( - IN HANDLE FileHandle, - IN PIO_STATUS_BLOCK IoStatusBlock, - IN PVOID FileInformation, - IN ULONG Length, - IN FILE_INFORMATION_CLASS FileInformationClass -); - -NTSTATUS -STDCALL -NtSetInformationJobObject( - HANDLE JobHandle, - JOBOBJECTINFOCLASS JobInformationClass, - PVOID JobInformation, - ULONG JobInformationLength -); - -NTSTATUS -STDCALL -ZwSetInformationJobObject( - HANDLE JobHandle, - JOBOBJECTINFOCLASS JobInformationClass, - PVOID JobInformation, - ULONG JobInformationLength -); - -NTSTATUS -STDCALL -NtSetInformationKey( - IN HANDLE KeyHandle, - IN KEY_SET_INFORMATION_CLASS KeyInformationClass, - IN PVOID KeyInformation, - IN ULONG KeyInformationLength -); - -NTSTATUS -STDCALL -ZwSetInformationKey( - IN HANDLE KeyHandle, - IN KEY_SET_INFORMATION_CLASS KeyInformationClass, - IN PVOID KeyInformation, - IN ULONG KeyInformationLength -); - -NTSTATUS -STDCALL -NtSetInformationObject( - IN HANDLE ObjectHandle, - IN OBJECT_INFORMATION_CLASS ObjectInformationClass, - IN PVOID ObjectInformation, - IN ULONG Length -); - -NTSTATUS -STDCALL -ZwSetInformationObject( - IN HANDLE ObjectHandle, - IN OBJECT_INFORMATION_CLASS ObjectInformationClass, - IN PVOID ObjectInformation, - IN ULONG Length -); - -NTSTATUS -STDCALL -NtSetInformationProcess( - IN HANDLE ProcessHandle, - IN PROCESSINFOCLASS ProcessInformationClass, - IN PVOID ProcessInformation, - IN ULONG ProcessInformationLength -); - -NTSTATUS -STDCALL -NtSetInformationThread( - IN HANDLE ThreadHandle, - IN THREADINFOCLASS ThreadInformationClass, - IN PVOID ThreadInformation, - IN ULONG ThreadInformationLength -); -NTSTATUS -STDCALL -ZwSetInformationThread( - IN HANDLE ThreadHandle, - IN THREADINFOCLASS ThreadInformationClass, - IN PVOID ThreadInformation, - IN ULONG ThreadInformationLength -); - -NTSTATUS -STDCALL -NtSetInformationToken( - IN HANDLE TokenHandle, - IN TOKEN_INFORMATION_CLASS TokenInformationClass, - OUT PVOID TokenInformation, - IN ULONG TokenInformationLength -); - -NTSTATUS -STDCALL -ZwSetInformationToken( - IN HANDLE TokenHandle, - IN TOKEN_INFORMATION_CLASS TokenInformationClass, - OUT PVOID TokenInformation, - IN ULONG TokenInformationLength -); - -NTSTATUS -STDCALL -NtSetIoCompletion( - IN HANDLE IoCompletionPortHandle, - IN PVOID CompletionKey, - IN PVOID CompletionContext, - IN NTSTATUS CompletionStatus, - IN ULONG CompletionInformation -); - -NTSTATUS -STDCALL -ZwSetIoCompletion( - IN HANDLE IoCompletionPortHandle, - IN PVOID CompletionKey, - IN PVOID CompletionContext, - IN NTSTATUS CompletionStatus, - IN ULONG CompletionInformation -); - -NTSTATUS -STDCALL -NtSetIntervalProfile( - ULONG Interval, - KPROFILE_SOURCE ClockSource -); - -NTSTATUS -STDCALL -ZwSetIntervalProfile( - ULONG Interval, - KPROFILE_SOURCE ClockSource -); - -NTSTATUS -STDCALL -NtSetLdtEntries( - ULONG Selector1, - LDT_ENTRY LdtEntry1, - ULONG Selector2, - LDT_ENTRY LdtEntry2 -); - -NTSTATUS -STDCALL -NtSetLowEventPair( - HANDLE EventPair -); - -NTSTATUS -STDCALL -ZwSetLowEventPair( - HANDLE EventPair -); - -NTSTATUS -STDCALL -NtSetLowWaitHighEventPair( - HANDLE EventPair -); - -NTSTATUS -STDCALL -ZwSetLowWaitHighEventPair( - HANDLE EventPair -); - -NTSTATUS -STDCALL -NtSetQuotaInformationFile( - HANDLE FileHandle, - PIO_STATUS_BLOCK IoStatusBlock, - PFILE_QUOTA_INFORMATION Buffer, - ULONG BufferLength -); - -NTSTATUS -STDCALL -ZwSetQuotaInformationFile( - HANDLE FileHandle, - PIO_STATUS_BLOCK IoStatusBlock, - PFILE_QUOTA_INFORMATION Buffer, - ULONG BufferLength -); - -NTSTATUS -STDCALL -NtSetSecurityObject( - IN HANDLE Handle, - IN SECURITY_INFORMATION SecurityInformation, - IN PSECURITY_DESCRIPTOR SecurityDescriptor -); - -NTSTATUS -STDCALL -ZwSetSecurityObject( - IN HANDLE Handle, - IN SECURITY_INFORMATION SecurityInformation, - IN PSECURITY_DESCRIPTOR SecurityDescriptor -); - -NTSTATUS -STDCALL -NtSetSystemEnvironmentValue( - IN PUNICODE_STRING VariableName, - IN PUNICODE_STRING Value -); -NTSTATUS -STDCALL -ZwSetSystemEnvironmentValue( - IN PUNICODE_STRING VariableName, - IN PUNICODE_STRING Value -); - -NTSTATUS -STDCALL -NtSetSystemInformation( - IN SYSTEM_INFORMATION_CLASS SystemInformationClass, - IN PVOID SystemInformation, - IN ULONG SystemInformationLength -); - -NTSTATUS -STDCALL -ZwSetSystemInformation( - IN SYSTEM_INFORMATION_CLASS SystemInformationClass, - IN PVOID SystemInformation, - IN ULONG SystemInformationLength -); - -NTSTATUS -STDCALL -NtSetSystemPowerState( - IN POWER_ACTION SystemAction, - IN SYSTEM_POWER_STATE MinSystemState, - IN ULONG Flags -); - -NTSTATUS -STDCALL -NtSetSystemTime( - IN PLARGE_INTEGER SystemTime, - IN PLARGE_INTEGER NewSystemTime OPTIONAL -); - -NTSTATUS -STDCALL -ZwSetSystemTime( - IN PLARGE_INTEGER SystemTime, - IN PLARGE_INTEGER NewSystemTime OPTIONAL -); - -NTSTATUS -STDCALL -NtSetTimer( - IN HANDLE TimerHandle, - IN PLARGE_INTEGER DueTime, - IN PTIMER_APC_ROUTINE TimerApcRoutine, - IN PVOID TimerContext, - IN BOOLEAN WakeTimer, - IN LONG Period OPTIONAL, - OUT PBOOLEAN PreviousState OPTIONAL -); - -NTSTATUS -STDCALL -NtSetTimerResolution( - IN ULONG RequestedResolution, - IN BOOLEAN SetOrUnset, - OUT PULONG ActualResolution -); - -NTSTATUS -STDCALL -ZwSetTimerResolution( - IN ULONG RequestedResolution, - IN BOOLEAN SetOrUnset, - OUT PULONG ActualResolution -); - -NTSTATUS -STDCALL -NtSetUuidSeed( - IN PUCHAR UuidSeed -); - -NTSTATUS -STDCALL -ZwSetUuidSeed( - IN PUCHAR UuidSeed -); - -NTSTATUS -STDCALL -NtSetValueKey( - IN HANDLE KeyHandle, - IN PUNICODE_STRING ValueName, - IN ULONG TitleIndex OPTIONAL, - IN ULONG Type, - IN PVOID Data, - IN ULONG DataSize -); - -NTSTATUS -STDCALL -ZwSetValueKey( - IN HANDLE KeyHandle, - IN PUNICODE_STRING ValueName, - IN ULONG TitleIndex OPTIONAL, - IN ULONG Type, - IN PVOID Data, - IN ULONG DataSize -); - -NTSTATUS -STDCALL -NtSetVolumeInformationFile( - IN HANDLE FileHandle, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN PVOID FsInformation, - IN ULONG Length, - IN FS_INFORMATION_CLASS FsInformationClass -); - -NTSTATUS -STDCALL -ZwSetVolumeInformationFile( - IN HANDLE FileHandle, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN PVOID FsInformation, - IN ULONG Length, - IN FS_INFORMATION_CLASS FsInformationClass -); - -NTSTATUS -STDCALL -NtShutdownSystem( - IN SHUTDOWN_ACTION Action -); - -NTSTATUS -STDCALL -ZwShutdownSystem( - IN SHUTDOWN_ACTION Action -); - -NTSTATUS -STDCALL -NtSignalAndWaitForSingleObject( - IN HANDLE SignalObject, - IN HANDLE WaitObject, - IN BOOLEAN Alertable, - IN PLARGE_INTEGER Time -); - -NTSTATUS -STDCALL -ZwSignalAndWaitForSingleObject( - IN HANDLE SignalObject, - IN HANDLE WaitObject, - IN BOOLEAN Alertable, - IN PLARGE_INTEGER Time -); - -NTSTATUS -STDCALL -NtStartProfile( - HANDLE ProfileHandle -); - -NTSTATUS -STDCALL -ZwStartProfile( - HANDLE ProfileHandle -); - -NTSTATUS -STDCALL -NtStopProfile( - HANDLE ProfileHandle -); - -NTSTATUS -STDCALL -ZwStopProfile( - HANDLE ProfileHandle -); - -NTSTATUS -STDCALL -NtSuspendProcess( - IN HANDLE ProcessHandle -); - -NTSTATUS -STDCALL -ZwSuspendProcess( - IN HANDLE ProcessHandle -); - -NTSTATUS -STDCALL -NtSuspendThread( - IN HANDLE ThreadHandle, - IN PULONG PreviousSuspendCount -); - -NTSTATUS -STDCALL -ZwSuspendThread( - IN HANDLE ThreadHandle, - IN PULONG PreviousSuspendCount -); - -NTSTATUS -STDCALL -NtSystemDebugControl( - DEBUG_CONTROL_CODE ControlCode, - PVOID InputBuffer, - ULONG InputBufferLength, - PVOID OutputBuffer, - ULONG OutputBufferLength, - PULONG ReturnLength -); - -NTSTATUS -STDCALL -NtTerminateProcess( - IN HANDLE ProcessHandle, - IN NTSTATUS ExitStatus -); - -NTSTATUS -STDCALL -ZwTerminateProcess( - IN HANDLE ProcessHandle, - IN NTSTATUS ExitStatus -); - -NTSTATUS -STDCALL -NtTerminateThread( - IN HANDLE ThreadHandle, - IN NTSTATUS ExitStatus -); - -NTSTATUS -STDCALL -ZwTerminateThread( - IN HANDLE ThreadHandle, - IN NTSTATUS ExitStatus -); - -NTSTATUS -STDCALL -NtTerminateJobObject( - HANDLE JobHandle, - NTSTATUS ExitStatus -); - -NTSTATUS -STDCALL -ZwTerminateJobObject( - HANDLE JobHandle, - NTSTATUS ExitStatus -); - -NTSTATUS -STDCALL -NtTestAlert( - VOID -); - -NTSTATUS -STDCALL -ZwTestAlert( - VOID -); - -NTSTATUS -STDCALL -NtTraceEvent( - IN ULONG TraceHandle, - IN ULONG Flags, - IN ULONG TraceHeaderLength, - IN struct _EVENT_TRACE_HEADER* TraceHeader -); - -NTSTATUS -STDCALL -ZwTraceEvent( - IN ULONG TraceHandle, - IN ULONG Flags, - IN ULONG TraceHeaderLength, - IN struct _EVENT_TRACE_HEADER* TraceHeader -); - -NTSTATUS -STDCALL -NtTranslateFilePath( - ULONG Unknown1, - ULONG Unknown2, - ULONG Unknown3 -); - -NTSTATUS -STDCALL -ZwTranslateFilePath( - ULONG Unknown1, - ULONG Unknown2, - ULONG Unknown3 -); - -NTSTATUS -STDCALL -NtUnloadDriver( - IN PUNICODE_STRING DriverServiceName -); - -NTSTATUS -STDCALL -ZwUnloadDriver( - IN PUNICODE_STRING DriverServiceName -); - -NTSTATUS -STDCALL -NtUnloadKey( - IN POBJECT_ATTRIBUTES KeyObjectAttributes -); - -NTSTATUS -STDCALL -ZwUnloadKey( - IN POBJECT_ATTRIBUTES KeyObjectAttributes -); - -NTSTATUS -STDCALL -NtUnlockFile( - IN HANDLE FileHandle, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN PLARGE_INTEGER ByteOffset, - IN PLARGE_INTEGER Lenght, - OUT PULONG Key OPTIONAL -); - -NTSTATUS -STDCALL -ZwUnlockFile( - IN HANDLE FileHandle, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN PLARGE_INTEGER ByteOffset, - IN PLARGE_INTEGER Lenght, - OUT PULONG Key OPTIONAL -); - -NTSTATUS -STDCALL -NtUnlockVirtualMemory( - IN HANDLE ProcessHandle, - IN PVOID BaseAddress, - IN ULONG NumberOfBytesToUnlock, - OUT PULONG NumberOfBytesUnlocked OPTIONAL -); - -NTSTATUS -STDCALL -ZwUnlockVirtualMemory( - IN HANDLE ProcessHandle, - IN PVOID BaseAddress, - IN ULONG NumberOfBytesToUnlock, - OUT PULONG NumberOfBytesUnlocked OPTIONAL -); - -NTSTATUS -STDCALL -NtUnmapViewOfSection( - IN HANDLE ProcessHandle, - IN PVOID BaseAddress -); - -NTSTATUS -STDCALL -ZwUnmapViewOfSection( - IN HANDLE ProcessHandle, - IN PVOID BaseAddress -); - -NTSTATUS -STDCALL -NtVdmControl( - ULONG ControlCode, - PVOID ControlData -); - -NTSTATUS -STDCALL -NtW32Call( - IN ULONG RoutineIndex, - IN PVOID Argument, - IN ULONG ArgumentLength, - OUT PVOID* Result OPTIONAL, - OUT PULONG ResultLength OPTIONAL -); - -NTSTATUS -STDCALL -NtWaitForMultipleObjects( - IN ULONG Count, - IN HANDLE Object[], - IN WAIT_TYPE WaitType, - IN BOOLEAN Alertable, - IN PLARGE_INTEGER Time -); - -NTSTATUS -STDCALL -ZwWaitForMultipleObjects( - IN ULONG Count, - IN HANDLE Object[], - IN WAIT_TYPE WaitType, - IN BOOLEAN Alertable, - IN PLARGE_INTEGER Time -); - -NTSTATUS -STDCALL -NtWaitForSingleObject( - IN HANDLE Object, - IN BOOLEAN Alertable, - IN PLARGE_INTEGER Time -); - -NTSTATUS -STDCALL -ZwWaitForSingleObject( - IN HANDLE Object, - IN BOOLEAN Alertable, - IN PLARGE_INTEGER Time -); - -NTSTATUS -STDCALL -NtWaitHighEventPair( - IN HANDLE EventPairHandle -); - -NTSTATUS -STDCALL -ZwWaitHighEventPair( - IN HANDLE EventPairHandle -); - -NTSTATUS -STDCALL -NtWaitLowEventPair( - IN HANDLE EventPairHandle -); - -NTSTATUS -STDCALL -ZwWaitLowEventPair( - IN HANDLE EventPairHandle -); - -NTSTATUS -STDCALL -NtWriteFile( - IN HANDLE FileHandle, - IN HANDLE Event OPTIONAL, - IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, - IN PVOID ApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN PVOID Buffer, - IN ULONG Length, - IN PLARGE_INTEGER ByteOffset, - IN PULONG Key OPTIONAL -); - -NTSTATUS -STDCALL -ZwWriteFile( - IN HANDLE FileHandle, - IN HANDLE Event OPTIONAL, - IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, - IN PVOID ApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN PVOID Buffer, - IN ULONG Length, - IN PLARGE_INTEGER ByteOffset, - IN PULONG Key OPTIONAL -); - -NTSTATUS -STDCALL -NtWriteFileGather( - IN HANDLE FileHandle, - IN HANDLE Event OPTIONAL, - IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, - IN PVOID ApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN FILE_SEGMENT_ELEMENT BufferDescription[], - IN ULONG BufferLength, - IN PLARGE_INTEGER ByteOffset, - IN PULONG Key OPTIONAL -); - -NTSTATUS -STDCALL -ZwWriteFileGather( - IN HANDLE FileHandle, - IN HANDLE Event OPTIONAL, - IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, - IN PVOID ApcContext OPTIONAL, - OUT PIO_STATUS_BLOCK IoStatusBlock, - IN FILE_SEGMENT_ELEMENT BufferDescription[], - IN ULONG BufferLength, - IN PLARGE_INTEGER ByteOffset, - IN PULONG Key OPTIONAL -); - -NTSTATUS -STDCALL -NtWriteRequestData( - HANDLE PortHandle, - PLPC_MESSAGE Message, - ULONG Index, - PVOID Buffer, - ULONG BufferLength, - PULONG ReturnLength -); - -NTSTATUS -STDCALL -ZwWriteRequestData( - HANDLE PortHandle, - PLPC_MESSAGE Message, - ULONG Index, - PVOID Buffer, - ULONG BufferLength, - PULONG ReturnLength -); - -NTSTATUS -STDCALL -NtWriteVirtualMemory( - IN HANDLE ProcessHandle, - IN PVOID BaseAddress, - IN PVOID Buffer, - IN ULONG NumberOfBytesToWrite, - OUT PULONG NumberOfBytesWritten -); - -NTSTATUS -STDCALL -ZwWriteVirtualMemory( - IN HANDLE ProcessHandle, - IN PVOID BaseAddress, - IN PVOID Buffer, - IN ULONG NumberOfBytesToWrite, - OUT PULONG NumberOfBytesWritten -); - -NTSTATUS -STDCALL -NtYieldExecution( - VOID -); - -NTSTATUS -STDCALL -ZwYieldExecution( - VOID -); - - -static __inline struct _PEB* NtCurrentPeb (void) -{ - struct _PEB * pPeb; - -#if defined(__GNUC__) - - __asm__ __volatile__ - ( - "movl %%fs:0x30, %0\n" /* fs:30h == Teb->Peb */ - : "=r" (pPeb) /* can't have two memory operands */ - : /* no inputs */ - ); - -#elif defined(_MSC_VER) - - __asm mov eax, fs:0x30; - __asm mov pPeb, eax - -#else -#error Unknown compiler for inline assembler -#endif - - return pPeb; -} -#endif +/* + * PROJECT: ReactOS Native Headers + * FILE: include/ndk/zwfuncs.h + * PURPOSE: Defintions for Native Functions not defined in DDK/IFS + * PROGRAMMER: Alex Ionescu (alex@relsoft.net) + * UPDATE HISTORY: + * Created 06/10/04 + */ +#ifndef _ZWFUNCS_H +#define _ZWFUNCS_H + +/* DEPENDENCIES **************************************************************/ +#include "lpctypes.h" +#include "zwtypes.h" +#include "kdtypes.h" +#define _WMIKM_ +#include + +/* FUNCTION TYPES ************************************************************/ + +/* PROTOTYPES ****************************************************************/ + +NTSTATUS +STDCALL +NtAcceptConnectPort( + PHANDLE PortHandle, + HANDLE NamedPortHandle, + PLPC_MESSAGE ServerReply, + BOOLEAN AcceptIt, + PLPC_SECTION_WRITE WriteMap, + PLPC_SECTION_READ ReadMap +); + +NTSTATUS +STDCALL +NtAccessCheck( + IN PSECURITY_DESCRIPTOR SecurityDescriptor, + IN HANDLE ClientToken, + IN ACCESS_MASK DesiredAcces, + IN PGENERIC_MAPPING GenericMapping, + OUT PPRIVILEGE_SET PrivilegeSet, + OUT PULONG ReturnLength, + OUT PACCESS_MASK GrantedAccess, + OUT PNTSTATUS AccessStatus +); + +NTSTATUS +STDCALL +ZwAccessCheck( + IN PSECURITY_DESCRIPTOR SecurityDescriptor, + IN HANDLE ClientToken, + IN ACCESS_MASK DesiredAcces, + IN PGENERIC_MAPPING GenericMapping, + OUT PPRIVILEGE_SET PrivilegeSet, + OUT PULONG ReturnLength, + OUT PACCESS_MASK GrantedAccess, + OUT PNTSTATUS AccessStatus +); + +NTSTATUS +STDCALL +NtAccessCheckAndAuditAlarm( + IN PUNICODE_STRING SubsystemName, + IN PHANDLE ObjectHandle, + IN PUNICODE_STRING ObjectTypeName, + IN PUNICODE_STRING ObjectName, + IN PSECURITY_DESCRIPTOR SecurityDescriptor, + IN ACCESS_MASK DesiredAccess, + IN PGENERIC_MAPPING GenericMapping, + IN BOOLEAN ObjectCreation, + OUT PACCESS_MASK GrantedAccess, + OUT PNTSTATUS AccessStatus, + OUT PBOOLEAN GenerateOnClose +); + +NTSTATUS +STDCALL +NtAddAtom( + IN PWSTR AtomName, + IN ULONG AtomNameLength, + IN OUT PRTL_ATOM Atom +); + +NTSTATUS +STDCALL +ZwAddAtom( + IN PWSTR AtomName, + IN ULONG AtomNameLength, + IN OUT PRTL_ATOM Atom +); + +NTSTATUS +STDCALL +NtAddBootEntry( + IN PUNICODE_STRING EntryName, + IN PUNICODE_STRING EntryValue +); + +NTSTATUS +STDCALL +ZwAddBootEntry( + IN PUNICODE_STRING EntryName, + IN PUNICODE_STRING EntryValue +); + +NTSTATUS +STDCALL +NtAdjustGroupsToken( + IN HANDLE TokenHandle, + IN BOOLEAN ResetToDefault, + IN PTOKEN_GROUPS NewState, + IN ULONG BufferLength, + OUT PTOKEN_GROUPS PreviousState OPTIONAL, + OUT PULONG ReturnLength +); + +NTSTATUS +STDCALL +ZwAdjustGroupsToken( + IN HANDLE TokenHandle, + IN BOOLEAN ResetToDefault, + IN PTOKEN_GROUPS NewState, + IN ULONG BufferLength, + OUT PTOKEN_GROUPS PreviousState, + OUT PULONG ReturnLength +); + +NTSTATUS +STDCALL +NtAdjustPrivilegesToken( + IN HANDLE TokenHandle, + IN BOOLEAN DisableAllPrivileges, + IN PTOKEN_PRIVILEGES NewState, + IN ULONG BufferLength, + OUT PTOKEN_PRIVILEGES PreviousState, + OUT PULONG ReturnLength +); + +NTSTATUS +STDCALL +ZwAdjustPrivilegesToken( + IN HANDLE TokenHandle, + IN BOOLEAN DisableAllPrivileges, + IN PTOKEN_PRIVILEGES NewState, + IN ULONG BufferLength, + OUT PTOKEN_PRIVILEGES PreviousState, + OUT PULONG ReturnLength +); + +NTSTATUS +STDCALL +NtAlertResumeThread( + IN HANDLE ThreadHandle, + OUT PULONG SuspendCount +); + +NTSTATUS +STDCALL +ZwAlertResumeThread( + IN HANDLE ThreadHandle, + OUT PULONG SuspendCount +); + +NTSTATUS +STDCALL +NtAlertThread( + IN HANDLE ThreadHandle +); + +NTSTATUS +STDCALL +ZwAlertThread( + IN HANDLE ThreadHandle +); + +NTSTATUS +STDCALL +NtAllocateLocallyUniqueId( + OUT LUID *LocallyUniqueId +); + +NTSTATUS +STDCALL +ZwAllocateLocallyUniqueId( + OUT PLUID Luid +); + +NTSTATUS +STDCALL +NtAllocateUuids( + PULARGE_INTEGER Time, + PULONG Range, + PULONG Sequence, + PUCHAR Seed +); + +NTSTATUS +STDCALL +ZwAllocateUuids( + PULARGE_INTEGER Time, + PULONG Range, + PULONG Sequence, + PUCHAR Seed +); + +NTSTATUS +STDCALL +NtAllocateVirtualMemory( + IN HANDLE ProcessHandle, + IN OUT PVOID *BaseAddress, + IN ULONG ZeroBits, + IN OUT PULONG RegionSize, + IN ULONG AllocationType, + IN ULONG Protect +); + +NTSTATUS +STDCALL +ZwAllocateVirtualMemory( + IN HANDLE ProcessHandle, + IN OUT PVOID *BaseAddress, + IN ULONG ZeroBits, + IN OUT PULONG RegionSize, + IN ULONG AllocationType, + IN ULONG Protect +); + +NTSTATUS +STDCALL +NtAssignProcessToJobObject( + HANDLE JobHandle, + HANDLE ProcessHandle +); + +NTSTATUS +STDCALL +ZwAssignProcessToJobObject( + HANDLE JobHandle, + HANDLE ProcessHandle +); + +NTSTATUS +STDCALL +NtCallbackReturn( + PVOID Result, + ULONG ResultLength, + NTSTATUS Status +); + +NTSTATUS +STDCALL +ZwCallbackReturn( + PVOID Result, + ULONG ResultLength, + NTSTATUS Status +); + +NTSTATUS +STDCALL +NtCancelIoFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock +); + +NTSTATUS +STDCALL +ZwCancelIoFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock +); + +NTSTATUS +STDCALL +NtCancelTimer( + IN HANDLE TimerHandle, + OUT PBOOLEAN CurrentState OPTIONAL +); + +NTSTATUS +STDCALL +NtClearEvent( + IN HANDLE EventHandle +); + +NTSTATUS +STDCALL +ZwClearEvent( + IN HANDLE EventHandle +); + +NTSTATUS +STDCALL +NtCreateJobObject( + PHANDLE JobHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +ZwCreateJobObject( + PHANDLE JobHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +NtClose( + IN HANDLE Handle +); + +NTSTATUS +STDCALL +ZwClose( + IN HANDLE Handle +); + +NTSTATUS +STDCALL +NtCloseObjectAuditAlarm( + IN PUNICODE_STRING SubsystemName, + IN PVOID HandleId, + IN BOOLEAN GenerateOnClose +); + +NTSTATUS +STDCALL +ZwCloseObjectAuditAlarm( + IN PUNICODE_STRING SubsystemName, + IN PVOID HandleId, + IN BOOLEAN GenerateOnClose +); + +NTSTATUS +STDCALL +NtCompleteConnectPort( + HANDLE PortHandle +); + +NTSTATUS +STDCALL +ZwCompleteConnectPort( + HANDLE PortHandle +); + +NTSTATUS +STDCALL +NtConnectPort( + PHANDLE PortHandle, + PUNICODE_STRING PortName, + PSECURITY_QUALITY_OF_SERVICE SecurityQos, + PLPC_SECTION_WRITE SectionInfo, + PLPC_SECTION_READ MapInfo, + PULONG MaxMessageSize, + PVOID ConnectInfo, + PULONG ConnectInfoLength +); + +NTSTATUS +STDCALL +ZwConnectPort( + PHANDLE PortHandle, + PUNICODE_STRING PortName, + PSECURITY_QUALITY_OF_SERVICE SecurityQos, + PLPC_SECTION_WRITE SectionInfo, + PLPC_SECTION_READ MapInfo, + PULONG MaxMessageSize, + PVOID ConnectInfo, + PULONG ConnectInfoLength +); + +NTSTATUS +STDCALL +NtContinue( + IN PCONTEXT Context, + IN BOOLEAN TestAlert +); + +NTSTATUS +STDCALL +ZwContinue( + IN PCONTEXT Context, + IN CINT IrqLevel +); + +NTSTATUS +STDCALL +NtCreateDirectoryObject( + OUT PHANDLE DirectoryHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +ZwCreateDirectoryObject( + OUT PHANDLE DirectoryHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +NtCreateEvent( + OUT PHANDLE EventHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN EVENT_TYPE EventType, + IN BOOLEAN InitialState +); + +NTSTATUS +STDCALL +ZwCreateEvent( + OUT PHANDLE EventHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN EVENT_TYPE EventType, + IN BOOLEAN InitialState +); + +NTSTATUS +STDCALL +NtCreateEventPair( + OUT PHANDLE EventPairHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +ZwCreateEventPair( + OUT PHANDLE EventPairHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +NtCreateFile( + OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER AllocationSize OPTIONAL, + IN ULONG FileAttributes, + IN ULONG ShareAccess, + IN ULONG CreateDisposition, + IN ULONG CreateOptions, + IN PVOID EaBuffer OPTIONAL, + IN ULONG EaLength +); + +NTSTATUS +STDCALL +ZwCreateFile( + OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER AllocationSize OPTIONAL, + IN ULONG FileAttributes, + IN ULONG ShareAccess, + IN ULONG CreateDisposition, + IN ULONG CreateOptions, + IN PVOID EaBuffer OPTIONAL, + IN ULONG EaLength +); + +NTSTATUS +STDCALL +NtCreateIoCompletion( + OUT PHANDLE IoCompletionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN ULONG NumberOfConcurrentThreads + ); + +NTSTATUS +STDCALL +ZwCreateIoCompletion( + OUT PHANDLE IoCompletionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN ULONG NumberOfConcurrentThreads + ); + +NTSTATUS +STDCALL +NtCreateKey( + OUT PHANDLE KeyHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN ULONG TitleIndex, + IN PUNICODE_STRING Class OPTIONAL, + IN ULONG CreateOptions, + IN PULONG Disposition OPTIONAL +); + +NTSTATUS +STDCALL +ZwCreateKey( + OUT PHANDLE KeyHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN ULONG TitleIndex, + IN PUNICODE_STRING Class OPTIONAL, + IN ULONG CreateOptions, + IN PULONG Disposition OPTIONAL +); + +NTSTATUS +STDCALL +NtCreateMailslotFile( + OUT PHANDLE MailSlotFileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG FileAttributes, + IN ULONG ShareAccess, + IN ULONG MaxMessageSize, + IN PLARGE_INTEGER TimeOut +); + +NTSTATUS +STDCALL +ZwCreateMailslotFile( + OUT PHANDLE MailSlotFileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG FileAttributes, + IN ULONG ShareAccess, + IN ULONG MaxMessageSize, + IN PLARGE_INTEGER TimeOut +); + +NTSTATUS +STDCALL +NtCreateMutant( + OUT PHANDLE MutantHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN BOOLEAN InitialOwner +); + +NTSTATUS +STDCALL +ZwCreateMutant( + OUT PHANDLE MutantHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN BOOLEAN InitialOwner +); + +NTSTATUS +STDCALL +NtCreateNamedPipeFile( + OUT PHANDLE NamedPipeFileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG ShareAccess, + IN ULONG CreateDisposition, + IN ULONG CreateOptions, + IN ULONG WriteModeMessage, + IN ULONG ReadModeMessage, + IN ULONG NonBlocking, + IN ULONG MaxInstances, + IN ULONG InBufferSize, + IN ULONG OutBufferSize, + IN PLARGE_INTEGER DefaultTimeOut +); + +NTSTATUS +STDCALL +ZwCreateNamedPipeFile( + OUT PHANDLE NamedPipeFileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG ShareAccess, + IN ULONG CreateDisposition, + IN ULONG CreateOptions, + IN ULONG WriteModeMessage, + IN ULONG ReadModeMessage, + IN ULONG NonBlocking, + IN ULONG MaxInstances, + IN ULONG InBufferSize, + IN ULONG OutBufferSize, + IN PLARGE_INTEGER DefaultTimeOut +); + +NTSTATUS +STDCALL +NtCreatePagingFile( + IN PUNICODE_STRING FileName, + IN PLARGE_INTEGER InitialSize, + IN PLARGE_INTEGER MaxiumSize, + IN ULONG Reserved +); + +NTSTATUS +STDCALL +ZwCreatePagingFile( + IN PUNICODE_STRING FileName, + IN PLARGE_INTEGER InitialSize, + IN PLARGE_INTEGER MaxiumSize, + IN ULONG Reserved +); + +NTSTATUS +STDCALL +NtCreatePort( + PHANDLE PortHandle, + POBJECT_ATTRIBUTES ObjectAttributes, + ULONG MaxConnectInfoLength, + ULONG MaxDataLength, + ULONG NPMessageQueueSize OPTIONAL +); + +NTSTATUS +STDCALL +NtCreatePort( + PHANDLE PortHandle, + POBJECT_ATTRIBUTES ObjectAttributes, + ULONG MaxConnectInfoLength, + ULONG MaxDataLength, + ULONG NPMessageQueueSize OPTIONAL +); + +NTSTATUS +STDCALL +NtCreateProcess( + OUT PHANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN HANDLE ParentProcess, + IN BOOLEAN InheritObjectTable, + IN HANDLE SectionHandle OPTIONAL, + IN HANDLE DebugPort OPTIONAL, + IN HANDLE ExceptionPort OPTIONAL +); + +NTSTATUS +STDCALL +ZwCreateProcess( + OUT PHANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN HANDLE ParentProcess, + IN BOOLEAN InheritObjectTable, + IN HANDLE SectionHandle OPTIONAL, + IN HANDLE DebugPort OPTIONAL, + IN HANDLE ExceptionPort OPTIONAL +); + +NTSTATUS +STDCALL +NtCreateProfile( + OUT PHANDLE ProfileHandle, + IN HANDLE ProcessHandle, + IN PVOID ImageBase, + IN ULONG ImageSize, + IN ULONG Granularity, + OUT PVOID Buffer, + IN ULONG ProfilingSize, + IN KPROFILE_SOURCE Source, + IN KAFFINITY ProcessorMask +); + +NTSTATUS +STDCALL +ZwCreateProfile( + OUT PHANDLE ProfileHandle, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN ULONG ImageBase, + IN ULONG ImageSize, + IN ULONG Granularity, + OUT PVOID Buffer, + IN ULONG ProfilingSize, + IN ULONG ClockSource, + IN ULONG ProcessorMask +); + +NTSTATUS +STDCALL +NtCreateSection( + OUT PHANDLE SectionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN PLARGE_INTEGER MaximumSize OPTIONAL, + IN ULONG SectionPageProtection OPTIONAL, + IN ULONG AllocationAttributes, + IN HANDLE FileHandle OPTIONAL +); + +NTSTATUS +STDCALL +ZwCreateSection( + OUT PHANDLE SectionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN PLARGE_INTEGER MaximumSize OPTIONAL, + IN ULONG SectionPageProtection OPTIONAL, + IN ULONG AllocationAttributes, + IN HANDLE FileHandle OPTIONAL +); + +NTSTATUS +STDCALL +NtCreateSemaphore( + OUT PHANDLE SemaphoreHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN LONG InitialCount, + IN LONG MaximumCount +); + +NTSTATUS +STDCALL +ZwCreateSemaphore( + OUT PHANDLE SemaphoreHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN LONG InitialCount, + IN LONG MaximumCount +); + +NTSTATUS +STDCALL +NtCreateSymbolicLinkObject( + OUT PHANDLE SymbolicLinkHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN PUNICODE_STRING Name +); + +NTSTATUS +STDCALL +ZwCreateSymbolicLinkObject( + OUT PHANDLE SymbolicLinkHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN PUNICODE_STRING Name +); + +NTSTATUS +STDCALL +NtCreateThread( + OUT PHANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN HANDLE ProcessHandle, + OUT PCLIENT_ID ClientId, + IN PCONTEXT ThreadContext, + IN PINITIAL_TEB UserStack, + IN BOOLEAN CreateSuspended +); + +NTSTATUS +STDCALL +ZwCreateThread( + OUT PHANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN HANDLE ProcessHandle, + OUT PCLIENT_ID ClientId, + IN PCONTEXT ThreadContext, + IN PINITIAL_TEB UserStack, + IN BOOLEAN CreateSuspended +); + +NTSTATUS +STDCALL +NtCreateTimer( + OUT PHANDLE TimerHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN TIMER_TYPE TimerType +); + +NTSTATUS +STDCALL +ZwCreateTimer( + OUT PHANDLE TimerHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN TIMER_TYPE TimerType +); + +NTSTATUS +STDCALL +NtCreateToken( + OUT PHANDLE TokenHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN TOKEN_TYPE TokenType, + IN PLUID AuthenticationId, + IN PLARGE_INTEGER ExpirationTime, + IN PTOKEN_USER TokenUser, + IN PTOKEN_GROUPS TokenGroups, + IN PTOKEN_PRIVILEGES TokenPrivileges, + IN PTOKEN_OWNER TokenOwner, + IN PTOKEN_PRIMARY_GROUP TokenPrimaryGroup, + IN PTOKEN_DEFAULT_DACL TokenDefaultDacl, + IN PTOKEN_SOURCE TokenSource +); + +NTSTATUS +STDCALL +ZwCreateToken( + OUT PHANDLE TokenHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN TOKEN_TYPE TokenType, + IN PLUID AuthenticationId, + IN PLARGE_INTEGER ExpirationTime, + IN PTOKEN_USER TokenUser, + IN PTOKEN_GROUPS TokenGroups, + IN PTOKEN_PRIVILEGES TokenPrivileges, + IN PTOKEN_OWNER TokenOwner, + IN PTOKEN_PRIMARY_GROUP TokenPrimaryGroup, + IN PTOKEN_DEFAULT_DACL TokenDefaultDacl, + IN PTOKEN_SOURCE TokenSource +); + +NTSTATUS +STDCALL +NtCreateWaitablePort( + PHANDLE PortHandle, + POBJECT_ATTRIBUTES ObjectAttributes, + ULONG MaxConnectInfoLength, + ULONG MaxDataLength, + ULONG NPMessageQueueSize OPTIONAL +); + +NTSTATUS +STDCALL +ZwCreateWaitablePort( + PHANDLE PortHandle, + POBJECT_ATTRIBUTES ObjectAttributes, + ULONG MaxConnectInfoLength, + ULONG MaxDataLength, + ULONG NPMessageQueueSize OPTIONAL +); + +NTSTATUS +STDCALL +NtDelayExecution( + IN BOOLEAN Alertable, + IN LARGE_INTEGER *Interval +); + +NTSTATUS +STDCALL +ZwDelayExecution( + IN BOOLEAN Alertable, + IN LARGE_INTEGER *Interval +); + +NTSTATUS +STDCALL +NtDeleteAtom( + IN RTL_ATOM Atom +); + +NTSTATUS +STDCALL +ZwDeleteAtom( + IN RTL_ATOM Atom +); + +NTSTATUS +STDCALL +NtDeleteBootEntry( + IN PUNICODE_STRING EntryName, + IN PUNICODE_STRING EntryValue +); + +NTSTATUS +STDCALL +ZwDeleteBootEntry( + IN PUNICODE_STRING EntryName, + IN PUNICODE_STRING EntryValue +); + +NTSTATUS +STDCALL +NtDeleteFile( + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +ZwDeleteFile( + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +NtDeleteKey( + IN HANDLE KeyHandle +); + +NTSTATUS +STDCALL +ZwDeleteKey( + IN HANDLE KeyHandle +); + +NTSTATUS +STDCALL +NtDeleteObjectAuditAlarm( + IN PUNICODE_STRING SubsystemName, + IN PVOID HandleId, + IN BOOLEAN GenerateOnClose +); + +NTSTATUS +STDCALL +ZwDeleteObjectAuditAlarm( + IN PUNICODE_STRING SubsystemName, + IN PVOID HandleId, + IN BOOLEAN GenerateOnClose +); + +NTSTATUS +STDCALL +NtDeleteValueKey( + IN HANDLE KeyHandle, + IN PUNICODE_STRING ValueName +); + +NTSTATUS +STDCALL +ZwDeleteValueKey( + IN HANDLE KeyHandle, + IN PUNICODE_STRING ValueName +); + +NTSTATUS +STDCALL +NtDeviceIoControlFile( + IN HANDLE DeviceHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, + IN PVOID UserApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG IoControlCode, + IN PVOID InputBuffer, + IN ULONG InputBufferSize, + OUT PVOID OutputBuffer, + IN ULONG OutputBufferSize +); + +NTSTATUS +STDCALL +ZwDeviceIoControlFile( + IN HANDLE DeviceHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, + IN PVOID UserApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG IoControlCode, + IN PVOID InputBuffer, + IN ULONG InputBufferSize, + OUT PVOID OutputBuffer, + IN ULONG OutputBufferSize +); + +NTSTATUS +STDCALL +NtDisplayString( + IN PUNICODE_STRING DisplayString +); + +NTSTATUS +STDCALL +ZwDisplayString( + IN PUNICODE_STRING DisplayString +); + +NTSTATUS +STDCALL +NtDuplicateObject( + IN HANDLE SourceProcessHandle, + IN HANDLE SourceHandle, + IN HANDLE TargetProcessHandle, + OUT PHANDLE TargetHandle, + IN ACCESS_MASK DesiredAccess, + IN ULONG HandleAttributes, + IN ULONG Options +); + +NTSTATUS +STDCALL +ZwDuplicateObject( + IN HANDLE SourceProcessHandle, + IN HANDLE SourceHandle, + IN HANDLE TargetProcessHandle, + OUT PHANDLE TargetHandle, + IN ACCESS_MASK DesiredAccess, + IN ULONG HandleAttributes, + IN ULONG Options +); + +NTSTATUS +STDCALL +NtDuplicateToken( + IN HANDLE ExistingTokenHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, + IN BOOLEAN EffectiveOnly, + IN TOKEN_TYPE TokenType, + OUT PHANDLE NewTokenHandle +); + +NTSTATUS +STDCALL +NtEnumerateBootEntries( + IN ULONG Unknown1, + IN ULONG Unknown2 +); + +NTSTATUS +STDCALL +ZwEnumerateBootEntries( + IN ULONG Unknown1, + IN ULONG Unknown2 +); + +NTSTATUS +STDCALL +NtEnumerateKey( + IN HANDLE KeyHandle, + IN ULONG Index, + IN KEY_INFORMATION_CLASS KeyInformationClass, + OUT PVOID KeyInformation, + IN ULONG Length, + OUT PULONG ResultLength +); + +NTSTATUS +STDCALL +ZwEnumerateKey( + IN HANDLE KeyHandle, + IN ULONG Index, + IN KEY_INFORMATION_CLASS KeyInformationClass, + OUT PVOID KeyInformation, + IN ULONG Length, + OUT PULONG ResultLength +); + +NTSTATUS +STDCALL +NtEnumerateValueKey( + IN HANDLE KeyHandle, + IN ULONG Index, + IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + OUT PVOID KeyValueInformation, + IN ULONG Length, + OUT PULONG ResultLength +); + +NTSTATUS +STDCALL +ZwEnumerateValueKey( + IN HANDLE KeyHandle, + IN ULONG Index, + IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + OUT PVOID KeyValueInformation, + IN ULONG Length, + OUT PULONG ResultLength +); + +NTSTATUS +STDCALL +NtExtendSection( + IN HANDLE SectionHandle, + IN PLARGE_INTEGER NewMaximumSize +); + +NTSTATUS +STDCALL +ZwExtendSection( + IN HANDLE SectionHandle, + IN PLARGE_INTEGER NewMaximumSize +); + +NTSTATUS +STDCALL +NtFindAtom( + IN PWSTR AtomName, + IN ULONG AtomNameLength, + OUT PRTL_ATOM Atom OPTIONAL +); + +NTSTATUS +STDCALL +ZwFindAtom( + IN PWSTR AtomName, + IN ULONG AtomNameLength, + OUT PRTL_ATOM Atom OPTIONAL +); + +NTSTATUS +STDCALL +NtFlushBuffersFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock +); + +NTSTATUS +STDCALL +ZwFlushBuffersFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock +); + +NTSTATUS +STDCALL +NtFlushInstructionCache( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + IN UINT NumberOfBytesToFlush +); + +NTSTATUS +STDCALL +NtFlushKey( + IN HANDLE KeyHandle +); + +NTSTATUS +STDCALL +ZwFlushKey( + IN HANDLE KeyHandle +); + +NTSTATUS +STDCALL +NtFlushVirtualMemory( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + IN ULONG NumberOfBytesToFlush, + OUT PULONG NumberOfBytesFlushed OPTIONAL +); + +NTSTATUS +STDCALL +NtFlushWriteBuffer(VOID); + +NTSTATUS +STDCALL +ZwFlushWriteBuffer(VOID); + +NTSTATUS +STDCALL +NtFreeVirtualMemory( + IN HANDLE ProcessHandle, + IN PVOID *BaseAddress, + IN PULONG RegionSize, + IN ULONG FreeType +); + +NTSTATUS +STDCALL +ZwFreeVirtualMemory( + IN HANDLE ProcessHandle, + IN PVOID *BaseAddress, + IN PULONG RegionSize, + IN ULONG FreeType +); + +NTSTATUS +STDCALL +NtFsControlFile( + IN HANDLE DeviceHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG IoControlCode, + IN PVOID InputBuffer, + IN ULONG InputBufferSize, + OUT PVOID OutputBuffer, + IN ULONG OutputBufferSize +); + +NTSTATUS +STDCALL +ZwFsControlFile( + IN HANDLE DeviceHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG IoControlCode, + IN PVOID InputBuffer, + IN ULONG InputBufferSize, + OUT PVOID OutputBuffer, + IN ULONG OutputBufferSize +); + +NTSTATUS +STDCALL +NtGetContextThread( + IN HANDLE ThreadHandle, + OUT PCONTEXT Context +); + +NTSTATUS +STDCALL +ZwGetContextThread( + IN HANDLE ThreadHandle, + OUT PCONTEXT Context +); + +NTSTATUS +STDCALL +NtGetPlugPlayEvent( + IN ULONG Reserved1, + IN ULONG Reserved2, + OUT PPLUGPLAY_EVENT_BLOCK Buffer, + IN ULONG BufferSize +); + +ULONG +STDCALL +NtGetTickCount( + VOID +); + +ULONG +STDCALL +ZwGetTickCount( + VOID +); + +NTSTATUS +STDCALL +NtImpersonateClientOfPort( + HANDLE PortHandle, + PLPC_MESSAGE ClientMessage +); + +NTSTATUS +STDCALL +ZwImpersonateClientOfPort( + HANDLE PortHandle, + PLPC_MESSAGE ClientMessage +); + +NTSTATUS +STDCALL +NtImpersonateThread( + IN HANDLE ThreadHandle, + IN HANDLE ThreadToImpersonate, + IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService +); + +NTSTATUS +STDCALL +ZwImpersonateThread( + IN HANDLE ThreadHandle, + IN HANDLE ThreadToImpersonate, + IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService +); + +NTSTATUS +STDCALL +NtInitiatePowerAction( + POWER_ACTION SystemAction, + SYSTEM_POWER_STATE MinSystemState, + ULONG Flags, + BOOLEAN Asynchronous +); + +NTSTATUS +STDCALL +ZwInitiatePowerAction( + POWER_ACTION SystemAction, + SYSTEM_POWER_STATE MinSystemState, + ULONG Flags, + BOOLEAN Asynchronous +); + +NTSTATUS +STDCALL +NtInitializeRegistry( + BOOLEAN SetUpBoot +); + +NTSTATUS +STDCALL +ZwInitializeRegistry( + BOOLEAN SetUpBoot +); + +NTSTATUS +STDCALL +NtIsProcessInJob( + IN HANDLE ProcessHandle, + IN HANDLE JobHandle OPTIONAL +); + +NTSTATUS +STDCALL +ZwIsProcessInJob( + IN HANDLE ProcessHandle, + IN HANDLE JobHandle OPTIONAL +); + +NTSTATUS +STDCALL +NtListenPort(HANDLE PortHandle, + PLPC_MESSAGE LpcMessage +); + +NTSTATUS +STDCALL +ZwListenPort(HANDLE PortHandle, + PLPC_MESSAGE LpcMessage +); + +NTSTATUS +STDCALL +NtLoadDriver( + IN PUNICODE_STRING DriverServiceName +); + +NTSTATUS +STDCALL +ZwLoadDriver( + IN PUNICODE_STRING DriverServiceName +); + +NTSTATUS +STDCALL +NtLoadKey( + IN POBJECT_ATTRIBUTES KeyObjectAttributes, + IN POBJECT_ATTRIBUTES FileObjectAttributes +); + +NTSTATUS +STDCALL +ZwLoadKey( + IN POBJECT_ATTRIBUTES KeyObjectAttributes, + IN POBJECT_ATTRIBUTES FileObjectAttributes +); + +NTSTATUS +STDCALL +NtLoadKey2( + IN POBJECT_ATTRIBUTES KeyObjectAttributes, + IN POBJECT_ATTRIBUTES FileObjectAttributes, + IN ULONG Flags +); + +NTSTATUS +STDCALL +ZwLoadKey2( + IN POBJECT_ATTRIBUTES KeyObjectAttributes, + IN POBJECT_ATTRIBUTES FileObjectAttributes, + IN ULONG Flags +); + +NTSTATUS +STDCALL +NtLockFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER ByteOffset, + IN PLARGE_INTEGER Length, + IN PULONG Key, + IN BOOLEAN FailImmediatedly, + IN BOOLEAN ExclusiveLock +); + +NTSTATUS +STDCALL +ZwLockFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER ByteOffset, + IN PLARGE_INTEGER Length, + IN PULONG Key, + IN BOOLEAN FailImmediatedly, + IN BOOLEAN ExclusiveLock +); + +NTSTATUS +STDCALL +NtLockVirtualMemory( + HANDLE ProcessHandle, + PVOID BaseAddress, + ULONG NumberOfBytesToLock, + PULONG NumberOfBytesLocked +); + +NTSTATUS +STDCALL +ZwLockVirtualMemory( + HANDLE ProcessHandle, + PVOID BaseAddress, + ULONG NumberOfBytesToLock, + PULONG NumberOfBytesLocked +); + +NTSTATUS +STDCALL +NtMakePermanentObject( + IN HANDLE Object +); + +NTSTATUS +STDCALL +ZwMakePermanentObject( + IN HANDLE Object +); + +NTSTATUS +STDCALL +NtMakeTemporaryObject( + IN HANDLE Handle +); + +NTSTATUS +STDCALL +ZwMakeTemporaryObject( + IN HANDLE Handle +); + +NTSTATUS +STDCALL +NtMapViewOfSection( + IN HANDLE SectionHandle, + IN HANDLE ProcessHandle, + IN OUT PVOID *BaseAddress, + IN ULONG ZeroBits, + IN ULONG CommitSize, + IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, + IN OUT PULONG ViewSize, + IN SECTION_INHERIT InheritDisposition, + IN ULONG AllocationType, + IN ULONG AccessProtection +); + +NTSTATUS +STDCALL +ZwMapViewOfSection( + IN HANDLE SectionHandle, + IN HANDLE ProcessHandle, + IN OUT PVOID *BaseAddress, + IN ULONG ZeroBits, + IN ULONG CommitSize, + IN OUT PLARGE_INTEGER SectionOffset OPTIONAL, + IN OUT PULONG ViewSize, + IN SECTION_INHERIT InheritDisposition, + IN ULONG AllocationType, + IN ULONG AccessProtection +); + +NTSTATUS +STDCALL +NtNotifyChangeDirectoryFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG BufferSize, + IN ULONG CompletionFilter, + IN BOOLEAN WatchTree +); + +NTSTATUS +STDCALL +ZwNotifyChangeDirectoryFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG BufferSize, + IN ULONG CompletionFilter, + IN BOOLEAN WatchTree +); + +NTSTATUS +STDCALL +NtNotifyChangeKey( + IN HANDLE KeyHandle, + IN HANDLE Event, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG CompletionFilter, + IN BOOLEAN Asynchroneous, + OUT PVOID ChangeBuffer, + IN ULONG Length, + IN BOOLEAN WatchSubtree +); + +NTSTATUS +STDCALL +ZwNotifyChangeKey( + IN HANDLE KeyHandle, + IN HANDLE Event, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG CompletionFilter, + IN BOOLEAN Asynchroneous, + OUT PVOID ChangeBuffer, + IN ULONG Length, + IN BOOLEAN WatchSubtree +); + +NTSTATUS +STDCALL +NtOpenDirectoryObject( + OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +ZwOpenDirectoryObject( + OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +NtOpenEvent( + OUT PHANDLE EventHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +ZwOpenEvent( + OUT PHANDLE EventHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +NtOpenEventPair( + OUT PHANDLE EventPairHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +ZwOpenEventPair( + OUT PHANDLE EventPairHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +NtOpenFile( + OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG ShareAccess, + IN ULONG OpenOptions +); + +NTSTATUS +STDCALL +ZwOpenFile( + OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG ShareAccess, + IN ULONG OpenOptions +); + +NTSTATUS +STDCALL +NtOpenIoCompletion( + OUT PHANDLE CompetionPort, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +ZwOpenIoCompletion( + OUT PHANDLE CompetionPort, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +NtOpenJobObject( + PHANDLE JobHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +ZwOpenJobObject( + PHANDLE JobHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +NtOpenKey( + OUT PHANDLE KeyHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +ZwOpenKey( + OUT PHANDLE KeyHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +NtOpenMutant( + OUT PHANDLE MutantHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +ZwOpenMutant( + OUT PHANDLE MutantHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +NtOpenObjectAuditAlarm( + IN PUNICODE_STRING SubsystemName, + IN PVOID HandleId, + IN PUNICODE_STRING ObjectTypeName, + IN PUNICODE_STRING ObjectName, + IN PSECURITY_DESCRIPTOR SecurityDescriptor, + IN HANDLE ClientToken, + IN ULONG DesiredAccess, + IN ULONG GrantedAccess, + IN PPRIVILEGE_SET Privileges, + IN BOOLEAN ObjectCreation, + IN BOOLEAN AccessGranted, + OUT PBOOLEAN GenerateOnClose +); + +NTSTATUS +STDCALL +ZwOpenObjectAuditAlarm( + IN PUNICODE_STRING SubsystemName, + IN PVOID HandleId, + IN PUNICODE_STRING ObjectTypeName, + IN PUNICODE_STRING ObjectName, + IN PSECURITY_DESCRIPTOR SecurityDescriptor, + IN HANDLE ClientToken, + IN ULONG DesiredAccess, + IN ULONG GrantedAccess, + IN PPRIVILEGE_SET Privileges, + IN BOOLEAN ObjectCreation, + IN BOOLEAN AccessGranted, + OUT PBOOLEAN GenerateOnClose +); + +NTSTATUS +STDCALL +NtOpenProcess( + OUT PHANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN PCLIENT_ID ClientId +); + +NTSTATUS +STDCALL +ZwOpenProcess( + OUT PHANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN PCLIENT_ID ClientId +); + +NTSTATUS +STDCALL +NtOpenProcessToken( + IN HANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE TokenHandle +); + +NTSTATUS +STDCALL +ZwOpenProcessToken( + IN HANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE TokenHandle +); + +NTSTATUS +STDCALL +NtOpenProcessTokenEx( + IN HANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN ULONG HandleAttributes, + OUT PHANDLE TokenHandle +); + +NTSTATUS +STDCALL +ZwOpenProcessTokenEx( + IN HANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN ULONG HandleAttributes, + OUT PHANDLE TokenHandle +); + +NTSTATUS +STDCALL +NtOpenSection( + OUT PHANDLE SectionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +ZwOpenSection( + OUT PHANDLE SectionHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +NtOpenSemaphore( + OUT PHANDLE SemaphoreHandle, + IN ACCESS_MASK DesiredAcces, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +ZwOpenSemaphore( + OUT PHANDLE SemaphoreHandle, + IN ACCESS_MASK DesiredAcces, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +NtOpenSymbolicLinkObject( + OUT PHANDLE SymbolicLinkHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +ZwOpenSymbolicLinkObject( + OUT PHANDLE SymbolicLinkHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +NtOpenThread( + OUT PHANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN PCLIENT_ID ClientId +); + +NTSTATUS +STDCALL +ZwOpenThread( + OUT PHANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN PCLIENT_ID ClientId +); + +NTSTATUS +STDCALL +NtOpenThreadToken( + IN HANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN BOOLEAN OpenAsSelf, + OUT PHANDLE TokenHandle +); + +NTSTATUS +STDCALL +ZwOpenThreadToken( + IN HANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN BOOLEAN OpenAsSelf, + OUT PHANDLE TokenHandle +); + +NTSTATUS +STDCALL +NtOpenThreadTokenEx( + IN HANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN BOOLEAN OpenAsSelf, + IN ULONG HandleAttributes, + OUT PHANDLE TokenHandle +); + +NTSTATUS +STDCALL +ZwOpenThreadTokenEx( + IN HANDLE ThreadHandle, + IN ACCESS_MASK DesiredAccess, + IN BOOLEAN OpenAsSelf, + IN ULONG HandleAttributes, + OUT PHANDLE TokenHandle +); + +NTSTATUS +STDCALL +NtOpenTimer( + OUT PHANDLE TimerHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); +NTSTATUS +STDCALL +ZwOpenTimer( + OUT PHANDLE TimerHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes +); + +NTSTATUS +STDCALL +NtPlugPlayControl( + IN PLUGPLAY_CONTROL_CLASS PlugPlayControlClass, + IN OUT PVOID Buffer, + IN ULONG BufferSize +); + +NTSTATUS +STDCALL +NtPowerInformation( + POWER_INFORMATION_LEVEL PowerInformationLevel, + PVOID InputBuffer, + ULONG InputBufferLength, + PVOID OutputBuffer, + ULONG OutputBufferLength +); + +NTSTATUS +STDCALL +ZwPowerInformation( + POWER_INFORMATION_LEVEL PowerInformationLevel, + PVOID InputBuffer, + ULONG InputBufferLength, + PVOID OutputBuffer, + ULONG OutputBufferLength +); + +NTSTATUS +STDCALL +NtPrivilegeCheck( + IN HANDLE ClientToken, + IN PPRIVILEGE_SET RequiredPrivileges, + IN PBOOLEAN Result +); + +NTSTATUS +STDCALL +ZwPrivilegeCheck( + IN HANDLE ClientToken, + IN PPRIVILEGE_SET RequiredPrivileges, + IN PBOOLEAN Result +); + +NTSTATUS +STDCALL +NtPrivilegedServiceAuditAlarm( + IN PUNICODE_STRING SubsystemName, + IN PUNICODE_STRING ServiceName, + IN HANDLE ClientToken, + IN PPRIVILEGE_SET Privileges, + IN BOOLEAN AccessGranted +); + +NTSTATUS +STDCALL +ZwPrivilegedServiceAuditAlarm( + IN PUNICODE_STRING SubsystemName, + IN PUNICODE_STRING ServiceName, + IN HANDLE ClientToken, + IN PPRIVILEGE_SET Privileges, + IN BOOLEAN AccessGranted +); + +NTSTATUS +STDCALL +NtPrivilegeObjectAuditAlarm( + IN PUNICODE_STRING SubsystemName, + IN PVOID HandleId, + IN HANDLE ClientToken, + IN ULONG DesiredAccess, + IN PPRIVILEGE_SET Privileges, + IN BOOLEAN AccessGranted +); + +NTSTATUS +STDCALL +ZwPrivilegeObjectAuditAlarm( + IN PUNICODE_STRING SubsystemName, + IN PVOID HandleId, + IN HANDLE ClientToken, + IN ULONG DesiredAccess, + IN PPRIVILEGE_SET Privileges, + IN BOOLEAN AccessGranted +); + +NTSTATUS +STDCALL +NtProtectVirtualMemory( + IN HANDLE ProcessHandle, + IN PVOID *BaseAddress, + IN ULONG *NumberOfBytesToProtect, + IN ULONG NewAccessProtection, + OUT PULONG OldAccessProtection +); + +NTSTATUS +STDCALL +ZwProtectVirtualMemory( + IN HANDLE ProcessHandle, + IN PVOID *BaseAddress, + IN ULONG *NumberOfBytesToProtect, + IN ULONG NewAccessProtection, + OUT PULONG OldAccessProtection +); + +NTSTATUS +STDCALL +NtPulseEvent( + IN HANDLE EventHandle, + IN PLONG PulseCount OPTIONAL +); + +NTSTATUS +STDCALL +ZwPulseEvent( + IN HANDLE EventHandle, + IN PLONG PulseCount OPTIONAL +); + +NTSTATUS +STDCALL +NtQueryAttributesFile( + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PFILE_BASIC_INFORMATION FileInformation +); + +NTSTATUS +STDCALL +ZwQueryAttributesFile( + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PFILE_BASIC_INFORMATION FileInformation +); + + +NTSTATUS +STDCALL +NtQueryBootEntryOrder( + IN ULONG Unknown1, + IN ULONG Unknown2 +); + +NTSTATUS +STDCALL +ZwQueryBootEntryOrder( + IN ULONG Unknown1, + IN ULONG Unknown2 +); + +NTSTATUS +STDCALL +NtQueryBootOptions( + IN ULONG Unknown1, + IN ULONG Unknown2 +); + +NTSTATUS +STDCALL +ZwQueryBootOptions( + IN ULONG Unknown1, + IN ULONG Unknown2 +); +NTSTATUS +STDCALL +NtQueryDefaultLocale( + IN BOOLEAN UserProfile, + OUT PLCID DefaultLocaleId +); + +NTSTATUS +STDCALL +ZwQueryDefaultLocale( + IN BOOLEAN UserProfile, + OUT PLCID DefaultLocaleId +); + +NTSTATUS +STDCALL +NtQueryDefaultUILanguage( + PLANGID LanguageId +); + +NTSTATUS +STDCALL +ZwQueryDefaultUILanguage( + PLANGID LanguageId +); + +NTSTATUS +STDCALL +NtQueryDirectoryFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID FileInformation, + IN ULONG Length, + IN FILE_INFORMATION_CLASS FileInformationClass, + IN BOOLEAN ReturnSingleEntry, + IN PUNICODE_STRING FileName OPTIONAL, + IN BOOLEAN RestartScan +); + +NTSTATUS +STDCALL +ZwQueryDirectoryFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID FileInformation, + IN ULONG Length, + IN FILE_INFORMATION_CLASS FileInformationClass, + IN BOOLEAN ReturnSingleEntry, + IN PUNICODE_STRING FileName OPTIONAL, + IN BOOLEAN RestartScan +); + +NTSTATUS +STDCALL +NtQueryDirectoryObject( + IN HANDLE DirectoryHandle, + OUT PVOID Buffer, + IN ULONG BufferLength, + IN BOOLEAN ReturnSingleEntry, + IN BOOLEAN RestartScan, + IN OUT PULONG Context, + OUT PULONG ReturnLength OPTIONAL +); + +NTSTATUS +STDCALL +ZwQueryDirectoryObject( + IN HANDLE DirectoryHandle, + OUT PVOID Buffer, + IN ULONG BufferLength, + IN BOOLEAN ReturnSingleEntry, + IN BOOLEAN RestartScan, + IN OUT PULONG Context, + OUT PULONG ReturnLength OPTIONAL +); + +NTSTATUS +STDCALL +NtQueryEaFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG Length, + IN BOOLEAN ReturnSingleEntry, + IN PVOID EaList OPTIONAL, + IN ULONG EaListLength, + IN PULONG EaIndex OPTIONAL, + IN BOOLEAN RestartScan +); + +NTSTATUS +STDCALL +ZwQueryEaFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG Length, + IN BOOLEAN ReturnSingleEntry, + IN PVOID EaList OPTIONAL, + IN ULONG EaListLength, + IN PULONG EaIndex OPTIONAL, + IN BOOLEAN RestartScan +); + +NTSTATUS +STDCALL +NtQueryEvent( + IN HANDLE EventHandle, + IN EVENT_INFORMATION_CLASS EventInformationClass, + OUT PVOID EventInformation, + IN ULONG EventInformationLength, + OUT PULONG ReturnLength +); +NTSTATUS +STDCALL +ZwQueryEvent( + IN HANDLE EventHandle, + IN EVENT_INFORMATION_CLASS EventInformationClass, + OUT PVOID EventInformation, + IN ULONG EventInformationLength, + OUT PULONG ReturnLength +); + +NTSTATUS +STDCALL +NtQueryFullAttributesFile( + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation +); + +NTSTATUS +STDCALL +ZwQueryFullAttributesFile( + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation +); + +NTSTATUS +STDCALL +NtQueryInformationAtom( + IN RTL_ATOM Atom, + IN ATOM_INFORMATION_CLASS AtomInformationClass, + OUT PVOID AtomInformation, + IN ULONG AtomInformationLength, + OUT PULONG ReturnLength OPTIONAL +); + +NTSTATUS +STDCALL +ZwQueryInformationAtom( + IN RTL_ATOM Atom, + IN ATOM_INFORMATION_CLASS AtomInformationClass, + OUT PVOID AtomInformation, + IN ULONG AtomInformationLength, + OUT PULONG ReturnLength OPTIONAL +); + +NTSTATUS +STDCALL +NtQueryInformationFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID FileInformation, + IN ULONG Length, + IN FILE_INFORMATION_CLASS FileInformationClass +); + +NTSTATUS +STDCALL +ZwQueryInformationFile( + HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass +); + +NTSTATUS +STDCALL +NtQueryInformationJobObject( + HANDLE JobHandle, + JOBOBJECTINFOCLASS JobInformationClass, + PVOID JobInformation, + ULONG JobInformationLength, + PULONG ReturnLength +); + +NTSTATUS +STDCALL +ZwQueryInformationJobObject( + HANDLE JobHandle, + JOBOBJECTINFOCLASS JobInformationClass, + PVOID JobInformation, + ULONG JobInformationLength, + PULONG ReturnLength +); + +NTSTATUS +STDCALL +NtQueryInformationPort( + HANDLE PortHandle, + CINT PortInformationClass, + PVOID PortInformation, + ULONG PortInformationLength, + PULONG ReturnLength +); + +NTSTATUS +STDCALL +ZwQueryInformationPort( + HANDLE PortHandle, + CINT PortInformationClass, + PVOID PortInformation, + ULONG PortInformationLength, + PULONG ReturnLength +); + +#ifndef _NTDDK_ +NTSTATUS +STDCALL +NtQueryInformationProcess( + IN HANDLE ProcessHandle, + IN PROCESSINFOCLASS ProcessInformationClass, + OUT PVOID ProcessInformation, + IN ULONG ProcessInformationLength, + OUT PULONG ReturnLength OPTIONAL +); + +NTSTATUS +STDCALL +ZwQueryInformationProcess( + IN HANDLE ProcessHandle, + IN PROCESSINFOCLASS ProcessInformationClass, + OUT PVOID ProcessInformation, + IN ULONG ProcessInformationLength, + OUT PULONG ReturnLength OPTIONAL +); +#endif + +NTSTATUS +STDCALL +NtQueryInformationThread( + IN HANDLE ThreadHandle, + IN THREADINFOCLASS ThreadInformationClass, + OUT PVOID ThreadInformation, + IN ULONG ThreadInformationLength, + OUT PULONG ReturnLength +); + +NTSTATUS +STDCALL +ZwQueryInformationThread( + IN HANDLE ThreadHandle, + IN THREADINFOCLASS ThreadInformationClass, + OUT PVOID ThreadInformation, + IN ULONG ThreadInformationLength, + OUT PULONG ReturnLength +); + +NTSTATUS +STDCALL +NtQueryInformationToken( + IN HANDLE TokenHandle, + IN TOKEN_INFORMATION_CLASS TokenInformationClass, + OUT PVOID TokenInformation, + IN ULONG TokenInformationLength, + OUT PULONG ReturnLength +); + +NTSTATUS +STDCALL +ZwQueryInformationToken( + IN HANDLE TokenHandle, + IN TOKEN_INFORMATION_CLASS TokenInformationClass, + OUT PVOID TokenInformation, + IN ULONG TokenInformationLength, + OUT PULONG ReturnLength +); + +NTSTATUS +STDCALL +NtQueryInstallUILanguage( + PLANGID LanguageId +); + +NTSTATUS +STDCALL +ZwQueryInstallUILanguage( + PLANGID LanguageId +); + +NTSTATUS +STDCALL +NtQueryIntervalProfile( + IN KPROFILE_SOURCE ProfileSource, + OUT PULONG Interval +); + +NTSTATUS +STDCALL +ZwQueryIntervalProfile( + OUT PULONG Interval, + OUT KPROFILE_SOURCE ClockSource +); + +NTSTATUS +STDCALL +NtQueryIoCompletion( + IN HANDLE IoCompletionHandle, + IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass, + OUT PVOID IoCompletionInformation, + IN ULONG IoCompletionInformationLength, + OUT PULONG ResultLength OPTIONAL +); + +NTSTATUS +STDCALL +ZwQueryIoCompletion( + IN HANDLE IoCompletionHandle, + IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass, + OUT PVOID IoCompletionInformation, + IN ULONG IoCompletionInformationLength, + OUT PULONG ResultLength OPTIONAL +); + +NTSTATUS +STDCALL +NtQueryKey( + IN HANDLE KeyHandle, + IN KEY_INFORMATION_CLASS KeyInformationClass, + OUT PVOID KeyInformation, + IN ULONG Length, + OUT PULONG ResultLength +); + +NTSTATUS +STDCALL +ZwQueryKey( + IN HANDLE KeyHandle, + IN KEY_INFORMATION_CLASS KeyInformationClass, + OUT PVOID KeyInformation, + IN ULONG Length, + OUT PULONG ResultLength +); + +NTSTATUS +STDCALL +NtQueryQuotaInformationFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG Length, + IN BOOLEAN ReturnSingleEntry, + IN PVOID SidList OPTIONAL, + IN ULONG SidListLength, + IN PSID StartSid OPTIONAL, + IN BOOLEAN RestartScan +); + +NTSTATUS +STDCALL +ZwQueryQuotaInformationFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG Length, + IN BOOLEAN ReturnSingleEntry, + IN PVOID SidList OPTIONAL, + IN ULONG SidListLength, + IN PSID StartSid OPTIONAL, + IN BOOLEAN RestartScan +); + +NTSTATUS +STDCALL +NtQueryMultipleValueKey( + IN HANDLE KeyHandle, + IN OUT PKEY_VALUE_ENTRY ValueList, + IN ULONG NumberOfValues, + OUT PVOID Buffer, + IN OUT PULONG Length, + OUT PULONG ReturnLength +); + +NTSTATUS +STDCALL +ZwQueryMultipleValueKey( + IN HANDLE KeyHandle, + IN OUT PKEY_VALUE_ENTRY ValueList, + IN ULONG NumberOfValues, + OUT PVOID Buffer, + IN OUT PULONG Length, + OUT PULONG ReturnLength +); + +NTSTATUS +STDCALL +NtQueryMutant( + IN HANDLE MutantHandle, + IN MUTANT_INFORMATION_CLASS MutantInformationClass, + OUT PVOID MutantInformation, + IN ULONG Length, + OUT PULONG ResultLength +); + +NTSTATUS +STDCALL +ZwQueryMutant( + IN HANDLE MutantHandle, + IN MUTANT_INFORMATION_CLASS MutantInformationClass, + OUT PVOID MutantInformation, + IN ULONG Length, + OUT PULONG ResultLength +); + +NTSTATUS +STDCALL +NtQueryObject( + IN HANDLE ObjectHandle, + IN OBJECT_INFORMATION_CLASS ObjectInformationClass, + OUT PVOID ObjectInformation, + IN ULONG Length, + OUT PULONG ResultLength OPTIONAL +); + +NTSTATUS +STDCALL +ZwQueryObject( + IN HANDLE ObjectHandle, + IN OBJECT_INFORMATION_CLASS ObjectInformationClass, + OUT PVOID ObjectInformation, + IN ULONG Length, + OUT PULONG ResultLength OPTIONAL +); + +NTSTATUS +STDCALL +NtQueryPerformanceCounter( + IN PLARGE_INTEGER Counter, + IN PLARGE_INTEGER Frequency +); + +NTSTATUS +STDCALL +ZwQueryPerformanceCounter( + IN PLARGE_INTEGER Counter, + IN PLARGE_INTEGER Frequency +); + +NTSTATUS +STDCALL +NtQuerySection( + IN HANDLE SectionHandle, + IN SECTION_INFORMATION_CLASS SectionInformationClass, + OUT PVOID SectionInformation, + IN ULONG Length, + OUT PULONG ResultLength +); + +NTSTATUS +STDCALL +ZwQuerySection( + IN HANDLE SectionHandle, + IN SECTION_INFORMATION_CLASS SectionInformationClass, + OUT PVOID SectionInformation, + IN ULONG Length, + OUT PULONG ResultLength +); + +NTSTATUS +STDCALL +NtQuerySecurityObject( + IN HANDLE Handle, + IN SECURITY_INFORMATION SecurityInformation, + OUT PSECURITY_DESCRIPTOR SecurityDescriptor, + IN ULONG Length, + OUT PULONG ResultLength +); + +NTSTATUS +STDCALL +ZwQuerySecurityObject( + IN HANDLE Handle, + IN SECURITY_INFORMATION SecurityInformation, + OUT PSECURITY_DESCRIPTOR SecurityDescriptor, + IN ULONG Length, + OUT PULONG ResultLength +); + +NTSTATUS +STDCALL +NtQuerySemaphore( + IN HANDLE SemaphoreHandle, + IN SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass, + OUT PVOID SemaphoreInformation, + IN ULONG Length, + OUT PULONG ReturnLength +); + +NTSTATUS +STDCALL +ZwQuerySemaphore( + IN HANDLE SemaphoreHandle, + IN SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass, + OUT PVOID SemaphoreInformation, + IN ULONG Length, + OUT PULONG ReturnLength +); + +NTSTATUS +STDCALL +NtQuerySymbolicLinkObject( + IN HANDLE SymLinkObjHandle, + OUT PUNICODE_STRING LinkTarget, + OUT PULONG DataWritten OPTIONAL +); + +NTSTATUS +STDCALL +ZwQuerySymbolicLinkObject( + IN HANDLE SymLinkObjHandle, + OUT PUNICODE_STRING LinkName, + OUT PULONG DataWritten OPTIONAL +); + +NTSTATUS +STDCALL +NtQuerySystemEnvironmentValue( + IN PUNICODE_STRING Name, + OUT PWSTR Value, + ULONG Length, + PULONG ReturnLength +); + +NTSTATUS +STDCALL +ZwQuerySystemEnvironmentValue( + IN PUNICODE_STRING Name, + OUT PVOID Value, + ULONG Length, + PULONG ReturnLength +); + +NTSTATUS +STDCALL +NtQuerySystemInformation( + IN SYSTEM_INFORMATION_CLASS SystemInformationClass, + OUT PVOID SystemInformation, + IN ULONG Length, + OUT PULONG ResultLength +); + +NTSTATUS +STDCALL +ZwQuerySystemInformation( + IN SYSTEM_INFORMATION_CLASS SystemInformationClass, + OUT PVOID SystemInformation, + IN ULONG Length, + OUT PULONG ResultLength +); + +NTSTATUS +STDCALL +NtQuerySystemTime( + OUT PLARGE_INTEGER CurrentTime +); + +NTSTATUS +STDCALL +ZwQuerySystemTime( + OUT PLARGE_INTEGER CurrentTime +); + +NTSTATUS +STDCALL +NtQueryTimer( + IN HANDLE TimerHandle, + IN TIMER_INFORMATION_CLASS TimerInformationClass, + OUT PVOID TimerInformation, + IN ULONG Length, + OUT PULONG ResultLength +); + +NTSTATUS +STDCALL +ZwQueryTimer( + IN HANDLE TimerHandle, + IN TIMER_INFORMATION_CLASS TimerInformationClass, + OUT PVOID TimerInformation, + IN ULONG Length, + OUT PULONG ResultLength +); + +NTSTATUS +STDCALL +NtQueryTimerResolution( + OUT PULONG MinimumResolution, + OUT PULONG MaximumResolution, + OUT PULONG ActualResolution +); + +NTSTATUS +STDCALL +ZwQueryTimerResolution( + OUT PULONG MinimumResolution, + OUT PULONG MaximumResolution, + OUT PULONG ActualResolution +); + +NTSTATUS +STDCALL +NtQueryValueKey( + IN HANDLE KeyHandle, + IN PUNICODE_STRING ValueName, + IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + OUT PVOID KeyValueInformation, + IN ULONG Length, + OUT PULONG ResultLength +); + +NTSTATUS +STDCALL +ZwQueryValueKey( + IN HANDLE KeyHandle, + IN PUNICODE_STRING ValueName, + IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + OUT PVOID KeyValueInformation, + IN ULONG Length, + OUT PULONG ResultLength +); + +NTSTATUS +STDCALL +NtQueryVirtualMemory( + IN HANDLE ProcessHandle, + IN PVOID Address, + IN IN CINT VirtualMemoryInformationClass, + OUT PVOID VirtualMemoryInformation, + IN ULONG Length, + OUT PULONG ResultLength +); + +NTSTATUS +STDCALL +ZwQueryVirtualMemory( + IN HANDLE ProcessHandle, + IN PVOID Address, + IN IN CINT VirtualMemoryInformationClass, + OUT PVOID VirtualMemoryInformation, + IN ULONG Length, + OUT PULONG ResultLength +); + +NTSTATUS +STDCALL +NtQueryVolumeInformationFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID FsInformation, + IN ULONG Length, + IN FS_INFORMATION_CLASS FsInformationClass +); + +NTSTATUS +STDCALL +ZwQueryVolumeInformationFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID FsInformation, + IN ULONG Length, + IN FS_INFORMATION_CLASS FsInformationClass +); + +NTSTATUS +STDCALL +NtQueueApcThread( + HANDLE ThreadHandle, + PKNORMAL_ROUTINE ApcRoutine, + PVOID NormalContext, + PVOID SystemArgument1, + PVOID SystemArgument2 +); + +NTSTATUS +STDCALL +ZwQueueApcThread( + HANDLE ThreadHandle, + PKNORMAL_ROUTINE ApcRoutine, + PVOID NormalContext, + PVOID SystemArgument1, + PVOID SystemArgument2 +); + +NTSTATUS +STDCALL +NtRaiseException( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PCONTEXT Context, + IN BOOLEAN SearchFrames +); + +NTSTATUS +STDCALL +ZwRaiseException( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PCONTEXT Context, + IN BOOLEAN SearchFrames +); + +NTSTATUS +STDCALL +NtRaiseHardError( + IN NTSTATUS ErrorStatus, + IN ULONG NumberOfParameters, + IN PUNICODE_STRING UnicodeStringParameterMask OPTIONAL, + IN PVOID *Parameters, + IN HARDERROR_RESPONSE_OPTION ResponseOption, + OUT PHARDERROR_RESPONSE Response +); + +NTSTATUS +STDCALL +ZwRaiseHardError( + IN NTSTATUS ErrorStatus, + IN ULONG NumberOfParameters, + IN PUNICODE_STRING UnicodeStringParameterMask OPTIONAL, + IN PVOID *Parameters, + IN HARDERROR_RESPONSE_OPTION ResponseOption, + OUT PHARDERROR_RESPONSE Response +); + +NTSTATUS +STDCALL +NtReadFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, + IN PVOID UserApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG BufferLength, + IN PLARGE_INTEGER ByteOffset OPTIONAL, + IN PULONG Key OPTIONAL +); + +NTSTATUS +STDCALL +ZwReadFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, + IN PVOID UserApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + OUT PVOID Buffer, + IN ULONG BufferLength, + IN PLARGE_INTEGER ByteOffset OPTIONAL, + IN PULONG Key OPTIONAL +); + +NTSTATUS +STDCALL +NtReadFileScatter( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, + IN PVOID UserApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK UserIoStatusBlock, + IN FILE_SEGMENT_ELEMENT BufferDescription[], + IN ULONG BufferLength, + IN PLARGE_INTEGER ByteOffset, + IN PULONG Key OPTIONAL +); + +NTSTATUS +STDCALL +ZwReadFileScatter( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL, + IN PVOID UserApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK UserIoStatusBlock, + IN FILE_SEGMENT_ELEMENT BufferDescription[], + IN ULONG BufferLength, + IN PLARGE_INTEGER ByteOffset, + IN PULONG Key OPTIONAL +); + +NTSTATUS +STDCALL +NtReadRequestData( + HANDLE PortHandle, + PLPC_MESSAGE Message, + ULONG Index, + PVOID Buffer, + ULONG BufferLength, + PULONG ReturnLength +); + +NTSTATUS +STDCALL +ZwReadRequestData( + HANDLE PortHandle, + PLPC_MESSAGE Message, + ULONG Index, + PVOID Buffer, + ULONG BufferLength, + PULONG ReturnLength +); + +NTSTATUS +STDCALL +NtReadVirtualMemory( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + OUT PVOID Buffer, + IN ULONG NumberOfBytesToRead, + OUT PULONG NumberOfBytesRead +); +NTSTATUS +STDCALL +ZwReadVirtualMemory( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + OUT PVOID Buffer, + IN ULONG NumberOfBytesToRead, + OUT PULONG NumberOfBytesRead +); + +NTSTATUS +STDCALL +NtRegisterThreadTerminatePort( + HANDLE TerminationPort +); + +NTSTATUS +STDCALL +ZwRegisterThreadTerminatePort( + HANDLE TerminationPort +); + +NTSTATUS +STDCALL +NtReleaseMutant( + IN HANDLE MutantHandle, + IN PLONG ReleaseCount OPTIONAL +); + +NTSTATUS +STDCALL +ZwReleaseMutant( + IN HANDLE MutantHandle, + IN PLONG ReleaseCount OPTIONAL +); + +NTSTATUS +STDCALL +NtReleaseSemaphore( + IN HANDLE SemaphoreHandle, + IN LONG ReleaseCount, + OUT PLONG PreviousCount +); + +NTSTATUS +STDCALL +ZwReleaseSemaphore( + IN HANDLE SemaphoreHandle, + IN LONG ReleaseCount, + OUT PLONG PreviousCount +); + +NTSTATUS +STDCALL +NtRemoveIoCompletion( + IN HANDLE IoCompletionHandle, + OUT PVOID *CompletionKey, + OUT PVOID *CompletionContext, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER Timeout OPTIONAL +); + +NTSTATUS +STDCALL +ZwRemoveIoCompletion( + IN HANDLE IoCompletionHandle, + OUT PVOID *CompletionKey, + OUT PVOID *CompletionContext, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER Timeout OPTIONAL +); + +NTSTATUS +STDCALL +NtReplaceKey( + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN HANDLE Key, + IN POBJECT_ATTRIBUTES ReplacedObjectAttributes +); + +NTSTATUS +STDCALL +ZwReplaceKey( + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN HANDLE Key, + IN POBJECT_ATTRIBUTES ReplacedObjectAttributes +); + +NTSTATUS +STDCALL +NtReplyPort( + HANDLE PortHandle, + PLPC_MESSAGE LpcReply +); + +NTSTATUS +STDCALL +ZwReplyPort( + HANDLE PortHandle, + PLPC_MESSAGE LpcReply +); + +NTSTATUS +STDCALL +NtReplyWaitReceivePort( + HANDLE PortHandle, + PULONG PortId, + PLPC_MESSAGE MessageReply, + PLPC_MESSAGE MessageRequest +); + +NTSTATUS +STDCALL +ZwReplyWaitReceivePort( + HANDLE PortHandle, + PULONG PortId, + PLPC_MESSAGE MessageReply, + PLPC_MESSAGE MessageRequest +); + +NTSTATUS +STDCALL +NtReplyWaitReplyPort( + HANDLE PortHandle, + PLPC_MESSAGE ReplyMessage +); + +NTSTATUS +STDCALL +ZwReplyWaitReplyPort( + HANDLE PortHandle, + PLPC_MESSAGE ReplyMessage +); + +NTSTATUS +STDCALL +NtRequestPort( + HANDLE PortHandle, + PLPC_MESSAGE LpcMessage); + +NTSTATUS +STDCALL +ZwRequestPort( + HANDLE PortHandle, + PLPC_MESSAGE LpcMessage +); + +NTSTATUS +STDCALL +NtRequestWaitReplyPort( + HANDLE PortHandle, + PLPC_MESSAGE LpcReply, + PLPC_MESSAGE LpcRequest +); + +NTSTATUS +STDCALL +ZwRequestWaitReplyPort( + HANDLE PortHandle, + PLPC_MESSAGE LpcReply, + PLPC_MESSAGE LpcRequest +); + +NTSTATUS +STDCALL +NtResetEvent( + HANDLE EventHandle, + PLONG NumberOfWaitingThreads OPTIONAL +); + +NTSTATUS +STDCALL +ZwResetEvent( + HANDLE EventHandle, + PLONG NumberOfWaitingThreads OPTIONAL +); + +NTSTATUS +STDCALL +NtRestoreKey( + HANDLE KeyHandle, + HANDLE FileHandle, + ULONG RestoreFlags +); + +NTSTATUS +STDCALL +ZwRestoreKey( + HANDLE KeyHandle, + HANDLE FileHandle, + ULONG RestoreFlags +); + +NTSTATUS +STDCALL +NtResumeThread( + IN HANDLE ThreadHandle, + OUT PULONG SuspendCount +); + +NTSTATUS +STDCALL +ZwResumeThread( + IN HANDLE ThreadHandle, + OUT PULONG SuspendCount +); + +NTSTATUS +STDCALL +NtResumeProcess( + IN HANDLE ProcessHandle +); + +NTSTATUS +STDCALL +ZwResumeProcess( + IN HANDLE ProcessHandle +); + +NTSTATUS +STDCALL +NtSaveKey( + IN HANDLE KeyHandle, + IN HANDLE FileHandle +); +NTSTATUS +STDCALL +ZwSaveKey( + IN HANDLE KeyHandle, + IN HANDLE FileHandle +); + +NTSTATUS +STDCALL +NtSaveKeyEx( + IN HANDLE KeyHandle, + IN HANDLE FileHandle, + IN ULONG Flags +); + +NTSTATUS +STDCALL +ZwSaveKeyEx( + IN HANDLE KeyHandle, + IN HANDLE FileHandle, + IN ULONG Flags +); + +NTSTATUS +STDCALL +NtSetBootEntryOrder( + IN ULONG Unknown1, + IN ULONG Unknown2 +); + +NTSTATUS +STDCALL +ZwSetBootEntryOrder( + IN ULONG Unknown1, + IN ULONG Unknown2 +); + +NTSTATUS +STDCALL +NtSetBootOptions( + ULONG Unknown1, + ULONG Unknown2 +); + +NTSTATUS +STDCALL +ZwSetBootOptions( + ULONG Unknown1, + ULONG Unknown2 +); + +NTSTATUS +STDCALL +NtSetContextThread( + IN HANDLE ThreadHandle, + IN PCONTEXT Context +); +NTSTATUS +STDCALL +ZwSetContextThread( + IN HANDLE ThreadHandle, + IN PCONTEXT Context +); + +NTSTATUS +STDCALL +NtSetDefaultLocale( + IN BOOLEAN UserProfile, + IN LCID DefaultLocaleId +); + +NTSTATUS +STDCALL +ZwSetDefaultLocale( + IN BOOLEAN UserProfile, + IN LCID DefaultLocaleId +); + +NTSTATUS +STDCALL +NtSetDefaultUILanguage( + LANGID LanguageId +); + +NTSTATUS +STDCALL +ZwSetDefaultUILanguage( + LANGID LanguageId +); +NTSTATUS +STDCALL +NtSetDefaultHardErrorPort( + IN HANDLE PortHandle +); +NTSTATUS +STDCALL +ZwSetDefaultHardErrorPort( + IN HANDLE PortHandle +); + +NTSTATUS +STDCALL +NtSetEaFile( + IN HANDLE FileHandle, + IN PIO_STATUS_BLOCK IoStatusBlock, + PVOID EaBuffer, + ULONG EaBufferSize +); + +NTSTATUS +STDCALL +ZwSetEaFile( + IN HANDLE FileHandle, + IN PIO_STATUS_BLOCK IoStatusBlock, + PVOID EaBuffer, + ULONG EaBufferSize +); + +NTSTATUS +STDCALL +NtSetEvent( + IN HANDLE EventHandle, + OUT PLONG PreviousState OPTIONAL +); + +NTSTATUS +STDCALL +ZwSetEvent( + IN HANDLE EventHandle, + OUT PLONG PreviousState OPTIONAL +); + +NTSTATUS +STDCALL +NtSetHighEventPair( + IN HANDLE EventPairHandle +); + +NTSTATUS +STDCALL +ZwSetHighEventPair( + IN HANDLE EventPairHandle +); +NTSTATUS +STDCALL +NtSetHighWaitLowEventPair( + IN HANDLE EventPairHandle +); +NTSTATUS +STDCALL +ZwSetHighWaitLowEventPair( + IN HANDLE EventPairHandle +); + +NTSTATUS +STDCALL +NtSetInformationFile( + IN HANDLE FileHandle, + IN PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID FileInformation, + IN ULONG Length, + IN FILE_INFORMATION_CLASS FileInformationClass +); + +NTSTATUS +STDCALL +ZwSetInformationFile( + IN HANDLE FileHandle, + IN PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID FileInformation, + IN ULONG Length, + IN FILE_INFORMATION_CLASS FileInformationClass +); + +NTSTATUS +STDCALL +NtSetInformationJobObject( + HANDLE JobHandle, + JOBOBJECTINFOCLASS JobInformationClass, + PVOID JobInformation, + ULONG JobInformationLength +); + +NTSTATUS +STDCALL +ZwSetInformationJobObject( + HANDLE JobHandle, + JOBOBJECTINFOCLASS JobInformationClass, + PVOID JobInformation, + ULONG JobInformationLength +); + +NTSTATUS +STDCALL +NtSetInformationKey( + IN HANDLE KeyHandle, + IN KEY_SET_INFORMATION_CLASS KeyInformationClass, + IN PVOID KeyInformation, + IN ULONG KeyInformationLength +); + +NTSTATUS +STDCALL +ZwSetInformationKey( + IN HANDLE KeyHandle, + IN KEY_SET_INFORMATION_CLASS KeyInformationClass, + IN PVOID KeyInformation, + IN ULONG KeyInformationLength +); + +NTSTATUS +STDCALL +NtSetInformationObject( + IN HANDLE ObjectHandle, + IN OBJECT_INFORMATION_CLASS ObjectInformationClass, + IN PVOID ObjectInformation, + IN ULONG Length +); + +NTSTATUS +STDCALL +ZwSetInformationObject( + IN HANDLE ObjectHandle, + IN OBJECT_INFORMATION_CLASS ObjectInformationClass, + IN PVOID ObjectInformation, + IN ULONG Length +); + +NTSTATUS +STDCALL +NtSetInformationProcess( + IN HANDLE ProcessHandle, + IN PROCESSINFOCLASS ProcessInformationClass, + IN PVOID ProcessInformation, + IN ULONG ProcessInformationLength +); + +NTSTATUS +STDCALL +NtSetInformationThread( + IN HANDLE ThreadHandle, + IN THREADINFOCLASS ThreadInformationClass, + IN PVOID ThreadInformation, + IN ULONG ThreadInformationLength +); +NTSTATUS +STDCALL +ZwSetInformationThread( + IN HANDLE ThreadHandle, + IN THREADINFOCLASS ThreadInformationClass, + IN PVOID ThreadInformation, + IN ULONG ThreadInformationLength +); + +NTSTATUS +STDCALL +NtSetInformationToken( + IN HANDLE TokenHandle, + IN TOKEN_INFORMATION_CLASS TokenInformationClass, + OUT PVOID TokenInformation, + IN ULONG TokenInformationLength +); + +NTSTATUS +STDCALL +ZwSetInformationToken( + IN HANDLE TokenHandle, + IN TOKEN_INFORMATION_CLASS TokenInformationClass, + OUT PVOID TokenInformation, + IN ULONG TokenInformationLength +); + +NTSTATUS +STDCALL +NtSetIoCompletion( + IN HANDLE IoCompletionPortHandle, + IN PVOID CompletionKey, + IN PVOID CompletionContext, + IN NTSTATUS CompletionStatus, + IN ULONG CompletionInformation +); + +NTSTATUS +STDCALL +ZwSetIoCompletion( + IN HANDLE IoCompletionPortHandle, + IN PVOID CompletionKey, + IN PVOID CompletionContext, + IN NTSTATUS CompletionStatus, + IN ULONG CompletionInformation +); + +NTSTATUS +STDCALL +NtSetIntervalProfile( + ULONG Interval, + KPROFILE_SOURCE ClockSource +); + +NTSTATUS +STDCALL +ZwSetIntervalProfile( + ULONG Interval, + KPROFILE_SOURCE ClockSource +); + +NTSTATUS +STDCALL +NtSetLdtEntries( + ULONG Selector1, + LDT_ENTRY LdtEntry1, + ULONG Selector2, + LDT_ENTRY LdtEntry2 +); + +NTSTATUS +STDCALL +NtSetLowEventPair( + HANDLE EventPair +); + +NTSTATUS +STDCALL +ZwSetLowEventPair( + HANDLE EventPair +); + +NTSTATUS +STDCALL +NtSetLowWaitHighEventPair( + HANDLE EventPair +); + +NTSTATUS +STDCALL +ZwSetLowWaitHighEventPair( + HANDLE EventPair +); + +NTSTATUS +STDCALL +NtSetQuotaInformationFile( + HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PFILE_QUOTA_INFORMATION Buffer, + ULONG BufferLength +); + +NTSTATUS +STDCALL +ZwSetQuotaInformationFile( + HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PFILE_QUOTA_INFORMATION Buffer, + ULONG BufferLength +); + +NTSTATUS +STDCALL +NtSetSecurityObject( + IN HANDLE Handle, + IN SECURITY_INFORMATION SecurityInformation, + IN PSECURITY_DESCRIPTOR SecurityDescriptor +); + +NTSTATUS +STDCALL +ZwSetSecurityObject( + IN HANDLE Handle, + IN SECURITY_INFORMATION SecurityInformation, + IN PSECURITY_DESCRIPTOR SecurityDescriptor +); + +NTSTATUS +STDCALL +NtSetSystemEnvironmentValue( + IN PUNICODE_STRING VariableName, + IN PUNICODE_STRING Value +); +NTSTATUS +STDCALL +ZwSetSystemEnvironmentValue( + IN PUNICODE_STRING VariableName, + IN PUNICODE_STRING Value +); + +NTSTATUS +STDCALL +NtSetSystemInformation( + IN SYSTEM_INFORMATION_CLASS SystemInformationClass, + IN PVOID SystemInformation, + IN ULONG SystemInformationLength +); + +NTSTATUS +STDCALL +ZwSetSystemInformation( + IN SYSTEM_INFORMATION_CLASS SystemInformationClass, + IN PVOID SystemInformation, + IN ULONG SystemInformationLength +); + +NTSTATUS +STDCALL +NtSetSystemPowerState( + IN POWER_ACTION SystemAction, + IN SYSTEM_POWER_STATE MinSystemState, + IN ULONG Flags +); + +NTSTATUS +STDCALL +NtSetSystemTime( + IN PLARGE_INTEGER SystemTime, + IN PLARGE_INTEGER NewSystemTime OPTIONAL +); + +NTSTATUS +STDCALL +ZwSetSystemTime( + IN PLARGE_INTEGER SystemTime, + IN PLARGE_INTEGER NewSystemTime OPTIONAL +); + +NTSTATUS +STDCALL +NtSetTimer( + IN HANDLE TimerHandle, + IN PLARGE_INTEGER DueTime, + IN PTIMER_APC_ROUTINE TimerApcRoutine, + IN PVOID TimerContext, + IN BOOLEAN WakeTimer, + IN LONG Period OPTIONAL, + OUT PBOOLEAN PreviousState OPTIONAL +); + +NTSTATUS +STDCALL +NtSetTimerResolution( + IN ULONG RequestedResolution, + IN BOOLEAN SetOrUnset, + OUT PULONG ActualResolution +); + +NTSTATUS +STDCALL +ZwSetTimerResolution( + IN ULONG RequestedResolution, + IN BOOLEAN SetOrUnset, + OUT PULONG ActualResolution +); + +NTSTATUS +STDCALL +NtSetUuidSeed( + IN PUCHAR UuidSeed +); + +NTSTATUS +STDCALL +ZwSetUuidSeed( + IN PUCHAR UuidSeed +); + +NTSTATUS +STDCALL +NtSetValueKey( + IN HANDLE KeyHandle, + IN PUNICODE_STRING ValueName, + IN ULONG TitleIndex OPTIONAL, + IN ULONG Type, + IN PVOID Data, + IN ULONG DataSize +); + +NTSTATUS +STDCALL +ZwSetValueKey( + IN HANDLE KeyHandle, + IN PUNICODE_STRING ValueName, + IN ULONG TitleIndex OPTIONAL, + IN ULONG Type, + IN PVOID Data, + IN ULONG DataSize +); + +NTSTATUS +STDCALL +NtSetVolumeInformationFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID FsInformation, + IN ULONG Length, + IN FS_INFORMATION_CLASS FsInformationClass +); + +NTSTATUS +STDCALL +ZwSetVolumeInformationFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID FsInformation, + IN ULONG Length, + IN FS_INFORMATION_CLASS FsInformationClass +); + +NTSTATUS +STDCALL +NtShutdownSystem( + IN SHUTDOWN_ACTION Action +); + +NTSTATUS +STDCALL +ZwShutdownSystem( + IN SHUTDOWN_ACTION Action +); + +NTSTATUS +STDCALL +NtSignalAndWaitForSingleObject( + IN HANDLE SignalObject, + IN HANDLE WaitObject, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER Time +); + +NTSTATUS +STDCALL +ZwSignalAndWaitForSingleObject( + IN HANDLE SignalObject, + IN HANDLE WaitObject, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER Time +); + +NTSTATUS +STDCALL +NtStartProfile( + HANDLE ProfileHandle +); + +NTSTATUS +STDCALL +ZwStartProfile( + HANDLE ProfileHandle +); + +NTSTATUS +STDCALL +NtStopProfile( + HANDLE ProfileHandle +); + +NTSTATUS +STDCALL +ZwStopProfile( + HANDLE ProfileHandle +); + +NTSTATUS +STDCALL +NtSuspendProcess( + IN HANDLE ProcessHandle +); + +NTSTATUS +STDCALL +ZwSuspendProcess( + IN HANDLE ProcessHandle +); + +NTSTATUS +STDCALL +NtSuspendThread( + IN HANDLE ThreadHandle, + IN PULONG PreviousSuspendCount +); + +NTSTATUS +STDCALL +ZwSuspendThread( + IN HANDLE ThreadHandle, + IN PULONG PreviousSuspendCount +); + +NTSTATUS +STDCALL +NtSystemDebugControl( + DEBUG_CONTROL_CODE ControlCode, + PVOID InputBuffer, + ULONG InputBufferLength, + PVOID OutputBuffer, + ULONG OutputBufferLength, + PULONG ReturnLength +); + +NTSTATUS +STDCALL +NtTerminateProcess( + IN HANDLE ProcessHandle, + IN NTSTATUS ExitStatus +); + +NTSTATUS +STDCALL +ZwTerminateProcess( + IN HANDLE ProcessHandle, + IN NTSTATUS ExitStatus +); + +NTSTATUS +STDCALL +NtTerminateThread( + IN HANDLE ThreadHandle, + IN NTSTATUS ExitStatus +); + +NTSTATUS +STDCALL +ZwTerminateThread( + IN HANDLE ThreadHandle, + IN NTSTATUS ExitStatus +); + +NTSTATUS +STDCALL +NtTerminateJobObject( + HANDLE JobHandle, + NTSTATUS ExitStatus +); + +NTSTATUS +STDCALL +ZwTerminateJobObject( + HANDLE JobHandle, + NTSTATUS ExitStatus +); + +NTSTATUS +STDCALL +NtTestAlert( + VOID +); + +NTSTATUS +STDCALL +ZwTestAlert( + VOID +); + +NTSTATUS +STDCALL +NtTraceEvent( + IN ULONG TraceHandle, + IN ULONG Flags, + IN ULONG TraceHeaderLength, + IN struct _EVENT_TRACE_HEADER* TraceHeader +); + +NTSTATUS +STDCALL +ZwTraceEvent( + IN ULONG TraceHandle, + IN ULONG Flags, + IN ULONG TraceHeaderLength, + IN struct _EVENT_TRACE_HEADER* TraceHeader +); + +NTSTATUS +STDCALL +NtTranslateFilePath( + ULONG Unknown1, + ULONG Unknown2, + ULONG Unknown3 +); + +NTSTATUS +STDCALL +ZwTranslateFilePath( + ULONG Unknown1, + ULONG Unknown2, + ULONG Unknown3 +); + +NTSTATUS +STDCALL +NtUnloadDriver( + IN PUNICODE_STRING DriverServiceName +); + +NTSTATUS +STDCALL +ZwUnloadDriver( + IN PUNICODE_STRING DriverServiceName +); + +NTSTATUS +STDCALL +NtUnloadKey( + IN POBJECT_ATTRIBUTES KeyObjectAttributes +); + +NTSTATUS +STDCALL +ZwUnloadKey( + IN POBJECT_ATTRIBUTES KeyObjectAttributes +); + +NTSTATUS +STDCALL +NtUnlockFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER ByteOffset, + IN PLARGE_INTEGER Lenght, + OUT PULONG Key OPTIONAL +); + +NTSTATUS +STDCALL +ZwUnlockFile( + IN HANDLE FileHandle, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PLARGE_INTEGER ByteOffset, + IN PLARGE_INTEGER Lenght, + OUT PULONG Key OPTIONAL +); + +NTSTATUS +STDCALL +NtUnlockVirtualMemory( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + IN ULONG NumberOfBytesToUnlock, + OUT PULONG NumberOfBytesUnlocked OPTIONAL +); + +NTSTATUS +STDCALL +ZwUnlockVirtualMemory( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + IN ULONG NumberOfBytesToUnlock, + OUT PULONG NumberOfBytesUnlocked OPTIONAL +); + +NTSTATUS +STDCALL +NtUnmapViewOfSection( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress +); + +NTSTATUS +STDCALL +ZwUnmapViewOfSection( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress +); + +NTSTATUS +STDCALL +NtVdmControl( + ULONG ControlCode, + PVOID ControlData +); + +NTSTATUS +STDCALL +NtW32Call( + IN ULONG RoutineIndex, + IN PVOID Argument, + IN ULONG ArgumentLength, + OUT PVOID* Result OPTIONAL, + OUT PULONG ResultLength OPTIONAL +); + +NTSTATUS +STDCALL +NtWaitForMultipleObjects( + IN ULONG Count, + IN HANDLE Object[], + IN WAIT_TYPE WaitType, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER Time +); + +NTSTATUS +STDCALL +ZwWaitForMultipleObjects( + IN ULONG Count, + IN HANDLE Object[], + IN WAIT_TYPE WaitType, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER Time +); + +NTSTATUS +STDCALL +NtWaitForSingleObject( + IN HANDLE Object, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER Time +); + +NTSTATUS +STDCALL +ZwWaitForSingleObject( + IN HANDLE Object, + IN BOOLEAN Alertable, + IN PLARGE_INTEGER Time +); + +NTSTATUS +STDCALL +NtWaitHighEventPair( + IN HANDLE EventPairHandle +); + +NTSTATUS +STDCALL +ZwWaitHighEventPair( + IN HANDLE EventPairHandle +); + +NTSTATUS +STDCALL +NtWaitLowEventPair( + IN HANDLE EventPairHandle +); + +NTSTATUS +STDCALL +ZwWaitLowEventPair( + IN HANDLE EventPairHandle +); + +NTSTATUS +STDCALL +NtWriteFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID Buffer, + IN ULONG Length, + IN PLARGE_INTEGER ByteOffset, + IN PULONG Key OPTIONAL +); + +NTSTATUS +STDCALL +ZwWriteFile( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN PVOID Buffer, + IN ULONG Length, + IN PLARGE_INTEGER ByteOffset, + IN PULONG Key OPTIONAL +); + +NTSTATUS +STDCALL +NtWriteFileGather( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN FILE_SEGMENT_ELEMENT BufferDescription[], + IN ULONG BufferLength, + IN PLARGE_INTEGER ByteOffset, + IN PULONG Key OPTIONAL +); + +NTSTATUS +STDCALL +ZwWriteFileGather( + IN HANDLE FileHandle, + IN HANDLE Event OPTIONAL, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN FILE_SEGMENT_ELEMENT BufferDescription[], + IN ULONG BufferLength, + IN PLARGE_INTEGER ByteOffset, + IN PULONG Key OPTIONAL +); + +NTSTATUS +STDCALL +NtWriteRequestData( + HANDLE PortHandle, + PLPC_MESSAGE Message, + ULONG Index, + PVOID Buffer, + ULONG BufferLength, + PULONG ReturnLength +); + +NTSTATUS +STDCALL +ZwWriteRequestData( + HANDLE PortHandle, + PLPC_MESSAGE Message, + ULONG Index, + PVOID Buffer, + ULONG BufferLength, + PULONG ReturnLength +); + +NTSTATUS +STDCALL +NtWriteVirtualMemory( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + IN PVOID Buffer, + IN ULONG NumberOfBytesToWrite, + OUT PULONG NumberOfBytesWritten +); + +NTSTATUS +STDCALL +ZwWriteVirtualMemory( + IN HANDLE ProcessHandle, + IN PVOID BaseAddress, + IN PVOID Buffer, + IN ULONG NumberOfBytesToWrite, + OUT PULONG NumberOfBytesWritten +); + +NTSTATUS +STDCALL +NtYieldExecution( + VOID +); + +NTSTATUS +STDCALL +ZwYieldExecution( + VOID +); + + +static __inline struct _PEB* NtCurrentPeb (void) +{ + struct _PEB * pPeb; + +#if defined(__GNUC__) + + __asm__ __volatile__ + ( + "movl %%fs:0x30, %0\n" /* fs:30h == Teb->Peb */ + : "=r" (pPeb) /* can't have two memory operands */ + : /* no inputs */ + ); + +#elif defined(_MSC_VER) + + __asm mov eax, fs:0x30; + __asm mov pPeb, eax + +#else +#error Unknown compiler for inline assembler +#endif + + return pPeb; +} +#endif diff --git a/reactos/include/reactos/helper.h b/reactos/include/reactos/helper.h index 465f96d2e72..93415061792 100644 --- a/reactos/include/reactos/helper.h +++ b/reactos/include/reactos/helper.h @@ -1,118 +1,118 @@ -#ifndef _HELPER_H -#define _HELPER_H - -#define ROUNDUP(a,b) ((((a)+(b)-1)/(b))*(b)) -#define ROUNDDOWN(a,b) (((a)/(b))*(b)) -#define ROUND_UP ROUNDUP -#define ROUND_DOWN ROUNDDOWN -#define PAGE_ROUND_DOWN(x) (((ULONG)x)&(~(PAGE_SIZE-1))) -#define PAGE_ROUND_UP(x) ( (((ULONG)x)%PAGE_SIZE) ? ((((ULONG)x)&(~(PAGE_SIZE-1)))+PAGE_SIZE) : ((ULONG)x) ) -#define ABS_VALUE(V) (((V) < 0) ? -(V) : (V)) -#define RtlRosMin(X,Y) (((X) < (Y))? (X) : (Y)) -#define RtlRosMin3(X,Y,Z) (((X) < (Y)) ? RtlRosMin(X,Z) : RtlRosMin(Y,Z)) -#define KEBUGCHECKEX(a,b,c,d,e) DbgPrint("KeBugCheckEx at %s:%i\n",__FILE__,__LINE__), KeBugCheckEx(a,b,c,d,e) -#define KEBUGCHECK(a) DbgPrint("KeBugCheck at %s:%i\n",__FILE__,__LINE__), KeBugCheck(a) -#define EXPORTED __declspec(dllexport) -#define IMPORTED __declspec(dllimport) -#define LIST_FOR_EACH(entry, head) \ - for(entry = (head)->Flink; entry != (head); entry = entry->Flink) -#define LIST_FOR_EACH_SAFE(tmp_entry, head, ptr, type, field) \ - for ((tmp_entry)=(head)->Flink; (tmp_entry)!=(head) && \ - ((ptr) = CONTAINING_RECORD(tmp_entry,type,field)) && \ - ((tmp_entry) = (tmp_entry)->Flink); ) -#define OPTHDROFFSET(a) ((LPVOID)((BYTE *)a + \ - ((PIMAGE_DOS_HEADER)a)->e_lfanew + \ - sizeof (IMAGE_NT_SIGNATURE) + \ - sizeof (IMAGE_FILE_HEADER))) -#define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24)) -#define RVA(m, b) ((PVOID)((ULONG_PTR)(b) + (ULONG_PTR)(m))) -#define NTSTAT_SEVERITY_SHIFT 30 -#define NTSTAT_SEVERITY_MASK 0x00000003 -#define NTSTAT_FACILITY_SHIFT 16 -#define NTSTAT_FACILITY_MASK 0x00000FFF -#define NTSTAT_CUSTOMER_MASK 0x20000000 -#define NT_SEVERITY(StatCode) (((StatCode) >> NTSTAT_SEVERITY_SHIFT) & NTSTAT_SEVERITY_MASK) -#define NT_FACILITY(StatCode) (((StatCode) >> NTSTAT_FACILITY_SHIFT) & NTSTAT_FACILITY_MASK) -#define NT_CUSTOMER(StatCode) ((StatCode) & NTSTAT_CUSTOMER_MASK) -#define RELATIVE_TIME(wait) (-(wait)) -#define NANOS_TO_100NS(nanos) (((LONGLONG)(nanos)) / 100) -#define MICROS_TO_100NS(micros) (((LONGLONG)(micros)) * NANOS_TO_100NS(1000)) -#define MILLIS_TO_100NS(milli) (((LONGLONG)(milli)) * MICROS_TO_100NS(1000)) -#define SECONDS_TO_100NS(seconds) (((LONGLONG)(seconds)) * MILLIS_TO_100NS(1000)) -#define MINUTES_TO_100NS(minutes) (((LONGLONG)(minutes)) * SECONDS_TO_100NS(60)) -#define HOURS_TO_100NS(hours) (((LONGLONG)(hours)) * MINUTES_TO_100NS(60)) -#define UNICODIZE1(x) L##x -#define UNICODIZE(x) UNICODIZE1(x) -#define InsertAscendingListFIFO(ListHead, Type, ListEntryField, NewEntry, SortField)\ -{\ - PLIST_ENTRY current;\ -\ - current = (ListHead)->Flink;\ - while (current != (ListHead))\ - {\ - if (CONTAINING_RECORD(current, Type, ListEntryField)->SortField >\ - (NewEntry)->SortField)\ - {\ - break;\ - }\ - current = current->Flink;\ - }\ -\ - InsertTailList(current, &((NewEntry)->ListEntryField));\ -} - -#define InsertDescendingListFIFO(ListHead, Type, ListEntryField, NewEntry, SortField)\ -{\ - PLIST_ENTRY current;\ -\ - current = (ListHead)->Flink;\ - while (current != (ListHead))\ - {\ - if (CONTAINING_RECORD(current, Type, ListEntryField)->SortField <\ - (NewEntry)->SortField)\ - {\ - break;\ - }\ - current = current->Flink;\ - }\ -\ - InsertTailList(current, &((NewEntry)->ListEntryField));\ -} - -#define InsertAscendingList(ListHead, Type, ListEntryField, NewEntry, SortField)\ -{\ - PLIST_ENTRY current;\ -\ - current = (ListHead)->Flink;\ - while (current != (ListHead))\ - {\ - if (CONTAINING_RECORD(current, Type, ListEntryField)->SortField >=\ - (NewEntry)->SortField)\ - {\ - break;\ - }\ - current = current->Flink;\ - }\ -\ - InsertTailList(current, &((NewEntry)->ListEntryField));\ -} - -#define InsertDescendingList(ListHead, Type, ListEntryField, NewEntry, SortField)\ -{\ - PLIST_ENTRY current;\ -\ - current = (ListHead)->Flink;\ - while (current != (ListHead))\ - {\ - if (CONTAINING_RECORD(current, Type, ListEntryField)->SortField <=\ - (NewEntry)->SortField)\ - {\ - break;\ - }\ - current = current->Flink;\ - }\ -\ - InsertTailList(current, &((NewEntry)->ListEntryField));\ -} - -#endif +#ifndef _HELPER_H +#define _HELPER_H + +#define ROUNDUP(a,b) ((((a)+(b)-1)/(b))*(b)) +#define ROUNDDOWN(a,b) (((a)/(b))*(b)) +#define ROUND_UP ROUNDUP +#define ROUND_DOWN ROUNDDOWN +#define PAGE_ROUND_DOWN(x) (((ULONG)x)&(~(PAGE_SIZE-1))) +#define PAGE_ROUND_UP(x) ( (((ULONG)x)%PAGE_SIZE) ? ((((ULONG)x)&(~(PAGE_SIZE-1)))+PAGE_SIZE) : ((ULONG)x) ) +#define ABS_VALUE(V) (((V) < 0) ? -(V) : (V)) +#define RtlRosMin(X,Y) (((X) < (Y))? (X) : (Y)) +#define RtlRosMin3(X,Y,Z) (((X) < (Y)) ? RtlRosMin(X,Z) : RtlRosMin(Y,Z)) +#define KEBUGCHECKEX(a,b,c,d,e) DbgPrint("KeBugCheckEx at %s:%i\n",__FILE__,__LINE__), KeBugCheckEx(a,b,c,d,e) +#define KEBUGCHECK(a) DbgPrint("KeBugCheck at %s:%i\n",__FILE__,__LINE__), KeBugCheck(a) +#define EXPORTED __declspec(dllexport) +#define IMPORTED __declspec(dllimport) +#define LIST_FOR_EACH(entry, head) \ + for(entry = (head)->Flink; entry != (head); entry = entry->Flink) +#define LIST_FOR_EACH_SAFE(tmp_entry, head, ptr, type, field) \ + for ((tmp_entry)=(head)->Flink; (tmp_entry)!=(head) && \ + ((ptr) = CONTAINING_RECORD(tmp_entry,type,field)) && \ + ((tmp_entry) = (tmp_entry)->Flink); ) +#define OPTHDROFFSET(a) ((LPVOID)((BYTE *)a + \ + ((PIMAGE_DOS_HEADER)a)->e_lfanew + \ + sizeof (IMAGE_NT_SIGNATURE) + \ + sizeof (IMAGE_FILE_HEADER))) +#define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24)) +#define RVA(m, b) ((PVOID)((ULONG_PTR)(b) + (ULONG_PTR)(m))) +#define NTSTAT_SEVERITY_SHIFT 30 +#define NTSTAT_SEVERITY_MASK 0x00000003 +#define NTSTAT_FACILITY_SHIFT 16 +#define NTSTAT_FACILITY_MASK 0x00000FFF +#define NTSTAT_CUSTOMER_MASK 0x20000000 +#define NT_SEVERITY(StatCode) (((StatCode) >> NTSTAT_SEVERITY_SHIFT) & NTSTAT_SEVERITY_MASK) +#define NT_FACILITY(StatCode) (((StatCode) >> NTSTAT_FACILITY_SHIFT) & NTSTAT_FACILITY_MASK) +#define NT_CUSTOMER(StatCode) ((StatCode) & NTSTAT_CUSTOMER_MASK) +#define RELATIVE_TIME(wait) (-(wait)) +#define NANOS_TO_100NS(nanos) (((LONGLONG)(nanos)) / 100) +#define MICROS_TO_100NS(micros) (((LONGLONG)(micros)) * NANOS_TO_100NS(1000)) +#define MILLIS_TO_100NS(milli) (((LONGLONG)(milli)) * MICROS_TO_100NS(1000)) +#define SECONDS_TO_100NS(seconds) (((LONGLONG)(seconds)) * MILLIS_TO_100NS(1000)) +#define MINUTES_TO_100NS(minutes) (((LONGLONG)(minutes)) * SECONDS_TO_100NS(60)) +#define HOURS_TO_100NS(hours) (((LONGLONG)(hours)) * MINUTES_TO_100NS(60)) +#define UNICODIZE1(x) L##x +#define UNICODIZE(x) UNICODIZE1(x) +#define InsertAscendingListFIFO(ListHead, Type, ListEntryField, NewEntry, SortField)\ +{\ + PLIST_ENTRY current;\ +\ + current = (ListHead)->Flink;\ + while (current != (ListHead))\ + {\ + if (CONTAINING_RECORD(current, Type, ListEntryField)->SortField >\ + (NewEntry)->SortField)\ + {\ + break;\ + }\ + current = current->Flink;\ + }\ +\ + InsertTailList(current, &((NewEntry)->ListEntryField));\ +} + +#define InsertDescendingListFIFO(ListHead, Type, ListEntryField, NewEntry, SortField)\ +{\ + PLIST_ENTRY current;\ +\ + current = (ListHead)->Flink;\ + while (current != (ListHead))\ + {\ + if (CONTAINING_RECORD(current, Type, ListEntryField)->SortField <\ + (NewEntry)->SortField)\ + {\ + break;\ + }\ + current = current->Flink;\ + }\ +\ + InsertTailList(current, &((NewEntry)->ListEntryField));\ +} + +#define InsertAscendingList(ListHead, Type, ListEntryField, NewEntry, SortField)\ +{\ + PLIST_ENTRY current;\ +\ + current = (ListHead)->Flink;\ + while (current != (ListHead))\ + {\ + if (CONTAINING_RECORD(current, Type, ListEntryField)->SortField >=\ + (NewEntry)->SortField)\ + {\ + break;\ + }\ + current = current->Flink;\ + }\ +\ + InsertTailList(current, &((NewEntry)->ListEntryField));\ +} + +#define InsertDescendingList(ListHead, Type, ListEntryField, NewEntry, SortField)\ +{\ + PLIST_ENTRY current;\ +\ + current = (ListHead)->Flink;\ + while (current != (ListHead))\ + {\ + if (CONTAINING_RECORD(current, Type, ListEntryField)->SortField <=\ + (NewEntry)->SortField)\ + {\ + break;\ + }\ + current = current->Flink;\ + }\ +\ + InsertTailList(current, &((NewEntry)->ListEntryField));\ +} + +#endif diff --git a/reactos/include/services/services.h b/reactos/include/services/services.h index 95818c026a3..188c355e31b 100644 --- a/reactos/include/services/services.h +++ b/reactos/include/services/services.h @@ -1,24 +1,24 @@ -/* $Id$ - * - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: include/services/services.h - * PURPOSE: Private interface between SERVICES.EXE and ADVAPI32.DLL - * PROGRAMMER: Eric Kohl - */ - -#ifndef __SERVICES_SERVICES_H__ -#define __SERVICES_SERVICES_H__ - -#define SCM_START_COMMAND 1 - -typedef struct _SCM_START_PACKET -{ - ULONG Command; - ULONG Size; - WCHAR Arguments[1]; -} SCM_START_PACKET, *PSCM_START_PACKET; - -#endif /* __SERVICES_SERVICES_H__ */ - -/* EOF */ +/* $Id$ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: include/services/services.h + * PURPOSE: Private interface between SERVICES.EXE and ADVAPI32.DLL + * PROGRAMMER: Eric Kohl + */ + +#ifndef __SERVICES_SERVICES_H__ +#define __SERVICES_SERVICES_H__ + +#define SCM_START_COMMAND 1 + +typedef struct _SCM_START_PACKET +{ + ULONG Command; + ULONG Size; + WCHAR Arguments[1]; +} SCM_START_PACKET, *PSCM_START_PACKET; + +#endif /* __SERVICES_SERVICES_H__ */ + +/* EOF */ diff --git a/reactos/include/subsys/lsass/lsasrv.h b/reactos/include/subsys/lsass/lsasrv.h index aaf12e14db7..601b27a2858 100644 --- a/reactos/include/subsys/lsass/lsasrv.h +++ b/reactos/include/subsys/lsass/lsasrv.h @@ -1,8 +1,8 @@ - -#ifndef __LSASRV_H -#define __LSASRV_H - -NTSTATUS STDCALL -LsapInitLsa(VOID); - -#endif /* __LSASRV_H */ + +#ifndef __LSASRV_H +#define __LSASRV_H + +NTSTATUS STDCALL +LsapInitLsa(VOID); + +#endif /* __LSASRV_H */ diff --git a/reactos/include/wine/list.h b/reactos/include/wine/list.h index 2e9df7bf1b3..8f4d61de83e 100644 --- a/reactos/include/wine/list.h +++ b/reactos/include/wine/list.h @@ -1,165 +1,165 @@ -/* - * Linked lists support - * - * Copyright (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_SERVER_LIST_H -#define __WINE_SERVER_LIST_H - -struct list -{ - struct list *next; - struct list *prev; -}; - -/* Define a list like so: - * - * struct gadget - * { - * struct list entry; <-- doesn't have to be the first item in the struct - * int a, b; - * }; - * - * static struct list global_gadgets = LIST_INIT( global_gadgets ); - * - * or - * - * struct some_global_thing - * { - * struct list gadgets; - * }; - * - * list_init( &some_global_thing->gadgets ); - * - * Manipulate it like this: - * - * list_add_head( &global_gadgets, &new_gadget->entry ); - * list_remove( &new_gadget->entry ); - * list_add_after( &some_random_gadget->entry, &new_gadget->entry ); - * - * And to iterate over it: - * - * struct list *cursor; - * LIST_FOR_EACH( cursor, &global_gadgets ) - * { - * struct gadget *gadget = LIST_ENTRY( cursor, struct gadget, entry ); - * } - * - */ - -/* add an element after the specified one */ -inline static void list_add_after( struct list *elem, struct list *to_add ) -{ - to_add->next = elem->next; - to_add->prev = elem; - elem->next->prev = to_add; - elem->next = to_add; -} - -/* add an element before the specified one */ -inline static void list_add_before( struct list *elem, struct list *to_add ) -{ - to_add->next = elem; - to_add->prev = elem->prev; - elem->prev->next = to_add; - elem->prev = to_add; -} - -/* add element at the head of the list */ -inline static void list_add_head( struct list *list, struct list *elem ) -{ - list_add_after( list, elem ); -} - -/* add element at the tail of the list */ -inline static void list_add_tail( struct list *list, struct list *elem ) -{ - list_add_before( list, elem ); -} - -/* remove an element from its list */ -inline static void list_remove( struct list *elem ) -{ - elem->next->prev = elem->prev; - elem->prev->next = elem->next; -} - -/* get the next element */ -inline static struct list *list_next( struct list *list, struct list *elem ) -{ - struct list *ret = elem->next; - if (elem->next == list) ret = NULL; - return ret; -} - -/* get the previous element */ -inline static struct list *list_prev( struct list *list, struct list *elem ) -{ - struct list *ret = elem->prev; - if (elem->prev == list) ret = NULL; - return ret; -} - -/* get the first element */ -inline static struct list *list_head( struct list *list ) -{ - return list_next( list, list ); -} - -/* get the last element */ -inline static struct list *list_tail( struct list *list ) -{ - return list_prev( list, list ); -} - -/* check if a list is empty */ -inline static int list_empty( struct list *list ) -{ - return list->next == list; -} - -/* initialize a list */ -inline static void list_init( struct list *list ) -{ - list->next = list->prev = list; -} - -/* iterate through the list */ -#define LIST_FOR_EACH(cursor,list) \ - for ((cursor) = (list)->next; (cursor) != (list); (cursor) = (cursor)->next) - -/* iterate through the list, with safety against removal */ -#define LIST_FOR_EACH_SAFE(cursor, cursor2, list) \ - for ((cursor) = (list)->next, (cursor2) = (cursor)->next; \ - (cursor) != (list); \ - (cursor) = (cursor2), (cursor2) = (cursor)->next) - -/* iterate through the list using a list entry */ -#define LIST_FOR_EACH_ENTRY(elem, list, type, field) \ - for ((elem) = LIST_ENTRY((list)->next, type, field); \ - &(elem)->field != (list); \ - (elem) = LIST_ENTRY((elem)->field.next, type, field)) - -/* macros for statically initialized lists */ -#define LIST_INIT(list) { &(list), &(list) } - -/* get pointer to object containing list element */ -#define LIST_ENTRY(elem, type, field) \ - ((type *)((char *)(elem) - (unsigned int)(&((type *)0)->field))) - -#endif /* __WINE_SERVER_LIST_H */ +/* + * Linked lists support + * + * Copyright (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_SERVER_LIST_H +#define __WINE_SERVER_LIST_H + +struct list +{ + struct list *next; + struct list *prev; +}; + +/* Define a list like so: + * + * struct gadget + * { + * struct list entry; <-- doesn't have to be the first item in the struct + * int a, b; + * }; + * + * static struct list global_gadgets = LIST_INIT( global_gadgets ); + * + * or + * + * struct some_global_thing + * { + * struct list gadgets; + * }; + * + * list_init( &some_global_thing->gadgets ); + * + * Manipulate it like this: + * + * list_add_head( &global_gadgets, &new_gadget->entry ); + * list_remove( &new_gadget->entry ); + * list_add_after( &some_random_gadget->entry, &new_gadget->entry ); + * + * And to iterate over it: + * + * struct list *cursor; + * LIST_FOR_EACH( cursor, &global_gadgets ) + * { + * struct gadget *gadget = LIST_ENTRY( cursor, struct gadget, entry ); + * } + * + */ + +/* add an element after the specified one */ +inline static void list_add_after( struct list *elem, struct list *to_add ) +{ + to_add->next = elem->next; + to_add->prev = elem; + elem->next->prev = to_add; + elem->next = to_add; +} + +/* add an element before the specified one */ +inline static void list_add_before( struct list *elem, struct list *to_add ) +{ + to_add->next = elem; + to_add->prev = elem->prev; + elem->prev->next = to_add; + elem->prev = to_add; +} + +/* add element at the head of the list */ +inline static void list_add_head( struct list *list, struct list *elem ) +{ + list_add_after( list, elem ); +} + +/* add element at the tail of the list */ +inline static void list_add_tail( struct list *list, struct list *elem ) +{ + list_add_before( list, elem ); +} + +/* remove an element from its list */ +inline static void list_remove( struct list *elem ) +{ + elem->next->prev = elem->prev; + elem->prev->next = elem->next; +} + +/* get the next element */ +inline static struct list *list_next( struct list *list, struct list *elem ) +{ + struct list *ret = elem->next; + if (elem->next == list) ret = NULL; + return ret; +} + +/* get the previous element */ +inline static struct list *list_prev( struct list *list, struct list *elem ) +{ + struct list *ret = elem->prev; + if (elem->prev == list) ret = NULL; + return ret; +} + +/* get the first element */ +inline static struct list *list_head( struct list *list ) +{ + return list_next( list, list ); +} + +/* get the last element */ +inline static struct list *list_tail( struct list *list ) +{ + return list_prev( list, list ); +} + +/* check if a list is empty */ +inline static int list_empty( struct list *list ) +{ + return list->next == list; +} + +/* initialize a list */ +inline static void list_init( struct list *list ) +{ + list->next = list->prev = list; +} + +/* iterate through the list */ +#define LIST_FOR_EACH(cursor,list) \ + for ((cursor) = (list)->next; (cursor) != (list); (cursor) = (cursor)->next) + +/* iterate through the list, with safety against removal */ +#define LIST_FOR_EACH_SAFE(cursor, cursor2, list) \ + for ((cursor) = (list)->next, (cursor2) = (cursor)->next; \ + (cursor) != (list); \ + (cursor) = (cursor2), (cursor2) = (cursor)->next) + +/* iterate through the list using a list entry */ +#define LIST_FOR_EACH_ENTRY(elem, list, type, field) \ + for ((elem) = LIST_ENTRY((list)->next, type, field); \ + &(elem)->field != (list); \ + (elem) = LIST_ENTRY((elem)->field.next, type, field)) + +/* macros for statically initialized lists */ +#define LIST_INIT(list) { &(list), &(list) } + +/* get pointer to object containing list element */ +#define LIST_ENTRY(elem, type, field) \ + ((type *)((char *)(elem) - (unsigned int)(&((type *)0)->field))) + +#endif /* __WINE_SERVER_LIST_H */ diff --git a/reactos/lib/cabinet/cabextract.c b/reactos/lib/cabinet/cabextract.c index e70adfc06b7..970217b2b67 100644 --- a/reactos/lib/cabinet/cabextract.c +++ b/reactos/lib/cabinet/cabextract.c @@ -1,2654 +1,2654 @@ -/* - * cabextract.c - * - * Copyright 2000-2002 Stuart Caie - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Principal author: Stuart Caie - * - * Based on specification documents from Microsoft Corporation - * Quantum decompression researched and implemented by Matthew Russoto - * Huffman code adapted from unlzx by Dave Tritscher. - * InfoZip team's INFLATE implementation adapted to MSZIP by Dirk Stoecker. - * Major LZX fixes by Jae Jung. - */ - -#include "config.h" - -#include -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" - -#include "cabinet.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(cabinet); - -THOSE_ZIP_CONSTS; - -/* all the file IO is abstracted into these routines: - * cabinet_(open|close|read|seek|skip|getoffset) - * file_(open|close|write) - */ - -/* try to open a cabinet file, returns success */ -BOOL cabinet_open(struct cabinet *cab) -{ - const char *name = cab->filename; - HANDLE fh; - - TRACE("(cab == ^%p)\n", cab); - - if ((fh = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL )) == INVALID_HANDLE_VALUE) { - ERR("Couldn't open %s\n", debugstr_a(name)); - return FALSE; - } - - /* seek to end of file and get the length */ - if ((cab->filelen = SetFilePointer(fh, 0, NULL, FILE_END)) == INVALID_SET_FILE_POINTER) { - if (GetLastError() != NO_ERROR) { - ERR("Seek END failed: %s\n", debugstr_a(name)); - CloseHandle(fh); - return FALSE; - } - } - - /* return to the start of the file */ - if (SetFilePointer(fh, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { - ERR("Seek BEGIN failed: %s\n", debugstr_a(name)); - CloseHandle(fh); - return FALSE; - } - - cab->fh = fh; - return TRUE; -} - -/******************************************************************* - * cabinet_close (internal) - * - * close the file handle in a struct cabinet. - */ -void cabinet_close(struct cabinet *cab) { - TRACE("(cab == ^%p)\n", cab); - if (cab->fh) CloseHandle(cab->fh); - cab->fh = 0; -} - -/******************************************************* - * ensure_filepath2 (internal) - */ -BOOL ensure_filepath2(char *path) { - BOOL ret = TRUE; - int len; - char *new_path; - - new_path = HeapAlloc(GetProcessHeap(), 0, (strlen(path) + 1)); - strcpy(new_path, path); - - while((len = strlen(new_path)) && new_path[len - 1] == '\\') - new_path[len - 1] = 0; - - TRACE("About to try to create directory %s\n", debugstr_a(new_path)); - while(!CreateDirectoryA(new_path, NULL)) { - char *slash; - DWORD last_error = GetLastError(); - - if(last_error == ERROR_ALREADY_EXISTS) - break; - - if(last_error != ERROR_PATH_NOT_FOUND) { - ret = FALSE; - break; - } - - if(!(slash = strrchr(new_path, '\\'))) { - ret = FALSE; - break; - } - - len = slash - new_path; - new_path[len] = 0; - if(! ensure_filepath2(new_path)) { - ret = FALSE; - break; - } - new_path[len] = '\\'; - TRACE("New path in next iteration: %s\n", debugstr_a(new_path)); - } - - HeapFree(GetProcessHeap(), 0, new_path); - return ret; -} - - -/********************************************************************** - * ensure_filepath (internal) - * - * ensure_filepath("a\b\c\d.txt") ensures a, a\b and a\b\c exist as dirs - */ -BOOL ensure_filepath(char *path) { - char new_path[MAX_PATH]; - int len, i, lastslashpos = -1; - - TRACE("(path == %s)\n", debugstr_a(path)); - - strcpy(new_path, path); - /* remove trailing slashes (shouldn't need to but wth...) */ - while ((len = strlen(new_path)) && new_path[len - 1] == '\\') - new_path[len - 1] = 0; - /* find the position of the last '\\' */ - for (i=0; i 0) { - new_path[lastslashpos] = 0; - /* may be trailing slashes but ensure_filepath2 will chop them */ - return ensure_filepath2(new_path); - } else - return TRUE; /* ? */ -} - -/******************************************************************* - * file_open (internal) - * - * opens a file for output, returns success - */ -BOOL file_open(struct cab_file *fi, BOOL lower, LPCSTR dir) -{ - char c, *d, *name; - BOOL ok = FALSE; - const char *s; - - TRACE("(fi == ^%p, lower == %s, dir == %s)\n", fi, lower ? "TRUE" : "FALSE", debugstr_a(dir)); - - if (!(name = malloc(strlen(fi->filename) + (dir ? strlen(dir) : 0) + 2))) { - ERR("out of memory!\n"); - return FALSE; - } - - /* start with blank name */ - *name = 0; - - /* add output directory if needed */ - if (dir) { - strcpy(name, dir); - strcat(name, "\\"); - } - - /* remove leading slashes */ - s = (char *) fi->filename; - while (*s == '\\') s++; - - /* copy from fi->filename to new name. - * lowercases characters if needed. - */ - d = &name[strlen(name)]; - do { - c = *s++; - *d++ = (lower ? tolower((unsigned char) c) : c); - } while (c); - - /* create directories if needed, attempt to write file */ - if (ensure_filepath(name)) { - fi->fh = CreateFileA(name, GENERIC_WRITE, 0, NULL, - CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - if (fi->fh != INVALID_HANDLE_VALUE) - ok = TRUE; - else { - ERR("CreateFileA returned INVALID_HANDLE_VALUE\n"); - fi->fh = 0; - } - } else - ERR("Couldn't ensure filepath for %s\n", debugstr_a(name)); - - if (!ok) { - ERR("Couldn't open file %s for writing\n", debugstr_a(name)); - } - - /* as full filename is no longer needed, free it */ - free(name); - - return ok; -} - -/******************************************************** - * close_file (internal) - * - * closes a completed file - */ -void file_close(struct cab_file *fi) -{ - TRACE("(fi == ^%p)\n", fi); - - if (fi->fh) { - CloseHandle(fi->fh); - } - fi->fh = 0; -} - -/****************************************************************** - * file_write (internal) - * - * writes from buf to a file specified as a cab_file struct. - * returns success/failure - */ -BOOL file_write(struct cab_file *fi, cab_UBYTE *buf, cab_off_t length) -{ - DWORD bytes_written; - - TRACE("(fi == ^%p, buf == ^%p, length == %u)\n", fi, buf, length); - - if ((!WriteFile( fi->fh, (LPCVOID) buf, length, &bytes_written, FALSE) || - (bytes_written != length))) { - ERR("Error writing file: %s\n", debugstr_a(fi->filename)); - return FALSE; - } - return TRUE; -} - - -/******************************************************************* - * cabinet_skip (internal) - * - * advance the file pointer associated with the cab structure - * by distance bytes - */ -void cabinet_skip(struct cabinet *cab, cab_off_t distance) -{ - TRACE("(cab == ^%p, distance == %u)\n", cab, distance); - if (SetFilePointer(cab->fh, distance, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER) { - if (distance != INVALID_SET_FILE_POINTER) - ERR("%s\n", debugstr_a(cab->filename)); - } -} - -/******************************************************************* - * cabinet_seek (internal) - * - * seek to the specified absolute offset in a cab - */ -void cabinet_seek(struct cabinet *cab, cab_off_t offset) { - TRACE("(cab == ^%p, offset == %u)\n", cab, offset); - if (SetFilePointer(cab->fh, offset, NULL, FILE_BEGIN) != offset) - ERR("%s seek failure\n", debugstr_a(cab->filename)); -} - -/******************************************************************* - * cabinet_getoffset (internal) - * - * returns the file pointer position of a cab - */ -cab_off_t cabinet_getoffset(struct cabinet *cab) -{ - return SetFilePointer(cab->fh, 0, NULL, FILE_CURRENT); -} - -/******************************************************************* - * cabinet_read (internal) - * - * read data from a cabinet, returns success - */ -BOOL cabinet_read(struct cabinet *cab, cab_UBYTE *buf, cab_off_t length) -{ - DWORD bytes_read; - cab_off_t avail = cab->filelen - cabinet_getoffset(cab); - - TRACE("(cab == ^%p, buf == ^%p, length == %u)\n", cab, buf, length); - - if (length > avail) { - WARN("%s: WARNING; cabinet is truncated\n", debugstr_a(cab->filename)); - length = avail; - } - - if (! ReadFile( cab->fh, (LPVOID) buf, length, &bytes_read, NULL )) { - ERR("%s read error\n", debugstr_a(cab->filename)); - return FALSE; - } else if (bytes_read != length) { - ERR("%s read size mismatch\n", debugstr_a(cab->filename)); - return FALSE; - } - - return TRUE; -} - -/********************************************************************** - * cabinet_read_string (internal) - * - * allocate and read an aribitrarily long string from the cabinet - */ -char *cabinet_read_string(struct cabinet *cab) -{ - cab_off_t len=256, base = cabinet_getoffset(cab), maxlen = cab->filelen - base; - BOOL ok = FALSE; - unsigned int i; - cab_UBYTE *buf = NULL; - - TRACE("(cab == ^%p)\n", cab); - - do { - if (len > maxlen) len = maxlen; - if (!(buf = realloc(buf, (size_t) len))) break; - if (!cabinet_read(cab, buf, (size_t) len)) break; - - /* search for a null terminator in what we've just read */ - for (i=0; i < len; i++) { - if (!buf[i]) {ok=TRUE; break;} - } - - if (!ok) { - if (len == maxlen) { - ERR("%s: WARNING; cabinet is truncated\n", debugstr_a(cab->filename)); - break; - } - len += 256; - cabinet_seek(cab, base); - } - } while (!ok); - - if (!ok) { - if (buf) - free(buf); - else - ERR("out of memory!\n"); - return NULL; - } - - /* otherwise, set the stream to just after the string and return */ - cabinet_seek(cab, base + ((cab_off_t) strlen((char *) buf)) + 1); - - return (char *) buf; -} - -/****************************************************************** - * cabinet_read_entries (internal) - * - * reads the header and all folder and file entries in this cabinet - */ -BOOL cabinet_read_entries(struct cabinet *cab) -{ - int num_folders, num_files, header_resv, folder_resv = 0, i; - struct cab_folder *fol, *linkfol = NULL; - struct cab_file *file, *linkfile = NULL; - cab_off_t base_offset; - cab_UBYTE buf[64]; - - TRACE("(cab == ^%p)\n", cab); - - /* read in the CFHEADER */ - base_offset = cabinet_getoffset(cab); - if (!cabinet_read(cab, buf, cfhead_SIZEOF)) { - return FALSE; - } - - /* check basic MSCF signature */ - if (EndGetI32(buf+cfhead_Signature) != 0x4643534d) { - ERR("%s: not a Microsoft cabinet file\n", debugstr_a(cab->filename)); - return FALSE; - } - - /* get the number of folders */ - num_folders = EndGetI16(buf+cfhead_NumFolders); - if (num_folders == 0) { - ERR("%s: no folders in cabinet\n", debugstr_a(cab->filename)); - return FALSE; - } - - /* get the number of files */ - num_files = EndGetI16(buf+cfhead_NumFiles); - if (num_files == 0) { - ERR("%s: no files in cabinet\n", debugstr_a(cab->filename)); - return FALSE; - } - - /* just check the header revision */ - if ((buf[cfhead_MajorVersion] > 1) || - (buf[cfhead_MajorVersion] == 1 && buf[cfhead_MinorVersion] > 3)) - { - WARN("%s: WARNING; cabinet format version > 1.3\n", debugstr_a(cab->filename)); - } - - /* read the reserved-sizes part of header, if present */ - cab->flags = EndGetI16(buf+cfhead_Flags); - if (cab->flags & cfheadRESERVE_PRESENT) { - if (!cabinet_read(cab, buf, cfheadext_SIZEOF)) return FALSE; - header_resv = EndGetI16(buf+cfheadext_HeaderReserved); - folder_resv = buf[cfheadext_FolderReserved]; - cab->block_resv = buf[cfheadext_DataReserved]; - - if (header_resv > 60000) { - WARN("%s: WARNING; header reserved space > 60000\n", debugstr_a(cab->filename)); - } - - /* skip the reserved header */ - if (header_resv) - if (SetFilePointer(cab->fh, (cab_off_t) header_resv, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER) - ERR("seek failure: %s\n", debugstr_a(cab->filename)); - } - - if (cab->flags & cfheadPREV_CABINET) { - cab->prevname = cabinet_read_string(cab); - if (!cab->prevname) return FALSE; - cab->previnfo = cabinet_read_string(cab); - } - - if (cab->flags & cfheadNEXT_CABINET) { - cab->nextname = cabinet_read_string(cab); - if (!cab->nextname) return FALSE; - cab->nextinfo = cabinet_read_string(cab); - } - - /* read folders */ - for (i = 0; i < num_folders; i++) { - if (!cabinet_read(cab, buf, cffold_SIZEOF)) return FALSE; - if (folder_resv) cabinet_skip(cab, folder_resv); - - fol = (struct cab_folder *) calloc(1, sizeof(struct cab_folder)); - if (!fol) { - ERR("out of memory!\n"); - return FALSE; - } - - fol->cab[0] = cab; - fol->offset[0] = base_offset + (cab_off_t) EndGetI32(buf+cffold_DataOffset); - fol->num_blocks = EndGetI16(buf+cffold_NumBlocks); - fol->comp_type = EndGetI16(buf+cffold_CompType); - - if (!linkfol) - cab->folders = fol; - else - linkfol->next = fol; - - linkfol = fol; - } - - /* read files */ - for (i = 0; i < num_files; i++) { - if (!cabinet_read(cab, buf, cffile_SIZEOF)) - return FALSE; - - file = (struct cab_file *) calloc(1, sizeof(struct cab_file)); - if (!file) { - ERR("out of memory!\n"); - return FALSE; - } - - file->length = EndGetI32(buf+cffile_UncompressedSize); - file->offset = EndGetI32(buf+cffile_FolderOffset); - file->index = EndGetI16(buf+cffile_FolderIndex); - file->time = EndGetI16(buf+cffile_Time); - file->date = EndGetI16(buf+cffile_Date); - file->attribs = EndGetI16(buf+cffile_Attribs); - file->filename = cabinet_read_string(cab); - - if (!file->filename) { - free(file); - return FALSE; - } - - if (!linkfile) - cab->files = file; - else - linkfile->next = file; - - linkfile = file; - } - return TRUE; -} - -/*********************************************************** - * load_cab_offset (internal) - * - * validates and reads file entries from a cabinet at offset [offset] in - * file [name]. Returns a cabinet structure if successful, or NULL - * otherwise. - */ -struct cabinet *load_cab_offset(LPCSTR name, cab_off_t offset) -{ - struct cabinet *cab = (struct cabinet *) calloc(1, sizeof(struct cabinet)); - int ok; - - TRACE("(name == %s, offset == %u)\n", debugstr_a(name), offset); - - if (!cab) return NULL; - - cab->filename = name; - if ((ok = cabinet_open(cab))) { - cabinet_seek(cab, offset); - ok = cabinet_read_entries(cab); - cabinet_close(cab); - } - - if (ok) return cab; - free(cab); - return NULL; -} - -/* MSZIP decruncher */ - -/* Dirk Stoecker wrote the ZIP decoder, based on the InfoZip deflate code */ - -/******************************************************** - * Ziphuft_free (internal) - */ -void Ziphuft_free(struct Ziphuft *t) -{ - register struct Ziphuft *p, *q; - - /* Go through linked list, freeing from the allocated (t[-1]) address. */ - p = t; - while (p != (struct Ziphuft *)NULL) - { - q = (--p)->v.t; - free(p); - p = q; - } -} - -/********************************************************* - * Ziphuft_build (internal) - */ -cab_LONG Ziphuft_build(cab_ULONG *b, cab_ULONG n, cab_ULONG s, cab_UWORD *d, cab_UWORD *e, -struct Ziphuft **t, cab_LONG *m, cab_decomp_state *decomp_state) -{ - cab_ULONG a; /* counter for codes of length k */ - cab_ULONG el; /* length of EOB code (value 256) */ - cab_ULONG f; /* i repeats in table every f entries */ - cab_LONG g; /* maximum code length */ - cab_LONG h; /* table level */ - register cab_ULONG i; /* counter, current code */ - register cab_ULONG j; /* counter */ - register cab_LONG k; /* number of bits in current code */ - cab_LONG *l; /* stack of bits per table */ - register cab_ULONG *p; /* pointer into ZIP(c)[],ZIP(b)[],ZIP(v)[] */ - register struct Ziphuft *q; /* points to current table */ - struct Ziphuft r; /* table entry for structure assignment */ - register cab_LONG w; /* bits before this table == (l * h) */ - cab_ULONG *xp; /* pointer into x */ - cab_LONG y; /* number of dummy codes added */ - cab_ULONG z; /* number of entries in current table */ - - l = ZIP(lx)+1; - - /* Generate counts for each bit length */ - el = n > 256 ? b[256] : ZIPBMAX; /* set length of EOB code, if any */ - - for(i = 0; i < ZIPBMAX+1; ++i) - ZIP(c)[i] = 0; - p = b; i = n; - do - { - ZIP(c)[*p]++; p++; /* assume all entries <= ZIPBMAX */ - } while (--i); - if (ZIP(c)[0] == n) /* null input--all zero length codes */ - { - *t = (struct Ziphuft *)NULL; - *m = 0; - return 0; - } - - /* Find minimum and maximum length, bound *m by those */ - for (j = 1; j <= ZIPBMAX; j++) - if (ZIP(c)[j]) - break; - k = j; /* minimum code length */ - if ((cab_ULONG)*m < j) - *m = j; - for (i = ZIPBMAX; i; i--) - if (ZIP(c)[i]) - break; - g = i; /* maximum code length */ - if ((cab_ULONG)*m > i) - *m = i; - - /* Adjust last length count to fill out codes, if needed */ - for (y = 1 << j; j < i; j++, y <<= 1) - if ((y -= ZIP(c)[j]) < 0) - return 2; /* bad input: more codes than bits */ - if ((y -= ZIP(c)[i]) < 0) - return 2; - ZIP(c)[i] += y; - - /* Generate starting offsets LONGo the value table for each length */ - ZIP(x)[1] = j = 0; - p = ZIP(c) + 1; xp = ZIP(x) + 2; - while (--i) - { /* note that i == g from above */ - *xp++ = (j += *p++); - } - - /* Make a table of values in order of bit lengths */ - p = b; i = 0; - do{ - if ((j = *p++) != 0) - ZIP(v)[ZIP(x)[j]++] = i; - } while (++i < n); - - - /* Generate the Huffman codes and for each, make the table entries */ - ZIP(x)[0] = i = 0; /* first Huffman code is zero */ - p = ZIP(v); /* grab values in bit order */ - h = -1; /* no tables yet--level -1 */ - w = l[-1] = 0; /* no bits decoded yet */ - ZIP(u)[0] = (struct Ziphuft *)NULL; /* just to keep compilers happy */ - q = (struct Ziphuft *)NULL; /* ditto */ - z = 0; /* ditto */ - - /* go through the bit lengths (k already is bits in shortest code) */ - for (; k <= g; k++) - { - a = ZIP(c)[k]; - while (a--) - { - /* here i is the Huffman code of length k bits for value *p */ - /* make tables up to required level */ - while (k > w + l[h]) - { - w += l[h++]; /* add bits already decoded */ - - /* compute minimum size table less than or equal to *m bits */ - z = (z = g - w) > (cab_ULONG)*m ? *m : z; /* upper limit */ - if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ - { /* too few codes for k-w bit table */ - f -= a + 1; /* deduct codes from patterns left */ - xp = ZIP(c) + k; - while (++j < z) /* try smaller tables up to z bits */ - { - if ((f <<= 1) <= *++xp) - break; /* enough codes to use up j bits */ - f -= *xp; /* else deduct codes from patterns */ - } - } - if ((cab_ULONG)w + j > el && (cab_ULONG)w < el) - j = el - w; /* make EOB code end at table */ - z = 1 << j; /* table entries for j-bit table */ - l[h] = j; /* set table size in stack */ - - /* allocate and link in new table */ - if (!(q = (struct Ziphuft *) malloc((z + 1)*sizeof(struct Ziphuft)))) - { - if(h) - Ziphuft_free(ZIP(u)[0]); - return 3; /* not enough memory */ - } - *t = q + 1; /* link to list for Ziphuft_free() */ - *(t = &(q->v.t)) = (struct Ziphuft *)NULL; - ZIP(u)[h] = ++q; /* table starts after link */ - - /* connect to last table, if there is one */ - if (h) - { - ZIP(x)[h] = i; /* save pattern for backing up */ - r.b = (cab_UBYTE)l[h-1]; /* bits to dump before this table */ - r.e = (cab_UBYTE)(16 + j); /* bits in this table */ - r.v.t = q; /* pointer to this table */ - j = (i & ((1 << w) - 1)) >> (w - l[h-1]); - ZIP(u)[h-1][j] = r; /* connect to last table */ - } - } - - /* set up table entry in r */ - r.b = (cab_UBYTE)(k - w); - if (p >= ZIP(v) + n) - r.e = 99; /* out of values--invalid code */ - else if (*p < s) - { - r.e = (cab_UBYTE)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */ - r.v.n = *p++; /* simple code is just the value */ - } - else - { - r.e = (cab_UBYTE)e[*p - s]; /* non-simple--look up in lists */ - r.v.n = d[*p++ - s]; - } - - /* fill code-like entries with r */ - f = 1 << (k - w); - for (j = i >> w; j < z; j += f) - q[j] = r; - - /* backwards increment the k-bit code i */ - for (j = 1 << (k - 1); i & j; j >>= 1) - i ^= j; - i ^= j; - - /* backup over finished tables */ - while ((i & ((1 << w) - 1)) != ZIP(x)[h]) - w -= l[--h]; /* don't need to update q */ - } - } - - /* return actual size of base table */ - *m = l[0]; - - /* Return true (1) if we were given an incomplete table */ - return y != 0 && g != 1; -} - -/********************************************************* - * Zipinflate_codes (internal) - */ -cab_LONG Zipinflate_codes(struct Ziphuft *tl, struct Ziphuft *td, - cab_LONG bl, cab_LONG bd, cab_decomp_state *decomp_state) -{ - register cab_ULONG e; /* table entry flag/number of extra bits */ - cab_ULONG n, d; /* length and index for copy */ - cab_ULONG w; /* current window position */ - struct Ziphuft *t; /* pointer to table entry */ - cab_ULONG ml, md; /* masks for bl and bd bits */ - register cab_ULONG b; /* bit buffer */ - register cab_ULONG k; /* number of bits in bit buffer */ - - /* make local copies of globals */ - b = ZIP(bb); /* initialize bit buffer */ - k = ZIP(bk); - w = ZIP(window_posn); /* initialize window position */ - - /* inflate the coded data */ - ml = Zipmask[bl]; /* precompute masks for speed */ - md = Zipmask[bd]; - - for(;;) - { - ZIPNEEDBITS((cab_ULONG)bl) - if((e = (t = tl + ((cab_ULONG)b & ml))->e) > 16) - do - { - if (e == 99) - return 1; - ZIPDUMPBITS(t->b) - e -= 16; - ZIPNEEDBITS(e) - } while ((e = (t = t->v.t + ((cab_ULONG)b & Zipmask[e]))->e) > 16); - ZIPDUMPBITS(t->b) - if (e == 16) /* then it's a literal */ - CAB(outbuf)[w++] = (cab_UBYTE)t->v.n; - else /* it's an EOB or a length */ - { - /* exit if end of block */ - if(e == 15) - break; - - /* get length of block to copy */ - ZIPNEEDBITS(e) - n = t->v.n + ((cab_ULONG)b & Zipmask[e]); - ZIPDUMPBITS(e); - - /* decode distance of block to copy */ - ZIPNEEDBITS((cab_ULONG)bd) - if ((e = (t = td + ((cab_ULONG)b & md))->e) > 16) - do { - if (e == 99) - return 1; - ZIPDUMPBITS(t->b) - e -= 16; - ZIPNEEDBITS(e) - } while ((e = (t = t->v.t + ((cab_ULONG)b & Zipmask[e]))->e) > 16); - ZIPDUMPBITS(t->b) - ZIPNEEDBITS(e) - d = w - t->v.n - ((cab_ULONG)b & Zipmask[e]); - ZIPDUMPBITS(e) - do - { - n -= (e = (e = ZIPWSIZE - ((d &= ZIPWSIZE-1) > w ? d : w)) > n ?n:e); - do - { - CAB(outbuf)[w++] = CAB(outbuf)[d++]; - } while (--e); - } while (n); - } - } - - /* restore the globals from the locals */ - ZIP(window_posn) = w; /* restore global window pointer */ - ZIP(bb) = b; /* restore global bit buffer */ - ZIP(bk) = k; - - /* done */ - return 0; -} - -/*********************************************************** - * Zipinflate_stored (internal) - */ -cab_LONG Zipinflate_stored(cab_decomp_state *decomp_state) -/* "decompress" an inflated type 0 (stored) block. */ -{ - cab_ULONG n; /* number of bytes in block */ - cab_ULONG w; /* current window position */ - register cab_ULONG b; /* bit buffer */ - register cab_ULONG k; /* number of bits in bit buffer */ - - /* make local copies of globals */ - b = ZIP(bb); /* initialize bit buffer */ - k = ZIP(bk); - w = ZIP(window_posn); /* initialize window position */ - - /* go to byte boundary */ - n = k & 7; - ZIPDUMPBITS(n); - - /* get the length and its complement */ - ZIPNEEDBITS(16) - n = ((cab_ULONG)b & 0xffff); - ZIPDUMPBITS(16) - ZIPNEEDBITS(16) - if (n != (cab_ULONG)((~b) & 0xffff)) - return 1; /* error in compressed data */ - ZIPDUMPBITS(16) - - /* read and output the compressed data */ - while(n--) - { - ZIPNEEDBITS(8) - CAB(outbuf)[w++] = (cab_UBYTE)b; - ZIPDUMPBITS(8) - } - - /* restore the globals from the locals */ - ZIP(window_posn) = w; /* restore global window pointer */ - ZIP(bb) = b; /* restore global bit buffer */ - ZIP(bk) = k; - return 0; -} - -/****************************************************** - * Zipinflate_fixed (internal) - */ -cab_LONG Zipinflate_fixed(cab_decomp_state *decomp_state) -{ - struct Ziphuft *fixed_tl; - struct Ziphuft *fixed_td; - cab_LONG fixed_bl, fixed_bd; - cab_LONG i; /* temporary variable */ - cab_ULONG *l; - - l = ZIP(ll); - - /* literal table */ - for(i = 0; i < 144; i++) - l[i] = 8; - for(; i < 256; i++) - l[i] = 9; - for(; i < 280; i++) - l[i] = 7; - for(; i < 288; i++) /* make a complete, but wrong code set */ - l[i] = 8; - fixed_bl = 7; - if((i = Ziphuft_build(l, 288, 257, (cab_UWORD *) Zipcplens, - (cab_UWORD *) Zipcplext, &fixed_tl, &fixed_bl, decomp_state))) - return i; - - /* distance table */ - for(i = 0; i < 30; i++) /* make an incomplete code set */ - l[i] = 5; - fixed_bd = 5; - if((i = Ziphuft_build(l, 30, 0, (cab_UWORD *) Zipcpdist, (cab_UWORD *) Zipcpdext, - &fixed_td, &fixed_bd, decomp_state)) > 1) - { - Ziphuft_free(fixed_tl); - return i; - } - - /* decompress until an end-of-block code */ - i = Zipinflate_codes(fixed_tl, fixed_td, fixed_bl, fixed_bd, decomp_state); - - Ziphuft_free(fixed_td); - Ziphuft_free(fixed_tl); - return i; -} - -/************************************************************** - * Zipinflate_dynamic (internal) - */ -cab_LONG Zipinflate_dynamic(cab_decomp_state *decomp_state) - /* decompress an inflated type 2 (dynamic Huffman codes) block. */ -{ - cab_LONG i; /* temporary variables */ - cab_ULONG j; - cab_ULONG *ll; - cab_ULONG l; /* last length */ - cab_ULONG m; /* mask for bit lengths table */ - cab_ULONG n; /* number of lengths to get */ - struct Ziphuft *tl; /* literal/length code table */ - struct Ziphuft *td; /* distance code table */ - cab_LONG bl; /* lookup bits for tl */ - cab_LONG bd; /* lookup bits for td */ - cab_ULONG nb; /* number of bit length codes */ - cab_ULONG nl; /* number of literal/length codes */ - cab_ULONG nd; /* number of distance codes */ - register cab_ULONG b; /* bit buffer */ - register cab_ULONG k; /* number of bits in bit buffer */ - - /* make local bit buffer */ - b = ZIP(bb); - k = ZIP(bk); - ll = ZIP(ll); - - /* read in table lengths */ - ZIPNEEDBITS(5) - nl = 257 + ((cab_ULONG)b & 0x1f); /* number of literal/length codes */ - ZIPDUMPBITS(5) - ZIPNEEDBITS(5) - nd = 1 + ((cab_ULONG)b & 0x1f); /* number of distance codes */ - ZIPDUMPBITS(5) - ZIPNEEDBITS(4) - nb = 4 + ((cab_ULONG)b & 0xf); /* number of bit length codes */ - ZIPDUMPBITS(4) - if(nl > 288 || nd > 32) - return 1; /* bad lengths */ - - /* read in bit-length-code lengths */ - for(j = 0; j < nb; j++) - { - ZIPNEEDBITS(3) - ll[Zipborder[j]] = (cab_ULONG)b & 7; - ZIPDUMPBITS(3) - } - for(; j < 19; j++) - ll[Zipborder[j]] = 0; - - /* build decoding table for trees--single level, 7 bit lookup */ - bl = 7; - if((i = Ziphuft_build(ll, 19, 19, NULL, NULL, &tl, &bl, decomp_state)) != 0) - { - if(i == 1) - Ziphuft_free(tl); - return i; /* incomplete code set */ - } - - /* read in literal and distance code lengths */ - n = nl + nd; - m = Zipmask[bl]; - i = l = 0; - while((cab_ULONG)i < n) - { - ZIPNEEDBITS((cab_ULONG)bl) - j = (td = tl + ((cab_ULONG)b & m))->b; - ZIPDUMPBITS(j) - j = td->v.n; - if (j < 16) /* length of code in bits (0..15) */ - ll[i++] = l = j; /* save last length in l */ - else if (j == 16) /* repeat last length 3 to 6 times */ - { - ZIPNEEDBITS(2) - j = 3 + ((cab_ULONG)b & 3); - ZIPDUMPBITS(2) - if((cab_ULONG)i + j > n) - return 1; - while (j--) - ll[i++] = l; - } - else if (j == 17) /* 3 to 10 zero length codes */ - { - ZIPNEEDBITS(3) - j = 3 + ((cab_ULONG)b & 7); - ZIPDUMPBITS(3) - if ((cab_ULONG)i + j > n) - return 1; - while (j--) - ll[i++] = 0; - l = 0; - } - else /* j == 18: 11 to 138 zero length codes */ - { - ZIPNEEDBITS(7) - j = 11 + ((cab_ULONG)b & 0x7f); - ZIPDUMPBITS(7) - if ((cab_ULONG)i + j > n) - return 1; - while (j--) - ll[i++] = 0; - l = 0; - } - } - - /* free decoding table for trees */ - Ziphuft_free(tl); - - /* restore the global bit buffer */ - ZIP(bb) = b; - ZIP(bk) = k; - - /* build the decoding tables for literal/length and distance codes */ - bl = ZIPLBITS; - if((i = Ziphuft_build(ll, nl, 257, (cab_UWORD *) Zipcplens, (cab_UWORD *) Zipcplext, - &tl, &bl, decomp_state)) != 0) - { - if(i == 1) - Ziphuft_free(tl); - return i; /* incomplete code set */ - } - bd = ZIPDBITS; - Ziphuft_build(ll + nl, nd, 0, (cab_UWORD *) Zipcpdist, (cab_UWORD *) Zipcpdext, - &td, &bd, decomp_state); - - /* decompress until an end-of-block code */ - if(Zipinflate_codes(tl, td, bl, bd, decomp_state)) - return 1; - - /* free the decoding tables, return */ - Ziphuft_free(tl); - Ziphuft_free(td); - return 0; -} - -/***************************************************** - * Zipinflate_block (internal) - */ -cab_LONG Zipinflate_block(cab_LONG *e, cab_decomp_state *decomp_state) /* e == last block flag */ -{ /* decompress an inflated block */ - cab_ULONG t; /* block type */ - register cab_ULONG b; /* bit buffer */ - register cab_ULONG k; /* number of bits in bit buffer */ - - /* make local bit buffer */ - b = ZIP(bb); - k = ZIP(bk); - - /* read in last block bit */ - ZIPNEEDBITS(1) - *e = (cab_LONG)b & 1; - ZIPDUMPBITS(1) - - /* read in block type */ - ZIPNEEDBITS(2) - t = (cab_ULONG)b & 3; - ZIPDUMPBITS(2) - - /* restore the global bit buffer */ - ZIP(bb) = b; - ZIP(bk) = k; - - /* inflate that block type */ - if(t == 2) - return Zipinflate_dynamic(decomp_state); - if(t == 0) - return Zipinflate_stored(decomp_state); - if(t == 1) - return Zipinflate_fixed(decomp_state); - /* bad block type */ - return 2; -} - -/**************************************************** - * ZIPdecompress (internal) - */ -int ZIPdecompress(int inlen, int outlen, cab_decomp_state *decomp_state) -{ - cab_LONG e; /* last block flag */ - - TRACE("(inlen == %d, outlen == %d)\n", inlen, outlen); - - ZIP(inpos) = CAB(inbuf); - ZIP(bb) = ZIP(bk) = ZIP(window_posn) = 0; - if(outlen > ZIPWSIZE) - return DECR_DATAFORMAT; - - /* CK = Chris Kirmse, official Microsoft purloiner */ - if(ZIP(inpos)[0] != 0x43 || ZIP(inpos)[1] != 0x4B) - return DECR_ILLEGALDATA; - ZIP(inpos) += 2; - - do - { - if(Zipinflate_block(&e, decomp_state)) - return DECR_ILLEGALDATA; - } while(!e); - - /* return success */ - return DECR_OK; -} - -/* Quantum decruncher */ - -/* This decruncher was researched and implemented by Matthew Russoto. */ -/* It has since been tidied up by Stuart Caie */ - -/****************************************************************** - * QTMinitmodel (internal) - * - * Initialise a model which decodes symbols from [s] to [s]+[n]-1 - */ -void QTMinitmodel(struct QTMmodel *m, struct QTMmodelsym *sym, int n, int s) { - int i; - m->shiftsleft = 4; - m->entries = n; - m->syms = sym; - memset(m->tabloc, 0xFF, sizeof(m->tabloc)); /* clear out look-up table */ - for (i = 0; i < n; i++) { - m->tabloc[i+s] = i; /* set up a look-up entry for symbol */ - m->syms[i].sym = i+s; /* actual symbol */ - m->syms[i].cumfreq = n-i; /* current frequency of that symbol */ - } - m->syms[n].cumfreq = 0; -} - -/****************************************************************** - * QTMinit (internal) - */ -int QTMinit(int window, int level, cab_decomp_state *decomp_state) { - unsigned int wndsize = 1 << window; - int msz = window * 2, i; - cab_ULONG j; - - /* QTM supports window sizes of 2^10 (1Kb) through 2^21 (2Mb) */ - /* if a previously allocated window is big enough, keep it */ - if (window < 10 || window > 21) return DECR_DATAFORMAT; - if (QTM(actual_size) < wndsize) { - if (QTM(window)) free(QTM(window)); - QTM(window) = NULL; - } - if (!QTM(window)) { - if (!(QTM(window) = malloc(wndsize))) return DECR_NOMEMORY; - QTM(actual_size) = wndsize; - } - QTM(window_size) = wndsize; - QTM(window_posn) = 0; - - /* initialise static slot/extrabits tables */ - for (i = 0, j = 0; i < 27; i++) { - CAB(q_length_extra)[i] = (i == 26) ? 0 : (i < 2 ? 0 : i - 2) >> 2; - CAB(q_length_base)[i] = j; j += 1 << ((i == 26) ? 5 : CAB(q_length_extra)[i]); - } - for (i = 0, j = 0; i < 42; i++) { - CAB(q_extra_bits)[i] = (i < 2 ? 0 : i-2) >> 1; - CAB(q_position_base)[i] = j; j += 1 << CAB(q_extra_bits)[i]; - } - - /* initialise arithmetic coding models */ - - QTMinitmodel(&QTM(model7), &QTM(m7sym)[0], 7, 0); - - QTMinitmodel(&QTM(model00), &QTM(m00sym)[0], 0x40, 0x00); - QTMinitmodel(&QTM(model40), &QTM(m40sym)[0], 0x40, 0x40); - QTMinitmodel(&QTM(model80), &QTM(m80sym)[0], 0x40, 0x80); - QTMinitmodel(&QTM(modelC0), &QTM(mC0sym)[0], 0x40, 0xC0); - - /* model 4 depends on table size, ranges from 20 to 24 */ - QTMinitmodel(&QTM(model4), &QTM(m4sym)[0], (msz < 24) ? msz : 24, 0); - /* model 5 depends on table size, ranges from 20 to 36 */ - QTMinitmodel(&QTM(model5), &QTM(m5sym)[0], (msz < 36) ? msz : 36, 0); - /* model 6pos depends on table size, ranges from 20 to 42 */ - QTMinitmodel(&QTM(model6pos), &QTM(m6psym)[0], msz, 0); - QTMinitmodel(&QTM(model6len), &QTM(m6lsym)[0], 27, 0); - - return DECR_OK; -} - -/**************************************************************** - * QTMupdatemodel (internal) - */ -void QTMupdatemodel(struct QTMmodel *model, int sym) { - struct QTMmodelsym temp; - int i, j; - - for (i = 0; i < sym; i++) model->syms[i].cumfreq += 8; - - if (model->syms[0].cumfreq > 3800) { - if (--model->shiftsleft) { - for (i = model->entries - 1; i >= 0; i--) { - /* -1, not -2; the 0 entry saves this */ - model->syms[i].cumfreq >>= 1; - if (model->syms[i].cumfreq <= model->syms[i+1].cumfreq) { - model->syms[i].cumfreq = model->syms[i+1].cumfreq + 1; - } - } - } - else { - model->shiftsleft = 50; - for (i = 0; i < model->entries ; i++) { - /* no -1, want to include the 0 entry */ - /* this converts cumfreqs into frequencies, then shifts right */ - model->syms[i].cumfreq -= model->syms[i+1].cumfreq; - model->syms[i].cumfreq++; /* avoid losing things entirely */ - model->syms[i].cumfreq >>= 1; - } - - /* now sort by frequencies, decreasing order -- this must be an - * inplace selection sort, or a sort with the same (in)stability - * characteristics - */ - for (i = 0; i < model->entries - 1; i++) { - for (j = i + 1; j < model->entries; j++) { - if (model->syms[i].cumfreq < model->syms[j].cumfreq) { - temp = model->syms[i]; - model->syms[i] = model->syms[j]; - model->syms[j] = temp; - } - } - } - - /* then convert frequencies back to cumfreq */ - for (i = model->entries - 1; i >= 0; i--) { - model->syms[i].cumfreq += model->syms[i+1].cumfreq; - } - /* then update the other part of the table */ - for (i = 0; i < model->entries; i++) { - model->tabloc[model->syms[i].sym] = i; - } - } - } -} - -/******************************************************************* - * QTMdecompress (internal) - */ -int QTMdecompress(int inlen, int outlen, cab_decomp_state *decomp_state) -{ - cab_UBYTE *inpos = CAB(inbuf); - cab_UBYTE *window = QTM(window); - cab_UBYTE *runsrc, *rundest; - - cab_ULONG window_posn = QTM(window_posn); - cab_ULONG window_size = QTM(window_size); - - /* used by bitstream macros */ - register int bitsleft, bitrun, bitsneed; - register cab_ULONG bitbuf; - - /* used by GET_SYMBOL */ - cab_ULONG range; - cab_UWORD symf; - int i; - - int extra, togo = outlen, match_length = 0, copy_length; - cab_UBYTE selector, sym; - cab_ULONG match_offset = 0; - - cab_UWORD H = 0xFFFF, L = 0, C; - - TRACE("(inlen == %d, outlen == %d)\n", inlen, outlen); - - /* read initial value of C */ - Q_INIT_BITSTREAM; - Q_READ_BITS(C, 16); - - /* apply 2^x-1 mask */ - window_posn &= window_size - 1; - /* runs can't straddle the window wraparound */ - if ((window_posn + togo) > window_size) { - TRACE("straddled run\n"); - return DECR_DATAFORMAT; - } - - while (togo > 0) { - GET_SYMBOL(model7, selector); - switch (selector) { - case 0: - GET_SYMBOL(model00, sym); window[window_posn++] = sym; togo--; - break; - case 1: - GET_SYMBOL(model40, sym); window[window_posn++] = sym; togo--; - break; - case 2: - GET_SYMBOL(model80, sym); window[window_posn++] = sym; togo--; - break; - case 3: - GET_SYMBOL(modelC0, sym); window[window_posn++] = sym; togo--; - break; - - case 4: - /* selector 4 = fixed length of 3 */ - GET_SYMBOL(model4, sym); - Q_READ_BITS(extra, CAB(q_extra_bits)[sym]); - match_offset = CAB(q_position_base)[sym] + extra + 1; - match_length = 3; - break; - - case 5: - /* selector 5 = fixed length of 4 */ - GET_SYMBOL(model5, sym); - Q_READ_BITS(extra, CAB(q_extra_bits)[sym]); - match_offset = CAB(q_position_base)[sym] + extra + 1; - match_length = 4; - break; - - case 6: - /* selector 6 = variable length */ - GET_SYMBOL(model6len, sym); - Q_READ_BITS(extra, CAB(q_length_extra)[sym]); - match_length = CAB(q_length_base)[sym] + extra + 5; - GET_SYMBOL(model6pos, sym); - Q_READ_BITS(extra, CAB(q_extra_bits)[sym]); - match_offset = CAB(q_position_base)[sym] + extra + 1; - break; - - default: - TRACE("Selector is bogus\n"); - return DECR_ILLEGALDATA; - } - - /* if this is a match */ - if (selector >= 4) { - rundest = window + window_posn; - togo -= match_length; - - /* copy any wrapped around source data */ - if (window_posn >= match_offset) { - /* no wrap */ - runsrc = rundest - match_offset; - } else { - runsrc = rundest + (window_size - match_offset); - copy_length = match_offset - window_posn; - if (copy_length < match_length) { - match_length -= copy_length; - window_posn += copy_length; - while (copy_length-- > 0) *rundest++ = *runsrc++; - runsrc = window; - } - } - window_posn += match_length; - - /* copy match data - no worries about destination wraps */ - while (match_length-- > 0) *rundest++ = *runsrc++; - } - } /* while (togo > 0) */ - - if (togo != 0) { - TRACE("Frame overflow, this_run = %d\n", togo); - return DECR_ILLEGALDATA; - } - - memcpy(CAB(outbuf), window + ((!window_posn) ? window_size : window_posn) - - outlen, outlen); - - QTM(window_posn) = window_posn; - return DECR_OK; -} - -/* LZX decruncher */ - -/* Microsoft's LZX document and their implementation of the - * com.ms.util.cab Java package do not concur. - * - * In the LZX document, there is a table showing the correlation between - * window size and the number of position slots. It states that the 1MB - * window = 40 slots and the 2MB window = 42 slots. In the implementation, - * 1MB = 42 slots, 2MB = 50 slots. The actual calculation is 'find the - * first slot whose position base is equal to or more than the required - * window size'. This would explain why other tables in the document refer - * to 50 slots rather than 42. - * - * The constant NUM_PRIMARY_LENGTHS used in the decompression pseudocode - * is not defined in the specification. - * - * The LZX document does not state the uncompressed block has an - * uncompressed length field. Where does this length field come from, so - * we can know how large the block is? The implementation has it as the 24 - * bits following after the 3 blocktype bits, before the alignment - * padding. - * - * The LZX document states that aligned offset blocks have their aligned - * offset huffman tree AFTER the main and length trees. The implementation - * suggests that the aligned offset tree is BEFORE the main and length - * trees. - * - * The LZX document decoding algorithm states that, in an aligned offset - * block, if an extra_bits value is 1, 2 or 3, then that number of bits - * should be read and the result added to the match offset. This is - * correct for 1 and 2, but not 3, where just a huffman symbol (using the - * aligned tree) should be read. - * - * Regarding the E8 preprocessing, the LZX document states 'No translation - * may be performed on the last 6 bytes of the input block'. This is - * correct. However, the pseudocode provided checks for the *E8 leader* - * up to the last 6 bytes. If the leader appears between -10 and -7 bytes - * from the end, this would cause the next four bytes to be modified, at - * least one of which would be in the last 6 bytes, which is not allowed - * according to the spec. - * - * The specification states that the huffman trees must always contain at - * least one element. However, many CAB files contain blocks where the - * length tree is completely empty (because there are no matches), and - * this is expected to succeed. - */ - - -/* LZX uses what it calls 'position slots' to represent match offsets. - * What this means is that a small 'position slot' number and a small - * offset from that slot are encoded instead of one large offset for - * every match. - * - lzx_position_base is an index to the position slot bases - * - lzx_extra_bits states how many bits of offset-from-base data is needed. - */ - -/************************************************************ - * LZXinit (internal) - */ -int LZXinit(int window, cab_decomp_state *decomp_state) { - cab_ULONG wndsize = 1 << window; - int i, j, posn_slots; - - /* LZX supports window sizes of 2^15 (32Kb) through 2^21 (2Mb) */ - /* if a previously allocated window is big enough, keep it */ - if (window < 15 || window > 21) return DECR_DATAFORMAT; - if (LZX(actual_size) < wndsize) { - if (LZX(window)) free(LZX(window)); - LZX(window) = NULL; - } - if (!LZX(window)) { - if (!(LZX(window) = malloc(wndsize))) return DECR_NOMEMORY; - LZX(actual_size) = wndsize; - } - LZX(window_size) = wndsize; - - /* initialise static tables */ - for (i=0, j=0; i <= 50; i += 2) { - CAB(extra_bits)[i] = CAB(extra_bits)[i+1] = j; /* 0,0,0,0,1,1,2,2,3,3... */ - if ((i != 0) && (j < 17)) j++; /* 0,0,1,2,3,4...15,16,17,17,17,17... */ - } - for (i=0, j=0; i <= 50; i++) { - CAB(lzx_position_base)[i] = j; /* 0,1,2,3,4,6,8,12,16,24,32,... */ - j += 1 << CAB(extra_bits)[i]; /* 1,1,1,1,2,2,4,4,8,8,16,16,32,32,... */ - } - - /* calculate required position slots */ - if (window == 20) posn_slots = 42; - else if (window == 21) posn_slots = 50; - else posn_slots = window << 1; - - /*posn_slots=i=0; while (i < wndsize) i += 1 << CAB(extra_bits)[posn_slots++]; */ - - LZX(R0) = LZX(R1) = LZX(R2) = 1; - LZX(main_elements) = LZX_NUM_CHARS + (posn_slots << 3); - LZX(header_read) = 0; - LZX(frames_read) = 0; - LZX(block_remaining) = 0; - LZX(block_type) = LZX_BLOCKTYPE_INVALID; - LZX(intel_curpos) = 0; - LZX(intel_started) = 0; - LZX(window_posn) = 0; - - /* initialise tables to 0 (because deltas will be applied to them) */ - for (i = 0; i < LZX_MAINTREE_MAXSYMBOLS; i++) LZX(MAINTREE_len)[i] = 0; - for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++) LZX(LENGTH_len)[i] = 0; - - return DECR_OK; -} - -/************************************************************************* - * make_decode_table (internal) - * - * This function was coded by David Tritscher. It builds a fast huffman - * decoding table out of just a canonical huffman code lengths table. - * - * PARAMS - * nsyms: total number of symbols in this huffman tree. - * nbits: any symbols with a code length of nbits or less can be decoded - * in one lookup of the table. - * length: A table to get code lengths from [0 to syms-1] - * table: The table to fill up with decoded symbols and pointers. - * - * RETURNS - * OK: 0 - * error: 1 - */ -int make_decode_table(cab_ULONG nsyms, cab_ULONG nbits, cab_UBYTE *length, cab_UWORD *table) { - register cab_UWORD sym; - register cab_ULONG leaf; - register cab_UBYTE bit_num = 1; - cab_ULONG fill; - cab_ULONG pos = 0; /* the current position in the decode table */ - cab_ULONG table_mask = 1 << nbits; - cab_ULONG bit_mask = table_mask >> 1; /* don't do 0 length codes */ - cab_ULONG next_symbol = bit_mask; /* base of allocation for long codes */ - - /* fill entries for codes short enough for a direct mapping */ - while (bit_num <= nbits) { - for (sym = 0; sym < nsyms; sym++) { - if (length[sym] == bit_num) { - leaf = pos; - - if((pos += bit_mask) > table_mask) return 1; /* table overrun */ - - /* fill all possible lookups of this symbol with the symbol itself */ - fill = bit_mask; - while (fill-- > 0) table[leaf++] = sym; - } - } - bit_mask >>= 1; - bit_num++; - } - - /* if there are any codes longer than nbits */ - if (pos != table_mask) { - /* clear the remainder of the table */ - for (sym = pos; sym < table_mask; sym++) table[sym] = 0; - - /* give ourselves room for codes to grow by up to 16 more bits */ - pos <<= 16; - table_mask <<= 16; - bit_mask = 1 << 15; - - while (bit_num <= 16) { - for (sym = 0; sym < nsyms; sym++) { - if (length[sym] == bit_num) { - leaf = pos >> 16; - for (fill = 0; fill < bit_num - nbits; fill++) { - /* if this path hasn't been taken yet, 'allocate' two entries */ - if (table[leaf] == 0) { - table[(next_symbol << 1)] = 0; - table[(next_symbol << 1) + 1] = 0; - table[leaf] = next_symbol++; - } - /* follow the path and select either left or right for next bit */ - leaf = table[leaf] << 1; - if ((pos >> (15-fill)) & 1) leaf++; - } - table[leaf] = sym; - - if ((pos += bit_mask) > table_mask) return 1; /* table overflow */ - } - } - bit_mask >>= 1; - bit_num++; - } - } - - /* full table? */ - if (pos == table_mask) return 0; - - /* either erroneous table, or all elements are 0 - let's find out. */ - for (sym = 0; sym < nsyms; sym++) if (length[sym]) return 1; - return 0; -} - -/************************************************************ - * lzx_read_lens (internal) - */ -int lzx_read_lens(cab_UBYTE *lens, cab_ULONG first, cab_ULONG last, struct lzx_bits *lb, - cab_decomp_state *decomp_state) { - cab_ULONG i,j, x,y; - int z; - - register cab_ULONG bitbuf = lb->bb; - register int bitsleft = lb->bl; - cab_UBYTE *inpos = lb->ip; - cab_UWORD *hufftbl; - - for (x = 0; x < 20; x++) { - READ_BITS(y, 4); - LENTABLE(PRETREE)[x] = y; - } - BUILD_TABLE(PRETREE); - - for (x = first; x < last; ) { - READ_HUFFSYM(PRETREE, z); - if (z == 17) { - READ_BITS(y, 4); y += 4; - while (y--) lens[x++] = 0; - } - else if (z == 18) { - READ_BITS(y, 5); y += 20; - while (y--) lens[x++] = 0; - } - else if (z == 19) { - READ_BITS(y, 1); y += 4; - READ_HUFFSYM(PRETREE, z); - z = lens[x] - z; if (z < 0) z += 17; - while (y--) lens[x++] = z; - } - else { - z = lens[x] - z; if (z < 0) z += 17; - lens[x++] = z; - } - } - - lb->bb = bitbuf; - lb->bl = bitsleft; - lb->ip = inpos; - return 0; -} - -/******************************************************* - * LZXdecompress (internal) - */ -int LZXdecompress(int inlen, int outlen, cab_decomp_state *decomp_state) { - cab_UBYTE *inpos = CAB(inbuf); - cab_UBYTE *endinp = inpos + inlen; - cab_UBYTE *window = LZX(window); - cab_UBYTE *runsrc, *rundest; - cab_UWORD *hufftbl; /* used in READ_HUFFSYM macro as chosen decoding table */ - - cab_ULONG window_posn = LZX(window_posn); - cab_ULONG window_size = LZX(window_size); - cab_ULONG R0 = LZX(R0); - cab_ULONG R1 = LZX(R1); - cab_ULONG R2 = LZX(R2); - - register cab_ULONG bitbuf; - register int bitsleft; - cab_ULONG match_offset, i,j,k; /* ijk used in READ_HUFFSYM macro */ - struct lzx_bits lb; /* used in READ_LENGTHS macro */ - - int togo = outlen, this_run, main_element, aligned_bits; - int match_length, copy_length, length_footer, extra, verbatim_bits; - - TRACE("(inlen == %d, outlen == %d)\n", inlen, outlen); - - INIT_BITSTREAM; - - /* read header if necessary */ - if (!LZX(header_read)) { - i = j = 0; - READ_BITS(k, 1); if (k) { READ_BITS(i,16); READ_BITS(j,16); } - LZX(intel_filesize) = (i << 16) | j; /* or 0 if not encoded */ - LZX(header_read) = 1; - } - - /* main decoding loop */ - while (togo > 0) { - /* last block finished, new block expected */ - if (LZX(block_remaining) == 0) { - if (LZX(block_type) == LZX_BLOCKTYPE_UNCOMPRESSED) { - if (LZX(block_length) & 1) inpos++; /* realign bitstream to word */ - INIT_BITSTREAM; - } - - READ_BITS(LZX(block_type), 3); - READ_BITS(i, 16); - READ_BITS(j, 8); - LZX(block_remaining) = LZX(block_length) = (i << 8) | j; - - switch (LZX(block_type)) { - case LZX_BLOCKTYPE_ALIGNED: - for (i = 0; i < 8; i++) { READ_BITS(j, 3); LENTABLE(ALIGNED)[i] = j; } - BUILD_TABLE(ALIGNED); - /* rest of aligned header is same as verbatim */ - - case LZX_BLOCKTYPE_VERBATIM: - READ_LENGTHS(MAINTREE, 0, 256, lzx_read_lens); - READ_LENGTHS(MAINTREE, 256, LZX(main_elements), lzx_read_lens); - BUILD_TABLE(MAINTREE); - if (LENTABLE(MAINTREE)[0xE8] != 0) LZX(intel_started) = 1; - - READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS, lzx_read_lens); - BUILD_TABLE(LENGTH); - break; - - case LZX_BLOCKTYPE_UNCOMPRESSED: - LZX(intel_started) = 1; /* because we can't assume otherwise */ - ENSURE_BITS(16); /* get up to 16 pad bits into the buffer */ - if (bitsleft > 16) inpos -= 2; /* and align the bitstream! */ - R0 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4; - R1 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4; - R2 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4; - break; - - default: - return DECR_ILLEGALDATA; - } - } - - /* buffer exhaustion check */ - if (inpos > endinp) { - /* it's possible to have a file where the next run is less than - * 16 bits in size. In this case, the READ_HUFFSYM() macro used - * in building the tables will exhaust the buffer, so we should - * allow for this, but not allow those accidentally read bits to - * be used (so we check that there are at least 16 bits - * remaining - in this boundary case they aren't really part of - * the compressed data) - */ - if (inpos > (endinp+2) || bitsleft < 16) return DECR_ILLEGALDATA; - } - - while ((this_run = LZX(block_remaining)) > 0 && togo > 0) { - if (this_run > togo) this_run = togo; - togo -= this_run; - LZX(block_remaining) -= this_run; - - /* apply 2^x-1 mask */ - window_posn &= window_size - 1; - /* runs can't straddle the window wraparound */ - if ((window_posn + this_run) > window_size) - return DECR_DATAFORMAT; - - switch (LZX(block_type)) { - - case LZX_BLOCKTYPE_VERBATIM: - while (this_run > 0) { - READ_HUFFSYM(MAINTREE, main_element); - - if (main_element < LZX_NUM_CHARS) { - /* literal: 0 to LZX_NUM_CHARS-1 */ - window[window_posn++] = main_element; - this_run--; - } - else { - /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */ - main_element -= LZX_NUM_CHARS; - - match_length = main_element & LZX_NUM_PRIMARY_LENGTHS; - if (match_length == LZX_NUM_PRIMARY_LENGTHS) { - READ_HUFFSYM(LENGTH, length_footer); - match_length += length_footer; - } - match_length += LZX_MIN_MATCH; - - match_offset = main_element >> 3; - - if (match_offset > 2) { - /* not repeated offset */ - if (match_offset != 3) { - extra = CAB(extra_bits)[match_offset]; - READ_BITS(verbatim_bits, extra); - match_offset = CAB(lzx_position_base)[match_offset] - - 2 + verbatim_bits; - } - else { - match_offset = 1; - } - - /* update repeated offset LRU queue */ - R2 = R1; R1 = R0; R0 = match_offset; - } - else if (match_offset == 0) { - match_offset = R0; - } - else if (match_offset == 1) { - match_offset = R1; - R1 = R0; R0 = match_offset; - } - else /* match_offset == 2 */ { - match_offset = R2; - R2 = R0; R0 = match_offset; - } - - rundest = window + window_posn; - this_run -= match_length; - - /* copy any wrapped around source data */ - if (window_posn >= match_offset) { - /* no wrap */ - runsrc = rundest - match_offset; - } else { - runsrc = rundest + (window_size - match_offset); - copy_length = match_offset - window_posn; - if (copy_length < match_length) { - match_length -= copy_length; - window_posn += copy_length; - while (copy_length-- > 0) *rundest++ = *runsrc++; - runsrc = window; - } - } - window_posn += match_length; - - /* copy match data - no worries about destination wraps */ - while (match_length-- > 0) *rundest++ = *runsrc++; - } - } - break; - - case LZX_BLOCKTYPE_ALIGNED: - while (this_run > 0) { - READ_HUFFSYM(MAINTREE, main_element); - - if (main_element < LZX_NUM_CHARS) { - /* literal: 0 to LZX_NUM_CHARS-1 */ - window[window_posn++] = main_element; - this_run--; - } - else { - /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */ - main_element -= LZX_NUM_CHARS; - - match_length = main_element & LZX_NUM_PRIMARY_LENGTHS; - if (match_length == LZX_NUM_PRIMARY_LENGTHS) { - READ_HUFFSYM(LENGTH, length_footer); - match_length += length_footer; - } - match_length += LZX_MIN_MATCH; - - match_offset = main_element >> 3; - - if (match_offset > 2) { - /* not repeated offset */ - extra = CAB(extra_bits)[match_offset]; - match_offset = CAB(lzx_position_base)[match_offset] - 2; - if (extra > 3) { - /* verbatim and aligned bits */ - extra -= 3; - READ_BITS(verbatim_bits, extra); - match_offset += (verbatim_bits << 3); - READ_HUFFSYM(ALIGNED, aligned_bits); - match_offset += aligned_bits; - } - else if (extra == 3) { - /* aligned bits only */ - READ_HUFFSYM(ALIGNED, aligned_bits); - match_offset += aligned_bits; - } - else if (extra > 0) { /* extra==1, extra==2 */ - /* verbatim bits only */ - READ_BITS(verbatim_bits, extra); - match_offset += verbatim_bits; - } - else /* extra == 0 */ { - /* ??? */ - match_offset = 1; - } - - /* update repeated offset LRU queue */ - R2 = R1; R1 = R0; R0 = match_offset; - } - else if (match_offset == 0) { - match_offset = R0; - } - else if (match_offset == 1) { - match_offset = R1; - R1 = R0; R0 = match_offset; - } - else /* match_offset == 2 */ { - match_offset = R2; - R2 = R0; R0 = match_offset; - } - - rundest = window + window_posn; - this_run -= match_length; - - /* copy any wrapped around source data */ - if (window_posn >= match_offset) { - /* no wrap */ - runsrc = rundest - match_offset; - } else { - runsrc = rundest + (window_size - match_offset); - copy_length = match_offset - window_posn; - if (copy_length < match_length) { - match_length -= copy_length; - window_posn += copy_length; - while (copy_length-- > 0) *rundest++ = *runsrc++; - runsrc = window; - } - } - window_posn += match_length; - - /* copy match data - no worries about destination wraps */ - while (match_length-- > 0) *rundest++ = *runsrc++; - } - } - break; - - case LZX_BLOCKTYPE_UNCOMPRESSED: - if ((inpos + this_run) > endinp) return DECR_ILLEGALDATA; - memcpy(window + window_posn, inpos, (size_t) this_run); - inpos += this_run; window_posn += this_run; - break; - - default: - return DECR_ILLEGALDATA; /* might as well */ - } - - } - } - - if (togo != 0) return DECR_ILLEGALDATA; - memcpy(CAB(outbuf), window + ((!window_posn) ? window_size : window_posn) - - outlen, (size_t) outlen); - - LZX(window_posn) = window_posn; - LZX(R0) = R0; - LZX(R1) = R1; - LZX(R2) = R2; - - /* intel E8 decoding */ - if ((LZX(frames_read)++ < 32768) && LZX(intel_filesize) != 0) { - if (outlen <= 6 || !LZX(intel_started)) { - LZX(intel_curpos) += outlen; - } - else { - cab_UBYTE *data = CAB(outbuf); - cab_UBYTE *dataend = data + outlen - 10; - cab_LONG curpos = LZX(intel_curpos); - cab_LONG filesize = LZX(intel_filesize); - cab_LONG abs_off, rel_off; - - LZX(intel_curpos) = curpos + outlen; - - while (data < dataend) { - if (*data++ != 0xE8) { curpos++; continue; } - abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24); - if ((abs_off >= -curpos) && (abs_off < filesize)) { - rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize; - data[0] = (cab_UBYTE) rel_off; - data[1] = (cab_UBYTE) (rel_off >> 8); - data[2] = (cab_UBYTE) (rel_off >> 16); - data[3] = (cab_UBYTE) (rel_off >> 24); - } - data += 4; - curpos += 5; - } - } - } - return DECR_OK; -} - -/********************************************************* - * find_cabs_in_file (internal) - */ -struct cabinet *find_cabs_in_file(LPCSTR name, cab_UBYTE search_buf[]) -{ - struct cabinet *cab, *cab2, *firstcab = NULL, *linkcab = NULL; - cab_UBYTE *pstart = &search_buf[0], *pend, *p; - cab_off_t offset, caboff, cablen = 0, foffset = 0, filelen, length; - int state = 0, found = 0, ok = 0; - - TRACE("(name == %s)\n", debugstr_a(name)); - - /* open the file and search for cabinet headers */ - if ((cab = (struct cabinet *) calloc(1, sizeof(struct cabinet)))) { - cab->filename = name; - if (cabinet_open(cab)) { - filelen = cab->filelen; - for (offset = 0; (offset < filelen); offset += length) { - /* search length is either the full length of the search buffer, - * or the amount of data remaining to the end of the file, - * whichever is less. - */ - length = filelen - offset; - if (length > CAB_SEARCH_SIZE) length = CAB_SEARCH_SIZE; - - /* fill the search buffer with data from disk */ - if (!cabinet_read(cab, search_buf, length)) break; - - /* read through the entire buffer. */ - p = pstart; - pend = &search_buf[length]; - while (p < pend) { - switch (state) { - /* starting state */ - case 0: - /* we spend most of our time in this while loop, looking for - * a leading 'M' of the 'MSCF' signature - */ - while (*p++ != 0x4D && p < pend); - if (p < pend) state = 1; /* if we found tht 'M', advance state */ - break; - - /* verify that the next 3 bytes are 'S', 'C' and 'F' */ - case 1: state = (*p++ == 0x53) ? 2 : 0; break; - case 2: state = (*p++ == 0x43) ? 3 : 0; break; - case 3: state = (*p++ == 0x46) ? 4 : 0; break; - - /* we don't care about bytes 4-7 */ - /* bytes 8-11 are the overall length of the cabinet */ - case 8: cablen = *p++; state++; break; - case 9: cablen |= *p++ << 8; state++; break; - case 10: cablen |= *p++ << 16; state++; break; - case 11: cablen |= *p++ << 24; state++; break; - - /* we don't care about bytes 12-15 */ - /* bytes 16-19 are the offset within the cabinet of the filedata */ - case 16: foffset = *p++; state++; break; - case 17: foffset |= *p++ << 8; state++; break; - case 18: foffset |= *p++ << 16; state++; break; - case 19: foffset |= *p++ << 24; - /* now we have received 20 bytes of potential cab header. */ - /* work out the offset in the file of this potential cabinet */ - caboff = offset + (p-pstart) - 20; - - /* check that the files offset is less than the alleged length - * of the cabinet, and that the offset + the alleged length are - * 'roughly' within the end of overall file length - */ - if ((foffset < cablen) && - ((caboff + foffset) < (filelen + 32)) && - ((caboff + cablen) < (filelen + 32)) ) - { - /* found a potential result - try loading it */ - found++; - cab2 = load_cab_offset(name, caboff); - if (cab2) { - /* success */ - ok++; - - /* cause the search to restart after this cab's data. */ - offset = caboff + cablen; - if (offset < cab->filelen) cabinet_seek(cab, offset); - length = 0; - p = pend; - - /* link the cab into the list */ - if (linkcab == NULL) firstcab = cab2; - else linkcab->next = cab2; - linkcab = cab2; - } - } - state = 0; - break; - default: - p++, state++; break; - } - } - } - cabinet_close(cab); - } - free(cab); - } - - /* if there were cabinets that were found but are not ok, point this out */ - if (found > ok) { - WARN("%s: found %d bad cabinets\n", debugstr_a(name), found-ok); - } - - /* if no cabinets were found, let the user know */ - if (!firstcab) { - WARN("%s: not a Microsoft cabinet file.\n", debugstr_a(name)); - } - return firstcab; -} - -/*********************************************************************** - * find_cabinet_file (internal) - * - * tries to find *cabname, from the directory path of origcab, correcting the - * case of *cabname if necessary, If found, writes back to *cabname. - */ -void find_cabinet_file(char **cabname, LPCSTR origcab) { - - char *tail, *cab, *name, *nextpart, nametmp[MAX_PATH]; - int found = 0; - - TRACE("(*cabname == ^%p, origcab == %s)\n", cabname ? *cabname : NULL, debugstr_a(origcab)); - - /* ensure we have a cabinet name at all */ - if (!(name = *cabname)) { - WARN("no cabinet name at all\n"); - } - - /* find if there's a directory path in the origcab */ - tail = origcab ? max(strrchr(origcab, '/'), strrchr(origcab, '\\')) : NULL; - - if ((cab = (char *) malloc(MAX_PATH))) { - /* add the directory path from the original cabinet name */ - if (tail) { - memcpy(cab, origcab, tail - origcab); - cab[tail - origcab] = '\0'; - } else { - /* default directory path of '.' */ - cab[0] = '.'; - cab[1] = '\0'; - } - - do { - TRACE("trying cab == %s\n", debugstr_a(cab)); - - /* we don't want null cabinet filenames */ - if (name[0] == '\0') { - WARN("null cab name\n"); - break; - } - - /* if there is a directory component in the cabinet name, - * look for that alone first - */ - nextpart = strchr(name, '\\'); - if (nextpart) *nextpart = '\0'; - - found = SearchPathA(cab, name, NULL, MAX_PATH, nametmp, NULL); - - /* if the component was not found, look for it in the current dir */ - if (!found) { - found = SearchPathA(".", name, NULL, MAX_PATH, nametmp, NULL); - } - - if (found) - TRACE("found: %s\n", debugstr_a(nametmp)); - else - TRACE("not found.\n"); - - /* restore the real name and skip to the next directory component - * or actual cabinet name - */ - if (nextpart) *nextpart = '\\', name = &nextpart[1]; - - /* while there is another directory component, and while we - * successfully found the current component - */ - } while (nextpart && found); - - /* if we found the cabinet, change the next cabinet's name. - * otherwise, pretend nothing happened - */ - if (found) { - free((void *) *cabname); - *cabname = cab; - memcpy(cab, nametmp, found+1); - TRACE("result: %s\n", debugstr_a(cab)); - } else { - free((void *) cab); - TRACE("result: nothing\n"); - } - } -} - -/************************************************************************ - * process_files (internal) - * - * this does the tricky job of running through every file in the cabinet, - * including spanning cabinets, and working out which file is in which - * folder in which cabinet. It also throws out the duplicate file entries - * that appear in spanning cabinets. There is memory leakage here because - * those entries are not freed. See the XAD CAB client (function CAB_GetInfo - * in CAB.c) for an implementation of this that correctly frees the discarded - * file entries. - */ -struct cab_file *process_files(struct cabinet *basecab) { - struct cabinet *cab; - struct cab_file *outfi = NULL, *linkfi = NULL, *nextfi, *fi, *cfi; - struct cab_folder *fol, *firstfol, *lastfol = NULL, *predfol; - int i, mergeok; - - FIXME("(basecab == ^%p): Memory leak.\n", basecab); - - for (cab = basecab; cab; cab = cab->nextcab) { - /* firstfol = first folder in this cabinet */ - /* lastfol = last folder in this cabinet */ - /* predfol = last folder in previous cabinet (or NULL if first cabinet) */ - predfol = lastfol; - firstfol = cab->folders; - for (lastfol = firstfol; lastfol->next;) lastfol = lastfol->next; - mergeok = 1; - - for (fi = cab->files; fi; fi = nextfi) { - i = fi->index; - nextfi = fi->next; - - if (i < cffileCONTINUED_FROM_PREV) { - for (fol = firstfol; fol && i--; ) fol = fol->next; - fi->folder = fol; /* NULL if an invalid folder index */ - } - else { - /* folder merging */ - if (i == cffileCONTINUED_TO_NEXT - || i == cffileCONTINUED_PREV_AND_NEXT) { - if (cab->nextcab && !lastfol->contfile) lastfol->contfile = fi; - } - - if (i == cffileCONTINUED_FROM_PREV - || i == cffileCONTINUED_PREV_AND_NEXT) { - /* these files are to be continued in yet another - * cabinet, don't merge them in just yet */ - if (i == cffileCONTINUED_PREV_AND_NEXT) mergeok = 0; - - /* only merge once per cabinet */ - if (predfol) { - if ((cfi = predfol->contfile) - && (cfi->offset == fi->offset) - && (cfi->length == fi->length) - && (strcmp(cfi->filename, fi->filename) == 0) - && (predfol->comp_type == firstfol->comp_type)) { - /* increase the number of splits */ - if ((i = ++(predfol->num_splits)) > CAB_SPLITMAX) { - mergeok = 0; - ERR("%s: internal error: CAB_SPLITMAX exceeded. please report this to wine-devel@winehq.org)\n", - debugstr_a(basecab->filename)); - } - else { - /* copy information across from the merged folder */ - predfol->offset[i] = firstfol->offset[0]; - predfol->cab[i] = firstfol->cab[0]; - predfol->next = firstfol->next; - predfol->contfile = firstfol->contfile; - - if (firstfol == lastfol) lastfol = predfol; - firstfol = predfol; - predfol = NULL; /* don't merge again within this cabinet */ - } - } - else { - /* if the folders won't merge, don't add their files */ - mergeok = 0; - } - } - - if (mergeok) fi->folder = firstfol; - } - } - - if (fi->folder) { - if (linkfi) linkfi->next = fi; else outfi = fi; - linkfi = fi; - } - } /* for (fi= .. */ - } /* for (cab= ...*/ - - return outfi; -} - -/**************************************************************** - * convertUTF (internal) - * - * translate UTF -> ASCII - * - * UTF translates two-byte unicode characters into 1, 2 or 3 bytes. - * %000000000xxxxxxx -> %0xxxxxxx - * %00000xxxxxyyyyyy -> %110xxxxx %10yyyyyy - * %xxxxyyyyyyzzzzzz -> %1110xxxx %10yyyyyy %10zzzzzz - * - * Therefore, the inverse is as follows: - * First char: - * 0x00 - 0x7F = one byte char - * 0x80 - 0xBF = invalid - * 0xC0 - 0xDF = 2 byte char (next char only 0x80-0xBF is valid) - * 0xE0 - 0xEF = 3 byte char (next 2 chars only 0x80-0xBF is valid) - * 0xF0 - 0xFF = invalid - * - * FIXME: use a winapi to do this - */ -int convertUTF(cab_UBYTE *in) { - cab_UBYTE c, *out = in, *end = in + strlen((char *) in) + 1; - cab_ULONG x; - - do { - /* read unicode character */ - if ((c = *in++) < 0x80) x = c; - else { - if (c < 0xC0) return 0; - else if (c < 0xE0) { - x = (c & 0x1F) << 6; - if ((c = *in++) < 0x80 || c > 0xBF) return 0; else x |= (c & 0x3F); - } - else if (c < 0xF0) { - x = (c & 0xF) << 12; - if ((c = *in++) < 0x80 || c > 0xBF) return 0; else x |= (c & 0x3F)<<6; - if ((c = *in++) < 0x80 || c > 0xBF) return 0; else x |= (c & 0x3F); - } - else return 0; - } - - /* terrible unicode -> ASCII conversion */ - if (x > 127) x = '_'; - - if (in > end) return 0; /* just in case */ - } while ((*out++ = (cab_UBYTE) x)); - return 1; -} - -/**************************************************** - * NONEdecompress (internal) - */ -int NONEdecompress(int inlen, int outlen, cab_decomp_state *decomp_state) -{ - if (inlen != outlen) return DECR_ILLEGALDATA; - memcpy(CAB(outbuf), CAB(inbuf), (size_t) inlen); - return DECR_OK; -} - -/************************************************** - * checksum (internal) - */ -cab_ULONG checksum(cab_UBYTE *data, cab_UWORD bytes, cab_ULONG csum) { - int len; - cab_ULONG ul = 0; - - for (len = bytes >> 2; len--; data += 4) { - csum ^= ((data[0]) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24)); - } - - switch (bytes & 3) { - case 3: ul |= *data++ << 16; - case 2: ul |= *data++ << 8; - case 1: ul |= *data; - } - csum ^= ul; - - return csum; -} - -/********************************************************** - * decompress (internal) - */ -int decompress(struct cab_file *fi, int savemode, int fix, cab_decomp_state *decomp_state) -{ - cab_ULONG bytes = savemode ? fi->length : fi->offset - CAB(offset); - struct cabinet *cab = CAB(current)->cab[CAB(split)]; - cab_UBYTE buf[cfdata_SIZEOF], *data; - cab_UWORD inlen, len, outlen, cando; - cab_ULONG cksum; - cab_LONG err; - - TRACE("(fi == ^%p, savemode == %d, fix == %d)\n", fi, savemode, fix); - - while (bytes > 0) { - /* cando = the max number of bytes we can do */ - cando = CAB(outlen); - if (cando > bytes) cando = bytes; - - /* if cando != 0 */ - if (cando && savemode) - file_write(fi, CAB(outpos), cando); - - CAB(outpos) += cando; - CAB(outlen) -= cando; - bytes -= cando; if (!bytes) break; - - /* we only get here if we emptied the output buffer */ - - /* read data header + data */ - inlen = outlen = 0; - while (outlen == 0) { - /* read the block header, skip the reserved part */ - if (!cabinet_read(cab, buf, cfdata_SIZEOF)) return DECR_INPUT; - cabinet_skip(cab, cab->block_resv); - - /* we shouldn't get blocks over CAB_INPUTMAX in size */ - data = CAB(inbuf) + inlen; - len = EndGetI16(buf+cfdata_CompressedSize); - inlen += len; - if (inlen > CAB_INPUTMAX) return DECR_INPUT; - if (!cabinet_read(cab, data, len)) return DECR_INPUT; - - /* clear two bytes after read-in data */ - data[len+1] = data[len+2] = 0; - - /* perform checksum test on the block (if one is stored) */ - cksum = EndGetI32(buf+cfdata_CheckSum); - if (cksum && cksum != checksum(buf+4, 4, checksum(data, len, 0))) { - /* checksum is wrong */ - if (fix && ((fi->folder->comp_type & cffoldCOMPTYPE_MASK) - == cffoldCOMPTYPE_MSZIP)) - { - WARN("%s: checksum failed\n", debugstr_a(fi->filename)); - } - else { - return DECR_CHECKSUM; - } - } - - /* outlen=0 means this block was part of a split block */ - outlen = EndGetI16(buf+cfdata_UncompressedSize); - if (outlen == 0) { - cabinet_close(cab); - cab = CAB(current)->cab[++CAB(split)]; - if (!cabinet_open(cab)) return DECR_INPUT; - cabinet_seek(cab, CAB(current)->offset[CAB(split)]); - } - } - - /* decompress block */ - if ((err = CAB(decompress)(inlen, outlen, decomp_state))) { - if (fix && ((fi->folder->comp_type & cffoldCOMPTYPE_MASK) - == cffoldCOMPTYPE_MSZIP)) - { - ERR("%s: failed decrunching block\n", debugstr_a(fi->filename)); - } - else { - return err; - } - } - CAB(outlen) = outlen; - CAB(outpos) = CAB(outbuf); - } - - return DECR_OK; -} - -/**************************************************************** - * extract_file (internal) - * - * workhorse to extract a particular file from a cab - */ -void extract_file(struct cab_file *fi, int lower, int fix, LPCSTR dir, cab_decomp_state *decomp_state) -{ - struct cab_folder *fol = fi->folder, *oldfol = CAB(current); - cab_LONG err = DECR_OK; - - TRACE("(fi == ^%p, lower == %d, fix == %d, dir == %s)\n", fi, lower, fix, debugstr_a(dir)); - - /* is a change of folder needed? do we need to reset the current folder? */ - if (fol != oldfol || fi->offset < CAB(offset)) { - cab_UWORD comptype = fol->comp_type; - int ct1 = comptype & cffoldCOMPTYPE_MASK; - int ct2 = oldfol ? (oldfol->comp_type & cffoldCOMPTYPE_MASK) : 0; - - /* if the archiver has changed, call the old archiver's free() function */ - if (ct1 != ct2) { - switch (ct2) { - case cffoldCOMPTYPE_LZX: - if (LZX(window)) { - free(LZX(window)); - LZX(window) = NULL; - } - break; - case cffoldCOMPTYPE_QUANTUM: - if (QTM(window)) { - free(QTM(window)); - QTM(window) = NULL; - } - break; - } - } - - switch (ct1) { - case cffoldCOMPTYPE_NONE: - CAB(decompress) = NONEdecompress; - break; - - case cffoldCOMPTYPE_MSZIP: - CAB(decompress) = ZIPdecompress; - break; - - case cffoldCOMPTYPE_QUANTUM: - CAB(decompress) = QTMdecompress; - err = QTMinit((comptype >> 8) & 0x1f, (comptype >> 4) & 0xF, decomp_state); - break; - - case cffoldCOMPTYPE_LZX: - CAB(decompress) = LZXdecompress; - err = LZXinit((comptype >> 8) & 0x1f, decomp_state); - break; - - default: - err = DECR_DATAFORMAT; - } - if (err) goto exit_handler; - - /* initialisation OK, set current folder and reset offset */ - if (oldfol) cabinet_close(oldfol->cab[CAB(split)]); - if (!cabinet_open(fol->cab[0])) goto exit_handler; - cabinet_seek(fol->cab[0], fol->offset[0]); - CAB(current) = fol; - CAB(offset) = 0; - CAB(outlen) = 0; /* discard existing block */ - CAB(split) = 0; - } - - if (fi->offset > CAB(offset)) { - /* decode bytes and send them to /dev/null */ - if ((err = decompress(fi, 0, fix, decomp_state))) goto exit_handler; - CAB(offset) = fi->offset; - } - - if (!file_open(fi, lower, dir)) return; - err = decompress(fi, 1, fix, decomp_state); - if (err) CAB(current) = NULL; else CAB(offset) += fi->length; - file_close(fi); - -exit_handler: - if (err) { - const char *errmsg; - const char *cabname; - switch (err) { - case DECR_NOMEMORY: - errmsg = "out of memory!\n"; break; - case DECR_ILLEGALDATA: - errmsg = "%s: illegal or corrupt data\n"; break; - case DECR_DATAFORMAT: - errmsg = "%s: unsupported data format\n"; break; - case DECR_CHECKSUM: - errmsg = "%s: checksum error\n"; break; - case DECR_INPUT: - errmsg = "%s: input error\n"; break; - case DECR_OUTPUT: - errmsg = "%s: output error\n"; break; - default: - errmsg = "%s: unknown error (BUG)\n"; - } - - if (CAB(current)) { - cabname = (CAB(current)->cab[CAB(split)]->filename); - } - else { - cabname = (fi->folder->cab[0]->filename); - } - - ERR((char *)errmsg, cabname); - } -} - -/********************************************************* - * print_fileinfo (internal) - */ -void print_fileinfo(struct cab_file *fi) { - char *fname = NULL; - - if (fi->attribs & cffile_A_NAME_IS_UTF) { - fname = malloc(strlen(fi->filename) + 1); - if (fname) { - strcpy(fname, fi->filename); - convertUTF((cab_UBYTE *) fname); - } - } - - TRACE("%9u | %02d.%02d.%04d %02d:%02d:%02d | %s\n", - fi->length, - fi->date & 0x1f, (fi->date>>5) & 0xf, (fi->date>>9) + 1980, - fi->time >> 11, (fi->time>>5) & 0x3f, (fi->time << 1) & 0x3e, - fname ? fname : fi->filename - ); - - if (fname) free(fname); -} - -/**************************************************************************** - * process_cabinet (internal) - * - * called to simply "extract" a cabinet file. Will find every cabinet file - * in that file, search for every chained cabinet attached to those cabinets, - * and will either extract the cabinets, or ? (call a callback?) - * - * PARAMS - * cabname [I] name of the cabinet file to extract - * dir [I] directory to extract to - * fix [I] attempt to process broken cabinets - * lower [I] ? (lower case something or other?) - * dest [O] - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL process_cabinet(LPCSTR cabname, LPCSTR dir, BOOL fix, BOOL lower, EXTRACTdest *dest) -{ - struct cabinet *basecab, *cab, *cab1, *cab2; - struct cab_file *filelist, *fi; - struct ExtractFileList **destlistptr = &(dest->filelist); - - /* The first result of a search will be returned, and - * the remaining results will be chained to it via the cab->next structure - * member. - */ - cab_UBYTE search_buf[CAB_SEARCH_SIZE]; - - cab_decomp_state decomp_state_local; - cab_decomp_state *decomp_state = &decomp_state_local; - - /* has the list-mode header been seen before? */ - int viewhdr = 0; - - ZeroMemory(decomp_state, sizeof(cab_decomp_state)); - - TRACE("Extract %s\n", debugstr_a(cabname)); - - /* load the file requested */ - basecab = find_cabs_in_file(cabname, search_buf); - if (!basecab) return FALSE; - - /* iterate over all cabinets found in that file */ - for (cab = basecab; cab; cab=cab->next) { - - /* bi-directionally load any spanning cabinets -- backwards */ - for (cab1 = cab; cab1->flags & cfheadPREV_CABINET; cab1 = cab1->prevcab) { - TRACE("%s: extends backwards to %s (%s)\n", debugstr_a(cabname), - debugstr_a(cab1->prevname), debugstr_a(cab1->previnfo)); - find_cabinet_file(&(cab1->prevname), cabname); - if (!(cab1->prevcab = load_cab_offset(cab1->prevname, 0))) { - ERR("%s: can't read previous cabinet %s\n", debugstr_a(cabname), debugstr_a(cab1->prevname)); - break; - } - cab1->prevcab->nextcab = cab1; - } - - /* bi-directionally load any spanning cabinets -- forwards */ - for (cab2 = cab; cab2->flags & cfheadNEXT_CABINET; cab2 = cab2->nextcab) { - TRACE("%s: extends to %s (%s)\n", debugstr_a(cabname), - debugstr_a(cab2->nextname), debugstr_a(cab2->nextinfo)); - find_cabinet_file(&(cab2->nextname), cabname); - if (!(cab2->nextcab = load_cab_offset(cab2->nextname, 0))) { - ERR("%s: can't read next cabinet %s\n", debugstr_a(cabname), debugstr_a(cab2->nextname)); - break; - } - cab2->nextcab->prevcab = cab2; - } - - filelist = process_files(cab1); - CAB(current) = NULL; - - if (!viewhdr) { - TRACE("File size | Date Time | Name\n"); - TRACE("----------+---------------------+-------------\n"); - viewhdr = 1; - } - for (fi = filelist; fi; fi = fi->next) { - print_fileinfo(fi); - dest->filecount++; - } - TRACE("Beginning Extraction...\n"); - for (fi = filelist; fi; fi = fi->next) { - TRACE(" extracting: %s\n", debugstr_a(fi->filename)); - extract_file(fi, lower, fix, dir, decomp_state); - sprintf(dest->lastfile, "%s%s%s", - strlen(dest->directory) ? dest->directory : "", - strlen(dest->directory) ? "\\": "", - fi->filename); - *destlistptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(struct ExtractFileList)); - if(*destlistptr) { - (*destlistptr)->unknown = TRUE; /* FIXME: were do we get the value? */ - (*destlistptr)->filename = HeapAlloc(GetProcessHeap(), 0, ( - strlen(fi->filename)+1)); - if((*destlistptr)->filename) - lstrcpyA((*destlistptr)->filename, fi->filename); - destlistptr = &((*destlistptr)->next); - } - } - } - - TRACE("Finished processing cabinet.\n"); - - return TRUE; -} +/* + * cabextract.c + * + * Copyright 2000-2002 Stuart Caie + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Principal author: Stuart Caie + * + * Based on specification documents from Microsoft Corporation + * Quantum decompression researched and implemented by Matthew Russoto + * Huffman code adapted from unlzx by Dave Tritscher. + * InfoZip team's INFLATE implementation adapted to MSZIP by Dirk Stoecker. + * Major LZX fixes by Jae Jung. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" + +#include "cabinet.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(cabinet); + +THOSE_ZIP_CONSTS; + +/* all the file IO is abstracted into these routines: + * cabinet_(open|close|read|seek|skip|getoffset) + * file_(open|close|write) + */ + +/* try to open a cabinet file, returns success */ +BOOL cabinet_open(struct cabinet *cab) +{ + const char *name = cab->filename; + HANDLE fh; + + TRACE("(cab == ^%p)\n", cab); + + if ((fh = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL )) == INVALID_HANDLE_VALUE) { + ERR("Couldn't open %s\n", debugstr_a(name)); + return FALSE; + } + + /* seek to end of file and get the length */ + if ((cab->filelen = SetFilePointer(fh, 0, NULL, FILE_END)) == INVALID_SET_FILE_POINTER) { + if (GetLastError() != NO_ERROR) { + ERR("Seek END failed: %s\n", debugstr_a(name)); + CloseHandle(fh); + return FALSE; + } + } + + /* return to the start of the file */ + if (SetFilePointer(fh, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { + ERR("Seek BEGIN failed: %s\n", debugstr_a(name)); + CloseHandle(fh); + return FALSE; + } + + cab->fh = fh; + return TRUE; +} + +/******************************************************************* + * cabinet_close (internal) + * + * close the file handle in a struct cabinet. + */ +void cabinet_close(struct cabinet *cab) { + TRACE("(cab == ^%p)\n", cab); + if (cab->fh) CloseHandle(cab->fh); + cab->fh = 0; +} + +/******************************************************* + * ensure_filepath2 (internal) + */ +BOOL ensure_filepath2(char *path) { + BOOL ret = TRUE; + int len; + char *new_path; + + new_path = HeapAlloc(GetProcessHeap(), 0, (strlen(path) + 1)); + strcpy(new_path, path); + + while((len = strlen(new_path)) && new_path[len - 1] == '\\') + new_path[len - 1] = 0; + + TRACE("About to try to create directory %s\n", debugstr_a(new_path)); + while(!CreateDirectoryA(new_path, NULL)) { + char *slash; + DWORD last_error = GetLastError(); + + if(last_error == ERROR_ALREADY_EXISTS) + break; + + if(last_error != ERROR_PATH_NOT_FOUND) { + ret = FALSE; + break; + } + + if(!(slash = strrchr(new_path, '\\'))) { + ret = FALSE; + break; + } + + len = slash - new_path; + new_path[len] = 0; + if(! ensure_filepath2(new_path)) { + ret = FALSE; + break; + } + new_path[len] = '\\'; + TRACE("New path in next iteration: %s\n", debugstr_a(new_path)); + } + + HeapFree(GetProcessHeap(), 0, new_path); + return ret; +} + + +/********************************************************************** + * ensure_filepath (internal) + * + * ensure_filepath("a\b\c\d.txt") ensures a, a\b and a\b\c exist as dirs + */ +BOOL ensure_filepath(char *path) { + char new_path[MAX_PATH]; + int len, i, lastslashpos = -1; + + TRACE("(path == %s)\n", debugstr_a(path)); + + strcpy(new_path, path); + /* remove trailing slashes (shouldn't need to but wth...) */ + while ((len = strlen(new_path)) && new_path[len - 1] == '\\') + new_path[len - 1] = 0; + /* find the position of the last '\\' */ + for (i=0; i 0) { + new_path[lastslashpos] = 0; + /* may be trailing slashes but ensure_filepath2 will chop them */ + return ensure_filepath2(new_path); + } else + return TRUE; /* ? */ +} + +/******************************************************************* + * file_open (internal) + * + * opens a file for output, returns success + */ +BOOL file_open(struct cab_file *fi, BOOL lower, LPCSTR dir) +{ + char c, *d, *name; + BOOL ok = FALSE; + const char *s; + + TRACE("(fi == ^%p, lower == %s, dir == %s)\n", fi, lower ? "TRUE" : "FALSE", debugstr_a(dir)); + + if (!(name = malloc(strlen(fi->filename) + (dir ? strlen(dir) : 0) + 2))) { + ERR("out of memory!\n"); + return FALSE; + } + + /* start with blank name */ + *name = 0; + + /* add output directory if needed */ + if (dir) { + strcpy(name, dir); + strcat(name, "\\"); + } + + /* remove leading slashes */ + s = (char *) fi->filename; + while (*s == '\\') s++; + + /* copy from fi->filename to new name. + * lowercases characters if needed. + */ + d = &name[strlen(name)]; + do { + c = *s++; + *d++ = (lower ? tolower((unsigned char) c) : c); + } while (c); + + /* create directories if needed, attempt to write file */ + if (ensure_filepath(name)) { + fi->fh = CreateFileA(name, GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (fi->fh != INVALID_HANDLE_VALUE) + ok = TRUE; + else { + ERR("CreateFileA returned INVALID_HANDLE_VALUE\n"); + fi->fh = 0; + } + } else + ERR("Couldn't ensure filepath for %s\n", debugstr_a(name)); + + if (!ok) { + ERR("Couldn't open file %s for writing\n", debugstr_a(name)); + } + + /* as full filename is no longer needed, free it */ + free(name); + + return ok; +} + +/******************************************************** + * close_file (internal) + * + * closes a completed file + */ +void file_close(struct cab_file *fi) +{ + TRACE("(fi == ^%p)\n", fi); + + if (fi->fh) { + CloseHandle(fi->fh); + } + fi->fh = 0; +} + +/****************************************************************** + * file_write (internal) + * + * writes from buf to a file specified as a cab_file struct. + * returns success/failure + */ +BOOL file_write(struct cab_file *fi, cab_UBYTE *buf, cab_off_t length) +{ + DWORD bytes_written; + + TRACE("(fi == ^%p, buf == ^%p, length == %u)\n", fi, buf, length); + + if ((!WriteFile( fi->fh, (LPCVOID) buf, length, &bytes_written, FALSE) || + (bytes_written != length))) { + ERR("Error writing file: %s\n", debugstr_a(fi->filename)); + return FALSE; + } + return TRUE; +} + + +/******************************************************************* + * cabinet_skip (internal) + * + * advance the file pointer associated with the cab structure + * by distance bytes + */ +void cabinet_skip(struct cabinet *cab, cab_off_t distance) +{ + TRACE("(cab == ^%p, distance == %u)\n", cab, distance); + if (SetFilePointer(cab->fh, distance, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER) { + if (distance != INVALID_SET_FILE_POINTER) + ERR("%s\n", debugstr_a(cab->filename)); + } +} + +/******************************************************************* + * cabinet_seek (internal) + * + * seek to the specified absolute offset in a cab + */ +void cabinet_seek(struct cabinet *cab, cab_off_t offset) { + TRACE("(cab == ^%p, offset == %u)\n", cab, offset); + if (SetFilePointer(cab->fh, offset, NULL, FILE_BEGIN) != offset) + ERR("%s seek failure\n", debugstr_a(cab->filename)); +} + +/******************************************************************* + * cabinet_getoffset (internal) + * + * returns the file pointer position of a cab + */ +cab_off_t cabinet_getoffset(struct cabinet *cab) +{ + return SetFilePointer(cab->fh, 0, NULL, FILE_CURRENT); +} + +/******************************************************************* + * cabinet_read (internal) + * + * read data from a cabinet, returns success + */ +BOOL cabinet_read(struct cabinet *cab, cab_UBYTE *buf, cab_off_t length) +{ + DWORD bytes_read; + cab_off_t avail = cab->filelen - cabinet_getoffset(cab); + + TRACE("(cab == ^%p, buf == ^%p, length == %u)\n", cab, buf, length); + + if (length > avail) { + WARN("%s: WARNING; cabinet is truncated\n", debugstr_a(cab->filename)); + length = avail; + } + + if (! ReadFile( cab->fh, (LPVOID) buf, length, &bytes_read, NULL )) { + ERR("%s read error\n", debugstr_a(cab->filename)); + return FALSE; + } else if (bytes_read != length) { + ERR("%s read size mismatch\n", debugstr_a(cab->filename)); + return FALSE; + } + + return TRUE; +} + +/********************************************************************** + * cabinet_read_string (internal) + * + * allocate and read an aribitrarily long string from the cabinet + */ +char *cabinet_read_string(struct cabinet *cab) +{ + cab_off_t len=256, base = cabinet_getoffset(cab), maxlen = cab->filelen - base; + BOOL ok = FALSE; + unsigned int i; + cab_UBYTE *buf = NULL; + + TRACE("(cab == ^%p)\n", cab); + + do { + if (len > maxlen) len = maxlen; + if (!(buf = realloc(buf, (size_t) len))) break; + if (!cabinet_read(cab, buf, (size_t) len)) break; + + /* search for a null terminator in what we've just read */ + for (i=0; i < len; i++) { + if (!buf[i]) {ok=TRUE; break;} + } + + if (!ok) { + if (len == maxlen) { + ERR("%s: WARNING; cabinet is truncated\n", debugstr_a(cab->filename)); + break; + } + len += 256; + cabinet_seek(cab, base); + } + } while (!ok); + + if (!ok) { + if (buf) + free(buf); + else + ERR("out of memory!\n"); + return NULL; + } + + /* otherwise, set the stream to just after the string and return */ + cabinet_seek(cab, base + ((cab_off_t) strlen((char *) buf)) + 1); + + return (char *) buf; +} + +/****************************************************************** + * cabinet_read_entries (internal) + * + * reads the header and all folder and file entries in this cabinet + */ +BOOL cabinet_read_entries(struct cabinet *cab) +{ + int num_folders, num_files, header_resv, folder_resv = 0, i; + struct cab_folder *fol, *linkfol = NULL; + struct cab_file *file, *linkfile = NULL; + cab_off_t base_offset; + cab_UBYTE buf[64]; + + TRACE("(cab == ^%p)\n", cab); + + /* read in the CFHEADER */ + base_offset = cabinet_getoffset(cab); + if (!cabinet_read(cab, buf, cfhead_SIZEOF)) { + return FALSE; + } + + /* check basic MSCF signature */ + if (EndGetI32(buf+cfhead_Signature) != 0x4643534d) { + ERR("%s: not a Microsoft cabinet file\n", debugstr_a(cab->filename)); + return FALSE; + } + + /* get the number of folders */ + num_folders = EndGetI16(buf+cfhead_NumFolders); + if (num_folders == 0) { + ERR("%s: no folders in cabinet\n", debugstr_a(cab->filename)); + return FALSE; + } + + /* get the number of files */ + num_files = EndGetI16(buf+cfhead_NumFiles); + if (num_files == 0) { + ERR("%s: no files in cabinet\n", debugstr_a(cab->filename)); + return FALSE; + } + + /* just check the header revision */ + if ((buf[cfhead_MajorVersion] > 1) || + (buf[cfhead_MajorVersion] == 1 && buf[cfhead_MinorVersion] > 3)) + { + WARN("%s: WARNING; cabinet format version > 1.3\n", debugstr_a(cab->filename)); + } + + /* read the reserved-sizes part of header, if present */ + cab->flags = EndGetI16(buf+cfhead_Flags); + if (cab->flags & cfheadRESERVE_PRESENT) { + if (!cabinet_read(cab, buf, cfheadext_SIZEOF)) return FALSE; + header_resv = EndGetI16(buf+cfheadext_HeaderReserved); + folder_resv = buf[cfheadext_FolderReserved]; + cab->block_resv = buf[cfheadext_DataReserved]; + + if (header_resv > 60000) { + WARN("%s: WARNING; header reserved space > 60000\n", debugstr_a(cab->filename)); + } + + /* skip the reserved header */ + if (header_resv) + if (SetFilePointer(cab->fh, (cab_off_t) header_resv, NULL, FILE_CURRENT) == INVALID_SET_FILE_POINTER) + ERR("seek failure: %s\n", debugstr_a(cab->filename)); + } + + if (cab->flags & cfheadPREV_CABINET) { + cab->prevname = cabinet_read_string(cab); + if (!cab->prevname) return FALSE; + cab->previnfo = cabinet_read_string(cab); + } + + if (cab->flags & cfheadNEXT_CABINET) { + cab->nextname = cabinet_read_string(cab); + if (!cab->nextname) return FALSE; + cab->nextinfo = cabinet_read_string(cab); + } + + /* read folders */ + for (i = 0; i < num_folders; i++) { + if (!cabinet_read(cab, buf, cffold_SIZEOF)) return FALSE; + if (folder_resv) cabinet_skip(cab, folder_resv); + + fol = (struct cab_folder *) calloc(1, sizeof(struct cab_folder)); + if (!fol) { + ERR("out of memory!\n"); + return FALSE; + } + + fol->cab[0] = cab; + fol->offset[0] = base_offset + (cab_off_t) EndGetI32(buf+cffold_DataOffset); + fol->num_blocks = EndGetI16(buf+cffold_NumBlocks); + fol->comp_type = EndGetI16(buf+cffold_CompType); + + if (!linkfol) + cab->folders = fol; + else + linkfol->next = fol; + + linkfol = fol; + } + + /* read files */ + for (i = 0; i < num_files; i++) { + if (!cabinet_read(cab, buf, cffile_SIZEOF)) + return FALSE; + + file = (struct cab_file *) calloc(1, sizeof(struct cab_file)); + if (!file) { + ERR("out of memory!\n"); + return FALSE; + } + + file->length = EndGetI32(buf+cffile_UncompressedSize); + file->offset = EndGetI32(buf+cffile_FolderOffset); + file->index = EndGetI16(buf+cffile_FolderIndex); + file->time = EndGetI16(buf+cffile_Time); + file->date = EndGetI16(buf+cffile_Date); + file->attribs = EndGetI16(buf+cffile_Attribs); + file->filename = cabinet_read_string(cab); + + if (!file->filename) { + free(file); + return FALSE; + } + + if (!linkfile) + cab->files = file; + else + linkfile->next = file; + + linkfile = file; + } + return TRUE; +} + +/*********************************************************** + * load_cab_offset (internal) + * + * validates and reads file entries from a cabinet at offset [offset] in + * file [name]. Returns a cabinet structure if successful, or NULL + * otherwise. + */ +struct cabinet *load_cab_offset(LPCSTR name, cab_off_t offset) +{ + struct cabinet *cab = (struct cabinet *) calloc(1, sizeof(struct cabinet)); + int ok; + + TRACE("(name == %s, offset == %u)\n", debugstr_a(name), offset); + + if (!cab) return NULL; + + cab->filename = name; + if ((ok = cabinet_open(cab))) { + cabinet_seek(cab, offset); + ok = cabinet_read_entries(cab); + cabinet_close(cab); + } + + if (ok) return cab; + free(cab); + return NULL; +} + +/* MSZIP decruncher */ + +/* Dirk Stoecker wrote the ZIP decoder, based on the InfoZip deflate code */ + +/******************************************************** + * Ziphuft_free (internal) + */ +void Ziphuft_free(struct Ziphuft *t) +{ + register struct Ziphuft *p, *q; + + /* Go through linked list, freeing from the allocated (t[-1]) address. */ + p = t; + while (p != (struct Ziphuft *)NULL) + { + q = (--p)->v.t; + free(p); + p = q; + } +} + +/********************************************************* + * Ziphuft_build (internal) + */ +cab_LONG Ziphuft_build(cab_ULONG *b, cab_ULONG n, cab_ULONG s, cab_UWORD *d, cab_UWORD *e, +struct Ziphuft **t, cab_LONG *m, cab_decomp_state *decomp_state) +{ + cab_ULONG a; /* counter for codes of length k */ + cab_ULONG el; /* length of EOB code (value 256) */ + cab_ULONG f; /* i repeats in table every f entries */ + cab_LONG g; /* maximum code length */ + cab_LONG h; /* table level */ + register cab_ULONG i; /* counter, current code */ + register cab_ULONG j; /* counter */ + register cab_LONG k; /* number of bits in current code */ + cab_LONG *l; /* stack of bits per table */ + register cab_ULONG *p; /* pointer into ZIP(c)[],ZIP(b)[],ZIP(v)[] */ + register struct Ziphuft *q; /* points to current table */ + struct Ziphuft r; /* table entry for structure assignment */ + register cab_LONG w; /* bits before this table == (l * h) */ + cab_ULONG *xp; /* pointer into x */ + cab_LONG y; /* number of dummy codes added */ + cab_ULONG z; /* number of entries in current table */ + + l = ZIP(lx)+1; + + /* Generate counts for each bit length */ + el = n > 256 ? b[256] : ZIPBMAX; /* set length of EOB code, if any */ + + for(i = 0; i < ZIPBMAX+1; ++i) + ZIP(c)[i] = 0; + p = b; i = n; + do + { + ZIP(c)[*p]++; p++; /* assume all entries <= ZIPBMAX */ + } while (--i); + if (ZIP(c)[0] == n) /* null input--all zero length codes */ + { + *t = (struct Ziphuft *)NULL; + *m = 0; + return 0; + } + + /* Find minimum and maximum length, bound *m by those */ + for (j = 1; j <= ZIPBMAX; j++) + if (ZIP(c)[j]) + break; + k = j; /* minimum code length */ + if ((cab_ULONG)*m < j) + *m = j; + for (i = ZIPBMAX; i; i--) + if (ZIP(c)[i]) + break; + g = i; /* maximum code length */ + if ((cab_ULONG)*m > i) + *m = i; + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= ZIP(c)[j]) < 0) + return 2; /* bad input: more codes than bits */ + if ((y -= ZIP(c)[i]) < 0) + return 2; + ZIP(c)[i] += y; + + /* Generate starting offsets LONGo the value table for each length */ + ZIP(x)[1] = j = 0; + p = ZIP(c) + 1; xp = ZIP(x) + 2; + while (--i) + { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do{ + if ((j = *p++) != 0) + ZIP(v)[ZIP(x)[j]++] = i; + } while (++i < n); + + + /* Generate the Huffman codes and for each, make the table entries */ + ZIP(x)[0] = i = 0; /* first Huffman code is zero */ + p = ZIP(v); /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = l[-1] = 0; /* no bits decoded yet */ + ZIP(u)[0] = (struct Ziphuft *)NULL; /* just to keep compilers happy */ + q = (struct Ziphuft *)NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = ZIP(c)[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l[h]) + { + w += l[h++]; /* add bits already decoded */ + + /* compute minimum size table less than or equal to *m bits */ + z = (z = g - w) > (cab_ULONG)*m ? *m : z; /* upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = ZIP(c) + k; + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + if ((cab_ULONG)w + j > el && (cab_ULONG)w < el) + j = el - w; /* make EOB code end at table */ + z = 1 << j; /* table entries for j-bit table */ + l[h] = j; /* set table size in stack */ + + /* allocate and link in new table */ + if (!(q = (struct Ziphuft *) malloc((z + 1)*sizeof(struct Ziphuft)))) + { + if(h) + Ziphuft_free(ZIP(u)[0]); + return 3; /* not enough memory */ + } + *t = q + 1; /* link to list for Ziphuft_free() */ + *(t = &(q->v.t)) = (struct Ziphuft *)NULL; + ZIP(u)[h] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (h) + { + ZIP(x)[h] = i; /* save pattern for backing up */ + r.b = (cab_UBYTE)l[h-1]; /* bits to dump before this table */ + r.e = (cab_UBYTE)(16 + j); /* bits in this table */ + r.v.t = q; /* pointer to this table */ + j = (i & ((1 << w) - 1)) >> (w - l[h-1]); + ZIP(u)[h-1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.b = (cab_UBYTE)(k - w); + if (p >= ZIP(v) + n) + r.e = 99; /* out of values--invalid code */ + else if (*p < s) + { + r.e = (cab_UBYTE)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */ + r.v.n = *p++; /* simple code is just the value */ + } + else + { + r.e = (cab_UBYTE)e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != ZIP(x)[h]) + w -= l[--h]; /* don't need to update q */ + } + } + + /* return actual size of base table */ + *m = l[0]; + + /* Return true (1) if we were given an incomplete table */ + return y != 0 && g != 1; +} + +/********************************************************* + * Zipinflate_codes (internal) + */ +cab_LONG Zipinflate_codes(struct Ziphuft *tl, struct Ziphuft *td, + cab_LONG bl, cab_LONG bd, cab_decomp_state *decomp_state) +{ + register cab_ULONG e; /* table entry flag/number of extra bits */ + cab_ULONG n, d; /* length and index for copy */ + cab_ULONG w; /* current window position */ + struct Ziphuft *t; /* pointer to table entry */ + cab_ULONG ml, md; /* masks for bl and bd bits */ + register cab_ULONG b; /* bit buffer */ + register cab_ULONG k; /* number of bits in bit buffer */ + + /* make local copies of globals */ + b = ZIP(bb); /* initialize bit buffer */ + k = ZIP(bk); + w = ZIP(window_posn); /* initialize window position */ + + /* inflate the coded data */ + ml = Zipmask[bl]; /* precompute masks for speed */ + md = Zipmask[bd]; + + for(;;) + { + ZIPNEEDBITS((cab_ULONG)bl) + if((e = (t = tl + ((cab_ULONG)b & ml))->e) > 16) + do + { + if (e == 99) + return 1; + ZIPDUMPBITS(t->b) + e -= 16; + ZIPNEEDBITS(e) + } while ((e = (t = t->v.t + ((cab_ULONG)b & Zipmask[e]))->e) > 16); + ZIPDUMPBITS(t->b) + if (e == 16) /* then it's a literal */ + CAB(outbuf)[w++] = (cab_UBYTE)t->v.n; + else /* it's an EOB or a length */ + { + /* exit if end of block */ + if(e == 15) + break; + + /* get length of block to copy */ + ZIPNEEDBITS(e) + n = t->v.n + ((cab_ULONG)b & Zipmask[e]); + ZIPDUMPBITS(e); + + /* decode distance of block to copy */ + ZIPNEEDBITS((cab_ULONG)bd) + if ((e = (t = td + ((cab_ULONG)b & md))->e) > 16) + do { + if (e == 99) + return 1; + ZIPDUMPBITS(t->b) + e -= 16; + ZIPNEEDBITS(e) + } while ((e = (t = t->v.t + ((cab_ULONG)b & Zipmask[e]))->e) > 16); + ZIPDUMPBITS(t->b) + ZIPNEEDBITS(e) + d = w - t->v.n - ((cab_ULONG)b & Zipmask[e]); + ZIPDUMPBITS(e) + do + { + n -= (e = (e = ZIPWSIZE - ((d &= ZIPWSIZE-1) > w ? d : w)) > n ?n:e); + do + { + CAB(outbuf)[w++] = CAB(outbuf)[d++]; + } while (--e); + } while (n); + } + } + + /* restore the globals from the locals */ + ZIP(window_posn) = w; /* restore global window pointer */ + ZIP(bb) = b; /* restore global bit buffer */ + ZIP(bk) = k; + + /* done */ + return 0; +} + +/*********************************************************** + * Zipinflate_stored (internal) + */ +cab_LONG Zipinflate_stored(cab_decomp_state *decomp_state) +/* "decompress" an inflated type 0 (stored) block. */ +{ + cab_ULONG n; /* number of bytes in block */ + cab_ULONG w; /* current window position */ + register cab_ULONG b; /* bit buffer */ + register cab_ULONG k; /* number of bits in bit buffer */ + + /* make local copies of globals */ + b = ZIP(bb); /* initialize bit buffer */ + k = ZIP(bk); + w = ZIP(window_posn); /* initialize window position */ + + /* go to byte boundary */ + n = k & 7; + ZIPDUMPBITS(n); + + /* get the length and its complement */ + ZIPNEEDBITS(16) + n = ((cab_ULONG)b & 0xffff); + ZIPDUMPBITS(16) + ZIPNEEDBITS(16) + if (n != (cab_ULONG)((~b) & 0xffff)) + return 1; /* error in compressed data */ + ZIPDUMPBITS(16) + + /* read and output the compressed data */ + while(n--) + { + ZIPNEEDBITS(8) + CAB(outbuf)[w++] = (cab_UBYTE)b; + ZIPDUMPBITS(8) + } + + /* restore the globals from the locals */ + ZIP(window_posn) = w; /* restore global window pointer */ + ZIP(bb) = b; /* restore global bit buffer */ + ZIP(bk) = k; + return 0; +} + +/****************************************************** + * Zipinflate_fixed (internal) + */ +cab_LONG Zipinflate_fixed(cab_decomp_state *decomp_state) +{ + struct Ziphuft *fixed_tl; + struct Ziphuft *fixed_td; + cab_LONG fixed_bl, fixed_bd; + cab_LONG i; /* temporary variable */ + cab_ULONG *l; + + l = ZIP(ll); + + /* literal table */ + for(i = 0; i < 144; i++) + l[i] = 8; + for(; i < 256; i++) + l[i] = 9; + for(; i < 280; i++) + l[i] = 7; + for(; i < 288; i++) /* make a complete, but wrong code set */ + l[i] = 8; + fixed_bl = 7; + if((i = Ziphuft_build(l, 288, 257, (cab_UWORD *) Zipcplens, + (cab_UWORD *) Zipcplext, &fixed_tl, &fixed_bl, decomp_state))) + return i; + + /* distance table */ + for(i = 0; i < 30; i++) /* make an incomplete code set */ + l[i] = 5; + fixed_bd = 5; + if((i = Ziphuft_build(l, 30, 0, (cab_UWORD *) Zipcpdist, (cab_UWORD *) Zipcpdext, + &fixed_td, &fixed_bd, decomp_state)) > 1) + { + Ziphuft_free(fixed_tl); + return i; + } + + /* decompress until an end-of-block code */ + i = Zipinflate_codes(fixed_tl, fixed_td, fixed_bl, fixed_bd, decomp_state); + + Ziphuft_free(fixed_td); + Ziphuft_free(fixed_tl); + return i; +} + +/************************************************************** + * Zipinflate_dynamic (internal) + */ +cab_LONG Zipinflate_dynamic(cab_decomp_state *decomp_state) + /* decompress an inflated type 2 (dynamic Huffman codes) block. */ +{ + cab_LONG i; /* temporary variables */ + cab_ULONG j; + cab_ULONG *ll; + cab_ULONG l; /* last length */ + cab_ULONG m; /* mask for bit lengths table */ + cab_ULONG n; /* number of lengths to get */ + struct Ziphuft *tl; /* literal/length code table */ + struct Ziphuft *td; /* distance code table */ + cab_LONG bl; /* lookup bits for tl */ + cab_LONG bd; /* lookup bits for td */ + cab_ULONG nb; /* number of bit length codes */ + cab_ULONG nl; /* number of literal/length codes */ + cab_ULONG nd; /* number of distance codes */ + register cab_ULONG b; /* bit buffer */ + register cab_ULONG k; /* number of bits in bit buffer */ + + /* make local bit buffer */ + b = ZIP(bb); + k = ZIP(bk); + ll = ZIP(ll); + + /* read in table lengths */ + ZIPNEEDBITS(5) + nl = 257 + ((cab_ULONG)b & 0x1f); /* number of literal/length codes */ + ZIPDUMPBITS(5) + ZIPNEEDBITS(5) + nd = 1 + ((cab_ULONG)b & 0x1f); /* number of distance codes */ + ZIPDUMPBITS(5) + ZIPNEEDBITS(4) + nb = 4 + ((cab_ULONG)b & 0xf); /* number of bit length codes */ + ZIPDUMPBITS(4) + if(nl > 288 || nd > 32) + return 1; /* bad lengths */ + + /* read in bit-length-code lengths */ + for(j = 0; j < nb; j++) + { + ZIPNEEDBITS(3) + ll[Zipborder[j]] = (cab_ULONG)b & 7; + ZIPDUMPBITS(3) + } + for(; j < 19; j++) + ll[Zipborder[j]] = 0; + + /* build decoding table for trees--single level, 7 bit lookup */ + bl = 7; + if((i = Ziphuft_build(ll, 19, 19, NULL, NULL, &tl, &bl, decomp_state)) != 0) + { + if(i == 1) + Ziphuft_free(tl); + return i; /* incomplete code set */ + } + + /* read in literal and distance code lengths */ + n = nl + nd; + m = Zipmask[bl]; + i = l = 0; + while((cab_ULONG)i < n) + { + ZIPNEEDBITS((cab_ULONG)bl) + j = (td = tl + ((cab_ULONG)b & m))->b; + ZIPDUMPBITS(j) + j = td->v.n; + if (j < 16) /* length of code in bits (0..15) */ + ll[i++] = l = j; /* save last length in l */ + else if (j == 16) /* repeat last length 3 to 6 times */ + { + ZIPNEEDBITS(2) + j = 3 + ((cab_ULONG)b & 3); + ZIPDUMPBITS(2) + if((cab_ULONG)i + j > n) + return 1; + while (j--) + ll[i++] = l; + } + else if (j == 17) /* 3 to 10 zero length codes */ + { + ZIPNEEDBITS(3) + j = 3 + ((cab_ULONG)b & 7); + ZIPDUMPBITS(3) + if ((cab_ULONG)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + else /* j == 18: 11 to 138 zero length codes */ + { + ZIPNEEDBITS(7) + j = 11 + ((cab_ULONG)b & 0x7f); + ZIPDUMPBITS(7) + if ((cab_ULONG)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + } + + /* free decoding table for trees */ + Ziphuft_free(tl); + + /* restore the global bit buffer */ + ZIP(bb) = b; + ZIP(bk) = k; + + /* build the decoding tables for literal/length and distance codes */ + bl = ZIPLBITS; + if((i = Ziphuft_build(ll, nl, 257, (cab_UWORD *) Zipcplens, (cab_UWORD *) Zipcplext, + &tl, &bl, decomp_state)) != 0) + { + if(i == 1) + Ziphuft_free(tl); + return i; /* incomplete code set */ + } + bd = ZIPDBITS; + Ziphuft_build(ll + nl, nd, 0, (cab_UWORD *) Zipcpdist, (cab_UWORD *) Zipcpdext, + &td, &bd, decomp_state); + + /* decompress until an end-of-block code */ + if(Zipinflate_codes(tl, td, bl, bd, decomp_state)) + return 1; + + /* free the decoding tables, return */ + Ziphuft_free(tl); + Ziphuft_free(td); + return 0; +} + +/***************************************************** + * Zipinflate_block (internal) + */ +cab_LONG Zipinflate_block(cab_LONG *e, cab_decomp_state *decomp_state) /* e == last block flag */ +{ /* decompress an inflated block */ + cab_ULONG t; /* block type */ + register cab_ULONG b; /* bit buffer */ + register cab_ULONG k; /* number of bits in bit buffer */ + + /* make local bit buffer */ + b = ZIP(bb); + k = ZIP(bk); + + /* read in last block bit */ + ZIPNEEDBITS(1) + *e = (cab_LONG)b & 1; + ZIPDUMPBITS(1) + + /* read in block type */ + ZIPNEEDBITS(2) + t = (cab_ULONG)b & 3; + ZIPDUMPBITS(2) + + /* restore the global bit buffer */ + ZIP(bb) = b; + ZIP(bk) = k; + + /* inflate that block type */ + if(t == 2) + return Zipinflate_dynamic(decomp_state); + if(t == 0) + return Zipinflate_stored(decomp_state); + if(t == 1) + return Zipinflate_fixed(decomp_state); + /* bad block type */ + return 2; +} + +/**************************************************** + * ZIPdecompress (internal) + */ +int ZIPdecompress(int inlen, int outlen, cab_decomp_state *decomp_state) +{ + cab_LONG e; /* last block flag */ + + TRACE("(inlen == %d, outlen == %d)\n", inlen, outlen); + + ZIP(inpos) = CAB(inbuf); + ZIP(bb) = ZIP(bk) = ZIP(window_posn) = 0; + if(outlen > ZIPWSIZE) + return DECR_DATAFORMAT; + + /* CK = Chris Kirmse, official Microsoft purloiner */ + if(ZIP(inpos)[0] != 0x43 || ZIP(inpos)[1] != 0x4B) + return DECR_ILLEGALDATA; + ZIP(inpos) += 2; + + do + { + if(Zipinflate_block(&e, decomp_state)) + return DECR_ILLEGALDATA; + } while(!e); + + /* return success */ + return DECR_OK; +} + +/* Quantum decruncher */ + +/* This decruncher was researched and implemented by Matthew Russoto. */ +/* It has since been tidied up by Stuart Caie */ + +/****************************************************************** + * QTMinitmodel (internal) + * + * Initialise a model which decodes symbols from [s] to [s]+[n]-1 + */ +void QTMinitmodel(struct QTMmodel *m, struct QTMmodelsym *sym, int n, int s) { + int i; + m->shiftsleft = 4; + m->entries = n; + m->syms = sym; + memset(m->tabloc, 0xFF, sizeof(m->tabloc)); /* clear out look-up table */ + for (i = 0; i < n; i++) { + m->tabloc[i+s] = i; /* set up a look-up entry for symbol */ + m->syms[i].sym = i+s; /* actual symbol */ + m->syms[i].cumfreq = n-i; /* current frequency of that symbol */ + } + m->syms[n].cumfreq = 0; +} + +/****************************************************************** + * QTMinit (internal) + */ +int QTMinit(int window, int level, cab_decomp_state *decomp_state) { + unsigned int wndsize = 1 << window; + int msz = window * 2, i; + cab_ULONG j; + + /* QTM supports window sizes of 2^10 (1Kb) through 2^21 (2Mb) */ + /* if a previously allocated window is big enough, keep it */ + if (window < 10 || window > 21) return DECR_DATAFORMAT; + if (QTM(actual_size) < wndsize) { + if (QTM(window)) free(QTM(window)); + QTM(window) = NULL; + } + if (!QTM(window)) { + if (!(QTM(window) = malloc(wndsize))) return DECR_NOMEMORY; + QTM(actual_size) = wndsize; + } + QTM(window_size) = wndsize; + QTM(window_posn) = 0; + + /* initialise static slot/extrabits tables */ + for (i = 0, j = 0; i < 27; i++) { + CAB(q_length_extra)[i] = (i == 26) ? 0 : (i < 2 ? 0 : i - 2) >> 2; + CAB(q_length_base)[i] = j; j += 1 << ((i == 26) ? 5 : CAB(q_length_extra)[i]); + } + for (i = 0, j = 0; i < 42; i++) { + CAB(q_extra_bits)[i] = (i < 2 ? 0 : i-2) >> 1; + CAB(q_position_base)[i] = j; j += 1 << CAB(q_extra_bits)[i]; + } + + /* initialise arithmetic coding models */ + + QTMinitmodel(&QTM(model7), &QTM(m7sym)[0], 7, 0); + + QTMinitmodel(&QTM(model00), &QTM(m00sym)[0], 0x40, 0x00); + QTMinitmodel(&QTM(model40), &QTM(m40sym)[0], 0x40, 0x40); + QTMinitmodel(&QTM(model80), &QTM(m80sym)[0], 0x40, 0x80); + QTMinitmodel(&QTM(modelC0), &QTM(mC0sym)[0], 0x40, 0xC0); + + /* model 4 depends on table size, ranges from 20 to 24 */ + QTMinitmodel(&QTM(model4), &QTM(m4sym)[0], (msz < 24) ? msz : 24, 0); + /* model 5 depends on table size, ranges from 20 to 36 */ + QTMinitmodel(&QTM(model5), &QTM(m5sym)[0], (msz < 36) ? msz : 36, 0); + /* model 6pos depends on table size, ranges from 20 to 42 */ + QTMinitmodel(&QTM(model6pos), &QTM(m6psym)[0], msz, 0); + QTMinitmodel(&QTM(model6len), &QTM(m6lsym)[0], 27, 0); + + return DECR_OK; +} + +/**************************************************************** + * QTMupdatemodel (internal) + */ +void QTMupdatemodel(struct QTMmodel *model, int sym) { + struct QTMmodelsym temp; + int i, j; + + for (i = 0; i < sym; i++) model->syms[i].cumfreq += 8; + + if (model->syms[0].cumfreq > 3800) { + if (--model->shiftsleft) { + for (i = model->entries - 1; i >= 0; i--) { + /* -1, not -2; the 0 entry saves this */ + model->syms[i].cumfreq >>= 1; + if (model->syms[i].cumfreq <= model->syms[i+1].cumfreq) { + model->syms[i].cumfreq = model->syms[i+1].cumfreq + 1; + } + } + } + else { + model->shiftsleft = 50; + for (i = 0; i < model->entries ; i++) { + /* no -1, want to include the 0 entry */ + /* this converts cumfreqs into frequencies, then shifts right */ + model->syms[i].cumfreq -= model->syms[i+1].cumfreq; + model->syms[i].cumfreq++; /* avoid losing things entirely */ + model->syms[i].cumfreq >>= 1; + } + + /* now sort by frequencies, decreasing order -- this must be an + * inplace selection sort, or a sort with the same (in)stability + * characteristics + */ + for (i = 0; i < model->entries - 1; i++) { + for (j = i + 1; j < model->entries; j++) { + if (model->syms[i].cumfreq < model->syms[j].cumfreq) { + temp = model->syms[i]; + model->syms[i] = model->syms[j]; + model->syms[j] = temp; + } + } + } + + /* then convert frequencies back to cumfreq */ + for (i = model->entries - 1; i >= 0; i--) { + model->syms[i].cumfreq += model->syms[i+1].cumfreq; + } + /* then update the other part of the table */ + for (i = 0; i < model->entries; i++) { + model->tabloc[model->syms[i].sym] = i; + } + } + } +} + +/******************************************************************* + * QTMdecompress (internal) + */ +int QTMdecompress(int inlen, int outlen, cab_decomp_state *decomp_state) +{ + cab_UBYTE *inpos = CAB(inbuf); + cab_UBYTE *window = QTM(window); + cab_UBYTE *runsrc, *rundest; + + cab_ULONG window_posn = QTM(window_posn); + cab_ULONG window_size = QTM(window_size); + + /* used by bitstream macros */ + register int bitsleft, bitrun, bitsneed; + register cab_ULONG bitbuf; + + /* used by GET_SYMBOL */ + cab_ULONG range; + cab_UWORD symf; + int i; + + int extra, togo = outlen, match_length = 0, copy_length; + cab_UBYTE selector, sym; + cab_ULONG match_offset = 0; + + cab_UWORD H = 0xFFFF, L = 0, C; + + TRACE("(inlen == %d, outlen == %d)\n", inlen, outlen); + + /* read initial value of C */ + Q_INIT_BITSTREAM; + Q_READ_BITS(C, 16); + + /* apply 2^x-1 mask */ + window_posn &= window_size - 1; + /* runs can't straddle the window wraparound */ + if ((window_posn + togo) > window_size) { + TRACE("straddled run\n"); + return DECR_DATAFORMAT; + } + + while (togo > 0) { + GET_SYMBOL(model7, selector); + switch (selector) { + case 0: + GET_SYMBOL(model00, sym); window[window_posn++] = sym; togo--; + break; + case 1: + GET_SYMBOL(model40, sym); window[window_posn++] = sym; togo--; + break; + case 2: + GET_SYMBOL(model80, sym); window[window_posn++] = sym; togo--; + break; + case 3: + GET_SYMBOL(modelC0, sym); window[window_posn++] = sym; togo--; + break; + + case 4: + /* selector 4 = fixed length of 3 */ + GET_SYMBOL(model4, sym); + Q_READ_BITS(extra, CAB(q_extra_bits)[sym]); + match_offset = CAB(q_position_base)[sym] + extra + 1; + match_length = 3; + break; + + case 5: + /* selector 5 = fixed length of 4 */ + GET_SYMBOL(model5, sym); + Q_READ_BITS(extra, CAB(q_extra_bits)[sym]); + match_offset = CAB(q_position_base)[sym] + extra + 1; + match_length = 4; + break; + + case 6: + /* selector 6 = variable length */ + GET_SYMBOL(model6len, sym); + Q_READ_BITS(extra, CAB(q_length_extra)[sym]); + match_length = CAB(q_length_base)[sym] + extra + 5; + GET_SYMBOL(model6pos, sym); + Q_READ_BITS(extra, CAB(q_extra_bits)[sym]); + match_offset = CAB(q_position_base)[sym] + extra + 1; + break; + + default: + TRACE("Selector is bogus\n"); + return DECR_ILLEGALDATA; + } + + /* if this is a match */ + if (selector >= 4) { + rundest = window + window_posn; + togo -= match_length; + + /* copy any wrapped around source data */ + if (window_posn >= match_offset) { + /* no wrap */ + runsrc = rundest - match_offset; + } else { + runsrc = rundest + (window_size - match_offset); + copy_length = match_offset - window_posn; + if (copy_length < match_length) { + match_length -= copy_length; + window_posn += copy_length; + while (copy_length-- > 0) *rundest++ = *runsrc++; + runsrc = window; + } + } + window_posn += match_length; + + /* copy match data - no worries about destination wraps */ + while (match_length-- > 0) *rundest++ = *runsrc++; + } + } /* while (togo > 0) */ + + if (togo != 0) { + TRACE("Frame overflow, this_run = %d\n", togo); + return DECR_ILLEGALDATA; + } + + memcpy(CAB(outbuf), window + ((!window_posn) ? window_size : window_posn) - + outlen, outlen); + + QTM(window_posn) = window_posn; + return DECR_OK; +} + +/* LZX decruncher */ + +/* Microsoft's LZX document and their implementation of the + * com.ms.util.cab Java package do not concur. + * + * In the LZX document, there is a table showing the correlation between + * window size and the number of position slots. It states that the 1MB + * window = 40 slots and the 2MB window = 42 slots. In the implementation, + * 1MB = 42 slots, 2MB = 50 slots. The actual calculation is 'find the + * first slot whose position base is equal to or more than the required + * window size'. This would explain why other tables in the document refer + * to 50 slots rather than 42. + * + * The constant NUM_PRIMARY_LENGTHS used in the decompression pseudocode + * is not defined in the specification. + * + * The LZX document does not state the uncompressed block has an + * uncompressed length field. Where does this length field come from, so + * we can know how large the block is? The implementation has it as the 24 + * bits following after the 3 blocktype bits, before the alignment + * padding. + * + * The LZX document states that aligned offset blocks have their aligned + * offset huffman tree AFTER the main and length trees. The implementation + * suggests that the aligned offset tree is BEFORE the main and length + * trees. + * + * The LZX document decoding algorithm states that, in an aligned offset + * block, if an extra_bits value is 1, 2 or 3, then that number of bits + * should be read and the result added to the match offset. This is + * correct for 1 and 2, but not 3, where just a huffman symbol (using the + * aligned tree) should be read. + * + * Regarding the E8 preprocessing, the LZX document states 'No translation + * may be performed on the last 6 bytes of the input block'. This is + * correct. However, the pseudocode provided checks for the *E8 leader* + * up to the last 6 bytes. If the leader appears between -10 and -7 bytes + * from the end, this would cause the next four bytes to be modified, at + * least one of which would be in the last 6 bytes, which is not allowed + * according to the spec. + * + * The specification states that the huffman trees must always contain at + * least one element. However, many CAB files contain blocks where the + * length tree is completely empty (because there are no matches), and + * this is expected to succeed. + */ + + +/* LZX uses what it calls 'position slots' to represent match offsets. + * What this means is that a small 'position slot' number and a small + * offset from that slot are encoded instead of one large offset for + * every match. + * - lzx_position_base is an index to the position slot bases + * - lzx_extra_bits states how many bits of offset-from-base data is needed. + */ + +/************************************************************ + * LZXinit (internal) + */ +int LZXinit(int window, cab_decomp_state *decomp_state) { + cab_ULONG wndsize = 1 << window; + int i, j, posn_slots; + + /* LZX supports window sizes of 2^15 (32Kb) through 2^21 (2Mb) */ + /* if a previously allocated window is big enough, keep it */ + if (window < 15 || window > 21) return DECR_DATAFORMAT; + if (LZX(actual_size) < wndsize) { + if (LZX(window)) free(LZX(window)); + LZX(window) = NULL; + } + if (!LZX(window)) { + if (!(LZX(window) = malloc(wndsize))) return DECR_NOMEMORY; + LZX(actual_size) = wndsize; + } + LZX(window_size) = wndsize; + + /* initialise static tables */ + for (i=0, j=0; i <= 50; i += 2) { + CAB(extra_bits)[i] = CAB(extra_bits)[i+1] = j; /* 0,0,0,0,1,1,2,2,3,3... */ + if ((i != 0) && (j < 17)) j++; /* 0,0,1,2,3,4...15,16,17,17,17,17... */ + } + for (i=0, j=0; i <= 50; i++) { + CAB(lzx_position_base)[i] = j; /* 0,1,2,3,4,6,8,12,16,24,32,... */ + j += 1 << CAB(extra_bits)[i]; /* 1,1,1,1,2,2,4,4,8,8,16,16,32,32,... */ + } + + /* calculate required position slots */ + if (window == 20) posn_slots = 42; + else if (window == 21) posn_slots = 50; + else posn_slots = window << 1; + + /*posn_slots=i=0; while (i < wndsize) i += 1 << CAB(extra_bits)[posn_slots++]; */ + + LZX(R0) = LZX(R1) = LZX(R2) = 1; + LZX(main_elements) = LZX_NUM_CHARS + (posn_slots << 3); + LZX(header_read) = 0; + LZX(frames_read) = 0; + LZX(block_remaining) = 0; + LZX(block_type) = LZX_BLOCKTYPE_INVALID; + LZX(intel_curpos) = 0; + LZX(intel_started) = 0; + LZX(window_posn) = 0; + + /* initialise tables to 0 (because deltas will be applied to them) */ + for (i = 0; i < LZX_MAINTREE_MAXSYMBOLS; i++) LZX(MAINTREE_len)[i] = 0; + for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++) LZX(LENGTH_len)[i] = 0; + + return DECR_OK; +} + +/************************************************************************* + * make_decode_table (internal) + * + * This function was coded by David Tritscher. It builds a fast huffman + * decoding table out of just a canonical huffman code lengths table. + * + * PARAMS + * nsyms: total number of symbols in this huffman tree. + * nbits: any symbols with a code length of nbits or less can be decoded + * in one lookup of the table. + * length: A table to get code lengths from [0 to syms-1] + * table: The table to fill up with decoded symbols and pointers. + * + * RETURNS + * OK: 0 + * error: 1 + */ +int make_decode_table(cab_ULONG nsyms, cab_ULONG nbits, cab_UBYTE *length, cab_UWORD *table) { + register cab_UWORD sym; + register cab_ULONG leaf; + register cab_UBYTE bit_num = 1; + cab_ULONG fill; + cab_ULONG pos = 0; /* the current position in the decode table */ + cab_ULONG table_mask = 1 << nbits; + cab_ULONG bit_mask = table_mask >> 1; /* don't do 0 length codes */ + cab_ULONG next_symbol = bit_mask; /* base of allocation for long codes */ + + /* fill entries for codes short enough for a direct mapping */ + while (bit_num <= nbits) { + for (sym = 0; sym < nsyms; sym++) { + if (length[sym] == bit_num) { + leaf = pos; + + if((pos += bit_mask) > table_mask) return 1; /* table overrun */ + + /* fill all possible lookups of this symbol with the symbol itself */ + fill = bit_mask; + while (fill-- > 0) table[leaf++] = sym; + } + } + bit_mask >>= 1; + bit_num++; + } + + /* if there are any codes longer than nbits */ + if (pos != table_mask) { + /* clear the remainder of the table */ + for (sym = pos; sym < table_mask; sym++) table[sym] = 0; + + /* give ourselves room for codes to grow by up to 16 more bits */ + pos <<= 16; + table_mask <<= 16; + bit_mask = 1 << 15; + + while (bit_num <= 16) { + for (sym = 0; sym < nsyms; sym++) { + if (length[sym] == bit_num) { + leaf = pos >> 16; + for (fill = 0; fill < bit_num - nbits; fill++) { + /* if this path hasn't been taken yet, 'allocate' two entries */ + if (table[leaf] == 0) { + table[(next_symbol << 1)] = 0; + table[(next_symbol << 1) + 1] = 0; + table[leaf] = next_symbol++; + } + /* follow the path and select either left or right for next bit */ + leaf = table[leaf] << 1; + if ((pos >> (15-fill)) & 1) leaf++; + } + table[leaf] = sym; + + if ((pos += bit_mask) > table_mask) return 1; /* table overflow */ + } + } + bit_mask >>= 1; + bit_num++; + } + } + + /* full table? */ + if (pos == table_mask) return 0; + + /* either erroneous table, or all elements are 0 - let's find out. */ + for (sym = 0; sym < nsyms; sym++) if (length[sym]) return 1; + return 0; +} + +/************************************************************ + * lzx_read_lens (internal) + */ +int lzx_read_lens(cab_UBYTE *lens, cab_ULONG first, cab_ULONG last, struct lzx_bits *lb, + cab_decomp_state *decomp_state) { + cab_ULONG i,j, x,y; + int z; + + register cab_ULONG bitbuf = lb->bb; + register int bitsleft = lb->bl; + cab_UBYTE *inpos = lb->ip; + cab_UWORD *hufftbl; + + for (x = 0; x < 20; x++) { + READ_BITS(y, 4); + LENTABLE(PRETREE)[x] = y; + } + BUILD_TABLE(PRETREE); + + for (x = first; x < last; ) { + READ_HUFFSYM(PRETREE, z); + if (z == 17) { + READ_BITS(y, 4); y += 4; + while (y--) lens[x++] = 0; + } + else if (z == 18) { + READ_BITS(y, 5); y += 20; + while (y--) lens[x++] = 0; + } + else if (z == 19) { + READ_BITS(y, 1); y += 4; + READ_HUFFSYM(PRETREE, z); + z = lens[x] - z; if (z < 0) z += 17; + while (y--) lens[x++] = z; + } + else { + z = lens[x] - z; if (z < 0) z += 17; + lens[x++] = z; + } + } + + lb->bb = bitbuf; + lb->bl = bitsleft; + lb->ip = inpos; + return 0; +} + +/******************************************************* + * LZXdecompress (internal) + */ +int LZXdecompress(int inlen, int outlen, cab_decomp_state *decomp_state) { + cab_UBYTE *inpos = CAB(inbuf); + cab_UBYTE *endinp = inpos + inlen; + cab_UBYTE *window = LZX(window); + cab_UBYTE *runsrc, *rundest; + cab_UWORD *hufftbl; /* used in READ_HUFFSYM macro as chosen decoding table */ + + cab_ULONG window_posn = LZX(window_posn); + cab_ULONG window_size = LZX(window_size); + cab_ULONG R0 = LZX(R0); + cab_ULONG R1 = LZX(R1); + cab_ULONG R2 = LZX(R2); + + register cab_ULONG bitbuf; + register int bitsleft; + cab_ULONG match_offset, i,j,k; /* ijk used in READ_HUFFSYM macro */ + struct lzx_bits lb; /* used in READ_LENGTHS macro */ + + int togo = outlen, this_run, main_element, aligned_bits; + int match_length, copy_length, length_footer, extra, verbatim_bits; + + TRACE("(inlen == %d, outlen == %d)\n", inlen, outlen); + + INIT_BITSTREAM; + + /* read header if necessary */ + if (!LZX(header_read)) { + i = j = 0; + READ_BITS(k, 1); if (k) { READ_BITS(i,16); READ_BITS(j,16); } + LZX(intel_filesize) = (i << 16) | j; /* or 0 if not encoded */ + LZX(header_read) = 1; + } + + /* main decoding loop */ + while (togo > 0) { + /* last block finished, new block expected */ + if (LZX(block_remaining) == 0) { + if (LZX(block_type) == LZX_BLOCKTYPE_UNCOMPRESSED) { + if (LZX(block_length) & 1) inpos++; /* realign bitstream to word */ + INIT_BITSTREAM; + } + + READ_BITS(LZX(block_type), 3); + READ_BITS(i, 16); + READ_BITS(j, 8); + LZX(block_remaining) = LZX(block_length) = (i << 8) | j; + + switch (LZX(block_type)) { + case LZX_BLOCKTYPE_ALIGNED: + for (i = 0; i < 8; i++) { READ_BITS(j, 3); LENTABLE(ALIGNED)[i] = j; } + BUILD_TABLE(ALIGNED); + /* rest of aligned header is same as verbatim */ + + case LZX_BLOCKTYPE_VERBATIM: + READ_LENGTHS(MAINTREE, 0, 256, lzx_read_lens); + READ_LENGTHS(MAINTREE, 256, LZX(main_elements), lzx_read_lens); + BUILD_TABLE(MAINTREE); + if (LENTABLE(MAINTREE)[0xE8] != 0) LZX(intel_started) = 1; + + READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS, lzx_read_lens); + BUILD_TABLE(LENGTH); + break; + + case LZX_BLOCKTYPE_UNCOMPRESSED: + LZX(intel_started) = 1; /* because we can't assume otherwise */ + ENSURE_BITS(16); /* get up to 16 pad bits into the buffer */ + if (bitsleft > 16) inpos -= 2; /* and align the bitstream! */ + R0 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4; + R1 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4; + R2 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4; + break; + + default: + return DECR_ILLEGALDATA; + } + } + + /* buffer exhaustion check */ + if (inpos > endinp) { + /* it's possible to have a file where the next run is less than + * 16 bits in size. In this case, the READ_HUFFSYM() macro used + * in building the tables will exhaust the buffer, so we should + * allow for this, but not allow those accidentally read bits to + * be used (so we check that there are at least 16 bits + * remaining - in this boundary case they aren't really part of + * the compressed data) + */ + if (inpos > (endinp+2) || bitsleft < 16) return DECR_ILLEGALDATA; + } + + while ((this_run = LZX(block_remaining)) > 0 && togo > 0) { + if (this_run > togo) this_run = togo; + togo -= this_run; + LZX(block_remaining) -= this_run; + + /* apply 2^x-1 mask */ + window_posn &= window_size - 1; + /* runs can't straddle the window wraparound */ + if ((window_posn + this_run) > window_size) + return DECR_DATAFORMAT; + + switch (LZX(block_type)) { + + case LZX_BLOCKTYPE_VERBATIM: + while (this_run > 0) { + READ_HUFFSYM(MAINTREE, main_element); + + if (main_element < LZX_NUM_CHARS) { + /* literal: 0 to LZX_NUM_CHARS-1 */ + window[window_posn++] = main_element; + this_run--; + } + else { + /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */ + main_element -= LZX_NUM_CHARS; + + match_length = main_element & LZX_NUM_PRIMARY_LENGTHS; + if (match_length == LZX_NUM_PRIMARY_LENGTHS) { + READ_HUFFSYM(LENGTH, length_footer); + match_length += length_footer; + } + match_length += LZX_MIN_MATCH; + + match_offset = main_element >> 3; + + if (match_offset > 2) { + /* not repeated offset */ + if (match_offset != 3) { + extra = CAB(extra_bits)[match_offset]; + READ_BITS(verbatim_bits, extra); + match_offset = CAB(lzx_position_base)[match_offset] + - 2 + verbatim_bits; + } + else { + match_offset = 1; + } + + /* update repeated offset LRU queue */ + R2 = R1; R1 = R0; R0 = match_offset; + } + else if (match_offset == 0) { + match_offset = R0; + } + else if (match_offset == 1) { + match_offset = R1; + R1 = R0; R0 = match_offset; + } + else /* match_offset == 2 */ { + match_offset = R2; + R2 = R0; R0 = match_offset; + } + + rundest = window + window_posn; + this_run -= match_length; + + /* copy any wrapped around source data */ + if (window_posn >= match_offset) { + /* no wrap */ + runsrc = rundest - match_offset; + } else { + runsrc = rundest + (window_size - match_offset); + copy_length = match_offset - window_posn; + if (copy_length < match_length) { + match_length -= copy_length; + window_posn += copy_length; + while (copy_length-- > 0) *rundest++ = *runsrc++; + runsrc = window; + } + } + window_posn += match_length; + + /* copy match data - no worries about destination wraps */ + while (match_length-- > 0) *rundest++ = *runsrc++; + } + } + break; + + case LZX_BLOCKTYPE_ALIGNED: + while (this_run > 0) { + READ_HUFFSYM(MAINTREE, main_element); + + if (main_element < LZX_NUM_CHARS) { + /* literal: 0 to LZX_NUM_CHARS-1 */ + window[window_posn++] = main_element; + this_run--; + } + else { + /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */ + main_element -= LZX_NUM_CHARS; + + match_length = main_element & LZX_NUM_PRIMARY_LENGTHS; + if (match_length == LZX_NUM_PRIMARY_LENGTHS) { + READ_HUFFSYM(LENGTH, length_footer); + match_length += length_footer; + } + match_length += LZX_MIN_MATCH; + + match_offset = main_element >> 3; + + if (match_offset > 2) { + /* not repeated offset */ + extra = CAB(extra_bits)[match_offset]; + match_offset = CAB(lzx_position_base)[match_offset] - 2; + if (extra > 3) { + /* verbatim and aligned bits */ + extra -= 3; + READ_BITS(verbatim_bits, extra); + match_offset += (verbatim_bits << 3); + READ_HUFFSYM(ALIGNED, aligned_bits); + match_offset += aligned_bits; + } + else if (extra == 3) { + /* aligned bits only */ + READ_HUFFSYM(ALIGNED, aligned_bits); + match_offset += aligned_bits; + } + else if (extra > 0) { /* extra==1, extra==2 */ + /* verbatim bits only */ + READ_BITS(verbatim_bits, extra); + match_offset += verbatim_bits; + } + else /* extra == 0 */ { + /* ??? */ + match_offset = 1; + } + + /* update repeated offset LRU queue */ + R2 = R1; R1 = R0; R0 = match_offset; + } + else if (match_offset == 0) { + match_offset = R0; + } + else if (match_offset == 1) { + match_offset = R1; + R1 = R0; R0 = match_offset; + } + else /* match_offset == 2 */ { + match_offset = R2; + R2 = R0; R0 = match_offset; + } + + rundest = window + window_posn; + this_run -= match_length; + + /* copy any wrapped around source data */ + if (window_posn >= match_offset) { + /* no wrap */ + runsrc = rundest - match_offset; + } else { + runsrc = rundest + (window_size - match_offset); + copy_length = match_offset - window_posn; + if (copy_length < match_length) { + match_length -= copy_length; + window_posn += copy_length; + while (copy_length-- > 0) *rundest++ = *runsrc++; + runsrc = window; + } + } + window_posn += match_length; + + /* copy match data - no worries about destination wraps */ + while (match_length-- > 0) *rundest++ = *runsrc++; + } + } + break; + + case LZX_BLOCKTYPE_UNCOMPRESSED: + if ((inpos + this_run) > endinp) return DECR_ILLEGALDATA; + memcpy(window + window_posn, inpos, (size_t) this_run); + inpos += this_run; window_posn += this_run; + break; + + default: + return DECR_ILLEGALDATA; /* might as well */ + } + + } + } + + if (togo != 0) return DECR_ILLEGALDATA; + memcpy(CAB(outbuf), window + ((!window_posn) ? window_size : window_posn) - + outlen, (size_t) outlen); + + LZX(window_posn) = window_posn; + LZX(R0) = R0; + LZX(R1) = R1; + LZX(R2) = R2; + + /* intel E8 decoding */ + if ((LZX(frames_read)++ < 32768) && LZX(intel_filesize) != 0) { + if (outlen <= 6 || !LZX(intel_started)) { + LZX(intel_curpos) += outlen; + } + else { + cab_UBYTE *data = CAB(outbuf); + cab_UBYTE *dataend = data + outlen - 10; + cab_LONG curpos = LZX(intel_curpos); + cab_LONG filesize = LZX(intel_filesize); + cab_LONG abs_off, rel_off; + + LZX(intel_curpos) = curpos + outlen; + + while (data < dataend) { + if (*data++ != 0xE8) { curpos++; continue; } + abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24); + if ((abs_off >= -curpos) && (abs_off < filesize)) { + rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize; + data[0] = (cab_UBYTE) rel_off; + data[1] = (cab_UBYTE) (rel_off >> 8); + data[2] = (cab_UBYTE) (rel_off >> 16); + data[3] = (cab_UBYTE) (rel_off >> 24); + } + data += 4; + curpos += 5; + } + } + } + return DECR_OK; +} + +/********************************************************* + * find_cabs_in_file (internal) + */ +struct cabinet *find_cabs_in_file(LPCSTR name, cab_UBYTE search_buf[]) +{ + struct cabinet *cab, *cab2, *firstcab = NULL, *linkcab = NULL; + cab_UBYTE *pstart = &search_buf[0], *pend, *p; + cab_off_t offset, caboff, cablen = 0, foffset = 0, filelen, length; + int state = 0, found = 0, ok = 0; + + TRACE("(name == %s)\n", debugstr_a(name)); + + /* open the file and search for cabinet headers */ + if ((cab = (struct cabinet *) calloc(1, sizeof(struct cabinet)))) { + cab->filename = name; + if (cabinet_open(cab)) { + filelen = cab->filelen; + for (offset = 0; (offset < filelen); offset += length) { + /* search length is either the full length of the search buffer, + * or the amount of data remaining to the end of the file, + * whichever is less. + */ + length = filelen - offset; + if (length > CAB_SEARCH_SIZE) length = CAB_SEARCH_SIZE; + + /* fill the search buffer with data from disk */ + if (!cabinet_read(cab, search_buf, length)) break; + + /* read through the entire buffer. */ + p = pstart; + pend = &search_buf[length]; + while (p < pend) { + switch (state) { + /* starting state */ + case 0: + /* we spend most of our time in this while loop, looking for + * a leading 'M' of the 'MSCF' signature + */ + while (*p++ != 0x4D && p < pend); + if (p < pend) state = 1; /* if we found tht 'M', advance state */ + break; + + /* verify that the next 3 bytes are 'S', 'C' and 'F' */ + case 1: state = (*p++ == 0x53) ? 2 : 0; break; + case 2: state = (*p++ == 0x43) ? 3 : 0; break; + case 3: state = (*p++ == 0x46) ? 4 : 0; break; + + /* we don't care about bytes 4-7 */ + /* bytes 8-11 are the overall length of the cabinet */ + case 8: cablen = *p++; state++; break; + case 9: cablen |= *p++ << 8; state++; break; + case 10: cablen |= *p++ << 16; state++; break; + case 11: cablen |= *p++ << 24; state++; break; + + /* we don't care about bytes 12-15 */ + /* bytes 16-19 are the offset within the cabinet of the filedata */ + case 16: foffset = *p++; state++; break; + case 17: foffset |= *p++ << 8; state++; break; + case 18: foffset |= *p++ << 16; state++; break; + case 19: foffset |= *p++ << 24; + /* now we have received 20 bytes of potential cab header. */ + /* work out the offset in the file of this potential cabinet */ + caboff = offset + (p-pstart) - 20; + + /* check that the files offset is less than the alleged length + * of the cabinet, and that the offset + the alleged length are + * 'roughly' within the end of overall file length + */ + if ((foffset < cablen) && + ((caboff + foffset) < (filelen + 32)) && + ((caboff + cablen) < (filelen + 32)) ) + { + /* found a potential result - try loading it */ + found++; + cab2 = load_cab_offset(name, caboff); + if (cab2) { + /* success */ + ok++; + + /* cause the search to restart after this cab's data. */ + offset = caboff + cablen; + if (offset < cab->filelen) cabinet_seek(cab, offset); + length = 0; + p = pend; + + /* link the cab into the list */ + if (linkcab == NULL) firstcab = cab2; + else linkcab->next = cab2; + linkcab = cab2; + } + } + state = 0; + break; + default: + p++, state++; break; + } + } + } + cabinet_close(cab); + } + free(cab); + } + + /* if there were cabinets that were found but are not ok, point this out */ + if (found > ok) { + WARN("%s: found %d bad cabinets\n", debugstr_a(name), found-ok); + } + + /* if no cabinets were found, let the user know */ + if (!firstcab) { + WARN("%s: not a Microsoft cabinet file.\n", debugstr_a(name)); + } + return firstcab; +} + +/*********************************************************************** + * find_cabinet_file (internal) + * + * tries to find *cabname, from the directory path of origcab, correcting the + * case of *cabname if necessary, If found, writes back to *cabname. + */ +void find_cabinet_file(char **cabname, LPCSTR origcab) { + + char *tail, *cab, *name, *nextpart, nametmp[MAX_PATH]; + int found = 0; + + TRACE("(*cabname == ^%p, origcab == %s)\n", cabname ? *cabname : NULL, debugstr_a(origcab)); + + /* ensure we have a cabinet name at all */ + if (!(name = *cabname)) { + WARN("no cabinet name at all\n"); + } + + /* find if there's a directory path in the origcab */ + tail = origcab ? max(strrchr(origcab, '/'), strrchr(origcab, '\\')) : NULL; + + if ((cab = (char *) malloc(MAX_PATH))) { + /* add the directory path from the original cabinet name */ + if (tail) { + memcpy(cab, origcab, tail - origcab); + cab[tail - origcab] = '\0'; + } else { + /* default directory path of '.' */ + cab[0] = '.'; + cab[1] = '\0'; + } + + do { + TRACE("trying cab == %s\n", debugstr_a(cab)); + + /* we don't want null cabinet filenames */ + if (name[0] == '\0') { + WARN("null cab name\n"); + break; + } + + /* if there is a directory component in the cabinet name, + * look for that alone first + */ + nextpart = strchr(name, '\\'); + if (nextpart) *nextpart = '\0'; + + found = SearchPathA(cab, name, NULL, MAX_PATH, nametmp, NULL); + + /* if the component was not found, look for it in the current dir */ + if (!found) { + found = SearchPathA(".", name, NULL, MAX_PATH, nametmp, NULL); + } + + if (found) + TRACE("found: %s\n", debugstr_a(nametmp)); + else + TRACE("not found.\n"); + + /* restore the real name and skip to the next directory component + * or actual cabinet name + */ + if (nextpart) *nextpart = '\\', name = &nextpart[1]; + + /* while there is another directory component, and while we + * successfully found the current component + */ + } while (nextpart && found); + + /* if we found the cabinet, change the next cabinet's name. + * otherwise, pretend nothing happened + */ + if (found) { + free((void *) *cabname); + *cabname = cab; + memcpy(cab, nametmp, found+1); + TRACE("result: %s\n", debugstr_a(cab)); + } else { + free((void *) cab); + TRACE("result: nothing\n"); + } + } +} + +/************************************************************************ + * process_files (internal) + * + * this does the tricky job of running through every file in the cabinet, + * including spanning cabinets, and working out which file is in which + * folder in which cabinet. It also throws out the duplicate file entries + * that appear in spanning cabinets. There is memory leakage here because + * those entries are not freed. See the XAD CAB client (function CAB_GetInfo + * in CAB.c) for an implementation of this that correctly frees the discarded + * file entries. + */ +struct cab_file *process_files(struct cabinet *basecab) { + struct cabinet *cab; + struct cab_file *outfi = NULL, *linkfi = NULL, *nextfi, *fi, *cfi; + struct cab_folder *fol, *firstfol, *lastfol = NULL, *predfol; + int i, mergeok; + + FIXME("(basecab == ^%p): Memory leak.\n", basecab); + + for (cab = basecab; cab; cab = cab->nextcab) { + /* firstfol = first folder in this cabinet */ + /* lastfol = last folder in this cabinet */ + /* predfol = last folder in previous cabinet (or NULL if first cabinet) */ + predfol = lastfol; + firstfol = cab->folders; + for (lastfol = firstfol; lastfol->next;) lastfol = lastfol->next; + mergeok = 1; + + for (fi = cab->files; fi; fi = nextfi) { + i = fi->index; + nextfi = fi->next; + + if (i < cffileCONTINUED_FROM_PREV) { + for (fol = firstfol; fol && i--; ) fol = fol->next; + fi->folder = fol; /* NULL if an invalid folder index */ + } + else { + /* folder merging */ + if (i == cffileCONTINUED_TO_NEXT + || i == cffileCONTINUED_PREV_AND_NEXT) { + if (cab->nextcab && !lastfol->contfile) lastfol->contfile = fi; + } + + if (i == cffileCONTINUED_FROM_PREV + || i == cffileCONTINUED_PREV_AND_NEXT) { + /* these files are to be continued in yet another + * cabinet, don't merge them in just yet */ + if (i == cffileCONTINUED_PREV_AND_NEXT) mergeok = 0; + + /* only merge once per cabinet */ + if (predfol) { + if ((cfi = predfol->contfile) + && (cfi->offset == fi->offset) + && (cfi->length == fi->length) + && (strcmp(cfi->filename, fi->filename) == 0) + && (predfol->comp_type == firstfol->comp_type)) { + /* increase the number of splits */ + if ((i = ++(predfol->num_splits)) > CAB_SPLITMAX) { + mergeok = 0; + ERR("%s: internal error: CAB_SPLITMAX exceeded. please report this to wine-devel@winehq.org)\n", + debugstr_a(basecab->filename)); + } + else { + /* copy information across from the merged folder */ + predfol->offset[i] = firstfol->offset[0]; + predfol->cab[i] = firstfol->cab[0]; + predfol->next = firstfol->next; + predfol->contfile = firstfol->contfile; + + if (firstfol == lastfol) lastfol = predfol; + firstfol = predfol; + predfol = NULL; /* don't merge again within this cabinet */ + } + } + else { + /* if the folders won't merge, don't add their files */ + mergeok = 0; + } + } + + if (mergeok) fi->folder = firstfol; + } + } + + if (fi->folder) { + if (linkfi) linkfi->next = fi; else outfi = fi; + linkfi = fi; + } + } /* for (fi= .. */ + } /* for (cab= ...*/ + + return outfi; +} + +/**************************************************************** + * convertUTF (internal) + * + * translate UTF -> ASCII + * + * UTF translates two-byte unicode characters into 1, 2 or 3 bytes. + * %000000000xxxxxxx -> %0xxxxxxx + * %00000xxxxxyyyyyy -> %110xxxxx %10yyyyyy + * %xxxxyyyyyyzzzzzz -> %1110xxxx %10yyyyyy %10zzzzzz + * + * Therefore, the inverse is as follows: + * First char: + * 0x00 - 0x7F = one byte char + * 0x80 - 0xBF = invalid + * 0xC0 - 0xDF = 2 byte char (next char only 0x80-0xBF is valid) + * 0xE0 - 0xEF = 3 byte char (next 2 chars only 0x80-0xBF is valid) + * 0xF0 - 0xFF = invalid + * + * FIXME: use a winapi to do this + */ +int convertUTF(cab_UBYTE *in) { + cab_UBYTE c, *out = in, *end = in + strlen((char *) in) + 1; + cab_ULONG x; + + do { + /* read unicode character */ + if ((c = *in++) < 0x80) x = c; + else { + if (c < 0xC0) return 0; + else if (c < 0xE0) { + x = (c & 0x1F) << 6; + if ((c = *in++) < 0x80 || c > 0xBF) return 0; else x |= (c & 0x3F); + } + else if (c < 0xF0) { + x = (c & 0xF) << 12; + if ((c = *in++) < 0x80 || c > 0xBF) return 0; else x |= (c & 0x3F)<<6; + if ((c = *in++) < 0x80 || c > 0xBF) return 0; else x |= (c & 0x3F); + } + else return 0; + } + + /* terrible unicode -> ASCII conversion */ + if (x > 127) x = '_'; + + if (in > end) return 0; /* just in case */ + } while ((*out++ = (cab_UBYTE) x)); + return 1; +} + +/**************************************************** + * NONEdecompress (internal) + */ +int NONEdecompress(int inlen, int outlen, cab_decomp_state *decomp_state) +{ + if (inlen != outlen) return DECR_ILLEGALDATA; + memcpy(CAB(outbuf), CAB(inbuf), (size_t) inlen); + return DECR_OK; +} + +/************************************************** + * checksum (internal) + */ +cab_ULONG checksum(cab_UBYTE *data, cab_UWORD bytes, cab_ULONG csum) { + int len; + cab_ULONG ul = 0; + + for (len = bytes >> 2; len--; data += 4) { + csum ^= ((data[0]) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24)); + } + + switch (bytes & 3) { + case 3: ul |= *data++ << 16; + case 2: ul |= *data++ << 8; + case 1: ul |= *data; + } + csum ^= ul; + + return csum; +} + +/********************************************************** + * decompress (internal) + */ +int decompress(struct cab_file *fi, int savemode, int fix, cab_decomp_state *decomp_state) +{ + cab_ULONG bytes = savemode ? fi->length : fi->offset - CAB(offset); + struct cabinet *cab = CAB(current)->cab[CAB(split)]; + cab_UBYTE buf[cfdata_SIZEOF], *data; + cab_UWORD inlen, len, outlen, cando; + cab_ULONG cksum; + cab_LONG err; + + TRACE("(fi == ^%p, savemode == %d, fix == %d)\n", fi, savemode, fix); + + while (bytes > 0) { + /* cando = the max number of bytes we can do */ + cando = CAB(outlen); + if (cando > bytes) cando = bytes; + + /* if cando != 0 */ + if (cando && savemode) + file_write(fi, CAB(outpos), cando); + + CAB(outpos) += cando; + CAB(outlen) -= cando; + bytes -= cando; if (!bytes) break; + + /* we only get here if we emptied the output buffer */ + + /* read data header + data */ + inlen = outlen = 0; + while (outlen == 0) { + /* read the block header, skip the reserved part */ + if (!cabinet_read(cab, buf, cfdata_SIZEOF)) return DECR_INPUT; + cabinet_skip(cab, cab->block_resv); + + /* we shouldn't get blocks over CAB_INPUTMAX in size */ + data = CAB(inbuf) + inlen; + len = EndGetI16(buf+cfdata_CompressedSize); + inlen += len; + if (inlen > CAB_INPUTMAX) return DECR_INPUT; + if (!cabinet_read(cab, data, len)) return DECR_INPUT; + + /* clear two bytes after read-in data */ + data[len+1] = data[len+2] = 0; + + /* perform checksum test on the block (if one is stored) */ + cksum = EndGetI32(buf+cfdata_CheckSum); + if (cksum && cksum != checksum(buf+4, 4, checksum(data, len, 0))) { + /* checksum is wrong */ + if (fix && ((fi->folder->comp_type & cffoldCOMPTYPE_MASK) + == cffoldCOMPTYPE_MSZIP)) + { + WARN("%s: checksum failed\n", debugstr_a(fi->filename)); + } + else { + return DECR_CHECKSUM; + } + } + + /* outlen=0 means this block was part of a split block */ + outlen = EndGetI16(buf+cfdata_UncompressedSize); + if (outlen == 0) { + cabinet_close(cab); + cab = CAB(current)->cab[++CAB(split)]; + if (!cabinet_open(cab)) return DECR_INPUT; + cabinet_seek(cab, CAB(current)->offset[CAB(split)]); + } + } + + /* decompress block */ + if ((err = CAB(decompress)(inlen, outlen, decomp_state))) { + if (fix && ((fi->folder->comp_type & cffoldCOMPTYPE_MASK) + == cffoldCOMPTYPE_MSZIP)) + { + ERR("%s: failed decrunching block\n", debugstr_a(fi->filename)); + } + else { + return err; + } + } + CAB(outlen) = outlen; + CAB(outpos) = CAB(outbuf); + } + + return DECR_OK; +} + +/**************************************************************** + * extract_file (internal) + * + * workhorse to extract a particular file from a cab + */ +void extract_file(struct cab_file *fi, int lower, int fix, LPCSTR dir, cab_decomp_state *decomp_state) +{ + struct cab_folder *fol = fi->folder, *oldfol = CAB(current); + cab_LONG err = DECR_OK; + + TRACE("(fi == ^%p, lower == %d, fix == %d, dir == %s)\n", fi, lower, fix, debugstr_a(dir)); + + /* is a change of folder needed? do we need to reset the current folder? */ + if (fol != oldfol || fi->offset < CAB(offset)) { + cab_UWORD comptype = fol->comp_type; + int ct1 = comptype & cffoldCOMPTYPE_MASK; + int ct2 = oldfol ? (oldfol->comp_type & cffoldCOMPTYPE_MASK) : 0; + + /* if the archiver has changed, call the old archiver's free() function */ + if (ct1 != ct2) { + switch (ct2) { + case cffoldCOMPTYPE_LZX: + if (LZX(window)) { + free(LZX(window)); + LZX(window) = NULL; + } + break; + case cffoldCOMPTYPE_QUANTUM: + if (QTM(window)) { + free(QTM(window)); + QTM(window) = NULL; + } + break; + } + } + + switch (ct1) { + case cffoldCOMPTYPE_NONE: + CAB(decompress) = NONEdecompress; + break; + + case cffoldCOMPTYPE_MSZIP: + CAB(decompress) = ZIPdecompress; + break; + + case cffoldCOMPTYPE_QUANTUM: + CAB(decompress) = QTMdecompress; + err = QTMinit((comptype >> 8) & 0x1f, (comptype >> 4) & 0xF, decomp_state); + break; + + case cffoldCOMPTYPE_LZX: + CAB(decompress) = LZXdecompress; + err = LZXinit((comptype >> 8) & 0x1f, decomp_state); + break; + + default: + err = DECR_DATAFORMAT; + } + if (err) goto exit_handler; + + /* initialisation OK, set current folder and reset offset */ + if (oldfol) cabinet_close(oldfol->cab[CAB(split)]); + if (!cabinet_open(fol->cab[0])) goto exit_handler; + cabinet_seek(fol->cab[0], fol->offset[0]); + CAB(current) = fol; + CAB(offset) = 0; + CAB(outlen) = 0; /* discard existing block */ + CAB(split) = 0; + } + + if (fi->offset > CAB(offset)) { + /* decode bytes and send them to /dev/null */ + if ((err = decompress(fi, 0, fix, decomp_state))) goto exit_handler; + CAB(offset) = fi->offset; + } + + if (!file_open(fi, lower, dir)) return; + err = decompress(fi, 1, fix, decomp_state); + if (err) CAB(current) = NULL; else CAB(offset) += fi->length; + file_close(fi); + +exit_handler: + if (err) { + const char *errmsg; + const char *cabname; + switch (err) { + case DECR_NOMEMORY: + errmsg = "out of memory!\n"; break; + case DECR_ILLEGALDATA: + errmsg = "%s: illegal or corrupt data\n"; break; + case DECR_DATAFORMAT: + errmsg = "%s: unsupported data format\n"; break; + case DECR_CHECKSUM: + errmsg = "%s: checksum error\n"; break; + case DECR_INPUT: + errmsg = "%s: input error\n"; break; + case DECR_OUTPUT: + errmsg = "%s: output error\n"; break; + default: + errmsg = "%s: unknown error (BUG)\n"; + } + + if (CAB(current)) { + cabname = (CAB(current)->cab[CAB(split)]->filename); + } + else { + cabname = (fi->folder->cab[0]->filename); + } + + ERR((char *)errmsg, cabname); + } +} + +/********************************************************* + * print_fileinfo (internal) + */ +void print_fileinfo(struct cab_file *fi) { + char *fname = NULL; + + if (fi->attribs & cffile_A_NAME_IS_UTF) { + fname = malloc(strlen(fi->filename) + 1); + if (fname) { + strcpy(fname, fi->filename); + convertUTF((cab_UBYTE *) fname); + } + } + + TRACE("%9u | %02d.%02d.%04d %02d:%02d:%02d | %s\n", + fi->length, + fi->date & 0x1f, (fi->date>>5) & 0xf, (fi->date>>9) + 1980, + fi->time >> 11, (fi->time>>5) & 0x3f, (fi->time << 1) & 0x3e, + fname ? fname : fi->filename + ); + + if (fname) free(fname); +} + +/**************************************************************************** + * process_cabinet (internal) + * + * called to simply "extract" a cabinet file. Will find every cabinet file + * in that file, search for every chained cabinet attached to those cabinets, + * and will either extract the cabinets, or ? (call a callback?) + * + * PARAMS + * cabname [I] name of the cabinet file to extract + * dir [I] directory to extract to + * fix [I] attempt to process broken cabinets + * lower [I] ? (lower case something or other?) + * dest [O] + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL process_cabinet(LPCSTR cabname, LPCSTR dir, BOOL fix, BOOL lower, EXTRACTdest *dest) +{ + struct cabinet *basecab, *cab, *cab1, *cab2; + struct cab_file *filelist, *fi; + struct ExtractFileList **destlistptr = &(dest->filelist); + + /* The first result of a search will be returned, and + * the remaining results will be chained to it via the cab->next structure + * member. + */ + cab_UBYTE search_buf[CAB_SEARCH_SIZE]; + + cab_decomp_state decomp_state_local; + cab_decomp_state *decomp_state = &decomp_state_local; + + /* has the list-mode header been seen before? */ + int viewhdr = 0; + + ZeroMemory(decomp_state, sizeof(cab_decomp_state)); + + TRACE("Extract %s\n", debugstr_a(cabname)); + + /* load the file requested */ + basecab = find_cabs_in_file(cabname, search_buf); + if (!basecab) return FALSE; + + /* iterate over all cabinets found in that file */ + for (cab = basecab; cab; cab=cab->next) { + + /* bi-directionally load any spanning cabinets -- backwards */ + for (cab1 = cab; cab1->flags & cfheadPREV_CABINET; cab1 = cab1->prevcab) { + TRACE("%s: extends backwards to %s (%s)\n", debugstr_a(cabname), + debugstr_a(cab1->prevname), debugstr_a(cab1->previnfo)); + find_cabinet_file(&(cab1->prevname), cabname); + if (!(cab1->prevcab = load_cab_offset(cab1->prevname, 0))) { + ERR("%s: can't read previous cabinet %s\n", debugstr_a(cabname), debugstr_a(cab1->prevname)); + break; + } + cab1->prevcab->nextcab = cab1; + } + + /* bi-directionally load any spanning cabinets -- forwards */ + for (cab2 = cab; cab2->flags & cfheadNEXT_CABINET; cab2 = cab2->nextcab) { + TRACE("%s: extends to %s (%s)\n", debugstr_a(cabname), + debugstr_a(cab2->nextname), debugstr_a(cab2->nextinfo)); + find_cabinet_file(&(cab2->nextname), cabname); + if (!(cab2->nextcab = load_cab_offset(cab2->nextname, 0))) { + ERR("%s: can't read next cabinet %s\n", debugstr_a(cabname), debugstr_a(cab2->nextname)); + break; + } + cab2->nextcab->prevcab = cab2; + } + + filelist = process_files(cab1); + CAB(current) = NULL; + + if (!viewhdr) { + TRACE("File size | Date Time | Name\n"); + TRACE("----------+---------------------+-------------\n"); + viewhdr = 1; + } + for (fi = filelist; fi; fi = fi->next) { + print_fileinfo(fi); + dest->filecount++; + } + TRACE("Beginning Extraction...\n"); + for (fi = filelist; fi; fi = fi->next) { + TRACE(" extracting: %s\n", debugstr_a(fi->filename)); + extract_file(fi, lower, fix, dir, decomp_state); + sprintf(dest->lastfile, "%s%s%s", + strlen(dest->directory) ? dest->directory : "", + strlen(dest->directory) ? "\\": "", + fi->filename); + *destlistptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(struct ExtractFileList)); + if(*destlistptr) { + (*destlistptr)->unknown = TRUE; /* FIXME: were do we get the value? */ + (*destlistptr)->filename = HeapAlloc(GetProcessHeap(), 0, ( + strlen(fi->filename)+1)); + if((*destlistptr)->filename) + lstrcpyA((*destlistptr)->filename, fi->filename); + destlistptr = &((*destlistptr)->next); + } + } + } + + TRACE("Finished processing cabinet.\n"); + + return TRUE; +} diff --git a/reactos/lib/cabinet/cabinet.h b/reactos/lib/cabinet/cabinet.h index 7e3f1ae014e..bb18ae097ff 100644 --- a/reactos/lib/cabinet/cabinet.h +++ b/reactos/lib/cabinet/cabinet.h @@ -1,640 +1,640 @@ -/* - * cabinet.h - * - * Copyright 2002 Greg Turner - * Copyright 2005 Gerold Jens Wucherpfennig - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __WINE_CABINET_H -#define __WINE_CABINET_H - -#include - -#include "windef.h" -#include "winbase.h" -#include "winnt.h" -#include "fdi.h" -#include "fci.h" - -/* from msvcrt/sys/stat.h */ -#define _S_IWRITE 0x0080 -#define _S_IREAD 0x0100 - -#define CAB_SPLITMAX (10) - -#define CAB_SEARCH_SIZE (32*1024) - -typedef unsigned char cab_UBYTE; /* 8 bits */ -typedef UINT16 cab_UWORD; /* 16 bits */ -typedef UINT32 cab_ULONG; /* 32 bits */ -typedef INT32 cab_LONG; /* 32 bits */ - -typedef UINT32 cab_off_t; - -/* number of bits in a ULONG */ -#ifndef CHAR_BIT -# define CHAR_BIT (8) -#endif -#define CAB_ULONG_BITS (sizeof(cab_ULONG) * CHAR_BIT) - -/* structure offsets */ -#define cfhead_Signature (0x00) -#define cfhead_CabinetSize (0x08) -#define cfhead_FileOffset (0x10) -#define cfhead_MinorVersion (0x18) -#define cfhead_MajorVersion (0x19) -#define cfhead_NumFolders (0x1A) -#define cfhead_NumFiles (0x1C) -#define cfhead_Flags (0x1E) -#define cfhead_SetID (0x20) -#define cfhead_CabinetIndex (0x22) -#define cfhead_SIZEOF (0x24) -#define cfheadext_HeaderReserved (0x00) -#define cfheadext_FolderReserved (0x02) -#define cfheadext_DataReserved (0x03) -#define cfheadext_SIZEOF (0x04) -#define cffold_DataOffset (0x00) -#define cffold_NumBlocks (0x04) -#define cffold_CompType (0x06) -#define cffold_SIZEOF (0x08) -#define cffile_UncompressedSize (0x00) -#define cffile_FolderOffset (0x04) -#define cffile_FolderIndex (0x08) -#define cffile_Date (0x0A) -#define cffile_Time (0x0C) -#define cffile_Attribs (0x0E) -#define cffile_SIZEOF (0x10) -#define cfdata_CheckSum (0x00) -#define cfdata_CompressedSize (0x04) -#define cfdata_UncompressedSize (0x06) -#define cfdata_SIZEOF (0x08) - -/* flags */ -#define cffoldCOMPTYPE_MASK (0x000f) -#define cffoldCOMPTYPE_NONE (0x0000) -#define cffoldCOMPTYPE_MSZIP (0x0001) -#define cffoldCOMPTYPE_QUANTUM (0x0002) -#define cffoldCOMPTYPE_LZX (0x0003) -#define cfheadPREV_CABINET (0x0001) -#define cfheadNEXT_CABINET (0x0002) -#define cfheadRESERVE_PRESENT (0x0004) -#define cffileCONTINUED_FROM_PREV (0xFFFD) -#define cffileCONTINUED_TO_NEXT (0xFFFE) -#define cffileCONTINUED_PREV_AND_NEXT (0xFFFF) -#define cffile_A_RDONLY (0x01) -#define cffile_A_HIDDEN (0x02) -#define cffile_A_SYSTEM (0x04) -#define cffile_A_ARCH (0x20) -#define cffile_A_EXEC (0x40) -#define cffile_A_NAME_IS_UTF (0x80) - -/****************************************************************************/ -/* our archiver information / state */ - -/* MSZIP stuff */ -#define ZIPWSIZE 0x8000 /* window size */ -#define ZIPLBITS 9 /* bits in base literal/length lookup table */ -#define ZIPDBITS 6 /* bits in base distance lookup table */ -#define ZIPBMAX 16 /* maximum bit length of any code */ -#define ZIPN_MAX 288 /* maximum number of codes in any set */ - -struct Ziphuft { - cab_UBYTE e; /* number of extra bits or operation */ - cab_UBYTE b; /* number of bits in this code or subcode */ - union { - cab_UWORD n; /* literal, length base, or distance base */ - struct Ziphuft *t; /* pointer to next level of table */ - } v; -}; - -struct ZIPstate { - cab_ULONG window_posn; /* current offset within the window */ - cab_ULONG bb; /* bit buffer */ - cab_ULONG bk; /* bits in bit buffer */ - cab_ULONG ll[288+32]; /* literal/length and distance code lengths */ - cab_ULONG c[ZIPBMAX+1]; /* bit length count table */ - cab_LONG lx[ZIPBMAX+1]; /* memory for l[-1..ZIPBMAX-1] */ - struct Ziphuft *u[ZIPBMAX]; /* table stack */ - cab_ULONG v[ZIPN_MAX]; /* values in order of bit length */ - cab_ULONG x[ZIPBMAX+1]; /* bit offsets, then code stack */ - cab_UBYTE *inpos; -}; - -/* Quantum stuff */ - -struct QTMmodelsym { - cab_UWORD sym, cumfreq; -}; - -struct QTMmodel { - int shiftsleft, entries; - struct QTMmodelsym *syms; - cab_UWORD tabloc[256]; -}; - -struct QTMstate { - cab_UBYTE *window; /* the actual decoding window */ - cab_ULONG window_size; /* window size (1Kb through 2Mb) */ - cab_ULONG actual_size; /* window size when it was first allocated */ - cab_ULONG window_posn; /* current offset within the window */ - - struct QTMmodel model7; - struct QTMmodelsym m7sym[7+1]; - - struct QTMmodel model4, model5, model6pos, model6len; - struct QTMmodelsym m4sym[0x18 + 1]; - struct QTMmodelsym m5sym[0x24 + 1]; - struct QTMmodelsym m6psym[0x2a + 1], m6lsym[0x1b + 1]; - - struct QTMmodel model00, model40, model80, modelC0; - struct QTMmodelsym m00sym[0x40 + 1], m40sym[0x40 + 1]; - struct QTMmodelsym m80sym[0x40 + 1], mC0sym[0x40 + 1]; -}; - -/* LZX stuff */ - -/* some constants defined by the LZX specification */ -#define LZX_MIN_MATCH (2) -#define LZX_MAX_MATCH (257) -#define LZX_NUM_CHARS (256) -#define LZX_BLOCKTYPE_INVALID (0) /* also blocktypes 4-7 invalid */ -#define LZX_BLOCKTYPE_VERBATIM (1) -#define LZX_BLOCKTYPE_ALIGNED (2) -#define LZX_BLOCKTYPE_UNCOMPRESSED (3) -#define LZX_PRETREE_NUM_ELEMENTS (20) -#define LZX_ALIGNED_NUM_ELEMENTS (8) /* aligned offset tree #elements */ -#define LZX_NUM_PRIMARY_LENGTHS (7) /* this one missing from spec! */ -#define LZX_NUM_SECONDARY_LENGTHS (249) /* length tree #elements */ - -/* LZX huffman defines: tweak tablebits as desired */ -#define LZX_PRETREE_MAXSYMBOLS (LZX_PRETREE_NUM_ELEMENTS) -#define LZX_PRETREE_TABLEBITS (6) -#define LZX_MAINTREE_MAXSYMBOLS (LZX_NUM_CHARS + 50*8) -#define LZX_MAINTREE_TABLEBITS (12) -#define LZX_LENGTH_MAXSYMBOLS (LZX_NUM_SECONDARY_LENGTHS+1) -#define LZX_LENGTH_TABLEBITS (12) -#define LZX_ALIGNED_MAXSYMBOLS (LZX_ALIGNED_NUM_ELEMENTS) -#define LZX_ALIGNED_TABLEBITS (7) - -#define LZX_LENTABLE_SAFETY (64) /* we allow length table decoding overruns */ - -#define LZX_DECLARE_TABLE(tbl) \ - cab_UWORD tbl##_table[(1<pfnalloc) (size)) -#define PFCI_FREE(hfdi, ptr) ((*PFCI_INT(hfdi)->pfnfree) (ptr)) -#define PFCI_GETTEMPFILE(hfci,name,length) ((*PFCI_INT(hfci)->pfnfcigtf)(name,length,PFCI_INT(hfci)->pv)) -#define PFCI_DELETE(hfci,name,err,pv) ((*PFCI_INT(hfci)->pfndelete)(name,err,pv)) -#define PFCI_OPEN(hfci,name,oflag,pmode,err,pv) ((*PFCI_INT(hfci)->pfnopen)(name,oflag,pmode,err,pv)) -#define PFCI_READ(hfci,hf,memory,cb,err,pv)((*PFCI_INT(hfci)->pfnread)(hf,memory,cb,err,pv)) -#define PFCI_WRITE(hfci,hf,memory,cb,err,pv) ((*PFCI_INT(hfci)->pfnwrite)(hf,memory,cb,err,pv)) -#define PFCI_CLOSE(hfci,hf,err,pv) ((*PFCI_INT(hfci)->pfnclose)(hf,err,pv)) -#define PFCI_SEEK(hfci,hf,dist,seektype,err,pv)((*PFCI_INT(hfci)->pfnseek)(hf,dist,seektype,err,pv)) -#define PFCI_FILEPLACED(hfci,pccab,name,cb,cont,pv)((*PFCI_INT(hfci)->pfnfiledest)(pccab,name,cb,cont,pv)) - -/* quickie pfdi method invokers */ -#define PFDI_ALLOC(hfdi, size) ((*PFDI_INT(hfdi)->pfnalloc) (size)) -#define PFDI_FREE(hfdi, ptr) ((*PFDI_INT(hfdi)->pfnfree) (ptr)) -#define PFDI_OPEN(hfdi, file, flag, mode) ((*PFDI_INT(hfdi)->pfnopen) (file, flag, mode)) -#define PFDI_READ(hfdi, hf, pv, cb) ((*PFDI_INT(hfdi)->pfnread) (hf, pv, cb)) -#define PFDI_WRITE(hfdi, hf, pv, cb) ((*PFDI_INT(hfdi)->pfnwrite) (hf, pv, cb)) -#define PFDI_CLOSE(hfdi, hf) ((*PFDI_INT(hfdi)->pfnclose) (hf)) -#define PFDI_SEEK(hfdi, hf, dist, type) ((*PFDI_INT(hfdi)->pfnseek) (hf, dist, type)) - -#define FCI_INT_MAGIC 0xfcfcfc05 -#define FDI_INT_MAGIC 0xfdfdfd05 - -#define REALLY_IS_FCI(hfci) ( \ - (((void *) hfci) != NULL) && \ - (PFCI_INT(hfci)->FCI_Intmagic == FCI_INT_MAGIC) ) - -#define REALLY_IS_FDI(hfdi) ( \ - (((void *) hfdi) != NULL) && \ - (PFDI_INT(hfdi)->FDI_Intmagic == FDI_INT_MAGIC) ) - -/* - * the rest of these are somewhat kludgy macros which are shared between fdi.c - * and cabextract.c. - */ - -#define ZIPNEEDBITS(n) {while(k<(n)){cab_LONG c=*(ZIP(inpos)++);\ - b|=((cab_ULONG)c)<>=(n);k-=(n);} - -/* endian-neutral reading of little-endian data */ -#define EndGetI32(a) ((((a)[3])<<24)|(((a)[2])<<16)|(((a)[1])<<8)|((a)[0])) -#define EndGetI16(a) ((((a)[1])<<8)|((a)[0])) - -#define CAB(x) (decomp_state->x) -#define ZIP(x) (decomp_state->methods.zip.x) -#define QTM(x) (decomp_state->methods.qtm.x) -#define LZX(x) (decomp_state->methods.lzx.x) -#define DECR_OK (0) -#define DECR_DATAFORMAT (1) -#define DECR_ILLEGALDATA (2) -#define DECR_NOMEMORY (3) -#define DECR_CHECKSUM (4) -#define DECR_INPUT (5) -#define DECR_OUTPUT (6) -#define DECR_USERABORT (7) - -/* Bitstream reading macros (Quantum / normal byte order) - * - * Q_INIT_BITSTREAM should be used first to set up the system - * Q_READ_BITS(var,n) takes N bits from the buffer and puts them in var. - * unlike LZX, this can loop several times to get the - * requisite number of bits. - * Q_FILL_BUFFER adds more data to the bit buffer, if there is room - * for another 16 bits. - * Q_PEEK_BITS(n) extracts (without removing) N bits from the bit - * buffer - * Q_REMOVE_BITS(n) removes N bits from the bit buffer - * - * These bit access routines work by using the area beyond the MSB and the - * LSB as a free source of zeroes. This avoids having to mask any bits. - * So we have to know the bit width of the bitbuffer variable. This is - * defined as ULONG_BITS. - * - * ULONG_BITS should be at least 16 bits. Unlike LZX's Huffman decoding, - * Quantum's arithmetic decoding only needs 1 bit at a time, it doesn't - * need an assured number. Retrieving larger bitstrings can be done with - * multiple reads and fills of the bitbuffer. The code should work fine - * for machines where ULONG >= 32 bits. - * - * Also note that Quantum reads bytes in normal order; LZX is in - * little-endian order. - */ - -#define Q_INIT_BITSTREAM do { bitsleft = 0; bitbuf = 0; } while (0) - -#define Q_FILL_BUFFER do { \ - if (bitsleft <= (CAB_ULONG_BITS - 16)) { \ - bitbuf |= ((inpos[0]<<8)|inpos[1]) << (CAB_ULONG_BITS-16 - bitsleft); \ - bitsleft += 16; inpos += 2; \ - } \ -} while (0) - -#define Q_PEEK_BITS(n) (bitbuf >> (CAB_ULONG_BITS - (n))) -#define Q_REMOVE_BITS(n) ((bitbuf <<= (n)), (bitsleft -= (n))) - -#define Q_READ_BITS(v,n) do { \ - (v) = 0; \ - for (bitsneed = (n); bitsneed; bitsneed -= bitrun) { \ - Q_FILL_BUFFER; \ - bitrun = (bitsneed > bitsleft) ? bitsleft : bitsneed; \ - (v) = ((v) << bitrun) | Q_PEEK_BITS(bitrun); \ - Q_REMOVE_BITS(bitrun); \ - } \ -} while (0) - -#define Q_MENTRIES(model) (QTM(model).entries) -#define Q_MSYM(model,symidx) (QTM(model).syms[(symidx)].sym) -#define Q_MSYMFREQ(model,symidx) (QTM(model).syms[(symidx)].cumfreq) - -/* GET_SYMBOL(model, var) fetches the next symbol from the stated model - * and puts it in var. it may need to read the bitstream to do this. - */ -#define GET_SYMBOL(m, var) do { \ - range = ((H - L) & 0xFFFF) + 1; \ - symf = ((((C - L + 1) * Q_MSYMFREQ(m,0)) - 1) / range) & 0xFFFF; \ - \ - for (i=1; i < Q_MENTRIES(m); i++) { \ - if (Q_MSYMFREQ(m,i) <= symf) break; \ - } \ - (var) = Q_MSYM(m,i-1); \ - \ - range = (H - L) + 1; \ - H = L + ((Q_MSYMFREQ(m,i-1) * range) / Q_MSYMFREQ(m,0)) - 1; \ - L = L + ((Q_MSYMFREQ(m,i) * range) / Q_MSYMFREQ(m,0)); \ - while (1) { \ - if ((L & 0x8000) != (H & 0x8000)) { \ - if ((L & 0x4000) && !(H & 0x4000)) { \ - /* underflow case */ \ - C ^= 0x4000; L &= 0x3FFF; H |= 0x4000; \ - } \ - else break; \ - } \ - L <<= 1; H = (H << 1) | 1; \ - Q_FILL_BUFFER; \ - C = (C << 1) | Q_PEEK_BITS(1); \ - Q_REMOVE_BITS(1); \ - } \ - \ - QTMupdatemodel(&(QTM(m)), i); \ -} while (0) - -/* Bitstream reading macros (LZX / intel little-endian byte order) - * - * INIT_BITSTREAM should be used first to set up the system - * READ_BITS(var,n) takes N bits from the buffer and puts them in var - * - * ENSURE_BITS(n) ensures there are at least N bits in the bit buffer. - * it can guarantee up to 17 bits (i.e. it can read in - * 16 new bits when there is down to 1 bit in the buffer, - * and it can read 32 bits when there are 0 bits in the - * buffer). - * PEEK_BITS(n) extracts (without removing) N bits from the bit buffer - * REMOVE_BITS(n) removes N bits from the bit buffer - * - * These bit access routines work by using the area beyond the MSB and the - * LSB as a free source of zeroes. This avoids having to mask any bits. - * So we have to know the bit width of the bitbuffer variable. - */ - -#define INIT_BITSTREAM do { bitsleft = 0; bitbuf = 0; } while (0) - -/* Quantum reads bytes in normal order; LZX is little-endian order */ -#define ENSURE_BITS(n) \ - while (bitsleft < (n)) { \ - bitbuf |= ((inpos[1]<<8)|inpos[0]) << (CAB_ULONG_BITS-16 - bitsleft); \ - bitsleft += 16; inpos+=2; \ - } - -#define PEEK_BITS(n) (bitbuf >> (CAB_ULONG_BITS - (n))) -#define REMOVE_BITS(n) ((bitbuf <<= (n)), (bitsleft -= (n))) - -#define READ_BITS(v,n) do { \ - if (n) { \ - ENSURE_BITS(n); \ - (v) = PEEK_BITS(n); \ - REMOVE_BITS(n); \ - } \ - else { \ - (v) = 0; \ - } \ -} while (0) - -/* Huffman macros */ - -#define TABLEBITS(tbl) (LZX_##tbl##_TABLEBITS) -#define MAXSYMBOLS(tbl) (LZX_##tbl##_MAXSYMBOLS) -#define SYMTABLE(tbl) (LZX(tbl##_table)) -#define LENTABLE(tbl) (LZX(tbl##_len)) - -/* BUILD_TABLE(tablename) builds a huffman lookup table from code lengths. - * In reality, it just calls make_decode_table() with the appropriate - * values - they're all fixed by some #defines anyway, so there's no point - * writing each call out in full by hand. - */ -#define BUILD_TABLE(tbl) \ - if (make_decode_table( \ - MAXSYMBOLS(tbl), TABLEBITS(tbl), LENTABLE(tbl), SYMTABLE(tbl) \ - )) { return DECR_ILLEGALDATA; } - -/* READ_HUFFSYM(tablename, var) decodes one huffman symbol from the - * bitstream using the stated table and puts it in var. - */ -#define READ_HUFFSYM(tbl,var) do { \ - ENSURE_BITS(16); \ - hufftbl = SYMTABLE(tbl); \ - if ((i = hufftbl[PEEK_BITS(TABLEBITS(tbl))]) >= MAXSYMBOLS(tbl)) { \ - j = 1 << (CAB_ULONG_BITS - TABLEBITS(tbl)); \ - do { \ - j >>= 1; i <<= 1; i |= (bitbuf & j) ? 1 : 0; \ - if (!j) { return DECR_ILLEGALDATA; } \ - } while ((i = hufftbl[i]) >= MAXSYMBOLS(tbl)); \ - } \ - j = LENTABLE(tbl)[(var) = i]; \ - REMOVE_BITS(j); \ -} while (0) - -/* READ_LENGTHS(tablename, first, last) reads in code lengths for symbols - * first to last in the given table. The code lengths are stored in their - * own special LZX way. - */ -#define READ_LENGTHS(tbl,first,last,fn) do { \ - lb.bb = bitbuf; lb.bl = bitsleft; lb.ip = inpos; \ - if (fn(LENTABLE(tbl),(first),(last),&lb,decomp_state)) { \ - return DECR_ILLEGALDATA; \ - } \ - bitbuf = lb.bb; bitsleft = lb.bl; inpos = lb.ip; \ -} while (0) - -/* Tables for deflate from PKZIP's appnote.txt. */ - -#define THOSE_ZIP_CONSTS \ -static const cab_UBYTE Zipborder[] = /* Order of the bit length code lengths */ \ -{ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; \ -static const cab_UWORD Zipcplens[] = /* Copy lengths for literal codes 257..285 */ \ -{ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, \ - 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; \ -static const cab_UWORD Zipcplext[] = /* Extra bits for literal codes 257..285 */ \ -{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, \ - 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */ \ -static const cab_UWORD Zipcpdist[] = /* Copy offsets for distance codes 0..29 */ \ -{ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, \ -513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; \ -static const cab_UWORD Zipcpdext[] = /* Extra bits for distance codes */ \ -{ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, \ -10, 11, 11, 12, 12, 13, 13}; \ -/* And'ing with Zipmask[n] masks the lower n bits */ \ -static const cab_UWORD Zipmask[17] = { \ - 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, \ - 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff \ -} - -struct ExtractFileList { - LPSTR filename; - struct ExtractFileList *next; - BOOL unknown; /* always 1L */ -} ; - -/* the first parameter of the function extract */ -typedef struct { - long result1; /* 0x000 */ - long unknown1[3]; /* 0x004 */ - struct ExtractFileList *filelist; /* 0x010 */ - long filecount; /* 0x014 */ - long unknown2; /* 0x018 */ - char directory[0x104]; /* 0x01c */ - char lastfile[0x20c]; /* 0x120 */ -} EXTRACTdest; - - -/* from cabextract.c */ -BOOL process_cabinet(LPCSTR cabname, LPCSTR dir, BOOL fix, BOOL lower, EXTRACTdest *dest); -void QTMupdatemodel(struct QTMmodel *model, int sym); -int make_decode_table(cab_ULONG nsyms, cab_ULONG nbits, cab_UBYTE *length, cab_UWORD *table); -cab_ULONG checksum(cab_UBYTE *data, cab_UWORD bytes, cab_ULONG csum); - -#endif /* __WINE_CABINET_H */ +/* + * cabinet.h + * + * Copyright 2002 Greg Turner + * Copyright 2005 Gerold Jens Wucherpfennig + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __WINE_CABINET_H +#define __WINE_CABINET_H + +#include + +#include "windef.h" +#include "winbase.h" +#include "winnt.h" +#include "fdi.h" +#include "fci.h" + +/* from msvcrt/sys/stat.h */ +#define _S_IWRITE 0x0080 +#define _S_IREAD 0x0100 + +#define CAB_SPLITMAX (10) + +#define CAB_SEARCH_SIZE (32*1024) + +typedef unsigned char cab_UBYTE; /* 8 bits */ +typedef UINT16 cab_UWORD; /* 16 bits */ +typedef UINT32 cab_ULONG; /* 32 bits */ +typedef INT32 cab_LONG; /* 32 bits */ + +typedef UINT32 cab_off_t; + +/* number of bits in a ULONG */ +#ifndef CHAR_BIT +# define CHAR_BIT (8) +#endif +#define CAB_ULONG_BITS (sizeof(cab_ULONG) * CHAR_BIT) + +/* structure offsets */ +#define cfhead_Signature (0x00) +#define cfhead_CabinetSize (0x08) +#define cfhead_FileOffset (0x10) +#define cfhead_MinorVersion (0x18) +#define cfhead_MajorVersion (0x19) +#define cfhead_NumFolders (0x1A) +#define cfhead_NumFiles (0x1C) +#define cfhead_Flags (0x1E) +#define cfhead_SetID (0x20) +#define cfhead_CabinetIndex (0x22) +#define cfhead_SIZEOF (0x24) +#define cfheadext_HeaderReserved (0x00) +#define cfheadext_FolderReserved (0x02) +#define cfheadext_DataReserved (0x03) +#define cfheadext_SIZEOF (0x04) +#define cffold_DataOffset (0x00) +#define cffold_NumBlocks (0x04) +#define cffold_CompType (0x06) +#define cffold_SIZEOF (0x08) +#define cffile_UncompressedSize (0x00) +#define cffile_FolderOffset (0x04) +#define cffile_FolderIndex (0x08) +#define cffile_Date (0x0A) +#define cffile_Time (0x0C) +#define cffile_Attribs (0x0E) +#define cffile_SIZEOF (0x10) +#define cfdata_CheckSum (0x00) +#define cfdata_CompressedSize (0x04) +#define cfdata_UncompressedSize (0x06) +#define cfdata_SIZEOF (0x08) + +/* flags */ +#define cffoldCOMPTYPE_MASK (0x000f) +#define cffoldCOMPTYPE_NONE (0x0000) +#define cffoldCOMPTYPE_MSZIP (0x0001) +#define cffoldCOMPTYPE_QUANTUM (0x0002) +#define cffoldCOMPTYPE_LZX (0x0003) +#define cfheadPREV_CABINET (0x0001) +#define cfheadNEXT_CABINET (0x0002) +#define cfheadRESERVE_PRESENT (0x0004) +#define cffileCONTINUED_FROM_PREV (0xFFFD) +#define cffileCONTINUED_TO_NEXT (0xFFFE) +#define cffileCONTINUED_PREV_AND_NEXT (0xFFFF) +#define cffile_A_RDONLY (0x01) +#define cffile_A_HIDDEN (0x02) +#define cffile_A_SYSTEM (0x04) +#define cffile_A_ARCH (0x20) +#define cffile_A_EXEC (0x40) +#define cffile_A_NAME_IS_UTF (0x80) + +/****************************************************************************/ +/* our archiver information / state */ + +/* MSZIP stuff */ +#define ZIPWSIZE 0x8000 /* window size */ +#define ZIPLBITS 9 /* bits in base literal/length lookup table */ +#define ZIPDBITS 6 /* bits in base distance lookup table */ +#define ZIPBMAX 16 /* maximum bit length of any code */ +#define ZIPN_MAX 288 /* maximum number of codes in any set */ + +struct Ziphuft { + cab_UBYTE e; /* number of extra bits or operation */ + cab_UBYTE b; /* number of bits in this code or subcode */ + union { + cab_UWORD n; /* literal, length base, or distance base */ + struct Ziphuft *t; /* pointer to next level of table */ + } v; +}; + +struct ZIPstate { + cab_ULONG window_posn; /* current offset within the window */ + cab_ULONG bb; /* bit buffer */ + cab_ULONG bk; /* bits in bit buffer */ + cab_ULONG ll[288+32]; /* literal/length and distance code lengths */ + cab_ULONG c[ZIPBMAX+1]; /* bit length count table */ + cab_LONG lx[ZIPBMAX+1]; /* memory for l[-1..ZIPBMAX-1] */ + struct Ziphuft *u[ZIPBMAX]; /* table stack */ + cab_ULONG v[ZIPN_MAX]; /* values in order of bit length */ + cab_ULONG x[ZIPBMAX+1]; /* bit offsets, then code stack */ + cab_UBYTE *inpos; +}; + +/* Quantum stuff */ + +struct QTMmodelsym { + cab_UWORD sym, cumfreq; +}; + +struct QTMmodel { + int shiftsleft, entries; + struct QTMmodelsym *syms; + cab_UWORD tabloc[256]; +}; + +struct QTMstate { + cab_UBYTE *window; /* the actual decoding window */ + cab_ULONG window_size; /* window size (1Kb through 2Mb) */ + cab_ULONG actual_size; /* window size when it was first allocated */ + cab_ULONG window_posn; /* current offset within the window */ + + struct QTMmodel model7; + struct QTMmodelsym m7sym[7+1]; + + struct QTMmodel model4, model5, model6pos, model6len; + struct QTMmodelsym m4sym[0x18 + 1]; + struct QTMmodelsym m5sym[0x24 + 1]; + struct QTMmodelsym m6psym[0x2a + 1], m6lsym[0x1b + 1]; + + struct QTMmodel model00, model40, model80, modelC0; + struct QTMmodelsym m00sym[0x40 + 1], m40sym[0x40 + 1]; + struct QTMmodelsym m80sym[0x40 + 1], mC0sym[0x40 + 1]; +}; + +/* LZX stuff */ + +/* some constants defined by the LZX specification */ +#define LZX_MIN_MATCH (2) +#define LZX_MAX_MATCH (257) +#define LZX_NUM_CHARS (256) +#define LZX_BLOCKTYPE_INVALID (0) /* also blocktypes 4-7 invalid */ +#define LZX_BLOCKTYPE_VERBATIM (1) +#define LZX_BLOCKTYPE_ALIGNED (2) +#define LZX_BLOCKTYPE_UNCOMPRESSED (3) +#define LZX_PRETREE_NUM_ELEMENTS (20) +#define LZX_ALIGNED_NUM_ELEMENTS (8) /* aligned offset tree #elements */ +#define LZX_NUM_PRIMARY_LENGTHS (7) /* this one missing from spec! */ +#define LZX_NUM_SECONDARY_LENGTHS (249) /* length tree #elements */ + +/* LZX huffman defines: tweak tablebits as desired */ +#define LZX_PRETREE_MAXSYMBOLS (LZX_PRETREE_NUM_ELEMENTS) +#define LZX_PRETREE_TABLEBITS (6) +#define LZX_MAINTREE_MAXSYMBOLS (LZX_NUM_CHARS + 50*8) +#define LZX_MAINTREE_TABLEBITS (12) +#define LZX_LENGTH_MAXSYMBOLS (LZX_NUM_SECONDARY_LENGTHS+1) +#define LZX_LENGTH_TABLEBITS (12) +#define LZX_ALIGNED_MAXSYMBOLS (LZX_ALIGNED_NUM_ELEMENTS) +#define LZX_ALIGNED_TABLEBITS (7) + +#define LZX_LENTABLE_SAFETY (64) /* we allow length table decoding overruns */ + +#define LZX_DECLARE_TABLE(tbl) \ + cab_UWORD tbl##_table[(1<pfnalloc) (size)) +#define PFCI_FREE(hfdi, ptr) ((*PFCI_INT(hfdi)->pfnfree) (ptr)) +#define PFCI_GETTEMPFILE(hfci,name,length) ((*PFCI_INT(hfci)->pfnfcigtf)(name,length,PFCI_INT(hfci)->pv)) +#define PFCI_DELETE(hfci,name,err,pv) ((*PFCI_INT(hfci)->pfndelete)(name,err,pv)) +#define PFCI_OPEN(hfci,name,oflag,pmode,err,pv) ((*PFCI_INT(hfci)->pfnopen)(name,oflag,pmode,err,pv)) +#define PFCI_READ(hfci,hf,memory,cb,err,pv)((*PFCI_INT(hfci)->pfnread)(hf,memory,cb,err,pv)) +#define PFCI_WRITE(hfci,hf,memory,cb,err,pv) ((*PFCI_INT(hfci)->pfnwrite)(hf,memory,cb,err,pv)) +#define PFCI_CLOSE(hfci,hf,err,pv) ((*PFCI_INT(hfci)->pfnclose)(hf,err,pv)) +#define PFCI_SEEK(hfci,hf,dist,seektype,err,pv)((*PFCI_INT(hfci)->pfnseek)(hf,dist,seektype,err,pv)) +#define PFCI_FILEPLACED(hfci,pccab,name,cb,cont,pv)((*PFCI_INT(hfci)->pfnfiledest)(pccab,name,cb,cont,pv)) + +/* quickie pfdi method invokers */ +#define PFDI_ALLOC(hfdi, size) ((*PFDI_INT(hfdi)->pfnalloc) (size)) +#define PFDI_FREE(hfdi, ptr) ((*PFDI_INT(hfdi)->pfnfree) (ptr)) +#define PFDI_OPEN(hfdi, file, flag, mode) ((*PFDI_INT(hfdi)->pfnopen) (file, flag, mode)) +#define PFDI_READ(hfdi, hf, pv, cb) ((*PFDI_INT(hfdi)->pfnread) (hf, pv, cb)) +#define PFDI_WRITE(hfdi, hf, pv, cb) ((*PFDI_INT(hfdi)->pfnwrite) (hf, pv, cb)) +#define PFDI_CLOSE(hfdi, hf) ((*PFDI_INT(hfdi)->pfnclose) (hf)) +#define PFDI_SEEK(hfdi, hf, dist, type) ((*PFDI_INT(hfdi)->pfnseek) (hf, dist, type)) + +#define FCI_INT_MAGIC 0xfcfcfc05 +#define FDI_INT_MAGIC 0xfdfdfd05 + +#define REALLY_IS_FCI(hfci) ( \ + (((void *) hfci) != NULL) && \ + (PFCI_INT(hfci)->FCI_Intmagic == FCI_INT_MAGIC) ) + +#define REALLY_IS_FDI(hfdi) ( \ + (((void *) hfdi) != NULL) && \ + (PFDI_INT(hfdi)->FDI_Intmagic == FDI_INT_MAGIC) ) + +/* + * the rest of these are somewhat kludgy macros which are shared between fdi.c + * and cabextract.c. + */ + +#define ZIPNEEDBITS(n) {while(k<(n)){cab_LONG c=*(ZIP(inpos)++);\ + b|=((cab_ULONG)c)<>=(n);k-=(n);} + +/* endian-neutral reading of little-endian data */ +#define EndGetI32(a) ((((a)[3])<<24)|(((a)[2])<<16)|(((a)[1])<<8)|((a)[0])) +#define EndGetI16(a) ((((a)[1])<<8)|((a)[0])) + +#define CAB(x) (decomp_state->x) +#define ZIP(x) (decomp_state->methods.zip.x) +#define QTM(x) (decomp_state->methods.qtm.x) +#define LZX(x) (decomp_state->methods.lzx.x) +#define DECR_OK (0) +#define DECR_DATAFORMAT (1) +#define DECR_ILLEGALDATA (2) +#define DECR_NOMEMORY (3) +#define DECR_CHECKSUM (4) +#define DECR_INPUT (5) +#define DECR_OUTPUT (6) +#define DECR_USERABORT (7) + +/* Bitstream reading macros (Quantum / normal byte order) + * + * Q_INIT_BITSTREAM should be used first to set up the system + * Q_READ_BITS(var,n) takes N bits from the buffer and puts them in var. + * unlike LZX, this can loop several times to get the + * requisite number of bits. + * Q_FILL_BUFFER adds more data to the bit buffer, if there is room + * for another 16 bits. + * Q_PEEK_BITS(n) extracts (without removing) N bits from the bit + * buffer + * Q_REMOVE_BITS(n) removes N bits from the bit buffer + * + * These bit access routines work by using the area beyond the MSB and the + * LSB as a free source of zeroes. This avoids having to mask any bits. + * So we have to know the bit width of the bitbuffer variable. This is + * defined as ULONG_BITS. + * + * ULONG_BITS should be at least 16 bits. Unlike LZX's Huffman decoding, + * Quantum's arithmetic decoding only needs 1 bit at a time, it doesn't + * need an assured number. Retrieving larger bitstrings can be done with + * multiple reads and fills of the bitbuffer. The code should work fine + * for machines where ULONG >= 32 bits. + * + * Also note that Quantum reads bytes in normal order; LZX is in + * little-endian order. + */ + +#define Q_INIT_BITSTREAM do { bitsleft = 0; bitbuf = 0; } while (0) + +#define Q_FILL_BUFFER do { \ + if (bitsleft <= (CAB_ULONG_BITS - 16)) { \ + bitbuf |= ((inpos[0]<<8)|inpos[1]) << (CAB_ULONG_BITS-16 - bitsleft); \ + bitsleft += 16; inpos += 2; \ + } \ +} while (0) + +#define Q_PEEK_BITS(n) (bitbuf >> (CAB_ULONG_BITS - (n))) +#define Q_REMOVE_BITS(n) ((bitbuf <<= (n)), (bitsleft -= (n))) + +#define Q_READ_BITS(v,n) do { \ + (v) = 0; \ + for (bitsneed = (n); bitsneed; bitsneed -= bitrun) { \ + Q_FILL_BUFFER; \ + bitrun = (bitsneed > bitsleft) ? bitsleft : bitsneed; \ + (v) = ((v) << bitrun) | Q_PEEK_BITS(bitrun); \ + Q_REMOVE_BITS(bitrun); \ + } \ +} while (0) + +#define Q_MENTRIES(model) (QTM(model).entries) +#define Q_MSYM(model,symidx) (QTM(model).syms[(symidx)].sym) +#define Q_MSYMFREQ(model,symidx) (QTM(model).syms[(symidx)].cumfreq) + +/* GET_SYMBOL(model, var) fetches the next symbol from the stated model + * and puts it in var. it may need to read the bitstream to do this. + */ +#define GET_SYMBOL(m, var) do { \ + range = ((H - L) & 0xFFFF) + 1; \ + symf = ((((C - L + 1) * Q_MSYMFREQ(m,0)) - 1) / range) & 0xFFFF; \ + \ + for (i=1; i < Q_MENTRIES(m); i++) { \ + if (Q_MSYMFREQ(m,i) <= symf) break; \ + } \ + (var) = Q_MSYM(m,i-1); \ + \ + range = (H - L) + 1; \ + H = L + ((Q_MSYMFREQ(m,i-1) * range) / Q_MSYMFREQ(m,0)) - 1; \ + L = L + ((Q_MSYMFREQ(m,i) * range) / Q_MSYMFREQ(m,0)); \ + while (1) { \ + if ((L & 0x8000) != (H & 0x8000)) { \ + if ((L & 0x4000) && !(H & 0x4000)) { \ + /* underflow case */ \ + C ^= 0x4000; L &= 0x3FFF; H |= 0x4000; \ + } \ + else break; \ + } \ + L <<= 1; H = (H << 1) | 1; \ + Q_FILL_BUFFER; \ + C = (C << 1) | Q_PEEK_BITS(1); \ + Q_REMOVE_BITS(1); \ + } \ + \ + QTMupdatemodel(&(QTM(m)), i); \ +} while (0) + +/* Bitstream reading macros (LZX / intel little-endian byte order) + * + * INIT_BITSTREAM should be used first to set up the system + * READ_BITS(var,n) takes N bits from the buffer and puts them in var + * + * ENSURE_BITS(n) ensures there are at least N bits in the bit buffer. + * it can guarantee up to 17 bits (i.e. it can read in + * 16 new bits when there is down to 1 bit in the buffer, + * and it can read 32 bits when there are 0 bits in the + * buffer). + * PEEK_BITS(n) extracts (without removing) N bits from the bit buffer + * REMOVE_BITS(n) removes N bits from the bit buffer + * + * These bit access routines work by using the area beyond the MSB and the + * LSB as a free source of zeroes. This avoids having to mask any bits. + * So we have to know the bit width of the bitbuffer variable. + */ + +#define INIT_BITSTREAM do { bitsleft = 0; bitbuf = 0; } while (0) + +/* Quantum reads bytes in normal order; LZX is little-endian order */ +#define ENSURE_BITS(n) \ + while (bitsleft < (n)) { \ + bitbuf |= ((inpos[1]<<8)|inpos[0]) << (CAB_ULONG_BITS-16 - bitsleft); \ + bitsleft += 16; inpos+=2; \ + } + +#define PEEK_BITS(n) (bitbuf >> (CAB_ULONG_BITS - (n))) +#define REMOVE_BITS(n) ((bitbuf <<= (n)), (bitsleft -= (n))) + +#define READ_BITS(v,n) do { \ + if (n) { \ + ENSURE_BITS(n); \ + (v) = PEEK_BITS(n); \ + REMOVE_BITS(n); \ + } \ + else { \ + (v) = 0; \ + } \ +} while (0) + +/* Huffman macros */ + +#define TABLEBITS(tbl) (LZX_##tbl##_TABLEBITS) +#define MAXSYMBOLS(tbl) (LZX_##tbl##_MAXSYMBOLS) +#define SYMTABLE(tbl) (LZX(tbl##_table)) +#define LENTABLE(tbl) (LZX(tbl##_len)) + +/* BUILD_TABLE(tablename) builds a huffman lookup table from code lengths. + * In reality, it just calls make_decode_table() with the appropriate + * values - they're all fixed by some #defines anyway, so there's no point + * writing each call out in full by hand. + */ +#define BUILD_TABLE(tbl) \ + if (make_decode_table( \ + MAXSYMBOLS(tbl), TABLEBITS(tbl), LENTABLE(tbl), SYMTABLE(tbl) \ + )) { return DECR_ILLEGALDATA; } + +/* READ_HUFFSYM(tablename, var) decodes one huffman symbol from the + * bitstream using the stated table and puts it in var. + */ +#define READ_HUFFSYM(tbl,var) do { \ + ENSURE_BITS(16); \ + hufftbl = SYMTABLE(tbl); \ + if ((i = hufftbl[PEEK_BITS(TABLEBITS(tbl))]) >= MAXSYMBOLS(tbl)) { \ + j = 1 << (CAB_ULONG_BITS - TABLEBITS(tbl)); \ + do { \ + j >>= 1; i <<= 1; i |= (bitbuf & j) ? 1 : 0; \ + if (!j) { return DECR_ILLEGALDATA; } \ + } while ((i = hufftbl[i]) >= MAXSYMBOLS(tbl)); \ + } \ + j = LENTABLE(tbl)[(var) = i]; \ + REMOVE_BITS(j); \ +} while (0) + +/* READ_LENGTHS(tablename, first, last) reads in code lengths for symbols + * first to last in the given table. The code lengths are stored in their + * own special LZX way. + */ +#define READ_LENGTHS(tbl,first,last,fn) do { \ + lb.bb = bitbuf; lb.bl = bitsleft; lb.ip = inpos; \ + if (fn(LENTABLE(tbl),(first),(last),&lb,decomp_state)) { \ + return DECR_ILLEGALDATA; \ + } \ + bitbuf = lb.bb; bitsleft = lb.bl; inpos = lb.ip; \ +} while (0) + +/* Tables for deflate from PKZIP's appnote.txt. */ + +#define THOSE_ZIP_CONSTS \ +static const cab_UBYTE Zipborder[] = /* Order of the bit length code lengths */ \ +{ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; \ +static const cab_UWORD Zipcplens[] = /* Copy lengths for literal codes 257..285 */ \ +{ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, \ + 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; \ +static const cab_UWORD Zipcplext[] = /* Extra bits for literal codes 257..285 */ \ +{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, \ + 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */ \ +static const cab_UWORD Zipcpdist[] = /* Copy offsets for distance codes 0..29 */ \ +{ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, \ +513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; \ +static const cab_UWORD Zipcpdext[] = /* Extra bits for distance codes */ \ +{ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, \ +10, 11, 11, 12, 12, 13, 13}; \ +/* And'ing with Zipmask[n] masks the lower n bits */ \ +static const cab_UWORD Zipmask[17] = { \ + 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, \ + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff \ +} + +struct ExtractFileList { + LPSTR filename; + struct ExtractFileList *next; + BOOL unknown; /* always 1L */ +} ; + +/* the first parameter of the function extract */ +typedef struct { + long result1; /* 0x000 */ + long unknown1[3]; /* 0x004 */ + struct ExtractFileList *filelist; /* 0x010 */ + long filecount; /* 0x014 */ + long unknown2; /* 0x018 */ + char directory[0x104]; /* 0x01c */ + char lastfile[0x20c]; /* 0x120 */ +} EXTRACTdest; + + +/* from cabextract.c */ +BOOL process_cabinet(LPCSTR cabname, LPCSTR dir, BOOL fix, BOOL lower, EXTRACTdest *dest); +void QTMupdatemodel(struct QTMmodel *model, int sym); +int make_decode_table(cab_ULONG nsyms, cab_ULONG nbits, cab_UBYTE *length, cab_UWORD *table); +cab_ULONG checksum(cab_UBYTE *data, cab_UWORD bytes, cab_ULONG csum); + +#endif /* __WINE_CABINET_H */ diff --git a/reactos/lib/cabinet/cabinet_main.c b/reactos/lib/cabinet/cabinet_main.c index 9d20968d8ea..cd92357ba0d 100644 --- a/reactos/lib/cabinet/cabinet_main.c +++ b/reactos/lib/cabinet/cabinet_main.c @@ -1,135 +1,135 @@ -/* - * cabinet.dll main - * - * Copyright 2002 Patrik Stridvall - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#define NO_SHLWAPI_REG -#include "shlwapi.h" -#undef NO_SHLWAPI_REG - -#include "cabinet.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(cabinet); - -/*********************************************************************** - * DllGetVersion (CABINET.2) - * - * Retrieves version information of the 'CABINET.DLL' - * - * PARAMS - * pdvi [O] pointer to version information structure. - * - * RETURNS - * Success: S_OK - * Failure: E_INVALIDARG - * - * NOTES - * Supposedly returns version from IE6SP1RP1 - */ -HRESULT WINAPI CABINET_DllGetVersion (DLLVERSIONINFO *pdvi) -{ - WARN("hmmm... not right version number \"5.1.1106.1\"?\n"); - - if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) return E_INVALIDARG; - - pdvi->dwMajorVersion = 5; - pdvi->dwMinorVersion = 1; - pdvi->dwBuildNumber = 1106; - pdvi->dwPlatformID = 1; - - return S_OK; -} - -/*********************************************************************** - * Extract (CABINET.3) - * - * Apparently an undocumented function, presumably to extract a CAB file - * to somewhere... - * - * PARAMS - * dest pointer to a buffer of 0x32c bytes containing - * [I] - number with value 1 at index 0x18 - * - the dest path starting at index 0x1c - * [O] - a linked list with the filename existing inside the - * CAB file at idx 0x10 - * - the number of files inside the CAB file at index 0x14 - * - the name of the last file with dest path at idx 0x120 - * what [I] char* describing what to uncompress, I guess. - * - * RETURNS - * Success: S_OK - * Failure: E_OUTOFMEMORY (?) - */ -HRESULT WINAPI Extract(EXTRACTdest *dest, LPCSTR what) -{ -#define DUMPC(idx) idx >= sizeof(EXTRACTdest) ? ' ' : \ - ((unsigned char*) dest)[idx] >= 0x20 ? \ - ((unsigned char*) dest)[idx] : '.' - -#define DUMPH(idx) idx >= sizeof(EXTRACTdest) ? 0x55 : ((unsigned char*) dest)[idx] - - LPSTR dir; - unsigned int i; - - TRACE("(dest == %0lx, what == %s)\n", (long) dest, debugstr_a(what)); - - if (!dest) { - /* win2k will crash here */ - FIXME("called without valid parameter dest!\n"); - return E_OUTOFMEMORY; - } - for (i=0; i < sizeof(EXTRACTdest); i+=8) - TRACE( "dest[%04x]:%02x %02x %02x %02x %02x %02x %02x %02x %c%c%c%c%c%c%c%c\n", - i, - DUMPH(i+0), DUMPH(i+1), DUMPH(i+2), DUMPH(i+3), - DUMPH(i+4), DUMPH(i+5), DUMPH(i+6), DUMPH(i+7), - DUMPC(i+0), DUMPC(i+1), DUMPC(i+2), DUMPC(i+3), - DUMPC(i+4), DUMPC(i+5), DUMPC(i+6), DUMPC(i+7)); - - dir = LocalAlloc(LPTR, strlen(dest->directory)+1); - if (!dir) return E_OUTOFMEMORY; - lstrcpyA(dir, dest->directory); - dest->filecount=0; - dest->filelist = NULL; - - TRACE("extracting to dir: %s\n", debugstr_a(dir)); - - /* FIXME: what to do on failure? */ - if (!process_cabinet(what, dir, FALSE, FALSE, dest)) { - LocalFree(dir); - return E_OUTOFMEMORY; - } - - LocalFree(dir); - - TRACE("filecount %08lx,lastfile %s\n", - dest->filecount, debugstr_a(dest->lastfile)); - - return S_OK; -} +/* + * cabinet.dll main + * + * Copyright 2002 Patrik Stridvall + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#define NO_SHLWAPI_REG +#include "shlwapi.h" +#undef NO_SHLWAPI_REG + +#include "cabinet.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(cabinet); + +/*********************************************************************** + * DllGetVersion (CABINET.2) + * + * Retrieves version information of the 'CABINET.DLL' + * + * PARAMS + * pdvi [O] pointer to version information structure. + * + * RETURNS + * Success: S_OK + * Failure: E_INVALIDARG + * + * NOTES + * Supposedly returns version from IE6SP1RP1 + */ +HRESULT WINAPI CABINET_DllGetVersion (DLLVERSIONINFO *pdvi) +{ + WARN("hmmm... not right version number \"5.1.1106.1\"?\n"); + + if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) return E_INVALIDARG; + + pdvi->dwMajorVersion = 5; + pdvi->dwMinorVersion = 1; + pdvi->dwBuildNumber = 1106; + pdvi->dwPlatformID = 1; + + return S_OK; +} + +/*********************************************************************** + * Extract (CABINET.3) + * + * Apparently an undocumented function, presumably to extract a CAB file + * to somewhere... + * + * PARAMS + * dest pointer to a buffer of 0x32c bytes containing + * [I] - number with value 1 at index 0x18 + * - the dest path starting at index 0x1c + * [O] - a linked list with the filename existing inside the + * CAB file at idx 0x10 + * - the number of files inside the CAB file at index 0x14 + * - the name of the last file with dest path at idx 0x120 + * what [I] char* describing what to uncompress, I guess. + * + * RETURNS + * Success: S_OK + * Failure: E_OUTOFMEMORY (?) + */ +HRESULT WINAPI Extract(EXTRACTdest *dest, LPCSTR what) +{ +#define DUMPC(idx) idx >= sizeof(EXTRACTdest) ? ' ' : \ + ((unsigned char*) dest)[idx] >= 0x20 ? \ + ((unsigned char*) dest)[idx] : '.' + +#define DUMPH(idx) idx >= sizeof(EXTRACTdest) ? 0x55 : ((unsigned char*) dest)[idx] + + LPSTR dir; + unsigned int i; + + TRACE("(dest == %0lx, what == %s)\n", (long) dest, debugstr_a(what)); + + if (!dest) { + /* win2k will crash here */ + FIXME("called without valid parameter dest!\n"); + return E_OUTOFMEMORY; + } + for (i=0; i < sizeof(EXTRACTdest); i+=8) + TRACE( "dest[%04x]:%02x %02x %02x %02x %02x %02x %02x %02x %c%c%c%c%c%c%c%c\n", + i, + DUMPH(i+0), DUMPH(i+1), DUMPH(i+2), DUMPH(i+3), + DUMPH(i+4), DUMPH(i+5), DUMPH(i+6), DUMPH(i+7), + DUMPC(i+0), DUMPC(i+1), DUMPC(i+2), DUMPC(i+3), + DUMPC(i+4), DUMPC(i+5), DUMPC(i+6), DUMPC(i+7)); + + dir = LocalAlloc(LPTR, strlen(dest->directory)+1); + if (!dir) return E_OUTOFMEMORY; + lstrcpyA(dir, dest->directory); + dest->filecount=0; + dest->filelist = NULL; + + TRACE("extracting to dir: %s\n", debugstr_a(dir)); + + /* FIXME: what to do on failure? */ + if (!process_cabinet(what, dir, FALSE, FALSE, dest)) { + LocalFree(dir); + return E_OUTOFMEMORY; + } + + LocalFree(dir); + + TRACE("filecount %08lx,lastfile %s\n", + dest->filecount, debugstr_a(dest->lastfile)); + + return S_OK; +} diff --git a/reactos/lib/cabinet/fci.c b/reactos/lib/cabinet/fci.c index c46464bcf49..08e71f1270b 100644 --- a/reactos/lib/cabinet/fci.c +++ b/reactos/lib/cabinet/fci.c @@ -1,2664 +1,2664 @@ -/* - * File Compression Interface - * - * Copyright 2002 Patrik Stridvall - * Copyright 2005 Gerold Jens Wucherpfennig - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - -There is still some work to be done: - -- currently no support for big-endian machines -- the ERF error structure aren't used on error -- no real compression yet -- unknown behaviour if files>4GB or cabinet >4GB -- incorrect status information -- check if the maximum size for a cabinet is too small to store any data -- call pfnfcignc on exactly the same position as MS FCIAddFile in every case - -*/ - - - -#include "config.h" - -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "fci.h" -#include "cabinet.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(cabinet); - -typedef struct { - cab_UBYTE signature[4]; /* !CAB for unfinished cabinets else MSCF */ - cab_ULONG reserved1; - cab_ULONG cbCabinet; /* size of the cabinet file in bytes*/ - cab_ULONG reserved2; - cab_ULONG coffFiles; /* offset to first CFFILE section */ - cab_ULONG reserved3; - cab_UBYTE versionMinor; /* 3 */ - cab_UBYTE versionMajor; /* 1 */ - cab_UWORD cFolders; /* number of CFFOLDER entries in the cabinet*/ - cab_UWORD cFiles; /* number of CFFILE entries in the cabinet*/ - cab_UWORD flags; /* 1=prev cab, 2=next cabinet, 4=reserved setions*/ - cab_UWORD setID; /* identification number of all cabinets in a set*/ - cab_UWORD iCabinet; /* number of the cabinet in a set */ - /* additional area if "flags" were set*/ -} CFHEADER; /* minimum 36 bytes */ - -typedef struct { - cab_ULONG coffCabStart; /* offset to the folder's first CFDATA section */ - cab_UWORD cCFData; /* number of this folder's CFDATA sections */ - cab_UWORD typeCompress; /* compression type of data in CFDATA section*/ - /* additional area if reserve flag was set */ -} CFFOLDER; /* minumum 8 bytes */ - -typedef struct { - cab_ULONG cbFile; /* size of the uncompressed file in bytes */ - cab_ULONG uoffFolderStart; /* offset of the uncompressed file in the folder */ - cab_UWORD iFolder; /* number of folder in the cabinet 0=first */ - /* for special values see below this structure*/ - cab_UWORD date; /* last modification date*/ - cab_UWORD time; /* last modification time*/ - cab_UWORD attribs; /* DOS fat attributes and UTF indicator */ - /* ... and a C string with the name of the file */ -} CFFILE; /* 16 bytes + name of file */ - - -typedef struct { - cab_ULONG csum; /* checksum of this entry*/ - cab_UWORD cbData; /* number of compressed bytes */ - cab_UWORD cbUncomp; /* number of bytes when data is uncompressed */ - /* optional reserved area */ - /* compressed data */ -} CFDATA; - - -/*********************************************************************** - * FCICreate (CABINET.10) - * - * FCICreate is provided with several callbacks and - * returns a handle which can be used to create cabinet files. - * - * PARAMS - * perf [IO] A pointer to an ERF structure. When FCICreate - * returns an error condition, error information may - * be found here as well as from GetLastError. - * pfnfiledest [I] A pointer to a function which is called when a file - * is placed. Only useful for subsequent cabinet files. - * pfnalloc [I] A pointer to a function which allocates ram. Uses - * the same interface as malloc. - * pfnfree [I] A pointer to a function which frees ram. Uses the - * same interface as free. - * pfnopen [I] A pointer to a function which opens a file. Uses - * the same interface as _open. - * pfnread [I] A pointer to a function which reads from a file into - * a caller-provided buffer. Uses the same interface - * as _read. - * pfnwrite [I] A pointer to a function which writes to a file from - * a caller-provided buffer. Uses the same interface - * as _write. - * pfnclose [I] A pointer to a function which closes a file handle. - * Uses the same interface as _close. - * pfnseek [I] A pointer to a function which seeks in a file. - * Uses the same interface as _lseek. - * pfndelete [I] A pointer to a function which deletes a file. - * pfnfcigtf [I] A pointer to a function which gets the name of a - * temporary file. - * pccab [I] A pointer to an initialized CCAB structure. - * pv [I] A pointer to an application-defined notification - * function which will be passed to other FCI functions - * as a parameter. - * - * RETURNS - * On success, returns an FCI handle of type HFCI. - * On failure, the NULL file handle is returned. Error - * info can be retrieved from perf. - * - * INCLUDES - * fci.h - * - */ -HFCI __cdecl FCICreate( - PERF perf, - PFNFCIFILEPLACED pfnfiledest, - PFNFCIALLOC pfnalloc, - PFNFCIFREE pfnfree, - PFNFCIOPEN pfnopen, - PFNFCIREAD pfnread, - PFNFCIWRITE pfnwrite, - PFNFCICLOSE pfnclose, - PFNFCISEEK pfnseek, - PFNFCIDELETE pfndelete, - PFNFCIGETTEMPFILE pfnfcigtf, - PCCAB pccab, - void *pv) -{ - HFCI hfci; - int err; - PFCI_Int p_fci_internal; - - if ((!perf) || (!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) || - (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) || - (!pfnfcigtf) || (!pccab)) { - perf->erfOper = FCIERR_NONE; - perf->erfType = ERROR_BAD_ARGUMENTS; - perf->fError = TRUE; - - SetLastError(ERROR_BAD_ARGUMENTS); - return NULL; - } - - if (!((hfci = ((HFCI) (*pfnalloc)(sizeof(FCI_Int)))))) { - perf->erfOper = FCIERR_ALLOC_FAIL; - perf->erfType = ERROR_NOT_ENOUGH_MEMORY; - perf->fError = TRUE; - - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return NULL; - } - - p_fci_internal=((PFCI_Int)(hfci)); - p_fci_internal->FCI_Intmagic = FCI_INT_MAGIC; - p_fci_internal->perf = perf; - p_fci_internal->pfnfiledest = pfnfiledest; - p_fci_internal->pfnalloc = pfnalloc; - p_fci_internal->pfnfree = pfnfree; - p_fci_internal->pfnopen = pfnopen; - p_fci_internal->pfnread = pfnread; - p_fci_internal->pfnwrite = pfnwrite; - p_fci_internal->pfnclose = pfnclose; - p_fci_internal->pfnseek = pfnseek; - p_fci_internal->pfndelete = pfndelete; - p_fci_internal->pfnfcigtf = pfnfcigtf; - p_fci_internal->pccab = pccab; - p_fci_internal->fPrevCab = FALSE; - p_fci_internal->fNextCab = FALSE; - p_fci_internal->fSplitFolder = FALSE; - p_fci_internal->fGetNextCabInVain = FALSE; - p_fci_internal->pv = pv; - p_fci_internal->data_in = NULL; - p_fci_internal->cdata_in = 0; - p_fci_internal->data_out = NULL; - p_fci_internal->cCompressedBytesInFolder = 0; - p_fci_internal->cFolders = 0; - p_fci_internal->cFiles = 0; - p_fci_internal->cDataBlocks = 0; - p_fci_internal->sizeFileCFDATA1 = 0; - p_fci_internal->sizeFileCFFILE1 = 0; - p_fci_internal->sizeFileCFDATA2 = 0; - p_fci_internal->sizeFileCFFILE2 = 0; - p_fci_internal->sizeFileCFFOLDER = 0; - p_fci_internal->sizeFileCFFOLDER = 0; - p_fci_internal->fNewPrevious = FALSE; - - memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME); - memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME); - - /* CFDATA */ - if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFDATA1, - CB_MAX_FILENAME)) { - /* TODO error handling */ - return FALSE; - } - /* safety */ - if ( strlen(p_fci_internal->szFileNameCFDATA1) >= CB_MAX_FILENAME ) { - /* TODO set error code */ - return FALSE; - } - - p_fci_internal->handleCFDATA1 = PFCI_OPEN(hfci, - p_fci_internal->szFileNameCFDATA1, 34050, 384, &err, pv); - /* TODO check handle */ - /* TODO error checking of err */ - - /* array of all CFFILE in a folder */ - if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE1, - CB_MAX_FILENAME)) { - /* TODO error handling */ - return FALSE; - } - /* safety */ - if ( strlen(p_fci_internal->szFileNameCFFILE1) >= CB_MAX_FILENAME ) { - /* TODO set error code */ - return FALSE; - } - p_fci_internal->handleCFFILE1 = PFCI_OPEN(hfci, - p_fci_internal->szFileNameCFFILE1, 34050, 384, &err, pv); - /* TODO check handle */ - /* TODO error checking of err */ - - /* CFDATA with checksum and ready to be copied into cabinet */ - if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFDATA2, - CB_MAX_FILENAME)) { - /* TODO error handling */ - return FALSE; - } - /* safety */ - if ( strlen(p_fci_internal->szFileNameCFDATA2) >= CB_MAX_FILENAME ) { - /* TODO set error code */ - return FALSE; - } - p_fci_internal->handleCFDATA2 = PFCI_OPEN(hfci, - p_fci_internal->szFileNameCFDATA2, 34050, 384, &err, pv); - /* TODO check handle */ - /* TODO error checking of err */ - - /* array of all CFFILE in a folder, ready to be copied into cabinet */ - if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE2, - CB_MAX_FILENAME)) { - /* TODO error handling */ - return FALSE; - } - /* safety */ - if ( strlen(p_fci_internal->szFileNameCFFILE2) >= CB_MAX_FILENAME ) { - /* TODO set error code */ - return FALSE; - } - p_fci_internal->handleCFFILE2 = PFCI_OPEN(hfci, - p_fci_internal->szFileNameCFFILE2, 34050, 384, &err, pv); - /* TODO check handle */ - /* TODO error checking of err */ - - /* array of all CFFILE in a folder, ready to be copied into cabinet */ - if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFOLDER, - CB_MAX_FILENAME)) { - /* TODO error handling */ - return FALSE; - } - /* safety */ - if ( strlen(p_fci_internal->szFileNameCFFOLDER) >= CB_MAX_FILENAME ) { - /* TODO set error code */ - return FALSE; - } - p_fci_internal->handleCFFOLDER = PFCI_OPEN(hfci, - p_fci_internal->szFileNameCFFOLDER, 34050, 384, &err, pv); - - - /* TODO close and delete new files when return FALSE */ - - /* TODO check handle */ - /* TODO error checking of err */ - - return hfci; -} /* end of FCICreate */ - - - - - - -static BOOL fci_flush_data_block (HFCI hfci, int* err, - PFNFCISTATUS pfnfcis) { - - /* attention no hfci checks!!! */ - /* attention no checks if there is data available!!! */ - CFDATA data; - CFDATA* cfdata=&data; - char* reserved; - PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); - UINT cbReserveCFData=p_fci_internal->pccab->cbReserveCFData; - UINT i; - - /* TODO compress the data of p_fci_internal->data_in */ - /* and write it to p_fci_internal->data_out */ - memcpy(p_fci_internal->data_out, p_fci_internal->data_in, - p_fci_internal->cdata_in /* number of bytes to copy */); - - cfdata->csum=0; /* checksum has to be set later */ - /* TODO set realsize of compressed data */ - cfdata->cbData = p_fci_internal->cdata_in; - cfdata->cbUncomp = p_fci_internal->cdata_in; - - /* write cfdata to p_fci_internal->handleCFDATA1 */ - if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA1, /* file handle */ - cfdata, sizeof(*cfdata), err, p_fci_internal->pv) - != sizeof(*cfdata) ) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - - p_fci_internal->sizeFileCFDATA1 += sizeof(*cfdata); - - /* add optional reserved area */ - - /* This allocation and freeing at each CFData block is a bit */ - /* inefficent, but it's harder to forget about freeing the buffer :-). */ - /* Reserved areas are used seldom besides that... */ - if (cbReserveCFData!=0) { - if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFData))) { - p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL; - p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; - p_fci_internal->perf->fError = TRUE; - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; - } - for(i=0;ihandleCFDATA1, /* file handle */ - reserved, /* memory buffer */ - cbReserveCFData, /* number of bytes to copy */ - err, p_fci_internal->pv) != cbReserveCFData ) { - PFCI_FREE(hfci, reserved); - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err PFCI_FREE(hfci, reserved)*/ - - p_fci_internal->sizeFileCFDATA1 += cbReserveCFData; - PFCI_FREE(hfci, reserved); - } - - /* write p_fci_internal->data_out to p_fci_internal->handleCFDATA1 */ - if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA1, /* file handle */ - p_fci_internal->data_out, /* memory buffer */ - cfdata->cbData, /* number of bytes to copy */ - err, p_fci_internal->pv) != cfdata->cbData) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - - p_fci_internal->sizeFileCFDATA1 += cfdata->cbData; - - /* reset the offset */ - p_fci_internal->cdata_in = 0; - p_fci_internal->cCompressedBytesInFolder += cfdata->cbData; - - /* report status with pfnfcis about uncompressed and compressed file data */ - if( (*pfnfcis)(statusFile, cfdata->cbData, cfdata->cbUncomp, - p_fci_internal->pv) == -1) { - /* TODO set error code and abort */ - return FALSE; - } - - ++(p_fci_internal->cDataBlocks); - - return TRUE; -} /* end of fci_flush_data_block */ - - - - - -static cab_ULONG fci_get_checksum(void *pv, UINT cb, CHECKSUM seed) -{ - cab_ULONG csum; - cab_ULONG ul; - int cUlong; - BYTE *pb; - - csum = seed; - cUlong = cb / 4; - pb = pv; - - while (cUlong-- > 0) { - ul = *pb++; - ul |= (((cab_ULONG)(*pb++)) << 8); - ul |= (((cab_ULONG)(*pb++)) << 16); - ul |= (((cab_ULONG)(*pb++)) << 24); - - csum ^= ul; - } - - ul = 0; - switch (cb % 4) { - case 3: - ul |= (((ULONG)(*pb++)) << 16); - case 2: - ul |= (((ULONG)(*pb++)) << 8); - case 1: - ul |= *pb++; - default: - break; - } - csum ^= ul; - - return csum; -} /* end of fci_get_checksum */ - - - - - -static BOOL fci_flushfolder_copy_cfdata(HFCI hfci, char* buffer, UINT cbReserveCFData, - PFNFCISTATUS pfnfcis, int* err, int handleCFDATA1new, - cab_ULONG* psizeFileCFDATA1new, cab_ULONG* payload) -{ - cab_ULONG read_result; - CFDATA* pcfdata=(CFDATA*)buffer; - BOOL split_block=FALSE; - cab_UWORD savedUncomp=0; - PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); - - *payload=0; - - /* while not all CFDATAs have been copied do */ - while(!FALSE) { - if( p_fci_internal->fNextCab ) { - if( split_block ) { - /* TODO internal error should never happen */ - return FALSE; - } - } - /* REUSE the variable read_result */ - if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || - p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || - p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { - read_result=4; - } else { - read_result=0; - } - if (p_fci_internal->fPrevCab) { - read_result+=strlen(p_fci_internal->szPrevCab)+1 + - strlen(p_fci_internal->szPrevDisk)+1; - } - /* No more CFDATA fits into the cabinet under construction */ - /* So don't try to store more data into it */ - if( p_fci_internal->fNextCab && - (p_fci_internal->oldCCAB.cb <= sizeof(CFDATA) + cbReserveCFData + - p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 + - p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER + - sizeof(CFHEADER) + - read_result + - p_fci_internal->oldCCAB.cbReserveCFHeader + - sizeof(CFFOLDER) + - p_fci_internal->oldCCAB.cbReserveCFFolder + - strlen(p_fci_internal->pccab->szCab)+1 + - strlen(p_fci_internal->pccab->szDisk)+1 - )) { - /* This may never be run for the first time the while loop is entered. - Pray that the code that calls fci_flushfolder_copy_cfdata handles this.*/ - split_block=TRUE; /* In this case split_block is abused to store */ - /* the complete data block into the next cabinet and not into the */ - /* current one. Originally split_block is the indicator that a */ - /* data block has been splitted across different cabinets. */ - } else { - - /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/ - read_result= PFCI_READ(hfci, p_fci_internal->handleCFDATA1,/*file handle*/ - buffer, /* memory buffer */ - sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */ - err, p_fci_internal->pv); - if (read_result!=sizeof(CFDATA)+cbReserveCFData) { - if (read_result==0) break; /* ALL DATA has been copied */ - /* TODO read error */ - return FALSE; - } - /* TODO error handling of err */ - - /* REUSE buffer p_fci_internal->data_out !!! */ - /* read data from p_fci_internal->handleCFDATA1 to */ - /* p_fci_internal->data_out */ - if( PFCI_READ(hfci, p_fci_internal->handleCFDATA1 /* file handle */, - p_fci_internal->data_out /* memory buffer */, - pcfdata->cbData /* number of bytes to copy */, - err, p_fci_internal->pv) != pcfdata->cbData ) { - /* TODO read error */ - return FALSE; - } - /* TODO error handling of err */ - - /* if cabinet size is too large */ - - /* REUSE the variable read_result */ - if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || - p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || - p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { - read_result=4; - } else { - read_result=0; - } - if (p_fci_internal->fPrevCab) { - read_result+=strlen(p_fci_internal->szPrevCab)+1 + - strlen(p_fci_internal->szPrevDisk)+1; - } - - /* Is cabinet with new CFDATA too large? Then data block has to be split */ - if( p_fci_internal->fNextCab && - (p_fci_internal->oldCCAB.cb < sizeof(CFDATA) + cbReserveCFData + - pcfdata->cbData + - p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 + - p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER + - sizeof(CFHEADER) + - read_result + - p_fci_internal->oldCCAB.cbReserveCFHeader + - sizeof(CFFOLDER) + /* size of new CFFolder entry */ - p_fci_internal->oldCCAB.cbReserveCFFolder + - strlen(p_fci_internal->pccab->szCab)+1 + /* name of next cabinet */ - strlen(p_fci_internal->pccab->szDisk)+1 /* name of next disk */ - )) { - /* REUSE read_result to save the size of the compressed data */ - read_result=pcfdata->cbData; - /* Modify the size of the compressed data to store only a part of the */ - /* data block into the current cabinet. This is done to prevent */ - /* that the maximum cabinet size will be exceeded. The remainer */ - /* will be stored into the next following cabinet. */ - - /* The cabinet will be of size "p_fci_internal->oldCCAB.cb". */ - /* Substract everything except the size of the block of data */ - /* to get it's actual size */ - pcfdata->cbData = p_fci_internal->oldCCAB.cb - ( - sizeof(CFDATA) + cbReserveCFData + - p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 + - p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER + - sizeof(CFHEADER) + - p_fci_internal->oldCCAB.cbReserveCFHeader + - sizeof(CFFOLDER) + /* set size of new CFFolder entry */ - p_fci_internal->oldCCAB.cbReserveCFFolder ); - /* substract the size of special header fields */ - if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || - p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || - p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { - pcfdata->cbData-=4; - } - if (p_fci_internal->fPrevCab) { - pcfdata->cbData-=strlen(p_fci_internal->szPrevCab)+1 + - strlen(p_fci_internal->szPrevDisk)+1; - } - pcfdata->cbData-=strlen(p_fci_internal->pccab->szCab)+1 + - strlen(p_fci_internal->pccab->szDisk)+1; - - savedUncomp = pcfdata->cbUncomp; - pcfdata->cbUncomp = 0; /* on splitted blocks of data this is zero */ - - /* if split_block==TRUE then the above while loop won't */ - /* be executed again */ - split_block=TRUE; /* split_block is the indicator that */ - /* a data block has been splitted across */ - /* diffentent cabinets.*/ - } - - /* This should never happen !!! */ - if (pcfdata->cbData==0) { - /* TODO set error */ - return FALSE; - } - - /* get checksum and write to cfdata.csum */ - pcfdata->csum = fci_get_checksum( &(pcfdata->cbData), - sizeof(CFDATA)+cbReserveCFData - - sizeof(pcfdata->csum), fci_get_checksum( p_fci_internal->data_out, /*buffer*/ - pcfdata->cbData, 0 ) ); - - /* write cfdata with checksum to p_fci_internal->handleCFDATA2 */ - if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA2, /* file handle */ - buffer, /* memory buffer */ - sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */ - err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - - p_fci_internal->sizeFileCFDATA2 += sizeof(CFDATA)+cbReserveCFData; - - /* write compressed data into p_fci_internal->handleCFDATA2 */ - if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA2, /* file handle */ - p_fci_internal->data_out, /* memory buffer */ - pcfdata->cbData, /* number of bytes to copy */ - err, p_fci_internal->pv) != pcfdata->cbData) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - - p_fci_internal->sizeFileCFDATA2 += pcfdata->cbData; - ++(p_fci_internal->cDataBlocks); - p_fci_internal->statusFolderCopied += pcfdata->cbData; - (*payload)+=pcfdata->cbUncomp; - /* if cabinet size too large and data has been split */ - /* write the remainer of the data block to the new CFDATA1 file */ - if( split_block ) { /* This does not include the */ - /* abused one (just search for "abused" )*/ - /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */ - if (p_fci_internal->fNextCab==FALSE ) { - /* TODO internal error */ - return FALSE; - } - - /* set cbData the size of the remainer of the data block */ - pcfdata->cbData = read_result - pcfdata->cbData; - /*recover former value of cfdata.cbData; read_result will be the offset*/ - read_result -= pcfdata->cbData; - pcfdata->cbUncomp = savedUncomp; - - /* reset checksum, it will be computed later */ - pcfdata->csum=0; - /* write cfdata WITHOUT checksum to handleCFDATA1new */ - if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */ - buffer, /* memory buffer */ - sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */ - err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err dont forget PFCI_FREE(hfci, reserved) */ - - *psizeFileCFDATA1new += sizeof(CFDATA)+cbReserveCFData; - - /* write compressed data into handleCFDATA1new */ - if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */ - p_fci_internal->data_out + read_result, /* memory buffer + offset */ - /* to last part of split data */ - pcfdata->cbData, /* number of bytes to copy */ - err, p_fci_internal->pv) != pcfdata->cbData) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - - p_fci_internal->statusFolderCopied += pcfdata->cbData; - - *psizeFileCFDATA1new += pcfdata->cbData; - /* the two blocks of the split data block have been written */ - /* dont reset split_data yet, because it is still needed see below */ - } - - /* report status with pfnfcis about copied size of folder */ - if( (*pfnfcis)(statusFolder, - p_fci_internal->statusFolderCopied, /*cfdata.cbData(+previous ones)*/ - p_fci_internal->statusFolderTotal, /* total folder size */ - p_fci_internal->pv) == -1) { - /* TODO set error code and abort */ - return FALSE; - } - } - - /* if cabinet size too large */ - /* write the remaining data blocks to the new CFDATA1 file */ - if ( split_block ) { /* This does include the */ - /* abused one (just search for "abused" )*/ - if (p_fci_internal->fNextCab==FALSE ) { - /* TODO internal error */ - return FALSE; - } - /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */ - while(!FALSE) { - /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/ - read_result= PFCI_READ(hfci, p_fci_internal->handleCFDATA1,/* handle */ - buffer, /* memory buffer */ - sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */ - err, p_fci_internal->pv); - if (read_result!=sizeof(CFDATA)+cbReserveCFData) { - if (read_result==0) break; /* ALL DATA has been copied */ - /* TODO read error */ - return FALSE; - } - /* TODO error handling of err */ - - /* REUSE buffer p_fci_internal->data_out !!! */ - /* read data from p_fci_internal->handleCFDATA1 to */ - /* p_fci_internal->data_out */ - if( PFCI_READ(hfci, p_fci_internal->handleCFDATA1 /* file handle */, - p_fci_internal->data_out /* memory buffer */, - pcfdata->cbData /* number of bytes to copy */, - err, p_fci_internal->pv) != pcfdata->cbData ) { - /* TODO read error */ - return FALSE; - } - /* TODO error handling of err dont forget PFCI_FREE(hfci, reserved) */ - - /* write cfdata with checksum to handleCFDATA1new */ - if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */ - buffer, /* memory buffer */ - sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */ - err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err dont forget PFCI_FREE(hfci, reserved) */ - - *psizeFileCFDATA1new += sizeof(CFDATA)+cbReserveCFData; - - /* write compressed data into handleCFDATA1new */ - if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */ - p_fci_internal->data_out, /* memory buffer */ - pcfdata->cbData, /* number of bytes to copy */ - err, p_fci_internal->pv) != pcfdata->cbData) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - - *psizeFileCFDATA1new += pcfdata->cbData; - p_fci_internal->statusFolderCopied += pcfdata->cbData; - - /* report status with pfnfcis about copied size of folder */ - if( (*pfnfcis)(statusFolder, - p_fci_internal->statusFolderCopied,/*cfdata.cbData(+revious ones)*/ - p_fci_internal->statusFolderTotal, /* total folder size */ - p_fci_internal->pv) == -1) { - /* TODO set error code and abort */ - return FALSE; - } - - } /* end of WHILE */ - break; /* jump out of the next while loop */ - } /* end of if( split_data ) */ - } /* end of WHILE */ - return TRUE; -} /* end of fci_flushfolder_copy_cfdata */ - - - - - -static BOOL fci_flushfolder_copy_cffolder(HFCI hfci, int* err, UINT cbReserveCFFolder, - cab_ULONG sizeFileCFDATA2old) -{ - CFFOLDER cffolder; - UINT i; - char* reserved; - PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); - - /* absolute offset cannot be set yet, because the size of cabinet header, */ - /* the number of CFFOLDERs and the number of CFFILEs may change. */ - /* Instead the size of all previous data blocks will be stored and */ - /* the remainer of the offset will be added when the cabinet will be */ - /* flushed to disk. */ - /* This is exactly the way the original CABINET.DLL works!!! */ - cffolder.coffCabStart=sizeFileCFDATA2old; - - /* set the number of this folder's CFDATA sections */ - cffolder.cCFData=p_fci_internal->cDataBlocks; - /* TODO set compression type */ - cffolder.typeCompress = tcompTYPE_NONE; - - /* write cffolder to p_fci_internal->handleCFFOLDER */ - if( PFCI_WRITE(hfci, p_fci_internal->handleCFFOLDER, /* file handle */ - &cffolder, /* memory buffer */ - sizeof(cffolder), /* number of bytes to copy */ - err, p_fci_internal->pv) != sizeof(cffolder) ) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - - p_fci_internal->sizeFileCFFOLDER += sizeof(cffolder); - - /* add optional reserved area */ - if (cbReserveCFFolder!=0) { - if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFFolder))) { - p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL; - p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; - p_fci_internal->perf->fError = TRUE; - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; - } - for(i=0;ihandleCFFOLDER, /* file handle */ - reserved, /* memory buffer */ - cbReserveCFFolder, /* number of bytes to copy */ - err, p_fci_internal->pv) != cbReserveCFFolder ) { - PFCI_FREE(hfci, reserved); - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - - p_fci_internal->sizeFileCFFOLDER += cbReserveCFFolder; - - PFCI_FREE(hfci, reserved); - } - return TRUE; -} /* end of fci_flushfolder_copy_cffolder */ - - - - - -static BOOL fci_flushfolder_copy_cffile(HFCI hfci, int* err, int handleCFFILE1new, - cab_ULONG *psizeFileCFFILE1new, cab_ULONG payload) -{ - CFFILE cffile; - cab_ULONG read_result; - cab_ULONG seek=0; - cab_ULONG sizeOfFiles=0, sizeOfFilesPrev; - BOOL may_be_prev=TRUE; - cab_ULONG cbFileRemainer=0; - PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); - /* set seek of p_fci_internal->handleCFFILE1 to 0 */ - if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE1,0,SEEK_SET,err, - p_fci_internal->pv) !=0 ) { - /* TODO wrong return value */ - } - /* TODO error handling of err */ - - /* while not all CFFILE structures have been copied do */ - while(!FALSE) { - /* REUSE the variable read_result */ - /* read data from p_fci_internal->handleCFFILE1 to cffile */ - read_result = PFCI_READ(hfci,p_fci_internal->handleCFFILE1/* file handle */, - &cffile, /* memory buffer */ - sizeof(cffile), /* number of bytes to copy */ - err, p_fci_internal->pv); - if( read_result != sizeof(cffile) ) { - if( read_result == 0 ) break; /* ALL CFFILE structures have been copied */ - /* TODO read error */ - return FALSE; - } - /* TODO error handling of err */ - - /* Microsoft's(R) CABINET.DLL would do a seek to the current! */ - /* position. I don't know why so I'll just omit it */ - - /* read the filename from p_fci_internal->handleCFFILE1 */ - /* REUSE the variable read_result AGAIN */ - /* REUSE the memory buffer PFCI(hfci)->data_out */ - if( PFCI_READ(hfci, p_fci_internal->handleCFFILE1 /*file handle*/, - p_fci_internal->data_out, /* memory buffer */ - CB_MAX_FILENAME, /* number of bytes to copy */ - err, p_fci_internal->pv) <2) { - /* TODO read error */ - return FALSE; - } - /* TODO maybe other checks of read_result */ - /* TODO error handling of err */ - - /* safety */ - if( strlen(p_fci_internal->data_out)>=CB_MAX_FILENAME ) { - /* TODO set error code internal error */ - return FALSE; - } - - seek+=sizeof(cffile) + strlen(p_fci_internal->data_out)+1; - - /* set seek of p_fci_internal->handleCFFILE1 to end of file name */ - /* i.e. seek to the next CFFILE area */ - if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE1, - seek, /* seek position*/ - SEEK_SET ,err, - p_fci_internal->pv) - != sizeof(cffile)+strlen(p_fci_internal->data_out)+1 ) { - /* TODO wrong return value */ - } - /* TODO error handling of err */ - - /* fnfilfnfildest: placed file on cabinet */ - if (p_fci_internal->fNextCab || - p_fci_internal->fGetNextCabInVain) { - PFCI_FILEPLACED( hfci, &(p_fci_internal->oldCCAB), - p_fci_internal->data_out, /* the file name*/ - cffile.cbFile, /* file size */ - (cffile.iFolder==cffileCONTINUED_FROM_PREV), - p_fci_internal->pv - ); - } else { - PFCI_FILEPLACED( hfci, p_fci_internal->pccab, - p_fci_internal->data_out, /* the file name*/ - cffile.cbFile, /* file size */ - (cffile.iFolder==cffileCONTINUED_FROM_PREV), - p_fci_internal->pv - ); - } - - /* Check special iFolder values */ - if( cffile.iFolder==cffileCONTINUED_FROM_PREV && - p_fci_internal->fPrevCab==FALSE ) { - /* THIS MAY NEVER HAPPEN */ - /* TODO set error code */ - return FALSE; - } - if( cffile.iFolder==cffileCONTINUED_PREV_AND_NEXT || - cffile.iFolder==cffileCONTINUED_TO_NEXT ) { - /* THIS MAY NEVER HAPPEN */ - /* TODO set error code */ - return FALSE; - } - if( may_be_prev && cffile.iFolder!=cffileCONTINUED_FROM_PREV ) { - may_be_prev=FALSE; - } - if( cffile.iFolder==cffileCONTINUED_FROM_PREV && may_be_prev==FALSE ) { - /* THIS MAY NEVER HAPPEN */ - /* TODO set error code */ - return FALSE; - } - if( cffile.iFolder!=cffileCONTINUED_FROM_PREV ) { - may_be_prev=FALSE; - } - - sizeOfFilesPrev=sizeOfFiles; - /* Set complete size of all processed files */ - if( cffile.iFolder==cffileCONTINUED_FROM_PREV && - p_fci_internal->cbFileRemainer!=0 - ) { - sizeOfFiles+=p_fci_internal->cbFileRemainer; - p_fci_internal->cbFileRemainer=0; - } else { - sizeOfFiles+=cffile.cbFile; - } - - /* Check if spanned file fits into this cabinet folder */ - if( cffile.iFolder==cffileCONTINUED_FROM_PREV && sizeOfFiles>payload ) { - cffile.iFolder=cffileCONTINUED_PREV_AND_NEXT; - } else - - /* Check if file doesn't fit into this cabinet folder */ - if( sizeOfFiles>payload ) { - cffile.iFolder=cffileCONTINUED_TO_NEXT; - } - - /* write cffile to p_fci_internal->handleCFFILE2 */ - if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE2, /* file handle */ - &cffile, /* memory buffer */ - sizeof(cffile), /* number of bytes to copy */ - err, p_fci_internal->pv) != sizeof(cffile) ) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - - p_fci_internal->sizeFileCFFILE2 += sizeof(cffile); - - /* write file name to p_fci_internal->handleCFFILE2 */ - if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE2, /* file handle */ - p_fci_internal->data_out, /* memory buffer */ - strlen(p_fci_internal->data_out)+1, /* number of bytes to copy */ - err, p_fci_internal->pv) != strlen(p_fci_internal->data_out)+1 ) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - - p_fci_internal->sizeFileCFFILE2 += strlen(p_fci_internal->data_out)+1; - - /* cFiles is used to count all files of a cabinet */ - ++(p_fci_internal->cFiles); - - /* This is only true for files which will be written into the */ - /* next cabinet of the spanning folder */ - if( sizeOfFiles>payload ) { - - /* Files which data will be partially written into the current cabinet */ - if( cffile.iFolder==cffileCONTINUED_PREV_AND_NEXT || - cffile.iFolder==cffileCONTINUED_TO_NEXT - ) { - if( sizeOfFilesPrev<=payload ) { - /* The size of the uncompressed, data of a spanning file in a */ - /* spanning data */ - cbFileRemainer=sizeOfFiles-payload; - } - cffile.iFolder=cffileCONTINUED_FROM_PREV; - } else { - cffile.iFolder=0; - } - - /* write cffile into handleCFFILE1new */ - if( PFCI_WRITE(hfci, handleCFFILE1new, /* file handle */ - &cffile, /* memory buffer */ - sizeof(cffile), /* number of bytes to copy */ - err, p_fci_internal->pv) != sizeof(cffile) ) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - - *psizeFileCFFILE1new += sizeof(cffile); - /* write name of file into handleCFFILE1new */ - if( PFCI_WRITE(hfci, handleCFFILE1new, /* file handle */ - p_fci_internal->data_out, /* memory buffer */ - strlen(p_fci_internal->data_out)+1, /* number of bytes to copy */ - err, p_fci_internal->pv) != strlen(p_fci_internal->data_out)+1 ) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - - *psizeFileCFFILE1new += strlen(p_fci_internal->data_out)+1; - } - - } /* END OF while */ - p_fci_internal->cbFileRemainer=cbFileRemainer; - return TRUE; -} /* end of fci_flushfolder_copy_cffile */ - - - - -static BOOL fci_flush_folder( - HFCI hfci, - BOOL fGetNextCab, - PFNFCIGETNEXTCABINET pfnfcignc, - PFNFCISTATUS pfnfcis) -{ - int err; - int handleCFDATA1new; /* handle for new temp file */ - char szFileNameCFDATA1new[CB_MAX_FILENAME]; /* name buffer for temp file */ - int handleCFFILE1new; /* handle for new temp file */ - char szFileNameCFFILE1new[CB_MAX_FILENAME]; /* name buffer for temp file */ - UINT cbReserveCFData, cbReserveCFFolder; - char* reserved; - cab_ULONG sizeFileCFDATA1new=0; - cab_ULONG sizeFileCFFILE1new=0; - cab_ULONG sizeFileCFDATA2old; - cab_ULONG payload; - cab_ULONG read_result; - PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); - - /* test hfci */ - if (!REALLY_IS_FCI(hfci)) { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - - if ((!pfnfcignc) || (!pfnfcis)) { - p_fci_internal->perf->erfOper = FCIERR_NONE; - p_fci_internal->perf->erfType = ERROR_BAD_ARGUMENTS; - p_fci_internal->perf->fError = TRUE; - - SetLastError(ERROR_BAD_ARGUMENTS); - return FALSE; - } - - if( p_fci_internal->fGetNextCabInVain && - p_fci_internal->fNextCab ){ - /* TODO internal error */ - return FALSE; - } - - /* If there was no FCIAddFile or FCIFlushFolder has already been called */ - /* this function will return TRUE */ - if( p_fci_internal->sizeFileCFFILE1 == 0 ) { - if ( p_fci_internal->sizeFileCFDATA1 != 0 ) { - /* TODO error handling */ - return FALSE; - } - return TRUE; - } - - if (p_fci_internal->data_in==NULL || p_fci_internal->data_out==NULL ) { - /* TODO error handling */ - return FALSE; - } - - /* FCIFlushFolder has already been called... */ - if (p_fci_internal->fSplitFolder && p_fci_internal->sizeFileCFFILE2!=0) { - if (p_fci_internal->sizeFileCFFILE2==0) { - /* TODO set error code */ - return FALSE; - } - return TRUE; - } - - /* TODO check what will happen when return FALSE later */ - /* and p_fci_internal->fSplitFolder is set to FALSE */ - p_fci_internal->fSplitFolder=FALSE; - - - if( p_fci_internal->fGetNextCabInVain || - p_fci_internal->fNextCab ){ - cbReserveCFData = p_fci_internal->oldCCAB.cbReserveCFData; - cbReserveCFFolder = p_fci_internal->oldCCAB.cbReserveCFFolder; - } else { - cbReserveCFData = p_fci_internal->pccab->cbReserveCFData; - cbReserveCFFolder = p_fci_internal->pccab->cbReserveCFFolder; - } - - /* START of COPY */ - /* if there is data in p_fci_internal->data_in */ - if (p_fci_internal->cdata_in!=0) { - - if( !fci_flush_data_block(hfci, &err, pfnfcis) ) return FALSE; - - } - /* reset to get the number of data blocks of this folder which are */ - /* actually in this cabinet ( at least partially ) */ - p_fci_internal->cDataBlocks=0; - - if ( p_fci_internal->fNextCab || - p_fci_internal->fGetNextCabInVain ) { - read_result= p_fci_internal->oldCCAB.cbReserveCFHeader+ - p_fci_internal->oldCCAB.cbReserveCFFolder; - if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || - p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || - p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { - read_result+=4; - } - } else { - read_result= p_fci_internal->pccab->cbReserveCFHeader+ - p_fci_internal->pccab->cbReserveCFFolder; - if ( p_fci_internal->pccab->cbReserveCFHeader != 0 || - p_fci_internal->pccab->cbReserveCFFolder != 0 || - p_fci_internal->pccab->cbReserveCFData != 0 ) { - read_result+=4; - } - } - if (p_fci_internal->fPrevCab) { - read_result+=strlen(p_fci_internal->szPrevCab)+1 + - strlen(p_fci_internal->szPrevDisk)+1; - } - if (p_fci_internal->fNextCab) { - read_result+=strlen(p_fci_internal->pccab->szCab)+1 + - strlen(p_fci_internal->pccab->szDisk)+1; - } - - p_fci_internal->statusFolderTotal = sizeof(CFHEADER)+read_result+ - sizeof(CFFOLDER) + p_fci_internal->sizeFileCFFILE2+ - p_fci_internal->sizeFileCFDATA2 + p_fci_internal->sizeFileCFFILE1+ - p_fci_internal->sizeFileCFDATA1; - p_fci_internal->statusFolderCopied = 0; - - /* report status with pfnfcis about copied size of folder */ - if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied, - p_fci_internal->statusFolderTotal, /* TODO total folder size */ - p_fci_internal->pv) == -1) { - /* TODO set error code and abort */ - return FALSE; - } - - /* get a new temp file */ - if(!PFCI_GETTEMPFILE(hfci,szFileNameCFDATA1new,CB_MAX_FILENAME)) { - /* TODO error handling */ - return FALSE; - } - /* safety */ - if ( strlen(szFileNameCFDATA1new) >= CB_MAX_FILENAME ) { - /* TODO set error code */ - return FALSE; - } - handleCFDATA1new = PFCI_OPEN(hfci,szFileNameCFDATA1new,34050,384,&err, - p_fci_internal->pv); - - /* get a new temp file */ - if(!PFCI_GETTEMPFILE(hfci,szFileNameCFFILE1new,CB_MAX_FILENAME)) { - /* TODO error handling */ - PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - return FALSE; - } - /* safety */ - if ( strlen(szFileNameCFFILE1new) >= CB_MAX_FILENAME ) { - /* TODO set error code */ - PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - return FALSE; - } - handleCFFILE1new = PFCI_OPEN(hfci,szFileNameCFFILE1new,34050,384,&err, - p_fci_internal->pv); - - /* USE the variable read_result */ - if ( p_fci_internal->fNextCab || - p_fci_internal->fGetNextCabInVain ) { - read_result= p_fci_internal->oldCCAB.cbReserveCFHeader; - if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || - p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || - p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { - read_result+=4; - } - } else { - read_result= p_fci_internal->pccab->cbReserveCFHeader; - if ( p_fci_internal->pccab->cbReserveCFHeader != 0 || - p_fci_internal->pccab->cbReserveCFFolder != 0 || - p_fci_internal->pccab->cbReserveCFData != 0 ) { - read_result+=4; - } - } - if (p_fci_internal->fPrevCab) { - read_result+=strlen(p_fci_internal->szPrevCab)+1 + - strlen(p_fci_internal->szPrevDisk)+1; - } - read_result+= sizeof(CFHEADER) + p_fci_internal->sizeFileCFDATA2 + - p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER; - - if(p_fci_internal->sizeFileCFFILE1!=0) { - read_result+= sizeof(CFFOLDER)+p_fci_internal->pccab->cbReserveCFFolder; - } - - /* Check if multiple cabinets have to be created. */ - - /* Might be too much data for the maximum allowed cabinet size.*/ - /* When any further data will be added later, it might not */ - /* be possible to flush the cabinet, because there might */ - /* not be enough space to store the name of the following */ - /* cabinet and name of the corresponding disk. */ - /* So take care of this and get the name of the next cabinet */ - if( p_fci_internal->fGetNextCabInVain==FALSE && - p_fci_internal->fNextCab==FALSE && - ( - ( - p_fci_internal->pccab->cb < read_result + - p_fci_internal->sizeFileCFDATA1 + - p_fci_internal->sizeFileCFFILE1 + - CB_MAX_CABINET_NAME + /* next cabinet name */ - CB_MAX_DISK_NAME /* next disk name */ - ) || fGetNextCab - ) - ) { - /* save CCAB */ - memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB)); - /* increment cabinet index */ - ++(p_fci_internal->pccab->iCab); - /* get name of next cabinet */ - if (!(*pfnfcignc)(p_fci_internal->pccab, 0, /* estimated size of cab */ - p_fci_internal->pv)) { - /* TODO error handling */ - PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - return FALSE; - } - - /* Skip a few lines of code. This is catched by the next if. */ - p_fci_internal->fGetNextCabInVain=TRUE; - } - - /* too much data for cabinet */ - if( (p_fci_internal->fGetNextCabInVain || - p_fci_internal->fNextCab ) && - ( - ( - p_fci_internal->oldCCAB.cb < read_result + - p_fci_internal->sizeFileCFDATA1 + - p_fci_internal->sizeFileCFFILE1 + - strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */ - strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */ - ) || fGetNextCab - ) - ) { - p_fci_internal->fGetNextCabInVain=FALSE; - p_fci_internal->fNextCab=TRUE; - - /* return FALSE if there is not enough space left*/ - /* this should never happen */ - if (p_fci_internal->oldCCAB.cb <= - p_fci_internal->sizeFileCFFILE1 + - read_result + - strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */ - strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */ - ) { - - PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - - /* close and delete p_fci_internal->handleCFFILE1 */ - PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_DELETE(hfci,szFileNameCFFILE1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - - return FALSE; - } - - /* the folder will be split across cabinets */ - p_fci_internal->fSplitFolder=TRUE; - - } else { - /* this should never happen */ - if (p_fci_internal->fNextCab) { - /* TODO internal error */ - return FALSE; - } - } - - /* set seek of p_fci_internal->handleCFDATA1 to 0 */ - if( PFCI_SEEK(hfci,p_fci_internal->handleCFDATA1,0,SEEK_SET,&err, - p_fci_internal->pv) !=0 ) { - /* TODO wrong return value */ - PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - return FALSE; - } - /* TODO error handling of err */ - - /* save size of file CFDATA2 - required for the folder's offset to data */ - sizeFileCFDATA2old = p_fci_internal->sizeFileCFDATA2; - - if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFData+sizeof(CFDATA)))) { - p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL; - p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; - p_fci_internal->perf->fError = TRUE; - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - return FALSE; - } - - if(!fci_flushfolder_copy_cfdata(hfci, reserved, cbReserveCFData, pfnfcis, &err, - handleCFDATA1new, &sizeFileCFDATA1new, &payload - )) { - PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_FREE(hfci,reserved); - return FALSE; - } - - PFCI_FREE(hfci,reserved); - - if(!fci_flushfolder_copy_cffolder(hfci, &err, cbReserveCFFolder, - sizeFileCFDATA2old )) { - PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - return FALSE; - } - - if(!fci_flushfolder_copy_cffile(hfci, &err, handleCFFILE1new, - &sizeFileCFFILE1new, payload)) { - PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_DELETE(hfci,szFileNameCFFILE1new,&err,p_fci_internal->pv); - /* TODO error handling of err */ - return FALSE; - } - - /* close and delete p_fci_internal->handleCFDATA1 */ - PFCI_CLOSE(hfci,p_fci_internal->handleCFDATA1,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_DELETE(hfci,p_fci_internal->szFileNameCFDATA1,&err,p_fci_internal->pv); - /* TODO error handling of err */ - - /* put new CFDATA1 into hfci */ - memcpy(p_fci_internal->szFileNameCFDATA1,szFileNameCFDATA1new, - CB_MAX_FILENAME); - - /* put CFDATA1 file handle */ - PFCI_INT(hfci)->handleCFDATA1 = handleCFDATA1new; - /* set file size */ - PFCI_INT(hfci)->sizeFileCFDATA1 = sizeFileCFDATA1new; - - /* close and delete PFCI_INT(hfci)->handleCFFILE1 */ - PFCI_CLOSE(hfci,p_fci_internal->handleCFFILE1,&err,PFCI_INT(hfci)->pv); - /* TODO error handling of err */ - PFCI_DELETE(hfci,p_fci_internal->szFileNameCFFILE1,&err,p_fci_internal->pv); - /* TODO error handling of err */ - - /* put new CFFILE1 into hfci */ - memcpy(p_fci_internal->szFileNameCFFILE1,szFileNameCFFILE1new, - CB_MAX_FILENAME); - - /* put CFFILE1 file handle */ - p_fci_internal->handleCFFILE1 = handleCFFILE1new; - /* set file size */ - p_fci_internal->sizeFileCFFILE1 = sizeFileCFFILE1new; - - ++(p_fci_internal->cFolders); - - /* reset CFFolder specific information */ - p_fci_internal->cDataBlocks=0; - p_fci_internal->cCompressedBytesInFolder=0; - - return TRUE; -} /* end of fci_flush_folder */ - - - - -static BOOL fci_flush_cabinet( - HFCI hfci, - BOOL fGetNextCab, - PFNFCIGETNEXTCABINET pfnfcignc, - PFNFCISTATUS pfnfcis) -{ - int err; - CFHEADER cfheader; - struct { - cab_UWORD cbCFHeader; - cab_UBYTE cbCFFolder; - cab_UBYTE cbCFData; - } cfreserved; - CFFOLDER cffolder; - cab_ULONG read_result; - int handleCABINET; /* file handle for cabinet */ - char pszFileNameCABINET[CB_MAX_CAB_PATH+CB_MAX_CABINET_NAME];/* name buffer */ - UINT cbReserveCFHeader, cbReserveCFFolder, i; - char* reserved; - BOOL returntrue=FALSE; - PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); - - /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */ - - /* when FCIFlushCabinet was or FCIAddFile wasn't called */ - if( p_fci_internal->sizeFileCFFILE1==0 && fGetNextCab ) { - returntrue=TRUE; - } - - if (!fci_flush_folder(hfci,fGetNextCab,pfnfcignc,pfnfcis)){ - /* TODO set error */ - return FALSE; - } - - if(returntrue) return TRUE; - - if (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE) { - /* TODO internal error */ - return FALSE; - } - - if( p_fci_internal->fNextCab || - p_fci_internal->fGetNextCabInVain ) { - cbReserveCFFolder=p_fci_internal->oldCCAB.cbReserveCFFolder; - cbReserveCFHeader=p_fci_internal->oldCCAB.cbReserveCFHeader; - /* safety */ - if (strlen(p_fci_internal->oldCCAB.szCabPath)>=CB_MAX_CAB_PATH || - strlen(p_fci_internal->oldCCAB.szCab)>=CB_MAX_CABINET_NAME) { - /* TODO set error */ - return FALSE; - } - /* get the full name of the cabinet */ - memcpy(pszFileNameCABINET,p_fci_internal->oldCCAB.szCabPath, - CB_MAX_CAB_PATH); - memcpy(pszFileNameCABINET+strlen(pszFileNameCABINET), - p_fci_internal->oldCCAB.szCab, CB_MAX_CABINET_NAME); - } else { - cbReserveCFFolder=p_fci_internal->pccab->cbReserveCFFolder; - cbReserveCFHeader=p_fci_internal->pccab->cbReserveCFHeader; - /* safety */ - if (strlen(p_fci_internal->pccab->szCabPath)>=CB_MAX_CAB_PATH || - strlen(p_fci_internal->pccab->szCab)>=CB_MAX_CABINET_NAME) { - /* TODO set error */ - return FALSE; - } - /* get the full name of the cabinet */ - memcpy(pszFileNameCABINET,p_fci_internal->pccab->szCabPath, - CB_MAX_CAB_PATH); - memcpy(pszFileNameCABINET+strlen(pszFileNameCABINET), - p_fci_internal->pccab->szCab, CB_MAX_CABINET_NAME); - } - - /* create the cabinet */ - handleCABINET = PFCI_OPEN(hfci, pszFileNameCABINET, - 33538, 384, &err, p_fci_internal->pv ); - /* TODO check handle */ - /* TODO error checking of err */ - - memcpy(cfheader.signature,"!CAB",4); - cfheader.reserved1=0; - cfheader.cbCabinet= /* size of the cabinet file in bytes */ - sizeof(CFHEADER) + - p_fci_internal->sizeFileCFFOLDER + - p_fci_internal->sizeFileCFFILE2 + - p_fci_internal->sizeFileCFDATA2; - - if (p_fci_internal->fPrevCab) { - cfheader.cbCabinet+=strlen(p_fci_internal->szPrevCab)+1 + - strlen(p_fci_internal->szPrevDisk)+1; - } - if (p_fci_internal->fNextCab) { - cfheader.cbCabinet+=strlen(p_fci_internal->pccab->szCab)+1 + - strlen(p_fci_internal->pccab->szDisk)+1; - } - if( p_fci_internal->fNextCab || - p_fci_internal->fGetNextCabInVain ) { - cfheader.cbCabinet+=p_fci_internal->oldCCAB.cbReserveCFHeader; - if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || - p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || - p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { - cfheader.cbCabinet+=4; - } - } else { - cfheader.cbCabinet+=p_fci_internal->pccab->cbReserveCFHeader; - if ( p_fci_internal->pccab->cbReserveCFHeader != 0 || - p_fci_internal->pccab->cbReserveCFFolder != 0 || - p_fci_internal->pccab->cbReserveCFData != 0 ) { - cfheader.cbCabinet+=4; - } - } - - cfheader.reserved2=0; - cfheader.coffFiles= /* offset to first CFFILE section */ - cfheader.cbCabinet - p_fci_internal->sizeFileCFFILE2 - - p_fci_internal->sizeFileCFDATA2; - - cfheader.reserved3=0; - cfheader.versionMinor=3; - cfheader.versionMajor=1; - /* number of CFFOLDER entries in the cabinet */ - cfheader.cFolders=p_fci_internal->cFolders; - /* number of CFFILE entries in the cabinet */ - cfheader.cFiles=p_fci_internal->cFiles; - cfheader.flags=0; /* 1=prev cab, 2=next cabinet, 4=reserved setions */ - - if( p_fci_internal->fPrevCab ) { - cfheader.flags = cfheadPREV_CABINET; - } - - if( p_fci_internal->fNextCab ) { - cfheader.flags |= cfheadNEXT_CABINET; - } - - if( p_fci_internal->fNextCab || - p_fci_internal->fGetNextCabInVain ) { - if( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || - p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || - p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { - cfheader.flags |= cfheadRESERVE_PRESENT; - } - cfheader.setID = p_fci_internal->oldCCAB.setID; - cfheader.iCabinet = p_fci_internal->oldCCAB.iCab-1; - } else { - if( p_fci_internal->pccab->cbReserveCFHeader != 0 || - p_fci_internal->pccab->cbReserveCFFolder != 0 || - p_fci_internal->pccab->cbReserveCFData != 0 ) { - cfheader.flags |= cfheadRESERVE_PRESENT; - } - cfheader.setID = p_fci_internal->pccab->setID; - cfheader.iCabinet = p_fci_internal->pccab->iCab-1; - } - - /* write CFHEADER into cabinet file */ - if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ - &cfheader, /* memory buffer */ - sizeof(cfheader), /* number of bytes to copy */ - &err, p_fci_internal->pv) != sizeof(cfheader) ) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - - if( cfheader.flags & cfheadRESERVE_PRESENT ) { - /* NOTE: No checks for maximum value overflows as designed by MS!!! */ - cfreserved.cbCFHeader = cbReserveCFHeader; - cfreserved.cbCFFolder = cbReserveCFFolder; - if( p_fci_internal->fNextCab || - p_fci_internal->fGetNextCabInVain ) { - cfreserved.cbCFData = p_fci_internal->oldCCAB.cbReserveCFData; - } else { - cfreserved.cbCFData = p_fci_internal->pccab->cbReserveCFData; - } - /* write reserved info into cabinet file */ - if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ - &cfreserved, /* memory buffer */ - sizeof(cfreserved), /* number of bytes to copy */ - &err, p_fci_internal->pv) != sizeof(cfreserved) ) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - } - - /* add optional reserved area */ - if (cbReserveCFHeader!=0) { - if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFHeader))) { - p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL; - p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; - p_fci_internal->perf->fError = TRUE; - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; - } - for(i=0;ipv) != cbReserveCFHeader ) { - PFCI_FREE(hfci, reserved); - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - PFCI_FREE(hfci, reserved); - } - - if( cfheader.flags & cfheadPREV_CABINET ) { - if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ - p_fci_internal->szPrevCab, /* memory buffer */ - strlen(p_fci_internal->szPrevCab)+1, /* number of bytes to copy */ - &err, p_fci_internal->pv) != strlen(p_fci_internal->szPrevCab)+1 ) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - - if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ - p_fci_internal->szPrevDisk, /* memory buffer */ - strlen(p_fci_internal->szPrevDisk)+1, /* number of bytes to copy */ - &err, p_fci_internal->pv) != strlen(p_fci_internal->szPrevDisk)+1 ) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - } - - if( cfheader.flags & cfheadNEXT_CABINET ) { - if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ - p_fci_internal->pccab->szCab, /* memory buffer */ - strlen(p_fci_internal->pccab->szCab)+1, /* number of bytes to copy */ - &err, p_fci_internal->pv) != strlen(p_fci_internal->pccab->szCab)+1 ) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - - if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ - p_fci_internal->pccab->szDisk, /* memory buffer */ - strlen(p_fci_internal->pccab->szDisk)+1, /* number of bytes to copy */ - &err, p_fci_internal->pv) != strlen(p_fci_internal->pccab->szDisk)+1 ) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - } - - /* set seek of p_fci_internal->handleCFFOLDER to 0 */ - if( PFCI_SEEK(hfci,p_fci_internal->handleCFFOLDER, - 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) { - /* TODO wrong return value */ - } - /* TODO error handling of err */ - - /* while not all CFFOLDER structures have been copied into the cabinet do */ - while(!FALSE) { - /* use the variable read_result */ - /* read cffolder of p_fci_internal->handleCFFOLDER */ - read_result = PFCI_READ(hfci, p_fci_internal->handleCFFOLDER, /* handle */ - &cffolder, /* memory buffer */ - sizeof(cffolder), /* number of bytes to copy */ - &err, p_fci_internal->pv); - if( read_result != sizeof(cffolder) ) { - if( read_result == 0 ) break; /*ALL CFFOLDER structures have been copied*/ - /* TODO read error */ - return FALSE; - } - /* TODO error handling of err */ - - /* add size of header size of all CFFOLDERs and size of all CFFILEs */ - cffolder.coffCabStart += - p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER + - sizeof(CFHEADER); - if( p_fci_internal->fNextCab || - p_fci_internal->fGetNextCabInVain ) { - cffolder.coffCabStart+=p_fci_internal->oldCCAB.cbReserveCFHeader; - } else { - cffolder.coffCabStart+=p_fci_internal->pccab->cbReserveCFHeader; - } - - if (p_fci_internal->fPrevCab) { - cffolder.coffCabStart += strlen(p_fci_internal->szPrevCab)+1 + - strlen(p_fci_internal->szPrevDisk)+1; - } - - if (p_fci_internal->fNextCab) { - cffolder.coffCabStart += strlen(p_fci_internal->oldCCAB.szCab)+1 + - strlen(p_fci_internal->oldCCAB.szDisk)+1; - } - - if( p_fci_internal->fNextCab || - p_fci_internal->fGetNextCabInVain ) { - cffolder.coffCabStart += p_fci_internal->oldCCAB.cbReserveCFHeader; - if( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || - p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || - p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { - cffolder.coffCabStart += 4; - } - } else { - cffolder.coffCabStart += p_fci_internal->pccab->cbReserveCFHeader; - if( p_fci_internal->pccab->cbReserveCFHeader != 0 || - p_fci_internal->pccab->cbReserveCFFolder != 0 || - p_fci_internal->pccab->cbReserveCFData != 0 ) { - cffolder.coffCabStart += 4; - } - } - - /* write cffolder to cabinet file */ - if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ - &cffolder, /* memory buffer */ - sizeof(cffolder), /* number of bytes to copy */ - &err, p_fci_internal->pv) != sizeof(cffolder) ) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - - /* add optional reserved area */ - - /* This allocation and freeing at each CFFolder block is a bit */ - /* inefficent, but it's harder to forget about freeing the buffer :-). */ - /* Reserved areas are used seldom besides that... */ - if (cbReserveCFFolder!=0) { - if(!(reserved = PFCI_ALLOC(hfci, cbReserveCFFolder))) { - p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL; - p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; - p_fci_internal->perf->fError = TRUE; - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; - } - - if( PFCI_READ(hfci, p_fci_internal->handleCFFOLDER, /* file handle */ - reserved, /* memory buffer */ - cbReserveCFFolder, /* number of bytes to copy */ - &err, p_fci_internal->pv) != cbReserveCFFolder ) { - PFCI_FREE(hfci, reserved); - /* TODO read error */ - return FALSE; - } - /* TODO error handling of err */ - - if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ - reserved, /* memory buffer */ - cbReserveCFFolder, /* number of bytes to copy */ - &err, p_fci_internal->pv) != cbReserveCFFolder ) { - PFCI_FREE(hfci, reserved); - /* TODO read error */ - return FALSE; - } - /* TODO error handling of err */ - - PFCI_FREE(hfci, reserved); - } - - } /* END OF while */ - - /* set seek of p_fci_internal->handleCFFILE2 to 0 */ - if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE2, - 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) { - /* TODO wrong return value */ - } - /* TODO error handling of err */ - - /* while not all CFFILE structures have been copied to the cabinet do */ - while(!FALSE) { - /* REUSE the variable read_result */ - /* REUSE the buffer p_fci_internal->data_out AGAIN */ - /* read a block from p_fci_internal->handleCFFILE2 */ - read_result = PFCI_READ(hfci, p_fci_internal->handleCFFILE2 /* handle */, - p_fci_internal->data_out, /* memory buffer */ - 32768, /* number of bytes to copy */ - &err, p_fci_internal->pv); - if( read_result == 0 ) break; /* ALL CFFILE structures have been copied */ - /* TODO error handling of err */ - - /* write the block to the cabinet file */ - if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ - p_fci_internal->data_out, /* memory buffer */ - read_result, /* number of bytes to copy */ - &err, p_fci_internal->pv) != read_result ) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - - if (p_fci_internal->fSplitFolder==FALSE) { - p_fci_internal->statusFolderCopied = 0; - p_fci_internal->statusFolderTotal = p_fci_internal->sizeFileCFDATA2+ - p_fci_internal->sizeFileCFFILE2; - } - p_fci_internal->statusFolderCopied += read_result; - -/* TODO is this correct */ - /* report status with pfnfcis about copied size of folder */ - if( (*pfnfcis)(statusFolder, - p_fci_internal->statusFolderCopied, /* length of copied blocks */ - p_fci_internal->statusFolderTotal, /* total size of folder */ - p_fci_internal->pv) == -1) { - /* TODO set error code and abort */ - return FALSE; - } - - } /* END OF while */ - - /* set seek of p_fci_internal->handleCFDATA2 to 0 */ - if( PFCI_SEEK(hfci,p_fci_internal->handleCFDATA2, - 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) { - /* TODO wrong return value */ - return FALSE; - } - /* TODO error handling of err */ - - /* reset the number of folders for the next cabinet */ - p_fci_internal->cFolders=0; - /* reset the number of files for the next cabinet */ - p_fci_internal->cFiles=0; - - /* while not all CFDATA structures have been copied to the cabinet do */ - while(!FALSE) { - /* REUSE the variable read_result AGAIN */ - /* REUSE the buffer p_fci_internal->data_out AGAIN */ - /* read a block from p_fci_internal->handleCFDATA2 */ - read_result = PFCI_READ(hfci, p_fci_internal->handleCFDATA2 /* handle */, - p_fci_internal->data_out, /* memory buffer */ - 32768, /* number of bytes to copy */ - &err, p_fci_internal->pv); - if( read_result == 0 ) break; /* ALL CFDATA structures have been copied */ - /* TODO error handling of err */ - - /* write the block to the cabinet file */ - if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ - p_fci_internal->data_out, /* memory buffer */ - read_result, /* number of bytes to copy */ - &err, p_fci_internal->pv) != read_result ) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - - p_fci_internal->statusFolderCopied += read_result; - /* report status with pfnfcis about copied size of folder */ - if( (*pfnfcis)(statusFolder, - p_fci_internal->statusFolderCopied, /* length of copied blocks */ - p_fci_internal->statusFolderTotal, /* total size of folder */ - p_fci_internal->pv) == -1) { - /* TODO set error code and abort */ - return FALSE; - } - } /* END OF while */ - - /* set seek of the cabinet file to 0 */ - if( PFCI_SEEK(hfci, handleCABINET, - 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) { - /* TODO wrong return value */ - } - /* TODO error handling of err */ - - /* write the signature "MSCF" into the cabinet file */ - memcpy( cfheader.signature, "MSCF", 4 ); - if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ - &cfheader, /* memory buffer */ - 4, /* number of bytes to copy */ - &err, p_fci_internal->pv) != 4 ) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - - /* close the cabinet file */ - PFCI_CLOSE(hfci,handleCABINET,&err,p_fci_internal->pv); - /* TODO error handling of err */ - - -/* COPIED FROM FCIDestroy */ - - PFCI_CLOSE (hfci, p_fci_internal->handleCFDATA2,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_DELETE(hfci, p_fci_internal->szFileNameCFDATA2, &err, - p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_CLOSE (hfci, p_fci_internal->handleCFFILE2,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFILE2, &err, - p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_CLOSE (hfci, p_fci_internal->handleCFFOLDER,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFOLDER, &err, - p_fci_internal->pv); - /* TODO error handling of err */ - -/* END OF copied from FCIDestroy */ - - /* get 3 temporary files and open them */ - /* write names and handles to hfci */ - - - p_fci_internal->sizeFileCFDATA2 = 0; - p_fci_internal->sizeFileCFFILE2 = 0; - p_fci_internal->sizeFileCFFOLDER = 0; - -/* COPIED FROM FCICreate */ - - /* CFDATA with checksum and ready to be copied into cabinet */ - if( !PFCI_GETTEMPFILE(hfci, p_fci_internal->szFileNameCFDATA2, - CB_MAX_FILENAME)) { - /* TODO error handling */ - return FALSE; - } - /* safety */ - if ( strlen(p_fci_internal->szFileNameCFDATA2) >= CB_MAX_FILENAME ) { - /* TODO set error code */ - return FALSE; - } - p_fci_internal->handleCFDATA2 = PFCI_OPEN(hfci, - p_fci_internal->szFileNameCFDATA2, 34050, 384, &err, p_fci_internal->pv); - /* TODO check handle */ - /* TODO error checking of err */ - - /* array of all CFFILE in a folder, ready to be copied into cabinet */ - if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE2, - CB_MAX_FILENAME)) { - /* TODO error handling */ - return FALSE; - } - /* safety */ - if ( strlen(p_fci_internal->szFileNameCFFILE2) >= CB_MAX_FILENAME ) { - /* TODO set error code */ - return FALSE; - } - p_fci_internal->handleCFFILE2 = PFCI_OPEN(hfci, - p_fci_internal->szFileNameCFFILE2, 34050, 384, &err, p_fci_internal->pv); - /* TODO check handle */ - /* TODO error checking of err */ - - /* array of all CFFILE in a folder, ready to be copied into cabinet */ - if (!PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFOLDER,CB_MAX_FILENAME)) { - /* TODO error handling */ - return FALSE; - } - /* safety */ - if ( strlen(p_fci_internal->szFileNameCFFOLDER) >= CB_MAX_FILENAME ) { - /* TODO set error code */ - return FALSE; - } - p_fci_internal->handleCFFOLDER = PFCI_OPEN(hfci, - p_fci_internal->szFileNameCFFOLDER, 34050, 384, &err, p_fci_internal->pv); - /* TODO check handle */ - /* TODO error checking of err */ - -/* END OF copied from FCICreate */ - - - /* TODO close and delete new files when return FALSE */ - - - /* report status with pfnfcis about copied size of folder */ - if( (*pfnfcis)(statusCabinet, p_fci_internal->statusFolderTotal, /* TODO estimated cabinet file size */ - cfheader.cbCabinet, /* real cabinet file size */ p_fci_internal->pv) == -1) { - /* TODO set error code and abort */ - return FALSE; - } - - p_fci_internal->fPrevCab=TRUE; - /* The sections szPrevCab and szPrevDisk are not being updated, because */ - /* MS CABINET.DLL always puts the first cabinet name and disk into them */ - - if (p_fci_internal->fNextCab) { - p_fci_internal->fNextCab=FALSE; - - if (p_fci_internal->sizeFileCFFILE1==0 && p_fci_internal->sizeFileCFDATA1!=0) { - /* THIS CAN NEVER HAPPEN */ - /* TODO set error code */ - return FALSE; - } - -/* COPIED FROM FCIAddFile and modified */ - - /* REUSE the variable read_result */ - if (p_fci_internal->fGetNextCabInVain) { - read_result=p_fci_internal->oldCCAB.cbReserveCFHeader; - if(p_fci_internal->sizeFileCFFILE1!=0) { - read_result+=p_fci_internal->oldCCAB.cbReserveCFFolder; - } - if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || - p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || - p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { - read_result+=4; - } - } else { - read_result=p_fci_internal->pccab->cbReserveCFHeader; - if(p_fci_internal->sizeFileCFFILE1!=0) { - read_result+=p_fci_internal->pccab->cbReserveCFFolder; - } - if ( p_fci_internal->pccab->cbReserveCFHeader != 0 || - p_fci_internal->pccab->cbReserveCFFolder != 0 || - p_fci_internal->pccab->cbReserveCFData != 0 ) { - read_result+=4; - } - } - if ( p_fci_internal->fPrevCab ) { - read_result+= strlen(p_fci_internal->szPrevCab)+1+ - strlen(p_fci_internal->szPrevDisk)+1; - } - read_result+= p_fci_internal->sizeFileCFDATA1 + - p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 + - p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER + - sizeof(CFHEADER) + - sizeof(CFFOLDER); /* set size of new CFFolder entry */ - - if( p_fci_internal->fNewPrevious ) { - memcpy(p_fci_internal->szPrevCab, p_fci_internal->oldCCAB.szCab, - CB_MAX_CABINET_NAME); - memcpy(p_fci_internal->szPrevDisk, p_fci_internal->oldCCAB.szDisk, - CB_MAX_DISK_NAME); - p_fci_internal->fNewPrevious=FALSE; - } - - /* too much data for the maximum size of a cabinet */ - if( p_fci_internal->fGetNextCabInVain==FALSE && - p_fci_internal->pccab->cb < read_result ) { - return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis); - } - - /* Might be too much data for the maximum size of a cabinet.*/ - /* When any further data will be added later, it might not */ - /* be possible to flush the cabinet, because there might */ - /* not be enough space to store the name of the following */ - /* cabinet and name of the corresponding disk. */ - /* So take care of this and get the name of the next cabinet */ - if (p_fci_internal->fGetNextCabInVain==FALSE && ( - p_fci_internal->pccab->cb < read_result + - CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME - )) { - /* save CCAB */ - memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB)); - /* increment cabinet index */ - ++(p_fci_internal->pccab->iCab); - /* get name of next cabinet */ - if (!(*pfnfcignc)(p_fci_internal->pccab, 0, /* estimated size of cab */ - p_fci_internal->pv)) { - /* TODO error handling */ - return FALSE; - } - /* Skip a few lines of code. This is catched by the next if. */ - p_fci_internal->fGetNextCabInVain=TRUE; - } - - /* too much data for cabinet */ - if (p_fci_internal->fGetNextCabInVain && ( - p_fci_internal->oldCCAB.cb < read_result + - strlen(p_fci_internal->oldCCAB.szCab)+1+ - strlen(p_fci_internal->oldCCAB.szDisk)+1 - )) { - p_fci_internal->fGetNextCabInVain=FALSE; - p_fci_internal->fNextCab=TRUE; - return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis); - } - - /* if the FolderThreshold has been reached flush the folder automatically */ - if( p_fci_internal->fGetNextCabInVain ) { - if( p_fci_internal->cCompressedBytesInFolder >= - p_fci_internal->oldCCAB.cbFolderThresh) { - return FCIFlushFolder(hfci, pfnfcignc, pfnfcis); - } - } else { - if( p_fci_internal->cCompressedBytesInFolder >= - p_fci_internal->pccab->cbFolderThresh) { - return FCIFlushFolder(hfci, pfnfcignc, pfnfcis); - } - } - -/* END OF COPIED FROM FCIAddFile and modified */ - - if( p_fci_internal->sizeFileCFFILE1>0 ) { - if( !FCIFlushFolder(hfci, pfnfcignc, pfnfcis) ) return FALSE; - p_fci_internal->fNewPrevious=TRUE; - } - } else { - p_fci_internal->fNewPrevious=FALSE; - if( p_fci_internal->sizeFileCFFILE1>0 || p_fci_internal->sizeFileCFDATA1) { - /* THIS MAY NEVER HAPPEN */ - /* TODO set error structures */ - return FALSE; - } - } - - return TRUE; -} /* end of fci_flush_cabinet */ - - - - - -/*********************************************************************** - * FCIAddFile (CABINET.11) - * - * FCIAddFile adds a file to the to be created cabinet file - * - * PARAMS - * hfci [I] An HFCI from FCICreate - * pszSourceFile [I] A pointer to a C string which contains the name and - * location of the file which will be added to the cabinet - * pszFileName [I] A pointer to a C string which contains the name under - * which the file will be stored in the cabinet - * fExecute [I] A boolean value which indicates if the file should be - * executed after extraction of self extracting - * executables - * pfnfcignc [I] A pointer to a function which gets information about - * the next cabinet - * pfnfcis [IO] A pointer to a function which will report status - * information about the compression process - * pfnfcioi [I] A pointer to a function which reports file attributes - * and time and date information - * typeCompress [I] Compression type - * - * RETURNS - * On success, returns TRUE - * On failure, returns FALSE - * - * INCLUDES - * fci.h - * - */ -BOOL __cdecl FCIAddFile( - HFCI hfci, - char *pszSourceFile, - char *pszFileName, - BOOL fExecute, - PFNFCIGETNEXTCABINET pfnfcignc, - PFNFCISTATUS pfnfcis, - PFNFCIGETOPENINFO pfnfcigoi, - TCOMP typeCompress) -{ - int err; - CFFILE cffile; - cab_ULONG read_result; - int file_handle; - PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); - - /* test hfci */ - if (!REALLY_IS_FCI(hfci)) { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - - if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) || - (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) { - p_fci_internal->perf->erfOper = FCIERR_NONE; - p_fci_internal->perf->erfType = ERROR_BAD_ARGUMENTS; - p_fci_internal->perf->fError = TRUE; - - SetLastError(ERROR_BAD_ARGUMENTS); - return FALSE; - } - - /* TODO check if pszSourceFile??? */ - - if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) { - /* TODO internal error */ - return FALSE; - } - - if(p_fci_internal->fNextCab) { - /* TODO internal error */ - return FALSE; - } - - cffile.cbFile=0; /* size of the to be added file*/ - /* offset of the uncompressed file in the folder */ - cffile.uoffFolderStart=p_fci_internal->cDataBlocks*CAB_BLOCKMAX + p_fci_internal->cdata_in; - /* number of folder in the cabinet or special 0=first */ - cffile.iFolder = p_fci_internal->cFolders; - - /* allocation of memory */ - if (p_fci_internal->data_in==NULL) { - if (p_fci_internal->cdata_in!=0) { - /* TODO error handling */ - return FALSE; - } - if (p_fci_internal->data_out!=NULL) { - /* TODO error handling */ - return FALSE; - } - if(!(p_fci_internal->data_in = (char*)PFCI_ALLOC(hfci,CB_MAX_CHUNK))) { - p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL; - p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; - p_fci_internal->perf->fError = TRUE; - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; - } - if (p_fci_internal->data_out==NULL) { - if(!(p_fci_internal->data_out = PFCI_ALLOC(hfci, 2 * CB_MAX_CHUNK))){ - p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL; - p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; - p_fci_internal->perf->fError = TRUE; - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return FALSE; - } - } - } - - if (p_fci_internal->data_out==NULL) { - PFCI_FREE(hfci,p_fci_internal->data_in); - /* TODO error handling */ - return FALSE; - } - - /* get information about the file */ - file_handle=(*pfnfcigoi)(pszSourceFile, &(cffile.date), &(cffile.time), - &(cffile.attribs), &err, p_fci_internal->pv); - /* TODO check file_handle */ - /* TODO error handling of err */ - - if (fExecute) { cffile.attribs |= _A_EXEC; } - - /* REUSE the variable read_result */ - if (p_fci_internal->fGetNextCabInVain) { - read_result=p_fci_internal->oldCCAB.cbReserveCFHeader + - p_fci_internal->oldCCAB.cbReserveCFFolder; - if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || - p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || - p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { - read_result+=4; - } - } else { - read_result=p_fci_internal->pccab->cbReserveCFHeader + - p_fci_internal->pccab->cbReserveCFFolder; - if ( p_fci_internal->pccab->cbReserveCFHeader != 0 || - p_fci_internal->pccab->cbReserveCFFolder != 0 || - p_fci_internal->pccab->cbReserveCFData != 0 ) { - read_result+=4; - } - } - if ( p_fci_internal->fPrevCab ) { - read_result+= strlen(p_fci_internal->szPrevCab)+1+ - strlen(p_fci_internal->szPrevDisk)+1; - } - if ( p_fci_internal->fNextCab ) { /* this is never the case */ - read_result+= strlen(p_fci_internal->pccab->szCab)+1+ - strlen(p_fci_internal->pccab->szDisk)+1; - } - - read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 + - p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 + - p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER + - sizeof(CFHEADER) + - sizeof(CFFOLDER); /* size of new CFFolder entry */ - - /* Might be too much data for the maximum size of a cabinet.*/ - /* When any further data will be added later, it might not */ - /* be possible to flush the cabinet, because there might */ - /* not be enough space to store the name of the following */ - /* cabinet and name of the corresponding disk. */ - /* So take care of this and get the name of the next cabinet */ - if( p_fci_internal->fGetNextCabInVain==FALSE && - p_fci_internal->fNextCab==FALSE && - ( p_fci_internal->pccab->cb < read_result + - CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME - ) - ) { - /* save CCAB */ - memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB)); - /* increment cabinet index */ - ++(p_fci_internal->pccab->iCab); - /* get name of next cabinet */ - if (!(*pfnfcignc)(p_fci_internal->pccab, 0,/* TODO estimated size of cab */ - p_fci_internal->pv)) { - /* TODO error handling */ - return FALSE; - } - /* Skip a few lines of code. This is catched by the next if. */ - p_fci_internal->fGetNextCabInVain=TRUE; - } - - if( p_fci_internal->fGetNextCabInVain && - p_fci_internal->fNextCab - ) { - /* THIS CAN NEVER HAPPEN */ - /* TODO set error code*/ - return FALSE; - } - - /* too much data for cabinet */ - if( p_fci_internal->fGetNextCabInVain && - ( - p_fci_internal->oldCCAB.cb < read_result + - strlen(p_fci_internal->pccab->szCab)+1+ - strlen(p_fci_internal->pccab->szDisk)+1 - )) { - p_fci_internal->fGetNextCabInVain=FALSE; - p_fci_internal->fNextCab=TRUE; - if(!fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis)) return FALSE; - } - - if( p_fci_internal->fNextCab ) { - /* THIS MAY NEVER HAPPEN */ - /* TODO set error code*/ - return FALSE; - } - - /* read the contents of the file blockwize*/ - while (!FALSE) { - if (p_fci_internal->cdata_in > CAB_BLOCKMAX) { - /* TODO internal error */ - return FALSE; - } - - read_result = PFCI_READ(hfci, file_handle /* file handle */, - (p_fci_internal->data_in + p_fci_internal->cdata_in) /* memory buffer */, - (CAB_BLOCKMAX - p_fci_internal->cdata_in) /* number of bytes to copy */, - &err, p_fci_internal->pv); - /* TODO error handling of err */ - - if( read_result==0 ) break; - - /* increment the block size */ - p_fci_internal->cdata_in += read_result; - - /* increment the file size */ - cffile.cbFile += read_result; - - - if ( p_fci_internal->cdata_in > CAB_BLOCKMAX ) { - /* TODO report internal error */ - return FALSE; - } - /* write a whole block */ - if ( p_fci_internal->cdata_in == CAB_BLOCKMAX ) { - - if( !fci_flush_data_block(hfci, &err, pfnfcis) ) return FALSE; - } - } - - /* close the file from FCIAddFile */ - PFCI_CLOSE(hfci,file_handle,&err,p_fci_internal->pv); - /* TODO error handling of err */ - - /* write cffile to p_fci_internal->handleCFFILE1 */ - if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE1, /* file handle */ - &cffile, sizeof(cffile),&err, p_fci_internal->pv) != sizeof(cffile) ) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - - p_fci_internal->sizeFileCFFILE1 += sizeof(cffile); - - /* append the name of file*/ - if (strlen(pszFileName)>=CB_MAX_FILENAME) { - /* IMPOSSIBLE */ - /* TODO set error code */ - return FALSE; - } - if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE1, /* file handle */ - pszFileName, strlen(pszFileName)+1, &err, p_fci_internal->pv) - != strlen(pszFileName)+1 ) { - /* TODO write error */ - return FALSE; - } - /* TODO error handling of err */ - - p_fci_internal->sizeFileCFFILE1 += strlen(pszFileName)+1; - - /* REUSE the variable read_result */ - if (p_fci_internal->fGetNextCabInVain || - p_fci_internal->fNextCab - ) { - read_result=p_fci_internal->oldCCAB.cbReserveCFHeader + - p_fci_internal->oldCCAB.cbReserveCFFolder; - if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || - p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || - p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { - read_result+=4; - } - } else { - read_result=p_fci_internal->pccab->cbReserveCFHeader + - p_fci_internal->pccab->cbReserveCFFolder; - if ( p_fci_internal->pccab->cbReserveCFHeader != 0 || - p_fci_internal->pccab->cbReserveCFFolder != 0 || - p_fci_internal->pccab->cbReserveCFData != 0 ) { - read_result+=4; - } - } - if ( p_fci_internal->fPrevCab ) { - read_result+= strlen(p_fci_internal->szPrevCab)+1+ - strlen(p_fci_internal->szPrevDisk)+1; - } - if ( p_fci_internal->fNextCab ) { /* this is never the case */ - read_result+= strlen(p_fci_internal->pccab->szCab)+1+ - strlen(p_fci_internal->pccab->szDisk)+1; - } - read_result+= p_fci_internal->sizeFileCFDATA1 + - p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 + - p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER + - sizeof(CFHEADER) + - sizeof(CFFOLDER); /* set size of new CFFolder entry */ - - /* too much data for the maximum size of a cabinet */ - /* (ignoring the unflushed data block) */ - if( p_fci_internal->fGetNextCabInVain==FALSE && - p_fci_internal->fNextCab==FALSE && /* this is always the case */ - p_fci_internal->pccab->cb < read_result ) { - return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis); - } - - /* Might be too much data for the maximum size of a cabinet.*/ - /* When any further data will be added later, it might not */ - /* be possible to flush the cabinet, because there might */ - /* not be enough space to store the name of the following */ - /* cabinet and name of the corresponding disk. */ - /* So take care of this and get the name of the next cabinet */ - /* (ignoring the unflushed data block) */ - if( p_fci_internal->fGetNextCabInVain==FALSE && - p_fci_internal->fNextCab==FALSE && - ( p_fci_internal->pccab->cb < read_result + - CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME - ) - ) { - /* save CCAB */ - memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB)); - /* increment cabinet index */ - ++(p_fci_internal->pccab->iCab); - /* get name of next cabinet */ - if (!(*pfnfcignc)(p_fci_internal->pccab, 0,/* TODO estimated size of cab */ - p_fci_internal->pv)) { - /* TODO error handling */ - return FALSE; - } - /* Skip a few lines of code. This is catched by the next if. */ - p_fci_internal->fGetNextCabInVain=TRUE; - } - - if( p_fci_internal->fGetNextCabInVain && - p_fci_internal->fNextCab - ) { - /* THIS CAN NEVER HAPPEN */ - /* TODO set error code*/ - return FALSE; - } - - /* too much data for cabinet */ - if( (p_fci_internal->fGetNextCabInVain || - p_fci_internal->fNextCab) && ( - p_fci_internal->oldCCAB.cb < read_result + - strlen(p_fci_internal->pccab->szCab)+1+ - strlen(p_fci_internal->pccab->szDisk)+1 - )) { - - p_fci_internal->fGetNextCabInVain=FALSE; - p_fci_internal->fNextCab=TRUE; - return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis); - } - - if( p_fci_internal->fNextCab ) { - /* THIS MAY NEVER HAPPEN */ - /* TODO set error code*/ - return FALSE; - } - - /* if the FolderThreshold has been reached flush the folder automatically */ - if( p_fci_internal->fGetNextCabInVain ) { - if( p_fci_internal->cCompressedBytesInFolder >= - p_fci_internal->oldCCAB.cbFolderThresh) { - return FCIFlushFolder(hfci, pfnfcignc, pfnfcis); - } - } else { - if( p_fci_internal->cCompressedBytesInFolder >= - p_fci_internal->pccab->cbFolderThresh) { - return FCIFlushFolder(hfci, pfnfcignc, pfnfcis); - } - } - - return TRUE; -} /* end of FCIAddFile */ - - - - - -/*********************************************************************** - * FCIFlushFolder (CABINET.12) - * - * FCIFlushFolder completes the CFFolder structure under construction. - * - * All further data which is added by FCIAddFile will be associateed to - * the next CFFolder structure. - * - * FCIFlushFolder will be called by FCIAddFile automatically if the - * threshold (stored in the member cbFolderThresh of the CCAB structure - * pccab passed to FCICreate) is exceeded. - * - * FCIFlushFolder will be called by FCIFlushFolder automatically before - * any data will be written into the cabinet file. - * - * PARAMS - * hfci [I] An HFCI from FCICreate - * pfnfcignc [I] A pointer to a function which gets information about - * the next cabinet - * pfnfcis [IO] A pointer to a function which will report status - * information about the compression process - * - * RETURNS - * On success, returns TRUE - * On failure, returns FALSE - * - * INCLUDES - * fci.h - * - */ -BOOL __cdecl FCIFlushFolder( - HFCI hfci, - PFNFCIGETNEXTCABINET pfnfcignc, - PFNFCISTATUS pfnfcis) -{ - return fci_flush_folder(hfci,FALSE,pfnfcignc,pfnfcis); -} /* end of FCIFlushFolder */ - - - -/*********************************************************************** - * FCIFlushCabinet (CABINET.13) - * - * FCIFlushCabinet stores the data which has been added by FCIAddFile - * into the cabinet file. If the maximum cabinet size (stored in the - * member cb of the CCAB structure pccab passed to FCICreate) has been - * exceeded FCIFlushCabinet will be called automatic by FCIAddFile. - * The remaining data still has to be flushed manually by calling - * FCIFlushCabinet. - * - * After FCIFlushCabinet has been called (manually) FCIAddFile must - * NOT be called again. Then hfci has to be released by FCIDestroy. - * - * PARAMS - * hfci [I] An HFCI from FCICreate - * fGetNextCab [I] Whether you want to add additional files to a - * cabinet set (TRUE) or whether you want to - * finalize it (FALSE) - * pfnfcignc [I] A pointer to a function which gets information about - * the next cabinet - * pfnfcis [IO] A pointer to a function which will report status - * information about the compression process - * - * RETURNS - * On success, returns TRUE - * On failure, returns FALSE - * - * INCLUDES - * fci.h - * - */ -BOOL __cdecl FCIFlushCabinet( - HFCI hfci, - BOOL fGetNextCab, - PFNFCIGETNEXTCABINET pfnfcignc, - PFNFCISTATUS pfnfcis) -{ - PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); - - if(!fci_flush_cabinet(hfci,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE; - - while( p_fci_internal->sizeFileCFFILE1>0 || - p_fci_internal->sizeFileCFFILE2>0 ) { - if(!fci_flush_cabinet(hfci,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE; - } - - return TRUE; -} /* end of FCIFlushCabinet */ - - -/*********************************************************************** - * FCIDestroy (CABINET.14) - * - * Frees a handle created by FCICreate. - * Only reason for failure would be an invalid handle. - * - * PARAMS - * hfci [I] The HFCI to free - * - * RETURNS - * TRUE for success - * FALSE for failure - */ -BOOL __cdecl FCIDestroy(HFCI hfci) -{ - int err; - PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); - if (REALLY_IS_FCI(hfci)) { - - /* before hfci can be removed all temporary files must be closed */ - /* and deleted */ - p_fci_internal->FCI_Intmagic = 0; - - PFCI_CLOSE (hfci, p_fci_internal->handleCFDATA1,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_DELETE(hfci, p_fci_internal->szFileNameCFDATA1, &err, - p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_CLOSE (hfci, p_fci_internal->handleCFFILE1,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFILE1, &err, - p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_CLOSE (hfci, p_fci_internal->handleCFDATA2,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_DELETE(hfci, p_fci_internal->szFileNameCFDATA2, &err, - p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_CLOSE (hfci, p_fci_internal->handleCFFILE2,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFILE2, &err, - p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_CLOSE (hfci, p_fci_internal->handleCFFOLDER,&err,p_fci_internal->pv); - /* TODO error handling of err */ - PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFOLDER, &err, - p_fci_internal->pv); - /* TODO error handling of err */ - - /* data in and out buffers have to be removed */ - if (p_fci_internal->data_in!=NULL) - PFCI_FREE(hfci, p_fci_internal->data_in); - if (p_fci_internal->data_out!=NULL) - PFCI_FREE(hfci, p_fci_internal->data_out); - - /* hfci can now be removed */ - PFCI_FREE(hfci, hfci); - return TRUE; - } else { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - -} /* end of FCIDestroy */ +/* + * File Compression Interface + * + * Copyright 2002 Patrik Stridvall + * Copyright 2005 Gerold Jens Wucherpfennig + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + +There is still some work to be done: + +- currently no support for big-endian machines +- the ERF error structure aren't used on error +- no real compression yet +- unknown behaviour if files>4GB or cabinet >4GB +- incorrect status information +- check if the maximum size for a cabinet is too small to store any data +- call pfnfcignc on exactly the same position as MS FCIAddFile in every case + +*/ + + + +#include "config.h" + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "fci.h" +#include "cabinet.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(cabinet); + +typedef struct { + cab_UBYTE signature[4]; /* !CAB for unfinished cabinets else MSCF */ + cab_ULONG reserved1; + cab_ULONG cbCabinet; /* size of the cabinet file in bytes*/ + cab_ULONG reserved2; + cab_ULONG coffFiles; /* offset to first CFFILE section */ + cab_ULONG reserved3; + cab_UBYTE versionMinor; /* 3 */ + cab_UBYTE versionMajor; /* 1 */ + cab_UWORD cFolders; /* number of CFFOLDER entries in the cabinet*/ + cab_UWORD cFiles; /* number of CFFILE entries in the cabinet*/ + cab_UWORD flags; /* 1=prev cab, 2=next cabinet, 4=reserved setions*/ + cab_UWORD setID; /* identification number of all cabinets in a set*/ + cab_UWORD iCabinet; /* number of the cabinet in a set */ + /* additional area if "flags" were set*/ +} CFHEADER; /* minimum 36 bytes */ + +typedef struct { + cab_ULONG coffCabStart; /* offset to the folder's first CFDATA section */ + cab_UWORD cCFData; /* number of this folder's CFDATA sections */ + cab_UWORD typeCompress; /* compression type of data in CFDATA section*/ + /* additional area if reserve flag was set */ +} CFFOLDER; /* minumum 8 bytes */ + +typedef struct { + cab_ULONG cbFile; /* size of the uncompressed file in bytes */ + cab_ULONG uoffFolderStart; /* offset of the uncompressed file in the folder */ + cab_UWORD iFolder; /* number of folder in the cabinet 0=first */ + /* for special values see below this structure*/ + cab_UWORD date; /* last modification date*/ + cab_UWORD time; /* last modification time*/ + cab_UWORD attribs; /* DOS fat attributes and UTF indicator */ + /* ... and a C string with the name of the file */ +} CFFILE; /* 16 bytes + name of file */ + + +typedef struct { + cab_ULONG csum; /* checksum of this entry*/ + cab_UWORD cbData; /* number of compressed bytes */ + cab_UWORD cbUncomp; /* number of bytes when data is uncompressed */ + /* optional reserved area */ + /* compressed data */ +} CFDATA; + + +/*********************************************************************** + * FCICreate (CABINET.10) + * + * FCICreate is provided with several callbacks and + * returns a handle which can be used to create cabinet files. + * + * PARAMS + * perf [IO] A pointer to an ERF structure. When FCICreate + * returns an error condition, error information may + * be found here as well as from GetLastError. + * pfnfiledest [I] A pointer to a function which is called when a file + * is placed. Only useful for subsequent cabinet files. + * pfnalloc [I] A pointer to a function which allocates ram. Uses + * the same interface as malloc. + * pfnfree [I] A pointer to a function which frees ram. Uses the + * same interface as free. + * pfnopen [I] A pointer to a function which opens a file. Uses + * the same interface as _open. + * pfnread [I] A pointer to a function which reads from a file into + * a caller-provided buffer. Uses the same interface + * as _read. + * pfnwrite [I] A pointer to a function which writes to a file from + * a caller-provided buffer. Uses the same interface + * as _write. + * pfnclose [I] A pointer to a function which closes a file handle. + * Uses the same interface as _close. + * pfnseek [I] A pointer to a function which seeks in a file. + * Uses the same interface as _lseek. + * pfndelete [I] A pointer to a function which deletes a file. + * pfnfcigtf [I] A pointer to a function which gets the name of a + * temporary file. + * pccab [I] A pointer to an initialized CCAB structure. + * pv [I] A pointer to an application-defined notification + * function which will be passed to other FCI functions + * as a parameter. + * + * RETURNS + * On success, returns an FCI handle of type HFCI. + * On failure, the NULL file handle is returned. Error + * info can be retrieved from perf. + * + * INCLUDES + * fci.h + * + */ +HFCI __cdecl FCICreate( + PERF perf, + PFNFCIFILEPLACED pfnfiledest, + PFNFCIALLOC pfnalloc, + PFNFCIFREE pfnfree, + PFNFCIOPEN pfnopen, + PFNFCIREAD pfnread, + PFNFCIWRITE pfnwrite, + PFNFCICLOSE pfnclose, + PFNFCISEEK pfnseek, + PFNFCIDELETE pfndelete, + PFNFCIGETTEMPFILE pfnfcigtf, + PCCAB pccab, + void *pv) +{ + HFCI hfci; + int err; + PFCI_Int p_fci_internal; + + if ((!perf) || (!pfnalloc) || (!pfnfree) || (!pfnopen) || (!pfnread) || + (!pfnwrite) || (!pfnclose) || (!pfnseek) || (!pfndelete) || + (!pfnfcigtf) || (!pccab)) { + perf->erfOper = FCIERR_NONE; + perf->erfType = ERROR_BAD_ARGUMENTS; + perf->fError = TRUE; + + SetLastError(ERROR_BAD_ARGUMENTS); + return NULL; + } + + if (!((hfci = ((HFCI) (*pfnalloc)(sizeof(FCI_Int)))))) { + perf->erfOper = FCIERR_ALLOC_FAIL; + perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + perf->fError = TRUE; + + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + + p_fci_internal=((PFCI_Int)(hfci)); + p_fci_internal->FCI_Intmagic = FCI_INT_MAGIC; + p_fci_internal->perf = perf; + p_fci_internal->pfnfiledest = pfnfiledest; + p_fci_internal->pfnalloc = pfnalloc; + p_fci_internal->pfnfree = pfnfree; + p_fci_internal->pfnopen = pfnopen; + p_fci_internal->pfnread = pfnread; + p_fci_internal->pfnwrite = pfnwrite; + p_fci_internal->pfnclose = pfnclose; + p_fci_internal->pfnseek = pfnseek; + p_fci_internal->pfndelete = pfndelete; + p_fci_internal->pfnfcigtf = pfnfcigtf; + p_fci_internal->pccab = pccab; + p_fci_internal->fPrevCab = FALSE; + p_fci_internal->fNextCab = FALSE; + p_fci_internal->fSplitFolder = FALSE; + p_fci_internal->fGetNextCabInVain = FALSE; + p_fci_internal->pv = pv; + p_fci_internal->data_in = NULL; + p_fci_internal->cdata_in = 0; + p_fci_internal->data_out = NULL; + p_fci_internal->cCompressedBytesInFolder = 0; + p_fci_internal->cFolders = 0; + p_fci_internal->cFiles = 0; + p_fci_internal->cDataBlocks = 0; + p_fci_internal->sizeFileCFDATA1 = 0; + p_fci_internal->sizeFileCFFILE1 = 0; + p_fci_internal->sizeFileCFDATA2 = 0; + p_fci_internal->sizeFileCFFILE2 = 0; + p_fci_internal->sizeFileCFFOLDER = 0; + p_fci_internal->sizeFileCFFOLDER = 0; + p_fci_internal->fNewPrevious = FALSE; + + memcpy(p_fci_internal->szPrevCab, pccab->szCab, CB_MAX_CABINET_NAME); + memcpy(p_fci_internal->szPrevDisk, pccab->szDisk, CB_MAX_DISK_NAME); + + /* CFDATA */ + if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFDATA1, + CB_MAX_FILENAME)) { + /* TODO error handling */ + return FALSE; + } + /* safety */ + if ( strlen(p_fci_internal->szFileNameCFDATA1) >= CB_MAX_FILENAME ) { + /* TODO set error code */ + return FALSE; + } + + p_fci_internal->handleCFDATA1 = PFCI_OPEN(hfci, + p_fci_internal->szFileNameCFDATA1, 34050, 384, &err, pv); + /* TODO check handle */ + /* TODO error checking of err */ + + /* array of all CFFILE in a folder */ + if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE1, + CB_MAX_FILENAME)) { + /* TODO error handling */ + return FALSE; + } + /* safety */ + if ( strlen(p_fci_internal->szFileNameCFFILE1) >= CB_MAX_FILENAME ) { + /* TODO set error code */ + return FALSE; + } + p_fci_internal->handleCFFILE1 = PFCI_OPEN(hfci, + p_fci_internal->szFileNameCFFILE1, 34050, 384, &err, pv); + /* TODO check handle */ + /* TODO error checking of err */ + + /* CFDATA with checksum and ready to be copied into cabinet */ + if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFDATA2, + CB_MAX_FILENAME)) { + /* TODO error handling */ + return FALSE; + } + /* safety */ + if ( strlen(p_fci_internal->szFileNameCFDATA2) >= CB_MAX_FILENAME ) { + /* TODO set error code */ + return FALSE; + } + p_fci_internal->handleCFDATA2 = PFCI_OPEN(hfci, + p_fci_internal->szFileNameCFDATA2, 34050, 384, &err, pv); + /* TODO check handle */ + /* TODO error checking of err */ + + /* array of all CFFILE in a folder, ready to be copied into cabinet */ + if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE2, + CB_MAX_FILENAME)) { + /* TODO error handling */ + return FALSE; + } + /* safety */ + if ( strlen(p_fci_internal->szFileNameCFFILE2) >= CB_MAX_FILENAME ) { + /* TODO set error code */ + return FALSE; + } + p_fci_internal->handleCFFILE2 = PFCI_OPEN(hfci, + p_fci_internal->szFileNameCFFILE2, 34050, 384, &err, pv); + /* TODO check handle */ + /* TODO error checking of err */ + + /* array of all CFFILE in a folder, ready to be copied into cabinet */ + if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFOLDER, + CB_MAX_FILENAME)) { + /* TODO error handling */ + return FALSE; + } + /* safety */ + if ( strlen(p_fci_internal->szFileNameCFFOLDER) >= CB_MAX_FILENAME ) { + /* TODO set error code */ + return FALSE; + } + p_fci_internal->handleCFFOLDER = PFCI_OPEN(hfci, + p_fci_internal->szFileNameCFFOLDER, 34050, 384, &err, pv); + + + /* TODO close and delete new files when return FALSE */ + + /* TODO check handle */ + /* TODO error checking of err */ + + return hfci; +} /* end of FCICreate */ + + + + + + +static BOOL fci_flush_data_block (HFCI hfci, int* err, + PFNFCISTATUS pfnfcis) { + + /* attention no hfci checks!!! */ + /* attention no checks if there is data available!!! */ + CFDATA data; + CFDATA* cfdata=&data; + char* reserved; + PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); + UINT cbReserveCFData=p_fci_internal->pccab->cbReserveCFData; + UINT i; + + /* TODO compress the data of p_fci_internal->data_in */ + /* and write it to p_fci_internal->data_out */ + memcpy(p_fci_internal->data_out, p_fci_internal->data_in, + p_fci_internal->cdata_in /* number of bytes to copy */); + + cfdata->csum=0; /* checksum has to be set later */ + /* TODO set realsize of compressed data */ + cfdata->cbData = p_fci_internal->cdata_in; + cfdata->cbUncomp = p_fci_internal->cdata_in; + + /* write cfdata to p_fci_internal->handleCFDATA1 */ + if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA1, /* file handle */ + cfdata, sizeof(*cfdata), err, p_fci_internal->pv) + != sizeof(*cfdata) ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + p_fci_internal->sizeFileCFDATA1 += sizeof(*cfdata); + + /* add optional reserved area */ + + /* This allocation and freeing at each CFData block is a bit */ + /* inefficent, but it's harder to forget about freeing the buffer :-). */ + /* Reserved areas are used seldom besides that... */ + if (cbReserveCFData!=0) { + if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFData))) { + p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL; + p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + p_fci_internal->perf->fError = TRUE; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + for(i=0;ihandleCFDATA1, /* file handle */ + reserved, /* memory buffer */ + cbReserveCFData, /* number of bytes to copy */ + err, p_fci_internal->pv) != cbReserveCFData ) { + PFCI_FREE(hfci, reserved); + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err PFCI_FREE(hfci, reserved)*/ + + p_fci_internal->sizeFileCFDATA1 += cbReserveCFData; + PFCI_FREE(hfci, reserved); + } + + /* write p_fci_internal->data_out to p_fci_internal->handleCFDATA1 */ + if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA1, /* file handle */ + p_fci_internal->data_out, /* memory buffer */ + cfdata->cbData, /* number of bytes to copy */ + err, p_fci_internal->pv) != cfdata->cbData) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + p_fci_internal->sizeFileCFDATA1 += cfdata->cbData; + + /* reset the offset */ + p_fci_internal->cdata_in = 0; + p_fci_internal->cCompressedBytesInFolder += cfdata->cbData; + + /* report status with pfnfcis about uncompressed and compressed file data */ + if( (*pfnfcis)(statusFile, cfdata->cbData, cfdata->cbUncomp, + p_fci_internal->pv) == -1) { + /* TODO set error code and abort */ + return FALSE; + } + + ++(p_fci_internal->cDataBlocks); + + return TRUE; +} /* end of fci_flush_data_block */ + + + + + +static cab_ULONG fci_get_checksum(void *pv, UINT cb, CHECKSUM seed) +{ + cab_ULONG csum; + cab_ULONG ul; + int cUlong; + BYTE *pb; + + csum = seed; + cUlong = cb / 4; + pb = pv; + + while (cUlong-- > 0) { + ul = *pb++; + ul |= (((cab_ULONG)(*pb++)) << 8); + ul |= (((cab_ULONG)(*pb++)) << 16); + ul |= (((cab_ULONG)(*pb++)) << 24); + + csum ^= ul; + } + + ul = 0; + switch (cb % 4) { + case 3: + ul |= (((ULONG)(*pb++)) << 16); + case 2: + ul |= (((ULONG)(*pb++)) << 8); + case 1: + ul |= *pb++; + default: + break; + } + csum ^= ul; + + return csum; +} /* end of fci_get_checksum */ + + + + + +static BOOL fci_flushfolder_copy_cfdata(HFCI hfci, char* buffer, UINT cbReserveCFData, + PFNFCISTATUS pfnfcis, int* err, int handleCFDATA1new, + cab_ULONG* psizeFileCFDATA1new, cab_ULONG* payload) +{ + cab_ULONG read_result; + CFDATA* pcfdata=(CFDATA*)buffer; + BOOL split_block=FALSE; + cab_UWORD savedUncomp=0; + PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); + + *payload=0; + + /* while not all CFDATAs have been copied do */ + while(!FALSE) { + if( p_fci_internal->fNextCab ) { + if( split_block ) { + /* TODO internal error should never happen */ + return FALSE; + } + } + /* REUSE the variable read_result */ + if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || + p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || + p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { + read_result=4; + } else { + read_result=0; + } + if (p_fci_internal->fPrevCab) { + read_result+=strlen(p_fci_internal->szPrevCab)+1 + + strlen(p_fci_internal->szPrevDisk)+1; + } + /* No more CFDATA fits into the cabinet under construction */ + /* So don't try to store more data into it */ + if( p_fci_internal->fNextCab && + (p_fci_internal->oldCCAB.cb <= sizeof(CFDATA) + cbReserveCFData + + p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 + + p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER + + sizeof(CFHEADER) + + read_result + + p_fci_internal->oldCCAB.cbReserveCFHeader + + sizeof(CFFOLDER) + + p_fci_internal->oldCCAB.cbReserveCFFolder + + strlen(p_fci_internal->pccab->szCab)+1 + + strlen(p_fci_internal->pccab->szDisk)+1 + )) { + /* This may never be run for the first time the while loop is entered. + Pray that the code that calls fci_flushfolder_copy_cfdata handles this.*/ + split_block=TRUE; /* In this case split_block is abused to store */ + /* the complete data block into the next cabinet and not into the */ + /* current one. Originally split_block is the indicator that a */ + /* data block has been splitted across different cabinets. */ + } else { + + /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/ + read_result= PFCI_READ(hfci, p_fci_internal->handleCFDATA1,/*file handle*/ + buffer, /* memory buffer */ + sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */ + err, p_fci_internal->pv); + if (read_result!=sizeof(CFDATA)+cbReserveCFData) { + if (read_result==0) break; /* ALL DATA has been copied */ + /* TODO read error */ + return FALSE; + } + /* TODO error handling of err */ + + /* REUSE buffer p_fci_internal->data_out !!! */ + /* read data from p_fci_internal->handleCFDATA1 to */ + /* p_fci_internal->data_out */ + if( PFCI_READ(hfci, p_fci_internal->handleCFDATA1 /* file handle */, + p_fci_internal->data_out /* memory buffer */, + pcfdata->cbData /* number of bytes to copy */, + err, p_fci_internal->pv) != pcfdata->cbData ) { + /* TODO read error */ + return FALSE; + } + /* TODO error handling of err */ + + /* if cabinet size is too large */ + + /* REUSE the variable read_result */ + if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || + p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || + p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { + read_result=4; + } else { + read_result=0; + } + if (p_fci_internal->fPrevCab) { + read_result+=strlen(p_fci_internal->szPrevCab)+1 + + strlen(p_fci_internal->szPrevDisk)+1; + } + + /* Is cabinet with new CFDATA too large? Then data block has to be split */ + if( p_fci_internal->fNextCab && + (p_fci_internal->oldCCAB.cb < sizeof(CFDATA) + cbReserveCFData + + pcfdata->cbData + + p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 + + p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER + + sizeof(CFHEADER) + + read_result + + p_fci_internal->oldCCAB.cbReserveCFHeader + + sizeof(CFFOLDER) + /* size of new CFFolder entry */ + p_fci_internal->oldCCAB.cbReserveCFFolder + + strlen(p_fci_internal->pccab->szCab)+1 + /* name of next cabinet */ + strlen(p_fci_internal->pccab->szDisk)+1 /* name of next disk */ + )) { + /* REUSE read_result to save the size of the compressed data */ + read_result=pcfdata->cbData; + /* Modify the size of the compressed data to store only a part of the */ + /* data block into the current cabinet. This is done to prevent */ + /* that the maximum cabinet size will be exceeded. The remainer */ + /* will be stored into the next following cabinet. */ + + /* The cabinet will be of size "p_fci_internal->oldCCAB.cb". */ + /* Substract everything except the size of the block of data */ + /* to get it's actual size */ + pcfdata->cbData = p_fci_internal->oldCCAB.cb - ( + sizeof(CFDATA) + cbReserveCFData + + p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 + + p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER + + sizeof(CFHEADER) + + p_fci_internal->oldCCAB.cbReserveCFHeader + + sizeof(CFFOLDER) + /* set size of new CFFolder entry */ + p_fci_internal->oldCCAB.cbReserveCFFolder ); + /* substract the size of special header fields */ + if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || + p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || + p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { + pcfdata->cbData-=4; + } + if (p_fci_internal->fPrevCab) { + pcfdata->cbData-=strlen(p_fci_internal->szPrevCab)+1 + + strlen(p_fci_internal->szPrevDisk)+1; + } + pcfdata->cbData-=strlen(p_fci_internal->pccab->szCab)+1 + + strlen(p_fci_internal->pccab->szDisk)+1; + + savedUncomp = pcfdata->cbUncomp; + pcfdata->cbUncomp = 0; /* on splitted blocks of data this is zero */ + + /* if split_block==TRUE then the above while loop won't */ + /* be executed again */ + split_block=TRUE; /* split_block is the indicator that */ + /* a data block has been splitted across */ + /* diffentent cabinets.*/ + } + + /* This should never happen !!! */ + if (pcfdata->cbData==0) { + /* TODO set error */ + return FALSE; + } + + /* get checksum and write to cfdata.csum */ + pcfdata->csum = fci_get_checksum( &(pcfdata->cbData), + sizeof(CFDATA)+cbReserveCFData - + sizeof(pcfdata->csum), fci_get_checksum( p_fci_internal->data_out, /*buffer*/ + pcfdata->cbData, 0 ) ); + + /* write cfdata with checksum to p_fci_internal->handleCFDATA2 */ + if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA2, /* file handle */ + buffer, /* memory buffer */ + sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */ + err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + p_fci_internal->sizeFileCFDATA2 += sizeof(CFDATA)+cbReserveCFData; + + /* write compressed data into p_fci_internal->handleCFDATA2 */ + if( PFCI_WRITE(hfci, p_fci_internal->handleCFDATA2, /* file handle */ + p_fci_internal->data_out, /* memory buffer */ + pcfdata->cbData, /* number of bytes to copy */ + err, p_fci_internal->pv) != pcfdata->cbData) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + p_fci_internal->sizeFileCFDATA2 += pcfdata->cbData; + ++(p_fci_internal->cDataBlocks); + p_fci_internal->statusFolderCopied += pcfdata->cbData; + (*payload)+=pcfdata->cbUncomp; + /* if cabinet size too large and data has been split */ + /* write the remainer of the data block to the new CFDATA1 file */ + if( split_block ) { /* This does not include the */ + /* abused one (just search for "abused" )*/ + /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */ + if (p_fci_internal->fNextCab==FALSE ) { + /* TODO internal error */ + return FALSE; + } + + /* set cbData the size of the remainer of the data block */ + pcfdata->cbData = read_result - pcfdata->cbData; + /*recover former value of cfdata.cbData; read_result will be the offset*/ + read_result -= pcfdata->cbData; + pcfdata->cbUncomp = savedUncomp; + + /* reset checksum, it will be computed later */ + pcfdata->csum=0; + /* write cfdata WITHOUT checksum to handleCFDATA1new */ + if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */ + buffer, /* memory buffer */ + sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */ + err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err dont forget PFCI_FREE(hfci, reserved) */ + + *psizeFileCFDATA1new += sizeof(CFDATA)+cbReserveCFData; + + /* write compressed data into handleCFDATA1new */ + if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */ + p_fci_internal->data_out + read_result, /* memory buffer + offset */ + /* to last part of split data */ + pcfdata->cbData, /* number of bytes to copy */ + err, p_fci_internal->pv) != pcfdata->cbData) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + p_fci_internal->statusFolderCopied += pcfdata->cbData; + + *psizeFileCFDATA1new += pcfdata->cbData; + /* the two blocks of the split data block have been written */ + /* dont reset split_data yet, because it is still needed see below */ + } + + /* report status with pfnfcis about copied size of folder */ + if( (*pfnfcis)(statusFolder, + p_fci_internal->statusFolderCopied, /*cfdata.cbData(+previous ones)*/ + p_fci_internal->statusFolderTotal, /* total folder size */ + p_fci_internal->pv) == -1) { + /* TODO set error code and abort */ + return FALSE; + } + } + + /* if cabinet size too large */ + /* write the remaining data blocks to the new CFDATA1 file */ + if ( split_block ) { /* This does include the */ + /* abused one (just search for "abused" )*/ + if (p_fci_internal->fNextCab==FALSE ) { + /* TODO internal error */ + return FALSE; + } + /* copy all CFDATA structures from handleCFDATA1 to handleCFDATA1new */ + while(!FALSE) { + /* read CFDATA from p_fci_internal->handleCFDATA1 to cfdata*/ + read_result= PFCI_READ(hfci, p_fci_internal->handleCFDATA1,/* handle */ + buffer, /* memory buffer */ + sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */ + err, p_fci_internal->pv); + if (read_result!=sizeof(CFDATA)+cbReserveCFData) { + if (read_result==0) break; /* ALL DATA has been copied */ + /* TODO read error */ + return FALSE; + } + /* TODO error handling of err */ + + /* REUSE buffer p_fci_internal->data_out !!! */ + /* read data from p_fci_internal->handleCFDATA1 to */ + /* p_fci_internal->data_out */ + if( PFCI_READ(hfci, p_fci_internal->handleCFDATA1 /* file handle */, + p_fci_internal->data_out /* memory buffer */, + pcfdata->cbData /* number of bytes to copy */, + err, p_fci_internal->pv) != pcfdata->cbData ) { + /* TODO read error */ + return FALSE; + } + /* TODO error handling of err dont forget PFCI_FREE(hfci, reserved) */ + + /* write cfdata with checksum to handleCFDATA1new */ + if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */ + buffer, /* memory buffer */ + sizeof(CFDATA)+cbReserveCFData, /* number of bytes to copy */ + err, p_fci_internal->pv) != sizeof(CFDATA)+cbReserveCFData ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err dont forget PFCI_FREE(hfci, reserved) */ + + *psizeFileCFDATA1new += sizeof(CFDATA)+cbReserveCFData; + + /* write compressed data into handleCFDATA1new */ + if( PFCI_WRITE(hfci, handleCFDATA1new, /* file handle */ + p_fci_internal->data_out, /* memory buffer */ + pcfdata->cbData, /* number of bytes to copy */ + err, p_fci_internal->pv) != pcfdata->cbData) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + *psizeFileCFDATA1new += pcfdata->cbData; + p_fci_internal->statusFolderCopied += pcfdata->cbData; + + /* report status with pfnfcis about copied size of folder */ + if( (*pfnfcis)(statusFolder, + p_fci_internal->statusFolderCopied,/*cfdata.cbData(+revious ones)*/ + p_fci_internal->statusFolderTotal, /* total folder size */ + p_fci_internal->pv) == -1) { + /* TODO set error code and abort */ + return FALSE; + } + + } /* end of WHILE */ + break; /* jump out of the next while loop */ + } /* end of if( split_data ) */ + } /* end of WHILE */ + return TRUE; +} /* end of fci_flushfolder_copy_cfdata */ + + + + + +static BOOL fci_flushfolder_copy_cffolder(HFCI hfci, int* err, UINT cbReserveCFFolder, + cab_ULONG sizeFileCFDATA2old) +{ + CFFOLDER cffolder; + UINT i; + char* reserved; + PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); + + /* absolute offset cannot be set yet, because the size of cabinet header, */ + /* the number of CFFOLDERs and the number of CFFILEs may change. */ + /* Instead the size of all previous data blocks will be stored and */ + /* the remainer of the offset will be added when the cabinet will be */ + /* flushed to disk. */ + /* This is exactly the way the original CABINET.DLL works!!! */ + cffolder.coffCabStart=sizeFileCFDATA2old; + + /* set the number of this folder's CFDATA sections */ + cffolder.cCFData=p_fci_internal->cDataBlocks; + /* TODO set compression type */ + cffolder.typeCompress = tcompTYPE_NONE; + + /* write cffolder to p_fci_internal->handleCFFOLDER */ + if( PFCI_WRITE(hfci, p_fci_internal->handleCFFOLDER, /* file handle */ + &cffolder, /* memory buffer */ + sizeof(cffolder), /* number of bytes to copy */ + err, p_fci_internal->pv) != sizeof(cffolder) ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + p_fci_internal->sizeFileCFFOLDER += sizeof(cffolder); + + /* add optional reserved area */ + if (cbReserveCFFolder!=0) { + if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFFolder))) { + p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL; + p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + p_fci_internal->perf->fError = TRUE; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + for(i=0;ihandleCFFOLDER, /* file handle */ + reserved, /* memory buffer */ + cbReserveCFFolder, /* number of bytes to copy */ + err, p_fci_internal->pv) != cbReserveCFFolder ) { + PFCI_FREE(hfci, reserved); + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + p_fci_internal->sizeFileCFFOLDER += cbReserveCFFolder; + + PFCI_FREE(hfci, reserved); + } + return TRUE; +} /* end of fci_flushfolder_copy_cffolder */ + + + + + +static BOOL fci_flushfolder_copy_cffile(HFCI hfci, int* err, int handleCFFILE1new, + cab_ULONG *psizeFileCFFILE1new, cab_ULONG payload) +{ + CFFILE cffile; + cab_ULONG read_result; + cab_ULONG seek=0; + cab_ULONG sizeOfFiles=0, sizeOfFilesPrev; + BOOL may_be_prev=TRUE; + cab_ULONG cbFileRemainer=0; + PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); + /* set seek of p_fci_internal->handleCFFILE1 to 0 */ + if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE1,0,SEEK_SET,err, + p_fci_internal->pv) !=0 ) { + /* TODO wrong return value */ + } + /* TODO error handling of err */ + + /* while not all CFFILE structures have been copied do */ + while(!FALSE) { + /* REUSE the variable read_result */ + /* read data from p_fci_internal->handleCFFILE1 to cffile */ + read_result = PFCI_READ(hfci,p_fci_internal->handleCFFILE1/* file handle */, + &cffile, /* memory buffer */ + sizeof(cffile), /* number of bytes to copy */ + err, p_fci_internal->pv); + if( read_result != sizeof(cffile) ) { + if( read_result == 0 ) break; /* ALL CFFILE structures have been copied */ + /* TODO read error */ + return FALSE; + } + /* TODO error handling of err */ + + /* Microsoft's(R) CABINET.DLL would do a seek to the current! */ + /* position. I don't know why so I'll just omit it */ + + /* read the filename from p_fci_internal->handleCFFILE1 */ + /* REUSE the variable read_result AGAIN */ + /* REUSE the memory buffer PFCI(hfci)->data_out */ + if( PFCI_READ(hfci, p_fci_internal->handleCFFILE1 /*file handle*/, + p_fci_internal->data_out, /* memory buffer */ + CB_MAX_FILENAME, /* number of bytes to copy */ + err, p_fci_internal->pv) <2) { + /* TODO read error */ + return FALSE; + } + /* TODO maybe other checks of read_result */ + /* TODO error handling of err */ + + /* safety */ + if( strlen(p_fci_internal->data_out)>=CB_MAX_FILENAME ) { + /* TODO set error code internal error */ + return FALSE; + } + + seek+=sizeof(cffile) + strlen(p_fci_internal->data_out)+1; + + /* set seek of p_fci_internal->handleCFFILE1 to end of file name */ + /* i.e. seek to the next CFFILE area */ + if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE1, + seek, /* seek position*/ + SEEK_SET ,err, + p_fci_internal->pv) + != sizeof(cffile)+strlen(p_fci_internal->data_out)+1 ) { + /* TODO wrong return value */ + } + /* TODO error handling of err */ + + /* fnfilfnfildest: placed file on cabinet */ + if (p_fci_internal->fNextCab || + p_fci_internal->fGetNextCabInVain) { + PFCI_FILEPLACED( hfci, &(p_fci_internal->oldCCAB), + p_fci_internal->data_out, /* the file name*/ + cffile.cbFile, /* file size */ + (cffile.iFolder==cffileCONTINUED_FROM_PREV), + p_fci_internal->pv + ); + } else { + PFCI_FILEPLACED( hfci, p_fci_internal->pccab, + p_fci_internal->data_out, /* the file name*/ + cffile.cbFile, /* file size */ + (cffile.iFolder==cffileCONTINUED_FROM_PREV), + p_fci_internal->pv + ); + } + + /* Check special iFolder values */ + if( cffile.iFolder==cffileCONTINUED_FROM_PREV && + p_fci_internal->fPrevCab==FALSE ) { + /* THIS MAY NEVER HAPPEN */ + /* TODO set error code */ + return FALSE; + } + if( cffile.iFolder==cffileCONTINUED_PREV_AND_NEXT || + cffile.iFolder==cffileCONTINUED_TO_NEXT ) { + /* THIS MAY NEVER HAPPEN */ + /* TODO set error code */ + return FALSE; + } + if( may_be_prev && cffile.iFolder!=cffileCONTINUED_FROM_PREV ) { + may_be_prev=FALSE; + } + if( cffile.iFolder==cffileCONTINUED_FROM_PREV && may_be_prev==FALSE ) { + /* THIS MAY NEVER HAPPEN */ + /* TODO set error code */ + return FALSE; + } + if( cffile.iFolder!=cffileCONTINUED_FROM_PREV ) { + may_be_prev=FALSE; + } + + sizeOfFilesPrev=sizeOfFiles; + /* Set complete size of all processed files */ + if( cffile.iFolder==cffileCONTINUED_FROM_PREV && + p_fci_internal->cbFileRemainer!=0 + ) { + sizeOfFiles+=p_fci_internal->cbFileRemainer; + p_fci_internal->cbFileRemainer=0; + } else { + sizeOfFiles+=cffile.cbFile; + } + + /* Check if spanned file fits into this cabinet folder */ + if( cffile.iFolder==cffileCONTINUED_FROM_PREV && sizeOfFiles>payload ) { + cffile.iFolder=cffileCONTINUED_PREV_AND_NEXT; + } else + + /* Check if file doesn't fit into this cabinet folder */ + if( sizeOfFiles>payload ) { + cffile.iFolder=cffileCONTINUED_TO_NEXT; + } + + /* write cffile to p_fci_internal->handleCFFILE2 */ + if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE2, /* file handle */ + &cffile, /* memory buffer */ + sizeof(cffile), /* number of bytes to copy */ + err, p_fci_internal->pv) != sizeof(cffile) ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + p_fci_internal->sizeFileCFFILE2 += sizeof(cffile); + + /* write file name to p_fci_internal->handleCFFILE2 */ + if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE2, /* file handle */ + p_fci_internal->data_out, /* memory buffer */ + strlen(p_fci_internal->data_out)+1, /* number of bytes to copy */ + err, p_fci_internal->pv) != strlen(p_fci_internal->data_out)+1 ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + p_fci_internal->sizeFileCFFILE2 += strlen(p_fci_internal->data_out)+1; + + /* cFiles is used to count all files of a cabinet */ + ++(p_fci_internal->cFiles); + + /* This is only true for files which will be written into the */ + /* next cabinet of the spanning folder */ + if( sizeOfFiles>payload ) { + + /* Files which data will be partially written into the current cabinet */ + if( cffile.iFolder==cffileCONTINUED_PREV_AND_NEXT || + cffile.iFolder==cffileCONTINUED_TO_NEXT + ) { + if( sizeOfFilesPrev<=payload ) { + /* The size of the uncompressed, data of a spanning file in a */ + /* spanning data */ + cbFileRemainer=sizeOfFiles-payload; + } + cffile.iFolder=cffileCONTINUED_FROM_PREV; + } else { + cffile.iFolder=0; + } + + /* write cffile into handleCFFILE1new */ + if( PFCI_WRITE(hfci, handleCFFILE1new, /* file handle */ + &cffile, /* memory buffer */ + sizeof(cffile), /* number of bytes to copy */ + err, p_fci_internal->pv) != sizeof(cffile) ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + *psizeFileCFFILE1new += sizeof(cffile); + /* write name of file into handleCFFILE1new */ + if( PFCI_WRITE(hfci, handleCFFILE1new, /* file handle */ + p_fci_internal->data_out, /* memory buffer */ + strlen(p_fci_internal->data_out)+1, /* number of bytes to copy */ + err, p_fci_internal->pv) != strlen(p_fci_internal->data_out)+1 ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + *psizeFileCFFILE1new += strlen(p_fci_internal->data_out)+1; + } + + } /* END OF while */ + p_fci_internal->cbFileRemainer=cbFileRemainer; + return TRUE; +} /* end of fci_flushfolder_copy_cffile */ + + + + +static BOOL fci_flush_folder( + HFCI hfci, + BOOL fGetNextCab, + PFNFCIGETNEXTCABINET pfnfcignc, + PFNFCISTATUS pfnfcis) +{ + int err; + int handleCFDATA1new; /* handle for new temp file */ + char szFileNameCFDATA1new[CB_MAX_FILENAME]; /* name buffer for temp file */ + int handleCFFILE1new; /* handle for new temp file */ + char szFileNameCFFILE1new[CB_MAX_FILENAME]; /* name buffer for temp file */ + UINT cbReserveCFData, cbReserveCFFolder; + char* reserved; + cab_ULONG sizeFileCFDATA1new=0; + cab_ULONG sizeFileCFFILE1new=0; + cab_ULONG sizeFileCFDATA2old; + cab_ULONG payload; + cab_ULONG read_result; + PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); + + /* test hfci */ + if (!REALLY_IS_FCI(hfci)) { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if ((!pfnfcignc) || (!pfnfcis)) { + p_fci_internal->perf->erfOper = FCIERR_NONE; + p_fci_internal->perf->erfType = ERROR_BAD_ARGUMENTS; + p_fci_internal->perf->fError = TRUE; + + SetLastError(ERROR_BAD_ARGUMENTS); + return FALSE; + } + + if( p_fci_internal->fGetNextCabInVain && + p_fci_internal->fNextCab ){ + /* TODO internal error */ + return FALSE; + } + + /* If there was no FCIAddFile or FCIFlushFolder has already been called */ + /* this function will return TRUE */ + if( p_fci_internal->sizeFileCFFILE1 == 0 ) { + if ( p_fci_internal->sizeFileCFDATA1 != 0 ) { + /* TODO error handling */ + return FALSE; + } + return TRUE; + } + + if (p_fci_internal->data_in==NULL || p_fci_internal->data_out==NULL ) { + /* TODO error handling */ + return FALSE; + } + + /* FCIFlushFolder has already been called... */ + if (p_fci_internal->fSplitFolder && p_fci_internal->sizeFileCFFILE2!=0) { + if (p_fci_internal->sizeFileCFFILE2==0) { + /* TODO set error code */ + return FALSE; + } + return TRUE; + } + + /* TODO check what will happen when return FALSE later */ + /* and p_fci_internal->fSplitFolder is set to FALSE */ + p_fci_internal->fSplitFolder=FALSE; + + + if( p_fci_internal->fGetNextCabInVain || + p_fci_internal->fNextCab ){ + cbReserveCFData = p_fci_internal->oldCCAB.cbReserveCFData; + cbReserveCFFolder = p_fci_internal->oldCCAB.cbReserveCFFolder; + } else { + cbReserveCFData = p_fci_internal->pccab->cbReserveCFData; + cbReserveCFFolder = p_fci_internal->pccab->cbReserveCFFolder; + } + + /* START of COPY */ + /* if there is data in p_fci_internal->data_in */ + if (p_fci_internal->cdata_in!=0) { + + if( !fci_flush_data_block(hfci, &err, pfnfcis) ) return FALSE; + + } + /* reset to get the number of data blocks of this folder which are */ + /* actually in this cabinet ( at least partially ) */ + p_fci_internal->cDataBlocks=0; + + if ( p_fci_internal->fNextCab || + p_fci_internal->fGetNextCabInVain ) { + read_result= p_fci_internal->oldCCAB.cbReserveCFHeader+ + p_fci_internal->oldCCAB.cbReserveCFFolder; + if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || + p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || + p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { + read_result+=4; + } + } else { + read_result= p_fci_internal->pccab->cbReserveCFHeader+ + p_fci_internal->pccab->cbReserveCFFolder; + if ( p_fci_internal->pccab->cbReserveCFHeader != 0 || + p_fci_internal->pccab->cbReserveCFFolder != 0 || + p_fci_internal->pccab->cbReserveCFData != 0 ) { + read_result+=4; + } + } + if (p_fci_internal->fPrevCab) { + read_result+=strlen(p_fci_internal->szPrevCab)+1 + + strlen(p_fci_internal->szPrevDisk)+1; + } + if (p_fci_internal->fNextCab) { + read_result+=strlen(p_fci_internal->pccab->szCab)+1 + + strlen(p_fci_internal->pccab->szDisk)+1; + } + + p_fci_internal->statusFolderTotal = sizeof(CFHEADER)+read_result+ + sizeof(CFFOLDER) + p_fci_internal->sizeFileCFFILE2+ + p_fci_internal->sizeFileCFDATA2 + p_fci_internal->sizeFileCFFILE1+ + p_fci_internal->sizeFileCFDATA1; + p_fci_internal->statusFolderCopied = 0; + + /* report status with pfnfcis about copied size of folder */ + if( (*pfnfcis)(statusFolder, p_fci_internal->statusFolderCopied, + p_fci_internal->statusFolderTotal, /* TODO total folder size */ + p_fci_internal->pv) == -1) { + /* TODO set error code and abort */ + return FALSE; + } + + /* get a new temp file */ + if(!PFCI_GETTEMPFILE(hfci,szFileNameCFDATA1new,CB_MAX_FILENAME)) { + /* TODO error handling */ + return FALSE; + } + /* safety */ + if ( strlen(szFileNameCFDATA1new) >= CB_MAX_FILENAME ) { + /* TODO set error code */ + return FALSE; + } + handleCFDATA1new = PFCI_OPEN(hfci,szFileNameCFDATA1new,34050,384,&err, + p_fci_internal->pv); + + /* get a new temp file */ + if(!PFCI_GETTEMPFILE(hfci,szFileNameCFFILE1new,CB_MAX_FILENAME)) { + /* TODO error handling */ + PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + return FALSE; + } + /* safety */ + if ( strlen(szFileNameCFFILE1new) >= CB_MAX_FILENAME ) { + /* TODO set error code */ + PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + return FALSE; + } + handleCFFILE1new = PFCI_OPEN(hfci,szFileNameCFFILE1new,34050,384,&err, + p_fci_internal->pv); + + /* USE the variable read_result */ + if ( p_fci_internal->fNextCab || + p_fci_internal->fGetNextCabInVain ) { + read_result= p_fci_internal->oldCCAB.cbReserveCFHeader; + if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || + p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || + p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { + read_result+=4; + } + } else { + read_result= p_fci_internal->pccab->cbReserveCFHeader; + if ( p_fci_internal->pccab->cbReserveCFHeader != 0 || + p_fci_internal->pccab->cbReserveCFFolder != 0 || + p_fci_internal->pccab->cbReserveCFData != 0 ) { + read_result+=4; + } + } + if (p_fci_internal->fPrevCab) { + read_result+=strlen(p_fci_internal->szPrevCab)+1 + + strlen(p_fci_internal->szPrevDisk)+1; + } + read_result+= sizeof(CFHEADER) + p_fci_internal->sizeFileCFDATA2 + + p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER; + + if(p_fci_internal->sizeFileCFFILE1!=0) { + read_result+= sizeof(CFFOLDER)+p_fci_internal->pccab->cbReserveCFFolder; + } + + /* Check if multiple cabinets have to be created. */ + + /* Might be too much data for the maximum allowed cabinet size.*/ + /* When any further data will be added later, it might not */ + /* be possible to flush the cabinet, because there might */ + /* not be enough space to store the name of the following */ + /* cabinet and name of the corresponding disk. */ + /* So take care of this and get the name of the next cabinet */ + if( p_fci_internal->fGetNextCabInVain==FALSE && + p_fci_internal->fNextCab==FALSE && + ( + ( + p_fci_internal->pccab->cb < read_result + + p_fci_internal->sizeFileCFDATA1 + + p_fci_internal->sizeFileCFFILE1 + + CB_MAX_CABINET_NAME + /* next cabinet name */ + CB_MAX_DISK_NAME /* next disk name */ + ) || fGetNextCab + ) + ) { + /* save CCAB */ + memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB)); + /* increment cabinet index */ + ++(p_fci_internal->pccab->iCab); + /* get name of next cabinet */ + if (!(*pfnfcignc)(p_fci_internal->pccab, 0, /* estimated size of cab */ + p_fci_internal->pv)) { + /* TODO error handling */ + PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + return FALSE; + } + + /* Skip a few lines of code. This is catched by the next if. */ + p_fci_internal->fGetNextCabInVain=TRUE; + } + + /* too much data for cabinet */ + if( (p_fci_internal->fGetNextCabInVain || + p_fci_internal->fNextCab ) && + ( + ( + p_fci_internal->oldCCAB.cb < read_result + + p_fci_internal->sizeFileCFDATA1 + + p_fci_internal->sizeFileCFFILE1 + + strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */ + strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */ + ) || fGetNextCab + ) + ) { + p_fci_internal->fGetNextCabInVain=FALSE; + p_fci_internal->fNextCab=TRUE; + + /* return FALSE if there is not enough space left*/ + /* this should never happen */ + if (p_fci_internal->oldCCAB.cb <= + p_fci_internal->sizeFileCFFILE1 + + read_result + + strlen(p_fci_internal->pccab->szCab)+1 + /* next cabinet name */ + strlen(p_fci_internal->pccab->szDisk)+1 /* next disk name */ + ) { + + PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + + /* close and delete p_fci_internal->handleCFFILE1 */ + PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_DELETE(hfci,szFileNameCFFILE1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + + return FALSE; + } + + /* the folder will be split across cabinets */ + p_fci_internal->fSplitFolder=TRUE; + + } else { + /* this should never happen */ + if (p_fci_internal->fNextCab) { + /* TODO internal error */ + return FALSE; + } + } + + /* set seek of p_fci_internal->handleCFDATA1 to 0 */ + if( PFCI_SEEK(hfci,p_fci_internal->handleCFDATA1,0,SEEK_SET,&err, + p_fci_internal->pv) !=0 ) { + /* TODO wrong return value */ + PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + return FALSE; + } + /* TODO error handling of err */ + + /* save size of file CFDATA2 - required for the folder's offset to data */ + sizeFileCFDATA2old = p_fci_internal->sizeFileCFDATA2; + + if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFData+sizeof(CFDATA)))) { + p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL; + p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + p_fci_internal->perf->fError = TRUE; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + return FALSE; + } + + if(!fci_flushfolder_copy_cfdata(hfci, reserved, cbReserveCFData, pfnfcis, &err, + handleCFDATA1new, &sizeFileCFDATA1new, &payload + )) { + PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_FREE(hfci,reserved); + return FALSE; + } + + PFCI_FREE(hfci,reserved); + + if(!fci_flushfolder_copy_cffolder(hfci, &err, cbReserveCFFolder, + sizeFileCFDATA2old )) { + PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + return FALSE; + } + + if(!fci_flushfolder_copy_cffile(hfci, &err, handleCFFILE1new, + &sizeFileCFFILE1new, payload)) { + PFCI_CLOSE(hfci,handleCFDATA1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_DELETE(hfci,szFileNameCFDATA1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_CLOSE(hfci,handleCFFILE1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_DELETE(hfci,szFileNameCFFILE1new,&err,p_fci_internal->pv); + /* TODO error handling of err */ + return FALSE; + } + + /* close and delete p_fci_internal->handleCFDATA1 */ + PFCI_CLOSE(hfci,p_fci_internal->handleCFDATA1,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_DELETE(hfci,p_fci_internal->szFileNameCFDATA1,&err,p_fci_internal->pv); + /* TODO error handling of err */ + + /* put new CFDATA1 into hfci */ + memcpy(p_fci_internal->szFileNameCFDATA1,szFileNameCFDATA1new, + CB_MAX_FILENAME); + + /* put CFDATA1 file handle */ + PFCI_INT(hfci)->handleCFDATA1 = handleCFDATA1new; + /* set file size */ + PFCI_INT(hfci)->sizeFileCFDATA1 = sizeFileCFDATA1new; + + /* close and delete PFCI_INT(hfci)->handleCFFILE1 */ + PFCI_CLOSE(hfci,p_fci_internal->handleCFFILE1,&err,PFCI_INT(hfci)->pv); + /* TODO error handling of err */ + PFCI_DELETE(hfci,p_fci_internal->szFileNameCFFILE1,&err,p_fci_internal->pv); + /* TODO error handling of err */ + + /* put new CFFILE1 into hfci */ + memcpy(p_fci_internal->szFileNameCFFILE1,szFileNameCFFILE1new, + CB_MAX_FILENAME); + + /* put CFFILE1 file handle */ + p_fci_internal->handleCFFILE1 = handleCFFILE1new; + /* set file size */ + p_fci_internal->sizeFileCFFILE1 = sizeFileCFFILE1new; + + ++(p_fci_internal->cFolders); + + /* reset CFFolder specific information */ + p_fci_internal->cDataBlocks=0; + p_fci_internal->cCompressedBytesInFolder=0; + + return TRUE; +} /* end of fci_flush_folder */ + + + + +static BOOL fci_flush_cabinet( + HFCI hfci, + BOOL fGetNextCab, + PFNFCIGETNEXTCABINET pfnfcignc, + PFNFCISTATUS pfnfcis) +{ + int err; + CFHEADER cfheader; + struct { + cab_UWORD cbCFHeader; + cab_UBYTE cbCFFolder; + cab_UBYTE cbCFData; + } cfreserved; + CFFOLDER cffolder; + cab_ULONG read_result; + int handleCABINET; /* file handle for cabinet */ + char pszFileNameCABINET[CB_MAX_CAB_PATH+CB_MAX_CABINET_NAME];/* name buffer */ + UINT cbReserveCFHeader, cbReserveCFFolder, i; + char* reserved; + BOOL returntrue=FALSE; + PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); + + /* TODO test if fci_flush_cabinet really aborts if there was no FCIAddFile */ + + /* when FCIFlushCabinet was or FCIAddFile wasn't called */ + if( p_fci_internal->sizeFileCFFILE1==0 && fGetNextCab ) { + returntrue=TRUE; + } + + if (!fci_flush_folder(hfci,fGetNextCab,pfnfcignc,pfnfcis)){ + /* TODO set error */ + return FALSE; + } + + if(returntrue) return TRUE; + + if (p_fci_internal->fSplitFolder && p_fci_internal->fNextCab==FALSE) { + /* TODO internal error */ + return FALSE; + } + + if( p_fci_internal->fNextCab || + p_fci_internal->fGetNextCabInVain ) { + cbReserveCFFolder=p_fci_internal->oldCCAB.cbReserveCFFolder; + cbReserveCFHeader=p_fci_internal->oldCCAB.cbReserveCFHeader; + /* safety */ + if (strlen(p_fci_internal->oldCCAB.szCabPath)>=CB_MAX_CAB_PATH || + strlen(p_fci_internal->oldCCAB.szCab)>=CB_MAX_CABINET_NAME) { + /* TODO set error */ + return FALSE; + } + /* get the full name of the cabinet */ + memcpy(pszFileNameCABINET,p_fci_internal->oldCCAB.szCabPath, + CB_MAX_CAB_PATH); + memcpy(pszFileNameCABINET+strlen(pszFileNameCABINET), + p_fci_internal->oldCCAB.szCab, CB_MAX_CABINET_NAME); + } else { + cbReserveCFFolder=p_fci_internal->pccab->cbReserveCFFolder; + cbReserveCFHeader=p_fci_internal->pccab->cbReserveCFHeader; + /* safety */ + if (strlen(p_fci_internal->pccab->szCabPath)>=CB_MAX_CAB_PATH || + strlen(p_fci_internal->pccab->szCab)>=CB_MAX_CABINET_NAME) { + /* TODO set error */ + return FALSE; + } + /* get the full name of the cabinet */ + memcpy(pszFileNameCABINET,p_fci_internal->pccab->szCabPath, + CB_MAX_CAB_PATH); + memcpy(pszFileNameCABINET+strlen(pszFileNameCABINET), + p_fci_internal->pccab->szCab, CB_MAX_CABINET_NAME); + } + + /* create the cabinet */ + handleCABINET = PFCI_OPEN(hfci, pszFileNameCABINET, + 33538, 384, &err, p_fci_internal->pv ); + /* TODO check handle */ + /* TODO error checking of err */ + + memcpy(cfheader.signature,"!CAB",4); + cfheader.reserved1=0; + cfheader.cbCabinet= /* size of the cabinet file in bytes */ + sizeof(CFHEADER) + + p_fci_internal->sizeFileCFFOLDER + + p_fci_internal->sizeFileCFFILE2 + + p_fci_internal->sizeFileCFDATA2; + + if (p_fci_internal->fPrevCab) { + cfheader.cbCabinet+=strlen(p_fci_internal->szPrevCab)+1 + + strlen(p_fci_internal->szPrevDisk)+1; + } + if (p_fci_internal->fNextCab) { + cfheader.cbCabinet+=strlen(p_fci_internal->pccab->szCab)+1 + + strlen(p_fci_internal->pccab->szDisk)+1; + } + if( p_fci_internal->fNextCab || + p_fci_internal->fGetNextCabInVain ) { + cfheader.cbCabinet+=p_fci_internal->oldCCAB.cbReserveCFHeader; + if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || + p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || + p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { + cfheader.cbCabinet+=4; + } + } else { + cfheader.cbCabinet+=p_fci_internal->pccab->cbReserveCFHeader; + if ( p_fci_internal->pccab->cbReserveCFHeader != 0 || + p_fci_internal->pccab->cbReserveCFFolder != 0 || + p_fci_internal->pccab->cbReserveCFData != 0 ) { + cfheader.cbCabinet+=4; + } + } + + cfheader.reserved2=0; + cfheader.coffFiles= /* offset to first CFFILE section */ + cfheader.cbCabinet - p_fci_internal->sizeFileCFFILE2 - + p_fci_internal->sizeFileCFDATA2; + + cfheader.reserved3=0; + cfheader.versionMinor=3; + cfheader.versionMajor=1; + /* number of CFFOLDER entries in the cabinet */ + cfheader.cFolders=p_fci_internal->cFolders; + /* number of CFFILE entries in the cabinet */ + cfheader.cFiles=p_fci_internal->cFiles; + cfheader.flags=0; /* 1=prev cab, 2=next cabinet, 4=reserved setions */ + + if( p_fci_internal->fPrevCab ) { + cfheader.flags = cfheadPREV_CABINET; + } + + if( p_fci_internal->fNextCab ) { + cfheader.flags |= cfheadNEXT_CABINET; + } + + if( p_fci_internal->fNextCab || + p_fci_internal->fGetNextCabInVain ) { + if( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || + p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || + p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { + cfheader.flags |= cfheadRESERVE_PRESENT; + } + cfheader.setID = p_fci_internal->oldCCAB.setID; + cfheader.iCabinet = p_fci_internal->oldCCAB.iCab-1; + } else { + if( p_fci_internal->pccab->cbReserveCFHeader != 0 || + p_fci_internal->pccab->cbReserveCFFolder != 0 || + p_fci_internal->pccab->cbReserveCFData != 0 ) { + cfheader.flags |= cfheadRESERVE_PRESENT; + } + cfheader.setID = p_fci_internal->pccab->setID; + cfheader.iCabinet = p_fci_internal->pccab->iCab-1; + } + + /* write CFHEADER into cabinet file */ + if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ + &cfheader, /* memory buffer */ + sizeof(cfheader), /* number of bytes to copy */ + &err, p_fci_internal->pv) != sizeof(cfheader) ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + if( cfheader.flags & cfheadRESERVE_PRESENT ) { + /* NOTE: No checks for maximum value overflows as designed by MS!!! */ + cfreserved.cbCFHeader = cbReserveCFHeader; + cfreserved.cbCFFolder = cbReserveCFFolder; + if( p_fci_internal->fNextCab || + p_fci_internal->fGetNextCabInVain ) { + cfreserved.cbCFData = p_fci_internal->oldCCAB.cbReserveCFData; + } else { + cfreserved.cbCFData = p_fci_internal->pccab->cbReserveCFData; + } + /* write reserved info into cabinet file */ + if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ + &cfreserved, /* memory buffer */ + sizeof(cfreserved), /* number of bytes to copy */ + &err, p_fci_internal->pv) != sizeof(cfreserved) ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + } + + /* add optional reserved area */ + if (cbReserveCFHeader!=0) { + if(!(reserved = (char*)PFCI_ALLOC(hfci, cbReserveCFHeader))) { + p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL; + p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + p_fci_internal->perf->fError = TRUE; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + for(i=0;ipv) != cbReserveCFHeader ) { + PFCI_FREE(hfci, reserved); + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + PFCI_FREE(hfci, reserved); + } + + if( cfheader.flags & cfheadPREV_CABINET ) { + if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ + p_fci_internal->szPrevCab, /* memory buffer */ + strlen(p_fci_internal->szPrevCab)+1, /* number of bytes to copy */ + &err, p_fci_internal->pv) != strlen(p_fci_internal->szPrevCab)+1 ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ + p_fci_internal->szPrevDisk, /* memory buffer */ + strlen(p_fci_internal->szPrevDisk)+1, /* number of bytes to copy */ + &err, p_fci_internal->pv) != strlen(p_fci_internal->szPrevDisk)+1 ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + } + + if( cfheader.flags & cfheadNEXT_CABINET ) { + if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ + p_fci_internal->pccab->szCab, /* memory buffer */ + strlen(p_fci_internal->pccab->szCab)+1, /* number of bytes to copy */ + &err, p_fci_internal->pv) != strlen(p_fci_internal->pccab->szCab)+1 ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ + p_fci_internal->pccab->szDisk, /* memory buffer */ + strlen(p_fci_internal->pccab->szDisk)+1, /* number of bytes to copy */ + &err, p_fci_internal->pv) != strlen(p_fci_internal->pccab->szDisk)+1 ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + } + + /* set seek of p_fci_internal->handleCFFOLDER to 0 */ + if( PFCI_SEEK(hfci,p_fci_internal->handleCFFOLDER, + 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) { + /* TODO wrong return value */ + } + /* TODO error handling of err */ + + /* while not all CFFOLDER structures have been copied into the cabinet do */ + while(!FALSE) { + /* use the variable read_result */ + /* read cffolder of p_fci_internal->handleCFFOLDER */ + read_result = PFCI_READ(hfci, p_fci_internal->handleCFFOLDER, /* handle */ + &cffolder, /* memory buffer */ + sizeof(cffolder), /* number of bytes to copy */ + &err, p_fci_internal->pv); + if( read_result != sizeof(cffolder) ) { + if( read_result == 0 ) break; /*ALL CFFOLDER structures have been copied*/ + /* TODO read error */ + return FALSE; + } + /* TODO error handling of err */ + + /* add size of header size of all CFFOLDERs and size of all CFFILEs */ + cffolder.coffCabStart += + p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER + + sizeof(CFHEADER); + if( p_fci_internal->fNextCab || + p_fci_internal->fGetNextCabInVain ) { + cffolder.coffCabStart+=p_fci_internal->oldCCAB.cbReserveCFHeader; + } else { + cffolder.coffCabStart+=p_fci_internal->pccab->cbReserveCFHeader; + } + + if (p_fci_internal->fPrevCab) { + cffolder.coffCabStart += strlen(p_fci_internal->szPrevCab)+1 + + strlen(p_fci_internal->szPrevDisk)+1; + } + + if (p_fci_internal->fNextCab) { + cffolder.coffCabStart += strlen(p_fci_internal->oldCCAB.szCab)+1 + + strlen(p_fci_internal->oldCCAB.szDisk)+1; + } + + if( p_fci_internal->fNextCab || + p_fci_internal->fGetNextCabInVain ) { + cffolder.coffCabStart += p_fci_internal->oldCCAB.cbReserveCFHeader; + if( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || + p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || + p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { + cffolder.coffCabStart += 4; + } + } else { + cffolder.coffCabStart += p_fci_internal->pccab->cbReserveCFHeader; + if( p_fci_internal->pccab->cbReserveCFHeader != 0 || + p_fci_internal->pccab->cbReserveCFFolder != 0 || + p_fci_internal->pccab->cbReserveCFData != 0 ) { + cffolder.coffCabStart += 4; + } + } + + /* write cffolder to cabinet file */ + if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ + &cffolder, /* memory buffer */ + sizeof(cffolder), /* number of bytes to copy */ + &err, p_fci_internal->pv) != sizeof(cffolder) ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + /* add optional reserved area */ + + /* This allocation and freeing at each CFFolder block is a bit */ + /* inefficent, but it's harder to forget about freeing the buffer :-). */ + /* Reserved areas are used seldom besides that... */ + if (cbReserveCFFolder!=0) { + if(!(reserved = PFCI_ALLOC(hfci, cbReserveCFFolder))) { + p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL; + p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + p_fci_internal->perf->fError = TRUE; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + + if( PFCI_READ(hfci, p_fci_internal->handleCFFOLDER, /* file handle */ + reserved, /* memory buffer */ + cbReserveCFFolder, /* number of bytes to copy */ + &err, p_fci_internal->pv) != cbReserveCFFolder ) { + PFCI_FREE(hfci, reserved); + /* TODO read error */ + return FALSE; + } + /* TODO error handling of err */ + + if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ + reserved, /* memory buffer */ + cbReserveCFFolder, /* number of bytes to copy */ + &err, p_fci_internal->pv) != cbReserveCFFolder ) { + PFCI_FREE(hfci, reserved); + /* TODO read error */ + return FALSE; + } + /* TODO error handling of err */ + + PFCI_FREE(hfci, reserved); + } + + } /* END OF while */ + + /* set seek of p_fci_internal->handleCFFILE2 to 0 */ + if( PFCI_SEEK(hfci,p_fci_internal->handleCFFILE2, + 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) { + /* TODO wrong return value */ + } + /* TODO error handling of err */ + + /* while not all CFFILE structures have been copied to the cabinet do */ + while(!FALSE) { + /* REUSE the variable read_result */ + /* REUSE the buffer p_fci_internal->data_out AGAIN */ + /* read a block from p_fci_internal->handleCFFILE2 */ + read_result = PFCI_READ(hfci, p_fci_internal->handleCFFILE2 /* handle */, + p_fci_internal->data_out, /* memory buffer */ + 32768, /* number of bytes to copy */ + &err, p_fci_internal->pv); + if( read_result == 0 ) break; /* ALL CFFILE structures have been copied */ + /* TODO error handling of err */ + + /* write the block to the cabinet file */ + if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ + p_fci_internal->data_out, /* memory buffer */ + read_result, /* number of bytes to copy */ + &err, p_fci_internal->pv) != read_result ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + if (p_fci_internal->fSplitFolder==FALSE) { + p_fci_internal->statusFolderCopied = 0; + p_fci_internal->statusFolderTotal = p_fci_internal->sizeFileCFDATA2+ + p_fci_internal->sizeFileCFFILE2; + } + p_fci_internal->statusFolderCopied += read_result; + +/* TODO is this correct */ + /* report status with pfnfcis about copied size of folder */ + if( (*pfnfcis)(statusFolder, + p_fci_internal->statusFolderCopied, /* length of copied blocks */ + p_fci_internal->statusFolderTotal, /* total size of folder */ + p_fci_internal->pv) == -1) { + /* TODO set error code and abort */ + return FALSE; + } + + } /* END OF while */ + + /* set seek of p_fci_internal->handleCFDATA2 to 0 */ + if( PFCI_SEEK(hfci,p_fci_internal->handleCFDATA2, + 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) { + /* TODO wrong return value */ + return FALSE; + } + /* TODO error handling of err */ + + /* reset the number of folders for the next cabinet */ + p_fci_internal->cFolders=0; + /* reset the number of files for the next cabinet */ + p_fci_internal->cFiles=0; + + /* while not all CFDATA structures have been copied to the cabinet do */ + while(!FALSE) { + /* REUSE the variable read_result AGAIN */ + /* REUSE the buffer p_fci_internal->data_out AGAIN */ + /* read a block from p_fci_internal->handleCFDATA2 */ + read_result = PFCI_READ(hfci, p_fci_internal->handleCFDATA2 /* handle */, + p_fci_internal->data_out, /* memory buffer */ + 32768, /* number of bytes to copy */ + &err, p_fci_internal->pv); + if( read_result == 0 ) break; /* ALL CFDATA structures have been copied */ + /* TODO error handling of err */ + + /* write the block to the cabinet file */ + if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ + p_fci_internal->data_out, /* memory buffer */ + read_result, /* number of bytes to copy */ + &err, p_fci_internal->pv) != read_result ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + p_fci_internal->statusFolderCopied += read_result; + /* report status with pfnfcis about copied size of folder */ + if( (*pfnfcis)(statusFolder, + p_fci_internal->statusFolderCopied, /* length of copied blocks */ + p_fci_internal->statusFolderTotal, /* total size of folder */ + p_fci_internal->pv) == -1) { + /* TODO set error code and abort */ + return FALSE; + } + } /* END OF while */ + + /* set seek of the cabinet file to 0 */ + if( PFCI_SEEK(hfci, handleCABINET, + 0, SEEK_SET, &err, p_fci_internal->pv) != 0 ) { + /* TODO wrong return value */ + } + /* TODO error handling of err */ + + /* write the signature "MSCF" into the cabinet file */ + memcpy( cfheader.signature, "MSCF", 4 ); + if( PFCI_WRITE(hfci, handleCABINET, /* file handle */ + &cfheader, /* memory buffer */ + 4, /* number of bytes to copy */ + &err, p_fci_internal->pv) != 4 ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + /* close the cabinet file */ + PFCI_CLOSE(hfci,handleCABINET,&err,p_fci_internal->pv); + /* TODO error handling of err */ + + +/* COPIED FROM FCIDestroy */ + + PFCI_CLOSE (hfci, p_fci_internal->handleCFDATA2,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_DELETE(hfci, p_fci_internal->szFileNameCFDATA2, &err, + p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_CLOSE (hfci, p_fci_internal->handleCFFILE2,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFILE2, &err, + p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_CLOSE (hfci, p_fci_internal->handleCFFOLDER,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFOLDER, &err, + p_fci_internal->pv); + /* TODO error handling of err */ + +/* END OF copied from FCIDestroy */ + + /* get 3 temporary files and open them */ + /* write names and handles to hfci */ + + + p_fci_internal->sizeFileCFDATA2 = 0; + p_fci_internal->sizeFileCFFILE2 = 0; + p_fci_internal->sizeFileCFFOLDER = 0; + +/* COPIED FROM FCICreate */ + + /* CFDATA with checksum and ready to be copied into cabinet */ + if( !PFCI_GETTEMPFILE(hfci, p_fci_internal->szFileNameCFDATA2, + CB_MAX_FILENAME)) { + /* TODO error handling */ + return FALSE; + } + /* safety */ + if ( strlen(p_fci_internal->szFileNameCFDATA2) >= CB_MAX_FILENAME ) { + /* TODO set error code */ + return FALSE; + } + p_fci_internal->handleCFDATA2 = PFCI_OPEN(hfci, + p_fci_internal->szFileNameCFDATA2, 34050, 384, &err, p_fci_internal->pv); + /* TODO check handle */ + /* TODO error checking of err */ + + /* array of all CFFILE in a folder, ready to be copied into cabinet */ + if( !PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFILE2, + CB_MAX_FILENAME)) { + /* TODO error handling */ + return FALSE; + } + /* safety */ + if ( strlen(p_fci_internal->szFileNameCFFILE2) >= CB_MAX_FILENAME ) { + /* TODO set error code */ + return FALSE; + } + p_fci_internal->handleCFFILE2 = PFCI_OPEN(hfci, + p_fci_internal->szFileNameCFFILE2, 34050, 384, &err, p_fci_internal->pv); + /* TODO check handle */ + /* TODO error checking of err */ + + /* array of all CFFILE in a folder, ready to be copied into cabinet */ + if (!PFCI_GETTEMPFILE(hfci,p_fci_internal->szFileNameCFFOLDER,CB_MAX_FILENAME)) { + /* TODO error handling */ + return FALSE; + } + /* safety */ + if ( strlen(p_fci_internal->szFileNameCFFOLDER) >= CB_MAX_FILENAME ) { + /* TODO set error code */ + return FALSE; + } + p_fci_internal->handleCFFOLDER = PFCI_OPEN(hfci, + p_fci_internal->szFileNameCFFOLDER, 34050, 384, &err, p_fci_internal->pv); + /* TODO check handle */ + /* TODO error checking of err */ + +/* END OF copied from FCICreate */ + + + /* TODO close and delete new files when return FALSE */ + + + /* report status with pfnfcis about copied size of folder */ + if( (*pfnfcis)(statusCabinet, p_fci_internal->statusFolderTotal, /* TODO estimated cabinet file size */ + cfheader.cbCabinet, /* real cabinet file size */ p_fci_internal->pv) == -1) { + /* TODO set error code and abort */ + return FALSE; + } + + p_fci_internal->fPrevCab=TRUE; + /* The sections szPrevCab and szPrevDisk are not being updated, because */ + /* MS CABINET.DLL always puts the first cabinet name and disk into them */ + + if (p_fci_internal->fNextCab) { + p_fci_internal->fNextCab=FALSE; + + if (p_fci_internal->sizeFileCFFILE1==0 && p_fci_internal->sizeFileCFDATA1!=0) { + /* THIS CAN NEVER HAPPEN */ + /* TODO set error code */ + return FALSE; + } + +/* COPIED FROM FCIAddFile and modified */ + + /* REUSE the variable read_result */ + if (p_fci_internal->fGetNextCabInVain) { + read_result=p_fci_internal->oldCCAB.cbReserveCFHeader; + if(p_fci_internal->sizeFileCFFILE1!=0) { + read_result+=p_fci_internal->oldCCAB.cbReserveCFFolder; + } + if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || + p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || + p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { + read_result+=4; + } + } else { + read_result=p_fci_internal->pccab->cbReserveCFHeader; + if(p_fci_internal->sizeFileCFFILE1!=0) { + read_result+=p_fci_internal->pccab->cbReserveCFFolder; + } + if ( p_fci_internal->pccab->cbReserveCFHeader != 0 || + p_fci_internal->pccab->cbReserveCFFolder != 0 || + p_fci_internal->pccab->cbReserveCFData != 0 ) { + read_result+=4; + } + } + if ( p_fci_internal->fPrevCab ) { + read_result+= strlen(p_fci_internal->szPrevCab)+1+ + strlen(p_fci_internal->szPrevDisk)+1; + } + read_result+= p_fci_internal->sizeFileCFDATA1 + + p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 + + p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER + + sizeof(CFHEADER) + + sizeof(CFFOLDER); /* set size of new CFFolder entry */ + + if( p_fci_internal->fNewPrevious ) { + memcpy(p_fci_internal->szPrevCab, p_fci_internal->oldCCAB.szCab, + CB_MAX_CABINET_NAME); + memcpy(p_fci_internal->szPrevDisk, p_fci_internal->oldCCAB.szDisk, + CB_MAX_DISK_NAME); + p_fci_internal->fNewPrevious=FALSE; + } + + /* too much data for the maximum size of a cabinet */ + if( p_fci_internal->fGetNextCabInVain==FALSE && + p_fci_internal->pccab->cb < read_result ) { + return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis); + } + + /* Might be too much data for the maximum size of a cabinet.*/ + /* When any further data will be added later, it might not */ + /* be possible to flush the cabinet, because there might */ + /* not be enough space to store the name of the following */ + /* cabinet and name of the corresponding disk. */ + /* So take care of this and get the name of the next cabinet */ + if (p_fci_internal->fGetNextCabInVain==FALSE && ( + p_fci_internal->pccab->cb < read_result + + CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME + )) { + /* save CCAB */ + memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB)); + /* increment cabinet index */ + ++(p_fci_internal->pccab->iCab); + /* get name of next cabinet */ + if (!(*pfnfcignc)(p_fci_internal->pccab, 0, /* estimated size of cab */ + p_fci_internal->pv)) { + /* TODO error handling */ + return FALSE; + } + /* Skip a few lines of code. This is catched by the next if. */ + p_fci_internal->fGetNextCabInVain=TRUE; + } + + /* too much data for cabinet */ + if (p_fci_internal->fGetNextCabInVain && ( + p_fci_internal->oldCCAB.cb < read_result + + strlen(p_fci_internal->oldCCAB.szCab)+1+ + strlen(p_fci_internal->oldCCAB.szDisk)+1 + )) { + p_fci_internal->fGetNextCabInVain=FALSE; + p_fci_internal->fNextCab=TRUE; + return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis); + } + + /* if the FolderThreshold has been reached flush the folder automatically */ + if( p_fci_internal->fGetNextCabInVain ) { + if( p_fci_internal->cCompressedBytesInFolder >= + p_fci_internal->oldCCAB.cbFolderThresh) { + return FCIFlushFolder(hfci, pfnfcignc, pfnfcis); + } + } else { + if( p_fci_internal->cCompressedBytesInFolder >= + p_fci_internal->pccab->cbFolderThresh) { + return FCIFlushFolder(hfci, pfnfcignc, pfnfcis); + } + } + +/* END OF COPIED FROM FCIAddFile and modified */ + + if( p_fci_internal->sizeFileCFFILE1>0 ) { + if( !FCIFlushFolder(hfci, pfnfcignc, pfnfcis) ) return FALSE; + p_fci_internal->fNewPrevious=TRUE; + } + } else { + p_fci_internal->fNewPrevious=FALSE; + if( p_fci_internal->sizeFileCFFILE1>0 || p_fci_internal->sizeFileCFDATA1) { + /* THIS MAY NEVER HAPPEN */ + /* TODO set error structures */ + return FALSE; + } + } + + return TRUE; +} /* end of fci_flush_cabinet */ + + + + + +/*********************************************************************** + * FCIAddFile (CABINET.11) + * + * FCIAddFile adds a file to the to be created cabinet file + * + * PARAMS + * hfci [I] An HFCI from FCICreate + * pszSourceFile [I] A pointer to a C string which contains the name and + * location of the file which will be added to the cabinet + * pszFileName [I] A pointer to a C string which contains the name under + * which the file will be stored in the cabinet + * fExecute [I] A boolean value which indicates if the file should be + * executed after extraction of self extracting + * executables + * pfnfcignc [I] A pointer to a function which gets information about + * the next cabinet + * pfnfcis [IO] A pointer to a function which will report status + * information about the compression process + * pfnfcioi [I] A pointer to a function which reports file attributes + * and time and date information + * typeCompress [I] Compression type + * + * RETURNS + * On success, returns TRUE + * On failure, returns FALSE + * + * INCLUDES + * fci.h + * + */ +BOOL __cdecl FCIAddFile( + HFCI hfci, + char *pszSourceFile, + char *pszFileName, + BOOL fExecute, + PFNFCIGETNEXTCABINET pfnfcignc, + PFNFCISTATUS pfnfcis, + PFNFCIGETOPENINFO pfnfcigoi, + TCOMP typeCompress) +{ + int err; + CFFILE cffile; + cab_ULONG read_result; + int file_handle; + PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); + + /* test hfci */ + if (!REALLY_IS_FCI(hfci)) { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if ((!pszSourceFile) || (!pszFileName) || (!pfnfcignc) || (!pfnfcis) || + (!pfnfcigoi) || strlen(pszFileName)>=CB_MAX_FILENAME) { + p_fci_internal->perf->erfOper = FCIERR_NONE; + p_fci_internal->perf->erfType = ERROR_BAD_ARGUMENTS; + p_fci_internal->perf->fError = TRUE; + + SetLastError(ERROR_BAD_ARGUMENTS); + return FALSE; + } + + /* TODO check if pszSourceFile??? */ + + if(p_fci_internal->fGetNextCabInVain && p_fci_internal->fNextCab) { + /* TODO internal error */ + return FALSE; + } + + if(p_fci_internal->fNextCab) { + /* TODO internal error */ + return FALSE; + } + + cffile.cbFile=0; /* size of the to be added file*/ + /* offset of the uncompressed file in the folder */ + cffile.uoffFolderStart=p_fci_internal->cDataBlocks*CAB_BLOCKMAX + p_fci_internal->cdata_in; + /* number of folder in the cabinet or special 0=first */ + cffile.iFolder = p_fci_internal->cFolders; + + /* allocation of memory */ + if (p_fci_internal->data_in==NULL) { + if (p_fci_internal->cdata_in!=0) { + /* TODO error handling */ + return FALSE; + } + if (p_fci_internal->data_out!=NULL) { + /* TODO error handling */ + return FALSE; + } + if(!(p_fci_internal->data_in = (char*)PFCI_ALLOC(hfci,CB_MAX_CHUNK))) { + p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL; + p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + p_fci_internal->perf->fError = TRUE; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + if (p_fci_internal->data_out==NULL) { + if(!(p_fci_internal->data_out = PFCI_ALLOC(hfci, 2 * CB_MAX_CHUNK))){ + p_fci_internal->perf->erfOper = FCIERR_ALLOC_FAIL; + p_fci_internal->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + p_fci_internal->perf->fError = TRUE; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + } + } + + if (p_fci_internal->data_out==NULL) { + PFCI_FREE(hfci,p_fci_internal->data_in); + /* TODO error handling */ + return FALSE; + } + + /* get information about the file */ + file_handle=(*pfnfcigoi)(pszSourceFile, &(cffile.date), &(cffile.time), + &(cffile.attribs), &err, p_fci_internal->pv); + /* TODO check file_handle */ + /* TODO error handling of err */ + + if (fExecute) { cffile.attribs |= _A_EXEC; } + + /* REUSE the variable read_result */ + if (p_fci_internal->fGetNextCabInVain) { + read_result=p_fci_internal->oldCCAB.cbReserveCFHeader + + p_fci_internal->oldCCAB.cbReserveCFFolder; + if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || + p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || + p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { + read_result+=4; + } + } else { + read_result=p_fci_internal->pccab->cbReserveCFHeader + + p_fci_internal->pccab->cbReserveCFFolder; + if ( p_fci_internal->pccab->cbReserveCFHeader != 0 || + p_fci_internal->pccab->cbReserveCFFolder != 0 || + p_fci_internal->pccab->cbReserveCFData != 0 ) { + read_result+=4; + } + } + if ( p_fci_internal->fPrevCab ) { + read_result+= strlen(p_fci_internal->szPrevCab)+1+ + strlen(p_fci_internal->szPrevDisk)+1; + } + if ( p_fci_internal->fNextCab ) { /* this is never the case */ + read_result+= strlen(p_fci_internal->pccab->szCab)+1+ + strlen(p_fci_internal->pccab->szDisk)+1; + } + + read_result+= sizeof(CFFILE) + strlen(pszFileName)+1 + + p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 + + p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER + + sizeof(CFHEADER) + + sizeof(CFFOLDER); /* size of new CFFolder entry */ + + /* Might be too much data for the maximum size of a cabinet.*/ + /* When any further data will be added later, it might not */ + /* be possible to flush the cabinet, because there might */ + /* not be enough space to store the name of the following */ + /* cabinet and name of the corresponding disk. */ + /* So take care of this and get the name of the next cabinet */ + if( p_fci_internal->fGetNextCabInVain==FALSE && + p_fci_internal->fNextCab==FALSE && + ( p_fci_internal->pccab->cb < read_result + + CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME + ) + ) { + /* save CCAB */ + memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB)); + /* increment cabinet index */ + ++(p_fci_internal->pccab->iCab); + /* get name of next cabinet */ + if (!(*pfnfcignc)(p_fci_internal->pccab, 0,/* TODO estimated size of cab */ + p_fci_internal->pv)) { + /* TODO error handling */ + return FALSE; + } + /* Skip a few lines of code. This is catched by the next if. */ + p_fci_internal->fGetNextCabInVain=TRUE; + } + + if( p_fci_internal->fGetNextCabInVain && + p_fci_internal->fNextCab + ) { + /* THIS CAN NEVER HAPPEN */ + /* TODO set error code*/ + return FALSE; + } + + /* too much data for cabinet */ + if( p_fci_internal->fGetNextCabInVain && + ( + p_fci_internal->oldCCAB.cb < read_result + + strlen(p_fci_internal->pccab->szCab)+1+ + strlen(p_fci_internal->pccab->szDisk)+1 + )) { + p_fci_internal->fGetNextCabInVain=FALSE; + p_fci_internal->fNextCab=TRUE; + if(!fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis)) return FALSE; + } + + if( p_fci_internal->fNextCab ) { + /* THIS MAY NEVER HAPPEN */ + /* TODO set error code*/ + return FALSE; + } + + /* read the contents of the file blockwize*/ + while (!FALSE) { + if (p_fci_internal->cdata_in > CAB_BLOCKMAX) { + /* TODO internal error */ + return FALSE; + } + + read_result = PFCI_READ(hfci, file_handle /* file handle */, + (p_fci_internal->data_in + p_fci_internal->cdata_in) /* memory buffer */, + (CAB_BLOCKMAX - p_fci_internal->cdata_in) /* number of bytes to copy */, + &err, p_fci_internal->pv); + /* TODO error handling of err */ + + if( read_result==0 ) break; + + /* increment the block size */ + p_fci_internal->cdata_in += read_result; + + /* increment the file size */ + cffile.cbFile += read_result; + + + if ( p_fci_internal->cdata_in > CAB_BLOCKMAX ) { + /* TODO report internal error */ + return FALSE; + } + /* write a whole block */ + if ( p_fci_internal->cdata_in == CAB_BLOCKMAX ) { + + if( !fci_flush_data_block(hfci, &err, pfnfcis) ) return FALSE; + } + } + + /* close the file from FCIAddFile */ + PFCI_CLOSE(hfci,file_handle,&err,p_fci_internal->pv); + /* TODO error handling of err */ + + /* write cffile to p_fci_internal->handleCFFILE1 */ + if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE1, /* file handle */ + &cffile, sizeof(cffile),&err, p_fci_internal->pv) != sizeof(cffile) ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + p_fci_internal->sizeFileCFFILE1 += sizeof(cffile); + + /* append the name of file*/ + if (strlen(pszFileName)>=CB_MAX_FILENAME) { + /* IMPOSSIBLE */ + /* TODO set error code */ + return FALSE; + } + if( PFCI_WRITE(hfci, p_fci_internal->handleCFFILE1, /* file handle */ + pszFileName, strlen(pszFileName)+1, &err, p_fci_internal->pv) + != strlen(pszFileName)+1 ) { + /* TODO write error */ + return FALSE; + } + /* TODO error handling of err */ + + p_fci_internal->sizeFileCFFILE1 += strlen(pszFileName)+1; + + /* REUSE the variable read_result */ + if (p_fci_internal->fGetNextCabInVain || + p_fci_internal->fNextCab + ) { + read_result=p_fci_internal->oldCCAB.cbReserveCFHeader + + p_fci_internal->oldCCAB.cbReserveCFFolder; + if ( p_fci_internal->oldCCAB.cbReserveCFHeader != 0 || + p_fci_internal->oldCCAB.cbReserveCFFolder != 0 || + p_fci_internal->oldCCAB.cbReserveCFData != 0 ) { + read_result+=4; + } + } else { + read_result=p_fci_internal->pccab->cbReserveCFHeader + + p_fci_internal->pccab->cbReserveCFFolder; + if ( p_fci_internal->pccab->cbReserveCFHeader != 0 || + p_fci_internal->pccab->cbReserveCFFolder != 0 || + p_fci_internal->pccab->cbReserveCFData != 0 ) { + read_result+=4; + } + } + if ( p_fci_internal->fPrevCab ) { + read_result+= strlen(p_fci_internal->szPrevCab)+1+ + strlen(p_fci_internal->szPrevDisk)+1; + } + if ( p_fci_internal->fNextCab ) { /* this is never the case */ + read_result+= strlen(p_fci_internal->pccab->szCab)+1+ + strlen(p_fci_internal->pccab->szDisk)+1; + } + read_result+= p_fci_internal->sizeFileCFDATA1 + + p_fci_internal->sizeFileCFFILE1 + p_fci_internal->sizeFileCFDATA2 + + p_fci_internal->sizeFileCFFILE2 + p_fci_internal->sizeFileCFFOLDER + + sizeof(CFHEADER) + + sizeof(CFFOLDER); /* set size of new CFFolder entry */ + + /* too much data for the maximum size of a cabinet */ + /* (ignoring the unflushed data block) */ + if( p_fci_internal->fGetNextCabInVain==FALSE && + p_fci_internal->fNextCab==FALSE && /* this is always the case */ + p_fci_internal->pccab->cb < read_result ) { + return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis); + } + + /* Might be too much data for the maximum size of a cabinet.*/ + /* When any further data will be added later, it might not */ + /* be possible to flush the cabinet, because there might */ + /* not be enough space to store the name of the following */ + /* cabinet and name of the corresponding disk. */ + /* So take care of this and get the name of the next cabinet */ + /* (ignoring the unflushed data block) */ + if( p_fci_internal->fGetNextCabInVain==FALSE && + p_fci_internal->fNextCab==FALSE && + ( p_fci_internal->pccab->cb < read_result + + CB_MAX_CABINET_NAME + CB_MAX_DISK_NAME + ) + ) { + /* save CCAB */ + memcpy(&(p_fci_internal->oldCCAB), p_fci_internal->pccab, sizeof(CCAB)); + /* increment cabinet index */ + ++(p_fci_internal->pccab->iCab); + /* get name of next cabinet */ + if (!(*pfnfcignc)(p_fci_internal->pccab, 0,/* TODO estimated size of cab */ + p_fci_internal->pv)) { + /* TODO error handling */ + return FALSE; + } + /* Skip a few lines of code. This is catched by the next if. */ + p_fci_internal->fGetNextCabInVain=TRUE; + } + + if( p_fci_internal->fGetNextCabInVain && + p_fci_internal->fNextCab + ) { + /* THIS CAN NEVER HAPPEN */ + /* TODO set error code*/ + return FALSE; + } + + /* too much data for cabinet */ + if( (p_fci_internal->fGetNextCabInVain || + p_fci_internal->fNextCab) && ( + p_fci_internal->oldCCAB.cb < read_result + + strlen(p_fci_internal->pccab->szCab)+1+ + strlen(p_fci_internal->pccab->szDisk)+1 + )) { + + p_fci_internal->fGetNextCabInVain=FALSE; + p_fci_internal->fNextCab=TRUE; + return fci_flush_cabinet( hfci, FALSE, pfnfcignc, pfnfcis); + } + + if( p_fci_internal->fNextCab ) { + /* THIS MAY NEVER HAPPEN */ + /* TODO set error code*/ + return FALSE; + } + + /* if the FolderThreshold has been reached flush the folder automatically */ + if( p_fci_internal->fGetNextCabInVain ) { + if( p_fci_internal->cCompressedBytesInFolder >= + p_fci_internal->oldCCAB.cbFolderThresh) { + return FCIFlushFolder(hfci, pfnfcignc, pfnfcis); + } + } else { + if( p_fci_internal->cCompressedBytesInFolder >= + p_fci_internal->pccab->cbFolderThresh) { + return FCIFlushFolder(hfci, pfnfcignc, pfnfcis); + } + } + + return TRUE; +} /* end of FCIAddFile */ + + + + + +/*********************************************************************** + * FCIFlushFolder (CABINET.12) + * + * FCIFlushFolder completes the CFFolder structure under construction. + * + * All further data which is added by FCIAddFile will be associateed to + * the next CFFolder structure. + * + * FCIFlushFolder will be called by FCIAddFile automatically if the + * threshold (stored in the member cbFolderThresh of the CCAB structure + * pccab passed to FCICreate) is exceeded. + * + * FCIFlushFolder will be called by FCIFlushFolder automatically before + * any data will be written into the cabinet file. + * + * PARAMS + * hfci [I] An HFCI from FCICreate + * pfnfcignc [I] A pointer to a function which gets information about + * the next cabinet + * pfnfcis [IO] A pointer to a function which will report status + * information about the compression process + * + * RETURNS + * On success, returns TRUE + * On failure, returns FALSE + * + * INCLUDES + * fci.h + * + */ +BOOL __cdecl FCIFlushFolder( + HFCI hfci, + PFNFCIGETNEXTCABINET pfnfcignc, + PFNFCISTATUS pfnfcis) +{ + return fci_flush_folder(hfci,FALSE,pfnfcignc,pfnfcis); +} /* end of FCIFlushFolder */ + + + +/*********************************************************************** + * FCIFlushCabinet (CABINET.13) + * + * FCIFlushCabinet stores the data which has been added by FCIAddFile + * into the cabinet file. If the maximum cabinet size (stored in the + * member cb of the CCAB structure pccab passed to FCICreate) has been + * exceeded FCIFlushCabinet will be called automatic by FCIAddFile. + * The remaining data still has to be flushed manually by calling + * FCIFlushCabinet. + * + * After FCIFlushCabinet has been called (manually) FCIAddFile must + * NOT be called again. Then hfci has to be released by FCIDestroy. + * + * PARAMS + * hfci [I] An HFCI from FCICreate + * fGetNextCab [I] Whether you want to add additional files to a + * cabinet set (TRUE) or whether you want to + * finalize it (FALSE) + * pfnfcignc [I] A pointer to a function which gets information about + * the next cabinet + * pfnfcis [IO] A pointer to a function which will report status + * information about the compression process + * + * RETURNS + * On success, returns TRUE + * On failure, returns FALSE + * + * INCLUDES + * fci.h + * + */ +BOOL __cdecl FCIFlushCabinet( + HFCI hfci, + BOOL fGetNextCab, + PFNFCIGETNEXTCABINET pfnfcignc, + PFNFCISTATUS pfnfcis) +{ + PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); + + if(!fci_flush_cabinet(hfci,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE; + + while( p_fci_internal->sizeFileCFFILE1>0 || + p_fci_internal->sizeFileCFFILE2>0 ) { + if(!fci_flush_cabinet(hfci,fGetNextCab,pfnfcignc,pfnfcis)) return FALSE; + } + + return TRUE; +} /* end of FCIFlushCabinet */ + + +/*********************************************************************** + * FCIDestroy (CABINET.14) + * + * Frees a handle created by FCICreate. + * Only reason for failure would be an invalid handle. + * + * PARAMS + * hfci [I] The HFCI to free + * + * RETURNS + * TRUE for success + * FALSE for failure + */ +BOOL __cdecl FCIDestroy(HFCI hfci) +{ + int err; + PFCI_Int p_fci_internal=((PFCI_Int)(hfci)); + if (REALLY_IS_FCI(hfci)) { + + /* before hfci can be removed all temporary files must be closed */ + /* and deleted */ + p_fci_internal->FCI_Intmagic = 0; + + PFCI_CLOSE (hfci, p_fci_internal->handleCFDATA1,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_DELETE(hfci, p_fci_internal->szFileNameCFDATA1, &err, + p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_CLOSE (hfci, p_fci_internal->handleCFFILE1,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFILE1, &err, + p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_CLOSE (hfci, p_fci_internal->handleCFDATA2,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_DELETE(hfci, p_fci_internal->szFileNameCFDATA2, &err, + p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_CLOSE (hfci, p_fci_internal->handleCFFILE2,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFILE2, &err, + p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_CLOSE (hfci, p_fci_internal->handleCFFOLDER,&err,p_fci_internal->pv); + /* TODO error handling of err */ + PFCI_DELETE(hfci, p_fci_internal->szFileNameCFFOLDER, &err, + p_fci_internal->pv); + /* TODO error handling of err */ + + /* data in and out buffers have to be removed */ + if (p_fci_internal->data_in!=NULL) + PFCI_FREE(hfci, p_fci_internal->data_in); + if (p_fci_internal->data_out!=NULL) + PFCI_FREE(hfci, p_fci_internal->data_out); + + /* hfci can now be removed */ + PFCI_FREE(hfci, hfci); + return TRUE; + } else { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + +} /* end of FCIDestroy */ diff --git a/reactos/lib/cabinet/fdi.c b/reactos/lib/cabinet/fdi.c index b845c7cf524..8dec46e5c25 100644 --- a/reactos/lib/cabinet/fdi.c +++ b/reactos/lib/cabinet/fdi.c @@ -1,2839 +1,2839 @@ -/* - * File Decompression Interface - * - * Copyright 2000-2002 Stuart Caie - * Copyright 2002 Patrik Stridvall - * Copyright 2003 Greg Turner - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * - * This is a largely redundant reimplementation of the stuff in cabextract.c. It - * would be theoretically preferable to have only one, shared implementation, however - * there are semantic differences which may discourage efforts to unify the two. It - * should be possible, if awkward, to go back and reimplement cabextract.c using FDI. - * But this approach would be quite a bit less performant. Probably a better way - * would be to create a "library" of routines in cabextract.c which do the actual - * decompression, and have both fdi.c and cabextract share those routines. The rest - * of the code is not sufficiently similar to merit a shared implementation. - * - * The worst thing about this API is the bug. "The bug" is this: when you extract a - * cabinet, it /always/ informs you (via the hasnext field of PFDICABINETINFO), that - * there is no subsequent cabinet, even if there is one. wine faithfully reproduces - * this behavior. - * - * TODO: - * - * Wine does not implement the AFAIK undocumented "enumerate" callback during - * FDICopy. It is implemented in Windows and therefore worth investigating... - * - * Lots of pointers flying around here... am I leaking RAM? - * - * WTF is FDITruncate? - * - * Probably, I need to weed out some dead code-paths. - * - * Test unit(s). - * - * The fdintNEXT_CABINET callbacks are probably not working quite as they should. - * There are several FIXME's in the source describing some of the deficiencies in - * some detail. Additionally, we do not do a very good job of returning the right - * error codes to this callback. - * - * FDICopy and fdi_decomp are incomprehensibly large; separating these into smaller - * functions would be nice. - * - * -gmt - */ - -#include "config.h" - -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "fdi.h" -#include "cabinet.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(cabinet); - -THOSE_ZIP_CONSTS; - -struct fdi_file { - struct fdi_file *next; /* next file in sequence */ - LPCSTR filename; /* output name of file */ - int fh; /* open file handle or NULL */ - cab_ULONG length; /* uncompressed length of file */ - cab_ULONG offset; /* uncompressed offset in folder */ - cab_UWORD index; /* magic index number of folder */ - cab_UWORD time, date, attribs; /* MS-DOS time/date/attributes */ - BOOL oppressed; /* never to be processed */ -}; - -struct fdi_folder { - struct fdi_folder *next; - cab_off_t offset; /* offset to data blocks (32 bit) */ - cab_UWORD comp_type; /* compression format/window size */ - cab_ULONG comp_size; /* compressed size of folder */ - cab_UBYTE num_splits; /* number of split blocks + 1 */ - cab_UWORD num_blocks; /* total number of blocks */ -}; - -/* - * this structure fills the gaps between what is available in a PFDICABINETINFO - * vs what is needed by FDICopy. Memory allocated for these becomes the responsibility - * of the caller to free. Yes, I am aware that this is totally, utterly inelegant. - * To make things even more unnecessarily confusing, we now attach these to the - * fdi_decomp_state. - */ -typedef struct { - char *prevname, *previnfo; - char *nextname, *nextinfo; - BOOL hasnext; /* bug free indicator */ - int folder_resv, header_resv; - cab_UBYTE block_resv; -} MORE_ISCAB_INFO, *PMORE_ISCAB_INFO; - -/* - * ugh, well, this ended up being pretty damn silly... - * now that I've conceded to build equivalent structures to struct cab.*, - * I should have just used those, or, better yet, unified the two... sue me. - * (Note to Microsoft: That's a joke. Please /don't/ actually sue me! -gmt). - * Nevertheless, I've come this far, it works, so I'm not gonna change it - * for now. This implementation has significant semantic differences anyhow. - */ - -typedef struct fdi_cds_fwd { - void *hfdi; /* the hfdi we are using */ - int filehf, cabhf; /* file handle we are using */ - struct fdi_folder *current; /* current folder we're extracting from */ - cab_ULONG offset; /* uncompressed offset within folder */ - cab_UBYTE *outpos; /* (high level) start of data to use up */ - cab_UWORD outlen; /* (high level) amount of data to use up */ - int (*decompress)(int, int, struct fdi_cds_fwd *); /* chosen compress fn */ - cab_UBYTE inbuf[CAB_INPUTMAX+2]; /* +2 for lzx bitbuffer overflows! */ - cab_UBYTE outbuf[CAB_BLOCKMAX]; - union { - struct ZIPstate zip; - struct QTMstate qtm; - struct LZXstate lzx; - } methods; - /* some temp variables for use during decompression */ - cab_UBYTE q_length_base[27], q_length_extra[27], q_extra_bits[42]; - cab_ULONG q_position_base[42]; - cab_ULONG lzx_position_base[51]; - cab_UBYTE extra_bits[51]; - USHORT setID; /* Cabinet set ID */ - USHORT iCabinet; /* Cabinet number in set (0 based) */ - struct fdi_cds_fwd *decomp_cab; - MORE_ISCAB_INFO mii; - struct fdi_folder *firstfol; - struct fdi_file *firstfile; - struct fdi_cds_fwd *next; -} fdi_decomp_state; - -/*********************************************************************** - * FDICreate (CABINET.20) - * - * Provided with several callbacks (all of them are mandatory), - * returns a handle which can be used to perform operations - * on cabinet files. - * - * PARAMS - * pfnalloc [I] A pointer to a function which allocates ram. Uses - * the same interface as malloc. - * pfnfree [I] A pointer to a function which frees ram. Uses the - * same interface as free. - * pfnopen [I] A pointer to a function which opens a file. Uses - * the same interface as _open. - * pfnread [I] A pointer to a function which reads from a file into - * a caller-provided buffer. Uses the same interface - * as _read - * pfnwrite [I] A pointer to a function which writes to a file from - * a caller-provided buffer. Uses the same interface - * as _write. - * pfnclose [I] A pointer to a function which closes a file handle. - * Uses the same interface as _close. - * pfnseek [I] A pointer to a function which seeks in a file. - * Uses the same interface as _lseek. - * cpuType [I] The type of CPU; ignored in wine (recommended value: - * cpuUNKNOWN, aka -1). - * perf [IO] A pointer to an ERF structure. When FDICreate - * returns an error condition, error information may - * be found here as well as from GetLastError. - * - * RETURNS - * On success, returns an FDI handle of type HFDI. - * On failure, the NULL file handle is returned. Error - * info can be retrieved from perf. - * - * INCLUDES - * fdi.h - * - */ -HFDI __cdecl FDICreate( - PFNALLOC pfnalloc, - PFNFREE pfnfree, - PFNOPEN pfnopen, - PFNREAD pfnread, - PFNWRITE pfnwrite, - PFNCLOSE pfnclose, - PFNSEEK pfnseek, - int cpuType, - PERF perf) -{ - HFDI rv; - - TRACE("(pfnalloc == ^%p, pfnfree == ^%p, pfnopen == ^%p, pfnread == ^%p, pfnwrite == ^%p, \ - pfnclose == ^%p, pfnseek == ^%p, cpuType == %d, perf == ^%p)\n", - pfnalloc, pfnfree, pfnopen, pfnread, pfnwrite, pfnclose, pfnseek, - cpuType, perf); - - if ((!pfnalloc) || (!pfnfree)) { - perf->erfOper = FDIERROR_NONE; - perf->erfType = ERROR_BAD_ARGUMENTS; - perf->fError = TRUE; - - SetLastError(ERROR_BAD_ARGUMENTS); - return NULL; - } - - if (!((rv = ((HFDI) (*pfnalloc)(sizeof(FDI_Int)))))) { - perf->erfOper = FDIERROR_ALLOC_FAIL; - perf->erfType = ERROR_NOT_ENOUGH_MEMORY; - perf->fError = TRUE; - - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - return NULL; - } - - PFDI_INT(rv)->FDI_Intmagic = FDI_INT_MAGIC; - PFDI_INT(rv)->pfnalloc = pfnalloc; - PFDI_INT(rv)->pfnfree = pfnfree; - PFDI_INT(rv)->pfnopen = pfnopen; - PFDI_INT(rv)->pfnread = pfnread; - PFDI_INT(rv)->pfnwrite = pfnwrite; - PFDI_INT(rv)->pfnclose = pfnclose; - PFDI_INT(rv)->pfnseek = pfnseek; - /* no-brainer: we ignore the cpu type; this is only used - for the 16-bit versions in Windows anyhow... */ - PFDI_INT(rv)->perf = perf; - - return rv; -} - -/******************************************************************* - * FDI_getoffset (internal) - * - * returns the file pointer position of a file handle. - */ -long FDI_getoffset(HFDI hfdi, INT_PTR hf) -{ - return PFDI_SEEK(hfdi, hf, 0L, SEEK_CUR); -} - -/********************************************************************** - * FDI_realloc (internal) - * - * we can't use _msize; the user might not be using malloc, so we require - * an explicit specification of the previous size. inefficient. - */ -void *FDI_realloc(HFDI hfdi, void *mem, size_t prevsize, size_t newsize) -{ - void *rslt = NULL; - char *irslt, *imem; - size_t copysize = (prevsize < newsize) ? prevsize : newsize; - if (prevsize == newsize) return mem; - rslt = PFDI_ALLOC(hfdi, newsize); - if (rslt) - for (irslt = (char *)rslt, imem = (char *)mem; (copysize); copysize--) - *irslt++ = *imem++; - PFDI_FREE(hfdi, mem); - return rslt; -} - -/********************************************************************** - * FDI_read_string (internal) - * - * allocate and read an arbitrarily long string from the cabinet - */ -char *FDI_read_string(HFDI hfdi, INT_PTR hf, long cabsize) -{ - size_t len=256, - oldlen = 0, - base = FDI_getoffset(hfdi, hf), - maxlen = cabsize - base; - BOOL ok = FALSE; - unsigned int i; - cab_UBYTE *buf = NULL; - - TRACE("(hfdi == ^%p, hf == %d)\n", hfdi, hf); - - do { - if (len > maxlen) len = maxlen; - if (!(buf = FDI_realloc(hfdi, buf, oldlen, len))) break; - oldlen = len; - if (!PFDI_READ(hfdi, hf, buf, len)) break; - - /* search for a null terminator in what we've just read */ - for (i=0; i < len; i++) { - if (!buf[i]) {ok=TRUE; break;} - } - - if (!ok) { - if (len == maxlen) { - ERR("cabinet is truncated\n"); - break; - } - len += 256; - PFDI_SEEK(hfdi, hf, base, SEEK_SET); - } - } while (!ok); - - if (!ok) { - if (buf) - PFDI_FREE(hfdi, buf); - else - ERR("out of memory!\n"); - return NULL; - } - - /* otherwise, set the stream to just after the string and return */ - PFDI_SEEK(hfdi, hf, base + ((cab_off_t) strlen((char *) buf)) + 1, SEEK_SET); - - return (char *) buf; -} - -/****************************************************************** - * FDI_read_entries (internal) - * - * process the cabinet header in the style of FDIIsCabinet, but - * without the sanity checks (and bug) - */ -BOOL FDI_read_entries( - HFDI hfdi, - INT_PTR hf, - PFDICABINETINFO pfdici, - PMORE_ISCAB_INFO pmii) -{ - int num_folders, num_files, header_resv, folder_resv = 0; - LONG base_offset, cabsize; - USHORT setid, cabidx, flags; - cab_UBYTE buf[64], block_resv; - char *prevname = NULL, *previnfo = NULL, *nextname = NULL, *nextinfo = NULL; - - TRACE("(hfdi == ^%p, hf == %d, pfdici == ^%p)\n", hfdi, hf, pfdici); - - /* - * FIXME: I just noticed that I am memorizing the initial file pointer - * offset and restoring it before reading in the rest of the header - * information in the cabinet. Perhaps that's correct -- that is, perhaps - * this API is supposed to support "streaming" cabinets which are embedded - * in other files, or cabinets which begin at file offsets other than zero. - * Otherwise, I should instead go to the absolute beginning of the file. - * (Either way, the semantics of wine's FDICopy require me to leave the - * file pointer where it is afterwards -- If Windows does not do so, we - * ought to duplicate the native behavior in the FDIIsCabinet API, not here. - * - * So, the answer lies in Windows; will native cabinet.dll recognize a - * cabinet "file" embedded in another file? Note that cabextract.c does - * support this, which implies that Microsoft's might. I haven't tried it - * yet so I don't know. ATM, most of wine's FDI cabinet routines (except - * this one) would not work in this way. To fix it, we could just make the - * various references to absolute file positions in the code relative to an - * initial "beginning" offset. Because the FDICopy API doesn't take a - * file-handle like this one, we would therein need to search through the - * file for the beginning of the cabinet (as we also do in cabextract.c). - * Note that this limits us to a maximum of one cabinet per. file: the first. - * - * So, in summary: either the code below is wrong, or the rest of fdi.c is - * wrong... I cannot imagine that both are correct ;) One of these flaws - * should be fixed after determining the behavior on Windows. We ought - * to check both FDIIsCabinet and FDICopy for the right behavior. - * - * -gmt - */ - - /* get basic offset & size info */ - base_offset = FDI_getoffset(hfdi, hf); - - if (PFDI_SEEK(hfdi, hf, 0, SEEK_END) == -1) { - if (pmii) { - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET; - PFDI_INT(hfdi)->perf->erfType = 0; - PFDI_INT(hfdi)->perf->fError = TRUE; - } - return FALSE; - } - - cabsize = FDI_getoffset(hfdi, hf); - - if ((cabsize == -1) || (base_offset == -1) || - ( PFDI_SEEK(hfdi, hf, base_offset, SEEK_SET) == -1 )) { - if (pmii) { - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET; - PFDI_INT(hfdi)->perf->erfType = 0; - PFDI_INT(hfdi)->perf->fError = TRUE; - } - return FALSE; - } - - /* read in the CFHEADER */ - if (PFDI_READ(hfdi, hf, buf, cfhead_SIZEOF) != cfhead_SIZEOF) { - if (pmii) { - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET; - PFDI_INT(hfdi)->perf->erfType = 0; - PFDI_INT(hfdi)->perf->fError = TRUE; - } - return FALSE; - } - - /* check basic MSCF signature */ - if (EndGetI32(buf+cfhead_Signature) != 0x4643534d) { - if (pmii) { - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET; - PFDI_INT(hfdi)->perf->erfType = 0; - PFDI_INT(hfdi)->perf->fError = TRUE; - } - return FALSE; - } - - /* get the number of folders */ - num_folders = EndGetI16(buf+cfhead_NumFolders); - if (num_folders == 0) { - /* PONDERME: is this really invalid? */ - WARN("weird cabinet detect failure: no folders in cabinet\n"); - if (pmii) { - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET; - PFDI_INT(hfdi)->perf->erfType = 0; - PFDI_INT(hfdi)->perf->fError = TRUE; - } - return FALSE; - } - - /* get the number of files */ - num_files = EndGetI16(buf+cfhead_NumFiles); - if (num_files == 0) { - /* PONDERME: is this really invalid? */ - WARN("weird cabinet detect failure: no files in cabinet\n"); - if (pmii) { - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET; - PFDI_INT(hfdi)->perf->erfType = 0; - PFDI_INT(hfdi)->perf->fError = TRUE; - } - return FALSE; - } - - /* setid */ - setid = EndGetI16(buf+cfhead_SetID); - - /* cabinet (set) index */ - cabidx = EndGetI16(buf+cfhead_CabinetIndex); - - /* check the header revision */ - if ((buf[cfhead_MajorVersion] > 1) || - (buf[cfhead_MajorVersion] == 1 && buf[cfhead_MinorVersion] > 3)) - { - WARN("cabinet format version > 1.3\n"); - if (pmii) { - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_UNKNOWN_CABINET_VERSION; - PFDI_INT(hfdi)->perf->erfType = 0; /* ? */ - PFDI_INT(hfdi)->perf->fError = TRUE; - } - return FALSE; - } - - /* pull the flags out */ - flags = EndGetI16(buf+cfhead_Flags); - - /* read the reserved-sizes part of header, if present */ - if (flags & cfheadRESERVE_PRESENT) { - if (PFDI_READ(hfdi, hf, buf, cfheadext_SIZEOF) != cfheadext_SIZEOF) { - ERR("bunk reserve-sizes?\n"); - if (pmii) { - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET; - PFDI_INT(hfdi)->perf->erfType = 0; /* ? */ - PFDI_INT(hfdi)->perf->fError = TRUE; - } - return FALSE; - } - - header_resv = EndGetI16(buf+cfheadext_HeaderReserved); - if (pmii) pmii->header_resv = header_resv; - folder_resv = buf[cfheadext_FolderReserved]; - if (pmii) pmii->folder_resv = folder_resv; - block_resv = buf[cfheadext_DataReserved]; - if (pmii) pmii->block_resv = block_resv; - - if (header_resv > 60000) { - WARN("WARNING; header reserved space > 60000\n"); - } - - /* skip the reserved header */ - if ((header_resv) && (PFDI_SEEK(hfdi, hf, header_resv, SEEK_CUR) == -1)) { - ERR("seek failure: header_resv\n"); - if (pmii) { - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET; - PFDI_INT(hfdi)->perf->erfType = 0; /* ? */ - PFDI_INT(hfdi)->perf->fError = TRUE; - } - return FALSE; - } - } - - if (flags & cfheadPREV_CABINET) { - prevname = FDI_read_string(hfdi, hf, cabsize); - if (!prevname) { - if (pmii) { - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET; - PFDI_INT(hfdi)->perf->erfType = 0; /* ? */ - PFDI_INT(hfdi)->perf->fError = TRUE; - } - return FALSE; - } else - if (pmii) - pmii->prevname = prevname; - else - PFDI_FREE(hfdi, prevname); - previnfo = FDI_read_string(hfdi, hf, cabsize); - if (previnfo) { - if (pmii) - pmii->previnfo = previnfo; - else - PFDI_FREE(hfdi, previnfo); - } - } - - if (flags & cfheadNEXT_CABINET) { - if (pmii) - pmii->hasnext = TRUE; - nextname = FDI_read_string(hfdi, hf, cabsize); - if (!nextname) { - if ((flags & cfheadPREV_CABINET) && pmii) { - if (pmii->prevname) PFDI_FREE(hfdi, prevname); - if (pmii->previnfo) PFDI_FREE(hfdi, previnfo); - } - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET; - PFDI_INT(hfdi)->perf->erfType = 0; /* ? */ - PFDI_INT(hfdi)->perf->fError = TRUE; - return FALSE; - } else - if (pmii) - pmii->nextname = nextname; - else - PFDI_FREE(hfdi, nextname); - nextinfo = FDI_read_string(hfdi, hf, cabsize); - if (nextinfo) { - if (pmii) - pmii->nextinfo = nextinfo; - else - PFDI_FREE(hfdi, nextinfo); - } - } - - /* we could process the whole cabinet searching for problems; - instead lets stop here. Now let's fill out the paperwork */ - pfdici->cbCabinet = cabsize; - pfdici->cFolders = num_folders; - pfdici->cFiles = num_files; - pfdici->setID = setid; - pfdici->iCabinet = cabidx; - pfdici->fReserve = (flags & cfheadRESERVE_PRESENT) ? TRUE : FALSE; - pfdici->hasprev = (flags & cfheadPREV_CABINET) ? TRUE : FALSE; - pfdici->hasnext = (flags & cfheadNEXT_CABINET) ? TRUE : FALSE; - return TRUE; -} - -/*********************************************************************** - * FDIIsCabinet (CABINET.21) - * - * Informs the caller as to whether or not the provided file handle is - * really a cabinet or not, filling out the provided PFDICABINETINFO - * structure with information about the cabinet. Brief explanations of - * the elements of this structure are available as comments accompanying - * its definition in wine's include/fdi.h. - * - * PARAMS - * hfdi [I] An HFDI from FDICreate - * hf [I] The file handle about which the caller inquires - * pfdici [IO] Pointer to a PFDICABINETINFO structure which will - * be filled out with information about the cabinet - * file indicated by hf if, indeed, it is determined - * to be a cabinet. - * - * RETURNS - * TRUE if the file is a cabinet. The info pointed to by pfdici will - * be provided. - * FALSE if the file is not a cabinet, or if an error was encountered - * while processing the cabinet. The PERF structure provided to - * FDICreate can be queried for more error information. - * - * INCLUDES - * fdi.c - */ -BOOL __cdecl FDIIsCabinet( - HFDI hfdi, - INT_PTR hf, - PFDICABINETINFO pfdici) -{ - BOOL rv; - - TRACE("(hfdi == ^%p, hf == ^%d, pfdici == ^%p)\n", hfdi, hf, pfdici); - - if (!REALLY_IS_FDI(hfdi)) { - ERR("REALLY_IS_FDI failed on ^%p\n", hfdi); - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - - if (!hf) { - ERR("(!hf)!\n"); - /* PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CABINET_NOT_FOUND; - PFDI_INT(hfdi)->perf->erfType = ERROR_INVALID_HANDLE; - PFDI_INT(hfdi)->perf->fError = TRUE; */ - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - - if (!pfdici) { - ERR("(!pfdici)!\n"); - /* PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NONE; - PFDI_INT(hfdi)->perf->erfType = ERROR_BAD_ARGUMENTS; - PFDI_INT(hfdi)->perf->fError = TRUE; */ - SetLastError(ERROR_BAD_ARGUMENTS); - return FALSE; - } - rv = FDI_read_entries(hfdi, hf, pfdici, NULL); - - if (rv) - pfdici->hasnext = FALSE; /* yuck. duplicate apparent cabinet.dll bug */ - - return rv; -} - -/****************************************************************** - * QTMfdi_initmodel (internal) - * - * Initialize a model which decodes symbols from [s] to [s]+[n]-1 - */ -void QTMfdi_initmodel(struct QTMmodel *m, struct QTMmodelsym *sym, int n, int s) { - int i; - m->shiftsleft = 4; - m->entries = n; - m->syms = sym; - memset(m->tabloc, 0xFF, sizeof(m->tabloc)); /* clear out look-up table */ - for (i = 0; i < n; i++) { - m->tabloc[i+s] = i; /* set up a look-up entry for symbol */ - m->syms[i].sym = i+s; /* actual symbol */ - m->syms[i].cumfreq = n-i; /* current frequency of that symbol */ - } - m->syms[n].cumfreq = 0; -} - -/****************************************************************** - * QTMfdi_init (internal) - */ -int QTMfdi_init(int window, int level, fdi_decomp_state *decomp_state) { - unsigned int wndsize = 1 << window; - int msz = window * 2, i; - cab_ULONG j; - - /* QTM supports window sizes of 2^10 (1Kb) through 2^21 (2Mb) */ - /* if a previously allocated window is big enough, keep it */ - if (window < 10 || window > 21) return DECR_DATAFORMAT; - if (QTM(actual_size) < wndsize) { - if (QTM(window)) PFDI_FREE(CAB(hfdi), QTM(window)); - QTM(window) = NULL; - } - if (!QTM(window)) { - if (!(QTM(window) = PFDI_ALLOC(CAB(hfdi), wndsize))) return DECR_NOMEMORY; - QTM(actual_size) = wndsize; - } - QTM(window_size) = wndsize; - QTM(window_posn) = 0; - - /* initialize static slot/extrabits tables */ - for (i = 0, j = 0; i < 27; i++) { - CAB(q_length_extra)[i] = (i == 26) ? 0 : (i < 2 ? 0 : i - 2) >> 2; - CAB(q_length_base)[i] = j; j += 1 << ((i == 26) ? 5 : CAB(q_length_extra)[i]); - } - for (i = 0, j = 0; i < 42; i++) { - CAB(q_extra_bits)[i] = (i < 2 ? 0 : i-2) >> 1; - CAB(q_position_base)[i] = j; j += 1 << CAB(q_extra_bits)[i]; - } - - /* initialize arithmetic coding models */ - - QTMfdi_initmodel(&QTM(model7), &QTM(m7sym)[0], 7, 0); - - QTMfdi_initmodel(&QTM(model00), &QTM(m00sym)[0], 0x40, 0x00); - QTMfdi_initmodel(&QTM(model40), &QTM(m40sym)[0], 0x40, 0x40); - QTMfdi_initmodel(&QTM(model80), &QTM(m80sym)[0], 0x40, 0x80); - QTMfdi_initmodel(&QTM(modelC0), &QTM(mC0sym)[0], 0x40, 0xC0); - - /* model 4 depends on table size, ranges from 20 to 24 */ - QTMfdi_initmodel(&QTM(model4), &QTM(m4sym)[0], (msz < 24) ? msz : 24, 0); - /* model 5 depends on table size, ranges from 20 to 36 */ - QTMfdi_initmodel(&QTM(model5), &QTM(m5sym)[0], (msz < 36) ? msz : 36, 0); - /* model 6pos depends on table size, ranges from 20 to 42 */ - QTMfdi_initmodel(&QTM(model6pos), &QTM(m6psym)[0], msz, 0); - QTMfdi_initmodel(&QTM(model6len), &QTM(m6lsym)[0], 27, 0); - - return DECR_OK; -} - -/************************************************************ - * LZXfdi_init (internal) - */ -int LZXfdi_init(int window, fdi_decomp_state *decomp_state) { - cab_ULONG wndsize = 1 << window; - int i, j, posn_slots; - - /* LZX supports window sizes of 2^15 (32Kb) through 2^21 (2Mb) */ - /* if a previously allocated window is big enough, keep it */ - if (window < 15 || window > 21) return DECR_DATAFORMAT; - if (LZX(actual_size) < wndsize) { - if (LZX(window)) PFDI_FREE(CAB(hfdi), LZX(window)); - LZX(window) = NULL; - } - if (!LZX(window)) { - if (!(LZX(window) = PFDI_ALLOC(CAB(hfdi), wndsize))) return DECR_NOMEMORY; - LZX(actual_size) = wndsize; - } - LZX(window_size) = wndsize; - - /* initialize static tables */ - for (i=0, j=0; i <= 50; i += 2) { - CAB(extra_bits)[i] = CAB(extra_bits)[i+1] = j; /* 0,0,0,0,1,1,2,2,3,3... */ - if ((i != 0) && (j < 17)) j++; /* 0,0,1,2,3,4...15,16,17,17,17,17... */ - } - for (i=0, j=0; i <= 50; i++) { - CAB(lzx_position_base)[i] = j; /* 0,1,2,3,4,6,8,12,16,24,32,... */ - j += 1 << CAB(extra_bits)[i]; /* 1,1,1,1,2,2,4,4,8,8,16,16,32,32,... */ - } - - /* calculate required position slots */ - if (window == 20) posn_slots = 42; - else if (window == 21) posn_slots = 50; - else posn_slots = window << 1; - - /*posn_slots=i=0; while (i < wndsize) i += 1 << CAB(extra_bits)[posn_slots++]; */ - - LZX(R0) = LZX(R1) = LZX(R2) = 1; - LZX(main_elements) = LZX_NUM_CHARS + (posn_slots << 3); - LZX(header_read) = 0; - LZX(frames_read) = 0; - LZX(block_remaining) = 0; - LZX(block_type) = LZX_BLOCKTYPE_INVALID; - LZX(intel_curpos) = 0; - LZX(intel_started) = 0; - LZX(window_posn) = 0; - - /* initialize tables to 0 (because deltas will be applied to them) */ - for (i = 0; i < LZX_MAINTREE_MAXSYMBOLS; i++) LZX(MAINTREE_len)[i] = 0; - for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++) LZX(LENGTH_len)[i] = 0; - - return DECR_OK; -} - -/**************************************************** - * NONEfdi_decomp(internal) - */ -int NONEfdi_decomp(int inlen, int outlen, fdi_decomp_state *decomp_state) -{ - if (inlen != outlen) return DECR_ILLEGALDATA; - memcpy(CAB(outbuf), CAB(inbuf), (size_t) inlen); - return DECR_OK; -} - -/******************************************************** - * Ziphuft_free (internal) - */ -void fdi_Ziphuft_free(HFDI hfdi, struct Ziphuft *t) -{ - register struct Ziphuft *p, *q; - - /* Go through linked list, freeing from the allocated (t[-1]) address. */ - p = t; - while (p != (struct Ziphuft *)NULL) - { - q = (--p)->v.t; - PFDI_FREE(hfdi, p); - p = q; - } -} - -/********************************************************* - * fdi_Ziphuft_build (internal) - */ -cab_LONG fdi_Ziphuft_build(cab_ULONG *b, cab_ULONG n, cab_ULONG s, cab_UWORD *d, cab_UWORD *e, -struct Ziphuft **t, cab_LONG *m, fdi_decomp_state *decomp_state) -{ - cab_ULONG a; /* counter for codes of length k */ - cab_ULONG el; /* length of EOB code (value 256) */ - cab_ULONG f; /* i repeats in table every f entries */ - cab_LONG g; /* maximum code length */ - cab_LONG h; /* table level */ - register cab_ULONG i; /* counter, current code */ - register cab_ULONG j; /* counter */ - register cab_LONG k; /* number of bits in current code */ - cab_LONG *l; /* stack of bits per table */ - register cab_ULONG *p; /* pointer into ZIP(c)[],ZIP(b)[],ZIP(v)[] */ - register struct Ziphuft *q; /* points to current table */ - struct Ziphuft r; /* table entry for structure assignment */ - register cab_LONG w; /* bits before this table == (l * h) */ - cab_ULONG *xp; /* pointer into x */ - cab_LONG y; /* number of dummy codes added */ - cab_ULONG z; /* number of entries in current table */ - - l = ZIP(lx)+1; - - /* Generate counts for each bit length */ - el = n > 256 ? b[256] : ZIPBMAX; /* set length of EOB code, if any */ - - for(i = 0; i < ZIPBMAX+1; ++i) - ZIP(c)[i] = 0; - p = b; i = n; - do - { - ZIP(c)[*p]++; p++; /* assume all entries <= ZIPBMAX */ - } while (--i); - if (ZIP(c)[0] == n) /* null input--all zero length codes */ - { - *t = (struct Ziphuft *)NULL; - *m = 0; - return 0; - } - - /* Find minimum and maximum length, bound *m by those */ - for (j = 1; j <= ZIPBMAX; j++) - if (ZIP(c)[j]) - break; - k = j; /* minimum code length */ - if ((cab_ULONG)*m < j) - *m = j; - for (i = ZIPBMAX; i; i--) - if (ZIP(c)[i]) - break; - g = i; /* maximum code length */ - if ((cab_ULONG)*m > i) - *m = i; - - /* Adjust last length count to fill out codes, if needed */ - for (y = 1 << j; j < i; j++, y <<= 1) - if ((y -= ZIP(c)[j]) < 0) - return 2; /* bad input: more codes than bits */ - if ((y -= ZIP(c)[i]) < 0) - return 2; - ZIP(c)[i] += y; - - /* Generate starting offsets LONGo the value table for each length */ - ZIP(x)[1] = j = 0; - p = ZIP(c) + 1; xp = ZIP(x) + 2; - while (--i) - { /* note that i == g from above */ - *xp++ = (j += *p++); - } - - /* Make a table of values in order of bit lengths */ - p = b; i = 0; - do{ - if ((j = *p++) != 0) - ZIP(v)[ZIP(x)[j]++] = i; - } while (++i < n); - - - /* Generate the Huffman codes and for each, make the table entries */ - ZIP(x)[0] = i = 0; /* first Huffman code is zero */ - p = ZIP(v); /* grab values in bit order */ - h = -1; /* no tables yet--level -1 */ - w = l[-1] = 0; /* no bits decoded yet */ - ZIP(u)[0] = (struct Ziphuft *)NULL; /* just to keep compilers happy */ - q = (struct Ziphuft *)NULL; /* ditto */ - z = 0; /* ditto */ - - /* go through the bit lengths (k already is bits in shortest code) */ - for (; k <= g; k++) - { - a = ZIP(c)[k]; - while (a--) - { - /* here i is the Huffman code of length k bits for value *p */ - /* make tables up to required level */ - while (k > w + l[h]) - { - w += l[h++]; /* add bits already decoded */ - - /* compute minimum size table less than or equal to *m bits */ - z = (z = g - w) > (cab_ULONG)*m ? *m : z; /* upper limit */ - if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ - { /* too few codes for k-w bit table */ - f -= a + 1; /* deduct codes from patterns left */ - xp = ZIP(c) + k; - while (++j < z) /* try smaller tables up to z bits */ - { - if ((f <<= 1) <= *++xp) - break; /* enough codes to use up j bits */ - f -= *xp; /* else deduct codes from patterns */ - } - } - if ((cab_ULONG)w + j > el && (cab_ULONG)w < el) - j = el - w; /* make EOB code end at table */ - z = 1 << j; /* table entries for j-bit table */ - l[h] = j; /* set table size in stack */ - - /* allocate and link in new table */ - if (!(q = (struct Ziphuft *) PFDI_ALLOC(CAB(hfdi), (z + 1)*sizeof(struct Ziphuft)))) - { - if(h) - fdi_Ziphuft_free(CAB(hfdi), ZIP(u)[0]); - return 3; /* not enough memory */ - } - *t = q + 1; /* link to list for Ziphuft_free() */ - *(t = &(q->v.t)) = (struct Ziphuft *)NULL; - ZIP(u)[h] = ++q; /* table starts after link */ - - /* connect to last table, if there is one */ - if (h) - { - ZIP(x)[h] = i; /* save pattern for backing up */ - r.b = (cab_UBYTE)l[h-1]; /* bits to dump before this table */ - r.e = (cab_UBYTE)(16 + j); /* bits in this table */ - r.v.t = q; /* pointer to this table */ - j = (i & ((1 << w) - 1)) >> (w - l[h-1]); - ZIP(u)[h-1][j] = r; /* connect to last table */ - } - } - - /* set up table entry in r */ - r.b = (cab_UBYTE)(k - w); - if (p >= ZIP(v) + n) - r.e = 99; /* out of values--invalid code */ - else if (*p < s) - { - r.e = (cab_UBYTE)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */ - r.v.n = *p++; /* simple code is just the value */ - } - else - { - r.e = (cab_UBYTE)e[*p - s]; /* non-simple--look up in lists */ - r.v.n = d[*p++ - s]; - } - - /* fill code-like entries with r */ - f = 1 << (k - w); - for (j = i >> w; j < z; j += f) - q[j] = r; - - /* backwards increment the k-bit code i */ - for (j = 1 << (k - 1); i & j; j >>= 1) - i ^= j; - i ^= j; - - /* backup over finished tables */ - while ((i & ((1 << w) - 1)) != ZIP(x)[h]) - w -= l[--h]; /* don't need to update q */ - } - } - - /* return actual size of base table */ - *m = l[0]; - - /* Return true (1) if we were given an incomplete table */ - return y != 0 && g != 1; -} - -/********************************************************* - * fdi_Zipinflate_codes (internal) - */ -cab_LONG fdi_Zipinflate_codes(struct Ziphuft *tl, struct Ziphuft *td, - cab_LONG bl, cab_LONG bd, fdi_decomp_state *decomp_state) -{ - register cab_ULONG e; /* table entry flag/number of extra bits */ - cab_ULONG n, d; /* length and index for copy */ - cab_ULONG w; /* current window position */ - struct Ziphuft *t; /* pointer to table entry */ - cab_ULONG ml, md; /* masks for bl and bd bits */ - register cab_ULONG b; /* bit buffer */ - register cab_ULONG k; /* number of bits in bit buffer */ - - /* make local copies of globals */ - b = ZIP(bb); /* initialize bit buffer */ - k = ZIP(bk); - w = ZIP(window_posn); /* initialize window position */ - - /* inflate the coded data */ - ml = Zipmask[bl]; /* precompute masks for speed */ - md = Zipmask[bd]; - - for(;;) - { - ZIPNEEDBITS((cab_ULONG)bl) - if((e = (t = tl + ((cab_ULONG)b & ml))->e) > 16) - do - { - if (e == 99) - return 1; - ZIPDUMPBITS(t->b) - e -= 16; - ZIPNEEDBITS(e) - } while ((e = (t = t->v.t + ((cab_ULONG)b & Zipmask[e]))->e) > 16); - ZIPDUMPBITS(t->b) - if (e == 16) /* then it's a literal */ - CAB(outbuf)[w++] = (cab_UBYTE)t->v.n; - else /* it's an EOB or a length */ - { - /* exit if end of block */ - if(e == 15) - break; - - /* get length of block to copy */ - ZIPNEEDBITS(e) - n = t->v.n + ((cab_ULONG)b & Zipmask[e]); - ZIPDUMPBITS(e); - - /* decode distance of block to copy */ - ZIPNEEDBITS((cab_ULONG)bd) - if ((e = (t = td + ((cab_ULONG)b & md))->e) > 16) - do { - if (e == 99) - return 1; - ZIPDUMPBITS(t->b) - e -= 16; - ZIPNEEDBITS(e) - } while ((e = (t = t->v.t + ((cab_ULONG)b & Zipmask[e]))->e) > 16); - ZIPDUMPBITS(t->b) - ZIPNEEDBITS(e) - d = w - t->v.n - ((cab_ULONG)b & Zipmask[e]); - ZIPDUMPBITS(e) - do - { - n -= (e = (e = ZIPWSIZE - ((d &= ZIPWSIZE-1) > w ? d : w)) > n ?n:e); - do - { - CAB(outbuf)[w++] = CAB(outbuf)[d++]; - } while (--e); - } while (n); - } - } - - /* restore the globals from the locals */ - ZIP(window_posn) = w; /* restore global window pointer */ - ZIP(bb) = b; /* restore global bit buffer */ - ZIP(bk) = k; - - /* done */ - return 0; -} - -/*********************************************************** - * Zipinflate_stored (internal) - */ -cab_LONG fdi_Zipinflate_stored(fdi_decomp_state *decomp_state) -/* "decompress" an inflated type 0 (stored) block. */ -{ - cab_ULONG n; /* number of bytes in block */ - cab_ULONG w; /* current window position */ - register cab_ULONG b; /* bit buffer */ - register cab_ULONG k; /* number of bits in bit buffer */ - - /* make local copies of globals */ - b = ZIP(bb); /* initialize bit buffer */ - k = ZIP(bk); - w = ZIP(window_posn); /* initialize window position */ - - /* go to byte boundary */ - n = k & 7; - ZIPDUMPBITS(n); - - /* get the length and its complement */ - ZIPNEEDBITS(16) - n = ((cab_ULONG)b & 0xffff); - ZIPDUMPBITS(16) - ZIPNEEDBITS(16) - if (n != (cab_ULONG)((~b) & 0xffff)) - return 1; /* error in compressed data */ - ZIPDUMPBITS(16) - - /* read and output the compressed data */ - while(n--) - { - ZIPNEEDBITS(8) - CAB(outbuf)[w++] = (cab_UBYTE)b; - ZIPDUMPBITS(8) - } - - /* restore the globals from the locals */ - ZIP(window_posn) = w; /* restore global window pointer */ - ZIP(bb) = b; /* restore global bit buffer */ - ZIP(bk) = k; - return 0; -} - -/****************************************************** - * fdi_Zipinflate_fixed (internal) - */ -cab_LONG fdi_Zipinflate_fixed(fdi_decomp_state *decomp_state) -{ - struct Ziphuft *fixed_tl; - struct Ziphuft *fixed_td; - cab_LONG fixed_bl, fixed_bd; - cab_LONG i; /* temporary variable */ - cab_ULONG *l; - - l = ZIP(ll); - - /* literal table */ - for(i = 0; i < 144; i++) - l[i] = 8; - for(; i < 256; i++) - l[i] = 9; - for(; i < 280; i++) - l[i] = 7; - for(; i < 288; i++) /* make a complete, but wrong code set */ - l[i] = 8; - fixed_bl = 7; - if((i = fdi_Ziphuft_build(l, 288, 257, (cab_UWORD *) Zipcplens, - (cab_UWORD *) Zipcplext, &fixed_tl, &fixed_bl, decomp_state))) - return i; - - /* distance table */ - for(i = 0; i < 30; i++) /* make an incomplete code set */ - l[i] = 5; - fixed_bd = 5; - if((i = fdi_Ziphuft_build(l, 30, 0, (cab_UWORD *) Zipcpdist, (cab_UWORD *) Zipcpdext, - &fixed_td, &fixed_bd, decomp_state)) > 1) - { - fdi_Ziphuft_free(CAB(hfdi), fixed_tl); - return i; - } - - /* decompress until an end-of-block code */ - i = fdi_Zipinflate_codes(fixed_tl, fixed_td, fixed_bl, fixed_bd, decomp_state); - - fdi_Ziphuft_free(CAB(hfdi), fixed_td); - fdi_Ziphuft_free(CAB(hfdi), fixed_tl); - return i; -} - -/************************************************************** - * fdi_Zipinflate_dynamic (internal) - */ -cab_LONG fdi_Zipinflate_dynamic(fdi_decomp_state *decomp_state) - /* decompress an inflated type 2 (dynamic Huffman codes) block. */ -{ - cab_LONG i; /* temporary variables */ - cab_ULONG j; - cab_ULONG *ll; - cab_ULONG l; /* last length */ - cab_ULONG m; /* mask for bit lengths table */ - cab_ULONG n; /* number of lengths to get */ - struct Ziphuft *tl; /* literal/length code table */ - struct Ziphuft *td; /* distance code table */ - cab_LONG bl; /* lookup bits for tl */ - cab_LONG bd; /* lookup bits for td */ - cab_ULONG nb; /* number of bit length codes */ - cab_ULONG nl; /* number of literal/length codes */ - cab_ULONG nd; /* number of distance codes */ - register cab_ULONG b; /* bit buffer */ - register cab_ULONG k; /* number of bits in bit buffer */ - - /* make local bit buffer */ - b = ZIP(bb); - k = ZIP(bk); - ll = ZIP(ll); - - /* read in table lengths */ - ZIPNEEDBITS(5) - nl = 257 + ((cab_ULONG)b & 0x1f); /* number of literal/length codes */ - ZIPDUMPBITS(5) - ZIPNEEDBITS(5) - nd = 1 + ((cab_ULONG)b & 0x1f); /* number of distance codes */ - ZIPDUMPBITS(5) - ZIPNEEDBITS(4) - nb = 4 + ((cab_ULONG)b & 0xf); /* number of bit length codes */ - ZIPDUMPBITS(4) - if(nl > 288 || nd > 32) - return 1; /* bad lengths */ - - /* read in bit-length-code lengths */ - for(j = 0; j < nb; j++) - { - ZIPNEEDBITS(3) - ll[Zipborder[j]] = (cab_ULONG)b & 7; - ZIPDUMPBITS(3) - } - for(; j < 19; j++) - ll[Zipborder[j]] = 0; - - /* build decoding table for trees--single level, 7 bit lookup */ - bl = 7; - if((i = fdi_Ziphuft_build(ll, 19, 19, NULL, NULL, &tl, &bl, decomp_state)) != 0) - { - if(i == 1) - fdi_Ziphuft_free(CAB(hfdi), tl); - return i; /* incomplete code set */ - } - - /* read in literal and distance code lengths */ - n = nl + nd; - m = Zipmask[bl]; - i = l = 0; - while((cab_ULONG)i < n) - { - ZIPNEEDBITS((cab_ULONG)bl) - j = (td = tl + ((cab_ULONG)b & m))->b; - ZIPDUMPBITS(j) - j = td->v.n; - if (j < 16) /* length of code in bits (0..15) */ - ll[i++] = l = j; /* save last length in l */ - else if (j == 16) /* repeat last length 3 to 6 times */ - { - ZIPNEEDBITS(2) - j = 3 + ((cab_ULONG)b & 3); - ZIPDUMPBITS(2) - if((cab_ULONG)i + j > n) - return 1; - while (j--) - ll[i++] = l; - } - else if (j == 17) /* 3 to 10 zero length codes */ - { - ZIPNEEDBITS(3) - j = 3 + ((cab_ULONG)b & 7); - ZIPDUMPBITS(3) - if ((cab_ULONG)i + j > n) - return 1; - while (j--) - ll[i++] = 0; - l = 0; - } - else /* j == 18: 11 to 138 zero length codes */ - { - ZIPNEEDBITS(7) - j = 11 + ((cab_ULONG)b & 0x7f); - ZIPDUMPBITS(7) - if ((cab_ULONG)i + j > n) - return 1; - while (j--) - ll[i++] = 0; - l = 0; - } - } - - /* free decoding table for trees */ - fdi_Ziphuft_free(CAB(hfdi), tl); - - /* restore the global bit buffer */ - ZIP(bb) = b; - ZIP(bk) = k; - - /* build the decoding tables for literal/length and distance codes */ - bl = ZIPLBITS; - if((i = fdi_Ziphuft_build(ll, nl, 257, (cab_UWORD *) Zipcplens, (cab_UWORD *) Zipcplext, - &tl, &bl, decomp_state)) != 0) - { - if(i == 1) - fdi_Ziphuft_free(CAB(hfdi), tl); - return i; /* incomplete code set */ - } - bd = ZIPDBITS; - fdi_Ziphuft_build(ll + nl, nd, 0, (cab_UWORD *) Zipcpdist, (cab_UWORD *) Zipcpdext, - &td, &bd, decomp_state); - - /* decompress until an end-of-block code */ - if(fdi_Zipinflate_codes(tl, td, bl, bd, decomp_state)) - return 1; - - /* free the decoding tables, return */ - fdi_Ziphuft_free(CAB(hfdi), tl); - fdi_Ziphuft_free(CAB(hfdi), td); - return 0; -} - -/***************************************************** - * fdi_Zipinflate_block (internal) - */ -cab_LONG fdi_Zipinflate_block(cab_LONG *e, fdi_decomp_state *decomp_state) /* e == last block flag */ -{ /* decompress an inflated block */ - cab_ULONG t; /* block type */ - register cab_ULONG b; /* bit buffer */ - register cab_ULONG k; /* number of bits in bit buffer */ - - /* make local bit buffer */ - b = ZIP(bb); - k = ZIP(bk); - - /* read in last block bit */ - ZIPNEEDBITS(1) - *e = (cab_LONG)b & 1; - ZIPDUMPBITS(1) - - /* read in block type */ - ZIPNEEDBITS(2) - t = (cab_ULONG)b & 3; - ZIPDUMPBITS(2) - - /* restore the global bit buffer */ - ZIP(bb) = b; - ZIP(bk) = k; - - /* inflate that block type */ - if(t == 2) - return fdi_Zipinflate_dynamic(decomp_state); - if(t == 0) - return fdi_Zipinflate_stored(decomp_state); - if(t == 1) - return fdi_Zipinflate_fixed(decomp_state); - /* bad block type */ - return 2; -} - -/**************************************************** - * ZIPfdi_decomp(internal) - */ -int ZIPfdi_decomp(int inlen, int outlen, fdi_decomp_state *decomp_state) -{ - cab_LONG e; /* last block flag */ - - TRACE("(inlen == %d, outlen == %d)\n", inlen, outlen); - - ZIP(inpos) = CAB(inbuf); - ZIP(bb) = ZIP(bk) = ZIP(window_posn) = 0; - if(outlen > ZIPWSIZE) - return DECR_DATAFORMAT; - - /* CK = Chris Kirmse, official Microsoft purloiner */ - if(ZIP(inpos)[0] != 0x43 || ZIP(inpos)[1] != 0x4B) - return DECR_ILLEGALDATA; - ZIP(inpos) += 2; - - do { - if(fdi_Zipinflate_block(&e, decomp_state)) - return DECR_ILLEGALDATA; - } while(!e); - - /* return success */ - return DECR_OK; -} - -/******************************************************************* - * QTMfdi_decomp(internal) - */ -int QTMfdi_decomp(int inlen, int outlen, fdi_decomp_state *decomp_state) -{ - cab_UBYTE *inpos = CAB(inbuf); - cab_UBYTE *window = QTM(window); - cab_UBYTE *runsrc, *rundest; - - cab_ULONG window_posn = QTM(window_posn); - cab_ULONG window_size = QTM(window_size); - - /* used by bitstream macros */ - register int bitsleft, bitrun, bitsneed; - register cab_ULONG bitbuf; - - /* used by GET_SYMBOL */ - cab_ULONG range; - cab_UWORD symf; - int i; - - int extra, togo = outlen, match_length = 0, copy_length; - cab_UBYTE selector, sym; - cab_ULONG match_offset = 0; - - cab_UWORD H = 0xFFFF, L = 0, C; - - TRACE("(inlen == %d, outlen == %d)\n", inlen, outlen); - - /* read initial value of C */ - Q_INIT_BITSTREAM; - Q_READ_BITS(C, 16); - - /* apply 2^x-1 mask */ - window_posn &= window_size - 1; - /* runs can't straddle the window wraparound */ - if ((window_posn + togo) > window_size) { - TRACE("straddled run\n"); - return DECR_DATAFORMAT; - } - - while (togo > 0) { - GET_SYMBOL(model7, selector); - switch (selector) { - case 0: - GET_SYMBOL(model00, sym); window[window_posn++] = sym; togo--; - break; - case 1: - GET_SYMBOL(model40, sym); window[window_posn++] = sym; togo--; - break; - case 2: - GET_SYMBOL(model80, sym); window[window_posn++] = sym; togo--; - break; - case 3: - GET_SYMBOL(modelC0, sym); window[window_posn++] = sym; togo--; - break; - - case 4: - /* selector 4 = fixed length of 3 */ - GET_SYMBOL(model4, sym); - Q_READ_BITS(extra, CAB(q_extra_bits)[sym]); - match_offset = CAB(q_position_base)[sym] + extra + 1; - match_length = 3; - break; - - case 5: - /* selector 5 = fixed length of 4 */ - GET_SYMBOL(model5, sym); - Q_READ_BITS(extra, CAB(q_extra_bits)[sym]); - match_offset = CAB(q_position_base)[sym] + extra + 1; - match_length = 4; - break; - - case 6: - /* selector 6 = variable length */ - GET_SYMBOL(model6len, sym); - Q_READ_BITS(extra, CAB(q_length_extra)[sym]); - match_length = CAB(q_length_base)[sym] + extra + 5; - GET_SYMBOL(model6pos, sym); - Q_READ_BITS(extra, CAB(q_extra_bits)[sym]); - match_offset = CAB(q_position_base)[sym] + extra + 1; - break; - - default: - TRACE("Selector is bogus\n"); - return DECR_ILLEGALDATA; - } - - /* if this is a match */ - if (selector >= 4) { - rundest = window + window_posn; - togo -= match_length; - - /* copy any wrapped around source data */ - if (window_posn >= match_offset) { - /* no wrap */ - runsrc = rundest - match_offset; - } else { - runsrc = rundest + (window_size - match_offset); - copy_length = match_offset - window_posn; - if (copy_length < match_length) { - match_length -= copy_length; - window_posn += copy_length; - while (copy_length-- > 0) *rundest++ = *runsrc++; - runsrc = window; - } - } - window_posn += match_length; - - /* copy match data - no worries about destination wraps */ - while (match_length-- > 0) *rundest++ = *runsrc++; - } - } /* while (togo > 0) */ - - if (togo != 0) { - TRACE("Frame overflow, this_run = %d\n", togo); - return DECR_ILLEGALDATA; - } - - memcpy(CAB(outbuf), window + ((!window_posn) ? window_size : window_posn) - - outlen, outlen); - - QTM(window_posn) = window_posn; - return DECR_OK; -} - -/************************************************************ - * fdi_lzx_read_lens (internal) - */ -int fdi_lzx_read_lens(cab_UBYTE *lens, cab_ULONG first, cab_ULONG last, struct lzx_bits *lb, - fdi_decomp_state *decomp_state) { - cab_ULONG i,j, x,y; - int z; - - register cab_ULONG bitbuf = lb->bb; - register int bitsleft = lb->bl; - cab_UBYTE *inpos = lb->ip; - cab_UWORD *hufftbl; - - for (x = 0; x < 20; x++) { - READ_BITS(y, 4); - LENTABLE(PRETREE)[x] = y; - } - BUILD_TABLE(PRETREE); - - for (x = first; x < last; ) { - READ_HUFFSYM(PRETREE, z); - if (z == 17) { - READ_BITS(y, 4); y += 4; - while (y--) lens[x++] = 0; - } - else if (z == 18) { - READ_BITS(y, 5); y += 20; - while (y--) lens[x++] = 0; - } - else if (z == 19) { - READ_BITS(y, 1); y += 4; - READ_HUFFSYM(PRETREE, z); - z = lens[x] - z; if (z < 0) z += 17; - while (y--) lens[x++] = z; - } - else { - z = lens[x] - z; if (z < 0) z += 17; - lens[x++] = z; - } - } - - lb->bb = bitbuf; - lb->bl = bitsleft; - lb->ip = inpos; - return 0; -} - -/******************************************************* - * LZXfdi_decomp(internal) - */ -int LZXfdi_decomp(int inlen, int outlen, fdi_decomp_state *decomp_state) { - cab_UBYTE *inpos = CAB(inbuf); - cab_UBYTE *endinp = inpos + inlen; - cab_UBYTE *window = LZX(window); - cab_UBYTE *runsrc, *rundest; - cab_UWORD *hufftbl; /* used in READ_HUFFSYM macro as chosen decoding table */ - - cab_ULONG window_posn = LZX(window_posn); - cab_ULONG window_size = LZX(window_size); - cab_ULONG R0 = LZX(R0); - cab_ULONG R1 = LZX(R1); - cab_ULONG R2 = LZX(R2); - - register cab_ULONG bitbuf; - register int bitsleft; - cab_ULONG match_offset, i,j,k; /* ijk used in READ_HUFFSYM macro */ - struct lzx_bits lb; /* used in READ_LENGTHS macro */ - - int togo = outlen, this_run, main_element, aligned_bits; - int match_length, copy_length, length_footer, extra, verbatim_bits; - - TRACE("(inlen == %d, outlen == %d)\n", inlen, outlen); - - INIT_BITSTREAM; - - /* read header if necessary */ - if (!LZX(header_read)) { - i = j = 0; - READ_BITS(k, 1); if (k) { READ_BITS(i,16); READ_BITS(j,16); } - LZX(intel_filesize) = (i << 16) | j; /* or 0 if not encoded */ - LZX(header_read) = 1; - } - - /* main decoding loop */ - while (togo > 0) { - /* last block finished, new block expected */ - if (LZX(block_remaining) == 0) { - if (LZX(block_type) == LZX_BLOCKTYPE_UNCOMPRESSED) { - if (LZX(block_length) & 1) inpos++; /* realign bitstream to word */ - INIT_BITSTREAM; - } - - READ_BITS(LZX(block_type), 3); - READ_BITS(i, 16); - READ_BITS(j, 8); - LZX(block_remaining) = LZX(block_length) = (i << 8) | j; - - switch (LZX(block_type)) { - case LZX_BLOCKTYPE_ALIGNED: - for (i = 0; i < 8; i++) { READ_BITS(j, 3); LENTABLE(ALIGNED)[i] = j; } - BUILD_TABLE(ALIGNED); - /* rest of aligned header is same as verbatim */ - - case LZX_BLOCKTYPE_VERBATIM: - READ_LENGTHS(MAINTREE, 0, 256, fdi_lzx_read_lens); - READ_LENGTHS(MAINTREE, 256, LZX(main_elements), fdi_lzx_read_lens); - BUILD_TABLE(MAINTREE); - if (LENTABLE(MAINTREE)[0xE8] != 0) LZX(intel_started) = 1; - - READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS, fdi_lzx_read_lens); - BUILD_TABLE(LENGTH); - break; - - case LZX_BLOCKTYPE_UNCOMPRESSED: - LZX(intel_started) = 1; /* because we can't assume otherwise */ - ENSURE_BITS(16); /* get up to 16 pad bits into the buffer */ - if (bitsleft > 16) inpos -= 2; /* and align the bitstream! */ - R0 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4; - R1 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4; - R2 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4; - break; - - default: - return DECR_ILLEGALDATA; - } - } - - /* buffer exhaustion check */ - if (inpos > endinp) { - /* it's possible to have a file where the next run is less than - * 16 bits in size. In this case, the READ_HUFFSYM() macro used - * in building the tables will exhaust the buffer, so we should - * allow for this, but not allow those accidentally read bits to - * be used (so we check that there are at least 16 bits - * remaining - in this boundary case they aren't really part of - * the compressed data) - */ - if (inpos > (endinp+2) || bitsleft < 16) return DECR_ILLEGALDATA; - } - - while ((this_run = LZX(block_remaining)) > 0 && togo > 0) { - if (this_run > togo) this_run = togo; - togo -= this_run; - LZX(block_remaining) -= this_run; - - /* apply 2^x-1 mask */ - window_posn &= window_size - 1; - /* runs can't straddle the window wraparound */ - if ((window_posn + this_run) > window_size) - return DECR_DATAFORMAT; - - switch (LZX(block_type)) { - - case LZX_BLOCKTYPE_VERBATIM: - while (this_run > 0) { - READ_HUFFSYM(MAINTREE, main_element); - - if (main_element < LZX_NUM_CHARS) { - /* literal: 0 to LZX_NUM_CHARS-1 */ - window[window_posn++] = main_element; - this_run--; - } - else { - /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */ - main_element -= LZX_NUM_CHARS; - - match_length = main_element & LZX_NUM_PRIMARY_LENGTHS; - if (match_length == LZX_NUM_PRIMARY_LENGTHS) { - READ_HUFFSYM(LENGTH, length_footer); - match_length += length_footer; - } - match_length += LZX_MIN_MATCH; - - match_offset = main_element >> 3; - - if (match_offset > 2) { - /* not repeated offset */ - if (match_offset != 3) { - extra = CAB(extra_bits)[match_offset]; - READ_BITS(verbatim_bits, extra); - match_offset = CAB(lzx_position_base)[match_offset] - - 2 + verbatim_bits; - } - else { - match_offset = 1; - } - - /* update repeated offset LRU queue */ - R2 = R1; R1 = R0; R0 = match_offset; - } - else if (match_offset == 0) { - match_offset = R0; - } - else if (match_offset == 1) { - match_offset = R1; - R1 = R0; R0 = match_offset; - } - else /* match_offset == 2 */ { - match_offset = R2; - R2 = R0; R0 = match_offset; - } - - rundest = window + window_posn; - this_run -= match_length; - - /* copy any wrapped around source data */ - if (window_posn >= match_offset) { - /* no wrap */ - runsrc = rundest - match_offset; - } else { - runsrc = rundest + (window_size - match_offset); - copy_length = match_offset - window_posn; - if (copy_length < match_length) { - match_length -= copy_length; - window_posn += copy_length; - while (copy_length-- > 0) *rundest++ = *runsrc++; - runsrc = window; - } - } - window_posn += match_length; - - /* copy match data - no worries about destination wraps */ - while (match_length-- > 0) *rundest++ = *runsrc++; - } - } - break; - - case LZX_BLOCKTYPE_ALIGNED: - while (this_run > 0) { - READ_HUFFSYM(MAINTREE, main_element); - - if (main_element < LZX_NUM_CHARS) { - /* literal: 0 to LZX_NUM_CHARS-1 */ - window[window_posn++] = main_element; - this_run--; - } - else { - /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */ - main_element -= LZX_NUM_CHARS; - - match_length = main_element & LZX_NUM_PRIMARY_LENGTHS; - if (match_length == LZX_NUM_PRIMARY_LENGTHS) { - READ_HUFFSYM(LENGTH, length_footer); - match_length += length_footer; - } - match_length += LZX_MIN_MATCH; - - match_offset = main_element >> 3; - - if (match_offset > 2) { - /* not repeated offset */ - extra = CAB(extra_bits)[match_offset]; - match_offset = CAB(lzx_position_base)[match_offset] - 2; - if (extra > 3) { - /* verbatim and aligned bits */ - extra -= 3; - READ_BITS(verbatim_bits, extra); - match_offset += (verbatim_bits << 3); - READ_HUFFSYM(ALIGNED, aligned_bits); - match_offset += aligned_bits; - } - else if (extra == 3) { - /* aligned bits only */ - READ_HUFFSYM(ALIGNED, aligned_bits); - match_offset += aligned_bits; - } - else if (extra > 0) { /* extra==1, extra==2 */ - /* verbatim bits only */ - READ_BITS(verbatim_bits, extra); - match_offset += verbatim_bits; - } - else /* extra == 0 */ { - /* ??? */ - match_offset = 1; - } - - /* update repeated offset LRU queue */ - R2 = R1; R1 = R0; R0 = match_offset; - } - else if (match_offset == 0) { - match_offset = R0; - } - else if (match_offset == 1) { - match_offset = R1; - R1 = R0; R0 = match_offset; - } - else /* match_offset == 2 */ { - match_offset = R2; - R2 = R0; R0 = match_offset; - } - - rundest = window + window_posn; - this_run -= match_length; - - /* copy any wrapped around source data */ - if (window_posn >= match_offset) { - /* no wrap */ - runsrc = rundest - match_offset; - } else { - runsrc = rundest + (window_size - match_offset); - copy_length = match_offset - window_posn; - if (copy_length < match_length) { - match_length -= copy_length; - window_posn += copy_length; - while (copy_length-- > 0) *rundest++ = *runsrc++; - runsrc = window; - } - } - window_posn += match_length; - - /* copy match data - no worries about destination wraps */ - while (match_length-- > 0) *rundest++ = *runsrc++; - } - } - break; - - case LZX_BLOCKTYPE_UNCOMPRESSED: - if ((inpos + this_run) > endinp) return DECR_ILLEGALDATA; - memcpy(window + window_posn, inpos, (size_t) this_run); - inpos += this_run; window_posn += this_run; - break; - - default: - return DECR_ILLEGALDATA; /* might as well */ - } - - } - } - - if (togo != 0) return DECR_ILLEGALDATA; - memcpy(CAB(outbuf), window + ((!window_posn) ? window_size : window_posn) - - outlen, (size_t) outlen); - - LZX(window_posn) = window_posn; - LZX(R0) = R0; - LZX(R1) = R1; - LZX(R2) = R2; - - /* intel E8 decoding */ - if ((LZX(frames_read)++ < 32768) && LZX(intel_filesize) != 0) { - if (outlen <= 6 || !LZX(intel_started)) { - LZX(intel_curpos) += outlen; - } - else { - cab_UBYTE *data = CAB(outbuf); - cab_UBYTE *dataend = data + outlen - 10; - cab_LONG curpos = LZX(intel_curpos); - cab_LONG filesize = LZX(intel_filesize); - cab_LONG abs_off, rel_off; - - LZX(intel_curpos) = curpos + outlen; - - while (data < dataend) { - if (*data++ != 0xE8) { curpos++; continue; } - abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24); - if ((abs_off >= -curpos) && (abs_off < filesize)) { - rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize; - data[0] = (cab_UBYTE) rel_off; - data[1] = (cab_UBYTE) (rel_off >> 8); - data[2] = (cab_UBYTE) (rel_off >> 16); - data[3] = (cab_UBYTE) (rel_off >> 24); - } - data += 4; - curpos += 5; - } - } - } - return DECR_OK; -} - -/********************************************************** - * fdi_decomp (internal) - * - * Decompress the requested number of bytes. If savemode is zero, - * do not save the output anywhere, just plow through blocks until we - * reach the specified (uncompressed) distance from the starting point, - * and remember the position of the cabfile pointer (and which cabfile) - * after we are done; otherwise, save the data out to CAB(filehf), - * decompressing the requested number of bytes and writing them out. This - * is also where we jump to additional cabinets in the case of split - * cab's, and provide (some of) the NEXT_CABINET notification semantics. - */ -int fdi_decomp(struct fdi_file *fi, int savemode, fdi_decomp_state *decomp_state, - char *pszCabPath, PFNFDINOTIFY pfnfdin, void *pvUser) -{ - cab_ULONG bytes = savemode ? fi->length : fi->offset - CAB(offset); - cab_UBYTE buf[cfdata_SIZEOF], *data; - cab_UWORD inlen, len, outlen, cando; - cab_ULONG cksum; - cab_LONG err; - fdi_decomp_state *cab = (savemode && CAB(decomp_cab)) ? CAB(decomp_cab) : decomp_state; - - TRACE("(fi == ^%p, savemode == %d, bytes == %d)\n", fi, savemode, bytes); - - while (bytes > 0) { - /* cando = the max number of bytes we can do */ - cando = CAB(outlen); - if (cando > bytes) cando = bytes; - - /* if cando != 0 */ - if (cando && savemode) - PFDI_WRITE(CAB(hfdi), CAB(filehf), CAB(outpos), cando); - - CAB(outpos) += cando; - CAB(outlen) -= cando; - bytes -= cando; if (!bytes) break; - - /* we only get here if we emptied the output buffer */ - - /* read data header + data */ - inlen = outlen = 0; - while (outlen == 0) { - /* read the block header, skip the reserved part */ - if (PFDI_READ(CAB(hfdi), cab->cabhf, buf, cfdata_SIZEOF) != cfdata_SIZEOF) - return DECR_INPUT; - - if (PFDI_SEEK(CAB(hfdi), cab->cabhf, cab->mii.block_resv, SEEK_CUR) == -1) - return DECR_INPUT; - - /* we shouldn't get blocks over CAB_INPUTMAX in size */ - data = CAB(inbuf) + inlen; - len = EndGetI16(buf+cfdata_CompressedSize); - inlen += len; - if (inlen > CAB_INPUTMAX) return DECR_INPUT; - if (PFDI_READ(CAB(hfdi), cab->cabhf, data, len) != len) - return DECR_INPUT; - - /* clear two bytes after read-in data */ - data[len+1] = data[len+2] = 0; - - /* perform checksum test on the block (if one is stored) */ - cksum = EndGetI32(buf+cfdata_CheckSum); - if (cksum && cksum != checksum(buf+4, 4, checksum(data, len, 0))) - return DECR_CHECKSUM; /* checksum is wrong */ - - outlen = EndGetI16(buf+cfdata_UncompressedSize); - - /* outlen=0 means this block was the last contiguous part - of a split block, continued in the next cabinet */ - if (outlen == 0) { - int pathlen, filenamelen, idx, i, cabhf; - char fullpath[MAX_PATH], userpath[256]; - FDINOTIFICATION fdin; - FDICABINETINFO fdici; - char emptystring = '\0'; - cab_UBYTE buf2[64]; - int success = FALSE; - struct fdi_folder *fol = NULL, *linkfol = NULL; - struct fdi_file *file = NULL, *linkfile = NULL; - - tryanothercab: - - /* set up the next decomp_state... */ - if (!(cab->next)) { - if (!cab->mii.hasnext) return DECR_INPUT; - - if (!((cab->next = PFDI_ALLOC(CAB(hfdi), sizeof(fdi_decomp_state))))) - return DECR_NOMEMORY; - - ZeroMemory(cab->next, sizeof(fdi_decomp_state)); - - /* copy pszCabPath to userpath */ - ZeroMemory(userpath, 256); - pathlen = (pszCabPath) ? strlen(pszCabPath) : 0; - if (pathlen) { - if (pathlen < 256) { - for (i = 0; i <= pathlen; i++) - userpath[i] = pszCabPath[i]; - } /* else we are in a weird place... let's leave it blank and see if the user fixes it */ - } - - /* initial fdintNEXT_CABINET notification */ - ZeroMemory(&fdin, sizeof(FDINOTIFICATION)); - fdin.psz1 = (cab->mii.nextname) ? cab->mii.nextname : &emptystring; - fdin.psz2 = (cab->mii.nextinfo) ? cab->mii.nextinfo : &emptystring; - fdin.psz3 = &userpath[0]; - fdin.fdie = FDIERROR_NONE; - fdin.pv = pvUser; - - if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT; - - do { - - pathlen = (userpath) ? strlen(userpath) : 0; - filenamelen = (cab->mii.nextname) ? strlen(cab->mii.nextname) : 0; - - /* slight overestimation here to save CPU cycles in the developer's brain */ - if ((pathlen + filenamelen + 3) > MAX_PATH) { - ERR("MAX_PATH exceeded.\n"); - return DECR_ILLEGALDATA; - } - - /* paste the path and filename together */ - idx = 0; - if (pathlen) { - for (i = 0; i < pathlen; i++) fullpath[idx++] = userpath[i]; - if (fullpath[idx - 1] != '\\') fullpath[idx++] = '\\'; - } - if (filenamelen) for (i = 0; i < filenamelen; i++) fullpath[idx++] = cab->mii.nextname[i]; - fullpath[idx] = '\0'; - - TRACE("full cab path/file name: %s\n", debugstr_a(fullpath)); - - /* try to get a handle to the cabfile */ - cabhf = PFDI_OPEN(CAB(hfdi), fullpath, 32768, _S_IREAD | _S_IWRITE); - if (cabhf == -1) { - /* no file. allow the user to try again */ - fdin.fdie = FDIERROR_CABINET_NOT_FOUND; - if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT; - continue; - } - - if (cabhf == 0) { - ERR("PFDI_OPEN returned zero for %s.\n", fullpath); - fdin.fdie = FDIERROR_CABINET_NOT_FOUND; - if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT; - continue; - } - - /* check if it's really a cabfile. Note that this doesn't implement the bug */ - if (!FDI_read_entries(CAB(hfdi), cabhf, &fdici, &(cab->next->mii))) { - WARN("FDIIsCabinet failed.\n"); - PFDI_CLOSE(CAB(hfdi), cabhf); - fdin.fdie = FDIERROR_NOT_A_CABINET; - if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT; - continue; - } - - if ((fdici.setID != cab->setID) || (fdici.iCabinet != (cab->iCabinet + 1))) { - WARN("Wrong Cabinet.\n"); - PFDI_CLOSE(CAB(hfdi), cabhf); - fdin.fdie = FDIERROR_WRONG_CABINET; - if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT; - continue; - } - - break; - - } while (1); - - /* cabinet notification */ - ZeroMemory(&fdin, sizeof(FDINOTIFICATION)); - fdin.setID = fdici.setID; - fdin.iCabinet = fdici.iCabinet; - fdin.pv = pvUser; - fdin.psz1 = (cab->next->mii.nextname) ? cab->next->mii.nextname : &emptystring; - fdin.psz2 = (cab->next->mii.nextinfo) ? cab->next->mii.nextinfo : &emptystring; - fdin.psz3 = pszCabPath; - - if (((*pfnfdin)(fdintCABINET_INFO, &fdin))) return DECR_USERABORT; - - cab->next->setID = fdici.setID; - cab->next->iCabinet = fdici.iCabinet; - cab->next->hfdi = CAB(hfdi); - cab->next->filehf = CAB(filehf); - cab->next->cabhf = cabhf; - cab->next->decompress = CAB(decompress); /* crude, but unused anyhow */ - - cab = cab->next; /* advance to the next cabinet */ - - /* read folders */ - for (i = 0; i < fdici.cFolders; i++) { - if (PFDI_READ(CAB(hfdi), cab->cabhf, buf2, cffold_SIZEOF) != cffold_SIZEOF) - return DECR_INPUT; - - if (cab->mii.folder_resv > 0) - PFDI_SEEK(CAB(hfdi), cab->cabhf, cab->mii.folder_resv, SEEK_CUR); - - fol = (struct fdi_folder *) PFDI_ALLOC(CAB(hfdi), sizeof(struct fdi_folder)); - if (!fol) { - ERR("out of memory!\n"); - return DECR_NOMEMORY; - } - ZeroMemory(fol, sizeof(struct fdi_folder)); - if (!(cab->firstfol)) cab->firstfol = fol; - - fol->offset = (cab_off_t) EndGetI32(buf2+cffold_DataOffset); - fol->num_blocks = EndGetI16(buf2+cffold_NumBlocks); - fol->comp_type = EndGetI16(buf2+cffold_CompType); - - if (linkfol) - linkfol->next = fol; - linkfol = fol; - } - - /* read files */ - for (i = 0; i < fdici.cFiles; i++) { - if (PFDI_READ(CAB(hfdi), cab->cabhf, buf2, cffile_SIZEOF) != cffile_SIZEOF) - return DECR_INPUT; - - file = (struct fdi_file *) PFDI_ALLOC(CAB(hfdi), sizeof(struct fdi_file)); - if (!file) { - ERR("out of memory!\n"); - return DECR_NOMEMORY; - } - ZeroMemory(file, sizeof(struct fdi_file)); - if (!(cab->firstfile)) cab->firstfile = file; - - file->length = EndGetI32(buf2+cffile_UncompressedSize); - file->offset = EndGetI32(buf2+cffile_FolderOffset); - file->index = EndGetI16(buf2+cffile_FolderIndex); - file->time = EndGetI16(buf2+cffile_Time); - file->date = EndGetI16(buf2+cffile_Date); - file->attribs = EndGetI16(buf2+cffile_Attribs); - file->filename = FDI_read_string(CAB(hfdi), cab->cabhf, fdici.cbCabinet); - - if (!file->filename) return DECR_INPUT; - - if (linkfile) - linkfile->next = file; - linkfile = file; - } - - } else - cab = cab->next; /* advance to the next cabinet */ - - /* iterate files -- if we encounter the continued file, process it -- - otherwise, jump to the label above and keep looking */ - - for (file = cab->firstfile; (file); file = file->next) { - if ((file->index & cffileCONTINUED_FROM_PREV) == cffileCONTINUED_FROM_PREV) { - /* check to ensure a real match */ - if (strcasecmp(fi->filename, file->filename) == 0) { - success = TRUE; - if (PFDI_SEEK(CAB(hfdi), cab->cabhf, cab->firstfol->offset, SEEK_SET) == -1) - return DECR_INPUT; - break; - } - } - } - if (!success) goto tryanothercab; /* FIXME: shouldn't this trigger - "Wrong Cabinet" notification? */ - } - } - - /* decompress block */ - if ((err = CAB(decompress)(inlen, outlen, decomp_state))) - return err; - CAB(outlen) = outlen; - CAB(outpos) = CAB(outbuf); - } - - CAB(decomp_cab) = cab; - return DECR_OK; -} - -/*********************************************************************** - * FDICopy (CABINET.22) - * - * Iterates through the files in the Cabinet file indicated by name and - * file-location. May chain forward to additional cabinets (typically - * only one) if files which begin in this Cabinet are continued in another - * cabinet. For each file which is partially contained in this cabinet, - * and partially contained in a prior cabinet, provides fdintPARTIAL_FILE - * notification to the pfnfdin callback. For each file which begins in - * this cabinet, fdintCOPY_FILE notification is provided to the pfnfdin - * callback, and the file is optionally decompressed and saved to disk. - * Notification is not provided for files which are not at least partially - * contained in the specified cabinet file. - * - * See below for a thorough explanation of the various notification - * callbacks. - * - * PARAMS - * hfdi [I] An HFDI from FDICreate - * pszCabinet [I] C-style string containing the filename of the cabinet - * pszCabPath [I] C-style string containing the file path of the cabinet - * flags [I] "Decoder parameters". Ignored. Suggested value: 0. - * pfnfdin [I] Pointer to a notification function. See CALLBACKS below. - * pfnfdid [I] Pointer to a decryption function. Ignored. Suggested - * value: NULL. - * pvUser [I] arbitrary void * value which is passed to callbacks. - * - * RETURNS - * TRUE if successful. - * FALSE if unsuccessful (error information is provided in the ERF structure - * associated with the provided decompression handle by FDICreate). - * - * CALLBACKS - * - * Two pointers to callback functions are provided as parameters to FDICopy: - * pfnfdin(of type PFNFDINOTIFY), and pfnfdid (of type PFNFDIDECRYPT). These - * types are as follows: - * - * typedef INT_PTR (__cdecl *PFNFDINOTIFY) ( FDINOTIFICATIONTYPE fdint, - * PFDINOTIFICATION pfdin ); - * - * typedef int (__cdecl *PFNFDIDECRYPT) ( PFDIDECRYPT pfdid ); - * - * You can create functions of this type using the FNFDINOTIFY() and - * FNFDIDECRYPT() macros, respectively. For example: - * - * FNFDINOTIFY(mycallback) { - * / * use variables fdint and pfdin to process notification * / - * } - * - * The second callback, which could be used for decrypting encrypted data, - * is not used at all. - * - * Each notification informs the user of some event which has occurred during - * decompression of the cabinet file; each notification is also an opportunity - * for the callee to abort decompression. The information provided to the - * callback and the meaning of the callback's return value vary drastically - * across the various types of notification. The type of notification is the - * fdint parameter; all other information is provided to the callback in - * notification-specific parts of the FDINOTIFICATION structure pointed to by - * pfdin. The only part of that structure which is assigned for every callback - * is the pv element, which contains the arbitrary value which was passed to - * FDICopy in the pvUser argument (psz1 is also used each time, but its meaning - * is highly dependent on fdint). - * - * If you encounter unknown notifications, you should return zero if you want - * decompression to continue (or -1 to abort). All strings used in the - * callbacks are regular C-style strings. Detailed descriptions of each - * notification type follow: - * - * fdintCABINET_INFO: - * - * This is the first notification provided after calling FDICopy, and provides - * the user with various information about the cabinet. Note that this is - * called for each cabinet FDICopy opens, not just the first one. In the - * structure pointed to by pfdin, psz1 contains a pointer to the name of the - * next cabinet file in the set after the one just loaded (if any), psz2 - * contains a pointer to the name or "info" of the next disk, psz3 - * contains a pointer to the file-path of the current cabinet, setID - * contains an arbitrary constant associated with this set of cabinet files, - * and iCabinet contains the numerical index of the current cabinet within - * that set. Return zero, or -1 to abort. - * - * fdintPARTIAL_FILE: - * - * This notification is provided when FDICopy encounters a part of a file - * contained in this cabinet which is missing its beginning. Files can be - * split across cabinets, so this is not necessarily an abnormality; it just - * means that the file in question begins in another cabinet. No file - * corresponding to this notification is extracted from the cabinet. In the - * structure pointed to by pfdin, psz1 contains a pointer to the name of the - * partial file, psz2 contains a pointer to the file name of the cabinet in - * which this file begins, and psz3 contains a pointer to the disk name or - * "info" of the cabinet where the file begins. Return zero, or -1 to abort. - * - * fdintCOPY_FILE: - * - * This notification is provided when FDICopy encounters a file which starts - * in the cabinet file, provided to FDICopy in pszCabinet. (FDICopy will not - * look for files in cabinets after the first one). One notification will be - * sent for each such file, before the file is decompressed. By returning - * zero, the callback can instruct FDICopy to skip the file. In the structure - * pointed to by pfdin, psz1 contains a pointer to the file's name, cb contains - * the size of the file (uncompressed), attribs contains the file attributes, - * and date and time contain the date and time of the file. attributes, date, - * and time are of the 16-bit ms-dos variety. Return -1 to abort decompression - * for the entire cabinet, 0 to skip just this file but continue scanning the - * cabinet for more files, or an FDIClose()-compatible file-handle. - * - * fdintCLOSE_FILE_INFO: - * - * This notification is important, don't forget to implement it. This - * notification indicates that a file has been successfully uncompressed and - * written to disk. Upon receipt of this notification, the callee is expected - * to close the file handle, to set the attributes and date/time of the - * closed file, and possibly to execute the file. In the structure pointed to - * by pfdin, psz1 contains a pointer to the name of the file, hf will be the - * open file handle (close it), cb contains 1 or zero, indicating respectively - * that the callee should or should not execute the file, and date, time - * and attributes will be set as in fdintCOPY_FILE. Bizarrely, the Cabinet SDK - * specifies that _A_EXEC will be xor'ed out of attributes! wine does not do - * do so. Return TRUE, or FALSE to abort decompression. - * - * fdintNEXT_CABINET: - * - * This notification is called when FDICopy must load in another cabinet. This - * can occur when a file's data is "split" across multiple cabinets. The - * callee has the opportunity to request that FDICopy look in a different file - * path for the specified cabinet file, by writing that data into a provided - * buffer (see below for more information). This notification will be received - * more than once per-cabinet in the instance that FDICopy failed to find a - * valid cabinet at the location specified by the first per-cabinet - * fdintNEXT_CABINET notification. In such instances, the fdie element of the - * structure pointed to by pfdin indicates the error which prevented FDICopy - * from proceeding successfully. Return zero to indicate success, or -1 to - * indicate failure and abort FDICopy. - * - * Upon receipt of this notification, the structure pointed to by pfdin will - * contain the following values: psz1 pointing to the name of the cabinet - * which FDICopy is attempting to open, psz2 pointing to the name ("info") of - * the next disk, psz3 pointing to the presumed file-location of the cabinet, - * and fdie containing either FDIERROR_NONE, or one of the following: - * - * FDIERROR_CABINET_NOT_FOUND, FDIERROR_NOT_A_CABINET, - * FDIERROR_UNKNOWN_CABINET_VERSION, FDIERROR_CORRUPT_CABINET, - * FDIERROR_BAD_COMPR_TYPE, FDIERROR_RESERVE_MISMATCH, and - * FDIERROR_WRONG_CABINET. - * - * The callee may choose to change the path where FDICopy will look for the - * cabinet after this notification. To do so, the caller may write the new - * pathname to the buffer pointed to by psz3, which is 256 characters in - * length, including the terminating null character, before returning zero. - * - * fdintENUMERATE: - * - * Undocumented and unimplemented in wine, this seems to be sent each time - * a cabinet is opened, along with the fdintCABINET_INFO notification. It - * probably has an interface similar to that of fdintCABINET_INFO; maybe this - * provides information about the current cabinet instead of the next one.... - * this is just a guess, it has not been looked at closely. - * - * INCLUDES - * fdi.c - */ -BOOL __cdecl FDICopy( - HFDI hfdi, - char *pszCabinet, - char *pszCabPath, - int flags, - PFNFDINOTIFY pfnfdin, - PFNFDIDECRYPT pfnfdid, - void *pvUser) -{ - FDICABINETINFO fdici; - FDINOTIFICATION fdin; - int cabhf, filehf, idx; - unsigned int i; - char fullpath[MAX_PATH]; - size_t pathlen, filenamelen; - char emptystring = '\0'; - cab_UBYTE buf[64]; - struct fdi_folder *fol = NULL, *linkfol = NULL; - struct fdi_file *file = NULL, *linkfile = NULL; - fdi_decomp_state _decomp_state; - fdi_decomp_state *decomp_state = &_decomp_state; - - TRACE("(hfdi == ^%p, pszCabinet == ^%p, pszCabPath == ^%p, flags == %0d, \ - pfnfdin == ^%p, pfnfdid == ^%p, pvUser == ^%p)\n", - hfdi, pszCabinet, pszCabPath, flags, pfnfdin, pfnfdid, pvUser); - - if (!REALLY_IS_FDI(hfdi)) { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - - ZeroMemory(decomp_state, sizeof(fdi_decomp_state)); - - pathlen = (pszCabPath) ? strlen(pszCabPath) : 0; - filenamelen = (pszCabinet) ? strlen(pszCabinet) : 0; - - /* slight overestimation here to save CPU cycles in the developer's brain */ - if ((pathlen + filenamelen + 3) > MAX_PATH) { - ERR("MAX_PATH exceeded.\n"); - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CABINET_NOT_FOUND; - PFDI_INT(hfdi)->perf->erfType = ERROR_FILE_NOT_FOUND; - PFDI_INT(hfdi)->perf->fError = TRUE; - SetLastError(ERROR_FILE_NOT_FOUND); - return FALSE; - } - - /* paste the path and filename together */ - idx = 0; - if (pathlen) { - for (i = 0; i < pathlen; i++) fullpath[idx++] = pszCabPath[i]; - if (fullpath[idx - 1] != '\\') fullpath[idx++] = '\\'; - } - if (filenamelen) for (i = 0; i < filenamelen; i++) fullpath[idx++] = pszCabinet[i]; - fullpath[idx] = '\0'; - - TRACE("full cab path/file name: %s\n", debugstr_a(fullpath)); - - /* get a handle to the cabfile */ - cabhf = PFDI_OPEN(hfdi, fullpath, 32768, _S_IREAD | _S_IWRITE); - if (cabhf == -1) { - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CABINET_NOT_FOUND; - PFDI_INT(hfdi)->perf->erfType = ERROR_FILE_NOT_FOUND; - PFDI_INT(hfdi)->perf->fError = TRUE; - SetLastError(ERROR_FILE_NOT_FOUND); - return FALSE; - } - - if (cabhf == 0) { - ERR("PFDI_OPEN returned zero for %s.\n", fullpath); - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CABINET_NOT_FOUND; - PFDI_INT(hfdi)->perf->erfType = ERROR_FILE_NOT_FOUND; - PFDI_INT(hfdi)->perf->fError = TRUE; - SetLastError(ERROR_FILE_NOT_FOUND); - return FALSE; - } - - /* check if it's really a cabfile. Note that this doesn't implement the bug */ - if (!FDI_read_entries(hfdi, cabhf, &fdici, &(CAB(mii)))) { - ERR("FDIIsCabinet failed.\n"); - PFDI_CLOSE(hfdi, cabhf); - return FALSE; - } - - /* cabinet notification */ - ZeroMemory(&fdin, sizeof(FDINOTIFICATION)); - fdin.setID = fdici.setID; - fdin.iCabinet = fdici.iCabinet; - fdin.pv = pvUser; - fdin.psz1 = (CAB(mii).nextname) ? CAB(mii).nextname : &emptystring; - fdin.psz2 = (CAB(mii).nextinfo) ? CAB(mii).nextinfo : &emptystring; - fdin.psz3 = pszCabPath; - - if (((*pfnfdin)(fdintCABINET_INFO, &fdin))) { - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT; - PFDI_INT(hfdi)->perf->erfType = 0; - PFDI_INT(hfdi)->perf->fError = TRUE; - goto bail_and_fail; - } - - CAB(setID) = fdici.setID; - CAB(iCabinet) = fdici.iCabinet; - - /* read folders */ - for (i = 0; i < fdici.cFolders; i++) { - if (PFDI_READ(hfdi, cabhf, buf, cffold_SIZEOF) != cffold_SIZEOF) { - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET; - PFDI_INT(hfdi)->perf->erfType = 0; - PFDI_INT(hfdi)->perf->fError = TRUE; - goto bail_and_fail; - } - - if (CAB(mii).folder_resv > 0) - PFDI_SEEK(hfdi, cabhf, CAB(mii).folder_resv, SEEK_CUR); - - fol = (struct fdi_folder *) PFDI_ALLOC(hfdi, sizeof(struct fdi_folder)); - if (!fol) { - ERR("out of memory!\n"); - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL; - PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; - PFDI_INT(hfdi)->perf->fError = TRUE; - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto bail_and_fail; - } - ZeroMemory(fol, sizeof(struct fdi_folder)); - if (!CAB(firstfol)) CAB(firstfol) = fol; - - fol->offset = (cab_off_t) EndGetI32(buf+cffold_DataOffset); - fol->num_blocks = EndGetI16(buf+cffold_NumBlocks); - fol->comp_type = EndGetI16(buf+cffold_CompType); - - if (linkfol) - linkfol->next = fol; - linkfol = fol; - } - - /* read files */ - for (i = 0; i < fdici.cFiles; i++) { - if (PFDI_READ(hfdi, cabhf, buf, cffile_SIZEOF) != cffile_SIZEOF) { - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET; - PFDI_INT(hfdi)->perf->erfType = 0; - PFDI_INT(hfdi)->perf->fError = TRUE; - goto bail_and_fail; - } - - file = (struct fdi_file *) PFDI_ALLOC(hfdi, sizeof(struct fdi_file)); - if (!file) { - ERR("out of memory!\n"); - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL; - PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; - PFDI_INT(hfdi)->perf->fError = TRUE; - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto bail_and_fail; - } - ZeroMemory(file, sizeof(struct fdi_file)); - if (!CAB(firstfile)) CAB(firstfile) = file; - - file->length = EndGetI32(buf+cffile_UncompressedSize); - file->offset = EndGetI32(buf+cffile_FolderOffset); - file->index = EndGetI16(buf+cffile_FolderIndex); - file->time = EndGetI16(buf+cffile_Time); - file->date = EndGetI16(buf+cffile_Date); - file->attribs = EndGetI16(buf+cffile_Attribs); - file->filename = FDI_read_string(hfdi, cabhf, fdici.cbCabinet); - - if (!file->filename) { - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET; - PFDI_INT(hfdi)->perf->erfType = 0; - PFDI_INT(hfdi)->perf->fError = TRUE; - goto bail_and_fail; - } - - if (linkfile) - linkfile->next = file; - linkfile = file; - } - - for (file = CAB(firstfile); (file); file = file->next) { - - /* - * FIXME: This implementation keeps multiple cabinet files open at once - * when encountering a split cabinet. It is a quirk of this implementation - * that sometimes we decrypt the same block of data more than once, to find - * the right starting point for a file, moving the file-pointer backwards. - * If we kept a cache of certain file-pointer information, we could eliminate - * that behavior... in fact I am not sure that the caching we already have - * is not sufficient. - * - * The current implementation seems to work fine in straightforward situations - * where all the cabinet files needed for decryption are simultaneously - * available. But presumably, the API is supposed to support cabinets which - * are split across multiple CDROMS; we may need to change our implementation - * to strictly serialize it's file usage so that it opens only one cabinet - * at a time. Some experimentation with Windows is needed to figure out the - * precise semantics required. The relevant code is here and in fdi_decomp(). - */ - - /* partial-file notification */ - if ((file->index & cffileCONTINUED_FROM_PREV) == cffileCONTINUED_FROM_PREV) { - /* - * FIXME: Need to create a Cabinet with a single file spanning multiple files - * and perform some tests to figure out the right behavior. The SDK says - * FDICopy will notify the user of the filename and "disk name" (info) of - * the cabinet where the spanning file /started/. - * - * That would certainly be convenient for the API-user, who could abort, - * everything (or parallelize, if that's allowed (it is in wine)), and call - * FDICopy again with the provided filename, so as to avoid partial file - * notification and successfully unpack. This task could be quite unpleasant - * from wine's perspective: the information specifying the "start cabinet" for - * a file is associated nowhere with the file header and is not to be found in - * the cabinet header. We have only the index of the cabinet wherein the folder - * begins, which contains the file. To find that cabinet, we must consider the - * index of the current cabinet, and chain backwards, cabinet-by-cabinet (for - * each cabinet refers to its "next" and "previous" cabinet only, like a linked - * list). - * - * Bear in mind that, in the spirit of CABINET.DLL, we must assume that any - * cabinet other than the active one might be at another filepath than the - * current one, or on another CDROM. This could get rather dicey, especially - * if we imagine parallelized access to the FDICopy API. - * - * The current implementation punts -- it just returns the previous cabinet and - * it's info from the header of this cabinet. This provides the right answer in - * 95% of the cases; its worth checking if Microsoft cuts the same corner before - * we "fix" it. - */ - ZeroMemory(&fdin, sizeof(FDINOTIFICATION)); - fdin.pv = pvUser; - fdin.psz1 = (char *)file->filename; - fdin.psz2 = (CAB(mii).prevname) ? CAB(mii).prevname : &emptystring; - fdin.psz3 = (CAB(mii).previnfo) ? CAB(mii).previnfo : &emptystring; - - if (((*pfnfdin)(fdintPARTIAL_FILE, &fdin))) { - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT; - PFDI_INT(hfdi)->perf->erfType = 0; - PFDI_INT(hfdi)->perf->fError = TRUE; - goto bail_and_fail; - } - /* I don't think we are supposed to decompress partial files. This prevents it. */ - file->oppressed = TRUE; - } - if (file->oppressed) { - filehf = 0; - } else { - ZeroMemory(&fdin, sizeof(FDINOTIFICATION)); - fdin.pv = pvUser; - fdin.psz1 = (char *)file->filename; - fdin.cb = file->length; - fdin.date = file->date; - fdin.time = file->time; - fdin.attribs = file->attribs; - if ((filehf = ((*pfnfdin)(fdintCOPY_FILE, &fdin))) == -1) { - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT; - PFDI_INT(hfdi)->perf->erfType = 0; - PFDI_INT(hfdi)->perf->fError = TRUE; - goto bail_and_fail; - } - } - - /* find the folder for this file if necc. */ - if (filehf) { - int i2; - - fol = CAB(firstfol); - if ((file->index & cffileCONTINUED_TO_NEXT) == cffileCONTINUED_TO_NEXT) { - /* pick the last folder */ - while (fol->next) fol = fol->next; - } else { - for (i2 = 0; (i2 < file->index); i2++) - if (fol->next) /* bug resistance, should always be true */ - fol = fol->next; - } - } - - if (filehf) { - cab_UWORD comptype = fol->comp_type; - int ct1 = comptype & cffoldCOMPTYPE_MASK; - int ct2 = CAB(current) ? (CAB(current)->comp_type & cffoldCOMPTYPE_MASK) : 0; - int err = 0; - - TRACE("Extracting file %s as requested by callee.\n", debugstr_a(file->filename)); - - /* set up decomp_state */ - CAB(hfdi) = hfdi; - CAB(filehf) = filehf; - CAB(cabhf) = cabhf; - - /* Was there a change of folder? Compression type? Did we somehow go backwards? */ - if ((ct1 != ct2) || (CAB(current) != fol) || (file->offset < CAB(offset))) { - - TRACE("Resetting folder for file %s.\n", debugstr_a(file->filename)); - - /* free stuff for the old decompresser */ - switch (ct2) { - case cffoldCOMPTYPE_LZX: - if (LZX(window)) { - PFDI_FREE(hfdi, LZX(window)); - LZX(window) = NULL; - } - break; - case cffoldCOMPTYPE_QUANTUM: - if (QTM(window)) { - PFDI_FREE(hfdi, QTM(window)); - QTM(window) = NULL; - } - break; - } - - CAB(decomp_cab) = NULL; - PFDI_SEEK(CAB(hfdi), CAB(cabhf), fol->offset, SEEK_SET); - CAB(offset) = 0; - CAB(outlen) = 0; - - /* initialize the new decompresser */ - switch (ct1) { - case cffoldCOMPTYPE_NONE: - CAB(decompress) = NONEfdi_decomp; - break; - case cffoldCOMPTYPE_MSZIP: - CAB(decompress) = ZIPfdi_decomp; - break; - case cffoldCOMPTYPE_QUANTUM: - CAB(decompress) = QTMfdi_decomp; - err = QTMfdi_init((comptype >> 8) & 0x1f, (comptype >> 4) & 0xF, decomp_state); - break; - case cffoldCOMPTYPE_LZX: - CAB(decompress) = LZXfdi_decomp; - err = LZXfdi_init((comptype >> 8) & 0x1f, decomp_state); - break; - default: - err = DECR_DATAFORMAT; - } - } - - CAB(current) = fol; - - switch (err) { - case DECR_OK: - break; - case DECR_NOMEMORY: - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL; - PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; - PFDI_INT(hfdi)->perf->fError = TRUE; - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto bail_and_fail; - default: - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET; - PFDI_INT(hfdi)->perf->erfOper = 0; - PFDI_INT(hfdi)->perf->fError = TRUE; - goto bail_and_fail; - } - - if (file->offset > CAB(offset)) { - /* decode bytes and send them to /dev/null */ - switch ((err = fdi_decomp(file, 0, decomp_state, pszCabPath, pfnfdin, pvUser))) { - case DECR_OK: - break; - case DECR_USERABORT: - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT; - PFDI_INT(hfdi)->perf->erfType = 0; - PFDI_INT(hfdi)->perf->fError = TRUE; - goto bail_and_fail; - case DECR_NOMEMORY: - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL; - PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; - PFDI_INT(hfdi)->perf->fError = TRUE; - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto bail_and_fail; - default: - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET; - PFDI_INT(hfdi)->perf->erfOper = 0; - PFDI_INT(hfdi)->perf->fError = TRUE; - goto bail_and_fail; - } - CAB(offset) = file->offset; - } - - /* now do the actual decompression */ - err = fdi_decomp(file, 1, decomp_state, pszCabPath, pfnfdin, pvUser); - if (err) CAB(current) = NULL; else CAB(offset) += file->length; - - switch (err) { - case DECR_OK: - break; - case DECR_USERABORT: - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT; - PFDI_INT(hfdi)->perf->erfType = 0; - PFDI_INT(hfdi)->perf->fError = TRUE; - goto bail_and_fail; - case DECR_NOMEMORY: - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL; - PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; - PFDI_INT(hfdi)->perf->fError = TRUE; - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto bail_and_fail; - default: - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET; - PFDI_INT(hfdi)->perf->erfOper = 0; - PFDI_INT(hfdi)->perf->fError = TRUE; - goto bail_and_fail; - } - - /* fdintCLOSE_FILE_INFO notification */ - ZeroMemory(&fdin, sizeof(FDINOTIFICATION)); - fdin.pv = pvUser; - fdin.psz1 = (char *)file->filename; - fdin.hf = filehf; - fdin.cb = (file->attribs & cffile_A_EXEC) ? TRUE : FALSE; /* FIXME: is that right? */ - fdin.date = file->date; - fdin.time = file->time; - fdin.attribs = file->attribs; /* FIXME: filter _A_EXEC? */ - err = ((*pfnfdin)(fdintCLOSE_FILE_INFO, &fdin)); - if (err == FALSE || err == -1) { - /* - * SDK states that even though they indicated failure, - * we are not supposed to try and close the file, so we - * just treat this like all the others - */ - PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT; - PFDI_INT(hfdi)->perf->erfType = 0; - PFDI_INT(hfdi)->perf->fError = TRUE; - goto bail_and_fail; - } - } - } - - /* free decompression temps */ - switch (fol->comp_type & cffoldCOMPTYPE_MASK) { - case cffoldCOMPTYPE_LZX: - if (LZX(window)) { - PFDI_FREE(hfdi, LZX(window)); - LZX(window) = NULL; - } - break; - case cffoldCOMPTYPE_QUANTUM: - if (QTM(window)) { - PFDI_FREE(hfdi, QTM(window)); - QTM(window) = NULL; - } - break; - } - - while (decomp_state) { - fdi_decomp_state *prev_fds; - - PFDI_CLOSE(hfdi, CAB(cabhf)); - - /* free the storage remembered by mii */ - if (CAB(mii).nextname) PFDI_FREE(hfdi, CAB(mii).nextname); - if (CAB(mii).nextinfo) PFDI_FREE(hfdi, CAB(mii).nextinfo); - if (CAB(mii).prevname) PFDI_FREE(hfdi, CAB(mii).prevname); - if (CAB(mii).previnfo) PFDI_FREE(hfdi, CAB(mii).previnfo); - - while (CAB(firstfol)) { - fol = CAB(firstfol); - CAB(firstfol) = CAB(firstfol)->next; - PFDI_FREE(hfdi, fol); - } - while (CAB(firstfile)) { - file = CAB(firstfile); - if (file->filename) PFDI_FREE(hfdi, (void *)file->filename); - CAB(firstfile) = CAB(firstfile)->next; - PFDI_FREE(hfdi, file); - } - prev_fds = decomp_state; - decomp_state = CAB(next); - if (prev_fds != &_decomp_state) - PFDI_FREE(hfdi, prev_fds); - } - - return TRUE; - - bail_and_fail: /* here we free ram before error returns */ - - /* free decompression temps */ - switch (fol->comp_type & cffoldCOMPTYPE_MASK) { - case cffoldCOMPTYPE_LZX: - if (LZX(window)) { - PFDI_FREE(hfdi, LZX(window)); - LZX(window) = NULL; - } - break; - case cffoldCOMPTYPE_QUANTUM: - if (QTM(window)) { - PFDI_FREE(hfdi, QTM(window)); - QTM(window) = NULL; - } - break; - } - - while (decomp_state) { - fdi_decomp_state *prev_fds; - - PFDI_CLOSE(hfdi, CAB(cabhf)); - - /* free the storage remembered by mii */ - if (CAB(mii).nextname) PFDI_FREE(hfdi, CAB(mii).nextname); - if (CAB(mii).nextinfo) PFDI_FREE(hfdi, CAB(mii).nextinfo); - if (CAB(mii).prevname) PFDI_FREE(hfdi, CAB(mii).prevname); - if (CAB(mii).previnfo) PFDI_FREE(hfdi, CAB(mii).previnfo); - - while (CAB(firstfol)) { - fol = CAB(firstfol); - CAB(firstfol) = CAB(firstfol)->next; - PFDI_FREE(hfdi, fol); - } - while (CAB(firstfile)) { - file = CAB(firstfile); - if (file->filename) PFDI_FREE(hfdi, (void *)file->filename); - CAB(firstfile) = CAB(firstfile)->next; - PFDI_FREE(hfdi, file); - } - prev_fds = decomp_state; - decomp_state = CAB(next); - if (prev_fds != &_decomp_state) - PFDI_FREE(hfdi, prev_fds); - } - - return FALSE; -} - -/*********************************************************************** - * FDIDestroy (CABINET.23) - * - * Frees a handle created by FDICreate. Do /not/ call this in the middle - * of FDICopy. Only reason for failure would be an invalid handle. - * - * PARAMS - * hfdi [I] The HFDI to free - * - * RETURNS - * TRUE for success - * FALSE for failure - */ -BOOL __cdecl FDIDestroy(HFDI hfdi) -{ - TRACE("(hfdi == ^%p)\n", hfdi); - if (REALLY_IS_FDI(hfdi)) { - PFDI_INT(hfdi)->FDI_Intmagic = 0; /* paranoia */ - PFDI_FREE(hfdi, hfdi); /* confusing, but correct */ - return TRUE; - } else { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } -} - -/*********************************************************************** - * FDITruncateCabinet (CABINET.24) - * - * Undocumented and unimplemented. - */ -BOOL __cdecl FDITruncateCabinet( - HFDI hfdi, - char *pszCabinetName, - USHORT iFolderToDelete) -{ - FIXME("(hfdi == ^%p, pszCabinetName == %s, iFolderToDelete == %hu): stub\n", - hfdi, debugstr_a(pszCabinetName), iFolderToDelete); - - if (!REALLY_IS_FDI(hfdi)) { - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} +/* + * File Decompression Interface + * + * Copyright 2000-2002 Stuart Caie + * Copyright 2002 Patrik Stridvall + * Copyright 2003 Greg Turner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * This is a largely redundant reimplementation of the stuff in cabextract.c. It + * would be theoretically preferable to have only one, shared implementation, however + * there are semantic differences which may discourage efforts to unify the two. It + * should be possible, if awkward, to go back and reimplement cabextract.c using FDI. + * But this approach would be quite a bit less performant. Probably a better way + * would be to create a "library" of routines in cabextract.c which do the actual + * decompression, and have both fdi.c and cabextract share those routines. The rest + * of the code is not sufficiently similar to merit a shared implementation. + * + * The worst thing about this API is the bug. "The bug" is this: when you extract a + * cabinet, it /always/ informs you (via the hasnext field of PFDICABINETINFO), that + * there is no subsequent cabinet, even if there is one. wine faithfully reproduces + * this behavior. + * + * TODO: + * + * Wine does not implement the AFAIK undocumented "enumerate" callback during + * FDICopy. It is implemented in Windows and therefore worth investigating... + * + * Lots of pointers flying around here... am I leaking RAM? + * + * WTF is FDITruncate? + * + * Probably, I need to weed out some dead code-paths. + * + * Test unit(s). + * + * The fdintNEXT_CABINET callbacks are probably not working quite as they should. + * There are several FIXME's in the source describing some of the deficiencies in + * some detail. Additionally, we do not do a very good job of returning the right + * error codes to this callback. + * + * FDICopy and fdi_decomp are incomprehensibly large; separating these into smaller + * functions would be nice. + * + * -gmt + */ + +#include "config.h" + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "fdi.h" +#include "cabinet.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(cabinet); + +THOSE_ZIP_CONSTS; + +struct fdi_file { + struct fdi_file *next; /* next file in sequence */ + LPCSTR filename; /* output name of file */ + int fh; /* open file handle or NULL */ + cab_ULONG length; /* uncompressed length of file */ + cab_ULONG offset; /* uncompressed offset in folder */ + cab_UWORD index; /* magic index number of folder */ + cab_UWORD time, date, attribs; /* MS-DOS time/date/attributes */ + BOOL oppressed; /* never to be processed */ +}; + +struct fdi_folder { + struct fdi_folder *next; + cab_off_t offset; /* offset to data blocks (32 bit) */ + cab_UWORD comp_type; /* compression format/window size */ + cab_ULONG comp_size; /* compressed size of folder */ + cab_UBYTE num_splits; /* number of split blocks + 1 */ + cab_UWORD num_blocks; /* total number of blocks */ +}; + +/* + * this structure fills the gaps between what is available in a PFDICABINETINFO + * vs what is needed by FDICopy. Memory allocated for these becomes the responsibility + * of the caller to free. Yes, I am aware that this is totally, utterly inelegant. + * To make things even more unnecessarily confusing, we now attach these to the + * fdi_decomp_state. + */ +typedef struct { + char *prevname, *previnfo; + char *nextname, *nextinfo; + BOOL hasnext; /* bug free indicator */ + int folder_resv, header_resv; + cab_UBYTE block_resv; +} MORE_ISCAB_INFO, *PMORE_ISCAB_INFO; + +/* + * ugh, well, this ended up being pretty damn silly... + * now that I've conceded to build equivalent structures to struct cab.*, + * I should have just used those, or, better yet, unified the two... sue me. + * (Note to Microsoft: That's a joke. Please /don't/ actually sue me! -gmt). + * Nevertheless, I've come this far, it works, so I'm not gonna change it + * for now. This implementation has significant semantic differences anyhow. + */ + +typedef struct fdi_cds_fwd { + void *hfdi; /* the hfdi we are using */ + int filehf, cabhf; /* file handle we are using */ + struct fdi_folder *current; /* current folder we're extracting from */ + cab_ULONG offset; /* uncompressed offset within folder */ + cab_UBYTE *outpos; /* (high level) start of data to use up */ + cab_UWORD outlen; /* (high level) amount of data to use up */ + int (*decompress)(int, int, struct fdi_cds_fwd *); /* chosen compress fn */ + cab_UBYTE inbuf[CAB_INPUTMAX+2]; /* +2 for lzx bitbuffer overflows! */ + cab_UBYTE outbuf[CAB_BLOCKMAX]; + union { + struct ZIPstate zip; + struct QTMstate qtm; + struct LZXstate lzx; + } methods; + /* some temp variables for use during decompression */ + cab_UBYTE q_length_base[27], q_length_extra[27], q_extra_bits[42]; + cab_ULONG q_position_base[42]; + cab_ULONG lzx_position_base[51]; + cab_UBYTE extra_bits[51]; + USHORT setID; /* Cabinet set ID */ + USHORT iCabinet; /* Cabinet number in set (0 based) */ + struct fdi_cds_fwd *decomp_cab; + MORE_ISCAB_INFO mii; + struct fdi_folder *firstfol; + struct fdi_file *firstfile; + struct fdi_cds_fwd *next; +} fdi_decomp_state; + +/*********************************************************************** + * FDICreate (CABINET.20) + * + * Provided with several callbacks (all of them are mandatory), + * returns a handle which can be used to perform operations + * on cabinet files. + * + * PARAMS + * pfnalloc [I] A pointer to a function which allocates ram. Uses + * the same interface as malloc. + * pfnfree [I] A pointer to a function which frees ram. Uses the + * same interface as free. + * pfnopen [I] A pointer to a function which opens a file. Uses + * the same interface as _open. + * pfnread [I] A pointer to a function which reads from a file into + * a caller-provided buffer. Uses the same interface + * as _read + * pfnwrite [I] A pointer to a function which writes to a file from + * a caller-provided buffer. Uses the same interface + * as _write. + * pfnclose [I] A pointer to a function which closes a file handle. + * Uses the same interface as _close. + * pfnseek [I] A pointer to a function which seeks in a file. + * Uses the same interface as _lseek. + * cpuType [I] The type of CPU; ignored in wine (recommended value: + * cpuUNKNOWN, aka -1). + * perf [IO] A pointer to an ERF structure. When FDICreate + * returns an error condition, error information may + * be found here as well as from GetLastError. + * + * RETURNS + * On success, returns an FDI handle of type HFDI. + * On failure, the NULL file handle is returned. Error + * info can be retrieved from perf. + * + * INCLUDES + * fdi.h + * + */ +HFDI __cdecl FDICreate( + PFNALLOC pfnalloc, + PFNFREE pfnfree, + PFNOPEN pfnopen, + PFNREAD pfnread, + PFNWRITE pfnwrite, + PFNCLOSE pfnclose, + PFNSEEK pfnseek, + int cpuType, + PERF perf) +{ + HFDI rv; + + TRACE("(pfnalloc == ^%p, pfnfree == ^%p, pfnopen == ^%p, pfnread == ^%p, pfnwrite == ^%p, \ + pfnclose == ^%p, pfnseek == ^%p, cpuType == %d, perf == ^%p)\n", + pfnalloc, pfnfree, pfnopen, pfnread, pfnwrite, pfnclose, pfnseek, + cpuType, perf); + + if ((!pfnalloc) || (!pfnfree)) { + perf->erfOper = FDIERROR_NONE; + perf->erfType = ERROR_BAD_ARGUMENTS; + perf->fError = TRUE; + + SetLastError(ERROR_BAD_ARGUMENTS); + return NULL; + } + + if (!((rv = ((HFDI) (*pfnalloc)(sizeof(FDI_Int)))))) { + perf->erfOper = FDIERROR_ALLOC_FAIL; + perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + perf->fError = TRUE; + + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + + PFDI_INT(rv)->FDI_Intmagic = FDI_INT_MAGIC; + PFDI_INT(rv)->pfnalloc = pfnalloc; + PFDI_INT(rv)->pfnfree = pfnfree; + PFDI_INT(rv)->pfnopen = pfnopen; + PFDI_INT(rv)->pfnread = pfnread; + PFDI_INT(rv)->pfnwrite = pfnwrite; + PFDI_INT(rv)->pfnclose = pfnclose; + PFDI_INT(rv)->pfnseek = pfnseek; + /* no-brainer: we ignore the cpu type; this is only used + for the 16-bit versions in Windows anyhow... */ + PFDI_INT(rv)->perf = perf; + + return rv; +} + +/******************************************************************* + * FDI_getoffset (internal) + * + * returns the file pointer position of a file handle. + */ +long FDI_getoffset(HFDI hfdi, INT_PTR hf) +{ + return PFDI_SEEK(hfdi, hf, 0L, SEEK_CUR); +} + +/********************************************************************** + * FDI_realloc (internal) + * + * we can't use _msize; the user might not be using malloc, so we require + * an explicit specification of the previous size. inefficient. + */ +void *FDI_realloc(HFDI hfdi, void *mem, size_t prevsize, size_t newsize) +{ + void *rslt = NULL; + char *irslt, *imem; + size_t copysize = (prevsize < newsize) ? prevsize : newsize; + if (prevsize == newsize) return mem; + rslt = PFDI_ALLOC(hfdi, newsize); + if (rslt) + for (irslt = (char *)rslt, imem = (char *)mem; (copysize); copysize--) + *irslt++ = *imem++; + PFDI_FREE(hfdi, mem); + return rslt; +} + +/********************************************************************** + * FDI_read_string (internal) + * + * allocate and read an arbitrarily long string from the cabinet + */ +char *FDI_read_string(HFDI hfdi, INT_PTR hf, long cabsize) +{ + size_t len=256, + oldlen = 0, + base = FDI_getoffset(hfdi, hf), + maxlen = cabsize - base; + BOOL ok = FALSE; + unsigned int i; + cab_UBYTE *buf = NULL; + + TRACE("(hfdi == ^%p, hf == %d)\n", hfdi, hf); + + do { + if (len > maxlen) len = maxlen; + if (!(buf = FDI_realloc(hfdi, buf, oldlen, len))) break; + oldlen = len; + if (!PFDI_READ(hfdi, hf, buf, len)) break; + + /* search for a null terminator in what we've just read */ + for (i=0; i < len; i++) { + if (!buf[i]) {ok=TRUE; break;} + } + + if (!ok) { + if (len == maxlen) { + ERR("cabinet is truncated\n"); + break; + } + len += 256; + PFDI_SEEK(hfdi, hf, base, SEEK_SET); + } + } while (!ok); + + if (!ok) { + if (buf) + PFDI_FREE(hfdi, buf); + else + ERR("out of memory!\n"); + return NULL; + } + + /* otherwise, set the stream to just after the string and return */ + PFDI_SEEK(hfdi, hf, base + ((cab_off_t) strlen((char *) buf)) + 1, SEEK_SET); + + return (char *) buf; +} + +/****************************************************************** + * FDI_read_entries (internal) + * + * process the cabinet header in the style of FDIIsCabinet, but + * without the sanity checks (and bug) + */ +BOOL FDI_read_entries( + HFDI hfdi, + INT_PTR hf, + PFDICABINETINFO pfdici, + PMORE_ISCAB_INFO pmii) +{ + int num_folders, num_files, header_resv, folder_resv = 0; + LONG base_offset, cabsize; + USHORT setid, cabidx, flags; + cab_UBYTE buf[64], block_resv; + char *prevname = NULL, *previnfo = NULL, *nextname = NULL, *nextinfo = NULL; + + TRACE("(hfdi == ^%p, hf == %d, pfdici == ^%p)\n", hfdi, hf, pfdici); + + /* + * FIXME: I just noticed that I am memorizing the initial file pointer + * offset and restoring it before reading in the rest of the header + * information in the cabinet. Perhaps that's correct -- that is, perhaps + * this API is supposed to support "streaming" cabinets which are embedded + * in other files, or cabinets which begin at file offsets other than zero. + * Otherwise, I should instead go to the absolute beginning of the file. + * (Either way, the semantics of wine's FDICopy require me to leave the + * file pointer where it is afterwards -- If Windows does not do so, we + * ought to duplicate the native behavior in the FDIIsCabinet API, not here. + * + * So, the answer lies in Windows; will native cabinet.dll recognize a + * cabinet "file" embedded in another file? Note that cabextract.c does + * support this, which implies that Microsoft's might. I haven't tried it + * yet so I don't know. ATM, most of wine's FDI cabinet routines (except + * this one) would not work in this way. To fix it, we could just make the + * various references to absolute file positions in the code relative to an + * initial "beginning" offset. Because the FDICopy API doesn't take a + * file-handle like this one, we would therein need to search through the + * file for the beginning of the cabinet (as we also do in cabextract.c). + * Note that this limits us to a maximum of one cabinet per. file: the first. + * + * So, in summary: either the code below is wrong, or the rest of fdi.c is + * wrong... I cannot imagine that both are correct ;) One of these flaws + * should be fixed after determining the behavior on Windows. We ought + * to check both FDIIsCabinet and FDICopy for the right behavior. + * + * -gmt + */ + + /* get basic offset & size info */ + base_offset = FDI_getoffset(hfdi, hf); + + if (PFDI_SEEK(hfdi, hf, 0, SEEK_END) == -1) { + if (pmii) { + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET; + PFDI_INT(hfdi)->perf->erfType = 0; + PFDI_INT(hfdi)->perf->fError = TRUE; + } + return FALSE; + } + + cabsize = FDI_getoffset(hfdi, hf); + + if ((cabsize == -1) || (base_offset == -1) || + ( PFDI_SEEK(hfdi, hf, base_offset, SEEK_SET) == -1 )) { + if (pmii) { + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET; + PFDI_INT(hfdi)->perf->erfType = 0; + PFDI_INT(hfdi)->perf->fError = TRUE; + } + return FALSE; + } + + /* read in the CFHEADER */ + if (PFDI_READ(hfdi, hf, buf, cfhead_SIZEOF) != cfhead_SIZEOF) { + if (pmii) { + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET; + PFDI_INT(hfdi)->perf->erfType = 0; + PFDI_INT(hfdi)->perf->fError = TRUE; + } + return FALSE; + } + + /* check basic MSCF signature */ + if (EndGetI32(buf+cfhead_Signature) != 0x4643534d) { + if (pmii) { + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET; + PFDI_INT(hfdi)->perf->erfType = 0; + PFDI_INT(hfdi)->perf->fError = TRUE; + } + return FALSE; + } + + /* get the number of folders */ + num_folders = EndGetI16(buf+cfhead_NumFolders); + if (num_folders == 0) { + /* PONDERME: is this really invalid? */ + WARN("weird cabinet detect failure: no folders in cabinet\n"); + if (pmii) { + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET; + PFDI_INT(hfdi)->perf->erfType = 0; + PFDI_INT(hfdi)->perf->fError = TRUE; + } + return FALSE; + } + + /* get the number of files */ + num_files = EndGetI16(buf+cfhead_NumFiles); + if (num_files == 0) { + /* PONDERME: is this really invalid? */ + WARN("weird cabinet detect failure: no files in cabinet\n"); + if (pmii) { + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NOT_A_CABINET; + PFDI_INT(hfdi)->perf->erfType = 0; + PFDI_INT(hfdi)->perf->fError = TRUE; + } + return FALSE; + } + + /* setid */ + setid = EndGetI16(buf+cfhead_SetID); + + /* cabinet (set) index */ + cabidx = EndGetI16(buf+cfhead_CabinetIndex); + + /* check the header revision */ + if ((buf[cfhead_MajorVersion] > 1) || + (buf[cfhead_MajorVersion] == 1 && buf[cfhead_MinorVersion] > 3)) + { + WARN("cabinet format version > 1.3\n"); + if (pmii) { + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_UNKNOWN_CABINET_VERSION; + PFDI_INT(hfdi)->perf->erfType = 0; /* ? */ + PFDI_INT(hfdi)->perf->fError = TRUE; + } + return FALSE; + } + + /* pull the flags out */ + flags = EndGetI16(buf+cfhead_Flags); + + /* read the reserved-sizes part of header, if present */ + if (flags & cfheadRESERVE_PRESENT) { + if (PFDI_READ(hfdi, hf, buf, cfheadext_SIZEOF) != cfheadext_SIZEOF) { + ERR("bunk reserve-sizes?\n"); + if (pmii) { + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET; + PFDI_INT(hfdi)->perf->erfType = 0; /* ? */ + PFDI_INT(hfdi)->perf->fError = TRUE; + } + return FALSE; + } + + header_resv = EndGetI16(buf+cfheadext_HeaderReserved); + if (pmii) pmii->header_resv = header_resv; + folder_resv = buf[cfheadext_FolderReserved]; + if (pmii) pmii->folder_resv = folder_resv; + block_resv = buf[cfheadext_DataReserved]; + if (pmii) pmii->block_resv = block_resv; + + if (header_resv > 60000) { + WARN("WARNING; header reserved space > 60000\n"); + } + + /* skip the reserved header */ + if ((header_resv) && (PFDI_SEEK(hfdi, hf, header_resv, SEEK_CUR) == -1)) { + ERR("seek failure: header_resv\n"); + if (pmii) { + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET; + PFDI_INT(hfdi)->perf->erfType = 0; /* ? */ + PFDI_INT(hfdi)->perf->fError = TRUE; + } + return FALSE; + } + } + + if (flags & cfheadPREV_CABINET) { + prevname = FDI_read_string(hfdi, hf, cabsize); + if (!prevname) { + if (pmii) { + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET; + PFDI_INT(hfdi)->perf->erfType = 0; /* ? */ + PFDI_INT(hfdi)->perf->fError = TRUE; + } + return FALSE; + } else + if (pmii) + pmii->prevname = prevname; + else + PFDI_FREE(hfdi, prevname); + previnfo = FDI_read_string(hfdi, hf, cabsize); + if (previnfo) { + if (pmii) + pmii->previnfo = previnfo; + else + PFDI_FREE(hfdi, previnfo); + } + } + + if (flags & cfheadNEXT_CABINET) { + if (pmii) + pmii->hasnext = TRUE; + nextname = FDI_read_string(hfdi, hf, cabsize); + if (!nextname) { + if ((flags & cfheadPREV_CABINET) && pmii) { + if (pmii->prevname) PFDI_FREE(hfdi, prevname); + if (pmii->previnfo) PFDI_FREE(hfdi, previnfo); + } + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET; + PFDI_INT(hfdi)->perf->erfType = 0; /* ? */ + PFDI_INT(hfdi)->perf->fError = TRUE; + return FALSE; + } else + if (pmii) + pmii->nextname = nextname; + else + PFDI_FREE(hfdi, nextname); + nextinfo = FDI_read_string(hfdi, hf, cabsize); + if (nextinfo) { + if (pmii) + pmii->nextinfo = nextinfo; + else + PFDI_FREE(hfdi, nextinfo); + } + } + + /* we could process the whole cabinet searching for problems; + instead lets stop here. Now let's fill out the paperwork */ + pfdici->cbCabinet = cabsize; + pfdici->cFolders = num_folders; + pfdici->cFiles = num_files; + pfdici->setID = setid; + pfdici->iCabinet = cabidx; + pfdici->fReserve = (flags & cfheadRESERVE_PRESENT) ? TRUE : FALSE; + pfdici->hasprev = (flags & cfheadPREV_CABINET) ? TRUE : FALSE; + pfdici->hasnext = (flags & cfheadNEXT_CABINET) ? TRUE : FALSE; + return TRUE; +} + +/*********************************************************************** + * FDIIsCabinet (CABINET.21) + * + * Informs the caller as to whether or not the provided file handle is + * really a cabinet or not, filling out the provided PFDICABINETINFO + * structure with information about the cabinet. Brief explanations of + * the elements of this structure are available as comments accompanying + * its definition in wine's include/fdi.h. + * + * PARAMS + * hfdi [I] An HFDI from FDICreate + * hf [I] The file handle about which the caller inquires + * pfdici [IO] Pointer to a PFDICABINETINFO structure which will + * be filled out with information about the cabinet + * file indicated by hf if, indeed, it is determined + * to be a cabinet. + * + * RETURNS + * TRUE if the file is a cabinet. The info pointed to by pfdici will + * be provided. + * FALSE if the file is not a cabinet, or if an error was encountered + * while processing the cabinet. The PERF structure provided to + * FDICreate can be queried for more error information. + * + * INCLUDES + * fdi.c + */ +BOOL __cdecl FDIIsCabinet( + HFDI hfdi, + INT_PTR hf, + PFDICABINETINFO pfdici) +{ + BOOL rv; + + TRACE("(hfdi == ^%p, hf == ^%d, pfdici == ^%p)\n", hfdi, hf, pfdici); + + if (!REALLY_IS_FDI(hfdi)) { + ERR("REALLY_IS_FDI failed on ^%p\n", hfdi); + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (!hf) { + ERR("(!hf)!\n"); + /* PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CABINET_NOT_FOUND; + PFDI_INT(hfdi)->perf->erfType = ERROR_INVALID_HANDLE; + PFDI_INT(hfdi)->perf->fError = TRUE; */ + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + if (!pfdici) { + ERR("(!pfdici)!\n"); + /* PFDI_INT(hfdi)->perf->erfOper = FDIERROR_NONE; + PFDI_INT(hfdi)->perf->erfType = ERROR_BAD_ARGUMENTS; + PFDI_INT(hfdi)->perf->fError = TRUE; */ + SetLastError(ERROR_BAD_ARGUMENTS); + return FALSE; + } + rv = FDI_read_entries(hfdi, hf, pfdici, NULL); + + if (rv) + pfdici->hasnext = FALSE; /* yuck. duplicate apparent cabinet.dll bug */ + + return rv; +} + +/****************************************************************** + * QTMfdi_initmodel (internal) + * + * Initialize a model which decodes symbols from [s] to [s]+[n]-1 + */ +void QTMfdi_initmodel(struct QTMmodel *m, struct QTMmodelsym *sym, int n, int s) { + int i; + m->shiftsleft = 4; + m->entries = n; + m->syms = sym; + memset(m->tabloc, 0xFF, sizeof(m->tabloc)); /* clear out look-up table */ + for (i = 0; i < n; i++) { + m->tabloc[i+s] = i; /* set up a look-up entry for symbol */ + m->syms[i].sym = i+s; /* actual symbol */ + m->syms[i].cumfreq = n-i; /* current frequency of that symbol */ + } + m->syms[n].cumfreq = 0; +} + +/****************************************************************** + * QTMfdi_init (internal) + */ +int QTMfdi_init(int window, int level, fdi_decomp_state *decomp_state) { + unsigned int wndsize = 1 << window; + int msz = window * 2, i; + cab_ULONG j; + + /* QTM supports window sizes of 2^10 (1Kb) through 2^21 (2Mb) */ + /* if a previously allocated window is big enough, keep it */ + if (window < 10 || window > 21) return DECR_DATAFORMAT; + if (QTM(actual_size) < wndsize) { + if (QTM(window)) PFDI_FREE(CAB(hfdi), QTM(window)); + QTM(window) = NULL; + } + if (!QTM(window)) { + if (!(QTM(window) = PFDI_ALLOC(CAB(hfdi), wndsize))) return DECR_NOMEMORY; + QTM(actual_size) = wndsize; + } + QTM(window_size) = wndsize; + QTM(window_posn) = 0; + + /* initialize static slot/extrabits tables */ + for (i = 0, j = 0; i < 27; i++) { + CAB(q_length_extra)[i] = (i == 26) ? 0 : (i < 2 ? 0 : i - 2) >> 2; + CAB(q_length_base)[i] = j; j += 1 << ((i == 26) ? 5 : CAB(q_length_extra)[i]); + } + for (i = 0, j = 0; i < 42; i++) { + CAB(q_extra_bits)[i] = (i < 2 ? 0 : i-2) >> 1; + CAB(q_position_base)[i] = j; j += 1 << CAB(q_extra_bits)[i]; + } + + /* initialize arithmetic coding models */ + + QTMfdi_initmodel(&QTM(model7), &QTM(m7sym)[0], 7, 0); + + QTMfdi_initmodel(&QTM(model00), &QTM(m00sym)[0], 0x40, 0x00); + QTMfdi_initmodel(&QTM(model40), &QTM(m40sym)[0], 0x40, 0x40); + QTMfdi_initmodel(&QTM(model80), &QTM(m80sym)[0], 0x40, 0x80); + QTMfdi_initmodel(&QTM(modelC0), &QTM(mC0sym)[0], 0x40, 0xC0); + + /* model 4 depends on table size, ranges from 20 to 24 */ + QTMfdi_initmodel(&QTM(model4), &QTM(m4sym)[0], (msz < 24) ? msz : 24, 0); + /* model 5 depends on table size, ranges from 20 to 36 */ + QTMfdi_initmodel(&QTM(model5), &QTM(m5sym)[0], (msz < 36) ? msz : 36, 0); + /* model 6pos depends on table size, ranges from 20 to 42 */ + QTMfdi_initmodel(&QTM(model6pos), &QTM(m6psym)[0], msz, 0); + QTMfdi_initmodel(&QTM(model6len), &QTM(m6lsym)[0], 27, 0); + + return DECR_OK; +} + +/************************************************************ + * LZXfdi_init (internal) + */ +int LZXfdi_init(int window, fdi_decomp_state *decomp_state) { + cab_ULONG wndsize = 1 << window; + int i, j, posn_slots; + + /* LZX supports window sizes of 2^15 (32Kb) through 2^21 (2Mb) */ + /* if a previously allocated window is big enough, keep it */ + if (window < 15 || window > 21) return DECR_DATAFORMAT; + if (LZX(actual_size) < wndsize) { + if (LZX(window)) PFDI_FREE(CAB(hfdi), LZX(window)); + LZX(window) = NULL; + } + if (!LZX(window)) { + if (!(LZX(window) = PFDI_ALLOC(CAB(hfdi), wndsize))) return DECR_NOMEMORY; + LZX(actual_size) = wndsize; + } + LZX(window_size) = wndsize; + + /* initialize static tables */ + for (i=0, j=0; i <= 50; i += 2) { + CAB(extra_bits)[i] = CAB(extra_bits)[i+1] = j; /* 0,0,0,0,1,1,2,2,3,3... */ + if ((i != 0) && (j < 17)) j++; /* 0,0,1,2,3,4...15,16,17,17,17,17... */ + } + for (i=0, j=0; i <= 50; i++) { + CAB(lzx_position_base)[i] = j; /* 0,1,2,3,4,6,8,12,16,24,32,... */ + j += 1 << CAB(extra_bits)[i]; /* 1,1,1,1,2,2,4,4,8,8,16,16,32,32,... */ + } + + /* calculate required position slots */ + if (window == 20) posn_slots = 42; + else if (window == 21) posn_slots = 50; + else posn_slots = window << 1; + + /*posn_slots=i=0; while (i < wndsize) i += 1 << CAB(extra_bits)[posn_slots++]; */ + + LZX(R0) = LZX(R1) = LZX(R2) = 1; + LZX(main_elements) = LZX_NUM_CHARS + (posn_slots << 3); + LZX(header_read) = 0; + LZX(frames_read) = 0; + LZX(block_remaining) = 0; + LZX(block_type) = LZX_BLOCKTYPE_INVALID; + LZX(intel_curpos) = 0; + LZX(intel_started) = 0; + LZX(window_posn) = 0; + + /* initialize tables to 0 (because deltas will be applied to them) */ + for (i = 0; i < LZX_MAINTREE_MAXSYMBOLS; i++) LZX(MAINTREE_len)[i] = 0; + for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++) LZX(LENGTH_len)[i] = 0; + + return DECR_OK; +} + +/**************************************************** + * NONEfdi_decomp(internal) + */ +int NONEfdi_decomp(int inlen, int outlen, fdi_decomp_state *decomp_state) +{ + if (inlen != outlen) return DECR_ILLEGALDATA; + memcpy(CAB(outbuf), CAB(inbuf), (size_t) inlen); + return DECR_OK; +} + +/******************************************************** + * Ziphuft_free (internal) + */ +void fdi_Ziphuft_free(HFDI hfdi, struct Ziphuft *t) +{ + register struct Ziphuft *p, *q; + + /* Go through linked list, freeing from the allocated (t[-1]) address. */ + p = t; + while (p != (struct Ziphuft *)NULL) + { + q = (--p)->v.t; + PFDI_FREE(hfdi, p); + p = q; + } +} + +/********************************************************* + * fdi_Ziphuft_build (internal) + */ +cab_LONG fdi_Ziphuft_build(cab_ULONG *b, cab_ULONG n, cab_ULONG s, cab_UWORD *d, cab_UWORD *e, +struct Ziphuft **t, cab_LONG *m, fdi_decomp_state *decomp_state) +{ + cab_ULONG a; /* counter for codes of length k */ + cab_ULONG el; /* length of EOB code (value 256) */ + cab_ULONG f; /* i repeats in table every f entries */ + cab_LONG g; /* maximum code length */ + cab_LONG h; /* table level */ + register cab_ULONG i; /* counter, current code */ + register cab_ULONG j; /* counter */ + register cab_LONG k; /* number of bits in current code */ + cab_LONG *l; /* stack of bits per table */ + register cab_ULONG *p; /* pointer into ZIP(c)[],ZIP(b)[],ZIP(v)[] */ + register struct Ziphuft *q; /* points to current table */ + struct Ziphuft r; /* table entry for structure assignment */ + register cab_LONG w; /* bits before this table == (l * h) */ + cab_ULONG *xp; /* pointer into x */ + cab_LONG y; /* number of dummy codes added */ + cab_ULONG z; /* number of entries in current table */ + + l = ZIP(lx)+1; + + /* Generate counts for each bit length */ + el = n > 256 ? b[256] : ZIPBMAX; /* set length of EOB code, if any */ + + for(i = 0; i < ZIPBMAX+1; ++i) + ZIP(c)[i] = 0; + p = b; i = n; + do + { + ZIP(c)[*p]++; p++; /* assume all entries <= ZIPBMAX */ + } while (--i); + if (ZIP(c)[0] == n) /* null input--all zero length codes */ + { + *t = (struct Ziphuft *)NULL; + *m = 0; + return 0; + } + + /* Find minimum and maximum length, bound *m by those */ + for (j = 1; j <= ZIPBMAX; j++) + if (ZIP(c)[j]) + break; + k = j; /* minimum code length */ + if ((cab_ULONG)*m < j) + *m = j; + for (i = ZIPBMAX; i; i--) + if (ZIP(c)[i]) + break; + g = i; /* maximum code length */ + if ((cab_ULONG)*m > i) + *m = i; + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= ZIP(c)[j]) < 0) + return 2; /* bad input: more codes than bits */ + if ((y -= ZIP(c)[i]) < 0) + return 2; + ZIP(c)[i] += y; + + /* Generate starting offsets LONGo the value table for each length */ + ZIP(x)[1] = j = 0; + p = ZIP(c) + 1; xp = ZIP(x) + 2; + while (--i) + { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do{ + if ((j = *p++) != 0) + ZIP(v)[ZIP(x)[j]++] = i; + } while (++i < n); + + + /* Generate the Huffman codes and for each, make the table entries */ + ZIP(x)[0] = i = 0; /* first Huffman code is zero */ + p = ZIP(v); /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = l[-1] = 0; /* no bits decoded yet */ + ZIP(u)[0] = (struct Ziphuft *)NULL; /* just to keep compilers happy */ + q = (struct Ziphuft *)NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = ZIP(c)[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l[h]) + { + w += l[h++]; /* add bits already decoded */ + + /* compute minimum size table less than or equal to *m bits */ + z = (z = g - w) > (cab_ULONG)*m ? *m : z; /* upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = ZIP(c) + k; + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + if ((cab_ULONG)w + j > el && (cab_ULONG)w < el) + j = el - w; /* make EOB code end at table */ + z = 1 << j; /* table entries for j-bit table */ + l[h] = j; /* set table size in stack */ + + /* allocate and link in new table */ + if (!(q = (struct Ziphuft *) PFDI_ALLOC(CAB(hfdi), (z + 1)*sizeof(struct Ziphuft)))) + { + if(h) + fdi_Ziphuft_free(CAB(hfdi), ZIP(u)[0]); + return 3; /* not enough memory */ + } + *t = q + 1; /* link to list for Ziphuft_free() */ + *(t = &(q->v.t)) = (struct Ziphuft *)NULL; + ZIP(u)[h] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (h) + { + ZIP(x)[h] = i; /* save pattern for backing up */ + r.b = (cab_UBYTE)l[h-1]; /* bits to dump before this table */ + r.e = (cab_UBYTE)(16 + j); /* bits in this table */ + r.v.t = q; /* pointer to this table */ + j = (i & ((1 << w) - 1)) >> (w - l[h-1]); + ZIP(u)[h-1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.b = (cab_UBYTE)(k - w); + if (p >= ZIP(v) + n) + r.e = 99; /* out of values--invalid code */ + else if (*p < s) + { + r.e = (cab_UBYTE)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */ + r.v.n = *p++; /* simple code is just the value */ + } + else + { + r.e = (cab_UBYTE)e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != ZIP(x)[h]) + w -= l[--h]; /* don't need to update q */ + } + } + + /* return actual size of base table */ + *m = l[0]; + + /* Return true (1) if we were given an incomplete table */ + return y != 0 && g != 1; +} + +/********************************************************* + * fdi_Zipinflate_codes (internal) + */ +cab_LONG fdi_Zipinflate_codes(struct Ziphuft *tl, struct Ziphuft *td, + cab_LONG bl, cab_LONG bd, fdi_decomp_state *decomp_state) +{ + register cab_ULONG e; /* table entry flag/number of extra bits */ + cab_ULONG n, d; /* length and index for copy */ + cab_ULONG w; /* current window position */ + struct Ziphuft *t; /* pointer to table entry */ + cab_ULONG ml, md; /* masks for bl and bd bits */ + register cab_ULONG b; /* bit buffer */ + register cab_ULONG k; /* number of bits in bit buffer */ + + /* make local copies of globals */ + b = ZIP(bb); /* initialize bit buffer */ + k = ZIP(bk); + w = ZIP(window_posn); /* initialize window position */ + + /* inflate the coded data */ + ml = Zipmask[bl]; /* precompute masks for speed */ + md = Zipmask[bd]; + + for(;;) + { + ZIPNEEDBITS((cab_ULONG)bl) + if((e = (t = tl + ((cab_ULONG)b & ml))->e) > 16) + do + { + if (e == 99) + return 1; + ZIPDUMPBITS(t->b) + e -= 16; + ZIPNEEDBITS(e) + } while ((e = (t = t->v.t + ((cab_ULONG)b & Zipmask[e]))->e) > 16); + ZIPDUMPBITS(t->b) + if (e == 16) /* then it's a literal */ + CAB(outbuf)[w++] = (cab_UBYTE)t->v.n; + else /* it's an EOB or a length */ + { + /* exit if end of block */ + if(e == 15) + break; + + /* get length of block to copy */ + ZIPNEEDBITS(e) + n = t->v.n + ((cab_ULONG)b & Zipmask[e]); + ZIPDUMPBITS(e); + + /* decode distance of block to copy */ + ZIPNEEDBITS((cab_ULONG)bd) + if ((e = (t = td + ((cab_ULONG)b & md))->e) > 16) + do { + if (e == 99) + return 1; + ZIPDUMPBITS(t->b) + e -= 16; + ZIPNEEDBITS(e) + } while ((e = (t = t->v.t + ((cab_ULONG)b & Zipmask[e]))->e) > 16); + ZIPDUMPBITS(t->b) + ZIPNEEDBITS(e) + d = w - t->v.n - ((cab_ULONG)b & Zipmask[e]); + ZIPDUMPBITS(e) + do + { + n -= (e = (e = ZIPWSIZE - ((d &= ZIPWSIZE-1) > w ? d : w)) > n ?n:e); + do + { + CAB(outbuf)[w++] = CAB(outbuf)[d++]; + } while (--e); + } while (n); + } + } + + /* restore the globals from the locals */ + ZIP(window_posn) = w; /* restore global window pointer */ + ZIP(bb) = b; /* restore global bit buffer */ + ZIP(bk) = k; + + /* done */ + return 0; +} + +/*********************************************************** + * Zipinflate_stored (internal) + */ +cab_LONG fdi_Zipinflate_stored(fdi_decomp_state *decomp_state) +/* "decompress" an inflated type 0 (stored) block. */ +{ + cab_ULONG n; /* number of bytes in block */ + cab_ULONG w; /* current window position */ + register cab_ULONG b; /* bit buffer */ + register cab_ULONG k; /* number of bits in bit buffer */ + + /* make local copies of globals */ + b = ZIP(bb); /* initialize bit buffer */ + k = ZIP(bk); + w = ZIP(window_posn); /* initialize window position */ + + /* go to byte boundary */ + n = k & 7; + ZIPDUMPBITS(n); + + /* get the length and its complement */ + ZIPNEEDBITS(16) + n = ((cab_ULONG)b & 0xffff); + ZIPDUMPBITS(16) + ZIPNEEDBITS(16) + if (n != (cab_ULONG)((~b) & 0xffff)) + return 1; /* error in compressed data */ + ZIPDUMPBITS(16) + + /* read and output the compressed data */ + while(n--) + { + ZIPNEEDBITS(8) + CAB(outbuf)[w++] = (cab_UBYTE)b; + ZIPDUMPBITS(8) + } + + /* restore the globals from the locals */ + ZIP(window_posn) = w; /* restore global window pointer */ + ZIP(bb) = b; /* restore global bit buffer */ + ZIP(bk) = k; + return 0; +} + +/****************************************************** + * fdi_Zipinflate_fixed (internal) + */ +cab_LONG fdi_Zipinflate_fixed(fdi_decomp_state *decomp_state) +{ + struct Ziphuft *fixed_tl; + struct Ziphuft *fixed_td; + cab_LONG fixed_bl, fixed_bd; + cab_LONG i; /* temporary variable */ + cab_ULONG *l; + + l = ZIP(ll); + + /* literal table */ + for(i = 0; i < 144; i++) + l[i] = 8; + for(; i < 256; i++) + l[i] = 9; + for(; i < 280; i++) + l[i] = 7; + for(; i < 288; i++) /* make a complete, but wrong code set */ + l[i] = 8; + fixed_bl = 7; + if((i = fdi_Ziphuft_build(l, 288, 257, (cab_UWORD *) Zipcplens, + (cab_UWORD *) Zipcplext, &fixed_tl, &fixed_bl, decomp_state))) + return i; + + /* distance table */ + for(i = 0; i < 30; i++) /* make an incomplete code set */ + l[i] = 5; + fixed_bd = 5; + if((i = fdi_Ziphuft_build(l, 30, 0, (cab_UWORD *) Zipcpdist, (cab_UWORD *) Zipcpdext, + &fixed_td, &fixed_bd, decomp_state)) > 1) + { + fdi_Ziphuft_free(CAB(hfdi), fixed_tl); + return i; + } + + /* decompress until an end-of-block code */ + i = fdi_Zipinflate_codes(fixed_tl, fixed_td, fixed_bl, fixed_bd, decomp_state); + + fdi_Ziphuft_free(CAB(hfdi), fixed_td); + fdi_Ziphuft_free(CAB(hfdi), fixed_tl); + return i; +} + +/************************************************************** + * fdi_Zipinflate_dynamic (internal) + */ +cab_LONG fdi_Zipinflate_dynamic(fdi_decomp_state *decomp_state) + /* decompress an inflated type 2 (dynamic Huffman codes) block. */ +{ + cab_LONG i; /* temporary variables */ + cab_ULONG j; + cab_ULONG *ll; + cab_ULONG l; /* last length */ + cab_ULONG m; /* mask for bit lengths table */ + cab_ULONG n; /* number of lengths to get */ + struct Ziphuft *tl; /* literal/length code table */ + struct Ziphuft *td; /* distance code table */ + cab_LONG bl; /* lookup bits for tl */ + cab_LONG bd; /* lookup bits for td */ + cab_ULONG nb; /* number of bit length codes */ + cab_ULONG nl; /* number of literal/length codes */ + cab_ULONG nd; /* number of distance codes */ + register cab_ULONG b; /* bit buffer */ + register cab_ULONG k; /* number of bits in bit buffer */ + + /* make local bit buffer */ + b = ZIP(bb); + k = ZIP(bk); + ll = ZIP(ll); + + /* read in table lengths */ + ZIPNEEDBITS(5) + nl = 257 + ((cab_ULONG)b & 0x1f); /* number of literal/length codes */ + ZIPDUMPBITS(5) + ZIPNEEDBITS(5) + nd = 1 + ((cab_ULONG)b & 0x1f); /* number of distance codes */ + ZIPDUMPBITS(5) + ZIPNEEDBITS(4) + nb = 4 + ((cab_ULONG)b & 0xf); /* number of bit length codes */ + ZIPDUMPBITS(4) + if(nl > 288 || nd > 32) + return 1; /* bad lengths */ + + /* read in bit-length-code lengths */ + for(j = 0; j < nb; j++) + { + ZIPNEEDBITS(3) + ll[Zipborder[j]] = (cab_ULONG)b & 7; + ZIPDUMPBITS(3) + } + for(; j < 19; j++) + ll[Zipborder[j]] = 0; + + /* build decoding table for trees--single level, 7 bit lookup */ + bl = 7; + if((i = fdi_Ziphuft_build(ll, 19, 19, NULL, NULL, &tl, &bl, decomp_state)) != 0) + { + if(i == 1) + fdi_Ziphuft_free(CAB(hfdi), tl); + return i; /* incomplete code set */ + } + + /* read in literal and distance code lengths */ + n = nl + nd; + m = Zipmask[bl]; + i = l = 0; + while((cab_ULONG)i < n) + { + ZIPNEEDBITS((cab_ULONG)bl) + j = (td = tl + ((cab_ULONG)b & m))->b; + ZIPDUMPBITS(j) + j = td->v.n; + if (j < 16) /* length of code in bits (0..15) */ + ll[i++] = l = j; /* save last length in l */ + else if (j == 16) /* repeat last length 3 to 6 times */ + { + ZIPNEEDBITS(2) + j = 3 + ((cab_ULONG)b & 3); + ZIPDUMPBITS(2) + if((cab_ULONG)i + j > n) + return 1; + while (j--) + ll[i++] = l; + } + else if (j == 17) /* 3 to 10 zero length codes */ + { + ZIPNEEDBITS(3) + j = 3 + ((cab_ULONG)b & 7); + ZIPDUMPBITS(3) + if ((cab_ULONG)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + else /* j == 18: 11 to 138 zero length codes */ + { + ZIPNEEDBITS(7) + j = 11 + ((cab_ULONG)b & 0x7f); + ZIPDUMPBITS(7) + if ((cab_ULONG)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + } + + /* free decoding table for trees */ + fdi_Ziphuft_free(CAB(hfdi), tl); + + /* restore the global bit buffer */ + ZIP(bb) = b; + ZIP(bk) = k; + + /* build the decoding tables for literal/length and distance codes */ + bl = ZIPLBITS; + if((i = fdi_Ziphuft_build(ll, nl, 257, (cab_UWORD *) Zipcplens, (cab_UWORD *) Zipcplext, + &tl, &bl, decomp_state)) != 0) + { + if(i == 1) + fdi_Ziphuft_free(CAB(hfdi), tl); + return i; /* incomplete code set */ + } + bd = ZIPDBITS; + fdi_Ziphuft_build(ll + nl, nd, 0, (cab_UWORD *) Zipcpdist, (cab_UWORD *) Zipcpdext, + &td, &bd, decomp_state); + + /* decompress until an end-of-block code */ + if(fdi_Zipinflate_codes(tl, td, bl, bd, decomp_state)) + return 1; + + /* free the decoding tables, return */ + fdi_Ziphuft_free(CAB(hfdi), tl); + fdi_Ziphuft_free(CAB(hfdi), td); + return 0; +} + +/***************************************************** + * fdi_Zipinflate_block (internal) + */ +cab_LONG fdi_Zipinflate_block(cab_LONG *e, fdi_decomp_state *decomp_state) /* e == last block flag */ +{ /* decompress an inflated block */ + cab_ULONG t; /* block type */ + register cab_ULONG b; /* bit buffer */ + register cab_ULONG k; /* number of bits in bit buffer */ + + /* make local bit buffer */ + b = ZIP(bb); + k = ZIP(bk); + + /* read in last block bit */ + ZIPNEEDBITS(1) + *e = (cab_LONG)b & 1; + ZIPDUMPBITS(1) + + /* read in block type */ + ZIPNEEDBITS(2) + t = (cab_ULONG)b & 3; + ZIPDUMPBITS(2) + + /* restore the global bit buffer */ + ZIP(bb) = b; + ZIP(bk) = k; + + /* inflate that block type */ + if(t == 2) + return fdi_Zipinflate_dynamic(decomp_state); + if(t == 0) + return fdi_Zipinflate_stored(decomp_state); + if(t == 1) + return fdi_Zipinflate_fixed(decomp_state); + /* bad block type */ + return 2; +} + +/**************************************************** + * ZIPfdi_decomp(internal) + */ +int ZIPfdi_decomp(int inlen, int outlen, fdi_decomp_state *decomp_state) +{ + cab_LONG e; /* last block flag */ + + TRACE("(inlen == %d, outlen == %d)\n", inlen, outlen); + + ZIP(inpos) = CAB(inbuf); + ZIP(bb) = ZIP(bk) = ZIP(window_posn) = 0; + if(outlen > ZIPWSIZE) + return DECR_DATAFORMAT; + + /* CK = Chris Kirmse, official Microsoft purloiner */ + if(ZIP(inpos)[0] != 0x43 || ZIP(inpos)[1] != 0x4B) + return DECR_ILLEGALDATA; + ZIP(inpos) += 2; + + do { + if(fdi_Zipinflate_block(&e, decomp_state)) + return DECR_ILLEGALDATA; + } while(!e); + + /* return success */ + return DECR_OK; +} + +/******************************************************************* + * QTMfdi_decomp(internal) + */ +int QTMfdi_decomp(int inlen, int outlen, fdi_decomp_state *decomp_state) +{ + cab_UBYTE *inpos = CAB(inbuf); + cab_UBYTE *window = QTM(window); + cab_UBYTE *runsrc, *rundest; + + cab_ULONG window_posn = QTM(window_posn); + cab_ULONG window_size = QTM(window_size); + + /* used by bitstream macros */ + register int bitsleft, bitrun, bitsneed; + register cab_ULONG bitbuf; + + /* used by GET_SYMBOL */ + cab_ULONG range; + cab_UWORD symf; + int i; + + int extra, togo = outlen, match_length = 0, copy_length; + cab_UBYTE selector, sym; + cab_ULONG match_offset = 0; + + cab_UWORD H = 0xFFFF, L = 0, C; + + TRACE("(inlen == %d, outlen == %d)\n", inlen, outlen); + + /* read initial value of C */ + Q_INIT_BITSTREAM; + Q_READ_BITS(C, 16); + + /* apply 2^x-1 mask */ + window_posn &= window_size - 1; + /* runs can't straddle the window wraparound */ + if ((window_posn + togo) > window_size) { + TRACE("straddled run\n"); + return DECR_DATAFORMAT; + } + + while (togo > 0) { + GET_SYMBOL(model7, selector); + switch (selector) { + case 0: + GET_SYMBOL(model00, sym); window[window_posn++] = sym; togo--; + break; + case 1: + GET_SYMBOL(model40, sym); window[window_posn++] = sym; togo--; + break; + case 2: + GET_SYMBOL(model80, sym); window[window_posn++] = sym; togo--; + break; + case 3: + GET_SYMBOL(modelC0, sym); window[window_posn++] = sym; togo--; + break; + + case 4: + /* selector 4 = fixed length of 3 */ + GET_SYMBOL(model4, sym); + Q_READ_BITS(extra, CAB(q_extra_bits)[sym]); + match_offset = CAB(q_position_base)[sym] + extra + 1; + match_length = 3; + break; + + case 5: + /* selector 5 = fixed length of 4 */ + GET_SYMBOL(model5, sym); + Q_READ_BITS(extra, CAB(q_extra_bits)[sym]); + match_offset = CAB(q_position_base)[sym] + extra + 1; + match_length = 4; + break; + + case 6: + /* selector 6 = variable length */ + GET_SYMBOL(model6len, sym); + Q_READ_BITS(extra, CAB(q_length_extra)[sym]); + match_length = CAB(q_length_base)[sym] + extra + 5; + GET_SYMBOL(model6pos, sym); + Q_READ_BITS(extra, CAB(q_extra_bits)[sym]); + match_offset = CAB(q_position_base)[sym] + extra + 1; + break; + + default: + TRACE("Selector is bogus\n"); + return DECR_ILLEGALDATA; + } + + /* if this is a match */ + if (selector >= 4) { + rundest = window + window_posn; + togo -= match_length; + + /* copy any wrapped around source data */ + if (window_posn >= match_offset) { + /* no wrap */ + runsrc = rundest - match_offset; + } else { + runsrc = rundest + (window_size - match_offset); + copy_length = match_offset - window_posn; + if (copy_length < match_length) { + match_length -= copy_length; + window_posn += copy_length; + while (copy_length-- > 0) *rundest++ = *runsrc++; + runsrc = window; + } + } + window_posn += match_length; + + /* copy match data - no worries about destination wraps */ + while (match_length-- > 0) *rundest++ = *runsrc++; + } + } /* while (togo > 0) */ + + if (togo != 0) { + TRACE("Frame overflow, this_run = %d\n", togo); + return DECR_ILLEGALDATA; + } + + memcpy(CAB(outbuf), window + ((!window_posn) ? window_size : window_posn) - + outlen, outlen); + + QTM(window_posn) = window_posn; + return DECR_OK; +} + +/************************************************************ + * fdi_lzx_read_lens (internal) + */ +int fdi_lzx_read_lens(cab_UBYTE *lens, cab_ULONG first, cab_ULONG last, struct lzx_bits *lb, + fdi_decomp_state *decomp_state) { + cab_ULONG i,j, x,y; + int z; + + register cab_ULONG bitbuf = lb->bb; + register int bitsleft = lb->bl; + cab_UBYTE *inpos = lb->ip; + cab_UWORD *hufftbl; + + for (x = 0; x < 20; x++) { + READ_BITS(y, 4); + LENTABLE(PRETREE)[x] = y; + } + BUILD_TABLE(PRETREE); + + for (x = first; x < last; ) { + READ_HUFFSYM(PRETREE, z); + if (z == 17) { + READ_BITS(y, 4); y += 4; + while (y--) lens[x++] = 0; + } + else if (z == 18) { + READ_BITS(y, 5); y += 20; + while (y--) lens[x++] = 0; + } + else if (z == 19) { + READ_BITS(y, 1); y += 4; + READ_HUFFSYM(PRETREE, z); + z = lens[x] - z; if (z < 0) z += 17; + while (y--) lens[x++] = z; + } + else { + z = lens[x] - z; if (z < 0) z += 17; + lens[x++] = z; + } + } + + lb->bb = bitbuf; + lb->bl = bitsleft; + lb->ip = inpos; + return 0; +} + +/******************************************************* + * LZXfdi_decomp(internal) + */ +int LZXfdi_decomp(int inlen, int outlen, fdi_decomp_state *decomp_state) { + cab_UBYTE *inpos = CAB(inbuf); + cab_UBYTE *endinp = inpos + inlen; + cab_UBYTE *window = LZX(window); + cab_UBYTE *runsrc, *rundest; + cab_UWORD *hufftbl; /* used in READ_HUFFSYM macro as chosen decoding table */ + + cab_ULONG window_posn = LZX(window_posn); + cab_ULONG window_size = LZX(window_size); + cab_ULONG R0 = LZX(R0); + cab_ULONG R1 = LZX(R1); + cab_ULONG R2 = LZX(R2); + + register cab_ULONG bitbuf; + register int bitsleft; + cab_ULONG match_offset, i,j,k; /* ijk used in READ_HUFFSYM macro */ + struct lzx_bits lb; /* used in READ_LENGTHS macro */ + + int togo = outlen, this_run, main_element, aligned_bits; + int match_length, copy_length, length_footer, extra, verbatim_bits; + + TRACE("(inlen == %d, outlen == %d)\n", inlen, outlen); + + INIT_BITSTREAM; + + /* read header if necessary */ + if (!LZX(header_read)) { + i = j = 0; + READ_BITS(k, 1); if (k) { READ_BITS(i,16); READ_BITS(j,16); } + LZX(intel_filesize) = (i << 16) | j; /* or 0 if not encoded */ + LZX(header_read) = 1; + } + + /* main decoding loop */ + while (togo > 0) { + /* last block finished, new block expected */ + if (LZX(block_remaining) == 0) { + if (LZX(block_type) == LZX_BLOCKTYPE_UNCOMPRESSED) { + if (LZX(block_length) & 1) inpos++; /* realign bitstream to word */ + INIT_BITSTREAM; + } + + READ_BITS(LZX(block_type), 3); + READ_BITS(i, 16); + READ_BITS(j, 8); + LZX(block_remaining) = LZX(block_length) = (i << 8) | j; + + switch (LZX(block_type)) { + case LZX_BLOCKTYPE_ALIGNED: + for (i = 0; i < 8; i++) { READ_BITS(j, 3); LENTABLE(ALIGNED)[i] = j; } + BUILD_TABLE(ALIGNED); + /* rest of aligned header is same as verbatim */ + + case LZX_BLOCKTYPE_VERBATIM: + READ_LENGTHS(MAINTREE, 0, 256, fdi_lzx_read_lens); + READ_LENGTHS(MAINTREE, 256, LZX(main_elements), fdi_lzx_read_lens); + BUILD_TABLE(MAINTREE); + if (LENTABLE(MAINTREE)[0xE8] != 0) LZX(intel_started) = 1; + + READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS, fdi_lzx_read_lens); + BUILD_TABLE(LENGTH); + break; + + case LZX_BLOCKTYPE_UNCOMPRESSED: + LZX(intel_started) = 1; /* because we can't assume otherwise */ + ENSURE_BITS(16); /* get up to 16 pad bits into the buffer */ + if (bitsleft > 16) inpos -= 2; /* and align the bitstream! */ + R0 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4; + R1 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4; + R2 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4; + break; + + default: + return DECR_ILLEGALDATA; + } + } + + /* buffer exhaustion check */ + if (inpos > endinp) { + /* it's possible to have a file where the next run is less than + * 16 bits in size. In this case, the READ_HUFFSYM() macro used + * in building the tables will exhaust the buffer, so we should + * allow for this, but not allow those accidentally read bits to + * be used (so we check that there are at least 16 bits + * remaining - in this boundary case they aren't really part of + * the compressed data) + */ + if (inpos > (endinp+2) || bitsleft < 16) return DECR_ILLEGALDATA; + } + + while ((this_run = LZX(block_remaining)) > 0 && togo > 0) { + if (this_run > togo) this_run = togo; + togo -= this_run; + LZX(block_remaining) -= this_run; + + /* apply 2^x-1 mask */ + window_posn &= window_size - 1; + /* runs can't straddle the window wraparound */ + if ((window_posn + this_run) > window_size) + return DECR_DATAFORMAT; + + switch (LZX(block_type)) { + + case LZX_BLOCKTYPE_VERBATIM: + while (this_run > 0) { + READ_HUFFSYM(MAINTREE, main_element); + + if (main_element < LZX_NUM_CHARS) { + /* literal: 0 to LZX_NUM_CHARS-1 */ + window[window_posn++] = main_element; + this_run--; + } + else { + /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */ + main_element -= LZX_NUM_CHARS; + + match_length = main_element & LZX_NUM_PRIMARY_LENGTHS; + if (match_length == LZX_NUM_PRIMARY_LENGTHS) { + READ_HUFFSYM(LENGTH, length_footer); + match_length += length_footer; + } + match_length += LZX_MIN_MATCH; + + match_offset = main_element >> 3; + + if (match_offset > 2) { + /* not repeated offset */ + if (match_offset != 3) { + extra = CAB(extra_bits)[match_offset]; + READ_BITS(verbatim_bits, extra); + match_offset = CAB(lzx_position_base)[match_offset] + - 2 + verbatim_bits; + } + else { + match_offset = 1; + } + + /* update repeated offset LRU queue */ + R2 = R1; R1 = R0; R0 = match_offset; + } + else if (match_offset == 0) { + match_offset = R0; + } + else if (match_offset == 1) { + match_offset = R1; + R1 = R0; R0 = match_offset; + } + else /* match_offset == 2 */ { + match_offset = R2; + R2 = R0; R0 = match_offset; + } + + rundest = window + window_posn; + this_run -= match_length; + + /* copy any wrapped around source data */ + if (window_posn >= match_offset) { + /* no wrap */ + runsrc = rundest - match_offset; + } else { + runsrc = rundest + (window_size - match_offset); + copy_length = match_offset - window_posn; + if (copy_length < match_length) { + match_length -= copy_length; + window_posn += copy_length; + while (copy_length-- > 0) *rundest++ = *runsrc++; + runsrc = window; + } + } + window_posn += match_length; + + /* copy match data - no worries about destination wraps */ + while (match_length-- > 0) *rundest++ = *runsrc++; + } + } + break; + + case LZX_BLOCKTYPE_ALIGNED: + while (this_run > 0) { + READ_HUFFSYM(MAINTREE, main_element); + + if (main_element < LZX_NUM_CHARS) { + /* literal: 0 to LZX_NUM_CHARS-1 */ + window[window_posn++] = main_element; + this_run--; + } + else { + /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */ + main_element -= LZX_NUM_CHARS; + + match_length = main_element & LZX_NUM_PRIMARY_LENGTHS; + if (match_length == LZX_NUM_PRIMARY_LENGTHS) { + READ_HUFFSYM(LENGTH, length_footer); + match_length += length_footer; + } + match_length += LZX_MIN_MATCH; + + match_offset = main_element >> 3; + + if (match_offset > 2) { + /* not repeated offset */ + extra = CAB(extra_bits)[match_offset]; + match_offset = CAB(lzx_position_base)[match_offset] - 2; + if (extra > 3) { + /* verbatim and aligned bits */ + extra -= 3; + READ_BITS(verbatim_bits, extra); + match_offset += (verbatim_bits << 3); + READ_HUFFSYM(ALIGNED, aligned_bits); + match_offset += aligned_bits; + } + else if (extra == 3) { + /* aligned bits only */ + READ_HUFFSYM(ALIGNED, aligned_bits); + match_offset += aligned_bits; + } + else if (extra > 0) { /* extra==1, extra==2 */ + /* verbatim bits only */ + READ_BITS(verbatim_bits, extra); + match_offset += verbatim_bits; + } + else /* extra == 0 */ { + /* ??? */ + match_offset = 1; + } + + /* update repeated offset LRU queue */ + R2 = R1; R1 = R0; R0 = match_offset; + } + else if (match_offset == 0) { + match_offset = R0; + } + else if (match_offset == 1) { + match_offset = R1; + R1 = R0; R0 = match_offset; + } + else /* match_offset == 2 */ { + match_offset = R2; + R2 = R0; R0 = match_offset; + } + + rundest = window + window_posn; + this_run -= match_length; + + /* copy any wrapped around source data */ + if (window_posn >= match_offset) { + /* no wrap */ + runsrc = rundest - match_offset; + } else { + runsrc = rundest + (window_size - match_offset); + copy_length = match_offset - window_posn; + if (copy_length < match_length) { + match_length -= copy_length; + window_posn += copy_length; + while (copy_length-- > 0) *rundest++ = *runsrc++; + runsrc = window; + } + } + window_posn += match_length; + + /* copy match data - no worries about destination wraps */ + while (match_length-- > 0) *rundest++ = *runsrc++; + } + } + break; + + case LZX_BLOCKTYPE_UNCOMPRESSED: + if ((inpos + this_run) > endinp) return DECR_ILLEGALDATA; + memcpy(window + window_posn, inpos, (size_t) this_run); + inpos += this_run; window_posn += this_run; + break; + + default: + return DECR_ILLEGALDATA; /* might as well */ + } + + } + } + + if (togo != 0) return DECR_ILLEGALDATA; + memcpy(CAB(outbuf), window + ((!window_posn) ? window_size : window_posn) - + outlen, (size_t) outlen); + + LZX(window_posn) = window_posn; + LZX(R0) = R0; + LZX(R1) = R1; + LZX(R2) = R2; + + /* intel E8 decoding */ + if ((LZX(frames_read)++ < 32768) && LZX(intel_filesize) != 0) { + if (outlen <= 6 || !LZX(intel_started)) { + LZX(intel_curpos) += outlen; + } + else { + cab_UBYTE *data = CAB(outbuf); + cab_UBYTE *dataend = data + outlen - 10; + cab_LONG curpos = LZX(intel_curpos); + cab_LONG filesize = LZX(intel_filesize); + cab_LONG abs_off, rel_off; + + LZX(intel_curpos) = curpos + outlen; + + while (data < dataend) { + if (*data++ != 0xE8) { curpos++; continue; } + abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24); + if ((abs_off >= -curpos) && (abs_off < filesize)) { + rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize; + data[0] = (cab_UBYTE) rel_off; + data[1] = (cab_UBYTE) (rel_off >> 8); + data[2] = (cab_UBYTE) (rel_off >> 16); + data[3] = (cab_UBYTE) (rel_off >> 24); + } + data += 4; + curpos += 5; + } + } + } + return DECR_OK; +} + +/********************************************************** + * fdi_decomp (internal) + * + * Decompress the requested number of bytes. If savemode is zero, + * do not save the output anywhere, just plow through blocks until we + * reach the specified (uncompressed) distance from the starting point, + * and remember the position of the cabfile pointer (and which cabfile) + * after we are done; otherwise, save the data out to CAB(filehf), + * decompressing the requested number of bytes and writing them out. This + * is also where we jump to additional cabinets in the case of split + * cab's, and provide (some of) the NEXT_CABINET notification semantics. + */ +int fdi_decomp(struct fdi_file *fi, int savemode, fdi_decomp_state *decomp_state, + char *pszCabPath, PFNFDINOTIFY pfnfdin, void *pvUser) +{ + cab_ULONG bytes = savemode ? fi->length : fi->offset - CAB(offset); + cab_UBYTE buf[cfdata_SIZEOF], *data; + cab_UWORD inlen, len, outlen, cando; + cab_ULONG cksum; + cab_LONG err; + fdi_decomp_state *cab = (savemode && CAB(decomp_cab)) ? CAB(decomp_cab) : decomp_state; + + TRACE("(fi == ^%p, savemode == %d, bytes == %d)\n", fi, savemode, bytes); + + while (bytes > 0) { + /* cando = the max number of bytes we can do */ + cando = CAB(outlen); + if (cando > bytes) cando = bytes; + + /* if cando != 0 */ + if (cando && savemode) + PFDI_WRITE(CAB(hfdi), CAB(filehf), CAB(outpos), cando); + + CAB(outpos) += cando; + CAB(outlen) -= cando; + bytes -= cando; if (!bytes) break; + + /* we only get here if we emptied the output buffer */ + + /* read data header + data */ + inlen = outlen = 0; + while (outlen == 0) { + /* read the block header, skip the reserved part */ + if (PFDI_READ(CAB(hfdi), cab->cabhf, buf, cfdata_SIZEOF) != cfdata_SIZEOF) + return DECR_INPUT; + + if (PFDI_SEEK(CAB(hfdi), cab->cabhf, cab->mii.block_resv, SEEK_CUR) == -1) + return DECR_INPUT; + + /* we shouldn't get blocks over CAB_INPUTMAX in size */ + data = CAB(inbuf) + inlen; + len = EndGetI16(buf+cfdata_CompressedSize); + inlen += len; + if (inlen > CAB_INPUTMAX) return DECR_INPUT; + if (PFDI_READ(CAB(hfdi), cab->cabhf, data, len) != len) + return DECR_INPUT; + + /* clear two bytes after read-in data */ + data[len+1] = data[len+2] = 0; + + /* perform checksum test on the block (if one is stored) */ + cksum = EndGetI32(buf+cfdata_CheckSum); + if (cksum && cksum != checksum(buf+4, 4, checksum(data, len, 0))) + return DECR_CHECKSUM; /* checksum is wrong */ + + outlen = EndGetI16(buf+cfdata_UncompressedSize); + + /* outlen=0 means this block was the last contiguous part + of a split block, continued in the next cabinet */ + if (outlen == 0) { + int pathlen, filenamelen, idx, i, cabhf; + char fullpath[MAX_PATH], userpath[256]; + FDINOTIFICATION fdin; + FDICABINETINFO fdici; + char emptystring = '\0'; + cab_UBYTE buf2[64]; + int success = FALSE; + struct fdi_folder *fol = NULL, *linkfol = NULL; + struct fdi_file *file = NULL, *linkfile = NULL; + + tryanothercab: + + /* set up the next decomp_state... */ + if (!(cab->next)) { + if (!cab->mii.hasnext) return DECR_INPUT; + + if (!((cab->next = PFDI_ALLOC(CAB(hfdi), sizeof(fdi_decomp_state))))) + return DECR_NOMEMORY; + + ZeroMemory(cab->next, sizeof(fdi_decomp_state)); + + /* copy pszCabPath to userpath */ + ZeroMemory(userpath, 256); + pathlen = (pszCabPath) ? strlen(pszCabPath) : 0; + if (pathlen) { + if (pathlen < 256) { + for (i = 0; i <= pathlen; i++) + userpath[i] = pszCabPath[i]; + } /* else we are in a weird place... let's leave it blank and see if the user fixes it */ + } + + /* initial fdintNEXT_CABINET notification */ + ZeroMemory(&fdin, sizeof(FDINOTIFICATION)); + fdin.psz1 = (cab->mii.nextname) ? cab->mii.nextname : &emptystring; + fdin.psz2 = (cab->mii.nextinfo) ? cab->mii.nextinfo : &emptystring; + fdin.psz3 = &userpath[0]; + fdin.fdie = FDIERROR_NONE; + fdin.pv = pvUser; + + if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT; + + do { + + pathlen = (userpath) ? strlen(userpath) : 0; + filenamelen = (cab->mii.nextname) ? strlen(cab->mii.nextname) : 0; + + /* slight overestimation here to save CPU cycles in the developer's brain */ + if ((pathlen + filenamelen + 3) > MAX_PATH) { + ERR("MAX_PATH exceeded.\n"); + return DECR_ILLEGALDATA; + } + + /* paste the path and filename together */ + idx = 0; + if (pathlen) { + for (i = 0; i < pathlen; i++) fullpath[idx++] = userpath[i]; + if (fullpath[idx - 1] != '\\') fullpath[idx++] = '\\'; + } + if (filenamelen) for (i = 0; i < filenamelen; i++) fullpath[idx++] = cab->mii.nextname[i]; + fullpath[idx] = '\0'; + + TRACE("full cab path/file name: %s\n", debugstr_a(fullpath)); + + /* try to get a handle to the cabfile */ + cabhf = PFDI_OPEN(CAB(hfdi), fullpath, 32768, _S_IREAD | _S_IWRITE); + if (cabhf == -1) { + /* no file. allow the user to try again */ + fdin.fdie = FDIERROR_CABINET_NOT_FOUND; + if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT; + continue; + } + + if (cabhf == 0) { + ERR("PFDI_OPEN returned zero for %s.\n", fullpath); + fdin.fdie = FDIERROR_CABINET_NOT_FOUND; + if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT; + continue; + } + + /* check if it's really a cabfile. Note that this doesn't implement the bug */ + if (!FDI_read_entries(CAB(hfdi), cabhf, &fdici, &(cab->next->mii))) { + WARN("FDIIsCabinet failed.\n"); + PFDI_CLOSE(CAB(hfdi), cabhf); + fdin.fdie = FDIERROR_NOT_A_CABINET; + if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT; + continue; + } + + if ((fdici.setID != cab->setID) || (fdici.iCabinet != (cab->iCabinet + 1))) { + WARN("Wrong Cabinet.\n"); + PFDI_CLOSE(CAB(hfdi), cabhf); + fdin.fdie = FDIERROR_WRONG_CABINET; + if (((*pfnfdin)(fdintNEXT_CABINET, &fdin))) return DECR_USERABORT; + continue; + } + + break; + + } while (1); + + /* cabinet notification */ + ZeroMemory(&fdin, sizeof(FDINOTIFICATION)); + fdin.setID = fdici.setID; + fdin.iCabinet = fdici.iCabinet; + fdin.pv = pvUser; + fdin.psz1 = (cab->next->mii.nextname) ? cab->next->mii.nextname : &emptystring; + fdin.psz2 = (cab->next->mii.nextinfo) ? cab->next->mii.nextinfo : &emptystring; + fdin.psz3 = pszCabPath; + + if (((*pfnfdin)(fdintCABINET_INFO, &fdin))) return DECR_USERABORT; + + cab->next->setID = fdici.setID; + cab->next->iCabinet = fdici.iCabinet; + cab->next->hfdi = CAB(hfdi); + cab->next->filehf = CAB(filehf); + cab->next->cabhf = cabhf; + cab->next->decompress = CAB(decompress); /* crude, but unused anyhow */ + + cab = cab->next; /* advance to the next cabinet */ + + /* read folders */ + for (i = 0; i < fdici.cFolders; i++) { + if (PFDI_READ(CAB(hfdi), cab->cabhf, buf2, cffold_SIZEOF) != cffold_SIZEOF) + return DECR_INPUT; + + if (cab->mii.folder_resv > 0) + PFDI_SEEK(CAB(hfdi), cab->cabhf, cab->mii.folder_resv, SEEK_CUR); + + fol = (struct fdi_folder *) PFDI_ALLOC(CAB(hfdi), sizeof(struct fdi_folder)); + if (!fol) { + ERR("out of memory!\n"); + return DECR_NOMEMORY; + } + ZeroMemory(fol, sizeof(struct fdi_folder)); + if (!(cab->firstfol)) cab->firstfol = fol; + + fol->offset = (cab_off_t) EndGetI32(buf2+cffold_DataOffset); + fol->num_blocks = EndGetI16(buf2+cffold_NumBlocks); + fol->comp_type = EndGetI16(buf2+cffold_CompType); + + if (linkfol) + linkfol->next = fol; + linkfol = fol; + } + + /* read files */ + for (i = 0; i < fdici.cFiles; i++) { + if (PFDI_READ(CAB(hfdi), cab->cabhf, buf2, cffile_SIZEOF) != cffile_SIZEOF) + return DECR_INPUT; + + file = (struct fdi_file *) PFDI_ALLOC(CAB(hfdi), sizeof(struct fdi_file)); + if (!file) { + ERR("out of memory!\n"); + return DECR_NOMEMORY; + } + ZeroMemory(file, sizeof(struct fdi_file)); + if (!(cab->firstfile)) cab->firstfile = file; + + file->length = EndGetI32(buf2+cffile_UncompressedSize); + file->offset = EndGetI32(buf2+cffile_FolderOffset); + file->index = EndGetI16(buf2+cffile_FolderIndex); + file->time = EndGetI16(buf2+cffile_Time); + file->date = EndGetI16(buf2+cffile_Date); + file->attribs = EndGetI16(buf2+cffile_Attribs); + file->filename = FDI_read_string(CAB(hfdi), cab->cabhf, fdici.cbCabinet); + + if (!file->filename) return DECR_INPUT; + + if (linkfile) + linkfile->next = file; + linkfile = file; + } + + } else + cab = cab->next; /* advance to the next cabinet */ + + /* iterate files -- if we encounter the continued file, process it -- + otherwise, jump to the label above and keep looking */ + + for (file = cab->firstfile; (file); file = file->next) { + if ((file->index & cffileCONTINUED_FROM_PREV) == cffileCONTINUED_FROM_PREV) { + /* check to ensure a real match */ + if (strcasecmp(fi->filename, file->filename) == 0) { + success = TRUE; + if (PFDI_SEEK(CAB(hfdi), cab->cabhf, cab->firstfol->offset, SEEK_SET) == -1) + return DECR_INPUT; + break; + } + } + } + if (!success) goto tryanothercab; /* FIXME: shouldn't this trigger + "Wrong Cabinet" notification? */ + } + } + + /* decompress block */ + if ((err = CAB(decompress)(inlen, outlen, decomp_state))) + return err; + CAB(outlen) = outlen; + CAB(outpos) = CAB(outbuf); + } + + CAB(decomp_cab) = cab; + return DECR_OK; +} + +/*********************************************************************** + * FDICopy (CABINET.22) + * + * Iterates through the files in the Cabinet file indicated by name and + * file-location. May chain forward to additional cabinets (typically + * only one) if files which begin in this Cabinet are continued in another + * cabinet. For each file which is partially contained in this cabinet, + * and partially contained in a prior cabinet, provides fdintPARTIAL_FILE + * notification to the pfnfdin callback. For each file which begins in + * this cabinet, fdintCOPY_FILE notification is provided to the pfnfdin + * callback, and the file is optionally decompressed and saved to disk. + * Notification is not provided for files which are not at least partially + * contained in the specified cabinet file. + * + * See below for a thorough explanation of the various notification + * callbacks. + * + * PARAMS + * hfdi [I] An HFDI from FDICreate + * pszCabinet [I] C-style string containing the filename of the cabinet + * pszCabPath [I] C-style string containing the file path of the cabinet + * flags [I] "Decoder parameters". Ignored. Suggested value: 0. + * pfnfdin [I] Pointer to a notification function. See CALLBACKS below. + * pfnfdid [I] Pointer to a decryption function. Ignored. Suggested + * value: NULL. + * pvUser [I] arbitrary void * value which is passed to callbacks. + * + * RETURNS + * TRUE if successful. + * FALSE if unsuccessful (error information is provided in the ERF structure + * associated with the provided decompression handle by FDICreate). + * + * CALLBACKS + * + * Two pointers to callback functions are provided as parameters to FDICopy: + * pfnfdin(of type PFNFDINOTIFY), and pfnfdid (of type PFNFDIDECRYPT). These + * types are as follows: + * + * typedef INT_PTR (__cdecl *PFNFDINOTIFY) ( FDINOTIFICATIONTYPE fdint, + * PFDINOTIFICATION pfdin ); + * + * typedef int (__cdecl *PFNFDIDECRYPT) ( PFDIDECRYPT pfdid ); + * + * You can create functions of this type using the FNFDINOTIFY() and + * FNFDIDECRYPT() macros, respectively. For example: + * + * FNFDINOTIFY(mycallback) { + * / * use variables fdint and pfdin to process notification * / + * } + * + * The second callback, which could be used for decrypting encrypted data, + * is not used at all. + * + * Each notification informs the user of some event which has occurred during + * decompression of the cabinet file; each notification is also an opportunity + * for the callee to abort decompression. The information provided to the + * callback and the meaning of the callback's return value vary drastically + * across the various types of notification. The type of notification is the + * fdint parameter; all other information is provided to the callback in + * notification-specific parts of the FDINOTIFICATION structure pointed to by + * pfdin. The only part of that structure which is assigned for every callback + * is the pv element, which contains the arbitrary value which was passed to + * FDICopy in the pvUser argument (psz1 is also used each time, but its meaning + * is highly dependent on fdint). + * + * If you encounter unknown notifications, you should return zero if you want + * decompression to continue (or -1 to abort). All strings used in the + * callbacks are regular C-style strings. Detailed descriptions of each + * notification type follow: + * + * fdintCABINET_INFO: + * + * This is the first notification provided after calling FDICopy, and provides + * the user with various information about the cabinet. Note that this is + * called for each cabinet FDICopy opens, not just the first one. In the + * structure pointed to by pfdin, psz1 contains a pointer to the name of the + * next cabinet file in the set after the one just loaded (if any), psz2 + * contains a pointer to the name or "info" of the next disk, psz3 + * contains a pointer to the file-path of the current cabinet, setID + * contains an arbitrary constant associated with this set of cabinet files, + * and iCabinet contains the numerical index of the current cabinet within + * that set. Return zero, or -1 to abort. + * + * fdintPARTIAL_FILE: + * + * This notification is provided when FDICopy encounters a part of a file + * contained in this cabinet which is missing its beginning. Files can be + * split across cabinets, so this is not necessarily an abnormality; it just + * means that the file in question begins in another cabinet. No file + * corresponding to this notification is extracted from the cabinet. In the + * structure pointed to by pfdin, psz1 contains a pointer to the name of the + * partial file, psz2 contains a pointer to the file name of the cabinet in + * which this file begins, and psz3 contains a pointer to the disk name or + * "info" of the cabinet where the file begins. Return zero, or -1 to abort. + * + * fdintCOPY_FILE: + * + * This notification is provided when FDICopy encounters a file which starts + * in the cabinet file, provided to FDICopy in pszCabinet. (FDICopy will not + * look for files in cabinets after the first one). One notification will be + * sent for each such file, before the file is decompressed. By returning + * zero, the callback can instruct FDICopy to skip the file. In the structure + * pointed to by pfdin, psz1 contains a pointer to the file's name, cb contains + * the size of the file (uncompressed), attribs contains the file attributes, + * and date and time contain the date and time of the file. attributes, date, + * and time are of the 16-bit ms-dos variety. Return -1 to abort decompression + * for the entire cabinet, 0 to skip just this file but continue scanning the + * cabinet for more files, or an FDIClose()-compatible file-handle. + * + * fdintCLOSE_FILE_INFO: + * + * This notification is important, don't forget to implement it. This + * notification indicates that a file has been successfully uncompressed and + * written to disk. Upon receipt of this notification, the callee is expected + * to close the file handle, to set the attributes and date/time of the + * closed file, and possibly to execute the file. In the structure pointed to + * by pfdin, psz1 contains a pointer to the name of the file, hf will be the + * open file handle (close it), cb contains 1 or zero, indicating respectively + * that the callee should or should not execute the file, and date, time + * and attributes will be set as in fdintCOPY_FILE. Bizarrely, the Cabinet SDK + * specifies that _A_EXEC will be xor'ed out of attributes! wine does not do + * do so. Return TRUE, or FALSE to abort decompression. + * + * fdintNEXT_CABINET: + * + * This notification is called when FDICopy must load in another cabinet. This + * can occur when a file's data is "split" across multiple cabinets. The + * callee has the opportunity to request that FDICopy look in a different file + * path for the specified cabinet file, by writing that data into a provided + * buffer (see below for more information). This notification will be received + * more than once per-cabinet in the instance that FDICopy failed to find a + * valid cabinet at the location specified by the first per-cabinet + * fdintNEXT_CABINET notification. In such instances, the fdie element of the + * structure pointed to by pfdin indicates the error which prevented FDICopy + * from proceeding successfully. Return zero to indicate success, or -1 to + * indicate failure and abort FDICopy. + * + * Upon receipt of this notification, the structure pointed to by pfdin will + * contain the following values: psz1 pointing to the name of the cabinet + * which FDICopy is attempting to open, psz2 pointing to the name ("info") of + * the next disk, psz3 pointing to the presumed file-location of the cabinet, + * and fdie containing either FDIERROR_NONE, or one of the following: + * + * FDIERROR_CABINET_NOT_FOUND, FDIERROR_NOT_A_CABINET, + * FDIERROR_UNKNOWN_CABINET_VERSION, FDIERROR_CORRUPT_CABINET, + * FDIERROR_BAD_COMPR_TYPE, FDIERROR_RESERVE_MISMATCH, and + * FDIERROR_WRONG_CABINET. + * + * The callee may choose to change the path where FDICopy will look for the + * cabinet after this notification. To do so, the caller may write the new + * pathname to the buffer pointed to by psz3, which is 256 characters in + * length, including the terminating null character, before returning zero. + * + * fdintENUMERATE: + * + * Undocumented and unimplemented in wine, this seems to be sent each time + * a cabinet is opened, along with the fdintCABINET_INFO notification. It + * probably has an interface similar to that of fdintCABINET_INFO; maybe this + * provides information about the current cabinet instead of the next one.... + * this is just a guess, it has not been looked at closely. + * + * INCLUDES + * fdi.c + */ +BOOL __cdecl FDICopy( + HFDI hfdi, + char *pszCabinet, + char *pszCabPath, + int flags, + PFNFDINOTIFY pfnfdin, + PFNFDIDECRYPT pfnfdid, + void *pvUser) +{ + FDICABINETINFO fdici; + FDINOTIFICATION fdin; + int cabhf, filehf, idx; + unsigned int i; + char fullpath[MAX_PATH]; + size_t pathlen, filenamelen; + char emptystring = '\0'; + cab_UBYTE buf[64]; + struct fdi_folder *fol = NULL, *linkfol = NULL; + struct fdi_file *file = NULL, *linkfile = NULL; + fdi_decomp_state _decomp_state; + fdi_decomp_state *decomp_state = &_decomp_state; + + TRACE("(hfdi == ^%p, pszCabinet == ^%p, pszCabPath == ^%p, flags == %0d, \ + pfnfdin == ^%p, pfnfdid == ^%p, pvUser == ^%p)\n", + hfdi, pszCabinet, pszCabPath, flags, pfnfdin, pfnfdid, pvUser); + + if (!REALLY_IS_FDI(hfdi)) { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + ZeroMemory(decomp_state, sizeof(fdi_decomp_state)); + + pathlen = (pszCabPath) ? strlen(pszCabPath) : 0; + filenamelen = (pszCabinet) ? strlen(pszCabinet) : 0; + + /* slight overestimation here to save CPU cycles in the developer's brain */ + if ((pathlen + filenamelen + 3) > MAX_PATH) { + ERR("MAX_PATH exceeded.\n"); + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CABINET_NOT_FOUND; + PFDI_INT(hfdi)->perf->erfType = ERROR_FILE_NOT_FOUND; + PFDI_INT(hfdi)->perf->fError = TRUE; + SetLastError(ERROR_FILE_NOT_FOUND); + return FALSE; + } + + /* paste the path and filename together */ + idx = 0; + if (pathlen) { + for (i = 0; i < pathlen; i++) fullpath[idx++] = pszCabPath[i]; + if (fullpath[idx - 1] != '\\') fullpath[idx++] = '\\'; + } + if (filenamelen) for (i = 0; i < filenamelen; i++) fullpath[idx++] = pszCabinet[i]; + fullpath[idx] = '\0'; + + TRACE("full cab path/file name: %s\n", debugstr_a(fullpath)); + + /* get a handle to the cabfile */ + cabhf = PFDI_OPEN(hfdi, fullpath, 32768, _S_IREAD | _S_IWRITE); + if (cabhf == -1) { + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CABINET_NOT_FOUND; + PFDI_INT(hfdi)->perf->erfType = ERROR_FILE_NOT_FOUND; + PFDI_INT(hfdi)->perf->fError = TRUE; + SetLastError(ERROR_FILE_NOT_FOUND); + return FALSE; + } + + if (cabhf == 0) { + ERR("PFDI_OPEN returned zero for %s.\n", fullpath); + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CABINET_NOT_FOUND; + PFDI_INT(hfdi)->perf->erfType = ERROR_FILE_NOT_FOUND; + PFDI_INT(hfdi)->perf->fError = TRUE; + SetLastError(ERROR_FILE_NOT_FOUND); + return FALSE; + } + + /* check if it's really a cabfile. Note that this doesn't implement the bug */ + if (!FDI_read_entries(hfdi, cabhf, &fdici, &(CAB(mii)))) { + ERR("FDIIsCabinet failed.\n"); + PFDI_CLOSE(hfdi, cabhf); + return FALSE; + } + + /* cabinet notification */ + ZeroMemory(&fdin, sizeof(FDINOTIFICATION)); + fdin.setID = fdici.setID; + fdin.iCabinet = fdici.iCabinet; + fdin.pv = pvUser; + fdin.psz1 = (CAB(mii).nextname) ? CAB(mii).nextname : &emptystring; + fdin.psz2 = (CAB(mii).nextinfo) ? CAB(mii).nextinfo : &emptystring; + fdin.psz3 = pszCabPath; + + if (((*pfnfdin)(fdintCABINET_INFO, &fdin))) { + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT; + PFDI_INT(hfdi)->perf->erfType = 0; + PFDI_INT(hfdi)->perf->fError = TRUE; + goto bail_and_fail; + } + + CAB(setID) = fdici.setID; + CAB(iCabinet) = fdici.iCabinet; + + /* read folders */ + for (i = 0; i < fdici.cFolders; i++) { + if (PFDI_READ(hfdi, cabhf, buf, cffold_SIZEOF) != cffold_SIZEOF) { + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET; + PFDI_INT(hfdi)->perf->erfType = 0; + PFDI_INT(hfdi)->perf->fError = TRUE; + goto bail_and_fail; + } + + if (CAB(mii).folder_resv > 0) + PFDI_SEEK(hfdi, cabhf, CAB(mii).folder_resv, SEEK_CUR); + + fol = (struct fdi_folder *) PFDI_ALLOC(hfdi, sizeof(struct fdi_folder)); + if (!fol) { + ERR("out of memory!\n"); + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL; + PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + PFDI_INT(hfdi)->perf->fError = TRUE; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto bail_and_fail; + } + ZeroMemory(fol, sizeof(struct fdi_folder)); + if (!CAB(firstfol)) CAB(firstfol) = fol; + + fol->offset = (cab_off_t) EndGetI32(buf+cffold_DataOffset); + fol->num_blocks = EndGetI16(buf+cffold_NumBlocks); + fol->comp_type = EndGetI16(buf+cffold_CompType); + + if (linkfol) + linkfol->next = fol; + linkfol = fol; + } + + /* read files */ + for (i = 0; i < fdici.cFiles; i++) { + if (PFDI_READ(hfdi, cabhf, buf, cffile_SIZEOF) != cffile_SIZEOF) { + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET; + PFDI_INT(hfdi)->perf->erfType = 0; + PFDI_INT(hfdi)->perf->fError = TRUE; + goto bail_and_fail; + } + + file = (struct fdi_file *) PFDI_ALLOC(hfdi, sizeof(struct fdi_file)); + if (!file) { + ERR("out of memory!\n"); + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL; + PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + PFDI_INT(hfdi)->perf->fError = TRUE; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto bail_and_fail; + } + ZeroMemory(file, sizeof(struct fdi_file)); + if (!CAB(firstfile)) CAB(firstfile) = file; + + file->length = EndGetI32(buf+cffile_UncompressedSize); + file->offset = EndGetI32(buf+cffile_FolderOffset); + file->index = EndGetI16(buf+cffile_FolderIndex); + file->time = EndGetI16(buf+cffile_Time); + file->date = EndGetI16(buf+cffile_Date); + file->attribs = EndGetI16(buf+cffile_Attribs); + file->filename = FDI_read_string(hfdi, cabhf, fdici.cbCabinet); + + if (!file->filename) { + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET; + PFDI_INT(hfdi)->perf->erfType = 0; + PFDI_INT(hfdi)->perf->fError = TRUE; + goto bail_and_fail; + } + + if (linkfile) + linkfile->next = file; + linkfile = file; + } + + for (file = CAB(firstfile); (file); file = file->next) { + + /* + * FIXME: This implementation keeps multiple cabinet files open at once + * when encountering a split cabinet. It is a quirk of this implementation + * that sometimes we decrypt the same block of data more than once, to find + * the right starting point for a file, moving the file-pointer backwards. + * If we kept a cache of certain file-pointer information, we could eliminate + * that behavior... in fact I am not sure that the caching we already have + * is not sufficient. + * + * The current implementation seems to work fine in straightforward situations + * where all the cabinet files needed for decryption are simultaneously + * available. But presumably, the API is supposed to support cabinets which + * are split across multiple CDROMS; we may need to change our implementation + * to strictly serialize it's file usage so that it opens only one cabinet + * at a time. Some experimentation with Windows is needed to figure out the + * precise semantics required. The relevant code is here and in fdi_decomp(). + */ + + /* partial-file notification */ + if ((file->index & cffileCONTINUED_FROM_PREV) == cffileCONTINUED_FROM_PREV) { + /* + * FIXME: Need to create a Cabinet with a single file spanning multiple files + * and perform some tests to figure out the right behavior. The SDK says + * FDICopy will notify the user of the filename and "disk name" (info) of + * the cabinet where the spanning file /started/. + * + * That would certainly be convenient for the API-user, who could abort, + * everything (or parallelize, if that's allowed (it is in wine)), and call + * FDICopy again with the provided filename, so as to avoid partial file + * notification and successfully unpack. This task could be quite unpleasant + * from wine's perspective: the information specifying the "start cabinet" for + * a file is associated nowhere with the file header and is not to be found in + * the cabinet header. We have only the index of the cabinet wherein the folder + * begins, which contains the file. To find that cabinet, we must consider the + * index of the current cabinet, and chain backwards, cabinet-by-cabinet (for + * each cabinet refers to its "next" and "previous" cabinet only, like a linked + * list). + * + * Bear in mind that, in the spirit of CABINET.DLL, we must assume that any + * cabinet other than the active one might be at another filepath than the + * current one, or on another CDROM. This could get rather dicey, especially + * if we imagine parallelized access to the FDICopy API. + * + * The current implementation punts -- it just returns the previous cabinet and + * it's info from the header of this cabinet. This provides the right answer in + * 95% of the cases; its worth checking if Microsoft cuts the same corner before + * we "fix" it. + */ + ZeroMemory(&fdin, sizeof(FDINOTIFICATION)); + fdin.pv = pvUser; + fdin.psz1 = (char *)file->filename; + fdin.psz2 = (CAB(mii).prevname) ? CAB(mii).prevname : &emptystring; + fdin.psz3 = (CAB(mii).previnfo) ? CAB(mii).previnfo : &emptystring; + + if (((*pfnfdin)(fdintPARTIAL_FILE, &fdin))) { + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT; + PFDI_INT(hfdi)->perf->erfType = 0; + PFDI_INT(hfdi)->perf->fError = TRUE; + goto bail_and_fail; + } + /* I don't think we are supposed to decompress partial files. This prevents it. */ + file->oppressed = TRUE; + } + if (file->oppressed) { + filehf = 0; + } else { + ZeroMemory(&fdin, sizeof(FDINOTIFICATION)); + fdin.pv = pvUser; + fdin.psz1 = (char *)file->filename; + fdin.cb = file->length; + fdin.date = file->date; + fdin.time = file->time; + fdin.attribs = file->attribs; + if ((filehf = ((*pfnfdin)(fdintCOPY_FILE, &fdin))) == -1) { + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT; + PFDI_INT(hfdi)->perf->erfType = 0; + PFDI_INT(hfdi)->perf->fError = TRUE; + goto bail_and_fail; + } + } + + /* find the folder for this file if necc. */ + if (filehf) { + int i2; + + fol = CAB(firstfol); + if ((file->index & cffileCONTINUED_TO_NEXT) == cffileCONTINUED_TO_NEXT) { + /* pick the last folder */ + while (fol->next) fol = fol->next; + } else { + for (i2 = 0; (i2 < file->index); i2++) + if (fol->next) /* bug resistance, should always be true */ + fol = fol->next; + } + } + + if (filehf) { + cab_UWORD comptype = fol->comp_type; + int ct1 = comptype & cffoldCOMPTYPE_MASK; + int ct2 = CAB(current) ? (CAB(current)->comp_type & cffoldCOMPTYPE_MASK) : 0; + int err = 0; + + TRACE("Extracting file %s as requested by callee.\n", debugstr_a(file->filename)); + + /* set up decomp_state */ + CAB(hfdi) = hfdi; + CAB(filehf) = filehf; + CAB(cabhf) = cabhf; + + /* Was there a change of folder? Compression type? Did we somehow go backwards? */ + if ((ct1 != ct2) || (CAB(current) != fol) || (file->offset < CAB(offset))) { + + TRACE("Resetting folder for file %s.\n", debugstr_a(file->filename)); + + /* free stuff for the old decompresser */ + switch (ct2) { + case cffoldCOMPTYPE_LZX: + if (LZX(window)) { + PFDI_FREE(hfdi, LZX(window)); + LZX(window) = NULL; + } + break; + case cffoldCOMPTYPE_QUANTUM: + if (QTM(window)) { + PFDI_FREE(hfdi, QTM(window)); + QTM(window) = NULL; + } + break; + } + + CAB(decomp_cab) = NULL; + PFDI_SEEK(CAB(hfdi), CAB(cabhf), fol->offset, SEEK_SET); + CAB(offset) = 0; + CAB(outlen) = 0; + + /* initialize the new decompresser */ + switch (ct1) { + case cffoldCOMPTYPE_NONE: + CAB(decompress) = NONEfdi_decomp; + break; + case cffoldCOMPTYPE_MSZIP: + CAB(decompress) = ZIPfdi_decomp; + break; + case cffoldCOMPTYPE_QUANTUM: + CAB(decompress) = QTMfdi_decomp; + err = QTMfdi_init((comptype >> 8) & 0x1f, (comptype >> 4) & 0xF, decomp_state); + break; + case cffoldCOMPTYPE_LZX: + CAB(decompress) = LZXfdi_decomp; + err = LZXfdi_init((comptype >> 8) & 0x1f, decomp_state); + break; + default: + err = DECR_DATAFORMAT; + } + } + + CAB(current) = fol; + + switch (err) { + case DECR_OK: + break; + case DECR_NOMEMORY: + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL; + PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + PFDI_INT(hfdi)->perf->fError = TRUE; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto bail_and_fail; + default: + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET; + PFDI_INT(hfdi)->perf->erfOper = 0; + PFDI_INT(hfdi)->perf->fError = TRUE; + goto bail_and_fail; + } + + if (file->offset > CAB(offset)) { + /* decode bytes and send them to /dev/null */ + switch ((err = fdi_decomp(file, 0, decomp_state, pszCabPath, pfnfdin, pvUser))) { + case DECR_OK: + break; + case DECR_USERABORT: + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT; + PFDI_INT(hfdi)->perf->erfType = 0; + PFDI_INT(hfdi)->perf->fError = TRUE; + goto bail_and_fail; + case DECR_NOMEMORY: + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL; + PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + PFDI_INT(hfdi)->perf->fError = TRUE; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto bail_and_fail; + default: + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET; + PFDI_INT(hfdi)->perf->erfOper = 0; + PFDI_INT(hfdi)->perf->fError = TRUE; + goto bail_and_fail; + } + CAB(offset) = file->offset; + } + + /* now do the actual decompression */ + err = fdi_decomp(file, 1, decomp_state, pszCabPath, pfnfdin, pvUser); + if (err) CAB(current) = NULL; else CAB(offset) += file->length; + + switch (err) { + case DECR_OK: + break; + case DECR_USERABORT: + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT; + PFDI_INT(hfdi)->perf->erfType = 0; + PFDI_INT(hfdi)->perf->fError = TRUE; + goto bail_and_fail; + case DECR_NOMEMORY: + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_ALLOC_FAIL; + PFDI_INT(hfdi)->perf->erfType = ERROR_NOT_ENOUGH_MEMORY; + PFDI_INT(hfdi)->perf->fError = TRUE; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto bail_and_fail; + default: + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_CORRUPT_CABINET; + PFDI_INT(hfdi)->perf->erfOper = 0; + PFDI_INT(hfdi)->perf->fError = TRUE; + goto bail_and_fail; + } + + /* fdintCLOSE_FILE_INFO notification */ + ZeroMemory(&fdin, sizeof(FDINOTIFICATION)); + fdin.pv = pvUser; + fdin.psz1 = (char *)file->filename; + fdin.hf = filehf; + fdin.cb = (file->attribs & cffile_A_EXEC) ? TRUE : FALSE; /* FIXME: is that right? */ + fdin.date = file->date; + fdin.time = file->time; + fdin.attribs = file->attribs; /* FIXME: filter _A_EXEC? */ + err = ((*pfnfdin)(fdintCLOSE_FILE_INFO, &fdin)); + if (err == FALSE || err == -1) { + /* + * SDK states that even though they indicated failure, + * we are not supposed to try and close the file, so we + * just treat this like all the others + */ + PFDI_INT(hfdi)->perf->erfOper = FDIERROR_USER_ABORT; + PFDI_INT(hfdi)->perf->erfType = 0; + PFDI_INT(hfdi)->perf->fError = TRUE; + goto bail_and_fail; + } + } + } + + /* free decompression temps */ + switch (fol->comp_type & cffoldCOMPTYPE_MASK) { + case cffoldCOMPTYPE_LZX: + if (LZX(window)) { + PFDI_FREE(hfdi, LZX(window)); + LZX(window) = NULL; + } + break; + case cffoldCOMPTYPE_QUANTUM: + if (QTM(window)) { + PFDI_FREE(hfdi, QTM(window)); + QTM(window) = NULL; + } + break; + } + + while (decomp_state) { + fdi_decomp_state *prev_fds; + + PFDI_CLOSE(hfdi, CAB(cabhf)); + + /* free the storage remembered by mii */ + if (CAB(mii).nextname) PFDI_FREE(hfdi, CAB(mii).nextname); + if (CAB(mii).nextinfo) PFDI_FREE(hfdi, CAB(mii).nextinfo); + if (CAB(mii).prevname) PFDI_FREE(hfdi, CAB(mii).prevname); + if (CAB(mii).previnfo) PFDI_FREE(hfdi, CAB(mii).previnfo); + + while (CAB(firstfol)) { + fol = CAB(firstfol); + CAB(firstfol) = CAB(firstfol)->next; + PFDI_FREE(hfdi, fol); + } + while (CAB(firstfile)) { + file = CAB(firstfile); + if (file->filename) PFDI_FREE(hfdi, (void *)file->filename); + CAB(firstfile) = CAB(firstfile)->next; + PFDI_FREE(hfdi, file); + } + prev_fds = decomp_state; + decomp_state = CAB(next); + if (prev_fds != &_decomp_state) + PFDI_FREE(hfdi, prev_fds); + } + + return TRUE; + + bail_and_fail: /* here we free ram before error returns */ + + /* free decompression temps */ + switch (fol->comp_type & cffoldCOMPTYPE_MASK) { + case cffoldCOMPTYPE_LZX: + if (LZX(window)) { + PFDI_FREE(hfdi, LZX(window)); + LZX(window) = NULL; + } + break; + case cffoldCOMPTYPE_QUANTUM: + if (QTM(window)) { + PFDI_FREE(hfdi, QTM(window)); + QTM(window) = NULL; + } + break; + } + + while (decomp_state) { + fdi_decomp_state *prev_fds; + + PFDI_CLOSE(hfdi, CAB(cabhf)); + + /* free the storage remembered by mii */ + if (CAB(mii).nextname) PFDI_FREE(hfdi, CAB(mii).nextname); + if (CAB(mii).nextinfo) PFDI_FREE(hfdi, CAB(mii).nextinfo); + if (CAB(mii).prevname) PFDI_FREE(hfdi, CAB(mii).prevname); + if (CAB(mii).previnfo) PFDI_FREE(hfdi, CAB(mii).previnfo); + + while (CAB(firstfol)) { + fol = CAB(firstfol); + CAB(firstfol) = CAB(firstfol)->next; + PFDI_FREE(hfdi, fol); + } + while (CAB(firstfile)) { + file = CAB(firstfile); + if (file->filename) PFDI_FREE(hfdi, (void *)file->filename); + CAB(firstfile) = CAB(firstfile)->next; + PFDI_FREE(hfdi, file); + } + prev_fds = decomp_state; + decomp_state = CAB(next); + if (prev_fds != &_decomp_state) + PFDI_FREE(hfdi, prev_fds); + } + + return FALSE; +} + +/*********************************************************************** + * FDIDestroy (CABINET.23) + * + * Frees a handle created by FDICreate. Do /not/ call this in the middle + * of FDICopy. Only reason for failure would be an invalid handle. + * + * PARAMS + * hfdi [I] The HFDI to free + * + * RETURNS + * TRUE for success + * FALSE for failure + */ +BOOL __cdecl FDIDestroy(HFDI hfdi) +{ + TRACE("(hfdi == ^%p)\n", hfdi); + if (REALLY_IS_FDI(hfdi)) { + PFDI_INT(hfdi)->FDI_Intmagic = 0; /* paranoia */ + PFDI_FREE(hfdi, hfdi); /* confusing, but correct */ + return TRUE; + } else { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } +} + +/*********************************************************************** + * FDITruncateCabinet (CABINET.24) + * + * Undocumented and unimplemented. + */ +BOOL __cdecl FDITruncateCabinet( + HFDI hfdi, + char *pszCabinetName, + USHORT iFolderToDelete) +{ + FIXME("(hfdi == ^%p, pszCabinetName == %s, iFolderToDelete == %hu): stub\n", + hfdi, debugstr_a(pszCabinetName), iFolderToDelete); + + if (!REALLY_IS_FDI(hfdi)) { + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} diff --git a/reactos/lib/comctl32/animate.c b/reactos/lib/comctl32/animate.c index b1fe5cad053..1a15609f7c7 100644 --- a/reactos/lib/comctl32/animate.c +++ b/reactos/lib/comctl32/animate.c @@ -1,977 +1,977 @@ -/* -*- tab-width: 8; c-basic-offset: 4 -*- */ -/* - * Animation control - * - * Copyright 1998, 1999 Eric Kohl - * Copyright 1999 Eric Pouech - * Copyright 2005 Dimitrie O. Paun - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTES - * - * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on Mar. 15, 2005, by Dimitrie O. Paun. - * - * Unless otherwise noted, we believe this code to be complete, as per - * the specification mentioned above. - * If you discover missing features, or bugs, please note them below. - * - * TODO: - * - check for the 'rec ' list in some AVI files - */ - -#define COM_NO_WINDOWS_H -#include -#include -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "vfw.h" -#include "mmsystem.h" -#include "comctl32.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(animate); - -static struct { - HMODULE hModule; - HIC (WINAPI *fnICOpen)(DWORD, DWORD, UINT); - LRESULT (WINAPI *fnICClose)(HIC); - LRESULT (WINAPI *fnICSendMessage)(HIC, UINT, DWORD, DWORD); - DWORD (WINAPIV *fnICDecompress)(HIC,DWORD,LPBITMAPINFOHEADER,LPVOID,LPBITMAPINFOHEADER,LPVOID); -} fnIC; - -typedef struct -{ - /* reference to input stream (file or resource) */ - HGLOBAL hRes; - HMMIO hMMio; /* handle to mmio stream */ - HWND hwndSelf; - HWND hwndNotify; - DWORD dwStyle; - /* information on the loaded AVI file */ - MainAVIHeader mah; - AVIStreamHeader ash; - LPBITMAPINFOHEADER inbih; - LPDWORD lpIndex; - /* data for the decompressor */ - HIC hic; - LPBITMAPINFOHEADER outbih; - LPVOID indata; - LPVOID outdata; - /* data for the background mechanism */ - CRITICAL_SECTION cs; - HANDLE hStopEvent; - HANDLE hThread; - DWORD threadId; - UINT uTimer; - /* data for playing the file */ - int nFromFrame; - int nToFrame; - int nLoop; - int currFrame; - /* tranparency info*/ - COLORREF transparentColor; - HBRUSH hbrushBG; - HBITMAP hbmPrevFrame; -} ANIMATE_INFO; - -#define ANIMATE_COLOR_NONE 0xffffffff - -static void ANIMATE_Notify(ANIMATE_INFO *infoPtr, UINT notif) -{ - SendMessageW(infoPtr->hwndNotify, WM_COMMAND, - MAKEWPARAM(GetDlgCtrlID(infoPtr->hwndSelf), notif), - (LPARAM)infoPtr->hwndSelf); -} - -static BOOL ANIMATE_LoadResW(ANIMATE_INFO *infoPtr, HINSTANCE hInst, LPWSTR lpName) -{ - static const WCHAR aviW[] = { 'A', 'V', 'I', 0 }; - HRSRC hrsrc; - MMIOINFO mminfo; - LPVOID lpAvi; - - hrsrc = FindResourceW(hInst, lpName, aviW); - if (!hrsrc) - return FALSE; - - infoPtr->hRes = LoadResource(hInst, hrsrc); - if (!infoPtr->hRes) - return FALSE; - - lpAvi = LockResource(infoPtr->hRes); - if (!lpAvi) - return FALSE; - - memset(&mminfo, 0, sizeof(mminfo)); - mminfo.fccIOProc = FOURCC_MEM; - mminfo.pchBuffer = (LPSTR)lpAvi; - mminfo.cchBuffer = SizeofResource(hInst, hrsrc); - infoPtr->hMMio = mmioOpenW(NULL, &mminfo, MMIO_READ); - if (!infoPtr->hMMio) - { - FreeResource(infoPtr->hRes); - return FALSE; - } - - return TRUE; -} - - -static BOOL ANIMATE_LoadFileW(ANIMATE_INFO *infoPtr, LPWSTR lpName) -{ - infoPtr->hMMio = mmioOpenW(lpName, 0, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE); - - return (BOOL)infoPtr->hMMio; -} - - -static BOOL ANIMATE_DoStop(ANIMATE_INFO *infoPtr) -{ - EnterCriticalSection(&infoPtr->cs); - - /* should stop playing */ - if (infoPtr->hThread) - { - HANDLE handle = infoPtr->hThread; - - TRACE("stopping animation thread\n"); - infoPtr->hThread = 0; - SetEvent( infoPtr->hStopEvent ); - - if (infoPtr->threadId != GetCurrentThreadId()) - { - LeaveCriticalSection(&infoPtr->cs); /* leave it a chance to run */ - WaitForSingleObject( handle, INFINITE ); - TRACE("animation thread stopped\n"); - EnterCriticalSection(&infoPtr->cs); - } - - CloseHandle( handle ); - CloseHandle( infoPtr->hStopEvent ); - infoPtr->hStopEvent = 0; - } - if (infoPtr->uTimer) { - KillTimer(infoPtr->hwndSelf, infoPtr->uTimer); - infoPtr->uTimer = 0; - } - - LeaveCriticalSection(&infoPtr->cs); - - ANIMATE_Notify(infoPtr, ACN_STOP); - - return TRUE; -} - - -static void ANIMATE_Free(ANIMATE_INFO *infoPtr) -{ - if (infoPtr->hMMio) { - ANIMATE_DoStop(infoPtr); - mmioClose(infoPtr->hMMio, 0); - if (infoPtr->hRes) { - FreeResource(infoPtr->hRes); - infoPtr->hRes = 0; - } - Free (infoPtr->lpIndex); - infoPtr->lpIndex = NULL; - if (infoPtr->hic) { - fnIC.fnICClose(infoPtr->hic); - infoPtr->hic = 0; - } - Free (infoPtr->inbih); - infoPtr->inbih = NULL; - Free (infoPtr->outbih); - infoPtr->outbih = NULL; - Free (infoPtr->indata); - infoPtr->indata = NULL; - Free (infoPtr->outdata); - infoPtr->outdata = NULL; - if( infoPtr->hbmPrevFrame ) - { - DeleteObject(infoPtr->hbmPrevFrame); - infoPtr->hbmPrevFrame = 0; - } - - memset(&infoPtr->mah, 0, sizeof(infoPtr->mah)); - memset(&infoPtr->ash, 0, sizeof(infoPtr->ash)); - infoPtr->nFromFrame = infoPtr->nToFrame = infoPtr->nLoop = infoPtr->currFrame = 0; - } - infoPtr->transparentColor = ANIMATE_COLOR_NONE; -} - -static void ANIMATE_TransparentBlt(ANIMATE_INFO *infoPtr, HDC hdcDest, HDC hdcSource) -{ - HDC hdcMask; - HBITMAP hbmMask; - HBITMAP hbmOld; - - /* create a transparency mask */ - hdcMask = CreateCompatibleDC(hdcDest); - hbmMask = CreateBitmap(infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, 1,1,NULL); - hbmOld = SelectObject(hdcMask, hbmMask); - - SetBkColor(hdcSource,infoPtr->transparentColor); - BitBlt(hdcMask,0,0,infoPtr->inbih->biWidth, infoPtr->inbih->biHeight,hdcSource,0,0,SRCCOPY); - - /* mask the source bitmap */ - SetBkColor(hdcSource, RGB(0,0,0)); - SetTextColor(hdcSource, RGB(255,255,255)); - BitBlt(hdcSource, 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, hdcMask, 0, 0, SRCAND); - - /* mask the destination bitmap */ - SetBkColor(hdcDest, RGB(255,255,255)); - SetTextColor(hdcDest, RGB(0,0,0)); - BitBlt(hdcDest, 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, hdcMask, 0, 0, SRCAND); - - /* combine source and destination */ - BitBlt(hdcDest,0,0,infoPtr->inbih->biWidth, infoPtr->inbih->biHeight,hdcSource,0,0,SRCPAINT); - - SelectObject(hdcMask, hbmOld); - DeleteObject(hbmMask); - DeleteDC(hdcMask); -} - -static BOOL ANIMATE_PaintFrame(ANIMATE_INFO* infoPtr, HDC hDC) -{ - void* pBitmapData = NULL; - LPBITMAPINFO pBitmapInfo = NULL; - - HDC hdcMem; - HBITMAP hbmOld; - - int nOffsetX = 0; - int nOffsetY = 0; - - int nWidth; - int nHeight; - - if (!hDC || !infoPtr->inbih) - return TRUE; - - if (infoPtr->hic ) - { - pBitmapData = infoPtr->outdata; - pBitmapInfo = (LPBITMAPINFO)infoPtr->outbih; - - nWidth = infoPtr->outbih->biWidth; - nHeight = infoPtr->outbih->biHeight; - } - else - { - pBitmapData = infoPtr->indata; - pBitmapInfo = (LPBITMAPINFO)infoPtr->inbih; - - nWidth = infoPtr->inbih->biWidth; - nHeight = infoPtr->inbih->biHeight; - } - - if(!infoPtr->hbmPrevFrame) - { - infoPtr->hbmPrevFrame=CreateCompatibleBitmap(hDC, nWidth,nHeight ); - } - - SetDIBits(hDC, infoPtr->hbmPrevFrame, 0, nHeight, pBitmapData, (LPBITMAPINFO)pBitmapInfo, DIB_RGB_COLORS); - - hdcMem = CreateCompatibleDC(hDC); - hbmOld = SelectObject(hdcMem, infoPtr->hbmPrevFrame); - - /* - * we need to get the transparent color even without ACS_TRANSPARENT, - * because the style can be changed later on and the color should always - * be obtained in the first frame - */ - if(infoPtr->transparentColor == ANIMATE_COLOR_NONE) - { - infoPtr->transparentColor = GetPixel(hdcMem,0,0); - } - - if(infoPtr->dwStyle & ACS_TRANSPARENT) - { - HDC hdcFinal = CreateCompatibleDC(hDC); - HBITMAP hbmFinal = CreateCompatibleBitmap(hDC,nWidth, nHeight); - HBITMAP hbmOld2 = SelectObject(hdcFinal, hbmFinal); - RECT rect; - - rect.left = 0; - rect.top = 0; - rect.right = nWidth; - rect.bottom = nHeight; - - if(!infoPtr->hbrushBG) - infoPtr->hbrushBG = GetCurrentObject(hDC, OBJ_BRUSH); - - FillRect(hdcFinal, &rect, infoPtr->hbrushBG); - ANIMATE_TransparentBlt(infoPtr, hdcFinal, hdcMem); - - SelectObject(hdcFinal, hbmOld2); - SelectObject(hdcMem, hbmFinal); - DeleteDC(hdcFinal); - DeleteObject(infoPtr->hbmPrevFrame); - infoPtr->hbmPrevFrame = hbmFinal; - } - - if (infoPtr->dwStyle & ACS_CENTER) - { - RECT rect; - - GetWindowRect(infoPtr->hwndSelf, &rect); - nOffsetX = ((rect.right - rect.left) - nWidth)/2; - nOffsetY = ((rect.bottom - rect.top) - nHeight)/2; - } - BitBlt(hDC, nOffsetX, nOffsetY, nWidth, nHeight, hdcMem, 0, 0, SRCCOPY); - - SelectObject(hdcMem, hbmOld); - DeleteDC(hdcMem); - return TRUE; -} - -static BOOL ANIMATE_DrawFrame(ANIMATE_INFO *infoPtr) -{ - HDC hDC; - - TRACE("Drawing frame %d (loop %d)\n", infoPtr->currFrame, infoPtr->nLoop); - - mmioSeek(infoPtr->hMMio, infoPtr->lpIndex[infoPtr->currFrame], SEEK_SET); - mmioRead(infoPtr->hMMio, infoPtr->indata, infoPtr->ash.dwSuggestedBufferSize); - - if (infoPtr->hic && - fnIC.fnICDecompress(infoPtr->hic, 0, infoPtr->inbih, infoPtr->indata, - infoPtr->outbih, infoPtr->outdata) != ICERR_OK) { - WARN("Decompression error\n"); - return FALSE; - } - - if ((hDC = GetDC(infoPtr->hwndSelf)) != 0) { - ANIMATE_PaintFrame(infoPtr, hDC); - ReleaseDC(infoPtr->hwndSelf, hDC); - } - - if (infoPtr->currFrame++ >= infoPtr->nToFrame) { - infoPtr->currFrame = infoPtr->nFromFrame; - if (infoPtr->nLoop != -1) { - if (--infoPtr->nLoop == 0) { - ANIMATE_DoStop(infoPtr); - } - } - } - - return TRUE; -} - -static LRESULT ANIMATE_Timer(ANIMATE_INFO *infoPtr) -{ - /* FIXME: we should pass the hDC instead of 0 to WM_CTLCOLORSTATIC */ - if (infoPtr->dwStyle & ACS_TRANSPARENT) - infoPtr->hbrushBG = (HBRUSH)SendMessageW(infoPtr->hwndNotify, - WM_CTLCOLORSTATIC, - 0, (LPARAM)infoPtr->hwndSelf); - EnterCriticalSection(&infoPtr->cs); - ANIMATE_DrawFrame(infoPtr); - LeaveCriticalSection(&infoPtr->cs); - - return 0; -} - -static DWORD CALLBACK ANIMATE_AnimationThread(LPVOID ptr_) -{ - ANIMATE_INFO *infoPtr = (ANIMATE_INFO *)ptr_; - HANDLE event; - DWORD timeout; - - while(1) - { - EnterCriticalSection(&infoPtr->cs); - ANIMATE_DrawFrame(infoPtr); - timeout = infoPtr->mah.dwMicroSecPerFrame; - event = infoPtr->hStopEvent; - LeaveCriticalSection(&infoPtr->cs); - - /* time is in microseconds, we should convert it to milliseconds */ - if ((event == 0) || WaitForSingleObject( event, (timeout+500)/1000) == WAIT_OBJECT_0) - break; - } - return TRUE; -} - -static LRESULT ANIMATE_Play(ANIMATE_INFO *infoPtr, UINT cRepeat, WORD wFrom, WORD wTo) -{ - /* nothing opened */ - if (!infoPtr->hMMio) - return FALSE; - - if (infoPtr->hThread || infoPtr->uTimer) { - TRACE("Already playing\n"); - return TRUE; - } - - infoPtr->nFromFrame = wFrom; - infoPtr->nToFrame = wTo; - infoPtr->nLoop = cRepeat; - - if (infoPtr->nToFrame == 0xFFFF) - infoPtr->nToFrame = infoPtr->mah.dwTotalFrames - 1; - - TRACE("(repeat=%d from=%d to=%d);\n", - infoPtr->nLoop, infoPtr->nFromFrame, infoPtr->nToFrame); - - if (infoPtr->nFromFrame >= infoPtr->nToFrame || - infoPtr->nToFrame >= infoPtr->mah.dwTotalFrames) - return FALSE; - - infoPtr->currFrame = infoPtr->nFromFrame; - - if (infoPtr->dwStyle & ACS_TIMER) - { - TRACE("Using a timer\n"); - /* create a timer to display AVI */ - infoPtr->uTimer = SetTimer(infoPtr->hwndSelf, 1, - infoPtr->mah.dwMicroSecPerFrame / 1000, NULL); - } - else - { - if(infoPtr->dwStyle & ACS_TRANSPARENT) - infoPtr->hbrushBG = (HBRUSH)SendMessageW(infoPtr->hwndNotify, - WM_CTLCOLORSTATIC, 0, - (LPARAM)infoPtr->hwndSelf); - - TRACE("Using an animation thread\n"); - infoPtr->hStopEvent = CreateEventW( NULL, TRUE, FALSE, NULL ); - infoPtr->hThread = CreateThread(0, 0, ANIMATE_AnimationThread, - (LPVOID)infoPtr, 0, &infoPtr->threadId); - if(!infoPtr->hThread) return FALSE; - - } - - ANIMATE_Notify(infoPtr, ACN_START); - - return TRUE; -} - - -static BOOL ANIMATE_GetAviInfo(ANIMATE_INFO *infoPtr) -{ - MMCKINFO ckMainRIFF; - MMCKINFO mmckHead; - MMCKINFO mmckList; - MMCKINFO mmckInfo; - DWORD numFrame; - DWORD insize; - - if (mmioDescend(infoPtr->hMMio, &ckMainRIFF, NULL, 0) != 0) { - WARN("Can't find 'RIFF' chunk\n"); - return FALSE; - } - - if ((ckMainRIFF.ckid != FOURCC_RIFF) || - (ckMainRIFF.fccType != mmioFOURCC('A', 'V', 'I', ' '))) { - WARN("Can't find 'AVI ' chunk\n"); - return FALSE; - } - - mmckHead.fccType = mmioFOURCC('h', 'd', 'r', 'l'); - if (mmioDescend(infoPtr->hMMio, &mmckHead, &ckMainRIFF, MMIO_FINDLIST) != 0) { - WARN("Can't find 'hdrl' list\n"); - return FALSE; - } - - mmckInfo.ckid = mmioFOURCC('a', 'v', 'i', 'h'); - if (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckHead, MMIO_FINDCHUNK) != 0) { - WARN("Can't find 'avih' chunk\n"); - return FALSE; - } - - mmioRead(infoPtr->hMMio, (LPSTR)&infoPtr->mah, sizeof(infoPtr->mah)); - - TRACE("mah.dwMicroSecPerFrame=%ld\n", infoPtr->mah.dwMicroSecPerFrame); - TRACE("mah.dwMaxBytesPerSec=%ld\n", infoPtr->mah.dwMaxBytesPerSec); - TRACE("mah.dwPaddingGranularity=%ld\n", infoPtr->mah.dwPaddingGranularity); - TRACE("mah.dwFlags=%ld\n", infoPtr->mah.dwFlags); - TRACE("mah.dwTotalFrames=%ld\n", infoPtr->mah.dwTotalFrames); - TRACE("mah.dwInitialFrames=%ld\n", infoPtr->mah.dwInitialFrames); - TRACE("mah.dwStreams=%ld\n", infoPtr->mah.dwStreams); - TRACE("mah.dwSuggestedBufferSize=%ld\n", infoPtr->mah.dwSuggestedBufferSize); - TRACE("mah.dwWidth=%ld\n", infoPtr->mah.dwWidth); - TRACE("mah.dwHeight=%ld\n", infoPtr->mah.dwHeight); - - mmioAscend(infoPtr->hMMio, &mmckInfo, 0); - - mmckList.fccType = mmioFOURCC('s', 't', 'r', 'l'); - if (mmioDescend(infoPtr->hMMio, &mmckList, &mmckHead, MMIO_FINDLIST) != 0) { - WARN("Can't find 'strl' list\n"); - return FALSE; - } - - mmckInfo.ckid = mmioFOURCC('s', 't', 'r', 'h'); - if (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, MMIO_FINDCHUNK) != 0) { - WARN("Can't find 'strh' chunk\n"); - return FALSE; - } - - mmioRead(infoPtr->hMMio, (LPSTR)&infoPtr->ash, sizeof(infoPtr->ash)); - - TRACE("ash.fccType='%c%c%c%c'\n", LOBYTE(LOWORD(infoPtr->ash.fccType)), - HIBYTE(LOWORD(infoPtr->ash.fccType)), - LOBYTE(HIWORD(infoPtr->ash.fccType)), - HIBYTE(HIWORD(infoPtr->ash.fccType))); - TRACE("ash.fccHandler='%c%c%c%c'\n", LOBYTE(LOWORD(infoPtr->ash.fccHandler)), - HIBYTE(LOWORD(infoPtr->ash.fccHandler)), - LOBYTE(HIWORD(infoPtr->ash.fccHandler)), - HIBYTE(HIWORD(infoPtr->ash.fccHandler))); - TRACE("ash.dwFlags=%ld\n", infoPtr->ash.dwFlags); - TRACE("ash.wPriority=%d\n", infoPtr->ash.wPriority); - TRACE("ash.wLanguage=%d\n", infoPtr->ash.wLanguage); - TRACE("ash.dwInitialFrames=%ld\n", infoPtr->ash.dwInitialFrames); - TRACE("ash.dwScale=%ld\n", infoPtr->ash.dwScale); - TRACE("ash.dwRate=%ld\n", infoPtr->ash.dwRate); - TRACE("ash.dwStart=%ld\n", infoPtr->ash.dwStart); - TRACE("ash.dwLength=%ld\n", infoPtr->ash.dwLength); - TRACE("ash.dwSuggestedBufferSize=%ld\n", infoPtr->ash.dwSuggestedBufferSize); - TRACE("ash.dwQuality=%ld\n", infoPtr->ash.dwQuality); - TRACE("ash.dwSampleSize=%ld\n", infoPtr->ash.dwSampleSize); - TRACE("ash.rcFrame=(%d,%d,%d,%d)\n", infoPtr->ash.rcFrame.top, infoPtr->ash.rcFrame.left, - infoPtr->ash.rcFrame.bottom, infoPtr->ash.rcFrame.right); - - mmioAscend(infoPtr->hMMio, &mmckInfo, 0); - - mmckInfo.ckid = mmioFOURCC('s', 't', 'r', 'f'); - if (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, MMIO_FINDCHUNK) != 0) { - WARN("Can't find 'strh' chunk\n"); - return FALSE; - } - - infoPtr->inbih = Alloc(mmckInfo.cksize); - if (!infoPtr->inbih) { - WARN("Can't alloc input BIH\n"); - return FALSE; - } - - mmioRead(infoPtr->hMMio, (LPSTR)infoPtr->inbih, mmckInfo.cksize); - - TRACE("bih.biSize=%ld\n", infoPtr->inbih->biSize); - TRACE("bih.biWidth=%ld\n", infoPtr->inbih->biWidth); - TRACE("bih.biHeight=%ld\n", infoPtr->inbih->biHeight); - TRACE("bih.biPlanes=%d\n", infoPtr->inbih->biPlanes); - TRACE("bih.biBitCount=%d\n", infoPtr->inbih->biBitCount); - TRACE("bih.biCompression=%ld\n", infoPtr->inbih->biCompression); - TRACE("bih.biSizeImage=%ld\n", infoPtr->inbih->biSizeImage); - TRACE("bih.biXPelsPerMeter=%ld\n", infoPtr->inbih->biXPelsPerMeter); - TRACE("bih.biYPelsPerMeter=%ld\n", infoPtr->inbih->biYPelsPerMeter); - TRACE("bih.biClrUsed=%ld\n", infoPtr->inbih->biClrUsed); - TRACE("bih.biClrImportant=%ld\n", infoPtr->inbih->biClrImportant); - - mmioAscend(infoPtr->hMMio, &mmckInfo, 0); - - mmioAscend(infoPtr->hMMio, &mmckList, 0); - -#if 0 - /* an AVI has 0 or 1 video stream, and to be animated should not contain - * an audio stream, so only one strl is allowed - */ - mmckList.fccType = mmioFOURCC('s', 't', 'r', 'l'); - if (mmioDescend(infoPtr->hMMio, &mmckList, &mmckHead, MMIO_FINDLIST) == 0) { - WARN("There should be a single 'strl' list\n"); - return FALSE; - } -#endif - - mmioAscend(infoPtr->hMMio, &mmckHead, 0); - - /* no need to read optional JUNK chunk */ - - mmckList.fccType = mmioFOURCC('m', 'o', 'v', 'i'); - if (mmioDescend(infoPtr->hMMio, &mmckList, &ckMainRIFF, MMIO_FINDLIST) != 0) { - WARN("Can't find 'movi' list\n"); - return FALSE; - } - - /* FIXME: should handle the 'rec ' LIST when present */ - - infoPtr->lpIndex = Alloc(infoPtr->mah.dwTotalFrames * sizeof(DWORD)); - if (!infoPtr->lpIndex) - return FALSE; - - numFrame = insize = 0; - while (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, 0) == 0 && - numFrame < infoPtr->mah.dwTotalFrames) { - infoPtr->lpIndex[numFrame] = mmckInfo.dwDataOffset; - if (insize < mmckInfo.cksize) - insize = mmckInfo.cksize; - numFrame++; - mmioAscend(infoPtr->hMMio, &mmckInfo, 0); - } - if (numFrame != infoPtr->mah.dwTotalFrames) { - WARN("Found %ld frames (/%ld)\n", numFrame, infoPtr->mah.dwTotalFrames); - return FALSE; - } - if (insize > infoPtr->ash.dwSuggestedBufferSize) { - WARN("insize=%ld suggestedSize=%ld\n", insize, infoPtr->ash.dwSuggestedBufferSize); - infoPtr->ash.dwSuggestedBufferSize = insize; - } - - infoPtr->indata = Alloc(infoPtr->ash.dwSuggestedBufferSize); - if (!infoPtr->indata) - return FALSE; - - return TRUE; -} - - -static BOOL ANIMATE_GetAviCodec(ANIMATE_INFO *infoPtr) -{ - DWORD outSize; - - /* check uncompressed AVI */ - if ((infoPtr->ash.fccHandler == mmioFOURCC('D', 'I', 'B', ' ')) || - (infoPtr->ash.fccHandler == mmioFOURCC('R', 'L', 'E', ' ')) || - (infoPtr->ash.fccHandler == mmioFOURCC(0, 0, 0, 0))) - { - infoPtr->hic = 0; - return TRUE; - } - - /* try to get a decompressor for that type */ - infoPtr->hic = fnIC.fnICOpen(ICTYPE_VIDEO, infoPtr->ash.fccHandler, ICMODE_DECOMPRESS); - if (!infoPtr->hic) { - WARN("Can't load codec for the file\n"); - return FALSE; - } - - outSize = fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_GET_FORMAT, - (DWORD)infoPtr->inbih, 0L); - - infoPtr->outbih = Alloc(outSize); - if (!infoPtr->outbih) - return FALSE; - - if (fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_GET_FORMAT, - (DWORD)infoPtr->inbih, (DWORD)infoPtr->outbih) != outSize) - { - WARN("Can't get output BIH\n"); - return FALSE; - } - - infoPtr->outdata = Alloc(infoPtr->outbih->biSizeImage); - if (!infoPtr->outdata) - return FALSE; - - if (fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_BEGIN, - (DWORD)infoPtr->inbih, (DWORD)infoPtr->outbih) != ICERR_OK) { - WARN("Can't begin decompression\n"); - return FALSE; - } - - return TRUE; -} - - -static BOOL ANIMATE_OpenW(ANIMATE_INFO *infoPtr, HINSTANCE hInstance, LPWSTR lpszName) -{ - ANIMATE_Free(infoPtr); - - if (!lpszName) - { - TRACE("Closing avi!\n"); - /* installer of thebat! v1.62 requires FALSE here */ - return (infoPtr->hMMio != 0); - } - - if (!hInstance) - hInstance = (HINSTANCE)GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_HINSTANCE); - - if (HIWORD(lpszName)) - { - TRACE("(\"%s\");\n", debugstr_w(lpszName)); - - if (!ANIMATE_LoadResW(infoPtr, hInstance, lpszName)) - { - TRACE("No AVI resource found!\n"); - if (!ANIMATE_LoadFileW(infoPtr, lpszName)) - { - WARN("No AVI file found!\n"); - return FALSE; - } - } - } - else - { - TRACE("(%u);\n", (WORD)(DWORD)lpszName); - - if (!ANIMATE_LoadResW(infoPtr, hInstance, MAKEINTRESOURCEW((INT)lpszName))) - { - WARN("No AVI resource found!\n"); - return FALSE; - } - } - - if (!ANIMATE_GetAviInfo(infoPtr)) - { - WARN("Can't get AVI information\n"); - ANIMATE_Free(infoPtr); - return FALSE; - } - - if (!ANIMATE_GetAviCodec(infoPtr)) - { - WARN("Can't get AVI Codec\n"); - ANIMATE_Free(infoPtr); - return FALSE; - } - - if (!(infoPtr->dwStyle & ACS_CENTER)) - SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, infoPtr->mah.dwWidth, infoPtr->mah.dwHeight, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); - - if (infoPtr->dwStyle & ACS_AUTOPLAY) - return ANIMATE_Play(infoPtr, -1, 0, infoPtr->mah.dwTotalFrames - 1); - - return TRUE; -} - - -static BOOL ANIMATE_OpenA(ANIMATE_INFO *infoPtr, HINSTANCE hInstance, LPSTR lpszName) -{ - LPWSTR lpwszName; - LRESULT result; - INT len; - - if (!HIWORD(lpszName)) - return ANIMATE_OpenW(infoPtr, hInstance, (LPWSTR)lpszName); - - len = MultiByteToWideChar(CP_ACP, 0, lpszName, -1, NULL, 0); - lpwszName = Alloc(len * sizeof(WCHAR)); - if (!lpwszName) return FALSE; - MultiByteToWideChar(CP_ACP, 0, lpszName, -1, lpwszName, len); - - result = ANIMATE_OpenW(infoPtr, hInstance, lpwszName); - Free (lpwszName); - return result; -} - - -static BOOL ANIMATE_Stop(ANIMATE_INFO *infoPtr) -{ - /* nothing opened */ - if (!infoPtr->hMMio) - return FALSE; - - ANIMATE_DoStop(infoPtr); - return TRUE; -} - - -static BOOL ANIMATE_Create(HWND hWnd, LPCREATESTRUCTW lpcs) -{ - static const WCHAR msvfw32W[] = { 'm', 's', 'v', 'f', 'w', '3', '2', '.', 'd', 'l', 'l', 0 }; - ANIMATE_INFO *infoPtr; - - if (!fnIC.hModule) - { - fnIC.hModule = LoadLibraryW(msvfw32W); - if (!fnIC.hModule) return FALSE; - - fnIC.fnICOpen = (void*)GetProcAddress(fnIC.hModule, "ICOpen"); - fnIC.fnICClose = (void*)GetProcAddress(fnIC.hModule, "ICClose"); - fnIC.fnICSendMessage = (void*)GetProcAddress(fnIC.hModule, "ICSendMessage"); - fnIC.fnICDecompress = (void*)GetProcAddress(fnIC.hModule, "ICDecompress"); - } - - /* allocate memory for info structure */ - infoPtr = (ANIMATE_INFO *)Alloc(sizeof(ANIMATE_INFO)); - if (!infoPtr) return FALSE; - - /* store crossref hWnd <-> info structure */ - SetWindowLongPtrW(hWnd, 0, (DWORD_PTR)infoPtr); - infoPtr->hwndSelf = hWnd; - infoPtr->hwndNotify = lpcs->hwndParent; - infoPtr->transparentColor = ANIMATE_COLOR_NONE; - infoPtr->hbmPrevFrame = 0; - infoPtr->dwStyle = lpcs->style; - - TRACE("Animate style=0x%08lx, parent=%p\n", infoPtr->dwStyle, infoPtr->hwndNotify); - - InitializeCriticalSection(&infoPtr->cs); - - return TRUE; -} - - -static LRESULT ANIMATE_Destroy(ANIMATE_INFO *infoPtr) -{ - /* free avi data */ - ANIMATE_Free(infoPtr); - - /* free animate info data */ - SetWindowLongPtrW(infoPtr->hwndSelf, 0, 0); - - DeleteCriticalSection(&infoPtr->cs); - Free(infoPtr); - - return 0; -} - - -static BOOL ANIMATE_EraseBackground(ANIMATE_INFO *infoPtr, HDC hdc) -{ - RECT rect; - HBRUSH hBrush = 0; - - if(infoPtr->dwStyle & ACS_TRANSPARENT) - { - hBrush = (HBRUSH)SendMessageW(infoPtr->hwndNotify, WM_CTLCOLORSTATIC, - (WPARAM)hdc, (LPARAM)infoPtr->hwndSelf); - } - - GetClientRect(infoPtr->hwndSelf, &rect); - FillRect(hdc, &rect, hBrush ? hBrush : GetCurrentObject(hdc, OBJ_BRUSH)); - - return TRUE; -} - - -static LRESULT ANIMATE_StyleChanged(ANIMATE_INFO *infoPtr, WPARAM wStyleType, LPSTYLESTRUCT lpss) -{ - TRACE("(styletype=%x, styleOld=0x%08lx, styleNew=0x%08lx)\n", - wStyleType, lpss->styleOld, lpss->styleNew); - - if (wStyleType != GWL_STYLE) return 0; - - infoPtr->dwStyle = lpss->styleNew; - - InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); - return 0; -} - - -static LRESULT WINAPI ANIMATE_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - ANIMATE_INFO *infoPtr = (ANIMATE_INFO *)GetWindowLongPtrW(hWnd, 0); - - TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hWnd, uMsg, wParam, lParam); - if (!infoPtr && (uMsg != WM_NCCREATE)) - return DefWindowProcW(hWnd, uMsg, wParam, lParam); - switch (uMsg) - { - case ACM_OPENA: - return ANIMATE_OpenA(infoPtr, (HINSTANCE)wParam, (LPSTR)lParam); - - case ACM_OPENW: - return ANIMATE_OpenW(infoPtr, (HINSTANCE)wParam, (LPWSTR)lParam); - - case ACM_PLAY: - return ANIMATE_Play(infoPtr, (INT)wParam, LOWORD(lParam), HIWORD(lParam)); - - case ACM_STOP: - return ANIMATE_Stop(infoPtr); - - case WM_CLOSE: - ANIMATE_Free(infoPtr); - return 0; - - case WM_NCCREATE: - return ANIMATE_Create(hWnd, (LPCREATESTRUCTW)lParam); - - case WM_NCHITTEST: - return HTTRANSPARENT; - - case WM_DESTROY: - return ANIMATE_Destroy(infoPtr); - - case WM_ERASEBKGND: - return ANIMATE_EraseBackground(infoPtr, (HDC)wParam); - - case WM_STYLECHANGED: - return ANIMATE_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam); - - case WM_TIMER: - return ANIMATE_Timer(infoPtr); - - case WM_PAINT: - { - /* the animation isn't playing, or has not decompressed - * (and displayed) the first frame yet, don't paint - */ - if ((!infoPtr->uTimer && !infoPtr->hThread) || - !infoPtr->hbmPrevFrame) - { - /* default paint handling */ - return DefWindowProcW(hWnd, uMsg, wParam, lParam); - } - - if (infoPtr->dwStyle & ACS_TRANSPARENT) - infoPtr->hbrushBG = (HBRUSH)SendMessageW(infoPtr->hwndNotify, - WM_CTLCOLORSTATIC, - wParam, (LPARAM)infoPtr->hwndSelf); - - if (wParam) - { - EnterCriticalSection(&infoPtr->cs); - ANIMATE_PaintFrame(infoPtr, (HDC)wParam); - LeaveCriticalSection(&infoPtr->cs); - } - else - { - PAINTSTRUCT ps; - HDC hDC = BeginPaint(infoPtr->hwndSelf, &ps); - - EnterCriticalSection(&infoPtr->cs); - ANIMATE_PaintFrame(infoPtr, hDC); - LeaveCriticalSection(&infoPtr->cs); - - EndPaint(infoPtr->hwndSelf, &ps); - } - } - break; - - case WM_SIZE: - if (infoPtr->dwStyle & ACS_CENTER) - InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); - return DefWindowProcW(hWnd, uMsg, wParam, lParam); - - default: - if ((uMsg >= WM_USER) && (uMsg < WM_APP)) - ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam); - - return DefWindowProcW(hWnd, uMsg, wParam, lParam); - } - return 0; -} - -void ANIMATE_Register(void) -{ - WNDCLASSW wndClass; - - ZeroMemory(&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS; - wndClass.lpfnWndProc = ANIMATE_WindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(ANIMATE_INFO *); - wndClass.hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW); - wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); - wndClass.lpszClassName = ANIMATE_CLASSW; - - RegisterClassW(&wndClass); -} - - -void ANIMATE_Unregister(void) -{ - UnregisterClassW(ANIMATE_CLASSW, NULL); -} +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ +/* + * Animation control + * + * Copyright 1998, 1999 Eric Kohl + * Copyright 1999 Eric Pouech + * Copyright 2005 Dimitrie O. Paun + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES + * + * This code was audited for completeness against the documented features + * of Comctl32.dll version 6.0 on Mar. 15, 2005, by Dimitrie O. Paun. + * + * Unless otherwise noted, we believe this code to be complete, as per + * the specification mentioned above. + * If you discover missing features, or bugs, please note them below. + * + * TODO: + * - check for the 'rec ' list in some AVI files + */ + +#define COM_NO_WINDOWS_H +#include +#include +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "vfw.h" +#include "mmsystem.h" +#include "comctl32.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(animate); + +static struct { + HMODULE hModule; + HIC (WINAPI *fnICOpen)(DWORD, DWORD, UINT); + LRESULT (WINAPI *fnICClose)(HIC); + LRESULT (WINAPI *fnICSendMessage)(HIC, UINT, DWORD, DWORD); + DWORD (WINAPIV *fnICDecompress)(HIC,DWORD,LPBITMAPINFOHEADER,LPVOID,LPBITMAPINFOHEADER,LPVOID); +} fnIC; + +typedef struct +{ + /* reference to input stream (file or resource) */ + HGLOBAL hRes; + HMMIO hMMio; /* handle to mmio stream */ + HWND hwndSelf; + HWND hwndNotify; + DWORD dwStyle; + /* information on the loaded AVI file */ + MainAVIHeader mah; + AVIStreamHeader ash; + LPBITMAPINFOHEADER inbih; + LPDWORD lpIndex; + /* data for the decompressor */ + HIC hic; + LPBITMAPINFOHEADER outbih; + LPVOID indata; + LPVOID outdata; + /* data for the background mechanism */ + CRITICAL_SECTION cs; + HANDLE hStopEvent; + HANDLE hThread; + DWORD threadId; + UINT uTimer; + /* data for playing the file */ + int nFromFrame; + int nToFrame; + int nLoop; + int currFrame; + /* tranparency info*/ + COLORREF transparentColor; + HBRUSH hbrushBG; + HBITMAP hbmPrevFrame; +} ANIMATE_INFO; + +#define ANIMATE_COLOR_NONE 0xffffffff + +static void ANIMATE_Notify(ANIMATE_INFO *infoPtr, UINT notif) +{ + SendMessageW(infoPtr->hwndNotify, WM_COMMAND, + MAKEWPARAM(GetDlgCtrlID(infoPtr->hwndSelf), notif), + (LPARAM)infoPtr->hwndSelf); +} + +static BOOL ANIMATE_LoadResW(ANIMATE_INFO *infoPtr, HINSTANCE hInst, LPWSTR lpName) +{ + static const WCHAR aviW[] = { 'A', 'V', 'I', 0 }; + HRSRC hrsrc; + MMIOINFO mminfo; + LPVOID lpAvi; + + hrsrc = FindResourceW(hInst, lpName, aviW); + if (!hrsrc) + return FALSE; + + infoPtr->hRes = LoadResource(hInst, hrsrc); + if (!infoPtr->hRes) + return FALSE; + + lpAvi = LockResource(infoPtr->hRes); + if (!lpAvi) + return FALSE; + + memset(&mminfo, 0, sizeof(mminfo)); + mminfo.fccIOProc = FOURCC_MEM; + mminfo.pchBuffer = (LPSTR)lpAvi; + mminfo.cchBuffer = SizeofResource(hInst, hrsrc); + infoPtr->hMMio = mmioOpenW(NULL, &mminfo, MMIO_READ); + if (!infoPtr->hMMio) + { + FreeResource(infoPtr->hRes); + return FALSE; + } + + return TRUE; +} + + +static BOOL ANIMATE_LoadFileW(ANIMATE_INFO *infoPtr, LPWSTR lpName) +{ + infoPtr->hMMio = mmioOpenW(lpName, 0, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE); + + return (BOOL)infoPtr->hMMio; +} + + +static BOOL ANIMATE_DoStop(ANIMATE_INFO *infoPtr) +{ + EnterCriticalSection(&infoPtr->cs); + + /* should stop playing */ + if (infoPtr->hThread) + { + HANDLE handle = infoPtr->hThread; + + TRACE("stopping animation thread\n"); + infoPtr->hThread = 0; + SetEvent( infoPtr->hStopEvent ); + + if (infoPtr->threadId != GetCurrentThreadId()) + { + LeaveCriticalSection(&infoPtr->cs); /* leave it a chance to run */ + WaitForSingleObject( handle, INFINITE ); + TRACE("animation thread stopped\n"); + EnterCriticalSection(&infoPtr->cs); + } + + CloseHandle( handle ); + CloseHandle( infoPtr->hStopEvent ); + infoPtr->hStopEvent = 0; + } + if (infoPtr->uTimer) { + KillTimer(infoPtr->hwndSelf, infoPtr->uTimer); + infoPtr->uTimer = 0; + } + + LeaveCriticalSection(&infoPtr->cs); + + ANIMATE_Notify(infoPtr, ACN_STOP); + + return TRUE; +} + + +static void ANIMATE_Free(ANIMATE_INFO *infoPtr) +{ + if (infoPtr->hMMio) { + ANIMATE_DoStop(infoPtr); + mmioClose(infoPtr->hMMio, 0); + if (infoPtr->hRes) { + FreeResource(infoPtr->hRes); + infoPtr->hRes = 0; + } + Free (infoPtr->lpIndex); + infoPtr->lpIndex = NULL; + if (infoPtr->hic) { + fnIC.fnICClose(infoPtr->hic); + infoPtr->hic = 0; + } + Free (infoPtr->inbih); + infoPtr->inbih = NULL; + Free (infoPtr->outbih); + infoPtr->outbih = NULL; + Free (infoPtr->indata); + infoPtr->indata = NULL; + Free (infoPtr->outdata); + infoPtr->outdata = NULL; + if( infoPtr->hbmPrevFrame ) + { + DeleteObject(infoPtr->hbmPrevFrame); + infoPtr->hbmPrevFrame = 0; + } + + memset(&infoPtr->mah, 0, sizeof(infoPtr->mah)); + memset(&infoPtr->ash, 0, sizeof(infoPtr->ash)); + infoPtr->nFromFrame = infoPtr->nToFrame = infoPtr->nLoop = infoPtr->currFrame = 0; + } + infoPtr->transparentColor = ANIMATE_COLOR_NONE; +} + +static void ANIMATE_TransparentBlt(ANIMATE_INFO *infoPtr, HDC hdcDest, HDC hdcSource) +{ + HDC hdcMask; + HBITMAP hbmMask; + HBITMAP hbmOld; + + /* create a transparency mask */ + hdcMask = CreateCompatibleDC(hdcDest); + hbmMask = CreateBitmap(infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, 1,1,NULL); + hbmOld = SelectObject(hdcMask, hbmMask); + + SetBkColor(hdcSource,infoPtr->transparentColor); + BitBlt(hdcMask,0,0,infoPtr->inbih->biWidth, infoPtr->inbih->biHeight,hdcSource,0,0,SRCCOPY); + + /* mask the source bitmap */ + SetBkColor(hdcSource, RGB(0,0,0)); + SetTextColor(hdcSource, RGB(255,255,255)); + BitBlt(hdcSource, 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, hdcMask, 0, 0, SRCAND); + + /* mask the destination bitmap */ + SetBkColor(hdcDest, RGB(255,255,255)); + SetTextColor(hdcDest, RGB(0,0,0)); + BitBlt(hdcDest, 0, 0, infoPtr->inbih->biWidth, infoPtr->inbih->biHeight, hdcMask, 0, 0, SRCAND); + + /* combine source and destination */ + BitBlt(hdcDest,0,0,infoPtr->inbih->biWidth, infoPtr->inbih->biHeight,hdcSource,0,0,SRCPAINT); + + SelectObject(hdcMask, hbmOld); + DeleteObject(hbmMask); + DeleteDC(hdcMask); +} + +static BOOL ANIMATE_PaintFrame(ANIMATE_INFO* infoPtr, HDC hDC) +{ + void* pBitmapData = NULL; + LPBITMAPINFO pBitmapInfo = NULL; + + HDC hdcMem; + HBITMAP hbmOld; + + int nOffsetX = 0; + int nOffsetY = 0; + + int nWidth; + int nHeight; + + if (!hDC || !infoPtr->inbih) + return TRUE; + + if (infoPtr->hic ) + { + pBitmapData = infoPtr->outdata; + pBitmapInfo = (LPBITMAPINFO)infoPtr->outbih; + + nWidth = infoPtr->outbih->biWidth; + nHeight = infoPtr->outbih->biHeight; + } + else + { + pBitmapData = infoPtr->indata; + pBitmapInfo = (LPBITMAPINFO)infoPtr->inbih; + + nWidth = infoPtr->inbih->biWidth; + nHeight = infoPtr->inbih->biHeight; + } + + if(!infoPtr->hbmPrevFrame) + { + infoPtr->hbmPrevFrame=CreateCompatibleBitmap(hDC, nWidth,nHeight ); + } + + SetDIBits(hDC, infoPtr->hbmPrevFrame, 0, nHeight, pBitmapData, (LPBITMAPINFO)pBitmapInfo, DIB_RGB_COLORS); + + hdcMem = CreateCompatibleDC(hDC); + hbmOld = SelectObject(hdcMem, infoPtr->hbmPrevFrame); + + /* + * we need to get the transparent color even without ACS_TRANSPARENT, + * because the style can be changed later on and the color should always + * be obtained in the first frame + */ + if(infoPtr->transparentColor == ANIMATE_COLOR_NONE) + { + infoPtr->transparentColor = GetPixel(hdcMem,0,0); + } + + if(infoPtr->dwStyle & ACS_TRANSPARENT) + { + HDC hdcFinal = CreateCompatibleDC(hDC); + HBITMAP hbmFinal = CreateCompatibleBitmap(hDC,nWidth, nHeight); + HBITMAP hbmOld2 = SelectObject(hdcFinal, hbmFinal); + RECT rect; + + rect.left = 0; + rect.top = 0; + rect.right = nWidth; + rect.bottom = nHeight; + + if(!infoPtr->hbrushBG) + infoPtr->hbrushBG = GetCurrentObject(hDC, OBJ_BRUSH); + + FillRect(hdcFinal, &rect, infoPtr->hbrushBG); + ANIMATE_TransparentBlt(infoPtr, hdcFinal, hdcMem); + + SelectObject(hdcFinal, hbmOld2); + SelectObject(hdcMem, hbmFinal); + DeleteDC(hdcFinal); + DeleteObject(infoPtr->hbmPrevFrame); + infoPtr->hbmPrevFrame = hbmFinal; + } + + if (infoPtr->dwStyle & ACS_CENTER) + { + RECT rect; + + GetWindowRect(infoPtr->hwndSelf, &rect); + nOffsetX = ((rect.right - rect.left) - nWidth)/2; + nOffsetY = ((rect.bottom - rect.top) - nHeight)/2; + } + BitBlt(hDC, nOffsetX, nOffsetY, nWidth, nHeight, hdcMem, 0, 0, SRCCOPY); + + SelectObject(hdcMem, hbmOld); + DeleteDC(hdcMem); + return TRUE; +} + +static BOOL ANIMATE_DrawFrame(ANIMATE_INFO *infoPtr) +{ + HDC hDC; + + TRACE("Drawing frame %d (loop %d)\n", infoPtr->currFrame, infoPtr->nLoop); + + mmioSeek(infoPtr->hMMio, infoPtr->lpIndex[infoPtr->currFrame], SEEK_SET); + mmioRead(infoPtr->hMMio, infoPtr->indata, infoPtr->ash.dwSuggestedBufferSize); + + if (infoPtr->hic && + fnIC.fnICDecompress(infoPtr->hic, 0, infoPtr->inbih, infoPtr->indata, + infoPtr->outbih, infoPtr->outdata) != ICERR_OK) { + WARN("Decompression error\n"); + return FALSE; + } + + if ((hDC = GetDC(infoPtr->hwndSelf)) != 0) { + ANIMATE_PaintFrame(infoPtr, hDC); + ReleaseDC(infoPtr->hwndSelf, hDC); + } + + if (infoPtr->currFrame++ >= infoPtr->nToFrame) { + infoPtr->currFrame = infoPtr->nFromFrame; + if (infoPtr->nLoop != -1) { + if (--infoPtr->nLoop == 0) { + ANIMATE_DoStop(infoPtr); + } + } + } + + return TRUE; +} + +static LRESULT ANIMATE_Timer(ANIMATE_INFO *infoPtr) +{ + /* FIXME: we should pass the hDC instead of 0 to WM_CTLCOLORSTATIC */ + if (infoPtr->dwStyle & ACS_TRANSPARENT) + infoPtr->hbrushBG = (HBRUSH)SendMessageW(infoPtr->hwndNotify, + WM_CTLCOLORSTATIC, + 0, (LPARAM)infoPtr->hwndSelf); + EnterCriticalSection(&infoPtr->cs); + ANIMATE_DrawFrame(infoPtr); + LeaveCriticalSection(&infoPtr->cs); + + return 0; +} + +static DWORD CALLBACK ANIMATE_AnimationThread(LPVOID ptr_) +{ + ANIMATE_INFO *infoPtr = (ANIMATE_INFO *)ptr_; + HANDLE event; + DWORD timeout; + + while(1) + { + EnterCriticalSection(&infoPtr->cs); + ANIMATE_DrawFrame(infoPtr); + timeout = infoPtr->mah.dwMicroSecPerFrame; + event = infoPtr->hStopEvent; + LeaveCriticalSection(&infoPtr->cs); + + /* time is in microseconds, we should convert it to milliseconds */ + if ((event == 0) || WaitForSingleObject( event, (timeout+500)/1000) == WAIT_OBJECT_0) + break; + } + return TRUE; +} + +static LRESULT ANIMATE_Play(ANIMATE_INFO *infoPtr, UINT cRepeat, WORD wFrom, WORD wTo) +{ + /* nothing opened */ + if (!infoPtr->hMMio) + return FALSE; + + if (infoPtr->hThread || infoPtr->uTimer) { + TRACE("Already playing\n"); + return TRUE; + } + + infoPtr->nFromFrame = wFrom; + infoPtr->nToFrame = wTo; + infoPtr->nLoop = cRepeat; + + if (infoPtr->nToFrame == 0xFFFF) + infoPtr->nToFrame = infoPtr->mah.dwTotalFrames - 1; + + TRACE("(repeat=%d from=%d to=%d);\n", + infoPtr->nLoop, infoPtr->nFromFrame, infoPtr->nToFrame); + + if (infoPtr->nFromFrame >= infoPtr->nToFrame || + infoPtr->nToFrame >= infoPtr->mah.dwTotalFrames) + return FALSE; + + infoPtr->currFrame = infoPtr->nFromFrame; + + if (infoPtr->dwStyle & ACS_TIMER) + { + TRACE("Using a timer\n"); + /* create a timer to display AVI */ + infoPtr->uTimer = SetTimer(infoPtr->hwndSelf, 1, + infoPtr->mah.dwMicroSecPerFrame / 1000, NULL); + } + else + { + if(infoPtr->dwStyle & ACS_TRANSPARENT) + infoPtr->hbrushBG = (HBRUSH)SendMessageW(infoPtr->hwndNotify, + WM_CTLCOLORSTATIC, 0, + (LPARAM)infoPtr->hwndSelf); + + TRACE("Using an animation thread\n"); + infoPtr->hStopEvent = CreateEventW( NULL, TRUE, FALSE, NULL ); + infoPtr->hThread = CreateThread(0, 0, ANIMATE_AnimationThread, + (LPVOID)infoPtr, 0, &infoPtr->threadId); + if(!infoPtr->hThread) return FALSE; + + } + + ANIMATE_Notify(infoPtr, ACN_START); + + return TRUE; +} + + +static BOOL ANIMATE_GetAviInfo(ANIMATE_INFO *infoPtr) +{ + MMCKINFO ckMainRIFF; + MMCKINFO mmckHead; + MMCKINFO mmckList; + MMCKINFO mmckInfo; + DWORD numFrame; + DWORD insize; + + if (mmioDescend(infoPtr->hMMio, &ckMainRIFF, NULL, 0) != 0) { + WARN("Can't find 'RIFF' chunk\n"); + return FALSE; + } + + if ((ckMainRIFF.ckid != FOURCC_RIFF) || + (ckMainRIFF.fccType != mmioFOURCC('A', 'V', 'I', ' '))) { + WARN("Can't find 'AVI ' chunk\n"); + return FALSE; + } + + mmckHead.fccType = mmioFOURCC('h', 'd', 'r', 'l'); + if (mmioDescend(infoPtr->hMMio, &mmckHead, &ckMainRIFF, MMIO_FINDLIST) != 0) { + WARN("Can't find 'hdrl' list\n"); + return FALSE; + } + + mmckInfo.ckid = mmioFOURCC('a', 'v', 'i', 'h'); + if (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckHead, MMIO_FINDCHUNK) != 0) { + WARN("Can't find 'avih' chunk\n"); + return FALSE; + } + + mmioRead(infoPtr->hMMio, (LPSTR)&infoPtr->mah, sizeof(infoPtr->mah)); + + TRACE("mah.dwMicroSecPerFrame=%ld\n", infoPtr->mah.dwMicroSecPerFrame); + TRACE("mah.dwMaxBytesPerSec=%ld\n", infoPtr->mah.dwMaxBytesPerSec); + TRACE("mah.dwPaddingGranularity=%ld\n", infoPtr->mah.dwPaddingGranularity); + TRACE("mah.dwFlags=%ld\n", infoPtr->mah.dwFlags); + TRACE("mah.dwTotalFrames=%ld\n", infoPtr->mah.dwTotalFrames); + TRACE("mah.dwInitialFrames=%ld\n", infoPtr->mah.dwInitialFrames); + TRACE("mah.dwStreams=%ld\n", infoPtr->mah.dwStreams); + TRACE("mah.dwSuggestedBufferSize=%ld\n", infoPtr->mah.dwSuggestedBufferSize); + TRACE("mah.dwWidth=%ld\n", infoPtr->mah.dwWidth); + TRACE("mah.dwHeight=%ld\n", infoPtr->mah.dwHeight); + + mmioAscend(infoPtr->hMMio, &mmckInfo, 0); + + mmckList.fccType = mmioFOURCC('s', 't', 'r', 'l'); + if (mmioDescend(infoPtr->hMMio, &mmckList, &mmckHead, MMIO_FINDLIST) != 0) { + WARN("Can't find 'strl' list\n"); + return FALSE; + } + + mmckInfo.ckid = mmioFOURCC('s', 't', 'r', 'h'); + if (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, MMIO_FINDCHUNK) != 0) { + WARN("Can't find 'strh' chunk\n"); + return FALSE; + } + + mmioRead(infoPtr->hMMio, (LPSTR)&infoPtr->ash, sizeof(infoPtr->ash)); + + TRACE("ash.fccType='%c%c%c%c'\n", LOBYTE(LOWORD(infoPtr->ash.fccType)), + HIBYTE(LOWORD(infoPtr->ash.fccType)), + LOBYTE(HIWORD(infoPtr->ash.fccType)), + HIBYTE(HIWORD(infoPtr->ash.fccType))); + TRACE("ash.fccHandler='%c%c%c%c'\n", LOBYTE(LOWORD(infoPtr->ash.fccHandler)), + HIBYTE(LOWORD(infoPtr->ash.fccHandler)), + LOBYTE(HIWORD(infoPtr->ash.fccHandler)), + HIBYTE(HIWORD(infoPtr->ash.fccHandler))); + TRACE("ash.dwFlags=%ld\n", infoPtr->ash.dwFlags); + TRACE("ash.wPriority=%d\n", infoPtr->ash.wPriority); + TRACE("ash.wLanguage=%d\n", infoPtr->ash.wLanguage); + TRACE("ash.dwInitialFrames=%ld\n", infoPtr->ash.dwInitialFrames); + TRACE("ash.dwScale=%ld\n", infoPtr->ash.dwScale); + TRACE("ash.dwRate=%ld\n", infoPtr->ash.dwRate); + TRACE("ash.dwStart=%ld\n", infoPtr->ash.dwStart); + TRACE("ash.dwLength=%ld\n", infoPtr->ash.dwLength); + TRACE("ash.dwSuggestedBufferSize=%ld\n", infoPtr->ash.dwSuggestedBufferSize); + TRACE("ash.dwQuality=%ld\n", infoPtr->ash.dwQuality); + TRACE("ash.dwSampleSize=%ld\n", infoPtr->ash.dwSampleSize); + TRACE("ash.rcFrame=(%d,%d,%d,%d)\n", infoPtr->ash.rcFrame.top, infoPtr->ash.rcFrame.left, + infoPtr->ash.rcFrame.bottom, infoPtr->ash.rcFrame.right); + + mmioAscend(infoPtr->hMMio, &mmckInfo, 0); + + mmckInfo.ckid = mmioFOURCC('s', 't', 'r', 'f'); + if (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, MMIO_FINDCHUNK) != 0) { + WARN("Can't find 'strh' chunk\n"); + return FALSE; + } + + infoPtr->inbih = Alloc(mmckInfo.cksize); + if (!infoPtr->inbih) { + WARN("Can't alloc input BIH\n"); + return FALSE; + } + + mmioRead(infoPtr->hMMio, (LPSTR)infoPtr->inbih, mmckInfo.cksize); + + TRACE("bih.biSize=%ld\n", infoPtr->inbih->biSize); + TRACE("bih.biWidth=%ld\n", infoPtr->inbih->biWidth); + TRACE("bih.biHeight=%ld\n", infoPtr->inbih->biHeight); + TRACE("bih.biPlanes=%d\n", infoPtr->inbih->biPlanes); + TRACE("bih.biBitCount=%d\n", infoPtr->inbih->biBitCount); + TRACE("bih.biCompression=%ld\n", infoPtr->inbih->biCompression); + TRACE("bih.biSizeImage=%ld\n", infoPtr->inbih->biSizeImage); + TRACE("bih.biXPelsPerMeter=%ld\n", infoPtr->inbih->biXPelsPerMeter); + TRACE("bih.biYPelsPerMeter=%ld\n", infoPtr->inbih->biYPelsPerMeter); + TRACE("bih.biClrUsed=%ld\n", infoPtr->inbih->biClrUsed); + TRACE("bih.biClrImportant=%ld\n", infoPtr->inbih->biClrImportant); + + mmioAscend(infoPtr->hMMio, &mmckInfo, 0); + + mmioAscend(infoPtr->hMMio, &mmckList, 0); + +#if 0 + /* an AVI has 0 or 1 video stream, and to be animated should not contain + * an audio stream, so only one strl is allowed + */ + mmckList.fccType = mmioFOURCC('s', 't', 'r', 'l'); + if (mmioDescend(infoPtr->hMMio, &mmckList, &mmckHead, MMIO_FINDLIST) == 0) { + WARN("There should be a single 'strl' list\n"); + return FALSE; + } +#endif + + mmioAscend(infoPtr->hMMio, &mmckHead, 0); + + /* no need to read optional JUNK chunk */ + + mmckList.fccType = mmioFOURCC('m', 'o', 'v', 'i'); + if (mmioDescend(infoPtr->hMMio, &mmckList, &ckMainRIFF, MMIO_FINDLIST) != 0) { + WARN("Can't find 'movi' list\n"); + return FALSE; + } + + /* FIXME: should handle the 'rec ' LIST when present */ + + infoPtr->lpIndex = Alloc(infoPtr->mah.dwTotalFrames * sizeof(DWORD)); + if (!infoPtr->lpIndex) + return FALSE; + + numFrame = insize = 0; + while (mmioDescend(infoPtr->hMMio, &mmckInfo, &mmckList, 0) == 0 && + numFrame < infoPtr->mah.dwTotalFrames) { + infoPtr->lpIndex[numFrame] = mmckInfo.dwDataOffset; + if (insize < mmckInfo.cksize) + insize = mmckInfo.cksize; + numFrame++; + mmioAscend(infoPtr->hMMio, &mmckInfo, 0); + } + if (numFrame != infoPtr->mah.dwTotalFrames) { + WARN("Found %ld frames (/%ld)\n", numFrame, infoPtr->mah.dwTotalFrames); + return FALSE; + } + if (insize > infoPtr->ash.dwSuggestedBufferSize) { + WARN("insize=%ld suggestedSize=%ld\n", insize, infoPtr->ash.dwSuggestedBufferSize); + infoPtr->ash.dwSuggestedBufferSize = insize; + } + + infoPtr->indata = Alloc(infoPtr->ash.dwSuggestedBufferSize); + if (!infoPtr->indata) + return FALSE; + + return TRUE; +} + + +static BOOL ANIMATE_GetAviCodec(ANIMATE_INFO *infoPtr) +{ + DWORD outSize; + + /* check uncompressed AVI */ + if ((infoPtr->ash.fccHandler == mmioFOURCC('D', 'I', 'B', ' ')) || + (infoPtr->ash.fccHandler == mmioFOURCC('R', 'L', 'E', ' ')) || + (infoPtr->ash.fccHandler == mmioFOURCC(0, 0, 0, 0))) + { + infoPtr->hic = 0; + return TRUE; + } + + /* try to get a decompressor for that type */ + infoPtr->hic = fnIC.fnICOpen(ICTYPE_VIDEO, infoPtr->ash.fccHandler, ICMODE_DECOMPRESS); + if (!infoPtr->hic) { + WARN("Can't load codec for the file\n"); + return FALSE; + } + + outSize = fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_GET_FORMAT, + (DWORD)infoPtr->inbih, 0L); + + infoPtr->outbih = Alloc(outSize); + if (!infoPtr->outbih) + return FALSE; + + if (fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_GET_FORMAT, + (DWORD)infoPtr->inbih, (DWORD)infoPtr->outbih) != outSize) + { + WARN("Can't get output BIH\n"); + return FALSE; + } + + infoPtr->outdata = Alloc(infoPtr->outbih->biSizeImage); + if (!infoPtr->outdata) + return FALSE; + + if (fnIC.fnICSendMessage(infoPtr->hic, ICM_DECOMPRESS_BEGIN, + (DWORD)infoPtr->inbih, (DWORD)infoPtr->outbih) != ICERR_OK) { + WARN("Can't begin decompression\n"); + return FALSE; + } + + return TRUE; +} + + +static BOOL ANIMATE_OpenW(ANIMATE_INFO *infoPtr, HINSTANCE hInstance, LPWSTR lpszName) +{ + ANIMATE_Free(infoPtr); + + if (!lpszName) + { + TRACE("Closing avi!\n"); + /* installer of thebat! v1.62 requires FALSE here */ + return (infoPtr->hMMio != 0); + } + + if (!hInstance) + hInstance = (HINSTANCE)GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_HINSTANCE); + + if (HIWORD(lpszName)) + { + TRACE("(\"%s\");\n", debugstr_w(lpszName)); + + if (!ANIMATE_LoadResW(infoPtr, hInstance, lpszName)) + { + TRACE("No AVI resource found!\n"); + if (!ANIMATE_LoadFileW(infoPtr, lpszName)) + { + WARN("No AVI file found!\n"); + return FALSE; + } + } + } + else + { + TRACE("(%u);\n", (WORD)(DWORD)lpszName); + + if (!ANIMATE_LoadResW(infoPtr, hInstance, MAKEINTRESOURCEW((INT)lpszName))) + { + WARN("No AVI resource found!\n"); + return FALSE; + } + } + + if (!ANIMATE_GetAviInfo(infoPtr)) + { + WARN("Can't get AVI information\n"); + ANIMATE_Free(infoPtr); + return FALSE; + } + + if (!ANIMATE_GetAviCodec(infoPtr)) + { + WARN("Can't get AVI Codec\n"); + ANIMATE_Free(infoPtr); + return FALSE; + } + + if (!(infoPtr->dwStyle & ACS_CENTER)) + SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, infoPtr->mah.dwWidth, infoPtr->mah.dwHeight, + SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER); + + if (infoPtr->dwStyle & ACS_AUTOPLAY) + return ANIMATE_Play(infoPtr, -1, 0, infoPtr->mah.dwTotalFrames - 1); + + return TRUE; +} + + +static BOOL ANIMATE_OpenA(ANIMATE_INFO *infoPtr, HINSTANCE hInstance, LPSTR lpszName) +{ + LPWSTR lpwszName; + LRESULT result; + INT len; + + if (!HIWORD(lpszName)) + return ANIMATE_OpenW(infoPtr, hInstance, (LPWSTR)lpszName); + + len = MultiByteToWideChar(CP_ACP, 0, lpszName, -1, NULL, 0); + lpwszName = Alloc(len * sizeof(WCHAR)); + if (!lpwszName) return FALSE; + MultiByteToWideChar(CP_ACP, 0, lpszName, -1, lpwszName, len); + + result = ANIMATE_OpenW(infoPtr, hInstance, lpwszName); + Free (lpwszName); + return result; +} + + +static BOOL ANIMATE_Stop(ANIMATE_INFO *infoPtr) +{ + /* nothing opened */ + if (!infoPtr->hMMio) + return FALSE; + + ANIMATE_DoStop(infoPtr); + return TRUE; +} + + +static BOOL ANIMATE_Create(HWND hWnd, LPCREATESTRUCTW lpcs) +{ + static const WCHAR msvfw32W[] = { 'm', 's', 'v', 'f', 'w', '3', '2', '.', 'd', 'l', 'l', 0 }; + ANIMATE_INFO *infoPtr; + + if (!fnIC.hModule) + { + fnIC.hModule = LoadLibraryW(msvfw32W); + if (!fnIC.hModule) return FALSE; + + fnIC.fnICOpen = (void*)GetProcAddress(fnIC.hModule, "ICOpen"); + fnIC.fnICClose = (void*)GetProcAddress(fnIC.hModule, "ICClose"); + fnIC.fnICSendMessage = (void*)GetProcAddress(fnIC.hModule, "ICSendMessage"); + fnIC.fnICDecompress = (void*)GetProcAddress(fnIC.hModule, "ICDecompress"); + } + + /* allocate memory for info structure */ + infoPtr = (ANIMATE_INFO *)Alloc(sizeof(ANIMATE_INFO)); + if (!infoPtr) return FALSE; + + /* store crossref hWnd <-> info structure */ + SetWindowLongPtrW(hWnd, 0, (DWORD_PTR)infoPtr); + infoPtr->hwndSelf = hWnd; + infoPtr->hwndNotify = lpcs->hwndParent; + infoPtr->transparentColor = ANIMATE_COLOR_NONE; + infoPtr->hbmPrevFrame = 0; + infoPtr->dwStyle = lpcs->style; + + TRACE("Animate style=0x%08lx, parent=%p\n", infoPtr->dwStyle, infoPtr->hwndNotify); + + InitializeCriticalSection(&infoPtr->cs); + + return TRUE; +} + + +static LRESULT ANIMATE_Destroy(ANIMATE_INFO *infoPtr) +{ + /* free avi data */ + ANIMATE_Free(infoPtr); + + /* free animate info data */ + SetWindowLongPtrW(infoPtr->hwndSelf, 0, 0); + + DeleteCriticalSection(&infoPtr->cs); + Free(infoPtr); + + return 0; +} + + +static BOOL ANIMATE_EraseBackground(ANIMATE_INFO *infoPtr, HDC hdc) +{ + RECT rect; + HBRUSH hBrush = 0; + + if(infoPtr->dwStyle & ACS_TRANSPARENT) + { + hBrush = (HBRUSH)SendMessageW(infoPtr->hwndNotify, WM_CTLCOLORSTATIC, + (WPARAM)hdc, (LPARAM)infoPtr->hwndSelf); + } + + GetClientRect(infoPtr->hwndSelf, &rect); + FillRect(hdc, &rect, hBrush ? hBrush : GetCurrentObject(hdc, OBJ_BRUSH)); + + return TRUE; +} + + +static LRESULT ANIMATE_StyleChanged(ANIMATE_INFO *infoPtr, WPARAM wStyleType, LPSTYLESTRUCT lpss) +{ + TRACE("(styletype=%x, styleOld=0x%08lx, styleNew=0x%08lx)\n", + wStyleType, lpss->styleOld, lpss->styleNew); + + if (wStyleType != GWL_STYLE) return 0; + + infoPtr->dwStyle = lpss->styleNew; + + InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); + return 0; +} + + +static LRESULT WINAPI ANIMATE_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + ANIMATE_INFO *infoPtr = (ANIMATE_INFO *)GetWindowLongPtrW(hWnd, 0); + + TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hWnd, uMsg, wParam, lParam); + if (!infoPtr && (uMsg != WM_NCCREATE)) + return DefWindowProcW(hWnd, uMsg, wParam, lParam); + switch (uMsg) + { + case ACM_OPENA: + return ANIMATE_OpenA(infoPtr, (HINSTANCE)wParam, (LPSTR)lParam); + + case ACM_OPENW: + return ANIMATE_OpenW(infoPtr, (HINSTANCE)wParam, (LPWSTR)lParam); + + case ACM_PLAY: + return ANIMATE_Play(infoPtr, (INT)wParam, LOWORD(lParam), HIWORD(lParam)); + + case ACM_STOP: + return ANIMATE_Stop(infoPtr); + + case WM_CLOSE: + ANIMATE_Free(infoPtr); + return 0; + + case WM_NCCREATE: + return ANIMATE_Create(hWnd, (LPCREATESTRUCTW)lParam); + + case WM_NCHITTEST: + return HTTRANSPARENT; + + case WM_DESTROY: + return ANIMATE_Destroy(infoPtr); + + case WM_ERASEBKGND: + return ANIMATE_EraseBackground(infoPtr, (HDC)wParam); + + case WM_STYLECHANGED: + return ANIMATE_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam); + + case WM_TIMER: + return ANIMATE_Timer(infoPtr); + + case WM_PAINT: + { + /* the animation isn't playing, or has not decompressed + * (and displayed) the first frame yet, don't paint + */ + if ((!infoPtr->uTimer && !infoPtr->hThread) || + !infoPtr->hbmPrevFrame) + { + /* default paint handling */ + return DefWindowProcW(hWnd, uMsg, wParam, lParam); + } + + if (infoPtr->dwStyle & ACS_TRANSPARENT) + infoPtr->hbrushBG = (HBRUSH)SendMessageW(infoPtr->hwndNotify, + WM_CTLCOLORSTATIC, + wParam, (LPARAM)infoPtr->hwndSelf); + + if (wParam) + { + EnterCriticalSection(&infoPtr->cs); + ANIMATE_PaintFrame(infoPtr, (HDC)wParam); + LeaveCriticalSection(&infoPtr->cs); + } + else + { + PAINTSTRUCT ps; + HDC hDC = BeginPaint(infoPtr->hwndSelf, &ps); + + EnterCriticalSection(&infoPtr->cs); + ANIMATE_PaintFrame(infoPtr, hDC); + LeaveCriticalSection(&infoPtr->cs); + + EndPaint(infoPtr->hwndSelf, &ps); + } + } + break; + + case WM_SIZE: + if (infoPtr->dwStyle & ACS_CENTER) + InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); + return DefWindowProcW(hWnd, uMsg, wParam, lParam); + + default: + if ((uMsg >= WM_USER) && (uMsg < WM_APP)) + ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam); + + return DefWindowProcW(hWnd, uMsg, wParam, lParam); + } + return 0; +} + +void ANIMATE_Register(void) +{ + WNDCLASSW wndClass; + + ZeroMemory(&wndClass, sizeof(WNDCLASSW)); + wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS; + wndClass.lpfnWndProc = ANIMATE_WindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(ANIMATE_INFO *); + wndClass.hCursor = LoadCursorW(0, (LPCWSTR)IDC_ARROW); + wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); + wndClass.lpszClassName = ANIMATE_CLASSW; + + RegisterClassW(&wndClass); +} + + +void ANIMATE_Unregister(void) +{ + UnregisterClassW(ANIMATE_CLASSW, NULL); +} diff --git a/reactos/lib/comctl32/comboex.c b/reactos/lib/comctl32/comboex.c index f23caca7ede..3fcbbea0be3 100644 --- a/reactos/lib/comctl32/comboex.c +++ b/reactos/lib/comctl32/comboex.c @@ -1,2298 +1,2298 @@ -/* - * ComboBoxEx control - * - * Copyright 1998, 1999 Eric Kohl - * Copyright 2000, 2001, 2002 Guy Albertelli - * Copyright 2002 Dimitrie O. Paun - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTE - * - * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on Sep. 9, 2002, by Dimitrie O. Paun. - * - * Unless otherwise noted, we believe this code to be complete, as per - * the specification mentioned above. - * If you discover missing features, or bugs, please note them below. - * - */ - -#include -#include -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "comctl32.h" -#include "wine/debug.h" -#include "wine/unicode.h" - -WINE_DEFAULT_DEBUG_CHANNEL(comboex); - -/* Item structure */ -typedef struct _CBE_ITEMDATA -{ - struct _CBE_ITEMDATA *next; - UINT mask; - LPWSTR pszText; - LPWSTR pszTemp; - int cchTextMax; - int iImage; - int iSelectedImage; - int iOverlay; - int iIndent; - LPARAM lParam; -} CBE_ITEMDATA; - -/* ComboBoxEx structure */ -typedef struct -{ - HIMAGELIST himl; - HWND hwndSelf; /* my own hwnd */ - HWND hwndNotify; /* my parent hwnd */ - HWND hwndCombo; - HWND hwndEdit; - WNDPROC prevEditWndProc; /* previous Edit WNDPROC value */ - WNDPROC prevComboWndProc; /* previous Combo WNDPROC value */ - DWORD dwExtStyle; - INT selected; /* index of selected item */ - DWORD flags; /* WINE internal flags */ - HFONT defaultFont; - HFONT font; - INT nb_items; /* Number of items */ - BOOL unicode; /* TRUE if this window is Unicode */ - BOOL NtfUnicode; /* TRUE if parent wants notify in Unicode */ - CBE_ITEMDATA *edit; /* item data for edit item */ - CBE_ITEMDATA *items; /* Array of items */ -} COMBOEX_INFO; - -/* internal flags in the COMBOEX_INFO structure */ -#define WCBE_ACTEDIT 0x00000001 /* Edit active i.e. - * CBEN_BEGINEDIT issued - * but CBEN_ENDEDIT{A|W} - * not yet issued. */ -#define WCBE_EDITCHG 0x00000002 /* Edit issued EN_CHANGE */ -#define WCBE_EDITHASCHANGED (WCBE_ACTEDIT | WCBE_EDITCHG) -#define WCBE_EDITFOCUSED 0x00000004 /* Edit control has focus */ -#define WCBE_MOUSECAPTURED 0x00000008 /* Combo has captured mouse */ -#define WCBE_MOUSEDRAGGED 0x00000010 /* User has dragged in combo */ - -#define ID_CB_EDIT 1001 - - -/* - * Special flag set in DRAWITEMSTRUCT itemState field. It is set by - * the ComboEx version of the Combo Window Proc so that when the - * WM_DRAWITEM message is then passed to ComboEx, we know that this - * particular WM_DRAWITEM message is for listbox only items. Any messasges - * without this flag is then for the Edit control field. - * - * We really cannot use the ODS_COMBOBOXEDIT flag because MSDN states that - * only version 4.0 applications will have ODS_COMBOBOXEDIT set. - */ -#define ODS_COMBOEXLBOX 0x4000 - - - -/* Height in pixels of control over the amount of the selected font */ -#define CBE_EXTRA 3 - -/* Indent amount per MS documentation */ -#define CBE_INDENT 10 - -/* Offset in pixels from left side for start of image or text */ -#define CBE_STARTOFFSET 6 - -/* Offset between image and text */ -#define CBE_SEP 4 - -static const WCHAR COMBOEX_SUBCLASS_PROP[] = { - 'C','C','C','o','m','b','o','E','x','3','2', - 'S','u','b','c','l','a','s','s','I','n','f','o',0 -}; - -#define COMBOEX_GetInfoPtr(hwnd) ((COMBOEX_INFO *)GetWindowLongPtrW (hwnd, 0)) - - -/* Things common to the entire DLL */ -static LRESULT WINAPI COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); -static LRESULT WINAPI COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); -static LRESULT COMBOEX_Destroy (COMBOEX_INFO *infoPtr); -typedef INT (WINAPI *cmp_func_t)(LPCWSTR, LPCWSTR); - -inline static BOOL is_textW(LPCWSTR str) -{ - return str && str != LPSTR_TEXTCALLBACKW; -} - -inline static BOOL is_textA(LPCSTR str) -{ - return str && str != LPSTR_TEXTCALLBACKA; -} - -inline static LPCSTR debugstr_txt(LPCWSTR str) -{ - if (str == LPSTR_TEXTCALLBACKW) return "(callback)"; - return debugstr_w(str); -} - -static void COMBOEX_DumpItem (CBE_ITEMDATA *item) -{ - TRACE("item %p - mask=%08x, pszText=%p, cchTM=%d, iImage=%d\n", - item, item->mask, item->pszText, item->cchTextMax, item->iImage); - TRACE("item %p - iSelectedImage=%d, iOverlay=%d, iIndent=%d, lParam=%08lx\n", - item, item->iSelectedImage, item->iOverlay, item->iIndent, item->lParam); - if (item->mask & CBEIF_TEXT) - TRACE("item %p - pszText=%s\n", item, debugstr_txt(item->pszText)); -} - - -static void COMBOEX_DumpInput (COMBOBOXEXITEMW *input) -{ - TRACE("input - mask=%08x, iItem=%d, pszText=%p, cchTM=%d, iImage=%d\n", - input->mask, input->iItem, input->pszText, input->cchTextMax, - input->iImage); - if (input->mask & CBEIF_TEXT) - TRACE("input - pszText=<%s>\n", debugstr_txt(input->pszText)); - TRACE("input - iSelectedImage=%d, iOverlay=%d, iIndent=%d, lParam=%08lx\n", - input->iSelectedImage, input->iOverlay, input->iIndent, input->lParam); -} - - -inline static CBE_ITEMDATA *get_item_data(COMBOEX_INFO *infoPtr, INT index) -{ - return (CBE_ITEMDATA *)SendMessageW (infoPtr->hwndCombo, CB_GETITEMDATA, - (WPARAM)index, 0); -} - -inline static cmp_func_t get_cmp_func(COMBOEX_INFO *infoPtr) -{ - return infoPtr->dwExtStyle & CBES_EX_CASESENSITIVE ? lstrcmpW : lstrcmpiW; -} - -static INT COMBOEX_Notify (COMBOEX_INFO *infoPtr, INT code, NMHDR *hdr) -{ - hdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf); - hdr->hwndFrom = infoPtr->hwndSelf; - hdr->code = code; - if (infoPtr->NtfUnicode) - return SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, 0, (LPARAM)hdr); - else - return SendMessageA (infoPtr->hwndNotify, WM_NOTIFY, 0, (LPARAM)hdr); -} - - -static INT -COMBOEX_NotifyItem (COMBOEX_INFO *infoPtr, INT code, NMCOMBOBOXEXW *hdr) -{ - /* Change the Text item from Unicode to ANSI if necessary for NOTIFY */ - if (infoPtr->NtfUnicode) - return COMBOEX_Notify (infoPtr, code, &hdr->hdr); - else { - LPWSTR wstr = hdr->ceItem.pszText; - LPSTR astr = 0; - INT ret, len = 0; - - if ((hdr->ceItem.mask & CBEIF_TEXT) && is_textW(wstr)) { - len = WideCharToMultiByte (CP_ACP, 0, wstr, -1, 0, 0, NULL, NULL); - if (len > 0) { - astr = (LPSTR)Alloc ((len + 1)*sizeof(CHAR)); - if (!astr) return 0; - WideCharToMultiByte (CP_ACP, 0, wstr, -1, astr, len, 0, 0); - hdr->ceItem.pszText = (LPWSTR)astr; - } - } - - if (code == CBEN_ENDEDITW) code = CBEN_ENDEDITA; - else if (code == CBEN_GETDISPINFOW) code = CBEN_GETDISPINFOA; - else if (code == CBEN_DRAGBEGINW) code = CBEN_DRAGBEGINA; - - ret = COMBOEX_Notify (infoPtr, code, (NMHDR *)hdr); - - if (astr && hdr->ceItem.pszText == (LPWSTR)astr) - hdr->ceItem.pszText = wstr; - - if (astr) Free(astr); - - return ret; - } -} - - -static INT COMBOEX_NotifyEndEdit (COMBOEX_INFO *infoPtr, NMCBEENDEDITW *neew, LPCWSTR wstr) -{ - /* Change the Text item from Unicode to ANSI if necessary for NOTIFY */ - if (infoPtr->NtfUnicode) { - lstrcpynW(neew->szText, wstr, CBEMAXSTRLEN); - return COMBOEX_Notify (infoPtr, CBEN_ENDEDITW, &neew->hdr); - } else { - NMCBEENDEDITA neea; - - memcpy (&neea.hdr, &neew->hdr, sizeof(NMHDR)); - neea.fChanged = neew->fChanged; - neea.iNewSelection = neew->iNewSelection; - WideCharToMultiByte (CP_ACP, 0, wstr, -1, neea.szText, CBEMAXSTRLEN, 0, 0); - neea.iWhy = neew->iWhy; - - return COMBOEX_Notify (infoPtr, CBEN_ENDEDITA, &neea.hdr); - } -} - - -static void COMBOEX_NotifyDragBegin(COMBOEX_INFO *infoPtr, LPCWSTR wstr) -{ - /* Change the Text item from Unicode to ANSI if necessary for NOTIFY */ - if (infoPtr->NtfUnicode) { - NMCBEDRAGBEGINW ndbw; - - ndbw.iItemid = -1; - lstrcpynW(ndbw.szText, wstr, CBEMAXSTRLEN); - COMBOEX_Notify (infoPtr, CBEN_DRAGBEGINW, &ndbw.hdr); - } else { - NMCBEDRAGBEGINA ndba; - - ndba.iItemid = -1; - WideCharToMultiByte (CP_ACP, 0, wstr, -1, ndba.szText, CBEMAXSTRLEN, 0, 0); - - COMBOEX_Notify (infoPtr, CBEN_DRAGBEGINA, &ndba.hdr); - } -} - - -static void COMBOEX_FreeText (CBE_ITEMDATA *item) -{ - if (is_textW(item->pszText)) Free(item->pszText); - item->pszText = 0; - if (item->pszTemp) Free(item->pszTemp); - item->pszTemp = 0; -} - - -static INT COMBOEX_GetIndex(COMBOEX_INFO *infoPtr, CBE_ITEMDATA *item) -{ - CBE_ITEMDATA *moving; - INT index; - - moving = infoPtr->items; - index = infoPtr->nb_items - 1; - - while (moving && (moving != item)) { - moving = moving->next; - index--; - } - if (!moving || (index < 0)) { - ERR("COMBOBOXEX item structures broken. Please report!\n"); - return -1; - } - return index; -} - - -static LPCWSTR COMBOEX_GetText(COMBOEX_INFO *infoPtr, CBE_ITEMDATA *item) -{ - NMCOMBOBOXEXW nmce; - LPWSTR text, buf; - INT len; - - if (item->pszText != LPSTR_TEXTCALLBACKW) - return item->pszText; - - ZeroMemory(&nmce, sizeof(nmce)); - nmce.ceItem.mask = CBEIF_TEXT; - nmce.ceItem.lParam = item->lParam; - nmce.ceItem.iItem = COMBOEX_GetIndex(infoPtr, item); - COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce); - - if (is_textW(nmce.ceItem.pszText)) { - len = MultiByteToWideChar (CP_ACP, 0, (LPSTR)nmce.ceItem.pszText, -1, NULL, 0); - buf = (LPWSTR)Alloc ((len + 1)*sizeof(WCHAR)); - if (buf) - MultiByteToWideChar (CP_ACP, 0, (LPSTR)nmce.ceItem.pszText, -1, buf, len); - if (nmce.ceItem.mask & CBEIF_DI_SETITEM) { - COMBOEX_FreeText(item); - item->pszText = buf; - } else { - if (item->pszTemp) Free(item->pszTemp); - item->pszTemp = buf; - } - text = buf; - } else - text = nmce.ceItem.pszText; - - if (nmce.ceItem.mask & CBEIF_DI_SETITEM) - item->pszText = text; - return text; -} - - -static void COMBOEX_GetComboFontSize (COMBOEX_INFO *infoPtr, SIZE *size) -{ - static const WCHAR strA[] = { 'A', 0 }; - HFONT nfont, ofont; - HDC mydc; - - mydc = GetDC (0); /* why the entire screen???? */ - nfont = (HFONT)SendMessageW (infoPtr->hwndCombo, WM_GETFONT, 0, 0); - ofont = (HFONT) SelectObject (mydc, nfont); - GetTextExtentPointW (mydc, strA, 1, size); - SelectObject (mydc, ofont); - ReleaseDC (0, mydc); - TRACE("selected font hwnd=%p, height=%ld\n", nfont, size->cy); -} - - -static void COMBOEX_CopyItem (CBE_ITEMDATA *item, COMBOBOXEXITEMW *cit) -{ - if (cit->mask & CBEIF_TEXT) { - /* - * when given a text buffer actually use that buffer - */ - if (cit->pszText) { - if (is_textW(item->pszText)) - lstrcpynW(cit->pszText, item->pszText, cit->cchTextMax); - else - cit->pszText[0] = 0; - } else { - cit->pszText = item->pszText; - cit->cchTextMax = item->cchTextMax; - } - } - if (cit->mask & CBEIF_IMAGE) - cit->iImage = item->iImage; - if (cit->mask & CBEIF_SELECTEDIMAGE) - cit->iSelectedImage = item->iSelectedImage; - if (cit->mask & CBEIF_OVERLAY) - cit->iOverlay = item->iOverlay; - if (cit->mask & CBEIF_INDENT) - cit->iIndent = item->iIndent; - if (cit->mask & CBEIF_LPARAM) - cit->lParam = item->lParam; -} - - -static void COMBOEX_AdjustEditPos (COMBOEX_INFO *infoPtr) -{ - SIZE mysize; - INT x, y, w, h, xioff; - RECT rect; - - if (!infoPtr->hwndEdit) return; - - if (infoPtr->himl && !(infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGEINDENT)) { - IMAGEINFO iinfo; - iinfo.rcImage.left = iinfo.rcImage.right = 0; - ImageList_GetImageInfo(infoPtr->himl, 0, &iinfo); - xioff = iinfo.rcImage.right - iinfo.rcImage.left + CBE_SEP; - } else xioff = 0; - - GetClientRect (infoPtr->hwndCombo, &rect); - InflateRect (&rect, -2, -2); - InvalidateRect (infoPtr->hwndCombo, &rect, TRUE); - - /* reposition the Edit control based on whether icon exists */ - COMBOEX_GetComboFontSize (infoPtr, &mysize); - TRACE("Combo font x=%ld, y=%ld\n", mysize.cx, mysize.cy); - x = xioff + CBE_STARTOFFSET + 1; - w = rect.right-rect.left - x - GetSystemMetrics(SM_CXVSCROLL) - 1; - h = mysize.cy + 1; - y = rect.bottom - h - 1; - - TRACE("Combo client (%ld,%ld)-(%ld,%ld), setting Edit to (%d,%d)-(%d,%d)\n", - rect.left, rect.top, rect.right, rect.bottom, x, y, x + w, y + h); - SetWindowPos(infoPtr->hwndEdit, HWND_TOP, x, y, w, h, - SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER); -} - - -static void COMBOEX_ReSize (COMBOEX_INFO *infoPtr) -{ - SIZE mysize; - LONG cy; - IMAGEINFO iinfo; - - COMBOEX_GetComboFontSize (infoPtr, &mysize); - cy = mysize.cy + CBE_EXTRA; - if (infoPtr->himl && ImageList_GetImageInfo(infoPtr->himl, 0, &iinfo)) { - cy = max (iinfo.rcImage.bottom - iinfo.rcImage.top, cy); - TRACE("upgraded height due to image: height=%ld\n", cy); - } - SendMessageW (infoPtr->hwndSelf, CB_SETITEMHEIGHT, (WPARAM)-1, (LPARAM)cy); - if (infoPtr->hwndCombo) { - SendMessageW (infoPtr->hwndCombo, CB_SETITEMHEIGHT, - (WPARAM) 0, (LPARAM) cy); - if ( !(infoPtr->flags & CBES_EX_NOSIZELIMIT)) { - RECT comboRect; - if (GetWindowRect(infoPtr->hwndCombo, &comboRect)) { - RECT ourRect; - if (GetWindowRect(infoPtr->hwndSelf, &ourRect)) { - if (comboRect.bottom > ourRect.bottom) { - POINT pt = { ourRect.left, ourRect.top }; - if (ScreenToClient(infoPtr->hwndSelf, &pt)) - MoveWindow( infoPtr->hwndSelf, pt.x, pt.y, ourRect.right - ourRect.left, - comboRect.bottom - comboRect.top, FALSE); - } - } - } - } - } -} - - -static void COMBOEX_SetEditText (COMBOEX_INFO *infoPtr, CBE_ITEMDATA *item) -{ - if (!infoPtr->hwndEdit) return; - /* native issues the following messages to the {Edit} control */ - /* WM_SETTEXT (0,addr) */ - /* EM_SETSEL32 (0,0) */ - /* EM_SETSEL32 (0,-1) */ - if (item->mask & CBEIF_TEXT) { - SendMessageW (infoPtr->hwndEdit, WM_SETTEXT, 0, (LPARAM)COMBOEX_GetText(infoPtr, item)); - SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, 0); - SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, -1); - } -} - - -static CBE_ITEMDATA * COMBOEX_FindItem(COMBOEX_INFO *infoPtr, INT index) -{ - CBE_ITEMDATA *item; - INT i; - - if ((index > infoPtr->nb_items) || (index < -1)) - return 0; - if (index == -1) - return infoPtr->edit; - item = infoPtr->items; - i = infoPtr->nb_items - 1; - - /* find the item in the list */ - while (item && (i > index)) { - item = item->next; - i--; - } - if (!item || (i != index)) { - ERR("COMBOBOXEX item structures broken. Please report!\n"); - return 0; - } - return item; -} - - -static inline BOOL COMBOEX_HasEdit(COMBOEX_INFO *infoPtr) -{ - return infoPtr->hwndEdit ? TRUE : FALSE; -} - - -/* *** CBEM_xxx message support *** */ - - -static INT COMBOEX_DeleteItem (COMBOEX_INFO *infoPtr, INT index) -{ - CBE_ITEMDATA *item; - - TRACE("(index=%d)\n", index); - - /* if item number requested does not exist then return failure */ - if ((index > infoPtr->nb_items) || (index < 0)) return CB_ERR; - if (!(item = COMBOEX_FindItem(infoPtr, index))) return CB_ERR; - - /* doing this will result in WM_DELETEITEM being issued */ - SendMessageW (infoPtr->hwndCombo, CB_DELETESTRING, (WPARAM)index, 0); - - return infoPtr->nb_items; -} - - -static BOOL COMBOEX_GetItemW (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW *cit) -{ - INT index = cit->iItem; - CBE_ITEMDATA *item; - - TRACE("(...)\n"); - - /* if item number requested does not exist then return failure */ - if ((index > infoPtr->nb_items) || (index < -1)) return FALSE; - - /* if the item is the edit control and there is no edit control, skip */ - if ((index == -1) && !COMBOEX_HasEdit(infoPtr)) return FALSE; - - if (!(item = COMBOEX_FindItem(infoPtr, index))) return FALSE; - - COMBOEX_CopyItem (item, cit); - - return TRUE; -} - - -static BOOL COMBOEX_GetItemA (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMA *cit) -{ - COMBOBOXEXITEMW tmpcit; - - TRACE("(...)\n"); - - tmpcit.mask = cit->mask; - tmpcit.iItem = cit->iItem; - tmpcit.pszText = 0; - if(!COMBOEX_GetItemW (infoPtr, &tmpcit)) return FALSE; - - if (is_textW(tmpcit.pszText) && cit->pszText) - WideCharToMultiByte (CP_ACP, 0, tmpcit.pszText, -1, - cit->pszText, cit->cchTextMax, NULL, NULL); - else if (cit->pszText) cit->pszText[0] = 0; - else cit->pszText = (LPSTR)tmpcit.pszText; - - cit->iImage = tmpcit.iImage; - cit->iSelectedImage = tmpcit.iSelectedImage; - cit->iOverlay = tmpcit.iOverlay; - cit->iIndent = tmpcit.iIndent; - cit->lParam = tmpcit.lParam; - - return TRUE; -} - - -inline static BOOL COMBOEX_HasEditChanged (COMBOEX_INFO *infoPtr) -{ - return COMBOEX_HasEdit(infoPtr) && - (infoPtr->flags & WCBE_EDITHASCHANGED) == WCBE_EDITHASCHANGED; -} - - -static INT COMBOEX_InsertItemW (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW *cit) -{ - INT index; - CBE_ITEMDATA *item; - NMCOMBOBOXEXW nmcit; - - TRACE("\n"); - - if (TRACE_ON(comboex)) COMBOEX_DumpInput (cit); - - /* get real index of item to insert */ - index = cit->iItem; - if (index == -1) index = infoPtr->nb_items; - if (index > infoPtr->nb_items) index = infoPtr->nb_items; - - /* get zero-filled space and chain it in */ - if(!(item = (CBE_ITEMDATA *)Alloc (sizeof(*item)))) return -1; - - /* locate position to insert new item in */ - if (index == infoPtr->nb_items) { - /* fast path for iItem = -1 */ - item->next = infoPtr->items; - infoPtr->items = item; - } - else { - INT i = infoPtr->nb_items-1; - CBE_ITEMDATA *moving = infoPtr->items; - - while ((i > index) && moving) { - moving = moving->next; - i--; - } - if (!moving) { - ERR("COMBOBOXEX item structures broken. Please report!\n"); - Free(item); - return -1; - } - item->next = moving->next; - moving->next = item; - } - - /* fill in our hidden item structure */ - item->mask = cit->mask; - if (item->mask & CBEIF_TEXT) { - INT len = 0; - - if (is_textW(cit->pszText)) len = strlenW (cit->pszText); - if (len > 0) { - item->pszText = (LPWSTR)Alloc ((len + 1)*sizeof(WCHAR)); - if (!item->pszText) { - Free(item); - return -1; - } - strcpyW (item->pszText, cit->pszText); - } - else if (cit->pszText == LPSTR_TEXTCALLBACKW) - item->pszText = LPSTR_TEXTCALLBACKW; - item->cchTextMax = cit->cchTextMax; - } - if (item->mask & CBEIF_IMAGE) - item->iImage = cit->iImage; - if (item->mask & CBEIF_SELECTEDIMAGE) - item->iSelectedImage = cit->iSelectedImage; - if (item->mask & CBEIF_OVERLAY) - item->iOverlay = cit->iOverlay; - if (item->mask & CBEIF_INDENT) - item->iIndent = cit->iIndent; - if (item->mask & CBEIF_LPARAM) - item->lParam = cit->lParam; - infoPtr->nb_items++; - - if (TRACE_ON(comboex)) COMBOEX_DumpItem (item); - - SendMessageW (infoPtr->hwndCombo, CB_INSERTSTRING, - (WPARAM)cit->iItem, (LPARAM)item); - - memset (&nmcit.ceItem, 0, sizeof(nmcit.ceItem)); - COMBOEX_CopyItem (item, &nmcit.ceItem); - COMBOEX_NotifyItem (infoPtr, CBEN_INSERTITEM, &nmcit); - - return index; - -} - - -static INT COMBOEX_InsertItemA (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMA *cit) -{ - COMBOBOXEXITEMW citW; - LPWSTR wstr = NULL; - INT ret; - - memcpy(&citW,cit,sizeof(COMBOBOXEXITEMA)); - if (cit->mask & CBEIF_TEXT && is_textA(cit->pszText)) { - INT len = MultiByteToWideChar (CP_ACP, 0, cit->pszText, -1, NULL, 0); - wstr = (LPWSTR)Alloc ((len + 1)*sizeof(WCHAR)); - if (!wstr) return -1; - MultiByteToWideChar (CP_ACP, 0, cit->pszText, -1, wstr, len); - citW.pszText = wstr; - } - ret = COMBOEX_InsertItemW(infoPtr, &citW); - - if (wstr) Free(wstr); - - return ret; -} - - -static DWORD -COMBOEX_SetExtendedStyle (COMBOEX_INFO *infoPtr, DWORD mask, DWORD style) -{ - DWORD dwTemp; - - TRACE("(mask=x%08lx, style=0x%08lx)\n", mask, style); - - dwTemp = infoPtr->dwExtStyle; - - if (mask) - infoPtr->dwExtStyle = (infoPtr->dwExtStyle & ~mask) | style; - else - infoPtr->dwExtStyle = style; - - /* see if we need to change the word break proc on the edit */ - if ((infoPtr->dwExtStyle ^ dwTemp) & CBES_EX_PATHWORDBREAKPROC) - SetPathWordBreakProc(infoPtr->hwndEdit, - (infoPtr->dwExtStyle & CBES_EX_PATHWORDBREAKPROC) ? TRUE : FALSE); - - /* test if the control's appearance has changed */ - mask = CBES_EX_NOEDITIMAGE | CBES_EX_NOEDITIMAGEINDENT; - if ((infoPtr->dwExtStyle & mask) != (dwTemp & mask)) { - /* if state of EX_NOEDITIMAGE changes, invalidate all */ - TRACE("EX_NOEDITIMAGE state changed to %ld\n", - infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGE); - InvalidateRect (infoPtr->hwndSelf, NULL, TRUE); - COMBOEX_AdjustEditPos (infoPtr); - if (infoPtr->hwndEdit) - InvalidateRect (infoPtr->hwndEdit, NULL, TRUE); - } - - return dwTemp; -} - - -static HIMAGELIST COMBOEX_SetImageList (COMBOEX_INFO *infoPtr, HIMAGELIST himl) -{ - HIMAGELIST himlTemp = infoPtr->himl; - - TRACE("(...)\n"); - - infoPtr->himl = himl; - - COMBOEX_ReSize (infoPtr); - InvalidateRect (infoPtr->hwndCombo, NULL, TRUE); - - /* reposition the Edit control based on whether icon exists */ - COMBOEX_AdjustEditPos (infoPtr); - return himlTemp; -} - -static BOOL COMBOEX_SetItemW (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW *cit) -{ - INT index = cit->iItem; - CBE_ITEMDATA *item; - - if (TRACE_ON(comboex)) COMBOEX_DumpInput (cit); - - /* if item number requested does not exist then return failure */ - if ((index > infoPtr->nb_items) || (index < -1)) return FALSE; - - /* if the item is the edit control and there is no edit control, skip */ - if ((index == -1) && !COMBOEX_HasEdit(infoPtr)) return FALSE; - - if (!(item = COMBOEX_FindItem(infoPtr, index))) return FALSE; - - /* add/change stuff to the internal item structure */ - item->mask |= cit->mask; - if (cit->mask & CBEIF_TEXT) { - INT len = 0; - - COMBOEX_FreeText(item); - if (is_textW(cit->pszText)) len = strlenW(cit->pszText); - if (len > 0) { - item->pszText = (LPWSTR)Alloc ((len + 1)*sizeof(WCHAR)); - if (!item->pszText) return FALSE; - strcpyW(item->pszText, cit->pszText); - } else if (cit->pszText == LPSTR_TEXTCALLBACKW) - item->pszText = LPSTR_TEXTCALLBACKW; - item->cchTextMax = cit->cchTextMax; - } - if (cit->mask & CBEIF_IMAGE) - item->iImage = cit->iImage; - if (cit->mask & CBEIF_SELECTEDIMAGE) - item->iSelectedImage = cit->iSelectedImage; - if (cit->mask & CBEIF_OVERLAY) - item->iOverlay = cit->iOverlay; - if (cit->mask & CBEIF_INDENT) - item->iIndent = cit->iIndent; - if (cit->mask & CBEIF_LPARAM) - cit->lParam = cit->lParam; - - if (TRACE_ON(comboex)) COMBOEX_DumpItem (item); - - /* if original request was to update edit control, do some fast foot work */ - if (cit->iItem == -1) { - COMBOEX_SetEditText (infoPtr, item); - RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE | RDW_INVALIDATE); - } - return TRUE; -} - -static BOOL COMBOEX_SetItemA (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMA *cit) -{ - COMBOBOXEXITEMW citW; - LPWSTR wstr = NULL; - BOOL ret; - - memcpy(&citW, cit, sizeof(COMBOBOXEXITEMA)); - if ((cit->mask & CBEIF_TEXT) && is_textA(cit->pszText)) { - INT len = MultiByteToWideChar (CP_ACP, 0, cit->pszText, -1, NULL, 0); - wstr = (LPWSTR)Alloc ((len + 1)*sizeof(WCHAR)); - if (!wstr) return FALSE; - MultiByteToWideChar (CP_ACP, 0, cit->pszText, -1, wstr, len); - citW.pszText = wstr; - } - ret = COMBOEX_SetItemW(infoPtr, &citW); - - if (wstr) Free(wstr); - - return ret; -} - - -static BOOL COMBOEX_SetUnicodeFormat (COMBOEX_INFO *infoPtr, BOOL value) -{ - BOOL bTemp = infoPtr->unicode; - - TRACE("to %s, was %s\n", value ? "TRUE":"FALSE", bTemp ? "TRUE":"FALSE"); - - infoPtr->unicode = value; - - return bTemp; -} - - -/* *** CB_xxx message support *** */ - -static INT -COMBOEX_FindStringExact (COMBOEX_INFO *infoPtr, INT start, LPCWSTR str) -{ - INT i; - cmp_func_t cmptext = get_cmp_func(infoPtr); - INT count = SendMessageW (infoPtr->hwndCombo, CB_GETCOUNT, 0, 0); - - /* now search from after starting loc and wrapping back to start */ - for(i=start+1; imask & CBEIF_LPARAM) ret = item1->lParam; - TRACE("returning 0x%08lx\n", ret); - } else { - ret = (DWORD)item1; - TRACE("non-valid result from combo, returning 0x%08lx\n", ret); - } - return ret; -} - - -static INT COMBOEX_SetCursel (COMBOEX_INFO *infoPtr, INT index) -{ - CBE_ITEMDATA *item; - INT sel; - - if (!(item = COMBOEX_FindItem(infoPtr, index))) - return SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL, index, 0); - - TRACE("selecting item %d text=%s\n", index, debugstr_txt(item->pszText)); - infoPtr->selected = index; - - sel = (INT)SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL, index, 0); - COMBOEX_SetEditText (infoPtr, item); - return sel; -} - - -static DWORD COMBOEX_SetItemData (COMBOEX_INFO *infoPtr, INT index, DWORD data) -{ - CBE_ITEMDATA *item1, *item2; - - item1 = get_item_data(infoPtr, index); - if ((item1 != NULL) && ((LRESULT)item1 != CB_ERR)) { - item2 = COMBOEX_FindItem (infoPtr, index); - if (item2 != item1) { - ERR("data structures damaged!\n"); - return CB_ERR; - } - item1->mask |= CBEIF_LPARAM; - item1->lParam = data; - TRACE("setting lparam to 0x%08lx\n", data); - return 0; - } - TRACE("non-valid result from combo 0x%08lx\n", (DWORD)item1); - return (LRESULT)item1; -} - - -static INT COMBOEX_SetItemHeight (COMBOEX_INFO *infoPtr, INT index, UINT height) -{ - RECT cb_wrect, cbx_wrect, cbx_crect; - - /* First, lets forward the message to the normal combo control - just like Windows. */ - if (infoPtr->hwndCombo) - if (SendMessageW (infoPtr->hwndCombo, CB_SETITEMHEIGHT, - index, height) == CB_ERR) return CB_ERR; - - GetWindowRect (infoPtr->hwndCombo, &cb_wrect); - GetWindowRect (infoPtr->hwndSelf, &cbx_wrect); - GetClientRect (infoPtr->hwndSelf, &cbx_crect); - /* the height of comboex as height of the combo + comboex border */ - height = cb_wrect.bottom-cb_wrect.top - + cbx_wrect.bottom-cbx_wrect.top - - (cbx_crect.bottom-cbx_crect.top); - TRACE("EX window=(%ld,%ld)-(%ld,%ld), client=(%ld,%ld)-(%ld,%ld)\n", - cbx_wrect.left, cbx_wrect.top, cbx_wrect.right, cbx_wrect.bottom, - cbx_crect.left, cbx_crect.top, cbx_crect.right, cbx_crect.bottom); - TRACE("CB window=(%ld,%ld)-(%ld,%ld), EX setting=(0,0)-(%ld,%d)\n", - cb_wrect.left, cb_wrect.top, cb_wrect.right, cb_wrect.bottom, - cbx_wrect.right-cbx_wrect.left, height); - SetWindowPos (infoPtr->hwndSelf, HWND_TOP, 0, 0, - cbx_wrect.right-cbx_wrect.left, height, - SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE); - - return 0; -} - - -/* *** WM_xxx message support *** */ - - -static LRESULT COMBOEX_Create (HWND hwnd, LPCREATESTRUCTA cs) -{ - static const WCHAR COMBOBOX[] = { 'C', 'o', 'm', 'b', 'o', 'B', 'o', 'x', 0 }; - static const WCHAR EDIT[] = { 'E', 'D', 'I', 'T', 0 }; - static const WCHAR NIL[] = { 0 }; - COMBOEX_INFO *infoPtr; - LOGFONTW mylogfont; - RECT wnrc1, clrc1, cmbwrc; - INT i; - - /* allocate memory for info structure */ - infoPtr = (COMBOEX_INFO *)Alloc (sizeof(COMBOEX_INFO)); - if (!infoPtr) return -1; - - /* initialize info structure */ - /* note that infoPtr is allocated zero-filled */ - - infoPtr->hwndSelf = hwnd; - infoPtr->selected = -1; - - infoPtr->unicode = IsWindowUnicode (hwnd); - infoPtr->hwndNotify = cs->hwndParent; - - i = SendMessageW(infoPtr->hwndNotify, WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY); - if ((i != NFR_ANSI) && (i != NFR_UNICODE)) { - WARN("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n", i); - i = NFR_ANSI; - } - infoPtr->NtfUnicode = (i == NFR_UNICODE); - - SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); - - /* create combo box */ - GetWindowRect(hwnd, &wnrc1); - GetClientRect(hwnd, &clrc1); - TRACE("EX window=(%ld,%ld)-(%ld,%ld) client=(%ld,%ld)-(%ld,%ld)\n", - wnrc1.left, wnrc1.top, wnrc1.right, wnrc1.bottom, - clrc1.left, clrc1.top, clrc1.right, clrc1.bottom); - - /* Native version of ComboEx creates the ComboBox with DROPDOWNLIST */ - /* specified. It then creates it's own version of the EDIT control */ - /* and makes the ComboBox the parent. This is because a normal */ - /* DROPDOWNLIST does not have an EDIT control, but we need one. */ - /* We also need to place the edit control at the proper location */ - /* (allow space for the icons). */ - - infoPtr->hwndCombo = CreateWindowW (COMBOBOX, NIL, - /* following line added to match native */ - WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VSCROLL | - CBS_NOINTEGRALHEIGHT | CBS_DROPDOWNLIST | - /* was base and is necessary */ - WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED | - GetWindowLongW (hwnd, GWL_STYLE), - cs->y, cs->x, cs->cx, cs->cy, hwnd, - (HMENU) GetWindowLongPtrW (hwnd, GWLP_ID), - (HINSTANCE)GetWindowLongPtrW (hwnd, GWLP_HINSTANCE), NULL); - - /* - * native does the following at this point according to trace: - * GetWindowThreadProcessId(hwndCombo,0) - * GetCurrentThreadId() - * GetWindowThreadProcessId(hwndCombo, &???) - * GetCurrentProcessId() - */ - - /* - * Setup a property to hold the pointer to the COMBOBOXEX - * data structure. - */ - SetPropW(infoPtr->hwndCombo, COMBOEX_SUBCLASS_PROP, hwnd); - infoPtr->prevComboWndProc = (WNDPROC)SetWindowLongPtrW(infoPtr->hwndCombo, - GWLP_WNDPROC, (DWORD_PTR)COMBOEX_ComboWndProc); - infoPtr->font = (HFONT)SendMessageW (infoPtr->hwndCombo, WM_GETFONT, 0, 0); - - - /* - * Now create our own EDIT control so we can position it. - * It is created only for CBS_DROPDOWN style - */ - if ((cs->style & CBS_DROPDOWNLIST) == CBS_DROPDOWN) { - infoPtr->hwndEdit = CreateWindowExW (0, EDIT, NIL, - WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | ES_AUTOHSCROLL, - 0, 0, 0, 0, /* will set later */ - infoPtr->hwndCombo, - (HMENU) GetWindowLongPtrW (hwnd, GWLP_ID), - (HINSTANCE)GetWindowLongPtrW (hwnd, GWLP_HINSTANCE), NULL); - - /* native does the following at this point according to trace: - * GetWindowThreadProcessId(hwndEdit,0) - * GetCurrentThreadId() - * GetWindowThreadProcessId(hwndEdit, &???) - * GetCurrentProcessId() - */ - - /* - * Setup a property to hold the pointer to the COMBOBOXEX - * data structure. - */ - SetPropW(infoPtr->hwndEdit, COMBOEX_SUBCLASS_PROP, hwnd); - infoPtr->prevEditWndProc = (WNDPROC)SetWindowLongPtrW(infoPtr->hwndEdit, - GWLP_WNDPROC, (DWORD_PTR)COMBOEX_EditWndProc); - infoPtr->font = (HFONT)SendMessageW(infoPtr->hwndCombo, WM_GETFONT, 0, 0); - } - - /* - * Locate the default font if necessary and then set it in - * all associated controls - */ - if (!infoPtr->font) { - SystemParametersInfoW (SPI_GETICONTITLELOGFONT, sizeof(mylogfont), - &mylogfont, 0); - infoPtr->font = infoPtr->defaultFont = CreateFontIndirectW (&mylogfont); - } - SendMessageW (infoPtr->hwndCombo, WM_SETFONT, (WPARAM)infoPtr->font, 0); - if (infoPtr->hwndEdit) { - SendMessageW (infoPtr->hwndEdit, WM_SETFONT, (WPARAM)infoPtr->font, 0); - SendMessageW (infoPtr->hwndEdit, EM_SETMARGINS, (WPARAM)EC_USEFONTINFO, 0); - } - - COMBOEX_ReSize (infoPtr); - - /* Above is fairly certain, below is much less certain. */ - - GetWindowRect(hwnd, &wnrc1); - GetClientRect(hwnd, &clrc1); - GetWindowRect(infoPtr->hwndCombo, &cmbwrc); - TRACE("EX window=(%ld,%ld)-(%ld,%ld) client=(%ld,%ld)-(%ld,%ld) CB wnd=(%ld,%ld)-(%ld,%ld)\n", - wnrc1.left, wnrc1.top, wnrc1.right, wnrc1.bottom, - clrc1.left, clrc1.top, clrc1.right, clrc1.bottom, - cmbwrc.left, cmbwrc.top, cmbwrc.right, cmbwrc.bottom); - SetWindowPos(infoPtr->hwndCombo, HWND_TOP, - 0, 0, wnrc1.right-wnrc1.left, wnrc1.bottom-wnrc1.top, - SWP_NOACTIVATE | SWP_NOREDRAW); - - GetWindowRect(infoPtr->hwndCombo, &cmbwrc); - TRACE("CB window=(%ld,%ld)-(%ld,%ld)\n", - cmbwrc.left, cmbwrc.top, cmbwrc.right, cmbwrc.bottom); - SetWindowPos(hwnd, HWND_TOP, - 0, 0, cmbwrc.right-cmbwrc.left, cmbwrc.bottom-cmbwrc.top, - SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE); - - COMBOEX_AdjustEditPos (infoPtr); - - /* - * Create an item structure to represent the data in the - * EDIT control. It is allocated zero-filled. - */ - infoPtr->edit = (CBE_ITEMDATA *)Alloc (sizeof (CBE_ITEMDATA)); - if (!infoPtr->edit) { - COMBOEX_Destroy(infoPtr); - return -1; - } - - return 0; -} - - -static LRESULT COMBOEX_Command (COMBOEX_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - LRESULT lret; - INT command = HIWORD(wParam); - CBE_ITEMDATA *item = 0; - WCHAR wintext[520]; - INT cursel, n, oldItem; - NMCBEENDEDITW cbeend; - DWORD oldflags; - HWND parent = infoPtr->hwndNotify; - - TRACE("for command %d\n", command); - - switch (command) - { - case CBN_DROPDOWN: - SetFocus (infoPtr->hwndCombo); - ShowWindow (infoPtr->hwndEdit, SW_HIDE); - return SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf); - - case CBN_CLOSEUP: - SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf); - /* - * from native trace of first dropdown after typing in URL in IE4 - * CB_GETCURSEL(Combo) - * GetWindowText(Edit) - * CB_GETCURSEL(Combo) - * CB_GETCOUNT(Combo) - * CB_GETITEMDATA(Combo, n) - * WM_NOTIFY(parent, CBEN_ENDEDITA|W) - * CB_GETCURSEL(Combo) - * CB_SETCURSEL(COMBOEX, n) - * SetFocus(Combo) - * the rest is supposition - */ - ShowWindow (infoPtr->hwndEdit, SW_SHOW); - InvalidateRect (infoPtr->hwndCombo, 0, TRUE); - InvalidateRect (infoPtr->hwndEdit, 0, TRUE); - cursel = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0); - if (cursel == -1) { - cmp_func_t cmptext = get_cmp_func(infoPtr); - /* find match from edit against those in Combobox */ - GetWindowTextW (infoPtr->hwndEdit, wintext, 520); - n = SendMessageW (infoPtr->hwndCombo, CB_GETCOUNT, 0, 0); - for (cursel = 0; cursel < n; cursel++){ - item = get_item_data(infoPtr, cursel); - if ((INT)item == CB_ERR) break; - if (!cmptext(COMBOEX_GetText(infoPtr, item), wintext)) break; - } - if ((cursel == n) || ((INT)item == CB_ERR)) { - TRACE("failed to find match??? item=%p cursel=%d\n", - item, cursel); - if (infoPtr->hwndEdit) - SetFocus(infoPtr->hwndEdit); - return 0; - } - } - else { - item = get_item_data(infoPtr, cursel); - if ((INT)item == CB_ERR) { - TRACE("failed to find match??? item=%p cursel=%d\n", - item, cursel); - if (infoPtr->hwndEdit) - SetFocus(infoPtr->hwndEdit); - return 0; - } - } - - /* Save flags for testing and reset them */ - oldflags = infoPtr->flags; - infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG); - - if (oldflags & WCBE_ACTEDIT) { - cbeend.fChanged = (oldflags & WCBE_EDITCHG); - cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo, - CB_GETCURSEL, 0, 0); - cbeend.iWhy = CBENF_DROPDOWN; - - if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, COMBOEX_GetText(infoPtr, item))) return 0; - } - - /* if selection has changed the set the new current selection */ - cursel = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0); - if ((oldflags & WCBE_EDITCHG) || (cursel != infoPtr->selected)) { - infoPtr->selected = cursel; - SendMessageW (infoPtr->hwndSelf, CB_SETCURSEL, cursel, 0); - SetFocus(infoPtr->hwndCombo); - } - return 0; - - case CBN_SELCHANGE: - /* - * CB_GETCURSEL(Combo) - * CB_GETITEMDATA(Combo) < simulated by COMBOEX_FindItem - * lstrlenA - * WM_SETTEXT(Edit) - * WM_GETTEXTLENGTH(Edit) - * WM_GETTEXT(Edit) - * EM_SETSEL(Edit, 0,0) - * WM_GETTEXTLENGTH(Edit) - * WM_GETTEXT(Edit) - * EM_SETSEL(Edit, 0,len) - * return WM_COMMAND to parent - */ - oldItem = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0); - if (!(item = COMBOEX_FindItem(infoPtr, oldItem))) { - ERR("item %d not found. Problem!\n", oldItem); - break; - } - infoPtr->selected = oldItem; - COMBOEX_SetEditText (infoPtr, item); - return SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf); - - case CBN_SELENDOK: - /* - * We have to change the handle since we are the control - * issuing the message. IE4 depends on this. - */ - return SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf); - - case CBN_KILLFOCUS: - /* - * from native trace: - * - * pass to parent - * WM_GETTEXT(Edit, 104) - * CB_GETCURSEL(Combo) rets -1 - * WM_NOTIFY(CBEN_ENDEDITA) with CBENF_KILLFOCUS - * CB_GETCURSEL(Combo) - * InvalidateRect(Combo, 0, 0) - * return 0 - */ - SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf); - if (infoPtr->flags & WCBE_ACTEDIT) { - GetWindowTextW (infoPtr->hwndEdit, wintext, 260); - cbeend.fChanged = (infoPtr->flags & WCBE_EDITCHG); - cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo, - CB_GETCURSEL, 0, 0); - cbeend.iWhy = CBENF_KILLFOCUS; - - infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG); - if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, wintext)) return 0; - } - /* possible CB_GETCURSEL */ - InvalidateRect (infoPtr->hwndCombo, 0, 0); - return 0; - - default: - /* - * We have to change the handle since we are the control - * issuing the message. IE4 depends on this. - * We also need to set the focus back to the Edit control - * after passing the command to the parent of the ComboEx. - */ - lret = SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf); - if (infoPtr->hwndEdit) - SetFocus(infoPtr->hwndEdit); - return lret; - } - return 0; -} - - -static BOOL COMBOEX_WM_DeleteItem (COMBOEX_INFO *infoPtr, DELETEITEMSTRUCT *dis) -{ - CBE_ITEMDATA *item, *olditem; - NMCOMBOBOXEXW nmcit; - UINT i; - - TRACE("CtlType=%08x, CtlID=%08x, itemID=%08x, hwnd=%p, data=%08lx\n", - dis->CtlType, dis->CtlID, dis->itemID, dis->hwndItem, dis->itemData); - - if (dis->itemID >= infoPtr->nb_items) return FALSE; - - olditem = infoPtr->items; - i = infoPtr->nb_items - 1; - - if (i == dis->itemID) { - infoPtr->items = infoPtr->items->next; - } - else { - item = olditem; - i--; - - /* find the prior item in the list */ - while (item->next && (i > dis->itemID)) { - item = item->next; - i--; - } - if (!item->next || (i != dis->itemID)) { - ERR("COMBOBOXEX item structures broken. Please report!\n"); - return FALSE; - } - olditem = item->next; - item->next = item->next->next; - } - infoPtr->nb_items--; - - memset (&nmcit.ceItem, 0, sizeof(nmcit.ceItem)); - COMBOEX_CopyItem (olditem, &nmcit.ceItem); - COMBOEX_NotifyItem (infoPtr, CBEN_DELETEITEM, &nmcit); - - COMBOEX_FreeText(olditem); - Free(olditem); - - return TRUE; -} - - -static LRESULT COMBOEX_DrawItem (COMBOEX_INFO *infoPtr, DRAWITEMSTRUCT *dis) -{ - static const WCHAR nil[] = { 0 }; - CBE_ITEMDATA *item = 0; - SIZE txtsize; - RECT rect; - LPCWSTR str = nil; - UINT xbase, x, y; - INT len; - COLORREF nbkc, ntxc, bkc, txc; - int drawimage, drawstate, xioff; - - if (!IsWindowEnabled(infoPtr->hwndCombo)) return 0; - - TRACE("DRAWITEMSTRUCT: CtlType=0x%08x CtlID=0x%08x\n", - dis->CtlType, dis->CtlID); - TRACE("itemID=0x%08x itemAction=0x%08x itemState=0x%08x\n", - dis->itemID, dis->itemAction, dis->itemState); - TRACE("hWnd=%p hDC=%p (%ld,%ld)-(%ld,%ld) itemData=0x%08lx\n", - dis->hwndItem, dis->hDC, dis->rcItem.left, - dis->rcItem.top, dis->rcItem.right, dis->rcItem.bottom, - dis->itemData); - - /* MSDN says: */ - /* "itemID - Specifies the menu item identifier for a menu */ - /* item or the index of the item in a list box or combo box. */ - /* For an empty list box or combo box, this member can be -1. */ - /* This allows the application to draw only the focus */ - /* rectangle at the coordinates specified by the rcItem */ - /* member even though there are no items in the control. */ - /* This indicates to the user whether the list box or combo */ - /* box has the focus. How the bits are set in the itemAction */ - /* member determines whether the rectangle is to be drawn as */ - /* though the list box or combo box has the focus. */ - if (dis->itemID == 0xffffffff) { - if ( ( (dis->itemAction & ODA_FOCUS) && (dis->itemState & ODS_SELECTED)) || - ( (dis->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)) && (dis->itemState & ODS_FOCUS) ) ) { - - TRACE("drawing item -1 special focus, rect=(%ld,%ld)-(%ld,%ld)\n", - dis->rcItem.left, dis->rcItem.top, - dis->rcItem.right, dis->rcItem.bottom); - } - else if ((dis->CtlType == ODT_COMBOBOX) && - (dis->itemAction == ODA_DRAWENTIRE)) { - /* draw of edit control data */ - - /* testing */ - { - RECT exrc, cbrc, edrc; - GetWindowRect (infoPtr->hwndSelf, &exrc); - GetWindowRect (infoPtr->hwndCombo, &cbrc); - edrc.left=edrc.top=edrc.right=edrc.bottom=-1; - if (infoPtr->hwndEdit) - GetWindowRect (infoPtr->hwndEdit, &edrc); - TRACE("window rects ex=(%ld,%ld)-(%ld,%ld), cb=(%ld,%ld)-(%ld,%ld), ed=(%ld,%ld)-(%ld,%ld)\n", - exrc.left, exrc.top, exrc.right, exrc.bottom, - cbrc.left, cbrc.top, cbrc.right, cbrc.bottom, - edrc.left, edrc.top, edrc.right, edrc.bottom); - } - } - else { - ERR("NOT drawing item -1 special focus, rect=(%ld,%ld)-(%ld,%ld), action=%08x, state=%08x\n", - dis->rcItem.left, dis->rcItem.top, - dis->rcItem.right, dis->rcItem.bottom, - dis->itemAction, dis->itemState); - return 0; - } - } - - /* If draw item is -1 (edit control) setup the item pointer */ - if (dis->itemID == 0xffffffff) { - item = infoPtr->edit; - - if (infoPtr->hwndEdit) { - INT len; - - /* free previous text of edit item */ - COMBOEX_FreeText(item); - item->mask &= ~CBEIF_TEXT; - if( (len = GetWindowTextLengthW(infoPtr->hwndEdit)) ) { - item->mask |= CBEIF_TEXT; - item->pszText = (LPWSTR)Alloc ((len + 1)*sizeof(WCHAR)); - if (item->pszText) - GetWindowTextW(infoPtr->hwndEdit, item->pszText, len+1); - - TRACE("edit control hwndEdit=%p, text len=%d str=%s\n", - infoPtr->hwndEdit, len, debugstr_txt(item->pszText)); - } - } - } - - - /* if the item pointer is not set, then get the data and locate it */ - if (!item) { - item = get_item_data(infoPtr, dis->itemID); - if (item == (CBE_ITEMDATA *)CB_ERR) { - ERR("invalid item for id %d \n", dis->itemID); - return 0; - } - } - - if (TRACE_ON(comboex)) COMBOEX_DumpItem (item); - - xbase = CBE_STARTOFFSET; - if ((item->mask & CBEIF_INDENT) && (dis->itemState & ODS_COMBOEXLBOX)) { - INT indent = item->iIndent; - if (indent == I_INDENTCALLBACK) { - NMCOMBOBOXEXW nmce; - ZeroMemory(&nmce, sizeof(nmce)); - nmce.ceItem.mask = CBEIF_INDENT; - nmce.ceItem.lParam = item->lParam; - nmce.ceItem.iItem = dis->itemID; - COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce); - if (nmce.ceItem.mask & CBEIF_DI_SETITEM) - item->iIndent = nmce.ceItem.iIndent; - indent = nmce.ceItem.iIndent; - } - xbase += (indent * CBE_INDENT); - } - - drawimage = -2; - drawstate = ILD_NORMAL; - if (item->mask & CBEIF_IMAGE) - drawimage = item->iImage; - if (dis->itemState & ODS_COMBOEXLBOX) { - /* drawing listbox entry */ - if (dis->itemState & ODS_SELECTED) { - if (item->mask & CBEIF_SELECTEDIMAGE) - drawimage = item->iSelectedImage; - drawstate = ILD_SELECTED; - } - } else { - /* drawing combo/edit entry */ - if (IsWindowVisible(infoPtr->hwndEdit)) { - /* if we have an edit control, the slave the - * selection state to the Edit focus state - */ - if (infoPtr->flags & WCBE_EDITFOCUSED) { - if (item->mask & CBEIF_SELECTEDIMAGE) - drawimage = item->iSelectedImage; - drawstate = ILD_SELECTED; - } - } else { - /* if we don't have an edit control, use - * the requested state. - */ - if (dis->itemState & ODS_SELECTED) { - if (item->mask & CBEIF_SELECTEDIMAGE) - drawimage = item->iSelectedImage; - drawstate = ILD_SELECTED; - } - } - } - - if (infoPtr->himl && !(infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGEINDENT)) { - IMAGEINFO iinfo; - iinfo.rcImage.left = iinfo.rcImage.right = 0; - ImageList_GetImageInfo(infoPtr->himl, 0, &iinfo); - xioff = iinfo.rcImage.right - iinfo.rcImage.left + CBE_SEP; - } else xioff = 0; - - /* setup pointer to text to be drawn */ - str = COMBOEX_GetText(infoPtr, item); - if (!str) str = nil; - - len = strlenW (str); - GetTextExtentPoint32W (dis->hDC, str, len, &txtsize); - - if (dis->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)) { - int overlay = item->iOverlay; - - if (drawimage == I_IMAGECALLBACK) { - NMCOMBOBOXEXW nmce; - ZeroMemory(&nmce, sizeof(nmce)); - nmce.ceItem.mask = (drawstate == ILD_NORMAL) ? CBEIF_IMAGE : CBEIF_SELECTEDIMAGE; - nmce.ceItem.lParam = item->lParam; - nmce.ceItem.iItem = dis->itemID; - COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce); - if (drawstate == ILD_NORMAL) { - if (nmce.ceItem.mask & CBEIF_DI_SETITEM) item->iImage = nmce.ceItem.iImage; - drawimage = nmce.ceItem.iImage; - } else if (drawstate == ILD_SELECTED) { - if (nmce.ceItem.mask & CBEIF_DI_SETITEM) item->iSelectedImage = nmce.ceItem.iSelectedImage; - drawimage = nmce.ceItem.iSelectedImage; - } else ERR("Bad draw state = %d\n", drawstate); - } - - if (overlay == I_IMAGECALLBACK) { - NMCOMBOBOXEXW nmce; - ZeroMemory(&nmce, sizeof(nmce)); - nmce.ceItem.mask = CBEIF_OVERLAY; - nmce.ceItem.lParam = item->lParam; - nmce.ceItem.iItem = dis->itemID; - COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce); - if (nmce.ceItem.mask & CBEIF_DI_SETITEM) - item->iOverlay = nmce.ceItem.iOverlay; - overlay = nmce.ceItem.iOverlay; - } - - if (drawimage >= 0 && - !(infoPtr->dwExtStyle & (CBES_EX_NOEDITIMAGE | CBES_EX_NOEDITIMAGEINDENT))) { - if (overlay > 0) ImageList_SetOverlayImage (infoPtr->himl, overlay, 1); - ImageList_Draw (infoPtr->himl, drawimage, dis->hDC, xbase, dis->rcItem.top, - drawstate | (overlay > 0 ? INDEXTOOVERLAYMASK(1) : 0)); - } - - /* now draw the text */ - if (!IsWindowVisible (infoPtr->hwndEdit)) { - nbkc = GetSysColor ((dis->itemState & ODS_SELECTED) ? - COLOR_HIGHLIGHT : COLOR_WINDOW); - bkc = SetBkColor (dis->hDC, nbkc); - ntxc = GetSysColor ((dis->itemState & ODS_SELECTED) ? - COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT); - txc = SetTextColor (dis->hDC, ntxc); - x = xbase + xioff; - y = dis->rcItem.top + - (dis->rcItem.bottom - dis->rcItem.top - txtsize.cy) / 2; - rect.left = x; - rect.right = x + txtsize.cx; - rect.top = dis->rcItem.top + 1; - rect.bottom = dis->rcItem.bottom - 1; - TRACE("drawing item %d text, rect=(%ld,%ld)-(%ld,%ld)\n", - dis->itemID, rect.left, rect.top, rect.right, rect.bottom); - ExtTextOutW (dis->hDC, x, y, ETO_OPAQUE | ETO_CLIPPED, - &rect, str, len, 0); - SetBkColor (dis->hDC, bkc); - SetTextColor (dis->hDC, txc); - } - } - - if (dis->itemAction & ODA_FOCUS) { - rect.left = xbase + xioff - 1; - rect.right = rect.left + txtsize.cx + 2; - rect.top = dis->rcItem.top; - rect.bottom = dis->rcItem.bottom; - DrawFocusRect(dis->hDC, &rect); - } - - return 0; -} - - -static LRESULT COMBOEX_Destroy (COMBOEX_INFO *infoPtr) -{ - if (infoPtr->hwndCombo) - DestroyWindow (infoPtr->hwndCombo); - - if (infoPtr->edit) { - Free (infoPtr->edit); - infoPtr->edit = 0; - } - - if (infoPtr->items) { - CBE_ITEMDATA *item, *next; - - item = infoPtr->items; - while (item) { - next = item->next; - COMBOEX_FreeText (item); - Free (item); - item = next; - } - infoPtr->items = 0; - } - - if (infoPtr->defaultFont) - DeleteObject (infoPtr->defaultFont); - - /* free comboex info data */ - Free (infoPtr); - SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0); - return 0; -} - - -static LRESULT COMBOEX_MeasureItem (COMBOEX_INFO *infoPtr, MEASUREITEMSTRUCT *mis) -{ - static const WCHAR strW[] = { 'W', 0 }; - SIZE mysize; - HDC hdc; - - hdc = GetDC (0); - GetTextExtentPointW (hdc, strW, 1, &mysize); - ReleaseDC (0, hdc); - mis->itemHeight = mysize.cy + CBE_EXTRA; - - TRACE("adjusted height hwnd=%p, height=%d\n", - infoPtr->hwndSelf, mis->itemHeight); - - return 0; -} - - -static LRESULT COMBOEX_NCCreate (HWND hwnd) -{ - /* WARNING: The COMBOEX_INFO structure is not yet created */ - DWORD oldstyle, newstyle; - - oldstyle = (DWORD)GetWindowLongW (hwnd, GWL_STYLE); - newstyle = oldstyle & ~(WS_VSCROLL | WS_HSCROLL | WS_BORDER); - if (newstyle != oldstyle) { - TRACE("req style %08lx, reseting style %08lx\n", - oldstyle, newstyle); - SetWindowLongW (hwnd, GWL_STYLE, newstyle); - } - return 1; -} - - -static LRESULT COMBOEX_NotifyFormat (COMBOEX_INFO *infoPtr, LPARAM lParam) -{ - if (lParam == NF_REQUERY) { - INT i = SendMessageW(infoPtr->hwndNotify, - WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY); - infoPtr->NtfUnicode = (i == NFR_UNICODE) ? 1 : 0; - } - return infoPtr->NtfUnicode ? NFR_UNICODE : NFR_ANSI; -} - - -static LRESULT COMBOEX_Size (COMBOEX_INFO *infoPtr, INT width, INT height) -{ - TRACE("(width=%d, height=%d)\n", width, height); - - MoveWindow (infoPtr->hwndCombo, 0, 0, width, height, TRUE); - - COMBOEX_AdjustEditPos (infoPtr); - - return 0; -} - - -static LRESULT COMBOEX_WindowPosChanging (COMBOEX_INFO *infoPtr, WINDOWPOS *wp) -{ - RECT cbx_wrect, cbx_crect, cb_wrect; - INT width, height; - - GetWindowRect (infoPtr->hwndSelf, &cbx_wrect); - GetClientRect (infoPtr->hwndSelf, &cbx_crect); - GetWindowRect (infoPtr->hwndCombo, &cb_wrect); - - /* width is winpos value + border width of comboex */ - width = wp->cx - + (cbx_wrect.right-cbx_wrect.left) - - (cbx_crect.right-cbx_crect.left); - - TRACE("winpos=(%d,%d %dx%d) flags=0x%08x\n", - wp->x, wp->y, wp->cx, wp->cy, wp->flags); - TRACE("EX window=(%ld,%ld)-(%ld,%ld), client=(%ld,%ld)-(%ld,%ld)\n", - cbx_wrect.left, cbx_wrect.top, cbx_wrect.right, cbx_wrect.bottom, - cbx_crect.left, cbx_crect.top, cbx_crect.right, cbx_crect.bottom); - TRACE("CB window=(%ld,%ld)-(%ld,%ld), EX setting=(0,0)-(%d,%ld)\n", - cb_wrect.left, cb_wrect.top, cb_wrect.right, cb_wrect.bottom, - width, cb_wrect.bottom-cb_wrect.top); - - if (width) SetWindowPos (infoPtr->hwndCombo, HWND_TOP, 0, 0, - width, - cb_wrect.bottom-cb_wrect.top, - SWP_NOACTIVATE); - - GetWindowRect (infoPtr->hwndCombo, &cb_wrect); - - /* height is combo window height plus border width of comboex */ - height = (cb_wrect.bottom-cb_wrect.top) - + (cbx_wrect.bottom-cbx_wrect.top) - - (cbx_crect.bottom-cbx_crect.top); - if (wp->cy < height) wp->cy = height; - if (infoPtr->hwndEdit) { - COMBOEX_AdjustEditPos (infoPtr); - InvalidateRect (infoPtr->hwndCombo, 0, TRUE); - } - - return 0; -} - -static LRESULT WINAPI -COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - HWND hwndComboex = (HWND)GetPropW(hwnd, COMBOEX_SUBCLASS_PROP); - COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwndComboex); - NMCBEENDEDITW cbeend; - WCHAR edit_text[260]; - COLORREF obkc; - HDC hDC; - RECT rect; - LRESULT lret; - - TRACE("hwnd=%p msg=%x wparam=%x lParam=%lx, info_ptr=%p\n", - hwnd, uMsg, wParam, lParam, infoPtr); - - if (!infoPtr) return 0; - - switch (uMsg) - { - - case WM_CHAR: - /* handle (ignore) the return character */ - if (wParam == VK_RETURN) return 0; - /* all other characters pass into the real Edit */ - return CallWindowProcW (infoPtr->prevEditWndProc, - hwnd, uMsg, wParam, lParam); - - case WM_ERASEBKGND: - /* - * The following was determined by traces of the native - */ - hDC = (HDC) wParam; - obkc = SetBkColor (hDC, GetSysColor (COLOR_WINDOW)); - GetClientRect (hwnd, &rect); - TRACE("erasing (%ld,%ld)-(%ld,%ld)\n", - rect.left, rect.top, rect.right, rect.bottom); - ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0); - SetBkColor (hDC, obkc); - return CallWindowProcW (infoPtr->prevEditWndProc, - hwnd, uMsg, wParam, lParam); - - case WM_KEYDOWN: { - INT oldItem, selected, step = 1; - CBE_ITEMDATA *item; - - switch ((INT)wParam) - { - case VK_ESCAPE: - /* native version seems to do following for COMBOEX */ - /* - * GetWindowTextW(Edit,&?, 0x104) x - * CB_GETCURSEL to Combo rets -1 x - * WM_NOTIFY to COMBOEX parent (rebar) x - * (CBEN_ENDEDIT{A|W} - * fChanged = FALSE x - * inewSelection = -1 x - * txt="www.hoho" x - * iWhy = 3 x - * CB_GETCURSEL to Combo rets -1 x - * InvalidateRect(Combo, 0) x - * WM_SETTEXT to Edit x - * EM_SETSEL to Edit (0,0) x - * EM_SETSEL to Edit (0,-1) x - * RedrawWindow(Combo, 0, 0, 5) x - */ - TRACE("special code for VK_ESCAPE\n"); - - GetWindowTextW (infoPtr->hwndEdit, edit_text, 260); - - infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG); - cbeend.fChanged = FALSE; - cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo, - CB_GETCURSEL, 0, 0); - cbeend.iWhy = CBENF_ESCAPE; - - if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text)) return 0; - oldItem = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0); - InvalidateRect (infoPtr->hwndCombo, 0, 0); - if (!(item = COMBOEX_FindItem(infoPtr, oldItem))) { - ERR("item %d not found. Problem!\n", oldItem); - break; - } - infoPtr->selected = oldItem; - COMBOEX_SetEditText (infoPtr, item); - RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE | - RDW_INVALIDATE); - break; - - case VK_RETURN: - /* native version seems to do following for COMBOEX */ - /* - * GetWindowTextW(Edit,&?, 0x104) x - * CB_GETCURSEL to Combo rets -1 x - * CB_GETCOUNT to Combo rets 0 - * if >0 loop - * CB_GETITEMDATA to match - * *** above 3 lines simulated by FindItem x - * WM_NOTIFY to COMBOEX parent (rebar) x - * (CBEN_ENDEDIT{A|W} x - * fChanged = TRUE (-1) x - * iNewSelection = -1 or selected x - * txt= x - * iWhy = 2 (CBENF_RETURN) x - * CB_GETCURSEL to Combo rets -1 x - * if -1 send CB_SETCURSEL to Combo -1 x - * InvalidateRect(Combo, 0, 0) x - * SetFocus(Edit) x - * CallWindowProc(406615a8, Edit, 0x100, 0xd, 0x1c0001) - */ - - TRACE("special code for VK_RETURN\n"); - - GetWindowTextW (infoPtr->hwndEdit, edit_text, 260); - - infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG); - selected = SendMessageW (infoPtr->hwndCombo, - CB_GETCURSEL, 0, 0); - - if (selected != -1) { - cmp_func_t cmptext = get_cmp_func(infoPtr); - item = COMBOEX_FindItem (infoPtr, selected); - TRACE("handling VK_RETURN, selected = %d, selected_text=%s\n", - selected, debugstr_txt(item->pszText)); - TRACE("handling VK_RETURN, edittext=%s\n", - debugstr_w(edit_text)); - if (cmptext (COMBOEX_GetText(infoPtr, item), edit_text)) { - /* strings not equal -- indicate edit has changed */ - selected = -1; - } - } - - cbeend.iNewSelection = selected; - cbeend.fChanged = TRUE; - cbeend.iWhy = CBENF_RETURN; - if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text)) { - /* abort the change, restore previous */ - TRACE("Notify requested abort of change\n"); - COMBOEX_SetEditText (infoPtr, infoPtr->edit); - RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE | - RDW_INVALIDATE); - return 0; - } - oldItem = SendMessageW (infoPtr->hwndCombo,CB_GETCURSEL, 0, 0); - if (oldItem != -1) { - /* if something is selected, then deselect it */ - SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL, - (WPARAM)-1, 0); - } - InvalidateRect (infoPtr->hwndCombo, 0, 0); - SetFocus(infoPtr->hwndEdit); - break; - - case VK_UP: - step = -1; - case VK_DOWN: - /* by default, step is 1 */ - oldItem = SendMessageW (infoPtr->hwndSelf, CB_GETCURSEL, 0, 0); - if (oldItem >= 0 && oldItem + step >= 0) - SendMessageW (infoPtr->hwndSelf, CB_SETCURSEL, oldItem + step, 0); - return 0; - default: - return CallWindowProcW (infoPtr->prevEditWndProc, - hwnd, uMsg, wParam, lParam); - } - return 0; - } - - case WM_SETFOCUS: - /* remember the focus to set state of icon */ - lret = CallWindowProcW (infoPtr->prevEditWndProc, - hwnd, uMsg, wParam, lParam); - infoPtr->flags |= WCBE_EDITFOCUSED; - return lret; - - case WM_KILLFOCUS: - /* - * do NOTIFY CBEN_ENDEDIT with CBENF_KILLFOCUS - */ - infoPtr->flags &= ~WCBE_EDITFOCUSED; - if (infoPtr->flags & WCBE_ACTEDIT) { - infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG); - - GetWindowTextW (infoPtr->hwndEdit, edit_text, 260); - cbeend.fChanged = FALSE; - cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo, - CB_GETCURSEL, 0, 0); - cbeend.iWhy = CBENF_KILLFOCUS; - - COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text); - } - /* fall through */ - - default: - return CallWindowProcW (infoPtr->prevEditWndProc, - hwnd, uMsg, wParam, lParam); - } -} - - -static LRESULT WINAPI -COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - HWND hwndComboex = (HWND)GetPropW(hwnd, COMBOEX_SUBCLASS_PROP); - COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwndComboex); - NMCBEENDEDITW cbeend; - NMMOUSE nmmse; - COLORREF obkc; - HDC hDC; - HWND focusedhwnd; - RECT rect; - POINT pt; - WCHAR edit_text[260]; - - TRACE("hwnd=%p msg=%x wparam=%x lParam=%lx, info_ptr=%p\n", - hwnd, uMsg, wParam, lParam, infoPtr); - - if (!infoPtr) return 0; - - switch (uMsg) - { - - case WM_DRAWITEM: - /* - * The only way this message should come is from the - * child Listbox issuing the message. Flag this so - * that ComboEx knows this is listbox. - */ - ((DRAWITEMSTRUCT *)lParam)->itemState |= ODS_COMBOEXLBOX; - return CallWindowProcW (infoPtr->prevComboWndProc, - hwnd, uMsg, wParam, lParam); - - case WM_ERASEBKGND: - /* - * The following was determined by traces of the native - */ - hDC = (HDC) wParam; - obkc = SetBkColor (hDC, GetSysColor (COLOR_WINDOW)); - GetClientRect (hwnd, &rect); - TRACE("erasing (%ld,%ld)-(%ld,%ld)\n", - rect.left, rect.top, rect.right, rect.bottom); - ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0); - SetBkColor (hDC, obkc); - return CallWindowProcW (infoPtr->prevComboWndProc, - hwnd, uMsg, wParam, lParam); - - case WM_SETCURSOR: - /* - * WM_NOTIFY to comboex parent (rebar) - * with NM_SETCURSOR with extra words of 0,0,0,0,0x02010001 - * CallWindowProc (previous) - */ - nmmse.dwItemSpec = 0; - nmmse.dwItemData = 0; - nmmse.pt.x = 0; - nmmse.pt.y = 0; - nmmse.dwHitInfo = lParam; - COMBOEX_Notify (infoPtr, NM_SETCURSOR, (NMHDR *)&nmmse); - return CallWindowProcW (infoPtr->prevComboWndProc, - hwnd, uMsg, wParam, lParam); - - case WM_LBUTTONDOWN: - GetClientRect (hwnd, &rect); - rect.bottom = rect.top + SendMessageW(infoPtr->hwndSelf, - CB_GETITEMHEIGHT, -1, 0); - rect.left = rect.right - GetSystemMetrics(SM_CXVSCROLL); - pt.x = (short)LOWORD(lParam); - pt.y = (short)HIWORD(lParam); - if (PtInRect(&rect, pt)) - return CallWindowProcW (infoPtr->prevComboWndProc, - hwnd, uMsg, wParam, lParam); - infoPtr->flags |= WCBE_MOUSECAPTURED; - SetCapture(hwnd); - break; - - case WM_LBUTTONUP: - if (!(infoPtr->flags & WCBE_MOUSECAPTURED)) - return CallWindowProcW (infoPtr->prevComboWndProc, - hwnd, uMsg, wParam, lParam); - ReleaseCapture(); - infoPtr->flags &= ~WCBE_MOUSECAPTURED; - if (infoPtr->flags & WCBE_MOUSEDRAGGED) { - infoPtr->flags &= ~WCBE_MOUSEDRAGGED; - } else { - SendMessageW(hwnd, CB_SHOWDROPDOWN, TRUE, 0); - } - break; - - case WM_MOUSEMOVE: - if ( (infoPtr->flags & WCBE_MOUSECAPTURED) && - !(infoPtr->flags & WCBE_MOUSEDRAGGED)) { - GetWindowTextW (infoPtr->hwndEdit, edit_text, 260); - COMBOEX_NotifyDragBegin(infoPtr, edit_text); - infoPtr->flags |= WCBE_MOUSEDRAGGED; - } - return CallWindowProcW (infoPtr->prevComboWndProc, - hwnd, uMsg, wParam, lParam); - - case WM_COMMAND: - switch (HIWORD(wParam)) { - - case EN_UPDATE: - /* traces show that COMBOEX does not issue CBN_EDITUPDATE - * on the EN_UPDATE - */ - return 0; - - case EN_KILLFOCUS: - /* - * Native does: - * - * GetFocus() retns AA - * GetWindowTextW(Edit) - * CB_GETCURSEL(Combo) (got -1) - * WM_NOTIFY(CBEN_ENDEDITA) with CBENF_KILLFOCUS - * CB_GETCURSEL(Combo) (got -1) - * InvalidateRect(Combo, 0, 0) - * WM_KILLFOCUS(Combo, AA) - * return 0; - */ - focusedhwnd = GetFocus(); - if (infoPtr->flags & WCBE_ACTEDIT) { - GetWindowTextW (infoPtr->hwndEdit, edit_text, 260); - cbeend.fChanged = (infoPtr->flags & WCBE_EDITCHG); - cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo, - CB_GETCURSEL, 0, 0); - cbeend.iWhy = CBENF_KILLFOCUS; - - infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG); - if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text)) return 0; - } - /* possible CB_GETCURSEL */ - InvalidateRect (infoPtr->hwndCombo, 0, 0); - if (focusedhwnd) - SendMessageW (infoPtr->hwndCombo, WM_KILLFOCUS, - (WPARAM)focusedhwnd, 0); - return 0; - - case EN_SETFOCUS: { - /* - * For EN_SETFOCUS this issues the same calls and messages - * as the native seems to do. - * - * for some cases however native does the following: - * (noticed after SetFocus during LBUTTONDOWN on - * on dropdown arrow) - * WM_GETTEXTLENGTH (Edit); - * WM_GETTEXT (Edit, len+1, str); - * EM_SETSEL (Edit, 0, 0); - * WM_GETTEXTLENGTH (Edit); - * WM_GETTEXT (Edit, len+1, str); - * EM_SETSEL (Edit, 0, len); - * WM_NOTIFY (parent, CBEN_BEGINEDIT) - */ - NMHDR hdr; - - SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, 0); - SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, -1); - COMBOEX_Notify (infoPtr, CBEN_BEGINEDIT, &hdr); - infoPtr->flags |= WCBE_ACTEDIT; - infoPtr->flags &= ~WCBE_EDITCHG; /* no change yet */ - return 0; - } - - case EN_CHANGE: { - /* - * For EN_CHANGE this issues the same calls and messages - * as the native seems to do. - */ - WCHAR edit_text[260]; - LPCWSTR lastwrk; - cmp_func_t cmptext = get_cmp_func(infoPtr); - - INT selected = SendMessageW (infoPtr->hwndCombo, - CB_GETCURSEL, 0, 0); - - /* lstrlenW( lastworkingURL ) */ - - GetWindowTextW (infoPtr->hwndEdit, edit_text, 260); - if (selected == -1) { - lastwrk = infoPtr->edit->pszText; - } - else { - CBE_ITEMDATA *item = COMBOEX_FindItem (infoPtr, selected); - lastwrk = COMBOEX_GetText(infoPtr, item); - } - - TRACE("handling EN_CHANGE, selected = %d, selected_text=%s\n", - selected, debugstr_w(lastwrk)); - TRACE("handling EN_CHANGE, edittext=%s\n", - debugstr_w(edit_text)); - - /* cmptext is between lastworkingURL and GetWindowText */ - if (cmptext (lastwrk, edit_text)) { - /* strings not equal -- indicate edit has changed */ - infoPtr->flags |= WCBE_EDITCHG; - } - SendMessageW ( infoPtr->hwndNotify, WM_COMMAND, - MAKEWPARAM(GetDlgCtrlID (infoPtr->hwndSelf), - CBN_EDITCHANGE), - (LPARAM)infoPtr->hwndSelf); - return 0; - } - - case LBN_SELCHANGE: - /* - * Therefore from traces there is no additional code here - */ - - /* - * Using native COMCTL32 gets the following: - * 1 == SHDOCVW.DLL issues call/message - * 2 == COMCTL32.DLL issues call/message - * 3 == WINE issues call/message - * - * - * for LBN_SELCHANGE: - * 1 CB_GETCURSEL(ComboEx) - * 1 CB_GETDROPPEDSTATE(ComboEx) - * 1 CallWindowProc( *2* for WM_COMMAND(LBN_SELCHANGE) - * 2 CallWindowProc( *3* for WM_COMMAND(LBN_SELCHANGE) - ** call CBRollUp( xxx, TRUE for LBN_SELCHANGE, TRUE) - * 3 WM_COMMAND(ComboEx, CBN_SELENDOK) - * WM_USER+49(ComboLB, 1,0) <=============!!!!!!!!!!! - * 3 ShowWindow(ComboLB, SW_HIDE) - * 3 RedrawWindow(Combo, RDW_UPDATENOW) - * 3 WM_COMMAND(ComboEX, CBN_CLOSEUP) - ** end of CBRollUp - * 3 WM_COMMAND(ComboEx, CBN_SELCHANGE) (echo to parent) - * ? LB_GETCURSEL <==| - * ? LB_GETTEXTLEN | - * ? LB_GETTEXT | Needs to be added to - * ? WM_CTLCOLOREDIT(ComboEx) | Combo processing - * ? LB_GETITEMDATA | - * ? WM_DRAWITEM(ComboEx) <==| - */ - default: - break; - }/* fall through */ - default: - return CallWindowProcW (infoPtr->prevComboWndProc, - hwnd, uMsg, wParam, lParam); - } - return 0; -} - - -static LRESULT WINAPI -COMBOEX_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd); - - TRACE("hwnd=%p msg=%x wparam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam); - - if (!infoPtr) { - if (uMsg == WM_CREATE) - return COMBOEX_Create (hwnd, (LPCREATESTRUCTA)lParam); - if (uMsg == WM_NCCREATE) - COMBOEX_NCCreate (hwnd); - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - } - - switch (uMsg) - { - case CBEM_DELETEITEM: - return COMBOEX_DeleteItem (infoPtr, wParam); - - case CBEM_GETCOMBOCONTROL: - return (LRESULT)infoPtr->hwndCombo; - - case CBEM_GETEDITCONTROL: - return (LRESULT)infoPtr->hwndEdit; - - case CBEM_GETEXTENDEDSTYLE: - return infoPtr->dwExtStyle; - - case CBEM_GETIMAGELIST: - return (LRESULT)infoPtr->himl; - - case CBEM_GETITEMA: - return (LRESULT)COMBOEX_GetItemA (infoPtr, (COMBOBOXEXITEMA *)lParam); - - case CBEM_GETITEMW: - return (LRESULT)COMBOEX_GetItemW (infoPtr, (COMBOBOXEXITEMW *)lParam); - - case CBEM_GETUNICODEFORMAT: - return infoPtr->unicode; - - case CBEM_HASEDITCHANGED: - return COMBOEX_HasEditChanged (infoPtr); - - case CBEM_INSERTITEMA: - return COMBOEX_InsertItemA (infoPtr, (COMBOBOXEXITEMA *)lParam); - - case CBEM_INSERTITEMW: - return COMBOEX_InsertItemW (infoPtr, (COMBOBOXEXITEMW *)lParam); - - case CBEM_SETEXSTYLE: - case CBEM_SETEXTENDEDSTYLE: - return COMBOEX_SetExtendedStyle (infoPtr, (DWORD)wParam, (DWORD)lParam); - - case CBEM_SETIMAGELIST: - return (LRESULT)COMBOEX_SetImageList (infoPtr, (HIMAGELIST)lParam); - - case CBEM_SETITEMA: - return COMBOEX_SetItemA (infoPtr, (COMBOBOXEXITEMA *)lParam); - - case CBEM_SETITEMW: - return COMBOEX_SetItemW (infoPtr, (COMBOBOXEXITEMW *)lParam); - - case CBEM_SETUNICODEFORMAT: - return COMBOEX_SetUnicodeFormat (infoPtr, wParam); - - /*case CBEM_SETWINDOWTHEME: - FIXME("CBEM_SETWINDOWTHEME: stub\n");*/ - - case WM_SETTEXT: - case WM_GETTEXT: - return SendMessageW(infoPtr->hwndEdit, uMsg, wParam, lParam); - -/* Combo messages we are not sure if we need to process or just forward */ - case CB_GETDROPPEDCONTROLRECT: - case CB_GETITEMHEIGHT: - case CB_GETLBTEXT: - case CB_GETLBTEXTLEN: - case CB_GETEXTENDEDUI: - case CB_LIMITTEXT: - case CB_RESETCONTENT: - case CB_SELECTSTRING: - -/* Combo messages OK to just forward to the regular COMBO */ - case CB_GETCOUNT: - case CB_GETCURSEL: - case CB_GETDROPPEDSTATE: - case CB_SETDROPPEDWIDTH: - case CB_SETEXTENDEDUI: - case CB_SHOWDROPDOWN: - return SendMessageW (infoPtr->hwndCombo, uMsg, wParam, lParam); - -/* Combo messages we need to process specially */ - case CB_FINDSTRINGEXACT: - return COMBOEX_FindStringExact (infoPtr, (INT)wParam, (LPCWSTR)lParam); - - case CB_GETITEMDATA: - return COMBOEX_GetItemData (infoPtr, (INT)wParam); - - case CB_SETCURSEL: - return COMBOEX_SetCursel (infoPtr, (INT)wParam); - - case CB_SETITEMDATA: - return COMBOEX_SetItemData (infoPtr, (INT)wParam, (DWORD)lParam); - - case CB_SETITEMHEIGHT: - return COMBOEX_SetItemHeight (infoPtr, (INT)wParam, (UINT)lParam); - - - -/* Window messages passed to parent */ - case WM_COMMAND: - return COMBOEX_Command (infoPtr, wParam, lParam); - - case WM_NOTIFY: - if (infoPtr->NtfUnicode) - return SendMessageW (infoPtr->hwndNotify, uMsg, wParam, lParam); - else - return SendMessageA (infoPtr->hwndNotify, uMsg, wParam, lParam); - - -/* Window messages we need to process */ - case WM_DELETEITEM: - return COMBOEX_WM_DeleteItem (infoPtr, (DELETEITEMSTRUCT *)lParam); - - case WM_DRAWITEM: - return COMBOEX_DrawItem (infoPtr, (DRAWITEMSTRUCT *)lParam); - - case WM_DESTROY: - return COMBOEX_Destroy (infoPtr); - - case WM_MEASUREITEM: - return COMBOEX_MeasureItem (infoPtr, (MEASUREITEMSTRUCT *)lParam); - - case WM_NOTIFYFORMAT: - return COMBOEX_NotifyFormat (infoPtr, lParam); - - case WM_SIZE: - return COMBOEX_Size (infoPtr, LOWORD(lParam), HIWORD(lParam)); - - case WM_WINDOWPOSCHANGING: - return COMBOEX_WindowPosChanging (infoPtr, (WINDOWPOS *)lParam); - - case WM_SETFOCUS: - SetFocus(infoPtr->hwndCombo); - return 0; - - default: - if ((uMsg >= WM_USER) && (uMsg < WM_APP)) - ERR("unknown msg %04x wp=%08x lp=%08lx\n",uMsg,wParam,lParam); - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - } -} - - -void COMBOEX_Register (void) -{ - WNDCLASSW wndClass; - - ZeroMemory (&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS; - wndClass.lpfnWndProc = COMBOEX_WindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(COMBOEX_INFO *); - wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); - wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wndClass.lpszClassName = WC_COMBOBOXEXW; - - RegisterClassW (&wndClass); -} - - -void COMBOEX_Unregister (void) -{ - UnregisterClassW (WC_COMBOBOXEXW, NULL); -} +/* + * ComboBoxEx control + * + * Copyright 1998, 1999 Eric Kohl + * Copyright 2000, 2001, 2002 Guy Albertelli + * Copyright 2002 Dimitrie O. Paun + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTE + * + * This code was audited for completeness against the documented features + * of Comctl32.dll version 6.0 on Sep. 9, 2002, by Dimitrie O. Paun. + * + * Unless otherwise noted, we believe this code to be complete, as per + * the specification mentioned above. + * If you discover missing features, or bugs, please note them below. + * + */ + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "comctl32.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +WINE_DEFAULT_DEBUG_CHANNEL(comboex); + +/* Item structure */ +typedef struct _CBE_ITEMDATA +{ + struct _CBE_ITEMDATA *next; + UINT mask; + LPWSTR pszText; + LPWSTR pszTemp; + int cchTextMax; + int iImage; + int iSelectedImage; + int iOverlay; + int iIndent; + LPARAM lParam; +} CBE_ITEMDATA; + +/* ComboBoxEx structure */ +typedef struct +{ + HIMAGELIST himl; + HWND hwndSelf; /* my own hwnd */ + HWND hwndNotify; /* my parent hwnd */ + HWND hwndCombo; + HWND hwndEdit; + WNDPROC prevEditWndProc; /* previous Edit WNDPROC value */ + WNDPROC prevComboWndProc; /* previous Combo WNDPROC value */ + DWORD dwExtStyle; + INT selected; /* index of selected item */ + DWORD flags; /* WINE internal flags */ + HFONT defaultFont; + HFONT font; + INT nb_items; /* Number of items */ + BOOL unicode; /* TRUE if this window is Unicode */ + BOOL NtfUnicode; /* TRUE if parent wants notify in Unicode */ + CBE_ITEMDATA *edit; /* item data for edit item */ + CBE_ITEMDATA *items; /* Array of items */ +} COMBOEX_INFO; + +/* internal flags in the COMBOEX_INFO structure */ +#define WCBE_ACTEDIT 0x00000001 /* Edit active i.e. + * CBEN_BEGINEDIT issued + * but CBEN_ENDEDIT{A|W} + * not yet issued. */ +#define WCBE_EDITCHG 0x00000002 /* Edit issued EN_CHANGE */ +#define WCBE_EDITHASCHANGED (WCBE_ACTEDIT | WCBE_EDITCHG) +#define WCBE_EDITFOCUSED 0x00000004 /* Edit control has focus */ +#define WCBE_MOUSECAPTURED 0x00000008 /* Combo has captured mouse */ +#define WCBE_MOUSEDRAGGED 0x00000010 /* User has dragged in combo */ + +#define ID_CB_EDIT 1001 + + +/* + * Special flag set in DRAWITEMSTRUCT itemState field. It is set by + * the ComboEx version of the Combo Window Proc so that when the + * WM_DRAWITEM message is then passed to ComboEx, we know that this + * particular WM_DRAWITEM message is for listbox only items. Any messasges + * without this flag is then for the Edit control field. + * + * We really cannot use the ODS_COMBOBOXEDIT flag because MSDN states that + * only version 4.0 applications will have ODS_COMBOBOXEDIT set. + */ +#define ODS_COMBOEXLBOX 0x4000 + + + +/* Height in pixels of control over the amount of the selected font */ +#define CBE_EXTRA 3 + +/* Indent amount per MS documentation */ +#define CBE_INDENT 10 + +/* Offset in pixels from left side for start of image or text */ +#define CBE_STARTOFFSET 6 + +/* Offset between image and text */ +#define CBE_SEP 4 + +static const WCHAR COMBOEX_SUBCLASS_PROP[] = { + 'C','C','C','o','m','b','o','E','x','3','2', + 'S','u','b','c','l','a','s','s','I','n','f','o',0 +}; + +#define COMBOEX_GetInfoPtr(hwnd) ((COMBOEX_INFO *)GetWindowLongPtrW (hwnd, 0)) + + +/* Things common to the entire DLL */ +static LRESULT WINAPI COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +static LRESULT WINAPI COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +static LRESULT COMBOEX_Destroy (COMBOEX_INFO *infoPtr); +typedef INT (WINAPI *cmp_func_t)(LPCWSTR, LPCWSTR); + +inline static BOOL is_textW(LPCWSTR str) +{ + return str && str != LPSTR_TEXTCALLBACKW; +} + +inline static BOOL is_textA(LPCSTR str) +{ + return str && str != LPSTR_TEXTCALLBACKA; +} + +inline static LPCSTR debugstr_txt(LPCWSTR str) +{ + if (str == LPSTR_TEXTCALLBACKW) return "(callback)"; + return debugstr_w(str); +} + +static void COMBOEX_DumpItem (CBE_ITEMDATA *item) +{ + TRACE("item %p - mask=%08x, pszText=%p, cchTM=%d, iImage=%d\n", + item, item->mask, item->pszText, item->cchTextMax, item->iImage); + TRACE("item %p - iSelectedImage=%d, iOverlay=%d, iIndent=%d, lParam=%08lx\n", + item, item->iSelectedImage, item->iOverlay, item->iIndent, item->lParam); + if (item->mask & CBEIF_TEXT) + TRACE("item %p - pszText=%s\n", item, debugstr_txt(item->pszText)); +} + + +static void COMBOEX_DumpInput (COMBOBOXEXITEMW *input) +{ + TRACE("input - mask=%08x, iItem=%d, pszText=%p, cchTM=%d, iImage=%d\n", + input->mask, input->iItem, input->pszText, input->cchTextMax, + input->iImage); + if (input->mask & CBEIF_TEXT) + TRACE("input - pszText=<%s>\n", debugstr_txt(input->pszText)); + TRACE("input - iSelectedImage=%d, iOverlay=%d, iIndent=%d, lParam=%08lx\n", + input->iSelectedImage, input->iOverlay, input->iIndent, input->lParam); +} + + +inline static CBE_ITEMDATA *get_item_data(COMBOEX_INFO *infoPtr, INT index) +{ + return (CBE_ITEMDATA *)SendMessageW (infoPtr->hwndCombo, CB_GETITEMDATA, + (WPARAM)index, 0); +} + +inline static cmp_func_t get_cmp_func(COMBOEX_INFO *infoPtr) +{ + return infoPtr->dwExtStyle & CBES_EX_CASESENSITIVE ? lstrcmpW : lstrcmpiW; +} + +static INT COMBOEX_Notify (COMBOEX_INFO *infoPtr, INT code, NMHDR *hdr) +{ + hdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf); + hdr->hwndFrom = infoPtr->hwndSelf; + hdr->code = code; + if (infoPtr->NtfUnicode) + return SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, 0, (LPARAM)hdr); + else + return SendMessageA (infoPtr->hwndNotify, WM_NOTIFY, 0, (LPARAM)hdr); +} + + +static INT +COMBOEX_NotifyItem (COMBOEX_INFO *infoPtr, INT code, NMCOMBOBOXEXW *hdr) +{ + /* Change the Text item from Unicode to ANSI if necessary for NOTIFY */ + if (infoPtr->NtfUnicode) + return COMBOEX_Notify (infoPtr, code, &hdr->hdr); + else { + LPWSTR wstr = hdr->ceItem.pszText; + LPSTR astr = 0; + INT ret, len = 0; + + if ((hdr->ceItem.mask & CBEIF_TEXT) && is_textW(wstr)) { + len = WideCharToMultiByte (CP_ACP, 0, wstr, -1, 0, 0, NULL, NULL); + if (len > 0) { + astr = (LPSTR)Alloc ((len + 1)*sizeof(CHAR)); + if (!astr) return 0; + WideCharToMultiByte (CP_ACP, 0, wstr, -1, astr, len, 0, 0); + hdr->ceItem.pszText = (LPWSTR)astr; + } + } + + if (code == CBEN_ENDEDITW) code = CBEN_ENDEDITA; + else if (code == CBEN_GETDISPINFOW) code = CBEN_GETDISPINFOA; + else if (code == CBEN_DRAGBEGINW) code = CBEN_DRAGBEGINA; + + ret = COMBOEX_Notify (infoPtr, code, (NMHDR *)hdr); + + if (astr && hdr->ceItem.pszText == (LPWSTR)astr) + hdr->ceItem.pszText = wstr; + + if (astr) Free(astr); + + return ret; + } +} + + +static INT COMBOEX_NotifyEndEdit (COMBOEX_INFO *infoPtr, NMCBEENDEDITW *neew, LPCWSTR wstr) +{ + /* Change the Text item from Unicode to ANSI if necessary for NOTIFY */ + if (infoPtr->NtfUnicode) { + lstrcpynW(neew->szText, wstr, CBEMAXSTRLEN); + return COMBOEX_Notify (infoPtr, CBEN_ENDEDITW, &neew->hdr); + } else { + NMCBEENDEDITA neea; + + memcpy (&neea.hdr, &neew->hdr, sizeof(NMHDR)); + neea.fChanged = neew->fChanged; + neea.iNewSelection = neew->iNewSelection; + WideCharToMultiByte (CP_ACP, 0, wstr, -1, neea.szText, CBEMAXSTRLEN, 0, 0); + neea.iWhy = neew->iWhy; + + return COMBOEX_Notify (infoPtr, CBEN_ENDEDITA, &neea.hdr); + } +} + + +static void COMBOEX_NotifyDragBegin(COMBOEX_INFO *infoPtr, LPCWSTR wstr) +{ + /* Change the Text item from Unicode to ANSI if necessary for NOTIFY */ + if (infoPtr->NtfUnicode) { + NMCBEDRAGBEGINW ndbw; + + ndbw.iItemid = -1; + lstrcpynW(ndbw.szText, wstr, CBEMAXSTRLEN); + COMBOEX_Notify (infoPtr, CBEN_DRAGBEGINW, &ndbw.hdr); + } else { + NMCBEDRAGBEGINA ndba; + + ndba.iItemid = -1; + WideCharToMultiByte (CP_ACP, 0, wstr, -1, ndba.szText, CBEMAXSTRLEN, 0, 0); + + COMBOEX_Notify (infoPtr, CBEN_DRAGBEGINA, &ndba.hdr); + } +} + + +static void COMBOEX_FreeText (CBE_ITEMDATA *item) +{ + if (is_textW(item->pszText)) Free(item->pszText); + item->pszText = 0; + if (item->pszTemp) Free(item->pszTemp); + item->pszTemp = 0; +} + + +static INT COMBOEX_GetIndex(COMBOEX_INFO *infoPtr, CBE_ITEMDATA *item) +{ + CBE_ITEMDATA *moving; + INT index; + + moving = infoPtr->items; + index = infoPtr->nb_items - 1; + + while (moving && (moving != item)) { + moving = moving->next; + index--; + } + if (!moving || (index < 0)) { + ERR("COMBOBOXEX item structures broken. Please report!\n"); + return -1; + } + return index; +} + + +static LPCWSTR COMBOEX_GetText(COMBOEX_INFO *infoPtr, CBE_ITEMDATA *item) +{ + NMCOMBOBOXEXW nmce; + LPWSTR text, buf; + INT len; + + if (item->pszText != LPSTR_TEXTCALLBACKW) + return item->pszText; + + ZeroMemory(&nmce, sizeof(nmce)); + nmce.ceItem.mask = CBEIF_TEXT; + nmce.ceItem.lParam = item->lParam; + nmce.ceItem.iItem = COMBOEX_GetIndex(infoPtr, item); + COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce); + + if (is_textW(nmce.ceItem.pszText)) { + len = MultiByteToWideChar (CP_ACP, 0, (LPSTR)nmce.ceItem.pszText, -1, NULL, 0); + buf = (LPWSTR)Alloc ((len + 1)*sizeof(WCHAR)); + if (buf) + MultiByteToWideChar (CP_ACP, 0, (LPSTR)nmce.ceItem.pszText, -1, buf, len); + if (nmce.ceItem.mask & CBEIF_DI_SETITEM) { + COMBOEX_FreeText(item); + item->pszText = buf; + } else { + if (item->pszTemp) Free(item->pszTemp); + item->pszTemp = buf; + } + text = buf; + } else + text = nmce.ceItem.pszText; + + if (nmce.ceItem.mask & CBEIF_DI_SETITEM) + item->pszText = text; + return text; +} + + +static void COMBOEX_GetComboFontSize (COMBOEX_INFO *infoPtr, SIZE *size) +{ + static const WCHAR strA[] = { 'A', 0 }; + HFONT nfont, ofont; + HDC mydc; + + mydc = GetDC (0); /* why the entire screen???? */ + nfont = (HFONT)SendMessageW (infoPtr->hwndCombo, WM_GETFONT, 0, 0); + ofont = (HFONT) SelectObject (mydc, nfont); + GetTextExtentPointW (mydc, strA, 1, size); + SelectObject (mydc, ofont); + ReleaseDC (0, mydc); + TRACE("selected font hwnd=%p, height=%ld\n", nfont, size->cy); +} + + +static void COMBOEX_CopyItem (CBE_ITEMDATA *item, COMBOBOXEXITEMW *cit) +{ + if (cit->mask & CBEIF_TEXT) { + /* + * when given a text buffer actually use that buffer + */ + if (cit->pszText) { + if (is_textW(item->pszText)) + lstrcpynW(cit->pszText, item->pszText, cit->cchTextMax); + else + cit->pszText[0] = 0; + } else { + cit->pszText = item->pszText; + cit->cchTextMax = item->cchTextMax; + } + } + if (cit->mask & CBEIF_IMAGE) + cit->iImage = item->iImage; + if (cit->mask & CBEIF_SELECTEDIMAGE) + cit->iSelectedImage = item->iSelectedImage; + if (cit->mask & CBEIF_OVERLAY) + cit->iOverlay = item->iOverlay; + if (cit->mask & CBEIF_INDENT) + cit->iIndent = item->iIndent; + if (cit->mask & CBEIF_LPARAM) + cit->lParam = item->lParam; +} + + +static void COMBOEX_AdjustEditPos (COMBOEX_INFO *infoPtr) +{ + SIZE mysize; + INT x, y, w, h, xioff; + RECT rect; + + if (!infoPtr->hwndEdit) return; + + if (infoPtr->himl && !(infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGEINDENT)) { + IMAGEINFO iinfo; + iinfo.rcImage.left = iinfo.rcImage.right = 0; + ImageList_GetImageInfo(infoPtr->himl, 0, &iinfo); + xioff = iinfo.rcImage.right - iinfo.rcImage.left + CBE_SEP; + } else xioff = 0; + + GetClientRect (infoPtr->hwndCombo, &rect); + InflateRect (&rect, -2, -2); + InvalidateRect (infoPtr->hwndCombo, &rect, TRUE); + + /* reposition the Edit control based on whether icon exists */ + COMBOEX_GetComboFontSize (infoPtr, &mysize); + TRACE("Combo font x=%ld, y=%ld\n", mysize.cx, mysize.cy); + x = xioff + CBE_STARTOFFSET + 1; + w = rect.right-rect.left - x - GetSystemMetrics(SM_CXVSCROLL) - 1; + h = mysize.cy + 1; + y = rect.bottom - h - 1; + + TRACE("Combo client (%ld,%ld)-(%ld,%ld), setting Edit to (%d,%d)-(%d,%d)\n", + rect.left, rect.top, rect.right, rect.bottom, x, y, x + w, y + h); + SetWindowPos(infoPtr->hwndEdit, HWND_TOP, x, y, w, h, + SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOZORDER); +} + + +static void COMBOEX_ReSize (COMBOEX_INFO *infoPtr) +{ + SIZE mysize; + LONG cy; + IMAGEINFO iinfo; + + COMBOEX_GetComboFontSize (infoPtr, &mysize); + cy = mysize.cy + CBE_EXTRA; + if (infoPtr->himl && ImageList_GetImageInfo(infoPtr->himl, 0, &iinfo)) { + cy = max (iinfo.rcImage.bottom - iinfo.rcImage.top, cy); + TRACE("upgraded height due to image: height=%ld\n", cy); + } + SendMessageW (infoPtr->hwndSelf, CB_SETITEMHEIGHT, (WPARAM)-1, (LPARAM)cy); + if (infoPtr->hwndCombo) { + SendMessageW (infoPtr->hwndCombo, CB_SETITEMHEIGHT, + (WPARAM) 0, (LPARAM) cy); + if ( !(infoPtr->flags & CBES_EX_NOSIZELIMIT)) { + RECT comboRect; + if (GetWindowRect(infoPtr->hwndCombo, &comboRect)) { + RECT ourRect; + if (GetWindowRect(infoPtr->hwndSelf, &ourRect)) { + if (comboRect.bottom > ourRect.bottom) { + POINT pt = { ourRect.left, ourRect.top }; + if (ScreenToClient(infoPtr->hwndSelf, &pt)) + MoveWindow( infoPtr->hwndSelf, pt.x, pt.y, ourRect.right - ourRect.left, + comboRect.bottom - comboRect.top, FALSE); + } + } + } + } + } +} + + +static void COMBOEX_SetEditText (COMBOEX_INFO *infoPtr, CBE_ITEMDATA *item) +{ + if (!infoPtr->hwndEdit) return; + /* native issues the following messages to the {Edit} control */ + /* WM_SETTEXT (0,addr) */ + /* EM_SETSEL32 (0,0) */ + /* EM_SETSEL32 (0,-1) */ + if (item->mask & CBEIF_TEXT) { + SendMessageW (infoPtr->hwndEdit, WM_SETTEXT, 0, (LPARAM)COMBOEX_GetText(infoPtr, item)); + SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, 0); + SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, -1); + } +} + + +static CBE_ITEMDATA * COMBOEX_FindItem(COMBOEX_INFO *infoPtr, INT index) +{ + CBE_ITEMDATA *item; + INT i; + + if ((index > infoPtr->nb_items) || (index < -1)) + return 0; + if (index == -1) + return infoPtr->edit; + item = infoPtr->items; + i = infoPtr->nb_items - 1; + + /* find the item in the list */ + while (item && (i > index)) { + item = item->next; + i--; + } + if (!item || (i != index)) { + ERR("COMBOBOXEX item structures broken. Please report!\n"); + return 0; + } + return item; +} + + +static inline BOOL COMBOEX_HasEdit(COMBOEX_INFO *infoPtr) +{ + return infoPtr->hwndEdit ? TRUE : FALSE; +} + + +/* *** CBEM_xxx message support *** */ + + +static INT COMBOEX_DeleteItem (COMBOEX_INFO *infoPtr, INT index) +{ + CBE_ITEMDATA *item; + + TRACE("(index=%d)\n", index); + + /* if item number requested does not exist then return failure */ + if ((index > infoPtr->nb_items) || (index < 0)) return CB_ERR; + if (!(item = COMBOEX_FindItem(infoPtr, index))) return CB_ERR; + + /* doing this will result in WM_DELETEITEM being issued */ + SendMessageW (infoPtr->hwndCombo, CB_DELETESTRING, (WPARAM)index, 0); + + return infoPtr->nb_items; +} + + +static BOOL COMBOEX_GetItemW (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW *cit) +{ + INT index = cit->iItem; + CBE_ITEMDATA *item; + + TRACE("(...)\n"); + + /* if item number requested does not exist then return failure */ + if ((index > infoPtr->nb_items) || (index < -1)) return FALSE; + + /* if the item is the edit control and there is no edit control, skip */ + if ((index == -1) && !COMBOEX_HasEdit(infoPtr)) return FALSE; + + if (!(item = COMBOEX_FindItem(infoPtr, index))) return FALSE; + + COMBOEX_CopyItem (item, cit); + + return TRUE; +} + + +static BOOL COMBOEX_GetItemA (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMA *cit) +{ + COMBOBOXEXITEMW tmpcit; + + TRACE("(...)\n"); + + tmpcit.mask = cit->mask; + tmpcit.iItem = cit->iItem; + tmpcit.pszText = 0; + if(!COMBOEX_GetItemW (infoPtr, &tmpcit)) return FALSE; + + if (is_textW(tmpcit.pszText) && cit->pszText) + WideCharToMultiByte (CP_ACP, 0, tmpcit.pszText, -1, + cit->pszText, cit->cchTextMax, NULL, NULL); + else if (cit->pszText) cit->pszText[0] = 0; + else cit->pszText = (LPSTR)tmpcit.pszText; + + cit->iImage = tmpcit.iImage; + cit->iSelectedImage = tmpcit.iSelectedImage; + cit->iOverlay = tmpcit.iOverlay; + cit->iIndent = tmpcit.iIndent; + cit->lParam = tmpcit.lParam; + + return TRUE; +} + + +inline static BOOL COMBOEX_HasEditChanged (COMBOEX_INFO *infoPtr) +{ + return COMBOEX_HasEdit(infoPtr) && + (infoPtr->flags & WCBE_EDITHASCHANGED) == WCBE_EDITHASCHANGED; +} + + +static INT COMBOEX_InsertItemW (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW *cit) +{ + INT index; + CBE_ITEMDATA *item; + NMCOMBOBOXEXW nmcit; + + TRACE("\n"); + + if (TRACE_ON(comboex)) COMBOEX_DumpInput (cit); + + /* get real index of item to insert */ + index = cit->iItem; + if (index == -1) index = infoPtr->nb_items; + if (index > infoPtr->nb_items) index = infoPtr->nb_items; + + /* get zero-filled space and chain it in */ + if(!(item = (CBE_ITEMDATA *)Alloc (sizeof(*item)))) return -1; + + /* locate position to insert new item in */ + if (index == infoPtr->nb_items) { + /* fast path for iItem = -1 */ + item->next = infoPtr->items; + infoPtr->items = item; + } + else { + INT i = infoPtr->nb_items-1; + CBE_ITEMDATA *moving = infoPtr->items; + + while ((i > index) && moving) { + moving = moving->next; + i--; + } + if (!moving) { + ERR("COMBOBOXEX item structures broken. Please report!\n"); + Free(item); + return -1; + } + item->next = moving->next; + moving->next = item; + } + + /* fill in our hidden item structure */ + item->mask = cit->mask; + if (item->mask & CBEIF_TEXT) { + INT len = 0; + + if (is_textW(cit->pszText)) len = strlenW (cit->pszText); + if (len > 0) { + item->pszText = (LPWSTR)Alloc ((len + 1)*sizeof(WCHAR)); + if (!item->pszText) { + Free(item); + return -1; + } + strcpyW (item->pszText, cit->pszText); + } + else if (cit->pszText == LPSTR_TEXTCALLBACKW) + item->pszText = LPSTR_TEXTCALLBACKW; + item->cchTextMax = cit->cchTextMax; + } + if (item->mask & CBEIF_IMAGE) + item->iImage = cit->iImage; + if (item->mask & CBEIF_SELECTEDIMAGE) + item->iSelectedImage = cit->iSelectedImage; + if (item->mask & CBEIF_OVERLAY) + item->iOverlay = cit->iOverlay; + if (item->mask & CBEIF_INDENT) + item->iIndent = cit->iIndent; + if (item->mask & CBEIF_LPARAM) + item->lParam = cit->lParam; + infoPtr->nb_items++; + + if (TRACE_ON(comboex)) COMBOEX_DumpItem (item); + + SendMessageW (infoPtr->hwndCombo, CB_INSERTSTRING, + (WPARAM)cit->iItem, (LPARAM)item); + + memset (&nmcit.ceItem, 0, sizeof(nmcit.ceItem)); + COMBOEX_CopyItem (item, &nmcit.ceItem); + COMBOEX_NotifyItem (infoPtr, CBEN_INSERTITEM, &nmcit); + + return index; + +} + + +static INT COMBOEX_InsertItemA (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMA *cit) +{ + COMBOBOXEXITEMW citW; + LPWSTR wstr = NULL; + INT ret; + + memcpy(&citW,cit,sizeof(COMBOBOXEXITEMA)); + if (cit->mask & CBEIF_TEXT && is_textA(cit->pszText)) { + INT len = MultiByteToWideChar (CP_ACP, 0, cit->pszText, -1, NULL, 0); + wstr = (LPWSTR)Alloc ((len + 1)*sizeof(WCHAR)); + if (!wstr) return -1; + MultiByteToWideChar (CP_ACP, 0, cit->pszText, -1, wstr, len); + citW.pszText = wstr; + } + ret = COMBOEX_InsertItemW(infoPtr, &citW); + + if (wstr) Free(wstr); + + return ret; +} + + +static DWORD +COMBOEX_SetExtendedStyle (COMBOEX_INFO *infoPtr, DWORD mask, DWORD style) +{ + DWORD dwTemp; + + TRACE("(mask=x%08lx, style=0x%08lx)\n", mask, style); + + dwTemp = infoPtr->dwExtStyle; + + if (mask) + infoPtr->dwExtStyle = (infoPtr->dwExtStyle & ~mask) | style; + else + infoPtr->dwExtStyle = style; + + /* see if we need to change the word break proc on the edit */ + if ((infoPtr->dwExtStyle ^ dwTemp) & CBES_EX_PATHWORDBREAKPROC) + SetPathWordBreakProc(infoPtr->hwndEdit, + (infoPtr->dwExtStyle & CBES_EX_PATHWORDBREAKPROC) ? TRUE : FALSE); + + /* test if the control's appearance has changed */ + mask = CBES_EX_NOEDITIMAGE | CBES_EX_NOEDITIMAGEINDENT; + if ((infoPtr->dwExtStyle & mask) != (dwTemp & mask)) { + /* if state of EX_NOEDITIMAGE changes, invalidate all */ + TRACE("EX_NOEDITIMAGE state changed to %ld\n", + infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGE); + InvalidateRect (infoPtr->hwndSelf, NULL, TRUE); + COMBOEX_AdjustEditPos (infoPtr); + if (infoPtr->hwndEdit) + InvalidateRect (infoPtr->hwndEdit, NULL, TRUE); + } + + return dwTemp; +} + + +static HIMAGELIST COMBOEX_SetImageList (COMBOEX_INFO *infoPtr, HIMAGELIST himl) +{ + HIMAGELIST himlTemp = infoPtr->himl; + + TRACE("(...)\n"); + + infoPtr->himl = himl; + + COMBOEX_ReSize (infoPtr); + InvalidateRect (infoPtr->hwndCombo, NULL, TRUE); + + /* reposition the Edit control based on whether icon exists */ + COMBOEX_AdjustEditPos (infoPtr); + return himlTemp; +} + +static BOOL COMBOEX_SetItemW (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMW *cit) +{ + INT index = cit->iItem; + CBE_ITEMDATA *item; + + if (TRACE_ON(comboex)) COMBOEX_DumpInput (cit); + + /* if item number requested does not exist then return failure */ + if ((index > infoPtr->nb_items) || (index < -1)) return FALSE; + + /* if the item is the edit control and there is no edit control, skip */ + if ((index == -1) && !COMBOEX_HasEdit(infoPtr)) return FALSE; + + if (!(item = COMBOEX_FindItem(infoPtr, index))) return FALSE; + + /* add/change stuff to the internal item structure */ + item->mask |= cit->mask; + if (cit->mask & CBEIF_TEXT) { + INT len = 0; + + COMBOEX_FreeText(item); + if (is_textW(cit->pszText)) len = strlenW(cit->pszText); + if (len > 0) { + item->pszText = (LPWSTR)Alloc ((len + 1)*sizeof(WCHAR)); + if (!item->pszText) return FALSE; + strcpyW(item->pszText, cit->pszText); + } else if (cit->pszText == LPSTR_TEXTCALLBACKW) + item->pszText = LPSTR_TEXTCALLBACKW; + item->cchTextMax = cit->cchTextMax; + } + if (cit->mask & CBEIF_IMAGE) + item->iImage = cit->iImage; + if (cit->mask & CBEIF_SELECTEDIMAGE) + item->iSelectedImage = cit->iSelectedImage; + if (cit->mask & CBEIF_OVERLAY) + item->iOverlay = cit->iOverlay; + if (cit->mask & CBEIF_INDENT) + item->iIndent = cit->iIndent; + if (cit->mask & CBEIF_LPARAM) + cit->lParam = cit->lParam; + + if (TRACE_ON(comboex)) COMBOEX_DumpItem (item); + + /* if original request was to update edit control, do some fast foot work */ + if (cit->iItem == -1) { + COMBOEX_SetEditText (infoPtr, item); + RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE | RDW_INVALIDATE); + } + return TRUE; +} + +static BOOL COMBOEX_SetItemA (COMBOEX_INFO *infoPtr, COMBOBOXEXITEMA *cit) +{ + COMBOBOXEXITEMW citW; + LPWSTR wstr = NULL; + BOOL ret; + + memcpy(&citW, cit, sizeof(COMBOBOXEXITEMA)); + if ((cit->mask & CBEIF_TEXT) && is_textA(cit->pszText)) { + INT len = MultiByteToWideChar (CP_ACP, 0, cit->pszText, -1, NULL, 0); + wstr = (LPWSTR)Alloc ((len + 1)*sizeof(WCHAR)); + if (!wstr) return FALSE; + MultiByteToWideChar (CP_ACP, 0, cit->pszText, -1, wstr, len); + citW.pszText = wstr; + } + ret = COMBOEX_SetItemW(infoPtr, &citW); + + if (wstr) Free(wstr); + + return ret; +} + + +static BOOL COMBOEX_SetUnicodeFormat (COMBOEX_INFO *infoPtr, BOOL value) +{ + BOOL bTemp = infoPtr->unicode; + + TRACE("to %s, was %s\n", value ? "TRUE":"FALSE", bTemp ? "TRUE":"FALSE"); + + infoPtr->unicode = value; + + return bTemp; +} + + +/* *** CB_xxx message support *** */ + +static INT +COMBOEX_FindStringExact (COMBOEX_INFO *infoPtr, INT start, LPCWSTR str) +{ + INT i; + cmp_func_t cmptext = get_cmp_func(infoPtr); + INT count = SendMessageW (infoPtr->hwndCombo, CB_GETCOUNT, 0, 0); + + /* now search from after starting loc and wrapping back to start */ + for(i=start+1; imask & CBEIF_LPARAM) ret = item1->lParam; + TRACE("returning 0x%08lx\n", ret); + } else { + ret = (DWORD)item1; + TRACE("non-valid result from combo, returning 0x%08lx\n", ret); + } + return ret; +} + + +static INT COMBOEX_SetCursel (COMBOEX_INFO *infoPtr, INT index) +{ + CBE_ITEMDATA *item; + INT sel; + + if (!(item = COMBOEX_FindItem(infoPtr, index))) + return SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL, index, 0); + + TRACE("selecting item %d text=%s\n", index, debugstr_txt(item->pszText)); + infoPtr->selected = index; + + sel = (INT)SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL, index, 0); + COMBOEX_SetEditText (infoPtr, item); + return sel; +} + + +static DWORD COMBOEX_SetItemData (COMBOEX_INFO *infoPtr, INT index, DWORD data) +{ + CBE_ITEMDATA *item1, *item2; + + item1 = get_item_data(infoPtr, index); + if ((item1 != NULL) && ((LRESULT)item1 != CB_ERR)) { + item2 = COMBOEX_FindItem (infoPtr, index); + if (item2 != item1) { + ERR("data structures damaged!\n"); + return CB_ERR; + } + item1->mask |= CBEIF_LPARAM; + item1->lParam = data; + TRACE("setting lparam to 0x%08lx\n", data); + return 0; + } + TRACE("non-valid result from combo 0x%08lx\n", (DWORD)item1); + return (LRESULT)item1; +} + + +static INT COMBOEX_SetItemHeight (COMBOEX_INFO *infoPtr, INT index, UINT height) +{ + RECT cb_wrect, cbx_wrect, cbx_crect; + + /* First, lets forward the message to the normal combo control + just like Windows. */ + if (infoPtr->hwndCombo) + if (SendMessageW (infoPtr->hwndCombo, CB_SETITEMHEIGHT, + index, height) == CB_ERR) return CB_ERR; + + GetWindowRect (infoPtr->hwndCombo, &cb_wrect); + GetWindowRect (infoPtr->hwndSelf, &cbx_wrect); + GetClientRect (infoPtr->hwndSelf, &cbx_crect); + /* the height of comboex as height of the combo + comboex border */ + height = cb_wrect.bottom-cb_wrect.top + + cbx_wrect.bottom-cbx_wrect.top + - (cbx_crect.bottom-cbx_crect.top); + TRACE("EX window=(%ld,%ld)-(%ld,%ld), client=(%ld,%ld)-(%ld,%ld)\n", + cbx_wrect.left, cbx_wrect.top, cbx_wrect.right, cbx_wrect.bottom, + cbx_crect.left, cbx_crect.top, cbx_crect.right, cbx_crect.bottom); + TRACE("CB window=(%ld,%ld)-(%ld,%ld), EX setting=(0,0)-(%ld,%d)\n", + cb_wrect.left, cb_wrect.top, cb_wrect.right, cb_wrect.bottom, + cbx_wrect.right-cbx_wrect.left, height); + SetWindowPos (infoPtr->hwndSelf, HWND_TOP, 0, 0, + cbx_wrect.right-cbx_wrect.left, height, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE); + + return 0; +} + + +/* *** WM_xxx message support *** */ + + +static LRESULT COMBOEX_Create (HWND hwnd, LPCREATESTRUCTA cs) +{ + static const WCHAR COMBOBOX[] = { 'C', 'o', 'm', 'b', 'o', 'B', 'o', 'x', 0 }; + static const WCHAR EDIT[] = { 'E', 'D', 'I', 'T', 0 }; + static const WCHAR NIL[] = { 0 }; + COMBOEX_INFO *infoPtr; + LOGFONTW mylogfont; + RECT wnrc1, clrc1, cmbwrc; + INT i; + + /* allocate memory for info structure */ + infoPtr = (COMBOEX_INFO *)Alloc (sizeof(COMBOEX_INFO)); + if (!infoPtr) return -1; + + /* initialize info structure */ + /* note that infoPtr is allocated zero-filled */ + + infoPtr->hwndSelf = hwnd; + infoPtr->selected = -1; + + infoPtr->unicode = IsWindowUnicode (hwnd); + infoPtr->hwndNotify = cs->hwndParent; + + i = SendMessageW(infoPtr->hwndNotify, WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY); + if ((i != NFR_ANSI) && (i != NFR_UNICODE)) { + WARN("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n", i); + i = NFR_ANSI; + } + infoPtr->NtfUnicode = (i == NFR_UNICODE); + + SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); + + /* create combo box */ + GetWindowRect(hwnd, &wnrc1); + GetClientRect(hwnd, &clrc1); + TRACE("EX window=(%ld,%ld)-(%ld,%ld) client=(%ld,%ld)-(%ld,%ld)\n", + wnrc1.left, wnrc1.top, wnrc1.right, wnrc1.bottom, + clrc1.left, clrc1.top, clrc1.right, clrc1.bottom); + + /* Native version of ComboEx creates the ComboBox with DROPDOWNLIST */ + /* specified. It then creates it's own version of the EDIT control */ + /* and makes the ComboBox the parent. This is because a normal */ + /* DROPDOWNLIST does not have an EDIT control, but we need one. */ + /* We also need to place the edit control at the proper location */ + /* (allow space for the icons). */ + + infoPtr->hwndCombo = CreateWindowW (COMBOBOX, NIL, + /* following line added to match native */ + WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VSCROLL | + CBS_NOINTEGRALHEIGHT | CBS_DROPDOWNLIST | + /* was base and is necessary */ + WS_CHILD | WS_VISIBLE | CBS_OWNERDRAWFIXED | + GetWindowLongW (hwnd, GWL_STYLE), + cs->y, cs->x, cs->cx, cs->cy, hwnd, + (HMENU) GetWindowLongPtrW (hwnd, GWLP_ID), + (HINSTANCE)GetWindowLongPtrW (hwnd, GWLP_HINSTANCE), NULL); + + /* + * native does the following at this point according to trace: + * GetWindowThreadProcessId(hwndCombo,0) + * GetCurrentThreadId() + * GetWindowThreadProcessId(hwndCombo, &???) + * GetCurrentProcessId() + */ + + /* + * Setup a property to hold the pointer to the COMBOBOXEX + * data structure. + */ + SetPropW(infoPtr->hwndCombo, COMBOEX_SUBCLASS_PROP, hwnd); + infoPtr->prevComboWndProc = (WNDPROC)SetWindowLongPtrW(infoPtr->hwndCombo, + GWLP_WNDPROC, (DWORD_PTR)COMBOEX_ComboWndProc); + infoPtr->font = (HFONT)SendMessageW (infoPtr->hwndCombo, WM_GETFONT, 0, 0); + + + /* + * Now create our own EDIT control so we can position it. + * It is created only for CBS_DROPDOWN style + */ + if ((cs->style & CBS_DROPDOWNLIST) == CBS_DROPDOWN) { + infoPtr->hwndEdit = CreateWindowExW (0, EDIT, NIL, + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | ES_AUTOHSCROLL, + 0, 0, 0, 0, /* will set later */ + infoPtr->hwndCombo, + (HMENU) GetWindowLongPtrW (hwnd, GWLP_ID), + (HINSTANCE)GetWindowLongPtrW (hwnd, GWLP_HINSTANCE), NULL); + + /* native does the following at this point according to trace: + * GetWindowThreadProcessId(hwndEdit,0) + * GetCurrentThreadId() + * GetWindowThreadProcessId(hwndEdit, &???) + * GetCurrentProcessId() + */ + + /* + * Setup a property to hold the pointer to the COMBOBOXEX + * data structure. + */ + SetPropW(infoPtr->hwndEdit, COMBOEX_SUBCLASS_PROP, hwnd); + infoPtr->prevEditWndProc = (WNDPROC)SetWindowLongPtrW(infoPtr->hwndEdit, + GWLP_WNDPROC, (DWORD_PTR)COMBOEX_EditWndProc); + infoPtr->font = (HFONT)SendMessageW(infoPtr->hwndCombo, WM_GETFONT, 0, 0); + } + + /* + * Locate the default font if necessary and then set it in + * all associated controls + */ + if (!infoPtr->font) { + SystemParametersInfoW (SPI_GETICONTITLELOGFONT, sizeof(mylogfont), + &mylogfont, 0); + infoPtr->font = infoPtr->defaultFont = CreateFontIndirectW (&mylogfont); + } + SendMessageW (infoPtr->hwndCombo, WM_SETFONT, (WPARAM)infoPtr->font, 0); + if (infoPtr->hwndEdit) { + SendMessageW (infoPtr->hwndEdit, WM_SETFONT, (WPARAM)infoPtr->font, 0); + SendMessageW (infoPtr->hwndEdit, EM_SETMARGINS, (WPARAM)EC_USEFONTINFO, 0); + } + + COMBOEX_ReSize (infoPtr); + + /* Above is fairly certain, below is much less certain. */ + + GetWindowRect(hwnd, &wnrc1); + GetClientRect(hwnd, &clrc1); + GetWindowRect(infoPtr->hwndCombo, &cmbwrc); + TRACE("EX window=(%ld,%ld)-(%ld,%ld) client=(%ld,%ld)-(%ld,%ld) CB wnd=(%ld,%ld)-(%ld,%ld)\n", + wnrc1.left, wnrc1.top, wnrc1.right, wnrc1.bottom, + clrc1.left, clrc1.top, clrc1.right, clrc1.bottom, + cmbwrc.left, cmbwrc.top, cmbwrc.right, cmbwrc.bottom); + SetWindowPos(infoPtr->hwndCombo, HWND_TOP, + 0, 0, wnrc1.right-wnrc1.left, wnrc1.bottom-wnrc1.top, + SWP_NOACTIVATE | SWP_NOREDRAW); + + GetWindowRect(infoPtr->hwndCombo, &cmbwrc); + TRACE("CB window=(%ld,%ld)-(%ld,%ld)\n", + cmbwrc.left, cmbwrc.top, cmbwrc.right, cmbwrc.bottom); + SetWindowPos(hwnd, HWND_TOP, + 0, 0, cmbwrc.right-cmbwrc.left, cmbwrc.bottom-cmbwrc.top, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE); + + COMBOEX_AdjustEditPos (infoPtr); + + /* + * Create an item structure to represent the data in the + * EDIT control. It is allocated zero-filled. + */ + infoPtr->edit = (CBE_ITEMDATA *)Alloc (sizeof (CBE_ITEMDATA)); + if (!infoPtr->edit) { + COMBOEX_Destroy(infoPtr); + return -1; + } + + return 0; +} + + +static LRESULT COMBOEX_Command (COMBOEX_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + LRESULT lret; + INT command = HIWORD(wParam); + CBE_ITEMDATA *item = 0; + WCHAR wintext[520]; + INT cursel, n, oldItem; + NMCBEENDEDITW cbeend; + DWORD oldflags; + HWND parent = infoPtr->hwndNotify; + + TRACE("for command %d\n", command); + + switch (command) + { + case CBN_DROPDOWN: + SetFocus (infoPtr->hwndCombo); + ShowWindow (infoPtr->hwndEdit, SW_HIDE); + return SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf); + + case CBN_CLOSEUP: + SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf); + /* + * from native trace of first dropdown after typing in URL in IE4 + * CB_GETCURSEL(Combo) + * GetWindowText(Edit) + * CB_GETCURSEL(Combo) + * CB_GETCOUNT(Combo) + * CB_GETITEMDATA(Combo, n) + * WM_NOTIFY(parent, CBEN_ENDEDITA|W) + * CB_GETCURSEL(Combo) + * CB_SETCURSEL(COMBOEX, n) + * SetFocus(Combo) + * the rest is supposition + */ + ShowWindow (infoPtr->hwndEdit, SW_SHOW); + InvalidateRect (infoPtr->hwndCombo, 0, TRUE); + InvalidateRect (infoPtr->hwndEdit, 0, TRUE); + cursel = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0); + if (cursel == -1) { + cmp_func_t cmptext = get_cmp_func(infoPtr); + /* find match from edit against those in Combobox */ + GetWindowTextW (infoPtr->hwndEdit, wintext, 520); + n = SendMessageW (infoPtr->hwndCombo, CB_GETCOUNT, 0, 0); + for (cursel = 0; cursel < n; cursel++){ + item = get_item_data(infoPtr, cursel); + if ((INT)item == CB_ERR) break; + if (!cmptext(COMBOEX_GetText(infoPtr, item), wintext)) break; + } + if ((cursel == n) || ((INT)item == CB_ERR)) { + TRACE("failed to find match??? item=%p cursel=%d\n", + item, cursel); + if (infoPtr->hwndEdit) + SetFocus(infoPtr->hwndEdit); + return 0; + } + } + else { + item = get_item_data(infoPtr, cursel); + if ((INT)item == CB_ERR) { + TRACE("failed to find match??? item=%p cursel=%d\n", + item, cursel); + if (infoPtr->hwndEdit) + SetFocus(infoPtr->hwndEdit); + return 0; + } + } + + /* Save flags for testing and reset them */ + oldflags = infoPtr->flags; + infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG); + + if (oldflags & WCBE_ACTEDIT) { + cbeend.fChanged = (oldflags & WCBE_EDITCHG); + cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo, + CB_GETCURSEL, 0, 0); + cbeend.iWhy = CBENF_DROPDOWN; + + if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, COMBOEX_GetText(infoPtr, item))) return 0; + } + + /* if selection has changed the set the new current selection */ + cursel = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0); + if ((oldflags & WCBE_EDITCHG) || (cursel != infoPtr->selected)) { + infoPtr->selected = cursel; + SendMessageW (infoPtr->hwndSelf, CB_SETCURSEL, cursel, 0); + SetFocus(infoPtr->hwndCombo); + } + return 0; + + case CBN_SELCHANGE: + /* + * CB_GETCURSEL(Combo) + * CB_GETITEMDATA(Combo) < simulated by COMBOEX_FindItem + * lstrlenA + * WM_SETTEXT(Edit) + * WM_GETTEXTLENGTH(Edit) + * WM_GETTEXT(Edit) + * EM_SETSEL(Edit, 0,0) + * WM_GETTEXTLENGTH(Edit) + * WM_GETTEXT(Edit) + * EM_SETSEL(Edit, 0,len) + * return WM_COMMAND to parent + */ + oldItem = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0); + if (!(item = COMBOEX_FindItem(infoPtr, oldItem))) { + ERR("item %d not found. Problem!\n", oldItem); + break; + } + infoPtr->selected = oldItem; + COMBOEX_SetEditText (infoPtr, item); + return SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf); + + case CBN_SELENDOK: + /* + * We have to change the handle since we are the control + * issuing the message. IE4 depends on this. + */ + return SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf); + + case CBN_KILLFOCUS: + /* + * from native trace: + * + * pass to parent + * WM_GETTEXT(Edit, 104) + * CB_GETCURSEL(Combo) rets -1 + * WM_NOTIFY(CBEN_ENDEDITA) with CBENF_KILLFOCUS + * CB_GETCURSEL(Combo) + * InvalidateRect(Combo, 0, 0) + * return 0 + */ + SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf); + if (infoPtr->flags & WCBE_ACTEDIT) { + GetWindowTextW (infoPtr->hwndEdit, wintext, 260); + cbeend.fChanged = (infoPtr->flags & WCBE_EDITCHG); + cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo, + CB_GETCURSEL, 0, 0); + cbeend.iWhy = CBENF_KILLFOCUS; + + infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG); + if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, wintext)) return 0; + } + /* possible CB_GETCURSEL */ + InvalidateRect (infoPtr->hwndCombo, 0, 0); + return 0; + + default: + /* + * We have to change the handle since we are the control + * issuing the message. IE4 depends on this. + * We also need to set the focus back to the Edit control + * after passing the command to the parent of the ComboEx. + */ + lret = SendMessageW (parent, WM_COMMAND, wParam, (LPARAM)infoPtr->hwndSelf); + if (infoPtr->hwndEdit) + SetFocus(infoPtr->hwndEdit); + return lret; + } + return 0; +} + + +static BOOL COMBOEX_WM_DeleteItem (COMBOEX_INFO *infoPtr, DELETEITEMSTRUCT *dis) +{ + CBE_ITEMDATA *item, *olditem; + NMCOMBOBOXEXW nmcit; + UINT i; + + TRACE("CtlType=%08x, CtlID=%08x, itemID=%08x, hwnd=%p, data=%08lx\n", + dis->CtlType, dis->CtlID, dis->itemID, dis->hwndItem, dis->itemData); + + if (dis->itemID >= infoPtr->nb_items) return FALSE; + + olditem = infoPtr->items; + i = infoPtr->nb_items - 1; + + if (i == dis->itemID) { + infoPtr->items = infoPtr->items->next; + } + else { + item = olditem; + i--; + + /* find the prior item in the list */ + while (item->next && (i > dis->itemID)) { + item = item->next; + i--; + } + if (!item->next || (i != dis->itemID)) { + ERR("COMBOBOXEX item structures broken. Please report!\n"); + return FALSE; + } + olditem = item->next; + item->next = item->next->next; + } + infoPtr->nb_items--; + + memset (&nmcit.ceItem, 0, sizeof(nmcit.ceItem)); + COMBOEX_CopyItem (olditem, &nmcit.ceItem); + COMBOEX_NotifyItem (infoPtr, CBEN_DELETEITEM, &nmcit); + + COMBOEX_FreeText(olditem); + Free(olditem); + + return TRUE; +} + + +static LRESULT COMBOEX_DrawItem (COMBOEX_INFO *infoPtr, DRAWITEMSTRUCT *dis) +{ + static const WCHAR nil[] = { 0 }; + CBE_ITEMDATA *item = 0; + SIZE txtsize; + RECT rect; + LPCWSTR str = nil; + UINT xbase, x, y; + INT len; + COLORREF nbkc, ntxc, bkc, txc; + int drawimage, drawstate, xioff; + + if (!IsWindowEnabled(infoPtr->hwndCombo)) return 0; + + TRACE("DRAWITEMSTRUCT: CtlType=0x%08x CtlID=0x%08x\n", + dis->CtlType, dis->CtlID); + TRACE("itemID=0x%08x itemAction=0x%08x itemState=0x%08x\n", + dis->itemID, dis->itemAction, dis->itemState); + TRACE("hWnd=%p hDC=%p (%ld,%ld)-(%ld,%ld) itemData=0x%08lx\n", + dis->hwndItem, dis->hDC, dis->rcItem.left, + dis->rcItem.top, dis->rcItem.right, dis->rcItem.bottom, + dis->itemData); + + /* MSDN says: */ + /* "itemID - Specifies the menu item identifier for a menu */ + /* item or the index of the item in a list box or combo box. */ + /* For an empty list box or combo box, this member can be -1. */ + /* This allows the application to draw only the focus */ + /* rectangle at the coordinates specified by the rcItem */ + /* member even though there are no items in the control. */ + /* This indicates to the user whether the list box or combo */ + /* box has the focus. How the bits are set in the itemAction */ + /* member determines whether the rectangle is to be drawn as */ + /* though the list box or combo box has the focus. */ + if (dis->itemID == 0xffffffff) { + if ( ( (dis->itemAction & ODA_FOCUS) && (dis->itemState & ODS_SELECTED)) || + ( (dis->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)) && (dis->itemState & ODS_FOCUS) ) ) { + + TRACE("drawing item -1 special focus, rect=(%ld,%ld)-(%ld,%ld)\n", + dis->rcItem.left, dis->rcItem.top, + dis->rcItem.right, dis->rcItem.bottom); + } + else if ((dis->CtlType == ODT_COMBOBOX) && + (dis->itemAction == ODA_DRAWENTIRE)) { + /* draw of edit control data */ + + /* testing */ + { + RECT exrc, cbrc, edrc; + GetWindowRect (infoPtr->hwndSelf, &exrc); + GetWindowRect (infoPtr->hwndCombo, &cbrc); + edrc.left=edrc.top=edrc.right=edrc.bottom=-1; + if (infoPtr->hwndEdit) + GetWindowRect (infoPtr->hwndEdit, &edrc); + TRACE("window rects ex=(%ld,%ld)-(%ld,%ld), cb=(%ld,%ld)-(%ld,%ld), ed=(%ld,%ld)-(%ld,%ld)\n", + exrc.left, exrc.top, exrc.right, exrc.bottom, + cbrc.left, cbrc.top, cbrc.right, cbrc.bottom, + edrc.left, edrc.top, edrc.right, edrc.bottom); + } + } + else { + ERR("NOT drawing item -1 special focus, rect=(%ld,%ld)-(%ld,%ld), action=%08x, state=%08x\n", + dis->rcItem.left, dis->rcItem.top, + dis->rcItem.right, dis->rcItem.bottom, + dis->itemAction, dis->itemState); + return 0; + } + } + + /* If draw item is -1 (edit control) setup the item pointer */ + if (dis->itemID == 0xffffffff) { + item = infoPtr->edit; + + if (infoPtr->hwndEdit) { + INT len; + + /* free previous text of edit item */ + COMBOEX_FreeText(item); + item->mask &= ~CBEIF_TEXT; + if( (len = GetWindowTextLengthW(infoPtr->hwndEdit)) ) { + item->mask |= CBEIF_TEXT; + item->pszText = (LPWSTR)Alloc ((len + 1)*sizeof(WCHAR)); + if (item->pszText) + GetWindowTextW(infoPtr->hwndEdit, item->pszText, len+1); + + TRACE("edit control hwndEdit=%p, text len=%d str=%s\n", + infoPtr->hwndEdit, len, debugstr_txt(item->pszText)); + } + } + } + + + /* if the item pointer is not set, then get the data and locate it */ + if (!item) { + item = get_item_data(infoPtr, dis->itemID); + if (item == (CBE_ITEMDATA *)CB_ERR) { + ERR("invalid item for id %d \n", dis->itemID); + return 0; + } + } + + if (TRACE_ON(comboex)) COMBOEX_DumpItem (item); + + xbase = CBE_STARTOFFSET; + if ((item->mask & CBEIF_INDENT) && (dis->itemState & ODS_COMBOEXLBOX)) { + INT indent = item->iIndent; + if (indent == I_INDENTCALLBACK) { + NMCOMBOBOXEXW nmce; + ZeroMemory(&nmce, sizeof(nmce)); + nmce.ceItem.mask = CBEIF_INDENT; + nmce.ceItem.lParam = item->lParam; + nmce.ceItem.iItem = dis->itemID; + COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce); + if (nmce.ceItem.mask & CBEIF_DI_SETITEM) + item->iIndent = nmce.ceItem.iIndent; + indent = nmce.ceItem.iIndent; + } + xbase += (indent * CBE_INDENT); + } + + drawimage = -2; + drawstate = ILD_NORMAL; + if (item->mask & CBEIF_IMAGE) + drawimage = item->iImage; + if (dis->itemState & ODS_COMBOEXLBOX) { + /* drawing listbox entry */ + if (dis->itemState & ODS_SELECTED) { + if (item->mask & CBEIF_SELECTEDIMAGE) + drawimage = item->iSelectedImage; + drawstate = ILD_SELECTED; + } + } else { + /* drawing combo/edit entry */ + if (IsWindowVisible(infoPtr->hwndEdit)) { + /* if we have an edit control, the slave the + * selection state to the Edit focus state + */ + if (infoPtr->flags & WCBE_EDITFOCUSED) { + if (item->mask & CBEIF_SELECTEDIMAGE) + drawimage = item->iSelectedImage; + drawstate = ILD_SELECTED; + } + } else { + /* if we don't have an edit control, use + * the requested state. + */ + if (dis->itemState & ODS_SELECTED) { + if (item->mask & CBEIF_SELECTEDIMAGE) + drawimage = item->iSelectedImage; + drawstate = ILD_SELECTED; + } + } + } + + if (infoPtr->himl && !(infoPtr->dwExtStyle & CBES_EX_NOEDITIMAGEINDENT)) { + IMAGEINFO iinfo; + iinfo.rcImage.left = iinfo.rcImage.right = 0; + ImageList_GetImageInfo(infoPtr->himl, 0, &iinfo); + xioff = iinfo.rcImage.right - iinfo.rcImage.left + CBE_SEP; + } else xioff = 0; + + /* setup pointer to text to be drawn */ + str = COMBOEX_GetText(infoPtr, item); + if (!str) str = nil; + + len = strlenW (str); + GetTextExtentPoint32W (dis->hDC, str, len, &txtsize); + + if (dis->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)) { + int overlay = item->iOverlay; + + if (drawimage == I_IMAGECALLBACK) { + NMCOMBOBOXEXW nmce; + ZeroMemory(&nmce, sizeof(nmce)); + nmce.ceItem.mask = (drawstate == ILD_NORMAL) ? CBEIF_IMAGE : CBEIF_SELECTEDIMAGE; + nmce.ceItem.lParam = item->lParam; + nmce.ceItem.iItem = dis->itemID; + COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce); + if (drawstate == ILD_NORMAL) { + if (nmce.ceItem.mask & CBEIF_DI_SETITEM) item->iImage = nmce.ceItem.iImage; + drawimage = nmce.ceItem.iImage; + } else if (drawstate == ILD_SELECTED) { + if (nmce.ceItem.mask & CBEIF_DI_SETITEM) item->iSelectedImage = nmce.ceItem.iSelectedImage; + drawimage = nmce.ceItem.iSelectedImage; + } else ERR("Bad draw state = %d\n", drawstate); + } + + if (overlay == I_IMAGECALLBACK) { + NMCOMBOBOXEXW nmce; + ZeroMemory(&nmce, sizeof(nmce)); + nmce.ceItem.mask = CBEIF_OVERLAY; + nmce.ceItem.lParam = item->lParam; + nmce.ceItem.iItem = dis->itemID; + COMBOEX_NotifyItem(infoPtr, CBEN_GETDISPINFOW, &nmce); + if (nmce.ceItem.mask & CBEIF_DI_SETITEM) + item->iOverlay = nmce.ceItem.iOverlay; + overlay = nmce.ceItem.iOverlay; + } + + if (drawimage >= 0 && + !(infoPtr->dwExtStyle & (CBES_EX_NOEDITIMAGE | CBES_EX_NOEDITIMAGEINDENT))) { + if (overlay > 0) ImageList_SetOverlayImage (infoPtr->himl, overlay, 1); + ImageList_Draw (infoPtr->himl, drawimage, dis->hDC, xbase, dis->rcItem.top, + drawstate | (overlay > 0 ? INDEXTOOVERLAYMASK(1) : 0)); + } + + /* now draw the text */ + if (!IsWindowVisible (infoPtr->hwndEdit)) { + nbkc = GetSysColor ((dis->itemState & ODS_SELECTED) ? + COLOR_HIGHLIGHT : COLOR_WINDOW); + bkc = SetBkColor (dis->hDC, nbkc); + ntxc = GetSysColor ((dis->itemState & ODS_SELECTED) ? + COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT); + txc = SetTextColor (dis->hDC, ntxc); + x = xbase + xioff; + y = dis->rcItem.top + + (dis->rcItem.bottom - dis->rcItem.top - txtsize.cy) / 2; + rect.left = x; + rect.right = x + txtsize.cx; + rect.top = dis->rcItem.top + 1; + rect.bottom = dis->rcItem.bottom - 1; + TRACE("drawing item %d text, rect=(%ld,%ld)-(%ld,%ld)\n", + dis->itemID, rect.left, rect.top, rect.right, rect.bottom); + ExtTextOutW (dis->hDC, x, y, ETO_OPAQUE | ETO_CLIPPED, + &rect, str, len, 0); + SetBkColor (dis->hDC, bkc); + SetTextColor (dis->hDC, txc); + } + } + + if (dis->itemAction & ODA_FOCUS) { + rect.left = xbase + xioff - 1; + rect.right = rect.left + txtsize.cx + 2; + rect.top = dis->rcItem.top; + rect.bottom = dis->rcItem.bottom; + DrawFocusRect(dis->hDC, &rect); + } + + return 0; +} + + +static LRESULT COMBOEX_Destroy (COMBOEX_INFO *infoPtr) +{ + if (infoPtr->hwndCombo) + DestroyWindow (infoPtr->hwndCombo); + + if (infoPtr->edit) { + Free (infoPtr->edit); + infoPtr->edit = 0; + } + + if (infoPtr->items) { + CBE_ITEMDATA *item, *next; + + item = infoPtr->items; + while (item) { + next = item->next; + COMBOEX_FreeText (item); + Free (item); + item = next; + } + infoPtr->items = 0; + } + + if (infoPtr->defaultFont) + DeleteObject (infoPtr->defaultFont); + + /* free comboex info data */ + Free (infoPtr); + SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0); + return 0; +} + + +static LRESULT COMBOEX_MeasureItem (COMBOEX_INFO *infoPtr, MEASUREITEMSTRUCT *mis) +{ + static const WCHAR strW[] = { 'W', 0 }; + SIZE mysize; + HDC hdc; + + hdc = GetDC (0); + GetTextExtentPointW (hdc, strW, 1, &mysize); + ReleaseDC (0, hdc); + mis->itemHeight = mysize.cy + CBE_EXTRA; + + TRACE("adjusted height hwnd=%p, height=%d\n", + infoPtr->hwndSelf, mis->itemHeight); + + return 0; +} + + +static LRESULT COMBOEX_NCCreate (HWND hwnd) +{ + /* WARNING: The COMBOEX_INFO structure is not yet created */ + DWORD oldstyle, newstyle; + + oldstyle = (DWORD)GetWindowLongW (hwnd, GWL_STYLE); + newstyle = oldstyle & ~(WS_VSCROLL | WS_HSCROLL | WS_BORDER); + if (newstyle != oldstyle) { + TRACE("req style %08lx, reseting style %08lx\n", + oldstyle, newstyle); + SetWindowLongW (hwnd, GWL_STYLE, newstyle); + } + return 1; +} + + +static LRESULT COMBOEX_NotifyFormat (COMBOEX_INFO *infoPtr, LPARAM lParam) +{ + if (lParam == NF_REQUERY) { + INT i = SendMessageW(infoPtr->hwndNotify, + WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY); + infoPtr->NtfUnicode = (i == NFR_UNICODE) ? 1 : 0; + } + return infoPtr->NtfUnicode ? NFR_UNICODE : NFR_ANSI; +} + + +static LRESULT COMBOEX_Size (COMBOEX_INFO *infoPtr, INT width, INT height) +{ + TRACE("(width=%d, height=%d)\n", width, height); + + MoveWindow (infoPtr->hwndCombo, 0, 0, width, height, TRUE); + + COMBOEX_AdjustEditPos (infoPtr); + + return 0; +} + + +static LRESULT COMBOEX_WindowPosChanging (COMBOEX_INFO *infoPtr, WINDOWPOS *wp) +{ + RECT cbx_wrect, cbx_crect, cb_wrect; + INT width, height; + + GetWindowRect (infoPtr->hwndSelf, &cbx_wrect); + GetClientRect (infoPtr->hwndSelf, &cbx_crect); + GetWindowRect (infoPtr->hwndCombo, &cb_wrect); + + /* width is winpos value + border width of comboex */ + width = wp->cx + + (cbx_wrect.right-cbx_wrect.left) + - (cbx_crect.right-cbx_crect.left); + + TRACE("winpos=(%d,%d %dx%d) flags=0x%08x\n", + wp->x, wp->y, wp->cx, wp->cy, wp->flags); + TRACE("EX window=(%ld,%ld)-(%ld,%ld), client=(%ld,%ld)-(%ld,%ld)\n", + cbx_wrect.left, cbx_wrect.top, cbx_wrect.right, cbx_wrect.bottom, + cbx_crect.left, cbx_crect.top, cbx_crect.right, cbx_crect.bottom); + TRACE("CB window=(%ld,%ld)-(%ld,%ld), EX setting=(0,0)-(%d,%ld)\n", + cb_wrect.left, cb_wrect.top, cb_wrect.right, cb_wrect.bottom, + width, cb_wrect.bottom-cb_wrect.top); + + if (width) SetWindowPos (infoPtr->hwndCombo, HWND_TOP, 0, 0, + width, + cb_wrect.bottom-cb_wrect.top, + SWP_NOACTIVATE); + + GetWindowRect (infoPtr->hwndCombo, &cb_wrect); + + /* height is combo window height plus border width of comboex */ + height = (cb_wrect.bottom-cb_wrect.top) + + (cbx_wrect.bottom-cbx_wrect.top) + - (cbx_crect.bottom-cbx_crect.top); + if (wp->cy < height) wp->cy = height; + if (infoPtr->hwndEdit) { + COMBOEX_AdjustEditPos (infoPtr); + InvalidateRect (infoPtr->hwndCombo, 0, TRUE); + } + + return 0; +} + +static LRESULT WINAPI +COMBOEX_EditWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + HWND hwndComboex = (HWND)GetPropW(hwnd, COMBOEX_SUBCLASS_PROP); + COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwndComboex); + NMCBEENDEDITW cbeend; + WCHAR edit_text[260]; + COLORREF obkc; + HDC hDC; + RECT rect; + LRESULT lret; + + TRACE("hwnd=%p msg=%x wparam=%x lParam=%lx, info_ptr=%p\n", + hwnd, uMsg, wParam, lParam, infoPtr); + + if (!infoPtr) return 0; + + switch (uMsg) + { + + case WM_CHAR: + /* handle (ignore) the return character */ + if (wParam == VK_RETURN) return 0; + /* all other characters pass into the real Edit */ + return CallWindowProcW (infoPtr->prevEditWndProc, + hwnd, uMsg, wParam, lParam); + + case WM_ERASEBKGND: + /* + * The following was determined by traces of the native + */ + hDC = (HDC) wParam; + obkc = SetBkColor (hDC, GetSysColor (COLOR_WINDOW)); + GetClientRect (hwnd, &rect); + TRACE("erasing (%ld,%ld)-(%ld,%ld)\n", + rect.left, rect.top, rect.right, rect.bottom); + ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0); + SetBkColor (hDC, obkc); + return CallWindowProcW (infoPtr->prevEditWndProc, + hwnd, uMsg, wParam, lParam); + + case WM_KEYDOWN: { + INT oldItem, selected, step = 1; + CBE_ITEMDATA *item; + + switch ((INT)wParam) + { + case VK_ESCAPE: + /* native version seems to do following for COMBOEX */ + /* + * GetWindowTextW(Edit,&?, 0x104) x + * CB_GETCURSEL to Combo rets -1 x + * WM_NOTIFY to COMBOEX parent (rebar) x + * (CBEN_ENDEDIT{A|W} + * fChanged = FALSE x + * inewSelection = -1 x + * txt="www.hoho" x + * iWhy = 3 x + * CB_GETCURSEL to Combo rets -1 x + * InvalidateRect(Combo, 0) x + * WM_SETTEXT to Edit x + * EM_SETSEL to Edit (0,0) x + * EM_SETSEL to Edit (0,-1) x + * RedrawWindow(Combo, 0, 0, 5) x + */ + TRACE("special code for VK_ESCAPE\n"); + + GetWindowTextW (infoPtr->hwndEdit, edit_text, 260); + + infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG); + cbeend.fChanged = FALSE; + cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo, + CB_GETCURSEL, 0, 0); + cbeend.iWhy = CBENF_ESCAPE; + + if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text)) return 0; + oldItem = SendMessageW (infoPtr->hwndCombo, CB_GETCURSEL, 0, 0); + InvalidateRect (infoPtr->hwndCombo, 0, 0); + if (!(item = COMBOEX_FindItem(infoPtr, oldItem))) { + ERR("item %d not found. Problem!\n", oldItem); + break; + } + infoPtr->selected = oldItem; + COMBOEX_SetEditText (infoPtr, item); + RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE | + RDW_INVALIDATE); + break; + + case VK_RETURN: + /* native version seems to do following for COMBOEX */ + /* + * GetWindowTextW(Edit,&?, 0x104) x + * CB_GETCURSEL to Combo rets -1 x + * CB_GETCOUNT to Combo rets 0 + * if >0 loop + * CB_GETITEMDATA to match + * *** above 3 lines simulated by FindItem x + * WM_NOTIFY to COMBOEX parent (rebar) x + * (CBEN_ENDEDIT{A|W} x + * fChanged = TRUE (-1) x + * iNewSelection = -1 or selected x + * txt= x + * iWhy = 2 (CBENF_RETURN) x + * CB_GETCURSEL to Combo rets -1 x + * if -1 send CB_SETCURSEL to Combo -1 x + * InvalidateRect(Combo, 0, 0) x + * SetFocus(Edit) x + * CallWindowProc(406615a8, Edit, 0x100, 0xd, 0x1c0001) + */ + + TRACE("special code for VK_RETURN\n"); + + GetWindowTextW (infoPtr->hwndEdit, edit_text, 260); + + infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG); + selected = SendMessageW (infoPtr->hwndCombo, + CB_GETCURSEL, 0, 0); + + if (selected != -1) { + cmp_func_t cmptext = get_cmp_func(infoPtr); + item = COMBOEX_FindItem (infoPtr, selected); + TRACE("handling VK_RETURN, selected = %d, selected_text=%s\n", + selected, debugstr_txt(item->pszText)); + TRACE("handling VK_RETURN, edittext=%s\n", + debugstr_w(edit_text)); + if (cmptext (COMBOEX_GetText(infoPtr, item), edit_text)) { + /* strings not equal -- indicate edit has changed */ + selected = -1; + } + } + + cbeend.iNewSelection = selected; + cbeend.fChanged = TRUE; + cbeend.iWhy = CBENF_RETURN; + if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text)) { + /* abort the change, restore previous */ + TRACE("Notify requested abort of change\n"); + COMBOEX_SetEditText (infoPtr, infoPtr->edit); + RedrawWindow (infoPtr->hwndCombo, 0, 0, RDW_ERASE | + RDW_INVALIDATE); + return 0; + } + oldItem = SendMessageW (infoPtr->hwndCombo,CB_GETCURSEL, 0, 0); + if (oldItem != -1) { + /* if something is selected, then deselect it */ + SendMessageW (infoPtr->hwndCombo, CB_SETCURSEL, + (WPARAM)-1, 0); + } + InvalidateRect (infoPtr->hwndCombo, 0, 0); + SetFocus(infoPtr->hwndEdit); + break; + + case VK_UP: + step = -1; + case VK_DOWN: + /* by default, step is 1 */ + oldItem = SendMessageW (infoPtr->hwndSelf, CB_GETCURSEL, 0, 0); + if (oldItem >= 0 && oldItem + step >= 0) + SendMessageW (infoPtr->hwndSelf, CB_SETCURSEL, oldItem + step, 0); + return 0; + default: + return CallWindowProcW (infoPtr->prevEditWndProc, + hwnd, uMsg, wParam, lParam); + } + return 0; + } + + case WM_SETFOCUS: + /* remember the focus to set state of icon */ + lret = CallWindowProcW (infoPtr->prevEditWndProc, + hwnd, uMsg, wParam, lParam); + infoPtr->flags |= WCBE_EDITFOCUSED; + return lret; + + case WM_KILLFOCUS: + /* + * do NOTIFY CBEN_ENDEDIT with CBENF_KILLFOCUS + */ + infoPtr->flags &= ~WCBE_EDITFOCUSED; + if (infoPtr->flags & WCBE_ACTEDIT) { + infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG); + + GetWindowTextW (infoPtr->hwndEdit, edit_text, 260); + cbeend.fChanged = FALSE; + cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo, + CB_GETCURSEL, 0, 0); + cbeend.iWhy = CBENF_KILLFOCUS; + + COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text); + } + /* fall through */ + + default: + return CallWindowProcW (infoPtr->prevEditWndProc, + hwnd, uMsg, wParam, lParam); + } +} + + +static LRESULT WINAPI +COMBOEX_ComboWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + HWND hwndComboex = (HWND)GetPropW(hwnd, COMBOEX_SUBCLASS_PROP); + COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwndComboex); + NMCBEENDEDITW cbeend; + NMMOUSE nmmse; + COLORREF obkc; + HDC hDC; + HWND focusedhwnd; + RECT rect; + POINT pt; + WCHAR edit_text[260]; + + TRACE("hwnd=%p msg=%x wparam=%x lParam=%lx, info_ptr=%p\n", + hwnd, uMsg, wParam, lParam, infoPtr); + + if (!infoPtr) return 0; + + switch (uMsg) + { + + case WM_DRAWITEM: + /* + * The only way this message should come is from the + * child Listbox issuing the message. Flag this so + * that ComboEx knows this is listbox. + */ + ((DRAWITEMSTRUCT *)lParam)->itemState |= ODS_COMBOEXLBOX; + return CallWindowProcW (infoPtr->prevComboWndProc, + hwnd, uMsg, wParam, lParam); + + case WM_ERASEBKGND: + /* + * The following was determined by traces of the native + */ + hDC = (HDC) wParam; + obkc = SetBkColor (hDC, GetSysColor (COLOR_WINDOW)); + GetClientRect (hwnd, &rect); + TRACE("erasing (%ld,%ld)-(%ld,%ld)\n", + rect.left, rect.top, rect.right, rect.bottom); + ExtTextOutW (hDC, 0, 0, ETO_OPAQUE, &rect, 0, 0, 0); + SetBkColor (hDC, obkc); + return CallWindowProcW (infoPtr->prevComboWndProc, + hwnd, uMsg, wParam, lParam); + + case WM_SETCURSOR: + /* + * WM_NOTIFY to comboex parent (rebar) + * with NM_SETCURSOR with extra words of 0,0,0,0,0x02010001 + * CallWindowProc (previous) + */ + nmmse.dwItemSpec = 0; + nmmse.dwItemData = 0; + nmmse.pt.x = 0; + nmmse.pt.y = 0; + nmmse.dwHitInfo = lParam; + COMBOEX_Notify (infoPtr, NM_SETCURSOR, (NMHDR *)&nmmse); + return CallWindowProcW (infoPtr->prevComboWndProc, + hwnd, uMsg, wParam, lParam); + + case WM_LBUTTONDOWN: + GetClientRect (hwnd, &rect); + rect.bottom = rect.top + SendMessageW(infoPtr->hwndSelf, + CB_GETITEMHEIGHT, -1, 0); + rect.left = rect.right - GetSystemMetrics(SM_CXVSCROLL); + pt.x = (short)LOWORD(lParam); + pt.y = (short)HIWORD(lParam); + if (PtInRect(&rect, pt)) + return CallWindowProcW (infoPtr->prevComboWndProc, + hwnd, uMsg, wParam, lParam); + infoPtr->flags |= WCBE_MOUSECAPTURED; + SetCapture(hwnd); + break; + + case WM_LBUTTONUP: + if (!(infoPtr->flags & WCBE_MOUSECAPTURED)) + return CallWindowProcW (infoPtr->prevComboWndProc, + hwnd, uMsg, wParam, lParam); + ReleaseCapture(); + infoPtr->flags &= ~WCBE_MOUSECAPTURED; + if (infoPtr->flags & WCBE_MOUSEDRAGGED) { + infoPtr->flags &= ~WCBE_MOUSEDRAGGED; + } else { + SendMessageW(hwnd, CB_SHOWDROPDOWN, TRUE, 0); + } + break; + + case WM_MOUSEMOVE: + if ( (infoPtr->flags & WCBE_MOUSECAPTURED) && + !(infoPtr->flags & WCBE_MOUSEDRAGGED)) { + GetWindowTextW (infoPtr->hwndEdit, edit_text, 260); + COMBOEX_NotifyDragBegin(infoPtr, edit_text); + infoPtr->flags |= WCBE_MOUSEDRAGGED; + } + return CallWindowProcW (infoPtr->prevComboWndProc, + hwnd, uMsg, wParam, lParam); + + case WM_COMMAND: + switch (HIWORD(wParam)) { + + case EN_UPDATE: + /* traces show that COMBOEX does not issue CBN_EDITUPDATE + * on the EN_UPDATE + */ + return 0; + + case EN_KILLFOCUS: + /* + * Native does: + * + * GetFocus() retns AA + * GetWindowTextW(Edit) + * CB_GETCURSEL(Combo) (got -1) + * WM_NOTIFY(CBEN_ENDEDITA) with CBENF_KILLFOCUS + * CB_GETCURSEL(Combo) (got -1) + * InvalidateRect(Combo, 0, 0) + * WM_KILLFOCUS(Combo, AA) + * return 0; + */ + focusedhwnd = GetFocus(); + if (infoPtr->flags & WCBE_ACTEDIT) { + GetWindowTextW (infoPtr->hwndEdit, edit_text, 260); + cbeend.fChanged = (infoPtr->flags & WCBE_EDITCHG); + cbeend.iNewSelection = SendMessageW (infoPtr->hwndCombo, + CB_GETCURSEL, 0, 0); + cbeend.iWhy = CBENF_KILLFOCUS; + + infoPtr->flags &= ~(WCBE_ACTEDIT | WCBE_EDITCHG); + if (COMBOEX_NotifyEndEdit (infoPtr, &cbeend, edit_text)) return 0; + } + /* possible CB_GETCURSEL */ + InvalidateRect (infoPtr->hwndCombo, 0, 0); + if (focusedhwnd) + SendMessageW (infoPtr->hwndCombo, WM_KILLFOCUS, + (WPARAM)focusedhwnd, 0); + return 0; + + case EN_SETFOCUS: { + /* + * For EN_SETFOCUS this issues the same calls and messages + * as the native seems to do. + * + * for some cases however native does the following: + * (noticed after SetFocus during LBUTTONDOWN on + * on dropdown arrow) + * WM_GETTEXTLENGTH (Edit); + * WM_GETTEXT (Edit, len+1, str); + * EM_SETSEL (Edit, 0, 0); + * WM_GETTEXTLENGTH (Edit); + * WM_GETTEXT (Edit, len+1, str); + * EM_SETSEL (Edit, 0, len); + * WM_NOTIFY (parent, CBEN_BEGINEDIT) + */ + NMHDR hdr; + + SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, 0); + SendMessageW (infoPtr->hwndEdit, EM_SETSEL, 0, -1); + COMBOEX_Notify (infoPtr, CBEN_BEGINEDIT, &hdr); + infoPtr->flags |= WCBE_ACTEDIT; + infoPtr->flags &= ~WCBE_EDITCHG; /* no change yet */ + return 0; + } + + case EN_CHANGE: { + /* + * For EN_CHANGE this issues the same calls and messages + * as the native seems to do. + */ + WCHAR edit_text[260]; + LPCWSTR lastwrk; + cmp_func_t cmptext = get_cmp_func(infoPtr); + + INT selected = SendMessageW (infoPtr->hwndCombo, + CB_GETCURSEL, 0, 0); + + /* lstrlenW( lastworkingURL ) */ + + GetWindowTextW (infoPtr->hwndEdit, edit_text, 260); + if (selected == -1) { + lastwrk = infoPtr->edit->pszText; + } + else { + CBE_ITEMDATA *item = COMBOEX_FindItem (infoPtr, selected); + lastwrk = COMBOEX_GetText(infoPtr, item); + } + + TRACE("handling EN_CHANGE, selected = %d, selected_text=%s\n", + selected, debugstr_w(lastwrk)); + TRACE("handling EN_CHANGE, edittext=%s\n", + debugstr_w(edit_text)); + + /* cmptext is between lastworkingURL and GetWindowText */ + if (cmptext (lastwrk, edit_text)) { + /* strings not equal -- indicate edit has changed */ + infoPtr->flags |= WCBE_EDITCHG; + } + SendMessageW ( infoPtr->hwndNotify, WM_COMMAND, + MAKEWPARAM(GetDlgCtrlID (infoPtr->hwndSelf), + CBN_EDITCHANGE), + (LPARAM)infoPtr->hwndSelf); + return 0; + } + + case LBN_SELCHANGE: + /* + * Therefore from traces there is no additional code here + */ + + /* + * Using native COMCTL32 gets the following: + * 1 == SHDOCVW.DLL issues call/message + * 2 == COMCTL32.DLL issues call/message + * 3 == WINE issues call/message + * + * + * for LBN_SELCHANGE: + * 1 CB_GETCURSEL(ComboEx) + * 1 CB_GETDROPPEDSTATE(ComboEx) + * 1 CallWindowProc( *2* for WM_COMMAND(LBN_SELCHANGE) + * 2 CallWindowProc( *3* for WM_COMMAND(LBN_SELCHANGE) + ** call CBRollUp( xxx, TRUE for LBN_SELCHANGE, TRUE) + * 3 WM_COMMAND(ComboEx, CBN_SELENDOK) + * WM_USER+49(ComboLB, 1,0) <=============!!!!!!!!!!! + * 3 ShowWindow(ComboLB, SW_HIDE) + * 3 RedrawWindow(Combo, RDW_UPDATENOW) + * 3 WM_COMMAND(ComboEX, CBN_CLOSEUP) + ** end of CBRollUp + * 3 WM_COMMAND(ComboEx, CBN_SELCHANGE) (echo to parent) + * ? LB_GETCURSEL <==| + * ? LB_GETTEXTLEN | + * ? LB_GETTEXT | Needs to be added to + * ? WM_CTLCOLOREDIT(ComboEx) | Combo processing + * ? LB_GETITEMDATA | + * ? WM_DRAWITEM(ComboEx) <==| + */ + default: + break; + }/* fall through */ + default: + return CallWindowProcW (infoPtr->prevComboWndProc, + hwnd, uMsg, wParam, lParam); + } + return 0; +} + + +static LRESULT WINAPI +COMBOEX_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd); + + TRACE("hwnd=%p msg=%x wparam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam); + + if (!infoPtr) { + if (uMsg == WM_CREATE) + return COMBOEX_Create (hwnd, (LPCREATESTRUCTA)lParam); + if (uMsg == WM_NCCREATE) + COMBOEX_NCCreate (hwnd); + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + } + + switch (uMsg) + { + case CBEM_DELETEITEM: + return COMBOEX_DeleteItem (infoPtr, wParam); + + case CBEM_GETCOMBOCONTROL: + return (LRESULT)infoPtr->hwndCombo; + + case CBEM_GETEDITCONTROL: + return (LRESULT)infoPtr->hwndEdit; + + case CBEM_GETEXTENDEDSTYLE: + return infoPtr->dwExtStyle; + + case CBEM_GETIMAGELIST: + return (LRESULT)infoPtr->himl; + + case CBEM_GETITEMA: + return (LRESULT)COMBOEX_GetItemA (infoPtr, (COMBOBOXEXITEMA *)lParam); + + case CBEM_GETITEMW: + return (LRESULT)COMBOEX_GetItemW (infoPtr, (COMBOBOXEXITEMW *)lParam); + + case CBEM_GETUNICODEFORMAT: + return infoPtr->unicode; + + case CBEM_HASEDITCHANGED: + return COMBOEX_HasEditChanged (infoPtr); + + case CBEM_INSERTITEMA: + return COMBOEX_InsertItemA (infoPtr, (COMBOBOXEXITEMA *)lParam); + + case CBEM_INSERTITEMW: + return COMBOEX_InsertItemW (infoPtr, (COMBOBOXEXITEMW *)lParam); + + case CBEM_SETEXSTYLE: + case CBEM_SETEXTENDEDSTYLE: + return COMBOEX_SetExtendedStyle (infoPtr, (DWORD)wParam, (DWORD)lParam); + + case CBEM_SETIMAGELIST: + return (LRESULT)COMBOEX_SetImageList (infoPtr, (HIMAGELIST)lParam); + + case CBEM_SETITEMA: + return COMBOEX_SetItemA (infoPtr, (COMBOBOXEXITEMA *)lParam); + + case CBEM_SETITEMW: + return COMBOEX_SetItemW (infoPtr, (COMBOBOXEXITEMW *)lParam); + + case CBEM_SETUNICODEFORMAT: + return COMBOEX_SetUnicodeFormat (infoPtr, wParam); + + /*case CBEM_SETWINDOWTHEME: + FIXME("CBEM_SETWINDOWTHEME: stub\n");*/ + + case WM_SETTEXT: + case WM_GETTEXT: + return SendMessageW(infoPtr->hwndEdit, uMsg, wParam, lParam); + +/* Combo messages we are not sure if we need to process or just forward */ + case CB_GETDROPPEDCONTROLRECT: + case CB_GETITEMHEIGHT: + case CB_GETLBTEXT: + case CB_GETLBTEXTLEN: + case CB_GETEXTENDEDUI: + case CB_LIMITTEXT: + case CB_RESETCONTENT: + case CB_SELECTSTRING: + +/* Combo messages OK to just forward to the regular COMBO */ + case CB_GETCOUNT: + case CB_GETCURSEL: + case CB_GETDROPPEDSTATE: + case CB_SETDROPPEDWIDTH: + case CB_SETEXTENDEDUI: + case CB_SHOWDROPDOWN: + return SendMessageW (infoPtr->hwndCombo, uMsg, wParam, lParam); + +/* Combo messages we need to process specially */ + case CB_FINDSTRINGEXACT: + return COMBOEX_FindStringExact (infoPtr, (INT)wParam, (LPCWSTR)lParam); + + case CB_GETITEMDATA: + return COMBOEX_GetItemData (infoPtr, (INT)wParam); + + case CB_SETCURSEL: + return COMBOEX_SetCursel (infoPtr, (INT)wParam); + + case CB_SETITEMDATA: + return COMBOEX_SetItemData (infoPtr, (INT)wParam, (DWORD)lParam); + + case CB_SETITEMHEIGHT: + return COMBOEX_SetItemHeight (infoPtr, (INT)wParam, (UINT)lParam); + + + +/* Window messages passed to parent */ + case WM_COMMAND: + return COMBOEX_Command (infoPtr, wParam, lParam); + + case WM_NOTIFY: + if (infoPtr->NtfUnicode) + return SendMessageW (infoPtr->hwndNotify, uMsg, wParam, lParam); + else + return SendMessageA (infoPtr->hwndNotify, uMsg, wParam, lParam); + + +/* Window messages we need to process */ + case WM_DELETEITEM: + return COMBOEX_WM_DeleteItem (infoPtr, (DELETEITEMSTRUCT *)lParam); + + case WM_DRAWITEM: + return COMBOEX_DrawItem (infoPtr, (DRAWITEMSTRUCT *)lParam); + + case WM_DESTROY: + return COMBOEX_Destroy (infoPtr); + + case WM_MEASUREITEM: + return COMBOEX_MeasureItem (infoPtr, (MEASUREITEMSTRUCT *)lParam); + + case WM_NOTIFYFORMAT: + return COMBOEX_NotifyFormat (infoPtr, lParam); + + case WM_SIZE: + return COMBOEX_Size (infoPtr, LOWORD(lParam), HIWORD(lParam)); + + case WM_WINDOWPOSCHANGING: + return COMBOEX_WindowPosChanging (infoPtr, (WINDOWPOS *)lParam); + + case WM_SETFOCUS: + SetFocus(infoPtr->hwndCombo); + return 0; + + default: + if ((uMsg >= WM_USER) && (uMsg < WM_APP)) + ERR("unknown msg %04x wp=%08x lp=%08lx\n",uMsg,wParam,lParam); + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + } +} + + +void COMBOEX_Register (void) +{ + WNDCLASSW wndClass; + + ZeroMemory (&wndClass, sizeof(WNDCLASSW)); + wndClass.style = CS_GLOBALCLASS; + wndClass.lpfnWndProc = COMBOEX_WindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(COMBOEX_INFO *); + wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); + wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wndClass.lpszClassName = WC_COMBOBOXEXW; + + RegisterClassW (&wndClass); +} + + +void COMBOEX_Unregister (void) +{ + UnregisterClassW (WC_COMBOBOXEXW, NULL); +} diff --git a/reactos/lib/comctl32/comctl32.h b/reactos/lib/comctl32/comctl32.h index a73911f8a91..1f7e0adecca 100644 --- a/reactos/lib/comctl32/comctl32.h +++ b/reactos/lib/comctl32/comctl32.h @@ -1,252 +1,252 @@ -/****************************************************************************** - * - * Common definitions (resource ids and global variables) - * - * Copyright 1999 Thuy Nguyen - * Copyright 1999 Eric Kohl - * Copyright 2002 Dimitrie O. Paun - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_COMCTL32_H -#define __WINE_COMCTL32_H - -#ifndef RC_INVOKED -#include -#endif - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" - -extern HMODULE COMCTL32_hModule; -extern HBRUSH COMCTL32_hPattern55AABrush; - -/* Property sheet / Wizard */ -#define IDD_PROPSHEET 1006 -#define IDD_WIZARD 1020 - -#define IDC_TABCONTROL 12320 -#define IDC_APPLY_BUTTON 12321 -#define IDC_BACK_BUTTON 12323 -#define IDC_NEXT_BUTTON 12324 -#define IDC_FINISH_BUTTON 12325 -#define IDC_SUNKEN_LINE 12326 -#define IDC_SUNKEN_LINEHEADER 12327 - -#define IDS_CLOSE 4160 - -/* Toolbar customization dialog */ -#define IDD_TBCUSTOMIZE 200 - -#define IDC_AVAILBTN_LBOX 201 -#define IDC_RESET_BTN 202 -#define IDC_TOOLBARBTN_LBOX 203 -#define IDC_REMOVE_BTN 204 -#define IDC_HELP_BTN 205 -#define IDC_MOVEUP_BTN 206 -#define IDC_MOVEDN_BTN 207 - -#define IDS_SEPARATOR 1024 - -/* Toolbar imagelist bitmaps */ -#define IDB_STD_SMALL 120 -#define IDB_STD_LARGE 121 -#define IDB_VIEW_SMALL 124 -#define IDB_VIEW_LARGE 125 -#define IDB_HIST_SMALL 130 -#define IDB_HIST_LARGE 131 - - -/* Month calendar month menu popup */ -#define IDD_MCMONTHMENU 300 - -#define IDM_JAN 301 -#define IDM_FEB 302 -#define IDM_MAR 303 -#define IDM_APR 304 -#define IDM_MAY 305 -#define IDM_JUN 306 -#define IDM_JUL 307 -#define IDM_AUG 308 -#define IDM_SEP 309 -#define IDM_OCT 310 -#define IDM_NOV 311 -#define IDM_DEC 312 - -#define IDM_TODAY 4163 -#define IDM_GOTODAY 4164 - -/* Treeview Checkboxes */ - -#define IDT_CHECK 401 - - -/* Header cursors */ -#define IDC_DIVIDER 106 -#define IDC_DIVIDEROPEN 107 - - -/* DragList resources */ -#define IDI_DRAGARROW 501 -#define IDC_COPY 502 - -#define IDC_MOVEBUTTON 1 - -/* HOTKEY internal strings */ -#define HKY_NONE 2048 - -/* Tooltip icons */ -#define IDI_TT_INFO_SM 22 -#define IDI_TT_WARN_SM 25 -#define IDI_TT_ERROR_SM 28 - -typedef struct -{ - COLORREF clrBtnHighlight; /* COLOR_BTNHIGHLIGHT */ - COLORREF clrBtnShadow; /* COLOR_BTNSHADOW */ - COLORREF clrBtnText; /* COLOR_BTNTEXT */ - COLORREF clrBtnFace; /* COLOR_BTNFACE */ - COLORREF clrHighlight; /* COLOR_HIGHLIGHT */ - COLORREF clrHighlightText; /* COLOR_HIGHLIGHTTEXT */ - COLORREF clr3dHilight; /* COLOR_3DHILIGHT */ - COLORREF clr3dShadow; /* COLOR_3DSHADOW */ - COLORREF clr3dDkShadow; /* COLOR_3DDKSHADOW */ - COLORREF clr3dFace; /* COLOR_3DFACE */ - COLORREF clrWindow; /* COLOR_WINDOW */ - COLORREF clrWindowText; /* COLOR_WINDOWTEXT */ - COLORREF clrGrayText; /* COLOR_GREYTEXT */ - COLORREF clrActiveCaption; /* COLOR_ACTIVECAPTION */ - COLORREF clrInfoBk; /* COLOR_INFOBK */ - COLORREF clrInfoText; /* COLOR_INFOTEXT */ -} COMCTL32_SysColor; - -extern COMCTL32_SysColor comctl32_color; - -/* Internal function */ -HWND COMCTL32_CreateToolTip (HWND); -VOID COMCTL32_RefreshSysColors(void); -void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal); -INT Str_GetPtrWtoA (LPCWSTR lpSrc, LPSTR lpDest, INT nMaxLen); -BOOL Str_SetPtrAtoW (LPWSTR *lppDest, LPCSTR lpSrc); - -#define COMCTL32_VERSION_MINOR 80 -#define WINE_FILEVERSION 5, COMCTL32_VERSION_MINOR, 0, 0 -#define WINE_FILEVERSIONSTR "5.80" - -/* Our internal stack structure of the window procedures to subclass */ -typedef struct _SUBCLASSPROCS { - SUBCLASSPROC subproc; - UINT_PTR id; - DWORD_PTR ref; - struct _SUBCLASSPROCS *next; -} SUBCLASSPROCS, *LPSUBCLASSPROCS; - -typedef struct -{ - SUBCLASSPROCS *SubclassProcs; - SUBCLASSPROCS *stackpos; - WNDPROC origproc; - int running; -} SUBCLASS_INFO, *LPSUBCLASS_INFO; - -/* undocumented functions */ - -LPVOID WINAPI Alloc (DWORD); -LPVOID WINAPI ReAlloc (LPVOID, DWORD); -BOOL WINAPI Free (LPVOID); -DWORD WINAPI GetSize (LPVOID); - -INT WINAPI Str_GetPtrA (LPCSTR, LPSTR, INT); -INT WINAPI Str_GetPtrW (LPCWSTR, LPWSTR, INT); - -INT WINAPI DPA_GetPtrIndex (const HDPA, LPVOID); -BOOL WINAPI DPA_Grow (const HDPA, INT); - -#define DPAM_NOSORT 0x0001 -#define DPAM_INSERT 0x0004 -#define DPAM_DELETE 0x0008 - -typedef PVOID (CALLBACK *PFNDPAMERGE)(DWORD,PVOID,PVOID,LPARAM); -BOOL WINAPI DPA_Merge (const HDPA, const HDPA, DWORD, PFNDPACOMPARE, PFNDPAMERGE, LPARAM); - -#define DPA_GetPtrCount(hdpa) (*(INT*)(hdpa)) - -LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet); -BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2); - -extern void ANIMATE_Register(void); -extern void ANIMATE_Unregister(void); -extern void COMBOEX_Register(void); -extern void COMBOEX_Unregister(void); -extern void DATETIME_Register(void); -extern void DATETIME_Unregister(void); -extern void FLATSB_Register(void); -extern void FLATSB_Unregister(void); -extern void HEADER_Register(void); -extern void HEADER_Unregister(void); -extern void HOTKEY_Register(void); -extern void HOTKEY_Unregister(void); -extern void IPADDRESS_Register(void); -extern void IPADDRESS_Unregister(void); -extern void LISTVIEW_Register(void); -extern void LISTVIEW_Unregister(void); -extern void MONTHCAL_Register(void); -extern void MONTHCAL_Unregister(void); -extern void NATIVEFONT_Register(void); -extern void NATIVEFONT_Unregister(void); -extern void PAGER_Register(void); -extern void PAGER_Unregister(void); -extern void PROGRESS_Register(void); -extern void PROGRESS_Unregister(void); -extern void REBAR_Register(void); -extern void REBAR_Unregister(void); -extern void STATUS_Register(void); -extern void STATUS_Unregister(void); -extern void SYSLINK_Register(void); -extern void SYSLINK_Unregister(void); -extern void TAB_Register(void); -extern void TAB_Unregister(void); -extern void TOOLBAR_Register(void); -extern void TOOLBAR_Unregister(void); -extern void TOOLTIPS_Register(void); -extern void TOOLTIPS_Unregister(void); -extern void TRACKBAR_Register(void); -extern void TRACKBAR_Unregister(void); -extern void TREEVIEW_Register(void); -extern void TREEVIEW_Unregister(void); -extern void UPDOWN_Register(void); -extern void UPDOWN_Unregister(void); - - -int MONTHCAL_MonthLength(int month, int year); - -static inline void MONTHCAL_CopyTime(const SYSTEMTIME *from, SYSTEMTIME *to) -{ - to->wYear = from->wYear; - to->wMonth = from->wMonth; - to->wDayOfWeek = from->wDayOfWeek; - to->wDay = from->wDay; - to->wHour = from->wHour; - to->wMinute = from->wMinute; - to->wSecond = from->wSecond; - to->wMilliseconds = from->wMilliseconds; -} - -#endif /* __WINE_COMCTL32_H */ +/****************************************************************************** + * + * Common definitions (resource ids and global variables) + * + * Copyright 1999 Thuy Nguyen + * Copyright 1999 Eric Kohl + * Copyright 2002 Dimitrie O. Paun + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_COMCTL32_H +#define __WINE_COMCTL32_H + +#ifndef RC_INVOKED +#include +#endif + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" + +extern HMODULE COMCTL32_hModule; +extern HBRUSH COMCTL32_hPattern55AABrush; + +/* Property sheet / Wizard */ +#define IDD_PROPSHEET 1006 +#define IDD_WIZARD 1020 + +#define IDC_TABCONTROL 12320 +#define IDC_APPLY_BUTTON 12321 +#define IDC_BACK_BUTTON 12323 +#define IDC_NEXT_BUTTON 12324 +#define IDC_FINISH_BUTTON 12325 +#define IDC_SUNKEN_LINE 12326 +#define IDC_SUNKEN_LINEHEADER 12327 + +#define IDS_CLOSE 4160 + +/* Toolbar customization dialog */ +#define IDD_TBCUSTOMIZE 200 + +#define IDC_AVAILBTN_LBOX 201 +#define IDC_RESET_BTN 202 +#define IDC_TOOLBARBTN_LBOX 203 +#define IDC_REMOVE_BTN 204 +#define IDC_HELP_BTN 205 +#define IDC_MOVEUP_BTN 206 +#define IDC_MOVEDN_BTN 207 + +#define IDS_SEPARATOR 1024 + +/* Toolbar imagelist bitmaps */ +#define IDB_STD_SMALL 120 +#define IDB_STD_LARGE 121 +#define IDB_VIEW_SMALL 124 +#define IDB_VIEW_LARGE 125 +#define IDB_HIST_SMALL 130 +#define IDB_HIST_LARGE 131 + + +/* Month calendar month menu popup */ +#define IDD_MCMONTHMENU 300 + +#define IDM_JAN 301 +#define IDM_FEB 302 +#define IDM_MAR 303 +#define IDM_APR 304 +#define IDM_MAY 305 +#define IDM_JUN 306 +#define IDM_JUL 307 +#define IDM_AUG 308 +#define IDM_SEP 309 +#define IDM_OCT 310 +#define IDM_NOV 311 +#define IDM_DEC 312 + +#define IDM_TODAY 4163 +#define IDM_GOTODAY 4164 + +/* Treeview Checkboxes */ + +#define IDT_CHECK 401 + + +/* Header cursors */ +#define IDC_DIVIDER 106 +#define IDC_DIVIDEROPEN 107 + + +/* DragList resources */ +#define IDI_DRAGARROW 501 +#define IDC_COPY 502 + +#define IDC_MOVEBUTTON 1 + +/* HOTKEY internal strings */ +#define HKY_NONE 2048 + +/* Tooltip icons */ +#define IDI_TT_INFO_SM 22 +#define IDI_TT_WARN_SM 25 +#define IDI_TT_ERROR_SM 28 + +typedef struct +{ + COLORREF clrBtnHighlight; /* COLOR_BTNHIGHLIGHT */ + COLORREF clrBtnShadow; /* COLOR_BTNSHADOW */ + COLORREF clrBtnText; /* COLOR_BTNTEXT */ + COLORREF clrBtnFace; /* COLOR_BTNFACE */ + COLORREF clrHighlight; /* COLOR_HIGHLIGHT */ + COLORREF clrHighlightText; /* COLOR_HIGHLIGHTTEXT */ + COLORREF clr3dHilight; /* COLOR_3DHILIGHT */ + COLORREF clr3dShadow; /* COLOR_3DSHADOW */ + COLORREF clr3dDkShadow; /* COLOR_3DDKSHADOW */ + COLORREF clr3dFace; /* COLOR_3DFACE */ + COLORREF clrWindow; /* COLOR_WINDOW */ + COLORREF clrWindowText; /* COLOR_WINDOWTEXT */ + COLORREF clrGrayText; /* COLOR_GREYTEXT */ + COLORREF clrActiveCaption; /* COLOR_ACTIVECAPTION */ + COLORREF clrInfoBk; /* COLOR_INFOBK */ + COLORREF clrInfoText; /* COLOR_INFOTEXT */ +} COMCTL32_SysColor; + +extern COMCTL32_SysColor comctl32_color; + +/* Internal function */ +HWND COMCTL32_CreateToolTip (HWND); +VOID COMCTL32_RefreshSysColors(void); +void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal); +INT Str_GetPtrWtoA (LPCWSTR lpSrc, LPSTR lpDest, INT nMaxLen); +BOOL Str_SetPtrAtoW (LPWSTR *lppDest, LPCSTR lpSrc); + +#define COMCTL32_VERSION_MINOR 80 +#define WINE_FILEVERSION 5, COMCTL32_VERSION_MINOR, 0, 0 +#define WINE_FILEVERSIONSTR "5.80" + +/* Our internal stack structure of the window procedures to subclass */ +typedef struct _SUBCLASSPROCS { + SUBCLASSPROC subproc; + UINT_PTR id; + DWORD_PTR ref; + struct _SUBCLASSPROCS *next; +} SUBCLASSPROCS, *LPSUBCLASSPROCS; + +typedef struct +{ + SUBCLASSPROCS *SubclassProcs; + SUBCLASSPROCS *stackpos; + WNDPROC origproc; + int running; +} SUBCLASS_INFO, *LPSUBCLASS_INFO; + +/* undocumented functions */ + +LPVOID WINAPI Alloc (DWORD); +LPVOID WINAPI ReAlloc (LPVOID, DWORD); +BOOL WINAPI Free (LPVOID); +DWORD WINAPI GetSize (LPVOID); + +INT WINAPI Str_GetPtrA (LPCSTR, LPSTR, INT); +INT WINAPI Str_GetPtrW (LPCWSTR, LPWSTR, INT); + +INT WINAPI DPA_GetPtrIndex (const HDPA, LPVOID); +BOOL WINAPI DPA_Grow (const HDPA, INT); + +#define DPAM_NOSORT 0x0001 +#define DPAM_INSERT 0x0004 +#define DPAM_DELETE 0x0008 + +typedef PVOID (CALLBACK *PFNDPAMERGE)(DWORD,PVOID,PVOID,LPARAM); +BOOL WINAPI DPA_Merge (const HDPA, const HDPA, DWORD, PFNDPACOMPARE, PFNDPAMERGE, LPARAM); + +#define DPA_GetPtrCount(hdpa) (*(INT*)(hdpa)) + +LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet); +BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2); + +extern void ANIMATE_Register(void); +extern void ANIMATE_Unregister(void); +extern void COMBOEX_Register(void); +extern void COMBOEX_Unregister(void); +extern void DATETIME_Register(void); +extern void DATETIME_Unregister(void); +extern void FLATSB_Register(void); +extern void FLATSB_Unregister(void); +extern void HEADER_Register(void); +extern void HEADER_Unregister(void); +extern void HOTKEY_Register(void); +extern void HOTKEY_Unregister(void); +extern void IPADDRESS_Register(void); +extern void IPADDRESS_Unregister(void); +extern void LISTVIEW_Register(void); +extern void LISTVIEW_Unregister(void); +extern void MONTHCAL_Register(void); +extern void MONTHCAL_Unregister(void); +extern void NATIVEFONT_Register(void); +extern void NATIVEFONT_Unregister(void); +extern void PAGER_Register(void); +extern void PAGER_Unregister(void); +extern void PROGRESS_Register(void); +extern void PROGRESS_Unregister(void); +extern void REBAR_Register(void); +extern void REBAR_Unregister(void); +extern void STATUS_Register(void); +extern void STATUS_Unregister(void); +extern void SYSLINK_Register(void); +extern void SYSLINK_Unregister(void); +extern void TAB_Register(void); +extern void TAB_Unregister(void); +extern void TOOLBAR_Register(void); +extern void TOOLBAR_Unregister(void); +extern void TOOLTIPS_Register(void); +extern void TOOLTIPS_Unregister(void); +extern void TRACKBAR_Register(void); +extern void TRACKBAR_Unregister(void); +extern void TREEVIEW_Register(void); +extern void TREEVIEW_Unregister(void); +extern void UPDOWN_Register(void); +extern void UPDOWN_Unregister(void); + + +int MONTHCAL_MonthLength(int month, int year); + +static inline void MONTHCAL_CopyTime(const SYSTEMTIME *from, SYSTEMTIME *to) +{ + to->wYear = from->wYear; + to->wMonth = from->wMonth; + to->wDayOfWeek = from->wDayOfWeek; + to->wDay = from->wDay; + to->wHour = from->wHour; + to->wMinute = from->wMinute; + to->wSecond = from->wSecond; + to->wMilliseconds = from->wMilliseconds; +} + +#endif /* __WINE_COMCTL32_H */ diff --git a/reactos/lib/comctl32/comctl32undoc.c b/reactos/lib/comctl32/comctl32undoc.c index 4695537f529..27438d38c68 100644 --- a/reactos/lib/comctl32/comctl32undoc.c +++ b/reactos/lib/comctl32/comctl32undoc.c @@ -1,2573 +1,2573 @@ -/* - * Undocumented functions from COMCTL32.DLL - * - * Copyright 1998 Eric Kohl - * 1998 Juergen Schmied - * 2000 Eric Kohl for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTES - * All of these functions are UNDOCUMENTED!! And I mean UNDOCUMENTED!!!! - * Do NOT rely on names or contents of undocumented structures and types!!! - * These functions are used by EXPLORER.EXE, IEXPLORE.EXE and - * COMCTL32.DLL (internally). - * - */ -#include "config.h" -#include "wine/port.h" - -#include -#include -#include -#include - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "winreg.h" -#include "commctrl.h" -#include "objbase.h" -#include "winerror.h" - -#include "wine/unicode.h" -#include "comctl32.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(commctrl); - -struct _DSA -{ - INT nItemCount; - LPVOID pData; - INT nMaxCount; - INT nItemSize; - INT nGrow; -}; - -struct _DPA -{ - INT nItemCount; - LPVOID *ptrs; - HANDLE hHeap; - INT nGrow; - INT nMaxCount; -}; - -typedef struct _STREAMDATA -{ - DWORD dwSize; - DWORD dwData2; - DWORD dwItems; -} STREAMDATA, *PSTREAMDATA; - -typedef struct _LOADDATA -{ - INT nCount; - PVOID ptr; -} LOADDATA, *LPLOADDATA; - -typedef HRESULT (CALLBACK *DPALOADPROC)(LPLOADDATA,IStream*,LPARAM); - -static const WCHAR strMRUList[] = { 'M','R','U','L','i','s','t',0 }; - -/************************************************************************** - * DPA_LoadStream [COMCTL32.9] - * - * Loads a dynamic pointer array from a stream - * - * PARAMS - * phDpa [O] pointer to a handle to a dynamic pointer array - * loadProc [I] pointer to a callback function - * pStream [I] pointer to a stream - * lParam [I] application specific value - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * NOTES - * No more information available yet! - */ -HRESULT WINAPI DPA_LoadStream (HDPA *phDpa, DPALOADPROC loadProc, - IStream *pStream, LPARAM lParam) -{ - HRESULT errCode; - LARGE_INTEGER position; - ULARGE_INTEGER newPosition; - STREAMDATA streamData; - LOADDATA loadData; - ULONG ulRead; - HDPA hDpa; - PVOID *ptr; - - FIXME ("phDpa=%p loadProc=%p pStream=%p lParam=%lx\n", - phDpa, loadProc, pStream, lParam); - - if (!phDpa || !loadProc || !pStream) - return E_INVALIDARG; - - *phDpa = (HDPA)NULL; - - position.QuadPart = 0; - - /* - * Zero out our streamData - */ - memset(&streamData,0,sizeof(STREAMDATA)); - - errCode = IStream_Seek (pStream, position, STREAM_SEEK_CUR, &newPosition); - if (errCode != S_OK) - return errCode; - - errCode = IStream_Read (pStream, &streamData, sizeof(STREAMDATA), &ulRead); - if (errCode != S_OK) - return errCode; - - FIXME ("dwSize=%lu dwData2=%lu dwItems=%lu\n", - streamData.dwSize, streamData.dwData2, streamData.dwItems); - - if ( ulRead < sizeof(STREAMDATA) || - lParam < sizeof(STREAMDATA) || - streamData.dwSize < sizeof(STREAMDATA) || - streamData.dwData2 < 1) { - errCode = E_FAIL; - } - - if (streamData.dwItems > (UINT_MAX / 2 / sizeof(VOID*))) /* 536870911 */ - return E_OUTOFMEMORY; - - /* create the dpa */ - hDpa = DPA_Create (streamData.dwItems); - if (!hDpa) - return E_OUTOFMEMORY; - - if (!DPA_Grow (hDpa, streamData.dwItems)) - return E_OUTOFMEMORY; - - /* load data from the stream into the dpa */ - ptr = hDpa->ptrs; - for (loadData.nCount = 0; loadData.nCount < streamData.dwItems; loadData.nCount++) { - errCode = (loadProc)(&loadData, pStream, lParam); - if (errCode != S_OK) { - errCode = S_FALSE; - break; - } - - *ptr = loadData.ptr; - ptr++; - } - - /* set the number of items */ - hDpa->nItemCount = loadData.nCount; - - /* store the handle to the dpa */ - *phDpa = hDpa; - FIXME ("new hDpa=%p, errorcode=%lx\n", hDpa, errCode); - - return errCode; -} - - -/************************************************************************** - * DPA_SaveStream [COMCTL32.10] - * - * Saves a dynamic pointer array to a stream - * - * PARAMS - * hDpa [I] handle to a dynamic pointer array - * loadProc [I] pointer to a callback function - * pStream [I] pointer to a stream - * lParam [I] application specific value - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * NOTES - * No more information available yet! - */ -HRESULT WINAPI DPA_SaveStream (const HDPA hDpa, DPALOADPROC loadProc, - IStream *pStream, LPARAM lParam) -{ - - FIXME ("hDpa=%p loadProc=%p pStream=%p lParam=%lx\n", - hDpa, loadProc, pStream, lParam); - - return E_FAIL; -} - - -/************************************************************************** - * DPA_Merge [COMCTL32.11] - * - * Merge two dynamic pointers arrays. - * - * PARAMS - * hdpa1 [I] handle to a dynamic pointer array - * hdpa2 [I] handle to a dynamic pointer array - * dwFlags [I] flags - * pfnCompare [I] pointer to sort function - * pfnMerge [I] pointer to merge function - * lParam [I] application specific value - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * NOTES - * No more information available yet! - */ -BOOL WINAPI DPA_Merge (const HDPA hdpa1, const HDPA hdpa2, DWORD dwFlags, - PFNDPACOMPARE pfnCompare, PFNDPAMERGE pfnMerge, - LPARAM lParam) -{ - INT nCount; - LPVOID *pWork1, *pWork2; - INT nResult, i; - INT nIndex; - - TRACE("%p %p %08lx %p %p %08lx)\n", - hdpa1, hdpa2, dwFlags, pfnCompare, pfnMerge, lParam); - - if (IsBadWritePtr (hdpa1, sizeof(*hdpa1))) - return FALSE; - - if (IsBadWritePtr (hdpa2, sizeof(*hdpa2))) - return FALSE; - - if (IsBadCodePtr ((FARPROC)pfnCompare)) - return FALSE; - - if (IsBadCodePtr ((FARPROC)pfnMerge)) - return FALSE; - - if (!(dwFlags & DPAM_NOSORT)) { - TRACE("sorting dpa's!\n"); - if (hdpa1->nItemCount > 0) - DPA_Sort (hdpa1, pfnCompare, lParam); - TRACE ("dpa 1 sorted!\n"); - if (hdpa2->nItemCount > 0) - DPA_Sort (hdpa2, pfnCompare, lParam); - TRACE ("dpa 2 sorted!\n"); - } - - if (hdpa2->nItemCount < 1) - return TRUE; - - TRACE("hdpa1->nItemCount=%d hdpa2->nItemCount=%d\n", - hdpa1->nItemCount, hdpa2->nItemCount); - - - /* working but untrusted implementation */ - - pWork1 = &(hdpa1->ptrs[hdpa1->nItemCount - 1]); - pWork2 = &(hdpa2->ptrs[hdpa2->nItemCount - 1]); - - nIndex = hdpa1->nItemCount - 1; - nCount = hdpa2->nItemCount - 1; - - do - { - if (nIndex < 0) { - if ((nCount >= 0) && (dwFlags & DPAM_INSERT)) { - /* Now insert the remaining new items into DPA 1 */ - TRACE("%d items to be inserted at start of DPA 1\n", - nCount+1); - for (i=nCount; i>=0; i--) { - PVOID ptr; - - ptr = (pfnMerge)(3, *pWork2, NULL, lParam); - if (!ptr) - return FALSE; - DPA_InsertPtr (hdpa1, 0, ptr); - pWork2--; - } - } - break; - } - nResult = (pfnCompare)(*pWork1, *pWork2, lParam); - TRACE("compare result=%d, dpa1.cnt=%d, dpa2.cnt=%d\n", - nResult, nIndex, nCount); - - if (nResult == 0) - { - PVOID ptr; - - ptr = (pfnMerge)(1, *pWork1, *pWork2, lParam); - if (!ptr) - return FALSE; - - nCount--; - pWork2--; - *pWork1 = ptr; - nIndex--; - pWork1--; - } - else if (nResult > 0) - { - /* item in DPA 1 missing from DPA 2 */ - if (dwFlags & DPAM_DELETE) - { - /* Now delete the extra item in DPA1 */ - PVOID ptr; - - ptr = DPA_DeletePtr (hdpa1, hdpa1->nItemCount - 1); - - (pfnMerge)(2, ptr, NULL, lParam); - } - nIndex--; - pWork1--; - } - else - { - /* new item in DPA 2 */ - if (dwFlags & DPAM_INSERT) - { - /* Now insert the new item in DPA 1 */ - PVOID ptr; - - ptr = (pfnMerge)(3, *pWork2, NULL, lParam); - if (!ptr) - return FALSE; - DPA_InsertPtr (hdpa1, nIndex+1, ptr); - } - nCount--; - pWork2--; - } - - } - while (nCount >= 0); - - return TRUE; -} - - -/************************************************************************** - * Alloc [COMCTL32.71] - * - * Allocates memory block from the dll's private heap - * - * PARAMS - * dwSize [I] size of the allocated memory block - * - * RETURNS - * Success: pointer to allocated memory block - * Failure: NULL - */ -LPVOID WINAPI Alloc (DWORD dwSize) -{ - return LocalAlloc( LMEM_ZEROINIT, dwSize ); -} - - -/************************************************************************** - * ReAlloc [COMCTL32.72] - * - * Changes the size of an allocated memory block or allocates a memory - * block using the dll's private heap. - * - * PARAMS - * lpSrc [I] pointer to memory block which will be resized - * dwSize [I] new size of the memory block. - * - * RETURNS - * Success: pointer to the resized memory block - * Failure: NULL - * - * NOTES - * If lpSrc is a NULL-pointer, then ReAlloc allocates a memory - * block like Alloc. - */ -LPVOID WINAPI ReAlloc (LPVOID lpSrc, DWORD dwSize) -{ - if (lpSrc) - return LocalReAlloc( lpSrc, dwSize, LMEM_ZEROINIT ); - else - return LocalAlloc( LMEM_ZEROINIT, dwSize); -} - - -/************************************************************************** - * Free [COMCTL32.73] - * - * Frees an allocated memory block from the dll's private heap. - * - * PARAMS - * lpMem [I] pointer to memory block which will be freed - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI Free (LPVOID lpMem) -{ - return !LocalFree( lpMem ); -} - - -/************************************************************************** - * GetSize [COMCTL32.74] - * - * Retrieves the size of the specified memory block from the dll's - * private heap. - * - * PARAMS - * lpMem [I] pointer to an allocated memory block - * - * RETURNS - * Success: size of the specified memory block - * Failure: 0 - */ -DWORD WINAPI GetSize (LPVOID lpMem) -{ - return LocalSize( lpMem ); -} - - -/************************************************************************** - * MRU-Functions {COMCTL32} - * - * NOTES - * The MRU-Api is a set of functions to manipulate lists of M.R.U. (Most Recently - * Used) items. It is an undocumented Api that is used (at least) by the shell - * and explorer to implement their recent documents feature. - * - * Since these functions are undocumented, they are unsupported by MS and - * may change at any time. - * - * Internally, the list is implemented as a last in, last out list of items - * persisted into the system registry under a caller chosen key. Each list - * item is given a one character identifier in the Ascii range from 'a' to - * '}'. A list of the identifiers in order from newest to oldest is stored - * under the same key in a value named "MRUList". - * - * Items are re-ordered by changing the order of the values in the MRUList - * value. When a new item is added, it becomes the new value of the oldest - * identifier, and that identifier is moved to the front of the MRUList value. - * - * Wine stores MRU-lists in the same registry format as Windows, so when - * switching between the builtin and native comctl32.dll no problems or - * incompatibilities should occur. - * - * The following undocumented structure is used to create an MRU-list: - *|typedef INT (CALLBACK *MRUStringCmpFn)(LPCTSTR lhs, LPCTSTR rhs); - *|typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length); - *| - *|typedef struct tagCREATEMRULIST - *|{ - *| DWORD cbSize; - *| DWORD nMaxItems; - *| DWORD dwFlags; - *| HKEY hKey; - *| LPCTSTR lpszSubKey; - *| PROC lpfnCompare; - *|} CREATEMRULIST, *LPCREATEMRULIST; - * - * MEMBERS - * cbSize [I] The size of the CREATEMRULIST structure. This must be set - * to sizeof(CREATEMRULIST) by the caller. - * nMaxItems [I] The maximum number of items allowed in the list. Because - * of the limited number of identifiers, this should be set to - * a value from 1 to 30 by the caller. - * dwFlags [I] If bit 0 is set, the list will be used to store binary - * data, otherwise it is assumed to store strings. If bit 1 - * is set, every change made to the list will be reflected in - * the registry immediately, otherwise changes will only be - * written when the list is closed. - * hKey [I] The registry key that the list should be written under. - * This must be supplied by the caller. - * lpszSubKey [I] A caller supplied name of a subkey under hKey to write - * the list to. This may not be blank. - * lpfnCompare [I] A caller supplied comparison function, which may be either - * an MRUStringCmpFn if dwFlags does not have bit 0 set, or a - * MRUBinaryCmpFn otherwise. - * - * FUNCTIONS - * - Create an MRU-list with CreateMRUList() or CreateMRUListLazy(). - * - Add items to an MRU-list with AddMRUString() or AddMRUData(). - * - Remove items from an MRU-list with DelMRUString(). - * - Find data in an MRU-list with FindMRUString() or FindMRUData(). - * - Iterate through an MRU-list with EnumMRUList(). - * - Free an MRU-list with FreeMRUList(). - */ - -typedef struct tagCREATEMRULISTA -{ - DWORD cbSize; - DWORD nMaxItems; - DWORD dwFlags; - HKEY hKey; - LPCSTR lpszSubKey; - PROC lpfnCompare; -} CREATEMRULISTA, *LPCREATEMRULISTA; - -typedef struct tagCREATEMRULISTW -{ - DWORD cbSize; - DWORD nMaxItems; - DWORD dwFlags; - HKEY hKey; - LPCWSTR lpszSubKey; - PROC lpfnCompare; -} CREATEMRULISTW, *LPCREATEMRULISTW; - -/* dwFlags */ -#define MRUF_STRING_LIST 0 /* list will contain strings */ -#define MRUF_BINARY_LIST 1 /* list will contain binary data */ -#define MRUF_DELAYED_SAVE 2 /* only save list order to reg. is FreeMRUList */ - -/* If list is a string list lpfnCompare has the following prototype - * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2) - * for binary lists the prototype is - * int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData) - * where cbData is the no. of bytes to compare. - * Need to check what return value means identical - 0? - */ - -typedef struct tagWINEMRUITEM -{ - DWORD size; /* size of data stored */ - DWORD itemFlag; /* flags */ - BYTE datastart; -} WINEMRUITEM, *LPWINEMRUITEM; - -/* itemFlag */ -#define WMRUIF_CHANGED 0x0001 /* this dataitem changed */ - -typedef struct tagWINEMRULIST -{ - CREATEMRULISTW extview; /* original create information */ - BOOL isUnicode; /* is compare fn Unicode */ - DWORD wineFlags; /* internal flags */ - DWORD cursize; /* current size of realMRU */ - LPWSTR realMRU; /* pointer to string of index names */ - LPWINEMRUITEM *array; /* array of pointers to data */ - /* in 'a' to 'z' order */ -} WINEMRULIST, *LPWINEMRULIST; - -/* wineFlags */ -#define WMRUF_CHANGED 0x0001 /* MRU list has changed */ - -/************************************************************************** - * MRU_SaveChanged (internal) - * - * Local MRU saving code - */ -static void MRU_SaveChanged ( LPWINEMRULIST mp ) -{ - UINT i, err; - HKEY newkey; - WCHAR realname[2]; - LPWINEMRUITEM witem; - static const WCHAR emptyW[] = {'\0'}; - - /* or should we do the following instead of RegOpenKeyEx: - */ - - /* open the sub key */ - if ((err = RegOpenKeyExW( mp->extview.hKey, mp->extview.lpszSubKey, - 0, KEY_WRITE, &newkey))) { - /* not present - what to do ??? */ - ERR("Could not open key, error=%d, attempting to create\n", - err); - if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey, - 0, - (LPWSTR)emptyW, - REG_OPTION_NON_VOLATILE, - KEY_READ | KEY_WRITE, - 0, - &newkey, - 0))) { - ERR("failed to create key /%s/, err=%d\n", - debugstr_w(mp->extview.lpszSubKey), err); - return; - } - } - if (mp->wineFlags & WMRUF_CHANGED) { - mp->wineFlags &= ~WMRUF_CHANGED; - err = RegSetValueExW(newkey, strMRUList, 0, REG_SZ, (LPBYTE)mp->realMRU, - (strlenW(mp->realMRU) + 1)*sizeof(WCHAR)); - if (err) { - ERR("error saving MRUList, err=%d\n", err); - } - TRACE("saving MRUList=/%s/\n", debugstr_w(mp->realMRU)); - } - realname[1] = 0; - for(i=0; icursize; i++) { - witem = mp->array[i]; - if (witem->itemFlag & WMRUIF_CHANGED) { - witem->itemFlag &= ~WMRUIF_CHANGED; - realname[0] = 'a' + i; - err = RegSetValueExW(newkey, realname, 0, - (mp->extview.dwFlags & MRUF_BINARY_LIST) ? - REG_BINARY : REG_SZ, - &witem->datastart, witem->size); - if (err) { - ERR("error saving /%s/, err=%d\n", debugstr_w(realname), err); - } - TRACE("saving value for name /%s/ size=%ld\n", - debugstr_w(realname), witem->size); - } - } - RegCloseKey( newkey ); -} - -/************************************************************************** - * FreeMRUList [COMCTL32.152] - * - * Frees a most-recently-used items list. - * - * PARAMS - * hMRUList [I] Handle to list. - * - * RETURNS - * Nothing. - */ -void WINAPI FreeMRUList (HANDLE hMRUList) -{ - LPWINEMRULIST mp = (LPWINEMRULIST)hMRUList; - UINT i; - - TRACE("(%p)\n", hMRUList); - if (!hMRUList) - return; - - if (mp->wineFlags & WMRUF_CHANGED) { - /* need to open key and then save the info */ - MRU_SaveChanged( mp ); - } - - for(i=0; iextview.nMaxItems; i++) { - if (mp->array[i]) - Free(mp->array[i]); - } - Free(mp->realMRU); - Free(mp->array); - Free((LPWSTR)mp->extview.lpszSubKey); - Free(mp); -} - - -/************************************************************************** - * FindMRUData [COMCTL32.169] - * - * Searches binary list for item that matches lpData of length cbData. - * Returns position in list order 0 -> MRU and if lpRegNum != NULL then value - * corresponding to item's reg. name will be stored in it ('a' -> 0). - * - * PARAMS - * hList [I] list handle - * lpData [I] data to find - * cbData [I] length of data - * lpRegNum [O] position in registry (maybe NULL) - * - * RETURNS - * Position in list 0 -> MRU. -1 if item not found. - */ -INT WINAPI FindMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData, - LPINT lpRegNum) -{ - LPWINEMRULIST mp = (LPWINEMRULIST)hList; - INT ret; - UINT i; - LPSTR dataA = NULL; - - if (!mp->extview.lpfnCompare) { - ERR("MRU list not properly created. No compare procedure.\n"); - return -1; - } - - if(!(mp->extview.dwFlags & MRUF_BINARY_LIST) && !mp->isUnicode) { - DWORD len = WideCharToMultiByte(CP_ACP, 0, lpData, -1, - NULL, 0, NULL, NULL); - dataA = Alloc(len); - WideCharToMultiByte(CP_ACP, 0, lpData, -1, dataA, len, NULL, NULL); - } - - for(i=0; icursize; i++) { - if (mp->extview.dwFlags & MRUF_BINARY_LIST) { - if (!mp->extview.lpfnCompare(lpData, &mp->array[i]->datastart, - cbData)) - break; - } - else { - if(mp->isUnicode) { - if (!mp->extview.lpfnCompare(lpData, &mp->array[i]->datastart)) - break; - } else { - DWORD len = WideCharToMultiByte(CP_ACP, 0, - (LPWSTR)&mp->array[i]->datastart, -1, - NULL, 0, NULL, NULL); - LPSTR itemA = Alloc(len); - INT cmp; - WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1, - itemA, len, NULL, NULL); - - cmp = mp->extview.lpfnCompare(dataA, itemA); - Free(itemA); - if(!cmp) - break; - } - } - } - if(dataA) - Free(dataA); - if (i < mp->cursize) - ret = i; - else - ret = -1; - if (lpRegNum && (ret != -1)) - *lpRegNum = 'a' + i; - - TRACE("(%p, %p, %ld, %p) returning %d\n", - hList, lpData, cbData, lpRegNum, ret); - - return ret; -} - - -/************************************************************************** - * AddMRUData [COMCTL32.167] - * - * Add item to MRU binary list. If item already exists in list then it is - * simply moved up to the top of the list and not added again. If list is - * full then the least recently used item is removed to make room. - * - * PARAMS - * hList [I] Handle to list. - * lpData [I] ptr to data to add. - * cbData [I] no. of bytes of data. - * - * RETURNS - * No. corresponding to registry name where value is stored 'a' -> 0 etc. - * -1 on error. - */ -INT WINAPI AddMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData) -{ - LPWINEMRULIST mp = (LPWINEMRULIST)hList; - LPWINEMRUITEM witem; - INT i, replace; - - if ((replace = FindMRUData (hList, lpData, cbData, NULL)) >= 0) { - /* Item exists, just move it to the front */ - LPWSTR pos = strchrW(mp->realMRU, replace + 'a'); - while (pos > mp->realMRU) - { - pos[0] = pos[-1]; - pos--; - } - } - else { - /* either add a new entry or replace oldest */ - if (mp->cursize < mp->extview.nMaxItems) { - /* Add in a new item */ - replace = mp->cursize; - mp->cursize++; - } - else { - /* get the oldest entry and replace data */ - replace = mp->realMRU[mp->cursize - 1] - 'a'; - Free(mp->array[replace]); - } - - /* Allocate space for new item and move in the data */ - mp->array[replace] = witem = Alloc(cbData + sizeof(WINEMRUITEM)); - witem->itemFlag |= WMRUIF_CHANGED; - witem->size = cbData; - memcpy( &witem->datastart, lpData, cbData); - - /* now rotate MRU list */ - for(i=mp->cursize-1; i>=1; i--) - mp->realMRU[i] = mp->realMRU[i-1]; - } - - /* The new item gets the front spot */ - mp->wineFlags |= WMRUF_CHANGED; - mp->realMRU[0] = replace + 'a'; - - TRACE("(%p, %p, %ld) adding data, /%c/ now most current\n", - hList, lpData, cbData, replace+'a'); - - if (!(mp->extview.dwFlags & MRUF_DELAYED_SAVE)) { - /* save changed stuff right now */ - MRU_SaveChanged( mp ); - } - - return replace; -} - -/************************************************************************** - * AddMRUStringW [COMCTL32.401] - * - * Add an item to an MRU string list. - * - * PARAMS - * hList [I] Handle to list. - * lpszString [I] The string to add. - * - * RETURNS - * Success: The number corresponding to the registry name where the string - * has been stored (0 maps to 'a', 1 to 'b' and so on). - * Failure: -1, if hList is NULL or memory allocation fails. If lpszString - * is invalid, the function returns 0, and GetLastError() returns - * ERROR_INVALID_PARAMETER. The last error value is set only in - * this case. - * - * NOTES - * -If lpszString exists in the list already, it is moved to the top of the - * MRU list (it is not duplicated). - * -If the list is full the least recently used list entry is replaced with - * lpszString. - * -If this function returns 0 you should check the last error value to - * ensure the call really succeeded. - */ -INT WINAPI AddMRUStringW(HANDLE hList, LPCWSTR lpszString) -{ - TRACE("(%p,%s)\n", hList, debugstr_w(lpszString)); - - if (!hList) - return -1; - - if (!lpszString || IsBadStringPtrW(lpszString, -1)) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - - return AddMRUData(hList, lpszString, - (strlenW(lpszString) + 1) * sizeof(WCHAR)); -} - -/************************************************************************** - * AddMRUStringA [COMCTL32.153] - * - * See AddMRUStringW. - */ -INT WINAPI AddMRUStringA(HANDLE hList, LPCSTR lpszString) -{ - DWORD len; - LPWSTR stringW; - INT ret; - - TRACE("(%p,%s)\n", hList, debugstr_a(lpszString)); - - if (!hList) - return -1; - - if (IsBadStringPtrA(lpszString, -1)) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - - len = MultiByteToWideChar(CP_ACP, 0, lpszString, -1, NULL, 0) * sizeof(WCHAR); - stringW = Alloc(len); - if (!stringW) - return -1; - - MultiByteToWideChar(CP_ACP, 0, lpszString, -1, stringW, len); - ret = AddMRUData(hList, stringW, len); - Free(stringW); - return ret; -} - -/************************************************************************** - * DelMRUString [COMCTL32.156] - * - * Removes item from either string or binary list (despite its name) - * - * PARAMS - * hList [I] list handle - * nItemPos [I] item position to remove 0 -> MRU - * - * RETURNS - * TRUE if successful, FALSE if nItemPos is out of range. - */ -BOOL WINAPI DelMRUString(HANDLE hList, INT nItemPos) -{ - FIXME("(%p, %d): stub\n", hList, nItemPos); - return TRUE; -} - -/************************************************************************** - * FindMRUStringW [COMCTL32.402] - * - * See FindMRUStringA. - */ -INT WINAPI FindMRUStringW (HANDLE hList, LPCWSTR lpszString, LPINT lpRegNum) -{ - return FindMRUData(hList, lpszString, - (lstrlenW(lpszString) + 1) * sizeof(WCHAR), lpRegNum); -} - -/************************************************************************** - * FindMRUStringA [COMCTL32.155] - * - * Searches string list for item that matches lpszString. - * Returns position in list order 0 -> MRU and if lpRegNum != NULL then value - * corresponding to item's reg. name will be stored in it ('a' -> 0). - * - * PARAMS - * hList [I] list handle - * lpszString [I] string to find - * lpRegNum [O] position in registry (maybe NULL) - * - * RETURNS - * Position in list 0 -> MRU. -1 if item not found. - */ -INT WINAPI FindMRUStringA (HANDLE hList, LPCSTR lpszString, LPINT lpRegNum) -{ - DWORD len = MultiByteToWideChar(CP_ACP, 0, lpszString, -1, NULL, 0); - LPWSTR stringW = Alloc(len * sizeof(WCHAR)); - INT ret; - - MultiByteToWideChar(CP_ACP, 0, lpszString, -1, stringW, len); - ret = FindMRUData(hList, stringW, len * sizeof(WCHAR), lpRegNum); - Free(stringW); - return ret; -} - -/************************************************************************* - * CreateMRUListLazy_common (internal) - */ -static HANDLE CreateMRUListLazy_common(LPWINEMRULIST mp) -{ - UINT i, err; - HKEY newkey; - DWORD datasize, dwdisp; - WCHAR realname[2]; - LPWINEMRUITEM witem; - DWORD type; - static const WCHAR emptyW[] = {'\0'}; - - /* get space to save indices that will turn into names - * but in order of most to least recently used - */ - mp->realMRU = Alloc((mp->extview.nMaxItems + 2) * sizeof(WCHAR)); - - /* get space to save pointers to actual data in order of - * 'a' to 'z' (0 to n). - */ - mp->array = Alloc(mp->extview.nMaxItems * sizeof(LPVOID)); - - /* open the sub key */ - if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey, - 0, - (LPWSTR)emptyW, - REG_OPTION_NON_VOLATILE, - KEY_READ | KEY_WRITE, - 0, - &newkey, - &dwdisp))) { - /* error - what to do ??? */ - ERR("(%lu %lu %lx %lx \"%s\" %p): Could not open key, error=%d\n", - mp->extview.cbSize, mp->extview.nMaxItems, mp->extview.dwFlags, - (DWORD)mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey), - mp->extview.lpfnCompare, err); - return 0; - } - - /* get values from key 'MRUList' */ - if (newkey) { - datasize = mp->extview.nMaxItems + 1; - if((err=RegQueryValueExW( newkey, strMRUList, 0, &type, - (LPBYTE)mp->realMRU, &datasize))) { - /* not present - set size to 1 (will become 0 later) */ - datasize = 1; - *mp->realMRU = 0; - } - - TRACE("MRU list = %s, datasize = %ld\n", debugstr_w(mp->realMRU), datasize); - - mp->cursize = datasize - 1; - /* datasize now has number of items in the MRUList */ - - /* get actual values for each entry */ - realname[1] = 0; - for(i=0; icursize; i++) { - realname[0] = 'a' + i; - if(RegQueryValueExW( newkey, realname, 0, &type, 0, &datasize)) { - /* not present - what to do ??? */ - ERR("Key %s not found 1\n", debugstr_w(realname)); - } - mp->array[i] = witem = Alloc(datasize + sizeof(WINEMRUITEM)); - witem->size = datasize; - if(RegQueryValueExW( newkey, realname, 0, &type, - &witem->datastart, &datasize)) { - /* not present - what to do ??? */ - ERR("Key %s not found 2\n", debugstr_w(realname)); - } - } - RegCloseKey( newkey ); - } - else - mp->cursize = 0; - - TRACE("(%lu %lu %lx %lx \"%s\" %p): Current Size = %ld\n", - mp->extview.cbSize, mp->extview.nMaxItems, mp->extview.dwFlags, - (DWORD)mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey), - mp->extview.lpfnCompare, mp->cursize); - return (HANDLE)mp; -} - -/************************************************************************** - * CreateMRUListLazyW [COMCTL32.404] - * - * See CreateMRUListLazyA. - */ -HANDLE WINAPI CreateMRUListLazyW (LPCREATEMRULISTW lpcml, DWORD dwParam2, - DWORD dwParam3, DWORD dwParam4) -{ - LPWINEMRULIST mp; - - /* Native does not check for a NULL lpcml */ - - if (lpcml->cbSize != sizeof(CREATEMRULISTW) || !lpcml->hKey || - IsBadStringPtrW(lpcml->lpszSubKey, -1)) - return NULL; - - mp = Alloc(sizeof(WINEMRULIST)); - memcpy(&mp->extview, lpcml, sizeof(CREATEMRULISTW)); - mp->extview.lpszSubKey = Alloc((strlenW(lpcml->lpszSubKey) + 1) * sizeof(WCHAR)); - strcpyW((LPWSTR)mp->extview.lpszSubKey, lpcml->lpszSubKey); - mp->isUnicode = TRUE; - - return CreateMRUListLazy_common(mp); -} - -/************************************************************************** - * CreateMRUListLazyA [COMCTL32.157] - * - * Creates a most-recently-used list. - * - * PARAMS - * lpcml [I] ptr to CREATEMRULIST structure. - * dwParam2 [I] Unknown - * dwParam3 [I] Unknown - * dwParam4 [I] Unknown - * - * RETURNS - * Handle to MRU list. - */ -HANDLE WINAPI CreateMRUListLazyA (LPCREATEMRULISTA lpcml, DWORD dwParam2, - DWORD dwParam3, DWORD dwParam4) -{ - LPWINEMRULIST mp; - DWORD len; - - /* Native does not check for a NULL lpcml */ - - if (lpcml->cbSize != sizeof(CREATEMRULISTA) || !lpcml->hKey || - IsBadStringPtrA(lpcml->lpszSubKey, -1)) - return 0; - - mp = Alloc(sizeof(WINEMRULIST)); - memcpy(&mp->extview, lpcml, sizeof(CREATEMRULISTW)); - len = MultiByteToWideChar(CP_ACP, 0, lpcml->lpszSubKey, -1, NULL, 0); - mp->extview.lpszSubKey = Alloc(len * sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpcml->lpszSubKey, -1, - (LPWSTR)mp->extview.lpszSubKey, len); - mp->isUnicode = FALSE; - return CreateMRUListLazy_common(mp); -} - -/************************************************************************** - * CreateMRUListW [COMCTL32.400] - * - * See CreateMRUListA. - */ -HANDLE WINAPI CreateMRUListW (LPCREATEMRULISTW lpcml) -{ - return CreateMRUListLazyW(lpcml, 0, 0, 0); -} - -/************************************************************************** - * CreateMRUListA [COMCTL32.151] - * - * Creates a most-recently-used list. - * - * PARAMS - * lpcml [I] ptr to CREATEMRULIST structure. - * - * RETURNS - * Handle to MRU list. - */ -HANDLE WINAPI CreateMRUListA (LPCREATEMRULISTA lpcml) -{ - return CreateMRUListLazyA (lpcml, 0, 0, 0); -} - - -/************************************************************************** - * EnumMRUListW [COMCTL32.403] - * - * Enumerate item in a most-recenty-used list - * - * PARAMS - * hList [I] list handle - * nItemPos [I] item position to enumerate - * lpBuffer [O] buffer to receive item - * nBufferSize [I] size of buffer - * - * RETURNS - * For binary lists specifies how many bytes were copied to buffer, for - * string lists specifies full length of string. Enumerating past the end - * of list returns -1. - * If lpBuffer == NULL or nItemPos is -ve return value is no. of items in - * the list. - */ -INT WINAPI EnumMRUListW (HANDLE hList, INT nItemPos, LPVOID lpBuffer, - DWORD nBufferSize) -{ - LPWINEMRULIST mp = (LPWINEMRULIST) hList; - LPWINEMRUITEM witem; - INT desired, datasize; - - if (nItemPos >= mp->cursize) return -1; - if ((nItemPos < 0) || !lpBuffer) return mp->cursize; - desired = mp->realMRU[nItemPos]; - desired -= 'a'; - TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired); - witem = mp->array[desired]; - datasize = min( witem->size, nBufferSize ); - memcpy( lpBuffer, &witem->datastart, datasize); - TRACE("(%p, %d, %p, %ld): returning len=%d\n", - hList, nItemPos, lpBuffer, nBufferSize, datasize); - return datasize; -} - -/************************************************************************** - * EnumMRUListA [COMCTL32.154] - * - * See EnumMRUListW. - */ -INT WINAPI EnumMRUListA (HANDLE hList, INT nItemPos, LPVOID lpBuffer, - DWORD nBufferSize) -{ - LPWINEMRULIST mp = (LPWINEMRULIST) hList; - LPWINEMRUITEM witem; - INT desired, datasize; - DWORD lenA; - - if (nItemPos >= mp->cursize) return -1; - if ((nItemPos < 0) || !lpBuffer) return mp->cursize; - desired = mp->realMRU[nItemPos]; - desired -= 'a'; - TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired); - witem = mp->array[desired]; - if(mp->extview.dwFlags & MRUF_BINARY_LIST) { - datasize = min( witem->size, nBufferSize ); - memcpy( lpBuffer, &witem->datastart, datasize); - } else { - lenA = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1, - NULL, 0, NULL, NULL); - datasize = min( witem->size, nBufferSize ); - WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1, - lpBuffer, datasize, NULL, NULL); - } - TRACE("(%p, %d, %p, %ld): returning len=%d\n", - hList, nItemPos, lpBuffer, nBufferSize, datasize); - return datasize; -} - - -/************************************************************************** - * Str_GetPtrA [COMCTL32.233] - * - * Copies a string into a destination buffer. - * - * PARAMS - * lpSrc [I] Source string - * lpDest [O] Destination buffer - * nMaxLen [I] Size of buffer in characters - * - * RETURNS - * The number of characters copied. - */ -INT WINAPI Str_GetPtrA (LPCSTR lpSrc, LPSTR lpDest, INT nMaxLen) -{ - INT len; - - TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen); - - if (!lpDest && lpSrc) - return strlen (lpSrc); - - if (nMaxLen == 0) - return 0; - - if (lpSrc == NULL) { - lpDest[0] = '\0'; - return 0; - } - - len = strlen (lpSrc); - if (len >= nMaxLen) - len = nMaxLen - 1; - - RtlMoveMemory (lpDest, lpSrc, len); - lpDest[len] = '\0'; - - return len; -} - - -/************************************************************************** - * Str_SetPtrA [COMCTL32.234] - * - * Makes a copy of a string, allocating memory if necessary. - * - * PARAMS - * lppDest [O] Pointer to destination string - * lpSrc [I] Source string - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * NOTES - * Set lpSrc to NULL to free the memory allocated by a previous call - * to this function. - */ -BOOL WINAPI Str_SetPtrA (LPSTR *lppDest, LPCSTR lpSrc) -{ - TRACE("(%p %p)\n", lppDest, lpSrc); - - if (lpSrc) { - LPSTR ptr = ReAlloc (*lppDest, strlen (lpSrc) + 1); - if (!ptr) - return FALSE; - strcpy (ptr, lpSrc); - *lppDest = ptr; - } - else { - if (*lppDest) { - Free (*lppDest); - *lppDest = NULL; - } - } - - return TRUE; -} - - -/************************************************************************** - * Str_GetPtrW [COMCTL32.235] - * - * See Str_GetPtrA. - */ -INT WINAPI Str_GetPtrW (LPCWSTR lpSrc, LPWSTR lpDest, INT nMaxLen) -{ - INT len; - - TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen); - - if (!lpDest && lpSrc) - return strlenW (lpSrc); - - if (nMaxLen == 0) - return 0; - - if (lpSrc == NULL) { - lpDest[0] = L'\0'; - return 0; - } - - len = strlenW (lpSrc); - if (len >= nMaxLen) - len = nMaxLen - 1; - - RtlMoveMemory (lpDest, lpSrc, len*sizeof(WCHAR)); - lpDest[len] = L'\0'; - - return len; -} - - -/************************************************************************** - * Str_SetPtrW [COMCTL32.236] - * - * See Str_SetPtrA. - */ -BOOL WINAPI Str_SetPtrW (LPWSTR *lppDest, LPCWSTR lpSrc) -{ - TRACE("(%p %p)\n", lppDest, lpSrc); - - if (lpSrc) { - INT len = strlenW (lpSrc) + 1; - LPWSTR ptr = ReAlloc (*lppDest, len * sizeof(WCHAR)); - if (!ptr) - return FALSE; - strcpyW (ptr, lpSrc); - *lppDest = ptr; - } - else { - if (*lppDest) { - Free (*lppDest); - *lppDest = NULL; - } - } - - return TRUE; -} - - -/************************************************************************** - * Str_GetPtrWtoA [internal] - * - * Converts a unicode string into a multi byte string - * - * PARAMS - * lpSrc [I] Pointer to the unicode source string - * lpDest [O] Pointer to caller supplied storage for the multi byte string - * nMaxLen [I] Size, in bytes, of the destination buffer - * - * RETURNS - * Length, in bytes, of the converted string. - */ - -INT Str_GetPtrWtoA (LPCWSTR lpSrc, LPSTR lpDest, INT nMaxLen) -{ - INT len; - - TRACE("(%s %p %d)\n", debugstr_w(lpSrc), lpDest, nMaxLen); - - if (!lpDest && lpSrc) - return WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL); - - if (nMaxLen == 0) - return 0; - - if (lpSrc == NULL) { - lpDest[0] = '\0'; - return 0; - } - - len = WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL); - if (len >= nMaxLen) - len = nMaxLen - 1; - - WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, lpDest, len, NULL, NULL); - lpDest[len] = '\0'; - - return len; -} - - -/************************************************************************** - * Str_SetPtrAtoW [internal] - * - * Converts a multi byte string to a unicode string. - * If the pointer to the destination buffer is NULL a buffer is allocated. - * If the destination buffer is too small to keep the converted multi byte - * string the destination buffer is reallocated. If the source pointer is - * NULL, the destination buffer is freed. - * - * PARAMS - * lppDest [I/O] pointer to a pointer to the destination buffer - * lpSrc [I] pointer to a multi byte string - * - * RETURNS - * TRUE: conversion successful - * FALSE: error - */ -BOOL Str_SetPtrAtoW (LPWSTR *lppDest, LPCSTR lpSrc) -{ - TRACE("(%p %s)\n", lppDest, lpSrc); - - if (lpSrc) { - INT len = MultiByteToWideChar(CP_ACP,0,lpSrc,-1,NULL,0); - LPWSTR ptr = ReAlloc (*lppDest, len*sizeof(WCHAR)); - - if (!ptr) - return FALSE; - MultiByteToWideChar(CP_ACP,0,lpSrc,-1,ptr,len); - *lppDest = ptr; - } - else { - if (*lppDest) { - Free (*lppDest); - *lppDest = NULL; - } - } - - return TRUE; -} - - -/************************************************************************** - * DSA_Create [COMCTL32.320] - * - * Creates a dynamic storage array - * - * PARAMS - * nSize [I] size of the array elements - * nGrow [I] number of elements by which the array grows when it is filled - * - * RETURNS - * Success: pointer to an array control structure. Use this like a handle. - * Failure: NULL - * - * NOTES - * The DSA_ functions can be used to create and manipulate arrays of - * fixed-size memory blocks. These arrays can store any kind of data - * (e.g. strings and icons). - */ -HDSA WINAPI DSA_Create (INT nSize, INT nGrow) -{ - HDSA hdsa; - - TRACE("(size=%d grow=%d)\n", nSize, nGrow); - - hdsa = Alloc (sizeof(*hdsa)); - if (hdsa) - { - hdsa->nItemCount = 0; - hdsa->pData = NULL; - hdsa->nMaxCount = 0; - hdsa->nItemSize = nSize; - hdsa->nGrow = max(1, nGrow); - } - - return hdsa; -} - - -/************************************************************************** - * DSA_Destroy [COMCTL32.321] - * - * Destroys a dynamic storage array - * - * PARAMS - * hdsa [I] pointer to the array control structure - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DSA_Destroy (const HDSA hdsa) -{ - TRACE("(%p)\n", hdsa); - - if (!hdsa) - return FALSE; - - if (hdsa->pData && (!Free (hdsa->pData))) - return FALSE; - - return Free (hdsa); -} - - -/************************************************************************** - * DSA_GetItem [COMCTL32.322] - * - * Copies the specified item into a caller-supplied buffer. - * - * PARAMS - * hdsa [I] pointer to the array control structure - * nIndex [I] number of the Item to get - * pDest [O] destination buffer. Has to be >= dwElementSize. - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DSA_GetItem (const HDSA hdsa, INT nIndex, LPVOID pDest) -{ - LPVOID pSrc; - - TRACE("(%p %d %p)\n", hdsa, nIndex, pDest); - - if (!hdsa) - return FALSE; - if ((nIndex < 0) || (nIndex >= hdsa->nItemCount)) - return FALSE; - - pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); - memmove (pDest, pSrc, hdsa->nItemSize); - - return TRUE; -} - - -/************************************************************************** - * DSA_GetItemPtr [COMCTL32.323] - * - * Retrieves a pointer to the specified item. - * - * PARAMS - * hdsa [I] pointer to the array control structure - * nIndex [I] index of the desired item - * - * RETURNS - * Success: pointer to an item - * Failure: NULL - */ -LPVOID WINAPI DSA_GetItemPtr (const HDSA hdsa, INT nIndex) -{ - LPVOID pSrc; - - TRACE("(%p %d)\n", hdsa, nIndex); - - if (!hdsa) - return NULL; - if ((nIndex < 0) || (nIndex >= hdsa->nItemCount)) - return NULL; - - pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); - - TRACE("-- ret=%p\n", pSrc); - - return pSrc; -} - - -/************************************************************************** - * DSA_SetItem [COMCTL32.325] - * - * Sets the contents of an item in the array. - * - * PARAMS - * hdsa [I] pointer to the array control structure - * nIndex [I] index for the item - * pSrc [I] pointer to the new item data - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DSA_SetItem (const HDSA hdsa, INT nIndex, LPVOID pSrc) -{ - INT nSize, nNewItems; - LPVOID pDest, lpTemp; - - TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc); - - if ((!hdsa) || nIndex < 0) - return FALSE; - - if (hdsa->nItemCount <= nIndex) { - /* within the old array */ - if (hdsa->nMaxCount > nIndex) { - /* within the allocated space, set a new boundary */ - hdsa->nItemCount = nIndex + 1; - } - else { - /* resize the block of memory */ - nNewItems = - hdsa->nGrow * ((INT)(((nIndex + 1) - 1) / hdsa->nGrow) + 1); - nSize = hdsa->nItemSize * nNewItems; - - lpTemp = ReAlloc (hdsa->pData, nSize); - if (!lpTemp) - return FALSE; - - hdsa->nMaxCount = nNewItems; - hdsa->nItemCount = nIndex + 1; - hdsa->pData = lpTemp; - } - } - - /* put the new entry in */ - pDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); - TRACE("-- move dest=%p src=%p size=%d\n", - pDest, pSrc, hdsa->nItemSize); - memmove (pDest, pSrc, hdsa->nItemSize); - - return TRUE; -} - - -/************************************************************************** - * DSA_InsertItem [COMCTL32.324] - * - * Inserts an item into the array at the specified index. - * - * PARAMS - * hdsa [I] pointer to the array control structure - * nIndex [I] index for the new item - * pSrc [I] pointer to the element - * - * RETURNS - * Success: position of the new item - * Failure: -1 - */ -INT WINAPI DSA_InsertItem (const HDSA hdsa, INT nIndex, LPVOID pSrc) -{ - INT nNewItems, nSize; - LPVOID lpTemp, lpDest; - - TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc); - - if ((!hdsa) || nIndex < 0) - return -1; - - /* when nIndex >= nItemCount then append */ - if (nIndex >= hdsa->nItemCount) - nIndex = hdsa->nItemCount; - - /* do we need to resize ? */ - if (hdsa->nItemCount >= hdsa->nMaxCount) { - nNewItems = hdsa->nMaxCount + hdsa->nGrow; - nSize = hdsa->nItemSize * nNewItems; - - lpTemp = ReAlloc (hdsa->pData, nSize); - if (!lpTemp) - return -1; - - hdsa->nMaxCount = nNewItems; - hdsa->pData = lpTemp; - } - - /* do we need to move elements ? */ - if (nIndex < hdsa->nItemCount) { - lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); - lpDest = (char *) lpTemp + hdsa->nItemSize; - nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize; - TRACE("-- move dest=%p src=%p size=%d\n", - lpDest, lpTemp, nSize); - memmove (lpDest, lpTemp, nSize); - } - - /* ok, we can put the new Item in */ - hdsa->nItemCount++; - lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); - TRACE("-- move dest=%p src=%p size=%d\n", - lpDest, pSrc, hdsa->nItemSize); - memmove (lpDest, pSrc, hdsa->nItemSize); - - return nIndex; -} - - -/************************************************************************** - * DSA_DeleteItem [COMCTL32.326] - * - * Deletes the specified item from the array. - * - * PARAMS - * hdsa [I] pointer to the array control structure - * nIndex [I] index for the element to delete - * - * RETURNS - * Success: number of the deleted element - * Failure: -1 - */ -INT WINAPI DSA_DeleteItem (const HDSA hdsa, INT nIndex) -{ - LPVOID lpDest,lpSrc; - INT nSize; - - TRACE("(%p %d)\n", hdsa, nIndex); - - if (!hdsa) - return -1; - if (nIndex < 0 || nIndex >= hdsa->nItemCount) - return -1; - - /* do we need to move ? */ - if (nIndex < hdsa->nItemCount - 1) { - lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); - lpSrc = (char *) lpDest + hdsa->nItemSize; - nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1); - TRACE("-- move dest=%p src=%p size=%d\n", - lpDest, lpSrc, nSize); - memmove (lpDest, lpSrc, nSize); - } - - hdsa->nItemCount--; - - /* free memory ? */ - if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) { - nSize = hdsa->nItemSize * hdsa->nItemCount; - - lpDest = ReAlloc (hdsa->pData, nSize); - if (!lpDest) - return -1; - - hdsa->nMaxCount = hdsa->nItemCount; - hdsa->pData = lpDest; - } - - return nIndex; -} - - -/************************************************************************** - * DSA_DeleteAllItems [COMCTL32.327] - * - * Removes all items and reinitializes the array. - * - * PARAMS - * hdsa [I] pointer to the array control structure - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DSA_DeleteAllItems (const HDSA hdsa) -{ - TRACE("(%p)\n", hdsa); - - if (!hdsa) - return FALSE; - if (hdsa->pData && (!Free (hdsa->pData))) - return FALSE; - - hdsa->nItemCount = 0; - hdsa->pData = NULL; - hdsa->nMaxCount = 0; - - return TRUE; -} - - -/************************************************************************** - * DPA_Destroy [COMCTL32.329] - * - * Destroys a dynamic pointer array - * - * PARAMS - * hdpa [I] handle (pointer) to the pointer array - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DPA_Destroy (const HDPA hdpa) -{ - TRACE("(%p)\n", hdpa); - - if (!hdpa) - return FALSE; - - if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs))) - return FALSE; - - return HeapFree (hdpa->hHeap, 0, hdpa); -} - - -/************************************************************************** - * DPA_Grow [COMCTL32.330] - * - * Sets the growth amount. - * - * PARAMS - * hdpa [I] handle (pointer) to the existing (source) pointer array - * nGrow [I] number of items by which the array grows when it's too small - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DPA_Grow (const HDPA hdpa, INT nGrow) -{ - TRACE("(%p %d)\n", hdpa, nGrow); - - if (!hdpa) - return FALSE; - - hdpa->nGrow = max(8, nGrow); - - return TRUE; -} - - -/************************************************************************** - * DPA_Clone [COMCTL32.331] - * - * Copies a pointer array to an other one or creates a copy - * - * PARAMS - * hdpa [I] handle (pointer) to the existing (source) pointer array - * hdpaNew [O] handle (pointer) to the destination pointer array - * - * RETURNS - * Success: pointer to the destination pointer array. - * Failure: NULL - * - * NOTES - * - If the 'hdpaNew' is a NULL-Pointer, a copy of the source pointer - * array will be created and it's handle (pointer) is returned. - * - If 'hdpa' is a NULL-Pointer, the original implementation crashes, - * this implementation just returns NULL. - */ -HDPA WINAPI DPA_Clone (const HDPA hdpa, const HDPA hdpaNew) -{ - INT nNewItems, nSize; - HDPA hdpaTemp; - - if (!hdpa) - return NULL; - - TRACE("(%p %p)\n", hdpa, hdpaNew); - - if (!hdpaNew) { - /* create a new DPA */ - hdpaTemp = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, - sizeof(*hdpaTemp)); - hdpaTemp->hHeap = hdpa->hHeap; - hdpaTemp->nGrow = hdpa->nGrow; - } - else - hdpaTemp = hdpaNew; - - if (hdpaTemp->ptrs) { - /* remove old pointer array */ - HeapFree (hdpaTemp->hHeap, 0, hdpaTemp->ptrs); - hdpaTemp->ptrs = NULL; - hdpaTemp->nItemCount = 0; - hdpaTemp->nMaxCount = 0; - } - - /* create a new pointer array */ - nNewItems = hdpaTemp->nGrow * - ((INT)((hdpa->nItemCount - 1) / hdpaTemp->nGrow) + 1); - nSize = nNewItems * sizeof(LPVOID); - hdpaTemp->ptrs = HeapAlloc (hdpaTemp->hHeap, HEAP_ZERO_MEMORY, nSize); - hdpaTemp->nMaxCount = nNewItems; - - /* clone the pointer array */ - hdpaTemp->nItemCount = hdpa->nItemCount; - memmove (hdpaTemp->ptrs, hdpa->ptrs, - hdpaTemp->nItemCount * sizeof(LPVOID)); - - return hdpaTemp; -} - - -/************************************************************************** - * DPA_GetPtr [COMCTL32.332] - * - * Retrieves a pointer from a dynamic pointer array - * - * PARAMS - * hdpa [I] handle (pointer) to the pointer array - * nIndex [I] array index of the desired pointer - * - * RETURNS - * Success: pointer - * Failure: NULL - */ -LPVOID WINAPI DPA_GetPtr (const HDPA hdpa, INT nIndex) -{ - TRACE("(%p %d)\n", hdpa, nIndex); - - if (!hdpa) - return NULL; - if (!hdpa->ptrs) { - WARN("no pointer array.\n"); - return NULL; - } - if ((nIndex < 0) || (nIndex >= hdpa->nItemCount)) { - WARN("not enough pointers in array (%d vs %d).\n",nIndex,hdpa->nItemCount); - return NULL; - } - - TRACE("-- %p\n", hdpa->ptrs[nIndex]); - - return hdpa->ptrs[nIndex]; -} - - -/************************************************************************** - * DPA_GetPtrIndex [COMCTL32.333] - * - * Retrieves the index of the specified pointer - * - * PARAMS - * hdpa [I] handle (pointer) to the pointer array - * p [I] pointer - * - * RETURNS - * Success: index of the specified pointer - * Failure: -1 - */ -INT WINAPI DPA_GetPtrIndex (const HDPA hdpa, LPVOID p) -{ - INT i; - - if (!hdpa || !hdpa->ptrs) - return -1; - - for (i = 0; i < hdpa->nItemCount; i++) { - if (hdpa->ptrs[i] == p) - return i; - } - - return -1; -} - - -/************************************************************************** - * DPA_InsertPtr [COMCTL32.334] - * - * Inserts a pointer into a dynamic pointer array - * - * PARAMS - * hdpa [I] handle (pointer) to the array - * i [I] array index - * p [I] pointer to insert - * - * RETURNS - * Success: index of the inserted pointer - * Failure: -1 - */ -INT WINAPI DPA_InsertPtr (const HDPA hdpa, INT i, LPVOID p) -{ - TRACE("(%p %d %p)\n", hdpa, i, p); - - if (!hdpa || i < 0) return -1; - - if (i >= 0x7fff) - i = hdpa->nItemCount; - - if (i >= hdpa->nItemCount) - return DPA_SetPtr(hdpa, i, p) ? i : -1; - - /* create empty spot at the end */ - if (!DPA_SetPtr(hdpa, hdpa->nItemCount, 0)) return -1; - memmove (hdpa->ptrs + i + 1, hdpa->ptrs + i, (hdpa->nItemCount - i - 1) * sizeof(LPVOID)); - hdpa->ptrs[i] = p; - return i; -} - -/************************************************************************** - * DPA_SetPtr [COMCTL32.335] - * - * Sets a pointer in the pointer array - * - * PARAMS - * hdpa [I] handle (pointer) to the pointer array - * i [I] index of the pointer that will be set - * p [I] pointer to be set - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DPA_SetPtr (const HDPA hdpa, INT i, LPVOID p) -{ - LPVOID *lpTemp; - - TRACE("(%p %d %p)\n", hdpa, i, p); - - if (!hdpa || i < 0 || i > 0x7fff) - return FALSE; - - if (hdpa->nItemCount <= i) { - /* within the old array */ - if (hdpa->nMaxCount <= i) { - /* resize the block of memory */ - INT nNewItems = - hdpa->nGrow * ((INT)(((i+1) - 1) / hdpa->nGrow) + 1); - INT nSize = nNewItems * sizeof(LPVOID); - - if (hdpa->ptrs) - lpTemp = HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, hdpa->ptrs, nSize); - else - lpTemp = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, nSize); - - if (!lpTemp) - return FALSE; - - hdpa->nMaxCount = nNewItems; - hdpa->ptrs = lpTemp; - } - hdpa->nItemCount = i+1; - } - - /* put the new entry in */ - hdpa->ptrs[i] = p; - - return TRUE; -} - - -/************************************************************************** - * DPA_DeletePtr [COMCTL32.336] - * - * Removes a pointer from the pointer array. - * - * PARAMS - * hdpa [I] handle (pointer) to the pointer array - * i [I] index of the pointer that will be deleted - * - * RETURNS - * Success: deleted pointer - * Failure: NULL - */ -LPVOID WINAPI DPA_DeletePtr (const HDPA hdpa, INT i) -{ - LPVOID *lpDest, *lpSrc, lpTemp = NULL; - INT nSize; - - TRACE("(%p %d)\n", hdpa, i); - - if ((!hdpa) || i < 0 || i >= hdpa->nItemCount) - return NULL; - - lpTemp = hdpa->ptrs[i]; - - /* do we need to move ?*/ - if (i < hdpa->nItemCount - 1) { - lpDest = hdpa->ptrs + i; - lpSrc = lpDest + 1; - nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID); - TRACE("-- move dest=%p src=%p size=%x\n", - lpDest, lpSrc, nSize); - memmove (lpDest, lpSrc, nSize); - } - - hdpa->nItemCount --; - - /* free memory ?*/ - if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) { - INT nNewItems = max(hdpa->nGrow * 2, hdpa->nItemCount); - nSize = nNewItems * sizeof(LPVOID); - lpDest = HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, - hdpa->ptrs, nSize); - if (!lpDest) - return NULL; - - hdpa->nMaxCount = nNewItems; - hdpa->ptrs = (LPVOID*)lpDest; - } - - return lpTemp; -} - - -/************************************************************************** - * DPA_DeleteAllPtrs [COMCTL32.337] - * - * Removes all pointers and reinitializes the array. - * - * PARAMS - * hdpa [I] handle (pointer) to the pointer array - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DPA_DeleteAllPtrs (const HDPA hdpa) -{ - TRACE("(%p)\n", hdpa); - - if (!hdpa) - return FALSE; - - if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs))) - return FALSE; - - hdpa->nItemCount = 0; - hdpa->nMaxCount = hdpa->nGrow * 2; - hdpa->ptrs = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, - hdpa->nMaxCount * sizeof(LPVOID)); - - return TRUE; -} - - -/************************************************************************** - * DPA_QuickSort [Internal] - * - * Ordinary quicksort (used by DPA_Sort). - * - * PARAMS - * lpPtrs [I] pointer to the pointer array - * l [I] index of the "left border" of the partition - * r [I] index of the "right border" of the partition - * pfnCompare [I] pointer to the compare function - * lParam [I] user defined value (3rd parameter in compare function) - * - * RETURNS - * NONE - */ -static VOID DPA_QuickSort (LPVOID *lpPtrs, INT l, INT r, - PFNDPACOMPARE pfnCompare, LPARAM lParam) -{ - INT m; - LPVOID t; - - TRACE("l=%i r=%i\n", l, r); - - if (l==r) /* one element is always sorted */ - return; - if (r0) - { - t = lpPtrs[m+1]; - memmove(&lpPtrs[l+1],&lpPtrs[l],(m-l+1)*sizeof(lpPtrs[l])); - lpPtrs[l] = t; - - m++; - } - l++; - } -} - - -/************************************************************************** - * DPA_Sort [COMCTL32.338] - * - * Sorts a pointer array using a user defined compare function - * - * PARAMS - * hdpa [I] handle (pointer) to the pointer array - * pfnCompare [I] pointer to the compare function - * lParam [I] user defined value (3rd parameter of compare function) - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DPA_Sort (const HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam) -{ - if (!hdpa || !pfnCompare) - return FALSE; - - TRACE("(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam); - - if ((hdpa->nItemCount > 1) && (hdpa->ptrs)) - DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1, - pfnCompare, lParam); - - return TRUE; -} - - -/************************************************************************** - * DPA_Search [COMCTL32.339] - * - * Searches a pointer array for a specified pointer - * - * PARAMS - * hdpa [I] handle (pointer) to the pointer array - * pFind [I] pointer to search for - * nStart [I] start index - * pfnCompare [I] pointer to the compare function - * lParam [I] user defined value (3rd parameter of compare function) - * uOptions [I] search options - * - * RETURNS - * Success: index of the pointer in the array. - * Failure: -1 - * - * NOTES - * Binary search taken from R.Sedgewick "Algorithms in C"! - * Function is NOT tested! - * If something goes wrong, blame HIM not ME! (Eric Kohl) - */ -INT WINAPI DPA_Search (const HDPA hdpa, LPVOID pFind, INT nStart, - PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions) -{ - if (!hdpa || !pfnCompare || !pFind) - return -1; - - TRACE("(%p %p %d %p 0x%08lx 0x%08x)\n", - hdpa, pFind, nStart, pfnCompare, lParam, uOptions); - - if (uOptions & DPAS_SORTED) { - /* array is sorted --> use binary search */ - INT l, r, x, n; - LPVOID *lpPtr; - - TRACE("binary search\n"); - - l = (nStart == -1) ? 0 : nStart; - r = hdpa->nItemCount - 1; - lpPtr = hdpa->ptrs; - while (r >= l) { - x = (l + r) / 2; - n = (pfnCompare)(pFind, lpPtr[x], lParam); - if (n < 0) - r = x - 1; - else - l = x + 1; - if (n == 0) { - TRACE("-- ret=%d\n", n); - return n; - } - } - - if (uOptions & DPAS_INSERTBEFORE) { - if (r == -1) r = 0; - TRACE("-- ret=%d\n", r); - return r; - } - - if (uOptions & DPAS_INSERTAFTER) { - TRACE("-- ret=%d\n", l); - return l; - } - } - else { - /* array is not sorted --> use linear search */ - LPVOID *lpPtr; - INT nIndex; - - TRACE("linear search\n"); - - nIndex = (nStart == -1)? 0 : nStart; - lpPtr = hdpa->ptrs; - for (; nIndex < hdpa->nItemCount; nIndex++) { - if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0) { - TRACE("-- ret=%d\n", nIndex); - return nIndex; - } - } - } - - TRACE("-- not found: ret=-1\n"); - return -1; -} - - -/************************************************************************** - * DPA_CreateEx [COMCTL32.340] - * - * Creates a dynamic pointer array using the specified size and heap. - * - * PARAMS - * nGrow [I] number of items by which the array grows when it is filled - * hHeap [I] handle to the heap where the array is stored - * - * RETURNS - * Success: handle (pointer) to the pointer array. - * Failure: NULL - * - * NOTES - * The DPA_ functions can be used to create and manipulate arrays of - * pointers. - */ -HDPA WINAPI DPA_CreateEx (INT nGrow, HANDLE hHeap) -{ - HDPA hdpa; - - TRACE("(%d %p)\n", nGrow, hHeap); - - if (hHeap) - hdpa = HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(*hdpa)); - else - hdpa = Alloc (sizeof(*hdpa)); - - if (hdpa) { - hdpa->nGrow = max(8, nGrow); - hdpa->hHeap = hHeap ? hHeap : GetProcessHeap(); - hdpa->nMaxCount = hdpa->nGrow * 2; - hdpa->ptrs = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, - hdpa->nMaxCount * sizeof(LPVOID)); - } - - TRACE("-- %p\n", hdpa); - - return hdpa; -} - - -/************************************************************************** - * DPA_Create [COMCTL32.328] - * - * Creates a dynamic pointer array. - * - * PARAMS - * nGrow [I] number of items by which the array grows when it is filled - * - * RETURNS - * Success: handle (pointer) to the pointer array. - * Failure: NULL - * - * NOTES - * The DPA_ functions can be used to create and manipulate arrays of - * pointers. - */ -HDPA WINAPI DPA_Create (INT nGrow) -{ - return DPA_CreateEx( nGrow, 0 ); -} - - -/************************************************************************** - * Notification functions - */ - -typedef struct tagNOTIFYDATA -{ - HWND hwndFrom; - HWND hwndTo; - DWORD dwParam3; - DWORD dwParam4; - DWORD dwParam5; - DWORD dwParam6; -} NOTIFYDATA, *LPNOTIFYDATA; - - -/************************************************************************** - * DoNotify [Internal] - */ - -static LRESULT DoNotify (LPNOTIFYDATA lpNotify, UINT uCode, LPNMHDR lpHdr) -{ - NMHDR nmhdr; - LPNMHDR lpNmh = NULL; - UINT idFrom = 0; - - TRACE("(%p %p %d %p 0x%08lx)\n", - lpNotify->hwndFrom, lpNotify->hwndTo, uCode, lpHdr, - lpNotify->dwParam5); - - if (!lpNotify->hwndTo) - return 0; - - if (lpNotify->hwndFrom == (HWND)-1) { - lpNmh = lpHdr; - idFrom = lpHdr->idFrom; - } - else { - if (lpNotify->hwndFrom) - idFrom = GetDlgCtrlID (lpNotify->hwndFrom); - - lpNmh = (lpHdr) ? lpHdr : &nmhdr; - - lpNmh->hwndFrom = lpNotify->hwndFrom; - lpNmh->idFrom = idFrom; - lpNmh->code = uCode; - } - - return SendMessageW (lpNotify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh); -} - - -/************************************************************************** - * SendNotify [COMCTL32.341] - * - * Sends a WM_NOTIFY message to the specified window. - * - * PARAMS - * hwndTo [I] Window to receive the message - * hwndFrom [I] Window that the message is from (see notes) - * uCode [I] Notification code - * lpHdr [I] The NMHDR and any additional information to send or NULL - * - * RETURNS - * Success: return value from notification - * Failure: 0 - * - * NOTES - * If hwndFrom is -1 then the identifier of the control sending the - * message is taken from the NMHDR structure. - * If hwndFrom is not -1 then lpHdr can be NULL. - */ -LRESULT WINAPI SendNotify (HWND hwndTo, HWND hwndFrom, UINT uCode, LPNMHDR lpHdr) -{ - NOTIFYDATA notify; - - TRACE("(%p %p %d %p)\n", - hwndTo, hwndFrom, uCode, lpHdr); - - notify.hwndFrom = hwndFrom; - notify.hwndTo = hwndTo; - notify.dwParam5 = 0; - notify.dwParam6 = 0; - - return DoNotify (¬ify, uCode, lpHdr); -} - - -/************************************************************************** - * SendNotifyEx [COMCTL32.342] - * - * Sends a WM_NOTIFY message to the specified window. - * - * PARAMS - * hwndFrom [I] Window to receive the message - * hwndTo [I] Window that the message is from - * uCode [I] Notification code - * lpHdr [I] The NMHDR and any additional information to send or NULL - * dwParam5 [I] Unknown - * - * RETURNS - * Success: return value from notification - * Failure: 0 - * - * NOTES - * If hwndFrom is -1 then the identifier of the control sending the - * message is taken from the NMHDR structure. - * If hwndFrom is not -1 then lpHdr can be NULL. - */ -LRESULT WINAPI SendNotifyEx (HWND hwndTo, HWND hwndFrom, UINT uCode, - LPNMHDR lpHdr, DWORD dwParam5) -{ - NOTIFYDATA notify; - HWND hwndNotify; - - TRACE("(%p %p %d %p 0x%08lx)\n", - hwndFrom, hwndTo, uCode, lpHdr, dwParam5); - - hwndNotify = hwndTo; - if (!hwndTo) { - if (IsWindow (hwndFrom)) { - hwndNotify = GetParent (hwndFrom); - if (!hwndNotify) - return 0; - } - } - - notify.hwndFrom = hwndFrom; - notify.hwndTo = hwndNotify; - notify.dwParam5 = dwParam5; - notify.dwParam6 = 0; - - return DoNotify (¬ify, uCode, lpHdr); -} - - - - -/************************************************************************** - * DPA_EnumCallback [COMCTL32.385] - * - * Enumerates all items in a dynamic pointer array. - * - * PARAMS - * hdpa [I] handle to the dynamic pointer array - * enumProc [I] - * lParam [I] - * - * RETURNS - * none - */ -VOID WINAPI DPA_EnumCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc, - LPVOID lParam) -{ - INT i; - - TRACE("(%p %p %p)\n", hdpa, enumProc, lParam); - - if (!hdpa) - return; - if (hdpa->nItemCount <= 0) - return; - - for (i = 0; i < hdpa->nItemCount; i++) { - if ((enumProc)(hdpa->ptrs[i], lParam) == 0) - return; - } - - return; -} - - -/************************************************************************** - * DPA_DestroyCallback [COMCTL32.386] - * - * Enumerates all items in a dynamic pointer array and destroys it. - * - * PARAMS - * hdpa [I] handle to the dynamic pointer array - * enumProc [I] - * lParam [I] - * - * RETURNS - * none - */ -void WINAPI DPA_DestroyCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc, - LPVOID lParam) -{ - TRACE("(%p %p %p)\n", hdpa, enumProc, lParam); - - DPA_EnumCallback (hdpa, enumProc, lParam); - DPA_Destroy (hdpa); -} - - -/************************************************************************** - * DSA_EnumCallback [COMCTL32.387] - * - * Enumerates all items in a dynamic storage array. - * - * PARAMS - * hdsa [I] handle to the dynamic storage array - * enumProc [I] - * lParam [I] - * - * RETURNS - * none - */ -VOID WINAPI DSA_EnumCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc, - LPVOID lParam) -{ - INT i; - - TRACE("(%p %p %p)\n", hdsa, enumProc, lParam); - - if (!hdsa) - return; - if (hdsa->nItemCount <= 0) - return; - - for (i = 0; i < hdsa->nItemCount; i++) { - LPVOID lpItem = DSA_GetItemPtr (hdsa, i); - if ((enumProc)(lpItem, lParam) == 0) - return; - } - - return; -} - - -/************************************************************************** - * DSA_DestroyCallback [COMCTL32.388] - * - * Enumerates all items in a dynamic storage array and destroys it. - * - * PARAMS - * hdsa [I] handle to the dynamic storage array - * enumProc [I] - * lParam [I] - * - * RETURNS - * none - */ -void WINAPI DSA_DestroyCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc, - LPVOID lParam) -{ - TRACE("(%p %p %p)\n", hdsa, enumProc, lParam); - - DSA_EnumCallback (hdsa, enumProc, lParam); - DSA_Destroy (hdsa); -} +/* + * Undocumented functions from COMCTL32.DLL + * + * Copyright 1998 Eric Kohl + * 1998 Juergen Schmied + * 2000 Eric Kohl for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES + * All of these functions are UNDOCUMENTED!! And I mean UNDOCUMENTED!!!! + * Do NOT rely on names or contents of undocumented structures and types!!! + * These functions are used by EXPLORER.EXE, IEXPLORE.EXE and + * COMCTL32.DLL (internally). + * + */ +#include "config.h" +#include "wine/port.h" + +#include +#include +#include +#include + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "winreg.h" +#include "commctrl.h" +#include "objbase.h" +#include "winerror.h" + +#include "wine/unicode.h" +#include "comctl32.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(commctrl); + +struct _DSA +{ + INT nItemCount; + LPVOID pData; + INT nMaxCount; + INT nItemSize; + INT nGrow; +}; + +struct _DPA +{ + INT nItemCount; + LPVOID *ptrs; + HANDLE hHeap; + INT nGrow; + INT nMaxCount; +}; + +typedef struct _STREAMDATA +{ + DWORD dwSize; + DWORD dwData2; + DWORD dwItems; +} STREAMDATA, *PSTREAMDATA; + +typedef struct _LOADDATA +{ + INT nCount; + PVOID ptr; +} LOADDATA, *LPLOADDATA; + +typedef HRESULT (CALLBACK *DPALOADPROC)(LPLOADDATA,IStream*,LPARAM); + +static const WCHAR strMRUList[] = { 'M','R','U','L','i','s','t',0 }; + +/************************************************************************** + * DPA_LoadStream [COMCTL32.9] + * + * Loads a dynamic pointer array from a stream + * + * PARAMS + * phDpa [O] pointer to a handle to a dynamic pointer array + * loadProc [I] pointer to a callback function + * pStream [I] pointer to a stream + * lParam [I] application specific value + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * No more information available yet! + */ +HRESULT WINAPI DPA_LoadStream (HDPA *phDpa, DPALOADPROC loadProc, + IStream *pStream, LPARAM lParam) +{ + HRESULT errCode; + LARGE_INTEGER position; + ULARGE_INTEGER newPosition; + STREAMDATA streamData; + LOADDATA loadData; + ULONG ulRead; + HDPA hDpa; + PVOID *ptr; + + FIXME ("phDpa=%p loadProc=%p pStream=%p lParam=%lx\n", + phDpa, loadProc, pStream, lParam); + + if (!phDpa || !loadProc || !pStream) + return E_INVALIDARG; + + *phDpa = (HDPA)NULL; + + position.QuadPart = 0; + + /* + * Zero out our streamData + */ + memset(&streamData,0,sizeof(STREAMDATA)); + + errCode = IStream_Seek (pStream, position, STREAM_SEEK_CUR, &newPosition); + if (errCode != S_OK) + return errCode; + + errCode = IStream_Read (pStream, &streamData, sizeof(STREAMDATA), &ulRead); + if (errCode != S_OK) + return errCode; + + FIXME ("dwSize=%lu dwData2=%lu dwItems=%lu\n", + streamData.dwSize, streamData.dwData2, streamData.dwItems); + + if ( ulRead < sizeof(STREAMDATA) || + lParam < sizeof(STREAMDATA) || + streamData.dwSize < sizeof(STREAMDATA) || + streamData.dwData2 < 1) { + errCode = E_FAIL; + } + + if (streamData.dwItems > (UINT_MAX / 2 / sizeof(VOID*))) /* 536870911 */ + return E_OUTOFMEMORY; + + /* create the dpa */ + hDpa = DPA_Create (streamData.dwItems); + if (!hDpa) + return E_OUTOFMEMORY; + + if (!DPA_Grow (hDpa, streamData.dwItems)) + return E_OUTOFMEMORY; + + /* load data from the stream into the dpa */ + ptr = hDpa->ptrs; + for (loadData.nCount = 0; loadData.nCount < streamData.dwItems; loadData.nCount++) { + errCode = (loadProc)(&loadData, pStream, lParam); + if (errCode != S_OK) { + errCode = S_FALSE; + break; + } + + *ptr = loadData.ptr; + ptr++; + } + + /* set the number of items */ + hDpa->nItemCount = loadData.nCount; + + /* store the handle to the dpa */ + *phDpa = hDpa; + FIXME ("new hDpa=%p, errorcode=%lx\n", hDpa, errCode); + + return errCode; +} + + +/************************************************************************** + * DPA_SaveStream [COMCTL32.10] + * + * Saves a dynamic pointer array to a stream + * + * PARAMS + * hDpa [I] handle to a dynamic pointer array + * loadProc [I] pointer to a callback function + * pStream [I] pointer to a stream + * lParam [I] application specific value + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * No more information available yet! + */ +HRESULT WINAPI DPA_SaveStream (const HDPA hDpa, DPALOADPROC loadProc, + IStream *pStream, LPARAM lParam) +{ + + FIXME ("hDpa=%p loadProc=%p pStream=%p lParam=%lx\n", + hDpa, loadProc, pStream, lParam); + + return E_FAIL; +} + + +/************************************************************************** + * DPA_Merge [COMCTL32.11] + * + * Merge two dynamic pointers arrays. + * + * PARAMS + * hdpa1 [I] handle to a dynamic pointer array + * hdpa2 [I] handle to a dynamic pointer array + * dwFlags [I] flags + * pfnCompare [I] pointer to sort function + * pfnMerge [I] pointer to merge function + * lParam [I] application specific value + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * No more information available yet! + */ +BOOL WINAPI DPA_Merge (const HDPA hdpa1, const HDPA hdpa2, DWORD dwFlags, + PFNDPACOMPARE pfnCompare, PFNDPAMERGE pfnMerge, + LPARAM lParam) +{ + INT nCount; + LPVOID *pWork1, *pWork2; + INT nResult, i; + INT nIndex; + + TRACE("%p %p %08lx %p %p %08lx)\n", + hdpa1, hdpa2, dwFlags, pfnCompare, pfnMerge, lParam); + + if (IsBadWritePtr (hdpa1, sizeof(*hdpa1))) + return FALSE; + + if (IsBadWritePtr (hdpa2, sizeof(*hdpa2))) + return FALSE; + + if (IsBadCodePtr ((FARPROC)pfnCompare)) + return FALSE; + + if (IsBadCodePtr ((FARPROC)pfnMerge)) + return FALSE; + + if (!(dwFlags & DPAM_NOSORT)) { + TRACE("sorting dpa's!\n"); + if (hdpa1->nItemCount > 0) + DPA_Sort (hdpa1, pfnCompare, lParam); + TRACE ("dpa 1 sorted!\n"); + if (hdpa2->nItemCount > 0) + DPA_Sort (hdpa2, pfnCompare, lParam); + TRACE ("dpa 2 sorted!\n"); + } + + if (hdpa2->nItemCount < 1) + return TRUE; + + TRACE("hdpa1->nItemCount=%d hdpa2->nItemCount=%d\n", + hdpa1->nItemCount, hdpa2->nItemCount); + + + /* working but untrusted implementation */ + + pWork1 = &(hdpa1->ptrs[hdpa1->nItemCount - 1]); + pWork2 = &(hdpa2->ptrs[hdpa2->nItemCount - 1]); + + nIndex = hdpa1->nItemCount - 1; + nCount = hdpa2->nItemCount - 1; + + do + { + if (nIndex < 0) { + if ((nCount >= 0) && (dwFlags & DPAM_INSERT)) { + /* Now insert the remaining new items into DPA 1 */ + TRACE("%d items to be inserted at start of DPA 1\n", + nCount+1); + for (i=nCount; i>=0; i--) { + PVOID ptr; + + ptr = (pfnMerge)(3, *pWork2, NULL, lParam); + if (!ptr) + return FALSE; + DPA_InsertPtr (hdpa1, 0, ptr); + pWork2--; + } + } + break; + } + nResult = (pfnCompare)(*pWork1, *pWork2, lParam); + TRACE("compare result=%d, dpa1.cnt=%d, dpa2.cnt=%d\n", + nResult, nIndex, nCount); + + if (nResult == 0) + { + PVOID ptr; + + ptr = (pfnMerge)(1, *pWork1, *pWork2, lParam); + if (!ptr) + return FALSE; + + nCount--; + pWork2--; + *pWork1 = ptr; + nIndex--; + pWork1--; + } + else if (nResult > 0) + { + /* item in DPA 1 missing from DPA 2 */ + if (dwFlags & DPAM_DELETE) + { + /* Now delete the extra item in DPA1 */ + PVOID ptr; + + ptr = DPA_DeletePtr (hdpa1, hdpa1->nItemCount - 1); + + (pfnMerge)(2, ptr, NULL, lParam); + } + nIndex--; + pWork1--; + } + else + { + /* new item in DPA 2 */ + if (dwFlags & DPAM_INSERT) + { + /* Now insert the new item in DPA 1 */ + PVOID ptr; + + ptr = (pfnMerge)(3, *pWork2, NULL, lParam); + if (!ptr) + return FALSE; + DPA_InsertPtr (hdpa1, nIndex+1, ptr); + } + nCount--; + pWork2--; + } + + } + while (nCount >= 0); + + return TRUE; +} + + +/************************************************************************** + * Alloc [COMCTL32.71] + * + * Allocates memory block from the dll's private heap + * + * PARAMS + * dwSize [I] size of the allocated memory block + * + * RETURNS + * Success: pointer to allocated memory block + * Failure: NULL + */ +LPVOID WINAPI Alloc (DWORD dwSize) +{ + return LocalAlloc( LMEM_ZEROINIT, dwSize ); +} + + +/************************************************************************** + * ReAlloc [COMCTL32.72] + * + * Changes the size of an allocated memory block or allocates a memory + * block using the dll's private heap. + * + * PARAMS + * lpSrc [I] pointer to memory block which will be resized + * dwSize [I] new size of the memory block. + * + * RETURNS + * Success: pointer to the resized memory block + * Failure: NULL + * + * NOTES + * If lpSrc is a NULL-pointer, then ReAlloc allocates a memory + * block like Alloc. + */ +LPVOID WINAPI ReAlloc (LPVOID lpSrc, DWORD dwSize) +{ + if (lpSrc) + return LocalReAlloc( lpSrc, dwSize, LMEM_ZEROINIT ); + else + return LocalAlloc( LMEM_ZEROINIT, dwSize); +} + + +/************************************************************************** + * Free [COMCTL32.73] + * + * Frees an allocated memory block from the dll's private heap. + * + * PARAMS + * lpMem [I] pointer to memory block which will be freed + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI Free (LPVOID lpMem) +{ + return !LocalFree( lpMem ); +} + + +/************************************************************************** + * GetSize [COMCTL32.74] + * + * Retrieves the size of the specified memory block from the dll's + * private heap. + * + * PARAMS + * lpMem [I] pointer to an allocated memory block + * + * RETURNS + * Success: size of the specified memory block + * Failure: 0 + */ +DWORD WINAPI GetSize (LPVOID lpMem) +{ + return LocalSize( lpMem ); +} + + +/************************************************************************** + * MRU-Functions {COMCTL32} + * + * NOTES + * The MRU-Api is a set of functions to manipulate lists of M.R.U. (Most Recently + * Used) items. It is an undocumented Api that is used (at least) by the shell + * and explorer to implement their recent documents feature. + * + * Since these functions are undocumented, they are unsupported by MS and + * may change at any time. + * + * Internally, the list is implemented as a last in, last out list of items + * persisted into the system registry under a caller chosen key. Each list + * item is given a one character identifier in the Ascii range from 'a' to + * '}'. A list of the identifiers in order from newest to oldest is stored + * under the same key in a value named "MRUList". + * + * Items are re-ordered by changing the order of the values in the MRUList + * value. When a new item is added, it becomes the new value of the oldest + * identifier, and that identifier is moved to the front of the MRUList value. + * + * Wine stores MRU-lists in the same registry format as Windows, so when + * switching between the builtin and native comctl32.dll no problems or + * incompatibilities should occur. + * + * The following undocumented structure is used to create an MRU-list: + *|typedef INT (CALLBACK *MRUStringCmpFn)(LPCTSTR lhs, LPCTSTR rhs); + *|typedef INT (CALLBACK *MRUBinaryCmpFn)(LPCVOID lhs, LPCVOID rhs, DWORD length); + *| + *|typedef struct tagCREATEMRULIST + *|{ + *| DWORD cbSize; + *| DWORD nMaxItems; + *| DWORD dwFlags; + *| HKEY hKey; + *| LPCTSTR lpszSubKey; + *| PROC lpfnCompare; + *|} CREATEMRULIST, *LPCREATEMRULIST; + * + * MEMBERS + * cbSize [I] The size of the CREATEMRULIST structure. This must be set + * to sizeof(CREATEMRULIST) by the caller. + * nMaxItems [I] The maximum number of items allowed in the list. Because + * of the limited number of identifiers, this should be set to + * a value from 1 to 30 by the caller. + * dwFlags [I] If bit 0 is set, the list will be used to store binary + * data, otherwise it is assumed to store strings. If bit 1 + * is set, every change made to the list will be reflected in + * the registry immediately, otherwise changes will only be + * written when the list is closed. + * hKey [I] The registry key that the list should be written under. + * This must be supplied by the caller. + * lpszSubKey [I] A caller supplied name of a subkey under hKey to write + * the list to. This may not be blank. + * lpfnCompare [I] A caller supplied comparison function, which may be either + * an MRUStringCmpFn if dwFlags does not have bit 0 set, or a + * MRUBinaryCmpFn otherwise. + * + * FUNCTIONS + * - Create an MRU-list with CreateMRUList() or CreateMRUListLazy(). + * - Add items to an MRU-list with AddMRUString() or AddMRUData(). + * - Remove items from an MRU-list with DelMRUString(). + * - Find data in an MRU-list with FindMRUString() or FindMRUData(). + * - Iterate through an MRU-list with EnumMRUList(). + * - Free an MRU-list with FreeMRUList(). + */ + +typedef struct tagCREATEMRULISTA +{ + DWORD cbSize; + DWORD nMaxItems; + DWORD dwFlags; + HKEY hKey; + LPCSTR lpszSubKey; + PROC lpfnCompare; +} CREATEMRULISTA, *LPCREATEMRULISTA; + +typedef struct tagCREATEMRULISTW +{ + DWORD cbSize; + DWORD nMaxItems; + DWORD dwFlags; + HKEY hKey; + LPCWSTR lpszSubKey; + PROC lpfnCompare; +} CREATEMRULISTW, *LPCREATEMRULISTW; + +/* dwFlags */ +#define MRUF_STRING_LIST 0 /* list will contain strings */ +#define MRUF_BINARY_LIST 1 /* list will contain binary data */ +#define MRUF_DELAYED_SAVE 2 /* only save list order to reg. is FreeMRUList */ + +/* If list is a string list lpfnCompare has the following prototype + * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2) + * for binary lists the prototype is + * int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData) + * where cbData is the no. of bytes to compare. + * Need to check what return value means identical - 0? + */ + +typedef struct tagWINEMRUITEM +{ + DWORD size; /* size of data stored */ + DWORD itemFlag; /* flags */ + BYTE datastart; +} WINEMRUITEM, *LPWINEMRUITEM; + +/* itemFlag */ +#define WMRUIF_CHANGED 0x0001 /* this dataitem changed */ + +typedef struct tagWINEMRULIST +{ + CREATEMRULISTW extview; /* original create information */ + BOOL isUnicode; /* is compare fn Unicode */ + DWORD wineFlags; /* internal flags */ + DWORD cursize; /* current size of realMRU */ + LPWSTR realMRU; /* pointer to string of index names */ + LPWINEMRUITEM *array; /* array of pointers to data */ + /* in 'a' to 'z' order */ +} WINEMRULIST, *LPWINEMRULIST; + +/* wineFlags */ +#define WMRUF_CHANGED 0x0001 /* MRU list has changed */ + +/************************************************************************** + * MRU_SaveChanged (internal) + * + * Local MRU saving code + */ +static void MRU_SaveChanged ( LPWINEMRULIST mp ) +{ + UINT i, err; + HKEY newkey; + WCHAR realname[2]; + LPWINEMRUITEM witem; + static const WCHAR emptyW[] = {'\0'}; + + /* or should we do the following instead of RegOpenKeyEx: + */ + + /* open the sub key */ + if ((err = RegOpenKeyExW( mp->extview.hKey, mp->extview.lpszSubKey, + 0, KEY_WRITE, &newkey))) { + /* not present - what to do ??? */ + ERR("Could not open key, error=%d, attempting to create\n", + err); + if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey, + 0, + (LPWSTR)emptyW, + REG_OPTION_NON_VOLATILE, + KEY_READ | KEY_WRITE, + 0, + &newkey, + 0))) { + ERR("failed to create key /%s/, err=%d\n", + debugstr_w(mp->extview.lpszSubKey), err); + return; + } + } + if (mp->wineFlags & WMRUF_CHANGED) { + mp->wineFlags &= ~WMRUF_CHANGED; + err = RegSetValueExW(newkey, strMRUList, 0, REG_SZ, (LPBYTE)mp->realMRU, + (strlenW(mp->realMRU) + 1)*sizeof(WCHAR)); + if (err) { + ERR("error saving MRUList, err=%d\n", err); + } + TRACE("saving MRUList=/%s/\n", debugstr_w(mp->realMRU)); + } + realname[1] = 0; + for(i=0; icursize; i++) { + witem = mp->array[i]; + if (witem->itemFlag & WMRUIF_CHANGED) { + witem->itemFlag &= ~WMRUIF_CHANGED; + realname[0] = 'a' + i; + err = RegSetValueExW(newkey, realname, 0, + (mp->extview.dwFlags & MRUF_BINARY_LIST) ? + REG_BINARY : REG_SZ, + &witem->datastart, witem->size); + if (err) { + ERR("error saving /%s/, err=%d\n", debugstr_w(realname), err); + } + TRACE("saving value for name /%s/ size=%ld\n", + debugstr_w(realname), witem->size); + } + } + RegCloseKey( newkey ); +} + +/************************************************************************** + * FreeMRUList [COMCTL32.152] + * + * Frees a most-recently-used items list. + * + * PARAMS + * hMRUList [I] Handle to list. + * + * RETURNS + * Nothing. + */ +void WINAPI FreeMRUList (HANDLE hMRUList) +{ + LPWINEMRULIST mp = (LPWINEMRULIST)hMRUList; + UINT i; + + TRACE("(%p)\n", hMRUList); + if (!hMRUList) + return; + + if (mp->wineFlags & WMRUF_CHANGED) { + /* need to open key and then save the info */ + MRU_SaveChanged( mp ); + } + + for(i=0; iextview.nMaxItems; i++) { + if (mp->array[i]) + Free(mp->array[i]); + } + Free(mp->realMRU); + Free(mp->array); + Free((LPWSTR)mp->extview.lpszSubKey); + Free(mp); +} + + +/************************************************************************** + * FindMRUData [COMCTL32.169] + * + * Searches binary list for item that matches lpData of length cbData. + * Returns position in list order 0 -> MRU and if lpRegNum != NULL then value + * corresponding to item's reg. name will be stored in it ('a' -> 0). + * + * PARAMS + * hList [I] list handle + * lpData [I] data to find + * cbData [I] length of data + * lpRegNum [O] position in registry (maybe NULL) + * + * RETURNS + * Position in list 0 -> MRU. -1 if item not found. + */ +INT WINAPI FindMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData, + LPINT lpRegNum) +{ + LPWINEMRULIST mp = (LPWINEMRULIST)hList; + INT ret; + UINT i; + LPSTR dataA = NULL; + + if (!mp->extview.lpfnCompare) { + ERR("MRU list not properly created. No compare procedure.\n"); + return -1; + } + + if(!(mp->extview.dwFlags & MRUF_BINARY_LIST) && !mp->isUnicode) { + DWORD len = WideCharToMultiByte(CP_ACP, 0, lpData, -1, + NULL, 0, NULL, NULL); + dataA = Alloc(len); + WideCharToMultiByte(CP_ACP, 0, lpData, -1, dataA, len, NULL, NULL); + } + + for(i=0; icursize; i++) { + if (mp->extview.dwFlags & MRUF_BINARY_LIST) { + if (!mp->extview.lpfnCompare(lpData, &mp->array[i]->datastart, + cbData)) + break; + } + else { + if(mp->isUnicode) { + if (!mp->extview.lpfnCompare(lpData, &mp->array[i]->datastart)) + break; + } else { + DWORD len = WideCharToMultiByte(CP_ACP, 0, + (LPWSTR)&mp->array[i]->datastart, -1, + NULL, 0, NULL, NULL); + LPSTR itemA = Alloc(len); + INT cmp; + WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&mp->array[i]->datastart, -1, + itemA, len, NULL, NULL); + + cmp = mp->extview.lpfnCompare(dataA, itemA); + Free(itemA); + if(!cmp) + break; + } + } + } + if(dataA) + Free(dataA); + if (i < mp->cursize) + ret = i; + else + ret = -1; + if (lpRegNum && (ret != -1)) + *lpRegNum = 'a' + i; + + TRACE("(%p, %p, %ld, %p) returning %d\n", + hList, lpData, cbData, lpRegNum, ret); + + return ret; +} + + +/************************************************************************** + * AddMRUData [COMCTL32.167] + * + * Add item to MRU binary list. If item already exists in list then it is + * simply moved up to the top of the list and not added again. If list is + * full then the least recently used item is removed to make room. + * + * PARAMS + * hList [I] Handle to list. + * lpData [I] ptr to data to add. + * cbData [I] no. of bytes of data. + * + * RETURNS + * No. corresponding to registry name where value is stored 'a' -> 0 etc. + * -1 on error. + */ +INT WINAPI AddMRUData (HANDLE hList, LPCVOID lpData, DWORD cbData) +{ + LPWINEMRULIST mp = (LPWINEMRULIST)hList; + LPWINEMRUITEM witem; + INT i, replace; + + if ((replace = FindMRUData (hList, lpData, cbData, NULL)) >= 0) { + /* Item exists, just move it to the front */ + LPWSTR pos = strchrW(mp->realMRU, replace + 'a'); + while (pos > mp->realMRU) + { + pos[0] = pos[-1]; + pos--; + } + } + else { + /* either add a new entry or replace oldest */ + if (mp->cursize < mp->extview.nMaxItems) { + /* Add in a new item */ + replace = mp->cursize; + mp->cursize++; + } + else { + /* get the oldest entry and replace data */ + replace = mp->realMRU[mp->cursize - 1] - 'a'; + Free(mp->array[replace]); + } + + /* Allocate space for new item and move in the data */ + mp->array[replace] = witem = Alloc(cbData + sizeof(WINEMRUITEM)); + witem->itemFlag |= WMRUIF_CHANGED; + witem->size = cbData; + memcpy( &witem->datastart, lpData, cbData); + + /* now rotate MRU list */ + for(i=mp->cursize-1; i>=1; i--) + mp->realMRU[i] = mp->realMRU[i-1]; + } + + /* The new item gets the front spot */ + mp->wineFlags |= WMRUF_CHANGED; + mp->realMRU[0] = replace + 'a'; + + TRACE("(%p, %p, %ld) adding data, /%c/ now most current\n", + hList, lpData, cbData, replace+'a'); + + if (!(mp->extview.dwFlags & MRUF_DELAYED_SAVE)) { + /* save changed stuff right now */ + MRU_SaveChanged( mp ); + } + + return replace; +} + +/************************************************************************** + * AddMRUStringW [COMCTL32.401] + * + * Add an item to an MRU string list. + * + * PARAMS + * hList [I] Handle to list. + * lpszString [I] The string to add. + * + * RETURNS + * Success: The number corresponding to the registry name where the string + * has been stored (0 maps to 'a', 1 to 'b' and so on). + * Failure: -1, if hList is NULL or memory allocation fails. If lpszString + * is invalid, the function returns 0, and GetLastError() returns + * ERROR_INVALID_PARAMETER. The last error value is set only in + * this case. + * + * NOTES + * -If lpszString exists in the list already, it is moved to the top of the + * MRU list (it is not duplicated). + * -If the list is full the least recently used list entry is replaced with + * lpszString. + * -If this function returns 0 you should check the last error value to + * ensure the call really succeeded. + */ +INT WINAPI AddMRUStringW(HANDLE hList, LPCWSTR lpszString) +{ + TRACE("(%p,%s)\n", hList, debugstr_w(lpszString)); + + if (!hList) + return -1; + + if (!lpszString || IsBadStringPtrW(lpszString, -1)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + return AddMRUData(hList, lpszString, + (strlenW(lpszString) + 1) * sizeof(WCHAR)); +} + +/************************************************************************** + * AddMRUStringA [COMCTL32.153] + * + * See AddMRUStringW. + */ +INT WINAPI AddMRUStringA(HANDLE hList, LPCSTR lpszString) +{ + DWORD len; + LPWSTR stringW; + INT ret; + + TRACE("(%p,%s)\n", hList, debugstr_a(lpszString)); + + if (!hList) + return -1; + + if (IsBadStringPtrA(lpszString, -1)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + len = MultiByteToWideChar(CP_ACP, 0, lpszString, -1, NULL, 0) * sizeof(WCHAR); + stringW = Alloc(len); + if (!stringW) + return -1; + + MultiByteToWideChar(CP_ACP, 0, lpszString, -1, stringW, len); + ret = AddMRUData(hList, stringW, len); + Free(stringW); + return ret; +} + +/************************************************************************** + * DelMRUString [COMCTL32.156] + * + * Removes item from either string or binary list (despite its name) + * + * PARAMS + * hList [I] list handle + * nItemPos [I] item position to remove 0 -> MRU + * + * RETURNS + * TRUE if successful, FALSE if nItemPos is out of range. + */ +BOOL WINAPI DelMRUString(HANDLE hList, INT nItemPos) +{ + FIXME("(%p, %d): stub\n", hList, nItemPos); + return TRUE; +} + +/************************************************************************** + * FindMRUStringW [COMCTL32.402] + * + * See FindMRUStringA. + */ +INT WINAPI FindMRUStringW (HANDLE hList, LPCWSTR lpszString, LPINT lpRegNum) +{ + return FindMRUData(hList, lpszString, + (lstrlenW(lpszString) + 1) * sizeof(WCHAR), lpRegNum); +} + +/************************************************************************** + * FindMRUStringA [COMCTL32.155] + * + * Searches string list for item that matches lpszString. + * Returns position in list order 0 -> MRU and if lpRegNum != NULL then value + * corresponding to item's reg. name will be stored in it ('a' -> 0). + * + * PARAMS + * hList [I] list handle + * lpszString [I] string to find + * lpRegNum [O] position in registry (maybe NULL) + * + * RETURNS + * Position in list 0 -> MRU. -1 if item not found. + */ +INT WINAPI FindMRUStringA (HANDLE hList, LPCSTR lpszString, LPINT lpRegNum) +{ + DWORD len = MultiByteToWideChar(CP_ACP, 0, lpszString, -1, NULL, 0); + LPWSTR stringW = Alloc(len * sizeof(WCHAR)); + INT ret; + + MultiByteToWideChar(CP_ACP, 0, lpszString, -1, stringW, len); + ret = FindMRUData(hList, stringW, len * sizeof(WCHAR), lpRegNum); + Free(stringW); + return ret; +} + +/************************************************************************* + * CreateMRUListLazy_common (internal) + */ +static HANDLE CreateMRUListLazy_common(LPWINEMRULIST mp) +{ + UINT i, err; + HKEY newkey; + DWORD datasize, dwdisp; + WCHAR realname[2]; + LPWINEMRUITEM witem; + DWORD type; + static const WCHAR emptyW[] = {'\0'}; + + /* get space to save indices that will turn into names + * but in order of most to least recently used + */ + mp->realMRU = Alloc((mp->extview.nMaxItems + 2) * sizeof(WCHAR)); + + /* get space to save pointers to actual data in order of + * 'a' to 'z' (0 to n). + */ + mp->array = Alloc(mp->extview.nMaxItems * sizeof(LPVOID)); + + /* open the sub key */ + if ((err = RegCreateKeyExW( mp->extview.hKey, mp->extview.lpszSubKey, + 0, + (LPWSTR)emptyW, + REG_OPTION_NON_VOLATILE, + KEY_READ | KEY_WRITE, + 0, + &newkey, + &dwdisp))) { + /* error - what to do ??? */ + ERR("(%lu %lu %lx %lx \"%s\" %p): Could not open key, error=%d\n", + mp->extview.cbSize, mp->extview.nMaxItems, mp->extview.dwFlags, + (DWORD)mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey), + mp->extview.lpfnCompare, err); + return 0; + } + + /* get values from key 'MRUList' */ + if (newkey) { + datasize = mp->extview.nMaxItems + 1; + if((err=RegQueryValueExW( newkey, strMRUList, 0, &type, + (LPBYTE)mp->realMRU, &datasize))) { + /* not present - set size to 1 (will become 0 later) */ + datasize = 1; + *mp->realMRU = 0; + } + + TRACE("MRU list = %s, datasize = %ld\n", debugstr_w(mp->realMRU), datasize); + + mp->cursize = datasize - 1; + /* datasize now has number of items in the MRUList */ + + /* get actual values for each entry */ + realname[1] = 0; + for(i=0; icursize; i++) { + realname[0] = 'a' + i; + if(RegQueryValueExW( newkey, realname, 0, &type, 0, &datasize)) { + /* not present - what to do ??? */ + ERR("Key %s not found 1\n", debugstr_w(realname)); + } + mp->array[i] = witem = Alloc(datasize + sizeof(WINEMRUITEM)); + witem->size = datasize; + if(RegQueryValueExW( newkey, realname, 0, &type, + &witem->datastart, &datasize)) { + /* not present - what to do ??? */ + ERR("Key %s not found 2\n", debugstr_w(realname)); + } + } + RegCloseKey( newkey ); + } + else + mp->cursize = 0; + + TRACE("(%lu %lu %lx %lx \"%s\" %p): Current Size = %ld\n", + mp->extview.cbSize, mp->extview.nMaxItems, mp->extview.dwFlags, + (DWORD)mp->extview.hKey, debugstr_w(mp->extview.lpszSubKey), + mp->extview.lpfnCompare, mp->cursize); + return (HANDLE)mp; +} + +/************************************************************************** + * CreateMRUListLazyW [COMCTL32.404] + * + * See CreateMRUListLazyA. + */ +HANDLE WINAPI CreateMRUListLazyW (LPCREATEMRULISTW lpcml, DWORD dwParam2, + DWORD dwParam3, DWORD dwParam4) +{ + LPWINEMRULIST mp; + + /* Native does not check for a NULL lpcml */ + + if (lpcml->cbSize != sizeof(CREATEMRULISTW) || !lpcml->hKey || + IsBadStringPtrW(lpcml->lpszSubKey, -1)) + return NULL; + + mp = Alloc(sizeof(WINEMRULIST)); + memcpy(&mp->extview, lpcml, sizeof(CREATEMRULISTW)); + mp->extview.lpszSubKey = Alloc((strlenW(lpcml->lpszSubKey) + 1) * sizeof(WCHAR)); + strcpyW((LPWSTR)mp->extview.lpszSubKey, lpcml->lpszSubKey); + mp->isUnicode = TRUE; + + return CreateMRUListLazy_common(mp); +} + +/************************************************************************** + * CreateMRUListLazyA [COMCTL32.157] + * + * Creates a most-recently-used list. + * + * PARAMS + * lpcml [I] ptr to CREATEMRULIST structure. + * dwParam2 [I] Unknown + * dwParam3 [I] Unknown + * dwParam4 [I] Unknown + * + * RETURNS + * Handle to MRU list. + */ +HANDLE WINAPI CreateMRUListLazyA (LPCREATEMRULISTA lpcml, DWORD dwParam2, + DWORD dwParam3, DWORD dwParam4) +{ + LPWINEMRULIST mp; + DWORD len; + + /* Native does not check for a NULL lpcml */ + + if (lpcml->cbSize != sizeof(CREATEMRULISTA) || !lpcml->hKey || + IsBadStringPtrA(lpcml->lpszSubKey, -1)) + return 0; + + mp = Alloc(sizeof(WINEMRULIST)); + memcpy(&mp->extview, lpcml, sizeof(CREATEMRULISTW)); + len = MultiByteToWideChar(CP_ACP, 0, lpcml->lpszSubKey, -1, NULL, 0); + mp->extview.lpszSubKey = Alloc(len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, lpcml->lpszSubKey, -1, + (LPWSTR)mp->extview.lpszSubKey, len); + mp->isUnicode = FALSE; + return CreateMRUListLazy_common(mp); +} + +/************************************************************************** + * CreateMRUListW [COMCTL32.400] + * + * See CreateMRUListA. + */ +HANDLE WINAPI CreateMRUListW (LPCREATEMRULISTW lpcml) +{ + return CreateMRUListLazyW(lpcml, 0, 0, 0); +} + +/************************************************************************** + * CreateMRUListA [COMCTL32.151] + * + * Creates a most-recently-used list. + * + * PARAMS + * lpcml [I] ptr to CREATEMRULIST structure. + * + * RETURNS + * Handle to MRU list. + */ +HANDLE WINAPI CreateMRUListA (LPCREATEMRULISTA lpcml) +{ + return CreateMRUListLazyA (lpcml, 0, 0, 0); +} + + +/************************************************************************** + * EnumMRUListW [COMCTL32.403] + * + * Enumerate item in a most-recenty-used list + * + * PARAMS + * hList [I] list handle + * nItemPos [I] item position to enumerate + * lpBuffer [O] buffer to receive item + * nBufferSize [I] size of buffer + * + * RETURNS + * For binary lists specifies how many bytes were copied to buffer, for + * string lists specifies full length of string. Enumerating past the end + * of list returns -1. + * If lpBuffer == NULL or nItemPos is -ve return value is no. of items in + * the list. + */ +INT WINAPI EnumMRUListW (HANDLE hList, INT nItemPos, LPVOID lpBuffer, + DWORD nBufferSize) +{ + LPWINEMRULIST mp = (LPWINEMRULIST) hList; + LPWINEMRUITEM witem; + INT desired, datasize; + + if (nItemPos >= mp->cursize) return -1; + if ((nItemPos < 0) || !lpBuffer) return mp->cursize; + desired = mp->realMRU[nItemPos]; + desired -= 'a'; + TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired); + witem = mp->array[desired]; + datasize = min( witem->size, nBufferSize ); + memcpy( lpBuffer, &witem->datastart, datasize); + TRACE("(%p, %d, %p, %ld): returning len=%d\n", + hList, nItemPos, lpBuffer, nBufferSize, datasize); + return datasize; +} + +/************************************************************************** + * EnumMRUListA [COMCTL32.154] + * + * See EnumMRUListW. + */ +INT WINAPI EnumMRUListA (HANDLE hList, INT nItemPos, LPVOID lpBuffer, + DWORD nBufferSize) +{ + LPWINEMRULIST mp = (LPWINEMRULIST) hList; + LPWINEMRUITEM witem; + INT desired, datasize; + DWORD lenA; + + if (nItemPos >= mp->cursize) return -1; + if ((nItemPos < 0) || !lpBuffer) return mp->cursize; + desired = mp->realMRU[nItemPos]; + desired -= 'a'; + TRACE("nItemPos=%d, desired=%d\n", nItemPos, desired); + witem = mp->array[desired]; + if(mp->extview.dwFlags & MRUF_BINARY_LIST) { + datasize = min( witem->size, nBufferSize ); + memcpy( lpBuffer, &witem->datastart, datasize); + } else { + lenA = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1, + NULL, 0, NULL, NULL); + datasize = min( witem->size, nBufferSize ); + WideCharToMultiByte(CP_ACP, 0, (LPWSTR)&witem->datastart, -1, + lpBuffer, datasize, NULL, NULL); + } + TRACE("(%p, %d, %p, %ld): returning len=%d\n", + hList, nItemPos, lpBuffer, nBufferSize, datasize); + return datasize; +} + + +/************************************************************************** + * Str_GetPtrA [COMCTL32.233] + * + * Copies a string into a destination buffer. + * + * PARAMS + * lpSrc [I] Source string + * lpDest [O] Destination buffer + * nMaxLen [I] Size of buffer in characters + * + * RETURNS + * The number of characters copied. + */ +INT WINAPI Str_GetPtrA (LPCSTR lpSrc, LPSTR lpDest, INT nMaxLen) +{ + INT len; + + TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen); + + if (!lpDest && lpSrc) + return strlen (lpSrc); + + if (nMaxLen == 0) + return 0; + + if (lpSrc == NULL) { + lpDest[0] = '\0'; + return 0; + } + + len = strlen (lpSrc); + if (len >= nMaxLen) + len = nMaxLen - 1; + + RtlMoveMemory (lpDest, lpSrc, len); + lpDest[len] = '\0'; + + return len; +} + + +/************************************************************************** + * Str_SetPtrA [COMCTL32.234] + * + * Makes a copy of a string, allocating memory if necessary. + * + * PARAMS + * lppDest [O] Pointer to destination string + * lpSrc [I] Source string + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * Set lpSrc to NULL to free the memory allocated by a previous call + * to this function. + */ +BOOL WINAPI Str_SetPtrA (LPSTR *lppDest, LPCSTR lpSrc) +{ + TRACE("(%p %p)\n", lppDest, lpSrc); + + if (lpSrc) { + LPSTR ptr = ReAlloc (*lppDest, strlen (lpSrc) + 1); + if (!ptr) + return FALSE; + strcpy (ptr, lpSrc); + *lppDest = ptr; + } + else { + if (*lppDest) { + Free (*lppDest); + *lppDest = NULL; + } + } + + return TRUE; +} + + +/************************************************************************** + * Str_GetPtrW [COMCTL32.235] + * + * See Str_GetPtrA. + */ +INT WINAPI Str_GetPtrW (LPCWSTR lpSrc, LPWSTR lpDest, INT nMaxLen) +{ + INT len; + + TRACE("(%p %p %d)\n", lpSrc, lpDest, nMaxLen); + + if (!lpDest && lpSrc) + return strlenW (lpSrc); + + if (nMaxLen == 0) + return 0; + + if (lpSrc == NULL) { + lpDest[0] = L'\0'; + return 0; + } + + len = strlenW (lpSrc); + if (len >= nMaxLen) + len = nMaxLen - 1; + + RtlMoveMemory (lpDest, lpSrc, len*sizeof(WCHAR)); + lpDest[len] = L'\0'; + + return len; +} + + +/************************************************************************** + * Str_SetPtrW [COMCTL32.236] + * + * See Str_SetPtrA. + */ +BOOL WINAPI Str_SetPtrW (LPWSTR *lppDest, LPCWSTR lpSrc) +{ + TRACE("(%p %p)\n", lppDest, lpSrc); + + if (lpSrc) { + INT len = strlenW (lpSrc) + 1; + LPWSTR ptr = ReAlloc (*lppDest, len * sizeof(WCHAR)); + if (!ptr) + return FALSE; + strcpyW (ptr, lpSrc); + *lppDest = ptr; + } + else { + if (*lppDest) { + Free (*lppDest); + *lppDest = NULL; + } + } + + return TRUE; +} + + +/************************************************************************** + * Str_GetPtrWtoA [internal] + * + * Converts a unicode string into a multi byte string + * + * PARAMS + * lpSrc [I] Pointer to the unicode source string + * lpDest [O] Pointer to caller supplied storage for the multi byte string + * nMaxLen [I] Size, in bytes, of the destination buffer + * + * RETURNS + * Length, in bytes, of the converted string. + */ + +INT Str_GetPtrWtoA (LPCWSTR lpSrc, LPSTR lpDest, INT nMaxLen) +{ + INT len; + + TRACE("(%s %p %d)\n", debugstr_w(lpSrc), lpDest, nMaxLen); + + if (!lpDest && lpSrc) + return WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL); + + if (nMaxLen == 0) + return 0; + + if (lpSrc == NULL) { + lpDest[0] = '\0'; + return 0; + } + + len = WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, 0, 0, NULL, NULL); + if (len >= nMaxLen) + len = nMaxLen - 1; + + WideCharToMultiByte(CP_ACP, 0, lpSrc, -1, lpDest, len, NULL, NULL); + lpDest[len] = '\0'; + + return len; +} + + +/************************************************************************** + * Str_SetPtrAtoW [internal] + * + * Converts a multi byte string to a unicode string. + * If the pointer to the destination buffer is NULL a buffer is allocated. + * If the destination buffer is too small to keep the converted multi byte + * string the destination buffer is reallocated. If the source pointer is + * NULL, the destination buffer is freed. + * + * PARAMS + * lppDest [I/O] pointer to a pointer to the destination buffer + * lpSrc [I] pointer to a multi byte string + * + * RETURNS + * TRUE: conversion successful + * FALSE: error + */ +BOOL Str_SetPtrAtoW (LPWSTR *lppDest, LPCSTR lpSrc) +{ + TRACE("(%p %s)\n", lppDest, lpSrc); + + if (lpSrc) { + INT len = MultiByteToWideChar(CP_ACP,0,lpSrc,-1,NULL,0); + LPWSTR ptr = ReAlloc (*lppDest, len*sizeof(WCHAR)); + + if (!ptr) + return FALSE; + MultiByteToWideChar(CP_ACP,0,lpSrc,-1,ptr,len); + *lppDest = ptr; + } + else { + if (*lppDest) { + Free (*lppDest); + *lppDest = NULL; + } + } + + return TRUE; +} + + +/************************************************************************** + * DSA_Create [COMCTL32.320] + * + * Creates a dynamic storage array + * + * PARAMS + * nSize [I] size of the array elements + * nGrow [I] number of elements by which the array grows when it is filled + * + * RETURNS + * Success: pointer to an array control structure. Use this like a handle. + * Failure: NULL + * + * NOTES + * The DSA_ functions can be used to create and manipulate arrays of + * fixed-size memory blocks. These arrays can store any kind of data + * (e.g. strings and icons). + */ +HDSA WINAPI DSA_Create (INT nSize, INT nGrow) +{ + HDSA hdsa; + + TRACE("(size=%d grow=%d)\n", nSize, nGrow); + + hdsa = Alloc (sizeof(*hdsa)); + if (hdsa) + { + hdsa->nItemCount = 0; + hdsa->pData = NULL; + hdsa->nMaxCount = 0; + hdsa->nItemSize = nSize; + hdsa->nGrow = max(1, nGrow); + } + + return hdsa; +} + + +/************************************************************************** + * DSA_Destroy [COMCTL32.321] + * + * Destroys a dynamic storage array + * + * PARAMS + * hdsa [I] pointer to the array control structure + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI DSA_Destroy (const HDSA hdsa) +{ + TRACE("(%p)\n", hdsa); + + if (!hdsa) + return FALSE; + + if (hdsa->pData && (!Free (hdsa->pData))) + return FALSE; + + return Free (hdsa); +} + + +/************************************************************************** + * DSA_GetItem [COMCTL32.322] + * + * Copies the specified item into a caller-supplied buffer. + * + * PARAMS + * hdsa [I] pointer to the array control structure + * nIndex [I] number of the Item to get + * pDest [O] destination buffer. Has to be >= dwElementSize. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI DSA_GetItem (const HDSA hdsa, INT nIndex, LPVOID pDest) +{ + LPVOID pSrc; + + TRACE("(%p %d %p)\n", hdsa, nIndex, pDest); + + if (!hdsa) + return FALSE; + if ((nIndex < 0) || (nIndex >= hdsa->nItemCount)) + return FALSE; + + pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); + memmove (pDest, pSrc, hdsa->nItemSize); + + return TRUE; +} + + +/************************************************************************** + * DSA_GetItemPtr [COMCTL32.323] + * + * Retrieves a pointer to the specified item. + * + * PARAMS + * hdsa [I] pointer to the array control structure + * nIndex [I] index of the desired item + * + * RETURNS + * Success: pointer to an item + * Failure: NULL + */ +LPVOID WINAPI DSA_GetItemPtr (const HDSA hdsa, INT nIndex) +{ + LPVOID pSrc; + + TRACE("(%p %d)\n", hdsa, nIndex); + + if (!hdsa) + return NULL; + if ((nIndex < 0) || (nIndex >= hdsa->nItemCount)) + return NULL; + + pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); + + TRACE("-- ret=%p\n", pSrc); + + return pSrc; +} + + +/************************************************************************** + * DSA_SetItem [COMCTL32.325] + * + * Sets the contents of an item in the array. + * + * PARAMS + * hdsa [I] pointer to the array control structure + * nIndex [I] index for the item + * pSrc [I] pointer to the new item data + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI DSA_SetItem (const HDSA hdsa, INT nIndex, LPVOID pSrc) +{ + INT nSize, nNewItems; + LPVOID pDest, lpTemp; + + TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc); + + if ((!hdsa) || nIndex < 0) + return FALSE; + + if (hdsa->nItemCount <= nIndex) { + /* within the old array */ + if (hdsa->nMaxCount > nIndex) { + /* within the allocated space, set a new boundary */ + hdsa->nItemCount = nIndex + 1; + } + else { + /* resize the block of memory */ + nNewItems = + hdsa->nGrow * ((INT)(((nIndex + 1) - 1) / hdsa->nGrow) + 1); + nSize = hdsa->nItemSize * nNewItems; + + lpTemp = ReAlloc (hdsa->pData, nSize); + if (!lpTemp) + return FALSE; + + hdsa->nMaxCount = nNewItems; + hdsa->nItemCount = nIndex + 1; + hdsa->pData = lpTemp; + } + } + + /* put the new entry in */ + pDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); + TRACE("-- move dest=%p src=%p size=%d\n", + pDest, pSrc, hdsa->nItemSize); + memmove (pDest, pSrc, hdsa->nItemSize); + + return TRUE; +} + + +/************************************************************************** + * DSA_InsertItem [COMCTL32.324] + * + * Inserts an item into the array at the specified index. + * + * PARAMS + * hdsa [I] pointer to the array control structure + * nIndex [I] index for the new item + * pSrc [I] pointer to the element + * + * RETURNS + * Success: position of the new item + * Failure: -1 + */ +INT WINAPI DSA_InsertItem (const HDSA hdsa, INT nIndex, LPVOID pSrc) +{ + INT nNewItems, nSize; + LPVOID lpTemp, lpDest; + + TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc); + + if ((!hdsa) || nIndex < 0) + return -1; + + /* when nIndex >= nItemCount then append */ + if (nIndex >= hdsa->nItemCount) + nIndex = hdsa->nItemCount; + + /* do we need to resize ? */ + if (hdsa->nItemCount >= hdsa->nMaxCount) { + nNewItems = hdsa->nMaxCount + hdsa->nGrow; + nSize = hdsa->nItemSize * nNewItems; + + lpTemp = ReAlloc (hdsa->pData, nSize); + if (!lpTemp) + return -1; + + hdsa->nMaxCount = nNewItems; + hdsa->pData = lpTemp; + } + + /* do we need to move elements ? */ + if (nIndex < hdsa->nItemCount) { + lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); + lpDest = (char *) lpTemp + hdsa->nItemSize; + nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize; + TRACE("-- move dest=%p src=%p size=%d\n", + lpDest, lpTemp, nSize); + memmove (lpDest, lpTemp, nSize); + } + + /* ok, we can put the new Item in */ + hdsa->nItemCount++; + lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); + TRACE("-- move dest=%p src=%p size=%d\n", + lpDest, pSrc, hdsa->nItemSize); + memmove (lpDest, pSrc, hdsa->nItemSize); + + return nIndex; +} + + +/************************************************************************** + * DSA_DeleteItem [COMCTL32.326] + * + * Deletes the specified item from the array. + * + * PARAMS + * hdsa [I] pointer to the array control structure + * nIndex [I] index for the element to delete + * + * RETURNS + * Success: number of the deleted element + * Failure: -1 + */ +INT WINAPI DSA_DeleteItem (const HDSA hdsa, INT nIndex) +{ + LPVOID lpDest,lpSrc; + INT nSize; + + TRACE("(%p %d)\n", hdsa, nIndex); + + if (!hdsa) + return -1; + if (nIndex < 0 || nIndex >= hdsa->nItemCount) + return -1; + + /* do we need to move ? */ + if (nIndex < hdsa->nItemCount - 1) { + lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); + lpSrc = (char *) lpDest + hdsa->nItemSize; + nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1); + TRACE("-- move dest=%p src=%p size=%d\n", + lpDest, lpSrc, nSize); + memmove (lpDest, lpSrc, nSize); + } + + hdsa->nItemCount--; + + /* free memory ? */ + if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) { + nSize = hdsa->nItemSize * hdsa->nItemCount; + + lpDest = ReAlloc (hdsa->pData, nSize); + if (!lpDest) + return -1; + + hdsa->nMaxCount = hdsa->nItemCount; + hdsa->pData = lpDest; + } + + return nIndex; +} + + +/************************************************************************** + * DSA_DeleteAllItems [COMCTL32.327] + * + * Removes all items and reinitializes the array. + * + * PARAMS + * hdsa [I] pointer to the array control structure + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI DSA_DeleteAllItems (const HDSA hdsa) +{ + TRACE("(%p)\n", hdsa); + + if (!hdsa) + return FALSE; + if (hdsa->pData && (!Free (hdsa->pData))) + return FALSE; + + hdsa->nItemCount = 0; + hdsa->pData = NULL; + hdsa->nMaxCount = 0; + + return TRUE; +} + + +/************************************************************************** + * DPA_Destroy [COMCTL32.329] + * + * Destroys a dynamic pointer array + * + * PARAMS + * hdpa [I] handle (pointer) to the pointer array + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI DPA_Destroy (const HDPA hdpa) +{ + TRACE("(%p)\n", hdpa); + + if (!hdpa) + return FALSE; + + if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs))) + return FALSE; + + return HeapFree (hdpa->hHeap, 0, hdpa); +} + + +/************************************************************************** + * DPA_Grow [COMCTL32.330] + * + * Sets the growth amount. + * + * PARAMS + * hdpa [I] handle (pointer) to the existing (source) pointer array + * nGrow [I] number of items by which the array grows when it's too small + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI DPA_Grow (const HDPA hdpa, INT nGrow) +{ + TRACE("(%p %d)\n", hdpa, nGrow); + + if (!hdpa) + return FALSE; + + hdpa->nGrow = max(8, nGrow); + + return TRUE; +} + + +/************************************************************************** + * DPA_Clone [COMCTL32.331] + * + * Copies a pointer array to an other one or creates a copy + * + * PARAMS + * hdpa [I] handle (pointer) to the existing (source) pointer array + * hdpaNew [O] handle (pointer) to the destination pointer array + * + * RETURNS + * Success: pointer to the destination pointer array. + * Failure: NULL + * + * NOTES + * - If the 'hdpaNew' is a NULL-Pointer, a copy of the source pointer + * array will be created and it's handle (pointer) is returned. + * - If 'hdpa' is a NULL-Pointer, the original implementation crashes, + * this implementation just returns NULL. + */ +HDPA WINAPI DPA_Clone (const HDPA hdpa, const HDPA hdpaNew) +{ + INT nNewItems, nSize; + HDPA hdpaTemp; + + if (!hdpa) + return NULL; + + TRACE("(%p %p)\n", hdpa, hdpaNew); + + if (!hdpaNew) { + /* create a new DPA */ + hdpaTemp = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, + sizeof(*hdpaTemp)); + hdpaTemp->hHeap = hdpa->hHeap; + hdpaTemp->nGrow = hdpa->nGrow; + } + else + hdpaTemp = hdpaNew; + + if (hdpaTemp->ptrs) { + /* remove old pointer array */ + HeapFree (hdpaTemp->hHeap, 0, hdpaTemp->ptrs); + hdpaTemp->ptrs = NULL; + hdpaTemp->nItemCount = 0; + hdpaTemp->nMaxCount = 0; + } + + /* create a new pointer array */ + nNewItems = hdpaTemp->nGrow * + ((INT)((hdpa->nItemCount - 1) / hdpaTemp->nGrow) + 1); + nSize = nNewItems * sizeof(LPVOID); + hdpaTemp->ptrs = HeapAlloc (hdpaTemp->hHeap, HEAP_ZERO_MEMORY, nSize); + hdpaTemp->nMaxCount = nNewItems; + + /* clone the pointer array */ + hdpaTemp->nItemCount = hdpa->nItemCount; + memmove (hdpaTemp->ptrs, hdpa->ptrs, + hdpaTemp->nItemCount * sizeof(LPVOID)); + + return hdpaTemp; +} + + +/************************************************************************** + * DPA_GetPtr [COMCTL32.332] + * + * Retrieves a pointer from a dynamic pointer array + * + * PARAMS + * hdpa [I] handle (pointer) to the pointer array + * nIndex [I] array index of the desired pointer + * + * RETURNS + * Success: pointer + * Failure: NULL + */ +LPVOID WINAPI DPA_GetPtr (const HDPA hdpa, INT nIndex) +{ + TRACE("(%p %d)\n", hdpa, nIndex); + + if (!hdpa) + return NULL; + if (!hdpa->ptrs) { + WARN("no pointer array.\n"); + return NULL; + } + if ((nIndex < 0) || (nIndex >= hdpa->nItemCount)) { + WARN("not enough pointers in array (%d vs %d).\n",nIndex,hdpa->nItemCount); + return NULL; + } + + TRACE("-- %p\n", hdpa->ptrs[nIndex]); + + return hdpa->ptrs[nIndex]; +} + + +/************************************************************************** + * DPA_GetPtrIndex [COMCTL32.333] + * + * Retrieves the index of the specified pointer + * + * PARAMS + * hdpa [I] handle (pointer) to the pointer array + * p [I] pointer + * + * RETURNS + * Success: index of the specified pointer + * Failure: -1 + */ +INT WINAPI DPA_GetPtrIndex (const HDPA hdpa, LPVOID p) +{ + INT i; + + if (!hdpa || !hdpa->ptrs) + return -1; + + for (i = 0; i < hdpa->nItemCount; i++) { + if (hdpa->ptrs[i] == p) + return i; + } + + return -1; +} + + +/************************************************************************** + * DPA_InsertPtr [COMCTL32.334] + * + * Inserts a pointer into a dynamic pointer array + * + * PARAMS + * hdpa [I] handle (pointer) to the array + * i [I] array index + * p [I] pointer to insert + * + * RETURNS + * Success: index of the inserted pointer + * Failure: -1 + */ +INT WINAPI DPA_InsertPtr (const HDPA hdpa, INT i, LPVOID p) +{ + TRACE("(%p %d %p)\n", hdpa, i, p); + + if (!hdpa || i < 0) return -1; + + if (i >= 0x7fff) + i = hdpa->nItemCount; + + if (i >= hdpa->nItemCount) + return DPA_SetPtr(hdpa, i, p) ? i : -1; + + /* create empty spot at the end */ + if (!DPA_SetPtr(hdpa, hdpa->nItemCount, 0)) return -1; + memmove (hdpa->ptrs + i + 1, hdpa->ptrs + i, (hdpa->nItemCount - i - 1) * sizeof(LPVOID)); + hdpa->ptrs[i] = p; + return i; +} + +/************************************************************************** + * DPA_SetPtr [COMCTL32.335] + * + * Sets a pointer in the pointer array + * + * PARAMS + * hdpa [I] handle (pointer) to the pointer array + * i [I] index of the pointer that will be set + * p [I] pointer to be set + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI DPA_SetPtr (const HDPA hdpa, INT i, LPVOID p) +{ + LPVOID *lpTemp; + + TRACE("(%p %d %p)\n", hdpa, i, p); + + if (!hdpa || i < 0 || i > 0x7fff) + return FALSE; + + if (hdpa->nItemCount <= i) { + /* within the old array */ + if (hdpa->nMaxCount <= i) { + /* resize the block of memory */ + INT nNewItems = + hdpa->nGrow * ((INT)(((i+1) - 1) / hdpa->nGrow) + 1); + INT nSize = nNewItems * sizeof(LPVOID); + + if (hdpa->ptrs) + lpTemp = HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, hdpa->ptrs, nSize); + else + lpTemp = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, nSize); + + if (!lpTemp) + return FALSE; + + hdpa->nMaxCount = nNewItems; + hdpa->ptrs = lpTemp; + } + hdpa->nItemCount = i+1; + } + + /* put the new entry in */ + hdpa->ptrs[i] = p; + + return TRUE; +} + + +/************************************************************************** + * DPA_DeletePtr [COMCTL32.336] + * + * Removes a pointer from the pointer array. + * + * PARAMS + * hdpa [I] handle (pointer) to the pointer array + * i [I] index of the pointer that will be deleted + * + * RETURNS + * Success: deleted pointer + * Failure: NULL + */ +LPVOID WINAPI DPA_DeletePtr (const HDPA hdpa, INT i) +{ + LPVOID *lpDest, *lpSrc, lpTemp = NULL; + INT nSize; + + TRACE("(%p %d)\n", hdpa, i); + + if ((!hdpa) || i < 0 || i >= hdpa->nItemCount) + return NULL; + + lpTemp = hdpa->ptrs[i]; + + /* do we need to move ?*/ + if (i < hdpa->nItemCount - 1) { + lpDest = hdpa->ptrs + i; + lpSrc = lpDest + 1; + nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID); + TRACE("-- move dest=%p src=%p size=%x\n", + lpDest, lpSrc, nSize); + memmove (lpDest, lpSrc, nSize); + } + + hdpa->nItemCount --; + + /* free memory ?*/ + if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) { + INT nNewItems = max(hdpa->nGrow * 2, hdpa->nItemCount); + nSize = nNewItems * sizeof(LPVOID); + lpDest = HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, + hdpa->ptrs, nSize); + if (!lpDest) + return NULL; + + hdpa->nMaxCount = nNewItems; + hdpa->ptrs = (LPVOID*)lpDest; + } + + return lpTemp; +} + + +/************************************************************************** + * DPA_DeleteAllPtrs [COMCTL32.337] + * + * Removes all pointers and reinitializes the array. + * + * PARAMS + * hdpa [I] handle (pointer) to the pointer array + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI DPA_DeleteAllPtrs (const HDPA hdpa) +{ + TRACE("(%p)\n", hdpa); + + if (!hdpa) + return FALSE; + + if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs))) + return FALSE; + + hdpa->nItemCount = 0; + hdpa->nMaxCount = hdpa->nGrow * 2; + hdpa->ptrs = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, + hdpa->nMaxCount * sizeof(LPVOID)); + + return TRUE; +} + + +/************************************************************************** + * DPA_QuickSort [Internal] + * + * Ordinary quicksort (used by DPA_Sort). + * + * PARAMS + * lpPtrs [I] pointer to the pointer array + * l [I] index of the "left border" of the partition + * r [I] index of the "right border" of the partition + * pfnCompare [I] pointer to the compare function + * lParam [I] user defined value (3rd parameter in compare function) + * + * RETURNS + * NONE + */ +static VOID DPA_QuickSort (LPVOID *lpPtrs, INT l, INT r, + PFNDPACOMPARE pfnCompare, LPARAM lParam) +{ + INT m; + LPVOID t; + + TRACE("l=%i r=%i\n", l, r); + + if (l==r) /* one element is always sorted */ + return; + if (r0) + { + t = lpPtrs[m+1]; + memmove(&lpPtrs[l+1],&lpPtrs[l],(m-l+1)*sizeof(lpPtrs[l])); + lpPtrs[l] = t; + + m++; + } + l++; + } +} + + +/************************************************************************** + * DPA_Sort [COMCTL32.338] + * + * Sorts a pointer array using a user defined compare function + * + * PARAMS + * hdpa [I] handle (pointer) to the pointer array + * pfnCompare [I] pointer to the compare function + * lParam [I] user defined value (3rd parameter of compare function) + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI DPA_Sort (const HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam) +{ + if (!hdpa || !pfnCompare) + return FALSE; + + TRACE("(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam); + + if ((hdpa->nItemCount > 1) && (hdpa->ptrs)) + DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1, + pfnCompare, lParam); + + return TRUE; +} + + +/************************************************************************** + * DPA_Search [COMCTL32.339] + * + * Searches a pointer array for a specified pointer + * + * PARAMS + * hdpa [I] handle (pointer) to the pointer array + * pFind [I] pointer to search for + * nStart [I] start index + * pfnCompare [I] pointer to the compare function + * lParam [I] user defined value (3rd parameter of compare function) + * uOptions [I] search options + * + * RETURNS + * Success: index of the pointer in the array. + * Failure: -1 + * + * NOTES + * Binary search taken from R.Sedgewick "Algorithms in C"! + * Function is NOT tested! + * If something goes wrong, blame HIM not ME! (Eric Kohl) + */ +INT WINAPI DPA_Search (const HDPA hdpa, LPVOID pFind, INT nStart, + PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions) +{ + if (!hdpa || !pfnCompare || !pFind) + return -1; + + TRACE("(%p %p %d %p 0x%08lx 0x%08x)\n", + hdpa, pFind, nStart, pfnCompare, lParam, uOptions); + + if (uOptions & DPAS_SORTED) { + /* array is sorted --> use binary search */ + INT l, r, x, n; + LPVOID *lpPtr; + + TRACE("binary search\n"); + + l = (nStart == -1) ? 0 : nStart; + r = hdpa->nItemCount - 1; + lpPtr = hdpa->ptrs; + while (r >= l) { + x = (l + r) / 2; + n = (pfnCompare)(pFind, lpPtr[x], lParam); + if (n < 0) + r = x - 1; + else + l = x + 1; + if (n == 0) { + TRACE("-- ret=%d\n", n); + return n; + } + } + + if (uOptions & DPAS_INSERTBEFORE) { + if (r == -1) r = 0; + TRACE("-- ret=%d\n", r); + return r; + } + + if (uOptions & DPAS_INSERTAFTER) { + TRACE("-- ret=%d\n", l); + return l; + } + } + else { + /* array is not sorted --> use linear search */ + LPVOID *lpPtr; + INT nIndex; + + TRACE("linear search\n"); + + nIndex = (nStart == -1)? 0 : nStart; + lpPtr = hdpa->ptrs; + for (; nIndex < hdpa->nItemCount; nIndex++) { + if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0) { + TRACE("-- ret=%d\n", nIndex); + return nIndex; + } + } + } + + TRACE("-- not found: ret=-1\n"); + return -1; +} + + +/************************************************************************** + * DPA_CreateEx [COMCTL32.340] + * + * Creates a dynamic pointer array using the specified size and heap. + * + * PARAMS + * nGrow [I] number of items by which the array grows when it is filled + * hHeap [I] handle to the heap where the array is stored + * + * RETURNS + * Success: handle (pointer) to the pointer array. + * Failure: NULL + * + * NOTES + * The DPA_ functions can be used to create and manipulate arrays of + * pointers. + */ +HDPA WINAPI DPA_CreateEx (INT nGrow, HANDLE hHeap) +{ + HDPA hdpa; + + TRACE("(%d %p)\n", nGrow, hHeap); + + if (hHeap) + hdpa = HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(*hdpa)); + else + hdpa = Alloc (sizeof(*hdpa)); + + if (hdpa) { + hdpa->nGrow = max(8, nGrow); + hdpa->hHeap = hHeap ? hHeap : GetProcessHeap(); + hdpa->nMaxCount = hdpa->nGrow * 2; + hdpa->ptrs = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, + hdpa->nMaxCount * sizeof(LPVOID)); + } + + TRACE("-- %p\n", hdpa); + + return hdpa; +} + + +/************************************************************************** + * DPA_Create [COMCTL32.328] + * + * Creates a dynamic pointer array. + * + * PARAMS + * nGrow [I] number of items by which the array grows when it is filled + * + * RETURNS + * Success: handle (pointer) to the pointer array. + * Failure: NULL + * + * NOTES + * The DPA_ functions can be used to create and manipulate arrays of + * pointers. + */ +HDPA WINAPI DPA_Create (INT nGrow) +{ + return DPA_CreateEx( nGrow, 0 ); +} + + +/************************************************************************** + * Notification functions + */ + +typedef struct tagNOTIFYDATA +{ + HWND hwndFrom; + HWND hwndTo; + DWORD dwParam3; + DWORD dwParam4; + DWORD dwParam5; + DWORD dwParam6; +} NOTIFYDATA, *LPNOTIFYDATA; + + +/************************************************************************** + * DoNotify [Internal] + */ + +static LRESULT DoNotify (LPNOTIFYDATA lpNotify, UINT uCode, LPNMHDR lpHdr) +{ + NMHDR nmhdr; + LPNMHDR lpNmh = NULL; + UINT idFrom = 0; + + TRACE("(%p %p %d %p 0x%08lx)\n", + lpNotify->hwndFrom, lpNotify->hwndTo, uCode, lpHdr, + lpNotify->dwParam5); + + if (!lpNotify->hwndTo) + return 0; + + if (lpNotify->hwndFrom == (HWND)-1) { + lpNmh = lpHdr; + idFrom = lpHdr->idFrom; + } + else { + if (lpNotify->hwndFrom) + idFrom = GetDlgCtrlID (lpNotify->hwndFrom); + + lpNmh = (lpHdr) ? lpHdr : &nmhdr; + + lpNmh->hwndFrom = lpNotify->hwndFrom; + lpNmh->idFrom = idFrom; + lpNmh->code = uCode; + } + + return SendMessageW (lpNotify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh); +} + + +/************************************************************************** + * SendNotify [COMCTL32.341] + * + * Sends a WM_NOTIFY message to the specified window. + * + * PARAMS + * hwndTo [I] Window to receive the message + * hwndFrom [I] Window that the message is from (see notes) + * uCode [I] Notification code + * lpHdr [I] The NMHDR and any additional information to send or NULL + * + * RETURNS + * Success: return value from notification + * Failure: 0 + * + * NOTES + * If hwndFrom is -1 then the identifier of the control sending the + * message is taken from the NMHDR structure. + * If hwndFrom is not -1 then lpHdr can be NULL. + */ +LRESULT WINAPI SendNotify (HWND hwndTo, HWND hwndFrom, UINT uCode, LPNMHDR lpHdr) +{ + NOTIFYDATA notify; + + TRACE("(%p %p %d %p)\n", + hwndTo, hwndFrom, uCode, lpHdr); + + notify.hwndFrom = hwndFrom; + notify.hwndTo = hwndTo; + notify.dwParam5 = 0; + notify.dwParam6 = 0; + + return DoNotify (¬ify, uCode, lpHdr); +} + + +/************************************************************************** + * SendNotifyEx [COMCTL32.342] + * + * Sends a WM_NOTIFY message to the specified window. + * + * PARAMS + * hwndFrom [I] Window to receive the message + * hwndTo [I] Window that the message is from + * uCode [I] Notification code + * lpHdr [I] The NMHDR and any additional information to send or NULL + * dwParam5 [I] Unknown + * + * RETURNS + * Success: return value from notification + * Failure: 0 + * + * NOTES + * If hwndFrom is -1 then the identifier of the control sending the + * message is taken from the NMHDR structure. + * If hwndFrom is not -1 then lpHdr can be NULL. + */ +LRESULT WINAPI SendNotifyEx (HWND hwndTo, HWND hwndFrom, UINT uCode, + LPNMHDR lpHdr, DWORD dwParam5) +{ + NOTIFYDATA notify; + HWND hwndNotify; + + TRACE("(%p %p %d %p 0x%08lx)\n", + hwndFrom, hwndTo, uCode, lpHdr, dwParam5); + + hwndNotify = hwndTo; + if (!hwndTo) { + if (IsWindow (hwndFrom)) { + hwndNotify = GetParent (hwndFrom); + if (!hwndNotify) + return 0; + } + } + + notify.hwndFrom = hwndFrom; + notify.hwndTo = hwndNotify; + notify.dwParam5 = dwParam5; + notify.dwParam6 = 0; + + return DoNotify (¬ify, uCode, lpHdr); +} + + + + +/************************************************************************** + * DPA_EnumCallback [COMCTL32.385] + * + * Enumerates all items in a dynamic pointer array. + * + * PARAMS + * hdpa [I] handle to the dynamic pointer array + * enumProc [I] + * lParam [I] + * + * RETURNS + * none + */ +VOID WINAPI DPA_EnumCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc, + LPVOID lParam) +{ + INT i; + + TRACE("(%p %p %p)\n", hdpa, enumProc, lParam); + + if (!hdpa) + return; + if (hdpa->nItemCount <= 0) + return; + + for (i = 0; i < hdpa->nItemCount; i++) { + if ((enumProc)(hdpa->ptrs[i], lParam) == 0) + return; + } + + return; +} + + +/************************************************************************** + * DPA_DestroyCallback [COMCTL32.386] + * + * Enumerates all items in a dynamic pointer array and destroys it. + * + * PARAMS + * hdpa [I] handle to the dynamic pointer array + * enumProc [I] + * lParam [I] + * + * RETURNS + * none + */ +void WINAPI DPA_DestroyCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc, + LPVOID lParam) +{ + TRACE("(%p %p %p)\n", hdpa, enumProc, lParam); + + DPA_EnumCallback (hdpa, enumProc, lParam); + DPA_Destroy (hdpa); +} + + +/************************************************************************** + * DSA_EnumCallback [COMCTL32.387] + * + * Enumerates all items in a dynamic storage array. + * + * PARAMS + * hdsa [I] handle to the dynamic storage array + * enumProc [I] + * lParam [I] + * + * RETURNS + * none + */ +VOID WINAPI DSA_EnumCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc, + LPVOID lParam) +{ + INT i; + + TRACE("(%p %p %p)\n", hdsa, enumProc, lParam); + + if (!hdsa) + return; + if (hdsa->nItemCount <= 0) + return; + + for (i = 0; i < hdsa->nItemCount; i++) { + LPVOID lpItem = DSA_GetItemPtr (hdsa, i); + if ((enumProc)(lpItem, lParam) == 0) + return; + } + + return; +} + + +/************************************************************************** + * DSA_DestroyCallback [COMCTL32.388] + * + * Enumerates all items in a dynamic storage array and destroys it. + * + * PARAMS + * hdsa [I] handle to the dynamic storage array + * enumProc [I] + * lParam [I] + * + * RETURNS + * none + */ +void WINAPI DSA_DestroyCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc, + LPVOID lParam) +{ + TRACE("(%p %p %p)\n", hdsa, enumProc, lParam); + + DSA_EnumCallback (hdsa, enumProc, lParam); + DSA_Destroy (hdsa); +} diff --git a/reactos/lib/comctl32/commctrl.c b/reactos/lib/comctl32/commctrl.c index 0d315e97173..4c1ea8a4b63 100644 --- a/reactos/lib/comctl32/commctrl.c +++ b/reactos/lib/comctl32/commctrl.c @@ -1,1508 +1,1508 @@ -/* - * Common controls functions - * - * Copyright 1997 Dimitrie O. Paun - * Copyright 1998,2000 Eric Kohl - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTES - * - * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on Oct. 21, 2002, by Christian Neumair. - * - * Unless otherwise noted, we believe this code to be complete, as per - * the specification mentioned above. - * If you discover missing features, or bugs, please note them below. - * - * TODO - * -- implement GetMUILanguage + InitMUILanguage - * -- LibMain => DLLMain ("DLLMain takes over the functionality of both the - * LibMain and the WEP function.", MSDN) - * -- finish NOTES for MenuHelp, GetEffectiveClientRect and GetStatusTextW - * -- FIXMEs + BUGS (search for them) - * - * Control Classes - * -- ICC_ANIMATE_CLASS - * -- ICC_BAR_CLASSES - * -- ICC_COOL_CLASSES - * -- ICC_DATE_CLASSES - * -- ICC_HOTKEY_CLASS - * -- ICC_INTERNET_CLASSES - * -- ICC_LINK_CLASS - * -- ICC_LISTVIEW_CLASSES - * -- ICC_NATIVEFNTCTL_CLASS - * -- ICC_PAGESCROLLER_CLASS - * -- ICC_PROGRESS_CLASS - * -- ICC_STANDARD_CLASSES (not yet implemented) - * -- ICC_TAB_CLASSES - * -- ICC_TREEVIEW_CLASSES - * -- ICC_UPDOWN_CLASS - * -- ICC_USEREX_CLASSES - * -- ICC_WIN95_CLASSES - */ - -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "winerror.h" -#include "winreg.h" -#define NO_SHLWAPI_STREAM -#include "shlwapi.h" -#include "comctl32.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(commctrl); - -LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - -LPWSTR COMCTL32_wSubclass = NULL; -HMODULE COMCTL32_hModule = 0; -LANGID COMCTL32_uiLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL); -HBRUSH COMCTL32_hPattern55AABrush = NULL; -COMCTL32_SysColor comctl32_color; - -static HBITMAP COMCTL32_hPattern55AABitmap = NULL; - -static const WORD wPattern55AA[] = -{ - 0x5555, 0xaaaa, 0x5555, 0xaaaa, - 0x5555, 0xaaaa, 0x5555, 0xaaaa -}; - -static const WCHAR strCC32SubclassInfo[] = { - 'C','C','3','2','S','u','b','c','l','a','s','s','I','n','f','o',0 -}; - -/*********************************************************************** - * DllMain [Internal] - * - * Initializes the internal 'COMCTL32.DLL'. - * - * PARAMS - * hinstDLL [I] handle to the 'dlls' instance - * fdwReason [I] - * lpvReserved [I] reserverd, must be NULL - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ - -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - TRACE("%p,%lx,%p\n", hinstDLL, fdwReason, lpvReserved); - - switch (fdwReason) { - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(hinstDLL); - - COMCTL32_hModule = (HMODULE)hinstDLL; - - /* add global subclassing atom (used by 'tooltip' and 'updown') */ - COMCTL32_wSubclass = (LPWSTR)(DWORD)GlobalAddAtomW (strCC32SubclassInfo); - TRACE("Subclassing atom added: %p\n", COMCTL32_wSubclass); - - /* create local pattern brush */ - COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA); - COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap); - - /* Get all the colors at DLL load */ - COMCTL32_RefreshSysColors(); - - /* register all Win95 common control classes */ - ANIMATE_Register (); - FLATSB_Register (); - HEADER_Register (); - HOTKEY_Register (); - LISTVIEW_Register (); - PROGRESS_Register (); - STATUS_Register (); - SYSLINK_Register (); - TAB_Register (); - TOOLBAR_Register (); - TOOLTIPS_Register (); - TRACKBAR_Register (); - TREEVIEW_Register (); - UPDOWN_Register (); - break; - - case DLL_PROCESS_DETACH: - /* unregister all common control classes */ - ANIMATE_Unregister (); - COMBOEX_Unregister (); - DATETIME_Unregister (); - FLATSB_Unregister (); - HEADER_Unregister (); - HOTKEY_Unregister (); - IPADDRESS_Unregister (); - LISTVIEW_Unregister (); - MONTHCAL_Unregister (); - NATIVEFONT_Unregister (); - PAGER_Unregister (); - PROGRESS_Unregister (); - REBAR_Unregister (); - STATUS_Unregister (); - SYSLINK_Unregister (); - TAB_Unregister (); - TOOLBAR_Unregister (); - TOOLTIPS_Unregister (); - TRACKBAR_Unregister (); - TREEVIEW_Unregister (); - UPDOWN_Unregister (); - - /* delete local pattern brush */ - DeleteObject (COMCTL32_hPattern55AABrush); - COMCTL32_hPattern55AABrush = NULL; - DeleteObject (COMCTL32_hPattern55AABitmap); - COMCTL32_hPattern55AABitmap = NULL; - - /* delete global subclassing atom */ - GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass)); - TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass); - COMCTL32_wSubclass = NULL; - break; - } - - return TRUE; -} - - -/*********************************************************************** - * MenuHelp [COMCTL32.2] - * - * Handles the setting of status bar help messages when the user - * selects menu items. - * - * PARAMS - * uMsg [I] message (WM_MENUSELECT) (see NOTES) - * wParam [I] wParam of the message uMsg - * lParam [I] lParam of the message uMsg - * hMainMenu [I] handle to the application's main menu - * hInst [I] handle to the module that contains string resources - * hwndStatus [I] handle to the status bar window - * lpwIDs [I] pointer to an array of integers (see NOTES) - * - * RETURNS - * No return value - * - * NOTES - * The official documentation is incomplete! - * This is the correct documentation: - * - * uMsg: - * MenuHelp() does NOT handle WM_COMMAND messages! It only handles - * WM_MENUSELECT messages. - * - * lpwIDs: - * (will be written ...) - */ - -VOID WINAPI -MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu, - HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs) -{ - UINT uMenuID = 0; - - if (!IsWindow (hwndStatus)) - return; - - switch (uMsg) { - case WM_MENUSELECT: - TRACE("WM_MENUSELECT wParam=0x%X lParam=0x%lX\n", - wParam, lParam); - - if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) { - /* menu was closed */ - TRACE("menu was closed!\n"); - SendMessageW (hwndStatus, SB_SIMPLE, FALSE, 0); - } - else { - /* menu item was selected */ - if (HIWORD(wParam) & MF_POPUP) - uMenuID = (UINT)*(lpwIDs+1); - else - uMenuID = (UINT)LOWORD(wParam); - TRACE("uMenuID = %u\n", uMenuID); - - if (uMenuID) { - WCHAR szText[256]; - - if (!LoadStringW (hInst, uMenuID, szText, sizeof(szText)/sizeof(szText[0]))) - szText[0] = '\0'; - - SendMessageW (hwndStatus, SB_SETTEXTW, - 255 | SBT_NOBORDERS, (LPARAM)szText); - SendMessageW (hwndStatus, SB_SIMPLE, TRUE, 0); - } - } - break; - - case WM_COMMAND : - TRACE("WM_COMMAND wParam=0x%X 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; - } -} - - -/*********************************************************************** - * ShowHideMenuCtl [COMCTL32.3] - * - * Shows or hides controls and updates the corresponding menu item. - * - * PARAMS - * hwnd [I] handle to the client window. - * uFlags [I] menu command id. - * lpInfo [I] pointer to an array of integers. (See NOTES.) - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * NOTES - * The official documentation is incomplete! - * This is the correct documentation: - * - * hwnd - * Handle to the window that contains the menu and controls. - * - * uFlags - * Identifier of the menu item to receive or lose a check mark. - * - * lpInfo - * The array of integers contains pairs of values. BOTH values of - * the first pair must be the handles to the application's main menu. - * Each subsequent pair consists of a menu id and control id. - */ - -BOOL WINAPI -ShowHideMenuCtl (HWND hwnd, UINT uFlags, LPINT lpInfo) -{ - LPINT lpMenuId; - - TRACE("%p, %x, %p\n", hwnd, uFlags, lpInfo); - - if (lpInfo == NULL) - return FALSE; - - if (!(lpInfo[0]) || !(lpInfo[1])) - return FALSE; - - /* search for control */ - lpMenuId = &lpInfo[2]; - while (*lpMenuId != uFlags) - lpMenuId += 2; - - if (GetMenuState ((HMENU)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) { - /* uncheck menu item */ - CheckMenuItem ((HMENU)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED); - - /* hide control */ - lpMenuId++; - SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0, - SWP_HIDEWINDOW); - } - else { - /* check menu item */ - CheckMenuItem ((HMENU)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED); - - /* show control */ - lpMenuId++; - SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0, - SWP_SHOWWINDOW); - } - - return TRUE; -} - - -/*********************************************************************** - * GetEffectiveClientRect [COMCTL32.4] - * - * Calculates the coordinates of a rectangle in the client area. - * - * PARAMS - * hwnd [I] handle to the client window. - * lpRect [O] pointer to the rectangle of the client window - * lpInfo [I] pointer to an array of integers (see NOTES) - * - * RETURNS - * No return value. - * - * NOTES - * The official documentation is incomplete! - * This is the correct documentation: - * - * lpInfo - * (will be written ...) - */ - -VOID WINAPI -GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, LPINT lpInfo) -{ - RECT rcCtrl; - INT *lpRun; - HWND hwndCtrl; - - TRACE("(0x%08lx 0x%08lx 0x%08lx)\n", - (DWORD)hwnd, (DWORD)lpRect, (DWORD)lpInfo); - - GetClientRect (hwnd, lpRect); - lpRun = lpInfo; - - do { - lpRun += 2; - if (*lpRun == 0) - return; - lpRun++; - hwndCtrl = GetDlgItem (hwnd, *lpRun); - if (GetWindowLongW (hwndCtrl, GWL_STYLE) & WS_VISIBLE) { - TRACE("control id 0x%x\n", *lpRun); - GetWindowRect (hwndCtrl, &rcCtrl); - MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2); - SubtractRect (lpRect, lpRect, &rcCtrl); - } - lpRun++; - } while (*lpRun); -} - - -/*********************************************************************** - * DrawStatusTextW [COMCTL32.@] - * - * Draws text with borders, like in a status bar. - * - * PARAMS - * hdc [I] handle to the window's display context - * lprc [I] pointer to a rectangle - * text [I] pointer to the text - * style [I] drawing style - * - * RETURNS - * No return value. - * - * NOTES - * The style variable can have one of the following values: - * (will be written ...) - */ - -void WINAPI DrawStatusTextW (HDC hdc, LPRECT lprc, LPCWSTR text, UINT style) -{ - RECT r = *lprc; - UINT border = BDR_SUNKENOUTER; - - if (style & SBT_POPOUT) - border = BDR_RAISEDOUTER; - else if (style & SBT_NOBORDERS) - border = 0; - - DrawEdge (hdc, &r, border, BF_RECT|BF_ADJUST); - - /* now draw text */ - if (text) { - int oldbkmode = SetBkMode (hdc, TRANSPARENT); - UINT align = DT_LEFT; - if (*text == L'\t') { - text++; - align = DT_CENTER; - if (*text == L'\t') { - text++; - align = DT_RIGHT; - } - } - r.left += 3; - if (style & SBT_RTLREADING) - FIXME("Unsupported RTL style!\n"); - DrawTextW (hdc, text, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX); - SetBkMode(hdc, oldbkmode); - } -} - - -/*********************************************************************** - * DrawStatusText [COMCTL32.@] - * DrawStatusTextA [COMCTL32.5] - * - * Draws text with borders, like in a status bar. - * - * PARAMS - * hdc [I] handle to the window's display context - * lprc [I] pointer to a rectangle - * text [I] pointer to the text - * style [I] drawing style - * - * RETURNS - * No return value. - */ - -void WINAPI DrawStatusTextA (HDC hdc, LPRECT lprc, LPCSTR text, UINT style) -{ - INT len; - LPWSTR textW = NULL; - - if ( text ) { - if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) { - if ( (textW = Alloc( len * sizeof(WCHAR) )) ) - MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len ); - } - } - DrawStatusTextW( hdc, lprc, textW, style ); - Free( textW ); -} - - -/*********************************************************************** - * CreateStatusWindow [COMCTL32.@] - * CreateStatusWindowA [COMCTL32.6] - * - * Creates a status bar - * - * PARAMS - * style [I] window style - * text [I] pointer to the window text - * parent [I] handle to the parent window - * wid [I] control id of the status bar - * - * RETURNS - * Success: handle to the status window - * Failure: 0 - */ - -HWND WINAPI -CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid) -{ - return CreateWindowA(STATUSCLASSNAMEA, text, style, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - parent, (HMENU)wid, 0, 0); -} - - -/*********************************************************************** - * CreateStatusWindowW [COMCTL32.@] - * - * Creates a status bar control - * - * PARAMS - * style [I] window style - * text [I] pointer to the window text - * parent [I] handle to the parent window - * wid [I] control id of the status bar - * - * RETURNS - * Success: handle to the status window - * Failure: 0 - */ - -HWND WINAPI -CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid) -{ - return CreateWindowW(STATUSCLASSNAMEW, text, style, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - parent, (HMENU)wid, 0, 0); -} - - -/*********************************************************************** - * CreateUpDownControl [COMCTL32.16] - * - * Creates an up-down control - * - * PARAMS - * style [I] window styles - * x [I] horizontal position of the control - * y [I] vertical position of the control - * cx [I] with of the control - * cy [I] height of the control - * parent [I] handle to the parent window - * id [I] the control's identifier - * inst [I] handle to the application's module instance - * buddy [I] handle to the buddy window, can be NULL - * maxVal [I] upper limit of the control - * minVal [I] lower limit of the control - * curVal [I] current value of the control - * - * RETURNS - * Success: handle to the updown control - * Failure: 0 - */ - -HWND WINAPI -CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy, - HWND parent, INT id, HINSTANCE inst, - HWND buddy, INT maxVal, INT minVal, INT curVal) -{ - HWND hUD = - CreateWindowW (UPDOWN_CLASSW, 0, style, x, y, cx, cy, - parent, (HMENU)id, inst, 0); - if (hUD) { - SendMessageW (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0); - SendMessageW (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal)); - SendMessageW (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0)); - } - - return hUD; -} - - -/*********************************************************************** - * InitCommonControls [COMCTL32.17] - * - * Registers the common controls. - * - * PARAMS - * No parameters. - * - * RETURNS - * No return values. - * - * NOTES - * This function is just a dummy. - * The Win95 controls are registered at the DLL's initialization. - * To register other controls InitCommonControlsEx() must be used. - */ - -VOID WINAPI -InitCommonControls (void) -{ -} - - -/*********************************************************************** - * InitCommonControlsEx [COMCTL32.@] - * - * Registers the common controls. - * - * PARAMS - * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure. - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * NOTES - * Only the additional common controls are registered by this function. - * The Win95 controls are registered at the DLL's initialization. - * - * FIXME - * implement the following control classes: - * ICC_LINK_CLASS - * ICC_STANDARD_CLASSES - */ - -BOOL WINAPI -InitCommonControlsEx (LPINITCOMMONCONTROLSEX lpInitCtrls) -{ - INT cCount; - DWORD dwMask; - - if (!lpInitCtrls) - return FALSE; - if (lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX)) - return FALSE; - - TRACE("(0x%08lx)\n", lpInitCtrls->dwICC); - - for (cCount = 0; cCount < 32; cCount++) { - dwMask = 1 << cCount; - if (!(lpInitCtrls->dwICC & dwMask)) - continue; - - switch (lpInitCtrls->dwICC & dwMask) { - /* dummy initialization */ - case ICC_ANIMATE_CLASS: - case ICC_BAR_CLASSES: - case ICC_LISTVIEW_CLASSES: - case ICC_TREEVIEW_CLASSES: - case ICC_TAB_CLASSES: - case ICC_UPDOWN_CLASS: - case ICC_PROGRESS_CLASS: - case ICC_HOTKEY_CLASS: - break; - - /* advanced classes - not included in Win95 */ - case ICC_DATE_CLASSES: - MONTHCAL_Register (); - DATETIME_Register (); - break; - - case ICC_USEREX_CLASSES: - COMBOEX_Register (); - break; - - case ICC_COOL_CLASSES: - REBAR_Register (); - break; - - case ICC_INTERNET_CLASSES: - IPADDRESS_Register (); - break; - - case ICC_PAGESCROLLER_CLASS: - PAGER_Register (); - break; - - case ICC_NATIVEFNTCTL_CLASS: - NATIVEFONT_Register (); - break; - - case ICC_LINK_CLASS: - SYSLINK_Register (); - break; - - default: - FIXME("Unknown class! dwICC=0x%lX\n", dwMask); - break; - } - } - - return TRUE; -} - - -/*********************************************************************** - * CreateToolbarEx [COMCTL32.@] - * - * Creates a toolbar window. - * - * PARAMS - * hwnd - * style - * wID - * nBitmaps - * hBMInst - * wBMID - * lpButtons - * iNumButtons - * dxButton - * dyButton - * dxBitmap - * dyBitmap - * uStructSize - * - * RETURNS - * Success: handle to the tool bar control - * Failure: 0 - */ - -HWND WINAPI -CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps, - HINSTANCE hBMInst, UINT wBMID, LPCTBBUTTON lpButtons, - INT iNumButtons, INT dxButton, INT dyButton, - INT dxBitmap, INT dyBitmap, UINT uStructSize) -{ - HWND hwndTB; - - hwndTB = - CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style|WS_CHILD, 0,0,100,30, - hwnd, (HMENU)wID, COMCTL32_hModule, NULL); - if(hwndTB) { - TBADDBITMAP tbab; - - SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM)uStructSize, 0); - - /* set bitmap and button size */ - /*If CreateToolbarEx receives 0, windows sets default values*/ - if (dxBitmap <= 0) - dxBitmap = 16; - if (dyBitmap <= 0) - dyBitmap = 15; - SendMessageW (hwndTB, TB_SETBITMAPSIZE, 0, - MAKELPARAM((WORD)dxBitmap, (WORD)dyBitmap)); - - if (dxButton <= 0) - dxButton = 24; - if (dyButton <= 0) - dyButton = 22; - SendMessageW (hwndTB, TB_SETBUTTONSIZE, 0, - MAKELPARAM((WORD)dxButton, (WORD)dyButton)); - - - /* add bitmaps */ - if (nBitmaps > 0) - { - tbab.hInst = hBMInst; - tbab.nID = wBMID; - - SendMessageW (hwndTB, TB_ADDBITMAP, (WPARAM)nBitmaps, (LPARAM)&tbab); - } - /* add buttons */ - if(iNumButtons > 0) - SendMessageW (hwndTB, TB_ADDBUTTONSW, - (WPARAM)iNumButtons, (LPARAM)lpButtons); - } - - return hwndTB; -} - - -/*********************************************************************** - * CreateMappedBitmap [COMCTL32.8] - * - * Loads a bitmap resource using a colour map. - * - * PARAMS - * hInstance [I] Handle to the module containing the bitmap. - * idBitmap [I] The bitmap resource ID. - * wFlags [I] CMB_MASKED for using bitmap as a mask or 0 for normal. - * lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours). - * iNumMaps [I] Number of COLORMAP's pointed to by lpColorMap. - * - * RETURNS - * Success: handle to the new bitmap - * Failure: 0 - */ - -HBITMAP WINAPI -CreateMappedBitmap (HINSTANCE hInstance, INT idBitmap, UINT wFlags, - LPCOLORMAP lpColorMap, INT iNumMaps) -{ - HGLOBAL hglb; - HRSRC hRsrc; - LPBITMAPINFOHEADER lpBitmap, 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 = (LPCOLORMAP)internalColorMap; - } - - hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP); - if (hRsrc == 0) - return 0; - hglb = LoadResource (hInstance, hRsrc); - if (hglb == 0) - return 0; - lpBitmap = (LPBITMAPINFOHEADER)LockResource (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 + nColorTableSize * sizeof(RGBQUAD); - lpBitmapInfo = (LPBITMAPINFOHEADER)GlobalAlloc (GMEM_FIXED, nSize); - if (lpBitmapInfo == NULL) - return 0; - RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize); - - pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo)+(UINT)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 = (INT)lpBitmapInfo->biWidth; - nHeight = (INT)lpBitmapInfo->biHeight; - hdcScreen = GetDC (NULL); - hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight); - if (hbm) { - HDC hdcDst = CreateCompatibleDC (hdcScreen); - HBITMAP hbmOld = SelectObject (hdcDst, hbm); - LPBYTE lpBits = (LPBYTE)(lpBitmap + 1); - lpBits += nColorTableSize * sizeof(RGBQUAD); - 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 ((HGLOBAL)lpBitmapInfo); - FreeResource (hglb); - - return hbm; -} - - -/*********************************************************************** - * CreateToolbar [COMCTL32.7] - * - * Creates a toolbar control. - * - * PARAMS - * hwnd - * style - * wID - * nBitmaps - * hBMInst - * wBMID - * lpButtons - * iNumButtons - * - * RETURNS - * Success: handle to the tool bar control - * Failure: 0 - * - * NOTES - * Do not use this functions anymore. Use CreateToolbarEx instead. - */ - -HWND WINAPI -CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps, - HINSTANCE hBMInst, UINT wBMID, - LPCTBBUTTON lpButtons,INT iNumButtons) -{ - return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps, - hBMInst, wBMID, lpButtons, - iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData)); -} - - -/*********************************************************************** - * DllGetVersion [COMCTL32.@] - * - * Retrieves version information of the 'COMCTL32.DLL' - * - * PARAMS - * pdvi [O] pointer to version information structure. - * - * RETURNS - * Success: S_OK - * Failure: E_INVALIDARG - * - * NOTES - * Returns version of a comctl32.dll from IE4.01 SP1. - */ - -HRESULT WINAPI -COMCTL32_DllGetVersion (DLLVERSIONINFO *pdvi) -{ - if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) { - WARN("wrong DLLVERSIONINFO size from app\n"); - return E_INVALIDARG; - } - - pdvi->dwMajorVersion = COMCTL32_VERSION; - pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR; - pdvi->dwBuildNumber = 2919; - pdvi->dwPlatformID = 6304; - - TRACE("%lu.%lu.%lu.%lu\n", - pdvi->dwMajorVersion, pdvi->dwMinorVersion, - pdvi->dwBuildNumber, pdvi->dwPlatformID); - - return S_OK; -} - -/*********************************************************************** - * DllInstall (COMCTL32.@) - * - * Installs the ComCtl32 DLL. - * - * RETURNS - * Success: S_OK - * Failure: A HRESULT error - */ -HRESULT WINAPI COMCTL32_DllInstall(BOOL bInstall, LPCWSTR cmdline) -{ - FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE", - debugstr_w(cmdline)); - - return S_OK; -} - -/*********************************************************************** - * _TrackMouseEvent [COMCTL32.@] - * - * Requests notification of mouse events - * - * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted - * to the hwnd specified in the ptme structure. After the event message - * is posted to the hwnd, the entry in the queue is removed. - * - * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely - * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted - * immediately and the TME_LEAVE flag being ignored. - * - * PARAMS - * ptme [I,O] pointer to TRACKMOUSEEVENT information structure. - * - * RETURNS - * Success: non-zero - * Failure: zero - * - * IMPLEMENTATION moved to USER32.TrackMouseEvent - * - */ - -BOOL WINAPI -_TrackMouseEvent (TRACKMOUSEEVENT *ptme) -{ - return TrackMouseEvent (ptme); -} - -/************************************************************************* - * GetMUILanguage [COMCTL32.@] - * - * Returns the user interface language in use by the current process. - * - * RETURNS - * Language ID in use by the current process. - */ -LANGID WINAPI GetMUILanguage (VOID) -{ - return COMCTL32_uiLang; -} - - -/************************************************************************* - * InitMUILanguage [COMCTL32.@] - * - * Sets the user interface language to be used by the current process. - * - * RETURNS - * Nothing. - */ -VOID WINAPI InitMUILanguage (LANGID uiLang) -{ - COMCTL32_uiLang = uiLang; -} - - -/*********************************************************************** - * SetWindowSubclass [COMCTL32.410] - * - * Starts a window subclass - * - * PARAMS - * hWnd [in] handle to window subclass. - * pfnSubclass [in] Pointer to new window procedure. - * uIDSubclass [in] Unique identifier of sublass together with pfnSubclass. - * dwRef [in] Reference data to pass to window procedure. - * - * RETURNS - * Success: non-zero - * Failure: zero - * - * BUGS - * If an application manually subclasses a window after subclassing it with - * this API and then with this API again, then none of the previous - * subclasses get called or the origional window procedure. - */ - -BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass, - UINT_PTR uIDSubclass, DWORD_PTR dwRef) -{ - LPSUBCLASS_INFO stack; - LPSUBCLASSPROCS proc; - - TRACE ("(%p, %p, %x, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef); - - /* Since the window procedure that we set here has two additional arguments, - * we can't simply set it as the new window procedure of the window. So we - * set our own window procedure and then calculate the other two arguments - * from there. */ - - /* See if we have been called for this window */ - stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass); - if (!stack) { - /* allocate stack */ - stack = Alloc (sizeof(SUBCLASS_INFO)); - if (!stack) { - ERR ("Failed to allocate our Subclassing stack\n"); - return FALSE; - } - SetPropW (hWnd, COMCTL32_wSubclass, (HANDLE)stack); - - /* set window procedure to our own and save the current one */ - if (IsWindowUnicode (hWnd)) - stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC, - (DWORD_PTR)COMCTL32_SubclassProc); - else - stack->origproc = (WNDPROC)SetWindowLongPtrA (hWnd, GWLP_WNDPROC, - (DWORD_PTR)COMCTL32_SubclassProc); - } - else { - /* Check to see if we have called this function with the same uIDSubClass - * and pfnSubclass */ - proc = stack->SubclassProcs; - while (proc) { - if ((proc->id == uIDSubclass) && - (proc->subproc == pfnSubclass)) { - proc->ref = dwRef; - return TRUE; - } - proc = proc->next; - } - } - - proc = Alloc(sizeof(SUBCLASSPROCS)); - if (!proc) { - ERR ("Failed to allocate subclass entry in stack\n"); - if (IsWindowUnicode (hWnd)) - SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); - else - SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); - Free (stack); - RemovePropW( hWnd, COMCTL32_wSubclass ); - return FALSE; - } - - proc->subproc = pfnSubclass; - proc->ref = dwRef; - proc->id = uIDSubclass; - proc->next = stack->SubclassProcs; - stack->SubclassProcs = proc; - - return TRUE; -} - - -/*********************************************************************** - * GetWindowSubclass [COMCTL32.411] - * - * Gets the Reference data from a subclass. - * - * PARAMS - * hWnd [in] Handle to window which were subclassing - * pfnSubclass [in] Pointer to the subclass procedure - * uID [in] Unique indentifier of the subclassing procedure - * pdwRef [out] Pointer to the reference data - * - * RETURNS - * Success: Non-zero - * Failure: 0 - */ - -BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass, - UINT_PTR uID, DWORD_PTR *pdwRef) -{ - LPSUBCLASS_INFO stack; - LPSUBCLASSPROCS proc; - - TRACE ("(%p, %p, %x, %p)\n", hWnd, pfnSubclass, uID, pdwRef); - - /* See if we have been called for this window */ - stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass); - if (!stack) - return FALSE; - - proc = stack->SubclassProcs; - while (proc) { - if ((proc->id == uID) && - (proc->subproc == pfnSubclass)) { - *pdwRef = proc->ref; - return TRUE; - } - proc = proc->next; - } - - return FALSE; -} - - -/*********************************************************************** - * RemoveWindowSubclass [COMCTL32.412] - * - * Removes a window subclass. - * - * PARAMS - * hWnd [in] Handle to the window were subclassing - * pfnSubclass [in] Pointer to the subclass procedure - * uID [in] Unique identifier of this subclass - * - * RETURNS - * Success: non-zero - * Failure: zero - */ - -BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID) -{ - LPSUBCLASS_INFO stack; - LPSUBCLASSPROCS prevproc = NULL; - LPSUBCLASSPROCS proc; - BOOL ret = FALSE; - - TRACE ("(%p, %p, %x)\n", hWnd, pfnSubclass, uID); - - /* Find the Subclass to remove */ - stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass); - if (!stack) - return FALSE; - - proc = stack->SubclassProcs; - while (proc) { - if ((proc->id == uID) && - (proc->subproc == pfnSubclass)) { - - if (!prevproc) - stack->SubclassProcs = proc->next; - else - prevproc->next = proc->next; - - if (stack->stackpos == proc) - stack->stackpos = stack->stackpos->next; - - Free (proc); - ret = TRUE; - break; - } - prevproc = proc; - proc = proc->next; - } - - if (!stack->SubclassProcs && !stack->running) { - TRACE("Last Subclass removed, cleaning up\n"); - /* clean up our heap and reset the origional window procedure */ - if (IsWindowUnicode (hWnd)) - SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); - else - SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); - Free (stack); - RemovePropW( hWnd, COMCTL32_wSubclass ); - } - - return ret; -} - -/*********************************************************************** - * COMCTL32_SubclassProc (internal) - * - * Window procedure for all subclassed windows. - * Saves the current subclassing stack position to support nested messages - */ -LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - LPSUBCLASS_INFO stack; - LPSUBCLASSPROCS proc; - LRESULT ret; - - TRACE ("(%p, 0x%08x, 0x%08x, 0x%08lx)\n", hWnd, uMsg, wParam, lParam); - - stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass); - if (!stack) { - ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd); - return 0; - } - - /* Save our old stackpos to properly handle nested messages */ - proc = stack->stackpos; - stack->stackpos = stack->SubclassProcs; - stack->running++; - ret = DefSubclassProc(hWnd, uMsg, wParam, lParam); - stack->running--; - stack->stackpos = proc; - - if (!stack->SubclassProcs && !stack->running) { - TRACE("Last Subclass removed, cleaning up\n"); - /* clean up our heap and reset the origional window procedure */ - if (IsWindowUnicode (hWnd)) - SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); - else - SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); - Free (stack); - RemovePropW( hWnd, COMCTL32_wSubclass ); - } - return ret; -} - -/*********************************************************************** - * DefSubclassProc [COMCTL32.413] - * - * Calls the next window procedure (ie. the one before this subclass) - * - * PARAMS - * hWnd [in] The window that we're subclassing - * uMsg [in] Message - * wParam [in] WPARAM - * lParam [in] LPARAM - * - * RETURNS - * Success: non-zero - * Failure: zero - */ - -LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - LPSUBCLASS_INFO stack; - LRESULT ret; - - TRACE ("(%p, 0x%08x, 0x%08x, 0x%08lx)\n", hWnd, uMsg, wParam, lParam); - - /* retrieve our little stack from the Properties */ - stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass); - if (!stack) { - ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd); - return 0; - } - - /* If we are at the end of stack then we have to call the original - * window procedure */ - if (!stack->stackpos) { - if (IsWindowUnicode (hWnd)) - ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam); - else - ret = CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam); - } else { - LPSUBCLASSPROCS proc = stack->stackpos; - stack->stackpos = stack->stackpos->next; - /* call the Subclass procedure from the stack */ - ret = proc->subproc (hWnd, uMsg, wParam, lParam, - proc->id, proc->ref); - } - - return ret; -} - - -/*********************************************************************** - * COMCTL32_CreateToolTip [NOT AN API] - * - * Creates a tooltip for the control specified in hwnd and does all - * necessary setup and notifications. - * - * PARAMS - * hwndOwner [I] Handle to the window that will own the tool tip. - * - * RETURNS - * Success: Handle of tool tip window. - * Failure: NULL - */ - -HWND -COMCTL32_CreateToolTip(HWND hwndOwner) -{ - HWND hwndToolTip; - - hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner, - 0, 0, 0); - - /* Send NM_TOOLTIPSCREATED notification */ - if (hwndToolTip) - { - NMTOOLTIPSCREATED nmttc; - /* true owner can be different if hwndOwner is a child window */ - HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER); - nmttc.hdr.hwndFrom = hwndTrueOwner; - nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID); - nmttc.hdr.code = NM_TOOLTIPSCREATED; - nmttc.hwndToolTips = hwndToolTip; - - SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY, - (WPARAM)GetWindowLongPtrW(hwndTrueOwner, GWLP_ID), - (LPARAM)&nmttc); - } - - return hwndToolTip; -} - - -/*********************************************************************** - * COMCTL32_RefreshSysColors [NOT AN API] - * - * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to - * refresh the color values in the color structure - * - * PARAMS - * none - * - * RETURNS - * none - */ - -VOID -COMCTL32_RefreshSysColors(void) -{ - comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT); - comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW); - comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT); - comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE); - comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT); - comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT); - comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT); - comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW); - comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW); - comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE); - comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW); - comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT); - comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT); - comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION); - comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK); - comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT); -} - -/*********************************************************************** - * COMCTL32_DrawInsertMark [NOT AN API] - * - * Draws an insertion mark (which looks similar to an 'I'). - * - * PARAMS - * hDC [I] Device context to draw onto. - * lpRect [I] Co-ordinates of insertion mark. - * clrInsertMark [I] Colour of the insertion mark. - * bHorizontal [I] True if insert mark should be drawn horizontally, - * vertical otherwise. - * - * RETURNS - * none - * - * NOTES - * Draws up to but not including the bottom co-ordinate when drawing - * vertically or the right co-ordinate when horizontal. - */ -void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal) -{ - HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark); - HPEN hOldPen; - static const DWORD adwPolyPoints[] = {4,4,4}; - LONG lCentre = (bHorizontal ? - lpRect->top + (lpRect->bottom - lpRect->top)/2 : - lpRect->left + (lpRect->right - lpRect->left)/2); - LONG l1 = (bHorizontal ? lpRect->left : lpRect->top); - LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom); - const POINT aptInsertMark[] = - { - /* top (V) or left (H) arrow */ - {lCentre , l1 + 2}, - {lCentre - 2, l1 }, - {lCentre + 3, l1 }, - {lCentre + 1, l1 + 2}, - /* middle line */ - {lCentre , l2 - 2}, - {lCentre , l1 - 1}, - {lCentre + 1, l1 - 1}, - {lCentre + 1, l2 - 2}, - /* bottom (V) or right (H) arrow */ - {lCentre , l2 - 3}, - {lCentre - 2, l2 - 1}, - {lCentre + 3, l2 - 1}, - {lCentre + 1, l2 - 3}, - }; - hOldPen = SelectObject(hDC, hPen); - PolyPolyline(hDC, aptInsertMark, adwPolyPoints, sizeof(adwPolyPoints)/sizeof(adwPolyPoints[0])); - SelectObject(hDC, hOldPen); - DeleteObject(hPen); -} - -/*********************************************************************** - * MirrorIcon [COMCTL32.414] - * - * Mirrors an icon so that it will appear correctly on a mirrored DC. - * - * PARAMS - * phicon1 [I/O] Icon. - * phicon2 [I/O] Icon. - * - * RETURNS - * Success: TRUE. - * Failure: FALSE. - */ -BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2) -{ - FIXME("(%p, %p): stub\n", phicon1, phicon2); - return FALSE; -} - -static inline int IsDelimiter(WCHAR c) -{ - switch(c) - { - case '/': - case '\\': - case '.': - case ' ': - return TRUE; - } - return FALSE; -} - -static int CALLBACK PathWordBreakProc(LPWSTR lpch, int ichCurrent, int cch, int code) -{ - if (code == WB_ISDELIMITER) - return IsDelimiter(lpch[ichCurrent]); - else - { - int dir = (code == WB_LEFT) ? -1 : 1; - for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir) - if (IsDelimiter(lpch[ichCurrent])) return ichCurrent; - } - return ichCurrent; -} - -/*********************************************************************** - * SetPathWordBreakProc [COMCTL32.384] - * - * Sets the word break procedure for an edit control to one that understands - * paths so that the user can jump over directories. - * - * PARAMS - * hwnd [I] Handle to edit control. - * bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed. - * - * RETURNS - * Result from EM_SETWORDBREAKPROC message. - */ -LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet) -{ - return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0, - (LPARAM)(bSet ? PathWordBreakProc : NULL)); -} +/* + * Common controls functions + * + * Copyright 1997 Dimitrie O. Paun + * Copyright 1998,2000 Eric Kohl + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES + * + * This code was audited for completeness against the documented features + * of Comctl32.dll version 6.0 on Oct. 21, 2002, by Christian Neumair. + * + * Unless otherwise noted, we believe this code to be complete, as per + * the specification mentioned above. + * If you discover missing features, or bugs, please note them below. + * + * TODO + * -- implement GetMUILanguage + InitMUILanguage + * -- LibMain => DLLMain ("DLLMain takes over the functionality of both the + * LibMain and the WEP function.", MSDN) + * -- finish NOTES for MenuHelp, GetEffectiveClientRect and GetStatusTextW + * -- FIXMEs + BUGS (search for them) + * + * Control Classes + * -- ICC_ANIMATE_CLASS + * -- ICC_BAR_CLASSES + * -- ICC_COOL_CLASSES + * -- ICC_DATE_CLASSES + * -- ICC_HOTKEY_CLASS + * -- ICC_INTERNET_CLASSES + * -- ICC_LINK_CLASS + * -- ICC_LISTVIEW_CLASSES + * -- ICC_NATIVEFNTCTL_CLASS + * -- ICC_PAGESCROLLER_CLASS + * -- ICC_PROGRESS_CLASS + * -- ICC_STANDARD_CLASSES (not yet implemented) + * -- ICC_TAB_CLASSES + * -- ICC_TREEVIEW_CLASSES + * -- ICC_UPDOWN_CLASS + * -- ICC_USEREX_CLASSES + * -- ICC_WIN95_CLASSES + */ + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "winerror.h" +#include "winreg.h" +#define NO_SHLWAPI_STREAM +#include "shlwapi.h" +#include "comctl32.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(commctrl); + +LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +LPWSTR COMCTL32_wSubclass = NULL; +HMODULE COMCTL32_hModule = 0; +LANGID COMCTL32_uiLang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL); +HBRUSH COMCTL32_hPattern55AABrush = NULL; +COMCTL32_SysColor comctl32_color; + +static HBITMAP COMCTL32_hPattern55AABitmap = NULL; + +static const WORD wPattern55AA[] = +{ + 0x5555, 0xaaaa, 0x5555, 0xaaaa, + 0x5555, 0xaaaa, 0x5555, 0xaaaa +}; + +static const WCHAR strCC32SubclassInfo[] = { + 'C','C','3','2','S','u','b','c','l','a','s','s','I','n','f','o',0 +}; + +/*********************************************************************** + * DllMain [Internal] + * + * Initializes the internal 'COMCTL32.DLL'. + * + * PARAMS + * hinstDLL [I] handle to the 'dlls' instance + * fdwReason [I] + * lpvReserved [I] reserverd, must be NULL + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + TRACE("%p,%lx,%p\n", hinstDLL, fdwReason, lpvReserved); + + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDLL); + + COMCTL32_hModule = (HMODULE)hinstDLL; + + /* add global subclassing atom (used by 'tooltip' and 'updown') */ + COMCTL32_wSubclass = (LPWSTR)(DWORD)GlobalAddAtomW (strCC32SubclassInfo); + TRACE("Subclassing atom added: %p\n", COMCTL32_wSubclass); + + /* create local pattern brush */ + COMCTL32_hPattern55AABitmap = CreateBitmap (8, 8, 1, 1, wPattern55AA); + COMCTL32_hPattern55AABrush = CreatePatternBrush (COMCTL32_hPattern55AABitmap); + + /* Get all the colors at DLL load */ + COMCTL32_RefreshSysColors(); + + /* register all Win95 common control classes */ + ANIMATE_Register (); + FLATSB_Register (); + HEADER_Register (); + HOTKEY_Register (); + LISTVIEW_Register (); + PROGRESS_Register (); + STATUS_Register (); + SYSLINK_Register (); + TAB_Register (); + TOOLBAR_Register (); + TOOLTIPS_Register (); + TRACKBAR_Register (); + TREEVIEW_Register (); + UPDOWN_Register (); + break; + + case DLL_PROCESS_DETACH: + /* unregister all common control classes */ + ANIMATE_Unregister (); + COMBOEX_Unregister (); + DATETIME_Unregister (); + FLATSB_Unregister (); + HEADER_Unregister (); + HOTKEY_Unregister (); + IPADDRESS_Unregister (); + LISTVIEW_Unregister (); + MONTHCAL_Unregister (); + NATIVEFONT_Unregister (); + PAGER_Unregister (); + PROGRESS_Unregister (); + REBAR_Unregister (); + STATUS_Unregister (); + SYSLINK_Unregister (); + TAB_Unregister (); + TOOLBAR_Unregister (); + TOOLTIPS_Unregister (); + TRACKBAR_Unregister (); + TREEVIEW_Unregister (); + UPDOWN_Unregister (); + + /* delete local pattern brush */ + DeleteObject (COMCTL32_hPattern55AABrush); + COMCTL32_hPattern55AABrush = NULL; + DeleteObject (COMCTL32_hPattern55AABitmap); + COMCTL32_hPattern55AABitmap = NULL; + + /* delete global subclassing atom */ + GlobalDeleteAtom (LOWORD(COMCTL32_wSubclass)); + TRACE("Subclassing atom deleted: %p\n", COMCTL32_wSubclass); + COMCTL32_wSubclass = NULL; + break; + } + + return TRUE; +} + + +/*********************************************************************** + * MenuHelp [COMCTL32.2] + * + * Handles the setting of status bar help messages when the user + * selects menu items. + * + * PARAMS + * uMsg [I] message (WM_MENUSELECT) (see NOTES) + * wParam [I] wParam of the message uMsg + * lParam [I] lParam of the message uMsg + * hMainMenu [I] handle to the application's main menu + * hInst [I] handle to the module that contains string resources + * hwndStatus [I] handle to the status bar window + * lpwIDs [I] pointer to an array of integers (see NOTES) + * + * RETURNS + * No return value + * + * NOTES + * The official documentation is incomplete! + * This is the correct documentation: + * + * uMsg: + * MenuHelp() does NOT handle WM_COMMAND messages! It only handles + * WM_MENUSELECT messages. + * + * lpwIDs: + * (will be written ...) + */ + +VOID WINAPI +MenuHelp (UINT uMsg, WPARAM wParam, LPARAM lParam, HMENU hMainMenu, + HINSTANCE hInst, HWND hwndStatus, UINT* lpwIDs) +{ + UINT uMenuID = 0; + + if (!IsWindow (hwndStatus)) + return; + + switch (uMsg) { + case WM_MENUSELECT: + TRACE("WM_MENUSELECT wParam=0x%X lParam=0x%lX\n", + wParam, lParam); + + if ((HIWORD(wParam) == 0xFFFF) && (lParam == 0)) { + /* menu was closed */ + TRACE("menu was closed!\n"); + SendMessageW (hwndStatus, SB_SIMPLE, FALSE, 0); + } + else { + /* menu item was selected */ + if (HIWORD(wParam) & MF_POPUP) + uMenuID = (UINT)*(lpwIDs+1); + else + uMenuID = (UINT)LOWORD(wParam); + TRACE("uMenuID = %u\n", uMenuID); + + if (uMenuID) { + WCHAR szText[256]; + + if (!LoadStringW (hInst, uMenuID, szText, sizeof(szText)/sizeof(szText[0]))) + szText[0] = '\0'; + + SendMessageW (hwndStatus, SB_SETTEXTW, + 255 | SBT_NOBORDERS, (LPARAM)szText); + SendMessageW (hwndStatus, SB_SIMPLE, TRUE, 0); + } + } + break; + + case WM_COMMAND : + TRACE("WM_COMMAND wParam=0x%X 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; + } +} + + +/*********************************************************************** + * ShowHideMenuCtl [COMCTL32.3] + * + * Shows or hides controls and updates the corresponding menu item. + * + * PARAMS + * hwnd [I] handle to the client window. + * uFlags [I] menu command id. + * lpInfo [I] pointer to an array of integers. (See NOTES.) + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * The official documentation is incomplete! + * This is the correct documentation: + * + * hwnd + * Handle to the window that contains the menu and controls. + * + * uFlags + * Identifier of the menu item to receive or lose a check mark. + * + * lpInfo + * The array of integers contains pairs of values. BOTH values of + * the first pair must be the handles to the application's main menu. + * Each subsequent pair consists of a menu id and control id. + */ + +BOOL WINAPI +ShowHideMenuCtl (HWND hwnd, UINT uFlags, LPINT lpInfo) +{ + LPINT lpMenuId; + + TRACE("%p, %x, %p\n", hwnd, uFlags, lpInfo); + + if (lpInfo == NULL) + return FALSE; + + if (!(lpInfo[0]) || !(lpInfo[1])) + return FALSE; + + /* search for control */ + lpMenuId = &lpInfo[2]; + while (*lpMenuId != uFlags) + lpMenuId += 2; + + if (GetMenuState ((HMENU)lpInfo[1], uFlags, MF_BYCOMMAND) & MFS_CHECKED) { + /* uncheck menu item */ + CheckMenuItem ((HMENU)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_UNCHECKED); + + /* hide control */ + lpMenuId++; + SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0, + SWP_HIDEWINDOW); + } + else { + /* check menu item */ + CheckMenuItem ((HMENU)lpInfo[0], *lpMenuId, MF_BYCOMMAND | MF_CHECKED); + + /* show control */ + lpMenuId++; + SetWindowPos (GetDlgItem (hwnd, *lpMenuId), 0, 0, 0, 0, 0, + SWP_SHOWWINDOW); + } + + return TRUE; +} + + +/*********************************************************************** + * GetEffectiveClientRect [COMCTL32.4] + * + * Calculates the coordinates of a rectangle in the client area. + * + * PARAMS + * hwnd [I] handle to the client window. + * lpRect [O] pointer to the rectangle of the client window + * lpInfo [I] pointer to an array of integers (see NOTES) + * + * RETURNS + * No return value. + * + * NOTES + * The official documentation is incomplete! + * This is the correct documentation: + * + * lpInfo + * (will be written ...) + */ + +VOID WINAPI +GetEffectiveClientRect (HWND hwnd, LPRECT lpRect, LPINT lpInfo) +{ + RECT rcCtrl; + INT *lpRun; + HWND hwndCtrl; + + TRACE("(0x%08lx 0x%08lx 0x%08lx)\n", + (DWORD)hwnd, (DWORD)lpRect, (DWORD)lpInfo); + + GetClientRect (hwnd, lpRect); + lpRun = lpInfo; + + do { + lpRun += 2; + if (*lpRun == 0) + return; + lpRun++; + hwndCtrl = GetDlgItem (hwnd, *lpRun); + if (GetWindowLongW (hwndCtrl, GWL_STYLE) & WS_VISIBLE) { + TRACE("control id 0x%x\n", *lpRun); + GetWindowRect (hwndCtrl, &rcCtrl); + MapWindowPoints (NULL, hwnd, (LPPOINT)&rcCtrl, 2); + SubtractRect (lpRect, lpRect, &rcCtrl); + } + lpRun++; + } while (*lpRun); +} + + +/*********************************************************************** + * DrawStatusTextW [COMCTL32.@] + * + * Draws text with borders, like in a status bar. + * + * PARAMS + * hdc [I] handle to the window's display context + * lprc [I] pointer to a rectangle + * text [I] pointer to the text + * style [I] drawing style + * + * RETURNS + * No return value. + * + * NOTES + * The style variable can have one of the following values: + * (will be written ...) + */ + +void WINAPI DrawStatusTextW (HDC hdc, LPRECT lprc, LPCWSTR text, UINT style) +{ + RECT r = *lprc; + UINT border = BDR_SUNKENOUTER; + + if (style & SBT_POPOUT) + border = BDR_RAISEDOUTER; + else if (style & SBT_NOBORDERS) + border = 0; + + DrawEdge (hdc, &r, border, BF_RECT|BF_ADJUST); + + /* now draw text */ + if (text) { + int oldbkmode = SetBkMode (hdc, TRANSPARENT); + UINT align = DT_LEFT; + if (*text == L'\t') { + text++; + align = DT_CENTER; + if (*text == L'\t') { + text++; + align = DT_RIGHT; + } + } + r.left += 3; + if (style & SBT_RTLREADING) + FIXME("Unsupported RTL style!\n"); + DrawTextW (hdc, text, -1, &r, align|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX); + SetBkMode(hdc, oldbkmode); + } +} + + +/*********************************************************************** + * DrawStatusText [COMCTL32.@] + * DrawStatusTextA [COMCTL32.5] + * + * Draws text with borders, like in a status bar. + * + * PARAMS + * hdc [I] handle to the window's display context + * lprc [I] pointer to a rectangle + * text [I] pointer to the text + * style [I] drawing style + * + * RETURNS + * No return value. + */ + +void WINAPI DrawStatusTextA (HDC hdc, LPRECT lprc, LPCSTR text, UINT style) +{ + INT len; + LPWSTR textW = NULL; + + if ( text ) { + if ( (len = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 )) ) { + if ( (textW = Alloc( len * sizeof(WCHAR) )) ) + MultiByteToWideChar( CP_ACP, 0, text, -1, textW, len ); + } + } + DrawStatusTextW( hdc, lprc, textW, style ); + Free( textW ); +} + + +/*********************************************************************** + * CreateStatusWindow [COMCTL32.@] + * CreateStatusWindowA [COMCTL32.6] + * + * Creates a status bar + * + * PARAMS + * style [I] window style + * text [I] pointer to the window text + * parent [I] handle to the parent window + * wid [I] control id of the status bar + * + * RETURNS + * Success: handle to the status window + * Failure: 0 + */ + +HWND WINAPI +CreateStatusWindowA (LONG style, LPCSTR text, HWND parent, UINT wid) +{ + return CreateWindowA(STATUSCLASSNAMEA, text, style, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + parent, (HMENU)wid, 0, 0); +} + + +/*********************************************************************** + * CreateStatusWindowW [COMCTL32.@] + * + * Creates a status bar control + * + * PARAMS + * style [I] window style + * text [I] pointer to the window text + * parent [I] handle to the parent window + * wid [I] control id of the status bar + * + * RETURNS + * Success: handle to the status window + * Failure: 0 + */ + +HWND WINAPI +CreateStatusWindowW (LONG style, LPCWSTR text, HWND parent, UINT wid) +{ + return CreateWindowW(STATUSCLASSNAMEW, text, style, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + parent, (HMENU)wid, 0, 0); +} + + +/*********************************************************************** + * CreateUpDownControl [COMCTL32.16] + * + * Creates an up-down control + * + * PARAMS + * style [I] window styles + * x [I] horizontal position of the control + * y [I] vertical position of the control + * cx [I] with of the control + * cy [I] height of the control + * parent [I] handle to the parent window + * id [I] the control's identifier + * inst [I] handle to the application's module instance + * buddy [I] handle to the buddy window, can be NULL + * maxVal [I] upper limit of the control + * minVal [I] lower limit of the control + * curVal [I] current value of the control + * + * RETURNS + * Success: handle to the updown control + * Failure: 0 + */ + +HWND WINAPI +CreateUpDownControl (DWORD style, INT x, INT y, INT cx, INT cy, + HWND parent, INT id, HINSTANCE inst, + HWND buddy, INT maxVal, INT minVal, INT curVal) +{ + HWND hUD = + CreateWindowW (UPDOWN_CLASSW, 0, style, x, y, cx, cy, + parent, (HMENU)id, inst, 0); + if (hUD) { + SendMessageW (hUD, UDM_SETBUDDY, (WPARAM)buddy, 0); + SendMessageW (hUD, UDM_SETRANGE, 0, MAKELONG(maxVal, minVal)); + SendMessageW (hUD, UDM_SETPOS, 0, MAKELONG(curVal, 0)); + } + + return hUD; +} + + +/*********************************************************************** + * InitCommonControls [COMCTL32.17] + * + * Registers the common controls. + * + * PARAMS + * No parameters. + * + * RETURNS + * No return values. + * + * NOTES + * This function is just a dummy. + * The Win95 controls are registered at the DLL's initialization. + * To register other controls InitCommonControlsEx() must be used. + */ + +VOID WINAPI +InitCommonControls (void) +{ +} + + +/*********************************************************************** + * InitCommonControlsEx [COMCTL32.@] + * + * Registers the common controls. + * + * PARAMS + * lpInitCtrls [I] pointer to an INITCOMMONCONTROLS structure. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * Only the additional common controls are registered by this function. + * The Win95 controls are registered at the DLL's initialization. + * + * FIXME + * implement the following control classes: + * ICC_LINK_CLASS + * ICC_STANDARD_CLASSES + */ + +BOOL WINAPI +InitCommonControlsEx (LPINITCOMMONCONTROLSEX lpInitCtrls) +{ + INT cCount; + DWORD dwMask; + + if (!lpInitCtrls) + return FALSE; + if (lpInitCtrls->dwSize != sizeof(INITCOMMONCONTROLSEX)) + return FALSE; + + TRACE("(0x%08lx)\n", lpInitCtrls->dwICC); + + for (cCount = 0; cCount < 32; cCount++) { + dwMask = 1 << cCount; + if (!(lpInitCtrls->dwICC & dwMask)) + continue; + + switch (lpInitCtrls->dwICC & dwMask) { + /* dummy initialization */ + case ICC_ANIMATE_CLASS: + case ICC_BAR_CLASSES: + case ICC_LISTVIEW_CLASSES: + case ICC_TREEVIEW_CLASSES: + case ICC_TAB_CLASSES: + case ICC_UPDOWN_CLASS: + case ICC_PROGRESS_CLASS: + case ICC_HOTKEY_CLASS: + break; + + /* advanced classes - not included in Win95 */ + case ICC_DATE_CLASSES: + MONTHCAL_Register (); + DATETIME_Register (); + break; + + case ICC_USEREX_CLASSES: + COMBOEX_Register (); + break; + + case ICC_COOL_CLASSES: + REBAR_Register (); + break; + + case ICC_INTERNET_CLASSES: + IPADDRESS_Register (); + break; + + case ICC_PAGESCROLLER_CLASS: + PAGER_Register (); + break; + + case ICC_NATIVEFNTCTL_CLASS: + NATIVEFONT_Register (); + break; + + case ICC_LINK_CLASS: + SYSLINK_Register (); + break; + + default: + FIXME("Unknown class! dwICC=0x%lX\n", dwMask); + break; + } + } + + return TRUE; +} + + +/*********************************************************************** + * CreateToolbarEx [COMCTL32.@] + * + * Creates a toolbar window. + * + * PARAMS + * hwnd + * style + * wID + * nBitmaps + * hBMInst + * wBMID + * lpButtons + * iNumButtons + * dxButton + * dyButton + * dxBitmap + * dyBitmap + * uStructSize + * + * RETURNS + * Success: handle to the tool bar control + * Failure: 0 + */ + +HWND WINAPI +CreateToolbarEx (HWND hwnd, DWORD style, UINT wID, INT nBitmaps, + HINSTANCE hBMInst, UINT wBMID, LPCTBBUTTON lpButtons, + INT iNumButtons, INT dxButton, INT dyButton, + INT dxBitmap, INT dyBitmap, UINT uStructSize) +{ + HWND hwndTB; + + hwndTB = + CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL, style|WS_CHILD, 0,0,100,30, + hwnd, (HMENU)wID, COMCTL32_hModule, NULL); + if(hwndTB) { + TBADDBITMAP tbab; + + SendMessageW (hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM)uStructSize, 0); + + /* set bitmap and button size */ + /*If CreateToolbarEx receives 0, windows sets default values*/ + if (dxBitmap <= 0) + dxBitmap = 16; + if (dyBitmap <= 0) + dyBitmap = 15; + SendMessageW (hwndTB, TB_SETBITMAPSIZE, 0, + MAKELPARAM((WORD)dxBitmap, (WORD)dyBitmap)); + + if (dxButton <= 0) + dxButton = 24; + if (dyButton <= 0) + dyButton = 22; + SendMessageW (hwndTB, TB_SETBUTTONSIZE, 0, + MAKELPARAM((WORD)dxButton, (WORD)dyButton)); + + + /* add bitmaps */ + if (nBitmaps > 0) + { + tbab.hInst = hBMInst; + tbab.nID = wBMID; + + SendMessageW (hwndTB, TB_ADDBITMAP, (WPARAM)nBitmaps, (LPARAM)&tbab); + } + /* add buttons */ + if(iNumButtons > 0) + SendMessageW (hwndTB, TB_ADDBUTTONSW, + (WPARAM)iNumButtons, (LPARAM)lpButtons); + } + + return hwndTB; +} + + +/*********************************************************************** + * CreateMappedBitmap [COMCTL32.8] + * + * Loads a bitmap resource using a colour map. + * + * PARAMS + * hInstance [I] Handle to the module containing the bitmap. + * idBitmap [I] The bitmap resource ID. + * wFlags [I] CMB_MASKED for using bitmap as a mask or 0 for normal. + * lpColorMap [I] Colour information needed for the bitmap or NULL (uses system colours). + * iNumMaps [I] Number of COLORMAP's pointed to by lpColorMap. + * + * RETURNS + * Success: handle to the new bitmap + * Failure: 0 + */ + +HBITMAP WINAPI +CreateMappedBitmap (HINSTANCE hInstance, INT idBitmap, UINT wFlags, + LPCOLORMAP lpColorMap, INT iNumMaps) +{ + HGLOBAL hglb; + HRSRC hRsrc; + LPBITMAPINFOHEADER lpBitmap, 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 = (LPCOLORMAP)internalColorMap; + } + + hRsrc = FindResourceW (hInstance, (LPWSTR)idBitmap, (LPWSTR)RT_BITMAP); + if (hRsrc == 0) + return 0; + hglb = LoadResource (hInstance, hRsrc); + if (hglb == 0) + return 0; + lpBitmap = (LPBITMAPINFOHEADER)LockResource (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 + nColorTableSize * sizeof(RGBQUAD); + lpBitmapInfo = (LPBITMAPINFOHEADER)GlobalAlloc (GMEM_FIXED, nSize); + if (lpBitmapInfo == NULL) + return 0; + RtlMoveMemory (lpBitmapInfo, lpBitmap, nSize); + + pColorTable = (RGBQUAD*)(((LPBYTE)lpBitmapInfo)+(UINT)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 = (INT)lpBitmapInfo->biWidth; + nHeight = (INT)lpBitmapInfo->biHeight; + hdcScreen = GetDC (NULL); + hbm = CreateCompatibleBitmap (hdcScreen, nWidth, nHeight); + if (hbm) { + HDC hdcDst = CreateCompatibleDC (hdcScreen); + HBITMAP hbmOld = SelectObject (hdcDst, hbm); + LPBYTE lpBits = (LPBYTE)(lpBitmap + 1); + lpBits += nColorTableSize * sizeof(RGBQUAD); + 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 ((HGLOBAL)lpBitmapInfo); + FreeResource (hglb); + + return hbm; +} + + +/*********************************************************************** + * CreateToolbar [COMCTL32.7] + * + * Creates a toolbar control. + * + * PARAMS + * hwnd + * style + * wID + * nBitmaps + * hBMInst + * wBMID + * lpButtons + * iNumButtons + * + * RETURNS + * Success: handle to the tool bar control + * Failure: 0 + * + * NOTES + * Do not use this functions anymore. Use CreateToolbarEx instead. + */ + +HWND WINAPI +CreateToolbar (HWND hwnd, DWORD style, UINT wID, INT nBitmaps, + HINSTANCE hBMInst, UINT wBMID, + LPCTBBUTTON lpButtons,INT iNumButtons) +{ + return CreateToolbarEx (hwnd, style | CCS_NODIVIDER, wID, nBitmaps, + hBMInst, wBMID, lpButtons, + iNumButtons, 0, 0, 0, 0, CCSIZEOF_STRUCT(TBBUTTON, dwData)); +} + + +/*********************************************************************** + * DllGetVersion [COMCTL32.@] + * + * Retrieves version information of the 'COMCTL32.DLL' + * + * PARAMS + * pdvi [O] pointer to version information structure. + * + * RETURNS + * Success: S_OK + * Failure: E_INVALIDARG + * + * NOTES + * Returns version of a comctl32.dll from IE4.01 SP1. + */ + +HRESULT WINAPI +COMCTL32_DllGetVersion (DLLVERSIONINFO *pdvi) +{ + if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) { + WARN("wrong DLLVERSIONINFO size from app\n"); + return E_INVALIDARG; + } + + pdvi->dwMajorVersion = COMCTL32_VERSION; + pdvi->dwMinorVersion = COMCTL32_VERSION_MINOR; + pdvi->dwBuildNumber = 2919; + pdvi->dwPlatformID = 6304; + + TRACE("%lu.%lu.%lu.%lu\n", + pdvi->dwMajorVersion, pdvi->dwMinorVersion, + pdvi->dwBuildNumber, pdvi->dwPlatformID); + + return S_OK; +} + +/*********************************************************************** + * DllInstall (COMCTL32.@) + * + * Installs the ComCtl32 DLL. + * + * RETURNS + * Success: S_OK + * Failure: A HRESULT error + */ +HRESULT WINAPI COMCTL32_DllInstall(BOOL bInstall, LPCWSTR cmdline) +{ + FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE", + debugstr_w(cmdline)); + + return S_OK; +} + +/*********************************************************************** + * _TrackMouseEvent [COMCTL32.@] + * + * Requests notification of mouse events + * + * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted + * to the hwnd specified in the ptme structure. After the event message + * is posted to the hwnd, the entry in the queue is removed. + * + * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely + * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted + * immediately and the TME_LEAVE flag being ignored. + * + * PARAMS + * ptme [I,O] pointer to TRACKMOUSEEVENT information structure. + * + * RETURNS + * Success: non-zero + * Failure: zero + * + * IMPLEMENTATION moved to USER32.TrackMouseEvent + * + */ + +BOOL WINAPI +_TrackMouseEvent (TRACKMOUSEEVENT *ptme) +{ + return TrackMouseEvent (ptme); +} + +/************************************************************************* + * GetMUILanguage [COMCTL32.@] + * + * Returns the user interface language in use by the current process. + * + * RETURNS + * Language ID in use by the current process. + */ +LANGID WINAPI GetMUILanguage (VOID) +{ + return COMCTL32_uiLang; +} + + +/************************************************************************* + * InitMUILanguage [COMCTL32.@] + * + * Sets the user interface language to be used by the current process. + * + * RETURNS + * Nothing. + */ +VOID WINAPI InitMUILanguage (LANGID uiLang) +{ + COMCTL32_uiLang = uiLang; +} + + +/*********************************************************************** + * SetWindowSubclass [COMCTL32.410] + * + * Starts a window subclass + * + * PARAMS + * hWnd [in] handle to window subclass. + * pfnSubclass [in] Pointer to new window procedure. + * uIDSubclass [in] Unique identifier of sublass together with pfnSubclass. + * dwRef [in] Reference data to pass to window procedure. + * + * RETURNS + * Success: non-zero + * Failure: zero + * + * BUGS + * If an application manually subclasses a window after subclassing it with + * this API and then with this API again, then none of the previous + * subclasses get called or the origional window procedure. + */ + +BOOL WINAPI SetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass, + UINT_PTR uIDSubclass, DWORD_PTR dwRef) +{ + LPSUBCLASS_INFO stack; + LPSUBCLASSPROCS proc; + + TRACE ("(%p, %p, %x, %lx)\n", hWnd, pfnSubclass, uIDSubclass, dwRef); + + /* Since the window procedure that we set here has two additional arguments, + * we can't simply set it as the new window procedure of the window. So we + * set our own window procedure and then calculate the other two arguments + * from there. */ + + /* See if we have been called for this window */ + stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass); + if (!stack) { + /* allocate stack */ + stack = Alloc (sizeof(SUBCLASS_INFO)); + if (!stack) { + ERR ("Failed to allocate our Subclassing stack\n"); + return FALSE; + } + SetPropW (hWnd, COMCTL32_wSubclass, (HANDLE)stack); + + /* set window procedure to our own and save the current one */ + if (IsWindowUnicode (hWnd)) + stack->origproc = (WNDPROC)SetWindowLongPtrW (hWnd, GWLP_WNDPROC, + (DWORD_PTR)COMCTL32_SubclassProc); + else + stack->origproc = (WNDPROC)SetWindowLongPtrA (hWnd, GWLP_WNDPROC, + (DWORD_PTR)COMCTL32_SubclassProc); + } + else { + /* Check to see if we have called this function with the same uIDSubClass + * and pfnSubclass */ + proc = stack->SubclassProcs; + while (proc) { + if ((proc->id == uIDSubclass) && + (proc->subproc == pfnSubclass)) { + proc->ref = dwRef; + return TRUE; + } + proc = proc->next; + } + } + + proc = Alloc(sizeof(SUBCLASSPROCS)); + if (!proc) { + ERR ("Failed to allocate subclass entry in stack\n"); + if (IsWindowUnicode (hWnd)) + SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); + else + SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); + Free (stack); + RemovePropW( hWnd, COMCTL32_wSubclass ); + return FALSE; + } + + proc->subproc = pfnSubclass; + proc->ref = dwRef; + proc->id = uIDSubclass; + proc->next = stack->SubclassProcs; + stack->SubclassProcs = proc; + + return TRUE; +} + + +/*********************************************************************** + * GetWindowSubclass [COMCTL32.411] + * + * Gets the Reference data from a subclass. + * + * PARAMS + * hWnd [in] Handle to window which were subclassing + * pfnSubclass [in] Pointer to the subclass procedure + * uID [in] Unique indentifier of the subclassing procedure + * pdwRef [out] Pointer to the reference data + * + * RETURNS + * Success: Non-zero + * Failure: 0 + */ + +BOOL WINAPI GetWindowSubclass (HWND hWnd, SUBCLASSPROC pfnSubclass, + UINT_PTR uID, DWORD_PTR *pdwRef) +{ + LPSUBCLASS_INFO stack; + LPSUBCLASSPROCS proc; + + TRACE ("(%p, %p, %x, %p)\n", hWnd, pfnSubclass, uID, pdwRef); + + /* See if we have been called for this window */ + stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass); + if (!stack) + return FALSE; + + proc = stack->SubclassProcs; + while (proc) { + if ((proc->id == uID) && + (proc->subproc == pfnSubclass)) { + *pdwRef = proc->ref; + return TRUE; + } + proc = proc->next; + } + + return FALSE; +} + + +/*********************************************************************** + * RemoveWindowSubclass [COMCTL32.412] + * + * Removes a window subclass. + * + * PARAMS + * hWnd [in] Handle to the window were subclassing + * pfnSubclass [in] Pointer to the subclass procedure + * uID [in] Unique identifier of this subclass + * + * RETURNS + * Success: non-zero + * Failure: zero + */ + +BOOL WINAPI RemoveWindowSubclass(HWND hWnd, SUBCLASSPROC pfnSubclass, UINT_PTR uID) +{ + LPSUBCLASS_INFO stack; + LPSUBCLASSPROCS prevproc = NULL; + LPSUBCLASSPROCS proc; + BOOL ret = FALSE; + + TRACE ("(%p, %p, %x)\n", hWnd, pfnSubclass, uID); + + /* Find the Subclass to remove */ + stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass); + if (!stack) + return FALSE; + + proc = stack->SubclassProcs; + while (proc) { + if ((proc->id == uID) && + (proc->subproc == pfnSubclass)) { + + if (!prevproc) + stack->SubclassProcs = proc->next; + else + prevproc->next = proc->next; + + if (stack->stackpos == proc) + stack->stackpos = stack->stackpos->next; + + Free (proc); + ret = TRUE; + break; + } + prevproc = proc; + proc = proc->next; + } + + if (!stack->SubclassProcs && !stack->running) { + TRACE("Last Subclass removed, cleaning up\n"); + /* clean up our heap and reset the origional window procedure */ + if (IsWindowUnicode (hWnd)) + SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); + else + SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); + Free (stack); + RemovePropW( hWnd, COMCTL32_wSubclass ); + } + + return ret; +} + +/*********************************************************************** + * COMCTL32_SubclassProc (internal) + * + * Window procedure for all subclassed windows. + * Saves the current subclassing stack position to support nested messages + */ +LRESULT WINAPI COMCTL32_SubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + LPSUBCLASS_INFO stack; + LPSUBCLASSPROCS proc; + LRESULT ret; + + TRACE ("(%p, 0x%08x, 0x%08x, 0x%08lx)\n", hWnd, uMsg, wParam, lParam); + + stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass); + if (!stack) { + ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd); + return 0; + } + + /* Save our old stackpos to properly handle nested messages */ + proc = stack->stackpos; + stack->stackpos = stack->SubclassProcs; + stack->running++; + ret = DefSubclassProc(hWnd, uMsg, wParam, lParam); + stack->running--; + stack->stackpos = proc; + + if (!stack->SubclassProcs && !stack->running) { + TRACE("Last Subclass removed, cleaning up\n"); + /* clean up our heap and reset the origional window procedure */ + if (IsWindowUnicode (hWnd)) + SetWindowLongPtrW (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); + else + SetWindowLongPtrA (hWnd, GWLP_WNDPROC, (DWORD_PTR)stack->origproc); + Free (stack); + RemovePropW( hWnd, COMCTL32_wSubclass ); + } + return ret; +} + +/*********************************************************************** + * DefSubclassProc [COMCTL32.413] + * + * Calls the next window procedure (ie. the one before this subclass) + * + * PARAMS + * hWnd [in] The window that we're subclassing + * uMsg [in] Message + * wParam [in] WPARAM + * lParam [in] LPARAM + * + * RETURNS + * Success: non-zero + * Failure: zero + */ + +LRESULT WINAPI DefSubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + LPSUBCLASS_INFO stack; + LRESULT ret; + + TRACE ("(%p, 0x%08x, 0x%08x, 0x%08lx)\n", hWnd, uMsg, wParam, lParam); + + /* retrieve our little stack from the Properties */ + stack = (LPSUBCLASS_INFO)GetPropW (hWnd, COMCTL32_wSubclass); + if (!stack) { + ERR ("Our sub classing stack got erased for %p!! Nothing we can do\n", hWnd); + return 0; + } + + /* If we are at the end of stack then we have to call the original + * window procedure */ + if (!stack->stackpos) { + if (IsWindowUnicode (hWnd)) + ret = CallWindowProcW (stack->origproc, hWnd, uMsg, wParam, lParam); + else + ret = CallWindowProcA (stack->origproc, hWnd, uMsg, wParam, lParam); + } else { + LPSUBCLASSPROCS proc = stack->stackpos; + stack->stackpos = stack->stackpos->next; + /* call the Subclass procedure from the stack */ + ret = proc->subproc (hWnd, uMsg, wParam, lParam, + proc->id, proc->ref); + } + + return ret; +} + + +/*********************************************************************** + * COMCTL32_CreateToolTip [NOT AN API] + * + * Creates a tooltip for the control specified in hwnd and does all + * necessary setup and notifications. + * + * PARAMS + * hwndOwner [I] Handle to the window that will own the tool tip. + * + * RETURNS + * Success: Handle of tool tip window. + * Failure: NULL + */ + +HWND +COMCTL32_CreateToolTip(HWND hwndOwner) +{ + HWND hwndToolTip; + + hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, 0, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, hwndOwner, + 0, 0, 0); + + /* Send NM_TOOLTIPSCREATED notification */ + if (hwndToolTip) + { + NMTOOLTIPSCREATED nmttc; + /* true owner can be different if hwndOwner is a child window */ + HWND hwndTrueOwner = GetWindow(hwndToolTip, GW_OWNER); + nmttc.hdr.hwndFrom = hwndTrueOwner; + nmttc.hdr.idFrom = GetWindowLongPtrW(hwndTrueOwner, GWLP_ID); + nmttc.hdr.code = NM_TOOLTIPSCREATED; + nmttc.hwndToolTips = hwndToolTip; + + SendMessageW(GetParent(hwndTrueOwner), WM_NOTIFY, + (WPARAM)GetWindowLongPtrW(hwndTrueOwner, GWLP_ID), + (LPARAM)&nmttc); + } + + return hwndToolTip; +} + + +/*********************************************************************** + * COMCTL32_RefreshSysColors [NOT AN API] + * + * Invoked on any control recognizing a WM_SYSCOLORCHANGE message to + * refresh the color values in the color structure + * + * PARAMS + * none + * + * RETURNS + * none + */ + +VOID +COMCTL32_RefreshSysColors(void) +{ + comctl32_color.clrBtnHighlight = GetSysColor (COLOR_BTNHIGHLIGHT); + comctl32_color.clrBtnShadow = GetSysColor (COLOR_BTNSHADOW); + comctl32_color.clrBtnText = GetSysColor (COLOR_BTNTEXT); + comctl32_color.clrBtnFace = GetSysColor (COLOR_BTNFACE); + comctl32_color.clrHighlight = GetSysColor (COLOR_HIGHLIGHT); + comctl32_color.clrHighlightText = GetSysColor (COLOR_HIGHLIGHTTEXT); + comctl32_color.clr3dHilight = GetSysColor (COLOR_3DHILIGHT); + comctl32_color.clr3dShadow = GetSysColor (COLOR_3DSHADOW); + comctl32_color.clr3dDkShadow = GetSysColor (COLOR_3DDKSHADOW); + comctl32_color.clr3dFace = GetSysColor (COLOR_3DFACE); + comctl32_color.clrWindow = GetSysColor (COLOR_WINDOW); + comctl32_color.clrWindowText = GetSysColor (COLOR_WINDOWTEXT); + comctl32_color.clrGrayText = GetSysColor (COLOR_GRAYTEXT); + comctl32_color.clrActiveCaption = GetSysColor (COLOR_ACTIVECAPTION); + comctl32_color.clrInfoBk = GetSysColor (COLOR_INFOBK); + comctl32_color.clrInfoText = GetSysColor (COLOR_INFOTEXT); +} + +/*********************************************************************** + * COMCTL32_DrawInsertMark [NOT AN API] + * + * Draws an insertion mark (which looks similar to an 'I'). + * + * PARAMS + * hDC [I] Device context to draw onto. + * lpRect [I] Co-ordinates of insertion mark. + * clrInsertMark [I] Colour of the insertion mark. + * bHorizontal [I] True if insert mark should be drawn horizontally, + * vertical otherwise. + * + * RETURNS + * none + * + * NOTES + * Draws up to but not including the bottom co-ordinate when drawing + * vertically or the right co-ordinate when horizontal. + */ +void COMCTL32_DrawInsertMark(HDC hDC, const RECT *lpRect, COLORREF clrInsertMark, BOOL bHorizontal) +{ + HPEN hPen = CreatePen(PS_SOLID, 1, clrInsertMark); + HPEN hOldPen; + static const DWORD adwPolyPoints[] = {4,4,4}; + LONG lCentre = (bHorizontal ? + lpRect->top + (lpRect->bottom - lpRect->top)/2 : + lpRect->left + (lpRect->right - lpRect->left)/2); + LONG l1 = (bHorizontal ? lpRect->left : lpRect->top); + LONG l2 = (bHorizontal ? lpRect->right : lpRect->bottom); + const POINT aptInsertMark[] = + { + /* top (V) or left (H) arrow */ + {lCentre , l1 + 2}, + {lCentre - 2, l1 }, + {lCentre + 3, l1 }, + {lCentre + 1, l1 + 2}, + /* middle line */ + {lCentre , l2 - 2}, + {lCentre , l1 - 1}, + {lCentre + 1, l1 - 1}, + {lCentre + 1, l2 - 2}, + /* bottom (V) or right (H) arrow */ + {lCentre , l2 - 3}, + {lCentre - 2, l2 - 1}, + {lCentre + 3, l2 - 1}, + {lCentre + 1, l2 - 3}, + }; + hOldPen = SelectObject(hDC, hPen); + PolyPolyline(hDC, aptInsertMark, adwPolyPoints, sizeof(adwPolyPoints)/sizeof(adwPolyPoints[0])); + SelectObject(hDC, hOldPen); + DeleteObject(hPen); +} + +/*********************************************************************** + * MirrorIcon [COMCTL32.414] + * + * Mirrors an icon so that it will appear correctly on a mirrored DC. + * + * PARAMS + * phicon1 [I/O] Icon. + * phicon2 [I/O] Icon. + * + * RETURNS + * Success: TRUE. + * Failure: FALSE. + */ +BOOL WINAPI MirrorIcon(HICON *phicon1, HICON *phicon2) +{ + FIXME("(%p, %p): stub\n", phicon1, phicon2); + return FALSE; +} + +static inline int IsDelimiter(WCHAR c) +{ + switch(c) + { + case '/': + case '\\': + case '.': + case ' ': + return TRUE; + } + return FALSE; +} + +static int CALLBACK PathWordBreakProc(LPWSTR lpch, int ichCurrent, int cch, int code) +{ + if (code == WB_ISDELIMITER) + return IsDelimiter(lpch[ichCurrent]); + else + { + int dir = (code == WB_LEFT) ? -1 : 1; + for(; 0 <= ichCurrent && ichCurrent < cch; ichCurrent += dir) + if (IsDelimiter(lpch[ichCurrent])) return ichCurrent; + } + return ichCurrent; +} + +/*********************************************************************** + * SetPathWordBreakProc [COMCTL32.384] + * + * Sets the word break procedure for an edit control to one that understands + * paths so that the user can jump over directories. + * + * PARAMS + * hwnd [I] Handle to edit control. + * bSet [I] If this is TRUE then the word break proc is set, otherwise it is removed. + * + * RETURNS + * Result from EM_SETWORDBREAKPROC message. + */ +LRESULT WINAPI SetPathWordBreakProc(HWND hwnd, BOOL bSet) +{ + return SendMessageW(hwnd, EM_SETWORDBREAKPROC, 0, + (LPARAM)(bSet ? PathWordBreakProc : NULL)); +} diff --git a/reactos/lib/comctl32/datetime.c b/reactos/lib/comctl32/datetime.c index 7e25903eb15..9b8842d7c83 100644 --- a/reactos/lib/comctl32/datetime.c +++ b/reactos/lib/comctl32/datetime.c @@ -1,1348 +1,1348 @@ -/* - * Date and time picker control - * - * Copyright 1998, 1999 Eric Kohl - * Copyright 1999, 2000 Alex Priem - * Copyright 2000 Chris Morgan - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTE - * - * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on Oct. 20, 2004, by Dimitrie O. Paun. - * - * Unless otherwise noted, we believe this code to be complete, as per - * the specification mentioned above. - * If you discover missing features, or bugs, please note them below. - * - * TODO: - * -- DTS_APPCANPARSE - * -- DTS_SHORTDATECENTURYFORMAT - * -- DTN_CLOSEUP - * -- DTN_FORMAT - * -- DTN_FORMATQUERY - * -- DTN_USERSTRING - * -- DTN_WMKEYDOWN - * -- FORMATCALLBACK - */ - -#include -#include -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "comctl32.h" -#include "wine/debug.h" -#include "wine/unicode.h" - -WINE_DEFAULT_DEBUG_CHANNEL(datetime); - -typedef struct -{ - HWND hwndSelf; - HWND hMonthCal; - HWND hwndNotify; - HWND hUpdown; - DWORD dwStyle; - SYSTEMTIME date; - BOOL dateValid; - HWND hwndCheckbut; - RECT rcClient; /* rect around the edge of the window */ - RECT rcDraw; /* rect inside of the border */ - RECT checkbox; /* checkbox allowing the control to be enabled/disabled */ - RECT calbutton; /* button that toggles the dropdown of the monthcal control */ - BOOL bCalDepressed; /* TRUE = cal button is depressed */ - int select; - HFONT hFont; - int nrFieldsAllocated; - int nrFields; - int haveFocus; - int *fieldspec; - RECT *fieldRect; - int *buflen; - WCHAR textbuf[256]; - POINT monthcal_pos; - int pendingUpdown; -} DATETIME_INFO, *LPDATETIME_INFO; - -/* in monthcal.c */ -extern int MONTHCAL_MonthLength(int month, int year); - -/* this list of defines is closely related to `allowedformatchars' defined - * in datetime.c; the high nibble indicates the `base type' of the format - * specifier. - * Do not change without first reading DATETIME_UseFormat. - * - */ - -#define DT_END_FORMAT 0 -#define ONEDIGITDAY 0x01 -#define TWODIGITDAY 0x02 -#define THREECHARDAY 0x03 -#define FULLDAY 0x04 -#define ONEDIGIT12HOUR 0x11 -#define TWODIGIT12HOUR 0x12 -#define ONEDIGIT24HOUR 0x21 -#define TWODIGIT24HOUR 0x22 -#define ONEDIGITMINUTE 0x31 -#define TWODIGITMINUTE 0x32 -#define ONEDIGITMONTH 0x41 -#define TWODIGITMONTH 0x42 -#define THREECHARMONTH 0x43 -#define FULLMONTH 0x44 -#define ONEDIGITSECOND 0x51 -#define TWODIGITSECOND 0x52 -#define ONELETTERAMPM 0x61 -#define TWOLETTERAMPM 0x62 -#define ONEDIGITYEAR 0x71 -#define TWODIGITYEAR 0x72 -#define INVALIDFULLYEAR 0x73 /* FIXME - yyy is not valid - we'll treat it as yyyy */ -#define FULLYEAR 0x74 -#define FORMATCALLBACK 0x81 /* -> maximum of 0x80 callbacks possible */ -#define FORMATCALLMASK 0x80 -#define DT_STRING 0x0100 - -#define DTHT_DATEFIELD 0xff /* for hit-testing */ - -#define DTHT_NONE 0 -#define DTHT_CHECKBOX 0x200 /* these should end at '00' , to make */ -#define DTHT_MCPOPUP 0x300 /* & DTHT_DATEFIELD 0 when DATETIME_KeyDown */ -#define DTHT_GOTFOCUS 0x400 /* tests for date-fields */ - -static BOOL DATETIME_SendSimpleNotify (DATETIME_INFO *infoPtr, UINT code); -static BOOL DATETIME_SendDateTimeChangeNotify (DATETIME_INFO *infoPtr); -extern void MONTHCAL_CopyTime(const SYSTEMTIME *from, SYSTEMTIME *to); -static const WCHAR allowedformatchars[] = {'d', 'h', 'H', 'm', 'M', 's', 't', 'y', 'X', '\'', 0}; -static const int maxrepetition [] = {4,2,2,2,4,2,2,4,-1,-1}; - - -static DWORD -DATETIME_GetSystemTime (DATETIME_INFO *infoPtr, SYSTEMTIME *lprgSysTimeArray) -{ - if (!lprgSysTimeArray) return GDT_NONE; - - if ((infoPtr->dwStyle & DTS_SHOWNONE) && - (SendMessageW (infoPtr->hwndCheckbut, BM_GETCHECK, 0, 0) == BST_UNCHECKED)) - return GDT_NONE; - - MONTHCAL_CopyTime (&infoPtr->date, lprgSysTimeArray); - - return GDT_VALID; -} - - -static BOOL -DATETIME_SetSystemTime (DATETIME_INFO *infoPtr, DWORD flag, SYSTEMTIME *lprgSysTimeArray) -{ - if (!lprgSysTimeArray) return 0; - - TRACE("%04d/%02d/%02d %02d:%02d:%02d\n", - lprgSysTimeArray->wYear, lprgSysTimeArray->wMonth, lprgSysTimeArray->wDay, - lprgSysTimeArray->wHour, lprgSysTimeArray->wMinute, lprgSysTimeArray->wSecond); - - if (flag == GDT_VALID) { - infoPtr->dateValid = TRUE; - MONTHCAL_CopyTime (lprgSysTimeArray, &infoPtr->date); - SendMessageW (infoPtr->hMonthCal, MCM_SETCURSEL, 0, (LPARAM)(&infoPtr->date)); - SendMessageW (infoPtr->hwndCheckbut, BM_SETCHECK, BST_CHECKED, 0); - } else if (flag == GDT_NONE) { - infoPtr->dateValid = FALSE; - SendMessageW (infoPtr->hwndCheckbut, BM_SETCHECK, BST_UNCHECKED, 0); - } - - InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); - return TRUE; -} - - -/*** - * Split up a formattxt in actions. - * See ms documentation for the meaning of the letter codes/'specifiers'. - * - * Notes: - * *'dddddd' is handled as 'dddd' plus 'dd'. - * *unrecognized formats are strings (here given the type DT_STRING; - * start of the string is encoded in lower bits of DT_STRING. - * Therefore, 'string' ends finally up as 'tring'. - * - */ -static void -DATETIME_UseFormat (DATETIME_INFO *infoPtr, LPCWSTR formattxt) -{ - unsigned int i; - int j, k, len; - int *nrFields = &infoPtr->nrFields; - - *nrFields = 0; - infoPtr->fieldspec[*nrFields] = 0; - len = strlenW(allowedformatchars); - k = 0; - - for (i = 0; formattxt[i]; i++) { - TRACE ("\n%d %c:", i, formattxt[i]); - for (j = 0; j < len; j++) { - if (allowedformatchars[j]==formattxt[i]) { - TRACE ("%c[%d,%x]", allowedformatchars[j], *nrFields, infoPtr->fieldspec[*nrFields]); - if ((*nrFields==0) && (infoPtr->fieldspec[*nrFields]==0)) { - infoPtr->fieldspec[*nrFields] = (j<<4) + 1; - break; - } - if (infoPtr->fieldspec[*nrFields] >> 4 != j) { - (*nrFields)++; - infoPtr->fieldspec[*nrFields] = (j<<4) + 1; - break; - } - if ((infoPtr->fieldspec[*nrFields] & 0x0f) == maxrepetition[j]) { - (*nrFields)++; - infoPtr->fieldspec[*nrFields] = (j<<4) + 1; - break; - } - infoPtr->fieldspec[*nrFields]++; - break; - } /* if allowedformatchar */ - } /* for j */ - - /* char is not a specifier: handle char like a string */ - if (j == len) { - if ((*nrFields==0) && (infoPtr->fieldspec[*nrFields]==0)) { - infoPtr->fieldspec[*nrFields] = DT_STRING + k; - infoPtr->buflen[*nrFields] = 0; - } else if ((infoPtr->fieldspec[*nrFields] & DT_STRING) != DT_STRING) { - (*nrFields)++; - infoPtr->fieldspec[*nrFields] = DT_STRING + k; - infoPtr->buflen[*nrFields] = 0; - } - infoPtr->textbuf[k] = formattxt[i]; - k++; - infoPtr->buflen[*nrFields]++; - } /* if j=len */ - - if (*nrFields == infoPtr->nrFieldsAllocated) { - FIXME ("out of memory; should reallocate. crash ahead.\n"); - } - } /* for i */ - - TRACE("\n"); - - if (infoPtr->fieldspec[*nrFields] != 0) (*nrFields)++; -} - - -static BOOL -DATETIME_SetFormatW (DATETIME_INFO *infoPtr, LPCWSTR lpszFormat) -{ - if (!lpszFormat) { - WCHAR format_buf[80]; - DWORD format_item; - - if (infoPtr->dwStyle & DTS_LONGDATEFORMAT) - format_item = LOCALE_SLONGDATE; - else if ((infoPtr->dwStyle & DTS_TIMEFORMAT) == DTS_TIMEFORMAT) - format_item = LOCALE_STIMEFORMAT; - else /* DTS_SHORTDATEFORMAT */ - format_item = LOCALE_SSHORTDATE; - GetLocaleInfoW( GetSystemDefaultLCID(), format_item, format_buf, sizeof(format_buf)/sizeof(format_buf[0])); - lpszFormat = format_buf; - } - - DATETIME_UseFormat (infoPtr, lpszFormat); - InvalidateRect (infoPtr->hwndSelf, NULL, TRUE); - - return infoPtr->nrFields; -} - - -static BOOL -DATETIME_SetFormatA (DATETIME_INFO *infoPtr, LPCSTR lpszFormat) -{ - if (lpszFormat) { - BOOL retval; - INT len = MultiByteToWideChar(CP_ACP, 0, lpszFormat, -1, NULL, 0); - LPWSTR wstr = Alloc(len * sizeof(WCHAR)); - if (wstr) MultiByteToWideChar(CP_ACP, 0, lpszFormat, -1, wstr, len); - retval = DATETIME_SetFormatW (infoPtr, wstr); - Free (wstr); - return retval; - } - else - return DATETIME_SetFormatW (infoPtr, 0); - -} - - -static void -DATETIME_ReturnTxt (DATETIME_INFO *infoPtr, int count, LPWSTR result, int resultSize) -{ - static const WCHAR fmt_dW[] = { '%', 'd', 0 }; - static const WCHAR fmt__2dW[] = { '%', '.', '2', 'd', 0 }; - static const WCHAR fmt__3sW[] = { '%', '.', '3', 's', 0 }; - SYSTEMTIME date = infoPtr->date; - int spec; - WCHAR buffer[80]; - - *result=0; - TRACE ("%d,%d\n", infoPtr->nrFields, count); - if (count>infoPtr->nrFields || count < 0) { - WARN ("buffer overrun, have %d want %d\n", infoPtr->nrFields, count); - return; - } - - if (!infoPtr->fieldspec) return; - - spec = infoPtr->fieldspec[count]; - if (spec & DT_STRING) { - int txtlen = infoPtr->buflen[count]; - - if (txtlen > resultSize) - txtlen = resultSize - 1; - memcpy (result, infoPtr->textbuf + (spec &~ DT_STRING), txtlen * sizeof(WCHAR)); - result[txtlen] = 0; - TRACE ("arg%d=%x->[%s]\n", count, infoPtr->fieldspec[count], debugstr_w(result)); - return; - } - - - switch (spec) { - case DT_END_FORMAT: - *result = 0; - break; - case ONEDIGITDAY: - wsprintfW (result, fmt_dW, date.wDay); - break; - case TWODIGITDAY: - wsprintfW (result, fmt__2dW, date.wDay); - break; - case THREECHARDAY: - GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SABBREVDAYNAME1+(date.wDayOfWeek+6)%7, result, 4); - /*wsprintfW (result,"%.3s",days[date.wDayOfWeek]);*/ - break; - case FULLDAY: - GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDAYNAME1+(date.wDayOfWeek+6)%7, result, resultSize); - break; - case ONEDIGIT12HOUR: - if (date.wHour == 0) { - result[0] = '1'; - result[1] = '2'; - result[2] = 0; - } - else - wsprintfW (result, fmt_dW, date.wHour - (date.wHour > 12 ? 12 : 0)); - break; - case TWODIGIT12HOUR: - if (date.wHour == 0) { - result[0] = '1'; - result[1] = '2'; - result[2] = 0; - } - else - wsprintfW (result, fmt__2dW, date.wHour - (date.wHour > 12 ? 12 : 0)); - break; - case ONEDIGIT24HOUR: - wsprintfW (result, fmt_dW, date.wHour); - break; - case TWODIGIT24HOUR: - wsprintfW (result, fmt__2dW, date.wHour); - break; - case ONEDIGITSECOND: - wsprintfW (result, fmt_dW, date.wSecond); - break; - case TWODIGITSECOND: - wsprintfW (result, fmt__2dW, date.wSecond); - break; - case ONEDIGITMINUTE: - wsprintfW (result, fmt_dW, date.wMinute); - break; - case TWODIGITMINUTE: - wsprintfW (result, fmt__2dW, date.wMinute); - break; - case ONEDIGITMONTH: - wsprintfW (result, fmt_dW, date.wMonth); - break; - case TWODIGITMONTH: - wsprintfW (result, fmt__2dW, date.wMonth); - break; - case THREECHARMONTH: - GetLocaleInfoW(GetSystemDefaultLCID(), LOCALE_SMONTHNAME1+date.wMonth -1, - buffer, sizeof(buffer)/sizeof(buffer[0])); - wsprintfW (result, fmt__3sW, buffer); - break; - case FULLMONTH: - GetLocaleInfoW(GetSystemDefaultLCID(),LOCALE_SMONTHNAME1+date.wMonth -1, - result, resultSize); - break; - case ONELETTERAMPM: - result[0] = (date.wHour < 12 ? 'A' : 'P'); - result[1] = 0; - break; - case TWOLETTERAMPM: - result[0] = (date.wHour < 12 ? 'A' : 'P'); - result[1] = 'M'; - result[2] = 0; - break; - case FORMATCALLBACK: - FIXME ("Not implemented\n"); - result[0] = 'x'; - result[1] = 0; - break; - case ONEDIGITYEAR: - wsprintfW (result, fmt_dW, date.wYear-10* (int) floor(date.wYear/10)); - break; - case TWODIGITYEAR: - wsprintfW (result, fmt__2dW, date.wYear-100* (int) floor(date.wYear/100)); - break; - case INVALIDFULLYEAR: - case FULLYEAR: - wsprintfW (result, fmt_dW, date.wYear); - break; - } - - TRACE ("arg%d=%x->[%s]\n", count, infoPtr->fieldspec[count], debugstr_w(result)); -} - -/* Offsets of days in the week to the weekday of january 1 in a leap year. */ -static const int DayOfWeekTable[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; - -/* returns the day in the week(0 == sunday, 6 == saturday) */ -/* day(1 == 1st, 2 == 2nd... etc), year is the year value */ -static int DATETIME_CalculateDayOfWeek(DWORD day, DWORD month, DWORD year) -{ - year-=(month < 3); - - return((year + year/4 - year/100 + year/400 + - DayOfWeekTable[month-1] + day ) % 7); -} - -static int wrap(int val, int delta, int minVal, int maxVal) -{ - val += delta; - if (delta == INT_MIN || val < minVal) return maxVal; - if (delta == INT_MAX || val > maxVal) return minVal; - return val; -} - -static void -DATETIME_IncreaseField (DATETIME_INFO *infoPtr, int number, int delta) -{ - SYSTEMTIME *date = &infoPtr->date; - - TRACE ("%d\n", number); - if ((number > infoPtr->nrFields) || (number < 0)) return; - - if ((infoPtr->fieldspec[number] & DTHT_DATEFIELD) == 0) return; - - switch (infoPtr->fieldspec[number]) { - case ONEDIGITYEAR: - case TWODIGITYEAR: - case FULLYEAR: - date->wYear = wrap(date->wYear, delta, 1752, 9999); - date->wDayOfWeek = DATETIME_CalculateDayOfWeek(date->wDay,date->wMonth,date->wYear); - break; - case ONEDIGITMONTH: - case TWODIGITMONTH: - case THREECHARMONTH: - case FULLMONTH: - date->wMonth = wrap(date->wMonth, delta, 1, 12); - date->wDayOfWeek = DATETIME_CalculateDayOfWeek(date->wDay,date->wMonth,date->wYear); - delta = 0; - /* fall through */ - case ONEDIGITDAY: - case TWODIGITDAY: - case THREECHARDAY: - case FULLDAY: - date->wDay = wrap(date->wDay, delta, 1, MONTHCAL_MonthLength(date->wMonth, date->wYear)); - date->wDayOfWeek = DATETIME_CalculateDayOfWeek(date->wDay,date->wMonth,date->wYear); - break; - case ONELETTERAMPM: - case TWOLETTERAMPM: - delta *= 12; - /* fall through */ - case ONEDIGIT12HOUR: - case TWODIGIT12HOUR: - case ONEDIGIT24HOUR: - case TWODIGIT24HOUR: - date->wHour = wrap(date->wHour, delta, 0, 23); - break; - case ONEDIGITMINUTE: - case TWODIGITMINUTE: - date->wMinute = wrap(date->wMinute, delta, 0, 59); - break; - case ONEDIGITSECOND: - case TWODIGITSECOND: - date->wSecond = wrap(date->wSecond, delta, 0, 59); - break; - case FORMATCALLBACK: - FIXME ("Not implemented\n"); - break; - } - - /* FYI: On 1752/9/14 the calendar changed and England and the - * American colonies changed to the Gregorian calendar. This change - * involved having September 14th follow September 2nd. So no date - * algorithm works before that date. - */ - if (10000 * date->wYear + 100 * date->wMonth + date->wDay < 17520914) { - date->wYear = 1752; - date->wMonth = 9; - date->wDay = 14; - date->wSecond = 0; - date->wMinute = 0; - date->wHour = 0; - } -} - - -static void -DATETIME_ReturnFieldWidth (DATETIME_INFO *infoPtr, HDC hdc, int count, SHORT *fieldWidthPtr) -{ - /* fields are a fixed width, determined by the largest possible string */ - /* presumably, these widths should be language dependent */ - static const WCHAR fld_d1W[] = { '2', 0 }; - static const WCHAR fld_d2W[] = { '2', '2', 0 }; - static const WCHAR fld_d4W[] = { '2', '2', '2', '2', 0 }; - static const WCHAR fld_am1[] = { 'A', 0 }; - static const WCHAR fld_am2[] = { 'A', 'M', 0 }; - static const WCHAR fld_day[] = { 'W', 'e', 'd', 'n', 'e', 's', 'd', 'a', 'y', 0 }; - static const WCHAR fld_day3[] = { 'W', 'e', 'd', 0 }; - static const WCHAR fld_mon[] = { 'S', 'e', 'p', 't', 'e', 'm', 'b', 'e', 'r', 0 }; - static const WCHAR fld_mon3[] = { 'D', 'e', 'c', 0 }; - int spec; - WCHAR buffer[80], *bufptr; - SIZE size; - - TRACE ("%d,%d\n", infoPtr->nrFields, count); - if (count>infoPtr->nrFields || count < 0) { - WARN ("buffer overrun, have %d want %d\n", infoPtr->nrFields, count); - return; - } - - if (!infoPtr->fieldspec) return; - - spec = infoPtr->fieldspec[count]; - if (spec & DT_STRING) { - int txtlen = infoPtr->buflen[count]; - - if (txtlen > 79) - txtlen = 79; - memcpy (buffer, infoPtr->textbuf + (spec &~ DT_STRING), txtlen * sizeof(WCHAR)); - buffer[txtlen] = 0; - bufptr = buffer; - } - else { - switch (spec) { - case ONEDIGITDAY: - case ONEDIGIT12HOUR: - case ONEDIGIT24HOUR: - case ONEDIGITSECOND: - case ONEDIGITMINUTE: - case ONEDIGITMONTH: - case ONEDIGITYEAR: - /* these seem to use a two byte field */ - case TWODIGITDAY: - case TWODIGIT12HOUR: - case TWODIGIT24HOUR: - case TWODIGITSECOND: - case TWODIGITMINUTE: - case TWODIGITMONTH: - case TWODIGITYEAR: - bufptr = (WCHAR *)fld_d2W; - break; - case INVALIDFULLYEAR: - case FULLYEAR: - bufptr = (WCHAR *)fld_d4W; - break; - case THREECHARDAY: - bufptr = (WCHAR *)fld_day3; - break; - case FULLDAY: - bufptr = (WCHAR *)fld_day; - break; - case THREECHARMONTH: - bufptr = (WCHAR *)fld_mon3; - break; - case FULLMONTH: - bufptr = (WCHAR *)fld_mon; - break; - case ONELETTERAMPM: - bufptr = (WCHAR *)fld_am1; - break; - case TWOLETTERAMPM: - bufptr = (WCHAR *)fld_am2; - break; - default: - bufptr = (WCHAR *)fld_d1W; - break; - } - } - GetTextExtentPoint32W (hdc, bufptr, strlenW(bufptr), &size); - *fieldWidthPtr = size.cx; -} - -static void -DATETIME_Refresh (DATETIME_INFO *infoPtr, HDC hdc) -{ - int i,prevright; - RECT *field; - RECT *rcDraw = &infoPtr->rcDraw; - RECT *calbutton = &infoPtr->calbutton; - RECT *checkbox = &infoPtr->checkbox; - SIZE size; - COLORREF oldTextColor; - SHORT fieldWidth = 0; - - /* draw control edge */ - TRACE("\n"); - - if (infoPtr->dateValid) { - HFONT oldFont = SelectObject (hdc, infoPtr->hFont); - INT oldBkMode = SetBkMode (hdc, TRANSPARENT); - WCHAR txt[80]; - - DATETIME_ReturnTxt (infoPtr, 0, txt, sizeof(txt)/sizeof(txt[0])); - GetTextExtentPoint32W (hdc, txt, strlenW(txt), &size); - rcDraw->bottom = size.cy + 2; - - prevright = checkbox->right = ((infoPtr->dwStyle & DTS_SHOWNONE) ? 18 : 2); - - for (i = 0; i < infoPtr->nrFields; i++) { - DATETIME_ReturnTxt (infoPtr, i, txt, sizeof(txt)/sizeof(txt[0])); - GetTextExtentPoint32W (hdc, txt, strlenW(txt), &size); - DATETIME_ReturnFieldWidth (infoPtr, hdc, i, &fieldWidth); - field = &infoPtr->fieldRect[i]; - field->left = prevright; - field->right = prevright + fieldWidth; - field->top = rcDraw->top; - field->bottom = rcDraw->bottom; - prevright = field->right; - - if (infoPtr->dwStyle & WS_DISABLED) - oldTextColor = SetTextColor (hdc, comctl32_color.clrGrayText); - else if ((infoPtr->haveFocus) && (i == infoPtr->select)) { - /* fill if focussed */ - HBRUSH hbr = CreateSolidBrush (comctl32_color.clrActiveCaption); - FillRect(hdc, field, hbr); - DeleteObject (hbr); - oldTextColor = SetTextColor (hdc, comctl32_color.clrWindow); - } - else - oldTextColor = SetTextColor (hdc, comctl32_color.clrWindowText); - - /* draw the date text using the colour set above */ - DrawTextW (hdc, txt, strlenW(txt), field, DT_RIGHT | DT_VCENTER | DT_SINGLELINE); - SetTextColor (hdc, oldTextColor); - } - SetBkMode (hdc, oldBkMode); - SelectObject (hdc, oldFont); - } - - if (!(infoPtr->dwStyle & DTS_UPDOWN)) { - DrawFrameControl(hdc, calbutton, DFC_SCROLL, - DFCS_SCROLLDOWN | (infoPtr->bCalDepressed ? DFCS_PUSHED : 0) | - (infoPtr->dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) ); - } -} - - -static INT -DATETIME_HitTest (DATETIME_INFO *infoPtr, POINT pt) -{ - int i; - - TRACE ("%ld, %ld\n", pt.x, pt.y); - - if (PtInRect (&infoPtr->calbutton, pt)) return DTHT_MCPOPUP; - if (PtInRect (&infoPtr->checkbox, pt)) return DTHT_CHECKBOX; - - for (i=0; i < infoPtr->nrFields; i++) { - if (PtInRect (&infoPtr->fieldRect[i], pt)) return i; - } - - return DTHT_NONE; -} - - -static LRESULT -DATETIME_LButtonDown (DATETIME_INFO *infoPtr, WORD wKey, INT x, INT y) -{ - POINT pt; - int old, new; - - pt.x = x; - pt.y = y; - old = infoPtr->select; - new = DATETIME_HitTest (infoPtr, pt); - - /* FIXME: might be conditions where we don't want to update infoPtr->select */ - infoPtr->select = new; - - SetFocus(infoPtr->hwndSelf); - - if (infoPtr->select == DTHT_MCPOPUP) { - RECT rcMonthCal; - SendMessageW(infoPtr->hMonthCal, MCM_GETMINREQRECT, 0, (LPARAM)&rcMonthCal); - - /* FIXME: button actually is only depressed during dropdown of the */ - /* calendar control and when the mouse is over the button window */ - infoPtr->bCalDepressed = TRUE; - - /* recalculate the position of the monthcal popup */ - if(infoPtr->dwStyle & DTS_RIGHTALIGN) - infoPtr->monthcal_pos.x = infoPtr->calbutton.left - - (rcMonthCal.right - rcMonthCal.left); - else - /* FIXME: this should be after the area reserved for the checkbox */ - infoPtr->monthcal_pos.x = infoPtr->rcDraw.left; - - infoPtr->monthcal_pos.y = infoPtr->rcClient.bottom; - ClientToScreen (infoPtr->hwndSelf, &(infoPtr->monthcal_pos)); - SetWindowPos(infoPtr->hMonthCal, 0, infoPtr->monthcal_pos.x, - infoPtr->monthcal_pos.y, rcMonthCal.right - rcMonthCal.left, - rcMonthCal.bottom - rcMonthCal.top, 0); - - if(IsWindowVisible(infoPtr->hMonthCal)) { - ShowWindow(infoPtr->hMonthCal, SW_HIDE); - } else { - SYSTEMTIME *lprgSysTimeArray = &infoPtr->date; - TRACE("update calendar %04d/%02d/%02d\n", - lprgSysTimeArray->wYear, lprgSysTimeArray->wMonth, lprgSysTimeArray->wDay); - SendMessageW(infoPtr->hMonthCal, MCM_SETCURSEL, 0, (LPARAM)(&infoPtr->date)); - ShowWindow(infoPtr->hMonthCal, SW_SHOW); - } - - TRACE ("dt:%p mc:%p mc parent:%p, desktop:%p\n", - infoPtr->hwndSelf, infoPtr->hMonthCal, infoPtr->hwndNotify, GetDesktopWindow ()); - DATETIME_SendSimpleNotify (infoPtr, DTN_DROPDOWN); - } - - InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); - - return 0; -} - - -static LRESULT -DATETIME_LButtonUp (DATETIME_INFO *infoPtr, WORD wKey) -{ - if(infoPtr->bCalDepressed) { - infoPtr->bCalDepressed = FALSE; - InvalidateRect(infoPtr->hwndSelf, &(infoPtr->calbutton), TRUE); - } - - return 0; -} - - -static LRESULT -DATETIME_Paint (DATETIME_INFO *infoPtr, HDC hdc) -{ - if (!hdc) { - PAINTSTRUCT ps; - hdc = BeginPaint (infoPtr->hwndSelf, &ps); - DATETIME_Refresh (infoPtr, hdc); - EndPaint (infoPtr->hwndSelf, &ps); - } else { - DATETIME_Refresh (infoPtr, hdc); - } - return 0; -} - - -static LRESULT -DATETIME_Button_Command (DATETIME_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - if( HIWORD(wParam) == BN_CLICKED) { - DWORD state = SendMessageW((HWND)lParam, BM_GETCHECK, 0, 0); - infoPtr->dateValid = (state == BST_CHECKED); - InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); - } - return 0; -} - - - -static LRESULT -DATETIME_Command (DATETIME_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - TRACE("hwndbutton = %p\n", infoPtr->hwndCheckbut); - if(infoPtr->hwndCheckbut == (HWND)lParam) - return DATETIME_Button_Command(infoPtr, wParam, lParam); - return 0; -} - - -static LRESULT -DATETIME_Enable (DATETIME_INFO *infoPtr, BOOL bEnable) -{ - TRACE("%p %s\n", infoPtr, bEnable ? "TRUE" : "FALSE"); - if (bEnable) - infoPtr->dwStyle &= ~WS_DISABLED; - else - infoPtr->dwStyle |= WS_DISABLED; - return 0; -} - - -static LRESULT -DATETIME_EraseBackground (DATETIME_INFO *infoPtr, HDC hdc) -{ - HBRUSH hBrush, hSolidBrush = NULL; - RECT rc; - - if (infoPtr->dwStyle & WS_DISABLED) - hBrush = hSolidBrush = CreateSolidBrush(comctl32_color.clrBtnFace); - else - { - hBrush = (HBRUSH)SendMessageW(infoPtr->hwndNotify, WM_CTLCOLOREDIT, - (WPARAM)hdc, (LPARAM)infoPtr->hwndSelf); - if (!hBrush) - hBrush = hSolidBrush = CreateSolidBrush(comctl32_color.clrWindow); - } - - GetClientRect (infoPtr->hwndSelf, &rc); - - FillRect (hdc, &rc, hBrush); - - if (hSolidBrush) - DeleteObject(hSolidBrush); - - return -1; -} - - -static LRESULT -DATETIME_Notify (DATETIME_INFO *infoPtr, int idCtrl, LPNMHDR lpnmh) -{ - TRACE ("Got notification %x from %p\n", lpnmh->code, lpnmh->hwndFrom); - TRACE ("info: %p %p %p\n", infoPtr->hwndSelf, infoPtr->hMonthCal, infoPtr->hUpdown); - - if (lpnmh->code == MCN_SELECT) { - ShowWindow(infoPtr->hMonthCal, SW_HIDE); - infoPtr->dateValid = TRUE; - SendMessageW (infoPtr->hMonthCal, MCM_GETCURSEL, 0, (LPARAM)&infoPtr->date); - TRACE("got from calendar %04d/%02d/%02d day of week %d\n", - infoPtr->date.wYear, infoPtr->date.wMonth, infoPtr->date.wDay, infoPtr->date.wDayOfWeek); - SendMessageW (infoPtr->hwndCheckbut, BM_SETCHECK, BST_CHECKED, 0); - InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); - DATETIME_SendDateTimeChangeNotify (infoPtr); - } - if ((lpnmh->hwndFrom == infoPtr->hUpdown) && (lpnmh->code == UDN_DELTAPOS)) { - LPNMUPDOWN lpnmud = (LPNMUPDOWN)lpnmh; - TRACE("Delta pos %d\n", lpnmud->iDelta); - infoPtr->pendingUpdown = lpnmud->iDelta; - } - return 0; -} - - -static LRESULT -DATETIME_KeyDown (DATETIME_INFO *infoPtr, DWORD vkCode, LPARAM flags) -{ - int fieldNum = infoPtr->select & DTHT_DATEFIELD; - int wrap = 0; - - if (!(infoPtr->haveFocus)) return 0; - if ((fieldNum==0) && (infoPtr->select)) return 0; - - if (infoPtr->select & FORMATCALLMASK) { - FIXME ("Callbacks not implemented yet\n"); - } - - if (vkCode >= '0' && vkCode <= '9') { - /* this is a somewhat simplified version of what Windows does */ - SYSTEMTIME *date = &infoPtr->date; - switch (infoPtr->fieldspec[fieldNum]) { - case ONEDIGITYEAR: - case TWODIGITYEAR: - date->wYear = date->wYear - (date->wYear%100) + - (date->wYear%10)*10 + (vkCode-'0'); - date->wDayOfWeek = DATETIME_CalculateDayOfWeek( - date->wDay,date->wMonth,date->wYear); - DATETIME_SendDateTimeChangeNotify (infoPtr); - break; - case INVALIDFULLYEAR: - case FULLYEAR: - date->wYear = (date->wYear%1000)*10 + (vkCode-'0'); - date->wDayOfWeek = DATETIME_CalculateDayOfWeek( - date->wDay,date->wMonth,date->wYear); - DATETIME_SendDateTimeChangeNotify (infoPtr); - break; - case ONEDIGITMONTH: - case TWODIGITMONTH: - if ((date->wMonth%10) > 1 || (vkCode-'0') > 2) - date->wMonth = vkCode-'0'; - else - date->wMonth = (date->wMonth%10)*10+vkCode-'0'; - date->wDayOfWeek = DATETIME_CalculateDayOfWeek( - date->wDay,date->wMonth,date->wYear); - DATETIME_SendDateTimeChangeNotify (infoPtr); - break; - case ONEDIGITDAY: - case TWODIGITDAY: - /* probably better checking here would help */ - if ((date->wDay%10) >= 3 && (vkCode-'0') > 1) - date->wDay = vkCode-'0'; - else - date->wDay = (date->wDay%10)*10+vkCode-'0'; - date->wDayOfWeek = DATETIME_CalculateDayOfWeek( - date->wDay,date->wMonth,date->wYear); - DATETIME_SendDateTimeChangeNotify (infoPtr); - break; - case ONEDIGIT12HOUR: - case TWODIGIT12HOUR: - if ((date->wHour%10) > 1 || (vkCode-'0') > 2) - date->wHour = vkCode-'0'; - else - date->wHour = (date->wHour%10)*10+vkCode-'0'; - DATETIME_SendDateTimeChangeNotify (infoPtr); - break; - case ONEDIGIT24HOUR: - case TWODIGIT24HOUR: - if ((date->wHour%10) > 2) - date->wHour = vkCode-'0'; - else if ((date->wHour%10) == 2 && (vkCode-'0') > 3) - date->wHour = vkCode-'0'; - else - date->wHour = (date->wHour%10)*10+vkCode-'0'; - DATETIME_SendDateTimeChangeNotify (infoPtr); - break; - case ONEDIGITMINUTE: - case TWODIGITMINUTE: - if ((date->wMinute%10) > 5) - date->wMinute = vkCode-'0'; - else - date->wMinute = (date->wMinute%10)*10+vkCode-'0'; - DATETIME_SendDateTimeChangeNotify (infoPtr); - break; - case ONEDIGITSECOND: - case TWODIGITSECOND: - if ((date->wSecond%10) > 5) - date->wSecond = vkCode-'0'; - else - date->wSecond = (date->wSecond%10)*10+vkCode-'0'; - DATETIME_SendDateTimeChangeNotify (infoPtr); - break; - } - } - - switch (vkCode) { - case VK_ADD: - case VK_UP: - DATETIME_IncreaseField (infoPtr, fieldNum, 1); - DATETIME_SendDateTimeChangeNotify (infoPtr); - break; - case VK_SUBTRACT: - case VK_DOWN: - DATETIME_IncreaseField (infoPtr, fieldNum, -1); - DATETIME_SendDateTimeChangeNotify (infoPtr); - break; - case VK_HOME: - DATETIME_IncreaseField (infoPtr, fieldNum, INT_MIN); - DATETIME_SendDateTimeChangeNotify (infoPtr); - break; - case VK_END: - DATETIME_IncreaseField (infoPtr, fieldNum, INT_MAX); - DATETIME_SendDateTimeChangeNotify (infoPtr); - break; - case VK_LEFT: - do { - if (infoPtr->select == 0) { - infoPtr->select = infoPtr->nrFields - 1; - wrap++; - } else { - infoPtr->select--; - } - } while ((infoPtr->fieldspec[infoPtr->select] & DT_STRING) && (wrap<2)); - break; - case VK_RIGHT: - do { - infoPtr->select++; - if (infoPtr->select==infoPtr->nrFields) { - infoPtr->select = 0; - wrap++; - } - } while ((infoPtr->fieldspec[infoPtr->select] & DT_STRING) && (wrap<2)); - break; - } - - InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); - - return 0; -} - - -static LRESULT -DATETIME_VScroll (DATETIME_INFO *infoPtr, WORD wScroll) -{ - int fieldNum = infoPtr->select & DTHT_DATEFIELD; - - if ((SHORT)LOWORD(wScroll) != SB_THUMBPOSITION) return 0; - if (!(infoPtr->haveFocus)) return 0; - if ((fieldNum==0) && (infoPtr->select)) return 0; - - if (infoPtr->pendingUpdown >= 0) { - DATETIME_IncreaseField (infoPtr, fieldNum, 1); - DATETIME_SendDateTimeChangeNotify (infoPtr); - } - else { - DATETIME_IncreaseField (infoPtr, fieldNum, -1); - DATETIME_SendDateTimeChangeNotify (infoPtr); - } - - InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); - - return 0; -} - - -static LRESULT -DATETIME_KillFocus (DATETIME_INFO *infoPtr, HWND lostFocus) -{ - TRACE("lost focus to %p\n", lostFocus); - - if (infoPtr->haveFocus) { - DATETIME_SendSimpleNotify (infoPtr, NM_KILLFOCUS); - infoPtr->haveFocus = 0; - } - - InvalidateRect (infoPtr->hwndSelf, NULL, TRUE); - - return 0; -} - - -static LRESULT -DATETIME_NCCreate (HWND hwnd, LPCREATESTRUCTW lpcs) -{ - DWORD dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE); - /* force control to have client edge */ - dwExStyle |= WS_EX_CLIENTEDGE; - SetWindowLongW(hwnd, GWL_EXSTYLE, dwExStyle); - - return DefWindowProcW(hwnd, WM_NCCREATE, 0, (LPARAM)lpcs); -} - - -static LRESULT -DATETIME_SetFocus (DATETIME_INFO *infoPtr, HWND lostFocus) -{ - TRACE("got focus from %p\n", lostFocus); - - if (infoPtr->haveFocus == 0) { - DATETIME_SendSimpleNotify (infoPtr, NM_SETFOCUS); - infoPtr->haveFocus = DTHT_GOTFOCUS; - } - - InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); - - return 0; -} - - -static BOOL -DATETIME_SendDateTimeChangeNotify (DATETIME_INFO *infoPtr) -{ - NMDATETIMECHANGE dtdtc; - - dtdtc.nmhdr.hwndFrom = infoPtr->hwndSelf; - dtdtc.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); - dtdtc.nmhdr.code = DTN_DATETIMECHANGE; - - dtdtc.dwFlags = (infoPtr->dwStyle & DTS_SHOWNONE) ? GDT_NONE : GDT_VALID; - - MONTHCAL_CopyTime (&infoPtr->date, &dtdtc.st); - return (BOOL) SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, - (WPARAM)dtdtc.nmhdr.idFrom, (LPARAM)&dtdtc); -} - - -static BOOL -DATETIME_SendSimpleNotify (DATETIME_INFO *infoPtr, UINT code) -{ - NMHDR nmhdr; - - TRACE("%x\n", code); - nmhdr.hwndFrom = infoPtr->hwndSelf; - nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); - nmhdr.code = code; - - return (BOOL) SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, - (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr); -} - -static LRESULT -DATETIME_Size (DATETIME_INFO *infoPtr, WORD flags, INT width, INT height) -{ - /* set size */ - infoPtr->rcClient.bottom = height; - infoPtr->rcClient.right = width; - - TRACE("Height=%ld, Width=%ld\n", infoPtr->rcClient.bottom, infoPtr->rcClient.right); - - infoPtr->rcDraw = infoPtr->rcClient; - - if (infoPtr->dwStyle & DTS_UPDOWN) { - SetWindowPos(infoPtr->hUpdown, NULL, - infoPtr->rcClient.right-14, 0, - 15, infoPtr->rcClient.bottom - infoPtr->rcClient.top, - SWP_NOACTIVATE | SWP_NOZORDER); - } - else { - /* set the size of the button that drops the calendar down */ - /* FIXME: account for style that allows button on left side */ - infoPtr->calbutton.top = infoPtr->rcDraw.top; - infoPtr->calbutton.bottom= infoPtr->rcDraw.bottom; - infoPtr->calbutton.left = infoPtr->rcDraw.right-15; - infoPtr->calbutton.right = infoPtr->rcDraw.right; - } - - /* set enable/disable button size for show none style being enabled */ - /* FIXME: these dimensions are completely incorrect */ - infoPtr->checkbox.top = infoPtr->rcDraw.top; - infoPtr->checkbox.bottom = infoPtr->rcDraw.bottom; - infoPtr->checkbox.left = infoPtr->rcDraw.left; - infoPtr->checkbox.right = infoPtr->rcDraw.left + 10; - - InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); - - return 0; -} - - -static LRESULT -DATETIME_StyleChanged(DATETIME_INFO *infoPtr, WPARAM wStyleType, LPSTYLESTRUCT lpss) -{ - static const WCHAR buttonW[] = { 'b', 'u', 't', 't', 'o', 'n', 0 }; - - TRACE("(styletype=%x, styleOld=0x%08lx, styleNew=0x%08lx)\n", - wStyleType, lpss->styleOld, lpss->styleNew); - - if (wStyleType != GWL_STYLE) return 0; - - infoPtr->dwStyle = lpss->styleNew; - - if ( !(lpss->styleOld & DTS_SHOWNONE) && (lpss->styleNew & DTS_SHOWNONE) ) { - infoPtr->hwndCheckbut = CreateWindowExW (0, buttonW, 0, WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, - 2, 2, 13, 13, infoPtr->hwndSelf, 0, - (HINSTANCE)GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_HINSTANCE), 0); - SendMessageW (infoPtr->hwndCheckbut, BM_SETCHECK, 1, 0); - } - if ( (lpss->styleOld & DTS_SHOWNONE) && !(lpss->styleNew & DTS_SHOWNONE) ) { - DestroyWindow(infoPtr->hwndCheckbut); - infoPtr->hwndCheckbut = 0; - } - if ( !(lpss->styleOld & DTS_UPDOWN) && (lpss->styleNew & DTS_UPDOWN) ) { - infoPtr->hUpdown = CreateUpDownControl (WS_CHILD | WS_BORDER | WS_VISIBLE, 120, 1, 20, 20, - infoPtr->hwndSelf, 1, 0, 0, UD_MAXVAL, UD_MINVAL, 0); - } - if ( (lpss->styleOld & DTS_UPDOWN) && !(lpss->styleNew & DTS_UPDOWN) ) { - DestroyWindow(infoPtr->hUpdown); - infoPtr->hUpdown = 0; - } - - InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); - return 0; -} - - -static LRESULT -DATETIME_Create (HWND hwnd, LPCREATESTRUCTW lpcs) -{ - static const WCHAR SysMonthCal32W[] = { 'S', 'y', 's', 'M', 'o', 'n', 't', 'h', 'C', 'a', 'l', '3', '2', 0 }; - DATETIME_INFO *infoPtr = (DATETIME_INFO *)Alloc (sizeof(DATETIME_INFO)); - STYLESTRUCT ss = { 0, lpcs->style }; - - if (!infoPtr) return -1; - - infoPtr->hwndSelf = hwnd; - infoPtr->dwStyle = lpcs->style; - - infoPtr->nrFieldsAllocated = 32; - infoPtr->fieldspec = (int *) Alloc (infoPtr->nrFieldsAllocated * sizeof(int)); - infoPtr->fieldRect = (RECT *) Alloc (infoPtr->nrFieldsAllocated * sizeof(RECT)); - infoPtr->buflen = (int *) Alloc (infoPtr->nrFieldsAllocated * sizeof(int)); - infoPtr->hwndNotify = lpcs->hwndParent; - infoPtr->select = -1; /* initially, nothing is selected */ - - DATETIME_StyleChanged(infoPtr, GWL_STYLE, &ss); - DATETIME_SetFormatW (infoPtr, 0); - - /* create the monthcal control */ - infoPtr->hMonthCal = CreateWindowExW (0, SysMonthCal32W, 0, WS_BORDER | WS_POPUP | WS_CLIPSIBLINGS, - 0, 0, 0, 0, infoPtr->hwndSelf, 0, 0, 0); - - /* initialize info structure */ - GetLocalTime (&infoPtr->date); - infoPtr->dateValid = TRUE; - infoPtr->hFont = GetStockObject(DEFAULT_GUI_FONT); - - SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); - - return 0; -} - - - -static LRESULT -DATETIME_Destroy (DATETIME_INFO *infoPtr) -{ - if (infoPtr->hwndCheckbut) - DestroyWindow(infoPtr->hwndCheckbut); - if (infoPtr->hUpdown) - DestroyWindow(infoPtr->hUpdown); - if (infoPtr->hMonthCal) - DestroyWindow(infoPtr->hMonthCal); - SetWindowLongPtrW( infoPtr->hwndSelf, 0, 0 ); /* clear infoPtr */ - Free (infoPtr); - return 0; -} - - -static LRESULT WINAPI -DATETIME_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - DATETIME_INFO *infoPtr = ((DATETIME_INFO *)GetWindowLongPtrW (hwnd, 0)); - LRESULT ret; - - TRACE ("%x, %x, %lx\n", uMsg, wParam, lParam); - - if (!infoPtr && (uMsg != WM_CREATE) && (uMsg != WM_NCCREATE)) - return DefWindowProcW( hwnd, uMsg, wParam, lParam ); - - switch (uMsg) { - - case DTM_GETSYSTEMTIME: - return DATETIME_GetSystemTime (infoPtr, (SYSTEMTIME *) lParam); - - case DTM_SETSYSTEMTIME: - return DATETIME_SetSystemTime (infoPtr, wParam, (SYSTEMTIME *) lParam); - - case DTM_GETRANGE: - ret = SendMessageW (infoPtr->hMonthCal, MCM_GETRANGE, wParam, lParam); - return ret ? ret : 1; /* bug emulation */ - - case DTM_SETRANGE: - return SendMessageW (infoPtr->hMonthCal, MCM_SETRANGE, wParam, lParam); - - case DTM_SETFORMATA: - return DATETIME_SetFormatA (infoPtr, (LPCSTR)lParam); - - case DTM_SETFORMATW: - return DATETIME_SetFormatW (infoPtr, (LPCWSTR)lParam); - - case DTM_GETMONTHCAL: - return (LRESULT)infoPtr->hMonthCal; - - case DTM_SETMCCOLOR: - return SendMessageW (infoPtr->hMonthCal, MCM_SETCOLOR, wParam, lParam); - - case DTM_GETMCCOLOR: - return SendMessageW (infoPtr->hMonthCal, MCM_GETCOLOR, wParam, 0); - - case DTM_SETMCFONT: - return SendMessageW (infoPtr->hMonthCal, WM_SETFONT, wParam, lParam); - - case DTM_GETMCFONT: - return SendMessageW (infoPtr->hMonthCal, WM_GETFONT, wParam, lParam); - - case WM_NOTIFY: - return DATETIME_Notify (infoPtr, (int)wParam, (LPNMHDR)lParam); - - case WM_ENABLE: - return DATETIME_Enable (infoPtr, (BOOL)wParam); - - case WM_ERASEBKGND: - return DATETIME_EraseBackground (infoPtr, (HDC)wParam); - - case WM_GETDLGCODE: - return DLGC_WANTARROWS | DLGC_WANTCHARS; - - case WM_PAINT: - return DATETIME_Paint (infoPtr, (HDC)wParam); - - case WM_KEYDOWN: - return DATETIME_KeyDown (infoPtr, wParam, lParam); - - case WM_KILLFOCUS: - return DATETIME_KillFocus (infoPtr, (HWND)wParam); - - case WM_NCCREATE: - return DATETIME_NCCreate (hwnd, (LPCREATESTRUCTW)lParam); - - case WM_SETFOCUS: - return DATETIME_SetFocus (infoPtr, (HWND)wParam); - - case WM_SIZE: - return DATETIME_Size (infoPtr, wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); - - case WM_LBUTTONDOWN: - return DATETIME_LButtonDown (infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); - - case WM_LBUTTONUP: - return DATETIME_LButtonUp (infoPtr, (WORD)wParam); - - case WM_VSCROLL: - return DATETIME_VScroll (infoPtr, (WORD)wParam); - - case WM_CREATE: - return DATETIME_Create (hwnd, (LPCREATESTRUCTW)lParam); - - case WM_DESTROY: - return DATETIME_Destroy (infoPtr); - - case WM_COMMAND: - return DATETIME_Command (infoPtr, wParam, lParam); - - case WM_STYLECHANGED: - return DATETIME_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam); - - default: - if ((uMsg >= WM_USER) && (uMsg < WM_APP)) - ERR("unknown msg %04x wp=%08x lp=%08lx\n", - uMsg, wParam, lParam); - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - } -} - - -void -DATETIME_Register (void) -{ - WNDCLASSW wndClass; - - ZeroMemory (&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS; - wndClass.lpfnWndProc = DATETIME_WindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(DATETIME_INFO *); - wndClass.hCursor = LoadCursorW (0, (LPCWSTR)IDC_ARROW); - wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wndClass.lpszClassName = DATETIMEPICK_CLASSW; - - RegisterClassW (&wndClass); -} - - -void -DATETIME_Unregister (void) -{ - UnregisterClassW (DATETIMEPICK_CLASSW, NULL); -} +/* + * Date and time picker control + * + * Copyright 1998, 1999 Eric Kohl + * Copyright 1999, 2000 Alex Priem + * Copyright 2000 Chris Morgan + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTE + * + * This code was audited for completeness against the documented features + * of Comctl32.dll version 6.0 on Oct. 20, 2004, by Dimitrie O. Paun. + * + * Unless otherwise noted, we believe this code to be complete, as per + * the specification mentioned above. + * If you discover missing features, or bugs, please note them below. + * + * TODO: + * -- DTS_APPCANPARSE + * -- DTS_SHORTDATECENTURYFORMAT + * -- DTN_CLOSEUP + * -- DTN_FORMAT + * -- DTN_FORMATQUERY + * -- DTN_USERSTRING + * -- DTN_WMKEYDOWN + * -- FORMATCALLBACK + */ + +#include +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "comctl32.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +WINE_DEFAULT_DEBUG_CHANNEL(datetime); + +typedef struct +{ + HWND hwndSelf; + HWND hMonthCal; + HWND hwndNotify; + HWND hUpdown; + DWORD dwStyle; + SYSTEMTIME date; + BOOL dateValid; + HWND hwndCheckbut; + RECT rcClient; /* rect around the edge of the window */ + RECT rcDraw; /* rect inside of the border */ + RECT checkbox; /* checkbox allowing the control to be enabled/disabled */ + RECT calbutton; /* button that toggles the dropdown of the monthcal control */ + BOOL bCalDepressed; /* TRUE = cal button is depressed */ + int select; + HFONT hFont; + int nrFieldsAllocated; + int nrFields; + int haveFocus; + int *fieldspec; + RECT *fieldRect; + int *buflen; + WCHAR textbuf[256]; + POINT monthcal_pos; + int pendingUpdown; +} DATETIME_INFO, *LPDATETIME_INFO; + +/* in monthcal.c */ +extern int MONTHCAL_MonthLength(int month, int year); + +/* this list of defines is closely related to `allowedformatchars' defined + * in datetime.c; the high nibble indicates the `base type' of the format + * specifier. + * Do not change without first reading DATETIME_UseFormat. + * + */ + +#define DT_END_FORMAT 0 +#define ONEDIGITDAY 0x01 +#define TWODIGITDAY 0x02 +#define THREECHARDAY 0x03 +#define FULLDAY 0x04 +#define ONEDIGIT12HOUR 0x11 +#define TWODIGIT12HOUR 0x12 +#define ONEDIGIT24HOUR 0x21 +#define TWODIGIT24HOUR 0x22 +#define ONEDIGITMINUTE 0x31 +#define TWODIGITMINUTE 0x32 +#define ONEDIGITMONTH 0x41 +#define TWODIGITMONTH 0x42 +#define THREECHARMONTH 0x43 +#define FULLMONTH 0x44 +#define ONEDIGITSECOND 0x51 +#define TWODIGITSECOND 0x52 +#define ONELETTERAMPM 0x61 +#define TWOLETTERAMPM 0x62 +#define ONEDIGITYEAR 0x71 +#define TWODIGITYEAR 0x72 +#define INVALIDFULLYEAR 0x73 /* FIXME - yyy is not valid - we'll treat it as yyyy */ +#define FULLYEAR 0x74 +#define FORMATCALLBACK 0x81 /* -> maximum of 0x80 callbacks possible */ +#define FORMATCALLMASK 0x80 +#define DT_STRING 0x0100 + +#define DTHT_DATEFIELD 0xff /* for hit-testing */ + +#define DTHT_NONE 0 +#define DTHT_CHECKBOX 0x200 /* these should end at '00' , to make */ +#define DTHT_MCPOPUP 0x300 /* & DTHT_DATEFIELD 0 when DATETIME_KeyDown */ +#define DTHT_GOTFOCUS 0x400 /* tests for date-fields */ + +static BOOL DATETIME_SendSimpleNotify (DATETIME_INFO *infoPtr, UINT code); +static BOOL DATETIME_SendDateTimeChangeNotify (DATETIME_INFO *infoPtr); +extern void MONTHCAL_CopyTime(const SYSTEMTIME *from, SYSTEMTIME *to); +static const WCHAR allowedformatchars[] = {'d', 'h', 'H', 'm', 'M', 's', 't', 'y', 'X', '\'', 0}; +static const int maxrepetition [] = {4,2,2,2,4,2,2,4,-1,-1}; + + +static DWORD +DATETIME_GetSystemTime (DATETIME_INFO *infoPtr, SYSTEMTIME *lprgSysTimeArray) +{ + if (!lprgSysTimeArray) return GDT_NONE; + + if ((infoPtr->dwStyle & DTS_SHOWNONE) && + (SendMessageW (infoPtr->hwndCheckbut, BM_GETCHECK, 0, 0) == BST_UNCHECKED)) + return GDT_NONE; + + MONTHCAL_CopyTime (&infoPtr->date, lprgSysTimeArray); + + return GDT_VALID; +} + + +static BOOL +DATETIME_SetSystemTime (DATETIME_INFO *infoPtr, DWORD flag, SYSTEMTIME *lprgSysTimeArray) +{ + if (!lprgSysTimeArray) return 0; + + TRACE("%04d/%02d/%02d %02d:%02d:%02d\n", + lprgSysTimeArray->wYear, lprgSysTimeArray->wMonth, lprgSysTimeArray->wDay, + lprgSysTimeArray->wHour, lprgSysTimeArray->wMinute, lprgSysTimeArray->wSecond); + + if (flag == GDT_VALID) { + infoPtr->dateValid = TRUE; + MONTHCAL_CopyTime (lprgSysTimeArray, &infoPtr->date); + SendMessageW (infoPtr->hMonthCal, MCM_SETCURSEL, 0, (LPARAM)(&infoPtr->date)); + SendMessageW (infoPtr->hwndCheckbut, BM_SETCHECK, BST_CHECKED, 0); + } else if (flag == GDT_NONE) { + infoPtr->dateValid = FALSE; + SendMessageW (infoPtr->hwndCheckbut, BM_SETCHECK, BST_UNCHECKED, 0); + } + + InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); + return TRUE; +} + + +/*** + * Split up a formattxt in actions. + * See ms documentation for the meaning of the letter codes/'specifiers'. + * + * Notes: + * *'dddddd' is handled as 'dddd' plus 'dd'. + * *unrecognized formats are strings (here given the type DT_STRING; + * start of the string is encoded in lower bits of DT_STRING. + * Therefore, 'string' ends finally up as 'tring'. + * + */ +static void +DATETIME_UseFormat (DATETIME_INFO *infoPtr, LPCWSTR formattxt) +{ + unsigned int i; + int j, k, len; + int *nrFields = &infoPtr->nrFields; + + *nrFields = 0; + infoPtr->fieldspec[*nrFields] = 0; + len = strlenW(allowedformatchars); + k = 0; + + for (i = 0; formattxt[i]; i++) { + TRACE ("\n%d %c:", i, formattxt[i]); + for (j = 0; j < len; j++) { + if (allowedformatchars[j]==formattxt[i]) { + TRACE ("%c[%d,%x]", allowedformatchars[j], *nrFields, infoPtr->fieldspec[*nrFields]); + if ((*nrFields==0) && (infoPtr->fieldspec[*nrFields]==0)) { + infoPtr->fieldspec[*nrFields] = (j<<4) + 1; + break; + } + if (infoPtr->fieldspec[*nrFields] >> 4 != j) { + (*nrFields)++; + infoPtr->fieldspec[*nrFields] = (j<<4) + 1; + break; + } + if ((infoPtr->fieldspec[*nrFields] & 0x0f) == maxrepetition[j]) { + (*nrFields)++; + infoPtr->fieldspec[*nrFields] = (j<<4) + 1; + break; + } + infoPtr->fieldspec[*nrFields]++; + break; + } /* if allowedformatchar */ + } /* for j */ + + /* char is not a specifier: handle char like a string */ + if (j == len) { + if ((*nrFields==0) && (infoPtr->fieldspec[*nrFields]==0)) { + infoPtr->fieldspec[*nrFields] = DT_STRING + k; + infoPtr->buflen[*nrFields] = 0; + } else if ((infoPtr->fieldspec[*nrFields] & DT_STRING) != DT_STRING) { + (*nrFields)++; + infoPtr->fieldspec[*nrFields] = DT_STRING + k; + infoPtr->buflen[*nrFields] = 0; + } + infoPtr->textbuf[k] = formattxt[i]; + k++; + infoPtr->buflen[*nrFields]++; + } /* if j=len */ + + if (*nrFields == infoPtr->nrFieldsAllocated) { + FIXME ("out of memory; should reallocate. crash ahead.\n"); + } + } /* for i */ + + TRACE("\n"); + + if (infoPtr->fieldspec[*nrFields] != 0) (*nrFields)++; +} + + +static BOOL +DATETIME_SetFormatW (DATETIME_INFO *infoPtr, LPCWSTR lpszFormat) +{ + if (!lpszFormat) { + WCHAR format_buf[80]; + DWORD format_item; + + if (infoPtr->dwStyle & DTS_LONGDATEFORMAT) + format_item = LOCALE_SLONGDATE; + else if ((infoPtr->dwStyle & DTS_TIMEFORMAT) == DTS_TIMEFORMAT) + format_item = LOCALE_STIMEFORMAT; + else /* DTS_SHORTDATEFORMAT */ + format_item = LOCALE_SSHORTDATE; + GetLocaleInfoW( GetSystemDefaultLCID(), format_item, format_buf, sizeof(format_buf)/sizeof(format_buf[0])); + lpszFormat = format_buf; + } + + DATETIME_UseFormat (infoPtr, lpszFormat); + InvalidateRect (infoPtr->hwndSelf, NULL, TRUE); + + return infoPtr->nrFields; +} + + +static BOOL +DATETIME_SetFormatA (DATETIME_INFO *infoPtr, LPCSTR lpszFormat) +{ + if (lpszFormat) { + BOOL retval; + INT len = MultiByteToWideChar(CP_ACP, 0, lpszFormat, -1, NULL, 0); + LPWSTR wstr = Alloc(len * sizeof(WCHAR)); + if (wstr) MultiByteToWideChar(CP_ACP, 0, lpszFormat, -1, wstr, len); + retval = DATETIME_SetFormatW (infoPtr, wstr); + Free (wstr); + return retval; + } + else + return DATETIME_SetFormatW (infoPtr, 0); + +} + + +static void +DATETIME_ReturnTxt (DATETIME_INFO *infoPtr, int count, LPWSTR result, int resultSize) +{ + static const WCHAR fmt_dW[] = { '%', 'd', 0 }; + static const WCHAR fmt__2dW[] = { '%', '.', '2', 'd', 0 }; + static const WCHAR fmt__3sW[] = { '%', '.', '3', 's', 0 }; + SYSTEMTIME date = infoPtr->date; + int spec; + WCHAR buffer[80]; + + *result=0; + TRACE ("%d,%d\n", infoPtr->nrFields, count); + if (count>infoPtr->nrFields || count < 0) { + WARN ("buffer overrun, have %d want %d\n", infoPtr->nrFields, count); + return; + } + + if (!infoPtr->fieldspec) return; + + spec = infoPtr->fieldspec[count]; + if (spec & DT_STRING) { + int txtlen = infoPtr->buflen[count]; + + if (txtlen > resultSize) + txtlen = resultSize - 1; + memcpy (result, infoPtr->textbuf + (spec &~ DT_STRING), txtlen * sizeof(WCHAR)); + result[txtlen] = 0; + TRACE ("arg%d=%x->[%s]\n", count, infoPtr->fieldspec[count], debugstr_w(result)); + return; + } + + + switch (spec) { + case DT_END_FORMAT: + *result = 0; + break; + case ONEDIGITDAY: + wsprintfW (result, fmt_dW, date.wDay); + break; + case TWODIGITDAY: + wsprintfW (result, fmt__2dW, date.wDay); + break; + case THREECHARDAY: + GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SABBREVDAYNAME1+(date.wDayOfWeek+6)%7, result, 4); + /*wsprintfW (result,"%.3s",days[date.wDayOfWeek]);*/ + break; + case FULLDAY: + GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDAYNAME1+(date.wDayOfWeek+6)%7, result, resultSize); + break; + case ONEDIGIT12HOUR: + if (date.wHour == 0) { + result[0] = '1'; + result[1] = '2'; + result[2] = 0; + } + else + wsprintfW (result, fmt_dW, date.wHour - (date.wHour > 12 ? 12 : 0)); + break; + case TWODIGIT12HOUR: + if (date.wHour == 0) { + result[0] = '1'; + result[1] = '2'; + result[2] = 0; + } + else + wsprintfW (result, fmt__2dW, date.wHour - (date.wHour > 12 ? 12 : 0)); + break; + case ONEDIGIT24HOUR: + wsprintfW (result, fmt_dW, date.wHour); + break; + case TWODIGIT24HOUR: + wsprintfW (result, fmt__2dW, date.wHour); + break; + case ONEDIGITSECOND: + wsprintfW (result, fmt_dW, date.wSecond); + break; + case TWODIGITSECOND: + wsprintfW (result, fmt__2dW, date.wSecond); + break; + case ONEDIGITMINUTE: + wsprintfW (result, fmt_dW, date.wMinute); + break; + case TWODIGITMINUTE: + wsprintfW (result, fmt__2dW, date.wMinute); + break; + case ONEDIGITMONTH: + wsprintfW (result, fmt_dW, date.wMonth); + break; + case TWODIGITMONTH: + wsprintfW (result, fmt__2dW, date.wMonth); + break; + case THREECHARMONTH: + GetLocaleInfoW(GetSystemDefaultLCID(), LOCALE_SMONTHNAME1+date.wMonth -1, + buffer, sizeof(buffer)/sizeof(buffer[0])); + wsprintfW (result, fmt__3sW, buffer); + break; + case FULLMONTH: + GetLocaleInfoW(GetSystemDefaultLCID(),LOCALE_SMONTHNAME1+date.wMonth -1, + result, resultSize); + break; + case ONELETTERAMPM: + result[0] = (date.wHour < 12 ? 'A' : 'P'); + result[1] = 0; + break; + case TWOLETTERAMPM: + result[0] = (date.wHour < 12 ? 'A' : 'P'); + result[1] = 'M'; + result[2] = 0; + break; + case FORMATCALLBACK: + FIXME ("Not implemented\n"); + result[0] = 'x'; + result[1] = 0; + break; + case ONEDIGITYEAR: + wsprintfW (result, fmt_dW, date.wYear-10* (int) floor(date.wYear/10)); + break; + case TWODIGITYEAR: + wsprintfW (result, fmt__2dW, date.wYear-100* (int) floor(date.wYear/100)); + break; + case INVALIDFULLYEAR: + case FULLYEAR: + wsprintfW (result, fmt_dW, date.wYear); + break; + } + + TRACE ("arg%d=%x->[%s]\n", count, infoPtr->fieldspec[count], debugstr_w(result)); +} + +/* Offsets of days in the week to the weekday of january 1 in a leap year. */ +static const int DayOfWeekTable[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; + +/* returns the day in the week(0 == sunday, 6 == saturday) */ +/* day(1 == 1st, 2 == 2nd... etc), year is the year value */ +static int DATETIME_CalculateDayOfWeek(DWORD day, DWORD month, DWORD year) +{ + year-=(month < 3); + + return((year + year/4 - year/100 + year/400 + + DayOfWeekTable[month-1] + day ) % 7); +} + +static int wrap(int val, int delta, int minVal, int maxVal) +{ + val += delta; + if (delta == INT_MIN || val < minVal) return maxVal; + if (delta == INT_MAX || val > maxVal) return minVal; + return val; +} + +static void +DATETIME_IncreaseField (DATETIME_INFO *infoPtr, int number, int delta) +{ + SYSTEMTIME *date = &infoPtr->date; + + TRACE ("%d\n", number); + if ((number > infoPtr->nrFields) || (number < 0)) return; + + if ((infoPtr->fieldspec[number] & DTHT_DATEFIELD) == 0) return; + + switch (infoPtr->fieldspec[number]) { + case ONEDIGITYEAR: + case TWODIGITYEAR: + case FULLYEAR: + date->wYear = wrap(date->wYear, delta, 1752, 9999); + date->wDayOfWeek = DATETIME_CalculateDayOfWeek(date->wDay,date->wMonth,date->wYear); + break; + case ONEDIGITMONTH: + case TWODIGITMONTH: + case THREECHARMONTH: + case FULLMONTH: + date->wMonth = wrap(date->wMonth, delta, 1, 12); + date->wDayOfWeek = DATETIME_CalculateDayOfWeek(date->wDay,date->wMonth,date->wYear); + delta = 0; + /* fall through */ + case ONEDIGITDAY: + case TWODIGITDAY: + case THREECHARDAY: + case FULLDAY: + date->wDay = wrap(date->wDay, delta, 1, MONTHCAL_MonthLength(date->wMonth, date->wYear)); + date->wDayOfWeek = DATETIME_CalculateDayOfWeek(date->wDay,date->wMonth,date->wYear); + break; + case ONELETTERAMPM: + case TWOLETTERAMPM: + delta *= 12; + /* fall through */ + case ONEDIGIT12HOUR: + case TWODIGIT12HOUR: + case ONEDIGIT24HOUR: + case TWODIGIT24HOUR: + date->wHour = wrap(date->wHour, delta, 0, 23); + break; + case ONEDIGITMINUTE: + case TWODIGITMINUTE: + date->wMinute = wrap(date->wMinute, delta, 0, 59); + break; + case ONEDIGITSECOND: + case TWODIGITSECOND: + date->wSecond = wrap(date->wSecond, delta, 0, 59); + break; + case FORMATCALLBACK: + FIXME ("Not implemented\n"); + break; + } + + /* FYI: On 1752/9/14 the calendar changed and England and the + * American colonies changed to the Gregorian calendar. This change + * involved having September 14th follow September 2nd. So no date + * algorithm works before that date. + */ + if (10000 * date->wYear + 100 * date->wMonth + date->wDay < 17520914) { + date->wYear = 1752; + date->wMonth = 9; + date->wDay = 14; + date->wSecond = 0; + date->wMinute = 0; + date->wHour = 0; + } +} + + +static void +DATETIME_ReturnFieldWidth (DATETIME_INFO *infoPtr, HDC hdc, int count, SHORT *fieldWidthPtr) +{ + /* fields are a fixed width, determined by the largest possible string */ + /* presumably, these widths should be language dependent */ + static const WCHAR fld_d1W[] = { '2', 0 }; + static const WCHAR fld_d2W[] = { '2', '2', 0 }; + static const WCHAR fld_d4W[] = { '2', '2', '2', '2', 0 }; + static const WCHAR fld_am1[] = { 'A', 0 }; + static const WCHAR fld_am2[] = { 'A', 'M', 0 }; + static const WCHAR fld_day[] = { 'W', 'e', 'd', 'n', 'e', 's', 'd', 'a', 'y', 0 }; + static const WCHAR fld_day3[] = { 'W', 'e', 'd', 0 }; + static const WCHAR fld_mon[] = { 'S', 'e', 'p', 't', 'e', 'm', 'b', 'e', 'r', 0 }; + static const WCHAR fld_mon3[] = { 'D', 'e', 'c', 0 }; + int spec; + WCHAR buffer[80], *bufptr; + SIZE size; + + TRACE ("%d,%d\n", infoPtr->nrFields, count); + if (count>infoPtr->nrFields || count < 0) { + WARN ("buffer overrun, have %d want %d\n", infoPtr->nrFields, count); + return; + } + + if (!infoPtr->fieldspec) return; + + spec = infoPtr->fieldspec[count]; + if (spec & DT_STRING) { + int txtlen = infoPtr->buflen[count]; + + if (txtlen > 79) + txtlen = 79; + memcpy (buffer, infoPtr->textbuf + (spec &~ DT_STRING), txtlen * sizeof(WCHAR)); + buffer[txtlen] = 0; + bufptr = buffer; + } + else { + switch (spec) { + case ONEDIGITDAY: + case ONEDIGIT12HOUR: + case ONEDIGIT24HOUR: + case ONEDIGITSECOND: + case ONEDIGITMINUTE: + case ONEDIGITMONTH: + case ONEDIGITYEAR: + /* these seem to use a two byte field */ + case TWODIGITDAY: + case TWODIGIT12HOUR: + case TWODIGIT24HOUR: + case TWODIGITSECOND: + case TWODIGITMINUTE: + case TWODIGITMONTH: + case TWODIGITYEAR: + bufptr = (WCHAR *)fld_d2W; + break; + case INVALIDFULLYEAR: + case FULLYEAR: + bufptr = (WCHAR *)fld_d4W; + break; + case THREECHARDAY: + bufptr = (WCHAR *)fld_day3; + break; + case FULLDAY: + bufptr = (WCHAR *)fld_day; + break; + case THREECHARMONTH: + bufptr = (WCHAR *)fld_mon3; + break; + case FULLMONTH: + bufptr = (WCHAR *)fld_mon; + break; + case ONELETTERAMPM: + bufptr = (WCHAR *)fld_am1; + break; + case TWOLETTERAMPM: + bufptr = (WCHAR *)fld_am2; + break; + default: + bufptr = (WCHAR *)fld_d1W; + break; + } + } + GetTextExtentPoint32W (hdc, bufptr, strlenW(bufptr), &size); + *fieldWidthPtr = size.cx; +} + +static void +DATETIME_Refresh (DATETIME_INFO *infoPtr, HDC hdc) +{ + int i,prevright; + RECT *field; + RECT *rcDraw = &infoPtr->rcDraw; + RECT *calbutton = &infoPtr->calbutton; + RECT *checkbox = &infoPtr->checkbox; + SIZE size; + COLORREF oldTextColor; + SHORT fieldWidth = 0; + + /* draw control edge */ + TRACE("\n"); + + if (infoPtr->dateValid) { + HFONT oldFont = SelectObject (hdc, infoPtr->hFont); + INT oldBkMode = SetBkMode (hdc, TRANSPARENT); + WCHAR txt[80]; + + DATETIME_ReturnTxt (infoPtr, 0, txt, sizeof(txt)/sizeof(txt[0])); + GetTextExtentPoint32W (hdc, txt, strlenW(txt), &size); + rcDraw->bottom = size.cy + 2; + + prevright = checkbox->right = ((infoPtr->dwStyle & DTS_SHOWNONE) ? 18 : 2); + + for (i = 0; i < infoPtr->nrFields; i++) { + DATETIME_ReturnTxt (infoPtr, i, txt, sizeof(txt)/sizeof(txt[0])); + GetTextExtentPoint32W (hdc, txt, strlenW(txt), &size); + DATETIME_ReturnFieldWidth (infoPtr, hdc, i, &fieldWidth); + field = &infoPtr->fieldRect[i]; + field->left = prevright; + field->right = prevright + fieldWidth; + field->top = rcDraw->top; + field->bottom = rcDraw->bottom; + prevright = field->right; + + if (infoPtr->dwStyle & WS_DISABLED) + oldTextColor = SetTextColor (hdc, comctl32_color.clrGrayText); + else if ((infoPtr->haveFocus) && (i == infoPtr->select)) { + /* fill if focussed */ + HBRUSH hbr = CreateSolidBrush (comctl32_color.clrActiveCaption); + FillRect(hdc, field, hbr); + DeleteObject (hbr); + oldTextColor = SetTextColor (hdc, comctl32_color.clrWindow); + } + else + oldTextColor = SetTextColor (hdc, comctl32_color.clrWindowText); + + /* draw the date text using the colour set above */ + DrawTextW (hdc, txt, strlenW(txt), field, DT_RIGHT | DT_VCENTER | DT_SINGLELINE); + SetTextColor (hdc, oldTextColor); + } + SetBkMode (hdc, oldBkMode); + SelectObject (hdc, oldFont); + } + + if (!(infoPtr->dwStyle & DTS_UPDOWN)) { + DrawFrameControl(hdc, calbutton, DFC_SCROLL, + DFCS_SCROLLDOWN | (infoPtr->bCalDepressed ? DFCS_PUSHED : 0) | + (infoPtr->dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) ); + } +} + + +static INT +DATETIME_HitTest (DATETIME_INFO *infoPtr, POINT pt) +{ + int i; + + TRACE ("%ld, %ld\n", pt.x, pt.y); + + if (PtInRect (&infoPtr->calbutton, pt)) return DTHT_MCPOPUP; + if (PtInRect (&infoPtr->checkbox, pt)) return DTHT_CHECKBOX; + + for (i=0; i < infoPtr->nrFields; i++) { + if (PtInRect (&infoPtr->fieldRect[i], pt)) return i; + } + + return DTHT_NONE; +} + + +static LRESULT +DATETIME_LButtonDown (DATETIME_INFO *infoPtr, WORD wKey, INT x, INT y) +{ + POINT pt; + int old, new; + + pt.x = x; + pt.y = y; + old = infoPtr->select; + new = DATETIME_HitTest (infoPtr, pt); + + /* FIXME: might be conditions where we don't want to update infoPtr->select */ + infoPtr->select = new; + + SetFocus(infoPtr->hwndSelf); + + if (infoPtr->select == DTHT_MCPOPUP) { + RECT rcMonthCal; + SendMessageW(infoPtr->hMonthCal, MCM_GETMINREQRECT, 0, (LPARAM)&rcMonthCal); + + /* FIXME: button actually is only depressed during dropdown of the */ + /* calendar control and when the mouse is over the button window */ + infoPtr->bCalDepressed = TRUE; + + /* recalculate the position of the monthcal popup */ + if(infoPtr->dwStyle & DTS_RIGHTALIGN) + infoPtr->monthcal_pos.x = infoPtr->calbutton.left - + (rcMonthCal.right - rcMonthCal.left); + else + /* FIXME: this should be after the area reserved for the checkbox */ + infoPtr->monthcal_pos.x = infoPtr->rcDraw.left; + + infoPtr->monthcal_pos.y = infoPtr->rcClient.bottom; + ClientToScreen (infoPtr->hwndSelf, &(infoPtr->monthcal_pos)); + SetWindowPos(infoPtr->hMonthCal, 0, infoPtr->monthcal_pos.x, + infoPtr->monthcal_pos.y, rcMonthCal.right - rcMonthCal.left, + rcMonthCal.bottom - rcMonthCal.top, 0); + + if(IsWindowVisible(infoPtr->hMonthCal)) { + ShowWindow(infoPtr->hMonthCal, SW_HIDE); + } else { + SYSTEMTIME *lprgSysTimeArray = &infoPtr->date; + TRACE("update calendar %04d/%02d/%02d\n", + lprgSysTimeArray->wYear, lprgSysTimeArray->wMonth, lprgSysTimeArray->wDay); + SendMessageW(infoPtr->hMonthCal, MCM_SETCURSEL, 0, (LPARAM)(&infoPtr->date)); + ShowWindow(infoPtr->hMonthCal, SW_SHOW); + } + + TRACE ("dt:%p mc:%p mc parent:%p, desktop:%p\n", + infoPtr->hwndSelf, infoPtr->hMonthCal, infoPtr->hwndNotify, GetDesktopWindow ()); + DATETIME_SendSimpleNotify (infoPtr, DTN_DROPDOWN); + } + + InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); + + return 0; +} + + +static LRESULT +DATETIME_LButtonUp (DATETIME_INFO *infoPtr, WORD wKey) +{ + if(infoPtr->bCalDepressed) { + infoPtr->bCalDepressed = FALSE; + InvalidateRect(infoPtr->hwndSelf, &(infoPtr->calbutton), TRUE); + } + + return 0; +} + + +static LRESULT +DATETIME_Paint (DATETIME_INFO *infoPtr, HDC hdc) +{ + if (!hdc) { + PAINTSTRUCT ps; + hdc = BeginPaint (infoPtr->hwndSelf, &ps); + DATETIME_Refresh (infoPtr, hdc); + EndPaint (infoPtr->hwndSelf, &ps); + } else { + DATETIME_Refresh (infoPtr, hdc); + } + return 0; +} + + +static LRESULT +DATETIME_Button_Command (DATETIME_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + if( HIWORD(wParam) == BN_CLICKED) { + DWORD state = SendMessageW((HWND)lParam, BM_GETCHECK, 0, 0); + infoPtr->dateValid = (state == BST_CHECKED); + InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); + } + return 0; +} + + + +static LRESULT +DATETIME_Command (DATETIME_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + TRACE("hwndbutton = %p\n", infoPtr->hwndCheckbut); + if(infoPtr->hwndCheckbut == (HWND)lParam) + return DATETIME_Button_Command(infoPtr, wParam, lParam); + return 0; +} + + +static LRESULT +DATETIME_Enable (DATETIME_INFO *infoPtr, BOOL bEnable) +{ + TRACE("%p %s\n", infoPtr, bEnable ? "TRUE" : "FALSE"); + if (bEnable) + infoPtr->dwStyle &= ~WS_DISABLED; + else + infoPtr->dwStyle |= WS_DISABLED; + return 0; +} + + +static LRESULT +DATETIME_EraseBackground (DATETIME_INFO *infoPtr, HDC hdc) +{ + HBRUSH hBrush, hSolidBrush = NULL; + RECT rc; + + if (infoPtr->dwStyle & WS_DISABLED) + hBrush = hSolidBrush = CreateSolidBrush(comctl32_color.clrBtnFace); + else + { + hBrush = (HBRUSH)SendMessageW(infoPtr->hwndNotify, WM_CTLCOLOREDIT, + (WPARAM)hdc, (LPARAM)infoPtr->hwndSelf); + if (!hBrush) + hBrush = hSolidBrush = CreateSolidBrush(comctl32_color.clrWindow); + } + + GetClientRect (infoPtr->hwndSelf, &rc); + + FillRect (hdc, &rc, hBrush); + + if (hSolidBrush) + DeleteObject(hSolidBrush); + + return -1; +} + + +static LRESULT +DATETIME_Notify (DATETIME_INFO *infoPtr, int idCtrl, LPNMHDR lpnmh) +{ + TRACE ("Got notification %x from %p\n", lpnmh->code, lpnmh->hwndFrom); + TRACE ("info: %p %p %p\n", infoPtr->hwndSelf, infoPtr->hMonthCal, infoPtr->hUpdown); + + if (lpnmh->code == MCN_SELECT) { + ShowWindow(infoPtr->hMonthCal, SW_HIDE); + infoPtr->dateValid = TRUE; + SendMessageW (infoPtr->hMonthCal, MCM_GETCURSEL, 0, (LPARAM)&infoPtr->date); + TRACE("got from calendar %04d/%02d/%02d day of week %d\n", + infoPtr->date.wYear, infoPtr->date.wMonth, infoPtr->date.wDay, infoPtr->date.wDayOfWeek); + SendMessageW (infoPtr->hwndCheckbut, BM_SETCHECK, BST_CHECKED, 0); + InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); + DATETIME_SendDateTimeChangeNotify (infoPtr); + } + if ((lpnmh->hwndFrom == infoPtr->hUpdown) && (lpnmh->code == UDN_DELTAPOS)) { + LPNMUPDOWN lpnmud = (LPNMUPDOWN)lpnmh; + TRACE("Delta pos %d\n", lpnmud->iDelta); + infoPtr->pendingUpdown = lpnmud->iDelta; + } + return 0; +} + + +static LRESULT +DATETIME_KeyDown (DATETIME_INFO *infoPtr, DWORD vkCode, LPARAM flags) +{ + int fieldNum = infoPtr->select & DTHT_DATEFIELD; + int wrap = 0; + + if (!(infoPtr->haveFocus)) return 0; + if ((fieldNum==0) && (infoPtr->select)) return 0; + + if (infoPtr->select & FORMATCALLMASK) { + FIXME ("Callbacks not implemented yet\n"); + } + + if (vkCode >= '0' && vkCode <= '9') { + /* this is a somewhat simplified version of what Windows does */ + SYSTEMTIME *date = &infoPtr->date; + switch (infoPtr->fieldspec[fieldNum]) { + case ONEDIGITYEAR: + case TWODIGITYEAR: + date->wYear = date->wYear - (date->wYear%100) + + (date->wYear%10)*10 + (vkCode-'0'); + date->wDayOfWeek = DATETIME_CalculateDayOfWeek( + date->wDay,date->wMonth,date->wYear); + DATETIME_SendDateTimeChangeNotify (infoPtr); + break; + case INVALIDFULLYEAR: + case FULLYEAR: + date->wYear = (date->wYear%1000)*10 + (vkCode-'0'); + date->wDayOfWeek = DATETIME_CalculateDayOfWeek( + date->wDay,date->wMonth,date->wYear); + DATETIME_SendDateTimeChangeNotify (infoPtr); + break; + case ONEDIGITMONTH: + case TWODIGITMONTH: + if ((date->wMonth%10) > 1 || (vkCode-'0') > 2) + date->wMonth = vkCode-'0'; + else + date->wMonth = (date->wMonth%10)*10+vkCode-'0'; + date->wDayOfWeek = DATETIME_CalculateDayOfWeek( + date->wDay,date->wMonth,date->wYear); + DATETIME_SendDateTimeChangeNotify (infoPtr); + break; + case ONEDIGITDAY: + case TWODIGITDAY: + /* probably better checking here would help */ + if ((date->wDay%10) >= 3 && (vkCode-'0') > 1) + date->wDay = vkCode-'0'; + else + date->wDay = (date->wDay%10)*10+vkCode-'0'; + date->wDayOfWeek = DATETIME_CalculateDayOfWeek( + date->wDay,date->wMonth,date->wYear); + DATETIME_SendDateTimeChangeNotify (infoPtr); + break; + case ONEDIGIT12HOUR: + case TWODIGIT12HOUR: + if ((date->wHour%10) > 1 || (vkCode-'0') > 2) + date->wHour = vkCode-'0'; + else + date->wHour = (date->wHour%10)*10+vkCode-'0'; + DATETIME_SendDateTimeChangeNotify (infoPtr); + break; + case ONEDIGIT24HOUR: + case TWODIGIT24HOUR: + if ((date->wHour%10) > 2) + date->wHour = vkCode-'0'; + else if ((date->wHour%10) == 2 && (vkCode-'0') > 3) + date->wHour = vkCode-'0'; + else + date->wHour = (date->wHour%10)*10+vkCode-'0'; + DATETIME_SendDateTimeChangeNotify (infoPtr); + break; + case ONEDIGITMINUTE: + case TWODIGITMINUTE: + if ((date->wMinute%10) > 5) + date->wMinute = vkCode-'0'; + else + date->wMinute = (date->wMinute%10)*10+vkCode-'0'; + DATETIME_SendDateTimeChangeNotify (infoPtr); + break; + case ONEDIGITSECOND: + case TWODIGITSECOND: + if ((date->wSecond%10) > 5) + date->wSecond = vkCode-'0'; + else + date->wSecond = (date->wSecond%10)*10+vkCode-'0'; + DATETIME_SendDateTimeChangeNotify (infoPtr); + break; + } + } + + switch (vkCode) { + case VK_ADD: + case VK_UP: + DATETIME_IncreaseField (infoPtr, fieldNum, 1); + DATETIME_SendDateTimeChangeNotify (infoPtr); + break; + case VK_SUBTRACT: + case VK_DOWN: + DATETIME_IncreaseField (infoPtr, fieldNum, -1); + DATETIME_SendDateTimeChangeNotify (infoPtr); + break; + case VK_HOME: + DATETIME_IncreaseField (infoPtr, fieldNum, INT_MIN); + DATETIME_SendDateTimeChangeNotify (infoPtr); + break; + case VK_END: + DATETIME_IncreaseField (infoPtr, fieldNum, INT_MAX); + DATETIME_SendDateTimeChangeNotify (infoPtr); + break; + case VK_LEFT: + do { + if (infoPtr->select == 0) { + infoPtr->select = infoPtr->nrFields - 1; + wrap++; + } else { + infoPtr->select--; + } + } while ((infoPtr->fieldspec[infoPtr->select] & DT_STRING) && (wrap<2)); + break; + case VK_RIGHT: + do { + infoPtr->select++; + if (infoPtr->select==infoPtr->nrFields) { + infoPtr->select = 0; + wrap++; + } + } while ((infoPtr->fieldspec[infoPtr->select] & DT_STRING) && (wrap<2)); + break; + } + + InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); + + return 0; +} + + +static LRESULT +DATETIME_VScroll (DATETIME_INFO *infoPtr, WORD wScroll) +{ + int fieldNum = infoPtr->select & DTHT_DATEFIELD; + + if ((SHORT)LOWORD(wScroll) != SB_THUMBPOSITION) return 0; + if (!(infoPtr->haveFocus)) return 0; + if ((fieldNum==0) && (infoPtr->select)) return 0; + + if (infoPtr->pendingUpdown >= 0) { + DATETIME_IncreaseField (infoPtr, fieldNum, 1); + DATETIME_SendDateTimeChangeNotify (infoPtr); + } + else { + DATETIME_IncreaseField (infoPtr, fieldNum, -1); + DATETIME_SendDateTimeChangeNotify (infoPtr); + } + + InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); + + return 0; +} + + +static LRESULT +DATETIME_KillFocus (DATETIME_INFO *infoPtr, HWND lostFocus) +{ + TRACE("lost focus to %p\n", lostFocus); + + if (infoPtr->haveFocus) { + DATETIME_SendSimpleNotify (infoPtr, NM_KILLFOCUS); + infoPtr->haveFocus = 0; + } + + InvalidateRect (infoPtr->hwndSelf, NULL, TRUE); + + return 0; +} + + +static LRESULT +DATETIME_NCCreate (HWND hwnd, LPCREATESTRUCTW lpcs) +{ + DWORD dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE); + /* force control to have client edge */ + dwExStyle |= WS_EX_CLIENTEDGE; + SetWindowLongW(hwnd, GWL_EXSTYLE, dwExStyle); + + return DefWindowProcW(hwnd, WM_NCCREATE, 0, (LPARAM)lpcs); +} + + +static LRESULT +DATETIME_SetFocus (DATETIME_INFO *infoPtr, HWND lostFocus) +{ + TRACE("got focus from %p\n", lostFocus); + + if (infoPtr->haveFocus == 0) { + DATETIME_SendSimpleNotify (infoPtr, NM_SETFOCUS); + infoPtr->haveFocus = DTHT_GOTFOCUS; + } + + InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); + + return 0; +} + + +static BOOL +DATETIME_SendDateTimeChangeNotify (DATETIME_INFO *infoPtr) +{ + NMDATETIMECHANGE dtdtc; + + dtdtc.nmhdr.hwndFrom = infoPtr->hwndSelf; + dtdtc.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); + dtdtc.nmhdr.code = DTN_DATETIMECHANGE; + + dtdtc.dwFlags = (infoPtr->dwStyle & DTS_SHOWNONE) ? GDT_NONE : GDT_VALID; + + MONTHCAL_CopyTime (&infoPtr->date, &dtdtc.st); + return (BOOL) SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, + (WPARAM)dtdtc.nmhdr.idFrom, (LPARAM)&dtdtc); +} + + +static BOOL +DATETIME_SendSimpleNotify (DATETIME_INFO *infoPtr, UINT code) +{ + NMHDR nmhdr; + + TRACE("%x\n", code); + nmhdr.hwndFrom = infoPtr->hwndSelf; + nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); + nmhdr.code = code; + + return (BOOL) SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, + (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr); +} + +static LRESULT +DATETIME_Size (DATETIME_INFO *infoPtr, WORD flags, INT width, INT height) +{ + /* set size */ + infoPtr->rcClient.bottom = height; + infoPtr->rcClient.right = width; + + TRACE("Height=%ld, Width=%ld\n", infoPtr->rcClient.bottom, infoPtr->rcClient.right); + + infoPtr->rcDraw = infoPtr->rcClient; + + if (infoPtr->dwStyle & DTS_UPDOWN) { + SetWindowPos(infoPtr->hUpdown, NULL, + infoPtr->rcClient.right-14, 0, + 15, infoPtr->rcClient.bottom - infoPtr->rcClient.top, + SWP_NOACTIVATE | SWP_NOZORDER); + } + else { + /* set the size of the button that drops the calendar down */ + /* FIXME: account for style that allows button on left side */ + infoPtr->calbutton.top = infoPtr->rcDraw.top; + infoPtr->calbutton.bottom= infoPtr->rcDraw.bottom; + infoPtr->calbutton.left = infoPtr->rcDraw.right-15; + infoPtr->calbutton.right = infoPtr->rcDraw.right; + } + + /* set enable/disable button size for show none style being enabled */ + /* FIXME: these dimensions are completely incorrect */ + infoPtr->checkbox.top = infoPtr->rcDraw.top; + infoPtr->checkbox.bottom = infoPtr->rcDraw.bottom; + infoPtr->checkbox.left = infoPtr->rcDraw.left; + infoPtr->checkbox.right = infoPtr->rcDraw.left + 10; + + InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); + + return 0; +} + + +static LRESULT +DATETIME_StyleChanged(DATETIME_INFO *infoPtr, WPARAM wStyleType, LPSTYLESTRUCT lpss) +{ + static const WCHAR buttonW[] = { 'b', 'u', 't', 't', 'o', 'n', 0 }; + + TRACE("(styletype=%x, styleOld=0x%08lx, styleNew=0x%08lx)\n", + wStyleType, lpss->styleOld, lpss->styleNew); + + if (wStyleType != GWL_STYLE) return 0; + + infoPtr->dwStyle = lpss->styleNew; + + if ( !(lpss->styleOld & DTS_SHOWNONE) && (lpss->styleNew & DTS_SHOWNONE) ) { + infoPtr->hwndCheckbut = CreateWindowExW (0, buttonW, 0, WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, + 2, 2, 13, 13, infoPtr->hwndSelf, 0, + (HINSTANCE)GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_HINSTANCE), 0); + SendMessageW (infoPtr->hwndCheckbut, BM_SETCHECK, 1, 0); + } + if ( (lpss->styleOld & DTS_SHOWNONE) && !(lpss->styleNew & DTS_SHOWNONE) ) { + DestroyWindow(infoPtr->hwndCheckbut); + infoPtr->hwndCheckbut = 0; + } + if ( !(lpss->styleOld & DTS_UPDOWN) && (lpss->styleNew & DTS_UPDOWN) ) { + infoPtr->hUpdown = CreateUpDownControl (WS_CHILD | WS_BORDER | WS_VISIBLE, 120, 1, 20, 20, + infoPtr->hwndSelf, 1, 0, 0, UD_MAXVAL, UD_MINVAL, 0); + } + if ( (lpss->styleOld & DTS_UPDOWN) && !(lpss->styleNew & DTS_UPDOWN) ) { + DestroyWindow(infoPtr->hUpdown); + infoPtr->hUpdown = 0; + } + + InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); + return 0; +} + + +static LRESULT +DATETIME_Create (HWND hwnd, LPCREATESTRUCTW lpcs) +{ + static const WCHAR SysMonthCal32W[] = { 'S', 'y', 's', 'M', 'o', 'n', 't', 'h', 'C', 'a', 'l', '3', '2', 0 }; + DATETIME_INFO *infoPtr = (DATETIME_INFO *)Alloc (sizeof(DATETIME_INFO)); + STYLESTRUCT ss = { 0, lpcs->style }; + + if (!infoPtr) return -1; + + infoPtr->hwndSelf = hwnd; + infoPtr->dwStyle = lpcs->style; + + infoPtr->nrFieldsAllocated = 32; + infoPtr->fieldspec = (int *) Alloc (infoPtr->nrFieldsAllocated * sizeof(int)); + infoPtr->fieldRect = (RECT *) Alloc (infoPtr->nrFieldsAllocated * sizeof(RECT)); + infoPtr->buflen = (int *) Alloc (infoPtr->nrFieldsAllocated * sizeof(int)); + infoPtr->hwndNotify = lpcs->hwndParent; + infoPtr->select = -1; /* initially, nothing is selected */ + + DATETIME_StyleChanged(infoPtr, GWL_STYLE, &ss); + DATETIME_SetFormatW (infoPtr, 0); + + /* create the monthcal control */ + infoPtr->hMonthCal = CreateWindowExW (0, SysMonthCal32W, 0, WS_BORDER | WS_POPUP | WS_CLIPSIBLINGS, + 0, 0, 0, 0, infoPtr->hwndSelf, 0, 0, 0); + + /* initialize info structure */ + GetLocalTime (&infoPtr->date); + infoPtr->dateValid = TRUE; + infoPtr->hFont = GetStockObject(DEFAULT_GUI_FONT); + + SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); + + return 0; +} + + + +static LRESULT +DATETIME_Destroy (DATETIME_INFO *infoPtr) +{ + if (infoPtr->hwndCheckbut) + DestroyWindow(infoPtr->hwndCheckbut); + if (infoPtr->hUpdown) + DestroyWindow(infoPtr->hUpdown); + if (infoPtr->hMonthCal) + DestroyWindow(infoPtr->hMonthCal); + SetWindowLongPtrW( infoPtr->hwndSelf, 0, 0 ); /* clear infoPtr */ + Free (infoPtr); + return 0; +} + + +static LRESULT WINAPI +DATETIME_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + DATETIME_INFO *infoPtr = ((DATETIME_INFO *)GetWindowLongPtrW (hwnd, 0)); + LRESULT ret; + + TRACE ("%x, %x, %lx\n", uMsg, wParam, lParam); + + if (!infoPtr && (uMsg != WM_CREATE) && (uMsg != WM_NCCREATE)) + return DefWindowProcW( hwnd, uMsg, wParam, lParam ); + + switch (uMsg) { + + case DTM_GETSYSTEMTIME: + return DATETIME_GetSystemTime (infoPtr, (SYSTEMTIME *) lParam); + + case DTM_SETSYSTEMTIME: + return DATETIME_SetSystemTime (infoPtr, wParam, (SYSTEMTIME *) lParam); + + case DTM_GETRANGE: + ret = SendMessageW (infoPtr->hMonthCal, MCM_GETRANGE, wParam, lParam); + return ret ? ret : 1; /* bug emulation */ + + case DTM_SETRANGE: + return SendMessageW (infoPtr->hMonthCal, MCM_SETRANGE, wParam, lParam); + + case DTM_SETFORMATA: + return DATETIME_SetFormatA (infoPtr, (LPCSTR)lParam); + + case DTM_SETFORMATW: + return DATETIME_SetFormatW (infoPtr, (LPCWSTR)lParam); + + case DTM_GETMONTHCAL: + return (LRESULT)infoPtr->hMonthCal; + + case DTM_SETMCCOLOR: + return SendMessageW (infoPtr->hMonthCal, MCM_SETCOLOR, wParam, lParam); + + case DTM_GETMCCOLOR: + return SendMessageW (infoPtr->hMonthCal, MCM_GETCOLOR, wParam, 0); + + case DTM_SETMCFONT: + return SendMessageW (infoPtr->hMonthCal, WM_SETFONT, wParam, lParam); + + case DTM_GETMCFONT: + return SendMessageW (infoPtr->hMonthCal, WM_GETFONT, wParam, lParam); + + case WM_NOTIFY: + return DATETIME_Notify (infoPtr, (int)wParam, (LPNMHDR)lParam); + + case WM_ENABLE: + return DATETIME_Enable (infoPtr, (BOOL)wParam); + + case WM_ERASEBKGND: + return DATETIME_EraseBackground (infoPtr, (HDC)wParam); + + case WM_GETDLGCODE: + return DLGC_WANTARROWS | DLGC_WANTCHARS; + + case WM_PAINT: + return DATETIME_Paint (infoPtr, (HDC)wParam); + + case WM_KEYDOWN: + return DATETIME_KeyDown (infoPtr, wParam, lParam); + + case WM_KILLFOCUS: + return DATETIME_KillFocus (infoPtr, (HWND)wParam); + + case WM_NCCREATE: + return DATETIME_NCCreate (hwnd, (LPCREATESTRUCTW)lParam); + + case WM_SETFOCUS: + return DATETIME_SetFocus (infoPtr, (HWND)wParam); + + case WM_SIZE: + return DATETIME_Size (infoPtr, wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); + + case WM_LBUTTONDOWN: + return DATETIME_LButtonDown (infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); + + case WM_LBUTTONUP: + return DATETIME_LButtonUp (infoPtr, (WORD)wParam); + + case WM_VSCROLL: + return DATETIME_VScroll (infoPtr, (WORD)wParam); + + case WM_CREATE: + return DATETIME_Create (hwnd, (LPCREATESTRUCTW)lParam); + + case WM_DESTROY: + return DATETIME_Destroy (infoPtr); + + case WM_COMMAND: + return DATETIME_Command (infoPtr, wParam, lParam); + + case WM_STYLECHANGED: + return DATETIME_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam); + + default: + if ((uMsg >= WM_USER) && (uMsg < WM_APP)) + ERR("unknown msg %04x wp=%08x lp=%08lx\n", + uMsg, wParam, lParam); + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + } +} + + +void +DATETIME_Register (void) +{ + WNDCLASSW wndClass; + + ZeroMemory (&wndClass, sizeof(WNDCLASSW)); + wndClass.style = CS_GLOBALCLASS; + wndClass.lpfnWndProc = DATETIME_WindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(DATETIME_INFO *); + wndClass.hCursor = LoadCursorW (0, (LPCWSTR)IDC_ARROW); + wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wndClass.lpszClassName = DATETIMEPICK_CLASSW; + + RegisterClassW (&wndClass); +} + + +void +DATETIME_Unregister (void) +{ + UnregisterClassW (DATETIMEPICK_CLASSW, NULL); +} diff --git a/reactos/lib/comctl32/draglist.c b/reactos/lib/comctl32/draglist.c index 4a9d619f07b..3f333739757 100644 --- a/reactos/lib/comctl32/draglist.c +++ b/reactos/lib/comctl32/draglist.c @@ -1,341 +1,341 @@ -/* - * Drag List control - * - * Copyright 1999 Eric Kohl - * Copyright 2004 Robert Shearman - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTES - * - * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on Mar. 10, 2004, by Robert Shearman. - * - * Unless otherwise noted, we believe this code to be complete, as per - * the specification mentioned above. - * If you discover missing features or bugs please note them below. - * - */ - -#include - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "comctl32.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(commctrl); - -#define DRAGLIST_SUBCLASSID 0 -#define DRAGLIST_SCROLLPERIOD 200 -#define DRAGLIST_TIMERID 666 - -/* properties relating to IDI_DRAGICON */ -#define DRAGICON_HOTSPOT_X 17 -#define DRAGICON_HOTSPOT_Y 7 -#define DRAGICON_HEIGHT 32 - -/* internal Wine specific data for the drag list control */ -typedef struct _DRAGLISTDATA -{ - /* are we currently in dragging mode? */ - BOOL dragging; - - /* cursor to use as determined by DL_DRAGGING notification. - * NOTE: as we use LoadCursor we don't have to use DeleteCursor - * when we are finished with it */ - HCURSOR cursor; - - /* optimisation so that we don't have to load the cursor - * all of the time whilst dragging */ - LRESULT last_dragging_response; - - /* prevents flicker with drawing drag arrow */ - RECT last_drag_icon_rect; -} DRAGLISTDATA; - -UINT uDragListMessage = 0; /* registered window message code */ -static DWORD dwLastScrollTime = 0; -static HICON hDragArrow = NULL; - -/*********************************************************************** - * DragList_Notify (internal) - * - * Sends notification messages to the parent control. Note that it - * does not use WM_NOTIFY like the rest of the controls, but a registered - * window message. - */ -static LRESULT DragList_Notify(HWND hwndLB, UINT uNotification) -{ - DRAGLISTINFO dli; - dli.hWnd = hwndLB; - dli.uNotification = uNotification; - GetCursorPos(&dli.ptCursor); - return SendMessageW(GetParent(hwndLB), uDragListMessage, GetDlgCtrlID(hwndLB), (LPARAM)&dli); -} - -/* cleans up after dragging */ -static void DragList_EndDrag(HWND hwnd, DRAGLISTDATA * data) -{ - KillTimer(hwnd, DRAGLIST_TIMERID); - ReleaseCapture(); - /* clear any drag insert icon present */ - InvalidateRect(GetParent(hwnd), &data->last_drag_icon_rect, TRUE); - /* clear data for next use */ - memset(data, 0, sizeof(*data)); -} - -/*********************************************************************** - * DragList_SubclassWindowProc (internal) - * - * Handles certain messages to enable dragging for the ListBox and forwards - * the rest to the ListBox. - */ -static LRESULT CALLBACK -DragList_SubclassWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) -{ - DRAGLISTDATA * data = (DRAGLISTDATA*)dwRefData; - switch (uMsg) - { - case WM_LBUTTONDOWN: - SetFocus(hwnd); - data->dragging = DragList_Notify(hwnd, DL_BEGINDRAG); - if (data->dragging) - { - SetCapture(hwnd); - SetTimer(hwnd, DRAGLIST_TIMERID, DRAGLIST_SCROLLPERIOD, NULL); - } - /* note that we don't absorb this message to let the list box - * do its thing (normally selecting an item) */ - break; - - case WM_KEYDOWN: - case WM_RBUTTONDOWN: - /* user cancelled drag by either right clicking or - * by pressing the escape key */ - if ((data->dragging) && - ((uMsg == WM_RBUTTONDOWN) || (wParam == VK_ESCAPE))) - { - /* clean up and absorb message */ - DragList_EndDrag(hwnd, data); - DragList_Notify(hwnd, DL_CANCELDRAG); - return 0; - } - break; - - case WM_MOUSEMOVE: - case WM_TIMER: - if (data->dragging) - { - LRESULT cursor = DragList_Notify(hwnd, DL_DRAGGING); - /* optimisation so that we don't have to load the cursor - * all of the time whilst dragging */ - if (data->last_dragging_response != cursor) - { - switch (cursor) - { - case DL_STOPCURSOR: - data->cursor = LoadCursorW(NULL, (LPCWSTR)IDC_NO); - SetCursor(data->cursor); - break; - case DL_COPYCURSOR: - data->cursor = LoadCursorW(COMCTL32_hModule, (LPCWSTR)IDC_COPY); - SetCursor(data->cursor); - break; - case DL_MOVECURSOR: - data->cursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW); - SetCursor(data->cursor); - break; - } - data->last_dragging_response = cursor; - } - /* don't pass this message on to List Box */ - return 0; - } - break; - - case WM_LBUTTONUP: - if (data->dragging) - { - DragList_EndDrag(hwnd, data); - DragList_Notify(hwnd, DL_DROPPED); - } - break; - - case WM_GETDLGCODE: - /* tell dialog boxes that we want to receive WM_KEYDOWN events - * for keys like VK_ESCAPE */ - if (data->dragging) - return DLGC_WANTALLKEYS; - break; - case WM_NCDESTROY: - RemoveWindowSubclass(hwnd, DragList_SubclassWindowProc, DRAGLIST_SUBCLASSID); - Free(data); - break; - } - return DefSubclassProc(hwnd, uMsg, wParam, lParam); -} - -/*********************************************************************** - * MakeDragList (COMCTL32.13) - * - * Makes a normal ListBox into a DragList by subclassing it. - * - * RETURNS - * Success: Non-zero - * Failure: Zero - */ -BOOL WINAPI MakeDragList (HWND hwndLB) -{ - DRAGLISTDATA *data = Alloc(sizeof(DRAGLISTDATA)); - - TRACE("(%p)\n", hwndLB); - - if (!uDragListMessage) - uDragListMessage = RegisterWindowMessageW(DRAGLISTMSGSTRINGW); - - return SetWindowSubclass(hwndLB, DragList_SubclassWindowProc, DRAGLIST_SUBCLASSID, (DWORD_PTR)data); -} - -/*********************************************************************** - * DrawInsert (COMCTL32.15) - * - * Draws insert arrow by the side of the ListBox item in the parent window. - * - * RETURNS - * Nothing. - */ -VOID WINAPI DrawInsert (HWND hwndParent, HWND hwndLB, INT nItem) -{ - RECT rcItem, rcListBox, rcDragIcon; - HDC hdc; - DRAGLISTDATA * data; - - TRACE("(%p %p %d)\n", hwndParent, hwndLB, nItem); - - if (!hDragArrow) - hDragArrow = LoadIconW(COMCTL32_hModule, (LPCWSTR)IDI_DRAGARROW); - - if (LB_ERR == SendMessageW(hwndLB, LB_GETITEMRECT, nItem, (LPARAM)&rcItem)) - return; - - if (!GetWindowRect(hwndLB, &rcListBox)) - return; - - /* convert item rect to parent co-ordinates */ - if (!MapWindowPoints(hwndLB, hwndParent, (LPPOINT)&rcItem, 2)) - return; - - /* convert list box rect to parent co-ordinates */ - if (!MapWindowPoints(HWND_DESKTOP, hwndParent, (LPPOINT)&rcListBox, 2)) - return; - - rcDragIcon.left = rcListBox.left - DRAGICON_HOTSPOT_X; - rcDragIcon.top = rcItem.top - DRAGICON_HOTSPOT_Y; - rcDragIcon.right = rcListBox.left; - rcDragIcon.bottom = rcDragIcon.top + DRAGICON_HEIGHT; - - if (!GetWindowSubclass(hwndLB, DragList_SubclassWindowProc, DRAGLIST_SUBCLASSID, (DWORD_PTR*)&data)) - return; - - if (nItem < 0) - SetRectEmpty(&rcDragIcon); - - /* prevent flicker by only redrawing when necessary */ - if (!EqualRect(&rcDragIcon, &data->last_drag_icon_rect)) - { - /* get rid of any previous inserts drawn */ - RedrawWindow(hwndParent, &data->last_drag_icon_rect, NULL, - RDW_INTERNALPAINT | RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW); - - CopyRect(&data->last_drag_icon_rect, &rcDragIcon); - - if (nItem >= 0) - { - hdc = GetDC(hwndParent); - - DrawIcon(hdc, rcDragIcon.left, rcDragIcon.top, hDragArrow); - - ReleaseDC(hwndParent, hdc); - } - } -} - -/*********************************************************************** - * LBItemFromPt (COMCTL32.14) - * - * Gets the index of the ListBox item under the specified point, - * scrolling if bAutoScroll is TRUE and pt is outside of the ListBox. - * - * RETURNS - * The ListBox item ID if pt is over a list item or -1 otherwise. - */ -INT WINAPI LBItemFromPt (HWND hwndLB, POINT pt, BOOL bAutoScroll) -{ - RECT rcClient; - INT nIndex; - DWORD dwScrollTime; - - TRACE("(%p %ld x %ld %s)\n", - hwndLB, pt.x, pt.y, bAutoScroll ? "TRUE" : "FALSE"); - - ScreenToClient (hwndLB, &pt); - GetClientRect (hwndLB, &rcClient); - nIndex = (INT)SendMessageW (hwndLB, LB_GETTOPINDEX, 0, 0); - - if (PtInRect (&rcClient, pt)) - { - /* point is inside -- get the item index */ - while (TRUE) - { - if (SendMessageW (hwndLB, LB_GETITEMRECT, nIndex, (LPARAM)&rcClient) == LB_ERR) - return -1; - - if (PtInRect (&rcClient, pt)) - return nIndex; - - nIndex++; - } - } - else - { - /* point is outside */ - if (!bAutoScroll) - return -1; - - if ((pt.x > rcClient.right) || (pt.x < rcClient.left)) - return -1; - - if (pt.y < 0) - nIndex--; - else - nIndex++; - - dwScrollTime = GetTickCount (); - - if ((dwScrollTime - dwLastScrollTime) < DRAGLIST_SCROLLPERIOD) - return -1; - - dwLastScrollTime = dwScrollTime; - - SendMessageW (hwndLB, LB_SETTOPINDEX, (WPARAM)nIndex, 0); - } - - return -1; -} +/* + * Drag List control + * + * Copyright 1999 Eric Kohl + * Copyright 2004 Robert Shearman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES + * + * This code was audited for completeness against the documented features + * of Comctl32.dll version 6.0 on Mar. 10, 2004, by Robert Shearman. + * + * Unless otherwise noted, we believe this code to be complete, as per + * the specification mentioned above. + * If you discover missing features or bugs please note them below. + * + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "comctl32.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(commctrl); + +#define DRAGLIST_SUBCLASSID 0 +#define DRAGLIST_SCROLLPERIOD 200 +#define DRAGLIST_TIMERID 666 + +/* properties relating to IDI_DRAGICON */ +#define DRAGICON_HOTSPOT_X 17 +#define DRAGICON_HOTSPOT_Y 7 +#define DRAGICON_HEIGHT 32 + +/* internal Wine specific data for the drag list control */ +typedef struct _DRAGLISTDATA +{ + /* are we currently in dragging mode? */ + BOOL dragging; + + /* cursor to use as determined by DL_DRAGGING notification. + * NOTE: as we use LoadCursor we don't have to use DeleteCursor + * when we are finished with it */ + HCURSOR cursor; + + /* optimisation so that we don't have to load the cursor + * all of the time whilst dragging */ + LRESULT last_dragging_response; + + /* prevents flicker with drawing drag arrow */ + RECT last_drag_icon_rect; +} DRAGLISTDATA; + +UINT uDragListMessage = 0; /* registered window message code */ +static DWORD dwLastScrollTime = 0; +static HICON hDragArrow = NULL; + +/*********************************************************************** + * DragList_Notify (internal) + * + * Sends notification messages to the parent control. Note that it + * does not use WM_NOTIFY like the rest of the controls, but a registered + * window message. + */ +static LRESULT DragList_Notify(HWND hwndLB, UINT uNotification) +{ + DRAGLISTINFO dli; + dli.hWnd = hwndLB; + dli.uNotification = uNotification; + GetCursorPos(&dli.ptCursor); + return SendMessageW(GetParent(hwndLB), uDragListMessage, GetDlgCtrlID(hwndLB), (LPARAM)&dli); +} + +/* cleans up after dragging */ +static void DragList_EndDrag(HWND hwnd, DRAGLISTDATA * data) +{ + KillTimer(hwnd, DRAGLIST_TIMERID); + ReleaseCapture(); + /* clear any drag insert icon present */ + InvalidateRect(GetParent(hwnd), &data->last_drag_icon_rect, TRUE); + /* clear data for next use */ + memset(data, 0, sizeof(*data)); +} + +/*********************************************************************** + * DragList_SubclassWindowProc (internal) + * + * Handles certain messages to enable dragging for the ListBox and forwards + * the rest to the ListBox. + */ +static LRESULT CALLBACK +DragList_SubclassWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) +{ + DRAGLISTDATA * data = (DRAGLISTDATA*)dwRefData; + switch (uMsg) + { + case WM_LBUTTONDOWN: + SetFocus(hwnd); + data->dragging = DragList_Notify(hwnd, DL_BEGINDRAG); + if (data->dragging) + { + SetCapture(hwnd); + SetTimer(hwnd, DRAGLIST_TIMERID, DRAGLIST_SCROLLPERIOD, NULL); + } + /* note that we don't absorb this message to let the list box + * do its thing (normally selecting an item) */ + break; + + case WM_KEYDOWN: + case WM_RBUTTONDOWN: + /* user cancelled drag by either right clicking or + * by pressing the escape key */ + if ((data->dragging) && + ((uMsg == WM_RBUTTONDOWN) || (wParam == VK_ESCAPE))) + { + /* clean up and absorb message */ + DragList_EndDrag(hwnd, data); + DragList_Notify(hwnd, DL_CANCELDRAG); + return 0; + } + break; + + case WM_MOUSEMOVE: + case WM_TIMER: + if (data->dragging) + { + LRESULT cursor = DragList_Notify(hwnd, DL_DRAGGING); + /* optimisation so that we don't have to load the cursor + * all of the time whilst dragging */ + if (data->last_dragging_response != cursor) + { + switch (cursor) + { + case DL_STOPCURSOR: + data->cursor = LoadCursorW(NULL, (LPCWSTR)IDC_NO); + SetCursor(data->cursor); + break; + case DL_COPYCURSOR: + data->cursor = LoadCursorW(COMCTL32_hModule, (LPCWSTR)IDC_COPY); + SetCursor(data->cursor); + break; + case DL_MOVECURSOR: + data->cursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW); + SetCursor(data->cursor); + break; + } + data->last_dragging_response = cursor; + } + /* don't pass this message on to List Box */ + return 0; + } + break; + + case WM_LBUTTONUP: + if (data->dragging) + { + DragList_EndDrag(hwnd, data); + DragList_Notify(hwnd, DL_DROPPED); + } + break; + + case WM_GETDLGCODE: + /* tell dialog boxes that we want to receive WM_KEYDOWN events + * for keys like VK_ESCAPE */ + if (data->dragging) + return DLGC_WANTALLKEYS; + break; + case WM_NCDESTROY: + RemoveWindowSubclass(hwnd, DragList_SubclassWindowProc, DRAGLIST_SUBCLASSID); + Free(data); + break; + } + return DefSubclassProc(hwnd, uMsg, wParam, lParam); +} + +/*********************************************************************** + * MakeDragList (COMCTL32.13) + * + * Makes a normal ListBox into a DragList by subclassing it. + * + * RETURNS + * Success: Non-zero + * Failure: Zero + */ +BOOL WINAPI MakeDragList (HWND hwndLB) +{ + DRAGLISTDATA *data = Alloc(sizeof(DRAGLISTDATA)); + + TRACE("(%p)\n", hwndLB); + + if (!uDragListMessage) + uDragListMessage = RegisterWindowMessageW(DRAGLISTMSGSTRINGW); + + return SetWindowSubclass(hwndLB, DragList_SubclassWindowProc, DRAGLIST_SUBCLASSID, (DWORD_PTR)data); +} + +/*********************************************************************** + * DrawInsert (COMCTL32.15) + * + * Draws insert arrow by the side of the ListBox item in the parent window. + * + * RETURNS + * Nothing. + */ +VOID WINAPI DrawInsert (HWND hwndParent, HWND hwndLB, INT nItem) +{ + RECT rcItem, rcListBox, rcDragIcon; + HDC hdc; + DRAGLISTDATA * data; + + TRACE("(%p %p %d)\n", hwndParent, hwndLB, nItem); + + if (!hDragArrow) + hDragArrow = LoadIconW(COMCTL32_hModule, (LPCWSTR)IDI_DRAGARROW); + + if (LB_ERR == SendMessageW(hwndLB, LB_GETITEMRECT, nItem, (LPARAM)&rcItem)) + return; + + if (!GetWindowRect(hwndLB, &rcListBox)) + return; + + /* convert item rect to parent co-ordinates */ + if (!MapWindowPoints(hwndLB, hwndParent, (LPPOINT)&rcItem, 2)) + return; + + /* convert list box rect to parent co-ordinates */ + if (!MapWindowPoints(HWND_DESKTOP, hwndParent, (LPPOINT)&rcListBox, 2)) + return; + + rcDragIcon.left = rcListBox.left - DRAGICON_HOTSPOT_X; + rcDragIcon.top = rcItem.top - DRAGICON_HOTSPOT_Y; + rcDragIcon.right = rcListBox.left; + rcDragIcon.bottom = rcDragIcon.top + DRAGICON_HEIGHT; + + if (!GetWindowSubclass(hwndLB, DragList_SubclassWindowProc, DRAGLIST_SUBCLASSID, (DWORD_PTR*)&data)) + return; + + if (nItem < 0) + SetRectEmpty(&rcDragIcon); + + /* prevent flicker by only redrawing when necessary */ + if (!EqualRect(&rcDragIcon, &data->last_drag_icon_rect)) + { + /* get rid of any previous inserts drawn */ + RedrawWindow(hwndParent, &data->last_drag_icon_rect, NULL, + RDW_INTERNALPAINT | RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW); + + CopyRect(&data->last_drag_icon_rect, &rcDragIcon); + + if (nItem >= 0) + { + hdc = GetDC(hwndParent); + + DrawIcon(hdc, rcDragIcon.left, rcDragIcon.top, hDragArrow); + + ReleaseDC(hwndParent, hdc); + } + } +} + +/*********************************************************************** + * LBItemFromPt (COMCTL32.14) + * + * Gets the index of the ListBox item under the specified point, + * scrolling if bAutoScroll is TRUE and pt is outside of the ListBox. + * + * RETURNS + * The ListBox item ID if pt is over a list item or -1 otherwise. + */ +INT WINAPI LBItemFromPt (HWND hwndLB, POINT pt, BOOL bAutoScroll) +{ + RECT rcClient; + INT nIndex; + DWORD dwScrollTime; + + TRACE("(%p %ld x %ld %s)\n", + hwndLB, pt.x, pt.y, bAutoScroll ? "TRUE" : "FALSE"); + + ScreenToClient (hwndLB, &pt); + GetClientRect (hwndLB, &rcClient); + nIndex = (INT)SendMessageW (hwndLB, LB_GETTOPINDEX, 0, 0); + + if (PtInRect (&rcClient, pt)) + { + /* point is inside -- get the item index */ + while (TRUE) + { + if (SendMessageW (hwndLB, LB_GETITEMRECT, nIndex, (LPARAM)&rcClient) == LB_ERR) + return -1; + + if (PtInRect (&rcClient, pt)) + return nIndex; + + nIndex++; + } + } + else + { + /* point is outside */ + if (!bAutoScroll) + return -1; + + if ((pt.x > rcClient.right) || (pt.x < rcClient.left)) + return -1; + + if (pt.y < 0) + nIndex--; + else + nIndex++; + + dwScrollTime = GetTickCount (); + + if ((dwScrollTime - dwLastScrollTime) < DRAGLIST_SCROLLPERIOD) + return -1; + + dwLastScrollTime = dwScrollTime; + + SendMessageW (hwndLB, LB_SETTOPINDEX, (WPARAM)nIndex, 0); + } + + return -1; +} diff --git a/reactos/lib/comctl32/flatsb.c b/reactos/lib/comctl32/flatsb.c index 6d16c3c0aa8..dd227b881c7 100644 --- a/reactos/lib/comctl32/flatsb.c +++ b/reactos/lib/comctl32/flatsb.c @@ -1,290 +1,290 @@ -/* - * Flat Scrollbar control - * - * Copyright 1998, 1999 Eric Kohl - * Copyright 1998 Alex Priem - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTES - * This is just a dummy control. An author is needed! Any volunteers? - * I will only improve this control once in a while. - * Eric - * - * TODO: - * - All messages. - * - All notifications. - * - */ - -#include -#include -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "winuser.h" -#include "commctrl.h" -#include "comctl32.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(commctrl); - -typedef struct -{ - DWORD dwDummy; /* just to keep the compiler happy ;-) */ -} FLATSB_INFO, *LPFLATSB_INFO; - -#define FlatSB_GetInfoPtr(hwnd) ((FLATSB_INFO*)GetWindowLongPtrW (hwnd, 0)) - - -/*********************************************************************** - * InitializeFlatSB (COMCTL32.@) - * - * Initializes flat scroll bars for the specified window. - * - * RETURNS - * Success: Non-zero - * Failure: Zero - * - * NOTES - * Subclasses specified window so that flat scroll bars may be drawn - * and used. - */ -BOOL WINAPI InitializeFlatSB(HWND hwnd) -{ - TRACE("[%p]\n", hwnd); - return FALSE; -} - -/*********************************************************************** - * UninitializeFlatSB (COMCTL32.@) - * - * Uninitializes flat scroll bars for the specified window. - * - * RETURNS - * E_FAIL if one of the scroll bars is currently in use - * S_FALSE if InitializeFlatSB() was never called on this hwnd - * S_OK otherwise - * - * NOTES - * Removes any subclassing on the specified window so that regular - * scroll bars are drawn and used. - */ -HRESULT WINAPI UninitializeFlatSB(HWND hwnd) -{ - TRACE("[%p]\n", hwnd); - return S_FALSE; -} - -/*********************************************************************** - * FlatSB_GetScrollProp (COMCTL32.@) - * - * Retrieves flat-scroll-bar-specific properties for the specified window. - * - * RETURNS - * nonzero if successful, or zero otherwise. If index is WSB_PROP_HSTYLE, - * the return is nonzero if InitializeFlatSB has been called for this window, or - * zero otherwise. - */ -BOOL WINAPI -FlatSB_GetScrollProp(HWND hwnd, INT propIndex, LPINT prop) -{ - TRACE("[%p] propIndex=%d\n", hwnd, propIndex); - return FALSE; -} - -/*********************************************************************** - * FlatSB_SetScrollProp (COMCTL32.@) - * - * Sets flat-scroll-bar-specific properties for the specified window. - * - * RETURNS - * Success: Non-zero - * Failure: Zero - */ -BOOL WINAPI -FlatSB_SetScrollProp(HWND hwnd, UINT index, INT newValue, BOOL flag) -{ - TRACE("[%p] index=%u newValue=%d flag=%d\n", hwnd, index, newValue, flag); - return FALSE; -} - -/*********************************************************************** - * From the Microsoft docs: - * "If flat scroll bars haven't been initialized for the - * window, the flat scroll bar APIs will defer to the corresponding - * standard APIs. This allows the developer to turn flat scroll - * bars on and off without having to write conditional code." - * - * So, if we just call the standard functions until we implement - * the flat scroll bar functions, flat scroll bars will show up and - * behave properly, as though they had simply not been setup to - * have flat properties. - * - * Susan - * - */ - -/*********************************************************************** - * FlatSB_EnableScrollBar (COMCTL32.@) - * - * See EnableScrollBar. - */ -BOOL WINAPI -FlatSB_EnableScrollBar(HWND hwnd, int nBar, UINT flags) -{ - return EnableScrollBar(hwnd, nBar, flags); -} - -/*********************************************************************** - * FlatSB_ShowScrollBar (COMCTL32.@) - * - * See ShowScrollBar. - */ -BOOL WINAPI -FlatSB_ShowScrollBar(HWND hwnd, int nBar, BOOL fShow) -{ - return ShowScrollBar(hwnd, nBar, fShow); -} - -/*********************************************************************** - * FlatSB_GetScrollRange (COMCTL32.@) - * - * See GetScrollRange. - */ -BOOL WINAPI -FlatSB_GetScrollRange(HWND hwnd, int nBar, LPINT min, LPINT max) -{ - return GetScrollRange(hwnd, nBar, min, max); -} - -/*********************************************************************** - * FlatSB_GetScrollInfo (COMCTL32.@) - * - * See GetScrollInfo. - */ -BOOL WINAPI -FlatSB_GetScrollInfo(HWND hwnd, int nBar, LPSCROLLINFO info) -{ - return GetScrollInfo(hwnd, nBar, info); -} - -/*********************************************************************** - * FlatSB_GetScrollPos (COMCTL32.@) - * - * See GetScrollPos. - */ -INT WINAPI -FlatSB_GetScrollPos(HWND hwnd, int nBar) -{ - return GetScrollPos(hwnd, nBar); -} - -/*********************************************************************** - * FlatSB_SetScrollPos (COMCTL32.@) - * - * See SetScrollPos. - */ -INT WINAPI -FlatSB_SetScrollPos(HWND hwnd, int nBar, INT pos, BOOL bRedraw) -{ - return SetScrollPos(hwnd, nBar, pos, bRedraw); -} - -/*********************************************************************** - * FlatSB_SetScrollInfo (COMCTL32.@) - * - * See SetScrollInfo. - */ -INT WINAPI -FlatSB_SetScrollInfo(HWND hwnd, int nBar, LPSCROLLINFO info, BOOL bRedraw) -{ - return SetScrollInfo(hwnd, nBar, info, bRedraw); -} - -/*********************************************************************** - * FlatSB_SetScrollRange (COMCTL32.@) - * - * See SetScrollRange. - */ -INT WINAPI -FlatSB_SetScrollRange(HWND hwnd, int nBar, INT min, INT max, BOOL bRedraw) -{ - return SetScrollRange(hwnd, nBar, min, max, bRedraw); -} - - -static LRESULT -FlatSB_Create (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TRACE("[%p] wParam=%04x lParam=%08lx\n", hwnd, wParam, lParam); - return 0; -} - - -static LRESULT -FlatSB_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TRACE("[%p] wParam=%04x lParam=%08lx\n", hwnd, wParam, lParam); - return 0; -} - - -static LRESULT WINAPI -FlatSB_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - if (!FlatSB_GetInfoPtr(hwnd) && (uMsg != WM_CREATE)) - return DefWindowProcW( hwnd, uMsg, wParam, lParam ); - - switch (uMsg) - { - case WM_CREATE: - return FlatSB_Create (hwnd, wParam, lParam); - - case WM_DESTROY: - return FlatSB_Destroy (hwnd, wParam, lParam); - - default: - if ((uMsg >= WM_USER) && (uMsg < WM_APP)) - ERR("unknown msg %04x wp=%08x lp=%08lx\n", - uMsg, wParam, lParam); - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - } -} - - -VOID -FLATSB_Register (void) -{ - WNDCLASSW wndClass; - - ZeroMemory (&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS; - wndClass.lpfnWndProc = FlatSB_WindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(FLATSB_INFO *); - wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); - wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wndClass.lpszClassName = FLATSB_CLASSW; - - RegisterClassW (&wndClass); -} - - -VOID -FLATSB_Unregister (void) -{ - UnregisterClassW (FLATSB_CLASSW, NULL); -} +/* + * Flat Scrollbar control + * + * Copyright 1998, 1999 Eric Kohl + * Copyright 1998 Alex Priem + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES + * This is just a dummy control. An author is needed! Any volunteers? + * I will only improve this control once in a while. + * Eric + * + * TODO: + * - All messages. + * - All notifications. + * + */ + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winuser.h" +#include "commctrl.h" +#include "comctl32.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(commctrl); + +typedef struct +{ + DWORD dwDummy; /* just to keep the compiler happy ;-) */ +} FLATSB_INFO, *LPFLATSB_INFO; + +#define FlatSB_GetInfoPtr(hwnd) ((FLATSB_INFO*)GetWindowLongPtrW (hwnd, 0)) + + +/*********************************************************************** + * InitializeFlatSB (COMCTL32.@) + * + * Initializes flat scroll bars for the specified window. + * + * RETURNS + * Success: Non-zero + * Failure: Zero + * + * NOTES + * Subclasses specified window so that flat scroll bars may be drawn + * and used. + */ +BOOL WINAPI InitializeFlatSB(HWND hwnd) +{ + TRACE("[%p]\n", hwnd); + return FALSE; +} + +/*********************************************************************** + * UninitializeFlatSB (COMCTL32.@) + * + * Uninitializes flat scroll bars for the specified window. + * + * RETURNS + * E_FAIL if one of the scroll bars is currently in use + * S_FALSE if InitializeFlatSB() was never called on this hwnd + * S_OK otherwise + * + * NOTES + * Removes any subclassing on the specified window so that regular + * scroll bars are drawn and used. + */ +HRESULT WINAPI UninitializeFlatSB(HWND hwnd) +{ + TRACE("[%p]\n", hwnd); + return S_FALSE; +} + +/*********************************************************************** + * FlatSB_GetScrollProp (COMCTL32.@) + * + * Retrieves flat-scroll-bar-specific properties for the specified window. + * + * RETURNS + * nonzero if successful, or zero otherwise. If index is WSB_PROP_HSTYLE, + * the return is nonzero if InitializeFlatSB has been called for this window, or + * zero otherwise. + */ +BOOL WINAPI +FlatSB_GetScrollProp(HWND hwnd, INT propIndex, LPINT prop) +{ + TRACE("[%p] propIndex=%d\n", hwnd, propIndex); + return FALSE; +} + +/*********************************************************************** + * FlatSB_SetScrollProp (COMCTL32.@) + * + * Sets flat-scroll-bar-specific properties for the specified window. + * + * RETURNS + * Success: Non-zero + * Failure: Zero + */ +BOOL WINAPI +FlatSB_SetScrollProp(HWND hwnd, UINT index, INT newValue, BOOL flag) +{ + TRACE("[%p] index=%u newValue=%d flag=%d\n", hwnd, index, newValue, flag); + return FALSE; +} + +/*********************************************************************** + * From the Microsoft docs: + * "If flat scroll bars haven't been initialized for the + * window, the flat scroll bar APIs will defer to the corresponding + * standard APIs. This allows the developer to turn flat scroll + * bars on and off without having to write conditional code." + * + * So, if we just call the standard functions until we implement + * the flat scroll bar functions, flat scroll bars will show up and + * behave properly, as though they had simply not been setup to + * have flat properties. + * + * Susan + * + */ + +/*********************************************************************** + * FlatSB_EnableScrollBar (COMCTL32.@) + * + * See EnableScrollBar. + */ +BOOL WINAPI +FlatSB_EnableScrollBar(HWND hwnd, int nBar, UINT flags) +{ + return EnableScrollBar(hwnd, nBar, flags); +} + +/*********************************************************************** + * FlatSB_ShowScrollBar (COMCTL32.@) + * + * See ShowScrollBar. + */ +BOOL WINAPI +FlatSB_ShowScrollBar(HWND hwnd, int nBar, BOOL fShow) +{ + return ShowScrollBar(hwnd, nBar, fShow); +} + +/*********************************************************************** + * FlatSB_GetScrollRange (COMCTL32.@) + * + * See GetScrollRange. + */ +BOOL WINAPI +FlatSB_GetScrollRange(HWND hwnd, int nBar, LPINT min, LPINT max) +{ + return GetScrollRange(hwnd, nBar, min, max); +} + +/*********************************************************************** + * FlatSB_GetScrollInfo (COMCTL32.@) + * + * See GetScrollInfo. + */ +BOOL WINAPI +FlatSB_GetScrollInfo(HWND hwnd, int nBar, LPSCROLLINFO info) +{ + return GetScrollInfo(hwnd, nBar, info); +} + +/*********************************************************************** + * FlatSB_GetScrollPos (COMCTL32.@) + * + * See GetScrollPos. + */ +INT WINAPI +FlatSB_GetScrollPos(HWND hwnd, int nBar) +{ + return GetScrollPos(hwnd, nBar); +} + +/*********************************************************************** + * FlatSB_SetScrollPos (COMCTL32.@) + * + * See SetScrollPos. + */ +INT WINAPI +FlatSB_SetScrollPos(HWND hwnd, int nBar, INT pos, BOOL bRedraw) +{ + return SetScrollPos(hwnd, nBar, pos, bRedraw); +} + +/*********************************************************************** + * FlatSB_SetScrollInfo (COMCTL32.@) + * + * See SetScrollInfo. + */ +INT WINAPI +FlatSB_SetScrollInfo(HWND hwnd, int nBar, LPSCROLLINFO info, BOOL bRedraw) +{ + return SetScrollInfo(hwnd, nBar, info, bRedraw); +} + +/*********************************************************************** + * FlatSB_SetScrollRange (COMCTL32.@) + * + * See SetScrollRange. + */ +INT WINAPI +FlatSB_SetScrollRange(HWND hwnd, int nBar, INT min, INT max, BOOL bRedraw) +{ + return SetScrollRange(hwnd, nBar, min, max, bRedraw); +} + + +static LRESULT +FlatSB_Create (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TRACE("[%p] wParam=%04x lParam=%08lx\n", hwnd, wParam, lParam); + return 0; +} + + +static LRESULT +FlatSB_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TRACE("[%p] wParam=%04x lParam=%08lx\n", hwnd, wParam, lParam); + return 0; +} + + +static LRESULT WINAPI +FlatSB_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + if (!FlatSB_GetInfoPtr(hwnd) && (uMsg != WM_CREATE)) + return DefWindowProcW( hwnd, uMsg, wParam, lParam ); + + switch (uMsg) + { + case WM_CREATE: + return FlatSB_Create (hwnd, wParam, lParam); + + case WM_DESTROY: + return FlatSB_Destroy (hwnd, wParam, lParam); + + default: + if ((uMsg >= WM_USER) && (uMsg < WM_APP)) + ERR("unknown msg %04x wp=%08x lp=%08lx\n", + uMsg, wParam, lParam); + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + } +} + + +VOID +FLATSB_Register (void) +{ + WNDCLASSW wndClass; + + ZeroMemory (&wndClass, sizeof(WNDCLASSW)); + wndClass.style = CS_GLOBALCLASS; + wndClass.lpfnWndProc = FlatSB_WindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(FLATSB_INFO *); + wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); + wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wndClass.lpszClassName = FLATSB_CLASSW; + + RegisterClassW (&wndClass); +} + + +VOID +FLATSB_Unregister (void) +{ + UnregisterClassW (FLATSB_CLASSW, NULL); +} diff --git a/reactos/lib/comctl32/header.c b/reactos/lib/comctl32/header.c index 21d087b0140..c66e48466d5 100644 --- a/reactos/lib/comctl32/header.c +++ b/reactos/lib/comctl32/header.c @@ -1,1849 +1,1849 @@ -/* - * Header control - * - * Copyright 1998 Eric Kohl - * Copyright 2000 Eric Kohl for CodeWeavers - * Copyright 2003 Maxime Bellenge - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * TODO: - * - Imagelist support (partially). - * - Callback items (under construction). - * - Hottrack support (partially). - * - Custom draw support (including Notifications). - * - Drag and Drop support (including Notifications). - * - New messages. - * - Use notification format - * - Correct the order maintenance code to preserve valid order - * - */ - -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "wine/unicode.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "comctl32.h" -#include "imagelist.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(header); - -typedef struct -{ - INT cxy; - HBITMAP hbm; - LPWSTR pszText; - INT fmt; - LPARAM lParam; - INT iImage; - INT iOrder; /* see documentation of HD_ITEM */ - - BOOL bDown; /* is item pressed? (used for drawing) */ - RECT rect; /* bounding rectangle of the item */ -} HEADER_ITEM; - - -typedef struct -{ - HWND hwndNotify; /* Owner window to send notifications to */ - INT nNotifyFormat; /* format used for WM_NOTIFY messages */ - UINT uNumItem; /* number of items (columns) */ - INT nHeight; /* height of the header (pixels) */ - HFONT hFont; /* handle to the current font */ - HCURSOR hcurArrow; /* handle to the arrow cursor */ - HCURSOR hcurDivider; /* handle to a cursor (used over dividers) <-|-> */ - HCURSOR hcurDivopen; /* handle to a cursor (used over dividers) <-||-> */ - BOOL bCaptured; /* Is the mouse captured? */ - BOOL bPressed; /* Is a header item pressed (down)? */ - BOOL bTracking; /* Is in tracking mode? */ - BOOL bUnicode; /* Unicode flag */ - INT iMoveItem; /* index of tracked item. (Tracking mode) */ - INT xTrackOffset; /* distance between the right side of the tracked item and the cursor */ - INT xOldTrack; /* track offset (see above) after the last WM_MOUSEMOVE */ - INT nOldWidth; /* width of a sizing item after the last WM_MOUSEMOVE */ - INT iHotItem; /* index of hot item (cursor is over this item) */ - INT iMargin; /* width of the margin that surrounds a bitmap */ - - HIMAGELIST himl; /* handle to an image list (may be 0) */ - HEADER_ITEM *items; /* pointer to array of HEADER_ITEM's */ - BOOL bRectsValid; /* validity flag for bounding rectangles */ -} HEADER_INFO; - - -#define VERT_BORDER 3 -#define DIVIDER_WIDTH 10 - -#define HEADER_GetInfoPtr(hwnd) ((HEADER_INFO *)GetWindowLongPtrW(hwnd,0)) - - -inline static LRESULT -HEADER_IndexToOrder (HWND hwnd, INT iItem) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - HEADER_ITEM *lpItem = &infoPtr->items[iItem]; - return lpItem->iOrder; -} - - -static INT -HEADER_OrderToIndex(HWND hwnd, WPARAM wParam) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - INT iorder = (INT)wParam; - UINT i; - - if ((iorder <0) || iorder >infoPtr->uNumItem) - return iorder; - for (i=0; iuNumItem; i++) - if (HEADER_IndexToOrder(hwnd,i) == iorder) - return i; - return iorder; -} - -static void -HEADER_SetItemBounds (HWND hwnd) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - HEADER_ITEM *phdi; - RECT rect; - unsigned int i; - int x; - - infoPtr->bRectsValid = TRUE; - - if (infoPtr->uNumItem == 0) - return; - - GetClientRect (hwnd, &rect); - - x = rect.left; - for (i = 0; i < infoPtr->uNumItem; i++) { - phdi = &infoPtr->items[HEADER_OrderToIndex(hwnd,i)]; - phdi->rect.top = rect.top; - phdi->rect.bottom = rect.bottom; - phdi->rect.left = x; - phdi->rect.right = phdi->rect.left + ((phdi->cxy>0)?phdi->cxy:0); - x = phdi->rect.right; - } -} - -static LRESULT -HEADER_Size (HWND hwnd, WPARAM wParam) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - - infoPtr->bRectsValid = FALSE; - - return 0; -} - - -static INT -HEADER_DrawItem (HWND hwnd, HDC hdc, INT iItem, BOOL bHotTrack) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - HEADER_ITEM *phdi = &infoPtr->items[iItem]; - RECT r; - INT oldBkMode, cxEdge = GetSystemMetrics(SM_CXEDGE); - - TRACE("DrawItem(iItem %d bHotTrack %d unicode flag %d)\n", iItem, bHotTrack, infoPtr->bUnicode); - - if (!infoPtr->bRectsValid) - HEADER_SetItemBounds(hwnd); - - r = phdi->rect; - if (r.right - r.left == 0) - return phdi->rect.right; - - if (GetWindowLongW (hwnd, GWL_STYLE) & HDS_BUTTONS) { - if (phdi->bDown) { - DrawEdge (hdc, &r, BDR_RAISEDOUTER, - BF_RECT | BF_FLAT | BF_MIDDLE | BF_ADJUST); - r.left += 2; - r.top += 2; - } - else - DrawEdge (hdc, &r, EDGE_RAISED, - BF_RECT | BF_SOFT | BF_MIDDLE | BF_ADJUST); - } - else - DrawEdge (hdc, &r, EDGE_ETCHED, BF_BOTTOM | BF_RIGHT | BF_ADJUST); - - r.left -= cxEdge; - r.right += cxEdge; - - if (phdi->fmt & HDF_OWNERDRAW) { - DRAWITEMSTRUCT dis; - dis.CtlType = ODT_HEADER; - dis.CtlID = GetWindowLongPtrW (hwnd, GWLP_ID); - dis.itemID = iItem; - dis.itemAction = ODA_DRAWENTIRE; - dis.itemState = phdi->bDown ? ODS_SELECTED : 0; - dis.hwndItem = hwnd; - dis.hDC = hdc; - dis.rcItem = r; - dis.itemData = phdi->lParam; - oldBkMode = SetBkMode(hdc, TRANSPARENT); - SendMessageW (infoPtr->hwndNotify, WM_DRAWITEM, - (WPARAM)dis.CtlID, (LPARAM)&dis); - if (oldBkMode != TRANSPARENT) - SetBkMode(hdc, oldBkMode); - } - else { - UINT rw, rh, /* width and height of r */ - *x = NULL, *w = NULL; /* x and width of the pic (bmp or img) which is part of cnt */ - /* cnt,txt,img,bmp */ - UINT cx, tx, ix, bx, - cw, tw, iw, bw; - BITMAP bmp; - - cw = tw = iw = bw = 0; - rw = r.right - r.left; - rh = r.bottom - r.top; - - if (phdi->fmt & HDF_STRING) { - RECT textRect; - - DrawTextW (hdc, phdi->pszText, -1, - &textRect, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_CALCRECT); - cw = textRect.right - textRect.left + 2 * infoPtr->iMargin; - } - - if ((phdi->fmt & HDF_IMAGE) && (infoPtr->himl)) { - iw = infoPtr->himl->cx + 2 * infoPtr->iMargin; - x = &ix; - w = &iw; - } - - if ((phdi->fmt & HDF_BITMAP) && (phdi->hbm)) { - GetObjectW (phdi->hbm, sizeof(BITMAP), (LPVOID)&bmp); - bw = bmp.bmWidth + 2 * infoPtr->iMargin; - if (!iw) { - x = &bx; - w = &bw; - } - } - - if (bw || iw) - cw += *w; - - /* align cx using the unclipped cw */ - if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_LEFT) - cx = r.left; - else if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_CENTER) - cx = r.left + rw / 2 - cw / 2; - else /* HDF_RIGHT */ - cx = r.right - cw; - - /* clip cx & cw */ - if (cx < r.left) - cx = r.left; - if (cx + cw > r.right) - cw = r.right - cx; - - tx = cx + infoPtr->iMargin; - /* since cw might have changed we have to recalculate tw */ - tw = cw - infoPtr->iMargin * 2; - - if (iw || bw) { - tw -= *w; - if (phdi->fmt & HDF_BITMAP_ON_RIGHT) { - /* put pic behind text */ - *x = cx + tw + infoPtr->iMargin * 3; - } else { - *x = cx + infoPtr->iMargin; - /* move text behind pic */ - tx += *w; - } - } - - if (iw && bw) { - /* since we're done with the layout we can - now calculate the position of bmp which - has no influence on alignment and layout - because of img */ - if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_RIGHT) - bx = cx - bw + infoPtr->iMargin; - else - bx = cx + cw + infoPtr->iMargin; - } - - if (iw || bw) { - HDC hClipDC = GetDC(hwnd); - HRGN hClipRgn = CreateRectRgn(r.left, r.top, r.right, r.bottom); - - SelectClipRgn(hClipDC, hClipRgn); - if (bw) { - HDC hdcBitmap = CreateCompatibleDC (hClipDC); - SelectObject (hdcBitmap, phdi->hbm); - BitBlt (hClipDC, bx, r.top + ((INT)rh - bmp.bmHeight) / 2, - bmp.bmWidth, bmp.bmHeight, hdcBitmap, 0, 0, SRCCOPY); - DeleteDC (hdcBitmap); - } - - if (iw) { - ImageList_DrawEx (infoPtr->himl, phdi->iImage, hClipDC, - ix, r.top + ((INT)rh - infoPtr->himl->cy) / 2, - infoPtr->himl->cx, infoPtr->himl->cy, CLR_DEFAULT, CLR_DEFAULT, 0); - } - - DeleteObject(hClipRgn); - ReleaseDC(hwnd, hClipDC); - } - - if (((phdi->fmt & HDF_STRING) - || (!(phdi->fmt & (HDF_OWNERDRAW|HDF_STRING|HDF_BITMAP| - HDF_BITMAP_ON_RIGHT|HDF_IMAGE)))) /* no explicit format specified? */ - && (phdi->pszText)) { - oldBkMode = SetBkMode(hdc, TRANSPARENT); - SetTextColor (hdc, (bHotTrack) ? COLOR_HIGHLIGHT : COLOR_BTNTEXT); - r.left = tx; - r.right = tx + tw; - DrawTextW (hdc, phdi->pszText, -1, - &r, DT_LEFT|DT_END_ELLIPSIS|DT_VCENTER|DT_SINGLELINE); - if (oldBkMode != TRANSPARENT) - SetBkMode(hdc, oldBkMode); - } - }/*Ownerdrawn*/ - - return phdi->rect.right; -} - - -static void -HEADER_Refresh (HWND hwnd, HDC hdc) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - HFONT hFont, hOldFont; - RECT rect; - HBRUSH hbrBk; - UINT i; - INT x; - - /* get rect for the bar, adjusted for the border */ - GetClientRect (hwnd, &rect); - - hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT); - hOldFont = SelectObject (hdc, hFont); - - /* draw Background */ - hbrBk = GetSysColorBrush(COLOR_3DFACE); - FillRect(hdc, &rect, hbrBk); - - x = rect.left; - for (i = 0; i < infoPtr->uNumItem; i++) { - x = HEADER_DrawItem (hwnd, hdc, HEADER_OrderToIndex(hwnd,i), FALSE); - } - - if ((x <= rect.right) && (infoPtr->uNumItem > 0)) { - rect.left = x; - if (GetWindowLongW (hwnd, GWL_STYLE) & HDS_BUTTONS) - DrawEdge (hdc, &rect, EDGE_RAISED, BF_TOP|BF_LEFT|BF_BOTTOM|BF_SOFT); - else - DrawEdge (hdc, &rect, EDGE_ETCHED, BF_BOTTOM); - } - - SelectObject (hdc, hOldFont); -} - - -static void -HEADER_RefreshItem (HWND hwnd, HDC hdc, INT iItem) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - HFONT hFont, hOldFont; - - hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT); - hOldFont = SelectObject (hdc, hFont); - HEADER_DrawItem (hwnd, hdc, iItem, FALSE); - SelectObject (hdc, hOldFont); -} - - -static void -HEADER_InternalHitTest (HWND hwnd, LPPOINT lpPt, UINT *pFlags, INT *pItem) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - RECT rect, rcTest; - UINT iCount; - INT width; - BOOL bNoWidth; - - GetClientRect (hwnd, &rect); - - *pFlags = 0; - bNoWidth = FALSE; - if (PtInRect (&rect, *lpPt)) - { - if (infoPtr->uNumItem == 0) { - *pFlags |= HHT_NOWHERE; - *pItem = 1; - TRACE("NOWHERE\n"); - return; - } - else { - /* somewhere inside */ - for (iCount = 0; iCount < infoPtr->uNumItem; iCount++) { - rect = infoPtr->items[iCount].rect; - width = rect.right - rect.left; - if (width == 0) { - bNoWidth = TRUE; - continue; - } - if (PtInRect (&rect, *lpPt)) { - if (width <= 2 * DIVIDER_WIDTH) { - *pFlags |= HHT_ONHEADER; - *pItem = iCount; - TRACE("ON HEADER %d\n", iCount); - return; - } - if (iCount > 0) { - rcTest = rect; - rcTest.right = rcTest.left + DIVIDER_WIDTH; - if (PtInRect (&rcTest, *lpPt)) { - if (bNoWidth) { - *pFlags |= HHT_ONDIVOPEN; - *pItem = iCount - 1; - TRACE("ON DIVOPEN %d\n", *pItem); - return; - } - else { - *pFlags |= HHT_ONDIVIDER; - *pItem = iCount - 1; - TRACE("ON DIVIDER %d\n", *pItem); - return; - } - } - } - rcTest = rect; - rcTest.left = rcTest.right - DIVIDER_WIDTH; - if (PtInRect (&rcTest, *lpPt)) { - *pFlags |= HHT_ONDIVIDER; - *pItem = iCount; - TRACE("ON DIVIDER %d\n", *pItem); - return; - } - - *pFlags |= HHT_ONHEADER; - *pItem = iCount; - TRACE("ON HEADER %d\n", iCount); - return; - } - } - - /* check for last divider part (on nowhere) */ - rect = infoPtr->items[infoPtr->uNumItem-1].rect; - rect.left = rect.right; - rect.right += DIVIDER_WIDTH; - if (PtInRect (&rect, *lpPt)) { - if (bNoWidth) { - *pFlags |= HHT_ONDIVOPEN; - *pItem = infoPtr->uNumItem - 1; - TRACE("ON DIVOPEN %d\n", *pItem); - return; - } - else { - *pFlags |= HHT_ONDIVIDER; - *pItem = infoPtr->uNumItem-1; - TRACE("ON DIVIDER %d\n", *pItem); - return; - } - } - - *pFlags |= HHT_NOWHERE; - *pItem = 1; - TRACE("NOWHERE\n"); - return; - } - } - else { - if (lpPt->x < rect.left) { - TRACE("TO LEFT\n"); - *pFlags |= HHT_TOLEFT; - } - else if (lpPt->x > rect.right) { - TRACE("TO RIGHT\n"); - *pFlags |= HHT_TORIGHT; - } - - if (lpPt->y < rect.top) { - TRACE("ABOVE\n"); - *pFlags |= HHT_ABOVE; - } - else if (lpPt->y > rect.bottom) { - TRACE("BELOW\n"); - *pFlags |= HHT_BELOW; - } - } - - *pItem = 1; - TRACE("flags=0x%X\n", *pFlags); - return; -} - - -static void -HEADER_DrawTrackLine (HWND hwnd, HDC hdc, INT x) -{ - RECT rect; - HPEN hOldPen; - INT oldRop; - - GetClientRect (hwnd, &rect); - - hOldPen = SelectObject (hdc, GetStockObject (BLACK_PEN)); - oldRop = SetROP2 (hdc, R2_XORPEN); - MoveToEx (hdc, x, rect.top, NULL); - LineTo (hdc, x, rect.bottom); - SetROP2 (hdc, oldRop); - SelectObject (hdc, hOldPen); -} - - -static BOOL -HEADER_SendSimpleNotify (HWND hwnd, UINT code) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - NMHDR nmhdr; - - nmhdr.hwndFrom = hwnd; - nmhdr.idFrom = GetWindowLongPtrW (hwnd, GWLP_ID); - nmhdr.code = code; - - return (BOOL)SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, - (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr); -} - -static BOOL -HEADER_SendHeaderNotify (HWND hwnd, UINT code, INT iItem, INT mask) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - NMHEADERA nmhdr; - HDITEMA nmitem; - - nmhdr.hdr.hwndFrom = hwnd; - nmhdr.hdr.idFrom = GetWindowLongPtrW (hwnd, GWLP_ID); - nmhdr.hdr.code = code; - nmhdr.iItem = iItem; - nmhdr.iButton = 0; - nmhdr.pitem = &nmitem; - nmitem.mask = mask; - nmitem.cxy = infoPtr->items[iItem].cxy; - nmitem.hbm = infoPtr->items[iItem].hbm; - nmitem.pszText = NULL; - nmitem.cchTextMax = 0; -/* nmitem.pszText = infoPtr->items[iItem].pszText; */ -/* nmitem.cchTextMax = infoPtr->items[iItem].cchTextMax; */ - nmitem.fmt = infoPtr->items[iItem].fmt; - nmitem.lParam = infoPtr->items[iItem].lParam; - nmitem.iOrder = infoPtr->items[iItem].iOrder; - nmitem.iImage = infoPtr->items[iItem].iImage; - - return (BOOL)SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, - (WPARAM)nmhdr.hdr.idFrom, (LPARAM)&nmhdr); -} - - -static BOOL -HEADER_SendClickNotify (HWND hwnd, UINT code, INT iItem) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - NMHEADERA nmhdr; - - nmhdr.hdr.hwndFrom = hwnd; - nmhdr.hdr.idFrom = GetWindowLongPtrW (hwnd, GWLP_ID); - nmhdr.hdr.code = code; - nmhdr.iItem = iItem; - nmhdr.iButton = 0; - nmhdr.pitem = NULL; - - return (BOOL)SendMessageA (infoPtr->hwndNotify, WM_NOTIFY, - (WPARAM)nmhdr.hdr.idFrom, (LPARAM)&nmhdr); -} - - -static LRESULT -HEADER_CreateDragImage (HWND hwnd, WPARAM wParam) -{ - FIXME("empty stub!\n"); - return 0; -} - - -static LRESULT -HEADER_DeleteItem (HWND hwnd, WPARAM wParam) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr(hwnd); - INT iItem = (INT)wParam; - - TRACE("[iItem=%d]\n", iItem); - - if ((iItem < 0) || (iItem >= (INT)infoPtr->uNumItem)) - return FALSE; - - if (infoPtr->uNumItem == 1) { - TRACE("Simple delete!\n"); - if (infoPtr->items[0].pszText) - Free (infoPtr->items[0].pszText); - Free (infoPtr->items); - infoPtr->items = 0; - infoPtr->uNumItem = 0; - } - else { - HEADER_ITEM *oldItems = infoPtr->items; - HEADER_ITEM *pItem; - INT i; - INT iOrder; - TRACE("Complex delete! [iItem=%d]\n", iItem); - - if (infoPtr->items[iItem].pszText) - Free (infoPtr->items[iItem].pszText); - iOrder = infoPtr->items[iItem].iOrder; - - infoPtr->uNumItem--; - infoPtr->items = Alloc (sizeof (HEADER_ITEM) * infoPtr->uNumItem); - /* pre delete copy */ - if (iItem > 0) { - memcpy (&infoPtr->items[0], &oldItems[0], - iItem * sizeof(HEADER_ITEM)); - } - - /* post delete copy */ - if (iItem < infoPtr->uNumItem) { - memcpy (&infoPtr->items[iItem], &oldItems[iItem+1], - (infoPtr->uNumItem - iItem) * sizeof(HEADER_ITEM)); - } - - /* Correct the orders */ - for (i=infoPtr->uNumItem, pItem = infoPtr->items; i; i--, pItem++) - { - if (pItem->iOrder > iOrder) - pItem->iOrder--; - } - Free (oldItems); - } - - HEADER_SetItemBounds (hwnd); - - InvalidateRect(hwnd, NULL, FALSE); - - return TRUE; -} - - -static LRESULT -HEADER_GetImageList (HWND hwnd) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - - return (LRESULT)infoPtr->himl; -} - - -static LRESULT -HEADER_GetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - HDITEMA *phdi = (HDITEMA*)lParam; - INT nItem = (INT)wParam; - HEADER_ITEM *lpItem; - - if (!phdi) - return FALSE; - - TRACE("[nItem=%d]\n", nItem); - - if (phdi->mask == 0) - return TRUE; - - if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem)) { - lpItem = NULL; - } - else { - lpItem = &infoPtr->items[nItem]; - } - - if (phdi->mask & HDI_BITMAP) - phdi->hbm = (lpItem != NULL) ? lpItem->hbm : 0; - - if (phdi->mask & HDI_FORMAT) - phdi->fmt = (lpItem != NULL) ? lpItem->fmt : 0; - - if (phdi->mask & HDI_WIDTH) - phdi->cxy = (lpItem != NULL) ? lpItem->cxy : 0; - - if (phdi->mask & HDI_LPARAM) - phdi->lParam = (lpItem != NULL) ? lpItem->lParam : 0; - - if (phdi->mask & HDI_TEXT) { - if (lpItem == NULL) { - *phdi->pszText = 0; - } - else if (lpItem->pszText != LPSTR_TEXTCALLBACKW) { - if (lpItem->pszText) - WideCharToMultiByte (CP_ACP, 0, lpItem->pszText, -1, - phdi->pszText, phdi->cchTextMax, NULL, NULL); - else - *phdi->pszText = 0; - } - else - phdi->pszText = LPSTR_TEXTCALLBACKA; - } - - if (phdi->mask & HDI_IMAGE) - phdi->iImage = (lpItem != NULL) ? lpItem->iImage : 0; - - if (phdi->mask & HDI_ORDER) - phdi->iOrder = (lpItem != NULL) ? lpItem->iOrder : 0; - - return TRUE; -} - - -static LRESULT -HEADER_GetItemW (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - HDITEMW *phdi = (HDITEMW*)lParam; - INT nItem = (INT)wParam; - HEADER_ITEM *lpItem; - - if (!phdi) - return FALSE; - - TRACE("[nItem=%d]\n", nItem); - - if (phdi->mask == 0) - return TRUE; - - if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem)) { - lpItem = NULL; - } - else { - lpItem = &infoPtr->items[nItem]; - } - - if (phdi->mask & HDI_BITMAP) - phdi->hbm = (lpItem != NULL) ? lpItem->hbm : 0; - - if (phdi->mask & HDI_FORMAT) - phdi->fmt = (lpItem != NULL) ? lpItem->fmt : 0; - - if (phdi->mask & HDI_WIDTH) - phdi->cxy = (lpItem != NULL) ? lpItem->cxy : 0; - - if (phdi->mask & HDI_LPARAM) - phdi->lParam = (lpItem != NULL) ? lpItem->lParam : 0; - - if (phdi->mask & HDI_TEXT) { - if (lpItem == NULL) { - *phdi->pszText = 0; - } - else if (lpItem->pszText != LPSTR_TEXTCALLBACKW) { - if (lpItem->pszText) - lstrcpynW (phdi->pszText, lpItem->pszText, phdi->cchTextMax); - else - *phdi->pszText = 0; - } - else - phdi->pszText = LPSTR_TEXTCALLBACKW; - } - - if (phdi->mask & HDI_IMAGE) - phdi->iImage = (lpItem != NULL) ? lpItem->iImage : 0; - - if (phdi->mask & HDI_ORDER) - phdi->iOrder = (lpItem != NULL) ? lpItem->iOrder : 0; - - return TRUE; -} - - -inline static LRESULT -HEADER_GetItemCount (HWND hwnd) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - return infoPtr->uNumItem; -} - - -static LRESULT -HEADER_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - INT iItem = (INT)wParam; - LPRECT lpRect = (LPRECT)lParam; - - if ((iItem < 0) || (iItem >= (INT)infoPtr->uNumItem)) - return FALSE; - - lpRect->left = infoPtr->items[iItem].rect.left; - lpRect->right = infoPtr->items[iItem].rect.right; - lpRect->top = infoPtr->items[iItem].rect.top; - lpRect->bottom = infoPtr->items[iItem].rect.bottom; - - return TRUE; -} - - -static LRESULT -HEADER_GetOrderArray(HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - int i; - LPINT order = (LPINT) lParam; - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - - if ((unsigned int)wParam uNumItem) - return FALSE; - for (i=0; i<(int)wParam; i++) - *order++=HEADER_OrderToIndex(hwnd,i); - return TRUE; -} - -static LRESULT -HEADER_SetOrderArray(HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - int i; - LPINT order = (LPINT) lParam; - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - HEADER_ITEM *lpItem; - - if ((unsigned int)wParam uNumItem) - return FALSE; - for (i=0; i<(int)wParam; i++) - { - lpItem = &infoPtr->items[*order++]; - lpItem->iOrder=i; - } - infoPtr->bRectsValid=0; - InvalidateRect(hwnd, NULL, FALSE); - return TRUE; -} - -inline static LRESULT -HEADER_GetUnicodeFormat (HWND hwnd) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - return infoPtr->bUnicode; -} - - -static LRESULT -HEADER_HitTest (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - LPHDHITTESTINFO phti = (LPHDHITTESTINFO)lParam; - - HEADER_InternalHitTest (hwnd, &phti->pt, &phti->flags, &phti->iItem); - - if (phti->flags == HHT_NOWHERE) - return -1; - else - return phti->iItem; -} - - -static LRESULT -HEADER_InsertItemA (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - HDITEMA *phdi = (HDITEMA*)lParam; - INT nItem = (INT)wParam; - HEADER_ITEM *lpItem; - INT len, iOrder; - UINT i; - - if ((phdi == NULL) || (nItem < 0)) - return -1; - - if (nItem > infoPtr->uNumItem) - nItem = infoPtr->uNumItem; - - iOrder = (phdi->mask & HDI_ORDER) ? phdi->iOrder : nItem; - - if (infoPtr->uNumItem == 0) { - infoPtr->items = Alloc (sizeof (HEADER_ITEM)); - infoPtr->uNumItem++; - } - else { - HEADER_ITEM *oldItems = infoPtr->items; - - infoPtr->uNumItem++; - infoPtr->items = Alloc (sizeof (HEADER_ITEM) * infoPtr->uNumItem); - if (nItem == 0) { - memcpy (&infoPtr->items[1], &oldItems[0], - (infoPtr->uNumItem-1) * sizeof(HEADER_ITEM)); - } - else - { - /* pre insert copy */ - if (nItem > 0) { - memcpy (&infoPtr->items[0], &oldItems[0], - nItem * sizeof(HEADER_ITEM)); - } - - /* post insert copy */ - if (nItem < infoPtr->uNumItem - 1) { - memcpy (&infoPtr->items[nItem+1], &oldItems[nItem], - (infoPtr->uNumItem - nItem - 1) * sizeof(HEADER_ITEM)); - } - } - - Free (oldItems); - } - - for (i=0; i < infoPtr->uNumItem; i++) - { - if (infoPtr->items[i].iOrder >= iOrder) - infoPtr->items[i].iOrder++; - } - - lpItem = &infoPtr->items[nItem]; - lpItem->bDown = FALSE; - - if (phdi->mask & HDI_WIDTH) - lpItem->cxy = phdi->cxy; - - if (phdi->mask & HDI_TEXT) { - if (!phdi->pszText) /* null pointer check */ - phdi->pszText = ""; - if (phdi->pszText != LPSTR_TEXTCALLBACKA) { - len = MultiByteToWideChar(CP_ACP, 0, phdi->pszText, -1, NULL, 0); - lpItem->pszText = Alloc( len*sizeof(WCHAR) ); - MultiByteToWideChar(CP_ACP, 0, phdi->pszText, -1, lpItem->pszText, len); - } - else - lpItem->pszText = LPSTR_TEXTCALLBACKW; - } - - if (phdi->mask & HDI_FORMAT) - lpItem->fmt = phdi->fmt; - - if (lpItem->fmt == 0) - lpItem->fmt = HDF_LEFT; - - if (!(lpItem->fmt & HDF_STRING) && (phdi->mask & HDI_TEXT)) - { - lpItem->fmt |= HDF_STRING; - } - if (phdi->mask & HDI_BITMAP) - lpItem->hbm = phdi->hbm; - - if (phdi->mask & HDI_LPARAM) - lpItem->lParam = phdi->lParam; - - if (phdi->mask & HDI_IMAGE) - lpItem->iImage = phdi->iImage; - - lpItem->iOrder = iOrder; - - HEADER_SetItemBounds (hwnd); - - InvalidateRect(hwnd, NULL, FALSE); - - return nItem; -} - - -static LRESULT -HEADER_InsertItemW (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - HDITEMW *phdi = (HDITEMW*)lParam; - INT nItem = (INT)wParam; - HEADER_ITEM *lpItem; - INT len, iOrder; - UINT i; - - if ((phdi == NULL) || (nItem < 0)) - return -1; - - if (nItem > infoPtr->uNumItem) - nItem = infoPtr->uNumItem; - - iOrder = (phdi->mask & HDI_ORDER) ? phdi->iOrder : nItem; - - if (infoPtr->uNumItem == 0) { - infoPtr->items = Alloc (sizeof (HEADER_ITEM)); - infoPtr->uNumItem++; - } - else { - HEADER_ITEM *oldItems = infoPtr->items; - - infoPtr->uNumItem++; - infoPtr->items = Alloc (sizeof (HEADER_ITEM) * infoPtr->uNumItem); - if (nItem == 0) { - memcpy (&infoPtr->items[1], &oldItems[0], - (infoPtr->uNumItem-1) * sizeof(HEADER_ITEM)); - } - else - { - /* pre insert copy */ - if (nItem > 0) { - memcpy (&infoPtr->items[0], &oldItems[0], - nItem * sizeof(HEADER_ITEM)); - } - - /* post insert copy */ - if (nItem < infoPtr->uNumItem - 1) { - memcpy (&infoPtr->items[nItem+1], &oldItems[nItem], - (infoPtr->uNumItem - nItem - 1) * sizeof(HEADER_ITEM)); - } - } - - Free (oldItems); - } - - for (i=0; i < infoPtr->uNumItem; i++) - { - if (infoPtr->items[i].iOrder >= iOrder) - infoPtr->items[i].iOrder++; - } - - lpItem = &infoPtr->items[nItem]; - lpItem->bDown = FALSE; - - if (phdi->mask & HDI_WIDTH) - lpItem->cxy = phdi->cxy; - - if (phdi->mask & HDI_TEXT) { - WCHAR wide_null_char = 0; - if (!phdi->pszText) /* null pointer check */ - phdi->pszText = &wide_null_char; - if (phdi->pszText != LPSTR_TEXTCALLBACKW) { - len = strlenW (phdi->pszText); - lpItem->pszText = Alloc ((len+1)*sizeof(WCHAR)); - strcpyW (lpItem->pszText, phdi->pszText); - } - else - lpItem->pszText = LPSTR_TEXTCALLBACKW; - } - - if (phdi->mask & HDI_FORMAT) - lpItem->fmt = phdi->fmt; - - if (lpItem->fmt == 0) - lpItem->fmt = HDF_LEFT; - - if (!(lpItem->fmt &HDF_STRING) && (phdi->mask & HDI_TEXT)) - { - lpItem->fmt |= HDF_STRING; - } - if (phdi->mask & HDI_BITMAP) - lpItem->hbm = phdi->hbm; - - if (phdi->mask & HDI_LPARAM) - lpItem->lParam = phdi->lParam; - - if (phdi->mask & HDI_IMAGE) - lpItem->iImage = phdi->iImage; - - lpItem->iOrder = iOrder; - - HEADER_SetItemBounds (hwnd); - - InvalidateRect(hwnd, NULL, FALSE); - - return nItem; -} - - -static LRESULT -HEADER_Layout (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - LPHDLAYOUT lpLayout = (LPHDLAYOUT)lParam; - - lpLayout->pwpos->hwnd = hwnd; - lpLayout->pwpos->hwndInsertAfter = 0; - lpLayout->pwpos->x = lpLayout->prc->left; - lpLayout->pwpos->y = lpLayout->prc->top; - lpLayout->pwpos->cx = lpLayout->prc->right - lpLayout->prc->left; - if (GetWindowLongW (hwnd, GWL_STYLE) & HDS_HIDDEN) - lpLayout->pwpos->cy = 0; - else { - lpLayout->pwpos->cy = infoPtr->nHeight; - lpLayout->prc->top += infoPtr->nHeight; - } - lpLayout->pwpos->flags = SWP_NOZORDER; - - TRACE("Layout x=%d y=%d cx=%d cy=%d\n", - lpLayout->pwpos->x, lpLayout->pwpos->y, - lpLayout->pwpos->cx, lpLayout->pwpos->cy); - - infoPtr->bRectsValid = FALSE; - - return TRUE; -} - - -static LRESULT -HEADER_SetImageList (HWND hwnd, HIMAGELIST himl) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - HIMAGELIST himlOld; - - TRACE("(himl 0x%x)\n", (int)himl); - himlOld = infoPtr->himl; - infoPtr->himl = himl; - - /* FIXME: Refresh needed??? */ - - return (LRESULT)himlOld; -} - - -static LRESULT -HEADER_GetBitmapMargin(HWND hwnd) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr(hwnd); - - return infoPtr->iMargin; -} - -static LRESULT -HEADER_SetBitmapMargin(HWND hwnd, WPARAM wParam) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - INT oldMargin = infoPtr->iMargin; - - infoPtr->iMargin = (INT)wParam; - - return oldMargin; -} - -static LRESULT -HEADER_SetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - HDITEMA *phdi = (HDITEMA*)lParam; - INT nItem = (INT)wParam; - HEADER_ITEM *lpItem; - - if (phdi == NULL) - return FALSE; - if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem)) - return FALSE; - - TRACE("[nItem=%d]\n", nItem); - - if (HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGINGA, nItem, phdi->mask)) - return FALSE; - - lpItem = &infoPtr->items[nItem]; - if (phdi->mask & HDI_BITMAP) - lpItem->hbm = phdi->hbm; - - if (phdi->mask & HDI_FORMAT) - lpItem->fmt = phdi->fmt; - - if (phdi->mask & HDI_LPARAM) - lpItem->lParam = phdi->lParam; - - if (phdi->mask & HDI_TEXT) { - if (phdi->pszText != LPSTR_TEXTCALLBACKA) { - if (lpItem->pszText) { - Free (lpItem->pszText); - lpItem->pszText = NULL; - } - if (phdi->pszText) { - INT len = MultiByteToWideChar (CP_ACP,0,phdi->pszText,-1,NULL,0); - lpItem->pszText = Alloc( len*sizeof(WCHAR) ); - MultiByteToWideChar (CP_ACP,0,phdi->pszText,-1,lpItem->pszText,len); - } - } - else - lpItem->pszText = LPSTR_TEXTCALLBACKW; - } - - if (phdi->mask & HDI_WIDTH) - lpItem->cxy = phdi->cxy; - - if (phdi->mask & HDI_IMAGE) - lpItem->iImage = phdi->iImage; - - if (phdi->mask & HDI_ORDER) - { - lpItem->iOrder = phdi->iOrder; - } - - HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGEDA, nItem, phdi->mask); - - HEADER_SetItemBounds (hwnd); - - InvalidateRect(hwnd, NULL, FALSE); - - return TRUE; -} - - -static LRESULT -HEADER_SetItemW (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - HDITEMW *phdi = (HDITEMW*)lParam; - INT nItem = (INT)wParam; - HEADER_ITEM *lpItem; - - if (phdi == NULL) - return FALSE; - if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem)) - return FALSE; - - TRACE("[nItem=%d]\n", nItem); - - if (HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGINGW, nItem, phdi->mask)) - return FALSE; - - lpItem = &infoPtr->items[nItem]; - if (phdi->mask & HDI_BITMAP) - lpItem->hbm = phdi->hbm; - - if (phdi->mask & HDI_FORMAT) - lpItem->fmt = phdi->fmt; - - if (phdi->mask & HDI_LPARAM) - lpItem->lParam = phdi->lParam; - - if (phdi->mask & HDI_TEXT) { - if (phdi->pszText != LPSTR_TEXTCALLBACKW) { - if (lpItem->pszText) { - Free (lpItem->pszText); - lpItem->pszText = NULL; - } - if (phdi->pszText) { - INT len = strlenW (phdi->pszText); - lpItem->pszText = Alloc ((len+1)*sizeof(WCHAR)); - strcpyW (lpItem->pszText, phdi->pszText); - } - } - else - lpItem->pszText = LPSTR_TEXTCALLBACKW; - } - - if (phdi->mask & HDI_WIDTH) - lpItem->cxy = phdi->cxy; - - if (phdi->mask & HDI_IMAGE) - lpItem->iImage = phdi->iImage; - - if (phdi->mask & HDI_ORDER) - { - lpItem->iOrder = phdi->iOrder; - } - - HEADER_SendHeaderNotify(hwnd, HDN_ITEMCHANGEDW, nItem, phdi->mask); - - HEADER_SetItemBounds (hwnd); - - InvalidateRect(hwnd, NULL, FALSE); - - return TRUE; -} - -inline static LRESULT -HEADER_SetUnicodeFormat (HWND hwnd, WPARAM wParam) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - BOOL bTemp = infoPtr->bUnicode; - - infoPtr->bUnicode = (BOOL)wParam; - - return bTemp; -} - - -static LRESULT -HEADER_Create (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - HEADER_INFO *infoPtr; - TEXTMETRICW tm; - HFONT hOldFont; - HDC hdc; - - infoPtr = (HEADER_INFO *)Alloc (sizeof(HEADER_INFO)); - SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); - - infoPtr->hwndNotify = ((LPCREATESTRUCTA)lParam)->hwndParent; - infoPtr->uNumItem = 0; - infoPtr->hFont = 0; - infoPtr->items = 0; - infoPtr->bRectsValid = FALSE; - infoPtr->hcurArrow = LoadCursorW (0, (LPWSTR)IDC_ARROW); - infoPtr->hcurDivider = LoadCursorW (COMCTL32_hModule, MAKEINTRESOURCEW(IDC_DIVIDER)); - infoPtr->hcurDivopen = LoadCursorW (COMCTL32_hModule, MAKEINTRESOURCEW(IDC_DIVIDEROPEN)); - infoPtr->bPressed = FALSE; - infoPtr->bTracking = FALSE; - infoPtr->iMoveItem = 0; - infoPtr->himl = 0; - infoPtr->iHotItem = -1; - infoPtr->bUnicode = IsWindowUnicode (hwnd); - infoPtr->iMargin = 3*GetSystemMetrics(SM_CXEDGE); - infoPtr->nNotifyFormat = - SendMessageW (infoPtr->hwndNotify, WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY); - - hdc = GetDC (0); - hOldFont = SelectObject (hdc, GetStockObject (SYSTEM_FONT)); - GetTextMetricsW (hdc, &tm); - infoPtr->nHeight = tm.tmHeight + VERT_BORDER; - SelectObject (hdc, hOldFont); - ReleaseDC (0, hdc); - - return 0; -} - - -static LRESULT -HEADER_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - HEADER_ITEM *lpItem; - INT nItem; - - if (infoPtr->items) { - lpItem = infoPtr->items; - for (nItem = 0; nItem < infoPtr->uNumItem; nItem++, lpItem++) { - if ((lpItem->pszText) && (lpItem->pszText != LPSTR_TEXTCALLBACKW)) - Free (lpItem->pszText); - } - Free (infoPtr->items); - } - - if (infoPtr->himl) - ImageList_Destroy (infoPtr->himl); - - SetWindowLongPtrW (hwnd, 0, 0); - Free (infoPtr); - return 0; -} - - -static inline LRESULT -HEADER_GetFont (HWND hwnd) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - - return (LRESULT)infoPtr->hFont; -} - - -static LRESULT -HEADER_LButtonDblClk (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - POINT pt; - UINT flags; - INT nItem; - - pt.x = (INT)LOWORD(lParam); - pt.y = (INT)HIWORD(lParam); - HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem); - - if ((GetWindowLongW (hwnd, GWL_STYLE) & HDS_BUTTONS) && (flags == HHT_ONHEADER)) - HEADER_SendHeaderNotify (hwnd, HDN_ITEMDBLCLICKA, nItem,0); - else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN)) - HEADER_SendHeaderNotify (hwnd, HDN_DIVIDERDBLCLICKA, nItem,0); - - return 0; -} - - -static LRESULT -HEADER_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE); - POINT pt; - UINT flags; - INT nItem; - HDC hdc; - - pt.x = (INT)LOWORD(lParam); - pt.y = (INT)HIWORD(lParam); - HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem); - - if ((dwStyle & HDS_BUTTONS) && (flags == HHT_ONHEADER)) { - SetCapture (hwnd); - infoPtr->bCaptured = TRUE; - infoPtr->bPressed = TRUE; - infoPtr->iMoveItem = nItem; - - infoPtr->items[nItem].bDown = TRUE; - - /* Send WM_CUSTOMDRAW */ - hdc = GetDC (hwnd); - HEADER_RefreshItem (hwnd, hdc, nItem); - ReleaseDC (hwnd, hdc); - - TRACE("Pressed item %d!\n", nItem); - } - else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN)) { - if (!(HEADER_SendHeaderNotify (hwnd, HDN_BEGINTRACKA, nItem,0))) { - SetCapture (hwnd); - infoPtr->bCaptured = TRUE; - infoPtr->bTracking = TRUE; - infoPtr->iMoveItem = nItem; - infoPtr->nOldWidth = infoPtr->items[nItem].cxy; - infoPtr->xTrackOffset = infoPtr->items[nItem].rect.right - pt.x; - - if (!(dwStyle & HDS_FULLDRAG)) { - infoPtr->xOldTrack = infoPtr->items[nItem].rect.right; - hdc = GetDC (hwnd); - HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack); - ReleaseDC (hwnd, hdc); - } - - TRACE("Begin tracking item %d!\n", nItem); - } - } - - return 0; -} - - -static LRESULT -HEADER_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - /* - *DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE); - */ - POINT pt; - UINT flags; - INT nItem, nWidth; - HDC hdc; - - pt.x = (INT)(SHORT)LOWORD(lParam); - pt.y = (INT)(SHORT)HIWORD(lParam); - HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem); - - if (infoPtr->bPressed) { - if ((nItem == infoPtr->iMoveItem) && (flags == HHT_ONHEADER)) { - infoPtr->items[infoPtr->iMoveItem].bDown = FALSE; - hdc = GetDC (hwnd); - HEADER_RefreshItem (hwnd, hdc, infoPtr->iMoveItem); - ReleaseDC (hwnd, hdc); - - HEADER_SendClickNotify (hwnd, HDN_ITEMCLICKA, infoPtr->iMoveItem); - } - else if (flags == HHT_ONHEADER) - { - HEADER_ITEM *lpItem; - INT newindex = HEADER_IndexToOrder(hwnd,nItem); - INT oldindex = HEADER_IndexToOrder(hwnd,infoPtr->iMoveItem); - - TRACE("Exchanging [index:order] [%d:%d] [%d:%d]\n", - infoPtr->iMoveItem,oldindex,nItem,newindex); - lpItem= &infoPtr->items[nItem]; - lpItem->iOrder=oldindex; - - lpItem= &infoPtr->items[infoPtr->iMoveItem]; - lpItem->iOrder = newindex; - - infoPtr->bRectsValid = FALSE; - InvalidateRect(hwnd, NULL, FALSE); - /* FIXME: Should some WM_NOTIFY be sent */ - } - - TRACE("Released item %d!\n", infoPtr->iMoveItem); - infoPtr->bPressed = FALSE; - } - else if (infoPtr->bTracking) { - TRACE("End tracking item %d!\n", infoPtr->iMoveItem); - infoPtr->bTracking = FALSE; - - HEADER_SendHeaderNotify (hwnd, HDN_ENDTRACKA, infoPtr->iMoveItem,HDI_WIDTH); - - /* - * we want to do this even for HDS_FULLDRAG because this is where - * we send the HDN_ITEMCHANGING and HDN_ITEMCHANGED notifications - * - * if (!(dwStyle & HDS_FULLDRAG)) { - */ - - hdc = GetDC (hwnd); - HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack); - ReleaseDC (hwnd, hdc); - if (HEADER_SendHeaderNotify(hwnd, HDN_ITEMCHANGINGA, infoPtr->iMoveItem, HDI_WIDTH)) - { - infoPtr->items[infoPtr->iMoveItem].cxy = infoPtr->nOldWidth; - } - else { - nWidth = pt.x - infoPtr->items[infoPtr->iMoveItem].rect.left + infoPtr->xTrackOffset; - if (nWidth < 0) - nWidth = 0; - infoPtr->items[infoPtr->iMoveItem].cxy = nWidth; - } - - HEADER_SetItemBounds (hwnd); - InvalidateRect(hwnd, NULL, TRUE); - HEADER_SendHeaderNotify(hwnd, HDN_ITEMCHANGEDA, infoPtr->iMoveItem, HDI_WIDTH); - /* - * } - */ - } - - if (infoPtr->bCaptured) { - infoPtr->bCaptured = FALSE; - ReleaseCapture (); - HEADER_SendSimpleNotify (hwnd, NM_RELEASEDCAPTURE); - } - - return 0; -} - - -static LRESULT -HEADER_NotifyFormat (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - - switch (lParam) - { - case NF_QUERY: - return infoPtr->nNotifyFormat; - - case NF_REQUERY: - infoPtr->nNotifyFormat = - SendMessageW ((HWND)wParam, WM_NOTIFYFORMAT, - (WPARAM)hwnd, (LPARAM)NF_QUERY); - return infoPtr->nNotifyFormat; - } - - return 0; -} - - -static LRESULT -HEADER_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE); - POINT pt; - UINT flags; - INT nItem, nWidth; - HDC hdc; - - pt.x = (INT)(SHORT)LOWORD(lParam); - pt.y = (INT)(SHORT)HIWORD(lParam); - HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem); - - if ((dwStyle & HDS_BUTTONS) && (dwStyle & HDS_HOTTRACK)) { - if (flags & (HHT_ONHEADER | HHT_ONDIVIDER | HHT_ONDIVOPEN)) - infoPtr->iHotItem = nItem; - else - infoPtr->iHotItem = -1; - InvalidateRect(hwnd, NULL, FALSE); - } - - if (infoPtr->bCaptured) { - if (infoPtr->bPressed) { - if ((nItem == infoPtr->iMoveItem) && (flags == HHT_ONHEADER)) - infoPtr->items[infoPtr->iMoveItem].bDown = TRUE; - else - infoPtr->items[infoPtr->iMoveItem].bDown = FALSE; - hdc = GetDC (hwnd); - HEADER_RefreshItem (hwnd, hdc, infoPtr->iMoveItem); - ReleaseDC (hwnd, hdc); - - TRACE("Moving pressed item %d!\n", infoPtr->iMoveItem); - } - else if (infoPtr->bTracking) { - if (dwStyle & HDS_FULLDRAG) { - if (HEADER_SendHeaderNotify (hwnd, HDN_TRACKA, infoPtr->iMoveItem, HDI_WIDTH)) - { - nWidth = pt.x - infoPtr->items[infoPtr->iMoveItem].rect.left + infoPtr->xTrackOffset; - if (nWidth < 0) - nWidth = 0; - infoPtr->items[infoPtr->iMoveItem].cxy = nWidth; - HEADER_SendHeaderNotify(hwnd, HDN_ITEMCHANGEDA, infoPtr->iMoveItem, HDI_WIDTH); - } - HEADER_SetItemBounds (hwnd); - } - else { - hdc = GetDC (hwnd); - HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack); - infoPtr->xOldTrack = pt.x + infoPtr->xTrackOffset; - if (infoPtr->xOldTrack < infoPtr->items[infoPtr->iMoveItem].rect.left) - infoPtr->xOldTrack = infoPtr->items[infoPtr->iMoveItem].rect.left; - infoPtr->items[infoPtr->iMoveItem].cxy = - infoPtr->xOldTrack - infoPtr->items[infoPtr->iMoveItem].rect.left; - HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack); - ReleaseDC (hwnd, hdc); - HEADER_SendHeaderNotify (hwnd, HDN_TRACKA, infoPtr->iMoveItem, HDI_WIDTH); - } - - TRACE("Tracking item %d!\n", infoPtr->iMoveItem); - } - } - - if ((dwStyle & HDS_BUTTONS) && (dwStyle & HDS_HOTTRACK)) { - FIXME("hot track support!\n"); - } - - return 0; -} - - -static LRESULT -HEADER_Paint (HWND hwnd, WPARAM wParam) -{ - HDC hdc; - PAINTSTRUCT ps; - - hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam; - HEADER_Refresh (hwnd, hdc); - if(!wParam) - EndPaint (hwnd, &ps); - return 0; -} - - -static LRESULT -HEADER_RButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - BOOL bRet; - POINT pt; - - pt.x = LOWORD(lParam); - pt.y = HIWORD(lParam); - - /* Send a Notify message */ - bRet = HEADER_SendSimpleNotify (hwnd, NM_RCLICK); - - /* Change to screen coordinate for WM_CONTEXTMENU */ - ClientToScreen(hwnd, &pt); - - /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */ - SendMessageW( hwnd, WM_CONTEXTMENU, (WPARAM) hwnd, MAKELPARAM(pt.x, pt.y)); - - return bRet; -} - - -static LRESULT -HEADER_SetCursor (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - POINT pt; - UINT flags; - INT nItem; - - TRACE("code=0x%X id=0x%X\n", LOWORD(lParam), HIWORD(lParam)); - - GetCursorPos (&pt); - ScreenToClient (hwnd, &pt); - - HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem); - - if (flags == HHT_ONDIVIDER) - SetCursor (infoPtr->hcurDivider); - else if (flags == HHT_ONDIVOPEN) - SetCursor (infoPtr->hcurDivopen); - else - SetCursor (infoPtr->hcurArrow); - - return 0; -} - - -static LRESULT -HEADER_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); - TEXTMETRICW tm; - HFONT hFont, hOldFont; - HDC hdc; - - infoPtr->hFont = (HFONT)wParam; - - hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT); - - hdc = GetDC (0); - hOldFont = SelectObject (hdc, hFont); - GetTextMetricsW (hdc, &tm); - infoPtr->nHeight = tm.tmHeight + VERT_BORDER; - SelectObject (hdc, hOldFont); - ReleaseDC (0, hdc); - - infoPtr->bRectsValid = FALSE; - - if (lParam) { - InvalidateRect(hwnd, NULL, FALSE); - } - - return 0; -} - - -static LRESULT WINAPI -HEADER_WindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - TRACE("hwnd=%p msg=%x wparam=%x lParam=%lx\n", hwnd, msg, wParam, lParam); - if (!HEADER_GetInfoPtr (hwnd) && (msg != WM_CREATE)) - return DefWindowProcW (hwnd, msg, wParam, lParam); - switch (msg) { -/* case HDM_CLEARFILTER: */ - - case HDM_CREATEDRAGIMAGE: - return HEADER_CreateDragImage (hwnd, wParam); - - case HDM_DELETEITEM: - return HEADER_DeleteItem (hwnd, wParam); - -/* case HDM_EDITFILTER: */ - - case HDM_GETBITMAPMARGIN: - return HEADER_GetBitmapMargin(hwnd); - - case HDM_GETIMAGELIST: - return HEADER_GetImageList (hwnd); - - case HDM_GETITEMA: - return HEADER_GetItemA (hwnd, wParam, lParam); - - case HDM_GETITEMW: - return HEADER_GetItemW (hwnd, wParam, lParam); - - case HDM_GETITEMCOUNT: - return HEADER_GetItemCount (hwnd); - - case HDM_GETITEMRECT: - return HEADER_GetItemRect (hwnd, wParam, lParam); - - case HDM_GETORDERARRAY: - return HEADER_GetOrderArray(hwnd, wParam, lParam); - - case HDM_GETUNICODEFORMAT: - return HEADER_GetUnicodeFormat (hwnd); - - case HDM_HITTEST: - return HEADER_HitTest (hwnd, wParam, lParam); - - case HDM_INSERTITEMA: - return HEADER_InsertItemA (hwnd, wParam, lParam); - - case HDM_INSERTITEMW: - return HEADER_InsertItemW (hwnd, wParam, lParam); - - case HDM_LAYOUT: - return HEADER_Layout (hwnd, wParam, lParam); - - case HDM_ORDERTOINDEX: - return HEADER_OrderToIndex(hwnd, wParam); - - case HDM_SETBITMAPMARGIN: - return HEADER_SetBitmapMargin(hwnd, wParam); - -/* case HDM_SETFILTERCHANGETIMEOUT: */ - -/* case HDM_SETHOTDIVIDER: */ - - case HDM_SETIMAGELIST: - return HEADER_SetImageList (hwnd, (HIMAGELIST)lParam); - - case HDM_SETITEMA: - return HEADER_SetItemA (hwnd, wParam, lParam); - - case HDM_SETITEMW: - return HEADER_SetItemW (hwnd, wParam, lParam); - - case HDM_SETORDERARRAY: - return HEADER_SetOrderArray(hwnd, wParam, lParam); - - case HDM_SETUNICODEFORMAT: - return HEADER_SetUnicodeFormat (hwnd, wParam); - - case WM_CREATE: - return HEADER_Create (hwnd, wParam, lParam); - - case WM_DESTROY: - return HEADER_Destroy (hwnd, wParam, lParam); - - case WM_ERASEBKGND: - return 1; - - case WM_GETDLGCODE: - return DLGC_WANTTAB | DLGC_WANTARROWS; - - case WM_GETFONT: - return HEADER_GetFont (hwnd); - - case WM_LBUTTONDBLCLK: - return HEADER_LButtonDblClk (hwnd, wParam, lParam); - - case WM_LBUTTONDOWN: - return HEADER_LButtonDown (hwnd, wParam, lParam); - - case WM_LBUTTONUP: - return HEADER_LButtonUp (hwnd, wParam, lParam); - - case WM_MOUSEMOVE: - return HEADER_MouseMove (hwnd, wParam, lParam); - - case WM_NOTIFYFORMAT: - return HEADER_NotifyFormat (hwnd, wParam, lParam); - - case WM_SIZE: - return HEADER_Size (hwnd, wParam); - - case WM_PAINT: - return HEADER_Paint (hwnd, wParam); - - case WM_RBUTTONUP: - return HEADER_RButtonUp (hwnd, wParam, lParam); - - case WM_SETCURSOR: - return HEADER_SetCursor (hwnd, wParam, lParam); - - case WM_SETFONT: - return HEADER_SetFont (hwnd, wParam, lParam); - - default: - if ((msg >= WM_USER) && (msg < WM_APP)) - ERR("unknown msg %04x wp=%04x lp=%08lx\n", - msg, wParam, lParam ); - return DefWindowProcA (hwnd, msg, wParam, lParam); - } -} - - -VOID -HEADER_Register (void) -{ - WNDCLASSW wndClass; - - ZeroMemory (&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS; - wndClass.lpfnWndProc = HEADER_WindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(HEADER_INFO *); - wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); - wndClass.lpszClassName = WC_HEADERW; - - RegisterClassW (&wndClass); -} - - -VOID -HEADER_Unregister (void) -{ - UnregisterClassW (WC_HEADERW, NULL); -} +/* + * Header control + * + * Copyright 1998 Eric Kohl + * Copyright 2000 Eric Kohl for CodeWeavers + * Copyright 2003 Maxime Bellenge + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * TODO: + * - Imagelist support (partially). + * - Callback items (under construction). + * - Hottrack support (partially). + * - Custom draw support (including Notifications). + * - Drag and Drop support (including Notifications). + * - New messages. + * - Use notification format + * - Correct the order maintenance code to preserve valid order + * + */ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wine/unicode.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "comctl32.h" +#include "imagelist.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(header); + +typedef struct +{ + INT cxy; + HBITMAP hbm; + LPWSTR pszText; + INT fmt; + LPARAM lParam; + INT iImage; + INT iOrder; /* see documentation of HD_ITEM */ + + BOOL bDown; /* is item pressed? (used for drawing) */ + RECT rect; /* bounding rectangle of the item */ +} HEADER_ITEM; + + +typedef struct +{ + HWND hwndNotify; /* Owner window to send notifications to */ + INT nNotifyFormat; /* format used for WM_NOTIFY messages */ + UINT uNumItem; /* number of items (columns) */ + INT nHeight; /* height of the header (pixels) */ + HFONT hFont; /* handle to the current font */ + HCURSOR hcurArrow; /* handle to the arrow cursor */ + HCURSOR hcurDivider; /* handle to a cursor (used over dividers) <-|-> */ + HCURSOR hcurDivopen; /* handle to a cursor (used over dividers) <-||-> */ + BOOL bCaptured; /* Is the mouse captured? */ + BOOL bPressed; /* Is a header item pressed (down)? */ + BOOL bTracking; /* Is in tracking mode? */ + BOOL bUnicode; /* Unicode flag */ + INT iMoveItem; /* index of tracked item. (Tracking mode) */ + INT xTrackOffset; /* distance between the right side of the tracked item and the cursor */ + INT xOldTrack; /* track offset (see above) after the last WM_MOUSEMOVE */ + INT nOldWidth; /* width of a sizing item after the last WM_MOUSEMOVE */ + INT iHotItem; /* index of hot item (cursor is over this item) */ + INT iMargin; /* width of the margin that surrounds a bitmap */ + + HIMAGELIST himl; /* handle to an image list (may be 0) */ + HEADER_ITEM *items; /* pointer to array of HEADER_ITEM's */ + BOOL bRectsValid; /* validity flag for bounding rectangles */ +} HEADER_INFO; + + +#define VERT_BORDER 3 +#define DIVIDER_WIDTH 10 + +#define HEADER_GetInfoPtr(hwnd) ((HEADER_INFO *)GetWindowLongPtrW(hwnd,0)) + + +inline static LRESULT +HEADER_IndexToOrder (HWND hwnd, INT iItem) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + HEADER_ITEM *lpItem = &infoPtr->items[iItem]; + return lpItem->iOrder; +} + + +static INT +HEADER_OrderToIndex(HWND hwnd, WPARAM wParam) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + INT iorder = (INT)wParam; + UINT i; + + if ((iorder <0) || iorder >infoPtr->uNumItem) + return iorder; + for (i=0; iuNumItem; i++) + if (HEADER_IndexToOrder(hwnd,i) == iorder) + return i; + return iorder; +} + +static void +HEADER_SetItemBounds (HWND hwnd) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + HEADER_ITEM *phdi; + RECT rect; + unsigned int i; + int x; + + infoPtr->bRectsValid = TRUE; + + if (infoPtr->uNumItem == 0) + return; + + GetClientRect (hwnd, &rect); + + x = rect.left; + for (i = 0; i < infoPtr->uNumItem; i++) { + phdi = &infoPtr->items[HEADER_OrderToIndex(hwnd,i)]; + phdi->rect.top = rect.top; + phdi->rect.bottom = rect.bottom; + phdi->rect.left = x; + phdi->rect.right = phdi->rect.left + ((phdi->cxy>0)?phdi->cxy:0); + x = phdi->rect.right; + } +} + +static LRESULT +HEADER_Size (HWND hwnd, WPARAM wParam) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + + infoPtr->bRectsValid = FALSE; + + return 0; +} + + +static INT +HEADER_DrawItem (HWND hwnd, HDC hdc, INT iItem, BOOL bHotTrack) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + HEADER_ITEM *phdi = &infoPtr->items[iItem]; + RECT r; + INT oldBkMode, cxEdge = GetSystemMetrics(SM_CXEDGE); + + TRACE("DrawItem(iItem %d bHotTrack %d unicode flag %d)\n", iItem, bHotTrack, infoPtr->bUnicode); + + if (!infoPtr->bRectsValid) + HEADER_SetItemBounds(hwnd); + + r = phdi->rect; + if (r.right - r.left == 0) + return phdi->rect.right; + + if (GetWindowLongW (hwnd, GWL_STYLE) & HDS_BUTTONS) { + if (phdi->bDown) { + DrawEdge (hdc, &r, BDR_RAISEDOUTER, + BF_RECT | BF_FLAT | BF_MIDDLE | BF_ADJUST); + r.left += 2; + r.top += 2; + } + else + DrawEdge (hdc, &r, EDGE_RAISED, + BF_RECT | BF_SOFT | BF_MIDDLE | BF_ADJUST); + } + else + DrawEdge (hdc, &r, EDGE_ETCHED, BF_BOTTOM | BF_RIGHT | BF_ADJUST); + + r.left -= cxEdge; + r.right += cxEdge; + + if (phdi->fmt & HDF_OWNERDRAW) { + DRAWITEMSTRUCT dis; + dis.CtlType = ODT_HEADER; + dis.CtlID = GetWindowLongPtrW (hwnd, GWLP_ID); + dis.itemID = iItem; + dis.itemAction = ODA_DRAWENTIRE; + dis.itemState = phdi->bDown ? ODS_SELECTED : 0; + dis.hwndItem = hwnd; + dis.hDC = hdc; + dis.rcItem = r; + dis.itemData = phdi->lParam; + oldBkMode = SetBkMode(hdc, TRANSPARENT); + SendMessageW (infoPtr->hwndNotify, WM_DRAWITEM, + (WPARAM)dis.CtlID, (LPARAM)&dis); + if (oldBkMode != TRANSPARENT) + SetBkMode(hdc, oldBkMode); + } + else { + UINT rw, rh, /* width and height of r */ + *x = NULL, *w = NULL; /* x and width of the pic (bmp or img) which is part of cnt */ + /* cnt,txt,img,bmp */ + UINT cx, tx, ix, bx, + cw, tw, iw, bw; + BITMAP bmp; + + cw = tw = iw = bw = 0; + rw = r.right - r.left; + rh = r.bottom - r.top; + + if (phdi->fmt & HDF_STRING) { + RECT textRect; + + DrawTextW (hdc, phdi->pszText, -1, + &textRect, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_CALCRECT); + cw = textRect.right - textRect.left + 2 * infoPtr->iMargin; + } + + if ((phdi->fmt & HDF_IMAGE) && (infoPtr->himl)) { + iw = infoPtr->himl->cx + 2 * infoPtr->iMargin; + x = &ix; + w = &iw; + } + + if ((phdi->fmt & HDF_BITMAP) && (phdi->hbm)) { + GetObjectW (phdi->hbm, sizeof(BITMAP), (LPVOID)&bmp); + bw = bmp.bmWidth + 2 * infoPtr->iMargin; + if (!iw) { + x = &bx; + w = &bw; + } + } + + if (bw || iw) + cw += *w; + + /* align cx using the unclipped cw */ + if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_LEFT) + cx = r.left; + else if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_CENTER) + cx = r.left + rw / 2 - cw / 2; + else /* HDF_RIGHT */ + cx = r.right - cw; + + /* clip cx & cw */ + if (cx < r.left) + cx = r.left; + if (cx + cw > r.right) + cw = r.right - cx; + + tx = cx + infoPtr->iMargin; + /* since cw might have changed we have to recalculate tw */ + tw = cw - infoPtr->iMargin * 2; + + if (iw || bw) { + tw -= *w; + if (phdi->fmt & HDF_BITMAP_ON_RIGHT) { + /* put pic behind text */ + *x = cx + tw + infoPtr->iMargin * 3; + } else { + *x = cx + infoPtr->iMargin; + /* move text behind pic */ + tx += *w; + } + } + + if (iw && bw) { + /* since we're done with the layout we can + now calculate the position of bmp which + has no influence on alignment and layout + because of img */ + if ((phdi->fmt & HDF_JUSTIFYMASK) == HDF_RIGHT) + bx = cx - bw + infoPtr->iMargin; + else + bx = cx + cw + infoPtr->iMargin; + } + + if (iw || bw) { + HDC hClipDC = GetDC(hwnd); + HRGN hClipRgn = CreateRectRgn(r.left, r.top, r.right, r.bottom); + + SelectClipRgn(hClipDC, hClipRgn); + if (bw) { + HDC hdcBitmap = CreateCompatibleDC (hClipDC); + SelectObject (hdcBitmap, phdi->hbm); + BitBlt (hClipDC, bx, r.top + ((INT)rh - bmp.bmHeight) / 2, + bmp.bmWidth, bmp.bmHeight, hdcBitmap, 0, 0, SRCCOPY); + DeleteDC (hdcBitmap); + } + + if (iw) { + ImageList_DrawEx (infoPtr->himl, phdi->iImage, hClipDC, + ix, r.top + ((INT)rh - infoPtr->himl->cy) / 2, + infoPtr->himl->cx, infoPtr->himl->cy, CLR_DEFAULT, CLR_DEFAULT, 0); + } + + DeleteObject(hClipRgn); + ReleaseDC(hwnd, hClipDC); + } + + if (((phdi->fmt & HDF_STRING) + || (!(phdi->fmt & (HDF_OWNERDRAW|HDF_STRING|HDF_BITMAP| + HDF_BITMAP_ON_RIGHT|HDF_IMAGE)))) /* no explicit format specified? */ + && (phdi->pszText)) { + oldBkMode = SetBkMode(hdc, TRANSPARENT); + SetTextColor (hdc, (bHotTrack) ? COLOR_HIGHLIGHT : COLOR_BTNTEXT); + r.left = tx; + r.right = tx + tw; + DrawTextW (hdc, phdi->pszText, -1, + &r, DT_LEFT|DT_END_ELLIPSIS|DT_VCENTER|DT_SINGLELINE); + if (oldBkMode != TRANSPARENT) + SetBkMode(hdc, oldBkMode); + } + }/*Ownerdrawn*/ + + return phdi->rect.right; +} + + +static void +HEADER_Refresh (HWND hwnd, HDC hdc) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + HFONT hFont, hOldFont; + RECT rect; + HBRUSH hbrBk; + UINT i; + INT x; + + /* get rect for the bar, adjusted for the border */ + GetClientRect (hwnd, &rect); + + hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT); + hOldFont = SelectObject (hdc, hFont); + + /* draw Background */ + hbrBk = GetSysColorBrush(COLOR_3DFACE); + FillRect(hdc, &rect, hbrBk); + + x = rect.left; + for (i = 0; i < infoPtr->uNumItem; i++) { + x = HEADER_DrawItem (hwnd, hdc, HEADER_OrderToIndex(hwnd,i), FALSE); + } + + if ((x <= rect.right) && (infoPtr->uNumItem > 0)) { + rect.left = x; + if (GetWindowLongW (hwnd, GWL_STYLE) & HDS_BUTTONS) + DrawEdge (hdc, &rect, EDGE_RAISED, BF_TOP|BF_LEFT|BF_BOTTOM|BF_SOFT); + else + DrawEdge (hdc, &rect, EDGE_ETCHED, BF_BOTTOM); + } + + SelectObject (hdc, hOldFont); +} + + +static void +HEADER_RefreshItem (HWND hwnd, HDC hdc, INT iItem) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + HFONT hFont, hOldFont; + + hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT); + hOldFont = SelectObject (hdc, hFont); + HEADER_DrawItem (hwnd, hdc, iItem, FALSE); + SelectObject (hdc, hOldFont); +} + + +static void +HEADER_InternalHitTest (HWND hwnd, LPPOINT lpPt, UINT *pFlags, INT *pItem) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + RECT rect, rcTest; + UINT iCount; + INT width; + BOOL bNoWidth; + + GetClientRect (hwnd, &rect); + + *pFlags = 0; + bNoWidth = FALSE; + if (PtInRect (&rect, *lpPt)) + { + if (infoPtr->uNumItem == 0) { + *pFlags |= HHT_NOWHERE; + *pItem = 1; + TRACE("NOWHERE\n"); + return; + } + else { + /* somewhere inside */ + for (iCount = 0; iCount < infoPtr->uNumItem; iCount++) { + rect = infoPtr->items[iCount].rect; + width = rect.right - rect.left; + if (width == 0) { + bNoWidth = TRUE; + continue; + } + if (PtInRect (&rect, *lpPt)) { + if (width <= 2 * DIVIDER_WIDTH) { + *pFlags |= HHT_ONHEADER; + *pItem = iCount; + TRACE("ON HEADER %d\n", iCount); + return; + } + if (iCount > 0) { + rcTest = rect; + rcTest.right = rcTest.left + DIVIDER_WIDTH; + if (PtInRect (&rcTest, *lpPt)) { + if (bNoWidth) { + *pFlags |= HHT_ONDIVOPEN; + *pItem = iCount - 1; + TRACE("ON DIVOPEN %d\n", *pItem); + return; + } + else { + *pFlags |= HHT_ONDIVIDER; + *pItem = iCount - 1; + TRACE("ON DIVIDER %d\n", *pItem); + return; + } + } + } + rcTest = rect; + rcTest.left = rcTest.right - DIVIDER_WIDTH; + if (PtInRect (&rcTest, *lpPt)) { + *pFlags |= HHT_ONDIVIDER; + *pItem = iCount; + TRACE("ON DIVIDER %d\n", *pItem); + return; + } + + *pFlags |= HHT_ONHEADER; + *pItem = iCount; + TRACE("ON HEADER %d\n", iCount); + return; + } + } + + /* check for last divider part (on nowhere) */ + rect = infoPtr->items[infoPtr->uNumItem-1].rect; + rect.left = rect.right; + rect.right += DIVIDER_WIDTH; + if (PtInRect (&rect, *lpPt)) { + if (bNoWidth) { + *pFlags |= HHT_ONDIVOPEN; + *pItem = infoPtr->uNumItem - 1; + TRACE("ON DIVOPEN %d\n", *pItem); + return; + } + else { + *pFlags |= HHT_ONDIVIDER; + *pItem = infoPtr->uNumItem-1; + TRACE("ON DIVIDER %d\n", *pItem); + return; + } + } + + *pFlags |= HHT_NOWHERE; + *pItem = 1; + TRACE("NOWHERE\n"); + return; + } + } + else { + if (lpPt->x < rect.left) { + TRACE("TO LEFT\n"); + *pFlags |= HHT_TOLEFT; + } + else if (lpPt->x > rect.right) { + TRACE("TO RIGHT\n"); + *pFlags |= HHT_TORIGHT; + } + + if (lpPt->y < rect.top) { + TRACE("ABOVE\n"); + *pFlags |= HHT_ABOVE; + } + else if (lpPt->y > rect.bottom) { + TRACE("BELOW\n"); + *pFlags |= HHT_BELOW; + } + } + + *pItem = 1; + TRACE("flags=0x%X\n", *pFlags); + return; +} + + +static void +HEADER_DrawTrackLine (HWND hwnd, HDC hdc, INT x) +{ + RECT rect; + HPEN hOldPen; + INT oldRop; + + GetClientRect (hwnd, &rect); + + hOldPen = SelectObject (hdc, GetStockObject (BLACK_PEN)); + oldRop = SetROP2 (hdc, R2_XORPEN); + MoveToEx (hdc, x, rect.top, NULL); + LineTo (hdc, x, rect.bottom); + SetROP2 (hdc, oldRop); + SelectObject (hdc, hOldPen); +} + + +static BOOL +HEADER_SendSimpleNotify (HWND hwnd, UINT code) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + NMHDR nmhdr; + + nmhdr.hwndFrom = hwnd; + nmhdr.idFrom = GetWindowLongPtrW (hwnd, GWLP_ID); + nmhdr.code = code; + + return (BOOL)SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, + (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr); +} + +static BOOL +HEADER_SendHeaderNotify (HWND hwnd, UINT code, INT iItem, INT mask) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + NMHEADERA nmhdr; + HDITEMA nmitem; + + nmhdr.hdr.hwndFrom = hwnd; + nmhdr.hdr.idFrom = GetWindowLongPtrW (hwnd, GWLP_ID); + nmhdr.hdr.code = code; + nmhdr.iItem = iItem; + nmhdr.iButton = 0; + nmhdr.pitem = &nmitem; + nmitem.mask = mask; + nmitem.cxy = infoPtr->items[iItem].cxy; + nmitem.hbm = infoPtr->items[iItem].hbm; + nmitem.pszText = NULL; + nmitem.cchTextMax = 0; +/* nmitem.pszText = infoPtr->items[iItem].pszText; */ +/* nmitem.cchTextMax = infoPtr->items[iItem].cchTextMax; */ + nmitem.fmt = infoPtr->items[iItem].fmt; + nmitem.lParam = infoPtr->items[iItem].lParam; + nmitem.iOrder = infoPtr->items[iItem].iOrder; + nmitem.iImage = infoPtr->items[iItem].iImage; + + return (BOOL)SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, + (WPARAM)nmhdr.hdr.idFrom, (LPARAM)&nmhdr); +} + + +static BOOL +HEADER_SendClickNotify (HWND hwnd, UINT code, INT iItem) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + NMHEADERA nmhdr; + + nmhdr.hdr.hwndFrom = hwnd; + nmhdr.hdr.idFrom = GetWindowLongPtrW (hwnd, GWLP_ID); + nmhdr.hdr.code = code; + nmhdr.iItem = iItem; + nmhdr.iButton = 0; + nmhdr.pitem = NULL; + + return (BOOL)SendMessageA (infoPtr->hwndNotify, WM_NOTIFY, + (WPARAM)nmhdr.hdr.idFrom, (LPARAM)&nmhdr); +} + + +static LRESULT +HEADER_CreateDragImage (HWND hwnd, WPARAM wParam) +{ + FIXME("empty stub!\n"); + return 0; +} + + +static LRESULT +HEADER_DeleteItem (HWND hwnd, WPARAM wParam) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr(hwnd); + INT iItem = (INT)wParam; + + TRACE("[iItem=%d]\n", iItem); + + if ((iItem < 0) || (iItem >= (INT)infoPtr->uNumItem)) + return FALSE; + + if (infoPtr->uNumItem == 1) { + TRACE("Simple delete!\n"); + if (infoPtr->items[0].pszText) + Free (infoPtr->items[0].pszText); + Free (infoPtr->items); + infoPtr->items = 0; + infoPtr->uNumItem = 0; + } + else { + HEADER_ITEM *oldItems = infoPtr->items; + HEADER_ITEM *pItem; + INT i; + INT iOrder; + TRACE("Complex delete! [iItem=%d]\n", iItem); + + if (infoPtr->items[iItem].pszText) + Free (infoPtr->items[iItem].pszText); + iOrder = infoPtr->items[iItem].iOrder; + + infoPtr->uNumItem--; + infoPtr->items = Alloc (sizeof (HEADER_ITEM) * infoPtr->uNumItem); + /* pre delete copy */ + if (iItem > 0) { + memcpy (&infoPtr->items[0], &oldItems[0], + iItem * sizeof(HEADER_ITEM)); + } + + /* post delete copy */ + if (iItem < infoPtr->uNumItem) { + memcpy (&infoPtr->items[iItem], &oldItems[iItem+1], + (infoPtr->uNumItem - iItem) * sizeof(HEADER_ITEM)); + } + + /* Correct the orders */ + for (i=infoPtr->uNumItem, pItem = infoPtr->items; i; i--, pItem++) + { + if (pItem->iOrder > iOrder) + pItem->iOrder--; + } + Free (oldItems); + } + + HEADER_SetItemBounds (hwnd); + + InvalidateRect(hwnd, NULL, FALSE); + + return TRUE; +} + + +static LRESULT +HEADER_GetImageList (HWND hwnd) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + + return (LRESULT)infoPtr->himl; +} + + +static LRESULT +HEADER_GetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + HDITEMA *phdi = (HDITEMA*)lParam; + INT nItem = (INT)wParam; + HEADER_ITEM *lpItem; + + if (!phdi) + return FALSE; + + TRACE("[nItem=%d]\n", nItem); + + if (phdi->mask == 0) + return TRUE; + + if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem)) { + lpItem = NULL; + } + else { + lpItem = &infoPtr->items[nItem]; + } + + if (phdi->mask & HDI_BITMAP) + phdi->hbm = (lpItem != NULL) ? lpItem->hbm : 0; + + if (phdi->mask & HDI_FORMAT) + phdi->fmt = (lpItem != NULL) ? lpItem->fmt : 0; + + if (phdi->mask & HDI_WIDTH) + phdi->cxy = (lpItem != NULL) ? lpItem->cxy : 0; + + if (phdi->mask & HDI_LPARAM) + phdi->lParam = (lpItem != NULL) ? lpItem->lParam : 0; + + if (phdi->mask & HDI_TEXT) { + if (lpItem == NULL) { + *phdi->pszText = 0; + } + else if (lpItem->pszText != LPSTR_TEXTCALLBACKW) { + if (lpItem->pszText) + WideCharToMultiByte (CP_ACP, 0, lpItem->pszText, -1, + phdi->pszText, phdi->cchTextMax, NULL, NULL); + else + *phdi->pszText = 0; + } + else + phdi->pszText = LPSTR_TEXTCALLBACKA; + } + + if (phdi->mask & HDI_IMAGE) + phdi->iImage = (lpItem != NULL) ? lpItem->iImage : 0; + + if (phdi->mask & HDI_ORDER) + phdi->iOrder = (lpItem != NULL) ? lpItem->iOrder : 0; + + return TRUE; +} + + +static LRESULT +HEADER_GetItemW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + HDITEMW *phdi = (HDITEMW*)lParam; + INT nItem = (INT)wParam; + HEADER_ITEM *lpItem; + + if (!phdi) + return FALSE; + + TRACE("[nItem=%d]\n", nItem); + + if (phdi->mask == 0) + return TRUE; + + if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem)) { + lpItem = NULL; + } + else { + lpItem = &infoPtr->items[nItem]; + } + + if (phdi->mask & HDI_BITMAP) + phdi->hbm = (lpItem != NULL) ? lpItem->hbm : 0; + + if (phdi->mask & HDI_FORMAT) + phdi->fmt = (lpItem != NULL) ? lpItem->fmt : 0; + + if (phdi->mask & HDI_WIDTH) + phdi->cxy = (lpItem != NULL) ? lpItem->cxy : 0; + + if (phdi->mask & HDI_LPARAM) + phdi->lParam = (lpItem != NULL) ? lpItem->lParam : 0; + + if (phdi->mask & HDI_TEXT) { + if (lpItem == NULL) { + *phdi->pszText = 0; + } + else if (lpItem->pszText != LPSTR_TEXTCALLBACKW) { + if (lpItem->pszText) + lstrcpynW (phdi->pszText, lpItem->pszText, phdi->cchTextMax); + else + *phdi->pszText = 0; + } + else + phdi->pszText = LPSTR_TEXTCALLBACKW; + } + + if (phdi->mask & HDI_IMAGE) + phdi->iImage = (lpItem != NULL) ? lpItem->iImage : 0; + + if (phdi->mask & HDI_ORDER) + phdi->iOrder = (lpItem != NULL) ? lpItem->iOrder : 0; + + return TRUE; +} + + +inline static LRESULT +HEADER_GetItemCount (HWND hwnd) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + return infoPtr->uNumItem; +} + + +static LRESULT +HEADER_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + INT iItem = (INT)wParam; + LPRECT lpRect = (LPRECT)lParam; + + if ((iItem < 0) || (iItem >= (INT)infoPtr->uNumItem)) + return FALSE; + + lpRect->left = infoPtr->items[iItem].rect.left; + lpRect->right = infoPtr->items[iItem].rect.right; + lpRect->top = infoPtr->items[iItem].rect.top; + lpRect->bottom = infoPtr->items[iItem].rect.bottom; + + return TRUE; +} + + +static LRESULT +HEADER_GetOrderArray(HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + int i; + LPINT order = (LPINT) lParam; + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + + if ((unsigned int)wParam uNumItem) + return FALSE; + for (i=0; i<(int)wParam; i++) + *order++=HEADER_OrderToIndex(hwnd,i); + return TRUE; +} + +static LRESULT +HEADER_SetOrderArray(HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + int i; + LPINT order = (LPINT) lParam; + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + HEADER_ITEM *lpItem; + + if ((unsigned int)wParam uNumItem) + return FALSE; + for (i=0; i<(int)wParam; i++) + { + lpItem = &infoPtr->items[*order++]; + lpItem->iOrder=i; + } + infoPtr->bRectsValid=0; + InvalidateRect(hwnd, NULL, FALSE); + return TRUE; +} + +inline static LRESULT +HEADER_GetUnicodeFormat (HWND hwnd) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + return infoPtr->bUnicode; +} + + +static LRESULT +HEADER_HitTest (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + LPHDHITTESTINFO phti = (LPHDHITTESTINFO)lParam; + + HEADER_InternalHitTest (hwnd, &phti->pt, &phti->flags, &phti->iItem); + + if (phti->flags == HHT_NOWHERE) + return -1; + else + return phti->iItem; +} + + +static LRESULT +HEADER_InsertItemA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + HDITEMA *phdi = (HDITEMA*)lParam; + INT nItem = (INT)wParam; + HEADER_ITEM *lpItem; + INT len, iOrder; + UINT i; + + if ((phdi == NULL) || (nItem < 0)) + return -1; + + if (nItem > infoPtr->uNumItem) + nItem = infoPtr->uNumItem; + + iOrder = (phdi->mask & HDI_ORDER) ? phdi->iOrder : nItem; + + if (infoPtr->uNumItem == 0) { + infoPtr->items = Alloc (sizeof (HEADER_ITEM)); + infoPtr->uNumItem++; + } + else { + HEADER_ITEM *oldItems = infoPtr->items; + + infoPtr->uNumItem++; + infoPtr->items = Alloc (sizeof (HEADER_ITEM) * infoPtr->uNumItem); + if (nItem == 0) { + memcpy (&infoPtr->items[1], &oldItems[0], + (infoPtr->uNumItem-1) * sizeof(HEADER_ITEM)); + } + else + { + /* pre insert copy */ + if (nItem > 0) { + memcpy (&infoPtr->items[0], &oldItems[0], + nItem * sizeof(HEADER_ITEM)); + } + + /* post insert copy */ + if (nItem < infoPtr->uNumItem - 1) { + memcpy (&infoPtr->items[nItem+1], &oldItems[nItem], + (infoPtr->uNumItem - nItem - 1) * sizeof(HEADER_ITEM)); + } + } + + Free (oldItems); + } + + for (i=0; i < infoPtr->uNumItem; i++) + { + if (infoPtr->items[i].iOrder >= iOrder) + infoPtr->items[i].iOrder++; + } + + lpItem = &infoPtr->items[nItem]; + lpItem->bDown = FALSE; + + if (phdi->mask & HDI_WIDTH) + lpItem->cxy = phdi->cxy; + + if (phdi->mask & HDI_TEXT) { + if (!phdi->pszText) /* null pointer check */ + phdi->pszText = ""; + if (phdi->pszText != LPSTR_TEXTCALLBACKA) { + len = MultiByteToWideChar(CP_ACP, 0, phdi->pszText, -1, NULL, 0); + lpItem->pszText = Alloc( len*sizeof(WCHAR) ); + MultiByteToWideChar(CP_ACP, 0, phdi->pszText, -1, lpItem->pszText, len); + } + else + lpItem->pszText = LPSTR_TEXTCALLBACKW; + } + + if (phdi->mask & HDI_FORMAT) + lpItem->fmt = phdi->fmt; + + if (lpItem->fmt == 0) + lpItem->fmt = HDF_LEFT; + + if (!(lpItem->fmt & HDF_STRING) && (phdi->mask & HDI_TEXT)) + { + lpItem->fmt |= HDF_STRING; + } + if (phdi->mask & HDI_BITMAP) + lpItem->hbm = phdi->hbm; + + if (phdi->mask & HDI_LPARAM) + lpItem->lParam = phdi->lParam; + + if (phdi->mask & HDI_IMAGE) + lpItem->iImage = phdi->iImage; + + lpItem->iOrder = iOrder; + + HEADER_SetItemBounds (hwnd); + + InvalidateRect(hwnd, NULL, FALSE); + + return nItem; +} + + +static LRESULT +HEADER_InsertItemW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + HDITEMW *phdi = (HDITEMW*)lParam; + INT nItem = (INT)wParam; + HEADER_ITEM *lpItem; + INT len, iOrder; + UINT i; + + if ((phdi == NULL) || (nItem < 0)) + return -1; + + if (nItem > infoPtr->uNumItem) + nItem = infoPtr->uNumItem; + + iOrder = (phdi->mask & HDI_ORDER) ? phdi->iOrder : nItem; + + if (infoPtr->uNumItem == 0) { + infoPtr->items = Alloc (sizeof (HEADER_ITEM)); + infoPtr->uNumItem++; + } + else { + HEADER_ITEM *oldItems = infoPtr->items; + + infoPtr->uNumItem++; + infoPtr->items = Alloc (sizeof (HEADER_ITEM) * infoPtr->uNumItem); + if (nItem == 0) { + memcpy (&infoPtr->items[1], &oldItems[0], + (infoPtr->uNumItem-1) * sizeof(HEADER_ITEM)); + } + else + { + /* pre insert copy */ + if (nItem > 0) { + memcpy (&infoPtr->items[0], &oldItems[0], + nItem * sizeof(HEADER_ITEM)); + } + + /* post insert copy */ + if (nItem < infoPtr->uNumItem - 1) { + memcpy (&infoPtr->items[nItem+1], &oldItems[nItem], + (infoPtr->uNumItem - nItem - 1) * sizeof(HEADER_ITEM)); + } + } + + Free (oldItems); + } + + for (i=0; i < infoPtr->uNumItem; i++) + { + if (infoPtr->items[i].iOrder >= iOrder) + infoPtr->items[i].iOrder++; + } + + lpItem = &infoPtr->items[nItem]; + lpItem->bDown = FALSE; + + if (phdi->mask & HDI_WIDTH) + lpItem->cxy = phdi->cxy; + + if (phdi->mask & HDI_TEXT) { + WCHAR wide_null_char = 0; + if (!phdi->pszText) /* null pointer check */ + phdi->pszText = &wide_null_char; + if (phdi->pszText != LPSTR_TEXTCALLBACKW) { + len = strlenW (phdi->pszText); + lpItem->pszText = Alloc ((len+1)*sizeof(WCHAR)); + strcpyW (lpItem->pszText, phdi->pszText); + } + else + lpItem->pszText = LPSTR_TEXTCALLBACKW; + } + + if (phdi->mask & HDI_FORMAT) + lpItem->fmt = phdi->fmt; + + if (lpItem->fmt == 0) + lpItem->fmt = HDF_LEFT; + + if (!(lpItem->fmt &HDF_STRING) && (phdi->mask & HDI_TEXT)) + { + lpItem->fmt |= HDF_STRING; + } + if (phdi->mask & HDI_BITMAP) + lpItem->hbm = phdi->hbm; + + if (phdi->mask & HDI_LPARAM) + lpItem->lParam = phdi->lParam; + + if (phdi->mask & HDI_IMAGE) + lpItem->iImage = phdi->iImage; + + lpItem->iOrder = iOrder; + + HEADER_SetItemBounds (hwnd); + + InvalidateRect(hwnd, NULL, FALSE); + + return nItem; +} + + +static LRESULT +HEADER_Layout (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + LPHDLAYOUT lpLayout = (LPHDLAYOUT)lParam; + + lpLayout->pwpos->hwnd = hwnd; + lpLayout->pwpos->hwndInsertAfter = 0; + lpLayout->pwpos->x = lpLayout->prc->left; + lpLayout->pwpos->y = lpLayout->prc->top; + lpLayout->pwpos->cx = lpLayout->prc->right - lpLayout->prc->left; + if (GetWindowLongW (hwnd, GWL_STYLE) & HDS_HIDDEN) + lpLayout->pwpos->cy = 0; + else { + lpLayout->pwpos->cy = infoPtr->nHeight; + lpLayout->prc->top += infoPtr->nHeight; + } + lpLayout->pwpos->flags = SWP_NOZORDER; + + TRACE("Layout x=%d y=%d cx=%d cy=%d\n", + lpLayout->pwpos->x, lpLayout->pwpos->y, + lpLayout->pwpos->cx, lpLayout->pwpos->cy); + + infoPtr->bRectsValid = FALSE; + + return TRUE; +} + + +static LRESULT +HEADER_SetImageList (HWND hwnd, HIMAGELIST himl) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + HIMAGELIST himlOld; + + TRACE("(himl 0x%x)\n", (int)himl); + himlOld = infoPtr->himl; + infoPtr->himl = himl; + + /* FIXME: Refresh needed??? */ + + return (LRESULT)himlOld; +} + + +static LRESULT +HEADER_GetBitmapMargin(HWND hwnd) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr(hwnd); + + return infoPtr->iMargin; +} + +static LRESULT +HEADER_SetBitmapMargin(HWND hwnd, WPARAM wParam) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + INT oldMargin = infoPtr->iMargin; + + infoPtr->iMargin = (INT)wParam; + + return oldMargin; +} + +static LRESULT +HEADER_SetItemA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + HDITEMA *phdi = (HDITEMA*)lParam; + INT nItem = (INT)wParam; + HEADER_ITEM *lpItem; + + if (phdi == NULL) + return FALSE; + if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem)) + return FALSE; + + TRACE("[nItem=%d]\n", nItem); + + if (HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGINGA, nItem, phdi->mask)) + return FALSE; + + lpItem = &infoPtr->items[nItem]; + if (phdi->mask & HDI_BITMAP) + lpItem->hbm = phdi->hbm; + + if (phdi->mask & HDI_FORMAT) + lpItem->fmt = phdi->fmt; + + if (phdi->mask & HDI_LPARAM) + lpItem->lParam = phdi->lParam; + + if (phdi->mask & HDI_TEXT) { + if (phdi->pszText != LPSTR_TEXTCALLBACKA) { + if (lpItem->pszText) { + Free (lpItem->pszText); + lpItem->pszText = NULL; + } + if (phdi->pszText) { + INT len = MultiByteToWideChar (CP_ACP,0,phdi->pszText,-1,NULL,0); + lpItem->pszText = Alloc( len*sizeof(WCHAR) ); + MultiByteToWideChar (CP_ACP,0,phdi->pszText,-1,lpItem->pszText,len); + } + } + else + lpItem->pszText = LPSTR_TEXTCALLBACKW; + } + + if (phdi->mask & HDI_WIDTH) + lpItem->cxy = phdi->cxy; + + if (phdi->mask & HDI_IMAGE) + lpItem->iImage = phdi->iImage; + + if (phdi->mask & HDI_ORDER) + { + lpItem->iOrder = phdi->iOrder; + } + + HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGEDA, nItem, phdi->mask); + + HEADER_SetItemBounds (hwnd); + + InvalidateRect(hwnd, NULL, FALSE); + + return TRUE; +} + + +static LRESULT +HEADER_SetItemW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + HDITEMW *phdi = (HDITEMW*)lParam; + INT nItem = (INT)wParam; + HEADER_ITEM *lpItem; + + if (phdi == NULL) + return FALSE; + if ((nItem < 0) || (nItem >= (INT)infoPtr->uNumItem)) + return FALSE; + + TRACE("[nItem=%d]\n", nItem); + + if (HEADER_SendHeaderNotify (hwnd, HDN_ITEMCHANGINGW, nItem, phdi->mask)) + return FALSE; + + lpItem = &infoPtr->items[nItem]; + if (phdi->mask & HDI_BITMAP) + lpItem->hbm = phdi->hbm; + + if (phdi->mask & HDI_FORMAT) + lpItem->fmt = phdi->fmt; + + if (phdi->mask & HDI_LPARAM) + lpItem->lParam = phdi->lParam; + + if (phdi->mask & HDI_TEXT) { + if (phdi->pszText != LPSTR_TEXTCALLBACKW) { + if (lpItem->pszText) { + Free (lpItem->pszText); + lpItem->pszText = NULL; + } + if (phdi->pszText) { + INT len = strlenW (phdi->pszText); + lpItem->pszText = Alloc ((len+1)*sizeof(WCHAR)); + strcpyW (lpItem->pszText, phdi->pszText); + } + } + else + lpItem->pszText = LPSTR_TEXTCALLBACKW; + } + + if (phdi->mask & HDI_WIDTH) + lpItem->cxy = phdi->cxy; + + if (phdi->mask & HDI_IMAGE) + lpItem->iImage = phdi->iImage; + + if (phdi->mask & HDI_ORDER) + { + lpItem->iOrder = phdi->iOrder; + } + + HEADER_SendHeaderNotify(hwnd, HDN_ITEMCHANGEDW, nItem, phdi->mask); + + HEADER_SetItemBounds (hwnd); + + InvalidateRect(hwnd, NULL, FALSE); + + return TRUE; +} + +inline static LRESULT +HEADER_SetUnicodeFormat (HWND hwnd, WPARAM wParam) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + BOOL bTemp = infoPtr->bUnicode; + + infoPtr->bUnicode = (BOOL)wParam; + + return bTemp; +} + + +static LRESULT +HEADER_Create (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + HEADER_INFO *infoPtr; + TEXTMETRICW tm; + HFONT hOldFont; + HDC hdc; + + infoPtr = (HEADER_INFO *)Alloc (sizeof(HEADER_INFO)); + SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); + + infoPtr->hwndNotify = ((LPCREATESTRUCTA)lParam)->hwndParent; + infoPtr->uNumItem = 0; + infoPtr->hFont = 0; + infoPtr->items = 0; + infoPtr->bRectsValid = FALSE; + infoPtr->hcurArrow = LoadCursorW (0, (LPWSTR)IDC_ARROW); + infoPtr->hcurDivider = LoadCursorW (COMCTL32_hModule, MAKEINTRESOURCEW(IDC_DIVIDER)); + infoPtr->hcurDivopen = LoadCursorW (COMCTL32_hModule, MAKEINTRESOURCEW(IDC_DIVIDEROPEN)); + infoPtr->bPressed = FALSE; + infoPtr->bTracking = FALSE; + infoPtr->iMoveItem = 0; + infoPtr->himl = 0; + infoPtr->iHotItem = -1; + infoPtr->bUnicode = IsWindowUnicode (hwnd); + infoPtr->iMargin = 3*GetSystemMetrics(SM_CXEDGE); + infoPtr->nNotifyFormat = + SendMessageW (infoPtr->hwndNotify, WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY); + + hdc = GetDC (0); + hOldFont = SelectObject (hdc, GetStockObject (SYSTEM_FONT)); + GetTextMetricsW (hdc, &tm); + infoPtr->nHeight = tm.tmHeight + VERT_BORDER; + SelectObject (hdc, hOldFont); + ReleaseDC (0, hdc); + + return 0; +} + + +static LRESULT +HEADER_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + HEADER_ITEM *lpItem; + INT nItem; + + if (infoPtr->items) { + lpItem = infoPtr->items; + for (nItem = 0; nItem < infoPtr->uNumItem; nItem++, lpItem++) { + if ((lpItem->pszText) && (lpItem->pszText != LPSTR_TEXTCALLBACKW)) + Free (lpItem->pszText); + } + Free (infoPtr->items); + } + + if (infoPtr->himl) + ImageList_Destroy (infoPtr->himl); + + SetWindowLongPtrW (hwnd, 0, 0); + Free (infoPtr); + return 0; +} + + +static inline LRESULT +HEADER_GetFont (HWND hwnd) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + + return (LRESULT)infoPtr->hFont; +} + + +static LRESULT +HEADER_LButtonDblClk (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + POINT pt; + UINT flags; + INT nItem; + + pt.x = (INT)LOWORD(lParam); + pt.y = (INT)HIWORD(lParam); + HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem); + + if ((GetWindowLongW (hwnd, GWL_STYLE) & HDS_BUTTONS) && (flags == HHT_ONHEADER)) + HEADER_SendHeaderNotify (hwnd, HDN_ITEMDBLCLICKA, nItem,0); + else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN)) + HEADER_SendHeaderNotify (hwnd, HDN_DIVIDERDBLCLICKA, nItem,0); + + return 0; +} + + +static LRESULT +HEADER_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE); + POINT pt; + UINT flags; + INT nItem; + HDC hdc; + + pt.x = (INT)LOWORD(lParam); + pt.y = (INT)HIWORD(lParam); + HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem); + + if ((dwStyle & HDS_BUTTONS) && (flags == HHT_ONHEADER)) { + SetCapture (hwnd); + infoPtr->bCaptured = TRUE; + infoPtr->bPressed = TRUE; + infoPtr->iMoveItem = nItem; + + infoPtr->items[nItem].bDown = TRUE; + + /* Send WM_CUSTOMDRAW */ + hdc = GetDC (hwnd); + HEADER_RefreshItem (hwnd, hdc, nItem); + ReleaseDC (hwnd, hdc); + + TRACE("Pressed item %d!\n", nItem); + } + else if ((flags == HHT_ONDIVIDER) || (flags == HHT_ONDIVOPEN)) { + if (!(HEADER_SendHeaderNotify (hwnd, HDN_BEGINTRACKA, nItem,0))) { + SetCapture (hwnd); + infoPtr->bCaptured = TRUE; + infoPtr->bTracking = TRUE; + infoPtr->iMoveItem = nItem; + infoPtr->nOldWidth = infoPtr->items[nItem].cxy; + infoPtr->xTrackOffset = infoPtr->items[nItem].rect.right - pt.x; + + if (!(dwStyle & HDS_FULLDRAG)) { + infoPtr->xOldTrack = infoPtr->items[nItem].rect.right; + hdc = GetDC (hwnd); + HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack); + ReleaseDC (hwnd, hdc); + } + + TRACE("Begin tracking item %d!\n", nItem); + } + } + + return 0; +} + + +static LRESULT +HEADER_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + /* + *DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE); + */ + POINT pt; + UINT flags; + INT nItem, nWidth; + HDC hdc; + + pt.x = (INT)(SHORT)LOWORD(lParam); + pt.y = (INT)(SHORT)HIWORD(lParam); + HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem); + + if (infoPtr->bPressed) { + if ((nItem == infoPtr->iMoveItem) && (flags == HHT_ONHEADER)) { + infoPtr->items[infoPtr->iMoveItem].bDown = FALSE; + hdc = GetDC (hwnd); + HEADER_RefreshItem (hwnd, hdc, infoPtr->iMoveItem); + ReleaseDC (hwnd, hdc); + + HEADER_SendClickNotify (hwnd, HDN_ITEMCLICKA, infoPtr->iMoveItem); + } + else if (flags == HHT_ONHEADER) + { + HEADER_ITEM *lpItem; + INT newindex = HEADER_IndexToOrder(hwnd,nItem); + INT oldindex = HEADER_IndexToOrder(hwnd,infoPtr->iMoveItem); + + TRACE("Exchanging [index:order] [%d:%d] [%d:%d]\n", + infoPtr->iMoveItem,oldindex,nItem,newindex); + lpItem= &infoPtr->items[nItem]; + lpItem->iOrder=oldindex; + + lpItem= &infoPtr->items[infoPtr->iMoveItem]; + lpItem->iOrder = newindex; + + infoPtr->bRectsValid = FALSE; + InvalidateRect(hwnd, NULL, FALSE); + /* FIXME: Should some WM_NOTIFY be sent */ + } + + TRACE("Released item %d!\n", infoPtr->iMoveItem); + infoPtr->bPressed = FALSE; + } + else if (infoPtr->bTracking) { + TRACE("End tracking item %d!\n", infoPtr->iMoveItem); + infoPtr->bTracking = FALSE; + + HEADER_SendHeaderNotify (hwnd, HDN_ENDTRACKA, infoPtr->iMoveItem,HDI_WIDTH); + + /* + * we want to do this even for HDS_FULLDRAG because this is where + * we send the HDN_ITEMCHANGING and HDN_ITEMCHANGED notifications + * + * if (!(dwStyle & HDS_FULLDRAG)) { + */ + + hdc = GetDC (hwnd); + HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack); + ReleaseDC (hwnd, hdc); + if (HEADER_SendHeaderNotify(hwnd, HDN_ITEMCHANGINGA, infoPtr->iMoveItem, HDI_WIDTH)) + { + infoPtr->items[infoPtr->iMoveItem].cxy = infoPtr->nOldWidth; + } + else { + nWidth = pt.x - infoPtr->items[infoPtr->iMoveItem].rect.left + infoPtr->xTrackOffset; + if (nWidth < 0) + nWidth = 0; + infoPtr->items[infoPtr->iMoveItem].cxy = nWidth; + } + + HEADER_SetItemBounds (hwnd); + InvalidateRect(hwnd, NULL, TRUE); + HEADER_SendHeaderNotify(hwnd, HDN_ITEMCHANGEDA, infoPtr->iMoveItem, HDI_WIDTH); + /* + * } + */ + } + + if (infoPtr->bCaptured) { + infoPtr->bCaptured = FALSE; + ReleaseCapture (); + HEADER_SendSimpleNotify (hwnd, NM_RELEASEDCAPTURE); + } + + return 0; +} + + +static LRESULT +HEADER_NotifyFormat (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + + switch (lParam) + { + case NF_QUERY: + return infoPtr->nNotifyFormat; + + case NF_REQUERY: + infoPtr->nNotifyFormat = + SendMessageW ((HWND)wParam, WM_NOTIFYFORMAT, + (WPARAM)hwnd, (LPARAM)NF_QUERY); + return infoPtr->nNotifyFormat; + } + + return 0; +} + + +static LRESULT +HEADER_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE); + POINT pt; + UINT flags; + INT nItem, nWidth; + HDC hdc; + + pt.x = (INT)(SHORT)LOWORD(lParam); + pt.y = (INT)(SHORT)HIWORD(lParam); + HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem); + + if ((dwStyle & HDS_BUTTONS) && (dwStyle & HDS_HOTTRACK)) { + if (flags & (HHT_ONHEADER | HHT_ONDIVIDER | HHT_ONDIVOPEN)) + infoPtr->iHotItem = nItem; + else + infoPtr->iHotItem = -1; + InvalidateRect(hwnd, NULL, FALSE); + } + + if (infoPtr->bCaptured) { + if (infoPtr->bPressed) { + if ((nItem == infoPtr->iMoveItem) && (flags == HHT_ONHEADER)) + infoPtr->items[infoPtr->iMoveItem].bDown = TRUE; + else + infoPtr->items[infoPtr->iMoveItem].bDown = FALSE; + hdc = GetDC (hwnd); + HEADER_RefreshItem (hwnd, hdc, infoPtr->iMoveItem); + ReleaseDC (hwnd, hdc); + + TRACE("Moving pressed item %d!\n", infoPtr->iMoveItem); + } + else if (infoPtr->bTracking) { + if (dwStyle & HDS_FULLDRAG) { + if (HEADER_SendHeaderNotify (hwnd, HDN_TRACKA, infoPtr->iMoveItem, HDI_WIDTH)) + { + nWidth = pt.x - infoPtr->items[infoPtr->iMoveItem].rect.left + infoPtr->xTrackOffset; + if (nWidth < 0) + nWidth = 0; + infoPtr->items[infoPtr->iMoveItem].cxy = nWidth; + HEADER_SendHeaderNotify(hwnd, HDN_ITEMCHANGEDA, infoPtr->iMoveItem, HDI_WIDTH); + } + HEADER_SetItemBounds (hwnd); + } + else { + hdc = GetDC (hwnd); + HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack); + infoPtr->xOldTrack = pt.x + infoPtr->xTrackOffset; + if (infoPtr->xOldTrack < infoPtr->items[infoPtr->iMoveItem].rect.left) + infoPtr->xOldTrack = infoPtr->items[infoPtr->iMoveItem].rect.left; + infoPtr->items[infoPtr->iMoveItem].cxy = + infoPtr->xOldTrack - infoPtr->items[infoPtr->iMoveItem].rect.left; + HEADER_DrawTrackLine (hwnd, hdc, infoPtr->xOldTrack); + ReleaseDC (hwnd, hdc); + HEADER_SendHeaderNotify (hwnd, HDN_TRACKA, infoPtr->iMoveItem, HDI_WIDTH); + } + + TRACE("Tracking item %d!\n", infoPtr->iMoveItem); + } + } + + if ((dwStyle & HDS_BUTTONS) && (dwStyle & HDS_HOTTRACK)) { + FIXME("hot track support!\n"); + } + + return 0; +} + + +static LRESULT +HEADER_Paint (HWND hwnd, WPARAM wParam) +{ + HDC hdc; + PAINTSTRUCT ps; + + hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam; + HEADER_Refresh (hwnd, hdc); + if(!wParam) + EndPaint (hwnd, &ps); + return 0; +} + + +static LRESULT +HEADER_RButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + BOOL bRet; + POINT pt; + + pt.x = LOWORD(lParam); + pt.y = HIWORD(lParam); + + /* Send a Notify message */ + bRet = HEADER_SendSimpleNotify (hwnd, NM_RCLICK); + + /* Change to screen coordinate for WM_CONTEXTMENU */ + ClientToScreen(hwnd, &pt); + + /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */ + SendMessageW( hwnd, WM_CONTEXTMENU, (WPARAM) hwnd, MAKELPARAM(pt.x, pt.y)); + + return bRet; +} + + +static LRESULT +HEADER_SetCursor (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + POINT pt; + UINT flags; + INT nItem; + + TRACE("code=0x%X id=0x%X\n", LOWORD(lParam), HIWORD(lParam)); + + GetCursorPos (&pt); + ScreenToClient (hwnd, &pt); + + HEADER_InternalHitTest (hwnd, &pt, &flags, &nItem); + + if (flags == HHT_ONDIVIDER) + SetCursor (infoPtr->hcurDivider); + else if (flags == HHT_ONDIVOPEN) + SetCursor (infoPtr->hcurDivopen); + else + SetCursor (infoPtr->hcurArrow); + + return 0; +} + + +static LRESULT +HEADER_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + HEADER_INFO *infoPtr = HEADER_GetInfoPtr (hwnd); + TEXTMETRICW tm; + HFONT hFont, hOldFont; + HDC hdc; + + infoPtr->hFont = (HFONT)wParam; + + hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT); + + hdc = GetDC (0); + hOldFont = SelectObject (hdc, hFont); + GetTextMetricsW (hdc, &tm); + infoPtr->nHeight = tm.tmHeight + VERT_BORDER; + SelectObject (hdc, hOldFont); + ReleaseDC (0, hdc); + + infoPtr->bRectsValid = FALSE; + + if (lParam) { + InvalidateRect(hwnd, NULL, FALSE); + } + + return 0; +} + + +static LRESULT WINAPI +HEADER_WindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + TRACE("hwnd=%p msg=%x wparam=%x lParam=%lx\n", hwnd, msg, wParam, lParam); + if (!HEADER_GetInfoPtr (hwnd) && (msg != WM_CREATE)) + return DefWindowProcW (hwnd, msg, wParam, lParam); + switch (msg) { +/* case HDM_CLEARFILTER: */ + + case HDM_CREATEDRAGIMAGE: + return HEADER_CreateDragImage (hwnd, wParam); + + case HDM_DELETEITEM: + return HEADER_DeleteItem (hwnd, wParam); + +/* case HDM_EDITFILTER: */ + + case HDM_GETBITMAPMARGIN: + return HEADER_GetBitmapMargin(hwnd); + + case HDM_GETIMAGELIST: + return HEADER_GetImageList (hwnd); + + case HDM_GETITEMA: + return HEADER_GetItemA (hwnd, wParam, lParam); + + case HDM_GETITEMW: + return HEADER_GetItemW (hwnd, wParam, lParam); + + case HDM_GETITEMCOUNT: + return HEADER_GetItemCount (hwnd); + + case HDM_GETITEMRECT: + return HEADER_GetItemRect (hwnd, wParam, lParam); + + case HDM_GETORDERARRAY: + return HEADER_GetOrderArray(hwnd, wParam, lParam); + + case HDM_GETUNICODEFORMAT: + return HEADER_GetUnicodeFormat (hwnd); + + case HDM_HITTEST: + return HEADER_HitTest (hwnd, wParam, lParam); + + case HDM_INSERTITEMA: + return HEADER_InsertItemA (hwnd, wParam, lParam); + + case HDM_INSERTITEMW: + return HEADER_InsertItemW (hwnd, wParam, lParam); + + case HDM_LAYOUT: + return HEADER_Layout (hwnd, wParam, lParam); + + case HDM_ORDERTOINDEX: + return HEADER_OrderToIndex(hwnd, wParam); + + case HDM_SETBITMAPMARGIN: + return HEADER_SetBitmapMargin(hwnd, wParam); + +/* case HDM_SETFILTERCHANGETIMEOUT: */ + +/* case HDM_SETHOTDIVIDER: */ + + case HDM_SETIMAGELIST: + return HEADER_SetImageList (hwnd, (HIMAGELIST)lParam); + + case HDM_SETITEMA: + return HEADER_SetItemA (hwnd, wParam, lParam); + + case HDM_SETITEMW: + return HEADER_SetItemW (hwnd, wParam, lParam); + + case HDM_SETORDERARRAY: + return HEADER_SetOrderArray(hwnd, wParam, lParam); + + case HDM_SETUNICODEFORMAT: + return HEADER_SetUnicodeFormat (hwnd, wParam); + + case WM_CREATE: + return HEADER_Create (hwnd, wParam, lParam); + + case WM_DESTROY: + return HEADER_Destroy (hwnd, wParam, lParam); + + case WM_ERASEBKGND: + return 1; + + case WM_GETDLGCODE: + return DLGC_WANTTAB | DLGC_WANTARROWS; + + case WM_GETFONT: + return HEADER_GetFont (hwnd); + + case WM_LBUTTONDBLCLK: + return HEADER_LButtonDblClk (hwnd, wParam, lParam); + + case WM_LBUTTONDOWN: + return HEADER_LButtonDown (hwnd, wParam, lParam); + + case WM_LBUTTONUP: + return HEADER_LButtonUp (hwnd, wParam, lParam); + + case WM_MOUSEMOVE: + return HEADER_MouseMove (hwnd, wParam, lParam); + + case WM_NOTIFYFORMAT: + return HEADER_NotifyFormat (hwnd, wParam, lParam); + + case WM_SIZE: + return HEADER_Size (hwnd, wParam); + + case WM_PAINT: + return HEADER_Paint (hwnd, wParam); + + case WM_RBUTTONUP: + return HEADER_RButtonUp (hwnd, wParam, lParam); + + case WM_SETCURSOR: + return HEADER_SetCursor (hwnd, wParam, lParam); + + case WM_SETFONT: + return HEADER_SetFont (hwnd, wParam, lParam); + + default: + if ((msg >= WM_USER) && (msg < WM_APP)) + ERR("unknown msg %04x wp=%04x lp=%08lx\n", + msg, wParam, lParam ); + return DefWindowProcA (hwnd, msg, wParam, lParam); + } +} + + +VOID +HEADER_Register (void) +{ + WNDCLASSW wndClass; + + ZeroMemory (&wndClass, sizeof(WNDCLASSW)); + wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS; + wndClass.lpfnWndProc = HEADER_WindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(HEADER_INFO *); + wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); + wndClass.lpszClassName = WC_HEADERW; + + RegisterClassW (&wndClass); +} + + +VOID +HEADER_Unregister (void) +{ + UnregisterClassW (WC_HEADERW, NULL); +} diff --git a/reactos/lib/comctl32/hotkey.c b/reactos/lib/comctl32/hotkey.c index 3861dde6e16..ab8d7465cbf 100644 --- a/reactos/lib/comctl32/hotkey.c +++ b/reactos/lib/comctl32/hotkey.c @@ -1,561 +1,561 @@ -/* - * Hotkey control - * - * Copyright 1998, 1999 Eric Kohl - * Copyright 2002 Gyorgy 'Nog' Jeney - * Copyright 2004 Robert Shearman - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on Sep. 21, 2004, by Robert Shearman. - * - * Unless otherwise noted, we believe this code to be complete, as per - * the specification mentioned above. - * If you discover missing features or bugs please note them below. - * - */ - -#include -#include -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "comctl32.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(hotkey); - -typedef struct tagHOTKEY_INFO -{ - HWND hwndSelf; - HWND hwndNotify; - HFONT hFont; - BOOL bFocus; - INT nHeight; - WORD HotKey; - WORD InvComb; - WORD InvMod; - BYTE CurrMod; - INT CaretPos; - DWORD ScanCode; - WCHAR strNone[15]; /* hope it's long enough ... */ -} HOTKEY_INFO; - -static const WCHAR HOTKEY_plussep[] = { ' ', '+', ' ' }; -static LRESULT HOTKEY_SetFont (HOTKEY_INFO *infoPtr, HFONT hFont, BOOL redraw); - -#define IsOnlySet(flags) (infoPtr->CurrMod == (flags)) - -static BOOL -HOTKEY_IsCombInv(HOTKEY_INFO *infoPtr) -{ - TRACE("(infoPtr=%p)\n", infoPtr); - if((infoPtr->InvComb & HKCOMB_NONE) && !infoPtr->CurrMod) - return TRUE; - if((infoPtr->InvComb & HKCOMB_S) && IsOnlySet(HOTKEYF_SHIFT)) - return TRUE; - if((infoPtr->InvComb & HKCOMB_C) && IsOnlySet(HOTKEYF_CONTROL)) - return TRUE; - if((infoPtr->InvComb & HKCOMB_A) && IsOnlySet(HOTKEYF_ALT)) - return TRUE; - if((infoPtr->InvComb & HKCOMB_SC) && - IsOnlySet(HOTKEYF_SHIFT | HOTKEYF_CONTROL)) - return TRUE; - if((infoPtr->InvComb & HKCOMB_SA) && IsOnlySet(HOTKEYF_SHIFT | HOTKEYF_ALT)) - return TRUE; - if((infoPtr->InvComb & HKCOMB_CA) && - IsOnlySet(HOTKEYF_CONTROL | HOTKEYF_ALT)) - return TRUE; - if((infoPtr->InvComb & HKCOMB_SCA) && - IsOnlySet(HOTKEYF_SHIFT | HOTKEYF_CONTROL | HOTKEYF_ALT)) - return TRUE; - - TRACE("() Modifiers are valid\n"); - return FALSE; -} -#undef IsOnlySet - -static void -HOTKEY_DrawHotKey(HOTKEY_INFO *infoPtr, HDC hdc, LPCWSTR KeyName, WORD NameLen) -{ - SIZE TextSize; - INT nXStart, nYStart; - COLORREF clrOldText, clrOldBk; - HFONT hFontOld; - - /* Make a gap from the frame */ - nXStart = GetSystemMetrics(SM_CXBORDER); - nYStart = GetSystemMetrics(SM_CYBORDER); - - hFontOld = SelectObject(hdc, infoPtr->hFont); - if (GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & WS_DISABLED) - { - clrOldText = SetTextColor(hdc, comctl32_color.clrGrayText); - clrOldBk = SetBkColor(hdc, comctl32_color.clrBtnFace); - } - else - { - clrOldText = SetTextColor(hdc, comctl32_color.clrWindowText); - clrOldBk = SetBkColor(hdc, comctl32_color.clrWindow); - } - - TextOutW(hdc, nXStart, nYStart, KeyName, NameLen); - - /* Get the text width for the caret */ - GetTextExtentPoint32W(hdc, KeyName, NameLen, &TextSize); - infoPtr->CaretPos = nXStart + TextSize.cx; - - SetBkColor(hdc, clrOldBk); - SetTextColor(hdc, clrOldText); - SelectObject(hdc, hFontOld); - - /* position the caret */ - SetCaretPos(infoPtr->CaretPos, nYStart); -} - -/* Draw the names of the keys in the control */ -static void -HOTKEY_Refresh(HOTKEY_INFO *infoPtr, HDC hdc) -{ - WCHAR KeyName[64]; - WORD NameLen = 0; - BYTE Modifier; - - TRACE("(infoPtr=%p hdc=%p)\n", infoPtr, hdc); - - if(!infoPtr->CurrMod && !infoPtr->HotKey) { - HOTKEY_DrawHotKey (infoPtr, hdc, infoPtr->strNone, 4); - return; - } - - if(infoPtr->HotKey) - Modifier = HIBYTE(infoPtr->HotKey); - else if(HOTKEY_IsCombInv(infoPtr)) - Modifier = infoPtr->InvMod; - else - Modifier = infoPtr->CurrMod; - - if(Modifier & HOTKEYF_CONTROL) { - GetKeyNameTextW(MAKELPARAM(0, MapVirtualKeyW(VK_CONTROL, 0)), - KeyName, 64); - NameLen = lstrlenW(KeyName); - memcpy(&KeyName[NameLen], HOTKEY_plussep, sizeof(HOTKEY_plussep)); - NameLen += 3; - } - if(Modifier & HOTKEYF_SHIFT) { - GetKeyNameTextW(MAKELPARAM(0, MapVirtualKeyW(VK_SHIFT, 0)), - &KeyName[NameLen], 64 - NameLen); - NameLen = lstrlenW(KeyName); - memcpy(&KeyName[NameLen], HOTKEY_plussep, sizeof(HOTKEY_plussep)); - NameLen += 3; - } - if(Modifier & HOTKEYF_ALT) { - GetKeyNameTextW(MAKELPARAM(0, MapVirtualKeyW(VK_MENU, 0)), - &KeyName[NameLen], 64 - NameLen); - NameLen = lstrlenW(KeyName); - memcpy(&KeyName[NameLen], HOTKEY_plussep, sizeof(HOTKEY_plussep)); - NameLen += 3; - } - - if(infoPtr->HotKey) { - GetKeyNameTextW(infoPtr->ScanCode, &KeyName[NameLen], 64 - NameLen); - NameLen = lstrlenW(KeyName); - } - else - KeyName[NameLen] = 0; - - HOTKEY_DrawHotKey (infoPtr, hdc, KeyName, NameLen); -} - -static void -HOTKEY_Paint(HOTKEY_INFO *infoPtr, HDC hdc) -{ - if (hdc) - HOTKEY_Refresh(infoPtr, hdc); - else { - PAINTSTRUCT ps; - hdc = BeginPaint (infoPtr->hwndSelf, &ps); - HOTKEY_Refresh (infoPtr, hdc); - EndPaint (infoPtr->hwndSelf, &ps); - } -} - -static LRESULT -HOTKEY_GetHotKey(HOTKEY_INFO *infoPtr) -{ - TRACE("(infoPtr=%p) Modifiers: 0x%x, Virtual Key: %d\n", infoPtr, - HIBYTE(infoPtr->HotKey), LOBYTE(infoPtr->HotKey)); - return (LRESULT)infoPtr->HotKey; -} - -static void -HOTKEY_SetHotKey(HOTKEY_INFO *infoPtr, WORD hotKey) -{ - infoPtr->HotKey = hotKey; - infoPtr->ScanCode = - MAKELPARAM(0, MapVirtualKeyW(LOBYTE(infoPtr->HotKey), 0)); - TRACE("(infoPtr=%p hotKey=%x) Modifiers: 0x%x, Virtual Key: %d\n", infoPtr, - hotKey, HIBYTE(infoPtr->HotKey), LOBYTE(infoPtr->HotKey)); - InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); -} - -static void -HOTKEY_SetRules(HOTKEY_INFO *infoPtr, WORD invComb, WORD invMod) -{ - infoPtr->InvComb = invComb; - infoPtr->InvMod = invMod; - TRACE("(infoPtr=%p) Invalid Modifers: 0x%x, If Invalid: 0x%x\n", infoPtr, - infoPtr->InvComb, infoPtr->InvMod); -} - - -static LRESULT -HOTKEY_Create (HOTKEY_INFO *infoPtr, LPCREATESTRUCTW lpcs) -{ - infoPtr->hwndNotify = lpcs->hwndParent; - - HOTKEY_SetFont(infoPtr, GetStockObject(SYSTEM_FONT), 0); - - return 0; -} - - -static LRESULT -HOTKEY_Destroy (HOTKEY_INFO *infoPtr) -{ - HWND hwnd = infoPtr->hwndSelf; - /* free hotkey info data */ - Free (infoPtr); - SetWindowLongPtrW (hwnd, 0, 0); - return 0; -} - - -static LRESULT -HOTKEY_EraseBackground (HOTKEY_INFO *infoPtr, HDC hdc) -{ - HBRUSH hBrush, hSolidBrush = NULL; - RECT rc; - - if (GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & WS_DISABLED) - hBrush = hSolidBrush = CreateSolidBrush(comctl32_color.clrBtnFace); - else - { - hBrush = (HBRUSH)SendMessageW(infoPtr->hwndNotify, WM_CTLCOLOREDIT, - (WPARAM)hdc, (LPARAM)infoPtr->hwndSelf); - if (!hBrush) - hBrush = hSolidBrush = CreateSolidBrush(comctl32_color.clrWindow); - } - - GetClientRect (infoPtr->hwndSelf, &rc); - - FillRect (hdc, &rc, hBrush); - - if (hSolidBrush) - DeleteObject(hSolidBrush); - - return -1; -} - - -inline static LRESULT -HOTKEY_GetFont (HOTKEY_INFO *infoPtr) -{ - return (LRESULT)infoPtr->hFont; -} - -static LRESULT -HOTKEY_KeyDown (HOTKEY_INFO *infoPtr, DWORD key, DWORD flags) -{ - WORD wOldHotKey; - BYTE bOldMod; - - if (GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & WS_DISABLED) - return 0; - - TRACE("() Key: %ld\n", key); - - wOldHotKey = infoPtr->HotKey; - bOldMod = infoPtr->CurrMod; - - /* If any key is Pressed, we have to reset the hotkey in the control */ - infoPtr->HotKey = 0; - - switch (key) - { - case VK_RETURN: - case VK_TAB: - case VK_SPACE: - case VK_DELETE: - case VK_ESCAPE: - case VK_BACK: - InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); - return DefWindowProcW (infoPtr->hwndSelf, WM_KEYDOWN, key, flags); - - case VK_SHIFT: - infoPtr->CurrMod |= HOTKEYF_SHIFT; - break; - case VK_CONTROL: - infoPtr->CurrMod |= HOTKEYF_CONTROL; - break; - case VK_MENU: - infoPtr->CurrMod |= HOTKEYF_ALT; - break; - - default: - if(HOTKEY_IsCombInv(infoPtr)) - infoPtr->HotKey = MAKEWORD(key, infoPtr->InvMod); - else - infoPtr->HotKey = MAKEWORD(key, infoPtr->CurrMod); - infoPtr->ScanCode = flags; - break; - } - - if ((wOldHotKey != infoPtr->HotKey) || (bOldMod != infoPtr->CurrMod)) - { - InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); - - /* send EN_CHANGE notification */ - SendMessageW(infoPtr->hwndNotify, WM_COMMAND, - MAKEWPARAM(GetDlgCtrlID(infoPtr->hwndSelf), EN_CHANGE), - (LPARAM)infoPtr->hwndSelf); - } - - return 0; -} - - -static LRESULT -HOTKEY_KeyUp (HOTKEY_INFO *infoPtr, DWORD key, DWORD flags) -{ - BYTE bOldMod; - - if (GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & WS_DISABLED) - return 0; - - TRACE("() Key: %ld\n", key); - - bOldMod = infoPtr->CurrMod; - - switch (key) - { - case VK_SHIFT: - infoPtr->CurrMod &= ~HOTKEYF_SHIFT; - break; - case VK_CONTROL: - infoPtr->CurrMod &= ~HOTKEYF_CONTROL; - break; - case VK_MENU: - infoPtr->CurrMod &= ~HOTKEYF_ALT; - break; - default: - return 1; - } - - if (bOldMod != infoPtr->CurrMod) - { - InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); - - /* send EN_CHANGE notification */ - SendMessageW(infoPtr->hwndNotify, WM_COMMAND, - MAKEWPARAM(GetDlgCtrlID(infoPtr->hwndSelf), EN_CHANGE), - (LPARAM)infoPtr->hwndSelf); - } - - return 0; -} - - -static LRESULT -HOTKEY_KillFocus (HOTKEY_INFO *infoPtr, HWND receiveFocus) -{ - infoPtr->bFocus = FALSE; - DestroyCaret (); - - return 0; -} - - -static LRESULT -HOTKEY_LButtonDown (HOTKEY_INFO *infoPtr) -{ - if (!(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & WS_DISABLED)) - SetFocus (infoPtr->hwndSelf); - - return 0; -} - - -inline static LRESULT -HOTKEY_NCCreate (HWND hwnd, LPCREATESTRUCTW lpcs) -{ - HOTKEY_INFO *infoPtr; - DWORD dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE); - SetWindowLongW (hwnd, GWL_EXSTYLE, - dwExStyle | WS_EX_CLIENTEDGE); - - /* allocate memory for info structure */ - infoPtr = (HOTKEY_INFO *)Alloc (sizeof(HOTKEY_INFO)); - SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)infoPtr); - - /* initialize info structure */ - infoPtr->HotKey = infoPtr->InvComb = infoPtr->InvMod = infoPtr->CurrMod = 0; - infoPtr->CaretPos = GetSystemMetrics(SM_CXBORDER); - infoPtr->hwndSelf = hwnd; - LoadStringW(COMCTL32_hModule, HKY_NONE, infoPtr->strNone, 15); - - return DefWindowProcW (infoPtr->hwndSelf, WM_NCCREATE, 0, (LPARAM)lpcs); -} - -static LRESULT -HOTKEY_SetFocus (HOTKEY_INFO *infoPtr, HWND lostFocus) -{ - infoPtr->bFocus = TRUE; - - CreateCaret (infoPtr->hwndSelf, NULL, 1, infoPtr->nHeight); - SetCaretPos (infoPtr->CaretPos, GetSystemMetrics(SM_CYBORDER)); - ShowCaret (infoPtr->hwndSelf); - - return 0; -} - - -static LRESULT -HOTKEY_SetFont (HOTKEY_INFO *infoPtr, HFONT hFont, BOOL redraw) -{ - TEXTMETRICW tm; - HDC hdc; - HFONT hOldFont = 0; - - infoPtr->hFont = hFont; - - hdc = GetDC (infoPtr->hwndSelf); - if (infoPtr->hFont) - hOldFont = SelectObject (hdc, infoPtr->hFont); - - GetTextMetricsW (hdc, &tm); - infoPtr->nHeight = tm.tmHeight; - - if (infoPtr->hFont) - SelectObject (hdc, hOldFont); - ReleaseDC (infoPtr->hwndSelf, hdc); - - if (redraw) - InvalidateRect (infoPtr->hwndSelf, NULL, TRUE); - - return 0; -} - -static LRESULT WINAPI -HOTKEY_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - HOTKEY_INFO *infoPtr = (HOTKEY_INFO *)GetWindowLongPtrW (hwnd, 0); - TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hwnd, uMsg, wParam, lParam); - if (!infoPtr && (uMsg != WM_NCCREATE)) - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - switch (uMsg) - { - case HKM_GETHOTKEY: - return HOTKEY_GetHotKey (infoPtr); - case HKM_SETHOTKEY: - HOTKEY_SetHotKey (infoPtr, (WORD)wParam); - break; - case HKM_SETRULES: - HOTKEY_SetRules (infoPtr, (WORD)wParam, (WORD)lParam); - break; - - case WM_CHAR: - case WM_SYSCHAR: - return HOTKEY_KeyDown (infoPtr, MapVirtualKeyW(LOBYTE(HIWORD(lParam)), 1), lParam); - - case WM_CREATE: - return HOTKEY_Create (infoPtr, (LPCREATESTRUCTW)lParam); - - case WM_DESTROY: - return HOTKEY_Destroy (infoPtr); - - case WM_ERASEBKGND: - return HOTKEY_EraseBackground (infoPtr, (HDC)wParam); - - case WM_GETDLGCODE: - return DLGC_WANTCHARS | DLGC_WANTARROWS; - - case WM_GETFONT: - return HOTKEY_GetFont (infoPtr); - - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - return HOTKEY_KeyDown (infoPtr, wParam, lParam); - - case WM_KEYUP: - case WM_SYSKEYUP: - return HOTKEY_KeyUp (infoPtr, wParam, lParam); - - case WM_KILLFOCUS: - return HOTKEY_KillFocus (infoPtr, (HWND)wParam); - - case WM_LBUTTONDOWN: - return HOTKEY_LButtonDown (infoPtr); - - case WM_NCCREATE: - return HOTKEY_NCCreate (hwnd, (LPCREATESTRUCTW)lParam); - - case WM_PAINT: - HOTKEY_Paint(infoPtr, (HDC)wParam); - return 0; - - case WM_SETFOCUS: - return HOTKEY_SetFocus (infoPtr, (HWND)wParam); - - case WM_SETFONT: - return HOTKEY_SetFont (infoPtr, (HFONT)wParam, LOWORD(lParam)); - - default: - if ((uMsg >= WM_USER) && (uMsg < WM_APP)) - ERR("unknown msg %04x wp=%08x lp=%08lx\n", - uMsg, wParam, lParam); - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - } - return 0; -} - - -void -HOTKEY_Register (void) -{ - WNDCLASSW wndClass; - - ZeroMemory (&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS; - wndClass.lpfnWndProc = HOTKEY_WindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(HOTKEY_INFO *); - wndClass.hCursor = 0; - wndClass.hbrBackground = 0; - wndClass.lpszClassName = HOTKEY_CLASSW; - - RegisterClassW (&wndClass); -} - - -void -HOTKEY_Unregister (void) -{ - UnregisterClassW (HOTKEY_CLASSW, NULL); -} +/* + * Hotkey control + * + * Copyright 1998, 1999 Eric Kohl + * Copyright 2002 Gyorgy 'Nog' Jeney + * Copyright 2004 Robert Shearman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This code was audited for completeness against the documented features + * of Comctl32.dll version 6.0 on Sep. 21, 2004, by Robert Shearman. + * + * Unless otherwise noted, we believe this code to be complete, as per + * the specification mentioned above. + * If you discover missing features or bugs please note them below. + * + */ + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "comctl32.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(hotkey); + +typedef struct tagHOTKEY_INFO +{ + HWND hwndSelf; + HWND hwndNotify; + HFONT hFont; + BOOL bFocus; + INT nHeight; + WORD HotKey; + WORD InvComb; + WORD InvMod; + BYTE CurrMod; + INT CaretPos; + DWORD ScanCode; + WCHAR strNone[15]; /* hope it's long enough ... */ +} HOTKEY_INFO; + +static const WCHAR HOTKEY_plussep[] = { ' ', '+', ' ' }; +static LRESULT HOTKEY_SetFont (HOTKEY_INFO *infoPtr, HFONT hFont, BOOL redraw); + +#define IsOnlySet(flags) (infoPtr->CurrMod == (flags)) + +static BOOL +HOTKEY_IsCombInv(HOTKEY_INFO *infoPtr) +{ + TRACE("(infoPtr=%p)\n", infoPtr); + if((infoPtr->InvComb & HKCOMB_NONE) && !infoPtr->CurrMod) + return TRUE; + if((infoPtr->InvComb & HKCOMB_S) && IsOnlySet(HOTKEYF_SHIFT)) + return TRUE; + if((infoPtr->InvComb & HKCOMB_C) && IsOnlySet(HOTKEYF_CONTROL)) + return TRUE; + if((infoPtr->InvComb & HKCOMB_A) && IsOnlySet(HOTKEYF_ALT)) + return TRUE; + if((infoPtr->InvComb & HKCOMB_SC) && + IsOnlySet(HOTKEYF_SHIFT | HOTKEYF_CONTROL)) + return TRUE; + if((infoPtr->InvComb & HKCOMB_SA) && IsOnlySet(HOTKEYF_SHIFT | HOTKEYF_ALT)) + return TRUE; + if((infoPtr->InvComb & HKCOMB_CA) && + IsOnlySet(HOTKEYF_CONTROL | HOTKEYF_ALT)) + return TRUE; + if((infoPtr->InvComb & HKCOMB_SCA) && + IsOnlySet(HOTKEYF_SHIFT | HOTKEYF_CONTROL | HOTKEYF_ALT)) + return TRUE; + + TRACE("() Modifiers are valid\n"); + return FALSE; +} +#undef IsOnlySet + +static void +HOTKEY_DrawHotKey(HOTKEY_INFO *infoPtr, HDC hdc, LPCWSTR KeyName, WORD NameLen) +{ + SIZE TextSize; + INT nXStart, nYStart; + COLORREF clrOldText, clrOldBk; + HFONT hFontOld; + + /* Make a gap from the frame */ + nXStart = GetSystemMetrics(SM_CXBORDER); + nYStart = GetSystemMetrics(SM_CYBORDER); + + hFontOld = SelectObject(hdc, infoPtr->hFont); + if (GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & WS_DISABLED) + { + clrOldText = SetTextColor(hdc, comctl32_color.clrGrayText); + clrOldBk = SetBkColor(hdc, comctl32_color.clrBtnFace); + } + else + { + clrOldText = SetTextColor(hdc, comctl32_color.clrWindowText); + clrOldBk = SetBkColor(hdc, comctl32_color.clrWindow); + } + + TextOutW(hdc, nXStart, nYStart, KeyName, NameLen); + + /* Get the text width for the caret */ + GetTextExtentPoint32W(hdc, KeyName, NameLen, &TextSize); + infoPtr->CaretPos = nXStart + TextSize.cx; + + SetBkColor(hdc, clrOldBk); + SetTextColor(hdc, clrOldText); + SelectObject(hdc, hFontOld); + + /* position the caret */ + SetCaretPos(infoPtr->CaretPos, nYStart); +} + +/* Draw the names of the keys in the control */ +static void +HOTKEY_Refresh(HOTKEY_INFO *infoPtr, HDC hdc) +{ + WCHAR KeyName[64]; + WORD NameLen = 0; + BYTE Modifier; + + TRACE("(infoPtr=%p hdc=%p)\n", infoPtr, hdc); + + if(!infoPtr->CurrMod && !infoPtr->HotKey) { + HOTKEY_DrawHotKey (infoPtr, hdc, infoPtr->strNone, 4); + return; + } + + if(infoPtr->HotKey) + Modifier = HIBYTE(infoPtr->HotKey); + else if(HOTKEY_IsCombInv(infoPtr)) + Modifier = infoPtr->InvMod; + else + Modifier = infoPtr->CurrMod; + + if(Modifier & HOTKEYF_CONTROL) { + GetKeyNameTextW(MAKELPARAM(0, MapVirtualKeyW(VK_CONTROL, 0)), + KeyName, 64); + NameLen = lstrlenW(KeyName); + memcpy(&KeyName[NameLen], HOTKEY_plussep, sizeof(HOTKEY_plussep)); + NameLen += 3; + } + if(Modifier & HOTKEYF_SHIFT) { + GetKeyNameTextW(MAKELPARAM(0, MapVirtualKeyW(VK_SHIFT, 0)), + &KeyName[NameLen], 64 - NameLen); + NameLen = lstrlenW(KeyName); + memcpy(&KeyName[NameLen], HOTKEY_plussep, sizeof(HOTKEY_plussep)); + NameLen += 3; + } + if(Modifier & HOTKEYF_ALT) { + GetKeyNameTextW(MAKELPARAM(0, MapVirtualKeyW(VK_MENU, 0)), + &KeyName[NameLen], 64 - NameLen); + NameLen = lstrlenW(KeyName); + memcpy(&KeyName[NameLen], HOTKEY_plussep, sizeof(HOTKEY_plussep)); + NameLen += 3; + } + + if(infoPtr->HotKey) { + GetKeyNameTextW(infoPtr->ScanCode, &KeyName[NameLen], 64 - NameLen); + NameLen = lstrlenW(KeyName); + } + else + KeyName[NameLen] = 0; + + HOTKEY_DrawHotKey (infoPtr, hdc, KeyName, NameLen); +} + +static void +HOTKEY_Paint(HOTKEY_INFO *infoPtr, HDC hdc) +{ + if (hdc) + HOTKEY_Refresh(infoPtr, hdc); + else { + PAINTSTRUCT ps; + hdc = BeginPaint (infoPtr->hwndSelf, &ps); + HOTKEY_Refresh (infoPtr, hdc); + EndPaint (infoPtr->hwndSelf, &ps); + } +} + +static LRESULT +HOTKEY_GetHotKey(HOTKEY_INFO *infoPtr) +{ + TRACE("(infoPtr=%p) Modifiers: 0x%x, Virtual Key: %d\n", infoPtr, + HIBYTE(infoPtr->HotKey), LOBYTE(infoPtr->HotKey)); + return (LRESULT)infoPtr->HotKey; +} + +static void +HOTKEY_SetHotKey(HOTKEY_INFO *infoPtr, WORD hotKey) +{ + infoPtr->HotKey = hotKey; + infoPtr->ScanCode = + MAKELPARAM(0, MapVirtualKeyW(LOBYTE(infoPtr->HotKey), 0)); + TRACE("(infoPtr=%p hotKey=%x) Modifiers: 0x%x, Virtual Key: %d\n", infoPtr, + hotKey, HIBYTE(infoPtr->HotKey), LOBYTE(infoPtr->HotKey)); + InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); +} + +static void +HOTKEY_SetRules(HOTKEY_INFO *infoPtr, WORD invComb, WORD invMod) +{ + infoPtr->InvComb = invComb; + infoPtr->InvMod = invMod; + TRACE("(infoPtr=%p) Invalid Modifers: 0x%x, If Invalid: 0x%x\n", infoPtr, + infoPtr->InvComb, infoPtr->InvMod); +} + + +static LRESULT +HOTKEY_Create (HOTKEY_INFO *infoPtr, LPCREATESTRUCTW lpcs) +{ + infoPtr->hwndNotify = lpcs->hwndParent; + + HOTKEY_SetFont(infoPtr, GetStockObject(SYSTEM_FONT), 0); + + return 0; +} + + +static LRESULT +HOTKEY_Destroy (HOTKEY_INFO *infoPtr) +{ + HWND hwnd = infoPtr->hwndSelf; + /* free hotkey info data */ + Free (infoPtr); + SetWindowLongPtrW (hwnd, 0, 0); + return 0; +} + + +static LRESULT +HOTKEY_EraseBackground (HOTKEY_INFO *infoPtr, HDC hdc) +{ + HBRUSH hBrush, hSolidBrush = NULL; + RECT rc; + + if (GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & WS_DISABLED) + hBrush = hSolidBrush = CreateSolidBrush(comctl32_color.clrBtnFace); + else + { + hBrush = (HBRUSH)SendMessageW(infoPtr->hwndNotify, WM_CTLCOLOREDIT, + (WPARAM)hdc, (LPARAM)infoPtr->hwndSelf); + if (!hBrush) + hBrush = hSolidBrush = CreateSolidBrush(comctl32_color.clrWindow); + } + + GetClientRect (infoPtr->hwndSelf, &rc); + + FillRect (hdc, &rc, hBrush); + + if (hSolidBrush) + DeleteObject(hSolidBrush); + + return -1; +} + + +inline static LRESULT +HOTKEY_GetFont (HOTKEY_INFO *infoPtr) +{ + return (LRESULT)infoPtr->hFont; +} + +static LRESULT +HOTKEY_KeyDown (HOTKEY_INFO *infoPtr, DWORD key, DWORD flags) +{ + WORD wOldHotKey; + BYTE bOldMod; + + if (GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & WS_DISABLED) + return 0; + + TRACE("() Key: %ld\n", key); + + wOldHotKey = infoPtr->HotKey; + bOldMod = infoPtr->CurrMod; + + /* If any key is Pressed, we have to reset the hotkey in the control */ + infoPtr->HotKey = 0; + + switch (key) + { + case VK_RETURN: + case VK_TAB: + case VK_SPACE: + case VK_DELETE: + case VK_ESCAPE: + case VK_BACK: + InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); + return DefWindowProcW (infoPtr->hwndSelf, WM_KEYDOWN, key, flags); + + case VK_SHIFT: + infoPtr->CurrMod |= HOTKEYF_SHIFT; + break; + case VK_CONTROL: + infoPtr->CurrMod |= HOTKEYF_CONTROL; + break; + case VK_MENU: + infoPtr->CurrMod |= HOTKEYF_ALT; + break; + + default: + if(HOTKEY_IsCombInv(infoPtr)) + infoPtr->HotKey = MAKEWORD(key, infoPtr->InvMod); + else + infoPtr->HotKey = MAKEWORD(key, infoPtr->CurrMod); + infoPtr->ScanCode = flags; + break; + } + + if ((wOldHotKey != infoPtr->HotKey) || (bOldMod != infoPtr->CurrMod)) + { + InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); + + /* send EN_CHANGE notification */ + SendMessageW(infoPtr->hwndNotify, WM_COMMAND, + MAKEWPARAM(GetDlgCtrlID(infoPtr->hwndSelf), EN_CHANGE), + (LPARAM)infoPtr->hwndSelf); + } + + return 0; +} + + +static LRESULT +HOTKEY_KeyUp (HOTKEY_INFO *infoPtr, DWORD key, DWORD flags) +{ + BYTE bOldMod; + + if (GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & WS_DISABLED) + return 0; + + TRACE("() Key: %ld\n", key); + + bOldMod = infoPtr->CurrMod; + + switch (key) + { + case VK_SHIFT: + infoPtr->CurrMod &= ~HOTKEYF_SHIFT; + break; + case VK_CONTROL: + infoPtr->CurrMod &= ~HOTKEYF_CONTROL; + break; + case VK_MENU: + infoPtr->CurrMod &= ~HOTKEYF_ALT; + break; + default: + return 1; + } + + if (bOldMod != infoPtr->CurrMod) + { + InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); + + /* send EN_CHANGE notification */ + SendMessageW(infoPtr->hwndNotify, WM_COMMAND, + MAKEWPARAM(GetDlgCtrlID(infoPtr->hwndSelf), EN_CHANGE), + (LPARAM)infoPtr->hwndSelf); + } + + return 0; +} + + +static LRESULT +HOTKEY_KillFocus (HOTKEY_INFO *infoPtr, HWND receiveFocus) +{ + infoPtr->bFocus = FALSE; + DestroyCaret (); + + return 0; +} + + +static LRESULT +HOTKEY_LButtonDown (HOTKEY_INFO *infoPtr) +{ + if (!(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & WS_DISABLED)) + SetFocus (infoPtr->hwndSelf); + + return 0; +} + + +inline static LRESULT +HOTKEY_NCCreate (HWND hwnd, LPCREATESTRUCTW lpcs) +{ + HOTKEY_INFO *infoPtr; + DWORD dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE); + SetWindowLongW (hwnd, GWL_EXSTYLE, + dwExStyle | WS_EX_CLIENTEDGE); + + /* allocate memory for info structure */ + infoPtr = (HOTKEY_INFO *)Alloc (sizeof(HOTKEY_INFO)); + SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)infoPtr); + + /* initialize info structure */ + infoPtr->HotKey = infoPtr->InvComb = infoPtr->InvMod = infoPtr->CurrMod = 0; + infoPtr->CaretPos = GetSystemMetrics(SM_CXBORDER); + infoPtr->hwndSelf = hwnd; + LoadStringW(COMCTL32_hModule, HKY_NONE, infoPtr->strNone, 15); + + return DefWindowProcW (infoPtr->hwndSelf, WM_NCCREATE, 0, (LPARAM)lpcs); +} + +static LRESULT +HOTKEY_SetFocus (HOTKEY_INFO *infoPtr, HWND lostFocus) +{ + infoPtr->bFocus = TRUE; + + CreateCaret (infoPtr->hwndSelf, NULL, 1, infoPtr->nHeight); + SetCaretPos (infoPtr->CaretPos, GetSystemMetrics(SM_CYBORDER)); + ShowCaret (infoPtr->hwndSelf); + + return 0; +} + + +static LRESULT +HOTKEY_SetFont (HOTKEY_INFO *infoPtr, HFONT hFont, BOOL redraw) +{ + TEXTMETRICW tm; + HDC hdc; + HFONT hOldFont = 0; + + infoPtr->hFont = hFont; + + hdc = GetDC (infoPtr->hwndSelf); + if (infoPtr->hFont) + hOldFont = SelectObject (hdc, infoPtr->hFont); + + GetTextMetricsW (hdc, &tm); + infoPtr->nHeight = tm.tmHeight; + + if (infoPtr->hFont) + SelectObject (hdc, hOldFont); + ReleaseDC (infoPtr->hwndSelf, hdc); + + if (redraw) + InvalidateRect (infoPtr->hwndSelf, NULL, TRUE); + + return 0; +} + +static LRESULT WINAPI +HOTKEY_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + HOTKEY_INFO *infoPtr = (HOTKEY_INFO *)GetWindowLongPtrW (hwnd, 0); + TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hwnd, uMsg, wParam, lParam); + if (!infoPtr && (uMsg != WM_NCCREATE)) + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + switch (uMsg) + { + case HKM_GETHOTKEY: + return HOTKEY_GetHotKey (infoPtr); + case HKM_SETHOTKEY: + HOTKEY_SetHotKey (infoPtr, (WORD)wParam); + break; + case HKM_SETRULES: + HOTKEY_SetRules (infoPtr, (WORD)wParam, (WORD)lParam); + break; + + case WM_CHAR: + case WM_SYSCHAR: + return HOTKEY_KeyDown (infoPtr, MapVirtualKeyW(LOBYTE(HIWORD(lParam)), 1), lParam); + + case WM_CREATE: + return HOTKEY_Create (infoPtr, (LPCREATESTRUCTW)lParam); + + case WM_DESTROY: + return HOTKEY_Destroy (infoPtr); + + case WM_ERASEBKGND: + return HOTKEY_EraseBackground (infoPtr, (HDC)wParam); + + case WM_GETDLGCODE: + return DLGC_WANTCHARS | DLGC_WANTARROWS; + + case WM_GETFONT: + return HOTKEY_GetFont (infoPtr); + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + return HOTKEY_KeyDown (infoPtr, wParam, lParam); + + case WM_KEYUP: + case WM_SYSKEYUP: + return HOTKEY_KeyUp (infoPtr, wParam, lParam); + + case WM_KILLFOCUS: + return HOTKEY_KillFocus (infoPtr, (HWND)wParam); + + case WM_LBUTTONDOWN: + return HOTKEY_LButtonDown (infoPtr); + + case WM_NCCREATE: + return HOTKEY_NCCreate (hwnd, (LPCREATESTRUCTW)lParam); + + case WM_PAINT: + HOTKEY_Paint(infoPtr, (HDC)wParam); + return 0; + + case WM_SETFOCUS: + return HOTKEY_SetFocus (infoPtr, (HWND)wParam); + + case WM_SETFONT: + return HOTKEY_SetFont (infoPtr, (HFONT)wParam, LOWORD(lParam)); + + default: + if ((uMsg >= WM_USER) && (uMsg < WM_APP)) + ERR("unknown msg %04x wp=%08x lp=%08lx\n", + uMsg, wParam, lParam); + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + } + return 0; +} + + +void +HOTKEY_Register (void) +{ + WNDCLASSW wndClass; + + ZeroMemory (&wndClass, sizeof(WNDCLASSW)); + wndClass.style = CS_GLOBALCLASS; + wndClass.lpfnWndProc = HOTKEY_WindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(HOTKEY_INFO *); + wndClass.hCursor = 0; + wndClass.hbrBackground = 0; + wndClass.lpszClassName = HOTKEY_CLASSW; + + RegisterClassW (&wndClass); +} + + +void +HOTKEY_Unregister (void) +{ + UnregisterClassW (HOTKEY_CLASSW, NULL); +} diff --git a/reactos/lib/comctl32/imagelist.c b/reactos/lib/comctl32/imagelist.c index 80b7980074a..b87309d6513 100644 --- a/reactos/lib/comctl32/imagelist.c +++ b/reactos/lib/comctl32/imagelist.c @@ -1,2862 +1,2862 @@ -/* - * ImageList implementation - * - * Copyright 1998 Eric Kohl - * Copyright 2000 Jason Mawdsley - * Copyright 2001, 2004 Michael Stefaniuc - * Copyright 2001 Charles Loep for CodeWeavers - * Copyright 2002 Dimitrie O. Paun - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTE - * - * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on Sep. 12, 2002, by Dimitrie O. Paun. - * - * Unless otherwise noted, we believe this code to be complete, as per - * the specification mentioned above. - * If you discover missing features, or bugs, please note them below. - * - * TODO: - * - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE - * - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE, ILS_ALPHA - * - Thread-safe locking - */ - -#include -#include -#include - -#define COBJMACROS - -#include "winerror.h" -#include "windef.h" -#include "winbase.h" -#include "objbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "commctrl.h" -#include "comctl32.h" -#include "imagelist.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(imagelist); - - -#define MAX_OVERLAYIMAGE 15 - -/* internal image list data used for Drag & Drop operations */ -typedef struct -{ - HWND hwnd; - HIMAGELIST himl; - /* position of the drag image relative to the window */ - INT x; - INT y; - /* offset of the hotspot relative to the origin of the image */ - INT dxHotspot; - INT dyHotspot; - /* is the drag image visible */ - BOOL bShow; - /* saved background */ - HBITMAP hbmBg; -} INTERNALDRAG; - -static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0 }; - -static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT width, UINT height); - -static inline BOOL is_valid(HIMAGELIST himl) -{ - return himl && himl->magic == IMAGELIST_MAGIC; -} - - -/************************************************************************* - * IMAGELIST_InternalExpandBitmaps [Internal] - * - * Expands the bitmaps of an image list by the given number of images. - * - * PARAMS - * himl [I] handle to image list - * nImageCount [I] number of images to add - * - * RETURNS - * nothing - * - * NOTES - * This function CANNOT be used to reduce the number of images. - */ -static void -IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy) -{ - HDC hdcBitmap; - HBITMAP hbmNewBitmap, hbmNull; - INT nNewWidth, nNewCount; - - if ((himl->cCurImage + nImageCount <= himl->cMaxImage) - && (himl->cy >= cy)) - return; - - if (cy == 0) cy = himl->cy; - nNewCount = himl->cCurImage + nImageCount + himl->cGrow; - nNewWidth = nNewCount * himl->cx; - - TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount); - hdcBitmap = CreateCompatibleDC (0); - - hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewWidth, cy); - - if (hbmNewBitmap == 0) - ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy); - - if(himl->cCurImage) - { - hbmNull = SelectObject (hdcBitmap, hbmNewBitmap); - BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy, - himl->hdcImage, 0, 0, SRCCOPY); - SelectObject (hdcBitmap, hbmNull); - } - SelectObject (himl->hdcImage, hbmNewBitmap); - DeleteObject (himl->hbmImage); - himl->hbmImage = hbmNewBitmap; - - if (himl->flags & ILC_MASK) - { - hbmNewBitmap = CreateBitmap (nNewWidth, cy, 1, 1, NULL); - - if (hbmNewBitmap == 0) - ERR("creating new mask bitmap!\n"); - - if(himl->cCurImage) - { - hbmNull = SelectObject (hdcBitmap, hbmNewBitmap); - BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy, - himl->hdcMask, 0, 0, SRCCOPY); - SelectObject (hdcBitmap, hbmNull); - } - SelectObject (himl->hdcMask, hbmNewBitmap); - DeleteObject (himl->hbmMask); - himl->hbmMask = hbmNewBitmap; - } - - himl->cMaxImage = nNewCount; - - DeleteDC (hdcBitmap); -} - - -/************************************************************************* - * ImageList_Add [COMCTL32.@] - * - * Add an image or images to an image list. - * - * PARAMS - * himl [I] handle to image list - * hbmImage [I] handle to image bitmap - * hbmMask [I] handle to mask bitmap - * - * RETURNS - * Success: Index of the first new image. - * Failure: -1 - */ - -INT WINAPI -ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask) -{ - HDC hdcBitmap; - INT nFirstIndex, nImageCount; - INT nStartX; - BITMAP bmp; - HBITMAP hOldBitmap; - - TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask); - if (!is_valid(himl)) - return -1; - - GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp); - nImageCount = bmp.bmWidth / himl->cx; - - IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight); - - nStartX = himl->cCurImage * himl->cx; - - hdcBitmap = CreateCompatibleDC(0); - - hOldBitmap = SelectObject(hdcBitmap, hbmImage); - - /* Copy result to the imagelist - */ - BitBlt (himl->hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight, - hdcBitmap, 0, 0, SRCCOPY); - - if(himl->hbmMask) - { - HDC hdcTemp; - HBITMAP hOldBitmapTemp; - - hdcTemp = CreateCompatibleDC(0); - hOldBitmapTemp = SelectObject(hdcTemp, hbmMask); - - BitBlt (himl->hdcMask, - nStartX, 0, bmp.bmWidth, bmp.bmHeight, - hdcTemp, - 0, 0, - SRCCOPY); - - SelectObject(hdcTemp, hOldBitmapTemp); - DeleteDC(hdcTemp); - - /* Remove the background from the image - */ - BitBlt (himl->hdcImage, - nStartX, 0, bmp.bmWidth, bmp.bmHeight, - himl->hdcMask, - nStartX, 0, - 0x220326); /* NOTSRCAND */ - } - - SelectObject(hdcBitmap, hOldBitmap); - DeleteDC(hdcBitmap); - - nFirstIndex = himl->cCurImage; - himl->cCurImage += nImageCount; - - return nFirstIndex; -} - - -/************************************************************************* - * ImageList_AddIcon [COMCTL32.@] - * - * Adds an icon to an image list. - * - * PARAMS - * himl [I] handle to image list - * hIcon [I] handle to icon - * - * RETURNS - * Success: index of the new image - * Failure: -1 - */ -#undef ImageList_AddIcon -INT WINAPI ImageList_AddIcon (HIMAGELIST himl, HICON hIcon) -{ - return ImageList_ReplaceIcon (himl, -1, hIcon); -} - - -/************************************************************************* - * ImageList_AddMasked [COMCTL32.@] - * - * Adds an image or images to an image list and creates a mask from the - * specified bitmap using the mask color. - * - * PARAMS - * himl [I] handle to image list. - * hBitmap [I] handle to bitmap - * clrMask [I] mask color. - * - * RETURNS - * Success: Index of the first new image. - * Failure: -1 - */ - -INT WINAPI -ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask) -{ - HDC hdcMask, hdcBitmap; - INT nIndex, nImageCount, nMaskXOffset=0; - BITMAP bmp; - HBITMAP hOldBitmap; - HBITMAP hMaskBitmap=0; - COLORREF bkColor; - - TRACE("himl=%p hbitmap=%p clrmask=%lx\n", himl, hBitmap, clrMask); - if (!is_valid(himl)) - return -1; - - if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp)) - return -1; - - if (himl->cx > 0) - nImageCount = bmp.bmWidth / himl->cx; - else - nImageCount = 0; - - IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight); - - nIndex = himl->cCurImage; - himl->cCurImage += nImageCount; - - hdcBitmap = CreateCompatibleDC(0); - - - hOldBitmap = SelectObject(hdcBitmap, hBitmap); - if(himl->hbmMask) - { - hdcMask = himl->hdcMask; - nMaskXOffset = nIndex * himl->cx; - } - else - { - /* - Create a temp Mask so we can remove the background of - the Image (Windows does this even if there is no mask) - */ - hdcMask = CreateCompatibleDC(0); - hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL); - SelectObject(hdcMask, hMaskBitmap); - nMaskXOffset = 0; - } - /* create monochrome image to the mask bitmap */ - bkColor = (clrMask != CLR_DEFAULT) ? clrMask : - GetPixel (hdcBitmap, 0, 0); - SetBkColor (hdcBitmap, bkColor); - BitBlt (hdcMask, - nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight, - hdcBitmap, 0, 0, - SRCCOPY); - - SetBkColor(hdcBitmap, RGB(255,255,255)); - /*Remove the background from the image - */ - /* - WINDOWS BUG ALERT!!!!!! - The statement below should not be done in common practice - but this is how ImageList_AddMasked works in Windows. - It overwrites the original bitmap passed, this was discovered - by using the same bitmap to iterate the different styles - on windows where it failed (BUT ImageList_Add is OK) - This is here in case some apps rely on this bug - */ - BitBlt(hdcBitmap, - 0, 0, bmp.bmWidth, bmp.bmHeight, - hdcMask, - nMaskXOffset, 0, - 0x220326); /* NOTSRCAND */ - /* Copy result to the imagelist - */ - BitBlt (himl->hdcImage, - nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight, - hdcBitmap, - 0, 0, - SRCCOPY); - /* Clean up - */ - SelectObject(hdcBitmap, hOldBitmap); - DeleteDC(hdcBitmap); - if(!himl->hbmMask) - { - DeleteObject(hMaskBitmap); - DeleteDC(hdcMask); - } - - return nIndex; -} - - -/************************************************************************* - * ImageList_BeginDrag [COMCTL32.@] - * - * Creates a temporary image list that contains one image. It will be used - * as a drag image. - * - * PARAMS - * himlTrack [I] handle to the source image list - * iTrack [I] index of the drag image in the source image list - * dxHotspot [I] X position of the hot spot of the drag image - * dyHotspot [I] Y position of the hot spot of the drag image - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ - -BOOL WINAPI -ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack, - INT dxHotspot, INT dyHotspot) -{ - INT cx, cy; - - TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack, - dxHotspot, dyHotspot); - - if (!is_valid(himlTrack)) - return FALSE; - - if (InternalDrag.himl) - ImageList_EndDrag (); - - cx = himlTrack->cx; - cy = himlTrack->cy; - - InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1); - if (InternalDrag.himl == NULL) { - WARN("Error creating drag image list!\n"); - return FALSE; - } - - InternalDrag.dxHotspot = dxHotspot; - InternalDrag.dyHotspot = dyHotspot; - - /* copy image */ - BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY); - - /* copy mask */ - BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY); - - InternalDrag.himl->cCurImage = 1; - - return TRUE; -} - - -/************************************************************************* - * ImageList_Copy [COMCTL32.@] - * - * Copies an image of the source image list to an image of the - * destination image list. Images can be copied or swapped. - * - * PARAMS - * himlDst [I] handle to the destination image list - * iDst [I] destination image index. - * himlSrc [I] handle to the source image list - * iSrc [I] source image index - * uFlags [I] flags for the copy operation - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * NOTES - * Copying from one image list to another is possible. The original - * implementation just copies or swaps within one image list. - * Could this feature become a bug??? ;-) - */ - -BOOL WINAPI -ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc, - INT iSrc, UINT uFlags) -{ - TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst, iDst, himlSrc, iSrc); - - if (!is_valid(himlSrc) || !is_valid(himlDst)) - return FALSE; - if ((iDst < 0) || (iDst >= himlDst->cCurImage)) - return FALSE; - if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage)) - return FALSE; - - if (uFlags & ILCF_SWAP) { - /* swap */ - HDC hdcBmp; - HBITMAP hbmTempImage, hbmTempMask; - - hdcBmp = CreateCompatibleDC (0); - - /* create temporary bitmaps */ - hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1, - himlSrc->uBitsPixel, NULL); - hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1, - 1, NULL); - - /* copy (and stretch) destination to temporary bitmaps.(save) */ - /* image */ - SelectObject (hdcBmp, hbmTempImage); - StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy, - himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy, - SRCCOPY); - /* mask */ - SelectObject (hdcBmp, hbmTempMask); - StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy, - himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy, - SRCCOPY); - - /* copy (and stretch) source to destination */ - /* image */ - StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy, - himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy, - SRCCOPY); - /* mask */ - StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy, - himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy, - SRCCOPY); - - /* copy (without stretching) temporary bitmaps to source (restore) */ - /* mask */ - BitBlt (himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy, - hdcBmp, 0, 0, SRCCOPY); - - /* image */ - BitBlt (himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy, - hdcBmp, 0, 0, SRCCOPY); - /* delete temporary bitmaps */ - DeleteObject (hbmTempMask); - DeleteObject (hbmTempImage); - DeleteDC(hdcBmp); - } - else { - /* copy image */ - StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy, - himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy, - SRCCOPY); - - /* copy mask */ - StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy, - himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy, - SRCCOPY); - } - - return TRUE; -} - - -/************************************************************************* - * ImageList_Create [COMCTL32.@] - * - * Creates a new image list. - * - * PARAMS - * cx [I] image height - * cy [I] image width - * flags [I] creation flags - * cInitial [I] initial number of images in the image list - * cGrow [I] number of images by which image list grows - * - * RETURNS - * Success: Handle to the created image list - * Failure: NULL - */ -HIMAGELIST WINAPI -ImageList_Create (INT cx, INT cy, UINT flags, - INT cInitial, INT cGrow) -{ - HIMAGELIST himl; - INT nCount; - HBITMAP hbmTemp; - UINT ilc = (flags & 0xFE); - static const WORD aBitBlend25[] = - {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00}; - - static const WORD aBitBlend50[] = - {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA}; - - TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow); - - himl = (HIMAGELIST)Alloc (sizeof(struct _IMAGELIST)); - if (!himl) - return NULL; - - cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3; - - himl->magic = IMAGELIST_MAGIC; - himl->cx = cx; - himl->cy = cy; - himl->flags = flags; - himl->cMaxImage = cInitial + cGrow; - himl->cInitial = cInitial; - himl->cGrow = cGrow; - himl->clrFg = CLR_DEFAULT; - himl->clrBk = CLR_NONE; - - /* initialize overlay mask indices */ - for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++) - himl->nOvlIdx[nCount] = -1; - - /* Create Image & Mask DCs */ - himl->hdcImage = CreateCompatibleDC (0); - if (!himl->hdcImage) - goto cleanup; - if (himl->flags & ILC_MASK){ - himl->hdcMask = CreateCompatibleDC(0); - if (!himl->hdcMask) - goto cleanup; - } - - /* Default to ILC_COLOR4 if none of the ILC_COLOR* flags are specified */ - if (ilc == ILC_COLOR) - ilc = ILC_COLOR4; - - if (ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32) - himl->uBitsPixel = ilc; - else - himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL); - - if (himl->cMaxImage > 0) { - himl->hbmImage = ImageList_CreateImage(himl->hdcImage, himl, cx * himl->cMaxImage, cy); - SelectObject(himl->hdcImage, himl->hbmImage); - } else - himl->hbmImage = 0; - - if ((himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) { - himl->hbmMask = - CreateBitmap (himl->cx * himl->cMaxImage, himl->cy, - 1, 1, NULL); - if (himl->hbmMask == 0) { - ERR("Error creating mask bitmap!\n"); - goto cleanup; - } - SelectObject(himl->hdcMask, himl->hbmMask); - } - else - himl->hbmMask = 0; - - /* create blending brushes */ - hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25); - himl->hbrBlend25 = CreatePatternBrush (hbmTemp); - DeleteObject (hbmTemp); - - hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50); - himl->hbrBlend50 = CreatePatternBrush (hbmTemp); - DeleteObject (hbmTemp); - - TRACE("created imagelist %p\n", himl); - return himl; - -cleanup: - if (himl) ImageList_Destroy(himl); - return NULL; -} - - -/************************************************************************* - * ImageList_Destroy [COMCTL32.@] - * - * Destroys an image list. - * - * PARAMS - * himl [I] handle to image list - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ - -BOOL WINAPI -ImageList_Destroy (HIMAGELIST himl) -{ - if (!is_valid(himl)) - return FALSE; - - /* delete image bitmaps */ - if (himl->hbmImage) - DeleteObject (himl->hbmImage); - if (himl->hbmMask) - DeleteObject (himl->hbmMask); - - /* delete image & mask DCs */ - if (himl->hdcImage) - DeleteDC(himl->hdcImage); - if (himl->hdcMask) - DeleteDC(himl->hdcMask); - - /* delete blending brushes */ - if (himl->hbrBlend25) - DeleteObject (himl->hbrBlend25); - if (himl->hbrBlend50) - DeleteObject (himl->hbrBlend50); - - ZeroMemory(himl, sizeof(*himl)); - Free (himl); - - return TRUE; -} - - -/************************************************************************* - * ImageList_DragEnter [COMCTL32.@] - * - * Locks window update and displays the drag image at the given position. - * - * PARAMS - * hwndLock [I] handle of the window that owns the drag image. - * x [I] X position of the drag image. - * y [I] Y position of the drag image. - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * NOTES - * The position of the drag image is relative to the window, not - * the client area. - */ - -BOOL WINAPI -ImageList_DragEnter (HWND hwndLock, INT x, INT y) -{ - TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y); - - if (!is_valid(InternalDrag.himl)) - return FALSE; - - if (hwndLock) - InternalDrag.hwnd = hwndLock; - else - InternalDrag.hwnd = GetDesktopWindow (); - - InternalDrag.x = x; - InternalDrag.y = y; - - /* draw the drag image and save the background */ - if (!ImageList_DragShowNolock(TRUE)) { - return FALSE; - } - - return TRUE; -} - - -/************************************************************************* - * ImageList_DragLeave [COMCTL32.@] - * - * Unlocks window update and hides the drag image. - * - * PARAMS - * hwndLock [I] handle of the window that owns the drag image. - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ - -BOOL WINAPI -ImageList_DragLeave (HWND hwndLock) -{ - /* As we don't save drag info in the window this can lead to problems if - an app does not supply the same window as DragEnter */ - /* if (hwndLock) - InternalDrag.hwnd = hwndLock; - else - InternalDrag.hwnd = GetDesktopWindow (); */ - if(!hwndLock) - hwndLock = GetDesktopWindow(); - if(InternalDrag.hwnd != hwndLock) - FIXME("DragLeave hWnd != DragEnter hWnd\n"); - - ImageList_DragShowNolock (FALSE); - - return TRUE; -} - - -/************************************************************************* - * ImageList_InternalDragDraw [Internal] - * - * Draws the drag image. - * - * PARAMS - * hdc [I] device context to draw into. - * x [I] X position of the drag image. - * y [I] Y position of the drag image. - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * NOTES - * The position of the drag image is relative to the window, not - * the client area. - * - */ - -static inline void -ImageList_InternalDragDraw (HDC hdc, INT x, INT y) -{ - IMAGELISTDRAWPARAMS imldp; - - ZeroMemory (&imldp, sizeof(imldp)); - imldp.cbSize = sizeof(imldp); - imldp.himl = InternalDrag.himl; - imldp.i = 0; - imldp.hdcDst = hdc, - imldp.x = x; - imldp.y = y; - imldp.rgbBk = CLR_DEFAULT; - imldp.rgbFg = CLR_DEFAULT; - imldp.fStyle = ILD_NORMAL; - imldp.fState = ILS_ALPHA; - imldp.Frame = 128; - - /* FIXME: instead of using the alpha blending, we should - * create a 50% mask, and draw it semitransparantly that way */ - ImageList_DrawIndirect (&imldp); -} - -/************************************************************************* - * ImageList_DragMove [COMCTL32.@] - * - * Moves the drag image. - * - * PARAMS - * x [I] X position of the drag image. - * y [I] Y position of the drag image. - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * NOTES - * The position of the drag image is relative to the window, not - * the client area. - * - * BUGS - * The drag image should be drawn semitransparent. - */ - -BOOL WINAPI -ImageList_DragMove (INT x, INT y) -{ - TRACE("(x=%d y=%d)\n", x, y); - - if (!is_valid(InternalDrag.himl)) - return FALSE; - - /* draw/update the drag image */ - if (InternalDrag.bShow) { - HDC hdcDrag; - HDC hdcOffScreen; - HDC hdcBg; - HBITMAP hbmOffScreen; - INT origNewX, origNewY; - INT origOldX, origOldY; - INT origRegX, origRegY; - INT sizeRegX, sizeRegY; - - - /* calculate the update region */ - origNewX = x - InternalDrag.dxHotspot; - origNewY = y - InternalDrag.dyHotspot; - origOldX = InternalDrag.x - InternalDrag.dxHotspot; - origOldY = InternalDrag.y - InternalDrag.dyHotspot; - origRegX = min(origNewX, origOldX); - origRegY = min(origNewY, origOldY); - sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x); - sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y); - - hdcDrag = GetDCEx(InternalDrag.hwnd, 0, - DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE); - hdcOffScreen = CreateCompatibleDC(hdcDrag); - hdcBg = CreateCompatibleDC(hdcDrag); - - hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY); - SelectObject(hdcOffScreen, hbmOffScreen); - SelectObject(hdcBg, InternalDrag.hbmBg); - - /* get the actual background of the update region */ - BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag, - origRegX, origRegY, SRCCOPY); - /* erase the old image */ - BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY, - InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0, - SRCCOPY); - /* save the background */ - BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy, - hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY); - /* draw the image */ - ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX, - origNewY - origRegY); - /* draw the update region to the screen */ - BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY, - hdcOffScreen, 0, 0, SRCCOPY); - - DeleteDC(hdcBg); - DeleteDC(hdcOffScreen); - DeleteObject(hbmOffScreen); - ReleaseDC(InternalDrag.hwnd, hdcDrag); - } - - /* update the image position */ - InternalDrag.x = x; - InternalDrag.y = y; - - return TRUE; -} - - -/************************************************************************* - * ImageList_DragShowNolock [COMCTL32.@] - * - * Shows or hides the drag image. - * - * PARAMS - * bShow [I] TRUE shows the drag image, FALSE hides it. - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * BUGS - * The drag image should be drawn semitransparent. - */ - -BOOL WINAPI -ImageList_DragShowNolock (BOOL bShow) -{ - HDC hdcDrag; - HDC hdcBg; - INT x, y; - - if (!is_valid(InternalDrag.himl)) - return FALSE; - - TRACE("bShow=0x%X!\n", bShow); - - /* DragImage is already visible/hidden */ - if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) { - return FALSE; - } - - /* position of the origin of the DragImage */ - x = InternalDrag.x - InternalDrag.dxHotspot; - y = InternalDrag.y - InternalDrag.dyHotspot; - - hdcDrag = GetDCEx (InternalDrag.hwnd, 0, - DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE); - if (!hdcDrag) { - return FALSE; - } - - hdcBg = CreateCompatibleDC(hdcDrag); - if (!InternalDrag.hbmBg) { - InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag, - InternalDrag.himl->cx, InternalDrag.himl->cy); - } - SelectObject(hdcBg, InternalDrag.hbmBg); - - if (bShow) { - /* save the background */ - BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy, - hdcDrag, x, y, SRCCOPY); - /* show the image */ - ImageList_InternalDragDraw(hdcDrag, x, y); - } else { - /* hide the image */ - BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy, - hdcBg, 0, 0, SRCCOPY); - } - - InternalDrag.bShow = !InternalDrag.bShow; - - DeleteDC(hdcBg); - ReleaseDC (InternalDrag.hwnd, hdcDrag); - return TRUE; -} - - -/************************************************************************* - * ImageList_Draw [COMCTL32.@] - * - * Draws an image. - * - * PARAMS - * himl [I] handle to image list - * i [I] image index - * hdc [I] handle to device context - * x [I] x position - * y [I] y position - * fStyle [I] drawing flags - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * SEE - * ImageList_DrawEx. - */ - -BOOL WINAPI -ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle) -{ - return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0, - CLR_DEFAULT, CLR_DEFAULT, fStyle); -} - - -/************************************************************************* - * ImageList_DrawEx [COMCTL32.@] - * - * Draws an image and allows to use extended drawing features. - * - * PARAMS - * himl [I] handle to image list - * i [I] image index - * hdc [I] handle to device context - * x [I] X position - * y [I] Y position - * dx [I] X offset - * dy [I] Y offset - * rgbBk [I] background color - * rgbFg [I] foreground color - * fStyle [I] drawing flags - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * NOTES - * Calls ImageList_DrawIndirect. - * - * SEE - * ImageList_DrawIndirect. - */ - -BOOL WINAPI -ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, - INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg, - UINT fStyle) -{ - IMAGELISTDRAWPARAMS imldp; - - ZeroMemory (&imldp, sizeof(imldp)); - imldp.cbSize = sizeof(imldp); - imldp.himl = himl; - imldp.i = i; - imldp.hdcDst = hdc, - imldp.x = x; - imldp.y = y; - imldp.cx = dx; - imldp.cy = dy; - imldp.rgbBk = rgbBk; - imldp.rgbFg = rgbFg; - imldp.fStyle = fStyle; - - return ImageList_DrawIndirect (&imldp); -} - - -/************************************************************************* - * ImageList_DrawIndirect [COMCTL32.@] - * - * Draws an image using various parameters specified in pimldp. - * - * PARAMS - * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure. - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ - -BOOL WINAPI -ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp) -{ - INT cx, cy, lx, ly, nOvlIdx; - DWORD fState, dwRop; - UINT fStyle; - COLORREF oldImageBk, oldImageFg; - HDC hImageDC, hImageListDC, hMaskListDC; - HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp; - BOOL bIsTransparent, bBlend, bResult = FALSE, bMask; - HIMAGELIST himl; - - if (!pimldp || !(himl = pimldp->himl)) return FALSE; - if (!is_valid(himl)) return FALSE; - if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE; - - lx = himl->cx * pimldp->i + pimldp->xBitmap; - ly = pimldp->yBitmap; - - fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState; - fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK; - cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx; - cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy; - - bIsTransparent = (fStyle & ILD_TRANSPARENT); - if( pimldp->rgbBk == CLR_NONE ) - bIsTransparent = TRUE; - if( ( pimldp->rgbBk == CLR_DEFAULT ) && ( himl->clrBk == CLR_NONE ) ) - bIsTransparent = TRUE; - bMask = (himl->flags & ILC_MASK) && (fStyle & ILD_MASK) ; - bBlend = (fStyle & (ILD_BLEND25 | ILD_BLEND50) ) && !bMask; - - TRACE("himl(0x%lx) hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n", - (DWORD)himl, himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy); - - /* we will use these DCs to access the images and masks in the ImageList */ - hImageListDC = himl->hdcImage; - hMaskListDC = himl->hdcMask; - - /* these will accumulate the image and mask for the image we're drawing */ - hImageDC = CreateCompatibleDC( pimldp->hdcDst ); - hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy ); - hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0; - - /* Create a compatible DC. */ - if (!hImageListDC || !hImageDC || !hImageBmp || - (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC)) - goto cleanup; - - hOldImageBmp = SelectObject(hImageDC, hImageBmp); - - /* - * To obtain a transparent look, background color should be set - * to white and foreground color to black when blting the - * monochrome mask. - */ - oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) ); - oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) ); - - /* - * Draw the initial image - */ - if( bMask ) { - if (himl->hbmMask) { - HBRUSH hOldBrush; - hOldBrush = SelectObject (hImageDC, CreateSolidBrush (GetTextColor(pimldp->hdcDst))); - PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY ); - BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCPAINT); - DeleteObject (SelectObject (hImageDC, hOldBrush)); - if( bIsTransparent ) - { - BitBlt ( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, SRCAND); - bResult = TRUE; - goto end; - } - } else { - HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH)); - PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY); - SelectObject(hImageDC, hOldBrush); - } - } else { - /* blend the image with the needed solid background */ - COLORREF colour = RGB(0,0,0); - HBRUSH hOldBrush; - - if( !bIsTransparent ) - { - colour = pimldp->rgbBk; - if( colour == CLR_DEFAULT ) - colour = himl->clrBk; - if( colour == CLR_NONE ) - colour = GetBkColor(pimldp->hdcDst); - } - - hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour)); - PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY ); - BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCAND ); - BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCPAINT ); - DeleteObject (SelectObject (hImageDC, hOldBrush)); - } - - /* Time for blending, if required */ - if (bBlend) { - HBRUSH hBlendBrush, hOldBrush; - COLORREF clrBlend = pimldp->rgbFg; - HDC hBlendMaskDC = hImageListDC; - HBITMAP hOldBitmap; - - /* Create the blend Mask */ - hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp); - hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25; - hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush); - PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY); - SelectObject(hBlendMaskDC, hOldBrush); - - /* Modify the blend mask if an Image Mask exist */ - if(himl->hbmMask) { - BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, lx, ly, 0x220326); /* NOTSRCAND */ - BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY); - } - - /* now apply blend to the current image given the BlendMask */ - if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT); - else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst); - hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend)); - BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */ - DeleteObject(SelectObject(hImageDC, hOldBrush)); - SelectObject(hBlendMaskDC, hOldBitmap); - } - - /* Now do the overlay image, if any */ - nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8; - if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) { - nOvlIdx = himl->nOvlIdx[nOvlIdx - 1]; - if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) { - const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap; - if (himl->hbmMask && !(fStyle & ILD_IMAGE)) - BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, ly, SRCAND); - BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, ly, SRCPAINT); - } - } - - if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n"); - if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n"); - if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n"); - if (fState & ILS_ALPHA) FIXME("ILS_ALPHA: unimplemented!\n"); - - if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n"); - if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n"); - if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n"); - - /* now copy the image to the screen */ - dwRop = SRCCOPY; - if (himl->hbmMask && bIsTransparent ) { - COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) ); - COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff )); - BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, lx, ly, SRCAND); - SetBkColor(pimldp->hdcDst, oldDstBk); - SetTextColor(pimldp->hdcDst, oldDstFg); - dwRop = SRCPAINT; - } - if (fStyle & ILD_ROP) dwRop = pimldp->dwRop; - BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop); - - bResult = TRUE; -end: - /* cleanup the mess */ - SetBkColor(hImageDC, oldImageBk); - SetTextColor(hImageDC, oldImageFg); - SelectObject(hImageDC, hOldImageBmp); -cleanup: - DeleteObject(hBlendMaskBmp); - DeleteObject(hImageBmp); - DeleteDC(hImageDC); - - return bResult; -} - - -/************************************************************************* - * ImageList_Duplicate [COMCTL32.@] - * - * Duplicates an image list. - * - * PARAMS - * himlSrc [I] source image list handle - * - * RETURNS - * Success: Handle of duplicated image list. - * Failure: NULL - */ - -HIMAGELIST WINAPI -ImageList_Duplicate (HIMAGELIST himlSrc) -{ - HIMAGELIST himlDst; - - if (!is_valid(himlSrc)) { - ERR("Invalid image list handle!\n"); - return NULL; - } - - himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags, - himlSrc->cInitial, himlSrc->cGrow); - - if (himlDst) - { - BitBlt (himlDst->hdcImage, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy, - himlSrc->hdcImage, 0, 0, SRCCOPY); - - if (himlDst->hbmMask) - BitBlt (himlDst->hdcMask, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy, - himlSrc->hdcMask, 0, 0, SRCCOPY); - - himlDst->cCurImage = himlSrc->cCurImage; - himlDst->cMaxImage = himlSrc->cMaxImage; - } - return himlDst; -} - - -/************************************************************************* - * ImageList_EndDrag [COMCTL32.@] - * - * Finishes a drag operation. - * - * PARAMS - * no Parameters - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ - -VOID WINAPI -ImageList_EndDrag (void) -{ - /* cleanup the InternalDrag struct */ - InternalDrag.hwnd = 0; - ImageList_Destroy (InternalDrag.himl); - InternalDrag.himl = 0; - InternalDrag.x= 0; - InternalDrag.y= 0; - InternalDrag.dxHotspot = 0; - InternalDrag.dyHotspot = 0; - InternalDrag.bShow = FALSE; - DeleteObject(InternalDrag.hbmBg); - InternalDrag.hbmBg = 0; -} - - -/************************************************************************* - * ImageList_GetBkColor [COMCTL32.@] - * - * Returns the background color of an image list. - * - * PARAMS - * himl [I] Image list handle. - * - * RETURNS - * Success: background color - * Failure: CLR_NONE - */ - -COLORREF WINAPI -ImageList_GetBkColor (HIMAGELIST himl) -{ - return himl ? himl->clrBk : CLR_NONE; -} - - -/************************************************************************* - * ImageList_GetDragImage [COMCTL32.@] - * - * Returns the handle to the internal drag image list. - * - * PARAMS - * ppt [O] Pointer to the drag position. Can be NULL. - * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL. - * - * RETURNS - * Success: Handle of the drag image list. - * Failure: NULL. - */ - -HIMAGELIST WINAPI -ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot) -{ - if (is_valid(InternalDrag.himl)) { - if (ppt) { - ppt->x = InternalDrag.x; - ppt->y = InternalDrag.y; - } - if (pptHotspot) { - pptHotspot->x = InternalDrag.dxHotspot; - pptHotspot->y = InternalDrag.dyHotspot; - } - return (InternalDrag.himl); - } - - return NULL; -} - - -/************************************************************************* - * ImageList_GetFlags [COMCTL32.@] - * - * Gets the flags of the specified image list. - * - * PARAMS - * himl [I] Handle to image list - * - * RETURNS - * Image list flags. - * - * BUGS - * Stub. - */ - -DWORD WINAPI -ImageList_GetFlags(HIMAGELIST himl) -{ - FIXME("(%p):empty stub\n", himl); - return 0; -} - - -/************************************************************************* - * ImageList_GetIcon [COMCTL32.@] - * - * Creates an icon from a masked image of an image list. - * - * PARAMS - * himl [I] handle to image list - * i [I] image index - * flags [I] drawing style flags - * - * RETURNS - * Success: icon handle - * Failure: NULL - */ - -HICON WINAPI -ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle) -{ - ICONINFO ii; - HICON hIcon; - HBITMAP hOldDstBitmap; - HDC hdcDst; - - TRACE("%p %d %d\n", himl, i, fStyle); - if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL; - - ii.fIcon = TRUE; - ii.xHotspot = 0; - ii.yHotspot = 0; - - /* create colour bitmap */ - hdcDst = GetDC(0); - ii.hbmColor = CreateCompatibleBitmap(hdcDst, himl->cx, himl->cy); - ReleaseDC(0, hdcDst); - - hdcDst = CreateCompatibleDC(0); - - /* draw mask*/ - ii.hbmMask = CreateBitmap (himl->cx, himl->cy, 1, 1, NULL); - hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask); - if (himl->hbmMask) { - BitBlt (hdcDst, 0, 0, himl->cx, himl->cy, - himl->hdcMask, i * himl->cx, 0, SRCCOPY); - } - else - PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS); - - /* draw image*/ - SelectObject (hdcDst, ii.hbmColor); - BitBlt (hdcDst, 0, 0, himl->cx, himl->cy, - himl->hdcImage, i * himl->cx, 0, SRCCOPY); - - /* - * CreateIconIndirect requires us to deselect the bitmaps from - * the DCs before calling - */ - SelectObject(hdcDst, hOldDstBitmap); - - hIcon = CreateIconIndirect (&ii); - - DeleteObject (ii.hbmMask); - DeleteObject (ii.hbmColor); - DeleteDC (hdcDst); - - return hIcon; -} - - -/************************************************************************* - * ImageList_GetIconSize [COMCTL32.@] - * - * Retrieves the size of an image in an image list. - * - * PARAMS - * himl [I] handle to image list - * cx [O] pointer to the image width. - * cy [O] pointer to the image height. - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * NOTES - * All images in an image list have the same size. - */ - -BOOL WINAPI -ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy) -{ - if (!is_valid(himl)) - return FALSE; - if ((himl->cx <= 0) || (himl->cy <= 0)) - return FALSE; - - if (cx) - *cx = himl->cx; - if (cy) - *cy = himl->cy; - - return TRUE; -} - - -/************************************************************************* - * ImageList_GetImageCount [COMCTL32.@] - * - * Returns the number of images in an image list. - * - * PARAMS - * himl [I] handle to image list - * - * RETURNS - * Success: Number of images. - * Failure: 0 - */ - -INT WINAPI -ImageList_GetImageCount (HIMAGELIST himl) -{ - if (!is_valid(himl)) - return 0; - - return himl->cCurImage; -} - - -/************************************************************************* - * ImageList_GetImageInfo [COMCTL32.@] - * - * Returns information about an image in an image list. - * - * PARAMS - * himl [I] handle to image list - * i [I] image index - * pImageInfo [O] pointer to the image information - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ - -BOOL WINAPI -ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo) -{ - if (!is_valid(himl) || (pImageInfo == NULL)) - return FALSE; - if ((i < 0) || (i >= himl->cCurImage)) - return FALSE; - - pImageInfo->hbmImage = himl->hbmImage; - pImageInfo->hbmMask = himl->hbmMask; - - pImageInfo->rcImage.top = 0; - pImageInfo->rcImage.bottom = himl->cy; - pImageInfo->rcImage.left = i * himl->cx; - pImageInfo->rcImage.right = (i+1) * himl->cx; - - return TRUE; -} - - -/************************************************************************* - * ImageList_GetImageRect [COMCTL32.@] - * - * Retrieves the rectangle of the specified image in an image list. - * - * PARAMS - * himl [I] handle to image list - * i [I] image index - * lpRect [O] pointer to the image rectangle - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * NOTES - * This is an UNDOCUMENTED function!!! - */ - -BOOL WINAPI -ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect) -{ - if (!is_valid(himl) || (lpRect == NULL)) - return FALSE; - if ((i < 0) || (i >= himl->cCurImage)) - return FALSE; - - lpRect->left = i * himl->cx; - lpRect->top = 0; - lpRect->right = lpRect->left + himl->cx; - lpRect->bottom = himl->cy; - - return TRUE; -} - - -/************************************************************************* - * ImageList_LoadImage [COMCTL32.@] - * ImageList_LoadImageA [COMCTL32.@] - * - * Creates an image list from a bitmap, icon or cursor. - * - * SEE - * ImageList_LoadImageW () - */ - -HIMAGELIST WINAPI -ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow, - COLORREF clrMask, UINT uType, UINT uFlags) -{ - HIMAGELIST himl; - LPWSTR lpbmpW; - DWORD len; - - if (!HIWORD(lpbmp)) - return ImageList_LoadImageW(hi, (LPCWSTR)lpbmp, cx, cGrow, clrMask, - uType, uFlags); - - len = MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, NULL, 0); - lpbmpW = Alloc(len * sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, lpbmpW, len); - - himl = ImageList_LoadImageW(hi, lpbmpW, cx, cGrow, clrMask, uType, uFlags); - Free (lpbmpW); - return himl; -} - - -/************************************************************************* - * ImageList_LoadImageW [COMCTL32.@] - * - * Creates an image list from a bitmap, icon or cursor. - * - * PARAMS - * hi [I] instance handle - * lpbmp [I] name or id of the image - * cx [I] width of each image - * cGrow [I] number of images to expand - * clrMask [I] mask color - * uType [I] type of image to load - * uFlags [I] loading flags - * - * RETURNS - * Success: handle to the loaded image list - * Failure: NULL - * - * SEE - * LoadImage () - */ - -HIMAGELIST WINAPI -ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow, - COLORREF clrMask, UINT uType, UINT uFlags) -{ - HIMAGELIST himl = NULL; - HANDLE handle; - INT nImageCount; - - handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags); - if (!handle) { - ERR("Error loading image!\n"); - return NULL; - } - - if (uType == IMAGE_BITMAP) { - BITMAP bmp; - GetObjectW (handle, sizeof(BITMAP), &bmp); - - /* To match windows behavior, if cx is set to zero and - the flag DI_DEFAULTSIZE is specified, cx becomes the - system metric value for icons. If the flag is not specified - the function sets the size to the height of the bitmap */ - if (cx == 0) - { - if (uFlags & DI_DEFAULTSIZE) - cx = GetSystemMetrics (SM_CXICON); - else - cx = bmp.bmHeight; - } - - nImageCount = bmp.bmWidth / cx; - - himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR, - nImageCount, cGrow); - if (!himl) { - DeleteObject (handle); - return NULL; - } - ImageList_AddMasked (himl, (HBITMAP)handle, clrMask); - } - else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) { - ICONINFO ii; - BITMAP bmp; - - GetIconInfo (handle, &ii); - GetObjectW (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp); - himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight, - ILC_MASK | ILC_COLOR, 1, cGrow); - if (!himl) { - DeleteObject (ii.hbmColor); - DeleteObject (ii.hbmMask); - DeleteObject (handle); - return NULL; - } - ImageList_Add (himl, ii.hbmColor, ii.hbmMask); - DeleteObject (ii.hbmColor); - DeleteObject (ii.hbmMask); - } - - DeleteObject (handle); - - return himl; -} - - -/************************************************************************* - * ImageList_Merge [COMCTL32.@] - * - * Create an image list containing a merged image from two image lists. - * - * PARAMS - * himl1 [I] handle to first image list - * i1 [I] first image index - * himl2 [I] handle to second image list - * i2 [I] second image index - * dx [I] X offset of the second image relative to the first. - * dy [I] Y offset of the second image relative to the first. - * - * RETURNS - * Success: The newly created image list. It contains a single image - * consisting of the second image merged with the first. - * Failure: NULL, if either himl1 or himl2 are invalid. - * - * NOTES - * - The returned image list should be deleted by the caller using - * ImageList_Destroy() when it is no longer required. - * - If either i1 or i2 are not valid image indices they will be treated - * as a blank image. - */ -HIMAGELIST WINAPI -ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2, - INT dx, INT dy) -{ - HIMAGELIST himlDst = NULL; - INT cxDst, cyDst; - INT xOff1, yOff1, xOff2, yOff2; - INT nX1, nX2; - - TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2, - i2, dx, dy); - - if (!is_valid(himl1) || !is_valid(himl2)) - return NULL; - - if (dx > 0) { - cxDst = max (himl1->cx, dx + himl2->cx); - xOff1 = 0; - xOff2 = dx; - } - else if (dx < 0) { - cxDst = max (himl2->cx, himl1->cx - dx); - xOff1 = -dx; - xOff2 = 0; - } - else { - cxDst = max (himl1->cx, himl2->cx); - xOff1 = 0; - xOff2 = 0; - } - - if (dy > 0) { - cyDst = max (himl1->cy, dy + himl2->cy); - yOff1 = 0; - yOff2 = dy; - } - else if (dy < 0) { - cyDst = max (himl2->cy, himl1->cy - dy); - yOff1 = -dy; - yOff2 = 0; - } - else { - cyDst = max (himl1->cy, himl2->cy); - yOff1 = 0; - yOff2 = 0; - } - - himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1); - - if (himlDst) - { - nX1 = i1 * himl1->cx; - nX2 = i2 * himl2->cx; - - /* copy image */ - BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS); - if (i1 >= 0 && i1 < himl1->cCurImage) - BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, nX1, 0, SRCCOPY); - if (i2 >= 0 && i2 < himl2->cCurImage) - { - BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , nX2, 0, SRCAND); - BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, nX2, 0, SRCPAINT); - } - - /* copy mask */ - BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS); - if (i1 >= 0 && i1 < himl1->cCurImage) - BitBlt (himlDst->hdcMask, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask, nX1, 0, SRCCOPY); - if (i2 >= 0 && i2 < himl2->cCurImage) - BitBlt (himlDst->hdcMask, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask, nX2, 0, SRCAND); - - himlDst->cCurImage = 1; - } - - return himlDst; -} - - -/* helper for _read_bitmap currently unused */ -#if 0 -static int may_use_dibsection(HDC hdc) { - int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES); - if (bitspixel>8) - return TRUE; - if (bitspixel<=4) - return FALSE; - return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE; -} -#endif - -/* helper for ImageList_Read, see comments below */ -static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) { - HDC xdc = 0, hBitmapDC =0; - BITMAPFILEHEADER bmfh; - BITMAPINFOHEADER bmih; - int bitsperpixel,palspace,longsperline,width,height; - LPBITMAPINFOHEADER bmihc = NULL; - int result = 0; - HBITMAP hbitmap = 0, hDIB = 0; - LPBYTE bits = NULL; - - if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) || - (bmfh.bfType != (('M'<<8)|'B')) || - !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) || - (bmih.biSize != sizeof(bmih)) - ) - return 0; - - bitsperpixel = bmih.biPlanes * bmih.biBitCount; - if (bitsperpixel<=8) - palspace = (1<>5; - bmihc->biSizeImage = (longsperline*height)<<2; - - /* read the palette right after the end of the bitmapinfoheader */ - if (palspace) - if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL))) - goto ret1; - - xdc = GetDC(0); -#if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */ - if ((bitsperpixel>1) && - ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc))) - ) { - hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0); - if (!hbitmap) - goto ret1; - if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL))) - goto ret1; - result = 1; - } else -#endif - { - int i,nwidth,nheight,nRows; - - nwidth = width*(height/cy); - nheight = cy; - nRows = (height/cy); - - if (bitsperpixel==1) - hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL); - else - hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight); - - hDIB = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0); - if (!hDIB) - goto ret1; - if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL))) - goto ret1; - - hBitmapDC = CreateCompatibleDC(0); - SelectObject(hBitmapDC, hbitmap); - - /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */ - /* Do not forget that windows bitmaps are bottom->top */ - TRACE("nRows=%d\n", nRows); - for (i=0; i < nRows; i++){ - StretchDIBits(hBitmapDC, width*i, 0, width, cy, 0, cy*(nRows-1-i), width, cy, bits, - (BITMAPINFO*)bmihc, DIB_RGB_COLORS, SRCCOPY); - } - - result = 1; - } -ret1: - if (xdc) ReleaseDC(0,xdc); - if (bmihc) LocalFree((HLOCAL)bmihc); - if (hDIB) DeleteObject(hDIB); - if (hBitmapDC) DeleteDC(hBitmapDC); - if (!result) { - if (hbitmap) { - DeleteObject(hbitmap); - hbitmap = 0; - } - } - return hbitmap; -} - -/************************************************************************* - * ImageList_Read [COMCTL32.@] - * - * Reads an image list from a stream. - * - * PARAMS - * pstm [I] pointer to a stream - * - * RETURNS - * Success: handle to image list - * Failure: NULL - * - * The format is like this: - * ILHEAD ilheadstruct; - * - * for the color image part: - * BITMAPFILEHEADER bmfh; - * BITMAPINFOHEADER bmih; - * only if it has a palette: - * RGBQUAD rgbs[nr_of_paletted_colors]; - * - * BYTE colorbits[imagesize]; - * - * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags: - * BITMAPFILEHEADER bmfh_mask; - * BITMAPINFOHEADER bmih_mask; - * only if it has a palette (it usually does not): - * RGBQUAD rgbs[nr_of_paletted_colors]; - * - * BYTE maskbits[imagesize]; - * - * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect. - * _read_bitmap needs to convert them. - */ -HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm) -{ - ILHEAD ilHead; - HIMAGELIST himl; - HBITMAP hbmColor=0,hbmMask=0; - int i; - - if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL))) - return NULL; - if (ilHead.usMagic != (('L' << 8) | 'I')) - return NULL; - if (ilHead.usVersion != 0x101) /* probably version? */ - return NULL; - -#if 0 - FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage); - FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage); - FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow); - FIXME(" ilHead.cx = %d\n",ilHead.cx); - FIXME(" ilHead.cy = %d\n",ilHead.cy); - FIXME(" ilHead.flags = %x\n",ilHead.flags); - FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]); - FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]); - FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]); - FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]); -#endif - - hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy); - if (!hbmColor) - return NULL; - if (ilHead.flags & ILC_MASK) { - hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy); - if (!hbmMask) { - DeleteObject(hbmColor); - return NULL; - } - } - - himl = ImageList_Create ( - ilHead.cx, - ilHead.cy, - ilHead.flags, - 1, /* initial */ - ilHead.cGrow - ); - if (!himl) { - DeleteObject(hbmColor); - DeleteObject(hbmMask); - return NULL; - } - SelectObject(himl->hdcImage, hbmColor); - DeleteObject(himl->hbmImage); - himl->hbmImage = hbmColor; - if (hbmMask){ - SelectObject(himl->hdcMask, hbmMask); - DeleteObject(himl->hbmMask); - himl->hbmMask = hbmMask; - } - himl->cCurImage = ilHead.cCurImage; - himl->cMaxImage = ilHead.cMaxImage; - - ImageList_SetBkColor(himl,ilHead.bkcolor); - for (i=0;i<4;i++) - ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1); - return himl; -} - - -/************************************************************************* - * ImageList_Remove [COMCTL32.@] - * - * Removes an image from an image list - * - * PARAMS - * himl [I] image list handle - * i [I] image index - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ - -BOOL WINAPI -ImageList_Remove (HIMAGELIST himl, INT i) -{ - HBITMAP hbmNewImage, hbmNewMask; - HDC hdcBmp; - INT cxNew, nCount; - - TRACE("(himl=%p i=%d)\n", himl, i); - - if (!is_valid(himl)) { - ERR("Invalid image list handle!\n"); - return FALSE; - } - - if ((i < -1) || (i >= himl->cCurImage)) { - TRACE("index out of range! %d\n", i); - return FALSE; - } - - if (i == -1) { - /* remove all */ - if (himl->cCurImage == 0) { - /* remove all on empty ImageList is allowed */ - TRACE("remove all on empty ImageList!\n"); - return TRUE; - } - - himl->cMaxImage = himl->cInitial + himl->cGrow; - himl->cCurImage = 0; - for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++) - himl->nOvlIdx[nCount] = -1; - - hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage * himl->cx, himl->cy); - SelectObject (himl->hdcImage, hbmNewImage); - DeleteObject (himl->hbmImage); - himl->hbmImage = hbmNewImage; - - if (himl->hbmMask) { - hbmNewMask = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy, - 1, 1, NULL); - SelectObject (himl->hdcMask, hbmNewMask); - DeleteObject (himl->hbmMask); - himl->hbmMask = hbmNewMask; - } - } - else { - /* delete one image */ - TRACE("Remove single image! %d\n", i); - - /* create new bitmap(s) */ - nCount = (himl->cCurImage + himl->cGrow - 1); - cxNew = nCount * himl->cx; - - TRACE(" - Number of images: %d / %d (Old/New)\n", - himl->cCurImage, himl->cCurImage - 1); - TRACE(" - Max. number of images: %d / %d (Old/New)\n", - himl->cMaxImage, himl->cCurImage + himl->cGrow - 1); - - hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, cxNew, himl->cy); - - if (himl->hbmMask) - hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL); - else - hbmNewMask = 0; /* Just to keep compiler happy! */ - - hdcBmp = CreateCompatibleDC (0); - - /* copy all images and masks prior to the "removed" image */ - if (i > 0) { - TRACE("Pre image copy: Copy %d images\n", i); - - SelectObject (hdcBmp, hbmNewImage); - BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy, - himl->hdcImage, 0, 0, SRCCOPY); - - if (himl->hbmMask) { - SelectObject (hdcBmp, hbmNewMask); - BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy, - himl->hdcMask, 0, 0, SRCCOPY); - } - } - - /* copy all images and masks behind the removed image */ - if (i < himl->cCurImage - 1) { - TRACE("Post image copy!\n"); - SelectObject (hdcBmp, hbmNewImage); - BitBlt (hdcBmp, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx, - himl->cy, himl->hdcImage, (i + 1) * himl->cx, 0, SRCCOPY); - - if (himl->hbmMask) { - SelectObject (hdcBmp, hbmNewMask); - BitBlt (hdcBmp, i * himl->cx, 0, - (himl->cCurImage - i - 1) * himl->cx, - himl->cy, himl->hdcMask, (i + 1) * himl->cx, 0, SRCCOPY); - } - } - - DeleteDC (hdcBmp); - - /* delete old images and insert new ones */ - SelectObject (himl->hdcImage, hbmNewImage); - DeleteObject (himl->hbmImage); - himl->hbmImage = hbmNewImage; - if (himl->hbmMask) { - SelectObject (himl->hdcMask, hbmNewMask); - DeleteObject (himl->hbmMask); - himl->hbmMask = hbmNewMask; - } - - himl->cCurImage--; - himl->cMaxImage = himl->cCurImage + himl->cGrow; - } - - return TRUE; -} - - -/************************************************************************* - * ImageList_Replace [COMCTL32.@] - * - * Replaces an image in an image list with a new image. - * - * PARAMS - * himl [I] handle to image list - * i [I] image index - * hbmImage [I] handle to image bitmap - * hbmMask [I] handle to mask bitmap. Can be NULL. - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ - -BOOL WINAPI -ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage, - HBITMAP hbmMask) -{ - HDC hdcImage; - BITMAP bmp; - - TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask); - - if (!is_valid(himl)) { - ERR("Invalid image list handle!\n"); - return FALSE; - } - - if ((i >= himl->cMaxImage) || (i < 0)) { - ERR("Invalid image index!\n"); - return FALSE; - } - - hdcImage = CreateCompatibleDC (0); - GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp); - - /* Replace Image */ - SelectObject (hdcImage, hbmImage); - - StretchBlt (himl->hdcImage, i * himl->cx, 0, himl->cx, himl->cy, - hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY); - - if (himl->hbmMask) - { - /* Replace Mask */ - SelectObject (hdcImage, hbmMask); - - StretchBlt (himl->hdcMask, i * himl->cx, 0, himl->cx, himl->cy, - hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY); - - - /* Remove the background from the image - */ - StretchBlt (himl->hdcImage, - i*himl->cx, 0, himl->cx, himl->cy, - hdcImage, - 0, 0, bmp.bmWidth, bmp.bmHeight, - 0x220326); /* NOTSRCAND */ - } - - DeleteDC (hdcImage); - - return TRUE; -} - - -/************************************************************************* - * ImageList_ReplaceIcon [COMCTL32.@] - * - * Replaces an image in an image list using an icon. - * - * PARAMS - * himl [I] handle to image list - * i [I] image index - * hIcon [I] handle to icon - * - * RETURNS - * Success: index of the replaced image - * Failure: -1 - */ - -INT WINAPI -ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon) -{ - HDC hdcImage; - INT nIndex; - HICON hBestFitIcon; - HBITMAP hbmOldSrc; - ICONINFO ii; - BITMAP bmp; - - TRACE("(%p %d %p)\n", himl, i, hIcon); - - if (!is_valid(himl)) - return -1; - if ((i >= himl->cMaxImage) || (i < -1)) - return -1; - - hBestFitIcon = CopyImage( - hIcon, IMAGE_ICON, - himl->cx, himl->cy, - LR_COPYFROMRESOURCE); - - GetIconInfo (hBestFitIcon, &ii); - if (ii.hbmMask == 0) - ERR("no mask!\n"); - if (ii.hbmColor == 0) - ERR("no color!\n"); - GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp); - - if (i == -1) { - if (himl->cCurImage + 1 > himl->cMaxImage) - IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0); - - nIndex = himl->cCurImage; - himl->cCurImage++; - } - else - nIndex = i; - - hdcImage = CreateCompatibleDC (0); - TRACE("hdcImage=%p\n", hdcImage); - if (hdcImage == 0) - ERR("invalid hdcImage!\n"); - - SetTextColor(himl->hdcImage, RGB(0,0,0)); - SetBkColor (himl->hdcImage, RGB(255,255,255)); - hbmOldSrc = SelectObject (hdcImage, ii.hbmColor); - - StretchBlt (himl->hdcImage, nIndex * himl->cx, 0, himl->cx, himl->cy, - hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY); - - if (himl->hbmMask) { - SelectObject (hdcImage, ii.hbmMask); - StretchBlt (himl->hdcMask, nIndex * himl->cx, 0, himl->cx, himl->cy, - hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY); - } - - SelectObject (hdcImage, hbmOldSrc); - - if(hBestFitIcon) - DestroyIcon(hBestFitIcon); - if (hdcImage) - DeleteDC (hdcImage); - if (ii.hbmColor) - DeleteObject (ii.hbmColor); - if (ii.hbmMask) - DeleteObject (ii.hbmMask); - - TRACE("Insert index = %d, himl->cCurImage = %d\n", nIndex, himl->cCurImage); - return nIndex; -} - - -/************************************************************************* - * ImageList_SetBkColor [COMCTL32.@] - * - * Sets the background color of an image list. - * - * PARAMS - * himl [I] handle to image list - * clrBk [I] background color - * - * RETURNS - * Success: previous background color - * Failure: CLR_NONE - */ - -COLORREF WINAPI -ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk) -{ - COLORREF clrOldBk; - - if (!is_valid(himl)) - return CLR_NONE; - - clrOldBk = himl->clrBk; - himl->clrBk = clrBk; - return clrOldBk; -} - - -/************************************************************************* - * ImageList_SetDragCursorImage [COMCTL32.@] - * - * Combines the specified image with the current drag image - * - * PARAMS - * himlDrag [I] handle to drag image list - * iDrag [I] drag image index - * dxHotspot [I] X position of the hot spot - * dyHotspot [I] Y position of the hot spot - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * NOTES - * - The names dxHotspot, dyHotspot are misleading because they have nothing - * to do with a hotspot but are only the offset of the origin of the new - * image relative to the origin of the old image. - * - * - When this function is called and the drag image is visible, a - * short flickering occurs but this matches the Win9x behavior. It is - * possible to fix the flickering using code like in ImageList_DragMove. - */ - -BOOL WINAPI -ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag, - INT dxHotspot, INT dyHotspot) -{ - HIMAGELIST himlTemp; - BOOL visible; - - if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag)) - return FALSE; - - TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n", - dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot); - - visible = InternalDrag.bShow; - - himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, - dxHotspot, dyHotspot); - - if (visible) { - /* hide the drag image */ - ImageList_DragShowNolock(FALSE); - } - if ((InternalDrag.himl->cx != himlTemp->cx) || - (InternalDrag.himl->cy != himlTemp->cy)) { - /* the size of the drag image changed, invalidate the buffer */ - DeleteObject(InternalDrag.hbmBg); - InternalDrag.hbmBg = 0; - } - - ImageList_Destroy (InternalDrag.himl); - InternalDrag.himl = himlTemp; - - if (visible) { - /* show the drag image */ - ImageList_DragShowNolock(TRUE); - } - - return TRUE; -} - - -/************************************************************************* - * ImageList_SetFilter [COMCTL32.@] - * - * Sets a filter (or does something completely different)!!??? - * It removes 12 Bytes from the stack (3 Parameters). - * - * PARAMS - * himl [I] SHOULD be a handle to image list - * i [I] COULD be an index? - * dwFilter [I] ??? - * - * RETURNS - * Success: TRUE ??? - * Failure: FALSE ??? - * - * BUGS - * This is an UNDOCUMENTED function!!!! - * empty stub. - */ - -BOOL WINAPI -ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter) -{ - FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter); - - return FALSE; -} - - -/************************************************************************* - * ImageList_SetFlags [COMCTL32.@] - * - * Sets the image list flags. - * - * PARAMS - * himl [I] Handle to image list - * flags [I] Flags to set - * - * RETURNS - * Old flags? - * - * BUGS - * Stub. - */ - -DWORD WINAPI -ImageList_SetFlags(HIMAGELIST himl, DWORD flags) -{ - FIXME("(%p %08lx):empty stub\n", himl, flags); - return 0; -} - - -/************************************************************************* - * ImageList_SetIconSize [COMCTL32.@] - * - * Sets the image size of the bitmap and deletes all images. - * - * PARAMS - * himl [I] handle to image list - * cx [I] image width - * cy [I] image height - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ - -BOOL WINAPI -ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy) -{ - INT nCount; - HBITMAP hbmNew; - - if (!is_valid(himl)) - return FALSE; - - /* remove all images */ - himl->cMaxImage = himl->cInitial + himl->cGrow; - himl->cCurImage = 0; - himl->cx = cx; - himl->cy = cy; - - /* initialize overlay mask indices */ - for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++) - himl->nOvlIdx[nCount] = -1; - - hbmNew = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage * himl->cx, himl->cy); - SelectObject (himl->hdcImage, hbmNew); - DeleteObject (himl->hbmImage); - himl->hbmImage = hbmNew; - - if (himl->hbmMask) { - hbmNew = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy, - 1, 1, NULL); - SelectObject (himl->hdcMask, hbmNew); - DeleteObject (himl->hbmMask); - himl->hbmMask = hbmNew; - } - - return TRUE; -} - - -/************************************************************************* - * ImageList_SetImageCount [COMCTL32.@] - * - * Resizes an image list to the specified number of images. - * - * PARAMS - * himl [I] handle to image list - * iImageCount [I] number of images in the image list - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ - -BOOL WINAPI -ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount) -{ - HDC hdcBitmap; - HBITMAP hbmNewBitmap; - INT nNewCount, nCopyCount; - - TRACE("%p %d\n",himl,iImageCount); - - if (!is_valid(himl)) - return FALSE; - if (himl->cCurImage >= iImageCount) - return FALSE; - if (himl->cMaxImage > iImageCount) - { - himl->cCurImage = iImageCount; - return TRUE; - } - - nNewCount = iImageCount + himl->cGrow; - nCopyCount = min(himl->cCurImage, iImageCount); - - hdcBitmap = CreateCompatibleDC (0); - - hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount * himl->cx, himl->cy); - - if (hbmNewBitmap != 0) - { - SelectObject (hdcBitmap, hbmNewBitmap); - - /* copy images */ - BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy, - himl->hdcImage, 0, 0, SRCCOPY); -#if 0 - /* delete 'empty' image space */ - SetBkColor (hdcBitmap, RGB(255, 255, 255)); - SetTextColor (hdcBitmap, RGB(0, 0, 0)); - PatBlt (hdcBitmap, nCopyCount * himl->cx, 0, - (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS); -#endif - SelectObject (himl->hdcImage, hbmNewBitmap); - DeleteObject (himl->hbmImage); - himl->hbmImage = hbmNewBitmap; - } - else - ERR("Could not create new image bitmap !\n"); - - if (himl->hbmMask) - { - hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy, - 1, 1, NULL); - if (hbmNewBitmap != 0) - { - SelectObject (hdcBitmap, hbmNewBitmap); - - /* copy images */ - BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy, - himl->hdcMask, 0, 0, SRCCOPY); -#if 0 - /* delete 'empty' image space */ - SetBkColor (hdcBitmap, RGB(255, 255, 255)); - SetTextColor (hdcBitmap, RGB(0, 0, 0)); - PatBlt (hdcBitmap, nCopyCount * himl->cx, 0, - (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS); -#endif - SelectObject (himl->hdcMask, hbmNewBitmap); - DeleteObject (himl->hbmMask); - himl->hbmMask = hbmNewBitmap; - } - else - ERR("Could not create new mask bitmap!\n"); - } - - DeleteDC (hdcBitmap); - - /* Update max image count and current image count */ - himl->cMaxImage = nNewCount; - himl->cCurImage = iImageCount; - - return TRUE; -} - - -/************************************************************************* - * ImageList_SetOverlayImage [COMCTL32.@] - * - * Assigns an overlay mask index to an existing image in an image list. - * - * PARAMS - * himl [I] handle to image list - * iImage [I] image index - * iOverlay [I] overlay mask index - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ - -BOOL WINAPI -ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay) -{ - if (!is_valid(himl)) - return FALSE; - if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE)) - return FALSE; - if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage))) - return FALSE; - himl->nOvlIdx[iOverlay - 1] = iImage; - return TRUE; -} - - - -/* helper for ImageList_Write - write bitmap to pstm - * currently everything is written as 24 bit RGB, except masks - */ -static BOOL -_write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy) -{ - LPBITMAPFILEHEADER bmfh; - LPBITMAPINFOHEADER bmih; - LPBYTE data, lpBits, lpBitsOrg; - BITMAP bm; - INT bitCount, sizeImage, offBits, totalSize; - INT nwidth, nheight, nsizeImage, icount; - HDC xdc; - BOOL result = FALSE; - - - xdc = GetDC(0); - GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm); - - /* XXX is this always correct? */ - icount = bm.bmWidth / cx; - nwidth = cx; - nheight = cy * icount; - - bitCount = bm.bmBitsPixel == 1 ? 1 : 24; - sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight; - nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight; - - totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); - if(bitCount != 24) - totalSize += (1 << bitCount) * sizeof(RGBQUAD); - offBits = totalSize; - totalSize += nsizeImage; - - data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize); - bmfh = (LPBITMAPFILEHEADER)data; - bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER)); - lpBits = data + offBits; - - /* setup BITMAPFILEHEADER */ - bmfh->bfType = (('M' << 8) | 'B'); - bmfh->bfSize = 0; - bmfh->bfReserved1 = 0; - bmfh->bfReserved2 = 0; - bmfh->bfOffBits = offBits; - - /* setup BITMAPINFOHEADER */ - bmih->biSize = sizeof(BITMAPINFOHEADER); - bmih->biWidth = bm.bmWidth; - bmih->biHeight = bm.bmHeight; - bmih->biPlanes = 1; - bmih->biBitCount = bitCount; - bmih->biCompression = BI_RGB; - bmih->biSizeImage = sizeImage; - bmih->biXPelsPerMeter = 0; - bmih->biYPelsPerMeter = 0; - bmih->biClrUsed = 0; - bmih->biClrImportant = 0; - - lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, sizeImage); - if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg, - (BITMAPINFO *)bmih, DIB_RGB_COLORS)) - goto failed; - else { - int i; - int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3); - int nbpl = (((nwidth*bitCount+31) & ~31)>>3); - - for(i = 0; i < nheight; i++) { - int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl); - int noff = (nbpl * (nheight-1-i)); - memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl); - } - } - - bmih->biWidth = nwidth; - bmih->biHeight = nheight; - bmih->biSizeImage = nsizeImage; - - if(bitCount == 1) { - /* Hack. */ - LPBITMAPINFO inf = (LPBITMAPINFO)bmih; - inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0; - inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff; - } - - if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL))) - goto failed; - - result = TRUE; - - failed: - ReleaseDC(0, xdc); - LocalFree((HLOCAL)lpBitsOrg); - LocalFree((HLOCAL)data); - - return result; -} - - -/************************************************************************* - * ImageList_Write [COMCTL32.@] - * - * Writes an image list to a stream. - * - * PARAMS - * himl [I] handle to image list - * pstm [O] Pointer to a stream. - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * BUGS - * probably. - */ - -BOOL WINAPI -ImageList_Write (HIMAGELIST himl, LPSTREAM pstm) -{ - ILHEAD ilHead; - int i; - - if (!is_valid(himl)) - return FALSE; - - ilHead.usMagic = (('L' << 8) | 'I'); - ilHead.usVersion = 0x101; - ilHead.cCurImage = himl->cCurImage; - ilHead.cMaxImage = himl->cMaxImage; - ilHead.cGrow = himl->cGrow; - ilHead.cx = himl->cx; - ilHead.cy = himl->cy; - ilHead.bkcolor = himl->clrBk; - ilHead.flags = himl->flags; - for(i = 0; i < 4; i++) { - ilHead.ovls[i] = himl->nOvlIdx[i]; - } - - if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL))) - return FALSE; - - /* write the bitmap */ - if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy)) - return FALSE; - - /* write the mask if we have one */ - if(himl->flags & ILC_MASK) { - if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy)) - return FALSE; - } - - return TRUE; -} - - -static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT width, UINT height) -{ - HBITMAP hbmNewBitmap; - UINT ilc = (himl->flags & 0xFE); - - if ((ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32) || ilc == ILC_COLOR) - { - VOID* bits; - BITMAPINFO *bmi; - - TRACE("Creating DIBSection: %d Bits per Pixel\n", himl->uBitsPixel); - - if (himl->uBitsPixel <= ILC_COLOR8) - { - LPPALETTEENTRY pal; - ULONG i, colors; - BYTE temp; - - colors = 1 << himl->uBitsPixel; - bmi = Alloc(sizeof(BITMAPINFOHEADER) + - sizeof(PALETTEENTRY) * colors); - - pal = (LPPALETTEENTRY)bmi->bmiColors; - GetPaletteEntries(GetStockObject(DEFAULT_PALETTE), 0, colors, pal); - - /* Swap colors returned by GetPaletteEntries so we can use them for - * CreateDIBSection call. */ - for (i = 0; i < colors; i++) - { - temp = pal[i].peBlue; - bmi->bmiColors[i].rgbRed = pal[i].peRed; - bmi->bmiColors[i].rgbBlue = temp; - } - } - else - { - bmi = Alloc(sizeof(BITMAPINFOHEADER)); - } - - bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi->bmiHeader.biWidth = width; - bmi->bmiHeader.biHeight = height; - bmi->bmiHeader.biPlanes = 1; - bmi->bmiHeader.biBitCount = himl->uBitsPixel; - bmi->bmiHeader.biCompression = BI_RGB; - bmi->bmiHeader.biSizeImage = 0; - bmi->bmiHeader.biXPelsPerMeter = 0; - bmi->bmiHeader.biYPelsPerMeter = 0; - bmi->bmiHeader.biClrUsed = 0; - bmi->bmiHeader.biClrImportant = 0; - - hbmNewBitmap = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, &bits, 0, 0); - - Free (bmi); - } - else /*if (ilc == ILC_COLORDDB)*/ - { - TRACE("Creating Bitmap: %d Bits per Pixel\n", himl->uBitsPixel); - - hbmNewBitmap = CreateBitmap (width, height, 1, himl->uBitsPixel, NULL); - } - TRACE("returning %p\n", hbmNewBitmap); - return hbmNewBitmap; -} - -/************************************************************************* - * ImageList_SetColorTable [COMCTL32.@] - * - * Sets the color table of an image list. - * - * PARAMS - * himl [I] Handle to the image list. - * uStartIndex [I] The first index to set. - * cEntries [I] Number of entries to set. - * prgb [I] New color information for color table for the image list. - * - * RETURNS - * Success: Number of entries in the table that were set. - * Failure: Zero. - * - * SEE - * ImageList_Create(), SetDIBColorTable() - */ - -UINT WINAPI -ImageList_SetColorTable (HIMAGELIST himl, UINT uStartIndex, UINT cEntries, CONST RGBQUAD * prgb) -{ - return SetDIBColorTable(himl->hdcImage, uStartIndex, cEntries, prgb); -} +/* + * ImageList implementation + * + * Copyright 1998 Eric Kohl + * Copyright 2000 Jason Mawdsley + * Copyright 2001, 2004 Michael Stefaniuc + * Copyright 2001 Charles Loep for CodeWeavers + * Copyright 2002 Dimitrie O. Paun + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTE + * + * This code was audited for completeness against the documented features + * of Comctl32.dll version 6.0 on Sep. 12, 2002, by Dimitrie O. Paun. + * + * Unless otherwise noted, we believe this code to be complete, as per + * the specification mentioned above. + * If you discover missing features, or bugs, please note them below. + * + * TODO: + * - Add support for ILD_PRESERVEALPHA, ILD_SCALE, ILD_DPISCALE + * - Add support for ILS_GLOW, ILS_SHADOW, ILS_SATURATE, ILS_ALPHA + * - Thread-safe locking + */ + +#include +#include +#include + +#define COBJMACROS + +#include "winerror.h" +#include "windef.h" +#include "winbase.h" +#include "objbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "commctrl.h" +#include "comctl32.h" +#include "imagelist.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(imagelist); + + +#define MAX_OVERLAYIMAGE 15 + +/* internal image list data used for Drag & Drop operations */ +typedef struct +{ + HWND hwnd; + HIMAGELIST himl; + /* position of the drag image relative to the window */ + INT x; + INT y; + /* offset of the hotspot relative to the origin of the image */ + INT dxHotspot; + INT dyHotspot; + /* is the drag image visible */ + BOOL bShow; + /* saved background */ + HBITMAP hbmBg; +} INTERNALDRAG; + +static INTERNALDRAG InternalDrag = { 0, 0, 0, 0, 0, 0, FALSE, 0 }; + +static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT width, UINT height); + +static inline BOOL is_valid(HIMAGELIST himl) +{ + return himl && himl->magic == IMAGELIST_MAGIC; +} + + +/************************************************************************* + * IMAGELIST_InternalExpandBitmaps [Internal] + * + * Expands the bitmaps of an image list by the given number of images. + * + * PARAMS + * himl [I] handle to image list + * nImageCount [I] number of images to add + * + * RETURNS + * nothing + * + * NOTES + * This function CANNOT be used to reduce the number of images. + */ +static void +IMAGELIST_InternalExpandBitmaps (HIMAGELIST himl, INT nImageCount, INT cx, INT cy) +{ + HDC hdcBitmap; + HBITMAP hbmNewBitmap, hbmNull; + INT nNewWidth, nNewCount; + + if ((himl->cCurImage + nImageCount <= himl->cMaxImage) + && (himl->cy >= cy)) + return; + + if (cy == 0) cy = himl->cy; + nNewCount = himl->cCurImage + nImageCount + himl->cGrow; + nNewWidth = nNewCount * himl->cx; + + TRACE("Create expanded bitmaps : himl=%p x=%d y=%d count=%d\n", himl, nNewWidth, cy, nNewCount); + hdcBitmap = CreateCompatibleDC (0); + + hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewWidth, cy); + + if (hbmNewBitmap == 0) + ERR("creating new image bitmap (x=%d y=%d)!\n", nNewWidth, cy); + + if(himl->cCurImage) + { + hbmNull = SelectObject (hdcBitmap, hbmNewBitmap); + BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy, + himl->hdcImage, 0, 0, SRCCOPY); + SelectObject (hdcBitmap, hbmNull); + } + SelectObject (himl->hdcImage, hbmNewBitmap); + DeleteObject (himl->hbmImage); + himl->hbmImage = hbmNewBitmap; + + if (himl->flags & ILC_MASK) + { + hbmNewBitmap = CreateBitmap (nNewWidth, cy, 1, 1, NULL); + + if (hbmNewBitmap == 0) + ERR("creating new mask bitmap!\n"); + + if(himl->cCurImage) + { + hbmNull = SelectObject (hdcBitmap, hbmNewBitmap); + BitBlt (hdcBitmap, 0, 0, himl->cCurImage * himl->cx, cy, + himl->hdcMask, 0, 0, SRCCOPY); + SelectObject (hdcBitmap, hbmNull); + } + SelectObject (himl->hdcMask, hbmNewBitmap); + DeleteObject (himl->hbmMask); + himl->hbmMask = hbmNewBitmap; + } + + himl->cMaxImage = nNewCount; + + DeleteDC (hdcBitmap); +} + + +/************************************************************************* + * ImageList_Add [COMCTL32.@] + * + * Add an image or images to an image list. + * + * PARAMS + * himl [I] handle to image list + * hbmImage [I] handle to image bitmap + * hbmMask [I] handle to mask bitmap + * + * RETURNS + * Success: Index of the first new image. + * Failure: -1 + */ + +INT WINAPI +ImageList_Add (HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask) +{ + HDC hdcBitmap; + INT nFirstIndex, nImageCount; + INT nStartX; + BITMAP bmp; + HBITMAP hOldBitmap; + + TRACE("himl=%p hbmimage=%p hbmmask=%p\n", himl, hbmImage, hbmMask); + if (!is_valid(himl)) + return -1; + + GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp); + nImageCount = bmp.bmWidth / himl->cx; + + IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight); + + nStartX = himl->cCurImage * himl->cx; + + hdcBitmap = CreateCompatibleDC(0); + + hOldBitmap = SelectObject(hdcBitmap, hbmImage); + + /* Copy result to the imagelist + */ + BitBlt (himl->hdcImage, nStartX, 0, bmp.bmWidth, bmp.bmHeight, + hdcBitmap, 0, 0, SRCCOPY); + + if(himl->hbmMask) + { + HDC hdcTemp; + HBITMAP hOldBitmapTemp; + + hdcTemp = CreateCompatibleDC(0); + hOldBitmapTemp = SelectObject(hdcTemp, hbmMask); + + BitBlt (himl->hdcMask, + nStartX, 0, bmp.bmWidth, bmp.bmHeight, + hdcTemp, + 0, 0, + SRCCOPY); + + SelectObject(hdcTemp, hOldBitmapTemp); + DeleteDC(hdcTemp); + + /* Remove the background from the image + */ + BitBlt (himl->hdcImage, + nStartX, 0, bmp.bmWidth, bmp.bmHeight, + himl->hdcMask, + nStartX, 0, + 0x220326); /* NOTSRCAND */ + } + + SelectObject(hdcBitmap, hOldBitmap); + DeleteDC(hdcBitmap); + + nFirstIndex = himl->cCurImage; + himl->cCurImage += nImageCount; + + return nFirstIndex; +} + + +/************************************************************************* + * ImageList_AddIcon [COMCTL32.@] + * + * Adds an icon to an image list. + * + * PARAMS + * himl [I] handle to image list + * hIcon [I] handle to icon + * + * RETURNS + * Success: index of the new image + * Failure: -1 + */ +#undef ImageList_AddIcon +INT WINAPI ImageList_AddIcon (HIMAGELIST himl, HICON hIcon) +{ + return ImageList_ReplaceIcon (himl, -1, hIcon); +} + + +/************************************************************************* + * ImageList_AddMasked [COMCTL32.@] + * + * Adds an image or images to an image list and creates a mask from the + * specified bitmap using the mask color. + * + * PARAMS + * himl [I] handle to image list. + * hBitmap [I] handle to bitmap + * clrMask [I] mask color. + * + * RETURNS + * Success: Index of the first new image. + * Failure: -1 + */ + +INT WINAPI +ImageList_AddMasked (HIMAGELIST himl, HBITMAP hBitmap, COLORREF clrMask) +{ + HDC hdcMask, hdcBitmap; + INT nIndex, nImageCount, nMaskXOffset=0; + BITMAP bmp; + HBITMAP hOldBitmap; + HBITMAP hMaskBitmap=0; + COLORREF bkColor; + + TRACE("himl=%p hbitmap=%p clrmask=%lx\n", himl, hBitmap, clrMask); + if (!is_valid(himl)) + return -1; + + if (!GetObjectA (hBitmap, sizeof(BITMAP), &bmp)) + return -1; + + if (himl->cx > 0) + nImageCount = bmp.bmWidth / himl->cx; + else + nImageCount = 0; + + IMAGELIST_InternalExpandBitmaps (himl, nImageCount, bmp.bmWidth, bmp.bmHeight); + + nIndex = himl->cCurImage; + himl->cCurImage += nImageCount; + + hdcBitmap = CreateCompatibleDC(0); + + + hOldBitmap = SelectObject(hdcBitmap, hBitmap); + if(himl->hbmMask) + { + hdcMask = himl->hdcMask; + nMaskXOffset = nIndex * himl->cx; + } + else + { + /* + Create a temp Mask so we can remove the background of + the Image (Windows does this even if there is no mask) + */ + hdcMask = CreateCompatibleDC(0); + hMaskBitmap = CreateBitmap(bmp.bmWidth, bmp.bmHeight, 1, 1, NULL); + SelectObject(hdcMask, hMaskBitmap); + nMaskXOffset = 0; + } + /* create monochrome image to the mask bitmap */ + bkColor = (clrMask != CLR_DEFAULT) ? clrMask : + GetPixel (hdcBitmap, 0, 0); + SetBkColor (hdcBitmap, bkColor); + BitBlt (hdcMask, + nMaskXOffset, 0, bmp.bmWidth, bmp.bmHeight, + hdcBitmap, 0, 0, + SRCCOPY); + + SetBkColor(hdcBitmap, RGB(255,255,255)); + /*Remove the background from the image + */ + /* + WINDOWS BUG ALERT!!!!!! + The statement below should not be done in common practice + but this is how ImageList_AddMasked works in Windows. + It overwrites the original bitmap passed, this was discovered + by using the same bitmap to iterate the different styles + on windows where it failed (BUT ImageList_Add is OK) + This is here in case some apps rely on this bug + */ + BitBlt(hdcBitmap, + 0, 0, bmp.bmWidth, bmp.bmHeight, + hdcMask, + nMaskXOffset, 0, + 0x220326); /* NOTSRCAND */ + /* Copy result to the imagelist + */ + BitBlt (himl->hdcImage, + nIndex * himl->cx, 0, bmp.bmWidth, bmp.bmHeight, + hdcBitmap, + 0, 0, + SRCCOPY); + /* Clean up + */ + SelectObject(hdcBitmap, hOldBitmap); + DeleteDC(hdcBitmap); + if(!himl->hbmMask) + { + DeleteObject(hMaskBitmap); + DeleteDC(hdcMask); + } + + return nIndex; +} + + +/************************************************************************* + * ImageList_BeginDrag [COMCTL32.@] + * + * Creates a temporary image list that contains one image. It will be used + * as a drag image. + * + * PARAMS + * himlTrack [I] handle to the source image list + * iTrack [I] index of the drag image in the source image list + * dxHotspot [I] X position of the hot spot of the drag image + * dyHotspot [I] Y position of the hot spot of the drag image + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ + +BOOL WINAPI +ImageList_BeginDrag (HIMAGELIST himlTrack, INT iTrack, + INT dxHotspot, INT dyHotspot) +{ + INT cx, cy; + + TRACE("(himlTrack=%p iTrack=%d dx=%d dy=%d)\n", himlTrack, iTrack, + dxHotspot, dyHotspot); + + if (!is_valid(himlTrack)) + return FALSE; + + if (InternalDrag.himl) + ImageList_EndDrag (); + + cx = himlTrack->cx; + cy = himlTrack->cy; + + InternalDrag.himl = ImageList_Create (cx, cy, himlTrack->flags, 1, 1); + if (InternalDrag.himl == NULL) { + WARN("Error creating drag image list!\n"); + return FALSE; + } + + InternalDrag.dxHotspot = dxHotspot; + InternalDrag.dyHotspot = dyHotspot; + + /* copy image */ + BitBlt (InternalDrag.himl->hdcImage, 0, 0, cx, cy, himlTrack->hdcImage, iTrack * cx, 0, SRCCOPY); + + /* copy mask */ + BitBlt (InternalDrag.himl->hdcMask, 0, 0, cx, cy, himlTrack->hdcMask, iTrack * cx, 0, SRCCOPY); + + InternalDrag.himl->cCurImage = 1; + + return TRUE; +} + + +/************************************************************************* + * ImageList_Copy [COMCTL32.@] + * + * Copies an image of the source image list to an image of the + * destination image list. Images can be copied or swapped. + * + * PARAMS + * himlDst [I] handle to the destination image list + * iDst [I] destination image index. + * himlSrc [I] handle to the source image list + * iSrc [I] source image index + * uFlags [I] flags for the copy operation + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * Copying from one image list to another is possible. The original + * implementation just copies or swaps within one image list. + * Could this feature become a bug??? ;-) + */ + +BOOL WINAPI +ImageList_Copy (HIMAGELIST himlDst, INT iDst, HIMAGELIST himlSrc, + INT iSrc, UINT uFlags) +{ + TRACE("himlDst=%p iDst=%d himlSrc=%p iSrc=%d\n", himlDst, iDst, himlSrc, iSrc); + + if (!is_valid(himlSrc) || !is_valid(himlDst)) + return FALSE; + if ((iDst < 0) || (iDst >= himlDst->cCurImage)) + return FALSE; + if ((iSrc < 0) || (iSrc >= himlSrc->cCurImage)) + return FALSE; + + if (uFlags & ILCF_SWAP) { + /* swap */ + HDC hdcBmp; + HBITMAP hbmTempImage, hbmTempMask; + + hdcBmp = CreateCompatibleDC (0); + + /* create temporary bitmaps */ + hbmTempImage = CreateBitmap (himlSrc->cx, himlSrc->cy, 1, + himlSrc->uBitsPixel, NULL); + hbmTempMask = CreateBitmap (himlSrc->cx, himlSrc->cy, 1, + 1, NULL); + + /* copy (and stretch) destination to temporary bitmaps.(save) */ + /* image */ + SelectObject (hdcBmp, hbmTempImage); + StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy, + himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy, + SRCCOPY); + /* mask */ + SelectObject (hdcBmp, hbmTempMask); + StretchBlt (hdcBmp, 0, 0, himlSrc->cx, himlSrc->cy, + himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy, + SRCCOPY); + + /* copy (and stretch) source to destination */ + /* image */ + StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy, + himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy, + SRCCOPY); + /* mask */ + StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy, + himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy, + SRCCOPY); + + /* copy (without stretching) temporary bitmaps to source (restore) */ + /* mask */ + BitBlt (himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy, + hdcBmp, 0, 0, SRCCOPY); + + /* image */ + BitBlt (himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy, + hdcBmp, 0, 0, SRCCOPY); + /* delete temporary bitmaps */ + DeleteObject (hbmTempMask); + DeleteObject (hbmTempImage); + DeleteDC(hdcBmp); + } + else { + /* copy image */ + StretchBlt (himlDst->hdcImage, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy, + himlSrc->hdcImage, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy, + SRCCOPY); + + /* copy mask */ + StretchBlt (himlDst->hdcMask, iDst * himlDst->cx, 0, himlDst->cx, himlDst->cy, + himlSrc->hdcMask, iSrc * himlSrc->cx, 0, himlSrc->cx, himlSrc->cy, + SRCCOPY); + } + + return TRUE; +} + + +/************************************************************************* + * ImageList_Create [COMCTL32.@] + * + * Creates a new image list. + * + * PARAMS + * cx [I] image height + * cy [I] image width + * flags [I] creation flags + * cInitial [I] initial number of images in the image list + * cGrow [I] number of images by which image list grows + * + * RETURNS + * Success: Handle to the created image list + * Failure: NULL + */ +HIMAGELIST WINAPI +ImageList_Create (INT cx, INT cy, UINT flags, + INT cInitial, INT cGrow) +{ + HIMAGELIST himl; + INT nCount; + HBITMAP hbmTemp; + UINT ilc = (flags & 0xFE); + static const WORD aBitBlend25[] = + {0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00}; + + static const WORD aBitBlend50[] = + {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA}; + + TRACE("(%d %d 0x%x %d %d)\n", cx, cy, flags, cInitial, cGrow); + + himl = (HIMAGELIST)Alloc (sizeof(struct _IMAGELIST)); + if (!himl) + return NULL; + + cGrow = (cGrow < 4) ? 4 : (cGrow + 3) & ~3; + + himl->magic = IMAGELIST_MAGIC; + himl->cx = cx; + himl->cy = cy; + himl->flags = flags; + himl->cMaxImage = cInitial + cGrow; + himl->cInitial = cInitial; + himl->cGrow = cGrow; + himl->clrFg = CLR_DEFAULT; + himl->clrBk = CLR_NONE; + + /* initialize overlay mask indices */ + for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++) + himl->nOvlIdx[nCount] = -1; + + /* Create Image & Mask DCs */ + himl->hdcImage = CreateCompatibleDC (0); + if (!himl->hdcImage) + goto cleanup; + if (himl->flags & ILC_MASK){ + himl->hdcMask = CreateCompatibleDC(0); + if (!himl->hdcMask) + goto cleanup; + } + + /* Default to ILC_COLOR4 if none of the ILC_COLOR* flags are specified */ + if (ilc == ILC_COLOR) + ilc = ILC_COLOR4; + + if (ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32) + himl->uBitsPixel = ilc; + else + himl->uBitsPixel = (UINT)GetDeviceCaps (himl->hdcImage, BITSPIXEL); + + if (himl->cMaxImage > 0) { + himl->hbmImage = ImageList_CreateImage(himl->hdcImage, himl, cx * himl->cMaxImage, cy); + SelectObject(himl->hdcImage, himl->hbmImage); + } else + himl->hbmImage = 0; + + if ((himl->cMaxImage > 0) && (himl->flags & ILC_MASK)) { + himl->hbmMask = + CreateBitmap (himl->cx * himl->cMaxImage, himl->cy, + 1, 1, NULL); + if (himl->hbmMask == 0) { + ERR("Error creating mask bitmap!\n"); + goto cleanup; + } + SelectObject(himl->hdcMask, himl->hbmMask); + } + else + himl->hbmMask = 0; + + /* create blending brushes */ + hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend25); + himl->hbrBlend25 = CreatePatternBrush (hbmTemp); + DeleteObject (hbmTemp); + + hbmTemp = CreateBitmap (8, 8, 1, 1, &aBitBlend50); + himl->hbrBlend50 = CreatePatternBrush (hbmTemp); + DeleteObject (hbmTemp); + + TRACE("created imagelist %p\n", himl); + return himl; + +cleanup: + if (himl) ImageList_Destroy(himl); + return NULL; +} + + +/************************************************************************* + * ImageList_Destroy [COMCTL32.@] + * + * Destroys an image list. + * + * PARAMS + * himl [I] handle to image list + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ + +BOOL WINAPI +ImageList_Destroy (HIMAGELIST himl) +{ + if (!is_valid(himl)) + return FALSE; + + /* delete image bitmaps */ + if (himl->hbmImage) + DeleteObject (himl->hbmImage); + if (himl->hbmMask) + DeleteObject (himl->hbmMask); + + /* delete image & mask DCs */ + if (himl->hdcImage) + DeleteDC(himl->hdcImage); + if (himl->hdcMask) + DeleteDC(himl->hdcMask); + + /* delete blending brushes */ + if (himl->hbrBlend25) + DeleteObject (himl->hbrBlend25); + if (himl->hbrBlend50) + DeleteObject (himl->hbrBlend50); + + ZeroMemory(himl, sizeof(*himl)); + Free (himl); + + return TRUE; +} + + +/************************************************************************* + * ImageList_DragEnter [COMCTL32.@] + * + * Locks window update and displays the drag image at the given position. + * + * PARAMS + * hwndLock [I] handle of the window that owns the drag image. + * x [I] X position of the drag image. + * y [I] Y position of the drag image. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * The position of the drag image is relative to the window, not + * the client area. + */ + +BOOL WINAPI +ImageList_DragEnter (HWND hwndLock, INT x, INT y) +{ + TRACE("(hwnd=%p x=%d y=%d)\n", hwndLock, x, y); + + if (!is_valid(InternalDrag.himl)) + return FALSE; + + if (hwndLock) + InternalDrag.hwnd = hwndLock; + else + InternalDrag.hwnd = GetDesktopWindow (); + + InternalDrag.x = x; + InternalDrag.y = y; + + /* draw the drag image and save the background */ + if (!ImageList_DragShowNolock(TRUE)) { + return FALSE; + } + + return TRUE; +} + + +/************************************************************************* + * ImageList_DragLeave [COMCTL32.@] + * + * Unlocks window update and hides the drag image. + * + * PARAMS + * hwndLock [I] handle of the window that owns the drag image. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ + +BOOL WINAPI +ImageList_DragLeave (HWND hwndLock) +{ + /* As we don't save drag info in the window this can lead to problems if + an app does not supply the same window as DragEnter */ + /* if (hwndLock) + InternalDrag.hwnd = hwndLock; + else + InternalDrag.hwnd = GetDesktopWindow (); */ + if(!hwndLock) + hwndLock = GetDesktopWindow(); + if(InternalDrag.hwnd != hwndLock) + FIXME("DragLeave hWnd != DragEnter hWnd\n"); + + ImageList_DragShowNolock (FALSE); + + return TRUE; +} + + +/************************************************************************* + * ImageList_InternalDragDraw [Internal] + * + * Draws the drag image. + * + * PARAMS + * hdc [I] device context to draw into. + * x [I] X position of the drag image. + * y [I] Y position of the drag image. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * The position of the drag image is relative to the window, not + * the client area. + * + */ + +static inline void +ImageList_InternalDragDraw (HDC hdc, INT x, INT y) +{ + IMAGELISTDRAWPARAMS imldp; + + ZeroMemory (&imldp, sizeof(imldp)); + imldp.cbSize = sizeof(imldp); + imldp.himl = InternalDrag.himl; + imldp.i = 0; + imldp.hdcDst = hdc, + imldp.x = x; + imldp.y = y; + imldp.rgbBk = CLR_DEFAULT; + imldp.rgbFg = CLR_DEFAULT; + imldp.fStyle = ILD_NORMAL; + imldp.fState = ILS_ALPHA; + imldp.Frame = 128; + + /* FIXME: instead of using the alpha blending, we should + * create a 50% mask, and draw it semitransparantly that way */ + ImageList_DrawIndirect (&imldp); +} + +/************************************************************************* + * ImageList_DragMove [COMCTL32.@] + * + * Moves the drag image. + * + * PARAMS + * x [I] X position of the drag image. + * y [I] Y position of the drag image. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * The position of the drag image is relative to the window, not + * the client area. + * + * BUGS + * The drag image should be drawn semitransparent. + */ + +BOOL WINAPI +ImageList_DragMove (INT x, INT y) +{ + TRACE("(x=%d y=%d)\n", x, y); + + if (!is_valid(InternalDrag.himl)) + return FALSE; + + /* draw/update the drag image */ + if (InternalDrag.bShow) { + HDC hdcDrag; + HDC hdcOffScreen; + HDC hdcBg; + HBITMAP hbmOffScreen; + INT origNewX, origNewY; + INT origOldX, origOldY; + INT origRegX, origRegY; + INT sizeRegX, sizeRegY; + + + /* calculate the update region */ + origNewX = x - InternalDrag.dxHotspot; + origNewY = y - InternalDrag.dyHotspot; + origOldX = InternalDrag.x - InternalDrag.dxHotspot; + origOldY = InternalDrag.y - InternalDrag.dyHotspot; + origRegX = min(origNewX, origOldX); + origRegY = min(origNewY, origOldY); + sizeRegX = InternalDrag.himl->cx + abs(x - InternalDrag.x); + sizeRegY = InternalDrag.himl->cy + abs(y - InternalDrag.y); + + hdcDrag = GetDCEx(InternalDrag.hwnd, 0, + DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE); + hdcOffScreen = CreateCompatibleDC(hdcDrag); + hdcBg = CreateCompatibleDC(hdcDrag); + + hbmOffScreen = CreateCompatibleBitmap(hdcDrag, sizeRegX, sizeRegY); + SelectObject(hdcOffScreen, hbmOffScreen); + SelectObject(hdcBg, InternalDrag.hbmBg); + + /* get the actual background of the update region */ + BitBlt(hdcOffScreen, 0, 0, sizeRegX, sizeRegY, hdcDrag, + origRegX, origRegY, SRCCOPY); + /* erase the old image */ + BitBlt(hdcOffScreen, origOldX - origRegX, origOldY - origRegY, + InternalDrag.himl->cx, InternalDrag.himl->cy, hdcBg, 0, 0, + SRCCOPY); + /* save the background */ + BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy, + hdcOffScreen, origNewX - origRegX, origNewY - origRegY, SRCCOPY); + /* draw the image */ + ImageList_InternalDragDraw(hdcOffScreen, origNewX - origRegX, + origNewY - origRegY); + /* draw the update region to the screen */ + BitBlt(hdcDrag, origRegX, origRegY, sizeRegX, sizeRegY, + hdcOffScreen, 0, 0, SRCCOPY); + + DeleteDC(hdcBg); + DeleteDC(hdcOffScreen); + DeleteObject(hbmOffScreen); + ReleaseDC(InternalDrag.hwnd, hdcDrag); + } + + /* update the image position */ + InternalDrag.x = x; + InternalDrag.y = y; + + return TRUE; +} + + +/************************************************************************* + * ImageList_DragShowNolock [COMCTL32.@] + * + * Shows or hides the drag image. + * + * PARAMS + * bShow [I] TRUE shows the drag image, FALSE hides it. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * BUGS + * The drag image should be drawn semitransparent. + */ + +BOOL WINAPI +ImageList_DragShowNolock (BOOL bShow) +{ + HDC hdcDrag; + HDC hdcBg; + INT x, y; + + if (!is_valid(InternalDrag.himl)) + return FALSE; + + TRACE("bShow=0x%X!\n", bShow); + + /* DragImage is already visible/hidden */ + if ((InternalDrag.bShow && bShow) || (!InternalDrag.bShow && !bShow)) { + return FALSE; + } + + /* position of the origin of the DragImage */ + x = InternalDrag.x - InternalDrag.dxHotspot; + y = InternalDrag.y - InternalDrag.dyHotspot; + + hdcDrag = GetDCEx (InternalDrag.hwnd, 0, + DCX_WINDOW | DCX_CACHE | DCX_LOCKWINDOWUPDATE); + if (!hdcDrag) { + return FALSE; + } + + hdcBg = CreateCompatibleDC(hdcDrag); + if (!InternalDrag.hbmBg) { + InternalDrag.hbmBg = CreateCompatibleBitmap(hdcDrag, + InternalDrag.himl->cx, InternalDrag.himl->cy); + } + SelectObject(hdcBg, InternalDrag.hbmBg); + + if (bShow) { + /* save the background */ + BitBlt(hdcBg, 0, 0, InternalDrag.himl->cx, InternalDrag.himl->cy, + hdcDrag, x, y, SRCCOPY); + /* show the image */ + ImageList_InternalDragDraw(hdcDrag, x, y); + } else { + /* hide the image */ + BitBlt(hdcDrag, x, y, InternalDrag.himl->cx, InternalDrag.himl->cy, + hdcBg, 0, 0, SRCCOPY); + } + + InternalDrag.bShow = !InternalDrag.bShow; + + DeleteDC(hdcBg); + ReleaseDC (InternalDrag.hwnd, hdcDrag); + return TRUE; +} + + +/************************************************************************* + * ImageList_Draw [COMCTL32.@] + * + * Draws an image. + * + * PARAMS + * himl [I] handle to image list + * i [I] image index + * hdc [I] handle to device context + * x [I] x position + * y [I] y position + * fStyle [I] drawing flags + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * SEE + * ImageList_DrawEx. + */ + +BOOL WINAPI +ImageList_Draw (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, UINT fStyle) +{ + return ImageList_DrawEx (himl, i, hdc, x, y, 0, 0, + CLR_DEFAULT, CLR_DEFAULT, fStyle); +} + + +/************************************************************************* + * ImageList_DrawEx [COMCTL32.@] + * + * Draws an image and allows to use extended drawing features. + * + * PARAMS + * himl [I] handle to image list + * i [I] image index + * hdc [I] handle to device context + * x [I] X position + * y [I] Y position + * dx [I] X offset + * dy [I] Y offset + * rgbBk [I] background color + * rgbFg [I] foreground color + * fStyle [I] drawing flags + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * Calls ImageList_DrawIndirect. + * + * SEE + * ImageList_DrawIndirect. + */ + +BOOL WINAPI +ImageList_DrawEx (HIMAGELIST himl, INT i, HDC hdc, INT x, INT y, + INT dx, INT dy, COLORREF rgbBk, COLORREF rgbFg, + UINT fStyle) +{ + IMAGELISTDRAWPARAMS imldp; + + ZeroMemory (&imldp, sizeof(imldp)); + imldp.cbSize = sizeof(imldp); + imldp.himl = himl; + imldp.i = i; + imldp.hdcDst = hdc, + imldp.x = x; + imldp.y = y; + imldp.cx = dx; + imldp.cy = dy; + imldp.rgbBk = rgbBk; + imldp.rgbFg = rgbFg; + imldp.fStyle = fStyle; + + return ImageList_DrawIndirect (&imldp); +} + + +/************************************************************************* + * ImageList_DrawIndirect [COMCTL32.@] + * + * Draws an image using various parameters specified in pimldp. + * + * PARAMS + * pimldp [I] pointer to IMAGELISTDRAWPARAMS structure. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ + +BOOL WINAPI +ImageList_DrawIndirect (IMAGELISTDRAWPARAMS *pimldp) +{ + INT cx, cy, lx, ly, nOvlIdx; + DWORD fState, dwRop; + UINT fStyle; + COLORREF oldImageBk, oldImageFg; + HDC hImageDC, hImageListDC, hMaskListDC; + HBITMAP hImageBmp, hOldImageBmp, hBlendMaskBmp; + BOOL bIsTransparent, bBlend, bResult = FALSE, bMask; + HIMAGELIST himl; + + if (!pimldp || !(himl = pimldp->himl)) return FALSE; + if (!is_valid(himl)) return FALSE; + if ((pimldp->i < 0) || (pimldp->i >= himl->cCurImage)) return FALSE; + + lx = himl->cx * pimldp->i + pimldp->xBitmap; + ly = pimldp->yBitmap; + + fState = pimldp->cbSize < sizeof(IMAGELISTDRAWPARAMS) ? ILS_NORMAL : pimldp->fState; + fStyle = pimldp->fStyle & ~ILD_OVERLAYMASK; + cx = (pimldp->cx == 0) ? himl->cx : pimldp->cx; + cy = (pimldp->cy == 0) ? himl->cy : pimldp->cy; + + bIsTransparent = (fStyle & ILD_TRANSPARENT); + if( pimldp->rgbBk == CLR_NONE ) + bIsTransparent = TRUE; + if( ( pimldp->rgbBk == CLR_DEFAULT ) && ( himl->clrBk == CLR_NONE ) ) + bIsTransparent = TRUE; + bMask = (himl->flags & ILC_MASK) && (fStyle & ILD_MASK) ; + bBlend = (fStyle & (ILD_BLEND25 | ILD_BLEND50) ) && !bMask; + + TRACE("himl(0x%lx) hbmMask(%p) iImage(%d) x(%d) y(%d) cx(%d) cy(%d)\n", + (DWORD)himl, himl->hbmMask, pimldp->i, pimldp->x, pimldp->y, cx, cy); + + /* we will use these DCs to access the images and masks in the ImageList */ + hImageListDC = himl->hdcImage; + hMaskListDC = himl->hdcMask; + + /* these will accumulate the image and mask for the image we're drawing */ + hImageDC = CreateCompatibleDC( pimldp->hdcDst ); + hImageBmp = CreateCompatibleBitmap( pimldp->hdcDst, cx, cy ); + hBlendMaskBmp = bBlend ? CreateBitmap(cx, cy, 1, 1, NULL) : 0; + + /* Create a compatible DC. */ + if (!hImageListDC || !hImageDC || !hImageBmp || + (bBlend && !hBlendMaskBmp) || (himl->hbmMask && !hMaskListDC)) + goto cleanup; + + hOldImageBmp = SelectObject(hImageDC, hImageBmp); + + /* + * To obtain a transparent look, background color should be set + * to white and foreground color to black when blting the + * monochrome mask. + */ + oldImageFg = SetTextColor( hImageDC, RGB( 0, 0, 0 ) ); + oldImageBk = SetBkColor( hImageDC, RGB( 0xff, 0xff, 0xff ) ); + + /* + * Draw the initial image + */ + if( bMask ) { + if (himl->hbmMask) { + HBRUSH hOldBrush; + hOldBrush = SelectObject (hImageDC, CreateSolidBrush (GetTextColor(pimldp->hdcDst))); + PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY ); + BitBlt(hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCPAINT); + DeleteObject (SelectObject (hImageDC, hOldBrush)); + if( bIsTransparent ) + { + BitBlt ( pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, SRCAND); + bResult = TRUE; + goto end; + } + } else { + HBRUSH hOldBrush = SelectObject (hImageDC, GetStockObject(BLACK_BRUSH)); + PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY); + SelectObject(hImageDC, hOldBrush); + } + } else { + /* blend the image with the needed solid background */ + COLORREF colour = RGB(0,0,0); + HBRUSH hOldBrush; + + if( !bIsTransparent ) + { + colour = pimldp->rgbBk; + if( colour == CLR_DEFAULT ) + colour = himl->clrBk; + if( colour == CLR_NONE ) + colour = GetBkColor(pimldp->hdcDst); + } + + hOldBrush = SelectObject (hImageDC, CreateSolidBrush (colour)); + PatBlt( hImageDC, 0, 0, cx, cy, PATCOPY ); + BitBlt( hImageDC, 0, 0, cx, cy, hMaskListDC, lx, ly, SRCAND ); + BitBlt( hImageDC, 0, 0, cx, cy, hImageListDC, lx, ly, SRCPAINT ); + DeleteObject (SelectObject (hImageDC, hOldBrush)); + } + + /* Time for blending, if required */ + if (bBlend) { + HBRUSH hBlendBrush, hOldBrush; + COLORREF clrBlend = pimldp->rgbFg; + HDC hBlendMaskDC = hImageListDC; + HBITMAP hOldBitmap; + + /* Create the blend Mask */ + hOldBitmap = SelectObject(hBlendMaskDC, hBlendMaskBmp); + hBlendBrush = fStyle & ILD_BLEND50 ? himl->hbrBlend50 : himl->hbrBlend25; + hOldBrush = (HBRUSH) SelectObject(hBlendMaskDC, hBlendBrush); + PatBlt(hBlendMaskDC, 0, 0, cx, cy, PATCOPY); + SelectObject(hBlendMaskDC, hOldBrush); + + /* Modify the blend mask if an Image Mask exist */ + if(himl->hbmMask) { + BitBlt(hBlendMaskDC, 0, 0, cx, cy, hMaskListDC, lx, ly, 0x220326); /* NOTSRCAND */ + BitBlt(hBlendMaskDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, NOTSRCCOPY); + } + + /* now apply blend to the current image given the BlendMask */ + if (clrBlend == CLR_DEFAULT) clrBlend = GetSysColor (COLOR_HIGHLIGHT); + else if (clrBlend == CLR_NONE) clrBlend = GetTextColor (pimldp->hdcDst); + hOldBrush = (HBRUSH) SelectObject (hImageDC, CreateSolidBrush(clrBlend)); + BitBlt (hImageDC, 0, 0, cx, cy, hBlendMaskDC, 0, 0, 0xB8074A); /* PSDPxax */ + DeleteObject(SelectObject(hImageDC, hOldBrush)); + SelectObject(hBlendMaskDC, hOldBitmap); + } + + /* Now do the overlay image, if any */ + nOvlIdx = (pimldp->fStyle & ILD_OVERLAYMASK) >> 8; + if ( (nOvlIdx >= 1) && (nOvlIdx <= MAX_OVERLAYIMAGE)) { + nOvlIdx = himl->nOvlIdx[nOvlIdx - 1]; + if ((nOvlIdx >= 0) && (nOvlIdx < himl->cCurImage)) { + const INT ox = himl->cx * nOvlIdx + pimldp->xBitmap; + if (himl->hbmMask && !(fStyle & ILD_IMAGE)) + BitBlt (hImageDC, 0, 0, cx, cy, hMaskListDC, ox, ly, SRCAND); + BitBlt (hImageDC, 0, 0, cx, cy, hImageListDC, ox, ly, SRCPAINT); + } + } + + if (fState & ILS_SATURATE) FIXME("ILS_SATURATE: unimplemented!\n"); + if (fState & ILS_GLOW) FIXME("ILS_GLOW: unimplemented!\n"); + if (fState & ILS_SHADOW) FIXME("ILS_SHADOW: unimplemented!\n"); + if (fState & ILS_ALPHA) FIXME("ILS_ALPHA: unimplemented!\n"); + + if (fStyle & ILD_PRESERVEALPHA) FIXME("ILD_PRESERVEALPHA: unimplemented!\n"); + if (fStyle & ILD_SCALE) FIXME("ILD_SCALE: unimplemented!\n"); + if (fStyle & ILD_DPISCALE) FIXME("ILD_DPISCALE: unimplemented!\n"); + + /* now copy the image to the screen */ + dwRop = SRCCOPY; + if (himl->hbmMask && bIsTransparent ) { + COLORREF oldDstFg = SetTextColor(pimldp->hdcDst, RGB( 0, 0, 0 ) ); + COLORREF oldDstBk = SetBkColor(pimldp->hdcDst, RGB( 0xff, 0xff, 0xff )); + BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hMaskListDC, lx, ly, SRCAND); + SetBkColor(pimldp->hdcDst, oldDstBk); + SetTextColor(pimldp->hdcDst, oldDstFg); + dwRop = SRCPAINT; + } + if (fStyle & ILD_ROP) dwRop = pimldp->dwRop; + BitBlt (pimldp->hdcDst, pimldp->x, pimldp->y, cx, cy, hImageDC, 0, 0, dwRop); + + bResult = TRUE; +end: + /* cleanup the mess */ + SetBkColor(hImageDC, oldImageBk); + SetTextColor(hImageDC, oldImageFg); + SelectObject(hImageDC, hOldImageBmp); +cleanup: + DeleteObject(hBlendMaskBmp); + DeleteObject(hImageBmp); + DeleteDC(hImageDC); + + return bResult; +} + + +/************************************************************************* + * ImageList_Duplicate [COMCTL32.@] + * + * Duplicates an image list. + * + * PARAMS + * himlSrc [I] source image list handle + * + * RETURNS + * Success: Handle of duplicated image list. + * Failure: NULL + */ + +HIMAGELIST WINAPI +ImageList_Duplicate (HIMAGELIST himlSrc) +{ + HIMAGELIST himlDst; + + if (!is_valid(himlSrc)) { + ERR("Invalid image list handle!\n"); + return NULL; + } + + himlDst = ImageList_Create (himlSrc->cx, himlSrc->cy, himlSrc->flags, + himlSrc->cInitial, himlSrc->cGrow); + + if (himlDst) + { + BitBlt (himlDst->hdcImage, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy, + himlSrc->hdcImage, 0, 0, SRCCOPY); + + if (himlDst->hbmMask) + BitBlt (himlDst->hdcMask, 0, 0, himlSrc->cCurImage * himlSrc->cx, himlSrc->cy, + himlSrc->hdcMask, 0, 0, SRCCOPY); + + himlDst->cCurImage = himlSrc->cCurImage; + himlDst->cMaxImage = himlSrc->cMaxImage; + } + return himlDst; +} + + +/************************************************************************* + * ImageList_EndDrag [COMCTL32.@] + * + * Finishes a drag operation. + * + * PARAMS + * no Parameters + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ + +VOID WINAPI +ImageList_EndDrag (void) +{ + /* cleanup the InternalDrag struct */ + InternalDrag.hwnd = 0; + ImageList_Destroy (InternalDrag.himl); + InternalDrag.himl = 0; + InternalDrag.x= 0; + InternalDrag.y= 0; + InternalDrag.dxHotspot = 0; + InternalDrag.dyHotspot = 0; + InternalDrag.bShow = FALSE; + DeleteObject(InternalDrag.hbmBg); + InternalDrag.hbmBg = 0; +} + + +/************************************************************************* + * ImageList_GetBkColor [COMCTL32.@] + * + * Returns the background color of an image list. + * + * PARAMS + * himl [I] Image list handle. + * + * RETURNS + * Success: background color + * Failure: CLR_NONE + */ + +COLORREF WINAPI +ImageList_GetBkColor (HIMAGELIST himl) +{ + return himl ? himl->clrBk : CLR_NONE; +} + + +/************************************************************************* + * ImageList_GetDragImage [COMCTL32.@] + * + * Returns the handle to the internal drag image list. + * + * PARAMS + * ppt [O] Pointer to the drag position. Can be NULL. + * pptHotspot [O] Pointer to the position of the hot spot. Can be NULL. + * + * RETURNS + * Success: Handle of the drag image list. + * Failure: NULL. + */ + +HIMAGELIST WINAPI +ImageList_GetDragImage (POINT *ppt, POINT *pptHotspot) +{ + if (is_valid(InternalDrag.himl)) { + if (ppt) { + ppt->x = InternalDrag.x; + ppt->y = InternalDrag.y; + } + if (pptHotspot) { + pptHotspot->x = InternalDrag.dxHotspot; + pptHotspot->y = InternalDrag.dyHotspot; + } + return (InternalDrag.himl); + } + + return NULL; +} + + +/************************************************************************* + * ImageList_GetFlags [COMCTL32.@] + * + * Gets the flags of the specified image list. + * + * PARAMS + * himl [I] Handle to image list + * + * RETURNS + * Image list flags. + * + * BUGS + * Stub. + */ + +DWORD WINAPI +ImageList_GetFlags(HIMAGELIST himl) +{ + FIXME("(%p):empty stub\n", himl); + return 0; +} + + +/************************************************************************* + * ImageList_GetIcon [COMCTL32.@] + * + * Creates an icon from a masked image of an image list. + * + * PARAMS + * himl [I] handle to image list + * i [I] image index + * flags [I] drawing style flags + * + * RETURNS + * Success: icon handle + * Failure: NULL + */ + +HICON WINAPI +ImageList_GetIcon (HIMAGELIST himl, INT i, UINT fStyle) +{ + ICONINFO ii; + HICON hIcon; + HBITMAP hOldDstBitmap; + HDC hdcDst; + + TRACE("%p %d %d\n", himl, i, fStyle); + if (!is_valid(himl) || (i < 0) || (i >= himl->cCurImage)) return NULL; + + ii.fIcon = TRUE; + ii.xHotspot = 0; + ii.yHotspot = 0; + + /* create colour bitmap */ + hdcDst = GetDC(0); + ii.hbmColor = CreateCompatibleBitmap(hdcDst, himl->cx, himl->cy); + ReleaseDC(0, hdcDst); + + hdcDst = CreateCompatibleDC(0); + + /* draw mask*/ + ii.hbmMask = CreateBitmap (himl->cx, himl->cy, 1, 1, NULL); + hOldDstBitmap = SelectObject (hdcDst, ii.hbmMask); + if (himl->hbmMask) { + BitBlt (hdcDst, 0, 0, himl->cx, himl->cy, + himl->hdcMask, i * himl->cx, 0, SRCCOPY); + } + else + PatBlt (hdcDst, 0, 0, himl->cx, himl->cy, BLACKNESS); + + /* draw image*/ + SelectObject (hdcDst, ii.hbmColor); + BitBlt (hdcDst, 0, 0, himl->cx, himl->cy, + himl->hdcImage, i * himl->cx, 0, SRCCOPY); + + /* + * CreateIconIndirect requires us to deselect the bitmaps from + * the DCs before calling + */ + SelectObject(hdcDst, hOldDstBitmap); + + hIcon = CreateIconIndirect (&ii); + + DeleteObject (ii.hbmMask); + DeleteObject (ii.hbmColor); + DeleteDC (hdcDst); + + return hIcon; +} + + +/************************************************************************* + * ImageList_GetIconSize [COMCTL32.@] + * + * Retrieves the size of an image in an image list. + * + * PARAMS + * himl [I] handle to image list + * cx [O] pointer to the image width. + * cy [O] pointer to the image height. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * All images in an image list have the same size. + */ + +BOOL WINAPI +ImageList_GetIconSize (HIMAGELIST himl, INT *cx, INT *cy) +{ + if (!is_valid(himl)) + return FALSE; + if ((himl->cx <= 0) || (himl->cy <= 0)) + return FALSE; + + if (cx) + *cx = himl->cx; + if (cy) + *cy = himl->cy; + + return TRUE; +} + + +/************************************************************************* + * ImageList_GetImageCount [COMCTL32.@] + * + * Returns the number of images in an image list. + * + * PARAMS + * himl [I] handle to image list + * + * RETURNS + * Success: Number of images. + * Failure: 0 + */ + +INT WINAPI +ImageList_GetImageCount (HIMAGELIST himl) +{ + if (!is_valid(himl)) + return 0; + + return himl->cCurImage; +} + + +/************************************************************************* + * ImageList_GetImageInfo [COMCTL32.@] + * + * Returns information about an image in an image list. + * + * PARAMS + * himl [I] handle to image list + * i [I] image index + * pImageInfo [O] pointer to the image information + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ + +BOOL WINAPI +ImageList_GetImageInfo (HIMAGELIST himl, INT i, IMAGEINFO *pImageInfo) +{ + if (!is_valid(himl) || (pImageInfo == NULL)) + return FALSE; + if ((i < 0) || (i >= himl->cCurImage)) + return FALSE; + + pImageInfo->hbmImage = himl->hbmImage; + pImageInfo->hbmMask = himl->hbmMask; + + pImageInfo->rcImage.top = 0; + pImageInfo->rcImage.bottom = himl->cy; + pImageInfo->rcImage.left = i * himl->cx; + pImageInfo->rcImage.right = (i+1) * himl->cx; + + return TRUE; +} + + +/************************************************************************* + * ImageList_GetImageRect [COMCTL32.@] + * + * Retrieves the rectangle of the specified image in an image list. + * + * PARAMS + * himl [I] handle to image list + * i [I] image index + * lpRect [O] pointer to the image rectangle + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * This is an UNDOCUMENTED function!!! + */ + +BOOL WINAPI +ImageList_GetImageRect (HIMAGELIST himl, INT i, LPRECT lpRect) +{ + if (!is_valid(himl) || (lpRect == NULL)) + return FALSE; + if ((i < 0) || (i >= himl->cCurImage)) + return FALSE; + + lpRect->left = i * himl->cx; + lpRect->top = 0; + lpRect->right = lpRect->left + himl->cx; + lpRect->bottom = himl->cy; + + return TRUE; +} + + +/************************************************************************* + * ImageList_LoadImage [COMCTL32.@] + * ImageList_LoadImageA [COMCTL32.@] + * + * Creates an image list from a bitmap, icon or cursor. + * + * SEE + * ImageList_LoadImageW () + */ + +HIMAGELIST WINAPI +ImageList_LoadImageA (HINSTANCE hi, LPCSTR lpbmp, INT cx, INT cGrow, + COLORREF clrMask, UINT uType, UINT uFlags) +{ + HIMAGELIST himl; + LPWSTR lpbmpW; + DWORD len; + + if (!HIWORD(lpbmp)) + return ImageList_LoadImageW(hi, (LPCWSTR)lpbmp, cx, cGrow, clrMask, + uType, uFlags); + + len = MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, NULL, 0); + lpbmpW = Alloc(len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, lpbmp, -1, lpbmpW, len); + + himl = ImageList_LoadImageW(hi, lpbmpW, cx, cGrow, clrMask, uType, uFlags); + Free (lpbmpW); + return himl; +} + + +/************************************************************************* + * ImageList_LoadImageW [COMCTL32.@] + * + * Creates an image list from a bitmap, icon or cursor. + * + * PARAMS + * hi [I] instance handle + * lpbmp [I] name or id of the image + * cx [I] width of each image + * cGrow [I] number of images to expand + * clrMask [I] mask color + * uType [I] type of image to load + * uFlags [I] loading flags + * + * RETURNS + * Success: handle to the loaded image list + * Failure: NULL + * + * SEE + * LoadImage () + */ + +HIMAGELIST WINAPI +ImageList_LoadImageW (HINSTANCE hi, LPCWSTR lpbmp, INT cx, INT cGrow, + COLORREF clrMask, UINT uType, UINT uFlags) +{ + HIMAGELIST himl = NULL; + HANDLE handle; + INT nImageCount; + + handle = LoadImageW (hi, lpbmp, uType, 0, 0, uFlags); + if (!handle) { + ERR("Error loading image!\n"); + return NULL; + } + + if (uType == IMAGE_BITMAP) { + BITMAP bmp; + GetObjectW (handle, sizeof(BITMAP), &bmp); + + /* To match windows behavior, if cx is set to zero and + the flag DI_DEFAULTSIZE is specified, cx becomes the + system metric value for icons. If the flag is not specified + the function sets the size to the height of the bitmap */ + if (cx == 0) + { + if (uFlags & DI_DEFAULTSIZE) + cx = GetSystemMetrics (SM_CXICON); + else + cx = bmp.bmHeight; + } + + nImageCount = bmp.bmWidth / cx; + + himl = ImageList_Create (cx, bmp.bmHeight, ILC_MASK | ILC_COLOR, + nImageCount, cGrow); + if (!himl) { + DeleteObject (handle); + return NULL; + } + ImageList_AddMasked (himl, (HBITMAP)handle, clrMask); + } + else if ((uType == IMAGE_ICON) || (uType == IMAGE_CURSOR)) { + ICONINFO ii; + BITMAP bmp; + + GetIconInfo (handle, &ii); + GetObjectW (ii.hbmColor, sizeof(BITMAP), (LPVOID)&bmp); + himl = ImageList_Create (bmp.bmWidth, bmp.bmHeight, + ILC_MASK | ILC_COLOR, 1, cGrow); + if (!himl) { + DeleteObject (ii.hbmColor); + DeleteObject (ii.hbmMask); + DeleteObject (handle); + return NULL; + } + ImageList_Add (himl, ii.hbmColor, ii.hbmMask); + DeleteObject (ii.hbmColor); + DeleteObject (ii.hbmMask); + } + + DeleteObject (handle); + + return himl; +} + + +/************************************************************************* + * ImageList_Merge [COMCTL32.@] + * + * Create an image list containing a merged image from two image lists. + * + * PARAMS + * himl1 [I] handle to first image list + * i1 [I] first image index + * himl2 [I] handle to second image list + * i2 [I] second image index + * dx [I] X offset of the second image relative to the first. + * dy [I] Y offset of the second image relative to the first. + * + * RETURNS + * Success: The newly created image list. It contains a single image + * consisting of the second image merged with the first. + * Failure: NULL, if either himl1 or himl2 are invalid. + * + * NOTES + * - The returned image list should be deleted by the caller using + * ImageList_Destroy() when it is no longer required. + * - If either i1 or i2 are not valid image indices they will be treated + * as a blank image. + */ +HIMAGELIST WINAPI +ImageList_Merge (HIMAGELIST himl1, INT i1, HIMAGELIST himl2, INT i2, + INT dx, INT dy) +{ + HIMAGELIST himlDst = NULL; + INT cxDst, cyDst; + INT xOff1, yOff1, xOff2, yOff2; + INT nX1, nX2; + + TRACE("(himl1=%p i1=%d himl2=%p i2=%d dx=%d dy=%d)\n", himl1, i1, himl2, + i2, dx, dy); + + if (!is_valid(himl1) || !is_valid(himl2)) + return NULL; + + if (dx > 0) { + cxDst = max (himl1->cx, dx + himl2->cx); + xOff1 = 0; + xOff2 = dx; + } + else if (dx < 0) { + cxDst = max (himl2->cx, himl1->cx - dx); + xOff1 = -dx; + xOff2 = 0; + } + else { + cxDst = max (himl1->cx, himl2->cx); + xOff1 = 0; + xOff2 = 0; + } + + if (dy > 0) { + cyDst = max (himl1->cy, dy + himl2->cy); + yOff1 = 0; + yOff2 = dy; + } + else if (dy < 0) { + cyDst = max (himl2->cy, himl1->cy - dy); + yOff1 = -dy; + yOff2 = 0; + } + else { + cyDst = max (himl1->cy, himl2->cy); + yOff1 = 0; + yOff2 = 0; + } + + himlDst = ImageList_Create (cxDst, cyDst, ILC_MASK | ILC_COLOR, 1, 1); + + if (himlDst) + { + nX1 = i1 * himl1->cx; + nX2 = i2 * himl2->cx; + + /* copy image */ + BitBlt (himlDst->hdcImage, 0, 0, cxDst, cyDst, himl1->hdcImage, 0, 0, BLACKNESS); + if (i1 >= 0 && i1 < himl1->cCurImage) + BitBlt (himlDst->hdcImage, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcImage, nX1, 0, SRCCOPY); + if (i2 >= 0 && i2 < himl2->cCurImage) + { + BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask , nX2, 0, SRCAND); + BitBlt (himlDst->hdcImage, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcImage, nX2, 0, SRCPAINT); + } + + /* copy mask */ + BitBlt (himlDst->hdcMask, 0, 0, cxDst, cyDst, himl1->hdcMask, 0, 0, WHITENESS); + if (i1 >= 0 && i1 < himl1->cCurImage) + BitBlt (himlDst->hdcMask, xOff1, yOff1, himl1->cx, himl1->cy, himl1->hdcMask, nX1, 0, SRCCOPY); + if (i2 >= 0 && i2 < himl2->cCurImage) + BitBlt (himlDst->hdcMask, xOff2, yOff2, himl2->cx, himl2->cy, himl2->hdcMask, nX2, 0, SRCAND); + + himlDst->cCurImage = 1; + } + + return himlDst; +} + + +/* helper for _read_bitmap currently unused */ +#if 0 +static int may_use_dibsection(HDC hdc) { + int bitspixel = GetDeviceCaps(hdc,BITSPIXEL)*GetDeviceCaps(hdc,PLANES); + if (bitspixel>8) + return TRUE; + if (bitspixel<=4) + return FALSE; + return GetDeviceCaps(hdc,CAPS1) & C1_DIBENGINE; +} +#endif + +/* helper for ImageList_Read, see comments below */ +static HBITMAP _read_bitmap(LPSTREAM pstm,int ilcFlag,int cx,int cy) { + HDC xdc = 0, hBitmapDC =0; + BITMAPFILEHEADER bmfh; + BITMAPINFOHEADER bmih; + int bitsperpixel,palspace,longsperline,width,height; + LPBITMAPINFOHEADER bmihc = NULL; + int result = 0; + HBITMAP hbitmap = 0, hDIB = 0; + LPBYTE bits = NULL; + + if (!SUCCEEDED(IStream_Read ( pstm, &bmfh, sizeof(bmfh), NULL)) || + (bmfh.bfType != (('M'<<8)|'B')) || + !SUCCEEDED(IStream_Read ( pstm, &bmih, sizeof(bmih), NULL)) || + (bmih.biSize != sizeof(bmih)) + ) + return 0; + + bitsperpixel = bmih.biPlanes * bmih.biBitCount; + if (bitsperpixel<=8) + palspace = (1<>5; + bmihc->biSizeImage = (longsperline*height)<<2; + + /* read the palette right after the end of the bitmapinfoheader */ + if (palspace) + if (!SUCCEEDED(IStream_Read ( pstm, bmihc+1, palspace, NULL))) + goto ret1; + + xdc = GetDC(0); +#if 0 /* Magic for NxM -> 1x(N*M) not implemented for DIB Sections */ + if ((bitsperpixel>1) && + ((ilcFlag!=ILC_COLORDDB) && (!ilcFlag || may_use_dibsection(xdc))) + ) { + hbitmap = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0); + if (!hbitmap) + goto ret1; + if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL))) + goto ret1; + result = 1; + } else +#endif + { + int i,nwidth,nheight,nRows; + + nwidth = width*(height/cy); + nheight = cy; + nRows = (height/cy); + + if (bitsperpixel==1) + hbitmap = CreateBitmap(nwidth,nheight,1,1,NULL); + else + hbitmap = CreateCompatibleBitmap(xdc,nwidth,nheight); + + hDIB = CreateDIBSection(xdc,(BITMAPINFO*)bmihc,0,(LPVOID*)&bits,0,0); + if (!hDIB) + goto ret1; + if (!SUCCEEDED(IStream_Read( pstm, bits, bmihc->biSizeImage, NULL))) + goto ret1; + + hBitmapDC = CreateCompatibleDC(0); + SelectObject(hBitmapDC, hbitmap); + + /* Copy the NxM bitmap into a 1x(N*M) bitmap we need, linewise */ + /* Do not forget that windows bitmaps are bottom->top */ + TRACE("nRows=%d\n", nRows); + for (i=0; i < nRows; i++){ + StretchDIBits(hBitmapDC, width*i, 0, width, cy, 0, cy*(nRows-1-i), width, cy, bits, + (BITMAPINFO*)bmihc, DIB_RGB_COLORS, SRCCOPY); + } + + result = 1; + } +ret1: + if (xdc) ReleaseDC(0,xdc); + if (bmihc) LocalFree((HLOCAL)bmihc); + if (hDIB) DeleteObject(hDIB); + if (hBitmapDC) DeleteDC(hBitmapDC); + if (!result) { + if (hbitmap) { + DeleteObject(hbitmap); + hbitmap = 0; + } + } + return hbitmap; +} + +/************************************************************************* + * ImageList_Read [COMCTL32.@] + * + * Reads an image list from a stream. + * + * PARAMS + * pstm [I] pointer to a stream + * + * RETURNS + * Success: handle to image list + * Failure: NULL + * + * The format is like this: + * ILHEAD ilheadstruct; + * + * for the color image part: + * BITMAPFILEHEADER bmfh; + * BITMAPINFOHEADER bmih; + * only if it has a palette: + * RGBQUAD rgbs[nr_of_paletted_colors]; + * + * BYTE colorbits[imagesize]; + * + * the following only if the ILC_MASK bit is set in ILHEAD.ilFlags: + * BITMAPFILEHEADER bmfh_mask; + * BITMAPINFOHEADER bmih_mask; + * only if it has a palette (it usually does not): + * RGBQUAD rgbs[nr_of_paletted_colors]; + * + * BYTE maskbits[imagesize]; + * + * CAVEAT: Those images are within a NxM bitmap, not the 1xN we expect. + * _read_bitmap needs to convert them. + */ +HIMAGELIST WINAPI ImageList_Read (LPSTREAM pstm) +{ + ILHEAD ilHead; + HIMAGELIST himl; + HBITMAP hbmColor=0,hbmMask=0; + int i; + + if (!SUCCEEDED(IStream_Read (pstm, &ilHead, sizeof(ILHEAD), NULL))) + return NULL; + if (ilHead.usMagic != (('L' << 8) | 'I')) + return NULL; + if (ilHead.usVersion != 0x101) /* probably version? */ + return NULL; + +#if 0 + FIXME(" ilHead.cCurImage = %d\n",ilHead.cCurImage); + FIXME(" ilHead.cMaxImage = %d\n",ilHead.cMaxImage); + FIXME(" ilHead.cGrow = %d\n",ilHead.cGrow); + FIXME(" ilHead.cx = %d\n",ilHead.cx); + FIXME(" ilHead.cy = %d\n",ilHead.cy); + FIXME(" ilHead.flags = %x\n",ilHead.flags); + FIXME(" ilHead.ovls[0] = %d\n",ilHead.ovls[0]); + FIXME(" ilHead.ovls[1] = %d\n",ilHead.ovls[1]); + FIXME(" ilHead.ovls[2] = %d\n",ilHead.ovls[2]); + FIXME(" ilHead.ovls[3] = %d\n",ilHead.ovls[3]); +#endif + + hbmColor = _read_bitmap(pstm,ilHead.flags & ~ILC_MASK,ilHead.cx,ilHead.cy); + if (!hbmColor) + return NULL; + if (ilHead.flags & ILC_MASK) { + hbmMask = _read_bitmap(pstm,0,ilHead.cx,ilHead.cy); + if (!hbmMask) { + DeleteObject(hbmColor); + return NULL; + } + } + + himl = ImageList_Create ( + ilHead.cx, + ilHead.cy, + ilHead.flags, + 1, /* initial */ + ilHead.cGrow + ); + if (!himl) { + DeleteObject(hbmColor); + DeleteObject(hbmMask); + return NULL; + } + SelectObject(himl->hdcImage, hbmColor); + DeleteObject(himl->hbmImage); + himl->hbmImage = hbmColor; + if (hbmMask){ + SelectObject(himl->hdcMask, hbmMask); + DeleteObject(himl->hbmMask); + himl->hbmMask = hbmMask; + } + himl->cCurImage = ilHead.cCurImage; + himl->cMaxImage = ilHead.cMaxImage; + + ImageList_SetBkColor(himl,ilHead.bkcolor); + for (i=0;i<4;i++) + ImageList_SetOverlayImage(himl,ilHead.ovls[i],i+1); + return himl; +} + + +/************************************************************************* + * ImageList_Remove [COMCTL32.@] + * + * Removes an image from an image list + * + * PARAMS + * himl [I] image list handle + * i [I] image index + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ + +BOOL WINAPI +ImageList_Remove (HIMAGELIST himl, INT i) +{ + HBITMAP hbmNewImage, hbmNewMask; + HDC hdcBmp; + INT cxNew, nCount; + + TRACE("(himl=%p i=%d)\n", himl, i); + + if (!is_valid(himl)) { + ERR("Invalid image list handle!\n"); + return FALSE; + } + + if ((i < -1) || (i >= himl->cCurImage)) { + TRACE("index out of range! %d\n", i); + return FALSE; + } + + if (i == -1) { + /* remove all */ + if (himl->cCurImage == 0) { + /* remove all on empty ImageList is allowed */ + TRACE("remove all on empty ImageList!\n"); + return TRUE; + } + + himl->cMaxImage = himl->cInitial + himl->cGrow; + himl->cCurImage = 0; + for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++) + himl->nOvlIdx[nCount] = -1; + + hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage * himl->cx, himl->cy); + SelectObject (himl->hdcImage, hbmNewImage); + DeleteObject (himl->hbmImage); + himl->hbmImage = hbmNewImage; + + if (himl->hbmMask) { + hbmNewMask = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy, + 1, 1, NULL); + SelectObject (himl->hdcMask, hbmNewMask); + DeleteObject (himl->hbmMask); + himl->hbmMask = hbmNewMask; + } + } + else { + /* delete one image */ + TRACE("Remove single image! %d\n", i); + + /* create new bitmap(s) */ + nCount = (himl->cCurImage + himl->cGrow - 1); + cxNew = nCount * himl->cx; + + TRACE(" - Number of images: %d / %d (Old/New)\n", + himl->cCurImage, himl->cCurImage - 1); + TRACE(" - Max. number of images: %d / %d (Old/New)\n", + himl->cMaxImage, himl->cCurImage + himl->cGrow - 1); + + hbmNewImage = ImageList_CreateImage(himl->hdcImage, himl, cxNew, himl->cy); + + if (himl->hbmMask) + hbmNewMask = CreateBitmap (cxNew, himl->cy, 1, 1, NULL); + else + hbmNewMask = 0; /* Just to keep compiler happy! */ + + hdcBmp = CreateCompatibleDC (0); + + /* copy all images and masks prior to the "removed" image */ + if (i > 0) { + TRACE("Pre image copy: Copy %d images\n", i); + + SelectObject (hdcBmp, hbmNewImage); + BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy, + himl->hdcImage, 0, 0, SRCCOPY); + + if (himl->hbmMask) { + SelectObject (hdcBmp, hbmNewMask); + BitBlt (hdcBmp, 0, 0, i * himl->cx, himl->cy, + himl->hdcMask, 0, 0, SRCCOPY); + } + } + + /* copy all images and masks behind the removed image */ + if (i < himl->cCurImage - 1) { + TRACE("Post image copy!\n"); + SelectObject (hdcBmp, hbmNewImage); + BitBlt (hdcBmp, i * himl->cx, 0, (himl->cCurImage - i - 1) * himl->cx, + himl->cy, himl->hdcImage, (i + 1) * himl->cx, 0, SRCCOPY); + + if (himl->hbmMask) { + SelectObject (hdcBmp, hbmNewMask); + BitBlt (hdcBmp, i * himl->cx, 0, + (himl->cCurImage - i - 1) * himl->cx, + himl->cy, himl->hdcMask, (i + 1) * himl->cx, 0, SRCCOPY); + } + } + + DeleteDC (hdcBmp); + + /* delete old images and insert new ones */ + SelectObject (himl->hdcImage, hbmNewImage); + DeleteObject (himl->hbmImage); + himl->hbmImage = hbmNewImage; + if (himl->hbmMask) { + SelectObject (himl->hdcMask, hbmNewMask); + DeleteObject (himl->hbmMask); + himl->hbmMask = hbmNewMask; + } + + himl->cCurImage--; + himl->cMaxImage = himl->cCurImage + himl->cGrow; + } + + return TRUE; +} + + +/************************************************************************* + * ImageList_Replace [COMCTL32.@] + * + * Replaces an image in an image list with a new image. + * + * PARAMS + * himl [I] handle to image list + * i [I] image index + * hbmImage [I] handle to image bitmap + * hbmMask [I] handle to mask bitmap. Can be NULL. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ + +BOOL WINAPI +ImageList_Replace (HIMAGELIST himl, INT i, HBITMAP hbmImage, + HBITMAP hbmMask) +{ + HDC hdcImage; + BITMAP bmp; + + TRACE("%p %d %p %p\n", himl, i, hbmImage, hbmMask); + + if (!is_valid(himl)) { + ERR("Invalid image list handle!\n"); + return FALSE; + } + + if ((i >= himl->cMaxImage) || (i < 0)) { + ERR("Invalid image index!\n"); + return FALSE; + } + + hdcImage = CreateCompatibleDC (0); + GetObjectA (hbmImage, sizeof(BITMAP), (LPVOID)&bmp); + + /* Replace Image */ + SelectObject (hdcImage, hbmImage); + + StretchBlt (himl->hdcImage, i * himl->cx, 0, himl->cx, himl->cy, + hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY); + + if (himl->hbmMask) + { + /* Replace Mask */ + SelectObject (hdcImage, hbmMask); + + StretchBlt (himl->hdcMask, i * himl->cx, 0, himl->cx, himl->cy, + hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY); + + + /* Remove the background from the image + */ + StretchBlt (himl->hdcImage, + i*himl->cx, 0, himl->cx, himl->cy, + hdcImage, + 0, 0, bmp.bmWidth, bmp.bmHeight, + 0x220326); /* NOTSRCAND */ + } + + DeleteDC (hdcImage); + + return TRUE; +} + + +/************************************************************************* + * ImageList_ReplaceIcon [COMCTL32.@] + * + * Replaces an image in an image list using an icon. + * + * PARAMS + * himl [I] handle to image list + * i [I] image index + * hIcon [I] handle to icon + * + * RETURNS + * Success: index of the replaced image + * Failure: -1 + */ + +INT WINAPI +ImageList_ReplaceIcon (HIMAGELIST himl, INT i, HICON hIcon) +{ + HDC hdcImage; + INT nIndex; + HICON hBestFitIcon; + HBITMAP hbmOldSrc; + ICONINFO ii; + BITMAP bmp; + + TRACE("(%p %d %p)\n", himl, i, hIcon); + + if (!is_valid(himl)) + return -1; + if ((i >= himl->cMaxImage) || (i < -1)) + return -1; + + hBestFitIcon = CopyImage( + hIcon, IMAGE_ICON, + himl->cx, himl->cy, + LR_COPYFROMRESOURCE); + + GetIconInfo (hBestFitIcon, &ii); + if (ii.hbmMask == 0) + ERR("no mask!\n"); + if (ii.hbmColor == 0) + ERR("no color!\n"); + GetObjectA (ii.hbmMask, sizeof(BITMAP), (LPVOID)&bmp); + + if (i == -1) { + if (himl->cCurImage + 1 > himl->cMaxImage) + IMAGELIST_InternalExpandBitmaps (himl, 1, 0, 0); + + nIndex = himl->cCurImage; + himl->cCurImage++; + } + else + nIndex = i; + + hdcImage = CreateCompatibleDC (0); + TRACE("hdcImage=%p\n", hdcImage); + if (hdcImage == 0) + ERR("invalid hdcImage!\n"); + + SetTextColor(himl->hdcImage, RGB(0,0,0)); + SetBkColor (himl->hdcImage, RGB(255,255,255)); + hbmOldSrc = SelectObject (hdcImage, ii.hbmColor); + + StretchBlt (himl->hdcImage, nIndex * himl->cx, 0, himl->cx, himl->cy, + hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY); + + if (himl->hbmMask) { + SelectObject (hdcImage, ii.hbmMask); + StretchBlt (himl->hdcMask, nIndex * himl->cx, 0, himl->cx, himl->cy, + hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY); + } + + SelectObject (hdcImage, hbmOldSrc); + + if(hBestFitIcon) + DestroyIcon(hBestFitIcon); + if (hdcImage) + DeleteDC (hdcImage); + if (ii.hbmColor) + DeleteObject (ii.hbmColor); + if (ii.hbmMask) + DeleteObject (ii.hbmMask); + + TRACE("Insert index = %d, himl->cCurImage = %d\n", nIndex, himl->cCurImage); + return nIndex; +} + + +/************************************************************************* + * ImageList_SetBkColor [COMCTL32.@] + * + * Sets the background color of an image list. + * + * PARAMS + * himl [I] handle to image list + * clrBk [I] background color + * + * RETURNS + * Success: previous background color + * Failure: CLR_NONE + */ + +COLORREF WINAPI +ImageList_SetBkColor (HIMAGELIST himl, COLORREF clrBk) +{ + COLORREF clrOldBk; + + if (!is_valid(himl)) + return CLR_NONE; + + clrOldBk = himl->clrBk; + himl->clrBk = clrBk; + return clrOldBk; +} + + +/************************************************************************* + * ImageList_SetDragCursorImage [COMCTL32.@] + * + * Combines the specified image with the current drag image + * + * PARAMS + * himlDrag [I] handle to drag image list + * iDrag [I] drag image index + * dxHotspot [I] X position of the hot spot + * dyHotspot [I] Y position of the hot spot + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * NOTES + * - The names dxHotspot, dyHotspot are misleading because they have nothing + * to do with a hotspot but are only the offset of the origin of the new + * image relative to the origin of the old image. + * + * - When this function is called and the drag image is visible, a + * short flickering occurs but this matches the Win9x behavior. It is + * possible to fix the flickering using code like in ImageList_DragMove. + */ + +BOOL WINAPI +ImageList_SetDragCursorImage (HIMAGELIST himlDrag, INT iDrag, + INT dxHotspot, INT dyHotspot) +{ + HIMAGELIST himlTemp; + BOOL visible; + + if (!is_valid(InternalDrag.himl) || !is_valid(himlDrag)) + return FALSE; + + TRACE(" dxH=%d dyH=%d nX=%d nY=%d\n", + dxHotspot, dyHotspot, InternalDrag.dxHotspot, InternalDrag.dyHotspot); + + visible = InternalDrag.bShow; + + himlTemp = ImageList_Merge (InternalDrag.himl, 0, himlDrag, iDrag, + dxHotspot, dyHotspot); + + if (visible) { + /* hide the drag image */ + ImageList_DragShowNolock(FALSE); + } + if ((InternalDrag.himl->cx != himlTemp->cx) || + (InternalDrag.himl->cy != himlTemp->cy)) { + /* the size of the drag image changed, invalidate the buffer */ + DeleteObject(InternalDrag.hbmBg); + InternalDrag.hbmBg = 0; + } + + ImageList_Destroy (InternalDrag.himl); + InternalDrag.himl = himlTemp; + + if (visible) { + /* show the drag image */ + ImageList_DragShowNolock(TRUE); + } + + return TRUE; +} + + +/************************************************************************* + * ImageList_SetFilter [COMCTL32.@] + * + * Sets a filter (or does something completely different)!!??? + * It removes 12 Bytes from the stack (3 Parameters). + * + * PARAMS + * himl [I] SHOULD be a handle to image list + * i [I] COULD be an index? + * dwFilter [I] ??? + * + * RETURNS + * Success: TRUE ??? + * Failure: FALSE ??? + * + * BUGS + * This is an UNDOCUMENTED function!!!! + * empty stub. + */ + +BOOL WINAPI +ImageList_SetFilter (HIMAGELIST himl, INT i, DWORD dwFilter) +{ + FIXME("(%p 0x%x 0x%lx):empty stub!\n", himl, i, dwFilter); + + return FALSE; +} + + +/************************************************************************* + * ImageList_SetFlags [COMCTL32.@] + * + * Sets the image list flags. + * + * PARAMS + * himl [I] Handle to image list + * flags [I] Flags to set + * + * RETURNS + * Old flags? + * + * BUGS + * Stub. + */ + +DWORD WINAPI +ImageList_SetFlags(HIMAGELIST himl, DWORD flags) +{ + FIXME("(%p %08lx):empty stub\n", himl, flags); + return 0; +} + + +/************************************************************************* + * ImageList_SetIconSize [COMCTL32.@] + * + * Sets the image size of the bitmap and deletes all images. + * + * PARAMS + * himl [I] handle to image list + * cx [I] image width + * cy [I] image height + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ + +BOOL WINAPI +ImageList_SetIconSize (HIMAGELIST himl, INT cx, INT cy) +{ + INT nCount; + HBITMAP hbmNew; + + if (!is_valid(himl)) + return FALSE; + + /* remove all images */ + himl->cMaxImage = himl->cInitial + himl->cGrow; + himl->cCurImage = 0; + himl->cx = cx; + himl->cy = cy; + + /* initialize overlay mask indices */ + for (nCount = 0; nCount < MAX_OVERLAYIMAGE; nCount++) + himl->nOvlIdx[nCount] = -1; + + hbmNew = ImageList_CreateImage(himl->hdcImage, himl, himl->cMaxImage * himl->cx, himl->cy); + SelectObject (himl->hdcImage, hbmNew); + DeleteObject (himl->hbmImage); + himl->hbmImage = hbmNew; + + if (himl->hbmMask) { + hbmNew = CreateBitmap (himl->cMaxImage * himl->cx, himl->cy, + 1, 1, NULL); + SelectObject (himl->hdcMask, hbmNew); + DeleteObject (himl->hbmMask); + himl->hbmMask = hbmNew; + } + + return TRUE; +} + + +/************************************************************************* + * ImageList_SetImageCount [COMCTL32.@] + * + * Resizes an image list to the specified number of images. + * + * PARAMS + * himl [I] handle to image list + * iImageCount [I] number of images in the image list + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ + +BOOL WINAPI +ImageList_SetImageCount (HIMAGELIST himl, UINT iImageCount) +{ + HDC hdcBitmap; + HBITMAP hbmNewBitmap; + INT nNewCount, nCopyCount; + + TRACE("%p %d\n",himl,iImageCount); + + if (!is_valid(himl)) + return FALSE; + if (himl->cCurImage >= iImageCount) + return FALSE; + if (himl->cMaxImage > iImageCount) + { + himl->cCurImage = iImageCount; + return TRUE; + } + + nNewCount = iImageCount + himl->cGrow; + nCopyCount = min(himl->cCurImage, iImageCount); + + hdcBitmap = CreateCompatibleDC (0); + + hbmNewBitmap = ImageList_CreateImage(hdcBitmap, himl, nNewCount * himl->cx, himl->cy); + + if (hbmNewBitmap != 0) + { + SelectObject (hdcBitmap, hbmNewBitmap); + + /* copy images */ + BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy, + himl->hdcImage, 0, 0, SRCCOPY); +#if 0 + /* delete 'empty' image space */ + SetBkColor (hdcBitmap, RGB(255, 255, 255)); + SetTextColor (hdcBitmap, RGB(0, 0, 0)); + PatBlt (hdcBitmap, nCopyCount * himl->cx, 0, + (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS); +#endif + SelectObject (himl->hdcImage, hbmNewBitmap); + DeleteObject (himl->hbmImage); + himl->hbmImage = hbmNewBitmap; + } + else + ERR("Could not create new image bitmap !\n"); + + if (himl->hbmMask) + { + hbmNewBitmap = CreateBitmap (nNewCount * himl->cx, himl->cy, + 1, 1, NULL); + if (hbmNewBitmap != 0) + { + SelectObject (hdcBitmap, hbmNewBitmap); + + /* copy images */ + BitBlt (hdcBitmap, 0, 0, nCopyCount * himl->cx, himl->cy, + himl->hdcMask, 0, 0, SRCCOPY); +#if 0 + /* delete 'empty' image space */ + SetBkColor (hdcBitmap, RGB(255, 255, 255)); + SetTextColor (hdcBitmap, RGB(0, 0, 0)); + PatBlt (hdcBitmap, nCopyCount * himl->cx, 0, + (nNewCount - nCopyCount) * himl->cx, himl->cy, BLACKNESS); +#endif + SelectObject (himl->hdcMask, hbmNewBitmap); + DeleteObject (himl->hbmMask); + himl->hbmMask = hbmNewBitmap; + } + else + ERR("Could not create new mask bitmap!\n"); + } + + DeleteDC (hdcBitmap); + + /* Update max image count and current image count */ + himl->cMaxImage = nNewCount; + himl->cCurImage = iImageCount; + + return TRUE; +} + + +/************************************************************************* + * ImageList_SetOverlayImage [COMCTL32.@] + * + * Assigns an overlay mask index to an existing image in an image list. + * + * PARAMS + * himl [I] handle to image list + * iImage [I] image index + * iOverlay [I] overlay mask index + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ + +BOOL WINAPI +ImageList_SetOverlayImage (HIMAGELIST himl, INT iImage, INT iOverlay) +{ + if (!is_valid(himl)) + return FALSE; + if ((iOverlay < 1) || (iOverlay > MAX_OVERLAYIMAGE)) + return FALSE; + if ((iImage!=-1) && ((iImage < 0) || (iImage > himl->cCurImage))) + return FALSE; + himl->nOvlIdx[iOverlay - 1] = iImage; + return TRUE; +} + + + +/* helper for ImageList_Write - write bitmap to pstm + * currently everything is written as 24 bit RGB, except masks + */ +static BOOL +_write_bitmap(HBITMAP hBitmap, LPSTREAM pstm, int cx, int cy) +{ + LPBITMAPFILEHEADER bmfh; + LPBITMAPINFOHEADER bmih; + LPBYTE data, lpBits, lpBitsOrg; + BITMAP bm; + INT bitCount, sizeImage, offBits, totalSize; + INT nwidth, nheight, nsizeImage, icount; + HDC xdc; + BOOL result = FALSE; + + + xdc = GetDC(0); + GetObjectA(hBitmap, sizeof(BITMAP), (LPVOID)&bm); + + /* XXX is this always correct? */ + icount = bm.bmWidth / cx; + nwidth = cx; + nheight = cy * icount; + + bitCount = bm.bmBitsPixel == 1 ? 1 : 24; + sizeImage = ((((bm.bmWidth * bitCount)+31) & ~31) >> 3) * bm.bmHeight; + nsizeImage = ((((nwidth * bitCount)+31) & ~31) >> 3) * nheight; + + totalSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); + if(bitCount != 24) + totalSize += (1 << bitCount) * sizeof(RGBQUAD); + offBits = totalSize; + totalSize += nsizeImage; + + data = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, totalSize); + bmfh = (LPBITMAPFILEHEADER)data; + bmih = (LPBITMAPINFOHEADER)(data + sizeof(BITMAPFILEHEADER)); + lpBits = data + offBits; + + /* setup BITMAPFILEHEADER */ + bmfh->bfType = (('M' << 8) | 'B'); + bmfh->bfSize = 0; + bmfh->bfReserved1 = 0; + bmfh->bfReserved2 = 0; + bmfh->bfOffBits = offBits; + + /* setup BITMAPINFOHEADER */ + bmih->biSize = sizeof(BITMAPINFOHEADER); + bmih->biWidth = bm.bmWidth; + bmih->biHeight = bm.bmHeight; + bmih->biPlanes = 1; + bmih->biBitCount = bitCount; + bmih->biCompression = BI_RGB; + bmih->biSizeImage = sizeImage; + bmih->biXPelsPerMeter = 0; + bmih->biYPelsPerMeter = 0; + bmih->biClrUsed = 0; + bmih->biClrImportant = 0; + + lpBitsOrg = (LPBYTE)LocalAlloc(LMEM_ZEROINIT, sizeImage); + if(!GetDIBits(xdc, hBitmap, 0, bm.bmHeight, lpBitsOrg, + (BITMAPINFO *)bmih, DIB_RGB_COLORS)) + goto failed; + else { + int i; + int obpl = (((bm.bmWidth*bitCount+31) & ~31)>>3); + int nbpl = (((nwidth*bitCount+31) & ~31)>>3); + + for(i = 0; i < nheight; i++) { + int ooff = ((nheight-1-i)%cy) * obpl + ((i/cy) * nbpl); + int noff = (nbpl * (nheight-1-i)); + memcpy(lpBits + noff, lpBitsOrg + ooff, nbpl); + } + } + + bmih->biWidth = nwidth; + bmih->biHeight = nheight; + bmih->biSizeImage = nsizeImage; + + if(bitCount == 1) { + /* Hack. */ + LPBITMAPINFO inf = (LPBITMAPINFO)bmih; + inf->bmiColors[0].rgbRed = inf->bmiColors[0].rgbGreen = inf->bmiColors[0].rgbBlue = 0; + inf->bmiColors[1].rgbRed = inf->bmiColors[1].rgbGreen = inf->bmiColors[1].rgbBlue = 0xff; + } + + if(!SUCCEEDED(IStream_Write(pstm, data, totalSize, NULL))) + goto failed; + + result = TRUE; + + failed: + ReleaseDC(0, xdc); + LocalFree((HLOCAL)lpBitsOrg); + LocalFree((HLOCAL)data); + + return result; +} + + +/************************************************************************* + * ImageList_Write [COMCTL32.@] + * + * Writes an image list to a stream. + * + * PARAMS + * himl [I] handle to image list + * pstm [O] Pointer to a stream. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * BUGS + * probably. + */ + +BOOL WINAPI +ImageList_Write (HIMAGELIST himl, LPSTREAM pstm) +{ + ILHEAD ilHead; + int i; + + if (!is_valid(himl)) + return FALSE; + + ilHead.usMagic = (('L' << 8) | 'I'); + ilHead.usVersion = 0x101; + ilHead.cCurImage = himl->cCurImage; + ilHead.cMaxImage = himl->cMaxImage; + ilHead.cGrow = himl->cGrow; + ilHead.cx = himl->cx; + ilHead.cy = himl->cy; + ilHead.bkcolor = himl->clrBk; + ilHead.flags = himl->flags; + for(i = 0; i < 4; i++) { + ilHead.ovls[i] = himl->nOvlIdx[i]; + } + + if(!SUCCEEDED(IStream_Write(pstm, &ilHead, sizeof(ILHEAD), NULL))) + return FALSE; + + /* write the bitmap */ + if(!_write_bitmap(himl->hbmImage, pstm, himl->cx, himl->cy)) + return FALSE; + + /* write the mask if we have one */ + if(himl->flags & ILC_MASK) { + if(!_write_bitmap(himl->hbmMask, pstm, himl->cx, himl->cy)) + return FALSE; + } + + return TRUE; +} + + +static HBITMAP ImageList_CreateImage(HDC hdc, HIMAGELIST himl, UINT width, UINT height) +{ + HBITMAP hbmNewBitmap; + UINT ilc = (himl->flags & 0xFE); + + if ((ilc >= ILC_COLOR4 && ilc <= ILC_COLOR32) || ilc == ILC_COLOR) + { + VOID* bits; + BITMAPINFO *bmi; + + TRACE("Creating DIBSection: %d Bits per Pixel\n", himl->uBitsPixel); + + if (himl->uBitsPixel <= ILC_COLOR8) + { + LPPALETTEENTRY pal; + ULONG i, colors; + BYTE temp; + + colors = 1 << himl->uBitsPixel; + bmi = Alloc(sizeof(BITMAPINFOHEADER) + + sizeof(PALETTEENTRY) * colors); + + pal = (LPPALETTEENTRY)bmi->bmiColors; + GetPaletteEntries(GetStockObject(DEFAULT_PALETTE), 0, colors, pal); + + /* Swap colors returned by GetPaletteEntries so we can use them for + * CreateDIBSection call. */ + for (i = 0; i < colors; i++) + { + temp = pal[i].peBlue; + bmi->bmiColors[i].rgbRed = pal[i].peRed; + bmi->bmiColors[i].rgbBlue = temp; + } + } + else + { + bmi = Alloc(sizeof(BITMAPINFOHEADER)); + } + + bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi->bmiHeader.biWidth = width; + bmi->bmiHeader.biHeight = height; + bmi->bmiHeader.biPlanes = 1; + bmi->bmiHeader.biBitCount = himl->uBitsPixel; + bmi->bmiHeader.biCompression = BI_RGB; + bmi->bmiHeader.biSizeImage = 0; + bmi->bmiHeader.biXPelsPerMeter = 0; + bmi->bmiHeader.biYPelsPerMeter = 0; + bmi->bmiHeader.biClrUsed = 0; + bmi->bmiHeader.biClrImportant = 0; + + hbmNewBitmap = CreateDIBSection(hdc, bmi, DIB_RGB_COLORS, &bits, 0, 0); + + Free (bmi); + } + else /*if (ilc == ILC_COLORDDB)*/ + { + TRACE("Creating Bitmap: %d Bits per Pixel\n", himl->uBitsPixel); + + hbmNewBitmap = CreateBitmap (width, height, 1, himl->uBitsPixel, NULL); + } + TRACE("returning %p\n", hbmNewBitmap); + return hbmNewBitmap; +} + +/************************************************************************* + * ImageList_SetColorTable [COMCTL32.@] + * + * Sets the color table of an image list. + * + * PARAMS + * himl [I] Handle to the image list. + * uStartIndex [I] The first index to set. + * cEntries [I] Number of entries to set. + * prgb [I] New color information for color table for the image list. + * + * RETURNS + * Success: Number of entries in the table that were set. + * Failure: Zero. + * + * SEE + * ImageList_Create(), SetDIBColorTable() + */ + +UINT WINAPI +ImageList_SetColorTable (HIMAGELIST himl, UINT uStartIndex, UINT cEntries, CONST RGBQUAD * prgb) +{ + return SetDIBColorTable(himl->hdcImage, uStartIndex, cEntries, prgb); +} diff --git a/reactos/lib/comctl32/imagelist.h b/reactos/lib/comctl32/imagelist.h index 454847f86c4..5c5ab6998d3 100644 --- a/reactos/lib/comctl32/imagelist.h +++ b/reactos/lib/comctl32/imagelist.h @@ -1,78 +1,78 @@ -/* - * ImageList definitions - * - * Copyright 1998 Eric Kohl - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_IMAGELIST_H -#define __WINE_IMAGELIST_H - -#include - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" - -#include "pshpack1.h" - -/* the ones with offsets at the end are the same as in Windows */ -struct _IMAGELIST -{ - DWORD magic; /* 00: 'SAMX' */ - INT cCurImage; /* 04: ImageCount */ - INT cMaxImage; /* 08: maximages */ - INT cGrow; /* 0c: cGrow */ - INT cx; /* 10: cx */ - INT cy; /* 14: cy */ - DWORD x4; - UINT flags; /* 1c: flags */ - COLORREF clrFg; /* 20: foreground color */ - COLORREF clrBk; /* 24: backgournd color */ - - - HBITMAP hbmImage; /* 30: images Bitmap */ - HBITMAP hbmMask; /* 34: masks Bitmap */ - HDC hdcImage; /* 38: images MemDC */ - HDC hdcMask; /* 3C: masks MemDC */ - INT nOvlIdx[15]; /* 40: overlay images index */ - - /* not yet found out */ - HBRUSH hbrBlend25; - HBRUSH hbrBlend50; - INT cInitial; - UINT uBitsPixel; -}; - -#define IMAGELIST_MAGIC 0x53414D58 - -/* Header used by ImageList_Read() and ImageList_Write() */ -typedef struct _ILHEAD -{ - USHORT usMagic; - USHORT usVersion; - WORD cCurImage; - WORD cMaxImage; - WORD cGrow; - WORD cx; - WORD cy; - COLORREF bkcolor; - WORD flags; - SHORT ovls[4]; -} ILHEAD; - -#include "poppack.h" -#endif /* __WINE_IMAGELIST_H */ +/* + * ImageList definitions + * + * Copyright 1998 Eric Kohl + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_IMAGELIST_H +#define __WINE_IMAGELIST_H + +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" + +#include "pshpack1.h" + +/* the ones with offsets at the end are the same as in Windows */ +struct _IMAGELIST +{ + DWORD magic; /* 00: 'SAMX' */ + INT cCurImage; /* 04: ImageCount */ + INT cMaxImage; /* 08: maximages */ + INT cGrow; /* 0c: cGrow */ + INT cx; /* 10: cx */ + INT cy; /* 14: cy */ + DWORD x4; + UINT flags; /* 1c: flags */ + COLORREF clrFg; /* 20: foreground color */ + COLORREF clrBk; /* 24: backgournd color */ + + + HBITMAP hbmImage; /* 30: images Bitmap */ + HBITMAP hbmMask; /* 34: masks Bitmap */ + HDC hdcImage; /* 38: images MemDC */ + HDC hdcMask; /* 3C: masks MemDC */ + INT nOvlIdx[15]; /* 40: overlay images index */ + + /* not yet found out */ + HBRUSH hbrBlend25; + HBRUSH hbrBlend50; + INT cInitial; + UINT uBitsPixel; +}; + +#define IMAGELIST_MAGIC 0x53414D58 + +/* Header used by ImageList_Read() and ImageList_Write() */ +typedef struct _ILHEAD +{ + USHORT usMagic; + USHORT usVersion; + WORD cCurImage; + WORD cMaxImage; + WORD cGrow; + WORD cx; + WORD cy; + COLORREF bkcolor; + WORD flags; + SHORT ovls[4]; +} ILHEAD; + +#include "poppack.h" +#endif /* __WINE_IMAGELIST_H */ diff --git a/reactos/lib/comctl32/ipaddress.c b/reactos/lib/comctl32/ipaddress.c index 5dd0cc166fd..e4654b1b2fe 100644 --- a/reactos/lib/comctl32/ipaddress.c +++ b/reactos/lib/comctl32/ipaddress.c @@ -1,613 +1,613 @@ -/* - * IP Address control - * - * Copyright 2002 Dimitrie O. Paun - * Copyright 1999 Chris Morgan - * Copyright 1999 James Abbatiello - * Copyright 1998, 1999 Eric Kohl - * Copyright 1998 Alex Priem - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTE - * - * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on Sep. 9, 2002, by Dimitrie O. Paun. - * - * Unless otherwise noted, we believe this code to be complete, as per - * the specification mentioned above. - * If you discover missing features, or bugs, please note them below. - * - */ - -#include -#include -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "comctl32.h" -#include "wine/unicode.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ipaddress); - -typedef struct -{ - HWND EditHwnd; - INT LowerLimit; - INT UpperLimit; - WNDPROC OrigProc; -} IPPART_INFO; - -typedef struct -{ - HWND Self; - HWND Notify; - BOOL Enabled; - IPPART_INFO Part[4]; -} IPADDRESS_INFO; - -static const WCHAR IP_SUBCLASS_PROP[] = - { 'C', 'C', 'I', 'P', '3', '2', 'S', 'u', 'b', 'c', 'l', 'a', 's', 's', 'I', 'n', 'f', 'o', 0 }; - -#define POS_DEFAULT 0 -#define POS_LEFT 1 -#define POS_RIGHT 2 -#define POS_SELALL 3 - -static LRESULT CALLBACK -IPADDRESS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - -static LRESULT IPADDRESS_Notify (IPADDRESS_INFO *infoPtr, UINT command) -{ - HWND hwnd = infoPtr->Self; - - TRACE("(command=%x)\n", command); - - return SendMessageW (infoPtr->Notify, WM_COMMAND, - MAKEWPARAM (GetWindowLongPtrW (hwnd, GWLP_ID), command), (LPARAM)hwnd); -} - -static INT IPADDRESS_IPNotify (IPADDRESS_INFO *infoPtr, INT field, INT value) -{ - NMIPADDRESS nmip; - - TRACE("(field=%x, value=%d)\n", field, value); - - nmip.hdr.hwndFrom = infoPtr->Self; - nmip.hdr.idFrom = GetWindowLongPtrW (infoPtr->Self, GWLP_ID); - nmip.hdr.code = IPN_FIELDCHANGED; - - nmip.iField = field; - nmip.iValue = value; - - SendMessageW (infoPtr->Notify, WM_NOTIFY, - (WPARAM)nmip.hdr.idFrom, (LPARAM)&nmip); - - TRACE("<-- %d\n", nmip.iValue); - - return nmip.iValue; -} - - -static int IPADDRESS_GetPartIndex(IPADDRESS_INFO *infoPtr, HWND hwnd) -{ - int i; - - TRACE("(hwnd=%p)\n", hwnd); - - for (i = 0; i < 4; i++) - if (infoPtr->Part[i].EditHwnd == hwnd) return i; - - ERR("We subclassed the wrong window! (hwnd=%p)\n", hwnd); - return -1; -} - - -static LRESULT IPADDRESS_Draw (IPADDRESS_INFO *infoPtr, HDC hdc) -{ - static const WCHAR dotW[] = { '.', 0 }; - RECT rect, rcPart; - POINT pt; - COLORREF bgCol, fgCol; - int i; - - TRACE("\n"); - - GetClientRect (infoPtr->Self, &rect); - - if (infoPtr->Enabled) { - bgCol = COLOR_WINDOW; - fgCol = COLOR_WINDOWTEXT; - } else { - bgCol = COLOR_3DFACE; - fgCol = COLOR_GRAYTEXT; - } - - FillRect (hdc, &rect, (HBRUSH) (bgCol+1)); - DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); - - SetBkColor (hdc, GetSysColor(bgCol)); - SetTextColor(hdc, GetSysColor(fgCol)); - - for (i = 0; i < 3; i++) { - GetWindowRect (infoPtr->Part[i].EditHwnd, &rcPart); - pt.x = rcPart.right; - ScreenToClient(infoPtr->Self, &pt); - rect.left = pt.x; - GetWindowRect (infoPtr->Part[i+1].EditHwnd, &rcPart); - pt.x = rcPart.left; - ScreenToClient(infoPtr->Self, &pt); - rect.right = pt.x; - DrawTextW(hdc, dotW, 1, &rect, DT_SINGLELINE | DT_CENTER | DT_BOTTOM); - } - - return 0; -} - - -static LRESULT IPADDRESS_Create (HWND hwnd, LPCREATESTRUCTA lpCreate) -{ - static const WCHAR EDIT[] = { 'E', 'd', 'i', 't', 0 }; - IPADDRESS_INFO *infoPtr; - RECT rcClient, edit; - int i, fieldsize; - - TRACE("\n"); - - SetWindowLongW (hwnd, GWL_STYLE, - GetWindowLongW(hwnd, GWL_STYLE) & ~WS_BORDER); - - infoPtr = (IPADDRESS_INFO *)Alloc (sizeof(IPADDRESS_INFO)); - if (!infoPtr) return -1; - SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); - - GetClientRect (hwnd, &rcClient); - - fieldsize = (rcClient.right - rcClient.left) / 4; - - edit.top = rcClient.top + 2; - edit.bottom = rcClient.bottom - 2; - - infoPtr->Self = hwnd; - infoPtr->Enabled = FALSE; - infoPtr->Notify = lpCreate->hwndParent; - - for (i = 0; i < 4; i++) { - IPPART_INFO* part = &infoPtr->Part[i]; - - part->LowerLimit = 0; - part->UpperLimit = 255; - edit.left = rcClient.left + i*fieldsize + 6; - edit.right = rcClient.left + (i+1)*fieldsize - 2; - part->EditHwnd = - CreateWindowW (EDIT, NULL, WS_CHILD | WS_VISIBLE | ES_CENTER, - edit.left, edit.top, edit.right - edit.left, - edit.bottom - edit.top, hwnd, (HMENU) 1, - (HINSTANCE)GetWindowLongPtrW(hwnd, GWLP_HINSTANCE), NULL); - SetPropW(part->EditHwnd, IP_SUBCLASS_PROP, hwnd); - part->OrigProc = (WNDPROC) - SetWindowLongPtrW (part->EditHwnd, GWLP_WNDPROC, - (DWORD_PTR)IPADDRESS_SubclassProc); - } - - return 0; -} - - -static LRESULT IPADDRESS_Destroy (IPADDRESS_INFO *infoPtr) -{ - int i; - - TRACE("\n"); - - for (i = 0; i < 4; i++) { - IPPART_INFO* part = &infoPtr->Part[i]; - SetWindowLongPtrW (part->EditHwnd, GWLP_WNDPROC, (DWORD_PTR)part->OrigProc); - } - - SetWindowLongPtrW (infoPtr->Self, 0, 0); - Free (infoPtr); - return 0; -} - - -static LRESULT IPADDRESS_Enable (IPADDRESS_INFO *infoPtr, BOOL enabled) -{ - int i; - - infoPtr->Enabled = enabled; - - for (i = 0; i < 4; i++) - EnableWindow(infoPtr->Part[i].EditHwnd, enabled); - - InvalidateRgn(infoPtr->Self, NULL, FALSE); - return 0; -} - - -static LRESULT IPADDRESS_Paint (IPADDRESS_INFO *infoPtr, HDC hdc) -{ - PAINTSTRUCT ps; - - TRACE("\n"); - - if (hdc) return IPADDRESS_Draw (infoPtr, hdc); - - hdc = BeginPaint (infoPtr->Self, &ps); - IPADDRESS_Draw (infoPtr, hdc); - EndPaint (infoPtr->Self, &ps); - return 0; -} - - -static BOOL IPADDRESS_IsBlank (IPADDRESS_INFO *infoPtr) -{ - int i; - - TRACE("\n"); - - for (i = 0; i < 4; i++) - if (GetWindowTextLengthW (infoPtr->Part[i].EditHwnd)) return FALSE; - - return TRUE; -} - - -static int IPADDRESS_GetAddress (IPADDRESS_INFO *infoPtr, LPDWORD ip_address) -{ - WCHAR field[5]; - int i, invalid = 0; - DWORD ip_addr = 0; - - TRACE("\n"); - - for (i = 0; i < 4; i++) { - ip_addr *= 256; - if (GetWindowTextW (infoPtr->Part[i].EditHwnd, field, 4)) - ip_addr += atolW(field); - else - invalid++; - } - *ip_address = ip_addr; - - return 4 - invalid; -} - - -static BOOL IPADDRESS_SetRange (IPADDRESS_INFO *infoPtr, int index, WORD range) -{ - TRACE("\n"); - - if ( (index < 0) || (index > 3) ) return FALSE; - - infoPtr->Part[index].LowerLimit = range & 0xFF; - infoPtr->Part[index].UpperLimit = (range >> 8) & 0xFF; - - return TRUE; -} - - -static void IPADDRESS_ClearAddress (IPADDRESS_INFO *infoPtr) -{ - WCHAR nil[1] = { 0 }; - int i; - - TRACE("\n"); - - for (i = 0; i < 4; i++) - SetWindowTextW (infoPtr->Part[i].EditHwnd, nil); -} - - -static LRESULT IPADDRESS_SetAddress (IPADDRESS_INFO *infoPtr, DWORD ip_address) -{ - WCHAR buf[20]; - static const WCHAR fmt[] = { '%', 'd', 0 }; - int i; - - TRACE("\n"); - - for (i = 3; i >= 0; i--) { - IPPART_INFO* part = &infoPtr->Part[i]; - int value = ip_address & 0xff; - if ( (value >= part->LowerLimit) && (value <= part->UpperLimit) ) { - wsprintfW (buf, fmt, value); - SetWindowTextW (part->EditHwnd, buf); - IPADDRESS_Notify (infoPtr, EN_CHANGE); - } - ip_address >>= 8; - } - - return TRUE; -} - - -static void IPADDRESS_SetFocusToField (IPADDRESS_INFO *infoPtr, INT index) -{ - TRACE("(index=%d)\n", index); - - if (index > 3 || index < 0) index=0; - - SetFocus (infoPtr->Part[index].EditHwnd); -} - - -static BOOL IPADDRESS_ConstrainField (IPADDRESS_INFO *infoPtr, int currentfield) -{ - IPPART_INFO *part = &infoPtr->Part[currentfield]; - WCHAR field[10]; - static const WCHAR fmt[] = { '%', 'd', 0 }; - int curValue, newValue; - - TRACE("(currentfield=%d)\n", currentfield); - - if (currentfield < 0 || currentfield > 3) return FALSE; - - if (!GetWindowTextW (part->EditHwnd, field, 4)) return FALSE; - - curValue = atoiW(field); - TRACE(" curValue=%d\n", curValue); - - newValue = IPADDRESS_IPNotify(infoPtr, currentfield, curValue); - TRACE(" newValue=%d\n", newValue); - - if (newValue < part->LowerLimit) newValue = part->LowerLimit; - if (newValue > part->UpperLimit) newValue = part->UpperLimit; - - if (newValue == curValue) return FALSE; - - wsprintfW (field, fmt, newValue); - TRACE(" field='%s'\n", debugstr_w(field)); - return SetWindowTextW (part->EditHwnd, field); -} - - -static BOOL IPADDRESS_GotoNextField (IPADDRESS_INFO *infoPtr, int cur, int sel) -{ - TRACE("\n"); - - if(cur >= -1 && cur < 4) { - IPADDRESS_ConstrainField(infoPtr, cur); - - if(cur < 3) { - IPPART_INFO *next = &infoPtr->Part[cur + 1]; - int start = 0, end = 0; - SetFocus (next->EditHwnd); - if (sel != POS_DEFAULT) { - if (sel == POS_RIGHT) - start = end = GetWindowTextLengthW(next->EditHwnd); - else if (sel == POS_SELALL) - end = -1; - SendMessageW(next->EditHwnd, EM_SETSEL, start, end); - } - return TRUE; - } - - } - return FALSE; -} - - -/* - * period: move and select the text in the next field to the right if - * the current field is not empty(l!=0), we are not in the - * left most position, and nothing is selected(startsel==endsel) - * - * spacebar: same behavior as period - * - * alpha characters: completely ignored - * - * digits: accepted when field text length < 2 ignored otherwise. - * when 3 numbers have been entered into the field the value - * of the field is checked, if the field value exceeds the - * maximum value and is changed the field remains the current - * field, otherwise focus moves to the field to the right - * - * tab: change focus from the current ipaddress control to the next - * control in the tab order - * - * right arrow: move to the field on the right to the left most - * position in that field if no text is selected, - * we are in the right most position in the field, - * we are not in the right most field - * - * left arrow: move to the field on the left to the right most - * position in that field if no text is selected, - * we are in the left most position in the current field - * and we are not in the left most field - * - * backspace: delete the character to the left of the cursor position, - * if none are present move to the field on the left if - * we are not in the left most field and delete the right - * most digit in that field while keeping the cursor - * on the right side of the field - */ -LRESULT CALLBACK -IPADDRESS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - HWND Self = (HWND)GetPropW (hwnd, IP_SUBCLASS_PROP); - IPADDRESS_INFO *infoPtr = (IPADDRESS_INFO *)GetWindowLongPtrW (Self, 0); - CHAR c = (CHAR)wParam; - INT index, len = 0, startsel, endsel; - IPPART_INFO *part; - - TRACE("(hwnd=%p msg=0x%x wparam=0x%x lparam=0x%lx)\n", hwnd, uMsg, wParam, lParam); - - if ( (index = IPADDRESS_GetPartIndex(infoPtr, hwnd)) < 0) return 0; - part = &infoPtr->Part[index]; - - if (uMsg == WM_CHAR || uMsg == WM_KEYDOWN) { - len = GetWindowTextLengthW (hwnd); - SendMessageW(hwnd, EM_GETSEL, (WPARAM)&startsel, (LPARAM)&endsel); - } - switch (uMsg) { - case WM_CHAR: - if(isdigit(c)) { - if(len == 2 && startsel==endsel && endsel==len) { - /* process the digit press before we check the field */ - int return_val = CallWindowProcW (part->OrigProc, hwnd, uMsg, wParam, lParam); - - /* if the field value was changed stay at the current field */ - if(!IPADDRESS_ConstrainField(infoPtr, index)) - IPADDRESS_GotoNextField (infoPtr, index, POS_DEFAULT); - - return return_val; - } else if (len == 3 && startsel==endsel && endsel==len) - IPADDRESS_GotoNextField (infoPtr, index, POS_SELALL); - else if (len < 3) break; - } else if(c == '.' || c == ' ') { - if(len && startsel==endsel && startsel != 0) { - IPADDRESS_GotoNextField(infoPtr, index, POS_SELALL); - } - } else if (c == VK_BACK) break; - return 0; - - case WM_KEYDOWN: - switch(c) { - case VK_RIGHT: - if(startsel==endsel && startsel==len) { - IPADDRESS_GotoNextField(infoPtr, index, POS_LEFT); - return 0; - } - break; - case VK_LEFT: - if(startsel==0 && startsel==endsel && index > 0) { - IPADDRESS_GotoNextField(infoPtr, index - 2, POS_RIGHT); - return 0; - } - break; - case VK_BACK: - if(startsel==endsel && startsel==0 && index > 0) { - IPPART_INFO *prev = &infoPtr->Part[index-1]; - WCHAR val[10]; - - if(GetWindowTextW(prev->EditHwnd, val, 5)) { - val[lstrlenW(val) - 1] = 0; - SetWindowTextW(prev->EditHwnd, val); - } - - IPADDRESS_GotoNextField(infoPtr, index - 2, POS_RIGHT); - return 0; - } - break; - } - break; - case WM_KILLFOCUS: - if (IPADDRESS_GetPartIndex(infoPtr, (HWND)wParam) < 0) - IPADDRESS_Notify(infoPtr, EN_KILLFOCUS); - break; - case WM_SETFOCUS: - if (IPADDRESS_GetPartIndex(infoPtr, (HWND)wParam) < 0) - IPADDRESS_Notify(infoPtr, EN_SETFOCUS); - break; - } - return CallWindowProcW (part->OrigProc, hwnd, uMsg, wParam, lParam); -} - - -static LRESULT WINAPI -IPADDRESS_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - IPADDRESS_INFO *infoPtr = (IPADDRESS_INFO *)GetWindowLongPtrW (hwnd, 0); - - TRACE("(hwnd=%p msg=0x%x wparam=0x%x lparam=0x%lx)\n", hwnd, uMsg, wParam, lParam); - - if (!infoPtr && (uMsg != WM_CREATE)) - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - - switch (uMsg) - { - case WM_CREATE: - return IPADDRESS_Create (hwnd, (LPCREATESTRUCTA)lParam); - - case WM_DESTROY: - return IPADDRESS_Destroy (infoPtr); - - case WM_ENABLE: - return IPADDRESS_Enable (infoPtr, (BOOL)wParam); - break; - - case WM_PAINT: - return IPADDRESS_Paint (infoPtr, (HDC)wParam); - - case WM_COMMAND: - switch(wParam >> 16) { - case EN_CHANGE: - IPADDRESS_Notify(infoPtr, EN_CHANGE); - break; - case EN_KILLFOCUS: - IPADDRESS_ConstrainField(infoPtr, IPADDRESS_GetPartIndex(infoPtr, (HWND)lParam)); - break; - } - break; - - case IPM_CLEARADDRESS: - IPADDRESS_ClearAddress (infoPtr); - break; - - case IPM_SETADDRESS: - return IPADDRESS_SetAddress (infoPtr, (DWORD)lParam); - - case IPM_GETADDRESS: - return IPADDRESS_GetAddress (infoPtr, (LPDWORD)lParam); - - case IPM_SETRANGE: - return IPADDRESS_SetRange (infoPtr, (int)wParam, (WORD)lParam); - - case IPM_SETFOCUS: - IPADDRESS_SetFocusToField (infoPtr, (int)wParam); - break; - - case IPM_ISBLANK: - return IPADDRESS_IsBlank (infoPtr); - - default: - if ((uMsg >= WM_USER) && (uMsg < WM_APP)) - ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam); - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - } - return 0; -} - - -void IPADDRESS_Register (void) -{ - WNDCLASSW wndClass; - - ZeroMemory (&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; - wndClass.lpfnWndProc = IPADDRESS_WindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(IPADDRESS_INFO *); - wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_IBEAM); - wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); - wndClass.lpszClassName = WC_IPADDRESSW; - - RegisterClassW (&wndClass); -} - - -void IPADDRESS_Unregister (void) -{ - UnregisterClassW (WC_IPADDRESSW, NULL); -} +/* + * IP Address control + * + * Copyright 2002 Dimitrie O. Paun + * Copyright 1999 Chris Morgan + * Copyright 1999 James Abbatiello + * Copyright 1998, 1999 Eric Kohl + * Copyright 1998 Alex Priem + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTE + * + * This code was audited for completeness against the documented features + * of Comctl32.dll version 6.0 on Sep. 9, 2002, by Dimitrie O. Paun. + * + * Unless otherwise noted, we believe this code to be complete, as per + * the specification mentioned above. + * If you discover missing features, or bugs, please note them below. + * + */ + +#include +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "comctl32.h" +#include "wine/unicode.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ipaddress); + +typedef struct +{ + HWND EditHwnd; + INT LowerLimit; + INT UpperLimit; + WNDPROC OrigProc; +} IPPART_INFO; + +typedef struct +{ + HWND Self; + HWND Notify; + BOOL Enabled; + IPPART_INFO Part[4]; +} IPADDRESS_INFO; + +static const WCHAR IP_SUBCLASS_PROP[] = + { 'C', 'C', 'I', 'P', '3', '2', 'S', 'u', 'b', 'c', 'l', 'a', 's', 's', 'I', 'n', 'f', 'o', 0 }; + +#define POS_DEFAULT 0 +#define POS_LEFT 1 +#define POS_RIGHT 2 +#define POS_SELALL 3 + +static LRESULT CALLBACK +IPADDRESS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +static LRESULT IPADDRESS_Notify (IPADDRESS_INFO *infoPtr, UINT command) +{ + HWND hwnd = infoPtr->Self; + + TRACE("(command=%x)\n", command); + + return SendMessageW (infoPtr->Notify, WM_COMMAND, + MAKEWPARAM (GetWindowLongPtrW (hwnd, GWLP_ID), command), (LPARAM)hwnd); +} + +static INT IPADDRESS_IPNotify (IPADDRESS_INFO *infoPtr, INT field, INT value) +{ + NMIPADDRESS nmip; + + TRACE("(field=%x, value=%d)\n", field, value); + + nmip.hdr.hwndFrom = infoPtr->Self; + nmip.hdr.idFrom = GetWindowLongPtrW (infoPtr->Self, GWLP_ID); + nmip.hdr.code = IPN_FIELDCHANGED; + + nmip.iField = field; + nmip.iValue = value; + + SendMessageW (infoPtr->Notify, WM_NOTIFY, + (WPARAM)nmip.hdr.idFrom, (LPARAM)&nmip); + + TRACE("<-- %d\n", nmip.iValue); + + return nmip.iValue; +} + + +static int IPADDRESS_GetPartIndex(IPADDRESS_INFO *infoPtr, HWND hwnd) +{ + int i; + + TRACE("(hwnd=%p)\n", hwnd); + + for (i = 0; i < 4; i++) + if (infoPtr->Part[i].EditHwnd == hwnd) return i; + + ERR("We subclassed the wrong window! (hwnd=%p)\n", hwnd); + return -1; +} + + +static LRESULT IPADDRESS_Draw (IPADDRESS_INFO *infoPtr, HDC hdc) +{ + static const WCHAR dotW[] = { '.', 0 }; + RECT rect, rcPart; + POINT pt; + COLORREF bgCol, fgCol; + int i; + + TRACE("\n"); + + GetClientRect (infoPtr->Self, &rect); + + if (infoPtr->Enabled) { + bgCol = COLOR_WINDOW; + fgCol = COLOR_WINDOWTEXT; + } else { + bgCol = COLOR_3DFACE; + fgCol = COLOR_GRAYTEXT; + } + + FillRect (hdc, &rect, (HBRUSH) (bgCol+1)); + DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); + + SetBkColor (hdc, GetSysColor(bgCol)); + SetTextColor(hdc, GetSysColor(fgCol)); + + for (i = 0; i < 3; i++) { + GetWindowRect (infoPtr->Part[i].EditHwnd, &rcPart); + pt.x = rcPart.right; + ScreenToClient(infoPtr->Self, &pt); + rect.left = pt.x; + GetWindowRect (infoPtr->Part[i+1].EditHwnd, &rcPart); + pt.x = rcPart.left; + ScreenToClient(infoPtr->Self, &pt); + rect.right = pt.x; + DrawTextW(hdc, dotW, 1, &rect, DT_SINGLELINE | DT_CENTER | DT_BOTTOM); + } + + return 0; +} + + +static LRESULT IPADDRESS_Create (HWND hwnd, LPCREATESTRUCTA lpCreate) +{ + static const WCHAR EDIT[] = { 'E', 'd', 'i', 't', 0 }; + IPADDRESS_INFO *infoPtr; + RECT rcClient, edit; + int i, fieldsize; + + TRACE("\n"); + + SetWindowLongW (hwnd, GWL_STYLE, + GetWindowLongW(hwnd, GWL_STYLE) & ~WS_BORDER); + + infoPtr = (IPADDRESS_INFO *)Alloc (sizeof(IPADDRESS_INFO)); + if (!infoPtr) return -1; + SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); + + GetClientRect (hwnd, &rcClient); + + fieldsize = (rcClient.right - rcClient.left) / 4; + + edit.top = rcClient.top + 2; + edit.bottom = rcClient.bottom - 2; + + infoPtr->Self = hwnd; + infoPtr->Enabled = FALSE; + infoPtr->Notify = lpCreate->hwndParent; + + for (i = 0; i < 4; i++) { + IPPART_INFO* part = &infoPtr->Part[i]; + + part->LowerLimit = 0; + part->UpperLimit = 255; + edit.left = rcClient.left + i*fieldsize + 6; + edit.right = rcClient.left + (i+1)*fieldsize - 2; + part->EditHwnd = + CreateWindowW (EDIT, NULL, WS_CHILD | WS_VISIBLE | ES_CENTER, + edit.left, edit.top, edit.right - edit.left, + edit.bottom - edit.top, hwnd, (HMENU) 1, + (HINSTANCE)GetWindowLongPtrW(hwnd, GWLP_HINSTANCE), NULL); + SetPropW(part->EditHwnd, IP_SUBCLASS_PROP, hwnd); + part->OrigProc = (WNDPROC) + SetWindowLongPtrW (part->EditHwnd, GWLP_WNDPROC, + (DWORD_PTR)IPADDRESS_SubclassProc); + } + + return 0; +} + + +static LRESULT IPADDRESS_Destroy (IPADDRESS_INFO *infoPtr) +{ + int i; + + TRACE("\n"); + + for (i = 0; i < 4; i++) { + IPPART_INFO* part = &infoPtr->Part[i]; + SetWindowLongPtrW (part->EditHwnd, GWLP_WNDPROC, (DWORD_PTR)part->OrigProc); + } + + SetWindowLongPtrW (infoPtr->Self, 0, 0); + Free (infoPtr); + return 0; +} + + +static LRESULT IPADDRESS_Enable (IPADDRESS_INFO *infoPtr, BOOL enabled) +{ + int i; + + infoPtr->Enabled = enabled; + + for (i = 0; i < 4; i++) + EnableWindow(infoPtr->Part[i].EditHwnd, enabled); + + InvalidateRgn(infoPtr->Self, NULL, FALSE); + return 0; +} + + +static LRESULT IPADDRESS_Paint (IPADDRESS_INFO *infoPtr, HDC hdc) +{ + PAINTSTRUCT ps; + + TRACE("\n"); + + if (hdc) return IPADDRESS_Draw (infoPtr, hdc); + + hdc = BeginPaint (infoPtr->Self, &ps); + IPADDRESS_Draw (infoPtr, hdc); + EndPaint (infoPtr->Self, &ps); + return 0; +} + + +static BOOL IPADDRESS_IsBlank (IPADDRESS_INFO *infoPtr) +{ + int i; + + TRACE("\n"); + + for (i = 0; i < 4; i++) + if (GetWindowTextLengthW (infoPtr->Part[i].EditHwnd)) return FALSE; + + return TRUE; +} + + +static int IPADDRESS_GetAddress (IPADDRESS_INFO *infoPtr, LPDWORD ip_address) +{ + WCHAR field[5]; + int i, invalid = 0; + DWORD ip_addr = 0; + + TRACE("\n"); + + for (i = 0; i < 4; i++) { + ip_addr *= 256; + if (GetWindowTextW (infoPtr->Part[i].EditHwnd, field, 4)) + ip_addr += atolW(field); + else + invalid++; + } + *ip_address = ip_addr; + + return 4 - invalid; +} + + +static BOOL IPADDRESS_SetRange (IPADDRESS_INFO *infoPtr, int index, WORD range) +{ + TRACE("\n"); + + if ( (index < 0) || (index > 3) ) return FALSE; + + infoPtr->Part[index].LowerLimit = range & 0xFF; + infoPtr->Part[index].UpperLimit = (range >> 8) & 0xFF; + + return TRUE; +} + + +static void IPADDRESS_ClearAddress (IPADDRESS_INFO *infoPtr) +{ + WCHAR nil[1] = { 0 }; + int i; + + TRACE("\n"); + + for (i = 0; i < 4; i++) + SetWindowTextW (infoPtr->Part[i].EditHwnd, nil); +} + + +static LRESULT IPADDRESS_SetAddress (IPADDRESS_INFO *infoPtr, DWORD ip_address) +{ + WCHAR buf[20]; + static const WCHAR fmt[] = { '%', 'd', 0 }; + int i; + + TRACE("\n"); + + for (i = 3; i >= 0; i--) { + IPPART_INFO* part = &infoPtr->Part[i]; + int value = ip_address & 0xff; + if ( (value >= part->LowerLimit) && (value <= part->UpperLimit) ) { + wsprintfW (buf, fmt, value); + SetWindowTextW (part->EditHwnd, buf); + IPADDRESS_Notify (infoPtr, EN_CHANGE); + } + ip_address >>= 8; + } + + return TRUE; +} + + +static void IPADDRESS_SetFocusToField (IPADDRESS_INFO *infoPtr, INT index) +{ + TRACE("(index=%d)\n", index); + + if (index > 3 || index < 0) index=0; + + SetFocus (infoPtr->Part[index].EditHwnd); +} + + +static BOOL IPADDRESS_ConstrainField (IPADDRESS_INFO *infoPtr, int currentfield) +{ + IPPART_INFO *part = &infoPtr->Part[currentfield]; + WCHAR field[10]; + static const WCHAR fmt[] = { '%', 'd', 0 }; + int curValue, newValue; + + TRACE("(currentfield=%d)\n", currentfield); + + if (currentfield < 0 || currentfield > 3) return FALSE; + + if (!GetWindowTextW (part->EditHwnd, field, 4)) return FALSE; + + curValue = atoiW(field); + TRACE(" curValue=%d\n", curValue); + + newValue = IPADDRESS_IPNotify(infoPtr, currentfield, curValue); + TRACE(" newValue=%d\n", newValue); + + if (newValue < part->LowerLimit) newValue = part->LowerLimit; + if (newValue > part->UpperLimit) newValue = part->UpperLimit; + + if (newValue == curValue) return FALSE; + + wsprintfW (field, fmt, newValue); + TRACE(" field='%s'\n", debugstr_w(field)); + return SetWindowTextW (part->EditHwnd, field); +} + + +static BOOL IPADDRESS_GotoNextField (IPADDRESS_INFO *infoPtr, int cur, int sel) +{ + TRACE("\n"); + + if(cur >= -1 && cur < 4) { + IPADDRESS_ConstrainField(infoPtr, cur); + + if(cur < 3) { + IPPART_INFO *next = &infoPtr->Part[cur + 1]; + int start = 0, end = 0; + SetFocus (next->EditHwnd); + if (sel != POS_DEFAULT) { + if (sel == POS_RIGHT) + start = end = GetWindowTextLengthW(next->EditHwnd); + else if (sel == POS_SELALL) + end = -1; + SendMessageW(next->EditHwnd, EM_SETSEL, start, end); + } + return TRUE; + } + + } + return FALSE; +} + + +/* + * period: move and select the text in the next field to the right if + * the current field is not empty(l!=0), we are not in the + * left most position, and nothing is selected(startsel==endsel) + * + * spacebar: same behavior as period + * + * alpha characters: completely ignored + * + * digits: accepted when field text length < 2 ignored otherwise. + * when 3 numbers have been entered into the field the value + * of the field is checked, if the field value exceeds the + * maximum value and is changed the field remains the current + * field, otherwise focus moves to the field to the right + * + * tab: change focus from the current ipaddress control to the next + * control in the tab order + * + * right arrow: move to the field on the right to the left most + * position in that field if no text is selected, + * we are in the right most position in the field, + * we are not in the right most field + * + * left arrow: move to the field on the left to the right most + * position in that field if no text is selected, + * we are in the left most position in the current field + * and we are not in the left most field + * + * backspace: delete the character to the left of the cursor position, + * if none are present move to the field on the left if + * we are not in the left most field and delete the right + * most digit in that field while keeping the cursor + * on the right side of the field + */ +LRESULT CALLBACK +IPADDRESS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + HWND Self = (HWND)GetPropW (hwnd, IP_SUBCLASS_PROP); + IPADDRESS_INFO *infoPtr = (IPADDRESS_INFO *)GetWindowLongPtrW (Self, 0); + CHAR c = (CHAR)wParam; + INT index, len = 0, startsel, endsel; + IPPART_INFO *part; + + TRACE("(hwnd=%p msg=0x%x wparam=0x%x lparam=0x%lx)\n", hwnd, uMsg, wParam, lParam); + + if ( (index = IPADDRESS_GetPartIndex(infoPtr, hwnd)) < 0) return 0; + part = &infoPtr->Part[index]; + + if (uMsg == WM_CHAR || uMsg == WM_KEYDOWN) { + len = GetWindowTextLengthW (hwnd); + SendMessageW(hwnd, EM_GETSEL, (WPARAM)&startsel, (LPARAM)&endsel); + } + switch (uMsg) { + case WM_CHAR: + if(isdigit(c)) { + if(len == 2 && startsel==endsel && endsel==len) { + /* process the digit press before we check the field */ + int return_val = CallWindowProcW (part->OrigProc, hwnd, uMsg, wParam, lParam); + + /* if the field value was changed stay at the current field */ + if(!IPADDRESS_ConstrainField(infoPtr, index)) + IPADDRESS_GotoNextField (infoPtr, index, POS_DEFAULT); + + return return_val; + } else if (len == 3 && startsel==endsel && endsel==len) + IPADDRESS_GotoNextField (infoPtr, index, POS_SELALL); + else if (len < 3) break; + } else if(c == '.' || c == ' ') { + if(len && startsel==endsel && startsel != 0) { + IPADDRESS_GotoNextField(infoPtr, index, POS_SELALL); + } + } else if (c == VK_BACK) break; + return 0; + + case WM_KEYDOWN: + switch(c) { + case VK_RIGHT: + if(startsel==endsel && startsel==len) { + IPADDRESS_GotoNextField(infoPtr, index, POS_LEFT); + return 0; + } + break; + case VK_LEFT: + if(startsel==0 && startsel==endsel && index > 0) { + IPADDRESS_GotoNextField(infoPtr, index - 2, POS_RIGHT); + return 0; + } + break; + case VK_BACK: + if(startsel==endsel && startsel==0 && index > 0) { + IPPART_INFO *prev = &infoPtr->Part[index-1]; + WCHAR val[10]; + + if(GetWindowTextW(prev->EditHwnd, val, 5)) { + val[lstrlenW(val) - 1] = 0; + SetWindowTextW(prev->EditHwnd, val); + } + + IPADDRESS_GotoNextField(infoPtr, index - 2, POS_RIGHT); + return 0; + } + break; + } + break; + case WM_KILLFOCUS: + if (IPADDRESS_GetPartIndex(infoPtr, (HWND)wParam) < 0) + IPADDRESS_Notify(infoPtr, EN_KILLFOCUS); + break; + case WM_SETFOCUS: + if (IPADDRESS_GetPartIndex(infoPtr, (HWND)wParam) < 0) + IPADDRESS_Notify(infoPtr, EN_SETFOCUS); + break; + } + return CallWindowProcW (part->OrigProc, hwnd, uMsg, wParam, lParam); +} + + +static LRESULT WINAPI +IPADDRESS_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + IPADDRESS_INFO *infoPtr = (IPADDRESS_INFO *)GetWindowLongPtrW (hwnd, 0); + + TRACE("(hwnd=%p msg=0x%x wparam=0x%x lparam=0x%lx)\n", hwnd, uMsg, wParam, lParam); + + if (!infoPtr && (uMsg != WM_CREATE)) + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + + switch (uMsg) + { + case WM_CREATE: + return IPADDRESS_Create (hwnd, (LPCREATESTRUCTA)lParam); + + case WM_DESTROY: + return IPADDRESS_Destroy (infoPtr); + + case WM_ENABLE: + return IPADDRESS_Enable (infoPtr, (BOOL)wParam); + break; + + case WM_PAINT: + return IPADDRESS_Paint (infoPtr, (HDC)wParam); + + case WM_COMMAND: + switch(wParam >> 16) { + case EN_CHANGE: + IPADDRESS_Notify(infoPtr, EN_CHANGE); + break; + case EN_KILLFOCUS: + IPADDRESS_ConstrainField(infoPtr, IPADDRESS_GetPartIndex(infoPtr, (HWND)lParam)); + break; + } + break; + + case IPM_CLEARADDRESS: + IPADDRESS_ClearAddress (infoPtr); + break; + + case IPM_SETADDRESS: + return IPADDRESS_SetAddress (infoPtr, (DWORD)lParam); + + case IPM_GETADDRESS: + return IPADDRESS_GetAddress (infoPtr, (LPDWORD)lParam); + + case IPM_SETRANGE: + return IPADDRESS_SetRange (infoPtr, (int)wParam, (WORD)lParam); + + case IPM_SETFOCUS: + IPADDRESS_SetFocusToField (infoPtr, (int)wParam); + break; + + case IPM_ISBLANK: + return IPADDRESS_IsBlank (infoPtr); + + default: + if ((uMsg >= WM_USER) && (uMsg < WM_APP)) + ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam); + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + } + return 0; +} + + +void IPADDRESS_Register (void) +{ + WNDCLASSW wndClass; + + ZeroMemory (&wndClass, sizeof(WNDCLASSW)); + wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; + wndClass.lpfnWndProc = IPADDRESS_WindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(IPADDRESS_INFO *); + wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_IBEAM); + wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wndClass.lpszClassName = WC_IPADDRESSW; + + RegisterClassW (&wndClass); +} + + +void IPADDRESS_Unregister (void) +{ + UnregisterClassW (WC_IPADDRESSW, NULL); +} diff --git a/reactos/lib/comctl32/listview.c b/reactos/lib/comctl32/listview.c index 56f2123d173..9f2a927da38 100644 --- a/reactos/lib/comctl32/listview.c +++ b/reactos/lib/comctl32/listview.c @@ -1,9666 +1,9666 @@ -/* - * Listview control - * - * Copyright 1998, 1999 Eric Kohl - * Copyright 1999 Luc Tourangeau - * Copyright 2000 Jason Mawdsley - * Copyright 2001 CodeWeavers Inc. - * Copyright 2002 Dimitrie O. Paun - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTES - * - * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on May. 20, 2005, by James Hawkins. - * - * Unless otherwise noted, we believe this code to be complete, as per - * the specification mentioned above. - * If you discover missing features, or bugs, please note them below. - * - * TODO: - * - * Default Message Processing - * -- EN_KILLFOCUS should be handled in WM_COMMAND - * -- WM_CREATE: create the icon and small icon image lists at this point only if - * the LVS_SHAREIMAGELISTS style is not specified. - * -- WM_ERASEBKGND: forward this message to the parent window if the bkgnd - * color is CLR_NONE. - * -- WM_WINDOWPOSCHANGED: arrange the list items if the current view is icon - * or small icon and the LVS_AUTOARRANGE style is specified. - * -- WM_TIMER - * -- WM_WININICHANGE - * - * Features - * -- Hot item handling, mouse hovering - * -- Workareas support - * -- Tilemode support - * -- Groups support - * - * Bugs - * -- Expand large item in ICON mode when the cursor is flying over the icon or text. - * -- Support CustomDraw options for _WIN32_IE >= 0x560 (see NMLVCUSTOMDRAW docs). - * -- LVA_SNAPTOGRID not implemented - * -- LISTVIEW_ApproximateViewRect partially implemented - * -- LISTVIEW_[GS]etColumnOrderArray stubs - * -- LISTVIEW_SetColumnWidth ignores header images & bitmap - * -- LISTVIEW_SetIconSpacing is incomplete - * -- LISTVIEW_SortItems is broken - * -- LISTVIEW_StyleChanged doesn't handle some changes too well - * - * Speedups - * -- LISTVIEW_GetNextItem needs to be rewritten. It is currently - * linear in the number of items in the list, and this is - * unacceptable for large lists. - * -- in sorted mode, LISTVIEW_InsertItemT sorts the array, - * instead of inserting in the right spot - * -- we should keep an ordered array of coordinates in iconic mode - * this would allow to frame items (iterator_frameditems), - * and find nearest item (LVFI_NEARESTXY) a lot more efficiently - * - * Flags - * -- LVIF_COLUMNS - * -- LVIF_GROUPID - * -- LVIF_NORECOMPUTE - * - * States - * -- LVIS_ACTIVATING (not currently supported by comctl32.dll version 6.0) - * -- LVIS_CUT - * -- LVIS_DROPHILITED - * -- LVIS_OVERLAYMASK - * - * Styles - * -- LVS_NOLABELWRAP - * -- LVS_NOSCROLL (see Q137520) - * -- LVS_SORTASCENDING, LVS_SORTDESCENDING - * -- LVS_ALIGNTOP - * -- LVS_TYPESTYLEMASK - * - * Extended Styles - * -- LVS_EX_BORDERSELECT - * -- LVS_EX_FLATSB - * -- LVS_EX_GRIDLINES - * -- LVS_EX_HEADERDRAGDROP - * -- LVS_EX_INFOTIP - * -- LVS_EX_LABELTIP - * -- LVS_EX_MULTIWORKAREAS - * -- LVS_EX_ONECLICKACTIVATE - * -- LVS_EX_REGIONAL - * -- LVS_EX_SIMPLESELECT - * -- LVS_EX_TRACKSELECT - * -- LVS_EX_TWOCLICKACTIVATE - * -- LVS_EX_UNDERLINECOLD - * -- LVS_EX_UNDERLINEHOT - * - * Notifications: - * -- LVN_BEGINSCROLL, LVN_ENDSCROLL - * -- LVN_GETINFOTIP - * -- LVN_HOTTRACK - * -- LVN_MARQUEEBEGIN - * -- LVN_ODFINDITEM - * -- LVN_SETDISPINFO - * -- NM_HOVER - * -- LVN_BEGINRDRAG - * - * Messages: - * -- LVM_CANCELEDITLABEL - * -- LVM_ENABLEGROUPVIEW - * -- LVM_GETBKIMAGE, LVM_SETBKIMAGE - * -- LVM_GETGROUPINFO, LVM_SETGROUPINFO - * -- LVM_GETGROUPMETRICS, LVM_SETGROUPMETRICS - * -- LVM_GETINSERTMARK, LVM_SETINSERTMARK - * -- LVM_GETINSERTMARKCOLOR, LVM_SETINSERTMARKCOLOR - * -- LVM_GETINSERTMARKRECT - * -- LVM_GETNUMBEROFWORKAREAS - * -- LVM_GETOUTLINECOLOR, LVM_SETOUTLINECOLOR - * -- LVM_GETSELECTEDCOLUMN, LVM_SETSELECTEDCOLUMN - * -- LVM_GETISEARCHSTRINGW, LVM_GETISEARCHSTRINGA - * -- LVM_GETTILEINFO, LVM_SETTILEINFO - * -- LVM_GETTILEVIEWINFO, LVM_SETTILEVIEWINFO - * -- LVM_GETUNICODEFORMAT, LVM_SETUNICODEFORMAT - * -- LVM_GETVIEW, LVM_SETVIEW - * -- LVM_GETWORKAREAS, LVM_SETWORKAREAS - * -- LVM_HASGROUP, LVM_INSERTGROUP, LVM_REMOVEGROUP, LVM_REMOVEALLGROUPS - * -- LVM_INSERTGROUPSORTED - * -- LVM_INSERTMARKHITTEST - * -- LVM_ISGROUPVIEWENABLED - * -- LVM_MAPIDTOINDEX, LVM_MAPINDEXTOID - * -- LVM_MOVEGROUP - * -- LVM_MOVEITEMTOGROUP - * -- LVM_SETINFOTIP - * -- LVM_SETTILEWIDTH - * -- LVM_SORTGROUPS - * -- LVM_SORTITEMSEX - * - * Macros: - * -- ListView_GetCheckSate, ListView_SetCheckState - * -- ListView_GetHoverTime, ListView_SetHoverTime - * -- ListView_GetISearchString - * -- ListView_GetNumberOfWorkAreas - * -- ListView_GetOrigin - * -- ListView_GetTextBkColor - * -- ListView_GetUnicodeFormat, ListView_SetUnicodeFormat - * -- ListView_GetWorkAreas, ListView_SetWorkAreas - * -- ListView_SortItemsEx - * - * Functions: - * -- LVGroupComparE - * - * Known differences in message stream from native control (not known if - * these differences cause problems): - * LVM_INSERTITEM issues LVM_SETITEMSTATE and LVM_SETITEM in certain cases. - * LVM_SETITEM does not always issue LVN_ITEMCHANGING/LVN_ITEMCHANGED. - * WM_CREATE does not issue WM_QUERYUISTATE and associated registry - * processing for "USEDOUBLECLICKTIME". - */ - -#include "config.h" -#include "wine/port.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "winnt.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "comctl32.h" - -#include "wine/debug.h" -#include "wine/unicode.h" - -WINE_DEFAULT_DEBUG_CHANNEL(listview); - -/* make sure you set this to 0 for production use! */ -#define DEBUG_RANGES 1 - -typedef struct tagCOLUMN_INFO -{ - RECT rcHeader; /* tracks the header's rectangle */ - int fmt; /* same as LVCOLUMN.fmt */ -} COLUMN_INFO; - -typedef struct tagITEMHDR -{ - LPWSTR pszText; - INT iImage; -} ITEMHDR, *LPITEMHDR; - -typedef struct tagSUBITEM_INFO -{ - ITEMHDR hdr; - INT iSubItem; -} SUBITEM_INFO; - -typedef struct tagITEM_INFO -{ - ITEMHDR hdr; - UINT state; - LPARAM lParam; - INT iIndent; -} ITEM_INFO; - -typedef struct tagRANGE -{ - INT lower; - INT upper; -} RANGE; - -typedef struct tagRANGES -{ - HDPA hdpa; -} *RANGES; - -typedef struct tagITERATOR -{ - INT nItem; - INT nSpecial; - RANGE range; - RANGES ranges; - INT index; -} ITERATOR; - -typedef struct tagLISTVIEW_INFO -{ - HWND hwndSelf; - HBRUSH hBkBrush; - COLORREF clrBk; - COLORREF clrText; - COLORREF clrTextBk; - COLORREF clrTextBkDefault; - HIMAGELIST himlNormal; - HIMAGELIST himlSmall; - HIMAGELIST himlState; - BOOL bLButtonDown; - BOOL bRButtonDown; - POINT ptClickPos; /* point where the user clicked */ - BOOL bNoItemMetrics; /* flags if item metrics are not yet computed */ - INT nItemHeight; - INT nItemWidth; - RANGES selectionRanges; - INT nSelectionMark; - INT nHotItem; - SHORT notifyFormat; - HWND hwndNotify; - RECT rcList; /* This rectangle is really the window - * client rectangle possibly reduced by the - * horizontal scroll bar and/or header - see - * LISTVIEW_UpdateSize. This rectangle offset - * by the LISTVIEW_GetOrigin value is in - * client coordinates */ - SIZE iconSize; - SIZE iconSpacing; - SIZE iconStateSize; - UINT uCallbackMask; - HWND hwndHeader; - HCURSOR hHotCursor; - HFONT hDefaultFont; - HFONT hFont; - INT ntmHeight; /* Some cached metrics of the font used */ - INT ntmMaxCharWidth; /* by the listview to draw items */ - INT nEllipsisWidth; - BOOL bRedraw; /* Turns on/off repaints & invalidations */ - BOOL bAutoarrange; /* Autoarrange flag when NOT in LVS_AUTOARRANGE */ - BOOL bFocus; - BOOL bDoChangeNotify; /* send change notification messages? */ - INT nFocusedItem; - RECT rcFocus; - DWORD dwStyle; /* the cached window GWL_STYLE */ - DWORD dwLvExStyle; /* extended listview style */ - INT nItemCount; /* the number of items in the list */ - HDPA hdpaItems; /* array ITEM_INFO pointers */ - HDPA hdpaPosX; /* maintains the (X, Y) coordinates of the */ - HDPA hdpaPosY; /* items in LVS_ICON, and LVS_SMALLICON modes */ - HDPA hdpaColumns; /* array of COLUMN_INFO pointers */ - POINT currIconPos; /* this is the position next icon will be placed */ - PFNLVCOMPARE pfnCompare; - LPARAM lParamSort; - HWND hwndEdit; - WNDPROC EditWndProc; - INT nEditLabelItem; - DWORD dwHoverTime; - HWND hwndToolTip; - - DWORD cditemmode; /* Keep the custom draw flags for an item/row */ - - DWORD lastKeyPressTimestamp; - WPARAM charCode; - INT nSearchParamLength; - WCHAR szSearchParam[ MAX_PATH ]; - BOOL bIsDrawing; - INT nMeasureItemHeight; -} LISTVIEW_INFO; - -/* - * constants - */ -/* How many we debug buffer to allocate */ -#define DEBUG_BUFFERS 20 -/* The size of a single debug bbuffer */ -#define DEBUG_BUFFER_SIZE 256 - -/* Internal interface to LISTVIEW_HScroll and LISTVIEW_VScroll */ -#define SB_INTERNAL -1 - -/* maximum size of a label */ -#define DISP_TEXT_SIZE 512 - -/* padding for items in list and small icon display modes */ -#define WIDTH_PADDING 12 - -/* padding for items in list, report and small icon display modes */ -#define HEIGHT_PADDING 1 - -/* offset of items in report display mode */ -#define REPORT_MARGINX 2 - -/* padding for icon in large icon display mode - * ICON_TOP_PADDING_NOTHITABLE - space between top of box and area - * that HITTEST will see. - * ICON_TOP_PADDING_HITABLE - spacing between above and icon. - * ICON_TOP_PADDING - sum of the two above. - * ICON_BOTTOM_PADDING - between bottom of icon and top of text - * LABEL_HOR_PADDING - between text and sides of box - * LABEL_VERT_PADDING - between bottom of text and end of box - * - * ICON_LR_PADDING - additional width above icon size. - * ICON_LR_HALF - half of the above value - */ -#define ICON_TOP_PADDING_NOTHITABLE 2 -#define ICON_TOP_PADDING_HITABLE 2 -#define ICON_TOP_PADDING (ICON_TOP_PADDING_NOTHITABLE + ICON_TOP_PADDING_HITABLE) -#define ICON_BOTTOM_PADDING 4 -#define LABEL_HOR_PADDING 5 -#define LABEL_VERT_PADDING 7 -#define ICON_LR_PADDING 16 -#define ICON_LR_HALF (ICON_LR_PADDING/2) - -/* default label width for items in list and small icon display modes */ -#define DEFAULT_LABEL_WIDTH 40 - -/* default column width for items in list display mode */ -#define DEFAULT_COLUMN_WIDTH 128 - -/* Size of "line" scroll for V & H scrolls */ -#define LISTVIEW_SCROLL_ICON_LINE_SIZE 37 - -/* Padding betwen image and label */ -#define IMAGE_PADDING 2 - -/* Padding behind the label */ -#define TRAILING_LABEL_PADDING 12 -#define TRAILING_HEADER_PADDING 11 - -/* Border for the icon caption */ -#define CAPTION_BORDER 2 - -/* Standard DrawText flags */ -#define LV_ML_DT_FLAGS (DT_TOP | DT_NOPREFIX | DT_EDITCONTROL | DT_CENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS | DT_END_ELLIPSIS) -#define LV_FL_DT_FLAGS (DT_TOP | DT_NOPREFIX | DT_EDITCONTROL | DT_CENTER | DT_WORDBREAK | DT_NOCLIP) -#define LV_SL_DT_FLAGS (DT_VCENTER | DT_NOPREFIX | DT_EDITCONTROL | DT_SINGLELINE | DT_WORD_ELLIPSIS | DT_END_ELLIPSIS) - -/* The time in milliseconds to reset the search in the list */ -#define KEY_DELAY 450 - -/* Dump the LISTVIEW_INFO structure to the debug channel */ -#define LISTVIEW_DUMP(iP) do { \ - TRACE("hwndSelf=%p, clrBk=0x%06lx, clrText=0x%06lx, clrTextBk=0x%06lx, ItemHeight=%d, ItemWidth=%d, Style=0x%08lx\n", \ - iP->hwndSelf, iP->clrBk, iP->clrText, iP->clrTextBk, \ - iP->nItemHeight, iP->nItemWidth, infoPtr->dwStyle); \ - TRACE("hwndSelf=%p, himlNor=%p, himlSml=%p, himlState=%p, Focused=%d, Hot=%d, exStyle=0x%08lx, Focus=%d\n", \ - iP->hwndSelf, iP->himlNormal, iP->himlSmall, iP->himlState, \ - iP->nFocusedItem, iP->nHotItem, iP->dwLvExStyle, iP->bFocus ); \ - TRACE("hwndSelf=%p, ntmH=%d, icSz.cx=%ld, icSz.cy=%ld, icSp.cx=%ld, icSp.cy=%ld, notifyFmt=%d\n", \ - iP->hwndSelf, iP->ntmHeight, iP->iconSize.cx, iP->iconSize.cy, \ - iP->iconSpacing.cx, iP->iconSpacing.cy, iP->notifyFormat); \ - TRACE("hwndSelf=%p, rcList=%s\n", iP->hwndSelf, debugrect(&iP->rcList)); \ -} while(0) - -/* - * forward declarations - */ -static BOOL LISTVIEW_GetItemT(LISTVIEW_INFO *, LPLVITEMW, BOOL); -static void LISTVIEW_GetItemBox(LISTVIEW_INFO *, INT, LPRECT); -static void LISTVIEW_GetItemOrigin(LISTVIEW_INFO *, INT, LPPOINT); -static BOOL LISTVIEW_GetItemPosition(LISTVIEW_INFO *, INT, LPPOINT); -static BOOL LISTVIEW_GetItemRect(LISTVIEW_INFO *, INT, LPRECT); -static INT LISTVIEW_GetLabelWidth(LISTVIEW_INFO *, INT); -static void LISTVIEW_GetOrigin(LISTVIEW_INFO *, LPPOINT); -static BOOL LISTVIEW_GetViewRect(LISTVIEW_INFO *, LPRECT); -static void LISTVIEW_SetGroupSelection(LISTVIEW_INFO *, INT); -static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *, const LVITEMW *, BOOL); -static void LISTVIEW_UpdateScroll(LISTVIEW_INFO *); -static void LISTVIEW_SetSelection(LISTVIEW_INFO *, INT); -static void LISTVIEW_UpdateSize(LISTVIEW_INFO *); -static HWND LISTVIEW_EditLabelT(LISTVIEW_INFO *, INT, BOOL); -static LRESULT LISTVIEW_Command(LISTVIEW_INFO *, WPARAM, LPARAM); -static BOOL LISTVIEW_SortItems(LISTVIEW_INFO *, PFNLVCOMPARE, LPARAM); -static INT LISTVIEW_GetStringWidthT(LISTVIEW_INFO *, LPCWSTR, BOOL); -static BOOL LISTVIEW_KeySelection(LISTVIEW_INFO *, INT); -static UINT LISTVIEW_GetItemState(LISTVIEW_INFO *, INT, UINT); -static BOOL LISTVIEW_SetItemState(LISTVIEW_INFO *, INT, const LVITEMW *); -static LRESULT LISTVIEW_VScroll(LISTVIEW_INFO *, INT, INT, HWND); -static LRESULT LISTVIEW_HScroll(LISTVIEW_INFO *, INT, INT, HWND); -static INT LISTVIEW_GetTopIndex(LISTVIEW_INFO *); -static BOOL LISTVIEW_EnsureVisible(LISTVIEW_INFO *, INT, BOOL); -static HWND CreateEditLabelT(LISTVIEW_INFO *, LPCWSTR, DWORD, INT, INT, INT, INT, BOOL); -static HIMAGELIST LISTVIEW_SetImageList(LISTVIEW_INFO *, INT, HIMAGELIST); -static INT LISTVIEW_HitTest(LISTVIEW_INFO *, LPLVHITTESTINFO, BOOL, BOOL); - -/******** Text handling functions *************************************/ - -/* A text pointer is either NULL, LPSTR_TEXTCALLBACK, or points to a - * text string. The string may be ANSI or Unicode, in which case - * the boolean isW tells us the type of the string. - * - * The name of the function tell what type of strings it expects: - * W: Unicode, T: ANSI/Unicode - function of isW - */ - -static inline BOOL is_textW(LPCWSTR text) -{ - return text != NULL && text != LPSTR_TEXTCALLBACKW; -} - -static inline BOOL is_textT(LPCWSTR text, BOOL isW) -{ - /* we can ignore isW since LPSTR_TEXTCALLBACKW == LPSTR_TEXTCALLBACKA */ - return is_textW(text); -} - -static inline int textlenT(LPCWSTR text, BOOL isW) -{ - return !is_textT(text, isW) ? 0 : - isW ? lstrlenW(text) : lstrlenA((LPCSTR)text); -} - -static inline void textcpynT(LPWSTR dest, BOOL isDestW, LPCWSTR src, BOOL isSrcW, INT max) -{ - if (isDestW) - if (isSrcW) lstrcpynW(dest, src, max); - else MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1, dest, max); - else - if (isSrcW) WideCharToMultiByte(CP_ACP, 0, src, -1, (LPSTR)dest, max, NULL, NULL); - else lstrcpynA((LPSTR)dest, (LPCSTR)src, max); -} - -static inline LPWSTR textdupTtoW(LPCWSTR text, BOOL isW) -{ - LPWSTR wstr = (LPWSTR)text; - - if (!isW && is_textT(text, isW)) - { - INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)text, -1, NULL, 0); - wstr = Alloc(len * sizeof(WCHAR)); - if (wstr) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)text, -1, wstr, len); - } - TRACE(" wstr=%s\n", text == LPSTR_TEXTCALLBACKW ? "(callback)" : debugstr_w(wstr)); - return wstr; -} - -static inline void textfreeT(LPWSTR wstr, BOOL isW) -{ - if (!isW && is_textT(wstr, isW)) Free (wstr); -} - -/* - * dest is a pointer to a Unicode string - * src is a pointer to a string (Unicode if isW, ANSI if !isW) - */ -static BOOL textsetptrT(LPWSTR *dest, LPWSTR src, BOOL isW) -{ - BOOL bResult = TRUE; - - if (src == LPSTR_TEXTCALLBACKW) - { - if (is_textW(*dest)) Free(*dest); - *dest = LPSTR_TEXTCALLBACKW; - } - else - { - LPWSTR pszText = textdupTtoW(src, isW); - if (*dest == LPSTR_TEXTCALLBACKW) *dest = NULL; - bResult = Str_SetPtrW(dest, pszText); - textfreeT(pszText, isW); - } - return bResult; -} - -/* - * compares a Unicode to a Unicode/ANSI text string - */ -static inline int textcmpWT(LPCWSTR aw, LPCWSTR bt, BOOL isW) -{ - if (!aw) return bt ? -1 : 0; - if (!bt) return aw ? 1 : 0; - if (aw == LPSTR_TEXTCALLBACKW) - return bt == LPSTR_TEXTCALLBACKW ? 0 : -1; - if (bt != LPSTR_TEXTCALLBACKW) - { - LPWSTR bw = textdupTtoW(bt, isW); - int r = bw ? lstrcmpW(aw, bw) : 1; - textfreeT(bw, isW); - return r; - } - - return 1; -} - -static inline int lstrncmpiW(LPCWSTR s1, LPCWSTR s2, int n) -{ - int res; - - n = min(min(n, strlenW(s1)), strlenW(s2)); - res = CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, s1, n, s2, n); - return res ? res - sizeof(WCHAR) : res; -} - -/******** Debugging functions *****************************************/ - -static inline LPCSTR debugtext_t(LPCWSTR text, BOOL isW) -{ - if (text == LPSTR_TEXTCALLBACKW) return "(callback)"; - return isW ? debugstr_w(text) : debugstr_a((LPCSTR)text); -} - -static inline LPCSTR debugtext_tn(LPCWSTR text, BOOL isW, INT n) -{ - if (text == LPSTR_TEXTCALLBACKW) return "(callback)"; - n = min(textlenT(text, isW), n); - return isW ? debugstr_wn(text, n) : debugstr_an((LPCSTR)text, n); -} - -static char* debug_getbuf(void) -{ - static int index = 0; - static char buffers[DEBUG_BUFFERS][DEBUG_BUFFER_SIZE]; - return buffers[index++ % DEBUG_BUFFERS]; -} - -static inline const char* debugrange(const RANGE *lprng) -{ - if (lprng) - { - char* buf = debug_getbuf(); - snprintf(buf, DEBUG_BUFFER_SIZE, "[%d, %d)", lprng->lower, lprng->upper); - return buf; - } else return "(null)"; -} - -static inline const char* debugpoint(const POINT *lppt) -{ - if (lppt) - { - char* buf = debug_getbuf(); - snprintf(buf, DEBUG_BUFFER_SIZE, "(%ld, %ld)", lppt->x, lppt->y); - return buf; - } else return "(null)"; -} - -static inline const char* debugrect(const RECT *rect) -{ - if (rect) - { - char* buf = debug_getbuf(); - snprintf(buf, DEBUG_BUFFER_SIZE, "[(%ld, %ld);(%ld, %ld)]", - rect->left, rect->top, rect->right, rect->bottom); - return buf; - } else return "(null)"; -} - -static const char* debugscrollinfo(const SCROLLINFO *pScrollInfo) -{ - char* buf = debug_getbuf(), *text = buf; - int len, size = DEBUG_BUFFER_SIZE; - - if (pScrollInfo == NULL) return "(null)"; - len = snprintf(buf, size, "{cbSize=%d, ", pScrollInfo->cbSize); - if (len == -1) goto end; buf += len; size -= len; - if (pScrollInfo->fMask & SIF_RANGE) - len = snprintf(buf, size, "nMin=%d, nMax=%d, ", pScrollInfo->nMin, pScrollInfo->nMax); - else len = 0; - if (len == -1) goto end; buf += len; size -= len; - if (pScrollInfo->fMask & SIF_PAGE) - len = snprintf(buf, size, "nPage=%u, ", pScrollInfo->nPage); - else len = 0; - if (len == -1) goto end; buf += len; size -= len; - if (pScrollInfo->fMask & SIF_POS) - len = snprintf(buf, size, "nPos=%d, ", pScrollInfo->nPos); - else len = 0; - if (len == -1) goto end; buf += len; size -= len; - if (pScrollInfo->fMask & SIF_TRACKPOS) - len = snprintf(buf, size, "nTrackPos=%d, ", pScrollInfo->nTrackPos); - else len = 0; - if (len == -1) goto end; buf += len; size -= len; - goto undo; -end: - buf = text + strlen(text); -undo: - if (buf - text > 2) { buf[-2] = '}'; buf[-1] = 0; } - return text; -} - -static const char* debugnmlistview(const NMLISTVIEW *plvnm) -{ - if (plvnm) - { - char* buf = debug_getbuf(); - snprintf(buf, DEBUG_BUFFER_SIZE, "iItem=%d, iSubItem=%d, uNewState=0x%x," - " uOldState=0x%x, uChanged=0x%x, ptAction=%s, lParam=%ld\n", - plvnm->iItem, plvnm->iSubItem, plvnm->uNewState, plvnm->uOldState, - plvnm->uChanged, debugpoint(&plvnm->ptAction), plvnm->lParam); - return buf; - } else return "(null)"; -} - -static const char* debuglvitem_t(const LVITEMW *lpLVItem, BOOL isW) -{ - char* buf = debug_getbuf(), *text = buf; - int len, size = DEBUG_BUFFER_SIZE; - - if (lpLVItem == NULL) return "(null)"; - len = snprintf(buf, size, "{iItem=%d, iSubItem=%d, ", lpLVItem->iItem, lpLVItem->iSubItem); - if (len == -1) goto end; buf += len; size -= len; - if (lpLVItem->mask & LVIF_STATE) - len = snprintf(buf, size, "state=%x, stateMask=%x, ", lpLVItem->state, lpLVItem->stateMask); - else len = 0; - if (len == -1) goto end; buf += len; size -= len; - if (lpLVItem->mask & LVIF_TEXT) - len = snprintf(buf, size, "pszText=%s, cchTextMax=%d, ", debugtext_tn(lpLVItem->pszText, isW, 80), lpLVItem->cchTextMax); - else len = 0; - if (len == -1) goto end; buf += len; size -= len; - if (lpLVItem->mask & LVIF_IMAGE) - len = snprintf(buf, size, "iImage=%d, ", lpLVItem->iImage); - else len = 0; - if (len == -1) goto end; buf += len; size -= len; - if (lpLVItem->mask & LVIF_PARAM) - len = snprintf(buf, size, "lParam=%lx, ", lpLVItem->lParam); - else len = 0; - if (len == -1) goto end; buf += len; size -= len; - if (lpLVItem->mask & LVIF_INDENT) - len = snprintf(buf, size, "iIndent=%d, ", lpLVItem->iIndent); - else len = 0; - if (len == -1) goto end; buf += len; size -= len; - goto undo; -end: - buf = text + strlen(text); -undo: - if (buf - text > 2) { buf[-2] = '}'; buf[-1] = 0; } - return text; -} - -static const char* debuglvcolumn_t(const LVCOLUMNW *lpColumn, BOOL isW) -{ - char* buf = debug_getbuf(), *text = buf; - int len, size = DEBUG_BUFFER_SIZE; - - if (lpColumn == NULL) return "(null)"; - len = snprintf(buf, size, "{"); - if (len == -1) goto end; buf += len; size -= len; - if (lpColumn->mask & LVCF_SUBITEM) - len = snprintf(buf, size, "iSubItem=%d, ", lpColumn->iSubItem); - else len = 0; - if (len == -1) goto end; buf += len; size -= len; - if (lpColumn->mask & LVCF_FMT) - len = snprintf(buf, size, "fmt=%x, ", lpColumn->fmt); - else len = 0; - if (len == -1) goto end; buf += len; size -= len; - if (lpColumn->mask & LVCF_WIDTH) - len = snprintf(buf, size, "cx=%d, ", lpColumn->cx); - else len = 0; - if (len == -1) goto end; buf += len; size -= len; - if (lpColumn->mask & LVCF_TEXT) - len = snprintf(buf, size, "pszText=%s, cchTextMax=%d, ", debugtext_tn(lpColumn->pszText, isW, 80), lpColumn->cchTextMax); - else len = 0; - if (len == -1) goto end; buf += len; size -= len; - if (lpColumn->mask & LVCF_IMAGE) - len = snprintf(buf, size, "iImage=%d, ", lpColumn->iImage); - else len = 0; - if (len == -1) goto end; buf += len; size -= len; - if (lpColumn->mask & LVCF_ORDER) - len = snprintf(buf, size, "iOrder=%d, ", lpColumn->iOrder); - else len = 0; - if (len == -1) goto end; buf += len; size -= len; - goto undo; -end: - buf = text + strlen(text); -undo: - if (buf - text > 2) { buf[-2] = '}'; buf[-1] = 0; } - return text; -} - -static const char* debuglvhittestinfo(const LVHITTESTINFO *lpht) -{ - if (lpht) - { - char* buf = debug_getbuf(); - snprintf(buf, DEBUG_BUFFER_SIZE, "{pt=%s, flags=0x%x, iItem=%d, iSubItem=%d}", - debugpoint(&lpht->pt), lpht->flags, lpht->iItem, lpht->iSubItem); - return buf; - } else return "(null)"; -} - -/* Return the corresponding text for a given scroll value */ -static inline LPCSTR debugscrollcode(int nScrollCode) -{ - switch(nScrollCode) - { - case SB_LINELEFT: return "SB_LINELEFT"; - case SB_LINERIGHT: return "SB_LINERIGHT"; - case SB_PAGELEFT: return "SB_PAGELEFT"; - case SB_PAGERIGHT: return "SB_PAGERIGHT"; - case SB_THUMBPOSITION: return "SB_THUMBPOSITION"; - case SB_THUMBTRACK: return "SB_THUMBTRACK"; - case SB_ENDSCROLL: return "SB_ENDSCROLL"; - case SB_INTERNAL: return "SB_INTERNAL"; - default: return "unknown"; - } -} - - -/******** Notification functions i************************************/ - -static LRESULT notify_hdr(LISTVIEW_INFO *infoPtr, INT code, LPNMHDR pnmh) -{ - LRESULT result; - - TRACE("(code=%d)\n", code); - - pnmh->hwndFrom = infoPtr->hwndSelf; - pnmh->idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); - pnmh->code = code; - result = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, - (WPARAM)pnmh->idFrom, (LPARAM)pnmh); - - TRACE(" <= %ld\n", result); - - return result; -} - -static inline LRESULT notify(LISTVIEW_INFO *infoPtr, INT code) -{ - NMHDR nmh; - return notify_hdr(infoPtr, code, &nmh); -} - -static inline void notify_itemactivate(LISTVIEW_INFO *infoPtr, LVHITTESTINFO *htInfo) -{ - NMITEMACTIVATE nmia; - LVITEMW item; - - if (htInfo) { - nmia.uNewState = 0; - nmia.uOldState = 0; - nmia.uChanged = 0; - nmia.uKeyFlags = 0; - - item.mask = LVIF_PARAM|LVIF_STATE; - item.iItem = htInfo->iItem; - item.iSubItem = 0; - if (LISTVIEW_GetItemT(infoPtr, &item, TRUE)) { - nmia.lParam = item.lParam; - nmia.uOldState = item.state; - nmia.uNewState = item.state | LVIS_ACTIVATING; - nmia.uChanged = LVIF_STATE; - } - - nmia.iItem = htInfo->iItem; - nmia.iSubItem = htInfo->iSubItem; - nmia.ptAction = htInfo->pt; - - if (GetKeyState(VK_SHIFT) & 0x8000) nmia.uKeyFlags |= LVKF_SHIFT; - if (GetKeyState(VK_CONTROL) & 0x8000) nmia.uKeyFlags |= LVKF_CONTROL; - if (GetKeyState(VK_MENU) & 0x8000) nmia.uKeyFlags |= LVKF_ALT; - } - notify_hdr(infoPtr, LVN_ITEMACTIVATE, (LPNMHDR)&nmia); -} - -static inline LRESULT notify_listview(LISTVIEW_INFO *infoPtr, INT code, LPNMLISTVIEW plvnm) -{ - TRACE("(code=%d, plvnm=%s)\n", code, debugnmlistview(plvnm)); - return notify_hdr(infoPtr, code, (LPNMHDR)plvnm); -} - -static LRESULT notify_click(LISTVIEW_INFO *infoPtr, INT code, LVHITTESTINFO *lvht) -{ - NMLISTVIEW nmlv; - LVITEMW item; - - TRACE("code=%d, lvht=%s\n", code, debuglvhittestinfo(lvht)); - ZeroMemory(&nmlv, sizeof(nmlv)); - nmlv.iItem = lvht->iItem; - nmlv.iSubItem = lvht->iSubItem; - nmlv.ptAction = lvht->pt; - item.mask = LVIF_PARAM; - item.iItem = lvht->iItem; - item.iSubItem = 0; - if (LISTVIEW_GetItemT(infoPtr, &item, TRUE)) nmlv.lParam = item.lParam; - return notify_listview(infoPtr, code, &nmlv); -} - -static void notify_deleteitem(LISTVIEW_INFO *infoPtr, INT nItem) -{ - NMLISTVIEW nmlv; - LVITEMW item; - - ZeroMemory(&nmlv, sizeof (NMLISTVIEW)); - nmlv.iItem = nItem; - item.mask = LVIF_PARAM; - item.iItem = nItem; - item.iSubItem = 0; - if (LISTVIEW_GetItemT(infoPtr, &item, TRUE)) nmlv.lParam = item.lParam; - notify_listview(infoPtr, LVN_DELETEITEM, &nmlv); -} - -static int get_ansi_notification(INT unicodeNotificationCode) -{ - switch (unicodeNotificationCode) - { - case LVN_BEGINLABELEDITW: return LVN_BEGINLABELEDITA; - case LVN_ENDLABELEDITW: return LVN_ENDLABELEDITA; - case LVN_GETDISPINFOW: return LVN_GETDISPINFOA; - case LVN_SETDISPINFOW: return LVN_SETDISPINFOA; - case LVN_ODFINDITEMW: return LVN_ODFINDITEMA; - case LVN_GETINFOTIPW: return LVN_GETINFOTIPA; - } - ERR("unknown notification %x\n", unicodeNotificationCode); - assert(FALSE); - return 0; -} - -/* - Send notification. depends on dispinfoW having same - structure as dispinfoA. - infoPtr : listview struct - notificationCode : *Unicode* notification code - pdi : dispinfo structure (can be unicode or ansi) - isW : TRUE if dispinfo is Unicode -*/ -static BOOL notify_dispinfoT(LISTVIEW_INFO *infoPtr, INT notificationCode, LPNMLVDISPINFOW pdi, BOOL isW) -{ - BOOL bResult = FALSE; - BOOL convertToAnsi = FALSE, convertToUnicode = FALSE; - INT cchTempBufMax = 0, savCchTextMax = 0, realNotifCode; - LPWSTR pszTempBuf = NULL, savPszText = NULL; - - if ((pdi->item.mask & LVIF_TEXT) && is_textT(pdi->item.pszText, isW)) - { - convertToAnsi = (isW && infoPtr->notifyFormat == NFR_ANSI); - convertToUnicode = (!isW && infoPtr->notifyFormat == NFR_UNICODE); - } - - if (convertToAnsi || convertToUnicode) - { - if (notificationCode != LVN_GETDISPINFOW) - { - cchTempBufMax = convertToUnicode ? - MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pdi->item.pszText, -1, NULL, 0): - WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, NULL, 0, NULL, NULL); - } - else - { - cchTempBufMax = pdi->item.cchTextMax; - *pdi->item.pszText = 0; /* make sure we don't process garbage */ - } - - pszTempBuf = Alloc( (convertToUnicode ? sizeof(WCHAR) : sizeof(CHAR)) * cchTempBufMax); - if (!pszTempBuf) return FALSE; - - if (convertToUnicode) - MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pdi->item.pszText, -1, - pszTempBuf, cchTempBufMax); - else - WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) pszTempBuf, - cchTempBufMax, NULL, NULL); - - savCchTextMax = pdi->item.cchTextMax; - savPszText = pdi->item.pszText; - pdi->item.pszText = pszTempBuf; - pdi->item.cchTextMax = cchTempBufMax; - } - - if (infoPtr->notifyFormat == NFR_ANSI) - realNotifCode = get_ansi_notification(notificationCode); - else - realNotifCode = notificationCode; - TRACE(" pdi->item=%s\n", debuglvitem_t(&pdi->item, infoPtr->notifyFormat != NFR_ANSI)); - bResult = notify_hdr(infoPtr, realNotifCode, &pdi->hdr); - - if (convertToUnicode || convertToAnsi) - { - if (convertToUnicode) /* note : pointer can be changed by app ! */ - WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) savPszText, - savCchTextMax, NULL, NULL); - else - MultiByteToWideChar(CP_ACP, 0, (LPSTR) pdi->item.pszText, -1, - savPszText, savCchTextMax); - pdi->item.pszText = savPszText; /* restores our buffer */ - pdi->item.cchTextMax = savCchTextMax; - Free (pszTempBuf); - } - return bResult; -} - -static void customdraw_fill(NMLVCUSTOMDRAW *lpnmlvcd, LISTVIEW_INFO *infoPtr, HDC hdc, - const RECT *rcBounds, const LVITEMW *lplvItem) -{ - ZeroMemory(lpnmlvcd, sizeof(NMLVCUSTOMDRAW)); - lpnmlvcd->nmcd.hdc = hdc; - lpnmlvcd->nmcd.rc = *rcBounds; - lpnmlvcd->clrTextBk = infoPtr->clrTextBk; - lpnmlvcd->clrText = infoPtr->clrText; - if (!lplvItem) return; - lpnmlvcd->nmcd.dwItemSpec = lplvItem->iItem + 1; - lpnmlvcd->iSubItem = lplvItem->iSubItem; - if (lplvItem->state & LVIS_SELECTED) lpnmlvcd->nmcd.uItemState |= CDIS_SELECTED; - if (lplvItem->state & LVIS_FOCUSED) lpnmlvcd->nmcd.uItemState |= CDIS_FOCUS; - if (lplvItem->iItem == infoPtr->nHotItem) lpnmlvcd->nmcd.uItemState |= CDIS_HOT; - lpnmlvcd->nmcd.lItemlParam = lplvItem->lParam; -} - -static inline DWORD notify_customdraw (LISTVIEW_INFO *infoPtr, DWORD dwDrawStage, NMLVCUSTOMDRAW *lpnmlvcd) -{ - BOOL isForItem = (lpnmlvcd->nmcd.dwItemSpec != 0); - DWORD result; - - lpnmlvcd->nmcd.dwDrawStage = dwDrawStage; - if (isForItem) lpnmlvcd->nmcd.dwDrawStage |= CDDS_ITEM; - if (lpnmlvcd->iSubItem) lpnmlvcd->nmcd.dwDrawStage |= CDDS_SUBITEM; - if (isForItem) lpnmlvcd->nmcd.dwItemSpec--; - result = notify_hdr(infoPtr, NM_CUSTOMDRAW, &lpnmlvcd->nmcd.hdr); - if (isForItem) lpnmlvcd->nmcd.dwItemSpec++; - return result; -} - -static void prepaint_setup (LISTVIEW_INFO *infoPtr, HDC hdc, NMLVCUSTOMDRAW *lpnmlvcd) -{ - /* apprently, for selected items, we have to override the returned values */ - if (lpnmlvcd->nmcd.uItemState & CDIS_SELECTED) - { - if (infoPtr->bFocus) - { - lpnmlvcd->clrTextBk = comctl32_color.clrHighlight; - lpnmlvcd->clrText = comctl32_color.clrHighlightText; - } - else if (infoPtr->dwStyle & LVS_SHOWSELALWAYS) - { - lpnmlvcd->clrTextBk = comctl32_color.clr3dFace; - lpnmlvcd->clrText = comctl32_color.clrBtnText; - } - } - - /* Set the text attributes */ - if (lpnmlvcd->clrTextBk != CLR_NONE) - { - SetBkMode(hdc, OPAQUE); - if (lpnmlvcd->clrTextBk == CLR_DEFAULT) - SetBkColor(hdc, infoPtr->clrTextBkDefault); - else - SetBkColor(hdc,lpnmlvcd->clrTextBk); - } - else - SetBkMode(hdc, TRANSPARENT); - SetTextColor(hdc, lpnmlvcd->clrText); -} - -static inline DWORD notify_postpaint (LISTVIEW_INFO *infoPtr, NMLVCUSTOMDRAW *lpnmlvcd) -{ - return notify_customdraw(infoPtr, CDDS_POSTPAINT, lpnmlvcd); -} - -/******** Item iterator functions **********************************/ - -static RANGES ranges_create(int count); -static void ranges_destroy(RANGES ranges); -static BOOL ranges_add(RANGES ranges, RANGE range); -static BOOL ranges_del(RANGES ranges, RANGE range); -static void ranges_dump(RANGES ranges); - -static inline BOOL ranges_additem(RANGES ranges, INT nItem) -{ - RANGE range = { nItem, nItem + 1 }; - - return ranges_add(ranges, range); -} - -static inline BOOL ranges_delitem(RANGES ranges, INT nItem) -{ - RANGE range = { nItem, nItem + 1 }; - - return ranges_del(ranges, range); -} - -/*** - * ITERATOR DOCUMENTATION - * - * The iterator functions allow for easy, and convenient iteration - * over items of iterest in the list. Typically, you create a - * iterator, use it, and destroy it, as such: - * ITERATOR i; - * - * iterator_xxxitems(&i, ...); - * while (iterator_{prev,next}(&i) - * { - * //code which uses i.nItem - * } - * iterator_destroy(&i); - * - * where xxx is either: framed, or visible. - * Note that it is important that the code destroys the iterator - * after it's done with it, as the creation of the iterator may - * allocate memory, which thus needs to be freed. - * - * You can iterate both forwards, and backwards through the list, - * by using iterator_next or iterator_prev respectively. - * - * Lower numbered items are draw on top of higher number items in - * LVS_ICON, and LVS_SMALLICON (which are the only modes where - * items may overlap). So, to test items, you should use - * iterator_next - * which lists the items top to bottom (in Z-order). - * For drawing items, you should use - * iterator_prev - * which lists the items bottom to top (in Z-order). - * If you keep iterating over the items after the end-of-items - * marker (-1) is returned, the iterator will start from the - * beginning. Typically, you don't need to test for -1, - * because iterator_{next,prev} will return TRUE if more items - * are to be iterated over, or FALSE otherwise. - * - * Note: the iterator is defined to be bidirectional. That is, - * any number of prev followed by any number of next, or - * five versa, should leave the iterator at the same item: - * prev * n, next * n = next * n, prev * n - * - * The iterator has a notion of an out-of-order, special item, - * which sits at the start of the list. This is used in - * LVS_ICON, and LVS_SMALLICON mode to handle the focused item, - * which needs to be first, as it may overlap other items. - * - * The code is a bit messy because we have: - * - a special item to deal with - * - simple range, or composite range - * - empty range. - * If you find bugs, or want to add features, please make sure you - * always check/modify *both* iterator_prev, and iterator_next. - */ - -/**** - * This function iterates through the items in increasing order, - * but prefixed by the special item, then -1. That is: - * special, 1, 2, 3, ..., n, -1. - * Each item is listed only once. - */ -static inline BOOL iterator_next(ITERATOR* i) -{ - if (i->nItem == -1) - { - i->nItem = i->nSpecial; - if (i->nItem != -1) return TRUE; - } - if (i->nItem == i->nSpecial) - { - if (i->ranges) i->index = 0; - goto pickarange; - } - - i->nItem++; -testitem: - if (i->nItem == i->nSpecial) i->nItem++; - if (i->nItem < i->range.upper) return TRUE; - -pickarange: - if (i->ranges) - { - if (i->index < DPA_GetPtrCount(i->ranges->hdpa)) - i->range = *(RANGE*)DPA_GetPtr(i->ranges->hdpa, i->index++); - else goto end; - } - else if (i->nItem >= i->range.upper) goto end; - - i->nItem = i->range.lower; - if (i->nItem >= 0) goto testitem; -end: - i->nItem = -1; - return FALSE; -} - -/**** - * This function iterates through the items in decreasing order, - * followed by the special item, then -1. That is: - * n, n-1, ..., 3, 2, 1, special, -1. - * Each item is listed only once. - */ -static inline BOOL iterator_prev(ITERATOR* i) -{ - BOOL start = FALSE; - - if (i->nItem == -1) - { - start = TRUE; - if (i->ranges) i->index = DPA_GetPtrCount(i->ranges->hdpa); - goto pickarange; - } - if (i->nItem == i->nSpecial) - { - i->nItem = -1; - return FALSE; - } - -testitem: - i->nItem--; - if (i->nItem == i->nSpecial) i->nItem--; - if (i->nItem >= i->range.lower) return TRUE; - -pickarange: - if (i->ranges) - { - if (i->index > 0) - i->range = *(RANGE*)DPA_GetPtr(i->ranges->hdpa, --i->index); - else goto end; - } - else if (!start && i->nItem < i->range.lower) goto end; - - i->nItem = i->range.upper; - if (i->nItem > 0) goto testitem; -end: - return (i->nItem = i->nSpecial) != -1; -} - -static RANGE iterator_range(ITERATOR* i) -{ - RANGE range; - - if (!i->ranges) return i->range; - - if (DPA_GetPtrCount(i->ranges->hdpa) > 0) - { - range.lower = (*(RANGE*)DPA_GetPtr(i->ranges->hdpa, 0)).lower; - range.upper = (*(RANGE*)DPA_GetPtr(i->ranges->hdpa, DPA_GetPtrCount(i->ranges->hdpa) - 1)).upper; - } - else range.lower = range.upper = 0; - - return range; -} - -/*** - * Releases resources associated with this ierator. - */ -static inline void iterator_destroy(ITERATOR* i) -{ - ranges_destroy(i->ranges); -} - -/*** - * Create an empty iterator. - */ -static inline BOOL iterator_empty(ITERATOR* i) -{ - ZeroMemory(i, sizeof(*i)); - i->nItem = i->nSpecial = i->range.lower = i->range.upper = -1; - return TRUE; -} - -/*** - * Create an iterator over a range. - */ -static inline BOOL iterator_rangeitems(ITERATOR* i, RANGE range) -{ - iterator_empty(i); - i->range = range; - return TRUE; -} - -/*** - * Create an iterator over a bunch of ranges. - * Please note that the iterator will take ownership of the ranges, - * and will free them upon destruction. - */ -static inline BOOL iterator_rangesitems(ITERATOR* i, RANGES ranges) -{ - iterator_empty(i); - i->ranges = ranges; - return TRUE; -} - -/*** - * Creates an iterator over the items which intersect lprc. - */ -static BOOL iterator_frameditems(ITERATOR* i, LISTVIEW_INFO* infoPtr, const RECT *lprc) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - RECT frame = *lprc, rcItem, rcTemp; - POINT Origin; - - /* in case we fail, we want to return an empty iterator */ - if (!iterator_empty(i)) return FALSE; - - LISTVIEW_GetOrigin(infoPtr, &Origin); - - TRACE("(lprc=%s)\n", debugrect(lprc)); - OffsetRect(&frame, -Origin.x, -Origin.y); - - if (uView == LVS_ICON || uView == LVS_SMALLICON) - { - INT nItem; - - if (uView == LVS_ICON && infoPtr->nFocusedItem != -1) - { - LISTVIEW_GetItemBox(infoPtr, infoPtr->nFocusedItem, &rcItem); - if (IntersectRect(&rcTemp, &rcItem, lprc)) - i->nSpecial = infoPtr->nFocusedItem; - } - if (!(iterator_rangesitems(i, ranges_create(50)))) return FALSE; - /* to do better here, we need to have PosX, and PosY sorted */ - TRACE("building icon ranges:\n"); - for (nItem = 0; nItem < infoPtr->nItemCount; nItem++) - { - rcItem.left = (LONG)DPA_GetPtr(infoPtr->hdpaPosX, nItem); - rcItem.top = (LONG)DPA_GetPtr(infoPtr->hdpaPosY, nItem); - rcItem.right = rcItem.left + infoPtr->nItemWidth; - rcItem.bottom = rcItem.top + infoPtr->nItemHeight; - if (IntersectRect(&rcTemp, &rcItem, &frame)) - ranges_additem(i->ranges, nItem); - } - return TRUE; - } - else if (uView == LVS_REPORT) - { - RANGE range; - - if (frame.left >= infoPtr->nItemWidth) return TRUE; - if (frame.top >= infoPtr->nItemHeight * infoPtr->nItemCount) return TRUE; - - range.lower = max(frame.top / infoPtr->nItemHeight, 0); - range.upper = min((frame.bottom - 1) / infoPtr->nItemHeight, infoPtr->nItemCount - 1) + 1; - if (range.upper <= range.lower) return TRUE; - if (!iterator_rangeitems(i, range)) return FALSE; - TRACE(" report=%s\n", debugrange(&i->range)); - } - else - { - INT nPerCol = max((infoPtr->rcList.bottom - infoPtr->rcList.top) / infoPtr->nItemHeight, 1); - INT nFirstRow = max(frame.top / infoPtr->nItemHeight, 0); - INT nLastRow = min((frame.bottom - 1) / infoPtr->nItemHeight, nPerCol - 1); - INT nFirstCol = max(frame.left / infoPtr->nItemWidth, 0); - INT nLastCol = min((frame.right - 1) / infoPtr->nItemWidth, (infoPtr->nItemCount + nPerCol - 1) / nPerCol); - INT lower = nFirstCol * nPerCol + nFirstRow; - RANGE item_range; - INT nCol; - - TRACE("nPerCol=%d, nFirstRow=%d, nLastRow=%d, nFirstCol=%d, nLastCol=%d, lower=%d\n", - nPerCol, nFirstRow, nLastRow, nFirstCol, nLastCol, lower); - - if (nLastCol < nFirstCol || nLastRow < nFirstRow) return TRUE; - - if (!(iterator_rangesitems(i, ranges_create(nLastCol - nFirstCol + 1)))) return FALSE; - TRACE("building list ranges:\n"); - for (nCol = nFirstCol; nCol <= nLastCol; nCol++) - { - item_range.lower = nCol * nPerCol + nFirstRow; - if(item_range.lower >= infoPtr->nItemCount) break; - item_range.upper = min(nCol * nPerCol + nLastRow + 1, infoPtr->nItemCount); - TRACE(" list=%s\n", debugrange(&item_range)); - ranges_add(i->ranges, item_range); - } - } - - return TRUE; -} - -/*** - * Creates an iterator over the items which intersect the visible region of hdc. - */ -static BOOL iterator_visibleitems(ITERATOR *i, LISTVIEW_INFO *infoPtr, HDC hdc) -{ - POINT Origin, Position; - RECT rcItem, rcClip; - INT rgntype; - - rgntype = GetClipBox(hdc, &rcClip); - if (rgntype == NULLREGION) return iterator_empty(i); - if (!iterator_frameditems(i, infoPtr, &rcClip)) return FALSE; - if (rgntype == SIMPLEREGION) return TRUE; - - /* first deal with the special item */ - if (i->nSpecial != -1) - { - LISTVIEW_GetItemBox(infoPtr, i->nSpecial, &rcItem); - if (!RectVisible(hdc, &rcItem)) i->nSpecial = -1; - } - - /* if we can't deal with the region, we'll just go with the simple range */ - LISTVIEW_GetOrigin(infoPtr, &Origin); - TRACE("building visible range:\n"); - if (!i->ranges && i->range.lower < i->range.upper) - { - if (!(i->ranges = ranges_create(50))) return TRUE; - if (!ranges_add(i->ranges, i->range)) - { - ranges_destroy(i->ranges); - i->ranges = 0; - return TRUE; - } - } - - /* now delete the invisible items from the list */ - while(iterator_next(i)) - { - LISTVIEW_GetItemOrigin(infoPtr, i->nItem, &Position); - rcItem.left = Position.x + Origin.x; - rcItem.top = Position.y + Origin.y; - rcItem.right = rcItem.left + infoPtr->nItemWidth; - rcItem.bottom = rcItem.top + infoPtr->nItemHeight; - if (!RectVisible(hdc, &rcItem)) - ranges_delitem(i->ranges, i->nItem); - } - /* the iterator should restart on the next iterator_next */ - TRACE("done\n"); - - return TRUE; -} - -/******** Misc helper functions ************************************/ - -static inline LRESULT CallWindowProcT(WNDPROC proc, HWND hwnd, UINT uMsg, - WPARAM wParam, LPARAM lParam, BOOL isW) -{ - if (isW) return CallWindowProcW(proc, hwnd, uMsg, wParam, lParam); - else return CallWindowProcA(proc, hwnd, uMsg, wParam, lParam); -} - -static inline BOOL is_autoarrange(LISTVIEW_INFO *infoPtr) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - - return ((infoPtr->dwStyle & LVS_AUTOARRANGE) || infoPtr->bAutoarrange) && - (uView == LVS_ICON || uView == LVS_SMALLICON); -} - -/******** Internal API functions ************************************/ - -static inline COLUMN_INFO * LISTVIEW_GetColumnInfo(LISTVIEW_INFO *infoPtr, INT nSubItem) -{ - static COLUMN_INFO mainItem; - - if (nSubItem == 0 && DPA_GetPtrCount(infoPtr->hdpaColumns) == 0) return &mainItem; - assert (nSubItem >= 0 && nSubItem < DPA_GetPtrCount(infoPtr->hdpaColumns)); - return (COLUMN_INFO *)DPA_GetPtr(infoPtr->hdpaColumns, nSubItem); -} - -static inline void LISTVIEW_GetHeaderRect(LISTVIEW_INFO *infoPtr, INT nSubItem, RECT *lprc) -{ - *lprc = LISTVIEW_GetColumnInfo(infoPtr, nSubItem)->rcHeader; -} - -static inline BOOL LISTVIEW_GetItemW(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem) -{ - return LISTVIEW_GetItemT(infoPtr, lpLVItem, TRUE); -} - -/* Listview invalidation functions: use _only_ these functions to invalidate */ - -static inline BOOL is_redrawing(LISTVIEW_INFO *infoPtr) -{ - return infoPtr->bRedraw; -} - -static inline void LISTVIEW_InvalidateRect(LISTVIEW_INFO *infoPtr, const RECT* rect) -{ - if(!is_redrawing(infoPtr)) return; - TRACE(" invalidating rect=%s\n", debugrect(rect)); - InvalidateRect(infoPtr->hwndSelf, rect, TRUE); -} - -static inline void LISTVIEW_InvalidateItem(LISTVIEW_INFO *infoPtr, INT nItem) -{ - RECT rcBox; - - if(!is_redrawing(infoPtr)) return; - LISTVIEW_GetItemBox(infoPtr, nItem, &rcBox); - LISTVIEW_InvalidateRect(infoPtr, &rcBox); -} - -static inline void LISTVIEW_InvalidateSubItem(LISTVIEW_INFO *infoPtr, INT nItem, INT nSubItem) -{ - POINT Origin, Position; - RECT rcBox; - - if(!is_redrawing(infoPtr)) return; - assert ((infoPtr->dwStyle & LVS_TYPEMASK) == LVS_REPORT); - LISTVIEW_GetOrigin(infoPtr, &Origin); - LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position); - LISTVIEW_GetHeaderRect(infoPtr, nSubItem, &rcBox); - rcBox.top = 0; - rcBox.bottom = infoPtr->nItemHeight; - OffsetRect(&rcBox, Origin.x + Position.x, Origin.y + Position.y); - LISTVIEW_InvalidateRect(infoPtr, &rcBox); -} - -static inline void LISTVIEW_InvalidateList(LISTVIEW_INFO *infoPtr) -{ - LISTVIEW_InvalidateRect(infoPtr, NULL); -} - -static inline void LISTVIEW_InvalidateColumn(LISTVIEW_INFO *infoPtr, INT nColumn) -{ - RECT rcCol; - - if(!is_redrawing(infoPtr)) return; - LISTVIEW_GetHeaderRect(infoPtr, nColumn, &rcCol); - rcCol.top = infoPtr->rcList.top; - rcCol.bottom = infoPtr->rcList.bottom; - LISTVIEW_InvalidateRect(infoPtr, &rcCol); -} - -/*** - * DESCRIPTION: - * Retrieves the number of items that can fit vertically in the client area. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * - * RETURN: - * Number of items per row. - */ -static inline INT LISTVIEW_GetCountPerRow(LISTVIEW_INFO *infoPtr) -{ - INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left; - - return max(nListWidth/infoPtr->nItemWidth, 1); -} - -/*** - * DESCRIPTION: - * Retrieves the number of items that can fit horizontally in the client - * area. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * - * RETURN: - * Number of items per column. - */ -static inline INT LISTVIEW_GetCountPerColumn(LISTVIEW_INFO *infoPtr) -{ - INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top; - - return max(nListHeight / infoPtr->nItemHeight, 1); -} - - -/************************************************************************* - * LISTVIEW_ProcessLetterKeys - * - * Processes keyboard messages generated by pressing the letter keys - * on the keyboard. - * What this does is perform a case insensitive search from the - * current position with the following quirks: - * - If two chars or more are pressed in quick succession we search - * for the corresponding string (e.g. 'abc'). - * - If there is a delay we wipe away the current search string and - * restart with just that char. - * - If the user keeps pressing the same character, whether slowly or - * fast, so that the search string is entirely composed of this - * character ('aaaaa' for instance), then we search for first item - * that starting with that character. - * - If the user types the above character in quick succession, then - * we must also search for the corresponding string ('aaaaa'), and - * go to that string if there is a match. - * - * PARAMETERS - * [I] hwnd : handle to the window - * [I] charCode : the character code, the actual character - * [I] keyData : key data - * - * RETURNS - * - * Zero. - * - * BUGS - * - * - The current implementation has a list of characters it will - * accept and it ignores averything else. In particular it will - * ignore accentuated characters which seems to match what - * Windows does. But I'm not sure it makes sense to follow - * Windows there. - * - We don't sound a beep when the search fails. - * - * SEE ALSO - * - * TREEVIEW_ProcessLetterKeys - */ -static INT LISTVIEW_ProcessLetterKeys(LISTVIEW_INFO *infoPtr, WPARAM charCode, LPARAM keyData) -{ - INT nItem; - INT endidx,idx; - LVITEMW item; - WCHAR buffer[MAX_PATH]; - DWORD lastKeyPressTimestamp = infoPtr->lastKeyPressTimestamp; - - /* simple parameter checking */ - if (!charCode || !keyData) return 0; - - /* only allow the valid WM_CHARs through */ - if (!isalnum(charCode) && - charCode != '.' && charCode != '`' && charCode != '!' && - charCode != '@' && charCode != '#' && charCode != '$' && - charCode != '%' && charCode != '^' && charCode != '&' && - charCode != '*' && charCode != '(' && charCode != ')' && - charCode != '-' && charCode != '_' && charCode != '+' && - charCode != '=' && charCode != '\\'&& charCode != ']' && - charCode != '}' && charCode != '[' && charCode != '{' && - charCode != '/' && charCode != '?' && charCode != '>' && - charCode != '<' && charCode != ',' && charCode != '~') - return 0; - - /* if there's one item or less, there is no where to go */ - if (infoPtr->nItemCount <= 1) return 0; - - /* update the search parameters */ - infoPtr->lastKeyPressTimestamp = GetTickCount(); - if (infoPtr->lastKeyPressTimestamp - lastKeyPressTimestamp < KEY_DELAY) { - if (infoPtr->nSearchParamLength < MAX_PATH) - infoPtr->szSearchParam[infoPtr->nSearchParamLength++]=charCode; - if (infoPtr->charCode != charCode) - infoPtr->charCode = charCode = 0; - } else { - infoPtr->charCode=charCode; - infoPtr->szSearchParam[0]=charCode; - infoPtr->nSearchParamLength=1; - /* Redundant with the 1 char string */ - charCode=0; - } - - /* and search from the current position */ - nItem=-1; - if (infoPtr->nFocusedItem >= 0) { - endidx=infoPtr->nFocusedItem; - idx=endidx; - /* if looking for single character match, - * then we must always move forward - */ - if (infoPtr->nSearchParamLength == 1) - idx++; - } else { - endidx=infoPtr->nItemCount; - idx=0; - } - do { - if (idx == infoPtr->nItemCount) { - if (endidx == infoPtr->nItemCount || endidx == 0) - break; - idx=0; - } - - /* get item */ - item.mask = LVIF_TEXT; - item.iItem = idx; - item.iSubItem = 0; - item.pszText = buffer; - item.cchTextMax = MAX_PATH; - if (!LISTVIEW_GetItemW(infoPtr, &item)) return 0; - - /* check for a match */ - if (lstrncmpiW(item.pszText,infoPtr->szSearchParam,infoPtr->nSearchParamLength) == 0) { - nItem=idx; - break; - } else if ( (charCode != 0) && (nItem == -1) && (nItem != infoPtr->nFocusedItem) && - (lstrncmpiW(item.pszText,infoPtr->szSearchParam,1) == 0) ) { - /* This would work but we must keep looking for a longer match */ - nItem=idx; - } - idx++; - } while (idx != endidx); - - if (nItem != -1) - LISTVIEW_KeySelection(infoPtr, nItem); - - return 0; -} - -/************************************************************************* - * LISTVIEW_UpdateHeaderSize [Internal] - * - * Function to resize the header control - * - * PARAMS - * [I] hwnd : handle to a window - * [I] nNewScrollPos : scroll pos to set - * - * RETURNS - * None. - */ -static void LISTVIEW_UpdateHeaderSize(LISTVIEW_INFO *infoPtr, INT nNewScrollPos) -{ - RECT winRect; - POINT point[2]; - - TRACE("nNewScrollPos=%d\n", nNewScrollPos); - - GetWindowRect(infoPtr->hwndHeader, &winRect); - point[0].x = winRect.left; - point[0].y = winRect.top; - point[1].x = winRect.right; - point[1].y = winRect.bottom; - - MapWindowPoints(HWND_DESKTOP, infoPtr->hwndSelf, point, 2); - point[0].x = -nNewScrollPos; - point[1].x += nNewScrollPos; - - SetWindowPos(infoPtr->hwndHeader,0, - point[0].x,point[0].y,point[1].x,point[1].y, - SWP_NOZORDER | SWP_NOACTIVATE); -} - -/*** - * DESCRIPTION: - * Update the scrollbars. This functions should be called whenever - * the content, size or view changes. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * - * RETURN: - * None - */ -static void LISTVIEW_UpdateScroll(LISTVIEW_INFO *infoPtr) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - SCROLLINFO horzInfo, vertInfo; - - if ((infoPtr->dwStyle & LVS_NOSCROLL) || !is_redrawing(infoPtr)) return; - - ZeroMemory(&horzInfo, sizeof(SCROLLINFO)); - horzInfo.cbSize = sizeof(SCROLLINFO); - horzInfo.nPage = infoPtr->rcList.right - infoPtr->rcList.left; - - /* for now, we'll set info.nMax to the _count_, and adjust it later */ - if (uView == LVS_LIST) - { - INT nPerCol = LISTVIEW_GetCountPerColumn(infoPtr); - horzInfo.nMax = (infoPtr->nItemCount + nPerCol - 1) / nPerCol; - - /* scroll by at least one column per page */ - if(horzInfo.nPage < infoPtr->nItemWidth) - horzInfo.nPage = infoPtr->nItemWidth; - - horzInfo.nPage /= infoPtr->nItemWidth; - } - else if (uView == LVS_REPORT) - { - horzInfo.nMax = infoPtr->nItemWidth; - } - else /* LVS_ICON, or LVS_SMALLICON */ - { - RECT rcView; - - if (LISTVIEW_GetViewRect(infoPtr, &rcView)) horzInfo.nMax = rcView.right - rcView.left; - } - - horzInfo.fMask = SIF_RANGE | SIF_PAGE; - horzInfo.nMax = max(horzInfo.nMax - 1, 0); - SetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &horzInfo, TRUE); - TRACE("horzInfo=%s\n", debugscrollinfo(&horzInfo)); - - /* Setting the horizontal scroll can change the listview size - * (and potentially everything else) so we need to recompute - * everything again for the vertical scroll - */ - - ZeroMemory(&vertInfo, sizeof(SCROLLINFO)); - vertInfo.cbSize = sizeof(SCROLLINFO); - vertInfo.nPage = infoPtr->rcList.bottom - infoPtr->rcList.top; - - if (uView == LVS_REPORT) - { - vertInfo.nMax = infoPtr->nItemCount; - - /* scroll by at least one page */ - if(vertInfo.nPage < infoPtr->nItemHeight) - vertInfo.nPage = infoPtr->nItemHeight; - - vertInfo.nPage /= infoPtr->nItemHeight; - } - else if (uView != LVS_LIST) /* LVS_ICON, or LVS_SMALLICON */ - { - RECT rcView; - - if (LISTVIEW_GetViewRect(infoPtr, &rcView)) vertInfo.nMax = rcView.bottom - rcView.top; - } - - vertInfo.fMask = SIF_RANGE | SIF_PAGE; - vertInfo.nMax = max(vertInfo.nMax - 1, 0); - SetScrollInfo(infoPtr->hwndSelf, SB_VERT, &vertInfo, TRUE); - TRACE("vertInfo=%s\n", debugscrollinfo(&vertInfo)); - - /* Update the Header Control */ - if (uView == LVS_REPORT) - { - horzInfo.fMask = SIF_POS; - GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &horzInfo); - LISTVIEW_UpdateHeaderSize(infoPtr, horzInfo.nPos); - } -} - - -/*** - * DESCRIPTION: - * Shows/hides the focus rectangle. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] fShow : TRUE to show the focus, FALSE to hide it. - * - * RETURN: - * None - */ -static void LISTVIEW_ShowFocusRect(LISTVIEW_INFO *infoPtr, BOOL fShow) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - HDC hdc; - - TRACE("fShow=%d, nItem=%d\n", fShow, infoPtr->nFocusedItem); - - if (infoPtr->nFocusedItem < 0) return; - - /* we need some gymnastics in ICON mode to handle large items */ - if ( (infoPtr->dwStyle & LVS_TYPEMASK) == LVS_ICON ) - { - RECT rcBox; - - LISTVIEW_GetItemBox(infoPtr, infoPtr->nFocusedItem, &rcBox); - if ((rcBox.bottom - rcBox.top) > infoPtr->nItemHeight) - { - LISTVIEW_InvalidateRect(infoPtr, &rcBox); - return; - } - } - - if (!(hdc = GetDC(infoPtr->hwndSelf))) return; - - /* for some reason, owner draw should work only in report mode */ - if ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (uView == LVS_REPORT)) - { - DRAWITEMSTRUCT dis; - LVITEMW item; - - item.iItem = infoPtr->nFocusedItem; - item.iSubItem = 0; - item.mask = LVIF_PARAM; - if (!LISTVIEW_GetItemW(infoPtr, &item)) goto done; - - ZeroMemory(&dis, sizeof(dis)); - dis.CtlType = ODT_LISTVIEW; - dis.CtlID = (UINT)GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); - dis.itemID = item.iItem; - dis.itemAction = ODA_FOCUS; - if (fShow) dis.itemState |= ODS_FOCUS; - dis.hwndItem = infoPtr->hwndSelf; - dis.hDC = hdc; - LISTVIEW_GetItemBox(infoPtr, dis.itemID, &dis.rcItem); - dis.itemData = item.lParam; - - SendMessageW(infoPtr->hwndNotify, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis); - } - else - { - DrawFocusRect(hdc, &infoPtr->rcFocus); - } -done: - ReleaseDC(infoPtr->hwndSelf, hdc); -} - -/*** - * Invalidates all visible selected items. - */ -static void LISTVIEW_InvalidateSelectedItems(LISTVIEW_INFO *infoPtr) -{ - ITERATOR i; - - iterator_frameditems(&i, infoPtr, &infoPtr->rcList); - while(iterator_next(&i)) - { - if (LISTVIEW_GetItemState(infoPtr, i.nItem, LVIS_SELECTED)) - LISTVIEW_InvalidateItem(infoPtr, i.nItem); - } - iterator_destroy(&i); -} - - -/*** - * DESCRIPTION: [INTERNAL] - * Computes an item's (left,top) corner, relative to rcView. - * That is, the position has NOT been made relative to the Origin. - * This is deliberate, to avoid computing the Origin over, and - * over again, when this function is call in a loop. Instead, - * one ca factor the computation of the Origin before the loop, - * and offset the value retured by this function, on every iteration. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nItem : item number - * [O] lpptOrig : item top, left corner - * - * RETURN: - * None. - */ -static void LISTVIEW_GetItemOrigin(LISTVIEW_INFO *infoPtr, INT nItem, LPPOINT lpptPosition) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - - assert(nItem >= 0 && nItem < infoPtr->nItemCount); - - if ((uView == LVS_SMALLICON) || (uView == LVS_ICON)) - { - lpptPosition->x = (LONG)DPA_GetPtr(infoPtr->hdpaPosX, nItem); - lpptPosition->y = (LONG)DPA_GetPtr(infoPtr->hdpaPosY, nItem); - } - else if (uView == LVS_LIST) - { - INT nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr); - lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth; - lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight; - } - else /* LVS_REPORT */ - { - lpptPosition->x = 0; - lpptPosition->y = nItem * infoPtr->nItemHeight; - } -} - -/*** - * DESCRIPTION: [INTERNAL] - * Compute the rectangles of an item. This is to localize all - * the computations in one place. If you are not interested in some - * of these values, simply pass in a NULL -- the fucntion is smart - * enough to compute only what's necessary. The function computes - * the standard rectangles (BOUNDS, ICON, LABEL) plus a non-standard - * one, the BOX rectangle. This rectangle is very cheap to compute, - * and is guaranteed to contain all the other rectangles. Computing - * the ICON rect is also cheap, but all the others are potentaily - * expensive. This gives an easy and effective optimization when - * searching (like point inclusion, or rectangle intersection): - * first test against the BOX, and if TRUE, test agains the desired - * rectangle. - * If the function does not have all the necessary information - * to computed the requested rectangles, will crash with a - * failed assertion. This is done so we catch all programming - * errors, given that the function is called only from our code. - * - * We have the following 'special' meanings for a few fields: - * * If LVIS_FOCUSED is set, we assume the item has the focus - * This is important in ICON mode, where it might get a larger - * then usual rectange - * - * Please note that subitem support works only in REPORT mode. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] lpLVItem : item to compute the measures for - * [O] lprcBox : ptr to Box rectangle - * The internal LVIR_BOX rectangle - * [0] lprcState : ptr to State icon rectangle - * The internal LVIR_STATE rectangle - * [O] lprcIcon : ptr to Icon rectangle - * Same as LVM_GETITEMRECT with LVIR_ICON - * [O] lprcLabel : ptr to Label rectangle - * Same as LVM_GETITEMRECT with LVIR_LABEL - * - * RETURN: - * None. - */ -static void LISTVIEW_GetItemMetrics(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, - LPRECT lprcBox, LPRECT lprcState, - LPRECT lprcIcon, LPRECT lprcLabel) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - BOOL doState = FALSE, doIcon = FALSE, doLabel = FALSE, oversizedBox = FALSE; - RECT Box, State, Icon, Label; - COLUMN_INFO *lpColumnInfo = NULL; - - TRACE("(lpLVItem=%s)\n", debuglvitem_t(lpLVItem, TRUE)); - - /* Be smart and try to figure out the minimum we have to do */ - if (lpLVItem->iSubItem) assert(uView == LVS_REPORT); - if (uView == LVS_ICON && (lprcBox || lprcLabel)) - { - assert((lpLVItem->mask & LVIF_STATE) && (lpLVItem->stateMask & LVIS_FOCUSED)); - if (lpLVItem->state & LVIS_FOCUSED) oversizedBox = doLabel = TRUE; - } - if (lprcLabel) doLabel = TRUE; - if (doLabel || lprcIcon) doIcon = TRUE; - if (doIcon || lprcState) doState = TRUE; - - /************************************************************/ - /* compute the box rectangle (it should be cheap to do) */ - /************************************************************/ - if (lpLVItem->iSubItem || uView == LVS_REPORT) - lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, lpLVItem->iSubItem); - - if (lpLVItem->iSubItem) - { - Box = lpColumnInfo->rcHeader; - } - else - { - Box.left = 0; - Box.right = infoPtr->nItemWidth; - } - Box.top = 0; - Box.bottom = infoPtr->nItemHeight; - - /************************************************************/ - /* compute STATEICON bounding box */ - /************************************************************/ - if (doState) - { - if (uView == LVS_ICON) - { - State.left = Box.left - infoPtr->iconStateSize.cx - 2; - if (infoPtr->himlNormal) - State.left += (infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2; - State.top = Box.top + infoPtr->iconSize.cy - infoPtr->iconStateSize.cy + 4; - } - else - { - /* we need the ident in report mode, if we don't have it, we fail */ - State.left = Box.left; - if (uView == LVS_REPORT) - { - if (lpLVItem->iSubItem == 0) - { - State.left += REPORT_MARGINX; - assert(lpLVItem->mask & LVIF_INDENT); - State.left += infoPtr->iconSize.cx * lpLVItem->iIndent; - } - } - State.top = Box.top; - } - State.right = State.left; - State.bottom = State.top; - if (infoPtr->himlState && lpLVItem->iSubItem == 0) - { - State.right += infoPtr->iconStateSize.cx; - State.bottom += infoPtr->iconStateSize.cy; - } - if (lprcState) *lprcState = State; - TRACE(" - state=%s\n", debugrect(&State)); - } - - /************************************************************/ - /* compute ICON bounding box (ala LVM_GETITEMRECT) */ - /************************************************************/ - if (doIcon) - { - if (uView == LVS_ICON) - { - Icon.left = Box.left; - if (infoPtr->himlNormal) - Icon.left += (infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2; - Icon.top = Box.top + ICON_TOP_PADDING; - Icon.right = Icon.left; - Icon.bottom = Icon.top; - if (infoPtr->himlNormal) - { - Icon.right += infoPtr->iconSize.cx; - Icon.bottom += infoPtr->iconSize.cy; - } - } - else /* LVS_SMALLICON, LVS_LIST or LVS_REPORT */ - { - Icon.left = State.right; - Icon.top = Box.top; - Icon.right = Icon.left; - if (infoPtr->himlSmall && - (!lpColumnInfo || lpLVItem->iSubItem == 0 || (lpColumnInfo->fmt & LVCFMT_IMAGE) || - ((infoPtr->dwLvExStyle & LVS_EX_SUBITEMIMAGES) && lpLVItem->iImage != I_IMAGECALLBACK))) - Icon.right += infoPtr->iconSize.cx; - Icon.bottom = Icon.top + infoPtr->nItemHeight; - } - if(lprcIcon) *lprcIcon = Icon; - TRACE(" - icon=%s\n", debugrect(&Icon)); - } - - /************************************************************/ - /* compute LABEL bounding box (ala LVM_GETITEMRECT) */ - /************************************************************/ - if (doLabel) - { - SIZE labelSize = { 0, 0 }; - - /* calculate how far to the right can the label strech */ - Label.right = Box.right; - if (uView == LVS_REPORT) - { - if (lpLVItem->iSubItem == 0) Label = lpColumnInfo->rcHeader; - } - - if (lpLVItem->iSubItem || ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && uView == LVS_REPORT)) - { - labelSize.cx = infoPtr->nItemWidth; - labelSize.cy = infoPtr->nItemHeight; - goto calc_label; - } - - /* we need the text in non owner draw mode */ - assert(lpLVItem->mask & LVIF_TEXT); - if (is_textT(lpLVItem->pszText, TRUE)) - { - HFONT hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont; - HDC hdc = GetDC(infoPtr->hwndSelf); - HFONT hOldFont = SelectObject(hdc, hFont); - UINT uFormat; - RECT rcText; - - /* compute rough rectangle where the label will go */ - SetRectEmpty(&rcText); - rcText.right = infoPtr->nItemWidth - TRAILING_LABEL_PADDING; - rcText.bottom = infoPtr->nItemHeight; - if (uView == LVS_ICON) - rcText.bottom -= ICON_TOP_PADDING + infoPtr->iconSize.cy + ICON_BOTTOM_PADDING; - - /* now figure out the flags */ - if (uView == LVS_ICON) - uFormat = oversizedBox ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS; - else - uFormat = LV_SL_DT_FLAGS; - - DrawTextW (hdc, lpLVItem->pszText, -1, &rcText, uFormat | DT_CALCRECT); - - labelSize.cx = min(rcText.right - rcText.left + TRAILING_LABEL_PADDING, infoPtr->nItemWidth); - labelSize.cy = rcText.bottom - rcText.top; - - SelectObject(hdc, hOldFont); - ReleaseDC(infoPtr->hwndSelf, hdc); - } - -calc_label: - if (uView == LVS_ICON) - { - Label.left = Box.left + (infoPtr->nItemWidth - labelSize.cx) / 2; - Label.top = Box.top + ICON_TOP_PADDING_HITABLE + - infoPtr->iconSize.cy + ICON_BOTTOM_PADDING; - Label.right = Label.left + labelSize.cx; - Label.bottom = Label.top + infoPtr->nItemHeight; - if (!oversizedBox && labelSize.cy > infoPtr->ntmHeight && - infoPtr->ntmHeight) - { - labelSize.cy = min(Box.bottom - Label.top, labelSize.cy); - labelSize.cy /= infoPtr->ntmHeight; - labelSize.cy = max(labelSize.cy, 1); - labelSize.cy *= infoPtr->ntmHeight; - } - Label.bottom = Label.top + labelSize.cy + HEIGHT_PADDING; - } - else /* LVS_SMALLICON, LVS_LIST or LVS_REPORT */ - { - Label.left = Icon.right; - Label.top = Box.top; - Label.right = min(Label.left + labelSize.cx, Label.right); - Label.bottom = Label.top + infoPtr->nItemHeight; - } - - if (lprcLabel) *lprcLabel = Label; - TRACE(" - label=%s\n", debugrect(&Label)); - } - - /* Fix the Box if necessary */ - if (lprcBox) - { - if (oversizedBox) UnionRect(lprcBox, &Box, &Label); - else *lprcBox = Box; - } - TRACE(" - box=%s\n", debugrect(&Box)); -} - -/*** - * DESCRIPTION: [INTERNAL] - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nItem : item number - * [O] lprcBox : ptr to Box rectangle - * - * RETURN: - * None. - */ -static void LISTVIEW_GetItemBox(LISTVIEW_INFO *infoPtr, INT nItem, LPRECT lprcBox) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' }; - POINT Position, Origin; - LVITEMW lvItem; - - LISTVIEW_GetOrigin(infoPtr, &Origin); - LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position); - - /* Be smart and try to figure out the minimum we have to do */ - lvItem.mask = 0; - if (uView == LVS_ICON && infoPtr->bFocus && LISTVIEW_GetItemState(infoPtr, nItem, LVIS_FOCUSED)) - lvItem.mask |= LVIF_TEXT; - lvItem.iItem = nItem; - lvItem.iSubItem = 0; - lvItem.pszText = szDispText; - lvItem.cchTextMax = DISP_TEXT_SIZE; - if (lvItem.mask) LISTVIEW_GetItemW(infoPtr, &lvItem); - if (uView == LVS_ICON) - { - lvItem.mask |= LVIF_STATE; - lvItem.stateMask = LVIS_FOCUSED; - lvItem.state = (lvItem.mask & LVIF_TEXT ? LVIS_FOCUSED : 0); - } - LISTVIEW_GetItemMetrics(infoPtr, &lvItem, lprcBox, 0, 0, 0); - - OffsetRect(lprcBox, Position.x + Origin.x, Position.y + Origin.y); -} - - -/*** - * DESCRIPTION: - * Returns the current icon position, and advances it along the top. - * The returned position is not offset by Origin. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [O] lpPos : will get the current icon position - * - * RETURN: - * None - */ -static void LISTVIEW_NextIconPosTop(LISTVIEW_INFO *infoPtr, LPPOINT lpPos) -{ - INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left; - - *lpPos = infoPtr->currIconPos; - - infoPtr->currIconPos.x += infoPtr->nItemWidth; - if (infoPtr->currIconPos.x + infoPtr->nItemWidth <= nListWidth) return; - - infoPtr->currIconPos.x = 0; - infoPtr->currIconPos.y += infoPtr->nItemHeight; -} - - -/*** - * DESCRIPTION: - * Returns the current icon position, and advances it down the left edge. - * The returned position is not offset by Origin. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [O] lpPos : will get the current icon position - * - * RETURN: - * None - */ -static void LISTVIEW_NextIconPosLeft(LISTVIEW_INFO *infoPtr, LPPOINT lpPos) -{ - INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top; - - *lpPos = infoPtr->currIconPos; - - infoPtr->currIconPos.y += infoPtr->nItemHeight; - if (infoPtr->currIconPos.y + infoPtr->nItemHeight <= nListHeight) return; - - infoPtr->currIconPos.x += infoPtr->nItemWidth; - infoPtr->currIconPos.y = 0; -} - - -/*** - * DESCRIPTION: - * Moves an icon to the specified position. - * It takes care of invalidating the item, etc. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nItem : the item to move - * [I] lpPos : the new icon position - * [I] isNew : flags the item as being new - * - * RETURN: - * Success: TRUE - * Failure: FALSE - */ -static BOOL LISTVIEW_MoveIconTo(LISTVIEW_INFO *infoPtr, INT nItem, const POINT *lppt, BOOL isNew) -{ - POINT old; - - if (!isNew) - { - old.x = (LONG)DPA_GetPtr(infoPtr->hdpaPosX, nItem); - old.y = (LONG)DPA_GetPtr(infoPtr->hdpaPosY, nItem); - - if (lppt->x == old.x && lppt->y == old.y) return TRUE; - LISTVIEW_InvalidateItem(infoPtr, nItem); - } - - /* Allocating a POINTER for every item is too resource intensive, - * so we'll keep the (x,y) in different arrays */ - if (!DPA_SetPtr(infoPtr->hdpaPosX, nItem, (void *)lppt->x)) return FALSE; - if (!DPA_SetPtr(infoPtr->hdpaPosY, nItem, (void *)lppt->y)) return FALSE; - - LISTVIEW_InvalidateItem(infoPtr, nItem); - - return TRUE; -} - -/*** - * DESCRIPTION: - * Arranges listview items in icon display mode. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nAlignCode : alignment code - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_Arrange(LISTVIEW_INFO *infoPtr, INT nAlignCode) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - void (*next_pos)(LISTVIEW_INFO *, LPPOINT); - POINT pos; - INT i; - - if (uView != LVS_ICON && uView != LVS_SMALLICON) return FALSE; - - TRACE("nAlignCode=%d\n", nAlignCode); - - if (nAlignCode == LVA_DEFAULT) - { - if (infoPtr->dwStyle & LVS_ALIGNLEFT) nAlignCode = LVA_ALIGNLEFT; - else nAlignCode = LVA_ALIGNTOP; - } - - switch (nAlignCode) - { - case LVA_ALIGNLEFT: next_pos = LISTVIEW_NextIconPosLeft; break; - case LVA_ALIGNTOP: next_pos = LISTVIEW_NextIconPosTop; break; - case LVA_SNAPTOGRID: next_pos = LISTVIEW_NextIconPosTop; break; /* FIXME */ - default: return FALSE; - } - - infoPtr->bAutoarrange = TRUE; - infoPtr->currIconPos.x = infoPtr->currIconPos.y = 0; - for (i = 0; i < infoPtr->nItemCount; i++) - { - next_pos(infoPtr, &pos); - LISTVIEW_MoveIconTo(infoPtr, i, &pos, FALSE); - } - - return TRUE; -} - -/*** - * DESCRIPTION: - * Retrieves the bounding rectangle of all the items, not offset by Origin. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [O] lprcView : bounding rectangle - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static void LISTVIEW_GetAreaRect(LISTVIEW_INFO *infoPtr, LPRECT lprcView) -{ - INT i, x, y; - - SetRectEmpty(lprcView); - - switch (infoPtr->dwStyle & LVS_TYPEMASK) - { - case LVS_ICON: - case LVS_SMALLICON: - for (i = 0; i < infoPtr->nItemCount; i++) - { - x = (LONG)DPA_GetPtr(infoPtr->hdpaPosX, i); - y = (LONG)DPA_GetPtr(infoPtr->hdpaPosY, i); - lprcView->right = max(lprcView->right, x); - lprcView->bottom = max(lprcView->bottom, y); - } - if (infoPtr->nItemCount > 0) - { - lprcView->right += infoPtr->nItemWidth; - lprcView->bottom += infoPtr->nItemHeight; - } - break; - - case LVS_LIST: - y = LISTVIEW_GetCountPerColumn(infoPtr); - x = infoPtr->nItemCount / y; - if (infoPtr->nItemCount % y) x++; - lprcView->right = x * infoPtr->nItemWidth; - lprcView->bottom = y * infoPtr->nItemHeight; - break; - - case LVS_REPORT: - lprcView->right = infoPtr->nItemWidth; - lprcView->bottom = infoPtr->nItemCount * infoPtr->nItemHeight; - break; - } -} - -/*** - * DESCRIPTION: - * Retrieves the bounding rectangle of all the items. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [O] lprcView : bounding rectangle - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_GetViewRect(LISTVIEW_INFO *infoPtr, LPRECT lprcView) -{ - POINT ptOrigin; - - TRACE("(lprcView=%p)\n", lprcView); - - if (!lprcView) return FALSE; - - LISTVIEW_GetOrigin(infoPtr, &ptOrigin); - LISTVIEW_GetAreaRect(infoPtr, lprcView); - OffsetRect(lprcView, ptOrigin.x, ptOrigin.y); - - TRACE("lprcView=%s\n", debugrect(lprcView)); - - return TRUE; -} - -/*** - * DESCRIPTION: - * Retrieves the subitem pointer associated with the subitem index. - * - * PARAMETER(S): - * [I] hdpaSubItems : DPA handle for a specific item - * [I] nSubItem : index of subitem - * - * RETURN: - * SUCCESS : subitem pointer - * FAILURE : NULL - */ -static SUBITEM_INFO* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems, INT nSubItem) -{ - SUBITEM_INFO *lpSubItem; - INT i; - - /* we should binary search here if need be */ - for (i = 1; i < DPA_GetPtrCount(hdpaSubItems); i++) - { - lpSubItem = (SUBITEM_INFO *)DPA_GetPtr(hdpaSubItems, i); - if (lpSubItem->iSubItem == nSubItem) - return lpSubItem; - } - - return NULL; -} - - -/*** - * DESCRIPTION: - * Caclulates the desired item width. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * - * RETURN: - * The desired item width. - */ -static INT LISTVIEW_CalculateItemWidth(LISTVIEW_INFO *infoPtr) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - INT nItemWidth = 0; - - TRACE("uView=%d\n", uView); - - if (uView == LVS_ICON) - nItemWidth = infoPtr->iconSpacing.cx; - else if (uView == LVS_REPORT) - { - RECT rcHeader; - - if (DPA_GetPtrCount(infoPtr->hdpaColumns) > 0) - { - LISTVIEW_GetHeaderRect(infoPtr, DPA_GetPtrCount(infoPtr->hdpaColumns) - 1, &rcHeader); - nItemWidth = rcHeader.right; - } - } - else /* LVS_SMALLICON, or LVS_LIST */ - { - INT i; - - for (i = 0; i < infoPtr->nItemCount; i++) - nItemWidth = max(LISTVIEW_GetLabelWidth(infoPtr, i), nItemWidth); - - if (infoPtr->himlSmall) nItemWidth += infoPtr->iconSize.cx; - if (infoPtr->himlState) nItemWidth += infoPtr->iconStateSize.cx; - - nItemWidth = max(DEFAULT_COLUMN_WIDTH, nItemWidth + WIDTH_PADDING); - } - - return max(nItemWidth, 1); -} - -/*** - * DESCRIPTION: - * Caclulates the desired item height. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * - * RETURN: - * The desired item height. - */ -static INT LISTVIEW_CalculateItemHeight(LISTVIEW_INFO *infoPtr) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - INT nItemHeight; - - TRACE("uView=%d\n", uView); - - if (uView == LVS_ICON) - nItemHeight = infoPtr->iconSpacing.cy; - else - { - nItemHeight = infoPtr->ntmHeight; - if (infoPtr->himlState) - nItemHeight = max(nItemHeight, infoPtr->iconStateSize.cy); - if (infoPtr->himlSmall) - nItemHeight = max(nItemHeight, infoPtr->iconSize.cy); - if (infoPtr->himlState || infoPtr->himlSmall) - nItemHeight += HEIGHT_PADDING; - if (infoPtr->nMeasureItemHeight > 0) - nItemHeight = infoPtr->nMeasureItemHeight; - } - - return max(nItemHeight, 1); -} - -/*** - * DESCRIPTION: - * Updates the width, and height of an item. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * - * RETURN: - * None. - */ -static inline void LISTVIEW_UpdateItemSize(LISTVIEW_INFO *infoPtr) -{ - infoPtr->nItemWidth = LISTVIEW_CalculateItemWidth(infoPtr); - infoPtr->nItemHeight = LISTVIEW_CalculateItemHeight(infoPtr); -} - - -/*** - * DESCRIPTION: - * Retrieves and saves important text metrics info for the current - * Listview font. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * - */ -static void LISTVIEW_SaveTextMetrics(LISTVIEW_INFO *infoPtr) -{ - HDC hdc = GetDC(infoPtr->hwndSelf); - HFONT hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont; - HFONT hOldFont = SelectObject(hdc, hFont); - TEXTMETRICW tm; - SIZE sz; - - if (GetTextMetricsW(hdc, &tm)) - { - infoPtr->ntmHeight = tm.tmHeight; - infoPtr->ntmMaxCharWidth = tm.tmMaxCharWidth; - } - - if (GetTextExtentPoint32A(hdc, "...", 3, &sz)) - infoPtr->nEllipsisWidth = sz.cx; - - SelectObject(hdc, hOldFont); - ReleaseDC(infoPtr->hwndSelf, hdc); - - TRACE("tmHeight=%d\n", infoPtr->ntmHeight); -} - -/*** - * DESCRIPTION: - * A compare function for ranges - * - * PARAMETER(S) - * [I] range1 : pointer to range 1; - * [I] range2 : pointer to range 2; - * [I] flags : flags - * - * RETURNS: - * > 0 : if range 1 > range 2 - * < 0 : if range 2 > range 1 - * = 0 : if range intersects range 2 - */ -static INT CALLBACK ranges_cmp(LPVOID range1, LPVOID range2, LPARAM flags) -{ - INT cmp; - - if (((RANGE*)range1)->upper <= ((RANGE*)range2)->lower) - cmp = -1; - else if (((RANGE*)range2)->upper <= ((RANGE*)range1)->lower) - cmp = 1; - else - cmp = 0; - - TRACE("range1=%s, range2=%s, cmp=%d\n", debugrange((RANGE*)range1), debugrange((RANGE*)range2), cmp); - - return cmp; -} - -#if DEBUG_RANGES -#define ranges_check(ranges, desc) ranges_assert(ranges, desc, __FUNCTION__, __LINE__) -#else -#define ranges_check(ranges, desc) do { } while(0) -#endif - -static void ranges_assert(RANGES ranges, LPCSTR desc, const char *func, int line) -{ - INT i; - RANGE *prev, *curr; - - TRACE("*** Checking %s:%d:%s ***\n", func, line, desc); - assert (ranges); - assert (DPA_GetPtrCount(ranges->hdpa) >= 0); - ranges_dump(ranges); - prev = (RANGE *)DPA_GetPtr(ranges->hdpa, 0); - if (DPA_GetPtrCount(ranges->hdpa) > 0) - assert (prev->lower >= 0 && prev->lower < prev->upper); - for (i = 1; i < DPA_GetPtrCount(ranges->hdpa); i++) - { - curr = (RANGE *)DPA_GetPtr(ranges->hdpa, i); - assert (prev->upper <= curr->lower); - assert (curr->lower < curr->upper); - prev = curr; - } - TRACE("--- Done checking---\n"); -} - -static RANGES ranges_create(int count) -{ - RANGES ranges = (RANGES)Alloc(sizeof(struct tagRANGES)); - if (!ranges) return NULL; - ranges->hdpa = DPA_Create(count); - if (ranges->hdpa) return ranges; - Free(ranges); - return NULL; -} - -static void ranges_clear(RANGES ranges) -{ - INT i; - - for(i = 0; i < DPA_GetPtrCount(ranges->hdpa); i++) - Free(DPA_GetPtr(ranges->hdpa, i)); - DPA_DeleteAllPtrs(ranges->hdpa); -} - - -static void ranges_destroy(RANGES ranges) -{ - if (!ranges) return; - ranges_clear(ranges); - DPA_Destroy(ranges->hdpa); - Free(ranges); -} - -static RANGES ranges_clone(RANGES ranges) -{ - RANGES clone; - INT i; - - if (!(clone = ranges_create(DPA_GetPtrCount(ranges->hdpa)))) goto fail; - - for (i = 0; i < DPA_GetPtrCount(ranges->hdpa); i++) - { - RANGE *newrng = (RANGE *)Alloc(sizeof(RANGE)); - if (!newrng) goto fail; - *newrng = *((RANGE*)DPA_GetPtr(ranges->hdpa, i)); - DPA_SetPtr(clone->hdpa, i, newrng); - } - return clone; - -fail: - TRACE ("clone failed\n"); - ranges_destroy(clone); - return NULL; -} - -static RANGES ranges_diff(RANGES ranges, RANGES sub) -{ - INT i; - - for (i = 0; i < DPA_GetPtrCount(sub->hdpa); i++) - ranges_del(ranges, *((RANGE *)DPA_GetPtr(sub->hdpa, i))); - - return ranges; -} - -static void ranges_dump(RANGES ranges) -{ - INT i; - - for (i = 0; i < DPA_GetPtrCount(ranges->hdpa); i++) - TRACE(" %s\n", debugrange(DPA_GetPtr(ranges->hdpa, i))); -} - -static inline BOOL ranges_contain(RANGES ranges, INT nItem) -{ - RANGE srchrng = { nItem, nItem + 1 }; - - TRACE("(nItem=%d)\n", nItem); - ranges_check(ranges, "before contain"); - return DPA_Search(ranges->hdpa, &srchrng, 0, ranges_cmp, 0, DPAS_SORTED) != -1; -} - -static INT ranges_itemcount(RANGES ranges) -{ - INT i, count = 0; - - for (i = 0; i < DPA_GetPtrCount(ranges->hdpa); i++) - { - RANGE *sel = DPA_GetPtr(ranges->hdpa, i); - count += sel->upper - sel->lower; - } - - return count; -} - -static BOOL ranges_shift(RANGES ranges, INT nItem, INT delta, INT nUpper) -{ - RANGE srchrng = { nItem, nItem + 1 }, *chkrng; - INT index; - - index = DPA_Search(ranges->hdpa, &srchrng, 0, ranges_cmp, 0, DPAS_SORTED | DPAS_INSERTAFTER); - if (index == -1) return TRUE; - - for (; index < DPA_GetPtrCount(ranges->hdpa); index++) - { - chkrng = DPA_GetPtr(ranges->hdpa, index); - if (chkrng->lower >= nItem) - chkrng->lower = max(min(chkrng->lower + delta, nUpper - 1), 0); - if (chkrng->upper > nItem) - chkrng->upper = max(min(chkrng->upper + delta, nUpper), 0); - } - return TRUE; -} - -static BOOL ranges_add(RANGES ranges, RANGE range) -{ - RANGE srchrgn; - INT index; - - TRACE("(%s)\n", debugrange(&range)); - ranges_check(ranges, "before add"); - - /* try find overlapping regions first */ - srchrgn.lower = range.lower - 1; - srchrgn.upper = range.upper + 1; - index = DPA_Search(ranges->hdpa, &srchrgn, 0, ranges_cmp, 0, DPAS_SORTED); - - if (index == -1) - { - RANGE *newrgn; - - TRACE("Adding new range\n"); - - /* create the brand new range to insert */ - newrgn = (RANGE *)Alloc(sizeof(RANGE)); - if(!newrgn) goto fail; - *newrgn = range; - - /* figure out where to insert it */ - index = DPA_Search(ranges->hdpa, newrgn, 0, ranges_cmp, 0, DPAS_SORTED | DPAS_INSERTAFTER); - TRACE("index=%d\n", index); - if (index == -1) index = 0; - - /* and get it over with */ - if (DPA_InsertPtr(ranges->hdpa, index, newrgn) == -1) - { - Free(newrgn); - goto fail; - } - } - else - { - RANGE *chkrgn, *mrgrgn; - INT fromindex, mergeindex; - - chkrgn = DPA_GetPtr(ranges->hdpa, index); - TRACE("Merge with %s @%d\n", debugrange(chkrgn), index); - - chkrgn->lower = min(range.lower, chkrgn->lower); - chkrgn->upper = max(range.upper, chkrgn->upper); - - TRACE("New range %s @%d\n", debugrange(chkrgn), index); - - /* merge now common anges */ - fromindex = 0; - srchrgn.lower = chkrgn->lower - 1; - srchrgn.upper = chkrgn->upper + 1; - - do - { - mergeindex = DPA_Search(ranges->hdpa, &srchrgn, fromindex, ranges_cmp, 0, 0); - if (mergeindex == -1) break; - if (mergeindex == index) - { - fromindex = index + 1; - continue; - } - - TRACE("Merge with index %i\n", mergeindex); - - mrgrgn = DPA_GetPtr(ranges->hdpa, mergeindex); - chkrgn->lower = min(chkrgn->lower, mrgrgn->lower); - chkrgn->upper = max(chkrgn->upper, mrgrgn->upper); - Free(mrgrgn); - DPA_DeletePtr(ranges->hdpa, mergeindex); - if (mergeindex < index) index --; - } while(1); - } - - ranges_check(ranges, "after add"); - return TRUE; - -fail: - ranges_check(ranges, "failed add"); - return FALSE; -} - -static BOOL ranges_del(RANGES ranges, RANGE range) -{ - RANGE *chkrgn; - INT index; - - TRACE("(%s)\n", debugrange(&range)); - ranges_check(ranges, "before del"); - - /* we don't use DPAS_SORTED here, since we need * - * to find the first overlapping range */ - index = DPA_Search(ranges->hdpa, &range, 0, ranges_cmp, 0, 0); - while(index != -1) - { - chkrgn = DPA_GetPtr(ranges->hdpa, index); - - TRACE("Matches range %s @%d\n", debugrange(chkrgn), index); - - /* case 1: Same range */ - if ( (chkrgn->upper == range.upper) && - (chkrgn->lower == range.lower) ) - { - DPA_DeletePtr(ranges->hdpa, index); - break; - } - /* case 2: engulf */ - else if ( (chkrgn->upper <= range.upper) && - (chkrgn->lower >= range.lower) ) - { - DPA_DeletePtr(ranges->hdpa, index); - } - /* case 3: overlap upper */ - else if ( (chkrgn->upper <= range.upper) && - (chkrgn->lower < range.lower) ) - { - chkrgn->upper = range.lower; - } - /* case 4: overlap lower */ - else if ( (chkrgn->upper > range.upper) && - (chkrgn->lower >= range.lower) ) - { - chkrgn->lower = range.upper; - break; - } - /* case 5: fully internal */ - else - { - RANGE tmprgn = *chkrgn, *newrgn; - - if (!(newrgn = (RANGE *)Alloc(sizeof(RANGE)))) goto fail; - newrgn->lower = chkrgn->lower; - newrgn->upper = range.lower; - chkrgn->lower = range.upper; - if (DPA_InsertPtr(ranges->hdpa, index, newrgn) == -1) - { - Free(newrgn); - goto fail; - } - chkrgn = &tmprgn; - break; - } - - index = DPA_Search(ranges->hdpa, &range, index, ranges_cmp, 0, 0); - } - - ranges_check(ranges, "after del"); - return TRUE; - -fail: - ranges_check(ranges, "failed del"); - return FALSE; -} - -/*** -* DESCRIPTION: -* Removes all selection ranges -* -* Parameters(s): -* [I] infoPtr : valid pointer to the listview structure -* [I] toSkip : item range to skip removing the selection -* -* RETURNS: -* SUCCESS : TRUE -* FAILURE : TRUE -*/ -static BOOL LISTVIEW_DeselectAllSkipItems(LISTVIEW_INFO *infoPtr, RANGES toSkip) -{ - LVITEMW lvItem; - ITERATOR i; - RANGES clone; - - TRACE("()\n"); - - lvItem.state = 0; - lvItem.stateMask = LVIS_SELECTED; - - /* need to clone the DPA because callbacks can change it */ - if (!(clone = ranges_clone(infoPtr->selectionRanges))) return FALSE; - iterator_rangesitems(&i, ranges_diff(clone, toSkip)); - while(iterator_next(&i)) - LISTVIEW_SetItemState(infoPtr, i.nItem, &lvItem); - /* note that the iterator destructor will free the cloned range */ - iterator_destroy(&i); - - return TRUE; -} - -static inline BOOL LISTVIEW_DeselectAllSkipItem(LISTVIEW_INFO *infoPtr, INT nItem) -{ - RANGES toSkip; - - if (!(toSkip = ranges_create(1))) return FALSE; - if (nItem != -1) ranges_additem(toSkip, nItem); - LISTVIEW_DeselectAllSkipItems(infoPtr, toSkip); - ranges_destroy(toSkip); - return TRUE; -} - -static inline BOOL LISTVIEW_DeselectAll(LISTVIEW_INFO *infoPtr) -{ - return LISTVIEW_DeselectAllSkipItem(infoPtr, -1); -} - -/*** - * DESCRIPTION: - * Retrieves the number of items that are marked as selected. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * - * RETURN: - * Number of items selected. - */ -static INT LISTVIEW_GetSelectedCount(LISTVIEW_INFO *infoPtr) -{ - INT nSelectedCount = 0; - - if (infoPtr->uCallbackMask & LVIS_SELECTED) - { - INT i; - for (i = 0; i < infoPtr->nItemCount; i++) - { - if (LISTVIEW_GetItemState(infoPtr, i, LVIS_SELECTED)) - nSelectedCount++; - } - } - else - nSelectedCount = ranges_itemcount(infoPtr->selectionRanges); - - TRACE("nSelectedCount=%d\n", nSelectedCount); - return nSelectedCount; -} - -/*** - * DESCRIPTION: - * Manages the item focus. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nItem : item index - * - * RETURN: - * TRUE : focused item changed - * FALSE : focused item has NOT changed - */ -static inline BOOL LISTVIEW_SetItemFocus(LISTVIEW_INFO *infoPtr, INT nItem) -{ - INT oldFocus = infoPtr->nFocusedItem; - LVITEMW lvItem; - - if (nItem == infoPtr->nFocusedItem) return FALSE; - - lvItem.state = nItem == -1 ? 0 : LVIS_FOCUSED; - lvItem.stateMask = LVIS_FOCUSED; - LISTVIEW_SetItemState(infoPtr, nItem == -1 ? infoPtr->nFocusedItem : nItem, &lvItem); - - return oldFocus != infoPtr->nFocusedItem; -} - -/* Helper function for LISTVIEW_ShiftIndices *only* */ -static INT shift_item(LISTVIEW_INFO *infoPtr, INT nShiftItem, INT nItem, INT direction) -{ - if (nShiftItem < nItem) return nShiftItem; - - if (nShiftItem > nItem) return nShiftItem + direction; - - if (direction > 0) return nShiftItem + direction; - - return min(nShiftItem, infoPtr->nItemCount - 1); -} - -/** -* DESCRIPTION: -* Updates the various indices after an item has been inserted or deleted. -* -* PARAMETER(S): -* [I] infoPtr : valid pointer to the listview structure -* [I] nItem : item index -* [I] direction : Direction of shift, +1 or -1. -* -* RETURN: -* None -*/ -static void LISTVIEW_ShiftIndices(LISTVIEW_INFO *infoPtr, INT nItem, INT direction) -{ - INT nNewFocus; - BOOL bOldChange; - - /* temporarily disable change notification while shifting items */ - bOldChange = infoPtr->bDoChangeNotify; - infoPtr->bDoChangeNotify = FALSE; - - TRACE("Shifting %iu, %i steps\n", nItem, direction); - - ranges_shift(infoPtr->selectionRanges, nItem, direction, infoPtr->nItemCount); - - assert(abs(direction) == 1); - - infoPtr->nSelectionMark = shift_item(infoPtr, infoPtr->nSelectionMark, nItem, direction); - - nNewFocus = shift_item(infoPtr, infoPtr->nFocusedItem, nItem, direction); - if (nNewFocus != infoPtr->nFocusedItem) - LISTVIEW_SetItemFocus(infoPtr, nNewFocus); - - /* But we are not supposed to modify nHotItem! */ - - infoPtr->bDoChangeNotify = bOldChange; -} - - -/** - * DESCRIPTION: - * Adds a block of selections. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nItem : item index - * - * RETURN: - * None - */ -static void LISTVIEW_AddGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem) -{ - INT nFirst = min(infoPtr->nSelectionMark, nItem); - INT nLast = max(infoPtr->nSelectionMark, nItem); - NMLVODSTATECHANGE nmlv; - LVITEMW item; - BOOL bOldChange; - INT i; - - /* Temporarily disable change notification - * If the control is LVS_OWNERDATA, we need to send - * only one LVN_ODSTATECHANGED notification. - * See MSDN documentation for LVN_ITEMCHANGED. - */ - bOldChange = infoPtr->bDoChangeNotify; - if (infoPtr->dwStyle & LVS_OWNERDATA) infoPtr->bDoChangeNotify = FALSE; - - if (nFirst == -1) nFirst = nItem; - - item.state = LVIS_SELECTED; - item.stateMask = LVIS_SELECTED; - - for (i = nFirst; i <= nLast; i++) - LISTVIEW_SetItemState(infoPtr,i,&item); - - ZeroMemory(&nmlv, sizeof(nmlv)); - nmlv.iFrom = nFirst; - nmlv.iTo = nLast; - nmlv.uNewState = 0; - nmlv.uOldState = item.state; - - notify_hdr(infoPtr, LVN_ODSTATECHANGED, (LPNMHDR)&nmlv); - infoPtr->bDoChangeNotify = bOldChange; -} - - -/*** - * DESCRIPTION: - * Sets a single group selection. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nItem : item index - * - * RETURN: - * None - */ -static void LISTVIEW_SetGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - RANGES selection; - LVITEMW item; - ITERATOR i; - - if (!(selection = ranges_create(100))) return; - - item.state = LVIS_SELECTED; - item.stateMask = LVIS_SELECTED; - - if ((uView == LVS_LIST) || (uView == LVS_REPORT)) - { - if (infoPtr->nSelectionMark == -1) - { - infoPtr->nSelectionMark = nItem; - ranges_additem(selection, nItem); - } - else - { - RANGE sel; - - sel.lower = min(infoPtr->nSelectionMark, nItem); - sel.upper = max(infoPtr->nSelectionMark, nItem) + 1; - ranges_add(selection, sel); - } - } - else - { - RECT rcItem, rcSel, rcSelMark; - POINT ptItem; - - rcItem.left = LVIR_BOUNDS; - if (!LISTVIEW_GetItemRect(infoPtr, nItem, &rcItem)) return; - rcSelMark.left = LVIR_BOUNDS; - if (!LISTVIEW_GetItemRect(infoPtr, infoPtr->nSelectionMark, &rcSelMark)) return; - UnionRect(&rcSel, &rcItem, &rcSelMark); - iterator_frameditems(&i, infoPtr, &rcSel); - while(iterator_next(&i)) - { - LISTVIEW_GetItemPosition(infoPtr, i.nItem, &ptItem); - if (PtInRect(&rcSel, ptItem)) ranges_additem(selection, i.nItem); - } - iterator_destroy(&i); - } - - LISTVIEW_DeselectAllSkipItems(infoPtr, selection); - iterator_rangesitems(&i, selection); - while(iterator_next(&i)) - LISTVIEW_SetItemState(infoPtr, i.nItem, &item); - /* this will also destroy the selection */ - iterator_destroy(&i); - - LISTVIEW_SetItemFocus(infoPtr, nItem); -} - -/*** - * DESCRIPTION: - * Sets a single selection. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nItem : item index - * - * RETURN: - * None - */ -static void LISTVIEW_SetSelection(LISTVIEW_INFO *infoPtr, INT nItem) -{ - LVITEMW lvItem; - - TRACE("nItem=%d\n", nItem); - - LISTVIEW_DeselectAllSkipItem(infoPtr, nItem); - - lvItem.state = LVIS_FOCUSED | LVIS_SELECTED; - lvItem.stateMask = LVIS_FOCUSED | LVIS_SELECTED; - LISTVIEW_SetItemState(infoPtr, nItem, &lvItem); - - infoPtr->nSelectionMark = nItem; -} - -/*** - * DESCRIPTION: - * Set selection(s) with keyboard. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nItem : item index - * - * RETURN: - * SUCCESS : TRUE (needs to be repainted) - * FAILURE : FALSE (nothing has changed) - */ -static BOOL LISTVIEW_KeySelection(LISTVIEW_INFO *infoPtr, INT nItem) -{ - /* FIXME: pass in the state */ - WORD wShift = HIWORD(GetKeyState(VK_SHIFT)); - WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL)); - BOOL bResult = FALSE; - - if ((nItem >= 0) && (nItem < infoPtr->nItemCount)) - { - if (infoPtr->dwStyle & LVS_SINGLESEL) - { - bResult = TRUE; - LISTVIEW_SetSelection(infoPtr, nItem); - } - else - { - if (wShift) - { - bResult = TRUE; - LISTVIEW_SetGroupSelection(infoPtr, nItem); - } - else if (wCtrl) - { - bResult = LISTVIEW_SetItemFocus(infoPtr, nItem); - } - else - { - bResult = TRUE; - LISTVIEW_SetSelection(infoPtr, nItem); - } - } - LISTVIEW_EnsureVisible(infoPtr, nItem, FALSE); - } - - UpdateWindow(infoPtr->hwndSelf); /* update client area */ - return bResult; -} - -static BOOL LISTVIEW_GetItemAtPt(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, POINT pt) -{ - LVHITTESTINFO lvHitTestInfo; - - ZeroMemory(&lvHitTestInfo, sizeof(lvHitTestInfo)); - lvHitTestInfo.pt.x = pt.x; - lvHitTestInfo.pt.y = pt.y; - - LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE); - - lpLVItem->mask = LVIF_PARAM; - lpLVItem->iItem = lvHitTestInfo.iItem; - lpLVItem->iSubItem = 0; - - return LISTVIEW_GetItemT(infoPtr, lpLVItem, TRUE); -} - -/*** - * DESCRIPTION: - * Called when the mouse is being actively tracked and has hovered for a specified - * amount of time - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] fwKeys : key indicator - * [I] x,y : mouse position - * - * RETURN: - * 0 if the message was processed, non-zero if there was an error - * - * INFO: - * LVS_EX_TRACKSELECT: An item is automatically selected when the cursor remains - * over the item for a certain period of time. - * - */ -static LRESULT LISTVIEW_MouseHover(LISTVIEW_INFO *infoPtr, WORD fwKyes, INT x, INT y) -{ - if (infoPtr->dwLvExStyle & LVS_EX_TRACKSELECT) - { - LVITEMW item; - POINT pt; - - pt.x = x; - pt.y = y; - - if (LISTVIEW_GetItemAtPt(infoPtr, &item, pt)) - LISTVIEW_SetSelection(infoPtr, item.iItem); - } - - return 0; -} - -/*** - * DESCRIPTION: - * Called whenever WM_MOUSEMOVE is received. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] fwKeys : key indicator - * [I] x,y : mouse position - * - * RETURN: - * 0 if the message is processed, non-zero if there was an error - */ -static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, INT y) -{ - TRACKMOUSEEVENT trackinfo; - - if (infoPtr->bLButtonDown && DragDetect(infoPtr->hwndSelf, infoPtr->ptClickPos)) - { - LVHITTESTINFO lvHitTestInfo; - NMLISTVIEW nmlv; - - lvHitTestInfo.pt = infoPtr->ptClickPos; - LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE); - - ZeroMemory(&nmlv, sizeof(nmlv)); - nmlv.iItem = lvHitTestInfo.iItem; - nmlv.ptAction = infoPtr->ptClickPos; - - notify_listview(infoPtr, LVN_BEGINDRAG, &nmlv); - - return 0; - } - - /* see if we are supposed to be tracking mouse hovering */ - if(infoPtr->dwLvExStyle & LVS_EX_TRACKSELECT) { - /* fill in the trackinfo struct */ - trackinfo.cbSize = sizeof(TRACKMOUSEEVENT); - trackinfo.dwFlags = TME_QUERY; - trackinfo.hwndTrack = infoPtr->hwndSelf; - trackinfo.dwHoverTime = infoPtr->dwHoverTime; - - /* see if we are already tracking this hwnd */ - _TrackMouseEvent(&trackinfo); - - if(!(trackinfo.dwFlags & TME_HOVER)) { - trackinfo.dwFlags = TME_HOVER; - - /* call TRACKMOUSEEVENT so we receive WM_MOUSEHOVER messages */ - _TrackMouseEvent(&trackinfo); - } - } - - return 0; -} - - -/*** - * Tests wheather the item is assignable to a list with style lStyle - */ -static inline BOOL is_assignable_item(const LVITEMW *lpLVItem, LONG lStyle) -{ - if ( (lpLVItem->mask & LVIF_TEXT) && - (lpLVItem->pszText == LPSTR_TEXTCALLBACKW) && - (lStyle & (LVS_SORTASCENDING | LVS_SORTDESCENDING)) ) return FALSE; - - return TRUE; -} - - -/*** - * DESCRIPTION: - * Helper for LISTVIEW_SetItemT *only*: sets item attributes. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] lpLVItem : valid pointer to new item atttributes - * [I] isNew : the item being set is being inserted - * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI - * [O] bChanged : will be set to TRUE if the item really changed - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL set_main_item(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isNew, BOOL isW, BOOL *bChanged) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - ITEM_INFO *lpItem; - NMLISTVIEW nmlv; - UINT uChanged = 0; - LVITEMW item; - - TRACE("()\n"); - - assert(lpLVItem->iItem >= 0 && lpLVItem->iItem < infoPtr->nItemCount); - - if (lpLVItem->mask == 0) return TRUE; - - if (infoPtr->dwStyle & LVS_OWNERDATA) - { - /* a virtual listview we stores only selection and focus */ - if (lpLVItem->mask & ~LVIF_STATE) - return FALSE; - lpItem = NULL; - } - else - { - HDPA hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem); - lpItem = (ITEM_INFO *)DPA_GetPtr(hdpaSubItems, 0); - assert (lpItem); - } - - /* we need to get the lParam and state of the item */ - item.iItem = lpLVItem->iItem; - item.iSubItem = lpLVItem->iSubItem; - item.mask = LVIF_STATE | LVIF_PARAM; - item.stateMask = ~0; - item.state = 0; - item.lParam = 0; - if (!isNew && !LISTVIEW_GetItemW(infoPtr, &item)) return FALSE; - - TRACE("oldState=%x, newState=%x\n", item.state, lpLVItem->state); - /* determine what fields will change */ - if ((lpLVItem->mask & LVIF_STATE) && ((item.state ^ lpLVItem->state) & lpLVItem->stateMask & ~infoPtr->uCallbackMask)) - uChanged |= LVIF_STATE; - - if ((lpLVItem->mask & LVIF_IMAGE) && (lpItem->hdr.iImage != lpLVItem->iImage)) - uChanged |= LVIF_IMAGE; - - if ((lpLVItem->mask & LVIF_PARAM) && (lpItem->lParam != lpLVItem->lParam)) - uChanged |= LVIF_PARAM; - - if ((lpLVItem->mask & LVIF_INDENT) && (lpItem->iIndent != lpLVItem->iIndent)) - uChanged |= LVIF_INDENT; - - if ((lpLVItem->mask & LVIF_TEXT) && textcmpWT(lpItem->hdr.pszText, lpLVItem->pszText, isW)) - uChanged |= LVIF_TEXT; - - TRACE("uChanged=0x%x\n", uChanged); - if (!uChanged) return TRUE; - *bChanged = TRUE; - - ZeroMemory(&nmlv, sizeof(NMLISTVIEW)); - nmlv.iItem = lpLVItem->iItem; - nmlv.uNewState = (item.state & ~lpLVItem->stateMask) | (lpLVItem->state & lpLVItem->stateMask); - nmlv.uOldState = item.state; - nmlv.uChanged = uChanged; - nmlv.lParam = item.lParam; - - /* send LVN_ITEMCHANGING notification, if the item is not being inserted */ - /* and we are _NOT_ virtual (LVS_OWERNDATA), and change notifications */ - /* are enabled */ - if(lpItem && !isNew && infoPtr->bDoChangeNotify && - notify_listview(infoPtr, LVN_ITEMCHANGING, &nmlv)) - return FALSE; - - /* copy information */ - if (lpLVItem->mask & LVIF_TEXT) - textsetptrT(&lpItem->hdr.pszText, lpLVItem->pszText, isW); - - if (lpLVItem->mask & LVIF_IMAGE) - lpItem->hdr.iImage = lpLVItem->iImage; - - if (lpLVItem->mask & LVIF_PARAM) - lpItem->lParam = lpLVItem->lParam; - - if (lpLVItem->mask & LVIF_INDENT) - lpItem->iIndent = lpLVItem->iIndent; - - if (uChanged & LVIF_STATE) - { - if (lpItem && (lpLVItem->stateMask & ~infoPtr->uCallbackMask & ~(LVIS_FOCUSED | LVIS_SELECTED))) - { - lpItem->state &= ~lpLVItem->stateMask; - lpItem->state |= (lpLVItem->state & lpLVItem->stateMask); - } - if (lpLVItem->state & lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED) - { - if (infoPtr->dwStyle & LVS_SINGLESEL) LISTVIEW_DeselectAllSkipItem(infoPtr, lpLVItem->iItem); - ranges_additem(infoPtr->selectionRanges, lpLVItem->iItem); - } - else if (lpLVItem->stateMask & LVIS_SELECTED) - ranges_delitem(infoPtr->selectionRanges, lpLVItem->iItem); - - /* if we are asked to change focus, and we manage it, do it */ - if (lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED) - { - if (lpLVItem->state & LVIS_FOCUSED) - { - LISTVIEW_SetItemFocus(infoPtr, -1); - infoPtr->nFocusedItem = lpLVItem->iItem; - LISTVIEW_EnsureVisible(infoPtr, lpLVItem->iItem, uView == LVS_LIST); - } - else if (infoPtr->nFocusedItem == lpLVItem->iItem) - infoPtr->nFocusedItem = -1; - } - } - - /* if we're inserting the item, we're done */ - if (isNew) return TRUE; - - /* send LVN_ITEMCHANGED notification */ - if (lpLVItem->mask & LVIF_PARAM) nmlv.lParam = lpLVItem->lParam; - if (infoPtr->bDoChangeNotify) notify_listview(infoPtr, LVN_ITEMCHANGED, &nmlv); - - return TRUE; -} - -/*** - * DESCRIPTION: - * Helper for LISTVIEW_{Set,Insert}ItemT *only*: sets subitem attributes. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] lpLVItem : valid pointer to new subitem atttributes - * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI - * [O] bChanged : will be set to TRUE if the item really changed - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL set_sub_item(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isW, BOOL *bChanged) -{ - HDPA hdpaSubItems; - SUBITEM_INFO *lpSubItem; - - /* we do not support subitems for virtual listviews */ - if (infoPtr->dwStyle & LVS_OWNERDATA) return FALSE; - - /* set subitem only if column is present */ - if (lpLVItem->iSubItem >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE; - - /* First do some sanity checks */ - if (lpLVItem->mask & ~(LVIF_TEXT | LVIF_IMAGE)) return FALSE; - if (!(lpLVItem->mask & (LVIF_TEXT | LVIF_IMAGE))) return TRUE; - - /* get the subitem structure, and create it if not there */ - hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem); - assert (hdpaSubItems); - - lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem); - if (!lpSubItem) - { - SUBITEM_INFO *tmpSubItem; - INT i; - - lpSubItem = (SUBITEM_INFO *)Alloc(sizeof(SUBITEM_INFO)); - if (!lpSubItem) return FALSE; - /* we could binary search here, if need be...*/ - for (i = 1; i < DPA_GetPtrCount(hdpaSubItems); i++) - { - tmpSubItem = (SUBITEM_INFO *)DPA_GetPtr(hdpaSubItems, i); - if (tmpSubItem->iSubItem > lpLVItem->iSubItem) break; - } - if (DPA_InsertPtr(hdpaSubItems, i, lpSubItem) == -1) - { - Free(lpSubItem); - return FALSE; - } - lpSubItem->iSubItem = lpLVItem->iSubItem; - lpSubItem->hdr.iImage = I_IMAGECALLBACK; - *bChanged = TRUE; - } - - if (lpLVItem->mask & LVIF_IMAGE) - if (lpSubItem->hdr.iImage != lpLVItem->iImage) - { - lpSubItem->hdr.iImage = lpLVItem->iImage; - *bChanged = TRUE; - } - - if (lpLVItem->mask & LVIF_TEXT) - if (lpSubItem->hdr.pszText != lpLVItem->pszText) - { - textsetptrT(&lpSubItem->hdr.pszText, lpLVItem->pszText, isW); - *bChanged = TRUE; - } - - return TRUE; -} - -/*** - * DESCRIPTION: - * Sets item attributes. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] lpLVItem : new item atttributes - * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isW) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - LPWSTR pszText = NULL; - BOOL bResult, bChanged = FALSE; - - TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW); - - if (!lpLVItem || lpLVItem->iItem < 0 || lpLVItem->iItem >= infoPtr->nItemCount) - return FALSE; - - /* For efficiency, we transform the lpLVItem->pszText to Unicode here */ - if ((lpLVItem->mask & LVIF_TEXT) && is_textW(lpLVItem->pszText)) - { - pszText = lpLVItem->pszText; - ((LVITEMW *)lpLVItem)->pszText = textdupTtoW(lpLVItem->pszText, isW); - } - - /* actually set the fields */ - if (!is_assignable_item(lpLVItem, infoPtr->dwStyle)) return FALSE; - - if (lpLVItem->iSubItem) - bResult = set_sub_item(infoPtr, lpLVItem, TRUE, &bChanged); - else - bResult = set_main_item(infoPtr, lpLVItem, FALSE, TRUE, &bChanged); - - /* redraw item, if necessary */ - if (bChanged && !infoPtr->bIsDrawing) - { - /* this little optimization eliminates some nasty flicker */ - if ( uView == LVS_REPORT && !(infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && - (!(infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) || lpLVItem->iSubItem) ) - LISTVIEW_InvalidateSubItem(infoPtr, lpLVItem->iItem, lpLVItem->iSubItem); - else - LISTVIEW_InvalidateItem(infoPtr, lpLVItem->iItem); - } - /* restore text */ - if (pszText) - { - textfreeT(lpLVItem->pszText, isW); - ((LVITEMW *)lpLVItem)->pszText = pszText; - } - - return bResult; -} - -/*** - * DESCRIPTION: - * Retrieves the index of the item at coordinate (0, 0) of the client area. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * - * RETURN: - * item index - */ -static INT LISTVIEW_GetTopIndex(LISTVIEW_INFO *infoPtr) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - INT nItem = 0; - SCROLLINFO scrollInfo; - - scrollInfo.cbSize = sizeof(SCROLLINFO); - scrollInfo.fMask = SIF_POS; - - if (uView == LVS_LIST) - { - if (GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo)) - nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(infoPtr); - } - else if (uView == LVS_REPORT) - { - if (GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo)) - nItem = scrollInfo.nPos; - } - else - { - if (GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo)) - nItem = LISTVIEW_GetCountPerRow(infoPtr) * (scrollInfo.nPos / infoPtr->nItemHeight); - } - - TRACE("nItem=%d\n", nItem); - - return nItem; -} - - -/*** - * DESCRIPTION: - * Erases the background of the given rectangle - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] hdc : device context handle - * [I] lprcBox : clipping rectangle - * - * RETURN: - * Success: TRUE - * Failure: FALSE - */ -static inline BOOL LISTVIEW_FillBkgnd(LISTVIEW_INFO *infoPtr, HDC hdc, const RECT *lprcBox) -{ - if (!infoPtr->hBkBrush) return FALSE; - - TRACE("(hdc=%p, lprcBox=%s, hBkBrush=%p)\n", hdc, debugrect(lprcBox), infoPtr->hBkBrush); - - return FillRect(hdc, lprcBox, infoPtr->hBkBrush); -} - -/*** - * DESCRIPTION: - * Draws an item. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] hdc : device context handle - * [I] nItem : item index - * [I] nSubItem : subitem index - * [I] pos : item position in client coordinates - * [I] cdmode : custom draw mode - * - * RETURN: - * Success: TRUE - * Failure: FALSE - */ -static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, INT nSubItem, POINT pos, DWORD cdmode) -{ - UINT uFormat, uView = infoPtr->dwStyle & LVS_TYPEMASK; - WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' }; - static const WCHAR szCallback[] = { '(', 'c', 'a', 'l', 'l', 'b', 'a', 'c', 'k', ')', 0 }; - DWORD cdsubitemmode = CDRF_DODEFAULT; - RECT* lprcFocus, rcSelect, rcBox, rcState, rcIcon, rcLabel; - NMLVCUSTOMDRAW nmlvcd; - HIMAGELIST himl; - LVITEMW lvItem; - - TRACE("(hdc=%p, nItem=%d, nSubItem=%d, pos=%s)\n", hdc, nItem, nSubItem, debugpoint(&pos)); - - /* get information needed for drawing the item */ - lvItem.mask = LVIF_TEXT | LVIF_IMAGE; - if (nSubItem == 0) lvItem.mask |= LVIF_STATE | LVIF_PARAM; - if (uView == LVS_REPORT) lvItem.mask |= LVIF_INDENT; - lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK; - lvItem.iItem = nItem; - lvItem.iSubItem = nSubItem; - lvItem.state = 0; - lvItem.lParam = 0; - lvItem.cchTextMax = DISP_TEXT_SIZE; - lvItem.pszText = szDispText; - if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE; - if (nSubItem > 0 && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)) - lvItem.state = LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED); - if (lvItem.pszText == LPSTR_TEXTCALLBACKW) lvItem.pszText = (LPWSTR)szCallback; - TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem, TRUE)); - - /* now check if we need to update the focus rectangle */ - lprcFocus = infoPtr->bFocus && (lvItem.state & LVIS_FOCUSED) ? &infoPtr->rcFocus : 0; - - if (!lprcFocus) lvItem.state &= ~LVIS_FOCUSED; - LISTVIEW_GetItemMetrics(infoPtr, &lvItem, &rcBox, &rcState, &rcIcon, &rcLabel); - OffsetRect(&rcBox, pos.x, pos.y); - OffsetRect(&rcState, pos.x, pos.y); - OffsetRect(&rcIcon, pos.x, pos.y); - OffsetRect(&rcLabel, pos.x, pos.y); - TRACE(" rcBox=%s, rcState=%s, rcIcon=%s. rcLabel=%s\n", - debugrect(&rcBox), debugrect(&rcState), debugrect(&rcIcon), debugrect(&rcLabel)); - - /* fill in the custom draw structure */ - customdraw_fill(&nmlvcd, infoPtr, hdc, &rcBox, &lvItem); - - if (nSubItem > 0) cdmode = infoPtr->cditemmode; - if (cdmode & CDRF_NOTIFYITEMDRAW) - cdsubitemmode = notify_customdraw(infoPtr, CDDS_PREPAINT, &nmlvcd); - if (nSubItem == 0) infoPtr->cditemmode = cdsubitemmode; - if (cdsubitemmode & CDRF_SKIPDEFAULT) goto postpaint; - /* we have to send a CDDS_SUBITEM customdraw explicitly for subitem 0 */ - if (nSubItem == 0 && cdsubitemmode == CDRF_NOTIFYITEMDRAW) - { - cdsubitemmode = notify_customdraw(infoPtr, CDDS_SUBITEM | CDDS_ITEMPREPAINT, &nmlvcd); - if (cdsubitemmode & CDRF_SKIPDEFAULT) goto postpaint; - } - if (nSubItem == 0 || (cdmode & CDRF_NOTIFYITEMDRAW)) - prepaint_setup(infoPtr, hdc, &nmlvcd); - - /* in full row select, subitems, will just use main item's colors */ - if (nSubItem && uView == LVS_REPORT && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)) - nmlvcd.clrTextBk = CLR_NONE; - - /* state icons */ - if (infoPtr->himlState && !IsRectEmpty(&rcState)) - { - UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12; - if (uStateImage) - { - TRACE("uStateImage=%d\n", uStateImage); - ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcState.left, rcState.top, ILD_NORMAL); - } - } - - /* small icons */ - himl = (uView == LVS_ICON ? infoPtr->himlNormal : infoPtr->himlSmall); - if (himl && lvItem.iImage >= 0 && !IsRectEmpty(&rcIcon)) - { - TRACE("iImage=%d\n", lvItem.iImage); - ImageList_Draw(himl, lvItem.iImage, hdc, rcIcon.left, rcIcon.top, - (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus) ? ILD_SELECTED : ILD_NORMAL); - } - - /* Don't bother painting item being edited */ - if (infoPtr->hwndEdit && nItem == infoPtr->nEditLabelItem && nSubItem == 0) goto postpaint; - - /* draw the selection background, if we're drawing the main item */ - if (nSubItem == 0) - { - rcSelect = rcLabel; - if (uView == LVS_REPORT && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)) - rcSelect.right = rcBox.right; - - if (nmlvcd.clrTextBk != CLR_NONE) - ExtTextOutW(hdc, rcSelect.left, rcSelect.top, ETO_OPAQUE, &rcSelect, 0, 0, 0); - if(lprcFocus) *lprcFocus = rcSelect; - } - - /* figure out the text drawing flags */ - uFormat = (uView == LVS_ICON ? (lprcFocus ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS) : LV_SL_DT_FLAGS); - if (uView == LVS_ICON) - uFormat = (lprcFocus ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS); - else if (nSubItem) - { - switch (LISTVIEW_GetColumnInfo(infoPtr, nSubItem)->fmt & LVCFMT_JUSTIFYMASK) - { - case LVCFMT_RIGHT: uFormat |= DT_RIGHT; break; - case LVCFMT_CENTER: uFormat |= DT_CENTER; break; - default: uFormat |= DT_LEFT; - } - } - if (!(uFormat & (DT_RIGHT | DT_CENTER))) - { - if (himl && lvItem.iImage >= 0 && !IsRectEmpty(&rcIcon)) rcLabel.left += IMAGE_PADDING; - else rcLabel.left += LABEL_HOR_PADDING; - } - else if (uFormat & DT_RIGHT) rcLabel.right -= LABEL_HOR_PADDING; - DrawTextW(hdc, lvItem.pszText, -1, &rcLabel, uFormat); - -postpaint: - if (cdsubitemmode & CDRF_NOTIFYPOSTPAINT) - notify_postpaint(infoPtr, &nmlvcd); - return TRUE; -} - -/*** - * DESCRIPTION: - * Draws listview items when in owner draw mode. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] hdc : device context handle - * - * RETURN: - * None - */ -static void LISTVIEW_RefreshOwnerDraw(LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, DWORD cdmode) -{ - UINT uID = (UINT)GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); - DWORD cditemmode = CDRF_DODEFAULT; - NMLVCUSTOMDRAW nmlvcd; - POINT Origin, Position; - DRAWITEMSTRUCT dis; - LVITEMW item; - - TRACE("()\n"); - - ZeroMemory(&dis, sizeof(dis)); - - /* Get scroll info once before loop */ - LISTVIEW_GetOrigin(infoPtr, &Origin); - - /* iterate through the invalidated rows */ - while(iterator_next(i)) - { - item.iItem = i->nItem; - item.iSubItem = 0; - item.mask = LVIF_PARAM | LVIF_STATE; - item.stateMask = LVIS_SELECTED | LVIS_FOCUSED; - if (!LISTVIEW_GetItemW(infoPtr, &item)) continue; - - dis.CtlType = ODT_LISTVIEW; - dis.CtlID = uID; - dis.itemID = item.iItem; - dis.itemAction = ODA_DRAWENTIRE; - dis.itemState = 0; - if (item.state & LVIS_SELECTED) dis.itemState |= ODS_SELECTED; - if (infoPtr->bFocus && (item.state & LVIS_FOCUSED)) dis.itemState |= ODS_FOCUS; - dis.hwndItem = infoPtr->hwndSelf; - dis.hDC = hdc; - LISTVIEW_GetItemOrigin(infoPtr, dis.itemID, &Position); - dis.rcItem.left = Position.x + Origin.x; - dis.rcItem.right = dis.rcItem.left + infoPtr->nItemWidth; - dis.rcItem.top = Position.y + Origin.y; - dis.rcItem.bottom = dis.rcItem.top + infoPtr->nItemHeight; - dis.itemData = item.lParam; - - TRACE("item=%s, rcItem=%s\n", debuglvitem_t(&item, TRUE), debugrect(&dis.rcItem)); - - /* - * Even if we do not send the CDRF_NOTIFYITEMDRAW we need to fill the nmlvcd - * structure for the rest. of the paint cycle - */ - customdraw_fill(&nmlvcd, infoPtr, hdc, &dis.rcItem, &item); - if (cdmode & CDRF_NOTIFYITEMDRAW) - cditemmode = notify_customdraw(infoPtr, CDDS_PREPAINT, &nmlvcd); - - if (!(cditemmode & CDRF_SKIPDEFAULT)) - { - prepaint_setup (infoPtr, hdc, &nmlvcd); - SendMessageW(infoPtr->hwndNotify, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis); - } - - if (cditemmode & CDRF_NOTIFYPOSTPAINT) - notify_postpaint(infoPtr, &nmlvcd); - } -} - -/*** - * DESCRIPTION: - * Draws listview items when in report display mode. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] hdc : device context handle - * [I] cdmode : custom draw mode - * - * RETURN: - * None - */ -static void LISTVIEW_RefreshReport(LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, DWORD cdmode) -{ - INT rgntype; - RECT rcClip, rcItem; - POINT Origin, Position; - RANGE colRange; - ITERATOR j; - - TRACE("()\n"); - - /* figure out what to draw */ - rgntype = GetClipBox(hdc, &rcClip); - if (rgntype == NULLREGION) return; - - /* Get scroll info once before loop */ - LISTVIEW_GetOrigin(infoPtr, &Origin); - - /* narrow down the columns we need to paint */ - for(colRange.lower = 0; colRange.lower < DPA_GetPtrCount(infoPtr->hdpaColumns); colRange.lower++) - { - LISTVIEW_GetHeaderRect(infoPtr, colRange.lower, &rcItem); - if (rcItem.right + Origin.x >= rcClip.left) break; - } - for(colRange.upper = DPA_GetPtrCount(infoPtr->hdpaColumns); colRange.upper > 0; colRange.upper--) - { - LISTVIEW_GetHeaderRect(infoPtr, colRange.upper - 1, &rcItem); - if (rcItem.left + Origin.x < rcClip.right) break; - } - iterator_rangeitems(&j, colRange); - - /* in full row select, we _have_ to draw the main item */ - if (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) - j.nSpecial = 0; - - /* iterate through the invalidated rows */ - while(iterator_next(i)) - { - /* iterate through the invalidated columns */ - while(iterator_next(&j)) - { - LISTVIEW_GetItemOrigin(infoPtr, i->nItem, &Position); - Position.x += Origin.x; - Position.y += Origin.y; - - if (rgntype == COMPLEXREGION && !((infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) && j.nItem == 0)) - { - LISTVIEW_GetHeaderRect(infoPtr, j.nItem, &rcItem); - rcItem.top = 0; - rcItem.bottom = infoPtr->nItemHeight; - OffsetRect(&rcItem, Position.x, Position.y); - if (!RectVisible(hdc, &rcItem)) continue; - } - - LISTVIEW_DrawItem(infoPtr, hdc, i->nItem, j.nItem, Position, cdmode); - } - } - iterator_destroy(&j); -} - -/*** - * DESCRIPTION: - * Draws listview items when in list display mode. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] hdc : device context handle - * [I] cdmode : custom draw mode - * - * RETURN: - * None - */ -static void LISTVIEW_RefreshList(LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, DWORD cdmode) -{ - POINT Origin, Position; - - /* Get scroll info once before loop */ - LISTVIEW_GetOrigin(infoPtr, &Origin); - - while(iterator_prev(i)) - { - LISTVIEW_GetItemOrigin(infoPtr, i->nItem, &Position); - Position.x += Origin.x; - Position.y += Origin.y; - - LISTVIEW_DrawItem(infoPtr, hdc, i->nItem, 0, Position, cdmode); - } -} - - -/*** - * DESCRIPTION: - * Draws listview items. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] hdc : device context handle - * - * RETURN: - * NoneX - */ -static void LISTVIEW_Refresh(LISTVIEW_INFO *infoPtr, HDC hdc) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - COLORREF oldTextColor, oldClrTextBk, oldClrText; - NMLVCUSTOMDRAW nmlvcd; - HFONT hOldFont; - DWORD cdmode; - INT oldBkMode; - RECT rcClient; - ITERATOR i; - - LISTVIEW_DUMP(infoPtr); - - infoPtr->bIsDrawing = TRUE; - - /* save dc values we're gonna trash while drawing */ - hOldFont = SelectObject(hdc, infoPtr->hFont); - oldBkMode = GetBkMode(hdc); - infoPtr->clrTextBkDefault = GetBkColor(hdc); - oldTextColor = GetTextColor(hdc); - - oldClrTextBk = infoPtr->clrTextBk; - oldClrText = infoPtr->clrText; - - infoPtr->cditemmode = CDRF_DODEFAULT; - - GetClientRect(infoPtr->hwndSelf, &rcClient); - customdraw_fill(&nmlvcd, infoPtr, hdc, &rcClient, 0); - cdmode = notify_customdraw(infoPtr, CDDS_PREPAINT, &nmlvcd); - if (cdmode & CDRF_SKIPDEFAULT) goto enddraw; - prepaint_setup(infoPtr, hdc, &nmlvcd); - - /* Use these colors to draw the items */ - infoPtr->clrTextBk = nmlvcd.clrTextBk; - infoPtr->clrText = nmlvcd.clrText; - - /* nothing to draw */ - if(infoPtr->nItemCount == 0) goto enddraw; - - /* figure out what we need to draw */ - iterator_visibleitems(&i, infoPtr, hdc); - - /* send cache hint notification */ - if (infoPtr->dwStyle & LVS_OWNERDATA) - { - RANGE range = iterator_range(&i); - NMLVCACHEHINT nmlv; - - ZeroMemory(&nmlv, sizeof(NMLVCACHEHINT)); - nmlv.iFrom = range.lower; - nmlv.iTo = range.upper - 1; - notify_hdr(infoPtr, LVN_ODCACHEHINT, &nmlv.hdr); - } - - if ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (uView == LVS_REPORT)) - LISTVIEW_RefreshOwnerDraw(infoPtr, &i, hdc, cdmode); - else - { - if (uView == LVS_REPORT) - LISTVIEW_RefreshReport(infoPtr, &i, hdc, cdmode); - else /* LVS_LIST, LVS_ICON or LVS_SMALLICON */ - LISTVIEW_RefreshList(infoPtr, &i, hdc, cdmode); - - /* if we have a focus rect, draw it */ - if (infoPtr->bFocus) - DrawFocusRect(hdc, &infoPtr->rcFocus); - } - iterator_destroy(&i); - -enddraw: - if (cdmode & CDRF_NOTIFYPOSTPAINT) - notify_postpaint(infoPtr, &nmlvcd); - - infoPtr->clrTextBk = oldClrTextBk; - infoPtr->clrText = oldClrText; - - SelectObject(hdc, hOldFont); - SetBkMode(hdc, oldBkMode); - SetBkColor(hdc, infoPtr->clrTextBkDefault); - SetTextColor(hdc, oldTextColor); - infoPtr->bIsDrawing = FALSE; -} - - -/*** - * DESCRIPTION: - * Calculates the approximate width and height of a given number of items. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nItemCount : number of items - * [I] wWidth : width - * [I] wHeight : height - * - * RETURN: - * Returns a DWORD. The width in the low word and the height in high word. - */ -static DWORD LISTVIEW_ApproximateViewRect(LISTVIEW_INFO *infoPtr, INT nItemCount, - WORD wWidth, WORD wHeight) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - INT nItemCountPerColumn = 1; - INT nColumnCount = 0; - DWORD dwViewRect = 0; - - if (nItemCount == -1) - nItemCount = infoPtr->nItemCount; - - if (uView == LVS_LIST) - { - if (wHeight == 0xFFFF) - { - /* use current height */ - wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top; - } - - if (wHeight < infoPtr->nItemHeight) - wHeight = infoPtr->nItemHeight; - - if (nItemCount > 0) - { - if (infoPtr->nItemHeight > 0) - { - nItemCountPerColumn = wHeight / infoPtr->nItemHeight; - if (nItemCountPerColumn == 0) - nItemCountPerColumn = 1; - - if (nItemCount % nItemCountPerColumn != 0) - nColumnCount = nItemCount / nItemCountPerColumn; - else - nColumnCount = nItemCount / nItemCountPerColumn + 1; - } - } - - /* Microsoft padding magic */ - wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2; - wWidth = nColumnCount * infoPtr->nItemWidth + 2; - - dwViewRect = MAKELONG(wWidth, wHeight); - } - else if (uView == LVS_REPORT) - { - RECT rcBox; - - if (infoPtr->nItemCount > 0) - { - LISTVIEW_GetItemBox(infoPtr, 0, &rcBox); - wWidth = rcBox.right - rcBox.left; - wHeight = (rcBox.bottom - rcBox.top) * nItemCount; - } - else - { - /* use current height and width */ - if (wHeight == 0xffff) - wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top; - if (wWidth == 0xffff) - wWidth = infoPtr->rcList.right - infoPtr->rcList.left; - } - - dwViewRect = MAKELONG(wWidth, wHeight); - } - else if (uView == LVS_SMALLICON) - FIXME("uView == LVS_SMALLICON: not implemented\n"); - else if (uView == LVS_ICON) - FIXME("uView == LVS_ICON: not implemented\n"); - - return dwViewRect; -} - - -/*** - * DESCRIPTION: - * Create a drag image list for the specified item. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] iItem : index of item - * [O] lppt : Upperr-left corner of the image - * - * RETURN: - * Returns a handle to the image list if successful, NULL otherwise. - */ -static HIMAGELIST LISTVIEW_CreateDragImage(LISTVIEW_INFO *infoPtr, INT iItem, LPPOINT lppt) -{ - RECT rcItem; - SIZE size; - POINT pos; - HDC hdc, hdcOrig; - HBITMAP hbmp, hOldbmp; - HIMAGELIST dragList = 0; - TRACE("iItem=%d Count=%d \n", iItem, infoPtr->nItemCount); - - if (iItem < 0 || iItem >= infoPtr->nItemCount) - return 0; - - rcItem.left = LVIR_BOUNDS; - if (!LISTVIEW_GetItemRect(infoPtr, iItem, &rcItem)) - return 0; - - lppt->x = rcItem.left; - lppt->y = rcItem.top; - - size.cx = rcItem.right - rcItem.left; - size.cy = rcItem.bottom - rcItem.top; - - hdcOrig = GetDC(infoPtr->hwndSelf); - hdc = CreateCompatibleDC(hdcOrig); - hbmp = CreateCompatibleBitmap(hdcOrig, size.cx, size.cy); - hOldbmp = SelectObject(hdc, hbmp); - - rcItem.left = rcItem.top = 0; - rcItem.right = size.cx; - rcItem.bottom = size.cy; - FillRect(hdc, &rcItem, infoPtr->hBkBrush); - - pos.x = pos.y = 0; - if (LISTVIEW_DrawItem(infoPtr, hdc, iItem, 0, pos, infoPtr->cditemmode)) - { - dragList = ImageList_Create(size.cx, size.cy, ILC_COLOR, 10, 10); - SelectObject(hdc, hOldbmp); - ImageList_Add(dragList, hbmp, 0); - } - else - SelectObject(hdc, hOldbmp); - - DeleteObject(hbmp); - DeleteDC(hdc); - ReleaseDC(infoPtr->hwndSelf, hdcOrig); - - TRACE("ret=%p\n", dragList); - - return dragList; -} - - -/*** - * DESCRIPTION: - * Removes all listview items and subitems. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_DeleteAllItems(LISTVIEW_INFO *infoPtr) -{ - NMLISTVIEW nmlv; - HDPA hdpaSubItems = NULL; - BOOL bSuppress; - ITEMHDR *hdrItem; - INT i, j; - - TRACE("()\n"); - - /* we do it directly, to avoid notifications */ - ranges_clear(infoPtr->selectionRanges); - infoPtr->nSelectionMark = -1; - infoPtr->nFocusedItem = -1; - SetRectEmpty(&infoPtr->rcFocus); - /* But we are supposed to leave nHotItem as is! */ - - - /* send LVN_DELETEALLITEMS notification */ - ZeroMemory(&nmlv, sizeof(NMLISTVIEW)); - nmlv.iItem = -1; - bSuppress = notify_listview(infoPtr, LVN_DELETEALLITEMS, &nmlv); - - for (i = infoPtr->nItemCount - 1; i >= 0; i--) - { - /* send LVN_DELETEITEM notification, if not suppressed */ - if (!bSuppress) notify_deleteitem(infoPtr, i); - if (!(infoPtr->dwStyle & LVS_OWNERDATA)) - { - hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i); - for (j = 0; j < DPA_GetPtrCount(hdpaSubItems); j++) - { - hdrItem = (ITEMHDR *)DPA_GetPtr(hdpaSubItems, j); - if (is_textW(hdrItem->pszText)) Free(hdrItem->pszText); - Free(hdrItem); - } - DPA_Destroy(hdpaSubItems); - DPA_DeletePtr(infoPtr->hdpaItems, i); - } - DPA_DeletePtr(infoPtr->hdpaPosX, i); - DPA_DeletePtr(infoPtr->hdpaPosY, i); - infoPtr->nItemCount --; - } - - LISTVIEW_UpdateScroll(infoPtr); - - LISTVIEW_InvalidateList(infoPtr); - - return TRUE; -} - -/*** - * DESCRIPTION: - * Scrolls, and updates the columns, when a column is changing width. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nColumn : column to scroll - * [I] dx : amount of scroll, in pixels - * - * RETURN: - * None. - */ -static void LISTVIEW_ScrollColumns(LISTVIEW_INFO *infoPtr, INT nColumn, INT dx) -{ - COLUMN_INFO *lpColumnInfo; - RECT rcOld, rcCol; - POINT ptOrigin; - INT nCol; - - if (nColumn < 0 || DPA_GetPtrCount(infoPtr->hdpaColumns) < 1) return; - lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, min(nColumn, DPA_GetPtrCount(infoPtr->hdpaColumns) - 1)); - rcCol = lpColumnInfo->rcHeader; - if (nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) - rcCol.left = rcCol.right; - - /* ajust the other columns */ - for (nCol = nColumn; nCol < DPA_GetPtrCount(infoPtr->hdpaColumns); nCol++) - { - lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, nCol); - lpColumnInfo->rcHeader.left += dx; - lpColumnInfo->rcHeader.right += dx; - } - - /* do not update screen if not in report mode */ - if (!is_redrawing(infoPtr) || (infoPtr->dwStyle & LVS_TYPEMASK) != LVS_REPORT) return; - - /* if we have a focus, must first erase the focus rect */ - if (infoPtr->bFocus) LISTVIEW_ShowFocusRect(infoPtr, FALSE); - - /* Need to reset the item width when inserting a new column */ - infoPtr->nItemWidth += dx; - - LISTVIEW_UpdateScroll(infoPtr); - LISTVIEW_GetOrigin(infoPtr, &ptOrigin); - - /* scroll to cover the deleted column, and invalidate for redraw */ - rcOld = infoPtr->rcList; - rcOld.left = ptOrigin.x + rcCol.left + dx; - ScrollWindowEx(infoPtr->hwndSelf, dx, 0, &rcOld, &rcOld, 0, 0, SW_ERASE | SW_INVALIDATE); - - /* we can restore focus now */ - if (infoPtr->bFocus) LISTVIEW_ShowFocusRect(infoPtr, TRUE); -} - -/*** - * DESCRIPTION: - * Removes a column from the listview control. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nColumn : column index - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_DeleteColumn(LISTVIEW_INFO *infoPtr, INT nColumn) -{ - RECT rcCol; - - TRACE("nColumn=%d\n", nColumn); - - if (nColumn < 0 || DPA_GetPtrCount(infoPtr->hdpaColumns) == 0 - || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE; - - /* While the MSDN specifically says that column zero should not be deleted, - what actually happens is that the column itself is deleted but no items or subitems - are removed. - */ - - LISTVIEW_GetHeaderRect(infoPtr, nColumn, &rcCol); - - if (!Header_DeleteItem(infoPtr->hwndHeader, nColumn)) - return FALSE; - - Free(DPA_GetPtr(infoPtr->hdpaColumns, nColumn)); - DPA_DeletePtr(infoPtr->hdpaColumns, nColumn); - - if (!(infoPtr->dwStyle & LVS_OWNERDATA) && nColumn) - { - SUBITEM_INFO *lpSubItem, *lpDelItem; - HDPA hdpaSubItems; - INT nItem, nSubItem, i; - - for (nItem = 0; nItem < infoPtr->nItemCount; nItem++) - { - hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem); - nSubItem = 0; - lpDelItem = 0; - for (i = 1; i < DPA_GetPtrCount(hdpaSubItems); i++) - { - lpSubItem = (SUBITEM_INFO *)DPA_GetPtr(hdpaSubItems, i); - if (lpSubItem->iSubItem == nColumn) - { - nSubItem = i; - lpDelItem = lpSubItem; - } - else if (lpSubItem->iSubItem > nColumn) - { - lpSubItem->iSubItem--; - } - } - - /* if we found our subitem, zapp it */ - if (nSubItem > 0) - { - /* free string */ - if (is_textW(lpDelItem->hdr.pszText)) - Free(lpDelItem->hdr.pszText); - - /* free item */ - Free(lpDelItem); - - /* free dpa memory */ - DPA_DeletePtr(hdpaSubItems, nSubItem); - } - } - } - - /* update the other column info */ - if(DPA_GetPtrCount(infoPtr->hdpaColumns) == 0) - LISTVIEW_InvalidateList(infoPtr); - else - LISTVIEW_ScrollColumns(infoPtr, nColumn, -(rcCol.right - rcCol.left)); - - return TRUE; -} - -/*** - * DESCRIPTION: - * Invalidates the listview after an item's insertion or deletion. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nItem : item index - * [I] dir : -1 if deleting, 1 if inserting - * - * RETURN: - * None - */ -static void LISTVIEW_ScrollOnInsert(LISTVIEW_INFO *infoPtr, INT nItem, INT dir) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - INT nPerCol, nItemCol, nItemRow; - RECT rcScroll; - POINT Origin; - - /* if we don't refresh, what's the point of scrolling? */ - if (!is_redrawing(infoPtr)) return; - - assert (abs(dir) == 1); - - /* arrange icons if autoarrange is on */ - if (is_autoarrange(infoPtr)) - { - BOOL arrange = TRUE; - if (dir < 0 && nItem >= infoPtr->nItemCount) arrange = FALSE; - if (dir > 0 && nItem == infoPtr->nItemCount - 1) arrange = FALSE; - if (arrange) LISTVIEW_Arrange(infoPtr, LVA_DEFAULT); - } - - /* scrollbars need updating */ - LISTVIEW_UpdateScroll(infoPtr); - - /* figure out the item's position */ - if (uView == LVS_REPORT) - nPerCol = infoPtr->nItemCount + 1; - else if (uView == LVS_LIST) - nPerCol = LISTVIEW_GetCountPerColumn(infoPtr); - else /* LVS_ICON, or LVS_SMALLICON */ - return; - - nItemCol = nItem / nPerCol; - nItemRow = nItem % nPerCol; - LISTVIEW_GetOrigin(infoPtr, &Origin); - - /* move the items below up a slot */ - rcScroll.left = nItemCol * infoPtr->nItemWidth; - rcScroll.top = nItemRow * infoPtr->nItemHeight; - rcScroll.right = rcScroll.left + infoPtr->nItemWidth; - rcScroll.bottom = nPerCol * infoPtr->nItemHeight; - OffsetRect(&rcScroll, Origin.x, Origin.y); - TRACE("rcScroll=%s, dx=%d\n", debugrect(&rcScroll), dir * infoPtr->nItemHeight); - if (IntersectRect(&rcScroll, &rcScroll, &infoPtr->rcList)) - { - TRACE("Scrolling rcScroll=%s, rcList=%s\n", debugrect(&rcScroll), debugrect(&infoPtr->rcList)); - ScrollWindowEx(infoPtr->hwndSelf, 0, dir * infoPtr->nItemHeight, - &rcScroll, &rcScroll, 0, 0, SW_ERASE | SW_INVALIDATE); - } - - /* report has only that column, so we're done */ - if (uView == LVS_REPORT) return; - - /* now for LISTs, we have to deal with the columns to the right */ - rcScroll.left = (nItemCol + 1) * infoPtr->nItemWidth; - rcScroll.top = 0; - rcScroll.right = (infoPtr->nItemCount / nPerCol + 1) * infoPtr->nItemWidth; - rcScroll.bottom = nPerCol * infoPtr->nItemHeight; - OffsetRect(&rcScroll, Origin.x, Origin.y); - if (IntersectRect(&rcScroll, &rcScroll, &infoPtr->rcList)) - ScrollWindowEx(infoPtr->hwndSelf, 0, dir * infoPtr->nItemHeight, - &rcScroll, &rcScroll, 0, 0, SW_ERASE | SW_INVALIDATE); -} - -/*** - * DESCRIPTION: - * Removes an item from the listview control. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nItem : item index - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_DeleteItem(LISTVIEW_INFO *infoPtr, INT nItem) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - LVITEMW item; - - TRACE("(nItem=%d)\n", nItem); - - if (nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE; - - /* remove selection, and focus */ - item.state = 0; - item.stateMask = LVIS_SELECTED | LVIS_FOCUSED; - LISTVIEW_SetItemState(infoPtr, nItem, &item); - - /* send LVN_DELETEITEM notification. */ - notify_deleteitem(infoPtr, nItem); - - /* we need to do this here, because we'll be deleting stuff */ - if (uView == LVS_SMALLICON || uView == LVS_ICON) - LISTVIEW_InvalidateItem(infoPtr, nItem); - - if (!(infoPtr->dwStyle & LVS_OWNERDATA)) - { - HDPA hdpaSubItems; - ITEMHDR *hdrItem; - INT i; - - hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem); - for (i = 0; i < DPA_GetPtrCount(hdpaSubItems); i++) - { - hdrItem = (ITEMHDR *)DPA_GetPtr(hdpaSubItems, i); - if (is_textW(hdrItem->pszText)) Free(hdrItem->pszText); - Free(hdrItem); - } - DPA_Destroy(hdpaSubItems); - } - - if (uView == LVS_SMALLICON || uView == LVS_ICON) - { - DPA_DeletePtr(infoPtr->hdpaPosX, nItem); - DPA_DeletePtr(infoPtr->hdpaPosY, nItem); - } - - infoPtr->nItemCount--; - LISTVIEW_ShiftIndices(infoPtr, nItem, -1); - - /* now is the invalidation fun */ - LISTVIEW_ScrollOnInsert(infoPtr, nItem, -1); - return TRUE; -} - - -/*** - * DESCRIPTION: - * Callback implementation for editlabel control - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] pszText : modified text - * [I] isW : TRUE if psxText is Unicode, FALSE if it's ANSI - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_EndEditLabelT(LISTVIEW_INFO *infoPtr, LPWSTR pszText, BOOL isW) -{ - NMLVDISPINFOW dispInfo; - - TRACE("(pszText=%s, isW=%d)\n", debugtext_t(pszText, isW), isW); - - ZeroMemory(&dispInfo, sizeof(dispInfo)); - dispInfo.item.mask = LVIF_PARAM | LVIF_STATE; - dispInfo.item.iItem = infoPtr->nEditLabelItem; - dispInfo.item.iSubItem = 0; - dispInfo.item.stateMask = ~0; - if (!LISTVIEW_GetItemW(infoPtr, &dispInfo.item)) return FALSE; - /* add the text from the edit in */ - dispInfo.item.mask |= LVIF_TEXT; - dispInfo.item.pszText = pszText; - dispInfo.item.cchTextMax = textlenT(pszText, isW); - - /* Do we need to update the Item Text */ - if (!notify_dispinfoT(infoPtr, LVN_ENDLABELEDITW, &dispInfo, isW)) return FALSE; - if (!pszText) return TRUE; - - if (!(infoPtr->dwStyle & LVS_OWNERDATA)) - { - HDPA hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, infoPtr->nEditLabelItem); - ITEM_INFO* lpItem = (ITEM_INFO *)DPA_GetPtr(hdpaSubItems, 0); - if (lpItem && lpItem->hdr.pszText == LPSTR_TEXTCALLBACKW) - { - LISTVIEW_InvalidateItem(infoPtr, infoPtr->nEditLabelItem); - return TRUE; - } - } - - ZeroMemory(&dispInfo, sizeof(dispInfo)); - dispInfo.item.mask = LVIF_TEXT; - dispInfo.item.iItem = infoPtr->nEditLabelItem; - dispInfo.item.iSubItem = 0; - dispInfo.item.pszText = pszText; - dispInfo.item.cchTextMax = textlenT(pszText, isW); - return LISTVIEW_SetItemT(infoPtr, &dispInfo.item, isW); -} - -/*** - * DESCRIPTION: - * Begin in place editing of specified list view item - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nItem : item index - * [I] isW : TRUE if it's a Unicode req, FALSE if ASCII - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static HWND LISTVIEW_EditLabelT(LISTVIEW_INFO *infoPtr, INT nItem, BOOL isW) -{ - WCHAR szDispText[DISP_TEXT_SIZE] = { 0 }; - NMLVDISPINFOW dispInfo; - RECT rect; - - TRACE("(nItem=%d, isW=%d)\n", nItem, isW); - - if (~infoPtr->dwStyle & LVS_EDITLABELS) return 0; - if (nItem < 0 || nItem >= infoPtr->nItemCount) return 0; - - infoPtr->nEditLabelItem = nItem; - - /* Is the EditBox still there, if so remove it */ - if(infoPtr->hwndEdit != 0) - { - SetFocus(infoPtr->hwndSelf); - infoPtr->hwndEdit = 0; - } - - LISTVIEW_SetSelection(infoPtr, nItem); - LISTVIEW_SetItemFocus(infoPtr, nItem); - LISTVIEW_InvalidateItem(infoPtr, nItem); - - rect.left = LVIR_LABEL; - if (!LISTVIEW_GetItemRect(infoPtr, nItem, &rect)) return 0; - - ZeroMemory(&dispInfo, sizeof(dispInfo)); - dispInfo.item.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT; - dispInfo.item.iItem = nItem; - dispInfo.item.iSubItem = 0; - dispInfo.item.stateMask = ~0; - dispInfo.item.pszText = szDispText; - dispInfo.item.cchTextMax = DISP_TEXT_SIZE; - if (!LISTVIEW_GetItemT(infoPtr, &dispInfo.item, isW)) return 0; - - infoPtr->hwndEdit = CreateEditLabelT(infoPtr, dispInfo.item.pszText, WS_VISIBLE, - rect.left-2, rect.top-1, 0, rect.bottom - rect.top+2, isW); - if (!infoPtr->hwndEdit) return 0; - - if (notify_dispinfoT(infoPtr, LVN_BEGINLABELEDITW, &dispInfo, isW)) - { - SendMessageW(infoPtr->hwndEdit, WM_CLOSE, 0, 0); - infoPtr->hwndEdit = 0; - return 0; - } - - ShowWindow(infoPtr->hwndEdit, SW_NORMAL); - SetFocus(infoPtr->hwndEdit); - SendMessageW(infoPtr->hwndEdit, EM_SETSEL, 0, -1); - return infoPtr->hwndEdit; -} - - -/*** - * DESCRIPTION: - * Ensures the specified item is visible, scrolling into view if necessary. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nItem : item index - * [I] bPartial : partially or entirely visible - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_EnsureVisible(LISTVIEW_INFO *infoPtr, INT nItem, BOOL bPartial) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - INT nScrollPosHeight = 0; - INT nScrollPosWidth = 0; - INT nHorzAdjust = 0; - INT nVertAdjust = 0; - INT nHorzDiff = 0; - INT nVertDiff = 0; - RECT rcItem, rcTemp; - - rcItem.left = LVIR_BOUNDS; - if (!LISTVIEW_GetItemRect(infoPtr, nItem, &rcItem)) return FALSE; - - if (bPartial && IntersectRect(&rcTemp, &infoPtr->rcList, &rcItem)) return TRUE; - - if (rcItem.left < infoPtr->rcList.left || rcItem.right > infoPtr->rcList.right) - { - /* scroll left/right, but in LVS_REPORT mode */ - if (uView == LVS_LIST) - nScrollPosWidth = infoPtr->nItemWidth; - else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON)) - nScrollPosWidth = 1; - - if (rcItem.left < infoPtr->rcList.left) - { - nHorzAdjust = -1; - if (uView != LVS_REPORT) nHorzDiff = rcItem.left - infoPtr->rcList.left; - } - else - { - nHorzAdjust = 1; - if (uView != LVS_REPORT) nHorzDiff = rcItem.right - infoPtr->rcList.right; - } - } - - if (rcItem.top < infoPtr->rcList.top || rcItem.bottom > infoPtr->rcList.bottom) - { - /* scroll up/down, but not in LVS_LIST mode */ - if (uView == LVS_REPORT) - nScrollPosHeight = infoPtr->nItemHeight; - else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON)) - nScrollPosHeight = 1; - - if (rcItem.top < infoPtr->rcList.top) - { - nVertAdjust = -1; - if (uView != LVS_LIST) nVertDiff = rcItem.top - infoPtr->rcList.top; - } - else - { - nVertAdjust = 1; - if (uView != LVS_LIST) nVertDiff = rcItem.bottom - infoPtr->rcList.bottom; - } - } - - if (!nScrollPosWidth && !nScrollPosHeight) return TRUE; - - if (nScrollPosWidth) - { - INT diff = nHorzDiff / nScrollPosWidth; - if (nHorzDiff % nScrollPosWidth) diff += nHorzAdjust; - LISTVIEW_HScroll(infoPtr, SB_INTERNAL, diff, 0); - } - - if (nScrollPosHeight) - { - INT diff = nVertDiff / nScrollPosHeight; - if (nVertDiff % nScrollPosHeight) diff += nVertAdjust; - LISTVIEW_VScroll(infoPtr, SB_INTERNAL, diff, 0); - } - - return TRUE; -} - -/*** - * DESCRIPTION: - * Searches for an item with specific characteristics. - * - * PARAMETER(S): - * [I] hwnd : window handle - * [I] nStart : base item index - * [I] lpFindInfo : item information to look for - * - * RETURN: - * SUCCESS : index of item - * FAILURE : -1 - */ -static INT LISTVIEW_FindItemW(LISTVIEW_INFO *infoPtr, INT nStart, - const LVFINDINFOW *lpFindInfo) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' }; - BOOL bWrap = FALSE, bNearest = FALSE; - INT nItem = nStart + 1, nLast = infoPtr->nItemCount, nNearestItem = -1; - ULONG xdist, ydist, dist, mindist = 0x7fffffff; - POINT Position, Destination; - LVITEMW lvItem; - - if (!lpFindInfo || nItem < 0) return -1; - - lvItem.mask = 0; - if (lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL)) - { - lvItem.mask |= LVIF_TEXT; - lvItem.pszText = szDispText; - lvItem.cchTextMax = DISP_TEXT_SIZE; - } - - if (lpFindInfo->flags & LVFI_WRAP) - bWrap = TRUE; - - if ((lpFindInfo->flags & LVFI_NEARESTXY) && - (uView == LVS_ICON || uView ==LVS_SMALLICON)) - { - POINT Origin; - RECT rcArea; - - LISTVIEW_GetOrigin(infoPtr, &Origin); - Destination.x = lpFindInfo->pt.x - Origin.x; - Destination.y = lpFindInfo->pt.y - Origin.y; - switch(lpFindInfo->vkDirection) - { - case VK_DOWN: Destination.y += infoPtr->nItemHeight; break; - case VK_UP: Destination.y -= infoPtr->nItemHeight; break; - case VK_RIGHT: Destination.x += infoPtr->nItemWidth; break; - case VK_LEFT: Destination.x -= infoPtr->nItemWidth; break; - case VK_HOME: Destination.x = Destination.y = 0; break; - case VK_NEXT: Destination.y += infoPtr->rcList.bottom - infoPtr->rcList.top; break; - case VK_PRIOR: Destination.y -= infoPtr->rcList.bottom - infoPtr->rcList.top; break; - case VK_END: - LISTVIEW_GetAreaRect(infoPtr, &rcArea); - Destination.x = rcArea.right; - Destination.y = rcArea.bottom; - break; - default: ERR("Unknown vkDirection=%d\n", lpFindInfo->vkDirection); - } - bNearest = TRUE; - } - - /* if LVFI_PARAM is specified, all other flags are ignored */ - if (lpFindInfo->flags & LVFI_PARAM) - { - lvItem.mask |= LVIF_PARAM; - bNearest = FALSE; - lvItem.mask &= ~LVIF_TEXT; - } - -again: - for (; nItem < nLast; nItem++) - { - lvItem.iItem = nItem; - lvItem.iSubItem = 0; - if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) continue; - - if (lvItem.mask & LVIF_PARAM) - { - if (lpFindInfo->lParam == lvItem.lParam) - return nItem; - else - continue; - } - - if (lvItem.mask & LVIF_TEXT) - { - if (lpFindInfo->flags & LVFI_PARTIAL) - { - if (strstrW(lvItem.pszText, lpFindInfo->psz) == NULL) continue; - } - else - { - if (lstrcmpW(lvItem.pszText, lpFindInfo->psz) != 0) continue; - } - } - - if (!bNearest) return nItem; - - /* This is very inefficient. To do a good job here, - * we need a sorted array of (x,y) item positions */ - LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position); - - /* compute the distance^2 to the destination */ - xdist = Destination.x - Position.x; - ydist = Destination.y - Position.y; - dist = xdist * xdist + ydist * ydist; - - /* remember the distance, and item if it's closer */ - if (dist < mindist) - { - mindist = dist; - nNearestItem = nItem; - } - } - - if (bWrap) - { - nItem = 0; - nLast = min(nStart + 1, infoPtr->nItemCount); - bWrap = FALSE; - goto again; - } - - return nNearestItem; -} - -/*** - * DESCRIPTION: - * Searches for an item with specific characteristics. - * - * PARAMETER(S): - * [I] hwnd : window handle - * [I] nStart : base item index - * [I] lpFindInfo : item information to look for - * - * RETURN: - * SUCCESS : index of item - * FAILURE : -1 - */ -static INT LISTVIEW_FindItemA(LISTVIEW_INFO *infoPtr, INT nStart, - const LVFINDINFOA *lpFindInfo) -{ - BOOL hasText = lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL); - LVFINDINFOW fiw; - INT res; - - memcpy(&fiw, lpFindInfo, sizeof(fiw)); - if (hasText) fiw.psz = textdupTtoW((LPCWSTR)lpFindInfo->psz, FALSE); - res = LISTVIEW_FindItemW(infoPtr, nStart, &fiw); - if (hasText) textfreeT((LPWSTR)fiw.psz, FALSE); - return res; -} - -/*** - * DESCRIPTION: - * Retrieves the background image of the listview control. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [O] lpBkImage : background image attributes - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -/* static BOOL LISTVIEW_GetBkImage(LISTVIEW_INFO *infoPtr, LPLVBKIMAGE lpBkImage) */ -/* { */ -/* FIXME (listview, "empty stub!\n"); */ -/* return FALSE; */ -/* } */ - -/*** - * DESCRIPTION: - * Retrieves column attributes. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nColumn : column index - * [IO] lpColumn : column information - * [I] isW : if TRUE, then lpColumn is a LPLVCOLUMNW - * otherwise it is in fact a LPLVCOLUMNA - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_GetColumnT(LISTVIEW_INFO *infoPtr, INT nColumn, LPLVCOLUMNW lpColumn, BOOL isW) -{ - COLUMN_INFO *lpColumnInfo; - HDITEMW hdi; - - if (!lpColumn || nColumn < 0 || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE; - lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, nColumn); - - /* initialize memory */ - ZeroMemory(&hdi, sizeof(hdi)); - - if (lpColumn->mask & LVCF_TEXT) - { - hdi.mask |= HDI_TEXT; - hdi.pszText = lpColumn->pszText; - hdi.cchTextMax = lpColumn->cchTextMax; - } - - if (lpColumn->mask & LVCF_IMAGE) - hdi.mask |= HDI_IMAGE; - - if (lpColumn->mask & LVCF_ORDER) - hdi.mask |= HDI_ORDER; - - if (!SendMessageW(infoPtr->hwndHeader, isW ? HDM_GETITEMW : HDM_GETITEMA, nColumn, (LPARAM)&hdi)) return FALSE; - - if (lpColumn->mask & LVCF_FMT) - lpColumn->fmt = lpColumnInfo->fmt; - - if (lpColumn->mask & LVCF_WIDTH) - lpColumn->cx = lpColumnInfo->rcHeader.right - lpColumnInfo->rcHeader.left; - - if (lpColumn->mask & LVCF_IMAGE) - lpColumn->iImage = hdi.iImage; - - if (lpColumn->mask & LVCF_ORDER) - lpColumn->iOrder = hdi.iOrder; - - return TRUE; -} - - -static BOOL LISTVIEW_GetColumnOrderArray(LISTVIEW_INFO *infoPtr, INT iCount, LPINT lpiArray) -{ - INT i; - - if (!lpiArray) - return FALSE; - - /* FIXME: little hack */ - for (i = 0; i < iCount; i++) - lpiArray[i] = i; - - return TRUE; -} - -/*** - * DESCRIPTION: - * Retrieves the column width. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] int : column index - * - * RETURN: - * SUCCESS : column width - * FAILURE : zero - */ -static INT LISTVIEW_GetColumnWidth(LISTVIEW_INFO *infoPtr, INT nColumn) -{ - INT nColumnWidth = 0; - RECT rcHeader; - - TRACE("nColumn=%d\n", nColumn); - - /* we have a 'column' in LIST and REPORT mode only */ - switch(infoPtr->dwStyle & LVS_TYPEMASK) - { - case LVS_LIST: - nColumnWidth = infoPtr->nItemWidth; - break; - case LVS_REPORT: - if (nColumn < 0 || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return 0; - LISTVIEW_GetHeaderRect(infoPtr, nColumn, &rcHeader); - nColumnWidth = rcHeader.right - rcHeader.left; - break; - } - - TRACE("nColumnWidth=%d\n", nColumnWidth); - return nColumnWidth; -} - -/*** - * DESCRIPTION: - * In list or report display mode, retrieves the number of items that can fit - * vertically in the visible area. In icon or small icon display mode, - * retrieves the total number of visible items. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * - * RETURN: - * Number of fully visible items. - */ -static INT LISTVIEW_GetCountPerPage(LISTVIEW_INFO *infoPtr) -{ - switch (infoPtr->dwStyle & LVS_TYPEMASK) - { - case LVS_ICON: - case LVS_SMALLICON: - return infoPtr->nItemCount; - case LVS_REPORT: - return LISTVIEW_GetCountPerColumn(infoPtr); - case LVS_LIST: - return LISTVIEW_GetCountPerRow(infoPtr) * LISTVIEW_GetCountPerColumn(infoPtr); - } - assert(FALSE); - return 0; -} - -/*** - * DESCRIPTION: - * Retrieves an image list handle. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nImageList : image list identifier - * - * RETURN: - * SUCCESS : image list handle - * FAILURE : NULL - */ -static HIMAGELIST LISTVIEW_GetImageList(LISTVIEW_INFO *infoPtr, INT nImageList) -{ - switch (nImageList) - { - case LVSIL_NORMAL: return infoPtr->himlNormal; - case LVSIL_SMALL: return infoPtr->himlSmall; - case LVSIL_STATE: return infoPtr->himlState; - } - return NULL; -} - -/* LISTVIEW_GetISearchString */ - -/*** - * DESCRIPTION: - * Retrieves item attributes. - * - * PARAMETER(S): - * [I] hwnd : window handle - * [IO] lpLVItem : item info - * [I] isW : if TRUE, then lpLVItem is a LPLVITEMW, - * if FALSE, the lpLVItem is a LPLVITEMA. - * - * NOTE: - * This is the internal 'GetItem' interface -- it tries to - * be smart, and avoids text copies, if possible, by modifing - * lpLVItem->pszText to point to the text string. Please note - * that this is not always possible (e.g. OWNERDATA), so on - * entry you *must* supply valid values for pszText, and cchTextMax. - * The only difference to the documented interface is that upon - * return, you should use *only* the lpLVItem->pszText, rather than - * the buffer pointer you provided on input. Most code already does - * that, so it's not a problem. - * For the two cases when the text must be copied (that is, - * for LVM_GETITEM, and LVM_GETITEMTEXT), use LISTVIEW_GetItemExtT. - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_GetItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW) -{ - ITEMHDR callbackHdr = { LPSTR_TEXTCALLBACKW, I_IMAGECALLBACK }; - NMLVDISPINFOW dispInfo; - ITEM_INFO *lpItem; - ITEMHDR* pItemHdr; - HDPA hdpaSubItems; - INT isubitem; - - TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW); - - if (!lpLVItem || lpLVItem->iItem < 0 || lpLVItem->iItem >= infoPtr->nItemCount) - return FALSE; - - if (lpLVItem->mask == 0) return TRUE; - - /* make a local copy */ - isubitem = lpLVItem->iSubItem; - - /* a quick optimization if all we're asked is the focus state - * these queries are worth optimising since they are common, - * and can be answered in constant time, without the heavy accesses */ - if ( (lpLVItem->mask == LVIF_STATE) && (lpLVItem->stateMask == LVIS_FOCUSED) && - !(infoPtr->uCallbackMask & LVIS_FOCUSED) ) - { - lpLVItem->state = 0; - if (infoPtr->nFocusedItem == lpLVItem->iItem) - lpLVItem->state |= LVIS_FOCUSED; - return TRUE; - } - - ZeroMemory(&dispInfo, sizeof(dispInfo)); - - /* if the app stores all the data, handle it separately */ - if (infoPtr->dwStyle & LVS_OWNERDATA) - { - dispInfo.item.state = 0; - - /* apprently, we should not callback for lParam in LVS_OWNERDATA */ - if ((lpLVItem->mask & ~(LVIF_STATE | LVIF_PARAM)) || infoPtr->uCallbackMask) - { - /* NOTE: copy only fields which we _know_ are initialized, some apps - * depend on the uninitialized fields being 0 */ - dispInfo.item.mask = lpLVItem->mask & ~LVIF_PARAM; - dispInfo.item.iItem = lpLVItem->iItem; - dispInfo.item.iSubItem = isubitem; - if (lpLVItem->mask & LVIF_TEXT) - { - dispInfo.item.pszText = lpLVItem->pszText; - dispInfo.item.cchTextMax = lpLVItem->cchTextMax; - } - if (lpLVItem->mask & LVIF_STATE) - dispInfo.item.stateMask = lpLVItem->stateMask & infoPtr->uCallbackMask; - notify_dispinfoT(infoPtr, LVN_GETDISPINFOW, &dispInfo, isW); - dispInfo.item.stateMask = lpLVItem->stateMask; - if (lpLVItem->mask & (LVIF_GROUPID|LVIF_COLUMNS)) - { - /* full size structure expected - _WIN32IE >= 0x560 */ - *lpLVItem = dispInfo.item; - } - else if (lpLVItem->mask & LVIF_INDENT) - { - /* indent member expected - _WIN32IE >= 0x300 */ - memcpy(lpLVItem, &dispInfo.item, offsetof( LVITEMW, iGroupId )); - } - else - { - /* minimal structure expected */ - memcpy(lpLVItem, &dispInfo.item, offsetof( LVITEMW, iIndent )); - } - TRACE(" getdispinfo(1):lpLVItem=%s\n", debuglvitem_t(lpLVItem, isW)); - } - - /* make sure lParam is zeroed out */ - if (lpLVItem->mask & LVIF_PARAM) lpLVItem->lParam = 0; - - /* we store only a little state, so if we're not asked, we're done */ - if (!(lpLVItem->mask & LVIF_STATE) || isubitem) return TRUE; - - /* if focus is handled by us, report it */ - if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED ) - { - lpLVItem->state &= ~LVIS_FOCUSED; - if (infoPtr->nFocusedItem == lpLVItem->iItem) - lpLVItem->state |= LVIS_FOCUSED; - } - - /* and do the same for selection, if we handle it */ - if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED ) - { - lpLVItem->state &= ~LVIS_SELECTED; - if (ranges_contain(infoPtr->selectionRanges, lpLVItem->iItem)) - lpLVItem->state |= LVIS_SELECTED; - } - - return TRUE; - } - - /* find the item and subitem structures before we proceed */ - hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem); - lpItem = (ITEM_INFO *)DPA_GetPtr(hdpaSubItems, 0); - assert (lpItem); - - if (isubitem) - { - SUBITEM_INFO *lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, isubitem); - pItemHdr = lpSubItem ? &lpSubItem->hdr : &callbackHdr; - if (!lpSubItem) - { - WARN(" iSubItem invalid (%08x), ignored.\n", isubitem); - isubitem = 0; - } - } - else - pItemHdr = &lpItem->hdr; - - /* Do we need to query the state from the app? */ - if ((lpLVItem->mask & LVIF_STATE) && infoPtr->uCallbackMask && isubitem == 0) - { - dispInfo.item.mask |= LVIF_STATE; - dispInfo.item.stateMask = infoPtr->uCallbackMask; - } - - /* Do we need to enquire about the image? */ - if ((lpLVItem->mask & LVIF_IMAGE) && pItemHdr->iImage == I_IMAGECALLBACK && - (isubitem == 0 || (infoPtr->dwLvExStyle & LVS_EX_SUBITEMIMAGES))) - { - dispInfo.item.mask |= LVIF_IMAGE; - dispInfo.item.iImage = I_IMAGECALLBACK; - } - - /* Apps depend on calling back for text if it is NULL or LPSTR_TEXTCALLBACKW */ - if ((lpLVItem->mask & LVIF_TEXT) && !is_textW(pItemHdr->pszText)) - { - dispInfo.item.mask |= LVIF_TEXT; - dispInfo.item.pszText = lpLVItem->pszText; - dispInfo.item.cchTextMax = lpLVItem->cchTextMax; - if (dispInfo.item.pszText && dispInfo.item.cchTextMax > 0) - *dispInfo.item.pszText = '\0'; - } - - /* If we don't have all the requested info, query the application */ - if (dispInfo.item.mask != 0) - { - dispInfo.item.iItem = lpLVItem->iItem; - dispInfo.item.iSubItem = lpLVItem->iSubItem; /* yes: the original subitem */ - dispInfo.item.lParam = lpItem->lParam; - notify_dispinfoT(infoPtr, LVN_GETDISPINFOW, &dispInfo, isW); - TRACE(" getdispinfo(2):item=%s\n", debuglvitem_t(&dispInfo.item, isW)); - } - - /* we should not store values for subitems */ - if (isubitem) dispInfo.item.mask &= ~LVIF_DI_SETITEM; - - /* Now, handle the iImage field */ - if (dispInfo.item.mask & LVIF_IMAGE) - { - lpLVItem->iImage = dispInfo.item.iImage; - if ((dispInfo.item.mask & LVIF_DI_SETITEM) && pItemHdr->iImage == I_IMAGECALLBACK) - pItemHdr->iImage = dispInfo.item.iImage; - } - else if (lpLVItem->mask & LVIF_IMAGE) - { - if(isubitem == 0 || (infoPtr->dwLvExStyle & LVS_EX_SUBITEMIMAGES)) - lpLVItem->iImage = pItemHdr->iImage; - else - lpLVItem->iImage = 0; - } - - /* The pszText field */ - if (dispInfo.item.mask & LVIF_TEXT) - { - if ((dispInfo.item.mask & LVIF_DI_SETITEM) && pItemHdr->pszText) - textsetptrT(&pItemHdr->pszText, dispInfo.item.pszText, isW); - - lpLVItem->pszText = dispInfo.item.pszText; - } - else if (lpLVItem->mask & LVIF_TEXT) - { - if (isW) lpLVItem->pszText = pItemHdr->pszText; - else textcpynT(lpLVItem->pszText, isW, pItemHdr->pszText, TRUE, lpLVItem->cchTextMax); - } - - /* if this is a subitem, we're done */ - if (isubitem) return TRUE; - - /* Next is the lParam field */ - if (dispInfo.item.mask & LVIF_PARAM) - { - lpLVItem->lParam = dispInfo.item.lParam; - if ((dispInfo.item.mask & LVIF_DI_SETITEM)) - lpItem->lParam = dispInfo.item.lParam; - } - else if (lpLVItem->mask & LVIF_PARAM) - lpLVItem->lParam = lpItem->lParam; - - /* ... the state field (this one is different due to uCallbackmask) */ - if (lpLVItem->mask & LVIF_STATE) - { - lpLVItem->state = lpItem->state; - if (dispInfo.item.mask & LVIF_STATE) - { - lpLVItem->state &= ~dispInfo.item.stateMask; - lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask); - } - if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED ) - { - lpLVItem->state &= ~LVIS_FOCUSED; - if (infoPtr->nFocusedItem == lpLVItem->iItem) - lpLVItem->state |= LVIS_FOCUSED; - } - if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED ) - { - lpLVItem->state &= ~LVIS_SELECTED; - if (ranges_contain(infoPtr->selectionRanges, lpLVItem->iItem)) - lpLVItem->state |= LVIS_SELECTED; - } - } - - /* and last, but not least, the indent field */ - if (lpLVItem->mask & LVIF_INDENT) - lpLVItem->iIndent = lpItem->iIndent; - - return TRUE; -} - -/*** - * DESCRIPTION: - * Retrieves item attributes. - * - * PARAMETER(S): - * [I] hwnd : window handle - * [IO] lpLVItem : item info - * [I] isW : if TRUE, then lpLVItem is a LPLVITEMW, - * if FALSE, the lpLVItem is a LPLVITEMA. - * - * NOTE: - * This is the external 'GetItem' interface -- it properly copies - * the text in the provided buffer. - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_GetItemExtT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW) -{ - LPWSTR pszText; - BOOL bResult; - - if (!lpLVItem || lpLVItem->iItem < 0 || lpLVItem->iItem >= infoPtr->nItemCount) - return FALSE; - - pszText = lpLVItem->pszText; - bResult = LISTVIEW_GetItemT(infoPtr, lpLVItem, isW); - if (bResult && lpLVItem->pszText != pszText) - textcpynT(pszText, isW, lpLVItem->pszText, isW, lpLVItem->cchTextMax); - lpLVItem->pszText = pszText; - - return bResult; -} - - -/*** - * DESCRIPTION: - * Retrieves the position (upper-left) of the listview control item. - * Note that for LVS_ICON style, the upper-left is that of the icon - * and not the bounding box. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nItem : item index - * [O] lpptPosition : coordinate information - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_GetItemPosition(LISTVIEW_INFO *infoPtr, INT nItem, LPPOINT lpptPosition) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - POINT Origin; - - TRACE("(nItem=%d, lpptPosition=%p)\n", nItem, lpptPosition); - - if (!lpptPosition || nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE; - - LISTVIEW_GetOrigin(infoPtr, &Origin); - LISTVIEW_GetItemOrigin(infoPtr, nItem, lpptPosition); - - if (uView == LVS_ICON) - { - lpptPosition->x += (infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2; - lpptPosition->y += ICON_TOP_PADDING; - } - lpptPosition->x += Origin.x; - lpptPosition->y += Origin.y; - - TRACE (" lpptPosition=%s\n", debugpoint(lpptPosition)); - return TRUE; -} - - -/*** - * DESCRIPTION: - * Retrieves the bounding rectangle for a listview control item. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nItem : item index - * [IO] lprc : bounding rectangle coordinates - * lprc->left specifies the portion of the item for which the bounding - * rectangle will be retrieved. - * - * LVIR_BOUNDS Returns the bounding rectangle of the entire item, - * including the icon and label. - * * - * * For LVS_ICON - * * Experiment shows that native control returns: - * * width = min (48, length of text line) - * * .left = position.x - (width - iconsize.cx)/2 - * * .right = .left + width - * * height = #lines of text * ntmHeight + icon height + 8 - * * .top = position.y - 2 - * * .bottom = .top + height - * * separation between items .y = itemSpacing.cy - height - * * .x = itemSpacing.cx - width - * LVIR_ICON Returns the bounding rectangle of the icon or small icon. - * * - * * For LVS_ICON - * * Experiment shows that native control returns: - * * width = iconSize.cx + 16 - * * .left = position.x - (width - iconsize.cx)/2 - * * .right = .left + width - * * height = iconSize.cy + 4 - * * .top = position.y - 2 - * * .bottom = .top + height - * * separation between items .y = itemSpacing.cy - height - * * .x = itemSpacing.cx - width - * LVIR_LABEL Returns the bounding rectangle of the item text. - * * - * * For LVS_ICON - * * Experiment shows that native control returns: - * * width = text length - * * .left = position.x - width/2 - * * .right = .left + width - * * height = ntmH * linecount + 2 - * * .top = position.y + iconSize.cy + 6 - * * .bottom = .top + height - * * separation between items .y = itemSpacing.cy - height - * * .x = itemSpacing.cx - width - * LVIR_SELECTBOUNDS Returns the union of the LVIR_ICON and LVIR_LABEL - * rectangles, but excludes columns in report view. - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - * - * NOTES - * Note that the bounding rectangle of the label in the LVS_ICON view depends - * upon whether the window has the focus currently and on whether the item - * is the one with the focus. Ensure that the control's record of which - * item has the focus agrees with the items' records. - */ -static BOOL LISTVIEW_GetItemRect(LISTVIEW_INFO *infoPtr, INT nItem, LPRECT lprc) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' }; - BOOL doLabel = TRUE, oversizedBox = FALSE; - POINT Position, Origin; - LVITEMW lvItem; - RECT label_rect; - - TRACE("(hwnd=%p, nItem=%d, lprc=%p)\n", infoPtr->hwndSelf, nItem, lprc); - - if (!lprc || nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE; - - LISTVIEW_GetOrigin(infoPtr, &Origin); - LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position); - - /* Be smart and try to figure out the minimum we have to do */ - if (lprc->left == LVIR_ICON) doLabel = FALSE; - if (uView == LVS_REPORT && lprc->left == LVIR_BOUNDS) doLabel = FALSE; - if (uView == LVS_ICON && lprc->left != LVIR_ICON && - infoPtr->bFocus && LISTVIEW_GetItemState(infoPtr, nItem, LVIS_FOCUSED)) - oversizedBox = TRUE; - - /* get what we need from the item before hand, so we make - * only one request. This can speed up things, if data - * is stored on the app side */ - lvItem.mask = 0; - if (uView == LVS_REPORT) lvItem.mask |= LVIF_INDENT; - if (doLabel) lvItem.mask |= LVIF_TEXT; - lvItem.iItem = nItem; - lvItem.iSubItem = 0; - lvItem.pszText = szDispText; - lvItem.cchTextMax = DISP_TEXT_SIZE; - if (lvItem.mask && !LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE; - /* we got the state already up, simulate it here, to avoid a reget */ - if (uView == LVS_ICON && (lprc->left != LVIR_ICON)) - { - lvItem.mask |= LVIF_STATE; - lvItem.stateMask = LVIS_FOCUSED; - lvItem.state = (oversizedBox ? LVIS_FOCUSED : 0); - } - - if (uView == LVS_REPORT && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) && lprc->left == LVIR_SELECTBOUNDS) - lprc->left = LVIR_BOUNDS; - switch(lprc->left) - { - case LVIR_ICON: - LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, lprc, NULL); - break; - - case LVIR_LABEL: - LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, NULL, lprc); - break; - - case LVIR_BOUNDS: - LISTVIEW_GetItemMetrics(infoPtr, &lvItem, lprc, NULL, NULL, NULL); - break; - - case LVIR_SELECTBOUNDS: - LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, lprc, &label_rect); - UnionRect(lprc, lprc, &label_rect); - break; - - default: - WARN("Unknown value: %ld\n", lprc->left); - return FALSE; - } - - OffsetRect(lprc, Position.x + Origin.x, Position.y + Origin.y); - - TRACE(" rect=%s\n", debugrect(lprc)); - - return TRUE; -} - -/*** - * DESCRIPTION: - * Retrieves the spacing between listview control items. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [IO] lprc : rectangle to receive the output - * on input, lprc->top = nSubItem - * lprc->left = LVIR_ICON | LVIR_BOUNDS | LVIR_LABEL - * - * NOTE: for subItem = 0, we should return the bounds of the _entire_ item, - * not only those of the first column. - * Fortunately, LISTVIEW_GetItemMetrics does the right thing. - * - * RETURN: - * TRUE: success - * FALSE: failure - */ -static BOOL LISTVIEW_GetSubItemRect(LISTVIEW_INFO *infoPtr, INT nItem, LPRECT lprc) -{ - POINT Position; - LVITEMW lvItem; - - if (!lprc) return FALSE; - - TRACE("(nItem=%d, nSubItem=%ld)\n", nItem, lprc->top); - /* On WinNT, a subitem of '0' calls LISTVIEW_GetItemRect */ - if (lprc->top == 0) - return LISTVIEW_GetItemRect(infoPtr, nItem, lprc); - - if ((infoPtr->dwStyle & LVS_TYPEMASK) != LVS_REPORT) return FALSE; - - if (!LISTVIEW_GetItemPosition(infoPtr, nItem, &Position)) return FALSE; - - lvItem.mask = 0; - lvItem.iItem = nItem; - lvItem.iSubItem = lprc->top; - - if (lvItem.mask && !LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE; - switch(lprc->left) - { - case LVIR_ICON: - LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, lprc, NULL); - break; - - case LVIR_LABEL: - case LVIR_BOUNDS: - LISTVIEW_GetItemMetrics(infoPtr, &lvItem, lprc, NULL, NULL, NULL); - break; - - default: - ERR("Unknown bounds=%ld\n", lprc->left); - return FALSE; - } - - OffsetRect(lprc, Position.x, Position.y); - return TRUE; -} - - -/*** - * DESCRIPTION: - * Retrieves the width of a label. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * - * RETURN: - * SUCCESS : string width (in pixels) - * FAILURE : zero - */ -static INT LISTVIEW_GetLabelWidth(LISTVIEW_INFO *infoPtr, INT nItem) -{ - WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' }; - LVITEMW lvItem; - - TRACE("(nItem=%d)\n", nItem); - - lvItem.mask = LVIF_TEXT; - lvItem.iItem = nItem; - lvItem.iSubItem = 0; - lvItem.pszText = szDispText; - lvItem.cchTextMax = DISP_TEXT_SIZE; - if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return 0; - - return LISTVIEW_GetStringWidthT(infoPtr, lvItem.pszText, TRUE); -} - -/*** - * DESCRIPTION: - * Retrieves the spacing between listview control items. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] bSmall : flag for small or large icon - * - * RETURN: - * Horizontal + vertical spacing - */ -static LONG LISTVIEW_GetItemSpacing(LISTVIEW_INFO *infoPtr, BOOL bSmall) -{ - LONG lResult; - - if (!bSmall) - { - lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy); - } - else - { - if ((infoPtr->dwStyle & LVS_TYPEMASK) == LVS_ICON) - lResult = MAKELONG(DEFAULT_COLUMN_WIDTH, GetSystemMetrics(SM_CXSMICON)+HEIGHT_PADDING); - else - lResult = MAKELONG(infoPtr->nItemWidth, infoPtr->nItemHeight); - } - return lResult; -} - -/*** - * DESCRIPTION: - * Retrieves the state of a listview control item. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nItem : item index - * [I] uMask : state mask - * - * RETURN: - * State specified by the mask. - */ -static UINT LISTVIEW_GetItemState(LISTVIEW_INFO *infoPtr, INT nItem, UINT uMask) -{ - LVITEMW lvItem; - - if (nItem < 0 || nItem >= infoPtr->nItemCount) return 0; - - lvItem.iItem = nItem; - lvItem.iSubItem = 0; - lvItem.mask = LVIF_STATE; - lvItem.stateMask = uMask; - if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return 0; - - return lvItem.state & uMask; -} - -/*** - * DESCRIPTION: - * Retrieves the text of a listview control item or subitem. - * - * PARAMETER(S): - * [I] hwnd : window handle - * [I] nItem : item index - * [IO] lpLVItem : item information - * [I] isW : TRUE if lpLVItem is Unicode - * - * RETURN: - * SUCCESS : string length - * FAILURE : 0 - */ -static INT LISTVIEW_GetItemTextT(LISTVIEW_INFO *infoPtr, INT nItem, LPLVITEMW lpLVItem, BOOL isW) -{ - if (!lpLVItem || nItem < 0 || nItem >= infoPtr->nItemCount) return 0; - - lpLVItem->mask = LVIF_TEXT; - lpLVItem->iItem = nItem; - if (!LISTVIEW_GetItemExtT(infoPtr, lpLVItem, isW)) return 0; - - return textlenT(lpLVItem->pszText, isW); -} - -/*** - * DESCRIPTION: - * Searches for an item based on properties + relationships. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nItem : item index - * [I] uFlags : relationship flag - * - * RETURN: - * SUCCESS : item index - * FAILURE : -1 - */ -static INT LISTVIEW_GetNextItem(LISTVIEW_INFO *infoPtr, INT nItem, UINT uFlags) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - UINT uMask = 0; - LVFINDINFOW lvFindInfo; - INT nCountPerColumn; - INT nCountPerRow; - INT i; - - TRACE("nItem=%d, uFlags=%x, nItemCount=%d\n", nItem, uFlags, infoPtr->nItemCount); - if (nItem < -1 || nItem >= infoPtr->nItemCount) return -1; - - ZeroMemory(&lvFindInfo, sizeof(lvFindInfo)); - - if (uFlags & LVNI_CUT) - uMask |= LVIS_CUT; - - if (uFlags & LVNI_DROPHILITED) - uMask |= LVIS_DROPHILITED; - - if (uFlags & LVNI_FOCUSED) - uMask |= LVIS_FOCUSED; - - if (uFlags & LVNI_SELECTED) - uMask |= LVIS_SELECTED; - - /* if we're asked for the focused item, that's only one, - * so it's worth optimizing */ - if (uFlags & LVNI_FOCUSED) - { - if ((LISTVIEW_GetItemState(infoPtr, infoPtr->nFocusedItem, uMask) & uMask) != uMask) return -1; - return (infoPtr->nFocusedItem == nItem) ? -1 : infoPtr->nFocusedItem; - } - - if (uFlags & LVNI_ABOVE) - { - if ((uView == LVS_LIST) || (uView == LVS_REPORT)) - { - while (nItem >= 0) - { - nItem--; - if ((ListView_GetItemState(infoPtr->hwndSelf, nItem, uMask) & uMask) == uMask) - return nItem; - } - } - else - { - /* Special case for autoarrange - move 'til the top of a list */ - if (is_autoarrange(infoPtr)) - { - nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr); - while (nItem - nCountPerRow >= 0) - { - nItem -= nCountPerRow; - if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask) - return nItem; - } - return -1; - } - lvFindInfo.flags = LVFI_NEARESTXY; - lvFindInfo.vkDirection = VK_UP; - ListView_GetItemPosition(infoPtr->hwndSelf, nItem, &lvFindInfo.pt); - while ((nItem = ListView_FindItemW(infoPtr->hwndSelf, nItem, &lvFindInfo)) != -1) - { - if ((ListView_GetItemState(infoPtr->hwndSelf, nItem, uMask) & uMask) == uMask) - return nItem; - } - } - } - else if (uFlags & LVNI_BELOW) - { - if ((uView == LVS_LIST) || (uView == LVS_REPORT)) - { - while (nItem < infoPtr->nItemCount) - { - nItem++; - if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask) - return nItem; - } - } - else - { - /* Special case for autoarrange - move 'til the bottom of a list */ - if (is_autoarrange(infoPtr)) - { - nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr); - while (nItem + nCountPerRow < infoPtr->nItemCount ) - { - nItem += nCountPerRow; - if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask) - return nItem; - } - return -1; - } - lvFindInfo.flags = LVFI_NEARESTXY; - lvFindInfo.vkDirection = VK_DOWN; - ListView_GetItemPosition(infoPtr->hwndSelf, nItem, &lvFindInfo.pt); - while ((nItem = ListView_FindItemW(infoPtr->hwndSelf, nItem, &lvFindInfo)) != -1) - { - if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask) - return nItem; - } - } - } - else if (uFlags & LVNI_TOLEFT) - { - if (uView == LVS_LIST) - { - nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr); - while (nItem - nCountPerColumn >= 0) - { - nItem -= nCountPerColumn; - if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask) - return nItem; - } - } - else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON)) - { - /* Special case for autoarrange - move 'ti the beginning of a row */ - if (is_autoarrange(infoPtr)) - { - nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr); - while (nItem % nCountPerRow > 0) - { - nItem --; - if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask) - return nItem; - } - return -1; - } - lvFindInfo.flags = LVFI_NEARESTXY; - lvFindInfo.vkDirection = VK_LEFT; - ListView_GetItemPosition(infoPtr->hwndSelf, nItem, &lvFindInfo.pt); - while ((nItem = ListView_FindItemW(infoPtr->hwndSelf, nItem, &lvFindInfo)) != -1) - { - if ((ListView_GetItemState(infoPtr->hwndSelf, nItem, uMask) & uMask) == uMask) - return nItem; - } - } - } - else if (uFlags & LVNI_TORIGHT) - { - if (uView == LVS_LIST) - { - nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr); - while (nItem + nCountPerColumn < infoPtr->nItemCount) - { - nItem += nCountPerColumn; - if ((ListView_GetItemState(infoPtr->hwndSelf, nItem, uMask) & uMask) == uMask) - return nItem; - } - } - else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON)) - { - /* Special case for autoarrange - move 'til the end of a row */ - if (is_autoarrange(infoPtr)) - { - nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr); - while (nItem % nCountPerRow < nCountPerRow - 1 ) - { - nItem ++; - if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask) - return nItem; - } - return -1; - } - lvFindInfo.flags = LVFI_NEARESTXY; - lvFindInfo.vkDirection = VK_RIGHT; - ListView_GetItemPosition(infoPtr->hwndSelf, nItem, &lvFindInfo.pt); - while ((nItem = ListView_FindItemW(infoPtr->hwndSelf, nItem, &lvFindInfo)) != -1) - { - if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask) - return nItem; - } - } - } - else - { - nItem++; - - /* search by index */ - for (i = nItem; i < infoPtr->nItemCount; i++) - { - if ((LISTVIEW_GetItemState(infoPtr, i, uMask) & uMask) == uMask) - return i; - } - } - - return -1; -} - -/* LISTVIEW_GetNumberOfWorkAreas */ - -/*** - * DESCRIPTION: - * Retrieves the origin coordinates when in icon or small icon display mode. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [O] lpptOrigin : coordinate information - * - * RETURN: - * None. - */ -static void LISTVIEW_GetOrigin(LISTVIEW_INFO *infoPtr, LPPOINT lpptOrigin) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - INT nHorzPos = 0, nVertPos = 0; - SCROLLINFO scrollInfo; - - scrollInfo.cbSize = sizeof(SCROLLINFO); - scrollInfo.fMask = SIF_POS; - - if (GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo)) - nHorzPos = scrollInfo.nPos; - if (GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo)) - nVertPos = scrollInfo.nPos; - - TRACE("nHorzPos=%d, nVertPos=%d\n", nHorzPos, nVertPos); - - lpptOrigin->x = infoPtr->rcList.left; - lpptOrigin->y = infoPtr->rcList.top; - if (uView == LVS_LIST) - nHorzPos *= infoPtr->nItemWidth; - else if (uView == LVS_REPORT) - nVertPos *= infoPtr->nItemHeight; - - lpptOrigin->x -= nHorzPos; - lpptOrigin->y -= nVertPos; - - TRACE(" origin=%s\n", debugpoint(lpptOrigin)); -} - -/*** - * DESCRIPTION: - * Retrieves the width of a string. - * - * PARAMETER(S): - * [I] hwnd : window handle - * [I] lpszText : text string to process - * [I] isW : TRUE if lpszText is Unicode, FALSE otherwise - * - * RETURN: - * SUCCESS : string width (in pixels) - * FAILURE : zero - */ -static INT LISTVIEW_GetStringWidthT(LISTVIEW_INFO *infoPtr, LPCWSTR lpszText, BOOL isW) -{ - SIZE stringSize; - - stringSize.cx = 0; - if (is_textT(lpszText, isW)) - { - HFONT hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont; - HDC hdc = GetDC(infoPtr->hwndSelf); - HFONT hOldFont = SelectObject(hdc, hFont); - - if (isW) - GetTextExtentPointW(hdc, lpszText, lstrlenW(lpszText), &stringSize); - else - GetTextExtentPointA(hdc, (LPCSTR)lpszText, lstrlenA((LPCSTR)lpszText), &stringSize); - SelectObject(hdc, hOldFont); - ReleaseDC(infoPtr->hwndSelf, hdc); - } - return stringSize.cx; -} - -/*** - * DESCRIPTION: - * Determines which listview item is located at the specified position. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [IO] lpht : hit test information - * [I] subitem : fill out iSubItem. - * [I] select : return the index only if the hit selects the item - * - * NOTE: - * (mm 20001022): We must not allow iSubItem to be touched, for - * an app might pass only a structure with space up to iItem! - * (MS Office 97 does that for instance in the file open dialog) - * - * RETURN: - * SUCCESS : item index - * FAILURE : -1 - */ -static INT LISTVIEW_HitTest(LISTVIEW_INFO *infoPtr, LPLVHITTESTINFO lpht, BOOL subitem, BOOL select) -{ - WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' }; - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - RECT rcBox, rcBounds, rcState, rcIcon, rcLabel, rcSearch; - POINT Origin, Position, opt; - LVITEMW lvItem; - ITERATOR i; - INT iItem; - - TRACE("(pt=%s, subitem=%d, select=%d)\n", debugpoint(&lpht->pt), subitem, select); - - lpht->flags = 0; - lpht->iItem = -1; - if (subitem) lpht->iSubItem = 0; - - if (infoPtr->rcList.left > lpht->pt.x) - lpht->flags |= LVHT_TOLEFT; - else if (infoPtr->rcList.right < lpht->pt.x) - lpht->flags |= LVHT_TORIGHT; - - if (infoPtr->rcList.top > lpht->pt.y) - lpht->flags |= LVHT_ABOVE; - else if (infoPtr->rcList.bottom < lpht->pt.y) - lpht->flags |= LVHT_BELOW; - - TRACE("lpht->flags=0x%x\n", lpht->flags); - if (lpht->flags) return -1; - - lpht->flags |= LVHT_NOWHERE; - - LISTVIEW_GetOrigin(infoPtr, &Origin); - - /* first deal with the large items */ - rcSearch.left = lpht->pt.x; - rcSearch.top = lpht->pt.y; - rcSearch.right = rcSearch.left + 1; - rcSearch.bottom = rcSearch.top + 1; - - iterator_frameditems(&i, infoPtr, &rcSearch); - iterator_next(&i); /* go to first item in the sequence */ - iItem = i.nItem; - iterator_destroy(&i); - - TRACE("lpht->iItem=%d\n", iItem); - if (iItem == -1) return -1; - - lvItem.mask = LVIF_STATE | LVIF_TEXT; - if (uView == LVS_REPORT) lvItem.mask |= LVIF_INDENT; - lvItem.stateMask = LVIS_STATEIMAGEMASK; - if (uView == LVS_ICON) lvItem.stateMask |= LVIS_FOCUSED; - lvItem.iItem = iItem; - lvItem.iSubItem = 0; - lvItem.pszText = szDispText; - lvItem.cchTextMax = DISP_TEXT_SIZE; - if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return -1; - if (!infoPtr->bFocus) lvItem.state &= ~LVIS_FOCUSED; - - LISTVIEW_GetItemMetrics(infoPtr, &lvItem, &rcBox, &rcState, &rcIcon, &rcLabel); - LISTVIEW_GetItemOrigin(infoPtr, iItem, &Position); - opt.x = lpht->pt.x - Position.x - Origin.x; - opt.y = lpht->pt.y - Position.y - Origin.y; - - if (uView == LVS_REPORT) - rcBounds = rcBox; - else - UnionRect(&rcBounds, &rcIcon, &rcLabel); - TRACE("rcBounds=%s\n", debugrect(&rcBounds)); - if (!PtInRect(&rcBounds, opt)) return -1; - - if (PtInRect(&rcIcon, opt)) - lpht->flags |= LVHT_ONITEMICON; - else if (PtInRect(&rcLabel, opt)) - lpht->flags |= LVHT_ONITEMLABEL; - else if (infoPtr->himlState && ((lvItem.state & LVIS_STATEIMAGEMASK) >> 12) && PtInRect(&rcState, opt)) - lpht->flags |= LVHT_ONITEMSTATEICON; - if (lpht->flags & LVHT_ONITEM) - lpht->flags &= ~LVHT_NOWHERE; - - TRACE("lpht->flags=0x%x\n", lpht->flags); - if (uView == LVS_REPORT && subitem) - { - INT j; - - rcBounds.right = rcBounds.left; - for (j = 0; j < DPA_GetPtrCount(infoPtr->hdpaColumns); j++) - { - rcBounds.left = rcBounds.right; - rcBounds.right += LISTVIEW_GetColumnWidth(infoPtr, j); - if (PtInRect(&rcBounds, opt)) - { - lpht->iSubItem = j; - break; - } - } - } - - if (select && !(uView == LVS_REPORT && - ((infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) || - (infoPtr->dwStyle & LVS_OWNERDRAWFIXED)))) - { - if (uView == LVS_REPORT) - { - UnionRect(&rcBounds, &rcIcon, &rcLabel); - UnionRect(&rcBounds, &rcBounds, &rcState); - } - if (!PtInRect(&rcBounds, opt)) iItem = -1; - } - return lpht->iItem = iItem; -} - - -/* LISTVIEW_InsertCompare: callback routine for comparing pszText members of the LV_ITEMS - in a LISTVIEW on insert. Passed to DPA_Sort in LISTVIEW_InsertItem. - This function should only be used for inserting items into a sorted list (LVM_INSERTITEM) - and not during the processing of a LVM_SORTITEMS message. Applications should provide - their own sort proc. when sending LVM_SORTITEMS. -*/ -/* Platform SDK: - (remarks on LVITEM: LVM_INSERTITEM will insert the new item in the proper sort postion... - if: - LVS_SORTXXX must be specified, - LVS_OWNERDRAW is not set, - .pszText is not LPSTR_TEXTCALLBACK. - - (LVS_SORT* flags): "For the LVS_SORTASCENDING... styles, item indices - are sorted based on item text..." -*/ -static INT WINAPI LISTVIEW_InsertCompare( LPVOID first, LPVOID second, LPARAM lParam) -{ - ITEM_INFO* lv_first = (ITEM_INFO*) DPA_GetPtr( (HDPA)first, 0 ); - ITEM_INFO* lv_second = (ITEM_INFO*) DPA_GetPtr( (HDPA)second, 0 ); - INT cmpv = textcmpWT(lv_first->hdr.pszText, lv_second->hdr.pszText, TRUE); - - /* if we're sorting descending, negate the return value */ - return (((LISTVIEW_INFO *)lParam)->dwStyle & LVS_SORTDESCENDING) ? -cmpv : cmpv; -} - -/*** - * DESCRIPTION: - * Inserts a new item in the listview control. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] lpLVItem : item information - * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI - * - * RETURN: - * SUCCESS : new item index - * FAILURE : -1 - */ -static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isW) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - INT nItem; - HDPA hdpaSubItems; - NMLISTVIEW nmlv; - ITEM_INFO *lpItem; - BOOL is_sorted, has_changed; - LVITEMW item; - - TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW); - - if (infoPtr->dwStyle & LVS_OWNERDATA) return infoPtr->nItemCount++; - - /* make sure it's an item, and not a subitem; cannot insert a subitem */ - if (!lpLVItem || lpLVItem->iItem < 0 || lpLVItem->iSubItem) return -1; - - if (!is_assignable_item(lpLVItem, infoPtr->dwStyle)) return -1; - - if (!(lpItem = (ITEM_INFO *)Alloc(sizeof(ITEM_INFO)))) return -1; - - /* insert item in listview control data structure */ - if ( !(hdpaSubItems = DPA_Create(8)) ) goto fail; - if ( !DPA_SetPtr(hdpaSubItems, 0, lpItem) ) assert (FALSE); - - is_sorted = (infoPtr->dwStyle & (LVS_SORTASCENDING | LVS_SORTDESCENDING)) && - !(infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (LPSTR_TEXTCALLBACKW != lpLVItem->pszText); - - nItem = is_sorted ? infoPtr->nItemCount : min(lpLVItem->iItem, infoPtr->nItemCount); - TRACE(" inserting at %d, sorted=%d, count=%d, iItem=%d\n", nItem, is_sorted, infoPtr->nItemCount, lpLVItem->iItem); - nItem = DPA_InsertPtr( infoPtr->hdpaItems, nItem, hdpaSubItems ); - if (nItem == -1) goto fail; - infoPtr->nItemCount++; - - /* shift indices first so they don't get tangled */ - LISTVIEW_ShiftIndices(infoPtr, nItem, 1); - - /* set the item attributes */ - if (lpLVItem->mask & (LVIF_GROUPID|LVIF_COLUMNS)) - { - /* full size structure expected - _WIN32IE >= 0x560 */ - item = *lpLVItem; - } - else if (lpLVItem->mask & LVIF_INDENT) - { - /* indent member expected - _WIN32IE >= 0x300 */ - memcpy(&item, lpLVItem, offsetof( LVITEMW, iGroupId )); - } - else - { - /* minimal structure expected */ - memcpy(&item, lpLVItem, offsetof( LVITEMW, iIndent )); - } - item.iItem = nItem; - if (infoPtr->dwLvExStyle & LVS_EX_CHECKBOXES) item.state &= ~LVIS_STATEIMAGEMASK; - if (!set_main_item(infoPtr, &item, TRUE, isW, &has_changed)) goto undo; - - /* if we're sorted, sort the list, and update the index */ - if (is_sorted) - { - DPA_Sort( infoPtr->hdpaItems, LISTVIEW_InsertCompare, (LPARAM)infoPtr ); - nItem = DPA_GetPtrIndex( infoPtr->hdpaItems, hdpaSubItems ); - assert(nItem != -1); - } - - /* make room for the position, if we are in the right mode */ - if ((uView == LVS_SMALLICON) || (uView == LVS_ICON)) - { - if (DPA_InsertPtr(infoPtr->hdpaPosX, nItem, 0) == -1) - goto undo; - if (DPA_InsertPtr(infoPtr->hdpaPosY, nItem, 0) == -1) - { - DPA_DeletePtr(infoPtr->hdpaPosX, nItem); - goto undo; - } - } - - /* send LVN_INSERTITEM notification */ - ZeroMemory(&nmlv, sizeof(NMLISTVIEW)); - nmlv.iItem = nItem; - nmlv.lParam = lpItem->lParam; - notify_listview(infoPtr, LVN_INSERTITEM, &nmlv); - - /* align items (set position of each item) */ - if ((uView == LVS_SMALLICON || uView == LVS_ICON)) - { - POINT pt; - - if (infoPtr->dwStyle & LVS_ALIGNLEFT) - LISTVIEW_NextIconPosLeft(infoPtr, &pt); - else - LISTVIEW_NextIconPosTop(infoPtr, &pt); - - LISTVIEW_MoveIconTo(infoPtr, nItem, &pt, TRUE); - } - - /* now is the invalidation fun */ - LISTVIEW_ScrollOnInsert(infoPtr, nItem, 1); - return nItem; - -undo: - LISTVIEW_ShiftIndices(infoPtr, nItem, -1); - DPA_DeletePtr(infoPtr->hdpaItems, nItem); - infoPtr->nItemCount--; -fail: - DPA_DeletePtr(hdpaSubItems, 0); - DPA_Destroy (hdpaSubItems); - Free (lpItem); - return -1; -} - -/*** - * DESCRIPTION: - * Redraws a range of items. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nFirst : first item - * [I] nLast : last item - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_RedrawItems(LISTVIEW_INFO *infoPtr, INT nFirst, INT nLast) -{ - INT i; - - if (nLast < nFirst || min(nFirst, nLast) < 0 || - max(nFirst, nLast) >= infoPtr->nItemCount) - return FALSE; - - for (i = nFirst; i <= nLast; i++) - LISTVIEW_InvalidateItem(infoPtr, i); - - return TRUE; -} - -/*** - * DESCRIPTION: - * Scroll the content of a listview. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] dx : horizontal scroll amount in pixels - * [I] dy : vertical scroll amount in pixels - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - * - * COMMENTS: - * If the control is in report mode (LVS_REPORT) the control can - * be scrolled only in line increments. "dy" will be rounded to the - * nearest number of pixels that are a whole line. Ex: if line height - * is 16 and an 8 is passed, the list will be scrolled by 16. If a 7 - * is passed the the scroll will be 0. (per MSDN 7/2002) - * - * For: (per experimentaion with native control and CSpy ListView) - * LVS_ICON dy=1 = 1 pixel (vertical only) - * dx ignored - * LVS_SMALLICON dy=1 = 1 pixel (vertical only) - * dx ignored - * LVS_LIST dx=1 = 1 column (horizontal only) - * but will only scroll 1 column per message - * no matter what the value. - * dy must be 0 or FALSE returned. - * LVS_REPORT dx=1 = 1 pixel - * dy= see above - * - */ -static BOOL LISTVIEW_Scroll(LISTVIEW_INFO *infoPtr, INT dx, INT dy) -{ - switch(infoPtr->dwStyle & LVS_TYPEMASK) { - case LVS_REPORT: - dy += (dy < 0 ? -1 : 1) * infoPtr->nItemHeight/2; - dy /= infoPtr->nItemHeight; - break; - case LVS_LIST: - if (dy != 0) return FALSE; - break; - default: /* icon */ - dx = 0; - break; - } - - if (dx != 0) LISTVIEW_HScroll(infoPtr, SB_INTERNAL, dx, 0); - if (dy != 0) LISTVIEW_VScroll(infoPtr, SB_INTERNAL, dy, 0); - - return TRUE; -} - -/*** - * DESCRIPTION: - * Sets the background color. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] clrBk : background color - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_SetBkColor(LISTVIEW_INFO *infoPtr, COLORREF clrBk) -{ - TRACE("(clrBk=%lx)\n", clrBk); - - if(infoPtr->clrBk != clrBk) { - if (infoPtr->clrBk != CLR_NONE) DeleteObject(infoPtr->hBkBrush); - infoPtr->clrBk = clrBk; - if (clrBk == CLR_NONE) - infoPtr->hBkBrush = (HBRUSH)GetClassLongPtrW(infoPtr->hwndSelf, GCLP_HBRBACKGROUND); - else - infoPtr->hBkBrush = CreateSolidBrush(clrBk); - LISTVIEW_InvalidateList(infoPtr); - } - - return TRUE; -} - -/* LISTVIEW_SetBkImage */ - -/*** Helper for {Insert,Set}ColumnT *only* */ -static void column_fill_hditem(LISTVIEW_INFO *infoPtr, HDITEMW *lphdi, INT nColumn, const LVCOLUMNW *lpColumn, BOOL isW) -{ - if (lpColumn->mask & LVCF_FMT) - { - /* format member is valid */ - lphdi->mask |= HDI_FORMAT; - - /* set text alignment (leftmost column must be left-aligned) */ - if (nColumn == 0 || (lpColumn->fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT) - lphdi->fmt |= HDF_LEFT; - else if ((lpColumn->fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_RIGHT) - lphdi->fmt |= HDF_RIGHT; - else if ((lpColumn->fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_CENTER) - lphdi->fmt |= HDF_CENTER; - - if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT) - lphdi->fmt |= HDF_BITMAP_ON_RIGHT; - - if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES) - { - lphdi->fmt |= HDF_IMAGE; - lphdi->iImage = I_IMAGECALLBACK; - } - } - - if (lpColumn->mask & LVCF_WIDTH) - { - lphdi->mask |= HDI_WIDTH; - if(lpColumn->cx == LVSCW_AUTOSIZE_USEHEADER) - { - /* make it fill the remainder of the controls width */ - RECT rcHeader; - INT item_index; - - for(item_index = 0; item_index < (nColumn - 1); item_index++) - { - LISTVIEW_GetHeaderRect(infoPtr, item_index, &rcHeader); - lphdi->cxy += rcHeader.right - rcHeader.left; - } - - /* retrieve the layout of the header */ - GetClientRect(infoPtr->hwndSelf, &rcHeader); - TRACE("start cxy=%d rcHeader=%s\n", lphdi->cxy, debugrect(&rcHeader)); - - lphdi->cxy = (rcHeader.right - rcHeader.left) - lphdi->cxy; - } - else - lphdi->cxy = lpColumn->cx; - } - - if (lpColumn->mask & LVCF_TEXT) - { - lphdi->mask |= HDI_TEXT | HDI_FORMAT; - lphdi->fmt |= HDF_STRING; - lphdi->pszText = lpColumn->pszText; - lphdi->cchTextMax = textlenT(lpColumn->pszText, isW); - } - - if (lpColumn->mask & LVCF_IMAGE) - { - lphdi->mask |= HDI_IMAGE; - lphdi->iImage = lpColumn->iImage; - } - - if (lpColumn->mask & LVCF_ORDER) - { - lphdi->mask |= HDI_ORDER; - lphdi->iOrder = lpColumn->iOrder; - } -} - - -/*** - * DESCRIPTION: - * Inserts a new column. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nColumn : column index - * [I] lpColumn : column information - * [I] isW : TRUE if lpColumn is Unicode, FALSE otherwise - * - * RETURN: - * SUCCESS : new column index - * FAILURE : -1 - */ -static INT LISTVIEW_InsertColumnT(LISTVIEW_INFO *infoPtr, INT nColumn, - const LVCOLUMNW *lpColumn, BOOL isW) -{ - COLUMN_INFO *lpColumnInfo; - INT nNewColumn; - HDITEMW hdi; - - TRACE("(nColumn=%d, lpColumn=%s, isW=%d)\n", nColumn, debuglvcolumn_t(lpColumn, isW), isW); - - if (!lpColumn || nColumn < 0) return -1; - nColumn = min(nColumn, DPA_GetPtrCount(infoPtr->hdpaColumns)); - - ZeroMemory(&hdi, sizeof(HDITEMW)); - column_fill_hditem(infoPtr, &hdi, nColumn, lpColumn, isW); - - /* insert item in header control */ - nNewColumn = SendMessageW(infoPtr->hwndHeader, - isW ? HDM_INSERTITEMW : HDM_INSERTITEMA, - (WPARAM)nColumn, (LPARAM)&hdi); - if (nNewColumn == -1) return -1; - if (nNewColumn != nColumn) ERR("nColumn=%d, nNewColumn=%d\n", nColumn, nNewColumn); - - /* create our own column info */ - if (!(lpColumnInfo = Alloc(sizeof(COLUMN_INFO)))) goto fail; - if (DPA_InsertPtr(infoPtr->hdpaColumns, nNewColumn, lpColumnInfo) == -1) goto fail; - - if (lpColumn->mask & LVCF_FMT) lpColumnInfo->fmt = lpColumn->fmt; - if (!Header_GetItemRect(infoPtr->hwndHeader, nNewColumn, &lpColumnInfo->rcHeader)) goto fail; - - /* now we have to actually adjust the data */ - if (!(infoPtr->dwStyle & LVS_OWNERDATA) && infoPtr->nItemCount > 0) - { - SUBITEM_INFO *lpSubItem; - HDPA hdpaSubItems; - INT nItem, i; - - for (nItem = 0; nItem < infoPtr->nItemCount; nItem++) - { - hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem); - for (i = 1; i < DPA_GetPtrCount(hdpaSubItems); i++) - { - lpSubItem = (SUBITEM_INFO *)DPA_GetPtr(hdpaSubItems, i); - if (lpSubItem->iSubItem >= nNewColumn) - lpSubItem->iSubItem++; - } - } - } - - /* make space for the new column */ - LISTVIEW_ScrollColumns(infoPtr, nNewColumn + 1, lpColumnInfo->rcHeader.right - lpColumnInfo->rcHeader.left); - - return nNewColumn; - -fail: - if (nNewColumn != -1) SendMessageW(infoPtr->hwndHeader, HDM_DELETEITEM, nNewColumn, 0); - if (lpColumnInfo) - { - DPA_DeletePtr(infoPtr->hdpaColumns, nNewColumn); - Free(lpColumnInfo); - } - return -1; -} - -/*** - * DESCRIPTION: - * Sets the attributes of a header item. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nColumn : column index - * [I] lpColumn : column attributes - * [I] isW: if TRUE, the lpColumn is a LPLVCOLUMNW, else it is a LPLVCOLUMNA - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_SetColumnT(LISTVIEW_INFO *infoPtr, INT nColumn, - const LVCOLUMNW *lpColumn, BOOL isW) -{ - HDITEMW hdi, hdiget; - BOOL bResult; - - TRACE("(nColumn=%d, lpColumn=%s, isW=%d)\n", nColumn, debuglvcolumn_t(lpColumn, isW), isW); - - if (!lpColumn || nColumn < 0 || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE; - - ZeroMemory(&hdi, sizeof(HDITEMW)); - if (lpColumn->mask & LVCF_FMT) - { - hdi.mask |= HDI_FORMAT; - hdiget.mask = HDI_FORMAT; - if (Header_GetItemW(infoPtr->hwndHeader, nColumn, &hdiget)) - hdi.fmt = hdiget.fmt & HDF_STRING; - } - column_fill_hditem(infoPtr, &hdi, nColumn, lpColumn, isW); - - /* set header item attributes */ - bResult = SendMessageW(infoPtr->hwndHeader, isW ? HDM_SETITEMW : HDM_SETITEMA, (WPARAM)nColumn, (LPARAM)&hdi); - if (!bResult) return FALSE; - - if (lpColumn->mask & LVCF_FMT) - { - COLUMN_INFO *lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, nColumn); - int oldFmt = lpColumnInfo->fmt; - - lpColumnInfo->fmt = lpColumn->fmt; - if ((oldFmt ^ lpColumn->fmt) & (LVCFMT_JUSTIFYMASK | LVCFMT_IMAGE)) - { - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - if (uView == LVS_REPORT) LISTVIEW_InvalidateColumn(infoPtr, nColumn); - } - } - - return TRUE; -} - -/*** - * DESCRIPTION: - * Sets the column order array - * - * PARAMETERS: - * [I] infoPtr : valid pointer to the listview structure - * [I] iCount : number of elements in column order array - * [I] lpiArray : pointer to column order array - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_SetColumnOrderArray(LISTVIEW_INFO *infoPtr, INT iCount, const INT *lpiArray) -{ - FIXME("iCount %d lpiArray %p\n", iCount, lpiArray); - - if (!lpiArray) - return FALSE; - - return TRUE; -} - - -/*** - * DESCRIPTION: - * Sets the width of a column - * - * PARAMETERS: - * [I] infoPtr : valid pointer to the listview structure - * [I] nColumn : column index - * [I] cx : column width - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_SetColumnWidth(LISTVIEW_INFO *infoPtr, INT nColumn, INT cx) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - WCHAR szDispText[DISP_TEXT_SIZE] = { 0 }; - INT max_cx = 0; - HDITEMW hdi; - - TRACE("(nColumn=%d, cx=%d\n", nColumn, cx); - - /* set column width only if in report or list mode */ - if (uView != LVS_REPORT && uView != LVS_LIST) return FALSE; - - /* take care of invalid cx values */ - if(uView == LVS_REPORT && cx < -2) cx = LVSCW_AUTOSIZE; - else if (uView == LVS_LIST && cx < 1) return FALSE; - - /* resize all columns if in LVS_LIST mode */ - if(uView == LVS_LIST) - { - infoPtr->nItemWidth = cx; - LISTVIEW_InvalidateList(infoPtr); - return TRUE; - } - - if (nColumn < 0 || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE; - - if (cx == LVSCW_AUTOSIZE || (cx == LVSCW_AUTOSIZE_USEHEADER && nColumn < DPA_GetPtrCount(infoPtr->hdpaColumns) -1)) - { - INT nLabelWidth; - LVITEMW lvItem; - - lvItem.mask = LVIF_TEXT; - lvItem.iItem = 0; - lvItem.iSubItem = nColumn; - lvItem.pszText = szDispText; - lvItem.cchTextMax = DISP_TEXT_SIZE; - for (; lvItem.iItem < infoPtr->nItemCount; lvItem.iItem++) - { - if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) continue; - nLabelWidth = LISTVIEW_GetStringWidthT(infoPtr, lvItem.pszText, TRUE); - if (max_cx < nLabelWidth) max_cx = nLabelWidth; - } - if (infoPtr->himlSmall && (nColumn == 0 || (LISTVIEW_GetColumnInfo(infoPtr, nColumn)->fmt & LVCFMT_IMAGE))) - max_cx += infoPtr->iconSize.cx; - max_cx += TRAILING_LABEL_PADDING; - } - - /* autosize based on listview items width */ - if(cx == LVSCW_AUTOSIZE) - cx = max_cx; - else if(cx == LVSCW_AUTOSIZE_USEHEADER) - { - /* if iCol is the last column make it fill the remainder of the controls width */ - if(nColumn == DPA_GetPtrCount(infoPtr->hdpaColumns) - 1) - { - RECT rcHeader; - POINT Origin; - - LISTVIEW_GetOrigin(infoPtr, &Origin); - LISTVIEW_GetHeaderRect(infoPtr, nColumn, &rcHeader); - - cx = infoPtr->rcList.right - Origin.x - rcHeader.left; - } - else - { - /* Despite what the MS docs say, if this is not the last - column, then MS resizes the column to the width of the - largest text string in the column, including headers - and items. This is different from LVSCW_AUTOSIZE in that - LVSCW_AUTOSIZE ignores the header string length. */ - cx = 0; - - /* retrieve header text */ - hdi.mask = HDI_TEXT; - hdi.cchTextMax = DISP_TEXT_SIZE; - hdi.pszText = szDispText; - if (Header_GetItemW(infoPtr->hwndHeader, nColumn, (LPARAM)&hdi)) - { - HDC hdc = GetDC(infoPtr->hwndSelf); - HFONT old_font = SelectObject(hdc, (HFONT)SendMessageW(infoPtr->hwndHeader, WM_GETFONT, 0, 0)); - SIZE size; - - if (GetTextExtentPoint32W(hdc, hdi.pszText, lstrlenW(hdi.pszText), &size)) - cx = size.cx + TRAILING_HEADER_PADDING; - /* FIXME: Take into account the header image, if one is present */ - SelectObject(hdc, old_font); - ReleaseDC(infoPtr->hwndSelf, hdc); - } - cx = max (cx, max_cx); - } - } - - if (cx < 0) return FALSE; - - /* call header to update the column change */ - hdi.mask = HDI_WIDTH; - hdi.cxy = cx; - TRACE("hdi.cxy=%d\n", hdi.cxy); - return Header_SetItemW(infoPtr->hwndHeader, nColumn, (LPARAM)&hdi); -} - -/*** - * Creates the checkbox imagelist. Helper for LISTVIEW_SetExtendedListViewStyle - * - */ -static HIMAGELIST LISTVIEW_CreateCheckBoxIL(LISTVIEW_INFO *infoPtr) -{ - HDC hdc_wnd, hdc; - HBITMAP hbm_im, hbm_mask, hbm_orig; - RECT rc; - HBRUSH hbr_white = GetStockObject(WHITE_BRUSH); - HBRUSH hbr_black = GetStockObject(BLACK_BRUSH); - HIMAGELIST himl; - - himl = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), - ILC_COLOR | ILC_MASK, 2, 2); - hdc_wnd = GetDC(infoPtr->hwndSelf); - hdc = CreateCompatibleDC(hdc_wnd); - hbm_im = CreateCompatibleBitmap(hdc_wnd, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON)); - hbm_mask = CreateBitmap(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 1, 1, NULL); - ReleaseDC(infoPtr->hwndSelf, hdc_wnd); - - rc.left = rc.top = 0; - rc.right = GetSystemMetrics(SM_CXSMICON); - rc.bottom = GetSystemMetrics(SM_CYSMICON); - - hbm_orig = SelectObject(hdc, hbm_mask); - FillRect(hdc, &rc, hbr_white); - InflateRect(&rc, -3, -3); - FillRect(hdc, &rc, hbr_black); - - SelectObject(hdc, hbm_im); - DrawFrameControl(hdc, &rc, DFC_BUTTON, DFCS_BUTTONCHECK | DFCS_MONO); - SelectObject(hdc, hbm_orig); - ImageList_Add(himl, hbm_im, hbm_mask); - - SelectObject(hdc, hbm_im); - DrawFrameControl(hdc, &rc, DFC_BUTTON, DFCS_BUTTONCHECK | DFCS_MONO | DFCS_CHECKED); - SelectObject(hdc, hbm_orig); - ImageList_Add(himl, hbm_im, hbm_mask); - - DeleteObject(hbm_mask); - DeleteObject(hbm_im); - DeleteDC(hdc); - - return himl; -} - -/*** - * DESCRIPTION: - * Sets the extended listview style. - * - * PARAMETERS: - * [I] infoPtr : valid pointer to the listview structure - * [I] dwMask : mask - * [I] dwStyle : style - * - * RETURN: - * SUCCESS : previous style - * FAILURE : 0 - */ -static DWORD LISTVIEW_SetExtendedListViewStyle(LISTVIEW_INFO *infoPtr, DWORD dwMask, DWORD dwStyle) -{ - DWORD dwOldStyle = infoPtr->dwLvExStyle; - - /* set new style */ - if (dwMask) - infoPtr->dwLvExStyle = (dwOldStyle & ~dwMask) | (dwStyle & dwMask); - else - infoPtr->dwLvExStyle = dwStyle; - - if((infoPtr->dwLvExStyle ^ dwOldStyle) & LVS_EX_CHECKBOXES) - { - HIMAGELIST himl = 0; - if(infoPtr->dwLvExStyle & LVS_EX_CHECKBOXES) - himl = LISTVIEW_CreateCheckBoxIL(infoPtr); - LISTVIEW_SetImageList(infoPtr, LVSIL_STATE, himl); - } - - return dwOldStyle; -} - -/*** - * DESCRIPTION: - * Sets the new hot cursor used during hot tracking and hover selection. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I} hCurosr : the new hot cursor handle - * - * RETURN: - * Returns the previous hot cursor - */ -static HCURSOR LISTVIEW_SetHotCursor(LISTVIEW_INFO *infoPtr, HCURSOR hCursor) -{ - HCURSOR oldCursor = infoPtr->hHotCursor; - - infoPtr->hHotCursor = hCursor; - - return oldCursor; -} - - -/*** - * DESCRIPTION: - * Sets the hot item index. - * - * PARAMETERS: - * [I] infoPtr : valid pointer to the listview structure - * [I] iIndex : index - * - * RETURN: - * SUCCESS : previous hot item index - * FAILURE : -1 (no hot item) - */ -static INT LISTVIEW_SetHotItem(LISTVIEW_INFO *infoPtr, INT iIndex) -{ - INT iOldIndex = infoPtr->nHotItem; - - infoPtr->nHotItem = iIndex; - - return iOldIndex; -} - - -/*** - * DESCRIPTION: - * Sets the amount of time the cursor must hover over an item before it is selected. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] dwHoverTime : hover time, if -1 the hover time is set to the default - * - * RETURN: - * Returns the previous hover time - */ -static DWORD LISTVIEW_SetHoverTime(LISTVIEW_INFO *infoPtr, DWORD dwHoverTime) -{ - DWORD oldHoverTime = infoPtr->dwHoverTime; - - infoPtr->dwHoverTime = dwHoverTime; - - return oldHoverTime; -} - -/*** - * DESCRIPTION: - * Sets spacing for icons of LVS_ICON style. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] cx : horizontal spacing (-1 = system spacing, 0 = autosize) - * [I] cy : vertical spacing (-1 = system spacing, 0 = autosize) - * - * RETURN: - * MAKELONG(oldcx, oldcy) - */ -static DWORD LISTVIEW_SetIconSpacing(LISTVIEW_INFO *infoPtr, INT cx, INT cy) -{ - DWORD oldspacing = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy); - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - - TRACE("requested=(%d,%d)\n", cx, cy); - - /* this is supported only for LVS_ICON style */ - if (uView != LVS_ICON) return oldspacing; - - /* set to defaults, if instructed to */ - if (cx == -1) cx = GetSystemMetrics(SM_CXICONSPACING); - if (cy == -1) cy = GetSystemMetrics(SM_CYICONSPACING); - - /* if 0 then compute width - * FIXME: Should scan each item and determine max width of - * icon or label, then make that the width */ - if (cx == 0) - cx = infoPtr->iconSpacing.cx; - - /* if 0 then compute height */ - if (cy == 0) - cy = infoPtr->iconSize.cy + 2 * infoPtr->ntmHeight + - ICON_BOTTOM_PADDING + ICON_TOP_PADDING + LABEL_VERT_PADDING; - - - infoPtr->iconSpacing.cx = cx; - infoPtr->iconSpacing.cy = cy; - - TRACE("old=(%d,%d), new=(%d,%d), iconSize=(%ld,%ld), ntmH=%d\n", - LOWORD(oldspacing), HIWORD(oldspacing), cx, cy, - infoPtr->iconSize.cx, infoPtr->iconSize.cy, - infoPtr->ntmHeight); - - /* these depend on the iconSpacing */ - LISTVIEW_UpdateItemSize(infoPtr); - - return oldspacing; -} - -static inline void set_icon_size(SIZE *size, HIMAGELIST himl, BOOL _small) -{ - INT cx, cy; - - if (himl && ImageList_GetIconSize(himl, &cx, &cy)) - { - size->cx = cx; - size->cy = cy; - } - else - { - size->cx = GetSystemMetrics(_small ? SM_CXSMICON : SM_CXICON); - size->cy = GetSystemMetrics(_small ? SM_CYSMICON : SM_CYICON); - } -} - -/*** - * DESCRIPTION: - * Sets image lists. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nType : image list type - * [I] himl : image list handle - * - * RETURN: - * SUCCESS : old image list - * FAILURE : NULL - */ -static HIMAGELIST LISTVIEW_SetImageList(LISTVIEW_INFO *infoPtr, INT nType, HIMAGELIST himl) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - INT oldHeight = infoPtr->nItemHeight; - HIMAGELIST himlOld = 0; - - TRACE("(nType=%d, himl=%p\n", nType, himl); - - switch (nType) - { - case LVSIL_NORMAL: - himlOld = infoPtr->himlNormal; - infoPtr->himlNormal = himl; - if (uView == LVS_ICON) set_icon_size(&infoPtr->iconSize, himl, FALSE); - LISTVIEW_SetIconSpacing(infoPtr, 0, 0); - break; - - case LVSIL_SMALL: - himlOld = infoPtr->himlSmall; - infoPtr->himlSmall = himl; - if (uView != LVS_ICON) set_icon_size(&infoPtr->iconSize, himl, TRUE); - break; - - case LVSIL_STATE: - himlOld = infoPtr->himlState; - infoPtr->himlState = himl; - set_icon_size(&infoPtr->iconStateSize, himl, TRUE); - ImageList_SetBkColor(infoPtr->himlState, CLR_NONE); - break; - - default: - ERR("Unknown icon type=%d\n", nType); - return NULL; - } - - infoPtr->nItemHeight = LISTVIEW_CalculateItemHeight(infoPtr); - if (infoPtr->nItemHeight != oldHeight) - LISTVIEW_UpdateScroll(infoPtr); - - return himlOld; -} - -/*** - * DESCRIPTION: - * Preallocates memory (does *not* set the actual count of items !) - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nItems : item count (projected number of items to allocate) - * [I] dwFlags : update flags - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_SetItemCount(LISTVIEW_INFO *infoPtr, INT nItems, DWORD dwFlags) -{ - TRACE("(nItems=%d, dwFlags=%lx)\n", nItems, dwFlags); - - if (infoPtr->dwStyle & LVS_OWNERDATA) - { - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - INT nOldCount = infoPtr->nItemCount; - - if (nItems < nOldCount) - { - RANGE range = { nItems, nOldCount }; - ranges_del(infoPtr->selectionRanges, range); - if (infoPtr->nFocusedItem >= nItems) - { - infoPtr->nFocusedItem = -1; - SetRectEmpty(&infoPtr->rcFocus); - } - } - - infoPtr->nItemCount = nItems; - LISTVIEW_UpdateScroll(infoPtr); - - /* the flags are valid only in ownerdata report and list modes */ - if (uView == LVS_ICON || uView == LVS_SMALLICON) dwFlags = 0; - - if (!(dwFlags & LVSICF_NOSCROLL) && infoPtr->nFocusedItem != -1) - LISTVIEW_EnsureVisible(infoPtr, infoPtr->nFocusedItem, FALSE); - - if (!(dwFlags & LVSICF_NOINVALIDATEALL)) - LISTVIEW_InvalidateList(infoPtr); - else - { - INT nFrom, nTo; - POINT Origin; - RECT rcErase; - - LISTVIEW_GetOrigin(infoPtr, &Origin); - nFrom = min(nOldCount, nItems); - nTo = max(nOldCount, nItems); - - if (uView == LVS_REPORT) - { - rcErase.left = 0; - rcErase.top = nFrom * infoPtr->nItemHeight; - rcErase.right = infoPtr->nItemWidth; - rcErase.bottom = nTo * infoPtr->nItemHeight; - OffsetRect(&rcErase, Origin.x, Origin.y); - if (IntersectRect(&rcErase, &rcErase, &infoPtr->rcList)) - LISTVIEW_InvalidateRect(infoPtr, &rcErase); - } - else /* LVS_LIST */ - { - INT nPerCol = LISTVIEW_GetCountPerColumn(infoPtr); - - rcErase.left = (nFrom / nPerCol) * infoPtr->nItemWidth; - rcErase.top = (nFrom % nPerCol) * infoPtr->nItemHeight; - rcErase.right = rcErase.left + infoPtr->nItemWidth; - rcErase.bottom = nPerCol * infoPtr->nItemHeight; - OffsetRect(&rcErase, Origin.x, Origin.y); - if (IntersectRect(&rcErase, &rcErase, &infoPtr->rcList)) - LISTVIEW_InvalidateRect(infoPtr, &rcErase); - - rcErase.left = (nFrom / nPerCol + 1) * infoPtr->nItemWidth; - rcErase.top = 0; - rcErase.right = (nTo / nPerCol + 1) * infoPtr->nItemWidth; - rcErase.bottom = nPerCol * infoPtr->nItemHeight; - OffsetRect(&rcErase, Origin.x, Origin.y); - if (IntersectRect(&rcErase, &rcErase, &infoPtr->rcList)) - LISTVIEW_InvalidateRect(infoPtr, &rcErase); - } - } - } - else - { - /* According to MSDN for non-LVS_OWNERDATA this is just - * a performance issue. The control allocates its internal - * data structures for the number of items specified. It - * cuts down on the number of memory allocations. Therefore - * we will just issue a WARN here - */ - WARN("for non-ownerdata performance option not implemented.\n"); - } - - return TRUE; -} - -/*** - * DESCRIPTION: - * Sets the position of an item. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nItem : item index - * [I] pt : coordinate - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_SetItemPosition(LISTVIEW_INFO *infoPtr, INT nItem, POINT pt) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - POINT Origin; - - TRACE("(nItem=%d, &pt=%s\n", nItem, debugpoint(&pt)); - - if (nItem < 0 || nItem >= infoPtr->nItemCount || - !(uView == LVS_ICON || uView == LVS_SMALLICON)) return FALSE; - - LISTVIEW_GetOrigin(infoPtr, &Origin); - - /* This point value seems to be an undocumented feature. - * The best guess is that it means either at the origin, - * or at true beginning of the list. I will assume the origin. */ - if ((pt.x == -1) && (pt.y == -1)) - pt = Origin; - - if (uView == LVS_ICON) - { - pt.x -= (infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2; - pt.y -= ICON_TOP_PADDING; - } - pt.x -= Origin.x; - pt.y -= Origin.y; - - infoPtr->bAutoarrange = FALSE; - - return LISTVIEW_MoveIconTo(infoPtr, nItem, &pt, FALSE); -} - -/*** - * DESCRIPTION: - * Sets the state of one or many items. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nItem : item index - * [I] lpLVItem : item or subitem info - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_SetItemState(LISTVIEW_INFO *infoPtr, INT nItem, const LVITEMW *lpLVItem) -{ - BOOL bResult = TRUE; - LVITEMW lvItem; - - lvItem.iItem = nItem; - lvItem.iSubItem = 0; - lvItem.mask = LVIF_STATE; - lvItem.state = lpLVItem->state; - lvItem.stateMask = lpLVItem->stateMask; - TRACE("lvItem=%s\n", debuglvitem_t(&lvItem, TRUE)); - - if (nItem == -1) - { - /* apply to all items */ - for (lvItem.iItem = 0; lvItem.iItem < infoPtr->nItemCount; lvItem.iItem++) - if (!LISTVIEW_SetItemT(infoPtr, &lvItem, TRUE)) bResult = FALSE; - } - else - bResult = LISTVIEW_SetItemT(infoPtr, &lvItem, TRUE); - - /* - * Update selection mark - * - * Investigation on windows 2k showed that selection mark was updated - * whenever a new selection was made, but if the selected item was - * unselected it was not updated. - * - * we are probably still not 100% accurate, but this at least sets the - * proper selection mark when it is needed - */ - - if (bResult && (lvItem.state & lvItem.stateMask & LVIS_SELECTED) && - ((infoPtr->nSelectionMark == -1) || (lvItem.iItem <= infoPtr->nSelectionMark))) - { - int i; - infoPtr->nSelectionMark = -1; - for (i = 0; i < infoPtr->nItemCount; i++) - { - if (infoPtr->uCallbackMask & LVIS_SELECTED) - { - if (LISTVIEW_GetItemState(infoPtr, i, LVIS_SELECTED)) - { - infoPtr->nSelectionMark = i; - break; - } - } - else if (ranges_contain(infoPtr->selectionRanges, i)) - { - infoPtr->nSelectionMark = i; - break; - } - } - } - - return bResult; -} - -/*** - * DESCRIPTION: - * Sets the text of an item or subitem. - * - * PARAMETER(S): - * [I] hwnd : window handle - * [I] nItem : item index - * [I] lpLVItem : item or subitem info - * [I] isW : TRUE if input is Unicode - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_SetItemTextT(LISTVIEW_INFO *infoPtr, INT nItem, const LVITEMW *lpLVItem, BOOL isW) -{ - LVITEMW lvItem; - - if (nItem < 0 && nItem >= infoPtr->nItemCount) return FALSE; - - lvItem.iItem = nItem; - lvItem.iSubItem = lpLVItem->iSubItem; - lvItem.mask = LVIF_TEXT; - lvItem.pszText = lpLVItem->pszText; - lvItem.cchTextMax = lpLVItem->cchTextMax; - - TRACE("(nItem=%d, lpLVItem=%s, isW=%d)\n", nItem, debuglvitem_t(&lvItem, isW), isW); - - return LISTVIEW_SetItemT(infoPtr, &lvItem, isW); -} - -/*** - * DESCRIPTION: - * Set item index that marks the start of a multiple selection. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nIndex : index - * - * RETURN: - * Index number or -1 if there is no selection mark. - */ -static INT LISTVIEW_SetSelectionMark(LISTVIEW_INFO *infoPtr, INT nIndex) -{ - INT nOldIndex = infoPtr->nSelectionMark; - - TRACE("(nIndex=%d)\n", nIndex); - - infoPtr->nSelectionMark = nIndex; - - return nOldIndex; -} - -/*** - * DESCRIPTION: - * Sets the text background color. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] clrTextBk : text background color - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_SetTextBkColor(LISTVIEW_INFO *infoPtr, COLORREF clrTextBk) -{ - TRACE("(clrTextBk=%lx)\n", clrTextBk); - - if (infoPtr->clrTextBk != clrTextBk) - { - infoPtr->clrTextBk = clrTextBk; - LISTVIEW_InvalidateList(infoPtr); - } - - return TRUE; -} - -/*** - * DESCRIPTION: - * Sets the text foreground color. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] clrText : text color - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_SetTextColor (LISTVIEW_INFO *infoPtr, COLORREF clrText) -{ - TRACE("(clrText=%lx)\n", clrText); - - if (infoPtr->clrText != clrText) - { - infoPtr->clrText = clrText; - LISTVIEW_InvalidateList(infoPtr); - } - - return TRUE; -} - -/*** - * DESCRIPTION: - * Determines which listview item is located at the specified position. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] hwndNewToolTip : handle to new ToolTip - * - * RETURN: - * old tool tip - */ -static HWND LISTVIEW_SetToolTips( LISTVIEW_INFO *infoPtr, HWND hwndNewToolTip) -{ - HWND hwndOldToolTip = infoPtr->hwndToolTip; - infoPtr->hwndToolTip = hwndNewToolTip; - return hwndOldToolTip; -} - -/* LISTVIEW_SetUnicodeFormat */ -/* LISTVIEW_SetWorkAreas */ - -/*** - * DESCRIPTION: - * Callback internally used by LISTVIEW_SortItems() - * - * PARAMETER(S): - * [I] first : pointer to first ITEM_INFO to compare - * [I] second : pointer to second ITEM_INFO to compare - * [I] lParam : HWND of control - * - * RETURN: - * if first comes before second : negative - * if first comes after second : positive - * if first and second are equivalent : zero - */ -static INT WINAPI LISTVIEW_CallBackCompare(LPVOID first, LPVOID second, LPARAM lParam) -{ - LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)lParam; - ITEM_INFO* lv_first = (ITEM_INFO*) DPA_GetPtr( (HDPA)first, 0 ); - ITEM_INFO* lv_second = (ITEM_INFO*) DPA_GetPtr( (HDPA)second, 0 ); - PFNLVCOMPARE CompareFunction = infoPtr->pfnCompare; - - /* Forward the call to the client defined callback */ - - return (CompareFunction)( lv_first->lParam , lv_second->lParam, infoPtr->lParamSort ); -} - -/*** - * DESCRIPTION: - * Sorts the listview items. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] pfnCompare : application-defined value - * [I] lParamSort : pointer to comparision callback - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_SortItems(LISTVIEW_INFO *infoPtr, PFNLVCOMPARE pfnCompare, LPARAM lParamSort) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - HDPA hdpaSubItems; - ITEM_INFO *lpItem; - LPVOID selectionMarkItem; - LVITEMW item; - int i; - - TRACE("(pfnCompare=%p, lParamSort=%lx)\n", pfnCompare, lParamSort); - - if (infoPtr->dwStyle & LVS_OWNERDATA) return FALSE; - - if (!pfnCompare) return FALSE; - if (!infoPtr->hdpaItems) return FALSE; - - /* if there are 0 or 1 items, there is no need to sort */ - if (infoPtr->nItemCount < 2) return TRUE; - - if (infoPtr->nFocusedItem >= 0) - { - hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, infoPtr->nFocusedItem); - lpItem = (ITEM_INFO *)DPA_GetPtr(hdpaSubItems, 0); - if (lpItem) lpItem->state |= LVIS_FOCUSED; - } - /* FIXME: go thorugh selected items and mark them so in lpItem->state */ - /* clear the lpItem->state for non-selected ones */ - /* remove the selection ranges */ - - infoPtr->pfnCompare = pfnCompare; - infoPtr->lParamSort = lParamSort; - DPA_Sort(infoPtr->hdpaItems, LISTVIEW_CallBackCompare, (LPARAM)infoPtr); - - /* Adjust selections and indices so that they are the way they should - * be after the sort (otherwise, the list items move around, but - * whatever is at the item's previous original position will be - * selected instead) - */ - selectionMarkItem=(infoPtr->nSelectionMark>=0)?DPA_GetPtr(infoPtr->hdpaItems, infoPtr->nSelectionMark):NULL; - for (i=0; i < infoPtr->nItemCount; i++) - { - hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i); - lpItem = (ITEM_INFO *)DPA_GetPtr(hdpaSubItems, 0); - - if (lpItem->state & LVIS_SELECTED) - { - item.state = LVIS_SELECTED; - item.stateMask = LVIS_SELECTED; - LISTVIEW_SetItemState(infoPtr, i, &item); - } - if (lpItem->state & LVIS_FOCUSED) - { - infoPtr->nFocusedItem = i; - lpItem->state &= ~LVIS_FOCUSED; - } - } - if (selectionMarkItem != NULL) - infoPtr->nSelectionMark = DPA_GetPtrIndex(infoPtr->hdpaItems, selectionMarkItem); - /* I believe nHotItem should be left alone, see LISTVIEW_ShiftIndices */ - - /* refresh the display */ - if (uView != LVS_ICON && uView != LVS_SMALLICON) - LISTVIEW_InvalidateList(infoPtr); - - return TRUE; -} - -/*** - * DESCRIPTION: - * Updates an items or rearranges the listview control. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nItem : item index - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_Update(LISTVIEW_INFO *infoPtr, INT nItem) -{ - TRACE("(nItem=%d)\n", nItem); - - if (nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE; - - /* rearrange with default alignment style */ - if (is_autoarrange(infoPtr)) - LISTVIEW_Arrange(infoPtr, LVA_DEFAULT); - else - LISTVIEW_InvalidateItem(infoPtr, nItem); - - return TRUE; -} - - -/*** - * DESCRIPTION: - * Creates the listview control. - * - * PARAMETER(S): - * [I] hwnd : window handle - * [I] lpcs : the create parameters - * - * RETURN: - * Success: 0 - * Failure: -1 - */ -static LRESULT LISTVIEW_Create(HWND hwnd, const CREATESTRUCTW *lpcs) -{ - LISTVIEW_INFO *infoPtr; - UINT uView = lpcs->style & LVS_TYPEMASK; - LOGFONTW logFont; - - TRACE("(lpcs=%p)\n", lpcs); - - /* initialize info pointer */ - infoPtr = (LISTVIEW_INFO *)Alloc(sizeof(LISTVIEW_INFO)); - if (!infoPtr) return -1; - - SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)infoPtr); - - infoPtr->hwndSelf = hwnd; - infoPtr->dwStyle = lpcs->style; - /* determine the type of structures to use */ - infoPtr->hwndNotify = lpcs->hwndParent; - infoPtr->notifyFormat = SendMessageW(infoPtr->hwndNotify, WM_NOTIFYFORMAT, - (WPARAM)infoPtr->hwndSelf, (LPARAM)NF_QUERY); - - /* initialize color information */ - infoPtr->clrBk = CLR_NONE; - infoPtr->clrText = comctl32_color.clrWindowText; - infoPtr->clrTextBk = CLR_DEFAULT; - LISTVIEW_SetBkColor(infoPtr, comctl32_color.clrWindow); - - /* set default values */ - infoPtr->nFocusedItem = -1; - infoPtr->nSelectionMark = -1; - infoPtr->nHotItem = -1; - infoPtr->bRedraw = TRUE; - infoPtr->bNoItemMetrics = TRUE; - infoPtr->bDoChangeNotify = TRUE; - infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING); - infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING); - infoPtr->nEditLabelItem = -1; - infoPtr->dwHoverTime = -1; /* default system hover time */ - infoPtr->nMeasureItemHeight = 0; - - /* get default font (icon title) */ - SystemParametersInfoW(SPI_GETICONTITLELOGFONT, 0, &logFont, 0); - infoPtr->hDefaultFont = CreateFontIndirectW(&logFont); - infoPtr->hFont = infoPtr->hDefaultFont; - LISTVIEW_SaveTextMetrics(infoPtr); - - /* create header */ - infoPtr->hwndHeader = CreateWindowW(WC_HEADERW, NULL, - WS_CHILD | HDS_HORZ | (DWORD)((LVS_NOSORTHEADER & lpcs->style)?0:HDS_BUTTONS), - 0, 0, 0, 0, hwnd, NULL, - lpcs->hInstance, NULL); - if (!infoPtr->hwndHeader) goto fail; - - /* set header unicode format */ - SendMessageW(infoPtr->hwndHeader, HDM_SETUNICODEFORMAT, (WPARAM)TRUE, (LPARAM)NULL); - - /* set header font */ - SendMessageW(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont, (LPARAM)TRUE); - - /* allocate memory for the data structure */ - if (!(infoPtr->selectionRanges = ranges_create(10))) goto fail; - if (!(infoPtr->hdpaItems = DPA_Create(10))) goto fail; - if (!(infoPtr->hdpaPosX = DPA_Create(10))) goto fail; - if (!(infoPtr->hdpaPosY = DPA_Create(10))) goto fail; - if (!(infoPtr->hdpaColumns = DPA_Create(10))) goto fail; - - /* initialize the icon sizes */ - set_icon_size(&infoPtr->iconSize, infoPtr->himlNormal, uView != LVS_ICON); - set_icon_size(&infoPtr->iconStateSize, infoPtr->himlState, TRUE); - - /* init item size to avoid division by 0 */ - LISTVIEW_UpdateItemSize (infoPtr); - - if (uView == LVS_REPORT) - { - if (!(LVS_NOCOLUMNHEADER & lpcs->style)) - { - ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL); - } - else - { - /* set HDS_HIDDEN flag to hide the header bar */ - SetWindowLongW(infoPtr->hwndHeader, GWL_STYLE, - GetWindowLongW(infoPtr->hwndHeader, GWL_STYLE) | HDS_HIDDEN); - } - } - - return 0; - -fail: - DestroyWindow(infoPtr->hwndHeader); - ranges_destroy(infoPtr->selectionRanges); - DPA_Destroy(infoPtr->hdpaItems); - DPA_Destroy(infoPtr->hdpaPosX); - DPA_Destroy(infoPtr->hdpaPosY); - DPA_Destroy(infoPtr->hdpaColumns); - Free(infoPtr); - return -1; -} - -/*** - * DESCRIPTION: - * Enables the listview control. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] bEnable : specifies whether to enable or disable the window - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static BOOL LISTVIEW_Enable(LISTVIEW_INFO *infoPtr, BOOL bEnable) -{ - if (infoPtr->dwStyle & LVS_OWNERDRAWFIXED) - InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); - return TRUE; -} - -/*** - * DESCRIPTION: - * Erases the background of the listview control. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] hdc : device context handle - * - * RETURN: - * SUCCESS : TRUE - * FAILURE : FALSE - */ -static inline BOOL LISTVIEW_EraseBkgnd(LISTVIEW_INFO *infoPtr, HDC hdc) -{ - RECT rc; - - TRACE("(hdc=%p)\n", hdc); - - if (!GetClipBox(hdc, &rc)) return FALSE; - - return LISTVIEW_FillBkgnd(infoPtr, hdc, &rc); -} - - -/*** - * DESCRIPTION: - * Helper function for LISTVIEW_[HV]Scroll *only*. - * Performs vertical/horizontal scrolling by a give amount. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] dx : amount of horizontal scroll - * [I] dy : amount of vertical scroll - */ -static void scroll_list(LISTVIEW_INFO *infoPtr, INT dx, INT dy) -{ - /* now we can scroll the list */ - ScrollWindowEx(infoPtr->hwndSelf, dx, dy, &infoPtr->rcList, - &infoPtr->rcList, 0, 0, SW_ERASE | SW_INVALIDATE); - /* if we have focus, adjust rect */ - OffsetRect(&infoPtr->rcFocus, dx, dy); - UpdateWindow(infoPtr->hwndSelf); -} - -/*** - * DESCRIPTION: - * Performs vertical scrolling. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nScrollCode : scroll code - * [I] nScrollDiff : units to scroll in SB_INTERNAL mode, 0 otherwise - * [I] hScrollWnd : scrollbar control window handle - * - * RETURN: - * Zero - * - * NOTES: - * SB_LINEUP/SB_LINEDOWN: - * for LVS_ICON, LVS_SMALLICON is 37 by experiment - * for LVS_REPORT is 1 line - * for LVS_LIST cannot occur - * - */ -static LRESULT LISTVIEW_VScroll(LISTVIEW_INFO *infoPtr, INT nScrollCode, - INT nScrollDiff, HWND hScrollWnd) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - INT nOldScrollPos, nNewScrollPos; - SCROLLINFO scrollInfo; - BOOL is_an_icon; - - TRACE("(nScrollCode=%d(%s), nScrollDiff=%d)\n", nScrollCode, - debugscrollcode(nScrollCode), nScrollDiff); - - if (infoPtr->hwndEdit) SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0); - - scrollInfo.cbSize = sizeof(SCROLLINFO); - scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS; - - is_an_icon = ((uView == LVS_ICON) || (uView == LVS_SMALLICON)); - - if (!GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo)) return 1; - - nOldScrollPos = scrollInfo.nPos; - switch (nScrollCode) - { - case SB_INTERNAL: - break; - - case SB_LINEUP: - nScrollDiff = (is_an_icon) ? -LISTVIEW_SCROLL_ICON_LINE_SIZE : -1; - break; - - case SB_LINEDOWN: - nScrollDiff = (is_an_icon) ? LISTVIEW_SCROLL_ICON_LINE_SIZE : 1; - break; - - case SB_PAGEUP: - nScrollDiff = -scrollInfo.nPage; - break; - - case SB_PAGEDOWN: - nScrollDiff = scrollInfo.nPage; - break; - - case SB_THUMBPOSITION: - case SB_THUMBTRACK: - nScrollDiff = scrollInfo.nTrackPos - scrollInfo.nPos; - break; - - default: - nScrollDiff = 0; - } - - /* quit right away if pos isn't changing */ - if (nScrollDiff == 0) return 0; - - /* calculate new position, and handle overflows */ - nNewScrollPos = scrollInfo.nPos + nScrollDiff; - if (nScrollDiff > 0) { - if (nNewScrollPos < nOldScrollPos || - nNewScrollPos > scrollInfo.nMax) - nNewScrollPos = scrollInfo.nMax; - } else { - if (nNewScrollPos > nOldScrollPos || - nNewScrollPos < scrollInfo.nMin) - nNewScrollPos = scrollInfo.nMin; - } - - /* set the new position, and reread in case it changed */ - scrollInfo.fMask = SIF_POS; - scrollInfo.nPos = nNewScrollPos; - nNewScrollPos = SetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo, TRUE); - - /* carry on only if it really changed */ - if (nNewScrollPos == nOldScrollPos) return 0; - - /* now adjust to client coordinates */ - nScrollDiff = nOldScrollPos - nNewScrollPos; - if (uView == LVS_REPORT) nScrollDiff *= infoPtr->nItemHeight; - - /* and scroll the window */ - scroll_list(infoPtr, 0, nScrollDiff); - - return 0; -} - -/*** - * DESCRIPTION: - * Performs horizontal scrolling. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nScrollCode : scroll code - * [I] nScrollDiff : units to scroll in SB_INTERNAL mode, 0 otherwise - * [I] hScrollWnd : scrollbar control window handle - * - * RETURN: - * Zero - * - * NOTES: - * SB_LINELEFT/SB_LINERIGHT: - * for LVS_ICON, LVS_SMALLICON 1 pixel - * for LVS_REPORT is 1 pixel - * for LVS_LIST is 1 column --> which is a 1 because the - * scroll is based on columns not pixels - * - */ -static LRESULT LISTVIEW_HScroll(LISTVIEW_INFO *infoPtr, INT nScrollCode, - INT nScrollDiff, HWND hScrollWnd) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - INT nOldScrollPos, nNewScrollPos; - SCROLLINFO scrollInfo; - - TRACE("(nScrollCode=%d(%s), nScrollDiff=%d)\n", nScrollCode, - debugscrollcode(nScrollCode), nScrollDiff); - - if (infoPtr->hwndEdit) SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0); - - scrollInfo.cbSize = sizeof(SCROLLINFO); - scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS; - - if (!GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo)) return 1; - - nOldScrollPos = scrollInfo.nPos; - - switch (nScrollCode) - { - case SB_INTERNAL: - break; - - case SB_LINELEFT: - nScrollDiff = -1; - break; - - case SB_LINERIGHT: - nScrollDiff = 1; - break; - - case SB_PAGELEFT: - nScrollDiff = -scrollInfo.nPage; - break; - - case SB_PAGERIGHT: - nScrollDiff = scrollInfo.nPage; - break; - - case SB_THUMBPOSITION: - case SB_THUMBTRACK: - nScrollDiff = scrollInfo.nTrackPos - scrollInfo.nPos; - break; - - default: - nScrollDiff = 0; - } - - /* quit right away if pos isn't changing */ - if (nScrollDiff == 0) return 0; - - /* calculate new position, and handle overflows */ - nNewScrollPos = scrollInfo.nPos + nScrollDiff; - if (nScrollDiff > 0) { - if (nNewScrollPos < nOldScrollPos || - nNewScrollPos > scrollInfo.nMax) - nNewScrollPos = scrollInfo.nMax; - } else { - if (nNewScrollPos > nOldScrollPos || - nNewScrollPos < scrollInfo.nMin) - nNewScrollPos = scrollInfo.nMin; - } - - /* set the new position, and reread in case it changed */ - scrollInfo.fMask = SIF_POS; - scrollInfo.nPos = nNewScrollPos; - nNewScrollPos = SetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo, TRUE); - - /* carry on only if it really changed */ - if (nNewScrollPos == nOldScrollPos) return 0; - - if(uView == LVS_REPORT) - LISTVIEW_UpdateHeaderSize(infoPtr, nNewScrollPos); - - /* now adjust to client coordinates */ - nScrollDiff = nOldScrollPos - nNewScrollPos; - if (uView == LVS_LIST) nScrollDiff *= infoPtr->nItemWidth; - - /* and scroll the window */ - scroll_list(infoPtr, nScrollDiff, 0); - - return 0; -} - -static LRESULT LISTVIEW_MouseWheel(LISTVIEW_INFO *infoPtr, INT wheelDelta) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - INT gcWheelDelta = 0; - INT pulScrollLines = 3; - SCROLLINFO scrollInfo; - - TRACE("(wheelDelta=%d)\n", wheelDelta); - - SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0); - gcWheelDelta -= wheelDelta; - - scrollInfo.cbSize = sizeof(SCROLLINFO); - scrollInfo.fMask = SIF_POS; - - switch(uView) - { - case LVS_ICON: - case LVS_SMALLICON: - /* - * listview should be scrolled by a multiple of 37 dependently on its dimension or its visible item number - * should be fixed in the future. - */ - LISTVIEW_VScroll(infoPtr, SB_INTERNAL, (gcWheelDelta < 0) ? - -LISTVIEW_SCROLL_ICON_LINE_SIZE : LISTVIEW_SCROLL_ICON_LINE_SIZE, 0); - break; - - case LVS_REPORT: - if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines) - { - int cLineScroll = min(LISTVIEW_GetCountPerColumn(infoPtr), pulScrollLines); - cLineScroll *= (gcWheelDelta / WHEEL_DELTA); - LISTVIEW_VScroll(infoPtr, SB_INTERNAL, cLineScroll, 0); - } - break; - - case LVS_LIST: - LISTVIEW_HScroll(infoPtr, (gcWheelDelta < 0) ? SB_LINELEFT : SB_LINERIGHT, 0, 0); - break; - } - return 0; -} - -/*** - * DESCRIPTION: - * ??? - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nVirtualKey : virtual key - * [I] lKeyData : key data - * - * RETURN: - * Zero - */ -static LRESULT LISTVIEW_KeyDown(LISTVIEW_INFO *infoPtr, INT nVirtualKey, LONG lKeyData) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - INT nItem = -1; - NMLVKEYDOWN nmKeyDown; - - TRACE("(nVirtualKey=%d, lKeyData=%ld)\n", nVirtualKey, lKeyData); - - /* send LVN_KEYDOWN notification */ - nmKeyDown.wVKey = nVirtualKey; - nmKeyDown.flags = 0; - notify_hdr(infoPtr, LVN_KEYDOWN, &nmKeyDown.hdr); - - switch (nVirtualKey) - { - case VK_RETURN: - if ((infoPtr->nItemCount > 0) && (infoPtr->nFocusedItem != -1)) - { - notify(infoPtr, NM_RETURN); - notify(infoPtr, LVN_ITEMACTIVATE); - } - break; - - case VK_HOME: - if (infoPtr->nItemCount > 0) - nItem = 0; - break; - - case VK_END: - if (infoPtr->nItemCount > 0) - nItem = infoPtr->nItemCount - 1; - break; - - case VK_LEFT: - nItem = ListView_GetNextItem(infoPtr->hwndSelf, infoPtr->nFocusedItem, LVNI_TOLEFT); - break; - - case VK_UP: - nItem = ListView_GetNextItem(infoPtr->hwndSelf, infoPtr->nFocusedItem, LVNI_ABOVE); - break; - - case VK_RIGHT: - nItem = ListView_GetNextItem(infoPtr->hwndSelf, infoPtr->nFocusedItem, LVNI_TORIGHT); - break; - - case VK_DOWN: - nItem = ListView_GetNextItem(infoPtr->hwndSelf, infoPtr->nFocusedItem, LVNI_BELOW); - break; - - case VK_PRIOR: - if (uView == LVS_REPORT) - nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(infoPtr); - else - nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(infoPtr) - * LISTVIEW_GetCountPerRow(infoPtr); - if(nItem < 0) nItem = 0; - break; - - case VK_NEXT: - if (uView == LVS_REPORT) - nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn(infoPtr); - else - nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn(infoPtr) - * LISTVIEW_GetCountPerRow(infoPtr); - if(nItem >= infoPtr->nItemCount) nItem = infoPtr->nItemCount - 1; - break; - } - - if ((nItem != -1) && (nItem != infoPtr->nFocusedItem)) - LISTVIEW_KeySelection(infoPtr, nItem); - - return 0; -} - -/*** - * DESCRIPTION: - * Kills the focus. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * - * RETURN: - * Zero - */ -static LRESULT LISTVIEW_KillFocus(LISTVIEW_INFO *infoPtr) -{ - TRACE("()\n"); - - /* if we did not have the focus, there's nothing to do */ - if (!infoPtr->bFocus) return 0; - - /* send NM_KILLFOCUS notification */ - notify(infoPtr, NM_KILLFOCUS); - - /* if we have a focus rectagle, get rid of it */ - LISTVIEW_ShowFocusRect(infoPtr, FALSE); - - /* set window focus flag */ - infoPtr->bFocus = FALSE; - - /* invalidate the selected items before reseting focus flag */ - LISTVIEW_InvalidateSelectedItems(infoPtr); - - return 0; -} - -/*** - * DESCRIPTION: - * Processes double click messages (left mouse button). - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] wKey : key flag - * [I] x,y : mouse coordinate - * - * RETURN: - * Zero - */ -static LRESULT LISTVIEW_LButtonDblClk(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y) -{ - LVHITTESTINFO htInfo; - - TRACE("(key=%hu, X=%hu, Y=%hu)\n", wKey, x, y); - - /* send NM_RELEASEDCAPTURE notification */ - notify(infoPtr, NM_RELEASEDCAPTURE); - - htInfo.pt.x = x; - htInfo.pt.y = y; - - /* send NM_DBLCLK notification */ - LISTVIEW_HitTest(infoPtr, &htInfo, TRUE, FALSE); - notify_click(infoPtr, NM_DBLCLK, &htInfo); - - /* To send the LVN_ITEMACTIVATE, it must be on an Item */ - if(htInfo.iItem != -1) notify_itemactivate(infoPtr,&htInfo); - - return 0; -} - -/*** - * DESCRIPTION: - * Processes mouse down messages (left mouse button). - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] wKey : key flag - * [I] x,y : mouse coordinate - * - * RETURN: - * Zero - */ -static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y) -{ - LVHITTESTINFO lvHitTestInfo; - static BOOL bGroupSelect = TRUE; - POINT pt = { x, y }; - INT nItem; - - TRACE("(key=%hu, X=%hu, Y=%hu)\n", wKey, x, y); - - /* send NM_RELEASEDCAPTURE notification */ - notify(infoPtr, NM_RELEASEDCAPTURE); - - if (!infoPtr->bFocus) SetFocus(infoPtr->hwndSelf); - - /* set left button down flag and record the click position */ - infoPtr->bLButtonDown = TRUE; - infoPtr->ptClickPos = pt; - - lvHitTestInfo.pt.x = x; - lvHitTestInfo.pt.y = y; - - nItem = LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE); - TRACE("at %s, nItem=%d\n", debugpoint(&pt), nItem); - infoPtr->nEditLabelItem = -1; - if ((nItem >= 0) && (nItem < infoPtr->nItemCount)) - { - if ((infoPtr->dwLvExStyle & LVS_EX_CHECKBOXES) && (lvHitTestInfo.flags & LVHT_ONITEMSTATEICON)) - { - DWORD state = LISTVIEW_GetItemState(infoPtr, nItem, LVIS_STATEIMAGEMASK) >> 12; - if(state == 1 || state == 2) - { - LVITEMW lvitem; - state ^= 3; - lvitem.state = state << 12; - lvitem.stateMask = LVIS_STATEIMAGEMASK; - LISTVIEW_SetItemState(infoPtr, nItem, &lvitem); - } - return 0; - } - - if (infoPtr->dwStyle & LVS_SINGLESEL) - { - if (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED)) - infoPtr->nEditLabelItem = nItem; - else - LISTVIEW_SetSelection(infoPtr, nItem); - } - else - { - if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT)) - { - if (bGroupSelect) - { - LISTVIEW_AddGroupSelection(infoPtr, nItem); - LISTVIEW_SetItemFocus(infoPtr, nItem); - infoPtr->nSelectionMark = nItem; - } - else - { - LVITEMW item; - - item.state = LVIS_SELECTED | LVIS_FOCUSED; - item.stateMask = LVIS_SELECTED | LVIS_FOCUSED; - - LISTVIEW_SetItemState(infoPtr,nItem,&item); - infoPtr->nSelectionMark = nItem; - } - } - else if (wKey & MK_CONTROL) - { - LVITEMW item; - - bGroupSelect = (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED) == 0); - - item.state = (bGroupSelect ? LVIS_SELECTED : 0) | LVIS_FOCUSED; - item.stateMask = LVIS_SELECTED | LVIS_FOCUSED; - LISTVIEW_SetItemState(infoPtr, nItem, &item); - infoPtr->nSelectionMark = nItem; - } - else if (wKey & MK_SHIFT) - { - LISTVIEW_SetGroupSelection(infoPtr, nItem); - } - else - { - if (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED)) - infoPtr->nEditLabelItem = nItem; - - /* set selection (clears other pre-existing selections) */ - LISTVIEW_SetSelection(infoPtr, nItem); - } - } - } - else - { - /* remove all selections */ - LISTVIEW_DeselectAll(infoPtr); - ReleaseCapture(); - } - - return 0; -} - -/*** - * DESCRIPTION: - * Processes mouse up messages (left mouse button). - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] wKey : key flag - * [I] x,y : mouse coordinate - * - * RETURN: - * Zero - */ -static LRESULT LISTVIEW_LButtonUp(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y) -{ - LVHITTESTINFO lvHitTestInfo; - - TRACE("(key=%hu, X=%hu, Y=%hu)\n", wKey, x, y); - - if (!infoPtr->bLButtonDown) return 0; - - lvHitTestInfo.pt.x = x; - lvHitTestInfo.pt.y = y; - - /* send NM_CLICK notification */ - LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE); - notify_click(infoPtr, NM_CLICK, &lvHitTestInfo); - - /* set left button flag */ - infoPtr->bLButtonDown = FALSE; - - /* if we clicked on a selected item, edit the label */ - if(lvHitTestInfo.iItem == infoPtr->nEditLabelItem && (lvHitTestInfo.flags & LVHT_ONITEMLABEL)) - LISTVIEW_EditLabelT(infoPtr, lvHitTestInfo.iItem, TRUE); - - return 0; -} - -/*** - * DESCRIPTION: - * Destroys the listview control (called after WM_DESTROY). - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * - * RETURN: - * Zero - */ -static LRESULT LISTVIEW_NCDestroy(LISTVIEW_INFO *infoPtr) -{ - TRACE("()\n"); - - /* delete all items */ - LISTVIEW_DeleteAllItems(infoPtr); - - /* destroy data structure */ - DPA_Destroy(infoPtr->hdpaItems); - DPA_Destroy(infoPtr->hdpaPosX); - DPA_Destroy(infoPtr->hdpaPosY); - DPA_Destroy(infoPtr->hdpaColumns); - ranges_destroy(infoPtr->selectionRanges); - - /* destroy image lists */ - if (!(infoPtr->dwStyle & LVS_SHAREIMAGELISTS)) - { - if (infoPtr->himlNormal) - ImageList_Destroy(infoPtr->himlNormal); - if (infoPtr->himlSmall) - ImageList_Destroy(infoPtr->himlSmall); - if (infoPtr->himlState) - ImageList_Destroy(infoPtr->himlState); - } - - /* destroy font, bkgnd brush */ - infoPtr->hFont = 0; - if (infoPtr->hDefaultFont) DeleteObject(infoPtr->hDefaultFont); - if (infoPtr->clrBk != CLR_NONE) DeleteObject(infoPtr->hBkBrush); - - SetWindowLongPtrW(infoPtr->hwndSelf, 0, 0); - - /* free listview info pointer*/ - Free(infoPtr); - - return 0; -} - -/*** - * DESCRIPTION: - * Handles notifications from header. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] nCtrlId : control identifier - * [I] lpnmh : notification information - * - * RETURN: - * Zero - */ -static LRESULT LISTVIEW_HeaderNotification(LISTVIEW_INFO *infoPtr, const NMHEADERW *lpnmh) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - - TRACE("(lpnmh=%p)\n", lpnmh); - - if (!lpnmh || lpnmh->iItem < 0 || lpnmh->iItem >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return 0; - - switch (lpnmh->hdr.code) - { - case HDN_TRACKW: - case HDN_TRACKA: - case HDN_ITEMCHANGEDW: - case HDN_ITEMCHANGEDA: - { - COLUMN_INFO *lpColumnInfo; - INT dx, cxy; - - if (!lpnmh->pitem || !(lpnmh->pitem->mask & HDI_WIDTH)) - { - HDITEMW hdi; - - hdi.mask = HDI_WIDTH; - if (!Header_GetItemW(infoPtr->hwndHeader, lpnmh->iItem, (LPARAM)&hdi)) return 0; - cxy = hdi.cxy; - } - else - cxy = lpnmh->pitem->cxy; - - /* determine how much we change since the last know position */ - lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, lpnmh->iItem); - dx = cxy - (lpColumnInfo->rcHeader.right - lpColumnInfo->rcHeader.left); - if (dx != 0) - { - lpColumnInfo->rcHeader.right += dx; - LISTVIEW_ScrollColumns(infoPtr, lpnmh->iItem + 1, dx); - LISTVIEW_UpdateItemSize(infoPtr); - if (uView == LVS_REPORT && is_redrawing(infoPtr)) - { - POINT ptOrigin; - RECT rcCol = lpColumnInfo->rcHeader; - - LISTVIEW_GetOrigin(infoPtr, &ptOrigin); - OffsetRect(&rcCol, ptOrigin.x, 0); - - rcCol.top = infoPtr->rcList.top; - rcCol.bottom = infoPtr->rcList.bottom; - - /* resizing left-aligned columns leaves most of the left side untouched */ - if ((lpColumnInfo->fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT) - { - INT nMaxDirty = infoPtr->nEllipsisWidth + infoPtr->ntmMaxCharWidth + dx; - rcCol.left = max (rcCol.left, rcCol.right - nMaxDirty); - } - - LISTVIEW_InvalidateRect(infoPtr, &rcCol); - } - } - } - break; - - case HDN_ITEMCLICKW: - case HDN_ITEMCLICKA: - { - /* Handle sorting by Header Column */ - NMLISTVIEW nmlv; - - ZeroMemory(&nmlv, sizeof(NMLISTVIEW)); - nmlv.iItem = -1; - nmlv.iSubItem = lpnmh->iItem; - notify_listview(infoPtr, LVN_COLUMNCLICK, &nmlv); - } - break; - - case HDN_DIVIDERDBLCLICKW: - case HDN_DIVIDERDBLCLICKA: - LISTVIEW_SetColumnWidth(infoPtr, lpnmh->iItem, LVSCW_AUTOSIZE); - break; - } - - return 0; -} - -/*** - * DESCRIPTION: - * Determines the type of structure to use. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structureof the sender - * [I] hwndFrom : listview window handle - * [I] nCommand : command specifying the nature of the WM_NOTIFYFORMAT - * - * RETURN: - * Zero - */ -static LRESULT LISTVIEW_NotifyFormat(LISTVIEW_INFO *infoPtr, HWND hwndFrom, INT nCommand) -{ - TRACE("(hwndFrom=%p, nCommand=%d)\n", hwndFrom, nCommand); - - if (nCommand != NF_REQUERY) return 0; - - infoPtr->notifyFormat = SendMessageW(hwndFrom, WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY); - - return 0; -} - -/*** - * DESCRIPTION: - * Paints/Repaints the listview control. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] hdc : device context handle - * - * RETURN: - * Zero - */ -static LRESULT LISTVIEW_Paint(LISTVIEW_INFO *infoPtr, HDC hdc) -{ - TRACE("(hdc=%p)\n", hdc); - - if (infoPtr->bNoItemMetrics && infoPtr->nItemCount) - { - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - - infoPtr->bNoItemMetrics = FALSE; - LISTVIEW_UpdateItemSize(infoPtr); - if (uView == LVS_ICON || uView == LVS_SMALLICON) - LISTVIEW_Arrange(infoPtr, LVA_DEFAULT); - LISTVIEW_UpdateScroll(infoPtr); - } - if (hdc) - LISTVIEW_Refresh(infoPtr, hdc); - else - { - PAINTSTRUCT ps; - - hdc = BeginPaint(infoPtr->hwndSelf, &ps); - if (!hdc) return 1; - if (ps.fErase) LISTVIEW_FillBkgnd(infoPtr, hdc, &ps.rcPaint); - LISTVIEW_Refresh(infoPtr, hdc); - EndPaint(infoPtr->hwndSelf, &ps); - } - - return 0; -} - - -/*** - * DESCRIPTION: - * Paints/Repaints the listview control. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] hdc : device context handle - * [I] options : drawing options - * - * RETURN: - * Zero - */ -static LRESULT LISTVIEW_PrintClient(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD options) -{ - FIXME("Partial Stub: (hdc=%p options=0x%08lx)\n", hdc, options); - - if ((options & PRF_CHECKVISIBLE) && !IsWindowVisible(infoPtr->hwndSelf)) - return 0; - - if (options & PRF_ERASEBKGND) - LISTVIEW_EraseBkgnd(infoPtr, hdc); - - if (options & PRF_CLIENT) - LISTVIEW_Paint(infoPtr, hdc); - - return 0; -} - - -/*** - * DESCRIPTION: - * Processes double click messages (right mouse button). - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] wKey : key flag - * [I] x,y : mouse coordinate - * - * RETURN: - * Zero - */ -static LRESULT LISTVIEW_RButtonDblClk(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y) -{ - LVHITTESTINFO lvHitTestInfo; - - TRACE("(key=%hu,X=%hu,Y=%hu)\n", wKey, x, y); - - /* send NM_RELEASEDCAPTURE notification */ - notify(infoPtr, NM_RELEASEDCAPTURE); - - /* send NM_RDBLCLK notification */ - lvHitTestInfo.pt.x = x; - lvHitTestInfo.pt.y = y; - LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE); - notify_click(infoPtr, NM_RDBLCLK, &lvHitTestInfo); - - return 0; -} - -/*** - * DESCRIPTION: - * Processes mouse down messages (right mouse button). - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] wKey : key flag - * [I] x,y : mouse coordinate - * - * RETURN: - * Zero - */ -static LRESULT LISTVIEW_RButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y) -{ - LVHITTESTINFO lvHitTestInfo; - INT nItem; - - TRACE("(key=%hu,X=%hu,Y=%hu)\n", wKey, x, y); - - /* send NM_RELEASEDCAPTURE notification */ - notify(infoPtr, NM_RELEASEDCAPTURE); - - /* make sure the listview control window has the focus */ - if (!infoPtr->bFocus) SetFocus(infoPtr->hwndSelf); - - /* set right button down flag */ - infoPtr->bRButtonDown = TRUE; - - /* determine the index of the selected item */ - lvHitTestInfo.pt.x = x; - lvHitTestInfo.pt.y = y; - nItem = LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE); - - if ((nItem >= 0) && (nItem < infoPtr->nItemCount)) - { - LISTVIEW_SetItemFocus(infoPtr, nItem); - if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)) && - !LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED)) - LISTVIEW_SetSelection(infoPtr, nItem); - } - else - { - LISTVIEW_DeselectAll(infoPtr); - } - - return 0; -} - -/*** - * DESCRIPTION: - * Processes mouse up messages (right mouse button). - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] wKey : key flag - * [I] x,y : mouse coordinate - * - * RETURN: - * Zero - */ -static LRESULT LISTVIEW_RButtonUp(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y) -{ - LVHITTESTINFO lvHitTestInfo; - POINT pt; - - TRACE("(key=%hu,X=%hu,Y=%hu)\n", wKey, x, y); - - if (!infoPtr->bRButtonDown) return 0; - - /* set button flag */ - infoPtr->bRButtonDown = FALSE; - - /* Send NM_RClICK notification */ - lvHitTestInfo.pt.x = x; - lvHitTestInfo.pt.y = y; - LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE); - notify_click(infoPtr, NM_RCLICK, &lvHitTestInfo); - - /* Change to screen coordinate for WM_CONTEXTMENU */ - pt = lvHitTestInfo.pt; - ClientToScreen(infoPtr->hwndSelf, &pt); - - /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */ - SendMessageW(infoPtr->hwndSelf, WM_CONTEXTMENU, - (WPARAM)infoPtr->hwndSelf, MAKELPARAM(pt.x, pt.y)); - - return 0; -} - - -/*** - * DESCRIPTION: - * Sets the cursor. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] hwnd : window handle of window containing the cursor - * [I] nHittest : hit-test code - * [I] wMouseMsg : ideintifier of the mouse message - * - * RETURN: - * TRUE if cursor is set - * FALSE otherwise - */ -static BOOL LISTVIEW_SetCursor(LISTVIEW_INFO *infoPtr, HWND hwnd, UINT nHittest, UINT wMouseMsg) -{ - LVHITTESTINFO lvHitTestInfo; - - if(!(infoPtr->dwLvExStyle & LVS_EX_TRACKSELECT)) return FALSE; - - if(!infoPtr->hHotCursor) return FALSE; - - GetCursorPos(&lvHitTestInfo.pt); - if (LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, FALSE, FALSE) < 0) return FALSE; - - SetCursor(infoPtr->hHotCursor); - - return TRUE; -} - -/*** - * DESCRIPTION: - * Sets the focus. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] hwndLoseFocus : handle of previously focused window - * - * RETURN: - * Zero - */ -static LRESULT LISTVIEW_SetFocus(LISTVIEW_INFO *infoPtr, HWND hwndLoseFocus) -{ - TRACE("(hwndLoseFocus=%p)\n", hwndLoseFocus); - - /* if we have the focus already, there's nothing to do */ - if (infoPtr->bFocus) return 0; - - /* send NM_SETFOCUS notification */ - notify(infoPtr, NM_SETFOCUS); - - /* set window focus flag */ - infoPtr->bFocus = TRUE; - - /* put the focus rect back on */ - LISTVIEW_ShowFocusRect(infoPtr, TRUE); - - /* redraw all visible selected items */ - LISTVIEW_InvalidateSelectedItems(infoPtr); - - return 0; -} - -/*** - * DESCRIPTION: - * Sets the font. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] fRedraw : font handle - * [I] fRedraw : redraw flag - * - * RETURN: - * Zero - */ -static LRESULT LISTVIEW_SetFont(LISTVIEW_INFO *infoPtr, HFONT hFont, WORD fRedraw) -{ - HFONT oldFont = infoPtr->hFont; - - TRACE("(hfont=%p,redraw=%hu)\n", hFont, fRedraw); - - infoPtr->hFont = hFont ? hFont : infoPtr->hDefaultFont; - if (infoPtr->hFont == oldFont) return 0; - - LISTVIEW_SaveTextMetrics(infoPtr); - - if ((infoPtr->dwStyle & LVS_TYPEMASK) == LVS_REPORT) - SendMessageW(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(fRedraw, 0)); - - if (fRedraw) LISTVIEW_InvalidateList(infoPtr); - - return 0; -} - -/*** - * DESCRIPTION: - * Message handling for WM_SETREDRAW. - * For the Listview, it invalidates the entire window (the doc specifies otherwise) - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] bRedraw: state of redraw flag - * - * RETURN: - * DefWinProc return value - */ -static LRESULT LISTVIEW_SetRedraw(LISTVIEW_INFO *infoPtr, BOOL bRedraw) -{ - TRACE("infoPtr->bRedraw=%d, bRedraw=%d\n", infoPtr->bRedraw, bRedraw); - - /* we cannot use straight equality here because _any_ non-zero value is TRUE */ - if ((infoPtr->bRedraw && bRedraw) || (!infoPtr->bRedraw && !bRedraw)) return 0; - - infoPtr->bRedraw = bRedraw; - - if(!bRedraw) return 0; - - if (is_autoarrange(infoPtr)) - LISTVIEW_Arrange(infoPtr, LVA_DEFAULT); - LISTVIEW_UpdateScroll(infoPtr); - - /* despite what the WM_SETREDRAW docs says, apps expect us - * to invalidate the listview here... stupid! */ - LISTVIEW_InvalidateList(infoPtr); - - return 0; -} - -/*** - * DESCRIPTION: - * Resizes the listview control. This function processes WM_SIZE - * messages. At this time, the width and height are not used. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] Width : new width - * [I] Height : new height - * - * RETURN: - * Zero - */ -static LRESULT LISTVIEW_Size(LISTVIEW_INFO *infoPtr, int Width, int Height) -{ - RECT rcOld = infoPtr->rcList; - - TRACE("(width=%d, height=%d)\n", Width, Height); - - LISTVIEW_UpdateSize(infoPtr); - if (EqualRect(&rcOld, &infoPtr->rcList)) return 0; - - /* do not bother with display related stuff if we're not redrawing */ - if (!is_redrawing(infoPtr)) return 0; - - if (is_autoarrange(infoPtr)) - LISTVIEW_Arrange(infoPtr, LVA_DEFAULT); - - LISTVIEW_UpdateScroll(infoPtr); - - /* refresh all only for lists whose height changed significantly */ - if ((infoPtr->dwStyle & LVS_TYPEMASK) == LVS_LIST && - (rcOld.bottom - rcOld.top) / infoPtr->nItemHeight != - (infoPtr->rcList.bottom - infoPtr->rcList.top) / infoPtr->nItemHeight) - LISTVIEW_InvalidateList(infoPtr); - - return 0; -} - -/*** - * DESCRIPTION: - * Sets the size information. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * - * RETURN: - * None - */ -static void LISTVIEW_UpdateSize(LISTVIEW_INFO *infoPtr) -{ - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - - TRACE("uView=%d, rcList(old)=%s\n", uView, debugrect(&infoPtr->rcList)); - - GetClientRect(infoPtr->hwndSelf, &infoPtr->rcList); - - if (uView == LVS_LIST) - { - /* Apparently the "LIST" style is supposed to have the same - * number of items in a column even if there is no scroll bar. - * Since if a scroll bar already exists then the bottom is already - * reduced, only reduce if the scroll bar does not currently exist. - * The "2" is there to mimic the native control. I think it may be - * related to either padding or edges. (GLA 7/2002) - */ - if (!(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & WS_HSCROLL)) - infoPtr->rcList.bottom -= GetSystemMetrics(SM_CYHSCROLL); - infoPtr->rcList.bottom = max (infoPtr->rcList.bottom - 2, 0); - } - else if (uView == LVS_REPORT && !(infoPtr->dwStyle & LVS_NOCOLUMNHEADER)) - { - HDLAYOUT hl; - WINDOWPOS wp; - - hl.prc = &infoPtr->rcList; - hl.pwpos = ℘ - Header_Layout(infoPtr->hwndHeader, &hl); - - SetWindowPos(wp.hwnd, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags); - - infoPtr->rcList.top = max(wp.cy, 0); - } - - TRACE(" rcList=%s\n", debugrect(&infoPtr->rcList)); -} - -/*** - * DESCRIPTION: - * Processes WM_STYLECHANGED messages. - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] wStyleType : window style type (normal or extended) - * [I] lpss : window style information - * - * RETURN: - * Zero - */ -static INT LISTVIEW_StyleChanged(LISTVIEW_INFO *infoPtr, WPARAM wStyleType, - const STYLESTRUCT *lpss) -{ - UINT uNewView = lpss->styleNew & LVS_TYPEMASK; - UINT uOldView = lpss->styleOld & LVS_TYPEMASK; - - TRACE("(styletype=%x, styleOld=0x%08lx, styleNew=0x%08lx)\n", - wStyleType, lpss->styleOld, lpss->styleNew); - - if (wStyleType != GWL_STYLE) return 0; - - /* FIXME: if LVS_NOSORTHEADER changed, update header */ - /* what if LVS_OWNERDATA changed? */ - /* or LVS_SINGLESEL */ - /* or LVS_SORT{AS,DES}CENDING */ - - infoPtr->dwStyle = lpss->styleNew; - - if (((lpss->styleOld & WS_HSCROLL) != 0)&& - ((lpss->styleNew & WS_HSCROLL) == 0)) - ShowScrollBar(infoPtr->hwndSelf, SB_HORZ, FALSE); - - if (((lpss->styleOld & WS_VSCROLL) != 0)&& - ((lpss->styleNew & WS_VSCROLL) == 0)) - ShowScrollBar(infoPtr->hwndSelf, SB_VERT, FALSE); - - if (uNewView != uOldView) - { - SIZE oldIconSize = infoPtr->iconSize; - HIMAGELIST himl; - - SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0); - ShowWindow(infoPtr->hwndHeader, SW_HIDE); - - ShowScrollBar(infoPtr->hwndSelf, SB_BOTH, FALSE); - SetRectEmpty(&infoPtr->rcFocus); - - himl = (uNewView == LVS_ICON ? infoPtr->himlNormal : infoPtr->himlSmall); - set_icon_size(&infoPtr->iconSize, himl, uNewView != LVS_ICON); - - if (uNewView == LVS_ICON) - { - if ((infoPtr->iconSize.cx != oldIconSize.cx) || (infoPtr->iconSize.cy != oldIconSize.cy)) - { - TRACE("icon old size=(%ld,%ld), new size=(%ld,%ld)\n", - oldIconSize.cx, oldIconSize.cy, infoPtr->iconSize.cx, infoPtr->iconSize.cy); - LISTVIEW_SetIconSpacing(infoPtr, 0, 0); - } - } - else if (uNewView == LVS_REPORT) - { - HDLAYOUT hl; - WINDOWPOS wp; - - hl.prc = &infoPtr->rcList; - hl.pwpos = ℘ - Header_Layout(infoPtr->hwndHeader, &hl); - SetWindowPos(infoPtr->hwndHeader, infoPtr->hwndSelf, wp.x, wp.y, wp.cx, wp.cy, wp.flags); - } - - LISTVIEW_UpdateItemSize(infoPtr); - } - - if (uNewView == LVS_REPORT) - ShowWindow(infoPtr->hwndHeader, (lpss->styleNew & LVS_NOCOLUMNHEADER) ? SW_HIDE : SW_SHOWNORMAL); - - if ( (uNewView == LVS_ICON || uNewView == LVS_SMALLICON) && - (uNewView != uOldView || ((lpss->styleNew ^ lpss->styleOld) & LVS_ALIGNMASK)) ) - LISTVIEW_Arrange(infoPtr, LVA_DEFAULT); - - /* update the size of the client area */ - LISTVIEW_UpdateSize(infoPtr); - - /* add scrollbars if needed */ - LISTVIEW_UpdateScroll(infoPtr); - - /* invalidate client area + erase background */ - LISTVIEW_InvalidateList(infoPtr); - - return 0; -} - -/*** - * DESCRIPTION: - * Window procedure of the listview control. - * - */ -static LRESULT WINAPI -LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongPtrW(hwnd, 0); - - TRACE("(uMsg=%x wParam=%x lParam=%lx)\n", uMsg, wParam, lParam); - - if (!infoPtr && (uMsg != WM_CREATE)) - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - - switch (uMsg) - { - case LVM_APPROXIMATEVIEWRECT: - return LISTVIEW_ApproximateViewRect(infoPtr, (INT)wParam, - LOWORD(lParam), HIWORD(lParam)); - case LVM_ARRANGE: - return LISTVIEW_Arrange(infoPtr, (INT)wParam); - -/* case LVM_CANCELEDITLABEL: */ - - case LVM_CREATEDRAGIMAGE: - return (LRESULT)LISTVIEW_CreateDragImage(infoPtr, (INT)wParam, (LPPOINT)lParam); - - case LVM_DELETEALLITEMS: - return LISTVIEW_DeleteAllItems(infoPtr); - - case LVM_DELETECOLUMN: - return LISTVIEW_DeleteColumn(infoPtr, (INT)wParam); - - case LVM_DELETEITEM: - return LISTVIEW_DeleteItem(infoPtr, (INT)wParam); - - case LVM_EDITLABELW: - return (LRESULT)LISTVIEW_EditLabelT(infoPtr, (INT)wParam, TRUE); - - case LVM_EDITLABELA: - return (LRESULT)LISTVIEW_EditLabelT(infoPtr, (INT)wParam, FALSE); - - /* case LVM_ENABLEGROUPVIEW: */ - - case LVM_ENSUREVISIBLE: - return LISTVIEW_EnsureVisible(infoPtr, (INT)wParam, (BOOL)lParam); - - case LVM_FINDITEMW: - return LISTVIEW_FindItemW(infoPtr, (INT)wParam, (LPLVFINDINFOW)lParam); - - case LVM_FINDITEMA: - return LISTVIEW_FindItemA(infoPtr, (INT)wParam, (LPLVFINDINFOA)lParam); - - case LVM_GETBKCOLOR: - return infoPtr->clrBk; - - /* case LVM_GETBKIMAGE: */ - - case LVM_GETCALLBACKMASK: - return infoPtr->uCallbackMask; - - case LVM_GETCOLUMNA: - return LISTVIEW_GetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, FALSE); - - case LVM_GETCOLUMNW: - return LISTVIEW_GetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, TRUE); - - case LVM_GETCOLUMNORDERARRAY: - return LISTVIEW_GetColumnOrderArray(infoPtr, (INT)wParam, (LPINT)lParam); - - case LVM_GETCOLUMNWIDTH: - return LISTVIEW_GetColumnWidth(infoPtr, (INT)wParam); - - case LVM_GETCOUNTPERPAGE: - return LISTVIEW_GetCountPerPage(infoPtr); - - case LVM_GETEDITCONTROL: - return (LRESULT)infoPtr->hwndEdit; - - case LVM_GETEXTENDEDLISTVIEWSTYLE: - return infoPtr->dwLvExStyle; - - /* case LVM_GETGROUPINFO: */ - - /* case LVM_GETGROUPMETRICS: */ - - case LVM_GETHEADER: - return (LRESULT)infoPtr->hwndHeader; - - case LVM_GETHOTCURSOR: - return (LRESULT)infoPtr->hHotCursor; - - case LVM_GETHOTITEM: - return infoPtr->nHotItem; - - case LVM_GETHOVERTIME: - return infoPtr->dwHoverTime; - - case LVM_GETIMAGELIST: - return (LRESULT)LISTVIEW_GetImageList(infoPtr, (INT)wParam); - - /* case LVM_GETINSERTMARK: */ - - /* case LVM_GETINSERTMARKCOLOR: */ - - /* case LVM_GETINSERTMARKRECT: */ - - case LVM_GETISEARCHSTRINGA: - case LVM_GETISEARCHSTRINGW: - FIXME("LVM_GETISEARCHSTRING: unimplemented\n"); - return FALSE; - - case LVM_GETITEMA: - return LISTVIEW_GetItemExtT(infoPtr, (LPLVITEMW)lParam, FALSE); - - case LVM_GETITEMW: - return LISTVIEW_GetItemExtT(infoPtr, (LPLVITEMW)lParam, TRUE); - - case LVM_GETITEMCOUNT: - return infoPtr->nItemCount; - - case LVM_GETITEMPOSITION: - return LISTVIEW_GetItemPosition(infoPtr, (INT)wParam, (LPPOINT)lParam); - - case LVM_GETITEMRECT: - return LISTVIEW_GetItemRect(infoPtr, (INT)wParam, (LPRECT)lParam); - - case LVM_GETITEMSPACING: - return LISTVIEW_GetItemSpacing(infoPtr, (BOOL)wParam); - - case LVM_GETITEMSTATE: - return LISTVIEW_GetItemState(infoPtr, (INT)wParam, (UINT)lParam); - - case LVM_GETITEMTEXTA: - return LISTVIEW_GetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam, FALSE); - - case LVM_GETITEMTEXTW: - return LISTVIEW_GetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam, TRUE); - - case LVM_GETNEXTITEM: - return LISTVIEW_GetNextItem(infoPtr, (INT)wParam, LOWORD(lParam)); - - case LVM_GETNUMBEROFWORKAREAS: - FIXME("LVM_GETNUMBEROFWORKAREAS: unimplemented\n"); - return 1; - - case LVM_GETORIGIN: - if (!lParam) return FALSE; - LISTVIEW_GetOrigin(infoPtr, (LPPOINT)lParam); - return TRUE; - - /* case LVM_GETOUTLINECOLOR: */ - - /* case LVM_GETSELECTEDCOLUMN: */ - - case LVM_GETSELECTEDCOUNT: - return LISTVIEW_GetSelectedCount(infoPtr); - - case LVM_GETSELECTIONMARK: - return infoPtr->nSelectionMark; - - case LVM_GETSTRINGWIDTHA: - return LISTVIEW_GetStringWidthT(infoPtr, (LPCWSTR)lParam, FALSE); - - case LVM_GETSTRINGWIDTHW: - return LISTVIEW_GetStringWidthT(infoPtr, (LPCWSTR)lParam, TRUE); - - case LVM_GETSUBITEMRECT: - return LISTVIEW_GetSubItemRect(infoPtr, (UINT)wParam, (LPRECT)lParam); - - case LVM_GETTEXTBKCOLOR: - return infoPtr->clrTextBk; - - case LVM_GETTEXTCOLOR: - return infoPtr->clrText; - - /* case LVM_GETTILEINFO: */ - - /* case LVM_GETTILEVIEWINFO: */ - - case LVM_GETTOOLTIPS: - if( !infoPtr->hwndToolTip ) - infoPtr->hwndToolTip = COMCTL32_CreateToolTip( hwnd ); - return (LRESULT)infoPtr->hwndToolTip; - - case LVM_GETTOPINDEX: - return LISTVIEW_GetTopIndex(infoPtr); - - /*case LVM_GETUNICODEFORMAT: - FIXME("LVM_GETUNICODEFORMAT: unimplemented\n"); - return FALSE;*/ - - /* case LVM_GETVIEW: */ - - case LVM_GETVIEWRECT: - return LISTVIEW_GetViewRect(infoPtr, (LPRECT)lParam); - - case LVM_GETWORKAREAS: - FIXME("LVM_GETWORKAREAS: unimplemented\n"); - return FALSE; - - /* case LVM_HASGROUP: */ - - case LVM_HITTEST: - return LISTVIEW_HitTest(infoPtr, (LPLVHITTESTINFO)lParam, FALSE, FALSE); - - case LVM_INSERTCOLUMNA: - return LISTVIEW_InsertColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, FALSE); - - case LVM_INSERTCOLUMNW: - return LISTVIEW_InsertColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, TRUE); - - /* case LVM_INSERTGROUP: */ - - /* case LVM_INSERTGROUPSORTED: */ - - case LVM_INSERTITEMA: - return LISTVIEW_InsertItemT(infoPtr, (LPLVITEMW)lParam, FALSE); - - case LVM_INSERTITEMW: - return LISTVIEW_InsertItemT(infoPtr, (LPLVITEMW)lParam, TRUE); - - /* case LVM_INSERTMARKHITTEST: */ - - /* case LVM_ISGROUPVIEWENABLED: */ - - /* case LVM_MAPIDTOINDEX: */ - - /* case LVM_MAPINDEXTOID: */ - - /* case LVM_MOVEGROUP: */ - - /* case LVM_MOVEITEMTOGROUP: */ - - case LVM_REDRAWITEMS: - return LISTVIEW_RedrawItems(infoPtr, (INT)wParam, (INT)lParam); - - /* case LVM_REMOVEALLGROUPS: */ - - /* case LVM_REMOVEGROUP: */ - - case LVM_SCROLL: - return LISTVIEW_Scroll(infoPtr, (INT)wParam, (INT)lParam); - - case LVM_SETBKCOLOR: - return LISTVIEW_SetBkColor(infoPtr, (COLORREF)lParam); - - /* case LVM_SETBKIMAGE: */ - - case LVM_SETCALLBACKMASK: - infoPtr->uCallbackMask = (UINT)wParam; - return TRUE; - - case LVM_SETCOLUMNA: - return LISTVIEW_SetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, FALSE); - - case LVM_SETCOLUMNW: - return LISTVIEW_SetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, TRUE); - - case LVM_SETCOLUMNORDERARRAY: - return LISTVIEW_SetColumnOrderArray(infoPtr, (INT)wParam, (LPINT)lParam); - - case LVM_SETCOLUMNWIDTH: - return LISTVIEW_SetColumnWidth(infoPtr, (INT)wParam, (short)LOWORD(lParam)); - - case LVM_SETEXTENDEDLISTVIEWSTYLE: - return LISTVIEW_SetExtendedListViewStyle(infoPtr, (DWORD)wParam, (DWORD)lParam); - - /* case LVM_SETGROUPINFO: */ - - /* case LVM_SETGROUPMETRICS: */ - - case LVM_SETHOTCURSOR: - return (LRESULT)LISTVIEW_SetHotCursor(infoPtr, (HCURSOR)lParam); - - case LVM_SETHOTITEM: - return LISTVIEW_SetHotItem(infoPtr, (INT)wParam); - - case LVM_SETHOVERTIME: - return LISTVIEW_SetHoverTime(infoPtr, (DWORD)wParam); - - case LVM_SETICONSPACING: - return LISTVIEW_SetIconSpacing(infoPtr, (short)LOWORD(lParam), (short)HIWORD(lParam)); - - case LVM_SETIMAGELIST: - return (LRESULT)LISTVIEW_SetImageList(infoPtr, (INT)wParam, (HIMAGELIST)lParam); - - /* case LVM_SETINFOTIP: */ - - /* case LVM_SETINSERTMARK: */ - - /* case LVM_SETINSERTMARKCOLOR: */ - - case LVM_SETITEMA: - return LISTVIEW_SetItemT(infoPtr, (LPLVITEMW)lParam, FALSE); - - case LVM_SETITEMW: - return LISTVIEW_SetItemT(infoPtr, (LPLVITEMW)lParam, TRUE); - - case LVM_SETITEMCOUNT: - return LISTVIEW_SetItemCount(infoPtr, (INT)wParam, (DWORD)lParam); - - case LVM_SETITEMPOSITION: - { - POINT pt; - pt.x = (short)LOWORD(lParam); - pt.y = (short)HIWORD(lParam); - return LISTVIEW_SetItemPosition(infoPtr, (INT)wParam, pt); - } - - case LVM_SETITEMPOSITION32: - if (lParam == 0) return FALSE; - return LISTVIEW_SetItemPosition(infoPtr, (INT)wParam, *((POINT*)lParam)); - - case LVM_SETITEMSTATE: - return LISTVIEW_SetItemState(infoPtr, (INT)wParam, (LPLVITEMW)lParam); - - case LVM_SETITEMTEXTA: - return LISTVIEW_SetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam, FALSE); - - case LVM_SETITEMTEXTW: - return LISTVIEW_SetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam, TRUE); - - /* case LVM_SETOUTLINECOLOR: */ - - /* case LVM_SETSELECTEDCOLUMN: */ - - case LVM_SETSELECTIONMARK: - return LISTVIEW_SetSelectionMark(infoPtr, (INT)lParam); - - case LVM_SETTEXTBKCOLOR: - return LISTVIEW_SetTextBkColor(infoPtr, (COLORREF)lParam); - - case LVM_SETTEXTCOLOR: - return LISTVIEW_SetTextColor(infoPtr, (COLORREF)lParam); - - /* case LVM_SETTILEINFO: */ - - /* case LVM_SETTILEVIEWINFO: */ - - /* case LVM_SETTILEWIDTH: */ - - case LVM_SETTOOLTIPS: - return (LRESULT)LISTVIEW_SetToolTips(infoPtr, (HWND)lParam); - - /* case LVM_SETUNICODEFORMAT: */ - - /* case LVM_SETVIEW: */ - - /* case LVM_SETWORKAREAS: */ - - /* case LVM_SORTGROUPS: */ - - case LVM_SORTITEMS: - return LISTVIEW_SortItems(infoPtr, (PFNLVCOMPARE)lParam, (LPARAM)wParam); - - /* LVM_SORTITEMSEX: */ - - case LVM_SUBITEMHITTEST: - return LISTVIEW_HitTest(infoPtr, (LPLVHITTESTINFO)lParam, TRUE, FALSE); - - case LVM_UPDATE: - return LISTVIEW_Update(infoPtr, (INT)wParam); - - case WM_CHAR: - return LISTVIEW_ProcessLetterKeys( infoPtr, wParam, lParam ); - - case WM_COMMAND: - return LISTVIEW_Command(infoPtr, wParam, lParam); - - case WM_CREATE: - return LISTVIEW_Create(hwnd, (LPCREATESTRUCTW)lParam); - - case WM_ENABLE: - return LISTVIEW_Enable(infoPtr, (BOOL)wParam); - - case WM_ERASEBKGND: - return LISTVIEW_EraseBkgnd(infoPtr, (HDC)wParam); - - case WM_GETDLGCODE: - return DLGC_WANTCHARS | DLGC_WANTARROWS; - - case WM_GETFONT: - return (LRESULT)infoPtr->hFont; - - case WM_HSCROLL: - return LISTVIEW_HScroll(infoPtr, (INT)LOWORD(wParam), 0, (HWND)lParam); - - case WM_KEYDOWN: - return LISTVIEW_KeyDown(infoPtr, (INT)wParam, (LONG)lParam); - - case WM_KILLFOCUS: - return LISTVIEW_KillFocus(infoPtr); - - case WM_LBUTTONDBLCLK: - return LISTVIEW_LButtonDblClk(infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); - - case WM_LBUTTONDOWN: - return LISTVIEW_LButtonDown(infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); - - case WM_LBUTTONUP: - return LISTVIEW_LButtonUp(infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); - - case WM_MOUSEMOVE: - return LISTVIEW_MouseMove (infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); - - case WM_MOUSEHOVER: - return LISTVIEW_MouseHover(infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); - - case WM_NCDESTROY: - return LISTVIEW_NCDestroy(infoPtr); - - case WM_NOTIFY: - if (lParam && ((LPNMHDR)lParam)->hwndFrom == infoPtr->hwndHeader) - return LISTVIEW_HeaderNotification(infoPtr, (LPNMHEADERW)lParam); - else return 0; - - case WM_NOTIFYFORMAT: - return LISTVIEW_NotifyFormat(infoPtr, (HWND)wParam, (INT)lParam); - - case WM_PRINTCLIENT: - return LISTVIEW_PrintClient(infoPtr, (HDC)wParam, (DWORD)lParam); - - case WM_PAINT: - return LISTVIEW_Paint(infoPtr, (HDC)wParam); - - case WM_RBUTTONDBLCLK: - return LISTVIEW_RButtonDblClk(infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); - - case WM_RBUTTONDOWN: - return LISTVIEW_RButtonDown(infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); - - case WM_RBUTTONUP: - return LISTVIEW_RButtonUp(infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); - - case WM_SETCURSOR: - if(LISTVIEW_SetCursor(infoPtr, (HWND)wParam, LOWORD(lParam), HIWORD(lParam))) - return TRUE; - goto fwd_msg; - - case WM_SETFOCUS: - return LISTVIEW_SetFocus(infoPtr, (HWND)wParam); - - case WM_SETFONT: - return LISTVIEW_SetFont(infoPtr, (HFONT)wParam, (WORD)lParam); - - case WM_SETREDRAW: - return LISTVIEW_SetRedraw(infoPtr, (BOOL)wParam); - - case WM_SIZE: - return LISTVIEW_Size(infoPtr, (short)LOWORD(lParam), (short)HIWORD(lParam)); - - case WM_STYLECHANGED: - return LISTVIEW_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam); - - case WM_SYSCOLORCHANGE: - COMCTL32_RefreshSysColors(); - return 0; - -/* case WM_TIMER: */ - - case WM_VSCROLL: - return LISTVIEW_VScroll(infoPtr, (INT)LOWORD(wParam), 0, (HWND)lParam); - - case WM_MOUSEWHEEL: - if (wParam & (MK_SHIFT | MK_CONTROL)) - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - return LISTVIEW_MouseWheel(infoPtr, (short int)HIWORD(wParam)); - - case WM_WINDOWPOSCHANGED: - if (!(((WINDOWPOS *)lParam)->flags & SWP_NOSIZE)) - { - UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; - SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | - SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE); - - if ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (uView == LVS_REPORT)) - { - MEASUREITEMSTRUCT mis; - mis.CtlType = ODT_LISTVIEW; - mis.CtlID = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); - mis.itemID = -1; - mis.itemWidth = 0; - mis.itemData = 0; - mis.itemHeight= infoPtr->nItemHeight; - SendMessageW(infoPtr->hwndNotify, WM_MEASUREITEM, mis.CtlID, (LPARAM)&mis); - if (infoPtr->nItemHeight != max(mis.itemHeight, 1)) - infoPtr->nMeasureItemHeight = infoPtr->nItemHeight = max(mis.itemHeight, 1); - } - - LISTVIEW_UpdateSize(infoPtr); - LISTVIEW_UpdateScroll(infoPtr); - } - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - -/* case WM_WININICHANGE: */ - - default: - if ((uMsg >= WM_USER) && (uMsg < WM_APP)) - ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam); - - fwd_msg: - /* call default window procedure */ - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - } - -} - -/*** - * DESCRIPTION: - * Registers the window class. - * - * PARAMETER(S): - * None - * - * RETURN: - * None - */ -void LISTVIEW_Register(void) -{ - WNDCLASSW wndClass; - - ZeroMemory(&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS; - wndClass.lpfnWndProc = LISTVIEW_WindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *); - wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW); - wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wndClass.lpszClassName = WC_LISTVIEWW; - RegisterClassW(&wndClass); -} - -/*** - * DESCRIPTION: - * Unregisters the window class. - * - * PARAMETER(S): - * None - * - * RETURN: - * None - */ -void LISTVIEW_Unregister(void) -{ - UnregisterClassW(WC_LISTVIEWW, NULL); -} - -/*** - * DESCRIPTION: - * Handle any WM_COMMAND messages - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] wParam : the first message parameter - * [I] lParam : the second message parameter - * - * RETURN: - * Zero. - */ -static LRESULT LISTVIEW_Command(LISTVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - switch (HIWORD(wParam)) - { - case EN_UPDATE: - { - /* - * Adjust the edit window size - */ - WCHAR buffer[1024]; - HDC hdc = GetDC(infoPtr->hwndEdit); - HFONT hFont, hOldFont = 0; - RECT rect; - SIZE sz; - int len; - - if (!infoPtr->hwndEdit || !hdc) return 0; - len = GetWindowTextW(infoPtr->hwndEdit, buffer, sizeof(buffer)/sizeof(buffer[0])); - GetWindowRect(infoPtr->hwndEdit, &rect); - - /* Select font to get the right dimension of the string */ - hFont = (HFONT)SendMessageW(infoPtr->hwndEdit, WM_GETFONT, 0, 0); - if(hFont != 0) - { - hOldFont = SelectObject(hdc, hFont); - } - - if (GetTextExtentPoint32W(hdc, buffer, lstrlenW(buffer), &sz)) - { - TEXTMETRICW textMetric; - - /* Add Extra spacing for the next character */ - GetTextMetricsW(hdc, &textMetric); - sz.cx += (textMetric.tmMaxCharWidth * 2); - - SetWindowPos ( - infoPtr->hwndEdit, - HWND_TOP, - 0, - 0, - sz.cx, - rect.bottom - rect.top, - SWP_DRAWFRAME|SWP_NOMOVE); - } - if(hFont != 0) - SelectObject(hdc, hOldFont); - - ReleaseDC(infoPtr->hwndEdit, hdc); - - break; - } - - default: - return SendMessageW (infoPtr->hwndNotify, WM_COMMAND, wParam, lParam); - } - - return 0; -} - - -/*** - * DESCRIPTION: - * Subclassed edit control windproc function - * - * PARAMETER(S): - * [I] hwnd : the edit window handle - * [I] uMsg : the message that is to be processed - * [I] wParam : first message parameter - * [I] lParam : second message parameter - * [I] isW : TRUE if input is Unicode - * - * RETURN: - * Zero. - */ -static LRESULT EditLblWndProcT(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL isW) -{ - LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongPtrW(GetParent(hwnd), 0); - BOOL cancel = FALSE; - - TRACE("(hwnd=%p, uMsg=%x, wParam=%x, lParam=%lx, isW=%d)\n", - hwnd, uMsg, wParam, lParam, isW); - - switch (uMsg) - { - case WM_GETDLGCODE: - return DLGC_WANTARROWS | DLGC_WANTALLKEYS; - - case WM_KILLFOCUS: - break; - - case WM_DESTROY: - { - WNDPROC editProc = infoPtr->EditWndProc; - infoPtr->EditWndProc = 0; - SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (DWORD_PTR)editProc); - return CallWindowProcT(editProc, hwnd, uMsg, wParam, lParam, isW); - } - - case WM_KEYDOWN: - if (VK_ESCAPE == (INT)wParam) - { - cancel = TRUE; - break; - } - else if (VK_RETURN == (INT)wParam) - break; - - default: - return CallWindowProcT(infoPtr->EditWndProc, hwnd, uMsg, wParam, lParam, isW); - } - - /* kill the edit */ - if (infoPtr->hwndEdit) - { - LPWSTR buffer = NULL; - - infoPtr->hwndEdit = 0; - if (!cancel) - { - DWORD len = isW ? GetWindowTextLengthW(hwnd) : GetWindowTextLengthA(hwnd); - - if (len) - { - if ( (buffer = Alloc((len+1) * (isW ? sizeof(WCHAR) : sizeof(CHAR)))) ) - { - if (isW) GetWindowTextW(hwnd, buffer, len+1); - else GetWindowTextA(hwnd, (CHAR*)buffer, len+1); - } - } - } - LISTVIEW_EndEditLabelT(infoPtr, buffer, isW); - - if (buffer) Free(buffer); - - } - - SendMessageW(hwnd, WM_CLOSE, 0, 0); - return 0; -} - -/*** - * DESCRIPTION: - * Subclassed edit control Unicode windproc function - * - * PARAMETER(S): - * [I] hwnd : the edit window handle - * [I] uMsg : the message that is to be processed - * [I] wParam : first message parameter - * [I] lParam : second message parameter - * - * RETURN: - */ -LRESULT CALLBACK EditLblWndProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - return EditLblWndProcT(hwnd, uMsg, wParam, lParam, TRUE); -} - -/*** - * DESCRIPTION: - * Subclassed edit control ANSI windproc function - * - * PARAMETER(S): - * [I] hwnd : the edit window handle - * [I] uMsg : the message that is to be processed - * [I] wParam : first message parameter - * [I] lParam : second message parameter - * - * RETURN: - */ -LRESULT CALLBACK EditLblWndProcA(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - return EditLblWndProcT(hwnd, uMsg, wParam, lParam, FALSE); -} - -/*** - * DESCRIPTION: - * Creates a subclassed edit cotrol - * - * PARAMETER(S): - * [I] infoPtr : valid pointer to the listview structure - * [I] text : initial text for the edit - * [I] style : the window style - * [I] isW : TRUE if input is Unicode - * - * RETURN: - */ -static HWND CreateEditLabelT(LISTVIEW_INFO *infoPtr, LPCWSTR text, DWORD style, - INT x, INT y, INT width, INT height, BOOL isW) -{ - WCHAR editName[5] = { 'E', 'd', 'i', 't', '\0' }; - HWND hedit; - SIZE sz; - HDC hdc; - HDC hOldFont=0; - TEXTMETRICW textMetric; - HINSTANCE hinst = (HINSTANCE)GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_HINSTANCE); - - TRACE("(text=%s, ..., isW=%d)\n", debugtext_t(text, isW), isW); - - style |= WS_CHILDWINDOW|WS_CLIPSIBLINGS|ES_LEFT|ES_AUTOHSCROLL|WS_BORDER; - hdc = GetDC(infoPtr->hwndSelf); - - /* Select the font to get appropriate metric dimensions */ - if(infoPtr->hFont != 0) - hOldFont = SelectObject(hdc, infoPtr->hFont); - - /*Get String Length in pixels */ - if(!GetTextExtentPoint32W(hdc, text, lstrlenW(text), &sz)) - sz.cx = 0; - - /*Add Extra spacing for the next character */ - GetTextMetricsW(hdc, &textMetric); - sz.cx += (textMetric.tmMaxCharWidth * 2); - - if(infoPtr->hFont != 0) - SelectObject(hdc, hOldFont); - - ReleaseDC(infoPtr->hwndSelf, hdc); - if (isW) - hedit = CreateWindowW(editName, text, style, x, y, sz.cx, height, infoPtr->hwndSelf, 0, hinst, 0); - else - hedit = CreateWindowA("Edit", (LPCSTR)text, style, x, y, sz.cx, height, infoPtr->hwndSelf, 0, hinst, 0); - - if (!hedit) return 0; - - infoPtr->EditWndProc = (WNDPROC) - (isW ? SetWindowLongPtrW(hedit, GWLP_WNDPROC, (DWORD_PTR)EditLblWndProcW) : - SetWindowLongPtrA(hedit, GWLP_WNDPROC, (DWORD_PTR)EditLblWndProcA) ); - - SendMessageW(hedit, WM_SETFONT, (WPARAM)infoPtr->hFont, FALSE); - - return hedit; -} +/* + * Listview control + * + * Copyright 1998, 1999 Eric Kohl + * Copyright 1999 Luc Tourangeau + * Copyright 2000 Jason Mawdsley + * Copyright 2001 CodeWeavers Inc. + * Copyright 2002 Dimitrie O. Paun + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES + * + * This code was audited for completeness against the documented features + * of Comctl32.dll version 6.0 on May. 20, 2005, by James Hawkins. + * + * Unless otherwise noted, we believe this code to be complete, as per + * the specification mentioned above. + * If you discover missing features, or bugs, please note them below. + * + * TODO: + * + * Default Message Processing + * -- EN_KILLFOCUS should be handled in WM_COMMAND + * -- WM_CREATE: create the icon and small icon image lists at this point only if + * the LVS_SHAREIMAGELISTS style is not specified. + * -- WM_ERASEBKGND: forward this message to the parent window if the bkgnd + * color is CLR_NONE. + * -- WM_WINDOWPOSCHANGED: arrange the list items if the current view is icon + * or small icon and the LVS_AUTOARRANGE style is specified. + * -- WM_TIMER + * -- WM_WININICHANGE + * + * Features + * -- Hot item handling, mouse hovering + * -- Workareas support + * -- Tilemode support + * -- Groups support + * + * Bugs + * -- Expand large item in ICON mode when the cursor is flying over the icon or text. + * -- Support CustomDraw options for _WIN32_IE >= 0x560 (see NMLVCUSTOMDRAW docs). + * -- LVA_SNAPTOGRID not implemented + * -- LISTVIEW_ApproximateViewRect partially implemented + * -- LISTVIEW_[GS]etColumnOrderArray stubs + * -- LISTVIEW_SetColumnWidth ignores header images & bitmap + * -- LISTVIEW_SetIconSpacing is incomplete + * -- LISTVIEW_SortItems is broken + * -- LISTVIEW_StyleChanged doesn't handle some changes too well + * + * Speedups + * -- LISTVIEW_GetNextItem needs to be rewritten. It is currently + * linear in the number of items in the list, and this is + * unacceptable for large lists. + * -- in sorted mode, LISTVIEW_InsertItemT sorts the array, + * instead of inserting in the right spot + * -- we should keep an ordered array of coordinates in iconic mode + * this would allow to frame items (iterator_frameditems), + * and find nearest item (LVFI_NEARESTXY) a lot more efficiently + * + * Flags + * -- LVIF_COLUMNS + * -- LVIF_GROUPID + * -- LVIF_NORECOMPUTE + * + * States + * -- LVIS_ACTIVATING (not currently supported by comctl32.dll version 6.0) + * -- LVIS_CUT + * -- LVIS_DROPHILITED + * -- LVIS_OVERLAYMASK + * + * Styles + * -- LVS_NOLABELWRAP + * -- LVS_NOSCROLL (see Q137520) + * -- LVS_SORTASCENDING, LVS_SORTDESCENDING + * -- LVS_ALIGNTOP + * -- LVS_TYPESTYLEMASK + * + * Extended Styles + * -- LVS_EX_BORDERSELECT + * -- LVS_EX_FLATSB + * -- LVS_EX_GRIDLINES + * -- LVS_EX_HEADERDRAGDROP + * -- LVS_EX_INFOTIP + * -- LVS_EX_LABELTIP + * -- LVS_EX_MULTIWORKAREAS + * -- LVS_EX_ONECLICKACTIVATE + * -- LVS_EX_REGIONAL + * -- LVS_EX_SIMPLESELECT + * -- LVS_EX_TRACKSELECT + * -- LVS_EX_TWOCLICKACTIVATE + * -- LVS_EX_UNDERLINECOLD + * -- LVS_EX_UNDERLINEHOT + * + * Notifications: + * -- LVN_BEGINSCROLL, LVN_ENDSCROLL + * -- LVN_GETINFOTIP + * -- LVN_HOTTRACK + * -- LVN_MARQUEEBEGIN + * -- LVN_ODFINDITEM + * -- LVN_SETDISPINFO + * -- NM_HOVER + * -- LVN_BEGINRDRAG + * + * Messages: + * -- LVM_CANCELEDITLABEL + * -- LVM_ENABLEGROUPVIEW + * -- LVM_GETBKIMAGE, LVM_SETBKIMAGE + * -- LVM_GETGROUPINFO, LVM_SETGROUPINFO + * -- LVM_GETGROUPMETRICS, LVM_SETGROUPMETRICS + * -- LVM_GETINSERTMARK, LVM_SETINSERTMARK + * -- LVM_GETINSERTMARKCOLOR, LVM_SETINSERTMARKCOLOR + * -- LVM_GETINSERTMARKRECT + * -- LVM_GETNUMBEROFWORKAREAS + * -- LVM_GETOUTLINECOLOR, LVM_SETOUTLINECOLOR + * -- LVM_GETSELECTEDCOLUMN, LVM_SETSELECTEDCOLUMN + * -- LVM_GETISEARCHSTRINGW, LVM_GETISEARCHSTRINGA + * -- LVM_GETTILEINFO, LVM_SETTILEINFO + * -- LVM_GETTILEVIEWINFO, LVM_SETTILEVIEWINFO + * -- LVM_GETUNICODEFORMAT, LVM_SETUNICODEFORMAT + * -- LVM_GETVIEW, LVM_SETVIEW + * -- LVM_GETWORKAREAS, LVM_SETWORKAREAS + * -- LVM_HASGROUP, LVM_INSERTGROUP, LVM_REMOVEGROUP, LVM_REMOVEALLGROUPS + * -- LVM_INSERTGROUPSORTED + * -- LVM_INSERTMARKHITTEST + * -- LVM_ISGROUPVIEWENABLED + * -- LVM_MAPIDTOINDEX, LVM_MAPINDEXTOID + * -- LVM_MOVEGROUP + * -- LVM_MOVEITEMTOGROUP + * -- LVM_SETINFOTIP + * -- LVM_SETTILEWIDTH + * -- LVM_SORTGROUPS + * -- LVM_SORTITEMSEX + * + * Macros: + * -- ListView_GetCheckSate, ListView_SetCheckState + * -- ListView_GetHoverTime, ListView_SetHoverTime + * -- ListView_GetISearchString + * -- ListView_GetNumberOfWorkAreas + * -- ListView_GetOrigin + * -- ListView_GetTextBkColor + * -- ListView_GetUnicodeFormat, ListView_SetUnicodeFormat + * -- ListView_GetWorkAreas, ListView_SetWorkAreas + * -- ListView_SortItemsEx + * + * Functions: + * -- LVGroupComparE + * + * Known differences in message stream from native control (not known if + * these differences cause problems): + * LVM_INSERTITEM issues LVM_SETITEMSTATE and LVM_SETITEM in certain cases. + * LVM_SETITEM does not always issue LVN_ITEMCHANGING/LVN_ITEMCHANGED. + * WM_CREATE does not issue WM_QUERYUISTATE and associated registry + * processing for "USEDOUBLECLICKTIME". + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winnt.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "comctl32.h" + +#include "wine/debug.h" +#include "wine/unicode.h" + +WINE_DEFAULT_DEBUG_CHANNEL(listview); + +/* make sure you set this to 0 for production use! */ +#define DEBUG_RANGES 1 + +typedef struct tagCOLUMN_INFO +{ + RECT rcHeader; /* tracks the header's rectangle */ + int fmt; /* same as LVCOLUMN.fmt */ +} COLUMN_INFO; + +typedef struct tagITEMHDR +{ + LPWSTR pszText; + INT iImage; +} ITEMHDR, *LPITEMHDR; + +typedef struct tagSUBITEM_INFO +{ + ITEMHDR hdr; + INT iSubItem; +} SUBITEM_INFO; + +typedef struct tagITEM_INFO +{ + ITEMHDR hdr; + UINT state; + LPARAM lParam; + INT iIndent; +} ITEM_INFO; + +typedef struct tagRANGE +{ + INT lower; + INT upper; +} RANGE; + +typedef struct tagRANGES +{ + HDPA hdpa; +} *RANGES; + +typedef struct tagITERATOR +{ + INT nItem; + INT nSpecial; + RANGE range; + RANGES ranges; + INT index; +} ITERATOR; + +typedef struct tagLISTVIEW_INFO +{ + HWND hwndSelf; + HBRUSH hBkBrush; + COLORREF clrBk; + COLORREF clrText; + COLORREF clrTextBk; + COLORREF clrTextBkDefault; + HIMAGELIST himlNormal; + HIMAGELIST himlSmall; + HIMAGELIST himlState; + BOOL bLButtonDown; + BOOL bRButtonDown; + POINT ptClickPos; /* point where the user clicked */ + BOOL bNoItemMetrics; /* flags if item metrics are not yet computed */ + INT nItemHeight; + INT nItemWidth; + RANGES selectionRanges; + INT nSelectionMark; + INT nHotItem; + SHORT notifyFormat; + HWND hwndNotify; + RECT rcList; /* This rectangle is really the window + * client rectangle possibly reduced by the + * horizontal scroll bar and/or header - see + * LISTVIEW_UpdateSize. This rectangle offset + * by the LISTVIEW_GetOrigin value is in + * client coordinates */ + SIZE iconSize; + SIZE iconSpacing; + SIZE iconStateSize; + UINT uCallbackMask; + HWND hwndHeader; + HCURSOR hHotCursor; + HFONT hDefaultFont; + HFONT hFont; + INT ntmHeight; /* Some cached metrics of the font used */ + INT ntmMaxCharWidth; /* by the listview to draw items */ + INT nEllipsisWidth; + BOOL bRedraw; /* Turns on/off repaints & invalidations */ + BOOL bAutoarrange; /* Autoarrange flag when NOT in LVS_AUTOARRANGE */ + BOOL bFocus; + BOOL bDoChangeNotify; /* send change notification messages? */ + INT nFocusedItem; + RECT rcFocus; + DWORD dwStyle; /* the cached window GWL_STYLE */ + DWORD dwLvExStyle; /* extended listview style */ + INT nItemCount; /* the number of items in the list */ + HDPA hdpaItems; /* array ITEM_INFO pointers */ + HDPA hdpaPosX; /* maintains the (X, Y) coordinates of the */ + HDPA hdpaPosY; /* items in LVS_ICON, and LVS_SMALLICON modes */ + HDPA hdpaColumns; /* array of COLUMN_INFO pointers */ + POINT currIconPos; /* this is the position next icon will be placed */ + PFNLVCOMPARE pfnCompare; + LPARAM lParamSort; + HWND hwndEdit; + WNDPROC EditWndProc; + INT nEditLabelItem; + DWORD dwHoverTime; + HWND hwndToolTip; + + DWORD cditemmode; /* Keep the custom draw flags for an item/row */ + + DWORD lastKeyPressTimestamp; + WPARAM charCode; + INT nSearchParamLength; + WCHAR szSearchParam[ MAX_PATH ]; + BOOL bIsDrawing; + INT nMeasureItemHeight; +} LISTVIEW_INFO; + +/* + * constants + */ +/* How many we debug buffer to allocate */ +#define DEBUG_BUFFERS 20 +/* The size of a single debug bbuffer */ +#define DEBUG_BUFFER_SIZE 256 + +/* Internal interface to LISTVIEW_HScroll and LISTVIEW_VScroll */ +#define SB_INTERNAL -1 + +/* maximum size of a label */ +#define DISP_TEXT_SIZE 512 + +/* padding for items in list and small icon display modes */ +#define WIDTH_PADDING 12 + +/* padding for items in list, report and small icon display modes */ +#define HEIGHT_PADDING 1 + +/* offset of items in report display mode */ +#define REPORT_MARGINX 2 + +/* padding for icon in large icon display mode + * ICON_TOP_PADDING_NOTHITABLE - space between top of box and area + * that HITTEST will see. + * ICON_TOP_PADDING_HITABLE - spacing between above and icon. + * ICON_TOP_PADDING - sum of the two above. + * ICON_BOTTOM_PADDING - between bottom of icon and top of text + * LABEL_HOR_PADDING - between text and sides of box + * LABEL_VERT_PADDING - between bottom of text and end of box + * + * ICON_LR_PADDING - additional width above icon size. + * ICON_LR_HALF - half of the above value + */ +#define ICON_TOP_PADDING_NOTHITABLE 2 +#define ICON_TOP_PADDING_HITABLE 2 +#define ICON_TOP_PADDING (ICON_TOP_PADDING_NOTHITABLE + ICON_TOP_PADDING_HITABLE) +#define ICON_BOTTOM_PADDING 4 +#define LABEL_HOR_PADDING 5 +#define LABEL_VERT_PADDING 7 +#define ICON_LR_PADDING 16 +#define ICON_LR_HALF (ICON_LR_PADDING/2) + +/* default label width for items in list and small icon display modes */ +#define DEFAULT_LABEL_WIDTH 40 + +/* default column width for items in list display mode */ +#define DEFAULT_COLUMN_WIDTH 128 + +/* Size of "line" scroll for V & H scrolls */ +#define LISTVIEW_SCROLL_ICON_LINE_SIZE 37 + +/* Padding betwen image and label */ +#define IMAGE_PADDING 2 + +/* Padding behind the label */ +#define TRAILING_LABEL_PADDING 12 +#define TRAILING_HEADER_PADDING 11 + +/* Border for the icon caption */ +#define CAPTION_BORDER 2 + +/* Standard DrawText flags */ +#define LV_ML_DT_FLAGS (DT_TOP | DT_NOPREFIX | DT_EDITCONTROL | DT_CENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS | DT_END_ELLIPSIS) +#define LV_FL_DT_FLAGS (DT_TOP | DT_NOPREFIX | DT_EDITCONTROL | DT_CENTER | DT_WORDBREAK | DT_NOCLIP) +#define LV_SL_DT_FLAGS (DT_VCENTER | DT_NOPREFIX | DT_EDITCONTROL | DT_SINGLELINE | DT_WORD_ELLIPSIS | DT_END_ELLIPSIS) + +/* The time in milliseconds to reset the search in the list */ +#define KEY_DELAY 450 + +/* Dump the LISTVIEW_INFO structure to the debug channel */ +#define LISTVIEW_DUMP(iP) do { \ + TRACE("hwndSelf=%p, clrBk=0x%06lx, clrText=0x%06lx, clrTextBk=0x%06lx, ItemHeight=%d, ItemWidth=%d, Style=0x%08lx\n", \ + iP->hwndSelf, iP->clrBk, iP->clrText, iP->clrTextBk, \ + iP->nItemHeight, iP->nItemWidth, infoPtr->dwStyle); \ + TRACE("hwndSelf=%p, himlNor=%p, himlSml=%p, himlState=%p, Focused=%d, Hot=%d, exStyle=0x%08lx, Focus=%d\n", \ + iP->hwndSelf, iP->himlNormal, iP->himlSmall, iP->himlState, \ + iP->nFocusedItem, iP->nHotItem, iP->dwLvExStyle, iP->bFocus ); \ + TRACE("hwndSelf=%p, ntmH=%d, icSz.cx=%ld, icSz.cy=%ld, icSp.cx=%ld, icSp.cy=%ld, notifyFmt=%d\n", \ + iP->hwndSelf, iP->ntmHeight, iP->iconSize.cx, iP->iconSize.cy, \ + iP->iconSpacing.cx, iP->iconSpacing.cy, iP->notifyFormat); \ + TRACE("hwndSelf=%p, rcList=%s\n", iP->hwndSelf, debugrect(&iP->rcList)); \ +} while(0) + +/* + * forward declarations + */ +static BOOL LISTVIEW_GetItemT(LISTVIEW_INFO *, LPLVITEMW, BOOL); +static void LISTVIEW_GetItemBox(LISTVIEW_INFO *, INT, LPRECT); +static void LISTVIEW_GetItemOrigin(LISTVIEW_INFO *, INT, LPPOINT); +static BOOL LISTVIEW_GetItemPosition(LISTVIEW_INFO *, INT, LPPOINT); +static BOOL LISTVIEW_GetItemRect(LISTVIEW_INFO *, INT, LPRECT); +static INT LISTVIEW_GetLabelWidth(LISTVIEW_INFO *, INT); +static void LISTVIEW_GetOrigin(LISTVIEW_INFO *, LPPOINT); +static BOOL LISTVIEW_GetViewRect(LISTVIEW_INFO *, LPRECT); +static void LISTVIEW_SetGroupSelection(LISTVIEW_INFO *, INT); +static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *, const LVITEMW *, BOOL); +static void LISTVIEW_UpdateScroll(LISTVIEW_INFO *); +static void LISTVIEW_SetSelection(LISTVIEW_INFO *, INT); +static void LISTVIEW_UpdateSize(LISTVIEW_INFO *); +static HWND LISTVIEW_EditLabelT(LISTVIEW_INFO *, INT, BOOL); +static LRESULT LISTVIEW_Command(LISTVIEW_INFO *, WPARAM, LPARAM); +static BOOL LISTVIEW_SortItems(LISTVIEW_INFO *, PFNLVCOMPARE, LPARAM); +static INT LISTVIEW_GetStringWidthT(LISTVIEW_INFO *, LPCWSTR, BOOL); +static BOOL LISTVIEW_KeySelection(LISTVIEW_INFO *, INT); +static UINT LISTVIEW_GetItemState(LISTVIEW_INFO *, INT, UINT); +static BOOL LISTVIEW_SetItemState(LISTVIEW_INFO *, INT, const LVITEMW *); +static LRESULT LISTVIEW_VScroll(LISTVIEW_INFO *, INT, INT, HWND); +static LRESULT LISTVIEW_HScroll(LISTVIEW_INFO *, INT, INT, HWND); +static INT LISTVIEW_GetTopIndex(LISTVIEW_INFO *); +static BOOL LISTVIEW_EnsureVisible(LISTVIEW_INFO *, INT, BOOL); +static HWND CreateEditLabelT(LISTVIEW_INFO *, LPCWSTR, DWORD, INT, INT, INT, INT, BOOL); +static HIMAGELIST LISTVIEW_SetImageList(LISTVIEW_INFO *, INT, HIMAGELIST); +static INT LISTVIEW_HitTest(LISTVIEW_INFO *, LPLVHITTESTINFO, BOOL, BOOL); + +/******** Text handling functions *************************************/ + +/* A text pointer is either NULL, LPSTR_TEXTCALLBACK, or points to a + * text string. The string may be ANSI or Unicode, in which case + * the boolean isW tells us the type of the string. + * + * The name of the function tell what type of strings it expects: + * W: Unicode, T: ANSI/Unicode - function of isW + */ + +static inline BOOL is_textW(LPCWSTR text) +{ + return text != NULL && text != LPSTR_TEXTCALLBACKW; +} + +static inline BOOL is_textT(LPCWSTR text, BOOL isW) +{ + /* we can ignore isW since LPSTR_TEXTCALLBACKW == LPSTR_TEXTCALLBACKA */ + return is_textW(text); +} + +static inline int textlenT(LPCWSTR text, BOOL isW) +{ + return !is_textT(text, isW) ? 0 : + isW ? lstrlenW(text) : lstrlenA((LPCSTR)text); +} + +static inline void textcpynT(LPWSTR dest, BOOL isDestW, LPCWSTR src, BOOL isSrcW, INT max) +{ + if (isDestW) + if (isSrcW) lstrcpynW(dest, src, max); + else MultiByteToWideChar(CP_ACP, 0, (LPCSTR)src, -1, dest, max); + else + if (isSrcW) WideCharToMultiByte(CP_ACP, 0, src, -1, (LPSTR)dest, max, NULL, NULL); + else lstrcpynA((LPSTR)dest, (LPCSTR)src, max); +} + +static inline LPWSTR textdupTtoW(LPCWSTR text, BOOL isW) +{ + LPWSTR wstr = (LPWSTR)text; + + if (!isW && is_textT(text, isW)) + { + INT len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)text, -1, NULL, 0); + wstr = Alloc(len * sizeof(WCHAR)); + if (wstr) MultiByteToWideChar(CP_ACP, 0, (LPCSTR)text, -1, wstr, len); + } + TRACE(" wstr=%s\n", text == LPSTR_TEXTCALLBACKW ? "(callback)" : debugstr_w(wstr)); + return wstr; +} + +static inline void textfreeT(LPWSTR wstr, BOOL isW) +{ + if (!isW && is_textT(wstr, isW)) Free (wstr); +} + +/* + * dest is a pointer to a Unicode string + * src is a pointer to a string (Unicode if isW, ANSI if !isW) + */ +static BOOL textsetptrT(LPWSTR *dest, LPWSTR src, BOOL isW) +{ + BOOL bResult = TRUE; + + if (src == LPSTR_TEXTCALLBACKW) + { + if (is_textW(*dest)) Free(*dest); + *dest = LPSTR_TEXTCALLBACKW; + } + else + { + LPWSTR pszText = textdupTtoW(src, isW); + if (*dest == LPSTR_TEXTCALLBACKW) *dest = NULL; + bResult = Str_SetPtrW(dest, pszText); + textfreeT(pszText, isW); + } + return bResult; +} + +/* + * compares a Unicode to a Unicode/ANSI text string + */ +static inline int textcmpWT(LPCWSTR aw, LPCWSTR bt, BOOL isW) +{ + if (!aw) return bt ? -1 : 0; + if (!bt) return aw ? 1 : 0; + if (aw == LPSTR_TEXTCALLBACKW) + return bt == LPSTR_TEXTCALLBACKW ? 0 : -1; + if (bt != LPSTR_TEXTCALLBACKW) + { + LPWSTR bw = textdupTtoW(bt, isW); + int r = bw ? lstrcmpW(aw, bw) : 1; + textfreeT(bw, isW); + return r; + } + + return 1; +} + +static inline int lstrncmpiW(LPCWSTR s1, LPCWSTR s2, int n) +{ + int res; + + n = min(min(n, strlenW(s1)), strlenW(s2)); + res = CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, s1, n, s2, n); + return res ? res - sizeof(WCHAR) : res; +} + +/******** Debugging functions *****************************************/ + +static inline LPCSTR debugtext_t(LPCWSTR text, BOOL isW) +{ + if (text == LPSTR_TEXTCALLBACKW) return "(callback)"; + return isW ? debugstr_w(text) : debugstr_a((LPCSTR)text); +} + +static inline LPCSTR debugtext_tn(LPCWSTR text, BOOL isW, INT n) +{ + if (text == LPSTR_TEXTCALLBACKW) return "(callback)"; + n = min(textlenT(text, isW), n); + return isW ? debugstr_wn(text, n) : debugstr_an((LPCSTR)text, n); +} + +static char* debug_getbuf(void) +{ + static int index = 0; + static char buffers[DEBUG_BUFFERS][DEBUG_BUFFER_SIZE]; + return buffers[index++ % DEBUG_BUFFERS]; +} + +static inline const char* debugrange(const RANGE *lprng) +{ + if (lprng) + { + char* buf = debug_getbuf(); + snprintf(buf, DEBUG_BUFFER_SIZE, "[%d, %d)", lprng->lower, lprng->upper); + return buf; + } else return "(null)"; +} + +static inline const char* debugpoint(const POINT *lppt) +{ + if (lppt) + { + char* buf = debug_getbuf(); + snprintf(buf, DEBUG_BUFFER_SIZE, "(%ld, %ld)", lppt->x, lppt->y); + return buf; + } else return "(null)"; +} + +static inline const char* debugrect(const RECT *rect) +{ + if (rect) + { + char* buf = debug_getbuf(); + snprintf(buf, DEBUG_BUFFER_SIZE, "[(%ld, %ld);(%ld, %ld)]", + rect->left, rect->top, rect->right, rect->bottom); + return buf; + } else return "(null)"; +} + +static const char* debugscrollinfo(const SCROLLINFO *pScrollInfo) +{ + char* buf = debug_getbuf(), *text = buf; + int len, size = DEBUG_BUFFER_SIZE; + + if (pScrollInfo == NULL) return "(null)"; + len = snprintf(buf, size, "{cbSize=%d, ", pScrollInfo->cbSize); + if (len == -1) goto end; buf += len; size -= len; + if (pScrollInfo->fMask & SIF_RANGE) + len = snprintf(buf, size, "nMin=%d, nMax=%d, ", pScrollInfo->nMin, pScrollInfo->nMax); + else len = 0; + if (len == -1) goto end; buf += len; size -= len; + if (pScrollInfo->fMask & SIF_PAGE) + len = snprintf(buf, size, "nPage=%u, ", pScrollInfo->nPage); + else len = 0; + if (len == -1) goto end; buf += len; size -= len; + if (pScrollInfo->fMask & SIF_POS) + len = snprintf(buf, size, "nPos=%d, ", pScrollInfo->nPos); + else len = 0; + if (len == -1) goto end; buf += len; size -= len; + if (pScrollInfo->fMask & SIF_TRACKPOS) + len = snprintf(buf, size, "nTrackPos=%d, ", pScrollInfo->nTrackPos); + else len = 0; + if (len == -1) goto end; buf += len; size -= len; + goto undo; +end: + buf = text + strlen(text); +undo: + if (buf - text > 2) { buf[-2] = '}'; buf[-1] = 0; } + return text; +} + +static const char* debugnmlistview(const NMLISTVIEW *plvnm) +{ + if (plvnm) + { + char* buf = debug_getbuf(); + snprintf(buf, DEBUG_BUFFER_SIZE, "iItem=%d, iSubItem=%d, uNewState=0x%x," + " uOldState=0x%x, uChanged=0x%x, ptAction=%s, lParam=%ld\n", + plvnm->iItem, plvnm->iSubItem, plvnm->uNewState, plvnm->uOldState, + plvnm->uChanged, debugpoint(&plvnm->ptAction), plvnm->lParam); + return buf; + } else return "(null)"; +} + +static const char* debuglvitem_t(const LVITEMW *lpLVItem, BOOL isW) +{ + char* buf = debug_getbuf(), *text = buf; + int len, size = DEBUG_BUFFER_SIZE; + + if (lpLVItem == NULL) return "(null)"; + len = snprintf(buf, size, "{iItem=%d, iSubItem=%d, ", lpLVItem->iItem, lpLVItem->iSubItem); + if (len == -1) goto end; buf += len; size -= len; + if (lpLVItem->mask & LVIF_STATE) + len = snprintf(buf, size, "state=%x, stateMask=%x, ", lpLVItem->state, lpLVItem->stateMask); + else len = 0; + if (len == -1) goto end; buf += len; size -= len; + if (lpLVItem->mask & LVIF_TEXT) + len = snprintf(buf, size, "pszText=%s, cchTextMax=%d, ", debugtext_tn(lpLVItem->pszText, isW, 80), lpLVItem->cchTextMax); + else len = 0; + if (len == -1) goto end; buf += len; size -= len; + if (lpLVItem->mask & LVIF_IMAGE) + len = snprintf(buf, size, "iImage=%d, ", lpLVItem->iImage); + else len = 0; + if (len == -1) goto end; buf += len; size -= len; + if (lpLVItem->mask & LVIF_PARAM) + len = snprintf(buf, size, "lParam=%lx, ", lpLVItem->lParam); + else len = 0; + if (len == -1) goto end; buf += len; size -= len; + if (lpLVItem->mask & LVIF_INDENT) + len = snprintf(buf, size, "iIndent=%d, ", lpLVItem->iIndent); + else len = 0; + if (len == -1) goto end; buf += len; size -= len; + goto undo; +end: + buf = text + strlen(text); +undo: + if (buf - text > 2) { buf[-2] = '}'; buf[-1] = 0; } + return text; +} + +static const char* debuglvcolumn_t(const LVCOLUMNW *lpColumn, BOOL isW) +{ + char* buf = debug_getbuf(), *text = buf; + int len, size = DEBUG_BUFFER_SIZE; + + if (lpColumn == NULL) return "(null)"; + len = snprintf(buf, size, "{"); + if (len == -1) goto end; buf += len; size -= len; + if (lpColumn->mask & LVCF_SUBITEM) + len = snprintf(buf, size, "iSubItem=%d, ", lpColumn->iSubItem); + else len = 0; + if (len == -1) goto end; buf += len; size -= len; + if (lpColumn->mask & LVCF_FMT) + len = snprintf(buf, size, "fmt=%x, ", lpColumn->fmt); + else len = 0; + if (len == -1) goto end; buf += len; size -= len; + if (lpColumn->mask & LVCF_WIDTH) + len = snprintf(buf, size, "cx=%d, ", lpColumn->cx); + else len = 0; + if (len == -1) goto end; buf += len; size -= len; + if (lpColumn->mask & LVCF_TEXT) + len = snprintf(buf, size, "pszText=%s, cchTextMax=%d, ", debugtext_tn(lpColumn->pszText, isW, 80), lpColumn->cchTextMax); + else len = 0; + if (len == -1) goto end; buf += len; size -= len; + if (lpColumn->mask & LVCF_IMAGE) + len = snprintf(buf, size, "iImage=%d, ", lpColumn->iImage); + else len = 0; + if (len == -1) goto end; buf += len; size -= len; + if (lpColumn->mask & LVCF_ORDER) + len = snprintf(buf, size, "iOrder=%d, ", lpColumn->iOrder); + else len = 0; + if (len == -1) goto end; buf += len; size -= len; + goto undo; +end: + buf = text + strlen(text); +undo: + if (buf - text > 2) { buf[-2] = '}'; buf[-1] = 0; } + return text; +} + +static const char* debuglvhittestinfo(const LVHITTESTINFO *lpht) +{ + if (lpht) + { + char* buf = debug_getbuf(); + snprintf(buf, DEBUG_BUFFER_SIZE, "{pt=%s, flags=0x%x, iItem=%d, iSubItem=%d}", + debugpoint(&lpht->pt), lpht->flags, lpht->iItem, lpht->iSubItem); + return buf; + } else return "(null)"; +} + +/* Return the corresponding text for a given scroll value */ +static inline LPCSTR debugscrollcode(int nScrollCode) +{ + switch(nScrollCode) + { + case SB_LINELEFT: return "SB_LINELEFT"; + case SB_LINERIGHT: return "SB_LINERIGHT"; + case SB_PAGELEFT: return "SB_PAGELEFT"; + case SB_PAGERIGHT: return "SB_PAGERIGHT"; + case SB_THUMBPOSITION: return "SB_THUMBPOSITION"; + case SB_THUMBTRACK: return "SB_THUMBTRACK"; + case SB_ENDSCROLL: return "SB_ENDSCROLL"; + case SB_INTERNAL: return "SB_INTERNAL"; + default: return "unknown"; + } +} + + +/******** Notification functions i************************************/ + +static LRESULT notify_hdr(LISTVIEW_INFO *infoPtr, INT code, LPNMHDR pnmh) +{ + LRESULT result; + + TRACE("(code=%d)\n", code); + + pnmh->hwndFrom = infoPtr->hwndSelf; + pnmh->idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); + pnmh->code = code; + result = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, + (WPARAM)pnmh->idFrom, (LPARAM)pnmh); + + TRACE(" <= %ld\n", result); + + return result; +} + +static inline LRESULT notify(LISTVIEW_INFO *infoPtr, INT code) +{ + NMHDR nmh; + return notify_hdr(infoPtr, code, &nmh); +} + +static inline void notify_itemactivate(LISTVIEW_INFO *infoPtr, LVHITTESTINFO *htInfo) +{ + NMITEMACTIVATE nmia; + LVITEMW item; + + if (htInfo) { + nmia.uNewState = 0; + nmia.uOldState = 0; + nmia.uChanged = 0; + nmia.uKeyFlags = 0; + + item.mask = LVIF_PARAM|LVIF_STATE; + item.iItem = htInfo->iItem; + item.iSubItem = 0; + if (LISTVIEW_GetItemT(infoPtr, &item, TRUE)) { + nmia.lParam = item.lParam; + nmia.uOldState = item.state; + nmia.uNewState = item.state | LVIS_ACTIVATING; + nmia.uChanged = LVIF_STATE; + } + + nmia.iItem = htInfo->iItem; + nmia.iSubItem = htInfo->iSubItem; + nmia.ptAction = htInfo->pt; + + if (GetKeyState(VK_SHIFT) & 0x8000) nmia.uKeyFlags |= LVKF_SHIFT; + if (GetKeyState(VK_CONTROL) & 0x8000) nmia.uKeyFlags |= LVKF_CONTROL; + if (GetKeyState(VK_MENU) & 0x8000) nmia.uKeyFlags |= LVKF_ALT; + } + notify_hdr(infoPtr, LVN_ITEMACTIVATE, (LPNMHDR)&nmia); +} + +static inline LRESULT notify_listview(LISTVIEW_INFO *infoPtr, INT code, LPNMLISTVIEW plvnm) +{ + TRACE("(code=%d, plvnm=%s)\n", code, debugnmlistview(plvnm)); + return notify_hdr(infoPtr, code, (LPNMHDR)plvnm); +} + +static LRESULT notify_click(LISTVIEW_INFO *infoPtr, INT code, LVHITTESTINFO *lvht) +{ + NMLISTVIEW nmlv; + LVITEMW item; + + TRACE("code=%d, lvht=%s\n", code, debuglvhittestinfo(lvht)); + ZeroMemory(&nmlv, sizeof(nmlv)); + nmlv.iItem = lvht->iItem; + nmlv.iSubItem = lvht->iSubItem; + nmlv.ptAction = lvht->pt; + item.mask = LVIF_PARAM; + item.iItem = lvht->iItem; + item.iSubItem = 0; + if (LISTVIEW_GetItemT(infoPtr, &item, TRUE)) nmlv.lParam = item.lParam; + return notify_listview(infoPtr, code, &nmlv); +} + +static void notify_deleteitem(LISTVIEW_INFO *infoPtr, INT nItem) +{ + NMLISTVIEW nmlv; + LVITEMW item; + + ZeroMemory(&nmlv, sizeof (NMLISTVIEW)); + nmlv.iItem = nItem; + item.mask = LVIF_PARAM; + item.iItem = nItem; + item.iSubItem = 0; + if (LISTVIEW_GetItemT(infoPtr, &item, TRUE)) nmlv.lParam = item.lParam; + notify_listview(infoPtr, LVN_DELETEITEM, &nmlv); +} + +static int get_ansi_notification(INT unicodeNotificationCode) +{ + switch (unicodeNotificationCode) + { + case LVN_BEGINLABELEDITW: return LVN_BEGINLABELEDITA; + case LVN_ENDLABELEDITW: return LVN_ENDLABELEDITA; + case LVN_GETDISPINFOW: return LVN_GETDISPINFOA; + case LVN_SETDISPINFOW: return LVN_SETDISPINFOA; + case LVN_ODFINDITEMW: return LVN_ODFINDITEMA; + case LVN_GETINFOTIPW: return LVN_GETINFOTIPA; + } + ERR("unknown notification %x\n", unicodeNotificationCode); + assert(FALSE); + return 0; +} + +/* + Send notification. depends on dispinfoW having same + structure as dispinfoA. + infoPtr : listview struct + notificationCode : *Unicode* notification code + pdi : dispinfo structure (can be unicode or ansi) + isW : TRUE if dispinfo is Unicode +*/ +static BOOL notify_dispinfoT(LISTVIEW_INFO *infoPtr, INT notificationCode, LPNMLVDISPINFOW pdi, BOOL isW) +{ + BOOL bResult = FALSE; + BOOL convertToAnsi = FALSE, convertToUnicode = FALSE; + INT cchTempBufMax = 0, savCchTextMax = 0, realNotifCode; + LPWSTR pszTempBuf = NULL, savPszText = NULL; + + if ((pdi->item.mask & LVIF_TEXT) && is_textT(pdi->item.pszText, isW)) + { + convertToAnsi = (isW && infoPtr->notifyFormat == NFR_ANSI); + convertToUnicode = (!isW && infoPtr->notifyFormat == NFR_UNICODE); + } + + if (convertToAnsi || convertToUnicode) + { + if (notificationCode != LVN_GETDISPINFOW) + { + cchTempBufMax = convertToUnicode ? + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pdi->item.pszText, -1, NULL, 0): + WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, NULL, 0, NULL, NULL); + } + else + { + cchTempBufMax = pdi->item.cchTextMax; + *pdi->item.pszText = 0; /* make sure we don't process garbage */ + } + + pszTempBuf = Alloc( (convertToUnicode ? sizeof(WCHAR) : sizeof(CHAR)) * cchTempBufMax); + if (!pszTempBuf) return FALSE; + + if (convertToUnicode) + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pdi->item.pszText, -1, + pszTempBuf, cchTempBufMax); + else + WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) pszTempBuf, + cchTempBufMax, NULL, NULL); + + savCchTextMax = pdi->item.cchTextMax; + savPszText = pdi->item.pszText; + pdi->item.pszText = pszTempBuf; + pdi->item.cchTextMax = cchTempBufMax; + } + + if (infoPtr->notifyFormat == NFR_ANSI) + realNotifCode = get_ansi_notification(notificationCode); + else + realNotifCode = notificationCode; + TRACE(" pdi->item=%s\n", debuglvitem_t(&pdi->item, infoPtr->notifyFormat != NFR_ANSI)); + bResult = notify_hdr(infoPtr, realNotifCode, &pdi->hdr); + + if (convertToUnicode || convertToAnsi) + { + if (convertToUnicode) /* note : pointer can be changed by app ! */ + WideCharToMultiByte(CP_ACP, 0, pdi->item.pszText, -1, (LPSTR) savPszText, + savCchTextMax, NULL, NULL); + else + MultiByteToWideChar(CP_ACP, 0, (LPSTR) pdi->item.pszText, -1, + savPszText, savCchTextMax); + pdi->item.pszText = savPszText; /* restores our buffer */ + pdi->item.cchTextMax = savCchTextMax; + Free (pszTempBuf); + } + return bResult; +} + +static void customdraw_fill(NMLVCUSTOMDRAW *lpnmlvcd, LISTVIEW_INFO *infoPtr, HDC hdc, + const RECT *rcBounds, const LVITEMW *lplvItem) +{ + ZeroMemory(lpnmlvcd, sizeof(NMLVCUSTOMDRAW)); + lpnmlvcd->nmcd.hdc = hdc; + lpnmlvcd->nmcd.rc = *rcBounds; + lpnmlvcd->clrTextBk = infoPtr->clrTextBk; + lpnmlvcd->clrText = infoPtr->clrText; + if (!lplvItem) return; + lpnmlvcd->nmcd.dwItemSpec = lplvItem->iItem + 1; + lpnmlvcd->iSubItem = lplvItem->iSubItem; + if (lplvItem->state & LVIS_SELECTED) lpnmlvcd->nmcd.uItemState |= CDIS_SELECTED; + if (lplvItem->state & LVIS_FOCUSED) lpnmlvcd->nmcd.uItemState |= CDIS_FOCUS; + if (lplvItem->iItem == infoPtr->nHotItem) lpnmlvcd->nmcd.uItemState |= CDIS_HOT; + lpnmlvcd->nmcd.lItemlParam = lplvItem->lParam; +} + +static inline DWORD notify_customdraw (LISTVIEW_INFO *infoPtr, DWORD dwDrawStage, NMLVCUSTOMDRAW *lpnmlvcd) +{ + BOOL isForItem = (lpnmlvcd->nmcd.dwItemSpec != 0); + DWORD result; + + lpnmlvcd->nmcd.dwDrawStage = dwDrawStage; + if (isForItem) lpnmlvcd->nmcd.dwDrawStage |= CDDS_ITEM; + if (lpnmlvcd->iSubItem) lpnmlvcd->nmcd.dwDrawStage |= CDDS_SUBITEM; + if (isForItem) lpnmlvcd->nmcd.dwItemSpec--; + result = notify_hdr(infoPtr, NM_CUSTOMDRAW, &lpnmlvcd->nmcd.hdr); + if (isForItem) lpnmlvcd->nmcd.dwItemSpec++; + return result; +} + +static void prepaint_setup (LISTVIEW_INFO *infoPtr, HDC hdc, NMLVCUSTOMDRAW *lpnmlvcd) +{ + /* apprently, for selected items, we have to override the returned values */ + if (lpnmlvcd->nmcd.uItemState & CDIS_SELECTED) + { + if (infoPtr->bFocus) + { + lpnmlvcd->clrTextBk = comctl32_color.clrHighlight; + lpnmlvcd->clrText = comctl32_color.clrHighlightText; + } + else if (infoPtr->dwStyle & LVS_SHOWSELALWAYS) + { + lpnmlvcd->clrTextBk = comctl32_color.clr3dFace; + lpnmlvcd->clrText = comctl32_color.clrBtnText; + } + } + + /* Set the text attributes */ + if (lpnmlvcd->clrTextBk != CLR_NONE) + { + SetBkMode(hdc, OPAQUE); + if (lpnmlvcd->clrTextBk == CLR_DEFAULT) + SetBkColor(hdc, infoPtr->clrTextBkDefault); + else + SetBkColor(hdc,lpnmlvcd->clrTextBk); + } + else + SetBkMode(hdc, TRANSPARENT); + SetTextColor(hdc, lpnmlvcd->clrText); +} + +static inline DWORD notify_postpaint (LISTVIEW_INFO *infoPtr, NMLVCUSTOMDRAW *lpnmlvcd) +{ + return notify_customdraw(infoPtr, CDDS_POSTPAINT, lpnmlvcd); +} + +/******** Item iterator functions **********************************/ + +static RANGES ranges_create(int count); +static void ranges_destroy(RANGES ranges); +static BOOL ranges_add(RANGES ranges, RANGE range); +static BOOL ranges_del(RANGES ranges, RANGE range); +static void ranges_dump(RANGES ranges); + +static inline BOOL ranges_additem(RANGES ranges, INT nItem) +{ + RANGE range = { nItem, nItem + 1 }; + + return ranges_add(ranges, range); +} + +static inline BOOL ranges_delitem(RANGES ranges, INT nItem) +{ + RANGE range = { nItem, nItem + 1 }; + + return ranges_del(ranges, range); +} + +/*** + * ITERATOR DOCUMENTATION + * + * The iterator functions allow for easy, and convenient iteration + * over items of iterest in the list. Typically, you create a + * iterator, use it, and destroy it, as such: + * ITERATOR i; + * + * iterator_xxxitems(&i, ...); + * while (iterator_{prev,next}(&i) + * { + * //code which uses i.nItem + * } + * iterator_destroy(&i); + * + * where xxx is either: framed, or visible. + * Note that it is important that the code destroys the iterator + * after it's done with it, as the creation of the iterator may + * allocate memory, which thus needs to be freed. + * + * You can iterate both forwards, and backwards through the list, + * by using iterator_next or iterator_prev respectively. + * + * Lower numbered items are draw on top of higher number items in + * LVS_ICON, and LVS_SMALLICON (which are the only modes where + * items may overlap). So, to test items, you should use + * iterator_next + * which lists the items top to bottom (in Z-order). + * For drawing items, you should use + * iterator_prev + * which lists the items bottom to top (in Z-order). + * If you keep iterating over the items after the end-of-items + * marker (-1) is returned, the iterator will start from the + * beginning. Typically, you don't need to test for -1, + * because iterator_{next,prev} will return TRUE if more items + * are to be iterated over, or FALSE otherwise. + * + * Note: the iterator is defined to be bidirectional. That is, + * any number of prev followed by any number of next, or + * five versa, should leave the iterator at the same item: + * prev * n, next * n = next * n, prev * n + * + * The iterator has a notion of an out-of-order, special item, + * which sits at the start of the list. This is used in + * LVS_ICON, and LVS_SMALLICON mode to handle the focused item, + * which needs to be first, as it may overlap other items. + * + * The code is a bit messy because we have: + * - a special item to deal with + * - simple range, or composite range + * - empty range. + * If you find bugs, or want to add features, please make sure you + * always check/modify *both* iterator_prev, and iterator_next. + */ + +/**** + * This function iterates through the items in increasing order, + * but prefixed by the special item, then -1. That is: + * special, 1, 2, 3, ..., n, -1. + * Each item is listed only once. + */ +static inline BOOL iterator_next(ITERATOR* i) +{ + if (i->nItem == -1) + { + i->nItem = i->nSpecial; + if (i->nItem != -1) return TRUE; + } + if (i->nItem == i->nSpecial) + { + if (i->ranges) i->index = 0; + goto pickarange; + } + + i->nItem++; +testitem: + if (i->nItem == i->nSpecial) i->nItem++; + if (i->nItem < i->range.upper) return TRUE; + +pickarange: + if (i->ranges) + { + if (i->index < DPA_GetPtrCount(i->ranges->hdpa)) + i->range = *(RANGE*)DPA_GetPtr(i->ranges->hdpa, i->index++); + else goto end; + } + else if (i->nItem >= i->range.upper) goto end; + + i->nItem = i->range.lower; + if (i->nItem >= 0) goto testitem; +end: + i->nItem = -1; + return FALSE; +} + +/**** + * This function iterates through the items in decreasing order, + * followed by the special item, then -1. That is: + * n, n-1, ..., 3, 2, 1, special, -1. + * Each item is listed only once. + */ +static inline BOOL iterator_prev(ITERATOR* i) +{ + BOOL start = FALSE; + + if (i->nItem == -1) + { + start = TRUE; + if (i->ranges) i->index = DPA_GetPtrCount(i->ranges->hdpa); + goto pickarange; + } + if (i->nItem == i->nSpecial) + { + i->nItem = -1; + return FALSE; + } + +testitem: + i->nItem--; + if (i->nItem == i->nSpecial) i->nItem--; + if (i->nItem >= i->range.lower) return TRUE; + +pickarange: + if (i->ranges) + { + if (i->index > 0) + i->range = *(RANGE*)DPA_GetPtr(i->ranges->hdpa, --i->index); + else goto end; + } + else if (!start && i->nItem < i->range.lower) goto end; + + i->nItem = i->range.upper; + if (i->nItem > 0) goto testitem; +end: + return (i->nItem = i->nSpecial) != -1; +} + +static RANGE iterator_range(ITERATOR* i) +{ + RANGE range; + + if (!i->ranges) return i->range; + + if (DPA_GetPtrCount(i->ranges->hdpa) > 0) + { + range.lower = (*(RANGE*)DPA_GetPtr(i->ranges->hdpa, 0)).lower; + range.upper = (*(RANGE*)DPA_GetPtr(i->ranges->hdpa, DPA_GetPtrCount(i->ranges->hdpa) - 1)).upper; + } + else range.lower = range.upper = 0; + + return range; +} + +/*** + * Releases resources associated with this ierator. + */ +static inline void iterator_destroy(ITERATOR* i) +{ + ranges_destroy(i->ranges); +} + +/*** + * Create an empty iterator. + */ +static inline BOOL iterator_empty(ITERATOR* i) +{ + ZeroMemory(i, sizeof(*i)); + i->nItem = i->nSpecial = i->range.lower = i->range.upper = -1; + return TRUE; +} + +/*** + * Create an iterator over a range. + */ +static inline BOOL iterator_rangeitems(ITERATOR* i, RANGE range) +{ + iterator_empty(i); + i->range = range; + return TRUE; +} + +/*** + * Create an iterator over a bunch of ranges. + * Please note that the iterator will take ownership of the ranges, + * and will free them upon destruction. + */ +static inline BOOL iterator_rangesitems(ITERATOR* i, RANGES ranges) +{ + iterator_empty(i); + i->ranges = ranges; + return TRUE; +} + +/*** + * Creates an iterator over the items which intersect lprc. + */ +static BOOL iterator_frameditems(ITERATOR* i, LISTVIEW_INFO* infoPtr, const RECT *lprc) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + RECT frame = *lprc, rcItem, rcTemp; + POINT Origin; + + /* in case we fail, we want to return an empty iterator */ + if (!iterator_empty(i)) return FALSE; + + LISTVIEW_GetOrigin(infoPtr, &Origin); + + TRACE("(lprc=%s)\n", debugrect(lprc)); + OffsetRect(&frame, -Origin.x, -Origin.y); + + if (uView == LVS_ICON || uView == LVS_SMALLICON) + { + INT nItem; + + if (uView == LVS_ICON && infoPtr->nFocusedItem != -1) + { + LISTVIEW_GetItemBox(infoPtr, infoPtr->nFocusedItem, &rcItem); + if (IntersectRect(&rcTemp, &rcItem, lprc)) + i->nSpecial = infoPtr->nFocusedItem; + } + if (!(iterator_rangesitems(i, ranges_create(50)))) return FALSE; + /* to do better here, we need to have PosX, and PosY sorted */ + TRACE("building icon ranges:\n"); + for (nItem = 0; nItem < infoPtr->nItemCount; nItem++) + { + rcItem.left = (LONG)DPA_GetPtr(infoPtr->hdpaPosX, nItem); + rcItem.top = (LONG)DPA_GetPtr(infoPtr->hdpaPosY, nItem); + rcItem.right = rcItem.left + infoPtr->nItemWidth; + rcItem.bottom = rcItem.top + infoPtr->nItemHeight; + if (IntersectRect(&rcTemp, &rcItem, &frame)) + ranges_additem(i->ranges, nItem); + } + return TRUE; + } + else if (uView == LVS_REPORT) + { + RANGE range; + + if (frame.left >= infoPtr->nItemWidth) return TRUE; + if (frame.top >= infoPtr->nItemHeight * infoPtr->nItemCount) return TRUE; + + range.lower = max(frame.top / infoPtr->nItemHeight, 0); + range.upper = min((frame.bottom - 1) / infoPtr->nItemHeight, infoPtr->nItemCount - 1) + 1; + if (range.upper <= range.lower) return TRUE; + if (!iterator_rangeitems(i, range)) return FALSE; + TRACE(" report=%s\n", debugrange(&i->range)); + } + else + { + INT nPerCol = max((infoPtr->rcList.bottom - infoPtr->rcList.top) / infoPtr->nItemHeight, 1); + INT nFirstRow = max(frame.top / infoPtr->nItemHeight, 0); + INT nLastRow = min((frame.bottom - 1) / infoPtr->nItemHeight, nPerCol - 1); + INT nFirstCol = max(frame.left / infoPtr->nItemWidth, 0); + INT nLastCol = min((frame.right - 1) / infoPtr->nItemWidth, (infoPtr->nItemCount + nPerCol - 1) / nPerCol); + INT lower = nFirstCol * nPerCol + nFirstRow; + RANGE item_range; + INT nCol; + + TRACE("nPerCol=%d, nFirstRow=%d, nLastRow=%d, nFirstCol=%d, nLastCol=%d, lower=%d\n", + nPerCol, nFirstRow, nLastRow, nFirstCol, nLastCol, lower); + + if (nLastCol < nFirstCol || nLastRow < nFirstRow) return TRUE; + + if (!(iterator_rangesitems(i, ranges_create(nLastCol - nFirstCol + 1)))) return FALSE; + TRACE("building list ranges:\n"); + for (nCol = nFirstCol; nCol <= nLastCol; nCol++) + { + item_range.lower = nCol * nPerCol + nFirstRow; + if(item_range.lower >= infoPtr->nItemCount) break; + item_range.upper = min(nCol * nPerCol + nLastRow + 1, infoPtr->nItemCount); + TRACE(" list=%s\n", debugrange(&item_range)); + ranges_add(i->ranges, item_range); + } + } + + return TRUE; +} + +/*** + * Creates an iterator over the items which intersect the visible region of hdc. + */ +static BOOL iterator_visibleitems(ITERATOR *i, LISTVIEW_INFO *infoPtr, HDC hdc) +{ + POINT Origin, Position; + RECT rcItem, rcClip; + INT rgntype; + + rgntype = GetClipBox(hdc, &rcClip); + if (rgntype == NULLREGION) return iterator_empty(i); + if (!iterator_frameditems(i, infoPtr, &rcClip)) return FALSE; + if (rgntype == SIMPLEREGION) return TRUE; + + /* first deal with the special item */ + if (i->nSpecial != -1) + { + LISTVIEW_GetItemBox(infoPtr, i->nSpecial, &rcItem); + if (!RectVisible(hdc, &rcItem)) i->nSpecial = -1; + } + + /* if we can't deal with the region, we'll just go with the simple range */ + LISTVIEW_GetOrigin(infoPtr, &Origin); + TRACE("building visible range:\n"); + if (!i->ranges && i->range.lower < i->range.upper) + { + if (!(i->ranges = ranges_create(50))) return TRUE; + if (!ranges_add(i->ranges, i->range)) + { + ranges_destroy(i->ranges); + i->ranges = 0; + return TRUE; + } + } + + /* now delete the invisible items from the list */ + while(iterator_next(i)) + { + LISTVIEW_GetItemOrigin(infoPtr, i->nItem, &Position); + rcItem.left = Position.x + Origin.x; + rcItem.top = Position.y + Origin.y; + rcItem.right = rcItem.left + infoPtr->nItemWidth; + rcItem.bottom = rcItem.top + infoPtr->nItemHeight; + if (!RectVisible(hdc, &rcItem)) + ranges_delitem(i->ranges, i->nItem); + } + /* the iterator should restart on the next iterator_next */ + TRACE("done\n"); + + return TRUE; +} + +/******** Misc helper functions ************************************/ + +static inline LRESULT CallWindowProcT(WNDPROC proc, HWND hwnd, UINT uMsg, + WPARAM wParam, LPARAM lParam, BOOL isW) +{ + if (isW) return CallWindowProcW(proc, hwnd, uMsg, wParam, lParam); + else return CallWindowProcA(proc, hwnd, uMsg, wParam, lParam); +} + +static inline BOOL is_autoarrange(LISTVIEW_INFO *infoPtr) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + + return ((infoPtr->dwStyle & LVS_AUTOARRANGE) || infoPtr->bAutoarrange) && + (uView == LVS_ICON || uView == LVS_SMALLICON); +} + +/******** Internal API functions ************************************/ + +static inline COLUMN_INFO * LISTVIEW_GetColumnInfo(LISTVIEW_INFO *infoPtr, INT nSubItem) +{ + static COLUMN_INFO mainItem; + + if (nSubItem == 0 && DPA_GetPtrCount(infoPtr->hdpaColumns) == 0) return &mainItem; + assert (nSubItem >= 0 && nSubItem < DPA_GetPtrCount(infoPtr->hdpaColumns)); + return (COLUMN_INFO *)DPA_GetPtr(infoPtr->hdpaColumns, nSubItem); +} + +static inline void LISTVIEW_GetHeaderRect(LISTVIEW_INFO *infoPtr, INT nSubItem, RECT *lprc) +{ + *lprc = LISTVIEW_GetColumnInfo(infoPtr, nSubItem)->rcHeader; +} + +static inline BOOL LISTVIEW_GetItemW(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem) +{ + return LISTVIEW_GetItemT(infoPtr, lpLVItem, TRUE); +} + +/* Listview invalidation functions: use _only_ these functions to invalidate */ + +static inline BOOL is_redrawing(LISTVIEW_INFO *infoPtr) +{ + return infoPtr->bRedraw; +} + +static inline void LISTVIEW_InvalidateRect(LISTVIEW_INFO *infoPtr, const RECT* rect) +{ + if(!is_redrawing(infoPtr)) return; + TRACE(" invalidating rect=%s\n", debugrect(rect)); + InvalidateRect(infoPtr->hwndSelf, rect, TRUE); +} + +static inline void LISTVIEW_InvalidateItem(LISTVIEW_INFO *infoPtr, INT nItem) +{ + RECT rcBox; + + if(!is_redrawing(infoPtr)) return; + LISTVIEW_GetItemBox(infoPtr, nItem, &rcBox); + LISTVIEW_InvalidateRect(infoPtr, &rcBox); +} + +static inline void LISTVIEW_InvalidateSubItem(LISTVIEW_INFO *infoPtr, INT nItem, INT nSubItem) +{ + POINT Origin, Position; + RECT rcBox; + + if(!is_redrawing(infoPtr)) return; + assert ((infoPtr->dwStyle & LVS_TYPEMASK) == LVS_REPORT); + LISTVIEW_GetOrigin(infoPtr, &Origin); + LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position); + LISTVIEW_GetHeaderRect(infoPtr, nSubItem, &rcBox); + rcBox.top = 0; + rcBox.bottom = infoPtr->nItemHeight; + OffsetRect(&rcBox, Origin.x + Position.x, Origin.y + Position.y); + LISTVIEW_InvalidateRect(infoPtr, &rcBox); +} + +static inline void LISTVIEW_InvalidateList(LISTVIEW_INFO *infoPtr) +{ + LISTVIEW_InvalidateRect(infoPtr, NULL); +} + +static inline void LISTVIEW_InvalidateColumn(LISTVIEW_INFO *infoPtr, INT nColumn) +{ + RECT rcCol; + + if(!is_redrawing(infoPtr)) return; + LISTVIEW_GetHeaderRect(infoPtr, nColumn, &rcCol); + rcCol.top = infoPtr->rcList.top; + rcCol.bottom = infoPtr->rcList.bottom; + LISTVIEW_InvalidateRect(infoPtr, &rcCol); +} + +/*** + * DESCRIPTION: + * Retrieves the number of items that can fit vertically in the client area. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * + * RETURN: + * Number of items per row. + */ +static inline INT LISTVIEW_GetCountPerRow(LISTVIEW_INFO *infoPtr) +{ + INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left; + + return max(nListWidth/infoPtr->nItemWidth, 1); +} + +/*** + * DESCRIPTION: + * Retrieves the number of items that can fit horizontally in the client + * area. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * + * RETURN: + * Number of items per column. + */ +static inline INT LISTVIEW_GetCountPerColumn(LISTVIEW_INFO *infoPtr) +{ + INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top; + + return max(nListHeight / infoPtr->nItemHeight, 1); +} + + +/************************************************************************* + * LISTVIEW_ProcessLetterKeys + * + * Processes keyboard messages generated by pressing the letter keys + * on the keyboard. + * What this does is perform a case insensitive search from the + * current position with the following quirks: + * - If two chars or more are pressed in quick succession we search + * for the corresponding string (e.g. 'abc'). + * - If there is a delay we wipe away the current search string and + * restart with just that char. + * - If the user keeps pressing the same character, whether slowly or + * fast, so that the search string is entirely composed of this + * character ('aaaaa' for instance), then we search for first item + * that starting with that character. + * - If the user types the above character in quick succession, then + * we must also search for the corresponding string ('aaaaa'), and + * go to that string if there is a match. + * + * PARAMETERS + * [I] hwnd : handle to the window + * [I] charCode : the character code, the actual character + * [I] keyData : key data + * + * RETURNS + * + * Zero. + * + * BUGS + * + * - The current implementation has a list of characters it will + * accept and it ignores averything else. In particular it will + * ignore accentuated characters which seems to match what + * Windows does. But I'm not sure it makes sense to follow + * Windows there. + * - We don't sound a beep when the search fails. + * + * SEE ALSO + * + * TREEVIEW_ProcessLetterKeys + */ +static INT LISTVIEW_ProcessLetterKeys(LISTVIEW_INFO *infoPtr, WPARAM charCode, LPARAM keyData) +{ + INT nItem; + INT endidx,idx; + LVITEMW item; + WCHAR buffer[MAX_PATH]; + DWORD lastKeyPressTimestamp = infoPtr->lastKeyPressTimestamp; + + /* simple parameter checking */ + if (!charCode || !keyData) return 0; + + /* only allow the valid WM_CHARs through */ + if (!isalnum(charCode) && + charCode != '.' && charCode != '`' && charCode != '!' && + charCode != '@' && charCode != '#' && charCode != '$' && + charCode != '%' && charCode != '^' && charCode != '&' && + charCode != '*' && charCode != '(' && charCode != ')' && + charCode != '-' && charCode != '_' && charCode != '+' && + charCode != '=' && charCode != '\\'&& charCode != ']' && + charCode != '}' && charCode != '[' && charCode != '{' && + charCode != '/' && charCode != '?' && charCode != '>' && + charCode != '<' && charCode != ',' && charCode != '~') + return 0; + + /* if there's one item or less, there is no where to go */ + if (infoPtr->nItemCount <= 1) return 0; + + /* update the search parameters */ + infoPtr->lastKeyPressTimestamp = GetTickCount(); + if (infoPtr->lastKeyPressTimestamp - lastKeyPressTimestamp < KEY_DELAY) { + if (infoPtr->nSearchParamLength < MAX_PATH) + infoPtr->szSearchParam[infoPtr->nSearchParamLength++]=charCode; + if (infoPtr->charCode != charCode) + infoPtr->charCode = charCode = 0; + } else { + infoPtr->charCode=charCode; + infoPtr->szSearchParam[0]=charCode; + infoPtr->nSearchParamLength=1; + /* Redundant with the 1 char string */ + charCode=0; + } + + /* and search from the current position */ + nItem=-1; + if (infoPtr->nFocusedItem >= 0) { + endidx=infoPtr->nFocusedItem; + idx=endidx; + /* if looking for single character match, + * then we must always move forward + */ + if (infoPtr->nSearchParamLength == 1) + idx++; + } else { + endidx=infoPtr->nItemCount; + idx=0; + } + do { + if (idx == infoPtr->nItemCount) { + if (endidx == infoPtr->nItemCount || endidx == 0) + break; + idx=0; + } + + /* get item */ + item.mask = LVIF_TEXT; + item.iItem = idx; + item.iSubItem = 0; + item.pszText = buffer; + item.cchTextMax = MAX_PATH; + if (!LISTVIEW_GetItemW(infoPtr, &item)) return 0; + + /* check for a match */ + if (lstrncmpiW(item.pszText,infoPtr->szSearchParam,infoPtr->nSearchParamLength) == 0) { + nItem=idx; + break; + } else if ( (charCode != 0) && (nItem == -1) && (nItem != infoPtr->nFocusedItem) && + (lstrncmpiW(item.pszText,infoPtr->szSearchParam,1) == 0) ) { + /* This would work but we must keep looking for a longer match */ + nItem=idx; + } + idx++; + } while (idx != endidx); + + if (nItem != -1) + LISTVIEW_KeySelection(infoPtr, nItem); + + return 0; +} + +/************************************************************************* + * LISTVIEW_UpdateHeaderSize [Internal] + * + * Function to resize the header control + * + * PARAMS + * [I] hwnd : handle to a window + * [I] nNewScrollPos : scroll pos to set + * + * RETURNS + * None. + */ +static void LISTVIEW_UpdateHeaderSize(LISTVIEW_INFO *infoPtr, INT nNewScrollPos) +{ + RECT winRect; + POINT point[2]; + + TRACE("nNewScrollPos=%d\n", nNewScrollPos); + + GetWindowRect(infoPtr->hwndHeader, &winRect); + point[0].x = winRect.left; + point[0].y = winRect.top; + point[1].x = winRect.right; + point[1].y = winRect.bottom; + + MapWindowPoints(HWND_DESKTOP, infoPtr->hwndSelf, point, 2); + point[0].x = -nNewScrollPos; + point[1].x += nNewScrollPos; + + SetWindowPos(infoPtr->hwndHeader,0, + point[0].x,point[0].y,point[1].x,point[1].y, + SWP_NOZORDER | SWP_NOACTIVATE); +} + +/*** + * DESCRIPTION: + * Update the scrollbars. This functions should be called whenever + * the content, size or view changes. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * + * RETURN: + * None + */ +static void LISTVIEW_UpdateScroll(LISTVIEW_INFO *infoPtr) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + SCROLLINFO horzInfo, vertInfo; + + if ((infoPtr->dwStyle & LVS_NOSCROLL) || !is_redrawing(infoPtr)) return; + + ZeroMemory(&horzInfo, sizeof(SCROLLINFO)); + horzInfo.cbSize = sizeof(SCROLLINFO); + horzInfo.nPage = infoPtr->rcList.right - infoPtr->rcList.left; + + /* for now, we'll set info.nMax to the _count_, and adjust it later */ + if (uView == LVS_LIST) + { + INT nPerCol = LISTVIEW_GetCountPerColumn(infoPtr); + horzInfo.nMax = (infoPtr->nItemCount + nPerCol - 1) / nPerCol; + + /* scroll by at least one column per page */ + if(horzInfo.nPage < infoPtr->nItemWidth) + horzInfo.nPage = infoPtr->nItemWidth; + + horzInfo.nPage /= infoPtr->nItemWidth; + } + else if (uView == LVS_REPORT) + { + horzInfo.nMax = infoPtr->nItemWidth; + } + else /* LVS_ICON, or LVS_SMALLICON */ + { + RECT rcView; + + if (LISTVIEW_GetViewRect(infoPtr, &rcView)) horzInfo.nMax = rcView.right - rcView.left; + } + + horzInfo.fMask = SIF_RANGE | SIF_PAGE; + horzInfo.nMax = max(horzInfo.nMax - 1, 0); + SetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &horzInfo, TRUE); + TRACE("horzInfo=%s\n", debugscrollinfo(&horzInfo)); + + /* Setting the horizontal scroll can change the listview size + * (and potentially everything else) so we need to recompute + * everything again for the vertical scroll + */ + + ZeroMemory(&vertInfo, sizeof(SCROLLINFO)); + vertInfo.cbSize = sizeof(SCROLLINFO); + vertInfo.nPage = infoPtr->rcList.bottom - infoPtr->rcList.top; + + if (uView == LVS_REPORT) + { + vertInfo.nMax = infoPtr->nItemCount; + + /* scroll by at least one page */ + if(vertInfo.nPage < infoPtr->nItemHeight) + vertInfo.nPage = infoPtr->nItemHeight; + + vertInfo.nPage /= infoPtr->nItemHeight; + } + else if (uView != LVS_LIST) /* LVS_ICON, or LVS_SMALLICON */ + { + RECT rcView; + + if (LISTVIEW_GetViewRect(infoPtr, &rcView)) vertInfo.nMax = rcView.bottom - rcView.top; + } + + vertInfo.fMask = SIF_RANGE | SIF_PAGE; + vertInfo.nMax = max(vertInfo.nMax - 1, 0); + SetScrollInfo(infoPtr->hwndSelf, SB_VERT, &vertInfo, TRUE); + TRACE("vertInfo=%s\n", debugscrollinfo(&vertInfo)); + + /* Update the Header Control */ + if (uView == LVS_REPORT) + { + horzInfo.fMask = SIF_POS; + GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &horzInfo); + LISTVIEW_UpdateHeaderSize(infoPtr, horzInfo.nPos); + } +} + + +/*** + * DESCRIPTION: + * Shows/hides the focus rectangle. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] fShow : TRUE to show the focus, FALSE to hide it. + * + * RETURN: + * None + */ +static void LISTVIEW_ShowFocusRect(LISTVIEW_INFO *infoPtr, BOOL fShow) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + HDC hdc; + + TRACE("fShow=%d, nItem=%d\n", fShow, infoPtr->nFocusedItem); + + if (infoPtr->nFocusedItem < 0) return; + + /* we need some gymnastics in ICON mode to handle large items */ + if ( (infoPtr->dwStyle & LVS_TYPEMASK) == LVS_ICON ) + { + RECT rcBox; + + LISTVIEW_GetItemBox(infoPtr, infoPtr->nFocusedItem, &rcBox); + if ((rcBox.bottom - rcBox.top) > infoPtr->nItemHeight) + { + LISTVIEW_InvalidateRect(infoPtr, &rcBox); + return; + } + } + + if (!(hdc = GetDC(infoPtr->hwndSelf))) return; + + /* for some reason, owner draw should work only in report mode */ + if ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (uView == LVS_REPORT)) + { + DRAWITEMSTRUCT dis; + LVITEMW item; + + item.iItem = infoPtr->nFocusedItem; + item.iSubItem = 0; + item.mask = LVIF_PARAM; + if (!LISTVIEW_GetItemW(infoPtr, &item)) goto done; + + ZeroMemory(&dis, sizeof(dis)); + dis.CtlType = ODT_LISTVIEW; + dis.CtlID = (UINT)GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); + dis.itemID = item.iItem; + dis.itemAction = ODA_FOCUS; + if (fShow) dis.itemState |= ODS_FOCUS; + dis.hwndItem = infoPtr->hwndSelf; + dis.hDC = hdc; + LISTVIEW_GetItemBox(infoPtr, dis.itemID, &dis.rcItem); + dis.itemData = item.lParam; + + SendMessageW(infoPtr->hwndNotify, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis); + } + else + { + DrawFocusRect(hdc, &infoPtr->rcFocus); + } +done: + ReleaseDC(infoPtr->hwndSelf, hdc); +} + +/*** + * Invalidates all visible selected items. + */ +static void LISTVIEW_InvalidateSelectedItems(LISTVIEW_INFO *infoPtr) +{ + ITERATOR i; + + iterator_frameditems(&i, infoPtr, &infoPtr->rcList); + while(iterator_next(&i)) + { + if (LISTVIEW_GetItemState(infoPtr, i.nItem, LVIS_SELECTED)) + LISTVIEW_InvalidateItem(infoPtr, i.nItem); + } + iterator_destroy(&i); +} + + +/*** + * DESCRIPTION: [INTERNAL] + * Computes an item's (left,top) corner, relative to rcView. + * That is, the position has NOT been made relative to the Origin. + * This is deliberate, to avoid computing the Origin over, and + * over again, when this function is call in a loop. Instead, + * one ca factor the computation of the Origin before the loop, + * and offset the value retured by this function, on every iteration. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nItem : item number + * [O] lpptOrig : item top, left corner + * + * RETURN: + * None. + */ +static void LISTVIEW_GetItemOrigin(LISTVIEW_INFO *infoPtr, INT nItem, LPPOINT lpptPosition) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + + assert(nItem >= 0 && nItem < infoPtr->nItemCount); + + if ((uView == LVS_SMALLICON) || (uView == LVS_ICON)) + { + lpptPosition->x = (LONG)DPA_GetPtr(infoPtr->hdpaPosX, nItem); + lpptPosition->y = (LONG)DPA_GetPtr(infoPtr->hdpaPosY, nItem); + } + else if (uView == LVS_LIST) + { + INT nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr); + lpptPosition->x = nItem / nCountPerColumn * infoPtr->nItemWidth; + lpptPosition->y = nItem % nCountPerColumn * infoPtr->nItemHeight; + } + else /* LVS_REPORT */ + { + lpptPosition->x = 0; + lpptPosition->y = nItem * infoPtr->nItemHeight; + } +} + +/*** + * DESCRIPTION: [INTERNAL] + * Compute the rectangles of an item. This is to localize all + * the computations in one place. If you are not interested in some + * of these values, simply pass in a NULL -- the fucntion is smart + * enough to compute only what's necessary. The function computes + * the standard rectangles (BOUNDS, ICON, LABEL) plus a non-standard + * one, the BOX rectangle. This rectangle is very cheap to compute, + * and is guaranteed to contain all the other rectangles. Computing + * the ICON rect is also cheap, but all the others are potentaily + * expensive. This gives an easy and effective optimization when + * searching (like point inclusion, or rectangle intersection): + * first test against the BOX, and if TRUE, test agains the desired + * rectangle. + * If the function does not have all the necessary information + * to computed the requested rectangles, will crash with a + * failed assertion. This is done so we catch all programming + * errors, given that the function is called only from our code. + * + * We have the following 'special' meanings for a few fields: + * * If LVIS_FOCUSED is set, we assume the item has the focus + * This is important in ICON mode, where it might get a larger + * then usual rectange + * + * Please note that subitem support works only in REPORT mode. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] lpLVItem : item to compute the measures for + * [O] lprcBox : ptr to Box rectangle + * The internal LVIR_BOX rectangle + * [0] lprcState : ptr to State icon rectangle + * The internal LVIR_STATE rectangle + * [O] lprcIcon : ptr to Icon rectangle + * Same as LVM_GETITEMRECT with LVIR_ICON + * [O] lprcLabel : ptr to Label rectangle + * Same as LVM_GETITEMRECT with LVIR_LABEL + * + * RETURN: + * None. + */ +static void LISTVIEW_GetItemMetrics(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, + LPRECT lprcBox, LPRECT lprcState, + LPRECT lprcIcon, LPRECT lprcLabel) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + BOOL doState = FALSE, doIcon = FALSE, doLabel = FALSE, oversizedBox = FALSE; + RECT Box, State, Icon, Label; + COLUMN_INFO *lpColumnInfo = NULL; + + TRACE("(lpLVItem=%s)\n", debuglvitem_t(lpLVItem, TRUE)); + + /* Be smart and try to figure out the minimum we have to do */ + if (lpLVItem->iSubItem) assert(uView == LVS_REPORT); + if (uView == LVS_ICON && (lprcBox || lprcLabel)) + { + assert((lpLVItem->mask & LVIF_STATE) && (lpLVItem->stateMask & LVIS_FOCUSED)); + if (lpLVItem->state & LVIS_FOCUSED) oversizedBox = doLabel = TRUE; + } + if (lprcLabel) doLabel = TRUE; + if (doLabel || lprcIcon) doIcon = TRUE; + if (doIcon || lprcState) doState = TRUE; + + /************************************************************/ + /* compute the box rectangle (it should be cheap to do) */ + /************************************************************/ + if (lpLVItem->iSubItem || uView == LVS_REPORT) + lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, lpLVItem->iSubItem); + + if (lpLVItem->iSubItem) + { + Box = lpColumnInfo->rcHeader; + } + else + { + Box.left = 0; + Box.right = infoPtr->nItemWidth; + } + Box.top = 0; + Box.bottom = infoPtr->nItemHeight; + + /************************************************************/ + /* compute STATEICON bounding box */ + /************************************************************/ + if (doState) + { + if (uView == LVS_ICON) + { + State.left = Box.left - infoPtr->iconStateSize.cx - 2; + if (infoPtr->himlNormal) + State.left += (infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2; + State.top = Box.top + infoPtr->iconSize.cy - infoPtr->iconStateSize.cy + 4; + } + else + { + /* we need the ident in report mode, if we don't have it, we fail */ + State.left = Box.left; + if (uView == LVS_REPORT) + { + if (lpLVItem->iSubItem == 0) + { + State.left += REPORT_MARGINX; + assert(lpLVItem->mask & LVIF_INDENT); + State.left += infoPtr->iconSize.cx * lpLVItem->iIndent; + } + } + State.top = Box.top; + } + State.right = State.left; + State.bottom = State.top; + if (infoPtr->himlState && lpLVItem->iSubItem == 0) + { + State.right += infoPtr->iconStateSize.cx; + State.bottom += infoPtr->iconStateSize.cy; + } + if (lprcState) *lprcState = State; + TRACE(" - state=%s\n", debugrect(&State)); + } + + /************************************************************/ + /* compute ICON bounding box (ala LVM_GETITEMRECT) */ + /************************************************************/ + if (doIcon) + { + if (uView == LVS_ICON) + { + Icon.left = Box.left; + if (infoPtr->himlNormal) + Icon.left += (infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2; + Icon.top = Box.top + ICON_TOP_PADDING; + Icon.right = Icon.left; + Icon.bottom = Icon.top; + if (infoPtr->himlNormal) + { + Icon.right += infoPtr->iconSize.cx; + Icon.bottom += infoPtr->iconSize.cy; + } + } + else /* LVS_SMALLICON, LVS_LIST or LVS_REPORT */ + { + Icon.left = State.right; + Icon.top = Box.top; + Icon.right = Icon.left; + if (infoPtr->himlSmall && + (!lpColumnInfo || lpLVItem->iSubItem == 0 || (lpColumnInfo->fmt & LVCFMT_IMAGE) || + ((infoPtr->dwLvExStyle & LVS_EX_SUBITEMIMAGES) && lpLVItem->iImage != I_IMAGECALLBACK))) + Icon.right += infoPtr->iconSize.cx; + Icon.bottom = Icon.top + infoPtr->nItemHeight; + } + if(lprcIcon) *lprcIcon = Icon; + TRACE(" - icon=%s\n", debugrect(&Icon)); + } + + /************************************************************/ + /* compute LABEL bounding box (ala LVM_GETITEMRECT) */ + /************************************************************/ + if (doLabel) + { + SIZE labelSize = { 0, 0 }; + + /* calculate how far to the right can the label strech */ + Label.right = Box.right; + if (uView == LVS_REPORT) + { + if (lpLVItem->iSubItem == 0) Label = lpColumnInfo->rcHeader; + } + + if (lpLVItem->iSubItem || ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && uView == LVS_REPORT)) + { + labelSize.cx = infoPtr->nItemWidth; + labelSize.cy = infoPtr->nItemHeight; + goto calc_label; + } + + /* we need the text in non owner draw mode */ + assert(lpLVItem->mask & LVIF_TEXT); + if (is_textT(lpLVItem->pszText, TRUE)) + { + HFONT hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont; + HDC hdc = GetDC(infoPtr->hwndSelf); + HFONT hOldFont = SelectObject(hdc, hFont); + UINT uFormat; + RECT rcText; + + /* compute rough rectangle where the label will go */ + SetRectEmpty(&rcText); + rcText.right = infoPtr->nItemWidth - TRAILING_LABEL_PADDING; + rcText.bottom = infoPtr->nItemHeight; + if (uView == LVS_ICON) + rcText.bottom -= ICON_TOP_PADDING + infoPtr->iconSize.cy + ICON_BOTTOM_PADDING; + + /* now figure out the flags */ + if (uView == LVS_ICON) + uFormat = oversizedBox ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS; + else + uFormat = LV_SL_DT_FLAGS; + + DrawTextW (hdc, lpLVItem->pszText, -1, &rcText, uFormat | DT_CALCRECT); + + labelSize.cx = min(rcText.right - rcText.left + TRAILING_LABEL_PADDING, infoPtr->nItemWidth); + labelSize.cy = rcText.bottom - rcText.top; + + SelectObject(hdc, hOldFont); + ReleaseDC(infoPtr->hwndSelf, hdc); + } + +calc_label: + if (uView == LVS_ICON) + { + Label.left = Box.left + (infoPtr->nItemWidth - labelSize.cx) / 2; + Label.top = Box.top + ICON_TOP_PADDING_HITABLE + + infoPtr->iconSize.cy + ICON_BOTTOM_PADDING; + Label.right = Label.left + labelSize.cx; + Label.bottom = Label.top + infoPtr->nItemHeight; + if (!oversizedBox && labelSize.cy > infoPtr->ntmHeight && + infoPtr->ntmHeight) + { + labelSize.cy = min(Box.bottom - Label.top, labelSize.cy); + labelSize.cy /= infoPtr->ntmHeight; + labelSize.cy = max(labelSize.cy, 1); + labelSize.cy *= infoPtr->ntmHeight; + } + Label.bottom = Label.top + labelSize.cy + HEIGHT_PADDING; + } + else /* LVS_SMALLICON, LVS_LIST or LVS_REPORT */ + { + Label.left = Icon.right; + Label.top = Box.top; + Label.right = min(Label.left + labelSize.cx, Label.right); + Label.bottom = Label.top + infoPtr->nItemHeight; + } + + if (lprcLabel) *lprcLabel = Label; + TRACE(" - label=%s\n", debugrect(&Label)); + } + + /* Fix the Box if necessary */ + if (lprcBox) + { + if (oversizedBox) UnionRect(lprcBox, &Box, &Label); + else *lprcBox = Box; + } + TRACE(" - box=%s\n", debugrect(&Box)); +} + +/*** + * DESCRIPTION: [INTERNAL] + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nItem : item number + * [O] lprcBox : ptr to Box rectangle + * + * RETURN: + * None. + */ +static void LISTVIEW_GetItemBox(LISTVIEW_INFO *infoPtr, INT nItem, LPRECT lprcBox) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' }; + POINT Position, Origin; + LVITEMW lvItem; + + LISTVIEW_GetOrigin(infoPtr, &Origin); + LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position); + + /* Be smart and try to figure out the minimum we have to do */ + lvItem.mask = 0; + if (uView == LVS_ICON && infoPtr->bFocus && LISTVIEW_GetItemState(infoPtr, nItem, LVIS_FOCUSED)) + lvItem.mask |= LVIF_TEXT; + lvItem.iItem = nItem; + lvItem.iSubItem = 0; + lvItem.pszText = szDispText; + lvItem.cchTextMax = DISP_TEXT_SIZE; + if (lvItem.mask) LISTVIEW_GetItemW(infoPtr, &lvItem); + if (uView == LVS_ICON) + { + lvItem.mask |= LVIF_STATE; + lvItem.stateMask = LVIS_FOCUSED; + lvItem.state = (lvItem.mask & LVIF_TEXT ? LVIS_FOCUSED : 0); + } + LISTVIEW_GetItemMetrics(infoPtr, &lvItem, lprcBox, 0, 0, 0); + + OffsetRect(lprcBox, Position.x + Origin.x, Position.y + Origin.y); +} + + +/*** + * DESCRIPTION: + * Returns the current icon position, and advances it along the top. + * The returned position is not offset by Origin. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [O] lpPos : will get the current icon position + * + * RETURN: + * None + */ +static void LISTVIEW_NextIconPosTop(LISTVIEW_INFO *infoPtr, LPPOINT lpPos) +{ + INT nListWidth = infoPtr->rcList.right - infoPtr->rcList.left; + + *lpPos = infoPtr->currIconPos; + + infoPtr->currIconPos.x += infoPtr->nItemWidth; + if (infoPtr->currIconPos.x + infoPtr->nItemWidth <= nListWidth) return; + + infoPtr->currIconPos.x = 0; + infoPtr->currIconPos.y += infoPtr->nItemHeight; +} + + +/*** + * DESCRIPTION: + * Returns the current icon position, and advances it down the left edge. + * The returned position is not offset by Origin. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [O] lpPos : will get the current icon position + * + * RETURN: + * None + */ +static void LISTVIEW_NextIconPosLeft(LISTVIEW_INFO *infoPtr, LPPOINT lpPos) +{ + INT nListHeight = infoPtr->rcList.bottom - infoPtr->rcList.top; + + *lpPos = infoPtr->currIconPos; + + infoPtr->currIconPos.y += infoPtr->nItemHeight; + if (infoPtr->currIconPos.y + infoPtr->nItemHeight <= nListHeight) return; + + infoPtr->currIconPos.x += infoPtr->nItemWidth; + infoPtr->currIconPos.y = 0; +} + + +/*** + * DESCRIPTION: + * Moves an icon to the specified position. + * It takes care of invalidating the item, etc. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nItem : the item to move + * [I] lpPos : the new icon position + * [I] isNew : flags the item as being new + * + * RETURN: + * Success: TRUE + * Failure: FALSE + */ +static BOOL LISTVIEW_MoveIconTo(LISTVIEW_INFO *infoPtr, INT nItem, const POINT *lppt, BOOL isNew) +{ + POINT old; + + if (!isNew) + { + old.x = (LONG)DPA_GetPtr(infoPtr->hdpaPosX, nItem); + old.y = (LONG)DPA_GetPtr(infoPtr->hdpaPosY, nItem); + + if (lppt->x == old.x && lppt->y == old.y) return TRUE; + LISTVIEW_InvalidateItem(infoPtr, nItem); + } + + /* Allocating a POINTER for every item is too resource intensive, + * so we'll keep the (x,y) in different arrays */ + if (!DPA_SetPtr(infoPtr->hdpaPosX, nItem, (void *)lppt->x)) return FALSE; + if (!DPA_SetPtr(infoPtr->hdpaPosY, nItem, (void *)lppt->y)) return FALSE; + + LISTVIEW_InvalidateItem(infoPtr, nItem); + + return TRUE; +} + +/*** + * DESCRIPTION: + * Arranges listview items in icon display mode. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nAlignCode : alignment code + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_Arrange(LISTVIEW_INFO *infoPtr, INT nAlignCode) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + void (*next_pos)(LISTVIEW_INFO *, LPPOINT); + POINT pos; + INT i; + + if (uView != LVS_ICON && uView != LVS_SMALLICON) return FALSE; + + TRACE("nAlignCode=%d\n", nAlignCode); + + if (nAlignCode == LVA_DEFAULT) + { + if (infoPtr->dwStyle & LVS_ALIGNLEFT) nAlignCode = LVA_ALIGNLEFT; + else nAlignCode = LVA_ALIGNTOP; + } + + switch (nAlignCode) + { + case LVA_ALIGNLEFT: next_pos = LISTVIEW_NextIconPosLeft; break; + case LVA_ALIGNTOP: next_pos = LISTVIEW_NextIconPosTop; break; + case LVA_SNAPTOGRID: next_pos = LISTVIEW_NextIconPosTop; break; /* FIXME */ + default: return FALSE; + } + + infoPtr->bAutoarrange = TRUE; + infoPtr->currIconPos.x = infoPtr->currIconPos.y = 0; + for (i = 0; i < infoPtr->nItemCount; i++) + { + next_pos(infoPtr, &pos); + LISTVIEW_MoveIconTo(infoPtr, i, &pos, FALSE); + } + + return TRUE; +} + +/*** + * DESCRIPTION: + * Retrieves the bounding rectangle of all the items, not offset by Origin. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [O] lprcView : bounding rectangle + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static void LISTVIEW_GetAreaRect(LISTVIEW_INFO *infoPtr, LPRECT lprcView) +{ + INT i, x, y; + + SetRectEmpty(lprcView); + + switch (infoPtr->dwStyle & LVS_TYPEMASK) + { + case LVS_ICON: + case LVS_SMALLICON: + for (i = 0; i < infoPtr->nItemCount; i++) + { + x = (LONG)DPA_GetPtr(infoPtr->hdpaPosX, i); + y = (LONG)DPA_GetPtr(infoPtr->hdpaPosY, i); + lprcView->right = max(lprcView->right, x); + lprcView->bottom = max(lprcView->bottom, y); + } + if (infoPtr->nItemCount > 0) + { + lprcView->right += infoPtr->nItemWidth; + lprcView->bottom += infoPtr->nItemHeight; + } + break; + + case LVS_LIST: + y = LISTVIEW_GetCountPerColumn(infoPtr); + x = infoPtr->nItemCount / y; + if (infoPtr->nItemCount % y) x++; + lprcView->right = x * infoPtr->nItemWidth; + lprcView->bottom = y * infoPtr->nItemHeight; + break; + + case LVS_REPORT: + lprcView->right = infoPtr->nItemWidth; + lprcView->bottom = infoPtr->nItemCount * infoPtr->nItemHeight; + break; + } +} + +/*** + * DESCRIPTION: + * Retrieves the bounding rectangle of all the items. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [O] lprcView : bounding rectangle + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_GetViewRect(LISTVIEW_INFO *infoPtr, LPRECT lprcView) +{ + POINT ptOrigin; + + TRACE("(lprcView=%p)\n", lprcView); + + if (!lprcView) return FALSE; + + LISTVIEW_GetOrigin(infoPtr, &ptOrigin); + LISTVIEW_GetAreaRect(infoPtr, lprcView); + OffsetRect(lprcView, ptOrigin.x, ptOrigin.y); + + TRACE("lprcView=%s\n", debugrect(lprcView)); + + return TRUE; +} + +/*** + * DESCRIPTION: + * Retrieves the subitem pointer associated with the subitem index. + * + * PARAMETER(S): + * [I] hdpaSubItems : DPA handle for a specific item + * [I] nSubItem : index of subitem + * + * RETURN: + * SUCCESS : subitem pointer + * FAILURE : NULL + */ +static SUBITEM_INFO* LISTVIEW_GetSubItemPtr(HDPA hdpaSubItems, INT nSubItem) +{ + SUBITEM_INFO *lpSubItem; + INT i; + + /* we should binary search here if need be */ + for (i = 1; i < DPA_GetPtrCount(hdpaSubItems); i++) + { + lpSubItem = (SUBITEM_INFO *)DPA_GetPtr(hdpaSubItems, i); + if (lpSubItem->iSubItem == nSubItem) + return lpSubItem; + } + + return NULL; +} + + +/*** + * DESCRIPTION: + * Caclulates the desired item width. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * + * RETURN: + * The desired item width. + */ +static INT LISTVIEW_CalculateItemWidth(LISTVIEW_INFO *infoPtr) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + INT nItemWidth = 0; + + TRACE("uView=%d\n", uView); + + if (uView == LVS_ICON) + nItemWidth = infoPtr->iconSpacing.cx; + else if (uView == LVS_REPORT) + { + RECT rcHeader; + + if (DPA_GetPtrCount(infoPtr->hdpaColumns) > 0) + { + LISTVIEW_GetHeaderRect(infoPtr, DPA_GetPtrCount(infoPtr->hdpaColumns) - 1, &rcHeader); + nItemWidth = rcHeader.right; + } + } + else /* LVS_SMALLICON, or LVS_LIST */ + { + INT i; + + for (i = 0; i < infoPtr->nItemCount; i++) + nItemWidth = max(LISTVIEW_GetLabelWidth(infoPtr, i), nItemWidth); + + if (infoPtr->himlSmall) nItemWidth += infoPtr->iconSize.cx; + if (infoPtr->himlState) nItemWidth += infoPtr->iconStateSize.cx; + + nItemWidth = max(DEFAULT_COLUMN_WIDTH, nItemWidth + WIDTH_PADDING); + } + + return max(nItemWidth, 1); +} + +/*** + * DESCRIPTION: + * Caclulates the desired item height. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * + * RETURN: + * The desired item height. + */ +static INT LISTVIEW_CalculateItemHeight(LISTVIEW_INFO *infoPtr) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + INT nItemHeight; + + TRACE("uView=%d\n", uView); + + if (uView == LVS_ICON) + nItemHeight = infoPtr->iconSpacing.cy; + else + { + nItemHeight = infoPtr->ntmHeight; + if (infoPtr->himlState) + nItemHeight = max(nItemHeight, infoPtr->iconStateSize.cy); + if (infoPtr->himlSmall) + nItemHeight = max(nItemHeight, infoPtr->iconSize.cy); + if (infoPtr->himlState || infoPtr->himlSmall) + nItemHeight += HEIGHT_PADDING; + if (infoPtr->nMeasureItemHeight > 0) + nItemHeight = infoPtr->nMeasureItemHeight; + } + + return max(nItemHeight, 1); +} + +/*** + * DESCRIPTION: + * Updates the width, and height of an item. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * + * RETURN: + * None. + */ +static inline void LISTVIEW_UpdateItemSize(LISTVIEW_INFO *infoPtr) +{ + infoPtr->nItemWidth = LISTVIEW_CalculateItemWidth(infoPtr); + infoPtr->nItemHeight = LISTVIEW_CalculateItemHeight(infoPtr); +} + + +/*** + * DESCRIPTION: + * Retrieves and saves important text metrics info for the current + * Listview font. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * + */ +static void LISTVIEW_SaveTextMetrics(LISTVIEW_INFO *infoPtr) +{ + HDC hdc = GetDC(infoPtr->hwndSelf); + HFONT hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont; + HFONT hOldFont = SelectObject(hdc, hFont); + TEXTMETRICW tm; + SIZE sz; + + if (GetTextMetricsW(hdc, &tm)) + { + infoPtr->ntmHeight = tm.tmHeight; + infoPtr->ntmMaxCharWidth = tm.tmMaxCharWidth; + } + + if (GetTextExtentPoint32A(hdc, "...", 3, &sz)) + infoPtr->nEllipsisWidth = sz.cx; + + SelectObject(hdc, hOldFont); + ReleaseDC(infoPtr->hwndSelf, hdc); + + TRACE("tmHeight=%d\n", infoPtr->ntmHeight); +} + +/*** + * DESCRIPTION: + * A compare function for ranges + * + * PARAMETER(S) + * [I] range1 : pointer to range 1; + * [I] range2 : pointer to range 2; + * [I] flags : flags + * + * RETURNS: + * > 0 : if range 1 > range 2 + * < 0 : if range 2 > range 1 + * = 0 : if range intersects range 2 + */ +static INT CALLBACK ranges_cmp(LPVOID range1, LPVOID range2, LPARAM flags) +{ + INT cmp; + + if (((RANGE*)range1)->upper <= ((RANGE*)range2)->lower) + cmp = -1; + else if (((RANGE*)range2)->upper <= ((RANGE*)range1)->lower) + cmp = 1; + else + cmp = 0; + + TRACE("range1=%s, range2=%s, cmp=%d\n", debugrange((RANGE*)range1), debugrange((RANGE*)range2), cmp); + + return cmp; +} + +#if DEBUG_RANGES +#define ranges_check(ranges, desc) ranges_assert(ranges, desc, __FUNCTION__, __LINE__) +#else +#define ranges_check(ranges, desc) do { } while(0) +#endif + +static void ranges_assert(RANGES ranges, LPCSTR desc, const char *func, int line) +{ + INT i; + RANGE *prev, *curr; + + TRACE("*** Checking %s:%d:%s ***\n", func, line, desc); + assert (ranges); + assert (DPA_GetPtrCount(ranges->hdpa) >= 0); + ranges_dump(ranges); + prev = (RANGE *)DPA_GetPtr(ranges->hdpa, 0); + if (DPA_GetPtrCount(ranges->hdpa) > 0) + assert (prev->lower >= 0 && prev->lower < prev->upper); + for (i = 1; i < DPA_GetPtrCount(ranges->hdpa); i++) + { + curr = (RANGE *)DPA_GetPtr(ranges->hdpa, i); + assert (prev->upper <= curr->lower); + assert (curr->lower < curr->upper); + prev = curr; + } + TRACE("--- Done checking---\n"); +} + +static RANGES ranges_create(int count) +{ + RANGES ranges = (RANGES)Alloc(sizeof(struct tagRANGES)); + if (!ranges) return NULL; + ranges->hdpa = DPA_Create(count); + if (ranges->hdpa) return ranges; + Free(ranges); + return NULL; +} + +static void ranges_clear(RANGES ranges) +{ + INT i; + + for(i = 0; i < DPA_GetPtrCount(ranges->hdpa); i++) + Free(DPA_GetPtr(ranges->hdpa, i)); + DPA_DeleteAllPtrs(ranges->hdpa); +} + + +static void ranges_destroy(RANGES ranges) +{ + if (!ranges) return; + ranges_clear(ranges); + DPA_Destroy(ranges->hdpa); + Free(ranges); +} + +static RANGES ranges_clone(RANGES ranges) +{ + RANGES clone; + INT i; + + if (!(clone = ranges_create(DPA_GetPtrCount(ranges->hdpa)))) goto fail; + + for (i = 0; i < DPA_GetPtrCount(ranges->hdpa); i++) + { + RANGE *newrng = (RANGE *)Alloc(sizeof(RANGE)); + if (!newrng) goto fail; + *newrng = *((RANGE*)DPA_GetPtr(ranges->hdpa, i)); + DPA_SetPtr(clone->hdpa, i, newrng); + } + return clone; + +fail: + TRACE ("clone failed\n"); + ranges_destroy(clone); + return NULL; +} + +static RANGES ranges_diff(RANGES ranges, RANGES sub) +{ + INT i; + + for (i = 0; i < DPA_GetPtrCount(sub->hdpa); i++) + ranges_del(ranges, *((RANGE *)DPA_GetPtr(sub->hdpa, i))); + + return ranges; +} + +static void ranges_dump(RANGES ranges) +{ + INT i; + + for (i = 0; i < DPA_GetPtrCount(ranges->hdpa); i++) + TRACE(" %s\n", debugrange(DPA_GetPtr(ranges->hdpa, i))); +} + +static inline BOOL ranges_contain(RANGES ranges, INT nItem) +{ + RANGE srchrng = { nItem, nItem + 1 }; + + TRACE("(nItem=%d)\n", nItem); + ranges_check(ranges, "before contain"); + return DPA_Search(ranges->hdpa, &srchrng, 0, ranges_cmp, 0, DPAS_SORTED) != -1; +} + +static INT ranges_itemcount(RANGES ranges) +{ + INT i, count = 0; + + for (i = 0; i < DPA_GetPtrCount(ranges->hdpa); i++) + { + RANGE *sel = DPA_GetPtr(ranges->hdpa, i); + count += sel->upper - sel->lower; + } + + return count; +} + +static BOOL ranges_shift(RANGES ranges, INT nItem, INT delta, INT nUpper) +{ + RANGE srchrng = { nItem, nItem + 1 }, *chkrng; + INT index; + + index = DPA_Search(ranges->hdpa, &srchrng, 0, ranges_cmp, 0, DPAS_SORTED | DPAS_INSERTAFTER); + if (index == -1) return TRUE; + + for (; index < DPA_GetPtrCount(ranges->hdpa); index++) + { + chkrng = DPA_GetPtr(ranges->hdpa, index); + if (chkrng->lower >= nItem) + chkrng->lower = max(min(chkrng->lower + delta, nUpper - 1), 0); + if (chkrng->upper > nItem) + chkrng->upper = max(min(chkrng->upper + delta, nUpper), 0); + } + return TRUE; +} + +static BOOL ranges_add(RANGES ranges, RANGE range) +{ + RANGE srchrgn; + INT index; + + TRACE("(%s)\n", debugrange(&range)); + ranges_check(ranges, "before add"); + + /* try find overlapping regions first */ + srchrgn.lower = range.lower - 1; + srchrgn.upper = range.upper + 1; + index = DPA_Search(ranges->hdpa, &srchrgn, 0, ranges_cmp, 0, DPAS_SORTED); + + if (index == -1) + { + RANGE *newrgn; + + TRACE("Adding new range\n"); + + /* create the brand new range to insert */ + newrgn = (RANGE *)Alloc(sizeof(RANGE)); + if(!newrgn) goto fail; + *newrgn = range; + + /* figure out where to insert it */ + index = DPA_Search(ranges->hdpa, newrgn, 0, ranges_cmp, 0, DPAS_SORTED | DPAS_INSERTAFTER); + TRACE("index=%d\n", index); + if (index == -1) index = 0; + + /* and get it over with */ + if (DPA_InsertPtr(ranges->hdpa, index, newrgn) == -1) + { + Free(newrgn); + goto fail; + } + } + else + { + RANGE *chkrgn, *mrgrgn; + INT fromindex, mergeindex; + + chkrgn = DPA_GetPtr(ranges->hdpa, index); + TRACE("Merge with %s @%d\n", debugrange(chkrgn), index); + + chkrgn->lower = min(range.lower, chkrgn->lower); + chkrgn->upper = max(range.upper, chkrgn->upper); + + TRACE("New range %s @%d\n", debugrange(chkrgn), index); + + /* merge now common anges */ + fromindex = 0; + srchrgn.lower = chkrgn->lower - 1; + srchrgn.upper = chkrgn->upper + 1; + + do + { + mergeindex = DPA_Search(ranges->hdpa, &srchrgn, fromindex, ranges_cmp, 0, 0); + if (mergeindex == -1) break; + if (mergeindex == index) + { + fromindex = index + 1; + continue; + } + + TRACE("Merge with index %i\n", mergeindex); + + mrgrgn = DPA_GetPtr(ranges->hdpa, mergeindex); + chkrgn->lower = min(chkrgn->lower, mrgrgn->lower); + chkrgn->upper = max(chkrgn->upper, mrgrgn->upper); + Free(mrgrgn); + DPA_DeletePtr(ranges->hdpa, mergeindex); + if (mergeindex < index) index --; + } while(1); + } + + ranges_check(ranges, "after add"); + return TRUE; + +fail: + ranges_check(ranges, "failed add"); + return FALSE; +} + +static BOOL ranges_del(RANGES ranges, RANGE range) +{ + RANGE *chkrgn; + INT index; + + TRACE("(%s)\n", debugrange(&range)); + ranges_check(ranges, "before del"); + + /* we don't use DPAS_SORTED here, since we need * + * to find the first overlapping range */ + index = DPA_Search(ranges->hdpa, &range, 0, ranges_cmp, 0, 0); + while(index != -1) + { + chkrgn = DPA_GetPtr(ranges->hdpa, index); + + TRACE("Matches range %s @%d\n", debugrange(chkrgn), index); + + /* case 1: Same range */ + if ( (chkrgn->upper == range.upper) && + (chkrgn->lower == range.lower) ) + { + DPA_DeletePtr(ranges->hdpa, index); + break; + } + /* case 2: engulf */ + else if ( (chkrgn->upper <= range.upper) && + (chkrgn->lower >= range.lower) ) + { + DPA_DeletePtr(ranges->hdpa, index); + } + /* case 3: overlap upper */ + else if ( (chkrgn->upper <= range.upper) && + (chkrgn->lower < range.lower) ) + { + chkrgn->upper = range.lower; + } + /* case 4: overlap lower */ + else if ( (chkrgn->upper > range.upper) && + (chkrgn->lower >= range.lower) ) + { + chkrgn->lower = range.upper; + break; + } + /* case 5: fully internal */ + else + { + RANGE tmprgn = *chkrgn, *newrgn; + + if (!(newrgn = (RANGE *)Alloc(sizeof(RANGE)))) goto fail; + newrgn->lower = chkrgn->lower; + newrgn->upper = range.lower; + chkrgn->lower = range.upper; + if (DPA_InsertPtr(ranges->hdpa, index, newrgn) == -1) + { + Free(newrgn); + goto fail; + } + chkrgn = &tmprgn; + break; + } + + index = DPA_Search(ranges->hdpa, &range, index, ranges_cmp, 0, 0); + } + + ranges_check(ranges, "after del"); + return TRUE; + +fail: + ranges_check(ranges, "failed del"); + return FALSE; +} + +/*** +* DESCRIPTION: +* Removes all selection ranges +* +* Parameters(s): +* [I] infoPtr : valid pointer to the listview structure +* [I] toSkip : item range to skip removing the selection +* +* RETURNS: +* SUCCESS : TRUE +* FAILURE : TRUE +*/ +static BOOL LISTVIEW_DeselectAllSkipItems(LISTVIEW_INFO *infoPtr, RANGES toSkip) +{ + LVITEMW lvItem; + ITERATOR i; + RANGES clone; + + TRACE("()\n"); + + lvItem.state = 0; + lvItem.stateMask = LVIS_SELECTED; + + /* need to clone the DPA because callbacks can change it */ + if (!(clone = ranges_clone(infoPtr->selectionRanges))) return FALSE; + iterator_rangesitems(&i, ranges_diff(clone, toSkip)); + while(iterator_next(&i)) + LISTVIEW_SetItemState(infoPtr, i.nItem, &lvItem); + /* note that the iterator destructor will free the cloned range */ + iterator_destroy(&i); + + return TRUE; +} + +static inline BOOL LISTVIEW_DeselectAllSkipItem(LISTVIEW_INFO *infoPtr, INT nItem) +{ + RANGES toSkip; + + if (!(toSkip = ranges_create(1))) return FALSE; + if (nItem != -1) ranges_additem(toSkip, nItem); + LISTVIEW_DeselectAllSkipItems(infoPtr, toSkip); + ranges_destroy(toSkip); + return TRUE; +} + +static inline BOOL LISTVIEW_DeselectAll(LISTVIEW_INFO *infoPtr) +{ + return LISTVIEW_DeselectAllSkipItem(infoPtr, -1); +} + +/*** + * DESCRIPTION: + * Retrieves the number of items that are marked as selected. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * + * RETURN: + * Number of items selected. + */ +static INT LISTVIEW_GetSelectedCount(LISTVIEW_INFO *infoPtr) +{ + INT nSelectedCount = 0; + + if (infoPtr->uCallbackMask & LVIS_SELECTED) + { + INT i; + for (i = 0; i < infoPtr->nItemCount; i++) + { + if (LISTVIEW_GetItemState(infoPtr, i, LVIS_SELECTED)) + nSelectedCount++; + } + } + else + nSelectedCount = ranges_itemcount(infoPtr->selectionRanges); + + TRACE("nSelectedCount=%d\n", nSelectedCount); + return nSelectedCount; +} + +/*** + * DESCRIPTION: + * Manages the item focus. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nItem : item index + * + * RETURN: + * TRUE : focused item changed + * FALSE : focused item has NOT changed + */ +static inline BOOL LISTVIEW_SetItemFocus(LISTVIEW_INFO *infoPtr, INT nItem) +{ + INT oldFocus = infoPtr->nFocusedItem; + LVITEMW lvItem; + + if (nItem == infoPtr->nFocusedItem) return FALSE; + + lvItem.state = nItem == -1 ? 0 : LVIS_FOCUSED; + lvItem.stateMask = LVIS_FOCUSED; + LISTVIEW_SetItemState(infoPtr, nItem == -1 ? infoPtr->nFocusedItem : nItem, &lvItem); + + return oldFocus != infoPtr->nFocusedItem; +} + +/* Helper function for LISTVIEW_ShiftIndices *only* */ +static INT shift_item(LISTVIEW_INFO *infoPtr, INT nShiftItem, INT nItem, INT direction) +{ + if (nShiftItem < nItem) return nShiftItem; + + if (nShiftItem > nItem) return nShiftItem + direction; + + if (direction > 0) return nShiftItem + direction; + + return min(nShiftItem, infoPtr->nItemCount - 1); +} + +/** +* DESCRIPTION: +* Updates the various indices after an item has been inserted or deleted. +* +* PARAMETER(S): +* [I] infoPtr : valid pointer to the listview structure +* [I] nItem : item index +* [I] direction : Direction of shift, +1 or -1. +* +* RETURN: +* None +*/ +static void LISTVIEW_ShiftIndices(LISTVIEW_INFO *infoPtr, INT nItem, INT direction) +{ + INT nNewFocus; + BOOL bOldChange; + + /* temporarily disable change notification while shifting items */ + bOldChange = infoPtr->bDoChangeNotify; + infoPtr->bDoChangeNotify = FALSE; + + TRACE("Shifting %iu, %i steps\n", nItem, direction); + + ranges_shift(infoPtr->selectionRanges, nItem, direction, infoPtr->nItemCount); + + assert(abs(direction) == 1); + + infoPtr->nSelectionMark = shift_item(infoPtr, infoPtr->nSelectionMark, nItem, direction); + + nNewFocus = shift_item(infoPtr, infoPtr->nFocusedItem, nItem, direction); + if (nNewFocus != infoPtr->nFocusedItem) + LISTVIEW_SetItemFocus(infoPtr, nNewFocus); + + /* But we are not supposed to modify nHotItem! */ + + infoPtr->bDoChangeNotify = bOldChange; +} + + +/** + * DESCRIPTION: + * Adds a block of selections. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nItem : item index + * + * RETURN: + * None + */ +static void LISTVIEW_AddGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem) +{ + INT nFirst = min(infoPtr->nSelectionMark, nItem); + INT nLast = max(infoPtr->nSelectionMark, nItem); + NMLVODSTATECHANGE nmlv; + LVITEMW item; + BOOL bOldChange; + INT i; + + /* Temporarily disable change notification + * If the control is LVS_OWNERDATA, we need to send + * only one LVN_ODSTATECHANGED notification. + * See MSDN documentation for LVN_ITEMCHANGED. + */ + bOldChange = infoPtr->bDoChangeNotify; + if (infoPtr->dwStyle & LVS_OWNERDATA) infoPtr->bDoChangeNotify = FALSE; + + if (nFirst == -1) nFirst = nItem; + + item.state = LVIS_SELECTED; + item.stateMask = LVIS_SELECTED; + + for (i = nFirst; i <= nLast; i++) + LISTVIEW_SetItemState(infoPtr,i,&item); + + ZeroMemory(&nmlv, sizeof(nmlv)); + nmlv.iFrom = nFirst; + nmlv.iTo = nLast; + nmlv.uNewState = 0; + nmlv.uOldState = item.state; + + notify_hdr(infoPtr, LVN_ODSTATECHANGED, (LPNMHDR)&nmlv); + infoPtr->bDoChangeNotify = bOldChange; +} + + +/*** + * DESCRIPTION: + * Sets a single group selection. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nItem : item index + * + * RETURN: + * None + */ +static void LISTVIEW_SetGroupSelection(LISTVIEW_INFO *infoPtr, INT nItem) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + RANGES selection; + LVITEMW item; + ITERATOR i; + + if (!(selection = ranges_create(100))) return; + + item.state = LVIS_SELECTED; + item.stateMask = LVIS_SELECTED; + + if ((uView == LVS_LIST) || (uView == LVS_REPORT)) + { + if (infoPtr->nSelectionMark == -1) + { + infoPtr->nSelectionMark = nItem; + ranges_additem(selection, nItem); + } + else + { + RANGE sel; + + sel.lower = min(infoPtr->nSelectionMark, nItem); + sel.upper = max(infoPtr->nSelectionMark, nItem) + 1; + ranges_add(selection, sel); + } + } + else + { + RECT rcItem, rcSel, rcSelMark; + POINT ptItem; + + rcItem.left = LVIR_BOUNDS; + if (!LISTVIEW_GetItemRect(infoPtr, nItem, &rcItem)) return; + rcSelMark.left = LVIR_BOUNDS; + if (!LISTVIEW_GetItemRect(infoPtr, infoPtr->nSelectionMark, &rcSelMark)) return; + UnionRect(&rcSel, &rcItem, &rcSelMark); + iterator_frameditems(&i, infoPtr, &rcSel); + while(iterator_next(&i)) + { + LISTVIEW_GetItemPosition(infoPtr, i.nItem, &ptItem); + if (PtInRect(&rcSel, ptItem)) ranges_additem(selection, i.nItem); + } + iterator_destroy(&i); + } + + LISTVIEW_DeselectAllSkipItems(infoPtr, selection); + iterator_rangesitems(&i, selection); + while(iterator_next(&i)) + LISTVIEW_SetItemState(infoPtr, i.nItem, &item); + /* this will also destroy the selection */ + iterator_destroy(&i); + + LISTVIEW_SetItemFocus(infoPtr, nItem); +} + +/*** + * DESCRIPTION: + * Sets a single selection. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nItem : item index + * + * RETURN: + * None + */ +static void LISTVIEW_SetSelection(LISTVIEW_INFO *infoPtr, INT nItem) +{ + LVITEMW lvItem; + + TRACE("nItem=%d\n", nItem); + + LISTVIEW_DeselectAllSkipItem(infoPtr, nItem); + + lvItem.state = LVIS_FOCUSED | LVIS_SELECTED; + lvItem.stateMask = LVIS_FOCUSED | LVIS_SELECTED; + LISTVIEW_SetItemState(infoPtr, nItem, &lvItem); + + infoPtr->nSelectionMark = nItem; +} + +/*** + * DESCRIPTION: + * Set selection(s) with keyboard. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nItem : item index + * + * RETURN: + * SUCCESS : TRUE (needs to be repainted) + * FAILURE : FALSE (nothing has changed) + */ +static BOOL LISTVIEW_KeySelection(LISTVIEW_INFO *infoPtr, INT nItem) +{ + /* FIXME: pass in the state */ + WORD wShift = HIWORD(GetKeyState(VK_SHIFT)); + WORD wCtrl = HIWORD(GetKeyState(VK_CONTROL)); + BOOL bResult = FALSE; + + if ((nItem >= 0) && (nItem < infoPtr->nItemCount)) + { + if (infoPtr->dwStyle & LVS_SINGLESEL) + { + bResult = TRUE; + LISTVIEW_SetSelection(infoPtr, nItem); + } + else + { + if (wShift) + { + bResult = TRUE; + LISTVIEW_SetGroupSelection(infoPtr, nItem); + } + else if (wCtrl) + { + bResult = LISTVIEW_SetItemFocus(infoPtr, nItem); + } + else + { + bResult = TRUE; + LISTVIEW_SetSelection(infoPtr, nItem); + } + } + LISTVIEW_EnsureVisible(infoPtr, nItem, FALSE); + } + + UpdateWindow(infoPtr->hwndSelf); /* update client area */ + return bResult; +} + +static BOOL LISTVIEW_GetItemAtPt(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, POINT pt) +{ + LVHITTESTINFO lvHitTestInfo; + + ZeroMemory(&lvHitTestInfo, sizeof(lvHitTestInfo)); + lvHitTestInfo.pt.x = pt.x; + lvHitTestInfo.pt.y = pt.y; + + LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE); + + lpLVItem->mask = LVIF_PARAM; + lpLVItem->iItem = lvHitTestInfo.iItem; + lpLVItem->iSubItem = 0; + + return LISTVIEW_GetItemT(infoPtr, lpLVItem, TRUE); +} + +/*** + * DESCRIPTION: + * Called when the mouse is being actively tracked and has hovered for a specified + * amount of time + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] fwKeys : key indicator + * [I] x,y : mouse position + * + * RETURN: + * 0 if the message was processed, non-zero if there was an error + * + * INFO: + * LVS_EX_TRACKSELECT: An item is automatically selected when the cursor remains + * over the item for a certain period of time. + * + */ +static LRESULT LISTVIEW_MouseHover(LISTVIEW_INFO *infoPtr, WORD fwKyes, INT x, INT y) +{ + if (infoPtr->dwLvExStyle & LVS_EX_TRACKSELECT) + { + LVITEMW item; + POINT pt; + + pt.x = x; + pt.y = y; + + if (LISTVIEW_GetItemAtPt(infoPtr, &item, pt)) + LISTVIEW_SetSelection(infoPtr, item.iItem); + } + + return 0; +} + +/*** + * DESCRIPTION: + * Called whenever WM_MOUSEMOVE is received. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] fwKeys : key indicator + * [I] x,y : mouse position + * + * RETURN: + * 0 if the message is processed, non-zero if there was an error + */ +static LRESULT LISTVIEW_MouseMove(LISTVIEW_INFO *infoPtr, WORD fwKeys, INT x, INT y) +{ + TRACKMOUSEEVENT trackinfo; + + if (infoPtr->bLButtonDown && DragDetect(infoPtr->hwndSelf, infoPtr->ptClickPos)) + { + LVHITTESTINFO lvHitTestInfo; + NMLISTVIEW nmlv; + + lvHitTestInfo.pt = infoPtr->ptClickPos; + LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE); + + ZeroMemory(&nmlv, sizeof(nmlv)); + nmlv.iItem = lvHitTestInfo.iItem; + nmlv.ptAction = infoPtr->ptClickPos; + + notify_listview(infoPtr, LVN_BEGINDRAG, &nmlv); + + return 0; + } + + /* see if we are supposed to be tracking mouse hovering */ + if(infoPtr->dwLvExStyle & LVS_EX_TRACKSELECT) { + /* fill in the trackinfo struct */ + trackinfo.cbSize = sizeof(TRACKMOUSEEVENT); + trackinfo.dwFlags = TME_QUERY; + trackinfo.hwndTrack = infoPtr->hwndSelf; + trackinfo.dwHoverTime = infoPtr->dwHoverTime; + + /* see if we are already tracking this hwnd */ + _TrackMouseEvent(&trackinfo); + + if(!(trackinfo.dwFlags & TME_HOVER)) { + trackinfo.dwFlags = TME_HOVER; + + /* call TRACKMOUSEEVENT so we receive WM_MOUSEHOVER messages */ + _TrackMouseEvent(&trackinfo); + } + } + + return 0; +} + + +/*** + * Tests wheather the item is assignable to a list with style lStyle + */ +static inline BOOL is_assignable_item(const LVITEMW *lpLVItem, LONG lStyle) +{ + if ( (lpLVItem->mask & LVIF_TEXT) && + (lpLVItem->pszText == LPSTR_TEXTCALLBACKW) && + (lStyle & (LVS_SORTASCENDING | LVS_SORTDESCENDING)) ) return FALSE; + + return TRUE; +} + + +/*** + * DESCRIPTION: + * Helper for LISTVIEW_SetItemT *only*: sets item attributes. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] lpLVItem : valid pointer to new item atttributes + * [I] isNew : the item being set is being inserted + * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI + * [O] bChanged : will be set to TRUE if the item really changed + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL set_main_item(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isNew, BOOL isW, BOOL *bChanged) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + ITEM_INFO *lpItem; + NMLISTVIEW nmlv; + UINT uChanged = 0; + LVITEMW item; + + TRACE("()\n"); + + assert(lpLVItem->iItem >= 0 && lpLVItem->iItem < infoPtr->nItemCount); + + if (lpLVItem->mask == 0) return TRUE; + + if (infoPtr->dwStyle & LVS_OWNERDATA) + { + /* a virtual listview we stores only selection and focus */ + if (lpLVItem->mask & ~LVIF_STATE) + return FALSE; + lpItem = NULL; + } + else + { + HDPA hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem); + lpItem = (ITEM_INFO *)DPA_GetPtr(hdpaSubItems, 0); + assert (lpItem); + } + + /* we need to get the lParam and state of the item */ + item.iItem = lpLVItem->iItem; + item.iSubItem = lpLVItem->iSubItem; + item.mask = LVIF_STATE | LVIF_PARAM; + item.stateMask = ~0; + item.state = 0; + item.lParam = 0; + if (!isNew && !LISTVIEW_GetItemW(infoPtr, &item)) return FALSE; + + TRACE("oldState=%x, newState=%x\n", item.state, lpLVItem->state); + /* determine what fields will change */ + if ((lpLVItem->mask & LVIF_STATE) && ((item.state ^ lpLVItem->state) & lpLVItem->stateMask & ~infoPtr->uCallbackMask)) + uChanged |= LVIF_STATE; + + if ((lpLVItem->mask & LVIF_IMAGE) && (lpItem->hdr.iImage != lpLVItem->iImage)) + uChanged |= LVIF_IMAGE; + + if ((lpLVItem->mask & LVIF_PARAM) && (lpItem->lParam != lpLVItem->lParam)) + uChanged |= LVIF_PARAM; + + if ((lpLVItem->mask & LVIF_INDENT) && (lpItem->iIndent != lpLVItem->iIndent)) + uChanged |= LVIF_INDENT; + + if ((lpLVItem->mask & LVIF_TEXT) && textcmpWT(lpItem->hdr.pszText, lpLVItem->pszText, isW)) + uChanged |= LVIF_TEXT; + + TRACE("uChanged=0x%x\n", uChanged); + if (!uChanged) return TRUE; + *bChanged = TRUE; + + ZeroMemory(&nmlv, sizeof(NMLISTVIEW)); + nmlv.iItem = lpLVItem->iItem; + nmlv.uNewState = (item.state & ~lpLVItem->stateMask) | (lpLVItem->state & lpLVItem->stateMask); + nmlv.uOldState = item.state; + nmlv.uChanged = uChanged; + nmlv.lParam = item.lParam; + + /* send LVN_ITEMCHANGING notification, if the item is not being inserted */ + /* and we are _NOT_ virtual (LVS_OWERNDATA), and change notifications */ + /* are enabled */ + if(lpItem && !isNew && infoPtr->bDoChangeNotify && + notify_listview(infoPtr, LVN_ITEMCHANGING, &nmlv)) + return FALSE; + + /* copy information */ + if (lpLVItem->mask & LVIF_TEXT) + textsetptrT(&lpItem->hdr.pszText, lpLVItem->pszText, isW); + + if (lpLVItem->mask & LVIF_IMAGE) + lpItem->hdr.iImage = lpLVItem->iImage; + + if (lpLVItem->mask & LVIF_PARAM) + lpItem->lParam = lpLVItem->lParam; + + if (lpLVItem->mask & LVIF_INDENT) + lpItem->iIndent = lpLVItem->iIndent; + + if (uChanged & LVIF_STATE) + { + if (lpItem && (lpLVItem->stateMask & ~infoPtr->uCallbackMask & ~(LVIS_FOCUSED | LVIS_SELECTED))) + { + lpItem->state &= ~lpLVItem->stateMask; + lpItem->state |= (lpLVItem->state & lpLVItem->stateMask); + } + if (lpLVItem->state & lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED) + { + if (infoPtr->dwStyle & LVS_SINGLESEL) LISTVIEW_DeselectAllSkipItem(infoPtr, lpLVItem->iItem); + ranges_additem(infoPtr->selectionRanges, lpLVItem->iItem); + } + else if (lpLVItem->stateMask & LVIS_SELECTED) + ranges_delitem(infoPtr->selectionRanges, lpLVItem->iItem); + + /* if we are asked to change focus, and we manage it, do it */ + if (lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED) + { + if (lpLVItem->state & LVIS_FOCUSED) + { + LISTVIEW_SetItemFocus(infoPtr, -1); + infoPtr->nFocusedItem = lpLVItem->iItem; + LISTVIEW_EnsureVisible(infoPtr, lpLVItem->iItem, uView == LVS_LIST); + } + else if (infoPtr->nFocusedItem == lpLVItem->iItem) + infoPtr->nFocusedItem = -1; + } + } + + /* if we're inserting the item, we're done */ + if (isNew) return TRUE; + + /* send LVN_ITEMCHANGED notification */ + if (lpLVItem->mask & LVIF_PARAM) nmlv.lParam = lpLVItem->lParam; + if (infoPtr->bDoChangeNotify) notify_listview(infoPtr, LVN_ITEMCHANGED, &nmlv); + + return TRUE; +} + +/*** + * DESCRIPTION: + * Helper for LISTVIEW_{Set,Insert}ItemT *only*: sets subitem attributes. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] lpLVItem : valid pointer to new subitem atttributes + * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI + * [O] bChanged : will be set to TRUE if the item really changed + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL set_sub_item(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isW, BOOL *bChanged) +{ + HDPA hdpaSubItems; + SUBITEM_INFO *lpSubItem; + + /* we do not support subitems for virtual listviews */ + if (infoPtr->dwStyle & LVS_OWNERDATA) return FALSE; + + /* set subitem only if column is present */ + if (lpLVItem->iSubItem >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE; + + /* First do some sanity checks */ + if (lpLVItem->mask & ~(LVIF_TEXT | LVIF_IMAGE)) return FALSE; + if (!(lpLVItem->mask & (LVIF_TEXT | LVIF_IMAGE))) return TRUE; + + /* get the subitem structure, and create it if not there */ + hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem); + assert (hdpaSubItems); + + lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, lpLVItem->iSubItem); + if (!lpSubItem) + { + SUBITEM_INFO *tmpSubItem; + INT i; + + lpSubItem = (SUBITEM_INFO *)Alloc(sizeof(SUBITEM_INFO)); + if (!lpSubItem) return FALSE; + /* we could binary search here, if need be...*/ + for (i = 1; i < DPA_GetPtrCount(hdpaSubItems); i++) + { + tmpSubItem = (SUBITEM_INFO *)DPA_GetPtr(hdpaSubItems, i); + if (tmpSubItem->iSubItem > lpLVItem->iSubItem) break; + } + if (DPA_InsertPtr(hdpaSubItems, i, lpSubItem) == -1) + { + Free(lpSubItem); + return FALSE; + } + lpSubItem->iSubItem = lpLVItem->iSubItem; + lpSubItem->hdr.iImage = I_IMAGECALLBACK; + *bChanged = TRUE; + } + + if (lpLVItem->mask & LVIF_IMAGE) + if (lpSubItem->hdr.iImage != lpLVItem->iImage) + { + lpSubItem->hdr.iImage = lpLVItem->iImage; + *bChanged = TRUE; + } + + if (lpLVItem->mask & LVIF_TEXT) + if (lpSubItem->hdr.pszText != lpLVItem->pszText) + { + textsetptrT(&lpSubItem->hdr.pszText, lpLVItem->pszText, isW); + *bChanged = TRUE; + } + + return TRUE; +} + +/*** + * DESCRIPTION: + * Sets item attributes. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] lpLVItem : new item atttributes + * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_SetItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isW) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + LPWSTR pszText = NULL; + BOOL bResult, bChanged = FALSE; + + TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW); + + if (!lpLVItem || lpLVItem->iItem < 0 || lpLVItem->iItem >= infoPtr->nItemCount) + return FALSE; + + /* For efficiency, we transform the lpLVItem->pszText to Unicode here */ + if ((lpLVItem->mask & LVIF_TEXT) && is_textW(lpLVItem->pszText)) + { + pszText = lpLVItem->pszText; + ((LVITEMW *)lpLVItem)->pszText = textdupTtoW(lpLVItem->pszText, isW); + } + + /* actually set the fields */ + if (!is_assignable_item(lpLVItem, infoPtr->dwStyle)) return FALSE; + + if (lpLVItem->iSubItem) + bResult = set_sub_item(infoPtr, lpLVItem, TRUE, &bChanged); + else + bResult = set_main_item(infoPtr, lpLVItem, FALSE, TRUE, &bChanged); + + /* redraw item, if necessary */ + if (bChanged && !infoPtr->bIsDrawing) + { + /* this little optimization eliminates some nasty flicker */ + if ( uView == LVS_REPORT && !(infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && + (!(infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) || lpLVItem->iSubItem) ) + LISTVIEW_InvalidateSubItem(infoPtr, lpLVItem->iItem, lpLVItem->iSubItem); + else + LISTVIEW_InvalidateItem(infoPtr, lpLVItem->iItem); + } + /* restore text */ + if (pszText) + { + textfreeT(lpLVItem->pszText, isW); + ((LVITEMW *)lpLVItem)->pszText = pszText; + } + + return bResult; +} + +/*** + * DESCRIPTION: + * Retrieves the index of the item at coordinate (0, 0) of the client area. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * + * RETURN: + * item index + */ +static INT LISTVIEW_GetTopIndex(LISTVIEW_INFO *infoPtr) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + INT nItem = 0; + SCROLLINFO scrollInfo; + + scrollInfo.cbSize = sizeof(SCROLLINFO); + scrollInfo.fMask = SIF_POS; + + if (uView == LVS_LIST) + { + if (GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo)) + nItem = scrollInfo.nPos * LISTVIEW_GetCountPerColumn(infoPtr); + } + else if (uView == LVS_REPORT) + { + if (GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo)) + nItem = scrollInfo.nPos; + } + else + { + if (GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo)) + nItem = LISTVIEW_GetCountPerRow(infoPtr) * (scrollInfo.nPos / infoPtr->nItemHeight); + } + + TRACE("nItem=%d\n", nItem); + + return nItem; +} + + +/*** + * DESCRIPTION: + * Erases the background of the given rectangle + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] hdc : device context handle + * [I] lprcBox : clipping rectangle + * + * RETURN: + * Success: TRUE + * Failure: FALSE + */ +static inline BOOL LISTVIEW_FillBkgnd(LISTVIEW_INFO *infoPtr, HDC hdc, const RECT *lprcBox) +{ + if (!infoPtr->hBkBrush) return FALSE; + + TRACE("(hdc=%p, lprcBox=%s, hBkBrush=%p)\n", hdc, debugrect(lprcBox), infoPtr->hBkBrush); + + return FillRect(hdc, lprcBox, infoPtr->hBkBrush); +} + +/*** + * DESCRIPTION: + * Draws an item. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] hdc : device context handle + * [I] nItem : item index + * [I] nSubItem : subitem index + * [I] pos : item position in client coordinates + * [I] cdmode : custom draw mode + * + * RETURN: + * Success: TRUE + * Failure: FALSE + */ +static BOOL LISTVIEW_DrawItem(LISTVIEW_INFO *infoPtr, HDC hdc, INT nItem, INT nSubItem, POINT pos, DWORD cdmode) +{ + UINT uFormat, uView = infoPtr->dwStyle & LVS_TYPEMASK; + WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' }; + static const WCHAR szCallback[] = { '(', 'c', 'a', 'l', 'l', 'b', 'a', 'c', 'k', ')', 0 }; + DWORD cdsubitemmode = CDRF_DODEFAULT; + RECT* lprcFocus, rcSelect, rcBox, rcState, rcIcon, rcLabel; + NMLVCUSTOMDRAW nmlvcd; + HIMAGELIST himl; + LVITEMW lvItem; + + TRACE("(hdc=%p, nItem=%d, nSubItem=%d, pos=%s)\n", hdc, nItem, nSubItem, debugpoint(&pos)); + + /* get information needed for drawing the item */ + lvItem.mask = LVIF_TEXT | LVIF_IMAGE; + if (nSubItem == 0) lvItem.mask |= LVIF_STATE | LVIF_PARAM; + if (uView == LVS_REPORT) lvItem.mask |= LVIF_INDENT; + lvItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED | LVIS_STATEIMAGEMASK; + lvItem.iItem = nItem; + lvItem.iSubItem = nSubItem; + lvItem.state = 0; + lvItem.lParam = 0; + lvItem.cchTextMax = DISP_TEXT_SIZE; + lvItem.pszText = szDispText; + if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE; + if (nSubItem > 0 && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)) + lvItem.state = LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED); + if (lvItem.pszText == LPSTR_TEXTCALLBACKW) lvItem.pszText = (LPWSTR)szCallback; + TRACE(" lvItem=%s\n", debuglvitem_t(&lvItem, TRUE)); + + /* now check if we need to update the focus rectangle */ + lprcFocus = infoPtr->bFocus && (lvItem.state & LVIS_FOCUSED) ? &infoPtr->rcFocus : 0; + + if (!lprcFocus) lvItem.state &= ~LVIS_FOCUSED; + LISTVIEW_GetItemMetrics(infoPtr, &lvItem, &rcBox, &rcState, &rcIcon, &rcLabel); + OffsetRect(&rcBox, pos.x, pos.y); + OffsetRect(&rcState, pos.x, pos.y); + OffsetRect(&rcIcon, pos.x, pos.y); + OffsetRect(&rcLabel, pos.x, pos.y); + TRACE(" rcBox=%s, rcState=%s, rcIcon=%s. rcLabel=%s\n", + debugrect(&rcBox), debugrect(&rcState), debugrect(&rcIcon), debugrect(&rcLabel)); + + /* fill in the custom draw structure */ + customdraw_fill(&nmlvcd, infoPtr, hdc, &rcBox, &lvItem); + + if (nSubItem > 0) cdmode = infoPtr->cditemmode; + if (cdmode & CDRF_NOTIFYITEMDRAW) + cdsubitemmode = notify_customdraw(infoPtr, CDDS_PREPAINT, &nmlvcd); + if (nSubItem == 0) infoPtr->cditemmode = cdsubitemmode; + if (cdsubitemmode & CDRF_SKIPDEFAULT) goto postpaint; + /* we have to send a CDDS_SUBITEM customdraw explicitly for subitem 0 */ + if (nSubItem == 0 && cdsubitemmode == CDRF_NOTIFYITEMDRAW) + { + cdsubitemmode = notify_customdraw(infoPtr, CDDS_SUBITEM | CDDS_ITEMPREPAINT, &nmlvcd); + if (cdsubitemmode & CDRF_SKIPDEFAULT) goto postpaint; + } + if (nSubItem == 0 || (cdmode & CDRF_NOTIFYITEMDRAW)) + prepaint_setup(infoPtr, hdc, &nmlvcd); + + /* in full row select, subitems, will just use main item's colors */ + if (nSubItem && uView == LVS_REPORT && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)) + nmlvcd.clrTextBk = CLR_NONE; + + /* state icons */ + if (infoPtr->himlState && !IsRectEmpty(&rcState)) + { + UINT uStateImage = (lvItem.state & LVIS_STATEIMAGEMASK) >> 12; + if (uStateImage) + { + TRACE("uStateImage=%d\n", uStateImage); + ImageList_Draw(infoPtr->himlState, uStateImage - 1, hdc, rcState.left, rcState.top, ILD_NORMAL); + } + } + + /* small icons */ + himl = (uView == LVS_ICON ? infoPtr->himlNormal : infoPtr->himlSmall); + if (himl && lvItem.iImage >= 0 && !IsRectEmpty(&rcIcon)) + { + TRACE("iImage=%d\n", lvItem.iImage); + ImageList_Draw(himl, lvItem.iImage, hdc, rcIcon.left, rcIcon.top, + (lvItem.state & LVIS_SELECTED) && (infoPtr->bFocus) ? ILD_SELECTED : ILD_NORMAL); + } + + /* Don't bother painting item being edited */ + if (infoPtr->hwndEdit && nItem == infoPtr->nEditLabelItem && nSubItem == 0) goto postpaint; + + /* draw the selection background, if we're drawing the main item */ + if (nSubItem == 0) + { + rcSelect = rcLabel; + if (uView == LVS_REPORT && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT)) + rcSelect.right = rcBox.right; + + if (nmlvcd.clrTextBk != CLR_NONE) + ExtTextOutW(hdc, rcSelect.left, rcSelect.top, ETO_OPAQUE, &rcSelect, 0, 0, 0); + if(lprcFocus) *lprcFocus = rcSelect; + } + + /* figure out the text drawing flags */ + uFormat = (uView == LVS_ICON ? (lprcFocus ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS) : LV_SL_DT_FLAGS); + if (uView == LVS_ICON) + uFormat = (lprcFocus ? LV_FL_DT_FLAGS : LV_ML_DT_FLAGS); + else if (nSubItem) + { + switch (LISTVIEW_GetColumnInfo(infoPtr, nSubItem)->fmt & LVCFMT_JUSTIFYMASK) + { + case LVCFMT_RIGHT: uFormat |= DT_RIGHT; break; + case LVCFMT_CENTER: uFormat |= DT_CENTER; break; + default: uFormat |= DT_LEFT; + } + } + if (!(uFormat & (DT_RIGHT | DT_CENTER))) + { + if (himl && lvItem.iImage >= 0 && !IsRectEmpty(&rcIcon)) rcLabel.left += IMAGE_PADDING; + else rcLabel.left += LABEL_HOR_PADDING; + } + else if (uFormat & DT_RIGHT) rcLabel.right -= LABEL_HOR_PADDING; + DrawTextW(hdc, lvItem.pszText, -1, &rcLabel, uFormat); + +postpaint: + if (cdsubitemmode & CDRF_NOTIFYPOSTPAINT) + notify_postpaint(infoPtr, &nmlvcd); + return TRUE; +} + +/*** + * DESCRIPTION: + * Draws listview items when in owner draw mode. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] hdc : device context handle + * + * RETURN: + * None + */ +static void LISTVIEW_RefreshOwnerDraw(LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, DWORD cdmode) +{ + UINT uID = (UINT)GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); + DWORD cditemmode = CDRF_DODEFAULT; + NMLVCUSTOMDRAW nmlvcd; + POINT Origin, Position; + DRAWITEMSTRUCT dis; + LVITEMW item; + + TRACE("()\n"); + + ZeroMemory(&dis, sizeof(dis)); + + /* Get scroll info once before loop */ + LISTVIEW_GetOrigin(infoPtr, &Origin); + + /* iterate through the invalidated rows */ + while(iterator_next(i)) + { + item.iItem = i->nItem; + item.iSubItem = 0; + item.mask = LVIF_PARAM | LVIF_STATE; + item.stateMask = LVIS_SELECTED | LVIS_FOCUSED; + if (!LISTVIEW_GetItemW(infoPtr, &item)) continue; + + dis.CtlType = ODT_LISTVIEW; + dis.CtlID = uID; + dis.itemID = item.iItem; + dis.itemAction = ODA_DRAWENTIRE; + dis.itemState = 0; + if (item.state & LVIS_SELECTED) dis.itemState |= ODS_SELECTED; + if (infoPtr->bFocus && (item.state & LVIS_FOCUSED)) dis.itemState |= ODS_FOCUS; + dis.hwndItem = infoPtr->hwndSelf; + dis.hDC = hdc; + LISTVIEW_GetItemOrigin(infoPtr, dis.itemID, &Position); + dis.rcItem.left = Position.x + Origin.x; + dis.rcItem.right = dis.rcItem.left + infoPtr->nItemWidth; + dis.rcItem.top = Position.y + Origin.y; + dis.rcItem.bottom = dis.rcItem.top + infoPtr->nItemHeight; + dis.itemData = item.lParam; + + TRACE("item=%s, rcItem=%s\n", debuglvitem_t(&item, TRUE), debugrect(&dis.rcItem)); + + /* + * Even if we do not send the CDRF_NOTIFYITEMDRAW we need to fill the nmlvcd + * structure for the rest. of the paint cycle + */ + customdraw_fill(&nmlvcd, infoPtr, hdc, &dis.rcItem, &item); + if (cdmode & CDRF_NOTIFYITEMDRAW) + cditemmode = notify_customdraw(infoPtr, CDDS_PREPAINT, &nmlvcd); + + if (!(cditemmode & CDRF_SKIPDEFAULT)) + { + prepaint_setup (infoPtr, hdc, &nmlvcd); + SendMessageW(infoPtr->hwndNotify, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis); + } + + if (cditemmode & CDRF_NOTIFYPOSTPAINT) + notify_postpaint(infoPtr, &nmlvcd); + } +} + +/*** + * DESCRIPTION: + * Draws listview items when in report display mode. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] hdc : device context handle + * [I] cdmode : custom draw mode + * + * RETURN: + * None + */ +static void LISTVIEW_RefreshReport(LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, DWORD cdmode) +{ + INT rgntype; + RECT rcClip, rcItem; + POINT Origin, Position; + RANGE colRange; + ITERATOR j; + + TRACE("()\n"); + + /* figure out what to draw */ + rgntype = GetClipBox(hdc, &rcClip); + if (rgntype == NULLREGION) return; + + /* Get scroll info once before loop */ + LISTVIEW_GetOrigin(infoPtr, &Origin); + + /* narrow down the columns we need to paint */ + for(colRange.lower = 0; colRange.lower < DPA_GetPtrCount(infoPtr->hdpaColumns); colRange.lower++) + { + LISTVIEW_GetHeaderRect(infoPtr, colRange.lower, &rcItem); + if (rcItem.right + Origin.x >= rcClip.left) break; + } + for(colRange.upper = DPA_GetPtrCount(infoPtr->hdpaColumns); colRange.upper > 0; colRange.upper--) + { + LISTVIEW_GetHeaderRect(infoPtr, colRange.upper - 1, &rcItem); + if (rcItem.left + Origin.x < rcClip.right) break; + } + iterator_rangeitems(&j, colRange); + + /* in full row select, we _have_ to draw the main item */ + if (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) + j.nSpecial = 0; + + /* iterate through the invalidated rows */ + while(iterator_next(i)) + { + /* iterate through the invalidated columns */ + while(iterator_next(&j)) + { + LISTVIEW_GetItemOrigin(infoPtr, i->nItem, &Position); + Position.x += Origin.x; + Position.y += Origin.y; + + if (rgntype == COMPLEXREGION && !((infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) && j.nItem == 0)) + { + LISTVIEW_GetHeaderRect(infoPtr, j.nItem, &rcItem); + rcItem.top = 0; + rcItem.bottom = infoPtr->nItemHeight; + OffsetRect(&rcItem, Position.x, Position.y); + if (!RectVisible(hdc, &rcItem)) continue; + } + + LISTVIEW_DrawItem(infoPtr, hdc, i->nItem, j.nItem, Position, cdmode); + } + } + iterator_destroy(&j); +} + +/*** + * DESCRIPTION: + * Draws listview items when in list display mode. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] hdc : device context handle + * [I] cdmode : custom draw mode + * + * RETURN: + * None + */ +static void LISTVIEW_RefreshList(LISTVIEW_INFO *infoPtr, ITERATOR *i, HDC hdc, DWORD cdmode) +{ + POINT Origin, Position; + + /* Get scroll info once before loop */ + LISTVIEW_GetOrigin(infoPtr, &Origin); + + while(iterator_prev(i)) + { + LISTVIEW_GetItemOrigin(infoPtr, i->nItem, &Position); + Position.x += Origin.x; + Position.y += Origin.y; + + LISTVIEW_DrawItem(infoPtr, hdc, i->nItem, 0, Position, cdmode); + } +} + + +/*** + * DESCRIPTION: + * Draws listview items. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] hdc : device context handle + * + * RETURN: + * NoneX + */ +static void LISTVIEW_Refresh(LISTVIEW_INFO *infoPtr, HDC hdc) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + COLORREF oldTextColor, oldClrTextBk, oldClrText; + NMLVCUSTOMDRAW nmlvcd; + HFONT hOldFont; + DWORD cdmode; + INT oldBkMode; + RECT rcClient; + ITERATOR i; + + LISTVIEW_DUMP(infoPtr); + + infoPtr->bIsDrawing = TRUE; + + /* save dc values we're gonna trash while drawing */ + hOldFont = SelectObject(hdc, infoPtr->hFont); + oldBkMode = GetBkMode(hdc); + infoPtr->clrTextBkDefault = GetBkColor(hdc); + oldTextColor = GetTextColor(hdc); + + oldClrTextBk = infoPtr->clrTextBk; + oldClrText = infoPtr->clrText; + + infoPtr->cditemmode = CDRF_DODEFAULT; + + GetClientRect(infoPtr->hwndSelf, &rcClient); + customdraw_fill(&nmlvcd, infoPtr, hdc, &rcClient, 0); + cdmode = notify_customdraw(infoPtr, CDDS_PREPAINT, &nmlvcd); + if (cdmode & CDRF_SKIPDEFAULT) goto enddraw; + prepaint_setup(infoPtr, hdc, &nmlvcd); + + /* Use these colors to draw the items */ + infoPtr->clrTextBk = nmlvcd.clrTextBk; + infoPtr->clrText = nmlvcd.clrText; + + /* nothing to draw */ + if(infoPtr->nItemCount == 0) goto enddraw; + + /* figure out what we need to draw */ + iterator_visibleitems(&i, infoPtr, hdc); + + /* send cache hint notification */ + if (infoPtr->dwStyle & LVS_OWNERDATA) + { + RANGE range = iterator_range(&i); + NMLVCACHEHINT nmlv; + + ZeroMemory(&nmlv, sizeof(NMLVCACHEHINT)); + nmlv.iFrom = range.lower; + nmlv.iTo = range.upper - 1; + notify_hdr(infoPtr, LVN_ODCACHEHINT, &nmlv.hdr); + } + + if ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (uView == LVS_REPORT)) + LISTVIEW_RefreshOwnerDraw(infoPtr, &i, hdc, cdmode); + else + { + if (uView == LVS_REPORT) + LISTVIEW_RefreshReport(infoPtr, &i, hdc, cdmode); + else /* LVS_LIST, LVS_ICON or LVS_SMALLICON */ + LISTVIEW_RefreshList(infoPtr, &i, hdc, cdmode); + + /* if we have a focus rect, draw it */ + if (infoPtr->bFocus) + DrawFocusRect(hdc, &infoPtr->rcFocus); + } + iterator_destroy(&i); + +enddraw: + if (cdmode & CDRF_NOTIFYPOSTPAINT) + notify_postpaint(infoPtr, &nmlvcd); + + infoPtr->clrTextBk = oldClrTextBk; + infoPtr->clrText = oldClrText; + + SelectObject(hdc, hOldFont); + SetBkMode(hdc, oldBkMode); + SetBkColor(hdc, infoPtr->clrTextBkDefault); + SetTextColor(hdc, oldTextColor); + infoPtr->bIsDrawing = FALSE; +} + + +/*** + * DESCRIPTION: + * Calculates the approximate width and height of a given number of items. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nItemCount : number of items + * [I] wWidth : width + * [I] wHeight : height + * + * RETURN: + * Returns a DWORD. The width in the low word and the height in high word. + */ +static DWORD LISTVIEW_ApproximateViewRect(LISTVIEW_INFO *infoPtr, INT nItemCount, + WORD wWidth, WORD wHeight) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + INT nItemCountPerColumn = 1; + INT nColumnCount = 0; + DWORD dwViewRect = 0; + + if (nItemCount == -1) + nItemCount = infoPtr->nItemCount; + + if (uView == LVS_LIST) + { + if (wHeight == 0xFFFF) + { + /* use current height */ + wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top; + } + + if (wHeight < infoPtr->nItemHeight) + wHeight = infoPtr->nItemHeight; + + if (nItemCount > 0) + { + if (infoPtr->nItemHeight > 0) + { + nItemCountPerColumn = wHeight / infoPtr->nItemHeight; + if (nItemCountPerColumn == 0) + nItemCountPerColumn = 1; + + if (nItemCount % nItemCountPerColumn != 0) + nColumnCount = nItemCount / nItemCountPerColumn; + else + nColumnCount = nItemCount / nItemCountPerColumn + 1; + } + } + + /* Microsoft padding magic */ + wHeight = nItemCountPerColumn * infoPtr->nItemHeight + 2; + wWidth = nColumnCount * infoPtr->nItemWidth + 2; + + dwViewRect = MAKELONG(wWidth, wHeight); + } + else if (uView == LVS_REPORT) + { + RECT rcBox; + + if (infoPtr->nItemCount > 0) + { + LISTVIEW_GetItemBox(infoPtr, 0, &rcBox); + wWidth = rcBox.right - rcBox.left; + wHeight = (rcBox.bottom - rcBox.top) * nItemCount; + } + else + { + /* use current height and width */ + if (wHeight == 0xffff) + wHeight = infoPtr->rcList.bottom - infoPtr->rcList.top; + if (wWidth == 0xffff) + wWidth = infoPtr->rcList.right - infoPtr->rcList.left; + } + + dwViewRect = MAKELONG(wWidth, wHeight); + } + else if (uView == LVS_SMALLICON) + FIXME("uView == LVS_SMALLICON: not implemented\n"); + else if (uView == LVS_ICON) + FIXME("uView == LVS_ICON: not implemented\n"); + + return dwViewRect; +} + + +/*** + * DESCRIPTION: + * Create a drag image list for the specified item. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] iItem : index of item + * [O] lppt : Upperr-left corner of the image + * + * RETURN: + * Returns a handle to the image list if successful, NULL otherwise. + */ +static HIMAGELIST LISTVIEW_CreateDragImage(LISTVIEW_INFO *infoPtr, INT iItem, LPPOINT lppt) +{ + RECT rcItem; + SIZE size; + POINT pos; + HDC hdc, hdcOrig; + HBITMAP hbmp, hOldbmp; + HIMAGELIST dragList = 0; + TRACE("iItem=%d Count=%d \n", iItem, infoPtr->nItemCount); + + if (iItem < 0 || iItem >= infoPtr->nItemCount) + return 0; + + rcItem.left = LVIR_BOUNDS; + if (!LISTVIEW_GetItemRect(infoPtr, iItem, &rcItem)) + return 0; + + lppt->x = rcItem.left; + lppt->y = rcItem.top; + + size.cx = rcItem.right - rcItem.left; + size.cy = rcItem.bottom - rcItem.top; + + hdcOrig = GetDC(infoPtr->hwndSelf); + hdc = CreateCompatibleDC(hdcOrig); + hbmp = CreateCompatibleBitmap(hdcOrig, size.cx, size.cy); + hOldbmp = SelectObject(hdc, hbmp); + + rcItem.left = rcItem.top = 0; + rcItem.right = size.cx; + rcItem.bottom = size.cy; + FillRect(hdc, &rcItem, infoPtr->hBkBrush); + + pos.x = pos.y = 0; + if (LISTVIEW_DrawItem(infoPtr, hdc, iItem, 0, pos, infoPtr->cditemmode)) + { + dragList = ImageList_Create(size.cx, size.cy, ILC_COLOR, 10, 10); + SelectObject(hdc, hOldbmp); + ImageList_Add(dragList, hbmp, 0); + } + else + SelectObject(hdc, hOldbmp); + + DeleteObject(hbmp); + DeleteDC(hdc); + ReleaseDC(infoPtr->hwndSelf, hdcOrig); + + TRACE("ret=%p\n", dragList); + + return dragList; +} + + +/*** + * DESCRIPTION: + * Removes all listview items and subitems. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_DeleteAllItems(LISTVIEW_INFO *infoPtr) +{ + NMLISTVIEW nmlv; + HDPA hdpaSubItems = NULL; + BOOL bSuppress; + ITEMHDR *hdrItem; + INT i, j; + + TRACE("()\n"); + + /* we do it directly, to avoid notifications */ + ranges_clear(infoPtr->selectionRanges); + infoPtr->nSelectionMark = -1; + infoPtr->nFocusedItem = -1; + SetRectEmpty(&infoPtr->rcFocus); + /* But we are supposed to leave nHotItem as is! */ + + + /* send LVN_DELETEALLITEMS notification */ + ZeroMemory(&nmlv, sizeof(NMLISTVIEW)); + nmlv.iItem = -1; + bSuppress = notify_listview(infoPtr, LVN_DELETEALLITEMS, &nmlv); + + for (i = infoPtr->nItemCount - 1; i >= 0; i--) + { + /* send LVN_DELETEITEM notification, if not suppressed */ + if (!bSuppress) notify_deleteitem(infoPtr, i); + if (!(infoPtr->dwStyle & LVS_OWNERDATA)) + { + hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i); + for (j = 0; j < DPA_GetPtrCount(hdpaSubItems); j++) + { + hdrItem = (ITEMHDR *)DPA_GetPtr(hdpaSubItems, j); + if (is_textW(hdrItem->pszText)) Free(hdrItem->pszText); + Free(hdrItem); + } + DPA_Destroy(hdpaSubItems); + DPA_DeletePtr(infoPtr->hdpaItems, i); + } + DPA_DeletePtr(infoPtr->hdpaPosX, i); + DPA_DeletePtr(infoPtr->hdpaPosY, i); + infoPtr->nItemCount --; + } + + LISTVIEW_UpdateScroll(infoPtr); + + LISTVIEW_InvalidateList(infoPtr); + + return TRUE; +} + +/*** + * DESCRIPTION: + * Scrolls, and updates the columns, when a column is changing width. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nColumn : column to scroll + * [I] dx : amount of scroll, in pixels + * + * RETURN: + * None. + */ +static void LISTVIEW_ScrollColumns(LISTVIEW_INFO *infoPtr, INT nColumn, INT dx) +{ + COLUMN_INFO *lpColumnInfo; + RECT rcOld, rcCol; + POINT ptOrigin; + INT nCol; + + if (nColumn < 0 || DPA_GetPtrCount(infoPtr->hdpaColumns) < 1) return; + lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, min(nColumn, DPA_GetPtrCount(infoPtr->hdpaColumns) - 1)); + rcCol = lpColumnInfo->rcHeader; + if (nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) + rcCol.left = rcCol.right; + + /* ajust the other columns */ + for (nCol = nColumn; nCol < DPA_GetPtrCount(infoPtr->hdpaColumns); nCol++) + { + lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, nCol); + lpColumnInfo->rcHeader.left += dx; + lpColumnInfo->rcHeader.right += dx; + } + + /* do not update screen if not in report mode */ + if (!is_redrawing(infoPtr) || (infoPtr->dwStyle & LVS_TYPEMASK) != LVS_REPORT) return; + + /* if we have a focus, must first erase the focus rect */ + if (infoPtr->bFocus) LISTVIEW_ShowFocusRect(infoPtr, FALSE); + + /* Need to reset the item width when inserting a new column */ + infoPtr->nItemWidth += dx; + + LISTVIEW_UpdateScroll(infoPtr); + LISTVIEW_GetOrigin(infoPtr, &ptOrigin); + + /* scroll to cover the deleted column, and invalidate for redraw */ + rcOld = infoPtr->rcList; + rcOld.left = ptOrigin.x + rcCol.left + dx; + ScrollWindowEx(infoPtr->hwndSelf, dx, 0, &rcOld, &rcOld, 0, 0, SW_ERASE | SW_INVALIDATE); + + /* we can restore focus now */ + if (infoPtr->bFocus) LISTVIEW_ShowFocusRect(infoPtr, TRUE); +} + +/*** + * DESCRIPTION: + * Removes a column from the listview control. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nColumn : column index + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_DeleteColumn(LISTVIEW_INFO *infoPtr, INT nColumn) +{ + RECT rcCol; + + TRACE("nColumn=%d\n", nColumn); + + if (nColumn < 0 || DPA_GetPtrCount(infoPtr->hdpaColumns) == 0 + || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE; + + /* While the MSDN specifically says that column zero should not be deleted, + what actually happens is that the column itself is deleted but no items or subitems + are removed. + */ + + LISTVIEW_GetHeaderRect(infoPtr, nColumn, &rcCol); + + if (!Header_DeleteItem(infoPtr->hwndHeader, nColumn)) + return FALSE; + + Free(DPA_GetPtr(infoPtr->hdpaColumns, nColumn)); + DPA_DeletePtr(infoPtr->hdpaColumns, nColumn); + + if (!(infoPtr->dwStyle & LVS_OWNERDATA) && nColumn) + { + SUBITEM_INFO *lpSubItem, *lpDelItem; + HDPA hdpaSubItems; + INT nItem, nSubItem, i; + + for (nItem = 0; nItem < infoPtr->nItemCount; nItem++) + { + hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem); + nSubItem = 0; + lpDelItem = 0; + for (i = 1; i < DPA_GetPtrCount(hdpaSubItems); i++) + { + lpSubItem = (SUBITEM_INFO *)DPA_GetPtr(hdpaSubItems, i); + if (lpSubItem->iSubItem == nColumn) + { + nSubItem = i; + lpDelItem = lpSubItem; + } + else if (lpSubItem->iSubItem > nColumn) + { + lpSubItem->iSubItem--; + } + } + + /* if we found our subitem, zapp it */ + if (nSubItem > 0) + { + /* free string */ + if (is_textW(lpDelItem->hdr.pszText)) + Free(lpDelItem->hdr.pszText); + + /* free item */ + Free(lpDelItem); + + /* free dpa memory */ + DPA_DeletePtr(hdpaSubItems, nSubItem); + } + } + } + + /* update the other column info */ + if(DPA_GetPtrCount(infoPtr->hdpaColumns) == 0) + LISTVIEW_InvalidateList(infoPtr); + else + LISTVIEW_ScrollColumns(infoPtr, nColumn, -(rcCol.right - rcCol.left)); + + return TRUE; +} + +/*** + * DESCRIPTION: + * Invalidates the listview after an item's insertion or deletion. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nItem : item index + * [I] dir : -1 if deleting, 1 if inserting + * + * RETURN: + * None + */ +static void LISTVIEW_ScrollOnInsert(LISTVIEW_INFO *infoPtr, INT nItem, INT dir) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + INT nPerCol, nItemCol, nItemRow; + RECT rcScroll; + POINT Origin; + + /* if we don't refresh, what's the point of scrolling? */ + if (!is_redrawing(infoPtr)) return; + + assert (abs(dir) == 1); + + /* arrange icons if autoarrange is on */ + if (is_autoarrange(infoPtr)) + { + BOOL arrange = TRUE; + if (dir < 0 && nItem >= infoPtr->nItemCount) arrange = FALSE; + if (dir > 0 && nItem == infoPtr->nItemCount - 1) arrange = FALSE; + if (arrange) LISTVIEW_Arrange(infoPtr, LVA_DEFAULT); + } + + /* scrollbars need updating */ + LISTVIEW_UpdateScroll(infoPtr); + + /* figure out the item's position */ + if (uView == LVS_REPORT) + nPerCol = infoPtr->nItemCount + 1; + else if (uView == LVS_LIST) + nPerCol = LISTVIEW_GetCountPerColumn(infoPtr); + else /* LVS_ICON, or LVS_SMALLICON */ + return; + + nItemCol = nItem / nPerCol; + nItemRow = nItem % nPerCol; + LISTVIEW_GetOrigin(infoPtr, &Origin); + + /* move the items below up a slot */ + rcScroll.left = nItemCol * infoPtr->nItemWidth; + rcScroll.top = nItemRow * infoPtr->nItemHeight; + rcScroll.right = rcScroll.left + infoPtr->nItemWidth; + rcScroll.bottom = nPerCol * infoPtr->nItemHeight; + OffsetRect(&rcScroll, Origin.x, Origin.y); + TRACE("rcScroll=%s, dx=%d\n", debugrect(&rcScroll), dir * infoPtr->nItemHeight); + if (IntersectRect(&rcScroll, &rcScroll, &infoPtr->rcList)) + { + TRACE("Scrolling rcScroll=%s, rcList=%s\n", debugrect(&rcScroll), debugrect(&infoPtr->rcList)); + ScrollWindowEx(infoPtr->hwndSelf, 0, dir * infoPtr->nItemHeight, + &rcScroll, &rcScroll, 0, 0, SW_ERASE | SW_INVALIDATE); + } + + /* report has only that column, so we're done */ + if (uView == LVS_REPORT) return; + + /* now for LISTs, we have to deal with the columns to the right */ + rcScroll.left = (nItemCol + 1) * infoPtr->nItemWidth; + rcScroll.top = 0; + rcScroll.right = (infoPtr->nItemCount / nPerCol + 1) * infoPtr->nItemWidth; + rcScroll.bottom = nPerCol * infoPtr->nItemHeight; + OffsetRect(&rcScroll, Origin.x, Origin.y); + if (IntersectRect(&rcScroll, &rcScroll, &infoPtr->rcList)) + ScrollWindowEx(infoPtr->hwndSelf, 0, dir * infoPtr->nItemHeight, + &rcScroll, &rcScroll, 0, 0, SW_ERASE | SW_INVALIDATE); +} + +/*** + * DESCRIPTION: + * Removes an item from the listview control. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nItem : item index + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_DeleteItem(LISTVIEW_INFO *infoPtr, INT nItem) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + LVITEMW item; + + TRACE("(nItem=%d)\n", nItem); + + if (nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE; + + /* remove selection, and focus */ + item.state = 0; + item.stateMask = LVIS_SELECTED | LVIS_FOCUSED; + LISTVIEW_SetItemState(infoPtr, nItem, &item); + + /* send LVN_DELETEITEM notification. */ + notify_deleteitem(infoPtr, nItem); + + /* we need to do this here, because we'll be deleting stuff */ + if (uView == LVS_SMALLICON || uView == LVS_ICON) + LISTVIEW_InvalidateItem(infoPtr, nItem); + + if (!(infoPtr->dwStyle & LVS_OWNERDATA)) + { + HDPA hdpaSubItems; + ITEMHDR *hdrItem; + INT i; + + hdpaSubItems = (HDPA)DPA_DeletePtr(infoPtr->hdpaItems, nItem); + for (i = 0; i < DPA_GetPtrCount(hdpaSubItems); i++) + { + hdrItem = (ITEMHDR *)DPA_GetPtr(hdpaSubItems, i); + if (is_textW(hdrItem->pszText)) Free(hdrItem->pszText); + Free(hdrItem); + } + DPA_Destroy(hdpaSubItems); + } + + if (uView == LVS_SMALLICON || uView == LVS_ICON) + { + DPA_DeletePtr(infoPtr->hdpaPosX, nItem); + DPA_DeletePtr(infoPtr->hdpaPosY, nItem); + } + + infoPtr->nItemCount--; + LISTVIEW_ShiftIndices(infoPtr, nItem, -1); + + /* now is the invalidation fun */ + LISTVIEW_ScrollOnInsert(infoPtr, nItem, -1); + return TRUE; +} + + +/*** + * DESCRIPTION: + * Callback implementation for editlabel control + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] pszText : modified text + * [I] isW : TRUE if psxText is Unicode, FALSE if it's ANSI + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_EndEditLabelT(LISTVIEW_INFO *infoPtr, LPWSTR pszText, BOOL isW) +{ + NMLVDISPINFOW dispInfo; + + TRACE("(pszText=%s, isW=%d)\n", debugtext_t(pszText, isW), isW); + + ZeroMemory(&dispInfo, sizeof(dispInfo)); + dispInfo.item.mask = LVIF_PARAM | LVIF_STATE; + dispInfo.item.iItem = infoPtr->nEditLabelItem; + dispInfo.item.iSubItem = 0; + dispInfo.item.stateMask = ~0; + if (!LISTVIEW_GetItemW(infoPtr, &dispInfo.item)) return FALSE; + /* add the text from the edit in */ + dispInfo.item.mask |= LVIF_TEXT; + dispInfo.item.pszText = pszText; + dispInfo.item.cchTextMax = textlenT(pszText, isW); + + /* Do we need to update the Item Text */ + if (!notify_dispinfoT(infoPtr, LVN_ENDLABELEDITW, &dispInfo, isW)) return FALSE; + if (!pszText) return TRUE; + + if (!(infoPtr->dwStyle & LVS_OWNERDATA)) + { + HDPA hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, infoPtr->nEditLabelItem); + ITEM_INFO* lpItem = (ITEM_INFO *)DPA_GetPtr(hdpaSubItems, 0); + if (lpItem && lpItem->hdr.pszText == LPSTR_TEXTCALLBACKW) + { + LISTVIEW_InvalidateItem(infoPtr, infoPtr->nEditLabelItem); + return TRUE; + } + } + + ZeroMemory(&dispInfo, sizeof(dispInfo)); + dispInfo.item.mask = LVIF_TEXT; + dispInfo.item.iItem = infoPtr->nEditLabelItem; + dispInfo.item.iSubItem = 0; + dispInfo.item.pszText = pszText; + dispInfo.item.cchTextMax = textlenT(pszText, isW); + return LISTVIEW_SetItemT(infoPtr, &dispInfo.item, isW); +} + +/*** + * DESCRIPTION: + * Begin in place editing of specified list view item + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nItem : item index + * [I] isW : TRUE if it's a Unicode req, FALSE if ASCII + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static HWND LISTVIEW_EditLabelT(LISTVIEW_INFO *infoPtr, INT nItem, BOOL isW) +{ + WCHAR szDispText[DISP_TEXT_SIZE] = { 0 }; + NMLVDISPINFOW dispInfo; + RECT rect; + + TRACE("(nItem=%d, isW=%d)\n", nItem, isW); + + if (~infoPtr->dwStyle & LVS_EDITLABELS) return 0; + if (nItem < 0 || nItem >= infoPtr->nItemCount) return 0; + + infoPtr->nEditLabelItem = nItem; + + /* Is the EditBox still there, if so remove it */ + if(infoPtr->hwndEdit != 0) + { + SetFocus(infoPtr->hwndSelf); + infoPtr->hwndEdit = 0; + } + + LISTVIEW_SetSelection(infoPtr, nItem); + LISTVIEW_SetItemFocus(infoPtr, nItem); + LISTVIEW_InvalidateItem(infoPtr, nItem); + + rect.left = LVIR_LABEL; + if (!LISTVIEW_GetItemRect(infoPtr, nItem, &rect)) return 0; + + ZeroMemory(&dispInfo, sizeof(dispInfo)); + dispInfo.item.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT; + dispInfo.item.iItem = nItem; + dispInfo.item.iSubItem = 0; + dispInfo.item.stateMask = ~0; + dispInfo.item.pszText = szDispText; + dispInfo.item.cchTextMax = DISP_TEXT_SIZE; + if (!LISTVIEW_GetItemT(infoPtr, &dispInfo.item, isW)) return 0; + + infoPtr->hwndEdit = CreateEditLabelT(infoPtr, dispInfo.item.pszText, WS_VISIBLE, + rect.left-2, rect.top-1, 0, rect.bottom - rect.top+2, isW); + if (!infoPtr->hwndEdit) return 0; + + if (notify_dispinfoT(infoPtr, LVN_BEGINLABELEDITW, &dispInfo, isW)) + { + SendMessageW(infoPtr->hwndEdit, WM_CLOSE, 0, 0); + infoPtr->hwndEdit = 0; + return 0; + } + + ShowWindow(infoPtr->hwndEdit, SW_NORMAL); + SetFocus(infoPtr->hwndEdit); + SendMessageW(infoPtr->hwndEdit, EM_SETSEL, 0, -1); + return infoPtr->hwndEdit; +} + + +/*** + * DESCRIPTION: + * Ensures the specified item is visible, scrolling into view if necessary. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nItem : item index + * [I] bPartial : partially or entirely visible + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_EnsureVisible(LISTVIEW_INFO *infoPtr, INT nItem, BOOL bPartial) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + INT nScrollPosHeight = 0; + INT nScrollPosWidth = 0; + INT nHorzAdjust = 0; + INT nVertAdjust = 0; + INT nHorzDiff = 0; + INT nVertDiff = 0; + RECT rcItem, rcTemp; + + rcItem.left = LVIR_BOUNDS; + if (!LISTVIEW_GetItemRect(infoPtr, nItem, &rcItem)) return FALSE; + + if (bPartial && IntersectRect(&rcTemp, &infoPtr->rcList, &rcItem)) return TRUE; + + if (rcItem.left < infoPtr->rcList.left || rcItem.right > infoPtr->rcList.right) + { + /* scroll left/right, but in LVS_REPORT mode */ + if (uView == LVS_LIST) + nScrollPosWidth = infoPtr->nItemWidth; + else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON)) + nScrollPosWidth = 1; + + if (rcItem.left < infoPtr->rcList.left) + { + nHorzAdjust = -1; + if (uView != LVS_REPORT) nHorzDiff = rcItem.left - infoPtr->rcList.left; + } + else + { + nHorzAdjust = 1; + if (uView != LVS_REPORT) nHorzDiff = rcItem.right - infoPtr->rcList.right; + } + } + + if (rcItem.top < infoPtr->rcList.top || rcItem.bottom > infoPtr->rcList.bottom) + { + /* scroll up/down, but not in LVS_LIST mode */ + if (uView == LVS_REPORT) + nScrollPosHeight = infoPtr->nItemHeight; + else if ((uView == LVS_ICON) || (uView == LVS_SMALLICON)) + nScrollPosHeight = 1; + + if (rcItem.top < infoPtr->rcList.top) + { + nVertAdjust = -1; + if (uView != LVS_LIST) nVertDiff = rcItem.top - infoPtr->rcList.top; + } + else + { + nVertAdjust = 1; + if (uView != LVS_LIST) nVertDiff = rcItem.bottom - infoPtr->rcList.bottom; + } + } + + if (!nScrollPosWidth && !nScrollPosHeight) return TRUE; + + if (nScrollPosWidth) + { + INT diff = nHorzDiff / nScrollPosWidth; + if (nHorzDiff % nScrollPosWidth) diff += nHorzAdjust; + LISTVIEW_HScroll(infoPtr, SB_INTERNAL, diff, 0); + } + + if (nScrollPosHeight) + { + INT diff = nVertDiff / nScrollPosHeight; + if (nVertDiff % nScrollPosHeight) diff += nVertAdjust; + LISTVIEW_VScroll(infoPtr, SB_INTERNAL, diff, 0); + } + + return TRUE; +} + +/*** + * DESCRIPTION: + * Searches for an item with specific characteristics. + * + * PARAMETER(S): + * [I] hwnd : window handle + * [I] nStart : base item index + * [I] lpFindInfo : item information to look for + * + * RETURN: + * SUCCESS : index of item + * FAILURE : -1 + */ +static INT LISTVIEW_FindItemW(LISTVIEW_INFO *infoPtr, INT nStart, + const LVFINDINFOW *lpFindInfo) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' }; + BOOL bWrap = FALSE, bNearest = FALSE; + INT nItem = nStart + 1, nLast = infoPtr->nItemCount, nNearestItem = -1; + ULONG xdist, ydist, dist, mindist = 0x7fffffff; + POINT Position, Destination; + LVITEMW lvItem; + + if (!lpFindInfo || nItem < 0) return -1; + + lvItem.mask = 0; + if (lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL)) + { + lvItem.mask |= LVIF_TEXT; + lvItem.pszText = szDispText; + lvItem.cchTextMax = DISP_TEXT_SIZE; + } + + if (lpFindInfo->flags & LVFI_WRAP) + bWrap = TRUE; + + if ((lpFindInfo->flags & LVFI_NEARESTXY) && + (uView == LVS_ICON || uView ==LVS_SMALLICON)) + { + POINT Origin; + RECT rcArea; + + LISTVIEW_GetOrigin(infoPtr, &Origin); + Destination.x = lpFindInfo->pt.x - Origin.x; + Destination.y = lpFindInfo->pt.y - Origin.y; + switch(lpFindInfo->vkDirection) + { + case VK_DOWN: Destination.y += infoPtr->nItemHeight; break; + case VK_UP: Destination.y -= infoPtr->nItemHeight; break; + case VK_RIGHT: Destination.x += infoPtr->nItemWidth; break; + case VK_LEFT: Destination.x -= infoPtr->nItemWidth; break; + case VK_HOME: Destination.x = Destination.y = 0; break; + case VK_NEXT: Destination.y += infoPtr->rcList.bottom - infoPtr->rcList.top; break; + case VK_PRIOR: Destination.y -= infoPtr->rcList.bottom - infoPtr->rcList.top; break; + case VK_END: + LISTVIEW_GetAreaRect(infoPtr, &rcArea); + Destination.x = rcArea.right; + Destination.y = rcArea.bottom; + break; + default: ERR("Unknown vkDirection=%d\n", lpFindInfo->vkDirection); + } + bNearest = TRUE; + } + + /* if LVFI_PARAM is specified, all other flags are ignored */ + if (lpFindInfo->flags & LVFI_PARAM) + { + lvItem.mask |= LVIF_PARAM; + bNearest = FALSE; + lvItem.mask &= ~LVIF_TEXT; + } + +again: + for (; nItem < nLast; nItem++) + { + lvItem.iItem = nItem; + lvItem.iSubItem = 0; + if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) continue; + + if (lvItem.mask & LVIF_PARAM) + { + if (lpFindInfo->lParam == lvItem.lParam) + return nItem; + else + continue; + } + + if (lvItem.mask & LVIF_TEXT) + { + if (lpFindInfo->flags & LVFI_PARTIAL) + { + if (strstrW(lvItem.pszText, lpFindInfo->psz) == NULL) continue; + } + else + { + if (lstrcmpW(lvItem.pszText, lpFindInfo->psz) != 0) continue; + } + } + + if (!bNearest) return nItem; + + /* This is very inefficient. To do a good job here, + * we need a sorted array of (x,y) item positions */ + LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position); + + /* compute the distance^2 to the destination */ + xdist = Destination.x - Position.x; + ydist = Destination.y - Position.y; + dist = xdist * xdist + ydist * ydist; + + /* remember the distance, and item if it's closer */ + if (dist < mindist) + { + mindist = dist; + nNearestItem = nItem; + } + } + + if (bWrap) + { + nItem = 0; + nLast = min(nStart + 1, infoPtr->nItemCount); + bWrap = FALSE; + goto again; + } + + return nNearestItem; +} + +/*** + * DESCRIPTION: + * Searches for an item with specific characteristics. + * + * PARAMETER(S): + * [I] hwnd : window handle + * [I] nStart : base item index + * [I] lpFindInfo : item information to look for + * + * RETURN: + * SUCCESS : index of item + * FAILURE : -1 + */ +static INT LISTVIEW_FindItemA(LISTVIEW_INFO *infoPtr, INT nStart, + const LVFINDINFOA *lpFindInfo) +{ + BOOL hasText = lpFindInfo->flags & (LVFI_STRING | LVFI_PARTIAL); + LVFINDINFOW fiw; + INT res; + + memcpy(&fiw, lpFindInfo, sizeof(fiw)); + if (hasText) fiw.psz = textdupTtoW((LPCWSTR)lpFindInfo->psz, FALSE); + res = LISTVIEW_FindItemW(infoPtr, nStart, &fiw); + if (hasText) textfreeT((LPWSTR)fiw.psz, FALSE); + return res; +} + +/*** + * DESCRIPTION: + * Retrieves the background image of the listview control. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [O] lpBkImage : background image attributes + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +/* static BOOL LISTVIEW_GetBkImage(LISTVIEW_INFO *infoPtr, LPLVBKIMAGE lpBkImage) */ +/* { */ +/* FIXME (listview, "empty stub!\n"); */ +/* return FALSE; */ +/* } */ + +/*** + * DESCRIPTION: + * Retrieves column attributes. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nColumn : column index + * [IO] lpColumn : column information + * [I] isW : if TRUE, then lpColumn is a LPLVCOLUMNW + * otherwise it is in fact a LPLVCOLUMNA + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_GetColumnT(LISTVIEW_INFO *infoPtr, INT nColumn, LPLVCOLUMNW lpColumn, BOOL isW) +{ + COLUMN_INFO *lpColumnInfo; + HDITEMW hdi; + + if (!lpColumn || nColumn < 0 || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE; + lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, nColumn); + + /* initialize memory */ + ZeroMemory(&hdi, sizeof(hdi)); + + if (lpColumn->mask & LVCF_TEXT) + { + hdi.mask |= HDI_TEXT; + hdi.pszText = lpColumn->pszText; + hdi.cchTextMax = lpColumn->cchTextMax; + } + + if (lpColumn->mask & LVCF_IMAGE) + hdi.mask |= HDI_IMAGE; + + if (lpColumn->mask & LVCF_ORDER) + hdi.mask |= HDI_ORDER; + + if (!SendMessageW(infoPtr->hwndHeader, isW ? HDM_GETITEMW : HDM_GETITEMA, nColumn, (LPARAM)&hdi)) return FALSE; + + if (lpColumn->mask & LVCF_FMT) + lpColumn->fmt = lpColumnInfo->fmt; + + if (lpColumn->mask & LVCF_WIDTH) + lpColumn->cx = lpColumnInfo->rcHeader.right - lpColumnInfo->rcHeader.left; + + if (lpColumn->mask & LVCF_IMAGE) + lpColumn->iImage = hdi.iImage; + + if (lpColumn->mask & LVCF_ORDER) + lpColumn->iOrder = hdi.iOrder; + + return TRUE; +} + + +static BOOL LISTVIEW_GetColumnOrderArray(LISTVIEW_INFO *infoPtr, INT iCount, LPINT lpiArray) +{ + INT i; + + if (!lpiArray) + return FALSE; + + /* FIXME: little hack */ + for (i = 0; i < iCount; i++) + lpiArray[i] = i; + + return TRUE; +} + +/*** + * DESCRIPTION: + * Retrieves the column width. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] int : column index + * + * RETURN: + * SUCCESS : column width + * FAILURE : zero + */ +static INT LISTVIEW_GetColumnWidth(LISTVIEW_INFO *infoPtr, INT nColumn) +{ + INT nColumnWidth = 0; + RECT rcHeader; + + TRACE("nColumn=%d\n", nColumn); + + /* we have a 'column' in LIST and REPORT mode only */ + switch(infoPtr->dwStyle & LVS_TYPEMASK) + { + case LVS_LIST: + nColumnWidth = infoPtr->nItemWidth; + break; + case LVS_REPORT: + if (nColumn < 0 || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return 0; + LISTVIEW_GetHeaderRect(infoPtr, nColumn, &rcHeader); + nColumnWidth = rcHeader.right - rcHeader.left; + break; + } + + TRACE("nColumnWidth=%d\n", nColumnWidth); + return nColumnWidth; +} + +/*** + * DESCRIPTION: + * In list or report display mode, retrieves the number of items that can fit + * vertically in the visible area. In icon or small icon display mode, + * retrieves the total number of visible items. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * + * RETURN: + * Number of fully visible items. + */ +static INT LISTVIEW_GetCountPerPage(LISTVIEW_INFO *infoPtr) +{ + switch (infoPtr->dwStyle & LVS_TYPEMASK) + { + case LVS_ICON: + case LVS_SMALLICON: + return infoPtr->nItemCount; + case LVS_REPORT: + return LISTVIEW_GetCountPerColumn(infoPtr); + case LVS_LIST: + return LISTVIEW_GetCountPerRow(infoPtr) * LISTVIEW_GetCountPerColumn(infoPtr); + } + assert(FALSE); + return 0; +} + +/*** + * DESCRIPTION: + * Retrieves an image list handle. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nImageList : image list identifier + * + * RETURN: + * SUCCESS : image list handle + * FAILURE : NULL + */ +static HIMAGELIST LISTVIEW_GetImageList(LISTVIEW_INFO *infoPtr, INT nImageList) +{ + switch (nImageList) + { + case LVSIL_NORMAL: return infoPtr->himlNormal; + case LVSIL_SMALL: return infoPtr->himlSmall; + case LVSIL_STATE: return infoPtr->himlState; + } + return NULL; +} + +/* LISTVIEW_GetISearchString */ + +/*** + * DESCRIPTION: + * Retrieves item attributes. + * + * PARAMETER(S): + * [I] hwnd : window handle + * [IO] lpLVItem : item info + * [I] isW : if TRUE, then lpLVItem is a LPLVITEMW, + * if FALSE, the lpLVItem is a LPLVITEMA. + * + * NOTE: + * This is the internal 'GetItem' interface -- it tries to + * be smart, and avoids text copies, if possible, by modifing + * lpLVItem->pszText to point to the text string. Please note + * that this is not always possible (e.g. OWNERDATA), so on + * entry you *must* supply valid values for pszText, and cchTextMax. + * The only difference to the documented interface is that upon + * return, you should use *only* the lpLVItem->pszText, rather than + * the buffer pointer you provided on input. Most code already does + * that, so it's not a problem. + * For the two cases when the text must be copied (that is, + * for LVM_GETITEM, and LVM_GETITEMTEXT), use LISTVIEW_GetItemExtT. + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_GetItemT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW) +{ + ITEMHDR callbackHdr = { LPSTR_TEXTCALLBACKW, I_IMAGECALLBACK }; + NMLVDISPINFOW dispInfo; + ITEM_INFO *lpItem; + ITEMHDR* pItemHdr; + HDPA hdpaSubItems; + INT isubitem; + + TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW); + + if (!lpLVItem || lpLVItem->iItem < 0 || lpLVItem->iItem >= infoPtr->nItemCount) + return FALSE; + + if (lpLVItem->mask == 0) return TRUE; + + /* make a local copy */ + isubitem = lpLVItem->iSubItem; + + /* a quick optimization if all we're asked is the focus state + * these queries are worth optimising since they are common, + * and can be answered in constant time, without the heavy accesses */ + if ( (lpLVItem->mask == LVIF_STATE) && (lpLVItem->stateMask == LVIS_FOCUSED) && + !(infoPtr->uCallbackMask & LVIS_FOCUSED) ) + { + lpLVItem->state = 0; + if (infoPtr->nFocusedItem == lpLVItem->iItem) + lpLVItem->state |= LVIS_FOCUSED; + return TRUE; + } + + ZeroMemory(&dispInfo, sizeof(dispInfo)); + + /* if the app stores all the data, handle it separately */ + if (infoPtr->dwStyle & LVS_OWNERDATA) + { + dispInfo.item.state = 0; + + /* apprently, we should not callback for lParam in LVS_OWNERDATA */ + if ((lpLVItem->mask & ~(LVIF_STATE | LVIF_PARAM)) || infoPtr->uCallbackMask) + { + /* NOTE: copy only fields which we _know_ are initialized, some apps + * depend on the uninitialized fields being 0 */ + dispInfo.item.mask = lpLVItem->mask & ~LVIF_PARAM; + dispInfo.item.iItem = lpLVItem->iItem; + dispInfo.item.iSubItem = isubitem; + if (lpLVItem->mask & LVIF_TEXT) + { + dispInfo.item.pszText = lpLVItem->pszText; + dispInfo.item.cchTextMax = lpLVItem->cchTextMax; + } + if (lpLVItem->mask & LVIF_STATE) + dispInfo.item.stateMask = lpLVItem->stateMask & infoPtr->uCallbackMask; + notify_dispinfoT(infoPtr, LVN_GETDISPINFOW, &dispInfo, isW); + dispInfo.item.stateMask = lpLVItem->stateMask; + if (lpLVItem->mask & (LVIF_GROUPID|LVIF_COLUMNS)) + { + /* full size structure expected - _WIN32IE >= 0x560 */ + *lpLVItem = dispInfo.item; + } + else if (lpLVItem->mask & LVIF_INDENT) + { + /* indent member expected - _WIN32IE >= 0x300 */ + memcpy(lpLVItem, &dispInfo.item, offsetof( LVITEMW, iGroupId )); + } + else + { + /* minimal structure expected */ + memcpy(lpLVItem, &dispInfo.item, offsetof( LVITEMW, iIndent )); + } + TRACE(" getdispinfo(1):lpLVItem=%s\n", debuglvitem_t(lpLVItem, isW)); + } + + /* make sure lParam is zeroed out */ + if (lpLVItem->mask & LVIF_PARAM) lpLVItem->lParam = 0; + + /* we store only a little state, so if we're not asked, we're done */ + if (!(lpLVItem->mask & LVIF_STATE) || isubitem) return TRUE; + + /* if focus is handled by us, report it */ + if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED ) + { + lpLVItem->state &= ~LVIS_FOCUSED; + if (infoPtr->nFocusedItem == lpLVItem->iItem) + lpLVItem->state |= LVIS_FOCUSED; + } + + /* and do the same for selection, if we handle it */ + if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED ) + { + lpLVItem->state &= ~LVIS_SELECTED; + if (ranges_contain(infoPtr->selectionRanges, lpLVItem->iItem)) + lpLVItem->state |= LVIS_SELECTED; + } + + return TRUE; + } + + /* find the item and subitem structures before we proceed */ + hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, lpLVItem->iItem); + lpItem = (ITEM_INFO *)DPA_GetPtr(hdpaSubItems, 0); + assert (lpItem); + + if (isubitem) + { + SUBITEM_INFO *lpSubItem = LISTVIEW_GetSubItemPtr(hdpaSubItems, isubitem); + pItemHdr = lpSubItem ? &lpSubItem->hdr : &callbackHdr; + if (!lpSubItem) + { + WARN(" iSubItem invalid (%08x), ignored.\n", isubitem); + isubitem = 0; + } + } + else + pItemHdr = &lpItem->hdr; + + /* Do we need to query the state from the app? */ + if ((lpLVItem->mask & LVIF_STATE) && infoPtr->uCallbackMask && isubitem == 0) + { + dispInfo.item.mask |= LVIF_STATE; + dispInfo.item.stateMask = infoPtr->uCallbackMask; + } + + /* Do we need to enquire about the image? */ + if ((lpLVItem->mask & LVIF_IMAGE) && pItemHdr->iImage == I_IMAGECALLBACK && + (isubitem == 0 || (infoPtr->dwLvExStyle & LVS_EX_SUBITEMIMAGES))) + { + dispInfo.item.mask |= LVIF_IMAGE; + dispInfo.item.iImage = I_IMAGECALLBACK; + } + + /* Apps depend on calling back for text if it is NULL or LPSTR_TEXTCALLBACKW */ + if ((lpLVItem->mask & LVIF_TEXT) && !is_textW(pItemHdr->pszText)) + { + dispInfo.item.mask |= LVIF_TEXT; + dispInfo.item.pszText = lpLVItem->pszText; + dispInfo.item.cchTextMax = lpLVItem->cchTextMax; + if (dispInfo.item.pszText && dispInfo.item.cchTextMax > 0) + *dispInfo.item.pszText = '\0'; + } + + /* If we don't have all the requested info, query the application */ + if (dispInfo.item.mask != 0) + { + dispInfo.item.iItem = lpLVItem->iItem; + dispInfo.item.iSubItem = lpLVItem->iSubItem; /* yes: the original subitem */ + dispInfo.item.lParam = lpItem->lParam; + notify_dispinfoT(infoPtr, LVN_GETDISPINFOW, &dispInfo, isW); + TRACE(" getdispinfo(2):item=%s\n", debuglvitem_t(&dispInfo.item, isW)); + } + + /* we should not store values for subitems */ + if (isubitem) dispInfo.item.mask &= ~LVIF_DI_SETITEM; + + /* Now, handle the iImage field */ + if (dispInfo.item.mask & LVIF_IMAGE) + { + lpLVItem->iImage = dispInfo.item.iImage; + if ((dispInfo.item.mask & LVIF_DI_SETITEM) && pItemHdr->iImage == I_IMAGECALLBACK) + pItemHdr->iImage = dispInfo.item.iImage; + } + else if (lpLVItem->mask & LVIF_IMAGE) + { + if(isubitem == 0 || (infoPtr->dwLvExStyle & LVS_EX_SUBITEMIMAGES)) + lpLVItem->iImage = pItemHdr->iImage; + else + lpLVItem->iImage = 0; + } + + /* The pszText field */ + if (dispInfo.item.mask & LVIF_TEXT) + { + if ((dispInfo.item.mask & LVIF_DI_SETITEM) && pItemHdr->pszText) + textsetptrT(&pItemHdr->pszText, dispInfo.item.pszText, isW); + + lpLVItem->pszText = dispInfo.item.pszText; + } + else if (lpLVItem->mask & LVIF_TEXT) + { + if (isW) lpLVItem->pszText = pItemHdr->pszText; + else textcpynT(lpLVItem->pszText, isW, pItemHdr->pszText, TRUE, lpLVItem->cchTextMax); + } + + /* if this is a subitem, we're done */ + if (isubitem) return TRUE; + + /* Next is the lParam field */ + if (dispInfo.item.mask & LVIF_PARAM) + { + lpLVItem->lParam = dispInfo.item.lParam; + if ((dispInfo.item.mask & LVIF_DI_SETITEM)) + lpItem->lParam = dispInfo.item.lParam; + } + else if (lpLVItem->mask & LVIF_PARAM) + lpLVItem->lParam = lpItem->lParam; + + /* ... the state field (this one is different due to uCallbackmask) */ + if (lpLVItem->mask & LVIF_STATE) + { + lpLVItem->state = lpItem->state; + if (dispInfo.item.mask & LVIF_STATE) + { + lpLVItem->state &= ~dispInfo.item.stateMask; + lpLVItem->state |= (dispInfo.item.state & dispInfo.item.stateMask); + } + if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_FOCUSED ) + { + lpLVItem->state &= ~LVIS_FOCUSED; + if (infoPtr->nFocusedItem == lpLVItem->iItem) + lpLVItem->state |= LVIS_FOCUSED; + } + if ( lpLVItem->stateMask & ~infoPtr->uCallbackMask & LVIS_SELECTED ) + { + lpLVItem->state &= ~LVIS_SELECTED; + if (ranges_contain(infoPtr->selectionRanges, lpLVItem->iItem)) + lpLVItem->state |= LVIS_SELECTED; + } + } + + /* and last, but not least, the indent field */ + if (lpLVItem->mask & LVIF_INDENT) + lpLVItem->iIndent = lpItem->iIndent; + + return TRUE; +} + +/*** + * DESCRIPTION: + * Retrieves item attributes. + * + * PARAMETER(S): + * [I] hwnd : window handle + * [IO] lpLVItem : item info + * [I] isW : if TRUE, then lpLVItem is a LPLVITEMW, + * if FALSE, the lpLVItem is a LPLVITEMA. + * + * NOTE: + * This is the external 'GetItem' interface -- it properly copies + * the text in the provided buffer. + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_GetItemExtT(LISTVIEW_INFO *infoPtr, LPLVITEMW lpLVItem, BOOL isW) +{ + LPWSTR pszText; + BOOL bResult; + + if (!lpLVItem || lpLVItem->iItem < 0 || lpLVItem->iItem >= infoPtr->nItemCount) + return FALSE; + + pszText = lpLVItem->pszText; + bResult = LISTVIEW_GetItemT(infoPtr, lpLVItem, isW); + if (bResult && lpLVItem->pszText != pszText) + textcpynT(pszText, isW, lpLVItem->pszText, isW, lpLVItem->cchTextMax); + lpLVItem->pszText = pszText; + + return bResult; +} + + +/*** + * DESCRIPTION: + * Retrieves the position (upper-left) of the listview control item. + * Note that for LVS_ICON style, the upper-left is that of the icon + * and not the bounding box. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nItem : item index + * [O] lpptPosition : coordinate information + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_GetItemPosition(LISTVIEW_INFO *infoPtr, INT nItem, LPPOINT lpptPosition) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + POINT Origin; + + TRACE("(nItem=%d, lpptPosition=%p)\n", nItem, lpptPosition); + + if (!lpptPosition || nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE; + + LISTVIEW_GetOrigin(infoPtr, &Origin); + LISTVIEW_GetItemOrigin(infoPtr, nItem, lpptPosition); + + if (uView == LVS_ICON) + { + lpptPosition->x += (infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2; + lpptPosition->y += ICON_TOP_PADDING; + } + lpptPosition->x += Origin.x; + lpptPosition->y += Origin.y; + + TRACE (" lpptPosition=%s\n", debugpoint(lpptPosition)); + return TRUE; +} + + +/*** + * DESCRIPTION: + * Retrieves the bounding rectangle for a listview control item. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nItem : item index + * [IO] lprc : bounding rectangle coordinates + * lprc->left specifies the portion of the item for which the bounding + * rectangle will be retrieved. + * + * LVIR_BOUNDS Returns the bounding rectangle of the entire item, + * including the icon and label. + * * + * * For LVS_ICON + * * Experiment shows that native control returns: + * * width = min (48, length of text line) + * * .left = position.x - (width - iconsize.cx)/2 + * * .right = .left + width + * * height = #lines of text * ntmHeight + icon height + 8 + * * .top = position.y - 2 + * * .bottom = .top + height + * * separation between items .y = itemSpacing.cy - height + * * .x = itemSpacing.cx - width + * LVIR_ICON Returns the bounding rectangle of the icon or small icon. + * * + * * For LVS_ICON + * * Experiment shows that native control returns: + * * width = iconSize.cx + 16 + * * .left = position.x - (width - iconsize.cx)/2 + * * .right = .left + width + * * height = iconSize.cy + 4 + * * .top = position.y - 2 + * * .bottom = .top + height + * * separation between items .y = itemSpacing.cy - height + * * .x = itemSpacing.cx - width + * LVIR_LABEL Returns the bounding rectangle of the item text. + * * + * * For LVS_ICON + * * Experiment shows that native control returns: + * * width = text length + * * .left = position.x - width/2 + * * .right = .left + width + * * height = ntmH * linecount + 2 + * * .top = position.y + iconSize.cy + 6 + * * .bottom = .top + height + * * separation between items .y = itemSpacing.cy - height + * * .x = itemSpacing.cx - width + * LVIR_SELECTBOUNDS Returns the union of the LVIR_ICON and LVIR_LABEL + * rectangles, but excludes columns in report view. + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + * + * NOTES + * Note that the bounding rectangle of the label in the LVS_ICON view depends + * upon whether the window has the focus currently and on whether the item + * is the one with the focus. Ensure that the control's record of which + * item has the focus agrees with the items' records. + */ +static BOOL LISTVIEW_GetItemRect(LISTVIEW_INFO *infoPtr, INT nItem, LPRECT lprc) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' }; + BOOL doLabel = TRUE, oversizedBox = FALSE; + POINT Position, Origin; + LVITEMW lvItem; + RECT label_rect; + + TRACE("(hwnd=%p, nItem=%d, lprc=%p)\n", infoPtr->hwndSelf, nItem, lprc); + + if (!lprc || nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE; + + LISTVIEW_GetOrigin(infoPtr, &Origin); + LISTVIEW_GetItemOrigin(infoPtr, nItem, &Position); + + /* Be smart and try to figure out the minimum we have to do */ + if (lprc->left == LVIR_ICON) doLabel = FALSE; + if (uView == LVS_REPORT && lprc->left == LVIR_BOUNDS) doLabel = FALSE; + if (uView == LVS_ICON && lprc->left != LVIR_ICON && + infoPtr->bFocus && LISTVIEW_GetItemState(infoPtr, nItem, LVIS_FOCUSED)) + oversizedBox = TRUE; + + /* get what we need from the item before hand, so we make + * only one request. This can speed up things, if data + * is stored on the app side */ + lvItem.mask = 0; + if (uView == LVS_REPORT) lvItem.mask |= LVIF_INDENT; + if (doLabel) lvItem.mask |= LVIF_TEXT; + lvItem.iItem = nItem; + lvItem.iSubItem = 0; + lvItem.pszText = szDispText; + lvItem.cchTextMax = DISP_TEXT_SIZE; + if (lvItem.mask && !LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE; + /* we got the state already up, simulate it here, to avoid a reget */ + if (uView == LVS_ICON && (lprc->left != LVIR_ICON)) + { + lvItem.mask |= LVIF_STATE; + lvItem.stateMask = LVIS_FOCUSED; + lvItem.state = (oversizedBox ? LVIS_FOCUSED : 0); + } + + if (uView == LVS_REPORT && (infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) && lprc->left == LVIR_SELECTBOUNDS) + lprc->left = LVIR_BOUNDS; + switch(lprc->left) + { + case LVIR_ICON: + LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, lprc, NULL); + break; + + case LVIR_LABEL: + LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, NULL, lprc); + break; + + case LVIR_BOUNDS: + LISTVIEW_GetItemMetrics(infoPtr, &lvItem, lprc, NULL, NULL, NULL); + break; + + case LVIR_SELECTBOUNDS: + LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, lprc, &label_rect); + UnionRect(lprc, lprc, &label_rect); + break; + + default: + WARN("Unknown value: %ld\n", lprc->left); + return FALSE; + } + + OffsetRect(lprc, Position.x + Origin.x, Position.y + Origin.y); + + TRACE(" rect=%s\n", debugrect(lprc)); + + return TRUE; +} + +/*** + * DESCRIPTION: + * Retrieves the spacing between listview control items. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [IO] lprc : rectangle to receive the output + * on input, lprc->top = nSubItem + * lprc->left = LVIR_ICON | LVIR_BOUNDS | LVIR_LABEL + * + * NOTE: for subItem = 0, we should return the bounds of the _entire_ item, + * not only those of the first column. + * Fortunately, LISTVIEW_GetItemMetrics does the right thing. + * + * RETURN: + * TRUE: success + * FALSE: failure + */ +static BOOL LISTVIEW_GetSubItemRect(LISTVIEW_INFO *infoPtr, INT nItem, LPRECT lprc) +{ + POINT Position; + LVITEMW lvItem; + + if (!lprc) return FALSE; + + TRACE("(nItem=%d, nSubItem=%ld)\n", nItem, lprc->top); + /* On WinNT, a subitem of '0' calls LISTVIEW_GetItemRect */ + if (lprc->top == 0) + return LISTVIEW_GetItemRect(infoPtr, nItem, lprc); + + if ((infoPtr->dwStyle & LVS_TYPEMASK) != LVS_REPORT) return FALSE; + + if (!LISTVIEW_GetItemPosition(infoPtr, nItem, &Position)) return FALSE; + + lvItem.mask = 0; + lvItem.iItem = nItem; + lvItem.iSubItem = lprc->top; + + if (lvItem.mask && !LISTVIEW_GetItemW(infoPtr, &lvItem)) return FALSE; + switch(lprc->left) + { + case LVIR_ICON: + LISTVIEW_GetItemMetrics(infoPtr, &lvItem, NULL, NULL, lprc, NULL); + break; + + case LVIR_LABEL: + case LVIR_BOUNDS: + LISTVIEW_GetItemMetrics(infoPtr, &lvItem, lprc, NULL, NULL, NULL); + break; + + default: + ERR("Unknown bounds=%ld\n", lprc->left); + return FALSE; + } + + OffsetRect(lprc, Position.x, Position.y); + return TRUE; +} + + +/*** + * DESCRIPTION: + * Retrieves the width of a label. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * + * RETURN: + * SUCCESS : string width (in pixels) + * FAILURE : zero + */ +static INT LISTVIEW_GetLabelWidth(LISTVIEW_INFO *infoPtr, INT nItem) +{ + WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' }; + LVITEMW lvItem; + + TRACE("(nItem=%d)\n", nItem); + + lvItem.mask = LVIF_TEXT; + lvItem.iItem = nItem; + lvItem.iSubItem = 0; + lvItem.pszText = szDispText; + lvItem.cchTextMax = DISP_TEXT_SIZE; + if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return 0; + + return LISTVIEW_GetStringWidthT(infoPtr, lvItem.pszText, TRUE); +} + +/*** + * DESCRIPTION: + * Retrieves the spacing between listview control items. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] bSmall : flag for small or large icon + * + * RETURN: + * Horizontal + vertical spacing + */ +static LONG LISTVIEW_GetItemSpacing(LISTVIEW_INFO *infoPtr, BOOL bSmall) +{ + LONG lResult; + + if (!bSmall) + { + lResult = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy); + } + else + { + if ((infoPtr->dwStyle & LVS_TYPEMASK) == LVS_ICON) + lResult = MAKELONG(DEFAULT_COLUMN_WIDTH, GetSystemMetrics(SM_CXSMICON)+HEIGHT_PADDING); + else + lResult = MAKELONG(infoPtr->nItemWidth, infoPtr->nItemHeight); + } + return lResult; +} + +/*** + * DESCRIPTION: + * Retrieves the state of a listview control item. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nItem : item index + * [I] uMask : state mask + * + * RETURN: + * State specified by the mask. + */ +static UINT LISTVIEW_GetItemState(LISTVIEW_INFO *infoPtr, INT nItem, UINT uMask) +{ + LVITEMW lvItem; + + if (nItem < 0 || nItem >= infoPtr->nItemCount) return 0; + + lvItem.iItem = nItem; + lvItem.iSubItem = 0; + lvItem.mask = LVIF_STATE; + lvItem.stateMask = uMask; + if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return 0; + + return lvItem.state & uMask; +} + +/*** + * DESCRIPTION: + * Retrieves the text of a listview control item or subitem. + * + * PARAMETER(S): + * [I] hwnd : window handle + * [I] nItem : item index + * [IO] lpLVItem : item information + * [I] isW : TRUE if lpLVItem is Unicode + * + * RETURN: + * SUCCESS : string length + * FAILURE : 0 + */ +static INT LISTVIEW_GetItemTextT(LISTVIEW_INFO *infoPtr, INT nItem, LPLVITEMW lpLVItem, BOOL isW) +{ + if (!lpLVItem || nItem < 0 || nItem >= infoPtr->nItemCount) return 0; + + lpLVItem->mask = LVIF_TEXT; + lpLVItem->iItem = nItem; + if (!LISTVIEW_GetItemExtT(infoPtr, lpLVItem, isW)) return 0; + + return textlenT(lpLVItem->pszText, isW); +} + +/*** + * DESCRIPTION: + * Searches for an item based on properties + relationships. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nItem : item index + * [I] uFlags : relationship flag + * + * RETURN: + * SUCCESS : item index + * FAILURE : -1 + */ +static INT LISTVIEW_GetNextItem(LISTVIEW_INFO *infoPtr, INT nItem, UINT uFlags) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + UINT uMask = 0; + LVFINDINFOW lvFindInfo; + INT nCountPerColumn; + INT nCountPerRow; + INT i; + + TRACE("nItem=%d, uFlags=%x, nItemCount=%d\n", nItem, uFlags, infoPtr->nItemCount); + if (nItem < -1 || nItem >= infoPtr->nItemCount) return -1; + + ZeroMemory(&lvFindInfo, sizeof(lvFindInfo)); + + if (uFlags & LVNI_CUT) + uMask |= LVIS_CUT; + + if (uFlags & LVNI_DROPHILITED) + uMask |= LVIS_DROPHILITED; + + if (uFlags & LVNI_FOCUSED) + uMask |= LVIS_FOCUSED; + + if (uFlags & LVNI_SELECTED) + uMask |= LVIS_SELECTED; + + /* if we're asked for the focused item, that's only one, + * so it's worth optimizing */ + if (uFlags & LVNI_FOCUSED) + { + if ((LISTVIEW_GetItemState(infoPtr, infoPtr->nFocusedItem, uMask) & uMask) != uMask) return -1; + return (infoPtr->nFocusedItem == nItem) ? -1 : infoPtr->nFocusedItem; + } + + if (uFlags & LVNI_ABOVE) + { + if ((uView == LVS_LIST) || (uView == LVS_REPORT)) + { + while (nItem >= 0) + { + nItem--; + if ((ListView_GetItemState(infoPtr->hwndSelf, nItem, uMask) & uMask) == uMask) + return nItem; + } + } + else + { + /* Special case for autoarrange - move 'til the top of a list */ + if (is_autoarrange(infoPtr)) + { + nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr); + while (nItem - nCountPerRow >= 0) + { + nItem -= nCountPerRow; + if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask) + return nItem; + } + return -1; + } + lvFindInfo.flags = LVFI_NEARESTXY; + lvFindInfo.vkDirection = VK_UP; + ListView_GetItemPosition(infoPtr->hwndSelf, nItem, &lvFindInfo.pt); + while ((nItem = ListView_FindItemW(infoPtr->hwndSelf, nItem, &lvFindInfo)) != -1) + { + if ((ListView_GetItemState(infoPtr->hwndSelf, nItem, uMask) & uMask) == uMask) + return nItem; + } + } + } + else if (uFlags & LVNI_BELOW) + { + if ((uView == LVS_LIST) || (uView == LVS_REPORT)) + { + while (nItem < infoPtr->nItemCount) + { + nItem++; + if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask) + return nItem; + } + } + else + { + /* Special case for autoarrange - move 'til the bottom of a list */ + if (is_autoarrange(infoPtr)) + { + nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr); + while (nItem + nCountPerRow < infoPtr->nItemCount ) + { + nItem += nCountPerRow; + if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask) + return nItem; + } + return -1; + } + lvFindInfo.flags = LVFI_NEARESTXY; + lvFindInfo.vkDirection = VK_DOWN; + ListView_GetItemPosition(infoPtr->hwndSelf, nItem, &lvFindInfo.pt); + while ((nItem = ListView_FindItemW(infoPtr->hwndSelf, nItem, &lvFindInfo)) != -1) + { + if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask) + return nItem; + } + } + } + else if (uFlags & LVNI_TOLEFT) + { + if (uView == LVS_LIST) + { + nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr); + while (nItem - nCountPerColumn >= 0) + { + nItem -= nCountPerColumn; + if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask) + return nItem; + } + } + else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON)) + { + /* Special case for autoarrange - move 'ti the beginning of a row */ + if (is_autoarrange(infoPtr)) + { + nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr); + while (nItem % nCountPerRow > 0) + { + nItem --; + if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask) + return nItem; + } + return -1; + } + lvFindInfo.flags = LVFI_NEARESTXY; + lvFindInfo.vkDirection = VK_LEFT; + ListView_GetItemPosition(infoPtr->hwndSelf, nItem, &lvFindInfo.pt); + while ((nItem = ListView_FindItemW(infoPtr->hwndSelf, nItem, &lvFindInfo)) != -1) + { + if ((ListView_GetItemState(infoPtr->hwndSelf, nItem, uMask) & uMask) == uMask) + return nItem; + } + } + } + else if (uFlags & LVNI_TORIGHT) + { + if (uView == LVS_LIST) + { + nCountPerColumn = LISTVIEW_GetCountPerColumn(infoPtr); + while (nItem + nCountPerColumn < infoPtr->nItemCount) + { + nItem += nCountPerColumn; + if ((ListView_GetItemState(infoPtr->hwndSelf, nItem, uMask) & uMask) == uMask) + return nItem; + } + } + else if ((uView == LVS_SMALLICON) || (uView == LVS_ICON)) + { + /* Special case for autoarrange - move 'til the end of a row */ + if (is_autoarrange(infoPtr)) + { + nCountPerRow = LISTVIEW_GetCountPerRow(infoPtr); + while (nItem % nCountPerRow < nCountPerRow - 1 ) + { + nItem ++; + if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask) + return nItem; + } + return -1; + } + lvFindInfo.flags = LVFI_NEARESTXY; + lvFindInfo.vkDirection = VK_RIGHT; + ListView_GetItemPosition(infoPtr->hwndSelf, nItem, &lvFindInfo.pt); + while ((nItem = ListView_FindItemW(infoPtr->hwndSelf, nItem, &lvFindInfo)) != -1) + { + if ((LISTVIEW_GetItemState(infoPtr, nItem, uMask) & uMask) == uMask) + return nItem; + } + } + } + else + { + nItem++; + + /* search by index */ + for (i = nItem; i < infoPtr->nItemCount; i++) + { + if ((LISTVIEW_GetItemState(infoPtr, i, uMask) & uMask) == uMask) + return i; + } + } + + return -1; +} + +/* LISTVIEW_GetNumberOfWorkAreas */ + +/*** + * DESCRIPTION: + * Retrieves the origin coordinates when in icon or small icon display mode. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [O] lpptOrigin : coordinate information + * + * RETURN: + * None. + */ +static void LISTVIEW_GetOrigin(LISTVIEW_INFO *infoPtr, LPPOINT lpptOrigin) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + INT nHorzPos = 0, nVertPos = 0; + SCROLLINFO scrollInfo; + + scrollInfo.cbSize = sizeof(SCROLLINFO); + scrollInfo.fMask = SIF_POS; + + if (GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo)) + nHorzPos = scrollInfo.nPos; + if (GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo)) + nVertPos = scrollInfo.nPos; + + TRACE("nHorzPos=%d, nVertPos=%d\n", nHorzPos, nVertPos); + + lpptOrigin->x = infoPtr->rcList.left; + lpptOrigin->y = infoPtr->rcList.top; + if (uView == LVS_LIST) + nHorzPos *= infoPtr->nItemWidth; + else if (uView == LVS_REPORT) + nVertPos *= infoPtr->nItemHeight; + + lpptOrigin->x -= nHorzPos; + lpptOrigin->y -= nVertPos; + + TRACE(" origin=%s\n", debugpoint(lpptOrigin)); +} + +/*** + * DESCRIPTION: + * Retrieves the width of a string. + * + * PARAMETER(S): + * [I] hwnd : window handle + * [I] lpszText : text string to process + * [I] isW : TRUE if lpszText is Unicode, FALSE otherwise + * + * RETURN: + * SUCCESS : string width (in pixels) + * FAILURE : zero + */ +static INT LISTVIEW_GetStringWidthT(LISTVIEW_INFO *infoPtr, LPCWSTR lpszText, BOOL isW) +{ + SIZE stringSize; + + stringSize.cx = 0; + if (is_textT(lpszText, isW)) + { + HFONT hFont = infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont; + HDC hdc = GetDC(infoPtr->hwndSelf); + HFONT hOldFont = SelectObject(hdc, hFont); + + if (isW) + GetTextExtentPointW(hdc, lpszText, lstrlenW(lpszText), &stringSize); + else + GetTextExtentPointA(hdc, (LPCSTR)lpszText, lstrlenA((LPCSTR)lpszText), &stringSize); + SelectObject(hdc, hOldFont); + ReleaseDC(infoPtr->hwndSelf, hdc); + } + return stringSize.cx; +} + +/*** + * DESCRIPTION: + * Determines which listview item is located at the specified position. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [IO] lpht : hit test information + * [I] subitem : fill out iSubItem. + * [I] select : return the index only if the hit selects the item + * + * NOTE: + * (mm 20001022): We must not allow iSubItem to be touched, for + * an app might pass only a structure with space up to iItem! + * (MS Office 97 does that for instance in the file open dialog) + * + * RETURN: + * SUCCESS : item index + * FAILURE : -1 + */ +static INT LISTVIEW_HitTest(LISTVIEW_INFO *infoPtr, LPLVHITTESTINFO lpht, BOOL subitem, BOOL select) +{ + WCHAR szDispText[DISP_TEXT_SIZE] = { '\0' }; + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + RECT rcBox, rcBounds, rcState, rcIcon, rcLabel, rcSearch; + POINT Origin, Position, opt; + LVITEMW lvItem; + ITERATOR i; + INT iItem; + + TRACE("(pt=%s, subitem=%d, select=%d)\n", debugpoint(&lpht->pt), subitem, select); + + lpht->flags = 0; + lpht->iItem = -1; + if (subitem) lpht->iSubItem = 0; + + if (infoPtr->rcList.left > lpht->pt.x) + lpht->flags |= LVHT_TOLEFT; + else if (infoPtr->rcList.right < lpht->pt.x) + lpht->flags |= LVHT_TORIGHT; + + if (infoPtr->rcList.top > lpht->pt.y) + lpht->flags |= LVHT_ABOVE; + else if (infoPtr->rcList.bottom < lpht->pt.y) + lpht->flags |= LVHT_BELOW; + + TRACE("lpht->flags=0x%x\n", lpht->flags); + if (lpht->flags) return -1; + + lpht->flags |= LVHT_NOWHERE; + + LISTVIEW_GetOrigin(infoPtr, &Origin); + + /* first deal with the large items */ + rcSearch.left = lpht->pt.x; + rcSearch.top = lpht->pt.y; + rcSearch.right = rcSearch.left + 1; + rcSearch.bottom = rcSearch.top + 1; + + iterator_frameditems(&i, infoPtr, &rcSearch); + iterator_next(&i); /* go to first item in the sequence */ + iItem = i.nItem; + iterator_destroy(&i); + + TRACE("lpht->iItem=%d\n", iItem); + if (iItem == -1) return -1; + + lvItem.mask = LVIF_STATE | LVIF_TEXT; + if (uView == LVS_REPORT) lvItem.mask |= LVIF_INDENT; + lvItem.stateMask = LVIS_STATEIMAGEMASK; + if (uView == LVS_ICON) lvItem.stateMask |= LVIS_FOCUSED; + lvItem.iItem = iItem; + lvItem.iSubItem = 0; + lvItem.pszText = szDispText; + lvItem.cchTextMax = DISP_TEXT_SIZE; + if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) return -1; + if (!infoPtr->bFocus) lvItem.state &= ~LVIS_FOCUSED; + + LISTVIEW_GetItemMetrics(infoPtr, &lvItem, &rcBox, &rcState, &rcIcon, &rcLabel); + LISTVIEW_GetItemOrigin(infoPtr, iItem, &Position); + opt.x = lpht->pt.x - Position.x - Origin.x; + opt.y = lpht->pt.y - Position.y - Origin.y; + + if (uView == LVS_REPORT) + rcBounds = rcBox; + else + UnionRect(&rcBounds, &rcIcon, &rcLabel); + TRACE("rcBounds=%s\n", debugrect(&rcBounds)); + if (!PtInRect(&rcBounds, opt)) return -1; + + if (PtInRect(&rcIcon, opt)) + lpht->flags |= LVHT_ONITEMICON; + else if (PtInRect(&rcLabel, opt)) + lpht->flags |= LVHT_ONITEMLABEL; + else if (infoPtr->himlState && ((lvItem.state & LVIS_STATEIMAGEMASK) >> 12) && PtInRect(&rcState, opt)) + lpht->flags |= LVHT_ONITEMSTATEICON; + if (lpht->flags & LVHT_ONITEM) + lpht->flags &= ~LVHT_NOWHERE; + + TRACE("lpht->flags=0x%x\n", lpht->flags); + if (uView == LVS_REPORT && subitem) + { + INT j; + + rcBounds.right = rcBounds.left; + for (j = 0; j < DPA_GetPtrCount(infoPtr->hdpaColumns); j++) + { + rcBounds.left = rcBounds.right; + rcBounds.right += LISTVIEW_GetColumnWidth(infoPtr, j); + if (PtInRect(&rcBounds, opt)) + { + lpht->iSubItem = j; + break; + } + } + } + + if (select && !(uView == LVS_REPORT && + ((infoPtr->dwLvExStyle & LVS_EX_FULLROWSELECT) || + (infoPtr->dwStyle & LVS_OWNERDRAWFIXED)))) + { + if (uView == LVS_REPORT) + { + UnionRect(&rcBounds, &rcIcon, &rcLabel); + UnionRect(&rcBounds, &rcBounds, &rcState); + } + if (!PtInRect(&rcBounds, opt)) iItem = -1; + } + return lpht->iItem = iItem; +} + + +/* LISTVIEW_InsertCompare: callback routine for comparing pszText members of the LV_ITEMS + in a LISTVIEW on insert. Passed to DPA_Sort in LISTVIEW_InsertItem. + This function should only be used for inserting items into a sorted list (LVM_INSERTITEM) + and not during the processing of a LVM_SORTITEMS message. Applications should provide + their own sort proc. when sending LVM_SORTITEMS. +*/ +/* Platform SDK: + (remarks on LVITEM: LVM_INSERTITEM will insert the new item in the proper sort postion... + if: + LVS_SORTXXX must be specified, + LVS_OWNERDRAW is not set, + .pszText is not LPSTR_TEXTCALLBACK. + + (LVS_SORT* flags): "For the LVS_SORTASCENDING... styles, item indices + are sorted based on item text..." +*/ +static INT WINAPI LISTVIEW_InsertCompare( LPVOID first, LPVOID second, LPARAM lParam) +{ + ITEM_INFO* lv_first = (ITEM_INFO*) DPA_GetPtr( (HDPA)first, 0 ); + ITEM_INFO* lv_second = (ITEM_INFO*) DPA_GetPtr( (HDPA)second, 0 ); + INT cmpv = textcmpWT(lv_first->hdr.pszText, lv_second->hdr.pszText, TRUE); + + /* if we're sorting descending, negate the return value */ + return (((LISTVIEW_INFO *)lParam)->dwStyle & LVS_SORTDESCENDING) ? -cmpv : cmpv; +} + +/*** + * DESCRIPTION: + * Inserts a new item in the listview control. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] lpLVItem : item information + * [I] isW : TRUE if lpLVItem is Unicode, FALSE if it's ANSI + * + * RETURN: + * SUCCESS : new item index + * FAILURE : -1 + */ +static INT LISTVIEW_InsertItemT(LISTVIEW_INFO *infoPtr, const LVITEMW *lpLVItem, BOOL isW) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + INT nItem; + HDPA hdpaSubItems; + NMLISTVIEW nmlv; + ITEM_INFO *lpItem; + BOOL is_sorted, has_changed; + LVITEMW item; + + TRACE("(lpLVItem=%s, isW=%d)\n", debuglvitem_t(lpLVItem, isW), isW); + + if (infoPtr->dwStyle & LVS_OWNERDATA) return infoPtr->nItemCount++; + + /* make sure it's an item, and not a subitem; cannot insert a subitem */ + if (!lpLVItem || lpLVItem->iItem < 0 || lpLVItem->iSubItem) return -1; + + if (!is_assignable_item(lpLVItem, infoPtr->dwStyle)) return -1; + + if (!(lpItem = (ITEM_INFO *)Alloc(sizeof(ITEM_INFO)))) return -1; + + /* insert item in listview control data structure */ + if ( !(hdpaSubItems = DPA_Create(8)) ) goto fail; + if ( !DPA_SetPtr(hdpaSubItems, 0, lpItem) ) assert (FALSE); + + is_sorted = (infoPtr->dwStyle & (LVS_SORTASCENDING | LVS_SORTDESCENDING)) && + !(infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (LPSTR_TEXTCALLBACKW != lpLVItem->pszText); + + nItem = is_sorted ? infoPtr->nItemCount : min(lpLVItem->iItem, infoPtr->nItemCount); + TRACE(" inserting at %d, sorted=%d, count=%d, iItem=%d\n", nItem, is_sorted, infoPtr->nItemCount, lpLVItem->iItem); + nItem = DPA_InsertPtr( infoPtr->hdpaItems, nItem, hdpaSubItems ); + if (nItem == -1) goto fail; + infoPtr->nItemCount++; + + /* shift indices first so they don't get tangled */ + LISTVIEW_ShiftIndices(infoPtr, nItem, 1); + + /* set the item attributes */ + if (lpLVItem->mask & (LVIF_GROUPID|LVIF_COLUMNS)) + { + /* full size structure expected - _WIN32IE >= 0x560 */ + item = *lpLVItem; + } + else if (lpLVItem->mask & LVIF_INDENT) + { + /* indent member expected - _WIN32IE >= 0x300 */ + memcpy(&item, lpLVItem, offsetof( LVITEMW, iGroupId )); + } + else + { + /* minimal structure expected */ + memcpy(&item, lpLVItem, offsetof( LVITEMW, iIndent )); + } + item.iItem = nItem; + if (infoPtr->dwLvExStyle & LVS_EX_CHECKBOXES) item.state &= ~LVIS_STATEIMAGEMASK; + if (!set_main_item(infoPtr, &item, TRUE, isW, &has_changed)) goto undo; + + /* if we're sorted, sort the list, and update the index */ + if (is_sorted) + { + DPA_Sort( infoPtr->hdpaItems, LISTVIEW_InsertCompare, (LPARAM)infoPtr ); + nItem = DPA_GetPtrIndex( infoPtr->hdpaItems, hdpaSubItems ); + assert(nItem != -1); + } + + /* make room for the position, if we are in the right mode */ + if ((uView == LVS_SMALLICON) || (uView == LVS_ICON)) + { + if (DPA_InsertPtr(infoPtr->hdpaPosX, nItem, 0) == -1) + goto undo; + if (DPA_InsertPtr(infoPtr->hdpaPosY, nItem, 0) == -1) + { + DPA_DeletePtr(infoPtr->hdpaPosX, nItem); + goto undo; + } + } + + /* send LVN_INSERTITEM notification */ + ZeroMemory(&nmlv, sizeof(NMLISTVIEW)); + nmlv.iItem = nItem; + nmlv.lParam = lpItem->lParam; + notify_listview(infoPtr, LVN_INSERTITEM, &nmlv); + + /* align items (set position of each item) */ + if ((uView == LVS_SMALLICON || uView == LVS_ICON)) + { + POINT pt; + + if (infoPtr->dwStyle & LVS_ALIGNLEFT) + LISTVIEW_NextIconPosLeft(infoPtr, &pt); + else + LISTVIEW_NextIconPosTop(infoPtr, &pt); + + LISTVIEW_MoveIconTo(infoPtr, nItem, &pt, TRUE); + } + + /* now is the invalidation fun */ + LISTVIEW_ScrollOnInsert(infoPtr, nItem, 1); + return nItem; + +undo: + LISTVIEW_ShiftIndices(infoPtr, nItem, -1); + DPA_DeletePtr(infoPtr->hdpaItems, nItem); + infoPtr->nItemCount--; +fail: + DPA_DeletePtr(hdpaSubItems, 0); + DPA_Destroy (hdpaSubItems); + Free (lpItem); + return -1; +} + +/*** + * DESCRIPTION: + * Redraws a range of items. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nFirst : first item + * [I] nLast : last item + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_RedrawItems(LISTVIEW_INFO *infoPtr, INT nFirst, INT nLast) +{ + INT i; + + if (nLast < nFirst || min(nFirst, nLast) < 0 || + max(nFirst, nLast) >= infoPtr->nItemCount) + return FALSE; + + for (i = nFirst; i <= nLast; i++) + LISTVIEW_InvalidateItem(infoPtr, i); + + return TRUE; +} + +/*** + * DESCRIPTION: + * Scroll the content of a listview. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] dx : horizontal scroll amount in pixels + * [I] dy : vertical scroll amount in pixels + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + * + * COMMENTS: + * If the control is in report mode (LVS_REPORT) the control can + * be scrolled only in line increments. "dy" will be rounded to the + * nearest number of pixels that are a whole line. Ex: if line height + * is 16 and an 8 is passed, the list will be scrolled by 16. If a 7 + * is passed the the scroll will be 0. (per MSDN 7/2002) + * + * For: (per experimentaion with native control and CSpy ListView) + * LVS_ICON dy=1 = 1 pixel (vertical only) + * dx ignored + * LVS_SMALLICON dy=1 = 1 pixel (vertical only) + * dx ignored + * LVS_LIST dx=1 = 1 column (horizontal only) + * but will only scroll 1 column per message + * no matter what the value. + * dy must be 0 or FALSE returned. + * LVS_REPORT dx=1 = 1 pixel + * dy= see above + * + */ +static BOOL LISTVIEW_Scroll(LISTVIEW_INFO *infoPtr, INT dx, INT dy) +{ + switch(infoPtr->dwStyle & LVS_TYPEMASK) { + case LVS_REPORT: + dy += (dy < 0 ? -1 : 1) * infoPtr->nItemHeight/2; + dy /= infoPtr->nItemHeight; + break; + case LVS_LIST: + if (dy != 0) return FALSE; + break; + default: /* icon */ + dx = 0; + break; + } + + if (dx != 0) LISTVIEW_HScroll(infoPtr, SB_INTERNAL, dx, 0); + if (dy != 0) LISTVIEW_VScroll(infoPtr, SB_INTERNAL, dy, 0); + + return TRUE; +} + +/*** + * DESCRIPTION: + * Sets the background color. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] clrBk : background color + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_SetBkColor(LISTVIEW_INFO *infoPtr, COLORREF clrBk) +{ + TRACE("(clrBk=%lx)\n", clrBk); + + if(infoPtr->clrBk != clrBk) { + if (infoPtr->clrBk != CLR_NONE) DeleteObject(infoPtr->hBkBrush); + infoPtr->clrBk = clrBk; + if (clrBk == CLR_NONE) + infoPtr->hBkBrush = (HBRUSH)GetClassLongPtrW(infoPtr->hwndSelf, GCLP_HBRBACKGROUND); + else + infoPtr->hBkBrush = CreateSolidBrush(clrBk); + LISTVIEW_InvalidateList(infoPtr); + } + + return TRUE; +} + +/* LISTVIEW_SetBkImage */ + +/*** Helper for {Insert,Set}ColumnT *only* */ +static void column_fill_hditem(LISTVIEW_INFO *infoPtr, HDITEMW *lphdi, INT nColumn, const LVCOLUMNW *lpColumn, BOOL isW) +{ + if (lpColumn->mask & LVCF_FMT) + { + /* format member is valid */ + lphdi->mask |= HDI_FORMAT; + + /* set text alignment (leftmost column must be left-aligned) */ + if (nColumn == 0 || (lpColumn->fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT) + lphdi->fmt |= HDF_LEFT; + else if ((lpColumn->fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_RIGHT) + lphdi->fmt |= HDF_RIGHT; + else if ((lpColumn->fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_CENTER) + lphdi->fmt |= HDF_CENTER; + + if (lpColumn->fmt & LVCFMT_BITMAP_ON_RIGHT) + lphdi->fmt |= HDF_BITMAP_ON_RIGHT; + + if (lpColumn->fmt & LVCFMT_COL_HAS_IMAGES) + { + lphdi->fmt |= HDF_IMAGE; + lphdi->iImage = I_IMAGECALLBACK; + } + } + + if (lpColumn->mask & LVCF_WIDTH) + { + lphdi->mask |= HDI_WIDTH; + if(lpColumn->cx == LVSCW_AUTOSIZE_USEHEADER) + { + /* make it fill the remainder of the controls width */ + RECT rcHeader; + INT item_index; + + for(item_index = 0; item_index < (nColumn - 1); item_index++) + { + LISTVIEW_GetHeaderRect(infoPtr, item_index, &rcHeader); + lphdi->cxy += rcHeader.right - rcHeader.left; + } + + /* retrieve the layout of the header */ + GetClientRect(infoPtr->hwndSelf, &rcHeader); + TRACE("start cxy=%d rcHeader=%s\n", lphdi->cxy, debugrect(&rcHeader)); + + lphdi->cxy = (rcHeader.right - rcHeader.left) - lphdi->cxy; + } + else + lphdi->cxy = lpColumn->cx; + } + + if (lpColumn->mask & LVCF_TEXT) + { + lphdi->mask |= HDI_TEXT | HDI_FORMAT; + lphdi->fmt |= HDF_STRING; + lphdi->pszText = lpColumn->pszText; + lphdi->cchTextMax = textlenT(lpColumn->pszText, isW); + } + + if (lpColumn->mask & LVCF_IMAGE) + { + lphdi->mask |= HDI_IMAGE; + lphdi->iImage = lpColumn->iImage; + } + + if (lpColumn->mask & LVCF_ORDER) + { + lphdi->mask |= HDI_ORDER; + lphdi->iOrder = lpColumn->iOrder; + } +} + + +/*** + * DESCRIPTION: + * Inserts a new column. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nColumn : column index + * [I] lpColumn : column information + * [I] isW : TRUE if lpColumn is Unicode, FALSE otherwise + * + * RETURN: + * SUCCESS : new column index + * FAILURE : -1 + */ +static INT LISTVIEW_InsertColumnT(LISTVIEW_INFO *infoPtr, INT nColumn, + const LVCOLUMNW *lpColumn, BOOL isW) +{ + COLUMN_INFO *lpColumnInfo; + INT nNewColumn; + HDITEMW hdi; + + TRACE("(nColumn=%d, lpColumn=%s, isW=%d)\n", nColumn, debuglvcolumn_t(lpColumn, isW), isW); + + if (!lpColumn || nColumn < 0) return -1; + nColumn = min(nColumn, DPA_GetPtrCount(infoPtr->hdpaColumns)); + + ZeroMemory(&hdi, sizeof(HDITEMW)); + column_fill_hditem(infoPtr, &hdi, nColumn, lpColumn, isW); + + /* insert item in header control */ + nNewColumn = SendMessageW(infoPtr->hwndHeader, + isW ? HDM_INSERTITEMW : HDM_INSERTITEMA, + (WPARAM)nColumn, (LPARAM)&hdi); + if (nNewColumn == -1) return -1; + if (nNewColumn != nColumn) ERR("nColumn=%d, nNewColumn=%d\n", nColumn, nNewColumn); + + /* create our own column info */ + if (!(lpColumnInfo = Alloc(sizeof(COLUMN_INFO)))) goto fail; + if (DPA_InsertPtr(infoPtr->hdpaColumns, nNewColumn, lpColumnInfo) == -1) goto fail; + + if (lpColumn->mask & LVCF_FMT) lpColumnInfo->fmt = lpColumn->fmt; + if (!Header_GetItemRect(infoPtr->hwndHeader, nNewColumn, &lpColumnInfo->rcHeader)) goto fail; + + /* now we have to actually adjust the data */ + if (!(infoPtr->dwStyle & LVS_OWNERDATA) && infoPtr->nItemCount > 0) + { + SUBITEM_INFO *lpSubItem; + HDPA hdpaSubItems; + INT nItem, i; + + for (nItem = 0; nItem < infoPtr->nItemCount; nItem++) + { + hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, nItem); + for (i = 1; i < DPA_GetPtrCount(hdpaSubItems); i++) + { + lpSubItem = (SUBITEM_INFO *)DPA_GetPtr(hdpaSubItems, i); + if (lpSubItem->iSubItem >= nNewColumn) + lpSubItem->iSubItem++; + } + } + } + + /* make space for the new column */ + LISTVIEW_ScrollColumns(infoPtr, nNewColumn + 1, lpColumnInfo->rcHeader.right - lpColumnInfo->rcHeader.left); + + return nNewColumn; + +fail: + if (nNewColumn != -1) SendMessageW(infoPtr->hwndHeader, HDM_DELETEITEM, nNewColumn, 0); + if (lpColumnInfo) + { + DPA_DeletePtr(infoPtr->hdpaColumns, nNewColumn); + Free(lpColumnInfo); + } + return -1; +} + +/*** + * DESCRIPTION: + * Sets the attributes of a header item. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nColumn : column index + * [I] lpColumn : column attributes + * [I] isW: if TRUE, the lpColumn is a LPLVCOLUMNW, else it is a LPLVCOLUMNA + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_SetColumnT(LISTVIEW_INFO *infoPtr, INT nColumn, + const LVCOLUMNW *lpColumn, BOOL isW) +{ + HDITEMW hdi, hdiget; + BOOL bResult; + + TRACE("(nColumn=%d, lpColumn=%s, isW=%d)\n", nColumn, debuglvcolumn_t(lpColumn, isW), isW); + + if (!lpColumn || nColumn < 0 || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE; + + ZeroMemory(&hdi, sizeof(HDITEMW)); + if (lpColumn->mask & LVCF_FMT) + { + hdi.mask |= HDI_FORMAT; + hdiget.mask = HDI_FORMAT; + if (Header_GetItemW(infoPtr->hwndHeader, nColumn, &hdiget)) + hdi.fmt = hdiget.fmt & HDF_STRING; + } + column_fill_hditem(infoPtr, &hdi, nColumn, lpColumn, isW); + + /* set header item attributes */ + bResult = SendMessageW(infoPtr->hwndHeader, isW ? HDM_SETITEMW : HDM_SETITEMA, (WPARAM)nColumn, (LPARAM)&hdi); + if (!bResult) return FALSE; + + if (lpColumn->mask & LVCF_FMT) + { + COLUMN_INFO *lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, nColumn); + int oldFmt = lpColumnInfo->fmt; + + lpColumnInfo->fmt = lpColumn->fmt; + if ((oldFmt ^ lpColumn->fmt) & (LVCFMT_JUSTIFYMASK | LVCFMT_IMAGE)) + { + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + if (uView == LVS_REPORT) LISTVIEW_InvalidateColumn(infoPtr, nColumn); + } + } + + return TRUE; +} + +/*** + * DESCRIPTION: + * Sets the column order array + * + * PARAMETERS: + * [I] infoPtr : valid pointer to the listview structure + * [I] iCount : number of elements in column order array + * [I] lpiArray : pointer to column order array + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_SetColumnOrderArray(LISTVIEW_INFO *infoPtr, INT iCount, const INT *lpiArray) +{ + FIXME("iCount %d lpiArray %p\n", iCount, lpiArray); + + if (!lpiArray) + return FALSE; + + return TRUE; +} + + +/*** + * DESCRIPTION: + * Sets the width of a column + * + * PARAMETERS: + * [I] infoPtr : valid pointer to the listview structure + * [I] nColumn : column index + * [I] cx : column width + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_SetColumnWidth(LISTVIEW_INFO *infoPtr, INT nColumn, INT cx) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + WCHAR szDispText[DISP_TEXT_SIZE] = { 0 }; + INT max_cx = 0; + HDITEMW hdi; + + TRACE("(nColumn=%d, cx=%d\n", nColumn, cx); + + /* set column width only if in report or list mode */ + if (uView != LVS_REPORT && uView != LVS_LIST) return FALSE; + + /* take care of invalid cx values */ + if(uView == LVS_REPORT && cx < -2) cx = LVSCW_AUTOSIZE; + else if (uView == LVS_LIST && cx < 1) return FALSE; + + /* resize all columns if in LVS_LIST mode */ + if(uView == LVS_LIST) + { + infoPtr->nItemWidth = cx; + LISTVIEW_InvalidateList(infoPtr); + return TRUE; + } + + if (nColumn < 0 || nColumn >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return FALSE; + + if (cx == LVSCW_AUTOSIZE || (cx == LVSCW_AUTOSIZE_USEHEADER && nColumn < DPA_GetPtrCount(infoPtr->hdpaColumns) -1)) + { + INT nLabelWidth; + LVITEMW lvItem; + + lvItem.mask = LVIF_TEXT; + lvItem.iItem = 0; + lvItem.iSubItem = nColumn; + lvItem.pszText = szDispText; + lvItem.cchTextMax = DISP_TEXT_SIZE; + for (; lvItem.iItem < infoPtr->nItemCount; lvItem.iItem++) + { + if (!LISTVIEW_GetItemW(infoPtr, &lvItem)) continue; + nLabelWidth = LISTVIEW_GetStringWidthT(infoPtr, lvItem.pszText, TRUE); + if (max_cx < nLabelWidth) max_cx = nLabelWidth; + } + if (infoPtr->himlSmall && (nColumn == 0 || (LISTVIEW_GetColumnInfo(infoPtr, nColumn)->fmt & LVCFMT_IMAGE))) + max_cx += infoPtr->iconSize.cx; + max_cx += TRAILING_LABEL_PADDING; + } + + /* autosize based on listview items width */ + if(cx == LVSCW_AUTOSIZE) + cx = max_cx; + else if(cx == LVSCW_AUTOSIZE_USEHEADER) + { + /* if iCol is the last column make it fill the remainder of the controls width */ + if(nColumn == DPA_GetPtrCount(infoPtr->hdpaColumns) - 1) + { + RECT rcHeader; + POINT Origin; + + LISTVIEW_GetOrigin(infoPtr, &Origin); + LISTVIEW_GetHeaderRect(infoPtr, nColumn, &rcHeader); + + cx = infoPtr->rcList.right - Origin.x - rcHeader.left; + } + else + { + /* Despite what the MS docs say, if this is not the last + column, then MS resizes the column to the width of the + largest text string in the column, including headers + and items. This is different from LVSCW_AUTOSIZE in that + LVSCW_AUTOSIZE ignores the header string length. */ + cx = 0; + + /* retrieve header text */ + hdi.mask = HDI_TEXT; + hdi.cchTextMax = DISP_TEXT_SIZE; + hdi.pszText = szDispText; + if (Header_GetItemW(infoPtr->hwndHeader, nColumn, (LPARAM)&hdi)) + { + HDC hdc = GetDC(infoPtr->hwndSelf); + HFONT old_font = SelectObject(hdc, (HFONT)SendMessageW(infoPtr->hwndHeader, WM_GETFONT, 0, 0)); + SIZE size; + + if (GetTextExtentPoint32W(hdc, hdi.pszText, lstrlenW(hdi.pszText), &size)) + cx = size.cx + TRAILING_HEADER_PADDING; + /* FIXME: Take into account the header image, if one is present */ + SelectObject(hdc, old_font); + ReleaseDC(infoPtr->hwndSelf, hdc); + } + cx = max (cx, max_cx); + } + } + + if (cx < 0) return FALSE; + + /* call header to update the column change */ + hdi.mask = HDI_WIDTH; + hdi.cxy = cx; + TRACE("hdi.cxy=%d\n", hdi.cxy); + return Header_SetItemW(infoPtr->hwndHeader, nColumn, (LPARAM)&hdi); +} + +/*** + * Creates the checkbox imagelist. Helper for LISTVIEW_SetExtendedListViewStyle + * + */ +static HIMAGELIST LISTVIEW_CreateCheckBoxIL(LISTVIEW_INFO *infoPtr) +{ + HDC hdc_wnd, hdc; + HBITMAP hbm_im, hbm_mask, hbm_orig; + RECT rc; + HBRUSH hbr_white = GetStockObject(WHITE_BRUSH); + HBRUSH hbr_black = GetStockObject(BLACK_BRUSH); + HIMAGELIST himl; + + himl = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), + ILC_COLOR | ILC_MASK, 2, 2); + hdc_wnd = GetDC(infoPtr->hwndSelf); + hdc = CreateCompatibleDC(hdc_wnd); + hbm_im = CreateCompatibleBitmap(hdc_wnd, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON)); + hbm_mask = CreateBitmap(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 1, 1, NULL); + ReleaseDC(infoPtr->hwndSelf, hdc_wnd); + + rc.left = rc.top = 0; + rc.right = GetSystemMetrics(SM_CXSMICON); + rc.bottom = GetSystemMetrics(SM_CYSMICON); + + hbm_orig = SelectObject(hdc, hbm_mask); + FillRect(hdc, &rc, hbr_white); + InflateRect(&rc, -3, -3); + FillRect(hdc, &rc, hbr_black); + + SelectObject(hdc, hbm_im); + DrawFrameControl(hdc, &rc, DFC_BUTTON, DFCS_BUTTONCHECK | DFCS_MONO); + SelectObject(hdc, hbm_orig); + ImageList_Add(himl, hbm_im, hbm_mask); + + SelectObject(hdc, hbm_im); + DrawFrameControl(hdc, &rc, DFC_BUTTON, DFCS_BUTTONCHECK | DFCS_MONO | DFCS_CHECKED); + SelectObject(hdc, hbm_orig); + ImageList_Add(himl, hbm_im, hbm_mask); + + DeleteObject(hbm_mask); + DeleteObject(hbm_im); + DeleteDC(hdc); + + return himl; +} + +/*** + * DESCRIPTION: + * Sets the extended listview style. + * + * PARAMETERS: + * [I] infoPtr : valid pointer to the listview structure + * [I] dwMask : mask + * [I] dwStyle : style + * + * RETURN: + * SUCCESS : previous style + * FAILURE : 0 + */ +static DWORD LISTVIEW_SetExtendedListViewStyle(LISTVIEW_INFO *infoPtr, DWORD dwMask, DWORD dwStyle) +{ + DWORD dwOldStyle = infoPtr->dwLvExStyle; + + /* set new style */ + if (dwMask) + infoPtr->dwLvExStyle = (dwOldStyle & ~dwMask) | (dwStyle & dwMask); + else + infoPtr->dwLvExStyle = dwStyle; + + if((infoPtr->dwLvExStyle ^ dwOldStyle) & LVS_EX_CHECKBOXES) + { + HIMAGELIST himl = 0; + if(infoPtr->dwLvExStyle & LVS_EX_CHECKBOXES) + himl = LISTVIEW_CreateCheckBoxIL(infoPtr); + LISTVIEW_SetImageList(infoPtr, LVSIL_STATE, himl); + } + + return dwOldStyle; +} + +/*** + * DESCRIPTION: + * Sets the new hot cursor used during hot tracking and hover selection. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I} hCurosr : the new hot cursor handle + * + * RETURN: + * Returns the previous hot cursor + */ +static HCURSOR LISTVIEW_SetHotCursor(LISTVIEW_INFO *infoPtr, HCURSOR hCursor) +{ + HCURSOR oldCursor = infoPtr->hHotCursor; + + infoPtr->hHotCursor = hCursor; + + return oldCursor; +} + + +/*** + * DESCRIPTION: + * Sets the hot item index. + * + * PARAMETERS: + * [I] infoPtr : valid pointer to the listview structure + * [I] iIndex : index + * + * RETURN: + * SUCCESS : previous hot item index + * FAILURE : -1 (no hot item) + */ +static INT LISTVIEW_SetHotItem(LISTVIEW_INFO *infoPtr, INT iIndex) +{ + INT iOldIndex = infoPtr->nHotItem; + + infoPtr->nHotItem = iIndex; + + return iOldIndex; +} + + +/*** + * DESCRIPTION: + * Sets the amount of time the cursor must hover over an item before it is selected. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] dwHoverTime : hover time, if -1 the hover time is set to the default + * + * RETURN: + * Returns the previous hover time + */ +static DWORD LISTVIEW_SetHoverTime(LISTVIEW_INFO *infoPtr, DWORD dwHoverTime) +{ + DWORD oldHoverTime = infoPtr->dwHoverTime; + + infoPtr->dwHoverTime = dwHoverTime; + + return oldHoverTime; +} + +/*** + * DESCRIPTION: + * Sets spacing for icons of LVS_ICON style. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] cx : horizontal spacing (-1 = system spacing, 0 = autosize) + * [I] cy : vertical spacing (-1 = system spacing, 0 = autosize) + * + * RETURN: + * MAKELONG(oldcx, oldcy) + */ +static DWORD LISTVIEW_SetIconSpacing(LISTVIEW_INFO *infoPtr, INT cx, INT cy) +{ + DWORD oldspacing = MAKELONG(infoPtr->iconSpacing.cx, infoPtr->iconSpacing.cy); + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + + TRACE("requested=(%d,%d)\n", cx, cy); + + /* this is supported only for LVS_ICON style */ + if (uView != LVS_ICON) return oldspacing; + + /* set to defaults, if instructed to */ + if (cx == -1) cx = GetSystemMetrics(SM_CXICONSPACING); + if (cy == -1) cy = GetSystemMetrics(SM_CYICONSPACING); + + /* if 0 then compute width + * FIXME: Should scan each item and determine max width of + * icon or label, then make that the width */ + if (cx == 0) + cx = infoPtr->iconSpacing.cx; + + /* if 0 then compute height */ + if (cy == 0) + cy = infoPtr->iconSize.cy + 2 * infoPtr->ntmHeight + + ICON_BOTTOM_PADDING + ICON_TOP_PADDING + LABEL_VERT_PADDING; + + + infoPtr->iconSpacing.cx = cx; + infoPtr->iconSpacing.cy = cy; + + TRACE("old=(%d,%d), new=(%d,%d), iconSize=(%ld,%ld), ntmH=%d\n", + LOWORD(oldspacing), HIWORD(oldspacing), cx, cy, + infoPtr->iconSize.cx, infoPtr->iconSize.cy, + infoPtr->ntmHeight); + + /* these depend on the iconSpacing */ + LISTVIEW_UpdateItemSize(infoPtr); + + return oldspacing; +} + +static inline void set_icon_size(SIZE *size, HIMAGELIST himl, BOOL _small) +{ + INT cx, cy; + + if (himl && ImageList_GetIconSize(himl, &cx, &cy)) + { + size->cx = cx; + size->cy = cy; + } + else + { + size->cx = GetSystemMetrics(_small ? SM_CXSMICON : SM_CXICON); + size->cy = GetSystemMetrics(_small ? SM_CYSMICON : SM_CYICON); + } +} + +/*** + * DESCRIPTION: + * Sets image lists. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nType : image list type + * [I] himl : image list handle + * + * RETURN: + * SUCCESS : old image list + * FAILURE : NULL + */ +static HIMAGELIST LISTVIEW_SetImageList(LISTVIEW_INFO *infoPtr, INT nType, HIMAGELIST himl) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + INT oldHeight = infoPtr->nItemHeight; + HIMAGELIST himlOld = 0; + + TRACE("(nType=%d, himl=%p\n", nType, himl); + + switch (nType) + { + case LVSIL_NORMAL: + himlOld = infoPtr->himlNormal; + infoPtr->himlNormal = himl; + if (uView == LVS_ICON) set_icon_size(&infoPtr->iconSize, himl, FALSE); + LISTVIEW_SetIconSpacing(infoPtr, 0, 0); + break; + + case LVSIL_SMALL: + himlOld = infoPtr->himlSmall; + infoPtr->himlSmall = himl; + if (uView != LVS_ICON) set_icon_size(&infoPtr->iconSize, himl, TRUE); + break; + + case LVSIL_STATE: + himlOld = infoPtr->himlState; + infoPtr->himlState = himl; + set_icon_size(&infoPtr->iconStateSize, himl, TRUE); + ImageList_SetBkColor(infoPtr->himlState, CLR_NONE); + break; + + default: + ERR("Unknown icon type=%d\n", nType); + return NULL; + } + + infoPtr->nItemHeight = LISTVIEW_CalculateItemHeight(infoPtr); + if (infoPtr->nItemHeight != oldHeight) + LISTVIEW_UpdateScroll(infoPtr); + + return himlOld; +} + +/*** + * DESCRIPTION: + * Preallocates memory (does *not* set the actual count of items !) + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nItems : item count (projected number of items to allocate) + * [I] dwFlags : update flags + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_SetItemCount(LISTVIEW_INFO *infoPtr, INT nItems, DWORD dwFlags) +{ + TRACE("(nItems=%d, dwFlags=%lx)\n", nItems, dwFlags); + + if (infoPtr->dwStyle & LVS_OWNERDATA) + { + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + INT nOldCount = infoPtr->nItemCount; + + if (nItems < nOldCount) + { + RANGE range = { nItems, nOldCount }; + ranges_del(infoPtr->selectionRanges, range); + if (infoPtr->nFocusedItem >= nItems) + { + infoPtr->nFocusedItem = -1; + SetRectEmpty(&infoPtr->rcFocus); + } + } + + infoPtr->nItemCount = nItems; + LISTVIEW_UpdateScroll(infoPtr); + + /* the flags are valid only in ownerdata report and list modes */ + if (uView == LVS_ICON || uView == LVS_SMALLICON) dwFlags = 0; + + if (!(dwFlags & LVSICF_NOSCROLL) && infoPtr->nFocusedItem != -1) + LISTVIEW_EnsureVisible(infoPtr, infoPtr->nFocusedItem, FALSE); + + if (!(dwFlags & LVSICF_NOINVALIDATEALL)) + LISTVIEW_InvalidateList(infoPtr); + else + { + INT nFrom, nTo; + POINT Origin; + RECT rcErase; + + LISTVIEW_GetOrigin(infoPtr, &Origin); + nFrom = min(nOldCount, nItems); + nTo = max(nOldCount, nItems); + + if (uView == LVS_REPORT) + { + rcErase.left = 0; + rcErase.top = nFrom * infoPtr->nItemHeight; + rcErase.right = infoPtr->nItemWidth; + rcErase.bottom = nTo * infoPtr->nItemHeight; + OffsetRect(&rcErase, Origin.x, Origin.y); + if (IntersectRect(&rcErase, &rcErase, &infoPtr->rcList)) + LISTVIEW_InvalidateRect(infoPtr, &rcErase); + } + else /* LVS_LIST */ + { + INT nPerCol = LISTVIEW_GetCountPerColumn(infoPtr); + + rcErase.left = (nFrom / nPerCol) * infoPtr->nItemWidth; + rcErase.top = (nFrom % nPerCol) * infoPtr->nItemHeight; + rcErase.right = rcErase.left + infoPtr->nItemWidth; + rcErase.bottom = nPerCol * infoPtr->nItemHeight; + OffsetRect(&rcErase, Origin.x, Origin.y); + if (IntersectRect(&rcErase, &rcErase, &infoPtr->rcList)) + LISTVIEW_InvalidateRect(infoPtr, &rcErase); + + rcErase.left = (nFrom / nPerCol + 1) * infoPtr->nItemWidth; + rcErase.top = 0; + rcErase.right = (nTo / nPerCol + 1) * infoPtr->nItemWidth; + rcErase.bottom = nPerCol * infoPtr->nItemHeight; + OffsetRect(&rcErase, Origin.x, Origin.y); + if (IntersectRect(&rcErase, &rcErase, &infoPtr->rcList)) + LISTVIEW_InvalidateRect(infoPtr, &rcErase); + } + } + } + else + { + /* According to MSDN for non-LVS_OWNERDATA this is just + * a performance issue. The control allocates its internal + * data structures for the number of items specified. It + * cuts down on the number of memory allocations. Therefore + * we will just issue a WARN here + */ + WARN("for non-ownerdata performance option not implemented.\n"); + } + + return TRUE; +} + +/*** + * DESCRIPTION: + * Sets the position of an item. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nItem : item index + * [I] pt : coordinate + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_SetItemPosition(LISTVIEW_INFO *infoPtr, INT nItem, POINT pt) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + POINT Origin; + + TRACE("(nItem=%d, &pt=%s\n", nItem, debugpoint(&pt)); + + if (nItem < 0 || nItem >= infoPtr->nItemCount || + !(uView == LVS_ICON || uView == LVS_SMALLICON)) return FALSE; + + LISTVIEW_GetOrigin(infoPtr, &Origin); + + /* This point value seems to be an undocumented feature. + * The best guess is that it means either at the origin, + * or at true beginning of the list. I will assume the origin. */ + if ((pt.x == -1) && (pt.y == -1)) + pt = Origin; + + if (uView == LVS_ICON) + { + pt.x -= (infoPtr->nItemWidth - infoPtr->iconSize.cx) / 2; + pt.y -= ICON_TOP_PADDING; + } + pt.x -= Origin.x; + pt.y -= Origin.y; + + infoPtr->bAutoarrange = FALSE; + + return LISTVIEW_MoveIconTo(infoPtr, nItem, &pt, FALSE); +} + +/*** + * DESCRIPTION: + * Sets the state of one or many items. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nItem : item index + * [I] lpLVItem : item or subitem info + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_SetItemState(LISTVIEW_INFO *infoPtr, INT nItem, const LVITEMW *lpLVItem) +{ + BOOL bResult = TRUE; + LVITEMW lvItem; + + lvItem.iItem = nItem; + lvItem.iSubItem = 0; + lvItem.mask = LVIF_STATE; + lvItem.state = lpLVItem->state; + lvItem.stateMask = lpLVItem->stateMask; + TRACE("lvItem=%s\n", debuglvitem_t(&lvItem, TRUE)); + + if (nItem == -1) + { + /* apply to all items */ + for (lvItem.iItem = 0; lvItem.iItem < infoPtr->nItemCount; lvItem.iItem++) + if (!LISTVIEW_SetItemT(infoPtr, &lvItem, TRUE)) bResult = FALSE; + } + else + bResult = LISTVIEW_SetItemT(infoPtr, &lvItem, TRUE); + + /* + * Update selection mark + * + * Investigation on windows 2k showed that selection mark was updated + * whenever a new selection was made, but if the selected item was + * unselected it was not updated. + * + * we are probably still not 100% accurate, but this at least sets the + * proper selection mark when it is needed + */ + + if (bResult && (lvItem.state & lvItem.stateMask & LVIS_SELECTED) && + ((infoPtr->nSelectionMark == -1) || (lvItem.iItem <= infoPtr->nSelectionMark))) + { + int i; + infoPtr->nSelectionMark = -1; + for (i = 0; i < infoPtr->nItemCount; i++) + { + if (infoPtr->uCallbackMask & LVIS_SELECTED) + { + if (LISTVIEW_GetItemState(infoPtr, i, LVIS_SELECTED)) + { + infoPtr->nSelectionMark = i; + break; + } + } + else if (ranges_contain(infoPtr->selectionRanges, i)) + { + infoPtr->nSelectionMark = i; + break; + } + } + } + + return bResult; +} + +/*** + * DESCRIPTION: + * Sets the text of an item or subitem. + * + * PARAMETER(S): + * [I] hwnd : window handle + * [I] nItem : item index + * [I] lpLVItem : item or subitem info + * [I] isW : TRUE if input is Unicode + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_SetItemTextT(LISTVIEW_INFO *infoPtr, INT nItem, const LVITEMW *lpLVItem, BOOL isW) +{ + LVITEMW lvItem; + + if (nItem < 0 && nItem >= infoPtr->nItemCount) return FALSE; + + lvItem.iItem = nItem; + lvItem.iSubItem = lpLVItem->iSubItem; + lvItem.mask = LVIF_TEXT; + lvItem.pszText = lpLVItem->pszText; + lvItem.cchTextMax = lpLVItem->cchTextMax; + + TRACE("(nItem=%d, lpLVItem=%s, isW=%d)\n", nItem, debuglvitem_t(&lvItem, isW), isW); + + return LISTVIEW_SetItemT(infoPtr, &lvItem, isW); +} + +/*** + * DESCRIPTION: + * Set item index that marks the start of a multiple selection. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nIndex : index + * + * RETURN: + * Index number or -1 if there is no selection mark. + */ +static INT LISTVIEW_SetSelectionMark(LISTVIEW_INFO *infoPtr, INT nIndex) +{ + INT nOldIndex = infoPtr->nSelectionMark; + + TRACE("(nIndex=%d)\n", nIndex); + + infoPtr->nSelectionMark = nIndex; + + return nOldIndex; +} + +/*** + * DESCRIPTION: + * Sets the text background color. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] clrTextBk : text background color + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_SetTextBkColor(LISTVIEW_INFO *infoPtr, COLORREF clrTextBk) +{ + TRACE("(clrTextBk=%lx)\n", clrTextBk); + + if (infoPtr->clrTextBk != clrTextBk) + { + infoPtr->clrTextBk = clrTextBk; + LISTVIEW_InvalidateList(infoPtr); + } + + return TRUE; +} + +/*** + * DESCRIPTION: + * Sets the text foreground color. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] clrText : text color + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_SetTextColor (LISTVIEW_INFO *infoPtr, COLORREF clrText) +{ + TRACE("(clrText=%lx)\n", clrText); + + if (infoPtr->clrText != clrText) + { + infoPtr->clrText = clrText; + LISTVIEW_InvalidateList(infoPtr); + } + + return TRUE; +} + +/*** + * DESCRIPTION: + * Determines which listview item is located at the specified position. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] hwndNewToolTip : handle to new ToolTip + * + * RETURN: + * old tool tip + */ +static HWND LISTVIEW_SetToolTips( LISTVIEW_INFO *infoPtr, HWND hwndNewToolTip) +{ + HWND hwndOldToolTip = infoPtr->hwndToolTip; + infoPtr->hwndToolTip = hwndNewToolTip; + return hwndOldToolTip; +} + +/* LISTVIEW_SetUnicodeFormat */ +/* LISTVIEW_SetWorkAreas */ + +/*** + * DESCRIPTION: + * Callback internally used by LISTVIEW_SortItems() + * + * PARAMETER(S): + * [I] first : pointer to first ITEM_INFO to compare + * [I] second : pointer to second ITEM_INFO to compare + * [I] lParam : HWND of control + * + * RETURN: + * if first comes before second : negative + * if first comes after second : positive + * if first and second are equivalent : zero + */ +static INT WINAPI LISTVIEW_CallBackCompare(LPVOID first, LPVOID second, LPARAM lParam) +{ + LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)lParam; + ITEM_INFO* lv_first = (ITEM_INFO*) DPA_GetPtr( (HDPA)first, 0 ); + ITEM_INFO* lv_second = (ITEM_INFO*) DPA_GetPtr( (HDPA)second, 0 ); + PFNLVCOMPARE CompareFunction = infoPtr->pfnCompare; + + /* Forward the call to the client defined callback */ + + return (CompareFunction)( lv_first->lParam , lv_second->lParam, infoPtr->lParamSort ); +} + +/*** + * DESCRIPTION: + * Sorts the listview items. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] pfnCompare : application-defined value + * [I] lParamSort : pointer to comparision callback + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_SortItems(LISTVIEW_INFO *infoPtr, PFNLVCOMPARE pfnCompare, LPARAM lParamSort) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + HDPA hdpaSubItems; + ITEM_INFO *lpItem; + LPVOID selectionMarkItem; + LVITEMW item; + int i; + + TRACE("(pfnCompare=%p, lParamSort=%lx)\n", pfnCompare, lParamSort); + + if (infoPtr->dwStyle & LVS_OWNERDATA) return FALSE; + + if (!pfnCompare) return FALSE; + if (!infoPtr->hdpaItems) return FALSE; + + /* if there are 0 or 1 items, there is no need to sort */ + if (infoPtr->nItemCount < 2) return TRUE; + + if (infoPtr->nFocusedItem >= 0) + { + hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, infoPtr->nFocusedItem); + lpItem = (ITEM_INFO *)DPA_GetPtr(hdpaSubItems, 0); + if (lpItem) lpItem->state |= LVIS_FOCUSED; + } + /* FIXME: go thorugh selected items and mark them so in lpItem->state */ + /* clear the lpItem->state for non-selected ones */ + /* remove the selection ranges */ + + infoPtr->pfnCompare = pfnCompare; + infoPtr->lParamSort = lParamSort; + DPA_Sort(infoPtr->hdpaItems, LISTVIEW_CallBackCompare, (LPARAM)infoPtr); + + /* Adjust selections and indices so that they are the way they should + * be after the sort (otherwise, the list items move around, but + * whatever is at the item's previous original position will be + * selected instead) + */ + selectionMarkItem=(infoPtr->nSelectionMark>=0)?DPA_GetPtr(infoPtr->hdpaItems, infoPtr->nSelectionMark):NULL; + for (i=0; i < infoPtr->nItemCount; i++) + { + hdpaSubItems = (HDPA)DPA_GetPtr(infoPtr->hdpaItems, i); + lpItem = (ITEM_INFO *)DPA_GetPtr(hdpaSubItems, 0); + + if (lpItem->state & LVIS_SELECTED) + { + item.state = LVIS_SELECTED; + item.stateMask = LVIS_SELECTED; + LISTVIEW_SetItemState(infoPtr, i, &item); + } + if (lpItem->state & LVIS_FOCUSED) + { + infoPtr->nFocusedItem = i; + lpItem->state &= ~LVIS_FOCUSED; + } + } + if (selectionMarkItem != NULL) + infoPtr->nSelectionMark = DPA_GetPtrIndex(infoPtr->hdpaItems, selectionMarkItem); + /* I believe nHotItem should be left alone, see LISTVIEW_ShiftIndices */ + + /* refresh the display */ + if (uView != LVS_ICON && uView != LVS_SMALLICON) + LISTVIEW_InvalidateList(infoPtr); + + return TRUE; +} + +/*** + * DESCRIPTION: + * Updates an items or rearranges the listview control. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nItem : item index + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_Update(LISTVIEW_INFO *infoPtr, INT nItem) +{ + TRACE("(nItem=%d)\n", nItem); + + if (nItem < 0 || nItem >= infoPtr->nItemCount) return FALSE; + + /* rearrange with default alignment style */ + if (is_autoarrange(infoPtr)) + LISTVIEW_Arrange(infoPtr, LVA_DEFAULT); + else + LISTVIEW_InvalidateItem(infoPtr, nItem); + + return TRUE; +} + + +/*** + * DESCRIPTION: + * Creates the listview control. + * + * PARAMETER(S): + * [I] hwnd : window handle + * [I] lpcs : the create parameters + * + * RETURN: + * Success: 0 + * Failure: -1 + */ +static LRESULT LISTVIEW_Create(HWND hwnd, const CREATESTRUCTW *lpcs) +{ + LISTVIEW_INFO *infoPtr; + UINT uView = lpcs->style & LVS_TYPEMASK; + LOGFONTW logFont; + + TRACE("(lpcs=%p)\n", lpcs); + + /* initialize info pointer */ + infoPtr = (LISTVIEW_INFO *)Alloc(sizeof(LISTVIEW_INFO)); + if (!infoPtr) return -1; + + SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)infoPtr); + + infoPtr->hwndSelf = hwnd; + infoPtr->dwStyle = lpcs->style; + /* determine the type of structures to use */ + infoPtr->hwndNotify = lpcs->hwndParent; + infoPtr->notifyFormat = SendMessageW(infoPtr->hwndNotify, WM_NOTIFYFORMAT, + (WPARAM)infoPtr->hwndSelf, (LPARAM)NF_QUERY); + + /* initialize color information */ + infoPtr->clrBk = CLR_NONE; + infoPtr->clrText = comctl32_color.clrWindowText; + infoPtr->clrTextBk = CLR_DEFAULT; + LISTVIEW_SetBkColor(infoPtr, comctl32_color.clrWindow); + + /* set default values */ + infoPtr->nFocusedItem = -1; + infoPtr->nSelectionMark = -1; + infoPtr->nHotItem = -1; + infoPtr->bRedraw = TRUE; + infoPtr->bNoItemMetrics = TRUE; + infoPtr->bDoChangeNotify = TRUE; + infoPtr->iconSpacing.cx = GetSystemMetrics(SM_CXICONSPACING); + infoPtr->iconSpacing.cy = GetSystemMetrics(SM_CYICONSPACING); + infoPtr->nEditLabelItem = -1; + infoPtr->dwHoverTime = -1; /* default system hover time */ + infoPtr->nMeasureItemHeight = 0; + + /* get default font (icon title) */ + SystemParametersInfoW(SPI_GETICONTITLELOGFONT, 0, &logFont, 0); + infoPtr->hDefaultFont = CreateFontIndirectW(&logFont); + infoPtr->hFont = infoPtr->hDefaultFont; + LISTVIEW_SaveTextMetrics(infoPtr); + + /* create header */ + infoPtr->hwndHeader = CreateWindowW(WC_HEADERW, NULL, + WS_CHILD | HDS_HORZ | (DWORD)((LVS_NOSORTHEADER & lpcs->style)?0:HDS_BUTTONS), + 0, 0, 0, 0, hwnd, NULL, + lpcs->hInstance, NULL); + if (!infoPtr->hwndHeader) goto fail; + + /* set header unicode format */ + SendMessageW(infoPtr->hwndHeader, HDM_SETUNICODEFORMAT, (WPARAM)TRUE, (LPARAM)NULL); + + /* set header font */ + SendMessageW(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)infoPtr->hFont, (LPARAM)TRUE); + + /* allocate memory for the data structure */ + if (!(infoPtr->selectionRanges = ranges_create(10))) goto fail; + if (!(infoPtr->hdpaItems = DPA_Create(10))) goto fail; + if (!(infoPtr->hdpaPosX = DPA_Create(10))) goto fail; + if (!(infoPtr->hdpaPosY = DPA_Create(10))) goto fail; + if (!(infoPtr->hdpaColumns = DPA_Create(10))) goto fail; + + /* initialize the icon sizes */ + set_icon_size(&infoPtr->iconSize, infoPtr->himlNormal, uView != LVS_ICON); + set_icon_size(&infoPtr->iconStateSize, infoPtr->himlState, TRUE); + + /* init item size to avoid division by 0 */ + LISTVIEW_UpdateItemSize (infoPtr); + + if (uView == LVS_REPORT) + { + if (!(LVS_NOCOLUMNHEADER & lpcs->style)) + { + ShowWindow(infoPtr->hwndHeader, SW_SHOWNORMAL); + } + else + { + /* set HDS_HIDDEN flag to hide the header bar */ + SetWindowLongW(infoPtr->hwndHeader, GWL_STYLE, + GetWindowLongW(infoPtr->hwndHeader, GWL_STYLE) | HDS_HIDDEN); + } + } + + return 0; + +fail: + DestroyWindow(infoPtr->hwndHeader); + ranges_destroy(infoPtr->selectionRanges); + DPA_Destroy(infoPtr->hdpaItems); + DPA_Destroy(infoPtr->hdpaPosX); + DPA_Destroy(infoPtr->hdpaPosY); + DPA_Destroy(infoPtr->hdpaColumns); + Free(infoPtr); + return -1; +} + +/*** + * DESCRIPTION: + * Enables the listview control. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] bEnable : specifies whether to enable or disable the window + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static BOOL LISTVIEW_Enable(LISTVIEW_INFO *infoPtr, BOOL bEnable) +{ + if (infoPtr->dwStyle & LVS_OWNERDRAWFIXED) + InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); + return TRUE; +} + +/*** + * DESCRIPTION: + * Erases the background of the listview control. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] hdc : device context handle + * + * RETURN: + * SUCCESS : TRUE + * FAILURE : FALSE + */ +static inline BOOL LISTVIEW_EraseBkgnd(LISTVIEW_INFO *infoPtr, HDC hdc) +{ + RECT rc; + + TRACE("(hdc=%p)\n", hdc); + + if (!GetClipBox(hdc, &rc)) return FALSE; + + return LISTVIEW_FillBkgnd(infoPtr, hdc, &rc); +} + + +/*** + * DESCRIPTION: + * Helper function for LISTVIEW_[HV]Scroll *only*. + * Performs vertical/horizontal scrolling by a give amount. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] dx : amount of horizontal scroll + * [I] dy : amount of vertical scroll + */ +static void scroll_list(LISTVIEW_INFO *infoPtr, INT dx, INT dy) +{ + /* now we can scroll the list */ + ScrollWindowEx(infoPtr->hwndSelf, dx, dy, &infoPtr->rcList, + &infoPtr->rcList, 0, 0, SW_ERASE | SW_INVALIDATE); + /* if we have focus, adjust rect */ + OffsetRect(&infoPtr->rcFocus, dx, dy); + UpdateWindow(infoPtr->hwndSelf); +} + +/*** + * DESCRIPTION: + * Performs vertical scrolling. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nScrollCode : scroll code + * [I] nScrollDiff : units to scroll in SB_INTERNAL mode, 0 otherwise + * [I] hScrollWnd : scrollbar control window handle + * + * RETURN: + * Zero + * + * NOTES: + * SB_LINEUP/SB_LINEDOWN: + * for LVS_ICON, LVS_SMALLICON is 37 by experiment + * for LVS_REPORT is 1 line + * for LVS_LIST cannot occur + * + */ +static LRESULT LISTVIEW_VScroll(LISTVIEW_INFO *infoPtr, INT nScrollCode, + INT nScrollDiff, HWND hScrollWnd) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + INT nOldScrollPos, nNewScrollPos; + SCROLLINFO scrollInfo; + BOOL is_an_icon; + + TRACE("(nScrollCode=%d(%s), nScrollDiff=%d)\n", nScrollCode, + debugscrollcode(nScrollCode), nScrollDiff); + + if (infoPtr->hwndEdit) SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0); + + scrollInfo.cbSize = sizeof(SCROLLINFO); + scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS; + + is_an_icon = ((uView == LVS_ICON) || (uView == LVS_SMALLICON)); + + if (!GetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo)) return 1; + + nOldScrollPos = scrollInfo.nPos; + switch (nScrollCode) + { + case SB_INTERNAL: + break; + + case SB_LINEUP: + nScrollDiff = (is_an_icon) ? -LISTVIEW_SCROLL_ICON_LINE_SIZE : -1; + break; + + case SB_LINEDOWN: + nScrollDiff = (is_an_icon) ? LISTVIEW_SCROLL_ICON_LINE_SIZE : 1; + break; + + case SB_PAGEUP: + nScrollDiff = -scrollInfo.nPage; + break; + + case SB_PAGEDOWN: + nScrollDiff = scrollInfo.nPage; + break; + + case SB_THUMBPOSITION: + case SB_THUMBTRACK: + nScrollDiff = scrollInfo.nTrackPos - scrollInfo.nPos; + break; + + default: + nScrollDiff = 0; + } + + /* quit right away if pos isn't changing */ + if (nScrollDiff == 0) return 0; + + /* calculate new position, and handle overflows */ + nNewScrollPos = scrollInfo.nPos + nScrollDiff; + if (nScrollDiff > 0) { + if (nNewScrollPos < nOldScrollPos || + nNewScrollPos > scrollInfo.nMax) + nNewScrollPos = scrollInfo.nMax; + } else { + if (nNewScrollPos > nOldScrollPos || + nNewScrollPos < scrollInfo.nMin) + nNewScrollPos = scrollInfo.nMin; + } + + /* set the new position, and reread in case it changed */ + scrollInfo.fMask = SIF_POS; + scrollInfo.nPos = nNewScrollPos; + nNewScrollPos = SetScrollInfo(infoPtr->hwndSelf, SB_VERT, &scrollInfo, TRUE); + + /* carry on only if it really changed */ + if (nNewScrollPos == nOldScrollPos) return 0; + + /* now adjust to client coordinates */ + nScrollDiff = nOldScrollPos - nNewScrollPos; + if (uView == LVS_REPORT) nScrollDiff *= infoPtr->nItemHeight; + + /* and scroll the window */ + scroll_list(infoPtr, 0, nScrollDiff); + + return 0; +} + +/*** + * DESCRIPTION: + * Performs horizontal scrolling. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nScrollCode : scroll code + * [I] nScrollDiff : units to scroll in SB_INTERNAL mode, 0 otherwise + * [I] hScrollWnd : scrollbar control window handle + * + * RETURN: + * Zero + * + * NOTES: + * SB_LINELEFT/SB_LINERIGHT: + * for LVS_ICON, LVS_SMALLICON 1 pixel + * for LVS_REPORT is 1 pixel + * for LVS_LIST is 1 column --> which is a 1 because the + * scroll is based on columns not pixels + * + */ +static LRESULT LISTVIEW_HScroll(LISTVIEW_INFO *infoPtr, INT nScrollCode, + INT nScrollDiff, HWND hScrollWnd) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + INT nOldScrollPos, nNewScrollPos; + SCROLLINFO scrollInfo; + + TRACE("(nScrollCode=%d(%s), nScrollDiff=%d)\n", nScrollCode, + debugscrollcode(nScrollCode), nScrollDiff); + + if (infoPtr->hwndEdit) SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0); + + scrollInfo.cbSize = sizeof(SCROLLINFO); + scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_TRACKPOS; + + if (!GetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo)) return 1; + + nOldScrollPos = scrollInfo.nPos; + + switch (nScrollCode) + { + case SB_INTERNAL: + break; + + case SB_LINELEFT: + nScrollDiff = -1; + break; + + case SB_LINERIGHT: + nScrollDiff = 1; + break; + + case SB_PAGELEFT: + nScrollDiff = -scrollInfo.nPage; + break; + + case SB_PAGERIGHT: + nScrollDiff = scrollInfo.nPage; + break; + + case SB_THUMBPOSITION: + case SB_THUMBTRACK: + nScrollDiff = scrollInfo.nTrackPos - scrollInfo.nPos; + break; + + default: + nScrollDiff = 0; + } + + /* quit right away if pos isn't changing */ + if (nScrollDiff == 0) return 0; + + /* calculate new position, and handle overflows */ + nNewScrollPos = scrollInfo.nPos + nScrollDiff; + if (nScrollDiff > 0) { + if (nNewScrollPos < nOldScrollPos || + nNewScrollPos > scrollInfo.nMax) + nNewScrollPos = scrollInfo.nMax; + } else { + if (nNewScrollPos > nOldScrollPos || + nNewScrollPos < scrollInfo.nMin) + nNewScrollPos = scrollInfo.nMin; + } + + /* set the new position, and reread in case it changed */ + scrollInfo.fMask = SIF_POS; + scrollInfo.nPos = nNewScrollPos; + nNewScrollPos = SetScrollInfo(infoPtr->hwndSelf, SB_HORZ, &scrollInfo, TRUE); + + /* carry on only if it really changed */ + if (nNewScrollPos == nOldScrollPos) return 0; + + if(uView == LVS_REPORT) + LISTVIEW_UpdateHeaderSize(infoPtr, nNewScrollPos); + + /* now adjust to client coordinates */ + nScrollDiff = nOldScrollPos - nNewScrollPos; + if (uView == LVS_LIST) nScrollDiff *= infoPtr->nItemWidth; + + /* and scroll the window */ + scroll_list(infoPtr, nScrollDiff, 0); + + return 0; +} + +static LRESULT LISTVIEW_MouseWheel(LISTVIEW_INFO *infoPtr, INT wheelDelta) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + INT gcWheelDelta = 0; + INT pulScrollLines = 3; + SCROLLINFO scrollInfo; + + TRACE("(wheelDelta=%d)\n", wheelDelta); + + SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0); + gcWheelDelta -= wheelDelta; + + scrollInfo.cbSize = sizeof(SCROLLINFO); + scrollInfo.fMask = SIF_POS; + + switch(uView) + { + case LVS_ICON: + case LVS_SMALLICON: + /* + * listview should be scrolled by a multiple of 37 dependently on its dimension or its visible item number + * should be fixed in the future. + */ + LISTVIEW_VScroll(infoPtr, SB_INTERNAL, (gcWheelDelta < 0) ? + -LISTVIEW_SCROLL_ICON_LINE_SIZE : LISTVIEW_SCROLL_ICON_LINE_SIZE, 0); + break; + + case LVS_REPORT: + if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines) + { + int cLineScroll = min(LISTVIEW_GetCountPerColumn(infoPtr), pulScrollLines); + cLineScroll *= (gcWheelDelta / WHEEL_DELTA); + LISTVIEW_VScroll(infoPtr, SB_INTERNAL, cLineScroll, 0); + } + break; + + case LVS_LIST: + LISTVIEW_HScroll(infoPtr, (gcWheelDelta < 0) ? SB_LINELEFT : SB_LINERIGHT, 0, 0); + break; + } + return 0; +} + +/*** + * DESCRIPTION: + * ??? + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nVirtualKey : virtual key + * [I] lKeyData : key data + * + * RETURN: + * Zero + */ +static LRESULT LISTVIEW_KeyDown(LISTVIEW_INFO *infoPtr, INT nVirtualKey, LONG lKeyData) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + INT nItem = -1; + NMLVKEYDOWN nmKeyDown; + + TRACE("(nVirtualKey=%d, lKeyData=%ld)\n", nVirtualKey, lKeyData); + + /* send LVN_KEYDOWN notification */ + nmKeyDown.wVKey = nVirtualKey; + nmKeyDown.flags = 0; + notify_hdr(infoPtr, LVN_KEYDOWN, &nmKeyDown.hdr); + + switch (nVirtualKey) + { + case VK_RETURN: + if ((infoPtr->nItemCount > 0) && (infoPtr->nFocusedItem != -1)) + { + notify(infoPtr, NM_RETURN); + notify(infoPtr, LVN_ITEMACTIVATE); + } + break; + + case VK_HOME: + if (infoPtr->nItemCount > 0) + nItem = 0; + break; + + case VK_END: + if (infoPtr->nItemCount > 0) + nItem = infoPtr->nItemCount - 1; + break; + + case VK_LEFT: + nItem = ListView_GetNextItem(infoPtr->hwndSelf, infoPtr->nFocusedItem, LVNI_TOLEFT); + break; + + case VK_UP: + nItem = ListView_GetNextItem(infoPtr->hwndSelf, infoPtr->nFocusedItem, LVNI_ABOVE); + break; + + case VK_RIGHT: + nItem = ListView_GetNextItem(infoPtr->hwndSelf, infoPtr->nFocusedItem, LVNI_TORIGHT); + break; + + case VK_DOWN: + nItem = ListView_GetNextItem(infoPtr->hwndSelf, infoPtr->nFocusedItem, LVNI_BELOW); + break; + + case VK_PRIOR: + if (uView == LVS_REPORT) + nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(infoPtr); + else + nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(infoPtr) + * LISTVIEW_GetCountPerRow(infoPtr); + if(nItem < 0) nItem = 0; + break; + + case VK_NEXT: + if (uView == LVS_REPORT) + nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn(infoPtr); + else + nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn(infoPtr) + * LISTVIEW_GetCountPerRow(infoPtr); + if(nItem >= infoPtr->nItemCount) nItem = infoPtr->nItemCount - 1; + break; + } + + if ((nItem != -1) && (nItem != infoPtr->nFocusedItem)) + LISTVIEW_KeySelection(infoPtr, nItem); + + return 0; +} + +/*** + * DESCRIPTION: + * Kills the focus. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * + * RETURN: + * Zero + */ +static LRESULT LISTVIEW_KillFocus(LISTVIEW_INFO *infoPtr) +{ + TRACE("()\n"); + + /* if we did not have the focus, there's nothing to do */ + if (!infoPtr->bFocus) return 0; + + /* send NM_KILLFOCUS notification */ + notify(infoPtr, NM_KILLFOCUS); + + /* if we have a focus rectagle, get rid of it */ + LISTVIEW_ShowFocusRect(infoPtr, FALSE); + + /* set window focus flag */ + infoPtr->bFocus = FALSE; + + /* invalidate the selected items before reseting focus flag */ + LISTVIEW_InvalidateSelectedItems(infoPtr); + + return 0; +} + +/*** + * DESCRIPTION: + * Processes double click messages (left mouse button). + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] wKey : key flag + * [I] x,y : mouse coordinate + * + * RETURN: + * Zero + */ +static LRESULT LISTVIEW_LButtonDblClk(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y) +{ + LVHITTESTINFO htInfo; + + TRACE("(key=%hu, X=%hu, Y=%hu)\n", wKey, x, y); + + /* send NM_RELEASEDCAPTURE notification */ + notify(infoPtr, NM_RELEASEDCAPTURE); + + htInfo.pt.x = x; + htInfo.pt.y = y; + + /* send NM_DBLCLK notification */ + LISTVIEW_HitTest(infoPtr, &htInfo, TRUE, FALSE); + notify_click(infoPtr, NM_DBLCLK, &htInfo); + + /* To send the LVN_ITEMACTIVATE, it must be on an Item */ + if(htInfo.iItem != -1) notify_itemactivate(infoPtr,&htInfo); + + return 0; +} + +/*** + * DESCRIPTION: + * Processes mouse down messages (left mouse button). + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] wKey : key flag + * [I] x,y : mouse coordinate + * + * RETURN: + * Zero + */ +static LRESULT LISTVIEW_LButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y) +{ + LVHITTESTINFO lvHitTestInfo; + static BOOL bGroupSelect = TRUE; + POINT pt = { x, y }; + INT nItem; + + TRACE("(key=%hu, X=%hu, Y=%hu)\n", wKey, x, y); + + /* send NM_RELEASEDCAPTURE notification */ + notify(infoPtr, NM_RELEASEDCAPTURE); + + if (!infoPtr->bFocus) SetFocus(infoPtr->hwndSelf); + + /* set left button down flag and record the click position */ + infoPtr->bLButtonDown = TRUE; + infoPtr->ptClickPos = pt; + + lvHitTestInfo.pt.x = x; + lvHitTestInfo.pt.y = y; + + nItem = LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE); + TRACE("at %s, nItem=%d\n", debugpoint(&pt), nItem); + infoPtr->nEditLabelItem = -1; + if ((nItem >= 0) && (nItem < infoPtr->nItemCount)) + { + if ((infoPtr->dwLvExStyle & LVS_EX_CHECKBOXES) && (lvHitTestInfo.flags & LVHT_ONITEMSTATEICON)) + { + DWORD state = LISTVIEW_GetItemState(infoPtr, nItem, LVIS_STATEIMAGEMASK) >> 12; + if(state == 1 || state == 2) + { + LVITEMW lvitem; + state ^= 3; + lvitem.state = state << 12; + lvitem.stateMask = LVIS_STATEIMAGEMASK; + LISTVIEW_SetItemState(infoPtr, nItem, &lvitem); + } + return 0; + } + + if (infoPtr->dwStyle & LVS_SINGLESEL) + { + if (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED)) + infoPtr->nEditLabelItem = nItem; + else + LISTVIEW_SetSelection(infoPtr, nItem); + } + else + { + if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT)) + { + if (bGroupSelect) + { + LISTVIEW_AddGroupSelection(infoPtr, nItem); + LISTVIEW_SetItemFocus(infoPtr, nItem); + infoPtr->nSelectionMark = nItem; + } + else + { + LVITEMW item; + + item.state = LVIS_SELECTED | LVIS_FOCUSED; + item.stateMask = LVIS_SELECTED | LVIS_FOCUSED; + + LISTVIEW_SetItemState(infoPtr,nItem,&item); + infoPtr->nSelectionMark = nItem; + } + } + else if (wKey & MK_CONTROL) + { + LVITEMW item; + + bGroupSelect = (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED) == 0); + + item.state = (bGroupSelect ? LVIS_SELECTED : 0) | LVIS_FOCUSED; + item.stateMask = LVIS_SELECTED | LVIS_FOCUSED; + LISTVIEW_SetItemState(infoPtr, nItem, &item); + infoPtr->nSelectionMark = nItem; + } + else if (wKey & MK_SHIFT) + { + LISTVIEW_SetGroupSelection(infoPtr, nItem); + } + else + { + if (LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED)) + infoPtr->nEditLabelItem = nItem; + + /* set selection (clears other pre-existing selections) */ + LISTVIEW_SetSelection(infoPtr, nItem); + } + } + } + else + { + /* remove all selections */ + LISTVIEW_DeselectAll(infoPtr); + ReleaseCapture(); + } + + return 0; +} + +/*** + * DESCRIPTION: + * Processes mouse up messages (left mouse button). + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] wKey : key flag + * [I] x,y : mouse coordinate + * + * RETURN: + * Zero + */ +static LRESULT LISTVIEW_LButtonUp(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y) +{ + LVHITTESTINFO lvHitTestInfo; + + TRACE("(key=%hu, X=%hu, Y=%hu)\n", wKey, x, y); + + if (!infoPtr->bLButtonDown) return 0; + + lvHitTestInfo.pt.x = x; + lvHitTestInfo.pt.y = y; + + /* send NM_CLICK notification */ + LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE); + notify_click(infoPtr, NM_CLICK, &lvHitTestInfo); + + /* set left button flag */ + infoPtr->bLButtonDown = FALSE; + + /* if we clicked on a selected item, edit the label */ + if(lvHitTestInfo.iItem == infoPtr->nEditLabelItem && (lvHitTestInfo.flags & LVHT_ONITEMLABEL)) + LISTVIEW_EditLabelT(infoPtr, lvHitTestInfo.iItem, TRUE); + + return 0; +} + +/*** + * DESCRIPTION: + * Destroys the listview control (called after WM_DESTROY). + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * + * RETURN: + * Zero + */ +static LRESULT LISTVIEW_NCDestroy(LISTVIEW_INFO *infoPtr) +{ + TRACE("()\n"); + + /* delete all items */ + LISTVIEW_DeleteAllItems(infoPtr); + + /* destroy data structure */ + DPA_Destroy(infoPtr->hdpaItems); + DPA_Destroy(infoPtr->hdpaPosX); + DPA_Destroy(infoPtr->hdpaPosY); + DPA_Destroy(infoPtr->hdpaColumns); + ranges_destroy(infoPtr->selectionRanges); + + /* destroy image lists */ + if (!(infoPtr->dwStyle & LVS_SHAREIMAGELISTS)) + { + if (infoPtr->himlNormal) + ImageList_Destroy(infoPtr->himlNormal); + if (infoPtr->himlSmall) + ImageList_Destroy(infoPtr->himlSmall); + if (infoPtr->himlState) + ImageList_Destroy(infoPtr->himlState); + } + + /* destroy font, bkgnd brush */ + infoPtr->hFont = 0; + if (infoPtr->hDefaultFont) DeleteObject(infoPtr->hDefaultFont); + if (infoPtr->clrBk != CLR_NONE) DeleteObject(infoPtr->hBkBrush); + + SetWindowLongPtrW(infoPtr->hwndSelf, 0, 0); + + /* free listview info pointer*/ + Free(infoPtr); + + return 0; +} + +/*** + * DESCRIPTION: + * Handles notifications from header. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] nCtrlId : control identifier + * [I] lpnmh : notification information + * + * RETURN: + * Zero + */ +static LRESULT LISTVIEW_HeaderNotification(LISTVIEW_INFO *infoPtr, const NMHEADERW *lpnmh) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + + TRACE("(lpnmh=%p)\n", lpnmh); + + if (!lpnmh || lpnmh->iItem < 0 || lpnmh->iItem >= DPA_GetPtrCount(infoPtr->hdpaColumns)) return 0; + + switch (lpnmh->hdr.code) + { + case HDN_TRACKW: + case HDN_TRACKA: + case HDN_ITEMCHANGEDW: + case HDN_ITEMCHANGEDA: + { + COLUMN_INFO *lpColumnInfo; + INT dx, cxy; + + if (!lpnmh->pitem || !(lpnmh->pitem->mask & HDI_WIDTH)) + { + HDITEMW hdi; + + hdi.mask = HDI_WIDTH; + if (!Header_GetItemW(infoPtr->hwndHeader, lpnmh->iItem, (LPARAM)&hdi)) return 0; + cxy = hdi.cxy; + } + else + cxy = lpnmh->pitem->cxy; + + /* determine how much we change since the last know position */ + lpColumnInfo = LISTVIEW_GetColumnInfo(infoPtr, lpnmh->iItem); + dx = cxy - (lpColumnInfo->rcHeader.right - lpColumnInfo->rcHeader.left); + if (dx != 0) + { + lpColumnInfo->rcHeader.right += dx; + LISTVIEW_ScrollColumns(infoPtr, lpnmh->iItem + 1, dx); + LISTVIEW_UpdateItemSize(infoPtr); + if (uView == LVS_REPORT && is_redrawing(infoPtr)) + { + POINT ptOrigin; + RECT rcCol = lpColumnInfo->rcHeader; + + LISTVIEW_GetOrigin(infoPtr, &ptOrigin); + OffsetRect(&rcCol, ptOrigin.x, 0); + + rcCol.top = infoPtr->rcList.top; + rcCol.bottom = infoPtr->rcList.bottom; + + /* resizing left-aligned columns leaves most of the left side untouched */ + if ((lpColumnInfo->fmt & LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT) + { + INT nMaxDirty = infoPtr->nEllipsisWidth + infoPtr->ntmMaxCharWidth + dx; + rcCol.left = max (rcCol.left, rcCol.right - nMaxDirty); + } + + LISTVIEW_InvalidateRect(infoPtr, &rcCol); + } + } + } + break; + + case HDN_ITEMCLICKW: + case HDN_ITEMCLICKA: + { + /* Handle sorting by Header Column */ + NMLISTVIEW nmlv; + + ZeroMemory(&nmlv, sizeof(NMLISTVIEW)); + nmlv.iItem = -1; + nmlv.iSubItem = lpnmh->iItem; + notify_listview(infoPtr, LVN_COLUMNCLICK, &nmlv); + } + break; + + case HDN_DIVIDERDBLCLICKW: + case HDN_DIVIDERDBLCLICKA: + LISTVIEW_SetColumnWidth(infoPtr, lpnmh->iItem, LVSCW_AUTOSIZE); + break; + } + + return 0; +} + +/*** + * DESCRIPTION: + * Determines the type of structure to use. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structureof the sender + * [I] hwndFrom : listview window handle + * [I] nCommand : command specifying the nature of the WM_NOTIFYFORMAT + * + * RETURN: + * Zero + */ +static LRESULT LISTVIEW_NotifyFormat(LISTVIEW_INFO *infoPtr, HWND hwndFrom, INT nCommand) +{ + TRACE("(hwndFrom=%p, nCommand=%d)\n", hwndFrom, nCommand); + + if (nCommand != NF_REQUERY) return 0; + + infoPtr->notifyFormat = SendMessageW(hwndFrom, WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY); + + return 0; +} + +/*** + * DESCRIPTION: + * Paints/Repaints the listview control. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] hdc : device context handle + * + * RETURN: + * Zero + */ +static LRESULT LISTVIEW_Paint(LISTVIEW_INFO *infoPtr, HDC hdc) +{ + TRACE("(hdc=%p)\n", hdc); + + if (infoPtr->bNoItemMetrics && infoPtr->nItemCount) + { + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + + infoPtr->bNoItemMetrics = FALSE; + LISTVIEW_UpdateItemSize(infoPtr); + if (uView == LVS_ICON || uView == LVS_SMALLICON) + LISTVIEW_Arrange(infoPtr, LVA_DEFAULT); + LISTVIEW_UpdateScroll(infoPtr); + } + if (hdc) + LISTVIEW_Refresh(infoPtr, hdc); + else + { + PAINTSTRUCT ps; + + hdc = BeginPaint(infoPtr->hwndSelf, &ps); + if (!hdc) return 1; + if (ps.fErase) LISTVIEW_FillBkgnd(infoPtr, hdc, &ps.rcPaint); + LISTVIEW_Refresh(infoPtr, hdc); + EndPaint(infoPtr->hwndSelf, &ps); + } + + return 0; +} + + +/*** + * DESCRIPTION: + * Paints/Repaints the listview control. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] hdc : device context handle + * [I] options : drawing options + * + * RETURN: + * Zero + */ +static LRESULT LISTVIEW_PrintClient(LISTVIEW_INFO *infoPtr, HDC hdc, DWORD options) +{ + FIXME("Partial Stub: (hdc=%p options=0x%08lx)\n", hdc, options); + + if ((options & PRF_CHECKVISIBLE) && !IsWindowVisible(infoPtr->hwndSelf)) + return 0; + + if (options & PRF_ERASEBKGND) + LISTVIEW_EraseBkgnd(infoPtr, hdc); + + if (options & PRF_CLIENT) + LISTVIEW_Paint(infoPtr, hdc); + + return 0; +} + + +/*** + * DESCRIPTION: + * Processes double click messages (right mouse button). + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] wKey : key flag + * [I] x,y : mouse coordinate + * + * RETURN: + * Zero + */ +static LRESULT LISTVIEW_RButtonDblClk(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y) +{ + LVHITTESTINFO lvHitTestInfo; + + TRACE("(key=%hu,X=%hu,Y=%hu)\n", wKey, x, y); + + /* send NM_RELEASEDCAPTURE notification */ + notify(infoPtr, NM_RELEASEDCAPTURE); + + /* send NM_RDBLCLK notification */ + lvHitTestInfo.pt.x = x; + lvHitTestInfo.pt.y = y; + LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE); + notify_click(infoPtr, NM_RDBLCLK, &lvHitTestInfo); + + return 0; +} + +/*** + * DESCRIPTION: + * Processes mouse down messages (right mouse button). + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] wKey : key flag + * [I] x,y : mouse coordinate + * + * RETURN: + * Zero + */ +static LRESULT LISTVIEW_RButtonDown(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y) +{ + LVHITTESTINFO lvHitTestInfo; + INT nItem; + + TRACE("(key=%hu,X=%hu,Y=%hu)\n", wKey, x, y); + + /* send NM_RELEASEDCAPTURE notification */ + notify(infoPtr, NM_RELEASEDCAPTURE); + + /* make sure the listview control window has the focus */ + if (!infoPtr->bFocus) SetFocus(infoPtr->hwndSelf); + + /* set right button down flag */ + infoPtr->bRButtonDown = TRUE; + + /* determine the index of the selected item */ + lvHitTestInfo.pt.x = x; + lvHitTestInfo.pt.y = y; + nItem = LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, TRUE); + + if ((nItem >= 0) && (nItem < infoPtr->nItemCount)) + { + LISTVIEW_SetItemFocus(infoPtr, nItem); + if (!((wKey & MK_SHIFT) || (wKey & MK_CONTROL)) && + !LISTVIEW_GetItemState(infoPtr, nItem, LVIS_SELECTED)) + LISTVIEW_SetSelection(infoPtr, nItem); + } + else + { + LISTVIEW_DeselectAll(infoPtr); + } + + return 0; +} + +/*** + * DESCRIPTION: + * Processes mouse up messages (right mouse button). + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] wKey : key flag + * [I] x,y : mouse coordinate + * + * RETURN: + * Zero + */ +static LRESULT LISTVIEW_RButtonUp(LISTVIEW_INFO *infoPtr, WORD wKey, INT x, INT y) +{ + LVHITTESTINFO lvHitTestInfo; + POINT pt; + + TRACE("(key=%hu,X=%hu,Y=%hu)\n", wKey, x, y); + + if (!infoPtr->bRButtonDown) return 0; + + /* set button flag */ + infoPtr->bRButtonDown = FALSE; + + /* Send NM_RClICK notification */ + lvHitTestInfo.pt.x = x; + lvHitTestInfo.pt.y = y; + LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, TRUE, FALSE); + notify_click(infoPtr, NM_RCLICK, &lvHitTestInfo); + + /* Change to screen coordinate for WM_CONTEXTMENU */ + pt = lvHitTestInfo.pt; + ClientToScreen(infoPtr->hwndSelf, &pt); + + /* Send a WM_CONTEXTMENU message in response to the RBUTTONUP */ + SendMessageW(infoPtr->hwndSelf, WM_CONTEXTMENU, + (WPARAM)infoPtr->hwndSelf, MAKELPARAM(pt.x, pt.y)); + + return 0; +} + + +/*** + * DESCRIPTION: + * Sets the cursor. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] hwnd : window handle of window containing the cursor + * [I] nHittest : hit-test code + * [I] wMouseMsg : ideintifier of the mouse message + * + * RETURN: + * TRUE if cursor is set + * FALSE otherwise + */ +static BOOL LISTVIEW_SetCursor(LISTVIEW_INFO *infoPtr, HWND hwnd, UINT nHittest, UINT wMouseMsg) +{ + LVHITTESTINFO lvHitTestInfo; + + if(!(infoPtr->dwLvExStyle & LVS_EX_TRACKSELECT)) return FALSE; + + if(!infoPtr->hHotCursor) return FALSE; + + GetCursorPos(&lvHitTestInfo.pt); + if (LISTVIEW_HitTest(infoPtr, &lvHitTestInfo, FALSE, FALSE) < 0) return FALSE; + + SetCursor(infoPtr->hHotCursor); + + return TRUE; +} + +/*** + * DESCRIPTION: + * Sets the focus. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] hwndLoseFocus : handle of previously focused window + * + * RETURN: + * Zero + */ +static LRESULT LISTVIEW_SetFocus(LISTVIEW_INFO *infoPtr, HWND hwndLoseFocus) +{ + TRACE("(hwndLoseFocus=%p)\n", hwndLoseFocus); + + /* if we have the focus already, there's nothing to do */ + if (infoPtr->bFocus) return 0; + + /* send NM_SETFOCUS notification */ + notify(infoPtr, NM_SETFOCUS); + + /* set window focus flag */ + infoPtr->bFocus = TRUE; + + /* put the focus rect back on */ + LISTVIEW_ShowFocusRect(infoPtr, TRUE); + + /* redraw all visible selected items */ + LISTVIEW_InvalidateSelectedItems(infoPtr); + + return 0; +} + +/*** + * DESCRIPTION: + * Sets the font. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] fRedraw : font handle + * [I] fRedraw : redraw flag + * + * RETURN: + * Zero + */ +static LRESULT LISTVIEW_SetFont(LISTVIEW_INFO *infoPtr, HFONT hFont, WORD fRedraw) +{ + HFONT oldFont = infoPtr->hFont; + + TRACE("(hfont=%p,redraw=%hu)\n", hFont, fRedraw); + + infoPtr->hFont = hFont ? hFont : infoPtr->hDefaultFont; + if (infoPtr->hFont == oldFont) return 0; + + LISTVIEW_SaveTextMetrics(infoPtr); + + if ((infoPtr->dwStyle & LVS_TYPEMASK) == LVS_REPORT) + SendMessageW(infoPtr->hwndHeader, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(fRedraw, 0)); + + if (fRedraw) LISTVIEW_InvalidateList(infoPtr); + + return 0; +} + +/*** + * DESCRIPTION: + * Message handling for WM_SETREDRAW. + * For the Listview, it invalidates the entire window (the doc specifies otherwise) + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] bRedraw: state of redraw flag + * + * RETURN: + * DefWinProc return value + */ +static LRESULT LISTVIEW_SetRedraw(LISTVIEW_INFO *infoPtr, BOOL bRedraw) +{ + TRACE("infoPtr->bRedraw=%d, bRedraw=%d\n", infoPtr->bRedraw, bRedraw); + + /* we cannot use straight equality here because _any_ non-zero value is TRUE */ + if ((infoPtr->bRedraw && bRedraw) || (!infoPtr->bRedraw && !bRedraw)) return 0; + + infoPtr->bRedraw = bRedraw; + + if(!bRedraw) return 0; + + if (is_autoarrange(infoPtr)) + LISTVIEW_Arrange(infoPtr, LVA_DEFAULT); + LISTVIEW_UpdateScroll(infoPtr); + + /* despite what the WM_SETREDRAW docs says, apps expect us + * to invalidate the listview here... stupid! */ + LISTVIEW_InvalidateList(infoPtr); + + return 0; +} + +/*** + * DESCRIPTION: + * Resizes the listview control. This function processes WM_SIZE + * messages. At this time, the width and height are not used. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] Width : new width + * [I] Height : new height + * + * RETURN: + * Zero + */ +static LRESULT LISTVIEW_Size(LISTVIEW_INFO *infoPtr, int Width, int Height) +{ + RECT rcOld = infoPtr->rcList; + + TRACE("(width=%d, height=%d)\n", Width, Height); + + LISTVIEW_UpdateSize(infoPtr); + if (EqualRect(&rcOld, &infoPtr->rcList)) return 0; + + /* do not bother with display related stuff if we're not redrawing */ + if (!is_redrawing(infoPtr)) return 0; + + if (is_autoarrange(infoPtr)) + LISTVIEW_Arrange(infoPtr, LVA_DEFAULT); + + LISTVIEW_UpdateScroll(infoPtr); + + /* refresh all only for lists whose height changed significantly */ + if ((infoPtr->dwStyle & LVS_TYPEMASK) == LVS_LIST && + (rcOld.bottom - rcOld.top) / infoPtr->nItemHeight != + (infoPtr->rcList.bottom - infoPtr->rcList.top) / infoPtr->nItemHeight) + LISTVIEW_InvalidateList(infoPtr); + + return 0; +} + +/*** + * DESCRIPTION: + * Sets the size information. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * + * RETURN: + * None + */ +static void LISTVIEW_UpdateSize(LISTVIEW_INFO *infoPtr) +{ + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + + TRACE("uView=%d, rcList(old)=%s\n", uView, debugrect(&infoPtr->rcList)); + + GetClientRect(infoPtr->hwndSelf, &infoPtr->rcList); + + if (uView == LVS_LIST) + { + /* Apparently the "LIST" style is supposed to have the same + * number of items in a column even if there is no scroll bar. + * Since if a scroll bar already exists then the bottom is already + * reduced, only reduce if the scroll bar does not currently exist. + * The "2" is there to mimic the native control. I think it may be + * related to either padding or edges. (GLA 7/2002) + */ + if (!(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & WS_HSCROLL)) + infoPtr->rcList.bottom -= GetSystemMetrics(SM_CYHSCROLL); + infoPtr->rcList.bottom = max (infoPtr->rcList.bottom - 2, 0); + } + else if (uView == LVS_REPORT && !(infoPtr->dwStyle & LVS_NOCOLUMNHEADER)) + { + HDLAYOUT hl; + WINDOWPOS wp; + + hl.prc = &infoPtr->rcList; + hl.pwpos = ℘ + Header_Layout(infoPtr->hwndHeader, &hl); + + SetWindowPos(wp.hwnd, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags); + + infoPtr->rcList.top = max(wp.cy, 0); + } + + TRACE(" rcList=%s\n", debugrect(&infoPtr->rcList)); +} + +/*** + * DESCRIPTION: + * Processes WM_STYLECHANGED messages. + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] wStyleType : window style type (normal or extended) + * [I] lpss : window style information + * + * RETURN: + * Zero + */ +static INT LISTVIEW_StyleChanged(LISTVIEW_INFO *infoPtr, WPARAM wStyleType, + const STYLESTRUCT *lpss) +{ + UINT uNewView = lpss->styleNew & LVS_TYPEMASK; + UINT uOldView = lpss->styleOld & LVS_TYPEMASK; + + TRACE("(styletype=%x, styleOld=0x%08lx, styleNew=0x%08lx)\n", + wStyleType, lpss->styleOld, lpss->styleNew); + + if (wStyleType != GWL_STYLE) return 0; + + /* FIXME: if LVS_NOSORTHEADER changed, update header */ + /* what if LVS_OWNERDATA changed? */ + /* or LVS_SINGLESEL */ + /* or LVS_SORT{AS,DES}CENDING */ + + infoPtr->dwStyle = lpss->styleNew; + + if (((lpss->styleOld & WS_HSCROLL) != 0)&& + ((lpss->styleNew & WS_HSCROLL) == 0)) + ShowScrollBar(infoPtr->hwndSelf, SB_HORZ, FALSE); + + if (((lpss->styleOld & WS_VSCROLL) != 0)&& + ((lpss->styleNew & WS_VSCROLL) == 0)) + ShowScrollBar(infoPtr->hwndSelf, SB_VERT, FALSE); + + if (uNewView != uOldView) + { + SIZE oldIconSize = infoPtr->iconSize; + HIMAGELIST himl; + + SendMessageW(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0); + ShowWindow(infoPtr->hwndHeader, SW_HIDE); + + ShowScrollBar(infoPtr->hwndSelf, SB_BOTH, FALSE); + SetRectEmpty(&infoPtr->rcFocus); + + himl = (uNewView == LVS_ICON ? infoPtr->himlNormal : infoPtr->himlSmall); + set_icon_size(&infoPtr->iconSize, himl, uNewView != LVS_ICON); + + if (uNewView == LVS_ICON) + { + if ((infoPtr->iconSize.cx != oldIconSize.cx) || (infoPtr->iconSize.cy != oldIconSize.cy)) + { + TRACE("icon old size=(%ld,%ld), new size=(%ld,%ld)\n", + oldIconSize.cx, oldIconSize.cy, infoPtr->iconSize.cx, infoPtr->iconSize.cy); + LISTVIEW_SetIconSpacing(infoPtr, 0, 0); + } + } + else if (uNewView == LVS_REPORT) + { + HDLAYOUT hl; + WINDOWPOS wp; + + hl.prc = &infoPtr->rcList; + hl.pwpos = ℘ + Header_Layout(infoPtr->hwndHeader, &hl); + SetWindowPos(infoPtr->hwndHeader, infoPtr->hwndSelf, wp.x, wp.y, wp.cx, wp.cy, wp.flags); + } + + LISTVIEW_UpdateItemSize(infoPtr); + } + + if (uNewView == LVS_REPORT) + ShowWindow(infoPtr->hwndHeader, (lpss->styleNew & LVS_NOCOLUMNHEADER) ? SW_HIDE : SW_SHOWNORMAL); + + if ( (uNewView == LVS_ICON || uNewView == LVS_SMALLICON) && + (uNewView != uOldView || ((lpss->styleNew ^ lpss->styleOld) & LVS_ALIGNMASK)) ) + LISTVIEW_Arrange(infoPtr, LVA_DEFAULT); + + /* update the size of the client area */ + LISTVIEW_UpdateSize(infoPtr); + + /* add scrollbars if needed */ + LISTVIEW_UpdateScroll(infoPtr); + + /* invalidate client area + erase background */ + LISTVIEW_InvalidateList(infoPtr); + + return 0; +} + +/*** + * DESCRIPTION: + * Window procedure of the listview control. + * + */ +static LRESULT WINAPI +LISTVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongPtrW(hwnd, 0); + + TRACE("(uMsg=%x wParam=%x lParam=%lx)\n", uMsg, wParam, lParam); + + if (!infoPtr && (uMsg != WM_CREATE)) + return DefWindowProcW(hwnd, uMsg, wParam, lParam); + + switch (uMsg) + { + case LVM_APPROXIMATEVIEWRECT: + return LISTVIEW_ApproximateViewRect(infoPtr, (INT)wParam, + LOWORD(lParam), HIWORD(lParam)); + case LVM_ARRANGE: + return LISTVIEW_Arrange(infoPtr, (INT)wParam); + +/* case LVM_CANCELEDITLABEL: */ + + case LVM_CREATEDRAGIMAGE: + return (LRESULT)LISTVIEW_CreateDragImage(infoPtr, (INT)wParam, (LPPOINT)lParam); + + case LVM_DELETEALLITEMS: + return LISTVIEW_DeleteAllItems(infoPtr); + + case LVM_DELETECOLUMN: + return LISTVIEW_DeleteColumn(infoPtr, (INT)wParam); + + case LVM_DELETEITEM: + return LISTVIEW_DeleteItem(infoPtr, (INT)wParam); + + case LVM_EDITLABELW: + return (LRESULT)LISTVIEW_EditLabelT(infoPtr, (INT)wParam, TRUE); + + case LVM_EDITLABELA: + return (LRESULT)LISTVIEW_EditLabelT(infoPtr, (INT)wParam, FALSE); + + /* case LVM_ENABLEGROUPVIEW: */ + + case LVM_ENSUREVISIBLE: + return LISTVIEW_EnsureVisible(infoPtr, (INT)wParam, (BOOL)lParam); + + case LVM_FINDITEMW: + return LISTVIEW_FindItemW(infoPtr, (INT)wParam, (LPLVFINDINFOW)lParam); + + case LVM_FINDITEMA: + return LISTVIEW_FindItemA(infoPtr, (INT)wParam, (LPLVFINDINFOA)lParam); + + case LVM_GETBKCOLOR: + return infoPtr->clrBk; + + /* case LVM_GETBKIMAGE: */ + + case LVM_GETCALLBACKMASK: + return infoPtr->uCallbackMask; + + case LVM_GETCOLUMNA: + return LISTVIEW_GetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, FALSE); + + case LVM_GETCOLUMNW: + return LISTVIEW_GetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, TRUE); + + case LVM_GETCOLUMNORDERARRAY: + return LISTVIEW_GetColumnOrderArray(infoPtr, (INT)wParam, (LPINT)lParam); + + case LVM_GETCOLUMNWIDTH: + return LISTVIEW_GetColumnWidth(infoPtr, (INT)wParam); + + case LVM_GETCOUNTPERPAGE: + return LISTVIEW_GetCountPerPage(infoPtr); + + case LVM_GETEDITCONTROL: + return (LRESULT)infoPtr->hwndEdit; + + case LVM_GETEXTENDEDLISTVIEWSTYLE: + return infoPtr->dwLvExStyle; + + /* case LVM_GETGROUPINFO: */ + + /* case LVM_GETGROUPMETRICS: */ + + case LVM_GETHEADER: + return (LRESULT)infoPtr->hwndHeader; + + case LVM_GETHOTCURSOR: + return (LRESULT)infoPtr->hHotCursor; + + case LVM_GETHOTITEM: + return infoPtr->nHotItem; + + case LVM_GETHOVERTIME: + return infoPtr->dwHoverTime; + + case LVM_GETIMAGELIST: + return (LRESULT)LISTVIEW_GetImageList(infoPtr, (INT)wParam); + + /* case LVM_GETINSERTMARK: */ + + /* case LVM_GETINSERTMARKCOLOR: */ + + /* case LVM_GETINSERTMARKRECT: */ + + case LVM_GETISEARCHSTRINGA: + case LVM_GETISEARCHSTRINGW: + FIXME("LVM_GETISEARCHSTRING: unimplemented\n"); + return FALSE; + + case LVM_GETITEMA: + return LISTVIEW_GetItemExtT(infoPtr, (LPLVITEMW)lParam, FALSE); + + case LVM_GETITEMW: + return LISTVIEW_GetItemExtT(infoPtr, (LPLVITEMW)lParam, TRUE); + + case LVM_GETITEMCOUNT: + return infoPtr->nItemCount; + + case LVM_GETITEMPOSITION: + return LISTVIEW_GetItemPosition(infoPtr, (INT)wParam, (LPPOINT)lParam); + + case LVM_GETITEMRECT: + return LISTVIEW_GetItemRect(infoPtr, (INT)wParam, (LPRECT)lParam); + + case LVM_GETITEMSPACING: + return LISTVIEW_GetItemSpacing(infoPtr, (BOOL)wParam); + + case LVM_GETITEMSTATE: + return LISTVIEW_GetItemState(infoPtr, (INT)wParam, (UINT)lParam); + + case LVM_GETITEMTEXTA: + return LISTVIEW_GetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam, FALSE); + + case LVM_GETITEMTEXTW: + return LISTVIEW_GetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam, TRUE); + + case LVM_GETNEXTITEM: + return LISTVIEW_GetNextItem(infoPtr, (INT)wParam, LOWORD(lParam)); + + case LVM_GETNUMBEROFWORKAREAS: + FIXME("LVM_GETNUMBEROFWORKAREAS: unimplemented\n"); + return 1; + + case LVM_GETORIGIN: + if (!lParam) return FALSE; + LISTVIEW_GetOrigin(infoPtr, (LPPOINT)lParam); + return TRUE; + + /* case LVM_GETOUTLINECOLOR: */ + + /* case LVM_GETSELECTEDCOLUMN: */ + + case LVM_GETSELECTEDCOUNT: + return LISTVIEW_GetSelectedCount(infoPtr); + + case LVM_GETSELECTIONMARK: + return infoPtr->nSelectionMark; + + case LVM_GETSTRINGWIDTHA: + return LISTVIEW_GetStringWidthT(infoPtr, (LPCWSTR)lParam, FALSE); + + case LVM_GETSTRINGWIDTHW: + return LISTVIEW_GetStringWidthT(infoPtr, (LPCWSTR)lParam, TRUE); + + case LVM_GETSUBITEMRECT: + return LISTVIEW_GetSubItemRect(infoPtr, (UINT)wParam, (LPRECT)lParam); + + case LVM_GETTEXTBKCOLOR: + return infoPtr->clrTextBk; + + case LVM_GETTEXTCOLOR: + return infoPtr->clrText; + + /* case LVM_GETTILEINFO: */ + + /* case LVM_GETTILEVIEWINFO: */ + + case LVM_GETTOOLTIPS: + if( !infoPtr->hwndToolTip ) + infoPtr->hwndToolTip = COMCTL32_CreateToolTip( hwnd ); + return (LRESULT)infoPtr->hwndToolTip; + + case LVM_GETTOPINDEX: + return LISTVIEW_GetTopIndex(infoPtr); + + /*case LVM_GETUNICODEFORMAT: + FIXME("LVM_GETUNICODEFORMAT: unimplemented\n"); + return FALSE;*/ + + /* case LVM_GETVIEW: */ + + case LVM_GETVIEWRECT: + return LISTVIEW_GetViewRect(infoPtr, (LPRECT)lParam); + + case LVM_GETWORKAREAS: + FIXME("LVM_GETWORKAREAS: unimplemented\n"); + return FALSE; + + /* case LVM_HASGROUP: */ + + case LVM_HITTEST: + return LISTVIEW_HitTest(infoPtr, (LPLVHITTESTINFO)lParam, FALSE, FALSE); + + case LVM_INSERTCOLUMNA: + return LISTVIEW_InsertColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, FALSE); + + case LVM_INSERTCOLUMNW: + return LISTVIEW_InsertColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, TRUE); + + /* case LVM_INSERTGROUP: */ + + /* case LVM_INSERTGROUPSORTED: */ + + case LVM_INSERTITEMA: + return LISTVIEW_InsertItemT(infoPtr, (LPLVITEMW)lParam, FALSE); + + case LVM_INSERTITEMW: + return LISTVIEW_InsertItemT(infoPtr, (LPLVITEMW)lParam, TRUE); + + /* case LVM_INSERTMARKHITTEST: */ + + /* case LVM_ISGROUPVIEWENABLED: */ + + /* case LVM_MAPIDTOINDEX: */ + + /* case LVM_MAPINDEXTOID: */ + + /* case LVM_MOVEGROUP: */ + + /* case LVM_MOVEITEMTOGROUP: */ + + case LVM_REDRAWITEMS: + return LISTVIEW_RedrawItems(infoPtr, (INT)wParam, (INT)lParam); + + /* case LVM_REMOVEALLGROUPS: */ + + /* case LVM_REMOVEGROUP: */ + + case LVM_SCROLL: + return LISTVIEW_Scroll(infoPtr, (INT)wParam, (INT)lParam); + + case LVM_SETBKCOLOR: + return LISTVIEW_SetBkColor(infoPtr, (COLORREF)lParam); + + /* case LVM_SETBKIMAGE: */ + + case LVM_SETCALLBACKMASK: + infoPtr->uCallbackMask = (UINT)wParam; + return TRUE; + + case LVM_SETCOLUMNA: + return LISTVIEW_SetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, FALSE); + + case LVM_SETCOLUMNW: + return LISTVIEW_SetColumnT(infoPtr, (INT)wParam, (LPLVCOLUMNW)lParam, TRUE); + + case LVM_SETCOLUMNORDERARRAY: + return LISTVIEW_SetColumnOrderArray(infoPtr, (INT)wParam, (LPINT)lParam); + + case LVM_SETCOLUMNWIDTH: + return LISTVIEW_SetColumnWidth(infoPtr, (INT)wParam, (short)LOWORD(lParam)); + + case LVM_SETEXTENDEDLISTVIEWSTYLE: + return LISTVIEW_SetExtendedListViewStyle(infoPtr, (DWORD)wParam, (DWORD)lParam); + + /* case LVM_SETGROUPINFO: */ + + /* case LVM_SETGROUPMETRICS: */ + + case LVM_SETHOTCURSOR: + return (LRESULT)LISTVIEW_SetHotCursor(infoPtr, (HCURSOR)lParam); + + case LVM_SETHOTITEM: + return LISTVIEW_SetHotItem(infoPtr, (INT)wParam); + + case LVM_SETHOVERTIME: + return LISTVIEW_SetHoverTime(infoPtr, (DWORD)wParam); + + case LVM_SETICONSPACING: + return LISTVIEW_SetIconSpacing(infoPtr, (short)LOWORD(lParam), (short)HIWORD(lParam)); + + case LVM_SETIMAGELIST: + return (LRESULT)LISTVIEW_SetImageList(infoPtr, (INT)wParam, (HIMAGELIST)lParam); + + /* case LVM_SETINFOTIP: */ + + /* case LVM_SETINSERTMARK: */ + + /* case LVM_SETINSERTMARKCOLOR: */ + + case LVM_SETITEMA: + return LISTVIEW_SetItemT(infoPtr, (LPLVITEMW)lParam, FALSE); + + case LVM_SETITEMW: + return LISTVIEW_SetItemT(infoPtr, (LPLVITEMW)lParam, TRUE); + + case LVM_SETITEMCOUNT: + return LISTVIEW_SetItemCount(infoPtr, (INT)wParam, (DWORD)lParam); + + case LVM_SETITEMPOSITION: + { + POINT pt; + pt.x = (short)LOWORD(lParam); + pt.y = (short)HIWORD(lParam); + return LISTVIEW_SetItemPosition(infoPtr, (INT)wParam, pt); + } + + case LVM_SETITEMPOSITION32: + if (lParam == 0) return FALSE; + return LISTVIEW_SetItemPosition(infoPtr, (INT)wParam, *((POINT*)lParam)); + + case LVM_SETITEMSTATE: + return LISTVIEW_SetItemState(infoPtr, (INT)wParam, (LPLVITEMW)lParam); + + case LVM_SETITEMTEXTA: + return LISTVIEW_SetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam, FALSE); + + case LVM_SETITEMTEXTW: + return LISTVIEW_SetItemTextT(infoPtr, (INT)wParam, (LPLVITEMW)lParam, TRUE); + + /* case LVM_SETOUTLINECOLOR: */ + + /* case LVM_SETSELECTEDCOLUMN: */ + + case LVM_SETSELECTIONMARK: + return LISTVIEW_SetSelectionMark(infoPtr, (INT)lParam); + + case LVM_SETTEXTBKCOLOR: + return LISTVIEW_SetTextBkColor(infoPtr, (COLORREF)lParam); + + case LVM_SETTEXTCOLOR: + return LISTVIEW_SetTextColor(infoPtr, (COLORREF)lParam); + + /* case LVM_SETTILEINFO: */ + + /* case LVM_SETTILEVIEWINFO: */ + + /* case LVM_SETTILEWIDTH: */ + + case LVM_SETTOOLTIPS: + return (LRESULT)LISTVIEW_SetToolTips(infoPtr, (HWND)lParam); + + /* case LVM_SETUNICODEFORMAT: */ + + /* case LVM_SETVIEW: */ + + /* case LVM_SETWORKAREAS: */ + + /* case LVM_SORTGROUPS: */ + + case LVM_SORTITEMS: + return LISTVIEW_SortItems(infoPtr, (PFNLVCOMPARE)lParam, (LPARAM)wParam); + + /* LVM_SORTITEMSEX: */ + + case LVM_SUBITEMHITTEST: + return LISTVIEW_HitTest(infoPtr, (LPLVHITTESTINFO)lParam, TRUE, FALSE); + + case LVM_UPDATE: + return LISTVIEW_Update(infoPtr, (INT)wParam); + + case WM_CHAR: + return LISTVIEW_ProcessLetterKeys( infoPtr, wParam, lParam ); + + case WM_COMMAND: + return LISTVIEW_Command(infoPtr, wParam, lParam); + + case WM_CREATE: + return LISTVIEW_Create(hwnd, (LPCREATESTRUCTW)lParam); + + case WM_ENABLE: + return LISTVIEW_Enable(infoPtr, (BOOL)wParam); + + case WM_ERASEBKGND: + return LISTVIEW_EraseBkgnd(infoPtr, (HDC)wParam); + + case WM_GETDLGCODE: + return DLGC_WANTCHARS | DLGC_WANTARROWS; + + case WM_GETFONT: + return (LRESULT)infoPtr->hFont; + + case WM_HSCROLL: + return LISTVIEW_HScroll(infoPtr, (INT)LOWORD(wParam), 0, (HWND)lParam); + + case WM_KEYDOWN: + return LISTVIEW_KeyDown(infoPtr, (INT)wParam, (LONG)lParam); + + case WM_KILLFOCUS: + return LISTVIEW_KillFocus(infoPtr); + + case WM_LBUTTONDBLCLK: + return LISTVIEW_LButtonDblClk(infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); + + case WM_LBUTTONDOWN: + return LISTVIEW_LButtonDown(infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); + + case WM_LBUTTONUP: + return LISTVIEW_LButtonUp(infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); + + case WM_MOUSEMOVE: + return LISTVIEW_MouseMove (infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); + + case WM_MOUSEHOVER: + return LISTVIEW_MouseHover(infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); + + case WM_NCDESTROY: + return LISTVIEW_NCDestroy(infoPtr); + + case WM_NOTIFY: + if (lParam && ((LPNMHDR)lParam)->hwndFrom == infoPtr->hwndHeader) + return LISTVIEW_HeaderNotification(infoPtr, (LPNMHEADERW)lParam); + else return 0; + + case WM_NOTIFYFORMAT: + return LISTVIEW_NotifyFormat(infoPtr, (HWND)wParam, (INT)lParam); + + case WM_PRINTCLIENT: + return LISTVIEW_PrintClient(infoPtr, (HDC)wParam, (DWORD)lParam); + + case WM_PAINT: + return LISTVIEW_Paint(infoPtr, (HDC)wParam); + + case WM_RBUTTONDBLCLK: + return LISTVIEW_RButtonDblClk(infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); + + case WM_RBUTTONDOWN: + return LISTVIEW_RButtonDown(infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); + + case WM_RBUTTONUP: + return LISTVIEW_RButtonUp(infoPtr, (WORD)wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); + + case WM_SETCURSOR: + if(LISTVIEW_SetCursor(infoPtr, (HWND)wParam, LOWORD(lParam), HIWORD(lParam))) + return TRUE; + goto fwd_msg; + + case WM_SETFOCUS: + return LISTVIEW_SetFocus(infoPtr, (HWND)wParam); + + case WM_SETFONT: + return LISTVIEW_SetFont(infoPtr, (HFONT)wParam, (WORD)lParam); + + case WM_SETREDRAW: + return LISTVIEW_SetRedraw(infoPtr, (BOOL)wParam); + + case WM_SIZE: + return LISTVIEW_Size(infoPtr, (short)LOWORD(lParam), (short)HIWORD(lParam)); + + case WM_STYLECHANGED: + return LISTVIEW_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam); + + case WM_SYSCOLORCHANGE: + COMCTL32_RefreshSysColors(); + return 0; + +/* case WM_TIMER: */ + + case WM_VSCROLL: + return LISTVIEW_VScroll(infoPtr, (INT)LOWORD(wParam), 0, (HWND)lParam); + + case WM_MOUSEWHEEL: + if (wParam & (MK_SHIFT | MK_CONTROL)) + return DefWindowProcW(hwnd, uMsg, wParam, lParam); + return LISTVIEW_MouseWheel(infoPtr, (short int)HIWORD(wParam)); + + case WM_WINDOWPOSCHANGED: + if (!(((WINDOWPOS *)lParam)->flags & SWP_NOSIZE)) + { + UINT uView = infoPtr->dwStyle & LVS_TYPEMASK; + SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | + SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE); + + if ((infoPtr->dwStyle & LVS_OWNERDRAWFIXED) && (uView == LVS_REPORT)) + { + MEASUREITEMSTRUCT mis; + mis.CtlType = ODT_LISTVIEW; + mis.CtlID = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); + mis.itemID = -1; + mis.itemWidth = 0; + mis.itemData = 0; + mis.itemHeight= infoPtr->nItemHeight; + SendMessageW(infoPtr->hwndNotify, WM_MEASUREITEM, mis.CtlID, (LPARAM)&mis); + if (infoPtr->nItemHeight != max(mis.itemHeight, 1)) + infoPtr->nMeasureItemHeight = infoPtr->nItemHeight = max(mis.itemHeight, 1); + } + + LISTVIEW_UpdateSize(infoPtr); + LISTVIEW_UpdateScroll(infoPtr); + } + return DefWindowProcW(hwnd, uMsg, wParam, lParam); + +/* case WM_WININICHANGE: */ + + default: + if ((uMsg >= WM_USER) && (uMsg < WM_APP)) + ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam); + + fwd_msg: + /* call default window procedure */ + return DefWindowProcW(hwnd, uMsg, wParam, lParam); + } + +} + +/*** + * DESCRIPTION: + * Registers the window class. + * + * PARAMETER(S): + * None + * + * RETURN: + * None + */ +void LISTVIEW_Register(void) +{ + WNDCLASSW wndClass; + + ZeroMemory(&wndClass, sizeof(WNDCLASSW)); + wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS; + wndClass.lpfnWndProc = LISTVIEW_WindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(LISTVIEW_INFO *); + wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW); + wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wndClass.lpszClassName = WC_LISTVIEWW; + RegisterClassW(&wndClass); +} + +/*** + * DESCRIPTION: + * Unregisters the window class. + * + * PARAMETER(S): + * None + * + * RETURN: + * None + */ +void LISTVIEW_Unregister(void) +{ + UnregisterClassW(WC_LISTVIEWW, NULL); +} + +/*** + * DESCRIPTION: + * Handle any WM_COMMAND messages + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] wParam : the first message parameter + * [I] lParam : the second message parameter + * + * RETURN: + * Zero. + */ +static LRESULT LISTVIEW_Command(LISTVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + switch (HIWORD(wParam)) + { + case EN_UPDATE: + { + /* + * Adjust the edit window size + */ + WCHAR buffer[1024]; + HDC hdc = GetDC(infoPtr->hwndEdit); + HFONT hFont, hOldFont = 0; + RECT rect; + SIZE sz; + int len; + + if (!infoPtr->hwndEdit || !hdc) return 0; + len = GetWindowTextW(infoPtr->hwndEdit, buffer, sizeof(buffer)/sizeof(buffer[0])); + GetWindowRect(infoPtr->hwndEdit, &rect); + + /* Select font to get the right dimension of the string */ + hFont = (HFONT)SendMessageW(infoPtr->hwndEdit, WM_GETFONT, 0, 0); + if(hFont != 0) + { + hOldFont = SelectObject(hdc, hFont); + } + + if (GetTextExtentPoint32W(hdc, buffer, lstrlenW(buffer), &sz)) + { + TEXTMETRICW textMetric; + + /* Add Extra spacing for the next character */ + GetTextMetricsW(hdc, &textMetric); + sz.cx += (textMetric.tmMaxCharWidth * 2); + + SetWindowPos ( + infoPtr->hwndEdit, + HWND_TOP, + 0, + 0, + sz.cx, + rect.bottom - rect.top, + SWP_DRAWFRAME|SWP_NOMOVE); + } + if(hFont != 0) + SelectObject(hdc, hOldFont); + + ReleaseDC(infoPtr->hwndEdit, hdc); + + break; + } + + default: + return SendMessageW (infoPtr->hwndNotify, WM_COMMAND, wParam, lParam); + } + + return 0; +} + + +/*** + * DESCRIPTION: + * Subclassed edit control windproc function + * + * PARAMETER(S): + * [I] hwnd : the edit window handle + * [I] uMsg : the message that is to be processed + * [I] wParam : first message parameter + * [I] lParam : second message parameter + * [I] isW : TRUE if input is Unicode + * + * RETURN: + * Zero. + */ +static LRESULT EditLblWndProcT(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL isW) +{ + LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)GetWindowLongPtrW(GetParent(hwnd), 0); + BOOL cancel = FALSE; + + TRACE("(hwnd=%p, uMsg=%x, wParam=%x, lParam=%lx, isW=%d)\n", + hwnd, uMsg, wParam, lParam, isW); + + switch (uMsg) + { + case WM_GETDLGCODE: + return DLGC_WANTARROWS | DLGC_WANTALLKEYS; + + case WM_KILLFOCUS: + break; + + case WM_DESTROY: + { + WNDPROC editProc = infoPtr->EditWndProc; + infoPtr->EditWndProc = 0; + SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (DWORD_PTR)editProc); + return CallWindowProcT(editProc, hwnd, uMsg, wParam, lParam, isW); + } + + case WM_KEYDOWN: + if (VK_ESCAPE == (INT)wParam) + { + cancel = TRUE; + break; + } + else if (VK_RETURN == (INT)wParam) + break; + + default: + return CallWindowProcT(infoPtr->EditWndProc, hwnd, uMsg, wParam, lParam, isW); + } + + /* kill the edit */ + if (infoPtr->hwndEdit) + { + LPWSTR buffer = NULL; + + infoPtr->hwndEdit = 0; + if (!cancel) + { + DWORD len = isW ? GetWindowTextLengthW(hwnd) : GetWindowTextLengthA(hwnd); + + if (len) + { + if ( (buffer = Alloc((len+1) * (isW ? sizeof(WCHAR) : sizeof(CHAR)))) ) + { + if (isW) GetWindowTextW(hwnd, buffer, len+1); + else GetWindowTextA(hwnd, (CHAR*)buffer, len+1); + } + } + } + LISTVIEW_EndEditLabelT(infoPtr, buffer, isW); + + if (buffer) Free(buffer); + + } + + SendMessageW(hwnd, WM_CLOSE, 0, 0); + return 0; +} + +/*** + * DESCRIPTION: + * Subclassed edit control Unicode windproc function + * + * PARAMETER(S): + * [I] hwnd : the edit window handle + * [I] uMsg : the message that is to be processed + * [I] wParam : first message parameter + * [I] lParam : second message parameter + * + * RETURN: + */ +LRESULT CALLBACK EditLblWndProcW(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + return EditLblWndProcT(hwnd, uMsg, wParam, lParam, TRUE); +} + +/*** + * DESCRIPTION: + * Subclassed edit control ANSI windproc function + * + * PARAMETER(S): + * [I] hwnd : the edit window handle + * [I] uMsg : the message that is to be processed + * [I] wParam : first message parameter + * [I] lParam : second message parameter + * + * RETURN: + */ +LRESULT CALLBACK EditLblWndProcA(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + return EditLblWndProcT(hwnd, uMsg, wParam, lParam, FALSE); +} + +/*** + * DESCRIPTION: + * Creates a subclassed edit cotrol + * + * PARAMETER(S): + * [I] infoPtr : valid pointer to the listview structure + * [I] text : initial text for the edit + * [I] style : the window style + * [I] isW : TRUE if input is Unicode + * + * RETURN: + */ +static HWND CreateEditLabelT(LISTVIEW_INFO *infoPtr, LPCWSTR text, DWORD style, + INT x, INT y, INT width, INT height, BOOL isW) +{ + WCHAR editName[5] = { 'E', 'd', 'i', 't', '\0' }; + HWND hedit; + SIZE sz; + HDC hdc; + HDC hOldFont=0; + TEXTMETRICW textMetric; + HINSTANCE hinst = (HINSTANCE)GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_HINSTANCE); + + TRACE("(text=%s, ..., isW=%d)\n", debugtext_t(text, isW), isW); + + style |= WS_CHILDWINDOW|WS_CLIPSIBLINGS|ES_LEFT|ES_AUTOHSCROLL|WS_BORDER; + hdc = GetDC(infoPtr->hwndSelf); + + /* Select the font to get appropriate metric dimensions */ + if(infoPtr->hFont != 0) + hOldFont = SelectObject(hdc, infoPtr->hFont); + + /*Get String Length in pixels */ + if(!GetTextExtentPoint32W(hdc, text, lstrlenW(text), &sz)) + sz.cx = 0; + + /*Add Extra spacing for the next character */ + GetTextMetricsW(hdc, &textMetric); + sz.cx += (textMetric.tmMaxCharWidth * 2); + + if(infoPtr->hFont != 0) + SelectObject(hdc, hOldFont); + + ReleaseDC(infoPtr->hwndSelf, hdc); + if (isW) + hedit = CreateWindowW(editName, text, style, x, y, sz.cx, height, infoPtr->hwndSelf, 0, hinst, 0); + else + hedit = CreateWindowA("Edit", (LPCSTR)text, style, x, y, sz.cx, height, infoPtr->hwndSelf, 0, hinst, 0); + + if (!hedit) return 0; + + infoPtr->EditWndProc = (WNDPROC) + (isW ? SetWindowLongPtrW(hedit, GWLP_WNDPROC, (DWORD_PTR)EditLblWndProcW) : + SetWindowLongPtrA(hedit, GWLP_WNDPROC, (DWORD_PTR)EditLblWndProcA) ); + + SendMessageW(hedit, WM_SETFONT, (WPARAM)infoPtr->hFont, FALSE); + + return hedit; +} diff --git a/reactos/lib/comctl32/monthcal.c b/reactos/lib/comctl32/monthcal.c index 25047586da9..21619e0595e 100644 --- a/reactos/lib/comctl32/monthcal.c +++ b/reactos/lib/comctl32/monthcal.c @@ -1,2024 +1,2024 @@ -/* Month calendar control - - * - * Copyright 1998, 1999 Eric Kohl (ekohl@abo.rhein-zeitung.de) - * Copyright 1999 Alex Priem (alexp@sci.kun.nl) - * Copyright 1999 Chris Morgan and - * James Abbatiello - * Copyright 2000 Uwe Bonnes - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTE - * - * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on Oct. 20, 2004, by Dimitrie O. Paun. - * - * Unless otherwise noted, we believe this code to be complete, as per - * the specification mentioned above. - * If you discover missing features, or bugs, please note them below. - * - * TODO: - * -- MCM_[GS]ETUNICODEFORMAT - * -- MONTHCAL_GetMonthRange - * -- handle resources better (doesn't work now); - * -- take care of internationalization. - * -- keyboard handling. - * -- GetRange: At the moment, we copy ranges anyway, regardless of - * infoPtr->rangeValid; an invalid range is simply filled - * with zeros in SetRange. Is this the right behavior? - * -- search for FIXME - */ - -#include -#include -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "comctl32.h" -#include "wine/unicode.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(monthcal); - -#define MC_SEL_LBUTUP 1 /* Left button released */ -#define MC_SEL_LBUTDOWN 2 /* Left button pressed in calendar */ -#define MC_PREVPRESSED 4 /* Prev month button pressed */ -#define MC_NEXTPRESSED 8 /* Next month button pressed */ -#define MC_NEXTMONTHDELAY 350 /* when continuously pressing `next */ - /* month', wait 500 ms before going */ - /* to the next month */ -#define MC_NEXTMONTHTIMER 1 /* Timer ID's */ -#define MC_PREVMONTHTIMER 2 - -#define countof(arr) (sizeof(arr)/sizeof(arr[0])) - -typedef struct -{ - HWND hwndSelf; - COLORREF bk; - COLORREF txt; - COLORREF titlebk; - COLORREF titletxt; - COLORREF monthbk; - COLORREF trailingtxt; - HFONT hFont; - HFONT hBoldFont; - int textHeight; - int textWidth; - int height_increment; - int width_increment; - int firstDayplace; /* place of the first day of the current month */ - int delta; /* scroll rate; # of months that the */ - /* control moves when user clicks a scroll button */ - int visible; /* # of months visible */ - int firstDay; /* Start month calendar with firstDay's day */ - int monthRange; - MONTHDAYSTATE *monthdayState; - SYSTEMTIME todaysDate; - DWORD currentMonth; - DWORD currentYear; - int status; /* See MC_SEL flags */ - int curSelDay; /* current selected day */ - int firstSelDay; /* first selected day */ - int maxSelCount; - SYSTEMTIME minSel; - SYSTEMTIME maxSel; - DWORD rangeValid; - SYSTEMTIME minDate; - SYSTEMTIME maxDate; - - RECT title; /* rect for the header above the calendar */ - RECT titlebtnnext; /* the `next month' button in the header */ - RECT titlebtnprev; /* the `prev month' button in the header */ - RECT titlemonth; /* the `month name' txt in the header */ - RECT titleyear; /* the `year number' txt in the header */ - RECT wdays; /* week days at top */ - RECT days; /* calendar area */ - RECT weeknums; /* week numbers at left side */ - RECT todayrect; /* `today: xx/xx/xx' text rect */ - HWND hwndNotify; /* Window to receive the notifications */ - HWND hWndYearEdit; /* Window Handle of edit box to handle years */ - HWND hWndYearUpDown;/* Window Handle of updown box to handle years */ -} MONTHCAL_INFO, *LPMONTHCAL_INFO; - - -/* Offsets of days in the week to the weekday of january 1 in a leap year */ -static const int DayOfWeekTable[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; - - -#define MONTHCAL_GetInfoPtr(hwnd) ((MONTHCAL_INFO *)GetWindowLongPtrW(hwnd, 0)) - -/* helper functions */ - -/* returns the number of days in any given month, checking for leap days */ -/* january is 1, december is 12 */ -int MONTHCAL_MonthLength(int month, int year) -{ - const int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}; - /*Wrap around, this eases handling*/ - if(month == 0) - month = 12; - if(month == 13) - month = 1; - - /* if we have a leap year add 1 day to February */ - /* a leap year is a year either divisible by 400 */ - /* or divisible by 4 and not by 100 */ - if(month == 2) { /* February */ - return mdays[month - 1] + ((year%400 == 0) ? 1 : ((year%100 != 0) && - (year%4 == 0)) ? 1 : 0); - } - else { - return mdays[month - 1]; - } -} - - -/* make sure that time is valid */ -static int MONTHCAL_ValidateTime(SYSTEMTIME time) -{ - if(time.wMonth > 12) return FALSE; - if(time.wDayOfWeek > 6) return FALSE; - if(time.wDay > MONTHCAL_MonthLength(time.wMonth, time.wYear)) - return FALSE; - if(time.wHour > 23) return FALSE; - if(time.wMinute > 59) return FALSE; - if(time.wSecond > 59) return FALSE; - if(time.wMilliseconds > 999) return FALSE; - - return TRUE; -} - - -/* Note:Depending on DST, this may be offset by a day. - Need to find out if we're on a DST place & adjust the clock accordingly. - Above function assumes we have a valid data. - Valid for year>1752; 1 <= d <= 31, 1 <= m <= 12. - 0 = Sunday. -*/ - -/* returns the day in the week(0 == sunday, 6 == saturday) */ -/* day(1 == 1st, 2 == 2nd... etc), year is the year value */ -static int MONTHCAL_CalculateDayOfWeek(DWORD day, DWORD month, DWORD year) -{ - year-=(month < 3); - - return((year + year/4 - year/100 + year/400 + - DayOfWeekTable[month-1] + day ) % 7); -} - -/* From a given point, calculate the row (weekpos), column(daypos) - and day in the calendar. day== 0 mean the last day of tha last month -*/ -static int MONTHCAL_CalcDayFromPos(MONTHCAL_INFO *infoPtr, int x, int y, - int *daypos,int *weekpos) -{ - int retval, firstDay; - RECT rcClient; - - GetClientRect(infoPtr->hwndSelf, &rcClient); - - /* if the point is outside the x bounds of the window put - it at the boundary */ - if (x > rcClient.right) - x = rcClient.right; - - - *daypos = (x - infoPtr->days.left ) / infoPtr->width_increment; - *weekpos = (y - infoPtr->days.top ) / infoPtr->height_increment; - - firstDay = (MONTHCAL_CalculateDayOfWeek(1, infoPtr->currentMonth, infoPtr->currentYear)+6 - infoPtr->firstDay)%7; - retval = *daypos + (7 * *weekpos) - firstDay; - return retval; -} - -/* day is the day of the month, 1 == 1st day of the month */ -/* sets x and y to be the position of the day */ -/* x == day, y == week where(0,0) == firstDay, 1st week */ -static void MONTHCAL_CalcDayXY(MONTHCAL_INFO *infoPtr, int day, int month, - int *x, int *y) -{ - int firstDay, prevMonth; - - firstDay = (MONTHCAL_CalculateDayOfWeek(1, infoPtr->currentMonth, infoPtr->currentYear) +6 - infoPtr->firstDay)%7; - - if(month==infoPtr->currentMonth) { - *x = (day + firstDay) % 7; - *y = (day + firstDay - *x) / 7; - return; - } - if(month < infoPtr->currentMonth) { - prevMonth = month - 1; - if(prevMonth==0) - prevMonth = 12; - - *x = (MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear) - firstDay) % 7; - *y = 0; - return; - } - - *y = MONTHCAL_MonthLength(month, infoPtr->currentYear - 1) / 7; - *x = (day + firstDay + MONTHCAL_MonthLength(month, - infoPtr->currentYear)) % 7; -} - - -/* x: column(day), y: row(week) */ -static void MONTHCAL_CalcDayRect(MONTHCAL_INFO *infoPtr, RECT *r, int x, int y) -{ - r->left = infoPtr->days.left + x * infoPtr->width_increment; - r->right = r->left + infoPtr->width_increment; - r->top = infoPtr->days.top + y * infoPtr->height_increment; - r->bottom = r->top + infoPtr->textHeight; -} - - -/* sets the RECT struct r to the rectangle around the day and month */ -/* day is the day value of the month(1 == 1st), month is the month */ -/* value(january == 1, december == 12) */ -static inline void MONTHCAL_CalcPosFromDay(MONTHCAL_INFO *infoPtr, - int day, int month, RECT *r) -{ - int x, y; - - MONTHCAL_CalcDayXY(infoPtr, day, month, &x, &y); - MONTHCAL_CalcDayRect(infoPtr, r, x, y); -} - - -/* day is the day in the month(1 == 1st of the month) */ -/* month is the month value(1 == january, 12 == december) */ -static void MONTHCAL_CircleDay(MONTHCAL_INFO *infoPtr, HDC hdc, int day, int month) -{ - HPEN hRedPen = CreatePen(PS_SOLID, 2, RGB(255, 0, 0)); - HPEN hOldPen2 = SelectObject(hdc, hRedPen); - POINT points[13]; - int x, y; - RECT day_rect; - - - MONTHCAL_CalcPosFromDay(infoPtr, day, month, &day_rect); - - x = day_rect.left; - y = day_rect.top; - - points[0].x = x; - points[0].y = y - 1; - points[1].x = x + 0.8 * infoPtr->width_increment; - points[1].y = y - 1; - points[2].x = x + 0.9 * infoPtr->width_increment; - points[2].y = y; - points[3].x = x + infoPtr->width_increment; - points[3].y = y + 0.5 * infoPtr->height_increment; - - points[4].x = x + infoPtr->width_increment; - points[4].y = y + 0.9 * infoPtr->height_increment; - points[5].x = x + 0.6 * infoPtr->width_increment; - points[5].y = y + 0.9 * infoPtr->height_increment; - points[6].x = x + 0.5 * infoPtr->width_increment; - points[6].y = y + 0.9 * infoPtr->height_increment; /* bring the bottom up just - a hair to fit inside the day rectangle */ - - points[7].x = x + 0.2 * infoPtr->width_increment; - points[7].y = y + 0.8 * infoPtr->height_increment; - points[8].x = x + 0.1 * infoPtr->width_increment; - points[8].y = y + 0.8 * infoPtr->height_increment; - points[9].x = x; - points[9].y = y + 0.5 * infoPtr->height_increment; - - points[10].x = x + 0.1 * infoPtr->width_increment; - points[10].y = y + 0.2 * infoPtr->height_increment; - points[11].x = x + 0.2 * infoPtr->width_increment; - points[11].y = y + 0.3 * infoPtr->height_increment; - points[12].x = x + 0.4 * infoPtr->width_increment; - points[12].y = y + 0.2 * infoPtr->height_increment; - - PolyBezier(hdc, points, 13); - DeleteObject(hRedPen); - SelectObject(hdc, hOldPen2); -} - - -static void MONTHCAL_DrawDay(MONTHCAL_INFO *infoPtr, HDC hdc, int day, int month, - int x, int y, int bold) -{ - static const WCHAR fmtW[] = { '%','d',0 }; - WCHAR buf[10]; - RECT r; - static int haveBoldFont, haveSelectedDay = FALSE; - HBRUSH hbr; - COLORREF oldCol = 0; - COLORREF oldBk = 0; - - wsprintfW(buf, fmtW, day); - -/* No need to check styles: when selection is not valid, it is set to zero. - * 1=infoPtr->minSel.wDay) && (day<=infoPtr->maxSel.wDay) - && (month==infoPtr->currentMonth)) { - HRGN hrgn; - RECT r2; - - TRACE("%d %d %d\n",day, infoPtr->minSel.wDay, infoPtr->maxSel.wDay); - TRACE("%ld %ld %ld %ld\n", r.left, r.top, r.right, r.bottom); - oldCol = SetTextColor(hdc, infoPtr->monthbk); - oldBk = SetBkColor(hdc, infoPtr->trailingtxt); - hbr = GetSysColorBrush(COLOR_GRAYTEXT); - hrgn = CreateEllipticRgn(r.left, r.top, r.right, r.bottom); - FillRgn(hdc, hrgn, hbr); - - /* FIXME: this may need to be changed now b/c of the other - drawing changes 11/3/99 CMM */ - r2.left = r.left - 0.25 * infoPtr->textWidth; - r2.top = r.top; - r2.right = r.left + 0.5 * infoPtr->textWidth; - r2.bottom = r.bottom; - if(haveSelectedDay) FillRect(hdc, &r2, hbr); - haveSelectedDay = TRUE; - } else { - haveSelectedDay = FALSE; - } - - /* need to add some code for multiple selections */ - - if((bold) &&(!haveBoldFont)) { - SelectObject(hdc, infoPtr->hBoldFont); - haveBoldFont = TRUE; - } - if((!bold) &&(haveBoldFont)) { - SelectObject(hdc, infoPtr->hFont); - haveBoldFont = FALSE; - } - - if(haveSelectedDay) { - SetTextColor(hdc, oldCol); - SetBkColor(hdc, oldBk); - } - - SetBkMode(hdc,TRANSPARENT); - DrawTextW(hdc, buf, -1, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE ); - - /* draw a rectangle around the currently selected days text */ - if((day==infoPtr->curSelDay) && (month==infoPtr->currentMonth)) - DrawFocusRect(hdc, &r); -} - - -static void MONTHCAL_Refresh(MONTHCAL_INFO *infoPtr, HDC hdc, PAINTSTRUCT* ps) -{ - static const WCHAR todayW[] = { 'T','o','d','a','y',':',0 }; - static const WCHAR fmt1W[] = { '%','s',' ','%','l','d',0 }; - static const WCHAR fmt2W[] = { '%','s',' ','%','s',0 }; - static const WCHAR fmt3W[] = { '%','d',0 }; - RECT *title=&infoPtr->title; - RECT *prev=&infoPtr->titlebtnprev; - RECT *next=&infoPtr->titlebtnnext; - RECT *titlemonth=&infoPtr->titlemonth; - RECT *titleyear=&infoPtr->titleyear; - RECT dayrect; - RECT *days=&dayrect; - RECT rtoday; - int i, j, m, mask, day, firstDay, weeknum, weeknum1,prevMonth; - int textHeight = infoPtr->textHeight, textWidth = infoPtr->textWidth; - SIZE size; - HBRUSH hbr; - HFONT currentFont; - WCHAR buf[20]; - WCHAR buf1[20]; - WCHAR buf2[32]; - COLORREF oldTextColor, oldBkColor; - DWORD dwStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE); - RECT rcTemp; - RECT rcDay; /* used in MONTHCAL_CalcDayRect() */ - SYSTEMTIME localtime; - int startofprescal; - - oldTextColor = SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); - - /* fill background */ - hbr = CreateSolidBrush (infoPtr->bk); - FillRect(hdc, &ps->rcPaint, hbr); - DeleteObject(hbr); - - /* draw header */ - if(IntersectRect(&rcTemp, &(ps->rcPaint), title)) - { - hbr = CreateSolidBrush(infoPtr->titlebk); - FillRect(hdc, title, hbr); - DeleteObject(hbr); - } - - /* if the previous button is pressed draw it depressed */ - if(IntersectRect(&rcTemp, &(ps->rcPaint), prev)) - { - if((infoPtr->status & MC_PREVPRESSED)) - DrawFrameControl(hdc, prev, DFC_SCROLL, - DFCS_SCROLLLEFT | DFCS_PUSHED | - (dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0)); - else /* if the previous button is pressed draw it depressed */ - DrawFrameControl(hdc, prev, DFC_SCROLL, - DFCS_SCROLLLEFT |(dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0)); - } - - /* if next button is depressed draw it depressed */ - if(IntersectRect(&rcTemp, &(ps->rcPaint), next)) - { - if((infoPtr->status & MC_NEXTPRESSED)) - DrawFrameControl(hdc, next, DFC_SCROLL, - DFCS_SCROLLRIGHT | DFCS_PUSHED | - (dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0)); - else /* if the next button is pressed draw it depressed */ - DrawFrameControl(hdc, next, DFC_SCROLL, - DFCS_SCROLLRIGHT |(dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0)); - } - - oldBkColor = SetBkColor(hdc, infoPtr->titlebk); - SetTextColor(hdc, infoPtr->titletxt); - currentFont = SelectObject(hdc, infoPtr->hBoldFont); - - GetLocaleInfoW( LOCALE_USER_DEFAULT,LOCALE_SMONTHNAME1+infoPtr->currentMonth -1, - buf1,countof(buf1)); - wsprintfW(buf, fmt1W, buf1, infoPtr->currentYear); - - if(IntersectRect(&rcTemp, &(ps->rcPaint), title)) - { - DrawTextW(hdc, buf, strlenW(buf), title, - DT_CENTER | DT_VCENTER | DT_SINGLELINE); - } - -/* titlemonth left/right contained rect for whole titletxt('June 1999') - * MCM_HitTestInfo wants month & year rects, so prepare these now. - *(no, we can't draw them separately; the whole text is centered) - */ - GetTextExtentPoint32W(hdc, buf, strlenW(buf), &size); - titlemonth->left = title->right / 2 + title->left / 2 - size.cx / 2; - titleyear->right = title->right / 2 + title->left / 2 + size.cx / 2; - GetTextExtentPoint32W(hdc, buf1, strlenW(buf1), &size); - titlemonth->right = titlemonth->left + size.cx; - titleyear->left = titlemonth->right; - - /* draw month area */ - rcTemp.top=infoPtr->wdays.top; - rcTemp.left=infoPtr->wdays.left; - rcTemp.bottom=infoPtr->todayrect.bottom; - rcTemp.right =infoPtr->todayrect.right; - if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcTemp)) - { - hbr = CreateSolidBrush(infoPtr->monthbk); - FillRect(hdc, &rcTemp, hbr); - DeleteObject(hbr); - } - -/* draw line under day abbreviatons */ - - MoveToEx(hdc, infoPtr->days.left + 3, title->bottom + textHeight + 1, NULL); - LineTo(hdc, infoPtr->days.right - 3, title->bottom + textHeight + 1); - - prevMonth = infoPtr->currentMonth - 1; - if(prevMonth == 0) /* if currentMonth is january(1) prevMonth is */ - prevMonth = 12; /* december(12) of the previous year */ - - infoPtr->wdays.left = infoPtr->days.left = infoPtr->weeknums.right; -/* draw day abbreviations */ - - SelectObject(hdc, infoPtr->hFont); - SetBkColor(hdc, infoPtr->monthbk); - SetTextColor(hdc, infoPtr->trailingtxt); - - /* copy this rect so we can change the values without changing */ - /* the original version */ - days->left = infoPtr->wdays.left; - days->right = days->left + infoPtr->width_increment; - days->top = infoPtr->wdays.top; - days->bottom = infoPtr->wdays.bottom; - - i = infoPtr->firstDay; - - for(j=0; j<7; j++) { - GetLocaleInfoW( LOCALE_USER_DEFAULT,LOCALE_SABBREVDAYNAME1 + (i+j+6)%7, buf, countof(buf)); - DrawTextW(hdc, buf, strlenW(buf), days, DT_CENTER | DT_VCENTER | DT_SINGLELINE ); - days->left+=infoPtr->width_increment; - days->right+=infoPtr->width_increment; - } - -/* draw day numbers; first, the previous month */ - - firstDay = MONTHCAL_CalculateDayOfWeek(1, infoPtr->currentMonth, infoPtr->currentYear); - - day = MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear) + - (infoPtr->firstDay + 7 - firstDay)%7 + 1; - if (day > MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear)) - day -=7; - startofprescal = day; - mask = 1<<(day-1); - - i = 0; - m = 0; - while(day <= MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear)) { - MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, 0); - if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay)) - { - MONTHCAL_DrawDay(infoPtr, hdc, day, prevMonth, i, 0, - infoPtr->monthdayState[m] & mask); - } - - mask<<=1; - day++; - i++; - } - -/* draw `current' month */ - - day = 1; /* start at the beginning of the current month */ - - infoPtr->firstDayplace = i; - SetTextColor(hdc, infoPtr->txt); - m++; - mask = 1; - - /* draw the first week of the current month */ - while(i<7) { - MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, 0); - if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay)) - { - - MONTHCAL_DrawDay(infoPtr, hdc, day, infoPtr->currentMonth, i, 0, - infoPtr->monthdayState[m] & mask); - - if((infoPtr->currentMonth==infoPtr->todaysDate.wMonth) && - (day==infoPtr->todaysDate.wDay) && - (infoPtr->currentYear == infoPtr->todaysDate.wYear)) { - if(!(dwStyle & MCS_NOTODAYCIRCLE)) - MONTHCAL_CircleDay(infoPtr, hdc, day, infoPtr->currentMonth); - } - } - - mask<<=1; - day++; - i++; - } - - j = 1; /* move to the 2nd week of the current month */ - i = 0; /* move back to sunday */ - while(day <= MONTHCAL_MonthLength(infoPtr->currentMonth, infoPtr->currentYear)) { - MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, j); - if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay)) - { - MONTHCAL_DrawDay(infoPtr, hdc, day, infoPtr->currentMonth, i, j, - infoPtr->monthdayState[m] & mask); - - if((infoPtr->currentMonth==infoPtr->todaysDate.wMonth) && - (day==infoPtr->todaysDate.wDay) && - (infoPtr->currentYear == infoPtr->todaysDate.wYear)) - if(!(dwStyle & MCS_NOTODAYCIRCLE)) - MONTHCAL_CircleDay(infoPtr, hdc, day, infoPtr->currentMonth); - } - mask<<=1; - day++; - i++; - if(i>6) { /* past saturday, goto the next weeks sunday */ - i = 0; - j++; - } - } - -/* draw `next' month */ - - day = 1; /* start at the first day of the next month */ - m++; - mask = 1; - - SetTextColor(hdc, infoPtr->trailingtxt); - while((i<7) &&(j<6)) { - MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, j); - if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay)) - { - MONTHCAL_DrawDay(infoPtr, hdc, day, infoPtr->currentMonth + 1, i, j, - infoPtr->monthdayState[m] & mask); - } - - mask<<=1; - day++; - i++; - if(i==7) { /* past saturday, go to next week's sunday */ - i = 0; - j++; - } - } - SetTextColor(hdc, infoPtr->txt); - - -/* draw `today' date if style allows it, and draw a circle before today's - * date if necessary */ - - if(!(dwStyle & MCS_NOTODAY)) { - int offset = 0; - if(!(dwStyle & MCS_NOTODAYCIRCLE)) { - /*day is the number of days from nextmonth we put on the calendar */ - MONTHCAL_CircleDay(infoPtr, hdc, - day+MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear), - infoPtr->currentMonth); - offset+=textWidth; - } - if (!LoadStringW(COMCTL32_hModule,IDM_TODAY,buf1,countof(buf1))) - { - WARN("Can't load resource\n"); - strcpyW(buf1, todayW); - } - MONTHCAL_CalcDayRect(infoPtr, &rtoday, 1, 6); - MONTHCAL_CopyTime(&infoPtr->todaysDate,&localtime); - GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&localtime,NULL,buf2,countof(buf2)); - wsprintfW(buf, fmt2W, buf1, buf2); - SelectObject(hdc, infoPtr->hBoldFont); - - DrawTextW(hdc, buf, -1, &rtoday, DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_SINGLELINE); - if(IntersectRect(&rcTemp, &(ps->rcPaint), &rtoday)) - { - DrawTextW(hdc, buf, -1, &rtoday, DT_LEFT | DT_VCENTER | DT_SINGLELINE); - } - SelectObject(hdc, infoPtr->hFont); - } - -/*eventually draw week numbers*/ - if(dwStyle & MCS_WEEKNUMBERS) { - /* display weeknumbers*/ - int mindays; - - /* Rules what week to call the first week of a new year: - LOCALE_IFIRSTWEEKOFYEAR == 0 (e.g US?): - The week containing Jan 1 is the first week of year - LOCALE_IFIRSTWEEKOFYEAR == 2 (e.g. Germany): - First week of year must contain 4 days of the new year - LOCALE_IFIRSTWEEKOFYEAR == 1 (what contries?) - The first week of the year must contain only days of the new year - */ - GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IFIRSTWEEKOFYEAR, buf, countof(buf)); - weeknum = atoiW(buf); - switch (weeknum) - { - case 1: mindays = 6; - break; - case 2: mindays = 3; - break; - case 0: - default: - mindays = 0; - } - if (infoPtr->currentMonth < 2) - { - /* calculate all those exceptions for january */ - weeknum1=MONTHCAL_CalculateDayOfWeek(1,1,infoPtr->currentYear); - if ((infoPtr->firstDay +7 - weeknum1)%7 > mindays) - weeknum =1; - else - { - weeknum = 0; - for(i=0; i<11; i++) - weeknum+=MONTHCAL_MonthLength(i+1, infoPtr->currentYear-1); - weeknum +=startofprescal+ 7; - weeknum /=7; - weeknum1=MONTHCAL_CalculateDayOfWeek(1,1,infoPtr->currentYear-1); - if ((infoPtr->firstDay + 7 - weeknum1)%7 > mindays) - weeknum++; - } - } - else - { - weeknum = 0; - for(i=0; icurrentYear); - weeknum +=startofprescal+ 7; - weeknum /=7; - weeknum1=MONTHCAL_CalculateDayOfWeek(1,1,infoPtr->currentYear); - if ((infoPtr->firstDay + 7 - weeknum1)%7 > mindays) - weeknum++; - } - days->left = infoPtr->weeknums.left; - days->right = infoPtr->weeknums.right; - days->top = infoPtr->weeknums.top; - days->bottom = days->top +infoPtr->height_increment; - for(i=0; i<6; i++) { - if((i==0)&&(weeknum>50)) - { - wsprintfW(buf, fmt3W, weeknum); - weeknum=0; - } - else if((i==5)&&(weeknum>47)) - { - wsprintfW(buf, fmt3W, 1); - } - else - wsprintfW(buf, fmt3W, weeknum + i); - DrawTextW(hdc, buf, -1, days, DT_CENTER | DT_VCENTER | DT_SINGLELINE ); - days->top+=infoPtr->height_increment; - days->bottom+=infoPtr->height_increment; - } - - MoveToEx(hdc, infoPtr->weeknums.right, infoPtr->weeknums.top + 3 , NULL); - LineTo(hdc, infoPtr->weeknums.right, infoPtr->weeknums.bottom ); - - } - /* currentFont was font at entering Refresh */ - - SetBkColor(hdc, oldBkColor); - SelectObject(hdc, currentFont); - SetTextColor(hdc, oldTextColor); -} - - -static LRESULT -MONTHCAL_GetMinReqRect(MONTHCAL_INFO *infoPtr, LPARAM lParam) -{ - LPRECT lpRect = (LPRECT) lParam; - - TRACE("rect %p\n", lpRect); - - /* validate parameters */ - - if((infoPtr==NULL) ||(lpRect == NULL) ) return FALSE; - - lpRect->left = infoPtr->title.left; - lpRect->top = infoPtr->title.top; - lpRect->right = infoPtr->title.right; - lpRect->bottom = infoPtr->todayrect.bottom; - AdjustWindowRect(lpRect, GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE), FALSE); - - TRACE("%s\n", wine_dbgstr_rect(lpRect)); - - return TRUE; -} - - -static LRESULT -MONTHCAL_GetColor(MONTHCAL_INFO *infoPtr, WPARAM wParam) -{ - TRACE("\n"); - - switch((int)wParam) { - case MCSC_BACKGROUND: - return infoPtr->bk; - case MCSC_TEXT: - return infoPtr->txt; - case MCSC_TITLEBK: - return infoPtr->titlebk; - case MCSC_TITLETEXT: - return infoPtr->titletxt; - case MCSC_MONTHBK: - return infoPtr->monthbk; - case MCSC_TRAILINGTEXT: - return infoPtr->trailingtxt; - } - - return -1; -} - - -static LRESULT -MONTHCAL_SetColor(MONTHCAL_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - int prev = -1; - - TRACE("%d: color %08lx\n", wParam, lParam); - - switch((int)wParam) { - case MCSC_BACKGROUND: - prev = infoPtr->bk; - infoPtr->bk = (COLORREF)lParam; - break; - case MCSC_TEXT: - prev = infoPtr->txt; - infoPtr->txt = (COLORREF)lParam; - break; - case MCSC_TITLEBK: - prev = infoPtr->titlebk; - infoPtr->titlebk = (COLORREF)lParam; - break; - case MCSC_TITLETEXT: - prev=infoPtr->titletxt; - infoPtr->titletxt = (COLORREF)lParam; - break; - case MCSC_MONTHBK: - prev = infoPtr->monthbk; - infoPtr->monthbk = (COLORREF)lParam; - break; - case MCSC_TRAILINGTEXT: - prev = infoPtr->trailingtxt; - infoPtr->trailingtxt = (COLORREF)lParam; - break; - } - - InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); - return prev; -} - - -static LRESULT -MONTHCAL_GetMonthDelta(MONTHCAL_INFO *infoPtr) -{ - TRACE("\n"); - - if(infoPtr->delta) - return infoPtr->delta; - else - return infoPtr->visible; -} - - -static LRESULT -MONTHCAL_SetMonthDelta(MONTHCAL_INFO *infoPtr, WPARAM wParam) -{ - int prev = infoPtr->delta; - - TRACE("delta %d\n", wParam); - - infoPtr->delta = (int)wParam; - return prev; -} - - -static LRESULT -MONTHCAL_GetFirstDayOfWeek(MONTHCAL_INFO *infoPtr) -{ - return infoPtr->firstDay; -} - - -/* sets the first day of the week that will appear in the control */ -/* 0 == Sunday, 6 == Saturday */ -/* FIXME: this needs to be implemented properly in MONTHCAL_Refresh() */ -/* FIXME: we need more error checking here */ -static LRESULT -MONTHCAL_SetFirstDayOfWeek(MONTHCAL_INFO *infoPtr, LPARAM lParam) -{ - int prev = infoPtr->firstDay; - WCHAR buf[40]; - - TRACE("day %ld\n", lParam); - - if((lParam >= 0) && (lParam < 7)) { - infoPtr->firstDay = (int)lParam; - } - else - { - GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK, buf, countof(buf)); - TRACE("%s %d\n", debugstr_w(buf), strlenW(buf)); - infoPtr->firstDay = (atoiW(buf)+1)%7; - } - return prev; -} - - -static LRESULT -MONTHCAL_GetMonthRange(MONTHCAL_INFO *infoPtr) -{ - TRACE("\n"); - - return infoPtr->monthRange; -} - - -static LRESULT -MONTHCAL_GetMaxTodayWidth(MONTHCAL_INFO *infoPtr) -{ - return(infoPtr->todayrect.right - infoPtr->todayrect.left); -} - - -/* FIXME: are validated times taken from current date/time or simply - * copied? - * FIXME: check whether MCM_GETMONTHRANGE shows correct result after - * adjusting range with MCM_SETRANGE - */ - -static LRESULT -MONTHCAL_SetRange(MONTHCAL_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - SYSTEMTIME *lprgSysTimeArray=(SYSTEMTIME *)lParam; - int prev; - - TRACE("%x %lx\n", wParam, lParam); - - if(wParam & GDTR_MAX) { - if(MONTHCAL_ValidateTime(lprgSysTimeArray[1])){ - MONTHCAL_CopyTime(&lprgSysTimeArray[1], &infoPtr->maxDate); - infoPtr->rangeValid|=GDTR_MAX; - } else { - GetSystemTime(&infoPtr->todaysDate); - MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->maxDate); - } - } - if(wParam & GDTR_MIN) { - if(MONTHCAL_ValidateTime(lprgSysTimeArray[0])) { - MONTHCAL_CopyTime(&lprgSysTimeArray[0], &infoPtr->minDate); - infoPtr->rangeValid|=GDTR_MIN; - } else { - GetSystemTime(&infoPtr->todaysDate); - MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->minDate); - } - } - - prev = infoPtr->monthRange; - infoPtr->monthRange = infoPtr->maxDate.wMonth - infoPtr->minDate.wMonth; - - if(infoPtr->monthRange!=prev) { - infoPtr->monthdayState = ReAlloc(infoPtr->monthdayState, - infoPtr->monthRange * sizeof(MONTHDAYSTATE)); - } - - return 1; -} - - -static LRESULT -MONTHCAL_GetRange(HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd); - SYSTEMTIME *lprgSysTimeArray = (SYSTEMTIME *)lParam; - - /* validate parameters */ - - if((infoPtr==NULL) || (lprgSysTimeArray==NULL)) return FALSE; - - MONTHCAL_CopyTime(&infoPtr->maxDate, &lprgSysTimeArray[1]); - MONTHCAL_CopyTime(&infoPtr->minDate, &lprgSysTimeArray[0]); - - return infoPtr->rangeValid; -} - - -static LRESULT -MONTHCAL_SetDayState(MONTHCAL_INFO *infoPtr, WPARAM wParam, LPARAM lParam) - -{ - int i, iMonths = (int)wParam; - MONTHDAYSTATE *dayStates = (LPMONTHDAYSTATE)lParam; - - TRACE("%x %lx\n", wParam, lParam); - if(iMonths!=infoPtr->monthRange) return 0; - - for(i=0; imonthdayState[i] = dayStates[i]; - return 1; -} - -static LRESULT -MONTHCAL_GetCurSel(MONTHCAL_INFO *infoPtr, LPARAM lParam) -{ - SYSTEMTIME *lpSel = (SYSTEMTIME *) lParam; - - TRACE("%lx\n", lParam); - if((infoPtr==NULL) ||(lpSel==NULL)) return FALSE; - if(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & MCS_MULTISELECT) return FALSE; - - MONTHCAL_CopyTime(&infoPtr->minSel, lpSel); - TRACE("%d/%d/%d\n", lpSel->wYear, lpSel->wMonth, lpSel->wDay); - return TRUE; -} - -/* FIXME: if the specified date is not visible, make it visible */ -/* FIXME: redraw? */ -static LRESULT -MONTHCAL_SetCurSel(MONTHCAL_INFO *infoPtr, LPARAM lParam) -{ - SYSTEMTIME *lpSel = (SYSTEMTIME *)lParam; - - TRACE("%lx\n", lParam); - if((infoPtr==NULL) ||(lpSel==NULL)) return FALSE; - if(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & MCS_MULTISELECT) return FALSE; - - infoPtr->currentMonth=lpSel->wMonth; - infoPtr->currentYear=lpSel->wYear; - - MONTHCAL_CopyTime(lpSel, &infoPtr->minSel); - MONTHCAL_CopyTime(lpSel, &infoPtr->maxSel); - - InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); - - return TRUE; -} - - -static LRESULT -MONTHCAL_GetMaxSelCount(MONTHCAL_INFO *infoPtr) -{ - return infoPtr->maxSelCount; -} - - -static LRESULT -MONTHCAL_SetMaxSelCount(MONTHCAL_INFO *infoPtr, WPARAM wParam) -{ - TRACE("%x\n", wParam); - - if(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & MCS_MULTISELECT) { - infoPtr->maxSelCount = wParam; - } - - return TRUE; -} - - -static LRESULT -MONTHCAL_GetSelRange(MONTHCAL_INFO *infoPtr, LPARAM lParam) -{ - SYSTEMTIME *lprgSysTimeArray = (SYSTEMTIME *) lParam; - - TRACE("%lx\n", lParam); - - /* validate parameters */ - - if((infoPtr==NULL) ||(lprgSysTimeArray==NULL)) return FALSE; - - if(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & MCS_MULTISELECT) - { - MONTHCAL_CopyTime(&infoPtr->maxSel, &lprgSysTimeArray[1]); - MONTHCAL_CopyTime(&infoPtr->minSel, &lprgSysTimeArray[0]); - TRACE("[min,max]=[%d %d]\n", infoPtr->minSel.wDay, infoPtr->maxSel.wDay); - return TRUE; - } - - return FALSE; -} - - -static LRESULT -MONTHCAL_SetSelRange(MONTHCAL_INFO *infoPtr, LPARAM lParam) -{ - SYSTEMTIME *lprgSysTimeArray = (SYSTEMTIME *) lParam; - - TRACE("%lx\n", lParam); - - /* validate parameters */ - - if((infoPtr==NULL) ||(lprgSysTimeArray==NULL)) return FALSE; - - if(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & MCS_MULTISELECT) - { - MONTHCAL_CopyTime(&lprgSysTimeArray[1], &infoPtr->maxSel); - MONTHCAL_CopyTime(&lprgSysTimeArray[0], &infoPtr->minSel); - TRACE("[min,max]=[%d %d]\n", infoPtr->minSel.wDay, infoPtr->maxSel.wDay); - return TRUE; - } - - return FALSE; -} - - -static LRESULT -MONTHCAL_GetToday(MONTHCAL_INFO *infoPtr, LPARAM lParam) -{ - SYSTEMTIME *lpToday = (SYSTEMTIME *) lParam; - - TRACE("%lx\n", lParam); - - /* validate parameters */ - - if((infoPtr==NULL) || (lpToday==NULL)) return FALSE; - MONTHCAL_CopyTime(&infoPtr->todaysDate, lpToday); - return TRUE; -} - - -static LRESULT -MONTHCAL_SetToday(MONTHCAL_INFO *infoPtr, LPARAM lParam) -{ - SYSTEMTIME *lpToday = (SYSTEMTIME *) lParam; - - TRACE("%lx\n", lParam); - - /* validate parameters */ - - if((infoPtr==NULL) ||(lpToday==NULL)) return FALSE; - MONTHCAL_CopyTime(lpToday, &infoPtr->todaysDate); - InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); - return TRUE; -} - - -static LRESULT -MONTHCAL_HitTest(MONTHCAL_INFO *infoPtr, LPARAM lParam) -{ - PMCHITTESTINFO lpht = (PMCHITTESTINFO)lParam; - UINT x,y; - DWORD retval; - int day,wday,wnum; - - - x = lpht->pt.x; - y = lpht->pt.y; - retval = MCHT_NOWHERE; - - ZeroMemory(&lpht->st, sizeof(lpht->st)); - - /* Comment in for debugging... - TRACE("%d %d wd[%d %d %d %d] d[%d %d %d %d] t[%d %d %d %d] wn[%d %d %d %d]\n", x, y, - infoPtr->wdays.left, infoPtr->wdays.right, - infoPtr->wdays.top, infoPtr->wdays.bottom, - infoPtr->days.left, infoPtr->days.right, - infoPtr->days.top, infoPtr->days.bottom, - infoPtr->todayrect.left, infoPtr->todayrect.right, - infoPtr->todayrect.top, infoPtr->todayrect.bottom, - infoPtr->weeknums.left, infoPtr->weeknums.right, - infoPtr->weeknums.top, infoPtr->weeknums.bottom); - */ - - /* are we in the header? */ - - if(PtInRect(&infoPtr->title, lpht->pt)) { - if(PtInRect(&infoPtr->titlebtnprev, lpht->pt)) { - retval = MCHT_TITLEBTNPREV; - goto done; - } - if(PtInRect(&infoPtr->titlebtnnext, lpht->pt)) { - retval = MCHT_TITLEBTNNEXT; - goto done; - } - if(PtInRect(&infoPtr->titlemonth, lpht->pt)) { - retval = MCHT_TITLEMONTH; - goto done; - } - if(PtInRect(&infoPtr->titleyear, lpht->pt)) { - retval = MCHT_TITLEYEAR; - goto done; - } - - retval = MCHT_TITLE; - goto done; - } - - day = MONTHCAL_CalcDayFromPos(infoPtr,x,y,&wday,&wnum); - if(PtInRect(&infoPtr->wdays, lpht->pt)) { - retval = MCHT_CALENDARDAY; - lpht->st.wYear = infoPtr->currentYear; - lpht->st.wMonth = (day < 1)? infoPtr->currentMonth -1 : infoPtr->currentMonth; - lpht->st.wDay = (day < 1)? - MONTHCAL_MonthLength(infoPtr->currentMonth-1,infoPtr->currentYear) -day : day; - goto done; - } - if(PtInRect(&infoPtr->weeknums, lpht->pt)) { - retval = MCHT_CALENDARWEEKNUM; - lpht->st.wYear = infoPtr->currentYear; - lpht->st.wMonth = (day < 1) ? infoPtr->currentMonth -1 : - (day > MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear)) ? - infoPtr->currentMonth +1 :infoPtr->currentMonth; - lpht->st.wDay = (day < 1 ) ? - MONTHCAL_MonthLength(infoPtr->currentMonth-1,infoPtr->currentYear) -day : - (day > MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear)) ? - day - MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear) : day; - goto done; - } - if(PtInRect(&infoPtr->days, lpht->pt)) - { - lpht->st.wYear = infoPtr->currentYear; - if ( day < 1) - { - retval = MCHT_CALENDARDATEPREV; - lpht->st.wMonth = infoPtr->currentMonth - 1; - if (lpht->st.wMonth <1) - { - lpht->st.wMonth = 12; - lpht->st.wYear--; - } - lpht->st.wDay = MONTHCAL_MonthLength(lpht->st.wMonth,lpht->st.wYear) -day; - } - else if (day > MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear)) - { - retval = MCHT_CALENDARDATENEXT; - lpht->st.wMonth = infoPtr->currentMonth + 1; - if (lpht->st.wMonth <12) - { - lpht->st.wMonth = 1; - lpht->st.wYear++; - } - lpht->st.wDay = day - MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear) ; - } - else { - retval = MCHT_CALENDARDATE; - lpht->st.wMonth = infoPtr->currentMonth; - lpht->st.wDay = day; - lpht->st.wDayOfWeek = MONTHCAL_CalculateDayOfWeek(day,lpht->st.wMonth,lpht->st.wYear); - } - goto done; - } - if(PtInRect(&infoPtr->todayrect, lpht->pt)) { - retval = MCHT_TODAYLINK; - goto done; - } - - - /* Hit nothing special? What's left must be background :-) */ - - retval = MCHT_CALENDARBK; - done: - lpht->uHit = retval; - return retval; -} - - -static void MONTHCAL_GoToNextMonth(MONTHCAL_INFO *infoPtr) -{ - DWORD dwStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE); - - TRACE("MONTHCAL_GoToNextMonth\n"); - - infoPtr->currentMonth++; - if(infoPtr->currentMonth > 12) { - infoPtr->currentYear++; - infoPtr->currentMonth = 1; - } - - if(dwStyle & MCS_DAYSTATE) { - NMDAYSTATE nmds; - int i; - - nmds.nmhdr.hwndFrom = infoPtr->hwndSelf; - nmds.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); - nmds.nmhdr.code = MCN_GETDAYSTATE; - nmds.cDayState = infoPtr->monthRange; - nmds.prgDayState = Alloc(infoPtr->monthRange * sizeof(MONTHDAYSTATE)); - - SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, - (WPARAM)nmds.nmhdr.idFrom, (LPARAM)&nmds); - for(i=0; imonthRange; i++) - infoPtr->monthdayState[i] = nmds.prgDayState[i]; - } -} - - -static void MONTHCAL_GoToPrevMonth(MONTHCAL_INFO *infoPtr) -{ - DWORD dwStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE); - - TRACE("\n"); - - infoPtr->currentMonth--; - if(infoPtr->currentMonth < 1) { - infoPtr->currentYear--; - infoPtr->currentMonth = 12; - } - - if(dwStyle & MCS_DAYSTATE) { - NMDAYSTATE nmds; - int i; - - nmds.nmhdr.hwndFrom = infoPtr->hwndSelf; - nmds.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); - nmds.nmhdr.code = MCN_GETDAYSTATE; - nmds.cDayState = infoPtr->monthRange; - nmds.prgDayState = Alloc - (infoPtr->monthRange * sizeof(MONTHDAYSTATE)); - - SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, - (WPARAM)nmds.nmhdr.idFrom, (LPARAM)&nmds); - for(i=0; imonthRange; i++) - infoPtr->monthdayState[i] = nmds.prgDayState[i]; - } -} - -static LRESULT -MONTHCAL_RButtonDown(MONTHCAL_INFO *infoPtr, LPARAM lParam) -{ - static const WCHAR todayW[] = { 'G','o',' ','t','o',' ','T','o','d','a','y',':',0 }; - HMENU hMenu; - POINT menupoint; - WCHAR buf[32]; - - hMenu = CreatePopupMenu(); - if (!LoadStringW(COMCTL32_hModule,IDM_GOTODAY,buf,countof(buf))) - { - WARN("Can't load resource\n"); - strcpyW(buf, todayW); - } - AppendMenuW(hMenu, MF_STRING|MF_ENABLED,1, buf); - menupoint.x=(INT)LOWORD(lParam); - menupoint.y=(INT)HIWORD(lParam); - ClientToScreen(infoPtr->hwndSelf, &menupoint); - if( TrackPopupMenu(hMenu,TPM_RIGHTBUTTON| TPM_NONOTIFY|TPM_RETURNCMD, - menupoint.x, menupoint.y, 0, infoPtr->hwndSelf, NULL)) - { - infoPtr->currentMonth=infoPtr->todaysDate.wMonth; - infoPtr->currentYear=infoPtr->todaysDate.wYear; - InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); - } - return 0; -} - -static LRESULT -MONTHCAL_LButtonDown(MONTHCAL_INFO *infoPtr, LPARAM lParam) -{ - static const WCHAR EditW[] = { 'E','D','I','T',0 }; - MCHITTESTINFO ht; - DWORD hit; - HMENU hMenu; - RECT rcDay; /* used in determining area to invalidate */ - WCHAR buf[32]; - int i; - POINT menupoint; - - TRACE("%lx\n", lParam); - - if (infoPtr->hWndYearUpDown) - { - infoPtr->currentYear=SendMessageW( infoPtr->hWndYearUpDown, UDM_SETPOS, (WPARAM) 0,(LPARAM)0); - if(!DestroyWindow(infoPtr->hWndYearUpDown)) - { - FIXME("Can't destroy Updown Control\n"); - } - else - infoPtr->hWndYearUpDown=0; - if(!DestroyWindow(infoPtr->hWndYearEdit)) - { - FIXME("Can't destroy Updown Control\n"); - } - else - infoPtr->hWndYearEdit=0; - InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); - } - - ht.pt.x = (INT)LOWORD(lParam); - ht.pt.y = (INT)HIWORD(lParam); - hit = MONTHCAL_HitTest(infoPtr, (LPARAM)&ht); - - /* FIXME: these flags should be checked by */ - /*((hit & MCHT_XXX) == MCHT_XXX) b/c some of the flags are */ - /* multi-bit */ - if(hit ==MCHT_TITLEBTNNEXT) { - MONTHCAL_GoToNextMonth(infoPtr); - infoPtr->status = MC_NEXTPRESSED; - SetTimer(infoPtr->hwndSelf, MC_NEXTMONTHTIMER, MC_NEXTMONTHDELAY, 0); - InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); - return TRUE; - } - if(hit == MCHT_TITLEBTNPREV){ - MONTHCAL_GoToPrevMonth(infoPtr); - infoPtr->status = MC_PREVPRESSED; - SetTimer(infoPtr->hwndSelf, MC_PREVMONTHTIMER, MC_NEXTMONTHDELAY, 0); - InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); - return TRUE; - } - - if(hit == MCHT_TITLEMONTH) { - hMenu = CreatePopupMenu(); - - for (i=0; i<12;i++) - { - GetLocaleInfoW(LOCALE_USER_DEFAULT,LOCALE_SMONTHNAME1+i, buf,countof(buf)); - AppendMenuW(hMenu, MF_STRING|MF_ENABLED,i+1, buf); - } - menupoint.x=infoPtr->titlemonth.right; - menupoint.y=infoPtr->titlemonth.bottom; - ClientToScreen(infoPtr->hwndSelf, &menupoint); - i= TrackPopupMenu(hMenu,TPM_LEFTALIGN | TPM_NONOTIFY | TPM_RIGHTBUTTON | TPM_RETURNCMD, - menupoint.x, menupoint.y, 0, infoPtr->hwndSelf, NULL); - if ((i>0) && (i<13)) - { - infoPtr->currentMonth=i; - InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); - } - } - if(hit == MCHT_TITLEYEAR) { - infoPtr->hWndYearEdit=CreateWindowExW(0, - EditW, - 0, - WS_VISIBLE | WS_CHILD |UDS_SETBUDDYINT, - infoPtr->titleyear.left+3,infoPtr->titlebtnnext.top, - infoPtr->titleyear.right-infoPtr->titleyear.left+4, - infoPtr->textHeight, - infoPtr->hwndSelf, - NULL, - NULL, - NULL); - SendMessageW( infoPtr->hWndYearEdit, WM_SETFONT, (WPARAM) infoPtr->hBoldFont, (LPARAM)TRUE); - infoPtr->hWndYearUpDown=CreateWindowExW(0, - UPDOWN_CLASSW, - 0, - WS_VISIBLE | WS_CHILD |UDS_SETBUDDYINT|UDS_NOTHOUSANDS|UDS_ARROWKEYS, - infoPtr->titleyear.right+7,infoPtr->titlebtnnext.top, - 18, - infoPtr->textHeight, - infoPtr->hwndSelf, - NULL, - NULL, - NULL); - SendMessageW( infoPtr->hWndYearUpDown, UDM_SETRANGE, (WPARAM) 0, MAKELONG (9999, 1753)); - SendMessageW( infoPtr->hWndYearUpDown, UDM_SETBUDDY, (WPARAM) infoPtr->hWndYearEdit, (LPARAM)0 ); - SendMessageW( infoPtr->hWndYearUpDown, UDM_SETPOS, (WPARAM) 0,(LPARAM)infoPtr->currentYear ); - return TRUE; - - } - if(hit == MCHT_TODAYLINK) { - infoPtr->currentMonth=infoPtr->todaysDate.wMonth; - infoPtr->currentYear=infoPtr->todaysDate.wYear; - InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); - return TRUE; - } - if(hit == MCHT_CALENDARDATE) { - SYSTEMTIME selArray[2]; - NMSELCHANGE nmsc; - - MONTHCAL_CopyTime(&ht.st, &selArray[0]); - MONTHCAL_CopyTime(&ht.st, &selArray[1]); - MONTHCAL_SetSelRange(infoPtr, (LPARAM)&selArray); - MONTHCAL_SetCurSel(infoPtr, (LPARAM)&selArray); - TRACE("MCHT_CALENDARDATE\n"); - nmsc.nmhdr.hwndFrom = infoPtr->hwndSelf; - nmsc.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); - nmsc.nmhdr.code = MCN_SELCHANGE; - MONTHCAL_CopyTime(&infoPtr->minSel,&nmsc.stSelStart); - MONTHCAL_CopyTime(&infoPtr->maxSel,&nmsc.stSelEnd); - - SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, - (WPARAM)nmsc.nmhdr.idFrom,(LPARAM)&nmsc); - - - /* redraw both old and new days if the selected day changed */ - if(infoPtr->curSelDay != ht.st.wDay) { - MONTHCAL_CalcPosFromDay(infoPtr, ht.st.wDay, ht.st.wMonth, &rcDay); - InvalidateRect(infoPtr->hwndSelf, &rcDay, TRUE); - - MONTHCAL_CalcPosFromDay(infoPtr, infoPtr->curSelDay, infoPtr->currentMonth, &rcDay); - InvalidateRect(infoPtr->hwndSelf, &rcDay, TRUE); - } - - infoPtr->firstSelDay = ht.st.wDay; - infoPtr->curSelDay = ht.st.wDay; - infoPtr->status = MC_SEL_LBUTDOWN; - return TRUE; - } - - return 0; -} - - -static LRESULT -MONTHCAL_LButtonUp(MONTHCAL_INFO *infoPtr, LPARAM lParam) -{ - NMSELCHANGE nmsc; - NMHDR nmhdr; - BOOL redraw = FALSE; - MCHITTESTINFO ht; - DWORD hit; - - TRACE("\n"); - - if(infoPtr->status & MC_NEXTPRESSED) { - KillTimer(infoPtr->hwndSelf, MC_NEXTMONTHTIMER); - infoPtr->status &= ~MC_NEXTPRESSED; - redraw = TRUE; - } - if(infoPtr->status & MC_PREVPRESSED) { - KillTimer(infoPtr->hwndSelf, MC_PREVMONTHTIMER); - infoPtr->status &= ~MC_PREVPRESSED; - redraw = TRUE; - } - - ht.pt.x = (INT)LOWORD(lParam); - ht.pt.y = (INT)HIWORD(lParam); - hit = MONTHCAL_HitTest(infoPtr, (LPARAM)&ht); - - infoPtr->status = MC_SEL_LBUTUP; - - if(hit ==MCHT_CALENDARDATENEXT) { - MONTHCAL_GoToNextMonth(infoPtr); - InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); - return TRUE; - } - if(hit == MCHT_CALENDARDATEPREV){ - MONTHCAL_GoToPrevMonth(infoPtr); - InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); - return TRUE; - } - nmhdr.hwndFrom = infoPtr->hwndSelf; - nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); - nmhdr.code = NM_RELEASEDCAPTURE; - TRACE("Sent notification from %p to %p\n", infoPtr->hwndSelf, infoPtr->hwndNotify); - - SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr); - /* redraw if necessary */ - if(redraw) - InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); - /* only send MCN_SELECT if currently displayed month's day was selected */ - if(hit == MCHT_CALENDARDATE) { - nmsc.nmhdr.hwndFrom = infoPtr->hwndSelf; - nmsc.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); - nmsc.nmhdr.code = MCN_SELECT; - MONTHCAL_CopyTime(&infoPtr->minSel, &nmsc.stSelStart); - MONTHCAL_CopyTime(&infoPtr->maxSel, &nmsc.stSelEnd); - - SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, (WPARAM)nmsc.nmhdr.idFrom, (LPARAM)&nmsc); - - } - return 0; -} - - -static LRESULT -MONTHCAL_Timer(MONTHCAL_INFO *infoPtr, WPARAM wParam) -{ - BOOL redraw = FALSE; - - TRACE("%d\n", wParam); - - switch(wParam) { - case MC_NEXTMONTHTIMER: - redraw = TRUE; - MONTHCAL_GoToNextMonth(infoPtr); - break; - case MC_PREVMONTHTIMER: - redraw = TRUE; - MONTHCAL_GoToPrevMonth(infoPtr); - break; - default: - ERR("got unknown timer\n"); - break; - } - - /* redraw only if necessary */ - if(redraw) - InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); - - return 0; -} - - -static LRESULT -MONTHCAL_MouseMove(MONTHCAL_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - MCHITTESTINFO ht; - int oldselday, selday, hit; - RECT r; - - if(!(infoPtr->status & MC_SEL_LBUTDOWN)) return 0; - - ht.pt.x = LOWORD(lParam); - ht.pt.y = HIWORD(lParam); - - hit = MONTHCAL_HitTest(infoPtr, (LPARAM)&ht); - - /* not on the calendar date numbers? bail out */ - TRACE("hit:%x\n",hit); - if((hit & MCHT_CALENDARDATE) != MCHT_CALENDARDATE) return 0; - - selday = ht.st.wDay; - oldselday = infoPtr->curSelDay; - infoPtr->curSelDay = selday; - MONTHCAL_CalcPosFromDay(infoPtr, selday, ht.st. wMonth, &r); - - if(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & MCS_MULTISELECT) { - SYSTEMTIME selArray[2]; - int i; - - MONTHCAL_GetSelRange(infoPtr, (LPARAM)&selArray); - i = 0; - if(infoPtr->firstSelDay==selArray[0].wDay) i=1; - TRACE("oldRange:%d %d %d %d\n", infoPtr->firstSelDay, selArray[0].wDay, selArray[1].wDay, i); - if(infoPtr->firstSelDay==selArray[1].wDay) { - /* 1st time we get here: selArray[0]=selArray[1]) */ - /* if we're still at the first selected date, return */ - if(infoPtr->firstSelDay==selday) goto done; - if(seldayfirstSelDay) i = 0; - } - - if(abs(infoPtr->firstSelDay - selday) >= infoPtr->maxSelCount) { - if(selday>infoPtr->firstSelDay) - selday = infoPtr->firstSelDay + infoPtr->maxSelCount; - else - selday = infoPtr->firstSelDay - infoPtr->maxSelCount; - } - - if(selArray[i].wDay!=selday) { - TRACE("newRange:%d %d %d %d\n", infoPtr->firstSelDay, selArray[0].wDay, selArray[1].wDay, i); - - selArray[i].wDay = selday; - - if(selArray[0].wDay>selArray[1].wDay) { - DWORD tempday; - tempday = selArray[1].wDay; - selArray[1].wDay = selArray[0].wDay; - selArray[0].wDay = tempday; - } - - MONTHCAL_SetSelRange(infoPtr, (LPARAM)&selArray); - } - } - -done: - - /* only redraw if the currently selected day changed */ - /* FIXME: this should specify a rectangle containing only the days that changed */ - /* using InvalidateRect */ - if(oldselday != infoPtr->curSelDay) - InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); - - return 0; -} - - -static LRESULT -MONTHCAL_Paint(MONTHCAL_INFO *infoPtr, WPARAM wParam) -{ - HDC hdc; - PAINTSTRUCT ps; - - if (wParam) - { - GetClientRect(infoPtr->hwndSelf, &ps.rcPaint); - hdc = (HDC)wParam; - } - else - hdc = BeginPaint(infoPtr->hwndSelf, &ps); - - MONTHCAL_Refresh(infoPtr, hdc, &ps); - if (!wParam) EndPaint(infoPtr->hwndSelf, &ps); - return 0; -} - - -static LRESULT -MONTHCAL_KillFocus(MONTHCAL_INFO *infoPtr) -{ - TRACE("\n"); - - InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); - - return 0; -} - - -static LRESULT -MONTHCAL_SetFocus(MONTHCAL_INFO *infoPtr) -{ - TRACE("\n"); - - InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); - - return 0; -} - -/* sets the size information */ -static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr) -{ - static const WCHAR SunW[] = { 'S','u','n',0 }; - static const WCHAR O0W[] = { '0','0',0 }; - HDC hdc = GetDC(infoPtr->hwndSelf); - RECT *title=&infoPtr->title; - RECT *prev=&infoPtr->titlebtnprev; - RECT *next=&infoPtr->titlebtnnext; - RECT *titlemonth=&infoPtr->titlemonth; - RECT *titleyear=&infoPtr->titleyear; - RECT *wdays=&infoPtr->wdays; - RECT *weeknumrect=&infoPtr->weeknums; - RECT *days=&infoPtr->days; - RECT *todayrect=&infoPtr->todayrect; - SIZE size; - TEXTMETRICW tm; - DWORD dwStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE); - HFONT currentFont; - int xdiv, left_offset; - RECT rcClient; - - GetClientRect(infoPtr->hwndSelf, &rcClient); - - currentFont = SelectObject(hdc, infoPtr->hFont); - - /* get the height and width of each day's text */ - GetTextMetricsW(hdc, &tm); - infoPtr->textHeight = tm.tmHeight + tm.tmExternalLeading + tm.tmInternalLeading; - GetTextExtentPoint32W(hdc, SunW, 3, &size); - infoPtr->textWidth = size.cx + 2; - - /* recalculate the height and width increments and offsets */ - GetTextExtentPoint32W(hdc, O0W, 2, &size); - - xdiv = (dwStyle & MCS_WEEKNUMBERS) ? 8 : 7; - - infoPtr->width_increment = size.cx * 2 + 4; - infoPtr->height_increment = infoPtr->textHeight; - left_offset = (rcClient.right - rcClient.left) - (infoPtr->width_increment * xdiv); - - /* calculate title area */ - title->top = rcClient.top; - title->bottom = title->top + 3 * infoPtr->height_increment / 2; - title->left = left_offset; - title->right = rcClient.right; - - /* set the dimensions of the next and previous buttons and center */ - /* the month text vertically */ - prev->top = next->top = title->top + 4; - prev->bottom = next->bottom = title->bottom - 4; - prev->left = title->left + 4; - prev->right = prev->left + (title->bottom - title->top) ; - next->right = title->right - 4; - next->left = next->right - (title->bottom - title->top); - - /* titlemonth->left and right change based upon the current month */ - /* and are recalculated in refresh as the current month may change */ - /* without the control being resized */ - titlemonth->top = titleyear->top = title->top + (infoPtr->height_increment)/2; - titlemonth->bottom = titleyear->bottom = title->bottom - (infoPtr->height_increment)/2; - - /* setup the dimensions of the rectangle we draw the names of the */ - /* days of the week in */ - weeknumrect->left = left_offset; - if(dwStyle & MCS_WEEKNUMBERS) - weeknumrect->right=prev->right; - else - weeknumrect->right=weeknumrect->left; - wdays->left = days->left = weeknumrect->right; - wdays->right = days->right = wdays->left + 7 * infoPtr->width_increment; - wdays->top = title->bottom ; - wdays->bottom = wdays->top + infoPtr->height_increment; - - days->top = weeknumrect->top = wdays->bottom ; - days->bottom = weeknumrect->bottom = days->top + 6 * infoPtr->height_increment; - - todayrect->left = rcClient.left; - todayrect->right = rcClient.right; - todayrect->top = days->bottom; - todayrect->bottom = days->bottom + infoPtr->height_increment; - - TRACE("dx=%d dy=%d client[%s] title[%s] wdays[%s] days[%s] today[%s]\n", - infoPtr->width_increment,infoPtr->height_increment, - wine_dbgstr_rect(&rcClient), - wine_dbgstr_rect(title), - wine_dbgstr_rect(wdays), - wine_dbgstr_rect(days), - wine_dbgstr_rect(todayrect)); - - /* restore the originally selected font */ - SelectObject(hdc, currentFont); - - ReleaseDC(infoPtr->hwndSelf, hdc); -} - -static LRESULT MONTHCAL_Size(MONTHCAL_INFO *infoPtr, int Width, int Height) -{ - TRACE("(width=%d, height=%d)\n", Width, Height); - - MONTHCAL_UpdateSize(infoPtr); - - /* invalidate client area and erase background */ - InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); - - return 0; -} - -static LRESULT MONTHCAL_GetFont(MONTHCAL_INFO *infoPtr) -{ - return (LRESULT)infoPtr->hFont; -} - -static LRESULT MONTHCAL_SetFont(MONTHCAL_INFO *infoPtr, HFONT hFont, BOOL redraw) -{ - HFONT hOldFont; - LOGFONTW lf; - - if (!hFont) return 0; - - hOldFont = infoPtr->hFont; - infoPtr->hFont = hFont; - - GetObjectW(infoPtr->hFont, sizeof(lf), &lf); - lf.lfWeight = FW_BOLD; - infoPtr->hBoldFont = CreateFontIndirectW(&lf); - - if (redraw) - InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); - - return (LRESULT)hOldFont; -} - -/* FIXME: check whether dateMin/dateMax need to be adjusted. */ -static LRESULT -MONTHCAL_Create(HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - MONTHCAL_INFO *infoPtr; - - /* allocate memory for info structure */ - infoPtr =(MONTHCAL_INFO*)Alloc(sizeof(MONTHCAL_INFO)); - SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)infoPtr); - - if(infoPtr == NULL) { - ERR( "could not allocate info memory!\n"); - return 0; - } - - infoPtr->hwndSelf = hwnd; - infoPtr->hwndNotify = ((LPCREATESTRUCTW)lParam)->hwndParent; - - MONTHCAL_SetFont(infoPtr, GetStockObject(DEFAULT_GUI_FONT), FALSE); - - /* initialize info structure */ - /* FIXME: calculate systemtime ->> localtime(substract timezoneinfo) */ - - GetLocalTime(&infoPtr->todaysDate); - MONTHCAL_SetFirstDayOfWeek(infoPtr, (LPARAM)-1); - infoPtr->currentMonth = infoPtr->todaysDate.wMonth; - infoPtr->currentYear = infoPtr->todaysDate.wYear; - MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->minDate); - MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->maxDate); - infoPtr->maxDate.wYear=2050; - infoPtr->minDate.wYear=1950; - infoPtr->maxSelCount = 7; - infoPtr->monthRange = 3; - infoPtr->monthdayState = Alloc - (infoPtr->monthRange * sizeof(MONTHDAYSTATE)); - infoPtr->titlebk = GetSysColor(COLOR_ACTIVECAPTION); - infoPtr->titletxt = GetSysColor(COLOR_WINDOW); - infoPtr->monthbk = GetSysColor(COLOR_WINDOW); - infoPtr->trailingtxt = GetSysColor(COLOR_GRAYTEXT); - infoPtr->bk = GetSysColor(COLOR_WINDOW); - infoPtr->txt = GetSysColor(COLOR_WINDOWTEXT); - - /* call MONTHCAL_UpdateSize to set all of the dimensions */ - /* of the control */ - MONTHCAL_UpdateSize(infoPtr); - - return 0; -} - - -static LRESULT -MONTHCAL_Destroy(MONTHCAL_INFO *infoPtr) -{ - /* free month calendar info data */ - if(infoPtr->monthdayState) - Free(infoPtr->monthdayState); - SetWindowLongPtrW(infoPtr->hwndSelf, 0, 0); - Free(infoPtr); - return 0; -} - - -static LRESULT WINAPI -MONTHCAL_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - MONTHCAL_INFO *infoPtr; - - TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hwnd, uMsg, wParam, lParam); - - infoPtr = MONTHCAL_GetInfoPtr(hwnd); - if (!infoPtr && (uMsg != WM_CREATE)) - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - switch(uMsg) - { - case MCM_GETCURSEL: - return MONTHCAL_GetCurSel(infoPtr, lParam); - - case MCM_SETCURSEL: - return MONTHCAL_SetCurSel(infoPtr, lParam); - - case MCM_GETMAXSELCOUNT: - return MONTHCAL_GetMaxSelCount(infoPtr); - - case MCM_SETMAXSELCOUNT: - return MONTHCAL_SetMaxSelCount(infoPtr, wParam); - - case MCM_GETSELRANGE: - return MONTHCAL_GetSelRange(infoPtr, lParam); - - case MCM_SETSELRANGE: - return MONTHCAL_SetSelRange(infoPtr, lParam); - - case MCM_GETMONTHRANGE: - return MONTHCAL_GetMonthRange(infoPtr); - - case MCM_SETDAYSTATE: - return MONTHCAL_SetDayState(infoPtr, wParam, lParam); - - case MCM_GETMINREQRECT: - return MONTHCAL_GetMinReqRect(infoPtr, lParam); - - case MCM_GETCOLOR: - return MONTHCAL_GetColor(infoPtr, wParam); - - case MCM_SETCOLOR: - return MONTHCAL_SetColor(infoPtr, wParam, lParam); - - case MCM_GETTODAY: - return MONTHCAL_GetToday(infoPtr, lParam); - - case MCM_SETTODAY: - return MONTHCAL_SetToday(infoPtr, lParam); - - case MCM_HITTEST: - return MONTHCAL_HitTest(infoPtr, lParam); - - case MCM_GETFIRSTDAYOFWEEK: - return MONTHCAL_GetFirstDayOfWeek(infoPtr); - - case MCM_SETFIRSTDAYOFWEEK: - return MONTHCAL_SetFirstDayOfWeek(infoPtr, lParam); - - case MCM_GETRANGE: - return MONTHCAL_GetRange(hwnd, wParam, lParam); - - case MCM_SETRANGE: - return MONTHCAL_SetRange(infoPtr, wParam, lParam); - - case MCM_GETMONTHDELTA: - return MONTHCAL_GetMonthDelta(infoPtr); - - case MCM_SETMONTHDELTA: - return MONTHCAL_SetMonthDelta(infoPtr, wParam); - - case MCM_GETMAXTODAYWIDTH: - return MONTHCAL_GetMaxTodayWidth(infoPtr); - - case WM_GETDLGCODE: - return DLGC_WANTARROWS | DLGC_WANTCHARS; - - case WM_KILLFOCUS: - return MONTHCAL_KillFocus(infoPtr); - - case WM_RBUTTONDOWN: - return MONTHCAL_RButtonDown(infoPtr, lParam); - - case WM_LBUTTONDOWN: - return MONTHCAL_LButtonDown(infoPtr, lParam); - - case WM_MOUSEMOVE: - return MONTHCAL_MouseMove(infoPtr, wParam, lParam); - - case WM_LBUTTONUP: - return MONTHCAL_LButtonUp(infoPtr, lParam); - - case WM_PAINT: - return MONTHCAL_Paint(infoPtr, wParam); - - case WM_SETFOCUS: - return MONTHCAL_SetFocus(infoPtr); - - case WM_SIZE: - return MONTHCAL_Size(infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); - - case WM_CREATE: - return MONTHCAL_Create(hwnd, wParam, lParam); - - case WM_SETFONT: - return MONTHCAL_SetFont(infoPtr, (HFONT)wParam, (BOOL)lParam); - - case WM_GETFONT: - return MONTHCAL_GetFont(infoPtr); - - case WM_TIMER: - return MONTHCAL_Timer(infoPtr, wParam); - - case WM_DESTROY: - return MONTHCAL_Destroy(infoPtr); - - default: - if ((uMsg >= WM_USER) && (uMsg < WM_APP)) - ERR( "unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam); - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - } -} - - -void -MONTHCAL_Register(void) -{ - WNDCLASSW wndClass; - - ZeroMemory(&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS; - wndClass.lpfnWndProc = MONTHCAL_WindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(MONTHCAL_INFO *); - wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW); - wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wndClass.lpszClassName = MONTHCAL_CLASSW; - - RegisterClassW(&wndClass); -} - - -void -MONTHCAL_Unregister(void) -{ - UnregisterClassW(MONTHCAL_CLASSW, NULL); -} +/* Month calendar control + + * + * Copyright 1998, 1999 Eric Kohl (ekohl@abo.rhein-zeitung.de) + * Copyright 1999 Alex Priem (alexp@sci.kun.nl) + * Copyright 1999 Chris Morgan and + * James Abbatiello + * Copyright 2000 Uwe Bonnes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTE + * + * This code was audited for completeness against the documented features + * of Comctl32.dll version 6.0 on Oct. 20, 2004, by Dimitrie O. Paun. + * + * Unless otherwise noted, we believe this code to be complete, as per + * the specification mentioned above. + * If you discover missing features, or bugs, please note them below. + * + * TODO: + * -- MCM_[GS]ETUNICODEFORMAT + * -- MONTHCAL_GetMonthRange + * -- handle resources better (doesn't work now); + * -- take care of internationalization. + * -- keyboard handling. + * -- GetRange: At the moment, we copy ranges anyway, regardless of + * infoPtr->rangeValid; an invalid range is simply filled + * with zeros in SetRange. Is this the right behavior? + * -- search for FIXME + */ + +#include +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "comctl32.h" +#include "wine/unicode.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(monthcal); + +#define MC_SEL_LBUTUP 1 /* Left button released */ +#define MC_SEL_LBUTDOWN 2 /* Left button pressed in calendar */ +#define MC_PREVPRESSED 4 /* Prev month button pressed */ +#define MC_NEXTPRESSED 8 /* Next month button pressed */ +#define MC_NEXTMONTHDELAY 350 /* when continuously pressing `next */ + /* month', wait 500 ms before going */ + /* to the next month */ +#define MC_NEXTMONTHTIMER 1 /* Timer ID's */ +#define MC_PREVMONTHTIMER 2 + +#define countof(arr) (sizeof(arr)/sizeof(arr[0])) + +typedef struct +{ + HWND hwndSelf; + COLORREF bk; + COLORREF txt; + COLORREF titlebk; + COLORREF titletxt; + COLORREF monthbk; + COLORREF trailingtxt; + HFONT hFont; + HFONT hBoldFont; + int textHeight; + int textWidth; + int height_increment; + int width_increment; + int firstDayplace; /* place of the first day of the current month */ + int delta; /* scroll rate; # of months that the */ + /* control moves when user clicks a scroll button */ + int visible; /* # of months visible */ + int firstDay; /* Start month calendar with firstDay's day */ + int monthRange; + MONTHDAYSTATE *monthdayState; + SYSTEMTIME todaysDate; + DWORD currentMonth; + DWORD currentYear; + int status; /* See MC_SEL flags */ + int curSelDay; /* current selected day */ + int firstSelDay; /* first selected day */ + int maxSelCount; + SYSTEMTIME minSel; + SYSTEMTIME maxSel; + DWORD rangeValid; + SYSTEMTIME minDate; + SYSTEMTIME maxDate; + + RECT title; /* rect for the header above the calendar */ + RECT titlebtnnext; /* the `next month' button in the header */ + RECT titlebtnprev; /* the `prev month' button in the header */ + RECT titlemonth; /* the `month name' txt in the header */ + RECT titleyear; /* the `year number' txt in the header */ + RECT wdays; /* week days at top */ + RECT days; /* calendar area */ + RECT weeknums; /* week numbers at left side */ + RECT todayrect; /* `today: xx/xx/xx' text rect */ + HWND hwndNotify; /* Window to receive the notifications */ + HWND hWndYearEdit; /* Window Handle of edit box to handle years */ + HWND hWndYearUpDown;/* Window Handle of updown box to handle years */ +} MONTHCAL_INFO, *LPMONTHCAL_INFO; + + +/* Offsets of days in the week to the weekday of january 1 in a leap year */ +static const int DayOfWeekTable[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; + + +#define MONTHCAL_GetInfoPtr(hwnd) ((MONTHCAL_INFO *)GetWindowLongPtrW(hwnd, 0)) + +/* helper functions */ + +/* returns the number of days in any given month, checking for leap days */ +/* january is 1, december is 12 */ +int MONTHCAL_MonthLength(int month, int year) +{ + const int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}; + /*Wrap around, this eases handling*/ + if(month == 0) + month = 12; + if(month == 13) + month = 1; + + /* if we have a leap year add 1 day to February */ + /* a leap year is a year either divisible by 400 */ + /* or divisible by 4 and not by 100 */ + if(month == 2) { /* February */ + return mdays[month - 1] + ((year%400 == 0) ? 1 : ((year%100 != 0) && + (year%4 == 0)) ? 1 : 0); + } + else { + return mdays[month - 1]; + } +} + + +/* make sure that time is valid */ +static int MONTHCAL_ValidateTime(SYSTEMTIME time) +{ + if(time.wMonth > 12) return FALSE; + if(time.wDayOfWeek > 6) return FALSE; + if(time.wDay > MONTHCAL_MonthLength(time.wMonth, time.wYear)) + return FALSE; + if(time.wHour > 23) return FALSE; + if(time.wMinute > 59) return FALSE; + if(time.wSecond > 59) return FALSE; + if(time.wMilliseconds > 999) return FALSE; + + return TRUE; +} + + +/* Note:Depending on DST, this may be offset by a day. + Need to find out if we're on a DST place & adjust the clock accordingly. + Above function assumes we have a valid data. + Valid for year>1752; 1 <= d <= 31, 1 <= m <= 12. + 0 = Sunday. +*/ + +/* returns the day in the week(0 == sunday, 6 == saturday) */ +/* day(1 == 1st, 2 == 2nd... etc), year is the year value */ +static int MONTHCAL_CalculateDayOfWeek(DWORD day, DWORD month, DWORD year) +{ + year-=(month < 3); + + return((year + year/4 - year/100 + year/400 + + DayOfWeekTable[month-1] + day ) % 7); +} + +/* From a given point, calculate the row (weekpos), column(daypos) + and day in the calendar. day== 0 mean the last day of tha last month +*/ +static int MONTHCAL_CalcDayFromPos(MONTHCAL_INFO *infoPtr, int x, int y, + int *daypos,int *weekpos) +{ + int retval, firstDay; + RECT rcClient; + + GetClientRect(infoPtr->hwndSelf, &rcClient); + + /* if the point is outside the x bounds of the window put + it at the boundary */ + if (x > rcClient.right) + x = rcClient.right; + + + *daypos = (x - infoPtr->days.left ) / infoPtr->width_increment; + *weekpos = (y - infoPtr->days.top ) / infoPtr->height_increment; + + firstDay = (MONTHCAL_CalculateDayOfWeek(1, infoPtr->currentMonth, infoPtr->currentYear)+6 - infoPtr->firstDay)%7; + retval = *daypos + (7 * *weekpos) - firstDay; + return retval; +} + +/* day is the day of the month, 1 == 1st day of the month */ +/* sets x and y to be the position of the day */ +/* x == day, y == week where(0,0) == firstDay, 1st week */ +static void MONTHCAL_CalcDayXY(MONTHCAL_INFO *infoPtr, int day, int month, + int *x, int *y) +{ + int firstDay, prevMonth; + + firstDay = (MONTHCAL_CalculateDayOfWeek(1, infoPtr->currentMonth, infoPtr->currentYear) +6 - infoPtr->firstDay)%7; + + if(month==infoPtr->currentMonth) { + *x = (day + firstDay) % 7; + *y = (day + firstDay - *x) / 7; + return; + } + if(month < infoPtr->currentMonth) { + prevMonth = month - 1; + if(prevMonth==0) + prevMonth = 12; + + *x = (MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear) - firstDay) % 7; + *y = 0; + return; + } + + *y = MONTHCAL_MonthLength(month, infoPtr->currentYear - 1) / 7; + *x = (day + firstDay + MONTHCAL_MonthLength(month, + infoPtr->currentYear)) % 7; +} + + +/* x: column(day), y: row(week) */ +static void MONTHCAL_CalcDayRect(MONTHCAL_INFO *infoPtr, RECT *r, int x, int y) +{ + r->left = infoPtr->days.left + x * infoPtr->width_increment; + r->right = r->left + infoPtr->width_increment; + r->top = infoPtr->days.top + y * infoPtr->height_increment; + r->bottom = r->top + infoPtr->textHeight; +} + + +/* sets the RECT struct r to the rectangle around the day and month */ +/* day is the day value of the month(1 == 1st), month is the month */ +/* value(january == 1, december == 12) */ +static inline void MONTHCAL_CalcPosFromDay(MONTHCAL_INFO *infoPtr, + int day, int month, RECT *r) +{ + int x, y; + + MONTHCAL_CalcDayXY(infoPtr, day, month, &x, &y); + MONTHCAL_CalcDayRect(infoPtr, r, x, y); +} + + +/* day is the day in the month(1 == 1st of the month) */ +/* month is the month value(1 == january, 12 == december) */ +static void MONTHCAL_CircleDay(MONTHCAL_INFO *infoPtr, HDC hdc, int day, int month) +{ + HPEN hRedPen = CreatePen(PS_SOLID, 2, RGB(255, 0, 0)); + HPEN hOldPen2 = SelectObject(hdc, hRedPen); + POINT points[13]; + int x, y; + RECT day_rect; + + + MONTHCAL_CalcPosFromDay(infoPtr, day, month, &day_rect); + + x = day_rect.left; + y = day_rect.top; + + points[0].x = x; + points[0].y = y - 1; + points[1].x = x + 0.8 * infoPtr->width_increment; + points[1].y = y - 1; + points[2].x = x + 0.9 * infoPtr->width_increment; + points[2].y = y; + points[3].x = x + infoPtr->width_increment; + points[3].y = y + 0.5 * infoPtr->height_increment; + + points[4].x = x + infoPtr->width_increment; + points[4].y = y + 0.9 * infoPtr->height_increment; + points[5].x = x + 0.6 * infoPtr->width_increment; + points[5].y = y + 0.9 * infoPtr->height_increment; + points[6].x = x + 0.5 * infoPtr->width_increment; + points[6].y = y + 0.9 * infoPtr->height_increment; /* bring the bottom up just + a hair to fit inside the day rectangle */ + + points[7].x = x + 0.2 * infoPtr->width_increment; + points[7].y = y + 0.8 * infoPtr->height_increment; + points[8].x = x + 0.1 * infoPtr->width_increment; + points[8].y = y + 0.8 * infoPtr->height_increment; + points[9].x = x; + points[9].y = y + 0.5 * infoPtr->height_increment; + + points[10].x = x + 0.1 * infoPtr->width_increment; + points[10].y = y + 0.2 * infoPtr->height_increment; + points[11].x = x + 0.2 * infoPtr->width_increment; + points[11].y = y + 0.3 * infoPtr->height_increment; + points[12].x = x + 0.4 * infoPtr->width_increment; + points[12].y = y + 0.2 * infoPtr->height_increment; + + PolyBezier(hdc, points, 13); + DeleteObject(hRedPen); + SelectObject(hdc, hOldPen2); +} + + +static void MONTHCAL_DrawDay(MONTHCAL_INFO *infoPtr, HDC hdc, int day, int month, + int x, int y, int bold) +{ + static const WCHAR fmtW[] = { '%','d',0 }; + WCHAR buf[10]; + RECT r; + static int haveBoldFont, haveSelectedDay = FALSE; + HBRUSH hbr; + COLORREF oldCol = 0; + COLORREF oldBk = 0; + + wsprintfW(buf, fmtW, day); + +/* No need to check styles: when selection is not valid, it is set to zero. + * 1=infoPtr->minSel.wDay) && (day<=infoPtr->maxSel.wDay) + && (month==infoPtr->currentMonth)) { + HRGN hrgn; + RECT r2; + + TRACE("%d %d %d\n",day, infoPtr->minSel.wDay, infoPtr->maxSel.wDay); + TRACE("%ld %ld %ld %ld\n", r.left, r.top, r.right, r.bottom); + oldCol = SetTextColor(hdc, infoPtr->monthbk); + oldBk = SetBkColor(hdc, infoPtr->trailingtxt); + hbr = GetSysColorBrush(COLOR_GRAYTEXT); + hrgn = CreateEllipticRgn(r.left, r.top, r.right, r.bottom); + FillRgn(hdc, hrgn, hbr); + + /* FIXME: this may need to be changed now b/c of the other + drawing changes 11/3/99 CMM */ + r2.left = r.left - 0.25 * infoPtr->textWidth; + r2.top = r.top; + r2.right = r.left + 0.5 * infoPtr->textWidth; + r2.bottom = r.bottom; + if(haveSelectedDay) FillRect(hdc, &r2, hbr); + haveSelectedDay = TRUE; + } else { + haveSelectedDay = FALSE; + } + + /* need to add some code for multiple selections */ + + if((bold) &&(!haveBoldFont)) { + SelectObject(hdc, infoPtr->hBoldFont); + haveBoldFont = TRUE; + } + if((!bold) &&(haveBoldFont)) { + SelectObject(hdc, infoPtr->hFont); + haveBoldFont = FALSE; + } + + if(haveSelectedDay) { + SetTextColor(hdc, oldCol); + SetBkColor(hdc, oldBk); + } + + SetBkMode(hdc,TRANSPARENT); + DrawTextW(hdc, buf, -1, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE ); + + /* draw a rectangle around the currently selected days text */ + if((day==infoPtr->curSelDay) && (month==infoPtr->currentMonth)) + DrawFocusRect(hdc, &r); +} + + +static void MONTHCAL_Refresh(MONTHCAL_INFO *infoPtr, HDC hdc, PAINTSTRUCT* ps) +{ + static const WCHAR todayW[] = { 'T','o','d','a','y',':',0 }; + static const WCHAR fmt1W[] = { '%','s',' ','%','l','d',0 }; + static const WCHAR fmt2W[] = { '%','s',' ','%','s',0 }; + static const WCHAR fmt3W[] = { '%','d',0 }; + RECT *title=&infoPtr->title; + RECT *prev=&infoPtr->titlebtnprev; + RECT *next=&infoPtr->titlebtnnext; + RECT *titlemonth=&infoPtr->titlemonth; + RECT *titleyear=&infoPtr->titleyear; + RECT dayrect; + RECT *days=&dayrect; + RECT rtoday; + int i, j, m, mask, day, firstDay, weeknum, weeknum1,prevMonth; + int textHeight = infoPtr->textHeight, textWidth = infoPtr->textWidth; + SIZE size; + HBRUSH hbr; + HFONT currentFont; + WCHAR buf[20]; + WCHAR buf1[20]; + WCHAR buf2[32]; + COLORREF oldTextColor, oldBkColor; + DWORD dwStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE); + RECT rcTemp; + RECT rcDay; /* used in MONTHCAL_CalcDayRect() */ + SYSTEMTIME localtime; + int startofprescal; + + oldTextColor = SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); + + /* fill background */ + hbr = CreateSolidBrush (infoPtr->bk); + FillRect(hdc, &ps->rcPaint, hbr); + DeleteObject(hbr); + + /* draw header */ + if(IntersectRect(&rcTemp, &(ps->rcPaint), title)) + { + hbr = CreateSolidBrush(infoPtr->titlebk); + FillRect(hdc, title, hbr); + DeleteObject(hbr); + } + + /* if the previous button is pressed draw it depressed */ + if(IntersectRect(&rcTemp, &(ps->rcPaint), prev)) + { + if((infoPtr->status & MC_PREVPRESSED)) + DrawFrameControl(hdc, prev, DFC_SCROLL, + DFCS_SCROLLLEFT | DFCS_PUSHED | + (dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0)); + else /* if the previous button is pressed draw it depressed */ + DrawFrameControl(hdc, prev, DFC_SCROLL, + DFCS_SCROLLLEFT |(dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0)); + } + + /* if next button is depressed draw it depressed */ + if(IntersectRect(&rcTemp, &(ps->rcPaint), next)) + { + if((infoPtr->status & MC_NEXTPRESSED)) + DrawFrameControl(hdc, next, DFC_SCROLL, + DFCS_SCROLLRIGHT | DFCS_PUSHED | + (dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0)); + else /* if the next button is pressed draw it depressed */ + DrawFrameControl(hdc, next, DFC_SCROLL, + DFCS_SCROLLRIGHT |(dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0)); + } + + oldBkColor = SetBkColor(hdc, infoPtr->titlebk); + SetTextColor(hdc, infoPtr->titletxt); + currentFont = SelectObject(hdc, infoPtr->hBoldFont); + + GetLocaleInfoW( LOCALE_USER_DEFAULT,LOCALE_SMONTHNAME1+infoPtr->currentMonth -1, + buf1,countof(buf1)); + wsprintfW(buf, fmt1W, buf1, infoPtr->currentYear); + + if(IntersectRect(&rcTemp, &(ps->rcPaint), title)) + { + DrawTextW(hdc, buf, strlenW(buf), title, + DT_CENTER | DT_VCENTER | DT_SINGLELINE); + } + +/* titlemonth left/right contained rect for whole titletxt('June 1999') + * MCM_HitTestInfo wants month & year rects, so prepare these now. + *(no, we can't draw them separately; the whole text is centered) + */ + GetTextExtentPoint32W(hdc, buf, strlenW(buf), &size); + titlemonth->left = title->right / 2 + title->left / 2 - size.cx / 2; + titleyear->right = title->right / 2 + title->left / 2 + size.cx / 2; + GetTextExtentPoint32W(hdc, buf1, strlenW(buf1), &size); + titlemonth->right = titlemonth->left + size.cx; + titleyear->left = titlemonth->right; + + /* draw month area */ + rcTemp.top=infoPtr->wdays.top; + rcTemp.left=infoPtr->wdays.left; + rcTemp.bottom=infoPtr->todayrect.bottom; + rcTemp.right =infoPtr->todayrect.right; + if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcTemp)) + { + hbr = CreateSolidBrush(infoPtr->monthbk); + FillRect(hdc, &rcTemp, hbr); + DeleteObject(hbr); + } + +/* draw line under day abbreviatons */ + + MoveToEx(hdc, infoPtr->days.left + 3, title->bottom + textHeight + 1, NULL); + LineTo(hdc, infoPtr->days.right - 3, title->bottom + textHeight + 1); + + prevMonth = infoPtr->currentMonth - 1; + if(prevMonth == 0) /* if currentMonth is january(1) prevMonth is */ + prevMonth = 12; /* december(12) of the previous year */ + + infoPtr->wdays.left = infoPtr->days.left = infoPtr->weeknums.right; +/* draw day abbreviations */ + + SelectObject(hdc, infoPtr->hFont); + SetBkColor(hdc, infoPtr->monthbk); + SetTextColor(hdc, infoPtr->trailingtxt); + + /* copy this rect so we can change the values without changing */ + /* the original version */ + days->left = infoPtr->wdays.left; + days->right = days->left + infoPtr->width_increment; + days->top = infoPtr->wdays.top; + days->bottom = infoPtr->wdays.bottom; + + i = infoPtr->firstDay; + + for(j=0; j<7; j++) { + GetLocaleInfoW( LOCALE_USER_DEFAULT,LOCALE_SABBREVDAYNAME1 + (i+j+6)%7, buf, countof(buf)); + DrawTextW(hdc, buf, strlenW(buf), days, DT_CENTER | DT_VCENTER | DT_SINGLELINE ); + days->left+=infoPtr->width_increment; + days->right+=infoPtr->width_increment; + } + +/* draw day numbers; first, the previous month */ + + firstDay = MONTHCAL_CalculateDayOfWeek(1, infoPtr->currentMonth, infoPtr->currentYear); + + day = MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear) + + (infoPtr->firstDay + 7 - firstDay)%7 + 1; + if (day > MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear)) + day -=7; + startofprescal = day; + mask = 1<<(day-1); + + i = 0; + m = 0; + while(day <= MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear)) { + MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, 0); + if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay)) + { + MONTHCAL_DrawDay(infoPtr, hdc, day, prevMonth, i, 0, + infoPtr->monthdayState[m] & mask); + } + + mask<<=1; + day++; + i++; + } + +/* draw `current' month */ + + day = 1; /* start at the beginning of the current month */ + + infoPtr->firstDayplace = i; + SetTextColor(hdc, infoPtr->txt); + m++; + mask = 1; + + /* draw the first week of the current month */ + while(i<7) { + MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, 0); + if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay)) + { + + MONTHCAL_DrawDay(infoPtr, hdc, day, infoPtr->currentMonth, i, 0, + infoPtr->monthdayState[m] & mask); + + if((infoPtr->currentMonth==infoPtr->todaysDate.wMonth) && + (day==infoPtr->todaysDate.wDay) && + (infoPtr->currentYear == infoPtr->todaysDate.wYear)) { + if(!(dwStyle & MCS_NOTODAYCIRCLE)) + MONTHCAL_CircleDay(infoPtr, hdc, day, infoPtr->currentMonth); + } + } + + mask<<=1; + day++; + i++; + } + + j = 1; /* move to the 2nd week of the current month */ + i = 0; /* move back to sunday */ + while(day <= MONTHCAL_MonthLength(infoPtr->currentMonth, infoPtr->currentYear)) { + MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, j); + if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay)) + { + MONTHCAL_DrawDay(infoPtr, hdc, day, infoPtr->currentMonth, i, j, + infoPtr->monthdayState[m] & mask); + + if((infoPtr->currentMonth==infoPtr->todaysDate.wMonth) && + (day==infoPtr->todaysDate.wDay) && + (infoPtr->currentYear == infoPtr->todaysDate.wYear)) + if(!(dwStyle & MCS_NOTODAYCIRCLE)) + MONTHCAL_CircleDay(infoPtr, hdc, day, infoPtr->currentMonth); + } + mask<<=1; + day++; + i++; + if(i>6) { /* past saturday, goto the next weeks sunday */ + i = 0; + j++; + } + } + +/* draw `next' month */ + + day = 1; /* start at the first day of the next month */ + m++; + mask = 1; + + SetTextColor(hdc, infoPtr->trailingtxt); + while((i<7) &&(j<6)) { + MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, j); + if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay)) + { + MONTHCAL_DrawDay(infoPtr, hdc, day, infoPtr->currentMonth + 1, i, j, + infoPtr->monthdayState[m] & mask); + } + + mask<<=1; + day++; + i++; + if(i==7) { /* past saturday, go to next week's sunday */ + i = 0; + j++; + } + } + SetTextColor(hdc, infoPtr->txt); + + +/* draw `today' date if style allows it, and draw a circle before today's + * date if necessary */ + + if(!(dwStyle & MCS_NOTODAY)) { + int offset = 0; + if(!(dwStyle & MCS_NOTODAYCIRCLE)) { + /*day is the number of days from nextmonth we put on the calendar */ + MONTHCAL_CircleDay(infoPtr, hdc, + day+MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear), + infoPtr->currentMonth); + offset+=textWidth; + } + if (!LoadStringW(COMCTL32_hModule,IDM_TODAY,buf1,countof(buf1))) + { + WARN("Can't load resource\n"); + strcpyW(buf1, todayW); + } + MONTHCAL_CalcDayRect(infoPtr, &rtoday, 1, 6); + MONTHCAL_CopyTime(&infoPtr->todaysDate,&localtime); + GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&localtime,NULL,buf2,countof(buf2)); + wsprintfW(buf, fmt2W, buf1, buf2); + SelectObject(hdc, infoPtr->hBoldFont); + + DrawTextW(hdc, buf, -1, &rtoday, DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_SINGLELINE); + if(IntersectRect(&rcTemp, &(ps->rcPaint), &rtoday)) + { + DrawTextW(hdc, buf, -1, &rtoday, DT_LEFT | DT_VCENTER | DT_SINGLELINE); + } + SelectObject(hdc, infoPtr->hFont); + } + +/*eventually draw week numbers*/ + if(dwStyle & MCS_WEEKNUMBERS) { + /* display weeknumbers*/ + int mindays; + + /* Rules what week to call the first week of a new year: + LOCALE_IFIRSTWEEKOFYEAR == 0 (e.g US?): + The week containing Jan 1 is the first week of year + LOCALE_IFIRSTWEEKOFYEAR == 2 (e.g. Germany): + First week of year must contain 4 days of the new year + LOCALE_IFIRSTWEEKOFYEAR == 1 (what contries?) + The first week of the year must contain only days of the new year + */ + GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IFIRSTWEEKOFYEAR, buf, countof(buf)); + weeknum = atoiW(buf); + switch (weeknum) + { + case 1: mindays = 6; + break; + case 2: mindays = 3; + break; + case 0: + default: + mindays = 0; + } + if (infoPtr->currentMonth < 2) + { + /* calculate all those exceptions for january */ + weeknum1=MONTHCAL_CalculateDayOfWeek(1,1,infoPtr->currentYear); + if ((infoPtr->firstDay +7 - weeknum1)%7 > mindays) + weeknum =1; + else + { + weeknum = 0; + for(i=0; i<11; i++) + weeknum+=MONTHCAL_MonthLength(i+1, infoPtr->currentYear-1); + weeknum +=startofprescal+ 7; + weeknum /=7; + weeknum1=MONTHCAL_CalculateDayOfWeek(1,1,infoPtr->currentYear-1); + if ((infoPtr->firstDay + 7 - weeknum1)%7 > mindays) + weeknum++; + } + } + else + { + weeknum = 0; + for(i=0; icurrentYear); + weeknum +=startofprescal+ 7; + weeknum /=7; + weeknum1=MONTHCAL_CalculateDayOfWeek(1,1,infoPtr->currentYear); + if ((infoPtr->firstDay + 7 - weeknum1)%7 > mindays) + weeknum++; + } + days->left = infoPtr->weeknums.left; + days->right = infoPtr->weeknums.right; + days->top = infoPtr->weeknums.top; + days->bottom = days->top +infoPtr->height_increment; + for(i=0; i<6; i++) { + if((i==0)&&(weeknum>50)) + { + wsprintfW(buf, fmt3W, weeknum); + weeknum=0; + } + else if((i==5)&&(weeknum>47)) + { + wsprintfW(buf, fmt3W, 1); + } + else + wsprintfW(buf, fmt3W, weeknum + i); + DrawTextW(hdc, buf, -1, days, DT_CENTER | DT_VCENTER | DT_SINGLELINE ); + days->top+=infoPtr->height_increment; + days->bottom+=infoPtr->height_increment; + } + + MoveToEx(hdc, infoPtr->weeknums.right, infoPtr->weeknums.top + 3 , NULL); + LineTo(hdc, infoPtr->weeknums.right, infoPtr->weeknums.bottom ); + + } + /* currentFont was font at entering Refresh */ + + SetBkColor(hdc, oldBkColor); + SelectObject(hdc, currentFont); + SetTextColor(hdc, oldTextColor); +} + + +static LRESULT +MONTHCAL_GetMinReqRect(MONTHCAL_INFO *infoPtr, LPARAM lParam) +{ + LPRECT lpRect = (LPRECT) lParam; + + TRACE("rect %p\n", lpRect); + + /* validate parameters */ + + if((infoPtr==NULL) ||(lpRect == NULL) ) return FALSE; + + lpRect->left = infoPtr->title.left; + lpRect->top = infoPtr->title.top; + lpRect->right = infoPtr->title.right; + lpRect->bottom = infoPtr->todayrect.bottom; + AdjustWindowRect(lpRect, GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE), FALSE); + + TRACE("%s\n", wine_dbgstr_rect(lpRect)); + + return TRUE; +} + + +static LRESULT +MONTHCAL_GetColor(MONTHCAL_INFO *infoPtr, WPARAM wParam) +{ + TRACE("\n"); + + switch((int)wParam) { + case MCSC_BACKGROUND: + return infoPtr->bk; + case MCSC_TEXT: + return infoPtr->txt; + case MCSC_TITLEBK: + return infoPtr->titlebk; + case MCSC_TITLETEXT: + return infoPtr->titletxt; + case MCSC_MONTHBK: + return infoPtr->monthbk; + case MCSC_TRAILINGTEXT: + return infoPtr->trailingtxt; + } + + return -1; +} + + +static LRESULT +MONTHCAL_SetColor(MONTHCAL_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + int prev = -1; + + TRACE("%d: color %08lx\n", wParam, lParam); + + switch((int)wParam) { + case MCSC_BACKGROUND: + prev = infoPtr->bk; + infoPtr->bk = (COLORREF)lParam; + break; + case MCSC_TEXT: + prev = infoPtr->txt; + infoPtr->txt = (COLORREF)lParam; + break; + case MCSC_TITLEBK: + prev = infoPtr->titlebk; + infoPtr->titlebk = (COLORREF)lParam; + break; + case MCSC_TITLETEXT: + prev=infoPtr->titletxt; + infoPtr->titletxt = (COLORREF)lParam; + break; + case MCSC_MONTHBK: + prev = infoPtr->monthbk; + infoPtr->monthbk = (COLORREF)lParam; + break; + case MCSC_TRAILINGTEXT: + prev = infoPtr->trailingtxt; + infoPtr->trailingtxt = (COLORREF)lParam; + break; + } + + InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); + return prev; +} + + +static LRESULT +MONTHCAL_GetMonthDelta(MONTHCAL_INFO *infoPtr) +{ + TRACE("\n"); + + if(infoPtr->delta) + return infoPtr->delta; + else + return infoPtr->visible; +} + + +static LRESULT +MONTHCAL_SetMonthDelta(MONTHCAL_INFO *infoPtr, WPARAM wParam) +{ + int prev = infoPtr->delta; + + TRACE("delta %d\n", wParam); + + infoPtr->delta = (int)wParam; + return prev; +} + + +static LRESULT +MONTHCAL_GetFirstDayOfWeek(MONTHCAL_INFO *infoPtr) +{ + return infoPtr->firstDay; +} + + +/* sets the first day of the week that will appear in the control */ +/* 0 == Sunday, 6 == Saturday */ +/* FIXME: this needs to be implemented properly in MONTHCAL_Refresh() */ +/* FIXME: we need more error checking here */ +static LRESULT +MONTHCAL_SetFirstDayOfWeek(MONTHCAL_INFO *infoPtr, LPARAM lParam) +{ + int prev = infoPtr->firstDay; + WCHAR buf[40]; + + TRACE("day %ld\n", lParam); + + if((lParam >= 0) && (lParam < 7)) { + infoPtr->firstDay = (int)lParam; + } + else + { + GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK, buf, countof(buf)); + TRACE("%s %d\n", debugstr_w(buf), strlenW(buf)); + infoPtr->firstDay = (atoiW(buf)+1)%7; + } + return prev; +} + + +static LRESULT +MONTHCAL_GetMonthRange(MONTHCAL_INFO *infoPtr) +{ + TRACE("\n"); + + return infoPtr->monthRange; +} + + +static LRESULT +MONTHCAL_GetMaxTodayWidth(MONTHCAL_INFO *infoPtr) +{ + return(infoPtr->todayrect.right - infoPtr->todayrect.left); +} + + +/* FIXME: are validated times taken from current date/time or simply + * copied? + * FIXME: check whether MCM_GETMONTHRANGE shows correct result after + * adjusting range with MCM_SETRANGE + */ + +static LRESULT +MONTHCAL_SetRange(MONTHCAL_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + SYSTEMTIME *lprgSysTimeArray=(SYSTEMTIME *)lParam; + int prev; + + TRACE("%x %lx\n", wParam, lParam); + + if(wParam & GDTR_MAX) { + if(MONTHCAL_ValidateTime(lprgSysTimeArray[1])){ + MONTHCAL_CopyTime(&lprgSysTimeArray[1], &infoPtr->maxDate); + infoPtr->rangeValid|=GDTR_MAX; + } else { + GetSystemTime(&infoPtr->todaysDate); + MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->maxDate); + } + } + if(wParam & GDTR_MIN) { + if(MONTHCAL_ValidateTime(lprgSysTimeArray[0])) { + MONTHCAL_CopyTime(&lprgSysTimeArray[0], &infoPtr->minDate); + infoPtr->rangeValid|=GDTR_MIN; + } else { + GetSystemTime(&infoPtr->todaysDate); + MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->minDate); + } + } + + prev = infoPtr->monthRange; + infoPtr->monthRange = infoPtr->maxDate.wMonth - infoPtr->minDate.wMonth; + + if(infoPtr->monthRange!=prev) { + infoPtr->monthdayState = ReAlloc(infoPtr->monthdayState, + infoPtr->monthRange * sizeof(MONTHDAYSTATE)); + } + + return 1; +} + + +static LRESULT +MONTHCAL_GetRange(HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd); + SYSTEMTIME *lprgSysTimeArray = (SYSTEMTIME *)lParam; + + /* validate parameters */ + + if((infoPtr==NULL) || (lprgSysTimeArray==NULL)) return FALSE; + + MONTHCAL_CopyTime(&infoPtr->maxDate, &lprgSysTimeArray[1]); + MONTHCAL_CopyTime(&infoPtr->minDate, &lprgSysTimeArray[0]); + + return infoPtr->rangeValid; +} + + +static LRESULT +MONTHCAL_SetDayState(MONTHCAL_INFO *infoPtr, WPARAM wParam, LPARAM lParam) + +{ + int i, iMonths = (int)wParam; + MONTHDAYSTATE *dayStates = (LPMONTHDAYSTATE)lParam; + + TRACE("%x %lx\n", wParam, lParam); + if(iMonths!=infoPtr->monthRange) return 0; + + for(i=0; imonthdayState[i] = dayStates[i]; + return 1; +} + +static LRESULT +MONTHCAL_GetCurSel(MONTHCAL_INFO *infoPtr, LPARAM lParam) +{ + SYSTEMTIME *lpSel = (SYSTEMTIME *) lParam; + + TRACE("%lx\n", lParam); + if((infoPtr==NULL) ||(lpSel==NULL)) return FALSE; + if(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & MCS_MULTISELECT) return FALSE; + + MONTHCAL_CopyTime(&infoPtr->minSel, lpSel); + TRACE("%d/%d/%d\n", lpSel->wYear, lpSel->wMonth, lpSel->wDay); + return TRUE; +} + +/* FIXME: if the specified date is not visible, make it visible */ +/* FIXME: redraw? */ +static LRESULT +MONTHCAL_SetCurSel(MONTHCAL_INFO *infoPtr, LPARAM lParam) +{ + SYSTEMTIME *lpSel = (SYSTEMTIME *)lParam; + + TRACE("%lx\n", lParam); + if((infoPtr==NULL) ||(lpSel==NULL)) return FALSE; + if(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & MCS_MULTISELECT) return FALSE; + + infoPtr->currentMonth=lpSel->wMonth; + infoPtr->currentYear=lpSel->wYear; + + MONTHCAL_CopyTime(lpSel, &infoPtr->minSel); + MONTHCAL_CopyTime(lpSel, &infoPtr->maxSel); + + InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); + + return TRUE; +} + + +static LRESULT +MONTHCAL_GetMaxSelCount(MONTHCAL_INFO *infoPtr) +{ + return infoPtr->maxSelCount; +} + + +static LRESULT +MONTHCAL_SetMaxSelCount(MONTHCAL_INFO *infoPtr, WPARAM wParam) +{ + TRACE("%x\n", wParam); + + if(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & MCS_MULTISELECT) { + infoPtr->maxSelCount = wParam; + } + + return TRUE; +} + + +static LRESULT +MONTHCAL_GetSelRange(MONTHCAL_INFO *infoPtr, LPARAM lParam) +{ + SYSTEMTIME *lprgSysTimeArray = (SYSTEMTIME *) lParam; + + TRACE("%lx\n", lParam); + + /* validate parameters */ + + if((infoPtr==NULL) ||(lprgSysTimeArray==NULL)) return FALSE; + + if(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & MCS_MULTISELECT) + { + MONTHCAL_CopyTime(&infoPtr->maxSel, &lprgSysTimeArray[1]); + MONTHCAL_CopyTime(&infoPtr->minSel, &lprgSysTimeArray[0]); + TRACE("[min,max]=[%d %d]\n", infoPtr->minSel.wDay, infoPtr->maxSel.wDay); + return TRUE; + } + + return FALSE; +} + + +static LRESULT +MONTHCAL_SetSelRange(MONTHCAL_INFO *infoPtr, LPARAM lParam) +{ + SYSTEMTIME *lprgSysTimeArray = (SYSTEMTIME *) lParam; + + TRACE("%lx\n", lParam); + + /* validate parameters */ + + if((infoPtr==NULL) ||(lprgSysTimeArray==NULL)) return FALSE; + + if(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & MCS_MULTISELECT) + { + MONTHCAL_CopyTime(&lprgSysTimeArray[1], &infoPtr->maxSel); + MONTHCAL_CopyTime(&lprgSysTimeArray[0], &infoPtr->minSel); + TRACE("[min,max]=[%d %d]\n", infoPtr->minSel.wDay, infoPtr->maxSel.wDay); + return TRUE; + } + + return FALSE; +} + + +static LRESULT +MONTHCAL_GetToday(MONTHCAL_INFO *infoPtr, LPARAM lParam) +{ + SYSTEMTIME *lpToday = (SYSTEMTIME *) lParam; + + TRACE("%lx\n", lParam); + + /* validate parameters */ + + if((infoPtr==NULL) || (lpToday==NULL)) return FALSE; + MONTHCAL_CopyTime(&infoPtr->todaysDate, lpToday); + return TRUE; +} + + +static LRESULT +MONTHCAL_SetToday(MONTHCAL_INFO *infoPtr, LPARAM lParam) +{ + SYSTEMTIME *lpToday = (SYSTEMTIME *) lParam; + + TRACE("%lx\n", lParam); + + /* validate parameters */ + + if((infoPtr==NULL) ||(lpToday==NULL)) return FALSE; + MONTHCAL_CopyTime(lpToday, &infoPtr->todaysDate); + InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); + return TRUE; +} + + +static LRESULT +MONTHCAL_HitTest(MONTHCAL_INFO *infoPtr, LPARAM lParam) +{ + PMCHITTESTINFO lpht = (PMCHITTESTINFO)lParam; + UINT x,y; + DWORD retval; + int day,wday,wnum; + + + x = lpht->pt.x; + y = lpht->pt.y; + retval = MCHT_NOWHERE; + + ZeroMemory(&lpht->st, sizeof(lpht->st)); + + /* Comment in for debugging... + TRACE("%d %d wd[%d %d %d %d] d[%d %d %d %d] t[%d %d %d %d] wn[%d %d %d %d]\n", x, y, + infoPtr->wdays.left, infoPtr->wdays.right, + infoPtr->wdays.top, infoPtr->wdays.bottom, + infoPtr->days.left, infoPtr->days.right, + infoPtr->days.top, infoPtr->days.bottom, + infoPtr->todayrect.left, infoPtr->todayrect.right, + infoPtr->todayrect.top, infoPtr->todayrect.bottom, + infoPtr->weeknums.left, infoPtr->weeknums.right, + infoPtr->weeknums.top, infoPtr->weeknums.bottom); + */ + + /* are we in the header? */ + + if(PtInRect(&infoPtr->title, lpht->pt)) { + if(PtInRect(&infoPtr->titlebtnprev, lpht->pt)) { + retval = MCHT_TITLEBTNPREV; + goto done; + } + if(PtInRect(&infoPtr->titlebtnnext, lpht->pt)) { + retval = MCHT_TITLEBTNNEXT; + goto done; + } + if(PtInRect(&infoPtr->titlemonth, lpht->pt)) { + retval = MCHT_TITLEMONTH; + goto done; + } + if(PtInRect(&infoPtr->titleyear, lpht->pt)) { + retval = MCHT_TITLEYEAR; + goto done; + } + + retval = MCHT_TITLE; + goto done; + } + + day = MONTHCAL_CalcDayFromPos(infoPtr,x,y,&wday,&wnum); + if(PtInRect(&infoPtr->wdays, lpht->pt)) { + retval = MCHT_CALENDARDAY; + lpht->st.wYear = infoPtr->currentYear; + lpht->st.wMonth = (day < 1)? infoPtr->currentMonth -1 : infoPtr->currentMonth; + lpht->st.wDay = (day < 1)? + MONTHCAL_MonthLength(infoPtr->currentMonth-1,infoPtr->currentYear) -day : day; + goto done; + } + if(PtInRect(&infoPtr->weeknums, lpht->pt)) { + retval = MCHT_CALENDARWEEKNUM; + lpht->st.wYear = infoPtr->currentYear; + lpht->st.wMonth = (day < 1) ? infoPtr->currentMonth -1 : + (day > MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear)) ? + infoPtr->currentMonth +1 :infoPtr->currentMonth; + lpht->st.wDay = (day < 1 ) ? + MONTHCAL_MonthLength(infoPtr->currentMonth-1,infoPtr->currentYear) -day : + (day > MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear)) ? + day - MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear) : day; + goto done; + } + if(PtInRect(&infoPtr->days, lpht->pt)) + { + lpht->st.wYear = infoPtr->currentYear; + if ( day < 1) + { + retval = MCHT_CALENDARDATEPREV; + lpht->st.wMonth = infoPtr->currentMonth - 1; + if (lpht->st.wMonth <1) + { + lpht->st.wMonth = 12; + lpht->st.wYear--; + } + lpht->st.wDay = MONTHCAL_MonthLength(lpht->st.wMonth,lpht->st.wYear) -day; + } + else if (day > MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear)) + { + retval = MCHT_CALENDARDATENEXT; + lpht->st.wMonth = infoPtr->currentMonth + 1; + if (lpht->st.wMonth <12) + { + lpht->st.wMonth = 1; + lpht->st.wYear++; + } + lpht->st.wDay = day - MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear) ; + } + else { + retval = MCHT_CALENDARDATE; + lpht->st.wMonth = infoPtr->currentMonth; + lpht->st.wDay = day; + lpht->st.wDayOfWeek = MONTHCAL_CalculateDayOfWeek(day,lpht->st.wMonth,lpht->st.wYear); + } + goto done; + } + if(PtInRect(&infoPtr->todayrect, lpht->pt)) { + retval = MCHT_TODAYLINK; + goto done; + } + + + /* Hit nothing special? What's left must be background :-) */ + + retval = MCHT_CALENDARBK; + done: + lpht->uHit = retval; + return retval; +} + + +static void MONTHCAL_GoToNextMonth(MONTHCAL_INFO *infoPtr) +{ + DWORD dwStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE); + + TRACE("MONTHCAL_GoToNextMonth\n"); + + infoPtr->currentMonth++; + if(infoPtr->currentMonth > 12) { + infoPtr->currentYear++; + infoPtr->currentMonth = 1; + } + + if(dwStyle & MCS_DAYSTATE) { + NMDAYSTATE nmds; + int i; + + nmds.nmhdr.hwndFrom = infoPtr->hwndSelf; + nmds.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); + nmds.nmhdr.code = MCN_GETDAYSTATE; + nmds.cDayState = infoPtr->monthRange; + nmds.prgDayState = Alloc(infoPtr->monthRange * sizeof(MONTHDAYSTATE)); + + SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, + (WPARAM)nmds.nmhdr.idFrom, (LPARAM)&nmds); + for(i=0; imonthRange; i++) + infoPtr->monthdayState[i] = nmds.prgDayState[i]; + } +} + + +static void MONTHCAL_GoToPrevMonth(MONTHCAL_INFO *infoPtr) +{ + DWORD dwStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE); + + TRACE("\n"); + + infoPtr->currentMonth--; + if(infoPtr->currentMonth < 1) { + infoPtr->currentYear--; + infoPtr->currentMonth = 12; + } + + if(dwStyle & MCS_DAYSTATE) { + NMDAYSTATE nmds; + int i; + + nmds.nmhdr.hwndFrom = infoPtr->hwndSelf; + nmds.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); + nmds.nmhdr.code = MCN_GETDAYSTATE; + nmds.cDayState = infoPtr->monthRange; + nmds.prgDayState = Alloc + (infoPtr->monthRange * sizeof(MONTHDAYSTATE)); + + SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, + (WPARAM)nmds.nmhdr.idFrom, (LPARAM)&nmds); + for(i=0; imonthRange; i++) + infoPtr->monthdayState[i] = nmds.prgDayState[i]; + } +} + +static LRESULT +MONTHCAL_RButtonDown(MONTHCAL_INFO *infoPtr, LPARAM lParam) +{ + static const WCHAR todayW[] = { 'G','o',' ','t','o',' ','T','o','d','a','y',':',0 }; + HMENU hMenu; + POINT menupoint; + WCHAR buf[32]; + + hMenu = CreatePopupMenu(); + if (!LoadStringW(COMCTL32_hModule,IDM_GOTODAY,buf,countof(buf))) + { + WARN("Can't load resource\n"); + strcpyW(buf, todayW); + } + AppendMenuW(hMenu, MF_STRING|MF_ENABLED,1, buf); + menupoint.x=(INT)LOWORD(lParam); + menupoint.y=(INT)HIWORD(lParam); + ClientToScreen(infoPtr->hwndSelf, &menupoint); + if( TrackPopupMenu(hMenu,TPM_RIGHTBUTTON| TPM_NONOTIFY|TPM_RETURNCMD, + menupoint.x, menupoint.y, 0, infoPtr->hwndSelf, NULL)) + { + infoPtr->currentMonth=infoPtr->todaysDate.wMonth; + infoPtr->currentYear=infoPtr->todaysDate.wYear; + InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); + } + return 0; +} + +static LRESULT +MONTHCAL_LButtonDown(MONTHCAL_INFO *infoPtr, LPARAM lParam) +{ + static const WCHAR EditW[] = { 'E','D','I','T',0 }; + MCHITTESTINFO ht; + DWORD hit; + HMENU hMenu; + RECT rcDay; /* used in determining area to invalidate */ + WCHAR buf[32]; + int i; + POINT menupoint; + + TRACE("%lx\n", lParam); + + if (infoPtr->hWndYearUpDown) + { + infoPtr->currentYear=SendMessageW( infoPtr->hWndYearUpDown, UDM_SETPOS, (WPARAM) 0,(LPARAM)0); + if(!DestroyWindow(infoPtr->hWndYearUpDown)) + { + FIXME("Can't destroy Updown Control\n"); + } + else + infoPtr->hWndYearUpDown=0; + if(!DestroyWindow(infoPtr->hWndYearEdit)) + { + FIXME("Can't destroy Updown Control\n"); + } + else + infoPtr->hWndYearEdit=0; + InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); + } + + ht.pt.x = (INT)LOWORD(lParam); + ht.pt.y = (INT)HIWORD(lParam); + hit = MONTHCAL_HitTest(infoPtr, (LPARAM)&ht); + + /* FIXME: these flags should be checked by */ + /*((hit & MCHT_XXX) == MCHT_XXX) b/c some of the flags are */ + /* multi-bit */ + if(hit ==MCHT_TITLEBTNNEXT) { + MONTHCAL_GoToNextMonth(infoPtr); + infoPtr->status = MC_NEXTPRESSED; + SetTimer(infoPtr->hwndSelf, MC_NEXTMONTHTIMER, MC_NEXTMONTHDELAY, 0); + InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); + return TRUE; + } + if(hit == MCHT_TITLEBTNPREV){ + MONTHCAL_GoToPrevMonth(infoPtr); + infoPtr->status = MC_PREVPRESSED; + SetTimer(infoPtr->hwndSelf, MC_PREVMONTHTIMER, MC_NEXTMONTHDELAY, 0); + InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); + return TRUE; + } + + if(hit == MCHT_TITLEMONTH) { + hMenu = CreatePopupMenu(); + + for (i=0; i<12;i++) + { + GetLocaleInfoW(LOCALE_USER_DEFAULT,LOCALE_SMONTHNAME1+i, buf,countof(buf)); + AppendMenuW(hMenu, MF_STRING|MF_ENABLED,i+1, buf); + } + menupoint.x=infoPtr->titlemonth.right; + menupoint.y=infoPtr->titlemonth.bottom; + ClientToScreen(infoPtr->hwndSelf, &menupoint); + i= TrackPopupMenu(hMenu,TPM_LEFTALIGN | TPM_NONOTIFY | TPM_RIGHTBUTTON | TPM_RETURNCMD, + menupoint.x, menupoint.y, 0, infoPtr->hwndSelf, NULL); + if ((i>0) && (i<13)) + { + infoPtr->currentMonth=i; + InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); + } + } + if(hit == MCHT_TITLEYEAR) { + infoPtr->hWndYearEdit=CreateWindowExW(0, + EditW, + 0, + WS_VISIBLE | WS_CHILD |UDS_SETBUDDYINT, + infoPtr->titleyear.left+3,infoPtr->titlebtnnext.top, + infoPtr->titleyear.right-infoPtr->titleyear.left+4, + infoPtr->textHeight, + infoPtr->hwndSelf, + NULL, + NULL, + NULL); + SendMessageW( infoPtr->hWndYearEdit, WM_SETFONT, (WPARAM) infoPtr->hBoldFont, (LPARAM)TRUE); + infoPtr->hWndYearUpDown=CreateWindowExW(0, + UPDOWN_CLASSW, + 0, + WS_VISIBLE | WS_CHILD |UDS_SETBUDDYINT|UDS_NOTHOUSANDS|UDS_ARROWKEYS, + infoPtr->titleyear.right+7,infoPtr->titlebtnnext.top, + 18, + infoPtr->textHeight, + infoPtr->hwndSelf, + NULL, + NULL, + NULL); + SendMessageW( infoPtr->hWndYearUpDown, UDM_SETRANGE, (WPARAM) 0, MAKELONG (9999, 1753)); + SendMessageW( infoPtr->hWndYearUpDown, UDM_SETBUDDY, (WPARAM) infoPtr->hWndYearEdit, (LPARAM)0 ); + SendMessageW( infoPtr->hWndYearUpDown, UDM_SETPOS, (WPARAM) 0,(LPARAM)infoPtr->currentYear ); + return TRUE; + + } + if(hit == MCHT_TODAYLINK) { + infoPtr->currentMonth=infoPtr->todaysDate.wMonth; + infoPtr->currentYear=infoPtr->todaysDate.wYear; + InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); + return TRUE; + } + if(hit == MCHT_CALENDARDATE) { + SYSTEMTIME selArray[2]; + NMSELCHANGE nmsc; + + MONTHCAL_CopyTime(&ht.st, &selArray[0]); + MONTHCAL_CopyTime(&ht.st, &selArray[1]); + MONTHCAL_SetSelRange(infoPtr, (LPARAM)&selArray); + MONTHCAL_SetCurSel(infoPtr, (LPARAM)&selArray); + TRACE("MCHT_CALENDARDATE\n"); + nmsc.nmhdr.hwndFrom = infoPtr->hwndSelf; + nmsc.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); + nmsc.nmhdr.code = MCN_SELCHANGE; + MONTHCAL_CopyTime(&infoPtr->minSel,&nmsc.stSelStart); + MONTHCAL_CopyTime(&infoPtr->maxSel,&nmsc.stSelEnd); + + SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, + (WPARAM)nmsc.nmhdr.idFrom,(LPARAM)&nmsc); + + + /* redraw both old and new days if the selected day changed */ + if(infoPtr->curSelDay != ht.st.wDay) { + MONTHCAL_CalcPosFromDay(infoPtr, ht.st.wDay, ht.st.wMonth, &rcDay); + InvalidateRect(infoPtr->hwndSelf, &rcDay, TRUE); + + MONTHCAL_CalcPosFromDay(infoPtr, infoPtr->curSelDay, infoPtr->currentMonth, &rcDay); + InvalidateRect(infoPtr->hwndSelf, &rcDay, TRUE); + } + + infoPtr->firstSelDay = ht.st.wDay; + infoPtr->curSelDay = ht.st.wDay; + infoPtr->status = MC_SEL_LBUTDOWN; + return TRUE; + } + + return 0; +} + + +static LRESULT +MONTHCAL_LButtonUp(MONTHCAL_INFO *infoPtr, LPARAM lParam) +{ + NMSELCHANGE nmsc; + NMHDR nmhdr; + BOOL redraw = FALSE; + MCHITTESTINFO ht; + DWORD hit; + + TRACE("\n"); + + if(infoPtr->status & MC_NEXTPRESSED) { + KillTimer(infoPtr->hwndSelf, MC_NEXTMONTHTIMER); + infoPtr->status &= ~MC_NEXTPRESSED; + redraw = TRUE; + } + if(infoPtr->status & MC_PREVPRESSED) { + KillTimer(infoPtr->hwndSelf, MC_PREVMONTHTIMER); + infoPtr->status &= ~MC_PREVPRESSED; + redraw = TRUE; + } + + ht.pt.x = (INT)LOWORD(lParam); + ht.pt.y = (INT)HIWORD(lParam); + hit = MONTHCAL_HitTest(infoPtr, (LPARAM)&ht); + + infoPtr->status = MC_SEL_LBUTUP; + + if(hit ==MCHT_CALENDARDATENEXT) { + MONTHCAL_GoToNextMonth(infoPtr); + InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); + return TRUE; + } + if(hit == MCHT_CALENDARDATEPREV){ + MONTHCAL_GoToPrevMonth(infoPtr); + InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); + return TRUE; + } + nmhdr.hwndFrom = infoPtr->hwndSelf; + nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); + nmhdr.code = NM_RELEASEDCAPTURE; + TRACE("Sent notification from %p to %p\n", infoPtr->hwndSelf, infoPtr->hwndNotify); + + SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr); + /* redraw if necessary */ + if(redraw) + InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); + /* only send MCN_SELECT if currently displayed month's day was selected */ + if(hit == MCHT_CALENDARDATE) { + nmsc.nmhdr.hwndFrom = infoPtr->hwndSelf; + nmsc.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); + nmsc.nmhdr.code = MCN_SELECT; + MONTHCAL_CopyTime(&infoPtr->minSel, &nmsc.stSelStart); + MONTHCAL_CopyTime(&infoPtr->maxSel, &nmsc.stSelEnd); + + SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, (WPARAM)nmsc.nmhdr.idFrom, (LPARAM)&nmsc); + + } + return 0; +} + + +static LRESULT +MONTHCAL_Timer(MONTHCAL_INFO *infoPtr, WPARAM wParam) +{ + BOOL redraw = FALSE; + + TRACE("%d\n", wParam); + + switch(wParam) { + case MC_NEXTMONTHTIMER: + redraw = TRUE; + MONTHCAL_GoToNextMonth(infoPtr); + break; + case MC_PREVMONTHTIMER: + redraw = TRUE; + MONTHCAL_GoToPrevMonth(infoPtr); + break; + default: + ERR("got unknown timer\n"); + break; + } + + /* redraw only if necessary */ + if(redraw) + InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); + + return 0; +} + + +static LRESULT +MONTHCAL_MouseMove(MONTHCAL_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + MCHITTESTINFO ht; + int oldselday, selday, hit; + RECT r; + + if(!(infoPtr->status & MC_SEL_LBUTDOWN)) return 0; + + ht.pt.x = LOWORD(lParam); + ht.pt.y = HIWORD(lParam); + + hit = MONTHCAL_HitTest(infoPtr, (LPARAM)&ht); + + /* not on the calendar date numbers? bail out */ + TRACE("hit:%x\n",hit); + if((hit & MCHT_CALENDARDATE) != MCHT_CALENDARDATE) return 0; + + selday = ht.st.wDay; + oldselday = infoPtr->curSelDay; + infoPtr->curSelDay = selday; + MONTHCAL_CalcPosFromDay(infoPtr, selday, ht.st. wMonth, &r); + + if(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & MCS_MULTISELECT) { + SYSTEMTIME selArray[2]; + int i; + + MONTHCAL_GetSelRange(infoPtr, (LPARAM)&selArray); + i = 0; + if(infoPtr->firstSelDay==selArray[0].wDay) i=1; + TRACE("oldRange:%d %d %d %d\n", infoPtr->firstSelDay, selArray[0].wDay, selArray[1].wDay, i); + if(infoPtr->firstSelDay==selArray[1].wDay) { + /* 1st time we get here: selArray[0]=selArray[1]) */ + /* if we're still at the first selected date, return */ + if(infoPtr->firstSelDay==selday) goto done; + if(seldayfirstSelDay) i = 0; + } + + if(abs(infoPtr->firstSelDay - selday) >= infoPtr->maxSelCount) { + if(selday>infoPtr->firstSelDay) + selday = infoPtr->firstSelDay + infoPtr->maxSelCount; + else + selday = infoPtr->firstSelDay - infoPtr->maxSelCount; + } + + if(selArray[i].wDay!=selday) { + TRACE("newRange:%d %d %d %d\n", infoPtr->firstSelDay, selArray[0].wDay, selArray[1].wDay, i); + + selArray[i].wDay = selday; + + if(selArray[0].wDay>selArray[1].wDay) { + DWORD tempday; + tempday = selArray[1].wDay; + selArray[1].wDay = selArray[0].wDay; + selArray[0].wDay = tempday; + } + + MONTHCAL_SetSelRange(infoPtr, (LPARAM)&selArray); + } + } + +done: + + /* only redraw if the currently selected day changed */ + /* FIXME: this should specify a rectangle containing only the days that changed */ + /* using InvalidateRect */ + if(oldselday != infoPtr->curSelDay) + InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); + + return 0; +} + + +static LRESULT +MONTHCAL_Paint(MONTHCAL_INFO *infoPtr, WPARAM wParam) +{ + HDC hdc; + PAINTSTRUCT ps; + + if (wParam) + { + GetClientRect(infoPtr->hwndSelf, &ps.rcPaint); + hdc = (HDC)wParam; + } + else + hdc = BeginPaint(infoPtr->hwndSelf, &ps); + + MONTHCAL_Refresh(infoPtr, hdc, &ps); + if (!wParam) EndPaint(infoPtr->hwndSelf, &ps); + return 0; +} + + +static LRESULT +MONTHCAL_KillFocus(MONTHCAL_INFO *infoPtr) +{ + TRACE("\n"); + + InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); + + return 0; +} + + +static LRESULT +MONTHCAL_SetFocus(MONTHCAL_INFO *infoPtr) +{ + TRACE("\n"); + + InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); + + return 0; +} + +/* sets the size information */ +static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr) +{ + static const WCHAR SunW[] = { 'S','u','n',0 }; + static const WCHAR O0W[] = { '0','0',0 }; + HDC hdc = GetDC(infoPtr->hwndSelf); + RECT *title=&infoPtr->title; + RECT *prev=&infoPtr->titlebtnprev; + RECT *next=&infoPtr->titlebtnnext; + RECT *titlemonth=&infoPtr->titlemonth; + RECT *titleyear=&infoPtr->titleyear; + RECT *wdays=&infoPtr->wdays; + RECT *weeknumrect=&infoPtr->weeknums; + RECT *days=&infoPtr->days; + RECT *todayrect=&infoPtr->todayrect; + SIZE size; + TEXTMETRICW tm; + DWORD dwStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE); + HFONT currentFont; + int xdiv, left_offset; + RECT rcClient; + + GetClientRect(infoPtr->hwndSelf, &rcClient); + + currentFont = SelectObject(hdc, infoPtr->hFont); + + /* get the height and width of each day's text */ + GetTextMetricsW(hdc, &tm); + infoPtr->textHeight = tm.tmHeight + tm.tmExternalLeading + tm.tmInternalLeading; + GetTextExtentPoint32W(hdc, SunW, 3, &size); + infoPtr->textWidth = size.cx + 2; + + /* recalculate the height and width increments and offsets */ + GetTextExtentPoint32W(hdc, O0W, 2, &size); + + xdiv = (dwStyle & MCS_WEEKNUMBERS) ? 8 : 7; + + infoPtr->width_increment = size.cx * 2 + 4; + infoPtr->height_increment = infoPtr->textHeight; + left_offset = (rcClient.right - rcClient.left) - (infoPtr->width_increment * xdiv); + + /* calculate title area */ + title->top = rcClient.top; + title->bottom = title->top + 3 * infoPtr->height_increment / 2; + title->left = left_offset; + title->right = rcClient.right; + + /* set the dimensions of the next and previous buttons and center */ + /* the month text vertically */ + prev->top = next->top = title->top + 4; + prev->bottom = next->bottom = title->bottom - 4; + prev->left = title->left + 4; + prev->right = prev->left + (title->bottom - title->top) ; + next->right = title->right - 4; + next->left = next->right - (title->bottom - title->top); + + /* titlemonth->left and right change based upon the current month */ + /* and are recalculated in refresh as the current month may change */ + /* without the control being resized */ + titlemonth->top = titleyear->top = title->top + (infoPtr->height_increment)/2; + titlemonth->bottom = titleyear->bottom = title->bottom - (infoPtr->height_increment)/2; + + /* setup the dimensions of the rectangle we draw the names of the */ + /* days of the week in */ + weeknumrect->left = left_offset; + if(dwStyle & MCS_WEEKNUMBERS) + weeknumrect->right=prev->right; + else + weeknumrect->right=weeknumrect->left; + wdays->left = days->left = weeknumrect->right; + wdays->right = days->right = wdays->left + 7 * infoPtr->width_increment; + wdays->top = title->bottom ; + wdays->bottom = wdays->top + infoPtr->height_increment; + + days->top = weeknumrect->top = wdays->bottom ; + days->bottom = weeknumrect->bottom = days->top + 6 * infoPtr->height_increment; + + todayrect->left = rcClient.left; + todayrect->right = rcClient.right; + todayrect->top = days->bottom; + todayrect->bottom = days->bottom + infoPtr->height_increment; + + TRACE("dx=%d dy=%d client[%s] title[%s] wdays[%s] days[%s] today[%s]\n", + infoPtr->width_increment,infoPtr->height_increment, + wine_dbgstr_rect(&rcClient), + wine_dbgstr_rect(title), + wine_dbgstr_rect(wdays), + wine_dbgstr_rect(days), + wine_dbgstr_rect(todayrect)); + + /* restore the originally selected font */ + SelectObject(hdc, currentFont); + + ReleaseDC(infoPtr->hwndSelf, hdc); +} + +static LRESULT MONTHCAL_Size(MONTHCAL_INFO *infoPtr, int Width, int Height) +{ + TRACE("(width=%d, height=%d)\n", Width, Height); + + MONTHCAL_UpdateSize(infoPtr); + + /* invalidate client area and erase background */ + InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); + + return 0; +} + +static LRESULT MONTHCAL_GetFont(MONTHCAL_INFO *infoPtr) +{ + return (LRESULT)infoPtr->hFont; +} + +static LRESULT MONTHCAL_SetFont(MONTHCAL_INFO *infoPtr, HFONT hFont, BOOL redraw) +{ + HFONT hOldFont; + LOGFONTW lf; + + if (!hFont) return 0; + + hOldFont = infoPtr->hFont; + infoPtr->hFont = hFont; + + GetObjectW(infoPtr->hFont, sizeof(lf), &lf); + lf.lfWeight = FW_BOLD; + infoPtr->hBoldFont = CreateFontIndirectW(&lf); + + if (redraw) + InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); + + return (LRESULT)hOldFont; +} + +/* FIXME: check whether dateMin/dateMax need to be adjusted. */ +static LRESULT +MONTHCAL_Create(HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + MONTHCAL_INFO *infoPtr; + + /* allocate memory for info structure */ + infoPtr =(MONTHCAL_INFO*)Alloc(sizeof(MONTHCAL_INFO)); + SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)infoPtr); + + if(infoPtr == NULL) { + ERR( "could not allocate info memory!\n"); + return 0; + } + + infoPtr->hwndSelf = hwnd; + infoPtr->hwndNotify = ((LPCREATESTRUCTW)lParam)->hwndParent; + + MONTHCAL_SetFont(infoPtr, GetStockObject(DEFAULT_GUI_FONT), FALSE); + + /* initialize info structure */ + /* FIXME: calculate systemtime ->> localtime(substract timezoneinfo) */ + + GetLocalTime(&infoPtr->todaysDate); + MONTHCAL_SetFirstDayOfWeek(infoPtr, (LPARAM)-1); + infoPtr->currentMonth = infoPtr->todaysDate.wMonth; + infoPtr->currentYear = infoPtr->todaysDate.wYear; + MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->minDate); + MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->maxDate); + infoPtr->maxDate.wYear=2050; + infoPtr->minDate.wYear=1950; + infoPtr->maxSelCount = 7; + infoPtr->monthRange = 3; + infoPtr->monthdayState = Alloc + (infoPtr->monthRange * sizeof(MONTHDAYSTATE)); + infoPtr->titlebk = GetSysColor(COLOR_ACTIVECAPTION); + infoPtr->titletxt = GetSysColor(COLOR_WINDOW); + infoPtr->monthbk = GetSysColor(COLOR_WINDOW); + infoPtr->trailingtxt = GetSysColor(COLOR_GRAYTEXT); + infoPtr->bk = GetSysColor(COLOR_WINDOW); + infoPtr->txt = GetSysColor(COLOR_WINDOWTEXT); + + /* call MONTHCAL_UpdateSize to set all of the dimensions */ + /* of the control */ + MONTHCAL_UpdateSize(infoPtr); + + return 0; +} + + +static LRESULT +MONTHCAL_Destroy(MONTHCAL_INFO *infoPtr) +{ + /* free month calendar info data */ + if(infoPtr->monthdayState) + Free(infoPtr->monthdayState); + SetWindowLongPtrW(infoPtr->hwndSelf, 0, 0); + Free(infoPtr); + return 0; +} + + +static LRESULT WINAPI +MONTHCAL_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + MONTHCAL_INFO *infoPtr; + + TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hwnd, uMsg, wParam, lParam); + + infoPtr = MONTHCAL_GetInfoPtr(hwnd); + if (!infoPtr && (uMsg != WM_CREATE)) + return DefWindowProcW(hwnd, uMsg, wParam, lParam); + switch(uMsg) + { + case MCM_GETCURSEL: + return MONTHCAL_GetCurSel(infoPtr, lParam); + + case MCM_SETCURSEL: + return MONTHCAL_SetCurSel(infoPtr, lParam); + + case MCM_GETMAXSELCOUNT: + return MONTHCAL_GetMaxSelCount(infoPtr); + + case MCM_SETMAXSELCOUNT: + return MONTHCAL_SetMaxSelCount(infoPtr, wParam); + + case MCM_GETSELRANGE: + return MONTHCAL_GetSelRange(infoPtr, lParam); + + case MCM_SETSELRANGE: + return MONTHCAL_SetSelRange(infoPtr, lParam); + + case MCM_GETMONTHRANGE: + return MONTHCAL_GetMonthRange(infoPtr); + + case MCM_SETDAYSTATE: + return MONTHCAL_SetDayState(infoPtr, wParam, lParam); + + case MCM_GETMINREQRECT: + return MONTHCAL_GetMinReqRect(infoPtr, lParam); + + case MCM_GETCOLOR: + return MONTHCAL_GetColor(infoPtr, wParam); + + case MCM_SETCOLOR: + return MONTHCAL_SetColor(infoPtr, wParam, lParam); + + case MCM_GETTODAY: + return MONTHCAL_GetToday(infoPtr, lParam); + + case MCM_SETTODAY: + return MONTHCAL_SetToday(infoPtr, lParam); + + case MCM_HITTEST: + return MONTHCAL_HitTest(infoPtr, lParam); + + case MCM_GETFIRSTDAYOFWEEK: + return MONTHCAL_GetFirstDayOfWeek(infoPtr); + + case MCM_SETFIRSTDAYOFWEEK: + return MONTHCAL_SetFirstDayOfWeek(infoPtr, lParam); + + case MCM_GETRANGE: + return MONTHCAL_GetRange(hwnd, wParam, lParam); + + case MCM_SETRANGE: + return MONTHCAL_SetRange(infoPtr, wParam, lParam); + + case MCM_GETMONTHDELTA: + return MONTHCAL_GetMonthDelta(infoPtr); + + case MCM_SETMONTHDELTA: + return MONTHCAL_SetMonthDelta(infoPtr, wParam); + + case MCM_GETMAXTODAYWIDTH: + return MONTHCAL_GetMaxTodayWidth(infoPtr); + + case WM_GETDLGCODE: + return DLGC_WANTARROWS | DLGC_WANTCHARS; + + case WM_KILLFOCUS: + return MONTHCAL_KillFocus(infoPtr); + + case WM_RBUTTONDOWN: + return MONTHCAL_RButtonDown(infoPtr, lParam); + + case WM_LBUTTONDOWN: + return MONTHCAL_LButtonDown(infoPtr, lParam); + + case WM_MOUSEMOVE: + return MONTHCAL_MouseMove(infoPtr, wParam, lParam); + + case WM_LBUTTONUP: + return MONTHCAL_LButtonUp(infoPtr, lParam); + + case WM_PAINT: + return MONTHCAL_Paint(infoPtr, wParam); + + case WM_SETFOCUS: + return MONTHCAL_SetFocus(infoPtr); + + case WM_SIZE: + return MONTHCAL_Size(infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); + + case WM_CREATE: + return MONTHCAL_Create(hwnd, wParam, lParam); + + case WM_SETFONT: + return MONTHCAL_SetFont(infoPtr, (HFONT)wParam, (BOOL)lParam); + + case WM_GETFONT: + return MONTHCAL_GetFont(infoPtr); + + case WM_TIMER: + return MONTHCAL_Timer(infoPtr, wParam); + + case WM_DESTROY: + return MONTHCAL_Destroy(infoPtr); + + default: + if ((uMsg >= WM_USER) && (uMsg < WM_APP)) + ERR( "unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam); + return DefWindowProcW(hwnd, uMsg, wParam, lParam); + } +} + + +void +MONTHCAL_Register(void) +{ + WNDCLASSW wndClass; + + ZeroMemory(&wndClass, sizeof(WNDCLASSW)); + wndClass.style = CS_GLOBALCLASS; + wndClass.lpfnWndProc = MONTHCAL_WindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(MONTHCAL_INFO *); + wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW); + wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wndClass.lpszClassName = MONTHCAL_CLASSW; + + RegisterClassW(&wndClass); +} + + +void +MONTHCAL_Unregister(void) +{ + UnregisterClassW(MONTHCAL_CLASSW, NULL); +} diff --git a/reactos/lib/comctl32/nativefont.c b/reactos/lib/comctl32/nativefont.c index 4955a8c83b1..4695e7fb8a4 100644 --- a/reactos/lib/comctl32/nativefont.c +++ b/reactos/lib/comctl32/nativefont.c @@ -1,134 +1,134 @@ -/* - * Native Font control - * - * Copyright 1998, 1999 Eric Kohl - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTES - * This is just a dummy control. An author is needed! Any volunteers? - * I will only improve this control once in a while. - * Eric - * - * TODO: - * - All messages. - * - All notifications. - */ - -#include - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "commctrl.h" -#include "comctl32.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(nativefont); - -typedef struct -{ - HWND hwndSelf; /* my own handle */ -} NATIVEFONT_INFO; - -#define NATIVEFONT_GetInfoPtr(hwnd) ((NATIVEFONT_INFO *)GetWindowLongPtrW (hwnd, 0)) - -static LRESULT -NATIVEFONT_Create (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - NATIVEFONT_INFO *infoPtr; - - /* allocate memory for info structure */ - infoPtr = (NATIVEFONT_INFO *)Alloc (sizeof(NATIVEFONT_INFO)); - SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); - - /* initialize info structure */ - infoPtr->hwndSelf = hwnd; - - return 0; -} - -static LRESULT -NATIVEFONT_Destroy (NATIVEFONT_INFO *infoPtr) -{ - /* free control info data */ - SetWindowLongPtrW( infoPtr->hwndSelf, 0, 0 ); - Free (infoPtr); - - return 0; -} - -static LRESULT WINAPI -NATIVEFONT_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - NATIVEFONT_INFO *infoPtr = NATIVEFONT_GetInfoPtr(hwnd); - - TRACE("hwnd=%p msg=%04x wparam=%08x lparam=%08lx\n", - hwnd, uMsg, wParam, lParam); - - if (!infoPtr && (uMsg != WM_CREATE)) - return DefWindowProcW( hwnd, uMsg, wParam, lParam ); - - switch (uMsg) - { - case WM_CREATE: - return NATIVEFONT_Create (hwnd, wParam, lParam); - - case WM_DESTROY: - return NATIVEFONT_Destroy (infoPtr); - - case WM_MOVE: - case WM_SIZE: - case WM_SHOWWINDOW: - case WM_WINDOWPOSCHANGING: - case WM_WINDOWPOSCHANGED: - case WM_SETFONT: - case WM_GETDLGCODE: - /* FIXME("message %04x seen but stubbed\n", uMsg); */ - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - - default: - if ((uMsg >= WM_USER) && (uMsg < WM_APP)) - ERR("unknown msg %04x wp=%08x lp=%08lx\n", - uMsg, wParam, lParam); - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - } -} - - -VOID -NATIVEFONT_Register (void) -{ - WNDCLASSW wndClass; - - ZeroMemory (&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS; - wndClass.lpfnWndProc = NATIVEFONT_WindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(NATIVEFONT_INFO *); - wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); - wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); - wndClass.lpszClassName = WC_NATIVEFONTCTLW; - - RegisterClassW (&wndClass); -} - - -VOID -NATIVEFONT_Unregister (void) -{ - UnregisterClassW (WC_NATIVEFONTCTLW, NULL); -} +/* + * Native Font control + * + * Copyright 1998, 1999 Eric Kohl + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES + * This is just a dummy control. An author is needed! Any volunteers? + * I will only improve this control once in a while. + * Eric + * + * TODO: + * - All messages. + * - All notifications. + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "commctrl.h" +#include "comctl32.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(nativefont); + +typedef struct +{ + HWND hwndSelf; /* my own handle */ +} NATIVEFONT_INFO; + +#define NATIVEFONT_GetInfoPtr(hwnd) ((NATIVEFONT_INFO *)GetWindowLongPtrW (hwnd, 0)) + +static LRESULT +NATIVEFONT_Create (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + NATIVEFONT_INFO *infoPtr; + + /* allocate memory for info structure */ + infoPtr = (NATIVEFONT_INFO *)Alloc (sizeof(NATIVEFONT_INFO)); + SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); + + /* initialize info structure */ + infoPtr->hwndSelf = hwnd; + + return 0; +} + +static LRESULT +NATIVEFONT_Destroy (NATIVEFONT_INFO *infoPtr) +{ + /* free control info data */ + SetWindowLongPtrW( infoPtr->hwndSelf, 0, 0 ); + Free (infoPtr); + + return 0; +} + +static LRESULT WINAPI +NATIVEFONT_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + NATIVEFONT_INFO *infoPtr = NATIVEFONT_GetInfoPtr(hwnd); + + TRACE("hwnd=%p msg=%04x wparam=%08x lparam=%08lx\n", + hwnd, uMsg, wParam, lParam); + + if (!infoPtr && (uMsg != WM_CREATE)) + return DefWindowProcW( hwnd, uMsg, wParam, lParam ); + + switch (uMsg) + { + case WM_CREATE: + return NATIVEFONT_Create (hwnd, wParam, lParam); + + case WM_DESTROY: + return NATIVEFONT_Destroy (infoPtr); + + case WM_MOVE: + case WM_SIZE: + case WM_SHOWWINDOW: + case WM_WINDOWPOSCHANGING: + case WM_WINDOWPOSCHANGED: + case WM_SETFONT: + case WM_GETDLGCODE: + /* FIXME("message %04x seen but stubbed\n", uMsg); */ + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + + default: + if ((uMsg >= WM_USER) && (uMsg < WM_APP)) + ERR("unknown msg %04x wp=%08x lp=%08lx\n", + uMsg, wParam, lParam); + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + } +} + + +VOID +NATIVEFONT_Register (void) +{ + WNDCLASSW wndClass; + + ZeroMemory (&wndClass, sizeof(WNDCLASSW)); + wndClass.style = CS_GLOBALCLASS; + wndClass.lpfnWndProc = NATIVEFONT_WindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(NATIVEFONT_INFO *); + wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); + wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); + wndClass.lpszClassName = WC_NATIVEFONTCTLW; + + RegisterClassW (&wndClass); +} + + +VOID +NATIVEFONT_Unregister (void) +{ + UnregisterClassW (WC_NATIVEFONTCTLW, NULL); +} diff --git a/reactos/lib/comctl32/pager.c b/reactos/lib/comctl32/pager.c index b426a631c8d..971da4e1b89 100644 --- a/reactos/lib/comctl32/pager.c +++ b/reactos/lib/comctl32/pager.c @@ -1,1382 +1,1382 @@ -/* - * Pager control - * - * Copyright 1998, 1999 Eric Kohl - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTES - * - * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on Sep. 18, 2004, by Robert Shearman. - * - * Unless otherwise noted, we believe this code to be complete, as per - * the specification mentioned above. - * If you discover missing features or bugs please note them below. - * - * TODO: - * Implement repetitive button press. - * Adjust arrow size relative to size of button. - * Allow border size changes. - * Styles: - * PGS_DRAGNDROP - * Notifications: - * PGN_HOTITEMCHANGE - * - * TESTING: - * Tested primarily with the controlspy Pager application. - * Susan Farley (susan@codeweavers.com) - * - * IMPLEMENTATION NOTES: - * This control uses WM_NCPAINT instead of WM_PAINT to paint itself - * as we need to scroll a child window. In order to do this we move - * the child window in the control's client area, using the clipping - * region that is automatically set around the client area. As the - * entire client area now consists of the child window, we must - * allocate space (WM_NCCALCSIZE) for the buttons and draw them as - * a non-client area (WM_NCPAINT). - * Robert Shearman - */ - -#include -#include -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "windowsx.h" -#include "commctrl.h" -#include "comctl32.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(pager); - -typedef struct -{ - HWND hwndSelf; /* handle of the control wnd */ - HWND hwndChild; /* handle of the contained wnd */ - HWND hwndNotify; /* handle of the parent wnd */ - DWORD dwStyle; /* styles for this control */ - COLORREF clrBk; /* background color */ - INT nBorder; /* border size for the control */ - INT nButtonSize;/* size of the pager btns */ - INT nPos; /* scroll position */ - INT nWidth; /* from child wnd's response to PGN_CALCSIZE */ - INT nHeight; /* from child wnd's response to PGN_CALCSIZE */ - BOOL bForward; /* forward WM_MOUSEMOVE msgs to the contained wnd */ - BOOL bCapture; /* we have captured the mouse */ - INT TLbtnState; /* state of top or left btn */ - INT BRbtnState; /* state of bottom or right btn */ - INT direction; /* direction of the scroll, (e.g. PGF_SCROLLUP) */ -} PAGER_INFO; - -#define MIN_ARROW_WIDTH 8 -#define MIN_ARROW_HEIGHT 5 - -#define TIMERID1 1 -#define TIMERID2 2 -#define INITIAL_DELAY 500 -#define REPEAT_DELAY 50 - -static void -PAGER_GetButtonRects(PAGER_INFO* infoPtr, RECT* prcTopLeft, RECT* prcBottomRight, BOOL bClientCoords) -{ - RECT rcWindow; - GetWindowRect (infoPtr->hwndSelf, &rcWindow); - - if (bClientCoords) - { - POINT pt = {rcWindow.left, rcWindow.top}; - ScreenToClient(infoPtr->hwndSelf, &pt); - OffsetRect(&rcWindow, -(rcWindow.left-pt.x), -(rcWindow.top-pt.y)); - } - else - OffsetRect(&rcWindow, -rcWindow.left, -rcWindow.top); - - *prcTopLeft = *prcBottomRight = rcWindow; - if (infoPtr->dwStyle & PGS_HORZ) - { - prcTopLeft->right = prcTopLeft->left + infoPtr->nButtonSize; - prcBottomRight->left = prcBottomRight->right - infoPtr->nButtonSize; - } - else - { - prcTopLeft->bottom = prcTopLeft->top + infoPtr->nButtonSize; - prcBottomRight->top = prcBottomRight->bottom - infoPtr->nButtonSize; - } -} - -/* the horizontal arrows are: - * - * 01234 01234 - * 1 * * - * 2 ** ** - * 3*** *** - * 4*** *** - * 5 ** ** - * 6 * * - * 7 - * - */ -static void -PAGER_DrawHorzArrow (HDC hdc, RECT r, INT colorRef, BOOL left) -{ - INT x, y, w, h; - HPEN hPen, hOldPen; - - w = r.right - r.left + 1; - h = r.bottom - r.top + 1; - if ((h < MIN_ARROW_WIDTH) || (w < MIN_ARROW_HEIGHT)) - return; /* refuse to draw partial arrow */ - - if (!(hPen = CreatePen( PS_SOLID, 1, GetSysColor( colorRef )))) return; - hOldPen = SelectObject ( hdc, hPen ); - if (left) - { - x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 3; - y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1; - MoveToEx (hdc, x, y, NULL); - LineTo (hdc, x--, y+5); y++; - MoveToEx (hdc, x, y, NULL); - LineTo (hdc, x--, y+3); y++; - MoveToEx (hdc, x, y, NULL); - LineTo (hdc, x, y+1); - } - else - { - x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1; - y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1; - MoveToEx (hdc, x, y, NULL); - LineTo (hdc, x++, y+5); y++; - MoveToEx (hdc, x, y, NULL); - LineTo (hdc, x++, y+3); y++; - MoveToEx (hdc, x, y, NULL); - LineTo (hdc, x, y+1); - } - - SelectObject( hdc, hOldPen ); - DeleteObject( hPen ); -} - -/* the vertical arrows are: - * - * 01234567 01234567 - * 1****** ** - * 2 **** **** - * 3 ** ****** - * 4 - * - */ -static void -PAGER_DrawVertArrow (HDC hdc, RECT r, INT colorRef, BOOL up) -{ - INT x, y, w, h; - HPEN hPen, hOldPen; - - w = r.right - r.left + 1; - h = r.bottom - r.top + 1; - if ((h < MIN_ARROW_WIDTH) || (w < MIN_ARROW_HEIGHT)) - return; /* refuse to draw partial arrow */ - - if (!(hPen = CreatePen( PS_SOLID, 1, GetSysColor( colorRef )))) return; - hOldPen = SelectObject ( hdc, hPen ); - if (up) - { - x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1; - y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 3; - MoveToEx (hdc, x, y, NULL); - LineTo (hdc, x+5, y--); x++; - MoveToEx (hdc, x, y, NULL); - LineTo (hdc, x+3, y--); x++; - MoveToEx (hdc, x, y, NULL); - LineTo (hdc, x+1, y); - } - else - { - x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1; - y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1; - MoveToEx (hdc, x, y, NULL); - LineTo (hdc, x+5, y++); x++; - MoveToEx (hdc, x, y, NULL); - LineTo (hdc, x+3, y++); x++; - MoveToEx (hdc, x, y, NULL); - LineTo (hdc, x+1, y); - } - - SelectObject( hdc, hOldPen ); - DeleteObject( hPen ); -} - -static void -PAGER_DrawButton(HDC hdc, COLORREF clrBk, RECT arrowRect, - BOOL horz, BOOL topLeft, INT btnState) -{ - HBRUSH hBrush, hOldBrush; - RECT rc = arrowRect; - - TRACE("arrowRect = %s, btnState = %d\n", wine_dbgstr_rect(&arrowRect), btnState); - - if (btnState == PGF_INVISIBLE) - return; - - if ((rc.right - rc.left <= 0) || (rc.bottom - rc.top <= 0)) - return; - - hBrush = CreateSolidBrush(clrBk); - hOldBrush = (HBRUSH)SelectObject(hdc, hBrush); - - FillRect(hdc, &rc, hBrush); - - if (btnState == PGF_HOT) - { - DrawEdge( hdc, &rc, BDR_RAISEDINNER, BF_RECT); - if (horz) - PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft); - else - PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft); - } - else if (btnState == PGF_NORMAL) - { - DrawEdge (hdc, &rc, BDR_OUTER, BF_FLAT); - if (horz) - PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft); - else - PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft); - } - else if (btnState == PGF_DEPRESSED) - { - DrawEdge( hdc, &rc, BDR_SUNKENOUTER, BF_RECT); - if (horz) - PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft); - else - PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft); - } - else if (btnState == PGF_GRAYED) - { - DrawEdge (hdc, &rc, BDR_OUTER, BF_FLAT); - if (horz) - { - PAGER_DrawHorzArrow(hdc, rc, COLOR_3DHIGHLIGHT, topLeft); - rc.left++, rc.top++; rc.right++, rc.bottom++; - PAGER_DrawHorzArrow(hdc, rc, COLOR_3DSHADOW, topLeft); - } - else - { - PAGER_DrawVertArrow(hdc, rc, COLOR_3DHIGHLIGHT, topLeft); - rc.left++, rc.top++; rc.right++, rc.bottom++; - PAGER_DrawVertArrow(hdc, rc, COLOR_3DSHADOW, topLeft); - } - } - - SelectObject( hdc, hOldBrush ); - DeleteObject(hBrush); -} - -/* << PAGER_GetDropTarget >> */ - -static inline LRESULT -PAGER_ForwardMouse (PAGER_INFO* infoPtr, BOOL bFwd) -{ - TRACE("[%p]\n", infoPtr->hwndSelf); - - infoPtr->bForward = bFwd; - - return 0; -} - -static inline LRESULT -PAGER_GetButtonState (PAGER_INFO* infoPtr, INT btn) -{ - LRESULT btnState = PGF_INVISIBLE; - TRACE("[%p]\n", infoPtr->hwndSelf); - - if (btn == PGB_TOPORLEFT) - btnState = infoPtr->TLbtnState; - else if (btn == PGB_BOTTOMORRIGHT) - btnState = infoPtr->BRbtnState; - - return btnState; -} - - -static inline INT -PAGER_GetPos(PAGER_INFO *infoPtr) -{ - TRACE("[%p] returns %d\n", infoPtr->hwndSelf, infoPtr->nPos); - return infoPtr->nPos; -} - -static inline INT -PAGER_GetButtonSize(PAGER_INFO *infoPtr) -{ - TRACE("[%p] returns %d\n", infoPtr->hwndSelf, infoPtr->nButtonSize); - return infoPtr->nButtonSize; -} - -static inline INT -PAGER_GetBorder(PAGER_INFO *infoPtr) -{ - TRACE("[%p] returns %d\n", infoPtr->hwndSelf, infoPtr->nBorder); - return infoPtr->nBorder; -} - -static inline COLORREF -PAGER_GetBkColor(PAGER_INFO *infoPtr) -{ - TRACE("[%p] returns %06lx\n", infoPtr->hwndSelf, infoPtr->clrBk); - return infoPtr->clrBk; -} - -static void -PAGER_CalcSize (PAGER_INFO *infoPtr, INT* size, BOOL getWidth) -{ - NMPGCALCSIZE nmpgcs; - ZeroMemory (&nmpgcs, sizeof (NMPGCALCSIZE)); - nmpgcs.hdr.hwndFrom = infoPtr->hwndSelf; - nmpgcs.hdr.idFrom = GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_ID); - nmpgcs.hdr.code = PGN_CALCSIZE; - nmpgcs.dwFlag = getWidth ? PGF_CALCWIDTH : PGF_CALCHEIGHT; - nmpgcs.iWidth = getWidth ? *size : 0; - nmpgcs.iHeight = getWidth ? 0 : *size; - SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, - (WPARAM)nmpgcs.hdr.idFrom, (LPARAM)&nmpgcs); - - *size = getWidth ? nmpgcs.iWidth : nmpgcs.iHeight; - - TRACE("[%p] PGN_CALCSIZE returns %s=%d\n", infoPtr->hwndSelf, - getWidth ? "width" : "height", *size); -} - -static void -PAGER_PositionChildWnd(PAGER_INFO* infoPtr) -{ - if (infoPtr->hwndChild) - { - RECT rcClient; - int nPos = infoPtr->nPos; - - /* compensate for a grayed btn, which will soon become invisible */ - if (infoPtr->TLbtnState == PGF_GRAYED) - nPos += infoPtr->nButtonSize; - - GetClientRect(infoPtr->hwndSelf, &rcClient); - - if (infoPtr->dwStyle & PGS_HORZ) - { - int wndSize = max(0, rcClient.right - rcClient.left); - if (infoPtr->nWidth < wndSize) - infoPtr->nWidth = wndSize; - - TRACE("[%p] SWP %dx%d at (%d,%d)\n", infoPtr->hwndSelf, - infoPtr->nWidth, infoPtr->nHeight, - -nPos, 0); - SetWindowPos(infoPtr->hwndChild, 0, - -nPos, 0, - infoPtr->nWidth, infoPtr->nHeight, - SWP_NOZORDER); - } - else - { - int wndSize = max(0, rcClient.bottom - rcClient.top); - if (infoPtr->nHeight < wndSize) - infoPtr->nHeight = wndSize; - - TRACE("[%p] SWP %dx%d at (%d,%d)\n", infoPtr->hwndSelf, - infoPtr->nWidth, infoPtr->nHeight, - 0, -nPos); - SetWindowPos(infoPtr->hwndChild, 0, - 0, -nPos, - infoPtr->nWidth, infoPtr->nHeight, - SWP_NOZORDER); - } - - InvalidateRect(infoPtr->hwndChild, NULL, TRUE); - } -} - -static INT -PAGER_GetScrollRange(PAGER_INFO* infoPtr) -{ - INT scrollRange = 0; - - if (infoPtr->hwndChild) - { - INT wndSize, childSize; - RECT wndRect; - GetWindowRect(infoPtr->hwndSelf, &wndRect); - - if (infoPtr->dwStyle & PGS_HORZ) - { - wndSize = wndRect.right - wndRect.left; - PAGER_CalcSize(infoPtr, &infoPtr->nWidth, TRUE); - childSize = infoPtr->nWidth; - } - else - { - wndSize = wndRect.bottom - wndRect.top; - PAGER_CalcSize(infoPtr, &infoPtr->nHeight, FALSE); - childSize = infoPtr->nHeight; - } - - TRACE("childSize = %d, wndSize = %d\n", childSize, wndSize); - if (childSize > wndSize) - scrollRange = childSize - wndSize + infoPtr->nButtonSize; - } - - TRACE("[%p] returns %d\n", infoPtr->hwndSelf, scrollRange); - return scrollRange; -} - -static void -PAGER_UpdateBtns(PAGER_INFO *infoPtr, INT scrollRange, BOOL hideGrayBtns) -{ - BOOL resizeClient; - BOOL repaintBtns; - INT oldTLbtnState = infoPtr->TLbtnState; - INT oldBRbtnState = infoPtr->BRbtnState; - POINT pt; - RECT rcTopLeft, rcBottomRight; - - /* get button rects */ - PAGER_GetButtonRects(infoPtr, &rcTopLeft, &rcBottomRight, FALSE); - - GetCursorPos(&pt); - - /* update states based on scroll position */ - if (infoPtr->nPos > 0) - { - if (infoPtr->TLbtnState == PGF_INVISIBLE || infoPtr->TLbtnState == PGF_GRAYED) - infoPtr->TLbtnState = PGF_NORMAL; - } - else if (PtInRect(&rcTopLeft, pt)) - infoPtr->TLbtnState = PGF_GRAYED; - else - infoPtr->TLbtnState = PGF_INVISIBLE; - - if (scrollRange <= 0) - { - infoPtr->TLbtnState = PGF_INVISIBLE; - infoPtr->BRbtnState = PGF_INVISIBLE; - } - else if (infoPtr->nPos < scrollRange) - { - if (infoPtr->BRbtnState == PGF_INVISIBLE || infoPtr->BRbtnState == PGF_GRAYED) - infoPtr->BRbtnState = PGF_NORMAL; - } - else if (PtInRect(&rcBottomRight, pt)) - infoPtr->BRbtnState = PGF_GRAYED; - else - infoPtr->BRbtnState = PGF_INVISIBLE; - - /* only need to resize when entering or leaving PGF_INVISIBLE state */ - resizeClient = - ((oldTLbtnState == PGF_INVISIBLE) != (infoPtr->TLbtnState == PGF_INVISIBLE)) || - ((oldBRbtnState == PGF_INVISIBLE) != (infoPtr->BRbtnState == PGF_INVISIBLE)); - /* initiate NCCalcSize to resize client wnd if necessary */ - if (resizeClient) - SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0, - SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | - SWP_NOZORDER | SWP_NOACTIVATE); - - /* repaint when changing any state */ - repaintBtns = (oldTLbtnState != infoPtr->TLbtnState) || - (oldBRbtnState != infoPtr->BRbtnState); - if (repaintBtns) - SendMessageW(infoPtr->hwndSelf, WM_NCPAINT, 0, 0); -} - -static LRESULT -PAGER_SetPos(PAGER_INFO* infoPtr, INT newPos, BOOL fromBtnPress) -{ - INT scrollRange = PAGER_GetScrollRange(infoPtr); - INT oldPos = infoPtr->nPos; - - if ((scrollRange <= 0) || (newPos < 0)) - infoPtr->nPos = 0; - else if (newPos > scrollRange) - infoPtr->nPos = scrollRange; - else - infoPtr->nPos = newPos; - - TRACE("[%p] pos=%d, oldpos=%d\n", infoPtr->hwndSelf, infoPtr->nPos, oldPos); - - if (infoPtr->nPos != oldPos) - { - /* gray and restore btns, and if from WM_SETPOS, hide the gray btns */ - PAGER_UpdateBtns(infoPtr, scrollRange, !fromBtnPress); - PAGER_PositionChildWnd(infoPtr); - } - - return 0; -} - -static LRESULT -PAGER_WindowPosChanging(PAGER_INFO* infoPtr, WINDOWPOS *winpos) -{ - if ((infoPtr->dwStyle & CCS_NORESIZE) && !(winpos->flags & SWP_NOSIZE)) - { - /* don't let the app resize the nonscrollable dimension of a control - * that was created with CCS_NORESIZE style - * (i.e. height for a horizontal pager, or width for a vertical one) */ - - /* except if the current dimension is 0 and app is setting for - * first time, then save amount as dimension. - GA 8/01 */ - - if (infoPtr->dwStyle & PGS_HORZ) - if (!infoPtr->nHeight && winpos->cy) - infoPtr->nHeight = winpos->cy; - else - winpos->cy = infoPtr->nHeight; - else - if (!infoPtr->nWidth && winpos->cx) - infoPtr->nWidth = winpos->cx; - else - winpos->cx = infoPtr->nWidth; - return 0; - } - - return DefWindowProcW (infoPtr->hwndSelf, WM_WINDOWPOSCHANGING, 0, (LPARAM)winpos); -} - -static INT -PAGER_SetFixedWidth(PAGER_INFO* infoPtr) -{ - /* Must set the non-scrollable dimension to be less than the full height/width - * so that NCCalcSize is called. The Msoft docs mention 3/4 factor for button - * size, and experimentation shows that affect is almost right. */ - - RECT wndRect; - INT delta, h; - GetWindowRect(infoPtr->hwndSelf, &wndRect); - - /* see what the app says for btn width */ - PAGER_CalcSize(infoPtr, &infoPtr->nWidth, TRUE); - - if (infoPtr->dwStyle & CCS_NORESIZE) - { - delta = wndRect.right - wndRect.left - infoPtr->nWidth; - if (delta > infoPtr->nButtonSize) - infoPtr->nWidth += 4 * infoPtr->nButtonSize / 3; - else if (delta > 0) - infoPtr->nWidth += infoPtr->nButtonSize / 3; - } - - h = wndRect.bottom - wndRect.top + infoPtr->nButtonSize; - - TRACE("[%p] infoPtr->nWidth set to %d\n", - infoPtr->hwndSelf, infoPtr->nWidth); - - return h; -} - -static INT -PAGER_SetFixedHeight(PAGER_INFO* infoPtr) -{ - /* Must set the non-scrollable dimension to be less than the full height/width - * so that NCCalcSize is called. The Msoft docs mention 3/4 factor for button - * size, and experimentation shows that affect is almost right. */ - - RECT wndRect; - INT delta, w; - GetWindowRect(infoPtr->hwndSelf, &wndRect); - - /* see what the app says for btn height */ - PAGER_CalcSize(infoPtr, &infoPtr->nHeight, FALSE); - - if (infoPtr->dwStyle & CCS_NORESIZE) - { - delta = wndRect.bottom - wndRect.top - infoPtr->nHeight; - if (delta > infoPtr->nButtonSize) - infoPtr->nHeight += infoPtr->nButtonSize; - else if (delta > 0) - infoPtr->nHeight += infoPtr->nButtonSize / 3; - } - - w = wndRect.right - wndRect.left + infoPtr->nButtonSize; - - TRACE("[%p] infoPtr->nHeight set to %d\n", - infoPtr->hwndSelf, infoPtr->nHeight); - - return w; -} - -/****************************************************************** - * For the PGM_RECALCSIZE message (but not the other uses in * - * this module), the native control does only the following: * - * * - * if (some condition) * - * PostMessageW(hwnd, EM_FMTLINES, 0, 0); * - * return DefWindowProcW(hwnd, PGM_RECALCSIZE, 0, 0); * - * * - * When we figure out what the "some condition" is we will * - * implement that for the message processing. * - ******************************************************************/ - -static LRESULT -PAGER_RecalcSize(PAGER_INFO *infoPtr) -{ - TRACE("[%p]\n", infoPtr->hwndSelf); - - if (infoPtr->hwndChild) - { - INT scrollRange = PAGER_GetScrollRange(infoPtr); - - if (scrollRange <= 0) - { - infoPtr->nPos = -1; - PAGER_SetPos(infoPtr, 0, FALSE); - } - else - PAGER_PositionChildWnd(infoPtr); - } - - return 1; -} - - -static COLORREF -PAGER_SetBkColor (PAGER_INFO* infoPtr, COLORREF clrBk) -{ - COLORREF clrTemp = infoPtr->clrBk; - - infoPtr->clrBk = clrBk; - TRACE("[%p] %06lx\n", infoPtr->hwndSelf, infoPtr->clrBk); - - /* the native control seems to do things this way */ - SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0, - SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | - SWP_NOZORDER | SWP_NOACTIVATE); - - RedrawWindow(infoPtr->hwndSelf, 0, 0, RDW_ERASE | RDW_INVALIDATE); - - return clrTemp; -} - - -static INT -PAGER_SetBorder (PAGER_INFO* infoPtr, INT iBorder) -{ - INT nTemp = infoPtr->nBorder; - - infoPtr->nBorder = iBorder; - TRACE("[%p] %d\n", infoPtr->hwndSelf, infoPtr->nBorder); - - PAGER_RecalcSize(infoPtr); - - return nTemp; -} - - -static INT -PAGER_SetButtonSize (PAGER_INFO* infoPtr, INT iButtonSize) -{ - INT nTemp = infoPtr->nButtonSize; - - infoPtr->nButtonSize = iButtonSize; - TRACE("[%p] %d\n", infoPtr->hwndSelf, infoPtr->nButtonSize); - - PAGER_RecalcSize(infoPtr); - - return nTemp; -} - - -static LRESULT -PAGER_SetChild (PAGER_INFO* infoPtr, HWND hwndChild) -{ - INT hw; - - infoPtr->hwndChild = IsWindow (hwndChild) ? hwndChild : 0; - - if (infoPtr->hwndChild) - { - TRACE("[%p] hwndChild=%p\n", infoPtr->hwndSelf, infoPtr->hwndChild); - - if (infoPtr->dwStyle & PGS_HORZ) { - hw = PAGER_SetFixedHeight(infoPtr); - /* adjust non-scrollable dimension to fit the child */ - SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, hw, infoPtr->nHeight, - SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER | - SWP_NOSIZE | SWP_NOACTIVATE); - } - else { - hw = PAGER_SetFixedWidth(infoPtr); - /* adjust non-scrollable dimension to fit the child */ - SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, infoPtr->nWidth, hw, - SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER | - SWP_NOSIZE | SWP_NOACTIVATE); - } - - /* position child within the page scroller */ - SetWindowPos(infoPtr->hwndChild, HWND_TOP, - 0,0,0,0, - SWP_SHOWWINDOW | SWP_NOSIZE); /* native is 0 */ - - infoPtr->nPos = -1; - PAGER_SetPos(infoPtr, 0, FALSE); - } - - return 0; -} - -static void -PAGER_Scroll(PAGER_INFO* infoPtr, INT dir) -{ - NMPGSCROLL nmpgScroll; - RECT rcWnd; - - if (infoPtr->hwndChild) - { - ZeroMemory (&nmpgScroll, sizeof (NMPGSCROLL)); - nmpgScroll.hdr.hwndFrom = infoPtr->hwndSelf; - nmpgScroll.hdr.idFrom = GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_ID); - nmpgScroll.hdr.code = PGN_SCROLL; - - GetWindowRect(infoPtr->hwndSelf, &rcWnd); - GetClientRect(infoPtr->hwndSelf, &nmpgScroll.rcParent); - nmpgScroll.iXpos = nmpgScroll.iYpos = 0; - nmpgScroll.iDir = dir; - - if (infoPtr->dwStyle & PGS_HORZ) - { - nmpgScroll.iScroll = rcWnd.right - rcWnd.left; - nmpgScroll.iXpos = infoPtr->nPos; - } - else - { - nmpgScroll.iScroll = rcWnd.bottom - rcWnd.top; - nmpgScroll.iYpos = infoPtr->nPos; - } - nmpgScroll.iScroll -= 2*infoPtr->nButtonSize; - - SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, - (WPARAM)nmpgScroll.hdr.idFrom, (LPARAM)&nmpgScroll); - - TRACE("[%p] PGN_SCROLL returns iScroll=%d\n", infoPtr->hwndSelf, nmpgScroll.iScroll); - - if (nmpgScroll.iScroll > 0) - { - infoPtr->direction = dir; - - if (dir == PGF_SCROLLLEFT || dir == PGF_SCROLLUP) - PAGER_SetPos(infoPtr, infoPtr->nPos - nmpgScroll.iScroll, TRUE); - else - PAGER_SetPos(infoPtr, infoPtr->nPos + nmpgScroll.iScroll, TRUE); - } - else - infoPtr->direction = -1; - } -} - -static LRESULT -PAGER_FmtLines(PAGER_INFO *infoPtr) -{ - /* initiate NCCalcSize to resize client wnd and get size */ - SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0, - SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | - SWP_NOZORDER | SWP_NOACTIVATE); - - SetWindowPos(infoPtr->hwndChild, 0, - 0,0,infoPtr->nWidth,infoPtr->nHeight, - 0); - - return DefWindowProcW (infoPtr->hwndSelf, EM_FMTLINES, 0, 0); -} - -static LRESULT -PAGER_Create (HWND hwnd, LPCREATESTRUCTW lpcs) -{ - PAGER_INFO *infoPtr; - - /* allocate memory for info structure */ - infoPtr = (PAGER_INFO *)Alloc (sizeof(PAGER_INFO)); - if (!infoPtr) return -1; - SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); - - /* set default settings */ - infoPtr->hwndSelf = hwnd; - infoPtr->hwndChild = NULL; - infoPtr->hwndNotify = lpcs->hwndParent; - infoPtr->dwStyle = lpcs->style; - infoPtr->clrBk = GetSysColor(COLOR_BTNFACE); - infoPtr->nBorder = 0; - infoPtr->nButtonSize = 12; - infoPtr->nPos = 0; - infoPtr->nWidth = 0; - infoPtr->nHeight = 0; - infoPtr->bForward = FALSE; - infoPtr->bCapture = FALSE; - infoPtr->TLbtnState = PGF_INVISIBLE; - infoPtr->BRbtnState = PGF_INVISIBLE; - infoPtr->direction = -1; - - if (infoPtr->dwStyle & PGS_DRAGNDROP) - FIXME("[%p] Drag and Drop style is not implemented yet.\n", infoPtr->hwndSelf); - - return 0; -} - - -static LRESULT -PAGER_Destroy (PAGER_INFO *infoPtr) -{ - SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0); - Free (infoPtr); /* free pager info data */ - return 0; -} - -static LRESULT -PAGER_NCCalcSize(PAGER_INFO* infoPtr, WPARAM wParam, LPRECT lpRect) -{ - RECT rcChild, rcWindow; - INT scrollRange; - - /* - * lpRect points to a RECT struct. On entry, the struct - * contains the proposed wnd rectangle for the window. - * On exit, the struct should contain the screen - * coordinates of the corresponding window's client area. - */ - - DefWindowProcW (infoPtr->hwndSelf, WM_NCCALCSIZE, wParam, (LPARAM)lpRect); - - TRACE("orig rect=%s\n", wine_dbgstr_rect(lpRect)); - - GetWindowRect (infoPtr->hwndChild, &rcChild); - MapWindowPoints (0, infoPtr->hwndSelf, (LPPOINT)&rcChild, 2); /* FIXME: RECT != 2 POINTS */ - GetWindowRect (infoPtr->hwndSelf, &rcWindow); - - if (infoPtr->dwStyle & PGS_HORZ) - { - infoPtr->nWidth = lpRect->right - lpRect->left; - PAGER_CalcSize (infoPtr, &infoPtr->nWidth, TRUE); - - scrollRange = infoPtr->nWidth - (rcWindow.right - rcWindow.left); - - if (infoPtr->TLbtnState && (lpRect->left + infoPtr->nButtonSize < lpRect->right)) - lpRect->left += infoPtr->nButtonSize; - if (infoPtr->BRbtnState && (lpRect->right - infoPtr->nButtonSize > lpRect->left)) - lpRect->right -= infoPtr->nButtonSize; - } - else - { - infoPtr->nHeight = lpRect->bottom - lpRect->top; - PAGER_CalcSize (infoPtr, &infoPtr->nHeight, FALSE); - - scrollRange = infoPtr->nHeight - (rcWindow.bottom - rcWindow.top); - - if (infoPtr->TLbtnState && (lpRect->top + infoPtr->nButtonSize < lpRect->bottom)) - lpRect->top += infoPtr->nButtonSize; - if (infoPtr->BRbtnState && (lpRect->bottom - infoPtr->nButtonSize > lpRect->top)) - lpRect->bottom -= infoPtr->nButtonSize; - } - - TRACE("nPos=%d, nHeigth=%d, window=%s\n", - infoPtr->nPos, infoPtr->nHeight, - wine_dbgstr_rect(&rcWindow)); - - TRACE("[%p] client rect set to %ldx%ld at (%ld,%ld) BtnState[%d,%d]\n", - infoPtr->hwndSelf, lpRect->right-lpRect->left, lpRect->bottom-lpRect->top, - lpRect->left, lpRect->top, - infoPtr->TLbtnState, infoPtr->BRbtnState); - - return 0; -} - -static LRESULT -PAGER_NCPaint (PAGER_INFO* infoPtr, HRGN hRgn) -{ - RECT rcBottomRight, rcTopLeft; - HDC hdc; - - if (infoPtr->dwStyle & WS_MINIMIZE) - return 0; - - DefWindowProcW (infoPtr->hwndSelf, WM_NCPAINT, (WPARAM)hRgn, 0); - - if (!(hdc = GetDCEx (infoPtr->hwndSelf, 0, DCX_USESTYLE | DCX_WINDOW))) - return 0; - - PAGER_GetButtonRects(infoPtr, &rcTopLeft, &rcBottomRight, FALSE); - - PAGER_DrawButton(hdc, infoPtr->clrBk, rcTopLeft, - infoPtr->dwStyle & PGS_HORZ, TRUE, infoPtr->TLbtnState); - PAGER_DrawButton(hdc, infoPtr->clrBk, rcBottomRight, - infoPtr->dwStyle & PGS_HORZ, FALSE, infoPtr->BRbtnState); - - ReleaseDC( infoPtr->hwndSelf, hdc ); - return 0; -} - -static INT -PAGER_HitTest (PAGER_INFO* infoPtr, const POINT * pt) -{ - RECT clientRect, rcTopLeft, rcBottomRight; - POINT ptWindow; - - GetClientRect (infoPtr->hwndSelf, &clientRect); - - if (PtInRect(&clientRect, *pt)) - { - TRACE("child\n"); - return -1; - } - - ptWindow = *pt; - PAGER_GetButtonRects(infoPtr, &rcTopLeft, &rcBottomRight, TRUE); - - if ((infoPtr->TLbtnState != PGF_INVISIBLE) && PtInRect(&rcTopLeft, ptWindow)) - { - TRACE("PGB_TOPORLEFT\n"); - return PGB_TOPORLEFT; - } - else if ((infoPtr->BRbtnState != PGF_INVISIBLE) && PtInRect(&rcBottomRight, ptWindow)) - { - TRACE("PGB_BOTTOMORRIGHT\n"); - return PGB_BOTTOMORRIGHT; - } - - TRACE("nowhere\n"); - return -1; -} - -static LRESULT -PAGER_NCHitTest (PAGER_INFO* infoPtr, INT x, INT y) -{ - POINT pt; - INT nHit; - - pt.x = x; - pt.y = y; - - ScreenToClient (infoPtr->hwndSelf, &pt); - nHit = PAGER_HitTest(infoPtr, &pt); - - return (nHit < 0) ? HTTRANSPARENT : HTCLIENT; -} - -static LRESULT -PAGER_MouseMove (PAGER_INFO* infoPtr, INT keys, INT x, INT y) -{ - POINT clpt, pt; - RECT wnrect, *btnrect = NULL; - BOOL topLeft = FALSE; - INT btnstate = 0; - INT hit; - HDC hdc; - - pt.x = x; - pt.y = y; - - TRACE("[%p] to (%d,%d)\n", infoPtr->hwndSelf, x, y); - ClientToScreen(infoPtr->hwndSelf, &pt); - GetWindowRect(infoPtr->hwndSelf, &wnrect); - if (PtInRect(&wnrect, pt)) { - RECT TLbtnrect, BRbtnrect; - PAGER_GetButtonRects(infoPtr, &TLbtnrect, &BRbtnrect, FALSE); - - clpt = pt; - MapWindowPoints(0, infoPtr->hwndSelf, &clpt, 1); - hit = PAGER_HitTest(infoPtr, &clpt); - if ((hit == PGB_TOPORLEFT) && (infoPtr->TLbtnState == PGF_NORMAL)) - { - topLeft = TRUE; - btnrect = &TLbtnrect; - infoPtr->TLbtnState = PGF_HOT; - btnstate = infoPtr->TLbtnState; - } - else if ((hit == PGB_BOTTOMORRIGHT) && (infoPtr->BRbtnState == PGF_NORMAL)) - { - topLeft = FALSE; - btnrect = &BRbtnrect; - infoPtr->BRbtnState = PGF_HOT; - btnstate = infoPtr->BRbtnState; - } - - /* If in one of the buttons the capture and draw buttons */ - if (btnrect) - { - TRACE("[%p] draw btn (%ld,%ld)-(%ld,%ld), Capture %s, style %08lx\n", - infoPtr->hwndSelf, btnrect->left, btnrect->top, - btnrect->right, btnrect->bottom, - (infoPtr->bCapture) ? "TRUE" : "FALSE", - infoPtr->dwStyle); - if (!infoPtr->bCapture) - { - TRACE("[%p] SetCapture\n", infoPtr->hwndSelf); - SetCapture(infoPtr->hwndSelf); - infoPtr->bCapture = TRUE; - } - if (infoPtr->dwStyle & PGS_AUTOSCROLL) - SetTimer(infoPtr->hwndSelf, TIMERID1, 0x3e, 0); - hdc = GetWindowDC(infoPtr->hwndSelf); - /* OffsetRect(wnrect, 0 | 1, 0 | 1) */ - PAGER_DrawButton(hdc, infoPtr->clrBk, *btnrect, - infoPtr->dwStyle & PGS_HORZ, topLeft, btnstate); - ReleaseDC(infoPtr->hwndSelf, hdc); - return 0; - } - } - - /* If we think we are captured, then do release */ - if (infoPtr->bCapture && (WindowFromPoint(pt) != infoPtr->hwndSelf)) - { - NMHDR nmhdr; - - infoPtr->bCapture = FALSE; - - if (GetCapture() == infoPtr->hwndSelf) - { - ReleaseCapture(); - - if (infoPtr->TLbtnState == PGF_GRAYED) - { - infoPtr->TLbtnState = PGF_INVISIBLE; - SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0, - SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | - SWP_NOZORDER | SWP_NOACTIVATE); - } - else if (infoPtr->TLbtnState == PGF_HOT) - { - infoPtr->TLbtnState = PGF_NORMAL; - /* FIXME: just invalidate button rect */ - RedrawWindow(infoPtr->hwndSelf, NULL, NULL, RDW_FRAME | RDW_INVALIDATE); - } - - if (infoPtr->BRbtnState == PGF_GRAYED) - { - infoPtr->BRbtnState = PGF_INVISIBLE; - SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0, - SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | - SWP_NOZORDER | SWP_NOACTIVATE); - } - else if (infoPtr->BRbtnState == PGF_HOT) - { - infoPtr->BRbtnState = PGF_NORMAL; - /* FIXME: just invalidate button rect */ - RedrawWindow(infoPtr->hwndSelf, NULL, NULL, RDW_FRAME | RDW_INVALIDATE); - } - - /* Notify parent of released mouse capture */ - memset(&nmhdr, 0, sizeof(NMHDR)); - nmhdr.hwndFrom = infoPtr->hwndSelf; - nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); - nmhdr.code = NM_RELEASEDCAPTURE; - SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, - (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr); - } - if (IsWindow(infoPtr->hwndSelf)) - KillTimer(infoPtr->hwndSelf, TIMERID1); - } - return 0; -} - -static LRESULT -PAGER_LButtonDown (PAGER_INFO* infoPtr, INT keys, INT x, INT y) -{ - BOOL repaintBtns = FALSE; - POINT pt; - INT hit; - - pt.x = x; - pt.y = y; - - TRACE("[%p] at (%d,%d)\n", infoPtr->hwndSelf, x, y); - - hit = PAGER_HitTest(infoPtr, &pt); - - /* put btn in DEPRESSED state */ - if (hit == PGB_TOPORLEFT) - { - repaintBtns = infoPtr->TLbtnState != PGF_DEPRESSED; - infoPtr->TLbtnState = PGF_DEPRESSED; - SetTimer(infoPtr->hwndSelf, TIMERID1, INITIAL_DELAY, 0); - } - else if (hit == PGB_BOTTOMORRIGHT) - { - repaintBtns = infoPtr->BRbtnState != PGF_DEPRESSED; - infoPtr->BRbtnState = PGF_DEPRESSED; - SetTimer(infoPtr->hwndSelf, TIMERID1, INITIAL_DELAY, 0); - } - - if (repaintBtns) - SendMessageW(infoPtr->hwndSelf, WM_NCPAINT, 0, 0); - - switch(hit) - { - case PGB_TOPORLEFT: - if (infoPtr->dwStyle & PGS_HORZ) - { - TRACE("[%p] PGF_SCROLLLEFT\n", infoPtr->hwndSelf); - PAGER_Scroll(infoPtr, PGF_SCROLLLEFT); - } - else - { - TRACE("[%p] PGF_SCROLLUP\n", infoPtr->hwndSelf); - PAGER_Scroll(infoPtr, PGF_SCROLLUP); - } - break; - case PGB_BOTTOMORRIGHT: - if (infoPtr->dwStyle & PGS_HORZ) - { - TRACE("[%p] PGF_SCROLLRIGHT\n", infoPtr->hwndSelf); - PAGER_Scroll(infoPtr, PGF_SCROLLRIGHT); - } - else - { - TRACE("[%p] PGF_SCROLLDOWN\n", infoPtr->hwndSelf); - PAGER_Scroll(infoPtr, PGF_SCROLLDOWN); - } - break; - default: - break; - } - - return 0; -} - -static LRESULT -PAGER_LButtonUp (PAGER_INFO* infoPtr, INT keys, INT x, INT y) -{ - TRACE("[%p]\n", infoPtr->hwndSelf); - - KillTimer (infoPtr->hwndSelf, TIMERID1); - KillTimer (infoPtr->hwndSelf, TIMERID2); - - /* make PRESSED btns NORMAL but don't hide gray btns */ - if (infoPtr->TLbtnState & (PGF_HOT | PGF_DEPRESSED)) - infoPtr->TLbtnState = PGF_NORMAL; - if (infoPtr->BRbtnState & (PGF_HOT | PGF_DEPRESSED)) - infoPtr->BRbtnState = PGF_NORMAL; - - return 0; -} - -static LRESULT -PAGER_Timer (PAGER_INFO* infoPtr, INT nTimerId) -{ - INT dir; - - /* if initial timer, kill it and start the repeat timer */ - if (nTimerId == TIMERID1) { - if (infoPtr->TLbtnState == PGF_HOT) - dir = (infoPtr->dwStyle & PGS_HORZ) ? - PGF_SCROLLLEFT : PGF_SCROLLUP; - else - dir = (infoPtr->dwStyle & PGS_HORZ) ? - PGF_SCROLLRIGHT : PGF_SCROLLDOWN; - TRACE("[%p] TIMERID1: style=%08lx, dir=%d\n", - infoPtr->hwndSelf, infoPtr->dwStyle, dir); - KillTimer(infoPtr->hwndSelf, TIMERID1); - SetTimer(infoPtr->hwndSelf, TIMERID1, REPEAT_DELAY, 0); - if (infoPtr->dwStyle & PGS_AUTOSCROLL) { - PAGER_Scroll(infoPtr, dir); - SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0, - SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | - SWP_NOZORDER | SWP_NOACTIVATE); - } - return 0; - - } - - TRACE("[%p] TIMERID2: dir=%d\n", infoPtr->hwndSelf, infoPtr->direction); - KillTimer(infoPtr->hwndSelf, TIMERID2); - if (infoPtr->direction > 0) { - PAGER_Scroll(infoPtr, infoPtr->direction); - SetTimer(infoPtr->hwndSelf, TIMERID2, REPEAT_DELAY, 0); - } - return 0; -} - -static LRESULT -PAGER_EraseBackground (PAGER_INFO* infoPtr, HDC hdc) -{ - POINT pt, ptorig; - HWND parent; - - pt.x = 0; - pt.y = 0; - parent = GetParent(infoPtr->hwndSelf); - MapWindowPoints(infoPtr->hwndSelf, parent, &pt, 1); - OffsetWindowOrgEx (hdc, pt.x, pt.y, &ptorig); - SendMessageW (parent, WM_ERASEBKGND, (WPARAM)hdc, 0); - SetWindowOrgEx (hdc, ptorig.x, ptorig.y, 0); - - return 0; -} - - -static LRESULT -PAGER_Size (PAGER_INFO* infoPtr, INT type, INT x, INT y) -{ - /* note that WM_SIZE is sent whenever NCCalcSize resizes the client wnd */ - - TRACE("[%p] %d,%d\n", infoPtr->hwndSelf, x, y); - - if (infoPtr->dwStyle & PGS_HORZ) - infoPtr->nHeight = y; - else - infoPtr->nWidth = x; - - return PAGER_RecalcSize(infoPtr); -} - - -static LRESULT -PAGER_StyleChanged(PAGER_INFO *infoPtr, WPARAM wStyleType, LPSTYLESTRUCT lpss) -{ - DWORD oldStyle = infoPtr->dwStyle; - - TRACE("(styletype=%x, styleOld=0x%08lx, styleNew=0x%08lx)\n", - wStyleType, lpss->styleOld, lpss->styleNew); - - if (wStyleType != GWL_STYLE) return 0; - - infoPtr->dwStyle = lpss->styleNew; - - if ((oldStyle ^ lpss->styleNew) & (PGS_HORZ | PGS_VERT)) - { - PAGER_RecalcSize(infoPtr); - } - - return 0; -} - -static LRESULT WINAPI -PAGER_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - PAGER_INFO *infoPtr = (PAGER_INFO *)GetWindowLongPtrW(hwnd, 0); - - if (!infoPtr && (uMsg != WM_CREATE)) - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - - switch (uMsg) - { - case EM_FMTLINES: - return PAGER_FmtLines(infoPtr); - - case PGM_FORWARDMOUSE: - return PAGER_ForwardMouse (infoPtr, (BOOL)wParam); - - case PGM_GETBKCOLOR: - return PAGER_GetBkColor(infoPtr); - - case PGM_GETBORDER: - return PAGER_GetBorder(infoPtr); - - case PGM_GETBUTTONSIZE: - return PAGER_GetButtonSize(infoPtr); - - case PGM_GETPOS: - return PAGER_GetPos(infoPtr); - - case PGM_GETBUTTONSTATE: - return PAGER_GetButtonState (infoPtr, (INT)lParam); - -/* case PGM_GETDROPTARGET: */ - - case PGM_RECALCSIZE: - return PAGER_RecalcSize(infoPtr); - - case PGM_SETBKCOLOR: - return PAGER_SetBkColor (infoPtr, (COLORREF)lParam); - - case PGM_SETBORDER: - return PAGER_SetBorder (infoPtr, (INT)lParam); - - case PGM_SETBUTTONSIZE: - return PAGER_SetButtonSize (infoPtr, (INT)lParam); - - case PGM_SETCHILD: - return PAGER_SetChild (infoPtr, (HWND)lParam); - - case PGM_SETPOS: - return PAGER_SetPos(infoPtr, (INT)lParam, FALSE); - - case WM_CREATE: - return PAGER_Create (hwnd, (LPCREATESTRUCTW)lParam); - - case WM_DESTROY: - return PAGER_Destroy (infoPtr); - - case WM_SIZE: - return PAGER_Size (infoPtr, (INT)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); - - case WM_NCPAINT: - return PAGER_NCPaint (infoPtr, (HRGN)wParam); - - case WM_WINDOWPOSCHANGING: - return PAGER_WindowPosChanging (infoPtr, (WINDOWPOS*)lParam); - - case WM_STYLECHANGED: - return PAGER_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam); - - case WM_NCCALCSIZE: - return PAGER_NCCalcSize (infoPtr, wParam, (LPRECT)lParam); - - case WM_NCHITTEST: - return PAGER_NCHitTest (infoPtr, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); - - case WM_MOUSEMOVE: - if (infoPtr->bForward && infoPtr->hwndChild) - PostMessageW(infoPtr->hwndChild, WM_MOUSEMOVE, wParam, lParam); - return PAGER_MouseMove (infoPtr, (INT)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); - - case WM_LBUTTONDOWN: - return PAGER_LButtonDown (infoPtr, (INT)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); - - case WM_LBUTTONUP: - return PAGER_LButtonUp (infoPtr, (INT)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); - - case WM_ERASEBKGND: - return PAGER_EraseBackground (infoPtr, (HDC)wParam); - - case WM_TIMER: - return PAGER_Timer (infoPtr, (INT)wParam); - - case WM_NOTIFY: - case WM_COMMAND: - return SendMessageW (infoPtr->hwndNotify, uMsg, wParam, lParam); - - default: - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - } -} - - -VOID -PAGER_Register (void) -{ - WNDCLASSW wndClass; - - ZeroMemory (&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS; - wndClass.lpfnWndProc = PAGER_WindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(PAGER_INFO *); - wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); - wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); - wndClass.lpszClassName = WC_PAGESCROLLERW; - - RegisterClassW (&wndClass); -} - - -VOID -PAGER_Unregister (void) -{ - UnregisterClassW (WC_PAGESCROLLERW, NULL); -} +/* + * Pager control + * + * Copyright 1998, 1999 Eric Kohl + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES + * + * This code was audited for completeness against the documented features + * of Comctl32.dll version 6.0 on Sep. 18, 2004, by Robert Shearman. + * + * Unless otherwise noted, we believe this code to be complete, as per + * the specification mentioned above. + * If you discover missing features or bugs please note them below. + * + * TODO: + * Implement repetitive button press. + * Adjust arrow size relative to size of button. + * Allow border size changes. + * Styles: + * PGS_DRAGNDROP + * Notifications: + * PGN_HOTITEMCHANGE + * + * TESTING: + * Tested primarily with the controlspy Pager application. + * Susan Farley (susan@codeweavers.com) + * + * IMPLEMENTATION NOTES: + * This control uses WM_NCPAINT instead of WM_PAINT to paint itself + * as we need to scroll a child window. In order to do this we move + * the child window in the control's client area, using the clipping + * region that is automatically set around the client area. As the + * entire client area now consists of the child window, we must + * allocate space (WM_NCCALCSIZE) for the buttons and draw them as + * a non-client area (WM_NCPAINT). + * Robert Shearman + */ + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "windowsx.h" +#include "commctrl.h" +#include "comctl32.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(pager); + +typedef struct +{ + HWND hwndSelf; /* handle of the control wnd */ + HWND hwndChild; /* handle of the contained wnd */ + HWND hwndNotify; /* handle of the parent wnd */ + DWORD dwStyle; /* styles for this control */ + COLORREF clrBk; /* background color */ + INT nBorder; /* border size for the control */ + INT nButtonSize;/* size of the pager btns */ + INT nPos; /* scroll position */ + INT nWidth; /* from child wnd's response to PGN_CALCSIZE */ + INT nHeight; /* from child wnd's response to PGN_CALCSIZE */ + BOOL bForward; /* forward WM_MOUSEMOVE msgs to the contained wnd */ + BOOL bCapture; /* we have captured the mouse */ + INT TLbtnState; /* state of top or left btn */ + INT BRbtnState; /* state of bottom or right btn */ + INT direction; /* direction of the scroll, (e.g. PGF_SCROLLUP) */ +} PAGER_INFO; + +#define MIN_ARROW_WIDTH 8 +#define MIN_ARROW_HEIGHT 5 + +#define TIMERID1 1 +#define TIMERID2 2 +#define INITIAL_DELAY 500 +#define REPEAT_DELAY 50 + +static void +PAGER_GetButtonRects(PAGER_INFO* infoPtr, RECT* prcTopLeft, RECT* prcBottomRight, BOOL bClientCoords) +{ + RECT rcWindow; + GetWindowRect (infoPtr->hwndSelf, &rcWindow); + + if (bClientCoords) + { + POINT pt = {rcWindow.left, rcWindow.top}; + ScreenToClient(infoPtr->hwndSelf, &pt); + OffsetRect(&rcWindow, -(rcWindow.left-pt.x), -(rcWindow.top-pt.y)); + } + else + OffsetRect(&rcWindow, -rcWindow.left, -rcWindow.top); + + *prcTopLeft = *prcBottomRight = rcWindow; + if (infoPtr->dwStyle & PGS_HORZ) + { + prcTopLeft->right = prcTopLeft->left + infoPtr->nButtonSize; + prcBottomRight->left = prcBottomRight->right - infoPtr->nButtonSize; + } + else + { + prcTopLeft->bottom = prcTopLeft->top + infoPtr->nButtonSize; + prcBottomRight->top = prcBottomRight->bottom - infoPtr->nButtonSize; + } +} + +/* the horizontal arrows are: + * + * 01234 01234 + * 1 * * + * 2 ** ** + * 3*** *** + * 4*** *** + * 5 ** ** + * 6 * * + * 7 + * + */ +static void +PAGER_DrawHorzArrow (HDC hdc, RECT r, INT colorRef, BOOL left) +{ + INT x, y, w, h; + HPEN hPen, hOldPen; + + w = r.right - r.left + 1; + h = r.bottom - r.top + 1; + if ((h < MIN_ARROW_WIDTH) || (w < MIN_ARROW_HEIGHT)) + return; /* refuse to draw partial arrow */ + + if (!(hPen = CreatePen( PS_SOLID, 1, GetSysColor( colorRef )))) return; + hOldPen = SelectObject ( hdc, hPen ); + if (left) + { + x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 3; + y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1; + MoveToEx (hdc, x, y, NULL); + LineTo (hdc, x--, y+5); y++; + MoveToEx (hdc, x, y, NULL); + LineTo (hdc, x--, y+3); y++; + MoveToEx (hdc, x, y, NULL); + LineTo (hdc, x, y+1); + } + else + { + x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1; + y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1; + MoveToEx (hdc, x, y, NULL); + LineTo (hdc, x++, y+5); y++; + MoveToEx (hdc, x, y, NULL); + LineTo (hdc, x++, y+3); y++; + MoveToEx (hdc, x, y, NULL); + LineTo (hdc, x, y+1); + } + + SelectObject( hdc, hOldPen ); + DeleteObject( hPen ); +} + +/* the vertical arrows are: + * + * 01234567 01234567 + * 1****** ** + * 2 **** **** + * 3 ** ****** + * 4 + * + */ +static void +PAGER_DrawVertArrow (HDC hdc, RECT r, INT colorRef, BOOL up) +{ + INT x, y, w, h; + HPEN hPen, hOldPen; + + w = r.right - r.left + 1; + h = r.bottom - r.top + 1; + if ((h < MIN_ARROW_WIDTH) || (w < MIN_ARROW_HEIGHT)) + return; /* refuse to draw partial arrow */ + + if (!(hPen = CreatePen( PS_SOLID, 1, GetSysColor( colorRef )))) return; + hOldPen = SelectObject ( hdc, hPen ); + if (up) + { + x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1; + y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 3; + MoveToEx (hdc, x, y, NULL); + LineTo (hdc, x+5, y--); x++; + MoveToEx (hdc, x, y, NULL); + LineTo (hdc, x+3, y--); x++; + MoveToEx (hdc, x, y, NULL); + LineTo (hdc, x+1, y); + } + else + { + x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1; + y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1; + MoveToEx (hdc, x, y, NULL); + LineTo (hdc, x+5, y++); x++; + MoveToEx (hdc, x, y, NULL); + LineTo (hdc, x+3, y++); x++; + MoveToEx (hdc, x, y, NULL); + LineTo (hdc, x+1, y); + } + + SelectObject( hdc, hOldPen ); + DeleteObject( hPen ); +} + +static void +PAGER_DrawButton(HDC hdc, COLORREF clrBk, RECT arrowRect, + BOOL horz, BOOL topLeft, INT btnState) +{ + HBRUSH hBrush, hOldBrush; + RECT rc = arrowRect; + + TRACE("arrowRect = %s, btnState = %d\n", wine_dbgstr_rect(&arrowRect), btnState); + + if (btnState == PGF_INVISIBLE) + return; + + if ((rc.right - rc.left <= 0) || (rc.bottom - rc.top <= 0)) + return; + + hBrush = CreateSolidBrush(clrBk); + hOldBrush = (HBRUSH)SelectObject(hdc, hBrush); + + FillRect(hdc, &rc, hBrush); + + if (btnState == PGF_HOT) + { + DrawEdge( hdc, &rc, BDR_RAISEDINNER, BF_RECT); + if (horz) + PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft); + else + PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft); + } + else if (btnState == PGF_NORMAL) + { + DrawEdge (hdc, &rc, BDR_OUTER, BF_FLAT); + if (horz) + PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft); + else + PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft); + } + else if (btnState == PGF_DEPRESSED) + { + DrawEdge( hdc, &rc, BDR_SUNKENOUTER, BF_RECT); + if (horz) + PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft); + else + PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft); + } + else if (btnState == PGF_GRAYED) + { + DrawEdge (hdc, &rc, BDR_OUTER, BF_FLAT); + if (horz) + { + PAGER_DrawHorzArrow(hdc, rc, COLOR_3DHIGHLIGHT, topLeft); + rc.left++, rc.top++; rc.right++, rc.bottom++; + PAGER_DrawHorzArrow(hdc, rc, COLOR_3DSHADOW, topLeft); + } + else + { + PAGER_DrawVertArrow(hdc, rc, COLOR_3DHIGHLIGHT, topLeft); + rc.left++, rc.top++; rc.right++, rc.bottom++; + PAGER_DrawVertArrow(hdc, rc, COLOR_3DSHADOW, topLeft); + } + } + + SelectObject( hdc, hOldBrush ); + DeleteObject(hBrush); +} + +/* << PAGER_GetDropTarget >> */ + +static inline LRESULT +PAGER_ForwardMouse (PAGER_INFO* infoPtr, BOOL bFwd) +{ + TRACE("[%p]\n", infoPtr->hwndSelf); + + infoPtr->bForward = bFwd; + + return 0; +} + +static inline LRESULT +PAGER_GetButtonState (PAGER_INFO* infoPtr, INT btn) +{ + LRESULT btnState = PGF_INVISIBLE; + TRACE("[%p]\n", infoPtr->hwndSelf); + + if (btn == PGB_TOPORLEFT) + btnState = infoPtr->TLbtnState; + else if (btn == PGB_BOTTOMORRIGHT) + btnState = infoPtr->BRbtnState; + + return btnState; +} + + +static inline INT +PAGER_GetPos(PAGER_INFO *infoPtr) +{ + TRACE("[%p] returns %d\n", infoPtr->hwndSelf, infoPtr->nPos); + return infoPtr->nPos; +} + +static inline INT +PAGER_GetButtonSize(PAGER_INFO *infoPtr) +{ + TRACE("[%p] returns %d\n", infoPtr->hwndSelf, infoPtr->nButtonSize); + return infoPtr->nButtonSize; +} + +static inline INT +PAGER_GetBorder(PAGER_INFO *infoPtr) +{ + TRACE("[%p] returns %d\n", infoPtr->hwndSelf, infoPtr->nBorder); + return infoPtr->nBorder; +} + +static inline COLORREF +PAGER_GetBkColor(PAGER_INFO *infoPtr) +{ + TRACE("[%p] returns %06lx\n", infoPtr->hwndSelf, infoPtr->clrBk); + return infoPtr->clrBk; +} + +static void +PAGER_CalcSize (PAGER_INFO *infoPtr, INT* size, BOOL getWidth) +{ + NMPGCALCSIZE nmpgcs; + ZeroMemory (&nmpgcs, sizeof (NMPGCALCSIZE)); + nmpgcs.hdr.hwndFrom = infoPtr->hwndSelf; + nmpgcs.hdr.idFrom = GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_ID); + nmpgcs.hdr.code = PGN_CALCSIZE; + nmpgcs.dwFlag = getWidth ? PGF_CALCWIDTH : PGF_CALCHEIGHT; + nmpgcs.iWidth = getWidth ? *size : 0; + nmpgcs.iHeight = getWidth ? 0 : *size; + SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, + (WPARAM)nmpgcs.hdr.idFrom, (LPARAM)&nmpgcs); + + *size = getWidth ? nmpgcs.iWidth : nmpgcs.iHeight; + + TRACE("[%p] PGN_CALCSIZE returns %s=%d\n", infoPtr->hwndSelf, + getWidth ? "width" : "height", *size); +} + +static void +PAGER_PositionChildWnd(PAGER_INFO* infoPtr) +{ + if (infoPtr->hwndChild) + { + RECT rcClient; + int nPos = infoPtr->nPos; + + /* compensate for a grayed btn, which will soon become invisible */ + if (infoPtr->TLbtnState == PGF_GRAYED) + nPos += infoPtr->nButtonSize; + + GetClientRect(infoPtr->hwndSelf, &rcClient); + + if (infoPtr->dwStyle & PGS_HORZ) + { + int wndSize = max(0, rcClient.right - rcClient.left); + if (infoPtr->nWidth < wndSize) + infoPtr->nWidth = wndSize; + + TRACE("[%p] SWP %dx%d at (%d,%d)\n", infoPtr->hwndSelf, + infoPtr->nWidth, infoPtr->nHeight, + -nPos, 0); + SetWindowPos(infoPtr->hwndChild, 0, + -nPos, 0, + infoPtr->nWidth, infoPtr->nHeight, + SWP_NOZORDER); + } + else + { + int wndSize = max(0, rcClient.bottom - rcClient.top); + if (infoPtr->nHeight < wndSize) + infoPtr->nHeight = wndSize; + + TRACE("[%p] SWP %dx%d at (%d,%d)\n", infoPtr->hwndSelf, + infoPtr->nWidth, infoPtr->nHeight, + 0, -nPos); + SetWindowPos(infoPtr->hwndChild, 0, + 0, -nPos, + infoPtr->nWidth, infoPtr->nHeight, + SWP_NOZORDER); + } + + InvalidateRect(infoPtr->hwndChild, NULL, TRUE); + } +} + +static INT +PAGER_GetScrollRange(PAGER_INFO* infoPtr) +{ + INT scrollRange = 0; + + if (infoPtr->hwndChild) + { + INT wndSize, childSize; + RECT wndRect; + GetWindowRect(infoPtr->hwndSelf, &wndRect); + + if (infoPtr->dwStyle & PGS_HORZ) + { + wndSize = wndRect.right - wndRect.left; + PAGER_CalcSize(infoPtr, &infoPtr->nWidth, TRUE); + childSize = infoPtr->nWidth; + } + else + { + wndSize = wndRect.bottom - wndRect.top; + PAGER_CalcSize(infoPtr, &infoPtr->nHeight, FALSE); + childSize = infoPtr->nHeight; + } + + TRACE("childSize = %d, wndSize = %d\n", childSize, wndSize); + if (childSize > wndSize) + scrollRange = childSize - wndSize + infoPtr->nButtonSize; + } + + TRACE("[%p] returns %d\n", infoPtr->hwndSelf, scrollRange); + return scrollRange; +} + +static void +PAGER_UpdateBtns(PAGER_INFO *infoPtr, INT scrollRange, BOOL hideGrayBtns) +{ + BOOL resizeClient; + BOOL repaintBtns; + INT oldTLbtnState = infoPtr->TLbtnState; + INT oldBRbtnState = infoPtr->BRbtnState; + POINT pt; + RECT rcTopLeft, rcBottomRight; + + /* get button rects */ + PAGER_GetButtonRects(infoPtr, &rcTopLeft, &rcBottomRight, FALSE); + + GetCursorPos(&pt); + + /* update states based on scroll position */ + if (infoPtr->nPos > 0) + { + if (infoPtr->TLbtnState == PGF_INVISIBLE || infoPtr->TLbtnState == PGF_GRAYED) + infoPtr->TLbtnState = PGF_NORMAL; + } + else if (PtInRect(&rcTopLeft, pt)) + infoPtr->TLbtnState = PGF_GRAYED; + else + infoPtr->TLbtnState = PGF_INVISIBLE; + + if (scrollRange <= 0) + { + infoPtr->TLbtnState = PGF_INVISIBLE; + infoPtr->BRbtnState = PGF_INVISIBLE; + } + else if (infoPtr->nPos < scrollRange) + { + if (infoPtr->BRbtnState == PGF_INVISIBLE || infoPtr->BRbtnState == PGF_GRAYED) + infoPtr->BRbtnState = PGF_NORMAL; + } + else if (PtInRect(&rcBottomRight, pt)) + infoPtr->BRbtnState = PGF_GRAYED; + else + infoPtr->BRbtnState = PGF_INVISIBLE; + + /* only need to resize when entering or leaving PGF_INVISIBLE state */ + resizeClient = + ((oldTLbtnState == PGF_INVISIBLE) != (infoPtr->TLbtnState == PGF_INVISIBLE)) || + ((oldBRbtnState == PGF_INVISIBLE) != (infoPtr->BRbtnState == PGF_INVISIBLE)); + /* initiate NCCalcSize to resize client wnd if necessary */ + if (resizeClient) + SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0, + SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | + SWP_NOZORDER | SWP_NOACTIVATE); + + /* repaint when changing any state */ + repaintBtns = (oldTLbtnState != infoPtr->TLbtnState) || + (oldBRbtnState != infoPtr->BRbtnState); + if (repaintBtns) + SendMessageW(infoPtr->hwndSelf, WM_NCPAINT, 0, 0); +} + +static LRESULT +PAGER_SetPos(PAGER_INFO* infoPtr, INT newPos, BOOL fromBtnPress) +{ + INT scrollRange = PAGER_GetScrollRange(infoPtr); + INT oldPos = infoPtr->nPos; + + if ((scrollRange <= 0) || (newPos < 0)) + infoPtr->nPos = 0; + else if (newPos > scrollRange) + infoPtr->nPos = scrollRange; + else + infoPtr->nPos = newPos; + + TRACE("[%p] pos=%d, oldpos=%d\n", infoPtr->hwndSelf, infoPtr->nPos, oldPos); + + if (infoPtr->nPos != oldPos) + { + /* gray and restore btns, and if from WM_SETPOS, hide the gray btns */ + PAGER_UpdateBtns(infoPtr, scrollRange, !fromBtnPress); + PAGER_PositionChildWnd(infoPtr); + } + + return 0; +} + +static LRESULT +PAGER_WindowPosChanging(PAGER_INFO* infoPtr, WINDOWPOS *winpos) +{ + if ((infoPtr->dwStyle & CCS_NORESIZE) && !(winpos->flags & SWP_NOSIZE)) + { + /* don't let the app resize the nonscrollable dimension of a control + * that was created with CCS_NORESIZE style + * (i.e. height for a horizontal pager, or width for a vertical one) */ + + /* except if the current dimension is 0 and app is setting for + * first time, then save amount as dimension. - GA 8/01 */ + + if (infoPtr->dwStyle & PGS_HORZ) + if (!infoPtr->nHeight && winpos->cy) + infoPtr->nHeight = winpos->cy; + else + winpos->cy = infoPtr->nHeight; + else + if (!infoPtr->nWidth && winpos->cx) + infoPtr->nWidth = winpos->cx; + else + winpos->cx = infoPtr->nWidth; + return 0; + } + + return DefWindowProcW (infoPtr->hwndSelf, WM_WINDOWPOSCHANGING, 0, (LPARAM)winpos); +} + +static INT +PAGER_SetFixedWidth(PAGER_INFO* infoPtr) +{ + /* Must set the non-scrollable dimension to be less than the full height/width + * so that NCCalcSize is called. The Msoft docs mention 3/4 factor for button + * size, and experimentation shows that affect is almost right. */ + + RECT wndRect; + INT delta, h; + GetWindowRect(infoPtr->hwndSelf, &wndRect); + + /* see what the app says for btn width */ + PAGER_CalcSize(infoPtr, &infoPtr->nWidth, TRUE); + + if (infoPtr->dwStyle & CCS_NORESIZE) + { + delta = wndRect.right - wndRect.left - infoPtr->nWidth; + if (delta > infoPtr->nButtonSize) + infoPtr->nWidth += 4 * infoPtr->nButtonSize / 3; + else if (delta > 0) + infoPtr->nWidth += infoPtr->nButtonSize / 3; + } + + h = wndRect.bottom - wndRect.top + infoPtr->nButtonSize; + + TRACE("[%p] infoPtr->nWidth set to %d\n", + infoPtr->hwndSelf, infoPtr->nWidth); + + return h; +} + +static INT +PAGER_SetFixedHeight(PAGER_INFO* infoPtr) +{ + /* Must set the non-scrollable dimension to be less than the full height/width + * so that NCCalcSize is called. The Msoft docs mention 3/4 factor for button + * size, and experimentation shows that affect is almost right. */ + + RECT wndRect; + INT delta, w; + GetWindowRect(infoPtr->hwndSelf, &wndRect); + + /* see what the app says for btn height */ + PAGER_CalcSize(infoPtr, &infoPtr->nHeight, FALSE); + + if (infoPtr->dwStyle & CCS_NORESIZE) + { + delta = wndRect.bottom - wndRect.top - infoPtr->nHeight; + if (delta > infoPtr->nButtonSize) + infoPtr->nHeight += infoPtr->nButtonSize; + else if (delta > 0) + infoPtr->nHeight += infoPtr->nButtonSize / 3; + } + + w = wndRect.right - wndRect.left + infoPtr->nButtonSize; + + TRACE("[%p] infoPtr->nHeight set to %d\n", + infoPtr->hwndSelf, infoPtr->nHeight); + + return w; +} + +/****************************************************************** + * For the PGM_RECALCSIZE message (but not the other uses in * + * this module), the native control does only the following: * + * * + * if (some condition) * + * PostMessageW(hwnd, EM_FMTLINES, 0, 0); * + * return DefWindowProcW(hwnd, PGM_RECALCSIZE, 0, 0); * + * * + * When we figure out what the "some condition" is we will * + * implement that for the message processing. * + ******************************************************************/ + +static LRESULT +PAGER_RecalcSize(PAGER_INFO *infoPtr) +{ + TRACE("[%p]\n", infoPtr->hwndSelf); + + if (infoPtr->hwndChild) + { + INT scrollRange = PAGER_GetScrollRange(infoPtr); + + if (scrollRange <= 0) + { + infoPtr->nPos = -1; + PAGER_SetPos(infoPtr, 0, FALSE); + } + else + PAGER_PositionChildWnd(infoPtr); + } + + return 1; +} + + +static COLORREF +PAGER_SetBkColor (PAGER_INFO* infoPtr, COLORREF clrBk) +{ + COLORREF clrTemp = infoPtr->clrBk; + + infoPtr->clrBk = clrBk; + TRACE("[%p] %06lx\n", infoPtr->hwndSelf, infoPtr->clrBk); + + /* the native control seems to do things this way */ + SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0, + SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | + SWP_NOZORDER | SWP_NOACTIVATE); + + RedrawWindow(infoPtr->hwndSelf, 0, 0, RDW_ERASE | RDW_INVALIDATE); + + return clrTemp; +} + + +static INT +PAGER_SetBorder (PAGER_INFO* infoPtr, INT iBorder) +{ + INT nTemp = infoPtr->nBorder; + + infoPtr->nBorder = iBorder; + TRACE("[%p] %d\n", infoPtr->hwndSelf, infoPtr->nBorder); + + PAGER_RecalcSize(infoPtr); + + return nTemp; +} + + +static INT +PAGER_SetButtonSize (PAGER_INFO* infoPtr, INT iButtonSize) +{ + INT nTemp = infoPtr->nButtonSize; + + infoPtr->nButtonSize = iButtonSize; + TRACE("[%p] %d\n", infoPtr->hwndSelf, infoPtr->nButtonSize); + + PAGER_RecalcSize(infoPtr); + + return nTemp; +} + + +static LRESULT +PAGER_SetChild (PAGER_INFO* infoPtr, HWND hwndChild) +{ + INT hw; + + infoPtr->hwndChild = IsWindow (hwndChild) ? hwndChild : 0; + + if (infoPtr->hwndChild) + { + TRACE("[%p] hwndChild=%p\n", infoPtr->hwndSelf, infoPtr->hwndChild); + + if (infoPtr->dwStyle & PGS_HORZ) { + hw = PAGER_SetFixedHeight(infoPtr); + /* adjust non-scrollable dimension to fit the child */ + SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, hw, infoPtr->nHeight, + SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER | + SWP_NOSIZE | SWP_NOACTIVATE); + } + else { + hw = PAGER_SetFixedWidth(infoPtr); + /* adjust non-scrollable dimension to fit the child */ + SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, infoPtr->nWidth, hw, + SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER | + SWP_NOSIZE | SWP_NOACTIVATE); + } + + /* position child within the page scroller */ + SetWindowPos(infoPtr->hwndChild, HWND_TOP, + 0,0,0,0, + SWP_SHOWWINDOW | SWP_NOSIZE); /* native is 0 */ + + infoPtr->nPos = -1; + PAGER_SetPos(infoPtr, 0, FALSE); + } + + return 0; +} + +static void +PAGER_Scroll(PAGER_INFO* infoPtr, INT dir) +{ + NMPGSCROLL nmpgScroll; + RECT rcWnd; + + if (infoPtr->hwndChild) + { + ZeroMemory (&nmpgScroll, sizeof (NMPGSCROLL)); + nmpgScroll.hdr.hwndFrom = infoPtr->hwndSelf; + nmpgScroll.hdr.idFrom = GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_ID); + nmpgScroll.hdr.code = PGN_SCROLL; + + GetWindowRect(infoPtr->hwndSelf, &rcWnd); + GetClientRect(infoPtr->hwndSelf, &nmpgScroll.rcParent); + nmpgScroll.iXpos = nmpgScroll.iYpos = 0; + nmpgScroll.iDir = dir; + + if (infoPtr->dwStyle & PGS_HORZ) + { + nmpgScroll.iScroll = rcWnd.right - rcWnd.left; + nmpgScroll.iXpos = infoPtr->nPos; + } + else + { + nmpgScroll.iScroll = rcWnd.bottom - rcWnd.top; + nmpgScroll.iYpos = infoPtr->nPos; + } + nmpgScroll.iScroll -= 2*infoPtr->nButtonSize; + + SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, + (WPARAM)nmpgScroll.hdr.idFrom, (LPARAM)&nmpgScroll); + + TRACE("[%p] PGN_SCROLL returns iScroll=%d\n", infoPtr->hwndSelf, nmpgScroll.iScroll); + + if (nmpgScroll.iScroll > 0) + { + infoPtr->direction = dir; + + if (dir == PGF_SCROLLLEFT || dir == PGF_SCROLLUP) + PAGER_SetPos(infoPtr, infoPtr->nPos - nmpgScroll.iScroll, TRUE); + else + PAGER_SetPos(infoPtr, infoPtr->nPos + nmpgScroll.iScroll, TRUE); + } + else + infoPtr->direction = -1; + } +} + +static LRESULT +PAGER_FmtLines(PAGER_INFO *infoPtr) +{ + /* initiate NCCalcSize to resize client wnd and get size */ + SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0, + SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | + SWP_NOZORDER | SWP_NOACTIVATE); + + SetWindowPos(infoPtr->hwndChild, 0, + 0,0,infoPtr->nWidth,infoPtr->nHeight, + 0); + + return DefWindowProcW (infoPtr->hwndSelf, EM_FMTLINES, 0, 0); +} + +static LRESULT +PAGER_Create (HWND hwnd, LPCREATESTRUCTW lpcs) +{ + PAGER_INFO *infoPtr; + + /* allocate memory for info structure */ + infoPtr = (PAGER_INFO *)Alloc (sizeof(PAGER_INFO)); + if (!infoPtr) return -1; + SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); + + /* set default settings */ + infoPtr->hwndSelf = hwnd; + infoPtr->hwndChild = NULL; + infoPtr->hwndNotify = lpcs->hwndParent; + infoPtr->dwStyle = lpcs->style; + infoPtr->clrBk = GetSysColor(COLOR_BTNFACE); + infoPtr->nBorder = 0; + infoPtr->nButtonSize = 12; + infoPtr->nPos = 0; + infoPtr->nWidth = 0; + infoPtr->nHeight = 0; + infoPtr->bForward = FALSE; + infoPtr->bCapture = FALSE; + infoPtr->TLbtnState = PGF_INVISIBLE; + infoPtr->BRbtnState = PGF_INVISIBLE; + infoPtr->direction = -1; + + if (infoPtr->dwStyle & PGS_DRAGNDROP) + FIXME("[%p] Drag and Drop style is not implemented yet.\n", infoPtr->hwndSelf); + + return 0; +} + + +static LRESULT +PAGER_Destroy (PAGER_INFO *infoPtr) +{ + SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0); + Free (infoPtr); /* free pager info data */ + return 0; +} + +static LRESULT +PAGER_NCCalcSize(PAGER_INFO* infoPtr, WPARAM wParam, LPRECT lpRect) +{ + RECT rcChild, rcWindow; + INT scrollRange; + + /* + * lpRect points to a RECT struct. On entry, the struct + * contains the proposed wnd rectangle for the window. + * On exit, the struct should contain the screen + * coordinates of the corresponding window's client area. + */ + + DefWindowProcW (infoPtr->hwndSelf, WM_NCCALCSIZE, wParam, (LPARAM)lpRect); + + TRACE("orig rect=%s\n", wine_dbgstr_rect(lpRect)); + + GetWindowRect (infoPtr->hwndChild, &rcChild); + MapWindowPoints (0, infoPtr->hwndSelf, (LPPOINT)&rcChild, 2); /* FIXME: RECT != 2 POINTS */ + GetWindowRect (infoPtr->hwndSelf, &rcWindow); + + if (infoPtr->dwStyle & PGS_HORZ) + { + infoPtr->nWidth = lpRect->right - lpRect->left; + PAGER_CalcSize (infoPtr, &infoPtr->nWidth, TRUE); + + scrollRange = infoPtr->nWidth - (rcWindow.right - rcWindow.left); + + if (infoPtr->TLbtnState && (lpRect->left + infoPtr->nButtonSize < lpRect->right)) + lpRect->left += infoPtr->nButtonSize; + if (infoPtr->BRbtnState && (lpRect->right - infoPtr->nButtonSize > lpRect->left)) + lpRect->right -= infoPtr->nButtonSize; + } + else + { + infoPtr->nHeight = lpRect->bottom - lpRect->top; + PAGER_CalcSize (infoPtr, &infoPtr->nHeight, FALSE); + + scrollRange = infoPtr->nHeight - (rcWindow.bottom - rcWindow.top); + + if (infoPtr->TLbtnState && (lpRect->top + infoPtr->nButtonSize < lpRect->bottom)) + lpRect->top += infoPtr->nButtonSize; + if (infoPtr->BRbtnState && (lpRect->bottom - infoPtr->nButtonSize > lpRect->top)) + lpRect->bottom -= infoPtr->nButtonSize; + } + + TRACE("nPos=%d, nHeigth=%d, window=%s\n", + infoPtr->nPos, infoPtr->nHeight, + wine_dbgstr_rect(&rcWindow)); + + TRACE("[%p] client rect set to %ldx%ld at (%ld,%ld) BtnState[%d,%d]\n", + infoPtr->hwndSelf, lpRect->right-lpRect->left, lpRect->bottom-lpRect->top, + lpRect->left, lpRect->top, + infoPtr->TLbtnState, infoPtr->BRbtnState); + + return 0; +} + +static LRESULT +PAGER_NCPaint (PAGER_INFO* infoPtr, HRGN hRgn) +{ + RECT rcBottomRight, rcTopLeft; + HDC hdc; + + if (infoPtr->dwStyle & WS_MINIMIZE) + return 0; + + DefWindowProcW (infoPtr->hwndSelf, WM_NCPAINT, (WPARAM)hRgn, 0); + + if (!(hdc = GetDCEx (infoPtr->hwndSelf, 0, DCX_USESTYLE | DCX_WINDOW))) + return 0; + + PAGER_GetButtonRects(infoPtr, &rcTopLeft, &rcBottomRight, FALSE); + + PAGER_DrawButton(hdc, infoPtr->clrBk, rcTopLeft, + infoPtr->dwStyle & PGS_HORZ, TRUE, infoPtr->TLbtnState); + PAGER_DrawButton(hdc, infoPtr->clrBk, rcBottomRight, + infoPtr->dwStyle & PGS_HORZ, FALSE, infoPtr->BRbtnState); + + ReleaseDC( infoPtr->hwndSelf, hdc ); + return 0; +} + +static INT +PAGER_HitTest (PAGER_INFO* infoPtr, const POINT * pt) +{ + RECT clientRect, rcTopLeft, rcBottomRight; + POINT ptWindow; + + GetClientRect (infoPtr->hwndSelf, &clientRect); + + if (PtInRect(&clientRect, *pt)) + { + TRACE("child\n"); + return -1; + } + + ptWindow = *pt; + PAGER_GetButtonRects(infoPtr, &rcTopLeft, &rcBottomRight, TRUE); + + if ((infoPtr->TLbtnState != PGF_INVISIBLE) && PtInRect(&rcTopLeft, ptWindow)) + { + TRACE("PGB_TOPORLEFT\n"); + return PGB_TOPORLEFT; + } + else if ((infoPtr->BRbtnState != PGF_INVISIBLE) && PtInRect(&rcBottomRight, ptWindow)) + { + TRACE("PGB_BOTTOMORRIGHT\n"); + return PGB_BOTTOMORRIGHT; + } + + TRACE("nowhere\n"); + return -1; +} + +static LRESULT +PAGER_NCHitTest (PAGER_INFO* infoPtr, INT x, INT y) +{ + POINT pt; + INT nHit; + + pt.x = x; + pt.y = y; + + ScreenToClient (infoPtr->hwndSelf, &pt); + nHit = PAGER_HitTest(infoPtr, &pt); + + return (nHit < 0) ? HTTRANSPARENT : HTCLIENT; +} + +static LRESULT +PAGER_MouseMove (PAGER_INFO* infoPtr, INT keys, INT x, INT y) +{ + POINT clpt, pt; + RECT wnrect, *btnrect = NULL; + BOOL topLeft = FALSE; + INT btnstate = 0; + INT hit; + HDC hdc; + + pt.x = x; + pt.y = y; + + TRACE("[%p] to (%d,%d)\n", infoPtr->hwndSelf, x, y); + ClientToScreen(infoPtr->hwndSelf, &pt); + GetWindowRect(infoPtr->hwndSelf, &wnrect); + if (PtInRect(&wnrect, pt)) { + RECT TLbtnrect, BRbtnrect; + PAGER_GetButtonRects(infoPtr, &TLbtnrect, &BRbtnrect, FALSE); + + clpt = pt; + MapWindowPoints(0, infoPtr->hwndSelf, &clpt, 1); + hit = PAGER_HitTest(infoPtr, &clpt); + if ((hit == PGB_TOPORLEFT) && (infoPtr->TLbtnState == PGF_NORMAL)) + { + topLeft = TRUE; + btnrect = &TLbtnrect; + infoPtr->TLbtnState = PGF_HOT; + btnstate = infoPtr->TLbtnState; + } + else if ((hit == PGB_BOTTOMORRIGHT) && (infoPtr->BRbtnState == PGF_NORMAL)) + { + topLeft = FALSE; + btnrect = &BRbtnrect; + infoPtr->BRbtnState = PGF_HOT; + btnstate = infoPtr->BRbtnState; + } + + /* If in one of the buttons the capture and draw buttons */ + if (btnrect) + { + TRACE("[%p] draw btn (%ld,%ld)-(%ld,%ld), Capture %s, style %08lx\n", + infoPtr->hwndSelf, btnrect->left, btnrect->top, + btnrect->right, btnrect->bottom, + (infoPtr->bCapture) ? "TRUE" : "FALSE", + infoPtr->dwStyle); + if (!infoPtr->bCapture) + { + TRACE("[%p] SetCapture\n", infoPtr->hwndSelf); + SetCapture(infoPtr->hwndSelf); + infoPtr->bCapture = TRUE; + } + if (infoPtr->dwStyle & PGS_AUTOSCROLL) + SetTimer(infoPtr->hwndSelf, TIMERID1, 0x3e, 0); + hdc = GetWindowDC(infoPtr->hwndSelf); + /* OffsetRect(wnrect, 0 | 1, 0 | 1) */ + PAGER_DrawButton(hdc, infoPtr->clrBk, *btnrect, + infoPtr->dwStyle & PGS_HORZ, topLeft, btnstate); + ReleaseDC(infoPtr->hwndSelf, hdc); + return 0; + } + } + + /* If we think we are captured, then do release */ + if (infoPtr->bCapture && (WindowFromPoint(pt) != infoPtr->hwndSelf)) + { + NMHDR nmhdr; + + infoPtr->bCapture = FALSE; + + if (GetCapture() == infoPtr->hwndSelf) + { + ReleaseCapture(); + + if (infoPtr->TLbtnState == PGF_GRAYED) + { + infoPtr->TLbtnState = PGF_INVISIBLE; + SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0, + SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | + SWP_NOZORDER | SWP_NOACTIVATE); + } + else if (infoPtr->TLbtnState == PGF_HOT) + { + infoPtr->TLbtnState = PGF_NORMAL; + /* FIXME: just invalidate button rect */ + RedrawWindow(infoPtr->hwndSelf, NULL, NULL, RDW_FRAME | RDW_INVALIDATE); + } + + if (infoPtr->BRbtnState == PGF_GRAYED) + { + infoPtr->BRbtnState = PGF_INVISIBLE; + SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0, + SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | + SWP_NOZORDER | SWP_NOACTIVATE); + } + else if (infoPtr->BRbtnState == PGF_HOT) + { + infoPtr->BRbtnState = PGF_NORMAL; + /* FIXME: just invalidate button rect */ + RedrawWindow(infoPtr->hwndSelf, NULL, NULL, RDW_FRAME | RDW_INVALIDATE); + } + + /* Notify parent of released mouse capture */ + memset(&nmhdr, 0, sizeof(NMHDR)); + nmhdr.hwndFrom = infoPtr->hwndSelf; + nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); + nmhdr.code = NM_RELEASEDCAPTURE; + SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, + (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr); + } + if (IsWindow(infoPtr->hwndSelf)) + KillTimer(infoPtr->hwndSelf, TIMERID1); + } + return 0; +} + +static LRESULT +PAGER_LButtonDown (PAGER_INFO* infoPtr, INT keys, INT x, INT y) +{ + BOOL repaintBtns = FALSE; + POINT pt; + INT hit; + + pt.x = x; + pt.y = y; + + TRACE("[%p] at (%d,%d)\n", infoPtr->hwndSelf, x, y); + + hit = PAGER_HitTest(infoPtr, &pt); + + /* put btn in DEPRESSED state */ + if (hit == PGB_TOPORLEFT) + { + repaintBtns = infoPtr->TLbtnState != PGF_DEPRESSED; + infoPtr->TLbtnState = PGF_DEPRESSED; + SetTimer(infoPtr->hwndSelf, TIMERID1, INITIAL_DELAY, 0); + } + else if (hit == PGB_BOTTOMORRIGHT) + { + repaintBtns = infoPtr->BRbtnState != PGF_DEPRESSED; + infoPtr->BRbtnState = PGF_DEPRESSED; + SetTimer(infoPtr->hwndSelf, TIMERID1, INITIAL_DELAY, 0); + } + + if (repaintBtns) + SendMessageW(infoPtr->hwndSelf, WM_NCPAINT, 0, 0); + + switch(hit) + { + case PGB_TOPORLEFT: + if (infoPtr->dwStyle & PGS_HORZ) + { + TRACE("[%p] PGF_SCROLLLEFT\n", infoPtr->hwndSelf); + PAGER_Scroll(infoPtr, PGF_SCROLLLEFT); + } + else + { + TRACE("[%p] PGF_SCROLLUP\n", infoPtr->hwndSelf); + PAGER_Scroll(infoPtr, PGF_SCROLLUP); + } + break; + case PGB_BOTTOMORRIGHT: + if (infoPtr->dwStyle & PGS_HORZ) + { + TRACE("[%p] PGF_SCROLLRIGHT\n", infoPtr->hwndSelf); + PAGER_Scroll(infoPtr, PGF_SCROLLRIGHT); + } + else + { + TRACE("[%p] PGF_SCROLLDOWN\n", infoPtr->hwndSelf); + PAGER_Scroll(infoPtr, PGF_SCROLLDOWN); + } + break; + default: + break; + } + + return 0; +} + +static LRESULT +PAGER_LButtonUp (PAGER_INFO* infoPtr, INT keys, INT x, INT y) +{ + TRACE("[%p]\n", infoPtr->hwndSelf); + + KillTimer (infoPtr->hwndSelf, TIMERID1); + KillTimer (infoPtr->hwndSelf, TIMERID2); + + /* make PRESSED btns NORMAL but don't hide gray btns */ + if (infoPtr->TLbtnState & (PGF_HOT | PGF_DEPRESSED)) + infoPtr->TLbtnState = PGF_NORMAL; + if (infoPtr->BRbtnState & (PGF_HOT | PGF_DEPRESSED)) + infoPtr->BRbtnState = PGF_NORMAL; + + return 0; +} + +static LRESULT +PAGER_Timer (PAGER_INFO* infoPtr, INT nTimerId) +{ + INT dir; + + /* if initial timer, kill it and start the repeat timer */ + if (nTimerId == TIMERID1) { + if (infoPtr->TLbtnState == PGF_HOT) + dir = (infoPtr->dwStyle & PGS_HORZ) ? + PGF_SCROLLLEFT : PGF_SCROLLUP; + else + dir = (infoPtr->dwStyle & PGS_HORZ) ? + PGF_SCROLLRIGHT : PGF_SCROLLDOWN; + TRACE("[%p] TIMERID1: style=%08lx, dir=%d\n", + infoPtr->hwndSelf, infoPtr->dwStyle, dir); + KillTimer(infoPtr->hwndSelf, TIMERID1); + SetTimer(infoPtr->hwndSelf, TIMERID1, REPEAT_DELAY, 0); + if (infoPtr->dwStyle & PGS_AUTOSCROLL) { + PAGER_Scroll(infoPtr, dir); + SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0, + SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | + SWP_NOZORDER | SWP_NOACTIVATE); + } + return 0; + + } + + TRACE("[%p] TIMERID2: dir=%d\n", infoPtr->hwndSelf, infoPtr->direction); + KillTimer(infoPtr->hwndSelf, TIMERID2); + if (infoPtr->direction > 0) { + PAGER_Scroll(infoPtr, infoPtr->direction); + SetTimer(infoPtr->hwndSelf, TIMERID2, REPEAT_DELAY, 0); + } + return 0; +} + +static LRESULT +PAGER_EraseBackground (PAGER_INFO* infoPtr, HDC hdc) +{ + POINT pt, ptorig; + HWND parent; + + pt.x = 0; + pt.y = 0; + parent = GetParent(infoPtr->hwndSelf); + MapWindowPoints(infoPtr->hwndSelf, parent, &pt, 1); + OffsetWindowOrgEx (hdc, pt.x, pt.y, &ptorig); + SendMessageW (parent, WM_ERASEBKGND, (WPARAM)hdc, 0); + SetWindowOrgEx (hdc, ptorig.x, ptorig.y, 0); + + return 0; +} + + +static LRESULT +PAGER_Size (PAGER_INFO* infoPtr, INT type, INT x, INT y) +{ + /* note that WM_SIZE is sent whenever NCCalcSize resizes the client wnd */ + + TRACE("[%p] %d,%d\n", infoPtr->hwndSelf, x, y); + + if (infoPtr->dwStyle & PGS_HORZ) + infoPtr->nHeight = y; + else + infoPtr->nWidth = x; + + return PAGER_RecalcSize(infoPtr); +} + + +static LRESULT +PAGER_StyleChanged(PAGER_INFO *infoPtr, WPARAM wStyleType, LPSTYLESTRUCT lpss) +{ + DWORD oldStyle = infoPtr->dwStyle; + + TRACE("(styletype=%x, styleOld=0x%08lx, styleNew=0x%08lx)\n", + wStyleType, lpss->styleOld, lpss->styleNew); + + if (wStyleType != GWL_STYLE) return 0; + + infoPtr->dwStyle = lpss->styleNew; + + if ((oldStyle ^ lpss->styleNew) & (PGS_HORZ | PGS_VERT)) + { + PAGER_RecalcSize(infoPtr); + } + + return 0; +} + +static LRESULT WINAPI +PAGER_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + PAGER_INFO *infoPtr = (PAGER_INFO *)GetWindowLongPtrW(hwnd, 0); + + if (!infoPtr && (uMsg != WM_CREATE)) + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + + switch (uMsg) + { + case EM_FMTLINES: + return PAGER_FmtLines(infoPtr); + + case PGM_FORWARDMOUSE: + return PAGER_ForwardMouse (infoPtr, (BOOL)wParam); + + case PGM_GETBKCOLOR: + return PAGER_GetBkColor(infoPtr); + + case PGM_GETBORDER: + return PAGER_GetBorder(infoPtr); + + case PGM_GETBUTTONSIZE: + return PAGER_GetButtonSize(infoPtr); + + case PGM_GETPOS: + return PAGER_GetPos(infoPtr); + + case PGM_GETBUTTONSTATE: + return PAGER_GetButtonState (infoPtr, (INT)lParam); + +/* case PGM_GETDROPTARGET: */ + + case PGM_RECALCSIZE: + return PAGER_RecalcSize(infoPtr); + + case PGM_SETBKCOLOR: + return PAGER_SetBkColor (infoPtr, (COLORREF)lParam); + + case PGM_SETBORDER: + return PAGER_SetBorder (infoPtr, (INT)lParam); + + case PGM_SETBUTTONSIZE: + return PAGER_SetButtonSize (infoPtr, (INT)lParam); + + case PGM_SETCHILD: + return PAGER_SetChild (infoPtr, (HWND)lParam); + + case PGM_SETPOS: + return PAGER_SetPos(infoPtr, (INT)lParam, FALSE); + + case WM_CREATE: + return PAGER_Create (hwnd, (LPCREATESTRUCTW)lParam); + + case WM_DESTROY: + return PAGER_Destroy (infoPtr); + + case WM_SIZE: + return PAGER_Size (infoPtr, (INT)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + + case WM_NCPAINT: + return PAGER_NCPaint (infoPtr, (HRGN)wParam); + + case WM_WINDOWPOSCHANGING: + return PAGER_WindowPosChanging (infoPtr, (WINDOWPOS*)lParam); + + case WM_STYLECHANGED: + return PAGER_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam); + + case WM_NCCALCSIZE: + return PAGER_NCCalcSize (infoPtr, wParam, (LPRECT)lParam); + + case WM_NCHITTEST: + return PAGER_NCHitTest (infoPtr, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + + case WM_MOUSEMOVE: + if (infoPtr->bForward && infoPtr->hwndChild) + PostMessageW(infoPtr->hwndChild, WM_MOUSEMOVE, wParam, lParam); + return PAGER_MouseMove (infoPtr, (INT)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + + case WM_LBUTTONDOWN: + return PAGER_LButtonDown (infoPtr, (INT)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + + case WM_LBUTTONUP: + return PAGER_LButtonUp (infoPtr, (INT)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); + + case WM_ERASEBKGND: + return PAGER_EraseBackground (infoPtr, (HDC)wParam); + + case WM_TIMER: + return PAGER_Timer (infoPtr, (INT)wParam); + + case WM_NOTIFY: + case WM_COMMAND: + return SendMessageW (infoPtr->hwndNotify, uMsg, wParam, lParam); + + default: + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + } +} + + +VOID +PAGER_Register (void) +{ + WNDCLASSW wndClass; + + ZeroMemory (&wndClass, sizeof(WNDCLASSW)); + wndClass.style = CS_GLOBALCLASS; + wndClass.lpfnWndProc = PAGER_WindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(PAGER_INFO *); + wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); + wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); + wndClass.lpszClassName = WC_PAGESCROLLERW; + + RegisterClassW (&wndClass); +} + + +VOID +PAGER_Unregister (void) +{ + UnregisterClassW (WC_PAGESCROLLERW, NULL); +} diff --git a/reactos/lib/comctl32/progress.c b/reactos/lib/comctl32/progress.c index ad2c01b35ce..72cc2516a4f 100644 --- a/reactos/lib/comctl32/progress.c +++ b/reactos/lib/comctl32/progress.c @@ -1,681 +1,681 @@ -/* - * Progress control - * - * Copyright 1997, 2002 Dimitrie O. Paun - * Copyright 1998, 1999 Eric Kohl - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTE - * - * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on Sep. 9, 2002, by Dimitrie O. Paun. - * - * Unless otherwise noted, we believe this code to be complete, as per - * the specification mentioned above. - * If you discover missing features, or bugs, please note them below. - * - */ - -#include -#include -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "comctl32.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(progress); - -typedef struct -{ - HWND Self; /* The window handle for this control */ - INT CurVal; /* Current progress value */ - INT MinVal; /* Minimum progress value */ - INT MaxVal; /* Maximum progress value */ - INT Step; /* Step to use on PMB_STEPIT */ - INT MarqueePos; /* Marquee animation position */ - BOOL Marquee; /* Whether the marquee animation is enabled */ - COLORREF ColorBar; /* Bar color */ - COLORREF ColorBk; /* Background color */ - HFONT Font; /* Handle to font (not unused) */ -} PROGRESS_INFO; - -/* Control configuration constants */ - -#define LED_GAP 2 -#define MARQUEE_LEDS 5 -#define ID_MARQUEE_TIMER 1 - -/*********************************************************************** - * PROGRESS_Invalidate - * - * Invalide the range between old and new pos. - */ -static void PROGRESS_Invalidate( PROGRESS_INFO *infoPtr, INT old, INT new ) -{ - LONG style = GetWindowLongW (infoPtr->Self, GWL_STYLE); - RECT rect; - int oldPos, newPos, ledWidth; - - GetClientRect (infoPtr->Self, &rect); - InflateRect(&rect, -1, -1); - - if (style & PBS_VERTICAL) - { - oldPos = rect.bottom - MulDiv (old - infoPtr->MinVal, rect.bottom - rect.top, - infoPtr->MaxVal - infoPtr->MinVal); - newPos = rect.bottom - MulDiv (new - infoPtr->MinVal, rect.bottom - rect.top, - infoPtr->MaxVal - infoPtr->MinVal); - ledWidth = MulDiv (rect.right - rect.left, 2, 3); - rect.top = min( oldPos, newPos ); - rect.bottom = max( oldPos, newPos ); - if (!(style & PBS_SMOOTH)) rect.top -= ledWidth; - InvalidateRect( infoPtr->Self, &rect, oldPos < newPos ); - } - else - { - oldPos = rect.left + MulDiv (old - infoPtr->MinVal, rect.right - rect.left, - infoPtr->MaxVal - infoPtr->MinVal); - newPos = rect.left + MulDiv (new - infoPtr->MinVal, rect.right - rect.left, - infoPtr->MaxVal - infoPtr->MinVal); - ledWidth = MulDiv (rect.bottom - rect.top, 2, 3); - rect.left = min( oldPos, newPos ); - rect.right = max( oldPos, newPos ); - if (!(style & PBS_SMOOTH)) rect.right += ledWidth; - InvalidateRect( infoPtr->Self, &rect, oldPos > newPos ); - } -} - - -/*********************************************************************** - * PROGRESS_Draw - * Draws the progress bar. - */ -static LRESULT PROGRESS_Draw (PROGRESS_INFO *infoPtr, HDC hdc) -{ - HBRUSH hbrBar, hbrBk; - int rightBar, rightMost, ledWidth; - RECT rect; - DWORD dwStyle; - - TRACE("(infoPtr=%p, hdc=%p)\n", infoPtr, hdc); - - /* get the required bar brush */ - if (infoPtr->ColorBar == CLR_DEFAULT) - hbrBar = GetSysColorBrush(COLOR_HIGHLIGHT); - else - hbrBar = CreateSolidBrush (infoPtr->ColorBar); - - if (infoPtr->ColorBk == CLR_DEFAULT) - hbrBk = GetSysColorBrush(COLOR_3DFACE); - else - hbrBk = CreateSolidBrush(infoPtr->ColorBk); - - /* get client rectangle */ - GetClientRect (infoPtr->Self, &rect); - FrameRect( hdc, &rect, hbrBk ); - InflateRect(&rect, -1, -1); - - /* get the window style */ - dwStyle = GetWindowLongW (infoPtr->Self, GWL_STYLE); - - /* compute extent of progress bar */ - if (dwStyle & PBS_VERTICAL) { - rightBar = rect.bottom - - MulDiv (infoPtr->CurVal - infoPtr->MinVal, - rect.bottom - rect.top, - infoPtr->MaxVal - infoPtr->MinVal); - ledWidth = MulDiv (rect.right - rect.left, 2, 3); - rightMost = rect.top; - } else { - rightBar = rect.left + - MulDiv (infoPtr->CurVal - infoPtr->MinVal, - rect.right - rect.left, - infoPtr->MaxVal - infoPtr->MinVal); - ledWidth = MulDiv (rect.bottom - rect.top, 2, 3); - rightMost = rect.right; - } - - /* now draw the bar */ - if (dwStyle & PBS_SMOOTH) - { - if (dwStyle & PBS_VERTICAL) - { - if (dwStyle & PBS_MARQUEE) - { - INT old_top, old_bottom, ledMStart, leds; - old_top = rect.top; - old_bottom = rect.bottom; - - leds = rect.bottom - rect.top; - ledMStart = (infoPtr->MarqueePos + MARQUEE_LEDS) - leds; - - if(ledMStart > 0) - { - rect.top = max(rect.bottom - ledMStart, old_top); - FillRect(hdc, &rect, hbrBar); - rect.bottom = rect.top; - } - if(infoPtr->MarqueePos > 0) - { - rect.top = max(old_bottom - infoPtr->MarqueePos, old_top); - FillRect(hdc, &rect, hbrBk); - rect.bottom = rect.top; - } - if(rect.top >= old_top) - { - rect.top = max(rect.bottom - MARQUEE_LEDS, old_top); - FillRect(hdc, &rect, hbrBar); - rect.bottom = rect.top; - } - if(rect.top >= old_top) - { - rect.top = old_top; - FillRect(hdc, &rect, hbrBk); - } - } - else - { - INT old_top = rect.top; - rect.top = rightBar; - FillRect(hdc, &rect, hbrBar); - rect.bottom = rect.top; - rect.top = old_top; - FillRect(hdc, &rect, hbrBk); - } - } - else - { - if (dwStyle & PBS_MARQUEE) - { - INT old_left, old_right, ledMStart, leds; - old_left = rect.left; - old_right = rect.right; - - leds = rect.right - rect.left; - ledMStart = (infoPtr->MarqueePos + MARQUEE_LEDS) - leds; - rect.right = rect.left; - - if(ledMStart > 0) - { - rect.right = min(rect.left + ledMStart, old_right); - FillRect(hdc, &rect, hbrBar); - rect.left = rect.right; - } - if(infoPtr->MarqueePos > 0) - { - rect.right = min(old_left + infoPtr->MarqueePos, old_right); - FillRect(hdc, &rect, hbrBk); - rect.left = rect.right; - } - if(rect.right < old_right) - { - rect.right = min(rect.left + MARQUEE_LEDS, old_right); - FillRect(hdc, &rect, hbrBar); - rect.left = rect.right; - } - if(rect.right < old_right) - { - rect.right = old_right; - FillRect(hdc, &rect, hbrBk); - } - } - else - { - INT old_right = rect.right; - rect.right = rightBar; - FillRect(hdc, &rect, hbrBar); - rect.left = rect.right; - rect.right = old_right; - FillRect(hdc, &rect, hbrBk); - } - } - } else { - if (dwStyle & PBS_VERTICAL) { - if (dwStyle & PBS_MARQUEE) - { - INT i, old_top, old_bottom, ledMStart, leds; - old_top = rect.top; - old_bottom = rect.bottom; - - leds = ((rect.bottom - rect.top) + (ledWidth + LED_GAP) - 1) / (ledWidth + LED_GAP); - ledMStart = (infoPtr->MarqueePos + MARQUEE_LEDS) - leds; - - while(ledMStart > 0) - { - rect.top = max(rect.bottom - ledWidth, old_top); - FillRect(hdc, &rect, hbrBar); - rect.bottom = rect.top; - rect.top -= LED_GAP; - if (rect.top <= old_top) break; - FillRect(hdc, &rect, hbrBk); - rect.bottom = rect.top; - ledMStart--; - } - if(infoPtr->MarqueePos > 0) - { - rect.top = max(old_bottom - (infoPtr->MarqueePos * (ledWidth + LED_GAP)), old_top); - FillRect(hdc, &rect, hbrBk); - rect.bottom = rect.top; - } - for(i = 0; i < MARQUEE_LEDS && rect.top >= old_top; i++) - { - rect.top = max(rect.bottom - ledWidth, old_top); - FillRect(hdc, &rect, hbrBar); - rect.bottom = rect.top; - rect.top -= LED_GAP; - if (rect.top <= old_top) break; - FillRect(hdc, &rect, hbrBk); - rect.bottom = rect.top; - } - if(rect.top >= old_top) - { - rect.top = old_top; - FillRect(hdc, &rect, hbrBk); - } - } - else - { - while(rect.bottom > rightBar) { - rect.top = rect.bottom - ledWidth; - if (rect.top < rightMost) - rect.top = rightMost; - FillRect(hdc, &rect, hbrBar); - rect.bottom = rect.top; - rect.top -= LED_GAP; - if (rect.top <= rightBar) break; - FillRect(hdc, &rect, hbrBk); - rect.bottom = rect.top; - } - } - rect.top = rightMost; - FillRect(hdc, &rect, hbrBk); - } else { - if (dwStyle & PBS_MARQUEE) - { - INT i, old_right, old_left, ledMStart, leds; - old_left = rect.left; - old_right = rect.right; - - leds = ((rect.right - rect.left) + ledWidth - 1) / (ledWidth + LED_GAP); - ledMStart = (infoPtr->MarqueePos + MARQUEE_LEDS) - leds; - rect.right = rect.left; - - while(ledMStart > 0) - { - rect.right = min(rect.left + ledWidth, old_right); - FillRect(hdc, &rect, hbrBar); - rect.left = rect.right; - rect.right += LED_GAP; - if (rect.right > old_right) break; - FillRect(hdc, &rect, hbrBk); - rect.left = rect.right; - ledMStart--; - } - if(infoPtr->MarqueePos > 0) - { - rect.right = min(old_left + (infoPtr->MarqueePos * (ledWidth + LED_GAP)), old_right); - FillRect(hdc, &rect, hbrBk); - rect.left = rect.right; - } - for(i = 0; i < MARQUEE_LEDS && rect.right < old_right; i++) - { - rect.right = min(rect.left + ledWidth, old_right); - FillRect(hdc, &rect, hbrBar); - rect.left = rect.right; - rect.right += LED_GAP; - if (rect.right > old_right) break; - FillRect(hdc, &rect, hbrBk); - rect.left = rect.right; - } - if(rect.right < old_right) - { - rect.right = old_right; - FillRect(hdc, &rect, hbrBk); - } - } - else - { - while(rect.left < rightBar) { - rect.right = rect.left + ledWidth; - if (rect.right > rightMost) - rect.right = rightMost; - FillRect(hdc, &rect, hbrBar); - rect.left = rect.right; - rect.right += LED_GAP; - if (rect.right >= rightBar) break; - FillRect(hdc, &rect, hbrBk); - rect.left = rect.right; - } - rect.right = rightMost; - FillRect(hdc, &rect, hbrBk); - } - } - } - - /* delete bar brush */ - if (infoPtr->ColorBar != CLR_DEFAULT) DeleteObject (hbrBar); - if (infoPtr->ColorBk != CLR_DEFAULT) DeleteObject (hbrBk); - - return 0; -} - - -/*********************************************************************** - * PROGRESS_Paint - * Draw the progress bar. The background need not be erased. - * If dc!=0, it draws on it - */ -static LRESULT PROGRESS_Paint (PROGRESS_INFO *infoPtr, HDC hdc) -{ - PAINTSTRUCT ps; - if (hdc) return PROGRESS_Draw (infoPtr, hdc); - hdc = BeginPaint (infoPtr->Self, &ps); - PROGRESS_Draw (infoPtr, hdc); - EndPaint (infoPtr->Self, &ps); - return 0; -} - - -/*********************************************************************** - * PROGRESS_Timer - * Handle the marquee timer messages - */ -static LRESULT PROGRESS_Timer (PROGRESS_INFO *infoPtr, INT idTimer) -{ - if(idTimer == ID_MARQUEE_TIMER) - { - LONG style = GetWindowLongW (infoPtr->Self, GWL_STYLE); - RECT rect; - int ledWidth, leds; - - GetClientRect (infoPtr->Self, &rect); - InflateRect(&rect, -1, -1); - - if(!(style & PBS_SMOOTH)) - { - int width, height; - - if(style & PBS_VERTICAL) - { - width = rect.bottom - rect.top; - height = rect.right - rect.left; - } - else - { - height = rect.bottom - rect.top; - width = rect.right - rect.left; - } - ledWidth = MulDiv (height, 2, 3); - leds = (width + ledWidth - 1) / (ledWidth + LED_GAP); - } - else - { - ledWidth = 1; - if(style & PBS_VERTICAL) - { - leds = rect.bottom - rect.top; - } - else - { - leds = rect.right - rect.left; - } - } - - /* increment the marquee progress */ - if(++infoPtr->MarqueePos >= leds) - { - infoPtr->MarqueePos = 0; - } - - InvalidateRect(infoPtr->Self, &rect, TRUE); - } - return 0; -} - - -/*********************************************************************** - * PROGRESS_CoercePos - * Makes sure the current position (CurVal) is within bounds. - */ -static void PROGRESS_CoercePos(PROGRESS_INFO *infoPtr) -{ - if(infoPtr->CurVal < infoPtr->MinVal) - infoPtr->CurVal = infoPtr->MinVal; - if(infoPtr->CurVal > infoPtr->MaxVal) - infoPtr->CurVal = infoPtr->MaxVal; -} - - -/*********************************************************************** - * PROGRESS_SetFont - * Set new Font for progress bar - */ -static HFONT PROGRESS_SetFont (PROGRESS_INFO *infoPtr, HFONT hFont, BOOL bRedraw) -{ - HFONT hOldFont = infoPtr->Font; - infoPtr->Font = hFont; - /* Since infoPtr->Font is not used, there is no need for repaint */ - return hOldFont; -} - -static DWORD PROGRESS_SetRange (PROGRESS_INFO *infoPtr, int low, int high) -{ - DWORD res = MAKELONG(LOWORD(infoPtr->MinVal), LOWORD(infoPtr->MaxVal)); - - /* if nothing changes, simply return */ - if(infoPtr->MinVal == low && infoPtr->MaxVal == high) return res; - - infoPtr->MinVal = low; - infoPtr->MaxVal = high; - PROGRESS_CoercePos(infoPtr); - InvalidateRect(infoPtr->Self, NULL, TRUE); - return res; -} - -/*********************************************************************** - * ProgressWindowProc - */ -static LRESULT WINAPI ProgressWindowProc(HWND hwnd, UINT message, - WPARAM wParam, LPARAM lParam) -{ - PROGRESS_INFO *infoPtr; - - TRACE("hwnd=%p msg=%04x wparam=%x lParam=%lx\n", hwnd, message, wParam, lParam); - - infoPtr = (PROGRESS_INFO *)GetWindowLongPtrW(hwnd, 0); - - if (!infoPtr && message != WM_CREATE) - return DefWindowProcW( hwnd, message, wParam, lParam ); - - switch(message) { - case WM_CREATE: - { - DWORD dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE); - dwExStyle &= ~(WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE); - dwExStyle |= WS_EX_STATICEDGE; - SetWindowLongW (hwnd, GWL_EXSTYLE, dwExStyle); - /* Force recalculation of a non-client area */ - SetWindowPos(hwnd, 0, 0, 0, 0, 0, - SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); - - /* allocate memory for info struct */ - infoPtr = (PROGRESS_INFO *)Alloc (sizeof(PROGRESS_INFO)); - if (!infoPtr) return -1; - SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); - - /* initialize the info struct */ - infoPtr->Self = hwnd; - infoPtr->MinVal = 0; - infoPtr->MaxVal = 100; - infoPtr->CurVal = 0; - infoPtr->Step = 10; - infoPtr->MarqueePos = 0; - infoPtr->Marquee = FALSE; - infoPtr->ColorBar = CLR_DEFAULT; - infoPtr->ColorBk = CLR_DEFAULT; - infoPtr->Font = 0; - TRACE("Progress Ctrl creation, hwnd=%p\n", hwnd); - return 0; - } - - case WM_DESTROY: - TRACE("Progress Ctrl destruction, hwnd=%p\n", hwnd); - Free (infoPtr); - SetWindowLongPtrW(hwnd, 0, 0); - return 0; - - case WM_GETFONT: - return (LRESULT)infoPtr->Font; - - case WM_SETFONT: - return (LRESULT)PROGRESS_SetFont(infoPtr, (HFONT)wParam, (BOOL)lParam); - - case WM_PAINT: - return PROGRESS_Paint (infoPtr, (HDC)wParam); - - case WM_TIMER: - return PROGRESS_Timer (infoPtr, (INT)wParam); - - case PBM_DELTAPOS: - { - INT oldVal; - oldVal = infoPtr->CurVal; - if(wParam != 0) { - infoPtr->CurVal += (INT)wParam; - PROGRESS_CoercePos (infoPtr); - TRACE("PBM_DELTAPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal); - PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal ); - } - return oldVal; - } - - case PBM_SETPOS: - { - UINT oldVal; - oldVal = infoPtr->CurVal; - if(oldVal != wParam) { - infoPtr->CurVal = (INT)wParam; - PROGRESS_CoercePos(infoPtr); - TRACE("PBM_SETPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal); - PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal ); - } - return oldVal; - } - - case PBM_SETRANGE: - return PROGRESS_SetRange (infoPtr, (int)LOWORD(lParam), (int)HIWORD(lParam)); - - case PBM_SETSTEP: - { - INT oldStep; - oldStep = infoPtr->Step; - infoPtr->Step = (INT)wParam; - return oldStep; - } - - case PBM_STEPIT: - { - INT oldVal; - oldVal = infoPtr->CurVal; - infoPtr->CurVal += infoPtr->Step; - if(infoPtr->CurVal > infoPtr->MaxVal) - infoPtr->CurVal = infoPtr->MinVal; - if(oldVal != infoPtr->CurVal) - { - TRACE("PBM_STEPIT: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal); - PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal ); - } - return oldVal; - } - - case PBM_SETRANGE32: - return PROGRESS_SetRange (infoPtr, (int)wParam, (int)lParam); - - case PBM_GETRANGE: - if (lParam) { - ((PPBRANGE)lParam)->iLow = infoPtr->MinVal; - ((PPBRANGE)lParam)->iHigh = infoPtr->MaxVal; - } - return wParam ? infoPtr->MinVal : infoPtr->MaxVal; - - case PBM_GETPOS: - return infoPtr->CurVal; - - case PBM_SETBARCOLOR: - infoPtr->ColorBar = (COLORREF)lParam; - InvalidateRect(hwnd, NULL, TRUE); - return 0; - - case PBM_SETBKCOLOR: - infoPtr->ColorBk = (COLORREF)lParam; - InvalidateRect(hwnd, NULL, TRUE); - return 0; - - case PBM_SETMARQUEE: - if(wParam != 0) - { - infoPtr->Marquee = TRUE; - SetTimer(infoPtr->Self, ID_MARQUEE_TIMER, (UINT)lParam, NULL); - } - else - { - infoPtr->Marquee = FALSE; - KillTimer(infoPtr->Self, ID_MARQUEE_TIMER); - } - return infoPtr->Marquee; - - default: - if ((message >= WM_USER) && (message < WM_APP)) - ERR("unknown msg %04x wp=%04x lp=%08lx\n", message, wParam, lParam ); - return DefWindowProcW( hwnd, message, wParam, lParam ); - } -} - - -/*********************************************************************** - * PROGRESS_Register [Internal] - * - * Registers the progress bar window class. - */ -void PROGRESS_Register (void) -{ - WNDCLASSW wndClass; - - ZeroMemory (&wndClass, sizeof(wndClass)); - wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW; - wndClass.lpfnWndProc = (WNDPROC)ProgressWindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof (PROGRESS_INFO *); - wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); - wndClass.lpszClassName = PROGRESS_CLASSW; - - RegisterClassW (&wndClass); -} - - -/*********************************************************************** - * PROGRESS_Unregister [Internal] - * - * Unregisters the progress bar window class. - */ -void PROGRESS_Unregister (void) -{ - UnregisterClassW (PROGRESS_CLASSW, NULL); -} +/* + * Progress control + * + * Copyright 1997, 2002 Dimitrie O. Paun + * Copyright 1998, 1999 Eric Kohl + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTE + * + * This code was audited for completeness against the documented features + * of Comctl32.dll version 6.0 on Sep. 9, 2002, by Dimitrie O. Paun. + * + * Unless otherwise noted, we believe this code to be complete, as per + * the specification mentioned above. + * If you discover missing features, or bugs, please note them below. + * + */ + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "comctl32.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(progress); + +typedef struct +{ + HWND Self; /* The window handle for this control */ + INT CurVal; /* Current progress value */ + INT MinVal; /* Minimum progress value */ + INT MaxVal; /* Maximum progress value */ + INT Step; /* Step to use on PMB_STEPIT */ + INT MarqueePos; /* Marquee animation position */ + BOOL Marquee; /* Whether the marquee animation is enabled */ + COLORREF ColorBar; /* Bar color */ + COLORREF ColorBk; /* Background color */ + HFONT Font; /* Handle to font (not unused) */ +} PROGRESS_INFO; + +/* Control configuration constants */ + +#define LED_GAP 2 +#define MARQUEE_LEDS 5 +#define ID_MARQUEE_TIMER 1 + +/*********************************************************************** + * PROGRESS_Invalidate + * + * Invalide the range between old and new pos. + */ +static void PROGRESS_Invalidate( PROGRESS_INFO *infoPtr, INT old, INT new ) +{ + LONG style = GetWindowLongW (infoPtr->Self, GWL_STYLE); + RECT rect; + int oldPos, newPos, ledWidth; + + GetClientRect (infoPtr->Self, &rect); + InflateRect(&rect, -1, -1); + + if (style & PBS_VERTICAL) + { + oldPos = rect.bottom - MulDiv (old - infoPtr->MinVal, rect.bottom - rect.top, + infoPtr->MaxVal - infoPtr->MinVal); + newPos = rect.bottom - MulDiv (new - infoPtr->MinVal, rect.bottom - rect.top, + infoPtr->MaxVal - infoPtr->MinVal); + ledWidth = MulDiv (rect.right - rect.left, 2, 3); + rect.top = min( oldPos, newPos ); + rect.bottom = max( oldPos, newPos ); + if (!(style & PBS_SMOOTH)) rect.top -= ledWidth; + InvalidateRect( infoPtr->Self, &rect, oldPos < newPos ); + } + else + { + oldPos = rect.left + MulDiv (old - infoPtr->MinVal, rect.right - rect.left, + infoPtr->MaxVal - infoPtr->MinVal); + newPos = rect.left + MulDiv (new - infoPtr->MinVal, rect.right - rect.left, + infoPtr->MaxVal - infoPtr->MinVal); + ledWidth = MulDiv (rect.bottom - rect.top, 2, 3); + rect.left = min( oldPos, newPos ); + rect.right = max( oldPos, newPos ); + if (!(style & PBS_SMOOTH)) rect.right += ledWidth; + InvalidateRect( infoPtr->Self, &rect, oldPos > newPos ); + } +} + + +/*********************************************************************** + * PROGRESS_Draw + * Draws the progress bar. + */ +static LRESULT PROGRESS_Draw (PROGRESS_INFO *infoPtr, HDC hdc) +{ + HBRUSH hbrBar, hbrBk; + int rightBar, rightMost, ledWidth; + RECT rect; + DWORD dwStyle; + + TRACE("(infoPtr=%p, hdc=%p)\n", infoPtr, hdc); + + /* get the required bar brush */ + if (infoPtr->ColorBar == CLR_DEFAULT) + hbrBar = GetSysColorBrush(COLOR_HIGHLIGHT); + else + hbrBar = CreateSolidBrush (infoPtr->ColorBar); + + if (infoPtr->ColorBk == CLR_DEFAULT) + hbrBk = GetSysColorBrush(COLOR_3DFACE); + else + hbrBk = CreateSolidBrush(infoPtr->ColorBk); + + /* get client rectangle */ + GetClientRect (infoPtr->Self, &rect); + FrameRect( hdc, &rect, hbrBk ); + InflateRect(&rect, -1, -1); + + /* get the window style */ + dwStyle = GetWindowLongW (infoPtr->Self, GWL_STYLE); + + /* compute extent of progress bar */ + if (dwStyle & PBS_VERTICAL) { + rightBar = rect.bottom - + MulDiv (infoPtr->CurVal - infoPtr->MinVal, + rect.bottom - rect.top, + infoPtr->MaxVal - infoPtr->MinVal); + ledWidth = MulDiv (rect.right - rect.left, 2, 3); + rightMost = rect.top; + } else { + rightBar = rect.left + + MulDiv (infoPtr->CurVal - infoPtr->MinVal, + rect.right - rect.left, + infoPtr->MaxVal - infoPtr->MinVal); + ledWidth = MulDiv (rect.bottom - rect.top, 2, 3); + rightMost = rect.right; + } + + /* now draw the bar */ + if (dwStyle & PBS_SMOOTH) + { + if (dwStyle & PBS_VERTICAL) + { + if (dwStyle & PBS_MARQUEE) + { + INT old_top, old_bottom, ledMStart, leds; + old_top = rect.top; + old_bottom = rect.bottom; + + leds = rect.bottom - rect.top; + ledMStart = (infoPtr->MarqueePos + MARQUEE_LEDS) - leds; + + if(ledMStart > 0) + { + rect.top = max(rect.bottom - ledMStart, old_top); + FillRect(hdc, &rect, hbrBar); + rect.bottom = rect.top; + } + if(infoPtr->MarqueePos > 0) + { + rect.top = max(old_bottom - infoPtr->MarqueePos, old_top); + FillRect(hdc, &rect, hbrBk); + rect.bottom = rect.top; + } + if(rect.top >= old_top) + { + rect.top = max(rect.bottom - MARQUEE_LEDS, old_top); + FillRect(hdc, &rect, hbrBar); + rect.bottom = rect.top; + } + if(rect.top >= old_top) + { + rect.top = old_top; + FillRect(hdc, &rect, hbrBk); + } + } + else + { + INT old_top = rect.top; + rect.top = rightBar; + FillRect(hdc, &rect, hbrBar); + rect.bottom = rect.top; + rect.top = old_top; + FillRect(hdc, &rect, hbrBk); + } + } + else + { + if (dwStyle & PBS_MARQUEE) + { + INT old_left, old_right, ledMStart, leds; + old_left = rect.left; + old_right = rect.right; + + leds = rect.right - rect.left; + ledMStart = (infoPtr->MarqueePos + MARQUEE_LEDS) - leds; + rect.right = rect.left; + + if(ledMStart > 0) + { + rect.right = min(rect.left + ledMStart, old_right); + FillRect(hdc, &rect, hbrBar); + rect.left = rect.right; + } + if(infoPtr->MarqueePos > 0) + { + rect.right = min(old_left + infoPtr->MarqueePos, old_right); + FillRect(hdc, &rect, hbrBk); + rect.left = rect.right; + } + if(rect.right < old_right) + { + rect.right = min(rect.left + MARQUEE_LEDS, old_right); + FillRect(hdc, &rect, hbrBar); + rect.left = rect.right; + } + if(rect.right < old_right) + { + rect.right = old_right; + FillRect(hdc, &rect, hbrBk); + } + } + else + { + INT old_right = rect.right; + rect.right = rightBar; + FillRect(hdc, &rect, hbrBar); + rect.left = rect.right; + rect.right = old_right; + FillRect(hdc, &rect, hbrBk); + } + } + } else { + if (dwStyle & PBS_VERTICAL) { + if (dwStyle & PBS_MARQUEE) + { + INT i, old_top, old_bottom, ledMStart, leds; + old_top = rect.top; + old_bottom = rect.bottom; + + leds = ((rect.bottom - rect.top) + (ledWidth + LED_GAP) - 1) / (ledWidth + LED_GAP); + ledMStart = (infoPtr->MarqueePos + MARQUEE_LEDS) - leds; + + while(ledMStart > 0) + { + rect.top = max(rect.bottom - ledWidth, old_top); + FillRect(hdc, &rect, hbrBar); + rect.bottom = rect.top; + rect.top -= LED_GAP; + if (rect.top <= old_top) break; + FillRect(hdc, &rect, hbrBk); + rect.bottom = rect.top; + ledMStart--; + } + if(infoPtr->MarqueePos > 0) + { + rect.top = max(old_bottom - (infoPtr->MarqueePos * (ledWidth + LED_GAP)), old_top); + FillRect(hdc, &rect, hbrBk); + rect.bottom = rect.top; + } + for(i = 0; i < MARQUEE_LEDS && rect.top >= old_top; i++) + { + rect.top = max(rect.bottom - ledWidth, old_top); + FillRect(hdc, &rect, hbrBar); + rect.bottom = rect.top; + rect.top -= LED_GAP; + if (rect.top <= old_top) break; + FillRect(hdc, &rect, hbrBk); + rect.bottom = rect.top; + } + if(rect.top >= old_top) + { + rect.top = old_top; + FillRect(hdc, &rect, hbrBk); + } + } + else + { + while(rect.bottom > rightBar) { + rect.top = rect.bottom - ledWidth; + if (rect.top < rightMost) + rect.top = rightMost; + FillRect(hdc, &rect, hbrBar); + rect.bottom = rect.top; + rect.top -= LED_GAP; + if (rect.top <= rightBar) break; + FillRect(hdc, &rect, hbrBk); + rect.bottom = rect.top; + } + } + rect.top = rightMost; + FillRect(hdc, &rect, hbrBk); + } else { + if (dwStyle & PBS_MARQUEE) + { + INT i, old_right, old_left, ledMStart, leds; + old_left = rect.left; + old_right = rect.right; + + leds = ((rect.right - rect.left) + ledWidth - 1) / (ledWidth + LED_GAP); + ledMStart = (infoPtr->MarqueePos + MARQUEE_LEDS) - leds; + rect.right = rect.left; + + while(ledMStart > 0) + { + rect.right = min(rect.left + ledWidth, old_right); + FillRect(hdc, &rect, hbrBar); + rect.left = rect.right; + rect.right += LED_GAP; + if (rect.right > old_right) break; + FillRect(hdc, &rect, hbrBk); + rect.left = rect.right; + ledMStart--; + } + if(infoPtr->MarqueePos > 0) + { + rect.right = min(old_left + (infoPtr->MarqueePos * (ledWidth + LED_GAP)), old_right); + FillRect(hdc, &rect, hbrBk); + rect.left = rect.right; + } + for(i = 0; i < MARQUEE_LEDS && rect.right < old_right; i++) + { + rect.right = min(rect.left + ledWidth, old_right); + FillRect(hdc, &rect, hbrBar); + rect.left = rect.right; + rect.right += LED_GAP; + if (rect.right > old_right) break; + FillRect(hdc, &rect, hbrBk); + rect.left = rect.right; + } + if(rect.right < old_right) + { + rect.right = old_right; + FillRect(hdc, &rect, hbrBk); + } + } + else + { + while(rect.left < rightBar) { + rect.right = rect.left + ledWidth; + if (rect.right > rightMost) + rect.right = rightMost; + FillRect(hdc, &rect, hbrBar); + rect.left = rect.right; + rect.right += LED_GAP; + if (rect.right >= rightBar) break; + FillRect(hdc, &rect, hbrBk); + rect.left = rect.right; + } + rect.right = rightMost; + FillRect(hdc, &rect, hbrBk); + } + } + } + + /* delete bar brush */ + if (infoPtr->ColorBar != CLR_DEFAULT) DeleteObject (hbrBar); + if (infoPtr->ColorBk != CLR_DEFAULT) DeleteObject (hbrBk); + + return 0; +} + + +/*********************************************************************** + * PROGRESS_Paint + * Draw the progress bar. The background need not be erased. + * If dc!=0, it draws on it + */ +static LRESULT PROGRESS_Paint (PROGRESS_INFO *infoPtr, HDC hdc) +{ + PAINTSTRUCT ps; + if (hdc) return PROGRESS_Draw (infoPtr, hdc); + hdc = BeginPaint (infoPtr->Self, &ps); + PROGRESS_Draw (infoPtr, hdc); + EndPaint (infoPtr->Self, &ps); + return 0; +} + + +/*********************************************************************** + * PROGRESS_Timer + * Handle the marquee timer messages + */ +static LRESULT PROGRESS_Timer (PROGRESS_INFO *infoPtr, INT idTimer) +{ + if(idTimer == ID_MARQUEE_TIMER) + { + LONG style = GetWindowLongW (infoPtr->Self, GWL_STYLE); + RECT rect; + int ledWidth, leds; + + GetClientRect (infoPtr->Self, &rect); + InflateRect(&rect, -1, -1); + + if(!(style & PBS_SMOOTH)) + { + int width, height; + + if(style & PBS_VERTICAL) + { + width = rect.bottom - rect.top; + height = rect.right - rect.left; + } + else + { + height = rect.bottom - rect.top; + width = rect.right - rect.left; + } + ledWidth = MulDiv (height, 2, 3); + leds = (width + ledWidth - 1) / (ledWidth + LED_GAP); + } + else + { + ledWidth = 1; + if(style & PBS_VERTICAL) + { + leds = rect.bottom - rect.top; + } + else + { + leds = rect.right - rect.left; + } + } + + /* increment the marquee progress */ + if(++infoPtr->MarqueePos >= leds) + { + infoPtr->MarqueePos = 0; + } + + InvalidateRect(infoPtr->Self, &rect, TRUE); + } + return 0; +} + + +/*********************************************************************** + * PROGRESS_CoercePos + * Makes sure the current position (CurVal) is within bounds. + */ +static void PROGRESS_CoercePos(PROGRESS_INFO *infoPtr) +{ + if(infoPtr->CurVal < infoPtr->MinVal) + infoPtr->CurVal = infoPtr->MinVal; + if(infoPtr->CurVal > infoPtr->MaxVal) + infoPtr->CurVal = infoPtr->MaxVal; +} + + +/*********************************************************************** + * PROGRESS_SetFont + * Set new Font for progress bar + */ +static HFONT PROGRESS_SetFont (PROGRESS_INFO *infoPtr, HFONT hFont, BOOL bRedraw) +{ + HFONT hOldFont = infoPtr->Font; + infoPtr->Font = hFont; + /* Since infoPtr->Font is not used, there is no need for repaint */ + return hOldFont; +} + +static DWORD PROGRESS_SetRange (PROGRESS_INFO *infoPtr, int low, int high) +{ + DWORD res = MAKELONG(LOWORD(infoPtr->MinVal), LOWORD(infoPtr->MaxVal)); + + /* if nothing changes, simply return */ + if(infoPtr->MinVal == low && infoPtr->MaxVal == high) return res; + + infoPtr->MinVal = low; + infoPtr->MaxVal = high; + PROGRESS_CoercePos(infoPtr); + InvalidateRect(infoPtr->Self, NULL, TRUE); + return res; +} + +/*********************************************************************** + * ProgressWindowProc + */ +static LRESULT WINAPI ProgressWindowProc(HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam) +{ + PROGRESS_INFO *infoPtr; + + TRACE("hwnd=%p msg=%04x wparam=%x lParam=%lx\n", hwnd, message, wParam, lParam); + + infoPtr = (PROGRESS_INFO *)GetWindowLongPtrW(hwnd, 0); + + if (!infoPtr && message != WM_CREATE) + return DefWindowProcW( hwnd, message, wParam, lParam ); + + switch(message) { + case WM_CREATE: + { + DWORD dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE); + dwExStyle &= ~(WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE); + dwExStyle |= WS_EX_STATICEDGE; + SetWindowLongW (hwnd, GWL_EXSTYLE, dwExStyle); + /* Force recalculation of a non-client area */ + SetWindowPos(hwnd, 0, 0, 0, 0, 0, + SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + + /* allocate memory for info struct */ + infoPtr = (PROGRESS_INFO *)Alloc (sizeof(PROGRESS_INFO)); + if (!infoPtr) return -1; + SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); + + /* initialize the info struct */ + infoPtr->Self = hwnd; + infoPtr->MinVal = 0; + infoPtr->MaxVal = 100; + infoPtr->CurVal = 0; + infoPtr->Step = 10; + infoPtr->MarqueePos = 0; + infoPtr->Marquee = FALSE; + infoPtr->ColorBar = CLR_DEFAULT; + infoPtr->ColorBk = CLR_DEFAULT; + infoPtr->Font = 0; + TRACE("Progress Ctrl creation, hwnd=%p\n", hwnd); + return 0; + } + + case WM_DESTROY: + TRACE("Progress Ctrl destruction, hwnd=%p\n", hwnd); + Free (infoPtr); + SetWindowLongPtrW(hwnd, 0, 0); + return 0; + + case WM_GETFONT: + return (LRESULT)infoPtr->Font; + + case WM_SETFONT: + return (LRESULT)PROGRESS_SetFont(infoPtr, (HFONT)wParam, (BOOL)lParam); + + case WM_PAINT: + return PROGRESS_Paint (infoPtr, (HDC)wParam); + + case WM_TIMER: + return PROGRESS_Timer (infoPtr, (INT)wParam); + + case PBM_DELTAPOS: + { + INT oldVal; + oldVal = infoPtr->CurVal; + if(wParam != 0) { + infoPtr->CurVal += (INT)wParam; + PROGRESS_CoercePos (infoPtr); + TRACE("PBM_DELTAPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal); + PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal ); + } + return oldVal; + } + + case PBM_SETPOS: + { + UINT oldVal; + oldVal = infoPtr->CurVal; + if(oldVal != wParam) { + infoPtr->CurVal = (INT)wParam; + PROGRESS_CoercePos(infoPtr); + TRACE("PBM_SETPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal); + PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal ); + } + return oldVal; + } + + case PBM_SETRANGE: + return PROGRESS_SetRange (infoPtr, (int)LOWORD(lParam), (int)HIWORD(lParam)); + + case PBM_SETSTEP: + { + INT oldStep; + oldStep = infoPtr->Step; + infoPtr->Step = (INT)wParam; + return oldStep; + } + + case PBM_STEPIT: + { + INT oldVal; + oldVal = infoPtr->CurVal; + infoPtr->CurVal += infoPtr->Step; + if(infoPtr->CurVal > infoPtr->MaxVal) + infoPtr->CurVal = infoPtr->MinVal; + if(oldVal != infoPtr->CurVal) + { + TRACE("PBM_STEPIT: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal); + PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal ); + } + return oldVal; + } + + case PBM_SETRANGE32: + return PROGRESS_SetRange (infoPtr, (int)wParam, (int)lParam); + + case PBM_GETRANGE: + if (lParam) { + ((PPBRANGE)lParam)->iLow = infoPtr->MinVal; + ((PPBRANGE)lParam)->iHigh = infoPtr->MaxVal; + } + return wParam ? infoPtr->MinVal : infoPtr->MaxVal; + + case PBM_GETPOS: + return infoPtr->CurVal; + + case PBM_SETBARCOLOR: + infoPtr->ColorBar = (COLORREF)lParam; + InvalidateRect(hwnd, NULL, TRUE); + return 0; + + case PBM_SETBKCOLOR: + infoPtr->ColorBk = (COLORREF)lParam; + InvalidateRect(hwnd, NULL, TRUE); + return 0; + + case PBM_SETMARQUEE: + if(wParam != 0) + { + infoPtr->Marquee = TRUE; + SetTimer(infoPtr->Self, ID_MARQUEE_TIMER, (UINT)lParam, NULL); + } + else + { + infoPtr->Marquee = FALSE; + KillTimer(infoPtr->Self, ID_MARQUEE_TIMER); + } + return infoPtr->Marquee; + + default: + if ((message >= WM_USER) && (message < WM_APP)) + ERR("unknown msg %04x wp=%04x lp=%08lx\n", message, wParam, lParam ); + return DefWindowProcW( hwnd, message, wParam, lParam ); + } +} + + +/*********************************************************************** + * PROGRESS_Register [Internal] + * + * Registers the progress bar window class. + */ +void PROGRESS_Register (void) +{ + WNDCLASSW wndClass; + + ZeroMemory (&wndClass, sizeof(wndClass)); + wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW; + wndClass.lpfnWndProc = (WNDPROC)ProgressWindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof (PROGRESS_INFO *); + wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); + wndClass.lpszClassName = PROGRESS_CLASSW; + + RegisterClassW (&wndClass); +} + + +/*********************************************************************** + * PROGRESS_Unregister [Internal] + * + * Unregisters the progress bar window class. + */ +void PROGRESS_Unregister (void) +{ + UnregisterClassW (PROGRESS_CLASSW, NULL); +} diff --git a/reactos/lib/comctl32/propsheet.c b/reactos/lib/comctl32/propsheet.c index 200c42982b7..67609adbe3a 100644 --- a/reactos/lib/comctl32/propsheet.c +++ b/reactos/lib/comctl32/propsheet.c @@ -1,3722 +1,3722 @@ -/* - * Property Sheets - * - * Copyright 1998 Francis Beaudet - * Copyright 1999 Thuy Nguyen - * Copyright 2004 Maxime Bellenge - * Copyright 2004 Filip Navara - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on Sep. 12, 2004, by Filip Navara. - * - * Unless otherwise noted, we believe this code to be complete, as per - * the specification mentioned above. - * If you discover missing features, or bugs, please note them below. - * - * TODO: - * - Tab order - * - Wizard 97 header resizing - * - Enforcing of minimal wizard size - * - Messages: - * o PSM_GETRESULT - * o PSM_IDTOINDEX - * o PSM_INSERTPAGE - * o PSM_RECALCPAGESIZES - * o PSM_SETHEADERSUBTITLE - * o PSM_SETHEADERTITLE - * o WM_HELP - * o WM_CONTEXTMENU - * - Notifications: - * o PSN_GETOBJECT - * o PSN_QUERYINITIALFOCUS - * o PSN_TRANSLATEACCELERATOR - * - Styles: - * o PSH_WIZARDHASFINISH - * o PSH_RTLREADING - * o PSH_STRETCHWATERMARK - * o PSH_USEPAGELANG - * o PSH_USEPSTARTPAGE - * - Page styles: - * o PSP_USEFUSIONCONTEXT - * o PSP_USEREFPARENT - */ - -#include -#include - -#define NONAMELESSUNION -#define NONAMELESSSTRUCT -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "prsht.h" -#include "comctl32.h" - -#include "wine/debug.h" -#include "wine/unicode.h" - -/****************************************************************************** - * Data structures - */ -#include "pshpack2.h" - -typedef struct -{ - WORD dlgVer; - WORD signature; - DWORD helpID; - DWORD exStyle; - DWORD style; -} MyDLGTEMPLATEEX; - -typedef struct -{ - DWORD helpid; - DWORD exStyle; - DWORD style; - short x; - short y; - short cx; - short cy; - DWORD id; -} MyDLGITEMTEMPLATEEX; -#include "poppack.h" - -typedef struct tagPropPageInfo -{ - HPROPSHEETPAGE hpage; /* to keep track of pages not passed to PropertySheet */ - HWND hwndPage; - BOOL isDirty; - LPCWSTR pszText; - BOOL hasHelp; - BOOL useCallback; - BOOL hasIcon; -} PropPageInfo; - -typedef struct tagPropSheetInfo -{ - HWND hwnd; - PROPSHEETHEADERW ppshheader; - BOOL unicode; - LPWSTR strPropertiesFor; - int nPages; - int active_page; - BOOL isModeless; - BOOL hasHelp; - BOOL hasApply; - BOOL useCallback; - BOOL restartWindows; - BOOL rebootSystem; - BOOL activeValid; - PropPageInfo* proppage; - HFONT hFont; - HFONT hFontBold; - int width; - int height; - HIMAGELIST hImageList; - BOOL ended; -} PropSheetInfo; - -typedef struct -{ - int x; - int y; -} PADDING_INFO; - -/****************************************************************************** - * Defines and global variables - */ - -const WCHAR PropSheetInfoStr[] = - {'P','r','o','p','e','r','t','y','S','h','e','e','t','I','n','f','o',0 }; - -#define PSP_INTERNAL_UNICODE 0x80000000 - -#define MAX_CAPTION_LENGTH 255 -#define MAX_TABTEXT_LENGTH 255 -#define MAX_BUTTONTEXT_LENGTH 64 - -#define INTRNL_ANY_WIZARD (PSH_WIZARD | PSH_WIZARD97_OLD | PSH_WIZARD97_NEW | PSH_WIZARD_LITE) - -/* Wizard metrics specified in DLUs */ -#define WIZARD_PADDING 7 -#define WIZARD_HEADER_HEIGHT 36 - -/****************************************************************************** - * Prototypes - */ -static int PROPSHEET_CreateDialog(PropSheetInfo* psInfo); -static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo); -static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo); -static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo); -static BOOL PROPSHEET_CollectSheetInfoA(LPCPROPSHEETHEADERA lppsh, - PropSheetInfo * psInfo); -static BOOL PROPSHEET_CollectSheetInfoW(LPCPROPSHEETHEADERW lppsh, - PropSheetInfo * psInfo); -static BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEW lppsp, - PropSheetInfo * psInfo, - int index); -static BOOL PROPSHEET_CreateTabControl(HWND hwndParent, - PropSheetInfo * psInfo); -static BOOL PROPSHEET_CreatePage(HWND hwndParent, int index, - const PropSheetInfo * psInfo, - LPCPROPSHEETPAGEW ppshpage); -static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo); -static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg); -static BOOL PROPSHEET_Back(HWND hwndDlg); -static BOOL PROPSHEET_Next(HWND hwndDlg); -static BOOL PROPSHEET_Finish(HWND hwndDlg); -static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam); -static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam); -static void PROPSHEET_Help(HWND hwndDlg); -static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage); -static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage); -static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID); -static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText); -static void PROPSHEET_SetFinishTextW(HWND hwndDlg, LPCWSTR lpszText); -static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText); -static void PROPSHEET_SetTitleW(HWND hwndDlg, DWORD dwStyle, LPCWSTR lpszText); -static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg); -static BOOL PROPSHEET_SetCurSel(HWND hwndDlg, - int index, - int skipdir, - HPROPSHEETPAGE hpage); -static void PROPSHEET_SetCurSelId(HWND hwndDlg, int id); -static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg, - WPARAM wParam, LPARAM lParam); -static BOOL PROPSHEET_AddPage(HWND hwndDlg, - HPROPSHEETPAGE hpage); - -static BOOL PROPSHEET_RemovePage(HWND hwndDlg, - int index, - HPROPSHEETPAGE hpage); -static void PROPSHEET_CleanUp(HWND hwndDlg); -static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo); -static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags); -static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo* psInfo); -static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg); -static BOOL PROPSHEET_DoCommand(HWND hwnd, WORD wID); - -INT_PTR CALLBACK -PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - -WINE_DEFAULT_DEBUG_CHANNEL(propsheet); - -#define add_flag(a) if (dwFlags & a) {strcat(string, #a );strcat(string," ");} -/****************************************************************************** - * PROPSHEET_UnImplementedFlags - * - * Document use of flags we don't implement yet. - */ -static VOID PROPSHEET_UnImplementedFlags(DWORD dwFlags) -{ - CHAR string[256]; - - string[0] = '\0'; - - /* - * unhandled header flags: - * PSH_WIZARDHASFINISH 0x00000010 - * PSH_RTLREADING 0x00000800 - * PSH_STRETCHWATERMARK 0x00040000 - * PSH_USEPAGELANG 0x00200000 - */ - - add_flag(PSH_WIZARDHASFINISH); - add_flag(PSH_RTLREADING); - add_flag(PSH_STRETCHWATERMARK); - add_flag(PSH_USEPAGELANG); - if (string[0] != '\0') - FIXME("%s\n", string); -} -#undef add_flag - -/****************************************************************************** - * PROPSHEET_GetPageRect - * - * Retrieve rect from tab control and map into the dialog for SetWindowPos - */ -static void PROPSHEET_GetPageRect(const PropSheetInfo * psInfo, HWND hwndDlg, - RECT *rc, LPCPROPSHEETPAGEW ppshpage) -{ - if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) { - HWND hwndChild; - RECT r; - - if (((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) && - (psInfo->ppshheader.dwFlags & PSH_HEADER) && - !(ppshpage->dwFlags & PSP_HIDEHEADER)) || - (psInfo->ppshheader.dwFlags & PSH_WIZARD)) - { - rc->left = rc->top = WIZARD_PADDING; - } - else - { - rc->left = rc->top = 0; - } - rc->right = psInfo->width - rc->left; - rc->bottom = psInfo->height - rc->top; - MapDialogRect(hwndDlg, rc); - - if ((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) && - (psInfo->ppshheader.dwFlags & PSH_HEADER) && - !(ppshpage->dwFlags & PSP_HIDEHEADER)) - { - hwndChild = GetDlgItem(hwndDlg, IDC_SUNKEN_LINEHEADER); - GetClientRect(hwndChild, &r); - MapWindowPoints(hwndChild, hwndDlg, (LPPOINT) &r, 2); - rc->top += r.bottom + 1; - } - } else { - HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL); - GetClientRect(hwndTabCtrl, rc); - SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)rc); - MapWindowPoints(hwndTabCtrl, hwndDlg, (LPPOINT)rc, 2); - } -} - -/****************************************************************************** - * PROPSHEET_FindPageByResId - * - * Find page index corresponding to page resource id. - */ -static INT PROPSHEET_FindPageByResId(PropSheetInfo * psInfo, LRESULT resId) -{ - INT i; - - for (i = 0; i < psInfo->nPages; i++) - { - LPCPROPSHEETPAGEA lppsp = (LPCPROPSHEETPAGEA)psInfo->proppage[i].hpage; - - /* Fixme: if resource ID is a string shall we use strcmp ??? */ - if (lppsp->u.pszTemplate == (LPVOID)resId) - break; - } - - return i; -} - -/****************************************************************************** - * PROPSHEET_AtoW - * - * Convert ASCII to Unicode since all data is saved as Unicode. - */ -static void PROPSHEET_AtoW(LPCWSTR *tostr, LPCSTR frstr) -{ - INT len; - - TRACE("<%s>\n", frstr); - len = MultiByteToWideChar(CP_ACP, 0, frstr, -1, 0, 0); - *tostr = Alloc(len * sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, frstr, -1, (LPWSTR)*tostr, len); -} - -/****************************************************************************** - * PROPSHEET_CollectSheetInfoA - * - * Collect relevant data. - */ -static BOOL PROPSHEET_CollectSheetInfoA(LPCPROPSHEETHEADERA lppsh, - PropSheetInfo * psInfo) -{ - DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERA)); - DWORD dwFlags = lppsh->dwFlags; - - psInfo->hasHelp = dwFlags & PSH_HASHELP; - psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW); - psInfo->useCallback = (dwFlags & PSH_USECALLBACK )&& (lppsh->pfnCallback); - psInfo->isModeless = dwFlags & PSH_MODELESS; - - memcpy(&psInfo->ppshheader,lppsh,dwSize); - TRACE("\n** PROPSHEETHEADER **\ndwSize\t\t%ld\ndwFlags\t\t%08lx\nhwndParent\t%p\nhInstance\t%p\npszCaption\t'%s'\nnPages\t\t%d\npfnCallback\t%p\n", - lppsh->dwSize, lppsh->dwFlags, lppsh->hwndParent, lppsh->hInstance, - debugstr_a(lppsh->pszCaption), lppsh->nPages, lppsh->pfnCallback); - - PROPSHEET_UnImplementedFlags(lppsh->dwFlags); - - if (lppsh->dwFlags & INTRNL_ANY_WIZARD) - psInfo->ppshheader.pszCaption = NULL; - else - { - if (HIWORD(lppsh->pszCaption)) - { - int len = MultiByteToWideChar(CP_ACP, 0, lppsh->pszCaption, -1, NULL, 0); - psInfo->ppshheader.pszCaption = Alloc( len*sizeof (WCHAR) ); - MultiByteToWideChar(CP_ACP, 0, lppsh->pszCaption, -1, (LPWSTR) psInfo->ppshheader.pszCaption, len); - } - } - psInfo->nPages = lppsh->nPages; - - if (dwFlags & PSH_USEPSTARTPAGE) - { - TRACE("PSH_USEPSTARTPAGE is on\n"); - psInfo->active_page = 0; - } - else - psInfo->active_page = lppsh->u2.nStartPage; - - if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages) - psInfo->active_page = 0; - - psInfo->restartWindows = FALSE; - psInfo->rebootSystem = FALSE; - psInfo->hImageList = 0; - psInfo->activeValid = FALSE; - - return TRUE; -} - -/****************************************************************************** - * PROPSHEET_CollectSheetInfoW - * - * Collect relevant data. - */ -static BOOL PROPSHEET_CollectSheetInfoW(LPCPROPSHEETHEADERW lppsh, - PropSheetInfo * psInfo) -{ - DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERW)); - DWORD dwFlags = lppsh->dwFlags; - - psInfo->hasHelp = dwFlags & PSH_HASHELP; - psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW); - psInfo->useCallback = (dwFlags & PSH_USECALLBACK) && (lppsh->pfnCallback); - psInfo->isModeless = dwFlags & PSH_MODELESS; - - memcpy(&psInfo->ppshheader,lppsh,dwSize); - TRACE("\n** PROPSHEETHEADER **\ndwSize\t\t%ld\ndwFlags\t\t%08lx\nhwndParent\t%p\nhInstance\t%p\npszCaption\t'%s'\nnPages\t\t%d\npfnCallback\t%p\n", - lppsh->dwSize, lppsh->dwFlags, lppsh->hwndParent, lppsh->hInstance, debugstr_w(lppsh->pszCaption), lppsh->nPages, lppsh->pfnCallback); - - PROPSHEET_UnImplementedFlags(lppsh->dwFlags); - - if (lppsh->dwFlags & INTRNL_ANY_WIZARD) - psInfo->ppshheader.pszCaption = NULL; - else - { - if (HIWORD(lppsh->pszCaption)) - { - int len = strlenW(lppsh->pszCaption); - psInfo->ppshheader.pszCaption = Alloc( (len+1)*sizeof(WCHAR) ); - strcpyW( (WCHAR *)psInfo->ppshheader.pszCaption, lppsh->pszCaption ); - } - } - psInfo->nPages = lppsh->nPages; - - if (dwFlags & PSH_USEPSTARTPAGE) - { - TRACE("PSH_USEPSTARTPAGE is on\n"); - psInfo->active_page = 0; - } - else - psInfo->active_page = lppsh->u2.nStartPage; - - if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages) - psInfo->active_page = 0; - - psInfo->restartWindows = FALSE; - psInfo->rebootSystem = FALSE; - psInfo->hImageList = 0; - psInfo->activeValid = FALSE; - - return TRUE; -} - -/****************************************************************************** - * PROPSHEET_CollectPageInfo - * - * Collect property sheet data. - * With code taken from DIALOG_ParseTemplate32. - */ -BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEW lppsp, - PropSheetInfo * psInfo, - int index) -{ - DLGTEMPLATE* pTemplate; - const WORD* p; - DWORD dwFlags; - int width, height; - - TRACE("\n"); - psInfo->proppage[index].hpage = (HPROPSHEETPAGE)lppsp; - psInfo->proppage[index].hwndPage = 0; - psInfo->proppage[index].isDirty = FALSE; - - /* - * Process property page flags. - */ - dwFlags = lppsp->dwFlags; - psInfo->proppage[index].useCallback = (dwFlags & PSP_USECALLBACK) && (lppsp->pfnCallback); - psInfo->proppage[index].hasHelp = dwFlags & PSP_HASHELP; - psInfo->proppage[index].hasIcon = dwFlags & (PSP_USEHICON | PSP_USEICONID); - - /* as soon as we have a page with the help flag, set the sheet flag on */ - if (psInfo->proppage[index].hasHelp) - psInfo->hasHelp = TRUE; - - /* - * Process page template. - */ - if (dwFlags & PSP_DLGINDIRECT) - pTemplate = (DLGTEMPLATE*)lppsp->u.pResource; - else if(dwFlags & PSP_INTERNAL_UNICODE ) - { - HRSRC hResource = FindResourceW(lppsp->hInstance, - lppsp->u.pszTemplate, - (LPWSTR)RT_DIALOG); - HGLOBAL hTemplate = LoadResource(lppsp->hInstance, - hResource); - pTemplate = (LPDLGTEMPLATEW)LockResource(hTemplate); - } - else - { - HRSRC hResource = FindResourceA(lppsp->hInstance, - (LPSTR)lppsp->u.pszTemplate, - (LPSTR)RT_DIALOG); - HGLOBAL hTemplate = LoadResource(lppsp->hInstance, - hResource); - pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate); - } - - /* - * Extract the size of the page and the caption. - */ - if (!pTemplate) - return FALSE; - - p = (const WORD *)pTemplate; - - if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF) - { - /* DLGTEMPLATEEX (not defined in any std. header file) */ - - p++; /* dlgVer */ - p++; /* signature */ - p += 2; /* help ID */ - p += 2; /* ext style */ - p += 2; /* style */ - } - else - { - /* DLGTEMPLATE */ - - p += 2; /* style */ - p += 2; /* ext style */ - } - - p++; /* nb items */ - p++; /* x */ - p++; /* y */ - width = (WORD)*p; p++; - height = (WORD)*p; p++; - - /* Special calculation for interior wizard pages so the largest page is - * calculated correctly. We need to add all the padding and space occupied - * by the header so the width and height sums up to the whole wizard client - * area. */ - if ((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) && - (psInfo->ppshheader.dwFlags & PSH_HEADER) && - !(dwFlags & PSP_HIDEHEADER)) - { - height += 2 * WIZARD_PADDING + WIZARD_HEADER_HEIGHT; - width += 2 * WIZARD_PADDING; - } - if (psInfo->ppshheader.dwFlags & PSH_WIZARD) - { - height += 2 * WIZARD_PADDING; - width += 2 * WIZARD_PADDING; - } - - /* remember the largest width and height */ - if (width > psInfo->width) - psInfo->width = width; - - if (height > psInfo->height) - psInfo->height = height; - - /* menu */ - switch ((WORD)*p) - { - case 0x0000: - p++; - break; - case 0xffff: - p += 2; - break; - default: - p += lstrlenW( (LPCWSTR)p ) + 1; - break; - } - - /* class */ - switch ((WORD)*p) - { - case 0x0000: - p++; - break; - case 0xffff: - p += 2; - break; - default: - p += lstrlenW( (LPCWSTR)p ) + 1; - break; - } - - /* Extract the caption */ - psInfo->proppage[index].pszText = (LPCWSTR)p; - TRACE("Tab %d %s\n",index,debugstr_w((LPCWSTR)p)); - p += lstrlenW((LPCWSTR)p) + 1; - - if (dwFlags & PSP_USETITLE) - { - WCHAR szTitle[256]; - const WCHAR *pTitle; - static const WCHAR pszNull[] = { '(','n','u','l','l',')',0 }; - int len; - - if ( !HIWORD( lppsp->pszTitle ) ) - { - if (!LoadStringW( lppsp->hInstance, (UINT)lppsp->pszTitle,szTitle,sizeof(szTitle) )) - { - pTitle = pszNull; - FIXME("Could not load resource #%04x?\n",LOWORD(lppsp->pszTitle)); - } - else - pTitle = szTitle; - } - else - pTitle = lppsp->pszTitle; - - len = strlenW(pTitle); - psInfo->proppage[index].pszText = Alloc( (len+1)*sizeof (WCHAR) ); - strcpyW( (LPWSTR)psInfo->proppage[index].pszText,pTitle); - } - - /* - * Build the image list for icons - */ - if ((dwFlags & PSP_USEHICON) || (dwFlags & PSP_USEICONID)) - { - HICON hIcon; - int icon_cx = GetSystemMetrics(SM_CXSMICON); - int icon_cy = GetSystemMetrics(SM_CYSMICON); - - if (dwFlags & PSP_USEICONID) - hIcon = LoadImageW(lppsp->hInstance, lppsp->u2.pszIcon, IMAGE_ICON, - icon_cx, icon_cy, LR_DEFAULTCOLOR); - else - hIcon = lppsp->u2.hIcon; - - if ( hIcon ) - { - if (psInfo->hImageList == 0 ) - psInfo->hImageList = ImageList_Create(icon_cx, icon_cy, ILC_COLOR, 1, 1); - - ImageList_AddIcon(psInfo->hImageList, hIcon); - } - - } - - return TRUE; -} - -/****************************************************************************** - * PROPSHEET_CreateDialog - * - * Creates the actual property sheet. - */ -int PROPSHEET_CreateDialog(PropSheetInfo* psInfo) -{ - LRESULT ret; - LPCVOID template; - LPVOID temp = 0; - HRSRC hRes; - DWORD resSize; - WORD resID = IDD_PROPSHEET; - - TRACE("\n"); - if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) - resID = IDD_WIZARD; - - if( psInfo->unicode ) - { - if(!(hRes = FindResourceW(COMCTL32_hModule, - MAKEINTRESOURCEW(resID), - (LPWSTR)RT_DIALOG))) - return -1; - } - else - { - if(!(hRes = FindResourceA(COMCTL32_hModule, - MAKEINTRESOURCEA(resID), - (LPSTR)RT_DIALOG))) - return -1; - } - - if(!(template = (LPVOID)LoadResource(COMCTL32_hModule, hRes))) - return -1; - - /* - * Make a copy of the dialog template. - */ - resSize = SizeofResource(COMCTL32_hModule, hRes); - - temp = Alloc(resSize); - - if (!temp) - return -1; - - memcpy(temp, template, resSize); - - if (psInfo->ppshheader.dwFlags & PSH_NOCONTEXTHELP) - { - if (((MyDLGTEMPLATEEX*)temp)->signature == 0xFFFF) - ((MyDLGTEMPLATEEX*)temp)->style &= ~DS_CONTEXTHELP; - else - ((DLGTEMPLATE*)temp)->style &= ~DS_CONTEXTHELP; - } - if ((psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) && - (psInfo->ppshheader.dwFlags & PSH_WIZARDCONTEXTHELP)) - { - if (((MyDLGTEMPLATEEX*)temp)->signature == 0xFFFF) - ((MyDLGTEMPLATEEX*)temp)->style |= DS_CONTEXTHELP; - else - ((DLGTEMPLATE*)temp)->style |= DS_CONTEXTHELP; - } - - if (psInfo->useCallback) - (*(psInfo->ppshheader.pfnCallback))(0, PSCB_PRECREATE, (LPARAM)temp); - - /* NOTE: MSDN states "Returns a positive value if successful, or -1 - * otherwise for modal property sheets.", but this is wrong. The - * actual return value is either TRUE (success), FALSE (cancel) or - * -1 (error). */ - if( psInfo->unicode ) - { - ret = (int)CreateDialogIndirectParamW(psInfo->ppshheader.hInstance, - (LPDLGTEMPLATEW) temp, - psInfo->ppshheader.hwndParent, - PROPSHEET_DialogProc, - (LPARAM)psInfo); - if ( !ret ) ret = -1; - } - else - { - ret = (int)CreateDialogIndirectParamA(psInfo->ppshheader.hInstance, - (LPDLGTEMPLATEA) temp, - psInfo->ppshheader.hwndParent, - PROPSHEET_DialogProc, - (LPARAM)psInfo); - if ( !ret ) ret = -1; - } - - Free(temp); - - return ret; -} - -/****************************************************************************** - * PROPSHEET_SizeMismatch - * - * Verify that the tab control and the "largest" property sheet page dlg. template - * match in size. - */ -static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo) -{ - HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL); - RECT rcOrigTab, rcPage; - - /* - * Original tab size. - */ - GetClientRect(hwndTabCtrl, &rcOrigTab); - TRACE("orig tab %ld %ld %ld %ld\n", rcOrigTab.left, rcOrigTab.top, - rcOrigTab.right, rcOrigTab.bottom); - - /* - * Biggest page size. - */ - rcPage.left = 0; - rcPage.top = 0; - rcPage.right = psInfo->width; - rcPage.bottom = psInfo->height; - - MapDialogRect(hwndDlg, &rcPage); - TRACE("biggest page %ld %ld %ld %ld\n", rcPage.left, rcPage.top, - rcPage.right, rcPage.bottom); - - if ( (rcPage.right - rcPage.left) != (rcOrigTab.right - rcOrigTab.left) ) - return TRUE; - if ( (rcPage.bottom - rcPage.top) != (rcOrigTab.bottom - rcOrigTab.top) ) - return TRUE; - - return FALSE; -} - -/****************************************************************************** - * PROPSHEET_AdjustSize - * - * Resizes the property sheet and the tab control to fit the largest page. - */ -static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo) -{ - HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL); - HWND hwndButton = GetDlgItem(hwndDlg, IDOK); - RECT rc,tabRect; - int tabOffsetX, tabOffsetY, buttonHeight; - PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndDlg); - RECT units; - - /* Get the height of buttons */ - GetClientRect(hwndButton, &rc); - buttonHeight = rc.bottom; - - /* - * Biggest page size. - */ - rc.left = 0; - rc.top = 0; - rc.right = psInfo->width; - rc.bottom = psInfo->height; - - MapDialogRect(hwndDlg, &rc); - - /* retrieve the dialog units */ - units.left = units.right = 4; - units.top = units.bottom = 8; - MapDialogRect(hwndDlg, &units); - - /* - * Resize the tab control. - */ - GetClientRect(hwndTabCtrl,&tabRect); - - SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&tabRect); - - if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top)) - { - rc.bottom = rc.top + tabRect.bottom - tabRect.top; - psInfo->height = MulDiv((rc.bottom - rc.top),8,units.top); - } - - if ((rc.right - rc.left) < (tabRect.right - tabRect.left)) - { - rc.right = rc.left + tabRect.right - tabRect.left; - psInfo->width = MulDiv((rc.right - rc.left),4,units.left); - } - - SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, TRUE, (LPARAM)&rc); - - tabOffsetX = -(rc.left); - tabOffsetY = -(rc.top); - - rc.right -= rc.left; - rc.bottom -= rc.top; - TRACE("setting tab %08lx, rc (0,0)-(%ld,%ld)\n", - (DWORD)hwndTabCtrl, rc.right, rc.bottom); - SetWindowPos(hwndTabCtrl, 0, 0, 0, rc.right, rc.bottom, - SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); - - GetClientRect(hwndTabCtrl, &rc); - - TRACE("tab client rc %ld %ld %ld %ld\n", - rc.left, rc.top, rc.right, rc.bottom); - - rc.right += ((padding.x * 2) + tabOffsetX); - rc.bottom += (buttonHeight + (3 * padding.y) + tabOffsetY); - - /* - * Resize the property sheet. - */ - TRACE("setting dialog %08lx, rc (0,0)-(%ld,%ld)\n", - (DWORD)hwndDlg, rc.right, rc.bottom); - SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom, - SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); - return TRUE; -} - -/****************************************************************************** - * PROPSHEET_AdjustSizeWizard - * - * Resizes the property sheet to fit the largest page. - */ -static BOOL PROPSHEET_AdjustSizeWizard(HWND hwndDlg, PropSheetInfo* psInfo) -{ - HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE); - RECT rc, lineRect, dialogRect; - - /* Biggest page size */ - rc.left = 0; - rc.top = 0; - rc.right = psInfo->width; - rc.bottom = psInfo->height; - MapDialogRect(hwndDlg, &rc); - - TRACE("Biggest page %ld %ld %ld %ld\n", rc.left, rc.top, rc.right, rc.bottom); - - /* Add space for the buttons row */ - GetWindowRect(hwndLine, &lineRect); - MapWindowPoints(NULL, hwndDlg, (LPPOINT)&lineRect, 2); - GetClientRect(hwndDlg, &dialogRect); - rc.bottom += dialogRect.bottom - lineRect.top - 1; - - /* Convert the client coordinates to window coordinates */ - AdjustWindowRect(&rc, GetWindowLongW(hwndDlg, GWL_STYLE), FALSE); - - /* Resize the property sheet */ - TRACE("setting dialog %08lx, rc (0,0)-(%ld,%ld)\n", - (DWORD)hwndDlg, rc.right, rc.bottom); - SetWindowPos(hwndDlg, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top, - SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); - - return TRUE; -} - -/****************************************************************************** - * PROPSHEET_AdjustButtons - * - * Adjusts the buttons' positions. - */ -static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo) -{ - HWND hwndButton = GetDlgItem(hwndParent, IDOK); - RECT rcSheet; - int x, y; - int num_buttons = 2; - int buttonWidth, buttonHeight; - PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent); - - if (psInfo->hasApply) - num_buttons++; - - if (psInfo->hasHelp) - num_buttons++; - - /* - * Obtain the size of the buttons. - */ - GetClientRect(hwndButton, &rcSheet); - buttonWidth = rcSheet.right; - buttonHeight = rcSheet.bottom; - - /* - * Get the size of the property sheet. - */ - GetClientRect(hwndParent, &rcSheet); - - /* - * All buttons will be at this y coordinate. - */ - y = rcSheet.bottom - (padding.y + buttonHeight); - - /* - * Position OK button and make it default. - */ - hwndButton = GetDlgItem(hwndParent, IDOK); - - x = rcSheet.right - ((padding.x + buttonWidth) * num_buttons); - - SetWindowPos(hwndButton, 0, x, y, 0, 0, - SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); - - SendMessageW(hwndParent, DM_SETDEFID, IDOK, 0); - - - /* - * Position Cancel button. - */ - hwndButton = GetDlgItem(hwndParent, IDCANCEL); - - x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1)); - - SetWindowPos(hwndButton, 0, x, y, 0, 0, - SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); - - /* - * Position Apply button. - */ - hwndButton = GetDlgItem(hwndParent, IDC_APPLY_BUTTON); - - if (psInfo->hasApply) - { - if (psInfo->hasHelp) - x = rcSheet.right - ((padding.x + buttonWidth) * 2); - else - x = rcSheet.right - (padding.x + buttonWidth); - - SetWindowPos(hwndButton, 0, x, y, 0, 0, - SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); - - EnableWindow(hwndButton, FALSE); - } - else - ShowWindow(hwndButton, SW_HIDE); - - /* - * Position Help button. - */ - hwndButton = GetDlgItem(hwndParent, IDHELP); - - if (psInfo->hasHelp) - { - x = rcSheet.right - (padding.x + buttonWidth); - - SetWindowPos(hwndButton, 0, x, y, 0, 0, - SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); - } - else - ShowWindow(hwndButton, SW_HIDE); - - return TRUE; -} - -/****************************************************************************** - * PROPSHEET_AdjustButtonsWizard - * - * Adjusts the buttons' positions. - */ -static BOOL PROPSHEET_AdjustButtonsWizard(HWND hwndParent, - PropSheetInfo* psInfo) -{ - HWND hwndButton = GetDlgItem(hwndParent, IDCANCEL); - HWND hwndLine = GetDlgItem(hwndParent, IDC_SUNKEN_LINE); - HWND hwndLineHeader = GetDlgItem(hwndParent, IDC_SUNKEN_LINEHEADER); - RECT rcSheet; - int x, y; - int num_buttons = 3; - int buttonWidth, buttonHeight, lineHeight, lineWidth; - PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndParent, psInfo); - - if (psInfo->hasHelp) - num_buttons++; - - /* - * Obtain the size of the buttons. - */ - GetClientRect(hwndButton, &rcSheet); - buttonWidth = rcSheet.right; - buttonHeight = rcSheet.bottom; - - GetClientRect(hwndLine, &rcSheet); - lineHeight = rcSheet.bottom; - - /* - * Get the size of the property sheet. - */ - GetClientRect(hwndParent, &rcSheet); - - /* - * All buttons will be at this y coordinate. - */ - y = rcSheet.bottom - (padding.y + buttonHeight); - - /* - * Position the Next and the Finish buttons. - */ - hwndButton = GetDlgItem(hwndParent, IDC_NEXT_BUTTON); - - x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1)); - - SetWindowPos(hwndButton, 0, x, y, 0, 0, - SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); - - hwndButton = GetDlgItem(hwndParent, IDC_FINISH_BUTTON); - - SetWindowPos(hwndButton, 0, x, y, 0, 0, - SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); - - ShowWindow(hwndButton, SW_HIDE); - - /* - * Position the Back button. - */ - hwndButton = GetDlgItem(hwndParent, IDC_BACK_BUTTON); - - x -= buttonWidth; - - SetWindowPos(hwndButton, 0, x, y, 0, 0, - SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); - - /* - * Position the Cancel button. - */ - hwndButton = GetDlgItem(hwndParent, IDCANCEL); - - x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 2)); - - SetWindowPos(hwndButton, 0, x, y, 0, 0, - SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); - - /* - * Position Help button. - */ - hwndButton = GetDlgItem(hwndParent, IDHELP); - - if (psInfo->hasHelp) - { - x = rcSheet.right - (padding.x + buttonWidth); - - SetWindowPos(hwndButton, 0, x, y, 0, 0, - SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); - } - else - ShowWindow(hwndButton, SW_HIDE); - - if (psInfo->ppshheader.dwFlags & - (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW | PSH_WIZARD_LITE)) - padding.x = 0; - - /* - * Position and resize the sunken line. - */ - x = padding.x; - y = rcSheet.bottom - ((padding.y * 2) + buttonHeight + lineHeight); - - lineWidth = rcSheet.right - (padding.x * 2); - SetWindowPos(hwndLine, 0, x, y, lineWidth, 2, - SWP_NOZORDER | SWP_NOACTIVATE); - - /* - * Position and resize the header sunken line. - */ - - SetWindowPos(hwndLineHeader, 0, 0, 0, rcSheet.right, 2, - SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); - if (!(psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW))) - ShowWindow(hwndLineHeader, SW_HIDE); - - return TRUE; -} - -/****************************************************************************** - * PROPSHEET_GetPaddingInfo - * - * Returns the layout information. - */ -static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg) -{ - HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABCONTROL); - RECT rcTab; - POINT tl; - PADDING_INFO padding; - - GetWindowRect(hwndTab, &rcTab); - - tl.x = rcTab.left; - tl.y = rcTab.top; - - ScreenToClient(hwndDlg, &tl); - - padding.x = tl.x; - padding.y = tl.y; - - return padding; -} - -/****************************************************************************** - * PROPSHEET_GetPaddingInfoWizard - * - * Returns the layout information. - * Vertical spacing is the distance between the line and the buttons. - * Do NOT use the Help button to gather padding information when it isn't mapped - * (PSH_HASHELP), as app writers aren't forced to supply correct coordinates - * for it in this case ! - * FIXME: I'm not sure about any other coordinate problems with these evil - * buttons. Fix it in case additional problems appear or maybe calculate - * a padding in a completely different way, as this is somewhat messy. - */ -static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo* - psInfo) -{ - PADDING_INFO padding; - RECT rc; - HWND hwndControl; - INT idButton; - POINT ptButton, ptLine; - - TRACE("\n"); - if (psInfo->hasHelp) - { - idButton = IDHELP; - } - else - { - if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) - { - idButton = IDC_NEXT_BUTTON; - } - else - { - /* hopefully this is ok */ - idButton = IDCANCEL; - } - } - - hwndControl = GetDlgItem(hwndDlg, idButton); - GetWindowRect(hwndControl, &rc); - - ptButton.x = rc.left; - ptButton.y = rc.top; - - ScreenToClient(hwndDlg, &ptButton); - - /* Line */ - hwndControl = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE); - GetWindowRect(hwndControl, &rc); - - ptLine.x = rc.left; - ptLine.y = rc.bottom; - - ScreenToClient(hwndDlg, &ptLine); - - padding.y = ptButton.y - ptLine.y; - - if (padding.y < 0) - ERR("padding negative ! Please report this !\n"); - - /* this is most probably not correct, but the best we have now */ - padding.x = padding.y; - return padding; -} - -/****************************************************************************** - * PROPSHEET_CreateTabControl - * - * Insert the tabs in the tab control. - */ -static BOOL PROPSHEET_CreateTabControl(HWND hwndParent, - PropSheetInfo * psInfo) -{ - HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL); - TCITEMW item; - int i, nTabs; - int iImage = 0; - - TRACE("\n"); - item.mask = TCIF_TEXT; - item.cchTextMax = MAX_TABTEXT_LENGTH; - - nTabs = psInfo->nPages; - - /* - * Set the image list for icons. - */ - if (psInfo->hImageList) - { - SendMessageW(hwndTabCtrl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList); - } - - SendMessageW(GetDlgItem(hwndTabCtrl, IDC_TABCONTROL), WM_SETREDRAW, 0, 0); - for (i = 0; i < nTabs; i++) - { - if ( psInfo->proppage[i].hasIcon ) - { - item.mask |= TCIF_IMAGE; - item.iImage = iImage++; - } - else - { - item.mask &= ~TCIF_IMAGE; - } - - item.pszText = (LPWSTR) psInfo->proppage[i].pszText; - SendMessageW(hwndTabCtrl, TCM_INSERTITEMW, (WPARAM)i, (LPARAM)&item); - } - SendMessageW(GetDlgItem(hwndTabCtrl, IDC_TABCONTROL), WM_SETREDRAW, 1, 0); - - return TRUE; -} - -/****************************************************************************** - * PROPSHEET_WizardSubclassProc - * - * Subclassing window procedure for wizard extrior pages to prevent drawing - * background and so drawing above the watermark. - */ -static LRESULT CALLBACK -PROPSHEET_WizardSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uID, DWORD_PTR dwRef) -{ - switch (uMsg) - { - case WM_ERASEBKGND: - return TRUE; - - case WM_CTLCOLORSTATIC: - SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW)); - return (INT_PTR)GetSysColorBrush(COLOR_WINDOW); - } - - return DefSubclassProc(hwnd, uMsg, wParam, lParam); -} - -/* - * Get the size of an in-memory Template - * - *( Based on the code of PROPSHEET_CollectPageInfo) - * See also dialog.c/DIALOG_ParseTemplate32(). - */ - -static UINT GetTemplateSize(DLGTEMPLATE* pTemplate) - -{ - const WORD* p = (const WORD *)pTemplate; - BOOL istemplateex = (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF); - WORD nrofitems; - - if (istemplateex) - { - /* DLGTEMPLATEEX (not defined in any std. header file) */ - - TRACE("is DLGTEMPLATEEX\n"); - p++; /* dlgVer */ - p++; /* signature */ - p += 2; /* help ID */ - p += 2; /* ext style */ - p += 2; /* style */ - } - else - { - /* DLGTEMPLATE */ - - TRACE("is DLGTEMPLATE\n"); - p += 2; /* style */ - p += 2; /* ext style */ - } - - nrofitems = (WORD)*p; p++; /* nb items */ - p++; /* x */ - p++; /* y */ - p++; /* width */ - p++; /* height */ - - /* menu */ - switch ((WORD)*p) - { - case 0x0000: - p++; - break; - case 0xffff: - p += 2; - break; - default: - TRACE("menu %s\n",debugstr_w((LPCWSTR)p)); - p += lstrlenW( (LPCWSTR)p ) + 1; - break; - } - - /* class */ - switch ((WORD)*p) - { - case 0x0000: - p++; - break; - case 0xffff: - p += 2; /* 0xffff plus predefined window class ordinal value */ - break; - default: - TRACE("class %s\n",debugstr_w((LPCWSTR)p)); - p += lstrlenW( (LPCWSTR)p ) + 1; - break; - } - - /* title */ - TRACE("title %s\n",debugstr_w((LPCWSTR)p)); - p += lstrlenW((LPCWSTR)p) + 1; - - /* font, if DS_SETFONT set */ - if ((DS_SETFONT & ((istemplateex)? ((MyDLGTEMPLATEEX*)pTemplate)->style : - pTemplate->style))) - { - p+=(istemplateex)?3:1; - TRACE("font %s\n",debugstr_w((LPCWSTR)p)); - p += lstrlenW( (LPCWSTR)p ) + 1; /* the font name */ - } - - /* now process the DLGITEMTEMPLATE(EX) structs (plus custom data) - * that are following the DLGTEMPLATE(EX) data */ - TRACE("%d items\n",nrofitems); - while (nrofitems > 0) - { - p = (WORD*)(((DWORD)p + 3) & ~3); /* DWORD align */ - - /* skip header */ - p += (istemplateex ? sizeof(MyDLGITEMTEMPLATEEX) : sizeof(DLGITEMTEMPLATE))/sizeof(WORD); - - /* check class */ - switch ((WORD)*p) - { - case 0x0000: - p++; - break; - case 0xffff: - TRACE("class ordinal 0x%08lx\n",*(DWORD*)p); - p += 2; - break; - default: - TRACE("class %s\n",debugstr_w((LPCWSTR)p)); - p += lstrlenW( (LPCWSTR)p ) + 1; - break; - } - - /* check title text */ - switch ((WORD)*p) - { - case 0x0000: - p++; - break; - case 0xffff: - TRACE("text ordinal 0x%08lx\n",*(DWORD*)p); - p += 2; - break; - default: - TRACE("text %s\n",debugstr_w((LPCWSTR)p)); - p += lstrlenW( (LPCWSTR)p ) + 1; - break; - } - p += *p / sizeof(WORD) + 1; /* Skip extra data */ - --nrofitems; - } - - TRACE("%p %p size 0x%08x\n",p, (WORD*)pTemplate,sizeof(WORD)*(p - (WORD*)pTemplate)); - return (p - (WORD*)pTemplate)*sizeof(WORD); - -} - -/****************************************************************************** - * PROPSHEET_CreatePage - * - * Creates a page. - */ -static BOOL PROPSHEET_CreatePage(HWND hwndParent, - int index, - const PropSheetInfo * psInfo, - LPCPROPSHEETPAGEW ppshpage) -{ - DLGTEMPLATE* pTemplate; - HWND hwndPage; - DWORD resSize; - LPVOID temp = NULL; - - TRACE("index %d\n", index); - - if (ppshpage == NULL) - { - return FALSE; - } - - if (ppshpage->dwFlags & PSP_DLGINDIRECT) - { - pTemplate = (DLGTEMPLATE*)ppshpage->u.pResource; - resSize = GetTemplateSize(pTemplate); - } - else if(ppshpage->dwFlags & PSP_INTERNAL_UNICODE) - { - HRSRC hResource; - HANDLE hTemplate; - - hResource = FindResourceW(ppshpage->hInstance, - ppshpage->u.pszTemplate, - (LPWSTR)RT_DIALOG); - if(!hResource) - return FALSE; - - resSize = SizeofResource(ppshpage->hInstance, hResource); - - hTemplate = LoadResource(ppshpage->hInstance, hResource); - if(!hTemplate) - return FALSE; - - pTemplate = (LPDLGTEMPLATEW)LockResource(hTemplate); - /* - * Make a copy of the dialog template to make it writable - */ - } - else - { - HRSRC hResource; - HANDLE hTemplate; - - hResource = FindResourceA(ppshpage->hInstance, - (LPSTR)ppshpage->u.pszTemplate, - (LPSTR)RT_DIALOG); - if(!hResource) - return FALSE; - - resSize = SizeofResource(ppshpage->hInstance, hResource); - - hTemplate = LoadResource(ppshpage->hInstance, hResource); - if(!hTemplate) - return FALSE; - - pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate); - /* - * Make a copy of the dialog template to make it writable - */ - } - temp = Alloc(resSize); - if (!temp) - return FALSE; - - TRACE("copying pTemplate %p into temp %p (%ld)\n", pTemplate, temp, resSize); - memcpy(temp, pTemplate, resSize); - pTemplate = temp; - - if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF) - { - ((MyDLGTEMPLATEEX*)pTemplate)->style |= WS_CHILD | WS_TABSTOP | DS_CONTROL; - ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~DS_MODALFRAME; - ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_CAPTION; - ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_SYSMENU; - ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_POPUP; - ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_DISABLED; - ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_VISIBLE; - ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_THICKFRAME; - - ((MyDLGTEMPLATEEX*)pTemplate)->exStyle |= WS_EX_CONTROLPARENT; - } - else - { - pTemplate->style |= WS_CHILD | WS_TABSTOP | DS_CONTROL; - pTemplate->style &= ~DS_MODALFRAME; - pTemplate->style &= ~WS_CAPTION; - pTemplate->style &= ~WS_SYSMENU; - pTemplate->style &= ~WS_POPUP; - pTemplate->style &= ~WS_DISABLED; - pTemplate->style &= ~WS_VISIBLE; - pTemplate->style &= ~WS_THICKFRAME; - - pTemplate->dwExtendedStyle |= WS_EX_CONTROLPARENT; - } - - if (psInfo->proppage[index].useCallback) - (*(ppshpage->pfnCallback))(0, PSPCB_CREATE, - (LPPROPSHEETPAGEW)ppshpage); - - if(ppshpage->dwFlags & PSP_INTERNAL_UNICODE) - hwndPage = CreateDialogIndirectParamW(ppshpage->hInstance, - pTemplate, - hwndParent, - ppshpage->pfnDlgProc, - (LPARAM)ppshpage); - else - hwndPage = CreateDialogIndirectParamA(ppshpage->hInstance, - pTemplate, - hwndParent, - ppshpage->pfnDlgProc, - (LPARAM)ppshpage); - /* Free a no more needed copy */ - if(temp) - Free(temp); - - psInfo->proppage[index].hwndPage = hwndPage; - - /* Subclass exterior wizard pages */ - if((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) && - (psInfo->ppshheader.dwFlags & PSH_WATERMARK) && - (ppshpage->dwFlags & PSP_HIDEHEADER)) - { - SetWindowSubclass(hwndPage, PROPSHEET_WizardSubclassProc, 1, - (DWORD_PTR)ppshpage); - } - - return TRUE; -} - -/****************************************************************************** - * PROPSHEET_LoadWizardBitmaps - * - * Loads the watermark and header bitmaps for a wizard. - */ -static VOID PROPSHEET_LoadWizardBitmaps(PropSheetInfo *psInfo) -{ - if (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) - { - /* if PSH_USEHBMWATERMARK is not set, load the resource from pszbmWatermark - and put the HBITMAP in hbmWatermark. Thus all the rest of the code always - considers hbmWatermark as valid. */ - if ((psInfo->ppshheader.dwFlags & PSH_WATERMARK) && - !(psInfo->ppshheader.dwFlags & PSH_USEHBMWATERMARK)) - { - ((PropSheetInfo *)psInfo)->ppshheader.u4.hbmWatermark = - CreateMappedBitmap(psInfo->ppshheader.hInstance, (INT)psInfo->ppshheader.u4.pszbmWatermark, 0, NULL, 0); - } - - /* Same behavior as for watermarks */ - if ((psInfo->ppshheader.dwFlags & PSH_HEADER) && - !(psInfo->ppshheader.dwFlags & PSH_USEHBMHEADER)) - { - ((PropSheetInfo *)psInfo)->ppshheader.u5.hbmHeader = - CreateMappedBitmap(psInfo->ppshheader.hInstance, (INT)psInfo->ppshheader.u5.pszbmHeader, 0, NULL, 0); - } - } -} - - -/****************************************************************************** - * PROPSHEET_ShowPage - * - * Displays or creates the specified page. - */ -static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo) -{ - HWND hwndTabCtrl; - HWND hwndLineHeader; - LPCPROPSHEETPAGEW ppshpage; - - TRACE("active_page %d, index %d\n", psInfo->active_page, index); - if (index == psInfo->active_page) - { - if (GetTopWindow(hwndDlg) != psInfo->proppage[index].hwndPage) - SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); - return TRUE; - } - - ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage; - if (psInfo->proppage[index].hwndPage == 0) - { - PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage); - } - - if ((psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) && - (ppshpage->dwFlags & PSP_USETITLE)) - { - PROPSHEET_SetTitleW(hwndDlg, psInfo->ppshheader.dwFlags, - psInfo->proppage[index].pszText); - } - - if (psInfo->active_page != -1) - ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE); - - ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW); - - /* Synchronize current selection with tab control - * It seems to be needed even in case of PSH_WIZARD (no tab controls there) */ - hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL); - SendMessageW(hwndTabCtrl, TCM_SETCURSEL, index, 0); - - psInfo->active_page = index; - psInfo->activeValid = TRUE; - - if (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW) ) - { - hwndLineHeader = GetDlgItem(hwndDlg, IDC_SUNKEN_LINEHEADER); - ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage; - - if ((ppshpage->dwFlags & PSP_HIDEHEADER) || (!(psInfo->ppshheader.dwFlags & PSH_HEADER)) ) - ShowWindow(hwndLineHeader, SW_HIDE); - else - ShowWindow(hwndLineHeader, SW_SHOW); - } - - InvalidateRgn(hwndDlg, NULL, TRUE); - UpdateWindow(hwndDlg); - - return TRUE; -} - -/****************************************************************************** - * PROPSHEET_Back - */ -static BOOL PROPSHEET_Back(HWND hwndDlg) -{ - PSHNOTIFY psn; - HWND hwndPage; - PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, - PropSheetInfoStr); - LRESULT result; - int idx; - - TRACE("active_page %d\n", psInfo->active_page); - if (psInfo->active_page < 0) - return FALSE; - - psn.hdr.code = PSN_WIZBACK; - psn.hdr.hwndFrom = hwndDlg; - psn.hdr.idFrom = 0; - psn.lParam = 0; - - hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; - - result = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); - if (result == -1) - return FALSE; - else if (result == 0) - idx = psInfo->active_page - 1; - else - idx = PROPSHEET_FindPageByResId(psInfo, result); - - if (idx >= 0 && idx < psInfo->nPages) - { - if (PROPSHEET_CanSetCurSel(hwndDlg)) - PROPSHEET_SetCurSel(hwndDlg, idx, -1, 0); - } - return TRUE; -} - -/****************************************************************************** - * PROPSHEET_Next - */ -static BOOL PROPSHEET_Next(HWND hwndDlg) -{ - PSHNOTIFY psn; - HWND hwndPage; - LRESULT msgResult = 0; - PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, - PropSheetInfoStr); - int idx; - - TRACE("active_page %d\n", psInfo->active_page); - if (psInfo->active_page < 0) - return FALSE; - - psn.hdr.code = PSN_WIZNEXT; - psn.hdr.hwndFrom = hwndDlg; - psn.hdr.idFrom = 0; - psn.lParam = 0; - - hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; - - msgResult = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); - if (msgResult == -1) - return FALSE; - else if (msgResult == 0) - idx = psInfo->active_page + 1; - else - idx = PROPSHEET_FindPageByResId(psInfo, msgResult); - - if (idx < psInfo->nPages ) - { - if (PROPSHEET_CanSetCurSel(hwndDlg) != FALSE) - PROPSHEET_SetCurSel(hwndDlg, idx, 1, 0); - } - - return TRUE; -} - -/****************************************************************************** - * PROPSHEET_Finish - */ -static BOOL PROPSHEET_Finish(HWND hwndDlg) -{ - PSHNOTIFY psn; - HWND hwndPage; - LRESULT msgResult = 0; - PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, - PropSheetInfoStr); - - TRACE("active_page %d\n", psInfo->active_page); - if (psInfo->active_page < 0) - return FALSE; - - psn.hdr.code = PSN_WIZFINISH; - psn.hdr.hwndFrom = hwndDlg; - psn.hdr.idFrom = 0; - psn.lParam = 0; - - hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; - - msgResult = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); - - TRACE("msg result %ld\n", msgResult); - - if (msgResult != 0) - return FALSE; - - if (psInfo->isModeless) - psInfo->activeValid = FALSE; - else - psInfo->ended = TRUE; - - return TRUE; -} - -/****************************************************************************** - * PROPSHEET_Apply - */ -static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam) -{ - int i; - HWND hwndPage; - PSHNOTIFY psn; - PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, - PropSheetInfoStr); - - TRACE("active_page %d\n", psInfo->active_page); - if (psInfo->active_page < 0) - return FALSE; - - psn.hdr.hwndFrom = hwndDlg; - psn.hdr.idFrom = 0; - psn.lParam = 0; - - - /* - * Send PSN_KILLACTIVE to the current page. - */ - psn.hdr.code = PSN_KILLACTIVE; - - hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; - - if (SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) != FALSE) - return FALSE; - - /* - * Send PSN_APPLY to all pages. - */ - psn.hdr.code = PSN_APPLY; - psn.lParam = lParam; - - for (i = 0; i < psInfo->nPages; i++) - { - hwndPage = psInfo->proppage[i].hwndPage; - if (hwndPage) - { - switch (SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn)) - { - case PSNRET_INVALID: - PROPSHEET_ShowPage(hwndDlg, i, psInfo); - /* fall through */ - case PSNRET_INVALID_NOCHANGEPAGE: - return FALSE; - } - } - } - - if(lParam) - { - psInfo->activeValid = FALSE; - } - else if(psInfo->active_page >= 0) - { - psn.hdr.code = PSN_SETACTIVE; - psn.lParam = 0; - hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; - SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); - } - - return TRUE; -} - -/****************************************************************************** - * PROPSHEET_Cancel - */ -static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam) -{ - PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, - PropSheetInfoStr); - HWND hwndPage; - PSHNOTIFY psn; - int i; - - TRACE("active_page %d\n", psInfo->active_page); - if (psInfo->active_page < 0) - return; - - hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; - psn.hdr.code = PSN_QUERYCANCEL; - psn.hdr.hwndFrom = hwndDlg; - psn.hdr.idFrom = 0; - psn.lParam = 0; - - if (SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn)) - return; - - psn.hdr.code = PSN_RESET; - psn.lParam = lParam; - - for (i = 0; i < psInfo->nPages; i++) - { - hwndPage = psInfo->proppage[i].hwndPage; - - if (hwndPage) - SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); - } - - if (psInfo->isModeless) - { - /* makes PSM_GETCURRENTPAGEHWND return NULL */ - psInfo->activeValid = FALSE; - } - else - psInfo->ended = TRUE; -} - -/****************************************************************************** - * PROPSHEET_Help - */ -static void PROPSHEET_Help(HWND hwndDlg) -{ - PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, - PropSheetInfoStr); - HWND hwndPage; - PSHNOTIFY psn; - - TRACE("active_page %d\n", psInfo->active_page); - if (psInfo->active_page < 0) - return; - - hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; - psn.hdr.code = PSN_HELP; - psn.hdr.hwndFrom = hwndDlg; - psn.hdr.idFrom = 0; - psn.lParam = 0; - - SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); -} - -/****************************************************************************** - * PROPSHEET_Changed - */ -static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage) -{ - int i; - PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, - PropSheetInfoStr); - - TRACE("\n"); - if (!psInfo) return; - /* - * Set the dirty flag of this page. - */ - for (i = 0; i < psInfo->nPages; i++) - { - if (psInfo->proppage[i].hwndPage == hwndDirtyPage) - psInfo->proppage[i].isDirty = TRUE; - } - - /* - * Enable the Apply button. - */ - if (psInfo->hasApply) - { - HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON); - - EnableWindow(hwndApplyBtn, TRUE); - } -} - -/****************************************************************************** - * PROPSHEET_UnChanged - */ -static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage) -{ - int i; - BOOL noPageDirty = TRUE; - HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON); - PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, - PropSheetInfoStr); - - TRACE("\n"); - if ( !psInfo ) return; - for (i = 0; i < psInfo->nPages; i++) - { - /* set the specified page as clean */ - if (psInfo->proppage[i].hwndPage == hwndCleanPage) - psInfo->proppage[i].isDirty = FALSE; - - /* look to see if there's any dirty pages */ - if (psInfo->proppage[i].isDirty) - noPageDirty = FALSE; - } - - /* - * Disable Apply button. - */ - if (noPageDirty) - EnableWindow(hwndApplyBtn, FALSE); -} - -/****************************************************************************** - * PROPSHEET_PressButton - */ -static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID) -{ - TRACE("buttonID %d\n", buttonID); - switch (buttonID) - { - case PSBTN_APPLYNOW: - PROPSHEET_DoCommand(hwndDlg, IDC_APPLY_BUTTON); - break; - case PSBTN_BACK: - PROPSHEET_Back(hwndDlg); - break; - case PSBTN_CANCEL: - PROPSHEET_DoCommand(hwndDlg, IDCANCEL); - break; - case PSBTN_FINISH: - PROPSHEET_Finish(hwndDlg); - break; - case PSBTN_HELP: - PROPSHEET_DoCommand(hwndDlg, IDHELP); - break; - case PSBTN_NEXT: - PROPSHEET_Next(hwndDlg); - break; - case PSBTN_OK: - PROPSHEET_DoCommand(hwndDlg, IDOK); - break; - default: - FIXME("Invalid button index %d\n", buttonID); - } -} - - -/************************************************************************* - * BOOL PROPSHEET_CanSetCurSel [Internal] - * - * Test whether the current page can be changed by sending a PSN_KILLACTIVE - * - * PARAMS - * hwndDlg [I] handle to a Dialog hWnd - * - * RETURNS - * TRUE if Current Selection can change - * - * NOTES - */ -static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg) -{ - PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, - PropSheetInfoStr); - HWND hwndPage; - PSHNOTIFY psn; - BOOL res = FALSE; - - TRACE("active_page %d\n", psInfo->active_page); - if (!psInfo) - { - res = FALSE; - goto end; - } - - if (psInfo->active_page < 0) - { - res = TRUE; - goto end; - } - - /* - * Notify the current page. - */ - hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; - psn.hdr.code = PSN_KILLACTIVE; - psn.hdr.hwndFrom = hwndDlg; - psn.hdr.idFrom = 0; - psn.lParam = 0; - - res = !SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); - -end: - TRACE("<-- %d\n", res); - return res; -} - -/****************************************************************************** - * PROPSHEET_SetCurSel - */ -static BOOL PROPSHEET_SetCurSel(HWND hwndDlg, - int index, - int skipdir, - HPROPSHEETPAGE hpage - ) -{ - PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr); - HWND hwndHelp = GetDlgItem(hwndDlg, IDHELP); - HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL); - - TRACE("index %d, skipdir %d, hpage %p\n", index, skipdir, hpage); - /* hpage takes precedence over index */ - if (hpage != NULL) - index = PROPSHEET_GetPageIndex(hpage, psInfo); - - if (index < 0 || index >= psInfo->nPages) - { - TRACE("Could not find page to select!\n"); - return FALSE; - } - - while (1) { - int result; - PSHNOTIFY psn; - RECT rc; - LPCPROPSHEETPAGEW ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage; - - if (hwndTabControl) - SendMessageW(hwndTabControl, TCM_SETCURSEL, index, 0); - - psn.hdr.code = PSN_SETACTIVE; - psn.hdr.hwndFrom = hwndDlg; - psn.hdr.idFrom = 0; - psn.lParam = 0; - - if (!psInfo->proppage[index].hwndPage) { - PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage); - } - - /* Resize the property sheet page to the fit in the Tab control - * (for regular property sheets) or to fit in the client area (for - * wizards). - * NOTE: The resizing happens every time the page is selected and - * not only when it's created (some applications depend on it). */ - PROPSHEET_GetPageRect(psInfo, hwndDlg, &rc, ppshpage); - TRACE("setting page %p, rc (%ld,%ld)-(%ld,%ld) w=%ld, h=%ld\n", - psInfo->proppage[index].hwndPage, rc.left, rc.top, rc.right, rc.bottom, - rc.right - rc.left, rc.bottom - rc.top); - SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, - rc.left, rc.top, - rc.right - rc.left, rc.bottom - rc.top, 0); - - result = SendMessageW(psInfo->proppage[index].hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); - if (!result) - break; - if (result == -1) { - index+=skipdir; - if (index < 0) { - index = 0; - WARN("Tried to skip before first property sheet page!\n"); - break; - } - if (index >= psInfo->nPages) { - WARN("Tried to skip after last property sheet page!\n"); - index = psInfo->nPages-1; - break; - } - } - else if (result != 0) - { - int old_index = index; - index = PROPSHEET_FindPageByResId(psInfo, result); - if(index >= psInfo->nPages) { - index = old_index; - WARN("Tried to skip to nonexistant page by res id\n"); - break; - } - continue; - } - } - /* - * Display the new page. - */ - PROPSHEET_ShowPage(hwndDlg, index, psInfo); - - if (psInfo->proppage[index].hasHelp) - EnableWindow(hwndHelp, TRUE); - else - EnableWindow(hwndHelp, FALSE); - - return TRUE; -} - -/****************************************************************************** - * PROPSHEET_SetCurSelId - * - * Selects the page, specified by resource id. - */ -static void PROPSHEET_SetCurSelId(HWND hwndDlg, int id) -{ - int idx; - PropSheetInfo* psInfo = - (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr); - - idx = PROPSHEET_FindPageByResId(psInfo, id); - if (idx < psInfo->nPages ) - { - if (PROPSHEET_CanSetCurSel(hwndDlg) != FALSE) - PROPSHEET_SetCurSel(hwndDlg, idx, 1, 0); - } -} - -/****************************************************************************** - * PROPSHEET_SetTitleA - */ -static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText) -{ - if(HIWORD(lpszText)) - { - WCHAR szTitle[256]; - MultiByteToWideChar(CP_ACP, 0, lpszText, -1, - szTitle, sizeof(szTitle)); - PROPSHEET_SetTitleW(hwndDlg, dwStyle, szTitle); - } - else - { - PROPSHEET_SetTitleW(hwndDlg, dwStyle, (LPCWSTR)lpszText); - } -} - -/****************************************************************************** - * PROPSHEET_SetTitleW - */ -static void PROPSHEET_SetTitleW(HWND hwndDlg, DWORD dwStyle, LPCWSTR lpszText) -{ - PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr); - WCHAR szTitle[256]; - - TRACE("'%s' (style %08lx)\n", debugstr_w(lpszText), dwStyle); - if (HIWORD(lpszText) == 0) { - if (!LoadStringW(psInfo->ppshheader.hInstance, - LOWORD(lpszText), szTitle, sizeof(szTitle)-sizeof(WCHAR))) - return; - lpszText = szTitle; - } - if (dwStyle & PSH_PROPTITLE) - { - WCHAR* dest; - int lentitle = strlenW(lpszText); - int lenprop = strlenW(psInfo->strPropertiesFor); - - dest = Alloc( (lentitle + lenprop + 1)*sizeof (WCHAR)); - strcpyW(dest, psInfo->strPropertiesFor); - strcatW(dest, lpszText); - - SetWindowTextW(hwndDlg, dest); - Free(dest); - } - else - SetWindowTextW(hwndDlg, lpszText); -} - -/****************************************************************************** - * PROPSHEET_SetFinishTextA - */ -static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText) -{ - HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON); - - TRACE("'%s'\n", lpszText); - /* Set text, show and enable the Finish button */ - SetWindowTextA(hwndButton, lpszText); - ShowWindow(hwndButton, SW_SHOW); - EnableWindow(hwndButton, TRUE); - - /* Make it default pushbutton */ - SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0); - - /* Hide Back button */ - hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON); - ShowWindow(hwndButton, SW_HIDE); - - /* Hide Next button */ - hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON); - ShowWindow(hwndButton, SW_HIDE); -} - -/****************************************************************************** - * PROPSHEET_SetFinishTextW - */ -static void PROPSHEET_SetFinishTextW(HWND hwndDlg, LPCWSTR lpszText) -{ - HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON); - - TRACE("'%s'\n", debugstr_w(lpszText)); - /* Set text, show and enable the Finish button */ - SetWindowTextW(hwndButton, lpszText); - ShowWindow(hwndButton, SW_SHOW); - EnableWindow(hwndButton, TRUE); - - /* Make it default pushbutton */ - SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0); - - /* Hide Back button */ - hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON); - ShowWindow(hwndButton, SW_HIDE); - - /* Hide Next button */ - hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON); - ShowWindow(hwndButton, SW_HIDE); -} - -/****************************************************************************** - * PROPSHEET_QuerySiblings - */ -static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg, - WPARAM wParam, LPARAM lParam) -{ - int i = 0; - HWND hwndPage; - LRESULT msgResult = 0; - PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr); - - while ((i < psInfo->nPages) && (msgResult == 0)) - { - hwndPage = psInfo->proppage[i].hwndPage; - msgResult = SendMessageW(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam); - i++; - } - - return msgResult; -} - - -/****************************************************************************** - * PROPSHEET_AddPage - */ -static BOOL PROPSHEET_AddPage(HWND hwndDlg, - HPROPSHEETPAGE hpage) -{ - PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg, - PropSheetInfoStr); - HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL); - TCITEMW item; - LPCPROPSHEETPAGEW ppsp = (LPCPROPSHEETPAGEW)hpage; - - TRACE("hpage %p\n", hpage); - /* - * Allocate and fill in a new PropPageInfo entry. - */ - psInfo->proppage = (PropPageInfo*) ReAlloc(psInfo->proppage, - sizeof(PropPageInfo) * - (psInfo->nPages + 1)); - if (!PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages)) - return FALSE; - - psInfo->proppage[psInfo->nPages].hpage = hpage; - - if (ppsp->dwFlags & PSP_PREMATURE) - { - /* Create the page but don't show it */ - PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp); - } - - /* - * Add a new tab to the tab control. - */ - item.mask = TCIF_TEXT; - item.pszText = (LPWSTR) psInfo->proppage[psInfo->nPages].pszText; - item.cchTextMax = MAX_TABTEXT_LENGTH; - - if (psInfo->hImageList) - { - SendMessageW(hwndTabControl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList); - } - - if ( psInfo->proppage[psInfo->nPages].hasIcon ) - { - item.mask |= TCIF_IMAGE; - item.iImage = psInfo->nPages; - } - - SendMessageW(hwndTabControl, TCM_INSERTITEMW, psInfo->nPages + 1, - (LPARAM)&item); - - psInfo->nPages++; - - /* If it is the only page - show it */ - if(psInfo->nPages == 1) - PROPSHEET_SetCurSel(hwndDlg, 0, 1, 0); - return TRUE; -} - -/****************************************************************************** - * PROPSHEET_RemovePage - */ -static BOOL PROPSHEET_RemovePage(HWND hwndDlg, - int index, - HPROPSHEETPAGE hpage) -{ - PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg, - PropSheetInfoStr); - HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL); - PropPageInfo* oldPages; - - TRACE("index %d, hpage %p\n", index, hpage); - if (!psInfo) { - return FALSE; - } - /* - * hpage takes precedence over index. - */ - if (hpage != 0) - { - index = PROPSHEET_GetPageIndex(hpage, psInfo); - } - - /* Make sure that index is within range */ - if (index < 0 || index >= psInfo->nPages) - { - TRACE("Could not find page to remove!\n"); - return FALSE; - } - - TRACE("total pages %d removing page %d active page %d\n", - psInfo->nPages, index, psInfo->active_page); - /* - * Check if we're removing the active page. - */ - if (index == psInfo->active_page) - { - if (psInfo->nPages > 1) - { - if (index > 0) - { - /* activate previous page */ - PROPSHEET_SetCurSel(hwndDlg, index - 1, -1, 0); - } - else - { - /* activate the next page */ - PROPSHEET_SetCurSel(hwndDlg, index + 1, 1, 0); - psInfo->active_page = index; - } - } - else - { - psInfo->active_page = -1; - if (!psInfo->isModeless) - { - psInfo->ended = TRUE; - return TRUE; - } - } - } - else if (index < psInfo->active_page) - psInfo->active_page--; - - /* Unsubclass the page dialog window */ - if((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD) && - (psInfo->ppshheader.dwFlags & PSH_WATERMARK) && - ((PROPSHEETPAGEW*)psInfo->proppage[index].hpage)->dwFlags & PSP_HIDEHEADER)) - { - RemoveWindowSubclass(psInfo->proppage[index].hwndPage, - PROPSHEET_WizardSubclassProc, 1); - } - - /* Destroy page dialog window */ - DestroyWindow(psInfo->proppage[index].hwndPage); - - /* Free page resources */ - if(psInfo->proppage[index].hpage) - { - PROPSHEETPAGEW* psp = (PROPSHEETPAGEW*)psInfo->proppage[index].hpage; - - if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[index].pszText) - Free ((LPVOID)psInfo->proppage[index].pszText); - - DestroyPropertySheetPage(psInfo->proppage[index].hpage); - } - - /* Remove the tab */ - SendMessageW(hwndTabControl, TCM_DELETEITEM, index, 0); - - oldPages = psInfo->proppage; - psInfo->nPages--; - psInfo->proppage = Alloc(sizeof(PropPageInfo) * psInfo->nPages); - - if (index > 0) - memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo)); - - if (index < psInfo->nPages) - memcpy(&psInfo->proppage[index], &oldPages[index + 1], - (psInfo->nPages - index) * sizeof(PropPageInfo)); - - Free(oldPages); - - return FALSE; -} - -/****************************************************************************** - * PROPSHEET_SetWizButtons - * - * This code will work if (and assumes that) the Next button is on top of the - * Finish button. ie. Finish comes after Next in the Z order. - * This means make sure the dialog template reflects this. - * - */ -static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags) -{ - HWND hwndBack = GetDlgItem(hwndDlg, IDC_BACK_BUTTON); - HWND hwndNext = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON); - HWND hwndFinish = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON); - - TRACE("%ld\n", dwFlags); - - EnableWindow(hwndBack, FALSE); - EnableWindow(hwndNext, FALSE); - EnableWindow(hwndFinish, FALSE); - - if (dwFlags & PSWIZB_BACK) - EnableWindow(hwndBack, TRUE); - - if (dwFlags & PSWIZB_NEXT) - { - /* Hide the Finish button */ - ShowWindow(hwndFinish, SW_HIDE); - - /* Show and enable the Next button */ - ShowWindow(hwndNext, SW_SHOW); - EnableWindow(hwndNext, TRUE); - - /* Set the Next button as the default pushbutton */ - SendMessageW(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0); - } - - if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH)) - { - /* Hide the Next button */ - ShowWindow(hwndNext, SW_HIDE); - - /* Show the Finish button */ - ShowWindow(hwndFinish, SW_SHOW); - - if (dwFlags & PSWIZB_FINISH) - EnableWindow(hwndFinish, TRUE); - - /* Set the Finish button as the default pushbutton */ - SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0); - } -} - -/****************************************************************************** - * PROPSHEET_InsertPage - */ -static BOOL PROPSHEET_InsertPage(HWND hwndDlg, HPROPSHEETPAGE hpageInsertAfter, HPROPSHEETPAGE hpage) -{ - if (!HIWORD(hpageInsertAfter)) - FIXME("(%p, %d, %p): stub\n", hwndDlg, LOWORD(hpageInsertAfter), hpage); - else - FIXME("(%p, %p, %p): stub\n", hwndDlg, hpageInsertAfter, hpage); - return FALSE; -} - -/****************************************************************************** - * PROPSHEET_SetHeaderTitleW - */ -static void PROPSHEET_SetHeaderTitleW(HWND hwndDlg, int iPageIndex, LPCWSTR pszHeaderTitle) -{ - FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_w(pszHeaderTitle)); -} - -/****************************************************************************** - * PROPSHEET_SetHeaderTitleA - */ -static void PROPSHEET_SetHeaderTitleA(HWND hwndDlg, int iPageIndex, LPCSTR pszHeaderTitle) -{ - FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_a(pszHeaderTitle)); -} - -/****************************************************************************** - * PROPSHEET_SetHeaderSubTitleW - */ -static void PROPSHEET_SetHeaderSubTitleW(HWND hwndDlg, int iPageIndex, LPCWSTR pszHeaderSubTitle) -{ - FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_w(pszHeaderSubTitle)); -} - -/****************************************************************************** - * PROPSHEET_SetHeaderSubTitleA - */ -static void PROPSHEET_SetHeaderSubTitleA(HWND hwndDlg, int iPageIndex, LPCSTR pszHeaderSubTitle) -{ - FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_a(pszHeaderSubTitle)); -} - -/****************************************************************************** - * PROPSHEET_HwndToIndex - */ -static LRESULT PROPSHEET_HwndToIndex(HWND hwndDlg, HWND hPageDlg) -{ - int index; - PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg, - PropSheetInfoStr); - - TRACE("(%p, %p)\n", hwndDlg, hPageDlg); - - for (index = 0; index < psInfo->nPages; index++) - if (psInfo->proppage[index].hwndPage == hPageDlg) - return index; - WARN("%p not found\n", hPageDlg); - return -1; -} - -/****************************************************************************** - * PROPSHEET_IndexToHwnd - */ -static LRESULT PROPSHEET_IndexToHwnd(HWND hwndDlg, int iPageIndex) -{ - PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg, - PropSheetInfoStr); - TRACE("(%p, %d)\n", hwndDlg, iPageIndex); - if (iPageIndex<0 || iPageIndex>=psInfo->nPages) { - WARN("%d out of range.\n", iPageIndex); - return 0; - } - return (LRESULT)psInfo->proppage[iPageIndex].hwndPage; -} - -/****************************************************************************** - * PROPSHEET_PageToIndex - */ -static LRESULT PROPSHEET_PageToIndex(HWND hwndDlg, HPROPSHEETPAGE hPage) -{ - int index; - PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg, - PropSheetInfoStr); - - TRACE("(%p, %p)\n", hwndDlg, hPage); - - for (index = 0; index < psInfo->nPages; index++) - if (psInfo->proppage[index].hpage == hPage) - return index; - WARN("%p not found\n", hPage); - return -1; -} - -/****************************************************************************** - * PROPSHEET_IndexToPage - */ -static LRESULT PROPSHEET_IndexToPage(HWND hwndDlg, int iPageIndex) -{ - PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg, - PropSheetInfoStr); - TRACE("(%p, %d)\n", hwndDlg, iPageIndex); - if (iPageIndex<0 || iPageIndex>=psInfo->nPages) { - WARN("%d out of range.\n", iPageIndex); - return 0; - } - return (LRESULT)psInfo->proppage[iPageIndex].hpage; -} - -/****************************************************************************** - * PROPSHEET_IdToIndex - */ -static LRESULT PROPSHEET_IdToIndex(HWND hwndDlg, int iPageId) -{ - FIXME("(%p, %d): stub\n", hwndDlg, iPageId); - return -1; -} - -/****************************************************************************** - * PROPSHEET_IndexToId - */ -static LRESULT PROPSHEET_IndexToId(HWND hwndDlg, int iPageIndex) -{ - PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg, - PropSheetInfoStr); - LPCPROPSHEETPAGEW psp; - TRACE("(%p, %d)\n", hwndDlg, iPageIndex); - if (iPageIndex<0 || iPageIndex>=psInfo->nPages) { - WARN("%d out of range.\n", iPageIndex); - return 0; - } - psp = (LPCPROPSHEETPAGEW)psInfo->proppage[iPageIndex].hpage; - if (psp->dwFlags & PSP_DLGINDIRECT || HIWORD(psp->u.pszTemplate)) { - return 0; - } - return (LRESULT)psp->u.pszTemplate; -} - -/****************************************************************************** - * PROPSHEET_GetResult - */ -static LRESULT PROPSHEET_GetResult(HWND hwndDlg) -{ - FIXME("(%p): stub\n", hwndDlg); - return -1; -} - -/****************************************************************************** - * PROPSHEET_RecalcPageSizes - */ -static BOOL PROPSHEET_RecalcPageSizes(HWND hwndDlg) -{ - FIXME("(%p): stub\n", hwndDlg); - return FALSE; -} - -/****************************************************************************** - * PROPSHEET_GetPageIndex - * - * Given a HPROPSHEETPAGE, returns the index of the corresponding page from - * the array of PropPageInfo. - */ -static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo) -{ - BOOL found = FALSE; - int index = 0; - - TRACE("hpage %p\n", hpage); - while ((index < psInfo->nPages) && (found == FALSE)) - { - if (psInfo->proppage[index].hpage == hpage) - found = TRUE; - else - index++; - } - - if (found == FALSE) - index = -1; - - return index; -} - -/****************************************************************************** - * PROPSHEET_CleanUp - */ -static void PROPSHEET_CleanUp(HWND hwndDlg) -{ - int i; - PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropW(hwndDlg, - PropSheetInfoStr); - - TRACE("\n"); - if (!psInfo) return; - if (HIWORD(psInfo->ppshheader.pszCaption)) - Free ((LPVOID)psInfo->ppshheader.pszCaption); - - for (i = 0; i < psInfo->nPages; i++) - { - PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[i].hpage; - - /* Unsubclass the page dialog window */ - if((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) && - (psInfo->ppshheader.dwFlags & PSH_WATERMARK) && - (psp->dwFlags & PSP_HIDEHEADER)) - { - RemoveWindowSubclass(psInfo->proppage[i].hwndPage, - PROPSHEET_WizardSubclassProc, 1); - } - - if(psInfo->proppage[i].hwndPage) - DestroyWindow(psInfo->proppage[i].hwndPage); - - if(psp) - { - if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[i].pszText) - Free ((LPVOID)psInfo->proppage[i].pszText); - - DestroyPropertySheetPage(psInfo->proppage[i].hpage); - } - } - - DeleteObject(psInfo->hFont); - DeleteObject(psInfo->hFontBold); - /* If we created the bitmaps, destroy them */ - if ((psInfo->ppshheader.dwFlags & PSH_WATERMARK) && - (!(psInfo->ppshheader.dwFlags & PSH_USEHBMWATERMARK)) ) - DeleteObject(psInfo->ppshheader.u4.hbmWatermark); - if ((psInfo->ppshheader.dwFlags & PSH_HEADER) && - (!(psInfo->ppshheader.dwFlags & PSH_USEHBMHEADER)) ) - DeleteObject(psInfo->ppshheader.u5.hbmHeader); - - Free(psInfo->proppage); - Free(psInfo->strPropertiesFor); - ImageList_Destroy(psInfo->hImageList); - - GlobalFree((HGLOBAL)psInfo); -} - -static INT do_loop(PropSheetInfo *psInfo) -{ - MSG msg; - INT ret = -1; - HWND hwnd = psInfo->hwnd; - - while(IsWindow(hwnd) && !psInfo->ended && (ret = GetMessageW(&msg, NULL, 0, 0))) - { - if(ret == -1) - break; - - if(!IsDialogMessageW(hwnd, &msg)) - { - TranslateMessage(&msg); - DispatchMessageW(&msg); - } - } - - if(ret == 0) - { - PostQuitMessage(msg.wParam); - ret = -1; - } - - DestroyWindow(hwnd); - return ret; -} - -/****************************************************************************** - * PropertySheet (COMCTL32.@) - * PropertySheetA (COMCTL32.@) - * - * Creates a property sheet in the specified property sheet header. - * - * RETURNS - * Modal property sheets: Positive if successful or -1 otherwise. - * Modeless property sheets: Property sheet handle. - * Or: - *| ID_PSREBOOTSYSTEM - The user must reboot the computer for the changes to take effect. - *| ID_PSRESTARTWINDOWS - The user must restart Windows for the changes to take effect. - */ -INT WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh) -{ - int bRet = 0; - PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR, - sizeof(PropSheetInfo)); - UINT i, n; - BYTE* pByte; - - TRACE("(%p)\n", lppsh); - - PROPSHEET_CollectSheetInfoA(lppsh, psInfo); - - psInfo->proppage = (PropPageInfo*) Alloc(sizeof(PropPageInfo) * - lppsh->nPages); - pByte = (BYTE*) psInfo->ppshheader.u3.ppsp; - - for (n = i = 0; i < lppsh->nPages; i++, n++) - { - if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE)) - psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i]; - else - { - psInfo->proppage[n].hpage = CreatePropertySheetPageA((LPCPROPSHEETPAGEA)pByte); - pByte += ((LPPROPSHEETPAGEA)pByte)->dwSize; - } - - if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEW)psInfo->proppage[n].hpage, - psInfo, n)) - { - if (lppsh->dwFlags & PSH_PROPSHEETPAGE) - DestroyPropertySheetPage(psInfo->proppage[n].hpage); - n--; - psInfo->nPages--; - } - } - - psInfo->unicode = FALSE; - psInfo->ended = FALSE; - - bRet = PROPSHEET_CreateDialog(psInfo); - if(!psInfo->isModeless) - bRet = do_loop(psInfo); - - return bRet; -} - -/****************************************************************************** - * PropertySheetW (COMCTL32.@) - * - * See PropertySheetA. - */ -INT WINAPI PropertySheetW(LPCPROPSHEETHEADERW lppsh) -{ - int bRet = 0; - PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR, - sizeof(PropSheetInfo)); - UINT i, n; - BYTE* pByte; - - TRACE("(%p)\n", lppsh); - - PROPSHEET_CollectSheetInfoW(lppsh, psInfo); - - psInfo->proppage = (PropPageInfo*) Alloc(sizeof(PropPageInfo) * - lppsh->nPages); - pByte = (BYTE*) psInfo->ppshheader.u3.ppsp; - - for (n = i = 0; i < lppsh->nPages; i++, n++) - { - if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE)) - psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i]; - else - { - psInfo->proppage[n].hpage = CreatePropertySheetPageW((LPCPROPSHEETPAGEW)pByte); - pByte += ((LPPROPSHEETPAGEW)pByte)->dwSize; - } - - if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEW)psInfo->proppage[n].hpage, - psInfo, n)) - { - if (lppsh->dwFlags & PSH_PROPSHEETPAGE) - DestroyPropertySheetPage(psInfo->proppage[n].hpage); - n--; - psInfo->nPages--; - } - } - - psInfo->unicode = TRUE; - psInfo->ended = FALSE; - - bRet = PROPSHEET_CreateDialog(psInfo); - if(!psInfo->isModeless) - bRet = do_loop(psInfo); - - return bRet; -} - -/****************************************************************************** - * CreatePropertySheetPage (COMCTL32.@) - * CreatePropertySheetPageA (COMCTL32.@) - * - * Creates a new property sheet page. - * - * RETURNS - * Success: Handle to new property sheet page. - * Failure: NULL. - * - * NOTES - * An application must use the PSM_ADDPAGE message to add the new page to - * an existing property sheet. - */ -HPROPSHEETPAGE WINAPI CreatePropertySheetPageA( - LPCPROPSHEETPAGEA lpPropSheetPage) -{ - PROPSHEETPAGEW* ppsp = Alloc(sizeof(PROPSHEETPAGEW)); - - memcpy(ppsp,lpPropSheetPage,min(lpPropSheetPage->dwSize,sizeof(PROPSHEETPAGEA))); - - ppsp->dwFlags &= ~ PSP_INTERNAL_UNICODE; - if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) && HIWORD( ppsp->u.pszTemplate ) ) - { - int len = strlen(lpPropSheetPage->u.pszTemplate); - - ppsp->u.pszTemplate = Alloc( len+1 ); - strcpy( (LPSTR)ppsp->u.pszTemplate, lpPropSheetPage->u.pszTemplate ); - } - if ( (ppsp->dwFlags & PSP_USEICONID) && HIWORD( ppsp->u2.pszIcon ) ) - { - PROPSHEET_AtoW(&ppsp->u2.pszIcon, lpPropSheetPage->u2.pszIcon); - } - - if ((ppsp->dwFlags & PSP_USETITLE) && HIWORD( ppsp->pszTitle )) - { - PROPSHEET_AtoW(&ppsp->pszTitle, lpPropSheetPage->pszTitle); - } - else if ( !(ppsp->dwFlags & PSP_USETITLE) ) - ppsp->pszTitle = NULL; - - return (HPROPSHEETPAGE)ppsp; -} - -/****************************************************************************** - * CreatePropertySheetPageW (COMCTL32.@) - * - * See CreatePropertySheetA. - */ -HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage) -{ - PROPSHEETPAGEW* ppsp = Alloc(sizeof(PROPSHEETPAGEW)); - - memcpy(ppsp,lpPropSheetPage,min(lpPropSheetPage->dwSize,sizeof(PROPSHEETPAGEW))); - - ppsp->dwFlags |= PSP_INTERNAL_UNICODE; - - if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) && HIWORD( ppsp->u.pszTemplate ) ) - { - int len = strlenW(lpPropSheetPage->u.pszTemplate); - - ppsp->u.pszTemplate = Alloc( (len+1)*sizeof (WCHAR) ); - strcpyW( (WCHAR *)ppsp->u.pszTemplate, lpPropSheetPage->u.pszTemplate ); - } - if ( (ppsp->dwFlags & PSP_USEICONID) && HIWORD( ppsp->u2.pszIcon ) ) - { - int len = strlenW(lpPropSheetPage->u2.pszIcon); - ppsp->u2.pszIcon = Alloc( (len+1)*sizeof (WCHAR) ); - strcpyW( (WCHAR *)ppsp->u2.pszIcon, lpPropSheetPage->u2.pszIcon ); - } - - if ((ppsp->dwFlags & PSP_USETITLE) && HIWORD( ppsp->pszTitle )) - { - int len = strlenW(lpPropSheetPage->pszTitle); - ppsp->pszTitle = Alloc( (len+1)*sizeof (WCHAR) ); - strcpyW( (WCHAR *)ppsp->pszTitle, lpPropSheetPage->pszTitle ); - } - else if ( !(ppsp->dwFlags & PSP_USETITLE) ) - ppsp->pszTitle = NULL; - - return (HPROPSHEETPAGE)ppsp; -} - -/****************************************************************************** - * DestroyPropertySheetPage (COMCTL32.@) - * - * Destroys a property sheet page previously created with - * CreatePropertySheetA() or CreatePropertySheetW() and frees the associated - * memory. - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage) -{ - PROPSHEETPAGEW *psp = (PROPSHEETPAGEW *)hPropPage; - - if (!psp) - return FALSE; - - if ( !(psp->dwFlags & PSP_DLGINDIRECT) && HIWORD( psp->u.pszTemplate ) ) - Free ((LPVOID)psp->u.pszTemplate); - - if ( (psp->dwFlags & PSP_USEICONID) && HIWORD( psp->u2.pszIcon ) ) - Free ((LPVOID)psp->u2.pszIcon); - - if ((psp->dwFlags & PSP_USETITLE) && HIWORD( psp->pszTitle )) - Free ((LPVOID)psp->pszTitle); - - Free(hPropPage); - - return TRUE; -} - -/****************************************************************************** - * PROPSHEET_IsDialogMessage - */ -static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg) -{ - PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, PropSheetInfoStr); - - TRACE("\n"); - if (!psInfo || (hwnd != lpMsg->hwnd && !IsChild(hwnd, lpMsg->hwnd))) - return FALSE; - - if (lpMsg->message == WM_KEYDOWN && (GetKeyState(VK_CONTROL) & 0x8000)) - { - int new_page = 0; - INT dlgCode = SendMessageW(lpMsg->hwnd, WM_GETDLGCODE, 0, (LPARAM)lpMsg); - - if (!(dlgCode & DLGC_WANTMESSAGE)) - { - switch (lpMsg->wParam) - { - case VK_TAB: - if (GetKeyState(VK_SHIFT) & 0x8000) - new_page = -1; - else - new_page = 1; - break; - - case VK_NEXT: new_page = 1; break; - case VK_PRIOR: new_page = -1; break; - } - } - - if (new_page) - { - if (PROPSHEET_CanSetCurSel(hwnd) != FALSE) - { - new_page += psInfo->active_page; - - if (new_page < 0) - new_page = psInfo->nPages - 1; - else if (new_page >= psInfo->nPages) - new_page = 0; - - PROPSHEET_SetCurSel(hwnd, new_page, 1, 0); - } - - return TRUE; - } - } - - return IsDialogMessageW(hwnd, lpMsg); -} - -/****************************************************************************** - * PROPSHEET_DoCommand - */ -static BOOL PROPSHEET_DoCommand(HWND hwnd, WORD wID) -{ - - switch (wID) { - - case IDOK: - case IDC_APPLY_BUTTON: - { - HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON); - - if (PROPSHEET_Apply(hwnd, wID == IDOK ? 1: 0) == FALSE) - break; - - if (wID == IDOK) - { - PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, - PropSheetInfoStr); - int result = TRUE; - - if (psInfo->restartWindows) - result = ID_PSRESTARTWINDOWS; - - /* reboot system takes precedence over restart windows */ - if (psInfo->rebootSystem) - result = ID_PSREBOOTSYSTEM; - - if (psInfo->isModeless) - psInfo->activeValid = FALSE; - else - psInfo->ended = TRUE; - } - else - EnableWindow(hwndApplyBtn, FALSE); - - break; - } - - case IDC_BACK_BUTTON: - PROPSHEET_Back(hwnd); - break; - - case IDC_NEXT_BUTTON: - PROPSHEET_Next(hwnd); - break; - - case IDC_FINISH_BUTTON: - PROPSHEET_Finish(hwnd); - break; - - case IDCANCEL: - PROPSHEET_Cancel(hwnd, 0); - break; - - case IDHELP: - PROPSHEET_Help(hwnd); - break; - - default: - return FALSE; - } - - return TRUE; -} - -/****************************************************************************** - * PROPSHEET_Paint - */ -static LRESULT PROPSHEET_Paint(HWND hwnd, HDC hdcParam) -{ - PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, PropSheetInfoStr); - PAINTSTRUCT ps; - HDC hdc, hdcSrc; - BITMAP bm; - HBITMAP hbmp; - HPALETTE hOldPal = 0; - int offsety = 0; - HBRUSH hbr; - RECT r, rzone; - LPCPROPSHEETPAGEW ppshpage; - WCHAR szBuffer[256]; - int nLength; - - hdc = hdcParam ? hdcParam : BeginPaint(hwnd, &ps); - if (!hdc) return 1; - - hdcSrc = CreateCompatibleDC(0); - ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[psInfo->active_page].hpage; - - if (psInfo->ppshheader.dwFlags & PSH_USEHPLWATERMARK) - hOldPal = SelectPalette(hdc, psInfo->ppshheader.hplWatermark, FALSE); - - if ( (!(ppshpage->dwFlags & PSP_HIDEHEADER)) && - (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) && - (psInfo->ppshheader.dwFlags & PSH_HEADER) ) - { - HWND hwndLineHeader = GetDlgItem(hwnd, IDC_SUNKEN_LINEHEADER); - HFONT hOldFont; - COLORREF clrOld = 0; - int oldBkMode = 0; - - hbmp = SelectObject(hdcSrc, psInfo->ppshheader.u5.hbmHeader); - hOldFont = SelectObject(hdc, psInfo->hFontBold); - - GetClientRect(hwndLineHeader, &r); - MapWindowPoints(hwndLineHeader, hwnd, (LPPOINT) &r, 2); - SetRect(&rzone, 0, 0, r.right + 1, r.top - 1); - - GetObjectW(psInfo->ppshheader.u5.hbmHeader, sizeof(BITMAP), (LPVOID)&bm); - - if (psInfo->ppshheader.dwFlags & PSH_WIZARD97_OLD) - { - /* Fill the unoccupied part of the header with color of the - * left-top pixel, but do it only when needed. - */ - if (bm.bmWidth < r.right || bm.bmHeight < r.bottom) - { - hbr = CreateSolidBrush(GetPixel(hdcSrc, 0, 0)); - CopyRect(&r, &rzone); - if (bm.bmWidth < r.right) - { - r.left = bm.bmWidth; - FillRect(hdc, &r, hbr); - } - if (bm.bmHeight < r.bottom) - { - r.left = 0; - r.top = bm.bmHeight; - FillRect(hdc, &r, hbr); - } - DeleteObject(hbr); - } - - /* Draw the header itself. */ - BitBlt(hdc, 0, 0, - bm.bmWidth, min(bm.bmHeight, rzone.bottom), - hdcSrc, 0, 0, SRCCOPY); - } - else - { - hbr = GetSysColorBrush(COLOR_WINDOW); - FillRect(hdc, &rzone, hbr); - - /* Draw the header bitmap. It's always centered like a - * common 49 x 49 bitmap. */ - BitBlt(hdc, rzone.right - 49 - ((rzone.bottom - 49) / 2), - (rzone.bottom - 49) / 2, - bm.bmWidth, bm.bmHeight, - hdcSrc, 0, 0, SRCCOPY); - - /* NOTE: Native COMCTL32 draws a white stripe over the bitmap - * if its height is smaller than 49 pixels. Because the reason - * for this bug is unknown the current code doesn't try to - * replicate it. */ - } - - clrOld = SetTextColor (hdc, 0x00000000); - oldBkMode = SetBkMode (hdc, TRANSPARENT); - - if (ppshpage->dwFlags & PSP_USEHEADERTITLE) { - SetRect(&r, 20, 10, 0, 0); - if (HIWORD(ppshpage->pszHeaderTitle)) - { - if (psInfo->unicode) - DrawTextW(hdc, (LPWSTR)ppshpage->pszHeaderTitle, - -1, &r, DT_LEFT | DT_SINGLELINE | DT_NOCLIP); - else - DrawTextA(hdc, (LPCSTR)ppshpage->pszHeaderTitle, - -1, &r, DT_LEFT | DT_SINGLELINE | DT_NOCLIP); - } - else - { - nLength = LoadStringW(ppshpage->hInstance, (UINT)ppshpage->pszHeaderTitle, - szBuffer, 256); - if (nLength != 0) - { - DrawTextW(hdc, szBuffer, nLength, - &r, DT_LEFT | DT_SINGLELINE | DT_NOCLIP); - } - } - } - - if (ppshpage->dwFlags & PSP_USEHEADERSUBTITLE) { - SelectObject(hdc, psInfo->hFont); - SetRect(&r, 40, 25, rzone.right - 69, rzone.bottom); - if (HIWORD(ppshpage->pszHeaderTitle)) - { - if (psInfo->unicode) - DrawTextW(hdc, (LPWSTR)ppshpage->pszHeaderSubTitle, - -1, &r, DT_LEFT | DT_SINGLELINE); - else - DrawTextA(hdc, (LPCSTR)ppshpage->pszHeaderSubTitle, - -1, &r, DT_LEFT | DT_SINGLELINE); - } - else - { - nLength = LoadStringW(ppshpage->hInstance, (UINT)ppshpage->pszHeaderSubTitle, - szBuffer, 256); - if (nLength != 0) - { - DrawTextW(hdc, szBuffer, nLength, - &r, DT_LEFT | DT_SINGLELINE); - } - } - } - - offsety = rzone.bottom + 2; - - SetTextColor(hdc, clrOld); - SetBkMode(hdc, oldBkMode); - SelectObject(hdc, hOldFont); - SelectObject(hdcSrc, hbmp); - } - - if ( (ppshpage->dwFlags & PSP_HIDEHEADER) && - (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) && - (psInfo->ppshheader.dwFlags & PSH_WATERMARK) ) - { - HWND hwndLine = GetDlgItem(hwnd, IDC_SUNKEN_LINE); - - GetClientRect(hwndLine, &r); - MapWindowPoints(hwndLine, hwnd, (LPPOINT) &r, 2); - - rzone.left = 0; - rzone.top = 0; - rzone.right = r.right; - rzone.bottom = r.top - 1; - - hbr = GetSysColorBrush(COLOR_WINDOW); - FillRect(hdc, &rzone, hbr); - - GetObjectW(psInfo->ppshheader.u4.hbmWatermark, sizeof(BITMAP), (LPVOID)&bm); - hbmp = SelectObject(hdcSrc, psInfo->ppshheader.u4.hbmWatermark); - - BitBlt(hdc, 0, offsety, min(bm.bmWidth, r.right), - min(bm.bmHeight, r.bottom), hdcSrc, 0, 0, SRCCOPY); - - /* If the bitmap is not big enough, fill the remaining area - with the color of pixel (0,0) of bitmap - see MSDN */ - if (r.top > bm.bmHeight) { - r.bottom = r.top - 1; - r.top = bm.bmHeight; - r.left = 0; - r.right = bm.bmWidth; - hbr = CreateSolidBrush(GetPixel(hdcSrc, 0, 0)); - FillRect(hdc, &r, hbr); - DeleteObject(hbr); - } - - SelectObject(hdcSrc, hbmp); - } - - if (psInfo->ppshheader.dwFlags & PSH_USEHPLWATERMARK) - SelectPalette(hdc, hOldPal, FALSE); - - DeleteDC(hdcSrc); - - if (!hdcParam) EndPaint(hwnd, &ps); - - return 0; -} - -/****************************************************************************** - * PROPSHEET_DialogProc - */ -INT_PTR CALLBACK -PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - TRACE("hwnd=%p msg=0x%04x wparam=%x lparam=%lx\n", - hwnd, uMsg, wParam, lParam); - - switch (uMsg) - { - case WM_INITDIALOG: - { - PropSheetInfo* psInfo = (PropSheetInfo*) lParam; - WCHAR* strCaption = (WCHAR*)Alloc(MAX_CAPTION_LENGTH*sizeof(WCHAR)); - HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL); - LPCPROPSHEETPAGEW ppshpage; - int idx; - LOGFONTW logFont; - - /* Using PropSheetInfoStr to store extra data doesn't match the native - * common control: native uses TCM_[GS]ETITEM - */ - SetPropW(hwnd, PropSheetInfoStr, (HANDLE)psInfo); - - /* - * psInfo->hwnd is not being used by WINE code - it exists - * for compatibility with "real" Windoze. The same about - * SetWindowLongPtr - WINE is only using the PropSheetInfoStr - * property. - */ - psInfo->hwnd = hwnd; - SetWindowLongPtrW(hwnd, DWLP_USER, (DWORD_PTR)psInfo); - - /* set up the Next and Back buttons by default */ - PROPSHEET_SetWizButtons(hwnd, PSWIZB_BACK|PSWIZB_NEXT); - - /* Set up fonts */ - SystemParametersInfoW (SPI_GETICONTITLELOGFONT, 0, &logFont, 0); - psInfo->hFont = CreateFontIndirectW (&logFont); - logFont.lfWeight = FW_BOLD; - psInfo->hFontBold = CreateFontIndirectW (&logFont); - - /* - * Small icon in the title bar. - */ - if ((psInfo->ppshheader.dwFlags & PSH_USEICONID) || - (psInfo->ppshheader.dwFlags & PSH_USEHICON)) - { - HICON hIcon; - int icon_cx = GetSystemMetrics(SM_CXSMICON); - int icon_cy = GetSystemMetrics(SM_CYSMICON); - - if (psInfo->ppshheader.dwFlags & PSH_USEICONID) - hIcon = LoadImageW(psInfo->ppshheader.hInstance, - psInfo->ppshheader.u.pszIcon, - IMAGE_ICON, - icon_cx, icon_cy, - LR_DEFAULTCOLOR); - else - hIcon = psInfo->ppshheader.u.hIcon; - - SendMessageW(hwnd, WM_SETICON, 0, (LPARAM)hIcon); - } - - if (psInfo->ppshheader.dwFlags & PSH_USEHICON) - SendMessageW(hwnd, WM_SETICON, 0, (LPARAM)psInfo->ppshheader.u.hIcon); - - psInfo->strPropertiesFor = strCaption; - - GetWindowTextW(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH); - - PROPSHEET_CreateTabControl(hwnd, psInfo); - - PROPSHEET_LoadWizardBitmaps(psInfo); - - if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) - { - ShowWindow(hwndTabCtrl, SW_HIDE); - PROPSHEET_AdjustSizeWizard(hwnd, psInfo); - PROPSHEET_AdjustButtonsWizard(hwnd, psInfo); - } - else - { - if (PROPSHEET_SizeMismatch(hwnd, psInfo)) - { - PROPSHEET_AdjustSize(hwnd, psInfo); - PROPSHEET_AdjustButtons(hwnd, psInfo); - } - } - - if (psInfo->useCallback) - (*(psInfo->ppshheader.pfnCallback))(hwnd, - PSCB_INITIALIZED, (LPARAM)0); - - idx = psInfo->active_page; - ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[idx].hpage; - psInfo->active_page = -1; - - PROPSHEET_SetCurSel(hwnd, idx, 1, psInfo->proppage[idx].hpage); - - /* doing TCM_SETCURSEL seems to be needed even in case of PSH_WIZARD, - * as some programs call TCM_GETCURSEL to get the current selection - * from which to switch to the next page */ - SendMessageW(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0); - - if (!HIWORD(psInfo->ppshheader.pszCaption) && - psInfo->ppshheader.hInstance) - { - WCHAR szText[256]; - - if (LoadStringW(psInfo->ppshheader.hInstance, - (UINT)psInfo->ppshheader.pszCaption, szText, 255)) - PROPSHEET_SetTitleW(hwnd, psInfo->ppshheader.dwFlags, szText); - } - else - { - PROPSHEET_SetTitleW(hwnd, psInfo->ppshheader.dwFlags, - psInfo->ppshheader.pszCaption); - } - - return TRUE; - } - - case WM_PAINT: - PROPSHEET_Paint(hwnd, (HDC)wParam); - return TRUE; - - case WM_DESTROY: - PROPSHEET_CleanUp(hwnd); - return TRUE; - - case WM_CLOSE: - PROPSHEET_Cancel(hwnd, 1); - return TRUE; - - case WM_COMMAND: - if (!PROPSHEET_DoCommand(hwnd, LOWORD(wParam))) - { - PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, PropSheetInfoStr); - - if (!psInfo) - return FALSE; - - /* No default handler, forward notification to active page */ - if (psInfo->activeValid && psInfo->active_page != -1) - { - HWND hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; - SendMessageW(hwndPage, WM_COMMAND, wParam, lParam); - } - } - return TRUE; - - case WM_SYSCOMMAND: - switch(wParam & 0xfff0) - { - case SC_CLOSE: - PROPSHEET_Cancel(hwnd, 1); - return TRUE; - - default: - return FALSE; - } - - case WM_NOTIFY: - { - NMHDR* pnmh = (LPNMHDR) lParam; - - if (pnmh->code == TCN_SELCHANGE) - { - int index = SendMessageW(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0); - PROPSHEET_SetCurSel(hwnd, index, 1, 0); - } - - if(pnmh->code == TCN_SELCHANGING) - { - BOOL bRet = PROPSHEET_CanSetCurSel(hwnd); - SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, !bRet); - return TRUE; - } - - return FALSE; - } - - case PSM_GETCURRENTPAGEHWND: - { - PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, - PropSheetInfoStr); - HWND hwndPage = 0; - - if (!psInfo) - return FALSE; - - if (psInfo->activeValid && psInfo->active_page != -1) - hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; - - SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, (DWORD_PTR)hwndPage); - - return TRUE; - } - - case PSM_CHANGED: - PROPSHEET_Changed(hwnd, (HWND)wParam); - return TRUE; - - case PSM_UNCHANGED: - PROPSHEET_UnChanged(hwnd, (HWND)wParam); - return TRUE; - - case PSM_GETTABCONTROL: - { - HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL); - - SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, (DWORD_PTR)hwndTabCtrl); - - return TRUE; - } - - case PSM_SETCURSEL: - { - BOOL msgResult; - - msgResult = PROPSHEET_CanSetCurSel(hwnd); - if(msgResult != FALSE) - { - msgResult = PROPSHEET_SetCurSel(hwnd, - (int)wParam, - 1, - (HPROPSHEETPAGE)lParam); - } - - SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); - - return TRUE; - } - - case PSM_CANCELTOCLOSE: - { - WCHAR buf[MAX_BUTTONTEXT_LENGTH]; - HWND hwndOK = GetDlgItem(hwnd, IDOK); - HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL); - - EnableWindow(hwndCancel, FALSE); - if (LoadStringW(COMCTL32_hModule, IDS_CLOSE, buf, sizeof(buf))) - SetWindowTextW(hwndOK, buf); - - return FALSE; - } - - case PSM_RESTARTWINDOWS: - { - PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, - PropSheetInfoStr); - - if (!psInfo) - return FALSE; - - psInfo->restartWindows = TRUE; - return TRUE; - } - - case PSM_REBOOTSYSTEM: - { - PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, - PropSheetInfoStr); - - if (!psInfo) - return FALSE; - - psInfo->rebootSystem = TRUE; - return TRUE; - } - - case PSM_SETTITLEA: - PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam); - return TRUE; - - case PSM_SETTITLEW: - PROPSHEET_SetTitleW(hwnd, (DWORD) wParam, (LPCWSTR) lParam); - return TRUE; - - case PSM_APPLY: - { - BOOL msgResult = PROPSHEET_Apply(hwnd, 0); - - SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); - - return TRUE; - } - - case PSM_QUERYSIBLINGS: - { - LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam); - - SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); - - return TRUE; - } - - case PSM_ADDPAGE: - { - /* - * Note: MSVC++ 6.0 documentation says that PSM_ADDPAGE does not have - * a return value. This is not true. PSM_ADDPAGE returns TRUE - * on success or FALSE otherwise, as specified on MSDN Online. - * Also see the MFC code for - * CPropertySheet::AddPage(CPropertyPage* pPage). - */ - - BOOL msgResult = PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam); - - SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); - - return TRUE; - } - - case PSM_REMOVEPAGE: - PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam); - return TRUE; - - case PSM_ISDIALOGMESSAGE: - { - BOOL msgResult = PROPSHEET_IsDialogMessage(hwnd, (LPMSG)lParam); - SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); - return TRUE; - } - - case PSM_PRESSBUTTON: - PROPSHEET_PressButton(hwnd, (int)wParam); - return TRUE; - - case PSM_SETFINISHTEXTA: - PROPSHEET_SetFinishTextA(hwnd, (LPCSTR) lParam); - return TRUE; - - case PSM_SETWIZBUTTONS: - PROPSHEET_SetWizButtons(hwnd, (DWORD)lParam); - return TRUE; - - case PSM_SETCURSELID: - PROPSHEET_SetCurSelId(hwnd, (int)lParam); - return TRUE; - - case PSM_SETFINISHTEXTW: - PROPSHEET_SetFinishTextW(hwnd, (LPCWSTR) lParam); - return FALSE; - - case PSM_INSERTPAGE: - { - BOOL msgResult = PROPSHEET_InsertPage(hwnd, (HPROPSHEETPAGE)wParam, (HPROPSHEETPAGE)lParam); - SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); - return TRUE; - } - - case PSM_SETHEADERTITLEW: - PROPSHEET_SetHeaderTitleW(hwnd, (int)wParam, (LPCWSTR)lParam); - return TRUE; - - case PSM_SETHEADERTITLEA: - PROPSHEET_SetHeaderTitleA(hwnd, (int)wParam, (LPCSTR)lParam); - return TRUE; - - case PSM_SETHEADERSUBTITLEW: - PROPSHEET_SetHeaderSubTitleW(hwnd, (int)wParam, (LPCWSTR)lParam); - return TRUE; - - case PSM_SETHEADERSUBTITLEA: - PROPSHEET_SetHeaderSubTitleA(hwnd, (int)wParam, (LPCSTR)lParam); - return TRUE; - - case PSM_HWNDTOINDEX: - { - LRESULT msgResult = PROPSHEET_HwndToIndex(hwnd, (HWND)wParam); - SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); - return TRUE; - } - - case PSM_INDEXTOHWND: - { - LRESULT msgResult = PROPSHEET_IndexToHwnd(hwnd, (int)wParam); - SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); - return TRUE; - } - - case PSM_PAGETOINDEX: - { - LRESULT msgResult = PROPSHEET_PageToIndex(hwnd, (HPROPSHEETPAGE)wParam); - SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); - return TRUE; - } - - case PSM_INDEXTOPAGE: - { - LRESULT msgResult = PROPSHEET_IndexToPage(hwnd, (int)wParam); - SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); - return TRUE; - } - - case PSM_IDTOINDEX: - { - LRESULT msgResult = PROPSHEET_IdToIndex(hwnd, (int)lParam); - SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); - return TRUE; - } - - case PSM_INDEXTOID: - { - LRESULT msgResult = PROPSHEET_IndexToId(hwnd, (int)wParam); - SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); - return TRUE; - } - - case PSM_GETRESULT: - { - LRESULT msgResult = PROPSHEET_GetResult(hwnd); - SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); - return TRUE; - } - - case PSM_RECALCPAGESIZES: - { - LRESULT msgResult = PROPSHEET_RecalcPageSizes(hwnd); - SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); - return TRUE; - } - - default: - return FALSE; - } -} +/* + * Property Sheets + * + * Copyright 1998 Francis Beaudet + * Copyright 1999 Thuy Nguyen + * Copyright 2004 Maxime Bellenge + * Copyright 2004 Filip Navara + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This code was audited for completeness against the documented features + * of Comctl32.dll version 6.0 on Sep. 12, 2004, by Filip Navara. + * + * Unless otherwise noted, we believe this code to be complete, as per + * the specification mentioned above. + * If you discover missing features, or bugs, please note them below. + * + * TODO: + * - Tab order + * - Wizard 97 header resizing + * - Enforcing of minimal wizard size + * - Messages: + * o PSM_GETRESULT + * o PSM_IDTOINDEX + * o PSM_INSERTPAGE + * o PSM_RECALCPAGESIZES + * o PSM_SETHEADERSUBTITLE + * o PSM_SETHEADERTITLE + * o WM_HELP + * o WM_CONTEXTMENU + * - Notifications: + * o PSN_GETOBJECT + * o PSN_QUERYINITIALFOCUS + * o PSN_TRANSLATEACCELERATOR + * - Styles: + * o PSH_WIZARDHASFINISH + * o PSH_RTLREADING + * o PSH_STRETCHWATERMARK + * o PSH_USEPAGELANG + * o PSH_USEPSTARTPAGE + * - Page styles: + * o PSP_USEFUSIONCONTEXT + * o PSP_USEREFPARENT + */ + +#include +#include + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "prsht.h" +#include "comctl32.h" + +#include "wine/debug.h" +#include "wine/unicode.h" + +/****************************************************************************** + * Data structures + */ +#include "pshpack2.h" + +typedef struct +{ + WORD dlgVer; + WORD signature; + DWORD helpID; + DWORD exStyle; + DWORD style; +} MyDLGTEMPLATEEX; + +typedef struct +{ + DWORD helpid; + DWORD exStyle; + DWORD style; + short x; + short y; + short cx; + short cy; + DWORD id; +} MyDLGITEMTEMPLATEEX; +#include "poppack.h" + +typedef struct tagPropPageInfo +{ + HPROPSHEETPAGE hpage; /* to keep track of pages not passed to PropertySheet */ + HWND hwndPage; + BOOL isDirty; + LPCWSTR pszText; + BOOL hasHelp; + BOOL useCallback; + BOOL hasIcon; +} PropPageInfo; + +typedef struct tagPropSheetInfo +{ + HWND hwnd; + PROPSHEETHEADERW ppshheader; + BOOL unicode; + LPWSTR strPropertiesFor; + int nPages; + int active_page; + BOOL isModeless; + BOOL hasHelp; + BOOL hasApply; + BOOL useCallback; + BOOL restartWindows; + BOOL rebootSystem; + BOOL activeValid; + PropPageInfo* proppage; + HFONT hFont; + HFONT hFontBold; + int width; + int height; + HIMAGELIST hImageList; + BOOL ended; +} PropSheetInfo; + +typedef struct +{ + int x; + int y; +} PADDING_INFO; + +/****************************************************************************** + * Defines and global variables + */ + +const WCHAR PropSheetInfoStr[] = + {'P','r','o','p','e','r','t','y','S','h','e','e','t','I','n','f','o',0 }; + +#define PSP_INTERNAL_UNICODE 0x80000000 + +#define MAX_CAPTION_LENGTH 255 +#define MAX_TABTEXT_LENGTH 255 +#define MAX_BUTTONTEXT_LENGTH 64 + +#define INTRNL_ANY_WIZARD (PSH_WIZARD | PSH_WIZARD97_OLD | PSH_WIZARD97_NEW | PSH_WIZARD_LITE) + +/* Wizard metrics specified in DLUs */ +#define WIZARD_PADDING 7 +#define WIZARD_HEADER_HEIGHT 36 + +/****************************************************************************** + * Prototypes + */ +static int PROPSHEET_CreateDialog(PropSheetInfo* psInfo); +static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo); +static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo); +static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo); +static BOOL PROPSHEET_CollectSheetInfoA(LPCPROPSHEETHEADERA lppsh, + PropSheetInfo * psInfo); +static BOOL PROPSHEET_CollectSheetInfoW(LPCPROPSHEETHEADERW lppsh, + PropSheetInfo * psInfo); +static BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEW lppsp, + PropSheetInfo * psInfo, + int index); +static BOOL PROPSHEET_CreateTabControl(HWND hwndParent, + PropSheetInfo * psInfo); +static BOOL PROPSHEET_CreatePage(HWND hwndParent, int index, + const PropSheetInfo * psInfo, + LPCPROPSHEETPAGEW ppshpage); +static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo); +static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg); +static BOOL PROPSHEET_Back(HWND hwndDlg); +static BOOL PROPSHEET_Next(HWND hwndDlg); +static BOOL PROPSHEET_Finish(HWND hwndDlg); +static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam); +static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam); +static void PROPSHEET_Help(HWND hwndDlg); +static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage); +static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage); +static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID); +static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText); +static void PROPSHEET_SetFinishTextW(HWND hwndDlg, LPCWSTR lpszText); +static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText); +static void PROPSHEET_SetTitleW(HWND hwndDlg, DWORD dwStyle, LPCWSTR lpszText); +static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg); +static BOOL PROPSHEET_SetCurSel(HWND hwndDlg, + int index, + int skipdir, + HPROPSHEETPAGE hpage); +static void PROPSHEET_SetCurSelId(HWND hwndDlg, int id); +static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg, + WPARAM wParam, LPARAM lParam); +static BOOL PROPSHEET_AddPage(HWND hwndDlg, + HPROPSHEETPAGE hpage); + +static BOOL PROPSHEET_RemovePage(HWND hwndDlg, + int index, + HPROPSHEETPAGE hpage); +static void PROPSHEET_CleanUp(HWND hwndDlg); +static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo); +static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags); +static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo* psInfo); +static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg); +static BOOL PROPSHEET_DoCommand(HWND hwnd, WORD wID); + +INT_PTR CALLBACK +PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +WINE_DEFAULT_DEBUG_CHANNEL(propsheet); + +#define add_flag(a) if (dwFlags & a) {strcat(string, #a );strcat(string," ");} +/****************************************************************************** + * PROPSHEET_UnImplementedFlags + * + * Document use of flags we don't implement yet. + */ +static VOID PROPSHEET_UnImplementedFlags(DWORD dwFlags) +{ + CHAR string[256]; + + string[0] = '\0'; + + /* + * unhandled header flags: + * PSH_WIZARDHASFINISH 0x00000010 + * PSH_RTLREADING 0x00000800 + * PSH_STRETCHWATERMARK 0x00040000 + * PSH_USEPAGELANG 0x00200000 + */ + + add_flag(PSH_WIZARDHASFINISH); + add_flag(PSH_RTLREADING); + add_flag(PSH_STRETCHWATERMARK); + add_flag(PSH_USEPAGELANG); + if (string[0] != '\0') + FIXME("%s\n", string); +} +#undef add_flag + +/****************************************************************************** + * PROPSHEET_GetPageRect + * + * Retrieve rect from tab control and map into the dialog for SetWindowPos + */ +static void PROPSHEET_GetPageRect(const PropSheetInfo * psInfo, HWND hwndDlg, + RECT *rc, LPCPROPSHEETPAGEW ppshpage) +{ + if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) { + HWND hwndChild; + RECT r; + + if (((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) && + (psInfo->ppshheader.dwFlags & PSH_HEADER) && + !(ppshpage->dwFlags & PSP_HIDEHEADER)) || + (psInfo->ppshheader.dwFlags & PSH_WIZARD)) + { + rc->left = rc->top = WIZARD_PADDING; + } + else + { + rc->left = rc->top = 0; + } + rc->right = psInfo->width - rc->left; + rc->bottom = psInfo->height - rc->top; + MapDialogRect(hwndDlg, rc); + + if ((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) && + (psInfo->ppshheader.dwFlags & PSH_HEADER) && + !(ppshpage->dwFlags & PSP_HIDEHEADER)) + { + hwndChild = GetDlgItem(hwndDlg, IDC_SUNKEN_LINEHEADER); + GetClientRect(hwndChild, &r); + MapWindowPoints(hwndChild, hwndDlg, (LPPOINT) &r, 2); + rc->top += r.bottom + 1; + } + } else { + HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL); + GetClientRect(hwndTabCtrl, rc); + SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)rc); + MapWindowPoints(hwndTabCtrl, hwndDlg, (LPPOINT)rc, 2); + } +} + +/****************************************************************************** + * PROPSHEET_FindPageByResId + * + * Find page index corresponding to page resource id. + */ +static INT PROPSHEET_FindPageByResId(PropSheetInfo * psInfo, LRESULT resId) +{ + INT i; + + for (i = 0; i < psInfo->nPages; i++) + { + LPCPROPSHEETPAGEA lppsp = (LPCPROPSHEETPAGEA)psInfo->proppage[i].hpage; + + /* Fixme: if resource ID is a string shall we use strcmp ??? */ + if (lppsp->u.pszTemplate == (LPVOID)resId) + break; + } + + return i; +} + +/****************************************************************************** + * PROPSHEET_AtoW + * + * Convert ASCII to Unicode since all data is saved as Unicode. + */ +static void PROPSHEET_AtoW(LPCWSTR *tostr, LPCSTR frstr) +{ + INT len; + + TRACE("<%s>\n", frstr); + len = MultiByteToWideChar(CP_ACP, 0, frstr, -1, 0, 0); + *tostr = Alloc(len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, frstr, -1, (LPWSTR)*tostr, len); +} + +/****************************************************************************** + * PROPSHEET_CollectSheetInfoA + * + * Collect relevant data. + */ +static BOOL PROPSHEET_CollectSheetInfoA(LPCPROPSHEETHEADERA lppsh, + PropSheetInfo * psInfo) +{ + DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERA)); + DWORD dwFlags = lppsh->dwFlags; + + psInfo->hasHelp = dwFlags & PSH_HASHELP; + psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW); + psInfo->useCallback = (dwFlags & PSH_USECALLBACK )&& (lppsh->pfnCallback); + psInfo->isModeless = dwFlags & PSH_MODELESS; + + memcpy(&psInfo->ppshheader,lppsh,dwSize); + TRACE("\n** PROPSHEETHEADER **\ndwSize\t\t%ld\ndwFlags\t\t%08lx\nhwndParent\t%p\nhInstance\t%p\npszCaption\t'%s'\nnPages\t\t%d\npfnCallback\t%p\n", + lppsh->dwSize, lppsh->dwFlags, lppsh->hwndParent, lppsh->hInstance, + debugstr_a(lppsh->pszCaption), lppsh->nPages, lppsh->pfnCallback); + + PROPSHEET_UnImplementedFlags(lppsh->dwFlags); + + if (lppsh->dwFlags & INTRNL_ANY_WIZARD) + psInfo->ppshheader.pszCaption = NULL; + else + { + if (HIWORD(lppsh->pszCaption)) + { + int len = MultiByteToWideChar(CP_ACP, 0, lppsh->pszCaption, -1, NULL, 0); + psInfo->ppshheader.pszCaption = Alloc( len*sizeof (WCHAR) ); + MultiByteToWideChar(CP_ACP, 0, lppsh->pszCaption, -1, (LPWSTR) psInfo->ppshheader.pszCaption, len); + } + } + psInfo->nPages = lppsh->nPages; + + if (dwFlags & PSH_USEPSTARTPAGE) + { + TRACE("PSH_USEPSTARTPAGE is on\n"); + psInfo->active_page = 0; + } + else + psInfo->active_page = lppsh->u2.nStartPage; + + if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages) + psInfo->active_page = 0; + + psInfo->restartWindows = FALSE; + psInfo->rebootSystem = FALSE; + psInfo->hImageList = 0; + psInfo->activeValid = FALSE; + + return TRUE; +} + +/****************************************************************************** + * PROPSHEET_CollectSheetInfoW + * + * Collect relevant data. + */ +static BOOL PROPSHEET_CollectSheetInfoW(LPCPROPSHEETHEADERW lppsh, + PropSheetInfo * psInfo) +{ + DWORD dwSize = min(lppsh->dwSize,sizeof(PROPSHEETHEADERW)); + DWORD dwFlags = lppsh->dwFlags; + + psInfo->hasHelp = dwFlags & PSH_HASHELP; + psInfo->hasApply = !(dwFlags & PSH_NOAPPLYNOW); + psInfo->useCallback = (dwFlags & PSH_USECALLBACK) && (lppsh->pfnCallback); + psInfo->isModeless = dwFlags & PSH_MODELESS; + + memcpy(&psInfo->ppshheader,lppsh,dwSize); + TRACE("\n** PROPSHEETHEADER **\ndwSize\t\t%ld\ndwFlags\t\t%08lx\nhwndParent\t%p\nhInstance\t%p\npszCaption\t'%s'\nnPages\t\t%d\npfnCallback\t%p\n", + lppsh->dwSize, lppsh->dwFlags, lppsh->hwndParent, lppsh->hInstance, debugstr_w(lppsh->pszCaption), lppsh->nPages, lppsh->pfnCallback); + + PROPSHEET_UnImplementedFlags(lppsh->dwFlags); + + if (lppsh->dwFlags & INTRNL_ANY_WIZARD) + psInfo->ppshheader.pszCaption = NULL; + else + { + if (HIWORD(lppsh->pszCaption)) + { + int len = strlenW(lppsh->pszCaption); + psInfo->ppshheader.pszCaption = Alloc( (len+1)*sizeof(WCHAR) ); + strcpyW( (WCHAR *)psInfo->ppshheader.pszCaption, lppsh->pszCaption ); + } + } + psInfo->nPages = lppsh->nPages; + + if (dwFlags & PSH_USEPSTARTPAGE) + { + TRACE("PSH_USEPSTARTPAGE is on\n"); + psInfo->active_page = 0; + } + else + psInfo->active_page = lppsh->u2.nStartPage; + + if (psInfo->active_page < 0 || psInfo->active_page >= psInfo->nPages) + psInfo->active_page = 0; + + psInfo->restartWindows = FALSE; + psInfo->rebootSystem = FALSE; + psInfo->hImageList = 0; + psInfo->activeValid = FALSE; + + return TRUE; +} + +/****************************************************************************** + * PROPSHEET_CollectPageInfo + * + * Collect property sheet data. + * With code taken from DIALOG_ParseTemplate32. + */ +BOOL PROPSHEET_CollectPageInfo(LPCPROPSHEETPAGEW lppsp, + PropSheetInfo * psInfo, + int index) +{ + DLGTEMPLATE* pTemplate; + const WORD* p; + DWORD dwFlags; + int width, height; + + TRACE("\n"); + psInfo->proppage[index].hpage = (HPROPSHEETPAGE)lppsp; + psInfo->proppage[index].hwndPage = 0; + psInfo->proppage[index].isDirty = FALSE; + + /* + * Process property page flags. + */ + dwFlags = lppsp->dwFlags; + psInfo->proppage[index].useCallback = (dwFlags & PSP_USECALLBACK) && (lppsp->pfnCallback); + psInfo->proppage[index].hasHelp = dwFlags & PSP_HASHELP; + psInfo->proppage[index].hasIcon = dwFlags & (PSP_USEHICON | PSP_USEICONID); + + /* as soon as we have a page with the help flag, set the sheet flag on */ + if (psInfo->proppage[index].hasHelp) + psInfo->hasHelp = TRUE; + + /* + * Process page template. + */ + if (dwFlags & PSP_DLGINDIRECT) + pTemplate = (DLGTEMPLATE*)lppsp->u.pResource; + else if(dwFlags & PSP_INTERNAL_UNICODE ) + { + HRSRC hResource = FindResourceW(lppsp->hInstance, + lppsp->u.pszTemplate, + (LPWSTR)RT_DIALOG); + HGLOBAL hTemplate = LoadResource(lppsp->hInstance, + hResource); + pTemplate = (LPDLGTEMPLATEW)LockResource(hTemplate); + } + else + { + HRSRC hResource = FindResourceA(lppsp->hInstance, + (LPSTR)lppsp->u.pszTemplate, + (LPSTR)RT_DIALOG); + HGLOBAL hTemplate = LoadResource(lppsp->hInstance, + hResource); + pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate); + } + + /* + * Extract the size of the page and the caption. + */ + if (!pTemplate) + return FALSE; + + p = (const WORD *)pTemplate; + + if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF) + { + /* DLGTEMPLATEEX (not defined in any std. header file) */ + + p++; /* dlgVer */ + p++; /* signature */ + p += 2; /* help ID */ + p += 2; /* ext style */ + p += 2; /* style */ + } + else + { + /* DLGTEMPLATE */ + + p += 2; /* style */ + p += 2; /* ext style */ + } + + p++; /* nb items */ + p++; /* x */ + p++; /* y */ + width = (WORD)*p; p++; + height = (WORD)*p; p++; + + /* Special calculation for interior wizard pages so the largest page is + * calculated correctly. We need to add all the padding and space occupied + * by the header so the width and height sums up to the whole wizard client + * area. */ + if ((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) && + (psInfo->ppshheader.dwFlags & PSH_HEADER) && + !(dwFlags & PSP_HIDEHEADER)) + { + height += 2 * WIZARD_PADDING + WIZARD_HEADER_HEIGHT; + width += 2 * WIZARD_PADDING; + } + if (psInfo->ppshheader.dwFlags & PSH_WIZARD) + { + height += 2 * WIZARD_PADDING; + width += 2 * WIZARD_PADDING; + } + + /* remember the largest width and height */ + if (width > psInfo->width) + psInfo->width = width; + + if (height > psInfo->height) + psInfo->height = height; + + /* menu */ + switch ((WORD)*p) + { + case 0x0000: + p++; + break; + case 0xffff: + p += 2; + break; + default: + p += lstrlenW( (LPCWSTR)p ) + 1; + break; + } + + /* class */ + switch ((WORD)*p) + { + case 0x0000: + p++; + break; + case 0xffff: + p += 2; + break; + default: + p += lstrlenW( (LPCWSTR)p ) + 1; + break; + } + + /* Extract the caption */ + psInfo->proppage[index].pszText = (LPCWSTR)p; + TRACE("Tab %d %s\n",index,debugstr_w((LPCWSTR)p)); + p += lstrlenW((LPCWSTR)p) + 1; + + if (dwFlags & PSP_USETITLE) + { + WCHAR szTitle[256]; + const WCHAR *pTitle; + static const WCHAR pszNull[] = { '(','n','u','l','l',')',0 }; + int len; + + if ( !HIWORD( lppsp->pszTitle ) ) + { + if (!LoadStringW( lppsp->hInstance, (UINT)lppsp->pszTitle,szTitle,sizeof(szTitle) )) + { + pTitle = pszNull; + FIXME("Could not load resource #%04x?\n",LOWORD(lppsp->pszTitle)); + } + else + pTitle = szTitle; + } + else + pTitle = lppsp->pszTitle; + + len = strlenW(pTitle); + psInfo->proppage[index].pszText = Alloc( (len+1)*sizeof (WCHAR) ); + strcpyW( (LPWSTR)psInfo->proppage[index].pszText,pTitle); + } + + /* + * Build the image list for icons + */ + if ((dwFlags & PSP_USEHICON) || (dwFlags & PSP_USEICONID)) + { + HICON hIcon; + int icon_cx = GetSystemMetrics(SM_CXSMICON); + int icon_cy = GetSystemMetrics(SM_CYSMICON); + + if (dwFlags & PSP_USEICONID) + hIcon = LoadImageW(lppsp->hInstance, lppsp->u2.pszIcon, IMAGE_ICON, + icon_cx, icon_cy, LR_DEFAULTCOLOR); + else + hIcon = lppsp->u2.hIcon; + + if ( hIcon ) + { + if (psInfo->hImageList == 0 ) + psInfo->hImageList = ImageList_Create(icon_cx, icon_cy, ILC_COLOR, 1, 1); + + ImageList_AddIcon(psInfo->hImageList, hIcon); + } + + } + + return TRUE; +} + +/****************************************************************************** + * PROPSHEET_CreateDialog + * + * Creates the actual property sheet. + */ +int PROPSHEET_CreateDialog(PropSheetInfo* psInfo) +{ + LRESULT ret; + LPCVOID template; + LPVOID temp = 0; + HRSRC hRes; + DWORD resSize; + WORD resID = IDD_PROPSHEET; + + TRACE("\n"); + if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) + resID = IDD_WIZARD; + + if( psInfo->unicode ) + { + if(!(hRes = FindResourceW(COMCTL32_hModule, + MAKEINTRESOURCEW(resID), + (LPWSTR)RT_DIALOG))) + return -1; + } + else + { + if(!(hRes = FindResourceA(COMCTL32_hModule, + MAKEINTRESOURCEA(resID), + (LPSTR)RT_DIALOG))) + return -1; + } + + if(!(template = (LPVOID)LoadResource(COMCTL32_hModule, hRes))) + return -1; + + /* + * Make a copy of the dialog template. + */ + resSize = SizeofResource(COMCTL32_hModule, hRes); + + temp = Alloc(resSize); + + if (!temp) + return -1; + + memcpy(temp, template, resSize); + + if (psInfo->ppshheader.dwFlags & PSH_NOCONTEXTHELP) + { + if (((MyDLGTEMPLATEEX*)temp)->signature == 0xFFFF) + ((MyDLGTEMPLATEEX*)temp)->style &= ~DS_CONTEXTHELP; + else + ((DLGTEMPLATE*)temp)->style &= ~DS_CONTEXTHELP; + } + if ((psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) && + (psInfo->ppshheader.dwFlags & PSH_WIZARDCONTEXTHELP)) + { + if (((MyDLGTEMPLATEEX*)temp)->signature == 0xFFFF) + ((MyDLGTEMPLATEEX*)temp)->style |= DS_CONTEXTHELP; + else + ((DLGTEMPLATE*)temp)->style |= DS_CONTEXTHELP; + } + + if (psInfo->useCallback) + (*(psInfo->ppshheader.pfnCallback))(0, PSCB_PRECREATE, (LPARAM)temp); + + /* NOTE: MSDN states "Returns a positive value if successful, or -1 + * otherwise for modal property sheets.", but this is wrong. The + * actual return value is either TRUE (success), FALSE (cancel) or + * -1 (error). */ + if( psInfo->unicode ) + { + ret = (int)CreateDialogIndirectParamW(psInfo->ppshheader.hInstance, + (LPDLGTEMPLATEW) temp, + psInfo->ppshheader.hwndParent, + PROPSHEET_DialogProc, + (LPARAM)psInfo); + if ( !ret ) ret = -1; + } + else + { + ret = (int)CreateDialogIndirectParamA(psInfo->ppshheader.hInstance, + (LPDLGTEMPLATEA) temp, + psInfo->ppshheader.hwndParent, + PROPSHEET_DialogProc, + (LPARAM)psInfo); + if ( !ret ) ret = -1; + } + + Free(temp); + + return ret; +} + +/****************************************************************************** + * PROPSHEET_SizeMismatch + * + * Verify that the tab control and the "largest" property sheet page dlg. template + * match in size. + */ +static BOOL PROPSHEET_SizeMismatch(HWND hwndDlg, PropSheetInfo* psInfo) +{ + HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL); + RECT rcOrigTab, rcPage; + + /* + * Original tab size. + */ + GetClientRect(hwndTabCtrl, &rcOrigTab); + TRACE("orig tab %ld %ld %ld %ld\n", rcOrigTab.left, rcOrigTab.top, + rcOrigTab.right, rcOrigTab.bottom); + + /* + * Biggest page size. + */ + rcPage.left = 0; + rcPage.top = 0; + rcPage.right = psInfo->width; + rcPage.bottom = psInfo->height; + + MapDialogRect(hwndDlg, &rcPage); + TRACE("biggest page %ld %ld %ld %ld\n", rcPage.left, rcPage.top, + rcPage.right, rcPage.bottom); + + if ( (rcPage.right - rcPage.left) != (rcOrigTab.right - rcOrigTab.left) ) + return TRUE; + if ( (rcPage.bottom - rcPage.top) != (rcOrigTab.bottom - rcOrigTab.top) ) + return TRUE; + + return FALSE; +} + +/****************************************************************************** + * PROPSHEET_AdjustSize + * + * Resizes the property sheet and the tab control to fit the largest page. + */ +static BOOL PROPSHEET_AdjustSize(HWND hwndDlg, PropSheetInfo* psInfo) +{ + HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL); + HWND hwndButton = GetDlgItem(hwndDlg, IDOK); + RECT rc,tabRect; + int tabOffsetX, tabOffsetY, buttonHeight; + PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndDlg); + RECT units; + + /* Get the height of buttons */ + GetClientRect(hwndButton, &rc); + buttonHeight = rc.bottom; + + /* + * Biggest page size. + */ + rc.left = 0; + rc.top = 0; + rc.right = psInfo->width; + rc.bottom = psInfo->height; + + MapDialogRect(hwndDlg, &rc); + + /* retrieve the dialog units */ + units.left = units.right = 4; + units.top = units.bottom = 8; + MapDialogRect(hwndDlg, &units); + + /* + * Resize the tab control. + */ + GetClientRect(hwndTabCtrl,&tabRect); + + SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&tabRect); + + if ((rc.bottom - rc.top) < (tabRect.bottom - tabRect.top)) + { + rc.bottom = rc.top + tabRect.bottom - tabRect.top; + psInfo->height = MulDiv((rc.bottom - rc.top),8,units.top); + } + + if ((rc.right - rc.left) < (tabRect.right - tabRect.left)) + { + rc.right = rc.left + tabRect.right - tabRect.left; + psInfo->width = MulDiv((rc.right - rc.left),4,units.left); + } + + SendMessageW(hwndTabCtrl, TCM_ADJUSTRECT, TRUE, (LPARAM)&rc); + + tabOffsetX = -(rc.left); + tabOffsetY = -(rc.top); + + rc.right -= rc.left; + rc.bottom -= rc.top; + TRACE("setting tab %08lx, rc (0,0)-(%ld,%ld)\n", + (DWORD)hwndTabCtrl, rc.right, rc.bottom); + SetWindowPos(hwndTabCtrl, 0, 0, 0, rc.right, rc.bottom, + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + + GetClientRect(hwndTabCtrl, &rc); + + TRACE("tab client rc %ld %ld %ld %ld\n", + rc.left, rc.top, rc.right, rc.bottom); + + rc.right += ((padding.x * 2) + tabOffsetX); + rc.bottom += (buttonHeight + (3 * padding.y) + tabOffsetY); + + /* + * Resize the property sheet. + */ + TRACE("setting dialog %08lx, rc (0,0)-(%ld,%ld)\n", + (DWORD)hwndDlg, rc.right, rc.bottom); + SetWindowPos(hwndDlg, 0, 0, 0, rc.right, rc.bottom, + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + return TRUE; +} + +/****************************************************************************** + * PROPSHEET_AdjustSizeWizard + * + * Resizes the property sheet to fit the largest page. + */ +static BOOL PROPSHEET_AdjustSizeWizard(HWND hwndDlg, PropSheetInfo* psInfo) +{ + HWND hwndLine = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE); + RECT rc, lineRect, dialogRect; + + /* Biggest page size */ + rc.left = 0; + rc.top = 0; + rc.right = psInfo->width; + rc.bottom = psInfo->height; + MapDialogRect(hwndDlg, &rc); + + TRACE("Biggest page %ld %ld %ld %ld\n", rc.left, rc.top, rc.right, rc.bottom); + + /* Add space for the buttons row */ + GetWindowRect(hwndLine, &lineRect); + MapWindowPoints(NULL, hwndDlg, (LPPOINT)&lineRect, 2); + GetClientRect(hwndDlg, &dialogRect); + rc.bottom += dialogRect.bottom - lineRect.top - 1; + + /* Convert the client coordinates to window coordinates */ + AdjustWindowRect(&rc, GetWindowLongW(hwndDlg, GWL_STYLE), FALSE); + + /* Resize the property sheet */ + TRACE("setting dialog %08lx, rc (0,0)-(%ld,%ld)\n", + (DWORD)hwndDlg, rc.right, rc.bottom); + SetWindowPos(hwndDlg, 0, 0, 0, rc.right - rc.left, rc.bottom - rc.top, + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); + + return TRUE; +} + +/****************************************************************************** + * PROPSHEET_AdjustButtons + * + * Adjusts the buttons' positions. + */ +static BOOL PROPSHEET_AdjustButtons(HWND hwndParent, PropSheetInfo* psInfo) +{ + HWND hwndButton = GetDlgItem(hwndParent, IDOK); + RECT rcSheet; + int x, y; + int num_buttons = 2; + int buttonWidth, buttonHeight; + PADDING_INFO padding = PROPSHEET_GetPaddingInfo(hwndParent); + + if (psInfo->hasApply) + num_buttons++; + + if (psInfo->hasHelp) + num_buttons++; + + /* + * Obtain the size of the buttons. + */ + GetClientRect(hwndButton, &rcSheet); + buttonWidth = rcSheet.right; + buttonHeight = rcSheet.bottom; + + /* + * Get the size of the property sheet. + */ + GetClientRect(hwndParent, &rcSheet); + + /* + * All buttons will be at this y coordinate. + */ + y = rcSheet.bottom - (padding.y + buttonHeight); + + /* + * Position OK button and make it default. + */ + hwndButton = GetDlgItem(hwndParent, IDOK); + + x = rcSheet.right - ((padding.x + buttonWidth) * num_buttons); + + SetWindowPos(hwndButton, 0, x, y, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + + SendMessageW(hwndParent, DM_SETDEFID, IDOK, 0); + + + /* + * Position Cancel button. + */ + hwndButton = GetDlgItem(hwndParent, IDCANCEL); + + x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1)); + + SetWindowPos(hwndButton, 0, x, y, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + + /* + * Position Apply button. + */ + hwndButton = GetDlgItem(hwndParent, IDC_APPLY_BUTTON); + + if (psInfo->hasApply) + { + if (psInfo->hasHelp) + x = rcSheet.right - ((padding.x + buttonWidth) * 2); + else + x = rcSheet.right - (padding.x + buttonWidth); + + SetWindowPos(hwndButton, 0, x, y, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + + EnableWindow(hwndButton, FALSE); + } + else + ShowWindow(hwndButton, SW_HIDE); + + /* + * Position Help button. + */ + hwndButton = GetDlgItem(hwndParent, IDHELP); + + if (psInfo->hasHelp) + { + x = rcSheet.right - (padding.x + buttonWidth); + + SetWindowPos(hwndButton, 0, x, y, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + } + else + ShowWindow(hwndButton, SW_HIDE); + + return TRUE; +} + +/****************************************************************************** + * PROPSHEET_AdjustButtonsWizard + * + * Adjusts the buttons' positions. + */ +static BOOL PROPSHEET_AdjustButtonsWizard(HWND hwndParent, + PropSheetInfo* psInfo) +{ + HWND hwndButton = GetDlgItem(hwndParent, IDCANCEL); + HWND hwndLine = GetDlgItem(hwndParent, IDC_SUNKEN_LINE); + HWND hwndLineHeader = GetDlgItem(hwndParent, IDC_SUNKEN_LINEHEADER); + RECT rcSheet; + int x, y; + int num_buttons = 3; + int buttonWidth, buttonHeight, lineHeight, lineWidth; + PADDING_INFO padding = PROPSHEET_GetPaddingInfoWizard(hwndParent, psInfo); + + if (psInfo->hasHelp) + num_buttons++; + + /* + * Obtain the size of the buttons. + */ + GetClientRect(hwndButton, &rcSheet); + buttonWidth = rcSheet.right; + buttonHeight = rcSheet.bottom; + + GetClientRect(hwndLine, &rcSheet); + lineHeight = rcSheet.bottom; + + /* + * Get the size of the property sheet. + */ + GetClientRect(hwndParent, &rcSheet); + + /* + * All buttons will be at this y coordinate. + */ + y = rcSheet.bottom - (padding.y + buttonHeight); + + /* + * Position the Next and the Finish buttons. + */ + hwndButton = GetDlgItem(hwndParent, IDC_NEXT_BUTTON); + + x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 1)); + + SetWindowPos(hwndButton, 0, x, y, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + + hwndButton = GetDlgItem(hwndParent, IDC_FINISH_BUTTON); + + SetWindowPos(hwndButton, 0, x, y, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + + ShowWindow(hwndButton, SW_HIDE); + + /* + * Position the Back button. + */ + hwndButton = GetDlgItem(hwndParent, IDC_BACK_BUTTON); + + x -= buttonWidth; + + SetWindowPos(hwndButton, 0, x, y, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + + /* + * Position the Cancel button. + */ + hwndButton = GetDlgItem(hwndParent, IDCANCEL); + + x = rcSheet.right - ((padding.x + buttonWidth) * (num_buttons - 2)); + + SetWindowPos(hwndButton, 0, x, y, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + + /* + * Position Help button. + */ + hwndButton = GetDlgItem(hwndParent, IDHELP); + + if (psInfo->hasHelp) + { + x = rcSheet.right - (padding.x + buttonWidth); + + SetWindowPos(hwndButton, 0, x, y, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE); + } + else + ShowWindow(hwndButton, SW_HIDE); + + if (psInfo->ppshheader.dwFlags & + (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW | PSH_WIZARD_LITE)) + padding.x = 0; + + /* + * Position and resize the sunken line. + */ + x = padding.x; + y = rcSheet.bottom - ((padding.y * 2) + buttonHeight + lineHeight); + + lineWidth = rcSheet.right - (padding.x * 2); + SetWindowPos(hwndLine, 0, x, y, lineWidth, 2, + SWP_NOZORDER | SWP_NOACTIVATE); + + /* + * Position and resize the header sunken line. + */ + + SetWindowPos(hwndLineHeader, 0, 0, 0, rcSheet.right, 2, + SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); + if (!(psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW))) + ShowWindow(hwndLineHeader, SW_HIDE); + + return TRUE; +} + +/****************************************************************************** + * PROPSHEET_GetPaddingInfo + * + * Returns the layout information. + */ +static PADDING_INFO PROPSHEET_GetPaddingInfo(HWND hwndDlg) +{ + HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABCONTROL); + RECT rcTab; + POINT tl; + PADDING_INFO padding; + + GetWindowRect(hwndTab, &rcTab); + + tl.x = rcTab.left; + tl.y = rcTab.top; + + ScreenToClient(hwndDlg, &tl); + + padding.x = tl.x; + padding.y = tl.y; + + return padding; +} + +/****************************************************************************** + * PROPSHEET_GetPaddingInfoWizard + * + * Returns the layout information. + * Vertical spacing is the distance between the line and the buttons. + * Do NOT use the Help button to gather padding information when it isn't mapped + * (PSH_HASHELP), as app writers aren't forced to supply correct coordinates + * for it in this case ! + * FIXME: I'm not sure about any other coordinate problems with these evil + * buttons. Fix it in case additional problems appear or maybe calculate + * a padding in a completely different way, as this is somewhat messy. + */ +static PADDING_INFO PROPSHEET_GetPaddingInfoWizard(HWND hwndDlg, const PropSheetInfo* + psInfo) +{ + PADDING_INFO padding; + RECT rc; + HWND hwndControl; + INT idButton; + POINT ptButton, ptLine; + + TRACE("\n"); + if (psInfo->hasHelp) + { + idButton = IDHELP; + } + else + { + if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) + { + idButton = IDC_NEXT_BUTTON; + } + else + { + /* hopefully this is ok */ + idButton = IDCANCEL; + } + } + + hwndControl = GetDlgItem(hwndDlg, idButton); + GetWindowRect(hwndControl, &rc); + + ptButton.x = rc.left; + ptButton.y = rc.top; + + ScreenToClient(hwndDlg, &ptButton); + + /* Line */ + hwndControl = GetDlgItem(hwndDlg, IDC_SUNKEN_LINE); + GetWindowRect(hwndControl, &rc); + + ptLine.x = rc.left; + ptLine.y = rc.bottom; + + ScreenToClient(hwndDlg, &ptLine); + + padding.y = ptButton.y - ptLine.y; + + if (padding.y < 0) + ERR("padding negative ! Please report this !\n"); + + /* this is most probably not correct, but the best we have now */ + padding.x = padding.y; + return padding; +} + +/****************************************************************************** + * PROPSHEET_CreateTabControl + * + * Insert the tabs in the tab control. + */ +static BOOL PROPSHEET_CreateTabControl(HWND hwndParent, + PropSheetInfo * psInfo) +{ + HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL); + TCITEMW item; + int i, nTabs; + int iImage = 0; + + TRACE("\n"); + item.mask = TCIF_TEXT; + item.cchTextMax = MAX_TABTEXT_LENGTH; + + nTabs = psInfo->nPages; + + /* + * Set the image list for icons. + */ + if (psInfo->hImageList) + { + SendMessageW(hwndTabCtrl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList); + } + + SendMessageW(GetDlgItem(hwndTabCtrl, IDC_TABCONTROL), WM_SETREDRAW, 0, 0); + for (i = 0; i < nTabs; i++) + { + if ( psInfo->proppage[i].hasIcon ) + { + item.mask |= TCIF_IMAGE; + item.iImage = iImage++; + } + else + { + item.mask &= ~TCIF_IMAGE; + } + + item.pszText = (LPWSTR) psInfo->proppage[i].pszText; + SendMessageW(hwndTabCtrl, TCM_INSERTITEMW, (WPARAM)i, (LPARAM)&item); + } + SendMessageW(GetDlgItem(hwndTabCtrl, IDC_TABCONTROL), WM_SETREDRAW, 1, 0); + + return TRUE; +} + +/****************************************************************************** + * PROPSHEET_WizardSubclassProc + * + * Subclassing window procedure for wizard extrior pages to prevent drawing + * background and so drawing above the watermark. + */ +static LRESULT CALLBACK +PROPSHEET_WizardSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uID, DWORD_PTR dwRef) +{ + switch (uMsg) + { + case WM_ERASEBKGND: + return TRUE; + + case WM_CTLCOLORSTATIC: + SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW)); + return (INT_PTR)GetSysColorBrush(COLOR_WINDOW); + } + + return DefSubclassProc(hwnd, uMsg, wParam, lParam); +} + +/* + * Get the size of an in-memory Template + * + *( Based on the code of PROPSHEET_CollectPageInfo) + * See also dialog.c/DIALOG_ParseTemplate32(). + */ + +static UINT GetTemplateSize(DLGTEMPLATE* pTemplate) + +{ + const WORD* p = (const WORD *)pTemplate; + BOOL istemplateex = (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF); + WORD nrofitems; + + if (istemplateex) + { + /* DLGTEMPLATEEX (not defined in any std. header file) */ + + TRACE("is DLGTEMPLATEEX\n"); + p++; /* dlgVer */ + p++; /* signature */ + p += 2; /* help ID */ + p += 2; /* ext style */ + p += 2; /* style */ + } + else + { + /* DLGTEMPLATE */ + + TRACE("is DLGTEMPLATE\n"); + p += 2; /* style */ + p += 2; /* ext style */ + } + + nrofitems = (WORD)*p; p++; /* nb items */ + p++; /* x */ + p++; /* y */ + p++; /* width */ + p++; /* height */ + + /* menu */ + switch ((WORD)*p) + { + case 0x0000: + p++; + break; + case 0xffff: + p += 2; + break; + default: + TRACE("menu %s\n",debugstr_w((LPCWSTR)p)); + p += lstrlenW( (LPCWSTR)p ) + 1; + break; + } + + /* class */ + switch ((WORD)*p) + { + case 0x0000: + p++; + break; + case 0xffff: + p += 2; /* 0xffff plus predefined window class ordinal value */ + break; + default: + TRACE("class %s\n",debugstr_w((LPCWSTR)p)); + p += lstrlenW( (LPCWSTR)p ) + 1; + break; + } + + /* title */ + TRACE("title %s\n",debugstr_w((LPCWSTR)p)); + p += lstrlenW((LPCWSTR)p) + 1; + + /* font, if DS_SETFONT set */ + if ((DS_SETFONT & ((istemplateex)? ((MyDLGTEMPLATEEX*)pTemplate)->style : + pTemplate->style))) + { + p+=(istemplateex)?3:1; + TRACE("font %s\n",debugstr_w((LPCWSTR)p)); + p += lstrlenW( (LPCWSTR)p ) + 1; /* the font name */ + } + + /* now process the DLGITEMTEMPLATE(EX) structs (plus custom data) + * that are following the DLGTEMPLATE(EX) data */ + TRACE("%d items\n",nrofitems); + while (nrofitems > 0) + { + p = (WORD*)(((DWORD)p + 3) & ~3); /* DWORD align */ + + /* skip header */ + p += (istemplateex ? sizeof(MyDLGITEMTEMPLATEEX) : sizeof(DLGITEMTEMPLATE))/sizeof(WORD); + + /* check class */ + switch ((WORD)*p) + { + case 0x0000: + p++; + break; + case 0xffff: + TRACE("class ordinal 0x%08lx\n",*(DWORD*)p); + p += 2; + break; + default: + TRACE("class %s\n",debugstr_w((LPCWSTR)p)); + p += lstrlenW( (LPCWSTR)p ) + 1; + break; + } + + /* check title text */ + switch ((WORD)*p) + { + case 0x0000: + p++; + break; + case 0xffff: + TRACE("text ordinal 0x%08lx\n",*(DWORD*)p); + p += 2; + break; + default: + TRACE("text %s\n",debugstr_w((LPCWSTR)p)); + p += lstrlenW( (LPCWSTR)p ) + 1; + break; + } + p += *p / sizeof(WORD) + 1; /* Skip extra data */ + --nrofitems; + } + + TRACE("%p %p size 0x%08x\n",p, (WORD*)pTemplate,sizeof(WORD)*(p - (WORD*)pTemplate)); + return (p - (WORD*)pTemplate)*sizeof(WORD); + +} + +/****************************************************************************** + * PROPSHEET_CreatePage + * + * Creates a page. + */ +static BOOL PROPSHEET_CreatePage(HWND hwndParent, + int index, + const PropSheetInfo * psInfo, + LPCPROPSHEETPAGEW ppshpage) +{ + DLGTEMPLATE* pTemplate; + HWND hwndPage; + DWORD resSize; + LPVOID temp = NULL; + + TRACE("index %d\n", index); + + if (ppshpage == NULL) + { + return FALSE; + } + + if (ppshpage->dwFlags & PSP_DLGINDIRECT) + { + pTemplate = (DLGTEMPLATE*)ppshpage->u.pResource; + resSize = GetTemplateSize(pTemplate); + } + else if(ppshpage->dwFlags & PSP_INTERNAL_UNICODE) + { + HRSRC hResource; + HANDLE hTemplate; + + hResource = FindResourceW(ppshpage->hInstance, + ppshpage->u.pszTemplate, + (LPWSTR)RT_DIALOG); + if(!hResource) + return FALSE; + + resSize = SizeofResource(ppshpage->hInstance, hResource); + + hTemplate = LoadResource(ppshpage->hInstance, hResource); + if(!hTemplate) + return FALSE; + + pTemplate = (LPDLGTEMPLATEW)LockResource(hTemplate); + /* + * Make a copy of the dialog template to make it writable + */ + } + else + { + HRSRC hResource; + HANDLE hTemplate; + + hResource = FindResourceA(ppshpage->hInstance, + (LPSTR)ppshpage->u.pszTemplate, + (LPSTR)RT_DIALOG); + if(!hResource) + return FALSE; + + resSize = SizeofResource(ppshpage->hInstance, hResource); + + hTemplate = LoadResource(ppshpage->hInstance, hResource); + if(!hTemplate) + return FALSE; + + pTemplate = (LPDLGTEMPLATEA)LockResource(hTemplate); + /* + * Make a copy of the dialog template to make it writable + */ + } + temp = Alloc(resSize); + if (!temp) + return FALSE; + + TRACE("copying pTemplate %p into temp %p (%ld)\n", pTemplate, temp, resSize); + memcpy(temp, pTemplate, resSize); + pTemplate = temp; + + if (((MyDLGTEMPLATEEX*)pTemplate)->signature == 0xFFFF) + { + ((MyDLGTEMPLATEEX*)pTemplate)->style |= WS_CHILD | WS_TABSTOP | DS_CONTROL; + ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~DS_MODALFRAME; + ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_CAPTION; + ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_SYSMENU; + ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_POPUP; + ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_DISABLED; + ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_VISIBLE; + ((MyDLGTEMPLATEEX*)pTemplate)->style &= ~WS_THICKFRAME; + + ((MyDLGTEMPLATEEX*)pTemplate)->exStyle |= WS_EX_CONTROLPARENT; + } + else + { + pTemplate->style |= WS_CHILD | WS_TABSTOP | DS_CONTROL; + pTemplate->style &= ~DS_MODALFRAME; + pTemplate->style &= ~WS_CAPTION; + pTemplate->style &= ~WS_SYSMENU; + pTemplate->style &= ~WS_POPUP; + pTemplate->style &= ~WS_DISABLED; + pTemplate->style &= ~WS_VISIBLE; + pTemplate->style &= ~WS_THICKFRAME; + + pTemplate->dwExtendedStyle |= WS_EX_CONTROLPARENT; + } + + if (psInfo->proppage[index].useCallback) + (*(ppshpage->pfnCallback))(0, PSPCB_CREATE, + (LPPROPSHEETPAGEW)ppshpage); + + if(ppshpage->dwFlags & PSP_INTERNAL_UNICODE) + hwndPage = CreateDialogIndirectParamW(ppshpage->hInstance, + pTemplate, + hwndParent, + ppshpage->pfnDlgProc, + (LPARAM)ppshpage); + else + hwndPage = CreateDialogIndirectParamA(ppshpage->hInstance, + pTemplate, + hwndParent, + ppshpage->pfnDlgProc, + (LPARAM)ppshpage); + /* Free a no more needed copy */ + if(temp) + Free(temp); + + psInfo->proppage[index].hwndPage = hwndPage; + + /* Subclass exterior wizard pages */ + if((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) && + (psInfo->ppshheader.dwFlags & PSH_WATERMARK) && + (ppshpage->dwFlags & PSP_HIDEHEADER)) + { + SetWindowSubclass(hwndPage, PROPSHEET_WizardSubclassProc, 1, + (DWORD_PTR)ppshpage); + } + + return TRUE; +} + +/****************************************************************************** + * PROPSHEET_LoadWizardBitmaps + * + * Loads the watermark and header bitmaps for a wizard. + */ +static VOID PROPSHEET_LoadWizardBitmaps(PropSheetInfo *psInfo) +{ + if (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) + { + /* if PSH_USEHBMWATERMARK is not set, load the resource from pszbmWatermark + and put the HBITMAP in hbmWatermark. Thus all the rest of the code always + considers hbmWatermark as valid. */ + if ((psInfo->ppshheader.dwFlags & PSH_WATERMARK) && + !(psInfo->ppshheader.dwFlags & PSH_USEHBMWATERMARK)) + { + ((PropSheetInfo *)psInfo)->ppshheader.u4.hbmWatermark = + CreateMappedBitmap(psInfo->ppshheader.hInstance, (INT)psInfo->ppshheader.u4.pszbmWatermark, 0, NULL, 0); + } + + /* Same behavior as for watermarks */ + if ((psInfo->ppshheader.dwFlags & PSH_HEADER) && + !(psInfo->ppshheader.dwFlags & PSH_USEHBMHEADER)) + { + ((PropSheetInfo *)psInfo)->ppshheader.u5.hbmHeader = + CreateMappedBitmap(psInfo->ppshheader.hInstance, (INT)psInfo->ppshheader.u5.pszbmHeader, 0, NULL, 0); + } + } +} + + +/****************************************************************************** + * PROPSHEET_ShowPage + * + * Displays or creates the specified page. + */ +static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo) +{ + HWND hwndTabCtrl; + HWND hwndLineHeader; + LPCPROPSHEETPAGEW ppshpage; + + TRACE("active_page %d, index %d\n", psInfo->active_page, index); + if (index == psInfo->active_page) + { + if (GetTopWindow(hwndDlg) != psInfo->proppage[index].hwndPage) + SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + return TRUE; + } + + ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage; + if (psInfo->proppage[index].hwndPage == 0) + { + PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage); + } + + if ((psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) && + (ppshpage->dwFlags & PSP_USETITLE)) + { + PROPSHEET_SetTitleW(hwndDlg, psInfo->ppshheader.dwFlags, + psInfo->proppage[index].pszText); + } + + if (psInfo->active_page != -1) + ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE); + + ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW); + + /* Synchronize current selection with tab control + * It seems to be needed even in case of PSH_WIZARD (no tab controls there) */ + hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL); + SendMessageW(hwndTabCtrl, TCM_SETCURSEL, index, 0); + + psInfo->active_page = index; + psInfo->activeValid = TRUE; + + if (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW) ) + { + hwndLineHeader = GetDlgItem(hwndDlg, IDC_SUNKEN_LINEHEADER); + ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage; + + if ((ppshpage->dwFlags & PSP_HIDEHEADER) || (!(psInfo->ppshheader.dwFlags & PSH_HEADER)) ) + ShowWindow(hwndLineHeader, SW_HIDE); + else + ShowWindow(hwndLineHeader, SW_SHOW); + } + + InvalidateRgn(hwndDlg, NULL, TRUE); + UpdateWindow(hwndDlg); + + return TRUE; +} + +/****************************************************************************** + * PROPSHEET_Back + */ +static BOOL PROPSHEET_Back(HWND hwndDlg) +{ + PSHNOTIFY psn; + HWND hwndPage; + PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, + PropSheetInfoStr); + LRESULT result; + int idx; + + TRACE("active_page %d\n", psInfo->active_page); + if (psInfo->active_page < 0) + return FALSE; + + psn.hdr.code = PSN_WIZBACK; + psn.hdr.hwndFrom = hwndDlg; + psn.hdr.idFrom = 0; + psn.lParam = 0; + + hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; + + result = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); + if (result == -1) + return FALSE; + else if (result == 0) + idx = psInfo->active_page - 1; + else + idx = PROPSHEET_FindPageByResId(psInfo, result); + + if (idx >= 0 && idx < psInfo->nPages) + { + if (PROPSHEET_CanSetCurSel(hwndDlg)) + PROPSHEET_SetCurSel(hwndDlg, idx, -1, 0); + } + return TRUE; +} + +/****************************************************************************** + * PROPSHEET_Next + */ +static BOOL PROPSHEET_Next(HWND hwndDlg) +{ + PSHNOTIFY psn; + HWND hwndPage; + LRESULT msgResult = 0; + PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, + PropSheetInfoStr); + int idx; + + TRACE("active_page %d\n", psInfo->active_page); + if (psInfo->active_page < 0) + return FALSE; + + psn.hdr.code = PSN_WIZNEXT; + psn.hdr.hwndFrom = hwndDlg; + psn.hdr.idFrom = 0; + psn.lParam = 0; + + hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; + + msgResult = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); + if (msgResult == -1) + return FALSE; + else if (msgResult == 0) + idx = psInfo->active_page + 1; + else + idx = PROPSHEET_FindPageByResId(psInfo, msgResult); + + if (idx < psInfo->nPages ) + { + if (PROPSHEET_CanSetCurSel(hwndDlg) != FALSE) + PROPSHEET_SetCurSel(hwndDlg, idx, 1, 0); + } + + return TRUE; +} + +/****************************************************************************** + * PROPSHEET_Finish + */ +static BOOL PROPSHEET_Finish(HWND hwndDlg) +{ + PSHNOTIFY psn; + HWND hwndPage; + LRESULT msgResult = 0; + PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, + PropSheetInfoStr); + + TRACE("active_page %d\n", psInfo->active_page); + if (psInfo->active_page < 0) + return FALSE; + + psn.hdr.code = PSN_WIZFINISH; + psn.hdr.hwndFrom = hwndDlg; + psn.hdr.idFrom = 0; + psn.lParam = 0; + + hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; + + msgResult = SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); + + TRACE("msg result %ld\n", msgResult); + + if (msgResult != 0) + return FALSE; + + if (psInfo->isModeless) + psInfo->activeValid = FALSE; + else + psInfo->ended = TRUE; + + return TRUE; +} + +/****************************************************************************** + * PROPSHEET_Apply + */ +static BOOL PROPSHEET_Apply(HWND hwndDlg, LPARAM lParam) +{ + int i; + HWND hwndPage; + PSHNOTIFY psn; + PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, + PropSheetInfoStr); + + TRACE("active_page %d\n", psInfo->active_page); + if (psInfo->active_page < 0) + return FALSE; + + psn.hdr.hwndFrom = hwndDlg; + psn.hdr.idFrom = 0; + psn.lParam = 0; + + + /* + * Send PSN_KILLACTIVE to the current page. + */ + psn.hdr.code = PSN_KILLACTIVE; + + hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; + + if (SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn) != FALSE) + return FALSE; + + /* + * Send PSN_APPLY to all pages. + */ + psn.hdr.code = PSN_APPLY; + psn.lParam = lParam; + + for (i = 0; i < psInfo->nPages; i++) + { + hwndPage = psInfo->proppage[i].hwndPage; + if (hwndPage) + { + switch (SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn)) + { + case PSNRET_INVALID: + PROPSHEET_ShowPage(hwndDlg, i, psInfo); + /* fall through */ + case PSNRET_INVALID_NOCHANGEPAGE: + return FALSE; + } + } + } + + if(lParam) + { + psInfo->activeValid = FALSE; + } + else if(psInfo->active_page >= 0) + { + psn.hdr.code = PSN_SETACTIVE; + psn.lParam = 0; + hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; + SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); + } + + return TRUE; +} + +/****************************************************************************** + * PROPSHEET_Cancel + */ +static void PROPSHEET_Cancel(HWND hwndDlg, LPARAM lParam) +{ + PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, + PropSheetInfoStr); + HWND hwndPage; + PSHNOTIFY psn; + int i; + + TRACE("active_page %d\n", psInfo->active_page); + if (psInfo->active_page < 0) + return; + + hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; + psn.hdr.code = PSN_QUERYCANCEL; + psn.hdr.hwndFrom = hwndDlg; + psn.hdr.idFrom = 0; + psn.lParam = 0; + + if (SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn)) + return; + + psn.hdr.code = PSN_RESET; + psn.lParam = lParam; + + for (i = 0; i < psInfo->nPages; i++) + { + hwndPage = psInfo->proppage[i].hwndPage; + + if (hwndPage) + SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); + } + + if (psInfo->isModeless) + { + /* makes PSM_GETCURRENTPAGEHWND return NULL */ + psInfo->activeValid = FALSE; + } + else + psInfo->ended = TRUE; +} + +/****************************************************************************** + * PROPSHEET_Help + */ +static void PROPSHEET_Help(HWND hwndDlg) +{ + PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, + PropSheetInfoStr); + HWND hwndPage; + PSHNOTIFY psn; + + TRACE("active_page %d\n", psInfo->active_page); + if (psInfo->active_page < 0) + return; + + hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; + psn.hdr.code = PSN_HELP; + psn.hdr.hwndFrom = hwndDlg; + psn.hdr.idFrom = 0; + psn.lParam = 0; + + SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); +} + +/****************************************************************************** + * PROPSHEET_Changed + */ +static void PROPSHEET_Changed(HWND hwndDlg, HWND hwndDirtyPage) +{ + int i; + PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, + PropSheetInfoStr); + + TRACE("\n"); + if (!psInfo) return; + /* + * Set the dirty flag of this page. + */ + for (i = 0; i < psInfo->nPages; i++) + { + if (psInfo->proppage[i].hwndPage == hwndDirtyPage) + psInfo->proppage[i].isDirty = TRUE; + } + + /* + * Enable the Apply button. + */ + if (psInfo->hasApply) + { + HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON); + + EnableWindow(hwndApplyBtn, TRUE); + } +} + +/****************************************************************************** + * PROPSHEET_UnChanged + */ +static void PROPSHEET_UnChanged(HWND hwndDlg, HWND hwndCleanPage) +{ + int i; + BOOL noPageDirty = TRUE; + HWND hwndApplyBtn = GetDlgItem(hwndDlg, IDC_APPLY_BUTTON); + PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, + PropSheetInfoStr); + + TRACE("\n"); + if ( !psInfo ) return; + for (i = 0; i < psInfo->nPages; i++) + { + /* set the specified page as clean */ + if (psInfo->proppage[i].hwndPage == hwndCleanPage) + psInfo->proppage[i].isDirty = FALSE; + + /* look to see if there's any dirty pages */ + if (psInfo->proppage[i].isDirty) + noPageDirty = FALSE; + } + + /* + * Disable Apply button. + */ + if (noPageDirty) + EnableWindow(hwndApplyBtn, FALSE); +} + +/****************************************************************************** + * PROPSHEET_PressButton + */ +static void PROPSHEET_PressButton(HWND hwndDlg, int buttonID) +{ + TRACE("buttonID %d\n", buttonID); + switch (buttonID) + { + case PSBTN_APPLYNOW: + PROPSHEET_DoCommand(hwndDlg, IDC_APPLY_BUTTON); + break; + case PSBTN_BACK: + PROPSHEET_Back(hwndDlg); + break; + case PSBTN_CANCEL: + PROPSHEET_DoCommand(hwndDlg, IDCANCEL); + break; + case PSBTN_FINISH: + PROPSHEET_Finish(hwndDlg); + break; + case PSBTN_HELP: + PROPSHEET_DoCommand(hwndDlg, IDHELP); + break; + case PSBTN_NEXT: + PROPSHEET_Next(hwndDlg); + break; + case PSBTN_OK: + PROPSHEET_DoCommand(hwndDlg, IDOK); + break; + default: + FIXME("Invalid button index %d\n", buttonID); + } +} + + +/************************************************************************* + * BOOL PROPSHEET_CanSetCurSel [Internal] + * + * Test whether the current page can be changed by sending a PSN_KILLACTIVE + * + * PARAMS + * hwndDlg [I] handle to a Dialog hWnd + * + * RETURNS + * TRUE if Current Selection can change + * + * NOTES + */ +static BOOL PROPSHEET_CanSetCurSel(HWND hwndDlg) +{ + PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, + PropSheetInfoStr); + HWND hwndPage; + PSHNOTIFY psn; + BOOL res = FALSE; + + TRACE("active_page %d\n", psInfo->active_page); + if (!psInfo) + { + res = FALSE; + goto end; + } + + if (psInfo->active_page < 0) + { + res = TRUE; + goto end; + } + + /* + * Notify the current page. + */ + hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; + psn.hdr.code = PSN_KILLACTIVE; + psn.hdr.hwndFrom = hwndDlg; + psn.hdr.idFrom = 0; + psn.lParam = 0; + + res = !SendMessageW(hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); + +end: + TRACE("<-- %d\n", res); + return res; +} + +/****************************************************************************** + * PROPSHEET_SetCurSel + */ +static BOOL PROPSHEET_SetCurSel(HWND hwndDlg, + int index, + int skipdir, + HPROPSHEETPAGE hpage + ) +{ + PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr); + HWND hwndHelp = GetDlgItem(hwndDlg, IDHELP); + HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL); + + TRACE("index %d, skipdir %d, hpage %p\n", index, skipdir, hpage); + /* hpage takes precedence over index */ + if (hpage != NULL) + index = PROPSHEET_GetPageIndex(hpage, psInfo); + + if (index < 0 || index >= psInfo->nPages) + { + TRACE("Could not find page to select!\n"); + return FALSE; + } + + while (1) { + int result; + PSHNOTIFY psn; + RECT rc; + LPCPROPSHEETPAGEW ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[index].hpage; + + if (hwndTabControl) + SendMessageW(hwndTabControl, TCM_SETCURSEL, index, 0); + + psn.hdr.code = PSN_SETACTIVE; + psn.hdr.hwndFrom = hwndDlg; + psn.hdr.idFrom = 0; + psn.lParam = 0; + + if (!psInfo->proppage[index].hwndPage) { + PROPSHEET_CreatePage(hwndDlg, index, psInfo, ppshpage); + } + + /* Resize the property sheet page to the fit in the Tab control + * (for regular property sheets) or to fit in the client area (for + * wizards). + * NOTE: The resizing happens every time the page is selected and + * not only when it's created (some applications depend on it). */ + PROPSHEET_GetPageRect(psInfo, hwndDlg, &rc, ppshpage); + TRACE("setting page %p, rc (%ld,%ld)-(%ld,%ld) w=%ld, h=%ld\n", + psInfo->proppage[index].hwndPage, rc.left, rc.top, rc.right, rc.bottom, + rc.right - rc.left, rc.bottom - rc.top); + SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, + rc.left, rc.top, + rc.right - rc.left, rc.bottom - rc.top, 0); + + result = SendMessageW(psInfo->proppage[index].hwndPage, WM_NOTIFY, 0, (LPARAM) &psn); + if (!result) + break; + if (result == -1) { + index+=skipdir; + if (index < 0) { + index = 0; + WARN("Tried to skip before first property sheet page!\n"); + break; + } + if (index >= psInfo->nPages) { + WARN("Tried to skip after last property sheet page!\n"); + index = psInfo->nPages-1; + break; + } + } + else if (result != 0) + { + int old_index = index; + index = PROPSHEET_FindPageByResId(psInfo, result); + if(index >= psInfo->nPages) { + index = old_index; + WARN("Tried to skip to nonexistant page by res id\n"); + break; + } + continue; + } + } + /* + * Display the new page. + */ + PROPSHEET_ShowPage(hwndDlg, index, psInfo); + + if (psInfo->proppage[index].hasHelp) + EnableWindow(hwndHelp, TRUE); + else + EnableWindow(hwndHelp, FALSE); + + return TRUE; +} + +/****************************************************************************** + * PROPSHEET_SetCurSelId + * + * Selects the page, specified by resource id. + */ +static void PROPSHEET_SetCurSelId(HWND hwndDlg, int id) +{ + int idx; + PropSheetInfo* psInfo = + (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr); + + idx = PROPSHEET_FindPageByResId(psInfo, id); + if (idx < psInfo->nPages ) + { + if (PROPSHEET_CanSetCurSel(hwndDlg) != FALSE) + PROPSHEET_SetCurSel(hwndDlg, idx, 1, 0); + } +} + +/****************************************************************************** + * PROPSHEET_SetTitleA + */ +static void PROPSHEET_SetTitleA(HWND hwndDlg, DWORD dwStyle, LPCSTR lpszText) +{ + if(HIWORD(lpszText)) + { + WCHAR szTitle[256]; + MultiByteToWideChar(CP_ACP, 0, lpszText, -1, + szTitle, sizeof(szTitle)); + PROPSHEET_SetTitleW(hwndDlg, dwStyle, szTitle); + } + else + { + PROPSHEET_SetTitleW(hwndDlg, dwStyle, (LPCWSTR)lpszText); + } +} + +/****************************************************************************** + * PROPSHEET_SetTitleW + */ +static void PROPSHEET_SetTitleW(HWND hwndDlg, DWORD dwStyle, LPCWSTR lpszText) +{ + PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr); + WCHAR szTitle[256]; + + TRACE("'%s' (style %08lx)\n", debugstr_w(lpszText), dwStyle); + if (HIWORD(lpszText) == 0) { + if (!LoadStringW(psInfo->ppshheader.hInstance, + LOWORD(lpszText), szTitle, sizeof(szTitle)-sizeof(WCHAR))) + return; + lpszText = szTitle; + } + if (dwStyle & PSH_PROPTITLE) + { + WCHAR* dest; + int lentitle = strlenW(lpszText); + int lenprop = strlenW(psInfo->strPropertiesFor); + + dest = Alloc( (lentitle + lenprop + 1)*sizeof (WCHAR)); + strcpyW(dest, psInfo->strPropertiesFor); + strcatW(dest, lpszText); + + SetWindowTextW(hwndDlg, dest); + Free(dest); + } + else + SetWindowTextW(hwndDlg, lpszText); +} + +/****************************************************************************** + * PROPSHEET_SetFinishTextA + */ +static void PROPSHEET_SetFinishTextA(HWND hwndDlg, LPCSTR lpszText) +{ + HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON); + + TRACE("'%s'\n", lpszText); + /* Set text, show and enable the Finish button */ + SetWindowTextA(hwndButton, lpszText); + ShowWindow(hwndButton, SW_SHOW); + EnableWindow(hwndButton, TRUE); + + /* Make it default pushbutton */ + SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0); + + /* Hide Back button */ + hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON); + ShowWindow(hwndButton, SW_HIDE); + + /* Hide Next button */ + hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON); + ShowWindow(hwndButton, SW_HIDE); +} + +/****************************************************************************** + * PROPSHEET_SetFinishTextW + */ +static void PROPSHEET_SetFinishTextW(HWND hwndDlg, LPCWSTR lpszText) +{ + HWND hwndButton = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON); + + TRACE("'%s'\n", debugstr_w(lpszText)); + /* Set text, show and enable the Finish button */ + SetWindowTextW(hwndButton, lpszText); + ShowWindow(hwndButton, SW_SHOW); + EnableWindow(hwndButton, TRUE); + + /* Make it default pushbutton */ + SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0); + + /* Hide Back button */ + hwndButton = GetDlgItem(hwndDlg, IDC_BACK_BUTTON); + ShowWindow(hwndButton, SW_HIDE); + + /* Hide Next button */ + hwndButton = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON); + ShowWindow(hwndButton, SW_HIDE); +} + +/****************************************************************************** + * PROPSHEET_QuerySiblings + */ +static LRESULT PROPSHEET_QuerySiblings(HWND hwndDlg, + WPARAM wParam, LPARAM lParam) +{ + int i = 0; + HWND hwndPage; + LRESULT msgResult = 0; + PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwndDlg, PropSheetInfoStr); + + while ((i < psInfo->nPages) && (msgResult == 0)) + { + hwndPage = psInfo->proppage[i].hwndPage; + msgResult = SendMessageW(hwndPage, PSM_QUERYSIBLINGS, wParam, lParam); + i++; + } + + return msgResult; +} + + +/****************************************************************************** + * PROPSHEET_AddPage + */ +static BOOL PROPSHEET_AddPage(HWND hwndDlg, + HPROPSHEETPAGE hpage) +{ + PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg, + PropSheetInfoStr); + HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL); + TCITEMW item; + LPCPROPSHEETPAGEW ppsp = (LPCPROPSHEETPAGEW)hpage; + + TRACE("hpage %p\n", hpage); + /* + * Allocate and fill in a new PropPageInfo entry. + */ + psInfo->proppage = (PropPageInfo*) ReAlloc(psInfo->proppage, + sizeof(PropPageInfo) * + (psInfo->nPages + 1)); + if (!PROPSHEET_CollectPageInfo(ppsp, psInfo, psInfo->nPages)) + return FALSE; + + psInfo->proppage[psInfo->nPages].hpage = hpage; + + if (ppsp->dwFlags & PSP_PREMATURE) + { + /* Create the page but don't show it */ + PROPSHEET_CreatePage(hwndDlg, psInfo->nPages, psInfo, ppsp); + } + + /* + * Add a new tab to the tab control. + */ + item.mask = TCIF_TEXT; + item.pszText = (LPWSTR) psInfo->proppage[psInfo->nPages].pszText; + item.cchTextMax = MAX_TABTEXT_LENGTH; + + if (psInfo->hImageList) + { + SendMessageW(hwndTabControl, TCM_SETIMAGELIST, 0, (LPARAM)psInfo->hImageList); + } + + if ( psInfo->proppage[psInfo->nPages].hasIcon ) + { + item.mask |= TCIF_IMAGE; + item.iImage = psInfo->nPages; + } + + SendMessageW(hwndTabControl, TCM_INSERTITEMW, psInfo->nPages + 1, + (LPARAM)&item); + + psInfo->nPages++; + + /* If it is the only page - show it */ + if(psInfo->nPages == 1) + PROPSHEET_SetCurSel(hwndDlg, 0, 1, 0); + return TRUE; +} + +/****************************************************************************** + * PROPSHEET_RemovePage + */ +static BOOL PROPSHEET_RemovePage(HWND hwndDlg, + int index, + HPROPSHEETPAGE hpage) +{ + PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg, + PropSheetInfoStr); + HWND hwndTabControl = GetDlgItem(hwndDlg, IDC_TABCONTROL); + PropPageInfo* oldPages; + + TRACE("index %d, hpage %p\n", index, hpage); + if (!psInfo) { + return FALSE; + } + /* + * hpage takes precedence over index. + */ + if (hpage != 0) + { + index = PROPSHEET_GetPageIndex(hpage, psInfo); + } + + /* Make sure that index is within range */ + if (index < 0 || index >= psInfo->nPages) + { + TRACE("Could not find page to remove!\n"); + return FALSE; + } + + TRACE("total pages %d removing page %d active page %d\n", + psInfo->nPages, index, psInfo->active_page); + /* + * Check if we're removing the active page. + */ + if (index == psInfo->active_page) + { + if (psInfo->nPages > 1) + { + if (index > 0) + { + /* activate previous page */ + PROPSHEET_SetCurSel(hwndDlg, index - 1, -1, 0); + } + else + { + /* activate the next page */ + PROPSHEET_SetCurSel(hwndDlg, index + 1, 1, 0); + psInfo->active_page = index; + } + } + else + { + psInfo->active_page = -1; + if (!psInfo->isModeless) + { + psInfo->ended = TRUE; + return TRUE; + } + } + } + else if (index < psInfo->active_page) + psInfo->active_page--; + + /* Unsubclass the page dialog window */ + if((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD) && + (psInfo->ppshheader.dwFlags & PSH_WATERMARK) && + ((PROPSHEETPAGEW*)psInfo->proppage[index].hpage)->dwFlags & PSP_HIDEHEADER)) + { + RemoveWindowSubclass(psInfo->proppage[index].hwndPage, + PROPSHEET_WizardSubclassProc, 1); + } + + /* Destroy page dialog window */ + DestroyWindow(psInfo->proppage[index].hwndPage); + + /* Free page resources */ + if(psInfo->proppage[index].hpage) + { + PROPSHEETPAGEW* psp = (PROPSHEETPAGEW*)psInfo->proppage[index].hpage; + + if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[index].pszText) + Free ((LPVOID)psInfo->proppage[index].pszText); + + DestroyPropertySheetPage(psInfo->proppage[index].hpage); + } + + /* Remove the tab */ + SendMessageW(hwndTabControl, TCM_DELETEITEM, index, 0); + + oldPages = psInfo->proppage; + psInfo->nPages--; + psInfo->proppage = Alloc(sizeof(PropPageInfo) * psInfo->nPages); + + if (index > 0) + memcpy(&psInfo->proppage[0], &oldPages[0], index * sizeof(PropPageInfo)); + + if (index < psInfo->nPages) + memcpy(&psInfo->proppage[index], &oldPages[index + 1], + (psInfo->nPages - index) * sizeof(PropPageInfo)); + + Free(oldPages); + + return FALSE; +} + +/****************************************************************************** + * PROPSHEET_SetWizButtons + * + * This code will work if (and assumes that) the Next button is on top of the + * Finish button. ie. Finish comes after Next in the Z order. + * This means make sure the dialog template reflects this. + * + */ +static void PROPSHEET_SetWizButtons(HWND hwndDlg, DWORD dwFlags) +{ + HWND hwndBack = GetDlgItem(hwndDlg, IDC_BACK_BUTTON); + HWND hwndNext = GetDlgItem(hwndDlg, IDC_NEXT_BUTTON); + HWND hwndFinish = GetDlgItem(hwndDlg, IDC_FINISH_BUTTON); + + TRACE("%ld\n", dwFlags); + + EnableWindow(hwndBack, FALSE); + EnableWindow(hwndNext, FALSE); + EnableWindow(hwndFinish, FALSE); + + if (dwFlags & PSWIZB_BACK) + EnableWindow(hwndBack, TRUE); + + if (dwFlags & PSWIZB_NEXT) + { + /* Hide the Finish button */ + ShowWindow(hwndFinish, SW_HIDE); + + /* Show and enable the Next button */ + ShowWindow(hwndNext, SW_SHOW); + EnableWindow(hwndNext, TRUE); + + /* Set the Next button as the default pushbutton */ + SendMessageW(hwndDlg, DM_SETDEFID, IDC_NEXT_BUTTON, 0); + } + + if ((dwFlags & PSWIZB_FINISH) || (dwFlags & PSWIZB_DISABLEDFINISH)) + { + /* Hide the Next button */ + ShowWindow(hwndNext, SW_HIDE); + + /* Show the Finish button */ + ShowWindow(hwndFinish, SW_SHOW); + + if (dwFlags & PSWIZB_FINISH) + EnableWindow(hwndFinish, TRUE); + + /* Set the Finish button as the default pushbutton */ + SendMessageW(hwndDlg, DM_SETDEFID, IDC_FINISH_BUTTON, 0); + } +} + +/****************************************************************************** + * PROPSHEET_InsertPage + */ +static BOOL PROPSHEET_InsertPage(HWND hwndDlg, HPROPSHEETPAGE hpageInsertAfter, HPROPSHEETPAGE hpage) +{ + if (!HIWORD(hpageInsertAfter)) + FIXME("(%p, %d, %p): stub\n", hwndDlg, LOWORD(hpageInsertAfter), hpage); + else + FIXME("(%p, %p, %p): stub\n", hwndDlg, hpageInsertAfter, hpage); + return FALSE; +} + +/****************************************************************************** + * PROPSHEET_SetHeaderTitleW + */ +static void PROPSHEET_SetHeaderTitleW(HWND hwndDlg, int iPageIndex, LPCWSTR pszHeaderTitle) +{ + FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_w(pszHeaderTitle)); +} + +/****************************************************************************** + * PROPSHEET_SetHeaderTitleA + */ +static void PROPSHEET_SetHeaderTitleA(HWND hwndDlg, int iPageIndex, LPCSTR pszHeaderTitle) +{ + FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_a(pszHeaderTitle)); +} + +/****************************************************************************** + * PROPSHEET_SetHeaderSubTitleW + */ +static void PROPSHEET_SetHeaderSubTitleW(HWND hwndDlg, int iPageIndex, LPCWSTR pszHeaderSubTitle) +{ + FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_w(pszHeaderSubTitle)); +} + +/****************************************************************************** + * PROPSHEET_SetHeaderSubTitleA + */ +static void PROPSHEET_SetHeaderSubTitleA(HWND hwndDlg, int iPageIndex, LPCSTR pszHeaderSubTitle) +{ + FIXME("(%p, %d, %s): stub\n", hwndDlg, iPageIndex, debugstr_a(pszHeaderSubTitle)); +} + +/****************************************************************************** + * PROPSHEET_HwndToIndex + */ +static LRESULT PROPSHEET_HwndToIndex(HWND hwndDlg, HWND hPageDlg) +{ + int index; + PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg, + PropSheetInfoStr); + + TRACE("(%p, %p)\n", hwndDlg, hPageDlg); + + for (index = 0; index < psInfo->nPages; index++) + if (psInfo->proppage[index].hwndPage == hPageDlg) + return index; + WARN("%p not found\n", hPageDlg); + return -1; +} + +/****************************************************************************** + * PROPSHEET_IndexToHwnd + */ +static LRESULT PROPSHEET_IndexToHwnd(HWND hwndDlg, int iPageIndex) +{ + PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg, + PropSheetInfoStr); + TRACE("(%p, %d)\n", hwndDlg, iPageIndex); + if (iPageIndex<0 || iPageIndex>=psInfo->nPages) { + WARN("%d out of range.\n", iPageIndex); + return 0; + } + return (LRESULT)psInfo->proppage[iPageIndex].hwndPage; +} + +/****************************************************************************** + * PROPSHEET_PageToIndex + */ +static LRESULT PROPSHEET_PageToIndex(HWND hwndDlg, HPROPSHEETPAGE hPage) +{ + int index; + PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg, + PropSheetInfoStr); + + TRACE("(%p, %p)\n", hwndDlg, hPage); + + for (index = 0; index < psInfo->nPages; index++) + if (psInfo->proppage[index].hpage == hPage) + return index; + WARN("%p not found\n", hPage); + return -1; +} + +/****************************************************************************** + * PROPSHEET_IndexToPage + */ +static LRESULT PROPSHEET_IndexToPage(HWND hwndDlg, int iPageIndex) +{ + PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg, + PropSheetInfoStr); + TRACE("(%p, %d)\n", hwndDlg, iPageIndex); + if (iPageIndex<0 || iPageIndex>=psInfo->nPages) { + WARN("%d out of range.\n", iPageIndex); + return 0; + } + return (LRESULT)psInfo->proppage[iPageIndex].hpage; +} + +/****************************************************************************** + * PROPSHEET_IdToIndex + */ +static LRESULT PROPSHEET_IdToIndex(HWND hwndDlg, int iPageId) +{ + FIXME("(%p, %d): stub\n", hwndDlg, iPageId); + return -1; +} + +/****************************************************************************** + * PROPSHEET_IndexToId + */ +static LRESULT PROPSHEET_IndexToId(HWND hwndDlg, int iPageIndex) +{ + PropSheetInfo * psInfo = (PropSheetInfo*) GetPropW(hwndDlg, + PropSheetInfoStr); + LPCPROPSHEETPAGEW psp; + TRACE("(%p, %d)\n", hwndDlg, iPageIndex); + if (iPageIndex<0 || iPageIndex>=psInfo->nPages) { + WARN("%d out of range.\n", iPageIndex); + return 0; + } + psp = (LPCPROPSHEETPAGEW)psInfo->proppage[iPageIndex].hpage; + if (psp->dwFlags & PSP_DLGINDIRECT || HIWORD(psp->u.pszTemplate)) { + return 0; + } + return (LRESULT)psp->u.pszTemplate; +} + +/****************************************************************************** + * PROPSHEET_GetResult + */ +static LRESULT PROPSHEET_GetResult(HWND hwndDlg) +{ + FIXME("(%p): stub\n", hwndDlg); + return -1; +} + +/****************************************************************************** + * PROPSHEET_RecalcPageSizes + */ +static BOOL PROPSHEET_RecalcPageSizes(HWND hwndDlg) +{ + FIXME("(%p): stub\n", hwndDlg); + return FALSE; +} + +/****************************************************************************** + * PROPSHEET_GetPageIndex + * + * Given a HPROPSHEETPAGE, returns the index of the corresponding page from + * the array of PropPageInfo. + */ +static int PROPSHEET_GetPageIndex(HPROPSHEETPAGE hpage, PropSheetInfo* psInfo) +{ + BOOL found = FALSE; + int index = 0; + + TRACE("hpage %p\n", hpage); + while ((index < psInfo->nPages) && (found == FALSE)) + { + if (psInfo->proppage[index].hpage == hpage) + found = TRUE; + else + index++; + } + + if (found == FALSE) + index = -1; + + return index; +} + +/****************************************************************************** + * PROPSHEET_CleanUp + */ +static void PROPSHEET_CleanUp(HWND hwndDlg) +{ + int i; + PropSheetInfo* psInfo = (PropSheetInfo*) RemovePropW(hwndDlg, + PropSheetInfoStr); + + TRACE("\n"); + if (!psInfo) return; + if (HIWORD(psInfo->ppshheader.pszCaption)) + Free ((LPVOID)psInfo->ppshheader.pszCaption); + + for (i = 0; i < psInfo->nPages; i++) + { + PROPSHEETPAGEA* psp = (PROPSHEETPAGEA*)psInfo->proppage[i].hpage; + + /* Unsubclass the page dialog window */ + if((psInfo->ppshheader.dwFlags & (PSH_WIZARD97_NEW | PSH_WIZARD97_OLD)) && + (psInfo->ppshheader.dwFlags & PSH_WATERMARK) && + (psp->dwFlags & PSP_HIDEHEADER)) + { + RemoveWindowSubclass(psInfo->proppage[i].hwndPage, + PROPSHEET_WizardSubclassProc, 1); + } + + if(psInfo->proppage[i].hwndPage) + DestroyWindow(psInfo->proppage[i].hwndPage); + + if(psp) + { + if ((psp->dwFlags & PSP_USETITLE) && psInfo->proppage[i].pszText) + Free ((LPVOID)psInfo->proppage[i].pszText); + + DestroyPropertySheetPage(psInfo->proppage[i].hpage); + } + } + + DeleteObject(psInfo->hFont); + DeleteObject(psInfo->hFontBold); + /* If we created the bitmaps, destroy them */ + if ((psInfo->ppshheader.dwFlags & PSH_WATERMARK) && + (!(psInfo->ppshheader.dwFlags & PSH_USEHBMWATERMARK)) ) + DeleteObject(psInfo->ppshheader.u4.hbmWatermark); + if ((psInfo->ppshheader.dwFlags & PSH_HEADER) && + (!(psInfo->ppshheader.dwFlags & PSH_USEHBMHEADER)) ) + DeleteObject(psInfo->ppshheader.u5.hbmHeader); + + Free(psInfo->proppage); + Free(psInfo->strPropertiesFor); + ImageList_Destroy(psInfo->hImageList); + + GlobalFree((HGLOBAL)psInfo); +} + +static INT do_loop(PropSheetInfo *psInfo) +{ + MSG msg; + INT ret = -1; + HWND hwnd = psInfo->hwnd; + + while(IsWindow(hwnd) && !psInfo->ended && (ret = GetMessageW(&msg, NULL, 0, 0))) + { + if(ret == -1) + break; + + if(!IsDialogMessageW(hwnd, &msg)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + + if(ret == 0) + { + PostQuitMessage(msg.wParam); + ret = -1; + } + + DestroyWindow(hwnd); + return ret; +} + +/****************************************************************************** + * PropertySheet (COMCTL32.@) + * PropertySheetA (COMCTL32.@) + * + * Creates a property sheet in the specified property sheet header. + * + * RETURNS + * Modal property sheets: Positive if successful or -1 otherwise. + * Modeless property sheets: Property sheet handle. + * Or: + *| ID_PSREBOOTSYSTEM - The user must reboot the computer for the changes to take effect. + *| ID_PSRESTARTWINDOWS - The user must restart Windows for the changes to take effect. + */ +INT WINAPI PropertySheetA(LPCPROPSHEETHEADERA lppsh) +{ + int bRet = 0; + PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR, + sizeof(PropSheetInfo)); + UINT i, n; + BYTE* pByte; + + TRACE("(%p)\n", lppsh); + + PROPSHEET_CollectSheetInfoA(lppsh, psInfo); + + psInfo->proppage = (PropPageInfo*) Alloc(sizeof(PropPageInfo) * + lppsh->nPages); + pByte = (BYTE*) psInfo->ppshheader.u3.ppsp; + + for (n = i = 0; i < lppsh->nPages; i++, n++) + { + if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE)) + psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i]; + else + { + psInfo->proppage[n].hpage = CreatePropertySheetPageA((LPCPROPSHEETPAGEA)pByte); + pByte += ((LPPROPSHEETPAGEA)pByte)->dwSize; + } + + if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEW)psInfo->proppage[n].hpage, + psInfo, n)) + { + if (lppsh->dwFlags & PSH_PROPSHEETPAGE) + DestroyPropertySheetPage(psInfo->proppage[n].hpage); + n--; + psInfo->nPages--; + } + } + + psInfo->unicode = FALSE; + psInfo->ended = FALSE; + + bRet = PROPSHEET_CreateDialog(psInfo); + if(!psInfo->isModeless) + bRet = do_loop(psInfo); + + return bRet; +} + +/****************************************************************************** + * PropertySheetW (COMCTL32.@) + * + * See PropertySheetA. + */ +INT WINAPI PropertySheetW(LPCPROPSHEETHEADERW lppsh) +{ + int bRet = 0; + PropSheetInfo* psInfo = (PropSheetInfo*) GlobalAlloc(GPTR, + sizeof(PropSheetInfo)); + UINT i, n; + BYTE* pByte; + + TRACE("(%p)\n", lppsh); + + PROPSHEET_CollectSheetInfoW(lppsh, psInfo); + + psInfo->proppage = (PropPageInfo*) Alloc(sizeof(PropPageInfo) * + lppsh->nPages); + pByte = (BYTE*) psInfo->ppshheader.u3.ppsp; + + for (n = i = 0; i < lppsh->nPages; i++, n++) + { + if (!(lppsh->dwFlags & PSH_PROPSHEETPAGE)) + psInfo->proppage[n].hpage = psInfo->ppshheader.u3.phpage[i]; + else + { + psInfo->proppage[n].hpage = CreatePropertySheetPageW((LPCPROPSHEETPAGEW)pByte); + pByte += ((LPPROPSHEETPAGEW)pByte)->dwSize; + } + + if (!PROPSHEET_CollectPageInfo((LPCPROPSHEETPAGEW)psInfo->proppage[n].hpage, + psInfo, n)) + { + if (lppsh->dwFlags & PSH_PROPSHEETPAGE) + DestroyPropertySheetPage(psInfo->proppage[n].hpage); + n--; + psInfo->nPages--; + } + } + + psInfo->unicode = TRUE; + psInfo->ended = FALSE; + + bRet = PROPSHEET_CreateDialog(psInfo); + if(!psInfo->isModeless) + bRet = do_loop(psInfo); + + return bRet; +} + +/****************************************************************************** + * CreatePropertySheetPage (COMCTL32.@) + * CreatePropertySheetPageA (COMCTL32.@) + * + * Creates a new property sheet page. + * + * RETURNS + * Success: Handle to new property sheet page. + * Failure: NULL. + * + * NOTES + * An application must use the PSM_ADDPAGE message to add the new page to + * an existing property sheet. + */ +HPROPSHEETPAGE WINAPI CreatePropertySheetPageA( + LPCPROPSHEETPAGEA lpPropSheetPage) +{ + PROPSHEETPAGEW* ppsp = Alloc(sizeof(PROPSHEETPAGEW)); + + memcpy(ppsp,lpPropSheetPage,min(lpPropSheetPage->dwSize,sizeof(PROPSHEETPAGEA))); + + ppsp->dwFlags &= ~ PSP_INTERNAL_UNICODE; + if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) && HIWORD( ppsp->u.pszTemplate ) ) + { + int len = strlen(lpPropSheetPage->u.pszTemplate); + + ppsp->u.pszTemplate = Alloc( len+1 ); + strcpy( (LPSTR)ppsp->u.pszTemplate, lpPropSheetPage->u.pszTemplate ); + } + if ( (ppsp->dwFlags & PSP_USEICONID) && HIWORD( ppsp->u2.pszIcon ) ) + { + PROPSHEET_AtoW(&ppsp->u2.pszIcon, lpPropSheetPage->u2.pszIcon); + } + + if ((ppsp->dwFlags & PSP_USETITLE) && HIWORD( ppsp->pszTitle )) + { + PROPSHEET_AtoW(&ppsp->pszTitle, lpPropSheetPage->pszTitle); + } + else if ( !(ppsp->dwFlags & PSP_USETITLE) ) + ppsp->pszTitle = NULL; + + return (HPROPSHEETPAGE)ppsp; +} + +/****************************************************************************** + * CreatePropertySheetPageW (COMCTL32.@) + * + * See CreatePropertySheetA. + */ +HPROPSHEETPAGE WINAPI CreatePropertySheetPageW(LPCPROPSHEETPAGEW lpPropSheetPage) +{ + PROPSHEETPAGEW* ppsp = Alloc(sizeof(PROPSHEETPAGEW)); + + memcpy(ppsp,lpPropSheetPage,min(lpPropSheetPage->dwSize,sizeof(PROPSHEETPAGEW))); + + ppsp->dwFlags |= PSP_INTERNAL_UNICODE; + + if ( !(ppsp->dwFlags & PSP_DLGINDIRECT) && HIWORD( ppsp->u.pszTemplate ) ) + { + int len = strlenW(lpPropSheetPage->u.pszTemplate); + + ppsp->u.pszTemplate = Alloc( (len+1)*sizeof (WCHAR) ); + strcpyW( (WCHAR *)ppsp->u.pszTemplate, lpPropSheetPage->u.pszTemplate ); + } + if ( (ppsp->dwFlags & PSP_USEICONID) && HIWORD( ppsp->u2.pszIcon ) ) + { + int len = strlenW(lpPropSheetPage->u2.pszIcon); + ppsp->u2.pszIcon = Alloc( (len+1)*sizeof (WCHAR) ); + strcpyW( (WCHAR *)ppsp->u2.pszIcon, lpPropSheetPage->u2.pszIcon ); + } + + if ((ppsp->dwFlags & PSP_USETITLE) && HIWORD( ppsp->pszTitle )) + { + int len = strlenW(lpPropSheetPage->pszTitle); + ppsp->pszTitle = Alloc( (len+1)*sizeof (WCHAR) ); + strcpyW( (WCHAR *)ppsp->pszTitle, lpPropSheetPage->pszTitle ); + } + else if ( !(ppsp->dwFlags & PSP_USETITLE) ) + ppsp->pszTitle = NULL; + + return (HPROPSHEETPAGE)ppsp; +} + +/****************************************************************************** + * DestroyPropertySheetPage (COMCTL32.@) + * + * Destroys a property sheet page previously created with + * CreatePropertySheetA() or CreatePropertySheetW() and frees the associated + * memory. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI DestroyPropertySheetPage(HPROPSHEETPAGE hPropPage) +{ + PROPSHEETPAGEW *psp = (PROPSHEETPAGEW *)hPropPage; + + if (!psp) + return FALSE; + + if ( !(psp->dwFlags & PSP_DLGINDIRECT) && HIWORD( psp->u.pszTemplate ) ) + Free ((LPVOID)psp->u.pszTemplate); + + if ( (psp->dwFlags & PSP_USEICONID) && HIWORD( psp->u2.pszIcon ) ) + Free ((LPVOID)psp->u2.pszIcon); + + if ((psp->dwFlags & PSP_USETITLE) && HIWORD( psp->pszTitle )) + Free ((LPVOID)psp->pszTitle); + + Free(hPropPage); + + return TRUE; +} + +/****************************************************************************** + * PROPSHEET_IsDialogMessage + */ +static BOOL PROPSHEET_IsDialogMessage(HWND hwnd, LPMSG lpMsg) +{ + PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, PropSheetInfoStr); + + TRACE("\n"); + if (!psInfo || (hwnd != lpMsg->hwnd && !IsChild(hwnd, lpMsg->hwnd))) + return FALSE; + + if (lpMsg->message == WM_KEYDOWN && (GetKeyState(VK_CONTROL) & 0x8000)) + { + int new_page = 0; + INT dlgCode = SendMessageW(lpMsg->hwnd, WM_GETDLGCODE, 0, (LPARAM)lpMsg); + + if (!(dlgCode & DLGC_WANTMESSAGE)) + { + switch (lpMsg->wParam) + { + case VK_TAB: + if (GetKeyState(VK_SHIFT) & 0x8000) + new_page = -1; + else + new_page = 1; + break; + + case VK_NEXT: new_page = 1; break; + case VK_PRIOR: new_page = -1; break; + } + } + + if (new_page) + { + if (PROPSHEET_CanSetCurSel(hwnd) != FALSE) + { + new_page += psInfo->active_page; + + if (new_page < 0) + new_page = psInfo->nPages - 1; + else if (new_page >= psInfo->nPages) + new_page = 0; + + PROPSHEET_SetCurSel(hwnd, new_page, 1, 0); + } + + return TRUE; + } + } + + return IsDialogMessageW(hwnd, lpMsg); +} + +/****************************************************************************** + * PROPSHEET_DoCommand + */ +static BOOL PROPSHEET_DoCommand(HWND hwnd, WORD wID) +{ + + switch (wID) { + + case IDOK: + case IDC_APPLY_BUTTON: + { + HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON); + + if (PROPSHEET_Apply(hwnd, wID == IDOK ? 1: 0) == FALSE) + break; + + if (wID == IDOK) + { + PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, + PropSheetInfoStr); + int result = TRUE; + + if (psInfo->restartWindows) + result = ID_PSRESTARTWINDOWS; + + /* reboot system takes precedence over restart windows */ + if (psInfo->rebootSystem) + result = ID_PSREBOOTSYSTEM; + + if (psInfo->isModeless) + psInfo->activeValid = FALSE; + else + psInfo->ended = TRUE; + } + else + EnableWindow(hwndApplyBtn, FALSE); + + break; + } + + case IDC_BACK_BUTTON: + PROPSHEET_Back(hwnd); + break; + + case IDC_NEXT_BUTTON: + PROPSHEET_Next(hwnd); + break; + + case IDC_FINISH_BUTTON: + PROPSHEET_Finish(hwnd); + break; + + case IDCANCEL: + PROPSHEET_Cancel(hwnd, 0); + break; + + case IDHELP: + PROPSHEET_Help(hwnd); + break; + + default: + return FALSE; + } + + return TRUE; +} + +/****************************************************************************** + * PROPSHEET_Paint + */ +static LRESULT PROPSHEET_Paint(HWND hwnd, HDC hdcParam) +{ + PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, PropSheetInfoStr); + PAINTSTRUCT ps; + HDC hdc, hdcSrc; + BITMAP bm; + HBITMAP hbmp; + HPALETTE hOldPal = 0; + int offsety = 0; + HBRUSH hbr; + RECT r, rzone; + LPCPROPSHEETPAGEW ppshpage; + WCHAR szBuffer[256]; + int nLength; + + hdc = hdcParam ? hdcParam : BeginPaint(hwnd, &ps); + if (!hdc) return 1; + + hdcSrc = CreateCompatibleDC(0); + ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[psInfo->active_page].hpage; + + if (psInfo->ppshheader.dwFlags & PSH_USEHPLWATERMARK) + hOldPal = SelectPalette(hdc, psInfo->ppshheader.hplWatermark, FALSE); + + if ( (!(ppshpage->dwFlags & PSP_HIDEHEADER)) && + (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) && + (psInfo->ppshheader.dwFlags & PSH_HEADER) ) + { + HWND hwndLineHeader = GetDlgItem(hwnd, IDC_SUNKEN_LINEHEADER); + HFONT hOldFont; + COLORREF clrOld = 0; + int oldBkMode = 0; + + hbmp = SelectObject(hdcSrc, psInfo->ppshheader.u5.hbmHeader); + hOldFont = SelectObject(hdc, psInfo->hFontBold); + + GetClientRect(hwndLineHeader, &r); + MapWindowPoints(hwndLineHeader, hwnd, (LPPOINT) &r, 2); + SetRect(&rzone, 0, 0, r.right + 1, r.top - 1); + + GetObjectW(psInfo->ppshheader.u5.hbmHeader, sizeof(BITMAP), (LPVOID)&bm); + + if (psInfo->ppshheader.dwFlags & PSH_WIZARD97_OLD) + { + /* Fill the unoccupied part of the header with color of the + * left-top pixel, but do it only when needed. + */ + if (bm.bmWidth < r.right || bm.bmHeight < r.bottom) + { + hbr = CreateSolidBrush(GetPixel(hdcSrc, 0, 0)); + CopyRect(&r, &rzone); + if (bm.bmWidth < r.right) + { + r.left = bm.bmWidth; + FillRect(hdc, &r, hbr); + } + if (bm.bmHeight < r.bottom) + { + r.left = 0; + r.top = bm.bmHeight; + FillRect(hdc, &r, hbr); + } + DeleteObject(hbr); + } + + /* Draw the header itself. */ + BitBlt(hdc, 0, 0, + bm.bmWidth, min(bm.bmHeight, rzone.bottom), + hdcSrc, 0, 0, SRCCOPY); + } + else + { + hbr = GetSysColorBrush(COLOR_WINDOW); + FillRect(hdc, &rzone, hbr); + + /* Draw the header bitmap. It's always centered like a + * common 49 x 49 bitmap. */ + BitBlt(hdc, rzone.right - 49 - ((rzone.bottom - 49) / 2), + (rzone.bottom - 49) / 2, + bm.bmWidth, bm.bmHeight, + hdcSrc, 0, 0, SRCCOPY); + + /* NOTE: Native COMCTL32 draws a white stripe over the bitmap + * if its height is smaller than 49 pixels. Because the reason + * for this bug is unknown the current code doesn't try to + * replicate it. */ + } + + clrOld = SetTextColor (hdc, 0x00000000); + oldBkMode = SetBkMode (hdc, TRANSPARENT); + + if (ppshpage->dwFlags & PSP_USEHEADERTITLE) { + SetRect(&r, 20, 10, 0, 0); + if (HIWORD(ppshpage->pszHeaderTitle)) + { + if (psInfo->unicode) + DrawTextW(hdc, (LPWSTR)ppshpage->pszHeaderTitle, + -1, &r, DT_LEFT | DT_SINGLELINE | DT_NOCLIP); + else + DrawTextA(hdc, (LPCSTR)ppshpage->pszHeaderTitle, + -1, &r, DT_LEFT | DT_SINGLELINE | DT_NOCLIP); + } + else + { + nLength = LoadStringW(ppshpage->hInstance, (UINT)ppshpage->pszHeaderTitle, + szBuffer, 256); + if (nLength != 0) + { + DrawTextW(hdc, szBuffer, nLength, + &r, DT_LEFT | DT_SINGLELINE | DT_NOCLIP); + } + } + } + + if (ppshpage->dwFlags & PSP_USEHEADERSUBTITLE) { + SelectObject(hdc, psInfo->hFont); + SetRect(&r, 40, 25, rzone.right - 69, rzone.bottom); + if (HIWORD(ppshpage->pszHeaderTitle)) + { + if (psInfo->unicode) + DrawTextW(hdc, (LPWSTR)ppshpage->pszHeaderSubTitle, + -1, &r, DT_LEFT | DT_SINGLELINE); + else + DrawTextA(hdc, (LPCSTR)ppshpage->pszHeaderSubTitle, + -1, &r, DT_LEFT | DT_SINGLELINE); + } + else + { + nLength = LoadStringW(ppshpage->hInstance, (UINT)ppshpage->pszHeaderSubTitle, + szBuffer, 256); + if (nLength != 0) + { + DrawTextW(hdc, szBuffer, nLength, + &r, DT_LEFT | DT_SINGLELINE); + } + } + } + + offsety = rzone.bottom + 2; + + SetTextColor(hdc, clrOld); + SetBkMode(hdc, oldBkMode); + SelectObject(hdc, hOldFont); + SelectObject(hdcSrc, hbmp); + } + + if ( (ppshpage->dwFlags & PSP_HIDEHEADER) && + (psInfo->ppshheader.dwFlags & (PSH_WIZARD97_OLD | PSH_WIZARD97_NEW)) && + (psInfo->ppshheader.dwFlags & PSH_WATERMARK) ) + { + HWND hwndLine = GetDlgItem(hwnd, IDC_SUNKEN_LINE); + + GetClientRect(hwndLine, &r); + MapWindowPoints(hwndLine, hwnd, (LPPOINT) &r, 2); + + rzone.left = 0; + rzone.top = 0; + rzone.right = r.right; + rzone.bottom = r.top - 1; + + hbr = GetSysColorBrush(COLOR_WINDOW); + FillRect(hdc, &rzone, hbr); + + GetObjectW(psInfo->ppshheader.u4.hbmWatermark, sizeof(BITMAP), (LPVOID)&bm); + hbmp = SelectObject(hdcSrc, psInfo->ppshheader.u4.hbmWatermark); + + BitBlt(hdc, 0, offsety, min(bm.bmWidth, r.right), + min(bm.bmHeight, r.bottom), hdcSrc, 0, 0, SRCCOPY); + + /* If the bitmap is not big enough, fill the remaining area + with the color of pixel (0,0) of bitmap - see MSDN */ + if (r.top > bm.bmHeight) { + r.bottom = r.top - 1; + r.top = bm.bmHeight; + r.left = 0; + r.right = bm.bmWidth; + hbr = CreateSolidBrush(GetPixel(hdcSrc, 0, 0)); + FillRect(hdc, &r, hbr); + DeleteObject(hbr); + } + + SelectObject(hdcSrc, hbmp); + } + + if (psInfo->ppshheader.dwFlags & PSH_USEHPLWATERMARK) + SelectPalette(hdc, hOldPal, FALSE); + + DeleteDC(hdcSrc); + + if (!hdcParam) EndPaint(hwnd, &ps); + + return 0; +} + +/****************************************************************************** + * PROPSHEET_DialogProc + */ +INT_PTR CALLBACK +PROPSHEET_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + TRACE("hwnd=%p msg=0x%04x wparam=%x lparam=%lx\n", + hwnd, uMsg, wParam, lParam); + + switch (uMsg) + { + case WM_INITDIALOG: + { + PropSheetInfo* psInfo = (PropSheetInfo*) lParam; + WCHAR* strCaption = (WCHAR*)Alloc(MAX_CAPTION_LENGTH*sizeof(WCHAR)); + HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL); + LPCPROPSHEETPAGEW ppshpage; + int idx; + LOGFONTW logFont; + + /* Using PropSheetInfoStr to store extra data doesn't match the native + * common control: native uses TCM_[GS]ETITEM + */ + SetPropW(hwnd, PropSheetInfoStr, (HANDLE)psInfo); + + /* + * psInfo->hwnd is not being used by WINE code - it exists + * for compatibility with "real" Windoze. The same about + * SetWindowLongPtr - WINE is only using the PropSheetInfoStr + * property. + */ + psInfo->hwnd = hwnd; + SetWindowLongPtrW(hwnd, DWLP_USER, (DWORD_PTR)psInfo); + + /* set up the Next and Back buttons by default */ + PROPSHEET_SetWizButtons(hwnd, PSWIZB_BACK|PSWIZB_NEXT); + + /* Set up fonts */ + SystemParametersInfoW (SPI_GETICONTITLELOGFONT, 0, &logFont, 0); + psInfo->hFont = CreateFontIndirectW (&logFont); + logFont.lfWeight = FW_BOLD; + psInfo->hFontBold = CreateFontIndirectW (&logFont); + + /* + * Small icon in the title bar. + */ + if ((psInfo->ppshheader.dwFlags & PSH_USEICONID) || + (psInfo->ppshheader.dwFlags & PSH_USEHICON)) + { + HICON hIcon; + int icon_cx = GetSystemMetrics(SM_CXSMICON); + int icon_cy = GetSystemMetrics(SM_CYSMICON); + + if (psInfo->ppshheader.dwFlags & PSH_USEICONID) + hIcon = LoadImageW(psInfo->ppshheader.hInstance, + psInfo->ppshheader.u.pszIcon, + IMAGE_ICON, + icon_cx, icon_cy, + LR_DEFAULTCOLOR); + else + hIcon = psInfo->ppshheader.u.hIcon; + + SendMessageW(hwnd, WM_SETICON, 0, (LPARAM)hIcon); + } + + if (psInfo->ppshheader.dwFlags & PSH_USEHICON) + SendMessageW(hwnd, WM_SETICON, 0, (LPARAM)psInfo->ppshheader.u.hIcon); + + psInfo->strPropertiesFor = strCaption; + + GetWindowTextW(hwnd, psInfo->strPropertiesFor, MAX_CAPTION_LENGTH); + + PROPSHEET_CreateTabControl(hwnd, psInfo); + + PROPSHEET_LoadWizardBitmaps(psInfo); + + if (psInfo->ppshheader.dwFlags & INTRNL_ANY_WIZARD) + { + ShowWindow(hwndTabCtrl, SW_HIDE); + PROPSHEET_AdjustSizeWizard(hwnd, psInfo); + PROPSHEET_AdjustButtonsWizard(hwnd, psInfo); + } + else + { + if (PROPSHEET_SizeMismatch(hwnd, psInfo)) + { + PROPSHEET_AdjustSize(hwnd, psInfo); + PROPSHEET_AdjustButtons(hwnd, psInfo); + } + } + + if (psInfo->useCallback) + (*(psInfo->ppshheader.pfnCallback))(hwnd, + PSCB_INITIALIZED, (LPARAM)0); + + idx = psInfo->active_page; + ppshpage = (LPCPROPSHEETPAGEW)psInfo->proppage[idx].hpage; + psInfo->active_page = -1; + + PROPSHEET_SetCurSel(hwnd, idx, 1, psInfo->proppage[idx].hpage); + + /* doing TCM_SETCURSEL seems to be needed even in case of PSH_WIZARD, + * as some programs call TCM_GETCURSEL to get the current selection + * from which to switch to the next page */ + SendMessageW(hwndTabCtrl, TCM_SETCURSEL, psInfo->active_page, 0); + + if (!HIWORD(psInfo->ppshheader.pszCaption) && + psInfo->ppshheader.hInstance) + { + WCHAR szText[256]; + + if (LoadStringW(psInfo->ppshheader.hInstance, + (UINT)psInfo->ppshheader.pszCaption, szText, 255)) + PROPSHEET_SetTitleW(hwnd, psInfo->ppshheader.dwFlags, szText); + } + else + { + PROPSHEET_SetTitleW(hwnd, psInfo->ppshheader.dwFlags, + psInfo->ppshheader.pszCaption); + } + + return TRUE; + } + + case WM_PAINT: + PROPSHEET_Paint(hwnd, (HDC)wParam); + return TRUE; + + case WM_DESTROY: + PROPSHEET_CleanUp(hwnd); + return TRUE; + + case WM_CLOSE: + PROPSHEET_Cancel(hwnd, 1); + return TRUE; + + case WM_COMMAND: + if (!PROPSHEET_DoCommand(hwnd, LOWORD(wParam))) + { + PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, PropSheetInfoStr); + + if (!psInfo) + return FALSE; + + /* No default handler, forward notification to active page */ + if (psInfo->activeValid && psInfo->active_page != -1) + { + HWND hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; + SendMessageW(hwndPage, WM_COMMAND, wParam, lParam); + } + } + return TRUE; + + case WM_SYSCOMMAND: + switch(wParam & 0xfff0) + { + case SC_CLOSE: + PROPSHEET_Cancel(hwnd, 1); + return TRUE; + + default: + return FALSE; + } + + case WM_NOTIFY: + { + NMHDR* pnmh = (LPNMHDR) lParam; + + if (pnmh->code == TCN_SELCHANGE) + { + int index = SendMessageW(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0); + PROPSHEET_SetCurSel(hwnd, index, 1, 0); + } + + if(pnmh->code == TCN_SELCHANGING) + { + BOOL bRet = PROPSHEET_CanSetCurSel(hwnd); + SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, !bRet); + return TRUE; + } + + return FALSE; + } + + case PSM_GETCURRENTPAGEHWND: + { + PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, + PropSheetInfoStr); + HWND hwndPage = 0; + + if (!psInfo) + return FALSE; + + if (psInfo->activeValid && psInfo->active_page != -1) + hwndPage = psInfo->proppage[psInfo->active_page].hwndPage; + + SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, (DWORD_PTR)hwndPage); + + return TRUE; + } + + case PSM_CHANGED: + PROPSHEET_Changed(hwnd, (HWND)wParam); + return TRUE; + + case PSM_UNCHANGED: + PROPSHEET_UnChanged(hwnd, (HWND)wParam); + return TRUE; + + case PSM_GETTABCONTROL: + { + HWND hwndTabCtrl = GetDlgItem(hwnd, IDC_TABCONTROL); + + SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, (DWORD_PTR)hwndTabCtrl); + + return TRUE; + } + + case PSM_SETCURSEL: + { + BOOL msgResult; + + msgResult = PROPSHEET_CanSetCurSel(hwnd); + if(msgResult != FALSE) + { + msgResult = PROPSHEET_SetCurSel(hwnd, + (int)wParam, + 1, + (HPROPSHEETPAGE)lParam); + } + + SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); + + return TRUE; + } + + case PSM_CANCELTOCLOSE: + { + WCHAR buf[MAX_BUTTONTEXT_LENGTH]; + HWND hwndOK = GetDlgItem(hwnd, IDOK); + HWND hwndCancel = GetDlgItem(hwnd, IDCANCEL); + + EnableWindow(hwndCancel, FALSE); + if (LoadStringW(COMCTL32_hModule, IDS_CLOSE, buf, sizeof(buf))) + SetWindowTextW(hwndOK, buf); + + return FALSE; + } + + case PSM_RESTARTWINDOWS: + { + PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, + PropSheetInfoStr); + + if (!psInfo) + return FALSE; + + psInfo->restartWindows = TRUE; + return TRUE; + } + + case PSM_REBOOTSYSTEM: + { + PropSheetInfo* psInfo = (PropSheetInfo*) GetPropW(hwnd, + PropSheetInfoStr); + + if (!psInfo) + return FALSE; + + psInfo->rebootSystem = TRUE; + return TRUE; + } + + case PSM_SETTITLEA: + PROPSHEET_SetTitleA(hwnd, (DWORD) wParam, (LPCSTR) lParam); + return TRUE; + + case PSM_SETTITLEW: + PROPSHEET_SetTitleW(hwnd, (DWORD) wParam, (LPCWSTR) lParam); + return TRUE; + + case PSM_APPLY: + { + BOOL msgResult = PROPSHEET_Apply(hwnd, 0); + + SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); + + return TRUE; + } + + case PSM_QUERYSIBLINGS: + { + LRESULT msgResult = PROPSHEET_QuerySiblings(hwnd, wParam, lParam); + + SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); + + return TRUE; + } + + case PSM_ADDPAGE: + { + /* + * Note: MSVC++ 6.0 documentation says that PSM_ADDPAGE does not have + * a return value. This is not true. PSM_ADDPAGE returns TRUE + * on success or FALSE otherwise, as specified on MSDN Online. + * Also see the MFC code for + * CPropertySheet::AddPage(CPropertyPage* pPage). + */ + + BOOL msgResult = PROPSHEET_AddPage(hwnd, (HPROPSHEETPAGE)lParam); + + SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); + + return TRUE; + } + + case PSM_REMOVEPAGE: + PROPSHEET_RemovePage(hwnd, (int)wParam, (HPROPSHEETPAGE)lParam); + return TRUE; + + case PSM_ISDIALOGMESSAGE: + { + BOOL msgResult = PROPSHEET_IsDialogMessage(hwnd, (LPMSG)lParam); + SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); + return TRUE; + } + + case PSM_PRESSBUTTON: + PROPSHEET_PressButton(hwnd, (int)wParam); + return TRUE; + + case PSM_SETFINISHTEXTA: + PROPSHEET_SetFinishTextA(hwnd, (LPCSTR) lParam); + return TRUE; + + case PSM_SETWIZBUTTONS: + PROPSHEET_SetWizButtons(hwnd, (DWORD)lParam); + return TRUE; + + case PSM_SETCURSELID: + PROPSHEET_SetCurSelId(hwnd, (int)lParam); + return TRUE; + + case PSM_SETFINISHTEXTW: + PROPSHEET_SetFinishTextW(hwnd, (LPCWSTR) lParam); + return FALSE; + + case PSM_INSERTPAGE: + { + BOOL msgResult = PROPSHEET_InsertPage(hwnd, (HPROPSHEETPAGE)wParam, (HPROPSHEETPAGE)lParam); + SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); + return TRUE; + } + + case PSM_SETHEADERTITLEW: + PROPSHEET_SetHeaderTitleW(hwnd, (int)wParam, (LPCWSTR)lParam); + return TRUE; + + case PSM_SETHEADERTITLEA: + PROPSHEET_SetHeaderTitleA(hwnd, (int)wParam, (LPCSTR)lParam); + return TRUE; + + case PSM_SETHEADERSUBTITLEW: + PROPSHEET_SetHeaderSubTitleW(hwnd, (int)wParam, (LPCWSTR)lParam); + return TRUE; + + case PSM_SETHEADERSUBTITLEA: + PROPSHEET_SetHeaderSubTitleA(hwnd, (int)wParam, (LPCSTR)lParam); + return TRUE; + + case PSM_HWNDTOINDEX: + { + LRESULT msgResult = PROPSHEET_HwndToIndex(hwnd, (HWND)wParam); + SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); + return TRUE; + } + + case PSM_INDEXTOHWND: + { + LRESULT msgResult = PROPSHEET_IndexToHwnd(hwnd, (int)wParam); + SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); + return TRUE; + } + + case PSM_PAGETOINDEX: + { + LRESULT msgResult = PROPSHEET_PageToIndex(hwnd, (HPROPSHEETPAGE)wParam); + SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); + return TRUE; + } + + case PSM_INDEXTOPAGE: + { + LRESULT msgResult = PROPSHEET_IndexToPage(hwnd, (int)wParam); + SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); + return TRUE; + } + + case PSM_IDTOINDEX: + { + LRESULT msgResult = PROPSHEET_IdToIndex(hwnd, (int)lParam); + SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); + return TRUE; + } + + case PSM_INDEXTOID: + { + LRESULT msgResult = PROPSHEET_IndexToId(hwnd, (int)wParam); + SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); + return TRUE; + } + + case PSM_GETRESULT: + { + LRESULT msgResult = PROPSHEET_GetResult(hwnd); + SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); + return TRUE; + } + + case PSM_RECALCPAGESIZES: + { + LRESULT msgResult = PROPSHEET_RecalcPageSizes(hwnd); + SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, msgResult); + return TRUE; + } + + default: + return FALSE; + } +} diff --git a/reactos/lib/comctl32/rebar.c b/reactos/lib/comctl32/rebar.c index 74caef36918..83cc85ada50 100644 --- a/reactos/lib/comctl32/rebar.c +++ b/reactos/lib/comctl32/rebar.c @@ -1,4743 +1,4743 @@ -/* - * Rebar control - * - * Copyright 1998, 1999 Eric Kohl - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTES - * - * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on Oct. 19, 2004, by Robert Shearman. - * - * Unless otherwise noted, we believe this code to be complete, as per - * the specification mentioned above. - * If you discover missing features or bugs please note them below. - * - * TODO - * Styles: - * - RBS_DBLCLKTOGGLE - * - RBS_FIXEDORDER - * - RBS_REGISTERDROP - * - RBS_TOOLTIPS - * - CCS_NORESIZE - * - CCS_NOMOVEX - * - CCS_NOMOVEY - * Messages: - * - RB_BEGINDRAG - * - RB_DRAGMOVE - * - RB_ENDDRAG - * - RB_GETBANDMARGINS - * - RB_GETCOLORSCHEME - * - RB_GETDROPTARGET - * - RB_GETPALETTE - * - RB_SETCOLORSCHEME - * - RB_SETPALETTE - * - RB_SETTOOLTIPS - * - WM_CHARTOITEM - * - WM_LBUTTONDBLCLK - * - WM_MEASUREITEM - * - WM_PALETTECHANGED - * - WM_PRINTCLIENT - * - WM_QUERYNEWPALETTE - * - WM_RBUTTONDOWN - * - WM_RBUTTONUP - * - WM_SYSCOLORCHANGE - * - WM_VKEYTOITEM - * - WM_WININICHANGE - * Notifications: - * - NM_HCHITTEST - * - NM_RELEASEDCAPTURE - * - RBN_AUTOBREAK - * - RBN_GETOBJECT - * - RBN_MINMAX - * Band styles: - * - RBBS_FIXEDBMP - * Native uses (on each draw!!) SM_CYBORDER (or SM_CXBORDER for CCS_VERT) - * to set the size of the separator width (the value SEP_WIDTH_SIZE - * in here). Should be fixed!! - */ - -/* - * Testing: set to 1 to make background brush *always* green - */ -#define GLATESTING 0 - -/* - * - * 2. At "FIXME: problem # 2" WinRAR: - * if "#if 1" then last band draws in separate row - * if "#if 0" then last band draws in previous row *** just like native *** - * - */ -#define PROBLEM2 0 - -/* - * 3. REBAR_MoveChildWindows should have a loop because more than - * one pass is made (together with the RBN_CHILDSIZEs) is made on - * at least RB_INSERTBAND - */ - -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "wine/unicode.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "comctl32.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(rebar); - -typedef struct -{ - UINT fStyle; - UINT fMask; - COLORREF clrFore; - COLORREF clrBack; - INT iImage; - HWND hwndChild; - UINT cxMinChild; /* valid if _CHILDSIZE */ - UINT cyMinChild; /* valid if _CHILDSIZE */ - UINT cx; /* valid if _SIZE */ - HBITMAP hbmBack; - UINT wID; - UINT cyChild; /* valid if _CHILDSIZE */ - UINT cyMaxChild; /* valid if _CHILDSIZE */ - UINT cyIntegral; /* valid if _CHILDSIZE */ - UINT cxIdeal; - LPARAM lParam; - UINT cxHeader; - - UINT lcx; /* minimum cx for band */ - UINT ccx; /* current cx for band */ - UINT hcx; /* maximum cx for band */ - UINT lcy; /* minimum cy for band */ - UINT ccy; /* current cy for band */ - UINT hcy; /* maximum cy for band */ - - SIZE offChild; /* x,y offset if child is not FIXEDSIZE */ - UINT uMinHeight; - INT iRow; /* zero-based index of the row this band assigned to */ - UINT fStatus; /* status flags, reset only by _Validate */ - UINT fDraw; /* drawing flags, reset only by _Layout */ - UINT uCDret; /* last return from NM_CUSTOMDRAW */ - RECT rcoldBand; /* previous calculated band rectangle */ - RECT rcBand; /* calculated band rectangle */ - RECT rcGripper; /* calculated gripper rectangle */ - RECT rcCapImage; /* calculated caption image rectangle */ - RECT rcCapText; /* calculated caption text rectangle */ - RECT rcChild; /* calculated child rectangle */ - RECT rcChevron; /* calculated chevron rectangle */ - - LPWSTR lpText; - HWND hwndPrevParent; -} REBAR_BAND; - -/* fStatus flags */ -#define HAS_GRIPPER 0x00000001 -#define HAS_IMAGE 0x00000002 -#define HAS_TEXT 0x00000004 - -/* fDraw flags */ -#define DRAW_GRIPPER 0x00000001 -#define DRAW_IMAGE 0x00000002 -#define DRAW_TEXT 0x00000004 -#define DRAW_RIGHTSEP 0x00000010 -#define DRAW_BOTTOMSEP 0x00000020 -#define DRAW_CHEVRONHOT 0x00000040 -#define DRAW_CHEVRONPUSHED 0x00000080 -#define DRAW_LAST_IN_ROW 0x00000100 -#define DRAW_FIRST_IN_ROW 0x00000200 -#define NTF_INVALIDATE 0x01000000 - -typedef struct -{ - COLORREF clrBk; /* background color */ - COLORREF clrText; /* text color */ - COLORREF clrBtnText; /* system color for BTNTEXT */ - COLORREF clrBtnFace; /* system color for BTNFACE */ - HIMAGELIST himl; /* handle to imagelist */ - UINT uNumBands; /* # of bands in rebar (first=0, last=uNumBands-1 */ - UINT uNumRows; /* # of rows of bands (first=1, last=uNumRows */ - HWND hwndSelf; /* handle of REBAR window itself */ - HWND hwndToolTip; /* handle to the tool tip control */ - HWND hwndNotify; /* notification window (parent) */ - HFONT hDefaultFont; - HFONT hFont; /* handle to the rebar's font */ - SIZE imageSize; /* image size (image list) */ - DWORD dwStyle; /* window style */ - SIZE calcSize; /* calculated rebar size */ - SIZE oldSize; /* previous calculated rebar size */ - BOOL bUnicode; /* TRUE if this window is W type */ - BOOL NtfUnicode; /* TRUE if parent wants notify in W format */ - BOOL DoRedraw; /* TRUE to acutally draw bands */ - UINT fStatus; /* Status flags (see below) */ - HCURSOR hcurArrow; /* handle to the arrow cursor */ - HCURSOR hcurHorz; /* handle to the EW cursor */ - HCURSOR hcurVert; /* handle to the NS cursor */ - HCURSOR hcurDrag; /* handle to the drag cursor */ - INT iVersion; /* version number */ - POINT dragStart; /* x,y of button down */ - POINT dragNow; /* x,y of this MouseMove */ - INT iOldBand; /* last band that had the mouse cursor over it */ - INT ihitoffset; /* offset of hotspot from gripper.left */ - POINT origin; /* left/upper corner of client */ - INT ichevronhotBand; /* last band that had a hot chevron */ - INT iGrabbedBand;/* band number of band whose gripper was grabbed */ - - REBAR_BAND *bands; /* pointer to the array of rebar bands */ -} REBAR_INFO; - -/* fStatus flags */ -#define BEGIN_DRAG_ISSUED 0x00000001 -#define AUTO_RESIZE 0x00000002 -#define RESIZE_ANYHOW 0x00000004 -#define NTF_HGHTCHG 0x00000008 -#define BAND_NEEDS_LAYOUT 0x00000010 -#define BAND_NEEDS_REDRAW 0x00000020 -#define CREATE_RUNNING 0x00000040 - -/* ---- REBAR layout constants. Mostly determined by ---- */ -/* ---- experiment on WIN 98. ---- */ - -/* Width (or height) of separators between bands (either horz. or */ -/* vert.). True only if RBS_BANDBORDERS is set */ -#define SEP_WIDTH_SIZE 2 -#define SEP_WIDTH ((infoPtr->dwStyle & RBS_BANDBORDERS) ? SEP_WIDTH_SIZE : 0) - -/* Blank (background color) space between Gripper (if present) */ -/* and next item (image, text, or window). Always present */ -#define REBAR_ALWAYS_SPACE 4 - -/* Blank (background color) space after Image (if present). */ -#define REBAR_POST_IMAGE 2 - -/* Blank (background color) space after Text (if present). */ -#define REBAR_POST_TEXT 4 - -/* Height of vertical gripper in a CCS_VERT rebar. */ -#define GRIPPER_HEIGHT 16 - -/* Blank (background color) space before Gripper (if present). */ -#define REBAR_PRE_GRIPPER 2 - -/* Width (of normal vertical gripper) or height (of horz. gripper) */ -/* if present. */ -#define GRIPPER_WIDTH 3 - -/* Width of the chevron button if present */ -#define CHEVRON_WIDTH 10 - -/* Height of divider for Rebar if not disabled (CCS_NODIVIDER) */ -/* either top or bottom */ -#define REBAR_DIVIDER 2 - -/* minimium vertical height of a normal bar */ -/* or minimum width of a CCS_VERT bar - from experiment on Win2k */ -#define REBAR_MINSIZE 23 - -/* This is the increment that is used over the band height */ -#define REBARSPACE(a) ((a->fStyle & RBBS_CHILDEDGE) ? 2*REBAR_DIVIDER : 0) - -/* ---- End of REBAR layout constants. ---- */ - -#define RB_GETBANDINFO_OLD (WM_USER+5) /* obsoleted after IE3, but we have to support it anyway */ - -/* The following 6 defines return the proper rcBand element */ -/* depending on whether CCS_VERT was set. */ -#define rcBlt(b) ((infoPtr->dwStyle & CCS_VERT) ? b->rcBand.top : b->rcBand.left) -#define rcBrb(b) ((infoPtr->dwStyle & CCS_VERT) ? b->rcBand.bottom : b->rcBand.right) -#define rcBw(b) ((infoPtr->dwStyle & CCS_VERT) ? (b->rcBand.bottom - b->rcBand.top) : \ - (b->rcBand.right - b->rcBand.left)) -#define ircBlt(b) ((infoPtr->dwStyle & CCS_VERT) ? b->rcBand.left : b->rcBand.top) -#define ircBrb(b) ((infoPtr->dwStyle & CCS_VERT) ? b->rcBand.right : b->rcBand.bottom) -#define ircBw(b) ((infoPtr->dwStyle & CCS_VERT) ? (b->rcBand.right - b->rcBand.left) : \ - (b->rcBand.bottom - b->rcBand.top)) - -/* The following define determines if a given band is hidden */ -#define HIDDENBAND(a) (((a)->fStyle & RBBS_HIDDEN) || \ - ((infoPtr->dwStyle & CCS_VERT) && \ - ((a)->fStyle & RBBS_NOVERT))) - -/* The following defines adjust the right or left end of a rectangle */ -#define READJ(b,i) do { if(infoPtr->dwStyle & CCS_VERT) b->rcBand.bottom+=(i); \ - else b->rcBand.right += (i); } while(0) -#define LEADJ(b,i) do { if(infoPtr->dwStyle & CCS_VERT) b->rcBand.top+=(i); \ - else b->rcBand.left += (i); } while(0) - - -#define REBAR_GetInfoPtr(wndPtr) ((REBAR_INFO *)GetWindowLongPtrW (hwnd, 0)) - - -/* "constant values" retrieved when DLL was initialized */ -/* FIXME we do this when the classes are registered. */ -static UINT mindragx = 0; -static UINT mindragy = 0; - -static const char *band_stylename[] = { - "RBBS_BREAK", /* 0001 */ - "RBBS_FIXEDSIZE", /* 0002 */ - "RBBS_CHILDEDGE", /* 0004 */ - "RBBS_HIDDEN", /* 0008 */ - "RBBS_NOVERT", /* 0010 */ - "RBBS_FIXEDBMP", /* 0020 */ - "RBBS_VARIABLEHEIGHT", /* 0040 */ - "RBBS_GRIPPERALWAYS", /* 0080 */ - "RBBS_NOGRIPPER", /* 0100 */ - NULL }; - -static const char *band_maskname[] = { - "RBBIM_STYLE", /* 0x00000001 */ - "RBBIM_COLORS", /* 0x00000002 */ - "RBBIM_TEXT", /* 0x00000004 */ - "RBBIM_IMAGE", /* 0x00000008 */ - "RBBIM_CHILD", /* 0x00000010 */ - "RBBIM_CHILDSIZE", /* 0x00000020 */ - "RBBIM_SIZE", /* 0x00000040 */ - "RBBIM_BACKGROUND", /* 0x00000080 */ - "RBBIM_ID", /* 0x00000100 */ - "RBBIM_IDEALSIZE", /* 0x00000200 */ - "RBBIM_LPARAM", /* 0x00000400 */ - "RBBIM_HEADERSIZE", /* 0x00000800 */ - NULL }; - - -static CHAR line[200]; - - -static CHAR * -REBAR_FmtStyle( UINT style) -{ - INT i = 0; - - *line = 0; - while (band_stylename[i]) { - if (style & (1<fMask & RBBIM_ID); - TRACE("ID=%u, ", pB->wID); - TRACE("size=%u, child=%p", pB->cbSize, pB->hwndChild); - if (pB->fMask & RBBIM_COLORS) - TRACE(", clrF=0x%06lx, clrB=0x%06lx", pB->clrFore, pB->clrBack); - TRACE("\n"); - - TRACE("band info: mask=0x%08x (%s)\n", pB->fMask, REBAR_FmtMask(pB->fMask)); - if (pB->fMask & RBBIM_STYLE) - TRACE("band info: style=0x%08x (%s)\n", pB->fStyle, REBAR_FmtStyle(pB->fStyle)); - if (pB->fMask & (RBBIM_SIZE | RBBIM_IDEALSIZE | RBBIM_HEADERSIZE | RBBIM_LPARAM )) { - TRACE("band info:"); - if (pB->fMask & RBBIM_SIZE) - TRACE(" cx=%u", pB->cx); - if (pB->fMask & RBBIM_IDEALSIZE) - TRACE(" xIdeal=%u", pB->cxIdeal); - if (pB->fMask & RBBIM_HEADERSIZE) - TRACE(" xHeader=%u", pB->cxHeader); - if (pB->fMask & RBBIM_LPARAM) - TRACE(" lParam=0x%08lx", pB->lParam); - TRACE("\n"); - } - if (pB->fMask & RBBIM_CHILDSIZE) - TRACE("band info: xMin=%u, yMin=%u, yChild=%u, yMax=%u, yIntgl=%u\n", - pB->cxMinChild, - pB->cyMinChild, pB->cyChild, pB->cyMaxChild, pB->cyIntegral); -} - -static VOID -REBAR_DumpBand (REBAR_INFO *iP) -{ - REBAR_BAND *pB; - UINT i; - - if(! TRACE_ON(rebar) ) return; - - TRACE("hwnd=%p: color=%08lx/%08lx, bands=%u, rows=%u, cSize=%ld,%ld\n", - iP->hwndSelf, iP->clrText, iP->clrBk, iP->uNumBands, iP->uNumRows, - iP->calcSize.cx, iP->calcSize.cy); - TRACE("hwnd=%p: flags=%08x, dragStart=%ld,%ld, dragNow=%ld,%ld, iGrabbedBand=%d\n", - iP->hwndSelf, iP->fStatus, iP->dragStart.x, iP->dragStart.y, - iP->dragNow.x, iP->dragNow.y, - iP->iGrabbedBand); - TRACE("hwnd=%p: style=%08lx, I'm Unicode=%s, notify in Unicode=%s, redraw=%s\n", - iP->hwndSelf, iP->dwStyle, (iP->bUnicode)?"TRUE":"FALSE", - (iP->NtfUnicode)?"TRUE":"FALSE", (iP->DoRedraw)?"TRUE":"FALSE"); - for (i = 0; i < iP->uNumBands; i++) { - pB = &iP->bands[i]; - TRACE("band # %u:", i); - if (pB->fMask & RBBIM_ID); - TRACE(" ID=%u", pB->wID); - if (pB->fMask & RBBIM_CHILD) - TRACE(" child=%p", pB->hwndChild); - if (pB->fMask & RBBIM_COLORS) - TRACE(" clrF=0x%06lx clrB=0x%06lx", pB->clrFore, pB->clrBack); - TRACE("\n"); - TRACE("band # %u: mask=0x%08x (%s)\n", i, pB->fMask, REBAR_FmtMask(pB->fMask)); - if (pB->fMask & RBBIM_STYLE) - TRACE("band # %u: style=0x%08x (%s)\n", - i, pB->fStyle, REBAR_FmtStyle(pB->fStyle)); - TRACE("band # %u: uMinH=%u xHeader=%u", - i, pB->uMinHeight, pB->cxHeader); - if (pB->fMask & (RBBIM_SIZE | RBBIM_IDEALSIZE | RBBIM_LPARAM )) { - if (pB->fMask & RBBIM_SIZE) - TRACE(" cx=%u", pB->cx); - if (pB->fMask & RBBIM_IDEALSIZE) - TRACE(" xIdeal=%u", pB->cxIdeal); - if (pB->fMask & RBBIM_LPARAM) - TRACE(" lParam=0x%08lx", pB->lParam); - } - TRACE("\n"); - if (RBBIM_CHILDSIZE) - TRACE("band # %u: xMin=%u, yMin=%u, yChild=%u, yMax=%u, yIntgl=%u\n", - i, pB->cxMinChild, pB->cyMinChild, pB->cyChild, pB->cyMaxChild, pB->cyIntegral); - if (pB->fMask & RBBIM_TEXT) - TRACE("band # %u: text=%s\n", - i, (pB->lpText) ? debugstr_w(pB->lpText) : "(null)"); - TRACE("band # %u: lcx=%u, ccx=%u, hcx=%u, lcy=%u, ccy=%u, hcy=%u, offChild=%ld,%ld\n", - i, pB->lcx, pB->ccx, pB->hcx, pB->lcy, pB->ccy, pB->hcy, pB->offChild.cx, pB->offChild.cy); - TRACE("band # %u: fStatus=%08x, fDraw=%08x, Band=(%ld,%ld)-(%ld,%ld), Grip=(%ld,%ld)-(%ld,%ld)\n", - i, pB->fStatus, pB->fDraw, - pB->rcBand.left, pB->rcBand.top, pB->rcBand.right, pB->rcBand.bottom, - pB->rcGripper.left, pB->rcGripper.top, pB->rcGripper.right, pB->rcGripper.bottom); - TRACE("band # %u: Img=(%ld,%ld)-(%ld,%ld), Txt=(%ld,%ld)-(%ld,%ld), Child=(%ld,%ld)-(%ld,%ld)\n", - i, - pB->rcCapImage.left, pB->rcCapImage.top, pB->rcCapImage.right, pB->rcCapImage.bottom, - pB->rcCapText.left, pB->rcCapText.top, pB->rcCapText.right, pB->rcCapText.bottom, - pB->rcChild.left, pB->rcChild.top, pB->rcChild.right, pB->rcChild.bottom); - } - -} - -static void -REBAR_DrawChevron (HDC hdc, INT left, INT top, INT colorRef) -{ - INT x, y; - HPEN hPen, hOldPen; - - if (!(hPen = CreatePen( PS_SOLID, 1, GetSysColor( colorRef )))) return; - hOldPen = SelectObject ( hdc, hPen ); - x = left + 2; - y = top; - MoveToEx (hdc, x, y, NULL); - LineTo (hdc, x+5, y++); x++; - MoveToEx (hdc, x, y, NULL); - LineTo (hdc, x+3, y++); x++; - MoveToEx (hdc, x, y, NULL); - LineTo (hdc, x+1, y++); - SelectObject( hdc, hOldPen ); - DeleteObject( hPen ); -} - -static HWND -REBAR_GetNotifyParent (REBAR_INFO *infoPtr) -{ - HWND parent, owner; - - parent = infoPtr->hwndNotify; - if (!parent) { - parent = GetParent (infoPtr->hwndSelf); - owner = GetWindow (infoPtr->hwndSelf, GW_OWNER); - if (owner) parent = owner; - } - return parent; -} - - -static INT -REBAR_Notify (NMHDR *nmhdr, REBAR_INFO *infoPtr, UINT code) -{ - HWND parent; - - parent = REBAR_GetNotifyParent (infoPtr); - nmhdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf); - nmhdr->hwndFrom = infoPtr->hwndSelf; - nmhdr->code = code; - - TRACE("window %p, code=%08x, %s\n", parent, code, - (infoPtr->NtfUnicode) ? "via Unicode" : "via ANSI"); - - if (infoPtr->NtfUnicode) - return SendMessageW (parent, WM_NOTIFY, (WPARAM) nmhdr->idFrom, - (LPARAM)nmhdr); - else - return SendMessageA (parent, WM_NOTIFY, (WPARAM) nmhdr->idFrom, - (LPARAM)nmhdr); -} - -static INT -REBAR_Notify_NMREBAR (REBAR_INFO *infoPtr, UINT uBand, UINT code) -{ - NMREBAR notify_rebar; - REBAR_BAND *lpBand; - - notify_rebar.dwMask = 0; - if (uBand!=-1) { - lpBand = &infoPtr->bands[uBand]; - if (lpBand->fMask & RBBIM_ID) { - notify_rebar.dwMask |= RBNM_ID; - notify_rebar.wID = lpBand->wID; - } - if (lpBand->fMask & RBBIM_LPARAM) { - notify_rebar.dwMask |= RBNM_LPARAM; - notify_rebar.lParam = lpBand->lParam; - } - if (lpBand->fMask & RBBIM_STYLE) { - notify_rebar.dwMask |= RBNM_STYLE; - notify_rebar.fStyle = lpBand->fStyle; - } - } - notify_rebar.uBand = uBand; - return REBAR_Notify ((NMHDR *)¬ify_rebar, infoPtr, code); -} - -static VOID -REBAR_DrawBand (HDC hdc, REBAR_INFO *infoPtr, REBAR_BAND *lpBand) -{ - HFONT hOldFont = 0; - INT oldBkMode = 0; - NMCUSTOMDRAW nmcd; - - if (lpBand->fDraw & DRAW_TEXT) { - hOldFont = SelectObject (hdc, infoPtr->hFont); - oldBkMode = SetBkMode (hdc, TRANSPARENT); - } - - /* should test for CDRF_NOTIFYITEMDRAW here */ - nmcd.dwDrawStage = CDDS_ITEMPREPAINT; - nmcd.hdc = hdc; - nmcd.rc = lpBand->rcBand; - nmcd.rc.right = lpBand->rcCapText.right; - nmcd.rc.bottom = lpBand->rcCapText.bottom; - nmcd.dwItemSpec = lpBand->wID; - nmcd.uItemState = 0; - nmcd.lItemlParam = lpBand->lParam; - lpBand->uCDret = REBAR_Notify ((NMHDR *)&nmcd, infoPtr, NM_CUSTOMDRAW); - if (lpBand->uCDret == CDRF_SKIPDEFAULT) { - if (oldBkMode != TRANSPARENT) - SetBkMode (hdc, oldBkMode); - SelectObject (hdc, hOldFont); - return; - } - - /* draw gripper */ - if (lpBand->fDraw & DRAW_GRIPPER) - DrawEdge (hdc, &lpBand->rcGripper, BDR_RAISEDINNER, BF_RECT | BF_MIDDLE); - - /* draw caption image */ - if (lpBand->fDraw & DRAW_IMAGE) { - POINT pt; - - /* center image */ - pt.y = (lpBand->rcCapImage.bottom + lpBand->rcCapImage.top - infoPtr->imageSize.cy)/2; - pt.x = (lpBand->rcCapImage.right + lpBand->rcCapImage.left - infoPtr->imageSize.cx)/2; - - ImageList_Draw (infoPtr->himl, lpBand->iImage, hdc, - pt.x, pt.y, - ILD_TRANSPARENT); - } - - /* draw caption text */ - if (lpBand->fDraw & DRAW_TEXT) { - /* need to handle CDRF_NEWFONT here */ - INT oldBkMode = SetBkMode (hdc, TRANSPARENT); - COLORREF oldcolor = CLR_NONE; - COLORREF new; - if (lpBand->clrFore != CLR_NONE) { - new = (lpBand->clrFore == CLR_DEFAULT) ? infoPtr->clrBtnText : - lpBand->clrFore; - oldcolor = SetTextColor (hdc, new); - } - DrawTextW (hdc, lpBand->lpText, -1, &lpBand->rcCapText, - DT_CENTER | DT_VCENTER | DT_SINGLELINE); - if (oldBkMode != TRANSPARENT) - SetBkMode (hdc, oldBkMode); - if (lpBand->clrFore != CLR_NONE) - SetTextColor (hdc, oldcolor); - SelectObject (hdc, hOldFont); - } - - if (!IsRectEmpty(&lpBand->rcChevron)) - { - if (lpBand->fDraw & DRAW_CHEVRONPUSHED) - { - DrawEdge(hdc, &lpBand->rcChevron, BDR_SUNKENOUTER, BF_RECT | BF_MIDDLE); - REBAR_DrawChevron(hdc, lpBand->rcChevron.left+1, lpBand->rcChevron.top + 11, COLOR_WINDOWFRAME); - } - else if (lpBand->fDraw & DRAW_CHEVRONHOT) - { - DrawEdge(hdc, &lpBand->rcChevron, BDR_RAISEDINNER, BF_RECT | BF_MIDDLE); - REBAR_DrawChevron(hdc, lpBand->rcChevron.left, lpBand->rcChevron.top + 10, COLOR_WINDOWFRAME); - } - else - REBAR_DrawChevron(hdc, lpBand->rcChevron.left, lpBand->rcChevron.top + 10, COLOR_WINDOWFRAME); - } - - if (lpBand->uCDret == (CDRF_NOTIFYPOSTPAINT | CDRF_NOTIFYITEMDRAW)) { - nmcd.dwDrawStage = CDDS_ITEMPOSTPAINT; - nmcd.hdc = hdc; - nmcd.rc = lpBand->rcBand; - nmcd.rc.right = lpBand->rcCapText.right; - nmcd.rc.bottom = lpBand->rcCapText.bottom; - nmcd.dwItemSpec = lpBand->wID; - nmcd.uItemState = 0; - nmcd.lItemlParam = lpBand->lParam; - lpBand->uCDret = REBAR_Notify ((NMHDR *)&nmcd, infoPtr, NM_CUSTOMDRAW); - } -} - - -static VOID -REBAR_Refresh (REBAR_INFO *infoPtr, HDC hdc) -{ - REBAR_BAND *lpBand; - UINT i; - - if (!infoPtr->DoRedraw) return; - - for (i = 0; i < infoPtr->uNumBands; i++) { - lpBand = &infoPtr->bands[i]; - - if (HIDDENBAND(lpBand)) continue; - - /* now draw the band */ - TRACE("[%p] drawing band %i, flags=%08x\n", - infoPtr->hwndSelf, i, lpBand->fDraw); - REBAR_DrawBand (hdc, infoPtr, lpBand); - - } -} - - -static void -REBAR_FixVert (REBAR_INFO *infoPtr, UINT rowstart, UINT rowend, - INT mcy) - /* Function: */ - /* Cycle through bands in row and fix height of each band. */ - /* Also determine whether each band has changed. */ - /* On entry: */ - /* all bands at desired size. */ - /* start and end bands are *not* hidden */ -{ - REBAR_BAND *lpBand; - INT i; - - for (i = (INT)rowstart; i<=(INT)rowend; i++) { - lpBand = &infoPtr->bands[i]; - if (HIDDENBAND(lpBand)) continue; - - /* adjust height of bands in row to "mcy" value */ - if (infoPtr->dwStyle & CCS_VERT) { - if (lpBand->rcBand.right != lpBand->rcBand.left + mcy) - lpBand->rcBand.right = lpBand->rcBand.left + mcy; - } - else { - if (lpBand->rcBand.bottom != lpBand->rcBand.top + mcy) - lpBand->rcBand.bottom = lpBand->rcBand.top + mcy; - - } - - /* mark whether we need to invalidate this band and trace */ - if ((lpBand->rcoldBand.left !=lpBand->rcBand.left) || - (lpBand->rcoldBand.top !=lpBand->rcBand.top) || - (lpBand->rcoldBand.right !=lpBand->rcBand.right) || - (lpBand->rcoldBand.bottom !=lpBand->rcBand.bottom)) { - lpBand->fDraw |= NTF_INVALIDATE; - TRACE("band %d row=%d: changed to (%ld,%ld)-(%ld,%ld) from (%ld,%ld)-(%ld,%ld)\n", - i, lpBand->iRow, - lpBand->rcBand.left, lpBand->rcBand.top, - lpBand->rcBand.right, lpBand->rcBand.bottom, - lpBand->rcoldBand.left, lpBand->rcoldBand.top, - lpBand->rcoldBand.right, lpBand->rcoldBand.bottom); - } - else - TRACE("band %d row=%d: unchanged (%ld,%ld)-(%ld,%ld)\n", - i, lpBand->iRow, - lpBand->rcBand.left, lpBand->rcBand.top, - lpBand->rcBand.right, lpBand->rcBand.bottom); - } -} - - -static void -REBAR_AdjustBands (REBAR_INFO *infoPtr, UINT rowstart, UINT rowend, - INT maxx, INT mcy) - /* Function: This routine distributes the extra space in a row. */ - /* See algorithm below. */ - /* On entry: */ - /* all bands @ ->cxHeader size */ - /* start and end bands are *not* hidden */ -{ - REBAR_BAND *lpBand; - UINT xsep, extra, curwidth, fudge; - INT x, i, last_adjusted; - - TRACE("start=%u, end=%u, max x=%d, max y=%d\n", - rowstart, rowend, maxx, mcy); - - /* ******************* Phase 1 ************************ */ - /* Alg: */ - /* For each visible band with valid child */ - /* a. inflate band till either all extra space used */ - /* or band's ->ccx reached. */ - /* If any band modified, add any space left to last band */ - /* adjusted. */ - /* */ - /* ****************************************************** */ - lpBand = &infoPtr->bands[rowend]; - extra = maxx - rcBrb(lpBand); - x = 0; - last_adjusted = -1; - for (i=(INT)rowstart; i<=(INT)rowend; i++) { - lpBand = &infoPtr->bands[i]; - if (HIDDENBAND(lpBand)) continue; - xsep = (x == 0) ? 0 : SEP_WIDTH; - curwidth = rcBw(lpBand); - - /* set new left/top point */ - if (infoPtr->dwStyle & CCS_VERT) - lpBand->rcBand.top = x + xsep; - else - lpBand->rcBand.left = x + xsep; - - /* compute new width */ - if ((lpBand->hwndChild && extra) && !(lpBand->fStyle & RBBS_FIXEDSIZE)) { - /* set to the "current" band size less the header */ - fudge = lpBand->ccx; - last_adjusted = i; - if ((lpBand->fMask & RBBIM_SIZE) && (lpBand->cx > 0) && - (fudge > curwidth)) { - TRACE("adjusting band %d by %d, fudge=%d, curwidth=%d, extra=%d\n", - i, fudge-curwidth, fudge, curwidth, extra); - if ((fudge - curwidth) > extra) - fudge = curwidth + extra; - extra -= (fudge - curwidth); - curwidth = fudge; - } - else { - TRACE("adjusting band %d by %d, fudge=%d, curwidth=%d\n", - i, extra, fudge, curwidth); - curwidth += extra; - extra = 0; - } - } - - /* set new right/bottom point */ - if (infoPtr->dwStyle & CCS_VERT) - lpBand->rcBand.bottom = lpBand->rcBand.top + curwidth; - else - lpBand->rcBand.right = lpBand->rcBand.left + curwidth; - TRACE("Phase 1 band %d, (%ld,%ld)-(%ld,%ld), orig x=%d, xsep=%d\n", - i, lpBand->rcBand.left, lpBand->rcBand.top, - lpBand->rcBand.right, lpBand->rcBand.bottom, x, xsep); - x = rcBrb(lpBand); - } - if ((x >= maxx) || (last_adjusted != -1)) { - if (x > maxx) { - ERR("Phase 1 failed, x=%d, maxx=%d, start=%u, end=%u\n", - x, maxx, rowstart, rowend); - } - /* done, so spread extra space */ - if (x < maxx) { - fudge = maxx - x; - TRACE("Need to spread %d on last adjusted band %d\n", - fudge, last_adjusted); - for (i=(INT)last_adjusted; i<=(INT)rowend; i++) { - lpBand = &infoPtr->bands[i]; - if (HIDDENBAND(lpBand)) continue; - - /* set right/bottom point */ - if (i != last_adjusted) { - if (infoPtr->dwStyle & CCS_VERT) - lpBand->rcBand.top += fudge; - else - lpBand->rcBand.left += fudge; - } - - /* set left/bottom point */ - if (infoPtr->dwStyle & CCS_VERT) - lpBand->rcBand.bottom += fudge; - else - lpBand->rcBand.right += fudge; - } - } - TRACE("Phase 1 succeeded, used x=%d\n", x); - REBAR_FixVert (infoPtr, rowstart, rowend, mcy); - return; - } - - /* ******************* Phase 2 ************************ */ - /* Alg: */ - /* Find first visible band, put all */ - /* extra space there. */ - /* */ - /* ****************************************************** */ - - x = 0; - for (i=(INT)rowstart; i<=(INT)rowend; i++) { - lpBand = &infoPtr->bands[i]; - if (HIDDENBAND(lpBand)) continue; - xsep = (x == 0) ? 0 : SEP_WIDTH; - curwidth = rcBw(lpBand); - - /* set new left/top point */ - if (infoPtr->dwStyle & CCS_VERT) - lpBand->rcBand.top = x + xsep; - else - lpBand->rcBand.left = x + xsep; - - /* compute new width */ - if (extra) { - curwidth += extra; - extra = 0; - } - - /* set new right/bottom point */ - if (infoPtr->dwStyle & CCS_VERT) - lpBand->rcBand.bottom = lpBand->rcBand.top + curwidth; - else - lpBand->rcBand.right = lpBand->rcBand.left + curwidth; - TRACE("Phase 2 band %d, (%ld,%ld)-(%ld,%ld), orig x=%d, xsep=%d\n", - i, lpBand->rcBand.left, lpBand->rcBand.top, - lpBand->rcBand.right, lpBand->rcBand.bottom, x, xsep); - x = rcBrb(lpBand); - } - if (x >= maxx) { - if (x > maxx) { - ERR("Phase 2 failed, x=%d, maxx=%d, start=%u, end=%u\n", - x, maxx, rowstart, rowend); - } - /* done, so spread extra space */ - TRACE("Phase 2 succeeded, used x=%d\n", x); - REBAR_FixVert (infoPtr, rowstart, rowend, mcy); - return; - } - - /* ******************* Phase 3 ************************ */ - /* at this point everything is back to ->cxHeader values */ - /* and should not have gotten here. */ - /* ****************************************************** */ - - lpBand = &infoPtr->bands[rowstart]; - ERR("Serious problem adjusting row %d, start band %d, end band %d\n", - lpBand->iRow, rowstart, rowend); - REBAR_DumpBand (infoPtr); - return; -} - - -static void -REBAR_CalcHorzBand (REBAR_INFO *infoPtr, UINT rstart, UINT rend, BOOL notify) - /* Function: this routine initializes all the rectangles in */ - /* each band in a row to fit in the adjusted rcBand rect. */ - /* *** Supports only Horizontal bars. *** */ -{ - REBAR_BAND *lpBand; - UINT i, xoff, yoff; - HWND parenthwnd; - RECT oldChild, work; - - /* MS seems to use GetDlgCtrlID() for above GetWindowLong call */ - parenthwnd = GetParent (infoPtr->hwndSelf); - - for(i=rstart; ibands[i]; - if (HIDDENBAND(lpBand)) { - SetRect (&lpBand->rcChild, - lpBand->rcBand.right, lpBand->rcBand.top, - lpBand->rcBand.right, lpBand->rcBand.bottom); - continue; - } - - oldChild = lpBand->rcChild; - - /* set initial gripper rectangle */ - SetRect (&lpBand->rcGripper, lpBand->rcBand.left, lpBand->rcBand.top, - lpBand->rcBand.left, lpBand->rcBand.bottom); - - /* calculate gripper rectangle */ - if ( lpBand->fStatus & HAS_GRIPPER) { - lpBand->fDraw |= DRAW_GRIPPER; - lpBand->rcGripper.left += REBAR_PRE_GRIPPER; - lpBand->rcGripper.right = lpBand->rcGripper.left + GRIPPER_WIDTH; - lpBand->rcGripper.top += 2; - lpBand->rcGripper.bottom -= 2; - - SetRect (&lpBand->rcCapImage, - lpBand->rcGripper.right+REBAR_ALWAYS_SPACE, lpBand->rcBand.top, - lpBand->rcGripper.right+REBAR_ALWAYS_SPACE, lpBand->rcBand.bottom); - } - else { /* no gripper will be drawn */ - xoff = 0; - if (lpBand->fStatus & (HAS_IMAGE | HAS_TEXT)) - /* if no gripper but either image or text, then leave space */ - xoff = REBAR_ALWAYS_SPACE; - SetRect (&lpBand->rcCapImage, - lpBand->rcBand.left+xoff, lpBand->rcBand.top, - lpBand->rcBand.left+xoff, lpBand->rcBand.bottom); - } - - /* image is visible */ - if (lpBand->fStatus & HAS_IMAGE) { - lpBand->fDraw |= DRAW_IMAGE; - lpBand->rcCapImage.right += infoPtr->imageSize.cx; - lpBand->rcCapImage.bottom = lpBand->rcCapImage.top + infoPtr->imageSize.cy; - - /* set initial caption text rectangle */ - SetRect (&lpBand->rcCapText, - lpBand->rcCapImage.right+REBAR_POST_IMAGE, lpBand->rcBand.top+1, - lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.bottom-1); - /* update band height - if (lpBand->uMinHeight < infoPtr->imageSize.cy + 2) { - lpBand->uMinHeight = infoPtr->imageSize.cy + 2; - lpBand->rcBand.bottom = lpBand->rcBand.top + lpBand->uMinHeight; - } */ - } - else { - /* set initial caption text rectangle */ - SetRect (&lpBand->rcCapText, lpBand->rcCapImage.right, lpBand->rcBand.top+1, - lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.bottom-1); - } - - /* text is visible */ - if ((lpBand->fStatus & HAS_TEXT) && !(lpBand->fStyle & RBBS_HIDETITLE)) { - lpBand->fDraw |= DRAW_TEXT; - lpBand->rcCapText.right = max(lpBand->rcCapText.left, - lpBand->rcCapText.right-REBAR_POST_TEXT); - } - - /* set initial child window rectangle if there is a child */ - if (lpBand->fMask & RBBIM_CHILD) { - xoff = lpBand->offChild.cx; - yoff = lpBand->offChild.cy; - SetRect (&lpBand->rcChild, - lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.top+yoff, - lpBand->rcBand.right-xoff, lpBand->rcBand.bottom-yoff); - if ((lpBand->fStyle & RBBS_USECHEVRON) && (lpBand->rcChild.right - lpBand->rcChild.left < lpBand->cxIdeal)) - { - lpBand->rcChild.right -= CHEVRON_WIDTH; - SetRect(&lpBand->rcChevron, lpBand->rcChild.right, - lpBand->rcChild.top, lpBand->rcChild.right + CHEVRON_WIDTH, - lpBand->rcChild.bottom); - } - } - else { - SetRect (&lpBand->rcChild, - lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.top, - lpBand->rcBand.right, lpBand->rcBand.bottom); - } - - /* flag if notify required and invalidate rectangle */ - if (notify && - ((oldChild.right-oldChild.left != lpBand->rcChild.right-lpBand->rcChild.left) || - (oldChild.bottom-oldChild.top != lpBand->rcChild.bottom-lpBand->rcChild.top))) { - TRACE("Child rectangle changed for band %u\n", i); - TRACE(" from (%ld,%ld)-(%ld,%ld) to (%ld,%ld)-(%ld,%ld)\n", - oldChild.left, oldChild.top, - oldChild.right, oldChild.bottom, - lpBand->rcChild.left, lpBand->rcChild.top, - lpBand->rcChild.right, lpBand->rcChild.bottom); - } - if (lpBand->fDraw & NTF_INVALIDATE) { - TRACE("invalidating (%ld,%ld)-(%ld,%ld)\n", - lpBand->rcBand.left, - lpBand->rcBand.top, - lpBand->rcBand.right + ((lpBand->fDraw & DRAW_RIGHTSEP) ? SEP_WIDTH_SIZE : 0), - lpBand->rcBand.bottom + ((lpBand->fDraw & DRAW_BOTTOMSEP) ? SEP_WIDTH_SIZE : 0)); - lpBand->fDraw &= ~NTF_INVALIDATE; - work = lpBand->rcBand; - if (lpBand->fDraw & DRAW_RIGHTSEP) work.right += SEP_WIDTH_SIZE; - if (lpBand->fDraw & DRAW_BOTTOMSEP) work.bottom += SEP_WIDTH_SIZE; - InvalidateRect(infoPtr->hwndSelf, &work, TRUE); - } - - } - -} - - -static VOID -REBAR_CalcVertBand (REBAR_INFO *infoPtr, UINT rstart, UINT rend, BOOL notify) - /* Function: this routine initializes all the rectangles in */ - /* each band in a row to fit in the adjusted rcBand rect. */ - /* *** Supports only Vertical bars. *** */ -{ - REBAR_BAND *lpBand; - UINT i, xoff, yoff; - HWND parenthwnd; - RECT oldChild, work; - - /* MS seems to use GetDlgCtrlID() for above GetWindowLong call */ - parenthwnd = GetParent (infoPtr->hwndSelf); - - for(i=rstart; ibands[i]; - if (HIDDENBAND(lpBand)) continue; - oldChild = lpBand->rcChild; - - /* set initial gripper rectangle */ - SetRect (&lpBand->rcGripper, lpBand->rcBand.left, lpBand->rcBand.top, - lpBand->rcBand.right, lpBand->rcBand.top); - - /* calculate gripper rectangle */ - if (lpBand->fStatus & HAS_GRIPPER) { - lpBand->fDraw |= DRAW_GRIPPER; - - if (infoPtr->dwStyle & RBS_VERTICALGRIPPER) { - /* vertical gripper */ - lpBand->rcGripper.left += 3; - lpBand->rcGripper.right = lpBand->rcGripper.left + GRIPPER_WIDTH; - lpBand->rcGripper.top += REBAR_PRE_GRIPPER; - lpBand->rcGripper.bottom = lpBand->rcGripper.top + GRIPPER_HEIGHT; - - /* initialize Caption image rectangle */ - SetRect (&lpBand->rcCapImage, lpBand->rcBand.left, - lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE, - lpBand->rcBand.right, - lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE); - } - else { - /* horizontal gripper */ - lpBand->rcGripper.left += 2; - lpBand->rcGripper.right -= 2; - lpBand->rcGripper.top += REBAR_PRE_GRIPPER; - lpBand->rcGripper.bottom = lpBand->rcGripper.top + GRIPPER_WIDTH; - - /* initialize Caption image rectangle */ - SetRect (&lpBand->rcCapImage, lpBand->rcBand.left, - lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE, - lpBand->rcBand.right, - lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE); - } - } - else { /* no gripper will be drawn */ - xoff = 0; - if (lpBand->fStatus & (HAS_IMAGE | HAS_TEXT)) - /* if no gripper but either image or text, then leave space */ - xoff = REBAR_ALWAYS_SPACE; - /* initialize Caption image rectangle */ - SetRect (&lpBand->rcCapImage, - lpBand->rcBand.left, lpBand->rcBand.top+xoff, - lpBand->rcBand.right, lpBand->rcBand.top+xoff); - } - - /* image is visible */ - if (lpBand->fStatus & HAS_IMAGE) { - lpBand->fDraw |= DRAW_IMAGE; - - lpBand->rcCapImage.right = lpBand->rcCapImage.left + infoPtr->imageSize.cx; - lpBand->rcCapImage.bottom += infoPtr->imageSize.cy; - - /* set initial caption text rectangle */ - SetRect (&lpBand->rcCapText, - lpBand->rcBand.left, lpBand->rcCapImage.bottom+REBAR_POST_IMAGE, - lpBand->rcBand.right, lpBand->rcBand.top+lpBand->cxHeader); - /* update band height * - if (lpBand->uMinHeight < infoPtr->imageSize.cx + 2) { - lpBand->uMinHeight = infoPtr->imageSize.cx + 2; - lpBand->rcBand.right = lpBand->rcBand.left + lpBand->uMinHeight; - } */ - } - else { - /* set initial caption text rectangle */ - SetRect (&lpBand->rcCapText, - lpBand->rcBand.left, lpBand->rcCapImage.bottom, - lpBand->rcBand.right, lpBand->rcBand.top+lpBand->cxHeader); - } - - /* text is visible */ - if ((lpBand->fStatus & HAS_TEXT) && !(lpBand->fStyle & RBBS_HIDETITLE)) { - lpBand->fDraw |= DRAW_TEXT; - lpBand->rcCapText.bottom = max(lpBand->rcCapText.top, - lpBand->rcCapText.bottom); - } - - /* set initial child window rectangle if there is a child */ - if (lpBand->fMask & RBBIM_CHILD) { - yoff = lpBand->offChild.cx; - xoff = lpBand->offChild.cy; - SetRect (&lpBand->rcChild, - lpBand->rcBand.left+xoff, lpBand->rcBand.top+lpBand->cxHeader, - lpBand->rcBand.right-xoff, lpBand->rcBand.bottom-yoff); - } - else { - SetRect (&lpBand->rcChild, - lpBand->rcBand.left, lpBand->rcBand.top+lpBand->cxHeader, - lpBand->rcBand.right, lpBand->rcBand.bottom); - } - - /* flag if notify required and invalidate rectangle */ - if (notify && - ((oldChild.right-oldChild.left != lpBand->rcChild.right-lpBand->rcChild.left) || - (oldChild.bottom-oldChild.top != lpBand->rcChild.bottom-lpBand->rcChild.top))) { - TRACE("Child rectangle changed for band %u\n", i); - TRACE(" from (%ld,%ld)-(%ld,%ld) to (%ld,%ld)-(%ld,%ld)\n", - oldChild.left, oldChild.top, - oldChild.right, oldChild.bottom, - lpBand->rcChild.left, lpBand->rcChild.top, - lpBand->rcChild.right, lpBand->rcChild.bottom); - } - if (lpBand->fDraw & NTF_INVALIDATE) { - TRACE("invalidating (%ld,%ld)-(%ld,%ld)\n", - lpBand->rcBand.left, - lpBand->rcBand.top, - lpBand->rcBand.right + ((lpBand->fDraw & DRAW_BOTTOMSEP) ? SEP_WIDTH_SIZE : 0), - lpBand->rcBand.bottom + ((lpBand->fDraw & DRAW_RIGHTSEP) ? SEP_WIDTH_SIZE : 0)); - lpBand->fDraw &= ~NTF_INVALIDATE; - work = lpBand->rcBand; - if (lpBand->fDraw & DRAW_RIGHTSEP) work.bottom += SEP_WIDTH_SIZE; - if (lpBand->fDraw & DRAW_BOTTOMSEP) work.right += SEP_WIDTH_SIZE; - InvalidateRect(infoPtr->hwndSelf, &work, TRUE); - } - - } -} - - -static VOID -REBAR_ForceResize (REBAR_INFO *infoPtr) - /* Function: This changes the size of the REBAR window to that */ - /* calculated by REBAR_Layout. */ -{ - RECT rc; - INT x, y, width, height; - INT xedge = GetSystemMetrics(SM_CXEDGE); - INT yedge = GetSystemMetrics(SM_CYEDGE); - - GetClientRect (infoPtr->hwndSelf, &rc); - - TRACE( " old [%ld x %ld], new [%ld x %ld], client [%ld x %ld]\n", - infoPtr->oldSize.cx, infoPtr->oldSize.cy, - infoPtr->calcSize.cx, infoPtr->calcSize.cy, - rc.right, rc.bottom); - - /* If we need to shrink client, then skip size test */ - if ((infoPtr->calcSize.cy >= rc.bottom) && - (infoPtr->calcSize.cx >= rc.right)) { - - /* if size did not change then skip process */ - if ((infoPtr->oldSize.cx == infoPtr->calcSize.cx) && - (infoPtr->oldSize.cy == infoPtr->calcSize.cy) && - !(infoPtr->fStatus & RESIZE_ANYHOW)) - { - TRACE("skipping reset\n"); - return; - } - } - - infoPtr->fStatus &= ~RESIZE_ANYHOW; - /* Set flag to ignore next WM_SIZE message */ - infoPtr->fStatus |= AUTO_RESIZE; - - width = 0; - height = 0; - x = 0; - y = 0; - - if (infoPtr->dwStyle & WS_BORDER) { - width = 2 * xedge; - height = 2 * yedge; - } - - if (!(infoPtr->dwStyle & CCS_NOPARENTALIGN)) { - INT mode = infoPtr->dwStyle & (CCS_VERT | CCS_TOP | CCS_BOTTOM); - RECT rcPcl; - - GetClientRect(GetParent(infoPtr->hwndSelf), &rcPcl); - switch (mode) { - case CCS_TOP: - /* _TOP sets width to parents width */ - width += (rcPcl.right - rcPcl.left); - height += infoPtr->calcSize.cy; - x += ((infoPtr->dwStyle & WS_BORDER) ? -xedge : 0); - y += ((infoPtr->dwStyle & WS_BORDER) ? -yedge : 0); - y += ((infoPtr->dwStyle & CCS_NODIVIDER) ? 0 : REBAR_DIVIDER); - break; - case CCS_BOTTOM: - /* FIXME: wrong wrong wrong */ - /* _BOTTOM sets width to parents width */ - width += (rcPcl.right - rcPcl.left); - height += infoPtr->calcSize.cy; - x += -xedge; - y = rcPcl.bottom - height + 1; - break; - case CCS_LEFT: - /* _LEFT sets height to parents height */ - width += infoPtr->calcSize.cx; - height += (rcPcl.bottom - rcPcl.top); - x += ((infoPtr->dwStyle & WS_BORDER) ? -xedge : 0); - x += ((infoPtr->dwStyle & CCS_NODIVIDER) ? 0 : REBAR_DIVIDER); - y += ((infoPtr->dwStyle & WS_BORDER) ? -yedge : 0); - break; - case CCS_RIGHT: - /* FIXME: wrong wrong wrong */ - /* _RIGHT sets height to parents height */ - width += infoPtr->calcSize.cx; - height += (rcPcl.bottom - rcPcl.top); - x = rcPcl.right - width + 1; - y = -yedge; - break; - default: - width += infoPtr->calcSize.cx; - height += infoPtr->calcSize.cy; - } - } - else { - width += infoPtr->calcSize.cx; - height += infoPtr->calcSize.cy; - x = infoPtr->origin.x; - y = infoPtr->origin.y; - } - - TRACE("hwnd %p, style=%08lx, setting at (%d,%d) for (%d,%d)\n", - infoPtr->hwndSelf, infoPtr->dwStyle, - x, y, width, height); - SetWindowPos (infoPtr->hwndSelf, 0, x, y, width, height, - SWP_NOZORDER); - infoPtr->fStatus &= ~AUTO_RESIZE; -} - - -static VOID -REBAR_MoveChildWindows (REBAR_INFO *infoPtr, UINT start, UINT endplus) -{ - const static WCHAR strComboBox[] = { 'C','o','m','b','o','B','o','x',0 }; - REBAR_BAND *lpBand; - WCHAR szClassName[40]; - UINT i; - NMREBARCHILDSIZE rbcz; - NMHDR heightchange; - HDWP deferpos; - - if (!(deferpos = BeginDeferWindowPos(infoPtr->uNumBands))) - ERR("BeginDeferWindowPos returned NULL\n"); - - for (i = start; i < endplus; i++) { - lpBand = &infoPtr->bands[i]; - - if (HIDDENBAND(lpBand)) continue; - if (lpBand->hwndChild) { - TRACE("hwndChild = %p\n", lpBand->hwndChild); - - /* Always geterate the RBN_CHILDSIZE even it child - did not change */ - rbcz.uBand = i; - rbcz.wID = lpBand->wID; - rbcz.rcChild = lpBand->rcChild; - rbcz.rcBand = lpBand->rcBand; - if (infoPtr->dwStyle & CCS_VERT) - rbcz.rcBand.top += lpBand->cxHeader; - else - rbcz.rcBand.left += lpBand->cxHeader; - REBAR_Notify ((NMHDR *)&rbcz, infoPtr, RBN_CHILDSIZE); - if (!EqualRect (&lpBand->rcChild, &rbcz.rcChild)) { - TRACE("Child rect changed by NOTIFY for band %u\n", i); - TRACE(" from (%ld,%ld)-(%ld,%ld) to (%ld,%ld)-(%ld,%ld)\n", - lpBand->rcChild.left, lpBand->rcChild.top, - lpBand->rcChild.right, lpBand->rcChild.bottom, - rbcz.rcChild.left, rbcz.rcChild.top, - rbcz.rcChild.right, rbcz.rcChild.bottom); - lpBand->rcChild = rbcz.rcChild; /* *** ??? */ - } - - /* native (IE4 in "Favorites" frame **1) does: - * SetRect (&rc, -1, -1, -1, -1) - * EqualRect (&rc,band->rc???) - * if ret==0 - * CopyRect (band->rc????, &rc) - * set flag outside of loop - */ - - GetClassNameW (lpBand->hwndChild, szClassName, sizeof(szClassName)/sizeof(szClassName[0])); - if (!lstrcmpW (szClassName, strComboBox) || - !lstrcmpW (szClassName, WC_COMBOBOXEXW)) { - INT nEditHeight, yPos; - RECT rc; - - /* special placement code for combo or comboex box */ - - - /* get size of edit line */ - GetWindowRect (lpBand->hwndChild, &rc); - nEditHeight = rc.bottom - rc.top; - yPos = (lpBand->rcChild.bottom + lpBand->rcChild.top - nEditHeight)/2; - - /* center combo box inside child area */ - TRACE("moving child (Combo(Ex)) %p to (%ld,%d) for (%ld,%d)\n", - lpBand->hwndChild, - lpBand->rcChild.left, yPos, - lpBand->rcChild.right - lpBand->rcChild.left, - nEditHeight); - deferpos = DeferWindowPos (deferpos, lpBand->hwndChild, HWND_TOP, - lpBand->rcChild.left, - /*lpBand->rcChild.top*/ yPos, - lpBand->rcChild.right - lpBand->rcChild.left, - nEditHeight, - SWP_NOZORDER); - if (!deferpos) - ERR("DeferWindowPos returned NULL\n"); - } - else { - TRACE("moving child (Other) %p to (%ld,%ld) for (%ld,%ld)\n", - lpBand->hwndChild, - lpBand->rcChild.left, lpBand->rcChild.top, - lpBand->rcChild.right - lpBand->rcChild.left, - lpBand->rcChild.bottom - lpBand->rcChild.top); - deferpos = DeferWindowPos (deferpos, lpBand->hwndChild, HWND_TOP, - lpBand->rcChild.left, - lpBand->rcChild.top, - lpBand->rcChild.right - lpBand->rcChild.left, - lpBand->rcChild.bottom - lpBand->rcChild.top, - SWP_NOZORDER); - if (!deferpos) - ERR("DeferWindowPos returned NULL\n"); - } - } - } - if (!EndDeferWindowPos(deferpos)) - ERR("EndDeferWindowPos returned NULL\n"); - - if (infoPtr->DoRedraw) - UpdateWindow (infoPtr->hwndSelf); - - if (infoPtr->fStatus & NTF_HGHTCHG) { - infoPtr->fStatus &= ~NTF_HGHTCHG; - /* - * We need to force a resize here, because some applications - * try to get the rebar size during processing of the - * RBN_HEIGHTCHANGE notification. - */ - REBAR_ForceResize (infoPtr); - REBAR_Notify (&heightchange, infoPtr, RBN_HEIGHTCHANGE); - } - - /* native (from **1 above) does: - * UpdateWindow(rebar) - * REBAR_ForceResize - * RBN_HEIGHTCHANGE if necessary - * if ret from any EqualRect was 0 - * Goto "BeginDeferWindowPos" - */ - -} - - -static VOID -REBAR_Layout (REBAR_INFO *infoPtr, LPRECT lpRect, BOOL notify, BOOL resetclient) - /* Function: This routine is resposible for laying out all */ - /* the bands in a rebar. It assigns each band to a row and*/ - /* determines when to start a new row. */ -{ - REBAR_BAND *lpBand, *prevBand; - RECT rcClient, rcAdj; - INT initx, inity, x, y, cx, cxsep, mmcy, mcy, clientcx, clientcy; - INT adjcx, adjcy, row, rightx, bottomy, origheight; - UINT i, j, rowstart, origrows, cntonrow; - BOOL dobreak; - - if (!(infoPtr->fStatus & BAND_NEEDS_LAYOUT)) { - TRACE("no layout done. No band changed.\n"); - REBAR_DumpBand (infoPtr); - return; - } - infoPtr->fStatus &= ~BAND_NEEDS_LAYOUT; - if (!infoPtr->DoRedraw) infoPtr->fStatus |= BAND_NEEDS_REDRAW; - - GetClientRect (infoPtr->hwndSelf, &rcClient); - TRACE("Client is (%ld,%ld)-(%ld,%ld)\n", - rcClient.left, rcClient.top, rcClient.right, rcClient.bottom); - - if (lpRect) { - rcAdj = *lpRect; - TRACE("adjustment rect is (%ld,%ld)-(%ld,%ld)\n", - rcAdj.left, rcAdj.top, rcAdj.right, rcAdj.bottom); - } - else { - CopyRect (&rcAdj, &rcClient); - } - - clientcx = rcClient.right - rcClient.left; - clientcy = rcClient.bottom - rcClient.top; - adjcx = rcAdj.right - rcAdj.left; - adjcy = rcAdj.bottom - rcAdj.top; - if (resetclient) { - TRACE("window client rect will be set to adj rect\n"); - clientcx = adjcx; - clientcy = adjcy; - } - - if (!infoPtr->DoRedraw && (clientcx == 0) && (clientcy == 0)) { - ERR("no redraw and client is zero, skip layout\n"); - infoPtr->fStatus |= BAND_NEEDS_LAYOUT; - return; - } - - /* save height of original control */ - if (infoPtr->dwStyle & CCS_VERT) - origheight = infoPtr->calcSize.cx; - else - origheight = infoPtr->calcSize.cy; - origrows = infoPtr->uNumRows; - - initx = 0; - inity = 0; - - /* ******* Start Phase 1 - all bands on row at minimum size ******* */ - - TRACE("band loop constants, clientcx=%d, clientcy=%d, adjcx=%d, adjcy=%d\n", - clientcx, clientcy, adjcx, adjcy); - x = initx; - y = inity; - row = 0; - cx = 0; - mcy = 0; - rowstart = 0; - prevBand = NULL; - cntonrow = 0; - - for (i = 0; i < infoPtr->uNumBands; i++) { - lpBand = &infoPtr->bands[i]; - lpBand->fDraw = 0; - lpBand->iRow = row; - - SetRectEmpty(&lpBand->rcChevron); - - if (HIDDENBAND(lpBand)) continue; - - lpBand->rcoldBand = lpBand->rcBand; - - /* Set the offset of the child window */ - if ((lpBand->fMask & RBBIM_CHILD) && - !(lpBand->fStyle & RBBS_FIXEDSIZE)) { - lpBand->offChild.cx = ((lpBand->fStyle & RBBS_CHILDEDGE) ? 4 : 0); - } - lpBand->offChild.cy = ((lpBand->fStyle & RBBS_CHILDEDGE) ? 2 : 0); - - /* separator from previous band */ - cxsep = (cntonrow == 0) ? 0 : SEP_WIDTH; - cx = lpBand->lcx; - - if (infoPtr->dwStyle & CCS_VERT) - dobreak = (y + cx + cxsep > adjcy); - else - dobreak = (x + cx + cxsep > adjcx); - - /* This is the check for whether we need to start a new row */ - if ( ( (lpBand->fStyle & RBBS_BREAK) && (i != 0) ) || - ( ((infoPtr->dwStyle & CCS_VERT) ? (y != 0) : (x != 0)) && dobreak)) { - - for (j = rowstart; j < i; j++) { - REBAR_BAND *lpB; - lpB = &infoPtr->bands[j]; - if (infoPtr->dwStyle & CCS_VERT) { - lpB->rcBand.right = lpB->rcBand.left + mcy; - } - else { - lpB->rcBand.bottom = lpB->rcBand.top + mcy; - } - } - - TRACE("P1 Spliting to new row %d on band %u\n", row+1, i); - if (infoPtr->dwStyle & CCS_VERT) { - y = inity; - x += (mcy + SEP_WIDTH); - } - else { - x = initx; - y += (mcy + SEP_WIDTH); - } - - mcy = 0; - cxsep = 0; - row++; - lpBand->iRow = row; - prevBand = NULL; - rowstart = i; - cntonrow = 0; - } - - if (mcy < lpBand->lcy + REBARSPACE(lpBand)) - mcy = lpBand->lcy + REBARSPACE(lpBand); - - /* if boundary rect specified then limit mcy */ - if (lpRect) { - if (infoPtr->dwStyle & CCS_VERT) { - if (x+mcy > adjcx) { - mcy = adjcx - x; - TRACE("P1 row %u limiting mcy=%d, adjcx=%d, x=%d\n", - i, mcy, adjcx, x); - } - } - else { - if (y+mcy > adjcy) { - mcy = adjcy - y; - TRACE("P1 row %u limiting mcy=%d, adjcy=%d, y=%d\n", - i, mcy, adjcy, y); - } - } - } - - TRACE("P1 band %u, row %d, x=%d, y=%d, cxsep=%d, cx=%d\n", - i, row, - x, y, cxsep, cx); - if (infoPtr->dwStyle & CCS_VERT) { - /* bound the bottom side if we have a bounding rectangle */ - rightx = clientcx; - bottomy = (lpRect) ? min(clientcy, y+cxsep+cx) : y+cxsep+cx; - lpBand->rcBand.left = x; - lpBand->rcBand.right = x + min(mcy, - lpBand->lcy+REBARSPACE(lpBand)); - lpBand->rcBand.top = min(bottomy, y + cxsep); - lpBand->rcBand.bottom = bottomy; - lpBand->uMinHeight = lpBand->lcy; - y = bottomy; - } - else { - /* bound the right side if we have a bounding rectangle */ - rightx = (lpRect) ? min(clientcx, x+cxsep+cx) : x+cxsep+cx; - bottomy = clientcy; - lpBand->rcBand.left = min(rightx, x + cxsep); - lpBand->rcBand.right = rightx; - lpBand->rcBand.top = y; - lpBand->rcBand.bottom = y + min(mcy, - lpBand->lcy+REBARSPACE(lpBand)); - lpBand->uMinHeight = lpBand->lcy; - x = rightx; - } - TRACE("P1 band %u, row %d, (%ld,%ld)-(%ld,%ld)\n", - i, row, - lpBand->rcBand.left, lpBand->rcBand.top, - lpBand->rcBand.right, lpBand->rcBand.bottom); - prevBand = lpBand; - cntonrow++; - - } /* for (i = 0; i < infoPtr->uNumBands... */ - - if (infoPtr->dwStyle & CCS_VERT) - x += mcy; - else - y += mcy; - - for (j = rowstart; j < infoPtr->uNumBands; j++) { - lpBand = &infoPtr->bands[j]; - if (infoPtr->dwStyle & CCS_VERT) { - lpBand->rcBand.right = lpBand->rcBand.left + mcy; - } - else { - lpBand->rcBand.bottom = lpBand->rcBand.top + mcy; - } - } - - if (infoPtr->uNumBands) - infoPtr->uNumRows = row + 1; - - /* ******* End Phase 1 - all bands on row at minimum size ******* */ - - - /* ******* Start Phase 1a - Adjust heights for RBS_VARHEIGHT off ******* */ - - mmcy = 0; - if (!(infoPtr->dwStyle & RBS_VARHEIGHT)) { - INT xy; - - /* get the max height of all bands */ - for (i=0; iuNumBands; i++) { - lpBand = &infoPtr->bands[i]; - if (HIDDENBAND(lpBand)) continue; - if (infoPtr->dwStyle & CCS_VERT) - mmcy = max(mmcy, lpBand->rcBand.right - lpBand->rcBand.left); - else - mmcy = max(mmcy, lpBand->rcBand.bottom - lpBand->rcBand.top); - } - - /* now adjust all rectangles by using the height found above */ - xy = 0; - row = 0; - for (i=0; iuNumBands; i++) { - lpBand = &infoPtr->bands[i]; - if (HIDDENBAND(lpBand)) continue; - if (lpBand->iRow != row) - xy += (mmcy + SEP_WIDTH); - if (infoPtr->dwStyle & CCS_VERT) { - lpBand->rcBand.left = xy; - lpBand->rcBand.right = xy + mmcy; - } - else { - lpBand->rcBand.top = xy; - lpBand->rcBand.bottom = xy + mmcy; - } - } - - /* set the x/y values to the correct maximum */ - if (infoPtr->dwStyle & CCS_VERT) - x = xy + mmcy; - else - y = xy + mmcy; - } - - /* ******* End Phase 1a - Adjust heights for RBS_VARHEIGHT off ******* */ - - - /* ******* Start Phase 2 - split rows till adjustment height full ******* */ - - /* assumes that the following variables contain: */ - /* y/x current height/width of all rows */ - if (lpRect) { - INT i, prev_rh, new_rh, adj_rh, prev_idx, current_idx; - REBAR_BAND *prev, *current, *walk; - UINT j; - -/* FIXME: problem # 2 */ - if (((infoPtr->dwStyle & CCS_VERT) ? -#if PROBLEM2 - (x < adjcx) : (y < adjcy) -#else - (adjcx - x > 5) : (adjcy - y > 4) -#endif - ) && - (infoPtr->uNumBands > 1)) { - for (i=(INT)infoPtr->uNumBands-2; i>=0; i--) { - TRACE("P2 adjcx=%d, adjcy=%d, x=%d, y=%d\n", - adjcx, adjcy, x, y); - - /* find the current band (starts at i+1) */ - current = &infoPtr->bands[i+1]; - current_idx = i+1; - while (HIDDENBAND(current)) { - i--; - if (i < 0) break; /* out of bands */ - current = &infoPtr->bands[i+1]; - current_idx = i+1; - } - if (i < 0) break; /* out of bands */ - - /* now find the prev band (starts at i) */ - prev = &infoPtr->bands[i]; - prev_idx = i; - while (HIDDENBAND(prev)) { - i--; - if (i < 0) break; /* out of bands */ - prev = &infoPtr->bands[i]; - prev_idx = i; - } - if (i < 0) break; /* out of bands */ - - prev_rh = ircBw(prev); - if (prev->iRow == current->iRow) { - new_rh = (infoPtr->dwStyle & RBS_VARHEIGHT) ? - current->lcy + REBARSPACE(current) : - mmcy; - adj_rh = new_rh + SEP_WIDTH; - infoPtr->uNumRows++; - current->fDraw |= NTF_INVALIDATE; - current->iRow++; - if (infoPtr->dwStyle & CCS_VERT) { - current->rcBand.top = inity; - current->rcBand.bottom = clientcy; - current->rcBand.left += (prev_rh + SEP_WIDTH); - current->rcBand.right = current->rcBand.left + new_rh; - x += adj_rh; - } - else { - current->rcBand.left = initx; - current->rcBand.right = clientcx; - current->rcBand.top += (prev_rh + SEP_WIDTH); - current->rcBand.bottom = current->rcBand.top + new_rh; - y += adj_rh; - } - TRACE("P2 moving band %d to own row at (%ld,%ld)-(%ld,%ld)\n", - current_idx, - current->rcBand.left, current->rcBand.top, - current->rcBand.right, current->rcBand.bottom); - TRACE("P2 prev band %d at (%ld,%ld)-(%ld,%ld)\n", - prev_idx, - prev->rcBand.left, prev->rcBand.top, - prev->rcBand.right, prev->rcBand.bottom); - TRACE("P2 values: prev_rh=%d, new_rh=%d, adj_rh=%d\n", - prev_rh, new_rh, adj_rh); - /* for bands below current adjust row # and top/bottom */ - for (j = current_idx+1; juNumBands; j++) { - walk = &infoPtr->bands[j]; - if (HIDDENBAND(walk)) continue; - walk->fDraw |= NTF_INVALIDATE; - walk->iRow++; - if (infoPtr->dwStyle & CCS_VERT) { - walk->rcBand.left += adj_rh; - walk->rcBand.right += adj_rh; - } - else { - walk->rcBand.top += adj_rh; - walk->rcBand.bottom += adj_rh; - } - } - if ((infoPtr->dwStyle & CCS_VERT) ? (x >= adjcx) : (y >= adjcy)) - break; /* all done */ - } - } - } - } - - /* ******* End Phase 2 - split rows till adjustment height full ******* */ - - - /* ******* Start Phase 2a - mark first and last band in each ******* */ - - prevBand = NULL; - for (i = 0; i < infoPtr->uNumBands; i++) { - lpBand = &infoPtr->bands[i]; - if (HIDDENBAND(lpBand)) - continue; - if( !prevBand ) { - lpBand->fDraw |= DRAW_FIRST_IN_ROW; - prevBand = lpBand; - } - else if( prevBand->iRow == lpBand->iRow ) - prevBand = lpBand; - else { - prevBand->fDraw |= DRAW_LAST_IN_ROW; - lpBand->fDraw |= DRAW_FIRST_IN_ROW; - prevBand = lpBand; - } - } - if( prevBand ) - prevBand->fDraw |= DRAW_LAST_IN_ROW; - - /* ******* End Phase 2a - mark first and last band in each ******* */ - - - /* ******* Start Phase 2b - adjust all bands for height full ******* */ - /* assumes that the following variables contain: */ - /* y/x current height/width of all rows */ - /* clientcy/clientcx height/width of client area */ - - if (((infoPtr->dwStyle & CCS_VERT) ? clientcx > x : clientcy > y) && - infoPtr->uNumBands) { - INT diff, i; - UINT j; - - diff = (infoPtr->dwStyle & CCS_VERT) ? clientcx - x : clientcy - y; - - /* iterate backwards thru the rows */ - for (i = infoPtr->uNumBands-1; i>=0; i--) { - lpBand = &infoPtr->bands[i]; - if(HIDDENBAND(lpBand)) continue; - - /* if row has more than 1 band, ignore it */ - if( !(lpBand->fDraw&DRAW_FIRST_IN_ROW) ) - continue; - if( !(lpBand->fDraw&DRAW_LAST_IN_ROW) ) - continue; - - /* FIXME: this next line is wrong, but fixing it to be inverted causes IE's sidebars to be the wrong size */ - if (lpBand->fMask & RBBS_VARIABLEHEIGHT) continue; - if (((INT)lpBand->cyMaxChild < 1) || - ((INT)lpBand->cyIntegral < 1)) { - if (lpBand->cyMaxChild + lpBand->cyIntegral == 0) continue; - ERR("P2b band %u RBBS_VARIABLEHEIGHT set but cyMax=%d, cyInt=%d\n", - i, lpBand->cyMaxChild, lpBand->cyIntegral); - continue; - } - /* j is now the maximum height/width in the client area */ - j = ((diff / lpBand->cyIntegral) * lpBand->cyIntegral) + - ircBw(lpBand); - if (j > lpBand->cyMaxChild + REBARSPACE(lpBand)) - j = lpBand->cyMaxChild + REBARSPACE(lpBand); - diff -= (j - ircBw(lpBand)); - if (infoPtr->dwStyle & CCS_VERT) - lpBand->rcBand.right = lpBand->rcBand.left + j; - else - lpBand->rcBand.bottom = lpBand->rcBand.top + j; - TRACE("P2b band %d, row %d changed to (%ld,%ld)-(%ld,%ld)\n", - i, lpBand->iRow, - lpBand->rcBand.left, lpBand->rcBand.top, - lpBand->rcBand.right, lpBand->rcBand.bottom); - if (diff <= 0) break; - } - if (diff < 0) { - ERR("P2b allocated more than available, diff=%d\n", diff); - diff = 0; - } - if (infoPtr->dwStyle & CCS_VERT) - x = clientcx - diff; - else - y = clientcy - diff; - } - - /* ******* End Phase 2b - adjust all bands for height full ******* */ - - - /* ******* Start Phase 3 - adjust all bands for width full ******* */ - - if (infoPtr->uNumBands) { - int startband; - - /* If RBS_BANDBORDERS set then indicate to draw bottom separator */ - /* on all bands in all rows but last row. */ - /* Also indicate to draw the right separator for each band in */ - /* each row but the rightmost band. */ - if (infoPtr->dwStyle & RBS_BANDBORDERS) { - - for (i=0; iuNumBands; i++) { - lpBand = &infoPtr->bands[i]; - if (HIDDENBAND(lpBand)) - continue; - - /* not righthand bands */ - if( !(lpBand->fDraw & DRAW_LAST_IN_ROW) ) - lpBand->fDraw |= DRAW_RIGHTSEP; - - /* not the last row */ - if( lpBand->iRow != infoPtr->uNumRows ) - lpBand->fDraw |= DRAW_BOTTOMSEP; - } - } - - /* Distribute the extra space on the horizontal and adjust */ - /* all bands in row to same height. */ - mcy = 0; - startband = -1; - for (i=0; iuNumBands; i++) { - - lpBand = &infoPtr->bands[i]; - - if( lpBand->fDraw & DRAW_FIRST_IN_ROW ) - { - startband = i; - mcy = 0; - } - - if ( (mcy < ircBw(lpBand)) && !HIDDENBAND(lpBand) ) - mcy = ircBw(lpBand); - - if( lpBand->fDraw & DRAW_LAST_IN_ROW ) - { - TRACE("P3 processing row %d, starting band %d, ending band %d\n", - lpBand->iRow, startband, i); - if( startband < 0 ) - ERR("Last band %d with no first, row %d\n", i, lpBand->iRow); - - REBAR_AdjustBands (infoPtr, startband, i, - (infoPtr->dwStyle & CCS_VERT) ? - clientcy : clientcx, mcy); - } - } - - /* Calculate the other rectangles in each band */ - if (infoPtr->dwStyle & CCS_VERT) { - REBAR_CalcVertBand (infoPtr, 0, infoPtr->uNumBands, - notify); - } - else { - REBAR_CalcHorzBand (infoPtr, 0, infoPtr->uNumBands, - notify); - } - } - - /* ******* End Phase 3 - adjust all bands for width full ******* */ - - /* now compute size of Rebar itself */ - infoPtr->oldSize = infoPtr->calcSize; - if (infoPtr->uNumBands == 0) { - /* we have no bands, so make size the size of client */ - x = clientcx; - y = clientcy; - } - if (infoPtr->dwStyle & CCS_VERT) { - if( x < REBAR_MINSIZE ) - x = REBAR_MINSIZE; - infoPtr->calcSize.cx = x; - infoPtr->calcSize.cy = clientcy; - TRACE("vert, notify=%d, x=%d, origheight=%d\n", - notify, x, origheight); - if (notify && (x != origheight)) infoPtr->fStatus |= NTF_HGHTCHG; - } - else { - if( y < REBAR_MINSIZE ) - y = REBAR_MINSIZE; - infoPtr->calcSize.cx = clientcx; - infoPtr->calcSize.cy = y; - TRACE("horz, notify=%d, y=%d, origheight=%d\n", - notify, y, origheight); - if (notify && (y != origheight)) infoPtr->fStatus |= NTF_HGHTCHG; - } - - REBAR_DumpBand (infoPtr); - - REBAR_MoveChildWindows (infoPtr, 0, infoPtr->uNumBands); - - REBAR_ForceResize (infoPtr); -} - - -static VOID -REBAR_ValidateBand (REBAR_INFO *infoPtr, REBAR_BAND *lpBand) - /* Function: This routine evaluates the band specs supplied */ - /* by the user and updates the following 5 fields in */ - /* the internal band structure: cxHeader, lcx, lcy, hcx, hcy*/ -{ - UINT header=0; - UINT textheight=0; - UINT i, nonfixed; - REBAR_BAND *tBand; - - lpBand->fStatus = 0; - lpBand->lcx = 0; - lpBand->lcy = 0; - lpBand->ccx = 0; - lpBand->ccy = 0; - lpBand->hcx = 0; - lpBand->hcy = 0; - - /* Data comming in from users into the cx... and cy... fields */ - /* may be bad, just garbage, because the user never clears */ - /* the fields. RB_{SET|INSERT}BAND{A|W} just passes the data */ - /* along if the fields exist in the input area. Here we must */ - /* determine if the data is valid. I have no idea how MS does */ - /* the validation, but it does because the RB_GETBANDINFO */ - /* returns a 0 when I know the sample program passed in an */ - /* address. Here I will use the algorithim that if the value */ - /* is greater than 65535 then it is bad and replace it with */ - /* a zero. Feel free to improve the algorithim. - GA 12/2000 */ - if (lpBand->cxMinChild > 65535) lpBand->cxMinChild = 0; - if (lpBand->cyMinChild > 65535) lpBand->cyMinChild = 0; - if (lpBand->cx > 65535) lpBand->cx = 0; - if (lpBand->cyChild > 65535) lpBand->cyChild = 0; - if (lpBand->cyMaxChild > 65535) lpBand->cyMaxChild = 0; - if (lpBand->cyIntegral > 65535) lpBand->cyIntegral = 0; - if (lpBand->cxIdeal > 65535) lpBand->cxIdeal = 0; - if (lpBand->cxHeader > 65535) lpBand->cxHeader = 0; - - /* FIXME: probably should only set NEEDS_LAYOUT flag when */ - /* values change. Till then always set it. */ - TRACE("setting NEEDS_LAYOUT\n"); - infoPtr->fStatus |= BAND_NEEDS_LAYOUT; - - /* Header is where the image, text and gripper exist */ - /* in the band and precede the child window. */ - - /* count number of non-FIXEDSIZE and non-Hidden bands */ - nonfixed = 0; - for (i=0; iuNumBands; i++){ - tBand = &infoPtr->bands[i]; - if (!HIDDENBAND(tBand) && !(tBand->fStyle & RBBS_FIXEDSIZE)) - nonfixed++; - } - - /* calculate gripper rectangle */ - if ( (!(lpBand->fStyle & RBBS_NOGRIPPER)) && - ( (lpBand->fStyle & RBBS_GRIPPERALWAYS) || - ( !(lpBand->fStyle & RBBS_FIXEDSIZE) && (nonfixed > 1))) - ) { - lpBand->fStatus |= HAS_GRIPPER; - if (infoPtr->dwStyle & CCS_VERT) - if (infoPtr->dwStyle & RBS_VERTICALGRIPPER) - header += (GRIPPER_HEIGHT + REBAR_PRE_GRIPPER); - else - header += (GRIPPER_WIDTH + REBAR_PRE_GRIPPER); - else - header += (REBAR_PRE_GRIPPER + GRIPPER_WIDTH); - /* Always have 4 pixels before anything else */ - header += REBAR_ALWAYS_SPACE; - } - - /* image is visible */ - if ((lpBand->fMask & RBBIM_IMAGE) && (infoPtr->himl)) { - lpBand->fStatus |= HAS_IMAGE; - if (infoPtr->dwStyle & CCS_VERT) { - header += (infoPtr->imageSize.cy + REBAR_POST_IMAGE); - lpBand->lcy = infoPtr->imageSize.cx + 2; - } - else { - header += (infoPtr->imageSize.cx + REBAR_POST_IMAGE); - lpBand->lcy = infoPtr->imageSize.cy + 2; - } - } - - /* text is visible */ - if ((lpBand->fMask & RBBIM_TEXT) && (lpBand->lpText) && - !(lpBand->fStyle & RBBS_HIDETITLE)) { - HDC hdc = GetDC (0); - HFONT hOldFont = SelectObject (hdc, infoPtr->hFont); - SIZE size; - - lpBand->fStatus |= HAS_TEXT; - GetTextExtentPoint32W (hdc, lpBand->lpText, - lstrlenW (lpBand->lpText), &size); - header += ((infoPtr->dwStyle & CCS_VERT) ? (size.cy + REBAR_POST_TEXT) : (size.cx + REBAR_POST_TEXT)); - textheight = (infoPtr->dwStyle & CCS_VERT) ? 0 : size.cy; - - SelectObject (hdc, hOldFont); - ReleaseDC (0, hdc); - } - - /* if no gripper but either image or text, then leave space */ - if ((lpBand->fStatus & (HAS_IMAGE | HAS_TEXT)) && - !(lpBand->fStatus & HAS_GRIPPER)) { - header += REBAR_ALWAYS_SPACE; - } - - /* check if user overrode the header value */ - if (!(lpBand->fMask & RBBIM_HEADERSIZE)) - lpBand->cxHeader = header; - - - /* Now compute minimum size of child window */ - lpBand->offChild.cx = 0; - lpBand->offChild.cy = 0; - lpBand->lcy = textheight; - lpBand->ccy = lpBand->lcy; - if (lpBand->fMask & RBBIM_CHILDSIZE) { - lpBand->lcx = lpBand->cxMinChild; - - /* Set the .cy values for CHILDSIZE case */ - lpBand->lcy = max(lpBand->lcy, lpBand->cyMinChild); - lpBand->ccy = lpBand->lcy; - lpBand->hcy = lpBand->lcy; - if (lpBand->cyMaxChild != 0xffffffff) { - lpBand->hcy = lpBand->cyMaxChild; - } - if (lpBand->cyChild != 0xffffffff) - lpBand->ccy = max (lpBand->cyChild, lpBand->lcy); - - TRACE("_CHILDSIZE\n"); - } - if (lpBand->fMask & RBBIM_SIZE) { - lpBand->hcx = max (lpBand->cx-lpBand->cxHeader, lpBand->lcx); - TRACE("_SIZE\n"); - } - else - lpBand->hcx = lpBand->lcx; - lpBand->ccx = lpBand->hcx; - - /* make ->.cx include header size for _Layout */ - lpBand->lcx += lpBand->cxHeader; - lpBand->ccx += lpBand->cxHeader; - lpBand->hcx += lpBand->cxHeader; - -} - -static BOOL -REBAR_CommonSetupBand (HWND hwnd, LPREBARBANDINFOA lprbbi, REBAR_BAND *lpBand) - /* Function: This routine copies the supplied values from */ - /* user input (lprbbi) to the internal band structure. */ - /* It returns true if something changed and false if not. */ -{ - BOOL bChanged = FALSE; - - lpBand->fMask |= lprbbi->fMask; - - if( (lprbbi->fMask & RBBIM_STYLE) && - (lpBand->fStyle != lprbbi->fStyle ) ) - { - lpBand->fStyle = lprbbi->fStyle; - bChanged = TRUE; - } - - if( (lprbbi->fMask & RBBIM_COLORS) && - ( ( lpBand->clrFore != lprbbi->clrFore ) || - ( lpBand->clrBack != lprbbi->clrBack ) ) ) - { - lpBand->clrFore = lprbbi->clrFore; - lpBand->clrBack = lprbbi->clrBack; - bChanged = TRUE; - } - - if( (lprbbi->fMask & RBBIM_IMAGE) && - ( lpBand->iImage != lprbbi->iImage ) ) - { - lpBand->iImage = lprbbi->iImage; - bChanged = TRUE; - } - - if( (lprbbi->fMask & RBBIM_CHILD) && - (lprbbi->hwndChild != lpBand->hwndChild ) ) - { - if (lprbbi->hwndChild) { - lpBand->hwndChild = lprbbi->hwndChild; - lpBand->hwndPrevParent = - SetParent (lpBand->hwndChild, hwnd); - /* below in trace fro WinRAR */ - ShowWindow(lpBand->hwndChild, SW_SHOWNOACTIVATE | SW_SHOWNORMAL); - /* above in trace fro WinRAR */ - } - else { - TRACE("child: %p prev parent: %p\n", - lpBand->hwndChild, lpBand->hwndPrevParent); - lpBand->hwndChild = 0; - lpBand->hwndPrevParent = 0; - } - bChanged = TRUE; - } - - if( (lprbbi->fMask & RBBIM_CHILDSIZE) && - ( (lpBand->cxMinChild != lprbbi->cxMinChild) || - (lpBand->cyMinChild != lprbbi->cyMinChild ) || - ( (lprbbi->cbSize >= sizeof (REBARBANDINFOA)) && - ( (lpBand->cyChild != lprbbi->cyChild ) || - (lpBand->cyMaxChild != lprbbi->cyMaxChild ) || - (lpBand->cyIntegral != lprbbi->cyIntegral ) ) ) || - ( (lprbbi->cbSize < sizeof (REBARBANDINFOA)) && - ( (lpBand->cyChild || - lpBand->cyMaxChild || - lpBand->cyIntegral ) ) ) ) ) - { - lpBand->cxMinChild = lprbbi->cxMinChild; - lpBand->cyMinChild = lprbbi->cyMinChild; - if (lprbbi->cbSize >= sizeof (REBARBANDINFOA)) { - lpBand->cyChild = lprbbi->cyChild; - lpBand->cyMaxChild = lprbbi->cyMaxChild; - lpBand->cyIntegral = lprbbi->cyIntegral; - } - else { /* special case - these should be zeroed out since */ - /* RBBIM_CHILDSIZE added these in WIN32_IE >= 0x0400 */ - lpBand->cyChild = 0; - lpBand->cyMaxChild = 0; - lpBand->cyIntegral = 0; - } - bChanged = TRUE; - } - - if( (lprbbi->fMask & RBBIM_SIZE) && - (lpBand->cx != lprbbi->cx ) ) - { - lpBand->cx = lprbbi->cx; - bChanged = TRUE; - } - - if( (lprbbi->fMask & RBBIM_BACKGROUND) && - ( lpBand->hbmBack != lprbbi->hbmBack ) ) - { - lpBand->hbmBack = lprbbi->hbmBack; - bChanged = TRUE; - } - - if( (lprbbi->fMask & RBBIM_ID) && - (lpBand->wID != lprbbi->wID ) ) - { - lpBand->wID = lprbbi->wID; - bChanged = TRUE; - } - - /* check for additional data */ - if (lprbbi->cbSize >= sizeof (REBARBANDINFOA)) { - if( (lprbbi->fMask & RBBIM_IDEALSIZE) && - ( lpBand->cxIdeal != lprbbi->cxIdeal ) ) - { - lpBand->cxIdeal = lprbbi->cxIdeal; - bChanged = TRUE; - } - - if( (lprbbi->fMask & RBBIM_LPARAM) && - (lpBand->lParam != lprbbi->lParam ) ) - { - lpBand->lParam = lprbbi->lParam; - bChanged = TRUE; - } - - if( (lprbbi->fMask & RBBIM_HEADERSIZE) && - (lpBand->cxHeader != lprbbi->cxHeader ) ) - { - lpBand->cxHeader = lprbbi->cxHeader; - bChanged = TRUE; - } - } - - return bChanged; -} - -static LRESULT -REBAR_InternalEraseBkGnd (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam, RECT *clip) - /* Function: This erases the background rectangle by drawing */ - /* each band with its background color (or the default) and */ - /* draws each bands right separator if necessary. The row */ - /* separators are drawn on the first band of the next row. */ -{ - REBAR_BAND *lpBand; - UINT i; - INT oldrow; - HDC hdc = (HDC)wParam; - RECT rect; - COLORREF old = CLR_NONE, new; - - oldrow = -1; - for(i=0; iuNumBands; i++) { - lpBand = &infoPtr->bands[i]; - if (HIDDENBAND(lpBand)) continue; - - /* draw band separator between rows */ - if (lpBand->iRow != oldrow) { - oldrow = lpBand->iRow; - if (lpBand->fDraw & DRAW_BOTTOMSEP) { - RECT rcRowSep; - rcRowSep = lpBand->rcBand; - if (infoPtr->dwStyle & CCS_VERT) { - rcRowSep.right += SEP_WIDTH_SIZE; - rcRowSep.bottom = infoPtr->calcSize.cy; - DrawEdge (hdc, &rcRowSep, EDGE_ETCHED, BF_RIGHT); - } - else { - rcRowSep.bottom += SEP_WIDTH_SIZE; - rcRowSep.right = infoPtr->calcSize.cx; - DrawEdge (hdc, &rcRowSep, EDGE_ETCHED, BF_BOTTOM); - } - TRACE ("drawing band separator bottom (%ld,%ld)-(%ld,%ld)\n", - rcRowSep.left, rcRowSep.top, - rcRowSep.right, rcRowSep.bottom); - } - } - - /* draw band separator between bands in a row */ - if (lpBand->fDraw & DRAW_RIGHTSEP) { - RECT rcSep; - rcSep = lpBand->rcBand; - if (infoPtr->dwStyle & CCS_VERT) { - rcSep.bottom += SEP_WIDTH_SIZE; - DrawEdge (hdc, &rcSep, EDGE_ETCHED, BF_BOTTOM); - } - else { - rcSep.right += SEP_WIDTH_SIZE; - DrawEdge (hdc, &rcSep, EDGE_ETCHED, BF_RIGHT); - } - TRACE("drawing band separator right (%ld,%ld)-(%ld,%ld)\n", - rcSep.left, rcSep.top, rcSep.right, rcSep.bottom); - } - - /* draw the actual background */ - if (lpBand->clrBack != CLR_NONE) { - new = (lpBand->clrBack == CLR_DEFAULT) ? infoPtr->clrBtnFace : - lpBand->clrBack; -#if GLATESTING - /* testing only - make background green to see it */ - new = RGB(0,128,0); -#endif - } - else { - /* In the absence of documentation for Rebar vs. CLR_NONE, - * we will use the default BtnFace color. Note documentation - * exists for Listview and Imagelist. - */ - new = infoPtr->clrBtnFace; -#if GLATESTING - /* testing only - make background green to see it */ - new = RGB(0,128,0); -#endif - } - old = SetBkColor (hdc, new); - - rect = lpBand->rcBand; - TRACE("%s background color=0x%06lx, band (%ld,%ld)-(%ld,%ld), clip (%ld,%ld)-(%ld,%ld)\n", - (lpBand->clrBack == CLR_NONE) ? "none" : - ((lpBand->clrBack == CLR_DEFAULT) ? "dft" : ""), - GetBkColor(hdc), - lpBand->rcBand.left,lpBand->rcBand.top, - lpBand->rcBand.right,lpBand->rcBand.bottom, - clip->left, clip->top, - clip->right, clip->bottom); - ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, 0); - if (lpBand->clrBack != CLR_NONE) - SetBkColor (hdc, old); - } - return TRUE; -} - -static void -REBAR_InternalHitTest (REBAR_INFO *infoPtr, const LPPOINT lpPt, UINT *pFlags, INT *pBand) -{ - REBAR_BAND *lpBand; - RECT rect; - UINT iCount; - - GetClientRect (infoPtr->hwndSelf, &rect); - - *pFlags = RBHT_NOWHERE; - if (PtInRect (&rect, *lpPt)) - { - if (infoPtr->uNumBands == 0) { - *pFlags = RBHT_NOWHERE; - if (pBand) - *pBand = -1; - TRACE("NOWHERE\n"); - return; - } - else { - /* somewhere inside */ - for (iCount = 0; iCount < infoPtr->uNumBands; iCount++) { - lpBand = &infoPtr->bands[iCount]; - if (HIDDENBAND(lpBand)) continue; - if (PtInRect (&lpBand->rcBand, *lpPt)) { - if (pBand) - *pBand = iCount; - if (PtInRect (&lpBand->rcGripper, *lpPt)) { - *pFlags = RBHT_GRABBER; - TRACE("ON GRABBER %d\n", iCount); - return; - } - else if (PtInRect (&lpBand->rcCapImage, *lpPt)) { - *pFlags = RBHT_CAPTION; - TRACE("ON CAPTION %d\n", iCount); - return; - } - else if (PtInRect (&lpBand->rcCapText, *lpPt)) { - *pFlags = RBHT_CAPTION; - TRACE("ON CAPTION %d\n", iCount); - return; - } - else if (PtInRect (&lpBand->rcChild, *lpPt)) { - *pFlags = RBHT_CLIENT; - TRACE("ON CLIENT %d\n", iCount); - return; - } - else if (PtInRect (&lpBand->rcChevron, *lpPt)) { - *pFlags = RBHT_CHEVRON; - TRACE("ON CHEVRON %d\n", iCount); - return; - } - else { - *pFlags = RBHT_NOWHERE; - TRACE("NOWHERE %d\n", iCount); - return; - } - } - } - - *pFlags = RBHT_NOWHERE; - if (pBand) - *pBand = -1; - - TRACE("NOWHERE\n"); - return; - } - } - else { - *pFlags = RBHT_NOWHERE; - if (pBand) - *pBand = -1; - TRACE("NOWHERE\n"); - return; - } -} - - -static INT -REBAR_Shrink (REBAR_INFO *infoPtr, REBAR_BAND *band, INT movement, INT i) - /* Function: This attempts to shrink the given band by the */ - /* the amount in "movement". A shrink to the left is indi- */ - /* cated by "movement" being negative. "i" is merely the */ - /* band index for trace messages. */ -{ - INT Leadjust, Readjust, avail, ret; - - /* Note: a left drag is indicated by "movement" being negative. */ - /* Similarly, a right drag is indicated by "movement" */ - /* being positive. "movement" should never be 0, but if */ - /* it is then the band does not move. */ - - avail = rcBw(band) - band->lcx; - - /* now compute the Left End adjustment factor and Right End */ - /* adjustment factor. They may be different if shrinking. */ - if (avail <= 0) { - /* if this band is not shrinkable, then just move it */ - Leadjust = Readjust = movement; - ret = movement; - } - else { - if (movement < 0) { - /* Drag to left */ - if (avail <= abs(movement)) { - Readjust = movement; - Leadjust = movement + avail; - ret = Leadjust; - } - else { - Readjust = movement; - Leadjust = 0; - ret = 0; - } - } - else { - /* Drag to right */ - if (avail <= abs(movement)) { - Leadjust = movement; - Readjust = movement - avail; - ret = Readjust; - } - else { - Leadjust = movement; - Readjust = 0; - ret = 0; - } - } - } - - /* Reasonability Check */ - if (rcBlt(band) + Leadjust < 0) { - ERR("adjustment will fail, band %d: left=%d, right=%d, move=%d, rtn=%d\n", - i, Leadjust, Readjust, movement, ret); - } - - LEADJ(band, Leadjust); - READJ(band, Readjust); - - TRACE("band %d: left=%d, right=%d, move=%d, rtn=%d, rcBand=(%ld,%ld)-(%ld,%ld)\n", - i, Leadjust, Readjust, movement, ret, - band->rcBand.left, band->rcBand.top, - band->rcBand.right, band->rcBand.bottom); - return ret; -} - - -static void -REBAR_HandleLRDrag (REBAR_INFO *infoPtr, const POINT *ptsmove) - /* Function: This will implement the functionality of a */ - /* Gripper drag within a row. It will not implement "out- */ - /* of-row" drags. (They are detected and handled in */ - /* REBAR_MouseMove.) */ - /* **** FIXME Switching order of bands in a row not **** */ - /* **** yet implemented. **** */ -{ - REBAR_BAND *hitBand, *band, *mindBand, *maxdBand; - RECT newrect; - INT imindBand = -1, imaxdBand, ihitBand, i, movement; - INT RHeaderSum = 0, LHeaderSum = 0; - INT compress; - - /* on first significant mouse movement, issue notify */ - - if (!(infoPtr->fStatus & BEGIN_DRAG_ISSUED)) { - if (REBAR_Notify_NMREBAR (infoPtr, -1, RBN_BEGINDRAG)) { - /* Notify returned TRUE - abort drag */ - infoPtr->dragStart.x = 0; - infoPtr->dragStart.y = 0; - infoPtr->dragNow = infoPtr->dragStart; - infoPtr->iGrabbedBand = -1; - ReleaseCapture (); - return ; - } - infoPtr->fStatus |= BEGIN_DRAG_ISSUED; - } - - ihitBand = infoPtr->iGrabbedBand; - hitBand = &infoPtr->bands[ihitBand]; - imaxdBand = ihitBand; /* to suppress warning message */ - - /* find all the bands in the row of the one whose Gripper was seized */ - for (i=0; iuNumBands; i++) { - band = &infoPtr->bands[i]; - if (HIDDENBAND(band)) continue; - if (band->iRow == hitBand->iRow) { - imaxdBand = i; - if (imindBand == -1) imindBand = i; - /* minimum size of each band is size of header plus */ - /* size of minimum child plus offset of child from header plus */ - /* one to separate each band. */ - if (i < ihitBand) - LHeaderSum += (band->lcx + SEP_WIDTH); - else - RHeaderSum += (band->lcx + SEP_WIDTH); - - } - } - if (RHeaderSum) RHeaderSum -= SEP_WIDTH; /* no separator after last band */ - - mindBand = &infoPtr->bands[imindBand]; - maxdBand = &infoPtr->bands[imaxdBand]; - - if (imindBand == imaxdBand) return; /* nothing to drag against */ - if (imindBand == ihitBand) return; /* first band in row, can't drag */ - - /* limit movement to inside adjustable bands - Left */ - if ( (ptsmove->x < mindBand->rcBand.left) || - (ptsmove->x > maxdBand->rcBand.right) || - (ptsmove->y < mindBand->rcBand.top) || - (ptsmove->y > maxdBand->rcBand.bottom)) - return; /* should swap bands */ - - if (infoPtr->dwStyle & CCS_VERT) - movement = ptsmove->y - ((hitBand->rcBand.top+REBAR_PRE_GRIPPER) - - infoPtr->ihitoffset); - else - movement = ptsmove->x - ((hitBand->rcBand.left+REBAR_PRE_GRIPPER) - - infoPtr->ihitoffset); - infoPtr->dragNow = *ptsmove; - - TRACE("before: movement=%d (%ld,%ld), imindBand=%d, ihitBand=%d, imaxdBand=%d, LSum=%d, RSum=%d\n", - movement, ptsmove->x, ptsmove->y, imindBand, ihitBand, - imaxdBand, LHeaderSum, RHeaderSum); - REBAR_DumpBand (infoPtr); - - if (movement < 0) { - - /* *** Drag left/up *** */ - compress = rcBlt(hitBand) - rcBlt(mindBand) - - LHeaderSum; - if (compress < abs(movement)) { - TRACE("limiting left drag, was %d changed to %d\n", - movement, -compress); - movement = -compress; - } - - for (i=ihitBand; i>=imindBand; i--) { - band = &infoPtr->bands[i]; - if (HIDDENBAND(band)) continue; - if (i == ihitBand) { - LEADJ(band, movement); - } - else - movement = REBAR_Shrink (infoPtr, band, movement, i); - band->ccx = rcBw(band); - } - } - else { - BOOL first = TRUE; - - /* *** Drag right/down *** */ - compress = rcBrb(maxdBand) - rcBlt(hitBand) - - RHeaderSum; - if (compress < abs(movement)) { - TRACE("limiting right drag, was %d changed to %d\n", - movement, compress); - movement = compress; - } - for (i=ihitBand-1; i<=imaxdBand; i++) { - band = &infoPtr->bands[i]; - if (HIDDENBAND(band)) continue; - if (first) { - first = FALSE; - READJ(band, movement); - } - else - movement = REBAR_Shrink (infoPtr, band, movement, i); - band->ccx = rcBw(band); - } - } - - /* recompute all rectangles */ - if (infoPtr->dwStyle & CCS_VERT) { - REBAR_CalcVertBand (infoPtr, imindBand, imaxdBand+1, - FALSE); - } - else { - REBAR_CalcHorzBand (infoPtr, imindBand, imaxdBand+1, - FALSE); - } - - TRACE("bands after adjustment, see band # %d, %d\n", - imindBand, imaxdBand); - REBAR_DumpBand (infoPtr); - - SetRect (&newrect, - mindBand->rcBand.left, - mindBand->rcBand.top, - maxdBand->rcBand.right, - maxdBand->rcBand.bottom); - - REBAR_MoveChildWindows (infoPtr, imindBand, imaxdBand+1); - - InvalidateRect (infoPtr->hwndSelf, &newrect, TRUE); - UpdateWindow (infoPtr->hwndSelf); - -} - - - -/* << REBAR_BeginDrag >> */ - - -static LRESULT -REBAR_DeleteBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - UINT uBand = (UINT)wParam; - HWND childhwnd = 0; - REBAR_BAND *lpBand; - - if (uBand >= infoPtr->uNumBands) - return FALSE; - - TRACE("deleting band %u!\n", uBand); - lpBand = &infoPtr->bands[uBand]; - REBAR_Notify_NMREBAR (infoPtr, uBand, RBN_DELETINGBAND); - - if (infoPtr->uNumBands == 1) { - TRACE(" simple delete!\n"); - if ((lpBand->fMask & RBBIM_CHILD) && lpBand->hwndChild) - childhwnd = lpBand->hwndChild; - Free (infoPtr->bands); - infoPtr->bands = NULL; - infoPtr->uNumBands = 0; - } - else { - REBAR_BAND *oldBands = infoPtr->bands; - TRACE("complex delete! [uBand=%u]\n", uBand); - - if ((lpBand->fMask & RBBIM_CHILD) && lpBand->hwndChild) - childhwnd = lpBand->hwndChild; - - infoPtr->uNumBands--; - infoPtr->bands = Alloc (sizeof (REBAR_BAND) * infoPtr->uNumBands); - if (uBand > 0) { - memcpy (&infoPtr->bands[0], &oldBands[0], - uBand * sizeof(REBAR_BAND)); - } - - if (uBand < infoPtr->uNumBands) { - memcpy (&infoPtr->bands[uBand], &oldBands[uBand+1], - (infoPtr->uNumBands - uBand) * sizeof(REBAR_BAND)); - } - - Free (oldBands); - } - - if (childhwnd) - ShowWindow (childhwnd, SW_HIDE); - - REBAR_Notify_NMREBAR (infoPtr, -1, RBN_DELETEDBAND); - - /* if only 1 band left the re-validate to possible eliminate gripper */ - if (infoPtr->uNumBands == 1) - REBAR_ValidateBand (infoPtr, &infoPtr->bands[0]); - - TRACE("setting NEEDS_LAYOUT\n"); - infoPtr->fStatus |= BAND_NEEDS_LAYOUT; - infoPtr->fStatus |= RESIZE_ANYHOW; - REBAR_Layout (infoPtr, NULL, TRUE, FALSE); - - return TRUE; -} - - -/* << REBAR_DragMove >> */ -/* << REBAR_EndDrag >> */ - - -static LRESULT -REBAR_GetBandBorders (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - LPRECT lpRect = (LPRECT)lParam; - REBAR_BAND *lpBand; - - if (!lParam) - return 0; - if ((UINT)wParam >= infoPtr->uNumBands) - return 0; - - lpBand = &infoPtr->bands[(UINT)wParam]; - - /* FIXME - the following values were determined by experimentation */ - /* with the REBAR Control Spy. I have guesses as to what the 4 and */ - /* 1 are, but I am not sure. There doesn't seem to be any actual */ - /* difference in size of the control area with and without the */ - /* style. - GA */ - if (infoPtr->dwStyle & RBS_BANDBORDERS) { - if (infoPtr->dwStyle & CCS_VERT) { - lpRect->left = 1; - lpRect->top = lpBand->cxHeader + 4; - lpRect->right = 1; - lpRect->bottom = 0; - } - else { - lpRect->left = lpBand->cxHeader + 4; - lpRect->top = 1; - lpRect->right = 0; - lpRect->bottom = 1; - } - } - else { - lpRect->left = lpBand->cxHeader; - } - return 0; -} - - -inline static LRESULT -REBAR_GetBandCount (REBAR_INFO *infoPtr) -{ - TRACE("band count %u!\n", infoPtr->uNumBands); - - return infoPtr->uNumBands; -} - - -static LRESULT -REBAR_GetBandInfoA (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - LPREBARBANDINFOA lprbbi = (LPREBARBANDINFOA)lParam; - REBAR_BAND *lpBand; - - if (lprbbi == NULL) - return FALSE; - if (lprbbi->cbSize < REBARBANDINFOA_V3_SIZE) - return FALSE; - if ((UINT)wParam >= infoPtr->uNumBands) - return FALSE; - - TRACE("index %u\n", (UINT)wParam); - - /* copy band information */ - lpBand = &infoPtr->bands[(UINT)wParam]; - - if (lprbbi->fMask & RBBIM_STYLE) - lprbbi->fStyle = lpBand->fStyle; - - if (lprbbi->fMask & RBBIM_COLORS) { - lprbbi->clrFore = lpBand->clrFore; - lprbbi->clrBack = lpBand->clrBack; - if (lprbbi->clrBack == CLR_DEFAULT) - lprbbi->clrBack = infoPtr->clrBtnFace; - } - - if ((lprbbi->fMask & RBBIM_TEXT) && (lprbbi->lpText)) { - if (lpBand->lpText && (lpBand->fMask & RBBIM_TEXT)) - { - if (!WideCharToMultiByte( CP_ACP, 0, lpBand->lpText, -1, - lprbbi->lpText, lprbbi->cch, NULL, NULL )) - lprbbi->lpText[lprbbi->cch-1] = 0; - } - else - *lprbbi->lpText = 0; - } - - if (lprbbi->fMask & RBBIM_IMAGE) { - if (lpBand->fMask & RBBIM_IMAGE) - lprbbi->iImage = lpBand->iImage; - else - lprbbi->iImage = -1; - } - - if (lprbbi->fMask & RBBIM_CHILD) - lprbbi->hwndChild = lpBand->hwndChild; - - if (lprbbi->fMask & RBBIM_CHILDSIZE) { - lprbbi->cxMinChild = lpBand->cxMinChild; - lprbbi->cyMinChild = lpBand->cyMinChild; - if (lprbbi->cbSize >= sizeof (REBARBANDINFOA)) { - lprbbi->cyChild = lpBand->cyChild; - lprbbi->cyMaxChild = lpBand->cyMaxChild; - lprbbi->cyIntegral = lpBand->cyIntegral; - } - } - - if (lprbbi->fMask & RBBIM_SIZE) - lprbbi->cx = lpBand->cx; - - if (lprbbi->fMask & RBBIM_BACKGROUND) - lprbbi->hbmBack = lpBand->hbmBack; - - if (lprbbi->fMask & RBBIM_ID) - lprbbi->wID = lpBand->wID; - - /* check for additional data */ - if (lprbbi->cbSize >= sizeof (REBARBANDINFOA)) { - if (lprbbi->fMask & RBBIM_IDEALSIZE) - lprbbi->cxIdeal = lpBand->cxIdeal; - - if (lprbbi->fMask & RBBIM_LPARAM) - lprbbi->lParam = lpBand->lParam; - - if (lprbbi->fMask & RBBIM_HEADERSIZE) - lprbbi->cxHeader = lpBand->cxHeader; - } - - REBAR_DumpBandInfo (lprbbi); - - return TRUE; -} - - -static LRESULT -REBAR_GetBandInfoW (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - LPREBARBANDINFOW lprbbi = (LPREBARBANDINFOW)lParam; - REBAR_BAND *lpBand; - - if (lprbbi == NULL) - return FALSE; - if (lprbbi->cbSize < REBARBANDINFOW_V3_SIZE) - return FALSE; - if ((UINT)wParam >= infoPtr->uNumBands) - return FALSE; - - TRACE("index %u\n", (UINT)wParam); - - /* copy band information */ - lpBand = &infoPtr->bands[(UINT)wParam]; - - if (lprbbi->fMask & RBBIM_STYLE) - lprbbi->fStyle = lpBand->fStyle; - - if (lprbbi->fMask & RBBIM_COLORS) { - lprbbi->clrFore = lpBand->clrFore; - lprbbi->clrBack = lpBand->clrBack; - if (lprbbi->clrBack == CLR_DEFAULT) - lprbbi->clrBack = infoPtr->clrBtnFace; - } - - if ((lprbbi->fMask & RBBIM_TEXT) && (lprbbi->lpText)) { - if (lpBand->lpText && (lpBand->fMask & RBBIM_TEXT)) - lstrcpynW (lprbbi->lpText, lpBand->lpText, lprbbi->cch); - else - *lprbbi->lpText = 0; - } - - if (lprbbi->fMask & RBBIM_IMAGE) { - if (lpBand->fMask & RBBIM_IMAGE) - lprbbi->iImage = lpBand->iImage; - else - lprbbi->iImage = -1; - } - - if (lprbbi->fMask & RBBIM_CHILD) - lprbbi->hwndChild = lpBand->hwndChild; - - if (lprbbi->fMask & RBBIM_CHILDSIZE) { - lprbbi->cxMinChild = lpBand->cxMinChild; - lprbbi->cyMinChild = lpBand->cyMinChild; - if (lprbbi->cbSize >= sizeof (REBARBANDINFOW)) { - lprbbi->cyChild = lpBand->cyChild; - lprbbi->cyMaxChild = lpBand->cyMaxChild; - lprbbi->cyIntegral = lpBand->cyIntegral; - } - } - - if (lprbbi->fMask & RBBIM_SIZE) - lprbbi->cx = lpBand->cx; - - if (lprbbi->fMask & RBBIM_BACKGROUND) - lprbbi->hbmBack = lpBand->hbmBack; - - if (lprbbi->fMask & RBBIM_ID) - lprbbi->wID = lpBand->wID; - - /* check for additional data */ - if (lprbbi->cbSize >= sizeof (REBARBANDINFOW)) { - if (lprbbi->fMask & RBBIM_IDEALSIZE) - lprbbi->cxIdeal = lpBand->cxIdeal; - - if (lprbbi->fMask & RBBIM_LPARAM) - lprbbi->lParam = lpBand->lParam; - - if (lprbbi->fMask & RBBIM_HEADERSIZE) - lprbbi->cxHeader = lpBand->cxHeader; - } - - REBAR_DumpBandInfo ((LPREBARBANDINFOA)lprbbi); - - return TRUE; -} - - -static LRESULT -REBAR_GetBarHeight (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - INT nHeight; - - nHeight = (infoPtr->dwStyle & CCS_VERT) ? infoPtr->calcSize.cx : infoPtr->calcSize.cy; - - TRACE("height = %d\n", nHeight); - - return nHeight; -} - - -static LRESULT -REBAR_GetBarInfo (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - LPREBARINFO lpInfo = (LPREBARINFO)lParam; - - if (lpInfo == NULL) - return FALSE; - - if (lpInfo->cbSize < sizeof (REBARINFO)) - return FALSE; - - TRACE("getting bar info!\n"); - - if (infoPtr->himl) { - lpInfo->himl = infoPtr->himl; - lpInfo->fMask |= RBIM_IMAGELIST; - } - - return TRUE; -} - - -inline static LRESULT -REBAR_GetBkColor (REBAR_INFO *infoPtr) -{ - COLORREF clr = infoPtr->clrBk; - - if (clr == CLR_DEFAULT) - clr = infoPtr->clrBtnFace; - - TRACE("background color 0x%06lx!\n", clr); - - return clr; -} - - -/* << REBAR_GetColorScheme >> */ -/* << REBAR_GetDropTarget >> */ - - -static LRESULT -REBAR_GetPalette (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - FIXME("empty stub!\n"); - - return 0; -} - - -static LRESULT -REBAR_GetRect (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - INT iBand = (INT)wParam; - LPRECT lprc = (LPRECT)lParam; - REBAR_BAND *lpBand; - - if ((iBand < 0) && ((UINT)iBand >= infoPtr->uNumBands)) - return FALSE; - if (!lprc) - return FALSE; - - lpBand = &infoPtr->bands[iBand]; - CopyRect (lprc, &lpBand->rcBand); - - TRACE("band %d, (%ld,%ld)-(%ld,%ld)\n", iBand, - lprc->left, lprc->top, lprc->right, lprc->bottom); - - return TRUE; -} - - -inline static LRESULT -REBAR_GetRowCount (REBAR_INFO *infoPtr) -{ - TRACE("%u\n", infoPtr->uNumRows); - - return infoPtr->uNumRows; -} - - -static LRESULT -REBAR_GetRowHeight (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - INT iRow = (INT)wParam; - int j = 0, ret = 0; - UINT i; - REBAR_BAND *lpBand; - - for (i=0; iuNumBands; i++) { - lpBand = &infoPtr->bands[i]; - if (HIDDENBAND(lpBand)) continue; - if (lpBand->iRow != iRow) continue; - if (infoPtr->dwStyle & CCS_VERT) - j = lpBand->rcBand.right - lpBand->rcBand.left; - else - j = lpBand->rcBand.bottom - lpBand->rcBand.top; - if (j > ret) ret = j; - } - - TRACE("row %d, height %d\n", iRow, ret); - - return ret; -} - - -inline static LRESULT -REBAR_GetTextColor (REBAR_INFO *infoPtr) -{ - TRACE("text color 0x%06lx!\n", infoPtr->clrText); - - return infoPtr->clrText; -} - - -inline static LRESULT -REBAR_GetToolTips (REBAR_INFO *infoPtr) -{ - return (LRESULT)infoPtr->hwndToolTip; -} - - -inline static LRESULT -REBAR_GetUnicodeFormat (REBAR_INFO *infoPtr) -{ - TRACE("%s hwnd=%p\n", - infoPtr->bUnicode ? "TRUE" : "FALSE", infoPtr->hwndSelf); - - return infoPtr->bUnicode; -} - - -inline static LRESULT -REBAR_GetVersion (REBAR_INFO *infoPtr) -{ - TRACE("version %d\n", infoPtr->iVersion); - return infoPtr->iVersion; -} - - -static LRESULT -REBAR_HitTest (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - LPRBHITTESTINFO lprbht = (LPRBHITTESTINFO)lParam; - - if (!lprbht) - return -1; - - REBAR_InternalHitTest (infoPtr, &lprbht->pt, &lprbht->flags, &lprbht->iBand); - - return lprbht->iBand; -} - - -static LRESULT -REBAR_IdToIndex (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - UINT i; - - if (infoPtr == NULL) - return -1; - - if (infoPtr->uNumBands < 1) - return -1; - - for (i = 0; i < infoPtr->uNumBands; i++) { - if (infoPtr->bands[i].wID == (UINT)wParam) { - TRACE("id %u is band %u found!\n", (UINT)wParam, i); - return i; - } - } - - TRACE("id %u is not found\n", (UINT)wParam); - return -1; -} - - -static LRESULT -REBAR_InsertBandA (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - LPREBARBANDINFOA lprbbi = (LPREBARBANDINFOA)lParam; - UINT uIndex = (UINT)wParam; - REBAR_BAND *lpBand; - - if (infoPtr == NULL) - return FALSE; - if (lprbbi == NULL) - return FALSE; - if (lprbbi->cbSize < REBARBANDINFOA_V3_SIZE) - return FALSE; - - /* trace the index as signed to see the -1 */ - TRACE("insert band at %d!\n", (INT)uIndex); - REBAR_DumpBandInfo (lprbbi); - - if (infoPtr->uNumBands == 0) { - infoPtr->bands = (REBAR_BAND *)Alloc (sizeof (REBAR_BAND)); - uIndex = 0; - } - else { - REBAR_BAND *oldBands = infoPtr->bands; - infoPtr->bands = - (REBAR_BAND *)Alloc ((infoPtr->uNumBands+1)*sizeof(REBAR_BAND)); - if (((INT)uIndex == -1) || (uIndex > infoPtr->uNumBands)) - uIndex = infoPtr->uNumBands; - - /* pre insert copy */ - if (uIndex > 0) { - memcpy (&infoPtr->bands[0], &oldBands[0], - uIndex * sizeof(REBAR_BAND)); - } - - /* post copy */ - if (uIndex < infoPtr->uNumBands) { - memcpy (&infoPtr->bands[uIndex+1], &oldBands[uIndex], - (infoPtr->uNumBands - uIndex) * sizeof(REBAR_BAND)); - } - - Free (oldBands); - } - - infoPtr->uNumBands++; - - TRACE("index %u!\n", uIndex); - - /* initialize band (infoPtr->bands[uIndex])*/ - lpBand = &infoPtr->bands[uIndex]; - lpBand->fMask = 0; - lpBand->fStatus = 0; - lpBand->clrFore = infoPtr->clrText; - lpBand->clrBack = infoPtr->clrBk; - lpBand->hwndChild = 0; - lpBand->hwndPrevParent = 0; - - REBAR_CommonSetupBand (infoPtr->hwndSelf, lprbbi, lpBand); - lpBand->lpText = NULL; - if ((lprbbi->fMask & RBBIM_TEXT) && (lprbbi->lpText)) { - INT len = MultiByteToWideChar( CP_ACP, 0, lprbbi->lpText, -1, NULL, 0 ); - if (len > 1) { - lpBand->lpText = (LPWSTR)Alloc (len*sizeof(WCHAR)); - MultiByteToWideChar( CP_ACP, 0, lprbbi->lpText, -1, lpBand->lpText, len ); - } - } - - REBAR_ValidateBand (infoPtr, lpBand); - /* On insert of second band, revalidate band 1 to possible add gripper */ - if (infoPtr->uNumBands == 2) - REBAR_ValidateBand (infoPtr, &infoPtr->bands[0]); - - REBAR_DumpBand (infoPtr); - - REBAR_Layout (infoPtr, NULL, TRUE, FALSE); - InvalidateRect(infoPtr->hwndSelf, 0, 1); - - return TRUE; -} - - -static LRESULT -REBAR_InsertBandW (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - LPREBARBANDINFOW lprbbi = (LPREBARBANDINFOW)lParam; - UINT uIndex = (UINT)wParam; - REBAR_BAND *lpBand; - - if (infoPtr == NULL) - return FALSE; - if (lprbbi == NULL) - return FALSE; - if (lprbbi->cbSize < REBARBANDINFOW_V3_SIZE) - return FALSE; - - /* trace the index as signed to see the -1 */ - TRACE("insert band at %d!\n", (INT)uIndex); - REBAR_DumpBandInfo ((LPREBARBANDINFOA)lprbbi); - - if (infoPtr->uNumBands == 0) { - infoPtr->bands = (REBAR_BAND *)Alloc (sizeof (REBAR_BAND)); - uIndex = 0; - } - else { - REBAR_BAND *oldBands = infoPtr->bands; - infoPtr->bands = - (REBAR_BAND *)Alloc ((infoPtr->uNumBands+1)*sizeof(REBAR_BAND)); - if (((INT)uIndex == -1) || (uIndex > infoPtr->uNumBands)) - uIndex = infoPtr->uNumBands; - - /* pre insert copy */ - if (uIndex > 0) { - memcpy (&infoPtr->bands[0], &oldBands[0], - uIndex * sizeof(REBAR_BAND)); - } - - /* post copy */ - if (uIndex <= infoPtr->uNumBands - 1) { - memcpy (&infoPtr->bands[uIndex+1], &oldBands[uIndex], - (infoPtr->uNumBands - uIndex) * sizeof(REBAR_BAND)); - } - - Free (oldBands); - } - - infoPtr->uNumBands++; - - TRACE("index %u!\n", uIndex); - - /* initialize band (infoPtr->bands[uIndex])*/ - lpBand = &infoPtr->bands[uIndex]; - lpBand->fMask = 0; - lpBand->fStatus = 0; - lpBand->clrFore = infoPtr->clrText; - lpBand->clrBack = infoPtr->clrBk; - lpBand->hwndChild = 0; - lpBand->hwndPrevParent = 0; - - REBAR_CommonSetupBand (infoPtr->hwndSelf, (LPREBARBANDINFOA)lprbbi, lpBand); - lpBand->lpText = NULL; - if ((lprbbi->fMask & RBBIM_TEXT) && (lprbbi->lpText)) { - INT len = lstrlenW (lprbbi->lpText); - if (len > 0) { - lpBand->lpText = (LPWSTR)Alloc ((len + 1)*sizeof(WCHAR)); - strcpyW (lpBand->lpText, lprbbi->lpText); - } - } - - REBAR_ValidateBand (infoPtr, lpBand); - /* On insert of second band, revalidate band 1 to possible add gripper */ - if (infoPtr->uNumBands == 2) - REBAR_ValidateBand (infoPtr, &infoPtr->bands[uIndex ? 0 : 1]); - - REBAR_DumpBand (infoPtr); - - REBAR_Layout (infoPtr, NULL, TRUE, FALSE); - InvalidateRect(infoPtr->hwndSelf, 0, 1); - - return TRUE; -} - - -static LRESULT -REBAR_MaximizeBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - REBAR_BAND *lpBand; - UINT uBand = (UINT) wParam; - - /* Validate */ - if ((infoPtr->uNumBands == 0) || - ((INT)uBand < 0) || (uBand >= infoPtr->uNumBands)) { - /* error !!! */ - ERR("Illegal MaximizeBand, requested=%d, current band count=%d\n", - (INT)uBand, infoPtr->uNumBands); - return FALSE; - } - - lpBand = &infoPtr->bands[uBand]; - - if (lParam && (lpBand->fMask & RBBIM_IDEALSIZE)) { - /* handle setting ideal size */ - lpBand->ccx = lpBand->cxIdeal; - } - else { - /* handle setting to max */ - FIXME("(uBand = %u fIdeal = %s) case not coded\n", - (UINT)wParam, lParam ? "TRUE" : "FALSE"); - return FALSE; - } - - infoPtr->fStatus |= BAND_NEEDS_LAYOUT; - REBAR_Layout (infoPtr, 0, TRUE, TRUE); - InvalidateRect (infoPtr->hwndSelf, 0, TRUE); - - return TRUE; - -} - - -static LRESULT -REBAR_MinimizeBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - REBAR_BAND *band, *lpBand; - UINT uBand = (UINT) wParam; - RECT newrect; - INT imindBand, imaxdBand, iprevBand, startBand, endBand; - INT movement, i; - - /* A "minimize" band is equivalent to "dragging" the gripper - * of than band to the right till the band is only the size - * of the cxHeader. - */ - - /* Validate */ - if ((infoPtr->uNumBands == 0) || - ((INT)uBand < 0) || (uBand >= infoPtr->uNumBands)) { - /* error !!! */ - ERR("Illegal MinimizeBand, requested=%d, current band count=%d\n", - (INT)uBand, infoPtr->uNumBands); - return FALSE; - } - - /* compute amount of movement and validate */ - lpBand = &infoPtr->bands[uBand]; - - if (infoPtr->dwStyle & CCS_VERT) - movement = lpBand->rcBand.bottom - lpBand->rcBand.top - - lpBand->cxHeader; - else - movement = lpBand->rcBand.right - lpBand->rcBand.left - - lpBand->cxHeader; - if (movement < 0) { - ERR("something is wrong, band=(%ld,%ld)-(%ld,%ld), cxheader=%d\n", - lpBand->rcBand.left, lpBand->rcBand.top, - lpBand->rcBand.right, lpBand->rcBand.bottom, - lpBand->cxHeader); - return FALSE; - } - - imindBand = -1; - imaxdBand = -1; - iprevBand = -1; /* to suppress warning message */ - - /* find the first band in row of the one whose is being minimized */ - for (i=0; iuNumBands; i++) { - band = &infoPtr->bands[i]; - if (HIDDENBAND(band)) continue; - if (band->iRow == lpBand->iRow) { - imaxdBand = i; - if (imindBand == -1) imindBand = i; - } - } - - /* if the selected band is first in row then need to expand */ - /* next visible band */ - if (imindBand == uBand) { - band = NULL; - movement = -movement; - /* find the first visible band to the right of the selected band */ - for (i=uBand+1; i<=imaxdBand; i++) { - band = &infoPtr->bands[i]; - if (!HIDDENBAND(band)) { - iprevBand = i; - LEADJ(band, movement); - band->ccx = rcBw(band); - break; - } - } - /* what case is this */ - if (iprevBand == -1) { - ERR("no previous visible band\n"); - return FALSE; - } - startBand = uBand; - endBand = iprevBand; - SetRect (&newrect, - lpBand->rcBand.left, - lpBand->rcBand.top, - band->rcBand.right, - band->rcBand.bottom); - } - /* otherwise expand previous visible band */ - else { - band = NULL; - /* find the first visible band to the left of the selected band */ - for (i=uBand-1; i>=imindBand; i--) { - band = &infoPtr->bands[i]; - if (!HIDDENBAND(band)) { - iprevBand = i; - READJ(band, movement); - band->ccx = rcBw(band); - break; - } - } - /* what case is this */ - if (iprevBand == -1) { - ERR("no previous visible band\n"); - return FALSE; - } - startBand = iprevBand; - endBand = uBand; - SetRect (&newrect, - band->rcBand.left, - band->rcBand.top, - lpBand->rcBand.right, - lpBand->rcBand.bottom); - } - - REBAR_Shrink (infoPtr, lpBand, movement, uBand); - - /* recompute all rectangles */ - if (infoPtr->dwStyle & CCS_VERT) { - REBAR_CalcVertBand (infoPtr, startBand, endBand+1, - FALSE); - } - else { - REBAR_CalcHorzBand (infoPtr, startBand, endBand+1, - FALSE); - } - - TRACE("bands after minimize, see band # %d, %d\n", - startBand, endBand); - REBAR_DumpBand (infoPtr); - - REBAR_MoveChildWindows (infoPtr, startBand, endBand+1); - - InvalidateRect (infoPtr->hwndSelf, &newrect, TRUE); - UpdateWindow (infoPtr->hwndSelf); - return FALSE; -} - - -static LRESULT -REBAR_MoveBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - REBAR_BAND *oldBands = infoPtr->bands; - REBAR_BAND holder; - UINT uFrom = (UINT)wParam; - UINT uTo = (UINT)lParam; - - /* Validate */ - if ((infoPtr->uNumBands == 0) || - ((INT)uFrom < 0) || (uFrom >= infoPtr->uNumBands) || - ((INT)uTo < 0) || (uTo >= infoPtr->uNumBands)) { - /* error !!! */ - ERR("Illegal MoveBand, from=%d, to=%d, current band count=%d\n", - (INT)uFrom, (INT)uTo, infoPtr->uNumBands); - return FALSE; - } - - /* save one to be moved */ - memcpy (&holder, &oldBands[uFrom], sizeof(REBAR_BAND)); - - /* close up rest of bands (pseudo delete) */ - if (uFrom < infoPtr->uNumBands - 1) { - memcpy (&oldBands[uFrom], &oldBands[uFrom+1], - (infoPtr->uNumBands - uFrom - 1) * sizeof(REBAR_BAND)); - } - - /* allocate new space and copy rest of bands into it */ - infoPtr->bands = - (REBAR_BAND *)Alloc ((infoPtr->uNumBands)*sizeof(REBAR_BAND)); - - /* pre insert copy */ - if (uTo > 0) { - memcpy (&infoPtr->bands[0], &oldBands[0], - uTo * sizeof(REBAR_BAND)); - } - - /* set moved band */ - memcpy (&infoPtr->bands[uTo], &holder, sizeof(REBAR_BAND)); - - /* post copy */ - if (uTo < infoPtr->uNumBands - 1) { - memcpy (&infoPtr->bands[uTo+1], &oldBands[uTo], - (infoPtr->uNumBands - uTo - 1) * sizeof(REBAR_BAND)); - } - - Free (oldBands); - - TRACE("moved band %d to index %d\n", uFrom, uTo); - REBAR_DumpBand (infoPtr); - - infoPtr->fStatus |= BAND_NEEDS_LAYOUT; - /* **************************************************** */ - /* */ - /* We do not do a REBAR_Layout here because the native */ - /* control does not do that. The actual layout and */ - /* repaint is done by the *next* real action, ex.: */ - /* RB_INSERTBAND, RB_DELETEBAND, RB_SIZETORECT, etc. */ - /* */ - /* **************************************************** */ - - return TRUE; -} - - -/* return TRUE if two strings are different */ -static BOOL -REBAR_strdifW( LPCWSTR a, LPCWSTR b ) -{ - return ( (a && !b) || (b && !a) || (a && b && lstrcmpW(a, b) ) ); -} - -static LRESULT -REBAR_SetBandInfoA (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - LPREBARBANDINFOA lprbbi = (LPREBARBANDINFOA)lParam; - REBAR_BAND *lpBand; - BOOL bChanged; - - if (lprbbi == NULL) - return FALSE; - if (lprbbi->cbSize < REBARBANDINFOA_V3_SIZE) - return FALSE; - if ((UINT)wParam >= infoPtr->uNumBands) - return FALSE; - - TRACE("index %u\n", (UINT)wParam); - REBAR_DumpBandInfo (lprbbi); - - /* set band information */ - lpBand = &infoPtr->bands[(UINT)wParam]; - - bChanged = REBAR_CommonSetupBand (infoPtr->hwndSelf, lprbbi, lpBand); - if (lprbbi->fMask & RBBIM_TEXT) { - LPWSTR wstr = NULL; - - if (lprbbi->lpText) - { - INT len; - len = MultiByteToWideChar( CP_ACP, 0, lprbbi->lpText, -1, NULL, 0 ); - if (len > 1) - wstr = (LPWSTR)Alloc (len*sizeof(WCHAR)); - if (wstr) - MultiByteToWideChar( CP_ACP, 0, lprbbi->lpText, -1, wstr, len ); - } - if (REBAR_strdifW(lpBand->lpText, wstr)) { - if (lpBand->lpText) { - Free (lpBand->lpText); - lpBand->lpText = NULL; - } - if (wstr) { - lpBand->lpText = wstr; - wstr = NULL; - } - bChanged = TRUE; - } - if (wstr) - Free (wstr); - } - - REBAR_ValidateBand (infoPtr, lpBand); - - REBAR_DumpBand (infoPtr); - - if (bChanged && (lprbbi->fMask & (RBBIM_CHILDSIZE | RBBIM_SIZE))) { - REBAR_Layout (infoPtr, NULL, TRUE, FALSE); - InvalidateRect(infoPtr->hwndSelf, 0, 1); - } - - return TRUE; -} - -static LRESULT -REBAR_SetBandInfoW (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - LPREBARBANDINFOW lprbbi = (LPREBARBANDINFOW)lParam; - REBAR_BAND *lpBand; - BOOL bChanged; - - if (lprbbi == NULL) - return FALSE; - if (lprbbi->cbSize < REBARBANDINFOW_V3_SIZE) - return FALSE; - if ((UINT)wParam >= infoPtr->uNumBands) - return FALSE; - - TRACE("index %u\n", (UINT)wParam); - REBAR_DumpBandInfo ((LPREBARBANDINFOA)lprbbi); - - /* set band information */ - lpBand = &infoPtr->bands[(UINT)wParam]; - - bChanged = REBAR_CommonSetupBand (infoPtr->hwndSelf, (LPREBARBANDINFOA)lprbbi, lpBand); - if( (lprbbi->fMask & RBBIM_TEXT) && - REBAR_strdifW( lpBand->lpText, lprbbi->lpText ) ) { - if (lpBand->lpText) { - Free (lpBand->lpText); - lpBand->lpText = NULL; - } - if (lprbbi->lpText) { - INT len = lstrlenW (lprbbi->lpText); - if (len > 0) - { - lpBand->lpText = (LPWSTR)Alloc ((len + 1)*sizeof(WCHAR)); - strcpyW (lpBand->lpText, lprbbi->lpText); - } - } - bChanged = TRUE; - } - - REBAR_ValidateBand (infoPtr, lpBand); - - REBAR_DumpBand (infoPtr); - - if ( bChanged && (lprbbi->fMask & (RBBIM_CHILDSIZE | RBBIM_SIZE)) ) { - REBAR_Layout (infoPtr, NULL, TRUE, FALSE); - InvalidateRect(infoPtr->hwndSelf, 0, 1); - } - - return TRUE; -} - - -static LRESULT -REBAR_SetBarInfo (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - LPREBARINFO lpInfo = (LPREBARINFO)lParam; - REBAR_BAND *lpBand; - UINT i; - - if (lpInfo == NULL) - return FALSE; - - if (lpInfo->cbSize < sizeof (REBARINFO)) - return FALSE; - - TRACE("setting bar info!\n"); - - if (lpInfo->fMask & RBIM_IMAGELIST) { - infoPtr->himl = lpInfo->himl; - if (infoPtr->himl) { - INT cx, cy; - ImageList_GetIconSize (infoPtr->himl, &cx, &cy); - infoPtr->imageSize.cx = cx; - infoPtr->imageSize.cy = cy; - } - else { - infoPtr->imageSize.cx = 0; - infoPtr->imageSize.cy = 0; - } - TRACE("new image cx=%ld, cy=%ld\n", infoPtr->imageSize.cx, - infoPtr->imageSize.cy); - } - - /* revalidate all bands to reset flags for images in headers of bands */ - for (i=0; iuNumBands; i++) { - lpBand = &infoPtr->bands[i]; - REBAR_ValidateBand (infoPtr, lpBand); - } - - return TRUE; -} - - -static LRESULT -REBAR_SetBkColor (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - COLORREF clrTemp; - - clrTemp = infoPtr->clrBk; - infoPtr->clrBk = (COLORREF)lParam; - - TRACE("background color 0x%06lx!\n", infoPtr->clrBk); - - return clrTemp; -} - - -/* << REBAR_SetColorScheme >> */ -/* << REBAR_SetPalette >> */ - - -static LRESULT -REBAR_SetParent (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - HWND hwndTemp = infoPtr->hwndNotify; - - infoPtr->hwndNotify = (HWND)wParam; - - return (LRESULT)hwndTemp; -} - - -static LRESULT -REBAR_SetTextColor (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - COLORREF clrTemp; - - clrTemp = infoPtr->clrText; - infoPtr->clrText = (COLORREF)lParam; - - TRACE("text color 0x%06lx!\n", infoPtr->clrText); - - return clrTemp; -} - - -/* << REBAR_SetTooltips >> */ - - -inline static LRESULT -REBAR_SetUnicodeFormat (REBAR_INFO *infoPtr, WPARAM wParam) -{ - BOOL bTemp = infoPtr->bUnicode; - - TRACE("to %s hwnd=%p, was %s\n", - ((BOOL)wParam) ? "TRUE" : "FALSE", infoPtr->hwndSelf, - (bTemp) ? "TRUE" : "FALSE"); - - infoPtr->bUnicode = (BOOL)wParam; - - return bTemp; -} - - -static LRESULT -REBAR_SetVersion (REBAR_INFO *infoPtr, INT iVersion) -{ - INT iOldVersion = infoPtr->iVersion; - - if (iVersion > COMCTL32_VERSION) - return -1; - - infoPtr->iVersion = iVersion; - - TRACE("new version %d\n", iVersion); - - return iOldVersion; -} - - -static LRESULT -REBAR_ShowBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - REBAR_BAND *lpBand; - - if (((INT)wParam < 0) || ((INT)wParam > infoPtr->uNumBands)) - return FALSE; - - lpBand = &infoPtr->bands[(INT)wParam]; - - if ((BOOL)lParam) { - TRACE("show band %d\n", (INT)wParam); - lpBand->fStyle = lpBand->fStyle & ~RBBS_HIDDEN; - if (IsWindow (lpBand->hwndChild)) - ShowWindow (lpBand->hwndChild, SW_SHOW); - } - else { - TRACE("hide band %d\n", (INT)wParam); - lpBand->fStyle = lpBand->fStyle | RBBS_HIDDEN; - if (IsWindow (lpBand->hwndChild)) - ShowWindow (lpBand->hwndChild, SW_HIDE); - } - - infoPtr->fStatus |= BAND_NEEDS_LAYOUT; - REBAR_Layout (infoPtr, NULL, TRUE, FALSE); - InvalidateRect(infoPtr->hwndSelf, 0, 1); - - return TRUE; -} - - -static LRESULT -REBAR_SizeToRect (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - LPRECT lpRect = (LPRECT)lParam; - RECT t1; - - if (lpRect == NULL) - return FALSE; - - TRACE("[%ld %ld %ld %ld]\n", - lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); - - /* what is going on???? */ - GetWindowRect(infoPtr->hwndSelf, &t1); - TRACE("window rect [%ld %ld %ld %ld]\n", - t1.left, t1.top, t1.right, t1.bottom); - GetClientRect(infoPtr->hwndSelf, &t1); - TRACE("client rect [%ld %ld %ld %ld]\n", - t1.left, t1.top, t1.right, t1.bottom); - - /* force full _Layout processing */ - TRACE("setting NEEDS_LAYOUT\n"); - infoPtr->fStatus |= BAND_NEEDS_LAYOUT; - REBAR_Layout (infoPtr, lpRect, TRUE, FALSE); - InvalidateRect (infoPtr->hwndSelf, NULL, TRUE); - return TRUE; -} - - - -static LRESULT -REBAR_Create (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - LPCREATESTRUCTW cs = (LPCREATESTRUCTW) lParam; - RECT wnrc1, clrc1; - - if (TRACE_ON(rebar)) { - GetWindowRect(infoPtr->hwndSelf, &wnrc1); - GetClientRect(infoPtr->hwndSelf, &clrc1); - TRACE("window=(%ld,%ld)-(%ld,%ld) client=(%ld,%ld)-(%ld,%ld) cs=(%d,%d %dx%d)\n", - wnrc1.left, wnrc1.top, wnrc1.right, wnrc1.bottom, - clrc1.left, clrc1.top, clrc1.right, clrc1.bottom, - cs->x, cs->y, cs->cx, cs->cy); - } - - TRACE("created!\n"); - return 0; -} - - -static LRESULT -REBAR_Destroy (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - REBAR_BAND *lpBand; - UINT i; - - - /* free rebar bands */ - if ((infoPtr->uNumBands > 0) && infoPtr->bands) { - /* clean up each band */ - for (i = 0; i < infoPtr->uNumBands; i++) { - lpBand = &infoPtr->bands[i]; - - /* delete text strings */ - if (lpBand->lpText) { - Free (lpBand->lpText); - lpBand->lpText = NULL; - } - /* destroy child window */ - DestroyWindow (lpBand->hwndChild); - } - - /* free band array */ - Free (infoPtr->bands); - infoPtr->bands = NULL; - } - - DestroyCursor (infoPtr->hcurArrow); - DestroyCursor (infoPtr->hcurHorz); - DestroyCursor (infoPtr->hcurVert); - DestroyCursor (infoPtr->hcurDrag); - if(infoPtr->hDefaultFont) DeleteObject (infoPtr->hDefaultFont); - SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0); - - /* free rebar info data */ - Free (infoPtr); - TRACE("destroyed!\n"); - return 0; -} - - -static LRESULT -REBAR_EraseBkGnd (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - RECT cliprect; - - if (GetClipBox ( (HDC)wParam, &cliprect)) - return REBAR_InternalEraseBkGnd (infoPtr, wParam, lParam, &cliprect); - return 0; -} - - -static LRESULT -REBAR_GetFont (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - return (LRESULT)infoPtr->hFont; -} - -static LRESULT -REBAR_PushChevron(REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - if (wParam >= 0 && (UINT)wParam < infoPtr->uNumBands) - { - NMREBARCHEVRON nmrbc; - REBAR_BAND *lpBand = &infoPtr->bands[wParam]; - - TRACE("Pressed chevron on band %d\n", wParam); - - /* redraw chevron in pushed state */ - lpBand->fDraw |= DRAW_CHEVRONPUSHED; - RedrawWindow(infoPtr->hwndSelf, &lpBand->rcChevron,0, - RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW); - - /* notify app so it can display a popup menu or whatever */ - nmrbc.uBand = wParam; - nmrbc.wID = lpBand->wID; - nmrbc.lParam = lpBand->lParam; - nmrbc.rc = lpBand->rcChevron; - nmrbc.lParamNM = lParam; - REBAR_Notify((NMHDR*)&nmrbc, infoPtr, RBN_CHEVRONPUSHED); - - /* redraw chevron in previous state */ - lpBand->fDraw &= ~DRAW_CHEVRONPUSHED; - InvalidateRect(infoPtr->hwndSelf, &lpBand->rcChevron, TRUE); - - return TRUE; - } - return FALSE; -} - -static LRESULT -REBAR_LButtonDown (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - REBAR_BAND *lpBand; - UINT htFlags; - UINT iHitBand; - POINT ptMouseDown; - ptMouseDown.x = (INT)LOWORD(lParam); - ptMouseDown.y = (INT)HIWORD(lParam); - - REBAR_InternalHitTest(infoPtr, &ptMouseDown, &htFlags, &iHitBand); - lpBand = &infoPtr->bands[iHitBand]; - - if (htFlags == RBHT_CHEVRON) - { - REBAR_PushChevron(infoPtr, iHitBand, 0); - } - else if (htFlags == RBHT_GRABBER || htFlags == RBHT_CAPTION) - { - TRACE("Starting drag\n"); - - SetCapture (infoPtr->hwndSelf); - infoPtr->iGrabbedBand = iHitBand; - - /* save off the LOWORD and HIWORD of lParam as initial x,y */ - infoPtr->dragStart.x = (short)LOWORD(lParam); - infoPtr->dragStart.y = (short)HIWORD(lParam); - infoPtr->dragNow = infoPtr->dragStart; - if (infoPtr->dwStyle & CCS_VERT) - infoPtr->ihitoffset = infoPtr->dragStart.y - (lpBand->rcBand.top+REBAR_PRE_GRIPPER); - else - infoPtr->ihitoffset = infoPtr->dragStart.x - (lpBand->rcBand.left+REBAR_PRE_GRIPPER); - } - return 0; -} - -static LRESULT -REBAR_LButtonUp (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - if (infoPtr->iGrabbedBand >= 0) - { - NMHDR layout; - RECT rect; - - infoPtr->dragStart.x = 0; - infoPtr->dragStart.y = 0; - infoPtr->dragNow = infoPtr->dragStart; - - ReleaseCapture (); - - if (infoPtr->fStatus & BEGIN_DRAG_ISSUED) { - REBAR_Notify(&layout, infoPtr, RBN_LAYOUTCHANGED); - REBAR_Notify_NMREBAR (infoPtr, infoPtr->iGrabbedBand, RBN_ENDDRAG); - infoPtr->fStatus &= ~BEGIN_DRAG_ISSUED; - } - - infoPtr->iGrabbedBand = -1; - - GetClientRect(infoPtr->hwndSelf, &rect); - InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); - } - - return 0; -} - -static LRESULT -REBAR_MouseLeave (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - if (infoPtr->ichevronhotBand >= 0) - { - REBAR_BAND *lpChevronBand = &infoPtr->bands[infoPtr->ichevronhotBand]; - if (lpChevronBand->fDraw & DRAW_CHEVRONHOT) - { - lpChevronBand->fDraw &= ~DRAW_CHEVRONHOT; - InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE); - } - } - infoPtr->iOldBand = -1; - infoPtr->ichevronhotBand = -2; - - return TRUE; -} - -static LRESULT -REBAR_MouseMove (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - REBAR_BAND *lpChevronBand; - POINT ptMove; - - ptMove.x = (short)LOWORD(lParam); - ptMove.y = (short)HIWORD(lParam); - - /* if we are currently dragging a band */ - if (infoPtr->iGrabbedBand >= 0) - { - REBAR_BAND *band1, *band2; - - if (GetCapture() != infoPtr->hwndSelf) - ERR("We are dragging but haven't got capture?!?\n"); - - band1 = &infoPtr->bands[infoPtr->iGrabbedBand-1]; - band2 = &infoPtr->bands[infoPtr->iGrabbedBand]; - - /* if mouse did not move much, exit */ - if ((abs(ptMove.x - infoPtr->dragNow.x) <= mindragx) && - (abs(ptMove.y - infoPtr->dragNow.y) <= mindragy)) return 0; - - /* Test for valid drag case - must not be first band in row */ - if (infoPtr->dwStyle & CCS_VERT) { - if ((ptMove.x < band2->rcBand.left) || - (ptMove.x > band2->rcBand.right) || - ((infoPtr->iGrabbedBand > 0) && (band1->iRow != band2->iRow))) { - FIXME("Cannot drag to other rows yet!!\n"); - } - else { - REBAR_HandleLRDrag (infoPtr, &ptMove); - } - } - else { - if ((ptMove.y < band2->rcBand.top) || - (ptMove.y > band2->rcBand.bottom) || - ((infoPtr->iGrabbedBand > 0) && (band1->iRow != band2->iRow))) { - FIXME("Cannot drag to other rows yet!!\n"); - } - else { - REBAR_HandleLRDrag (infoPtr, &ptMove); - } - } - } - else - { - INT iHitBand; - UINT htFlags; - TRACKMOUSEEVENT trackinfo; - - REBAR_InternalHitTest(infoPtr, &ptMove, &htFlags, &iHitBand); - - if (infoPtr->iOldBand >= 0 && infoPtr->iOldBand == infoPtr->ichevronhotBand) - { - lpChevronBand = &infoPtr->bands[infoPtr->ichevronhotBand]; - if (lpChevronBand->fDraw & DRAW_CHEVRONHOT) - { - lpChevronBand->fDraw &= ~DRAW_CHEVRONHOT; - InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE); - } - infoPtr->ichevronhotBand = -2; - } - - if (htFlags == RBHT_CHEVRON) - { - /* fill in the TRACKMOUSEEVENT struct */ - trackinfo.cbSize = sizeof(TRACKMOUSEEVENT); - trackinfo.dwFlags = TME_QUERY; - trackinfo.hwndTrack = infoPtr->hwndSelf; - trackinfo.dwHoverTime = 0; - - /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */ - _TrackMouseEvent(&trackinfo); - - /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */ - if(!(trackinfo.dwFlags & TME_LEAVE)) - { - trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */ - - /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */ - /* and can properly deactivate the hot chevron */ - _TrackMouseEvent(&trackinfo); - } - - lpChevronBand = &infoPtr->bands[iHitBand]; - if (!(lpChevronBand->fDraw & DRAW_CHEVRONHOT)) - { - lpChevronBand->fDraw |= DRAW_CHEVRONHOT; - InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE); - infoPtr->ichevronhotBand = iHitBand; - } - } - infoPtr->iOldBand = iHitBand; - } - - return 0; -} - - -inline static LRESULT -REBAR_NCCalcSize (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - if (infoPtr->dwStyle & WS_BORDER) { - InflateRect((LPRECT)lParam, -GetSystemMetrics(SM_CXEDGE), - -GetSystemMetrics(SM_CYEDGE)); - } - TRACE("new client=(%ld,%ld)-(%ld,%ld)\n", - ((LPRECT)lParam)->left, ((LPRECT)lParam)->top, - ((LPRECT)lParam)->right, ((LPRECT)lParam)->bottom); - return 0; -} - - -static LRESULT -REBAR_NCCreate (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - LPCREATESTRUCTW cs = (LPCREATESTRUCTW) lParam; - REBAR_INFO *infoPtr = REBAR_GetInfoPtr (hwnd); - RECT wnrc1, clrc1; - NONCLIENTMETRICSW ncm; - HFONT tfont; - INT i; - - if (infoPtr != NULL) { - ERR("Strange info structure pointer *not* NULL\n"); - return FALSE; - } - - if (TRACE_ON(rebar)) { - GetWindowRect(hwnd, &wnrc1); - GetClientRect(hwnd, &clrc1); - TRACE("window=(%ld,%ld)-(%ld,%ld) client=(%ld,%ld)-(%ld,%ld) cs=(%d,%d %dx%d)\n", - wnrc1.left, wnrc1.top, wnrc1.right, wnrc1.bottom, - clrc1.left, clrc1.top, clrc1.right, clrc1.bottom, - cs->x, cs->y, cs->cx, cs->cy); - } - - /* allocate memory for info structure */ - infoPtr = (REBAR_INFO *)Alloc (sizeof(REBAR_INFO)); - SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); - - /* initialize info structure - initial values are 0 */ - infoPtr->clrBk = CLR_NONE; - infoPtr->clrText = CLR_NONE; - infoPtr->clrBtnText = GetSysColor (COLOR_BTNTEXT); - infoPtr->clrBtnFace = GetSysColor (COLOR_BTNFACE); - infoPtr->iOldBand = -1; - infoPtr->ichevronhotBand = -2; - infoPtr->iGrabbedBand = -1; - infoPtr->hwndSelf = hwnd; - infoPtr->DoRedraw = TRUE; - infoPtr->hcurArrow = LoadCursorW (0, (LPWSTR)IDC_ARROW); - infoPtr->hcurHorz = LoadCursorW (0, (LPWSTR)IDC_SIZEWE); - infoPtr->hcurVert = LoadCursorW (0, (LPWSTR)IDC_SIZENS); - infoPtr->hcurDrag = LoadCursorW (0, (LPWSTR)IDC_SIZE); - infoPtr->bUnicode = IsWindowUnicode (hwnd); - infoPtr->fStatus = CREATE_RUNNING; - infoPtr->hFont = GetStockObject (SYSTEM_FONT); - - /* issue WM_NOTIFYFORMAT to get unicode status of parent */ - i = SendMessageW(REBAR_GetNotifyParent (infoPtr), - WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY); - if ((i < NFR_ANSI) || (i > NFR_UNICODE)) { - ERR("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n", i); - i = NFR_ANSI; - } - infoPtr->NtfUnicode = (i == NFR_UNICODE) ? 1 : 0; - - /* add necessary styles to the requested styles */ - infoPtr->dwStyle = cs->style | WS_VISIBLE | CCS_TOP; - SetWindowLongW (hwnd, GWL_STYLE, infoPtr->dwStyle); - - /* get font handle for Caption Font */ - ncm.cbSize = sizeof(ncm); - SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0); - /* if the font is bold, set to normal */ - if (ncm.lfCaptionFont.lfWeight > FW_NORMAL) { - ncm.lfCaptionFont.lfWeight = FW_NORMAL; - } - tfont = CreateFontIndirectW (&ncm.lfCaptionFont); - if (tfont) { - infoPtr->hFont = infoPtr->hDefaultFont = tfont; - } - -/* native does: - GetSysColor (numerous); - GetSysColorBrush (numerous) (see WM_SYSCOLORCHANGE); - *GetStockObject (SYSTEM_FONT); - *SetWindowLong (hwnd, 0, info ptr); - *WM_NOTIFYFORMAT; - *SetWindowLong (hwnd, GWL_STYLE, style+0x10000001); - WS_VISIBLE = 0x10000000; - CCS_TOP = 0x00000001; - *SystemParametersInfo (SPI_GETNONCLIENTMETRICS...); - *CreateFontIndirect (lfCaptionFont from above); - GetDC (); - SelectObject (hdc, fontabove); - GetTextMetrics (hdc, ); guessing is tmHeight - SelectObject (hdc, oldfont); - ReleaseDC (); - GetWindowRect (); - MapWindowPoints (0, parent, rectabove, 2); - GetWindowRect (); - GetClientRect (); - ClientToScreen (clientrect); - SetWindowPos (hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER); - */ - return TRUE; -} - - -static LRESULT -REBAR_NCHitTest (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - NMMOUSE nmmouse; - POINT clpt; - INT i; - UINT scrap; - LRESULT ret = HTCLIENT; - - /* - * Differences from doc at MSDN (as observed with version 4.71 of - * comctl32.dll - * 1. doc says nmmouse.pt is in screen coord, trace shows client coord. - * 2. if band is not identified .dwItemSpec is 0xffffffff. - * 3. native always seems to return HTCLIENT if notify return is 0. - */ - - clpt.x = (short)LOWORD(lParam); - clpt.y = (short)HIWORD(lParam); - ScreenToClient (infoPtr->hwndSelf, &clpt); - REBAR_InternalHitTest (infoPtr, &clpt, &scrap, - (INT *)&nmmouse.dwItemSpec); - nmmouse.dwItemData = 0; - nmmouse.pt = clpt; - nmmouse.dwHitInfo = 0; - if ((i = REBAR_Notify((NMHDR *) &nmmouse, infoPtr, NM_NCHITTEST))) { - TRACE("notify changed return value from %ld to %d\n", - ret, i); - ret = (LRESULT) i; - } - TRACE("returning %ld, client point (%ld,%ld)\n", ret, clpt.x, clpt.y); - return ret; -} - - -static LRESULT -REBAR_NCPaint (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - RECT rcWindow; - HDC hdc; - - if (infoPtr->dwStyle & WS_MINIMIZE) - return 0; /* Nothing to do */ - - if (infoPtr->dwStyle & WS_BORDER) { - - /* adjust rectangle and draw the necessary edge */ - if (!(hdc = GetDCEx( infoPtr->hwndSelf, 0, DCX_USESTYLE | DCX_WINDOW ))) - return 0; - GetWindowRect (infoPtr->hwndSelf, &rcWindow); - OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top); - TRACE("rect (%ld,%ld)-(%ld,%ld)\n", - rcWindow.left, rcWindow.top, - rcWindow.right, rcWindow.bottom); - DrawEdge (hdc, &rcWindow, EDGE_ETCHED, BF_RECT); - ReleaseDC( infoPtr->hwndSelf, hdc ); - } - - return 0; -} - - -static LRESULT -REBAR_NotifyFormat (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - INT i; - - if (lParam == NF_REQUERY) { - i = SendMessageW(REBAR_GetNotifyParent (infoPtr), - WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY); - if ((i < NFR_ANSI) || (i > NFR_UNICODE)) { - ERR("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n", i); - i = NFR_ANSI; - } - infoPtr->NtfUnicode = (i == NFR_UNICODE) ? 1 : 0; - return (LRESULT)i; - } - return (LRESULT)((infoPtr->bUnicode) ? NFR_UNICODE : NFR_ANSI); -} - - -static LRESULT -REBAR_Paint (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - HDC hdc; - PAINTSTRUCT ps; - RECT rc; - - GetClientRect(infoPtr->hwndSelf, &rc); - hdc = wParam==0 ? BeginPaint (infoPtr->hwndSelf, &ps) : (HDC)wParam; - - TRACE("painting (%ld,%ld)-(%ld,%ld) client (%ld,%ld)-(%ld,%ld)\n", - ps.rcPaint.left, ps.rcPaint.top, - ps.rcPaint.right, ps.rcPaint.bottom, - rc.left, rc.top, rc.right, rc.bottom); - - if (ps.fErase) { - /* Erase area of paint if requested */ - REBAR_InternalEraseBkGnd (infoPtr, wParam, lParam, &ps.rcPaint); - } - - REBAR_Refresh (infoPtr, hdc); - if (!wParam) - EndPaint (infoPtr->hwndSelf, &ps); - return 0; -} - - -static LRESULT -REBAR_SetCursor (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - POINT pt; - UINT flags; - - TRACE("code=0x%X id=0x%X\n", LOWORD(lParam), HIWORD(lParam)); - - GetCursorPos (&pt); - ScreenToClient (infoPtr->hwndSelf, &pt); - - REBAR_InternalHitTest (infoPtr, &pt, &flags, NULL); - - if (flags == RBHT_GRABBER) { - if ((infoPtr->dwStyle & CCS_VERT) && - !(infoPtr->dwStyle & RBS_VERTICALGRIPPER)) - SetCursor (infoPtr->hcurVert); - else - SetCursor (infoPtr->hcurHorz); - } - else if (flags != RBHT_CLIENT) - SetCursor (infoPtr->hcurArrow); - - return 0; -} - - -static LRESULT -REBAR_SetFont (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - RECT rcClient; - REBAR_BAND *lpBand; - UINT i; - - infoPtr->hFont = (HFONT)wParam; - - /* revalidate all bands to change sizes of text in headers of bands */ - for (i=0; iuNumBands; i++) { - lpBand = &infoPtr->bands[i]; - REBAR_ValidateBand (infoPtr, lpBand); - } - - - if (LOWORD(lParam)) { - GetClientRect (infoPtr->hwndSelf, &rcClient); - REBAR_Layout (infoPtr, &rcClient, FALSE, TRUE); - } - - return 0; -} - - -inline static LRESULT -REBAR_SetRedraw (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) - /***************************************************** - * - * Function; - * Handles the WM_SETREDRAW message. - * - * Documentation: - * According to testing V4.71 of COMCTL32 returns the - * *previous* status of the redraw flag (either 0 or -1) - * instead of the MSDN documented value of 0 if handled - * - *****************************************************/ -{ - BOOL oldredraw = infoPtr->DoRedraw; - - TRACE("set to %s, fStatus=%08x\n", - (wParam) ? "TRUE" : "FALSE", infoPtr->fStatus); - infoPtr->DoRedraw = (BOOL) wParam; - if (wParam) { - if (infoPtr->fStatus & BAND_NEEDS_REDRAW) { - REBAR_MoveChildWindows (infoPtr, 0, infoPtr->uNumBands); - REBAR_ForceResize (infoPtr); - InvalidateRect (infoPtr->hwndSelf, 0, TRUE); - } - infoPtr->fStatus &= ~BAND_NEEDS_REDRAW; - } - return (oldredraw) ? -1 : 0; -} - - -static LRESULT -REBAR_Size (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - RECT rcClient; - - /* auto resize deadlock check */ - if (infoPtr->fStatus & AUTO_RESIZE) { - infoPtr->fStatus &= ~AUTO_RESIZE; - TRACE("AUTO_RESIZE was set, reset, fStatus=%08x lparam=%08lx\n", - infoPtr->fStatus, lParam); - return 0; - } - - if (infoPtr->fStatus & CREATE_RUNNING) { - /* still in CreateWindow */ - RECT rcWin; - - if ((INT)wParam != SIZE_RESTORED) { - ERR("WM_SIZE in create and flags=%08x, lParam=%08lx\n", - wParam, lParam); - } - - TRACE("still in CreateWindow\n"); - infoPtr->fStatus &= ~CREATE_RUNNING; - GetWindowRect ( infoPtr->hwndSelf, &rcWin); - TRACE("win rect (%ld,%ld)-(%ld,%ld)\n", - rcWin.left, rcWin.top, rcWin.right, rcWin.bottom); - - if ((lParam == 0) && (rcWin.right-rcWin.left == 0) && - (rcWin.bottom-rcWin.top == 0)) { - /* native control seems to do this */ - GetClientRect (GetParent(infoPtr->hwndSelf), &rcClient); - TRACE("sizing rebar, message and client zero, parent client (%ld,%ld)\n", - rcClient.right, rcClient.bottom); - } - else { - INT cx, cy; - - cx = rcWin.right - rcWin.left; - cy = rcWin.bottom - rcWin.top; - if ((cx == LOWORD(lParam)) && (cy == HIWORD(lParam))) { - return 0; - } - - /* do the actual WM_SIZE request */ - GetClientRect (infoPtr->hwndSelf, &rcClient); - TRACE("sizing rebar from (%ld,%ld) to (%d,%d), client (%ld,%ld)\n", - infoPtr->calcSize.cx, infoPtr->calcSize.cy, - LOWORD(lParam), HIWORD(lParam), - rcClient.right, rcClient.bottom); - } - } - else { - if ((INT)wParam != SIZE_RESTORED) { - ERR("WM_SIZE out of create and flags=%08x, lParam=%08lx\n", - wParam, lParam); - } - - /* Handle cases when outside of the CreateWindow process */ - - GetClientRect (infoPtr->hwndSelf, &rcClient); - if ((lParam == 0) && (rcClient.right + rcClient.bottom != 0) && - (infoPtr->dwStyle & RBS_AUTOSIZE)) { - /* on a WM_SIZE to zero and current client not zero and AUTOSIZE */ - /* native seems to use the current client rect for the size */ - infoPtr->fStatus |= BAND_NEEDS_LAYOUT; - TRACE("sizing rebar to client (%ld,%ld) size is zero but AUTOSIZE set\n", - rcClient.right, rcClient.bottom); - } - else { - TRACE("sizing rebar from (%ld,%ld) to (%d,%d), client (%ld,%ld)\n", - infoPtr->calcSize.cx, infoPtr->calcSize.cy, - LOWORD(lParam), HIWORD(lParam), - rcClient.right, rcClient.bottom); - } - } - - if (infoPtr->dwStyle & RBS_AUTOSIZE) { - NMRBAUTOSIZE autosize; - - GetClientRect(infoPtr->hwndSelf, &autosize.rcTarget); - autosize.fChanged = 0; /* ??? */ - autosize.rcActual = autosize.rcTarget; /* ??? */ - REBAR_Notify((NMHDR *) &autosize, infoPtr, RBN_AUTOSIZE); - TRACE("RBN_AUTOSIZE client=(%ld,%ld), lp=%08lx\n", - autosize.rcTarget.right, autosize.rcTarget.bottom, lParam); - } - - if ((infoPtr->calcSize.cx != rcClient.right) || - (infoPtr->calcSize.cy != rcClient.bottom)) - infoPtr->fStatus |= BAND_NEEDS_LAYOUT; - - REBAR_Layout (infoPtr, &rcClient, TRUE, TRUE); - - return 0; -} - - -static LRESULT -REBAR_StyleChanged (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - STYLESTRUCT *ss = (STYLESTRUCT *)lParam; - - TRACE("current style=%08lx, styleOld=%08lx, style being set to=%08lx\n", - infoPtr->dwStyle, ss->styleOld, ss->styleNew); - infoPtr->dwStyle = ss->styleNew; - - return FALSE; -} - - -static LRESULT -REBAR_WindowPosChanged (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - WINDOWPOS *lpwp = (WINDOWPOS *)lParam; - LRESULT ret; - RECT rc; - - /* Save the new origin of this window - used by _ForceResize */ - infoPtr->origin.x = lpwp->x; - infoPtr->origin.y = lpwp->y; - ret = DefWindowProcW(infoPtr->hwndSelf, WM_WINDOWPOSCHANGED, - wParam, lParam); - GetWindowRect(infoPtr->hwndSelf, &rc); - TRACE("hwnd %p new pos (%ld,%ld)-(%ld,%ld)\n", - infoPtr->hwndSelf, rc.left, rc.top, rc.right, rc.bottom); - return ret; -} - - -static LRESULT WINAPI -REBAR_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - REBAR_INFO *infoPtr = REBAR_GetInfoPtr (hwnd); - - TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", - hwnd, uMsg, wParam, lParam); - if (!infoPtr && (uMsg != WM_NCCREATE)) - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - switch (uMsg) - { -/* case RB_BEGINDRAG: */ - - case RB_DELETEBAND: - return REBAR_DeleteBand (infoPtr, wParam, lParam); - -/* case RB_DRAGMOVE: */ -/* case RB_ENDDRAG: */ - - case RB_GETBANDBORDERS: - return REBAR_GetBandBorders (infoPtr, wParam, lParam); - - case RB_GETBANDCOUNT: - return REBAR_GetBandCount (infoPtr); - - case RB_GETBANDINFO_OLD: - case RB_GETBANDINFOA: - return REBAR_GetBandInfoA (infoPtr, wParam, lParam); - - case RB_GETBANDINFOW: - return REBAR_GetBandInfoW (infoPtr, wParam, lParam); - - case RB_GETBARHEIGHT: - return REBAR_GetBarHeight (infoPtr, wParam, lParam); - - case RB_GETBARINFO: - return REBAR_GetBarInfo (infoPtr, wParam, lParam); - - case RB_GETBKCOLOR: - return REBAR_GetBkColor (infoPtr); - -/* case RB_GETCOLORSCHEME: */ -/* case RB_GETDROPTARGET: */ - - case RB_GETPALETTE: - return REBAR_GetPalette (infoPtr, wParam, lParam); - - case RB_GETRECT: - return REBAR_GetRect (infoPtr, wParam, lParam); - - case RB_GETROWCOUNT: - return REBAR_GetRowCount (infoPtr); - - case RB_GETROWHEIGHT: - return REBAR_GetRowHeight (infoPtr, wParam, lParam); - - case RB_GETTEXTCOLOR: - return REBAR_GetTextColor (infoPtr); - - case RB_GETTOOLTIPS: - return REBAR_GetToolTips (infoPtr); - - case RB_GETUNICODEFORMAT: - return REBAR_GetUnicodeFormat (infoPtr); - - case CCM_GETVERSION: - return REBAR_GetVersion (infoPtr); - - case RB_HITTEST: - return REBAR_HitTest (infoPtr, wParam, lParam); - - case RB_IDTOINDEX: - return REBAR_IdToIndex (infoPtr, wParam, lParam); - - case RB_INSERTBANDA: - return REBAR_InsertBandA (infoPtr, wParam, lParam); - - case RB_INSERTBANDW: - return REBAR_InsertBandW (infoPtr, wParam, lParam); - - case RB_MAXIMIZEBAND: - return REBAR_MaximizeBand (infoPtr, wParam, lParam); - - case RB_MINIMIZEBAND: - return REBAR_MinimizeBand (infoPtr, wParam, lParam); - - case RB_MOVEBAND: - return REBAR_MoveBand (infoPtr, wParam, lParam); - - case RB_PUSHCHEVRON: - return REBAR_PushChevron (infoPtr, wParam, lParam); - - case RB_SETBANDINFOA: - return REBAR_SetBandInfoA (infoPtr, wParam, lParam); - - case RB_SETBANDINFOW: - return REBAR_SetBandInfoW (infoPtr, wParam, lParam); - - case RB_SETBARINFO: - return REBAR_SetBarInfo (infoPtr, wParam, lParam); - - case RB_SETBKCOLOR: - return REBAR_SetBkColor (infoPtr, wParam, lParam); - -/* case RB_SETCOLORSCHEME: */ -/* case RB_SETPALETTE: */ -/* return REBAR_GetPalette (infoPtr, wParam, lParam); */ - - case RB_SETPARENT: - return REBAR_SetParent (infoPtr, wParam, lParam); - - case RB_SETTEXTCOLOR: - return REBAR_SetTextColor (infoPtr, wParam, lParam); - -/* case RB_SETTOOLTIPS: */ - - case RB_SETUNICODEFORMAT: - return REBAR_SetUnicodeFormat (infoPtr, wParam); - - case CCM_SETVERSION: - return REBAR_SetVersion (infoPtr, (INT)wParam); - - case RB_SHOWBAND: - return REBAR_ShowBand (infoPtr, wParam, lParam); - - case RB_SIZETORECT: - return REBAR_SizeToRect (infoPtr, wParam, lParam); - - -/* Messages passed to parent */ - case WM_COMMAND: - case WM_DRAWITEM: - case WM_NOTIFY: - if (infoPtr->NtfUnicode) - return SendMessageW (REBAR_GetNotifyParent (infoPtr), - uMsg, wParam, lParam); - else - return SendMessageA (REBAR_GetNotifyParent (infoPtr), - uMsg, wParam, lParam); - - -/* case WM_CHARTOITEM: supported according to ControlSpy */ - - case WM_CREATE: - return REBAR_Create (infoPtr, wParam, lParam); - - case WM_DESTROY: - return REBAR_Destroy (infoPtr, wParam, lParam); - - case WM_ERASEBKGND: - return REBAR_EraseBkGnd (infoPtr, wParam, lParam); - - case WM_GETFONT: - return REBAR_GetFont (infoPtr, wParam, lParam); - -/* case WM_LBUTTONDBLCLK: supported according to ControlSpy */ - - case WM_LBUTTONDOWN: - return REBAR_LButtonDown (infoPtr, wParam, lParam); - - case WM_LBUTTONUP: - return REBAR_LButtonUp (infoPtr, wParam, lParam); - -/* case WM_MEASUREITEM: supported according to ControlSpy */ - - case WM_MOUSEMOVE: - return REBAR_MouseMove (infoPtr, wParam, lParam); - - case WM_MOUSELEAVE: - return REBAR_MouseLeave (infoPtr, wParam, lParam); - - case WM_NCCALCSIZE: - return REBAR_NCCalcSize (infoPtr, wParam, lParam); - - case WM_NCCREATE: - return REBAR_NCCreate (hwnd, wParam, lParam); - - case WM_NCHITTEST: - return REBAR_NCHitTest (infoPtr, wParam, lParam); - - case WM_NCPAINT: - return REBAR_NCPaint (infoPtr, wParam, lParam); - - case WM_NOTIFYFORMAT: - return REBAR_NotifyFormat (infoPtr, wParam, lParam); - - case WM_PAINT: - return REBAR_Paint (infoPtr, wParam, lParam); - -/* case WM_PALETTECHANGED: supported according to ControlSpy */ -/* case WM_PRINTCLIENT: supported according to ControlSpy */ -/* case WM_QUERYNEWPALETTE:supported according to ControlSpy */ -/* case WM_RBUTTONDOWN: supported according to ControlSpy */ -/* case WM_RBUTTONUP: supported according to ControlSpy */ - - case WM_SETCURSOR: - return REBAR_SetCursor (infoPtr, wParam, lParam); - - case WM_SETFONT: - return REBAR_SetFont (infoPtr, wParam, lParam); - - case WM_SETREDRAW: - return REBAR_SetRedraw (infoPtr, wParam, lParam); - - case WM_SIZE: - return REBAR_Size (infoPtr, wParam, lParam); - - case WM_STYLECHANGED: - return REBAR_StyleChanged (infoPtr, wParam, lParam); - -/* case WM_SYSCOLORCHANGE: supported according to ControlSpy */ -/* "Applications that have brushes using the existing system colors - should delete those brushes and recreate them using the new - system colors." per MSDN */ - -/* case WM_VKEYTOITEM: supported according to ControlSpy */ -/* case WM_WININICHANGE: */ - - case WM_WINDOWPOSCHANGED: - return REBAR_WindowPosChanged (infoPtr, wParam, lParam); - - default: - if ((uMsg >= WM_USER) && (uMsg < WM_APP)) - ERR("unknown msg %04x wp=%08x lp=%08lx\n", - uMsg, wParam, lParam); - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - } -} - - -VOID -REBAR_Register (void) -{ - WNDCLASSW wndClass; - - ZeroMemory (&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS; - wndClass.lpfnWndProc = REBAR_WindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(REBAR_INFO *); - wndClass.hCursor = 0; - wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); -#if GLATESTING - wndClass.hbrBackground = CreateSolidBrush(RGB(0,128,0)); -#endif - wndClass.lpszClassName = REBARCLASSNAMEW; - - RegisterClassW (&wndClass); - - mindragx = GetSystemMetrics (SM_CXDRAG); - mindragy = GetSystemMetrics (SM_CYDRAG); - -} - - -VOID -REBAR_Unregister (void) -{ - UnregisterClassW (REBARCLASSNAMEW, NULL); -} +/* + * Rebar control + * + * Copyright 1998, 1999 Eric Kohl + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES + * + * This code was audited for completeness against the documented features + * of Comctl32.dll version 6.0 on Oct. 19, 2004, by Robert Shearman. + * + * Unless otherwise noted, we believe this code to be complete, as per + * the specification mentioned above. + * If you discover missing features or bugs please note them below. + * + * TODO + * Styles: + * - RBS_DBLCLKTOGGLE + * - RBS_FIXEDORDER + * - RBS_REGISTERDROP + * - RBS_TOOLTIPS + * - CCS_NORESIZE + * - CCS_NOMOVEX + * - CCS_NOMOVEY + * Messages: + * - RB_BEGINDRAG + * - RB_DRAGMOVE + * - RB_ENDDRAG + * - RB_GETBANDMARGINS + * - RB_GETCOLORSCHEME + * - RB_GETDROPTARGET + * - RB_GETPALETTE + * - RB_SETCOLORSCHEME + * - RB_SETPALETTE + * - RB_SETTOOLTIPS + * - WM_CHARTOITEM + * - WM_LBUTTONDBLCLK + * - WM_MEASUREITEM + * - WM_PALETTECHANGED + * - WM_PRINTCLIENT + * - WM_QUERYNEWPALETTE + * - WM_RBUTTONDOWN + * - WM_RBUTTONUP + * - WM_SYSCOLORCHANGE + * - WM_VKEYTOITEM + * - WM_WININICHANGE + * Notifications: + * - NM_HCHITTEST + * - NM_RELEASEDCAPTURE + * - RBN_AUTOBREAK + * - RBN_GETOBJECT + * - RBN_MINMAX + * Band styles: + * - RBBS_FIXEDBMP + * Native uses (on each draw!!) SM_CYBORDER (or SM_CXBORDER for CCS_VERT) + * to set the size of the separator width (the value SEP_WIDTH_SIZE + * in here). Should be fixed!! + */ + +/* + * Testing: set to 1 to make background brush *always* green + */ +#define GLATESTING 0 + +/* + * + * 2. At "FIXME: problem # 2" WinRAR: + * if "#if 1" then last band draws in separate row + * if "#if 0" then last band draws in previous row *** just like native *** + * + */ +#define PROBLEM2 0 + +/* + * 3. REBAR_MoveChildWindows should have a loop because more than + * one pass is made (together with the RBN_CHILDSIZEs) is made on + * at least RB_INSERTBAND + */ + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "wine/unicode.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "comctl32.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(rebar); + +typedef struct +{ + UINT fStyle; + UINT fMask; + COLORREF clrFore; + COLORREF clrBack; + INT iImage; + HWND hwndChild; + UINT cxMinChild; /* valid if _CHILDSIZE */ + UINT cyMinChild; /* valid if _CHILDSIZE */ + UINT cx; /* valid if _SIZE */ + HBITMAP hbmBack; + UINT wID; + UINT cyChild; /* valid if _CHILDSIZE */ + UINT cyMaxChild; /* valid if _CHILDSIZE */ + UINT cyIntegral; /* valid if _CHILDSIZE */ + UINT cxIdeal; + LPARAM lParam; + UINT cxHeader; + + UINT lcx; /* minimum cx for band */ + UINT ccx; /* current cx for band */ + UINT hcx; /* maximum cx for band */ + UINT lcy; /* minimum cy for band */ + UINT ccy; /* current cy for band */ + UINT hcy; /* maximum cy for band */ + + SIZE offChild; /* x,y offset if child is not FIXEDSIZE */ + UINT uMinHeight; + INT iRow; /* zero-based index of the row this band assigned to */ + UINT fStatus; /* status flags, reset only by _Validate */ + UINT fDraw; /* drawing flags, reset only by _Layout */ + UINT uCDret; /* last return from NM_CUSTOMDRAW */ + RECT rcoldBand; /* previous calculated band rectangle */ + RECT rcBand; /* calculated band rectangle */ + RECT rcGripper; /* calculated gripper rectangle */ + RECT rcCapImage; /* calculated caption image rectangle */ + RECT rcCapText; /* calculated caption text rectangle */ + RECT rcChild; /* calculated child rectangle */ + RECT rcChevron; /* calculated chevron rectangle */ + + LPWSTR lpText; + HWND hwndPrevParent; +} REBAR_BAND; + +/* fStatus flags */ +#define HAS_GRIPPER 0x00000001 +#define HAS_IMAGE 0x00000002 +#define HAS_TEXT 0x00000004 + +/* fDraw flags */ +#define DRAW_GRIPPER 0x00000001 +#define DRAW_IMAGE 0x00000002 +#define DRAW_TEXT 0x00000004 +#define DRAW_RIGHTSEP 0x00000010 +#define DRAW_BOTTOMSEP 0x00000020 +#define DRAW_CHEVRONHOT 0x00000040 +#define DRAW_CHEVRONPUSHED 0x00000080 +#define DRAW_LAST_IN_ROW 0x00000100 +#define DRAW_FIRST_IN_ROW 0x00000200 +#define NTF_INVALIDATE 0x01000000 + +typedef struct +{ + COLORREF clrBk; /* background color */ + COLORREF clrText; /* text color */ + COLORREF clrBtnText; /* system color for BTNTEXT */ + COLORREF clrBtnFace; /* system color for BTNFACE */ + HIMAGELIST himl; /* handle to imagelist */ + UINT uNumBands; /* # of bands in rebar (first=0, last=uNumBands-1 */ + UINT uNumRows; /* # of rows of bands (first=1, last=uNumRows */ + HWND hwndSelf; /* handle of REBAR window itself */ + HWND hwndToolTip; /* handle to the tool tip control */ + HWND hwndNotify; /* notification window (parent) */ + HFONT hDefaultFont; + HFONT hFont; /* handle to the rebar's font */ + SIZE imageSize; /* image size (image list) */ + DWORD dwStyle; /* window style */ + SIZE calcSize; /* calculated rebar size */ + SIZE oldSize; /* previous calculated rebar size */ + BOOL bUnicode; /* TRUE if this window is W type */ + BOOL NtfUnicode; /* TRUE if parent wants notify in W format */ + BOOL DoRedraw; /* TRUE to acutally draw bands */ + UINT fStatus; /* Status flags (see below) */ + HCURSOR hcurArrow; /* handle to the arrow cursor */ + HCURSOR hcurHorz; /* handle to the EW cursor */ + HCURSOR hcurVert; /* handle to the NS cursor */ + HCURSOR hcurDrag; /* handle to the drag cursor */ + INT iVersion; /* version number */ + POINT dragStart; /* x,y of button down */ + POINT dragNow; /* x,y of this MouseMove */ + INT iOldBand; /* last band that had the mouse cursor over it */ + INT ihitoffset; /* offset of hotspot from gripper.left */ + POINT origin; /* left/upper corner of client */ + INT ichevronhotBand; /* last band that had a hot chevron */ + INT iGrabbedBand;/* band number of band whose gripper was grabbed */ + + REBAR_BAND *bands; /* pointer to the array of rebar bands */ +} REBAR_INFO; + +/* fStatus flags */ +#define BEGIN_DRAG_ISSUED 0x00000001 +#define AUTO_RESIZE 0x00000002 +#define RESIZE_ANYHOW 0x00000004 +#define NTF_HGHTCHG 0x00000008 +#define BAND_NEEDS_LAYOUT 0x00000010 +#define BAND_NEEDS_REDRAW 0x00000020 +#define CREATE_RUNNING 0x00000040 + +/* ---- REBAR layout constants. Mostly determined by ---- */ +/* ---- experiment on WIN 98. ---- */ + +/* Width (or height) of separators between bands (either horz. or */ +/* vert.). True only if RBS_BANDBORDERS is set */ +#define SEP_WIDTH_SIZE 2 +#define SEP_WIDTH ((infoPtr->dwStyle & RBS_BANDBORDERS) ? SEP_WIDTH_SIZE : 0) + +/* Blank (background color) space between Gripper (if present) */ +/* and next item (image, text, or window). Always present */ +#define REBAR_ALWAYS_SPACE 4 + +/* Blank (background color) space after Image (if present). */ +#define REBAR_POST_IMAGE 2 + +/* Blank (background color) space after Text (if present). */ +#define REBAR_POST_TEXT 4 + +/* Height of vertical gripper in a CCS_VERT rebar. */ +#define GRIPPER_HEIGHT 16 + +/* Blank (background color) space before Gripper (if present). */ +#define REBAR_PRE_GRIPPER 2 + +/* Width (of normal vertical gripper) or height (of horz. gripper) */ +/* if present. */ +#define GRIPPER_WIDTH 3 + +/* Width of the chevron button if present */ +#define CHEVRON_WIDTH 10 + +/* Height of divider for Rebar if not disabled (CCS_NODIVIDER) */ +/* either top or bottom */ +#define REBAR_DIVIDER 2 + +/* minimium vertical height of a normal bar */ +/* or minimum width of a CCS_VERT bar - from experiment on Win2k */ +#define REBAR_MINSIZE 23 + +/* This is the increment that is used over the band height */ +#define REBARSPACE(a) ((a->fStyle & RBBS_CHILDEDGE) ? 2*REBAR_DIVIDER : 0) + +/* ---- End of REBAR layout constants. ---- */ + +#define RB_GETBANDINFO_OLD (WM_USER+5) /* obsoleted after IE3, but we have to support it anyway */ + +/* The following 6 defines return the proper rcBand element */ +/* depending on whether CCS_VERT was set. */ +#define rcBlt(b) ((infoPtr->dwStyle & CCS_VERT) ? b->rcBand.top : b->rcBand.left) +#define rcBrb(b) ((infoPtr->dwStyle & CCS_VERT) ? b->rcBand.bottom : b->rcBand.right) +#define rcBw(b) ((infoPtr->dwStyle & CCS_VERT) ? (b->rcBand.bottom - b->rcBand.top) : \ + (b->rcBand.right - b->rcBand.left)) +#define ircBlt(b) ((infoPtr->dwStyle & CCS_VERT) ? b->rcBand.left : b->rcBand.top) +#define ircBrb(b) ((infoPtr->dwStyle & CCS_VERT) ? b->rcBand.right : b->rcBand.bottom) +#define ircBw(b) ((infoPtr->dwStyle & CCS_VERT) ? (b->rcBand.right - b->rcBand.left) : \ + (b->rcBand.bottom - b->rcBand.top)) + +/* The following define determines if a given band is hidden */ +#define HIDDENBAND(a) (((a)->fStyle & RBBS_HIDDEN) || \ + ((infoPtr->dwStyle & CCS_VERT) && \ + ((a)->fStyle & RBBS_NOVERT))) + +/* The following defines adjust the right or left end of a rectangle */ +#define READJ(b,i) do { if(infoPtr->dwStyle & CCS_VERT) b->rcBand.bottom+=(i); \ + else b->rcBand.right += (i); } while(0) +#define LEADJ(b,i) do { if(infoPtr->dwStyle & CCS_VERT) b->rcBand.top+=(i); \ + else b->rcBand.left += (i); } while(0) + + +#define REBAR_GetInfoPtr(wndPtr) ((REBAR_INFO *)GetWindowLongPtrW (hwnd, 0)) + + +/* "constant values" retrieved when DLL was initialized */ +/* FIXME we do this when the classes are registered. */ +static UINT mindragx = 0; +static UINT mindragy = 0; + +static const char *band_stylename[] = { + "RBBS_BREAK", /* 0001 */ + "RBBS_FIXEDSIZE", /* 0002 */ + "RBBS_CHILDEDGE", /* 0004 */ + "RBBS_HIDDEN", /* 0008 */ + "RBBS_NOVERT", /* 0010 */ + "RBBS_FIXEDBMP", /* 0020 */ + "RBBS_VARIABLEHEIGHT", /* 0040 */ + "RBBS_GRIPPERALWAYS", /* 0080 */ + "RBBS_NOGRIPPER", /* 0100 */ + NULL }; + +static const char *band_maskname[] = { + "RBBIM_STYLE", /* 0x00000001 */ + "RBBIM_COLORS", /* 0x00000002 */ + "RBBIM_TEXT", /* 0x00000004 */ + "RBBIM_IMAGE", /* 0x00000008 */ + "RBBIM_CHILD", /* 0x00000010 */ + "RBBIM_CHILDSIZE", /* 0x00000020 */ + "RBBIM_SIZE", /* 0x00000040 */ + "RBBIM_BACKGROUND", /* 0x00000080 */ + "RBBIM_ID", /* 0x00000100 */ + "RBBIM_IDEALSIZE", /* 0x00000200 */ + "RBBIM_LPARAM", /* 0x00000400 */ + "RBBIM_HEADERSIZE", /* 0x00000800 */ + NULL }; + + +static CHAR line[200]; + + +static CHAR * +REBAR_FmtStyle( UINT style) +{ + INT i = 0; + + *line = 0; + while (band_stylename[i]) { + if (style & (1<fMask & RBBIM_ID); + TRACE("ID=%u, ", pB->wID); + TRACE("size=%u, child=%p", pB->cbSize, pB->hwndChild); + if (pB->fMask & RBBIM_COLORS) + TRACE(", clrF=0x%06lx, clrB=0x%06lx", pB->clrFore, pB->clrBack); + TRACE("\n"); + + TRACE("band info: mask=0x%08x (%s)\n", pB->fMask, REBAR_FmtMask(pB->fMask)); + if (pB->fMask & RBBIM_STYLE) + TRACE("band info: style=0x%08x (%s)\n", pB->fStyle, REBAR_FmtStyle(pB->fStyle)); + if (pB->fMask & (RBBIM_SIZE | RBBIM_IDEALSIZE | RBBIM_HEADERSIZE | RBBIM_LPARAM )) { + TRACE("band info:"); + if (pB->fMask & RBBIM_SIZE) + TRACE(" cx=%u", pB->cx); + if (pB->fMask & RBBIM_IDEALSIZE) + TRACE(" xIdeal=%u", pB->cxIdeal); + if (pB->fMask & RBBIM_HEADERSIZE) + TRACE(" xHeader=%u", pB->cxHeader); + if (pB->fMask & RBBIM_LPARAM) + TRACE(" lParam=0x%08lx", pB->lParam); + TRACE("\n"); + } + if (pB->fMask & RBBIM_CHILDSIZE) + TRACE("band info: xMin=%u, yMin=%u, yChild=%u, yMax=%u, yIntgl=%u\n", + pB->cxMinChild, + pB->cyMinChild, pB->cyChild, pB->cyMaxChild, pB->cyIntegral); +} + +static VOID +REBAR_DumpBand (REBAR_INFO *iP) +{ + REBAR_BAND *pB; + UINT i; + + if(! TRACE_ON(rebar) ) return; + + TRACE("hwnd=%p: color=%08lx/%08lx, bands=%u, rows=%u, cSize=%ld,%ld\n", + iP->hwndSelf, iP->clrText, iP->clrBk, iP->uNumBands, iP->uNumRows, + iP->calcSize.cx, iP->calcSize.cy); + TRACE("hwnd=%p: flags=%08x, dragStart=%ld,%ld, dragNow=%ld,%ld, iGrabbedBand=%d\n", + iP->hwndSelf, iP->fStatus, iP->dragStart.x, iP->dragStart.y, + iP->dragNow.x, iP->dragNow.y, + iP->iGrabbedBand); + TRACE("hwnd=%p: style=%08lx, I'm Unicode=%s, notify in Unicode=%s, redraw=%s\n", + iP->hwndSelf, iP->dwStyle, (iP->bUnicode)?"TRUE":"FALSE", + (iP->NtfUnicode)?"TRUE":"FALSE", (iP->DoRedraw)?"TRUE":"FALSE"); + for (i = 0; i < iP->uNumBands; i++) { + pB = &iP->bands[i]; + TRACE("band # %u:", i); + if (pB->fMask & RBBIM_ID); + TRACE(" ID=%u", pB->wID); + if (pB->fMask & RBBIM_CHILD) + TRACE(" child=%p", pB->hwndChild); + if (pB->fMask & RBBIM_COLORS) + TRACE(" clrF=0x%06lx clrB=0x%06lx", pB->clrFore, pB->clrBack); + TRACE("\n"); + TRACE("band # %u: mask=0x%08x (%s)\n", i, pB->fMask, REBAR_FmtMask(pB->fMask)); + if (pB->fMask & RBBIM_STYLE) + TRACE("band # %u: style=0x%08x (%s)\n", + i, pB->fStyle, REBAR_FmtStyle(pB->fStyle)); + TRACE("band # %u: uMinH=%u xHeader=%u", + i, pB->uMinHeight, pB->cxHeader); + if (pB->fMask & (RBBIM_SIZE | RBBIM_IDEALSIZE | RBBIM_LPARAM )) { + if (pB->fMask & RBBIM_SIZE) + TRACE(" cx=%u", pB->cx); + if (pB->fMask & RBBIM_IDEALSIZE) + TRACE(" xIdeal=%u", pB->cxIdeal); + if (pB->fMask & RBBIM_LPARAM) + TRACE(" lParam=0x%08lx", pB->lParam); + } + TRACE("\n"); + if (RBBIM_CHILDSIZE) + TRACE("band # %u: xMin=%u, yMin=%u, yChild=%u, yMax=%u, yIntgl=%u\n", + i, pB->cxMinChild, pB->cyMinChild, pB->cyChild, pB->cyMaxChild, pB->cyIntegral); + if (pB->fMask & RBBIM_TEXT) + TRACE("band # %u: text=%s\n", + i, (pB->lpText) ? debugstr_w(pB->lpText) : "(null)"); + TRACE("band # %u: lcx=%u, ccx=%u, hcx=%u, lcy=%u, ccy=%u, hcy=%u, offChild=%ld,%ld\n", + i, pB->lcx, pB->ccx, pB->hcx, pB->lcy, pB->ccy, pB->hcy, pB->offChild.cx, pB->offChild.cy); + TRACE("band # %u: fStatus=%08x, fDraw=%08x, Band=(%ld,%ld)-(%ld,%ld), Grip=(%ld,%ld)-(%ld,%ld)\n", + i, pB->fStatus, pB->fDraw, + pB->rcBand.left, pB->rcBand.top, pB->rcBand.right, pB->rcBand.bottom, + pB->rcGripper.left, pB->rcGripper.top, pB->rcGripper.right, pB->rcGripper.bottom); + TRACE("band # %u: Img=(%ld,%ld)-(%ld,%ld), Txt=(%ld,%ld)-(%ld,%ld), Child=(%ld,%ld)-(%ld,%ld)\n", + i, + pB->rcCapImage.left, pB->rcCapImage.top, pB->rcCapImage.right, pB->rcCapImage.bottom, + pB->rcCapText.left, pB->rcCapText.top, pB->rcCapText.right, pB->rcCapText.bottom, + pB->rcChild.left, pB->rcChild.top, pB->rcChild.right, pB->rcChild.bottom); + } + +} + +static void +REBAR_DrawChevron (HDC hdc, INT left, INT top, INT colorRef) +{ + INT x, y; + HPEN hPen, hOldPen; + + if (!(hPen = CreatePen( PS_SOLID, 1, GetSysColor( colorRef )))) return; + hOldPen = SelectObject ( hdc, hPen ); + x = left + 2; + y = top; + MoveToEx (hdc, x, y, NULL); + LineTo (hdc, x+5, y++); x++; + MoveToEx (hdc, x, y, NULL); + LineTo (hdc, x+3, y++); x++; + MoveToEx (hdc, x, y, NULL); + LineTo (hdc, x+1, y++); + SelectObject( hdc, hOldPen ); + DeleteObject( hPen ); +} + +static HWND +REBAR_GetNotifyParent (REBAR_INFO *infoPtr) +{ + HWND parent, owner; + + parent = infoPtr->hwndNotify; + if (!parent) { + parent = GetParent (infoPtr->hwndSelf); + owner = GetWindow (infoPtr->hwndSelf, GW_OWNER); + if (owner) parent = owner; + } + return parent; +} + + +static INT +REBAR_Notify (NMHDR *nmhdr, REBAR_INFO *infoPtr, UINT code) +{ + HWND parent; + + parent = REBAR_GetNotifyParent (infoPtr); + nmhdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf); + nmhdr->hwndFrom = infoPtr->hwndSelf; + nmhdr->code = code; + + TRACE("window %p, code=%08x, %s\n", parent, code, + (infoPtr->NtfUnicode) ? "via Unicode" : "via ANSI"); + + if (infoPtr->NtfUnicode) + return SendMessageW (parent, WM_NOTIFY, (WPARAM) nmhdr->idFrom, + (LPARAM)nmhdr); + else + return SendMessageA (parent, WM_NOTIFY, (WPARAM) nmhdr->idFrom, + (LPARAM)nmhdr); +} + +static INT +REBAR_Notify_NMREBAR (REBAR_INFO *infoPtr, UINT uBand, UINT code) +{ + NMREBAR notify_rebar; + REBAR_BAND *lpBand; + + notify_rebar.dwMask = 0; + if (uBand!=-1) { + lpBand = &infoPtr->bands[uBand]; + if (lpBand->fMask & RBBIM_ID) { + notify_rebar.dwMask |= RBNM_ID; + notify_rebar.wID = lpBand->wID; + } + if (lpBand->fMask & RBBIM_LPARAM) { + notify_rebar.dwMask |= RBNM_LPARAM; + notify_rebar.lParam = lpBand->lParam; + } + if (lpBand->fMask & RBBIM_STYLE) { + notify_rebar.dwMask |= RBNM_STYLE; + notify_rebar.fStyle = lpBand->fStyle; + } + } + notify_rebar.uBand = uBand; + return REBAR_Notify ((NMHDR *)¬ify_rebar, infoPtr, code); +} + +static VOID +REBAR_DrawBand (HDC hdc, REBAR_INFO *infoPtr, REBAR_BAND *lpBand) +{ + HFONT hOldFont = 0; + INT oldBkMode = 0; + NMCUSTOMDRAW nmcd; + + if (lpBand->fDraw & DRAW_TEXT) { + hOldFont = SelectObject (hdc, infoPtr->hFont); + oldBkMode = SetBkMode (hdc, TRANSPARENT); + } + + /* should test for CDRF_NOTIFYITEMDRAW here */ + nmcd.dwDrawStage = CDDS_ITEMPREPAINT; + nmcd.hdc = hdc; + nmcd.rc = lpBand->rcBand; + nmcd.rc.right = lpBand->rcCapText.right; + nmcd.rc.bottom = lpBand->rcCapText.bottom; + nmcd.dwItemSpec = lpBand->wID; + nmcd.uItemState = 0; + nmcd.lItemlParam = lpBand->lParam; + lpBand->uCDret = REBAR_Notify ((NMHDR *)&nmcd, infoPtr, NM_CUSTOMDRAW); + if (lpBand->uCDret == CDRF_SKIPDEFAULT) { + if (oldBkMode != TRANSPARENT) + SetBkMode (hdc, oldBkMode); + SelectObject (hdc, hOldFont); + return; + } + + /* draw gripper */ + if (lpBand->fDraw & DRAW_GRIPPER) + DrawEdge (hdc, &lpBand->rcGripper, BDR_RAISEDINNER, BF_RECT | BF_MIDDLE); + + /* draw caption image */ + if (lpBand->fDraw & DRAW_IMAGE) { + POINT pt; + + /* center image */ + pt.y = (lpBand->rcCapImage.bottom + lpBand->rcCapImage.top - infoPtr->imageSize.cy)/2; + pt.x = (lpBand->rcCapImage.right + lpBand->rcCapImage.left - infoPtr->imageSize.cx)/2; + + ImageList_Draw (infoPtr->himl, lpBand->iImage, hdc, + pt.x, pt.y, + ILD_TRANSPARENT); + } + + /* draw caption text */ + if (lpBand->fDraw & DRAW_TEXT) { + /* need to handle CDRF_NEWFONT here */ + INT oldBkMode = SetBkMode (hdc, TRANSPARENT); + COLORREF oldcolor = CLR_NONE; + COLORREF new; + if (lpBand->clrFore != CLR_NONE) { + new = (lpBand->clrFore == CLR_DEFAULT) ? infoPtr->clrBtnText : + lpBand->clrFore; + oldcolor = SetTextColor (hdc, new); + } + DrawTextW (hdc, lpBand->lpText, -1, &lpBand->rcCapText, + DT_CENTER | DT_VCENTER | DT_SINGLELINE); + if (oldBkMode != TRANSPARENT) + SetBkMode (hdc, oldBkMode); + if (lpBand->clrFore != CLR_NONE) + SetTextColor (hdc, oldcolor); + SelectObject (hdc, hOldFont); + } + + if (!IsRectEmpty(&lpBand->rcChevron)) + { + if (lpBand->fDraw & DRAW_CHEVRONPUSHED) + { + DrawEdge(hdc, &lpBand->rcChevron, BDR_SUNKENOUTER, BF_RECT | BF_MIDDLE); + REBAR_DrawChevron(hdc, lpBand->rcChevron.left+1, lpBand->rcChevron.top + 11, COLOR_WINDOWFRAME); + } + else if (lpBand->fDraw & DRAW_CHEVRONHOT) + { + DrawEdge(hdc, &lpBand->rcChevron, BDR_RAISEDINNER, BF_RECT | BF_MIDDLE); + REBAR_DrawChevron(hdc, lpBand->rcChevron.left, lpBand->rcChevron.top + 10, COLOR_WINDOWFRAME); + } + else + REBAR_DrawChevron(hdc, lpBand->rcChevron.left, lpBand->rcChevron.top + 10, COLOR_WINDOWFRAME); + } + + if (lpBand->uCDret == (CDRF_NOTIFYPOSTPAINT | CDRF_NOTIFYITEMDRAW)) { + nmcd.dwDrawStage = CDDS_ITEMPOSTPAINT; + nmcd.hdc = hdc; + nmcd.rc = lpBand->rcBand; + nmcd.rc.right = lpBand->rcCapText.right; + nmcd.rc.bottom = lpBand->rcCapText.bottom; + nmcd.dwItemSpec = lpBand->wID; + nmcd.uItemState = 0; + nmcd.lItemlParam = lpBand->lParam; + lpBand->uCDret = REBAR_Notify ((NMHDR *)&nmcd, infoPtr, NM_CUSTOMDRAW); + } +} + + +static VOID +REBAR_Refresh (REBAR_INFO *infoPtr, HDC hdc) +{ + REBAR_BAND *lpBand; + UINT i; + + if (!infoPtr->DoRedraw) return; + + for (i = 0; i < infoPtr->uNumBands; i++) { + lpBand = &infoPtr->bands[i]; + + if (HIDDENBAND(lpBand)) continue; + + /* now draw the band */ + TRACE("[%p] drawing band %i, flags=%08x\n", + infoPtr->hwndSelf, i, lpBand->fDraw); + REBAR_DrawBand (hdc, infoPtr, lpBand); + + } +} + + +static void +REBAR_FixVert (REBAR_INFO *infoPtr, UINT rowstart, UINT rowend, + INT mcy) + /* Function: */ + /* Cycle through bands in row and fix height of each band. */ + /* Also determine whether each band has changed. */ + /* On entry: */ + /* all bands at desired size. */ + /* start and end bands are *not* hidden */ +{ + REBAR_BAND *lpBand; + INT i; + + for (i = (INT)rowstart; i<=(INT)rowend; i++) { + lpBand = &infoPtr->bands[i]; + if (HIDDENBAND(lpBand)) continue; + + /* adjust height of bands in row to "mcy" value */ + if (infoPtr->dwStyle & CCS_VERT) { + if (lpBand->rcBand.right != lpBand->rcBand.left + mcy) + lpBand->rcBand.right = lpBand->rcBand.left + mcy; + } + else { + if (lpBand->rcBand.bottom != lpBand->rcBand.top + mcy) + lpBand->rcBand.bottom = lpBand->rcBand.top + mcy; + + } + + /* mark whether we need to invalidate this band and trace */ + if ((lpBand->rcoldBand.left !=lpBand->rcBand.left) || + (lpBand->rcoldBand.top !=lpBand->rcBand.top) || + (lpBand->rcoldBand.right !=lpBand->rcBand.right) || + (lpBand->rcoldBand.bottom !=lpBand->rcBand.bottom)) { + lpBand->fDraw |= NTF_INVALIDATE; + TRACE("band %d row=%d: changed to (%ld,%ld)-(%ld,%ld) from (%ld,%ld)-(%ld,%ld)\n", + i, lpBand->iRow, + lpBand->rcBand.left, lpBand->rcBand.top, + lpBand->rcBand.right, lpBand->rcBand.bottom, + lpBand->rcoldBand.left, lpBand->rcoldBand.top, + lpBand->rcoldBand.right, lpBand->rcoldBand.bottom); + } + else + TRACE("band %d row=%d: unchanged (%ld,%ld)-(%ld,%ld)\n", + i, lpBand->iRow, + lpBand->rcBand.left, lpBand->rcBand.top, + lpBand->rcBand.right, lpBand->rcBand.bottom); + } +} + + +static void +REBAR_AdjustBands (REBAR_INFO *infoPtr, UINT rowstart, UINT rowend, + INT maxx, INT mcy) + /* Function: This routine distributes the extra space in a row. */ + /* See algorithm below. */ + /* On entry: */ + /* all bands @ ->cxHeader size */ + /* start and end bands are *not* hidden */ +{ + REBAR_BAND *lpBand; + UINT xsep, extra, curwidth, fudge; + INT x, i, last_adjusted; + + TRACE("start=%u, end=%u, max x=%d, max y=%d\n", + rowstart, rowend, maxx, mcy); + + /* ******************* Phase 1 ************************ */ + /* Alg: */ + /* For each visible band with valid child */ + /* a. inflate band till either all extra space used */ + /* or band's ->ccx reached. */ + /* If any band modified, add any space left to last band */ + /* adjusted. */ + /* */ + /* ****************************************************** */ + lpBand = &infoPtr->bands[rowend]; + extra = maxx - rcBrb(lpBand); + x = 0; + last_adjusted = -1; + for (i=(INT)rowstart; i<=(INT)rowend; i++) { + lpBand = &infoPtr->bands[i]; + if (HIDDENBAND(lpBand)) continue; + xsep = (x == 0) ? 0 : SEP_WIDTH; + curwidth = rcBw(lpBand); + + /* set new left/top point */ + if (infoPtr->dwStyle & CCS_VERT) + lpBand->rcBand.top = x + xsep; + else + lpBand->rcBand.left = x + xsep; + + /* compute new width */ + if ((lpBand->hwndChild && extra) && !(lpBand->fStyle & RBBS_FIXEDSIZE)) { + /* set to the "current" band size less the header */ + fudge = lpBand->ccx; + last_adjusted = i; + if ((lpBand->fMask & RBBIM_SIZE) && (lpBand->cx > 0) && + (fudge > curwidth)) { + TRACE("adjusting band %d by %d, fudge=%d, curwidth=%d, extra=%d\n", + i, fudge-curwidth, fudge, curwidth, extra); + if ((fudge - curwidth) > extra) + fudge = curwidth + extra; + extra -= (fudge - curwidth); + curwidth = fudge; + } + else { + TRACE("adjusting band %d by %d, fudge=%d, curwidth=%d\n", + i, extra, fudge, curwidth); + curwidth += extra; + extra = 0; + } + } + + /* set new right/bottom point */ + if (infoPtr->dwStyle & CCS_VERT) + lpBand->rcBand.bottom = lpBand->rcBand.top + curwidth; + else + lpBand->rcBand.right = lpBand->rcBand.left + curwidth; + TRACE("Phase 1 band %d, (%ld,%ld)-(%ld,%ld), orig x=%d, xsep=%d\n", + i, lpBand->rcBand.left, lpBand->rcBand.top, + lpBand->rcBand.right, lpBand->rcBand.bottom, x, xsep); + x = rcBrb(lpBand); + } + if ((x >= maxx) || (last_adjusted != -1)) { + if (x > maxx) { + ERR("Phase 1 failed, x=%d, maxx=%d, start=%u, end=%u\n", + x, maxx, rowstart, rowend); + } + /* done, so spread extra space */ + if (x < maxx) { + fudge = maxx - x; + TRACE("Need to spread %d on last adjusted band %d\n", + fudge, last_adjusted); + for (i=(INT)last_adjusted; i<=(INT)rowend; i++) { + lpBand = &infoPtr->bands[i]; + if (HIDDENBAND(lpBand)) continue; + + /* set right/bottom point */ + if (i != last_adjusted) { + if (infoPtr->dwStyle & CCS_VERT) + lpBand->rcBand.top += fudge; + else + lpBand->rcBand.left += fudge; + } + + /* set left/bottom point */ + if (infoPtr->dwStyle & CCS_VERT) + lpBand->rcBand.bottom += fudge; + else + lpBand->rcBand.right += fudge; + } + } + TRACE("Phase 1 succeeded, used x=%d\n", x); + REBAR_FixVert (infoPtr, rowstart, rowend, mcy); + return; + } + + /* ******************* Phase 2 ************************ */ + /* Alg: */ + /* Find first visible band, put all */ + /* extra space there. */ + /* */ + /* ****************************************************** */ + + x = 0; + for (i=(INT)rowstart; i<=(INT)rowend; i++) { + lpBand = &infoPtr->bands[i]; + if (HIDDENBAND(lpBand)) continue; + xsep = (x == 0) ? 0 : SEP_WIDTH; + curwidth = rcBw(lpBand); + + /* set new left/top point */ + if (infoPtr->dwStyle & CCS_VERT) + lpBand->rcBand.top = x + xsep; + else + lpBand->rcBand.left = x + xsep; + + /* compute new width */ + if (extra) { + curwidth += extra; + extra = 0; + } + + /* set new right/bottom point */ + if (infoPtr->dwStyle & CCS_VERT) + lpBand->rcBand.bottom = lpBand->rcBand.top + curwidth; + else + lpBand->rcBand.right = lpBand->rcBand.left + curwidth; + TRACE("Phase 2 band %d, (%ld,%ld)-(%ld,%ld), orig x=%d, xsep=%d\n", + i, lpBand->rcBand.left, lpBand->rcBand.top, + lpBand->rcBand.right, lpBand->rcBand.bottom, x, xsep); + x = rcBrb(lpBand); + } + if (x >= maxx) { + if (x > maxx) { + ERR("Phase 2 failed, x=%d, maxx=%d, start=%u, end=%u\n", + x, maxx, rowstart, rowend); + } + /* done, so spread extra space */ + TRACE("Phase 2 succeeded, used x=%d\n", x); + REBAR_FixVert (infoPtr, rowstart, rowend, mcy); + return; + } + + /* ******************* Phase 3 ************************ */ + /* at this point everything is back to ->cxHeader values */ + /* and should not have gotten here. */ + /* ****************************************************** */ + + lpBand = &infoPtr->bands[rowstart]; + ERR("Serious problem adjusting row %d, start band %d, end band %d\n", + lpBand->iRow, rowstart, rowend); + REBAR_DumpBand (infoPtr); + return; +} + + +static void +REBAR_CalcHorzBand (REBAR_INFO *infoPtr, UINT rstart, UINT rend, BOOL notify) + /* Function: this routine initializes all the rectangles in */ + /* each band in a row to fit in the adjusted rcBand rect. */ + /* *** Supports only Horizontal bars. *** */ +{ + REBAR_BAND *lpBand; + UINT i, xoff, yoff; + HWND parenthwnd; + RECT oldChild, work; + + /* MS seems to use GetDlgCtrlID() for above GetWindowLong call */ + parenthwnd = GetParent (infoPtr->hwndSelf); + + for(i=rstart; ibands[i]; + if (HIDDENBAND(lpBand)) { + SetRect (&lpBand->rcChild, + lpBand->rcBand.right, lpBand->rcBand.top, + lpBand->rcBand.right, lpBand->rcBand.bottom); + continue; + } + + oldChild = lpBand->rcChild; + + /* set initial gripper rectangle */ + SetRect (&lpBand->rcGripper, lpBand->rcBand.left, lpBand->rcBand.top, + lpBand->rcBand.left, lpBand->rcBand.bottom); + + /* calculate gripper rectangle */ + if ( lpBand->fStatus & HAS_GRIPPER) { + lpBand->fDraw |= DRAW_GRIPPER; + lpBand->rcGripper.left += REBAR_PRE_GRIPPER; + lpBand->rcGripper.right = lpBand->rcGripper.left + GRIPPER_WIDTH; + lpBand->rcGripper.top += 2; + lpBand->rcGripper.bottom -= 2; + + SetRect (&lpBand->rcCapImage, + lpBand->rcGripper.right+REBAR_ALWAYS_SPACE, lpBand->rcBand.top, + lpBand->rcGripper.right+REBAR_ALWAYS_SPACE, lpBand->rcBand.bottom); + } + else { /* no gripper will be drawn */ + xoff = 0; + if (lpBand->fStatus & (HAS_IMAGE | HAS_TEXT)) + /* if no gripper but either image or text, then leave space */ + xoff = REBAR_ALWAYS_SPACE; + SetRect (&lpBand->rcCapImage, + lpBand->rcBand.left+xoff, lpBand->rcBand.top, + lpBand->rcBand.left+xoff, lpBand->rcBand.bottom); + } + + /* image is visible */ + if (lpBand->fStatus & HAS_IMAGE) { + lpBand->fDraw |= DRAW_IMAGE; + lpBand->rcCapImage.right += infoPtr->imageSize.cx; + lpBand->rcCapImage.bottom = lpBand->rcCapImage.top + infoPtr->imageSize.cy; + + /* set initial caption text rectangle */ + SetRect (&lpBand->rcCapText, + lpBand->rcCapImage.right+REBAR_POST_IMAGE, lpBand->rcBand.top+1, + lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.bottom-1); + /* update band height + if (lpBand->uMinHeight < infoPtr->imageSize.cy + 2) { + lpBand->uMinHeight = infoPtr->imageSize.cy + 2; + lpBand->rcBand.bottom = lpBand->rcBand.top + lpBand->uMinHeight; + } */ + } + else { + /* set initial caption text rectangle */ + SetRect (&lpBand->rcCapText, lpBand->rcCapImage.right, lpBand->rcBand.top+1, + lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.bottom-1); + } + + /* text is visible */ + if ((lpBand->fStatus & HAS_TEXT) && !(lpBand->fStyle & RBBS_HIDETITLE)) { + lpBand->fDraw |= DRAW_TEXT; + lpBand->rcCapText.right = max(lpBand->rcCapText.left, + lpBand->rcCapText.right-REBAR_POST_TEXT); + } + + /* set initial child window rectangle if there is a child */ + if (lpBand->fMask & RBBIM_CHILD) { + xoff = lpBand->offChild.cx; + yoff = lpBand->offChild.cy; + SetRect (&lpBand->rcChild, + lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.top+yoff, + lpBand->rcBand.right-xoff, lpBand->rcBand.bottom-yoff); + if ((lpBand->fStyle & RBBS_USECHEVRON) && (lpBand->rcChild.right - lpBand->rcChild.left < lpBand->cxIdeal)) + { + lpBand->rcChild.right -= CHEVRON_WIDTH; + SetRect(&lpBand->rcChevron, lpBand->rcChild.right, + lpBand->rcChild.top, lpBand->rcChild.right + CHEVRON_WIDTH, + lpBand->rcChild.bottom); + } + } + else { + SetRect (&lpBand->rcChild, + lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.top, + lpBand->rcBand.right, lpBand->rcBand.bottom); + } + + /* flag if notify required and invalidate rectangle */ + if (notify && + ((oldChild.right-oldChild.left != lpBand->rcChild.right-lpBand->rcChild.left) || + (oldChild.bottom-oldChild.top != lpBand->rcChild.bottom-lpBand->rcChild.top))) { + TRACE("Child rectangle changed for band %u\n", i); + TRACE(" from (%ld,%ld)-(%ld,%ld) to (%ld,%ld)-(%ld,%ld)\n", + oldChild.left, oldChild.top, + oldChild.right, oldChild.bottom, + lpBand->rcChild.left, lpBand->rcChild.top, + lpBand->rcChild.right, lpBand->rcChild.bottom); + } + if (lpBand->fDraw & NTF_INVALIDATE) { + TRACE("invalidating (%ld,%ld)-(%ld,%ld)\n", + lpBand->rcBand.left, + lpBand->rcBand.top, + lpBand->rcBand.right + ((lpBand->fDraw & DRAW_RIGHTSEP) ? SEP_WIDTH_SIZE : 0), + lpBand->rcBand.bottom + ((lpBand->fDraw & DRAW_BOTTOMSEP) ? SEP_WIDTH_SIZE : 0)); + lpBand->fDraw &= ~NTF_INVALIDATE; + work = lpBand->rcBand; + if (lpBand->fDraw & DRAW_RIGHTSEP) work.right += SEP_WIDTH_SIZE; + if (lpBand->fDraw & DRAW_BOTTOMSEP) work.bottom += SEP_WIDTH_SIZE; + InvalidateRect(infoPtr->hwndSelf, &work, TRUE); + } + + } + +} + + +static VOID +REBAR_CalcVertBand (REBAR_INFO *infoPtr, UINT rstart, UINT rend, BOOL notify) + /* Function: this routine initializes all the rectangles in */ + /* each band in a row to fit in the adjusted rcBand rect. */ + /* *** Supports only Vertical bars. *** */ +{ + REBAR_BAND *lpBand; + UINT i, xoff, yoff; + HWND parenthwnd; + RECT oldChild, work; + + /* MS seems to use GetDlgCtrlID() for above GetWindowLong call */ + parenthwnd = GetParent (infoPtr->hwndSelf); + + for(i=rstart; ibands[i]; + if (HIDDENBAND(lpBand)) continue; + oldChild = lpBand->rcChild; + + /* set initial gripper rectangle */ + SetRect (&lpBand->rcGripper, lpBand->rcBand.left, lpBand->rcBand.top, + lpBand->rcBand.right, lpBand->rcBand.top); + + /* calculate gripper rectangle */ + if (lpBand->fStatus & HAS_GRIPPER) { + lpBand->fDraw |= DRAW_GRIPPER; + + if (infoPtr->dwStyle & RBS_VERTICALGRIPPER) { + /* vertical gripper */ + lpBand->rcGripper.left += 3; + lpBand->rcGripper.right = lpBand->rcGripper.left + GRIPPER_WIDTH; + lpBand->rcGripper.top += REBAR_PRE_GRIPPER; + lpBand->rcGripper.bottom = lpBand->rcGripper.top + GRIPPER_HEIGHT; + + /* initialize Caption image rectangle */ + SetRect (&lpBand->rcCapImage, lpBand->rcBand.left, + lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE, + lpBand->rcBand.right, + lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE); + } + else { + /* horizontal gripper */ + lpBand->rcGripper.left += 2; + lpBand->rcGripper.right -= 2; + lpBand->rcGripper.top += REBAR_PRE_GRIPPER; + lpBand->rcGripper.bottom = lpBand->rcGripper.top + GRIPPER_WIDTH; + + /* initialize Caption image rectangle */ + SetRect (&lpBand->rcCapImage, lpBand->rcBand.left, + lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE, + lpBand->rcBand.right, + lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE); + } + } + else { /* no gripper will be drawn */ + xoff = 0; + if (lpBand->fStatus & (HAS_IMAGE | HAS_TEXT)) + /* if no gripper but either image or text, then leave space */ + xoff = REBAR_ALWAYS_SPACE; + /* initialize Caption image rectangle */ + SetRect (&lpBand->rcCapImage, + lpBand->rcBand.left, lpBand->rcBand.top+xoff, + lpBand->rcBand.right, lpBand->rcBand.top+xoff); + } + + /* image is visible */ + if (lpBand->fStatus & HAS_IMAGE) { + lpBand->fDraw |= DRAW_IMAGE; + + lpBand->rcCapImage.right = lpBand->rcCapImage.left + infoPtr->imageSize.cx; + lpBand->rcCapImage.bottom += infoPtr->imageSize.cy; + + /* set initial caption text rectangle */ + SetRect (&lpBand->rcCapText, + lpBand->rcBand.left, lpBand->rcCapImage.bottom+REBAR_POST_IMAGE, + lpBand->rcBand.right, lpBand->rcBand.top+lpBand->cxHeader); + /* update band height * + if (lpBand->uMinHeight < infoPtr->imageSize.cx + 2) { + lpBand->uMinHeight = infoPtr->imageSize.cx + 2; + lpBand->rcBand.right = lpBand->rcBand.left + lpBand->uMinHeight; + } */ + } + else { + /* set initial caption text rectangle */ + SetRect (&lpBand->rcCapText, + lpBand->rcBand.left, lpBand->rcCapImage.bottom, + lpBand->rcBand.right, lpBand->rcBand.top+lpBand->cxHeader); + } + + /* text is visible */ + if ((lpBand->fStatus & HAS_TEXT) && !(lpBand->fStyle & RBBS_HIDETITLE)) { + lpBand->fDraw |= DRAW_TEXT; + lpBand->rcCapText.bottom = max(lpBand->rcCapText.top, + lpBand->rcCapText.bottom); + } + + /* set initial child window rectangle if there is a child */ + if (lpBand->fMask & RBBIM_CHILD) { + yoff = lpBand->offChild.cx; + xoff = lpBand->offChild.cy; + SetRect (&lpBand->rcChild, + lpBand->rcBand.left+xoff, lpBand->rcBand.top+lpBand->cxHeader, + lpBand->rcBand.right-xoff, lpBand->rcBand.bottom-yoff); + } + else { + SetRect (&lpBand->rcChild, + lpBand->rcBand.left, lpBand->rcBand.top+lpBand->cxHeader, + lpBand->rcBand.right, lpBand->rcBand.bottom); + } + + /* flag if notify required and invalidate rectangle */ + if (notify && + ((oldChild.right-oldChild.left != lpBand->rcChild.right-lpBand->rcChild.left) || + (oldChild.bottom-oldChild.top != lpBand->rcChild.bottom-lpBand->rcChild.top))) { + TRACE("Child rectangle changed for band %u\n", i); + TRACE(" from (%ld,%ld)-(%ld,%ld) to (%ld,%ld)-(%ld,%ld)\n", + oldChild.left, oldChild.top, + oldChild.right, oldChild.bottom, + lpBand->rcChild.left, lpBand->rcChild.top, + lpBand->rcChild.right, lpBand->rcChild.bottom); + } + if (lpBand->fDraw & NTF_INVALIDATE) { + TRACE("invalidating (%ld,%ld)-(%ld,%ld)\n", + lpBand->rcBand.left, + lpBand->rcBand.top, + lpBand->rcBand.right + ((lpBand->fDraw & DRAW_BOTTOMSEP) ? SEP_WIDTH_SIZE : 0), + lpBand->rcBand.bottom + ((lpBand->fDraw & DRAW_RIGHTSEP) ? SEP_WIDTH_SIZE : 0)); + lpBand->fDraw &= ~NTF_INVALIDATE; + work = lpBand->rcBand; + if (lpBand->fDraw & DRAW_RIGHTSEP) work.bottom += SEP_WIDTH_SIZE; + if (lpBand->fDraw & DRAW_BOTTOMSEP) work.right += SEP_WIDTH_SIZE; + InvalidateRect(infoPtr->hwndSelf, &work, TRUE); + } + + } +} + + +static VOID +REBAR_ForceResize (REBAR_INFO *infoPtr) + /* Function: This changes the size of the REBAR window to that */ + /* calculated by REBAR_Layout. */ +{ + RECT rc; + INT x, y, width, height; + INT xedge = GetSystemMetrics(SM_CXEDGE); + INT yedge = GetSystemMetrics(SM_CYEDGE); + + GetClientRect (infoPtr->hwndSelf, &rc); + + TRACE( " old [%ld x %ld], new [%ld x %ld], client [%ld x %ld]\n", + infoPtr->oldSize.cx, infoPtr->oldSize.cy, + infoPtr->calcSize.cx, infoPtr->calcSize.cy, + rc.right, rc.bottom); + + /* If we need to shrink client, then skip size test */ + if ((infoPtr->calcSize.cy >= rc.bottom) && + (infoPtr->calcSize.cx >= rc.right)) { + + /* if size did not change then skip process */ + if ((infoPtr->oldSize.cx == infoPtr->calcSize.cx) && + (infoPtr->oldSize.cy == infoPtr->calcSize.cy) && + !(infoPtr->fStatus & RESIZE_ANYHOW)) + { + TRACE("skipping reset\n"); + return; + } + } + + infoPtr->fStatus &= ~RESIZE_ANYHOW; + /* Set flag to ignore next WM_SIZE message */ + infoPtr->fStatus |= AUTO_RESIZE; + + width = 0; + height = 0; + x = 0; + y = 0; + + if (infoPtr->dwStyle & WS_BORDER) { + width = 2 * xedge; + height = 2 * yedge; + } + + if (!(infoPtr->dwStyle & CCS_NOPARENTALIGN)) { + INT mode = infoPtr->dwStyle & (CCS_VERT | CCS_TOP | CCS_BOTTOM); + RECT rcPcl; + + GetClientRect(GetParent(infoPtr->hwndSelf), &rcPcl); + switch (mode) { + case CCS_TOP: + /* _TOP sets width to parents width */ + width += (rcPcl.right - rcPcl.left); + height += infoPtr->calcSize.cy; + x += ((infoPtr->dwStyle & WS_BORDER) ? -xedge : 0); + y += ((infoPtr->dwStyle & WS_BORDER) ? -yedge : 0); + y += ((infoPtr->dwStyle & CCS_NODIVIDER) ? 0 : REBAR_DIVIDER); + break; + case CCS_BOTTOM: + /* FIXME: wrong wrong wrong */ + /* _BOTTOM sets width to parents width */ + width += (rcPcl.right - rcPcl.left); + height += infoPtr->calcSize.cy; + x += -xedge; + y = rcPcl.bottom - height + 1; + break; + case CCS_LEFT: + /* _LEFT sets height to parents height */ + width += infoPtr->calcSize.cx; + height += (rcPcl.bottom - rcPcl.top); + x += ((infoPtr->dwStyle & WS_BORDER) ? -xedge : 0); + x += ((infoPtr->dwStyle & CCS_NODIVIDER) ? 0 : REBAR_DIVIDER); + y += ((infoPtr->dwStyle & WS_BORDER) ? -yedge : 0); + break; + case CCS_RIGHT: + /* FIXME: wrong wrong wrong */ + /* _RIGHT sets height to parents height */ + width += infoPtr->calcSize.cx; + height += (rcPcl.bottom - rcPcl.top); + x = rcPcl.right - width + 1; + y = -yedge; + break; + default: + width += infoPtr->calcSize.cx; + height += infoPtr->calcSize.cy; + } + } + else { + width += infoPtr->calcSize.cx; + height += infoPtr->calcSize.cy; + x = infoPtr->origin.x; + y = infoPtr->origin.y; + } + + TRACE("hwnd %p, style=%08lx, setting at (%d,%d) for (%d,%d)\n", + infoPtr->hwndSelf, infoPtr->dwStyle, + x, y, width, height); + SetWindowPos (infoPtr->hwndSelf, 0, x, y, width, height, + SWP_NOZORDER); + infoPtr->fStatus &= ~AUTO_RESIZE; +} + + +static VOID +REBAR_MoveChildWindows (REBAR_INFO *infoPtr, UINT start, UINT endplus) +{ + const static WCHAR strComboBox[] = { 'C','o','m','b','o','B','o','x',0 }; + REBAR_BAND *lpBand; + WCHAR szClassName[40]; + UINT i; + NMREBARCHILDSIZE rbcz; + NMHDR heightchange; + HDWP deferpos; + + if (!(deferpos = BeginDeferWindowPos(infoPtr->uNumBands))) + ERR("BeginDeferWindowPos returned NULL\n"); + + for (i = start; i < endplus; i++) { + lpBand = &infoPtr->bands[i]; + + if (HIDDENBAND(lpBand)) continue; + if (lpBand->hwndChild) { + TRACE("hwndChild = %p\n", lpBand->hwndChild); + + /* Always geterate the RBN_CHILDSIZE even it child + did not change */ + rbcz.uBand = i; + rbcz.wID = lpBand->wID; + rbcz.rcChild = lpBand->rcChild; + rbcz.rcBand = lpBand->rcBand; + if (infoPtr->dwStyle & CCS_VERT) + rbcz.rcBand.top += lpBand->cxHeader; + else + rbcz.rcBand.left += lpBand->cxHeader; + REBAR_Notify ((NMHDR *)&rbcz, infoPtr, RBN_CHILDSIZE); + if (!EqualRect (&lpBand->rcChild, &rbcz.rcChild)) { + TRACE("Child rect changed by NOTIFY for band %u\n", i); + TRACE(" from (%ld,%ld)-(%ld,%ld) to (%ld,%ld)-(%ld,%ld)\n", + lpBand->rcChild.left, lpBand->rcChild.top, + lpBand->rcChild.right, lpBand->rcChild.bottom, + rbcz.rcChild.left, rbcz.rcChild.top, + rbcz.rcChild.right, rbcz.rcChild.bottom); + lpBand->rcChild = rbcz.rcChild; /* *** ??? */ + } + + /* native (IE4 in "Favorites" frame **1) does: + * SetRect (&rc, -1, -1, -1, -1) + * EqualRect (&rc,band->rc???) + * if ret==0 + * CopyRect (band->rc????, &rc) + * set flag outside of loop + */ + + GetClassNameW (lpBand->hwndChild, szClassName, sizeof(szClassName)/sizeof(szClassName[0])); + if (!lstrcmpW (szClassName, strComboBox) || + !lstrcmpW (szClassName, WC_COMBOBOXEXW)) { + INT nEditHeight, yPos; + RECT rc; + + /* special placement code for combo or comboex box */ + + + /* get size of edit line */ + GetWindowRect (lpBand->hwndChild, &rc); + nEditHeight = rc.bottom - rc.top; + yPos = (lpBand->rcChild.bottom + lpBand->rcChild.top - nEditHeight)/2; + + /* center combo box inside child area */ + TRACE("moving child (Combo(Ex)) %p to (%ld,%d) for (%ld,%d)\n", + lpBand->hwndChild, + lpBand->rcChild.left, yPos, + lpBand->rcChild.right - lpBand->rcChild.left, + nEditHeight); + deferpos = DeferWindowPos (deferpos, lpBand->hwndChild, HWND_TOP, + lpBand->rcChild.left, + /*lpBand->rcChild.top*/ yPos, + lpBand->rcChild.right - lpBand->rcChild.left, + nEditHeight, + SWP_NOZORDER); + if (!deferpos) + ERR("DeferWindowPos returned NULL\n"); + } + else { + TRACE("moving child (Other) %p to (%ld,%ld) for (%ld,%ld)\n", + lpBand->hwndChild, + lpBand->rcChild.left, lpBand->rcChild.top, + lpBand->rcChild.right - lpBand->rcChild.left, + lpBand->rcChild.bottom - lpBand->rcChild.top); + deferpos = DeferWindowPos (deferpos, lpBand->hwndChild, HWND_TOP, + lpBand->rcChild.left, + lpBand->rcChild.top, + lpBand->rcChild.right - lpBand->rcChild.left, + lpBand->rcChild.bottom - lpBand->rcChild.top, + SWP_NOZORDER); + if (!deferpos) + ERR("DeferWindowPos returned NULL\n"); + } + } + } + if (!EndDeferWindowPos(deferpos)) + ERR("EndDeferWindowPos returned NULL\n"); + + if (infoPtr->DoRedraw) + UpdateWindow (infoPtr->hwndSelf); + + if (infoPtr->fStatus & NTF_HGHTCHG) { + infoPtr->fStatus &= ~NTF_HGHTCHG; + /* + * We need to force a resize here, because some applications + * try to get the rebar size during processing of the + * RBN_HEIGHTCHANGE notification. + */ + REBAR_ForceResize (infoPtr); + REBAR_Notify (&heightchange, infoPtr, RBN_HEIGHTCHANGE); + } + + /* native (from **1 above) does: + * UpdateWindow(rebar) + * REBAR_ForceResize + * RBN_HEIGHTCHANGE if necessary + * if ret from any EqualRect was 0 + * Goto "BeginDeferWindowPos" + */ + +} + + +static VOID +REBAR_Layout (REBAR_INFO *infoPtr, LPRECT lpRect, BOOL notify, BOOL resetclient) + /* Function: This routine is resposible for laying out all */ + /* the bands in a rebar. It assigns each band to a row and*/ + /* determines when to start a new row. */ +{ + REBAR_BAND *lpBand, *prevBand; + RECT rcClient, rcAdj; + INT initx, inity, x, y, cx, cxsep, mmcy, mcy, clientcx, clientcy; + INT adjcx, adjcy, row, rightx, bottomy, origheight; + UINT i, j, rowstart, origrows, cntonrow; + BOOL dobreak; + + if (!(infoPtr->fStatus & BAND_NEEDS_LAYOUT)) { + TRACE("no layout done. No band changed.\n"); + REBAR_DumpBand (infoPtr); + return; + } + infoPtr->fStatus &= ~BAND_NEEDS_LAYOUT; + if (!infoPtr->DoRedraw) infoPtr->fStatus |= BAND_NEEDS_REDRAW; + + GetClientRect (infoPtr->hwndSelf, &rcClient); + TRACE("Client is (%ld,%ld)-(%ld,%ld)\n", + rcClient.left, rcClient.top, rcClient.right, rcClient.bottom); + + if (lpRect) { + rcAdj = *lpRect; + TRACE("adjustment rect is (%ld,%ld)-(%ld,%ld)\n", + rcAdj.left, rcAdj.top, rcAdj.right, rcAdj.bottom); + } + else { + CopyRect (&rcAdj, &rcClient); + } + + clientcx = rcClient.right - rcClient.left; + clientcy = rcClient.bottom - rcClient.top; + adjcx = rcAdj.right - rcAdj.left; + adjcy = rcAdj.bottom - rcAdj.top; + if (resetclient) { + TRACE("window client rect will be set to adj rect\n"); + clientcx = adjcx; + clientcy = adjcy; + } + + if (!infoPtr->DoRedraw && (clientcx == 0) && (clientcy == 0)) { + ERR("no redraw and client is zero, skip layout\n"); + infoPtr->fStatus |= BAND_NEEDS_LAYOUT; + return; + } + + /* save height of original control */ + if (infoPtr->dwStyle & CCS_VERT) + origheight = infoPtr->calcSize.cx; + else + origheight = infoPtr->calcSize.cy; + origrows = infoPtr->uNumRows; + + initx = 0; + inity = 0; + + /* ******* Start Phase 1 - all bands on row at minimum size ******* */ + + TRACE("band loop constants, clientcx=%d, clientcy=%d, adjcx=%d, adjcy=%d\n", + clientcx, clientcy, adjcx, adjcy); + x = initx; + y = inity; + row = 0; + cx = 0; + mcy = 0; + rowstart = 0; + prevBand = NULL; + cntonrow = 0; + + for (i = 0; i < infoPtr->uNumBands; i++) { + lpBand = &infoPtr->bands[i]; + lpBand->fDraw = 0; + lpBand->iRow = row; + + SetRectEmpty(&lpBand->rcChevron); + + if (HIDDENBAND(lpBand)) continue; + + lpBand->rcoldBand = lpBand->rcBand; + + /* Set the offset of the child window */ + if ((lpBand->fMask & RBBIM_CHILD) && + !(lpBand->fStyle & RBBS_FIXEDSIZE)) { + lpBand->offChild.cx = ((lpBand->fStyle & RBBS_CHILDEDGE) ? 4 : 0); + } + lpBand->offChild.cy = ((lpBand->fStyle & RBBS_CHILDEDGE) ? 2 : 0); + + /* separator from previous band */ + cxsep = (cntonrow == 0) ? 0 : SEP_WIDTH; + cx = lpBand->lcx; + + if (infoPtr->dwStyle & CCS_VERT) + dobreak = (y + cx + cxsep > adjcy); + else + dobreak = (x + cx + cxsep > adjcx); + + /* This is the check for whether we need to start a new row */ + if ( ( (lpBand->fStyle & RBBS_BREAK) && (i != 0) ) || + ( ((infoPtr->dwStyle & CCS_VERT) ? (y != 0) : (x != 0)) && dobreak)) { + + for (j = rowstart; j < i; j++) { + REBAR_BAND *lpB; + lpB = &infoPtr->bands[j]; + if (infoPtr->dwStyle & CCS_VERT) { + lpB->rcBand.right = lpB->rcBand.left + mcy; + } + else { + lpB->rcBand.bottom = lpB->rcBand.top + mcy; + } + } + + TRACE("P1 Spliting to new row %d on band %u\n", row+1, i); + if (infoPtr->dwStyle & CCS_VERT) { + y = inity; + x += (mcy + SEP_WIDTH); + } + else { + x = initx; + y += (mcy + SEP_WIDTH); + } + + mcy = 0; + cxsep = 0; + row++; + lpBand->iRow = row; + prevBand = NULL; + rowstart = i; + cntonrow = 0; + } + + if (mcy < lpBand->lcy + REBARSPACE(lpBand)) + mcy = lpBand->lcy + REBARSPACE(lpBand); + + /* if boundary rect specified then limit mcy */ + if (lpRect) { + if (infoPtr->dwStyle & CCS_VERT) { + if (x+mcy > adjcx) { + mcy = adjcx - x; + TRACE("P1 row %u limiting mcy=%d, adjcx=%d, x=%d\n", + i, mcy, adjcx, x); + } + } + else { + if (y+mcy > adjcy) { + mcy = adjcy - y; + TRACE("P1 row %u limiting mcy=%d, adjcy=%d, y=%d\n", + i, mcy, adjcy, y); + } + } + } + + TRACE("P1 band %u, row %d, x=%d, y=%d, cxsep=%d, cx=%d\n", + i, row, + x, y, cxsep, cx); + if (infoPtr->dwStyle & CCS_VERT) { + /* bound the bottom side if we have a bounding rectangle */ + rightx = clientcx; + bottomy = (lpRect) ? min(clientcy, y+cxsep+cx) : y+cxsep+cx; + lpBand->rcBand.left = x; + lpBand->rcBand.right = x + min(mcy, + lpBand->lcy+REBARSPACE(lpBand)); + lpBand->rcBand.top = min(bottomy, y + cxsep); + lpBand->rcBand.bottom = bottomy; + lpBand->uMinHeight = lpBand->lcy; + y = bottomy; + } + else { + /* bound the right side if we have a bounding rectangle */ + rightx = (lpRect) ? min(clientcx, x+cxsep+cx) : x+cxsep+cx; + bottomy = clientcy; + lpBand->rcBand.left = min(rightx, x + cxsep); + lpBand->rcBand.right = rightx; + lpBand->rcBand.top = y; + lpBand->rcBand.bottom = y + min(mcy, + lpBand->lcy+REBARSPACE(lpBand)); + lpBand->uMinHeight = lpBand->lcy; + x = rightx; + } + TRACE("P1 band %u, row %d, (%ld,%ld)-(%ld,%ld)\n", + i, row, + lpBand->rcBand.left, lpBand->rcBand.top, + lpBand->rcBand.right, lpBand->rcBand.bottom); + prevBand = lpBand; + cntonrow++; + + } /* for (i = 0; i < infoPtr->uNumBands... */ + + if (infoPtr->dwStyle & CCS_VERT) + x += mcy; + else + y += mcy; + + for (j = rowstart; j < infoPtr->uNumBands; j++) { + lpBand = &infoPtr->bands[j]; + if (infoPtr->dwStyle & CCS_VERT) { + lpBand->rcBand.right = lpBand->rcBand.left + mcy; + } + else { + lpBand->rcBand.bottom = lpBand->rcBand.top + mcy; + } + } + + if (infoPtr->uNumBands) + infoPtr->uNumRows = row + 1; + + /* ******* End Phase 1 - all bands on row at minimum size ******* */ + + + /* ******* Start Phase 1a - Adjust heights for RBS_VARHEIGHT off ******* */ + + mmcy = 0; + if (!(infoPtr->dwStyle & RBS_VARHEIGHT)) { + INT xy; + + /* get the max height of all bands */ + for (i=0; iuNumBands; i++) { + lpBand = &infoPtr->bands[i]; + if (HIDDENBAND(lpBand)) continue; + if (infoPtr->dwStyle & CCS_VERT) + mmcy = max(mmcy, lpBand->rcBand.right - lpBand->rcBand.left); + else + mmcy = max(mmcy, lpBand->rcBand.bottom - lpBand->rcBand.top); + } + + /* now adjust all rectangles by using the height found above */ + xy = 0; + row = 0; + for (i=0; iuNumBands; i++) { + lpBand = &infoPtr->bands[i]; + if (HIDDENBAND(lpBand)) continue; + if (lpBand->iRow != row) + xy += (mmcy + SEP_WIDTH); + if (infoPtr->dwStyle & CCS_VERT) { + lpBand->rcBand.left = xy; + lpBand->rcBand.right = xy + mmcy; + } + else { + lpBand->rcBand.top = xy; + lpBand->rcBand.bottom = xy + mmcy; + } + } + + /* set the x/y values to the correct maximum */ + if (infoPtr->dwStyle & CCS_VERT) + x = xy + mmcy; + else + y = xy + mmcy; + } + + /* ******* End Phase 1a - Adjust heights for RBS_VARHEIGHT off ******* */ + + + /* ******* Start Phase 2 - split rows till adjustment height full ******* */ + + /* assumes that the following variables contain: */ + /* y/x current height/width of all rows */ + if (lpRect) { + INT i, prev_rh, new_rh, adj_rh, prev_idx, current_idx; + REBAR_BAND *prev, *current, *walk; + UINT j; + +/* FIXME: problem # 2 */ + if (((infoPtr->dwStyle & CCS_VERT) ? +#if PROBLEM2 + (x < adjcx) : (y < adjcy) +#else + (adjcx - x > 5) : (adjcy - y > 4) +#endif + ) && + (infoPtr->uNumBands > 1)) { + for (i=(INT)infoPtr->uNumBands-2; i>=0; i--) { + TRACE("P2 adjcx=%d, adjcy=%d, x=%d, y=%d\n", + adjcx, adjcy, x, y); + + /* find the current band (starts at i+1) */ + current = &infoPtr->bands[i+1]; + current_idx = i+1; + while (HIDDENBAND(current)) { + i--; + if (i < 0) break; /* out of bands */ + current = &infoPtr->bands[i+1]; + current_idx = i+1; + } + if (i < 0) break; /* out of bands */ + + /* now find the prev band (starts at i) */ + prev = &infoPtr->bands[i]; + prev_idx = i; + while (HIDDENBAND(prev)) { + i--; + if (i < 0) break; /* out of bands */ + prev = &infoPtr->bands[i]; + prev_idx = i; + } + if (i < 0) break; /* out of bands */ + + prev_rh = ircBw(prev); + if (prev->iRow == current->iRow) { + new_rh = (infoPtr->dwStyle & RBS_VARHEIGHT) ? + current->lcy + REBARSPACE(current) : + mmcy; + adj_rh = new_rh + SEP_WIDTH; + infoPtr->uNumRows++; + current->fDraw |= NTF_INVALIDATE; + current->iRow++; + if (infoPtr->dwStyle & CCS_VERT) { + current->rcBand.top = inity; + current->rcBand.bottom = clientcy; + current->rcBand.left += (prev_rh + SEP_WIDTH); + current->rcBand.right = current->rcBand.left + new_rh; + x += adj_rh; + } + else { + current->rcBand.left = initx; + current->rcBand.right = clientcx; + current->rcBand.top += (prev_rh + SEP_WIDTH); + current->rcBand.bottom = current->rcBand.top + new_rh; + y += adj_rh; + } + TRACE("P2 moving band %d to own row at (%ld,%ld)-(%ld,%ld)\n", + current_idx, + current->rcBand.left, current->rcBand.top, + current->rcBand.right, current->rcBand.bottom); + TRACE("P2 prev band %d at (%ld,%ld)-(%ld,%ld)\n", + prev_idx, + prev->rcBand.left, prev->rcBand.top, + prev->rcBand.right, prev->rcBand.bottom); + TRACE("P2 values: prev_rh=%d, new_rh=%d, adj_rh=%d\n", + prev_rh, new_rh, adj_rh); + /* for bands below current adjust row # and top/bottom */ + for (j = current_idx+1; juNumBands; j++) { + walk = &infoPtr->bands[j]; + if (HIDDENBAND(walk)) continue; + walk->fDraw |= NTF_INVALIDATE; + walk->iRow++; + if (infoPtr->dwStyle & CCS_VERT) { + walk->rcBand.left += adj_rh; + walk->rcBand.right += adj_rh; + } + else { + walk->rcBand.top += adj_rh; + walk->rcBand.bottom += adj_rh; + } + } + if ((infoPtr->dwStyle & CCS_VERT) ? (x >= adjcx) : (y >= adjcy)) + break; /* all done */ + } + } + } + } + + /* ******* End Phase 2 - split rows till adjustment height full ******* */ + + + /* ******* Start Phase 2a - mark first and last band in each ******* */ + + prevBand = NULL; + for (i = 0; i < infoPtr->uNumBands; i++) { + lpBand = &infoPtr->bands[i]; + if (HIDDENBAND(lpBand)) + continue; + if( !prevBand ) { + lpBand->fDraw |= DRAW_FIRST_IN_ROW; + prevBand = lpBand; + } + else if( prevBand->iRow == lpBand->iRow ) + prevBand = lpBand; + else { + prevBand->fDraw |= DRAW_LAST_IN_ROW; + lpBand->fDraw |= DRAW_FIRST_IN_ROW; + prevBand = lpBand; + } + } + if( prevBand ) + prevBand->fDraw |= DRAW_LAST_IN_ROW; + + /* ******* End Phase 2a - mark first and last band in each ******* */ + + + /* ******* Start Phase 2b - adjust all bands for height full ******* */ + /* assumes that the following variables contain: */ + /* y/x current height/width of all rows */ + /* clientcy/clientcx height/width of client area */ + + if (((infoPtr->dwStyle & CCS_VERT) ? clientcx > x : clientcy > y) && + infoPtr->uNumBands) { + INT diff, i; + UINT j; + + diff = (infoPtr->dwStyle & CCS_VERT) ? clientcx - x : clientcy - y; + + /* iterate backwards thru the rows */ + for (i = infoPtr->uNumBands-1; i>=0; i--) { + lpBand = &infoPtr->bands[i]; + if(HIDDENBAND(lpBand)) continue; + + /* if row has more than 1 band, ignore it */ + if( !(lpBand->fDraw&DRAW_FIRST_IN_ROW) ) + continue; + if( !(lpBand->fDraw&DRAW_LAST_IN_ROW) ) + continue; + + /* FIXME: this next line is wrong, but fixing it to be inverted causes IE's sidebars to be the wrong size */ + if (lpBand->fMask & RBBS_VARIABLEHEIGHT) continue; + if (((INT)lpBand->cyMaxChild < 1) || + ((INT)lpBand->cyIntegral < 1)) { + if (lpBand->cyMaxChild + lpBand->cyIntegral == 0) continue; + ERR("P2b band %u RBBS_VARIABLEHEIGHT set but cyMax=%d, cyInt=%d\n", + i, lpBand->cyMaxChild, lpBand->cyIntegral); + continue; + } + /* j is now the maximum height/width in the client area */ + j = ((diff / lpBand->cyIntegral) * lpBand->cyIntegral) + + ircBw(lpBand); + if (j > lpBand->cyMaxChild + REBARSPACE(lpBand)) + j = lpBand->cyMaxChild + REBARSPACE(lpBand); + diff -= (j - ircBw(lpBand)); + if (infoPtr->dwStyle & CCS_VERT) + lpBand->rcBand.right = lpBand->rcBand.left + j; + else + lpBand->rcBand.bottom = lpBand->rcBand.top + j; + TRACE("P2b band %d, row %d changed to (%ld,%ld)-(%ld,%ld)\n", + i, lpBand->iRow, + lpBand->rcBand.left, lpBand->rcBand.top, + lpBand->rcBand.right, lpBand->rcBand.bottom); + if (diff <= 0) break; + } + if (diff < 0) { + ERR("P2b allocated more than available, diff=%d\n", diff); + diff = 0; + } + if (infoPtr->dwStyle & CCS_VERT) + x = clientcx - diff; + else + y = clientcy - diff; + } + + /* ******* End Phase 2b - adjust all bands for height full ******* */ + + + /* ******* Start Phase 3 - adjust all bands for width full ******* */ + + if (infoPtr->uNumBands) { + int startband; + + /* If RBS_BANDBORDERS set then indicate to draw bottom separator */ + /* on all bands in all rows but last row. */ + /* Also indicate to draw the right separator for each band in */ + /* each row but the rightmost band. */ + if (infoPtr->dwStyle & RBS_BANDBORDERS) { + + for (i=0; iuNumBands; i++) { + lpBand = &infoPtr->bands[i]; + if (HIDDENBAND(lpBand)) + continue; + + /* not righthand bands */ + if( !(lpBand->fDraw & DRAW_LAST_IN_ROW) ) + lpBand->fDraw |= DRAW_RIGHTSEP; + + /* not the last row */ + if( lpBand->iRow != infoPtr->uNumRows ) + lpBand->fDraw |= DRAW_BOTTOMSEP; + } + } + + /* Distribute the extra space on the horizontal and adjust */ + /* all bands in row to same height. */ + mcy = 0; + startband = -1; + for (i=0; iuNumBands; i++) { + + lpBand = &infoPtr->bands[i]; + + if( lpBand->fDraw & DRAW_FIRST_IN_ROW ) + { + startband = i; + mcy = 0; + } + + if ( (mcy < ircBw(lpBand)) && !HIDDENBAND(lpBand) ) + mcy = ircBw(lpBand); + + if( lpBand->fDraw & DRAW_LAST_IN_ROW ) + { + TRACE("P3 processing row %d, starting band %d, ending band %d\n", + lpBand->iRow, startband, i); + if( startband < 0 ) + ERR("Last band %d with no first, row %d\n", i, lpBand->iRow); + + REBAR_AdjustBands (infoPtr, startband, i, + (infoPtr->dwStyle & CCS_VERT) ? + clientcy : clientcx, mcy); + } + } + + /* Calculate the other rectangles in each band */ + if (infoPtr->dwStyle & CCS_VERT) { + REBAR_CalcVertBand (infoPtr, 0, infoPtr->uNumBands, + notify); + } + else { + REBAR_CalcHorzBand (infoPtr, 0, infoPtr->uNumBands, + notify); + } + } + + /* ******* End Phase 3 - adjust all bands for width full ******* */ + + /* now compute size of Rebar itself */ + infoPtr->oldSize = infoPtr->calcSize; + if (infoPtr->uNumBands == 0) { + /* we have no bands, so make size the size of client */ + x = clientcx; + y = clientcy; + } + if (infoPtr->dwStyle & CCS_VERT) { + if( x < REBAR_MINSIZE ) + x = REBAR_MINSIZE; + infoPtr->calcSize.cx = x; + infoPtr->calcSize.cy = clientcy; + TRACE("vert, notify=%d, x=%d, origheight=%d\n", + notify, x, origheight); + if (notify && (x != origheight)) infoPtr->fStatus |= NTF_HGHTCHG; + } + else { + if( y < REBAR_MINSIZE ) + y = REBAR_MINSIZE; + infoPtr->calcSize.cx = clientcx; + infoPtr->calcSize.cy = y; + TRACE("horz, notify=%d, y=%d, origheight=%d\n", + notify, y, origheight); + if (notify && (y != origheight)) infoPtr->fStatus |= NTF_HGHTCHG; + } + + REBAR_DumpBand (infoPtr); + + REBAR_MoveChildWindows (infoPtr, 0, infoPtr->uNumBands); + + REBAR_ForceResize (infoPtr); +} + + +static VOID +REBAR_ValidateBand (REBAR_INFO *infoPtr, REBAR_BAND *lpBand) + /* Function: This routine evaluates the band specs supplied */ + /* by the user and updates the following 5 fields in */ + /* the internal band structure: cxHeader, lcx, lcy, hcx, hcy*/ +{ + UINT header=0; + UINT textheight=0; + UINT i, nonfixed; + REBAR_BAND *tBand; + + lpBand->fStatus = 0; + lpBand->lcx = 0; + lpBand->lcy = 0; + lpBand->ccx = 0; + lpBand->ccy = 0; + lpBand->hcx = 0; + lpBand->hcy = 0; + + /* Data comming in from users into the cx... and cy... fields */ + /* may be bad, just garbage, because the user never clears */ + /* the fields. RB_{SET|INSERT}BAND{A|W} just passes the data */ + /* along if the fields exist in the input area. Here we must */ + /* determine if the data is valid. I have no idea how MS does */ + /* the validation, but it does because the RB_GETBANDINFO */ + /* returns a 0 when I know the sample program passed in an */ + /* address. Here I will use the algorithim that if the value */ + /* is greater than 65535 then it is bad and replace it with */ + /* a zero. Feel free to improve the algorithim. - GA 12/2000 */ + if (lpBand->cxMinChild > 65535) lpBand->cxMinChild = 0; + if (lpBand->cyMinChild > 65535) lpBand->cyMinChild = 0; + if (lpBand->cx > 65535) lpBand->cx = 0; + if (lpBand->cyChild > 65535) lpBand->cyChild = 0; + if (lpBand->cyMaxChild > 65535) lpBand->cyMaxChild = 0; + if (lpBand->cyIntegral > 65535) lpBand->cyIntegral = 0; + if (lpBand->cxIdeal > 65535) lpBand->cxIdeal = 0; + if (lpBand->cxHeader > 65535) lpBand->cxHeader = 0; + + /* FIXME: probably should only set NEEDS_LAYOUT flag when */ + /* values change. Till then always set it. */ + TRACE("setting NEEDS_LAYOUT\n"); + infoPtr->fStatus |= BAND_NEEDS_LAYOUT; + + /* Header is where the image, text and gripper exist */ + /* in the band and precede the child window. */ + + /* count number of non-FIXEDSIZE and non-Hidden bands */ + nonfixed = 0; + for (i=0; iuNumBands; i++){ + tBand = &infoPtr->bands[i]; + if (!HIDDENBAND(tBand) && !(tBand->fStyle & RBBS_FIXEDSIZE)) + nonfixed++; + } + + /* calculate gripper rectangle */ + if ( (!(lpBand->fStyle & RBBS_NOGRIPPER)) && + ( (lpBand->fStyle & RBBS_GRIPPERALWAYS) || + ( !(lpBand->fStyle & RBBS_FIXEDSIZE) && (nonfixed > 1))) + ) { + lpBand->fStatus |= HAS_GRIPPER; + if (infoPtr->dwStyle & CCS_VERT) + if (infoPtr->dwStyle & RBS_VERTICALGRIPPER) + header += (GRIPPER_HEIGHT + REBAR_PRE_GRIPPER); + else + header += (GRIPPER_WIDTH + REBAR_PRE_GRIPPER); + else + header += (REBAR_PRE_GRIPPER + GRIPPER_WIDTH); + /* Always have 4 pixels before anything else */ + header += REBAR_ALWAYS_SPACE; + } + + /* image is visible */ + if ((lpBand->fMask & RBBIM_IMAGE) && (infoPtr->himl)) { + lpBand->fStatus |= HAS_IMAGE; + if (infoPtr->dwStyle & CCS_VERT) { + header += (infoPtr->imageSize.cy + REBAR_POST_IMAGE); + lpBand->lcy = infoPtr->imageSize.cx + 2; + } + else { + header += (infoPtr->imageSize.cx + REBAR_POST_IMAGE); + lpBand->lcy = infoPtr->imageSize.cy + 2; + } + } + + /* text is visible */ + if ((lpBand->fMask & RBBIM_TEXT) && (lpBand->lpText) && + !(lpBand->fStyle & RBBS_HIDETITLE)) { + HDC hdc = GetDC (0); + HFONT hOldFont = SelectObject (hdc, infoPtr->hFont); + SIZE size; + + lpBand->fStatus |= HAS_TEXT; + GetTextExtentPoint32W (hdc, lpBand->lpText, + lstrlenW (lpBand->lpText), &size); + header += ((infoPtr->dwStyle & CCS_VERT) ? (size.cy + REBAR_POST_TEXT) : (size.cx + REBAR_POST_TEXT)); + textheight = (infoPtr->dwStyle & CCS_VERT) ? 0 : size.cy; + + SelectObject (hdc, hOldFont); + ReleaseDC (0, hdc); + } + + /* if no gripper but either image or text, then leave space */ + if ((lpBand->fStatus & (HAS_IMAGE | HAS_TEXT)) && + !(lpBand->fStatus & HAS_GRIPPER)) { + header += REBAR_ALWAYS_SPACE; + } + + /* check if user overrode the header value */ + if (!(lpBand->fMask & RBBIM_HEADERSIZE)) + lpBand->cxHeader = header; + + + /* Now compute minimum size of child window */ + lpBand->offChild.cx = 0; + lpBand->offChild.cy = 0; + lpBand->lcy = textheight; + lpBand->ccy = lpBand->lcy; + if (lpBand->fMask & RBBIM_CHILDSIZE) { + lpBand->lcx = lpBand->cxMinChild; + + /* Set the .cy values for CHILDSIZE case */ + lpBand->lcy = max(lpBand->lcy, lpBand->cyMinChild); + lpBand->ccy = lpBand->lcy; + lpBand->hcy = lpBand->lcy; + if (lpBand->cyMaxChild != 0xffffffff) { + lpBand->hcy = lpBand->cyMaxChild; + } + if (lpBand->cyChild != 0xffffffff) + lpBand->ccy = max (lpBand->cyChild, lpBand->lcy); + + TRACE("_CHILDSIZE\n"); + } + if (lpBand->fMask & RBBIM_SIZE) { + lpBand->hcx = max (lpBand->cx-lpBand->cxHeader, lpBand->lcx); + TRACE("_SIZE\n"); + } + else + lpBand->hcx = lpBand->lcx; + lpBand->ccx = lpBand->hcx; + + /* make ->.cx include header size for _Layout */ + lpBand->lcx += lpBand->cxHeader; + lpBand->ccx += lpBand->cxHeader; + lpBand->hcx += lpBand->cxHeader; + +} + +static BOOL +REBAR_CommonSetupBand (HWND hwnd, LPREBARBANDINFOA lprbbi, REBAR_BAND *lpBand) + /* Function: This routine copies the supplied values from */ + /* user input (lprbbi) to the internal band structure. */ + /* It returns true if something changed and false if not. */ +{ + BOOL bChanged = FALSE; + + lpBand->fMask |= lprbbi->fMask; + + if( (lprbbi->fMask & RBBIM_STYLE) && + (lpBand->fStyle != lprbbi->fStyle ) ) + { + lpBand->fStyle = lprbbi->fStyle; + bChanged = TRUE; + } + + if( (lprbbi->fMask & RBBIM_COLORS) && + ( ( lpBand->clrFore != lprbbi->clrFore ) || + ( lpBand->clrBack != lprbbi->clrBack ) ) ) + { + lpBand->clrFore = lprbbi->clrFore; + lpBand->clrBack = lprbbi->clrBack; + bChanged = TRUE; + } + + if( (lprbbi->fMask & RBBIM_IMAGE) && + ( lpBand->iImage != lprbbi->iImage ) ) + { + lpBand->iImage = lprbbi->iImage; + bChanged = TRUE; + } + + if( (lprbbi->fMask & RBBIM_CHILD) && + (lprbbi->hwndChild != lpBand->hwndChild ) ) + { + if (lprbbi->hwndChild) { + lpBand->hwndChild = lprbbi->hwndChild; + lpBand->hwndPrevParent = + SetParent (lpBand->hwndChild, hwnd); + /* below in trace fro WinRAR */ + ShowWindow(lpBand->hwndChild, SW_SHOWNOACTIVATE | SW_SHOWNORMAL); + /* above in trace fro WinRAR */ + } + else { + TRACE("child: %p prev parent: %p\n", + lpBand->hwndChild, lpBand->hwndPrevParent); + lpBand->hwndChild = 0; + lpBand->hwndPrevParent = 0; + } + bChanged = TRUE; + } + + if( (lprbbi->fMask & RBBIM_CHILDSIZE) && + ( (lpBand->cxMinChild != lprbbi->cxMinChild) || + (lpBand->cyMinChild != lprbbi->cyMinChild ) || + ( (lprbbi->cbSize >= sizeof (REBARBANDINFOA)) && + ( (lpBand->cyChild != lprbbi->cyChild ) || + (lpBand->cyMaxChild != lprbbi->cyMaxChild ) || + (lpBand->cyIntegral != lprbbi->cyIntegral ) ) ) || + ( (lprbbi->cbSize < sizeof (REBARBANDINFOA)) && + ( (lpBand->cyChild || + lpBand->cyMaxChild || + lpBand->cyIntegral ) ) ) ) ) + { + lpBand->cxMinChild = lprbbi->cxMinChild; + lpBand->cyMinChild = lprbbi->cyMinChild; + if (lprbbi->cbSize >= sizeof (REBARBANDINFOA)) { + lpBand->cyChild = lprbbi->cyChild; + lpBand->cyMaxChild = lprbbi->cyMaxChild; + lpBand->cyIntegral = lprbbi->cyIntegral; + } + else { /* special case - these should be zeroed out since */ + /* RBBIM_CHILDSIZE added these in WIN32_IE >= 0x0400 */ + lpBand->cyChild = 0; + lpBand->cyMaxChild = 0; + lpBand->cyIntegral = 0; + } + bChanged = TRUE; + } + + if( (lprbbi->fMask & RBBIM_SIZE) && + (lpBand->cx != lprbbi->cx ) ) + { + lpBand->cx = lprbbi->cx; + bChanged = TRUE; + } + + if( (lprbbi->fMask & RBBIM_BACKGROUND) && + ( lpBand->hbmBack != lprbbi->hbmBack ) ) + { + lpBand->hbmBack = lprbbi->hbmBack; + bChanged = TRUE; + } + + if( (lprbbi->fMask & RBBIM_ID) && + (lpBand->wID != lprbbi->wID ) ) + { + lpBand->wID = lprbbi->wID; + bChanged = TRUE; + } + + /* check for additional data */ + if (lprbbi->cbSize >= sizeof (REBARBANDINFOA)) { + if( (lprbbi->fMask & RBBIM_IDEALSIZE) && + ( lpBand->cxIdeal != lprbbi->cxIdeal ) ) + { + lpBand->cxIdeal = lprbbi->cxIdeal; + bChanged = TRUE; + } + + if( (lprbbi->fMask & RBBIM_LPARAM) && + (lpBand->lParam != lprbbi->lParam ) ) + { + lpBand->lParam = lprbbi->lParam; + bChanged = TRUE; + } + + if( (lprbbi->fMask & RBBIM_HEADERSIZE) && + (lpBand->cxHeader != lprbbi->cxHeader ) ) + { + lpBand->cxHeader = lprbbi->cxHeader; + bChanged = TRUE; + } + } + + return bChanged; +} + +static LRESULT +REBAR_InternalEraseBkGnd (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam, RECT *clip) + /* Function: This erases the background rectangle by drawing */ + /* each band with its background color (or the default) and */ + /* draws each bands right separator if necessary. The row */ + /* separators are drawn on the first band of the next row. */ +{ + REBAR_BAND *lpBand; + UINT i; + INT oldrow; + HDC hdc = (HDC)wParam; + RECT rect; + COLORREF old = CLR_NONE, new; + + oldrow = -1; + for(i=0; iuNumBands; i++) { + lpBand = &infoPtr->bands[i]; + if (HIDDENBAND(lpBand)) continue; + + /* draw band separator between rows */ + if (lpBand->iRow != oldrow) { + oldrow = lpBand->iRow; + if (lpBand->fDraw & DRAW_BOTTOMSEP) { + RECT rcRowSep; + rcRowSep = lpBand->rcBand; + if (infoPtr->dwStyle & CCS_VERT) { + rcRowSep.right += SEP_WIDTH_SIZE; + rcRowSep.bottom = infoPtr->calcSize.cy; + DrawEdge (hdc, &rcRowSep, EDGE_ETCHED, BF_RIGHT); + } + else { + rcRowSep.bottom += SEP_WIDTH_SIZE; + rcRowSep.right = infoPtr->calcSize.cx; + DrawEdge (hdc, &rcRowSep, EDGE_ETCHED, BF_BOTTOM); + } + TRACE ("drawing band separator bottom (%ld,%ld)-(%ld,%ld)\n", + rcRowSep.left, rcRowSep.top, + rcRowSep.right, rcRowSep.bottom); + } + } + + /* draw band separator between bands in a row */ + if (lpBand->fDraw & DRAW_RIGHTSEP) { + RECT rcSep; + rcSep = lpBand->rcBand; + if (infoPtr->dwStyle & CCS_VERT) { + rcSep.bottom += SEP_WIDTH_SIZE; + DrawEdge (hdc, &rcSep, EDGE_ETCHED, BF_BOTTOM); + } + else { + rcSep.right += SEP_WIDTH_SIZE; + DrawEdge (hdc, &rcSep, EDGE_ETCHED, BF_RIGHT); + } + TRACE("drawing band separator right (%ld,%ld)-(%ld,%ld)\n", + rcSep.left, rcSep.top, rcSep.right, rcSep.bottom); + } + + /* draw the actual background */ + if (lpBand->clrBack != CLR_NONE) { + new = (lpBand->clrBack == CLR_DEFAULT) ? infoPtr->clrBtnFace : + lpBand->clrBack; +#if GLATESTING + /* testing only - make background green to see it */ + new = RGB(0,128,0); +#endif + } + else { + /* In the absence of documentation for Rebar vs. CLR_NONE, + * we will use the default BtnFace color. Note documentation + * exists for Listview and Imagelist. + */ + new = infoPtr->clrBtnFace; +#if GLATESTING + /* testing only - make background green to see it */ + new = RGB(0,128,0); +#endif + } + old = SetBkColor (hdc, new); + + rect = lpBand->rcBand; + TRACE("%s background color=0x%06lx, band (%ld,%ld)-(%ld,%ld), clip (%ld,%ld)-(%ld,%ld)\n", + (lpBand->clrBack == CLR_NONE) ? "none" : + ((lpBand->clrBack == CLR_DEFAULT) ? "dft" : ""), + GetBkColor(hdc), + lpBand->rcBand.left,lpBand->rcBand.top, + lpBand->rcBand.right,lpBand->rcBand.bottom, + clip->left, clip->top, + clip->right, clip->bottom); + ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, 0); + if (lpBand->clrBack != CLR_NONE) + SetBkColor (hdc, old); + } + return TRUE; +} + +static void +REBAR_InternalHitTest (REBAR_INFO *infoPtr, const LPPOINT lpPt, UINT *pFlags, INT *pBand) +{ + REBAR_BAND *lpBand; + RECT rect; + UINT iCount; + + GetClientRect (infoPtr->hwndSelf, &rect); + + *pFlags = RBHT_NOWHERE; + if (PtInRect (&rect, *lpPt)) + { + if (infoPtr->uNumBands == 0) { + *pFlags = RBHT_NOWHERE; + if (pBand) + *pBand = -1; + TRACE("NOWHERE\n"); + return; + } + else { + /* somewhere inside */ + for (iCount = 0; iCount < infoPtr->uNumBands; iCount++) { + lpBand = &infoPtr->bands[iCount]; + if (HIDDENBAND(lpBand)) continue; + if (PtInRect (&lpBand->rcBand, *lpPt)) { + if (pBand) + *pBand = iCount; + if (PtInRect (&lpBand->rcGripper, *lpPt)) { + *pFlags = RBHT_GRABBER; + TRACE("ON GRABBER %d\n", iCount); + return; + } + else if (PtInRect (&lpBand->rcCapImage, *lpPt)) { + *pFlags = RBHT_CAPTION; + TRACE("ON CAPTION %d\n", iCount); + return; + } + else if (PtInRect (&lpBand->rcCapText, *lpPt)) { + *pFlags = RBHT_CAPTION; + TRACE("ON CAPTION %d\n", iCount); + return; + } + else if (PtInRect (&lpBand->rcChild, *lpPt)) { + *pFlags = RBHT_CLIENT; + TRACE("ON CLIENT %d\n", iCount); + return; + } + else if (PtInRect (&lpBand->rcChevron, *lpPt)) { + *pFlags = RBHT_CHEVRON; + TRACE("ON CHEVRON %d\n", iCount); + return; + } + else { + *pFlags = RBHT_NOWHERE; + TRACE("NOWHERE %d\n", iCount); + return; + } + } + } + + *pFlags = RBHT_NOWHERE; + if (pBand) + *pBand = -1; + + TRACE("NOWHERE\n"); + return; + } + } + else { + *pFlags = RBHT_NOWHERE; + if (pBand) + *pBand = -1; + TRACE("NOWHERE\n"); + return; + } +} + + +static INT +REBAR_Shrink (REBAR_INFO *infoPtr, REBAR_BAND *band, INT movement, INT i) + /* Function: This attempts to shrink the given band by the */ + /* the amount in "movement". A shrink to the left is indi- */ + /* cated by "movement" being negative. "i" is merely the */ + /* band index for trace messages. */ +{ + INT Leadjust, Readjust, avail, ret; + + /* Note: a left drag is indicated by "movement" being negative. */ + /* Similarly, a right drag is indicated by "movement" */ + /* being positive. "movement" should never be 0, but if */ + /* it is then the band does not move. */ + + avail = rcBw(band) - band->lcx; + + /* now compute the Left End adjustment factor and Right End */ + /* adjustment factor. They may be different if shrinking. */ + if (avail <= 0) { + /* if this band is not shrinkable, then just move it */ + Leadjust = Readjust = movement; + ret = movement; + } + else { + if (movement < 0) { + /* Drag to left */ + if (avail <= abs(movement)) { + Readjust = movement; + Leadjust = movement + avail; + ret = Leadjust; + } + else { + Readjust = movement; + Leadjust = 0; + ret = 0; + } + } + else { + /* Drag to right */ + if (avail <= abs(movement)) { + Leadjust = movement; + Readjust = movement - avail; + ret = Readjust; + } + else { + Leadjust = movement; + Readjust = 0; + ret = 0; + } + } + } + + /* Reasonability Check */ + if (rcBlt(band) + Leadjust < 0) { + ERR("adjustment will fail, band %d: left=%d, right=%d, move=%d, rtn=%d\n", + i, Leadjust, Readjust, movement, ret); + } + + LEADJ(band, Leadjust); + READJ(band, Readjust); + + TRACE("band %d: left=%d, right=%d, move=%d, rtn=%d, rcBand=(%ld,%ld)-(%ld,%ld)\n", + i, Leadjust, Readjust, movement, ret, + band->rcBand.left, band->rcBand.top, + band->rcBand.right, band->rcBand.bottom); + return ret; +} + + +static void +REBAR_HandleLRDrag (REBAR_INFO *infoPtr, const POINT *ptsmove) + /* Function: This will implement the functionality of a */ + /* Gripper drag within a row. It will not implement "out- */ + /* of-row" drags. (They are detected and handled in */ + /* REBAR_MouseMove.) */ + /* **** FIXME Switching order of bands in a row not **** */ + /* **** yet implemented. **** */ +{ + REBAR_BAND *hitBand, *band, *mindBand, *maxdBand; + RECT newrect; + INT imindBand = -1, imaxdBand, ihitBand, i, movement; + INT RHeaderSum = 0, LHeaderSum = 0; + INT compress; + + /* on first significant mouse movement, issue notify */ + + if (!(infoPtr->fStatus & BEGIN_DRAG_ISSUED)) { + if (REBAR_Notify_NMREBAR (infoPtr, -1, RBN_BEGINDRAG)) { + /* Notify returned TRUE - abort drag */ + infoPtr->dragStart.x = 0; + infoPtr->dragStart.y = 0; + infoPtr->dragNow = infoPtr->dragStart; + infoPtr->iGrabbedBand = -1; + ReleaseCapture (); + return ; + } + infoPtr->fStatus |= BEGIN_DRAG_ISSUED; + } + + ihitBand = infoPtr->iGrabbedBand; + hitBand = &infoPtr->bands[ihitBand]; + imaxdBand = ihitBand; /* to suppress warning message */ + + /* find all the bands in the row of the one whose Gripper was seized */ + for (i=0; iuNumBands; i++) { + band = &infoPtr->bands[i]; + if (HIDDENBAND(band)) continue; + if (band->iRow == hitBand->iRow) { + imaxdBand = i; + if (imindBand == -1) imindBand = i; + /* minimum size of each band is size of header plus */ + /* size of minimum child plus offset of child from header plus */ + /* one to separate each band. */ + if (i < ihitBand) + LHeaderSum += (band->lcx + SEP_WIDTH); + else + RHeaderSum += (band->lcx + SEP_WIDTH); + + } + } + if (RHeaderSum) RHeaderSum -= SEP_WIDTH; /* no separator after last band */ + + mindBand = &infoPtr->bands[imindBand]; + maxdBand = &infoPtr->bands[imaxdBand]; + + if (imindBand == imaxdBand) return; /* nothing to drag against */ + if (imindBand == ihitBand) return; /* first band in row, can't drag */ + + /* limit movement to inside adjustable bands - Left */ + if ( (ptsmove->x < mindBand->rcBand.left) || + (ptsmove->x > maxdBand->rcBand.right) || + (ptsmove->y < mindBand->rcBand.top) || + (ptsmove->y > maxdBand->rcBand.bottom)) + return; /* should swap bands */ + + if (infoPtr->dwStyle & CCS_VERT) + movement = ptsmove->y - ((hitBand->rcBand.top+REBAR_PRE_GRIPPER) - + infoPtr->ihitoffset); + else + movement = ptsmove->x - ((hitBand->rcBand.left+REBAR_PRE_GRIPPER) - + infoPtr->ihitoffset); + infoPtr->dragNow = *ptsmove; + + TRACE("before: movement=%d (%ld,%ld), imindBand=%d, ihitBand=%d, imaxdBand=%d, LSum=%d, RSum=%d\n", + movement, ptsmove->x, ptsmove->y, imindBand, ihitBand, + imaxdBand, LHeaderSum, RHeaderSum); + REBAR_DumpBand (infoPtr); + + if (movement < 0) { + + /* *** Drag left/up *** */ + compress = rcBlt(hitBand) - rcBlt(mindBand) - + LHeaderSum; + if (compress < abs(movement)) { + TRACE("limiting left drag, was %d changed to %d\n", + movement, -compress); + movement = -compress; + } + + for (i=ihitBand; i>=imindBand; i--) { + band = &infoPtr->bands[i]; + if (HIDDENBAND(band)) continue; + if (i == ihitBand) { + LEADJ(band, movement); + } + else + movement = REBAR_Shrink (infoPtr, band, movement, i); + band->ccx = rcBw(band); + } + } + else { + BOOL first = TRUE; + + /* *** Drag right/down *** */ + compress = rcBrb(maxdBand) - rcBlt(hitBand) - + RHeaderSum; + if (compress < abs(movement)) { + TRACE("limiting right drag, was %d changed to %d\n", + movement, compress); + movement = compress; + } + for (i=ihitBand-1; i<=imaxdBand; i++) { + band = &infoPtr->bands[i]; + if (HIDDENBAND(band)) continue; + if (first) { + first = FALSE; + READJ(band, movement); + } + else + movement = REBAR_Shrink (infoPtr, band, movement, i); + band->ccx = rcBw(band); + } + } + + /* recompute all rectangles */ + if (infoPtr->dwStyle & CCS_VERT) { + REBAR_CalcVertBand (infoPtr, imindBand, imaxdBand+1, + FALSE); + } + else { + REBAR_CalcHorzBand (infoPtr, imindBand, imaxdBand+1, + FALSE); + } + + TRACE("bands after adjustment, see band # %d, %d\n", + imindBand, imaxdBand); + REBAR_DumpBand (infoPtr); + + SetRect (&newrect, + mindBand->rcBand.left, + mindBand->rcBand.top, + maxdBand->rcBand.right, + maxdBand->rcBand.bottom); + + REBAR_MoveChildWindows (infoPtr, imindBand, imaxdBand+1); + + InvalidateRect (infoPtr->hwndSelf, &newrect, TRUE); + UpdateWindow (infoPtr->hwndSelf); + +} + + + +/* << REBAR_BeginDrag >> */ + + +static LRESULT +REBAR_DeleteBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + UINT uBand = (UINT)wParam; + HWND childhwnd = 0; + REBAR_BAND *lpBand; + + if (uBand >= infoPtr->uNumBands) + return FALSE; + + TRACE("deleting band %u!\n", uBand); + lpBand = &infoPtr->bands[uBand]; + REBAR_Notify_NMREBAR (infoPtr, uBand, RBN_DELETINGBAND); + + if (infoPtr->uNumBands == 1) { + TRACE(" simple delete!\n"); + if ((lpBand->fMask & RBBIM_CHILD) && lpBand->hwndChild) + childhwnd = lpBand->hwndChild; + Free (infoPtr->bands); + infoPtr->bands = NULL; + infoPtr->uNumBands = 0; + } + else { + REBAR_BAND *oldBands = infoPtr->bands; + TRACE("complex delete! [uBand=%u]\n", uBand); + + if ((lpBand->fMask & RBBIM_CHILD) && lpBand->hwndChild) + childhwnd = lpBand->hwndChild; + + infoPtr->uNumBands--; + infoPtr->bands = Alloc (sizeof (REBAR_BAND) * infoPtr->uNumBands); + if (uBand > 0) { + memcpy (&infoPtr->bands[0], &oldBands[0], + uBand * sizeof(REBAR_BAND)); + } + + if (uBand < infoPtr->uNumBands) { + memcpy (&infoPtr->bands[uBand], &oldBands[uBand+1], + (infoPtr->uNumBands - uBand) * sizeof(REBAR_BAND)); + } + + Free (oldBands); + } + + if (childhwnd) + ShowWindow (childhwnd, SW_HIDE); + + REBAR_Notify_NMREBAR (infoPtr, -1, RBN_DELETEDBAND); + + /* if only 1 band left the re-validate to possible eliminate gripper */ + if (infoPtr->uNumBands == 1) + REBAR_ValidateBand (infoPtr, &infoPtr->bands[0]); + + TRACE("setting NEEDS_LAYOUT\n"); + infoPtr->fStatus |= BAND_NEEDS_LAYOUT; + infoPtr->fStatus |= RESIZE_ANYHOW; + REBAR_Layout (infoPtr, NULL, TRUE, FALSE); + + return TRUE; +} + + +/* << REBAR_DragMove >> */ +/* << REBAR_EndDrag >> */ + + +static LRESULT +REBAR_GetBandBorders (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + LPRECT lpRect = (LPRECT)lParam; + REBAR_BAND *lpBand; + + if (!lParam) + return 0; + if ((UINT)wParam >= infoPtr->uNumBands) + return 0; + + lpBand = &infoPtr->bands[(UINT)wParam]; + + /* FIXME - the following values were determined by experimentation */ + /* with the REBAR Control Spy. I have guesses as to what the 4 and */ + /* 1 are, but I am not sure. There doesn't seem to be any actual */ + /* difference in size of the control area with and without the */ + /* style. - GA */ + if (infoPtr->dwStyle & RBS_BANDBORDERS) { + if (infoPtr->dwStyle & CCS_VERT) { + lpRect->left = 1; + lpRect->top = lpBand->cxHeader + 4; + lpRect->right = 1; + lpRect->bottom = 0; + } + else { + lpRect->left = lpBand->cxHeader + 4; + lpRect->top = 1; + lpRect->right = 0; + lpRect->bottom = 1; + } + } + else { + lpRect->left = lpBand->cxHeader; + } + return 0; +} + + +inline static LRESULT +REBAR_GetBandCount (REBAR_INFO *infoPtr) +{ + TRACE("band count %u!\n", infoPtr->uNumBands); + + return infoPtr->uNumBands; +} + + +static LRESULT +REBAR_GetBandInfoA (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + LPREBARBANDINFOA lprbbi = (LPREBARBANDINFOA)lParam; + REBAR_BAND *lpBand; + + if (lprbbi == NULL) + return FALSE; + if (lprbbi->cbSize < REBARBANDINFOA_V3_SIZE) + return FALSE; + if ((UINT)wParam >= infoPtr->uNumBands) + return FALSE; + + TRACE("index %u\n", (UINT)wParam); + + /* copy band information */ + lpBand = &infoPtr->bands[(UINT)wParam]; + + if (lprbbi->fMask & RBBIM_STYLE) + lprbbi->fStyle = lpBand->fStyle; + + if (lprbbi->fMask & RBBIM_COLORS) { + lprbbi->clrFore = lpBand->clrFore; + lprbbi->clrBack = lpBand->clrBack; + if (lprbbi->clrBack == CLR_DEFAULT) + lprbbi->clrBack = infoPtr->clrBtnFace; + } + + if ((lprbbi->fMask & RBBIM_TEXT) && (lprbbi->lpText)) { + if (lpBand->lpText && (lpBand->fMask & RBBIM_TEXT)) + { + if (!WideCharToMultiByte( CP_ACP, 0, lpBand->lpText, -1, + lprbbi->lpText, lprbbi->cch, NULL, NULL )) + lprbbi->lpText[lprbbi->cch-1] = 0; + } + else + *lprbbi->lpText = 0; + } + + if (lprbbi->fMask & RBBIM_IMAGE) { + if (lpBand->fMask & RBBIM_IMAGE) + lprbbi->iImage = lpBand->iImage; + else + lprbbi->iImage = -1; + } + + if (lprbbi->fMask & RBBIM_CHILD) + lprbbi->hwndChild = lpBand->hwndChild; + + if (lprbbi->fMask & RBBIM_CHILDSIZE) { + lprbbi->cxMinChild = lpBand->cxMinChild; + lprbbi->cyMinChild = lpBand->cyMinChild; + if (lprbbi->cbSize >= sizeof (REBARBANDINFOA)) { + lprbbi->cyChild = lpBand->cyChild; + lprbbi->cyMaxChild = lpBand->cyMaxChild; + lprbbi->cyIntegral = lpBand->cyIntegral; + } + } + + if (lprbbi->fMask & RBBIM_SIZE) + lprbbi->cx = lpBand->cx; + + if (lprbbi->fMask & RBBIM_BACKGROUND) + lprbbi->hbmBack = lpBand->hbmBack; + + if (lprbbi->fMask & RBBIM_ID) + lprbbi->wID = lpBand->wID; + + /* check for additional data */ + if (lprbbi->cbSize >= sizeof (REBARBANDINFOA)) { + if (lprbbi->fMask & RBBIM_IDEALSIZE) + lprbbi->cxIdeal = lpBand->cxIdeal; + + if (lprbbi->fMask & RBBIM_LPARAM) + lprbbi->lParam = lpBand->lParam; + + if (lprbbi->fMask & RBBIM_HEADERSIZE) + lprbbi->cxHeader = lpBand->cxHeader; + } + + REBAR_DumpBandInfo (lprbbi); + + return TRUE; +} + + +static LRESULT +REBAR_GetBandInfoW (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + LPREBARBANDINFOW lprbbi = (LPREBARBANDINFOW)lParam; + REBAR_BAND *lpBand; + + if (lprbbi == NULL) + return FALSE; + if (lprbbi->cbSize < REBARBANDINFOW_V3_SIZE) + return FALSE; + if ((UINT)wParam >= infoPtr->uNumBands) + return FALSE; + + TRACE("index %u\n", (UINT)wParam); + + /* copy band information */ + lpBand = &infoPtr->bands[(UINT)wParam]; + + if (lprbbi->fMask & RBBIM_STYLE) + lprbbi->fStyle = lpBand->fStyle; + + if (lprbbi->fMask & RBBIM_COLORS) { + lprbbi->clrFore = lpBand->clrFore; + lprbbi->clrBack = lpBand->clrBack; + if (lprbbi->clrBack == CLR_DEFAULT) + lprbbi->clrBack = infoPtr->clrBtnFace; + } + + if ((lprbbi->fMask & RBBIM_TEXT) && (lprbbi->lpText)) { + if (lpBand->lpText && (lpBand->fMask & RBBIM_TEXT)) + lstrcpynW (lprbbi->lpText, lpBand->lpText, lprbbi->cch); + else + *lprbbi->lpText = 0; + } + + if (lprbbi->fMask & RBBIM_IMAGE) { + if (lpBand->fMask & RBBIM_IMAGE) + lprbbi->iImage = lpBand->iImage; + else + lprbbi->iImage = -1; + } + + if (lprbbi->fMask & RBBIM_CHILD) + lprbbi->hwndChild = lpBand->hwndChild; + + if (lprbbi->fMask & RBBIM_CHILDSIZE) { + lprbbi->cxMinChild = lpBand->cxMinChild; + lprbbi->cyMinChild = lpBand->cyMinChild; + if (lprbbi->cbSize >= sizeof (REBARBANDINFOW)) { + lprbbi->cyChild = lpBand->cyChild; + lprbbi->cyMaxChild = lpBand->cyMaxChild; + lprbbi->cyIntegral = lpBand->cyIntegral; + } + } + + if (lprbbi->fMask & RBBIM_SIZE) + lprbbi->cx = lpBand->cx; + + if (lprbbi->fMask & RBBIM_BACKGROUND) + lprbbi->hbmBack = lpBand->hbmBack; + + if (lprbbi->fMask & RBBIM_ID) + lprbbi->wID = lpBand->wID; + + /* check for additional data */ + if (lprbbi->cbSize >= sizeof (REBARBANDINFOW)) { + if (lprbbi->fMask & RBBIM_IDEALSIZE) + lprbbi->cxIdeal = lpBand->cxIdeal; + + if (lprbbi->fMask & RBBIM_LPARAM) + lprbbi->lParam = lpBand->lParam; + + if (lprbbi->fMask & RBBIM_HEADERSIZE) + lprbbi->cxHeader = lpBand->cxHeader; + } + + REBAR_DumpBandInfo ((LPREBARBANDINFOA)lprbbi); + + return TRUE; +} + + +static LRESULT +REBAR_GetBarHeight (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + INT nHeight; + + nHeight = (infoPtr->dwStyle & CCS_VERT) ? infoPtr->calcSize.cx : infoPtr->calcSize.cy; + + TRACE("height = %d\n", nHeight); + + return nHeight; +} + + +static LRESULT +REBAR_GetBarInfo (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + LPREBARINFO lpInfo = (LPREBARINFO)lParam; + + if (lpInfo == NULL) + return FALSE; + + if (lpInfo->cbSize < sizeof (REBARINFO)) + return FALSE; + + TRACE("getting bar info!\n"); + + if (infoPtr->himl) { + lpInfo->himl = infoPtr->himl; + lpInfo->fMask |= RBIM_IMAGELIST; + } + + return TRUE; +} + + +inline static LRESULT +REBAR_GetBkColor (REBAR_INFO *infoPtr) +{ + COLORREF clr = infoPtr->clrBk; + + if (clr == CLR_DEFAULT) + clr = infoPtr->clrBtnFace; + + TRACE("background color 0x%06lx!\n", clr); + + return clr; +} + + +/* << REBAR_GetColorScheme >> */ +/* << REBAR_GetDropTarget >> */ + + +static LRESULT +REBAR_GetPalette (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + FIXME("empty stub!\n"); + + return 0; +} + + +static LRESULT +REBAR_GetRect (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + INT iBand = (INT)wParam; + LPRECT lprc = (LPRECT)lParam; + REBAR_BAND *lpBand; + + if ((iBand < 0) && ((UINT)iBand >= infoPtr->uNumBands)) + return FALSE; + if (!lprc) + return FALSE; + + lpBand = &infoPtr->bands[iBand]; + CopyRect (lprc, &lpBand->rcBand); + + TRACE("band %d, (%ld,%ld)-(%ld,%ld)\n", iBand, + lprc->left, lprc->top, lprc->right, lprc->bottom); + + return TRUE; +} + + +inline static LRESULT +REBAR_GetRowCount (REBAR_INFO *infoPtr) +{ + TRACE("%u\n", infoPtr->uNumRows); + + return infoPtr->uNumRows; +} + + +static LRESULT +REBAR_GetRowHeight (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + INT iRow = (INT)wParam; + int j = 0, ret = 0; + UINT i; + REBAR_BAND *lpBand; + + for (i=0; iuNumBands; i++) { + lpBand = &infoPtr->bands[i]; + if (HIDDENBAND(lpBand)) continue; + if (lpBand->iRow != iRow) continue; + if (infoPtr->dwStyle & CCS_VERT) + j = lpBand->rcBand.right - lpBand->rcBand.left; + else + j = lpBand->rcBand.bottom - lpBand->rcBand.top; + if (j > ret) ret = j; + } + + TRACE("row %d, height %d\n", iRow, ret); + + return ret; +} + + +inline static LRESULT +REBAR_GetTextColor (REBAR_INFO *infoPtr) +{ + TRACE("text color 0x%06lx!\n", infoPtr->clrText); + + return infoPtr->clrText; +} + + +inline static LRESULT +REBAR_GetToolTips (REBAR_INFO *infoPtr) +{ + return (LRESULT)infoPtr->hwndToolTip; +} + + +inline static LRESULT +REBAR_GetUnicodeFormat (REBAR_INFO *infoPtr) +{ + TRACE("%s hwnd=%p\n", + infoPtr->bUnicode ? "TRUE" : "FALSE", infoPtr->hwndSelf); + + return infoPtr->bUnicode; +} + + +inline static LRESULT +REBAR_GetVersion (REBAR_INFO *infoPtr) +{ + TRACE("version %d\n", infoPtr->iVersion); + return infoPtr->iVersion; +} + + +static LRESULT +REBAR_HitTest (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + LPRBHITTESTINFO lprbht = (LPRBHITTESTINFO)lParam; + + if (!lprbht) + return -1; + + REBAR_InternalHitTest (infoPtr, &lprbht->pt, &lprbht->flags, &lprbht->iBand); + + return lprbht->iBand; +} + + +static LRESULT +REBAR_IdToIndex (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + UINT i; + + if (infoPtr == NULL) + return -1; + + if (infoPtr->uNumBands < 1) + return -1; + + for (i = 0; i < infoPtr->uNumBands; i++) { + if (infoPtr->bands[i].wID == (UINT)wParam) { + TRACE("id %u is band %u found!\n", (UINT)wParam, i); + return i; + } + } + + TRACE("id %u is not found\n", (UINT)wParam); + return -1; +} + + +static LRESULT +REBAR_InsertBandA (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + LPREBARBANDINFOA lprbbi = (LPREBARBANDINFOA)lParam; + UINT uIndex = (UINT)wParam; + REBAR_BAND *lpBand; + + if (infoPtr == NULL) + return FALSE; + if (lprbbi == NULL) + return FALSE; + if (lprbbi->cbSize < REBARBANDINFOA_V3_SIZE) + return FALSE; + + /* trace the index as signed to see the -1 */ + TRACE("insert band at %d!\n", (INT)uIndex); + REBAR_DumpBandInfo (lprbbi); + + if (infoPtr->uNumBands == 0) { + infoPtr->bands = (REBAR_BAND *)Alloc (sizeof (REBAR_BAND)); + uIndex = 0; + } + else { + REBAR_BAND *oldBands = infoPtr->bands; + infoPtr->bands = + (REBAR_BAND *)Alloc ((infoPtr->uNumBands+1)*sizeof(REBAR_BAND)); + if (((INT)uIndex == -1) || (uIndex > infoPtr->uNumBands)) + uIndex = infoPtr->uNumBands; + + /* pre insert copy */ + if (uIndex > 0) { + memcpy (&infoPtr->bands[0], &oldBands[0], + uIndex * sizeof(REBAR_BAND)); + } + + /* post copy */ + if (uIndex < infoPtr->uNumBands) { + memcpy (&infoPtr->bands[uIndex+1], &oldBands[uIndex], + (infoPtr->uNumBands - uIndex) * sizeof(REBAR_BAND)); + } + + Free (oldBands); + } + + infoPtr->uNumBands++; + + TRACE("index %u!\n", uIndex); + + /* initialize band (infoPtr->bands[uIndex])*/ + lpBand = &infoPtr->bands[uIndex]; + lpBand->fMask = 0; + lpBand->fStatus = 0; + lpBand->clrFore = infoPtr->clrText; + lpBand->clrBack = infoPtr->clrBk; + lpBand->hwndChild = 0; + lpBand->hwndPrevParent = 0; + + REBAR_CommonSetupBand (infoPtr->hwndSelf, lprbbi, lpBand); + lpBand->lpText = NULL; + if ((lprbbi->fMask & RBBIM_TEXT) && (lprbbi->lpText)) { + INT len = MultiByteToWideChar( CP_ACP, 0, lprbbi->lpText, -1, NULL, 0 ); + if (len > 1) { + lpBand->lpText = (LPWSTR)Alloc (len*sizeof(WCHAR)); + MultiByteToWideChar( CP_ACP, 0, lprbbi->lpText, -1, lpBand->lpText, len ); + } + } + + REBAR_ValidateBand (infoPtr, lpBand); + /* On insert of second band, revalidate band 1 to possible add gripper */ + if (infoPtr->uNumBands == 2) + REBAR_ValidateBand (infoPtr, &infoPtr->bands[0]); + + REBAR_DumpBand (infoPtr); + + REBAR_Layout (infoPtr, NULL, TRUE, FALSE); + InvalidateRect(infoPtr->hwndSelf, 0, 1); + + return TRUE; +} + + +static LRESULT +REBAR_InsertBandW (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + LPREBARBANDINFOW lprbbi = (LPREBARBANDINFOW)lParam; + UINT uIndex = (UINT)wParam; + REBAR_BAND *lpBand; + + if (infoPtr == NULL) + return FALSE; + if (lprbbi == NULL) + return FALSE; + if (lprbbi->cbSize < REBARBANDINFOW_V3_SIZE) + return FALSE; + + /* trace the index as signed to see the -1 */ + TRACE("insert band at %d!\n", (INT)uIndex); + REBAR_DumpBandInfo ((LPREBARBANDINFOA)lprbbi); + + if (infoPtr->uNumBands == 0) { + infoPtr->bands = (REBAR_BAND *)Alloc (sizeof (REBAR_BAND)); + uIndex = 0; + } + else { + REBAR_BAND *oldBands = infoPtr->bands; + infoPtr->bands = + (REBAR_BAND *)Alloc ((infoPtr->uNumBands+1)*sizeof(REBAR_BAND)); + if (((INT)uIndex == -1) || (uIndex > infoPtr->uNumBands)) + uIndex = infoPtr->uNumBands; + + /* pre insert copy */ + if (uIndex > 0) { + memcpy (&infoPtr->bands[0], &oldBands[0], + uIndex * sizeof(REBAR_BAND)); + } + + /* post copy */ + if (uIndex <= infoPtr->uNumBands - 1) { + memcpy (&infoPtr->bands[uIndex+1], &oldBands[uIndex], + (infoPtr->uNumBands - uIndex) * sizeof(REBAR_BAND)); + } + + Free (oldBands); + } + + infoPtr->uNumBands++; + + TRACE("index %u!\n", uIndex); + + /* initialize band (infoPtr->bands[uIndex])*/ + lpBand = &infoPtr->bands[uIndex]; + lpBand->fMask = 0; + lpBand->fStatus = 0; + lpBand->clrFore = infoPtr->clrText; + lpBand->clrBack = infoPtr->clrBk; + lpBand->hwndChild = 0; + lpBand->hwndPrevParent = 0; + + REBAR_CommonSetupBand (infoPtr->hwndSelf, (LPREBARBANDINFOA)lprbbi, lpBand); + lpBand->lpText = NULL; + if ((lprbbi->fMask & RBBIM_TEXT) && (lprbbi->lpText)) { + INT len = lstrlenW (lprbbi->lpText); + if (len > 0) { + lpBand->lpText = (LPWSTR)Alloc ((len + 1)*sizeof(WCHAR)); + strcpyW (lpBand->lpText, lprbbi->lpText); + } + } + + REBAR_ValidateBand (infoPtr, lpBand); + /* On insert of second band, revalidate band 1 to possible add gripper */ + if (infoPtr->uNumBands == 2) + REBAR_ValidateBand (infoPtr, &infoPtr->bands[uIndex ? 0 : 1]); + + REBAR_DumpBand (infoPtr); + + REBAR_Layout (infoPtr, NULL, TRUE, FALSE); + InvalidateRect(infoPtr->hwndSelf, 0, 1); + + return TRUE; +} + + +static LRESULT +REBAR_MaximizeBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + REBAR_BAND *lpBand; + UINT uBand = (UINT) wParam; + + /* Validate */ + if ((infoPtr->uNumBands == 0) || + ((INT)uBand < 0) || (uBand >= infoPtr->uNumBands)) { + /* error !!! */ + ERR("Illegal MaximizeBand, requested=%d, current band count=%d\n", + (INT)uBand, infoPtr->uNumBands); + return FALSE; + } + + lpBand = &infoPtr->bands[uBand]; + + if (lParam && (lpBand->fMask & RBBIM_IDEALSIZE)) { + /* handle setting ideal size */ + lpBand->ccx = lpBand->cxIdeal; + } + else { + /* handle setting to max */ + FIXME("(uBand = %u fIdeal = %s) case not coded\n", + (UINT)wParam, lParam ? "TRUE" : "FALSE"); + return FALSE; + } + + infoPtr->fStatus |= BAND_NEEDS_LAYOUT; + REBAR_Layout (infoPtr, 0, TRUE, TRUE); + InvalidateRect (infoPtr->hwndSelf, 0, TRUE); + + return TRUE; + +} + + +static LRESULT +REBAR_MinimizeBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + REBAR_BAND *band, *lpBand; + UINT uBand = (UINT) wParam; + RECT newrect; + INT imindBand, imaxdBand, iprevBand, startBand, endBand; + INT movement, i; + + /* A "minimize" band is equivalent to "dragging" the gripper + * of than band to the right till the band is only the size + * of the cxHeader. + */ + + /* Validate */ + if ((infoPtr->uNumBands == 0) || + ((INT)uBand < 0) || (uBand >= infoPtr->uNumBands)) { + /* error !!! */ + ERR("Illegal MinimizeBand, requested=%d, current band count=%d\n", + (INT)uBand, infoPtr->uNumBands); + return FALSE; + } + + /* compute amount of movement and validate */ + lpBand = &infoPtr->bands[uBand]; + + if (infoPtr->dwStyle & CCS_VERT) + movement = lpBand->rcBand.bottom - lpBand->rcBand.top - + lpBand->cxHeader; + else + movement = lpBand->rcBand.right - lpBand->rcBand.left - + lpBand->cxHeader; + if (movement < 0) { + ERR("something is wrong, band=(%ld,%ld)-(%ld,%ld), cxheader=%d\n", + lpBand->rcBand.left, lpBand->rcBand.top, + lpBand->rcBand.right, lpBand->rcBand.bottom, + lpBand->cxHeader); + return FALSE; + } + + imindBand = -1; + imaxdBand = -1; + iprevBand = -1; /* to suppress warning message */ + + /* find the first band in row of the one whose is being minimized */ + for (i=0; iuNumBands; i++) { + band = &infoPtr->bands[i]; + if (HIDDENBAND(band)) continue; + if (band->iRow == lpBand->iRow) { + imaxdBand = i; + if (imindBand == -1) imindBand = i; + } + } + + /* if the selected band is first in row then need to expand */ + /* next visible band */ + if (imindBand == uBand) { + band = NULL; + movement = -movement; + /* find the first visible band to the right of the selected band */ + for (i=uBand+1; i<=imaxdBand; i++) { + band = &infoPtr->bands[i]; + if (!HIDDENBAND(band)) { + iprevBand = i; + LEADJ(band, movement); + band->ccx = rcBw(band); + break; + } + } + /* what case is this */ + if (iprevBand == -1) { + ERR("no previous visible band\n"); + return FALSE; + } + startBand = uBand; + endBand = iprevBand; + SetRect (&newrect, + lpBand->rcBand.left, + lpBand->rcBand.top, + band->rcBand.right, + band->rcBand.bottom); + } + /* otherwise expand previous visible band */ + else { + band = NULL; + /* find the first visible band to the left of the selected band */ + for (i=uBand-1; i>=imindBand; i--) { + band = &infoPtr->bands[i]; + if (!HIDDENBAND(band)) { + iprevBand = i; + READJ(band, movement); + band->ccx = rcBw(band); + break; + } + } + /* what case is this */ + if (iprevBand == -1) { + ERR("no previous visible band\n"); + return FALSE; + } + startBand = iprevBand; + endBand = uBand; + SetRect (&newrect, + band->rcBand.left, + band->rcBand.top, + lpBand->rcBand.right, + lpBand->rcBand.bottom); + } + + REBAR_Shrink (infoPtr, lpBand, movement, uBand); + + /* recompute all rectangles */ + if (infoPtr->dwStyle & CCS_VERT) { + REBAR_CalcVertBand (infoPtr, startBand, endBand+1, + FALSE); + } + else { + REBAR_CalcHorzBand (infoPtr, startBand, endBand+1, + FALSE); + } + + TRACE("bands after minimize, see band # %d, %d\n", + startBand, endBand); + REBAR_DumpBand (infoPtr); + + REBAR_MoveChildWindows (infoPtr, startBand, endBand+1); + + InvalidateRect (infoPtr->hwndSelf, &newrect, TRUE); + UpdateWindow (infoPtr->hwndSelf); + return FALSE; +} + + +static LRESULT +REBAR_MoveBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + REBAR_BAND *oldBands = infoPtr->bands; + REBAR_BAND holder; + UINT uFrom = (UINT)wParam; + UINT uTo = (UINT)lParam; + + /* Validate */ + if ((infoPtr->uNumBands == 0) || + ((INT)uFrom < 0) || (uFrom >= infoPtr->uNumBands) || + ((INT)uTo < 0) || (uTo >= infoPtr->uNumBands)) { + /* error !!! */ + ERR("Illegal MoveBand, from=%d, to=%d, current band count=%d\n", + (INT)uFrom, (INT)uTo, infoPtr->uNumBands); + return FALSE; + } + + /* save one to be moved */ + memcpy (&holder, &oldBands[uFrom], sizeof(REBAR_BAND)); + + /* close up rest of bands (pseudo delete) */ + if (uFrom < infoPtr->uNumBands - 1) { + memcpy (&oldBands[uFrom], &oldBands[uFrom+1], + (infoPtr->uNumBands - uFrom - 1) * sizeof(REBAR_BAND)); + } + + /* allocate new space and copy rest of bands into it */ + infoPtr->bands = + (REBAR_BAND *)Alloc ((infoPtr->uNumBands)*sizeof(REBAR_BAND)); + + /* pre insert copy */ + if (uTo > 0) { + memcpy (&infoPtr->bands[0], &oldBands[0], + uTo * sizeof(REBAR_BAND)); + } + + /* set moved band */ + memcpy (&infoPtr->bands[uTo], &holder, sizeof(REBAR_BAND)); + + /* post copy */ + if (uTo < infoPtr->uNumBands - 1) { + memcpy (&infoPtr->bands[uTo+1], &oldBands[uTo], + (infoPtr->uNumBands - uTo - 1) * sizeof(REBAR_BAND)); + } + + Free (oldBands); + + TRACE("moved band %d to index %d\n", uFrom, uTo); + REBAR_DumpBand (infoPtr); + + infoPtr->fStatus |= BAND_NEEDS_LAYOUT; + /* **************************************************** */ + /* */ + /* We do not do a REBAR_Layout here because the native */ + /* control does not do that. The actual layout and */ + /* repaint is done by the *next* real action, ex.: */ + /* RB_INSERTBAND, RB_DELETEBAND, RB_SIZETORECT, etc. */ + /* */ + /* **************************************************** */ + + return TRUE; +} + + +/* return TRUE if two strings are different */ +static BOOL +REBAR_strdifW( LPCWSTR a, LPCWSTR b ) +{ + return ( (a && !b) || (b && !a) || (a && b && lstrcmpW(a, b) ) ); +} + +static LRESULT +REBAR_SetBandInfoA (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + LPREBARBANDINFOA lprbbi = (LPREBARBANDINFOA)lParam; + REBAR_BAND *lpBand; + BOOL bChanged; + + if (lprbbi == NULL) + return FALSE; + if (lprbbi->cbSize < REBARBANDINFOA_V3_SIZE) + return FALSE; + if ((UINT)wParam >= infoPtr->uNumBands) + return FALSE; + + TRACE("index %u\n", (UINT)wParam); + REBAR_DumpBandInfo (lprbbi); + + /* set band information */ + lpBand = &infoPtr->bands[(UINT)wParam]; + + bChanged = REBAR_CommonSetupBand (infoPtr->hwndSelf, lprbbi, lpBand); + if (lprbbi->fMask & RBBIM_TEXT) { + LPWSTR wstr = NULL; + + if (lprbbi->lpText) + { + INT len; + len = MultiByteToWideChar( CP_ACP, 0, lprbbi->lpText, -1, NULL, 0 ); + if (len > 1) + wstr = (LPWSTR)Alloc (len*sizeof(WCHAR)); + if (wstr) + MultiByteToWideChar( CP_ACP, 0, lprbbi->lpText, -1, wstr, len ); + } + if (REBAR_strdifW(lpBand->lpText, wstr)) { + if (lpBand->lpText) { + Free (lpBand->lpText); + lpBand->lpText = NULL; + } + if (wstr) { + lpBand->lpText = wstr; + wstr = NULL; + } + bChanged = TRUE; + } + if (wstr) + Free (wstr); + } + + REBAR_ValidateBand (infoPtr, lpBand); + + REBAR_DumpBand (infoPtr); + + if (bChanged && (lprbbi->fMask & (RBBIM_CHILDSIZE | RBBIM_SIZE))) { + REBAR_Layout (infoPtr, NULL, TRUE, FALSE); + InvalidateRect(infoPtr->hwndSelf, 0, 1); + } + + return TRUE; +} + +static LRESULT +REBAR_SetBandInfoW (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + LPREBARBANDINFOW lprbbi = (LPREBARBANDINFOW)lParam; + REBAR_BAND *lpBand; + BOOL bChanged; + + if (lprbbi == NULL) + return FALSE; + if (lprbbi->cbSize < REBARBANDINFOW_V3_SIZE) + return FALSE; + if ((UINT)wParam >= infoPtr->uNumBands) + return FALSE; + + TRACE("index %u\n", (UINT)wParam); + REBAR_DumpBandInfo ((LPREBARBANDINFOA)lprbbi); + + /* set band information */ + lpBand = &infoPtr->bands[(UINT)wParam]; + + bChanged = REBAR_CommonSetupBand (infoPtr->hwndSelf, (LPREBARBANDINFOA)lprbbi, lpBand); + if( (lprbbi->fMask & RBBIM_TEXT) && + REBAR_strdifW( lpBand->lpText, lprbbi->lpText ) ) { + if (lpBand->lpText) { + Free (lpBand->lpText); + lpBand->lpText = NULL; + } + if (lprbbi->lpText) { + INT len = lstrlenW (lprbbi->lpText); + if (len > 0) + { + lpBand->lpText = (LPWSTR)Alloc ((len + 1)*sizeof(WCHAR)); + strcpyW (lpBand->lpText, lprbbi->lpText); + } + } + bChanged = TRUE; + } + + REBAR_ValidateBand (infoPtr, lpBand); + + REBAR_DumpBand (infoPtr); + + if ( bChanged && (lprbbi->fMask & (RBBIM_CHILDSIZE | RBBIM_SIZE)) ) { + REBAR_Layout (infoPtr, NULL, TRUE, FALSE); + InvalidateRect(infoPtr->hwndSelf, 0, 1); + } + + return TRUE; +} + + +static LRESULT +REBAR_SetBarInfo (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + LPREBARINFO lpInfo = (LPREBARINFO)lParam; + REBAR_BAND *lpBand; + UINT i; + + if (lpInfo == NULL) + return FALSE; + + if (lpInfo->cbSize < sizeof (REBARINFO)) + return FALSE; + + TRACE("setting bar info!\n"); + + if (lpInfo->fMask & RBIM_IMAGELIST) { + infoPtr->himl = lpInfo->himl; + if (infoPtr->himl) { + INT cx, cy; + ImageList_GetIconSize (infoPtr->himl, &cx, &cy); + infoPtr->imageSize.cx = cx; + infoPtr->imageSize.cy = cy; + } + else { + infoPtr->imageSize.cx = 0; + infoPtr->imageSize.cy = 0; + } + TRACE("new image cx=%ld, cy=%ld\n", infoPtr->imageSize.cx, + infoPtr->imageSize.cy); + } + + /* revalidate all bands to reset flags for images in headers of bands */ + for (i=0; iuNumBands; i++) { + lpBand = &infoPtr->bands[i]; + REBAR_ValidateBand (infoPtr, lpBand); + } + + return TRUE; +} + + +static LRESULT +REBAR_SetBkColor (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + COLORREF clrTemp; + + clrTemp = infoPtr->clrBk; + infoPtr->clrBk = (COLORREF)lParam; + + TRACE("background color 0x%06lx!\n", infoPtr->clrBk); + + return clrTemp; +} + + +/* << REBAR_SetColorScheme >> */ +/* << REBAR_SetPalette >> */ + + +static LRESULT +REBAR_SetParent (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + HWND hwndTemp = infoPtr->hwndNotify; + + infoPtr->hwndNotify = (HWND)wParam; + + return (LRESULT)hwndTemp; +} + + +static LRESULT +REBAR_SetTextColor (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + COLORREF clrTemp; + + clrTemp = infoPtr->clrText; + infoPtr->clrText = (COLORREF)lParam; + + TRACE("text color 0x%06lx!\n", infoPtr->clrText); + + return clrTemp; +} + + +/* << REBAR_SetTooltips >> */ + + +inline static LRESULT +REBAR_SetUnicodeFormat (REBAR_INFO *infoPtr, WPARAM wParam) +{ + BOOL bTemp = infoPtr->bUnicode; + + TRACE("to %s hwnd=%p, was %s\n", + ((BOOL)wParam) ? "TRUE" : "FALSE", infoPtr->hwndSelf, + (bTemp) ? "TRUE" : "FALSE"); + + infoPtr->bUnicode = (BOOL)wParam; + + return bTemp; +} + + +static LRESULT +REBAR_SetVersion (REBAR_INFO *infoPtr, INT iVersion) +{ + INT iOldVersion = infoPtr->iVersion; + + if (iVersion > COMCTL32_VERSION) + return -1; + + infoPtr->iVersion = iVersion; + + TRACE("new version %d\n", iVersion); + + return iOldVersion; +} + + +static LRESULT +REBAR_ShowBand (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + REBAR_BAND *lpBand; + + if (((INT)wParam < 0) || ((INT)wParam > infoPtr->uNumBands)) + return FALSE; + + lpBand = &infoPtr->bands[(INT)wParam]; + + if ((BOOL)lParam) { + TRACE("show band %d\n", (INT)wParam); + lpBand->fStyle = lpBand->fStyle & ~RBBS_HIDDEN; + if (IsWindow (lpBand->hwndChild)) + ShowWindow (lpBand->hwndChild, SW_SHOW); + } + else { + TRACE("hide band %d\n", (INT)wParam); + lpBand->fStyle = lpBand->fStyle | RBBS_HIDDEN; + if (IsWindow (lpBand->hwndChild)) + ShowWindow (lpBand->hwndChild, SW_HIDE); + } + + infoPtr->fStatus |= BAND_NEEDS_LAYOUT; + REBAR_Layout (infoPtr, NULL, TRUE, FALSE); + InvalidateRect(infoPtr->hwndSelf, 0, 1); + + return TRUE; +} + + +static LRESULT +REBAR_SizeToRect (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + LPRECT lpRect = (LPRECT)lParam; + RECT t1; + + if (lpRect == NULL) + return FALSE; + + TRACE("[%ld %ld %ld %ld]\n", + lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + + /* what is going on???? */ + GetWindowRect(infoPtr->hwndSelf, &t1); + TRACE("window rect [%ld %ld %ld %ld]\n", + t1.left, t1.top, t1.right, t1.bottom); + GetClientRect(infoPtr->hwndSelf, &t1); + TRACE("client rect [%ld %ld %ld %ld]\n", + t1.left, t1.top, t1.right, t1.bottom); + + /* force full _Layout processing */ + TRACE("setting NEEDS_LAYOUT\n"); + infoPtr->fStatus |= BAND_NEEDS_LAYOUT; + REBAR_Layout (infoPtr, lpRect, TRUE, FALSE); + InvalidateRect (infoPtr->hwndSelf, NULL, TRUE); + return TRUE; +} + + + +static LRESULT +REBAR_Create (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + LPCREATESTRUCTW cs = (LPCREATESTRUCTW) lParam; + RECT wnrc1, clrc1; + + if (TRACE_ON(rebar)) { + GetWindowRect(infoPtr->hwndSelf, &wnrc1); + GetClientRect(infoPtr->hwndSelf, &clrc1); + TRACE("window=(%ld,%ld)-(%ld,%ld) client=(%ld,%ld)-(%ld,%ld) cs=(%d,%d %dx%d)\n", + wnrc1.left, wnrc1.top, wnrc1.right, wnrc1.bottom, + clrc1.left, clrc1.top, clrc1.right, clrc1.bottom, + cs->x, cs->y, cs->cx, cs->cy); + } + + TRACE("created!\n"); + return 0; +} + + +static LRESULT +REBAR_Destroy (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + REBAR_BAND *lpBand; + UINT i; + + + /* free rebar bands */ + if ((infoPtr->uNumBands > 0) && infoPtr->bands) { + /* clean up each band */ + for (i = 0; i < infoPtr->uNumBands; i++) { + lpBand = &infoPtr->bands[i]; + + /* delete text strings */ + if (lpBand->lpText) { + Free (lpBand->lpText); + lpBand->lpText = NULL; + } + /* destroy child window */ + DestroyWindow (lpBand->hwndChild); + } + + /* free band array */ + Free (infoPtr->bands); + infoPtr->bands = NULL; + } + + DestroyCursor (infoPtr->hcurArrow); + DestroyCursor (infoPtr->hcurHorz); + DestroyCursor (infoPtr->hcurVert); + DestroyCursor (infoPtr->hcurDrag); + if(infoPtr->hDefaultFont) DeleteObject (infoPtr->hDefaultFont); + SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0); + + /* free rebar info data */ + Free (infoPtr); + TRACE("destroyed!\n"); + return 0; +} + + +static LRESULT +REBAR_EraseBkGnd (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + RECT cliprect; + + if (GetClipBox ( (HDC)wParam, &cliprect)) + return REBAR_InternalEraseBkGnd (infoPtr, wParam, lParam, &cliprect); + return 0; +} + + +static LRESULT +REBAR_GetFont (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + return (LRESULT)infoPtr->hFont; +} + +static LRESULT +REBAR_PushChevron(REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + if (wParam >= 0 && (UINT)wParam < infoPtr->uNumBands) + { + NMREBARCHEVRON nmrbc; + REBAR_BAND *lpBand = &infoPtr->bands[wParam]; + + TRACE("Pressed chevron on band %d\n", wParam); + + /* redraw chevron in pushed state */ + lpBand->fDraw |= DRAW_CHEVRONPUSHED; + RedrawWindow(infoPtr->hwndSelf, &lpBand->rcChevron,0, + RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW); + + /* notify app so it can display a popup menu or whatever */ + nmrbc.uBand = wParam; + nmrbc.wID = lpBand->wID; + nmrbc.lParam = lpBand->lParam; + nmrbc.rc = lpBand->rcChevron; + nmrbc.lParamNM = lParam; + REBAR_Notify((NMHDR*)&nmrbc, infoPtr, RBN_CHEVRONPUSHED); + + /* redraw chevron in previous state */ + lpBand->fDraw &= ~DRAW_CHEVRONPUSHED; + InvalidateRect(infoPtr->hwndSelf, &lpBand->rcChevron, TRUE); + + return TRUE; + } + return FALSE; +} + +static LRESULT +REBAR_LButtonDown (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + REBAR_BAND *lpBand; + UINT htFlags; + UINT iHitBand; + POINT ptMouseDown; + ptMouseDown.x = (INT)LOWORD(lParam); + ptMouseDown.y = (INT)HIWORD(lParam); + + REBAR_InternalHitTest(infoPtr, &ptMouseDown, &htFlags, &iHitBand); + lpBand = &infoPtr->bands[iHitBand]; + + if (htFlags == RBHT_CHEVRON) + { + REBAR_PushChevron(infoPtr, iHitBand, 0); + } + else if (htFlags == RBHT_GRABBER || htFlags == RBHT_CAPTION) + { + TRACE("Starting drag\n"); + + SetCapture (infoPtr->hwndSelf); + infoPtr->iGrabbedBand = iHitBand; + + /* save off the LOWORD and HIWORD of lParam as initial x,y */ + infoPtr->dragStart.x = (short)LOWORD(lParam); + infoPtr->dragStart.y = (short)HIWORD(lParam); + infoPtr->dragNow = infoPtr->dragStart; + if (infoPtr->dwStyle & CCS_VERT) + infoPtr->ihitoffset = infoPtr->dragStart.y - (lpBand->rcBand.top+REBAR_PRE_GRIPPER); + else + infoPtr->ihitoffset = infoPtr->dragStart.x - (lpBand->rcBand.left+REBAR_PRE_GRIPPER); + } + return 0; +} + +static LRESULT +REBAR_LButtonUp (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + if (infoPtr->iGrabbedBand >= 0) + { + NMHDR layout; + RECT rect; + + infoPtr->dragStart.x = 0; + infoPtr->dragStart.y = 0; + infoPtr->dragNow = infoPtr->dragStart; + + ReleaseCapture (); + + if (infoPtr->fStatus & BEGIN_DRAG_ISSUED) { + REBAR_Notify(&layout, infoPtr, RBN_LAYOUTCHANGED); + REBAR_Notify_NMREBAR (infoPtr, infoPtr->iGrabbedBand, RBN_ENDDRAG); + infoPtr->fStatus &= ~BEGIN_DRAG_ISSUED; + } + + infoPtr->iGrabbedBand = -1; + + GetClientRect(infoPtr->hwndSelf, &rect); + InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); + } + + return 0; +} + +static LRESULT +REBAR_MouseLeave (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + if (infoPtr->ichevronhotBand >= 0) + { + REBAR_BAND *lpChevronBand = &infoPtr->bands[infoPtr->ichevronhotBand]; + if (lpChevronBand->fDraw & DRAW_CHEVRONHOT) + { + lpChevronBand->fDraw &= ~DRAW_CHEVRONHOT; + InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE); + } + } + infoPtr->iOldBand = -1; + infoPtr->ichevronhotBand = -2; + + return TRUE; +} + +static LRESULT +REBAR_MouseMove (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + REBAR_BAND *lpChevronBand; + POINT ptMove; + + ptMove.x = (short)LOWORD(lParam); + ptMove.y = (short)HIWORD(lParam); + + /* if we are currently dragging a band */ + if (infoPtr->iGrabbedBand >= 0) + { + REBAR_BAND *band1, *band2; + + if (GetCapture() != infoPtr->hwndSelf) + ERR("We are dragging but haven't got capture?!?\n"); + + band1 = &infoPtr->bands[infoPtr->iGrabbedBand-1]; + band2 = &infoPtr->bands[infoPtr->iGrabbedBand]; + + /* if mouse did not move much, exit */ + if ((abs(ptMove.x - infoPtr->dragNow.x) <= mindragx) && + (abs(ptMove.y - infoPtr->dragNow.y) <= mindragy)) return 0; + + /* Test for valid drag case - must not be first band in row */ + if (infoPtr->dwStyle & CCS_VERT) { + if ((ptMove.x < band2->rcBand.left) || + (ptMove.x > band2->rcBand.right) || + ((infoPtr->iGrabbedBand > 0) && (band1->iRow != band2->iRow))) { + FIXME("Cannot drag to other rows yet!!\n"); + } + else { + REBAR_HandleLRDrag (infoPtr, &ptMove); + } + } + else { + if ((ptMove.y < band2->rcBand.top) || + (ptMove.y > band2->rcBand.bottom) || + ((infoPtr->iGrabbedBand > 0) && (band1->iRow != band2->iRow))) { + FIXME("Cannot drag to other rows yet!!\n"); + } + else { + REBAR_HandleLRDrag (infoPtr, &ptMove); + } + } + } + else + { + INT iHitBand; + UINT htFlags; + TRACKMOUSEEVENT trackinfo; + + REBAR_InternalHitTest(infoPtr, &ptMove, &htFlags, &iHitBand); + + if (infoPtr->iOldBand >= 0 && infoPtr->iOldBand == infoPtr->ichevronhotBand) + { + lpChevronBand = &infoPtr->bands[infoPtr->ichevronhotBand]; + if (lpChevronBand->fDraw & DRAW_CHEVRONHOT) + { + lpChevronBand->fDraw &= ~DRAW_CHEVRONHOT; + InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE); + } + infoPtr->ichevronhotBand = -2; + } + + if (htFlags == RBHT_CHEVRON) + { + /* fill in the TRACKMOUSEEVENT struct */ + trackinfo.cbSize = sizeof(TRACKMOUSEEVENT); + trackinfo.dwFlags = TME_QUERY; + trackinfo.hwndTrack = infoPtr->hwndSelf; + trackinfo.dwHoverTime = 0; + + /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */ + _TrackMouseEvent(&trackinfo); + + /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */ + if(!(trackinfo.dwFlags & TME_LEAVE)) + { + trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */ + + /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */ + /* and can properly deactivate the hot chevron */ + _TrackMouseEvent(&trackinfo); + } + + lpChevronBand = &infoPtr->bands[iHitBand]; + if (!(lpChevronBand->fDraw & DRAW_CHEVRONHOT)) + { + lpChevronBand->fDraw |= DRAW_CHEVRONHOT; + InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE); + infoPtr->ichevronhotBand = iHitBand; + } + } + infoPtr->iOldBand = iHitBand; + } + + return 0; +} + + +inline static LRESULT +REBAR_NCCalcSize (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + if (infoPtr->dwStyle & WS_BORDER) { + InflateRect((LPRECT)lParam, -GetSystemMetrics(SM_CXEDGE), + -GetSystemMetrics(SM_CYEDGE)); + } + TRACE("new client=(%ld,%ld)-(%ld,%ld)\n", + ((LPRECT)lParam)->left, ((LPRECT)lParam)->top, + ((LPRECT)lParam)->right, ((LPRECT)lParam)->bottom); + return 0; +} + + +static LRESULT +REBAR_NCCreate (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + LPCREATESTRUCTW cs = (LPCREATESTRUCTW) lParam; + REBAR_INFO *infoPtr = REBAR_GetInfoPtr (hwnd); + RECT wnrc1, clrc1; + NONCLIENTMETRICSW ncm; + HFONT tfont; + INT i; + + if (infoPtr != NULL) { + ERR("Strange info structure pointer *not* NULL\n"); + return FALSE; + } + + if (TRACE_ON(rebar)) { + GetWindowRect(hwnd, &wnrc1); + GetClientRect(hwnd, &clrc1); + TRACE("window=(%ld,%ld)-(%ld,%ld) client=(%ld,%ld)-(%ld,%ld) cs=(%d,%d %dx%d)\n", + wnrc1.left, wnrc1.top, wnrc1.right, wnrc1.bottom, + clrc1.left, clrc1.top, clrc1.right, clrc1.bottom, + cs->x, cs->y, cs->cx, cs->cy); + } + + /* allocate memory for info structure */ + infoPtr = (REBAR_INFO *)Alloc (sizeof(REBAR_INFO)); + SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); + + /* initialize info structure - initial values are 0 */ + infoPtr->clrBk = CLR_NONE; + infoPtr->clrText = CLR_NONE; + infoPtr->clrBtnText = GetSysColor (COLOR_BTNTEXT); + infoPtr->clrBtnFace = GetSysColor (COLOR_BTNFACE); + infoPtr->iOldBand = -1; + infoPtr->ichevronhotBand = -2; + infoPtr->iGrabbedBand = -1; + infoPtr->hwndSelf = hwnd; + infoPtr->DoRedraw = TRUE; + infoPtr->hcurArrow = LoadCursorW (0, (LPWSTR)IDC_ARROW); + infoPtr->hcurHorz = LoadCursorW (0, (LPWSTR)IDC_SIZEWE); + infoPtr->hcurVert = LoadCursorW (0, (LPWSTR)IDC_SIZENS); + infoPtr->hcurDrag = LoadCursorW (0, (LPWSTR)IDC_SIZE); + infoPtr->bUnicode = IsWindowUnicode (hwnd); + infoPtr->fStatus = CREATE_RUNNING; + infoPtr->hFont = GetStockObject (SYSTEM_FONT); + + /* issue WM_NOTIFYFORMAT to get unicode status of parent */ + i = SendMessageW(REBAR_GetNotifyParent (infoPtr), + WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY); + if ((i < NFR_ANSI) || (i > NFR_UNICODE)) { + ERR("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n", i); + i = NFR_ANSI; + } + infoPtr->NtfUnicode = (i == NFR_UNICODE) ? 1 : 0; + + /* add necessary styles to the requested styles */ + infoPtr->dwStyle = cs->style | WS_VISIBLE | CCS_TOP; + SetWindowLongW (hwnd, GWL_STYLE, infoPtr->dwStyle); + + /* get font handle for Caption Font */ + ncm.cbSize = sizeof(ncm); + SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0); + /* if the font is bold, set to normal */ + if (ncm.lfCaptionFont.lfWeight > FW_NORMAL) { + ncm.lfCaptionFont.lfWeight = FW_NORMAL; + } + tfont = CreateFontIndirectW (&ncm.lfCaptionFont); + if (tfont) { + infoPtr->hFont = infoPtr->hDefaultFont = tfont; + } + +/* native does: + GetSysColor (numerous); + GetSysColorBrush (numerous) (see WM_SYSCOLORCHANGE); + *GetStockObject (SYSTEM_FONT); + *SetWindowLong (hwnd, 0, info ptr); + *WM_NOTIFYFORMAT; + *SetWindowLong (hwnd, GWL_STYLE, style+0x10000001); + WS_VISIBLE = 0x10000000; + CCS_TOP = 0x00000001; + *SystemParametersInfo (SPI_GETNONCLIENTMETRICS...); + *CreateFontIndirect (lfCaptionFont from above); + GetDC (); + SelectObject (hdc, fontabove); + GetTextMetrics (hdc, ); guessing is tmHeight + SelectObject (hdc, oldfont); + ReleaseDC (); + GetWindowRect (); + MapWindowPoints (0, parent, rectabove, 2); + GetWindowRect (); + GetClientRect (); + ClientToScreen (clientrect); + SetWindowPos (hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER); + */ + return TRUE; +} + + +static LRESULT +REBAR_NCHitTest (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + NMMOUSE nmmouse; + POINT clpt; + INT i; + UINT scrap; + LRESULT ret = HTCLIENT; + + /* + * Differences from doc at MSDN (as observed with version 4.71 of + * comctl32.dll + * 1. doc says nmmouse.pt is in screen coord, trace shows client coord. + * 2. if band is not identified .dwItemSpec is 0xffffffff. + * 3. native always seems to return HTCLIENT if notify return is 0. + */ + + clpt.x = (short)LOWORD(lParam); + clpt.y = (short)HIWORD(lParam); + ScreenToClient (infoPtr->hwndSelf, &clpt); + REBAR_InternalHitTest (infoPtr, &clpt, &scrap, + (INT *)&nmmouse.dwItemSpec); + nmmouse.dwItemData = 0; + nmmouse.pt = clpt; + nmmouse.dwHitInfo = 0; + if ((i = REBAR_Notify((NMHDR *) &nmmouse, infoPtr, NM_NCHITTEST))) { + TRACE("notify changed return value from %ld to %d\n", + ret, i); + ret = (LRESULT) i; + } + TRACE("returning %ld, client point (%ld,%ld)\n", ret, clpt.x, clpt.y); + return ret; +} + + +static LRESULT +REBAR_NCPaint (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + RECT rcWindow; + HDC hdc; + + if (infoPtr->dwStyle & WS_MINIMIZE) + return 0; /* Nothing to do */ + + if (infoPtr->dwStyle & WS_BORDER) { + + /* adjust rectangle and draw the necessary edge */ + if (!(hdc = GetDCEx( infoPtr->hwndSelf, 0, DCX_USESTYLE | DCX_WINDOW ))) + return 0; + GetWindowRect (infoPtr->hwndSelf, &rcWindow); + OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top); + TRACE("rect (%ld,%ld)-(%ld,%ld)\n", + rcWindow.left, rcWindow.top, + rcWindow.right, rcWindow.bottom); + DrawEdge (hdc, &rcWindow, EDGE_ETCHED, BF_RECT); + ReleaseDC( infoPtr->hwndSelf, hdc ); + } + + return 0; +} + + +static LRESULT +REBAR_NotifyFormat (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + INT i; + + if (lParam == NF_REQUERY) { + i = SendMessageW(REBAR_GetNotifyParent (infoPtr), + WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY); + if ((i < NFR_ANSI) || (i > NFR_UNICODE)) { + ERR("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n", i); + i = NFR_ANSI; + } + infoPtr->NtfUnicode = (i == NFR_UNICODE) ? 1 : 0; + return (LRESULT)i; + } + return (LRESULT)((infoPtr->bUnicode) ? NFR_UNICODE : NFR_ANSI); +} + + +static LRESULT +REBAR_Paint (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + HDC hdc; + PAINTSTRUCT ps; + RECT rc; + + GetClientRect(infoPtr->hwndSelf, &rc); + hdc = wParam==0 ? BeginPaint (infoPtr->hwndSelf, &ps) : (HDC)wParam; + + TRACE("painting (%ld,%ld)-(%ld,%ld) client (%ld,%ld)-(%ld,%ld)\n", + ps.rcPaint.left, ps.rcPaint.top, + ps.rcPaint.right, ps.rcPaint.bottom, + rc.left, rc.top, rc.right, rc.bottom); + + if (ps.fErase) { + /* Erase area of paint if requested */ + REBAR_InternalEraseBkGnd (infoPtr, wParam, lParam, &ps.rcPaint); + } + + REBAR_Refresh (infoPtr, hdc); + if (!wParam) + EndPaint (infoPtr->hwndSelf, &ps); + return 0; +} + + +static LRESULT +REBAR_SetCursor (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + POINT pt; + UINT flags; + + TRACE("code=0x%X id=0x%X\n", LOWORD(lParam), HIWORD(lParam)); + + GetCursorPos (&pt); + ScreenToClient (infoPtr->hwndSelf, &pt); + + REBAR_InternalHitTest (infoPtr, &pt, &flags, NULL); + + if (flags == RBHT_GRABBER) { + if ((infoPtr->dwStyle & CCS_VERT) && + !(infoPtr->dwStyle & RBS_VERTICALGRIPPER)) + SetCursor (infoPtr->hcurVert); + else + SetCursor (infoPtr->hcurHorz); + } + else if (flags != RBHT_CLIENT) + SetCursor (infoPtr->hcurArrow); + + return 0; +} + + +static LRESULT +REBAR_SetFont (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + RECT rcClient; + REBAR_BAND *lpBand; + UINT i; + + infoPtr->hFont = (HFONT)wParam; + + /* revalidate all bands to change sizes of text in headers of bands */ + for (i=0; iuNumBands; i++) { + lpBand = &infoPtr->bands[i]; + REBAR_ValidateBand (infoPtr, lpBand); + } + + + if (LOWORD(lParam)) { + GetClientRect (infoPtr->hwndSelf, &rcClient); + REBAR_Layout (infoPtr, &rcClient, FALSE, TRUE); + } + + return 0; +} + + +inline static LRESULT +REBAR_SetRedraw (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) + /***************************************************** + * + * Function; + * Handles the WM_SETREDRAW message. + * + * Documentation: + * According to testing V4.71 of COMCTL32 returns the + * *previous* status of the redraw flag (either 0 or -1) + * instead of the MSDN documented value of 0 if handled + * + *****************************************************/ +{ + BOOL oldredraw = infoPtr->DoRedraw; + + TRACE("set to %s, fStatus=%08x\n", + (wParam) ? "TRUE" : "FALSE", infoPtr->fStatus); + infoPtr->DoRedraw = (BOOL) wParam; + if (wParam) { + if (infoPtr->fStatus & BAND_NEEDS_REDRAW) { + REBAR_MoveChildWindows (infoPtr, 0, infoPtr->uNumBands); + REBAR_ForceResize (infoPtr); + InvalidateRect (infoPtr->hwndSelf, 0, TRUE); + } + infoPtr->fStatus &= ~BAND_NEEDS_REDRAW; + } + return (oldredraw) ? -1 : 0; +} + + +static LRESULT +REBAR_Size (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + RECT rcClient; + + /* auto resize deadlock check */ + if (infoPtr->fStatus & AUTO_RESIZE) { + infoPtr->fStatus &= ~AUTO_RESIZE; + TRACE("AUTO_RESIZE was set, reset, fStatus=%08x lparam=%08lx\n", + infoPtr->fStatus, lParam); + return 0; + } + + if (infoPtr->fStatus & CREATE_RUNNING) { + /* still in CreateWindow */ + RECT rcWin; + + if ((INT)wParam != SIZE_RESTORED) { + ERR("WM_SIZE in create and flags=%08x, lParam=%08lx\n", + wParam, lParam); + } + + TRACE("still in CreateWindow\n"); + infoPtr->fStatus &= ~CREATE_RUNNING; + GetWindowRect ( infoPtr->hwndSelf, &rcWin); + TRACE("win rect (%ld,%ld)-(%ld,%ld)\n", + rcWin.left, rcWin.top, rcWin.right, rcWin.bottom); + + if ((lParam == 0) && (rcWin.right-rcWin.left == 0) && + (rcWin.bottom-rcWin.top == 0)) { + /* native control seems to do this */ + GetClientRect (GetParent(infoPtr->hwndSelf), &rcClient); + TRACE("sizing rebar, message and client zero, parent client (%ld,%ld)\n", + rcClient.right, rcClient.bottom); + } + else { + INT cx, cy; + + cx = rcWin.right - rcWin.left; + cy = rcWin.bottom - rcWin.top; + if ((cx == LOWORD(lParam)) && (cy == HIWORD(lParam))) { + return 0; + } + + /* do the actual WM_SIZE request */ + GetClientRect (infoPtr->hwndSelf, &rcClient); + TRACE("sizing rebar from (%ld,%ld) to (%d,%d), client (%ld,%ld)\n", + infoPtr->calcSize.cx, infoPtr->calcSize.cy, + LOWORD(lParam), HIWORD(lParam), + rcClient.right, rcClient.bottom); + } + } + else { + if ((INT)wParam != SIZE_RESTORED) { + ERR("WM_SIZE out of create and flags=%08x, lParam=%08lx\n", + wParam, lParam); + } + + /* Handle cases when outside of the CreateWindow process */ + + GetClientRect (infoPtr->hwndSelf, &rcClient); + if ((lParam == 0) && (rcClient.right + rcClient.bottom != 0) && + (infoPtr->dwStyle & RBS_AUTOSIZE)) { + /* on a WM_SIZE to zero and current client not zero and AUTOSIZE */ + /* native seems to use the current client rect for the size */ + infoPtr->fStatus |= BAND_NEEDS_LAYOUT; + TRACE("sizing rebar to client (%ld,%ld) size is zero but AUTOSIZE set\n", + rcClient.right, rcClient.bottom); + } + else { + TRACE("sizing rebar from (%ld,%ld) to (%d,%d), client (%ld,%ld)\n", + infoPtr->calcSize.cx, infoPtr->calcSize.cy, + LOWORD(lParam), HIWORD(lParam), + rcClient.right, rcClient.bottom); + } + } + + if (infoPtr->dwStyle & RBS_AUTOSIZE) { + NMRBAUTOSIZE autosize; + + GetClientRect(infoPtr->hwndSelf, &autosize.rcTarget); + autosize.fChanged = 0; /* ??? */ + autosize.rcActual = autosize.rcTarget; /* ??? */ + REBAR_Notify((NMHDR *) &autosize, infoPtr, RBN_AUTOSIZE); + TRACE("RBN_AUTOSIZE client=(%ld,%ld), lp=%08lx\n", + autosize.rcTarget.right, autosize.rcTarget.bottom, lParam); + } + + if ((infoPtr->calcSize.cx != rcClient.right) || + (infoPtr->calcSize.cy != rcClient.bottom)) + infoPtr->fStatus |= BAND_NEEDS_LAYOUT; + + REBAR_Layout (infoPtr, &rcClient, TRUE, TRUE); + + return 0; +} + + +static LRESULT +REBAR_StyleChanged (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + STYLESTRUCT *ss = (STYLESTRUCT *)lParam; + + TRACE("current style=%08lx, styleOld=%08lx, style being set to=%08lx\n", + infoPtr->dwStyle, ss->styleOld, ss->styleNew); + infoPtr->dwStyle = ss->styleNew; + + return FALSE; +} + + +static LRESULT +REBAR_WindowPosChanged (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + WINDOWPOS *lpwp = (WINDOWPOS *)lParam; + LRESULT ret; + RECT rc; + + /* Save the new origin of this window - used by _ForceResize */ + infoPtr->origin.x = lpwp->x; + infoPtr->origin.y = lpwp->y; + ret = DefWindowProcW(infoPtr->hwndSelf, WM_WINDOWPOSCHANGED, + wParam, lParam); + GetWindowRect(infoPtr->hwndSelf, &rc); + TRACE("hwnd %p new pos (%ld,%ld)-(%ld,%ld)\n", + infoPtr->hwndSelf, rc.left, rc.top, rc.right, rc.bottom); + return ret; +} + + +static LRESULT WINAPI +REBAR_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + REBAR_INFO *infoPtr = REBAR_GetInfoPtr (hwnd); + + TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", + hwnd, uMsg, wParam, lParam); + if (!infoPtr && (uMsg != WM_NCCREATE)) + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + switch (uMsg) + { +/* case RB_BEGINDRAG: */ + + case RB_DELETEBAND: + return REBAR_DeleteBand (infoPtr, wParam, lParam); + +/* case RB_DRAGMOVE: */ +/* case RB_ENDDRAG: */ + + case RB_GETBANDBORDERS: + return REBAR_GetBandBorders (infoPtr, wParam, lParam); + + case RB_GETBANDCOUNT: + return REBAR_GetBandCount (infoPtr); + + case RB_GETBANDINFO_OLD: + case RB_GETBANDINFOA: + return REBAR_GetBandInfoA (infoPtr, wParam, lParam); + + case RB_GETBANDINFOW: + return REBAR_GetBandInfoW (infoPtr, wParam, lParam); + + case RB_GETBARHEIGHT: + return REBAR_GetBarHeight (infoPtr, wParam, lParam); + + case RB_GETBARINFO: + return REBAR_GetBarInfo (infoPtr, wParam, lParam); + + case RB_GETBKCOLOR: + return REBAR_GetBkColor (infoPtr); + +/* case RB_GETCOLORSCHEME: */ +/* case RB_GETDROPTARGET: */ + + case RB_GETPALETTE: + return REBAR_GetPalette (infoPtr, wParam, lParam); + + case RB_GETRECT: + return REBAR_GetRect (infoPtr, wParam, lParam); + + case RB_GETROWCOUNT: + return REBAR_GetRowCount (infoPtr); + + case RB_GETROWHEIGHT: + return REBAR_GetRowHeight (infoPtr, wParam, lParam); + + case RB_GETTEXTCOLOR: + return REBAR_GetTextColor (infoPtr); + + case RB_GETTOOLTIPS: + return REBAR_GetToolTips (infoPtr); + + case RB_GETUNICODEFORMAT: + return REBAR_GetUnicodeFormat (infoPtr); + + case CCM_GETVERSION: + return REBAR_GetVersion (infoPtr); + + case RB_HITTEST: + return REBAR_HitTest (infoPtr, wParam, lParam); + + case RB_IDTOINDEX: + return REBAR_IdToIndex (infoPtr, wParam, lParam); + + case RB_INSERTBANDA: + return REBAR_InsertBandA (infoPtr, wParam, lParam); + + case RB_INSERTBANDW: + return REBAR_InsertBandW (infoPtr, wParam, lParam); + + case RB_MAXIMIZEBAND: + return REBAR_MaximizeBand (infoPtr, wParam, lParam); + + case RB_MINIMIZEBAND: + return REBAR_MinimizeBand (infoPtr, wParam, lParam); + + case RB_MOVEBAND: + return REBAR_MoveBand (infoPtr, wParam, lParam); + + case RB_PUSHCHEVRON: + return REBAR_PushChevron (infoPtr, wParam, lParam); + + case RB_SETBANDINFOA: + return REBAR_SetBandInfoA (infoPtr, wParam, lParam); + + case RB_SETBANDINFOW: + return REBAR_SetBandInfoW (infoPtr, wParam, lParam); + + case RB_SETBARINFO: + return REBAR_SetBarInfo (infoPtr, wParam, lParam); + + case RB_SETBKCOLOR: + return REBAR_SetBkColor (infoPtr, wParam, lParam); + +/* case RB_SETCOLORSCHEME: */ +/* case RB_SETPALETTE: */ +/* return REBAR_GetPalette (infoPtr, wParam, lParam); */ + + case RB_SETPARENT: + return REBAR_SetParent (infoPtr, wParam, lParam); + + case RB_SETTEXTCOLOR: + return REBAR_SetTextColor (infoPtr, wParam, lParam); + +/* case RB_SETTOOLTIPS: */ + + case RB_SETUNICODEFORMAT: + return REBAR_SetUnicodeFormat (infoPtr, wParam); + + case CCM_SETVERSION: + return REBAR_SetVersion (infoPtr, (INT)wParam); + + case RB_SHOWBAND: + return REBAR_ShowBand (infoPtr, wParam, lParam); + + case RB_SIZETORECT: + return REBAR_SizeToRect (infoPtr, wParam, lParam); + + +/* Messages passed to parent */ + case WM_COMMAND: + case WM_DRAWITEM: + case WM_NOTIFY: + if (infoPtr->NtfUnicode) + return SendMessageW (REBAR_GetNotifyParent (infoPtr), + uMsg, wParam, lParam); + else + return SendMessageA (REBAR_GetNotifyParent (infoPtr), + uMsg, wParam, lParam); + + +/* case WM_CHARTOITEM: supported according to ControlSpy */ + + case WM_CREATE: + return REBAR_Create (infoPtr, wParam, lParam); + + case WM_DESTROY: + return REBAR_Destroy (infoPtr, wParam, lParam); + + case WM_ERASEBKGND: + return REBAR_EraseBkGnd (infoPtr, wParam, lParam); + + case WM_GETFONT: + return REBAR_GetFont (infoPtr, wParam, lParam); + +/* case WM_LBUTTONDBLCLK: supported according to ControlSpy */ + + case WM_LBUTTONDOWN: + return REBAR_LButtonDown (infoPtr, wParam, lParam); + + case WM_LBUTTONUP: + return REBAR_LButtonUp (infoPtr, wParam, lParam); + +/* case WM_MEASUREITEM: supported according to ControlSpy */ + + case WM_MOUSEMOVE: + return REBAR_MouseMove (infoPtr, wParam, lParam); + + case WM_MOUSELEAVE: + return REBAR_MouseLeave (infoPtr, wParam, lParam); + + case WM_NCCALCSIZE: + return REBAR_NCCalcSize (infoPtr, wParam, lParam); + + case WM_NCCREATE: + return REBAR_NCCreate (hwnd, wParam, lParam); + + case WM_NCHITTEST: + return REBAR_NCHitTest (infoPtr, wParam, lParam); + + case WM_NCPAINT: + return REBAR_NCPaint (infoPtr, wParam, lParam); + + case WM_NOTIFYFORMAT: + return REBAR_NotifyFormat (infoPtr, wParam, lParam); + + case WM_PAINT: + return REBAR_Paint (infoPtr, wParam, lParam); + +/* case WM_PALETTECHANGED: supported according to ControlSpy */ +/* case WM_PRINTCLIENT: supported according to ControlSpy */ +/* case WM_QUERYNEWPALETTE:supported according to ControlSpy */ +/* case WM_RBUTTONDOWN: supported according to ControlSpy */ +/* case WM_RBUTTONUP: supported according to ControlSpy */ + + case WM_SETCURSOR: + return REBAR_SetCursor (infoPtr, wParam, lParam); + + case WM_SETFONT: + return REBAR_SetFont (infoPtr, wParam, lParam); + + case WM_SETREDRAW: + return REBAR_SetRedraw (infoPtr, wParam, lParam); + + case WM_SIZE: + return REBAR_Size (infoPtr, wParam, lParam); + + case WM_STYLECHANGED: + return REBAR_StyleChanged (infoPtr, wParam, lParam); + +/* case WM_SYSCOLORCHANGE: supported according to ControlSpy */ +/* "Applications that have brushes using the existing system colors + should delete those brushes and recreate them using the new + system colors." per MSDN */ + +/* case WM_VKEYTOITEM: supported according to ControlSpy */ +/* case WM_WININICHANGE: */ + + case WM_WINDOWPOSCHANGED: + return REBAR_WindowPosChanged (infoPtr, wParam, lParam); + + default: + if ((uMsg >= WM_USER) && (uMsg < WM_APP)) + ERR("unknown msg %04x wp=%08x lp=%08lx\n", + uMsg, wParam, lParam); + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + } +} + + +VOID +REBAR_Register (void) +{ + WNDCLASSW wndClass; + + ZeroMemory (&wndClass, sizeof(WNDCLASSW)); + wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS; + wndClass.lpfnWndProc = REBAR_WindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(REBAR_INFO *); + wndClass.hCursor = 0; + wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); +#if GLATESTING + wndClass.hbrBackground = CreateSolidBrush(RGB(0,128,0)); +#endif + wndClass.lpszClassName = REBARCLASSNAMEW; + + RegisterClassW (&wndClass); + + mindragx = GetSystemMetrics (SM_CXDRAG); + mindragy = GetSystemMetrics (SM_CYDRAG); + +} + + +VOID +REBAR_Unregister (void) +{ + UnregisterClassW (REBARCLASSNAMEW, NULL); +} diff --git a/reactos/lib/comctl32/smoothscroll.c b/reactos/lib/comctl32/smoothscroll.c index 5c0030fc355..f70c664f450 100644 --- a/reactos/lib/comctl32/smoothscroll.c +++ b/reactos/lib/comctl32/smoothscroll.c @@ -1,131 +1,131 @@ -/* - * Undocumented SmoothScrollWindow function from COMCTL32.DLL - * - * Copyright 2000 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * TODO - * - actually add smooth scrolling - */ - -#include - -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "winerror.h" -#include "winuser.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(commctrl); - -static DWORD smoothscroll = 2; - -typedef BOOL (CALLBACK *SCROLLWINDOWEXPROC)(HWND,INT,INT,LPRECT,LPRECT,HRGN,LPRECT,DWORD); -typedef struct tagSMOOTHSCROLLSTRUCT { - DWORD dwSize; - DWORD x2; - HWND hwnd; - DWORD dx; - - DWORD dy; - LPRECT lpscrollrect; - LPRECT lpcliprect; - HRGN hrgnupdate; - - LPRECT lpupdaterect; - DWORD flags; - DWORD stepinterval; - DWORD dx_step; - - DWORD dy_step; - SCROLLWINDOWEXPROC scrollfun; /* same parameters as ScrollWindowEx */ -} SMOOTHSCROLLSTRUCT; - -/************************************************************************** - * SmoothScrollWindow [COMCTL32.382] - * - * Lots of magic for smooth scrolling windows. - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - * BUGS - * Currently only scrolls ONCE. The comctl32 implementation uses GetTickCount - * and what else to do smooth scrolling. - */ -BOOL WINAPI SmoothScrollWindow( SMOOTHSCROLLSTRUCT *smooth ) { - LPRECT lpupdaterect = smooth->lpupdaterect; - HRGN hrgnupdate = smooth->hrgnupdate; - RECT tmprect; - DWORD flags = smooth->flags; - - if (smooth->dwSize!=sizeof(SMOOTHSCROLLSTRUCT)) - return FALSE; - - if (!lpupdaterect) - lpupdaterect = &tmprect; - SetRectEmpty(lpupdaterect); - - if (!(flags & 0x40000)) { /* no override, use system wide defaults */ - if (smoothscroll == 2) { - HKEY hkey; - - smoothscroll = 0; - if (!RegOpenKeyA(HKEY_CURRENT_USER,"Control Panel\\Desktop",&hkey)) { - DWORD len = 4; - - RegQueryValueExA(hkey,"SmoothScroll",0,0,(LPBYTE)&smoothscroll,&len); - RegCloseKey(hkey); - } - } - if (!smoothscroll) - flags |= 0x20000; - } - - if (flags & 0x20000) { /* are we doing jump scrolling? */ - if ((smooth->x2 & 1) && smooth->scrollfun) - return smooth->scrollfun( - smooth->hwnd,smooth->dx,smooth->dy,smooth->lpscrollrect, - smooth->lpcliprect,hrgnupdate,lpupdaterect, - flags & 0xffff - ); - else - return ScrollWindowEx( - smooth->hwnd,smooth->dx,smooth->dy,smooth->lpscrollrect, - smooth->lpcliprect,hrgnupdate,lpupdaterect, - flags & 0xffff - ); - } - - FIXME("(hwnd=%p,flags=%lx,x2=%lx): should smooth scroll here.\n", - smooth->hwnd,flags,smooth->x2 - ); - /* FIXME: do timer based smooth scrolling */ - if ((smooth->x2 & 1) && smooth->scrollfun) - return smooth->scrollfun( - smooth->hwnd,smooth->dx,smooth->dy,smooth->lpscrollrect, - smooth->lpcliprect,hrgnupdate,lpupdaterect, - flags & 0xffff - ); - else - return ScrollWindowEx( - smooth->hwnd,smooth->dx,smooth->dy,smooth->lpscrollrect, - smooth->lpcliprect,hrgnupdate,lpupdaterect, - flags & 0xffff - ); -} +/* + * Undocumented SmoothScrollWindow function from COMCTL32.DLL + * + * Copyright 2000 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * TODO + * - actually add smooth scrolling + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winerror.h" +#include "winuser.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(commctrl); + +static DWORD smoothscroll = 2; + +typedef BOOL (CALLBACK *SCROLLWINDOWEXPROC)(HWND,INT,INT,LPRECT,LPRECT,HRGN,LPRECT,DWORD); +typedef struct tagSMOOTHSCROLLSTRUCT { + DWORD dwSize; + DWORD x2; + HWND hwnd; + DWORD dx; + + DWORD dy; + LPRECT lpscrollrect; + LPRECT lpcliprect; + HRGN hrgnupdate; + + LPRECT lpupdaterect; + DWORD flags; + DWORD stepinterval; + DWORD dx_step; + + DWORD dy_step; + SCROLLWINDOWEXPROC scrollfun; /* same parameters as ScrollWindowEx */ +} SMOOTHSCROLLSTRUCT; + +/************************************************************************** + * SmoothScrollWindow [COMCTL32.382] + * + * Lots of magic for smooth scrolling windows. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + * BUGS + * Currently only scrolls ONCE. The comctl32 implementation uses GetTickCount + * and what else to do smooth scrolling. + */ +BOOL WINAPI SmoothScrollWindow( SMOOTHSCROLLSTRUCT *smooth ) { + LPRECT lpupdaterect = smooth->lpupdaterect; + HRGN hrgnupdate = smooth->hrgnupdate; + RECT tmprect; + DWORD flags = smooth->flags; + + if (smooth->dwSize!=sizeof(SMOOTHSCROLLSTRUCT)) + return FALSE; + + if (!lpupdaterect) + lpupdaterect = &tmprect; + SetRectEmpty(lpupdaterect); + + if (!(flags & 0x40000)) { /* no override, use system wide defaults */ + if (smoothscroll == 2) { + HKEY hkey; + + smoothscroll = 0; + if (!RegOpenKeyA(HKEY_CURRENT_USER,"Control Panel\\Desktop",&hkey)) { + DWORD len = 4; + + RegQueryValueExA(hkey,"SmoothScroll",0,0,(LPBYTE)&smoothscroll,&len); + RegCloseKey(hkey); + } + } + if (!smoothscroll) + flags |= 0x20000; + } + + if (flags & 0x20000) { /* are we doing jump scrolling? */ + if ((smooth->x2 & 1) && smooth->scrollfun) + return smooth->scrollfun( + smooth->hwnd,smooth->dx,smooth->dy,smooth->lpscrollrect, + smooth->lpcliprect,hrgnupdate,lpupdaterect, + flags & 0xffff + ); + else + return ScrollWindowEx( + smooth->hwnd,smooth->dx,smooth->dy,smooth->lpscrollrect, + smooth->lpcliprect,hrgnupdate,lpupdaterect, + flags & 0xffff + ); + } + + FIXME("(hwnd=%p,flags=%lx,x2=%lx): should smooth scroll here.\n", + smooth->hwnd,flags,smooth->x2 + ); + /* FIXME: do timer based smooth scrolling */ + if ((smooth->x2 & 1) && smooth->scrollfun) + return smooth->scrollfun( + smooth->hwnd,smooth->dx,smooth->dy,smooth->lpscrollrect, + smooth->lpcliprect,hrgnupdate,lpupdaterect, + flags & 0xffff + ); + else + return ScrollWindowEx( + smooth->hwnd,smooth->dx,smooth->dy,smooth->lpscrollrect, + smooth->lpcliprect,hrgnupdate,lpupdaterect, + flags & 0xffff + ); +} diff --git a/reactos/lib/comctl32/status.c b/reactos/lib/comctl32/status.c index bd4898cd303..68672aafe53 100644 --- a/reactos/lib/comctl32/status.c +++ b/reactos/lib/comctl32/status.c @@ -1,1310 +1,1310 @@ -/* - * Interface code to StatusWindow widget/control - * - * Copyright 1996 Bruce Milner - * Copyright 1998, 1999 Eric Kohl - * Copyright 2002 Dimitrie O. Paun - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTE - * - * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on Sep. 24, 2002, by Dimitrie O. Paun. - * - * Unless otherwise noted, we believe this code to be complete, as per - * the specification mentioned above. - * If you discover missing features, or bugs, please note them below. - * - * TODO: - * -- CCS_BOTTOM (default) - * -- CCS_LEFT - * -- CCS_NODEVIDER - * -- CCS_NOMOVEX - * -- CCS_NOMOVEY - * -- CCS_NOPARENTALIGN - * -- CCS_RIGHT - * -- CCS_TOP - * -- CCS_VERT (defaults to RIGHT) - */ - -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "wine/unicode.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "comctl32.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(statusbar); - -typedef struct -{ - INT x; - INT style; - RECT bound; - LPWSTR text; - HICON hIcon; -} STATUSWINDOWPART; - -typedef struct -{ - HWND Self; - HWND Notify; - WORD numParts; - UINT height; - BOOL simple; - HWND hwndToolTip; - HFONT hFont; - HFONT hDefaultFont; - COLORREF clrBk; /* background color */ - BOOL bUnicode; /* unicode flag */ - BOOL NtfUnicode; /* notify format */ - STATUSWINDOWPART part0; /* simple window */ - STATUSWINDOWPART* parts; - INT horizontalBorder; - INT verticalBorder; - INT horizontalGap; -} STATUS_INFO; - -/* - * Run tests using Waite Group Windows95 API Bible Vol. 1&2 - * The second cdrom contains executables drawstat.exe, gettext.exe, - * simple.exe, getparts.exe, setparts.exe, statwnd.exe - */ - -#define HORZ_BORDER 0 -#define VERT_BORDER 2 -#define HORZ_GAP 2 - -/* prototype */ -static void -STATUSBAR_SetPartBounds (STATUS_INFO *infoPtr); - -static inline LPCSTR debugstr_t(LPCWSTR text, BOOL isW) -{ - return isW ? debugstr_w(text) : debugstr_a((LPCSTR)text); -} - -static void -STATUSBAR_DrawSizeGrip (HDC hdc, LPRECT lpRect) -{ - HPEN hPenFace, hPenShadow, hPenHighlight, hOldPen; - POINT pt; - INT i; - - TRACE("draw size grip %ld,%ld - %ld,%ld\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); - - pt.x = lpRect->right - 1; - pt.y = lpRect->bottom - 1; - - hPenFace = CreatePen( PS_SOLID, 1, GetSysColor( COLOR_3DFACE )); - hOldPen = SelectObject( hdc, hPenFace ); - MoveToEx (hdc, pt.x - 12, pt.y, NULL); - LineTo (hdc, pt.x, pt.y); - LineTo (hdc, pt.x, pt.y - 13); - - pt.x--; - pt.y--; - - hPenShadow = CreatePen( PS_SOLID, 1, GetSysColor( COLOR_3DSHADOW )); - SelectObject( hdc, hPenShadow ); - for (i = 1; i < 11; i += 4) { - MoveToEx (hdc, pt.x - i, pt.y, NULL); - LineTo (hdc, pt.x + 1, pt.y - i - 1); - - MoveToEx (hdc, pt.x - i - 1, pt.y, NULL); - LineTo (hdc, pt.x + 1, pt.y - i - 2); - } - - hPenHighlight = CreatePen( PS_SOLID, 1, GetSysColor( COLOR_3DHIGHLIGHT )); - SelectObject( hdc, hPenHighlight ); - for (i = 3; i < 13; i += 4) { - MoveToEx (hdc, pt.x - i, pt.y, NULL); - LineTo (hdc, pt.x + 1, pt.y - i - 1); - } - - SelectObject (hdc, hOldPen); - DeleteObject( hPenFace ); - DeleteObject( hPenShadow ); - DeleteObject( hPenHighlight ); -} - - -static void -STATUSBAR_DrawPart (STATUS_INFO *infoPtr, HDC hdc, STATUSWINDOWPART *part, int itemID) -{ - RECT r = part->bound; - UINT border = BDR_SUNKENOUTER; - - TRACE("part bound %ld,%ld - %ld,%ld\n", r.left, r.top, r.right, r.bottom); - if (part->style & SBT_POPOUT) - border = BDR_RAISEDOUTER; - else if (part->style & SBT_NOBORDERS) - border = 0; - - DrawEdge(hdc, &r, border, BF_RECT|BF_ADJUST); - - if (part->style & SBT_OWNERDRAW) { - DRAWITEMSTRUCT dis; - - dis.CtlID = GetWindowLongPtrW (infoPtr->Self, GWLP_ID); - dis.itemID = itemID; - dis.hwndItem = infoPtr->Self; - dis.hDC = hdc; - dis.rcItem = r; - dis.itemData = (INT)part->text; - SendMessageW (infoPtr->Notify, WM_DRAWITEM, (WPARAM)dis.CtlID, (LPARAM)&dis); - } else { - if (part->hIcon) { - INT cy = r.bottom - r.top; - - r.left += 2; - DrawIconEx (hdc, r.left, r.top, part->hIcon, cy, cy, 0, 0, DI_NORMAL); - r.left += cy; - } - DrawStatusTextW (hdc, &r, part->text, SBT_NOBORDERS); - } -} - - -static void -STATUSBAR_RefreshPart (STATUS_INFO *infoPtr, HDC hdc, STATUSWINDOWPART *part, int itemID) -{ - HBRUSH hbrBk; - HFONT hOldFont; - - TRACE("item %d\n", itemID); - if (!IsWindowVisible (infoPtr->Self)) - return; - - if (part->bound.right < part->bound.left) return; - - if (infoPtr->clrBk != CLR_DEFAULT) - hbrBk = CreateSolidBrush (infoPtr->clrBk); - else - hbrBk = GetSysColorBrush (COLOR_3DFACE); - FillRect(hdc, &part->bound, hbrBk); - - hOldFont = SelectObject (hdc, infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont); - - STATUSBAR_DrawPart (infoPtr, hdc, part, itemID); - - SelectObject (hdc, hOldFont); - - if (infoPtr->clrBk != CLR_DEFAULT) - DeleteObject (hbrBk); - - if (GetWindowLongW (infoPtr->Self, GWL_STYLE) & SBARS_SIZEGRIP) { - RECT rect; - - GetClientRect (infoPtr->Self, &rect); - STATUSBAR_DrawSizeGrip (hdc, &rect); - } -} - - -static LRESULT -STATUSBAR_Refresh (STATUS_INFO *infoPtr, HDC hdc) -{ - int i; - RECT rect; - HBRUSH hbrBk; - HFONT hOldFont; - - TRACE("\n"); - if (!IsWindowVisible(infoPtr->Self)) - return 0; - - STATUSBAR_SetPartBounds(infoPtr); - - GetClientRect (infoPtr->Self, &rect); - - if (infoPtr->clrBk != CLR_DEFAULT) - hbrBk = CreateSolidBrush (infoPtr->clrBk); - else - hbrBk = GetSysColorBrush (COLOR_3DFACE); - FillRect(hdc, &rect, hbrBk); - - hOldFont = SelectObject (hdc, infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont); - - if (infoPtr->simple) { - STATUSBAR_RefreshPart (infoPtr, hdc, &infoPtr->part0, 0); - } else { - for (i = 0; i < infoPtr->numParts; i++) { - STATUSBAR_RefreshPart (infoPtr, hdc, &infoPtr->parts[i], i); - } - } - - SelectObject (hdc, hOldFont); - - if (infoPtr->clrBk != CLR_DEFAULT) - DeleteObject (hbrBk); - - if (GetWindowLongW (infoPtr->Self, GWL_STYLE) & SBARS_SIZEGRIP) - STATUSBAR_DrawSizeGrip (hdc, &rect); - - return 0; -} - - -static void -STATUSBAR_SetPartBounds (STATUS_INFO *infoPtr) -{ - STATUSWINDOWPART *part; - RECT rect, *r; - int i; - - /* get our window size */ - GetClientRect (infoPtr->Self, &rect); - TRACE("client wnd size is %ld,%ld - %ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom); - - rect.left += infoPtr->horizontalBorder; - rect.top += infoPtr->verticalBorder; - - /* set bounds for simple rectangle */ - infoPtr->part0.bound = rect; - - /* set bounds for non-simple rectangles */ - for (i = 0; i < infoPtr->numParts; i++) { - part = &infoPtr->parts[i]; - r = &infoPtr->parts[i].bound; - r->top = rect.top; - r->bottom = rect.bottom; - if (i == 0) - r->left = 0; - else - r->left = infoPtr->parts[i-1].bound.right + infoPtr->horizontalGap; - if (part->x == -1) - r->right = rect.right; - else - r->right = part->x; - - if (infoPtr->hwndToolTip) { - TTTOOLINFOW ti; - - ti.cbSize = sizeof(TTTOOLINFOW); - ti.hwnd = infoPtr->Self; - ti.uId = i; - ti.rect = *r; - SendMessageW (infoPtr->hwndToolTip, TTM_NEWTOOLRECTW, - 0, (LPARAM)&ti); - } - } -} - - -static LRESULT -STATUSBAR_Relay2Tip (STATUS_INFO *infoPtr, UINT uMsg, - WPARAM wParam, LPARAM lParam) -{ - MSG msg; - - msg.hwnd = infoPtr->Self; - msg.message = uMsg; - msg.wParam = wParam; - msg.lParam = lParam; - msg.time = GetMessageTime (); - msg.pt.x = LOWORD(GetMessagePos ()); - msg.pt.y = HIWORD(GetMessagePos ()); - - return SendMessageW (infoPtr->hwndToolTip, TTM_RELAYEVENT, 0, (LPARAM)&msg); -} - - -static BOOL -STATUSBAR_GetBorders (STATUS_INFO *infoPtr, INT out[]) -{ - TRACE("\n"); - out[0] = infoPtr->horizontalBorder; - out[1] = infoPtr->verticalBorder; - out[2] = infoPtr->horizontalGap; - - return TRUE; -} - - -static BOOL -STATUSBAR_SetBorders (STATUS_INFO *infoPtr, INT in[]) -{ - TRACE("\n"); - infoPtr->horizontalBorder = in[0]; - infoPtr->verticalBorder = in[1]; - infoPtr->horizontalGap = in[2]; - InvalidateRect(infoPtr->Self, NULL, FALSE); - - return TRUE; -} - - -static HICON -STATUSBAR_GetIcon (STATUS_INFO *infoPtr, INT nPart) -{ - TRACE("%d\n", nPart); - /* MSDN says: "simple parts are indexed with -1" */ - if ((nPart < -1) || (nPart >= infoPtr->numParts)) - return 0; - - if (nPart == -1) - return (infoPtr->part0.hIcon); - else - return (infoPtr->parts[nPart].hIcon); -} - - -static INT -STATUSBAR_GetParts (STATUS_INFO *infoPtr, INT num_parts, INT parts[]) -{ - INT i; - - TRACE("(%d)\n", num_parts); - if (parts) { - for (i = 0; i < num_parts; i++) { - parts[i] = infoPtr->parts[i].x; - } - } - return infoPtr->numParts; -} - - -static BOOL -STATUSBAR_GetRect (STATUS_INFO *infoPtr, INT nPart, LPRECT rect) -{ - TRACE("part %d\n", nPart); - if (infoPtr->simple) - *rect = infoPtr->part0.bound; - else - *rect = infoPtr->parts[nPart].bound; - return TRUE; -} - - -static LRESULT -STATUSBAR_GetTextA (STATUS_INFO *infoPtr, INT nPart, LPSTR buf) -{ - STATUSWINDOWPART *part; - LRESULT result; - - TRACE("part %d\n", nPart); - - /* MSDN says: "simple parts use index of 0", so this check is ok. */ - if (nPart < 0 || nPart >= infoPtr->numParts) return 0; - - if (infoPtr->simple) - part = &infoPtr->part0; - else - part = &infoPtr->parts[nPart]; - - if (part->style & SBT_OWNERDRAW) - result = (LRESULT)part->text; - else { - DWORD len = part->text ? WideCharToMultiByte( CP_ACP, 0, part->text, -1, - NULL, 0, NULL, NULL ) - 1 : 0; - result = MAKELONG( len, part->style ); - if (part->text && buf) - WideCharToMultiByte( CP_ACP, 0, part->text, -1, buf, len+1, NULL, NULL ); - } - return result; -} - - -static LRESULT -STATUSBAR_GetTextW (STATUS_INFO *infoPtr, INT nPart, LPWSTR buf) -{ - STATUSWINDOWPART *part; - LRESULT result; - - TRACE("part %d\n", nPart); - if (nPart < 0 || nPart >= infoPtr->numParts) return 0; - - if (infoPtr->simple) - part = &infoPtr->part0; - else - part = &infoPtr->parts[nPart]; - - if (part->style & SBT_OWNERDRAW) - result = (LRESULT)part->text; - else { - result = part->text ? strlenW (part->text) : 0; - result |= (part->style << 16); - if (part->text && buf) - strcpyW (buf, part->text); - } - return result; -} - - -static LRESULT -STATUSBAR_GetTextLength (STATUS_INFO *infoPtr, INT nPart) -{ - STATUSWINDOWPART *part; - DWORD result; - - TRACE("part %d\n", nPart); - - /* MSDN says: "simple parts use index of 0", so this check is ok. */ - if (nPart < 0 || nPart >= infoPtr->numParts) return 0; - - if (infoPtr->simple) - part = &infoPtr->part0; - else - part = &infoPtr->parts[nPart]; - - if ((~part->style & SBT_OWNERDRAW) && part->text) - result = strlenW(part->text); - else - result = 0; - - result |= (part->style << 16); - return result; -} - -static LRESULT -STATUSBAR_GetTipTextA (STATUS_INFO *infoPtr, INT id, LPSTR tip, INT size) -{ - TRACE("\n"); - if (tip) { - CHAR buf[INFOTIPSIZE]; - buf[0]='\0'; - - if (infoPtr->hwndToolTip) { - TTTOOLINFOA ti; - ti.cbSize = sizeof(TTTOOLINFOA); - ti.hwnd = infoPtr->Self; - ti.uId = id; - ti.lpszText = buf; - SendMessageA (infoPtr->hwndToolTip, TTM_GETTEXTA, 0, (LPARAM)&ti); - } - lstrcpynA (tip, buf, size); - } - return 0; -} - - -static LRESULT -STATUSBAR_GetTipTextW (STATUS_INFO *infoPtr, INT id, LPWSTR tip, INT size) -{ - TRACE("\n"); - if (tip) { - WCHAR buf[INFOTIPSIZE]; - buf[0]=0; - - if (infoPtr->hwndToolTip) { - TTTOOLINFOW ti; - ti.cbSize = sizeof(TTTOOLINFOW); - ti.hwnd = infoPtr->Self; - ti.uId = id; - ti.lpszText = buf; - SendMessageW(infoPtr->hwndToolTip, TTM_GETTEXTW, 0, (LPARAM)&ti); - } - lstrcpynW(tip, buf, size); - } - - return 0; -} - - -static COLORREF -STATUSBAR_SetBkColor (STATUS_INFO *infoPtr, COLORREF color) -{ - COLORREF oldBkColor; - - oldBkColor = infoPtr->clrBk; - infoPtr->clrBk = color; - InvalidateRect(infoPtr->Self, NULL, FALSE); - - TRACE("CREF: %08lx -> %08lx\n", oldBkColor, infoPtr->clrBk); - return oldBkColor; -} - - -static BOOL -STATUSBAR_SetIcon (STATUS_INFO *infoPtr, INT nPart, HICON hIcon) -{ - if ((nPart < -1) || (nPart >= infoPtr->numParts)) - return FALSE; - - TRACE("setting part %d\n", nPart); - - /* FIXME: MSDN says "if nPart is -1, the status bar is assumed simple" */ - if (nPart == -1) { - if (infoPtr->part0.hIcon == hIcon) /* same as - no redraw */ - return TRUE; - infoPtr->part0.hIcon = hIcon; - if (infoPtr->simple) - InvalidateRect(infoPtr->Self, &infoPtr->part0.bound, FALSE); - } else { - if (infoPtr->parts[nPart].hIcon == hIcon) /* same as - no redraw */ - return TRUE; - - infoPtr->parts[nPart].hIcon = hIcon; - if (!(infoPtr->simple)) - InvalidateRect(infoPtr->Self, &infoPtr->parts[nPart].bound, FALSE); - } - return TRUE; -} - - -static BOOL -STATUSBAR_SetMinHeight (STATUS_INFO *infoPtr, INT height) -{ - - TRACE("(height=%d)\n", height); - if (IsWindowVisible (infoPtr->Self)) { - INT width, x, y; - RECT parent_rect; - - GetClientRect (infoPtr->Notify, &parent_rect); - infoPtr->height = height + infoPtr->verticalBorder; - width = parent_rect.right - parent_rect.left; - x = parent_rect.left; - y = parent_rect.bottom - infoPtr->height; - MoveWindow (infoPtr->Self, parent_rect.left, - parent_rect.bottom - infoPtr->height, - width, infoPtr->height, TRUE); - STATUSBAR_SetPartBounds (infoPtr); - } - - return TRUE; -} - - -static BOOL -STATUSBAR_SetParts (STATUS_INFO *infoPtr, INT count, LPINT parts) -{ - STATUSWINDOWPART *tmp; - int i, oldNumParts; - - TRACE("(%d,%p)\n", count, parts); - - oldNumParts = infoPtr->numParts; - infoPtr->numParts = count; - if (oldNumParts > infoPtr->numParts) { - for (i = infoPtr->numParts ; i < oldNumParts; i++) { - if (infoPtr->parts[i].text && !(infoPtr->parts[i].style & SBT_OWNERDRAW)) - Free (infoPtr->parts[i].text); - } - } else if (oldNumParts < infoPtr->numParts) { - tmp = Alloc (sizeof(STATUSWINDOWPART) * infoPtr->numParts); - if (!tmp) return FALSE; - for (i = 0; i < oldNumParts; i++) { - tmp[i] = infoPtr->parts[i]; - } - if (infoPtr->parts) - Free (infoPtr->parts); - infoPtr->parts = tmp; - } - if (oldNumParts == infoPtr->numParts) { - for (i=0; i < oldNumParts; i++) - if (infoPtr->parts[i].x != parts[i]) - break; - if (i==oldNumParts) /* Unchanged? no need to redraw! */ - return TRUE; - } - - for (i = 0; i < infoPtr->numParts; i++) - infoPtr->parts[i].x = parts[i]; - - if (infoPtr->hwndToolTip) { - INT nTipCount, i; - TTTOOLINFOW ti; - - ZeroMemory (&ti, sizeof(TTTOOLINFOW)); - ti.cbSize = sizeof(TTTOOLINFOW); - ti.hwnd = infoPtr->Self; - - nTipCount = SendMessageW (infoPtr->hwndToolTip, TTM_GETTOOLCOUNT, 0, 0); - if (nTipCount < infoPtr->numParts) { - /* add tools */ - for (i = nTipCount; i < infoPtr->numParts; i++) { - TRACE("add tool %d\n", i); - ti.uId = i; - SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, - 0, (LPARAM)&ti); - } - } - else if (nTipCount > infoPtr->numParts) { - /* delete tools */ - for (i = nTipCount - 1; i >= infoPtr->numParts; i--) { - TRACE("delete tool %d\n", i); - ti.uId = i; - SendMessageW (infoPtr->hwndToolTip, TTM_DELTOOLW, - 0, (LPARAM)&ti); - } - } - } - STATUSBAR_SetPartBounds (infoPtr); - InvalidateRect(infoPtr->Self, NULL, FALSE); - return TRUE; -} - - -static BOOL -STATUSBAR_SetTextT (STATUS_INFO *infoPtr, INT nPart, WORD style, - LPCWSTR text, BOOL isW) -{ - STATUSWINDOWPART *part=NULL; - BOOL changed = FALSE; - INT oldStyle; - - if (style & SBT_OWNERDRAW) { - TRACE("part %d, text %p\n",nPart,text); - } - else TRACE("part %d, text %s\n", nPart, debugstr_t(text, isW)); - - /* MSDN says: "If the parameter is set to SB_SIMPLEID (255), the status - * window is assumed to be a simple window */ - - if (nPart == 0x00ff) { - part = &infoPtr->part0; - } else { - if (infoPtr->parts && nPart >= 0 && nPart < infoPtr->numParts) { - part = &infoPtr->parts[nPart]; - } - } - if (!part) return FALSE; - - if (part->style != style) - changed = TRUE; - - oldStyle = part->style; - part->style = style; - if (style & SBT_OWNERDRAW) { - if (!(oldStyle & SBT_OWNERDRAW)) { - if (part->text) - Free (part->text); - } else if (part->text == text) - return TRUE; - part->text = (LPWSTR)text; - } else { - LPWSTR ntext; - - if (text && !isW) { - LPCSTR atxt = (LPCSTR)text; - DWORD len = MultiByteToWideChar( CP_ACP, 0, atxt, -1, NULL, 0 ); - ntext = Alloc( (len + 1)*sizeof(WCHAR) ); - if (!ntext) return FALSE; - MultiByteToWideChar( CP_ACP, 0, atxt, -1, ntext, len ); - } else if (text) { - ntext = Alloc( (strlenW(text) + 1)*sizeof(WCHAR) ); - if (!ntext) return FALSE; - strcpyW (ntext, text); - } else ntext = 0; - - /* check if text is unchanged -> no need to redraw */ - if (text) { - if (!changed && part->text && !lstrcmpW(ntext, part->text)) { - Free(ntext); - return TRUE; - } - } else { - if (!changed && !part->text) - return TRUE; - } - - if (part->text && !(oldStyle & SBT_OWNERDRAW)) - Free (part->text); - part->text = ntext; - } - InvalidateRect(infoPtr->Self, &part->bound, FALSE); - - return TRUE; -} - - -static LRESULT -STATUSBAR_SetTipTextA (STATUS_INFO *infoPtr, INT id, LPSTR text) -{ - TRACE("part %d: \"%s\"\n", id, text); - if (infoPtr->hwndToolTip) { - TTTOOLINFOA ti; - ti.cbSize = sizeof(TTTOOLINFOA); - ti.hwnd = infoPtr->Self; - ti.uId = id; - ti.hinst = 0; - ti.lpszText = text; - SendMessageA (infoPtr->hwndToolTip, TTM_UPDATETIPTEXTA, 0, (LPARAM)&ti); - } - - return 0; -} - - -static LRESULT -STATUSBAR_SetTipTextW (STATUS_INFO *infoPtr, INT id, LPWSTR text) -{ - TRACE("part %d: \"%s\"\n", id, debugstr_w(text)); - if (infoPtr->hwndToolTip) { - TTTOOLINFOW ti; - ti.cbSize = sizeof(TTTOOLINFOW); - ti.hwnd = infoPtr->Self; - ti.uId = id; - ti.hinst = 0; - ti.lpszText = text; - SendMessageW (infoPtr->hwndToolTip, TTM_UPDATETIPTEXTW, 0, (LPARAM)&ti); - } - - return 0; -} - - -inline static LRESULT -STATUSBAR_SetUnicodeFormat (STATUS_INFO *infoPtr, BOOL bUnicode) -{ - BOOL bOld = infoPtr->bUnicode; - - TRACE("(0x%x)\n", bUnicode); - infoPtr->bUnicode = bUnicode; - - return bOld; -} - - -static BOOL -STATUSBAR_Simple (STATUS_INFO *infoPtr, BOOL simple) -{ - NMHDR nmhdr; - - TRACE("(simple=%d)\n", simple); - if (infoPtr->simple == simple) /* no need to change */ - return TRUE; - - infoPtr->simple = simple; - - /* send notification */ - nmhdr.hwndFrom = infoPtr->Self; - nmhdr.idFrom = GetWindowLongPtrW (infoPtr->Self, GWLP_ID); - nmhdr.code = SBN_SIMPLEMODECHANGE; - SendMessageW (infoPtr->Notify, WM_NOTIFY, 0, (LPARAM)&nmhdr); - InvalidateRect(infoPtr->Self, NULL, FALSE); - return TRUE; -} - - -static LRESULT -STATUSBAR_WMDestroy (STATUS_INFO *infoPtr) -{ - int i; - - TRACE("\n"); - for (i = 0; i < infoPtr->numParts; i++) { - if (infoPtr->parts[i].text && !(infoPtr->parts[i].style & SBT_OWNERDRAW)) - Free (infoPtr->parts[i].text); - } - if (infoPtr->part0.text && !(infoPtr->part0.style & SBT_OWNERDRAW)) - Free (infoPtr->part0.text); - Free (infoPtr->parts); - - /* delete default font */ - if (infoPtr->hDefaultFont) - DeleteObject (infoPtr->hDefaultFont); - - /* delete tool tip control */ - if (infoPtr->hwndToolTip) - DestroyWindow (infoPtr->hwndToolTip); - - SetWindowLongPtrW(infoPtr->Self, 0, 0); - Free (infoPtr); - return 0; -} - - -static LRESULT -STATUSBAR_WMCreate (HWND hwnd, LPCREATESTRUCTA lpCreate) -{ - STATUS_INFO *infoPtr; - NONCLIENTMETRICSW nclm; - DWORD dwStyle; - RECT rect; - int i, width, len, textHeight = 0; - HDC hdc; - - TRACE("\n"); - infoPtr = (STATUS_INFO*)Alloc (sizeof(STATUS_INFO)); - if (!infoPtr) goto create_fail; - SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); - - infoPtr->Self = hwnd; - infoPtr->Notify = lpCreate->hwndParent; - infoPtr->numParts = 1; - infoPtr->parts = 0; - infoPtr->simple = FALSE; - infoPtr->clrBk = CLR_DEFAULT; - infoPtr->hFont = 0; - infoPtr->horizontalBorder = HORZ_BORDER; - infoPtr->verticalBorder = VERT_BORDER; - infoPtr->horizontalGap = HORZ_GAP; - - i = SendMessageW(infoPtr->Notify, WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY); - infoPtr->NtfUnicode = (i == NFR_UNICODE); - - GetClientRect (hwnd, &rect); - InvalidateRect (hwnd, &rect, 0); - UpdateWindow(hwnd); - - ZeroMemory (&nclm, sizeof(nclm)); - nclm.cbSize = sizeof(nclm); - SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, nclm.cbSize, &nclm, 0); - infoPtr->hDefaultFont = CreateFontIndirectW (&nclm.lfStatusFont); - - /* initialize simple case */ - infoPtr->part0.bound = rect; - infoPtr->part0.text = 0; - infoPtr->part0.x = 0; - infoPtr->part0.style = 0; - infoPtr->part0.hIcon = 0; - - /* initialize first part */ - infoPtr->parts = Alloc (sizeof(STATUSWINDOWPART)); - if (!infoPtr->parts) goto create_fail; - infoPtr->parts[0].bound = rect; - infoPtr->parts[0].text = 0; - infoPtr->parts[0].x = -1; - infoPtr->parts[0].style = 0; - infoPtr->parts[0].hIcon = 0; - - if (IsWindowUnicode (hwnd)) { - infoPtr->bUnicode = TRUE; - if (lpCreate->lpszName && - (len = strlenW ((LPCWSTR)lpCreate->lpszName))) { - infoPtr->parts[0].text = Alloc ((len + 1)*sizeof(WCHAR)); - if (!infoPtr->parts[0].text) goto create_fail; - strcpyW (infoPtr->parts[0].text, (LPCWSTR)lpCreate->lpszName); - } - } - else { - if (lpCreate->lpszName && - (len = strlen((LPCSTR)lpCreate->lpszName))) { - DWORD lenW = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)lpCreate->lpszName, -1, NULL, 0 ); - infoPtr->parts[0].text = Alloc (lenW*sizeof(WCHAR)); - if (!infoPtr->parts[0].text) goto create_fail; - MultiByteToWideChar( CP_ACP, 0, (LPCSTR)lpCreate->lpszName, -1, - infoPtr->parts[0].text, lenW ); - } - } - - dwStyle = GetWindowLongW (hwnd, GWL_STYLE); - - /* statusbars on managed windows should not have SIZEGRIP style */ - if ((dwStyle & SBARS_SIZEGRIP) && lpCreate->hwndParent && - GetPropA( lpCreate->hwndParent, "__wine_x11_managed" )) - SetWindowLongW (hwnd, GWL_STYLE, dwStyle & ~SBARS_SIZEGRIP); - - if ((hdc = GetDC (hwnd))) { - TEXTMETRICW tm; - HFONT hOldFont; - - hOldFont = SelectObject (hdc, infoPtr->hDefaultFont); - GetTextMetricsW (hdc, &tm); - textHeight = tm.tmHeight; - SelectObject (hdc, hOldFont); - ReleaseDC (hwnd, hdc); - } - TRACE(" textHeight=%d\n", textHeight); - - if (dwStyle & SBT_TOOLTIPS) { - infoPtr->hwndToolTip = - CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, 0, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, hwnd, 0, - (HINSTANCE)GetWindowLongPtrW(hwnd, GWLP_HINSTANCE), NULL); - - if (infoPtr->hwndToolTip) { - NMTOOLTIPSCREATED nmttc; - - nmttc.hdr.hwndFrom = hwnd; - nmttc.hdr.idFrom = GetWindowLongPtrW (hwnd, GWLP_ID); - nmttc.hdr.code = NM_TOOLTIPSCREATED; - nmttc.hwndToolTips = infoPtr->hwndToolTip; - - SendMessageW (lpCreate->hwndParent, WM_NOTIFY, - (WPARAM)nmttc.hdr.idFrom, (LPARAM)&nmttc); - } - } - - if (!(dwStyle & CCS_NORESIZE)) { /* don't resize wnd if it doesn't want it ! */ - GetClientRect (infoPtr->Notify, &rect); - width = rect.right - rect.left; - infoPtr->height = textHeight + 4 + infoPtr->verticalBorder; - SetWindowPos(hwnd, 0, lpCreate->x, lpCreate->y - 1, - width, infoPtr->height, SWP_NOZORDER); - STATUSBAR_SetPartBounds (infoPtr); - } - - return 0; - -create_fail: - TRACE(" failed!\n"); - if (infoPtr) STATUSBAR_WMDestroy(infoPtr); - return -1; -} - - -/* in contrast to SB_GETTEXT*, WM_GETTEXT handles the text - * of the first part only (usual behaviour) */ -static INT -STATUSBAR_WMGetText (STATUS_INFO *infoPtr, INT size, LPWSTR buf) -{ - INT len; - - TRACE("\n"); - if (!(infoPtr->parts[0].text)) - return 0; - if (infoPtr->bUnicode) - len = strlenW (infoPtr->parts[0].text); - else - len = WideCharToMultiByte( CP_ACP, 0, infoPtr->parts[0].text, -1, NULL, 0, NULL, NULL )-1; - - if (size > len) { - if (infoPtr->bUnicode) - strcpyW (buf, infoPtr->parts[0].text); - else - WideCharToMultiByte( CP_ACP, 0, infoPtr->parts[0].text, -1, - (LPSTR)buf, len+1, NULL, NULL ); - return len; - } - - return -1; -} - - -static BOOL -STATUSBAR_WMNCHitTest (STATUS_INFO *infoPtr, INT x, INT y) -{ - if (GetWindowLongW (infoPtr->Self, GWL_STYLE) & SBARS_SIZEGRIP) { - RECT rect; - POINT pt; - - GetClientRect (infoPtr->Self, &rect); - - pt.x = x; - pt.y = y; - ScreenToClient (infoPtr->Self, &pt); - - rect.left = rect.right - 13; - rect.top += 2; - - if (PtInRect (&rect, pt)) - return HTBOTTOMRIGHT; - } - - return HTERROR; -} - - -static LRESULT -STATUSBAR_WMPaint (STATUS_INFO *infoPtr, HDC hdc) -{ - PAINTSTRUCT ps; - - TRACE("\n"); - if (hdc) return STATUSBAR_Refresh (infoPtr, hdc); - hdc = BeginPaint (infoPtr->Self, &ps); - STATUSBAR_Refresh (infoPtr, hdc); - EndPaint (infoPtr->Self, &ps); - - return 0; -} - - -static LRESULT -STATUSBAR_WMSetFont (STATUS_INFO *infoPtr, HFONT font, BOOL redraw) -{ - infoPtr->hFont = font; - TRACE("%p\n", infoPtr->hFont); - if (redraw) - InvalidateRect(infoPtr->Self, NULL, FALSE); - - return 0; -} - - -static BOOL -STATUSBAR_WMSetText (STATUS_INFO *infoPtr, LPCSTR text) -{ - STATUSWINDOWPART *part; - int len; - - TRACE("\n"); - if (infoPtr->numParts == 0) - return FALSE; - - part = &infoPtr->parts[0]; - /* duplicate string */ - if (part->text) - Free (part->text); - part->text = 0; - if (infoPtr->bUnicode) { - if (text && (len = strlenW((LPCWSTR)text))) { - part->text = Alloc ((len+1)*sizeof(WCHAR)); - if (!part->text) return FALSE; - strcpyW (part->text, (LPCWSTR)text); - } - } - else { - if (text && (len = lstrlenA(text))) { - DWORD lenW = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 ); - part->text = Alloc (lenW*sizeof(WCHAR)); - if (!part->text) return FALSE; - MultiByteToWideChar( CP_ACP, 0, text, -1, part->text, lenW ); - } - } - - InvalidateRect(infoPtr->Self, &part->bound, FALSE); - - return TRUE; -} - - -static BOOL -STATUSBAR_WMSize (STATUS_INFO *infoPtr, WORD flags) -{ - INT width, x, y; - RECT parent_rect; - - /* Need to resize width to match parent */ - TRACE("flags %04x\n", flags); - - if (flags != SIZE_RESTORED && flags != SIZE_MAXIMIZED) { - WARN("flags MUST be SIZE_RESTORED or SIZE_MAXIMIZED\n"); - return FALSE; - } - - if (GetWindowLongW(infoPtr->Self, GWL_STYLE) & CCS_NORESIZE) return FALSE; - - /* width and height don't apply */ - GetClientRect (infoPtr->Notify, &parent_rect); - width = parent_rect.right - parent_rect.left; - x = parent_rect.left; - y = parent_rect.bottom - infoPtr->height; - MoveWindow (infoPtr->Self, parent_rect.left, - parent_rect.bottom - infoPtr->height, - width, infoPtr->height, TRUE); - STATUSBAR_SetPartBounds (infoPtr); - return TRUE; -} - - -static LRESULT -STATUSBAR_NotifyFormat (STATUS_INFO *infoPtr, HWND from, INT cmd) -{ - if (cmd == NF_REQUERY) { - INT i = SendMessageW(from, WM_NOTIFYFORMAT, (WPARAM)infoPtr->Self, NF_QUERY); - infoPtr->NtfUnicode = (i == NFR_UNICODE); - } - return infoPtr->NtfUnicode ? NFR_UNICODE : NFR_ANSI; -} - - -static LRESULT -STATUSBAR_SendNotify (STATUS_INFO *infoPtr, UINT code) -{ - NMHDR nmhdr; - - TRACE("code %04x\n", code); - nmhdr.hwndFrom = infoPtr->Self; - nmhdr.idFrom = GetWindowLongPtrW (infoPtr->Self, GWLP_ID); - nmhdr.code = code; - SendMessageW (infoPtr->Notify, WM_NOTIFY, 0, (LPARAM)&nmhdr); - return 0; -} - - - -static LRESULT WINAPI -StatusWindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - STATUS_INFO *infoPtr = (STATUS_INFO *)GetWindowLongPtrW (hwnd, 0); - INT nPart = ((INT) wParam) & 0x00ff; - LRESULT res; - - TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hwnd, msg, wParam, lParam); - if (!infoPtr && msg != WM_CREATE) - return DefWindowProcW (hwnd, msg, wParam, lParam); - - switch (msg) { - case SB_GETBORDERS: - return STATUSBAR_GetBorders (infoPtr, (INT *)lParam); - - case SB_GETICON: - return (LRESULT)STATUSBAR_GetIcon (infoPtr, nPart); - - case SB_GETPARTS: - return STATUSBAR_GetParts (infoPtr, (INT)wParam, (INT *)lParam); - - case SB_GETRECT: - return STATUSBAR_GetRect (infoPtr, nPart, (LPRECT)lParam); - - case SB_GETTEXTA: - return STATUSBAR_GetTextA (infoPtr, nPart, (LPSTR)lParam); - - case SB_GETTEXTW: - return STATUSBAR_GetTextW (infoPtr, nPart, (LPWSTR)lParam); - - case SB_GETTEXTLENGTHA: - case SB_GETTEXTLENGTHW: - return STATUSBAR_GetTextLength (infoPtr, nPart); - - case SB_GETTIPTEXTA: - return STATUSBAR_GetTipTextA (infoPtr, LOWORD(wParam), (LPSTR)lParam, HIWORD(wParam)); - - case SB_GETTIPTEXTW: - return STATUSBAR_GetTipTextW (infoPtr, LOWORD(wParam), (LPWSTR)lParam, HIWORD(wParam)); - - case SB_GETUNICODEFORMAT: - return infoPtr->bUnicode; - - case SB_ISSIMPLE: - return infoPtr->simple; - - case SB_SETBORDERS: - return STATUSBAR_SetBorders (infoPtr, (INT *)lParam); - - case SB_SETBKCOLOR: - return STATUSBAR_SetBkColor (infoPtr, (COLORREF)lParam); - - case SB_SETICON: - return STATUSBAR_SetIcon (infoPtr, nPart, (HICON)lParam); - - case SB_SETMINHEIGHT: - return STATUSBAR_SetMinHeight (infoPtr, (INT)wParam); - - case SB_SETPARTS: - return STATUSBAR_SetParts (infoPtr, (INT)wParam, (LPINT)lParam); - - case SB_SETTEXTA: - return STATUSBAR_SetTextT (infoPtr, nPart, wParam & 0xff00, (LPCWSTR)lParam, FALSE); - - case SB_SETTEXTW: - return STATUSBAR_SetTextT (infoPtr, nPart, wParam & 0xff00, (LPCWSTR)lParam, TRUE); - - case SB_SETTIPTEXTA: - return STATUSBAR_SetTipTextA (infoPtr, (INT)wParam, (LPSTR)lParam); - - case SB_SETTIPTEXTW: - return STATUSBAR_SetTipTextW (infoPtr, (INT)wParam, (LPWSTR)lParam); - - case SB_SETUNICODEFORMAT: - return STATUSBAR_SetUnicodeFormat (infoPtr, (BOOL)wParam); - - case SB_SIMPLE: - return STATUSBAR_Simple (infoPtr, (BOOL)wParam); - - case WM_CREATE: - return STATUSBAR_WMCreate (hwnd, (LPCREATESTRUCTA)lParam); - - case WM_DESTROY: - return STATUSBAR_WMDestroy (infoPtr); - - case WM_GETFONT: - return (LRESULT)(infoPtr->hFont? infoPtr->hFont : infoPtr->hDefaultFont); - - case WM_GETTEXT: - return STATUSBAR_WMGetText (infoPtr, (INT)wParam, (LPWSTR)lParam); - - case WM_GETTEXTLENGTH: - return STATUSBAR_GetTextLength (infoPtr, 0); - - case WM_LBUTTONDBLCLK: - return STATUSBAR_SendNotify (infoPtr, NM_DBLCLK); - - case WM_LBUTTONUP: - return STATUSBAR_SendNotify (infoPtr, NM_CLICK); - - case WM_MOUSEMOVE: - return STATUSBAR_Relay2Tip (infoPtr, msg, wParam, lParam); - - case WM_NCHITTEST: - res = STATUSBAR_WMNCHitTest(infoPtr, (INT)LOWORD(lParam), - (INT)HIWORD(lParam)); - if (res != HTERROR) return res; - return DefWindowProcW (hwnd, msg, wParam, lParam); - - case WM_NCLBUTTONUP: - case WM_NCLBUTTONDOWN: - PostMessageW (infoPtr->Notify, msg, wParam, lParam); - return 0; - - case WM_NOTIFYFORMAT: - return STATUSBAR_NotifyFormat(infoPtr, (HWND)wParam, (INT)lParam); - - case WM_PAINT: - return STATUSBAR_WMPaint (infoPtr, (HDC)wParam); - - case WM_RBUTTONDBLCLK: - return STATUSBAR_SendNotify (infoPtr, NM_RDBLCLK); - - case WM_RBUTTONUP: - return STATUSBAR_SendNotify (infoPtr, NM_RCLICK); - - case WM_SETFONT: - return STATUSBAR_WMSetFont (infoPtr, (HFONT)wParam, LOWORD(lParam)); - - case WM_SETTEXT: - return STATUSBAR_WMSetText (infoPtr, (LPCSTR)lParam); - - case WM_SIZE: - if (STATUSBAR_WMSize (infoPtr, (WORD)wParam)) return 0; - return DefWindowProcW (hwnd, msg, wParam, lParam); - - default: - if ((msg >= WM_USER) && (msg < WM_APP)) - ERR("unknown msg %04x wp=%04x lp=%08lx\n", - msg, wParam, lParam); - return DefWindowProcW (hwnd, msg, wParam, lParam); - } -} - - -/*********************************************************************** - * STATUS_Register [Internal] - * - * Registers the status window class. - */ - -void -STATUS_Register (void) -{ - WNDCLASSW wndClass; - - ZeroMemory (&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_VREDRAW; - wndClass.lpfnWndProc = StatusWindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(STATUS_INFO *); - wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); - wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); - wndClass.lpszClassName = STATUSCLASSNAMEW; - - RegisterClassW (&wndClass); -} - - -/*********************************************************************** - * STATUS_Unregister [Internal] - * - * Unregisters the status window class. - */ - -void -STATUS_Unregister (void) -{ - UnregisterClassW (STATUSCLASSNAMEW, NULL); -} +/* + * Interface code to StatusWindow widget/control + * + * Copyright 1996 Bruce Milner + * Copyright 1998, 1999 Eric Kohl + * Copyright 2002 Dimitrie O. Paun + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTE + * + * This code was audited for completeness against the documented features + * of Comctl32.dll version 6.0 on Sep. 24, 2002, by Dimitrie O. Paun. + * + * Unless otherwise noted, we believe this code to be complete, as per + * the specification mentioned above. + * If you discover missing features, or bugs, please note them below. + * + * TODO: + * -- CCS_BOTTOM (default) + * -- CCS_LEFT + * -- CCS_NODEVIDER + * -- CCS_NOMOVEX + * -- CCS_NOMOVEY + * -- CCS_NOPARENTALIGN + * -- CCS_RIGHT + * -- CCS_TOP + * -- CCS_VERT (defaults to RIGHT) + */ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wine/unicode.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "comctl32.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(statusbar); + +typedef struct +{ + INT x; + INT style; + RECT bound; + LPWSTR text; + HICON hIcon; +} STATUSWINDOWPART; + +typedef struct +{ + HWND Self; + HWND Notify; + WORD numParts; + UINT height; + BOOL simple; + HWND hwndToolTip; + HFONT hFont; + HFONT hDefaultFont; + COLORREF clrBk; /* background color */ + BOOL bUnicode; /* unicode flag */ + BOOL NtfUnicode; /* notify format */ + STATUSWINDOWPART part0; /* simple window */ + STATUSWINDOWPART* parts; + INT horizontalBorder; + INT verticalBorder; + INT horizontalGap; +} STATUS_INFO; + +/* + * Run tests using Waite Group Windows95 API Bible Vol. 1&2 + * The second cdrom contains executables drawstat.exe, gettext.exe, + * simple.exe, getparts.exe, setparts.exe, statwnd.exe + */ + +#define HORZ_BORDER 0 +#define VERT_BORDER 2 +#define HORZ_GAP 2 + +/* prototype */ +static void +STATUSBAR_SetPartBounds (STATUS_INFO *infoPtr); + +static inline LPCSTR debugstr_t(LPCWSTR text, BOOL isW) +{ + return isW ? debugstr_w(text) : debugstr_a((LPCSTR)text); +} + +static void +STATUSBAR_DrawSizeGrip (HDC hdc, LPRECT lpRect) +{ + HPEN hPenFace, hPenShadow, hPenHighlight, hOldPen; + POINT pt; + INT i; + + TRACE("draw size grip %ld,%ld - %ld,%ld\n", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); + + pt.x = lpRect->right - 1; + pt.y = lpRect->bottom - 1; + + hPenFace = CreatePen( PS_SOLID, 1, GetSysColor( COLOR_3DFACE )); + hOldPen = SelectObject( hdc, hPenFace ); + MoveToEx (hdc, pt.x - 12, pt.y, NULL); + LineTo (hdc, pt.x, pt.y); + LineTo (hdc, pt.x, pt.y - 13); + + pt.x--; + pt.y--; + + hPenShadow = CreatePen( PS_SOLID, 1, GetSysColor( COLOR_3DSHADOW )); + SelectObject( hdc, hPenShadow ); + for (i = 1; i < 11; i += 4) { + MoveToEx (hdc, pt.x - i, pt.y, NULL); + LineTo (hdc, pt.x + 1, pt.y - i - 1); + + MoveToEx (hdc, pt.x - i - 1, pt.y, NULL); + LineTo (hdc, pt.x + 1, pt.y - i - 2); + } + + hPenHighlight = CreatePen( PS_SOLID, 1, GetSysColor( COLOR_3DHIGHLIGHT )); + SelectObject( hdc, hPenHighlight ); + for (i = 3; i < 13; i += 4) { + MoveToEx (hdc, pt.x - i, pt.y, NULL); + LineTo (hdc, pt.x + 1, pt.y - i - 1); + } + + SelectObject (hdc, hOldPen); + DeleteObject( hPenFace ); + DeleteObject( hPenShadow ); + DeleteObject( hPenHighlight ); +} + + +static void +STATUSBAR_DrawPart (STATUS_INFO *infoPtr, HDC hdc, STATUSWINDOWPART *part, int itemID) +{ + RECT r = part->bound; + UINT border = BDR_SUNKENOUTER; + + TRACE("part bound %ld,%ld - %ld,%ld\n", r.left, r.top, r.right, r.bottom); + if (part->style & SBT_POPOUT) + border = BDR_RAISEDOUTER; + else if (part->style & SBT_NOBORDERS) + border = 0; + + DrawEdge(hdc, &r, border, BF_RECT|BF_ADJUST); + + if (part->style & SBT_OWNERDRAW) { + DRAWITEMSTRUCT dis; + + dis.CtlID = GetWindowLongPtrW (infoPtr->Self, GWLP_ID); + dis.itemID = itemID; + dis.hwndItem = infoPtr->Self; + dis.hDC = hdc; + dis.rcItem = r; + dis.itemData = (INT)part->text; + SendMessageW (infoPtr->Notify, WM_DRAWITEM, (WPARAM)dis.CtlID, (LPARAM)&dis); + } else { + if (part->hIcon) { + INT cy = r.bottom - r.top; + + r.left += 2; + DrawIconEx (hdc, r.left, r.top, part->hIcon, cy, cy, 0, 0, DI_NORMAL); + r.left += cy; + } + DrawStatusTextW (hdc, &r, part->text, SBT_NOBORDERS); + } +} + + +static void +STATUSBAR_RefreshPart (STATUS_INFO *infoPtr, HDC hdc, STATUSWINDOWPART *part, int itemID) +{ + HBRUSH hbrBk; + HFONT hOldFont; + + TRACE("item %d\n", itemID); + if (!IsWindowVisible (infoPtr->Self)) + return; + + if (part->bound.right < part->bound.left) return; + + if (infoPtr->clrBk != CLR_DEFAULT) + hbrBk = CreateSolidBrush (infoPtr->clrBk); + else + hbrBk = GetSysColorBrush (COLOR_3DFACE); + FillRect(hdc, &part->bound, hbrBk); + + hOldFont = SelectObject (hdc, infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont); + + STATUSBAR_DrawPart (infoPtr, hdc, part, itemID); + + SelectObject (hdc, hOldFont); + + if (infoPtr->clrBk != CLR_DEFAULT) + DeleteObject (hbrBk); + + if (GetWindowLongW (infoPtr->Self, GWL_STYLE) & SBARS_SIZEGRIP) { + RECT rect; + + GetClientRect (infoPtr->Self, &rect); + STATUSBAR_DrawSizeGrip (hdc, &rect); + } +} + + +static LRESULT +STATUSBAR_Refresh (STATUS_INFO *infoPtr, HDC hdc) +{ + int i; + RECT rect; + HBRUSH hbrBk; + HFONT hOldFont; + + TRACE("\n"); + if (!IsWindowVisible(infoPtr->Self)) + return 0; + + STATUSBAR_SetPartBounds(infoPtr); + + GetClientRect (infoPtr->Self, &rect); + + if (infoPtr->clrBk != CLR_DEFAULT) + hbrBk = CreateSolidBrush (infoPtr->clrBk); + else + hbrBk = GetSysColorBrush (COLOR_3DFACE); + FillRect(hdc, &rect, hbrBk); + + hOldFont = SelectObject (hdc, infoPtr->hFont ? infoPtr->hFont : infoPtr->hDefaultFont); + + if (infoPtr->simple) { + STATUSBAR_RefreshPart (infoPtr, hdc, &infoPtr->part0, 0); + } else { + for (i = 0; i < infoPtr->numParts; i++) { + STATUSBAR_RefreshPart (infoPtr, hdc, &infoPtr->parts[i], i); + } + } + + SelectObject (hdc, hOldFont); + + if (infoPtr->clrBk != CLR_DEFAULT) + DeleteObject (hbrBk); + + if (GetWindowLongW (infoPtr->Self, GWL_STYLE) & SBARS_SIZEGRIP) + STATUSBAR_DrawSizeGrip (hdc, &rect); + + return 0; +} + + +static void +STATUSBAR_SetPartBounds (STATUS_INFO *infoPtr) +{ + STATUSWINDOWPART *part; + RECT rect, *r; + int i; + + /* get our window size */ + GetClientRect (infoPtr->Self, &rect); + TRACE("client wnd size is %ld,%ld - %ld,%ld\n", rect.left, rect.top, rect.right, rect.bottom); + + rect.left += infoPtr->horizontalBorder; + rect.top += infoPtr->verticalBorder; + + /* set bounds for simple rectangle */ + infoPtr->part0.bound = rect; + + /* set bounds for non-simple rectangles */ + for (i = 0; i < infoPtr->numParts; i++) { + part = &infoPtr->parts[i]; + r = &infoPtr->parts[i].bound; + r->top = rect.top; + r->bottom = rect.bottom; + if (i == 0) + r->left = 0; + else + r->left = infoPtr->parts[i-1].bound.right + infoPtr->horizontalGap; + if (part->x == -1) + r->right = rect.right; + else + r->right = part->x; + + if (infoPtr->hwndToolTip) { + TTTOOLINFOW ti; + + ti.cbSize = sizeof(TTTOOLINFOW); + ti.hwnd = infoPtr->Self; + ti.uId = i; + ti.rect = *r; + SendMessageW (infoPtr->hwndToolTip, TTM_NEWTOOLRECTW, + 0, (LPARAM)&ti); + } + } +} + + +static LRESULT +STATUSBAR_Relay2Tip (STATUS_INFO *infoPtr, UINT uMsg, + WPARAM wParam, LPARAM lParam) +{ + MSG msg; + + msg.hwnd = infoPtr->Self; + msg.message = uMsg; + msg.wParam = wParam; + msg.lParam = lParam; + msg.time = GetMessageTime (); + msg.pt.x = LOWORD(GetMessagePos ()); + msg.pt.y = HIWORD(GetMessagePos ()); + + return SendMessageW (infoPtr->hwndToolTip, TTM_RELAYEVENT, 0, (LPARAM)&msg); +} + + +static BOOL +STATUSBAR_GetBorders (STATUS_INFO *infoPtr, INT out[]) +{ + TRACE("\n"); + out[0] = infoPtr->horizontalBorder; + out[1] = infoPtr->verticalBorder; + out[2] = infoPtr->horizontalGap; + + return TRUE; +} + + +static BOOL +STATUSBAR_SetBorders (STATUS_INFO *infoPtr, INT in[]) +{ + TRACE("\n"); + infoPtr->horizontalBorder = in[0]; + infoPtr->verticalBorder = in[1]; + infoPtr->horizontalGap = in[2]; + InvalidateRect(infoPtr->Self, NULL, FALSE); + + return TRUE; +} + + +static HICON +STATUSBAR_GetIcon (STATUS_INFO *infoPtr, INT nPart) +{ + TRACE("%d\n", nPart); + /* MSDN says: "simple parts are indexed with -1" */ + if ((nPart < -1) || (nPart >= infoPtr->numParts)) + return 0; + + if (nPart == -1) + return (infoPtr->part0.hIcon); + else + return (infoPtr->parts[nPart].hIcon); +} + + +static INT +STATUSBAR_GetParts (STATUS_INFO *infoPtr, INT num_parts, INT parts[]) +{ + INT i; + + TRACE("(%d)\n", num_parts); + if (parts) { + for (i = 0; i < num_parts; i++) { + parts[i] = infoPtr->parts[i].x; + } + } + return infoPtr->numParts; +} + + +static BOOL +STATUSBAR_GetRect (STATUS_INFO *infoPtr, INT nPart, LPRECT rect) +{ + TRACE("part %d\n", nPart); + if (infoPtr->simple) + *rect = infoPtr->part0.bound; + else + *rect = infoPtr->parts[nPart].bound; + return TRUE; +} + + +static LRESULT +STATUSBAR_GetTextA (STATUS_INFO *infoPtr, INT nPart, LPSTR buf) +{ + STATUSWINDOWPART *part; + LRESULT result; + + TRACE("part %d\n", nPart); + + /* MSDN says: "simple parts use index of 0", so this check is ok. */ + if (nPart < 0 || nPart >= infoPtr->numParts) return 0; + + if (infoPtr->simple) + part = &infoPtr->part0; + else + part = &infoPtr->parts[nPart]; + + if (part->style & SBT_OWNERDRAW) + result = (LRESULT)part->text; + else { + DWORD len = part->text ? WideCharToMultiByte( CP_ACP, 0, part->text, -1, + NULL, 0, NULL, NULL ) - 1 : 0; + result = MAKELONG( len, part->style ); + if (part->text && buf) + WideCharToMultiByte( CP_ACP, 0, part->text, -1, buf, len+1, NULL, NULL ); + } + return result; +} + + +static LRESULT +STATUSBAR_GetTextW (STATUS_INFO *infoPtr, INT nPart, LPWSTR buf) +{ + STATUSWINDOWPART *part; + LRESULT result; + + TRACE("part %d\n", nPart); + if (nPart < 0 || nPart >= infoPtr->numParts) return 0; + + if (infoPtr->simple) + part = &infoPtr->part0; + else + part = &infoPtr->parts[nPart]; + + if (part->style & SBT_OWNERDRAW) + result = (LRESULT)part->text; + else { + result = part->text ? strlenW (part->text) : 0; + result |= (part->style << 16); + if (part->text && buf) + strcpyW (buf, part->text); + } + return result; +} + + +static LRESULT +STATUSBAR_GetTextLength (STATUS_INFO *infoPtr, INT nPart) +{ + STATUSWINDOWPART *part; + DWORD result; + + TRACE("part %d\n", nPart); + + /* MSDN says: "simple parts use index of 0", so this check is ok. */ + if (nPart < 0 || nPart >= infoPtr->numParts) return 0; + + if (infoPtr->simple) + part = &infoPtr->part0; + else + part = &infoPtr->parts[nPart]; + + if ((~part->style & SBT_OWNERDRAW) && part->text) + result = strlenW(part->text); + else + result = 0; + + result |= (part->style << 16); + return result; +} + +static LRESULT +STATUSBAR_GetTipTextA (STATUS_INFO *infoPtr, INT id, LPSTR tip, INT size) +{ + TRACE("\n"); + if (tip) { + CHAR buf[INFOTIPSIZE]; + buf[0]='\0'; + + if (infoPtr->hwndToolTip) { + TTTOOLINFOA ti; + ti.cbSize = sizeof(TTTOOLINFOA); + ti.hwnd = infoPtr->Self; + ti.uId = id; + ti.lpszText = buf; + SendMessageA (infoPtr->hwndToolTip, TTM_GETTEXTA, 0, (LPARAM)&ti); + } + lstrcpynA (tip, buf, size); + } + return 0; +} + + +static LRESULT +STATUSBAR_GetTipTextW (STATUS_INFO *infoPtr, INT id, LPWSTR tip, INT size) +{ + TRACE("\n"); + if (tip) { + WCHAR buf[INFOTIPSIZE]; + buf[0]=0; + + if (infoPtr->hwndToolTip) { + TTTOOLINFOW ti; + ti.cbSize = sizeof(TTTOOLINFOW); + ti.hwnd = infoPtr->Self; + ti.uId = id; + ti.lpszText = buf; + SendMessageW(infoPtr->hwndToolTip, TTM_GETTEXTW, 0, (LPARAM)&ti); + } + lstrcpynW(tip, buf, size); + } + + return 0; +} + + +static COLORREF +STATUSBAR_SetBkColor (STATUS_INFO *infoPtr, COLORREF color) +{ + COLORREF oldBkColor; + + oldBkColor = infoPtr->clrBk; + infoPtr->clrBk = color; + InvalidateRect(infoPtr->Self, NULL, FALSE); + + TRACE("CREF: %08lx -> %08lx\n", oldBkColor, infoPtr->clrBk); + return oldBkColor; +} + + +static BOOL +STATUSBAR_SetIcon (STATUS_INFO *infoPtr, INT nPart, HICON hIcon) +{ + if ((nPart < -1) || (nPart >= infoPtr->numParts)) + return FALSE; + + TRACE("setting part %d\n", nPart); + + /* FIXME: MSDN says "if nPart is -1, the status bar is assumed simple" */ + if (nPart == -1) { + if (infoPtr->part0.hIcon == hIcon) /* same as - no redraw */ + return TRUE; + infoPtr->part0.hIcon = hIcon; + if (infoPtr->simple) + InvalidateRect(infoPtr->Self, &infoPtr->part0.bound, FALSE); + } else { + if (infoPtr->parts[nPart].hIcon == hIcon) /* same as - no redraw */ + return TRUE; + + infoPtr->parts[nPart].hIcon = hIcon; + if (!(infoPtr->simple)) + InvalidateRect(infoPtr->Self, &infoPtr->parts[nPart].bound, FALSE); + } + return TRUE; +} + + +static BOOL +STATUSBAR_SetMinHeight (STATUS_INFO *infoPtr, INT height) +{ + + TRACE("(height=%d)\n", height); + if (IsWindowVisible (infoPtr->Self)) { + INT width, x, y; + RECT parent_rect; + + GetClientRect (infoPtr->Notify, &parent_rect); + infoPtr->height = height + infoPtr->verticalBorder; + width = parent_rect.right - parent_rect.left; + x = parent_rect.left; + y = parent_rect.bottom - infoPtr->height; + MoveWindow (infoPtr->Self, parent_rect.left, + parent_rect.bottom - infoPtr->height, + width, infoPtr->height, TRUE); + STATUSBAR_SetPartBounds (infoPtr); + } + + return TRUE; +} + + +static BOOL +STATUSBAR_SetParts (STATUS_INFO *infoPtr, INT count, LPINT parts) +{ + STATUSWINDOWPART *tmp; + int i, oldNumParts; + + TRACE("(%d,%p)\n", count, parts); + + oldNumParts = infoPtr->numParts; + infoPtr->numParts = count; + if (oldNumParts > infoPtr->numParts) { + for (i = infoPtr->numParts ; i < oldNumParts; i++) { + if (infoPtr->parts[i].text && !(infoPtr->parts[i].style & SBT_OWNERDRAW)) + Free (infoPtr->parts[i].text); + } + } else if (oldNumParts < infoPtr->numParts) { + tmp = Alloc (sizeof(STATUSWINDOWPART) * infoPtr->numParts); + if (!tmp) return FALSE; + for (i = 0; i < oldNumParts; i++) { + tmp[i] = infoPtr->parts[i]; + } + if (infoPtr->parts) + Free (infoPtr->parts); + infoPtr->parts = tmp; + } + if (oldNumParts == infoPtr->numParts) { + for (i=0; i < oldNumParts; i++) + if (infoPtr->parts[i].x != parts[i]) + break; + if (i==oldNumParts) /* Unchanged? no need to redraw! */ + return TRUE; + } + + for (i = 0; i < infoPtr->numParts; i++) + infoPtr->parts[i].x = parts[i]; + + if (infoPtr->hwndToolTip) { + INT nTipCount, i; + TTTOOLINFOW ti; + + ZeroMemory (&ti, sizeof(TTTOOLINFOW)); + ti.cbSize = sizeof(TTTOOLINFOW); + ti.hwnd = infoPtr->Self; + + nTipCount = SendMessageW (infoPtr->hwndToolTip, TTM_GETTOOLCOUNT, 0, 0); + if (nTipCount < infoPtr->numParts) { + /* add tools */ + for (i = nTipCount; i < infoPtr->numParts; i++) { + TRACE("add tool %d\n", i); + ti.uId = i; + SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, + 0, (LPARAM)&ti); + } + } + else if (nTipCount > infoPtr->numParts) { + /* delete tools */ + for (i = nTipCount - 1; i >= infoPtr->numParts; i--) { + TRACE("delete tool %d\n", i); + ti.uId = i; + SendMessageW (infoPtr->hwndToolTip, TTM_DELTOOLW, + 0, (LPARAM)&ti); + } + } + } + STATUSBAR_SetPartBounds (infoPtr); + InvalidateRect(infoPtr->Self, NULL, FALSE); + return TRUE; +} + + +static BOOL +STATUSBAR_SetTextT (STATUS_INFO *infoPtr, INT nPart, WORD style, + LPCWSTR text, BOOL isW) +{ + STATUSWINDOWPART *part=NULL; + BOOL changed = FALSE; + INT oldStyle; + + if (style & SBT_OWNERDRAW) { + TRACE("part %d, text %p\n",nPart,text); + } + else TRACE("part %d, text %s\n", nPart, debugstr_t(text, isW)); + + /* MSDN says: "If the parameter is set to SB_SIMPLEID (255), the status + * window is assumed to be a simple window */ + + if (nPart == 0x00ff) { + part = &infoPtr->part0; + } else { + if (infoPtr->parts && nPart >= 0 && nPart < infoPtr->numParts) { + part = &infoPtr->parts[nPart]; + } + } + if (!part) return FALSE; + + if (part->style != style) + changed = TRUE; + + oldStyle = part->style; + part->style = style; + if (style & SBT_OWNERDRAW) { + if (!(oldStyle & SBT_OWNERDRAW)) { + if (part->text) + Free (part->text); + } else if (part->text == text) + return TRUE; + part->text = (LPWSTR)text; + } else { + LPWSTR ntext; + + if (text && !isW) { + LPCSTR atxt = (LPCSTR)text; + DWORD len = MultiByteToWideChar( CP_ACP, 0, atxt, -1, NULL, 0 ); + ntext = Alloc( (len + 1)*sizeof(WCHAR) ); + if (!ntext) return FALSE; + MultiByteToWideChar( CP_ACP, 0, atxt, -1, ntext, len ); + } else if (text) { + ntext = Alloc( (strlenW(text) + 1)*sizeof(WCHAR) ); + if (!ntext) return FALSE; + strcpyW (ntext, text); + } else ntext = 0; + + /* check if text is unchanged -> no need to redraw */ + if (text) { + if (!changed && part->text && !lstrcmpW(ntext, part->text)) { + Free(ntext); + return TRUE; + } + } else { + if (!changed && !part->text) + return TRUE; + } + + if (part->text && !(oldStyle & SBT_OWNERDRAW)) + Free (part->text); + part->text = ntext; + } + InvalidateRect(infoPtr->Self, &part->bound, FALSE); + + return TRUE; +} + + +static LRESULT +STATUSBAR_SetTipTextA (STATUS_INFO *infoPtr, INT id, LPSTR text) +{ + TRACE("part %d: \"%s\"\n", id, text); + if (infoPtr->hwndToolTip) { + TTTOOLINFOA ti; + ti.cbSize = sizeof(TTTOOLINFOA); + ti.hwnd = infoPtr->Self; + ti.uId = id; + ti.hinst = 0; + ti.lpszText = text; + SendMessageA (infoPtr->hwndToolTip, TTM_UPDATETIPTEXTA, 0, (LPARAM)&ti); + } + + return 0; +} + + +static LRESULT +STATUSBAR_SetTipTextW (STATUS_INFO *infoPtr, INT id, LPWSTR text) +{ + TRACE("part %d: \"%s\"\n", id, debugstr_w(text)); + if (infoPtr->hwndToolTip) { + TTTOOLINFOW ti; + ti.cbSize = sizeof(TTTOOLINFOW); + ti.hwnd = infoPtr->Self; + ti.uId = id; + ti.hinst = 0; + ti.lpszText = text; + SendMessageW (infoPtr->hwndToolTip, TTM_UPDATETIPTEXTW, 0, (LPARAM)&ti); + } + + return 0; +} + + +inline static LRESULT +STATUSBAR_SetUnicodeFormat (STATUS_INFO *infoPtr, BOOL bUnicode) +{ + BOOL bOld = infoPtr->bUnicode; + + TRACE("(0x%x)\n", bUnicode); + infoPtr->bUnicode = bUnicode; + + return bOld; +} + + +static BOOL +STATUSBAR_Simple (STATUS_INFO *infoPtr, BOOL simple) +{ + NMHDR nmhdr; + + TRACE("(simple=%d)\n", simple); + if (infoPtr->simple == simple) /* no need to change */ + return TRUE; + + infoPtr->simple = simple; + + /* send notification */ + nmhdr.hwndFrom = infoPtr->Self; + nmhdr.idFrom = GetWindowLongPtrW (infoPtr->Self, GWLP_ID); + nmhdr.code = SBN_SIMPLEMODECHANGE; + SendMessageW (infoPtr->Notify, WM_NOTIFY, 0, (LPARAM)&nmhdr); + InvalidateRect(infoPtr->Self, NULL, FALSE); + return TRUE; +} + + +static LRESULT +STATUSBAR_WMDestroy (STATUS_INFO *infoPtr) +{ + int i; + + TRACE("\n"); + for (i = 0; i < infoPtr->numParts; i++) { + if (infoPtr->parts[i].text && !(infoPtr->parts[i].style & SBT_OWNERDRAW)) + Free (infoPtr->parts[i].text); + } + if (infoPtr->part0.text && !(infoPtr->part0.style & SBT_OWNERDRAW)) + Free (infoPtr->part0.text); + Free (infoPtr->parts); + + /* delete default font */ + if (infoPtr->hDefaultFont) + DeleteObject (infoPtr->hDefaultFont); + + /* delete tool tip control */ + if (infoPtr->hwndToolTip) + DestroyWindow (infoPtr->hwndToolTip); + + SetWindowLongPtrW(infoPtr->Self, 0, 0); + Free (infoPtr); + return 0; +} + + +static LRESULT +STATUSBAR_WMCreate (HWND hwnd, LPCREATESTRUCTA lpCreate) +{ + STATUS_INFO *infoPtr; + NONCLIENTMETRICSW nclm; + DWORD dwStyle; + RECT rect; + int i, width, len, textHeight = 0; + HDC hdc; + + TRACE("\n"); + infoPtr = (STATUS_INFO*)Alloc (sizeof(STATUS_INFO)); + if (!infoPtr) goto create_fail; + SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); + + infoPtr->Self = hwnd; + infoPtr->Notify = lpCreate->hwndParent; + infoPtr->numParts = 1; + infoPtr->parts = 0; + infoPtr->simple = FALSE; + infoPtr->clrBk = CLR_DEFAULT; + infoPtr->hFont = 0; + infoPtr->horizontalBorder = HORZ_BORDER; + infoPtr->verticalBorder = VERT_BORDER; + infoPtr->horizontalGap = HORZ_GAP; + + i = SendMessageW(infoPtr->Notify, WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_QUERY); + infoPtr->NtfUnicode = (i == NFR_UNICODE); + + GetClientRect (hwnd, &rect); + InvalidateRect (hwnd, &rect, 0); + UpdateWindow(hwnd); + + ZeroMemory (&nclm, sizeof(nclm)); + nclm.cbSize = sizeof(nclm); + SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, nclm.cbSize, &nclm, 0); + infoPtr->hDefaultFont = CreateFontIndirectW (&nclm.lfStatusFont); + + /* initialize simple case */ + infoPtr->part0.bound = rect; + infoPtr->part0.text = 0; + infoPtr->part0.x = 0; + infoPtr->part0.style = 0; + infoPtr->part0.hIcon = 0; + + /* initialize first part */ + infoPtr->parts = Alloc (sizeof(STATUSWINDOWPART)); + if (!infoPtr->parts) goto create_fail; + infoPtr->parts[0].bound = rect; + infoPtr->parts[0].text = 0; + infoPtr->parts[0].x = -1; + infoPtr->parts[0].style = 0; + infoPtr->parts[0].hIcon = 0; + + if (IsWindowUnicode (hwnd)) { + infoPtr->bUnicode = TRUE; + if (lpCreate->lpszName && + (len = strlenW ((LPCWSTR)lpCreate->lpszName))) { + infoPtr->parts[0].text = Alloc ((len + 1)*sizeof(WCHAR)); + if (!infoPtr->parts[0].text) goto create_fail; + strcpyW (infoPtr->parts[0].text, (LPCWSTR)lpCreate->lpszName); + } + } + else { + if (lpCreate->lpszName && + (len = strlen((LPCSTR)lpCreate->lpszName))) { + DWORD lenW = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)lpCreate->lpszName, -1, NULL, 0 ); + infoPtr->parts[0].text = Alloc (lenW*sizeof(WCHAR)); + if (!infoPtr->parts[0].text) goto create_fail; + MultiByteToWideChar( CP_ACP, 0, (LPCSTR)lpCreate->lpszName, -1, + infoPtr->parts[0].text, lenW ); + } + } + + dwStyle = GetWindowLongW (hwnd, GWL_STYLE); + + /* statusbars on managed windows should not have SIZEGRIP style */ + if ((dwStyle & SBARS_SIZEGRIP) && lpCreate->hwndParent && + GetPropA( lpCreate->hwndParent, "__wine_x11_managed" )) + SetWindowLongW (hwnd, GWL_STYLE, dwStyle & ~SBARS_SIZEGRIP); + + if ((hdc = GetDC (hwnd))) { + TEXTMETRICW tm; + HFONT hOldFont; + + hOldFont = SelectObject (hdc, infoPtr->hDefaultFont); + GetTextMetricsW (hdc, &tm); + textHeight = tm.tmHeight; + SelectObject (hdc, hOldFont); + ReleaseDC (hwnd, hdc); + } + TRACE(" textHeight=%d\n", textHeight); + + if (dwStyle & SBT_TOOLTIPS) { + infoPtr->hwndToolTip = + CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, 0, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, hwnd, 0, + (HINSTANCE)GetWindowLongPtrW(hwnd, GWLP_HINSTANCE), NULL); + + if (infoPtr->hwndToolTip) { + NMTOOLTIPSCREATED nmttc; + + nmttc.hdr.hwndFrom = hwnd; + nmttc.hdr.idFrom = GetWindowLongPtrW (hwnd, GWLP_ID); + nmttc.hdr.code = NM_TOOLTIPSCREATED; + nmttc.hwndToolTips = infoPtr->hwndToolTip; + + SendMessageW (lpCreate->hwndParent, WM_NOTIFY, + (WPARAM)nmttc.hdr.idFrom, (LPARAM)&nmttc); + } + } + + if (!(dwStyle & CCS_NORESIZE)) { /* don't resize wnd if it doesn't want it ! */ + GetClientRect (infoPtr->Notify, &rect); + width = rect.right - rect.left; + infoPtr->height = textHeight + 4 + infoPtr->verticalBorder; + SetWindowPos(hwnd, 0, lpCreate->x, lpCreate->y - 1, + width, infoPtr->height, SWP_NOZORDER); + STATUSBAR_SetPartBounds (infoPtr); + } + + return 0; + +create_fail: + TRACE(" failed!\n"); + if (infoPtr) STATUSBAR_WMDestroy(infoPtr); + return -1; +} + + +/* in contrast to SB_GETTEXT*, WM_GETTEXT handles the text + * of the first part only (usual behaviour) */ +static INT +STATUSBAR_WMGetText (STATUS_INFO *infoPtr, INT size, LPWSTR buf) +{ + INT len; + + TRACE("\n"); + if (!(infoPtr->parts[0].text)) + return 0; + if (infoPtr->bUnicode) + len = strlenW (infoPtr->parts[0].text); + else + len = WideCharToMultiByte( CP_ACP, 0, infoPtr->parts[0].text, -1, NULL, 0, NULL, NULL )-1; + + if (size > len) { + if (infoPtr->bUnicode) + strcpyW (buf, infoPtr->parts[0].text); + else + WideCharToMultiByte( CP_ACP, 0, infoPtr->parts[0].text, -1, + (LPSTR)buf, len+1, NULL, NULL ); + return len; + } + + return -1; +} + + +static BOOL +STATUSBAR_WMNCHitTest (STATUS_INFO *infoPtr, INT x, INT y) +{ + if (GetWindowLongW (infoPtr->Self, GWL_STYLE) & SBARS_SIZEGRIP) { + RECT rect; + POINT pt; + + GetClientRect (infoPtr->Self, &rect); + + pt.x = x; + pt.y = y; + ScreenToClient (infoPtr->Self, &pt); + + rect.left = rect.right - 13; + rect.top += 2; + + if (PtInRect (&rect, pt)) + return HTBOTTOMRIGHT; + } + + return HTERROR; +} + + +static LRESULT +STATUSBAR_WMPaint (STATUS_INFO *infoPtr, HDC hdc) +{ + PAINTSTRUCT ps; + + TRACE("\n"); + if (hdc) return STATUSBAR_Refresh (infoPtr, hdc); + hdc = BeginPaint (infoPtr->Self, &ps); + STATUSBAR_Refresh (infoPtr, hdc); + EndPaint (infoPtr->Self, &ps); + + return 0; +} + + +static LRESULT +STATUSBAR_WMSetFont (STATUS_INFO *infoPtr, HFONT font, BOOL redraw) +{ + infoPtr->hFont = font; + TRACE("%p\n", infoPtr->hFont); + if (redraw) + InvalidateRect(infoPtr->Self, NULL, FALSE); + + return 0; +} + + +static BOOL +STATUSBAR_WMSetText (STATUS_INFO *infoPtr, LPCSTR text) +{ + STATUSWINDOWPART *part; + int len; + + TRACE("\n"); + if (infoPtr->numParts == 0) + return FALSE; + + part = &infoPtr->parts[0]; + /* duplicate string */ + if (part->text) + Free (part->text); + part->text = 0; + if (infoPtr->bUnicode) { + if (text && (len = strlenW((LPCWSTR)text))) { + part->text = Alloc ((len+1)*sizeof(WCHAR)); + if (!part->text) return FALSE; + strcpyW (part->text, (LPCWSTR)text); + } + } + else { + if (text && (len = lstrlenA(text))) { + DWORD lenW = MultiByteToWideChar( CP_ACP, 0, text, -1, NULL, 0 ); + part->text = Alloc (lenW*sizeof(WCHAR)); + if (!part->text) return FALSE; + MultiByteToWideChar( CP_ACP, 0, text, -1, part->text, lenW ); + } + } + + InvalidateRect(infoPtr->Self, &part->bound, FALSE); + + return TRUE; +} + + +static BOOL +STATUSBAR_WMSize (STATUS_INFO *infoPtr, WORD flags) +{ + INT width, x, y; + RECT parent_rect; + + /* Need to resize width to match parent */ + TRACE("flags %04x\n", flags); + + if (flags != SIZE_RESTORED && flags != SIZE_MAXIMIZED) { + WARN("flags MUST be SIZE_RESTORED or SIZE_MAXIMIZED\n"); + return FALSE; + } + + if (GetWindowLongW(infoPtr->Self, GWL_STYLE) & CCS_NORESIZE) return FALSE; + + /* width and height don't apply */ + GetClientRect (infoPtr->Notify, &parent_rect); + width = parent_rect.right - parent_rect.left; + x = parent_rect.left; + y = parent_rect.bottom - infoPtr->height; + MoveWindow (infoPtr->Self, parent_rect.left, + parent_rect.bottom - infoPtr->height, + width, infoPtr->height, TRUE); + STATUSBAR_SetPartBounds (infoPtr); + return TRUE; +} + + +static LRESULT +STATUSBAR_NotifyFormat (STATUS_INFO *infoPtr, HWND from, INT cmd) +{ + if (cmd == NF_REQUERY) { + INT i = SendMessageW(from, WM_NOTIFYFORMAT, (WPARAM)infoPtr->Self, NF_QUERY); + infoPtr->NtfUnicode = (i == NFR_UNICODE); + } + return infoPtr->NtfUnicode ? NFR_UNICODE : NFR_ANSI; +} + + +static LRESULT +STATUSBAR_SendNotify (STATUS_INFO *infoPtr, UINT code) +{ + NMHDR nmhdr; + + TRACE("code %04x\n", code); + nmhdr.hwndFrom = infoPtr->Self; + nmhdr.idFrom = GetWindowLongPtrW (infoPtr->Self, GWLP_ID); + nmhdr.code = code; + SendMessageW (infoPtr->Notify, WM_NOTIFY, 0, (LPARAM)&nmhdr); + return 0; +} + + + +static LRESULT WINAPI +StatusWindowProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + STATUS_INFO *infoPtr = (STATUS_INFO *)GetWindowLongPtrW (hwnd, 0); + INT nPart = ((INT) wParam) & 0x00ff; + LRESULT res; + + TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hwnd, msg, wParam, lParam); + if (!infoPtr && msg != WM_CREATE) + return DefWindowProcW (hwnd, msg, wParam, lParam); + + switch (msg) { + case SB_GETBORDERS: + return STATUSBAR_GetBorders (infoPtr, (INT *)lParam); + + case SB_GETICON: + return (LRESULT)STATUSBAR_GetIcon (infoPtr, nPart); + + case SB_GETPARTS: + return STATUSBAR_GetParts (infoPtr, (INT)wParam, (INT *)lParam); + + case SB_GETRECT: + return STATUSBAR_GetRect (infoPtr, nPart, (LPRECT)lParam); + + case SB_GETTEXTA: + return STATUSBAR_GetTextA (infoPtr, nPart, (LPSTR)lParam); + + case SB_GETTEXTW: + return STATUSBAR_GetTextW (infoPtr, nPart, (LPWSTR)lParam); + + case SB_GETTEXTLENGTHA: + case SB_GETTEXTLENGTHW: + return STATUSBAR_GetTextLength (infoPtr, nPart); + + case SB_GETTIPTEXTA: + return STATUSBAR_GetTipTextA (infoPtr, LOWORD(wParam), (LPSTR)lParam, HIWORD(wParam)); + + case SB_GETTIPTEXTW: + return STATUSBAR_GetTipTextW (infoPtr, LOWORD(wParam), (LPWSTR)lParam, HIWORD(wParam)); + + case SB_GETUNICODEFORMAT: + return infoPtr->bUnicode; + + case SB_ISSIMPLE: + return infoPtr->simple; + + case SB_SETBORDERS: + return STATUSBAR_SetBorders (infoPtr, (INT *)lParam); + + case SB_SETBKCOLOR: + return STATUSBAR_SetBkColor (infoPtr, (COLORREF)lParam); + + case SB_SETICON: + return STATUSBAR_SetIcon (infoPtr, nPart, (HICON)lParam); + + case SB_SETMINHEIGHT: + return STATUSBAR_SetMinHeight (infoPtr, (INT)wParam); + + case SB_SETPARTS: + return STATUSBAR_SetParts (infoPtr, (INT)wParam, (LPINT)lParam); + + case SB_SETTEXTA: + return STATUSBAR_SetTextT (infoPtr, nPart, wParam & 0xff00, (LPCWSTR)lParam, FALSE); + + case SB_SETTEXTW: + return STATUSBAR_SetTextT (infoPtr, nPart, wParam & 0xff00, (LPCWSTR)lParam, TRUE); + + case SB_SETTIPTEXTA: + return STATUSBAR_SetTipTextA (infoPtr, (INT)wParam, (LPSTR)lParam); + + case SB_SETTIPTEXTW: + return STATUSBAR_SetTipTextW (infoPtr, (INT)wParam, (LPWSTR)lParam); + + case SB_SETUNICODEFORMAT: + return STATUSBAR_SetUnicodeFormat (infoPtr, (BOOL)wParam); + + case SB_SIMPLE: + return STATUSBAR_Simple (infoPtr, (BOOL)wParam); + + case WM_CREATE: + return STATUSBAR_WMCreate (hwnd, (LPCREATESTRUCTA)lParam); + + case WM_DESTROY: + return STATUSBAR_WMDestroy (infoPtr); + + case WM_GETFONT: + return (LRESULT)(infoPtr->hFont? infoPtr->hFont : infoPtr->hDefaultFont); + + case WM_GETTEXT: + return STATUSBAR_WMGetText (infoPtr, (INT)wParam, (LPWSTR)lParam); + + case WM_GETTEXTLENGTH: + return STATUSBAR_GetTextLength (infoPtr, 0); + + case WM_LBUTTONDBLCLK: + return STATUSBAR_SendNotify (infoPtr, NM_DBLCLK); + + case WM_LBUTTONUP: + return STATUSBAR_SendNotify (infoPtr, NM_CLICK); + + case WM_MOUSEMOVE: + return STATUSBAR_Relay2Tip (infoPtr, msg, wParam, lParam); + + case WM_NCHITTEST: + res = STATUSBAR_WMNCHitTest(infoPtr, (INT)LOWORD(lParam), + (INT)HIWORD(lParam)); + if (res != HTERROR) return res; + return DefWindowProcW (hwnd, msg, wParam, lParam); + + case WM_NCLBUTTONUP: + case WM_NCLBUTTONDOWN: + PostMessageW (infoPtr->Notify, msg, wParam, lParam); + return 0; + + case WM_NOTIFYFORMAT: + return STATUSBAR_NotifyFormat(infoPtr, (HWND)wParam, (INT)lParam); + + case WM_PAINT: + return STATUSBAR_WMPaint (infoPtr, (HDC)wParam); + + case WM_RBUTTONDBLCLK: + return STATUSBAR_SendNotify (infoPtr, NM_RDBLCLK); + + case WM_RBUTTONUP: + return STATUSBAR_SendNotify (infoPtr, NM_RCLICK); + + case WM_SETFONT: + return STATUSBAR_WMSetFont (infoPtr, (HFONT)wParam, LOWORD(lParam)); + + case WM_SETTEXT: + return STATUSBAR_WMSetText (infoPtr, (LPCSTR)lParam); + + case WM_SIZE: + if (STATUSBAR_WMSize (infoPtr, (WORD)wParam)) return 0; + return DefWindowProcW (hwnd, msg, wParam, lParam); + + default: + if ((msg >= WM_USER) && (msg < WM_APP)) + ERR("unknown msg %04x wp=%04x lp=%08lx\n", + msg, wParam, lParam); + return DefWindowProcW (hwnd, msg, wParam, lParam); + } +} + + +/*********************************************************************** + * STATUS_Register [Internal] + * + * Registers the status window class. + */ + +void +STATUS_Register (void) +{ + WNDCLASSW wndClass; + + ZeroMemory (&wndClass, sizeof(WNDCLASSW)); + wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_VREDRAW; + wndClass.lpfnWndProc = StatusWindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(STATUS_INFO *); + wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); + wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); + wndClass.lpszClassName = STATUSCLASSNAMEW; + + RegisterClassW (&wndClass); +} + + +/*********************************************************************** + * STATUS_Unregister [Internal] + * + * Unregisters the status window class. + */ + +void +STATUS_Unregister (void) +{ + UnregisterClassW (STATUSCLASSNAMEW, NULL); +} diff --git a/reactos/lib/comctl32/string.c b/reactos/lib/comctl32/string.c index b9aa285cc8f..7e7afe0675c 100644 --- a/reactos/lib/comctl32/string.c +++ b/reactos/lib/comctl32/string.c @@ -1,851 +1,851 @@ -/* - * String manipulation functions - * - * Copyright 1998 Eric Kohl - * 1998 Juergen Schmied - * 2000 Eric Kohl for CodeWeavers - * Copyright 2002 Jon Griffiths - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include /* atoi */ - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "winnls.h" - -#include "wine/unicode.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(commctrl); - -/************************************************************************* - * COMCTL32_ChrCmpHelperA - * - * Internal helper for ChrCmpA/COMCTL32_ChrCmpIA. - * - * NOTES - * Both this function and its Unicode counterpart are very inneficient. To - * fix this, CompareString must be completely implemented and optimised - * first. Then the core character test can be taken out of that function and - * placed here, so that it need never be called at all. Until then, do not - * attempt to optimise this code unless you are willing to test that it - * still performs correctly. - */ -static BOOL COMCTL32_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags) -{ - char str1[3], str2[3]; - - str1[0] = LOBYTE(ch1); - if (IsDBCSLeadByte(str1[0])) - { - str1[1] = HIBYTE(ch1); - str1[2] = '\0'; - } - else - str1[1] = '\0'; - - str2[0] = LOBYTE(ch2); - if (IsDBCSLeadByte(str2[0])) - { - str2[1] = HIBYTE(ch2); - str2[2] = '\0'; - } - else - str2[1] = '\0'; - - return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2; -} - -/************************************************************************* - * COMCTL32_ChrCmpHelperW - * - * Internal helper for COMCTL32_ChrCmpW/ChrCmpIW. - */ -static BOOL COMCTL32_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags) -{ - WCHAR str1[2], str2[2]; - - str1[0] = ch1; - str1[1] = '\0'; - str2[0] = ch2; - str2[1] = '\0'; - return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2; -} - -/************************************************************************* - * COMCTL32_ChrCmpA (internal) - * - * Internal helper function. - */ -static BOOL COMCTL32_ChrCmpA(WORD ch1, WORD ch2) -{ - return COMCTL32_ChrCmpHelperA(ch1, ch2, 0); -} - -/************************************************************************* - * COMCTL32_ChrCmpIA (internal) - * - * Compare two characters, ignoring case. - * - * PARAMS - * ch1 [I] First character to compare - * ch2 [I] Second character to compare - * - * RETURNS - * FALSE, if the characters are equal. - * Non-zero otherwise. - */ -static BOOL COMCTL32_ChrCmpIA(WORD ch1, WORD ch2) -{ - TRACE("(%d,%d)\n", ch1, ch2); - - return COMCTL32_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE); -} - -/************************************************************************* - * COMCTL32_ChrCmpW - * - * Internal helper function. - */ -static BOOL COMCTL32_ChrCmpW(WCHAR ch1, WCHAR ch2) -{ - return COMCTL32_ChrCmpHelperW(ch1, ch2, 0); -} - -/************************************************************************* - * COMCTL32_ChrCmpIW - * - * Internal helper function. - */ -static BOOL COMCTL32_ChrCmpIW(WCHAR ch1, WCHAR ch2) -{ - return COMCTL32_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE); -} - -/************************************************************************** - * StrChrA [COMCTL32.350] - * - * Find a given character in a string. - * - * PARAMS - * lpszStr [I] String to search in. - * ch [I] Character to search for. - * - * RETURNS - * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if - * not found. - * Failure: NULL, if any arguments are invalid. - */ -LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch) -{ - TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch); - - if (lpszStr) - { - while (*lpszStr) - { - if (!COMCTL32_ChrCmpA(*lpszStr, ch)) - return (LPSTR)lpszStr; - lpszStr = CharNextA(lpszStr); - } - } - return NULL; -} - -/************************************************************************* - * COMCTL32_StrStrHelperA - * - * Internal implementation of StrStrA/StrStrIA - */ -static LPSTR COMCTL32_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch, - int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t)) -{ - size_t iLen; - - if (!lpszStr || !lpszSearch || !*lpszSearch) - return NULL; - - iLen = strlen(lpszSearch); - - while (*lpszStr) - { - if (!pStrCmpFn(lpszStr, lpszSearch, iLen)) - return (LPSTR)lpszStr; - lpszStr = CharNextA(lpszStr); - } - return NULL; -} - -/************************************************************************* - * COMCTL32_StrStrHelperW - * - * Internal implementation of StrStrW/StrStrIW - */ -static LPWSTR COMCTL32_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch, - int (*pStrCmpFn)(LPCWSTR,LPCWSTR,int)) -{ - int iLen; - - if (!lpszStr || !lpszSearch || !*lpszSearch) - return NULL; - - iLen = strlenW(lpszSearch); - - while (*lpszStr) - { - if (!pStrCmpFn(lpszStr, lpszSearch, iLen)) - return (LPWSTR)lpszStr; - lpszStr = CharNextW(lpszStr); - } - return NULL; -} - -/************************************************************************** - * StrStrIA [COMCTL32.355] - * - * Find a substring within a string, ignoring case. - * - * PARAMS - * lpszStr [I] String to search in - * lpszSearch [I] String to look for - * - * RETURNS - * The start of lpszSearch within lpszStr, or NULL if not found. - */ -LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch) -{ - TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch)); - - return COMCTL32_StrStrHelperA(lpszStr, lpszSearch, strncasecmp); -} - -/************************************************************************** - * StrToIntA [COMCTL32.357] - * - * Read a signed integer from a string. - * - * PARAMS - * lpszStr [I] String to read integer from - * - * RETURNS - * The signed integer value represented by the string, or 0 if no integer is - * present. - */ -INT WINAPI StrToIntA (LPSTR lpszStr) -{ - return atoi(lpszStr); -} - -/************************************************************************** - * StrStrIW [COMCTL32.363] - * - * See StrStrIA. - */ -LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch) -{ - TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch)); - - return COMCTL32_StrStrHelperW(lpszStr, lpszSearch, (int (*)(LPCWSTR,LPCWSTR,int)) wcsnicmp); -} - -/************************************************************************** - * StrToIntW [COMCTL32.365] - * - * See StrToIntA. - */ -INT WINAPI StrToIntW (LPWSTR lpString) -{ - return atoiW(lpString); -} - -/************************************************************************* - * COMCTL32_StrSpnHelperA (internal) - * - * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA - */ -static int COMCTL32_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch, - LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD), - BOOL bInvert) -{ - LPCSTR lpszRead = lpszStr; - if (lpszStr && *lpszStr && lpszMatch) - { - while (*lpszRead) - { - LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead); - - if (!bInvert && !lpszTest) - break; - if (bInvert && lpszTest) - break; - lpszRead = CharNextA(lpszRead); - }; - } - return lpszRead - lpszStr; -} - -/************************************************************************** - * StrCSpnA [COMCTL32.356] - * - * Find the length of the start of a string that does not contain certain - * characters. - * - * PARAMS - * lpszStr [I] String to search - * lpszMatch [I] Characters that cannot be in the substring - * - * RETURNS - * The length of the part of lpszStr containing only chars not in lpszMatch, - * or 0 if any parameter is invalid. - */ -int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch) -{ - TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); - - return COMCTL32_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE); -} - -/************************************************************************** - * StrChrW [COMCTL32.358] - * - * See StrChrA. - */ -LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch) -{ - LPWSTR lpszRet = NULL; - - TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch); - - if (lpszStr) - lpszRet = strchrW(lpszStr, ch); - return lpszRet; -} - -/************************************************************************** - * StrCmpNA [COMCTL32.352] - * - * Compare two strings, up to a maximum length. - * - * PARAMS - * lpszStr [I] First string to compare - * lpszComp [I] Second string to compare - * iLen [I] Maximum number of chars to compare. - * - * RETURNS - * An integer less than, equal to or greater than 0, indicating that - * lpszStr is less than, the same, or greater than lpszComp. - */ -INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen) -{ - INT iRet; - - TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen); - - iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen); - return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; -} - -/************************************************************************** - * StrCmpNIA [COMCTL32.353] - * - * Compare two strings, up to a maximum length, ignoring case. - * - * PARAMS - * lpszStr [I] First string to compare - * lpszComp [I] Second string to compare - * iLen [I] Maximum number of chars to compare. - * - * RETURNS - * An integer less than, equal to or greater than 0, indicating that - * lpszStr is less than, the same, or greater than lpszComp. - */ -int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen) -{ - INT iRet; - - TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen); - - iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen); - return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; -} - -/************************************************************************* - * StrCmpNIW [COMCTL32.361] - * - * See StrCmpNIA. - */ -INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen) -{ - INT iRet; - - TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen); - - iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen); - return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; -} - -/************************************************************************** - * StrCmpNW [COMCTL32.360] - * - * See StrCmpNA. - */ -INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen) -{ - INT iRet; - - TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen); - - iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen); - return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; -} - -/************************************************************************** - * StrRChrA [COMCTL32.351] - * - * Find the last occurrence of a character in string. - * - * PARAMS - * lpszStr [I] String to search in - * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr - * ch [I] Character to search for. - * - * RETURNS - * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd, - * or NULL if not found. - * Failure: NULL, if any arguments are invalid. - */ -LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch) -{ - LPCSTR lpszRet = NULL; - - TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch); - - if (lpszStr) - { - WORD ch2; - - if (!lpszEnd) - lpszEnd = lpszStr + lstrlenA(lpszStr); - - while (*lpszStr && lpszStr <= lpszEnd) - { - ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr; - - if (!COMCTL32_ChrCmpA(ch, ch2)) - lpszRet = lpszStr; - lpszStr = CharNextA(lpszStr); - } - } - return (LPSTR)lpszRet; -} - - -/************************************************************************** - * StrRChrW [COMCTL32.359] - * - * See StrRChrA. - */ -LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch) -{ - LPCWSTR lpszRet = NULL; - - TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch); - - if (lpszStr) - { - if (!lpszEnd) - lpszEnd = lpszStr + strlenW(lpszStr); - - while (*lpszStr && lpszStr <= lpszEnd) - { - if (!COMCTL32_ChrCmpW(ch, *lpszStr)) - lpszRet = lpszStr; - lpszStr = CharNextW(lpszStr); - } - } - return (LPWSTR)lpszRet; -} - -/************************************************************************** - * StrStrA [COMCTL32.354] - * - * Find a substring within a string. - * - * PARAMS - * lpszStr [I] String to search in - * lpszSearch [I] String to look for - * - * RETURNS - * The start of lpszSearch within lpszStr, or NULL if not found. - */ -LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch) -{ - TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch)); - - return COMCTL32_StrStrHelperA(lpszStr, lpszSearch, strncmp); -} - -/************************************************************************** - * StrStrW [COMCTL32.362] - * - * See StrStrA. - */ -LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch) -{ - TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch)); - - return COMCTL32_StrStrHelperW(lpszStr, lpszSearch, (int (*)(LPCWSTR,LPCWSTR,int)) wcsncmp); -} - -/************************************************************************* - * StrChrIA [COMCTL32.366] - * - * Find a given character in a string, ignoring case. - * - * PARAMS - * lpszStr [I] String to search in. - * ch [I] Character to search for. - * - * RETURNS - * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if - * not found. - * Failure: NULL, if any arguments are invalid. - */ -LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch) -{ - TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch); - - if (lpszStr) - { - while (*lpszStr) - { - if (!COMCTL32_ChrCmpIA(*lpszStr, ch)) - return (LPSTR)lpszStr; - lpszStr = CharNextA(lpszStr); - } - } - return NULL; -} - -/************************************************************************* - * StrChrIW [COMCTL32.367] - * - * See StrChrA. - */ -LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch) -{ - TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch); - - if (lpszStr) - { - ch = toupperW(ch); - while (*lpszStr) - { - if (toupperW(*lpszStr) == ch) - return (LPWSTR)lpszStr; - lpszStr = CharNextW(lpszStr); - } - lpszStr = NULL; - } - return (LPWSTR)lpszStr; -} - -/************************************************************************* - * StrRStrIA [COMCTL32.372] - * - * Find the last occurrence of a substring within a string. - * - * PARAMS - * lpszStr [I] String to search in - * lpszEnd [I] End of lpszStr - * lpszSearch [I] String to look for - * - * RETURNS - * The last occurrence lpszSearch within lpszStr, or NULL if not found. - */ -LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch) -{ - LPSTR lpszRet = NULL; - WORD ch1, ch2; - INT iLen; - - TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch)); - - if (!lpszStr || !lpszSearch || !*lpszSearch) - return NULL; - - if (!lpszEnd) - lpszEnd = lpszStr + lstrlenA(lpszStr); - - if (IsDBCSLeadByte(*lpszSearch)) - ch1 = *lpszSearch << 8 | lpszSearch[1]; - else - ch1 = *lpszSearch; - iLen = lstrlenA(lpszSearch); - - while (lpszStr <= lpszEnd && *lpszStr) - { - ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr; - if (!COMCTL32_ChrCmpIA(ch1, ch2)) - { - if (!StrCmpNIA(lpszStr, lpszSearch, iLen)) - lpszRet = (LPSTR)lpszStr; - } - lpszStr = CharNextA(lpszStr); - } - return lpszRet; -} - -/************************************************************************* - * StrRStrIW [COMCTL32.373] - * - * See StrRStrIA. - */ -LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch) -{ - LPWSTR lpszRet = NULL; - INT iLen; - - TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch)); - - if (!lpszStr || !lpszSearch || !*lpszSearch) - return NULL; - - if (!lpszEnd) - lpszEnd = lpszStr + strlenW(lpszStr); - - iLen = strlenW(lpszSearch); - - while (lpszStr <= lpszEnd && *lpszStr) - { - if (!COMCTL32_ChrCmpIW(*lpszSearch, *lpszStr)) - { - if (!StrCmpNIW(lpszStr, lpszSearch, iLen)) - lpszRet = (LPWSTR)lpszStr; - } - lpszStr = CharNextW(lpszStr); - } - return lpszRet; -} - -/************************************************************************* - * COMCTL32_StrSpnHelperW - * - * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW - */ -static int COMCTL32_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch, - LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR), - BOOL bInvert) -{ - LPCWSTR lpszRead = lpszStr; - if (lpszStr && *lpszStr && lpszMatch) - { - while (*lpszRead) - { - LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead); - - if (!bInvert && !lpszTest) - break; - if (bInvert && lpszTest) - break; - lpszRead = CharNextW(lpszRead); - }; - } - return lpszRead - lpszStr; -} - -/************************************************************************* - * StrCSpnIA [COMCTL32.374] - * - * Find the length of the start of a string that does not contain certain - * characters, ignoring case. - * - * PARAMS - * lpszStr [I] String to search - * lpszMatch [I] Characters that cannot be in the substring - * - * RETURNS - * The length of the part of lpszStr containing only chars not in lpszMatch, - * or 0 if any parameter is invalid. - */ -int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch) -{ - TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); - - return COMCTL32_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE); -} - -/************************************************************************* - * StrCSpnIW [COMCTL32.375] - * - * See StrCSpnIA. - */ -int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch) -{ - TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch)); - - return COMCTL32_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE); -} - -/************************************************************************** - * StrRChrIA [COMCTL32.368] - * - * Find the last occurrence of a character in string, ignoring case. - * - * PARAMS - * lpszStr [I] String to search in - * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr - * ch [I] Character to search for. - * - * RETURNS - * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd, - * or NULL if not found. - * Failure: NULL, if any arguments are invalid. - */ -LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch) -{ - LPCSTR lpszRet = NULL; - - TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch); - - if (lpszStr) - { - WORD ch2; - - if (!lpszEnd) - lpszEnd = lpszStr + lstrlenA(lpszStr); - - while (*lpszStr && lpszStr <= lpszEnd) - { - ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr; - - if (ch == ch2) - lpszRet = lpszStr; - lpszStr = CharNextA(lpszStr); - } - } - return (LPSTR)lpszRet; -} - -/************************************************************************** - * StrRChrIW [COMCTL32.369] - * - * See StrRChrIA. - */ -LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch) -{ - LPCWSTR lpszRet = NULL; - - TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch); - - if (lpszStr) - { - if (!lpszEnd) - lpszEnd = lpszStr + strlenW(lpszStr); - - while (*lpszStr && lpszStr <= lpszEnd) - { - if (ch == *lpszStr) - lpszRet = lpszStr; - lpszStr = CharNextW(lpszStr); - } - } - return (LPWSTR)lpszRet; -} - -/************************************************************************* - * StrCSpnW [COMCTL32.364] - * - * See StrCSpnA. - */ -int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch) -{ - TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch)); - - return COMCTL32_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE); -} - -/************************************************************************* - * IntlStrEqWorkerA [COMCTL32.376] - * - * Compare two strings. - * - * PARAMS - * bCase [I] Whether to compare case sensitively - * lpszStr [I] First string to compare - * lpszComp [I] Second string to compare - * iLen [I] Length to compare - * - * RETURNS - * TRUE If the strings are equal. - * FALSE Otherwise. - */ -BOOL WINAPI IntlStrEqWorkerA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp, - int iLen) -{ - DWORD dwFlags = LOCALE_USE_CP_ACP; - int iRet; - - TRACE("(%d,%s,%s,%d)\n", bCase, - debugstr_a(lpszStr), debugstr_a(lpszComp), iLen); - - /* FIXME: These flags are undocumented and unknown by our CompareString. - * We need defines for them. - */ - dwFlags |= bCase ? 0x10000000 : 0x10000001; - - iRet = CompareStringA(GetThreadLocale(), - dwFlags, lpszStr, iLen, lpszComp, iLen); - - if (!iRet) - iRet = CompareStringA(2048, dwFlags, lpszStr, iLen, lpszComp, iLen); - - return iRet == 2 ? TRUE : FALSE; -} - -/************************************************************************* - * IntlStrEqWorkerW [COMCTL32.377] - * - * See IntlStrEqWorkerA. - */ -BOOL WINAPI IntlStrEqWorkerW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp, - int iLen) -{ - DWORD dwFlags; - int iRet; - - TRACE("(%d,%s,%s,%d)\n", bCase, - debugstr_w(lpszStr),debugstr_w(lpszComp), iLen); - - /* FIXME: These flags are undocumented and unknown by our CompareString. - * We need defines for them. - */ - dwFlags = bCase ? 0x10000000 : 0x10000001; - - iRet = CompareStringW(GetThreadLocale(), - dwFlags, lpszStr, iLen, lpszComp, iLen); - - if (!iRet) - iRet = CompareStringW(2048, dwFlags, lpszStr, iLen, lpszComp, iLen); - - return iRet == 2 ? TRUE : FALSE; -} +/* + * String manipulation functions + * + * Copyright 1998 Eric Kohl + * 1998 Juergen Schmied + * 2000 Eric Kohl for CodeWeavers + * Copyright 2002 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include /* atoi */ + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winnls.h" + +#include "wine/unicode.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(commctrl); + +/************************************************************************* + * COMCTL32_ChrCmpHelperA + * + * Internal helper for ChrCmpA/COMCTL32_ChrCmpIA. + * + * NOTES + * Both this function and its Unicode counterpart are very inneficient. To + * fix this, CompareString must be completely implemented and optimised + * first. Then the core character test can be taken out of that function and + * placed here, so that it need never be called at all. Until then, do not + * attempt to optimise this code unless you are willing to test that it + * still performs correctly. + */ +static BOOL COMCTL32_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags) +{ + char str1[3], str2[3]; + + str1[0] = LOBYTE(ch1); + if (IsDBCSLeadByte(str1[0])) + { + str1[1] = HIBYTE(ch1); + str1[2] = '\0'; + } + else + str1[1] = '\0'; + + str2[0] = LOBYTE(ch2); + if (IsDBCSLeadByte(str2[0])) + { + str2[1] = HIBYTE(ch2); + str2[2] = '\0'; + } + else + str2[1] = '\0'; + + return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2; +} + +/************************************************************************* + * COMCTL32_ChrCmpHelperW + * + * Internal helper for COMCTL32_ChrCmpW/ChrCmpIW. + */ +static BOOL COMCTL32_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags) +{ + WCHAR str1[2], str2[2]; + + str1[0] = ch1; + str1[1] = '\0'; + str2[0] = ch2; + str2[1] = '\0'; + return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2; +} + +/************************************************************************* + * COMCTL32_ChrCmpA (internal) + * + * Internal helper function. + */ +static BOOL COMCTL32_ChrCmpA(WORD ch1, WORD ch2) +{ + return COMCTL32_ChrCmpHelperA(ch1, ch2, 0); +} + +/************************************************************************* + * COMCTL32_ChrCmpIA (internal) + * + * Compare two characters, ignoring case. + * + * PARAMS + * ch1 [I] First character to compare + * ch2 [I] Second character to compare + * + * RETURNS + * FALSE, if the characters are equal. + * Non-zero otherwise. + */ +static BOOL COMCTL32_ChrCmpIA(WORD ch1, WORD ch2) +{ + TRACE("(%d,%d)\n", ch1, ch2); + + return COMCTL32_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE); +} + +/************************************************************************* + * COMCTL32_ChrCmpW + * + * Internal helper function. + */ +static BOOL COMCTL32_ChrCmpW(WCHAR ch1, WCHAR ch2) +{ + return COMCTL32_ChrCmpHelperW(ch1, ch2, 0); +} + +/************************************************************************* + * COMCTL32_ChrCmpIW + * + * Internal helper function. + */ +static BOOL COMCTL32_ChrCmpIW(WCHAR ch1, WCHAR ch2) +{ + return COMCTL32_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE); +} + +/************************************************************************** + * StrChrA [COMCTL32.350] + * + * Find a given character in a string. + * + * PARAMS + * lpszStr [I] String to search in. + * ch [I] Character to search for. + * + * RETURNS + * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if + * not found. + * Failure: NULL, if any arguments are invalid. + */ +LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch) +{ + TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch); + + if (lpszStr) + { + while (*lpszStr) + { + if (!COMCTL32_ChrCmpA(*lpszStr, ch)) + return (LPSTR)lpszStr; + lpszStr = CharNextA(lpszStr); + } + } + return NULL; +} + +/************************************************************************* + * COMCTL32_StrStrHelperA + * + * Internal implementation of StrStrA/StrStrIA + */ +static LPSTR COMCTL32_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch, + int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t)) +{ + size_t iLen; + + if (!lpszStr || !lpszSearch || !*lpszSearch) + return NULL; + + iLen = strlen(lpszSearch); + + while (*lpszStr) + { + if (!pStrCmpFn(lpszStr, lpszSearch, iLen)) + return (LPSTR)lpszStr; + lpszStr = CharNextA(lpszStr); + } + return NULL; +} + +/************************************************************************* + * COMCTL32_StrStrHelperW + * + * Internal implementation of StrStrW/StrStrIW + */ +static LPWSTR COMCTL32_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch, + int (*pStrCmpFn)(LPCWSTR,LPCWSTR,int)) +{ + int iLen; + + if (!lpszStr || !lpszSearch || !*lpszSearch) + return NULL; + + iLen = strlenW(lpszSearch); + + while (*lpszStr) + { + if (!pStrCmpFn(lpszStr, lpszSearch, iLen)) + return (LPWSTR)lpszStr; + lpszStr = CharNextW(lpszStr); + } + return NULL; +} + +/************************************************************************** + * StrStrIA [COMCTL32.355] + * + * Find a substring within a string, ignoring case. + * + * PARAMS + * lpszStr [I] String to search in + * lpszSearch [I] String to look for + * + * RETURNS + * The start of lpszSearch within lpszStr, or NULL if not found. + */ +LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch) +{ + TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch)); + + return COMCTL32_StrStrHelperA(lpszStr, lpszSearch, strncasecmp); +} + +/************************************************************************** + * StrToIntA [COMCTL32.357] + * + * Read a signed integer from a string. + * + * PARAMS + * lpszStr [I] String to read integer from + * + * RETURNS + * The signed integer value represented by the string, or 0 if no integer is + * present. + */ +INT WINAPI StrToIntA (LPSTR lpszStr) +{ + return atoi(lpszStr); +} + +/************************************************************************** + * StrStrIW [COMCTL32.363] + * + * See StrStrIA. + */ +LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch) +{ + TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch)); + + return COMCTL32_StrStrHelperW(lpszStr, lpszSearch, (int (*)(LPCWSTR,LPCWSTR,int)) wcsnicmp); +} + +/************************************************************************** + * StrToIntW [COMCTL32.365] + * + * See StrToIntA. + */ +INT WINAPI StrToIntW (LPWSTR lpString) +{ + return atoiW(lpString); +} + +/************************************************************************* + * COMCTL32_StrSpnHelperA (internal) + * + * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA + */ +static int COMCTL32_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch, + LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD), + BOOL bInvert) +{ + LPCSTR lpszRead = lpszStr; + if (lpszStr && *lpszStr && lpszMatch) + { + while (*lpszRead) + { + LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead); + + if (!bInvert && !lpszTest) + break; + if (bInvert && lpszTest) + break; + lpszRead = CharNextA(lpszRead); + }; + } + return lpszRead - lpszStr; +} + +/************************************************************************** + * StrCSpnA [COMCTL32.356] + * + * Find the length of the start of a string that does not contain certain + * characters. + * + * PARAMS + * lpszStr [I] String to search + * lpszMatch [I] Characters that cannot be in the substring + * + * RETURNS + * The length of the part of lpszStr containing only chars not in lpszMatch, + * or 0 if any parameter is invalid. + */ +int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch) +{ + TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); + + return COMCTL32_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE); +} + +/************************************************************************** + * StrChrW [COMCTL32.358] + * + * See StrChrA. + */ +LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch) +{ + LPWSTR lpszRet = NULL; + + TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch); + + if (lpszStr) + lpszRet = strchrW(lpszStr, ch); + return lpszRet; +} + +/************************************************************************** + * StrCmpNA [COMCTL32.352] + * + * Compare two strings, up to a maximum length. + * + * PARAMS + * lpszStr [I] First string to compare + * lpszComp [I] Second string to compare + * iLen [I] Maximum number of chars to compare. + * + * RETURNS + * An integer less than, equal to or greater than 0, indicating that + * lpszStr is less than, the same, or greater than lpszComp. + */ +INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen) +{ + INT iRet; + + TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen); + + iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen); + return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; +} + +/************************************************************************** + * StrCmpNIA [COMCTL32.353] + * + * Compare two strings, up to a maximum length, ignoring case. + * + * PARAMS + * lpszStr [I] First string to compare + * lpszComp [I] Second string to compare + * iLen [I] Maximum number of chars to compare. + * + * RETURNS + * An integer less than, equal to or greater than 0, indicating that + * lpszStr is less than, the same, or greater than lpszComp. + */ +int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen) +{ + INT iRet; + + TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen); + + iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen); + return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; +} + +/************************************************************************* + * StrCmpNIW [COMCTL32.361] + * + * See StrCmpNIA. + */ +INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen) +{ + INT iRet; + + TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen); + + iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen); + return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; +} + +/************************************************************************** + * StrCmpNW [COMCTL32.360] + * + * See StrCmpNA. + */ +INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen) +{ + INT iRet; + + TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen); + + iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen); + return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; +} + +/************************************************************************** + * StrRChrA [COMCTL32.351] + * + * Find the last occurrence of a character in string. + * + * PARAMS + * lpszStr [I] String to search in + * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr + * ch [I] Character to search for. + * + * RETURNS + * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd, + * or NULL if not found. + * Failure: NULL, if any arguments are invalid. + */ +LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch) +{ + LPCSTR lpszRet = NULL; + + TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch); + + if (lpszStr) + { + WORD ch2; + + if (!lpszEnd) + lpszEnd = lpszStr + lstrlenA(lpszStr); + + while (*lpszStr && lpszStr <= lpszEnd) + { + ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr; + + if (!COMCTL32_ChrCmpA(ch, ch2)) + lpszRet = lpszStr; + lpszStr = CharNextA(lpszStr); + } + } + return (LPSTR)lpszRet; +} + + +/************************************************************************** + * StrRChrW [COMCTL32.359] + * + * See StrRChrA. + */ +LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch) +{ + LPCWSTR lpszRet = NULL; + + TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch); + + if (lpszStr) + { + if (!lpszEnd) + lpszEnd = lpszStr + strlenW(lpszStr); + + while (*lpszStr && lpszStr <= lpszEnd) + { + if (!COMCTL32_ChrCmpW(ch, *lpszStr)) + lpszRet = lpszStr; + lpszStr = CharNextW(lpszStr); + } + } + return (LPWSTR)lpszRet; +} + +/************************************************************************** + * StrStrA [COMCTL32.354] + * + * Find a substring within a string. + * + * PARAMS + * lpszStr [I] String to search in + * lpszSearch [I] String to look for + * + * RETURNS + * The start of lpszSearch within lpszStr, or NULL if not found. + */ +LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch) +{ + TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch)); + + return COMCTL32_StrStrHelperA(lpszStr, lpszSearch, strncmp); +} + +/************************************************************************** + * StrStrW [COMCTL32.362] + * + * See StrStrA. + */ +LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch) +{ + TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch)); + + return COMCTL32_StrStrHelperW(lpszStr, lpszSearch, (int (*)(LPCWSTR,LPCWSTR,int)) wcsncmp); +} + +/************************************************************************* + * StrChrIA [COMCTL32.366] + * + * Find a given character in a string, ignoring case. + * + * PARAMS + * lpszStr [I] String to search in. + * ch [I] Character to search for. + * + * RETURNS + * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if + * not found. + * Failure: NULL, if any arguments are invalid. + */ +LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch) +{ + TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch); + + if (lpszStr) + { + while (*lpszStr) + { + if (!COMCTL32_ChrCmpIA(*lpszStr, ch)) + return (LPSTR)lpszStr; + lpszStr = CharNextA(lpszStr); + } + } + return NULL; +} + +/************************************************************************* + * StrChrIW [COMCTL32.367] + * + * See StrChrA. + */ +LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch) +{ + TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch); + + if (lpszStr) + { + ch = toupperW(ch); + while (*lpszStr) + { + if (toupperW(*lpszStr) == ch) + return (LPWSTR)lpszStr; + lpszStr = CharNextW(lpszStr); + } + lpszStr = NULL; + } + return (LPWSTR)lpszStr; +} + +/************************************************************************* + * StrRStrIA [COMCTL32.372] + * + * Find the last occurrence of a substring within a string. + * + * PARAMS + * lpszStr [I] String to search in + * lpszEnd [I] End of lpszStr + * lpszSearch [I] String to look for + * + * RETURNS + * The last occurrence lpszSearch within lpszStr, or NULL if not found. + */ +LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch) +{ + LPSTR lpszRet = NULL; + WORD ch1, ch2; + INT iLen; + + TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch)); + + if (!lpszStr || !lpszSearch || !*lpszSearch) + return NULL; + + if (!lpszEnd) + lpszEnd = lpszStr + lstrlenA(lpszStr); + + if (IsDBCSLeadByte(*lpszSearch)) + ch1 = *lpszSearch << 8 | lpszSearch[1]; + else + ch1 = *lpszSearch; + iLen = lstrlenA(lpszSearch); + + while (lpszStr <= lpszEnd && *lpszStr) + { + ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr; + if (!COMCTL32_ChrCmpIA(ch1, ch2)) + { + if (!StrCmpNIA(lpszStr, lpszSearch, iLen)) + lpszRet = (LPSTR)lpszStr; + } + lpszStr = CharNextA(lpszStr); + } + return lpszRet; +} + +/************************************************************************* + * StrRStrIW [COMCTL32.373] + * + * See StrRStrIA. + */ +LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch) +{ + LPWSTR lpszRet = NULL; + INT iLen; + + TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch)); + + if (!lpszStr || !lpszSearch || !*lpszSearch) + return NULL; + + if (!lpszEnd) + lpszEnd = lpszStr + strlenW(lpszStr); + + iLen = strlenW(lpszSearch); + + while (lpszStr <= lpszEnd && *lpszStr) + { + if (!COMCTL32_ChrCmpIW(*lpszSearch, *lpszStr)) + { + if (!StrCmpNIW(lpszStr, lpszSearch, iLen)) + lpszRet = (LPWSTR)lpszStr; + } + lpszStr = CharNextW(lpszStr); + } + return lpszRet; +} + +/************************************************************************* + * COMCTL32_StrSpnHelperW + * + * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW + */ +static int COMCTL32_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch, + LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR), + BOOL bInvert) +{ + LPCWSTR lpszRead = lpszStr; + if (lpszStr && *lpszStr && lpszMatch) + { + while (*lpszRead) + { + LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead); + + if (!bInvert && !lpszTest) + break; + if (bInvert && lpszTest) + break; + lpszRead = CharNextW(lpszRead); + }; + } + return lpszRead - lpszStr; +} + +/************************************************************************* + * StrCSpnIA [COMCTL32.374] + * + * Find the length of the start of a string that does not contain certain + * characters, ignoring case. + * + * PARAMS + * lpszStr [I] String to search + * lpszMatch [I] Characters that cannot be in the substring + * + * RETURNS + * The length of the part of lpszStr containing only chars not in lpszMatch, + * or 0 if any parameter is invalid. + */ +int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch) +{ + TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); + + return COMCTL32_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE); +} + +/************************************************************************* + * StrCSpnIW [COMCTL32.375] + * + * See StrCSpnIA. + */ +int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch) +{ + TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch)); + + return COMCTL32_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE); +} + +/************************************************************************** + * StrRChrIA [COMCTL32.368] + * + * Find the last occurrence of a character in string, ignoring case. + * + * PARAMS + * lpszStr [I] String to search in + * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr + * ch [I] Character to search for. + * + * RETURNS + * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd, + * or NULL if not found. + * Failure: NULL, if any arguments are invalid. + */ +LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch) +{ + LPCSTR lpszRet = NULL; + + TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch); + + if (lpszStr) + { + WORD ch2; + + if (!lpszEnd) + lpszEnd = lpszStr + lstrlenA(lpszStr); + + while (*lpszStr && lpszStr <= lpszEnd) + { + ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr; + + if (ch == ch2) + lpszRet = lpszStr; + lpszStr = CharNextA(lpszStr); + } + } + return (LPSTR)lpszRet; +} + +/************************************************************************** + * StrRChrIW [COMCTL32.369] + * + * See StrRChrIA. + */ +LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch) +{ + LPCWSTR lpszRet = NULL; + + TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch); + + if (lpszStr) + { + if (!lpszEnd) + lpszEnd = lpszStr + strlenW(lpszStr); + + while (*lpszStr && lpszStr <= lpszEnd) + { + if (ch == *lpszStr) + lpszRet = lpszStr; + lpszStr = CharNextW(lpszStr); + } + } + return (LPWSTR)lpszRet; +} + +/************************************************************************* + * StrCSpnW [COMCTL32.364] + * + * See StrCSpnA. + */ +int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch) +{ + TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch)); + + return COMCTL32_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE); +} + +/************************************************************************* + * IntlStrEqWorkerA [COMCTL32.376] + * + * Compare two strings. + * + * PARAMS + * bCase [I] Whether to compare case sensitively + * lpszStr [I] First string to compare + * lpszComp [I] Second string to compare + * iLen [I] Length to compare + * + * RETURNS + * TRUE If the strings are equal. + * FALSE Otherwise. + */ +BOOL WINAPI IntlStrEqWorkerA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp, + int iLen) +{ + DWORD dwFlags = LOCALE_USE_CP_ACP; + int iRet; + + TRACE("(%d,%s,%s,%d)\n", bCase, + debugstr_a(lpszStr), debugstr_a(lpszComp), iLen); + + /* FIXME: These flags are undocumented and unknown by our CompareString. + * We need defines for them. + */ + dwFlags |= bCase ? 0x10000000 : 0x10000001; + + iRet = CompareStringA(GetThreadLocale(), + dwFlags, lpszStr, iLen, lpszComp, iLen); + + if (!iRet) + iRet = CompareStringA(2048, dwFlags, lpszStr, iLen, lpszComp, iLen); + + return iRet == 2 ? TRUE : FALSE; +} + +/************************************************************************* + * IntlStrEqWorkerW [COMCTL32.377] + * + * See IntlStrEqWorkerA. + */ +BOOL WINAPI IntlStrEqWorkerW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp, + int iLen) +{ + DWORD dwFlags; + int iRet; + + TRACE("(%d,%s,%s,%d)\n", bCase, + debugstr_w(lpszStr),debugstr_w(lpszComp), iLen); + + /* FIXME: These flags are undocumented and unknown by our CompareString. + * We need defines for them. + */ + dwFlags = bCase ? 0x10000000 : 0x10000001; + + iRet = CompareStringW(GetThreadLocale(), + dwFlags, lpszStr, iLen, lpszComp, iLen); + + if (!iRet) + iRet = CompareStringW(2048, dwFlags, lpszStr, iLen, lpszComp, iLen); + + return iRet == 2 ? TRUE : FALSE; +} diff --git a/reactos/lib/comctl32/syslink.c b/reactos/lib/comctl32/syslink.c index e39332d0119..12a06055648 100644 --- a/reactos/lib/comctl32/syslink.c +++ b/reactos/lib/comctl32/syslink.c @@ -1,1690 +1,1690 @@ -/* - * SysLink control - * - * Copyright 2004 Thomas Weidenmueller - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTES - * - * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on Apr. 4, 2005, by Dimitrie O. Paun. - * - * Unless otherwise noted, we believe this code to be complete, as per - * the specification mentioned above. - * If you discover missing features, or bugs, please note them below. - * - * TODO: - * - Fix SHIFT+TAB and TAB issue (wrong link is selected when control gets the focus) - * - Better string parsing - * - Improve word wrapping - * - */ - -#include -#include -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "comctl32.h" -#include "wine/unicode.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(progress); - -INT WINAPI StrCmpNIW(LPCWSTR,LPCWSTR,INT); - -typedef struct -{ - int nChars; - RECT rc; -} DOC_TEXTBLOCK, *PDOC_TEXTBLOCK; - -#define LIF_FLAGSMASK (LIF_STATE | LIF_ITEMID | LIF_URL) -#define LIS_MASK (LIS_FOCUSED | LIS_ENABLED | LIS_VISITED) - -typedef enum -{ - slText = 0, - slLink -} SL_ITEM_TYPE; - -typedef struct _DOC_ITEM -{ - struct _DOC_ITEM *Next; /* Address to the next item */ - LPWSTR Text; /* Text of the document item */ - UINT nText; /* Number of characters of the text */ - SL_ITEM_TYPE Type; /* type of the item */ - PDOC_TEXTBLOCK Blocks; /* Array of text blocks */ - union - { - struct - { - UINT state; /* Link state */ - WCHAR *szID; /* Link ID string */ - WCHAR *szUrl; /* Link URL string */ - HRGN hRgn; /* Region of the link */ - } Link; - struct - { - UINT Dummy; - } Text; - } u; -} DOC_ITEM, *PDOC_ITEM; - -typedef struct -{ - HWND Self; /* The window handle for this control */ - HWND Notify; /* The parent handle to receive notifications */ - DWORD Style; /* Styles for this control */ - PDOC_ITEM Items; /* Address to the first document item */ - BOOL HasFocus; /* Whether the control has the input focus */ - int MouseDownID; /* ID of the link that the mouse button first selected */ - HFONT Font; /* Handle to the font for text */ - HFONT LinkFont; /* Handle to the font for links */ - COLORREF TextColor; /* Color of the text */ - COLORREF LinkColor; /* Color of links */ - COLORREF VisitedColor; /* Color of visited links */ -} SYSLINK_INFO; - -static const WCHAR SL_LINKOPEN[] = { '<','a', 0 }; -static const WCHAR SL_HREF[] = { 'h','r','e','f','=','\"',0 }; -static const WCHAR SL_ID[] = { 'i','d','=','\"',0 }; -static const WCHAR SL_LINKCLOSE[] = { '<','/','a','>',0 }; - -/* Control configuration constants */ - -#define SL_LEFTMARGIN (0) -#define SL_TOPMARGIN (0) -#define SL_RIGHTMARGIN (0) -#define SL_BOTTOMMARGIN (0) - -/*********************************************************************** - * SYSLINK_FreeDocItem - * Frees all data and gdi objects associated with a document item - */ -static VOID SYSLINK_FreeDocItem (PDOC_ITEM DocItem) -{ - if(DocItem->Type == slLink) - { - Free(DocItem->u.Link.szID); - Free(DocItem->u.Link.szUrl); - } - - if(DocItem->Type == slLink && DocItem->u.Link.hRgn != NULL) - { - DeleteObject(DocItem->u.Link.hRgn); - } - - /* we don't free Text because it's just a pointer to a character in the - entire window text string */ - - Free(DocItem); -} - -/*********************************************************************** - * SYSLINK_AppendDocItem - * Create and append a new document item. - */ -static PDOC_ITEM SYSLINK_AppendDocItem (SYSLINK_INFO *infoPtr, LPCWSTR Text, UINT textlen, - SL_ITEM_TYPE type, PDOC_ITEM LastItem) -{ - PDOC_ITEM Item; - Item = Alloc(sizeof(DOC_ITEM) + ((textlen + 1) * sizeof(WCHAR))); - if(Item == NULL) - { - ERR("Failed to alloc DOC_ITEM structure!\n"); - return NULL; - } - textlen = min(textlen, lstrlenW(Text)); - - Item->Next = NULL; - Item->Text = (LPWSTR)(Item + 1); - Item->nText = textlen; - Item->Type = type; - Item->Blocks = NULL; - - if(LastItem != NULL) - { - LastItem->Next = Item; - } - else - { - infoPtr->Items = Item; - } - - lstrcpynW(Item->Text, Text, textlen + 1); - Item->Text[textlen] = 0; - - return Item; -} - -/*********************************************************************** - * SYSLINK_ClearDoc - * Clears the document tree - */ -static VOID SYSLINK_ClearDoc (SYSLINK_INFO *infoPtr) -{ - PDOC_ITEM Item, Next; - - Item = infoPtr->Items; - while(Item != NULL) - { - Next = Item->Next; - SYSLINK_FreeDocItem(Item); - Item = Next; - } - - infoPtr->Items = NULL; -} - -/*********************************************************************** - * SYSLINK_ParseText - * Parses the window text string and creates a document. Returns the - * number of document items created. - */ -static UINT SYSLINK_ParseText (SYSLINK_INFO *infoPtr, LPCWSTR Text) -{ - LPCWSTR current, textstart = NULL, linktext = NULL, firsttag = NULL; - int taglen = 0, textlen = 0, linklen = 0, docitems = 0; - PDOC_ITEM Last = NULL; - SL_ITEM_TYPE CurrentType = slText; - LPCWSTR lpID, lpUrl; - UINT lenId, lenUrl; - - for(current = Text; *current != 0;) - { - if(*current == '<') - { - if(!StrCmpNIW(current, SL_LINKOPEN, 2) && (CurrentType == slText)) - { - BOOL ValidParam = FALSE, ValidLink = FALSE; - - switch (*(current + 2)) - { - case '>': - /* we just have to deal with a tag */ - taglen = 3; - ValidLink = TRUE; - ValidParam = TRUE; - firsttag = current; - linklen = 0; - lpID = NULL; - lpUrl = NULL; - break; - case ' ': - { - /* we expect parameters, parse them */ - LPCWSTR *CurrentParameter = NULL, tmp; - UINT *CurrentParameterLen = NULL; - - taglen = 3; - tmp = current + taglen; - lpID = NULL; - lpUrl = NULL; - -CheckParameter: - /* compare the current position with all known parameters */ - if(!StrCmpNIW(tmp, SL_HREF, 6)) - { - taglen += 6; - ValidParam = TRUE; - CurrentParameter = &lpUrl; - CurrentParameterLen = &lenUrl; - } - else if(!StrCmpNIW(tmp, SL_ID, 4)) - { - taglen += 4; - ValidParam = TRUE; - CurrentParameter = &lpID; - CurrentParameterLen = &lenId; - } - else - { - ValidParam = FALSE; - } - - if(ValidParam) - { - /* we got a known parameter, now search until the next " character. - If we can't find a " character, there's a syntax error and we just assume it's text */ - ValidParam = FALSE; - *CurrentParameter = current + taglen; - *CurrentParameterLen = 0; - - for(tmp = *CurrentParameter; *tmp != 0; tmp++) - { - taglen++; - if(*tmp == '\"') - { - ValidParam = TRUE; - tmp++; - break; - } - (*CurrentParameterLen)++; - } - } - if(ValidParam) - { - /* we're done with this parameter, now there are only 2 possibilities: - * 1. another parameter is coming, so expect a ' ' (space) character - * 2. the tag is being closed, so expect a '<' character - */ - switch(*tmp) - { - case ' ': - /* we expect another parameter, do the whole thing again */ - taglen++; - tmp++; - goto CheckParameter; - - case '>': - /* the tag is being closed, we're done */ - ValidLink = TRUE; - taglen++; - break; - default: - tmp++; - break; - } - } - - break; - } - } - - if(ValidLink && ValidParam) - { - /* the tag appears to be valid. save all information - so we can add the link if we find a valid tag later */ - CurrentType = slLink; - linktext = current + taglen; - linklen = 0; - firsttag = current; - } - else - { - taglen = 1; - lpID = NULL; - lpUrl = NULL; - if(textstart == NULL) - { - textstart = current; - } - } - } - else if(!StrCmpNIW(current, SL_LINKCLOSE, 4) && (CurrentType == slLink) && firsttag) - { - /* there's a tag opened, first add the previous text, if present */ - if(textstart != NULL && textlen > 0 && firsttag > textstart) - { - Last = SYSLINK_AppendDocItem(infoPtr, textstart, firsttag - textstart, slText, Last); - if(Last == NULL) - { - ERR("Unable to create new document item!\n"); - return docitems; - } - docitems++; - textstart = NULL; - textlen = 0; - } - - /* now it's time to add the link to the document */ - current += 4; - if(linktext != NULL && linklen > 0) - { - Last = SYSLINK_AppendDocItem(infoPtr, linktext, linklen, slLink, Last); - if(Last == NULL) - { - ERR("Unable to create new document item!\n"); - return docitems; - } - docitems++; - if(CurrentType == slLink) - { - int nc; - - if(!(infoPtr->Style & WS_DISABLED)) - { - Last->u.Link.state |= LIS_ENABLED; - } - /* Copy the tag parameters */ - if(lpID != NULL) - { - nc = min(lenId, strlenW(lpID)); - nc = min(nc, MAX_LINKID_TEXT); - Last->u.Link.szID = Alloc((MAX_LINKID_TEXT + 1) * sizeof(WCHAR)); - if(Last->u.Link.szID != NULL) - { - lstrcpynW(Last->u.Link.szID, lpID, nc + 1); - Last->u.Link.szID[nc] = 0; - } - } - else - Last->u.Link.szID = NULL; - if(lpUrl != NULL) - { - nc = min(lenUrl, strlenW(lpUrl)); - nc = min(nc, L_MAX_URL_LENGTH); - Last->u.Link.szUrl = Alloc((L_MAX_URL_LENGTH + 1) * sizeof(WCHAR)); - if(Last->u.Link.szUrl != NULL) - { - lstrcpynW(Last->u.Link.szUrl, lpUrl, nc + 1); - Last->u.Link.szUrl[nc] = 0; - } - } - else - Last->u.Link.szUrl = NULL; - } - linktext = NULL; - } - CurrentType = slText; - firsttag = NULL; - textstart = NULL; - continue; - } - else - { - /* we don't know what tag it is, so just continue */ - taglen = 1; - linklen++; - if(CurrentType == slText && textstart == NULL) - { - textstart = current; - } - } - - textlen += taglen; - current += taglen; - } - else - { - textlen++; - linklen++; - - /* save the pointer of the current text item if we couldn't find a tag */ - if(textstart == NULL && CurrentType == slText) - { - textstart = current; - } - - current++; - } - } - - if(textstart != NULL && textlen > 0) - { - Last = SYSLINK_AppendDocItem(infoPtr, textstart, textlen, CurrentType, Last); - if(Last == NULL) - { - ERR("Unable to create new document item!\n"); - return docitems; - } - if(CurrentType == slLink) - { - int nc; - - if(!(infoPtr->Style & WS_DISABLED)) - { - Last->u.Link.state |= LIS_ENABLED; - } - /* Copy the tag parameters */ - if(lpID != NULL) - { - nc = min(lenId, strlenW(lpID)); - nc = min(nc, MAX_LINKID_TEXT); - Last->u.Link.szID = Alloc((MAX_LINKID_TEXT + 1) * sizeof(WCHAR)); - if(Last->u.Link.szID != NULL) - { - lstrcpynW(Last->u.Link.szID, lpID, nc + 1); - Last->u.Link.szID[nc] = 0; - } - } - else - Last->u.Link.szID = NULL; - if(lpUrl != NULL) - { - nc = min(lenUrl, strlenW(lpUrl)); - nc = min(nc, L_MAX_URL_LENGTH); - Last->u.Link.szUrl = Alloc((L_MAX_URL_LENGTH + 1) * sizeof(WCHAR)); - if(Last->u.Link.szUrl != NULL) - { - lstrcpynW(Last->u.Link.szUrl, lpUrl, nc + 1); - Last->u.Link.szUrl[nc] = 0; - } - } - else - Last->u.Link.szUrl = NULL; - } - docitems++; - } - - if(linktext != NULL && linklen > 0) - { - /* we got an unclosed link, just display the text */ - Last = SYSLINK_AppendDocItem(infoPtr, linktext, linklen, slText, Last); - if(Last == NULL) - { - ERR("Unable to create new document item!\n"); - return docitems; - } - docitems++; - } - - return docitems; -} - -/*********************************************************************** - * SYSLINK_RepaintLink - * Repaints a link. - */ -static VOID SYSLINK_RepaintLink (SYSLINK_INFO *infoPtr, PDOC_ITEM DocItem) -{ - if(DocItem->Type != slLink) - { - ERR("DocItem not a link!\n"); - return; - } - - if(DocItem->u.Link.hRgn != NULL) - { - /* repaint the region */ - RedrawWindow(infoPtr->Self, NULL, DocItem->u.Link.hRgn, RDW_INVALIDATE | RDW_UPDATENOW); - } -} - -/*********************************************************************** - * SYSLINK_GetLinkItemByIndex - * Retrieves a document link by its index - */ -static PDOC_ITEM SYSLINK_GetLinkItemByIndex (SYSLINK_INFO *infoPtr, int iLink) -{ - PDOC_ITEM Current = infoPtr->Items; - - while(Current != NULL) - { - if((Current->Type == slLink) && (iLink-- <= 0)) - { - return Current; - } - Current = Current->Next; - } - return NULL; -} - -/*********************************************************************** - * SYSLINK_GetFocusLink - * Retrieves the link that has the LIS_FOCUSED bit - */ -static PDOC_ITEM SYSLINK_GetFocusLink (SYSLINK_INFO *infoPtr, int *LinkId) -{ - PDOC_ITEM Current = infoPtr->Items; - int id = 0; - - while(Current != NULL) - { - if((Current->Type == slLink)) - { - if(Current->u.Link.state & LIS_FOCUSED) - { - if(LinkId != NULL) - *LinkId = id; - return Current; - } - id++; - } - Current = Current->Next; - } - return NULL; -} - -/*********************************************************************** - * SYSLINK_GetNextLink - * Gets the next link - */ -static PDOC_ITEM SYSLINK_GetNextLink (SYSLINK_INFO *infoPtr, PDOC_ITEM Current) -{ - for(Current = (Current != NULL ? Current->Next : infoPtr->Items); - Current != NULL; - Current = Current->Next) - { - if(Current->Type == slLink) - { - return Current; - } - } - return NULL; -} - -/*********************************************************************** - * SYSLINK_GetPrevLink - * Gets the previous link - */ -static PDOC_ITEM SYSLINK_GetPrevLink (SYSLINK_INFO *infoPtr, PDOC_ITEM Current) -{ - if(Current == NULL) - { - /* returns the last link */ - PDOC_ITEM Last = NULL; - - for(Current = infoPtr->Items; Current != NULL; Current = Current->Next) - { - if(Current->Type == slLink) - { - Last = Current; - } - } - return Last; - } - else - { - /* returns the previous link */ - PDOC_ITEM Cur, Prev = NULL; - - for(Cur = infoPtr->Items; Cur != NULL; Cur = Cur->Next) - { - if(Cur == Current) - { - break; - } - if(Cur->Type == slLink) - { - Prev = Cur; - } - } - return Prev; - } -} - -/*********************************************************************** - * SYSLINK_WrapLine - * Tries to wrap a line. - */ -static BOOL SYSLINK_WrapLine (HDC hdc, LPWSTR Text, WCHAR BreakChar, int *LineLen, int nFit, LPSIZE Extent, int Width) -{ - WCHAR *Current; - - if(nFit == *LineLen) - { - return FALSE; - } - - *LineLen = nFit; - - Current = Text + nFit; - - /* check if we're in the middle of a word */ - if((*Current) != BreakChar) - { - /* search for the beginning of the word */ - while(Current > Text && (*(Current - 1)) != BreakChar) - { - Current--; - (*LineLen)--; - } - - if((*LineLen) == 0) - { - Extent->cx = 0; - Extent->cy = 0; - } - return TRUE; - } - - return TRUE; -} - -/*********************************************************************** - * SYSLINK_Render - * Renders the document in memory - */ -static VOID SYSLINK_Render (SYSLINK_INFO *infoPtr, HDC hdc) -{ - RECT rc; - PDOC_ITEM Current; - HGDIOBJ hOldFont; - int x, y, LineHeight; - TEXTMETRICW tm; - - GetClientRect(infoPtr->Self, &rc); - rc.right -= SL_RIGHTMARGIN; - rc.bottom -= SL_BOTTOMMARGIN; - - if(rc.right - SL_LEFTMARGIN < 0 || rc.bottom - SL_TOPMARGIN < 0) return; - - hOldFont = SelectObject(hdc, infoPtr->Font); - GetTextMetricsW(hdc, &tm); - - x = SL_LEFTMARGIN; - y = SL_TOPMARGIN; - LineHeight = 0; - - for(Current = infoPtr->Items; Current != NULL; Current = Current->Next) - { - int n, nBlocks; - LPWSTR tx; - PDOC_TEXTBLOCK bl, cbl; - INT nFit; - SIZE szDim; - - if(Current->nText == 0) - { - ERR("DOC_ITEM with no text?!\n"); - continue; - } - - tx = Current->Text; - n = Current->nText; - bl = Current->Blocks; - nBlocks = 0; - - if(Current->Type == slText) - { - SelectObject(hdc, infoPtr->Font); - } - else if(Current->Type == slLink) - { - SelectObject(hdc, infoPtr->LinkFont); - } - - while(n > 0) - { - if(GetTextExtentExPointW(hdc, tx, n, rc.right - x, &nFit, NULL, &szDim)) - { - int LineLen = n; - BOOL Wrap = SYSLINK_WrapLine(hdc, tx, tm.tmBreakChar, &LineLen, nFit, &szDim, rc.right - x); - - if(LineLen == 0) - { - if(x > SL_LEFTMARGIN) - { - /* move one line down, the word didn't fit into the line */ - x = SL_LEFTMARGIN; - y += LineHeight; - LineHeight = 0; - continue; - } - else - { - /* the word starts at the beginning of the line and doesn't - fit into the line, so break it at the last character that fits */ - LineLen = max(nFit, 1); - } - } - - if(LineLen != n) - { - GetTextExtentExPointW(hdc, tx, LineLen, rc.right - x, NULL, NULL, &szDim); - } - - if(bl != NULL) - { - bl = ReAlloc(bl, ++nBlocks * sizeof(DOC_TEXTBLOCK)); - } - else - { - bl = Alloc(++nBlocks * sizeof(DOC_TEXTBLOCK)); - } - - if(bl != NULL) - { - cbl = bl + nBlocks - 1; - - cbl->nChars = LineLen; - cbl->rc.left = x; - cbl->rc.top = y; - cbl->rc.right = x + szDim.cx; - cbl->rc.bottom = y + szDim.cy; - - x += szDim.cx; - LineHeight = max(LineHeight, szDim.cy); - - /* (re)calculate the link's region */ - if(Current->Type == slLink) - { - if(nBlocks <= 1) - { - if(Current->u.Link.hRgn != NULL) - { - DeleteObject(Current->u.Link.hRgn); - } - /* initialize the link's hRgn */ - Current->u.Link.hRgn = CreateRectRgnIndirect(&cbl->rc); - } - else if(Current->u.Link.hRgn != NULL) - { - HRGN hrgn; - hrgn = CreateRectRgnIndirect(&cbl->rc); - /* add the rectangle */ - CombineRgn(Current->u.Link.hRgn, Current->u.Link.hRgn, hrgn, RGN_OR); - DeleteObject(hrgn); - } - } - - if(Wrap) - { - x = SL_LEFTMARGIN; - y += LineHeight; - LineHeight = 0; - } - } - else - { - ERR("Failed to alloc DOC_TEXTBLOCK structure!\n"); - break; - } - n -= LineLen; - tx += LineLen; - } - else - { - ERR("GetTextExtentExPoint() failed?!\n"); - n--; - } - } - Current->Blocks = bl; - } - - SelectObject(hdc, hOldFont); -} - -/*********************************************************************** - * SYSLINK_Draw - * Draws the SysLink control. - */ -static LRESULT SYSLINK_Draw (SYSLINK_INFO *infoPtr, HDC hdc) -{ - RECT rc; - PDOC_ITEM Current; - HFONT hOldFont; - COLORREF OldTextColor, OldBkColor; - - hOldFont = SelectObject(hdc, infoPtr->Font); - OldTextColor = SetTextColor(hdc, infoPtr->TextColor); - OldBkColor = SetBkColor(hdc, GetSysColor(COLOR_BTNFACE)); - - GetClientRect(infoPtr->Self, &rc); - rc.right -= SL_RIGHTMARGIN + SL_LEFTMARGIN; - rc.bottom -= SL_BOTTOMMARGIN + SL_TOPMARGIN; - - if(rc.right < 0 || rc.bottom < 0) return 0; - - for(Current = infoPtr->Items; Current != NULL; Current = Current->Next) - { - int n; - LPWSTR tx; - PDOC_TEXTBLOCK bl; - - bl = Current->Blocks; - if(bl != NULL) - { - tx = Current->Text; - n = Current->nText; - - if(Current->Type == slText) - { - SelectObject(hdc, infoPtr->Font); - SetTextColor(hdc, infoPtr->TextColor); - } - else - { - SelectObject(hdc, infoPtr->LinkFont); - SetTextColor(hdc, (!(Current->u.Link.state & LIS_VISITED) ? infoPtr->LinkColor : infoPtr->VisitedColor)); - } - - while(n > 0) - { - ExtTextOutW(hdc, bl->rc.left, bl->rc.top, ETO_OPAQUE | ETO_CLIPPED, &bl->rc, tx, bl->nChars, NULL); - if((Current->Type == slLink) && (Current->u.Link.state & LIS_FOCUSED) && infoPtr->HasFocus) - { - COLORREF PrevColor; - PrevColor = SetBkColor(hdc, OldBkColor); - DrawFocusRect(hdc, &bl->rc); - SetBkColor(hdc, PrevColor); - } - tx += bl->nChars; - n -= bl->nChars; - bl++; - } - } - } - - SetBkColor(hdc, OldBkColor); - SetTextColor(hdc, OldTextColor); - SelectObject(hdc, hOldFont); - - return 0; -} - - -/*********************************************************************** - * SYSLINK_Paint - * Handles the WM_PAINT message. - */ -static LRESULT SYSLINK_Paint (SYSLINK_INFO *infoPtr, HDC hdcParam) -{ - HDC hdc; - PAINTSTRUCT ps; - - hdc = hdcParam ? hdcParam : BeginPaint (infoPtr->Self, &ps); - SYSLINK_Draw (infoPtr, hdc); - if (!hdcParam) EndPaint (infoPtr->Self, &ps); - return 0; -} - - -/*********************************************************************** - * SYSLINK_SetFont - * Set new Font for the SysLink control. - */ -static HFONT SYSLINK_SetFont (SYSLINK_INFO *infoPtr, HFONT hFont, BOOL bRedraw) -{ - HDC hdc; - LOGFONTW lf; - HFONT hOldFont = infoPtr->Font; - infoPtr->Font = hFont; - - /* free the underline font */ - if(infoPtr->LinkFont != NULL) - { - DeleteObject(infoPtr->LinkFont); - infoPtr->LinkFont = NULL; - } - - /* Render text position and word wrapping in memory */ - hdc = GetDC(infoPtr->Self); - if(hdc != NULL) - { - /* create a new underline font */ - if(GetObjectW(infoPtr->Font, sizeof(LOGFONTW), &lf)) - { - lf.lfUnderline = TRUE; - infoPtr->LinkFont = CreateFontIndirectW(&lf); - } - else - { - ERR("Failed to create link font!\n"); - } - - SYSLINK_Render(infoPtr, hdc); - ReleaseDC(infoPtr->Self, hdc); - } - - if(bRedraw) - { - RedrawWindow(infoPtr->Self, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); - } - - return hOldFont; -} - -/*********************************************************************** - * SYSLINK_SetText - * Set new text for the SysLink control. - */ -static LRESULT SYSLINK_SetText (SYSLINK_INFO *infoPtr, LPCWSTR Text) -{ - int textlen; - - /* clear the document */ - SYSLINK_ClearDoc(infoPtr); - - textlen = lstrlenW(Text); - if(Text == NULL || textlen == 0) - { - return TRUE; - } - - /* let's parse the string and create a document */ - if(SYSLINK_ParseText(infoPtr, Text) > 0) - { - /* Render text position and word wrapping in memory */ - HDC hdc = GetDC(infoPtr->Self); - SYSLINK_Render(infoPtr, hdc); - SYSLINK_Draw(infoPtr, hdc); - ReleaseDC(infoPtr->Self, hdc); - } - - return TRUE; -} - -/*********************************************************************** - * SYSLINK_SetFocusLink - * Updates the focus status bits and focusses the specified link. - * If no document item is specified, the focus bit will be removed from all links. - * Returns the previous focused item. - */ -static PDOC_ITEM SYSLINK_SetFocusLink (SYSLINK_INFO *infoPtr, PDOC_ITEM DocItem) -{ - PDOC_ITEM Current, PrevFocus = NULL; - - for(Current = infoPtr->Items; Current != NULL; Current = Current->Next) - { - if(Current->Type == slLink) - { - if((PrevFocus == NULL) && (Current->u.Link.state & LIS_FOCUSED)) - { - PrevFocus = Current; - } - - if(Current == DocItem) - { - Current->u.Link.state |= LIS_FOCUSED; - } - else - { - Current->u.Link.state &= ~LIS_FOCUSED; - } - } - } - - return PrevFocus; -} - -/*********************************************************************** - * SYSLINK_SetItem - * Sets the states and attributes of a link item. - */ -static LRESULT SYSLINK_SetItem (SYSLINK_INFO *infoPtr, PLITEM Item) -{ - PDOC_ITEM di; - BOOL Repaint = FALSE; - BOOL Ret = TRUE; - - if(!(Item->mask & LIF_ITEMINDEX) || !(Item->mask & (LIF_FLAGSMASK))) - { - ERR("Invalid Flags!\n"); - return FALSE; - } - - di = SYSLINK_GetLinkItemByIndex(infoPtr, Item->iLink); - if(di == NULL) - { - ERR("Link %d couldn't be found\n", Item->iLink); - return FALSE; - } - - if(Item->mask & LIF_STATE) - { - UINT oldstate = di->u.Link.state; - /* clear the masked bits */ - di->u.Link.state &= ~(Item->stateMask & LIS_MASK); - /* copy the bits */ - di->u.Link.state |= (Item->state & Item->stateMask) & LIS_MASK; - Repaint = (oldstate != di->u.Link.state); - - /* update the focus */ - SYSLINK_SetFocusLink(infoPtr, ((di->u.Link.state & LIS_FOCUSED) ? di : NULL)); - } - - if(Item->mask & LIF_ITEMID) - { - if(!di->u.Link.szID) - { - di->u.Link.szID = Alloc((MAX_LINKID_TEXT + 1) * sizeof(WCHAR)); - if(!Item->szID) - { - ERR("Unable to allocate memory for link id\n"); - Ret = FALSE; - } - } - if(di->u.Link.szID) - { - lstrcpynW(di->u.Link.szID, Item->szID, MAX_LINKID_TEXT + 1); - } - } - - if(Item->mask & LIF_URL) - { - if(!di->u.Link.szUrl) - { - di->u.Link.szUrl = Alloc((MAX_LINKID_TEXT + 1) * sizeof(WCHAR)); - if(!Item->szUrl) - { - ERR("Unable to allocate memory for link url\n"); - Ret = FALSE; - } - } - if(di->u.Link.szUrl) - { - lstrcpynW(di->u.Link.szUrl, Item->szUrl, MAX_LINKID_TEXT + 1); - } - } - - if(Repaint) - { - SYSLINK_RepaintLink(infoPtr, di); - } - - return Ret; -} - -/*********************************************************************** - * SYSLINK_GetItem - * Retrieves the states and attributes of a link item. - */ -static LRESULT SYSLINK_GetItem (SYSLINK_INFO *infoPtr, PLITEM Item) -{ - PDOC_ITEM di; - - if(!(Item->mask & LIF_ITEMINDEX) || !(Item->mask & (LIF_FLAGSMASK))) - { - ERR("Invalid Flags!\n"); - return FALSE; - } - - di = SYSLINK_GetLinkItemByIndex(infoPtr, Item->iLink); - if(di == NULL) - { - ERR("Link %d couldn't be found\n", Item->iLink); - return FALSE; - } - - if(Item->mask & LIF_STATE) - { - Item->state = (di->u.Link.state & Item->stateMask); - if(!infoPtr->HasFocus) - { - /* remove the LIS_FOCUSED bit if the control doesn't have focus */ - Item->state &= ~LIS_FOCUSED; - } - } - - if(Item->mask & LIF_ITEMID) - { - if(di->u.Link.szID) - { - lstrcpynW(Item->szID, di->u.Link.szID, MAX_LINKID_TEXT + 1); - } - else - { - Item->szID[0] = 0; - } - } - - if(Item->mask & LIF_URL) - { - if(di->u.Link.szUrl) - { - lstrcpynW(Item->szUrl, di->u.Link.szUrl, L_MAX_URL_LENGTH + 1); - } - else - { - Item->szUrl[0] = 0; - } - } - - return TRUE; -} - -/*********************************************************************** - * SYSLINK_HitTest - * Determines the link the user clicked on. - */ -static LRESULT SYSLINK_HitTest (SYSLINK_INFO *infoPtr, PLHITTESTINFO HitTest) -{ - PDOC_ITEM Current; - int id = 0; - - for(Current = infoPtr->Items; Current != NULL; Current = Current->Next) - { - if(Current->Type == slLink) - { - if((Current->u.Link.hRgn != NULL) && - PtInRegion(Current->u.Link.hRgn, HitTest->pt.x, HitTest->pt.y)) - { - HitTest->item.mask = 0; - HitTest->item.iLink = id; - HitTest->item.state = 0; - HitTest->item.stateMask = 0; - if(Current->u.Link.szID) - { - lstrcpynW(HitTest->item.szID, Current->u.Link.szID, MAX_LINKID_TEXT + 1); - } - else - { - HitTest->item.szID[0] = 0; - } - if(Current->u.Link.szUrl) - { - lstrcpynW(HitTest->item.szUrl, Current->u.Link.szUrl, L_MAX_URL_LENGTH + 1); - } - else - { - HitTest->item.szUrl[0] = 0; - } - return TRUE; - } - id++; - } - } - - return FALSE; -} - -/*********************************************************************** - * SYSLINK_GetIdealHeight - * Returns the preferred height of a link at the current control's width. - */ -static LRESULT SYSLINK_GetIdealHeight (SYSLINK_INFO *infoPtr) -{ - HDC hdc = GetDC(infoPtr->Self); - if(hdc != NULL) - { - LRESULT height; - TEXTMETRICW tm; - HGDIOBJ hOldFont = SelectObject(hdc, infoPtr->Font); - - if(GetTextMetricsW(hdc, &tm)) - { - height = tm.tmHeight; - } - else - { - height = 0; - } - SelectObject(hdc, hOldFont); - ReleaseDC(infoPtr->Self, hdc); - - return height; - } - return 0; -} - -/*********************************************************************** - * SYSLINK_SendParentNotify - * Sends a WM_NOTIFY message to the parent window. - */ -static LRESULT SYSLINK_SendParentNotify (SYSLINK_INFO *infoPtr, UINT code, PDOC_ITEM Link, int iLink) -{ - NMLINK nml; - - nml.hdr.hwndFrom = infoPtr->Self; - nml.hdr.idFrom = GetWindowLongPtrW(infoPtr->Self, GWLP_ID); - nml.hdr.code = code; - - nml.item.mask = 0; - nml.item.iLink = iLink; - nml.item.state = 0; - nml.item.stateMask = 0; - if(Link->u.Link.szID) - { - lstrcpynW(nml.item.szID, Link->u.Link.szID, MAX_LINKID_TEXT + 1); - } - else - { - nml.item.szID[0] = 0; - } - if(Link->u.Link.szUrl) - { - lstrcpynW(nml.item.szUrl, Link->u.Link.szUrl, L_MAX_URL_LENGTH + 1); - } - else - { - nml.item.szUrl[0] = 0; - } - - return SendMessageW(infoPtr->Notify, WM_NOTIFY, (WPARAM)nml.hdr.idFrom, (LPARAM)&nml); -} - -/*********************************************************************** - * SYSLINK_SetFocus - * Handles receiving the input focus. - */ -static LRESULT SYSLINK_SetFocus (SYSLINK_INFO *infoPtr, HWND PrevFocusWindow) -{ - PDOC_ITEM Focus; - - infoPtr->HasFocus = TRUE; - -#if 1 - /* FIXME - How to detect whether SHIFT+TAB or just TAB has been pressed? - * The problem is we could get this message without keyboard input, too - */ - Focus = SYSLINK_GetFocusLink(infoPtr, NULL); - - if(Focus == NULL && (Focus = SYSLINK_GetNextLink(infoPtr, NULL))) - { - SYSLINK_SetFocusLink(infoPtr, Focus); - } -#else - /* This is a temporary hack since I'm not really sure how to detect which link to select. - See message above! */ - Focus = SYSLINK_GetNextLink(infoPtr, NULL); - if(Focus != NULL) - { - SYSLINK_SetFocusLink(infoPtr, Focus); - } -#endif - - SYSLINK_RepaintLink(infoPtr, Focus); - - return 0; -} - -/*********************************************************************** - * SYSLINK_KillFocus - * Handles losing the input focus. - */ -static LRESULT SYSLINK_KillFocus (SYSLINK_INFO *infoPtr, HWND NewFocusWindow) -{ - PDOC_ITEM Focus; - - infoPtr->HasFocus = FALSE; - Focus = SYSLINK_GetFocusLink(infoPtr, NULL); - - if(Focus != NULL) - { - SYSLINK_RepaintLink(infoPtr, Focus); - } - - return 0; -} - -/*********************************************************************** - * SYSLINK_LinkAtPt - * Returns a link at the specified position - */ -static PDOC_ITEM SYSLINK_LinkAtPt (SYSLINK_INFO *infoPtr, POINT *pt, int *LinkId, BOOL MustBeEnabled) -{ - PDOC_ITEM Current; - int id = 0; - - for(Current = infoPtr->Items; Current != NULL; Current = Current->Next) - { - if((Current->Type == slLink) && (Current->u.Link.hRgn != NULL) && - PtInRegion(Current->u.Link.hRgn, pt->x, pt->y) && - (!MustBeEnabled || (MustBeEnabled && (Current->u.Link.state & LIS_ENABLED)))) - { - if(LinkId != NULL) - { - *LinkId = id; - } - return Current; - } - id++; - } - - return NULL; -} - -/*********************************************************************** - * SYSLINK_LButtonDown - * Handles mouse clicks - */ -static LRESULT SYSLINK_LButtonDown (SYSLINK_INFO *infoPtr, DWORD Buttons, POINT *pt) -{ - PDOC_ITEM Current, Old; - int id; - - Current = SYSLINK_LinkAtPt(infoPtr, pt, &id, TRUE); - if(Current != NULL) - { - Old = SYSLINK_SetFocusLink(infoPtr, Current); - if(Old != NULL && Old != Current) - { - SYSLINK_RepaintLink(infoPtr, Old); - } - infoPtr->MouseDownID = id; - SYSLINK_RepaintLink(infoPtr, Current); - SetFocus(infoPtr->Self); - } - - return 0; -} - -/*********************************************************************** - * SYSLINK_LButtonUp - * Handles mouse clicks - */ -static LRESULT SYSLINK_LButtonUp (SYSLINK_INFO *infoPtr, DWORD Buttons, POINT *pt) -{ - if(infoPtr->MouseDownID > -1) - { - PDOC_ITEM Current; - int id; - - Current = SYSLINK_LinkAtPt(infoPtr, pt, &id, TRUE); - if((Current != NULL) && (Current->u.Link.state & LIS_FOCUSED) && (infoPtr->MouseDownID == id)) - { - SYSLINK_SendParentNotify(infoPtr, NM_CLICK, Current, id); - } - } - - infoPtr->MouseDownID = -1; - - return 0; -} - -/*********************************************************************** - * SYSLINK_OnEnter - * Handles ENTER key events - */ -static BOOL SYSLINK_OnEnter (SYSLINK_INFO *infoPtr) -{ - if(infoPtr->HasFocus) - { - PDOC_ITEM Focus; - int id; - - Focus = SYSLINK_GetFocusLink(infoPtr, &id); - if(Focus != NULL) - { - SYSLINK_SendParentNotify(infoPtr, NM_RETURN, Focus, id); - return TRUE; - } - } - return FALSE; -} - -/*********************************************************************** - * SYSKEY_SelectNextPrevLink - * Changes the currently focused link - */ -static BOOL SYSKEY_SelectNextPrevLink (SYSLINK_INFO *infoPtr, BOOL Prev) -{ - if(infoPtr->HasFocus) - { - PDOC_ITEM Focus; - int id; - - Focus = SYSLINK_GetFocusLink(infoPtr, &id); - if(Focus != NULL) - { - PDOC_ITEM NewFocus, OldFocus; - - if(Prev) - NewFocus = SYSLINK_GetPrevLink(infoPtr, Focus); - else - NewFocus = SYSLINK_GetNextLink(infoPtr, Focus); - - if(NewFocus != NULL) - { - OldFocus = SYSLINK_SetFocusLink(infoPtr, NewFocus); - - if(OldFocus != NewFocus) - { - SYSLINK_RepaintLink(infoPtr, OldFocus); - } - SYSLINK_RepaintLink(infoPtr, NewFocus); - return TRUE; - } - } - } - return FALSE; -} - -/*********************************************************************** - * SYSKEY_SelectNextPrevLink - * Determines if there's a next or previous link to decide whether the control - * should capture the tab key message - */ -static BOOL SYSLINK_NoNextLink (SYSLINK_INFO *infoPtr, BOOL Prev) -{ - PDOC_ITEM Focus, NewFocus; - - Focus = SYSLINK_GetFocusLink(infoPtr, NULL); - if(Prev) - NewFocus = SYSLINK_GetPrevLink(infoPtr, Focus); - else - NewFocus = SYSLINK_GetNextLink(infoPtr, Focus); - - return NewFocus == NULL; -} - -/*********************************************************************** - * SysLinkWindowProc - */ -static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message, - WPARAM wParam, LPARAM lParam) -{ - SYSLINK_INFO *infoPtr; - - TRACE("hwnd=%p msg=%04x wparam=%x lParam=%lx\n", hwnd, message, wParam, lParam); - - infoPtr = (SYSLINK_INFO *)GetWindowLongPtrW(hwnd, 0); - - if (!infoPtr && message != WM_CREATE) - return DefWindowProcW( hwnd, message, wParam, lParam ); - - switch(message) { - case WM_PAINT: - return SYSLINK_Paint (infoPtr, (HDC)wParam); - - case WM_SETCURSOR: - { - LHITTESTINFO ht; - DWORD mp = GetMessagePos(); - - ht.pt.x = (short)LOWORD(mp); - ht.pt.y = (short)HIWORD(mp); - - ScreenToClient(infoPtr->Self, &ht.pt); - if(SYSLINK_HitTest (infoPtr, &ht)) - { - SetCursor(LoadCursorW(0, (LPCWSTR)IDC_HAND)); - return TRUE; - } - /* let the default window proc handle this message */ - return DefWindowProcW(hwnd, message, wParam, lParam); - - } - - case WM_SIZE: - { - HDC hdc = GetDC(infoPtr->Self); - if(hdc != NULL) - { - SYSLINK_Render(infoPtr, hdc); - ReleaseDC(infoPtr->Self, hdc); - } - return 0; - } - - case WM_GETFONT: - return (LRESULT)infoPtr->Font; - - case WM_SETFONT: - return (LRESULT)SYSLINK_SetFont(infoPtr, (HFONT)wParam, (BOOL)lParam); - - case WM_SETTEXT: - SYSLINK_SetText(infoPtr, (LPWSTR)lParam); - return DefWindowProcW(hwnd, message, wParam, lParam); - - case WM_LBUTTONDOWN: - { - POINT pt; - pt.x = LOWORD(lParam); - pt.y = HIWORD(lParam); - return SYSLINK_LButtonDown(infoPtr, wParam, &pt); - } - case WM_LBUTTONUP: - { - POINT pt; - pt.x = LOWORD(lParam); - pt.y = HIWORD(lParam); - return SYSLINK_LButtonUp(infoPtr, wParam, &pt); - } - - case WM_KEYDOWN: - { - switch(wParam) - { - case VK_RETURN: - SYSLINK_OnEnter(infoPtr); - return 0; - case VK_TAB: - { - BOOL shift = GetKeyState(VK_SHIFT) & 0x8000; - SYSKEY_SelectNextPrevLink(infoPtr, shift); - return 0; - } - } - return DefWindowProcW(hwnd, message, wParam, lParam); - } - - case WM_GETDLGCODE: - { - LRESULT Ret = DLGC_HASSETSEL; - int vk = (lParam != 0 ? (int)((LPMSG)lParam)->wParam : 0); - switch(vk) - { - case VK_RETURN: - Ret |= DLGC_WANTMESSAGE; - break; - case VK_TAB: - { - BOOL shift = GetKeyState(VK_SHIFT) & 0x8000; - if(!SYSLINK_NoNextLink(infoPtr, shift)) - { - Ret |= DLGC_WANTTAB; - } - else - { - Ret |= DLGC_WANTCHARS; - } - break; - } - } - return Ret; - } - - case WM_NCHITTEST: - { - POINT pt; - RECT rc; - pt.x = LOWORD(lParam); - pt.y = HIWORD(lParam); - - GetClientRect(infoPtr->Self, &rc); - ScreenToClient(infoPtr->Self, &pt); - if(pt.x < 0 || pt.y < 0 || pt.x > rc.right || pt.y > rc.bottom) - { - return HTNOWHERE; - } - - if(SYSLINK_LinkAtPt(infoPtr, &pt, NULL, FALSE)) - { - return HTCLIENT; - } - - return HTTRANSPARENT; - } - - case LM_HITTEST: - return SYSLINK_HitTest(infoPtr, (PLHITTESTINFO)lParam); - - case LM_SETITEM: - return SYSLINK_SetItem(infoPtr, (PLITEM)lParam); - - case LM_GETITEM: - return SYSLINK_GetItem(infoPtr, (PLITEM)lParam); - - case LM_GETIDEALHEIGHT: - return SYSLINK_GetIdealHeight(infoPtr); - - case WM_SETFOCUS: - return SYSLINK_SetFocus(infoPtr, (HWND)wParam); - - case WM_KILLFOCUS: - return SYSLINK_KillFocus(infoPtr, (HWND)wParam); - - case WM_ENABLE: - infoPtr->Style &= ~WS_DISABLED; - infoPtr->Style |= (wParam ? 0 : WS_DISABLED); - InvalidateRect (infoPtr->Self, NULL, FALSE); - return 0; - - case WM_STYLECHANGED: - if (wParam == GWL_STYLE) - { - infoPtr->Style = ((LPSTYLESTRUCT)lParam)->styleNew; - - InvalidateRect(infoPtr->Self, NULL, TRUE); - } - return 0; - - case WM_CREATE: - /* allocate memory for info struct */ - infoPtr = Alloc (sizeof(SYSLINK_INFO)); - if (!infoPtr) return -1; - SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); - - /* initialize the info struct */ - infoPtr->Self = hwnd; - infoPtr->Notify = ((LPCREATESTRUCTW)lParam)->hwndParent; - infoPtr->Style = ((LPCREATESTRUCTW)lParam)->style; - infoPtr->Font = 0; - infoPtr->LinkFont = 0; - infoPtr->Items = NULL; - infoPtr->HasFocus = FALSE; - infoPtr->MouseDownID = -1; - infoPtr->TextColor = GetSysColor(COLOR_WINDOWTEXT); - infoPtr->LinkColor = GetSysColor(COLOR_HIGHLIGHT); - infoPtr->VisitedColor = GetSysColor(COLOR_HIGHLIGHT); - TRACE("SysLink Ctrl creation, hwnd=%p\n", hwnd); - SYSLINK_SetText(infoPtr, ((LPCREATESTRUCTW)lParam)->lpszName); - return 0; - - case WM_DESTROY: - TRACE("SysLink Ctrl destruction, hwnd=%p\n", hwnd); - SYSLINK_ClearDoc(infoPtr); - if(infoPtr->Font != 0) DeleteObject(infoPtr->Font); - if(infoPtr->LinkFont != 0) DeleteObject(infoPtr->LinkFont); - SetWindowLongPtrW(hwnd, 0, 0); - Free (infoPtr); - return 0; - - default: - if ((message >= WM_USER) && (message < WM_APP)) - ERR("unknown msg %04x wp=%04x lp=%08lx\n", message, wParam, lParam ); - return DefWindowProcW(hwnd, message, wParam, lParam); - } -} - - -/*********************************************************************** - * SYSLINK_Register [Internal] - * - * Registers the SysLink window class. - */ -VOID SYSLINK_Register (void) -{ - WNDCLASSW wndClass; - - ZeroMemory (&wndClass, sizeof(wndClass)); - wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW; - wndClass.lpfnWndProc = SysLinkWindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof (SYSLINK_INFO *); - wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); - wndClass.lpszClassName = WC_LINK; - - RegisterClassW (&wndClass); -} - - -/*********************************************************************** - * SYSLINK_Unregister [Internal] - * - * Unregisters the SysLink window class. - */ -VOID SYSLINK_Unregister (void) -{ - UnregisterClassW (WC_LINK, NULL); -} +/* + * SysLink control + * + * Copyright 2004 Thomas Weidenmueller + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES + * + * This code was audited for completeness against the documented features + * of Comctl32.dll version 6.0 on Apr. 4, 2005, by Dimitrie O. Paun. + * + * Unless otherwise noted, we believe this code to be complete, as per + * the specification mentioned above. + * If you discover missing features, or bugs, please note them below. + * + * TODO: + * - Fix SHIFT+TAB and TAB issue (wrong link is selected when control gets the focus) + * - Better string parsing + * - Improve word wrapping + * + */ + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "comctl32.h" +#include "wine/unicode.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(progress); + +INT WINAPI StrCmpNIW(LPCWSTR,LPCWSTR,INT); + +typedef struct +{ + int nChars; + RECT rc; +} DOC_TEXTBLOCK, *PDOC_TEXTBLOCK; + +#define LIF_FLAGSMASK (LIF_STATE | LIF_ITEMID | LIF_URL) +#define LIS_MASK (LIS_FOCUSED | LIS_ENABLED | LIS_VISITED) + +typedef enum +{ + slText = 0, + slLink +} SL_ITEM_TYPE; + +typedef struct _DOC_ITEM +{ + struct _DOC_ITEM *Next; /* Address to the next item */ + LPWSTR Text; /* Text of the document item */ + UINT nText; /* Number of characters of the text */ + SL_ITEM_TYPE Type; /* type of the item */ + PDOC_TEXTBLOCK Blocks; /* Array of text blocks */ + union + { + struct + { + UINT state; /* Link state */ + WCHAR *szID; /* Link ID string */ + WCHAR *szUrl; /* Link URL string */ + HRGN hRgn; /* Region of the link */ + } Link; + struct + { + UINT Dummy; + } Text; + } u; +} DOC_ITEM, *PDOC_ITEM; + +typedef struct +{ + HWND Self; /* The window handle for this control */ + HWND Notify; /* The parent handle to receive notifications */ + DWORD Style; /* Styles for this control */ + PDOC_ITEM Items; /* Address to the first document item */ + BOOL HasFocus; /* Whether the control has the input focus */ + int MouseDownID; /* ID of the link that the mouse button first selected */ + HFONT Font; /* Handle to the font for text */ + HFONT LinkFont; /* Handle to the font for links */ + COLORREF TextColor; /* Color of the text */ + COLORREF LinkColor; /* Color of links */ + COLORREF VisitedColor; /* Color of visited links */ +} SYSLINK_INFO; + +static const WCHAR SL_LINKOPEN[] = { '<','a', 0 }; +static const WCHAR SL_HREF[] = { 'h','r','e','f','=','\"',0 }; +static const WCHAR SL_ID[] = { 'i','d','=','\"',0 }; +static const WCHAR SL_LINKCLOSE[] = { '<','/','a','>',0 }; + +/* Control configuration constants */ + +#define SL_LEFTMARGIN (0) +#define SL_TOPMARGIN (0) +#define SL_RIGHTMARGIN (0) +#define SL_BOTTOMMARGIN (0) + +/*********************************************************************** + * SYSLINK_FreeDocItem + * Frees all data and gdi objects associated with a document item + */ +static VOID SYSLINK_FreeDocItem (PDOC_ITEM DocItem) +{ + if(DocItem->Type == slLink) + { + Free(DocItem->u.Link.szID); + Free(DocItem->u.Link.szUrl); + } + + if(DocItem->Type == slLink && DocItem->u.Link.hRgn != NULL) + { + DeleteObject(DocItem->u.Link.hRgn); + } + + /* we don't free Text because it's just a pointer to a character in the + entire window text string */ + + Free(DocItem); +} + +/*********************************************************************** + * SYSLINK_AppendDocItem + * Create and append a new document item. + */ +static PDOC_ITEM SYSLINK_AppendDocItem (SYSLINK_INFO *infoPtr, LPCWSTR Text, UINT textlen, + SL_ITEM_TYPE type, PDOC_ITEM LastItem) +{ + PDOC_ITEM Item; + Item = Alloc(sizeof(DOC_ITEM) + ((textlen + 1) * sizeof(WCHAR))); + if(Item == NULL) + { + ERR("Failed to alloc DOC_ITEM structure!\n"); + return NULL; + } + textlen = min(textlen, lstrlenW(Text)); + + Item->Next = NULL; + Item->Text = (LPWSTR)(Item + 1); + Item->nText = textlen; + Item->Type = type; + Item->Blocks = NULL; + + if(LastItem != NULL) + { + LastItem->Next = Item; + } + else + { + infoPtr->Items = Item; + } + + lstrcpynW(Item->Text, Text, textlen + 1); + Item->Text[textlen] = 0; + + return Item; +} + +/*********************************************************************** + * SYSLINK_ClearDoc + * Clears the document tree + */ +static VOID SYSLINK_ClearDoc (SYSLINK_INFO *infoPtr) +{ + PDOC_ITEM Item, Next; + + Item = infoPtr->Items; + while(Item != NULL) + { + Next = Item->Next; + SYSLINK_FreeDocItem(Item); + Item = Next; + } + + infoPtr->Items = NULL; +} + +/*********************************************************************** + * SYSLINK_ParseText + * Parses the window text string and creates a document. Returns the + * number of document items created. + */ +static UINT SYSLINK_ParseText (SYSLINK_INFO *infoPtr, LPCWSTR Text) +{ + LPCWSTR current, textstart = NULL, linktext = NULL, firsttag = NULL; + int taglen = 0, textlen = 0, linklen = 0, docitems = 0; + PDOC_ITEM Last = NULL; + SL_ITEM_TYPE CurrentType = slText; + LPCWSTR lpID, lpUrl; + UINT lenId, lenUrl; + + for(current = Text; *current != 0;) + { + if(*current == '<') + { + if(!StrCmpNIW(current, SL_LINKOPEN, 2) && (CurrentType == slText)) + { + BOOL ValidParam = FALSE, ValidLink = FALSE; + + switch (*(current + 2)) + { + case '>': + /* we just have to deal with a tag */ + taglen = 3; + ValidLink = TRUE; + ValidParam = TRUE; + firsttag = current; + linklen = 0; + lpID = NULL; + lpUrl = NULL; + break; + case ' ': + { + /* we expect parameters, parse them */ + LPCWSTR *CurrentParameter = NULL, tmp; + UINT *CurrentParameterLen = NULL; + + taglen = 3; + tmp = current + taglen; + lpID = NULL; + lpUrl = NULL; + +CheckParameter: + /* compare the current position with all known parameters */ + if(!StrCmpNIW(tmp, SL_HREF, 6)) + { + taglen += 6; + ValidParam = TRUE; + CurrentParameter = &lpUrl; + CurrentParameterLen = &lenUrl; + } + else if(!StrCmpNIW(tmp, SL_ID, 4)) + { + taglen += 4; + ValidParam = TRUE; + CurrentParameter = &lpID; + CurrentParameterLen = &lenId; + } + else + { + ValidParam = FALSE; + } + + if(ValidParam) + { + /* we got a known parameter, now search until the next " character. + If we can't find a " character, there's a syntax error and we just assume it's text */ + ValidParam = FALSE; + *CurrentParameter = current + taglen; + *CurrentParameterLen = 0; + + for(tmp = *CurrentParameter; *tmp != 0; tmp++) + { + taglen++; + if(*tmp == '\"') + { + ValidParam = TRUE; + tmp++; + break; + } + (*CurrentParameterLen)++; + } + } + if(ValidParam) + { + /* we're done with this parameter, now there are only 2 possibilities: + * 1. another parameter is coming, so expect a ' ' (space) character + * 2. the tag is being closed, so expect a '<' character + */ + switch(*tmp) + { + case ' ': + /* we expect another parameter, do the whole thing again */ + taglen++; + tmp++; + goto CheckParameter; + + case '>': + /* the tag is being closed, we're done */ + ValidLink = TRUE; + taglen++; + break; + default: + tmp++; + break; + } + } + + break; + } + } + + if(ValidLink && ValidParam) + { + /* the tag appears to be valid. save all information + so we can add the link if we find a valid tag later */ + CurrentType = slLink; + linktext = current + taglen; + linklen = 0; + firsttag = current; + } + else + { + taglen = 1; + lpID = NULL; + lpUrl = NULL; + if(textstart == NULL) + { + textstart = current; + } + } + } + else if(!StrCmpNIW(current, SL_LINKCLOSE, 4) && (CurrentType == slLink) && firsttag) + { + /* there's a tag opened, first add the previous text, if present */ + if(textstart != NULL && textlen > 0 && firsttag > textstart) + { + Last = SYSLINK_AppendDocItem(infoPtr, textstart, firsttag - textstart, slText, Last); + if(Last == NULL) + { + ERR("Unable to create new document item!\n"); + return docitems; + } + docitems++; + textstart = NULL; + textlen = 0; + } + + /* now it's time to add the link to the document */ + current += 4; + if(linktext != NULL && linklen > 0) + { + Last = SYSLINK_AppendDocItem(infoPtr, linktext, linklen, slLink, Last); + if(Last == NULL) + { + ERR("Unable to create new document item!\n"); + return docitems; + } + docitems++; + if(CurrentType == slLink) + { + int nc; + + if(!(infoPtr->Style & WS_DISABLED)) + { + Last->u.Link.state |= LIS_ENABLED; + } + /* Copy the tag parameters */ + if(lpID != NULL) + { + nc = min(lenId, strlenW(lpID)); + nc = min(nc, MAX_LINKID_TEXT); + Last->u.Link.szID = Alloc((MAX_LINKID_TEXT + 1) * sizeof(WCHAR)); + if(Last->u.Link.szID != NULL) + { + lstrcpynW(Last->u.Link.szID, lpID, nc + 1); + Last->u.Link.szID[nc] = 0; + } + } + else + Last->u.Link.szID = NULL; + if(lpUrl != NULL) + { + nc = min(lenUrl, strlenW(lpUrl)); + nc = min(nc, L_MAX_URL_LENGTH); + Last->u.Link.szUrl = Alloc((L_MAX_URL_LENGTH + 1) * sizeof(WCHAR)); + if(Last->u.Link.szUrl != NULL) + { + lstrcpynW(Last->u.Link.szUrl, lpUrl, nc + 1); + Last->u.Link.szUrl[nc] = 0; + } + } + else + Last->u.Link.szUrl = NULL; + } + linktext = NULL; + } + CurrentType = slText; + firsttag = NULL; + textstart = NULL; + continue; + } + else + { + /* we don't know what tag it is, so just continue */ + taglen = 1; + linklen++; + if(CurrentType == slText && textstart == NULL) + { + textstart = current; + } + } + + textlen += taglen; + current += taglen; + } + else + { + textlen++; + linklen++; + + /* save the pointer of the current text item if we couldn't find a tag */ + if(textstart == NULL && CurrentType == slText) + { + textstart = current; + } + + current++; + } + } + + if(textstart != NULL && textlen > 0) + { + Last = SYSLINK_AppendDocItem(infoPtr, textstart, textlen, CurrentType, Last); + if(Last == NULL) + { + ERR("Unable to create new document item!\n"); + return docitems; + } + if(CurrentType == slLink) + { + int nc; + + if(!(infoPtr->Style & WS_DISABLED)) + { + Last->u.Link.state |= LIS_ENABLED; + } + /* Copy the tag parameters */ + if(lpID != NULL) + { + nc = min(lenId, strlenW(lpID)); + nc = min(nc, MAX_LINKID_TEXT); + Last->u.Link.szID = Alloc((MAX_LINKID_TEXT + 1) * sizeof(WCHAR)); + if(Last->u.Link.szID != NULL) + { + lstrcpynW(Last->u.Link.szID, lpID, nc + 1); + Last->u.Link.szID[nc] = 0; + } + } + else + Last->u.Link.szID = NULL; + if(lpUrl != NULL) + { + nc = min(lenUrl, strlenW(lpUrl)); + nc = min(nc, L_MAX_URL_LENGTH); + Last->u.Link.szUrl = Alloc((L_MAX_URL_LENGTH + 1) * sizeof(WCHAR)); + if(Last->u.Link.szUrl != NULL) + { + lstrcpynW(Last->u.Link.szUrl, lpUrl, nc + 1); + Last->u.Link.szUrl[nc] = 0; + } + } + else + Last->u.Link.szUrl = NULL; + } + docitems++; + } + + if(linktext != NULL && linklen > 0) + { + /* we got an unclosed link, just display the text */ + Last = SYSLINK_AppendDocItem(infoPtr, linktext, linklen, slText, Last); + if(Last == NULL) + { + ERR("Unable to create new document item!\n"); + return docitems; + } + docitems++; + } + + return docitems; +} + +/*********************************************************************** + * SYSLINK_RepaintLink + * Repaints a link. + */ +static VOID SYSLINK_RepaintLink (SYSLINK_INFO *infoPtr, PDOC_ITEM DocItem) +{ + if(DocItem->Type != slLink) + { + ERR("DocItem not a link!\n"); + return; + } + + if(DocItem->u.Link.hRgn != NULL) + { + /* repaint the region */ + RedrawWindow(infoPtr->Self, NULL, DocItem->u.Link.hRgn, RDW_INVALIDATE | RDW_UPDATENOW); + } +} + +/*********************************************************************** + * SYSLINK_GetLinkItemByIndex + * Retrieves a document link by its index + */ +static PDOC_ITEM SYSLINK_GetLinkItemByIndex (SYSLINK_INFO *infoPtr, int iLink) +{ + PDOC_ITEM Current = infoPtr->Items; + + while(Current != NULL) + { + if((Current->Type == slLink) && (iLink-- <= 0)) + { + return Current; + } + Current = Current->Next; + } + return NULL; +} + +/*********************************************************************** + * SYSLINK_GetFocusLink + * Retrieves the link that has the LIS_FOCUSED bit + */ +static PDOC_ITEM SYSLINK_GetFocusLink (SYSLINK_INFO *infoPtr, int *LinkId) +{ + PDOC_ITEM Current = infoPtr->Items; + int id = 0; + + while(Current != NULL) + { + if((Current->Type == slLink)) + { + if(Current->u.Link.state & LIS_FOCUSED) + { + if(LinkId != NULL) + *LinkId = id; + return Current; + } + id++; + } + Current = Current->Next; + } + return NULL; +} + +/*********************************************************************** + * SYSLINK_GetNextLink + * Gets the next link + */ +static PDOC_ITEM SYSLINK_GetNextLink (SYSLINK_INFO *infoPtr, PDOC_ITEM Current) +{ + for(Current = (Current != NULL ? Current->Next : infoPtr->Items); + Current != NULL; + Current = Current->Next) + { + if(Current->Type == slLink) + { + return Current; + } + } + return NULL; +} + +/*********************************************************************** + * SYSLINK_GetPrevLink + * Gets the previous link + */ +static PDOC_ITEM SYSLINK_GetPrevLink (SYSLINK_INFO *infoPtr, PDOC_ITEM Current) +{ + if(Current == NULL) + { + /* returns the last link */ + PDOC_ITEM Last = NULL; + + for(Current = infoPtr->Items; Current != NULL; Current = Current->Next) + { + if(Current->Type == slLink) + { + Last = Current; + } + } + return Last; + } + else + { + /* returns the previous link */ + PDOC_ITEM Cur, Prev = NULL; + + for(Cur = infoPtr->Items; Cur != NULL; Cur = Cur->Next) + { + if(Cur == Current) + { + break; + } + if(Cur->Type == slLink) + { + Prev = Cur; + } + } + return Prev; + } +} + +/*********************************************************************** + * SYSLINK_WrapLine + * Tries to wrap a line. + */ +static BOOL SYSLINK_WrapLine (HDC hdc, LPWSTR Text, WCHAR BreakChar, int *LineLen, int nFit, LPSIZE Extent, int Width) +{ + WCHAR *Current; + + if(nFit == *LineLen) + { + return FALSE; + } + + *LineLen = nFit; + + Current = Text + nFit; + + /* check if we're in the middle of a word */ + if((*Current) != BreakChar) + { + /* search for the beginning of the word */ + while(Current > Text && (*(Current - 1)) != BreakChar) + { + Current--; + (*LineLen)--; + } + + if((*LineLen) == 0) + { + Extent->cx = 0; + Extent->cy = 0; + } + return TRUE; + } + + return TRUE; +} + +/*********************************************************************** + * SYSLINK_Render + * Renders the document in memory + */ +static VOID SYSLINK_Render (SYSLINK_INFO *infoPtr, HDC hdc) +{ + RECT rc; + PDOC_ITEM Current; + HGDIOBJ hOldFont; + int x, y, LineHeight; + TEXTMETRICW tm; + + GetClientRect(infoPtr->Self, &rc); + rc.right -= SL_RIGHTMARGIN; + rc.bottom -= SL_BOTTOMMARGIN; + + if(rc.right - SL_LEFTMARGIN < 0 || rc.bottom - SL_TOPMARGIN < 0) return; + + hOldFont = SelectObject(hdc, infoPtr->Font); + GetTextMetricsW(hdc, &tm); + + x = SL_LEFTMARGIN; + y = SL_TOPMARGIN; + LineHeight = 0; + + for(Current = infoPtr->Items; Current != NULL; Current = Current->Next) + { + int n, nBlocks; + LPWSTR tx; + PDOC_TEXTBLOCK bl, cbl; + INT nFit; + SIZE szDim; + + if(Current->nText == 0) + { + ERR("DOC_ITEM with no text?!\n"); + continue; + } + + tx = Current->Text; + n = Current->nText; + bl = Current->Blocks; + nBlocks = 0; + + if(Current->Type == slText) + { + SelectObject(hdc, infoPtr->Font); + } + else if(Current->Type == slLink) + { + SelectObject(hdc, infoPtr->LinkFont); + } + + while(n > 0) + { + if(GetTextExtentExPointW(hdc, tx, n, rc.right - x, &nFit, NULL, &szDim)) + { + int LineLen = n; + BOOL Wrap = SYSLINK_WrapLine(hdc, tx, tm.tmBreakChar, &LineLen, nFit, &szDim, rc.right - x); + + if(LineLen == 0) + { + if(x > SL_LEFTMARGIN) + { + /* move one line down, the word didn't fit into the line */ + x = SL_LEFTMARGIN; + y += LineHeight; + LineHeight = 0; + continue; + } + else + { + /* the word starts at the beginning of the line and doesn't + fit into the line, so break it at the last character that fits */ + LineLen = max(nFit, 1); + } + } + + if(LineLen != n) + { + GetTextExtentExPointW(hdc, tx, LineLen, rc.right - x, NULL, NULL, &szDim); + } + + if(bl != NULL) + { + bl = ReAlloc(bl, ++nBlocks * sizeof(DOC_TEXTBLOCK)); + } + else + { + bl = Alloc(++nBlocks * sizeof(DOC_TEXTBLOCK)); + } + + if(bl != NULL) + { + cbl = bl + nBlocks - 1; + + cbl->nChars = LineLen; + cbl->rc.left = x; + cbl->rc.top = y; + cbl->rc.right = x + szDim.cx; + cbl->rc.bottom = y + szDim.cy; + + x += szDim.cx; + LineHeight = max(LineHeight, szDim.cy); + + /* (re)calculate the link's region */ + if(Current->Type == slLink) + { + if(nBlocks <= 1) + { + if(Current->u.Link.hRgn != NULL) + { + DeleteObject(Current->u.Link.hRgn); + } + /* initialize the link's hRgn */ + Current->u.Link.hRgn = CreateRectRgnIndirect(&cbl->rc); + } + else if(Current->u.Link.hRgn != NULL) + { + HRGN hrgn; + hrgn = CreateRectRgnIndirect(&cbl->rc); + /* add the rectangle */ + CombineRgn(Current->u.Link.hRgn, Current->u.Link.hRgn, hrgn, RGN_OR); + DeleteObject(hrgn); + } + } + + if(Wrap) + { + x = SL_LEFTMARGIN; + y += LineHeight; + LineHeight = 0; + } + } + else + { + ERR("Failed to alloc DOC_TEXTBLOCK structure!\n"); + break; + } + n -= LineLen; + tx += LineLen; + } + else + { + ERR("GetTextExtentExPoint() failed?!\n"); + n--; + } + } + Current->Blocks = bl; + } + + SelectObject(hdc, hOldFont); +} + +/*********************************************************************** + * SYSLINK_Draw + * Draws the SysLink control. + */ +static LRESULT SYSLINK_Draw (SYSLINK_INFO *infoPtr, HDC hdc) +{ + RECT rc; + PDOC_ITEM Current; + HFONT hOldFont; + COLORREF OldTextColor, OldBkColor; + + hOldFont = SelectObject(hdc, infoPtr->Font); + OldTextColor = SetTextColor(hdc, infoPtr->TextColor); + OldBkColor = SetBkColor(hdc, GetSysColor(COLOR_BTNFACE)); + + GetClientRect(infoPtr->Self, &rc); + rc.right -= SL_RIGHTMARGIN + SL_LEFTMARGIN; + rc.bottom -= SL_BOTTOMMARGIN + SL_TOPMARGIN; + + if(rc.right < 0 || rc.bottom < 0) return 0; + + for(Current = infoPtr->Items; Current != NULL; Current = Current->Next) + { + int n; + LPWSTR tx; + PDOC_TEXTBLOCK bl; + + bl = Current->Blocks; + if(bl != NULL) + { + tx = Current->Text; + n = Current->nText; + + if(Current->Type == slText) + { + SelectObject(hdc, infoPtr->Font); + SetTextColor(hdc, infoPtr->TextColor); + } + else + { + SelectObject(hdc, infoPtr->LinkFont); + SetTextColor(hdc, (!(Current->u.Link.state & LIS_VISITED) ? infoPtr->LinkColor : infoPtr->VisitedColor)); + } + + while(n > 0) + { + ExtTextOutW(hdc, bl->rc.left, bl->rc.top, ETO_OPAQUE | ETO_CLIPPED, &bl->rc, tx, bl->nChars, NULL); + if((Current->Type == slLink) && (Current->u.Link.state & LIS_FOCUSED) && infoPtr->HasFocus) + { + COLORREF PrevColor; + PrevColor = SetBkColor(hdc, OldBkColor); + DrawFocusRect(hdc, &bl->rc); + SetBkColor(hdc, PrevColor); + } + tx += bl->nChars; + n -= bl->nChars; + bl++; + } + } + } + + SetBkColor(hdc, OldBkColor); + SetTextColor(hdc, OldTextColor); + SelectObject(hdc, hOldFont); + + return 0; +} + + +/*********************************************************************** + * SYSLINK_Paint + * Handles the WM_PAINT message. + */ +static LRESULT SYSLINK_Paint (SYSLINK_INFO *infoPtr, HDC hdcParam) +{ + HDC hdc; + PAINTSTRUCT ps; + + hdc = hdcParam ? hdcParam : BeginPaint (infoPtr->Self, &ps); + SYSLINK_Draw (infoPtr, hdc); + if (!hdcParam) EndPaint (infoPtr->Self, &ps); + return 0; +} + + +/*********************************************************************** + * SYSLINK_SetFont + * Set new Font for the SysLink control. + */ +static HFONT SYSLINK_SetFont (SYSLINK_INFO *infoPtr, HFONT hFont, BOOL bRedraw) +{ + HDC hdc; + LOGFONTW lf; + HFONT hOldFont = infoPtr->Font; + infoPtr->Font = hFont; + + /* free the underline font */ + if(infoPtr->LinkFont != NULL) + { + DeleteObject(infoPtr->LinkFont); + infoPtr->LinkFont = NULL; + } + + /* Render text position and word wrapping in memory */ + hdc = GetDC(infoPtr->Self); + if(hdc != NULL) + { + /* create a new underline font */ + if(GetObjectW(infoPtr->Font, sizeof(LOGFONTW), &lf)) + { + lf.lfUnderline = TRUE; + infoPtr->LinkFont = CreateFontIndirectW(&lf); + } + else + { + ERR("Failed to create link font!\n"); + } + + SYSLINK_Render(infoPtr, hdc); + ReleaseDC(infoPtr->Self, hdc); + } + + if(bRedraw) + { + RedrawWindow(infoPtr->Self, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW); + } + + return hOldFont; +} + +/*********************************************************************** + * SYSLINK_SetText + * Set new text for the SysLink control. + */ +static LRESULT SYSLINK_SetText (SYSLINK_INFO *infoPtr, LPCWSTR Text) +{ + int textlen; + + /* clear the document */ + SYSLINK_ClearDoc(infoPtr); + + textlen = lstrlenW(Text); + if(Text == NULL || textlen == 0) + { + return TRUE; + } + + /* let's parse the string and create a document */ + if(SYSLINK_ParseText(infoPtr, Text) > 0) + { + /* Render text position and word wrapping in memory */ + HDC hdc = GetDC(infoPtr->Self); + SYSLINK_Render(infoPtr, hdc); + SYSLINK_Draw(infoPtr, hdc); + ReleaseDC(infoPtr->Self, hdc); + } + + return TRUE; +} + +/*********************************************************************** + * SYSLINK_SetFocusLink + * Updates the focus status bits and focusses the specified link. + * If no document item is specified, the focus bit will be removed from all links. + * Returns the previous focused item. + */ +static PDOC_ITEM SYSLINK_SetFocusLink (SYSLINK_INFO *infoPtr, PDOC_ITEM DocItem) +{ + PDOC_ITEM Current, PrevFocus = NULL; + + for(Current = infoPtr->Items; Current != NULL; Current = Current->Next) + { + if(Current->Type == slLink) + { + if((PrevFocus == NULL) && (Current->u.Link.state & LIS_FOCUSED)) + { + PrevFocus = Current; + } + + if(Current == DocItem) + { + Current->u.Link.state |= LIS_FOCUSED; + } + else + { + Current->u.Link.state &= ~LIS_FOCUSED; + } + } + } + + return PrevFocus; +} + +/*********************************************************************** + * SYSLINK_SetItem + * Sets the states and attributes of a link item. + */ +static LRESULT SYSLINK_SetItem (SYSLINK_INFO *infoPtr, PLITEM Item) +{ + PDOC_ITEM di; + BOOL Repaint = FALSE; + BOOL Ret = TRUE; + + if(!(Item->mask & LIF_ITEMINDEX) || !(Item->mask & (LIF_FLAGSMASK))) + { + ERR("Invalid Flags!\n"); + return FALSE; + } + + di = SYSLINK_GetLinkItemByIndex(infoPtr, Item->iLink); + if(di == NULL) + { + ERR("Link %d couldn't be found\n", Item->iLink); + return FALSE; + } + + if(Item->mask & LIF_STATE) + { + UINT oldstate = di->u.Link.state; + /* clear the masked bits */ + di->u.Link.state &= ~(Item->stateMask & LIS_MASK); + /* copy the bits */ + di->u.Link.state |= (Item->state & Item->stateMask) & LIS_MASK; + Repaint = (oldstate != di->u.Link.state); + + /* update the focus */ + SYSLINK_SetFocusLink(infoPtr, ((di->u.Link.state & LIS_FOCUSED) ? di : NULL)); + } + + if(Item->mask & LIF_ITEMID) + { + if(!di->u.Link.szID) + { + di->u.Link.szID = Alloc((MAX_LINKID_TEXT + 1) * sizeof(WCHAR)); + if(!Item->szID) + { + ERR("Unable to allocate memory for link id\n"); + Ret = FALSE; + } + } + if(di->u.Link.szID) + { + lstrcpynW(di->u.Link.szID, Item->szID, MAX_LINKID_TEXT + 1); + } + } + + if(Item->mask & LIF_URL) + { + if(!di->u.Link.szUrl) + { + di->u.Link.szUrl = Alloc((MAX_LINKID_TEXT + 1) * sizeof(WCHAR)); + if(!Item->szUrl) + { + ERR("Unable to allocate memory for link url\n"); + Ret = FALSE; + } + } + if(di->u.Link.szUrl) + { + lstrcpynW(di->u.Link.szUrl, Item->szUrl, MAX_LINKID_TEXT + 1); + } + } + + if(Repaint) + { + SYSLINK_RepaintLink(infoPtr, di); + } + + return Ret; +} + +/*********************************************************************** + * SYSLINK_GetItem + * Retrieves the states and attributes of a link item. + */ +static LRESULT SYSLINK_GetItem (SYSLINK_INFO *infoPtr, PLITEM Item) +{ + PDOC_ITEM di; + + if(!(Item->mask & LIF_ITEMINDEX) || !(Item->mask & (LIF_FLAGSMASK))) + { + ERR("Invalid Flags!\n"); + return FALSE; + } + + di = SYSLINK_GetLinkItemByIndex(infoPtr, Item->iLink); + if(di == NULL) + { + ERR("Link %d couldn't be found\n", Item->iLink); + return FALSE; + } + + if(Item->mask & LIF_STATE) + { + Item->state = (di->u.Link.state & Item->stateMask); + if(!infoPtr->HasFocus) + { + /* remove the LIS_FOCUSED bit if the control doesn't have focus */ + Item->state &= ~LIS_FOCUSED; + } + } + + if(Item->mask & LIF_ITEMID) + { + if(di->u.Link.szID) + { + lstrcpynW(Item->szID, di->u.Link.szID, MAX_LINKID_TEXT + 1); + } + else + { + Item->szID[0] = 0; + } + } + + if(Item->mask & LIF_URL) + { + if(di->u.Link.szUrl) + { + lstrcpynW(Item->szUrl, di->u.Link.szUrl, L_MAX_URL_LENGTH + 1); + } + else + { + Item->szUrl[0] = 0; + } + } + + return TRUE; +} + +/*********************************************************************** + * SYSLINK_HitTest + * Determines the link the user clicked on. + */ +static LRESULT SYSLINK_HitTest (SYSLINK_INFO *infoPtr, PLHITTESTINFO HitTest) +{ + PDOC_ITEM Current; + int id = 0; + + for(Current = infoPtr->Items; Current != NULL; Current = Current->Next) + { + if(Current->Type == slLink) + { + if((Current->u.Link.hRgn != NULL) && + PtInRegion(Current->u.Link.hRgn, HitTest->pt.x, HitTest->pt.y)) + { + HitTest->item.mask = 0; + HitTest->item.iLink = id; + HitTest->item.state = 0; + HitTest->item.stateMask = 0; + if(Current->u.Link.szID) + { + lstrcpynW(HitTest->item.szID, Current->u.Link.szID, MAX_LINKID_TEXT + 1); + } + else + { + HitTest->item.szID[0] = 0; + } + if(Current->u.Link.szUrl) + { + lstrcpynW(HitTest->item.szUrl, Current->u.Link.szUrl, L_MAX_URL_LENGTH + 1); + } + else + { + HitTest->item.szUrl[0] = 0; + } + return TRUE; + } + id++; + } + } + + return FALSE; +} + +/*********************************************************************** + * SYSLINK_GetIdealHeight + * Returns the preferred height of a link at the current control's width. + */ +static LRESULT SYSLINK_GetIdealHeight (SYSLINK_INFO *infoPtr) +{ + HDC hdc = GetDC(infoPtr->Self); + if(hdc != NULL) + { + LRESULT height; + TEXTMETRICW tm; + HGDIOBJ hOldFont = SelectObject(hdc, infoPtr->Font); + + if(GetTextMetricsW(hdc, &tm)) + { + height = tm.tmHeight; + } + else + { + height = 0; + } + SelectObject(hdc, hOldFont); + ReleaseDC(infoPtr->Self, hdc); + + return height; + } + return 0; +} + +/*********************************************************************** + * SYSLINK_SendParentNotify + * Sends a WM_NOTIFY message to the parent window. + */ +static LRESULT SYSLINK_SendParentNotify (SYSLINK_INFO *infoPtr, UINT code, PDOC_ITEM Link, int iLink) +{ + NMLINK nml; + + nml.hdr.hwndFrom = infoPtr->Self; + nml.hdr.idFrom = GetWindowLongPtrW(infoPtr->Self, GWLP_ID); + nml.hdr.code = code; + + nml.item.mask = 0; + nml.item.iLink = iLink; + nml.item.state = 0; + nml.item.stateMask = 0; + if(Link->u.Link.szID) + { + lstrcpynW(nml.item.szID, Link->u.Link.szID, MAX_LINKID_TEXT + 1); + } + else + { + nml.item.szID[0] = 0; + } + if(Link->u.Link.szUrl) + { + lstrcpynW(nml.item.szUrl, Link->u.Link.szUrl, L_MAX_URL_LENGTH + 1); + } + else + { + nml.item.szUrl[0] = 0; + } + + return SendMessageW(infoPtr->Notify, WM_NOTIFY, (WPARAM)nml.hdr.idFrom, (LPARAM)&nml); +} + +/*********************************************************************** + * SYSLINK_SetFocus + * Handles receiving the input focus. + */ +static LRESULT SYSLINK_SetFocus (SYSLINK_INFO *infoPtr, HWND PrevFocusWindow) +{ + PDOC_ITEM Focus; + + infoPtr->HasFocus = TRUE; + +#if 1 + /* FIXME - How to detect whether SHIFT+TAB or just TAB has been pressed? + * The problem is we could get this message without keyboard input, too + */ + Focus = SYSLINK_GetFocusLink(infoPtr, NULL); + + if(Focus == NULL && (Focus = SYSLINK_GetNextLink(infoPtr, NULL))) + { + SYSLINK_SetFocusLink(infoPtr, Focus); + } +#else + /* This is a temporary hack since I'm not really sure how to detect which link to select. + See message above! */ + Focus = SYSLINK_GetNextLink(infoPtr, NULL); + if(Focus != NULL) + { + SYSLINK_SetFocusLink(infoPtr, Focus); + } +#endif + + SYSLINK_RepaintLink(infoPtr, Focus); + + return 0; +} + +/*********************************************************************** + * SYSLINK_KillFocus + * Handles losing the input focus. + */ +static LRESULT SYSLINK_KillFocus (SYSLINK_INFO *infoPtr, HWND NewFocusWindow) +{ + PDOC_ITEM Focus; + + infoPtr->HasFocus = FALSE; + Focus = SYSLINK_GetFocusLink(infoPtr, NULL); + + if(Focus != NULL) + { + SYSLINK_RepaintLink(infoPtr, Focus); + } + + return 0; +} + +/*********************************************************************** + * SYSLINK_LinkAtPt + * Returns a link at the specified position + */ +static PDOC_ITEM SYSLINK_LinkAtPt (SYSLINK_INFO *infoPtr, POINT *pt, int *LinkId, BOOL MustBeEnabled) +{ + PDOC_ITEM Current; + int id = 0; + + for(Current = infoPtr->Items; Current != NULL; Current = Current->Next) + { + if((Current->Type == slLink) && (Current->u.Link.hRgn != NULL) && + PtInRegion(Current->u.Link.hRgn, pt->x, pt->y) && + (!MustBeEnabled || (MustBeEnabled && (Current->u.Link.state & LIS_ENABLED)))) + { + if(LinkId != NULL) + { + *LinkId = id; + } + return Current; + } + id++; + } + + return NULL; +} + +/*********************************************************************** + * SYSLINK_LButtonDown + * Handles mouse clicks + */ +static LRESULT SYSLINK_LButtonDown (SYSLINK_INFO *infoPtr, DWORD Buttons, POINT *pt) +{ + PDOC_ITEM Current, Old; + int id; + + Current = SYSLINK_LinkAtPt(infoPtr, pt, &id, TRUE); + if(Current != NULL) + { + Old = SYSLINK_SetFocusLink(infoPtr, Current); + if(Old != NULL && Old != Current) + { + SYSLINK_RepaintLink(infoPtr, Old); + } + infoPtr->MouseDownID = id; + SYSLINK_RepaintLink(infoPtr, Current); + SetFocus(infoPtr->Self); + } + + return 0; +} + +/*********************************************************************** + * SYSLINK_LButtonUp + * Handles mouse clicks + */ +static LRESULT SYSLINK_LButtonUp (SYSLINK_INFO *infoPtr, DWORD Buttons, POINT *pt) +{ + if(infoPtr->MouseDownID > -1) + { + PDOC_ITEM Current; + int id; + + Current = SYSLINK_LinkAtPt(infoPtr, pt, &id, TRUE); + if((Current != NULL) && (Current->u.Link.state & LIS_FOCUSED) && (infoPtr->MouseDownID == id)) + { + SYSLINK_SendParentNotify(infoPtr, NM_CLICK, Current, id); + } + } + + infoPtr->MouseDownID = -1; + + return 0; +} + +/*********************************************************************** + * SYSLINK_OnEnter + * Handles ENTER key events + */ +static BOOL SYSLINK_OnEnter (SYSLINK_INFO *infoPtr) +{ + if(infoPtr->HasFocus) + { + PDOC_ITEM Focus; + int id; + + Focus = SYSLINK_GetFocusLink(infoPtr, &id); + if(Focus != NULL) + { + SYSLINK_SendParentNotify(infoPtr, NM_RETURN, Focus, id); + return TRUE; + } + } + return FALSE; +} + +/*********************************************************************** + * SYSKEY_SelectNextPrevLink + * Changes the currently focused link + */ +static BOOL SYSKEY_SelectNextPrevLink (SYSLINK_INFO *infoPtr, BOOL Prev) +{ + if(infoPtr->HasFocus) + { + PDOC_ITEM Focus; + int id; + + Focus = SYSLINK_GetFocusLink(infoPtr, &id); + if(Focus != NULL) + { + PDOC_ITEM NewFocus, OldFocus; + + if(Prev) + NewFocus = SYSLINK_GetPrevLink(infoPtr, Focus); + else + NewFocus = SYSLINK_GetNextLink(infoPtr, Focus); + + if(NewFocus != NULL) + { + OldFocus = SYSLINK_SetFocusLink(infoPtr, NewFocus); + + if(OldFocus != NewFocus) + { + SYSLINK_RepaintLink(infoPtr, OldFocus); + } + SYSLINK_RepaintLink(infoPtr, NewFocus); + return TRUE; + } + } + } + return FALSE; +} + +/*********************************************************************** + * SYSKEY_SelectNextPrevLink + * Determines if there's a next or previous link to decide whether the control + * should capture the tab key message + */ +static BOOL SYSLINK_NoNextLink (SYSLINK_INFO *infoPtr, BOOL Prev) +{ + PDOC_ITEM Focus, NewFocus; + + Focus = SYSLINK_GetFocusLink(infoPtr, NULL); + if(Prev) + NewFocus = SYSLINK_GetPrevLink(infoPtr, Focus); + else + NewFocus = SYSLINK_GetNextLink(infoPtr, Focus); + + return NewFocus == NULL; +} + +/*********************************************************************** + * SysLinkWindowProc + */ +static LRESULT WINAPI SysLinkWindowProc(HWND hwnd, UINT message, + WPARAM wParam, LPARAM lParam) +{ + SYSLINK_INFO *infoPtr; + + TRACE("hwnd=%p msg=%04x wparam=%x lParam=%lx\n", hwnd, message, wParam, lParam); + + infoPtr = (SYSLINK_INFO *)GetWindowLongPtrW(hwnd, 0); + + if (!infoPtr && message != WM_CREATE) + return DefWindowProcW( hwnd, message, wParam, lParam ); + + switch(message) { + case WM_PAINT: + return SYSLINK_Paint (infoPtr, (HDC)wParam); + + case WM_SETCURSOR: + { + LHITTESTINFO ht; + DWORD mp = GetMessagePos(); + + ht.pt.x = (short)LOWORD(mp); + ht.pt.y = (short)HIWORD(mp); + + ScreenToClient(infoPtr->Self, &ht.pt); + if(SYSLINK_HitTest (infoPtr, &ht)) + { + SetCursor(LoadCursorW(0, (LPCWSTR)IDC_HAND)); + return TRUE; + } + /* let the default window proc handle this message */ + return DefWindowProcW(hwnd, message, wParam, lParam); + + } + + case WM_SIZE: + { + HDC hdc = GetDC(infoPtr->Self); + if(hdc != NULL) + { + SYSLINK_Render(infoPtr, hdc); + ReleaseDC(infoPtr->Self, hdc); + } + return 0; + } + + case WM_GETFONT: + return (LRESULT)infoPtr->Font; + + case WM_SETFONT: + return (LRESULT)SYSLINK_SetFont(infoPtr, (HFONT)wParam, (BOOL)lParam); + + case WM_SETTEXT: + SYSLINK_SetText(infoPtr, (LPWSTR)lParam); + return DefWindowProcW(hwnd, message, wParam, lParam); + + case WM_LBUTTONDOWN: + { + POINT pt; + pt.x = LOWORD(lParam); + pt.y = HIWORD(lParam); + return SYSLINK_LButtonDown(infoPtr, wParam, &pt); + } + case WM_LBUTTONUP: + { + POINT pt; + pt.x = LOWORD(lParam); + pt.y = HIWORD(lParam); + return SYSLINK_LButtonUp(infoPtr, wParam, &pt); + } + + case WM_KEYDOWN: + { + switch(wParam) + { + case VK_RETURN: + SYSLINK_OnEnter(infoPtr); + return 0; + case VK_TAB: + { + BOOL shift = GetKeyState(VK_SHIFT) & 0x8000; + SYSKEY_SelectNextPrevLink(infoPtr, shift); + return 0; + } + } + return DefWindowProcW(hwnd, message, wParam, lParam); + } + + case WM_GETDLGCODE: + { + LRESULT Ret = DLGC_HASSETSEL; + int vk = (lParam != 0 ? (int)((LPMSG)lParam)->wParam : 0); + switch(vk) + { + case VK_RETURN: + Ret |= DLGC_WANTMESSAGE; + break; + case VK_TAB: + { + BOOL shift = GetKeyState(VK_SHIFT) & 0x8000; + if(!SYSLINK_NoNextLink(infoPtr, shift)) + { + Ret |= DLGC_WANTTAB; + } + else + { + Ret |= DLGC_WANTCHARS; + } + break; + } + } + return Ret; + } + + case WM_NCHITTEST: + { + POINT pt; + RECT rc; + pt.x = LOWORD(lParam); + pt.y = HIWORD(lParam); + + GetClientRect(infoPtr->Self, &rc); + ScreenToClient(infoPtr->Self, &pt); + if(pt.x < 0 || pt.y < 0 || pt.x > rc.right || pt.y > rc.bottom) + { + return HTNOWHERE; + } + + if(SYSLINK_LinkAtPt(infoPtr, &pt, NULL, FALSE)) + { + return HTCLIENT; + } + + return HTTRANSPARENT; + } + + case LM_HITTEST: + return SYSLINK_HitTest(infoPtr, (PLHITTESTINFO)lParam); + + case LM_SETITEM: + return SYSLINK_SetItem(infoPtr, (PLITEM)lParam); + + case LM_GETITEM: + return SYSLINK_GetItem(infoPtr, (PLITEM)lParam); + + case LM_GETIDEALHEIGHT: + return SYSLINK_GetIdealHeight(infoPtr); + + case WM_SETFOCUS: + return SYSLINK_SetFocus(infoPtr, (HWND)wParam); + + case WM_KILLFOCUS: + return SYSLINK_KillFocus(infoPtr, (HWND)wParam); + + case WM_ENABLE: + infoPtr->Style &= ~WS_DISABLED; + infoPtr->Style |= (wParam ? 0 : WS_DISABLED); + InvalidateRect (infoPtr->Self, NULL, FALSE); + return 0; + + case WM_STYLECHANGED: + if (wParam == GWL_STYLE) + { + infoPtr->Style = ((LPSTYLESTRUCT)lParam)->styleNew; + + InvalidateRect(infoPtr->Self, NULL, TRUE); + } + return 0; + + case WM_CREATE: + /* allocate memory for info struct */ + infoPtr = Alloc (sizeof(SYSLINK_INFO)); + if (!infoPtr) return -1; + SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); + + /* initialize the info struct */ + infoPtr->Self = hwnd; + infoPtr->Notify = ((LPCREATESTRUCTW)lParam)->hwndParent; + infoPtr->Style = ((LPCREATESTRUCTW)lParam)->style; + infoPtr->Font = 0; + infoPtr->LinkFont = 0; + infoPtr->Items = NULL; + infoPtr->HasFocus = FALSE; + infoPtr->MouseDownID = -1; + infoPtr->TextColor = GetSysColor(COLOR_WINDOWTEXT); + infoPtr->LinkColor = GetSysColor(COLOR_HIGHLIGHT); + infoPtr->VisitedColor = GetSysColor(COLOR_HIGHLIGHT); + TRACE("SysLink Ctrl creation, hwnd=%p\n", hwnd); + SYSLINK_SetText(infoPtr, ((LPCREATESTRUCTW)lParam)->lpszName); + return 0; + + case WM_DESTROY: + TRACE("SysLink Ctrl destruction, hwnd=%p\n", hwnd); + SYSLINK_ClearDoc(infoPtr); + if(infoPtr->Font != 0) DeleteObject(infoPtr->Font); + if(infoPtr->LinkFont != 0) DeleteObject(infoPtr->LinkFont); + SetWindowLongPtrW(hwnd, 0, 0); + Free (infoPtr); + return 0; + + default: + if ((message >= WM_USER) && (message < WM_APP)) + ERR("unknown msg %04x wp=%04x lp=%08lx\n", message, wParam, lParam ); + return DefWindowProcW(hwnd, message, wParam, lParam); + } +} + + +/*********************************************************************** + * SYSLINK_Register [Internal] + * + * Registers the SysLink window class. + */ +VOID SYSLINK_Register (void) +{ + WNDCLASSW wndClass; + + ZeroMemory (&wndClass, sizeof(wndClass)); + wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW; + wndClass.lpfnWndProc = SysLinkWindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof (SYSLINK_INFO *); + wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); + wndClass.lpszClassName = WC_LINK; + + RegisterClassW (&wndClass); +} + + +/*********************************************************************** + * SYSLINK_Unregister [Internal] + * + * Unregisters the SysLink window class. + */ +VOID SYSLINK_Unregister (void) +{ + UnregisterClassW (WC_LINK, NULL); +} diff --git a/reactos/lib/comctl32/tab.c b/reactos/lib/comctl32/tab.c index 927046cfb76..043db7e2092 100644 --- a/reactos/lib/comctl32/tab.c +++ b/reactos/lib/comctl32/tab.c @@ -1,3224 +1,3224 @@ -/* - * Tab control - * - * Copyright 1998 Anders Carlsson - * Copyright 1999 Alex Priem - * Copyright 1999 Francis Beaudet - * Copyright 2003 Vitaliy Margolen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTES - * - * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on May. 20, 2005, by James Hawkins. - * - * Unless otherwise noted, we believe this code to be complete, as per - * the specification mentioned above. - * If you discover missing features, or bugs, please note them below. - * - * TODO: - * - * Styles: - * TCS_MULTISELECT - * TCS_RIGHT - * TCS_RIGHTJUSTIFY - * TCS_SCROLLOPPOSITE - * TCS_SINGLELINE - * TCIF_RTLREADING - * - * Extended Styles: - * TCS_EX_FLATSEPARATORS - * TCS_EX_REGISTERDROP - * - * States: - * TCIS_BUTTONPRESSED - * - * Notifications: - * NM_RELEASEDCAPTURE - * TCN_FOCUSCHANGE - * TCN_GETOBJECT - * TCN_KEYDOWN - * - * Messages: - * TCM_REMOVEIMAGE - * TCM_DESELECTALL - * TCM_GETEXTENDEDSTYLE - * TCM_SETEXTENDEDSTYLE - * - * Macros: - * TabCtrl_AdjustRect - * - */ - -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "comctl32.h" -#include "wine/debug.h" -#include - -WINE_DEFAULT_DEBUG_CHANNEL(tab); - -typedef struct -{ - UINT mask; - DWORD dwState; - LPWSTR pszText; - INT iImage; - RECT rect; /* bounding rectangle of the item relative to the - * leftmost item (the leftmost item, 0, would have a - * "left" member of 0 in this rectangle) - * - * additionally the top member holds the row number - * and bottom is unused and should be 0 */ - BYTE extra[1]; /* Space for caller supplied info, variable size */ -} TAB_ITEM; - -/* The size of a tab item depends on how much extra data is requested */ -#define TAB_ITEM_SIZE(infoPtr) (sizeof(TAB_ITEM) - sizeof(BYTE) + infoPtr->cbInfo) - -typedef struct -{ - HWND hwnd; /* Tab control window */ - HWND hwndNotify; /* notification window (parent) */ - UINT uNumItem; /* number of tab items */ - UINT uNumRows; /* number of tab rows */ - INT tabHeight; /* height of the tab row */ - INT tabWidth; /* width of tabs */ - INT tabMinWidth; /* minimum width of items */ - USHORT uHItemPadding; /* amount of horizontal padding, in pixels */ - USHORT uVItemPadding; /* amount of vertical padding, in pixels */ - USHORT uHItemPadding_s; /* Set amount of horizontal padding, in pixels */ - USHORT uVItemPadding_s; /* Set amount of vertical padding, in pixels */ - HFONT hFont; /* handle to the current font */ - HCURSOR hcurArrow; /* handle to the current cursor */ - HIMAGELIST himl; /* handle to an image list (may be 0) */ - HWND hwndToolTip; /* handle to tab's tooltip */ - INT leftmostVisible; /* Used for scrolling, this member contains - * the index of the first visible item */ - INT iSelected; /* the currently selected item */ - INT iHotTracked; /* the highlighted item under the mouse */ - INT uFocus; /* item which has the focus */ - TAB_ITEM* items; /* pointer to an array of TAB_ITEM's */ - BOOL DoRedraw; /* flag for redrawing when tab contents is changed*/ - BOOL needsScrolling; /* TRUE if the size of the tabs is greater than - * the size of the control */ - BOOL fHeightSet; /* was the height of the tabs explicitly set? */ - BOOL bUnicode; /* Unicode control? */ - HWND hwndUpDown; /* Updown control used for scrolling */ - INT cbInfo; /* Number of bytes of caller supplied info per tab */ -} TAB_INFO; - -/****************************************************************************** - * Positioning constants - */ -#define SELECTED_TAB_OFFSET 2 -#define ROUND_CORNER_SIZE 2 -#define DISPLAY_AREA_PADDINGX 2 -#define DISPLAY_AREA_PADDINGY 2 -#define CONTROL_BORDER_SIZEX 2 -#define CONTROL_BORDER_SIZEY 2 -#define BUTTON_SPACINGX 3 -#define BUTTON_SPACINGY 3 -#define FLAT_BTN_SPACINGX 8 -#define DEFAULT_TAB_WIDTH 96 - -#define TAB_GetInfoPtr(hwnd) ((TAB_INFO *)GetWindowLongPtrW(hwnd,0)) -/* Since items are variable sized, cannot directly access them */ -#define TAB_GetItem(info,i) \ - ((TAB_ITEM*)((LPBYTE)info->items + (i) * TAB_ITEM_SIZE(info))) - -/****************************************************************************** - * Hot-tracking timer constants - */ -#define TAB_HOTTRACK_TIMER 1 -#define TAB_HOTTRACK_TIMER_INTERVAL 100 /* milliseconds */ - -/****************************************************************************** - * Prototypes - */ -static void TAB_InvalidateTabArea(TAB_INFO *); -static void TAB_EnsureSelectionVisible(TAB_INFO *); -static void TAB_DrawItemInterior(TAB_INFO *, HDC, INT, RECT*); - -static BOOL -TAB_SendSimpleNotify (const TAB_INFO *infoPtr, UINT code) -{ - NMHDR nmhdr; - - nmhdr.hwndFrom = infoPtr->hwnd; - nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwnd, GWLP_ID); - nmhdr.code = code; - - return (BOOL) SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, - (WPARAM) nmhdr.idFrom, (LPARAM) &nmhdr); -} - -static void -TAB_RelayEvent (HWND hwndTip, HWND hwndMsg, UINT uMsg, - WPARAM wParam, LPARAM lParam) -{ - MSG msg; - - msg.hwnd = hwndMsg; - msg.message = uMsg; - msg.wParam = wParam; - msg.lParam = lParam; - msg.time = GetMessageTime (); - msg.pt.x = LOWORD(GetMessagePos ()); - msg.pt.y = HIWORD(GetMessagePos ()); - - SendMessageW (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg); -} - -static void -TAB_DumpItemExternalT(TCITEMW *pti, UINT iItem, BOOL isW) -{ - if (TRACE_ON(tab)) { - TRACE("external tab %d, mask=0x%08x, dwState=0x%08lx, dwStateMask=0x%08lx, cchTextMax=0x%08x\n", - iItem, pti->mask, pti->dwState, pti->dwStateMask, pti->cchTextMax); - TRACE("external tab %d, iImage=%d, lParam=0x%08lx, pszTextW=%s\n", - iItem, pti->iImage, pti->lParam, isW ? debugstr_w(pti->pszText) : debugstr_a((LPSTR)pti->pszText)); - } -} - -static void -TAB_DumpItemInternal(TAB_INFO *infoPtr, UINT iItem) -{ - if (TRACE_ON(tab)) { - TAB_ITEM *ti; - - ti = TAB_GetItem(infoPtr, iItem); - TRACE("tab %d, mask=0x%08x, dwState=0x%08lx, pszText=%s, iImage=%d\n", - iItem, ti->mask, ti->dwState, debugstr_w(ti->pszText), - ti->iImage); - TRACE("tab %d, rect.left=%ld, rect.top(row)=%ld\n", - iItem, ti->rect.left, ti->rect.top); - } -} - -/* RETURNS - * the index of the selected tab, or -1 if no tab is selected. */ -static inline LRESULT TAB_GetCurSel (const TAB_INFO *infoPtr) -{ - return infoPtr->iSelected; -} - -/* RETURNS - * the index of the tab item that has the focus - * NOTE - * we have not to return negative value - * TODO - * test for windows */ -static inline LRESULT -TAB_GetCurFocus (const TAB_INFO *infoPtr) -{ - if (infoPtr->uFocus<0) - { - FIXME("we have not to return negative value"); - return 0; - } - return infoPtr->uFocus; -} - -static inline LRESULT TAB_GetToolTips (const TAB_INFO *infoPtr) -{ - if (infoPtr == NULL) return 0; - return (LRESULT)infoPtr->hwndToolTip; -} - -static inline LRESULT TAB_SetCurSel (TAB_INFO *infoPtr, INT iItem) -{ - INT prevItem = -1; - - if (iItem >= 0 && iItem < infoPtr->uNumItem) { - prevItem=infoPtr->iSelected; - infoPtr->iSelected=iItem; - TAB_EnsureSelectionVisible(infoPtr); - TAB_InvalidateTabArea(infoPtr); - } - return prevItem; -} - -static LRESULT TAB_SetCurFocus (TAB_INFO *infoPtr, INT iItem) -{ - if (iItem < 0 || iItem >= infoPtr->uNumItem) return 0; - - if (GetWindowLongW(infoPtr->hwnd, GWL_STYLE) & TCS_BUTTONS) { - FIXME("Should set input focus\n"); - } else { - int oldFocus = infoPtr->uFocus; - if (infoPtr->iSelected != iItem || oldFocus == -1 ) { - infoPtr->uFocus = iItem; - if (oldFocus != -1) { - if (!TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING)) { - infoPtr->iSelected = iItem; - TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGE); - } - else - infoPtr->iSelected = iItem; - TAB_EnsureSelectionVisible(infoPtr); - TAB_InvalidateTabArea(infoPtr); - } - } - } - return 0; -} - -static inline LRESULT -TAB_SetToolTips (TAB_INFO *infoPtr, HWND hwndToolTip) -{ - if (infoPtr) - infoPtr->hwndToolTip = hwndToolTip; - return 0; -} - -static inline LRESULT -TAB_SetPadding (TAB_INFO *infoPtr, LPARAM lParam) -{ - if (infoPtr) - { - infoPtr->uHItemPadding_s=LOWORD(lParam); - infoPtr->uVItemPadding_s=HIWORD(lParam); - } - return 0; -} - -/****************************************************************************** - * TAB_InternalGetItemRect - * - * This method will calculate the rectangle representing a given tab item in - * client coordinates. This method takes scrolling into account. - * - * This method returns TRUE if the item is visible in the window and FALSE - * if it is completely outside the client area. - */ -static BOOL TAB_InternalGetItemRect( - const TAB_INFO* infoPtr, - INT itemIndex, - RECT* itemRect, - RECT* selectedRect) -{ - RECT tmpItemRect,clientRect; - LONG lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); - - /* Perform a sanity check and a trivial visibility check. */ - if ( (infoPtr->uNumItem <= 0) || - (itemIndex >= infoPtr->uNumItem) || - (!((lStyle & TCS_MULTILINE) || (lStyle & TCS_VERTICAL)) && (itemIndex < infoPtr->leftmostVisible)) ) - return FALSE; - - /* - * Avoid special cases in this procedure by assigning the "out" - * parameters if the caller didn't supply them - */ - if (itemRect == NULL) - itemRect = &tmpItemRect; - - /* Retrieve the unmodified item rect. */ - *itemRect = TAB_GetItem(infoPtr,itemIndex)->rect; - - /* calculate the times bottom and top based on the row */ - GetClientRect(infoPtr->hwnd, &clientRect); - - if ((lStyle & TCS_BOTTOM) && (lStyle & TCS_VERTICAL)) - { - itemRect->right = clientRect.right - SELECTED_TAB_OFFSET - itemRect->left * infoPtr->tabHeight - - ((lStyle & TCS_BUTTONS) ? itemRect->left * BUTTON_SPACINGX : 0); - itemRect->left = itemRect->right - infoPtr->tabHeight; - } - else if (lStyle & TCS_VERTICAL) - { - itemRect->left = clientRect.left + SELECTED_TAB_OFFSET + itemRect->left * infoPtr->tabHeight + - ((lStyle & TCS_BUTTONS) ? itemRect->left * BUTTON_SPACINGX : 0); - itemRect->right = itemRect->left + infoPtr->tabHeight; - } - else if (lStyle & TCS_BOTTOM) - { - itemRect->bottom = clientRect.bottom - itemRect->top * infoPtr->tabHeight - - ((lStyle & TCS_BUTTONS) ? itemRect->top * BUTTON_SPACINGY : SELECTED_TAB_OFFSET); - itemRect->top = itemRect->bottom - infoPtr->tabHeight; - } - else /* not TCS_BOTTOM and not TCS_VERTICAL */ - { - itemRect->top = clientRect.top + itemRect->top * infoPtr->tabHeight + - ((lStyle & TCS_BUTTONS) ? itemRect->top * BUTTON_SPACINGY : SELECTED_TAB_OFFSET); - itemRect->bottom = itemRect->top + infoPtr->tabHeight; - } - - /* - * "scroll" it to make sure the item at the very left of the - * tab control is the leftmost visible tab. - */ - if(lStyle & TCS_VERTICAL) - { - OffsetRect(itemRect, - 0, - -TAB_GetItem(infoPtr, infoPtr->leftmostVisible)->rect.top); - - /* - * Move the rectangle so the first item is slightly offset from - * the bottom of the tab control. - */ - OffsetRect(itemRect, - 0, - SELECTED_TAB_OFFSET); - - } else - { - OffsetRect(itemRect, - -TAB_GetItem(infoPtr, infoPtr->leftmostVisible)->rect.left, - 0); - - /* - * Move the rectangle so the first item is slightly offset from - * the left of the tab control. - */ - OffsetRect(itemRect, - SELECTED_TAB_OFFSET, - 0); - } - TRACE("item %d tab h=%d, rect=(%ld,%ld)-(%ld,%ld)\n", - itemIndex, infoPtr->tabHeight, - itemRect->left, itemRect->top, itemRect->right, itemRect->bottom); - - /* Now, calculate the position of the item as if it were selected. */ - if (selectedRect!=NULL) - { - CopyRect(selectedRect, itemRect); - - /* The rectangle of a selected item is a bit wider. */ - if(lStyle & TCS_VERTICAL) - InflateRect(selectedRect, 0, SELECTED_TAB_OFFSET); - else - InflateRect(selectedRect, SELECTED_TAB_OFFSET, 0); - - /* If it also a bit higher. */ - if ((lStyle & TCS_BOTTOM) && (lStyle & TCS_VERTICAL)) - { - selectedRect->left -= 2; /* the border is thicker on the right */ - selectedRect->right += SELECTED_TAB_OFFSET; - } - else if (lStyle & TCS_VERTICAL) - { - selectedRect->left -= SELECTED_TAB_OFFSET; - selectedRect->right += 1; - } - else if (lStyle & TCS_BOTTOM) - { - selectedRect->bottom += SELECTED_TAB_OFFSET; - } - else /* not TCS_BOTTOM and not TCS_VERTICAL */ - { - selectedRect->top -= SELECTED_TAB_OFFSET; - selectedRect->bottom -= 1; - } - } - - /* Check for visibility */ - if (lStyle & TCS_VERTICAL) - return (itemRect->top < clientRect.bottom) && (itemRect->bottom > clientRect.top); - else - return (itemRect->left < clientRect.right) && (itemRect->right > clientRect.left); -} - -static inline BOOL -TAB_GetItemRect(TAB_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - return TAB_InternalGetItemRect(infoPtr, (INT)wParam, (LPRECT)lParam, (LPRECT)NULL); -} - -/****************************************************************************** - * TAB_KeyUp - * - * This method is called to handle keyboard input - */ -static LRESULT TAB_KeyUp(TAB_INFO* infoPtr, WPARAM keyCode) -{ - int newItem = -1; - - switch (keyCode) - { - case VK_LEFT: - newItem = infoPtr->uFocus - 1; - break; - case VK_RIGHT: - newItem = infoPtr->uFocus + 1; - break; - } - - /* - * If we changed to a valid item, change the selection - */ - if (newItem >= 0 && - newItem < infoPtr->uNumItem && - infoPtr->uFocus != newItem) - { - if (!TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING)) - { - infoPtr->iSelected = newItem; - infoPtr->uFocus = newItem; - TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGE); - - TAB_EnsureSelectionVisible(infoPtr); - TAB_InvalidateTabArea(infoPtr); - } - } - - return 0; -} - -/****************************************************************************** - * TAB_FocusChanging - * - * This method is called whenever the focus goes in or out of this control - * it is used to update the visual state of the control. - */ -static void TAB_FocusChanging(const TAB_INFO *infoPtr) -{ - RECT selectedRect; - BOOL isVisible; - - /* - * Get the rectangle for the item. - */ - isVisible = TAB_InternalGetItemRect(infoPtr, - infoPtr->uFocus, - NULL, - &selectedRect); - - /* - * If the rectangle is not completely invisible, invalidate that - * portion of the window. - */ - if (isVisible) - { - TRACE("invalidate (%ld,%ld)-(%ld,%ld)\n", - selectedRect.left,selectedRect.top, - selectedRect.right,selectedRect.bottom); - InvalidateRect(infoPtr->hwnd, &selectedRect, TRUE); - } -} - -static INT TAB_InternalHitTest ( - TAB_INFO* infoPtr, - POINT pt, - UINT* flags) - -{ - RECT rect; - INT iCount; - - for (iCount = 0; iCount < infoPtr->uNumItem; iCount++) - { - TAB_InternalGetItemRect(infoPtr, iCount, &rect, NULL); - - if (PtInRect(&rect, pt)) - { - *flags = TCHT_ONITEM; - return iCount; - } - } - - *flags = TCHT_NOWHERE; - return -1; -} - -static inline LRESULT -TAB_HitTest (TAB_INFO *infoPtr, LPTCHITTESTINFO lptest) -{ - return TAB_InternalHitTest (infoPtr, lptest->pt, &lptest->flags); -} - -/****************************************************************************** - * TAB_NCHitTest - * - * Napster v2b5 has a tab control for its main navigation which has a client - * area that covers the whole area of the dialog pages. - * That's why it receives all msgs for that area and the underlying dialog ctrls - * are dead. - * So I decided that we should handle WM_NCHITTEST here and return - * HTTRANSPARENT if we don't hit the tab control buttons. - * FIXME: WM_NCHITTEST handling correct ? Fix it if you know that Windows - * doesn't do it that way. Maybe depends on tab control styles ? - */ -static inline LRESULT -TAB_NCHitTest (TAB_INFO *infoPtr, LPARAM lParam) -{ - POINT pt; - UINT dummyflag; - - pt.x = LOWORD(lParam); - pt.y = HIWORD(lParam); - ScreenToClient(infoPtr->hwnd, &pt); - - if (TAB_InternalHitTest(infoPtr, pt, &dummyflag) == -1) - return HTTRANSPARENT; - else - return HTCLIENT; -} - -static LRESULT -TAB_LButtonDown (TAB_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - POINT pt; - INT newItem, dummy; - - if (infoPtr->hwndToolTip) - TAB_RelayEvent (infoPtr->hwndToolTip, infoPtr->hwnd, - WM_LBUTTONDOWN, wParam, lParam); - - if (GetWindowLongW(infoPtr->hwnd, GWL_STYLE) & TCS_FOCUSONBUTTONDOWN ) { - SetFocus (infoPtr->hwnd); - } - - if (infoPtr->hwndToolTip) - TAB_RelayEvent (infoPtr->hwndToolTip, infoPtr->hwnd, - WM_LBUTTONDOWN, wParam, lParam); - - pt.x = (INT)LOWORD(lParam); - pt.y = (INT)HIWORD(lParam); - - newItem = TAB_InternalHitTest (infoPtr, pt, &dummy); - - TRACE("On Tab, item %d\n", newItem); - - if (newItem != -1 && infoPtr->iSelected != newItem) - { - if (!TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING)) - { - infoPtr->iSelected = newItem; - infoPtr->uFocus = newItem; - TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGE); - - TAB_EnsureSelectionVisible(infoPtr); - - TAB_InvalidateTabArea(infoPtr); - } - } - return 0; -} - -static inline LRESULT -TAB_LButtonUp (const TAB_INFO *infoPtr) -{ - TAB_SendSimpleNotify(infoPtr, NM_CLICK); - - return 0; -} - -static inline LRESULT -TAB_RButtonDown (const TAB_INFO *infoPtr) -{ - TAB_SendSimpleNotify(infoPtr, NM_RCLICK); - return 0; -} - -/****************************************************************************** - * TAB_DrawLoneItemInterior - * - * This calls TAB_DrawItemInterior. However, TAB_DrawItemInterior is normally - * called by TAB_DrawItem which is normally called by TAB_Refresh which sets - * up the device context and font. This routine does the same setup but - * only calls TAB_DrawItemInterior for the single specified item. - */ -static void -TAB_DrawLoneItemInterior(TAB_INFO* infoPtr, int iItem) -{ - HDC hdc = GetDC(infoPtr->hwnd); - RECT r, rC; - - /* Clip UpDown control to not draw over it */ - if (infoPtr->needsScrolling) - { - GetWindowRect(infoPtr->hwnd, &rC); - GetWindowRect(infoPtr->hwndUpDown, &r); - ExcludeClipRect(hdc, r.left - rC.left, r.top - rC.top, r.right - rC.left, r.bottom - rC.top); - } - TAB_DrawItemInterior(infoPtr, hdc, iItem, NULL); - ReleaseDC(infoPtr->hwnd, hdc); -} - -/****************************************************************************** - * TAB_HotTrackTimerProc - * - * When a mouse-move event causes a tab to be highlighted (hot-tracking), a - * timer is setup so we can check if the mouse is moved out of our window. - * (We don't get an event when the mouse leaves, the mouse-move events just - * stop being delivered to our window and just start being delivered to - * another window.) This function is called when the timer triggers so - * we can check if the mouse has left our window. If so, we un-highlight - * the hot-tracked tab. - */ -static void CALLBACK -TAB_HotTrackTimerProc - ( - HWND hwnd, /* handle of window for timer messages */ - UINT uMsg, /* WM_TIMER message */ - UINT idEvent, /* timer identifier */ - DWORD dwTime /* current system time */ - ) -{ - TAB_INFO* infoPtr = TAB_GetInfoPtr(hwnd); - - if (infoPtr != NULL && infoPtr->iHotTracked >= 0) - { - POINT pt; - - /* - ** If we can't get the cursor position, or if the cursor is outside our - ** window, we un-highlight the hot-tracked tab. Note that the cursor is - ** "outside" even if it is within our bounding rect if another window - ** overlaps. Note also that the case where the cursor stayed within our - ** window but has moved off the hot-tracked tab will be handled by the - ** WM_MOUSEMOVE event. - */ - if (!GetCursorPos(&pt) || WindowFromPoint(pt) != hwnd) - { - /* Redraw iHotTracked to look normal */ - INT iRedraw = infoPtr->iHotTracked; - infoPtr->iHotTracked = -1; - TAB_DrawLoneItemInterior(infoPtr, iRedraw); - - /* Kill this timer */ - KillTimer(hwnd, TAB_HOTTRACK_TIMER); - } - } -} - -/****************************************************************************** - * TAB_RecalcHotTrack - * - * If a tab control has the TCS_HOTTRACK style, then the tab under the mouse - * should be highlighted. This function determines which tab in a tab control, - * if any, is under the mouse and records that information. The caller may - * supply output parameters to receive the item number of the tab item which - * was highlighted but isn't any longer and of the tab item which is now - * highlighted but wasn't previously. The caller can use this information to - * selectively redraw those tab items. - * - * If the caller has a mouse position, it can supply it through the pos - * parameter. For example, TAB_MouseMove does this. Otherwise, the caller - * supplies NULL and this function determines the current mouse position - * itself. - */ -static void -TAB_RecalcHotTrack - ( - TAB_INFO* infoPtr, - const LPARAM* pos, - int* out_redrawLeave, - int* out_redrawEnter - ) -{ - int item = -1; - - - if (out_redrawLeave != NULL) - *out_redrawLeave = -1; - if (out_redrawEnter != NULL) - *out_redrawEnter = -1; - - if (GetWindowLongW(infoPtr->hwnd, GWL_STYLE) & TCS_HOTTRACK) - { - POINT pt; - UINT flags; - - if (pos == NULL) - { - GetCursorPos(&pt); - ScreenToClient(infoPtr->hwnd, &pt); - } - else - { - pt.x = LOWORD(*pos); - pt.y = HIWORD(*pos); - } - - item = TAB_InternalHitTest(infoPtr, pt, &flags); - } - - if (item != infoPtr->iHotTracked) - { - if (infoPtr->iHotTracked >= 0) - { - /* Mark currently hot-tracked to be redrawn to look normal */ - if (out_redrawLeave != NULL) - *out_redrawLeave = infoPtr->iHotTracked; - - if (item < 0) - { - /* Kill timer which forces recheck of mouse pos */ - KillTimer(infoPtr->hwnd, TAB_HOTTRACK_TIMER); - } - } - else - { - /* Start timer so we recheck mouse pos */ - UINT timerID = SetTimer - ( - infoPtr->hwnd, - TAB_HOTTRACK_TIMER, - TAB_HOTTRACK_TIMER_INTERVAL, - TAB_HotTrackTimerProc - ); - - if (timerID == 0) - return; /* Hot tracking not available */ - } - - infoPtr->iHotTracked = item; - - if (item >= 0) - { - /* Mark new hot-tracked to be redrawn to look highlighted */ - if (out_redrawEnter != NULL) - *out_redrawEnter = item; - } - } -} - -/****************************************************************************** - * TAB_MouseMove - * - * Handles the mouse-move event. Updates tooltips. Updates hot-tracking. - */ -static LRESULT -TAB_MouseMove (TAB_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - int redrawLeave; - int redrawEnter; - - if (infoPtr->hwndToolTip) - TAB_RelayEvent (infoPtr->hwndToolTip, infoPtr->hwnd, - WM_LBUTTONDOWN, wParam, lParam); - - /* Determine which tab to highlight. Redraw tabs which change highlight - ** status. */ - TAB_RecalcHotTrack(infoPtr, &lParam, &redrawLeave, &redrawEnter); - - if (redrawLeave != -1) - TAB_DrawLoneItemInterior(infoPtr, redrawLeave); - if (redrawEnter != -1) - TAB_DrawLoneItemInterior(infoPtr, redrawEnter); - - return 0; -} - -/****************************************************************************** - * TAB_AdjustRect - * - * Calculates the tab control's display area given the window rectangle or - * the window rectangle given the requested display rectangle. - */ -static LRESULT TAB_AdjustRect( - TAB_INFO *infoPtr, - WPARAM fLarger, - LPRECT prc) -{ - DWORD lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); - LONG *iRightBottom, *iLeftTop; - - TRACE ("hwnd=%p fLarger=%d (%ld,%ld)-(%ld,%ld)\n", infoPtr->hwnd, fLarger, prc->left, prc->top, prc->right, prc->bottom); - - if(lStyle & TCS_VERTICAL) - { - iRightBottom = &(prc->right); - iLeftTop = &(prc->left); - } - else - { - iRightBottom = &(prc->bottom); - iLeftTop = &(prc->top); - } - - if (fLarger) /* Go from display rectangle */ - { - /* Add the height of the tabs. */ - if (lStyle & TCS_BOTTOM) - *iRightBottom += infoPtr->tabHeight * infoPtr->uNumRows; - else - *iLeftTop -= infoPtr->tabHeight * infoPtr->uNumRows + - ((lStyle & TCS_BUTTONS)? 3 * (infoPtr->uNumRows - 1) : 0); - - /* Inflate the rectangle for the padding */ - InflateRect(prc, DISPLAY_AREA_PADDINGX, DISPLAY_AREA_PADDINGY); - - /* Inflate for the border */ - InflateRect(prc, CONTROL_BORDER_SIZEX, CONTROL_BORDER_SIZEY); - } - else /* Go from window rectangle. */ - { - /* Deflate the rectangle for the border */ - InflateRect(prc, -CONTROL_BORDER_SIZEX, -CONTROL_BORDER_SIZEY); - - /* Deflate the rectangle for the padding */ - InflateRect(prc, -DISPLAY_AREA_PADDINGX, -DISPLAY_AREA_PADDINGY); - - /* Remove the height of the tabs. */ - if (lStyle & TCS_BOTTOM) - *iRightBottom -= infoPtr->tabHeight * infoPtr->uNumRows; - else - *iLeftTop += (infoPtr->tabHeight) * infoPtr->uNumRows + - ((lStyle & TCS_BUTTONS)? 3 * (infoPtr->uNumRows - 1) : 0); - } - - return 0; -} - -/****************************************************************************** - * TAB_OnHScroll - * - * This method will handle the notification from the scroll control and - * perform the scrolling operation on the tab control. - */ -static LRESULT TAB_OnHScroll( - TAB_INFO *infoPtr, - int nScrollCode, - int nPos, - HWND hwndScroll) -{ - if(nScrollCode == SB_THUMBPOSITION && nPos != infoPtr->leftmostVisible) - { - if(nPos < infoPtr->leftmostVisible) - infoPtr->leftmostVisible--; - else - infoPtr->leftmostVisible++; - - TAB_RecalcHotTrack(infoPtr, NULL, NULL, NULL); - TAB_InvalidateTabArea(infoPtr); - SendMessageW(infoPtr->hwndUpDown, UDM_SETPOS, 0, - MAKELONG(infoPtr->leftmostVisible, 0)); - } - - return 0; -} - -/****************************************************************************** - * TAB_SetupScrolling - * - * This method will check the current scrolling state and make sure the - * scrolling control is displayed (or not). - */ -static void TAB_SetupScrolling( - HWND hwnd, - TAB_INFO* infoPtr, - const RECT* clientRect) -{ - static const WCHAR msctls_updown32W[] = { 'm','s','c','t','l','s','_','u','p','d','o','w','n','3','2',0 }; - static const WCHAR emptyW[] = { 0 }; - INT maxRange = 0; - DWORD lStyle = GetWindowLongW(hwnd, GWL_STYLE); - - if (infoPtr->needsScrolling) - { - RECT controlPos; - INT vsize, tabwidth; - - /* - * Calculate the position of the scroll control. - */ - if(lStyle & TCS_VERTICAL) - { - controlPos.right = clientRect->right; - controlPos.left = controlPos.right - 2 * GetSystemMetrics(SM_CXHSCROLL); - - if (lStyle & TCS_BOTTOM) - { - controlPos.top = clientRect->bottom - infoPtr->tabHeight; - controlPos.bottom = controlPos.top + GetSystemMetrics(SM_CYHSCROLL); - } - else - { - controlPos.bottom = clientRect->top + infoPtr->tabHeight; - controlPos.top = controlPos.bottom - GetSystemMetrics(SM_CYHSCROLL); - } - } - else - { - controlPos.right = clientRect->right; - controlPos.left = controlPos.right - 2 * GetSystemMetrics(SM_CXHSCROLL); - - if (lStyle & TCS_BOTTOM) - { - controlPos.top = clientRect->bottom - infoPtr->tabHeight; - controlPos.bottom = controlPos.top + GetSystemMetrics(SM_CYHSCROLL); - } - else - { - controlPos.bottom = clientRect->top + infoPtr->tabHeight; - controlPos.top = controlPos.bottom - GetSystemMetrics(SM_CYHSCROLL); - } - } - - /* - * If we don't have a scroll control yet, we want to create one. - * If we have one, we want to make sure it's positioned properly. - */ - if (infoPtr->hwndUpDown==0) - { - infoPtr->hwndUpDown = CreateWindowW(msctls_updown32W, emptyW, - WS_VISIBLE | WS_CHILD | UDS_HORZ, - controlPos.left, controlPos.top, - controlPos.right - controlPos.left, - controlPos.bottom - controlPos.top, - hwnd, NULL, NULL, NULL); - } - else - { - SetWindowPos(infoPtr->hwndUpDown, - NULL, - controlPos.left, controlPos.top, - controlPos.right - controlPos.left, - controlPos.bottom - controlPos.top, - SWP_SHOWWINDOW | SWP_NOZORDER); - } - - /* Now calculate upper limit of the updown control range. - * We do this by calculating how many tabs will be offscreen when the - * last tab is visible. - */ - if(infoPtr->uNumItem) - { - vsize = clientRect->right - (controlPos.right - controlPos.left + 1); - maxRange = infoPtr->uNumItem; - tabwidth = TAB_GetItem(infoPtr, infoPtr->uNumItem - 1)->rect.right; - - for(; maxRange > 0; maxRange--) - { - if(tabwidth - TAB_GetItem(infoPtr,maxRange - 1)->rect.left > vsize) - break; - } - - if(maxRange == infoPtr->uNumItem) - maxRange--; - } - } - else - { - /* If we once had a scroll control... hide it */ - if (infoPtr->hwndUpDown!=0) - ShowWindow(infoPtr->hwndUpDown, SW_HIDE); - } - if (infoPtr->hwndUpDown) - SendMessageW(infoPtr->hwndUpDown, UDM_SETRANGE32, 0, maxRange); -} - -/****************************************************************************** - * TAB_SetItemBounds - * - * This method will calculate the position rectangles of all the items in the - * control. The rectangle calculated starts at 0 for the first item in the - * list and ignores scrolling and selection. - * It also uses the current font to determine the height of the tab row and - * it checks if all the tabs fit in the client area of the window. If they - * don't, a scrolling control is added. - */ -static void TAB_SetItemBounds (TAB_INFO *infoPtr) -{ - LONG lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); - TEXTMETRICW fontMetrics; - UINT curItem; - INT curItemLeftPos; - INT curItemRowCount; - HFONT hFont, hOldFont; - HDC hdc; - RECT clientRect; - SIZE size; - INT iTemp; - RECT* rcItem; - INT iIndex; - INT icon_width = 0; - - /* - * We need to get text information so we need a DC and we need to select - * a font. - */ - hdc = GetDC(infoPtr->hwnd); - - hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT); - hOldFont = SelectObject (hdc, hFont); - - /* - * We will base the rectangle calculations on the client rectangle - * of the control. - */ - GetClientRect(infoPtr->hwnd, &clientRect); - - /* if TCS_VERTICAL then swap the height and width so this code places the - tabs along the top of the rectangle and we can just rotate them after - rather than duplicate all of the below code */ - if(lStyle & TCS_VERTICAL) - { - iTemp = clientRect.bottom; - clientRect.bottom = clientRect.right; - clientRect.right = iTemp; - } - - /* Now use hPadding and vPadding */ - infoPtr->uHItemPadding = infoPtr->uHItemPadding_s; - infoPtr->uVItemPadding = infoPtr->uVItemPadding_s; - - /* The leftmost item will be "0" aligned */ - curItemLeftPos = 0; - curItemRowCount = infoPtr->uNumItem ? 1 : 0; - - if (!(infoPtr->fHeightSet)) - { - int item_height; - int icon_height = 0; - - /* Use the current font to determine the height of a tab. */ - GetTextMetricsW(hdc, &fontMetrics); - - /* Get the icon height */ - if (infoPtr->himl) - ImageList_GetIconSize(infoPtr->himl, 0, &icon_height); - - /* Take the highest between font or icon */ - if (fontMetrics.tmHeight > icon_height) - item_height = fontMetrics.tmHeight + 2; - else - item_height = icon_height; - - /* - * Make sure there is enough space for the letters + icon + growing the - * selected item + extra space for the selected item. - */ - infoPtr->tabHeight = item_height + - ((lStyle & TCS_BUTTONS) ? 2 : 1) * - infoPtr->uVItemPadding; - - TRACE("tabH=%d, tmH=%ld, iconh=%d\n", - infoPtr->tabHeight, fontMetrics.tmHeight, icon_height); - } - - TRACE("client right=%ld\n", clientRect.right); - - /* Get the icon width */ - if (infoPtr->himl) - { - ImageList_GetIconSize(infoPtr->himl, &icon_width, 0); - - if (lStyle & TCS_FIXEDWIDTH) - icon_width += 4; - else - /* Add padding if icon is present */ - icon_width += infoPtr->uHItemPadding; - } - - for (curItem = 0; curItem < infoPtr->uNumItem; curItem++) - { - TAB_ITEM *curr = TAB_GetItem(infoPtr, curItem); - - /* Set the leftmost position of the tab. */ - curr->rect.left = curItemLeftPos; - - if ((lStyle & TCS_FIXEDWIDTH) || !curr->pszText) - { - curr->rect.right = curr->rect.left + - max(infoPtr->tabWidth, icon_width); - } - else - { - int num = 2; - - /* Calculate how wide the tab is depending on the text it contains */ - GetTextExtentPoint32W(hdc, curr->pszText, - lstrlenW(curr->pszText), &size); - - curr->rect.right = curr->rect.left + size.cx + icon_width + - num * infoPtr->uHItemPadding; - TRACE("for <%s>, l,r=%ld,%ld, num=%d\n", - debugstr_w(curr->pszText), curr->rect.left, curr->rect.right, num); - } - - /* - * Check if this is a multiline tab control and if so - * check to see if we should wrap the tabs - * - * Wrap all these tabs. We will arrange them evenly later. - * - */ - - if (((lStyle & TCS_MULTILINE) || (lStyle & TCS_VERTICAL)) && - (curr->rect.right > - (clientRect.right - CONTROL_BORDER_SIZEX - DISPLAY_AREA_PADDINGX))) - { - curr->rect.right -= curr->rect.left; - - curr->rect.left = 0; - curItemRowCount++; - TRACE("wrapping <%s>, l,r=%ld,%ld\n", debugstr_w(curr->pszText), - curr->rect.left, curr->rect.right); - } - - curr->rect.bottom = 0; - curr->rect.top = curItemRowCount - 1; - - TRACE("TextSize: %li\n", size.cx); - TRACE("Rect: T %li, L %li, B %li, R %li\n", curr->rect.top, - curr->rect.left, curr->rect.bottom, curr->rect.right); - - /* - * The leftmost position of the next item is the rightmost position - * of this one. - */ - if (lStyle & TCS_BUTTONS) - { - curItemLeftPos = curr->rect.right + BUTTON_SPACINGX; - if (lStyle & TCS_FLATBUTTONS) - curItemLeftPos += FLAT_BTN_SPACINGX; - } - else - curItemLeftPos = curr->rect.right; - } - - if (!((lStyle & TCS_MULTILINE) || (lStyle & TCS_VERTICAL))) - { - /* - * Check if we need a scrolling control. - */ - infoPtr->needsScrolling = (curItemLeftPos + (2 * SELECTED_TAB_OFFSET) > - clientRect.right); - - /* Don't need scrolling, then update infoPtr->leftmostVisible */ - if(!infoPtr->needsScrolling) - infoPtr->leftmostVisible = 0; - } - else - { - /* - * No scrolling in Multiline or Vertical styles. - */ - infoPtr->needsScrolling = FALSE; - infoPtr->leftmostVisible = 0; - } - TAB_SetupScrolling(infoPtr->hwnd, infoPtr, &clientRect); - - /* Set the number of rows */ - infoPtr->uNumRows = curItemRowCount; - - /* Arrange all tabs evenly if style says so */ - if (!(lStyle & TCS_RAGGEDRIGHT) && ((lStyle & TCS_MULTILINE) || (lStyle & TCS_VERTICAL)) && (infoPtr->uNumItem > 0)) - { - INT tabPerRow,remTab,iRow; - UINT iItm; - INT iCount=0; - - /* - * Ok windows tries to even out the rows. place the same - * number of tabs in each row. So lets give that a shot - */ - - tabPerRow = infoPtr->uNumItem / (infoPtr->uNumRows); - remTab = infoPtr->uNumItem % (infoPtr->uNumRows); - - for (iItm=0,iRow=0,iCount=0,curItemLeftPos=0; - iItmuNumItem; - iItm++,iCount++) - { - /* normalize the current rect */ - TAB_ITEM *curr = TAB_GetItem(infoPtr, iItm); - - /* shift the item to the left side of the clientRect */ - curr->rect.right -= curr->rect.left; - curr->rect.left = 0; - - TRACE("r=%ld, cl=%d, cl.r=%ld, iCount=%d, iRow=%d, uNumRows=%d, remTab=%d, tabPerRow=%d\n", - curr->rect.right, curItemLeftPos, clientRect.right, - iCount, iRow, infoPtr->uNumRows, remTab, tabPerRow); - - /* if we have reached the maximum number of tabs on this row */ - /* move to the next row, reset our current item left position and */ - /* the count of items on this row */ - - if (lStyle & TCS_VERTICAL) { - /* Vert: Add the remaining tabs in the *last* remainder rows */ - if (iCount >= ((iRow>=(INT)infoPtr->uNumRows - remTab)?tabPerRow + 1:tabPerRow)) { - iRow++; - curItemLeftPos = 0; - iCount = 0; - } - } else { - /* Horz: Add the remaining tabs in the *first* remainder rows */ - if (iCount >= ((iRowrect.left += curItemLeftPos; - curr->rect.right += curItemLeftPos; - curr->rect.top = iRow; - if (lStyle & TCS_BUTTONS) - { - curItemLeftPos = curr->rect.right + 1; - if (lStyle & TCS_FLATBUTTONS) - curItemLeftPos += FLAT_BTN_SPACINGX; - } - else - curItemLeftPos = curr->rect.right; - - TRACE("arranging <%s>, l,r=%ld,%ld, row=%ld\n", - debugstr_w(curr->pszText), curr->rect.left, - curr->rect.right, curr->rect.top); - } - - /* - * Justify the rows - */ - { - INT widthDiff, iIndexStart=0, iIndexEnd=0; - INT remainder; - INT iCount=0; - - while(iIndexStart < infoPtr->uNumItem) - { - TAB_ITEM *start = TAB_GetItem(infoPtr, iIndexStart); - - /* - * find the index of the row - */ - /* find the first item on the next row */ - for (iIndexEnd=iIndexStart; - (iIndexEnd < infoPtr->uNumItem) && - (TAB_GetItem(infoPtr, iIndexEnd)->rect.top == - start->rect.top) ; - iIndexEnd++) - /* intentionally blank */; - - /* - * we need to justify these tabs so they fill the whole given - * client area - * - */ - /* find the amount of space remaining on this row */ - widthDiff = clientRect.right - (2 * SELECTED_TAB_OFFSET) - - TAB_GetItem(infoPtr, iIndexEnd - 1)->rect.right; - - /* iCount is the number of tab items on this row */ - iCount = iIndexEnd - iIndexStart; - - if (iCount > 1) - { - remainder = widthDiff % iCount; - widthDiff = widthDiff / iCount; - /* add widthDiff/iCount, or extra space/items on row, to each item on this row */ - for (iIndex=iIndexStart, iCount=0; iIndex < iIndexEnd; iIndex++, iCount++) - { - TAB_ITEM *item = TAB_GetItem(infoPtr, iIndex); - - item->rect.left += iCount * widthDiff; - item->rect.right += (iCount + 1) * widthDiff; - - TRACE("adjusting 1 <%s>, l,r=%ld,%ld\n", - debugstr_w(item->pszText), - item->rect.left, item->rect.right); - - } - TAB_GetItem(infoPtr, iIndex - 1)->rect.right += remainder; - } - else /* we have only one item on this row, make it take up the entire row */ - { - start->rect.left = clientRect.left; - start->rect.right = clientRect.right - 4; - - TRACE("adjusting 2 <%s>, l,r=%ld,%ld\n", - debugstr_w(start->pszText), - start->rect.left, start->rect.right); - - } - - - iIndexStart = iIndexEnd; - } - } - } - - /* if TCS_VERTICAL rotate the tabs so they are along the side of the clientRect */ - if(lStyle & TCS_VERTICAL) - { - RECT rcOriginal; - for(iIndex = 0; iIndex < infoPtr->uNumItem; iIndex++) - { - rcItem = &TAB_GetItem(infoPtr, iIndex)->rect; - - rcOriginal = *rcItem; - - /* this is rotating the items by 90 degrees clockwise around the center of the control */ - rcItem->top = (rcOriginal.left - clientRect.left); - rcItem->bottom = rcItem->top + (rcOriginal.right - rcOriginal.left); - rcItem->left = rcOriginal.top; - rcItem->right = rcOriginal.bottom; - } - } - - TAB_EnsureSelectionVisible(infoPtr); - TAB_RecalcHotTrack(infoPtr, NULL, NULL, NULL); - - /* Cleanup */ - SelectObject (hdc, hOldFont); - ReleaseDC (infoPtr->hwnd, hdc); -} - - -static void -TAB_EraseTabInterior - ( - TAB_INFO* infoPtr, - HDC hdc, - INT iItem, - RECT* drawRect - ) -{ - LONG lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); - HBRUSH hbr = CreateSolidBrush (comctl32_color.clrBtnFace); - BOOL deleteBrush = TRUE; - RECT rTemp = *drawRect; - - InflateRect(&rTemp, -2, -2); - if (lStyle & TCS_BUTTONS) - { - if (iItem == infoPtr->iSelected) - { - /* Background color */ - if (!(lStyle & TCS_OWNERDRAWFIXED)) - { - DeleteObject(hbr); - hbr = GetSysColorBrush(COLOR_SCROLLBAR); - - SetTextColor(hdc, comctl32_color.clr3dFace); - SetBkColor(hdc, comctl32_color.clr3dHilight); - - /* if COLOR_WINDOW happens to be the same as COLOR_3DHILIGHT - * we better use 0x55aa bitmap brush to make scrollbar's background - * look different from the window background. - */ - if (comctl32_color.clr3dHilight == comctl32_color.clrWindow) - hbr = COMCTL32_hPattern55AABrush; - - deleteBrush = FALSE; - } - FillRect(hdc, &rTemp, hbr); - } - else /* ! selected */ - { - if (lStyle & TCS_FLATBUTTONS) - { - FillRect(hdc, drawRect, hbr); - if (iItem == infoPtr->iHotTracked) - DrawEdge(hdc, drawRect, EDGE_RAISED, BF_SOFT|BF_RECT); - } - else - FillRect(hdc, &rTemp, hbr); - } - - } - else /* !TCS_BUTTONS */ - { - FillRect(hdc, &rTemp, hbr); - } - - /* Cleanup */ - if (deleteBrush) DeleteObject(hbr); -} - -/****************************************************************************** - * TAB_DrawItemInterior - * - * This method is used to draw the interior (text and icon) of a single tab - * into the tab control. - */ -static void -TAB_DrawItemInterior - ( - TAB_INFO* infoPtr, - HDC hdc, - INT iItem, - RECT* drawRect - ) -{ - LONG lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); - - RECT localRect; - - HPEN htextPen; - HPEN holdPen; - INT oldBkMode; - HFONT hOldFont; - -/* if (drawRect == NULL) */ - { - BOOL isVisible; - RECT itemRect; - RECT selectedRect; - - /* - * Get the rectangle for the item. - */ - isVisible = TAB_InternalGetItemRect(infoPtr, iItem, &itemRect, &selectedRect); - if (!isVisible) - return; - - /* - * Make sure drawRect points to something valid; simplifies code. - */ - drawRect = &localRect; - - /* - * This logic copied from the part of TAB_DrawItem which draws - * the tab background. It's important to keep it in sync. I - * would have liked to avoid code duplication, but couldn't figure - * out how without making spaghetti of TAB_DrawItem. - */ - if (iItem == infoPtr->iSelected) - *drawRect = selectedRect; - else - *drawRect = itemRect; - - if (lStyle & TCS_BUTTONS) - { - if (iItem == infoPtr->iSelected) - { - drawRect->left += 4; - drawRect->top += 4; - drawRect->right -= 4; - drawRect->bottom -= 1; - } - else - { - drawRect->left += 2; - drawRect->top += 2; - drawRect->right -= 2; - drawRect->bottom -= 2; - } - } - else - { - if ((lStyle & TCS_VERTICAL) && (lStyle & TCS_BOTTOM)) - { - if (iItem != infoPtr->iSelected) - { - drawRect->left += 2; - drawRect->top += 2; - drawRect->bottom -= 2; - } - } - else if (lStyle & TCS_VERTICAL) - { - if (iItem == infoPtr->iSelected) - { - drawRect->right += 1; - } - else - { - drawRect->top += 2; - drawRect->right -= 2; - drawRect->bottom -= 2; - } - } - else if (lStyle & TCS_BOTTOM) - { - if (iItem == infoPtr->iSelected) - { - drawRect->top -= 2; - } - else - { - InflateRect(drawRect, -2, -2); - drawRect->bottom += 2; - } - } - else - { - if (iItem == infoPtr->iSelected) - { - drawRect->bottom += 3; - } - else - { - drawRect->bottom -= 2; - InflateRect(drawRect, -2, 0); - } - } - } - } - TRACE("drawRect=(%ld,%ld)-(%ld,%ld)\n", - drawRect->left, drawRect->top, drawRect->right, drawRect->bottom); - - /* Clear interior */ - TAB_EraseTabInterior (infoPtr, hdc, iItem, drawRect); - - /* Draw the focus rectangle */ - if (!(lStyle & TCS_FOCUSNEVER) && - (GetFocus() == infoPtr->hwnd) && - (iItem == infoPtr->uFocus) ) - { - RECT rFocus = *drawRect; - InflateRect(&rFocus, -3, -3); - if (lStyle & TCS_BOTTOM && !(lStyle & TCS_VERTICAL)) - rFocus.top -= 3; - if (lStyle & TCS_BUTTONS) - { - rFocus.left -= 3; - rFocus.top -= 3; - } - - DrawFocusRect(hdc, &rFocus); - } - - /* - * Text pen - */ - htextPen = CreatePen( PS_SOLID, 1, GetSysColor(COLOR_BTNTEXT) ); - holdPen = SelectObject(hdc, htextPen); - hOldFont = SelectObject(hdc, infoPtr->hFont); - - /* - * Setup for text output - */ - oldBkMode = SetBkMode(hdc, TRANSPARENT); - SetTextColor(hdc, (((iItem == infoPtr->iHotTracked) && !(lStyle & TCS_FLATBUTTONS)) | - (TAB_GetItem(infoPtr, iItem)->dwState & TCIS_HIGHLIGHTED)) ? - comctl32_color.clrHighlight : comctl32_color.clrBtnText); - - /* - * if owner draw, tell the owner to draw - */ - if ((lStyle & TCS_OWNERDRAWFIXED) && GetParent(infoPtr->hwnd)) - { - DRAWITEMSTRUCT dis; - UINT id; - - drawRect->top += 2; - drawRect->right -= 1; - if ( iItem == infoPtr->iSelected ) - { - drawRect->right -= 1; - drawRect->left += 1; - } - - /* - * get the control id - */ - id = (UINT)GetWindowLongPtrW( infoPtr->hwnd, GWLP_ID ); - - /* - * put together the DRAWITEMSTRUCT - */ - dis.CtlType = ODT_TAB; - dis.CtlID = id; - dis.itemID = iItem; - dis.itemAction = ODA_DRAWENTIRE; - dis.itemState = 0; - if ( iItem == infoPtr->iSelected ) - dis.itemState |= ODS_SELECTED; - if (infoPtr->uFocus == iItem) - dis.itemState |= ODS_FOCUS; - dis.hwndItem = infoPtr->hwnd; - dis.hDC = hdc; - CopyRect(&dis.rcItem,drawRect); - dis.itemData = (ULONG_PTR)TAB_GetItem(infoPtr, iItem)->extra; - - /* - * send the draw message - */ - SendMessageW( infoPtr->hwndNotify, WM_DRAWITEM, (WPARAM)id, (LPARAM)&dis ); - } - else - { - TAB_ITEM *item = TAB_GetItem(infoPtr, iItem); - RECT rcTemp; - RECT rcImage; - - /* used to center the icon and text in the tab */ - RECT rcText; - INT center_offset_h, center_offset_v; - - /* set rcImage to drawRect, we will use top & left in our ImageList_Draw call */ - rcImage = *drawRect; - - rcTemp = *drawRect; - - rcText.left = rcText.top = rcText.right = rcText.bottom = 0; - - /* get the rectangle that the text fits in */ - if (item->pszText) - { - DrawTextW(hdc, item->pszText, -1, &rcText, DT_CALCRECT); - } - /* - * If not owner draw, then do the drawing ourselves. - * - * Draw the icon. - */ - if (infoPtr->himl && (item->mask & TCIF_IMAGE)) - { - INT cx; - INT cy; - - ImageList_GetIconSize(infoPtr->himl, &cx, &cy); - - if(lStyle & TCS_VERTICAL) - { - center_offset_h = ((drawRect->bottom - drawRect->top) - (cy + infoPtr->uHItemPadding + (rcText.right - rcText.left))) / 2; - center_offset_v = ((drawRect->right - drawRect->left) - (cx + infoPtr->uVItemPadding)) / 2; - } - else - { - center_offset_h = ((drawRect->right - drawRect->left) - (cx + infoPtr->uHItemPadding + (rcText.right - rcText.left))) / 2; - center_offset_v = ((drawRect->bottom - drawRect->top) - (cy + infoPtr->uVItemPadding)) / 2; - } - - if (lStyle & TCS_FIXEDWIDTH && lStyle & (TCS_FORCELABELLEFT | TCS_FORCEICONLEFT)) - center_offset_h = infoPtr->uHItemPadding; - - if (center_offset_h < 2) - center_offset_h = 2; - - if (center_offset_v < 0) - center_offset_v = 0; - - TRACE("for <%s>, c_o_h=%d, c_o_v=%d, draw=(%ld,%ld)-(%ld,%ld), textlen=%ld\n", - debugstr_w(item->pszText), center_offset_h, center_offset_v, - drawRect->left, drawRect->top, drawRect->right, drawRect->bottom, - (rcText.right-rcText.left)); - - if((lStyle & TCS_VERTICAL) && (lStyle & TCS_BOTTOM)) - { - rcImage.top = drawRect->top + center_offset_h; - /* if tab is TCS_VERTICAL and TCS_BOTTOM, the text is drawn from the */ - /* right side of the tab, but the image still uses the left as its x position */ - /* this keeps the image always drawn off of the same side of the tab */ - rcImage.left = drawRect->right - cx - center_offset_v; - drawRect->top += cy + infoPtr->uHItemPadding; - } - else if(lStyle & TCS_VERTICAL) - { - rcImage.top = drawRect->bottom - cy - center_offset_h; - rcImage.left = drawRect->left + center_offset_v; - drawRect->bottom -= cy + infoPtr->uHItemPadding; - } - else /* normal style, whether TCS_BOTTOM or not */ - { - rcImage.left = drawRect->left + center_offset_h; - rcImage.top = drawRect->top + center_offset_v; - drawRect->left += cx + infoPtr->uHItemPadding; - } - - TRACE("drawing image=%d, left=%ld, top=%ld\n", - item->iImage, rcImage.left, rcImage.top-1); - ImageList_Draw - ( - infoPtr->himl, - item->iImage, - hdc, - rcImage.left, - rcImage.top, - ILD_NORMAL - ); - } - - /* Now position text */ - if (lStyle & TCS_FIXEDWIDTH && lStyle & TCS_FORCELABELLEFT) - center_offset_h = infoPtr->uHItemPadding; - else - if(lStyle & TCS_VERTICAL) - center_offset_h = ((drawRect->bottom - drawRect->top) - (rcText.right - rcText.left)) / 2; - else - center_offset_h = ((drawRect->right - drawRect->left) - (rcText.right - rcText.left)) / 2; - - if(lStyle & TCS_VERTICAL) - { - if(lStyle & TCS_BOTTOM) - drawRect->top+=center_offset_h; - else - drawRect->bottom-=center_offset_h; - - center_offset_v = ((drawRect->right - drawRect->left) - (rcText.bottom - rcText.top)) / 2; - } - else - { - drawRect->left += center_offset_h; - center_offset_v = ((drawRect->bottom - drawRect->top) - (rcText.bottom - rcText.top)) / 2; - } - - /* if an item is selected, the text is shifted up instead of down */ - if (iItem == infoPtr->iSelected) - center_offset_v -= infoPtr->uVItemPadding / 2; - else - center_offset_v += infoPtr->uVItemPadding / 2; - - if (center_offset_v < 0) - center_offset_v = 0; - - if(lStyle & TCS_VERTICAL) - drawRect->left += center_offset_v; - else - drawRect->top += center_offset_v; - - /* Draw the text */ - if(lStyle & TCS_VERTICAL) /* if we are vertical rotate the text and each character */ - { - static const WCHAR ArialW[] = { 'A','r','i','a','l',0 }; - LOGFONTW logfont; - HFONT hFont = 0; - INT nEscapement = 900; - INT nOrientation = 900; - - if(lStyle & TCS_BOTTOM) - { - nEscapement = -900; - nOrientation = -900; - } - - /* to get a font with the escapement and orientation we are looking for, we need to */ - /* call CreateFontIndirectA, which requires us to set the values of the logfont we pass in */ - if (!GetObjectW((infoPtr->hFont) ? - infoPtr->hFont : GetStockObject(SYSTEM_FONT), - sizeof(LOGFONTW),&logfont)) - { - INT iPointSize = 9; - - lstrcpyW(logfont.lfFaceName, ArialW); - logfont.lfHeight = -MulDiv(iPointSize, GetDeviceCaps(hdc, LOGPIXELSY), - 72); - logfont.lfWeight = FW_NORMAL; - logfont.lfItalic = 0; - logfont.lfUnderline = 0; - logfont.lfStrikeOut = 0; - } - - logfont.lfEscapement = nEscapement; - logfont.lfOrientation = nOrientation; - hFont = CreateFontIndirectW(&logfont); - SelectObject(hdc, hFont); - - if (item->pszText) - { - ExtTextOutW(hdc, - (lStyle & TCS_BOTTOM) ? drawRect->right : drawRect->left, - (!(lStyle & TCS_BOTTOM)) ? drawRect->bottom : drawRect->top, - ETO_CLIPPED, - drawRect, - item->pszText, - lstrlenW(item->pszText), - 0); - } - - DeleteObject(hFont); - } - else - { - TRACE("for <%s>, c_o_h=%d, c_o_v=%d, draw=(%ld,%ld)-(%ld,%ld), textlen=%ld\n", - debugstr_w(item->pszText), center_offset_h, center_offset_v, - drawRect->left, drawRect->top, drawRect->right, drawRect->bottom, - (rcText.right-rcText.left)); - if (item->pszText) - { - DrawTextW - ( - hdc, - item->pszText, - lstrlenW(item->pszText), - drawRect, - DT_LEFT | DT_SINGLELINE - ); - } - } - - *drawRect = rcTemp; /* restore drawRect */ - } - - /* - * Cleanup - */ - SelectObject(hdc, hOldFont); - SetBkMode(hdc, oldBkMode); - SelectObject(hdc, holdPen); - DeleteObject( htextPen ); -} - -/****************************************************************************** - * TAB_DrawItem - * - * This method is used to draw a single tab into the tab control. - */ -static void TAB_DrawItem( - TAB_INFO *infoPtr, - HDC hdc, - INT iItem) -{ - LONG lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); - RECT itemRect; - RECT selectedRect; - BOOL isVisible; - RECT r, fillRect, r1; - INT clRight = 0; - INT clBottom = 0; - COLORREF bkgnd, corner; - - /* - * Get the rectangle for the item. - */ - isVisible = TAB_InternalGetItemRect(infoPtr, - iItem, - &itemRect, - &selectedRect); - - if (isVisible) - { - RECT rUD, rC; - - /* Clip UpDown control to not draw over it */ - if (infoPtr->needsScrolling) - { - GetWindowRect(infoPtr->hwnd, &rC); - GetWindowRect(infoPtr->hwndUpDown, &rUD); - ExcludeClipRect(hdc, rUD.left - rC.left, rUD.top - rC.top, rUD.right - rC.left, rUD.bottom - rC.top); - } - - /* If you need to see what the control is doing, - * then override these variables. They will change what - * fill colors are used for filling the tabs, and the - * corners when drawing the edge. - */ - bkgnd = comctl32_color.clrBtnFace; - corner = comctl32_color.clrBtnFace; - - if (lStyle & TCS_BUTTONS) - { - /* Get item rectangle */ - r = itemRect; - - /* Separators between flat buttons */ - if (lStyle & TCS_FLATBUTTONS) - { - r1 = r; - r1.right += (FLAT_BTN_SPACINGX -2); - DrawEdge(hdc, &r1, EDGE_ETCHED, BF_RIGHT); - } - - if (iItem == infoPtr->iSelected) - { - DrawEdge(hdc, &r, EDGE_SUNKEN, BF_SOFT|BF_RECT); - - OffsetRect(&r, 1, 1); - } - else /* ! selected */ - { - if (!(lStyle & TCS_FLATBUTTONS)) - DrawEdge(hdc, &r, EDGE_RAISED, BF_SOFT|BF_RECT); - } - } - else /* !TCS_BUTTONS */ - { - /* We draw a rectangle of different sizes depending on the selection - * state. */ - if (iItem == infoPtr->iSelected) { - RECT rect; - GetClientRect (infoPtr->hwnd, &rect); - clRight = rect.right; - clBottom = rect.bottom; - r = selectedRect; - } - else - r = itemRect; - - /* - * Erase the background. (Delay it but setup rectangle.) - * This is necessary when drawing the selected item since it is larger - * than the others, it might overlap with stuff already drawn by the - * other tabs - */ - fillRect = r; - - if(lStyle & TCS_VERTICAL) - { - /* These are for adjusting the drawing of a Selected tab */ - /* The initial values are for the normal case of non-Selected */ - int ZZ = 1; /* Do not strech if selected */ - if (iItem == infoPtr->iSelected) { - ZZ = 0; - - /* if leftmost draw the line longer */ - if(selectedRect.top == 0) - fillRect.top += CONTROL_BORDER_SIZEY; - /* if rightmost draw the line longer */ - if(selectedRect.bottom == clBottom) - fillRect.bottom -= CONTROL_BORDER_SIZEY; - } - - if (lStyle & TCS_BOTTOM) - { - /* Adjust both rectangles to match native */ - r.left += (1-ZZ); - - TRACE(" item=%d, fill=(%ld,%ld)-(%ld,%ld), edge=(%ld,%ld)-(%ld,%ld)\n", - iItem, - fillRect.left,fillRect.top,fillRect.right,fillRect.bottom, - r.left,r.top,r.right,r.bottom); - - /* Clear interior */ - SetBkColor(hdc, bkgnd); - ExtTextOutW(hdc, 0, 0, 2, &fillRect, NULL, 0, 0); - - /* Draw rectangular edge around tab */ - DrawEdge(hdc, &r, EDGE_RAISED, BF_SOFT|BF_RIGHT|BF_TOP|BF_BOTTOM); - - /* Now erase the top corner and draw diagonal edge */ - SetBkColor(hdc, corner); - r1.left = r.right - ROUND_CORNER_SIZE - 1; - r1.top = r.top; - r1.right = r.right; - r1.bottom = r1.top + ROUND_CORNER_SIZE; - ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0); - r1.right--; - DrawEdge(hdc, &r1, EDGE_RAISED, BF_SOFT|BF_DIAGONAL_ENDTOPLEFT); - - /* Now erase the bottom corner and draw diagonal edge */ - r1.left = r.right - ROUND_CORNER_SIZE - 1; - r1.bottom = r.bottom; - r1.right = r.right; - r1.top = r1.bottom - ROUND_CORNER_SIZE; - ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0); - r1.right--; - DrawEdge(hdc, &r1, EDGE_RAISED, BF_SOFT|BF_DIAGONAL_ENDBOTTOMLEFT); - - if ((iItem == infoPtr->iSelected) && (selectedRect.top == 0)) { - r1 = r; - r1.right = r1.left; - r1.left--; - DrawEdge(hdc, &r1, EDGE_RAISED, BF_SOFT|BF_TOP); - } - - } - else - { - TRACE(" item=%d, fill=(%ld,%ld)-(%ld,%ld), edge=(%ld,%ld)-(%ld,%ld)\n", - iItem, - fillRect.left,fillRect.top,fillRect.right,fillRect.bottom, - r.left,r.top,r.right,r.bottom); - - /* Clear interior */ - SetBkColor(hdc, bkgnd); - ExtTextOutW(hdc, 0, 0, 2, &fillRect, NULL, 0, 0); - - /* Draw rectangular edge around tab */ - DrawEdge(hdc, &r, EDGE_RAISED, BF_SOFT|BF_LEFT|BF_TOP|BF_BOTTOM); - - /* Now erase the top corner and draw diagonal edge */ - SetBkColor(hdc, corner); - r1.left = r.left; - r1.top = r.top; - r1.right = r1.left + ROUND_CORNER_SIZE + 1; - r1.bottom = r1.top + ROUND_CORNER_SIZE; - ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0); - r1.left++; - DrawEdge(hdc, &r1, EDGE_RAISED, BF_SOFT|BF_DIAGONAL_ENDTOPRIGHT); - - /* Now erase the bottom corner and draw diagonal edge */ - r1.left = r.left; - r1.bottom = r.bottom; - r1.right = r1.left + ROUND_CORNER_SIZE + 1; - r1.top = r1.bottom - ROUND_CORNER_SIZE; - ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0); - r1.left++; - DrawEdge(hdc, &r1, EDGE_SUNKEN, BF_DIAGONAL_ENDTOPLEFT); - } - } - else /* ! TCS_VERTICAL */ - { - /* These are for adjusting the drawing of a Selected tab */ - /* The initial values are for the normal case of non-Selected */ - if (iItem == infoPtr->iSelected) { - /* if leftmost draw the line longer */ - if(selectedRect.left == 0) - fillRect.left += CONTROL_BORDER_SIZEX; - /* if rightmost draw the line longer */ - if(selectedRect.right == clRight) - fillRect.right -= CONTROL_BORDER_SIZEX; - } - - if (lStyle & TCS_BOTTOM) - { - /* Adjust both rectangles for topmost row */ - if (TAB_GetItem(infoPtr, iItem)->rect.top == infoPtr->uNumRows-1) - { - fillRect.top -= 2; - r.top -= 1; - } - - TRACE(" item=%d, fill=(%ld,%ld)-(%ld,%ld), edge=(%ld,%ld)-(%ld,%ld)\n", - iItem, - fillRect.left,fillRect.top,fillRect.right,fillRect.bottom, - r.left,r.top,r.right,r.bottom); - - /* Clear interior */ - SetBkColor(hdc, bkgnd); - ExtTextOutW(hdc, 0, 0, 2, &fillRect, NULL, 0, 0); - - /* Draw rectangular edge around tab */ - DrawEdge(hdc, &r, EDGE_RAISED, BF_SOFT|BF_LEFT|BF_BOTTOM|BF_RIGHT); - - /* Now erase the righthand corner and draw diagonal edge */ - SetBkColor(hdc, corner); - r1.left = r.right - ROUND_CORNER_SIZE; - r1.bottom = r.bottom; - r1.right = r.right; - r1.top = r1.bottom - ROUND_CORNER_SIZE - 1; - ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0); - r1.bottom--; - DrawEdge(hdc, &r1, EDGE_RAISED, BF_SOFT|BF_DIAGONAL_ENDBOTTOMLEFT); - - /* Now erase the lefthand corner and draw diagonal edge */ - r1.left = r.left; - r1.bottom = r.bottom; - r1.right = r1.left + ROUND_CORNER_SIZE; - r1.top = r1.bottom - ROUND_CORNER_SIZE - 1; - ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0); - r1.bottom--; - DrawEdge(hdc, &r1, EDGE_RAISED, BF_SOFT|BF_DIAGONAL_ENDTOPLEFT); - - if (iItem == infoPtr->iSelected) - { - r.top += 2; - r.left += 1; - if (selectedRect.left == 0) - { - r1 = r; - r1.bottom = r1.top; - r1.top--; - DrawEdge(hdc, &r1, EDGE_RAISED, BF_SOFT|BF_LEFT); - } - } - - } - else - { - /* Adjust both rectangles for bottommost row */ - if (TAB_GetItem(infoPtr, iItem)->rect.top == infoPtr->uNumRows-1) - { - fillRect.bottom += 3; - r.bottom += 2; - } - - TRACE(" item=%d, fill=(%ld,%ld)-(%ld,%ld), edge=(%ld,%ld)-(%ld,%ld)\n", - iItem, - fillRect.left,fillRect.top,fillRect.right,fillRect.bottom, - r.left,r.top,r.right,r.bottom); - - /* Clear interior */ - SetBkColor(hdc, bkgnd); - ExtTextOutW(hdc, 0, 0, 2, &fillRect, NULL, 0, 0); - - /* Draw rectangular edge around tab */ - DrawEdge(hdc, &r, EDGE_RAISED, BF_SOFT|BF_LEFT|BF_TOP|BF_RIGHT); - - /* Now erase the righthand corner and draw diagonal edge */ - SetBkColor(hdc, corner); - r1.left = r.right - ROUND_CORNER_SIZE; - r1.top = r.top; - r1.right = r.right; - r1.bottom = r1.top + ROUND_CORNER_SIZE + 1; - ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0); - r1.top++; - DrawEdge(hdc, &r1, EDGE_RAISED, BF_SOFT|BF_DIAGONAL_ENDBOTTOMRIGHT); - - /* Now erase the lefthand corner and draw diagonal edge */ - r1.left = r.left; - r1.top = r.top; - r1.right = r1.left + ROUND_CORNER_SIZE; - r1.bottom = r1.top + ROUND_CORNER_SIZE + 1; - ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0); - r1.top++; - DrawEdge(hdc, &r1, EDGE_RAISED, BF_SOFT|BF_DIAGONAL_ENDTOPRIGHT); - } - } - } - - TAB_DumpItemInternal(infoPtr, iItem); - - /* This modifies r to be the text rectangle. */ - TAB_DrawItemInterior(infoPtr, hdc, iItem, &r); - } -} - -/****************************************************************************** - * TAB_DrawBorder - * - * This method is used to draw the raised border around the tab control - * "content" area. - */ -static void TAB_DrawBorder (TAB_INFO *infoPtr, HDC hdc) -{ - RECT rect; - DWORD lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); - - GetClientRect (infoPtr->hwnd, &rect); - - /* - * Adjust for the style - */ - - if (infoPtr->uNumItem) - { - if ((lStyle & TCS_BOTTOM) && !(lStyle & TCS_VERTICAL)) - rect.bottom -= infoPtr->tabHeight * infoPtr->uNumRows + CONTROL_BORDER_SIZEX; - else if((lStyle & TCS_BOTTOM) && (lStyle & TCS_VERTICAL)) - rect.right -= infoPtr->tabHeight * infoPtr->uNumRows + CONTROL_BORDER_SIZEX; - else if(lStyle & TCS_VERTICAL) - rect.left += infoPtr->tabHeight * infoPtr->uNumRows + CONTROL_BORDER_SIZEX; - else /* not TCS_VERTICAL and not TCS_BOTTOM */ - rect.top += infoPtr->tabHeight * infoPtr->uNumRows + CONTROL_BORDER_SIZEX; - } - - TRACE("border=(%ld,%ld)-(%ld,%ld)\n", - rect.left, rect.top, rect.right, rect.bottom); - - DrawEdge(hdc, &rect, EDGE_RAISED, BF_SOFT|BF_RECT); -} - -/****************************************************************************** - * TAB_Refresh - * - * This method repaints the tab control.. - */ -static void TAB_Refresh (TAB_INFO *infoPtr, HDC hdc) -{ - HFONT hOldFont; - INT i; - - if (!infoPtr->DoRedraw) - return; - - hOldFont = SelectObject (hdc, infoPtr->hFont); - - if (GetWindowLongW(infoPtr->hwnd, GWL_STYLE) & TCS_BUTTONS) - { - for (i = 0; i < infoPtr->uNumItem; i++) - TAB_DrawItem (infoPtr, hdc, i); - } - else - { - /* Draw all the non selected item first */ - for (i = 0; i < infoPtr->uNumItem; i++) - { - if (i != infoPtr->iSelected) - TAB_DrawItem (infoPtr, hdc, i); - } - - /* Now, draw the border, draw it before the selected item - * since the selected item overwrites part of the border. */ - TAB_DrawBorder (infoPtr, hdc); - - /* Then, draw the selected item */ - TAB_DrawItem (infoPtr, hdc, infoPtr->iSelected); - - /* If we haven't set the current focus yet, set it now. - * Only happens when we first paint the tab controls */ - if (infoPtr->uFocus == -1) - TAB_SetCurFocus(infoPtr, infoPtr->iSelected); - } - - SelectObject (hdc, hOldFont); -} - -static inline DWORD TAB_GetRowCount (const TAB_INFO *infoPtr) -{ - return infoPtr->uNumRows; -} - -static inline LRESULT TAB_SetRedraw (TAB_INFO *infoPtr, BOOL doRedraw) -{ - infoPtr->DoRedraw = doRedraw; - return 0; -} - -/****************************************************************************** - * TAB_EnsureSelectionVisible - * - * This method will make sure that the current selection is completely - * visible by scrolling until it is. - */ -static void TAB_EnsureSelectionVisible( - TAB_INFO* infoPtr) -{ - INT iSelected = infoPtr->iSelected; - LONG lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); - INT iOrigLeftmostVisible = infoPtr->leftmostVisible; - - /* set the items row to the bottommost row or topmost row depending on - * style */ - if ((infoPtr->uNumRows > 1) && !(lStyle & TCS_BUTTONS)) - { - TAB_ITEM *selected = TAB_GetItem(infoPtr, iSelected); - INT newselected; - INT iTargetRow; - - if(lStyle & TCS_VERTICAL) - newselected = selected->rect.left; - else - newselected = selected->rect.top; - - /* the target row is always (number of rows - 1) - as row 0 is furthest from the clientRect */ - iTargetRow = infoPtr->uNumRows - 1; - - if (newselected != iTargetRow) - { - UINT i; - if(lStyle & TCS_VERTICAL) - { - for (i=0; i < infoPtr->uNumItem; i++) - { - /* move everything in the row of the selected item to the iTargetRow */ - TAB_ITEM *item = TAB_GetItem(infoPtr, i); - - if (item->rect.left == newselected ) - item->rect.left = iTargetRow; - else - { - if (item->rect.left > newselected) - item->rect.left-=1; - } - } - } - else - { - for (i=0; i < infoPtr->uNumItem; i++) - { - TAB_ITEM *item = TAB_GetItem(infoPtr, i); - - if (item->rect.top == newselected ) - item->rect.top = iTargetRow; - else - { - if (item->rect.top > newselected) - item->rect.top-=1; - } - } - } - TAB_RecalcHotTrack(infoPtr, NULL, NULL, NULL); - } - } - - /* - * Do the trivial cases first. - */ - if ( (!infoPtr->needsScrolling) || - (infoPtr->hwndUpDown==0) || (lStyle & TCS_VERTICAL)) - return; - - if (infoPtr->leftmostVisible >= iSelected) - { - infoPtr->leftmostVisible = iSelected; - } - else - { - TAB_ITEM *selected = TAB_GetItem(infoPtr, iSelected); - RECT r; - INT width; - UINT i; - - /* Calculate the part of the client area that is visible */ - GetClientRect(infoPtr->hwnd, &r); - width = r.right; - - GetClientRect(infoPtr->hwndUpDown, &r); - width -= r.right; - - if ((selected->rect.right - - selected->rect.left) >= width ) - { - /* Special case: width of selected item is greater than visible - * part of control. - */ - infoPtr->leftmostVisible = iSelected; - } - else - { - for (i = infoPtr->leftmostVisible; i < infoPtr->uNumItem; i++) - { - if ((selected->rect.right - TAB_GetItem(infoPtr, i)->rect.left) < width) - break; - } - infoPtr->leftmostVisible = i; - } - } - - if (infoPtr->leftmostVisible != iOrigLeftmostVisible) - TAB_RecalcHotTrack(infoPtr, NULL, NULL, NULL); - - SendMessageW(infoPtr->hwndUpDown, UDM_SETPOS, 0, - MAKELONG(infoPtr->leftmostVisible, 0)); -} - -/****************************************************************************** - * TAB_InvalidateTabArea - * - * This method will invalidate the portion of the control that contains the - * tabs. It is called when the state of the control changes and needs - * to be redisplayed - */ -static void TAB_InvalidateTabArea(TAB_INFO* infoPtr) -{ - RECT clientRect, rInvalidate, rAdjClient; - DWORD lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); - INT lastRow = infoPtr->uNumRows - 1; - RECT rect; - - if (lastRow < 0) return; - - GetClientRect(infoPtr->hwnd, &clientRect); - rInvalidate = clientRect; - rAdjClient = clientRect; - - TAB_AdjustRect(infoPtr, 0, &rAdjClient); - - TAB_InternalGetItemRect(infoPtr, infoPtr->uNumItem-1 , &rect, NULL); - if ((lStyle & TCS_BOTTOM) && (lStyle & TCS_VERTICAL)) - { - rInvalidate.left = rAdjClient.right; - if (infoPtr->uNumRows == 1) - rInvalidate.bottom = clientRect.top + rect.bottom + 2 * SELECTED_TAB_OFFSET; - } - else if(lStyle & TCS_VERTICAL) - { - rInvalidate.right = rAdjClient.left; - if (infoPtr->uNumRows == 1) - rInvalidate.bottom = clientRect.top + rect.bottom + 2 * SELECTED_TAB_OFFSET; - } - else if (lStyle & TCS_BOTTOM) - { - rInvalidate.top = rAdjClient.bottom; - if (infoPtr->uNumRows == 1) - rInvalidate.right = clientRect.left + rect.right + 2 * SELECTED_TAB_OFFSET; - } - else - { - rInvalidate.bottom = rAdjClient.top; - if (infoPtr->uNumRows == 1) - rInvalidate.right = clientRect.left + rect.right + 2 * SELECTED_TAB_OFFSET; - } - - /* Punch out the updown control */ - if (infoPtr->needsScrolling && (rInvalidate.right > 0)) { - RECT r; - GetClientRect(infoPtr->hwndUpDown, &r); - if (rInvalidate.right > clientRect.right - r.left) - rInvalidate.right = rInvalidate.right - (r.right - r.left); - else - rInvalidate.right = clientRect.right - r.left; - } - - TRACE("invalidate (%ld,%ld)-(%ld,%ld)\n", - rInvalidate.left, rInvalidate.top, - rInvalidate.right, rInvalidate.bottom); - - InvalidateRect(infoPtr->hwnd, &rInvalidate, TRUE); -} - -static inline LRESULT TAB_Paint (TAB_INFO *infoPtr, HDC hdcPaint) -{ - HDC hdc; - PAINTSTRUCT ps; - - if (hdcPaint) - hdc = hdcPaint; - else - { - hdc = BeginPaint (infoPtr->hwnd, &ps); - TRACE("erase %d, rect=(%ld,%ld)-(%ld,%ld)\n", - ps.fErase, - ps.rcPaint.left,ps.rcPaint.top,ps.rcPaint.right,ps.rcPaint.bottom); - } - - TAB_Refresh (infoPtr, hdc); - - if (!hdcPaint) - EndPaint (infoPtr->hwnd, &ps); - - return 0; -} - -static LRESULT -TAB_InsertItemT (TAB_INFO *infoPtr, WPARAM wParam, LPARAM lParam, BOOL bUnicode) -{ - TAB_ITEM *item; - TCITEMW *pti; - INT iItem; - RECT rect; - - GetClientRect (infoPtr->hwnd, &rect); - TRACE("Rect: %p T %li, L %li, B %li, R %li\n", infoPtr->hwnd, - rect.top, rect.left, rect.bottom, rect.right); - - pti = (TCITEMW *)lParam; - iItem = (INT)wParam; - - if (iItem < 0) return -1; - if (iItem > infoPtr->uNumItem) - iItem = infoPtr->uNumItem; - - TAB_DumpItemExternalT(pti, iItem, bUnicode); - - - if (infoPtr->uNumItem == 0) { - infoPtr->items = Alloc (TAB_ITEM_SIZE(infoPtr)); - infoPtr->uNumItem++; - infoPtr->iSelected = 0; - } - else { - LPBYTE oldItems = (LPBYTE)infoPtr->items; - - infoPtr->uNumItem++; - infoPtr->items = Alloc (TAB_ITEM_SIZE(infoPtr) * infoPtr->uNumItem); - - /* pre insert copy */ - if (iItem > 0) { - memcpy (infoPtr->items, oldItems, - iItem * TAB_ITEM_SIZE(infoPtr)); - } - - /* post insert copy */ - if (iItem < infoPtr->uNumItem - 1) { - memcpy (TAB_GetItem(infoPtr, iItem + 1), - oldItems + iItem * TAB_ITEM_SIZE(infoPtr), - (infoPtr->uNumItem - iItem - 1) * TAB_ITEM_SIZE(infoPtr)); - - } - - if (iItem <= infoPtr->iSelected) - infoPtr->iSelected++; - - Free (oldItems); - } - - item = TAB_GetItem(infoPtr, iItem); - - item->mask = pti->mask; - item->pszText = NULL; - - if (pti->mask & TCIF_TEXT) - { - if (bUnicode) - Str_SetPtrW (&item->pszText, pti->pszText); - else - Str_SetPtrAtoW (&item->pszText, (LPSTR)pti->pszText); - } - - if (pti->mask & TCIF_IMAGE) - item->iImage = pti->iImage; - else - item->iImage = -1; - - if (pti->mask & TCIF_PARAM) - memcpy(item->extra, &pti->lParam, infoPtr->cbInfo); - else - memset(item->extra, 0, infoPtr->cbInfo); - - TAB_SetItemBounds(infoPtr); - if (infoPtr->uNumItem > 1) - TAB_InvalidateTabArea(infoPtr); - else - InvalidateRect(infoPtr->hwnd, NULL, TRUE); - - TRACE("[%p]: added item %d %s\n", - infoPtr->hwnd, iItem, debugstr_w(item->pszText)); - - return iItem; -} - -static LRESULT -TAB_SetItemSize (TAB_INFO *infoPtr, LPARAM lParam) -{ - LONG lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); - LONG lResult = 0; - BOOL bNeedPaint = FALSE; - - lResult = MAKELONG(infoPtr->tabWidth, infoPtr->tabHeight); - - /* UNDOCUMENTED: If requested Width or Height is 0 this means that program wants to use auto size. */ - if (lStyle & TCS_FIXEDWIDTH && (infoPtr->tabWidth != (INT)LOWORD(lParam))) - { - infoPtr->tabWidth = max((INT)LOWORD(lParam), infoPtr->tabMinWidth); - bNeedPaint = TRUE; - } - - if (infoPtr->tabHeight != (INT)HIWORD(lParam)) - { - if ((infoPtr->fHeightSet = ((INT)HIWORD(lParam) != 0))) - infoPtr->tabHeight = (INT)HIWORD(lParam); - - bNeedPaint = TRUE; - } - TRACE("was h=%d,w=%d, now h=%d,w=%d\n", - HIWORD(lResult), LOWORD(lResult), - infoPtr->tabHeight, infoPtr->tabWidth); - - if (bNeedPaint) - { - TAB_SetItemBounds(infoPtr); - RedrawWindow(infoPtr->hwnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW); - } - - return lResult; -} - -static inline LRESULT TAB_SetMinTabWidth (TAB_INFO *infoPtr, INT cx) -{ - INT oldcx = 0; - - TRACE("(%p,%d)\n", infoPtr, cx); - - if (infoPtr) { - oldcx = infoPtr->tabMinWidth; - infoPtr->tabMinWidth = (cx==-1)?DEFAULT_TAB_WIDTH:cx; - } - - return oldcx; -} - -static inline LRESULT -TAB_HighlightItem (TAB_INFO *infoPtr, INT iItem, BOOL fHighlight) -{ - LPDWORD lpState; - - TRACE("(%p,%d,%s)\n", infoPtr, iItem, fHighlight ? "true" : "false"); - - if (!infoPtr || iItem < 0 || iItem >= infoPtr->uNumItem) - return FALSE; - - lpState = &TAB_GetItem(infoPtr, iItem)->dwState; - - if (fHighlight) - *lpState |= TCIS_HIGHLIGHTED; - else - *lpState &= ~TCIS_HIGHLIGHTED; - - return TRUE; -} - -static LRESULT -TAB_SetItemT (TAB_INFO *infoPtr, INT iItem, LPTCITEMW tabItem, BOOL bUnicode) -{ - TAB_ITEM *wineItem; - - TRACE("(%p,%d,%p,%s)\n", infoPtr, iItem, tabItem, bUnicode ? "true" : "false"); - - if (iItem < 0 || iItem >= infoPtr->uNumItem) - return FALSE; - - TAB_DumpItemExternalT(tabItem, iItem, bUnicode); - - wineItem = TAB_GetItem(infoPtr, iItem); - - if (tabItem->mask & TCIF_IMAGE) - wineItem->iImage = tabItem->iImage; - - if (tabItem->mask & TCIF_PARAM) - memcpy(wineItem->extra, &tabItem->lParam, infoPtr->cbInfo); - - if (tabItem->mask & TCIF_RTLREADING) - FIXME("TCIF_RTLREADING\n"); - - if (tabItem->mask & TCIF_STATE) - wineItem->dwState = tabItem->dwState; - - if (tabItem->mask & TCIF_TEXT) - { - if (wineItem->pszText) - { - Free(wineItem->pszText); - wineItem->pszText = NULL; - } - if (bUnicode) - Str_SetPtrW(&wineItem->pszText, tabItem->pszText); - else - Str_SetPtrAtoW(&wineItem->pszText, (LPSTR)tabItem->pszText); - } - - /* Update and repaint tabs */ - TAB_SetItemBounds(infoPtr); - TAB_InvalidateTabArea(infoPtr); - - return TRUE; -} - -static inline LRESULT TAB_GetItemCount (const TAB_INFO *infoPtr) -{ - return infoPtr->uNumItem; -} - - -static LRESULT -TAB_GetItemT (TAB_INFO *infoPtr, INT iItem, LPTCITEMW tabItem, BOOL bUnicode) -{ - TAB_ITEM *wineItem; - - TRACE("(%p,%d,%p,%s)\n", infoPtr, iItem, tabItem, bUnicode ? "true" : "false"); - - if (iItem < 0 || iItem >= infoPtr->uNumItem) - return FALSE; - - wineItem = TAB_GetItem(infoPtr, iItem); - - if (tabItem->mask & TCIF_IMAGE) - tabItem->iImage = wineItem->iImage; - - if (tabItem->mask & TCIF_PARAM) - memcpy(&tabItem->lParam, wineItem->extra, infoPtr->cbInfo); - - if (tabItem->mask & TCIF_RTLREADING) - FIXME("TCIF_RTLREADING\n"); - - if (tabItem->mask & TCIF_STATE) - tabItem->dwState = wineItem->dwState; - - if (tabItem->mask & TCIF_TEXT) - { - if (bUnicode) - Str_GetPtrW (wineItem->pszText, tabItem->pszText, tabItem->cchTextMax); - else - Str_GetPtrWtoA (wineItem->pszText, (LPSTR)tabItem->pszText, tabItem->cchTextMax); - } - - TAB_DumpItemExternalT(tabItem, iItem, bUnicode); - - return TRUE; -} - - -static LRESULT TAB_DeleteItem (TAB_INFO *infoPtr, INT iItem) -{ - BOOL bResult = FALSE; - - TRACE("(%p, %d)\n", infoPtr, iItem); - - if ((iItem >= 0) && (iItem < infoPtr->uNumItem)) - { - TAB_ITEM *item = TAB_GetItem(infoPtr, iItem); - LPBYTE oldItems = (LPBYTE)infoPtr->items; - - TAB_InvalidateTabArea(infoPtr); - - if ((item->mask & TCIF_TEXT) && item->pszText) - Free(item->pszText); - - infoPtr->uNumItem--; - - if (!infoPtr->uNumItem) - { - infoPtr->items = NULL; - if (infoPtr->iHotTracked >= 0) - { - KillTimer(infoPtr->hwnd, TAB_HOTTRACK_TIMER); - infoPtr->iHotTracked = -1; - } - } - else - { - infoPtr->items = Alloc(TAB_ITEM_SIZE(infoPtr) * infoPtr->uNumItem); - - if (iItem > 0) - memcpy(infoPtr->items, oldItems, iItem * TAB_ITEM_SIZE(infoPtr)); - - if (iItem < infoPtr->uNumItem) - memcpy(TAB_GetItem(infoPtr, iItem), - oldItems + (iItem + 1) * TAB_ITEM_SIZE(infoPtr), - (infoPtr->uNumItem - iItem) * TAB_ITEM_SIZE(infoPtr)); - - if (iItem <= infoPtr->iHotTracked) - { - /* When tabs move left/up, the hot track item may change */ - FIXME("Recalc hot track"); - } - } - Free(oldItems); - - /* Readjust the selected index */ - if ((iItem == infoPtr->iSelected) && (iItem > 0)) - infoPtr->iSelected--; - - if (iItem < infoPtr->iSelected) - infoPtr->iSelected--; - - if (infoPtr->uNumItem == 0) - infoPtr->iSelected = -1; - - /* Reposition and repaint tabs */ - TAB_SetItemBounds(infoPtr); - - bResult = TRUE; - } - - return bResult; -} - -static inline LRESULT TAB_DeleteAllItems (TAB_INFO *infoPtr) -{ - TRACE("(%p)\n", infoPtr); - while (infoPtr->uNumItem) - TAB_DeleteItem (infoPtr, 0); - return TRUE; -} - - -static inline LRESULT TAB_GetFont (const TAB_INFO *infoPtr) -{ - TRACE("(%p) returning %p\n", infoPtr, infoPtr->hFont); - return (LRESULT)infoPtr->hFont; -} - -static inline LRESULT TAB_SetFont (TAB_INFO *infoPtr, HFONT hNewFont) -{ - TRACE("(%p,%p)\n", infoPtr, hNewFont); - - infoPtr->hFont = hNewFont; - - TAB_SetItemBounds(infoPtr); - - TAB_InvalidateTabArea(infoPtr); - - return 0; -} - - -static inline LRESULT TAB_GetImageList (const TAB_INFO *infoPtr) -{ - TRACE("\n"); - return (LRESULT)infoPtr->himl; -} - -static inline LRESULT TAB_SetImageList (TAB_INFO *infoPtr, HIMAGELIST himlNew) -{ - HIMAGELIST himlPrev = infoPtr->himl; - TRACE("\n"); - infoPtr->himl = himlNew; - return (LRESULT)himlPrev; -} - -static inline LRESULT TAB_GetUnicodeFormat (const TAB_INFO *infoPtr) -{ - return infoPtr->bUnicode; -} - -static inline LRESULT TAB_SetUnicodeFormat (TAB_INFO *infoPtr, BOOL bUnicode) -{ - BOOL bTemp = infoPtr->bUnicode; - - infoPtr->bUnicode = bUnicode; - - return bTemp; -} - -static inline LRESULT TAB_Size (TAB_INFO *infoPtr) -{ -/* I'm not really sure what the following code was meant to do. - This is what it is doing: - When WM_SIZE is sent with SIZE_RESTORED, the control - gets positioned in the top left corner. - - RECT parent_rect; - HWND parent; - UINT uPosFlags,cx,cy; - - uPosFlags=0; - if (!wParam) { - parent = GetParent (hwnd); - GetClientRect(parent, &parent_rect); - cx=LOWORD (lParam); - cy=HIWORD (lParam); - if (GetWindowLongW(hwnd, GWL_STYLE) & CCS_NORESIZE) - uPosFlags |= (SWP_NOSIZE | SWP_NOMOVE); - - SetWindowPos (hwnd, 0, parent_rect.left, parent_rect.top, - cx, cy, uPosFlags | SWP_NOZORDER); - } else { - FIXME("WM_SIZE flag %x %lx not handled\n", wParam, lParam); - } */ - - /* Recompute the size/position of the tabs. */ - TAB_SetItemBounds (infoPtr); - - /* Force a repaint of the control. */ - InvalidateRect(infoPtr->hwnd, NULL, TRUE); - - return 0; -} - - -static LRESULT TAB_Create (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TAB_INFO *infoPtr; - TEXTMETRICW fontMetrics; - HDC hdc; - HFONT hOldFont; - DWORD dwStyle; - - infoPtr = (TAB_INFO *)Alloc (sizeof(TAB_INFO)); - - SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)infoPtr); - - infoPtr->hwnd = hwnd; - infoPtr->hwndNotify = ((LPCREATESTRUCTW)lParam)->hwndParent; - infoPtr->uNumItem = 0; - infoPtr->uNumRows = 0; - infoPtr->uHItemPadding = 6; - infoPtr->uVItemPadding = 3; - infoPtr->uHItemPadding_s = 6; - infoPtr->uVItemPadding_s = 3; - infoPtr->hFont = 0; - infoPtr->items = 0; - infoPtr->hcurArrow = LoadCursorW (0, (LPWSTR)IDC_ARROW); - infoPtr->iSelected = -1; - infoPtr->iHotTracked = -1; - infoPtr->uFocus = -1; - infoPtr->hwndToolTip = 0; - infoPtr->DoRedraw = TRUE; - infoPtr->needsScrolling = FALSE; - infoPtr->hwndUpDown = 0; - infoPtr->leftmostVisible = 0; - infoPtr->fHeightSet = FALSE; - infoPtr->bUnicode = IsWindowUnicode (hwnd); - infoPtr->cbInfo = sizeof(LPARAM); - - TRACE("Created tab control, hwnd [%p]\n", hwnd); - - /* The tab control always has the WS_CLIPSIBLINGS style. Even - if you don't specify it in CreateWindow. This is necessary in - order for paint to work correctly. This follows windows behaviour. */ - dwStyle = GetWindowLongW(hwnd, GWL_STYLE); - SetWindowLongW(hwnd, GWL_STYLE, dwStyle|WS_CLIPSIBLINGS); - - if (dwStyle & TCS_TOOLTIPS) { - /* Create tooltip control */ - infoPtr->hwndToolTip = - CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, 0, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - hwnd, 0, 0, 0); - - /* Send NM_TOOLTIPSCREATED notification */ - if (infoPtr->hwndToolTip) { - NMTOOLTIPSCREATED nmttc; - - nmttc.hdr.hwndFrom = hwnd; - nmttc.hdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID); - nmttc.hdr.code = NM_TOOLTIPSCREATED; - nmttc.hwndToolTips = infoPtr->hwndToolTip; - - SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, - (WPARAM)GetWindowLongPtrW(hwnd, GWLP_ID), (LPARAM)&nmttc); - } - } - - /* - * We need to get text information so we need a DC and we need to select - * a font. - */ - hdc = GetDC(hwnd); - hOldFont = SelectObject (hdc, GetStockObject (SYSTEM_FONT)); - - /* Use the system font to determine the initial height of a tab. */ - GetTextMetricsW(hdc, &fontMetrics); - - /* - * Make sure there is enough space for the letters + growing the - * selected item + extra space for the selected item. - */ - infoPtr->tabHeight = fontMetrics.tmHeight + SELECTED_TAB_OFFSET + - ((dwStyle & TCS_BUTTONS) ? 2 : 1) * - infoPtr->uVItemPadding; - - /* Initialize the width of a tab. */ - infoPtr->tabWidth = DEFAULT_TAB_WIDTH; - infoPtr->tabMinWidth = 0; - - TRACE("tabH=%d, tabW=%d\n", infoPtr->tabHeight, infoPtr->tabWidth); - - SelectObject (hdc, hOldFont); - ReleaseDC(hwnd, hdc); - - return 0; -} - -static LRESULT -TAB_Destroy (TAB_INFO *infoPtr) -{ - UINT iItem; - - if (!infoPtr) - return 0; - - SetWindowLongPtrW(infoPtr->hwnd, 0, 0); - - if (infoPtr->items) { - for (iItem = 0; iItem < infoPtr->uNumItem; iItem++) { - if (TAB_GetItem(infoPtr, iItem)->pszText) - Free (TAB_GetItem(infoPtr, iItem)->pszText); - } - Free (infoPtr->items); - } - - if (infoPtr->hwndToolTip) - DestroyWindow (infoPtr->hwndToolTip); - - if (infoPtr->hwndUpDown) - DestroyWindow(infoPtr->hwndUpDown); - - if (infoPtr->iHotTracked >= 0) - KillTimer(infoPtr->hwnd, TAB_HOTTRACK_TIMER); - - Free (infoPtr); - return 0; -} - -static LRESULT TAB_NCCalcSize(HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - if (!wParam) - return 0; - return WVR_ALIGNTOP; -} - -static inline LRESULT -TAB_SetItemExtra (TAB_INFO *infoPtr, INT cbInfo) -{ - if (!infoPtr || cbInfo <= 0) - return FALSE; - - if (infoPtr->uNumItem) - { - /* FIXME: MSDN says this is not allowed, but this hasn't been verified */ - return FALSE; - } - - infoPtr->cbInfo = cbInfo; - return TRUE; -} - -static LRESULT WINAPI -TAB_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd); - - TRACE("hwnd=%p msg=%x wParam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam); - if (!infoPtr && (uMsg != WM_CREATE)) - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - - switch (uMsg) - { - case TCM_GETIMAGELIST: - return TAB_GetImageList (infoPtr); - - case TCM_SETIMAGELIST: - return TAB_SetImageList (infoPtr, (HIMAGELIST)lParam); - - case TCM_GETITEMCOUNT: - return TAB_GetItemCount (infoPtr); - - case TCM_GETITEMA: - case TCM_GETITEMW: - return TAB_GetItemT (infoPtr, (INT)wParam, (LPTCITEMW)lParam, uMsg == TCM_GETITEMW); - - case TCM_SETITEMA: - case TCM_SETITEMW: - return TAB_SetItemT (infoPtr, (INT)wParam, (LPTCITEMW)lParam, uMsg == TCM_SETITEMW); - - case TCM_DELETEITEM: - return TAB_DeleteItem (infoPtr, (INT)wParam); - - case TCM_DELETEALLITEMS: - return TAB_DeleteAllItems (infoPtr); - - case TCM_GETITEMRECT: - return TAB_GetItemRect (infoPtr, wParam, lParam); - - case TCM_GETCURSEL: - return TAB_GetCurSel (infoPtr); - - case TCM_HITTEST: - return TAB_HitTest (infoPtr, (LPTCHITTESTINFO)lParam); - - case TCM_SETCURSEL: - return TAB_SetCurSel (infoPtr, (INT)wParam); - - case TCM_INSERTITEMA: - case TCM_INSERTITEMW: - return TAB_InsertItemT (infoPtr, wParam, lParam, uMsg == TCM_INSERTITEMW); - - case TCM_SETITEMEXTRA: - return TAB_SetItemExtra (infoPtr, (int)wParam); - - case TCM_ADJUSTRECT: - return TAB_AdjustRect (infoPtr, (BOOL)wParam, (LPRECT)lParam); - - case TCM_SETITEMSIZE: - return TAB_SetItemSize (infoPtr, lParam); - - case TCM_REMOVEIMAGE: - FIXME("Unimplemented msg TCM_REMOVEIMAGE\n"); - return 0; - - case TCM_SETPADDING: - return TAB_SetPadding (infoPtr, lParam); - - case TCM_GETROWCOUNT: - return TAB_GetRowCount(infoPtr); - - case TCM_GETUNICODEFORMAT: - return TAB_GetUnicodeFormat (infoPtr); - - case TCM_SETUNICODEFORMAT: - return TAB_SetUnicodeFormat (infoPtr, (BOOL)wParam); - - case TCM_HIGHLIGHTITEM: - return TAB_HighlightItem (infoPtr, (INT)wParam, (BOOL)LOWORD(lParam)); - - case TCM_GETTOOLTIPS: - return TAB_GetToolTips (infoPtr); - - case TCM_SETTOOLTIPS: - return TAB_SetToolTips (infoPtr, (HWND)wParam); - - case TCM_GETCURFOCUS: - return TAB_GetCurFocus (infoPtr); - - case TCM_SETCURFOCUS: - return TAB_SetCurFocus (infoPtr, (INT)wParam); - - case TCM_SETMINTABWIDTH: - return TAB_SetMinTabWidth(infoPtr, (INT)lParam); - - case TCM_DESELECTALL: - FIXME("Unimplemented msg TCM_DESELECTALL\n"); - return 0; - - case TCM_GETEXTENDEDSTYLE: - FIXME("Unimplemented msg TCM_GETEXTENDEDSTYLE\n"); - return 0; - - case TCM_SETEXTENDEDSTYLE: - FIXME("Unimplemented msg TCM_SETEXTENDEDSTYLE\n"); - return 0; - - case WM_GETFONT: - return TAB_GetFont (infoPtr); - - case WM_SETFONT: - return TAB_SetFont (infoPtr, (HFONT)wParam); - - case WM_CREATE: - return TAB_Create (hwnd, wParam, lParam); - - case WM_NCDESTROY: - return TAB_Destroy (infoPtr); - - case WM_GETDLGCODE: - return DLGC_WANTARROWS | DLGC_WANTCHARS; - - case WM_LBUTTONDOWN: - return TAB_LButtonDown (infoPtr, wParam, lParam); - - case WM_LBUTTONUP: - return TAB_LButtonUp (infoPtr); - - case WM_NOTIFY: - return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, wParam, lParam); - - case WM_RBUTTONDOWN: - return TAB_RButtonDown (infoPtr); - - case WM_MOUSEMOVE: - return TAB_MouseMove (infoPtr, wParam, lParam); - - case WM_PAINT: - return TAB_Paint (infoPtr, (HDC)wParam); - - case WM_SIZE: - return TAB_Size (infoPtr); - - case WM_SETREDRAW: - return TAB_SetRedraw (infoPtr, (BOOL)wParam); - - case WM_HSCROLL: - return TAB_OnHScroll(infoPtr, (int)LOWORD(wParam), (int)HIWORD(wParam), (HWND)lParam); - - case WM_STYLECHANGED: - TAB_SetItemBounds (infoPtr); - InvalidateRect(hwnd, NULL, TRUE); - return 0; - - case WM_SYSCOLORCHANGE: - COMCTL32_RefreshSysColors(); - return 0; - - case WM_KILLFOCUS: - case WM_SETFOCUS: - TAB_FocusChanging(infoPtr); - break; /* Don't disturb normal focus behavior */ - - case WM_KEYUP: - return TAB_KeyUp(infoPtr, wParam); - case WM_NCHITTEST: - return TAB_NCHitTest(infoPtr, lParam); - - case WM_NCCALCSIZE: - return TAB_NCCalcSize(hwnd, wParam, lParam); - - default: - if (uMsg >= WM_USER && uMsg < WM_APP) - WARN("unknown msg %04x wp=%08x lp=%08lx\n", - uMsg, wParam, lParam); - break; - } - return DefWindowProcW(hwnd, uMsg, wParam, lParam); -} - - -void -TAB_Register (void) -{ - WNDCLASSW wndClass; - - ZeroMemory (&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; - wndClass.lpfnWndProc = TAB_WindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(TAB_INFO *); - wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); - wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); - wndClass.lpszClassName = WC_TABCONTROLW; - - RegisterClassW (&wndClass); -} - - -void -TAB_Unregister (void) -{ - UnregisterClassW (WC_TABCONTROLW, NULL); -} +/* + * Tab control + * + * Copyright 1998 Anders Carlsson + * Copyright 1999 Alex Priem + * Copyright 1999 Francis Beaudet + * Copyright 2003 Vitaliy Margolen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES + * + * This code was audited for completeness against the documented features + * of Comctl32.dll version 6.0 on May. 20, 2005, by James Hawkins. + * + * Unless otherwise noted, we believe this code to be complete, as per + * the specification mentioned above. + * If you discover missing features, or bugs, please note them below. + * + * TODO: + * + * Styles: + * TCS_MULTISELECT + * TCS_RIGHT + * TCS_RIGHTJUSTIFY + * TCS_SCROLLOPPOSITE + * TCS_SINGLELINE + * TCIF_RTLREADING + * + * Extended Styles: + * TCS_EX_FLATSEPARATORS + * TCS_EX_REGISTERDROP + * + * States: + * TCIS_BUTTONPRESSED + * + * Notifications: + * NM_RELEASEDCAPTURE + * TCN_FOCUSCHANGE + * TCN_GETOBJECT + * TCN_KEYDOWN + * + * Messages: + * TCM_REMOVEIMAGE + * TCM_DESELECTALL + * TCM_GETEXTENDEDSTYLE + * TCM_SETEXTENDEDSTYLE + * + * Macros: + * TabCtrl_AdjustRect + * + */ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "comctl32.h" +#include "wine/debug.h" +#include + +WINE_DEFAULT_DEBUG_CHANNEL(tab); + +typedef struct +{ + UINT mask; + DWORD dwState; + LPWSTR pszText; + INT iImage; + RECT rect; /* bounding rectangle of the item relative to the + * leftmost item (the leftmost item, 0, would have a + * "left" member of 0 in this rectangle) + * + * additionally the top member holds the row number + * and bottom is unused and should be 0 */ + BYTE extra[1]; /* Space for caller supplied info, variable size */ +} TAB_ITEM; + +/* The size of a tab item depends on how much extra data is requested */ +#define TAB_ITEM_SIZE(infoPtr) (sizeof(TAB_ITEM) - sizeof(BYTE) + infoPtr->cbInfo) + +typedef struct +{ + HWND hwnd; /* Tab control window */ + HWND hwndNotify; /* notification window (parent) */ + UINT uNumItem; /* number of tab items */ + UINT uNumRows; /* number of tab rows */ + INT tabHeight; /* height of the tab row */ + INT tabWidth; /* width of tabs */ + INT tabMinWidth; /* minimum width of items */ + USHORT uHItemPadding; /* amount of horizontal padding, in pixels */ + USHORT uVItemPadding; /* amount of vertical padding, in pixels */ + USHORT uHItemPadding_s; /* Set amount of horizontal padding, in pixels */ + USHORT uVItemPadding_s; /* Set amount of vertical padding, in pixels */ + HFONT hFont; /* handle to the current font */ + HCURSOR hcurArrow; /* handle to the current cursor */ + HIMAGELIST himl; /* handle to an image list (may be 0) */ + HWND hwndToolTip; /* handle to tab's tooltip */ + INT leftmostVisible; /* Used for scrolling, this member contains + * the index of the first visible item */ + INT iSelected; /* the currently selected item */ + INT iHotTracked; /* the highlighted item under the mouse */ + INT uFocus; /* item which has the focus */ + TAB_ITEM* items; /* pointer to an array of TAB_ITEM's */ + BOOL DoRedraw; /* flag for redrawing when tab contents is changed*/ + BOOL needsScrolling; /* TRUE if the size of the tabs is greater than + * the size of the control */ + BOOL fHeightSet; /* was the height of the tabs explicitly set? */ + BOOL bUnicode; /* Unicode control? */ + HWND hwndUpDown; /* Updown control used for scrolling */ + INT cbInfo; /* Number of bytes of caller supplied info per tab */ +} TAB_INFO; + +/****************************************************************************** + * Positioning constants + */ +#define SELECTED_TAB_OFFSET 2 +#define ROUND_CORNER_SIZE 2 +#define DISPLAY_AREA_PADDINGX 2 +#define DISPLAY_AREA_PADDINGY 2 +#define CONTROL_BORDER_SIZEX 2 +#define CONTROL_BORDER_SIZEY 2 +#define BUTTON_SPACINGX 3 +#define BUTTON_SPACINGY 3 +#define FLAT_BTN_SPACINGX 8 +#define DEFAULT_TAB_WIDTH 96 + +#define TAB_GetInfoPtr(hwnd) ((TAB_INFO *)GetWindowLongPtrW(hwnd,0)) +/* Since items are variable sized, cannot directly access them */ +#define TAB_GetItem(info,i) \ + ((TAB_ITEM*)((LPBYTE)info->items + (i) * TAB_ITEM_SIZE(info))) + +/****************************************************************************** + * Hot-tracking timer constants + */ +#define TAB_HOTTRACK_TIMER 1 +#define TAB_HOTTRACK_TIMER_INTERVAL 100 /* milliseconds */ + +/****************************************************************************** + * Prototypes + */ +static void TAB_InvalidateTabArea(TAB_INFO *); +static void TAB_EnsureSelectionVisible(TAB_INFO *); +static void TAB_DrawItemInterior(TAB_INFO *, HDC, INT, RECT*); + +static BOOL +TAB_SendSimpleNotify (const TAB_INFO *infoPtr, UINT code) +{ + NMHDR nmhdr; + + nmhdr.hwndFrom = infoPtr->hwnd; + nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwnd, GWLP_ID); + nmhdr.code = code; + + return (BOOL) SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, + (WPARAM) nmhdr.idFrom, (LPARAM) &nmhdr); +} + +static void +TAB_RelayEvent (HWND hwndTip, HWND hwndMsg, UINT uMsg, + WPARAM wParam, LPARAM lParam) +{ + MSG msg; + + msg.hwnd = hwndMsg; + msg.message = uMsg; + msg.wParam = wParam; + msg.lParam = lParam; + msg.time = GetMessageTime (); + msg.pt.x = LOWORD(GetMessagePos ()); + msg.pt.y = HIWORD(GetMessagePos ()); + + SendMessageW (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg); +} + +static void +TAB_DumpItemExternalT(TCITEMW *pti, UINT iItem, BOOL isW) +{ + if (TRACE_ON(tab)) { + TRACE("external tab %d, mask=0x%08x, dwState=0x%08lx, dwStateMask=0x%08lx, cchTextMax=0x%08x\n", + iItem, pti->mask, pti->dwState, pti->dwStateMask, pti->cchTextMax); + TRACE("external tab %d, iImage=%d, lParam=0x%08lx, pszTextW=%s\n", + iItem, pti->iImage, pti->lParam, isW ? debugstr_w(pti->pszText) : debugstr_a((LPSTR)pti->pszText)); + } +} + +static void +TAB_DumpItemInternal(TAB_INFO *infoPtr, UINT iItem) +{ + if (TRACE_ON(tab)) { + TAB_ITEM *ti; + + ti = TAB_GetItem(infoPtr, iItem); + TRACE("tab %d, mask=0x%08x, dwState=0x%08lx, pszText=%s, iImage=%d\n", + iItem, ti->mask, ti->dwState, debugstr_w(ti->pszText), + ti->iImage); + TRACE("tab %d, rect.left=%ld, rect.top(row)=%ld\n", + iItem, ti->rect.left, ti->rect.top); + } +} + +/* RETURNS + * the index of the selected tab, or -1 if no tab is selected. */ +static inline LRESULT TAB_GetCurSel (const TAB_INFO *infoPtr) +{ + return infoPtr->iSelected; +} + +/* RETURNS + * the index of the tab item that has the focus + * NOTE + * we have not to return negative value + * TODO + * test for windows */ +static inline LRESULT +TAB_GetCurFocus (const TAB_INFO *infoPtr) +{ + if (infoPtr->uFocus<0) + { + FIXME("we have not to return negative value"); + return 0; + } + return infoPtr->uFocus; +} + +static inline LRESULT TAB_GetToolTips (const TAB_INFO *infoPtr) +{ + if (infoPtr == NULL) return 0; + return (LRESULT)infoPtr->hwndToolTip; +} + +static inline LRESULT TAB_SetCurSel (TAB_INFO *infoPtr, INT iItem) +{ + INT prevItem = -1; + + if (iItem >= 0 && iItem < infoPtr->uNumItem) { + prevItem=infoPtr->iSelected; + infoPtr->iSelected=iItem; + TAB_EnsureSelectionVisible(infoPtr); + TAB_InvalidateTabArea(infoPtr); + } + return prevItem; +} + +static LRESULT TAB_SetCurFocus (TAB_INFO *infoPtr, INT iItem) +{ + if (iItem < 0 || iItem >= infoPtr->uNumItem) return 0; + + if (GetWindowLongW(infoPtr->hwnd, GWL_STYLE) & TCS_BUTTONS) { + FIXME("Should set input focus\n"); + } else { + int oldFocus = infoPtr->uFocus; + if (infoPtr->iSelected != iItem || oldFocus == -1 ) { + infoPtr->uFocus = iItem; + if (oldFocus != -1) { + if (!TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING)) { + infoPtr->iSelected = iItem; + TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGE); + } + else + infoPtr->iSelected = iItem; + TAB_EnsureSelectionVisible(infoPtr); + TAB_InvalidateTabArea(infoPtr); + } + } + } + return 0; +} + +static inline LRESULT +TAB_SetToolTips (TAB_INFO *infoPtr, HWND hwndToolTip) +{ + if (infoPtr) + infoPtr->hwndToolTip = hwndToolTip; + return 0; +} + +static inline LRESULT +TAB_SetPadding (TAB_INFO *infoPtr, LPARAM lParam) +{ + if (infoPtr) + { + infoPtr->uHItemPadding_s=LOWORD(lParam); + infoPtr->uVItemPadding_s=HIWORD(lParam); + } + return 0; +} + +/****************************************************************************** + * TAB_InternalGetItemRect + * + * This method will calculate the rectangle representing a given tab item in + * client coordinates. This method takes scrolling into account. + * + * This method returns TRUE if the item is visible in the window and FALSE + * if it is completely outside the client area. + */ +static BOOL TAB_InternalGetItemRect( + const TAB_INFO* infoPtr, + INT itemIndex, + RECT* itemRect, + RECT* selectedRect) +{ + RECT tmpItemRect,clientRect; + LONG lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); + + /* Perform a sanity check and a trivial visibility check. */ + if ( (infoPtr->uNumItem <= 0) || + (itemIndex >= infoPtr->uNumItem) || + (!((lStyle & TCS_MULTILINE) || (lStyle & TCS_VERTICAL)) && (itemIndex < infoPtr->leftmostVisible)) ) + return FALSE; + + /* + * Avoid special cases in this procedure by assigning the "out" + * parameters if the caller didn't supply them + */ + if (itemRect == NULL) + itemRect = &tmpItemRect; + + /* Retrieve the unmodified item rect. */ + *itemRect = TAB_GetItem(infoPtr,itemIndex)->rect; + + /* calculate the times bottom and top based on the row */ + GetClientRect(infoPtr->hwnd, &clientRect); + + if ((lStyle & TCS_BOTTOM) && (lStyle & TCS_VERTICAL)) + { + itemRect->right = clientRect.right - SELECTED_TAB_OFFSET - itemRect->left * infoPtr->tabHeight - + ((lStyle & TCS_BUTTONS) ? itemRect->left * BUTTON_SPACINGX : 0); + itemRect->left = itemRect->right - infoPtr->tabHeight; + } + else if (lStyle & TCS_VERTICAL) + { + itemRect->left = clientRect.left + SELECTED_TAB_OFFSET + itemRect->left * infoPtr->tabHeight + + ((lStyle & TCS_BUTTONS) ? itemRect->left * BUTTON_SPACINGX : 0); + itemRect->right = itemRect->left + infoPtr->tabHeight; + } + else if (lStyle & TCS_BOTTOM) + { + itemRect->bottom = clientRect.bottom - itemRect->top * infoPtr->tabHeight - + ((lStyle & TCS_BUTTONS) ? itemRect->top * BUTTON_SPACINGY : SELECTED_TAB_OFFSET); + itemRect->top = itemRect->bottom - infoPtr->tabHeight; + } + else /* not TCS_BOTTOM and not TCS_VERTICAL */ + { + itemRect->top = clientRect.top + itemRect->top * infoPtr->tabHeight + + ((lStyle & TCS_BUTTONS) ? itemRect->top * BUTTON_SPACINGY : SELECTED_TAB_OFFSET); + itemRect->bottom = itemRect->top + infoPtr->tabHeight; + } + + /* + * "scroll" it to make sure the item at the very left of the + * tab control is the leftmost visible tab. + */ + if(lStyle & TCS_VERTICAL) + { + OffsetRect(itemRect, + 0, + -TAB_GetItem(infoPtr, infoPtr->leftmostVisible)->rect.top); + + /* + * Move the rectangle so the first item is slightly offset from + * the bottom of the tab control. + */ + OffsetRect(itemRect, + 0, + SELECTED_TAB_OFFSET); + + } else + { + OffsetRect(itemRect, + -TAB_GetItem(infoPtr, infoPtr->leftmostVisible)->rect.left, + 0); + + /* + * Move the rectangle so the first item is slightly offset from + * the left of the tab control. + */ + OffsetRect(itemRect, + SELECTED_TAB_OFFSET, + 0); + } + TRACE("item %d tab h=%d, rect=(%ld,%ld)-(%ld,%ld)\n", + itemIndex, infoPtr->tabHeight, + itemRect->left, itemRect->top, itemRect->right, itemRect->bottom); + + /* Now, calculate the position of the item as if it were selected. */ + if (selectedRect!=NULL) + { + CopyRect(selectedRect, itemRect); + + /* The rectangle of a selected item is a bit wider. */ + if(lStyle & TCS_VERTICAL) + InflateRect(selectedRect, 0, SELECTED_TAB_OFFSET); + else + InflateRect(selectedRect, SELECTED_TAB_OFFSET, 0); + + /* If it also a bit higher. */ + if ((lStyle & TCS_BOTTOM) && (lStyle & TCS_VERTICAL)) + { + selectedRect->left -= 2; /* the border is thicker on the right */ + selectedRect->right += SELECTED_TAB_OFFSET; + } + else if (lStyle & TCS_VERTICAL) + { + selectedRect->left -= SELECTED_TAB_OFFSET; + selectedRect->right += 1; + } + else if (lStyle & TCS_BOTTOM) + { + selectedRect->bottom += SELECTED_TAB_OFFSET; + } + else /* not TCS_BOTTOM and not TCS_VERTICAL */ + { + selectedRect->top -= SELECTED_TAB_OFFSET; + selectedRect->bottom -= 1; + } + } + + /* Check for visibility */ + if (lStyle & TCS_VERTICAL) + return (itemRect->top < clientRect.bottom) && (itemRect->bottom > clientRect.top); + else + return (itemRect->left < clientRect.right) && (itemRect->right > clientRect.left); +} + +static inline BOOL +TAB_GetItemRect(TAB_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + return TAB_InternalGetItemRect(infoPtr, (INT)wParam, (LPRECT)lParam, (LPRECT)NULL); +} + +/****************************************************************************** + * TAB_KeyUp + * + * This method is called to handle keyboard input + */ +static LRESULT TAB_KeyUp(TAB_INFO* infoPtr, WPARAM keyCode) +{ + int newItem = -1; + + switch (keyCode) + { + case VK_LEFT: + newItem = infoPtr->uFocus - 1; + break; + case VK_RIGHT: + newItem = infoPtr->uFocus + 1; + break; + } + + /* + * If we changed to a valid item, change the selection + */ + if (newItem >= 0 && + newItem < infoPtr->uNumItem && + infoPtr->uFocus != newItem) + { + if (!TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING)) + { + infoPtr->iSelected = newItem; + infoPtr->uFocus = newItem; + TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGE); + + TAB_EnsureSelectionVisible(infoPtr); + TAB_InvalidateTabArea(infoPtr); + } + } + + return 0; +} + +/****************************************************************************** + * TAB_FocusChanging + * + * This method is called whenever the focus goes in or out of this control + * it is used to update the visual state of the control. + */ +static void TAB_FocusChanging(const TAB_INFO *infoPtr) +{ + RECT selectedRect; + BOOL isVisible; + + /* + * Get the rectangle for the item. + */ + isVisible = TAB_InternalGetItemRect(infoPtr, + infoPtr->uFocus, + NULL, + &selectedRect); + + /* + * If the rectangle is not completely invisible, invalidate that + * portion of the window. + */ + if (isVisible) + { + TRACE("invalidate (%ld,%ld)-(%ld,%ld)\n", + selectedRect.left,selectedRect.top, + selectedRect.right,selectedRect.bottom); + InvalidateRect(infoPtr->hwnd, &selectedRect, TRUE); + } +} + +static INT TAB_InternalHitTest ( + TAB_INFO* infoPtr, + POINT pt, + UINT* flags) + +{ + RECT rect; + INT iCount; + + for (iCount = 0; iCount < infoPtr->uNumItem; iCount++) + { + TAB_InternalGetItemRect(infoPtr, iCount, &rect, NULL); + + if (PtInRect(&rect, pt)) + { + *flags = TCHT_ONITEM; + return iCount; + } + } + + *flags = TCHT_NOWHERE; + return -1; +} + +static inline LRESULT +TAB_HitTest (TAB_INFO *infoPtr, LPTCHITTESTINFO lptest) +{ + return TAB_InternalHitTest (infoPtr, lptest->pt, &lptest->flags); +} + +/****************************************************************************** + * TAB_NCHitTest + * + * Napster v2b5 has a tab control for its main navigation which has a client + * area that covers the whole area of the dialog pages. + * That's why it receives all msgs for that area and the underlying dialog ctrls + * are dead. + * So I decided that we should handle WM_NCHITTEST here and return + * HTTRANSPARENT if we don't hit the tab control buttons. + * FIXME: WM_NCHITTEST handling correct ? Fix it if you know that Windows + * doesn't do it that way. Maybe depends on tab control styles ? + */ +static inline LRESULT +TAB_NCHitTest (TAB_INFO *infoPtr, LPARAM lParam) +{ + POINT pt; + UINT dummyflag; + + pt.x = LOWORD(lParam); + pt.y = HIWORD(lParam); + ScreenToClient(infoPtr->hwnd, &pt); + + if (TAB_InternalHitTest(infoPtr, pt, &dummyflag) == -1) + return HTTRANSPARENT; + else + return HTCLIENT; +} + +static LRESULT +TAB_LButtonDown (TAB_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + POINT pt; + INT newItem, dummy; + + if (infoPtr->hwndToolTip) + TAB_RelayEvent (infoPtr->hwndToolTip, infoPtr->hwnd, + WM_LBUTTONDOWN, wParam, lParam); + + if (GetWindowLongW(infoPtr->hwnd, GWL_STYLE) & TCS_FOCUSONBUTTONDOWN ) { + SetFocus (infoPtr->hwnd); + } + + if (infoPtr->hwndToolTip) + TAB_RelayEvent (infoPtr->hwndToolTip, infoPtr->hwnd, + WM_LBUTTONDOWN, wParam, lParam); + + pt.x = (INT)LOWORD(lParam); + pt.y = (INT)HIWORD(lParam); + + newItem = TAB_InternalHitTest (infoPtr, pt, &dummy); + + TRACE("On Tab, item %d\n", newItem); + + if (newItem != -1 && infoPtr->iSelected != newItem) + { + if (!TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGING)) + { + infoPtr->iSelected = newItem; + infoPtr->uFocus = newItem; + TAB_SendSimpleNotify(infoPtr, TCN_SELCHANGE); + + TAB_EnsureSelectionVisible(infoPtr); + + TAB_InvalidateTabArea(infoPtr); + } + } + return 0; +} + +static inline LRESULT +TAB_LButtonUp (const TAB_INFO *infoPtr) +{ + TAB_SendSimpleNotify(infoPtr, NM_CLICK); + + return 0; +} + +static inline LRESULT +TAB_RButtonDown (const TAB_INFO *infoPtr) +{ + TAB_SendSimpleNotify(infoPtr, NM_RCLICK); + return 0; +} + +/****************************************************************************** + * TAB_DrawLoneItemInterior + * + * This calls TAB_DrawItemInterior. However, TAB_DrawItemInterior is normally + * called by TAB_DrawItem which is normally called by TAB_Refresh which sets + * up the device context and font. This routine does the same setup but + * only calls TAB_DrawItemInterior for the single specified item. + */ +static void +TAB_DrawLoneItemInterior(TAB_INFO* infoPtr, int iItem) +{ + HDC hdc = GetDC(infoPtr->hwnd); + RECT r, rC; + + /* Clip UpDown control to not draw over it */ + if (infoPtr->needsScrolling) + { + GetWindowRect(infoPtr->hwnd, &rC); + GetWindowRect(infoPtr->hwndUpDown, &r); + ExcludeClipRect(hdc, r.left - rC.left, r.top - rC.top, r.right - rC.left, r.bottom - rC.top); + } + TAB_DrawItemInterior(infoPtr, hdc, iItem, NULL); + ReleaseDC(infoPtr->hwnd, hdc); +} + +/****************************************************************************** + * TAB_HotTrackTimerProc + * + * When a mouse-move event causes a tab to be highlighted (hot-tracking), a + * timer is setup so we can check if the mouse is moved out of our window. + * (We don't get an event when the mouse leaves, the mouse-move events just + * stop being delivered to our window and just start being delivered to + * another window.) This function is called when the timer triggers so + * we can check if the mouse has left our window. If so, we un-highlight + * the hot-tracked tab. + */ +static void CALLBACK +TAB_HotTrackTimerProc + ( + HWND hwnd, /* handle of window for timer messages */ + UINT uMsg, /* WM_TIMER message */ + UINT idEvent, /* timer identifier */ + DWORD dwTime /* current system time */ + ) +{ + TAB_INFO* infoPtr = TAB_GetInfoPtr(hwnd); + + if (infoPtr != NULL && infoPtr->iHotTracked >= 0) + { + POINT pt; + + /* + ** If we can't get the cursor position, or if the cursor is outside our + ** window, we un-highlight the hot-tracked tab. Note that the cursor is + ** "outside" even if it is within our bounding rect if another window + ** overlaps. Note also that the case where the cursor stayed within our + ** window but has moved off the hot-tracked tab will be handled by the + ** WM_MOUSEMOVE event. + */ + if (!GetCursorPos(&pt) || WindowFromPoint(pt) != hwnd) + { + /* Redraw iHotTracked to look normal */ + INT iRedraw = infoPtr->iHotTracked; + infoPtr->iHotTracked = -1; + TAB_DrawLoneItemInterior(infoPtr, iRedraw); + + /* Kill this timer */ + KillTimer(hwnd, TAB_HOTTRACK_TIMER); + } + } +} + +/****************************************************************************** + * TAB_RecalcHotTrack + * + * If a tab control has the TCS_HOTTRACK style, then the tab under the mouse + * should be highlighted. This function determines which tab in a tab control, + * if any, is under the mouse and records that information. The caller may + * supply output parameters to receive the item number of the tab item which + * was highlighted but isn't any longer and of the tab item which is now + * highlighted but wasn't previously. The caller can use this information to + * selectively redraw those tab items. + * + * If the caller has a mouse position, it can supply it through the pos + * parameter. For example, TAB_MouseMove does this. Otherwise, the caller + * supplies NULL and this function determines the current mouse position + * itself. + */ +static void +TAB_RecalcHotTrack + ( + TAB_INFO* infoPtr, + const LPARAM* pos, + int* out_redrawLeave, + int* out_redrawEnter + ) +{ + int item = -1; + + + if (out_redrawLeave != NULL) + *out_redrawLeave = -1; + if (out_redrawEnter != NULL) + *out_redrawEnter = -1; + + if (GetWindowLongW(infoPtr->hwnd, GWL_STYLE) & TCS_HOTTRACK) + { + POINT pt; + UINT flags; + + if (pos == NULL) + { + GetCursorPos(&pt); + ScreenToClient(infoPtr->hwnd, &pt); + } + else + { + pt.x = LOWORD(*pos); + pt.y = HIWORD(*pos); + } + + item = TAB_InternalHitTest(infoPtr, pt, &flags); + } + + if (item != infoPtr->iHotTracked) + { + if (infoPtr->iHotTracked >= 0) + { + /* Mark currently hot-tracked to be redrawn to look normal */ + if (out_redrawLeave != NULL) + *out_redrawLeave = infoPtr->iHotTracked; + + if (item < 0) + { + /* Kill timer which forces recheck of mouse pos */ + KillTimer(infoPtr->hwnd, TAB_HOTTRACK_TIMER); + } + } + else + { + /* Start timer so we recheck mouse pos */ + UINT timerID = SetTimer + ( + infoPtr->hwnd, + TAB_HOTTRACK_TIMER, + TAB_HOTTRACK_TIMER_INTERVAL, + TAB_HotTrackTimerProc + ); + + if (timerID == 0) + return; /* Hot tracking not available */ + } + + infoPtr->iHotTracked = item; + + if (item >= 0) + { + /* Mark new hot-tracked to be redrawn to look highlighted */ + if (out_redrawEnter != NULL) + *out_redrawEnter = item; + } + } +} + +/****************************************************************************** + * TAB_MouseMove + * + * Handles the mouse-move event. Updates tooltips. Updates hot-tracking. + */ +static LRESULT +TAB_MouseMove (TAB_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + int redrawLeave; + int redrawEnter; + + if (infoPtr->hwndToolTip) + TAB_RelayEvent (infoPtr->hwndToolTip, infoPtr->hwnd, + WM_LBUTTONDOWN, wParam, lParam); + + /* Determine which tab to highlight. Redraw tabs which change highlight + ** status. */ + TAB_RecalcHotTrack(infoPtr, &lParam, &redrawLeave, &redrawEnter); + + if (redrawLeave != -1) + TAB_DrawLoneItemInterior(infoPtr, redrawLeave); + if (redrawEnter != -1) + TAB_DrawLoneItemInterior(infoPtr, redrawEnter); + + return 0; +} + +/****************************************************************************** + * TAB_AdjustRect + * + * Calculates the tab control's display area given the window rectangle or + * the window rectangle given the requested display rectangle. + */ +static LRESULT TAB_AdjustRect( + TAB_INFO *infoPtr, + WPARAM fLarger, + LPRECT prc) +{ + DWORD lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); + LONG *iRightBottom, *iLeftTop; + + TRACE ("hwnd=%p fLarger=%d (%ld,%ld)-(%ld,%ld)\n", infoPtr->hwnd, fLarger, prc->left, prc->top, prc->right, prc->bottom); + + if(lStyle & TCS_VERTICAL) + { + iRightBottom = &(prc->right); + iLeftTop = &(prc->left); + } + else + { + iRightBottom = &(prc->bottom); + iLeftTop = &(prc->top); + } + + if (fLarger) /* Go from display rectangle */ + { + /* Add the height of the tabs. */ + if (lStyle & TCS_BOTTOM) + *iRightBottom += infoPtr->tabHeight * infoPtr->uNumRows; + else + *iLeftTop -= infoPtr->tabHeight * infoPtr->uNumRows + + ((lStyle & TCS_BUTTONS)? 3 * (infoPtr->uNumRows - 1) : 0); + + /* Inflate the rectangle for the padding */ + InflateRect(prc, DISPLAY_AREA_PADDINGX, DISPLAY_AREA_PADDINGY); + + /* Inflate for the border */ + InflateRect(prc, CONTROL_BORDER_SIZEX, CONTROL_BORDER_SIZEY); + } + else /* Go from window rectangle. */ + { + /* Deflate the rectangle for the border */ + InflateRect(prc, -CONTROL_BORDER_SIZEX, -CONTROL_BORDER_SIZEY); + + /* Deflate the rectangle for the padding */ + InflateRect(prc, -DISPLAY_AREA_PADDINGX, -DISPLAY_AREA_PADDINGY); + + /* Remove the height of the tabs. */ + if (lStyle & TCS_BOTTOM) + *iRightBottom -= infoPtr->tabHeight * infoPtr->uNumRows; + else + *iLeftTop += (infoPtr->tabHeight) * infoPtr->uNumRows + + ((lStyle & TCS_BUTTONS)? 3 * (infoPtr->uNumRows - 1) : 0); + } + + return 0; +} + +/****************************************************************************** + * TAB_OnHScroll + * + * This method will handle the notification from the scroll control and + * perform the scrolling operation on the tab control. + */ +static LRESULT TAB_OnHScroll( + TAB_INFO *infoPtr, + int nScrollCode, + int nPos, + HWND hwndScroll) +{ + if(nScrollCode == SB_THUMBPOSITION && nPos != infoPtr->leftmostVisible) + { + if(nPos < infoPtr->leftmostVisible) + infoPtr->leftmostVisible--; + else + infoPtr->leftmostVisible++; + + TAB_RecalcHotTrack(infoPtr, NULL, NULL, NULL); + TAB_InvalidateTabArea(infoPtr); + SendMessageW(infoPtr->hwndUpDown, UDM_SETPOS, 0, + MAKELONG(infoPtr->leftmostVisible, 0)); + } + + return 0; +} + +/****************************************************************************** + * TAB_SetupScrolling + * + * This method will check the current scrolling state and make sure the + * scrolling control is displayed (or not). + */ +static void TAB_SetupScrolling( + HWND hwnd, + TAB_INFO* infoPtr, + const RECT* clientRect) +{ + static const WCHAR msctls_updown32W[] = { 'm','s','c','t','l','s','_','u','p','d','o','w','n','3','2',0 }; + static const WCHAR emptyW[] = { 0 }; + INT maxRange = 0; + DWORD lStyle = GetWindowLongW(hwnd, GWL_STYLE); + + if (infoPtr->needsScrolling) + { + RECT controlPos; + INT vsize, tabwidth; + + /* + * Calculate the position of the scroll control. + */ + if(lStyle & TCS_VERTICAL) + { + controlPos.right = clientRect->right; + controlPos.left = controlPos.right - 2 * GetSystemMetrics(SM_CXHSCROLL); + + if (lStyle & TCS_BOTTOM) + { + controlPos.top = clientRect->bottom - infoPtr->tabHeight; + controlPos.bottom = controlPos.top + GetSystemMetrics(SM_CYHSCROLL); + } + else + { + controlPos.bottom = clientRect->top + infoPtr->tabHeight; + controlPos.top = controlPos.bottom - GetSystemMetrics(SM_CYHSCROLL); + } + } + else + { + controlPos.right = clientRect->right; + controlPos.left = controlPos.right - 2 * GetSystemMetrics(SM_CXHSCROLL); + + if (lStyle & TCS_BOTTOM) + { + controlPos.top = clientRect->bottom - infoPtr->tabHeight; + controlPos.bottom = controlPos.top + GetSystemMetrics(SM_CYHSCROLL); + } + else + { + controlPos.bottom = clientRect->top + infoPtr->tabHeight; + controlPos.top = controlPos.bottom - GetSystemMetrics(SM_CYHSCROLL); + } + } + + /* + * If we don't have a scroll control yet, we want to create one. + * If we have one, we want to make sure it's positioned properly. + */ + if (infoPtr->hwndUpDown==0) + { + infoPtr->hwndUpDown = CreateWindowW(msctls_updown32W, emptyW, + WS_VISIBLE | WS_CHILD | UDS_HORZ, + controlPos.left, controlPos.top, + controlPos.right - controlPos.left, + controlPos.bottom - controlPos.top, + hwnd, NULL, NULL, NULL); + } + else + { + SetWindowPos(infoPtr->hwndUpDown, + NULL, + controlPos.left, controlPos.top, + controlPos.right - controlPos.left, + controlPos.bottom - controlPos.top, + SWP_SHOWWINDOW | SWP_NOZORDER); + } + + /* Now calculate upper limit of the updown control range. + * We do this by calculating how many tabs will be offscreen when the + * last tab is visible. + */ + if(infoPtr->uNumItem) + { + vsize = clientRect->right - (controlPos.right - controlPos.left + 1); + maxRange = infoPtr->uNumItem; + tabwidth = TAB_GetItem(infoPtr, infoPtr->uNumItem - 1)->rect.right; + + for(; maxRange > 0; maxRange--) + { + if(tabwidth - TAB_GetItem(infoPtr,maxRange - 1)->rect.left > vsize) + break; + } + + if(maxRange == infoPtr->uNumItem) + maxRange--; + } + } + else + { + /* If we once had a scroll control... hide it */ + if (infoPtr->hwndUpDown!=0) + ShowWindow(infoPtr->hwndUpDown, SW_HIDE); + } + if (infoPtr->hwndUpDown) + SendMessageW(infoPtr->hwndUpDown, UDM_SETRANGE32, 0, maxRange); +} + +/****************************************************************************** + * TAB_SetItemBounds + * + * This method will calculate the position rectangles of all the items in the + * control. The rectangle calculated starts at 0 for the first item in the + * list and ignores scrolling and selection. + * It also uses the current font to determine the height of the tab row and + * it checks if all the tabs fit in the client area of the window. If they + * don't, a scrolling control is added. + */ +static void TAB_SetItemBounds (TAB_INFO *infoPtr) +{ + LONG lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); + TEXTMETRICW fontMetrics; + UINT curItem; + INT curItemLeftPos; + INT curItemRowCount; + HFONT hFont, hOldFont; + HDC hdc; + RECT clientRect; + SIZE size; + INT iTemp; + RECT* rcItem; + INT iIndex; + INT icon_width = 0; + + /* + * We need to get text information so we need a DC and we need to select + * a font. + */ + hdc = GetDC(infoPtr->hwnd); + + hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT); + hOldFont = SelectObject (hdc, hFont); + + /* + * We will base the rectangle calculations on the client rectangle + * of the control. + */ + GetClientRect(infoPtr->hwnd, &clientRect); + + /* if TCS_VERTICAL then swap the height and width so this code places the + tabs along the top of the rectangle and we can just rotate them after + rather than duplicate all of the below code */ + if(lStyle & TCS_VERTICAL) + { + iTemp = clientRect.bottom; + clientRect.bottom = clientRect.right; + clientRect.right = iTemp; + } + + /* Now use hPadding and vPadding */ + infoPtr->uHItemPadding = infoPtr->uHItemPadding_s; + infoPtr->uVItemPadding = infoPtr->uVItemPadding_s; + + /* The leftmost item will be "0" aligned */ + curItemLeftPos = 0; + curItemRowCount = infoPtr->uNumItem ? 1 : 0; + + if (!(infoPtr->fHeightSet)) + { + int item_height; + int icon_height = 0; + + /* Use the current font to determine the height of a tab. */ + GetTextMetricsW(hdc, &fontMetrics); + + /* Get the icon height */ + if (infoPtr->himl) + ImageList_GetIconSize(infoPtr->himl, 0, &icon_height); + + /* Take the highest between font or icon */ + if (fontMetrics.tmHeight > icon_height) + item_height = fontMetrics.tmHeight + 2; + else + item_height = icon_height; + + /* + * Make sure there is enough space for the letters + icon + growing the + * selected item + extra space for the selected item. + */ + infoPtr->tabHeight = item_height + + ((lStyle & TCS_BUTTONS) ? 2 : 1) * + infoPtr->uVItemPadding; + + TRACE("tabH=%d, tmH=%ld, iconh=%d\n", + infoPtr->tabHeight, fontMetrics.tmHeight, icon_height); + } + + TRACE("client right=%ld\n", clientRect.right); + + /* Get the icon width */ + if (infoPtr->himl) + { + ImageList_GetIconSize(infoPtr->himl, &icon_width, 0); + + if (lStyle & TCS_FIXEDWIDTH) + icon_width += 4; + else + /* Add padding if icon is present */ + icon_width += infoPtr->uHItemPadding; + } + + for (curItem = 0; curItem < infoPtr->uNumItem; curItem++) + { + TAB_ITEM *curr = TAB_GetItem(infoPtr, curItem); + + /* Set the leftmost position of the tab. */ + curr->rect.left = curItemLeftPos; + + if ((lStyle & TCS_FIXEDWIDTH) || !curr->pszText) + { + curr->rect.right = curr->rect.left + + max(infoPtr->tabWidth, icon_width); + } + else + { + int num = 2; + + /* Calculate how wide the tab is depending on the text it contains */ + GetTextExtentPoint32W(hdc, curr->pszText, + lstrlenW(curr->pszText), &size); + + curr->rect.right = curr->rect.left + size.cx + icon_width + + num * infoPtr->uHItemPadding; + TRACE("for <%s>, l,r=%ld,%ld, num=%d\n", + debugstr_w(curr->pszText), curr->rect.left, curr->rect.right, num); + } + + /* + * Check if this is a multiline tab control and if so + * check to see if we should wrap the tabs + * + * Wrap all these tabs. We will arrange them evenly later. + * + */ + + if (((lStyle & TCS_MULTILINE) || (lStyle & TCS_VERTICAL)) && + (curr->rect.right > + (clientRect.right - CONTROL_BORDER_SIZEX - DISPLAY_AREA_PADDINGX))) + { + curr->rect.right -= curr->rect.left; + + curr->rect.left = 0; + curItemRowCount++; + TRACE("wrapping <%s>, l,r=%ld,%ld\n", debugstr_w(curr->pszText), + curr->rect.left, curr->rect.right); + } + + curr->rect.bottom = 0; + curr->rect.top = curItemRowCount - 1; + + TRACE("TextSize: %li\n", size.cx); + TRACE("Rect: T %li, L %li, B %li, R %li\n", curr->rect.top, + curr->rect.left, curr->rect.bottom, curr->rect.right); + + /* + * The leftmost position of the next item is the rightmost position + * of this one. + */ + if (lStyle & TCS_BUTTONS) + { + curItemLeftPos = curr->rect.right + BUTTON_SPACINGX; + if (lStyle & TCS_FLATBUTTONS) + curItemLeftPos += FLAT_BTN_SPACINGX; + } + else + curItemLeftPos = curr->rect.right; + } + + if (!((lStyle & TCS_MULTILINE) || (lStyle & TCS_VERTICAL))) + { + /* + * Check if we need a scrolling control. + */ + infoPtr->needsScrolling = (curItemLeftPos + (2 * SELECTED_TAB_OFFSET) > + clientRect.right); + + /* Don't need scrolling, then update infoPtr->leftmostVisible */ + if(!infoPtr->needsScrolling) + infoPtr->leftmostVisible = 0; + } + else + { + /* + * No scrolling in Multiline or Vertical styles. + */ + infoPtr->needsScrolling = FALSE; + infoPtr->leftmostVisible = 0; + } + TAB_SetupScrolling(infoPtr->hwnd, infoPtr, &clientRect); + + /* Set the number of rows */ + infoPtr->uNumRows = curItemRowCount; + + /* Arrange all tabs evenly if style says so */ + if (!(lStyle & TCS_RAGGEDRIGHT) && ((lStyle & TCS_MULTILINE) || (lStyle & TCS_VERTICAL)) && (infoPtr->uNumItem > 0)) + { + INT tabPerRow,remTab,iRow; + UINT iItm; + INT iCount=0; + + /* + * Ok windows tries to even out the rows. place the same + * number of tabs in each row. So lets give that a shot + */ + + tabPerRow = infoPtr->uNumItem / (infoPtr->uNumRows); + remTab = infoPtr->uNumItem % (infoPtr->uNumRows); + + for (iItm=0,iRow=0,iCount=0,curItemLeftPos=0; + iItmuNumItem; + iItm++,iCount++) + { + /* normalize the current rect */ + TAB_ITEM *curr = TAB_GetItem(infoPtr, iItm); + + /* shift the item to the left side of the clientRect */ + curr->rect.right -= curr->rect.left; + curr->rect.left = 0; + + TRACE("r=%ld, cl=%d, cl.r=%ld, iCount=%d, iRow=%d, uNumRows=%d, remTab=%d, tabPerRow=%d\n", + curr->rect.right, curItemLeftPos, clientRect.right, + iCount, iRow, infoPtr->uNumRows, remTab, tabPerRow); + + /* if we have reached the maximum number of tabs on this row */ + /* move to the next row, reset our current item left position and */ + /* the count of items on this row */ + + if (lStyle & TCS_VERTICAL) { + /* Vert: Add the remaining tabs in the *last* remainder rows */ + if (iCount >= ((iRow>=(INT)infoPtr->uNumRows - remTab)?tabPerRow + 1:tabPerRow)) { + iRow++; + curItemLeftPos = 0; + iCount = 0; + } + } else { + /* Horz: Add the remaining tabs in the *first* remainder rows */ + if (iCount >= ((iRowrect.left += curItemLeftPos; + curr->rect.right += curItemLeftPos; + curr->rect.top = iRow; + if (lStyle & TCS_BUTTONS) + { + curItemLeftPos = curr->rect.right + 1; + if (lStyle & TCS_FLATBUTTONS) + curItemLeftPos += FLAT_BTN_SPACINGX; + } + else + curItemLeftPos = curr->rect.right; + + TRACE("arranging <%s>, l,r=%ld,%ld, row=%ld\n", + debugstr_w(curr->pszText), curr->rect.left, + curr->rect.right, curr->rect.top); + } + + /* + * Justify the rows + */ + { + INT widthDiff, iIndexStart=0, iIndexEnd=0; + INT remainder; + INT iCount=0; + + while(iIndexStart < infoPtr->uNumItem) + { + TAB_ITEM *start = TAB_GetItem(infoPtr, iIndexStart); + + /* + * find the index of the row + */ + /* find the first item on the next row */ + for (iIndexEnd=iIndexStart; + (iIndexEnd < infoPtr->uNumItem) && + (TAB_GetItem(infoPtr, iIndexEnd)->rect.top == + start->rect.top) ; + iIndexEnd++) + /* intentionally blank */; + + /* + * we need to justify these tabs so they fill the whole given + * client area + * + */ + /* find the amount of space remaining on this row */ + widthDiff = clientRect.right - (2 * SELECTED_TAB_OFFSET) - + TAB_GetItem(infoPtr, iIndexEnd - 1)->rect.right; + + /* iCount is the number of tab items on this row */ + iCount = iIndexEnd - iIndexStart; + + if (iCount > 1) + { + remainder = widthDiff % iCount; + widthDiff = widthDiff / iCount; + /* add widthDiff/iCount, or extra space/items on row, to each item on this row */ + for (iIndex=iIndexStart, iCount=0; iIndex < iIndexEnd; iIndex++, iCount++) + { + TAB_ITEM *item = TAB_GetItem(infoPtr, iIndex); + + item->rect.left += iCount * widthDiff; + item->rect.right += (iCount + 1) * widthDiff; + + TRACE("adjusting 1 <%s>, l,r=%ld,%ld\n", + debugstr_w(item->pszText), + item->rect.left, item->rect.right); + + } + TAB_GetItem(infoPtr, iIndex - 1)->rect.right += remainder; + } + else /* we have only one item on this row, make it take up the entire row */ + { + start->rect.left = clientRect.left; + start->rect.right = clientRect.right - 4; + + TRACE("adjusting 2 <%s>, l,r=%ld,%ld\n", + debugstr_w(start->pszText), + start->rect.left, start->rect.right); + + } + + + iIndexStart = iIndexEnd; + } + } + } + + /* if TCS_VERTICAL rotate the tabs so they are along the side of the clientRect */ + if(lStyle & TCS_VERTICAL) + { + RECT rcOriginal; + for(iIndex = 0; iIndex < infoPtr->uNumItem; iIndex++) + { + rcItem = &TAB_GetItem(infoPtr, iIndex)->rect; + + rcOriginal = *rcItem; + + /* this is rotating the items by 90 degrees clockwise around the center of the control */ + rcItem->top = (rcOriginal.left - clientRect.left); + rcItem->bottom = rcItem->top + (rcOriginal.right - rcOriginal.left); + rcItem->left = rcOriginal.top; + rcItem->right = rcOriginal.bottom; + } + } + + TAB_EnsureSelectionVisible(infoPtr); + TAB_RecalcHotTrack(infoPtr, NULL, NULL, NULL); + + /* Cleanup */ + SelectObject (hdc, hOldFont); + ReleaseDC (infoPtr->hwnd, hdc); +} + + +static void +TAB_EraseTabInterior + ( + TAB_INFO* infoPtr, + HDC hdc, + INT iItem, + RECT* drawRect + ) +{ + LONG lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); + HBRUSH hbr = CreateSolidBrush (comctl32_color.clrBtnFace); + BOOL deleteBrush = TRUE; + RECT rTemp = *drawRect; + + InflateRect(&rTemp, -2, -2); + if (lStyle & TCS_BUTTONS) + { + if (iItem == infoPtr->iSelected) + { + /* Background color */ + if (!(lStyle & TCS_OWNERDRAWFIXED)) + { + DeleteObject(hbr); + hbr = GetSysColorBrush(COLOR_SCROLLBAR); + + SetTextColor(hdc, comctl32_color.clr3dFace); + SetBkColor(hdc, comctl32_color.clr3dHilight); + + /* if COLOR_WINDOW happens to be the same as COLOR_3DHILIGHT + * we better use 0x55aa bitmap brush to make scrollbar's background + * look different from the window background. + */ + if (comctl32_color.clr3dHilight == comctl32_color.clrWindow) + hbr = COMCTL32_hPattern55AABrush; + + deleteBrush = FALSE; + } + FillRect(hdc, &rTemp, hbr); + } + else /* ! selected */ + { + if (lStyle & TCS_FLATBUTTONS) + { + FillRect(hdc, drawRect, hbr); + if (iItem == infoPtr->iHotTracked) + DrawEdge(hdc, drawRect, EDGE_RAISED, BF_SOFT|BF_RECT); + } + else + FillRect(hdc, &rTemp, hbr); + } + + } + else /* !TCS_BUTTONS */ + { + FillRect(hdc, &rTemp, hbr); + } + + /* Cleanup */ + if (deleteBrush) DeleteObject(hbr); +} + +/****************************************************************************** + * TAB_DrawItemInterior + * + * This method is used to draw the interior (text and icon) of a single tab + * into the tab control. + */ +static void +TAB_DrawItemInterior + ( + TAB_INFO* infoPtr, + HDC hdc, + INT iItem, + RECT* drawRect + ) +{ + LONG lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); + + RECT localRect; + + HPEN htextPen; + HPEN holdPen; + INT oldBkMode; + HFONT hOldFont; + +/* if (drawRect == NULL) */ + { + BOOL isVisible; + RECT itemRect; + RECT selectedRect; + + /* + * Get the rectangle for the item. + */ + isVisible = TAB_InternalGetItemRect(infoPtr, iItem, &itemRect, &selectedRect); + if (!isVisible) + return; + + /* + * Make sure drawRect points to something valid; simplifies code. + */ + drawRect = &localRect; + + /* + * This logic copied from the part of TAB_DrawItem which draws + * the tab background. It's important to keep it in sync. I + * would have liked to avoid code duplication, but couldn't figure + * out how without making spaghetti of TAB_DrawItem. + */ + if (iItem == infoPtr->iSelected) + *drawRect = selectedRect; + else + *drawRect = itemRect; + + if (lStyle & TCS_BUTTONS) + { + if (iItem == infoPtr->iSelected) + { + drawRect->left += 4; + drawRect->top += 4; + drawRect->right -= 4; + drawRect->bottom -= 1; + } + else + { + drawRect->left += 2; + drawRect->top += 2; + drawRect->right -= 2; + drawRect->bottom -= 2; + } + } + else + { + if ((lStyle & TCS_VERTICAL) && (lStyle & TCS_BOTTOM)) + { + if (iItem != infoPtr->iSelected) + { + drawRect->left += 2; + drawRect->top += 2; + drawRect->bottom -= 2; + } + } + else if (lStyle & TCS_VERTICAL) + { + if (iItem == infoPtr->iSelected) + { + drawRect->right += 1; + } + else + { + drawRect->top += 2; + drawRect->right -= 2; + drawRect->bottom -= 2; + } + } + else if (lStyle & TCS_BOTTOM) + { + if (iItem == infoPtr->iSelected) + { + drawRect->top -= 2; + } + else + { + InflateRect(drawRect, -2, -2); + drawRect->bottom += 2; + } + } + else + { + if (iItem == infoPtr->iSelected) + { + drawRect->bottom += 3; + } + else + { + drawRect->bottom -= 2; + InflateRect(drawRect, -2, 0); + } + } + } + } + TRACE("drawRect=(%ld,%ld)-(%ld,%ld)\n", + drawRect->left, drawRect->top, drawRect->right, drawRect->bottom); + + /* Clear interior */ + TAB_EraseTabInterior (infoPtr, hdc, iItem, drawRect); + + /* Draw the focus rectangle */ + if (!(lStyle & TCS_FOCUSNEVER) && + (GetFocus() == infoPtr->hwnd) && + (iItem == infoPtr->uFocus) ) + { + RECT rFocus = *drawRect; + InflateRect(&rFocus, -3, -3); + if (lStyle & TCS_BOTTOM && !(lStyle & TCS_VERTICAL)) + rFocus.top -= 3; + if (lStyle & TCS_BUTTONS) + { + rFocus.left -= 3; + rFocus.top -= 3; + } + + DrawFocusRect(hdc, &rFocus); + } + + /* + * Text pen + */ + htextPen = CreatePen( PS_SOLID, 1, GetSysColor(COLOR_BTNTEXT) ); + holdPen = SelectObject(hdc, htextPen); + hOldFont = SelectObject(hdc, infoPtr->hFont); + + /* + * Setup for text output + */ + oldBkMode = SetBkMode(hdc, TRANSPARENT); + SetTextColor(hdc, (((iItem == infoPtr->iHotTracked) && !(lStyle & TCS_FLATBUTTONS)) | + (TAB_GetItem(infoPtr, iItem)->dwState & TCIS_HIGHLIGHTED)) ? + comctl32_color.clrHighlight : comctl32_color.clrBtnText); + + /* + * if owner draw, tell the owner to draw + */ + if ((lStyle & TCS_OWNERDRAWFIXED) && GetParent(infoPtr->hwnd)) + { + DRAWITEMSTRUCT dis; + UINT id; + + drawRect->top += 2; + drawRect->right -= 1; + if ( iItem == infoPtr->iSelected ) + { + drawRect->right -= 1; + drawRect->left += 1; + } + + /* + * get the control id + */ + id = (UINT)GetWindowLongPtrW( infoPtr->hwnd, GWLP_ID ); + + /* + * put together the DRAWITEMSTRUCT + */ + dis.CtlType = ODT_TAB; + dis.CtlID = id; + dis.itemID = iItem; + dis.itemAction = ODA_DRAWENTIRE; + dis.itemState = 0; + if ( iItem == infoPtr->iSelected ) + dis.itemState |= ODS_SELECTED; + if (infoPtr->uFocus == iItem) + dis.itemState |= ODS_FOCUS; + dis.hwndItem = infoPtr->hwnd; + dis.hDC = hdc; + CopyRect(&dis.rcItem,drawRect); + dis.itemData = (ULONG_PTR)TAB_GetItem(infoPtr, iItem)->extra; + + /* + * send the draw message + */ + SendMessageW( infoPtr->hwndNotify, WM_DRAWITEM, (WPARAM)id, (LPARAM)&dis ); + } + else + { + TAB_ITEM *item = TAB_GetItem(infoPtr, iItem); + RECT rcTemp; + RECT rcImage; + + /* used to center the icon and text in the tab */ + RECT rcText; + INT center_offset_h, center_offset_v; + + /* set rcImage to drawRect, we will use top & left in our ImageList_Draw call */ + rcImage = *drawRect; + + rcTemp = *drawRect; + + rcText.left = rcText.top = rcText.right = rcText.bottom = 0; + + /* get the rectangle that the text fits in */ + if (item->pszText) + { + DrawTextW(hdc, item->pszText, -1, &rcText, DT_CALCRECT); + } + /* + * If not owner draw, then do the drawing ourselves. + * + * Draw the icon. + */ + if (infoPtr->himl && (item->mask & TCIF_IMAGE)) + { + INT cx; + INT cy; + + ImageList_GetIconSize(infoPtr->himl, &cx, &cy); + + if(lStyle & TCS_VERTICAL) + { + center_offset_h = ((drawRect->bottom - drawRect->top) - (cy + infoPtr->uHItemPadding + (rcText.right - rcText.left))) / 2; + center_offset_v = ((drawRect->right - drawRect->left) - (cx + infoPtr->uVItemPadding)) / 2; + } + else + { + center_offset_h = ((drawRect->right - drawRect->left) - (cx + infoPtr->uHItemPadding + (rcText.right - rcText.left))) / 2; + center_offset_v = ((drawRect->bottom - drawRect->top) - (cy + infoPtr->uVItemPadding)) / 2; + } + + if (lStyle & TCS_FIXEDWIDTH && lStyle & (TCS_FORCELABELLEFT | TCS_FORCEICONLEFT)) + center_offset_h = infoPtr->uHItemPadding; + + if (center_offset_h < 2) + center_offset_h = 2; + + if (center_offset_v < 0) + center_offset_v = 0; + + TRACE("for <%s>, c_o_h=%d, c_o_v=%d, draw=(%ld,%ld)-(%ld,%ld), textlen=%ld\n", + debugstr_w(item->pszText), center_offset_h, center_offset_v, + drawRect->left, drawRect->top, drawRect->right, drawRect->bottom, + (rcText.right-rcText.left)); + + if((lStyle & TCS_VERTICAL) && (lStyle & TCS_BOTTOM)) + { + rcImage.top = drawRect->top + center_offset_h; + /* if tab is TCS_VERTICAL and TCS_BOTTOM, the text is drawn from the */ + /* right side of the tab, but the image still uses the left as its x position */ + /* this keeps the image always drawn off of the same side of the tab */ + rcImage.left = drawRect->right - cx - center_offset_v; + drawRect->top += cy + infoPtr->uHItemPadding; + } + else if(lStyle & TCS_VERTICAL) + { + rcImage.top = drawRect->bottom - cy - center_offset_h; + rcImage.left = drawRect->left + center_offset_v; + drawRect->bottom -= cy + infoPtr->uHItemPadding; + } + else /* normal style, whether TCS_BOTTOM or not */ + { + rcImage.left = drawRect->left + center_offset_h; + rcImage.top = drawRect->top + center_offset_v; + drawRect->left += cx + infoPtr->uHItemPadding; + } + + TRACE("drawing image=%d, left=%ld, top=%ld\n", + item->iImage, rcImage.left, rcImage.top-1); + ImageList_Draw + ( + infoPtr->himl, + item->iImage, + hdc, + rcImage.left, + rcImage.top, + ILD_NORMAL + ); + } + + /* Now position text */ + if (lStyle & TCS_FIXEDWIDTH && lStyle & TCS_FORCELABELLEFT) + center_offset_h = infoPtr->uHItemPadding; + else + if(lStyle & TCS_VERTICAL) + center_offset_h = ((drawRect->bottom - drawRect->top) - (rcText.right - rcText.left)) / 2; + else + center_offset_h = ((drawRect->right - drawRect->left) - (rcText.right - rcText.left)) / 2; + + if(lStyle & TCS_VERTICAL) + { + if(lStyle & TCS_BOTTOM) + drawRect->top+=center_offset_h; + else + drawRect->bottom-=center_offset_h; + + center_offset_v = ((drawRect->right - drawRect->left) - (rcText.bottom - rcText.top)) / 2; + } + else + { + drawRect->left += center_offset_h; + center_offset_v = ((drawRect->bottom - drawRect->top) - (rcText.bottom - rcText.top)) / 2; + } + + /* if an item is selected, the text is shifted up instead of down */ + if (iItem == infoPtr->iSelected) + center_offset_v -= infoPtr->uVItemPadding / 2; + else + center_offset_v += infoPtr->uVItemPadding / 2; + + if (center_offset_v < 0) + center_offset_v = 0; + + if(lStyle & TCS_VERTICAL) + drawRect->left += center_offset_v; + else + drawRect->top += center_offset_v; + + /* Draw the text */ + if(lStyle & TCS_VERTICAL) /* if we are vertical rotate the text and each character */ + { + static const WCHAR ArialW[] = { 'A','r','i','a','l',0 }; + LOGFONTW logfont; + HFONT hFont = 0; + INT nEscapement = 900; + INT nOrientation = 900; + + if(lStyle & TCS_BOTTOM) + { + nEscapement = -900; + nOrientation = -900; + } + + /* to get a font with the escapement and orientation we are looking for, we need to */ + /* call CreateFontIndirectA, which requires us to set the values of the logfont we pass in */ + if (!GetObjectW((infoPtr->hFont) ? + infoPtr->hFont : GetStockObject(SYSTEM_FONT), + sizeof(LOGFONTW),&logfont)) + { + INT iPointSize = 9; + + lstrcpyW(logfont.lfFaceName, ArialW); + logfont.lfHeight = -MulDiv(iPointSize, GetDeviceCaps(hdc, LOGPIXELSY), + 72); + logfont.lfWeight = FW_NORMAL; + logfont.lfItalic = 0; + logfont.lfUnderline = 0; + logfont.lfStrikeOut = 0; + } + + logfont.lfEscapement = nEscapement; + logfont.lfOrientation = nOrientation; + hFont = CreateFontIndirectW(&logfont); + SelectObject(hdc, hFont); + + if (item->pszText) + { + ExtTextOutW(hdc, + (lStyle & TCS_BOTTOM) ? drawRect->right : drawRect->left, + (!(lStyle & TCS_BOTTOM)) ? drawRect->bottom : drawRect->top, + ETO_CLIPPED, + drawRect, + item->pszText, + lstrlenW(item->pszText), + 0); + } + + DeleteObject(hFont); + } + else + { + TRACE("for <%s>, c_o_h=%d, c_o_v=%d, draw=(%ld,%ld)-(%ld,%ld), textlen=%ld\n", + debugstr_w(item->pszText), center_offset_h, center_offset_v, + drawRect->left, drawRect->top, drawRect->right, drawRect->bottom, + (rcText.right-rcText.left)); + if (item->pszText) + { + DrawTextW + ( + hdc, + item->pszText, + lstrlenW(item->pszText), + drawRect, + DT_LEFT | DT_SINGLELINE + ); + } + } + + *drawRect = rcTemp; /* restore drawRect */ + } + + /* + * Cleanup + */ + SelectObject(hdc, hOldFont); + SetBkMode(hdc, oldBkMode); + SelectObject(hdc, holdPen); + DeleteObject( htextPen ); +} + +/****************************************************************************** + * TAB_DrawItem + * + * This method is used to draw a single tab into the tab control. + */ +static void TAB_DrawItem( + TAB_INFO *infoPtr, + HDC hdc, + INT iItem) +{ + LONG lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); + RECT itemRect; + RECT selectedRect; + BOOL isVisible; + RECT r, fillRect, r1; + INT clRight = 0; + INT clBottom = 0; + COLORREF bkgnd, corner; + + /* + * Get the rectangle for the item. + */ + isVisible = TAB_InternalGetItemRect(infoPtr, + iItem, + &itemRect, + &selectedRect); + + if (isVisible) + { + RECT rUD, rC; + + /* Clip UpDown control to not draw over it */ + if (infoPtr->needsScrolling) + { + GetWindowRect(infoPtr->hwnd, &rC); + GetWindowRect(infoPtr->hwndUpDown, &rUD); + ExcludeClipRect(hdc, rUD.left - rC.left, rUD.top - rC.top, rUD.right - rC.left, rUD.bottom - rC.top); + } + + /* If you need to see what the control is doing, + * then override these variables. They will change what + * fill colors are used for filling the tabs, and the + * corners when drawing the edge. + */ + bkgnd = comctl32_color.clrBtnFace; + corner = comctl32_color.clrBtnFace; + + if (lStyle & TCS_BUTTONS) + { + /* Get item rectangle */ + r = itemRect; + + /* Separators between flat buttons */ + if (lStyle & TCS_FLATBUTTONS) + { + r1 = r; + r1.right += (FLAT_BTN_SPACINGX -2); + DrawEdge(hdc, &r1, EDGE_ETCHED, BF_RIGHT); + } + + if (iItem == infoPtr->iSelected) + { + DrawEdge(hdc, &r, EDGE_SUNKEN, BF_SOFT|BF_RECT); + + OffsetRect(&r, 1, 1); + } + else /* ! selected */ + { + if (!(lStyle & TCS_FLATBUTTONS)) + DrawEdge(hdc, &r, EDGE_RAISED, BF_SOFT|BF_RECT); + } + } + else /* !TCS_BUTTONS */ + { + /* We draw a rectangle of different sizes depending on the selection + * state. */ + if (iItem == infoPtr->iSelected) { + RECT rect; + GetClientRect (infoPtr->hwnd, &rect); + clRight = rect.right; + clBottom = rect.bottom; + r = selectedRect; + } + else + r = itemRect; + + /* + * Erase the background. (Delay it but setup rectangle.) + * This is necessary when drawing the selected item since it is larger + * than the others, it might overlap with stuff already drawn by the + * other tabs + */ + fillRect = r; + + if(lStyle & TCS_VERTICAL) + { + /* These are for adjusting the drawing of a Selected tab */ + /* The initial values are for the normal case of non-Selected */ + int ZZ = 1; /* Do not strech if selected */ + if (iItem == infoPtr->iSelected) { + ZZ = 0; + + /* if leftmost draw the line longer */ + if(selectedRect.top == 0) + fillRect.top += CONTROL_BORDER_SIZEY; + /* if rightmost draw the line longer */ + if(selectedRect.bottom == clBottom) + fillRect.bottom -= CONTROL_BORDER_SIZEY; + } + + if (lStyle & TCS_BOTTOM) + { + /* Adjust both rectangles to match native */ + r.left += (1-ZZ); + + TRACE(" item=%d, fill=(%ld,%ld)-(%ld,%ld), edge=(%ld,%ld)-(%ld,%ld)\n", + iItem, + fillRect.left,fillRect.top,fillRect.right,fillRect.bottom, + r.left,r.top,r.right,r.bottom); + + /* Clear interior */ + SetBkColor(hdc, bkgnd); + ExtTextOutW(hdc, 0, 0, 2, &fillRect, NULL, 0, 0); + + /* Draw rectangular edge around tab */ + DrawEdge(hdc, &r, EDGE_RAISED, BF_SOFT|BF_RIGHT|BF_TOP|BF_BOTTOM); + + /* Now erase the top corner and draw diagonal edge */ + SetBkColor(hdc, corner); + r1.left = r.right - ROUND_CORNER_SIZE - 1; + r1.top = r.top; + r1.right = r.right; + r1.bottom = r1.top + ROUND_CORNER_SIZE; + ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0); + r1.right--; + DrawEdge(hdc, &r1, EDGE_RAISED, BF_SOFT|BF_DIAGONAL_ENDTOPLEFT); + + /* Now erase the bottom corner and draw diagonal edge */ + r1.left = r.right - ROUND_CORNER_SIZE - 1; + r1.bottom = r.bottom; + r1.right = r.right; + r1.top = r1.bottom - ROUND_CORNER_SIZE; + ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0); + r1.right--; + DrawEdge(hdc, &r1, EDGE_RAISED, BF_SOFT|BF_DIAGONAL_ENDBOTTOMLEFT); + + if ((iItem == infoPtr->iSelected) && (selectedRect.top == 0)) { + r1 = r; + r1.right = r1.left; + r1.left--; + DrawEdge(hdc, &r1, EDGE_RAISED, BF_SOFT|BF_TOP); + } + + } + else + { + TRACE(" item=%d, fill=(%ld,%ld)-(%ld,%ld), edge=(%ld,%ld)-(%ld,%ld)\n", + iItem, + fillRect.left,fillRect.top,fillRect.right,fillRect.bottom, + r.left,r.top,r.right,r.bottom); + + /* Clear interior */ + SetBkColor(hdc, bkgnd); + ExtTextOutW(hdc, 0, 0, 2, &fillRect, NULL, 0, 0); + + /* Draw rectangular edge around tab */ + DrawEdge(hdc, &r, EDGE_RAISED, BF_SOFT|BF_LEFT|BF_TOP|BF_BOTTOM); + + /* Now erase the top corner and draw diagonal edge */ + SetBkColor(hdc, corner); + r1.left = r.left; + r1.top = r.top; + r1.right = r1.left + ROUND_CORNER_SIZE + 1; + r1.bottom = r1.top + ROUND_CORNER_SIZE; + ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0); + r1.left++; + DrawEdge(hdc, &r1, EDGE_RAISED, BF_SOFT|BF_DIAGONAL_ENDTOPRIGHT); + + /* Now erase the bottom corner and draw diagonal edge */ + r1.left = r.left; + r1.bottom = r.bottom; + r1.right = r1.left + ROUND_CORNER_SIZE + 1; + r1.top = r1.bottom - ROUND_CORNER_SIZE; + ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0); + r1.left++; + DrawEdge(hdc, &r1, EDGE_SUNKEN, BF_DIAGONAL_ENDTOPLEFT); + } + } + else /* ! TCS_VERTICAL */ + { + /* These are for adjusting the drawing of a Selected tab */ + /* The initial values are for the normal case of non-Selected */ + if (iItem == infoPtr->iSelected) { + /* if leftmost draw the line longer */ + if(selectedRect.left == 0) + fillRect.left += CONTROL_BORDER_SIZEX; + /* if rightmost draw the line longer */ + if(selectedRect.right == clRight) + fillRect.right -= CONTROL_BORDER_SIZEX; + } + + if (lStyle & TCS_BOTTOM) + { + /* Adjust both rectangles for topmost row */ + if (TAB_GetItem(infoPtr, iItem)->rect.top == infoPtr->uNumRows-1) + { + fillRect.top -= 2; + r.top -= 1; + } + + TRACE(" item=%d, fill=(%ld,%ld)-(%ld,%ld), edge=(%ld,%ld)-(%ld,%ld)\n", + iItem, + fillRect.left,fillRect.top,fillRect.right,fillRect.bottom, + r.left,r.top,r.right,r.bottom); + + /* Clear interior */ + SetBkColor(hdc, bkgnd); + ExtTextOutW(hdc, 0, 0, 2, &fillRect, NULL, 0, 0); + + /* Draw rectangular edge around tab */ + DrawEdge(hdc, &r, EDGE_RAISED, BF_SOFT|BF_LEFT|BF_BOTTOM|BF_RIGHT); + + /* Now erase the righthand corner and draw diagonal edge */ + SetBkColor(hdc, corner); + r1.left = r.right - ROUND_CORNER_SIZE; + r1.bottom = r.bottom; + r1.right = r.right; + r1.top = r1.bottom - ROUND_CORNER_SIZE - 1; + ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0); + r1.bottom--; + DrawEdge(hdc, &r1, EDGE_RAISED, BF_SOFT|BF_DIAGONAL_ENDBOTTOMLEFT); + + /* Now erase the lefthand corner and draw diagonal edge */ + r1.left = r.left; + r1.bottom = r.bottom; + r1.right = r1.left + ROUND_CORNER_SIZE; + r1.top = r1.bottom - ROUND_CORNER_SIZE - 1; + ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0); + r1.bottom--; + DrawEdge(hdc, &r1, EDGE_RAISED, BF_SOFT|BF_DIAGONAL_ENDTOPLEFT); + + if (iItem == infoPtr->iSelected) + { + r.top += 2; + r.left += 1; + if (selectedRect.left == 0) + { + r1 = r; + r1.bottom = r1.top; + r1.top--; + DrawEdge(hdc, &r1, EDGE_RAISED, BF_SOFT|BF_LEFT); + } + } + + } + else + { + /* Adjust both rectangles for bottommost row */ + if (TAB_GetItem(infoPtr, iItem)->rect.top == infoPtr->uNumRows-1) + { + fillRect.bottom += 3; + r.bottom += 2; + } + + TRACE(" item=%d, fill=(%ld,%ld)-(%ld,%ld), edge=(%ld,%ld)-(%ld,%ld)\n", + iItem, + fillRect.left,fillRect.top,fillRect.right,fillRect.bottom, + r.left,r.top,r.right,r.bottom); + + /* Clear interior */ + SetBkColor(hdc, bkgnd); + ExtTextOutW(hdc, 0, 0, 2, &fillRect, NULL, 0, 0); + + /* Draw rectangular edge around tab */ + DrawEdge(hdc, &r, EDGE_RAISED, BF_SOFT|BF_LEFT|BF_TOP|BF_RIGHT); + + /* Now erase the righthand corner and draw diagonal edge */ + SetBkColor(hdc, corner); + r1.left = r.right - ROUND_CORNER_SIZE; + r1.top = r.top; + r1.right = r.right; + r1.bottom = r1.top + ROUND_CORNER_SIZE + 1; + ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0); + r1.top++; + DrawEdge(hdc, &r1, EDGE_RAISED, BF_SOFT|BF_DIAGONAL_ENDBOTTOMRIGHT); + + /* Now erase the lefthand corner and draw diagonal edge */ + r1.left = r.left; + r1.top = r.top; + r1.right = r1.left + ROUND_CORNER_SIZE; + r1.bottom = r1.top + ROUND_CORNER_SIZE + 1; + ExtTextOutW(hdc, 0, 0, 2, &r1, NULL, 0, 0); + r1.top++; + DrawEdge(hdc, &r1, EDGE_RAISED, BF_SOFT|BF_DIAGONAL_ENDTOPRIGHT); + } + } + } + + TAB_DumpItemInternal(infoPtr, iItem); + + /* This modifies r to be the text rectangle. */ + TAB_DrawItemInterior(infoPtr, hdc, iItem, &r); + } +} + +/****************************************************************************** + * TAB_DrawBorder + * + * This method is used to draw the raised border around the tab control + * "content" area. + */ +static void TAB_DrawBorder (TAB_INFO *infoPtr, HDC hdc) +{ + RECT rect; + DWORD lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); + + GetClientRect (infoPtr->hwnd, &rect); + + /* + * Adjust for the style + */ + + if (infoPtr->uNumItem) + { + if ((lStyle & TCS_BOTTOM) && !(lStyle & TCS_VERTICAL)) + rect.bottom -= infoPtr->tabHeight * infoPtr->uNumRows + CONTROL_BORDER_SIZEX; + else if((lStyle & TCS_BOTTOM) && (lStyle & TCS_VERTICAL)) + rect.right -= infoPtr->tabHeight * infoPtr->uNumRows + CONTROL_BORDER_SIZEX; + else if(lStyle & TCS_VERTICAL) + rect.left += infoPtr->tabHeight * infoPtr->uNumRows + CONTROL_BORDER_SIZEX; + else /* not TCS_VERTICAL and not TCS_BOTTOM */ + rect.top += infoPtr->tabHeight * infoPtr->uNumRows + CONTROL_BORDER_SIZEX; + } + + TRACE("border=(%ld,%ld)-(%ld,%ld)\n", + rect.left, rect.top, rect.right, rect.bottom); + + DrawEdge(hdc, &rect, EDGE_RAISED, BF_SOFT|BF_RECT); +} + +/****************************************************************************** + * TAB_Refresh + * + * This method repaints the tab control.. + */ +static void TAB_Refresh (TAB_INFO *infoPtr, HDC hdc) +{ + HFONT hOldFont; + INT i; + + if (!infoPtr->DoRedraw) + return; + + hOldFont = SelectObject (hdc, infoPtr->hFont); + + if (GetWindowLongW(infoPtr->hwnd, GWL_STYLE) & TCS_BUTTONS) + { + for (i = 0; i < infoPtr->uNumItem; i++) + TAB_DrawItem (infoPtr, hdc, i); + } + else + { + /* Draw all the non selected item first */ + for (i = 0; i < infoPtr->uNumItem; i++) + { + if (i != infoPtr->iSelected) + TAB_DrawItem (infoPtr, hdc, i); + } + + /* Now, draw the border, draw it before the selected item + * since the selected item overwrites part of the border. */ + TAB_DrawBorder (infoPtr, hdc); + + /* Then, draw the selected item */ + TAB_DrawItem (infoPtr, hdc, infoPtr->iSelected); + + /* If we haven't set the current focus yet, set it now. + * Only happens when we first paint the tab controls */ + if (infoPtr->uFocus == -1) + TAB_SetCurFocus(infoPtr, infoPtr->iSelected); + } + + SelectObject (hdc, hOldFont); +} + +static inline DWORD TAB_GetRowCount (const TAB_INFO *infoPtr) +{ + return infoPtr->uNumRows; +} + +static inline LRESULT TAB_SetRedraw (TAB_INFO *infoPtr, BOOL doRedraw) +{ + infoPtr->DoRedraw = doRedraw; + return 0; +} + +/****************************************************************************** + * TAB_EnsureSelectionVisible + * + * This method will make sure that the current selection is completely + * visible by scrolling until it is. + */ +static void TAB_EnsureSelectionVisible( + TAB_INFO* infoPtr) +{ + INT iSelected = infoPtr->iSelected; + LONG lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); + INT iOrigLeftmostVisible = infoPtr->leftmostVisible; + + /* set the items row to the bottommost row or topmost row depending on + * style */ + if ((infoPtr->uNumRows > 1) && !(lStyle & TCS_BUTTONS)) + { + TAB_ITEM *selected = TAB_GetItem(infoPtr, iSelected); + INT newselected; + INT iTargetRow; + + if(lStyle & TCS_VERTICAL) + newselected = selected->rect.left; + else + newselected = selected->rect.top; + + /* the target row is always (number of rows - 1) + as row 0 is furthest from the clientRect */ + iTargetRow = infoPtr->uNumRows - 1; + + if (newselected != iTargetRow) + { + UINT i; + if(lStyle & TCS_VERTICAL) + { + for (i=0; i < infoPtr->uNumItem; i++) + { + /* move everything in the row of the selected item to the iTargetRow */ + TAB_ITEM *item = TAB_GetItem(infoPtr, i); + + if (item->rect.left == newselected ) + item->rect.left = iTargetRow; + else + { + if (item->rect.left > newselected) + item->rect.left-=1; + } + } + } + else + { + for (i=0; i < infoPtr->uNumItem; i++) + { + TAB_ITEM *item = TAB_GetItem(infoPtr, i); + + if (item->rect.top == newselected ) + item->rect.top = iTargetRow; + else + { + if (item->rect.top > newselected) + item->rect.top-=1; + } + } + } + TAB_RecalcHotTrack(infoPtr, NULL, NULL, NULL); + } + } + + /* + * Do the trivial cases first. + */ + if ( (!infoPtr->needsScrolling) || + (infoPtr->hwndUpDown==0) || (lStyle & TCS_VERTICAL)) + return; + + if (infoPtr->leftmostVisible >= iSelected) + { + infoPtr->leftmostVisible = iSelected; + } + else + { + TAB_ITEM *selected = TAB_GetItem(infoPtr, iSelected); + RECT r; + INT width; + UINT i; + + /* Calculate the part of the client area that is visible */ + GetClientRect(infoPtr->hwnd, &r); + width = r.right; + + GetClientRect(infoPtr->hwndUpDown, &r); + width -= r.right; + + if ((selected->rect.right - + selected->rect.left) >= width ) + { + /* Special case: width of selected item is greater than visible + * part of control. + */ + infoPtr->leftmostVisible = iSelected; + } + else + { + for (i = infoPtr->leftmostVisible; i < infoPtr->uNumItem; i++) + { + if ((selected->rect.right - TAB_GetItem(infoPtr, i)->rect.left) < width) + break; + } + infoPtr->leftmostVisible = i; + } + } + + if (infoPtr->leftmostVisible != iOrigLeftmostVisible) + TAB_RecalcHotTrack(infoPtr, NULL, NULL, NULL); + + SendMessageW(infoPtr->hwndUpDown, UDM_SETPOS, 0, + MAKELONG(infoPtr->leftmostVisible, 0)); +} + +/****************************************************************************** + * TAB_InvalidateTabArea + * + * This method will invalidate the portion of the control that contains the + * tabs. It is called when the state of the control changes and needs + * to be redisplayed + */ +static void TAB_InvalidateTabArea(TAB_INFO* infoPtr) +{ + RECT clientRect, rInvalidate, rAdjClient; + DWORD lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); + INT lastRow = infoPtr->uNumRows - 1; + RECT rect; + + if (lastRow < 0) return; + + GetClientRect(infoPtr->hwnd, &clientRect); + rInvalidate = clientRect; + rAdjClient = clientRect; + + TAB_AdjustRect(infoPtr, 0, &rAdjClient); + + TAB_InternalGetItemRect(infoPtr, infoPtr->uNumItem-1 , &rect, NULL); + if ((lStyle & TCS_BOTTOM) && (lStyle & TCS_VERTICAL)) + { + rInvalidate.left = rAdjClient.right; + if (infoPtr->uNumRows == 1) + rInvalidate.bottom = clientRect.top + rect.bottom + 2 * SELECTED_TAB_OFFSET; + } + else if(lStyle & TCS_VERTICAL) + { + rInvalidate.right = rAdjClient.left; + if (infoPtr->uNumRows == 1) + rInvalidate.bottom = clientRect.top + rect.bottom + 2 * SELECTED_TAB_OFFSET; + } + else if (lStyle & TCS_BOTTOM) + { + rInvalidate.top = rAdjClient.bottom; + if (infoPtr->uNumRows == 1) + rInvalidate.right = clientRect.left + rect.right + 2 * SELECTED_TAB_OFFSET; + } + else + { + rInvalidate.bottom = rAdjClient.top; + if (infoPtr->uNumRows == 1) + rInvalidate.right = clientRect.left + rect.right + 2 * SELECTED_TAB_OFFSET; + } + + /* Punch out the updown control */ + if (infoPtr->needsScrolling && (rInvalidate.right > 0)) { + RECT r; + GetClientRect(infoPtr->hwndUpDown, &r); + if (rInvalidate.right > clientRect.right - r.left) + rInvalidate.right = rInvalidate.right - (r.right - r.left); + else + rInvalidate.right = clientRect.right - r.left; + } + + TRACE("invalidate (%ld,%ld)-(%ld,%ld)\n", + rInvalidate.left, rInvalidate.top, + rInvalidate.right, rInvalidate.bottom); + + InvalidateRect(infoPtr->hwnd, &rInvalidate, TRUE); +} + +static inline LRESULT TAB_Paint (TAB_INFO *infoPtr, HDC hdcPaint) +{ + HDC hdc; + PAINTSTRUCT ps; + + if (hdcPaint) + hdc = hdcPaint; + else + { + hdc = BeginPaint (infoPtr->hwnd, &ps); + TRACE("erase %d, rect=(%ld,%ld)-(%ld,%ld)\n", + ps.fErase, + ps.rcPaint.left,ps.rcPaint.top,ps.rcPaint.right,ps.rcPaint.bottom); + } + + TAB_Refresh (infoPtr, hdc); + + if (!hdcPaint) + EndPaint (infoPtr->hwnd, &ps); + + return 0; +} + +static LRESULT +TAB_InsertItemT (TAB_INFO *infoPtr, WPARAM wParam, LPARAM lParam, BOOL bUnicode) +{ + TAB_ITEM *item; + TCITEMW *pti; + INT iItem; + RECT rect; + + GetClientRect (infoPtr->hwnd, &rect); + TRACE("Rect: %p T %li, L %li, B %li, R %li\n", infoPtr->hwnd, + rect.top, rect.left, rect.bottom, rect.right); + + pti = (TCITEMW *)lParam; + iItem = (INT)wParam; + + if (iItem < 0) return -1; + if (iItem > infoPtr->uNumItem) + iItem = infoPtr->uNumItem; + + TAB_DumpItemExternalT(pti, iItem, bUnicode); + + + if (infoPtr->uNumItem == 0) { + infoPtr->items = Alloc (TAB_ITEM_SIZE(infoPtr)); + infoPtr->uNumItem++; + infoPtr->iSelected = 0; + } + else { + LPBYTE oldItems = (LPBYTE)infoPtr->items; + + infoPtr->uNumItem++; + infoPtr->items = Alloc (TAB_ITEM_SIZE(infoPtr) * infoPtr->uNumItem); + + /* pre insert copy */ + if (iItem > 0) { + memcpy (infoPtr->items, oldItems, + iItem * TAB_ITEM_SIZE(infoPtr)); + } + + /* post insert copy */ + if (iItem < infoPtr->uNumItem - 1) { + memcpy (TAB_GetItem(infoPtr, iItem + 1), + oldItems + iItem * TAB_ITEM_SIZE(infoPtr), + (infoPtr->uNumItem - iItem - 1) * TAB_ITEM_SIZE(infoPtr)); + + } + + if (iItem <= infoPtr->iSelected) + infoPtr->iSelected++; + + Free (oldItems); + } + + item = TAB_GetItem(infoPtr, iItem); + + item->mask = pti->mask; + item->pszText = NULL; + + if (pti->mask & TCIF_TEXT) + { + if (bUnicode) + Str_SetPtrW (&item->pszText, pti->pszText); + else + Str_SetPtrAtoW (&item->pszText, (LPSTR)pti->pszText); + } + + if (pti->mask & TCIF_IMAGE) + item->iImage = pti->iImage; + else + item->iImage = -1; + + if (pti->mask & TCIF_PARAM) + memcpy(item->extra, &pti->lParam, infoPtr->cbInfo); + else + memset(item->extra, 0, infoPtr->cbInfo); + + TAB_SetItemBounds(infoPtr); + if (infoPtr->uNumItem > 1) + TAB_InvalidateTabArea(infoPtr); + else + InvalidateRect(infoPtr->hwnd, NULL, TRUE); + + TRACE("[%p]: added item %d %s\n", + infoPtr->hwnd, iItem, debugstr_w(item->pszText)); + + return iItem; +} + +static LRESULT +TAB_SetItemSize (TAB_INFO *infoPtr, LPARAM lParam) +{ + LONG lStyle = GetWindowLongW(infoPtr->hwnd, GWL_STYLE); + LONG lResult = 0; + BOOL bNeedPaint = FALSE; + + lResult = MAKELONG(infoPtr->tabWidth, infoPtr->tabHeight); + + /* UNDOCUMENTED: If requested Width or Height is 0 this means that program wants to use auto size. */ + if (lStyle & TCS_FIXEDWIDTH && (infoPtr->tabWidth != (INT)LOWORD(lParam))) + { + infoPtr->tabWidth = max((INT)LOWORD(lParam), infoPtr->tabMinWidth); + bNeedPaint = TRUE; + } + + if (infoPtr->tabHeight != (INT)HIWORD(lParam)) + { + if ((infoPtr->fHeightSet = ((INT)HIWORD(lParam) != 0))) + infoPtr->tabHeight = (INT)HIWORD(lParam); + + bNeedPaint = TRUE; + } + TRACE("was h=%d,w=%d, now h=%d,w=%d\n", + HIWORD(lResult), LOWORD(lResult), + infoPtr->tabHeight, infoPtr->tabWidth); + + if (bNeedPaint) + { + TAB_SetItemBounds(infoPtr); + RedrawWindow(infoPtr->hwnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW); + } + + return lResult; +} + +static inline LRESULT TAB_SetMinTabWidth (TAB_INFO *infoPtr, INT cx) +{ + INT oldcx = 0; + + TRACE("(%p,%d)\n", infoPtr, cx); + + if (infoPtr) { + oldcx = infoPtr->tabMinWidth; + infoPtr->tabMinWidth = (cx==-1)?DEFAULT_TAB_WIDTH:cx; + } + + return oldcx; +} + +static inline LRESULT +TAB_HighlightItem (TAB_INFO *infoPtr, INT iItem, BOOL fHighlight) +{ + LPDWORD lpState; + + TRACE("(%p,%d,%s)\n", infoPtr, iItem, fHighlight ? "true" : "false"); + + if (!infoPtr || iItem < 0 || iItem >= infoPtr->uNumItem) + return FALSE; + + lpState = &TAB_GetItem(infoPtr, iItem)->dwState; + + if (fHighlight) + *lpState |= TCIS_HIGHLIGHTED; + else + *lpState &= ~TCIS_HIGHLIGHTED; + + return TRUE; +} + +static LRESULT +TAB_SetItemT (TAB_INFO *infoPtr, INT iItem, LPTCITEMW tabItem, BOOL bUnicode) +{ + TAB_ITEM *wineItem; + + TRACE("(%p,%d,%p,%s)\n", infoPtr, iItem, tabItem, bUnicode ? "true" : "false"); + + if (iItem < 0 || iItem >= infoPtr->uNumItem) + return FALSE; + + TAB_DumpItemExternalT(tabItem, iItem, bUnicode); + + wineItem = TAB_GetItem(infoPtr, iItem); + + if (tabItem->mask & TCIF_IMAGE) + wineItem->iImage = tabItem->iImage; + + if (tabItem->mask & TCIF_PARAM) + memcpy(wineItem->extra, &tabItem->lParam, infoPtr->cbInfo); + + if (tabItem->mask & TCIF_RTLREADING) + FIXME("TCIF_RTLREADING\n"); + + if (tabItem->mask & TCIF_STATE) + wineItem->dwState = tabItem->dwState; + + if (tabItem->mask & TCIF_TEXT) + { + if (wineItem->pszText) + { + Free(wineItem->pszText); + wineItem->pszText = NULL; + } + if (bUnicode) + Str_SetPtrW(&wineItem->pszText, tabItem->pszText); + else + Str_SetPtrAtoW(&wineItem->pszText, (LPSTR)tabItem->pszText); + } + + /* Update and repaint tabs */ + TAB_SetItemBounds(infoPtr); + TAB_InvalidateTabArea(infoPtr); + + return TRUE; +} + +static inline LRESULT TAB_GetItemCount (const TAB_INFO *infoPtr) +{ + return infoPtr->uNumItem; +} + + +static LRESULT +TAB_GetItemT (TAB_INFO *infoPtr, INT iItem, LPTCITEMW tabItem, BOOL bUnicode) +{ + TAB_ITEM *wineItem; + + TRACE("(%p,%d,%p,%s)\n", infoPtr, iItem, tabItem, bUnicode ? "true" : "false"); + + if (iItem < 0 || iItem >= infoPtr->uNumItem) + return FALSE; + + wineItem = TAB_GetItem(infoPtr, iItem); + + if (tabItem->mask & TCIF_IMAGE) + tabItem->iImage = wineItem->iImage; + + if (tabItem->mask & TCIF_PARAM) + memcpy(&tabItem->lParam, wineItem->extra, infoPtr->cbInfo); + + if (tabItem->mask & TCIF_RTLREADING) + FIXME("TCIF_RTLREADING\n"); + + if (tabItem->mask & TCIF_STATE) + tabItem->dwState = wineItem->dwState; + + if (tabItem->mask & TCIF_TEXT) + { + if (bUnicode) + Str_GetPtrW (wineItem->pszText, tabItem->pszText, tabItem->cchTextMax); + else + Str_GetPtrWtoA (wineItem->pszText, (LPSTR)tabItem->pszText, tabItem->cchTextMax); + } + + TAB_DumpItemExternalT(tabItem, iItem, bUnicode); + + return TRUE; +} + + +static LRESULT TAB_DeleteItem (TAB_INFO *infoPtr, INT iItem) +{ + BOOL bResult = FALSE; + + TRACE("(%p, %d)\n", infoPtr, iItem); + + if ((iItem >= 0) && (iItem < infoPtr->uNumItem)) + { + TAB_ITEM *item = TAB_GetItem(infoPtr, iItem); + LPBYTE oldItems = (LPBYTE)infoPtr->items; + + TAB_InvalidateTabArea(infoPtr); + + if ((item->mask & TCIF_TEXT) && item->pszText) + Free(item->pszText); + + infoPtr->uNumItem--; + + if (!infoPtr->uNumItem) + { + infoPtr->items = NULL; + if (infoPtr->iHotTracked >= 0) + { + KillTimer(infoPtr->hwnd, TAB_HOTTRACK_TIMER); + infoPtr->iHotTracked = -1; + } + } + else + { + infoPtr->items = Alloc(TAB_ITEM_SIZE(infoPtr) * infoPtr->uNumItem); + + if (iItem > 0) + memcpy(infoPtr->items, oldItems, iItem * TAB_ITEM_SIZE(infoPtr)); + + if (iItem < infoPtr->uNumItem) + memcpy(TAB_GetItem(infoPtr, iItem), + oldItems + (iItem + 1) * TAB_ITEM_SIZE(infoPtr), + (infoPtr->uNumItem - iItem) * TAB_ITEM_SIZE(infoPtr)); + + if (iItem <= infoPtr->iHotTracked) + { + /* When tabs move left/up, the hot track item may change */ + FIXME("Recalc hot track"); + } + } + Free(oldItems); + + /* Readjust the selected index */ + if ((iItem == infoPtr->iSelected) && (iItem > 0)) + infoPtr->iSelected--; + + if (iItem < infoPtr->iSelected) + infoPtr->iSelected--; + + if (infoPtr->uNumItem == 0) + infoPtr->iSelected = -1; + + /* Reposition and repaint tabs */ + TAB_SetItemBounds(infoPtr); + + bResult = TRUE; + } + + return bResult; +} + +static inline LRESULT TAB_DeleteAllItems (TAB_INFO *infoPtr) +{ + TRACE("(%p)\n", infoPtr); + while (infoPtr->uNumItem) + TAB_DeleteItem (infoPtr, 0); + return TRUE; +} + + +static inline LRESULT TAB_GetFont (const TAB_INFO *infoPtr) +{ + TRACE("(%p) returning %p\n", infoPtr, infoPtr->hFont); + return (LRESULT)infoPtr->hFont; +} + +static inline LRESULT TAB_SetFont (TAB_INFO *infoPtr, HFONT hNewFont) +{ + TRACE("(%p,%p)\n", infoPtr, hNewFont); + + infoPtr->hFont = hNewFont; + + TAB_SetItemBounds(infoPtr); + + TAB_InvalidateTabArea(infoPtr); + + return 0; +} + + +static inline LRESULT TAB_GetImageList (const TAB_INFO *infoPtr) +{ + TRACE("\n"); + return (LRESULT)infoPtr->himl; +} + +static inline LRESULT TAB_SetImageList (TAB_INFO *infoPtr, HIMAGELIST himlNew) +{ + HIMAGELIST himlPrev = infoPtr->himl; + TRACE("\n"); + infoPtr->himl = himlNew; + return (LRESULT)himlPrev; +} + +static inline LRESULT TAB_GetUnicodeFormat (const TAB_INFO *infoPtr) +{ + return infoPtr->bUnicode; +} + +static inline LRESULT TAB_SetUnicodeFormat (TAB_INFO *infoPtr, BOOL bUnicode) +{ + BOOL bTemp = infoPtr->bUnicode; + + infoPtr->bUnicode = bUnicode; + + return bTemp; +} + +static inline LRESULT TAB_Size (TAB_INFO *infoPtr) +{ +/* I'm not really sure what the following code was meant to do. + This is what it is doing: + When WM_SIZE is sent with SIZE_RESTORED, the control + gets positioned in the top left corner. + + RECT parent_rect; + HWND parent; + UINT uPosFlags,cx,cy; + + uPosFlags=0; + if (!wParam) { + parent = GetParent (hwnd); + GetClientRect(parent, &parent_rect); + cx=LOWORD (lParam); + cy=HIWORD (lParam); + if (GetWindowLongW(hwnd, GWL_STYLE) & CCS_NORESIZE) + uPosFlags |= (SWP_NOSIZE | SWP_NOMOVE); + + SetWindowPos (hwnd, 0, parent_rect.left, parent_rect.top, + cx, cy, uPosFlags | SWP_NOZORDER); + } else { + FIXME("WM_SIZE flag %x %lx not handled\n", wParam, lParam); + } */ + + /* Recompute the size/position of the tabs. */ + TAB_SetItemBounds (infoPtr); + + /* Force a repaint of the control. */ + InvalidateRect(infoPtr->hwnd, NULL, TRUE); + + return 0; +} + + +static LRESULT TAB_Create (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TAB_INFO *infoPtr; + TEXTMETRICW fontMetrics; + HDC hdc; + HFONT hOldFont; + DWORD dwStyle; + + infoPtr = (TAB_INFO *)Alloc (sizeof(TAB_INFO)); + + SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)infoPtr); + + infoPtr->hwnd = hwnd; + infoPtr->hwndNotify = ((LPCREATESTRUCTW)lParam)->hwndParent; + infoPtr->uNumItem = 0; + infoPtr->uNumRows = 0; + infoPtr->uHItemPadding = 6; + infoPtr->uVItemPadding = 3; + infoPtr->uHItemPadding_s = 6; + infoPtr->uVItemPadding_s = 3; + infoPtr->hFont = 0; + infoPtr->items = 0; + infoPtr->hcurArrow = LoadCursorW (0, (LPWSTR)IDC_ARROW); + infoPtr->iSelected = -1; + infoPtr->iHotTracked = -1; + infoPtr->uFocus = -1; + infoPtr->hwndToolTip = 0; + infoPtr->DoRedraw = TRUE; + infoPtr->needsScrolling = FALSE; + infoPtr->hwndUpDown = 0; + infoPtr->leftmostVisible = 0; + infoPtr->fHeightSet = FALSE; + infoPtr->bUnicode = IsWindowUnicode (hwnd); + infoPtr->cbInfo = sizeof(LPARAM); + + TRACE("Created tab control, hwnd [%p]\n", hwnd); + + /* The tab control always has the WS_CLIPSIBLINGS style. Even + if you don't specify it in CreateWindow. This is necessary in + order for paint to work correctly. This follows windows behaviour. */ + dwStyle = GetWindowLongW(hwnd, GWL_STYLE); + SetWindowLongW(hwnd, GWL_STYLE, dwStyle|WS_CLIPSIBLINGS); + + if (dwStyle & TCS_TOOLTIPS) { + /* Create tooltip control */ + infoPtr->hwndToolTip = + CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, 0, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + hwnd, 0, 0, 0); + + /* Send NM_TOOLTIPSCREATED notification */ + if (infoPtr->hwndToolTip) { + NMTOOLTIPSCREATED nmttc; + + nmttc.hdr.hwndFrom = hwnd; + nmttc.hdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID); + nmttc.hdr.code = NM_TOOLTIPSCREATED; + nmttc.hwndToolTips = infoPtr->hwndToolTip; + + SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, + (WPARAM)GetWindowLongPtrW(hwnd, GWLP_ID), (LPARAM)&nmttc); + } + } + + /* + * We need to get text information so we need a DC and we need to select + * a font. + */ + hdc = GetDC(hwnd); + hOldFont = SelectObject (hdc, GetStockObject (SYSTEM_FONT)); + + /* Use the system font to determine the initial height of a tab. */ + GetTextMetricsW(hdc, &fontMetrics); + + /* + * Make sure there is enough space for the letters + growing the + * selected item + extra space for the selected item. + */ + infoPtr->tabHeight = fontMetrics.tmHeight + SELECTED_TAB_OFFSET + + ((dwStyle & TCS_BUTTONS) ? 2 : 1) * + infoPtr->uVItemPadding; + + /* Initialize the width of a tab. */ + infoPtr->tabWidth = DEFAULT_TAB_WIDTH; + infoPtr->tabMinWidth = 0; + + TRACE("tabH=%d, tabW=%d\n", infoPtr->tabHeight, infoPtr->tabWidth); + + SelectObject (hdc, hOldFont); + ReleaseDC(hwnd, hdc); + + return 0; +} + +static LRESULT +TAB_Destroy (TAB_INFO *infoPtr) +{ + UINT iItem; + + if (!infoPtr) + return 0; + + SetWindowLongPtrW(infoPtr->hwnd, 0, 0); + + if (infoPtr->items) { + for (iItem = 0; iItem < infoPtr->uNumItem; iItem++) { + if (TAB_GetItem(infoPtr, iItem)->pszText) + Free (TAB_GetItem(infoPtr, iItem)->pszText); + } + Free (infoPtr->items); + } + + if (infoPtr->hwndToolTip) + DestroyWindow (infoPtr->hwndToolTip); + + if (infoPtr->hwndUpDown) + DestroyWindow(infoPtr->hwndUpDown); + + if (infoPtr->iHotTracked >= 0) + KillTimer(infoPtr->hwnd, TAB_HOTTRACK_TIMER); + + Free (infoPtr); + return 0; +} + +static LRESULT TAB_NCCalcSize(HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + if (!wParam) + return 0; + return WVR_ALIGNTOP; +} + +static inline LRESULT +TAB_SetItemExtra (TAB_INFO *infoPtr, INT cbInfo) +{ + if (!infoPtr || cbInfo <= 0) + return FALSE; + + if (infoPtr->uNumItem) + { + /* FIXME: MSDN says this is not allowed, but this hasn't been verified */ + return FALSE; + } + + infoPtr->cbInfo = cbInfo; + return TRUE; +} + +static LRESULT WINAPI +TAB_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd); + + TRACE("hwnd=%p msg=%x wParam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam); + if (!infoPtr && (uMsg != WM_CREATE)) + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + + switch (uMsg) + { + case TCM_GETIMAGELIST: + return TAB_GetImageList (infoPtr); + + case TCM_SETIMAGELIST: + return TAB_SetImageList (infoPtr, (HIMAGELIST)lParam); + + case TCM_GETITEMCOUNT: + return TAB_GetItemCount (infoPtr); + + case TCM_GETITEMA: + case TCM_GETITEMW: + return TAB_GetItemT (infoPtr, (INT)wParam, (LPTCITEMW)lParam, uMsg == TCM_GETITEMW); + + case TCM_SETITEMA: + case TCM_SETITEMW: + return TAB_SetItemT (infoPtr, (INT)wParam, (LPTCITEMW)lParam, uMsg == TCM_SETITEMW); + + case TCM_DELETEITEM: + return TAB_DeleteItem (infoPtr, (INT)wParam); + + case TCM_DELETEALLITEMS: + return TAB_DeleteAllItems (infoPtr); + + case TCM_GETITEMRECT: + return TAB_GetItemRect (infoPtr, wParam, lParam); + + case TCM_GETCURSEL: + return TAB_GetCurSel (infoPtr); + + case TCM_HITTEST: + return TAB_HitTest (infoPtr, (LPTCHITTESTINFO)lParam); + + case TCM_SETCURSEL: + return TAB_SetCurSel (infoPtr, (INT)wParam); + + case TCM_INSERTITEMA: + case TCM_INSERTITEMW: + return TAB_InsertItemT (infoPtr, wParam, lParam, uMsg == TCM_INSERTITEMW); + + case TCM_SETITEMEXTRA: + return TAB_SetItemExtra (infoPtr, (int)wParam); + + case TCM_ADJUSTRECT: + return TAB_AdjustRect (infoPtr, (BOOL)wParam, (LPRECT)lParam); + + case TCM_SETITEMSIZE: + return TAB_SetItemSize (infoPtr, lParam); + + case TCM_REMOVEIMAGE: + FIXME("Unimplemented msg TCM_REMOVEIMAGE\n"); + return 0; + + case TCM_SETPADDING: + return TAB_SetPadding (infoPtr, lParam); + + case TCM_GETROWCOUNT: + return TAB_GetRowCount(infoPtr); + + case TCM_GETUNICODEFORMAT: + return TAB_GetUnicodeFormat (infoPtr); + + case TCM_SETUNICODEFORMAT: + return TAB_SetUnicodeFormat (infoPtr, (BOOL)wParam); + + case TCM_HIGHLIGHTITEM: + return TAB_HighlightItem (infoPtr, (INT)wParam, (BOOL)LOWORD(lParam)); + + case TCM_GETTOOLTIPS: + return TAB_GetToolTips (infoPtr); + + case TCM_SETTOOLTIPS: + return TAB_SetToolTips (infoPtr, (HWND)wParam); + + case TCM_GETCURFOCUS: + return TAB_GetCurFocus (infoPtr); + + case TCM_SETCURFOCUS: + return TAB_SetCurFocus (infoPtr, (INT)wParam); + + case TCM_SETMINTABWIDTH: + return TAB_SetMinTabWidth(infoPtr, (INT)lParam); + + case TCM_DESELECTALL: + FIXME("Unimplemented msg TCM_DESELECTALL\n"); + return 0; + + case TCM_GETEXTENDEDSTYLE: + FIXME("Unimplemented msg TCM_GETEXTENDEDSTYLE\n"); + return 0; + + case TCM_SETEXTENDEDSTYLE: + FIXME("Unimplemented msg TCM_SETEXTENDEDSTYLE\n"); + return 0; + + case WM_GETFONT: + return TAB_GetFont (infoPtr); + + case WM_SETFONT: + return TAB_SetFont (infoPtr, (HFONT)wParam); + + case WM_CREATE: + return TAB_Create (hwnd, wParam, lParam); + + case WM_NCDESTROY: + return TAB_Destroy (infoPtr); + + case WM_GETDLGCODE: + return DLGC_WANTARROWS | DLGC_WANTCHARS; + + case WM_LBUTTONDOWN: + return TAB_LButtonDown (infoPtr, wParam, lParam); + + case WM_LBUTTONUP: + return TAB_LButtonUp (infoPtr); + + case WM_NOTIFY: + return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, wParam, lParam); + + case WM_RBUTTONDOWN: + return TAB_RButtonDown (infoPtr); + + case WM_MOUSEMOVE: + return TAB_MouseMove (infoPtr, wParam, lParam); + + case WM_PAINT: + return TAB_Paint (infoPtr, (HDC)wParam); + + case WM_SIZE: + return TAB_Size (infoPtr); + + case WM_SETREDRAW: + return TAB_SetRedraw (infoPtr, (BOOL)wParam); + + case WM_HSCROLL: + return TAB_OnHScroll(infoPtr, (int)LOWORD(wParam), (int)HIWORD(wParam), (HWND)lParam); + + case WM_STYLECHANGED: + TAB_SetItemBounds (infoPtr); + InvalidateRect(hwnd, NULL, TRUE); + return 0; + + case WM_SYSCOLORCHANGE: + COMCTL32_RefreshSysColors(); + return 0; + + case WM_KILLFOCUS: + case WM_SETFOCUS: + TAB_FocusChanging(infoPtr); + break; /* Don't disturb normal focus behavior */ + + case WM_KEYUP: + return TAB_KeyUp(infoPtr, wParam); + case WM_NCHITTEST: + return TAB_NCHitTest(infoPtr, lParam); + + case WM_NCCALCSIZE: + return TAB_NCCalcSize(hwnd, wParam, lParam); + + default: + if (uMsg >= WM_USER && uMsg < WM_APP) + WARN("unknown msg %04x wp=%08x lp=%08lx\n", + uMsg, wParam, lParam); + break; + } + return DefWindowProcW(hwnd, uMsg, wParam, lParam); +} + + +void +TAB_Register (void) +{ + WNDCLASSW wndClass; + + ZeroMemory (&wndClass, sizeof(WNDCLASSW)); + wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; + wndClass.lpfnWndProc = TAB_WindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(TAB_INFO *); + wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); + wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); + wndClass.lpszClassName = WC_TABCONTROLW; + + RegisterClassW (&wndClass); +} + + +void +TAB_Unregister (void) +{ + UnregisterClassW (WC_TABCONTROLW, NULL); +} diff --git a/reactos/lib/comctl32/toolbar.c b/reactos/lib/comctl32/toolbar.c index 53f188490a2..cd8c0b43248 100644 --- a/reactos/lib/comctl32/toolbar.c +++ b/reactos/lib/comctl32/toolbar.c @@ -1,7366 +1,7366 @@ -/* - * Toolbar control - * - * Copyright 1998,1999 Eric Kohl - * Copyright 2000 Eric Kohl for CodeWeavers - * Copyright 2004 Robert Shearman - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTES - * - * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on Mar. 14, 2004, by Robert Shearman. - * - * Unless otherwise noted, we believe this code to be complete, as per - * the specification mentioned above. - * If you discover missing features or bugs please note them below. - * - * TODO: - * - Styles: - * - TBSTYLE_REGISTERDROP - * - TBSTYLE_EX_DOUBLEBUFFER - * - Messages: - * - TB_GETMETRICS - * - TB_GETOBJECT - * - TB_INSERTMARKHITTEST - * - TB_SAVERESTORE - * - TB_SETMETRICS - * - WM_WININICHANGE - * - Notifications: - * - NM_CHAR - * - NM_KEYDOWN - * - TBN_GETOBJECT - * - TBN_SAVE - * - Button wrapping (under construction). - * - Fix TB_SETROWS. - * - iListGap custom draw support. - * - * Testing: - * - Run tests using Waite Group Windows95 API Bible Volume 2. - * The second cdrom contains executables addstr.exe, btncount.exe, - * btnstate.exe, butstrsz.exe, chkbtn.exe, chngbmp.exe, customiz.exe, - * enablebtn.exe, getbmp.exe, getbtn.exe, getflags.exe, hidebtn.exe, - * indetbtn.exe, insbtn.exe, pressbtn.exe, setbtnsz.exe, setcmdid.exe, - * setparnt.exe, setrows.exe, toolwnd.exe. - * - Microsoft's controlspy examples. - * - Charles Petzold's 'Programming Windows': gadgets.exe - * - * Differences between MSDN and actual native control operation: - * 1. MSDN says: "TBSTYLE_LIST: Creates a flat toolbar with button text - * to the right of the bitmap. Otherwise, this style is - * identical to TBSTYLE_FLAT." - * As implemented by both v4.71 and v5.80 of the native COMCTL32.DLL - * you can create a TBSTYLE_LIST without TBSTYLE_FLAT and the result - * is non-flat non-transparent buttons. Therefore TBSTYLE_LIST does - * *not* imply TBSTYLE_FLAT as documented. (GA 8/2001) - * - */ - -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "wingdi.h" -#include "winuser.h" -#include "wine/unicode.h" -#include "winnls.h" -#include "commctrl.h" -#include "comctl32.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(toolbar); - -static HCURSOR hCursorDrag = NULL; - -typedef struct -{ - INT iBitmap; - INT idCommand; - BYTE fsState; - BYTE fsStyle; - BYTE bHot; - BYTE bDropDownPressed; - DWORD dwData; - INT iString; - INT nRow; - RECT rect; - INT cx; /* manually set size */ -} TBUTTON_INFO; - -typedef struct -{ - UINT nButtons; - HINSTANCE hInst; - UINT nID; -} TBITMAP_INFO; - -typedef struct -{ - HIMAGELIST himl; - INT id; -} IMLENTRY, *PIMLENTRY; - -typedef struct -{ - DWORD dwStructSize; /* size of TBBUTTON struct */ - INT nHeight; /* height of the toolbar */ - INT nWidth; /* width of the toolbar */ - RECT client_rect; - RECT rcBound; /* bounding rectangle */ - INT nButtonHeight; - INT nButtonWidth; - INT nBitmapHeight; - INT nBitmapWidth; - INT nIndent; - INT nRows; /* number of button rows */ - INT nMaxTextRows; /* maximum number of text rows */ - INT cxMin; /* minimum button width */ - INT cxMax; /* maximum button width */ - INT nNumButtons; /* number of buttons */ - INT nNumBitmaps; /* number of bitmaps */ - INT nNumStrings; /* number of strings */ - INT nNumBitmapInfos; - INT nButtonDown; /* toolbar button being pressed or -1 if none */ - INT nButtonDrag; /* toolbar button being dragged or -1 if none */ - INT nOldHit; - INT nHotItem; /* index of the "hot" item */ - DWORD dwBaseCustDraw; /* CDRF_ response (w/o TBCDRF_) from PREPAINT */ - DWORD dwItemCustDraw; /* CDRF_ response (w/o TBCDRF_) from ITEMPREP */ - DWORD dwItemCDFlag; /* TBCDRF_ flags from last ITEMPREPAINT */ - SIZE szPadding; /* padding values around button */ - INT iListGap; /* default gap between text and image for toolbar with list style */ - HFONT hDefaultFont; - HFONT hFont; /* text font */ - HIMAGELIST himlInt; /* image list created internally */ - PIMLENTRY *himlDef; /* default image list array */ - INT cimlDef; /* default image list array count */ - PIMLENTRY *himlHot; /* hot image list array */ - INT cimlHot; /* hot image list array count */ - PIMLENTRY *himlDis; /* disabled image list array */ - INT cimlDis; /* disabled image list array count */ - HWND hwndToolTip; /* handle to tool tip control */ - HWND hwndNotify; /* handle to the window that gets notifications */ - HWND hwndSelf; /* my own handle */ - BOOL bBtnTranspnt; /* button transparency flag */ - BOOL bAutoSize; /* auto size deadlock indicator */ - BOOL bAnchor; /* anchor highlight enabled */ - BOOL bDoRedraw; /* Redraw status */ - BOOL bDragOutSent; /* has TBN_DRAGOUT notification been sent for this drag? */ - BOOL bUnicode; /* Notifications are ASCII (FALSE) or Unicode (TRUE)? */ - BOOL bCaptured; /* mouse captured? */ - DWORD dwStyle; /* regular toolbar style */ - DWORD dwExStyle; /* extended toolbar style */ - DWORD dwDTFlags; /* DrawText flags */ - - COLORREF clrInsertMark; /* insert mark color */ - COLORREF clrBtnHighlight; /* color for Flat Separator */ - COLORREF clrBtnShadow; /* color for Flag Separator */ - INT iVersion; - LPWSTR pszTooltipText; /* temporary store for a string > 80 characters - * for TTN_GETDISPINFOW notification */ - TBINSERTMARK tbim; /* info on insertion mark */ - TBUTTON_INFO *buttons; /* pointer to button array */ - LPWSTR *strings; /* pointer to string array */ - TBITMAP_INFO *bitmaps; -} TOOLBAR_INFO, *PTOOLBAR_INFO; - - -/* used by customization dialog */ -typedef struct -{ - PTOOLBAR_INFO tbInfo; - HWND tbHwnd; -} CUSTDLG_INFO, *PCUSTDLG_INFO; - -typedef struct -{ - TBBUTTON btn; - BOOL bVirtual; - BOOL bRemovable; - WCHAR text[64]; -} CUSTOMBUTTON, *PCUSTOMBUTTON; - -typedef enum -{ - IMAGE_LIST_DEFAULT, - IMAGE_LIST_HOT, - IMAGE_LIST_DISABLED -} IMAGE_LIST_TYPE; - -#define SEPARATOR_WIDTH 8 -#define TOP_BORDER 2 -#define BOTTOM_BORDER 2 -#define DDARROW_WIDTH 11 -#define ARROW_HEIGHT 3 -#define INSERTMARK_WIDTH 2 - -#define DEFPAD_CX 7 -#define DEFPAD_CY 6 -#define DEFLISTGAP 4 - -/* vertical padding used in list mode when image is present */ -#define LISTPAD_CY 9 - -/* how wide to treat the bitmap if it isn't present */ -#define NONLIST_NOTEXT_OFFSET 2 - -#define TOOLBAR_NOWHERE (-1) - -#define TOOLBAR_GetInfoPtr(hwnd) ((TOOLBAR_INFO *)GetWindowLongPtrW(hwnd,0)) -#define TOOLBAR_HasText(x, y) (TOOLBAR_GetText(x, y) ? TRUE : FALSE) -#define TOOLBAR_HasDropDownArrows(exStyle) ((exStyle & TBSTYLE_EX_DRAWDDARROWS) ? TRUE : FALSE) - -/* Used to find undocumented extended styles */ -#define TBSTYLE_EX_ALL (TBSTYLE_EX_DRAWDDARROWS | \ - TBSTYLE_EX_UNDOC1 | \ - TBSTYLE_EX_MIXEDBUTTONS | \ - TBSTYLE_EX_HIDECLIPPEDBUTTONS) - -/* all of the CCS_ styles */ -#define COMMON_STYLES (CCS_TOP|CCS_NOMOVEY|CCS_BOTTOM|CCS_NORESIZE| \ - CCS_NOPARENTALIGN|CCS_ADJUSTABLE|CCS_NODIVIDER|CCS_VERT) - -#define GETIBITMAP(infoPtr, i) (infoPtr->iVersion >= 5 ? LOWORD(i) : i) -#define GETHIMLID(infoPtr, i) (infoPtr->iVersion >= 5 ? HIWORD(i) : 0) -#define GETDEFIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlDef, infoPtr->cimlDef, id) -#define GETHOTIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlHot, infoPtr->cimlHot, id) -#define GETDISIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlDis, infoPtr->cimlDis, id) - -static BOOL TOOLBAR_GetButtonInfo(TOOLBAR_INFO *infoPtr, NMTOOLBARW *nmtb); -static BOOL TOOLBAR_IsButtonRemovable(TOOLBAR_INFO *infoPtr, int iItem, PCUSTOMBUTTON btnInfo); -static HIMAGELIST TOOLBAR_GetImageList(PIMLENTRY *pies, INT cies, INT id); -static PIMLENTRY TOOLBAR_GetImageListEntry(PIMLENTRY *pies, INT cies, INT id); -static VOID TOOLBAR_DeleteImageList(PIMLENTRY **pies, INT *cies); -static HIMAGELIST TOOLBAR_InsertImageList(PIMLENTRY **pies, INT *cies, HIMAGELIST himl, INT id); -static LRESULT TOOLBAR_LButtonDown(HWND hwnd, WPARAM wParam, LPARAM lParam); -static void TOOLBAR_SetHotItemEx (TOOLBAR_INFO *infoPtr, INT nHit, DWORD dwReason); - -static LRESULT -TOOLBAR_NotifyFormat(TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam); - - -static LPWSTR -TOOLBAR_GetText(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr) -{ - LPWSTR lpText = NULL; - - /* NOTE: iString == -1 is undocumented */ - if ((HIWORD(btnPtr->iString) != 0) && (btnPtr->iString != -1)) - lpText = (LPWSTR)btnPtr->iString; - else if ((btnPtr->iString >= 0) && (btnPtr->iString < infoPtr->nNumStrings)) - lpText = infoPtr->strings[btnPtr->iString]; - - return lpText; -} - -static void -TOOLBAR_DumpButton(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *bP, INT btn_num, BOOL internal) -{ - if (TRACE_ON(toolbar)){ - TRACE("button %d id %d, bitmap=%d, state=%02x, style=%02x, data=%08lx, stringid=0x%08x\n", - btn_num, bP->idCommand, GETIBITMAP(infoPtr, bP->iBitmap), - bP->fsState, bP->fsStyle, bP->dwData, bP->iString); - TRACE("string %s\n", debugstr_w(TOOLBAR_GetText(infoPtr,bP))); - if (internal) - TRACE("button %d id %d, hot=%s, row=%d, rect=(%ld,%ld)-(%ld,%ld)\n", - btn_num, bP->idCommand, - (bP->bHot) ? "TRUE":"FALSE", bP->nRow, - bP->rect.left, bP->rect.top, - bP->rect.right, bP->rect.bottom); - } -} - - -static void -TOOLBAR_DumpToolbar(TOOLBAR_INFO *iP, INT line) -{ - if (TRACE_ON(toolbar)) { - INT i; - - TRACE("toolbar %p at line %d, exStyle=%08lx, buttons=%d, bitmaps=%d, strings=%d, style=%08lx\n", - iP->hwndSelf, line, - iP->dwExStyle, iP->nNumButtons, iP->nNumBitmaps, - iP->nNumStrings, iP->dwStyle); - TRACE("toolbar %p at line %d, himlInt=%p, himlDef=%p, himlHot=%p, himlDis=%p, redrawable=%s\n", - iP->hwndSelf, line, - iP->himlInt, iP->himlDef, iP->himlHot, iP->himlDis, - (iP->bDoRedraw) ? "TRUE" : "FALSE"); - for(i=0; inNumButtons; i++) { - TOOLBAR_DumpButton(iP, &iP->buttons[i], i, TRUE); - } - } -} - - -/*********************************************************************** -* TOOLBAR_CheckStyle -* -* This function validates that the styles set are implemented and -* issues FIXME's warning of possible problems. In a perfect world this -* function should be null. -*/ -static void -TOOLBAR_CheckStyle (HWND hwnd, DWORD dwStyle) -{ - if (dwStyle & TBSTYLE_REGISTERDROP) - FIXME("[%p] TBSTYLE_REGISTERDROP not implemented\n", hwnd); -} - - -static INT -TOOLBAR_SendNotify (NMHDR *nmhdr, TOOLBAR_INFO *infoPtr, UINT code) -{ - if(!IsWindow(infoPtr->hwndSelf)) - return 0; /* we have just been destroyed */ - - nmhdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf); - nmhdr->hwndFrom = infoPtr->hwndSelf; - nmhdr->code = code; - - TRACE("to window %p, code=%08x, %s\n", infoPtr->hwndNotify, code, - (infoPtr->bUnicode) ? "via Unicode" : "via ANSI"); - - return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, - (WPARAM)nmhdr->idFrom, (LPARAM)nmhdr); -} - -/*********************************************************************** -* TOOLBAR_GetBitmapIndex -* -* This function returns the bitmap index associated with a button. -* If the button specifies I_IMAGECALLBACK, then the TBN_GETDISPINFO -* is issued to retrieve the index. -*/ -static INT -TOOLBAR_GetBitmapIndex(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr) -{ - INT ret = btnPtr->iBitmap; - - if (ret == I_IMAGECALLBACK) - { - /* issue TBN_GETDISPINFO */ - NMTBDISPINFOA nmgd; - - memset(&nmgd, 0, sizeof(nmgd)); - nmgd.idCommand = btnPtr->idCommand; - nmgd.lParam = btnPtr->dwData; - nmgd.dwMask = TBNF_IMAGE; - TOOLBAR_SendNotify(&nmgd.hdr, infoPtr, - infoPtr->bUnicode ? TBN_GETDISPINFOW : TBN_GETDISPINFOA); - if (nmgd.dwMask & TBNF_DI_SETITEM) - btnPtr->iBitmap = nmgd.iImage; - ret = nmgd.iImage; - TRACE("TBN_GETDISPINFO returned bitmap id %d, mask=%08lx, nNumBitmaps=%d\n", - ret, nmgd.dwMask, infoPtr->nNumBitmaps); - } - - if (ret != I_IMAGENONE) - ret = GETIBITMAP(infoPtr, ret); - - return ret; -} - - -static BOOL -TOOLBAR_IsValidBitmapIndex(TOOLBAR_INFO *infoPtr, INT index) -{ - HIMAGELIST himl; - INT id = GETHIMLID(infoPtr, index); - INT iBitmap = GETIBITMAP(infoPtr, index); - - if (((himl = GETDEFIMAGELIST(infoPtr, id)) && - iBitmap >= 0 && iBitmap < ImageList_GetImageCount(himl)) || - (index == I_IMAGECALLBACK)) - return TRUE; - else - return FALSE; -} - - -static inline BOOL -TOOLBAR_IsValidImageList(TOOLBAR_INFO *infoPtr, INT index) -{ - HIMAGELIST himl = GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr, index)); - return (himl != NULL) && (ImageList_GetImageCount(himl) > 0); -} - - -/*********************************************************************** -* TOOLBAR_GetImageListForDrawing -* -* This function validates the bitmap index (including I_IMAGECALLBACK -* functionality) and returns the corresponding image list. -*/ -static HIMAGELIST -TOOLBAR_GetImageListForDrawing (TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, IMAGE_LIST_TYPE imagelist, INT * index) -{ - HIMAGELIST himl; - - if (!TOOLBAR_IsValidBitmapIndex(infoPtr,btnPtr->iBitmap)) { - if (btnPtr->iBitmap == I_IMAGENONE) return NULL; - ERR("bitmap for ID %d, index %d is not valid, number of bitmaps in imagelist: %d\n", - HIWORD(btnPtr->iBitmap), LOWORD(btnPtr->iBitmap), infoPtr->nNumBitmaps); - return NULL; - } - - if ((*index = TOOLBAR_GetBitmapIndex(infoPtr, btnPtr)) < 0) { - if ((*index == I_IMAGECALLBACK) || - (*index == I_IMAGENONE)) return NULL; - ERR("TBN_GETDISPINFO returned invalid index %d\n", - *index); - return NULL; - } - - switch(imagelist) - { - case IMAGE_LIST_DEFAULT: - himl = GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr, btnPtr->iBitmap)); - break; - case IMAGE_LIST_HOT: - himl = GETHOTIMAGELIST(infoPtr, GETHIMLID(infoPtr, btnPtr->iBitmap)); - break; - case IMAGE_LIST_DISABLED: - himl = GETDISIMAGELIST(infoPtr, GETHIMLID(infoPtr, btnPtr->iBitmap)); - break; - default: - himl = NULL; - FIXME("Shouldn't reach here\n"); - } - - if (!himl) - TRACE("no image list\n"); - - return himl; -} - - -static void -TOOLBAR_DrawFlatSeparator (LPRECT lpRect, HDC hdc, TOOLBAR_INFO *infoPtr) -{ - RECT myrect; - COLORREF oldcolor, newcolor; - - myrect.left = (lpRect->left + lpRect->right) / 2 - 1; - myrect.right = myrect.left + 1; - myrect.top = lpRect->top + 2; - myrect.bottom = lpRect->bottom - 2; - - newcolor = (infoPtr->clrBtnShadow == CLR_DEFAULT) ? - comctl32_color.clrBtnShadow : infoPtr->clrBtnShadow; - oldcolor = SetBkColor (hdc, newcolor); - ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0); - - myrect.left = myrect.right; - myrect.right = myrect.left + 1; - - newcolor = (infoPtr->clrBtnHighlight == CLR_DEFAULT) ? - comctl32_color.clrBtnHighlight : infoPtr->clrBtnHighlight; - SetBkColor (hdc, newcolor); - ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0); - - SetBkColor (hdc, oldcolor); -} - - -/*********************************************************************** -* TOOLBAR_DrawDDFlatSeparator -* -* This function draws the separator that was flagged as BTNS_DROPDOWN. -* In this case, the separator is a pixel high line of COLOR_BTNSHADOW, -* followed by a pixel high line of COLOR_BTNHIGHLIGHT. These separators -* are horizontal as opposed to the vertical separators for not dropdown -* type. -* -* FIXME: It is possible that the height of each line is really SM_CYBORDER. -*/ -static void -TOOLBAR_DrawDDFlatSeparator (LPRECT lpRect, HDC hdc, TBUTTON_INFO *btnPtr, TOOLBAR_INFO *infoPtr) -{ - RECT myrect; - COLORREF oldcolor, newcolor; - - myrect.left = lpRect->left; - myrect.right = lpRect->right; - myrect.top = lpRect->top + (lpRect->bottom - lpRect->top - 2)/2; - myrect.bottom = myrect.top + 1; - - InflateRect (&myrect, -2, 0); - - TRACE("rect=(%ld,%ld)-(%ld,%ld)\n", - myrect.left, myrect.top, myrect.right, myrect.bottom); - - newcolor = (infoPtr->clrBtnShadow == CLR_DEFAULT) ? - comctl32_color.clrBtnShadow : infoPtr->clrBtnShadow; - oldcolor = SetBkColor (hdc, newcolor); - ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0); - - myrect.top = myrect.bottom; - myrect.bottom = myrect.top + 1; - - newcolor = (infoPtr->clrBtnHighlight == CLR_DEFAULT) ? - comctl32_color.clrBtnHighlight : infoPtr->clrBtnHighlight; - SetBkColor (hdc, newcolor); - ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0); - - SetBkColor (hdc, oldcolor); -} - - -static void -TOOLBAR_DrawArrow (HDC hdc, INT left, INT top, COLORREF clr) -{ - INT x, y; - HPEN hPen, hOldPen; - - if (!(hPen = CreatePen( PS_SOLID, 1, clr))) return; - hOldPen = SelectObject ( hdc, hPen ); - x = left + 2; - y = top; - MoveToEx (hdc, x, y, NULL); - LineTo (hdc, x+5, y++); x++; - MoveToEx (hdc, x, y, NULL); - LineTo (hdc, x+3, y++); x++; - MoveToEx (hdc, x, y, NULL); - LineTo (hdc, x+1, y++); - SelectObject( hdc, hOldPen ); - DeleteObject( hPen ); -} - -/* - * Draw the text string for this button. - * note: infoPtr->himlDis *SHOULD* be non-zero when infoPtr->himlDef - * is non-zero, so we can simply check himlDef to see if we have - * an image list - */ -static void -TOOLBAR_DrawString (TOOLBAR_INFO *infoPtr, RECT *rcText, LPWSTR lpText, - NMTBCUSTOMDRAW *tbcd) -{ - HDC hdc = tbcd->nmcd.hdc; - HFONT hOldFont = 0; - COLORREF clrOld = 0; - COLORREF clrOldBk = 0; - int oldBkMode = 0; - UINT state = tbcd->nmcd.uItemState; - - /* draw text */ - if (lpText) { - TRACE("string=%s rect=(%ld,%ld)-(%ld,%ld)\n", debugstr_w(lpText), - rcText->left, rcText->top, rcText->right, rcText->bottom); - - hOldFont = SelectObject (hdc, infoPtr->hFont); - if ((state & CDIS_HOT) && (infoPtr->dwItemCDFlag & TBCDRF_HILITEHOTTRACK )) { - clrOld = SetTextColor (hdc, tbcd->clrTextHighlight); - } - else if (state & CDIS_DISABLED) { - clrOld = SetTextColor (hdc, tbcd->clrBtnHighlight); - OffsetRect (rcText, 1, 1); - DrawTextW (hdc, lpText, -1, rcText, infoPtr->dwDTFlags); - SetTextColor (hdc, comctl32_color.clr3dShadow); - OffsetRect (rcText, -1, -1); - } - else if (state & CDIS_INDETERMINATE) { - clrOld = SetTextColor (hdc, comctl32_color.clr3dShadow); - } - else if ((state & CDIS_MARKED) && !(infoPtr->dwItemCDFlag & TBCDRF_NOMARK)) { - clrOld = SetTextColor (hdc, tbcd->clrTextHighlight); - clrOldBk = SetBkColor (hdc, tbcd->clrMark); - oldBkMode = SetBkMode (hdc, OPAQUE); /* FIXME: should this be in the NMTBCUSTOMDRAW structure? */ - } - else { - clrOld = SetTextColor (hdc, tbcd->clrText); - } - - DrawTextW (hdc, lpText, -1, rcText, infoPtr->dwDTFlags); - SetTextColor (hdc, clrOld); - if ((state & CDIS_MARKED) && !(infoPtr->dwItemCDFlag & TBCDRF_NOMARK)) - { - SetBkColor (hdc, clrOldBk); - SetBkMode (hdc, oldBkMode); - } - SelectObject (hdc, hOldFont); - } -} - - -static void -TOOLBAR_DrawPattern (LPRECT lpRect, NMTBCUSTOMDRAW *tbcd) -{ - HDC hdc = tbcd->nmcd.hdc; - HBRUSH hbr = SelectObject (hdc, tbcd->hbrMonoDither); - COLORREF clrTextOld; - COLORREF clrBkOld; - INT cx = lpRect->right - lpRect->left; - INT cy = lpRect->bottom - lpRect->top; - INT cxEdge = GetSystemMetrics(SM_CXEDGE); - INT cyEdge = GetSystemMetrics(SM_CYEDGE); - clrTextOld = SetTextColor(hdc, tbcd->clrBtnHighlight); - clrBkOld = SetBkColor(hdc, tbcd->clrBtnFace); - PatBlt (hdc, lpRect->left + cxEdge, lpRect->top + cyEdge, - cx - (2 * cxEdge), cy - (2 * cyEdge), PATCOPY); - SetBkColor(hdc, clrBkOld); - SetTextColor(hdc, clrTextOld); - SelectObject (hdc, hbr); -} - - -static void TOOLBAR_DrawMasked(HIMAGELIST himl, int index, HDC hdc, INT x, INT y, UINT draw_flags) -{ - INT cx, cy; - HBITMAP hbmMask, hbmImage; - HDC hdcMask, hdcImage; - - ImageList_GetIconSize(himl, &cx, &cy); - - /* Create src image */ - hdcImage = CreateCompatibleDC(hdc); - hbmImage = CreateCompatibleBitmap(hdc, cx, cy); - SelectObject(hdcImage, hbmImage); - ImageList_DrawEx(himl, index, hdcImage, 0, 0, cx, cy, - RGB(0xff, 0xff, 0xff), RGB(0,0,0), draw_flags); - - /* Create Mask */ - hdcMask = CreateCompatibleDC(0); - hbmMask = CreateBitmap(cx, cy, 1, 1, NULL); - SelectObject(hdcMask, hbmMask); - - /* Remove the background and all white pixels */ - ImageList_DrawEx(himl, index, hdcMask, 0, 0, cx, cy, - RGB(0xff, 0xff, 0xff), RGB(0,0,0), ILD_MASK); - SetBkColor(hdcImage, RGB(0xff, 0xff, 0xff)); - BitBlt(hdcMask, 0, 0, cx, cy, hdcImage, 0, 0, NOTSRCERASE); - - /* draw the new mask 'etched' to hdc */ - SetBkColor(hdc, RGB(255, 255, 255)); - SelectObject(hdc, GetSysColorBrush(COLOR_3DHILIGHT)); - /* E20746 op code is (Dst ^ (Src & (Pat ^ Dst))) */ - BitBlt(hdc, x + 1, y + 1, cx, cy, hdcMask, 0, 0, 0xE20746); - SelectObject(hdc, GetSysColorBrush(COLOR_3DSHADOW)); - BitBlt(hdc, x, y, cx, cy, hdcMask, 0, 0, 0xE20746); - - /* Cleanup */ - DeleteObject(hbmImage); - DeleteDC(hdcImage); - DeleteObject (hbmMask); - DeleteDC(hdcMask); -} - - -static UINT -TOOLBAR_TranslateState(TBUTTON_INFO *btnPtr) -{ - UINT retstate = 0; - - retstate |= (btnPtr->fsState & TBSTATE_CHECKED) ? CDIS_CHECKED : 0; - retstate |= (btnPtr->fsState & TBSTATE_PRESSED) ? CDIS_SELECTED : 0; - retstate |= (btnPtr->fsState & TBSTATE_ENABLED) ? 0 : CDIS_DISABLED; - retstate |= (btnPtr->fsState & TBSTATE_MARKED ) ? CDIS_MARKED : 0; - retstate |= (btnPtr->bHot ) ? CDIS_HOT : 0; - retstate |= (btnPtr->fsState & TBSTATE_INDETERMINATE) ? CDIS_INDETERMINATE : 0; - /* NOTE: we don't set CDIS_GRAYED, CDIS_FOCUS, CDIS_DEFAULT */ - return retstate; -} - -/* draws the image on a toolbar button */ -static void -TOOLBAR_DrawImage(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, INT left, INT top, const NMTBCUSTOMDRAW *tbcd) -{ - HIMAGELIST himl = NULL; - BOOL draw_masked = FALSE; - INT index; - INT offset = 0; - UINT draw_flags = ILD_TRANSPARENT; - - if (tbcd->nmcd.uItemState & (CDIS_DISABLED | CDIS_INDETERMINATE)) - { - himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DISABLED, &index); - if (!himl) - { - himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DEFAULT, &index); - draw_masked = TRUE; - } - } - else if ((tbcd->nmcd.uItemState & CDIS_HOT) && (infoPtr->dwStyle & TBSTYLE_FLAT)) - { - /* if hot, attempt to draw with hot image list, if fails, - use default image list */ - himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_HOT, &index); - if (!himl) - himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DEFAULT, &index); - } - else - himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DEFAULT, &index); - - if (!himl) - return; - - if (!(infoPtr->dwItemCDFlag & TBCDRF_NOOFFSET) && - (tbcd->nmcd.uItemState & (CDIS_SELECTED | CDIS_CHECKED))) - offset = 1; - - if (!(infoPtr->dwItemCDFlag & TBCDRF_NOMARK) && - (tbcd->nmcd.uItemState & CDIS_MARKED)) - draw_flags |= ILD_BLEND50; - - TRACE("drawing index=%d, himl=%p, left=%d, top=%d, offset=%d\n", - index, himl, left, top, offset); - - if (draw_masked) - TOOLBAR_DrawMasked (himl, index, tbcd->nmcd.hdc, left + offset, top + offset, draw_flags); - else - ImageList_Draw (himl, index, tbcd->nmcd.hdc, left + offset, top + offset, draw_flags); -} - -/* draws a blank frame for a toolbar button */ -static void -TOOLBAR_DrawFrame(const TOOLBAR_INFO *infoPtr, const NMTBCUSTOMDRAW *tbcd) -{ - HDC hdc = tbcd->nmcd.hdc; - RECT rc = tbcd->nmcd.rc; - /* if the state is disabled or indeterminate then the button - * cannot have an interactive look like pressed or hot */ - BOOL non_interactive_state = (tbcd->nmcd.uItemState & CDIS_DISABLED) || - (tbcd->nmcd.uItemState & CDIS_INDETERMINATE); - BOOL pressed_look = !non_interactive_state && - ((tbcd->nmcd.uItemState & CDIS_SELECTED) || - (tbcd->nmcd.uItemState & CDIS_CHECKED)); - - /* app don't want us to draw any edges */ - if (infoPtr->dwItemCDFlag & TBCDRF_NOEDGES) - return; - - if (infoPtr->dwStyle & TBSTYLE_FLAT) - { - if (pressed_look) - DrawEdge (hdc, &rc, BDR_SUNKENOUTER, BF_RECT); - else if ((tbcd->nmcd.uItemState & CDIS_HOT) && !non_interactive_state) - DrawEdge (hdc, &rc, BDR_RAISEDINNER, BF_RECT); - } - else - { - if (pressed_look) - DrawEdge (hdc, &rc, EDGE_SUNKEN, BF_RECT | BF_MIDDLE); - else - DrawEdge (hdc, &rc, EDGE_RAISED, - BF_SOFT | BF_RECT | BF_MIDDLE); - } -} - -static void -TOOLBAR_DrawSepDDArrow(const TOOLBAR_INFO *infoPtr, const NMTBCUSTOMDRAW *tbcd, RECT *rcArrow, BOOL bDropDownPressed) -{ - HDC hdc = tbcd->nmcd.hdc; - int offset = 0; - BOOL pressed = bDropDownPressed || - (tbcd->nmcd.uItemState & (CDIS_SELECTED | CDIS_CHECKED)); - - if (infoPtr->dwStyle & TBSTYLE_FLAT) - { - if (pressed) - DrawEdge (hdc, rcArrow, BDR_SUNKENOUTER, BF_RECT); - else if ( (tbcd->nmcd.uItemState & CDIS_HOT) && - !(tbcd->nmcd.uItemState & CDIS_DISABLED) && - !(tbcd->nmcd.uItemState & CDIS_INDETERMINATE)) - DrawEdge (hdc, rcArrow, BDR_RAISEDINNER, BF_RECT); - } - else - { - if (pressed) - DrawEdge (hdc, rcArrow, EDGE_SUNKEN, BF_RECT | BF_MIDDLE); - else - DrawEdge (hdc, rcArrow, EDGE_RAISED, - BF_SOFT | BF_RECT | BF_MIDDLE); - } - - if (pressed) - offset = (infoPtr->dwItemCDFlag & TBCDRF_NOOFFSET) ? 0 : 1; - - if (tbcd->nmcd.uItemState & (CDIS_DISABLED | CDIS_INDETERMINATE)) - { - TOOLBAR_DrawArrow(hdc, rcArrow->left+1, rcArrow->top+1 + (rcArrow->bottom - rcArrow->top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnHighlight); - TOOLBAR_DrawArrow(hdc, rcArrow->left, rcArrow->top + (rcArrow->bottom - rcArrow->top - ARROW_HEIGHT) / 2, comctl32_color.clr3dShadow); - } - else - TOOLBAR_DrawArrow(hdc, rcArrow->left + offset, rcArrow->top + offset + (rcArrow->bottom - rcArrow->top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnText); -} - -/* draws a complete toolbar button */ -static void -TOOLBAR_DrawButton (HWND hwnd, TBUTTON_INFO *btnPtr, HDC hdc) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - DWORD dwStyle = infoPtr->dwStyle; - BOOL hasDropDownArrow = (TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle) && - (btnPtr->fsStyle & BTNS_DROPDOWN)) || - (btnPtr->fsStyle & BTNS_WHOLEDROPDOWN); - BOOL drawSepDropDownArrow = hasDropDownArrow && - (~btnPtr->fsStyle & BTNS_WHOLEDROPDOWN); - RECT rc, rcArrow, rcBitmap, rcText; - LPWSTR lpText = NULL; - NMTBCUSTOMDRAW tbcd; - DWORD ntfret; - INT offset; - - rc = btnPtr->rect; - CopyRect (&rcArrow, &rc); - - /* get a pointer to the text */ - lpText = TOOLBAR_GetText(infoPtr, btnPtr); - - if (hasDropDownArrow) - { - int right; - - if (dwStyle & TBSTYLE_FLAT) - right = max(rc.left, rc.right - DDARROW_WIDTH); - else - right = max(rc.left, rc.right - DDARROW_WIDTH - 2); - - if (drawSepDropDownArrow) - rc.right = right; - - rcArrow.left = right; - } - - /* copy text & bitmap rects after adjusting for drop-down arrow - * so that text & bitmap is centred in the rectangle not containing - * the arrow */ - CopyRect(&rcText, &rc); - CopyRect(&rcBitmap, &rc); - - /* Center the bitmap horizontally and vertically */ - if (dwStyle & TBSTYLE_LIST) - { - if (lpText && - infoPtr->nMaxTextRows > 0 && - (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || - (btnPtr->fsStyle & BTNS_SHOWTEXT)) ) - rcBitmap.left += GetSystemMetrics(SM_CXEDGE) + infoPtr->szPadding.cx / 2; - else - rcBitmap.left += GetSystemMetrics(SM_CXEDGE) + infoPtr->iListGap / 2; - } - else - rcBitmap.left += (infoPtr->nButtonWidth - infoPtr->nBitmapWidth) / 2; - - rcBitmap.top += infoPtr->szPadding.cy / 2; - - TRACE("iBitmap=%d, start=(%ld,%ld) w=%d, h=%d\n", - btnPtr->iBitmap, rcBitmap.left, rcBitmap.top, - infoPtr->nBitmapWidth, infoPtr->nBitmapHeight); - TRACE("Text=%s\n", debugstr_w(lpText)); - TRACE("iListGap=%d, padding = { %ld, %ld }\n", infoPtr->iListGap, infoPtr->szPadding.cx, infoPtr->szPadding.cy); - - /* calculate text position */ - if (lpText) - { - rcText.left += GetSystemMetrics(SM_CXEDGE); - rcText.right -= GetSystemMetrics(SM_CXEDGE); - if (dwStyle & TBSTYLE_LIST) - { - if (TOOLBAR_IsValidBitmapIndex(infoPtr,btnPtr->iBitmap)) - rcText.left += infoPtr->nBitmapWidth + infoPtr->iListGap + 2; - } - else - { - if (ImageList_GetImageCount(GETDEFIMAGELIST(infoPtr, 0)) > 0) - rcText.top += infoPtr->szPadding.cy/2 + infoPtr->nBitmapHeight + 1; - else - rcText.top += infoPtr->szPadding.cy/2 + 2; - } - } - - /* Initialize fields in all cases, because we use these later - * NOTE: applications can and do alter these to customize their - * toolbars */ - ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW)); - tbcd.clrText = comctl32_color.clrBtnText; - tbcd.clrTextHighlight = comctl32_color.clrHighlightText; - tbcd.clrBtnFace = comctl32_color.clrBtnFace; - tbcd.clrBtnHighlight = comctl32_color.clrBtnHighlight; - tbcd.clrMark = comctl32_color.clrHighlight; - tbcd.clrHighlightHotTrack = 0; - tbcd.nStringBkMode = (infoPtr->bBtnTranspnt) ? TRANSPARENT : OPAQUE; - tbcd.nHLStringBkMode = (infoPtr->bBtnTranspnt) ? TRANSPARENT : OPAQUE; - /* MSDN says that this is the text rectangle. - * But (why always a but) tracing of v5.7 of native shows - * that this is really a *relative* rectangle based on the - * the nmcd.rc. Also the left and top are always 0 ignoring - * any bitmap that might be present. */ - tbcd.rcText.left = 0; - tbcd.rcText.top = 0; - tbcd.rcText.right = rcText.right - rc.left; - tbcd.rcText.bottom = rcText.bottom - rc.top; - tbcd.nmcd.uItemState = TOOLBAR_TranslateState(btnPtr); - tbcd.nmcd.hdc = hdc; - tbcd.nmcd.rc = rc; - tbcd.hbrMonoDither = COMCTL32_hPattern55AABrush; - - /* FIXME: what are these used for? */ - tbcd.hbrLines = 0; - tbcd.hpenLines = 0; - - /* Issue Item Prepaint notify */ - infoPtr->dwItemCustDraw = 0; - infoPtr->dwItemCDFlag = 0; - if (infoPtr->dwBaseCustDraw & CDRF_NOTIFYITEMDRAW) - { - tbcd.nmcd.dwDrawStage = CDDS_ITEMPREPAINT; - tbcd.nmcd.dwItemSpec = btnPtr->idCommand; - tbcd.nmcd.lItemlParam = btnPtr->dwData; - ntfret = TOOLBAR_SendNotify(&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); - /* reset these fields so the user can't alter the behaviour like native */ - tbcd.nmcd.hdc = hdc; - tbcd.nmcd.rc = rc; - - infoPtr->dwItemCustDraw = ntfret & 0xffff; - infoPtr->dwItemCDFlag = ntfret & 0xffff0000; - if (infoPtr->dwItemCustDraw & CDRF_SKIPDEFAULT) - return; - /* save the only part of the rect that the user can change */ - rcText.right = tbcd.rcText.right + rc.left; - rcText.bottom = tbcd.rcText.bottom + rc.top; - } - - /* separator */ - if (btnPtr->fsStyle & BTNS_SEP) { - /* with the FLAT style, iBitmap is the width and has already */ - /* been taken into consideration in calculating the width */ - /* so now we need to draw the vertical separator */ - /* empirical tests show that iBitmap can/will be non-zero */ - /* when drawing the vertical bar... */ - if ((dwStyle & TBSTYLE_FLAT) /* && (btnPtr->iBitmap == 0) */) { - if (btnPtr->fsStyle & BTNS_DROPDOWN) - TOOLBAR_DrawDDFlatSeparator (&rc, hdc, btnPtr, infoPtr); - else - TOOLBAR_DrawFlatSeparator (&rc, hdc, infoPtr); - } - else if (btnPtr->fsStyle != BTNS_SEP) { - FIXME("Draw some kind of separator: fsStyle=%x\n", - btnPtr->fsStyle); - } - goto FINALNOTIFY; - } - - if (!(infoPtr->dwItemCDFlag & TBCDRF_NOOFFSET) && - (btnPtr->fsState & (TBSTATE_PRESSED | TBSTATE_CHECKED))) - OffsetRect(&rcText, 1, 1); - - if (!(tbcd.nmcd.uItemState & CDIS_HOT) && - ((tbcd.nmcd.uItemState & CDIS_CHECKED) || (tbcd.nmcd.uItemState & CDIS_INDETERMINATE))) - TOOLBAR_DrawPattern (&rc, &tbcd); - - if ((dwStyle & TBSTYLE_FLAT) && (tbcd.nmcd.uItemState & CDIS_HOT)) - { - if ( infoPtr->dwItemCDFlag & TBCDRF_HILITEHOTTRACK ) - { - COLORREF oldclr; - - oldclr = SetBkColor(hdc, tbcd.clrHighlightHotTrack); - ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, 0); - if (hasDropDownArrow) - ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &rcArrow, NULL, 0, 0); - SetBkColor(hdc, oldclr); - } - } - - TOOLBAR_DrawFrame(infoPtr, &tbcd); - - if (drawSepDropDownArrow) - TOOLBAR_DrawSepDDArrow(infoPtr, &tbcd, &rcArrow, btnPtr->bDropDownPressed); - - if (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || (btnPtr->fsStyle & BTNS_SHOWTEXT)) - TOOLBAR_DrawString (infoPtr, &rcText, lpText, &tbcd); - - TOOLBAR_DrawImage(infoPtr, btnPtr, rcBitmap.left, rcBitmap.top, &tbcd); - - if (hasDropDownArrow && !drawSepDropDownArrow) - { - if (tbcd.nmcd.uItemState & (CDIS_DISABLED | CDIS_INDETERMINATE)) - { - TOOLBAR_DrawArrow(hdc, rcArrow.left+1, rcArrow.top+1 + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnHighlight); - TOOLBAR_DrawArrow(hdc, rcArrow.left, rcArrow.top + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, comctl32_color.clr3dShadow); - } - else if (tbcd.nmcd.uItemState & (CDIS_SELECTED | CDIS_CHECKED)) - { - offset = (infoPtr->dwItemCDFlag & TBCDRF_NOOFFSET) ? 0 : 1; - TOOLBAR_DrawArrow(hdc, rcArrow.left + offset, rcArrow.top + offset + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnText); - } - else - TOOLBAR_DrawArrow(hdc, rcArrow.left, rcArrow.top + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnText); - } - -FINALNOTIFY: - if (infoPtr->dwItemCustDraw & CDRF_NOTIFYPOSTPAINT) - { - tbcd.nmcd.dwDrawStage = CDDS_ITEMPOSTPAINT; - tbcd.nmcd.hdc = hdc; - tbcd.nmcd.rc = rc; - tbcd.nmcd.dwItemSpec = btnPtr->idCommand; - tbcd.nmcd.uItemState = TOOLBAR_TranslateState(btnPtr); - tbcd.nmcd.lItemlParam = btnPtr->dwData; - tbcd.rcText = rcText; - tbcd.nStringBkMode = (infoPtr->bBtnTranspnt) ? TRANSPARENT : OPAQUE; - tbcd.nHLStringBkMode = (infoPtr->bBtnTranspnt) ? TRANSPARENT : OPAQUE; - ntfret = TOOLBAR_SendNotify(&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); - } - -} - - -static void -TOOLBAR_Refresh (HWND hwnd, HDC hdc, PAINTSTRUCT* ps) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - TBUTTON_INFO *btnPtr; - INT i, oldBKmode = 0; - RECT rcTemp, rcClient; - NMTBCUSTOMDRAW tbcd; - DWORD ntfret; - - /* the app has told us not to redraw the toolbar */ - if (!infoPtr->bDoRedraw) - return; - - /* if imagelist belongs to the app, it can be changed - by the app after setting it */ - if (GETDEFIMAGELIST(infoPtr, 0) != infoPtr->himlInt) - { - infoPtr->nNumBitmaps = 0; - for (i = 0; i < infoPtr->cimlDef; i++) - infoPtr->nNumBitmaps += ImageList_GetImageCount(infoPtr->himlDef[i]->himl); - } - - TOOLBAR_DumpToolbar (infoPtr, __LINE__); - - /* Send initial notify */ - ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW)); - tbcd.nmcd.dwDrawStage = CDDS_PREPAINT; - tbcd.nmcd.hdc = hdc; - tbcd.nmcd.rc = ps->rcPaint; - ntfret = TOOLBAR_SendNotify(&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); - infoPtr->dwBaseCustDraw = ntfret & 0xffff; - - if (infoPtr->bBtnTranspnt) - oldBKmode = SetBkMode (hdc, TRANSPARENT); - - GetClientRect(hwnd, &rcClient); - - /* redraw necessary buttons */ - btnPtr = infoPtr->buttons; - for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) - { - BOOL bDraw; - if (infoPtr->dwExStyle & TBSTYLE_EX_HIDECLIPPEDBUTTONS) - { - IntersectRect(&rcTemp, &rcClient, &btnPtr->rect); - bDraw = EqualRect(&rcTemp, &btnPtr->rect); - } - else - bDraw = TRUE; - bDraw &= IntersectRect(&rcTemp, &(ps->rcPaint), &(btnPtr->rect)); - bDraw = (btnPtr->fsState & TBSTATE_HIDDEN) ? FALSE : bDraw; - if (bDraw) - TOOLBAR_DrawButton (hwnd, btnPtr, hdc); - } - - /* draw insert mark if required */ - if (infoPtr->tbim.iButton != -1) - { - RECT rcButton = infoPtr->buttons[infoPtr->tbim.iButton].rect; - RECT rcInsertMark; - rcInsertMark.top = rcButton.top; - rcInsertMark.bottom = rcButton.bottom; - if (infoPtr->tbim.dwFlags & TBIMHT_AFTER) - rcInsertMark.left = rcInsertMark.right = rcButton.right; - else - rcInsertMark.left = rcInsertMark.right = rcButton.left - INSERTMARK_WIDTH; - COMCTL32_DrawInsertMark(hdc, &rcInsertMark, infoPtr->clrInsertMark, FALSE); - } - - if (infoPtr->bBtnTranspnt && (oldBKmode != TRANSPARENT)) - SetBkMode (hdc, oldBKmode); - - if (infoPtr->dwBaseCustDraw & CDRF_NOTIFYPOSTPAINT) - { - ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW)); - tbcd.nmcd.dwDrawStage = CDDS_POSTPAINT; - tbcd.nmcd.hdc = hdc; - tbcd.nmcd.rc = ps->rcPaint; - ntfret = TOOLBAR_SendNotify(&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); - } -} - -/*********************************************************************** -* TOOLBAR_MeasureString -* -* This function gets the width and height of a string in pixels. This -* is done first by using GetTextExtentPoint to get the basic width -* and height. The DrawText is called with DT_CALCRECT to get the exact -* width. The reason is because the text may have more than one "&" (or -* prefix characters as M$ likes to call them). The prefix character -* indicates where the underline goes, except for the string "&&" which -* is reduced to a single "&". GetTextExtentPoint does not process these -* only DrawText does. Note that the BTNS_NOPREFIX is handled here. -*/ -static void -TOOLBAR_MeasureString(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, - HDC hdc, LPSIZE lpSize) -{ - RECT myrect; - - lpSize->cx = 0; - lpSize->cy = 0; - - if (infoPtr->nMaxTextRows > 0 && - !(btnPtr->fsState & TBSTATE_HIDDEN) && - (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || - (btnPtr->fsStyle & BTNS_SHOWTEXT)) ) - { - LPWSTR lpText = TOOLBAR_GetText(infoPtr, btnPtr); - - if(lpText != NULL) { - /* first get size of all the text */ - GetTextExtentPoint32W (hdc, lpText, strlenW (lpText), lpSize); - - /* feed above size into the rectangle for DrawText */ - myrect.left = myrect.top = 0; - myrect.right = lpSize->cx; - myrect.bottom = lpSize->cy; - - /* Use DrawText to get true size as drawn (less pesky "&") */ - DrawTextW (hdc, lpText, -1, &myrect, DT_VCENTER | DT_SINGLELINE | - DT_CALCRECT | ((btnPtr->fsStyle & BTNS_NOPREFIX) ? - DT_NOPREFIX : 0)); - - /* feed back to caller */ - lpSize->cx = myrect.right; - lpSize->cy = myrect.bottom; - } - } - - TRACE("string size %ld x %ld!\n", lpSize->cx, lpSize->cy); -} - -/*********************************************************************** -* TOOLBAR_CalcStrings -* -* This function walks through each string and measures it and returns -* the largest height and width to caller. -*/ -static void -TOOLBAR_CalcStrings (HWND hwnd, LPSIZE lpSize) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - TBUTTON_INFO *btnPtr; - INT i; - SIZE sz; - HDC hdc; - HFONT hOldFont; - - lpSize->cx = 0; - lpSize->cy = 0; - - if(infoPtr->nMaxTextRows == 0) - return; - - hdc = GetDC (hwnd); - hOldFont = SelectObject (hdc, infoPtr->hFont); - - btnPtr = infoPtr->buttons; - for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) { - if(TOOLBAR_HasText(infoPtr, btnPtr)) - { - TOOLBAR_MeasureString(infoPtr, btnPtr, hdc, &sz); - if (sz.cx > lpSize->cx) - lpSize->cx = sz.cx; - if (sz.cy > lpSize->cy) - lpSize->cy = sz.cy; - } - } - - SelectObject (hdc, hOldFont); - ReleaseDC (hwnd, hdc); - - TRACE("max string size %ld x %ld!\n", lpSize->cx, lpSize->cy); -} - -/*********************************************************************** -* TOOLBAR_WrapToolbar -* -* This function walks through the buttons and separators in the -* toolbar, and sets the TBSTATE_WRAP flag only on those items where -* wrapping should occur based on the width of the toolbar window. -* It does *not* calculate button placement itself. That task -* takes place in TOOLBAR_CalcToolbar. If the program wants to manage -* the toolbar wrapping on its own, it can use the TBSTYLE_WRAPABLE -* flag, and set the TBSTATE_WRAP flags manually on the appropriate items. -* -* Note: TBSTYLE_WRAPABLE or TBSTYLE_EX_UNDOC1 can be used also to allow -* vertical toolbar lists. -*/ - -static void -TOOLBAR_WrapToolbar( HWND hwnd, DWORD dwStyle ) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - TBUTTON_INFO *btnPtr; - INT x, cx, i, j; - RECT rc; - BOOL bWrap, bButtonWrap; - - /* When the toolbar window style is not TBSTYLE_WRAPABLE, */ - /* no layout is necessary. Applications may use this style */ - /* to perform their own layout on the toolbar. */ - if( !(dwStyle & TBSTYLE_WRAPABLE) && - !(infoPtr->dwExStyle & TBSTYLE_EX_UNDOC1) ) return; - - btnPtr = infoPtr->buttons; - x = infoPtr->nIndent; - - /* this can get the parents width, to know how far we can extend - * this toolbar. We cannot use its height, as there may be multiple - * toolbars in a rebar control - */ - GetClientRect( GetParent(hwnd), &rc ); - infoPtr->nWidth = rc.right - rc.left; - bButtonWrap = FALSE; - - TRACE("start ButtonWidth=%d, BitmapWidth=%d, nWidth=%d, nIndent=%d\n", - infoPtr->nButtonWidth, infoPtr->nBitmapWidth, infoPtr->nWidth, - infoPtr->nIndent); - - for (i = 0; i < infoPtr->nNumButtons; i++ ) - { - bWrap = FALSE; - btnPtr[i].fsState &= ~TBSTATE_WRAP; - - if (btnPtr[i].fsState & TBSTATE_HIDDEN) - continue; - - /* UNDOCUMENTED: If a separator has a non zero bitmap index, */ - /* it is the actual width of the separator. This is used for */ - /* custom controls in toolbars. */ - /* */ - /* BTNS_DROPDOWN separators are treated as buttons for */ - /* width. - GA 8/01 */ - if ((btnPtr[i].fsStyle & BTNS_SEP) && - !(btnPtr[i].fsStyle & BTNS_DROPDOWN)) - cx = (btnPtr[i].iBitmap > 0) ? - btnPtr[i].iBitmap : SEPARATOR_WIDTH; - else - cx = infoPtr->nButtonWidth; - - /* Two or more adjacent separators form a separator group. */ - /* The first separator in a group should be wrapped to the */ - /* next row if the previous wrapping is on a button. */ - if( bButtonWrap && - (btnPtr[i].fsStyle & BTNS_SEP) && - (i + 1 < infoPtr->nNumButtons ) && - (btnPtr[i + 1].fsStyle & BTNS_SEP) ) - { - TRACE("wrap point 1 btn %d style %02x\n", i, btnPtr[i].fsStyle); - btnPtr[i].fsState |= TBSTATE_WRAP; - x = infoPtr->nIndent; - i++; - bButtonWrap = FALSE; - continue; - } - - /* The layout makes sure the bitmap is visible, but not the button. */ - /* Test added to also wrap after a button that starts a row but */ - /* is bigger than the area. - GA 8/01 */ - if (( x + cx - (infoPtr->nButtonWidth - infoPtr->nBitmapWidth) / 2 - > infoPtr->nWidth ) || - ((x == infoPtr->nIndent) && (cx > infoPtr->nWidth))) - { - BOOL bFound = FALSE; - - /* If the current button is a separator and not hidden, */ - /* go to the next until it reaches a non separator. */ - /* Wrap the last separator if it is before a button. */ - while( ( ((btnPtr[i].fsStyle & BTNS_SEP) && - !(btnPtr[i].fsStyle & BTNS_DROPDOWN)) || - (btnPtr[i].fsState & TBSTATE_HIDDEN) ) && - i < infoPtr->nNumButtons ) - { - i++; - bFound = TRUE; - } - - if( bFound && i < infoPtr->nNumButtons ) - { - i--; - TRACE("wrap point 2 btn %d style %02x, x=%d, cx=%d\n", - i, btnPtr[i].fsStyle, x, cx); - btnPtr[i].fsState |= TBSTATE_WRAP; - x = infoPtr->nIndent; - bButtonWrap = FALSE; - continue; - } - else if ( i >= infoPtr->nNumButtons) - break; - - /* If the current button is not a separator, find the last */ - /* separator and wrap it. */ - for ( j = i - 1; j >= 0 && !(btnPtr[j].fsState & TBSTATE_WRAP); j--) - { - if ((btnPtr[j].fsStyle & BTNS_SEP) && - !(btnPtr[j].fsState & TBSTATE_HIDDEN)) - { - bFound = TRUE; - i = j; - TRACE("wrap point 3 btn %d style %02x, x=%d, cx=%d\n", - i, btnPtr[i].fsStyle, x, cx); - x = infoPtr->nIndent; - btnPtr[j].fsState |= TBSTATE_WRAP; - bButtonWrap = FALSE; - break; - } - } - - /* If no separator available for wrapping, wrap one of */ - /* non-hidden previous button. */ - if (!bFound) - { - for ( j = i - 1; - j >= 0 && !(btnPtr[j].fsState & TBSTATE_WRAP); j--) - { - if (btnPtr[j].fsState & TBSTATE_HIDDEN) - continue; - - bFound = TRUE; - i = j; - TRACE("wrap point 4 btn %d style %02x, x=%d, cx=%d\n", - i, btnPtr[i].fsStyle, x, cx); - x = infoPtr->nIndent; - btnPtr[j].fsState |= TBSTATE_WRAP; - bButtonWrap = TRUE; - break; - } - } - - /* If all above failed, wrap the current button. */ - if (!bFound) - { - TRACE("wrap point 5 btn %d style %02x, x=%d, cx=%d\n", - i, btnPtr[i].fsStyle, x, cx); - btnPtr[i].fsState |= TBSTATE_WRAP; - bFound = TRUE; - x = infoPtr->nIndent; - if (btnPtr[i].fsStyle & BTNS_SEP ) - bButtonWrap = FALSE; - else - bButtonWrap = TRUE; - } - } - else { - TRACE("wrap point 6 btn %d style %02x, x=%d, cx=%d\n", - i, btnPtr[i].fsStyle, x, cx); - x += cx; - } - } -} - - -/*********************************************************************** -* TOOLBAR_MeasureButton -* -* Calculates the width and height required for a button. Used in -* TOOLBAR_CalcToolbar to set the all-button width and height and also for -* the width of buttons that are autosized. -* -* Note that it would have been rather elegant to use one piece of code for -* both the laying out of the toolbar and for controlling where button parts -* are drawn, but the native control has inconsistencies between the two that -* prevent this from being effectively. These inconsistencies can be seen as -* artefacts where parts of the button appear outside of the bounding button -* rectangle. -* -* There are several cases for the calculation of the button dimensions and -* button part positioning: -* -* List -* ==== -* -* With Bitmap: -* -* +--------------------------------------------------------+ ^ -* | ^ ^ | | -* | | pad.cy / 2 | centred | | -* | pad.cx/2 + cxedge +--------------+ +------------+ | | DEFPAD_CY + -* |<----------------->| nBitmapWidth | | Text | | | max(nBitmapHeight, szText.cy) -* | |<------------>| | | | | -* | +--------------+ +------------+ | | -* |<-------------------------------------->| | | -* | cxedge + iListGap + nBitmapWidth + 2 |<-----------> | | -* | szText.cx | | -* +--------------------------------------------------------+ - -* <--------------------------------------------------------> -* 2*cxedge + nBitmapWidth + iListGap + szText.cx + pad.cx -* -* Without Bitmap (I_IMAGENONE): -* -* +-----------------------------------+ ^ -* | ^ | | -* | | centred | | LISTPAD_CY + -* | +------------+ | | szText.cy -* | | Text | | | -* | | | | | -* | +------------+ | | -* |<----------------->| | | -* | cxedge |<-----------> | | -* | szText.cx | | -* +-----------------------------------+ - -* <-----------------------------------> -* szText.cx + pad.cx -* -* Without text: -* -* +--------------------------------------+ ^ -* | ^ | | -* | | padding.cy/2 | | DEFPAD_CY + -* | +------------+ | | nBitmapHeight -* | | Bitmap | | | -* | | | | | -* | +------------+ | | -* |<------------------->| | | -* | cxedge + iListGap/2 |<-----------> | | -* | nBitmapWidth | | -* +--------------------------------------+ - -* <--------------------------------------> -* 2*cxedge + nBitmapWidth + iListGap -* -* Non-List -* ======== -* -* With bitmap: -* -* +-----------------------------------+ ^ -* | ^ | | -* | | pad.cy / 2 | | nBitmapHeight + -* | - | | szText.cy + -* | +------------+ | | DEFPAD_CY + 1 -* | centred | Bitmap | | | -* |<----------------->| | | | -* | +------------+ | | -* | ^ | | -* | 1 | | | -* | - | | -* | centred +---------------+ | | -* |<--------------->| Text | | | -* | +---------------+ | | -* +-----------------------------------+ - -* <-----------------------------------> -* pad.cx + max(nBitmapWidth, szText.cx) -* -* Without bitmaps (NULL imagelist or ImageList_GetImageCount() = 0): -* -* +---------------------------------------+ ^ -* | ^ | | -* | | 2 + pad.cy / 2 | | -* | - | | szText.cy + -* | centred +-----------------+ | | pad.cy + 2 -* |<--------------->| Text | | | -* | +-----------------+ | | -* | | | -* +---------------------------------------+ - -* <---------------------------------------> -* 2*cxedge + pad.cx + szText.cx -* -* Without text: -* As for with bitmaps, but with szText.cx zero. -*/ -static inline SIZE TOOLBAR_MeasureButton(TOOLBAR_INFO *infoPtr, SIZE sizeString, BOOL bHasBitmap, BOOL bValidImageList) -{ - SIZE sizeButton; - if (infoPtr->dwStyle & TBSTYLE_LIST) - { - /* set button height from bitmap / text height... */ - sizeButton.cy = max((bHasBitmap ? infoPtr->nBitmapHeight : 0), - sizeString.cy); - - /* ... add on the necessary padding */ - if (bValidImageList) - { - if (bHasBitmap) - sizeButton.cy += DEFPAD_CY; - else - sizeButton.cy += LISTPAD_CY; - } - else - sizeButton.cy += infoPtr->szPadding.cy; - - /* calculate button width */ - if (bHasBitmap) - { - sizeButton.cx = 2*GetSystemMetrics(SM_CXEDGE) + - infoPtr->nBitmapWidth + infoPtr->iListGap; - if (sizeString.cx > 0) - sizeButton.cx += sizeString.cx + infoPtr->szPadding.cx; - } - else - sizeButton.cx = sizeString.cx + infoPtr->szPadding.cx; - } - else - { - if (bHasBitmap) - { - sizeButton.cy = infoPtr->nBitmapHeight + 1 + - sizeString.cy + DEFPAD_CY; - sizeButton.cx = infoPtr->szPadding.cx + - max(sizeString.cx, infoPtr->nBitmapWidth); - } - else - { - sizeButton.cy = sizeString.cy + infoPtr->szPadding.cy + - NONLIST_NOTEXT_OFFSET; - sizeButton.cx = 2*GetSystemMetrics(SM_CXEDGE) + - infoPtr->szPadding.cx + sizeString.cx; - } - } - return sizeButton; -} - - -/*********************************************************************** -* TOOLBAR_CalcToolbar -* -* This function calculates button and separator placement. It first -* calculates the button sizes, gets the toolbar window width and then -* calls TOOLBAR_WrapToolbar to determine which buttons we need to wrap -* on. It assigns a new location to each item and sends this location to -* the tooltip window if appropriate. Finally, it updates the rcBound -* rect and calculates the new required toolbar window height. -*/ -static void -TOOLBAR_CalcToolbar (HWND hwnd) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd); - DWORD dwStyle = infoPtr->dwStyle; - TBUTTON_INFO *btnPtr; - INT i, nRows, nSepRows; - INT x, y, cx, cy; - SIZE sizeString, sizeButton; - BOOL bWrap; - BOOL usesBitmaps = FALSE; - BOOL validImageList = FALSE; - BOOL hasDropDownArrows = TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle); - - TOOLBAR_CalcStrings (hwnd, &sizeString); - - TOOLBAR_DumpToolbar (infoPtr, __LINE__); - - for (i = 0; i < infoPtr->nNumButtons && !usesBitmaps; i++) - { - if (TOOLBAR_IsValidBitmapIndex(infoPtr,infoPtr->buttons[i].iBitmap)) - usesBitmaps = TRUE; - } - if (TOOLBAR_IsValidImageList(infoPtr, 0)) - validImageList = TRUE; - sizeButton = TOOLBAR_MeasureButton(infoPtr, sizeString, usesBitmaps, validImageList); - infoPtr->nButtonWidth = sizeButton.cx; - infoPtr->nButtonHeight = sizeButton.cy; - - if ( infoPtr->cxMin >= 0 && infoPtr->nButtonWidth < infoPtr->cxMin ) - infoPtr->nButtonWidth = infoPtr->cxMin; - if ( infoPtr->cxMax > 0 && infoPtr->nButtonWidth > infoPtr->cxMax ) - infoPtr->nButtonWidth = infoPtr->cxMax; - - TOOLBAR_WrapToolbar( hwnd, dwStyle ); - - x = infoPtr->nIndent; - y = 0; - - /* from above, minimum is a button, and possible text */ - cx = infoPtr->nButtonWidth; - - infoPtr->nHeight = infoPtr->nButtonHeight; - - cy = infoPtr->nHeight; - - nRows = nSepRows = 0; - - infoPtr->rcBound.top = y; - infoPtr->rcBound.left = x; - infoPtr->rcBound.bottom = y + cy; - infoPtr->rcBound.right = x; - - btnPtr = infoPtr->buttons; - - TRACE("cy=%d\n", cy); - - for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++ ) - { - bWrap = FALSE; - if (btnPtr->fsState & TBSTATE_HIDDEN) - { - SetRectEmpty (&btnPtr->rect); - continue; - } - - cy = infoPtr->nHeight; - - /* UNDOCUMENTED: If a separator has a non zero bitmap index, */ - /* it is the actual width of the separator. This is used for */ - /* custom controls in toolbars. */ - if (btnPtr->fsStyle & BTNS_SEP) { - if (btnPtr->fsStyle & BTNS_DROPDOWN) { - cy = (btnPtr->iBitmap > 0) ? - btnPtr->iBitmap : SEPARATOR_WIDTH; - cx = infoPtr->nButtonWidth; - } - else - cx = (btnPtr->iBitmap > 0) ? - btnPtr->iBitmap : SEPARATOR_WIDTH; - } - else - { - if (btnPtr->cx) - cx = btnPtr->cx; - else if ((infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || - (btnPtr->fsStyle & BTNS_AUTOSIZE)) - { - SIZE sz; - HDC hdc; - HFONT hOldFont; - - hdc = GetDC (hwnd); - hOldFont = SelectObject (hdc, infoPtr->hFont); - - TOOLBAR_MeasureString(infoPtr, btnPtr, hdc, &sz); - - SelectObject (hdc, hOldFont); - ReleaseDC (hwnd, hdc); - - sizeButton = TOOLBAR_MeasureButton(infoPtr, sz, - TOOLBAR_IsValidBitmapIndex(infoPtr, infoPtr->buttons[i].iBitmap), - validImageList); - cx = sizeButton.cx; - } - else - cx = infoPtr->nButtonWidth; - - /* if size has been set manually then don't add on extra space - * for the drop down arrow */ - if (!btnPtr->cx && hasDropDownArrows && - ((btnPtr->fsStyle & BTNS_DROPDOWN) || (btnPtr->fsStyle & BTNS_WHOLEDROPDOWN))) - cx += DDARROW_WIDTH; - } - if (btnPtr->fsState & TBSTATE_WRAP ) - bWrap = TRUE; - - SetRect (&btnPtr->rect, x, y, x + cx, y + cy); - - if (infoPtr->rcBound.left > x) - infoPtr->rcBound.left = x; - if (infoPtr->rcBound.right < x + cx) - infoPtr->rcBound.right = x + cx; - if (infoPtr->rcBound.bottom < y + cy) - infoPtr->rcBound.bottom = y + cy; - - /* Set the toolTip only for non-hidden, non-separator button */ - if (infoPtr->hwndToolTip && !(btnPtr->fsStyle & BTNS_SEP )) - { - TTTOOLINFOW ti; - - ZeroMemory (&ti, sizeof(ti)); - ti.cbSize = sizeof(ti); - ti.hwnd = hwnd; - ti.uId = btnPtr->idCommand; - ti.rect = btnPtr->rect; - SendMessageW (infoPtr->hwndToolTip, TTM_NEWTOOLRECTW, - 0, (LPARAM)&ti); - } - - /* btnPtr->nRow is zero based. The space between the rows is */ - /* also considered as a row. */ - btnPtr->nRow = nRows + nSepRows; - - TRACE("button %d style=%x, bWrap=%d, nRows=%d, nSepRows=%d, btnrow=%d, (%d,%d)-(%d,%d)\n", - i, btnPtr->fsStyle, bWrap, nRows, nSepRows, btnPtr->nRow, - x, y, x+cx, y+cy); - - if( bWrap ) - { - if ( !(btnPtr->fsStyle & BTNS_SEP) ) - y += cy; - else - { - /* UNDOCUMENTED: If a separator has a non zero bitmap index, */ - /* it is the actual width of the separator. This is used for */ - /* custom controls in toolbars. */ - if ( !(btnPtr->fsStyle & BTNS_DROPDOWN)) - y += cy + ( (btnPtr->iBitmap > 0 ) ? - btnPtr->iBitmap : SEPARATOR_WIDTH) * 2 /3; - else - y += cy; - - /* nSepRows is used to calculate the extra height follwoing */ - /* the last row. */ - nSepRows++; - } - x = infoPtr->nIndent; - - /* Increment row number unless this is the last button */ - /* and it has Wrap set. */ - if (i != infoPtr->nNumButtons-1) - nRows++; - } - else - x += cx; - } - - /* infoPtr->nRows is the number of rows on the toolbar */ - infoPtr->nRows = nRows + nSepRows + 1; - -#if 0 - /******************************************************************** - * The following while interesting, does not match the values * - * created above for the button rectangles, nor the rcBound rect. * - * We will comment it out and remove it later. * - * * - * The problem showed up as heights in the pager control that was * - * wrong. * - ********************************************************************/ - - /* nSepRows * (infoPtr->nBitmapHeight + 1) is the space following */ - /* the last row. */ - infoPtr->nHeight = TOP_BORDER + (nRows + 1) * infoPtr->nButtonHeight + - nSepRows * (SEPARATOR_WIDTH * 2 / 3) + - nSepRows * (infoPtr->nBitmapHeight + 1) + - BOTTOM_BORDER; -#endif - - infoPtr->nHeight = infoPtr->rcBound.bottom - infoPtr->rcBound.top; - - TRACE("toolbar height %d, button width %d\n", infoPtr->nHeight, infoPtr->nButtonWidth); -} - - -static INT -TOOLBAR_InternalHitTest (HWND hwnd, LPPOINT lpPt) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - TBUTTON_INFO *btnPtr; - INT i; - - btnPtr = infoPtr->buttons; - for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) { - if (btnPtr->fsState & TBSTATE_HIDDEN) - continue; - - if (btnPtr->fsStyle & BTNS_SEP) { - if (PtInRect (&btnPtr->rect, *lpPt)) { - TRACE(" ON SEPARATOR %d!\n", i); - return -i; - } - } - else { - if (PtInRect (&btnPtr->rect, *lpPt)) { - TRACE(" ON BUTTON %d!\n", i); - return i; - } - } - } - - TRACE(" NOWHERE!\n"); - return TOOLBAR_NOWHERE; -} - - -static INT -TOOLBAR_GetButtonIndex (TOOLBAR_INFO *infoPtr, INT idCommand, BOOL CommandIsIndex) -{ - TBUTTON_INFO *btnPtr; - INT i; - - if (CommandIsIndex) { - TRACE("command is really index command=%d\n", idCommand); - if (idCommand >= infoPtr->nNumButtons) return -1; - return idCommand; - } - btnPtr = infoPtr->buttons; - for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) { - if (btnPtr->idCommand == idCommand) { - TRACE("command=%d index=%d\n", idCommand, i); - return i; - } - } - TRACE("no index found for command=%d\n", idCommand); - return -1; -} - - -static INT -TOOLBAR_GetCheckedGroupButtonIndex (TOOLBAR_INFO *infoPtr, INT nIndex) -{ - TBUTTON_INFO *btnPtr; - INT nRunIndex; - - if ((nIndex < 0) || (nIndex > infoPtr->nNumButtons)) - return -1; - - /* check index button */ - btnPtr = &infoPtr->buttons[nIndex]; - if ((btnPtr->fsStyle & BTNS_CHECKGROUP) == BTNS_CHECKGROUP) { - if (btnPtr->fsState & TBSTATE_CHECKED) - return nIndex; - } - - /* check previous buttons */ - nRunIndex = nIndex - 1; - while (nRunIndex >= 0) { - btnPtr = &infoPtr->buttons[nRunIndex]; - if ((btnPtr->fsStyle & BTNS_CHECKGROUP) == BTNS_CHECKGROUP) { - if (btnPtr->fsState & TBSTATE_CHECKED) - return nRunIndex; - } - else - break; - nRunIndex--; - } - - /* check next buttons */ - nRunIndex = nIndex + 1; - while (nRunIndex < infoPtr->nNumButtons) { - btnPtr = &infoPtr->buttons[nRunIndex]; - if ((btnPtr->fsStyle & BTNS_CHECKGROUP) == BTNS_CHECKGROUP) { - if (btnPtr->fsState & TBSTATE_CHECKED) - return nRunIndex; - } - else - break; - nRunIndex++; - } - - return -1; -} - - -static VOID -TOOLBAR_RelayEvent (HWND hwndTip, HWND hwndMsg, UINT uMsg, - WPARAM wParam, LPARAM lParam) -{ - MSG msg; - - msg.hwnd = hwndMsg; - msg.message = uMsg; - msg.wParam = wParam; - msg.lParam = lParam; - msg.time = GetMessageTime (); - msg.pt.x = LOWORD(GetMessagePos ()); - msg.pt.y = HIWORD(GetMessagePos ()); - - SendMessageW (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg); -} - -/* keeps available button list box sorted by button id */ -static void TOOLBAR_Cust_InsertAvailButton(HWND hwnd, PCUSTOMBUTTON btnInfoNew) -{ - int i; - int count; - PCUSTOMBUTTON btnInfo; - HWND hwndAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX); - - TRACE("button %s, idCommand %d\n", debugstr_w(btnInfoNew->text), btnInfoNew->btn.idCommand); - - count = SendMessageW(hwndAvail, LB_GETCOUNT, 0, 0); - - /* position 0 is always separator */ - for (i = 1; i < count; i++) - { - btnInfo = (PCUSTOMBUTTON)SendMessageW(hwndAvail, LB_GETITEMDATA, i, 0); - if (btnInfoNew->btn.idCommand < btnInfo->btn.idCommand) - { - i = SendMessageW(hwndAvail, LB_INSERTSTRING, i, 0); - SendMessageW(hwndAvail, LB_SETITEMDATA, i, (LPARAM)btnInfoNew); - return; - } - } - /* id higher than all others add to end */ - i = SendMessageW(hwndAvail, LB_ADDSTRING, 0, 0); - SendMessageW(hwndAvail, LB_SETITEMDATA, i, (LPARAM)btnInfoNew); -} - -static void TOOLBAR_Cust_MoveButton(PCUSTDLG_INFO custInfo, HWND hwnd, INT nIndexFrom, INT nIndexTo) -{ - NMTOOLBARW nmtb; - - TRACE("index from %d, index to %d\n", nIndexFrom, nIndexTo); - - if (nIndexFrom == nIndexTo) - return; - - /* MSDN states that iItem is the index of the button, rather than the - * command ID as used by every other NMTOOLBAR notification */ - nmtb.iItem = nIndexFrom; - if (TOOLBAR_SendNotify(&nmtb.hdr, custInfo->tbInfo, TBN_QUERYINSERT)) - { - PCUSTOMBUTTON btnInfo; - NMHDR hdr; - HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX); - int count = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); - - btnInfo = (PCUSTOMBUTTON)SendMessageW(hwndList, LB_GETITEMDATA, nIndexFrom, 0); - - SendMessageW(hwndList, LB_DELETESTRING, nIndexFrom, 0); - SendMessageW(hwndList, LB_INSERTSTRING, nIndexTo, 0); - SendMessageW(hwndList, LB_SETITEMDATA, nIndexTo, (LPARAM)btnInfo); - SendMessageW(hwndList, LB_SETCURSEL, nIndexTo, 0); - - if (nIndexTo <= 0) - EnableWindow(GetDlgItem(hwnd,IDC_MOVEUP_BTN), FALSE); - else - EnableWindow(GetDlgItem(hwnd,IDC_MOVEUP_BTN), TRUE); - - /* last item is always separator, so -2 instead of -1 */ - if (nIndexTo >= (count - 2)) - EnableWindow(GetDlgItem(hwnd,IDC_MOVEDN_BTN), FALSE); - else - EnableWindow(GetDlgItem(hwnd,IDC_MOVEDN_BTN), TRUE); - - SendMessageW(custInfo->tbHwnd, TB_DELETEBUTTON, nIndexFrom, 0); - SendMessageW(custInfo->tbHwnd, TB_INSERTBUTTONW, nIndexTo, (LPARAM)&(btnInfo->btn)); - - TOOLBAR_SendNotify(&hdr, custInfo->tbInfo, TBN_TOOLBARCHANGE); - } -} - -static void TOOLBAR_Cust_AddButton(PCUSTDLG_INFO custInfo, HWND hwnd, INT nIndexAvail, INT nIndexTo) -{ - NMTOOLBARW nmtb; - - TRACE("Add: nIndexAvail %d, nIndexTo %d\n", nIndexAvail, nIndexTo); - - /* MSDN states that iItem is the index of the button, rather than the - * command ID as used by every other NMTOOLBAR notification */ - nmtb.iItem = nIndexAvail; - if (TOOLBAR_SendNotify(&nmtb.hdr, custInfo->tbInfo, TBN_QUERYINSERT)) - { - PCUSTOMBUTTON btnInfo; - NMHDR hdr; - HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX); - HWND hwndAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX); - int count = SendMessageW(hwndAvail, LB_GETCOUNT, 0, 0); - - btnInfo = (PCUSTOMBUTTON)SendMessageW(hwndAvail, LB_GETITEMDATA, nIndexAvail, 0); - - if (nIndexAvail != 0) /* index == 0 indicates separator */ - { - /* remove from 'available buttons' list */ - SendMessageW(hwndAvail, LB_DELETESTRING, nIndexAvail, 0); - if (nIndexAvail == count-1) - SendMessageW(hwndAvail, LB_SETCURSEL, nIndexAvail-1 , 0); - else - SendMessageW(hwndAvail, LB_SETCURSEL, nIndexAvail , 0); - } - else - { - PCUSTOMBUTTON btnNew; - - /* duplicate 'separator' button */ - btnNew = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON)); - memcpy(btnNew, btnInfo, sizeof(CUSTOMBUTTON)); - btnInfo = btnNew; - } - - /* insert into 'toolbar button' list */ - SendMessageW(hwndList, LB_INSERTSTRING, nIndexTo, 0); - SendMessageW(hwndList, LB_SETITEMDATA, nIndexTo, (LPARAM)btnInfo); - - SendMessageW(custInfo->tbHwnd, TB_INSERTBUTTONW, nIndexTo, (LPARAM)&(btnInfo->btn)); - - TOOLBAR_SendNotify(&hdr, custInfo->tbInfo, TBN_TOOLBARCHANGE); - } -} - -static void TOOLBAR_Cust_RemoveButton(PCUSTDLG_INFO custInfo, HWND hwnd, INT index) -{ - PCUSTOMBUTTON btnInfo; - HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX); - - TRACE("Remove: index %d\n", index); - - btnInfo = (PCUSTOMBUTTON)SendMessageW(hwndList, LB_GETITEMDATA, index, 0); - - /* send TBN_QUERYDELETE notification */ - if (TOOLBAR_IsButtonRemovable(custInfo->tbInfo, index, btnInfo)) - { - NMHDR hdr; - - SendMessageW(hwndList, LB_DELETESTRING, index, 0); - SendMessageW(hwndList, LB_SETCURSEL, index , 0); - - SendMessageW(custInfo->tbHwnd, TB_DELETEBUTTON, index, 0); - - /* insert into 'available button' list */ - if (!(btnInfo->btn.fsStyle & BTNS_SEP)) - TOOLBAR_Cust_InsertAvailButton(hwnd, btnInfo); - else - Free(btnInfo); - - TOOLBAR_SendNotify(&hdr, custInfo->tbInfo, TBN_TOOLBARCHANGE); - } -} - -/* drag list notification function for toolbar buttons list box */ -static LRESULT TOOLBAR_Cust_ToolbarDragListNotification(PCUSTDLG_INFO custInfo, HWND hwnd, DRAGLISTINFO *pDLI) -{ - HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX); - switch (pDLI->uNotification) - { - case DL_BEGINDRAG: - { - INT nCurrentItem = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE); - INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); - /* no dragging for last item (separator) */ - if (nCurrentItem >= (nCount - 1)) return FALSE; - return TRUE; - } - case DL_DRAGGING: - { - INT nCurrentItem = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE); - INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); - /* no dragging past last item (separator) */ - if ((nCurrentItem >= 0) && (nCurrentItem < (nCount - 1))) - { - DrawInsert(hwnd, hwndList, nCurrentItem); - /* FIXME: native uses "move button" cursor */ - return DL_COPYCURSOR; - } - - /* not over toolbar buttons list */ - if (nCurrentItem < 0) - { - POINT ptWindow = pDLI->ptCursor; - HWND hwndListAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX); - MapWindowPoints(NULL, hwnd, &ptWindow, 1); - /* over available buttons list? */ - if (ChildWindowFromPoint(hwnd, ptWindow) == hwndListAvail) - /* FIXME: native uses "move button" cursor */ - return DL_COPYCURSOR; - } - /* clear drag arrow */ - DrawInsert(hwnd, hwndList, -1); - return DL_STOPCURSOR; - } - case DL_DROPPED: - { - INT nIndexTo = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE); - INT nIndexFrom = SendMessageW(hwndList, LB_GETCURSEL, 0, 0); - INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); - if ((nIndexTo >= 0) && (nIndexTo < (nCount - 1))) - { - /* clear drag arrow */ - DrawInsert(hwnd, hwndList, -1); - /* move item */ - TOOLBAR_Cust_MoveButton(custInfo, hwnd, nIndexFrom, nIndexTo); - } - /* not over toolbar buttons list */ - if (nIndexTo < 0) - { - POINT ptWindow = pDLI->ptCursor; - HWND hwndListAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX); - MapWindowPoints(NULL, hwnd, &ptWindow, 1); - /* over available buttons list? */ - if (ChildWindowFromPoint(hwnd, ptWindow) == hwndListAvail) - TOOLBAR_Cust_RemoveButton(custInfo, hwnd, nIndexFrom); - } - break; - } - case DL_CANCELDRAG: - /* Clear drag arrow */ - DrawInsert(hwnd, hwndList, -1); - break; - } - - return 0; -} - -/* drag list notification function for available buttons list box */ -static LRESULT TOOLBAR_Cust_AvailDragListNotification(PCUSTDLG_INFO custInfo, HWND hwnd, DRAGLISTINFO *pDLI) -{ - HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX); - switch (pDLI->uNotification) - { - case DL_BEGINDRAG: - return TRUE; - case DL_DRAGGING: - { - INT nCurrentItem = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE); - INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); - /* no dragging past last item (separator) */ - if ((nCurrentItem >= 0) && (nCurrentItem < nCount)) - { - DrawInsert(hwnd, hwndList, nCurrentItem); - /* FIXME: native uses "move button" cursor */ - return DL_COPYCURSOR; - } - - /* not over toolbar buttons list */ - if (nCurrentItem < 0) - { - POINT ptWindow = pDLI->ptCursor; - HWND hwndListAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX); - MapWindowPoints(NULL, hwnd, &ptWindow, 1); - /* over available buttons list? */ - if (ChildWindowFromPoint(hwnd, ptWindow) == hwndListAvail) - /* FIXME: native uses "move button" cursor */ - return DL_COPYCURSOR; - } - /* clear drag arrow */ - DrawInsert(hwnd, hwndList, -1); - return DL_STOPCURSOR; - } - case DL_DROPPED: - { - INT nIndexTo = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE); - INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); - INT nIndexFrom = SendDlgItemMessageW(hwnd, IDC_AVAILBTN_LBOX, LB_GETCURSEL, 0, 0); - if ((nIndexTo >= 0) && (nIndexTo < nCount)) - { - /* clear drag arrow */ - DrawInsert(hwnd, hwndList, -1); - /* add item */ - TOOLBAR_Cust_AddButton(custInfo, hwnd, nIndexFrom, nIndexTo); - } - } - case DL_CANCELDRAG: - /* Clear drag arrow */ - DrawInsert(hwnd, hwndList, -1); - break; - } - return 0; -} - -extern UINT uDragListMessage; - -/*********************************************************************** - * TOOLBAR_CustomizeDialogProc - * This function implements the toolbar customization dialog. - */ -static INT_PTR CALLBACK -TOOLBAR_CustomizeDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - PCUSTDLG_INFO custInfo = (PCUSTDLG_INFO)GetWindowLongPtrW (hwnd, DWLP_USER); - PCUSTOMBUTTON btnInfo; - NMTOOLBARA nmtb; - TOOLBAR_INFO *infoPtr = custInfo ? custInfo->tbInfo : NULL; - - switch (uMsg) - { - case WM_INITDIALOG: - custInfo = (PCUSTDLG_INFO)lParam; - SetWindowLongPtrW (hwnd, DWLP_USER, (LONG_PTR)custInfo); - - if (custInfo) - { - WCHAR Buffer[256]; - int i = 0; - int index; - - infoPtr = custInfo->tbInfo; - - /* send TBN_QUERYINSERT notification */ - nmtb.iItem = custInfo->tbInfo->nNumButtons; - - if (!TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_QUERYINSERT)) - return FALSE; - - /* UNDOCUMENTED: dialog hwnd immediately follows NMHDR */ - /* FIXME: this hack won't work on 64-bit - we need to declare a structure for this */ - nmtb.iItem = (int)hwnd; - /* Send TBN_INITCUSTOMIZE notification */ - if (TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr, TBN_INITCUSTOMIZE) == - TBNRF_HIDEHELP) - { - TRACE("TBNRF_HIDEHELP requested\n"); - ShowWindow(GetDlgItem(hwnd, IDC_HELP_BTN), SW_HIDE); - } - - /* add items to 'toolbar buttons' list and check if removable */ - for (i = 0; i < custInfo->tbInfo->nNumButtons; i++) - { - btnInfo = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON)); - memset (&btnInfo->btn, 0, sizeof(TBBUTTON)); - btnInfo->btn.fsStyle = BTNS_SEP; - btnInfo->bVirtual = FALSE; - LoadStringW (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64); - - /* send TBN_QUERYDELETE notification */ - btnInfo->bRemovable = TOOLBAR_IsButtonRemovable(infoPtr, i, btnInfo); - - index = (int)SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_ADDSTRING, 0, 0); - SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo); - } - - SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMHEIGHT, 0, infoPtr->nBitmapHeight + 8); - - /* insert separator button into 'available buttons' list */ - btnInfo = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON)); - memset (&btnInfo->btn, 0, sizeof(TBBUTTON)); - btnInfo->btn.fsStyle = BTNS_SEP; - btnInfo->bVirtual = FALSE; - btnInfo->bRemovable = TRUE; - LoadStringW (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64); - index = (int)SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_ADDSTRING, 0, (LPARAM)btnInfo); - SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo); - - /* insert all buttons into dsa */ - for (i = 0;; i++) - { - /* send TBN_GETBUTTONINFO notification */ - NMTOOLBARW nmtb; - nmtb.iItem = i; - nmtb.pszText = Buffer; - nmtb.cchText = 256; - - /* Clear previous button's text */ - ZeroMemory(nmtb.pszText, nmtb.cchText * sizeof(WCHAR)); - - if (!TOOLBAR_GetButtonInfo(infoPtr, &nmtb)) - break; - - TRACE("WM_INITDIALOG style: %x iItem(%d) idCommand(%d) iString(%d) %s\n", - nmtb.tbButton.fsStyle, i, - nmtb.tbButton.idCommand, - nmtb.tbButton.iString, - nmtb.tbButton.iString >= 0 ? debugstr_w(infoPtr->strings[nmtb.tbButton.iString]) - : ""); - - /* insert button into the apropriate list */ - index = TOOLBAR_GetButtonIndex (custInfo->tbInfo, nmtb.tbButton.idCommand, FALSE); - if (index == -1) - { - btnInfo = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON)); - btnInfo->bVirtual = FALSE; - btnInfo->bRemovable = TRUE; - } - else - { - btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, - IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0); - } - - memcpy (&btnInfo->btn, &nmtb.tbButton, sizeof(TBBUTTON)); - if (!(nmtb.tbButton.fsStyle & BTNS_SEP)) - { - if (lstrlenW(nmtb.pszText)) - lstrcpyW(btnInfo->text, nmtb.pszText); - else if (nmtb.tbButton.iString >= 0 && - nmtb.tbButton.iString < infoPtr->nNumStrings) - { - lstrcpyW(btnInfo->text, - infoPtr->strings[nmtb.tbButton.iString]); - } - } - - if (index == -1) - TOOLBAR_Cust_InsertAvailButton(hwnd, btnInfo); - } - - SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMHEIGHT, 0, infoPtr->nBitmapHeight + 8); - - /* select first item in the 'available' list */ - SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_SETCURSEL, 0, 0); - - /* append 'virtual' separator button to the 'toolbar buttons' list */ - btnInfo = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON)); - memset (&btnInfo->btn, 0, sizeof(TBBUTTON)); - btnInfo->btn.fsStyle = BTNS_SEP; - btnInfo->bVirtual = TRUE; - btnInfo->bRemovable = FALSE; - LoadStringW (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64); - index = (int)SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_ADDSTRING, 0, (LPARAM)btnInfo); - SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo); - - /* select last item in the 'toolbar' list */ - SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETCURSEL, index, 0); - SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETTOPINDEX, index, 0); - - MakeDragList(GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX)); - MakeDragList(GetDlgItem(hwnd, IDC_AVAILBTN_LBOX)); - - /* set focus and disable buttons */ - PostMessageW (hwnd, WM_USER, 0, 0); - } - return TRUE; - - case WM_USER: - EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE); - EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE); - EnableWindow (GetDlgItem (hwnd,IDC_REMOVE_BTN), FALSE); - SetFocus (GetDlgItem (hwnd, IDC_TOOLBARBTN_LBOX)); - return TRUE; - - case WM_CLOSE: - EndDialog(hwnd, FALSE); - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDC_TOOLBARBTN_LBOX: - if (HIWORD(wParam) == LBN_SELCHANGE) - { - PCUSTOMBUTTON btnInfo; - NMTOOLBARA nmtb; - int count; - int index; - - count = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0); - index = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0); - - /* send TBN_QUERYINSERT notification */ - nmtb.iItem = index; - TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_QUERYINSERT); - - /* get list box item */ - btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0); - - if (index == (count - 1)) - { - /* last item (virtual separator) */ - EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE); - EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE); - } - else if (index == (count - 2)) - { - /* second last item (last non-virtual item) */ - EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), TRUE); - EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE); - } - else if (index == 0) - { - /* first item */ - EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE); - EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), TRUE); - } - else - { - EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), TRUE); - EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), TRUE); - } - - EnableWindow (GetDlgItem (hwnd,IDC_REMOVE_BTN), btnInfo->bRemovable); - } - break; - - case IDC_MOVEUP_BTN: - { - int index = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0); - TOOLBAR_Cust_MoveButton(custInfo, hwnd, index, index-1); - } - break; - - case IDC_MOVEDN_BTN: /* move down */ - { - int index = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0); - TOOLBAR_Cust_MoveButton(custInfo, hwnd, index, index+1); - } - break; - - case IDC_REMOVE_BTN: /* remove button */ - { - int index = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0); - - if (LB_ERR == index) - break; - - TOOLBAR_Cust_RemoveButton(custInfo, hwnd, index); - } - break; - case IDC_HELP_BTN: - TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_CUSTHELP); - break; - case IDC_RESET_BTN: - TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_RESET); - break; - - case IDOK: /* Add button */ - { - int index; - int indexto; - - index = SendDlgItemMessageW(hwnd, IDC_AVAILBTN_LBOX, LB_GETCURSEL, 0, 0); - indexto = SendDlgItemMessageW(hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0); - - TOOLBAR_Cust_AddButton(custInfo, hwnd, index, indexto); - } - break; - - case IDCANCEL: - EndDialog(hwnd, FALSE); - break; - } - return TRUE; - - case WM_DESTROY: - { - int count; - int i; - - /* delete items from 'toolbar buttons' listbox*/ - count = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0); - for (i = 0; i < count; i++) - { - btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, i, 0); - Free(btnInfo); - SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, 0, 0); - } - SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_RESETCONTENT, 0, 0); - - - /* delete items from 'available buttons' listbox*/ - count = SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_GETCOUNT, 0, 0); - for (i = 0; i < count; i++) - { - btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_GETITEMDATA, i, 0); - Free(btnInfo); - SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMDATA, i, 0); - } - SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_RESETCONTENT, 0, 0); - } - return TRUE; - - case WM_DRAWITEM: - if (wParam == IDC_AVAILBTN_LBOX || wParam == IDC_TOOLBARBTN_LBOX) - { - LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam; - RECT rcButton; - RECT rcText; - HPEN hPen, hOldPen; - HBRUSH hOldBrush; - COLORREF oldText = 0; - COLORREF oldBk = 0; - - /* get item data */ - btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, wParam, LB_GETITEMDATA, (WPARAM)lpdis->itemID, 0); - if (btnInfo == NULL) - { - FIXME("btnInfo invalid!\n"); - return TRUE; - } - - /* set colors and select objects */ - oldBk = SetBkColor (lpdis->hDC, (lpdis->itemState & ODS_FOCUS)?comctl32_color.clrHighlight:comctl32_color.clrWindow); - if (btnInfo->bVirtual) - oldText = SetTextColor (lpdis->hDC, comctl32_color.clrGrayText); - else - oldText = SetTextColor (lpdis->hDC, (lpdis->itemState & ODS_FOCUS)?comctl32_color.clrHighlightText:comctl32_color.clrWindowText); - hPen = CreatePen( PS_SOLID, 1, - GetSysColor( (lpdis->itemState & ODS_SELECTED)?COLOR_HIGHLIGHT:COLOR_WINDOW)); - hOldPen = SelectObject (lpdis->hDC, hPen ); - hOldBrush = SelectObject (lpdis->hDC, GetSysColorBrush ((lpdis->itemState & ODS_FOCUS)?COLOR_HIGHLIGHT:COLOR_WINDOW)); - - /* fill background rectangle */ - Rectangle (lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, - lpdis->rcItem.right, lpdis->rcItem.bottom); - - /* calculate button and text rectangles */ - CopyRect (&rcButton, &lpdis->rcItem); - InflateRect (&rcButton, -1, -1); - CopyRect (&rcText, &rcButton); - rcButton.right = rcButton.left + custInfo->tbInfo->nBitmapWidth + 6; - rcText.left = rcButton.right + 2; - - /* draw focus rectangle */ - if (lpdis->itemState & ODS_FOCUS) - DrawFocusRect (lpdis->hDC, &lpdis->rcItem); - - /* draw button */ - if (!(infoPtr->dwStyle & TBSTYLE_FLAT)) - DrawEdge (lpdis->hDC, &rcButton, EDGE_RAISED, BF_RECT|BF_MIDDLE|BF_SOFT); - - /* draw image and text */ - if ((btnInfo->btn.fsStyle & BTNS_SEP) == 0) { - HIMAGELIST himl = GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr, - btnInfo->btn.iBitmap)); - ImageList_Draw (himl, GETIBITMAP(infoPtr, btnInfo->btn.iBitmap), - lpdis->hDC, rcButton.left+3, rcButton.top+3, ILD_NORMAL); - } - DrawTextW (lpdis->hDC, btnInfo->text, -1, &rcText, - DT_LEFT | DT_VCENTER | DT_SINGLELINE); - - /* delete objects and reset colors */ - SelectObject (lpdis->hDC, hOldBrush); - SelectObject (lpdis->hDC, hOldPen); - SetBkColor (lpdis->hDC, oldBk); - SetTextColor (lpdis->hDC, oldText); - DeleteObject( hPen ); - return TRUE; - } - return FALSE; - - case WM_MEASUREITEM: - if (wParam == IDC_AVAILBTN_LBOX || wParam == IDC_TOOLBARBTN_LBOX) - { - MEASUREITEMSTRUCT *lpmis = (MEASUREITEMSTRUCT*)lParam; - - lpmis->itemHeight = 15 + 8; /* default height */ - - return TRUE; - } - return FALSE; - - default: - if (uDragListMessage && (uMsg == uDragListMessage)) - { - if (wParam == IDC_TOOLBARBTN_LBOX) - { - LRESULT res = TOOLBAR_Cust_ToolbarDragListNotification( - custInfo, hwnd, (DRAGLISTINFO *)lParam); - SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, res); - return TRUE; - } - else if (wParam == IDC_AVAILBTN_LBOX) - { - LRESULT res = TOOLBAR_Cust_AvailDragListNotification( - custInfo, hwnd, (DRAGLISTINFO *)lParam); - SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, res); - return TRUE; - } - } - return FALSE; - } -} - - -/*********************************************************************** - * TOOLBAR_AddBitmap: Add the bitmaps to the default image list. - * - */ -static LRESULT -TOOLBAR_AddBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - LPTBADDBITMAP lpAddBmp = (LPTBADDBITMAP)lParam; - INT nIndex = 0, nButtons, nCount; - HBITMAP hbmLoad; - HIMAGELIST himlDef; - - TRACE("hwnd=%p wParam=%x lParam=%lx\n", hwnd, wParam, lParam); - if (!lpAddBmp) - return -1; - - if (lpAddBmp->hInst == HINST_COMMCTRL) - { - if ((lpAddBmp->nID & ~1) == IDB_STD_SMALL_COLOR) - nButtons = 15; - else if ((lpAddBmp->nID & ~1) == IDB_VIEW_SMALL_COLOR) - nButtons = 13; - else if ((lpAddBmp->nID & ~1) == IDB_HIST_SMALL_COLOR) - nButtons = 5; - else - return -1; - - TRACE ("adding %d internal bitmaps!\n", nButtons); - - /* Windows resize all the buttons to the size of a newly added standard image */ - if (lpAddBmp->nID & 1) - { - /* large icons */ - /* FIXME: on windows the size of the images is 25x24 but the size of the bitmap - * in rsrc is only 24x24. Fix the bitmap (how?) and then fix this - */ - SendMessageW (hwnd, TB_SETBITMAPSIZE, 0, - MAKELPARAM((WORD)24, (WORD)24)); - SendMessageW (hwnd, TB_SETBUTTONSIZE, 0, - MAKELPARAM((WORD)31, (WORD)30)); - } - else - { - /* small icons */ - SendMessageW (hwnd, TB_SETBITMAPSIZE, 0, - MAKELPARAM((WORD)16, (WORD)16)); - SendMessageW (hwnd, TB_SETBUTTONSIZE, 0, - MAKELPARAM((WORD)22, (WORD)22)); - } - - TOOLBAR_CalcToolbar (hwnd); - } - else - { - nButtons = (INT)wParam; - if (nButtons <= 0) - return -1; - - TRACE ("adding %d bitmaps!\n", nButtons); - } - - if (!infoPtr->cimlDef) { - /* create new default image list */ - TRACE ("creating default image list!\n"); - - himlDef = ImageList_Create (infoPtr->nBitmapWidth, infoPtr->nBitmapHeight, - ILC_COLORDDB | ILC_MASK, nButtons, 2); - TOOLBAR_InsertImageList(&infoPtr->himlDef, &infoPtr->cimlDef, himlDef, 0); - infoPtr->himlInt = himlDef; - } - else { - himlDef = GETDEFIMAGELIST(infoPtr, 0); - } - - if (!himlDef) { - WARN("No default image list available\n"); - return -1; - } - - nCount = ImageList_GetImageCount(himlDef); - - /* Add bitmaps to the default image list */ - if (lpAddBmp->hInst == NULL) - { - BITMAP bmp; - HBITMAP hOldBitmapBitmap, hOldBitmapLoad; - HDC hdcImage, hdcBitmap; - - /* copy the bitmap before adding it so that the user's bitmap - * doesn't get modified. - */ - GetObjectW ((HBITMAP)lpAddBmp->nID, sizeof(BITMAP), (LPVOID)&bmp); - - hdcImage = CreateCompatibleDC(0); - hdcBitmap = CreateCompatibleDC(0); - - /* create new bitmap */ - hbmLoad = CreateBitmap (bmp.bmWidth, bmp.bmHeight, bmp.bmPlanes, bmp.bmBitsPixel, NULL); - hOldBitmapBitmap = SelectObject(hdcBitmap, (HBITMAP)lpAddBmp->nID); - hOldBitmapLoad = SelectObject(hdcImage, hbmLoad); - - /* Copy the user's image */ - BitBlt (hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, - hdcBitmap, 0, 0, SRCCOPY); - - SelectObject (hdcImage, hOldBitmapLoad); - SelectObject (hdcBitmap, hOldBitmapBitmap); - DeleteDC (hdcImage); - DeleteDC (hdcBitmap); - - nIndex = ImageList_AddMasked (himlDef, hbmLoad, comctl32_color.clrBtnFace); - DeleteObject (hbmLoad); - } - else if (lpAddBmp->hInst == HINST_COMMCTRL) - { - /* Add system bitmaps */ - switch (lpAddBmp->nID) - { - case IDB_STD_SMALL_COLOR: - hbmLoad = LoadBitmapW (COMCTL32_hModule, - MAKEINTRESOURCEW(IDB_STD_SMALL)); - nIndex = ImageList_AddMasked (himlDef, - hbmLoad, comctl32_color.clrBtnFace); - DeleteObject (hbmLoad); - break; - - case IDB_STD_LARGE_COLOR: - hbmLoad = LoadBitmapW (COMCTL32_hModule, - MAKEINTRESOURCEW(IDB_STD_LARGE)); - nIndex = ImageList_AddMasked (himlDef, - hbmLoad, comctl32_color.clrBtnFace); - DeleteObject (hbmLoad); - break; - - case IDB_VIEW_SMALL_COLOR: - hbmLoad = LoadBitmapW (COMCTL32_hModule, - MAKEINTRESOURCEW(IDB_VIEW_SMALL)); - nIndex = ImageList_AddMasked (himlDef, - hbmLoad, comctl32_color.clrBtnFace); - DeleteObject (hbmLoad); - break; - - case IDB_VIEW_LARGE_COLOR: - hbmLoad = LoadBitmapW (COMCTL32_hModule, - MAKEINTRESOURCEW(IDB_VIEW_LARGE)); - nIndex = ImageList_AddMasked (himlDef, - hbmLoad, comctl32_color.clrBtnFace); - DeleteObject (hbmLoad); - break; - - case IDB_HIST_SMALL_COLOR: - hbmLoad = LoadBitmapW (COMCTL32_hModule, - MAKEINTRESOURCEW(IDB_HIST_SMALL)); - nIndex = ImageList_AddMasked (himlDef, - hbmLoad, comctl32_color.clrBtnFace); - DeleteObject (hbmLoad); - break; - - case IDB_HIST_LARGE_COLOR: - hbmLoad = LoadBitmapW (COMCTL32_hModule, - MAKEINTRESOURCEW(IDB_HIST_LARGE)); - nIndex = ImageList_AddMasked (himlDef, - hbmLoad, comctl32_color.clrBtnFace); - DeleteObject (hbmLoad); - break; - - default: - nIndex = ImageList_GetImageCount (himlDef); - ERR ("invalid imagelist!\n"); - break; - } - } - else - { - hbmLoad = LoadBitmapW (lpAddBmp->hInst, (LPWSTR)lpAddBmp->nID); - nIndex = ImageList_AddMasked (himlDef, hbmLoad, comctl32_color.clrBtnFace); - DeleteObject (hbmLoad); - } - - TRACE("Number of bitmap infos: %d\n", infoPtr->nNumBitmapInfos); - - if (infoPtr->nNumBitmapInfos == 0) - { - infoPtr->bitmaps = Alloc(sizeof(TBITMAP_INFO)); - } - else - { - TBITMAP_INFO *oldBitmaps = infoPtr->bitmaps; - infoPtr->bitmaps = Alloc((infoPtr->nNumBitmapInfos + 1) * sizeof(TBITMAP_INFO)); - memcpy(&infoPtr->bitmaps[0], &oldBitmaps[0], infoPtr->nNumBitmapInfos); - } - - infoPtr->bitmaps[infoPtr->nNumBitmapInfos].nButtons = nButtons; - infoPtr->bitmaps[infoPtr->nNumBitmapInfos].hInst = lpAddBmp->hInst; - infoPtr->bitmaps[infoPtr->nNumBitmapInfos].nID = lpAddBmp->nID; - - infoPtr->nNumBitmapInfos++; - TRACE("Number of bitmap infos: %d\n", infoPtr->nNumBitmapInfos); - - if (nIndex != -1) - { - INT imagecount = ImageList_GetImageCount(himlDef); - - if (infoPtr->nNumBitmaps + nButtons != imagecount) - { - WARN("Desired images do not match received images : Previous image number %i Previous images in list %i added %i expecting total %i, Images in list %i\n", - infoPtr->nNumBitmaps, nCount, imagecount - nCount, - infoPtr->nNumBitmaps+nButtons,imagecount); - - infoPtr->nNumBitmaps = imagecount; - } - else - infoPtr->nNumBitmaps += nButtons; - } - - InvalidateRect(hwnd, NULL, TRUE); - - return nIndex; -} - - -static LRESULT -TOOLBAR_AddButtonsA (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - LPTBBUTTON lpTbb = (LPTBBUTTON)lParam; - INT nOldButtons, nNewButtons, nAddButtons, nCount; - - TRACE("adding %d buttons!\n", wParam); - - nAddButtons = (UINT)wParam; - nOldButtons = infoPtr->nNumButtons; - nNewButtons = nOldButtons + nAddButtons; - - if (infoPtr->nNumButtons == 0) { - infoPtr->buttons = - Alloc (sizeof(TBUTTON_INFO) * nNewButtons); - } - else { - TBUTTON_INFO *oldButtons = infoPtr->buttons; - infoPtr->buttons = - Alloc (sizeof(TBUTTON_INFO) * nNewButtons); - memcpy (&infoPtr->buttons[0], &oldButtons[0], - nOldButtons * sizeof(TBUTTON_INFO)); - Free (oldButtons); - } - - infoPtr->nNumButtons = nNewButtons; - - /* insert new button data */ - for (nCount = 0; nCount < nAddButtons; nCount++) { - TBUTTON_INFO *btnPtr = &infoPtr->buttons[nOldButtons+nCount]; - btnPtr->iBitmap = lpTbb[nCount].iBitmap; - btnPtr->idCommand = lpTbb[nCount].idCommand; - btnPtr->fsState = lpTbb[nCount].fsState; - btnPtr->fsStyle = lpTbb[nCount].fsStyle; - btnPtr->dwData = lpTbb[nCount].dwData; - if(HIWORD(lpTbb[nCount].iString) && lpTbb[nCount].iString != -1) - Str_SetPtrAtoW ((LPWSTR*)&btnPtr->iString, (LPSTR)lpTbb[nCount].iString ); - else - btnPtr->iString = lpTbb[nCount].iString; - btnPtr->bHot = FALSE; - - if ((infoPtr->hwndToolTip) && !(btnPtr->fsStyle & BTNS_SEP)) { - TTTOOLINFOW ti; - - ZeroMemory (&ti, sizeof(ti)); - ti.cbSize = sizeof(ti); - ti.hwnd = hwnd; - ti.uId = btnPtr->idCommand; - ti.hinst = 0; - ti.lpszText = LPSTR_TEXTCALLBACKW; - - SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, - 0, (LPARAM)&ti); - } - } - - TOOLBAR_CalcToolbar (hwnd); - - TOOLBAR_DumpToolbar (infoPtr, __LINE__); - - InvalidateRect(hwnd, NULL, TRUE); - - return TRUE; -} - - -static LRESULT -TOOLBAR_AddButtonsW (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - LPTBBUTTON lpTbb = (LPTBBUTTON)lParam; - INT nOldButtons, nNewButtons, nAddButtons, nCount; - - TRACE("adding %d buttons!\n", wParam); - - nAddButtons = (UINT)wParam; - nOldButtons = infoPtr->nNumButtons; - nNewButtons = nOldButtons + nAddButtons; - - if (infoPtr->nNumButtons == 0) { - infoPtr->buttons = - Alloc (sizeof(TBUTTON_INFO) * nNewButtons); - } - else { - TBUTTON_INFO *oldButtons = infoPtr->buttons; - infoPtr->buttons = - Alloc (sizeof(TBUTTON_INFO) * nNewButtons); - memcpy (&infoPtr->buttons[0], &oldButtons[0], - nOldButtons * sizeof(TBUTTON_INFO)); - Free (oldButtons); - } - - infoPtr->nNumButtons = nNewButtons; - - /* insert new button data */ - for (nCount = 0; nCount < nAddButtons; nCount++) { - TBUTTON_INFO *btnPtr = &infoPtr->buttons[nOldButtons+nCount]; - btnPtr->iBitmap = lpTbb[nCount].iBitmap; - btnPtr->idCommand = lpTbb[nCount].idCommand; - btnPtr->fsState = lpTbb[nCount].fsState; - btnPtr->fsStyle = lpTbb[nCount].fsStyle; - btnPtr->dwData = lpTbb[nCount].dwData; - if(HIWORD(lpTbb[nCount].iString) && lpTbb[nCount].iString != -1) - Str_SetPtrW ((LPWSTR*)&btnPtr->iString, (LPWSTR)lpTbb[nCount].iString ); - else - btnPtr->iString = lpTbb[nCount].iString; - btnPtr->bHot = FALSE; - - if ((infoPtr->hwndToolTip) && !(btnPtr->fsStyle & BTNS_SEP)) { - TTTOOLINFOW ti; - - ZeroMemory (&ti, sizeof(TTTOOLINFOW)); - ti.cbSize = sizeof (TTTOOLINFOW); - ti.hwnd = hwnd; - ti.uId = btnPtr->idCommand; - ti.hinst = 0; - ti.lpszText = LPSTR_TEXTCALLBACKW; - ti.lParam = lParam; - - SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, - 0, (LPARAM)&ti); - } - } - - TOOLBAR_CalcToolbar (hwnd); - - TOOLBAR_DumpToolbar (infoPtr, __LINE__); - - InvalidateRect(hwnd, NULL, TRUE); - - return TRUE; -} - - -static LRESULT -TOOLBAR_AddStringA (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - INT nIndex; - - if ((wParam) && (HIWORD(lParam) == 0)) { - char szString[256]; - INT len; - TRACE("adding string from resource!\n"); - - len = LoadStringA ((HINSTANCE)wParam, (UINT)lParam, szString, sizeof(szString)); - - TRACE("len=%d \"%s\"\n", len, szString); - nIndex = infoPtr->nNumStrings; - if (infoPtr->nNumStrings == 0) { - infoPtr->strings = - Alloc (sizeof(LPWSTR)); - } - else { - LPWSTR *oldStrings = infoPtr->strings; - infoPtr->strings = - Alloc (sizeof(LPWSTR) * (infoPtr->nNumStrings + 1)); - memcpy (&infoPtr->strings[0], &oldStrings[0], - sizeof(LPWSTR) * infoPtr->nNumStrings); - Free (oldStrings); - } - - /*Alloc zeros out the allocated memory*/ - Str_SetPtrAtoW (&infoPtr->strings[infoPtr->nNumStrings], szString ); - infoPtr->nNumStrings++; - } - else { - LPSTR p = (LPSTR)lParam; - INT len; - - if (p == NULL) - return -1; - TRACE("adding string(s) from array!\n"); - - nIndex = infoPtr->nNumStrings; - while (*p) { - len = strlen (p); - TRACE("len=%d \"%s\"\n", len, p); - - if (infoPtr->nNumStrings == 0) { - infoPtr->strings = - Alloc (sizeof(LPWSTR)); - } - else { - LPWSTR *oldStrings = infoPtr->strings; - infoPtr->strings = - Alloc (sizeof(LPWSTR) * (infoPtr->nNumStrings + 1)); - memcpy (&infoPtr->strings[0], &oldStrings[0], - sizeof(LPWSTR) * infoPtr->nNumStrings); - Free (oldStrings); - } - - Str_SetPtrAtoW (&infoPtr->strings[infoPtr->nNumStrings], p ); - infoPtr->nNumStrings++; - - p += (len+1); - } - } - - return nIndex; -} - - -static LRESULT -TOOLBAR_AddStringW (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ -#define MAX_RESOURCE_STRING_LENGTH 512 - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - INT nIndex; - - if ((wParam) && (HIWORD(lParam) == 0)) { - WCHAR szString[MAX_RESOURCE_STRING_LENGTH]; - INT len; - TRACE("adding string from resource!\n"); - - len = LoadStringW ((HINSTANCE)wParam, (UINT)lParam, - szString, MAX_RESOURCE_STRING_LENGTH); - - TRACE("len=%d %s\n", len, debugstr_w(szString)); - TRACE("First char: 0x%x\n", *szString); - if (szString[0] == L'|') - { - PWSTR p = szString + 1; - - nIndex = infoPtr->nNumStrings; - while (*p != L'|' && *p != L'\0') { - PWSTR np; - - if (infoPtr->nNumStrings == 0) { - infoPtr->strings = Alloc (sizeof(LPWSTR)); - } - else - { - LPWSTR *oldStrings = infoPtr->strings; - infoPtr->strings = Alloc(sizeof(LPWSTR) * (infoPtr->nNumStrings + 1)); - memcpy(&infoPtr->strings[0], &oldStrings[0], - sizeof(LPWSTR) * infoPtr->nNumStrings); - Free(oldStrings); - } - - np=strchrW (p, '|'); - if (np!=NULL) { - len = np - p; - np++; - } else { - len = strlenW(p); - np = p + len; - } - TRACE("len=%d %s\n", len, debugstr_w(p)); - infoPtr->strings[infoPtr->nNumStrings] = - Alloc (sizeof(WCHAR)*(len+1)); - lstrcpynW (infoPtr->strings[infoPtr->nNumStrings], p, len+1); - infoPtr->nNumStrings++; - - p = np; - } - } - else - { - nIndex = infoPtr->nNumStrings; - if (infoPtr->nNumStrings == 0) { - infoPtr->strings = - Alloc (sizeof(LPWSTR)); - } - else { - LPWSTR *oldStrings = infoPtr->strings; - infoPtr->strings = - Alloc (sizeof(LPWSTR) * (infoPtr->nNumStrings + 1)); - memcpy (&infoPtr->strings[0], &oldStrings[0], - sizeof(LPWSTR) * infoPtr->nNumStrings); - Free (oldStrings); - } - - Str_SetPtrW (&infoPtr->strings[infoPtr->nNumStrings], szString); - infoPtr->nNumStrings++; - } - } - else { - LPWSTR p = (LPWSTR)lParam; - INT len; - - if (p == NULL) - return -1; - TRACE("adding string(s) from array!\n"); - nIndex = infoPtr->nNumStrings; - while (*p) { - len = strlenW (p); - - TRACE("len=%d %s\n", len, debugstr_w(p)); - if (infoPtr->nNumStrings == 0) { - infoPtr->strings = - Alloc (sizeof(LPWSTR)); - } - else { - LPWSTR *oldStrings = infoPtr->strings; - infoPtr->strings = - Alloc (sizeof(LPWSTR) * (infoPtr->nNumStrings + 1)); - memcpy (&infoPtr->strings[0], &oldStrings[0], - sizeof(LPWSTR) * infoPtr->nNumStrings); - Free (oldStrings); - } - - Str_SetPtrW (&infoPtr->strings[infoPtr->nNumStrings], p); - infoPtr->nNumStrings++; - - p += (len+1); - } - } - - return nIndex; -} - - -static LRESULT -TOOLBAR_AutoSize (HWND hwnd) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - RECT parent_rect; - RECT window_rect; - HWND parent; - INT x, y; - INT cx, cy; - UINT uPosFlags = SWP_NOZORDER; - - TRACE("resize forced, style=%lx!\n", infoPtr->dwStyle); - - parent = GetParent (hwnd); - GetClientRect(parent, &parent_rect); - - x = parent_rect.left; - y = parent_rect.top; - - /* FIXME: we should be able to early out if nothing */ - /* has changed with nWidth != parent_rect width */ - - if (infoPtr->dwStyle & CCS_NORESIZE) { - uPosFlags |= (SWP_NOSIZE | SWP_NOMOVE); - cx = 0; - cy = 0; - TOOLBAR_CalcToolbar (hwnd); - } - else { - infoPtr->nWidth = parent_rect.right - parent_rect.left; - TOOLBAR_CalcToolbar (hwnd); - InvalidateRect( hwnd, NULL, TRUE ); - cy = infoPtr->nHeight; - cx = infoPtr->nWidth; - - if ((infoPtr->dwStyle & CCS_BOTTOM) == CCS_NOMOVEY) { - GetWindowRect(hwnd, &window_rect); - ScreenToClient(parent, (LPPOINT)&window_rect.left); - y = window_rect.top; - } - if ((infoPtr->dwStyle & CCS_BOTTOM) == CCS_BOTTOM) { - GetWindowRect(hwnd, &window_rect); - y = parent_rect.bottom - ( window_rect.bottom - window_rect.top); - } - } - - if (infoPtr->dwStyle & CCS_NOPARENTALIGN) - uPosFlags |= SWP_NOMOVE; - - if (!(infoPtr->dwStyle & CCS_NODIVIDER)) - cy += GetSystemMetrics(SM_CYEDGE); - - if (infoPtr->dwStyle & WS_BORDER) - { - x = y = 1; - cy += GetSystemMetrics(SM_CYEDGE); - cx += GetSystemMetrics(SM_CXEDGE); - } - - infoPtr->bAutoSize = TRUE; - SetWindowPos (hwnd, HWND_TOP, x, y, cx, cy, uPosFlags); - /* The following line makes sure that the infoPtr->bAutoSize is turned off - * after the setwindowpos calls */ - infoPtr->bAutoSize = FALSE; - - return 0; -} - - -static LRESULT -TOOLBAR_ButtonCount (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - return infoPtr->nNumButtons; -} - - -static LRESULT -TOOLBAR_ButtonStructSize (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - infoPtr->dwStructSize = (DWORD)wParam; - - return 0; -} - - -static LRESULT -TOOLBAR_ChangeBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - TBUTTON_INFO *btnPtr; - INT nIndex; - - TRACE("button %d, iBitmap now %d\n", wParam, LOWORD(lParam)); - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); - if (nIndex == -1) - return FALSE; - - btnPtr = &infoPtr->buttons[nIndex]; - btnPtr->iBitmap = LOWORD(lParam); - - /* we HAVE to erase the background, the new bitmap could be */ - /* transparent */ - InvalidateRect(hwnd, &btnPtr->rect, TRUE); - - return TRUE; -} - - -static LRESULT -TOOLBAR_CheckButton (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - TBUTTON_INFO *btnPtr; - INT nIndex; - INT nOldIndex = -1; - BOOL bChecked = FALSE; - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); - - TRACE("hwnd=%p, btn index=%d, lParam=0x%08lx\n", hwnd, nIndex, lParam); - - if (nIndex == -1) - return FALSE; - - btnPtr = &infoPtr->buttons[nIndex]; - - bChecked = (btnPtr->fsState & TBSTATE_CHECKED) ? TRUE : FALSE; - - if (LOWORD(lParam) == FALSE) - btnPtr->fsState &= ~TBSTATE_CHECKED; - else { - if (btnPtr->fsStyle & BTNS_GROUP) { - nOldIndex = - TOOLBAR_GetCheckedGroupButtonIndex (infoPtr, nIndex); - if (nOldIndex == nIndex) - return 0; - if (nOldIndex != -1) - infoPtr->buttons[nOldIndex].fsState &= ~TBSTATE_CHECKED; - } - btnPtr->fsState |= TBSTATE_CHECKED; - } - - if( bChecked != LOWORD(lParam) ) - { - if (nOldIndex != -1) - InvalidateRect(hwnd, &infoPtr->buttons[nOldIndex].rect, TRUE); - InvalidateRect(hwnd, &btnPtr->rect, TRUE); - } - - /* FIXME: Send a WM_NOTIFY?? */ - - return TRUE; -} - - -static LRESULT -TOOLBAR_CommandToIndex (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - return TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); -} - - -static LRESULT -TOOLBAR_Customize (HWND hwnd) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - CUSTDLG_INFO custInfo; - LRESULT ret; - LPCVOID template; - HRSRC hRes; - NMHDR nmhdr; - - custInfo.tbInfo = infoPtr; - custInfo.tbHwnd = hwnd; - - /* send TBN_BEGINADJUST notification */ - TOOLBAR_SendNotify (&nmhdr, infoPtr, TBN_BEGINADJUST); - - if (!(hRes = FindResourceW (COMCTL32_hModule, - MAKEINTRESOURCEW(IDD_TBCUSTOMIZE), - (LPWSTR)RT_DIALOG))) - return FALSE; - - if(!(template = (LPVOID)LoadResource (COMCTL32_hModule, hRes))) - return FALSE; - - ret = DialogBoxIndirectParamW ((HINSTANCE)GetWindowLongPtrW(hwnd, GWLP_HINSTANCE), - (LPDLGTEMPLATEW)template, - hwnd, - TOOLBAR_CustomizeDialogProc, - (LPARAM)&custInfo); - - /* send TBN_ENDADJUST notification */ - TOOLBAR_SendNotify (&nmhdr, infoPtr, TBN_ENDADJUST); - - return ret; -} - - -static LRESULT -TOOLBAR_DeleteButton (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - INT nIndex = (INT)wParam; - NMTOOLBARW nmtb; - TBUTTON_INFO *btnPtr = &infoPtr->buttons[nIndex]; - - if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons)) - return FALSE; - - memset(&nmtb, 0, sizeof(nmtb)); - nmtb.iItem = btnPtr->idCommand; - nmtb.tbButton.iBitmap = btnPtr->iBitmap; - nmtb.tbButton.idCommand = btnPtr->idCommand; - nmtb.tbButton.fsState = btnPtr->fsState; - nmtb.tbButton.fsStyle = btnPtr->fsStyle; - nmtb.tbButton.dwData = btnPtr->dwData; - nmtb.tbButton.iString = btnPtr->iString; - TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_DELETINGBUTTON); - - if ((infoPtr->hwndToolTip) && - !(btnPtr->fsStyle & BTNS_SEP)) { - TTTOOLINFOW ti; - - ZeroMemory (&ti, sizeof(ti)); - ti.cbSize = sizeof(ti); - ti.hwnd = hwnd; - ti.uId = infoPtr->buttons[nIndex].idCommand; - - SendMessageW (infoPtr->hwndToolTip, TTM_DELTOOLW, 0, (LPARAM)&ti); - } - - if (infoPtr->nNumButtons == 1) { - TRACE(" simple delete!\n"); - Free (infoPtr->buttons); - infoPtr->buttons = NULL; - infoPtr->nNumButtons = 0; - } - else { - TBUTTON_INFO *oldButtons = infoPtr->buttons; - TRACE("complex delete! [nIndex=%d]\n", nIndex); - - infoPtr->nNumButtons--; - infoPtr->buttons = Alloc (sizeof (TBUTTON_INFO) * infoPtr->nNumButtons); - if (nIndex > 0) { - memcpy (&infoPtr->buttons[0], &oldButtons[0], - nIndex * sizeof(TBUTTON_INFO)); - } - - if (nIndex < infoPtr->nNumButtons) { - memcpy (&infoPtr->buttons[nIndex], &oldButtons[nIndex+1], - (infoPtr->nNumButtons - nIndex) * sizeof(TBUTTON_INFO)); - } - - Free (oldButtons); - } - - TOOLBAR_CalcToolbar (hwnd); - - InvalidateRect (hwnd, NULL, TRUE); - - return TRUE; -} - - -static LRESULT -TOOLBAR_EnableButton (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - TBUTTON_INFO *btnPtr; - INT nIndex; - DWORD bState; - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); - - TRACE("hwnd=%p, btn index=%d, lParam=0x%08lx\n", hwnd, wParam, lParam); - - if (nIndex == -1) - return FALSE; - - btnPtr = &infoPtr->buttons[nIndex]; - - bState = btnPtr->fsState & TBSTATE_ENABLED; - - /* update the toolbar button state */ - if(LOWORD(lParam) == FALSE) { - btnPtr->fsState &= ~(TBSTATE_ENABLED | TBSTATE_PRESSED); - } else { - btnPtr->fsState |= TBSTATE_ENABLED; - } - - /* redraw the button only if the state of the button changed */ - if(bState != (btnPtr->fsState & TBSTATE_ENABLED)) - InvalidateRect(hwnd, &btnPtr->rect, TRUE); - - return TRUE; -} - - -static inline LRESULT -TOOLBAR_GetAnchorHighlight (HWND hwnd) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - return infoPtr->bAnchor; -} - - -static LRESULT -TOOLBAR_GetBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - INT nIndex; - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); - if (nIndex == -1) - return -1; - - return infoPtr->buttons[nIndex].iBitmap; -} - - -static inline LRESULT -TOOLBAR_GetBitmapFlags (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - return (GetDeviceCaps (0, LOGPIXELSX) >= 120) ? TBBF_LARGE : 0; -} - - -static LRESULT -TOOLBAR_GetButton (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - LPTBBUTTON lpTbb = (LPTBBUTTON)lParam; - INT nIndex = (INT)wParam; - TBUTTON_INFO *btnPtr; - - if (lpTbb == NULL) - return FALSE; - - if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons)) - return FALSE; - - btnPtr = &infoPtr->buttons[nIndex]; - lpTbb->iBitmap = btnPtr->iBitmap; - lpTbb->idCommand = btnPtr->idCommand; - lpTbb->fsState = btnPtr->fsState; - lpTbb->fsStyle = btnPtr->fsStyle; - lpTbb->bReserved[0] = 0; - lpTbb->bReserved[1] = 0; - lpTbb->dwData = btnPtr->dwData; - lpTbb->iString = btnPtr->iString; - - return TRUE; -} - - -static LRESULT -TOOLBAR_GetButtonInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - LPTBBUTTONINFOA lpTbInfo = (LPTBBUTTONINFOA)lParam; - TBUTTON_INFO *btnPtr; - INT nIndex; - - if (lpTbInfo == NULL) - return -1; - if (lpTbInfo->cbSize < sizeof(TBBUTTONINFOA)) - return -1; - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, - lpTbInfo->dwMask & 0x80000000); - if (nIndex == -1) - return -1; - - if (!(btnPtr = &infoPtr->buttons[nIndex])) return -1; - - if (lpTbInfo->dwMask & TBIF_COMMAND) - lpTbInfo->idCommand = btnPtr->idCommand; - if (lpTbInfo->dwMask & TBIF_IMAGE) - lpTbInfo->iImage = btnPtr->iBitmap; - if (lpTbInfo->dwMask & TBIF_LPARAM) - lpTbInfo->lParam = btnPtr->dwData; - if (lpTbInfo->dwMask & TBIF_SIZE) - lpTbInfo->cx = (WORD)(btnPtr->rect.right - btnPtr->rect.left); - if (lpTbInfo->dwMask & TBIF_STATE) - lpTbInfo->fsState = btnPtr->fsState; - if (lpTbInfo->dwMask & TBIF_STYLE) - lpTbInfo->fsStyle = btnPtr->fsStyle; - if (lpTbInfo->dwMask & TBIF_TEXT) { - /* TB_GETBUTTONINFO doesn't retrieve text from the string list, so we - can't use TOOLBAR_GetText here */ - LPWSTR lpText; - if (HIWORD(btnPtr->iString) && (btnPtr->iString != -1)) { - lpText = (LPWSTR)btnPtr->iString; - Str_GetPtrWtoA (lpText, lpTbInfo->pszText,lpTbInfo->cchText); - } else - lpTbInfo->pszText[0] = '\0'; - } - return nIndex; -} - - -static LRESULT -TOOLBAR_GetButtonInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - LPTBBUTTONINFOW lpTbInfo = (LPTBBUTTONINFOW)lParam; - TBUTTON_INFO *btnPtr; - INT nIndex; - - if (lpTbInfo == NULL) - return -1; - if (lpTbInfo->cbSize < sizeof(TBBUTTONINFOW)) - return -1; - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, - lpTbInfo->dwMask & 0x80000000); - if (nIndex == -1) - return -1; - - btnPtr = &infoPtr->buttons[nIndex]; - - if(!btnPtr) - return -1; - - if (lpTbInfo->dwMask & TBIF_COMMAND) - lpTbInfo->idCommand = btnPtr->idCommand; - if (lpTbInfo->dwMask & TBIF_IMAGE) - lpTbInfo->iImage = btnPtr->iBitmap; - if (lpTbInfo->dwMask & TBIF_LPARAM) - lpTbInfo->lParam = btnPtr->dwData; - if (lpTbInfo->dwMask & TBIF_SIZE) - lpTbInfo->cx = (WORD)(btnPtr->rect.right - btnPtr->rect.left); - if (lpTbInfo->dwMask & TBIF_STATE) - lpTbInfo->fsState = btnPtr->fsState; - if (lpTbInfo->dwMask & TBIF_STYLE) - lpTbInfo->fsStyle = btnPtr->fsStyle; - if (lpTbInfo->dwMask & TBIF_TEXT) { - /* TB_GETBUTTONINFO doesn't retrieve text from the string list, so we - can't use TOOLBAR_GetText here */ - LPWSTR lpText; - if (HIWORD(btnPtr->iString) && (btnPtr->iString != -1)) { - lpText = (LPWSTR)btnPtr->iString; - Str_GetPtrW (lpText,lpTbInfo->pszText,lpTbInfo->cchText); - } else - lpTbInfo->pszText[0] = '\0'; - } - - return nIndex; -} - - -static LRESULT -TOOLBAR_GetButtonSize (HWND hwnd) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - if (infoPtr->nNumButtons > 0) - return MAKELONG((WORD)infoPtr->nButtonWidth, - (WORD)infoPtr->nButtonHeight); - else - return MAKELONG(23,22); -} - - -static LRESULT -TOOLBAR_GetButtonTextA (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - INT nIndex; - LPWSTR lpText; - - if (lParam == 0) - return -1; - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); - if (nIndex == -1) - return -1; - - lpText = TOOLBAR_GetText(infoPtr,&infoPtr->buttons[nIndex]); - - return WideCharToMultiByte( CP_ACP, 0, lpText, -1, - (LPSTR)lParam, 0x7fffffff, NULL, NULL ) - 1; -} - - -static LRESULT -TOOLBAR_GetButtonTextW (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - INT nIndex; - LPWSTR lpText; - LRESULT ret = 0; - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); - if (nIndex == -1) - return -1; - - lpText = TOOLBAR_GetText(infoPtr,&infoPtr->buttons[nIndex]); - - if (lpText) - { - ret = strlenW (lpText); - - if (lParam) - strcpyW ((LPWSTR)lParam, lpText); - } - - return ret; -} - - -static LRESULT -TOOLBAR_GetDisabledImageList (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TRACE("hwnd=%p, wParam=%d, lParam=0x%lx\n", hwnd, wParam, lParam); - /* UNDOCUMENTED: wParam is actually the ID of the image list to return */ - return (LRESULT)GETDISIMAGELIST(TOOLBAR_GetInfoPtr (hwnd), wParam); -} - - -inline static LRESULT -TOOLBAR_GetExtendedStyle (HWND hwnd) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - TRACE("\n"); - - return infoPtr->dwExStyle; -} - - -static LRESULT -TOOLBAR_GetHotImageList (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TRACE("hwnd=%p, wParam=%d, lParam=0x%lx\n", hwnd, wParam, lParam); - /* UNDOCUMENTED: wParam is actually the ID of the image list to return */ - return (LRESULT)GETHOTIMAGELIST(TOOLBAR_GetInfoPtr (hwnd), wParam); -} - - -static LRESULT -TOOLBAR_GetHotItem (HWND hwnd) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - if (!(infoPtr->dwStyle & TBSTYLE_FLAT)) - return -1; - - if (infoPtr->nHotItem < 0) - return -1; - - return (LRESULT)infoPtr->nHotItem; -} - - -static LRESULT -TOOLBAR_GetDefImageList (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TRACE("hwnd=%p, wParam=%d, lParam=0x%lx\n", hwnd, wParam, lParam); - /* UNDOCUMENTED: wParam is actually the ID of the image list to return */ - return (LRESULT) GETDEFIMAGELIST(TOOLBAR_GetInfoPtr(hwnd), wParam); -} - - -static LRESULT -TOOLBAR_GetInsertMark (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - TBINSERTMARK *lptbim = (TBINSERTMARK*)lParam; - - TRACE("hwnd = %p, lptbim = %p\n", hwnd, lptbim); - - *lptbim = infoPtr->tbim; - - return 0; -} - - -static LRESULT -TOOLBAR_GetInsertMarkColor (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - TRACE("hwnd = %p\n", hwnd); - - return (LRESULT)infoPtr->clrInsertMark; -} - - -static LRESULT -TOOLBAR_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - TBUTTON_INFO *btnPtr; - LPRECT lpRect; - INT nIndex; - - nIndex = (INT)wParam; - btnPtr = &infoPtr->buttons[nIndex]; - if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons)) - return FALSE; - lpRect = (LPRECT)lParam; - if (lpRect == NULL) - return FALSE; - if (btnPtr->fsState & TBSTATE_HIDDEN) - return FALSE; - - lpRect->left = btnPtr->rect.left; - lpRect->right = btnPtr->rect.right; - lpRect->bottom = btnPtr->rect.bottom; - lpRect->top = btnPtr->rect.top; - - return TRUE; -} - - -static LRESULT -TOOLBAR_GetMaxSize (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - LPSIZE lpSize = (LPSIZE)lParam; - - if (lpSize == NULL) - return FALSE; - - lpSize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left; - lpSize->cy = infoPtr->rcBound.bottom - infoPtr->rcBound.top; - - TRACE("maximum size %ld x %ld\n", - infoPtr->rcBound.right - infoPtr->rcBound.left, - infoPtr->rcBound.bottom - infoPtr->rcBound.top); - - return TRUE; -} - - -/* << TOOLBAR_GetObject >> */ - - -static LRESULT -TOOLBAR_GetPadding (HWND hwnd) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - DWORD oldPad; - - oldPad = MAKELONG(infoPtr->szPadding.cx, infoPtr->szPadding.cy); - return (LRESULT) oldPad; -} - - -static LRESULT -TOOLBAR_GetRect (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - TBUTTON_INFO *btnPtr; - LPRECT lpRect; - INT nIndex; - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); - btnPtr = &infoPtr->buttons[nIndex]; - if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons)) - return FALSE; - lpRect = (LPRECT)lParam; - if (lpRect == NULL) - return FALSE; - - lpRect->left = btnPtr->rect.left; - lpRect->right = btnPtr->rect.right; - lpRect->bottom = btnPtr->rect.bottom; - lpRect->top = btnPtr->rect.top; - - return TRUE; -} - - -static LRESULT -TOOLBAR_GetRows (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - if (infoPtr->dwStyle & TBSTYLE_WRAPABLE) - return infoPtr->nRows; - else - return 1; -} - - -static LRESULT -TOOLBAR_GetState (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - INT nIndex; - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); - if (nIndex == -1) - return -1; - - return infoPtr->buttons[nIndex].fsState; -} - - -static LRESULT -TOOLBAR_GetStyle (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - return GetWindowLongW(hwnd, GWL_STYLE); -} - - -static LRESULT -TOOLBAR_GetTextRows (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - return infoPtr->nMaxTextRows; -} - - -static LRESULT -TOOLBAR_GetToolTips (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - return (LRESULT)infoPtr->hwndToolTip; -} - - -static LRESULT -TOOLBAR_GetUnicodeFormat (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - TRACE("%s hwnd=%p\n", - infoPtr->bUnicode ? "TRUE" : "FALSE", hwnd); - - return infoPtr->bUnicode; -} - - -inline static LRESULT -TOOLBAR_GetVersion (HWND hwnd) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - return infoPtr->iVersion; -} - - -static LRESULT -TOOLBAR_HideButton (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - TBUTTON_INFO *btnPtr; - INT nIndex; - - TRACE("\n"); - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); - if (nIndex == -1) - return FALSE; - - btnPtr = &infoPtr->buttons[nIndex]; - if (LOWORD(lParam) == FALSE) - btnPtr->fsState &= ~TBSTATE_HIDDEN; - else - btnPtr->fsState |= TBSTATE_HIDDEN; - - TOOLBAR_CalcToolbar (hwnd); - - InvalidateRect (hwnd, NULL, TRUE); - - return TRUE; -} - - -inline static LRESULT -TOOLBAR_HitTest (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - return TOOLBAR_InternalHitTest (hwnd, (LPPOINT)lParam); -} - - -static LRESULT -TOOLBAR_Indeterminate (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - TBUTTON_INFO *btnPtr; - INT nIndex; - DWORD oldState; - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); - if (nIndex == -1) - return FALSE; - - btnPtr = &infoPtr->buttons[nIndex]; - oldState = btnPtr->fsState; - if (LOWORD(lParam) == FALSE) - btnPtr->fsState &= ~TBSTATE_INDETERMINATE; - else - btnPtr->fsState |= TBSTATE_INDETERMINATE; - - if(oldState != btnPtr->fsState) - InvalidateRect(hwnd, &btnPtr->rect, TRUE); - - return TRUE; -} - - -static LRESULT -TOOLBAR_InsertButtonA (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - LPTBBUTTON lpTbb = (LPTBBUTTON)lParam; - INT nIndex = (INT)wParam; - TBUTTON_INFO *oldButtons; - - if (lpTbb == NULL) - return FALSE; - - TOOLBAR_DumpButton(infoPtr, (TBUTTON_INFO *)lpTbb, nIndex, FALSE); - - if (nIndex == -1) { - /* EPP: this seems to be an undocumented call (from my IE4) - * I assume in that case that: - * - lpTbb->iString is a string pointer (not a string index in strings[] table - * - index of insertion is at the end of existing buttons - * I only see this happen with nIndex == -1, but it could have a special - * meaning (like -nIndex (or ~nIndex) to get the real position of insertion). - */ - nIndex = infoPtr->nNumButtons; - - } else if (nIndex < 0) - return FALSE; - - /* If the string passed is not an index, assume address of string - and do our own AddString */ - if ((HIWORD(lpTbb->iString) != 0) && (lpTbb->iString != -1)) { - LPSTR ptr; - INT len; - - TRACE("string %s passed instead of index, adding string\n", - debugstr_a((LPSTR)lpTbb->iString)); - len = strlen((LPSTR)lpTbb->iString) + 2; - ptr = Alloc(len); - strcpy(ptr, (LPSTR)lpTbb->iString); - ptr[len - 1] = 0; /* ended by two '\0' */ - lpTbb->iString = TOOLBAR_AddStringA(hwnd, 0, (LPARAM)ptr); - Free(ptr); - } - - TRACE("inserting button index=%d\n", nIndex); - if (nIndex > infoPtr->nNumButtons) { - nIndex = infoPtr->nNumButtons; - TRACE("adjust index=%d\n", nIndex); - } - - oldButtons = infoPtr->buttons; - infoPtr->nNumButtons++; - infoPtr->buttons = Alloc (sizeof (TBUTTON_INFO) * infoPtr->nNumButtons); - /* pre insert copy */ - if (nIndex > 0) { - memcpy (&infoPtr->buttons[0], &oldButtons[0], - nIndex * sizeof(TBUTTON_INFO)); - } - - /* insert new button */ - infoPtr->buttons[nIndex].iBitmap = lpTbb->iBitmap; - infoPtr->buttons[nIndex].idCommand = lpTbb->idCommand; - infoPtr->buttons[nIndex].fsState = lpTbb->fsState; - infoPtr->buttons[nIndex].fsStyle = lpTbb->fsStyle; - infoPtr->buttons[nIndex].dwData = lpTbb->dwData; - /* if passed string and not index, then add string */ - if(HIWORD(lpTbb->iString) && lpTbb->iString!=-1) { - Str_SetPtrAtoW ((LPWSTR *)&infoPtr->buttons[nIndex].iString, (LPCSTR )lpTbb->iString); - } - else - infoPtr->buttons[nIndex].iString = lpTbb->iString; - - if ((infoPtr->hwndToolTip) && !(lpTbb->fsStyle & BTNS_SEP)) { - TTTOOLINFOW ti; - - ZeroMemory (&ti, sizeof(ti)); - ti.cbSize = sizeof (ti); - ti.hwnd = hwnd; - ti.uId = lpTbb->idCommand; - ti.hinst = 0; - ti.lpszText = LPSTR_TEXTCALLBACKW; - - SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, - 0, (LPARAM)&ti); - } - - /* post insert copy */ - if (nIndex < infoPtr->nNumButtons - 1) { - memcpy (&infoPtr->buttons[nIndex+1], &oldButtons[nIndex], - (infoPtr->nNumButtons - nIndex - 1) * sizeof(TBUTTON_INFO)); - } - - Free (oldButtons); - - TOOLBAR_CalcToolbar (hwnd); - - InvalidateRect (hwnd, NULL, TRUE); - - return TRUE; -} - - -static LRESULT -TOOLBAR_InsertButtonW (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - LPTBBUTTON lpTbb = (LPTBBUTTON)lParam; - INT nIndex = (INT)wParam; - TBUTTON_INFO *oldButtons; - - if (lpTbb == NULL) - return FALSE; - - TOOLBAR_DumpButton(infoPtr, (TBUTTON_INFO *)lpTbb, nIndex, FALSE); - - if (nIndex == -1) { - /* EPP: this seems to be an undocumented call (from my IE4) - * I assume in that case that: - * - lpTbb->iString is a string pointer (not a string index in strings[] table - * - index of insertion is at the end of existing buttons - * I only see this happen with nIndex == -1, but it could have a special - * meaning (like -nIndex (or ~nIndex) to get the real position of insertion). - */ - nIndex = infoPtr->nNumButtons; - - } else if (nIndex < 0) - return FALSE; - - /* If the string passed is not an index, assume address of string - and do our own AddString */ - if ((HIWORD(lpTbb->iString) != 0) && (lpTbb->iString != -1)) { - LPWSTR ptr; - INT len; - - TRACE("string %s passed instead of index, adding string\n", - debugstr_w((LPWSTR)lpTbb->iString)); - len = strlenW((LPWSTR)lpTbb->iString) + 2; - ptr = Alloc(len*sizeof(WCHAR)); - strcpyW(ptr, (LPWSTR)lpTbb->iString); - ptr[len - 1] = 0; /* ended by two '\0' */ - lpTbb->iString = TOOLBAR_AddStringW(hwnd, 0, (LPARAM)ptr); - Free(ptr); - } - - TRACE("inserting button index=%d\n", nIndex); - if (nIndex > infoPtr->nNumButtons) { - nIndex = infoPtr->nNumButtons; - TRACE("adjust index=%d\n", nIndex); - } - - oldButtons = infoPtr->buttons; - infoPtr->nNumButtons++; - infoPtr->buttons = Alloc (sizeof (TBUTTON_INFO) * infoPtr->nNumButtons); - /* pre insert copy */ - if (nIndex > 0) { - memcpy (&infoPtr->buttons[0], &oldButtons[0], - nIndex * sizeof(TBUTTON_INFO)); - } - - /* insert new button */ - infoPtr->buttons[nIndex].iBitmap = lpTbb->iBitmap; - infoPtr->buttons[nIndex].idCommand = lpTbb->idCommand; - infoPtr->buttons[nIndex].fsState = lpTbb->fsState; - infoPtr->buttons[nIndex].fsStyle = lpTbb->fsStyle; - infoPtr->buttons[nIndex].dwData = lpTbb->dwData; - /* if passed string and not index, then add string */ - if(HIWORD(lpTbb->iString) && lpTbb->iString!=-1) { - Str_SetPtrW ((LPWSTR *)&infoPtr->buttons[nIndex].iString, (LPWSTR)lpTbb->iString); - } - else - infoPtr->buttons[nIndex].iString = lpTbb->iString; - - if ((infoPtr->hwndToolTip) && !(lpTbb->fsStyle & BTNS_SEP)) { - TTTOOLINFOW ti; - - ZeroMemory (&ti, sizeof(TTTOOLINFOW)); - ti.cbSize = sizeof (TTTOOLINFOW); - ti.hwnd = hwnd; - ti.uId = lpTbb->idCommand; - ti.hinst = 0; - ti.lpszText = LPSTR_TEXTCALLBACKW; - - SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, - 0, (LPARAM)&ti); - } - - /* post insert copy */ - if (nIndex < infoPtr->nNumButtons - 1) { - memcpy (&infoPtr->buttons[nIndex+1], &oldButtons[nIndex], - (infoPtr->nNumButtons - nIndex - 1) * sizeof(TBUTTON_INFO)); - } - - Free (oldButtons); - - TOOLBAR_CalcToolbar (hwnd); - - InvalidateRect (hwnd, NULL, TRUE); - - return TRUE; -} - - -/* << TOOLBAR_InsertMarkHitTest >> */ - - -static LRESULT -TOOLBAR_IsButtonChecked (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - INT nIndex; - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); - if (nIndex == -1) - return FALSE; - - return (infoPtr->buttons[nIndex].fsState & TBSTATE_CHECKED); -} - - -static LRESULT -TOOLBAR_IsButtonEnabled (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - INT nIndex; - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); - if (nIndex == -1) - return FALSE; - - return (infoPtr->buttons[nIndex].fsState & TBSTATE_ENABLED); -} - - -static LRESULT -TOOLBAR_IsButtonHidden (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - INT nIndex; - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); - if (nIndex == -1) - return TRUE; - - return (infoPtr->buttons[nIndex].fsState & TBSTATE_HIDDEN); -} - - -static LRESULT -TOOLBAR_IsButtonHighlighted (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - INT nIndex; - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); - if (nIndex == -1) - return FALSE; - - return (infoPtr->buttons[nIndex].fsState & TBSTATE_MARKED); -} - - -static LRESULT -TOOLBAR_IsButtonIndeterminate (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - INT nIndex; - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); - if (nIndex == -1) - return FALSE; - - return (infoPtr->buttons[nIndex].fsState & TBSTATE_INDETERMINATE); -} - - -static LRESULT -TOOLBAR_IsButtonPressed (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - INT nIndex; - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); - if (nIndex == -1) - return FALSE; - - return (infoPtr->buttons[nIndex].fsState & TBSTATE_PRESSED); -} - - -static LRESULT -TOOLBAR_LoadImages (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TBADDBITMAP tbab; - tbab.hInst = (HINSTANCE)lParam; - tbab.nID = (UINT_PTR)wParam; - - TRACE("hwnd = %p, hInst = %p, nID = %u\n", hwnd, tbab.hInst, tbab.nID); - - return TOOLBAR_AddBitmap(hwnd, 0, (LPARAM)&tbab); -} - - -static LRESULT -TOOLBAR_MapAccelerator (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - WCHAR wAccel = (WCHAR)wParam; - UINT* pIDButton = (UINT*)lParam; - WCHAR wszAccel[] = {'&',wAccel,0}; - int i; - - TRACE("hwnd = %p, wAccel = %x(%s), pIDButton = %p\n", - hwnd, wAccel, debugstr_wn(&wAccel,1), pIDButton); - - for (i = 0; i < infoPtr->nNumButtons; i++) - { - TBUTTON_INFO *btnPtr = infoPtr->buttons+i; - if (!(btnPtr->fsStyle & BTNS_NOPREFIX) && - !(btnPtr->fsState & TBSTATE_HIDDEN)) - { - int iLen = strlenW(wszAccel); - LPCWSTR lpszStr = TOOLBAR_GetText(infoPtr, btnPtr); - - if (!lpszStr) - continue; - - while (*lpszStr) - { - if ((lpszStr[0] == '&') && (lpszStr[1] == '&')) - { - lpszStr += 2; - continue; - } - if (!strncmpiW(lpszStr, wszAccel, iLen)) - { - *pIDButton = btnPtr->idCommand; - return TRUE; - } - lpszStr++; - } - } - } - return FALSE; -} - - -static LRESULT -TOOLBAR_MarkButton (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - INT nIndex; - DWORD oldState; - TBUTTON_INFO *btnPtr; - - TRACE("hwnd = %p, wParam = %d, lParam = 0x%08lx\n", hwnd, wParam, lParam); - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); - if (nIndex == -1) - return FALSE; - - btnPtr = &infoPtr->buttons[nIndex]; - oldState = btnPtr->fsState; - - if (LOWORD(lParam)) - btnPtr->fsState |= TBSTATE_MARKED; - else - btnPtr->fsState &= ~TBSTATE_MARKED; - - if(oldState != btnPtr->fsState) - InvalidateRect(hwnd, &btnPtr->rect, TRUE); - - return TRUE; -} - - -/* fixes up an index of a button affected by a move */ -inline static void TOOLBAR_MoveFixupIndex(INT* pIndex, INT nIndex, INT nMoveIndex, BOOL bMoveUp) -{ - if (bMoveUp) - { - if (*pIndex > nIndex && *pIndex <= nMoveIndex) - (*pIndex)--; - else if (*pIndex == nIndex) - *pIndex = nMoveIndex; - } - else - { - if (*pIndex >= nMoveIndex && *pIndex < nIndex) - (*pIndex)++; - else if (*pIndex == nIndex) - *pIndex = nMoveIndex; - } -} - - -static LRESULT -TOOLBAR_MoveButton (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - INT nIndex; - INT nCount; - INT nMoveIndex = (INT)lParam; - TBUTTON_INFO button; - - TRACE("hwnd=%p, wParam=%d, lParam=%ld\n", hwnd, wParam, lParam); - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, TRUE); - if ((nIndex == -1) || (nMoveIndex < 0)) - return FALSE; - - if (nMoveIndex > infoPtr->nNumButtons - 1) - nMoveIndex = infoPtr->nNumButtons - 1; - - button = infoPtr->buttons[nIndex]; - - /* move button right */ - if (nIndex < nMoveIndex) - { - nCount = nMoveIndex - nIndex; - memmove(&infoPtr->buttons[nIndex], &infoPtr->buttons[nIndex+1], nCount*sizeof(TBUTTON_INFO)); - infoPtr->buttons[nMoveIndex] = button; - - TOOLBAR_MoveFixupIndex(&infoPtr->nButtonDown, nIndex, nMoveIndex, TRUE); - TOOLBAR_MoveFixupIndex(&infoPtr->nButtonDrag, nIndex, nMoveIndex, TRUE); - TOOLBAR_MoveFixupIndex(&infoPtr->nOldHit, nIndex, nMoveIndex, TRUE); - TOOLBAR_MoveFixupIndex(&infoPtr->nHotItem, nIndex, nMoveIndex, TRUE); - } - else if (nIndex > nMoveIndex) /* move button left */ - { - nCount = nIndex - nMoveIndex; - memmove(&infoPtr->buttons[nMoveIndex+1], &infoPtr->buttons[nMoveIndex], nCount*sizeof(TBUTTON_INFO)); - infoPtr->buttons[nMoveIndex] = button; - - TOOLBAR_MoveFixupIndex(&infoPtr->nButtonDown, nIndex, nMoveIndex, FALSE); - TOOLBAR_MoveFixupIndex(&infoPtr->nButtonDrag, nIndex, nMoveIndex, FALSE); - TOOLBAR_MoveFixupIndex(&infoPtr->nOldHit, nIndex, nMoveIndex, FALSE); - TOOLBAR_MoveFixupIndex(&infoPtr->nHotItem, nIndex, nMoveIndex, FALSE); - } - - TOOLBAR_CalcToolbar(hwnd); - InvalidateRect(hwnd, NULL, TRUE); - - return TRUE; -} - - -static LRESULT -TOOLBAR_PressButton (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - TBUTTON_INFO *btnPtr; - INT nIndex; - DWORD oldState; - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); - if (nIndex == -1) - return FALSE; - - btnPtr = &infoPtr->buttons[nIndex]; - oldState = btnPtr->fsState; - if (LOWORD(lParam) == FALSE) - btnPtr->fsState &= ~TBSTATE_PRESSED; - else - btnPtr->fsState |= TBSTATE_PRESSED; - - if(oldState != btnPtr->fsState) - InvalidateRect(hwnd, &btnPtr->rect, TRUE); - - return TRUE; -} - -/* FIXME: there might still be some confusion her between number of buttons - * and number of bitmaps */ -static LRESULT -TOOLBAR_ReplaceBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - LPTBREPLACEBITMAP lpReplace = (LPTBREPLACEBITMAP) lParam; - HBITMAP hBitmap; - int i = 0, nOldButtons = 0, pos = 0; - int nOldBitmaps, nNewBitmaps = 0; - HIMAGELIST himlDef = 0; - - TRACE("hInstOld %p nIDOld %x hInstNew %p nIDNew %x nButtons %x\n", - lpReplace->hInstOld, lpReplace->nIDOld, lpReplace->hInstNew, lpReplace->nIDNew, - lpReplace->nButtons); - - if (lpReplace->hInstOld == HINST_COMMCTRL) - { - FIXME("changing standard bitmaps not implemented\n"); - return FALSE; - } - else if (lpReplace->hInstOld != 0) - { - FIXME("resources not in the current module not implemented\n"); - return FALSE; - } - else - { - hBitmap = (HBITMAP) lpReplace->nIDNew; - } - - TRACE("To be replaced hInstOld %p nIDOld %x\n", lpReplace->hInstOld, lpReplace->nIDOld); - for (i = 0; i < infoPtr->nNumBitmapInfos; i++) { - TBITMAP_INFO *tbi = &infoPtr->bitmaps[i]; - TRACE("tbimapinfo %d hInstOld %p nIDOld %x\n", i, tbi->hInst, tbi->nID); - if (tbi->hInst == lpReplace->hInstOld && tbi->nID == lpReplace->nIDOld) - { - TRACE("Found: nButtons %d hInst %p nID %x\n", tbi->nButtons, tbi->hInst, tbi->nID); - nOldButtons = tbi->nButtons; - tbi->nButtons = lpReplace->nButtons; - tbi->hInst = lpReplace->hInstNew; - tbi->nID = lpReplace->nIDNew; - TRACE("tbimapinfo changed %d hInstOld %p nIDOld %x\n", i, tbi->hInst, tbi->nID); - break; - } - pos += tbi->nButtons; - } - - if (nOldButtons == 0) - { - WARN("No hinst/bitmap found! hInst %p nID %x\n", lpReplace->hInstOld, lpReplace->nIDOld); - return FALSE; - } - - himlDef = GETDEFIMAGELIST(infoPtr, 0); /* fixme: correct? */ - nOldBitmaps = ImageList_GetImageCount(himlDef); - - /* ImageList_Replace(GETDEFIMAGELIST(), pos, hBitmap, NULL); */ - - for (i = pos + nOldBitmaps - 1; i >= pos; i--) - ImageList_Remove(himlDef, i); - - if (hBitmap) - { - BITMAP bmp; - HBITMAP hOldBitmapBitmap, hOldBitmapLoad, hbmLoad; - HDC hdcImage, hdcBitmap; - - /* copy the bitmap before adding it so that the user's bitmap - * doesn't get modified. - */ - GetObjectW (hBitmap, sizeof(BITMAP), (LPVOID)&bmp); - - hdcImage = CreateCompatibleDC(0); - hdcBitmap = CreateCompatibleDC(0); - - /* create new bitmap */ - hbmLoad = CreateBitmap (bmp.bmWidth, bmp.bmHeight, bmp.bmPlanes, bmp.bmBitsPixel, NULL); - hOldBitmapBitmap = SelectObject(hdcBitmap, hBitmap); - hOldBitmapLoad = SelectObject(hdcImage, hbmLoad); - - /* Copy the user's image */ - BitBlt (hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, - hdcBitmap, 0, 0, SRCCOPY); - - SelectObject (hdcImage, hOldBitmapLoad); - SelectObject (hdcBitmap, hOldBitmapBitmap); - DeleteDC (hdcImage); - DeleteDC (hdcBitmap); - - ImageList_AddMasked (himlDef, hbmLoad, comctl32_color.clrBtnFace); - nNewBitmaps = ImageList_GetImageCount(himlDef); - DeleteObject (hbmLoad); - } - - infoPtr->nNumBitmaps = infoPtr->nNumBitmaps - nOldBitmaps + nNewBitmaps; - - TRACE(" pos %d %d old bitmaps replaced by %d new ones.\n", - pos, nOldBitmaps, nNewBitmaps); - - InvalidateRect(hwnd, NULL, TRUE); - - return TRUE; -} - - -/* helper for TOOLBAR_SaveRestoreW */ -static BOOL -TOOLBAR_Save(TOOLBAR_INFO *infoPtr, LPTBSAVEPARAMSW lpSave) -{ - FIXME("save to %s %s\n", debugstr_w(lpSave->pszSubKey), - debugstr_w(lpSave->pszValueName)); - - return FALSE; -} - - -/* helper for TOOLBAR_Restore */ -static void -TOOLBAR_DeleteAllButtons(TOOLBAR_INFO *infoPtr) -{ - INT i; - TTTOOLINFOW ti; - - ZeroMemory(&ti, sizeof(ti)); - ti.cbSize = sizeof(ti); - ti.hwnd = infoPtr->hwndSelf; - - for (i = 0; i < infoPtr->nNumButtons; i++) - { - if ((infoPtr->hwndToolTip) && - !(infoPtr->buttons[i].fsStyle & BTNS_SEP)) - { - ti.uId = infoPtr->buttons[i].idCommand; - SendMessageW(infoPtr->hwndToolTip, TTM_DELTOOLW, 0, (LPARAM)&ti); - } - } - - Free(infoPtr->buttons); - infoPtr->buttons = NULL; - infoPtr->nNumButtons = 0; -} - - -/* helper for TOOLBAR_SaveRestoreW */ -static BOOL -TOOLBAR_Restore(TOOLBAR_INFO *infoPtr, LPTBSAVEPARAMSW lpSave) -{ - LONG res; - HKEY hkey = NULL; - BOOL ret = FALSE; - DWORD dwType; - DWORD dwSize = 0; - NMTBRESTORE nmtbr; - - /* restore toolbar information */ - TRACE("restore from %s %s\n", debugstr_w(lpSave->pszSubKey), - debugstr_w(lpSave->pszValueName)); - - memset(&nmtbr, 0, sizeof(nmtbr)); - - res = RegOpenKeyExW(lpSave->hkr, lpSave->pszSubKey, 0, - KEY_QUERY_VALUE, &hkey); - if (!res) - res = RegQueryValueExW(hkey, lpSave->pszValueName, NULL, &dwType, - NULL, &dwSize); - if (!res && dwType != REG_BINARY) - res = ERROR_FILE_NOT_FOUND; - if (!res) - { - nmtbr.pData = Alloc(dwSize); - nmtbr.cbData = (UINT)dwSize; - if (!nmtbr.pData) res = ERROR_OUTOFMEMORY; - } - if (!res) - res = RegQueryValueExW(hkey, lpSave->pszValueName, NULL, &dwType, - (LPBYTE)nmtbr.pData, &dwSize); - if (!res) - { - nmtbr.pCurrent = nmtbr.pData; - nmtbr.iItem = -1; - nmtbr.cbBytesPerRecord = sizeof(DWORD); - nmtbr.cButtons = nmtbr.cbData / nmtbr.cbBytesPerRecord; - - if (!TOOLBAR_SendNotify(&nmtbr.hdr, infoPtr, TBN_RESTORE)) - { - INT i; - - /* remove all existing buttons as this function is designed to - * restore the toolbar to a previously saved state */ - TOOLBAR_DeleteAllButtons(infoPtr); - - for (i = 0; i < nmtbr.cButtons; i++) - { - nmtbr.iItem = i; - nmtbr.tbButton.iBitmap = -1; - nmtbr.tbButton.fsState = 0; - nmtbr.tbButton.fsStyle = 0; - nmtbr.tbButton.idCommand = 0; - if (*nmtbr.pCurrent == (DWORD)-1) - { - /* separator */ - nmtbr.tbButton.fsStyle = TBSTYLE_SEP; - nmtbr.tbButton.iBitmap = SEPARATOR_WIDTH; - } - else if (*nmtbr.pCurrent == (DWORD)-2) - /* hidden button */ - nmtbr.tbButton.fsState = TBSTATE_HIDDEN; - else - nmtbr.tbButton.idCommand = (int)*nmtbr.pCurrent; - - nmtbr.pCurrent++; - - TOOLBAR_SendNotify(&nmtbr.hdr, infoPtr, TBN_RESTORE); - - /* can't contain real string as we don't know whether - * the client put an ANSI or Unicode string in there */ - if (HIWORD(nmtbr.tbButton.iString)) - nmtbr.tbButton.iString = 0; - - TOOLBAR_InsertButtonW(infoPtr->hwndSelf, -1, - (LPARAM)&nmtbr.tbButton); - } - - /* do legacy notifications */ - if (infoPtr->iVersion < 5) - { - /* FIXME: send TBN_BEGINADJUST */ - FIXME("send TBN_GETBUTTONINFO for each button\n"); - /* FIXME: send TBN_ENDADJUST */ - } - - /* remove all uninitialised buttons - * note: loop backwards to avoid having to fixup i on a - * delete */ - for (i = infoPtr->nNumButtons - 1; i >= 0; i--) - if (infoPtr->buttons[i].iBitmap == -1) - TOOLBAR_DeleteButton(infoPtr->hwndSelf, i, 0); - - /* only indicate success if at least one button survived */ - if (infoPtr->nNumButtons > 0) ret = TRUE; - } - } - Free (nmtbr.pData); - RegCloseKey(hkey); - - return ret; -} - - -static LRESULT -TOOLBAR_SaveRestoreW (HWND hwnd, WPARAM wParam, LPTBSAVEPARAMSW lpSave) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - if (lpSave == NULL) return 0; - - if (wParam) - return TOOLBAR_Save(infoPtr, lpSave); - else - return TOOLBAR_Restore(infoPtr, lpSave); -} - - -static LRESULT -TOOLBAR_SaveRestoreA (HWND hwnd, WPARAM wParam, LPTBSAVEPARAMSA lpSave) -{ - LPWSTR pszValueName = 0, pszSubKey = 0; - TBSAVEPARAMSW SaveW; - LRESULT result = 0; - int len; - - if (lpSave == NULL) return 0; - - len = MultiByteToWideChar(CP_ACP, 0, lpSave->pszSubKey, -1, NULL, 0); - pszSubKey = Alloc(len * sizeof(WCHAR)); - if (pszSubKey) goto exit; - MultiByteToWideChar(CP_ACP, 0, lpSave->pszSubKey, -1, pszSubKey, len); - - len = MultiByteToWideChar(CP_ACP, 0, lpSave->pszValueName, -1, NULL, 0); - pszValueName = Alloc(len * sizeof(WCHAR)); - if (!pszValueName) goto exit; - MultiByteToWideChar(CP_ACP, 0, lpSave->pszValueName, -1, pszValueName, len); - - SaveW.pszValueName = pszValueName; - SaveW.pszSubKey = pszSubKey; - SaveW.hkr = lpSave->hkr; - result = TOOLBAR_SaveRestoreW(hwnd, wParam, &SaveW); - -exit: - Free (pszValueName); - Free (pszSubKey); - - return result; -} - - -static LRESULT -TOOLBAR_SetAnchorHighlight (HWND hwnd, WPARAM wParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - BOOL bOldAnchor = infoPtr->bAnchor; - - TRACE("hwnd=%p, bAnchor = %s\n", hwnd, wParam ? "TRUE" : "FALSE"); - - infoPtr->bAnchor = (BOOL)wParam; - - /* Native does not remove the hot effect from an already hot button */ - - return (LRESULT)bOldAnchor; -} - - -static LRESULT -TOOLBAR_SetBitmapSize (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - HIMAGELIST himlDef = GETDEFIMAGELIST(infoPtr, 0); - - TRACE("hwnd=%p, wParam=%d, lParam=%ld\n", hwnd, wParam, lParam); - - if (wParam != 0) - FIXME("wParam is %d. Perhaps image list index?\n", wParam); - - if ((LOWORD(lParam) <= 0) || (HIWORD(lParam)<=0)) - return FALSE; - - if (infoPtr->nNumButtons > 0) - WARN("%d buttons, undoc increase to bitmap size : %d-%d -> %d-%d\n", - infoPtr->nNumButtons, - infoPtr->nBitmapWidth, infoPtr->nBitmapHeight, - LOWORD(lParam), HIWORD(lParam)); - - infoPtr->nBitmapWidth = (INT)LOWORD(lParam); - infoPtr->nBitmapHeight = (INT)HIWORD(lParam); - - - if ((himlDef == infoPtr->himlInt) && - (ImageList_GetImageCount(infoPtr->himlInt) == 0)) - { - ImageList_SetIconSize(infoPtr->himlInt, infoPtr->nBitmapWidth, - infoPtr->nBitmapHeight); - } - - return TRUE; -} - - -static LRESULT -TOOLBAR_SetButtonInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - LPTBBUTTONINFOA lptbbi = (LPTBBUTTONINFOA)lParam; - TBUTTON_INFO *btnPtr; - INT nIndex; - RECT oldBtnRect; - - if (lptbbi == NULL) - return FALSE; - if (lptbbi->cbSize < sizeof(TBBUTTONINFOA)) - return FALSE; - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, - lptbbi->dwMask & 0x80000000); - if (nIndex == -1) - return FALSE; - - btnPtr = &infoPtr->buttons[nIndex]; - if (lptbbi->dwMask & TBIF_COMMAND) - btnPtr->idCommand = lptbbi->idCommand; - if (lptbbi->dwMask & TBIF_IMAGE) - btnPtr->iBitmap = lptbbi->iImage; - if (lptbbi->dwMask & TBIF_LPARAM) - btnPtr->dwData = lptbbi->lParam; - if (lptbbi->dwMask & TBIF_SIZE) - btnPtr->cx = lptbbi->cx; - if (lptbbi->dwMask & TBIF_STATE) - btnPtr->fsState = lptbbi->fsState; - if (lptbbi->dwMask & TBIF_STYLE) - btnPtr->fsStyle = lptbbi->fsStyle; - - if ((lptbbi->dwMask & TBIF_TEXT) && ((INT)lptbbi->pszText != -1)) { - if ((HIWORD(btnPtr->iString) == 0) || (btnPtr->iString == -1)) - /* iString is index, zero it to make Str_SetPtr succeed */ - btnPtr->iString=0; - - Str_SetPtrAtoW ((LPWSTR *)&btnPtr->iString, lptbbi->pszText); - } - - /* save the button rect to see if we need to redraw the whole toolbar */ - oldBtnRect = btnPtr->rect; - TOOLBAR_CalcToolbar(hwnd); - - if (!EqualRect(&oldBtnRect, &btnPtr->rect)) - InvalidateRect(hwnd, NULL, TRUE); - else - InvalidateRect(hwnd, &btnPtr->rect, TRUE); - - return TRUE; -} - - -static LRESULT -TOOLBAR_SetButtonInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - LPTBBUTTONINFOW lptbbi = (LPTBBUTTONINFOW)lParam; - TBUTTON_INFO *btnPtr; - INT nIndex; - RECT oldBtnRect; - - if (lptbbi == NULL) - return FALSE; - if (lptbbi->cbSize < sizeof(TBBUTTONINFOW)) - return FALSE; - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, - lptbbi->dwMask & 0x80000000); - if (nIndex == -1) - return FALSE; - - btnPtr = &infoPtr->buttons[nIndex]; - if (lptbbi->dwMask & TBIF_COMMAND) - btnPtr->idCommand = lptbbi->idCommand; - if (lptbbi->dwMask & TBIF_IMAGE) - btnPtr->iBitmap = lptbbi->iImage; - if (lptbbi->dwMask & TBIF_LPARAM) - btnPtr->dwData = lptbbi->lParam; - if (lptbbi->dwMask & TBIF_SIZE) - btnPtr->cx = lptbbi->cx; - if (lptbbi->dwMask & TBIF_STATE) - btnPtr->fsState = lptbbi->fsState; - if (lptbbi->dwMask & TBIF_STYLE) - btnPtr->fsStyle = lptbbi->fsStyle; - - if ((lptbbi->dwMask & TBIF_TEXT) && ((INT)lptbbi->pszText != -1)) { - if ((HIWORD(btnPtr->iString) == 0) || (btnPtr->iString == -1)) - /* iString is index, zero it to make Str_SetPtr succeed */ - btnPtr->iString=0; - Str_SetPtrW ((LPWSTR *)&btnPtr->iString, lptbbi->pszText); - } - - /* save the button rect to see if we need to redraw the whole toolbar */ - oldBtnRect = btnPtr->rect; - TOOLBAR_CalcToolbar(hwnd); - - if (!EqualRect(&oldBtnRect, &btnPtr->rect)) - InvalidateRect(hwnd, NULL, TRUE); - else - InvalidateRect(hwnd, &btnPtr->rect, TRUE); - - return TRUE; -} - - -static LRESULT -TOOLBAR_SetButtonSize (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - INT cx = LOWORD(lParam), cy = HIWORD(lParam); - - if ((cx < 0) || (cy < 0)) - { - ERR("invalid parameter 0x%08lx\n", (DWORD)lParam); - return FALSE; - } - - TRACE("%p, cx = %d, cy = %d\n", hwnd, cx, cy); - - /* The documentation claims you can only change the button size before - * any button has been added. But this is wrong. - * WINZIP32.EXE (ver 8) calls this on one of its buttons after adding - * it to the toolbar, and it checks that the return value is nonzero - mjm - * Further testing shows that we must actually perform the change too. - */ - /* - * The documentation also does not mention that if 0 is supplied for - * either size, the system changes it to the default of 24 wide and - * 22 high. Demonstarted in ControlSpy Toolbar. GLA 3/02 - */ - infoPtr->nButtonWidth = (cx) ? cx : 24; - infoPtr->nButtonHeight = (cy) ? cy : 22; - return TRUE; -} - - -static LRESULT -TOOLBAR_SetButtonWidth (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - /* if setting to current values, ignore */ - if ((infoPtr->cxMin == (INT)LOWORD(lParam)) && - (infoPtr->cxMax == (INT)HIWORD(lParam))) { - TRACE("matches current width, min=%d, max=%d, no recalc\n", - infoPtr->cxMin, infoPtr->cxMax); - return TRUE; - } - - /* save new values */ - infoPtr->cxMin = (INT)LOWORD(lParam); - infoPtr->cxMax = (INT)HIWORD(lParam); - - /* if both values are 0 then we are done */ - if (lParam == 0) { - TRACE("setting both min and max to 0, norecalc\n"); - return TRUE; - } - - /* otherwise we need to recalc the toolbar and in some cases - recalc the bounding rectangle (does DrawText w/ DT_CALCRECT - which doesn't actually draw - GA). */ - TRACE("number of buttons %d, cx=%d, cy=%d, recalcing\n", - infoPtr->nNumButtons, infoPtr->cxMin, infoPtr->cxMax); - - TOOLBAR_CalcToolbar (hwnd); - - InvalidateRect (hwnd, NULL, TRUE); - - return TRUE; -} - - -static LRESULT -TOOLBAR_SetCmdId (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - INT nIndex = (INT)wParam; - - if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons)) - return FALSE; - - infoPtr->buttons[nIndex].idCommand = (INT)lParam; - - if (infoPtr->hwndToolTip) { - - FIXME("change tool tip!\n"); - - } - - return TRUE; -} - - -static LRESULT -TOOLBAR_SetDisabledImageList (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - HIMAGELIST himl = (HIMAGELIST)lParam; - HIMAGELIST himlTemp; - INT id = 0; - - if (infoPtr->iVersion >= 5) - id = wParam; - - himlTemp = TOOLBAR_InsertImageList(&infoPtr->himlDis, - &infoPtr->cimlDis, himl, id); - - /* FIXME: redraw ? */ - - return (LRESULT)himlTemp; -} - - -static LRESULT -TOOLBAR_SetDrawTextFlags (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - DWORD dwTemp; - - TRACE("hwnd = %p, dwMask = 0x%08lx, dwDTFlags = 0x%08lx\n", hwnd, (DWORD)wParam, (DWORD)lParam); - - dwTemp = infoPtr->dwDTFlags; - infoPtr->dwDTFlags = - (infoPtr->dwDTFlags & (DWORD)wParam) | (DWORD)lParam; - - return (LRESULT)dwTemp; -} - -/* This function differs a bit from what MSDN says it does: - * 1. lParam contains extended style flags to OR with current style - * (MSDN isn't clear on the OR bit) - * 2. wParam appears to contain extended style flags to be reset - * (MSDN says that this parameter is reserved) - */ -static LRESULT -TOOLBAR_SetExtendedStyle (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - DWORD dwTemp; - - dwTemp = infoPtr->dwExStyle; - infoPtr->dwExStyle &= ~wParam; - infoPtr->dwExStyle |= (DWORD)lParam; - - TRACE("new style 0x%08lx\n", infoPtr->dwExStyle); - - if (infoPtr->dwExStyle & ~TBSTYLE_EX_ALL) - FIXME("Unknown Toolbar Extended Style 0x%08lx. Please report.\n", - (infoPtr->dwExStyle & ~TBSTYLE_EX_ALL)); - - TOOLBAR_CalcToolbar (hwnd); - - TOOLBAR_AutoSize(hwnd); - - InvalidateRect(hwnd, NULL, TRUE); - - return (LRESULT)dwTemp; -} - - -static LRESULT -TOOLBAR_SetHotImageList (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd); - HIMAGELIST himlTemp; - HIMAGELIST himl = (HIMAGELIST)lParam; - INT id = 0; - - if (infoPtr->iVersion >= 5) - id = wParam; - - TRACE("hwnd = %p, himl = %p, id = %d\n", hwnd, himl, id); - - himlTemp = TOOLBAR_InsertImageList(&infoPtr->himlHot, - &infoPtr->cimlHot, himl, id); - - /* FIXME: redraw ? */ - - return (LRESULT)himlTemp; -} - - -/* Makes previous hot button no longer hot, makes the specified - * button hot and sends appropriate notifications. dwReason is one or - * more HICF_ flags. Specify nHit < 0 to make no buttons hot. - * NOTE 1: this function does not validate nHit - * NOTE 2: the name of this function is completely made up and - * not based on any documentation from Microsoft. */ -static void -TOOLBAR_SetHotItemEx (TOOLBAR_INFO *infoPtr, INT nHit, DWORD dwReason) -{ - if (infoPtr->nHotItem != nHit) - { - NMTBHOTITEM nmhotitem; - TBUTTON_INFO *btnPtr = NULL, *oldBtnPtr = NULL; - LRESULT no_highlight; - - /* Remove the effect of an old hot button if the button was - drawn with the hot button effect */ - if(infoPtr->nHotItem >= 0) - { - oldBtnPtr = &infoPtr->buttons[infoPtr->nHotItem]; - oldBtnPtr->bHot = FALSE; - } - - infoPtr->nHotItem = nHit; - - /* It's not a separator or in nowhere. It's a hot button. */ - if (nHit >= 0) - btnPtr = &infoPtr->buttons[nHit]; - - nmhotitem.dwFlags = dwReason; - if (oldBtnPtr) - nmhotitem.idOld = oldBtnPtr->idCommand; - else - nmhotitem.dwFlags |= HICF_ENTERING; - if (btnPtr) - nmhotitem.idNew = btnPtr->idCommand; - else - nmhotitem.dwFlags |= HICF_LEAVING; - - no_highlight = TOOLBAR_SendNotify(&nmhotitem.hdr, infoPtr, TBN_HOTITEMCHANGE); - - /* now invalidate the old and new buttons so they will be painted, - * but only if they are enabled - disabled buttons cannot become hot */ - if (oldBtnPtr && (oldBtnPtr->fsState & TBSTATE_ENABLED)) - InvalidateRect(infoPtr->hwndSelf, &oldBtnPtr->rect, TRUE); - if (btnPtr && !no_highlight && (btnPtr->fsState & TBSTATE_ENABLED)) - { - btnPtr->bHot = TRUE; - InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); - } - } -} - -static LRESULT -TOOLBAR_SetHotItem (HWND hwnd, WPARAM wParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd); - INT nOldHotItem = infoPtr->nHotItem; - - TRACE("hwnd = %p, nHit = %d\n", hwnd, (INT)wParam); - - if ((INT) wParam < 0 || (INT)wParam > infoPtr->nNumButtons) - wParam = -1; - - /* NOTE: an application can still remove the hot item even if anchor - * highlighting is enabled */ - - if (infoPtr->dwStyle & TBSTYLE_FLAT) - TOOLBAR_SetHotItemEx(infoPtr, wParam, HICF_OTHER); - - if (nOldHotItem < 0) - return -1; - - return (LRESULT)nOldHotItem; -} - - -static LRESULT -TOOLBAR_SetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - HIMAGELIST himlTemp; - HIMAGELIST himl = (HIMAGELIST)lParam; - INT i, id = 0; - - if (infoPtr->iVersion >= 5) - id = wParam; - - himlTemp = TOOLBAR_InsertImageList(&infoPtr->himlDef, - &infoPtr->cimlDef, himl, id); - - infoPtr->nNumBitmaps = 0; - for (i = 0; i < infoPtr->cimlDef; i++) - infoPtr->nNumBitmaps += ImageList_GetImageCount(infoPtr->himlDef[i]->himl); - - if (!ImageList_GetIconSize(himl, &infoPtr->nBitmapWidth, - &infoPtr->nBitmapHeight)) - { - infoPtr->nBitmapWidth = 1; - infoPtr->nBitmapHeight = 1; - } - - TRACE("hwnd %p, new himl=%p, id = %d, count=%d, bitmap w=%d, h=%d\n", - hwnd, infoPtr->himlDef, id, infoPtr->nNumBitmaps, - infoPtr->nBitmapWidth, infoPtr->nBitmapHeight); - - InvalidateRect(hwnd, NULL, TRUE); - - return (LRESULT)himlTemp; -} - - -static LRESULT -TOOLBAR_SetIndent (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - infoPtr->nIndent = (INT)wParam; - - TRACE("\n"); - - /* process only on indent changing */ - if(infoPtr->nIndent != (INT)wParam) - { - infoPtr->nIndent = (INT)wParam; - TOOLBAR_CalcToolbar (hwnd); - InvalidateRect(hwnd, NULL, FALSE); - } - - return TRUE; -} - - -static LRESULT -TOOLBAR_SetInsertMark (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - TBINSERTMARK *lptbim = (TBINSERTMARK*)lParam; - - TRACE("hwnd = %p, lptbim = { %d, 0x%08lx}\n", hwnd, lptbim->iButton, lptbim->dwFlags); - - if ((lptbim->dwFlags & ~TBIMHT_AFTER) != 0) - { - FIXME("Unrecognized flag(s): 0x%08lx\n", (lptbim->dwFlags & ~TBIMHT_AFTER)); - return 0; - } - - if ((lptbim->iButton == -1) || - ((lptbim->iButton < infoPtr->nNumButtons) && - (lptbim->iButton >= 0))) - { - infoPtr->tbim = *lptbim; - /* FIXME: don't need to update entire toolbar */ - InvalidateRect(hwnd, NULL, TRUE); - } - else - ERR("Invalid button index %d\n", lptbim->iButton); - - return 0; -} - - -static LRESULT -TOOLBAR_SetInsertMarkColor (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - infoPtr->clrInsertMark = (COLORREF)lParam; - - /* FIXME: don't need to update entire toolbar */ - InvalidateRect(hwnd, NULL, TRUE); - - return 0; -} - - -static LRESULT -TOOLBAR_SetMaxTextRows (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - infoPtr->nMaxTextRows = (INT)wParam; - - TOOLBAR_CalcToolbar(hwnd); - return TRUE; -} - - -/* MSDN gives slightly wrong info on padding. - * 1. It is not only used on buttons with the BTNS_AUTOSIZE style - * 2. It is not used to create a blank area between the edge of the button - * and the text or image if TBSTYLE_LIST is set. It is used to control - * the gap between the image and text. - * 3. It is not applied to both sides. If TBSTYLE_LIST is set it is used - * to control the bottom and right borders [with the border being - * szPadding.cx - (GetSystemMetrics(SM_CXEDGE)+1)], otherwise the padding - * is shared evenly on both sides of the button. - * See blueprints in comments above TOOLBAR_MeasureButton for more info. - */ -static LRESULT -TOOLBAR_SetPadding (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - DWORD oldPad; - - oldPad = MAKELONG(infoPtr->szPadding.cx, infoPtr->szPadding.cy); - infoPtr->szPadding.cx = min(LOWORD((DWORD)lParam), GetSystemMetrics(SM_CXEDGE)); - infoPtr->szPadding.cy = min(HIWORD((DWORD)lParam), GetSystemMetrics(SM_CYEDGE)); - TRACE("cx=%ld, cy=%ld\n", - infoPtr->szPadding.cx, infoPtr->szPadding.cy); - return (LRESULT) oldPad; -} - - -static LRESULT -TOOLBAR_SetParent (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - HWND hwndOldNotify; - - TRACE("\n"); - - hwndOldNotify = infoPtr->hwndNotify; - infoPtr->hwndNotify = (HWND)wParam; - - return (LRESULT)hwndOldNotify; -} - - -static LRESULT -TOOLBAR_SetRows (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - LPRECT lprc = (LPRECT)lParam; - - TRACE("\n"); - - if (LOWORD(wParam) > 1) { - FIXME("multiple rows not supported!\n"); - } - - if(infoPtr->nRows != LOWORD(wParam)) - { - infoPtr->nRows = LOWORD(wParam); - - /* recalculate toolbar */ - TOOLBAR_CalcToolbar (hwnd); - - /* repaint toolbar */ - InvalidateRect(hwnd, NULL, TRUE); - } - - /* return bounding rectangle */ - if (lprc) { - lprc->left = infoPtr->rcBound.left; - lprc->right = infoPtr->rcBound.right; - lprc->top = infoPtr->rcBound.top; - lprc->bottom = infoPtr->rcBound.bottom; - } - - return 0; -} - - -static LRESULT -TOOLBAR_SetState (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - TBUTTON_INFO *btnPtr; - INT nIndex; - - nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); - if (nIndex == -1) - return FALSE; - - btnPtr = &infoPtr->buttons[nIndex]; - - /* if hidden state has changed the invalidate entire window and recalc */ - if ((btnPtr->fsState & TBSTATE_HIDDEN) != (LOWORD(lParam) & TBSTATE_HIDDEN)) { - btnPtr->fsState = LOWORD(lParam); - TOOLBAR_CalcToolbar (hwnd); - InvalidateRect(hwnd, 0, TRUE); - return TRUE; - } - - /* process state changing if current state doesn't match new state */ - if(btnPtr->fsState != LOWORD(lParam)) - { - btnPtr->fsState = LOWORD(lParam); - InvalidateRect(hwnd, &btnPtr->rect, TRUE); - } - - return TRUE; -} - - -static LRESULT -TOOLBAR_SetStyle (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - SetWindowLongW(hwnd, GWL_STYLE, lParam); - - return TRUE; -} - - -inline static LRESULT -TOOLBAR_SetToolTips (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - TRACE("hwnd=%p, hwndTooltip=%p, lParam=0x%lx\n", hwnd, (HWND)wParam, lParam); - - infoPtr->hwndToolTip = (HWND)wParam; - return 0; -} - - -static LRESULT -TOOLBAR_SetUnicodeFormat (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - BOOL bTemp; - - TRACE("%s hwnd=%p\n", - ((BOOL)wParam) ? "TRUE" : "FALSE", hwnd); - - bTemp = infoPtr->bUnicode; - infoPtr->bUnicode = (BOOL)wParam; - - return bTemp; -} - - -static LRESULT -TOOLBAR_GetColorScheme (HWND hwnd, LPCOLORSCHEME lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - lParam->clrBtnHighlight = (infoPtr->clrBtnHighlight == CLR_DEFAULT) ? - comctl32_color.clrBtnHighlight : - infoPtr->clrBtnHighlight; - lParam->clrBtnShadow = (infoPtr->clrBtnShadow == CLR_DEFAULT) ? - comctl32_color.clrBtnShadow : infoPtr->clrBtnShadow; - return 1; -} - - -static LRESULT -TOOLBAR_SetColorScheme (HWND hwnd, LPCOLORSCHEME lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - TRACE("new colors Hl=%lx Shd=%lx, old colors Hl=%lx Shd=%lx\n", - lParam->clrBtnHighlight, lParam->clrBtnShadow, - infoPtr->clrBtnHighlight, infoPtr->clrBtnShadow); - - infoPtr->clrBtnHighlight = lParam->clrBtnHighlight; - infoPtr->clrBtnShadow = lParam->clrBtnShadow; - InvalidateRect(hwnd, NULL, TRUE); - return 0; -} - - -static LRESULT -TOOLBAR_SetVersion (HWND hwnd, INT iVersion) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - INT iOldVersion = infoPtr->iVersion; - - infoPtr->iVersion = iVersion; - - if (infoPtr->iVersion >= 5) - TOOLBAR_SetUnicodeFormat(hwnd, (WPARAM)TRUE, (LPARAM)0); - - return iOldVersion; -} - - -static LRESULT -TOOLBAR_GetStringA (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd); - WORD iString = HIWORD(wParam); - WORD buffersize = LOWORD(wParam); - LPSTR str = (LPSTR)lParam; - LRESULT ret = -1; - - TRACE("hwnd=%p, iString=%d, buffersize=%d, string=%p\n", hwnd, iString, buffersize, str); - - if (iString < infoPtr->nNumStrings) - { - ret = WideCharToMultiByte(CP_ACP, 0, infoPtr->strings[iString], -1, str, buffersize, NULL, NULL); - - TRACE("returning %s\n", debugstr_a(str)); - } - else - ERR("String index %d out of range (largest is %d)\n", iString, infoPtr->nNumStrings - 1); - - return ret; -} - - -static LRESULT -TOOLBAR_GetStringW (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd); - WORD iString = HIWORD(wParam); - WORD len = LOWORD(wParam)/sizeof(WCHAR) - 1; - LPWSTR str = (LPWSTR)lParam; - LRESULT ret = -1; - - TRACE("hwnd=%p, iString=%d, buffersize=%d, string=%p\n", hwnd, iString, LOWORD(wParam), str); - - if (iString < infoPtr->nNumStrings) - { - len = min(len, strlenW(infoPtr->strings[iString])); - ret = (len+1)*sizeof(WCHAR); - memcpy(str, infoPtr->strings[iString], ret); - str[len] = '\0'; - - TRACE("returning %s\n", debugstr_w(str)); - } - else - ERR("String index %d out of range (largest is %d)\n", iString, infoPtr->nNumStrings - 1); - - return ret; -} - -/* UNDOCUMENTED MESSAGE: This appears to set some kind of size. Perhaps it - * is the maximum size of the toolbar? */ -static LRESULT TOOLBAR_Unkwn45D(HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - SIZE * pSize = (SIZE*)lParam; - FIXME("hwnd=%p, wParam=0x%08x, size.cx=%ld, size.cy=%ld stub!\n", hwnd, wParam, pSize->cx, pSize->cy); - return 0; -} - - -/* UNDOCUMENTED MESSAGE: This is an extended version of the - * TB_SETHOTITEM message. It allows the caller to specify a reason why the - * hot item changed (rather than just the HICF_OTHER that TB_SETHOTITEM - * sends). */ -static LRESULT -TOOLBAR_Unkwn45E (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd); - INT nOldHotItem = infoPtr->nHotItem; - - TRACE("old item=%d, new item=%d, flags=%08lx\n", - nOldHotItem, infoPtr->nHotItem, (DWORD)lParam); - - if ((INT) wParam < 0 || (INT)wParam > infoPtr->nNumButtons) - wParam = -1; - - /* NOTE: an application can still remove the hot item even if anchor - * highlighting is enabled */ - - TOOLBAR_SetHotItemEx(infoPtr, wParam, lParam); - - GetFocus(); - - return (nOldHotItem < 0) ? -1 : (LRESULT)nOldHotItem; -} - -/* UNDOCUMENTED MESSAGE: This sets the toolbar global iListGap parameter - * which controls the amount of spacing between the image and the text - * of buttons for TBSTYLE_LIST toolbars. */ -static LRESULT TOOLBAR_Unkwn460(HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd); - - TRACE("hwnd=%p iListGap=%d\n", hwnd, wParam); - - if (lParam != 0) - FIXME("lParam = 0x%08lx. Please report\n", lParam); - - infoPtr->iListGap = (INT)wParam; - - InvalidateRect(hwnd, NULL, TRUE); - - return 0; -} - -/* UNDOCUMENTED MESSAGE: This returns the number of maximum number - * of image lists associated with the various states. */ -static LRESULT TOOLBAR_Unkwn462(HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd); - - TRACE("hwnd=%p wParam %08x lParam %08lx\n", hwnd, wParam, lParam); - - return max(infoPtr->cimlDef, max(infoPtr->cimlHot, infoPtr->cimlDis)); -} - -static LRESULT -TOOLBAR_Unkwn463 (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - LPSIZE lpsize = (LPSIZE)lParam; - - if (lpsize == NULL) - return FALSE; - - /* - * Testing shows the following: - * wParam = 0 adjust cx value - * = 1 set cy value to max size. - * lParam pointer to SIZE structure - * - */ - TRACE("[0463] wParam %d, lParam 0x%08lx -> 0x%08lx 0x%08lx\n", - wParam, lParam, lpsize->cx, lpsize->cy); - - switch(wParam) { - case 0: - if (lpsize->cx == -1) { - /* **** this is wrong, native measures each button and sets it */ - lpsize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left; - } - else if(HIWORD(lpsize->cx)) { - RECT rc; - HWND hwndParent = GetParent(hwnd); - - GetWindowRect(hwnd, &rc); - MapWindowPoints(0, hwndParent, (LPPOINT)&rc, 2); - TRACE("mapped to (%ld,%ld)-(%ld,%ld)\n", - rc.left, rc.top, rc.right, rc.bottom); - lpsize->cx = max(rc.right-rc.left, - infoPtr->rcBound.right - infoPtr->rcBound.left); - } - else { - lpsize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left; - } - break; - case 1: - lpsize->cy = infoPtr->rcBound.bottom - infoPtr->rcBound.top; - /* lpsize->cy = infoPtr->nHeight; */ - break; - default: - ERR("Unknown wParam %d for Toolbar message [0463]. Please report\n", - wParam); - return 0; - } - TRACE("[0463] set to -> 0x%08lx 0x%08lx\n", - lpsize->cx, lpsize->cy); - return 1; -} - -static LRESULT TOOLBAR_Unkwn464(HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - FIXME("hwnd=%p wParam %08x lParam %08lx\n", hwnd, wParam, lParam); - - InvalidateRect(hwnd, NULL, TRUE); - return 1; -} - - -static LRESULT -TOOLBAR_Create (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE); - LOGFONTW logFont; - - TRACE("hwnd = %p\n", hwnd); - - /* initialize info structure */ - infoPtr->nButtonHeight = 22; - infoPtr->nButtonWidth = 24; - infoPtr->nBitmapHeight = 15; - infoPtr->nBitmapWidth = 16; - - infoPtr->nHeight = infoPtr->nButtonHeight + TOP_BORDER + BOTTOM_BORDER; - infoPtr->nMaxTextRows = 1; - infoPtr->cxMin = -1; - infoPtr->cxMax = -1; - infoPtr->nNumBitmaps = 0; - infoPtr->nNumStrings = 0; - - infoPtr->bCaptured = FALSE; - infoPtr->nButtonDown = -1; - infoPtr->nButtonDrag = -1; - infoPtr->nOldHit = -1; - infoPtr->nHotItem = -1; - infoPtr->hwndNotify = ((LPCREATESTRUCTW)lParam)->hwndParent; - infoPtr->bBtnTranspnt = (dwStyle & (TBSTYLE_FLAT | TBSTYLE_LIST)); - infoPtr->dwDTFlags = (dwStyle & TBSTYLE_LIST) ? DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS: DT_CENTER | DT_END_ELLIPSIS; - infoPtr->bAnchor = FALSE; /* no anchor highlighting */ - infoPtr->bDragOutSent = FALSE; - infoPtr->iVersion = 0; - infoPtr->hwndSelf = hwnd; - infoPtr->bDoRedraw = TRUE; - infoPtr->clrBtnHighlight = CLR_DEFAULT; - infoPtr->clrBtnShadow = CLR_DEFAULT; - infoPtr->szPadding.cx = DEFPAD_CX; - infoPtr->szPadding.cy = DEFPAD_CY; - infoPtr->iListGap = DEFLISTGAP; - infoPtr->dwStyle = dwStyle; - infoPtr->tbim.iButton = -1; - GetClientRect(hwnd, &infoPtr->client_rect); - infoPtr->bUnicode = infoPtr->hwndNotify && - (NFR_UNICODE == SendMessageW(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwnd, (LPARAM)NF_REQUERY)); - - SystemParametersInfoW (SPI_GETICONTITLELOGFONT, 0, &logFont, 0); - infoPtr->hFont = infoPtr->hDefaultFont = CreateFontIndirectW (&logFont); - - if (dwStyle & TBSTYLE_TOOLTIPS) { - /* Create tooltip control */ - infoPtr->hwndToolTip = - CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, 0, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - hwnd, 0, 0, 0); - - /* Send NM_TOOLTIPSCREATED notification */ - if (infoPtr->hwndToolTip) - { - NMTOOLTIPSCREATED nmttc; - - nmttc.hwndToolTips = infoPtr->hwndToolTip; - - TOOLBAR_SendNotify (&nmttc.hdr, infoPtr, NM_TOOLTIPSCREATED); - } - } - - TOOLBAR_CheckStyle (hwnd, dwStyle); - - TOOLBAR_CalcToolbar(hwnd); - - return 0; -} - - -static LRESULT -TOOLBAR_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - /* delete tooltip control */ - if (infoPtr->hwndToolTip) - DestroyWindow (infoPtr->hwndToolTip); - - /* delete temporary buffer for tooltip text */ - Free (infoPtr->pszTooltipText); - - /* delete button data */ - if (infoPtr->buttons) - Free (infoPtr->buttons); - - /* delete strings */ - if (infoPtr->strings) { - INT i; - for (i = 0; i < infoPtr->nNumStrings; i++) - if (infoPtr->strings[i]) - Free (infoPtr->strings[i]); - - Free (infoPtr->strings); - } - - /* destroy internal image list */ - if (infoPtr->himlInt) - ImageList_Destroy (infoPtr->himlInt); - - TOOLBAR_DeleteImageList(&infoPtr->himlDef, &infoPtr->cimlDef); - TOOLBAR_DeleteImageList(&infoPtr->himlDis, &infoPtr->cimlDis); - TOOLBAR_DeleteImageList(&infoPtr->himlHot, &infoPtr->cimlHot); - - /* delete default font */ - if (infoPtr->hFont) - DeleteObject (infoPtr->hDefaultFont); - - /* free toolbar info data */ - Free (infoPtr); - SetWindowLongPtrW (hwnd, 0, 0); - - return 0; -} - - -static LRESULT -TOOLBAR_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - NMTBCUSTOMDRAW tbcd; - INT ret = FALSE; - DWORD ntfret; - - /* the app has told us not to redraw the toolbar */ - if (!infoPtr->bDoRedraw) - return FALSE; - - if (infoPtr->dwStyle & TBSTYLE_CUSTOMERASE) { - ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW)); - tbcd.nmcd.dwDrawStage = CDDS_PREERASE; - tbcd.nmcd.hdc = (HDC)wParam; - ntfret = TOOLBAR_SendNotify (&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); - infoPtr->dwBaseCustDraw = ntfret & 0xffff; - - /* FIXME: in general the return flags *can* be or'ed together */ - switch (infoPtr->dwBaseCustDraw) - { - case CDRF_DODEFAULT: - break; - case CDRF_SKIPDEFAULT: - return TRUE; - default: - FIXME("[%p] response %ld not handled to NM_CUSTOMDRAW (CDDS_PREERASE)\n", - hwnd, ntfret); - } - } - - /* If the toolbar is "transparent" then pass the WM_ERASEBKGND up - * to my parent for processing. - */ - if (infoPtr->dwStyle & TBSTYLE_TRANSPARENT) { - POINT pt, ptorig; - HDC hdc = (HDC)wParam; - HWND parent; - - pt.x = 0; - pt.y = 0; - parent = GetParent(hwnd); - MapWindowPoints(hwnd, parent, &pt, 1); - OffsetWindowOrgEx (hdc, pt.x, pt.y, &ptorig); - ret = SendMessageW (parent, WM_ERASEBKGND, wParam, lParam); - SetWindowOrgEx (hdc, ptorig.x, ptorig.y, 0); - } - if (!ret) - ret = DefWindowProcW (hwnd, WM_ERASEBKGND, wParam, lParam); - - if ((infoPtr->dwStyle & TBSTYLE_CUSTOMERASE) && - (infoPtr->dwBaseCustDraw & CDRF_NOTIFYPOSTERASE)) { - ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW)); - tbcd.nmcd.dwDrawStage = CDDS_POSTERASE; - tbcd.nmcd.hdc = (HDC)wParam; - ntfret = TOOLBAR_SendNotify (&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); - infoPtr->dwBaseCustDraw = ntfret & 0xffff; - switch (infoPtr->dwBaseCustDraw) - { - case CDRF_DODEFAULT: - break; - case CDRF_SKIPDEFAULT: - return TRUE; - default: - FIXME("[%p] response %ld not handled to NM_CUSTOMDRAW (CDDS_POSTERASE)\n", - hwnd, ntfret); - } - } - return ret; -} - - -static LRESULT -TOOLBAR_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - return (LRESULT)infoPtr->hFont; -} - - -static LRESULT -TOOLBAR_LButtonDblClk (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - POINT pt; - INT nHit; - - pt.x = (INT)LOWORD(lParam); - pt.y = (INT)HIWORD(lParam); - nHit = TOOLBAR_InternalHitTest (hwnd, &pt); - - if (nHit >= 0) - TOOLBAR_LButtonDown (hwnd, wParam, lParam); - else if (GetWindowLongW (hwnd, GWL_STYLE) & CCS_ADJUSTABLE) - TOOLBAR_Customize (hwnd); - - return 0; -} - - -static LRESULT -TOOLBAR_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - TBUTTON_INFO *btnPtr; - POINT pt; - INT nHit; - NMTOOLBARA nmtb; - NMMOUSE nmmouse; - BOOL bDragKeyPressed; - - TRACE("\n"); - - if (infoPtr->dwStyle & TBSTYLE_ALTDRAG) - bDragKeyPressed = (GetKeyState(VK_MENU) < 0); - else - bDragKeyPressed = (wParam & MK_SHIFT); - - if (infoPtr->hwndToolTip) - TOOLBAR_RelayEvent (infoPtr->hwndToolTip, hwnd, - WM_LBUTTONDOWN, wParam, lParam); - - pt.x = (INT)LOWORD(lParam); - pt.y = (INT)HIWORD(lParam); - nHit = TOOLBAR_InternalHitTest (hwnd, &pt); - - btnPtr = &infoPtr->buttons[nHit]; - - if ((nHit >= 0) && bDragKeyPressed && (infoPtr->dwStyle & CCS_ADJUSTABLE)) - { - infoPtr->nButtonDrag = nHit; - SetCapture (hwnd); - - /* If drag cursor has not been loaded, load it. - * Note: it doesn't need to be freed */ - if (!hCursorDrag) - hCursorDrag = LoadCursorW(COMCTL32_hModule, (LPCWSTR)IDC_MOVEBUTTON); - SetCursor(hCursorDrag); - } - else if (nHit >= 0) - { - RECT arrowRect; - infoPtr->nOldHit = nHit; - - CopyRect(&arrowRect, &btnPtr->rect); - arrowRect.left = max(btnPtr->rect.left, btnPtr->rect.right - DDARROW_WIDTH); - - /* for EX_DRAWDDARROWS style, click must be in the drop-down arrow rect */ - if ((btnPtr->fsState & TBSTATE_ENABLED) && - ((btnPtr->fsStyle & BTNS_WHOLEDROPDOWN) || - ((btnPtr->fsStyle & BTNS_DROPDOWN) && - ((TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle) && PtInRect(&arrowRect, pt)) || - (!TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle)))))) - { - LRESULT res; - - /* draw in pressed state */ - if (btnPtr->fsStyle & BTNS_WHOLEDROPDOWN) - btnPtr->fsState |= TBSTATE_PRESSED; - else - btnPtr->bDropDownPressed = TRUE; - RedrawWindow(hwnd,&btnPtr->rect,0, - RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW); - - memset(&nmtb, 0, sizeof(nmtb)); - nmtb.iItem = btnPtr->idCommand; - nmtb.rcButton = btnPtr->rect; - res = TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr, - TBN_DROPDOWN); - TRACE("TBN_DROPDOWN responded with %ld\n", res); - - if (res != TBDDRET_TREATPRESSED) - { - MSG msg; - - /* redraw button in unpressed state */ - if (btnPtr->fsStyle & BTNS_WHOLEDROPDOWN) - btnPtr->fsState &= ~TBSTATE_PRESSED; - else - btnPtr->bDropDownPressed = FALSE; - InvalidateRect(hwnd, &btnPtr->rect, TRUE); - - /* find and set hot item - * NOTE: native doesn't do this, but that is a bug */ - GetCursorPos(&pt); - ScreenToClient(hwnd, &pt); - nHit = TOOLBAR_InternalHitTest(hwnd, &pt); - if (!infoPtr->bAnchor || (nHit >= 0)) - TOOLBAR_SetHotItemEx(infoPtr, nHit, HICF_MOUSE | HICF_LMOUSE); - - /* remove any left mouse button down or double-click messages - * so that we can get a toggle effect on the button */ - while (PeekMessageW(&msg, hwnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE) || - PeekMessageW(&msg, hwnd, WM_LBUTTONDBLCLK, WM_LBUTTONDBLCLK, PM_REMOVE)) - ; - - return 0; - } - /* otherwise drop through and process as pushed */ - } - infoPtr->bCaptured = TRUE; - infoPtr->nButtonDown = nHit; - infoPtr->bDragOutSent = FALSE; - - btnPtr->fsState |= TBSTATE_PRESSED; - - TOOLBAR_SetHotItemEx(infoPtr, nHit, HICF_MOUSE | HICF_LMOUSE); - - if (btnPtr->fsState & TBSTATE_ENABLED) - InvalidateRect(hwnd, &btnPtr->rect, TRUE); - UpdateWindow(hwnd); - SetCapture (hwnd); - } - - if (nHit >=0) - { - memset(&nmtb, 0, sizeof(nmtb)); - nmtb.iItem = btnPtr->idCommand; - TOOLBAR_SendNotify((NMHDR *)&nmtb, infoPtr, TBN_BEGINDRAG); - } - - nmmouse.dwHitInfo = nHit; - - /* !!! Undocumented - sends NM_LDOWN with the NMMOUSE structure. */ - if (nHit < 0) - nmmouse.dwItemSpec = -1; - else - { - nmmouse.dwItemSpec = infoPtr->buttons[nmmouse.dwHitInfo].idCommand; - nmmouse.dwItemData = infoPtr->buttons[nmmouse.dwHitInfo].dwData; - } - - ClientToScreen(hwnd, &pt); - nmmouse.pt = pt; - - if (!TOOLBAR_SendNotify(&nmmouse.hdr, infoPtr, NM_LDOWN)) - return DefWindowProcW(hwnd, WM_LBUTTONDOWN, wParam, lParam); - - return 0; -} - -static LRESULT -TOOLBAR_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - TBUTTON_INFO *btnPtr; - POINT pt; - INT nHit; - INT nOldIndex = -1; - BOOL bSendMessage = TRUE; - NMHDR hdr; - NMMOUSE nmmouse; - NMTOOLBARA nmtb; - - if (infoPtr->hwndToolTip) - TOOLBAR_RelayEvent (infoPtr->hwndToolTip, hwnd, - WM_LBUTTONUP, wParam, lParam); - - pt.x = (INT)LOWORD(lParam); - pt.y = (INT)HIWORD(lParam); - nHit = TOOLBAR_InternalHitTest (hwnd, &pt); - - if (!infoPtr->bAnchor || (nHit >= 0)) - TOOLBAR_SetHotItemEx(infoPtr, nHit, HICF_MOUSE | HICF_LMOUSE); - - if (infoPtr->nButtonDrag >= 0) { - RECT rcClient; - NMHDR hdr; - - btnPtr = &infoPtr->buttons[infoPtr->nButtonDrag]; - ReleaseCapture(); - /* reset cursor */ - SetCursor(LoadCursorW(NULL, (LPCWSTR)IDC_ARROW)); - - GetClientRect(hwnd, &rcClient); - if (PtInRect(&rcClient, pt)) - { - INT nButton = -1; - if (nHit >= 0) - nButton = nHit; - else if (nHit < -1) - nButton = -nHit; - else if ((nHit == -1) && PtInRect(&infoPtr->buttons[-nHit].rect, pt)) - nButton = -nHit; - - if (nButton == infoPtr->nButtonDrag) - { - /* if the button is moved sightly left and we have a - * separator there then remove it */ - if (pt.x < (btnPtr->rect.left + (btnPtr->rect.right - btnPtr->rect.left)/2)) - { - if ((nButton > 0) && (infoPtr->buttons[nButton-1].fsStyle & BTNS_SEP)) - TOOLBAR_DeleteButton(hwnd, nButton - 1, 0); - } - else /* else insert a separator before the dragged button */ - { - TBBUTTON tbb; - memset(&tbb, 0, sizeof(tbb)); - tbb.fsStyle = BTNS_SEP; - tbb.iString = -1; - TOOLBAR_InsertButtonW(hwnd, nButton, (LPARAM)&tbb); - } - } - else - { - if (nButton == -1) - { - if ((infoPtr->nNumButtons > 0) && (pt.x < infoPtr->buttons[0].rect.left)) - TOOLBAR_MoveButton(hwnd, infoPtr->nButtonDrag, 0); - else - TOOLBAR_MoveButton(hwnd, infoPtr->nButtonDrag, infoPtr->nNumButtons); - } - else - TOOLBAR_MoveButton(hwnd, infoPtr->nButtonDrag, nButton); - } - } - else - { - TRACE("button %d dragged out of toolbar\n", infoPtr->nButtonDrag); - TOOLBAR_DeleteButton(hwnd, (WPARAM)infoPtr->nButtonDrag, 0); - } - - /* button under cursor changed so need to re-set hot item */ - TOOLBAR_SetHotItemEx(infoPtr, nHit, HICF_MOUSE | HICF_LMOUSE); - infoPtr->nButtonDrag = -1; - - TOOLBAR_SendNotify(&hdr, infoPtr, TBN_TOOLBARCHANGE); - } - else if (infoPtr->nButtonDown >= 0) { - btnPtr = &infoPtr->buttons[infoPtr->nButtonDown]; - btnPtr->fsState &= ~TBSTATE_PRESSED; - - if (btnPtr->fsStyle & BTNS_CHECK) { - if (btnPtr->fsStyle & BTNS_GROUP) { - nOldIndex = TOOLBAR_GetCheckedGroupButtonIndex (infoPtr, - nHit); - if (nOldIndex == nHit) - bSendMessage = FALSE; - if ((nOldIndex != nHit) && - (nOldIndex != -1)) - infoPtr->buttons[nOldIndex].fsState &= ~TBSTATE_CHECKED; - btnPtr->fsState |= TBSTATE_CHECKED; - } - else { - if (btnPtr->fsState & TBSTATE_CHECKED) - btnPtr->fsState &= ~TBSTATE_CHECKED; - else - btnPtr->fsState |= TBSTATE_CHECKED; - } - } - - if (nOldIndex != -1) - InvalidateRect(hwnd, &infoPtr->buttons[nOldIndex].rect, TRUE); - - /* - * now we can ReleaseCapture, which triggers CAPTURECHANGED msg, - * that resets bCaptured and btn TBSTATE_PRESSED flags, - * and obliterates nButtonDown and nOldHit (see TOOLBAR_CaptureChanged) - */ - if ((infoPtr->bCaptured) && (infoPtr->nButtonDown >= 0)) - ReleaseCapture (); - infoPtr->nButtonDown = -1; - - /* Issue NM_RELEASEDCAPTURE to parent to let him know it is released */ - TOOLBAR_SendNotify ((NMHDR *) &hdr, infoPtr, - NM_RELEASEDCAPTURE); - - /* native issues TBN_ENDDRAG here, if _LBUTTONDOWN issued the - * TBN_BEGINDRAG - */ - memset(&nmtb, 0, sizeof(nmtb)); - nmtb.iItem = btnPtr->idCommand; - TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr, - TBN_ENDDRAG); - - if (btnPtr->fsState & TBSTATE_ENABLED) - { - SendMessageW (infoPtr->hwndNotify, WM_COMMAND, - MAKEWPARAM(infoPtr->buttons[nHit].idCommand, 0), (LPARAM)hwnd); - } - } - - /* !!! Undocumented - toolbar at 4.71 level and above sends - * NM_CLICK with the NMMOUSE structure. */ - nmmouse.dwHitInfo = nHit; - - if (nmmouse.dwHitInfo < 0) - nmmouse.dwItemSpec = -1; - else - { - nmmouse.dwItemSpec = infoPtr->buttons[nmmouse.dwHitInfo].idCommand; - nmmouse.dwItemData = infoPtr->buttons[nmmouse.dwHitInfo].dwData; - } - - ClientToScreen(hwnd, &pt); - nmmouse.pt = pt; - - if (!TOOLBAR_SendNotify((LPNMHDR)&nmmouse, infoPtr, NM_CLICK)) - return DefWindowProcW(hwnd, WM_LBUTTONUP, wParam, lParam); - - return 0; -} - -static LRESULT -TOOLBAR_RButtonUp( HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - INT nHit; - NMMOUSE nmmouse; - POINT pt; - - pt.x = LOWORD(lParam); - pt.y = HIWORD(lParam); - - nHit = TOOLBAR_InternalHitTest(hwnd, &pt); - nmmouse.dwHitInfo = nHit; - - if (nHit < 0) { - nmmouse.dwItemSpec = -1; - } else { - nmmouse.dwItemSpec = infoPtr->buttons[nmmouse.dwHitInfo].idCommand; - nmmouse.dwItemData = infoPtr->buttons[nmmouse.dwHitInfo].dwData; - } - - ClientToScreen(hwnd, &pt); - nmmouse.pt = pt; - - if (!TOOLBAR_SendNotify((LPNMHDR)&nmmouse, infoPtr, NM_RCLICK)) - return DefWindowProcW(hwnd, WM_RBUTTONUP, wParam, lParam); - - return 0; -} - -static LRESULT -TOOLBAR_RButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - NMHDR nmhdr; - - if (!TOOLBAR_SendNotify(&nmhdr, infoPtr, NM_RDBLCLK)) - return DefWindowProcW(hwnd, WM_RBUTTONDBLCLK, wParam, lParam); - - return 0; -} - -static LRESULT -TOOLBAR_CaptureChanged(HWND hwnd) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - TBUTTON_INFO *btnPtr; - - infoPtr->bCaptured = FALSE; - - if (infoPtr->nButtonDown >= 0) - { - btnPtr = &infoPtr->buttons[infoPtr->nButtonDown]; - btnPtr->fsState &= ~TBSTATE_PRESSED; - - infoPtr->nOldHit = -1; - - if (btnPtr->fsState & TBSTATE_ENABLED) - InvalidateRect(hwnd, &btnPtr->rect, TRUE); - } - return 0; -} - -static LRESULT -TOOLBAR_MouseLeave (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - TBUTTON_INFO *hotBtnPtr; - - hotBtnPtr = &infoPtr->buttons[infoPtr->nOldHit]; - - /* don't remove hot effects when in anchor highlighting mode or when a - * drop-down button is pressed */ - if (!infoPtr->bAnchor && (infoPtr->nOldHit < 0 || !hotBtnPtr->bDropDownPressed)) - TOOLBAR_SetHotItemEx(infoPtr, TOOLBAR_NOWHERE, HICF_MOUSE); - - if (infoPtr->nOldHit < 0) - return TRUE; - - /* If the last button we were over is depressed then make it not */ - /* depressed and redraw it */ - if(infoPtr->nOldHit == infoPtr->nButtonDown) - { - TBUTTON_INFO *btnPtr; - RECT rc1; - - btnPtr = &infoPtr->buttons[infoPtr->nButtonDown]; - - btnPtr->fsState &= ~TBSTATE_PRESSED; - - rc1 = hotBtnPtr->rect; - InflateRect (&rc1, 1, 1); - InvalidateRect (hwnd, &rc1, TRUE); - } - - if (infoPtr->bCaptured && !infoPtr->bDragOutSent) - { - NMTOOLBARW nmt; - ZeroMemory(&nmt, sizeof(nmt)); - nmt.iItem = infoPtr->buttons[infoPtr->nButtonDown].idCommand; - TOOLBAR_SendNotify(&nmt.hdr, infoPtr, TBN_DRAGOUT); - infoPtr->bDragOutSent = TRUE; - } - - infoPtr->nOldHit = -1; /* reset the old hit index as we've left the toolbar */ - - return TRUE; -} - -static LRESULT -TOOLBAR_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - POINT pt; - TRACKMOUSEEVENT trackinfo; - INT nHit; - TBUTTON_INFO *btnPtr; - - if (infoPtr->dwStyle & TBSTYLE_FLAT) { - /* fill in the TRACKMOUSEEVENT struct */ - trackinfo.cbSize = sizeof(TRACKMOUSEEVENT); - trackinfo.dwFlags = TME_QUERY; - trackinfo.hwndTrack = hwnd; - trackinfo.dwHoverTime = HOVER_DEFAULT; - - /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */ - _TrackMouseEvent(&trackinfo); - - /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */ - if(!(trackinfo.dwFlags & TME_LEAVE)) { - trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */ - - /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */ - /* and can properly deactivate the hot toolbar button */ - _TrackMouseEvent(&trackinfo); - } - } - - if (infoPtr->hwndToolTip) - TOOLBAR_RelayEvent (infoPtr->hwndToolTip, hwnd, - WM_MOUSEMOVE, wParam, lParam); - - pt.x = (INT)LOWORD(lParam); - pt.y = (INT)HIWORD(lParam); - - nHit = TOOLBAR_InternalHitTest (hwnd, &pt); - - if ((infoPtr->dwStyle & TBSTYLE_FLAT) && (!infoPtr->bAnchor || (nHit >= 0))) - TOOLBAR_SetHotItemEx(infoPtr, nHit, HICF_MOUSE); - - if (infoPtr->nOldHit != nHit) - { - if (infoPtr->bCaptured) - { - if (!infoPtr->bDragOutSent) - { - NMTOOLBARW nmt; - ZeroMemory(&nmt, sizeof(nmt)); - nmt.iItem = infoPtr->buttons[infoPtr->nButtonDown].idCommand; - TOOLBAR_SendNotify(&nmt.hdr, infoPtr, TBN_DRAGOUT); - infoPtr->bDragOutSent = TRUE; - } - - btnPtr = &infoPtr->buttons[infoPtr->nButtonDown]; - if (infoPtr->nOldHit == infoPtr->nButtonDown) { - btnPtr->fsState &= ~TBSTATE_PRESSED; - InvalidateRect(hwnd, &btnPtr->rect, TRUE); - } - else if (nHit == infoPtr->nButtonDown) { - btnPtr->fsState |= TBSTATE_PRESSED; - InvalidateRect(hwnd, &btnPtr->rect, TRUE); - } - infoPtr->nOldHit = nHit; - } - } - - return 0; -} - - -inline static LRESULT -TOOLBAR_NCActivate (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ -/* if (wndPtr->dwStyle & CCS_NODIVIDER) */ - return DefWindowProcW (hwnd, WM_NCACTIVATE, wParam, lParam); -/* else */ -/* return TOOLBAR_NCPaint (wndPtr, wParam, lParam); */ -} - - -inline static LRESULT -TOOLBAR_NCCalcSize (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - if (!(GetWindowLongW(hwnd, GWL_STYLE) & CCS_NODIVIDER)) - ((LPRECT)lParam)->top += GetSystemMetrics(SM_CYEDGE); - - return DefWindowProcW (hwnd, WM_NCCALCSIZE, wParam, lParam); -} - - -static LRESULT -TOOLBAR_NCCreate (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr; - LPCREATESTRUCTA cs = (LPCREATESTRUCTA)lParam; - DWORD styleadd = 0; - - /* allocate memory for info structure */ - infoPtr = (TOOLBAR_INFO *)Alloc (sizeof(TOOLBAR_INFO)); - SetWindowLongPtrW (hwnd, 0, (LONG_PTR)infoPtr); - - /* paranoid!! */ - infoPtr->dwStructSize = sizeof(TBBUTTON); - infoPtr->nRows = 1; - - /* fix instance handle, if the toolbar was created by CreateToolbarEx() */ - if (!GetWindowLongPtrW (hwnd, GWLP_HINSTANCE)) { - HINSTANCE hInst = (HINSTANCE)GetWindowLongPtrW (GetParent (hwnd), GWLP_HINSTANCE); - SetWindowLongPtrW (hwnd, GWLP_HINSTANCE, (LONG_PTR)hInst); - } - - /* native control does: - * Get a lot of colors and brushes - * WM_NOTIFYFORMAT - * SystemParametersInfoW(0x1f, 0x3c, adr1, 0) - * CreateFontIndirectW(adr1) - * CreateBitmap(0x27, 0x24, 1, 1, 0) - * hdc = GetDC(toolbar) - * GetSystemMetrics(0x48) - * fnt2=CreateFontW(0xe, 0, 0, 0, 0x190, 0, 0, 0, 0, 2, - * 0, 0, 0, 0, "MARLETT") - * oldfnt = SelectObject(hdc, fnt2) - * GetCharWidthW(hdc, 0x36, 0x36, adr2) - * GetTextMetricsW(hdc, adr3) - * SelectObject(hdc, oldfnt) - * DeleteObject(fnt2) - * ReleaseDC(hdc) - * InvalidateRect(toolbar, 0, 1) - * SetWindowLongW(toolbar, 0, addr) - * SetWindowLongW(toolbar, -16, xxx) **sometimes** - * WM_STYLECHANGING - * CallWinEx old new - * ie 1 0x56000a4c 0x46000a4c 0x56008a4d - * ie 2 0x4600094c 0x4600094c 0x4600894d - * ie 3 0x56000b4c 0x46000b4c 0x56008b4d - * rebar 0x50008844 0x40008844 0x50008845 - * pager 0x50000844 0x40000844 0x50008845 - * IC35mgr 0x5400084e **nochange** - * on entry to _NCCREATE 0x5400084e - * rowlist 0x5400004e **nochange** - * on entry to _NCCREATE 0x5400004e - * - */ - - /* I think the code below is a bug, but it is the way that the native - * controls seem to work. The effect is that if the user of TBSTYLE_FLAT - * forgets to specify TBSTYLE_TRANSPARENT but does specify either - * CCS_TOP or CCS_BOTTOM (_NOMOVEY and _TOP), then the control - * does *not* set TBSTYLE_TRANSPARENT even though it should!!!! - * Somehow, the only cases of this seem to be MFC programs. - * - * Note also that the addition of _TRANSPARENT occurs *only* here. It - * does not occur in the WM_STYLECHANGING routine. - * (Guy Albertelli 9/2001) - * - */ - if ((cs->style & TBSTYLE_FLAT) && !(cs->style & TBSTYLE_TRANSPARENT)) - styleadd |= TBSTYLE_TRANSPARENT; - if (!(cs->style & (CCS_TOP | CCS_NOMOVEY))) { - styleadd |= CCS_TOP; /* default to top */ - SetWindowLongW (hwnd, GWL_STYLE, cs->style | styleadd); - } - - return DefWindowProcW (hwnd, WM_NCCREATE, wParam, lParam); -} - - -static LRESULT -TOOLBAR_NCPaint (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - DWORD dwStyle = GetWindowLongW(hwnd, GWL_STYLE); - RECT rcWindow; - HDC hdc; - - if (dwStyle & WS_MINIMIZE) - return 0; /* Nothing to do */ - - DefWindowProcW (hwnd, WM_NCPAINT, wParam, lParam); - - if (!(hdc = GetDCEx (hwnd, 0, DCX_USESTYLE | DCX_WINDOW))) - return 0; - - if (!(dwStyle & CCS_NODIVIDER)) - { - GetWindowRect (hwnd, &rcWindow); - OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top); - if( dwStyle & WS_BORDER ) - OffsetRect (&rcWindow, 1, 1); - DrawEdge (hdc, &rcWindow, EDGE_ETCHED, BF_TOP); - } - - ReleaseDC( hwnd, hdc ); - - return 0; -} - - -/* handles requests from the tooltip control on what text to display */ -static LRESULT TOOLBAR_TTGetDispInfo (TOOLBAR_INFO *infoPtr, NMTTDISPINFOW *lpnmtdi) -{ - int index = TOOLBAR_GetButtonIndex(infoPtr, lpnmtdi->hdr.idFrom, FALSE); - - TRACE("button index = %d\n", index); - - Free (infoPtr->pszTooltipText); - infoPtr->pszTooltipText = NULL; - - if (index < 0) - return 0; - - if (infoPtr->bUnicode) - { - WCHAR wszBuffer[INFOTIPSIZE+1]; - NMTBGETINFOTIPW tbgit; - unsigned int len; /* in chars */ - - wszBuffer[0] = '\0'; - wszBuffer[INFOTIPSIZE] = '\0'; - - tbgit.pszText = wszBuffer; - tbgit.cchTextMax = INFOTIPSIZE; - tbgit.iItem = lpnmtdi->hdr.idFrom; - tbgit.lParam = infoPtr->buttons[index].dwData; - - TOOLBAR_SendNotify(&tbgit.hdr, infoPtr, TBN_GETINFOTIPW); - - TRACE("TBN_GETINFOTIPW - got string %s\n", debugstr_w(tbgit.pszText)); - - len = strlenW(tbgit.pszText); - if (len > sizeof(lpnmtdi->szText)/sizeof(lpnmtdi->szText[0])-1) - { - /* need to allocate temporary buffer in infoPtr as there - * isn't enough space in buffer passed to us by the - * tooltip control */ - infoPtr->pszTooltipText = Alloc((len+1)*sizeof(WCHAR)); - if (infoPtr->pszTooltipText) - { - memcpy(infoPtr->pszTooltipText, tbgit.pszText, (len+1)*sizeof(WCHAR)); - lpnmtdi->lpszText = infoPtr->pszTooltipText; - return 0; - } - } - else if (len > 0) - { - memcpy(lpnmtdi->lpszText, tbgit.pszText, (len+1)*sizeof(WCHAR)); - return 0; - } - } - else - { - CHAR szBuffer[INFOTIPSIZE+1]; - NMTBGETINFOTIPA tbgit; - unsigned int len; /* in chars */ - - szBuffer[0] = '\0'; - szBuffer[INFOTIPSIZE] = '\0'; - - tbgit.pszText = szBuffer; - tbgit.cchTextMax = INFOTIPSIZE; - tbgit.iItem = lpnmtdi->hdr.idFrom; - tbgit.lParam = infoPtr->buttons[index].dwData; - - TOOLBAR_SendNotify(&tbgit.hdr, infoPtr, TBN_GETINFOTIPA); - - TRACE("TBN_GETINFOTIPA - got string %s\n", debugstr_a(tbgit.pszText)); - - len = -1 + MultiByteToWideChar(CP_ACP, 0, tbgit.pszText, -1, NULL, 0); - if (len > sizeof(lpnmtdi->szText)/sizeof(lpnmtdi->szText[0])-1) - { - /* need to allocate temporary buffer in infoPtr as there - * isn't enough space in buffer passed to us by the - * tooltip control */ - infoPtr->pszTooltipText = Alloc((len+1)*sizeof(WCHAR)); - if (infoPtr->pszTooltipText) - { - MultiByteToWideChar(CP_ACP, 0, tbgit.pszText, len+1, infoPtr->pszTooltipText, (len+1)*sizeof(WCHAR)); - lpnmtdi->lpszText = infoPtr->pszTooltipText; - return 0; - } - } - else if (len > 0) - { - MultiByteToWideChar(CP_ACP, 0, tbgit.pszText, len+1, lpnmtdi->lpszText, (len+1)*sizeof(WCHAR)); - return 0; - } - } - - /* if button has text, but it is not shown then automatically - * use that text as tooltip */ - if ((infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) && - !(infoPtr->buttons[index].fsStyle & BTNS_SHOWTEXT)) - { - LPWSTR pszText = TOOLBAR_GetText(infoPtr, &infoPtr->buttons[index]); - unsigned int len = pszText ? strlenW(pszText) : 0; - - TRACE("using button hidden text %s\n", debugstr_w(pszText)); - - if (len > sizeof(lpnmtdi->szText)/sizeof(lpnmtdi->szText[0])-1) - { - /* need to allocate temporary buffer in infoPtr as there - * isn't enough space in buffer passed to us by the - * tooltip control */ - infoPtr->pszTooltipText = Alloc((len+1)*sizeof(WCHAR)); - if (infoPtr->pszTooltipText) - { - memcpy(infoPtr->pszTooltipText, pszText, (len+1)*sizeof(WCHAR)); - lpnmtdi->lpszText = infoPtr->pszTooltipText; - return 0; - } - } - else if (len > 0) - { - memcpy(lpnmtdi->lpszText, pszText, (len+1)*sizeof(WCHAR)); - return 0; - } - } - - TRACE("Sending tooltip notification to %p\n", infoPtr->hwndNotify); - - /* last resort: send notification on to app */ - /* FIXME: find out what is really used here */ - return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, 0, (LPARAM)lpnmtdi); -} - - -inline static LRESULT -TOOLBAR_Notify (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - LPNMHDR lpnmh = (LPNMHDR)lParam; - - switch (lpnmh->code) - { - case PGN_CALCSIZE: - { - LPNMPGCALCSIZE lppgc = (LPNMPGCALCSIZE)lParam; - - if (lppgc->dwFlag == PGF_CALCWIDTH) { - lppgc->iWidth = infoPtr->rcBound.right - infoPtr->rcBound.left; - TRACE("processed PGN_CALCSIZE, returning horz size = %d\n", - lppgc->iWidth); - } - else { - lppgc->iHeight = infoPtr->rcBound.bottom - infoPtr->rcBound.top; - TRACE("processed PGN_CALCSIZE, returning vert size = %d\n", - lppgc->iHeight); - } - return 0; - } - - case PGN_SCROLL: - { - LPNMPGSCROLL lppgs = (LPNMPGSCROLL)lParam; - - lppgs->iScroll = (lppgs->iDir & (PGF_SCROLLLEFT | PGF_SCROLLRIGHT)) ? - infoPtr->nButtonWidth : infoPtr->nButtonHeight; - TRACE("processed PGN_SCROLL, returning scroll=%d, dir=%d\n", - lppgs->iScroll, lppgs->iDir); - return 0; - } - - case TTN_GETDISPINFOW: - return TOOLBAR_TTGetDispInfo(infoPtr, (LPNMTTDISPINFOW)lParam); - - case TTN_GETDISPINFOA: - FIXME("TTN_GETDISPINFOA - should not be received; please report\n"); - return 0; - - default: - return 0; - } -} - - -static LRESULT -TOOLBAR_NotifyFormat(TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - LRESULT format; - - TRACE("wParam = 0x%x, lParam = 0x%08lx\n", wParam, lParam); - - if (lParam == NF_QUERY) - return NFR_UNICODE; - - if (lParam == NF_REQUERY) { - format = SendMessageW(infoPtr->hwndNotify, - WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY); - if ((format != NFR_ANSI) && (format != NFR_UNICODE)) { - ERR("wrong response to WM_NOTIFYFORMAT (%ld), assuming ANSI\n", - format); - format = NFR_ANSI; - } - return format; - } - return 0; -} - - -static LRESULT -TOOLBAR_Paint (HWND hwnd, WPARAM wParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd); - HDC hdc; - PAINTSTRUCT ps; - - /* fill ps.rcPaint with a default rect */ - memcpy(&(ps.rcPaint), &(infoPtr->rcBound), sizeof(infoPtr->rcBound)); - - hdc = wParam==0 ? BeginPaint(hwnd, &ps) : (HDC)wParam; - - TRACE("psrect=(%ld,%ld)-(%ld,%ld)\n", - ps.rcPaint.left, ps.rcPaint.top, - ps.rcPaint.right, ps.rcPaint.bottom); - - TOOLBAR_Refresh (hwnd, hdc, &ps); - if (!wParam) EndPaint (hwnd, &ps); - - return 0; -} - - -static LRESULT -TOOLBAR_SetRedraw (HWND hwnd, WPARAM wParam, LPARAM lParam) - /***************************************************** - * - * Function; - * Handles the WM_SETREDRAW message. - * - * Documentation: - * According to testing V4.71 of COMCTL32 returns the - * *previous* status of the redraw flag (either 0 or 1) - * instead of the MSDN documented value of 0 if handled. - * (For laughs see the "consistency" with same function - * in rebar.) - * - *****************************************************/ -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - BOOL oldredraw = infoPtr->bDoRedraw; - - TRACE("set to %s\n", - (wParam) ? "TRUE" : "FALSE"); - infoPtr->bDoRedraw = (BOOL) wParam; - if (wParam) { - InvalidateRect (infoPtr->hwndSelf, 0, TRUE); - } - return (oldredraw) ? 1 : 0; -} - - -static LRESULT -TOOLBAR_Size (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - DWORD dwStyle = infoPtr->dwStyle; - RECT parent_rect; - RECT window_rect; - HWND parent; - INT x, y; - INT cx, cy; - INT flags; - UINT uPosFlags = 0; - - /* Resize deadlock check */ - if (infoPtr->bAutoSize) { - infoPtr->bAutoSize = FALSE; - return 0; - } - - /* FIXME: optimize to only update size if the new size doesn't */ - /* match the current size */ - - flags = (INT) wParam; - - /* FIXME for flags = - * SIZE_MAXIMIZED, SIZE_MAXSHOW, SIZE_MINIMIZED - */ - - TRACE("sizing toolbar!\n"); - - if (flags == SIZE_RESTORED) { - /* width and height don't apply */ - parent = GetParent (hwnd); - GetClientRect(parent, &parent_rect); - x = parent_rect.left; - y = parent_rect.top; - - if (dwStyle & CCS_NORESIZE) { - uPosFlags |= (SWP_NOSIZE | SWP_NOMOVE); - - /* - * this sets the working width of the toolbar, and - * Calc Toolbar will not adjust it, only the height - */ - infoPtr->nWidth = parent_rect.right - parent_rect.left; - cy = infoPtr->nHeight; - cx = infoPtr->nWidth; - TOOLBAR_CalcToolbar (hwnd); - infoPtr->nWidth = cx; - infoPtr->nHeight = cy; - } - else { - infoPtr->nWidth = parent_rect.right - parent_rect.left; - TOOLBAR_CalcToolbar (hwnd); - cy = infoPtr->nHeight; - cx = infoPtr->nWidth; - - if ((dwStyle & CCS_BOTTOM) == CCS_NOMOVEY) { - GetWindowRect(hwnd, &window_rect); - ScreenToClient(parent, (LPPOINT)&window_rect.left); - y = window_rect.top; - } - if ((dwStyle & CCS_BOTTOM) == CCS_BOTTOM) { - GetWindowRect(hwnd, &window_rect); - y = parent_rect.bottom - - ( window_rect.bottom - window_rect.top); - } - } - - if (dwStyle & CCS_NOPARENTALIGN) { - uPosFlags |= SWP_NOMOVE; - cy = infoPtr->nHeight; - cx = infoPtr->nWidth; - } - - if (!(dwStyle & CCS_NODIVIDER)) - cy += GetSystemMetrics(SM_CYEDGE); - - if (dwStyle & WS_BORDER) - { - x = y = 1; - cy += GetSystemMetrics(SM_CYEDGE); - cx += GetSystemMetrics(SM_CXEDGE); - } - - if(infoPtr->dwExStyle & TBSTYLE_EX_HIDECLIPPEDBUTTONS) - { - RECT delta_width, delta_height, client, dummy; - DWORD min_x, max_x, min_y, max_y; - TBUTTON_INFO *btnPtr; - INT i; - - GetClientRect(hwnd, &client); - if(client.right > infoPtr->client_rect.right) - { - min_x = infoPtr->client_rect.right; - max_x = client.right; - } - else - { - max_x = infoPtr->client_rect.right; - min_x = client.right; - } - if(client.bottom > infoPtr->client_rect.bottom) - { - min_y = infoPtr->client_rect.bottom; - max_y = client.bottom; - } - else - { - max_y = infoPtr->client_rect.bottom; - min_y = client.bottom; - } - - SetRect(&delta_width, min_x, 0, max_x, min_y); - SetRect(&delta_height, 0, min_y, max_x, max_y); - - TRACE("delta_width %s delta_height %s\n", wine_dbgstr_rect(&delta_width), wine_dbgstr_rect(&delta_height)); - btnPtr = infoPtr->buttons; - for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) - if(IntersectRect(&dummy, &delta_width, &btnPtr->rect) || - IntersectRect(&dummy, &delta_height, &btnPtr->rect)) - InvalidateRect(hwnd, &btnPtr->rect, TRUE); - } - - if((uPosFlags & (SWP_NOSIZE | SWP_NOMOVE)) != (SWP_NOSIZE | SWP_NOMOVE)) - SetWindowPos (hwnd, 0, x, y, cx, cy, uPosFlags | SWP_NOZORDER); - } - GetClientRect(hwnd, &infoPtr->client_rect); - return 0; -} - - -static LRESULT -TOOLBAR_StyleChanged (HWND hwnd, INT nType, LPSTYLESTRUCT lpStyle) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - if (nType == GWL_STYLE) - { - if (lpStyle->styleNew & TBSTYLE_LIST) - infoPtr->dwDTFlags = DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS; - else - infoPtr->dwDTFlags = DT_CENTER | DT_END_ELLIPSIS; - - infoPtr->bBtnTranspnt = (lpStyle->styleNew & - (TBSTYLE_FLAT | TBSTYLE_LIST)); - TOOLBAR_CheckStyle (hwnd, lpStyle->styleNew); - - TRACE("new style 0x%08lx\n", lpStyle->styleNew); - - infoPtr->dwStyle = lpStyle->styleNew; - - /* only resize if one of the CCS_* styles was changed */ - if ((infoPtr->dwStyle ^ lpStyle->styleNew) & COMMON_STYLES) - { - TOOLBAR_AutoSize (hwnd); - - InvalidateRect(hwnd, NULL, TRUE); - } - } - - return 0; -} - - -static LRESULT -TOOLBAR_SysColorChange (HWND hwnd) -{ - COMCTL32_RefreshSysColors(); - - return 0; -} - - - -static LRESULT WINAPI -ToolbarWindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); - - TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", - hwnd, uMsg, /* SPY_GetMsgName(uMsg), */ wParam, lParam); - - if (!infoPtr && (uMsg != WM_NCCREATE)) - return DefWindowProcW( hwnd, uMsg, wParam, lParam ); - - switch (uMsg) - { - case TB_ADDBITMAP: - return TOOLBAR_AddBitmap (hwnd, wParam, lParam); - - case TB_ADDBUTTONSA: - return TOOLBAR_AddButtonsA (hwnd, wParam, lParam); - - case TB_ADDBUTTONSW: - return TOOLBAR_AddButtonsW (hwnd, wParam, lParam); - - case TB_ADDSTRINGA: - return TOOLBAR_AddStringA (hwnd, wParam, lParam); - - case TB_ADDSTRINGW: - return TOOLBAR_AddStringW (hwnd, wParam, lParam); - - case TB_AUTOSIZE: - return TOOLBAR_AutoSize (hwnd); - - case TB_BUTTONCOUNT: - return TOOLBAR_ButtonCount (hwnd, wParam, lParam); - - case TB_BUTTONSTRUCTSIZE: - return TOOLBAR_ButtonStructSize (hwnd, wParam, lParam); - - case TB_CHANGEBITMAP: - return TOOLBAR_ChangeBitmap (hwnd, wParam, lParam); - - case TB_CHECKBUTTON: - return TOOLBAR_CheckButton (hwnd, wParam, lParam); - - case TB_COMMANDTOINDEX: - return TOOLBAR_CommandToIndex (hwnd, wParam, lParam); - - case TB_CUSTOMIZE: - return TOOLBAR_Customize (hwnd); - - case TB_DELETEBUTTON: - return TOOLBAR_DeleteButton (hwnd, wParam, lParam); - - case TB_ENABLEBUTTON: - return TOOLBAR_EnableButton (hwnd, wParam, lParam); - - case TB_GETANCHORHIGHLIGHT: - return TOOLBAR_GetAnchorHighlight (hwnd); - - case TB_GETBITMAP: - return TOOLBAR_GetBitmap (hwnd, wParam, lParam); - - case TB_GETBITMAPFLAGS: - return TOOLBAR_GetBitmapFlags (hwnd, wParam, lParam); - - case TB_GETBUTTON: - return TOOLBAR_GetButton (hwnd, wParam, lParam); - - case TB_GETBUTTONINFOA: - return TOOLBAR_GetButtonInfoA (hwnd, wParam, lParam); - - case TB_GETBUTTONINFOW: - return TOOLBAR_GetButtonInfoW (hwnd, wParam, lParam); - - case TB_GETBUTTONSIZE: - return TOOLBAR_GetButtonSize (hwnd); - - case TB_GETBUTTONTEXTA: - return TOOLBAR_GetButtonTextA (hwnd, wParam, lParam); - - case TB_GETBUTTONTEXTW: - return TOOLBAR_GetButtonTextW (hwnd, wParam, lParam); - - case TB_GETDISABLEDIMAGELIST: - return TOOLBAR_GetDisabledImageList (hwnd, wParam, lParam); - - case TB_GETEXTENDEDSTYLE: - return TOOLBAR_GetExtendedStyle (hwnd); - - case TB_GETHOTIMAGELIST: - return TOOLBAR_GetHotImageList (hwnd, wParam, lParam); - - case TB_GETHOTITEM: - return TOOLBAR_GetHotItem (hwnd); - - case TB_GETIMAGELIST: - return TOOLBAR_GetDefImageList (hwnd, wParam, lParam); - - case TB_GETINSERTMARK: - return TOOLBAR_GetInsertMark (hwnd, wParam, lParam); - - case TB_GETINSERTMARKCOLOR: - return TOOLBAR_GetInsertMarkColor (hwnd, wParam, lParam); - - case TB_GETITEMRECT: - return TOOLBAR_GetItemRect (hwnd, wParam, lParam); - - case TB_GETMAXSIZE: - return TOOLBAR_GetMaxSize (hwnd, wParam, lParam); - -/* case TB_GETOBJECT: */ /* 4.71 */ - - case TB_GETPADDING: - return TOOLBAR_GetPadding (hwnd); - - case TB_GETRECT: - return TOOLBAR_GetRect (hwnd, wParam, lParam); - - case TB_GETROWS: - return TOOLBAR_GetRows (hwnd, wParam, lParam); - - case TB_GETSTATE: - return TOOLBAR_GetState (hwnd, wParam, lParam); - - case TB_GETSTRINGA: - return TOOLBAR_GetStringA (hwnd, wParam, lParam); - - case TB_GETSTRINGW: - return TOOLBAR_GetStringW (hwnd, wParam, lParam); - - case TB_GETSTYLE: - return TOOLBAR_GetStyle (hwnd, wParam, lParam); - - case TB_GETTEXTROWS: - return TOOLBAR_GetTextRows (hwnd, wParam, lParam); - - case TB_GETTOOLTIPS: - return TOOLBAR_GetToolTips (hwnd, wParam, lParam); - - case TB_GETUNICODEFORMAT: - return TOOLBAR_GetUnicodeFormat (hwnd, wParam, lParam); - - case TB_HIDEBUTTON: - return TOOLBAR_HideButton (hwnd, wParam, lParam); - - case TB_HITTEST: - return TOOLBAR_HitTest (hwnd, wParam, lParam); - - case TB_INDETERMINATE: - return TOOLBAR_Indeterminate (hwnd, wParam, lParam); - - case TB_INSERTBUTTONA: - return TOOLBAR_InsertButtonA (hwnd, wParam, lParam); - - case TB_INSERTBUTTONW: - return TOOLBAR_InsertButtonW (hwnd, wParam, lParam); - -/* case TB_INSERTMARKHITTEST: */ /* 4.71 */ - - case TB_ISBUTTONCHECKED: - return TOOLBAR_IsButtonChecked (hwnd, wParam, lParam); - - case TB_ISBUTTONENABLED: - return TOOLBAR_IsButtonEnabled (hwnd, wParam, lParam); - - case TB_ISBUTTONHIDDEN: - return TOOLBAR_IsButtonHidden (hwnd, wParam, lParam); - - case TB_ISBUTTONHIGHLIGHTED: - return TOOLBAR_IsButtonHighlighted (hwnd, wParam, lParam); - - case TB_ISBUTTONINDETERMINATE: - return TOOLBAR_IsButtonIndeterminate (hwnd, wParam, lParam); - - case TB_ISBUTTONPRESSED: - return TOOLBAR_IsButtonPressed (hwnd, wParam, lParam); - - case TB_LOADIMAGES: - return TOOLBAR_LoadImages (hwnd, wParam, lParam); - - case TB_MAPACCELERATORA: - case TB_MAPACCELERATORW: - return TOOLBAR_MapAccelerator (hwnd, wParam, lParam); - - case TB_MARKBUTTON: - return TOOLBAR_MarkButton (hwnd, wParam, lParam); - - case TB_MOVEBUTTON: - return TOOLBAR_MoveButton (hwnd, wParam, lParam); - - case TB_PRESSBUTTON: - return TOOLBAR_PressButton (hwnd, wParam, lParam); - - case TB_REPLACEBITMAP: - return TOOLBAR_ReplaceBitmap (hwnd, wParam, lParam); - - case TB_SAVERESTOREA: - return TOOLBAR_SaveRestoreA (hwnd, wParam, (LPTBSAVEPARAMSA)lParam); - - case TB_SAVERESTOREW: - return TOOLBAR_SaveRestoreW (hwnd, wParam, (LPTBSAVEPARAMSW)lParam); - - case TB_SETANCHORHIGHLIGHT: - return TOOLBAR_SetAnchorHighlight (hwnd, wParam); - - case TB_SETBITMAPSIZE: - return TOOLBAR_SetBitmapSize (hwnd, wParam, lParam); - - case TB_SETBUTTONINFOA: - return TOOLBAR_SetButtonInfoA (hwnd, wParam, lParam); - - case TB_SETBUTTONINFOW: - return TOOLBAR_SetButtonInfoW (hwnd, wParam, lParam); - - case TB_SETBUTTONSIZE: - return TOOLBAR_SetButtonSize (hwnd, wParam, lParam); - - case TB_SETBUTTONWIDTH: - return TOOLBAR_SetButtonWidth (hwnd, wParam, lParam); - - case TB_SETCMDID: - return TOOLBAR_SetCmdId (hwnd, wParam, lParam); - - case TB_SETDISABLEDIMAGELIST: - return TOOLBAR_SetDisabledImageList (hwnd, wParam, lParam); - - case TB_SETDRAWTEXTFLAGS: - return TOOLBAR_SetDrawTextFlags (hwnd, wParam, lParam); - - case TB_SETEXTENDEDSTYLE: - return TOOLBAR_SetExtendedStyle (hwnd, wParam, lParam); - - case TB_SETHOTIMAGELIST: - return TOOLBAR_SetHotImageList (hwnd, wParam, lParam); - - case TB_SETHOTITEM: - return TOOLBAR_SetHotItem (hwnd, wParam); - - case TB_SETIMAGELIST: - return TOOLBAR_SetImageList (hwnd, wParam, lParam); - - case TB_SETINDENT: - return TOOLBAR_SetIndent (hwnd, wParam, lParam); - - case TB_SETINSERTMARK: - return TOOLBAR_SetInsertMark (hwnd, wParam, lParam); - - case TB_SETINSERTMARKCOLOR: - return TOOLBAR_SetInsertMarkColor (hwnd, wParam, lParam); - - case TB_SETMAXTEXTROWS: - return TOOLBAR_SetMaxTextRows (hwnd, wParam, lParam); - - case TB_SETPADDING: - return TOOLBAR_SetPadding (hwnd, wParam, lParam); - - case TB_SETPARENT: - return TOOLBAR_SetParent (hwnd, wParam, lParam); - - case TB_SETROWS: - return TOOLBAR_SetRows (hwnd, wParam, lParam); - - case TB_SETSTATE: - return TOOLBAR_SetState (hwnd, wParam, lParam); - - case TB_SETSTYLE: - return TOOLBAR_SetStyle (hwnd, wParam, lParam); - - case TB_SETTOOLTIPS: - return TOOLBAR_SetToolTips (hwnd, wParam, lParam); - - case TB_SETUNICODEFORMAT: - return TOOLBAR_SetUnicodeFormat (hwnd, wParam, lParam); - - case TB_UNKWN45D: - return TOOLBAR_Unkwn45D(hwnd, wParam, lParam); - - case TB_UNKWN45E: - return TOOLBAR_Unkwn45E (hwnd, wParam, lParam); - - case TB_UNKWN460: - return TOOLBAR_Unkwn460(hwnd, wParam, lParam); - - case TB_UNKWN462: - return TOOLBAR_Unkwn462(hwnd, wParam, lParam); - - case TB_UNKWN463: - return TOOLBAR_Unkwn463 (hwnd, wParam, lParam); - - case TB_UNKWN464: - return TOOLBAR_Unkwn464(hwnd, wParam, lParam); - -/* Common Control Messages */ - -/* case TB_GETCOLORSCHEME: */ /* identical to CCM_ */ - case CCM_GETCOLORSCHEME: - return TOOLBAR_GetColorScheme (hwnd, (LPCOLORSCHEME)lParam); - -/* case TB_SETCOLORSCHEME: */ /* identical to CCM_ */ - case CCM_SETCOLORSCHEME: - return TOOLBAR_SetColorScheme (hwnd, (LPCOLORSCHEME)lParam); - - case CCM_GETVERSION: - return TOOLBAR_GetVersion (hwnd); - - case CCM_SETVERSION: - return TOOLBAR_SetVersion (hwnd, (INT)wParam); - - -/* case WM_CHAR: */ - - case WM_CREATE: - return TOOLBAR_Create (hwnd, wParam, lParam); - - case WM_DESTROY: - return TOOLBAR_Destroy (hwnd, wParam, lParam); - - case WM_ERASEBKGND: - return TOOLBAR_EraseBackground (hwnd, wParam, lParam); - - case WM_GETFONT: - return TOOLBAR_GetFont (hwnd, wParam, lParam); - -/* case WM_KEYDOWN: */ -/* case WM_KILLFOCUS: */ - - case WM_LBUTTONDBLCLK: - return TOOLBAR_LButtonDblClk (hwnd, wParam, lParam); - - case WM_LBUTTONDOWN: - return TOOLBAR_LButtonDown (hwnd, wParam, lParam); - - case WM_LBUTTONUP: - return TOOLBAR_LButtonUp (hwnd, wParam, lParam); - - case WM_RBUTTONUP: - return TOOLBAR_RButtonUp (hwnd, wParam, lParam); - - case WM_RBUTTONDBLCLK: - return TOOLBAR_RButtonDblClk (hwnd, wParam, lParam); - - case WM_MOUSEMOVE: - return TOOLBAR_MouseMove (hwnd, wParam, lParam); - - case WM_MOUSELEAVE: - return TOOLBAR_MouseLeave (hwnd, wParam, lParam); - - case WM_CAPTURECHANGED: - return TOOLBAR_CaptureChanged(hwnd); - - case WM_NCACTIVATE: - return TOOLBAR_NCActivate (hwnd, wParam, lParam); - - case WM_NCCALCSIZE: - return TOOLBAR_NCCalcSize (hwnd, wParam, lParam); - - case WM_NCCREATE: - return TOOLBAR_NCCreate (hwnd, wParam, lParam); - - case WM_NCPAINT: - return TOOLBAR_NCPaint (hwnd, wParam, lParam); - - case WM_NOTIFY: - return TOOLBAR_Notify (hwnd, wParam, lParam); - - case WM_NOTIFYFORMAT: - return TOOLBAR_NotifyFormat (infoPtr, wParam, lParam); - - case WM_PAINT: - return TOOLBAR_Paint (hwnd, wParam); - - case WM_SETREDRAW: - return TOOLBAR_SetRedraw (hwnd, wParam, lParam); - - case WM_SIZE: - return TOOLBAR_Size (hwnd, wParam, lParam); - - case WM_STYLECHANGED: - return TOOLBAR_StyleChanged (hwnd, (INT)wParam, (LPSTYLESTRUCT)lParam); - - case WM_SYSCOLORCHANGE: - return TOOLBAR_SysColorChange (hwnd); - -/* case WM_WININICHANGE: */ - - case WM_CHARTOITEM: - case WM_COMMAND: - case WM_DRAWITEM: - case WM_MEASUREITEM: - case WM_VKEYTOITEM: - return SendMessageW (infoPtr->hwndNotify, uMsg, wParam, lParam); - - /* We see this in Outlook Express 5.x and just does DefWindowProc */ - case PGM_FORWARDMOUSE: - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - - default: - if ((uMsg >= WM_USER) && (uMsg < WM_APP)) - ERR("unknown msg %04x wp=%08x lp=%08lx\n", - uMsg, wParam, lParam); - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - } -} - - -VOID -TOOLBAR_Register (void) -{ - WNDCLASSW wndClass; - - ZeroMemory (&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS; - wndClass.lpfnWndProc = ToolbarWindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(TOOLBAR_INFO *); - wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); - wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); - wndClass.lpszClassName = TOOLBARCLASSNAMEW; - - RegisterClassW (&wndClass); -} - - -VOID -TOOLBAR_Unregister (void) -{ - UnregisterClassW (TOOLBARCLASSNAMEW, NULL); -} - -static HIMAGELIST TOOLBAR_InsertImageList(PIMLENTRY **pies, INT *cies, HIMAGELIST himl, INT id) -{ - HIMAGELIST himlold; - PIMLENTRY c = NULL; - - /* Check if the entry already exists */ - c = TOOLBAR_GetImageListEntry(*pies, *cies, id); - - /* If this is a new entry we must create it and insert into the array */ - if (!c) - { - PIMLENTRY *pnies; - - c = (PIMLENTRY) Alloc(sizeof(IMLENTRY)); - c->id = id; - - pnies = Alloc((*cies + 1) * sizeof(PIMLENTRY)); - memcpy(pnies, *pies, ((*cies) * sizeof(PIMLENTRY))); - pnies[*cies] = c; - (*cies)++; - - Free(*pies); - *pies = pnies; - } - - himlold = c->himl; - c->himl = himl; - - return himlold; -} - - -static VOID TOOLBAR_DeleteImageList(PIMLENTRY **pies, INT *cies) -{ - int i; - - for (i = 0; i < *cies; i++) - Free((*pies)[i]); - - Free(*pies); - - *cies = 0; - *pies = NULL; -} - - -static PIMLENTRY TOOLBAR_GetImageListEntry(PIMLENTRY *pies, INT cies, INT id) -{ - PIMLENTRY c = NULL; - - if (pies != NULL) - { - int i; - - for (i = 0; i < cies; i++) - { - if (pies[i]->id == id) - { - c = pies[i]; - break; - } - } - } - - return c; -} - - -static HIMAGELIST TOOLBAR_GetImageList(PIMLENTRY *pies, INT cies, INT id) -{ - HIMAGELIST himlDef = 0; - PIMLENTRY pie = TOOLBAR_GetImageListEntry(pies, cies, id); - - if (pie) - himlDef = pie->himl; - - return himlDef; -} - - -static BOOL TOOLBAR_GetButtonInfo(TOOLBAR_INFO *infoPtr, NMTOOLBARW *nmtb) -{ - if (infoPtr->bUnicode) - return TOOLBAR_SendNotify(&nmtb->hdr, infoPtr, TBN_GETBUTTONINFOW); - else - { - CHAR Buffer[256]; - NMTOOLBARA nmtba; - BOOL bRet = FALSE; - - nmtba.iItem = nmtb->iItem; - nmtba.pszText = Buffer; - nmtba.cchText = 256; - ZeroMemory(nmtba.pszText, nmtba.cchText); - - if (TOOLBAR_SendNotify(&nmtba.hdr, infoPtr, TBN_GETBUTTONINFOA)) - { - int ccht = strlen(nmtba.pszText); - if (ccht) - MultiByteToWideChar(CP_ACP, 0, (LPCSTR)nmtba.pszText, -1, - nmtb->pszText, nmtb->cchText); - - memcpy(&nmtb->tbButton, &nmtba.tbButton, sizeof(TBBUTTON)); - bRet = TRUE; - } - - return bRet; - } -} - - -static BOOL TOOLBAR_IsButtonRemovable(TOOLBAR_INFO *infoPtr, - int iItem, PCUSTOMBUTTON btnInfo) -{ - NMTOOLBARW nmtb; - - /* MSDN states that iItem is the index of the button, rather than the - * command ID as used by every other NMTOOLBAR notification */ - nmtb.iItem = iItem; - memcpy(&nmtb.tbButton, &btnInfo->btn, sizeof(TBBUTTON)); - - return TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_QUERYDELETE); -} +/* + * Toolbar control + * + * Copyright 1998,1999 Eric Kohl + * Copyright 2000 Eric Kohl for CodeWeavers + * Copyright 2004 Robert Shearman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES + * + * This code was audited for completeness against the documented features + * of Comctl32.dll version 6.0 on Mar. 14, 2004, by Robert Shearman. + * + * Unless otherwise noted, we believe this code to be complete, as per + * the specification mentioned above. + * If you discover missing features or bugs please note them below. + * + * TODO: + * - Styles: + * - TBSTYLE_REGISTERDROP + * - TBSTYLE_EX_DOUBLEBUFFER + * - Messages: + * - TB_GETMETRICS + * - TB_GETOBJECT + * - TB_INSERTMARKHITTEST + * - TB_SAVERESTORE + * - TB_SETMETRICS + * - WM_WININICHANGE + * - Notifications: + * - NM_CHAR + * - NM_KEYDOWN + * - TBN_GETOBJECT + * - TBN_SAVE + * - Button wrapping (under construction). + * - Fix TB_SETROWS. + * - iListGap custom draw support. + * + * Testing: + * - Run tests using Waite Group Windows95 API Bible Volume 2. + * The second cdrom contains executables addstr.exe, btncount.exe, + * btnstate.exe, butstrsz.exe, chkbtn.exe, chngbmp.exe, customiz.exe, + * enablebtn.exe, getbmp.exe, getbtn.exe, getflags.exe, hidebtn.exe, + * indetbtn.exe, insbtn.exe, pressbtn.exe, setbtnsz.exe, setcmdid.exe, + * setparnt.exe, setrows.exe, toolwnd.exe. + * - Microsoft's controlspy examples. + * - Charles Petzold's 'Programming Windows': gadgets.exe + * + * Differences between MSDN and actual native control operation: + * 1. MSDN says: "TBSTYLE_LIST: Creates a flat toolbar with button text + * to the right of the bitmap. Otherwise, this style is + * identical to TBSTYLE_FLAT." + * As implemented by both v4.71 and v5.80 of the native COMCTL32.DLL + * you can create a TBSTYLE_LIST without TBSTYLE_FLAT and the result + * is non-flat non-transparent buttons. Therefore TBSTYLE_LIST does + * *not* imply TBSTYLE_FLAT as documented. (GA 8/2001) + * + */ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "wingdi.h" +#include "winuser.h" +#include "wine/unicode.h" +#include "winnls.h" +#include "commctrl.h" +#include "comctl32.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(toolbar); + +static HCURSOR hCursorDrag = NULL; + +typedef struct +{ + INT iBitmap; + INT idCommand; + BYTE fsState; + BYTE fsStyle; + BYTE bHot; + BYTE bDropDownPressed; + DWORD dwData; + INT iString; + INT nRow; + RECT rect; + INT cx; /* manually set size */ +} TBUTTON_INFO; + +typedef struct +{ + UINT nButtons; + HINSTANCE hInst; + UINT nID; +} TBITMAP_INFO; + +typedef struct +{ + HIMAGELIST himl; + INT id; +} IMLENTRY, *PIMLENTRY; + +typedef struct +{ + DWORD dwStructSize; /* size of TBBUTTON struct */ + INT nHeight; /* height of the toolbar */ + INT nWidth; /* width of the toolbar */ + RECT client_rect; + RECT rcBound; /* bounding rectangle */ + INT nButtonHeight; + INT nButtonWidth; + INT nBitmapHeight; + INT nBitmapWidth; + INT nIndent; + INT nRows; /* number of button rows */ + INT nMaxTextRows; /* maximum number of text rows */ + INT cxMin; /* minimum button width */ + INT cxMax; /* maximum button width */ + INT nNumButtons; /* number of buttons */ + INT nNumBitmaps; /* number of bitmaps */ + INT nNumStrings; /* number of strings */ + INT nNumBitmapInfos; + INT nButtonDown; /* toolbar button being pressed or -1 if none */ + INT nButtonDrag; /* toolbar button being dragged or -1 if none */ + INT nOldHit; + INT nHotItem; /* index of the "hot" item */ + DWORD dwBaseCustDraw; /* CDRF_ response (w/o TBCDRF_) from PREPAINT */ + DWORD dwItemCustDraw; /* CDRF_ response (w/o TBCDRF_) from ITEMPREP */ + DWORD dwItemCDFlag; /* TBCDRF_ flags from last ITEMPREPAINT */ + SIZE szPadding; /* padding values around button */ + INT iListGap; /* default gap between text and image for toolbar with list style */ + HFONT hDefaultFont; + HFONT hFont; /* text font */ + HIMAGELIST himlInt; /* image list created internally */ + PIMLENTRY *himlDef; /* default image list array */ + INT cimlDef; /* default image list array count */ + PIMLENTRY *himlHot; /* hot image list array */ + INT cimlHot; /* hot image list array count */ + PIMLENTRY *himlDis; /* disabled image list array */ + INT cimlDis; /* disabled image list array count */ + HWND hwndToolTip; /* handle to tool tip control */ + HWND hwndNotify; /* handle to the window that gets notifications */ + HWND hwndSelf; /* my own handle */ + BOOL bBtnTranspnt; /* button transparency flag */ + BOOL bAutoSize; /* auto size deadlock indicator */ + BOOL bAnchor; /* anchor highlight enabled */ + BOOL bDoRedraw; /* Redraw status */ + BOOL bDragOutSent; /* has TBN_DRAGOUT notification been sent for this drag? */ + BOOL bUnicode; /* Notifications are ASCII (FALSE) or Unicode (TRUE)? */ + BOOL bCaptured; /* mouse captured? */ + DWORD dwStyle; /* regular toolbar style */ + DWORD dwExStyle; /* extended toolbar style */ + DWORD dwDTFlags; /* DrawText flags */ + + COLORREF clrInsertMark; /* insert mark color */ + COLORREF clrBtnHighlight; /* color for Flat Separator */ + COLORREF clrBtnShadow; /* color for Flag Separator */ + INT iVersion; + LPWSTR pszTooltipText; /* temporary store for a string > 80 characters + * for TTN_GETDISPINFOW notification */ + TBINSERTMARK tbim; /* info on insertion mark */ + TBUTTON_INFO *buttons; /* pointer to button array */ + LPWSTR *strings; /* pointer to string array */ + TBITMAP_INFO *bitmaps; +} TOOLBAR_INFO, *PTOOLBAR_INFO; + + +/* used by customization dialog */ +typedef struct +{ + PTOOLBAR_INFO tbInfo; + HWND tbHwnd; +} CUSTDLG_INFO, *PCUSTDLG_INFO; + +typedef struct +{ + TBBUTTON btn; + BOOL bVirtual; + BOOL bRemovable; + WCHAR text[64]; +} CUSTOMBUTTON, *PCUSTOMBUTTON; + +typedef enum +{ + IMAGE_LIST_DEFAULT, + IMAGE_LIST_HOT, + IMAGE_LIST_DISABLED +} IMAGE_LIST_TYPE; + +#define SEPARATOR_WIDTH 8 +#define TOP_BORDER 2 +#define BOTTOM_BORDER 2 +#define DDARROW_WIDTH 11 +#define ARROW_HEIGHT 3 +#define INSERTMARK_WIDTH 2 + +#define DEFPAD_CX 7 +#define DEFPAD_CY 6 +#define DEFLISTGAP 4 + +/* vertical padding used in list mode when image is present */ +#define LISTPAD_CY 9 + +/* how wide to treat the bitmap if it isn't present */ +#define NONLIST_NOTEXT_OFFSET 2 + +#define TOOLBAR_NOWHERE (-1) + +#define TOOLBAR_GetInfoPtr(hwnd) ((TOOLBAR_INFO *)GetWindowLongPtrW(hwnd,0)) +#define TOOLBAR_HasText(x, y) (TOOLBAR_GetText(x, y) ? TRUE : FALSE) +#define TOOLBAR_HasDropDownArrows(exStyle) ((exStyle & TBSTYLE_EX_DRAWDDARROWS) ? TRUE : FALSE) + +/* Used to find undocumented extended styles */ +#define TBSTYLE_EX_ALL (TBSTYLE_EX_DRAWDDARROWS | \ + TBSTYLE_EX_UNDOC1 | \ + TBSTYLE_EX_MIXEDBUTTONS | \ + TBSTYLE_EX_HIDECLIPPEDBUTTONS) + +/* all of the CCS_ styles */ +#define COMMON_STYLES (CCS_TOP|CCS_NOMOVEY|CCS_BOTTOM|CCS_NORESIZE| \ + CCS_NOPARENTALIGN|CCS_ADJUSTABLE|CCS_NODIVIDER|CCS_VERT) + +#define GETIBITMAP(infoPtr, i) (infoPtr->iVersion >= 5 ? LOWORD(i) : i) +#define GETHIMLID(infoPtr, i) (infoPtr->iVersion >= 5 ? HIWORD(i) : 0) +#define GETDEFIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlDef, infoPtr->cimlDef, id) +#define GETHOTIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlHot, infoPtr->cimlHot, id) +#define GETDISIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlDis, infoPtr->cimlDis, id) + +static BOOL TOOLBAR_GetButtonInfo(TOOLBAR_INFO *infoPtr, NMTOOLBARW *nmtb); +static BOOL TOOLBAR_IsButtonRemovable(TOOLBAR_INFO *infoPtr, int iItem, PCUSTOMBUTTON btnInfo); +static HIMAGELIST TOOLBAR_GetImageList(PIMLENTRY *pies, INT cies, INT id); +static PIMLENTRY TOOLBAR_GetImageListEntry(PIMLENTRY *pies, INT cies, INT id); +static VOID TOOLBAR_DeleteImageList(PIMLENTRY **pies, INT *cies); +static HIMAGELIST TOOLBAR_InsertImageList(PIMLENTRY **pies, INT *cies, HIMAGELIST himl, INT id); +static LRESULT TOOLBAR_LButtonDown(HWND hwnd, WPARAM wParam, LPARAM lParam); +static void TOOLBAR_SetHotItemEx (TOOLBAR_INFO *infoPtr, INT nHit, DWORD dwReason); + +static LRESULT +TOOLBAR_NotifyFormat(TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam); + + +static LPWSTR +TOOLBAR_GetText(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr) +{ + LPWSTR lpText = NULL; + + /* NOTE: iString == -1 is undocumented */ + if ((HIWORD(btnPtr->iString) != 0) && (btnPtr->iString != -1)) + lpText = (LPWSTR)btnPtr->iString; + else if ((btnPtr->iString >= 0) && (btnPtr->iString < infoPtr->nNumStrings)) + lpText = infoPtr->strings[btnPtr->iString]; + + return lpText; +} + +static void +TOOLBAR_DumpButton(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *bP, INT btn_num, BOOL internal) +{ + if (TRACE_ON(toolbar)){ + TRACE("button %d id %d, bitmap=%d, state=%02x, style=%02x, data=%08lx, stringid=0x%08x\n", + btn_num, bP->idCommand, GETIBITMAP(infoPtr, bP->iBitmap), + bP->fsState, bP->fsStyle, bP->dwData, bP->iString); + TRACE("string %s\n", debugstr_w(TOOLBAR_GetText(infoPtr,bP))); + if (internal) + TRACE("button %d id %d, hot=%s, row=%d, rect=(%ld,%ld)-(%ld,%ld)\n", + btn_num, bP->idCommand, + (bP->bHot) ? "TRUE":"FALSE", bP->nRow, + bP->rect.left, bP->rect.top, + bP->rect.right, bP->rect.bottom); + } +} + + +static void +TOOLBAR_DumpToolbar(TOOLBAR_INFO *iP, INT line) +{ + if (TRACE_ON(toolbar)) { + INT i; + + TRACE("toolbar %p at line %d, exStyle=%08lx, buttons=%d, bitmaps=%d, strings=%d, style=%08lx\n", + iP->hwndSelf, line, + iP->dwExStyle, iP->nNumButtons, iP->nNumBitmaps, + iP->nNumStrings, iP->dwStyle); + TRACE("toolbar %p at line %d, himlInt=%p, himlDef=%p, himlHot=%p, himlDis=%p, redrawable=%s\n", + iP->hwndSelf, line, + iP->himlInt, iP->himlDef, iP->himlHot, iP->himlDis, + (iP->bDoRedraw) ? "TRUE" : "FALSE"); + for(i=0; inNumButtons; i++) { + TOOLBAR_DumpButton(iP, &iP->buttons[i], i, TRUE); + } + } +} + + +/*********************************************************************** +* TOOLBAR_CheckStyle +* +* This function validates that the styles set are implemented and +* issues FIXME's warning of possible problems. In a perfect world this +* function should be null. +*/ +static void +TOOLBAR_CheckStyle (HWND hwnd, DWORD dwStyle) +{ + if (dwStyle & TBSTYLE_REGISTERDROP) + FIXME("[%p] TBSTYLE_REGISTERDROP not implemented\n", hwnd); +} + + +static INT +TOOLBAR_SendNotify (NMHDR *nmhdr, TOOLBAR_INFO *infoPtr, UINT code) +{ + if(!IsWindow(infoPtr->hwndSelf)) + return 0; /* we have just been destroyed */ + + nmhdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf); + nmhdr->hwndFrom = infoPtr->hwndSelf; + nmhdr->code = code; + + TRACE("to window %p, code=%08x, %s\n", infoPtr->hwndNotify, code, + (infoPtr->bUnicode) ? "via Unicode" : "via ANSI"); + + return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, + (WPARAM)nmhdr->idFrom, (LPARAM)nmhdr); +} + +/*********************************************************************** +* TOOLBAR_GetBitmapIndex +* +* This function returns the bitmap index associated with a button. +* If the button specifies I_IMAGECALLBACK, then the TBN_GETDISPINFO +* is issued to retrieve the index. +*/ +static INT +TOOLBAR_GetBitmapIndex(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr) +{ + INT ret = btnPtr->iBitmap; + + if (ret == I_IMAGECALLBACK) + { + /* issue TBN_GETDISPINFO */ + NMTBDISPINFOA nmgd; + + memset(&nmgd, 0, sizeof(nmgd)); + nmgd.idCommand = btnPtr->idCommand; + nmgd.lParam = btnPtr->dwData; + nmgd.dwMask = TBNF_IMAGE; + TOOLBAR_SendNotify(&nmgd.hdr, infoPtr, + infoPtr->bUnicode ? TBN_GETDISPINFOW : TBN_GETDISPINFOA); + if (nmgd.dwMask & TBNF_DI_SETITEM) + btnPtr->iBitmap = nmgd.iImage; + ret = nmgd.iImage; + TRACE("TBN_GETDISPINFO returned bitmap id %d, mask=%08lx, nNumBitmaps=%d\n", + ret, nmgd.dwMask, infoPtr->nNumBitmaps); + } + + if (ret != I_IMAGENONE) + ret = GETIBITMAP(infoPtr, ret); + + return ret; +} + + +static BOOL +TOOLBAR_IsValidBitmapIndex(TOOLBAR_INFO *infoPtr, INT index) +{ + HIMAGELIST himl; + INT id = GETHIMLID(infoPtr, index); + INT iBitmap = GETIBITMAP(infoPtr, index); + + if (((himl = GETDEFIMAGELIST(infoPtr, id)) && + iBitmap >= 0 && iBitmap < ImageList_GetImageCount(himl)) || + (index == I_IMAGECALLBACK)) + return TRUE; + else + return FALSE; +} + + +static inline BOOL +TOOLBAR_IsValidImageList(TOOLBAR_INFO *infoPtr, INT index) +{ + HIMAGELIST himl = GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr, index)); + return (himl != NULL) && (ImageList_GetImageCount(himl) > 0); +} + + +/*********************************************************************** +* TOOLBAR_GetImageListForDrawing +* +* This function validates the bitmap index (including I_IMAGECALLBACK +* functionality) and returns the corresponding image list. +*/ +static HIMAGELIST +TOOLBAR_GetImageListForDrawing (TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, IMAGE_LIST_TYPE imagelist, INT * index) +{ + HIMAGELIST himl; + + if (!TOOLBAR_IsValidBitmapIndex(infoPtr,btnPtr->iBitmap)) { + if (btnPtr->iBitmap == I_IMAGENONE) return NULL; + ERR("bitmap for ID %d, index %d is not valid, number of bitmaps in imagelist: %d\n", + HIWORD(btnPtr->iBitmap), LOWORD(btnPtr->iBitmap), infoPtr->nNumBitmaps); + return NULL; + } + + if ((*index = TOOLBAR_GetBitmapIndex(infoPtr, btnPtr)) < 0) { + if ((*index == I_IMAGECALLBACK) || + (*index == I_IMAGENONE)) return NULL; + ERR("TBN_GETDISPINFO returned invalid index %d\n", + *index); + return NULL; + } + + switch(imagelist) + { + case IMAGE_LIST_DEFAULT: + himl = GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr, btnPtr->iBitmap)); + break; + case IMAGE_LIST_HOT: + himl = GETHOTIMAGELIST(infoPtr, GETHIMLID(infoPtr, btnPtr->iBitmap)); + break; + case IMAGE_LIST_DISABLED: + himl = GETDISIMAGELIST(infoPtr, GETHIMLID(infoPtr, btnPtr->iBitmap)); + break; + default: + himl = NULL; + FIXME("Shouldn't reach here\n"); + } + + if (!himl) + TRACE("no image list\n"); + + return himl; +} + + +static void +TOOLBAR_DrawFlatSeparator (LPRECT lpRect, HDC hdc, TOOLBAR_INFO *infoPtr) +{ + RECT myrect; + COLORREF oldcolor, newcolor; + + myrect.left = (lpRect->left + lpRect->right) / 2 - 1; + myrect.right = myrect.left + 1; + myrect.top = lpRect->top + 2; + myrect.bottom = lpRect->bottom - 2; + + newcolor = (infoPtr->clrBtnShadow == CLR_DEFAULT) ? + comctl32_color.clrBtnShadow : infoPtr->clrBtnShadow; + oldcolor = SetBkColor (hdc, newcolor); + ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0); + + myrect.left = myrect.right; + myrect.right = myrect.left + 1; + + newcolor = (infoPtr->clrBtnHighlight == CLR_DEFAULT) ? + comctl32_color.clrBtnHighlight : infoPtr->clrBtnHighlight; + SetBkColor (hdc, newcolor); + ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0); + + SetBkColor (hdc, oldcolor); +} + + +/*********************************************************************** +* TOOLBAR_DrawDDFlatSeparator +* +* This function draws the separator that was flagged as BTNS_DROPDOWN. +* In this case, the separator is a pixel high line of COLOR_BTNSHADOW, +* followed by a pixel high line of COLOR_BTNHIGHLIGHT. These separators +* are horizontal as opposed to the vertical separators for not dropdown +* type. +* +* FIXME: It is possible that the height of each line is really SM_CYBORDER. +*/ +static void +TOOLBAR_DrawDDFlatSeparator (LPRECT lpRect, HDC hdc, TBUTTON_INFO *btnPtr, TOOLBAR_INFO *infoPtr) +{ + RECT myrect; + COLORREF oldcolor, newcolor; + + myrect.left = lpRect->left; + myrect.right = lpRect->right; + myrect.top = lpRect->top + (lpRect->bottom - lpRect->top - 2)/2; + myrect.bottom = myrect.top + 1; + + InflateRect (&myrect, -2, 0); + + TRACE("rect=(%ld,%ld)-(%ld,%ld)\n", + myrect.left, myrect.top, myrect.right, myrect.bottom); + + newcolor = (infoPtr->clrBtnShadow == CLR_DEFAULT) ? + comctl32_color.clrBtnShadow : infoPtr->clrBtnShadow; + oldcolor = SetBkColor (hdc, newcolor); + ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0); + + myrect.top = myrect.bottom; + myrect.bottom = myrect.top + 1; + + newcolor = (infoPtr->clrBtnHighlight == CLR_DEFAULT) ? + comctl32_color.clrBtnHighlight : infoPtr->clrBtnHighlight; + SetBkColor (hdc, newcolor); + ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0); + + SetBkColor (hdc, oldcolor); +} + + +static void +TOOLBAR_DrawArrow (HDC hdc, INT left, INT top, COLORREF clr) +{ + INT x, y; + HPEN hPen, hOldPen; + + if (!(hPen = CreatePen( PS_SOLID, 1, clr))) return; + hOldPen = SelectObject ( hdc, hPen ); + x = left + 2; + y = top; + MoveToEx (hdc, x, y, NULL); + LineTo (hdc, x+5, y++); x++; + MoveToEx (hdc, x, y, NULL); + LineTo (hdc, x+3, y++); x++; + MoveToEx (hdc, x, y, NULL); + LineTo (hdc, x+1, y++); + SelectObject( hdc, hOldPen ); + DeleteObject( hPen ); +} + +/* + * Draw the text string for this button. + * note: infoPtr->himlDis *SHOULD* be non-zero when infoPtr->himlDef + * is non-zero, so we can simply check himlDef to see if we have + * an image list + */ +static void +TOOLBAR_DrawString (TOOLBAR_INFO *infoPtr, RECT *rcText, LPWSTR lpText, + NMTBCUSTOMDRAW *tbcd) +{ + HDC hdc = tbcd->nmcd.hdc; + HFONT hOldFont = 0; + COLORREF clrOld = 0; + COLORREF clrOldBk = 0; + int oldBkMode = 0; + UINT state = tbcd->nmcd.uItemState; + + /* draw text */ + if (lpText) { + TRACE("string=%s rect=(%ld,%ld)-(%ld,%ld)\n", debugstr_w(lpText), + rcText->left, rcText->top, rcText->right, rcText->bottom); + + hOldFont = SelectObject (hdc, infoPtr->hFont); + if ((state & CDIS_HOT) && (infoPtr->dwItemCDFlag & TBCDRF_HILITEHOTTRACK )) { + clrOld = SetTextColor (hdc, tbcd->clrTextHighlight); + } + else if (state & CDIS_DISABLED) { + clrOld = SetTextColor (hdc, tbcd->clrBtnHighlight); + OffsetRect (rcText, 1, 1); + DrawTextW (hdc, lpText, -1, rcText, infoPtr->dwDTFlags); + SetTextColor (hdc, comctl32_color.clr3dShadow); + OffsetRect (rcText, -1, -1); + } + else if (state & CDIS_INDETERMINATE) { + clrOld = SetTextColor (hdc, comctl32_color.clr3dShadow); + } + else if ((state & CDIS_MARKED) && !(infoPtr->dwItemCDFlag & TBCDRF_NOMARK)) { + clrOld = SetTextColor (hdc, tbcd->clrTextHighlight); + clrOldBk = SetBkColor (hdc, tbcd->clrMark); + oldBkMode = SetBkMode (hdc, OPAQUE); /* FIXME: should this be in the NMTBCUSTOMDRAW structure? */ + } + else { + clrOld = SetTextColor (hdc, tbcd->clrText); + } + + DrawTextW (hdc, lpText, -1, rcText, infoPtr->dwDTFlags); + SetTextColor (hdc, clrOld); + if ((state & CDIS_MARKED) && !(infoPtr->dwItemCDFlag & TBCDRF_NOMARK)) + { + SetBkColor (hdc, clrOldBk); + SetBkMode (hdc, oldBkMode); + } + SelectObject (hdc, hOldFont); + } +} + + +static void +TOOLBAR_DrawPattern (LPRECT lpRect, NMTBCUSTOMDRAW *tbcd) +{ + HDC hdc = tbcd->nmcd.hdc; + HBRUSH hbr = SelectObject (hdc, tbcd->hbrMonoDither); + COLORREF clrTextOld; + COLORREF clrBkOld; + INT cx = lpRect->right - lpRect->left; + INT cy = lpRect->bottom - lpRect->top; + INT cxEdge = GetSystemMetrics(SM_CXEDGE); + INT cyEdge = GetSystemMetrics(SM_CYEDGE); + clrTextOld = SetTextColor(hdc, tbcd->clrBtnHighlight); + clrBkOld = SetBkColor(hdc, tbcd->clrBtnFace); + PatBlt (hdc, lpRect->left + cxEdge, lpRect->top + cyEdge, + cx - (2 * cxEdge), cy - (2 * cyEdge), PATCOPY); + SetBkColor(hdc, clrBkOld); + SetTextColor(hdc, clrTextOld); + SelectObject (hdc, hbr); +} + + +static void TOOLBAR_DrawMasked(HIMAGELIST himl, int index, HDC hdc, INT x, INT y, UINT draw_flags) +{ + INT cx, cy; + HBITMAP hbmMask, hbmImage; + HDC hdcMask, hdcImage; + + ImageList_GetIconSize(himl, &cx, &cy); + + /* Create src image */ + hdcImage = CreateCompatibleDC(hdc); + hbmImage = CreateCompatibleBitmap(hdc, cx, cy); + SelectObject(hdcImage, hbmImage); + ImageList_DrawEx(himl, index, hdcImage, 0, 0, cx, cy, + RGB(0xff, 0xff, 0xff), RGB(0,0,0), draw_flags); + + /* Create Mask */ + hdcMask = CreateCompatibleDC(0); + hbmMask = CreateBitmap(cx, cy, 1, 1, NULL); + SelectObject(hdcMask, hbmMask); + + /* Remove the background and all white pixels */ + ImageList_DrawEx(himl, index, hdcMask, 0, 0, cx, cy, + RGB(0xff, 0xff, 0xff), RGB(0,0,0), ILD_MASK); + SetBkColor(hdcImage, RGB(0xff, 0xff, 0xff)); + BitBlt(hdcMask, 0, 0, cx, cy, hdcImage, 0, 0, NOTSRCERASE); + + /* draw the new mask 'etched' to hdc */ + SetBkColor(hdc, RGB(255, 255, 255)); + SelectObject(hdc, GetSysColorBrush(COLOR_3DHILIGHT)); + /* E20746 op code is (Dst ^ (Src & (Pat ^ Dst))) */ + BitBlt(hdc, x + 1, y + 1, cx, cy, hdcMask, 0, 0, 0xE20746); + SelectObject(hdc, GetSysColorBrush(COLOR_3DSHADOW)); + BitBlt(hdc, x, y, cx, cy, hdcMask, 0, 0, 0xE20746); + + /* Cleanup */ + DeleteObject(hbmImage); + DeleteDC(hdcImage); + DeleteObject (hbmMask); + DeleteDC(hdcMask); +} + + +static UINT +TOOLBAR_TranslateState(TBUTTON_INFO *btnPtr) +{ + UINT retstate = 0; + + retstate |= (btnPtr->fsState & TBSTATE_CHECKED) ? CDIS_CHECKED : 0; + retstate |= (btnPtr->fsState & TBSTATE_PRESSED) ? CDIS_SELECTED : 0; + retstate |= (btnPtr->fsState & TBSTATE_ENABLED) ? 0 : CDIS_DISABLED; + retstate |= (btnPtr->fsState & TBSTATE_MARKED ) ? CDIS_MARKED : 0; + retstate |= (btnPtr->bHot ) ? CDIS_HOT : 0; + retstate |= (btnPtr->fsState & TBSTATE_INDETERMINATE) ? CDIS_INDETERMINATE : 0; + /* NOTE: we don't set CDIS_GRAYED, CDIS_FOCUS, CDIS_DEFAULT */ + return retstate; +} + +/* draws the image on a toolbar button */ +static void +TOOLBAR_DrawImage(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, INT left, INT top, const NMTBCUSTOMDRAW *tbcd) +{ + HIMAGELIST himl = NULL; + BOOL draw_masked = FALSE; + INT index; + INT offset = 0; + UINT draw_flags = ILD_TRANSPARENT; + + if (tbcd->nmcd.uItemState & (CDIS_DISABLED | CDIS_INDETERMINATE)) + { + himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DISABLED, &index); + if (!himl) + { + himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DEFAULT, &index); + draw_masked = TRUE; + } + } + else if ((tbcd->nmcd.uItemState & CDIS_HOT) && (infoPtr->dwStyle & TBSTYLE_FLAT)) + { + /* if hot, attempt to draw with hot image list, if fails, + use default image list */ + himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_HOT, &index); + if (!himl) + himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DEFAULT, &index); + } + else + himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DEFAULT, &index); + + if (!himl) + return; + + if (!(infoPtr->dwItemCDFlag & TBCDRF_NOOFFSET) && + (tbcd->nmcd.uItemState & (CDIS_SELECTED | CDIS_CHECKED))) + offset = 1; + + if (!(infoPtr->dwItemCDFlag & TBCDRF_NOMARK) && + (tbcd->nmcd.uItemState & CDIS_MARKED)) + draw_flags |= ILD_BLEND50; + + TRACE("drawing index=%d, himl=%p, left=%d, top=%d, offset=%d\n", + index, himl, left, top, offset); + + if (draw_masked) + TOOLBAR_DrawMasked (himl, index, tbcd->nmcd.hdc, left + offset, top + offset, draw_flags); + else + ImageList_Draw (himl, index, tbcd->nmcd.hdc, left + offset, top + offset, draw_flags); +} + +/* draws a blank frame for a toolbar button */ +static void +TOOLBAR_DrawFrame(const TOOLBAR_INFO *infoPtr, const NMTBCUSTOMDRAW *tbcd) +{ + HDC hdc = tbcd->nmcd.hdc; + RECT rc = tbcd->nmcd.rc; + /* if the state is disabled or indeterminate then the button + * cannot have an interactive look like pressed or hot */ + BOOL non_interactive_state = (tbcd->nmcd.uItemState & CDIS_DISABLED) || + (tbcd->nmcd.uItemState & CDIS_INDETERMINATE); + BOOL pressed_look = !non_interactive_state && + ((tbcd->nmcd.uItemState & CDIS_SELECTED) || + (tbcd->nmcd.uItemState & CDIS_CHECKED)); + + /* app don't want us to draw any edges */ + if (infoPtr->dwItemCDFlag & TBCDRF_NOEDGES) + return; + + if (infoPtr->dwStyle & TBSTYLE_FLAT) + { + if (pressed_look) + DrawEdge (hdc, &rc, BDR_SUNKENOUTER, BF_RECT); + else if ((tbcd->nmcd.uItemState & CDIS_HOT) && !non_interactive_state) + DrawEdge (hdc, &rc, BDR_RAISEDINNER, BF_RECT); + } + else + { + if (pressed_look) + DrawEdge (hdc, &rc, EDGE_SUNKEN, BF_RECT | BF_MIDDLE); + else + DrawEdge (hdc, &rc, EDGE_RAISED, + BF_SOFT | BF_RECT | BF_MIDDLE); + } +} + +static void +TOOLBAR_DrawSepDDArrow(const TOOLBAR_INFO *infoPtr, const NMTBCUSTOMDRAW *tbcd, RECT *rcArrow, BOOL bDropDownPressed) +{ + HDC hdc = tbcd->nmcd.hdc; + int offset = 0; + BOOL pressed = bDropDownPressed || + (tbcd->nmcd.uItemState & (CDIS_SELECTED | CDIS_CHECKED)); + + if (infoPtr->dwStyle & TBSTYLE_FLAT) + { + if (pressed) + DrawEdge (hdc, rcArrow, BDR_SUNKENOUTER, BF_RECT); + else if ( (tbcd->nmcd.uItemState & CDIS_HOT) && + !(tbcd->nmcd.uItemState & CDIS_DISABLED) && + !(tbcd->nmcd.uItemState & CDIS_INDETERMINATE)) + DrawEdge (hdc, rcArrow, BDR_RAISEDINNER, BF_RECT); + } + else + { + if (pressed) + DrawEdge (hdc, rcArrow, EDGE_SUNKEN, BF_RECT | BF_MIDDLE); + else + DrawEdge (hdc, rcArrow, EDGE_RAISED, + BF_SOFT | BF_RECT | BF_MIDDLE); + } + + if (pressed) + offset = (infoPtr->dwItemCDFlag & TBCDRF_NOOFFSET) ? 0 : 1; + + if (tbcd->nmcd.uItemState & (CDIS_DISABLED | CDIS_INDETERMINATE)) + { + TOOLBAR_DrawArrow(hdc, rcArrow->left+1, rcArrow->top+1 + (rcArrow->bottom - rcArrow->top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnHighlight); + TOOLBAR_DrawArrow(hdc, rcArrow->left, rcArrow->top + (rcArrow->bottom - rcArrow->top - ARROW_HEIGHT) / 2, comctl32_color.clr3dShadow); + } + else + TOOLBAR_DrawArrow(hdc, rcArrow->left + offset, rcArrow->top + offset + (rcArrow->bottom - rcArrow->top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnText); +} + +/* draws a complete toolbar button */ +static void +TOOLBAR_DrawButton (HWND hwnd, TBUTTON_INFO *btnPtr, HDC hdc) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + DWORD dwStyle = infoPtr->dwStyle; + BOOL hasDropDownArrow = (TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle) && + (btnPtr->fsStyle & BTNS_DROPDOWN)) || + (btnPtr->fsStyle & BTNS_WHOLEDROPDOWN); + BOOL drawSepDropDownArrow = hasDropDownArrow && + (~btnPtr->fsStyle & BTNS_WHOLEDROPDOWN); + RECT rc, rcArrow, rcBitmap, rcText; + LPWSTR lpText = NULL; + NMTBCUSTOMDRAW tbcd; + DWORD ntfret; + INT offset; + + rc = btnPtr->rect; + CopyRect (&rcArrow, &rc); + + /* get a pointer to the text */ + lpText = TOOLBAR_GetText(infoPtr, btnPtr); + + if (hasDropDownArrow) + { + int right; + + if (dwStyle & TBSTYLE_FLAT) + right = max(rc.left, rc.right - DDARROW_WIDTH); + else + right = max(rc.left, rc.right - DDARROW_WIDTH - 2); + + if (drawSepDropDownArrow) + rc.right = right; + + rcArrow.left = right; + } + + /* copy text & bitmap rects after adjusting for drop-down arrow + * so that text & bitmap is centred in the rectangle not containing + * the arrow */ + CopyRect(&rcText, &rc); + CopyRect(&rcBitmap, &rc); + + /* Center the bitmap horizontally and vertically */ + if (dwStyle & TBSTYLE_LIST) + { + if (lpText && + infoPtr->nMaxTextRows > 0 && + (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || + (btnPtr->fsStyle & BTNS_SHOWTEXT)) ) + rcBitmap.left += GetSystemMetrics(SM_CXEDGE) + infoPtr->szPadding.cx / 2; + else + rcBitmap.left += GetSystemMetrics(SM_CXEDGE) + infoPtr->iListGap / 2; + } + else + rcBitmap.left += (infoPtr->nButtonWidth - infoPtr->nBitmapWidth) / 2; + + rcBitmap.top += infoPtr->szPadding.cy / 2; + + TRACE("iBitmap=%d, start=(%ld,%ld) w=%d, h=%d\n", + btnPtr->iBitmap, rcBitmap.left, rcBitmap.top, + infoPtr->nBitmapWidth, infoPtr->nBitmapHeight); + TRACE("Text=%s\n", debugstr_w(lpText)); + TRACE("iListGap=%d, padding = { %ld, %ld }\n", infoPtr->iListGap, infoPtr->szPadding.cx, infoPtr->szPadding.cy); + + /* calculate text position */ + if (lpText) + { + rcText.left += GetSystemMetrics(SM_CXEDGE); + rcText.right -= GetSystemMetrics(SM_CXEDGE); + if (dwStyle & TBSTYLE_LIST) + { + if (TOOLBAR_IsValidBitmapIndex(infoPtr,btnPtr->iBitmap)) + rcText.left += infoPtr->nBitmapWidth + infoPtr->iListGap + 2; + } + else + { + if (ImageList_GetImageCount(GETDEFIMAGELIST(infoPtr, 0)) > 0) + rcText.top += infoPtr->szPadding.cy/2 + infoPtr->nBitmapHeight + 1; + else + rcText.top += infoPtr->szPadding.cy/2 + 2; + } + } + + /* Initialize fields in all cases, because we use these later + * NOTE: applications can and do alter these to customize their + * toolbars */ + ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW)); + tbcd.clrText = comctl32_color.clrBtnText; + tbcd.clrTextHighlight = comctl32_color.clrHighlightText; + tbcd.clrBtnFace = comctl32_color.clrBtnFace; + tbcd.clrBtnHighlight = comctl32_color.clrBtnHighlight; + tbcd.clrMark = comctl32_color.clrHighlight; + tbcd.clrHighlightHotTrack = 0; + tbcd.nStringBkMode = (infoPtr->bBtnTranspnt) ? TRANSPARENT : OPAQUE; + tbcd.nHLStringBkMode = (infoPtr->bBtnTranspnt) ? TRANSPARENT : OPAQUE; + /* MSDN says that this is the text rectangle. + * But (why always a but) tracing of v5.7 of native shows + * that this is really a *relative* rectangle based on the + * the nmcd.rc. Also the left and top are always 0 ignoring + * any bitmap that might be present. */ + tbcd.rcText.left = 0; + tbcd.rcText.top = 0; + tbcd.rcText.right = rcText.right - rc.left; + tbcd.rcText.bottom = rcText.bottom - rc.top; + tbcd.nmcd.uItemState = TOOLBAR_TranslateState(btnPtr); + tbcd.nmcd.hdc = hdc; + tbcd.nmcd.rc = rc; + tbcd.hbrMonoDither = COMCTL32_hPattern55AABrush; + + /* FIXME: what are these used for? */ + tbcd.hbrLines = 0; + tbcd.hpenLines = 0; + + /* Issue Item Prepaint notify */ + infoPtr->dwItemCustDraw = 0; + infoPtr->dwItemCDFlag = 0; + if (infoPtr->dwBaseCustDraw & CDRF_NOTIFYITEMDRAW) + { + tbcd.nmcd.dwDrawStage = CDDS_ITEMPREPAINT; + tbcd.nmcd.dwItemSpec = btnPtr->idCommand; + tbcd.nmcd.lItemlParam = btnPtr->dwData; + ntfret = TOOLBAR_SendNotify(&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); + /* reset these fields so the user can't alter the behaviour like native */ + tbcd.nmcd.hdc = hdc; + tbcd.nmcd.rc = rc; + + infoPtr->dwItemCustDraw = ntfret & 0xffff; + infoPtr->dwItemCDFlag = ntfret & 0xffff0000; + if (infoPtr->dwItemCustDraw & CDRF_SKIPDEFAULT) + return; + /* save the only part of the rect that the user can change */ + rcText.right = tbcd.rcText.right + rc.left; + rcText.bottom = tbcd.rcText.bottom + rc.top; + } + + /* separator */ + if (btnPtr->fsStyle & BTNS_SEP) { + /* with the FLAT style, iBitmap is the width and has already */ + /* been taken into consideration in calculating the width */ + /* so now we need to draw the vertical separator */ + /* empirical tests show that iBitmap can/will be non-zero */ + /* when drawing the vertical bar... */ + if ((dwStyle & TBSTYLE_FLAT) /* && (btnPtr->iBitmap == 0) */) { + if (btnPtr->fsStyle & BTNS_DROPDOWN) + TOOLBAR_DrawDDFlatSeparator (&rc, hdc, btnPtr, infoPtr); + else + TOOLBAR_DrawFlatSeparator (&rc, hdc, infoPtr); + } + else if (btnPtr->fsStyle != BTNS_SEP) { + FIXME("Draw some kind of separator: fsStyle=%x\n", + btnPtr->fsStyle); + } + goto FINALNOTIFY; + } + + if (!(infoPtr->dwItemCDFlag & TBCDRF_NOOFFSET) && + (btnPtr->fsState & (TBSTATE_PRESSED | TBSTATE_CHECKED))) + OffsetRect(&rcText, 1, 1); + + if (!(tbcd.nmcd.uItemState & CDIS_HOT) && + ((tbcd.nmcd.uItemState & CDIS_CHECKED) || (tbcd.nmcd.uItemState & CDIS_INDETERMINATE))) + TOOLBAR_DrawPattern (&rc, &tbcd); + + if ((dwStyle & TBSTYLE_FLAT) && (tbcd.nmcd.uItemState & CDIS_HOT)) + { + if ( infoPtr->dwItemCDFlag & TBCDRF_HILITEHOTTRACK ) + { + COLORREF oldclr; + + oldclr = SetBkColor(hdc, tbcd.clrHighlightHotTrack); + ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, 0); + if (hasDropDownArrow) + ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &rcArrow, NULL, 0, 0); + SetBkColor(hdc, oldclr); + } + } + + TOOLBAR_DrawFrame(infoPtr, &tbcd); + + if (drawSepDropDownArrow) + TOOLBAR_DrawSepDDArrow(infoPtr, &tbcd, &rcArrow, btnPtr->bDropDownPressed); + + if (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || (btnPtr->fsStyle & BTNS_SHOWTEXT)) + TOOLBAR_DrawString (infoPtr, &rcText, lpText, &tbcd); + + TOOLBAR_DrawImage(infoPtr, btnPtr, rcBitmap.left, rcBitmap.top, &tbcd); + + if (hasDropDownArrow && !drawSepDropDownArrow) + { + if (tbcd.nmcd.uItemState & (CDIS_DISABLED | CDIS_INDETERMINATE)) + { + TOOLBAR_DrawArrow(hdc, rcArrow.left+1, rcArrow.top+1 + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnHighlight); + TOOLBAR_DrawArrow(hdc, rcArrow.left, rcArrow.top + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, comctl32_color.clr3dShadow); + } + else if (tbcd.nmcd.uItemState & (CDIS_SELECTED | CDIS_CHECKED)) + { + offset = (infoPtr->dwItemCDFlag & TBCDRF_NOOFFSET) ? 0 : 1; + TOOLBAR_DrawArrow(hdc, rcArrow.left + offset, rcArrow.top + offset + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnText); + } + else + TOOLBAR_DrawArrow(hdc, rcArrow.left, rcArrow.top + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnText); + } + +FINALNOTIFY: + if (infoPtr->dwItemCustDraw & CDRF_NOTIFYPOSTPAINT) + { + tbcd.nmcd.dwDrawStage = CDDS_ITEMPOSTPAINT; + tbcd.nmcd.hdc = hdc; + tbcd.nmcd.rc = rc; + tbcd.nmcd.dwItemSpec = btnPtr->idCommand; + tbcd.nmcd.uItemState = TOOLBAR_TranslateState(btnPtr); + tbcd.nmcd.lItemlParam = btnPtr->dwData; + tbcd.rcText = rcText; + tbcd.nStringBkMode = (infoPtr->bBtnTranspnt) ? TRANSPARENT : OPAQUE; + tbcd.nHLStringBkMode = (infoPtr->bBtnTranspnt) ? TRANSPARENT : OPAQUE; + ntfret = TOOLBAR_SendNotify(&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); + } + +} + + +static void +TOOLBAR_Refresh (HWND hwnd, HDC hdc, PAINTSTRUCT* ps) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + TBUTTON_INFO *btnPtr; + INT i, oldBKmode = 0; + RECT rcTemp, rcClient; + NMTBCUSTOMDRAW tbcd; + DWORD ntfret; + + /* the app has told us not to redraw the toolbar */ + if (!infoPtr->bDoRedraw) + return; + + /* if imagelist belongs to the app, it can be changed + by the app after setting it */ + if (GETDEFIMAGELIST(infoPtr, 0) != infoPtr->himlInt) + { + infoPtr->nNumBitmaps = 0; + for (i = 0; i < infoPtr->cimlDef; i++) + infoPtr->nNumBitmaps += ImageList_GetImageCount(infoPtr->himlDef[i]->himl); + } + + TOOLBAR_DumpToolbar (infoPtr, __LINE__); + + /* Send initial notify */ + ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW)); + tbcd.nmcd.dwDrawStage = CDDS_PREPAINT; + tbcd.nmcd.hdc = hdc; + tbcd.nmcd.rc = ps->rcPaint; + ntfret = TOOLBAR_SendNotify(&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); + infoPtr->dwBaseCustDraw = ntfret & 0xffff; + + if (infoPtr->bBtnTranspnt) + oldBKmode = SetBkMode (hdc, TRANSPARENT); + + GetClientRect(hwnd, &rcClient); + + /* redraw necessary buttons */ + btnPtr = infoPtr->buttons; + for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) + { + BOOL bDraw; + if (infoPtr->dwExStyle & TBSTYLE_EX_HIDECLIPPEDBUTTONS) + { + IntersectRect(&rcTemp, &rcClient, &btnPtr->rect); + bDraw = EqualRect(&rcTemp, &btnPtr->rect); + } + else + bDraw = TRUE; + bDraw &= IntersectRect(&rcTemp, &(ps->rcPaint), &(btnPtr->rect)); + bDraw = (btnPtr->fsState & TBSTATE_HIDDEN) ? FALSE : bDraw; + if (bDraw) + TOOLBAR_DrawButton (hwnd, btnPtr, hdc); + } + + /* draw insert mark if required */ + if (infoPtr->tbim.iButton != -1) + { + RECT rcButton = infoPtr->buttons[infoPtr->tbim.iButton].rect; + RECT rcInsertMark; + rcInsertMark.top = rcButton.top; + rcInsertMark.bottom = rcButton.bottom; + if (infoPtr->tbim.dwFlags & TBIMHT_AFTER) + rcInsertMark.left = rcInsertMark.right = rcButton.right; + else + rcInsertMark.left = rcInsertMark.right = rcButton.left - INSERTMARK_WIDTH; + COMCTL32_DrawInsertMark(hdc, &rcInsertMark, infoPtr->clrInsertMark, FALSE); + } + + if (infoPtr->bBtnTranspnt && (oldBKmode != TRANSPARENT)) + SetBkMode (hdc, oldBKmode); + + if (infoPtr->dwBaseCustDraw & CDRF_NOTIFYPOSTPAINT) + { + ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW)); + tbcd.nmcd.dwDrawStage = CDDS_POSTPAINT; + tbcd.nmcd.hdc = hdc; + tbcd.nmcd.rc = ps->rcPaint; + ntfret = TOOLBAR_SendNotify(&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); + } +} + +/*********************************************************************** +* TOOLBAR_MeasureString +* +* This function gets the width and height of a string in pixels. This +* is done first by using GetTextExtentPoint to get the basic width +* and height. The DrawText is called with DT_CALCRECT to get the exact +* width. The reason is because the text may have more than one "&" (or +* prefix characters as M$ likes to call them). The prefix character +* indicates where the underline goes, except for the string "&&" which +* is reduced to a single "&". GetTextExtentPoint does not process these +* only DrawText does. Note that the BTNS_NOPREFIX is handled here. +*/ +static void +TOOLBAR_MeasureString(TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, + HDC hdc, LPSIZE lpSize) +{ + RECT myrect; + + lpSize->cx = 0; + lpSize->cy = 0; + + if (infoPtr->nMaxTextRows > 0 && + !(btnPtr->fsState & TBSTATE_HIDDEN) && + (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || + (btnPtr->fsStyle & BTNS_SHOWTEXT)) ) + { + LPWSTR lpText = TOOLBAR_GetText(infoPtr, btnPtr); + + if(lpText != NULL) { + /* first get size of all the text */ + GetTextExtentPoint32W (hdc, lpText, strlenW (lpText), lpSize); + + /* feed above size into the rectangle for DrawText */ + myrect.left = myrect.top = 0; + myrect.right = lpSize->cx; + myrect.bottom = lpSize->cy; + + /* Use DrawText to get true size as drawn (less pesky "&") */ + DrawTextW (hdc, lpText, -1, &myrect, DT_VCENTER | DT_SINGLELINE | + DT_CALCRECT | ((btnPtr->fsStyle & BTNS_NOPREFIX) ? + DT_NOPREFIX : 0)); + + /* feed back to caller */ + lpSize->cx = myrect.right; + lpSize->cy = myrect.bottom; + } + } + + TRACE("string size %ld x %ld!\n", lpSize->cx, lpSize->cy); +} + +/*********************************************************************** +* TOOLBAR_CalcStrings +* +* This function walks through each string and measures it and returns +* the largest height and width to caller. +*/ +static void +TOOLBAR_CalcStrings (HWND hwnd, LPSIZE lpSize) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + TBUTTON_INFO *btnPtr; + INT i; + SIZE sz; + HDC hdc; + HFONT hOldFont; + + lpSize->cx = 0; + lpSize->cy = 0; + + if(infoPtr->nMaxTextRows == 0) + return; + + hdc = GetDC (hwnd); + hOldFont = SelectObject (hdc, infoPtr->hFont); + + btnPtr = infoPtr->buttons; + for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) { + if(TOOLBAR_HasText(infoPtr, btnPtr)) + { + TOOLBAR_MeasureString(infoPtr, btnPtr, hdc, &sz); + if (sz.cx > lpSize->cx) + lpSize->cx = sz.cx; + if (sz.cy > lpSize->cy) + lpSize->cy = sz.cy; + } + } + + SelectObject (hdc, hOldFont); + ReleaseDC (hwnd, hdc); + + TRACE("max string size %ld x %ld!\n", lpSize->cx, lpSize->cy); +} + +/*********************************************************************** +* TOOLBAR_WrapToolbar +* +* This function walks through the buttons and separators in the +* toolbar, and sets the TBSTATE_WRAP flag only on those items where +* wrapping should occur based on the width of the toolbar window. +* It does *not* calculate button placement itself. That task +* takes place in TOOLBAR_CalcToolbar. If the program wants to manage +* the toolbar wrapping on its own, it can use the TBSTYLE_WRAPABLE +* flag, and set the TBSTATE_WRAP flags manually on the appropriate items. +* +* Note: TBSTYLE_WRAPABLE or TBSTYLE_EX_UNDOC1 can be used also to allow +* vertical toolbar lists. +*/ + +static void +TOOLBAR_WrapToolbar( HWND hwnd, DWORD dwStyle ) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + TBUTTON_INFO *btnPtr; + INT x, cx, i, j; + RECT rc; + BOOL bWrap, bButtonWrap; + + /* When the toolbar window style is not TBSTYLE_WRAPABLE, */ + /* no layout is necessary. Applications may use this style */ + /* to perform their own layout on the toolbar. */ + if( !(dwStyle & TBSTYLE_WRAPABLE) && + !(infoPtr->dwExStyle & TBSTYLE_EX_UNDOC1) ) return; + + btnPtr = infoPtr->buttons; + x = infoPtr->nIndent; + + /* this can get the parents width, to know how far we can extend + * this toolbar. We cannot use its height, as there may be multiple + * toolbars in a rebar control + */ + GetClientRect( GetParent(hwnd), &rc ); + infoPtr->nWidth = rc.right - rc.left; + bButtonWrap = FALSE; + + TRACE("start ButtonWidth=%d, BitmapWidth=%d, nWidth=%d, nIndent=%d\n", + infoPtr->nButtonWidth, infoPtr->nBitmapWidth, infoPtr->nWidth, + infoPtr->nIndent); + + for (i = 0; i < infoPtr->nNumButtons; i++ ) + { + bWrap = FALSE; + btnPtr[i].fsState &= ~TBSTATE_WRAP; + + if (btnPtr[i].fsState & TBSTATE_HIDDEN) + continue; + + /* UNDOCUMENTED: If a separator has a non zero bitmap index, */ + /* it is the actual width of the separator. This is used for */ + /* custom controls in toolbars. */ + /* */ + /* BTNS_DROPDOWN separators are treated as buttons for */ + /* width. - GA 8/01 */ + if ((btnPtr[i].fsStyle & BTNS_SEP) && + !(btnPtr[i].fsStyle & BTNS_DROPDOWN)) + cx = (btnPtr[i].iBitmap > 0) ? + btnPtr[i].iBitmap : SEPARATOR_WIDTH; + else + cx = infoPtr->nButtonWidth; + + /* Two or more adjacent separators form a separator group. */ + /* The first separator in a group should be wrapped to the */ + /* next row if the previous wrapping is on a button. */ + if( bButtonWrap && + (btnPtr[i].fsStyle & BTNS_SEP) && + (i + 1 < infoPtr->nNumButtons ) && + (btnPtr[i + 1].fsStyle & BTNS_SEP) ) + { + TRACE("wrap point 1 btn %d style %02x\n", i, btnPtr[i].fsStyle); + btnPtr[i].fsState |= TBSTATE_WRAP; + x = infoPtr->nIndent; + i++; + bButtonWrap = FALSE; + continue; + } + + /* The layout makes sure the bitmap is visible, but not the button. */ + /* Test added to also wrap after a button that starts a row but */ + /* is bigger than the area. - GA 8/01 */ + if (( x + cx - (infoPtr->nButtonWidth - infoPtr->nBitmapWidth) / 2 + > infoPtr->nWidth ) || + ((x == infoPtr->nIndent) && (cx > infoPtr->nWidth))) + { + BOOL bFound = FALSE; + + /* If the current button is a separator and not hidden, */ + /* go to the next until it reaches a non separator. */ + /* Wrap the last separator if it is before a button. */ + while( ( ((btnPtr[i].fsStyle & BTNS_SEP) && + !(btnPtr[i].fsStyle & BTNS_DROPDOWN)) || + (btnPtr[i].fsState & TBSTATE_HIDDEN) ) && + i < infoPtr->nNumButtons ) + { + i++; + bFound = TRUE; + } + + if( bFound && i < infoPtr->nNumButtons ) + { + i--; + TRACE("wrap point 2 btn %d style %02x, x=%d, cx=%d\n", + i, btnPtr[i].fsStyle, x, cx); + btnPtr[i].fsState |= TBSTATE_WRAP; + x = infoPtr->nIndent; + bButtonWrap = FALSE; + continue; + } + else if ( i >= infoPtr->nNumButtons) + break; + + /* If the current button is not a separator, find the last */ + /* separator and wrap it. */ + for ( j = i - 1; j >= 0 && !(btnPtr[j].fsState & TBSTATE_WRAP); j--) + { + if ((btnPtr[j].fsStyle & BTNS_SEP) && + !(btnPtr[j].fsState & TBSTATE_HIDDEN)) + { + bFound = TRUE; + i = j; + TRACE("wrap point 3 btn %d style %02x, x=%d, cx=%d\n", + i, btnPtr[i].fsStyle, x, cx); + x = infoPtr->nIndent; + btnPtr[j].fsState |= TBSTATE_WRAP; + bButtonWrap = FALSE; + break; + } + } + + /* If no separator available for wrapping, wrap one of */ + /* non-hidden previous button. */ + if (!bFound) + { + for ( j = i - 1; + j >= 0 && !(btnPtr[j].fsState & TBSTATE_WRAP); j--) + { + if (btnPtr[j].fsState & TBSTATE_HIDDEN) + continue; + + bFound = TRUE; + i = j; + TRACE("wrap point 4 btn %d style %02x, x=%d, cx=%d\n", + i, btnPtr[i].fsStyle, x, cx); + x = infoPtr->nIndent; + btnPtr[j].fsState |= TBSTATE_WRAP; + bButtonWrap = TRUE; + break; + } + } + + /* If all above failed, wrap the current button. */ + if (!bFound) + { + TRACE("wrap point 5 btn %d style %02x, x=%d, cx=%d\n", + i, btnPtr[i].fsStyle, x, cx); + btnPtr[i].fsState |= TBSTATE_WRAP; + bFound = TRUE; + x = infoPtr->nIndent; + if (btnPtr[i].fsStyle & BTNS_SEP ) + bButtonWrap = FALSE; + else + bButtonWrap = TRUE; + } + } + else { + TRACE("wrap point 6 btn %d style %02x, x=%d, cx=%d\n", + i, btnPtr[i].fsStyle, x, cx); + x += cx; + } + } +} + + +/*********************************************************************** +* TOOLBAR_MeasureButton +* +* Calculates the width and height required for a button. Used in +* TOOLBAR_CalcToolbar to set the all-button width and height and also for +* the width of buttons that are autosized. +* +* Note that it would have been rather elegant to use one piece of code for +* both the laying out of the toolbar and for controlling where button parts +* are drawn, but the native control has inconsistencies between the two that +* prevent this from being effectively. These inconsistencies can be seen as +* artefacts where parts of the button appear outside of the bounding button +* rectangle. +* +* There are several cases for the calculation of the button dimensions and +* button part positioning: +* +* List +* ==== +* +* With Bitmap: +* +* +--------------------------------------------------------+ ^ +* | ^ ^ | | +* | | pad.cy / 2 | centred | | +* | pad.cx/2 + cxedge +--------------+ +------------+ | | DEFPAD_CY + +* |<----------------->| nBitmapWidth | | Text | | | max(nBitmapHeight, szText.cy) +* | |<------------>| | | | | +* | +--------------+ +------------+ | | +* |<-------------------------------------->| | | +* | cxedge + iListGap + nBitmapWidth + 2 |<-----------> | | +* | szText.cx | | +* +--------------------------------------------------------+ - +* <--------------------------------------------------------> +* 2*cxedge + nBitmapWidth + iListGap + szText.cx + pad.cx +* +* Without Bitmap (I_IMAGENONE): +* +* +-----------------------------------+ ^ +* | ^ | | +* | | centred | | LISTPAD_CY + +* | +------------+ | | szText.cy +* | | Text | | | +* | | | | | +* | +------------+ | | +* |<----------------->| | | +* | cxedge |<-----------> | | +* | szText.cx | | +* +-----------------------------------+ - +* <-----------------------------------> +* szText.cx + pad.cx +* +* Without text: +* +* +--------------------------------------+ ^ +* | ^ | | +* | | padding.cy/2 | | DEFPAD_CY + +* | +------------+ | | nBitmapHeight +* | | Bitmap | | | +* | | | | | +* | +------------+ | | +* |<------------------->| | | +* | cxedge + iListGap/2 |<-----------> | | +* | nBitmapWidth | | +* +--------------------------------------+ - +* <--------------------------------------> +* 2*cxedge + nBitmapWidth + iListGap +* +* Non-List +* ======== +* +* With bitmap: +* +* +-----------------------------------+ ^ +* | ^ | | +* | | pad.cy / 2 | | nBitmapHeight + +* | - | | szText.cy + +* | +------------+ | | DEFPAD_CY + 1 +* | centred | Bitmap | | | +* |<----------------->| | | | +* | +------------+ | | +* | ^ | | +* | 1 | | | +* | - | | +* | centred +---------------+ | | +* |<--------------->| Text | | | +* | +---------------+ | | +* +-----------------------------------+ - +* <-----------------------------------> +* pad.cx + max(nBitmapWidth, szText.cx) +* +* Without bitmaps (NULL imagelist or ImageList_GetImageCount() = 0): +* +* +---------------------------------------+ ^ +* | ^ | | +* | | 2 + pad.cy / 2 | | +* | - | | szText.cy + +* | centred +-----------------+ | | pad.cy + 2 +* |<--------------->| Text | | | +* | +-----------------+ | | +* | | | +* +---------------------------------------+ - +* <---------------------------------------> +* 2*cxedge + pad.cx + szText.cx +* +* Without text: +* As for with bitmaps, but with szText.cx zero. +*/ +static inline SIZE TOOLBAR_MeasureButton(TOOLBAR_INFO *infoPtr, SIZE sizeString, BOOL bHasBitmap, BOOL bValidImageList) +{ + SIZE sizeButton; + if (infoPtr->dwStyle & TBSTYLE_LIST) + { + /* set button height from bitmap / text height... */ + sizeButton.cy = max((bHasBitmap ? infoPtr->nBitmapHeight : 0), + sizeString.cy); + + /* ... add on the necessary padding */ + if (bValidImageList) + { + if (bHasBitmap) + sizeButton.cy += DEFPAD_CY; + else + sizeButton.cy += LISTPAD_CY; + } + else + sizeButton.cy += infoPtr->szPadding.cy; + + /* calculate button width */ + if (bHasBitmap) + { + sizeButton.cx = 2*GetSystemMetrics(SM_CXEDGE) + + infoPtr->nBitmapWidth + infoPtr->iListGap; + if (sizeString.cx > 0) + sizeButton.cx += sizeString.cx + infoPtr->szPadding.cx; + } + else + sizeButton.cx = sizeString.cx + infoPtr->szPadding.cx; + } + else + { + if (bHasBitmap) + { + sizeButton.cy = infoPtr->nBitmapHeight + 1 + + sizeString.cy + DEFPAD_CY; + sizeButton.cx = infoPtr->szPadding.cx + + max(sizeString.cx, infoPtr->nBitmapWidth); + } + else + { + sizeButton.cy = sizeString.cy + infoPtr->szPadding.cy + + NONLIST_NOTEXT_OFFSET; + sizeButton.cx = 2*GetSystemMetrics(SM_CXEDGE) + + infoPtr->szPadding.cx + sizeString.cx; + } + } + return sizeButton; +} + + +/*********************************************************************** +* TOOLBAR_CalcToolbar +* +* This function calculates button and separator placement. It first +* calculates the button sizes, gets the toolbar window width and then +* calls TOOLBAR_WrapToolbar to determine which buttons we need to wrap +* on. It assigns a new location to each item and sends this location to +* the tooltip window if appropriate. Finally, it updates the rcBound +* rect and calculates the new required toolbar window height. +*/ +static void +TOOLBAR_CalcToolbar (HWND hwnd) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd); + DWORD dwStyle = infoPtr->dwStyle; + TBUTTON_INFO *btnPtr; + INT i, nRows, nSepRows; + INT x, y, cx, cy; + SIZE sizeString, sizeButton; + BOOL bWrap; + BOOL usesBitmaps = FALSE; + BOOL validImageList = FALSE; + BOOL hasDropDownArrows = TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle); + + TOOLBAR_CalcStrings (hwnd, &sizeString); + + TOOLBAR_DumpToolbar (infoPtr, __LINE__); + + for (i = 0; i < infoPtr->nNumButtons && !usesBitmaps; i++) + { + if (TOOLBAR_IsValidBitmapIndex(infoPtr,infoPtr->buttons[i].iBitmap)) + usesBitmaps = TRUE; + } + if (TOOLBAR_IsValidImageList(infoPtr, 0)) + validImageList = TRUE; + sizeButton = TOOLBAR_MeasureButton(infoPtr, sizeString, usesBitmaps, validImageList); + infoPtr->nButtonWidth = sizeButton.cx; + infoPtr->nButtonHeight = sizeButton.cy; + + if ( infoPtr->cxMin >= 0 && infoPtr->nButtonWidth < infoPtr->cxMin ) + infoPtr->nButtonWidth = infoPtr->cxMin; + if ( infoPtr->cxMax > 0 && infoPtr->nButtonWidth > infoPtr->cxMax ) + infoPtr->nButtonWidth = infoPtr->cxMax; + + TOOLBAR_WrapToolbar( hwnd, dwStyle ); + + x = infoPtr->nIndent; + y = 0; + + /* from above, minimum is a button, and possible text */ + cx = infoPtr->nButtonWidth; + + infoPtr->nHeight = infoPtr->nButtonHeight; + + cy = infoPtr->nHeight; + + nRows = nSepRows = 0; + + infoPtr->rcBound.top = y; + infoPtr->rcBound.left = x; + infoPtr->rcBound.bottom = y + cy; + infoPtr->rcBound.right = x; + + btnPtr = infoPtr->buttons; + + TRACE("cy=%d\n", cy); + + for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++ ) + { + bWrap = FALSE; + if (btnPtr->fsState & TBSTATE_HIDDEN) + { + SetRectEmpty (&btnPtr->rect); + continue; + } + + cy = infoPtr->nHeight; + + /* UNDOCUMENTED: If a separator has a non zero bitmap index, */ + /* it is the actual width of the separator. This is used for */ + /* custom controls in toolbars. */ + if (btnPtr->fsStyle & BTNS_SEP) { + if (btnPtr->fsStyle & BTNS_DROPDOWN) { + cy = (btnPtr->iBitmap > 0) ? + btnPtr->iBitmap : SEPARATOR_WIDTH; + cx = infoPtr->nButtonWidth; + } + else + cx = (btnPtr->iBitmap > 0) ? + btnPtr->iBitmap : SEPARATOR_WIDTH; + } + else + { + if (btnPtr->cx) + cx = btnPtr->cx; + else if ((infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || + (btnPtr->fsStyle & BTNS_AUTOSIZE)) + { + SIZE sz; + HDC hdc; + HFONT hOldFont; + + hdc = GetDC (hwnd); + hOldFont = SelectObject (hdc, infoPtr->hFont); + + TOOLBAR_MeasureString(infoPtr, btnPtr, hdc, &sz); + + SelectObject (hdc, hOldFont); + ReleaseDC (hwnd, hdc); + + sizeButton = TOOLBAR_MeasureButton(infoPtr, sz, + TOOLBAR_IsValidBitmapIndex(infoPtr, infoPtr->buttons[i].iBitmap), + validImageList); + cx = sizeButton.cx; + } + else + cx = infoPtr->nButtonWidth; + + /* if size has been set manually then don't add on extra space + * for the drop down arrow */ + if (!btnPtr->cx && hasDropDownArrows && + ((btnPtr->fsStyle & BTNS_DROPDOWN) || (btnPtr->fsStyle & BTNS_WHOLEDROPDOWN))) + cx += DDARROW_WIDTH; + } + if (btnPtr->fsState & TBSTATE_WRAP ) + bWrap = TRUE; + + SetRect (&btnPtr->rect, x, y, x + cx, y + cy); + + if (infoPtr->rcBound.left > x) + infoPtr->rcBound.left = x; + if (infoPtr->rcBound.right < x + cx) + infoPtr->rcBound.right = x + cx; + if (infoPtr->rcBound.bottom < y + cy) + infoPtr->rcBound.bottom = y + cy; + + /* Set the toolTip only for non-hidden, non-separator button */ + if (infoPtr->hwndToolTip && !(btnPtr->fsStyle & BTNS_SEP )) + { + TTTOOLINFOW ti; + + ZeroMemory (&ti, sizeof(ti)); + ti.cbSize = sizeof(ti); + ti.hwnd = hwnd; + ti.uId = btnPtr->idCommand; + ti.rect = btnPtr->rect; + SendMessageW (infoPtr->hwndToolTip, TTM_NEWTOOLRECTW, + 0, (LPARAM)&ti); + } + + /* btnPtr->nRow is zero based. The space between the rows is */ + /* also considered as a row. */ + btnPtr->nRow = nRows + nSepRows; + + TRACE("button %d style=%x, bWrap=%d, nRows=%d, nSepRows=%d, btnrow=%d, (%d,%d)-(%d,%d)\n", + i, btnPtr->fsStyle, bWrap, nRows, nSepRows, btnPtr->nRow, + x, y, x+cx, y+cy); + + if( bWrap ) + { + if ( !(btnPtr->fsStyle & BTNS_SEP) ) + y += cy; + else + { + /* UNDOCUMENTED: If a separator has a non zero bitmap index, */ + /* it is the actual width of the separator. This is used for */ + /* custom controls in toolbars. */ + if ( !(btnPtr->fsStyle & BTNS_DROPDOWN)) + y += cy + ( (btnPtr->iBitmap > 0 ) ? + btnPtr->iBitmap : SEPARATOR_WIDTH) * 2 /3; + else + y += cy; + + /* nSepRows is used to calculate the extra height follwoing */ + /* the last row. */ + nSepRows++; + } + x = infoPtr->nIndent; + + /* Increment row number unless this is the last button */ + /* and it has Wrap set. */ + if (i != infoPtr->nNumButtons-1) + nRows++; + } + else + x += cx; + } + + /* infoPtr->nRows is the number of rows on the toolbar */ + infoPtr->nRows = nRows + nSepRows + 1; + +#if 0 + /******************************************************************** + * The following while interesting, does not match the values * + * created above for the button rectangles, nor the rcBound rect. * + * We will comment it out and remove it later. * + * * + * The problem showed up as heights in the pager control that was * + * wrong. * + ********************************************************************/ + + /* nSepRows * (infoPtr->nBitmapHeight + 1) is the space following */ + /* the last row. */ + infoPtr->nHeight = TOP_BORDER + (nRows + 1) * infoPtr->nButtonHeight + + nSepRows * (SEPARATOR_WIDTH * 2 / 3) + + nSepRows * (infoPtr->nBitmapHeight + 1) + + BOTTOM_BORDER; +#endif + + infoPtr->nHeight = infoPtr->rcBound.bottom - infoPtr->rcBound.top; + + TRACE("toolbar height %d, button width %d\n", infoPtr->nHeight, infoPtr->nButtonWidth); +} + + +static INT +TOOLBAR_InternalHitTest (HWND hwnd, LPPOINT lpPt) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + TBUTTON_INFO *btnPtr; + INT i; + + btnPtr = infoPtr->buttons; + for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) { + if (btnPtr->fsState & TBSTATE_HIDDEN) + continue; + + if (btnPtr->fsStyle & BTNS_SEP) { + if (PtInRect (&btnPtr->rect, *lpPt)) { + TRACE(" ON SEPARATOR %d!\n", i); + return -i; + } + } + else { + if (PtInRect (&btnPtr->rect, *lpPt)) { + TRACE(" ON BUTTON %d!\n", i); + return i; + } + } + } + + TRACE(" NOWHERE!\n"); + return TOOLBAR_NOWHERE; +} + + +static INT +TOOLBAR_GetButtonIndex (TOOLBAR_INFO *infoPtr, INT idCommand, BOOL CommandIsIndex) +{ + TBUTTON_INFO *btnPtr; + INT i; + + if (CommandIsIndex) { + TRACE("command is really index command=%d\n", idCommand); + if (idCommand >= infoPtr->nNumButtons) return -1; + return idCommand; + } + btnPtr = infoPtr->buttons; + for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) { + if (btnPtr->idCommand == idCommand) { + TRACE("command=%d index=%d\n", idCommand, i); + return i; + } + } + TRACE("no index found for command=%d\n", idCommand); + return -1; +} + + +static INT +TOOLBAR_GetCheckedGroupButtonIndex (TOOLBAR_INFO *infoPtr, INT nIndex) +{ + TBUTTON_INFO *btnPtr; + INT nRunIndex; + + if ((nIndex < 0) || (nIndex > infoPtr->nNumButtons)) + return -1; + + /* check index button */ + btnPtr = &infoPtr->buttons[nIndex]; + if ((btnPtr->fsStyle & BTNS_CHECKGROUP) == BTNS_CHECKGROUP) { + if (btnPtr->fsState & TBSTATE_CHECKED) + return nIndex; + } + + /* check previous buttons */ + nRunIndex = nIndex - 1; + while (nRunIndex >= 0) { + btnPtr = &infoPtr->buttons[nRunIndex]; + if ((btnPtr->fsStyle & BTNS_CHECKGROUP) == BTNS_CHECKGROUP) { + if (btnPtr->fsState & TBSTATE_CHECKED) + return nRunIndex; + } + else + break; + nRunIndex--; + } + + /* check next buttons */ + nRunIndex = nIndex + 1; + while (nRunIndex < infoPtr->nNumButtons) { + btnPtr = &infoPtr->buttons[nRunIndex]; + if ((btnPtr->fsStyle & BTNS_CHECKGROUP) == BTNS_CHECKGROUP) { + if (btnPtr->fsState & TBSTATE_CHECKED) + return nRunIndex; + } + else + break; + nRunIndex++; + } + + return -1; +} + + +static VOID +TOOLBAR_RelayEvent (HWND hwndTip, HWND hwndMsg, UINT uMsg, + WPARAM wParam, LPARAM lParam) +{ + MSG msg; + + msg.hwnd = hwndMsg; + msg.message = uMsg; + msg.wParam = wParam; + msg.lParam = lParam; + msg.time = GetMessageTime (); + msg.pt.x = LOWORD(GetMessagePos ()); + msg.pt.y = HIWORD(GetMessagePos ()); + + SendMessageW (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg); +} + +/* keeps available button list box sorted by button id */ +static void TOOLBAR_Cust_InsertAvailButton(HWND hwnd, PCUSTOMBUTTON btnInfoNew) +{ + int i; + int count; + PCUSTOMBUTTON btnInfo; + HWND hwndAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX); + + TRACE("button %s, idCommand %d\n", debugstr_w(btnInfoNew->text), btnInfoNew->btn.idCommand); + + count = SendMessageW(hwndAvail, LB_GETCOUNT, 0, 0); + + /* position 0 is always separator */ + for (i = 1; i < count; i++) + { + btnInfo = (PCUSTOMBUTTON)SendMessageW(hwndAvail, LB_GETITEMDATA, i, 0); + if (btnInfoNew->btn.idCommand < btnInfo->btn.idCommand) + { + i = SendMessageW(hwndAvail, LB_INSERTSTRING, i, 0); + SendMessageW(hwndAvail, LB_SETITEMDATA, i, (LPARAM)btnInfoNew); + return; + } + } + /* id higher than all others add to end */ + i = SendMessageW(hwndAvail, LB_ADDSTRING, 0, 0); + SendMessageW(hwndAvail, LB_SETITEMDATA, i, (LPARAM)btnInfoNew); +} + +static void TOOLBAR_Cust_MoveButton(PCUSTDLG_INFO custInfo, HWND hwnd, INT nIndexFrom, INT nIndexTo) +{ + NMTOOLBARW nmtb; + + TRACE("index from %d, index to %d\n", nIndexFrom, nIndexTo); + + if (nIndexFrom == nIndexTo) + return; + + /* MSDN states that iItem is the index of the button, rather than the + * command ID as used by every other NMTOOLBAR notification */ + nmtb.iItem = nIndexFrom; + if (TOOLBAR_SendNotify(&nmtb.hdr, custInfo->tbInfo, TBN_QUERYINSERT)) + { + PCUSTOMBUTTON btnInfo; + NMHDR hdr; + HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX); + int count = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); + + btnInfo = (PCUSTOMBUTTON)SendMessageW(hwndList, LB_GETITEMDATA, nIndexFrom, 0); + + SendMessageW(hwndList, LB_DELETESTRING, nIndexFrom, 0); + SendMessageW(hwndList, LB_INSERTSTRING, nIndexTo, 0); + SendMessageW(hwndList, LB_SETITEMDATA, nIndexTo, (LPARAM)btnInfo); + SendMessageW(hwndList, LB_SETCURSEL, nIndexTo, 0); + + if (nIndexTo <= 0) + EnableWindow(GetDlgItem(hwnd,IDC_MOVEUP_BTN), FALSE); + else + EnableWindow(GetDlgItem(hwnd,IDC_MOVEUP_BTN), TRUE); + + /* last item is always separator, so -2 instead of -1 */ + if (nIndexTo >= (count - 2)) + EnableWindow(GetDlgItem(hwnd,IDC_MOVEDN_BTN), FALSE); + else + EnableWindow(GetDlgItem(hwnd,IDC_MOVEDN_BTN), TRUE); + + SendMessageW(custInfo->tbHwnd, TB_DELETEBUTTON, nIndexFrom, 0); + SendMessageW(custInfo->tbHwnd, TB_INSERTBUTTONW, nIndexTo, (LPARAM)&(btnInfo->btn)); + + TOOLBAR_SendNotify(&hdr, custInfo->tbInfo, TBN_TOOLBARCHANGE); + } +} + +static void TOOLBAR_Cust_AddButton(PCUSTDLG_INFO custInfo, HWND hwnd, INT nIndexAvail, INT nIndexTo) +{ + NMTOOLBARW nmtb; + + TRACE("Add: nIndexAvail %d, nIndexTo %d\n", nIndexAvail, nIndexTo); + + /* MSDN states that iItem is the index of the button, rather than the + * command ID as used by every other NMTOOLBAR notification */ + nmtb.iItem = nIndexAvail; + if (TOOLBAR_SendNotify(&nmtb.hdr, custInfo->tbInfo, TBN_QUERYINSERT)) + { + PCUSTOMBUTTON btnInfo; + NMHDR hdr; + HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX); + HWND hwndAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX); + int count = SendMessageW(hwndAvail, LB_GETCOUNT, 0, 0); + + btnInfo = (PCUSTOMBUTTON)SendMessageW(hwndAvail, LB_GETITEMDATA, nIndexAvail, 0); + + if (nIndexAvail != 0) /* index == 0 indicates separator */ + { + /* remove from 'available buttons' list */ + SendMessageW(hwndAvail, LB_DELETESTRING, nIndexAvail, 0); + if (nIndexAvail == count-1) + SendMessageW(hwndAvail, LB_SETCURSEL, nIndexAvail-1 , 0); + else + SendMessageW(hwndAvail, LB_SETCURSEL, nIndexAvail , 0); + } + else + { + PCUSTOMBUTTON btnNew; + + /* duplicate 'separator' button */ + btnNew = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON)); + memcpy(btnNew, btnInfo, sizeof(CUSTOMBUTTON)); + btnInfo = btnNew; + } + + /* insert into 'toolbar button' list */ + SendMessageW(hwndList, LB_INSERTSTRING, nIndexTo, 0); + SendMessageW(hwndList, LB_SETITEMDATA, nIndexTo, (LPARAM)btnInfo); + + SendMessageW(custInfo->tbHwnd, TB_INSERTBUTTONW, nIndexTo, (LPARAM)&(btnInfo->btn)); + + TOOLBAR_SendNotify(&hdr, custInfo->tbInfo, TBN_TOOLBARCHANGE); + } +} + +static void TOOLBAR_Cust_RemoveButton(PCUSTDLG_INFO custInfo, HWND hwnd, INT index) +{ + PCUSTOMBUTTON btnInfo; + HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX); + + TRACE("Remove: index %d\n", index); + + btnInfo = (PCUSTOMBUTTON)SendMessageW(hwndList, LB_GETITEMDATA, index, 0); + + /* send TBN_QUERYDELETE notification */ + if (TOOLBAR_IsButtonRemovable(custInfo->tbInfo, index, btnInfo)) + { + NMHDR hdr; + + SendMessageW(hwndList, LB_DELETESTRING, index, 0); + SendMessageW(hwndList, LB_SETCURSEL, index , 0); + + SendMessageW(custInfo->tbHwnd, TB_DELETEBUTTON, index, 0); + + /* insert into 'available button' list */ + if (!(btnInfo->btn.fsStyle & BTNS_SEP)) + TOOLBAR_Cust_InsertAvailButton(hwnd, btnInfo); + else + Free(btnInfo); + + TOOLBAR_SendNotify(&hdr, custInfo->tbInfo, TBN_TOOLBARCHANGE); + } +} + +/* drag list notification function for toolbar buttons list box */ +static LRESULT TOOLBAR_Cust_ToolbarDragListNotification(PCUSTDLG_INFO custInfo, HWND hwnd, DRAGLISTINFO *pDLI) +{ + HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX); + switch (pDLI->uNotification) + { + case DL_BEGINDRAG: + { + INT nCurrentItem = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE); + INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); + /* no dragging for last item (separator) */ + if (nCurrentItem >= (nCount - 1)) return FALSE; + return TRUE; + } + case DL_DRAGGING: + { + INT nCurrentItem = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE); + INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); + /* no dragging past last item (separator) */ + if ((nCurrentItem >= 0) && (nCurrentItem < (nCount - 1))) + { + DrawInsert(hwnd, hwndList, nCurrentItem); + /* FIXME: native uses "move button" cursor */ + return DL_COPYCURSOR; + } + + /* not over toolbar buttons list */ + if (nCurrentItem < 0) + { + POINT ptWindow = pDLI->ptCursor; + HWND hwndListAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX); + MapWindowPoints(NULL, hwnd, &ptWindow, 1); + /* over available buttons list? */ + if (ChildWindowFromPoint(hwnd, ptWindow) == hwndListAvail) + /* FIXME: native uses "move button" cursor */ + return DL_COPYCURSOR; + } + /* clear drag arrow */ + DrawInsert(hwnd, hwndList, -1); + return DL_STOPCURSOR; + } + case DL_DROPPED: + { + INT nIndexTo = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE); + INT nIndexFrom = SendMessageW(hwndList, LB_GETCURSEL, 0, 0); + INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); + if ((nIndexTo >= 0) && (nIndexTo < (nCount - 1))) + { + /* clear drag arrow */ + DrawInsert(hwnd, hwndList, -1); + /* move item */ + TOOLBAR_Cust_MoveButton(custInfo, hwnd, nIndexFrom, nIndexTo); + } + /* not over toolbar buttons list */ + if (nIndexTo < 0) + { + POINT ptWindow = pDLI->ptCursor; + HWND hwndListAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX); + MapWindowPoints(NULL, hwnd, &ptWindow, 1); + /* over available buttons list? */ + if (ChildWindowFromPoint(hwnd, ptWindow) == hwndListAvail) + TOOLBAR_Cust_RemoveButton(custInfo, hwnd, nIndexFrom); + } + break; + } + case DL_CANCELDRAG: + /* Clear drag arrow */ + DrawInsert(hwnd, hwndList, -1); + break; + } + + return 0; +} + +/* drag list notification function for available buttons list box */ +static LRESULT TOOLBAR_Cust_AvailDragListNotification(PCUSTDLG_INFO custInfo, HWND hwnd, DRAGLISTINFO *pDLI) +{ + HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX); + switch (pDLI->uNotification) + { + case DL_BEGINDRAG: + return TRUE; + case DL_DRAGGING: + { + INT nCurrentItem = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE); + INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); + /* no dragging past last item (separator) */ + if ((nCurrentItem >= 0) && (nCurrentItem < nCount)) + { + DrawInsert(hwnd, hwndList, nCurrentItem); + /* FIXME: native uses "move button" cursor */ + return DL_COPYCURSOR; + } + + /* not over toolbar buttons list */ + if (nCurrentItem < 0) + { + POINT ptWindow = pDLI->ptCursor; + HWND hwndListAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX); + MapWindowPoints(NULL, hwnd, &ptWindow, 1); + /* over available buttons list? */ + if (ChildWindowFromPoint(hwnd, ptWindow) == hwndListAvail) + /* FIXME: native uses "move button" cursor */ + return DL_COPYCURSOR; + } + /* clear drag arrow */ + DrawInsert(hwnd, hwndList, -1); + return DL_STOPCURSOR; + } + case DL_DROPPED: + { + INT nIndexTo = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE); + INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); + INT nIndexFrom = SendDlgItemMessageW(hwnd, IDC_AVAILBTN_LBOX, LB_GETCURSEL, 0, 0); + if ((nIndexTo >= 0) && (nIndexTo < nCount)) + { + /* clear drag arrow */ + DrawInsert(hwnd, hwndList, -1); + /* add item */ + TOOLBAR_Cust_AddButton(custInfo, hwnd, nIndexFrom, nIndexTo); + } + } + case DL_CANCELDRAG: + /* Clear drag arrow */ + DrawInsert(hwnd, hwndList, -1); + break; + } + return 0; +} + +extern UINT uDragListMessage; + +/*********************************************************************** + * TOOLBAR_CustomizeDialogProc + * This function implements the toolbar customization dialog. + */ +static INT_PTR CALLBACK +TOOLBAR_CustomizeDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + PCUSTDLG_INFO custInfo = (PCUSTDLG_INFO)GetWindowLongPtrW (hwnd, DWLP_USER); + PCUSTOMBUTTON btnInfo; + NMTOOLBARA nmtb; + TOOLBAR_INFO *infoPtr = custInfo ? custInfo->tbInfo : NULL; + + switch (uMsg) + { + case WM_INITDIALOG: + custInfo = (PCUSTDLG_INFO)lParam; + SetWindowLongPtrW (hwnd, DWLP_USER, (LONG_PTR)custInfo); + + if (custInfo) + { + WCHAR Buffer[256]; + int i = 0; + int index; + + infoPtr = custInfo->tbInfo; + + /* send TBN_QUERYINSERT notification */ + nmtb.iItem = custInfo->tbInfo->nNumButtons; + + if (!TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_QUERYINSERT)) + return FALSE; + + /* UNDOCUMENTED: dialog hwnd immediately follows NMHDR */ + /* FIXME: this hack won't work on 64-bit - we need to declare a structure for this */ + nmtb.iItem = (int)hwnd; + /* Send TBN_INITCUSTOMIZE notification */ + if (TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr, TBN_INITCUSTOMIZE) == + TBNRF_HIDEHELP) + { + TRACE("TBNRF_HIDEHELP requested\n"); + ShowWindow(GetDlgItem(hwnd, IDC_HELP_BTN), SW_HIDE); + } + + /* add items to 'toolbar buttons' list and check if removable */ + for (i = 0; i < custInfo->tbInfo->nNumButtons; i++) + { + btnInfo = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON)); + memset (&btnInfo->btn, 0, sizeof(TBBUTTON)); + btnInfo->btn.fsStyle = BTNS_SEP; + btnInfo->bVirtual = FALSE; + LoadStringW (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64); + + /* send TBN_QUERYDELETE notification */ + btnInfo->bRemovable = TOOLBAR_IsButtonRemovable(infoPtr, i, btnInfo); + + index = (int)SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_ADDSTRING, 0, 0); + SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo); + } + + SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMHEIGHT, 0, infoPtr->nBitmapHeight + 8); + + /* insert separator button into 'available buttons' list */ + btnInfo = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON)); + memset (&btnInfo->btn, 0, sizeof(TBBUTTON)); + btnInfo->btn.fsStyle = BTNS_SEP; + btnInfo->bVirtual = FALSE; + btnInfo->bRemovable = TRUE; + LoadStringW (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64); + index = (int)SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_ADDSTRING, 0, (LPARAM)btnInfo); + SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo); + + /* insert all buttons into dsa */ + for (i = 0;; i++) + { + /* send TBN_GETBUTTONINFO notification */ + NMTOOLBARW nmtb; + nmtb.iItem = i; + nmtb.pszText = Buffer; + nmtb.cchText = 256; + + /* Clear previous button's text */ + ZeroMemory(nmtb.pszText, nmtb.cchText * sizeof(WCHAR)); + + if (!TOOLBAR_GetButtonInfo(infoPtr, &nmtb)) + break; + + TRACE("WM_INITDIALOG style: %x iItem(%d) idCommand(%d) iString(%d) %s\n", + nmtb.tbButton.fsStyle, i, + nmtb.tbButton.idCommand, + nmtb.tbButton.iString, + nmtb.tbButton.iString >= 0 ? debugstr_w(infoPtr->strings[nmtb.tbButton.iString]) + : ""); + + /* insert button into the apropriate list */ + index = TOOLBAR_GetButtonIndex (custInfo->tbInfo, nmtb.tbButton.idCommand, FALSE); + if (index == -1) + { + btnInfo = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON)); + btnInfo->bVirtual = FALSE; + btnInfo->bRemovable = TRUE; + } + else + { + btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, + IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0); + } + + memcpy (&btnInfo->btn, &nmtb.tbButton, sizeof(TBBUTTON)); + if (!(nmtb.tbButton.fsStyle & BTNS_SEP)) + { + if (lstrlenW(nmtb.pszText)) + lstrcpyW(btnInfo->text, nmtb.pszText); + else if (nmtb.tbButton.iString >= 0 && + nmtb.tbButton.iString < infoPtr->nNumStrings) + { + lstrcpyW(btnInfo->text, + infoPtr->strings[nmtb.tbButton.iString]); + } + } + + if (index == -1) + TOOLBAR_Cust_InsertAvailButton(hwnd, btnInfo); + } + + SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMHEIGHT, 0, infoPtr->nBitmapHeight + 8); + + /* select first item in the 'available' list */ + SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_SETCURSEL, 0, 0); + + /* append 'virtual' separator button to the 'toolbar buttons' list */ + btnInfo = (PCUSTOMBUTTON)Alloc(sizeof(CUSTOMBUTTON)); + memset (&btnInfo->btn, 0, sizeof(TBBUTTON)); + btnInfo->btn.fsStyle = BTNS_SEP; + btnInfo->bVirtual = TRUE; + btnInfo->bRemovable = FALSE; + LoadStringW (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64); + index = (int)SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_ADDSTRING, 0, (LPARAM)btnInfo); + SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo); + + /* select last item in the 'toolbar' list */ + SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETCURSEL, index, 0); + SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETTOPINDEX, index, 0); + + MakeDragList(GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX)); + MakeDragList(GetDlgItem(hwnd, IDC_AVAILBTN_LBOX)); + + /* set focus and disable buttons */ + PostMessageW (hwnd, WM_USER, 0, 0); + } + return TRUE; + + case WM_USER: + EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE); + EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE); + EnableWindow (GetDlgItem (hwnd,IDC_REMOVE_BTN), FALSE); + SetFocus (GetDlgItem (hwnd, IDC_TOOLBARBTN_LBOX)); + return TRUE; + + case WM_CLOSE: + EndDialog(hwnd, FALSE); + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_TOOLBARBTN_LBOX: + if (HIWORD(wParam) == LBN_SELCHANGE) + { + PCUSTOMBUTTON btnInfo; + NMTOOLBARA nmtb; + int count; + int index; + + count = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0); + index = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0); + + /* send TBN_QUERYINSERT notification */ + nmtb.iItem = index; + TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_QUERYINSERT); + + /* get list box item */ + btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0); + + if (index == (count - 1)) + { + /* last item (virtual separator) */ + EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE); + EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE); + } + else if (index == (count - 2)) + { + /* second last item (last non-virtual item) */ + EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), TRUE); + EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE); + } + else if (index == 0) + { + /* first item */ + EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE); + EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), TRUE); + } + else + { + EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), TRUE); + EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), TRUE); + } + + EnableWindow (GetDlgItem (hwnd,IDC_REMOVE_BTN), btnInfo->bRemovable); + } + break; + + case IDC_MOVEUP_BTN: + { + int index = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0); + TOOLBAR_Cust_MoveButton(custInfo, hwnd, index, index-1); + } + break; + + case IDC_MOVEDN_BTN: /* move down */ + { + int index = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0); + TOOLBAR_Cust_MoveButton(custInfo, hwnd, index, index+1); + } + break; + + case IDC_REMOVE_BTN: /* remove button */ + { + int index = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0); + + if (LB_ERR == index) + break; + + TOOLBAR_Cust_RemoveButton(custInfo, hwnd, index); + } + break; + case IDC_HELP_BTN: + TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_CUSTHELP); + break; + case IDC_RESET_BTN: + TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_RESET); + break; + + case IDOK: /* Add button */ + { + int index; + int indexto; + + index = SendDlgItemMessageW(hwnd, IDC_AVAILBTN_LBOX, LB_GETCURSEL, 0, 0); + indexto = SendDlgItemMessageW(hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0); + + TOOLBAR_Cust_AddButton(custInfo, hwnd, index, indexto); + } + break; + + case IDCANCEL: + EndDialog(hwnd, FALSE); + break; + } + return TRUE; + + case WM_DESTROY: + { + int count; + int i; + + /* delete items from 'toolbar buttons' listbox*/ + count = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0); + for (i = 0; i < count; i++) + { + btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, i, 0); + Free(btnInfo); + SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, 0, 0); + } + SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_RESETCONTENT, 0, 0); + + + /* delete items from 'available buttons' listbox*/ + count = SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_GETCOUNT, 0, 0); + for (i = 0; i < count; i++) + { + btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_GETITEMDATA, i, 0); + Free(btnInfo); + SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMDATA, i, 0); + } + SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_RESETCONTENT, 0, 0); + } + return TRUE; + + case WM_DRAWITEM: + if (wParam == IDC_AVAILBTN_LBOX || wParam == IDC_TOOLBARBTN_LBOX) + { + LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam; + RECT rcButton; + RECT rcText; + HPEN hPen, hOldPen; + HBRUSH hOldBrush; + COLORREF oldText = 0; + COLORREF oldBk = 0; + + /* get item data */ + btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, wParam, LB_GETITEMDATA, (WPARAM)lpdis->itemID, 0); + if (btnInfo == NULL) + { + FIXME("btnInfo invalid!\n"); + return TRUE; + } + + /* set colors and select objects */ + oldBk = SetBkColor (lpdis->hDC, (lpdis->itemState & ODS_FOCUS)?comctl32_color.clrHighlight:comctl32_color.clrWindow); + if (btnInfo->bVirtual) + oldText = SetTextColor (lpdis->hDC, comctl32_color.clrGrayText); + else + oldText = SetTextColor (lpdis->hDC, (lpdis->itemState & ODS_FOCUS)?comctl32_color.clrHighlightText:comctl32_color.clrWindowText); + hPen = CreatePen( PS_SOLID, 1, + GetSysColor( (lpdis->itemState & ODS_SELECTED)?COLOR_HIGHLIGHT:COLOR_WINDOW)); + hOldPen = SelectObject (lpdis->hDC, hPen ); + hOldBrush = SelectObject (lpdis->hDC, GetSysColorBrush ((lpdis->itemState & ODS_FOCUS)?COLOR_HIGHLIGHT:COLOR_WINDOW)); + + /* fill background rectangle */ + Rectangle (lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, + lpdis->rcItem.right, lpdis->rcItem.bottom); + + /* calculate button and text rectangles */ + CopyRect (&rcButton, &lpdis->rcItem); + InflateRect (&rcButton, -1, -1); + CopyRect (&rcText, &rcButton); + rcButton.right = rcButton.left + custInfo->tbInfo->nBitmapWidth + 6; + rcText.left = rcButton.right + 2; + + /* draw focus rectangle */ + if (lpdis->itemState & ODS_FOCUS) + DrawFocusRect (lpdis->hDC, &lpdis->rcItem); + + /* draw button */ + if (!(infoPtr->dwStyle & TBSTYLE_FLAT)) + DrawEdge (lpdis->hDC, &rcButton, EDGE_RAISED, BF_RECT|BF_MIDDLE|BF_SOFT); + + /* draw image and text */ + if ((btnInfo->btn.fsStyle & BTNS_SEP) == 0) { + HIMAGELIST himl = GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr, + btnInfo->btn.iBitmap)); + ImageList_Draw (himl, GETIBITMAP(infoPtr, btnInfo->btn.iBitmap), + lpdis->hDC, rcButton.left+3, rcButton.top+3, ILD_NORMAL); + } + DrawTextW (lpdis->hDC, btnInfo->text, -1, &rcText, + DT_LEFT | DT_VCENTER | DT_SINGLELINE); + + /* delete objects and reset colors */ + SelectObject (lpdis->hDC, hOldBrush); + SelectObject (lpdis->hDC, hOldPen); + SetBkColor (lpdis->hDC, oldBk); + SetTextColor (lpdis->hDC, oldText); + DeleteObject( hPen ); + return TRUE; + } + return FALSE; + + case WM_MEASUREITEM: + if (wParam == IDC_AVAILBTN_LBOX || wParam == IDC_TOOLBARBTN_LBOX) + { + MEASUREITEMSTRUCT *lpmis = (MEASUREITEMSTRUCT*)lParam; + + lpmis->itemHeight = 15 + 8; /* default height */ + + return TRUE; + } + return FALSE; + + default: + if (uDragListMessage && (uMsg == uDragListMessage)) + { + if (wParam == IDC_TOOLBARBTN_LBOX) + { + LRESULT res = TOOLBAR_Cust_ToolbarDragListNotification( + custInfo, hwnd, (DRAGLISTINFO *)lParam); + SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, res); + return TRUE; + } + else if (wParam == IDC_AVAILBTN_LBOX) + { + LRESULT res = TOOLBAR_Cust_AvailDragListNotification( + custInfo, hwnd, (DRAGLISTINFO *)lParam); + SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, res); + return TRUE; + } + } + return FALSE; + } +} + + +/*********************************************************************** + * TOOLBAR_AddBitmap: Add the bitmaps to the default image list. + * + */ +static LRESULT +TOOLBAR_AddBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + LPTBADDBITMAP lpAddBmp = (LPTBADDBITMAP)lParam; + INT nIndex = 0, nButtons, nCount; + HBITMAP hbmLoad; + HIMAGELIST himlDef; + + TRACE("hwnd=%p wParam=%x lParam=%lx\n", hwnd, wParam, lParam); + if (!lpAddBmp) + return -1; + + if (lpAddBmp->hInst == HINST_COMMCTRL) + { + if ((lpAddBmp->nID & ~1) == IDB_STD_SMALL_COLOR) + nButtons = 15; + else if ((lpAddBmp->nID & ~1) == IDB_VIEW_SMALL_COLOR) + nButtons = 13; + else if ((lpAddBmp->nID & ~1) == IDB_HIST_SMALL_COLOR) + nButtons = 5; + else + return -1; + + TRACE ("adding %d internal bitmaps!\n", nButtons); + + /* Windows resize all the buttons to the size of a newly added standard image */ + if (lpAddBmp->nID & 1) + { + /* large icons */ + /* FIXME: on windows the size of the images is 25x24 but the size of the bitmap + * in rsrc is only 24x24. Fix the bitmap (how?) and then fix this + */ + SendMessageW (hwnd, TB_SETBITMAPSIZE, 0, + MAKELPARAM((WORD)24, (WORD)24)); + SendMessageW (hwnd, TB_SETBUTTONSIZE, 0, + MAKELPARAM((WORD)31, (WORD)30)); + } + else + { + /* small icons */ + SendMessageW (hwnd, TB_SETBITMAPSIZE, 0, + MAKELPARAM((WORD)16, (WORD)16)); + SendMessageW (hwnd, TB_SETBUTTONSIZE, 0, + MAKELPARAM((WORD)22, (WORD)22)); + } + + TOOLBAR_CalcToolbar (hwnd); + } + else + { + nButtons = (INT)wParam; + if (nButtons <= 0) + return -1; + + TRACE ("adding %d bitmaps!\n", nButtons); + } + + if (!infoPtr->cimlDef) { + /* create new default image list */ + TRACE ("creating default image list!\n"); + + himlDef = ImageList_Create (infoPtr->nBitmapWidth, infoPtr->nBitmapHeight, + ILC_COLORDDB | ILC_MASK, nButtons, 2); + TOOLBAR_InsertImageList(&infoPtr->himlDef, &infoPtr->cimlDef, himlDef, 0); + infoPtr->himlInt = himlDef; + } + else { + himlDef = GETDEFIMAGELIST(infoPtr, 0); + } + + if (!himlDef) { + WARN("No default image list available\n"); + return -1; + } + + nCount = ImageList_GetImageCount(himlDef); + + /* Add bitmaps to the default image list */ + if (lpAddBmp->hInst == NULL) + { + BITMAP bmp; + HBITMAP hOldBitmapBitmap, hOldBitmapLoad; + HDC hdcImage, hdcBitmap; + + /* copy the bitmap before adding it so that the user's bitmap + * doesn't get modified. + */ + GetObjectW ((HBITMAP)lpAddBmp->nID, sizeof(BITMAP), (LPVOID)&bmp); + + hdcImage = CreateCompatibleDC(0); + hdcBitmap = CreateCompatibleDC(0); + + /* create new bitmap */ + hbmLoad = CreateBitmap (bmp.bmWidth, bmp.bmHeight, bmp.bmPlanes, bmp.bmBitsPixel, NULL); + hOldBitmapBitmap = SelectObject(hdcBitmap, (HBITMAP)lpAddBmp->nID); + hOldBitmapLoad = SelectObject(hdcImage, hbmLoad); + + /* Copy the user's image */ + BitBlt (hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, + hdcBitmap, 0, 0, SRCCOPY); + + SelectObject (hdcImage, hOldBitmapLoad); + SelectObject (hdcBitmap, hOldBitmapBitmap); + DeleteDC (hdcImage); + DeleteDC (hdcBitmap); + + nIndex = ImageList_AddMasked (himlDef, hbmLoad, comctl32_color.clrBtnFace); + DeleteObject (hbmLoad); + } + else if (lpAddBmp->hInst == HINST_COMMCTRL) + { + /* Add system bitmaps */ + switch (lpAddBmp->nID) + { + case IDB_STD_SMALL_COLOR: + hbmLoad = LoadBitmapW (COMCTL32_hModule, + MAKEINTRESOURCEW(IDB_STD_SMALL)); + nIndex = ImageList_AddMasked (himlDef, + hbmLoad, comctl32_color.clrBtnFace); + DeleteObject (hbmLoad); + break; + + case IDB_STD_LARGE_COLOR: + hbmLoad = LoadBitmapW (COMCTL32_hModule, + MAKEINTRESOURCEW(IDB_STD_LARGE)); + nIndex = ImageList_AddMasked (himlDef, + hbmLoad, comctl32_color.clrBtnFace); + DeleteObject (hbmLoad); + break; + + case IDB_VIEW_SMALL_COLOR: + hbmLoad = LoadBitmapW (COMCTL32_hModule, + MAKEINTRESOURCEW(IDB_VIEW_SMALL)); + nIndex = ImageList_AddMasked (himlDef, + hbmLoad, comctl32_color.clrBtnFace); + DeleteObject (hbmLoad); + break; + + case IDB_VIEW_LARGE_COLOR: + hbmLoad = LoadBitmapW (COMCTL32_hModule, + MAKEINTRESOURCEW(IDB_VIEW_LARGE)); + nIndex = ImageList_AddMasked (himlDef, + hbmLoad, comctl32_color.clrBtnFace); + DeleteObject (hbmLoad); + break; + + case IDB_HIST_SMALL_COLOR: + hbmLoad = LoadBitmapW (COMCTL32_hModule, + MAKEINTRESOURCEW(IDB_HIST_SMALL)); + nIndex = ImageList_AddMasked (himlDef, + hbmLoad, comctl32_color.clrBtnFace); + DeleteObject (hbmLoad); + break; + + case IDB_HIST_LARGE_COLOR: + hbmLoad = LoadBitmapW (COMCTL32_hModule, + MAKEINTRESOURCEW(IDB_HIST_LARGE)); + nIndex = ImageList_AddMasked (himlDef, + hbmLoad, comctl32_color.clrBtnFace); + DeleteObject (hbmLoad); + break; + + default: + nIndex = ImageList_GetImageCount (himlDef); + ERR ("invalid imagelist!\n"); + break; + } + } + else + { + hbmLoad = LoadBitmapW (lpAddBmp->hInst, (LPWSTR)lpAddBmp->nID); + nIndex = ImageList_AddMasked (himlDef, hbmLoad, comctl32_color.clrBtnFace); + DeleteObject (hbmLoad); + } + + TRACE("Number of bitmap infos: %d\n", infoPtr->nNumBitmapInfos); + + if (infoPtr->nNumBitmapInfos == 0) + { + infoPtr->bitmaps = Alloc(sizeof(TBITMAP_INFO)); + } + else + { + TBITMAP_INFO *oldBitmaps = infoPtr->bitmaps; + infoPtr->bitmaps = Alloc((infoPtr->nNumBitmapInfos + 1) * sizeof(TBITMAP_INFO)); + memcpy(&infoPtr->bitmaps[0], &oldBitmaps[0], infoPtr->nNumBitmapInfos); + } + + infoPtr->bitmaps[infoPtr->nNumBitmapInfos].nButtons = nButtons; + infoPtr->bitmaps[infoPtr->nNumBitmapInfos].hInst = lpAddBmp->hInst; + infoPtr->bitmaps[infoPtr->nNumBitmapInfos].nID = lpAddBmp->nID; + + infoPtr->nNumBitmapInfos++; + TRACE("Number of bitmap infos: %d\n", infoPtr->nNumBitmapInfos); + + if (nIndex != -1) + { + INT imagecount = ImageList_GetImageCount(himlDef); + + if (infoPtr->nNumBitmaps + nButtons != imagecount) + { + WARN("Desired images do not match received images : Previous image number %i Previous images in list %i added %i expecting total %i, Images in list %i\n", + infoPtr->nNumBitmaps, nCount, imagecount - nCount, + infoPtr->nNumBitmaps+nButtons,imagecount); + + infoPtr->nNumBitmaps = imagecount; + } + else + infoPtr->nNumBitmaps += nButtons; + } + + InvalidateRect(hwnd, NULL, TRUE); + + return nIndex; +} + + +static LRESULT +TOOLBAR_AddButtonsA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + LPTBBUTTON lpTbb = (LPTBBUTTON)lParam; + INT nOldButtons, nNewButtons, nAddButtons, nCount; + + TRACE("adding %d buttons!\n", wParam); + + nAddButtons = (UINT)wParam; + nOldButtons = infoPtr->nNumButtons; + nNewButtons = nOldButtons + nAddButtons; + + if (infoPtr->nNumButtons == 0) { + infoPtr->buttons = + Alloc (sizeof(TBUTTON_INFO) * nNewButtons); + } + else { + TBUTTON_INFO *oldButtons = infoPtr->buttons; + infoPtr->buttons = + Alloc (sizeof(TBUTTON_INFO) * nNewButtons); + memcpy (&infoPtr->buttons[0], &oldButtons[0], + nOldButtons * sizeof(TBUTTON_INFO)); + Free (oldButtons); + } + + infoPtr->nNumButtons = nNewButtons; + + /* insert new button data */ + for (nCount = 0; nCount < nAddButtons; nCount++) { + TBUTTON_INFO *btnPtr = &infoPtr->buttons[nOldButtons+nCount]; + btnPtr->iBitmap = lpTbb[nCount].iBitmap; + btnPtr->idCommand = lpTbb[nCount].idCommand; + btnPtr->fsState = lpTbb[nCount].fsState; + btnPtr->fsStyle = lpTbb[nCount].fsStyle; + btnPtr->dwData = lpTbb[nCount].dwData; + if(HIWORD(lpTbb[nCount].iString) && lpTbb[nCount].iString != -1) + Str_SetPtrAtoW ((LPWSTR*)&btnPtr->iString, (LPSTR)lpTbb[nCount].iString ); + else + btnPtr->iString = lpTbb[nCount].iString; + btnPtr->bHot = FALSE; + + if ((infoPtr->hwndToolTip) && !(btnPtr->fsStyle & BTNS_SEP)) { + TTTOOLINFOW ti; + + ZeroMemory (&ti, sizeof(ti)); + ti.cbSize = sizeof(ti); + ti.hwnd = hwnd; + ti.uId = btnPtr->idCommand; + ti.hinst = 0; + ti.lpszText = LPSTR_TEXTCALLBACKW; + + SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, + 0, (LPARAM)&ti); + } + } + + TOOLBAR_CalcToolbar (hwnd); + + TOOLBAR_DumpToolbar (infoPtr, __LINE__); + + InvalidateRect(hwnd, NULL, TRUE); + + return TRUE; +} + + +static LRESULT +TOOLBAR_AddButtonsW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + LPTBBUTTON lpTbb = (LPTBBUTTON)lParam; + INT nOldButtons, nNewButtons, nAddButtons, nCount; + + TRACE("adding %d buttons!\n", wParam); + + nAddButtons = (UINT)wParam; + nOldButtons = infoPtr->nNumButtons; + nNewButtons = nOldButtons + nAddButtons; + + if (infoPtr->nNumButtons == 0) { + infoPtr->buttons = + Alloc (sizeof(TBUTTON_INFO) * nNewButtons); + } + else { + TBUTTON_INFO *oldButtons = infoPtr->buttons; + infoPtr->buttons = + Alloc (sizeof(TBUTTON_INFO) * nNewButtons); + memcpy (&infoPtr->buttons[0], &oldButtons[0], + nOldButtons * sizeof(TBUTTON_INFO)); + Free (oldButtons); + } + + infoPtr->nNumButtons = nNewButtons; + + /* insert new button data */ + for (nCount = 0; nCount < nAddButtons; nCount++) { + TBUTTON_INFO *btnPtr = &infoPtr->buttons[nOldButtons+nCount]; + btnPtr->iBitmap = lpTbb[nCount].iBitmap; + btnPtr->idCommand = lpTbb[nCount].idCommand; + btnPtr->fsState = lpTbb[nCount].fsState; + btnPtr->fsStyle = lpTbb[nCount].fsStyle; + btnPtr->dwData = lpTbb[nCount].dwData; + if(HIWORD(lpTbb[nCount].iString) && lpTbb[nCount].iString != -1) + Str_SetPtrW ((LPWSTR*)&btnPtr->iString, (LPWSTR)lpTbb[nCount].iString ); + else + btnPtr->iString = lpTbb[nCount].iString; + btnPtr->bHot = FALSE; + + if ((infoPtr->hwndToolTip) && !(btnPtr->fsStyle & BTNS_SEP)) { + TTTOOLINFOW ti; + + ZeroMemory (&ti, sizeof(TTTOOLINFOW)); + ti.cbSize = sizeof (TTTOOLINFOW); + ti.hwnd = hwnd; + ti.uId = btnPtr->idCommand; + ti.hinst = 0; + ti.lpszText = LPSTR_TEXTCALLBACKW; + ti.lParam = lParam; + + SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, + 0, (LPARAM)&ti); + } + } + + TOOLBAR_CalcToolbar (hwnd); + + TOOLBAR_DumpToolbar (infoPtr, __LINE__); + + InvalidateRect(hwnd, NULL, TRUE); + + return TRUE; +} + + +static LRESULT +TOOLBAR_AddStringA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + INT nIndex; + + if ((wParam) && (HIWORD(lParam) == 0)) { + char szString[256]; + INT len; + TRACE("adding string from resource!\n"); + + len = LoadStringA ((HINSTANCE)wParam, (UINT)lParam, szString, sizeof(szString)); + + TRACE("len=%d \"%s\"\n", len, szString); + nIndex = infoPtr->nNumStrings; + if (infoPtr->nNumStrings == 0) { + infoPtr->strings = + Alloc (sizeof(LPWSTR)); + } + else { + LPWSTR *oldStrings = infoPtr->strings; + infoPtr->strings = + Alloc (sizeof(LPWSTR) * (infoPtr->nNumStrings + 1)); + memcpy (&infoPtr->strings[0], &oldStrings[0], + sizeof(LPWSTR) * infoPtr->nNumStrings); + Free (oldStrings); + } + + /*Alloc zeros out the allocated memory*/ + Str_SetPtrAtoW (&infoPtr->strings[infoPtr->nNumStrings], szString ); + infoPtr->nNumStrings++; + } + else { + LPSTR p = (LPSTR)lParam; + INT len; + + if (p == NULL) + return -1; + TRACE("adding string(s) from array!\n"); + + nIndex = infoPtr->nNumStrings; + while (*p) { + len = strlen (p); + TRACE("len=%d \"%s\"\n", len, p); + + if (infoPtr->nNumStrings == 0) { + infoPtr->strings = + Alloc (sizeof(LPWSTR)); + } + else { + LPWSTR *oldStrings = infoPtr->strings; + infoPtr->strings = + Alloc (sizeof(LPWSTR) * (infoPtr->nNumStrings + 1)); + memcpy (&infoPtr->strings[0], &oldStrings[0], + sizeof(LPWSTR) * infoPtr->nNumStrings); + Free (oldStrings); + } + + Str_SetPtrAtoW (&infoPtr->strings[infoPtr->nNumStrings], p ); + infoPtr->nNumStrings++; + + p += (len+1); + } + } + + return nIndex; +} + + +static LRESULT +TOOLBAR_AddStringW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ +#define MAX_RESOURCE_STRING_LENGTH 512 + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + INT nIndex; + + if ((wParam) && (HIWORD(lParam) == 0)) { + WCHAR szString[MAX_RESOURCE_STRING_LENGTH]; + INT len; + TRACE("adding string from resource!\n"); + + len = LoadStringW ((HINSTANCE)wParam, (UINT)lParam, + szString, MAX_RESOURCE_STRING_LENGTH); + + TRACE("len=%d %s\n", len, debugstr_w(szString)); + TRACE("First char: 0x%x\n", *szString); + if (szString[0] == L'|') + { + PWSTR p = szString + 1; + + nIndex = infoPtr->nNumStrings; + while (*p != L'|' && *p != L'\0') { + PWSTR np; + + if (infoPtr->nNumStrings == 0) { + infoPtr->strings = Alloc (sizeof(LPWSTR)); + } + else + { + LPWSTR *oldStrings = infoPtr->strings; + infoPtr->strings = Alloc(sizeof(LPWSTR) * (infoPtr->nNumStrings + 1)); + memcpy(&infoPtr->strings[0], &oldStrings[0], + sizeof(LPWSTR) * infoPtr->nNumStrings); + Free(oldStrings); + } + + np=strchrW (p, '|'); + if (np!=NULL) { + len = np - p; + np++; + } else { + len = strlenW(p); + np = p + len; + } + TRACE("len=%d %s\n", len, debugstr_w(p)); + infoPtr->strings[infoPtr->nNumStrings] = + Alloc (sizeof(WCHAR)*(len+1)); + lstrcpynW (infoPtr->strings[infoPtr->nNumStrings], p, len+1); + infoPtr->nNumStrings++; + + p = np; + } + } + else + { + nIndex = infoPtr->nNumStrings; + if (infoPtr->nNumStrings == 0) { + infoPtr->strings = + Alloc (sizeof(LPWSTR)); + } + else { + LPWSTR *oldStrings = infoPtr->strings; + infoPtr->strings = + Alloc (sizeof(LPWSTR) * (infoPtr->nNumStrings + 1)); + memcpy (&infoPtr->strings[0], &oldStrings[0], + sizeof(LPWSTR) * infoPtr->nNumStrings); + Free (oldStrings); + } + + Str_SetPtrW (&infoPtr->strings[infoPtr->nNumStrings], szString); + infoPtr->nNumStrings++; + } + } + else { + LPWSTR p = (LPWSTR)lParam; + INT len; + + if (p == NULL) + return -1; + TRACE("adding string(s) from array!\n"); + nIndex = infoPtr->nNumStrings; + while (*p) { + len = strlenW (p); + + TRACE("len=%d %s\n", len, debugstr_w(p)); + if (infoPtr->nNumStrings == 0) { + infoPtr->strings = + Alloc (sizeof(LPWSTR)); + } + else { + LPWSTR *oldStrings = infoPtr->strings; + infoPtr->strings = + Alloc (sizeof(LPWSTR) * (infoPtr->nNumStrings + 1)); + memcpy (&infoPtr->strings[0], &oldStrings[0], + sizeof(LPWSTR) * infoPtr->nNumStrings); + Free (oldStrings); + } + + Str_SetPtrW (&infoPtr->strings[infoPtr->nNumStrings], p); + infoPtr->nNumStrings++; + + p += (len+1); + } + } + + return nIndex; +} + + +static LRESULT +TOOLBAR_AutoSize (HWND hwnd) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + RECT parent_rect; + RECT window_rect; + HWND parent; + INT x, y; + INT cx, cy; + UINT uPosFlags = SWP_NOZORDER; + + TRACE("resize forced, style=%lx!\n", infoPtr->dwStyle); + + parent = GetParent (hwnd); + GetClientRect(parent, &parent_rect); + + x = parent_rect.left; + y = parent_rect.top; + + /* FIXME: we should be able to early out if nothing */ + /* has changed with nWidth != parent_rect width */ + + if (infoPtr->dwStyle & CCS_NORESIZE) { + uPosFlags |= (SWP_NOSIZE | SWP_NOMOVE); + cx = 0; + cy = 0; + TOOLBAR_CalcToolbar (hwnd); + } + else { + infoPtr->nWidth = parent_rect.right - parent_rect.left; + TOOLBAR_CalcToolbar (hwnd); + InvalidateRect( hwnd, NULL, TRUE ); + cy = infoPtr->nHeight; + cx = infoPtr->nWidth; + + if ((infoPtr->dwStyle & CCS_BOTTOM) == CCS_NOMOVEY) { + GetWindowRect(hwnd, &window_rect); + ScreenToClient(parent, (LPPOINT)&window_rect.left); + y = window_rect.top; + } + if ((infoPtr->dwStyle & CCS_BOTTOM) == CCS_BOTTOM) { + GetWindowRect(hwnd, &window_rect); + y = parent_rect.bottom - ( window_rect.bottom - window_rect.top); + } + } + + if (infoPtr->dwStyle & CCS_NOPARENTALIGN) + uPosFlags |= SWP_NOMOVE; + + if (!(infoPtr->dwStyle & CCS_NODIVIDER)) + cy += GetSystemMetrics(SM_CYEDGE); + + if (infoPtr->dwStyle & WS_BORDER) + { + x = y = 1; + cy += GetSystemMetrics(SM_CYEDGE); + cx += GetSystemMetrics(SM_CXEDGE); + } + + infoPtr->bAutoSize = TRUE; + SetWindowPos (hwnd, HWND_TOP, x, y, cx, cy, uPosFlags); + /* The following line makes sure that the infoPtr->bAutoSize is turned off + * after the setwindowpos calls */ + infoPtr->bAutoSize = FALSE; + + return 0; +} + + +static LRESULT +TOOLBAR_ButtonCount (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + return infoPtr->nNumButtons; +} + + +static LRESULT +TOOLBAR_ButtonStructSize (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + infoPtr->dwStructSize = (DWORD)wParam; + + return 0; +} + + +static LRESULT +TOOLBAR_ChangeBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + TBUTTON_INFO *btnPtr; + INT nIndex; + + TRACE("button %d, iBitmap now %d\n", wParam, LOWORD(lParam)); + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); + if (nIndex == -1) + return FALSE; + + btnPtr = &infoPtr->buttons[nIndex]; + btnPtr->iBitmap = LOWORD(lParam); + + /* we HAVE to erase the background, the new bitmap could be */ + /* transparent */ + InvalidateRect(hwnd, &btnPtr->rect, TRUE); + + return TRUE; +} + + +static LRESULT +TOOLBAR_CheckButton (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + TBUTTON_INFO *btnPtr; + INT nIndex; + INT nOldIndex = -1; + BOOL bChecked = FALSE; + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); + + TRACE("hwnd=%p, btn index=%d, lParam=0x%08lx\n", hwnd, nIndex, lParam); + + if (nIndex == -1) + return FALSE; + + btnPtr = &infoPtr->buttons[nIndex]; + + bChecked = (btnPtr->fsState & TBSTATE_CHECKED) ? TRUE : FALSE; + + if (LOWORD(lParam) == FALSE) + btnPtr->fsState &= ~TBSTATE_CHECKED; + else { + if (btnPtr->fsStyle & BTNS_GROUP) { + nOldIndex = + TOOLBAR_GetCheckedGroupButtonIndex (infoPtr, nIndex); + if (nOldIndex == nIndex) + return 0; + if (nOldIndex != -1) + infoPtr->buttons[nOldIndex].fsState &= ~TBSTATE_CHECKED; + } + btnPtr->fsState |= TBSTATE_CHECKED; + } + + if( bChecked != LOWORD(lParam) ) + { + if (nOldIndex != -1) + InvalidateRect(hwnd, &infoPtr->buttons[nOldIndex].rect, TRUE); + InvalidateRect(hwnd, &btnPtr->rect, TRUE); + } + + /* FIXME: Send a WM_NOTIFY?? */ + + return TRUE; +} + + +static LRESULT +TOOLBAR_CommandToIndex (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + return TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); +} + + +static LRESULT +TOOLBAR_Customize (HWND hwnd) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + CUSTDLG_INFO custInfo; + LRESULT ret; + LPCVOID template; + HRSRC hRes; + NMHDR nmhdr; + + custInfo.tbInfo = infoPtr; + custInfo.tbHwnd = hwnd; + + /* send TBN_BEGINADJUST notification */ + TOOLBAR_SendNotify (&nmhdr, infoPtr, TBN_BEGINADJUST); + + if (!(hRes = FindResourceW (COMCTL32_hModule, + MAKEINTRESOURCEW(IDD_TBCUSTOMIZE), + (LPWSTR)RT_DIALOG))) + return FALSE; + + if(!(template = (LPVOID)LoadResource (COMCTL32_hModule, hRes))) + return FALSE; + + ret = DialogBoxIndirectParamW ((HINSTANCE)GetWindowLongPtrW(hwnd, GWLP_HINSTANCE), + (LPDLGTEMPLATEW)template, + hwnd, + TOOLBAR_CustomizeDialogProc, + (LPARAM)&custInfo); + + /* send TBN_ENDADJUST notification */ + TOOLBAR_SendNotify (&nmhdr, infoPtr, TBN_ENDADJUST); + + return ret; +} + + +static LRESULT +TOOLBAR_DeleteButton (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + INT nIndex = (INT)wParam; + NMTOOLBARW nmtb; + TBUTTON_INFO *btnPtr = &infoPtr->buttons[nIndex]; + + if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons)) + return FALSE; + + memset(&nmtb, 0, sizeof(nmtb)); + nmtb.iItem = btnPtr->idCommand; + nmtb.tbButton.iBitmap = btnPtr->iBitmap; + nmtb.tbButton.idCommand = btnPtr->idCommand; + nmtb.tbButton.fsState = btnPtr->fsState; + nmtb.tbButton.fsStyle = btnPtr->fsStyle; + nmtb.tbButton.dwData = btnPtr->dwData; + nmtb.tbButton.iString = btnPtr->iString; + TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_DELETINGBUTTON); + + if ((infoPtr->hwndToolTip) && + !(btnPtr->fsStyle & BTNS_SEP)) { + TTTOOLINFOW ti; + + ZeroMemory (&ti, sizeof(ti)); + ti.cbSize = sizeof(ti); + ti.hwnd = hwnd; + ti.uId = infoPtr->buttons[nIndex].idCommand; + + SendMessageW (infoPtr->hwndToolTip, TTM_DELTOOLW, 0, (LPARAM)&ti); + } + + if (infoPtr->nNumButtons == 1) { + TRACE(" simple delete!\n"); + Free (infoPtr->buttons); + infoPtr->buttons = NULL; + infoPtr->nNumButtons = 0; + } + else { + TBUTTON_INFO *oldButtons = infoPtr->buttons; + TRACE("complex delete! [nIndex=%d]\n", nIndex); + + infoPtr->nNumButtons--; + infoPtr->buttons = Alloc (sizeof (TBUTTON_INFO) * infoPtr->nNumButtons); + if (nIndex > 0) { + memcpy (&infoPtr->buttons[0], &oldButtons[0], + nIndex * sizeof(TBUTTON_INFO)); + } + + if (nIndex < infoPtr->nNumButtons) { + memcpy (&infoPtr->buttons[nIndex], &oldButtons[nIndex+1], + (infoPtr->nNumButtons - nIndex) * sizeof(TBUTTON_INFO)); + } + + Free (oldButtons); + } + + TOOLBAR_CalcToolbar (hwnd); + + InvalidateRect (hwnd, NULL, TRUE); + + return TRUE; +} + + +static LRESULT +TOOLBAR_EnableButton (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + TBUTTON_INFO *btnPtr; + INT nIndex; + DWORD bState; + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); + + TRACE("hwnd=%p, btn index=%d, lParam=0x%08lx\n", hwnd, wParam, lParam); + + if (nIndex == -1) + return FALSE; + + btnPtr = &infoPtr->buttons[nIndex]; + + bState = btnPtr->fsState & TBSTATE_ENABLED; + + /* update the toolbar button state */ + if(LOWORD(lParam) == FALSE) { + btnPtr->fsState &= ~(TBSTATE_ENABLED | TBSTATE_PRESSED); + } else { + btnPtr->fsState |= TBSTATE_ENABLED; + } + + /* redraw the button only if the state of the button changed */ + if(bState != (btnPtr->fsState & TBSTATE_ENABLED)) + InvalidateRect(hwnd, &btnPtr->rect, TRUE); + + return TRUE; +} + + +static inline LRESULT +TOOLBAR_GetAnchorHighlight (HWND hwnd) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + return infoPtr->bAnchor; +} + + +static LRESULT +TOOLBAR_GetBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + INT nIndex; + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); + if (nIndex == -1) + return -1; + + return infoPtr->buttons[nIndex].iBitmap; +} + + +static inline LRESULT +TOOLBAR_GetBitmapFlags (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + return (GetDeviceCaps (0, LOGPIXELSX) >= 120) ? TBBF_LARGE : 0; +} + + +static LRESULT +TOOLBAR_GetButton (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + LPTBBUTTON lpTbb = (LPTBBUTTON)lParam; + INT nIndex = (INT)wParam; + TBUTTON_INFO *btnPtr; + + if (lpTbb == NULL) + return FALSE; + + if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons)) + return FALSE; + + btnPtr = &infoPtr->buttons[nIndex]; + lpTbb->iBitmap = btnPtr->iBitmap; + lpTbb->idCommand = btnPtr->idCommand; + lpTbb->fsState = btnPtr->fsState; + lpTbb->fsStyle = btnPtr->fsStyle; + lpTbb->bReserved[0] = 0; + lpTbb->bReserved[1] = 0; + lpTbb->dwData = btnPtr->dwData; + lpTbb->iString = btnPtr->iString; + + return TRUE; +} + + +static LRESULT +TOOLBAR_GetButtonInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + LPTBBUTTONINFOA lpTbInfo = (LPTBBUTTONINFOA)lParam; + TBUTTON_INFO *btnPtr; + INT nIndex; + + if (lpTbInfo == NULL) + return -1; + if (lpTbInfo->cbSize < sizeof(TBBUTTONINFOA)) + return -1; + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, + lpTbInfo->dwMask & 0x80000000); + if (nIndex == -1) + return -1; + + if (!(btnPtr = &infoPtr->buttons[nIndex])) return -1; + + if (lpTbInfo->dwMask & TBIF_COMMAND) + lpTbInfo->idCommand = btnPtr->idCommand; + if (lpTbInfo->dwMask & TBIF_IMAGE) + lpTbInfo->iImage = btnPtr->iBitmap; + if (lpTbInfo->dwMask & TBIF_LPARAM) + lpTbInfo->lParam = btnPtr->dwData; + if (lpTbInfo->dwMask & TBIF_SIZE) + lpTbInfo->cx = (WORD)(btnPtr->rect.right - btnPtr->rect.left); + if (lpTbInfo->dwMask & TBIF_STATE) + lpTbInfo->fsState = btnPtr->fsState; + if (lpTbInfo->dwMask & TBIF_STYLE) + lpTbInfo->fsStyle = btnPtr->fsStyle; + if (lpTbInfo->dwMask & TBIF_TEXT) { + /* TB_GETBUTTONINFO doesn't retrieve text from the string list, so we + can't use TOOLBAR_GetText here */ + LPWSTR lpText; + if (HIWORD(btnPtr->iString) && (btnPtr->iString != -1)) { + lpText = (LPWSTR)btnPtr->iString; + Str_GetPtrWtoA (lpText, lpTbInfo->pszText,lpTbInfo->cchText); + } else + lpTbInfo->pszText[0] = '\0'; + } + return nIndex; +} + + +static LRESULT +TOOLBAR_GetButtonInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + LPTBBUTTONINFOW lpTbInfo = (LPTBBUTTONINFOW)lParam; + TBUTTON_INFO *btnPtr; + INT nIndex; + + if (lpTbInfo == NULL) + return -1; + if (lpTbInfo->cbSize < sizeof(TBBUTTONINFOW)) + return -1; + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, + lpTbInfo->dwMask & 0x80000000); + if (nIndex == -1) + return -1; + + btnPtr = &infoPtr->buttons[nIndex]; + + if(!btnPtr) + return -1; + + if (lpTbInfo->dwMask & TBIF_COMMAND) + lpTbInfo->idCommand = btnPtr->idCommand; + if (lpTbInfo->dwMask & TBIF_IMAGE) + lpTbInfo->iImage = btnPtr->iBitmap; + if (lpTbInfo->dwMask & TBIF_LPARAM) + lpTbInfo->lParam = btnPtr->dwData; + if (lpTbInfo->dwMask & TBIF_SIZE) + lpTbInfo->cx = (WORD)(btnPtr->rect.right - btnPtr->rect.left); + if (lpTbInfo->dwMask & TBIF_STATE) + lpTbInfo->fsState = btnPtr->fsState; + if (lpTbInfo->dwMask & TBIF_STYLE) + lpTbInfo->fsStyle = btnPtr->fsStyle; + if (lpTbInfo->dwMask & TBIF_TEXT) { + /* TB_GETBUTTONINFO doesn't retrieve text from the string list, so we + can't use TOOLBAR_GetText here */ + LPWSTR lpText; + if (HIWORD(btnPtr->iString) && (btnPtr->iString != -1)) { + lpText = (LPWSTR)btnPtr->iString; + Str_GetPtrW (lpText,lpTbInfo->pszText,lpTbInfo->cchText); + } else + lpTbInfo->pszText[0] = '\0'; + } + + return nIndex; +} + + +static LRESULT +TOOLBAR_GetButtonSize (HWND hwnd) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + if (infoPtr->nNumButtons > 0) + return MAKELONG((WORD)infoPtr->nButtonWidth, + (WORD)infoPtr->nButtonHeight); + else + return MAKELONG(23,22); +} + + +static LRESULT +TOOLBAR_GetButtonTextA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + INT nIndex; + LPWSTR lpText; + + if (lParam == 0) + return -1; + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); + if (nIndex == -1) + return -1; + + lpText = TOOLBAR_GetText(infoPtr,&infoPtr->buttons[nIndex]); + + return WideCharToMultiByte( CP_ACP, 0, lpText, -1, + (LPSTR)lParam, 0x7fffffff, NULL, NULL ) - 1; +} + + +static LRESULT +TOOLBAR_GetButtonTextW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + INT nIndex; + LPWSTR lpText; + LRESULT ret = 0; + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); + if (nIndex == -1) + return -1; + + lpText = TOOLBAR_GetText(infoPtr,&infoPtr->buttons[nIndex]); + + if (lpText) + { + ret = strlenW (lpText); + + if (lParam) + strcpyW ((LPWSTR)lParam, lpText); + } + + return ret; +} + + +static LRESULT +TOOLBAR_GetDisabledImageList (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TRACE("hwnd=%p, wParam=%d, lParam=0x%lx\n", hwnd, wParam, lParam); + /* UNDOCUMENTED: wParam is actually the ID of the image list to return */ + return (LRESULT)GETDISIMAGELIST(TOOLBAR_GetInfoPtr (hwnd), wParam); +} + + +inline static LRESULT +TOOLBAR_GetExtendedStyle (HWND hwnd) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + TRACE("\n"); + + return infoPtr->dwExStyle; +} + + +static LRESULT +TOOLBAR_GetHotImageList (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TRACE("hwnd=%p, wParam=%d, lParam=0x%lx\n", hwnd, wParam, lParam); + /* UNDOCUMENTED: wParam is actually the ID of the image list to return */ + return (LRESULT)GETHOTIMAGELIST(TOOLBAR_GetInfoPtr (hwnd), wParam); +} + + +static LRESULT +TOOLBAR_GetHotItem (HWND hwnd) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + if (!(infoPtr->dwStyle & TBSTYLE_FLAT)) + return -1; + + if (infoPtr->nHotItem < 0) + return -1; + + return (LRESULT)infoPtr->nHotItem; +} + + +static LRESULT +TOOLBAR_GetDefImageList (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TRACE("hwnd=%p, wParam=%d, lParam=0x%lx\n", hwnd, wParam, lParam); + /* UNDOCUMENTED: wParam is actually the ID of the image list to return */ + return (LRESULT) GETDEFIMAGELIST(TOOLBAR_GetInfoPtr(hwnd), wParam); +} + + +static LRESULT +TOOLBAR_GetInsertMark (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + TBINSERTMARK *lptbim = (TBINSERTMARK*)lParam; + + TRACE("hwnd = %p, lptbim = %p\n", hwnd, lptbim); + + *lptbim = infoPtr->tbim; + + return 0; +} + + +static LRESULT +TOOLBAR_GetInsertMarkColor (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + TRACE("hwnd = %p\n", hwnd); + + return (LRESULT)infoPtr->clrInsertMark; +} + + +static LRESULT +TOOLBAR_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + TBUTTON_INFO *btnPtr; + LPRECT lpRect; + INT nIndex; + + nIndex = (INT)wParam; + btnPtr = &infoPtr->buttons[nIndex]; + if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons)) + return FALSE; + lpRect = (LPRECT)lParam; + if (lpRect == NULL) + return FALSE; + if (btnPtr->fsState & TBSTATE_HIDDEN) + return FALSE; + + lpRect->left = btnPtr->rect.left; + lpRect->right = btnPtr->rect.right; + lpRect->bottom = btnPtr->rect.bottom; + lpRect->top = btnPtr->rect.top; + + return TRUE; +} + + +static LRESULT +TOOLBAR_GetMaxSize (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + LPSIZE lpSize = (LPSIZE)lParam; + + if (lpSize == NULL) + return FALSE; + + lpSize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left; + lpSize->cy = infoPtr->rcBound.bottom - infoPtr->rcBound.top; + + TRACE("maximum size %ld x %ld\n", + infoPtr->rcBound.right - infoPtr->rcBound.left, + infoPtr->rcBound.bottom - infoPtr->rcBound.top); + + return TRUE; +} + + +/* << TOOLBAR_GetObject >> */ + + +static LRESULT +TOOLBAR_GetPadding (HWND hwnd) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + DWORD oldPad; + + oldPad = MAKELONG(infoPtr->szPadding.cx, infoPtr->szPadding.cy); + return (LRESULT) oldPad; +} + + +static LRESULT +TOOLBAR_GetRect (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + TBUTTON_INFO *btnPtr; + LPRECT lpRect; + INT nIndex; + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); + btnPtr = &infoPtr->buttons[nIndex]; + if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons)) + return FALSE; + lpRect = (LPRECT)lParam; + if (lpRect == NULL) + return FALSE; + + lpRect->left = btnPtr->rect.left; + lpRect->right = btnPtr->rect.right; + lpRect->bottom = btnPtr->rect.bottom; + lpRect->top = btnPtr->rect.top; + + return TRUE; +} + + +static LRESULT +TOOLBAR_GetRows (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + if (infoPtr->dwStyle & TBSTYLE_WRAPABLE) + return infoPtr->nRows; + else + return 1; +} + + +static LRESULT +TOOLBAR_GetState (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + INT nIndex; + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); + if (nIndex == -1) + return -1; + + return infoPtr->buttons[nIndex].fsState; +} + + +static LRESULT +TOOLBAR_GetStyle (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + return GetWindowLongW(hwnd, GWL_STYLE); +} + + +static LRESULT +TOOLBAR_GetTextRows (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + return infoPtr->nMaxTextRows; +} + + +static LRESULT +TOOLBAR_GetToolTips (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + return (LRESULT)infoPtr->hwndToolTip; +} + + +static LRESULT +TOOLBAR_GetUnicodeFormat (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + TRACE("%s hwnd=%p\n", + infoPtr->bUnicode ? "TRUE" : "FALSE", hwnd); + + return infoPtr->bUnicode; +} + + +inline static LRESULT +TOOLBAR_GetVersion (HWND hwnd) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + return infoPtr->iVersion; +} + + +static LRESULT +TOOLBAR_HideButton (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + TBUTTON_INFO *btnPtr; + INT nIndex; + + TRACE("\n"); + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); + if (nIndex == -1) + return FALSE; + + btnPtr = &infoPtr->buttons[nIndex]; + if (LOWORD(lParam) == FALSE) + btnPtr->fsState &= ~TBSTATE_HIDDEN; + else + btnPtr->fsState |= TBSTATE_HIDDEN; + + TOOLBAR_CalcToolbar (hwnd); + + InvalidateRect (hwnd, NULL, TRUE); + + return TRUE; +} + + +inline static LRESULT +TOOLBAR_HitTest (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + return TOOLBAR_InternalHitTest (hwnd, (LPPOINT)lParam); +} + + +static LRESULT +TOOLBAR_Indeterminate (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + TBUTTON_INFO *btnPtr; + INT nIndex; + DWORD oldState; + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); + if (nIndex == -1) + return FALSE; + + btnPtr = &infoPtr->buttons[nIndex]; + oldState = btnPtr->fsState; + if (LOWORD(lParam) == FALSE) + btnPtr->fsState &= ~TBSTATE_INDETERMINATE; + else + btnPtr->fsState |= TBSTATE_INDETERMINATE; + + if(oldState != btnPtr->fsState) + InvalidateRect(hwnd, &btnPtr->rect, TRUE); + + return TRUE; +} + + +static LRESULT +TOOLBAR_InsertButtonA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + LPTBBUTTON lpTbb = (LPTBBUTTON)lParam; + INT nIndex = (INT)wParam; + TBUTTON_INFO *oldButtons; + + if (lpTbb == NULL) + return FALSE; + + TOOLBAR_DumpButton(infoPtr, (TBUTTON_INFO *)lpTbb, nIndex, FALSE); + + if (nIndex == -1) { + /* EPP: this seems to be an undocumented call (from my IE4) + * I assume in that case that: + * - lpTbb->iString is a string pointer (not a string index in strings[] table + * - index of insertion is at the end of existing buttons + * I only see this happen with nIndex == -1, but it could have a special + * meaning (like -nIndex (or ~nIndex) to get the real position of insertion). + */ + nIndex = infoPtr->nNumButtons; + + } else if (nIndex < 0) + return FALSE; + + /* If the string passed is not an index, assume address of string + and do our own AddString */ + if ((HIWORD(lpTbb->iString) != 0) && (lpTbb->iString != -1)) { + LPSTR ptr; + INT len; + + TRACE("string %s passed instead of index, adding string\n", + debugstr_a((LPSTR)lpTbb->iString)); + len = strlen((LPSTR)lpTbb->iString) + 2; + ptr = Alloc(len); + strcpy(ptr, (LPSTR)lpTbb->iString); + ptr[len - 1] = 0; /* ended by two '\0' */ + lpTbb->iString = TOOLBAR_AddStringA(hwnd, 0, (LPARAM)ptr); + Free(ptr); + } + + TRACE("inserting button index=%d\n", nIndex); + if (nIndex > infoPtr->nNumButtons) { + nIndex = infoPtr->nNumButtons; + TRACE("adjust index=%d\n", nIndex); + } + + oldButtons = infoPtr->buttons; + infoPtr->nNumButtons++; + infoPtr->buttons = Alloc (sizeof (TBUTTON_INFO) * infoPtr->nNumButtons); + /* pre insert copy */ + if (nIndex > 0) { + memcpy (&infoPtr->buttons[0], &oldButtons[0], + nIndex * sizeof(TBUTTON_INFO)); + } + + /* insert new button */ + infoPtr->buttons[nIndex].iBitmap = lpTbb->iBitmap; + infoPtr->buttons[nIndex].idCommand = lpTbb->idCommand; + infoPtr->buttons[nIndex].fsState = lpTbb->fsState; + infoPtr->buttons[nIndex].fsStyle = lpTbb->fsStyle; + infoPtr->buttons[nIndex].dwData = lpTbb->dwData; + /* if passed string and not index, then add string */ + if(HIWORD(lpTbb->iString) && lpTbb->iString!=-1) { + Str_SetPtrAtoW ((LPWSTR *)&infoPtr->buttons[nIndex].iString, (LPCSTR )lpTbb->iString); + } + else + infoPtr->buttons[nIndex].iString = lpTbb->iString; + + if ((infoPtr->hwndToolTip) && !(lpTbb->fsStyle & BTNS_SEP)) { + TTTOOLINFOW ti; + + ZeroMemory (&ti, sizeof(ti)); + ti.cbSize = sizeof (ti); + ti.hwnd = hwnd; + ti.uId = lpTbb->idCommand; + ti.hinst = 0; + ti.lpszText = LPSTR_TEXTCALLBACKW; + + SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, + 0, (LPARAM)&ti); + } + + /* post insert copy */ + if (nIndex < infoPtr->nNumButtons - 1) { + memcpy (&infoPtr->buttons[nIndex+1], &oldButtons[nIndex], + (infoPtr->nNumButtons - nIndex - 1) * sizeof(TBUTTON_INFO)); + } + + Free (oldButtons); + + TOOLBAR_CalcToolbar (hwnd); + + InvalidateRect (hwnd, NULL, TRUE); + + return TRUE; +} + + +static LRESULT +TOOLBAR_InsertButtonW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + LPTBBUTTON lpTbb = (LPTBBUTTON)lParam; + INT nIndex = (INT)wParam; + TBUTTON_INFO *oldButtons; + + if (lpTbb == NULL) + return FALSE; + + TOOLBAR_DumpButton(infoPtr, (TBUTTON_INFO *)lpTbb, nIndex, FALSE); + + if (nIndex == -1) { + /* EPP: this seems to be an undocumented call (from my IE4) + * I assume in that case that: + * - lpTbb->iString is a string pointer (not a string index in strings[] table + * - index of insertion is at the end of existing buttons + * I only see this happen with nIndex == -1, but it could have a special + * meaning (like -nIndex (or ~nIndex) to get the real position of insertion). + */ + nIndex = infoPtr->nNumButtons; + + } else if (nIndex < 0) + return FALSE; + + /* If the string passed is not an index, assume address of string + and do our own AddString */ + if ((HIWORD(lpTbb->iString) != 0) && (lpTbb->iString != -1)) { + LPWSTR ptr; + INT len; + + TRACE("string %s passed instead of index, adding string\n", + debugstr_w((LPWSTR)lpTbb->iString)); + len = strlenW((LPWSTR)lpTbb->iString) + 2; + ptr = Alloc(len*sizeof(WCHAR)); + strcpyW(ptr, (LPWSTR)lpTbb->iString); + ptr[len - 1] = 0; /* ended by two '\0' */ + lpTbb->iString = TOOLBAR_AddStringW(hwnd, 0, (LPARAM)ptr); + Free(ptr); + } + + TRACE("inserting button index=%d\n", nIndex); + if (nIndex > infoPtr->nNumButtons) { + nIndex = infoPtr->nNumButtons; + TRACE("adjust index=%d\n", nIndex); + } + + oldButtons = infoPtr->buttons; + infoPtr->nNumButtons++; + infoPtr->buttons = Alloc (sizeof (TBUTTON_INFO) * infoPtr->nNumButtons); + /* pre insert copy */ + if (nIndex > 0) { + memcpy (&infoPtr->buttons[0], &oldButtons[0], + nIndex * sizeof(TBUTTON_INFO)); + } + + /* insert new button */ + infoPtr->buttons[nIndex].iBitmap = lpTbb->iBitmap; + infoPtr->buttons[nIndex].idCommand = lpTbb->idCommand; + infoPtr->buttons[nIndex].fsState = lpTbb->fsState; + infoPtr->buttons[nIndex].fsStyle = lpTbb->fsStyle; + infoPtr->buttons[nIndex].dwData = lpTbb->dwData; + /* if passed string and not index, then add string */ + if(HIWORD(lpTbb->iString) && lpTbb->iString!=-1) { + Str_SetPtrW ((LPWSTR *)&infoPtr->buttons[nIndex].iString, (LPWSTR)lpTbb->iString); + } + else + infoPtr->buttons[nIndex].iString = lpTbb->iString; + + if ((infoPtr->hwndToolTip) && !(lpTbb->fsStyle & BTNS_SEP)) { + TTTOOLINFOW ti; + + ZeroMemory (&ti, sizeof(TTTOOLINFOW)); + ti.cbSize = sizeof (TTTOOLINFOW); + ti.hwnd = hwnd; + ti.uId = lpTbb->idCommand; + ti.hinst = 0; + ti.lpszText = LPSTR_TEXTCALLBACKW; + + SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, + 0, (LPARAM)&ti); + } + + /* post insert copy */ + if (nIndex < infoPtr->nNumButtons - 1) { + memcpy (&infoPtr->buttons[nIndex+1], &oldButtons[nIndex], + (infoPtr->nNumButtons - nIndex - 1) * sizeof(TBUTTON_INFO)); + } + + Free (oldButtons); + + TOOLBAR_CalcToolbar (hwnd); + + InvalidateRect (hwnd, NULL, TRUE); + + return TRUE; +} + + +/* << TOOLBAR_InsertMarkHitTest >> */ + + +static LRESULT +TOOLBAR_IsButtonChecked (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + INT nIndex; + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); + if (nIndex == -1) + return FALSE; + + return (infoPtr->buttons[nIndex].fsState & TBSTATE_CHECKED); +} + + +static LRESULT +TOOLBAR_IsButtonEnabled (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + INT nIndex; + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); + if (nIndex == -1) + return FALSE; + + return (infoPtr->buttons[nIndex].fsState & TBSTATE_ENABLED); +} + + +static LRESULT +TOOLBAR_IsButtonHidden (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + INT nIndex; + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); + if (nIndex == -1) + return TRUE; + + return (infoPtr->buttons[nIndex].fsState & TBSTATE_HIDDEN); +} + + +static LRESULT +TOOLBAR_IsButtonHighlighted (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + INT nIndex; + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); + if (nIndex == -1) + return FALSE; + + return (infoPtr->buttons[nIndex].fsState & TBSTATE_MARKED); +} + + +static LRESULT +TOOLBAR_IsButtonIndeterminate (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + INT nIndex; + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); + if (nIndex == -1) + return FALSE; + + return (infoPtr->buttons[nIndex].fsState & TBSTATE_INDETERMINATE); +} + + +static LRESULT +TOOLBAR_IsButtonPressed (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + INT nIndex; + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); + if (nIndex == -1) + return FALSE; + + return (infoPtr->buttons[nIndex].fsState & TBSTATE_PRESSED); +} + + +static LRESULT +TOOLBAR_LoadImages (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TBADDBITMAP tbab; + tbab.hInst = (HINSTANCE)lParam; + tbab.nID = (UINT_PTR)wParam; + + TRACE("hwnd = %p, hInst = %p, nID = %u\n", hwnd, tbab.hInst, tbab.nID); + + return TOOLBAR_AddBitmap(hwnd, 0, (LPARAM)&tbab); +} + + +static LRESULT +TOOLBAR_MapAccelerator (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + WCHAR wAccel = (WCHAR)wParam; + UINT* pIDButton = (UINT*)lParam; + WCHAR wszAccel[] = {'&',wAccel,0}; + int i; + + TRACE("hwnd = %p, wAccel = %x(%s), pIDButton = %p\n", + hwnd, wAccel, debugstr_wn(&wAccel,1), pIDButton); + + for (i = 0; i < infoPtr->nNumButtons; i++) + { + TBUTTON_INFO *btnPtr = infoPtr->buttons+i; + if (!(btnPtr->fsStyle & BTNS_NOPREFIX) && + !(btnPtr->fsState & TBSTATE_HIDDEN)) + { + int iLen = strlenW(wszAccel); + LPCWSTR lpszStr = TOOLBAR_GetText(infoPtr, btnPtr); + + if (!lpszStr) + continue; + + while (*lpszStr) + { + if ((lpszStr[0] == '&') && (lpszStr[1] == '&')) + { + lpszStr += 2; + continue; + } + if (!strncmpiW(lpszStr, wszAccel, iLen)) + { + *pIDButton = btnPtr->idCommand; + return TRUE; + } + lpszStr++; + } + } + } + return FALSE; +} + + +static LRESULT +TOOLBAR_MarkButton (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + INT nIndex; + DWORD oldState; + TBUTTON_INFO *btnPtr; + + TRACE("hwnd = %p, wParam = %d, lParam = 0x%08lx\n", hwnd, wParam, lParam); + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); + if (nIndex == -1) + return FALSE; + + btnPtr = &infoPtr->buttons[nIndex]; + oldState = btnPtr->fsState; + + if (LOWORD(lParam)) + btnPtr->fsState |= TBSTATE_MARKED; + else + btnPtr->fsState &= ~TBSTATE_MARKED; + + if(oldState != btnPtr->fsState) + InvalidateRect(hwnd, &btnPtr->rect, TRUE); + + return TRUE; +} + + +/* fixes up an index of a button affected by a move */ +inline static void TOOLBAR_MoveFixupIndex(INT* pIndex, INT nIndex, INT nMoveIndex, BOOL bMoveUp) +{ + if (bMoveUp) + { + if (*pIndex > nIndex && *pIndex <= nMoveIndex) + (*pIndex)--; + else if (*pIndex == nIndex) + *pIndex = nMoveIndex; + } + else + { + if (*pIndex >= nMoveIndex && *pIndex < nIndex) + (*pIndex)++; + else if (*pIndex == nIndex) + *pIndex = nMoveIndex; + } +} + + +static LRESULT +TOOLBAR_MoveButton (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + INT nIndex; + INT nCount; + INT nMoveIndex = (INT)lParam; + TBUTTON_INFO button; + + TRACE("hwnd=%p, wParam=%d, lParam=%ld\n", hwnd, wParam, lParam); + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, TRUE); + if ((nIndex == -1) || (nMoveIndex < 0)) + return FALSE; + + if (nMoveIndex > infoPtr->nNumButtons - 1) + nMoveIndex = infoPtr->nNumButtons - 1; + + button = infoPtr->buttons[nIndex]; + + /* move button right */ + if (nIndex < nMoveIndex) + { + nCount = nMoveIndex - nIndex; + memmove(&infoPtr->buttons[nIndex], &infoPtr->buttons[nIndex+1], nCount*sizeof(TBUTTON_INFO)); + infoPtr->buttons[nMoveIndex] = button; + + TOOLBAR_MoveFixupIndex(&infoPtr->nButtonDown, nIndex, nMoveIndex, TRUE); + TOOLBAR_MoveFixupIndex(&infoPtr->nButtonDrag, nIndex, nMoveIndex, TRUE); + TOOLBAR_MoveFixupIndex(&infoPtr->nOldHit, nIndex, nMoveIndex, TRUE); + TOOLBAR_MoveFixupIndex(&infoPtr->nHotItem, nIndex, nMoveIndex, TRUE); + } + else if (nIndex > nMoveIndex) /* move button left */ + { + nCount = nIndex - nMoveIndex; + memmove(&infoPtr->buttons[nMoveIndex+1], &infoPtr->buttons[nMoveIndex], nCount*sizeof(TBUTTON_INFO)); + infoPtr->buttons[nMoveIndex] = button; + + TOOLBAR_MoveFixupIndex(&infoPtr->nButtonDown, nIndex, nMoveIndex, FALSE); + TOOLBAR_MoveFixupIndex(&infoPtr->nButtonDrag, nIndex, nMoveIndex, FALSE); + TOOLBAR_MoveFixupIndex(&infoPtr->nOldHit, nIndex, nMoveIndex, FALSE); + TOOLBAR_MoveFixupIndex(&infoPtr->nHotItem, nIndex, nMoveIndex, FALSE); + } + + TOOLBAR_CalcToolbar(hwnd); + InvalidateRect(hwnd, NULL, TRUE); + + return TRUE; +} + + +static LRESULT +TOOLBAR_PressButton (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + TBUTTON_INFO *btnPtr; + INT nIndex; + DWORD oldState; + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); + if (nIndex == -1) + return FALSE; + + btnPtr = &infoPtr->buttons[nIndex]; + oldState = btnPtr->fsState; + if (LOWORD(lParam) == FALSE) + btnPtr->fsState &= ~TBSTATE_PRESSED; + else + btnPtr->fsState |= TBSTATE_PRESSED; + + if(oldState != btnPtr->fsState) + InvalidateRect(hwnd, &btnPtr->rect, TRUE); + + return TRUE; +} + +/* FIXME: there might still be some confusion her between number of buttons + * and number of bitmaps */ +static LRESULT +TOOLBAR_ReplaceBitmap (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + LPTBREPLACEBITMAP lpReplace = (LPTBREPLACEBITMAP) lParam; + HBITMAP hBitmap; + int i = 0, nOldButtons = 0, pos = 0; + int nOldBitmaps, nNewBitmaps = 0; + HIMAGELIST himlDef = 0; + + TRACE("hInstOld %p nIDOld %x hInstNew %p nIDNew %x nButtons %x\n", + lpReplace->hInstOld, lpReplace->nIDOld, lpReplace->hInstNew, lpReplace->nIDNew, + lpReplace->nButtons); + + if (lpReplace->hInstOld == HINST_COMMCTRL) + { + FIXME("changing standard bitmaps not implemented\n"); + return FALSE; + } + else if (lpReplace->hInstOld != 0) + { + FIXME("resources not in the current module not implemented\n"); + return FALSE; + } + else + { + hBitmap = (HBITMAP) lpReplace->nIDNew; + } + + TRACE("To be replaced hInstOld %p nIDOld %x\n", lpReplace->hInstOld, lpReplace->nIDOld); + for (i = 0; i < infoPtr->nNumBitmapInfos; i++) { + TBITMAP_INFO *tbi = &infoPtr->bitmaps[i]; + TRACE("tbimapinfo %d hInstOld %p nIDOld %x\n", i, tbi->hInst, tbi->nID); + if (tbi->hInst == lpReplace->hInstOld && tbi->nID == lpReplace->nIDOld) + { + TRACE("Found: nButtons %d hInst %p nID %x\n", tbi->nButtons, tbi->hInst, tbi->nID); + nOldButtons = tbi->nButtons; + tbi->nButtons = lpReplace->nButtons; + tbi->hInst = lpReplace->hInstNew; + tbi->nID = lpReplace->nIDNew; + TRACE("tbimapinfo changed %d hInstOld %p nIDOld %x\n", i, tbi->hInst, tbi->nID); + break; + } + pos += tbi->nButtons; + } + + if (nOldButtons == 0) + { + WARN("No hinst/bitmap found! hInst %p nID %x\n", lpReplace->hInstOld, lpReplace->nIDOld); + return FALSE; + } + + himlDef = GETDEFIMAGELIST(infoPtr, 0); /* fixme: correct? */ + nOldBitmaps = ImageList_GetImageCount(himlDef); + + /* ImageList_Replace(GETDEFIMAGELIST(), pos, hBitmap, NULL); */ + + for (i = pos + nOldBitmaps - 1; i >= pos; i--) + ImageList_Remove(himlDef, i); + + if (hBitmap) + { + BITMAP bmp; + HBITMAP hOldBitmapBitmap, hOldBitmapLoad, hbmLoad; + HDC hdcImage, hdcBitmap; + + /* copy the bitmap before adding it so that the user's bitmap + * doesn't get modified. + */ + GetObjectW (hBitmap, sizeof(BITMAP), (LPVOID)&bmp); + + hdcImage = CreateCompatibleDC(0); + hdcBitmap = CreateCompatibleDC(0); + + /* create new bitmap */ + hbmLoad = CreateBitmap (bmp.bmWidth, bmp.bmHeight, bmp.bmPlanes, bmp.bmBitsPixel, NULL); + hOldBitmapBitmap = SelectObject(hdcBitmap, hBitmap); + hOldBitmapLoad = SelectObject(hdcImage, hbmLoad); + + /* Copy the user's image */ + BitBlt (hdcImage, 0, 0, bmp.bmWidth, bmp.bmHeight, + hdcBitmap, 0, 0, SRCCOPY); + + SelectObject (hdcImage, hOldBitmapLoad); + SelectObject (hdcBitmap, hOldBitmapBitmap); + DeleteDC (hdcImage); + DeleteDC (hdcBitmap); + + ImageList_AddMasked (himlDef, hbmLoad, comctl32_color.clrBtnFace); + nNewBitmaps = ImageList_GetImageCount(himlDef); + DeleteObject (hbmLoad); + } + + infoPtr->nNumBitmaps = infoPtr->nNumBitmaps - nOldBitmaps + nNewBitmaps; + + TRACE(" pos %d %d old bitmaps replaced by %d new ones.\n", + pos, nOldBitmaps, nNewBitmaps); + + InvalidateRect(hwnd, NULL, TRUE); + + return TRUE; +} + + +/* helper for TOOLBAR_SaveRestoreW */ +static BOOL +TOOLBAR_Save(TOOLBAR_INFO *infoPtr, LPTBSAVEPARAMSW lpSave) +{ + FIXME("save to %s %s\n", debugstr_w(lpSave->pszSubKey), + debugstr_w(lpSave->pszValueName)); + + return FALSE; +} + + +/* helper for TOOLBAR_Restore */ +static void +TOOLBAR_DeleteAllButtons(TOOLBAR_INFO *infoPtr) +{ + INT i; + TTTOOLINFOW ti; + + ZeroMemory(&ti, sizeof(ti)); + ti.cbSize = sizeof(ti); + ti.hwnd = infoPtr->hwndSelf; + + for (i = 0; i < infoPtr->nNumButtons; i++) + { + if ((infoPtr->hwndToolTip) && + !(infoPtr->buttons[i].fsStyle & BTNS_SEP)) + { + ti.uId = infoPtr->buttons[i].idCommand; + SendMessageW(infoPtr->hwndToolTip, TTM_DELTOOLW, 0, (LPARAM)&ti); + } + } + + Free(infoPtr->buttons); + infoPtr->buttons = NULL; + infoPtr->nNumButtons = 0; +} + + +/* helper for TOOLBAR_SaveRestoreW */ +static BOOL +TOOLBAR_Restore(TOOLBAR_INFO *infoPtr, LPTBSAVEPARAMSW lpSave) +{ + LONG res; + HKEY hkey = NULL; + BOOL ret = FALSE; + DWORD dwType; + DWORD dwSize = 0; + NMTBRESTORE nmtbr; + + /* restore toolbar information */ + TRACE("restore from %s %s\n", debugstr_w(lpSave->pszSubKey), + debugstr_w(lpSave->pszValueName)); + + memset(&nmtbr, 0, sizeof(nmtbr)); + + res = RegOpenKeyExW(lpSave->hkr, lpSave->pszSubKey, 0, + KEY_QUERY_VALUE, &hkey); + if (!res) + res = RegQueryValueExW(hkey, lpSave->pszValueName, NULL, &dwType, + NULL, &dwSize); + if (!res && dwType != REG_BINARY) + res = ERROR_FILE_NOT_FOUND; + if (!res) + { + nmtbr.pData = Alloc(dwSize); + nmtbr.cbData = (UINT)dwSize; + if (!nmtbr.pData) res = ERROR_OUTOFMEMORY; + } + if (!res) + res = RegQueryValueExW(hkey, lpSave->pszValueName, NULL, &dwType, + (LPBYTE)nmtbr.pData, &dwSize); + if (!res) + { + nmtbr.pCurrent = nmtbr.pData; + nmtbr.iItem = -1; + nmtbr.cbBytesPerRecord = sizeof(DWORD); + nmtbr.cButtons = nmtbr.cbData / nmtbr.cbBytesPerRecord; + + if (!TOOLBAR_SendNotify(&nmtbr.hdr, infoPtr, TBN_RESTORE)) + { + INT i; + + /* remove all existing buttons as this function is designed to + * restore the toolbar to a previously saved state */ + TOOLBAR_DeleteAllButtons(infoPtr); + + for (i = 0; i < nmtbr.cButtons; i++) + { + nmtbr.iItem = i; + nmtbr.tbButton.iBitmap = -1; + nmtbr.tbButton.fsState = 0; + nmtbr.tbButton.fsStyle = 0; + nmtbr.tbButton.idCommand = 0; + if (*nmtbr.pCurrent == (DWORD)-1) + { + /* separator */ + nmtbr.tbButton.fsStyle = TBSTYLE_SEP; + nmtbr.tbButton.iBitmap = SEPARATOR_WIDTH; + } + else if (*nmtbr.pCurrent == (DWORD)-2) + /* hidden button */ + nmtbr.tbButton.fsState = TBSTATE_HIDDEN; + else + nmtbr.tbButton.idCommand = (int)*nmtbr.pCurrent; + + nmtbr.pCurrent++; + + TOOLBAR_SendNotify(&nmtbr.hdr, infoPtr, TBN_RESTORE); + + /* can't contain real string as we don't know whether + * the client put an ANSI or Unicode string in there */ + if (HIWORD(nmtbr.tbButton.iString)) + nmtbr.tbButton.iString = 0; + + TOOLBAR_InsertButtonW(infoPtr->hwndSelf, -1, + (LPARAM)&nmtbr.tbButton); + } + + /* do legacy notifications */ + if (infoPtr->iVersion < 5) + { + /* FIXME: send TBN_BEGINADJUST */ + FIXME("send TBN_GETBUTTONINFO for each button\n"); + /* FIXME: send TBN_ENDADJUST */ + } + + /* remove all uninitialised buttons + * note: loop backwards to avoid having to fixup i on a + * delete */ + for (i = infoPtr->nNumButtons - 1; i >= 0; i--) + if (infoPtr->buttons[i].iBitmap == -1) + TOOLBAR_DeleteButton(infoPtr->hwndSelf, i, 0); + + /* only indicate success if at least one button survived */ + if (infoPtr->nNumButtons > 0) ret = TRUE; + } + } + Free (nmtbr.pData); + RegCloseKey(hkey); + + return ret; +} + + +static LRESULT +TOOLBAR_SaveRestoreW (HWND hwnd, WPARAM wParam, LPTBSAVEPARAMSW lpSave) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + if (lpSave == NULL) return 0; + + if (wParam) + return TOOLBAR_Save(infoPtr, lpSave); + else + return TOOLBAR_Restore(infoPtr, lpSave); +} + + +static LRESULT +TOOLBAR_SaveRestoreA (HWND hwnd, WPARAM wParam, LPTBSAVEPARAMSA lpSave) +{ + LPWSTR pszValueName = 0, pszSubKey = 0; + TBSAVEPARAMSW SaveW; + LRESULT result = 0; + int len; + + if (lpSave == NULL) return 0; + + len = MultiByteToWideChar(CP_ACP, 0, lpSave->pszSubKey, -1, NULL, 0); + pszSubKey = Alloc(len * sizeof(WCHAR)); + if (pszSubKey) goto exit; + MultiByteToWideChar(CP_ACP, 0, lpSave->pszSubKey, -1, pszSubKey, len); + + len = MultiByteToWideChar(CP_ACP, 0, lpSave->pszValueName, -1, NULL, 0); + pszValueName = Alloc(len * sizeof(WCHAR)); + if (!pszValueName) goto exit; + MultiByteToWideChar(CP_ACP, 0, lpSave->pszValueName, -1, pszValueName, len); + + SaveW.pszValueName = pszValueName; + SaveW.pszSubKey = pszSubKey; + SaveW.hkr = lpSave->hkr; + result = TOOLBAR_SaveRestoreW(hwnd, wParam, &SaveW); + +exit: + Free (pszValueName); + Free (pszSubKey); + + return result; +} + + +static LRESULT +TOOLBAR_SetAnchorHighlight (HWND hwnd, WPARAM wParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + BOOL bOldAnchor = infoPtr->bAnchor; + + TRACE("hwnd=%p, bAnchor = %s\n", hwnd, wParam ? "TRUE" : "FALSE"); + + infoPtr->bAnchor = (BOOL)wParam; + + /* Native does not remove the hot effect from an already hot button */ + + return (LRESULT)bOldAnchor; +} + + +static LRESULT +TOOLBAR_SetBitmapSize (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + HIMAGELIST himlDef = GETDEFIMAGELIST(infoPtr, 0); + + TRACE("hwnd=%p, wParam=%d, lParam=%ld\n", hwnd, wParam, lParam); + + if (wParam != 0) + FIXME("wParam is %d. Perhaps image list index?\n", wParam); + + if ((LOWORD(lParam) <= 0) || (HIWORD(lParam)<=0)) + return FALSE; + + if (infoPtr->nNumButtons > 0) + WARN("%d buttons, undoc increase to bitmap size : %d-%d -> %d-%d\n", + infoPtr->nNumButtons, + infoPtr->nBitmapWidth, infoPtr->nBitmapHeight, + LOWORD(lParam), HIWORD(lParam)); + + infoPtr->nBitmapWidth = (INT)LOWORD(lParam); + infoPtr->nBitmapHeight = (INT)HIWORD(lParam); + + + if ((himlDef == infoPtr->himlInt) && + (ImageList_GetImageCount(infoPtr->himlInt) == 0)) + { + ImageList_SetIconSize(infoPtr->himlInt, infoPtr->nBitmapWidth, + infoPtr->nBitmapHeight); + } + + return TRUE; +} + + +static LRESULT +TOOLBAR_SetButtonInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + LPTBBUTTONINFOA lptbbi = (LPTBBUTTONINFOA)lParam; + TBUTTON_INFO *btnPtr; + INT nIndex; + RECT oldBtnRect; + + if (lptbbi == NULL) + return FALSE; + if (lptbbi->cbSize < sizeof(TBBUTTONINFOA)) + return FALSE; + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, + lptbbi->dwMask & 0x80000000); + if (nIndex == -1) + return FALSE; + + btnPtr = &infoPtr->buttons[nIndex]; + if (lptbbi->dwMask & TBIF_COMMAND) + btnPtr->idCommand = lptbbi->idCommand; + if (lptbbi->dwMask & TBIF_IMAGE) + btnPtr->iBitmap = lptbbi->iImage; + if (lptbbi->dwMask & TBIF_LPARAM) + btnPtr->dwData = lptbbi->lParam; + if (lptbbi->dwMask & TBIF_SIZE) + btnPtr->cx = lptbbi->cx; + if (lptbbi->dwMask & TBIF_STATE) + btnPtr->fsState = lptbbi->fsState; + if (lptbbi->dwMask & TBIF_STYLE) + btnPtr->fsStyle = lptbbi->fsStyle; + + if ((lptbbi->dwMask & TBIF_TEXT) && ((INT)lptbbi->pszText != -1)) { + if ((HIWORD(btnPtr->iString) == 0) || (btnPtr->iString == -1)) + /* iString is index, zero it to make Str_SetPtr succeed */ + btnPtr->iString=0; + + Str_SetPtrAtoW ((LPWSTR *)&btnPtr->iString, lptbbi->pszText); + } + + /* save the button rect to see if we need to redraw the whole toolbar */ + oldBtnRect = btnPtr->rect; + TOOLBAR_CalcToolbar(hwnd); + + if (!EqualRect(&oldBtnRect, &btnPtr->rect)) + InvalidateRect(hwnd, NULL, TRUE); + else + InvalidateRect(hwnd, &btnPtr->rect, TRUE); + + return TRUE; +} + + +static LRESULT +TOOLBAR_SetButtonInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + LPTBBUTTONINFOW lptbbi = (LPTBBUTTONINFOW)lParam; + TBUTTON_INFO *btnPtr; + INT nIndex; + RECT oldBtnRect; + + if (lptbbi == NULL) + return FALSE; + if (lptbbi->cbSize < sizeof(TBBUTTONINFOW)) + return FALSE; + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, + lptbbi->dwMask & 0x80000000); + if (nIndex == -1) + return FALSE; + + btnPtr = &infoPtr->buttons[nIndex]; + if (lptbbi->dwMask & TBIF_COMMAND) + btnPtr->idCommand = lptbbi->idCommand; + if (lptbbi->dwMask & TBIF_IMAGE) + btnPtr->iBitmap = lptbbi->iImage; + if (lptbbi->dwMask & TBIF_LPARAM) + btnPtr->dwData = lptbbi->lParam; + if (lptbbi->dwMask & TBIF_SIZE) + btnPtr->cx = lptbbi->cx; + if (lptbbi->dwMask & TBIF_STATE) + btnPtr->fsState = lptbbi->fsState; + if (lptbbi->dwMask & TBIF_STYLE) + btnPtr->fsStyle = lptbbi->fsStyle; + + if ((lptbbi->dwMask & TBIF_TEXT) && ((INT)lptbbi->pszText != -1)) { + if ((HIWORD(btnPtr->iString) == 0) || (btnPtr->iString == -1)) + /* iString is index, zero it to make Str_SetPtr succeed */ + btnPtr->iString=0; + Str_SetPtrW ((LPWSTR *)&btnPtr->iString, lptbbi->pszText); + } + + /* save the button rect to see if we need to redraw the whole toolbar */ + oldBtnRect = btnPtr->rect; + TOOLBAR_CalcToolbar(hwnd); + + if (!EqualRect(&oldBtnRect, &btnPtr->rect)) + InvalidateRect(hwnd, NULL, TRUE); + else + InvalidateRect(hwnd, &btnPtr->rect, TRUE); + + return TRUE; +} + + +static LRESULT +TOOLBAR_SetButtonSize (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + INT cx = LOWORD(lParam), cy = HIWORD(lParam); + + if ((cx < 0) || (cy < 0)) + { + ERR("invalid parameter 0x%08lx\n", (DWORD)lParam); + return FALSE; + } + + TRACE("%p, cx = %d, cy = %d\n", hwnd, cx, cy); + + /* The documentation claims you can only change the button size before + * any button has been added. But this is wrong. + * WINZIP32.EXE (ver 8) calls this on one of its buttons after adding + * it to the toolbar, and it checks that the return value is nonzero - mjm + * Further testing shows that we must actually perform the change too. + */ + /* + * The documentation also does not mention that if 0 is supplied for + * either size, the system changes it to the default of 24 wide and + * 22 high. Demonstarted in ControlSpy Toolbar. GLA 3/02 + */ + infoPtr->nButtonWidth = (cx) ? cx : 24; + infoPtr->nButtonHeight = (cy) ? cy : 22; + return TRUE; +} + + +static LRESULT +TOOLBAR_SetButtonWidth (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + /* if setting to current values, ignore */ + if ((infoPtr->cxMin == (INT)LOWORD(lParam)) && + (infoPtr->cxMax == (INT)HIWORD(lParam))) { + TRACE("matches current width, min=%d, max=%d, no recalc\n", + infoPtr->cxMin, infoPtr->cxMax); + return TRUE; + } + + /* save new values */ + infoPtr->cxMin = (INT)LOWORD(lParam); + infoPtr->cxMax = (INT)HIWORD(lParam); + + /* if both values are 0 then we are done */ + if (lParam == 0) { + TRACE("setting both min and max to 0, norecalc\n"); + return TRUE; + } + + /* otherwise we need to recalc the toolbar and in some cases + recalc the bounding rectangle (does DrawText w/ DT_CALCRECT + which doesn't actually draw - GA). */ + TRACE("number of buttons %d, cx=%d, cy=%d, recalcing\n", + infoPtr->nNumButtons, infoPtr->cxMin, infoPtr->cxMax); + + TOOLBAR_CalcToolbar (hwnd); + + InvalidateRect (hwnd, NULL, TRUE); + + return TRUE; +} + + +static LRESULT +TOOLBAR_SetCmdId (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + INT nIndex = (INT)wParam; + + if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons)) + return FALSE; + + infoPtr->buttons[nIndex].idCommand = (INT)lParam; + + if (infoPtr->hwndToolTip) { + + FIXME("change tool tip!\n"); + + } + + return TRUE; +} + + +static LRESULT +TOOLBAR_SetDisabledImageList (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + HIMAGELIST himl = (HIMAGELIST)lParam; + HIMAGELIST himlTemp; + INT id = 0; + + if (infoPtr->iVersion >= 5) + id = wParam; + + himlTemp = TOOLBAR_InsertImageList(&infoPtr->himlDis, + &infoPtr->cimlDis, himl, id); + + /* FIXME: redraw ? */ + + return (LRESULT)himlTemp; +} + + +static LRESULT +TOOLBAR_SetDrawTextFlags (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + DWORD dwTemp; + + TRACE("hwnd = %p, dwMask = 0x%08lx, dwDTFlags = 0x%08lx\n", hwnd, (DWORD)wParam, (DWORD)lParam); + + dwTemp = infoPtr->dwDTFlags; + infoPtr->dwDTFlags = + (infoPtr->dwDTFlags & (DWORD)wParam) | (DWORD)lParam; + + return (LRESULT)dwTemp; +} + +/* This function differs a bit from what MSDN says it does: + * 1. lParam contains extended style flags to OR with current style + * (MSDN isn't clear on the OR bit) + * 2. wParam appears to contain extended style flags to be reset + * (MSDN says that this parameter is reserved) + */ +static LRESULT +TOOLBAR_SetExtendedStyle (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + DWORD dwTemp; + + dwTemp = infoPtr->dwExStyle; + infoPtr->dwExStyle &= ~wParam; + infoPtr->dwExStyle |= (DWORD)lParam; + + TRACE("new style 0x%08lx\n", infoPtr->dwExStyle); + + if (infoPtr->dwExStyle & ~TBSTYLE_EX_ALL) + FIXME("Unknown Toolbar Extended Style 0x%08lx. Please report.\n", + (infoPtr->dwExStyle & ~TBSTYLE_EX_ALL)); + + TOOLBAR_CalcToolbar (hwnd); + + TOOLBAR_AutoSize(hwnd); + + InvalidateRect(hwnd, NULL, TRUE); + + return (LRESULT)dwTemp; +} + + +static LRESULT +TOOLBAR_SetHotImageList (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd); + HIMAGELIST himlTemp; + HIMAGELIST himl = (HIMAGELIST)lParam; + INT id = 0; + + if (infoPtr->iVersion >= 5) + id = wParam; + + TRACE("hwnd = %p, himl = %p, id = %d\n", hwnd, himl, id); + + himlTemp = TOOLBAR_InsertImageList(&infoPtr->himlHot, + &infoPtr->cimlHot, himl, id); + + /* FIXME: redraw ? */ + + return (LRESULT)himlTemp; +} + + +/* Makes previous hot button no longer hot, makes the specified + * button hot and sends appropriate notifications. dwReason is one or + * more HICF_ flags. Specify nHit < 0 to make no buttons hot. + * NOTE 1: this function does not validate nHit + * NOTE 2: the name of this function is completely made up and + * not based on any documentation from Microsoft. */ +static void +TOOLBAR_SetHotItemEx (TOOLBAR_INFO *infoPtr, INT nHit, DWORD dwReason) +{ + if (infoPtr->nHotItem != nHit) + { + NMTBHOTITEM nmhotitem; + TBUTTON_INFO *btnPtr = NULL, *oldBtnPtr = NULL; + LRESULT no_highlight; + + /* Remove the effect of an old hot button if the button was + drawn with the hot button effect */ + if(infoPtr->nHotItem >= 0) + { + oldBtnPtr = &infoPtr->buttons[infoPtr->nHotItem]; + oldBtnPtr->bHot = FALSE; + } + + infoPtr->nHotItem = nHit; + + /* It's not a separator or in nowhere. It's a hot button. */ + if (nHit >= 0) + btnPtr = &infoPtr->buttons[nHit]; + + nmhotitem.dwFlags = dwReason; + if (oldBtnPtr) + nmhotitem.idOld = oldBtnPtr->idCommand; + else + nmhotitem.dwFlags |= HICF_ENTERING; + if (btnPtr) + nmhotitem.idNew = btnPtr->idCommand; + else + nmhotitem.dwFlags |= HICF_LEAVING; + + no_highlight = TOOLBAR_SendNotify(&nmhotitem.hdr, infoPtr, TBN_HOTITEMCHANGE); + + /* now invalidate the old and new buttons so they will be painted, + * but only if they are enabled - disabled buttons cannot become hot */ + if (oldBtnPtr && (oldBtnPtr->fsState & TBSTATE_ENABLED)) + InvalidateRect(infoPtr->hwndSelf, &oldBtnPtr->rect, TRUE); + if (btnPtr && !no_highlight && (btnPtr->fsState & TBSTATE_ENABLED)) + { + btnPtr->bHot = TRUE; + InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); + } + } +} + +static LRESULT +TOOLBAR_SetHotItem (HWND hwnd, WPARAM wParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd); + INT nOldHotItem = infoPtr->nHotItem; + + TRACE("hwnd = %p, nHit = %d\n", hwnd, (INT)wParam); + + if ((INT) wParam < 0 || (INT)wParam > infoPtr->nNumButtons) + wParam = -1; + + /* NOTE: an application can still remove the hot item even if anchor + * highlighting is enabled */ + + if (infoPtr->dwStyle & TBSTYLE_FLAT) + TOOLBAR_SetHotItemEx(infoPtr, wParam, HICF_OTHER); + + if (nOldHotItem < 0) + return -1; + + return (LRESULT)nOldHotItem; +} + + +static LRESULT +TOOLBAR_SetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + HIMAGELIST himlTemp; + HIMAGELIST himl = (HIMAGELIST)lParam; + INT i, id = 0; + + if (infoPtr->iVersion >= 5) + id = wParam; + + himlTemp = TOOLBAR_InsertImageList(&infoPtr->himlDef, + &infoPtr->cimlDef, himl, id); + + infoPtr->nNumBitmaps = 0; + for (i = 0; i < infoPtr->cimlDef; i++) + infoPtr->nNumBitmaps += ImageList_GetImageCount(infoPtr->himlDef[i]->himl); + + if (!ImageList_GetIconSize(himl, &infoPtr->nBitmapWidth, + &infoPtr->nBitmapHeight)) + { + infoPtr->nBitmapWidth = 1; + infoPtr->nBitmapHeight = 1; + } + + TRACE("hwnd %p, new himl=%p, id = %d, count=%d, bitmap w=%d, h=%d\n", + hwnd, infoPtr->himlDef, id, infoPtr->nNumBitmaps, + infoPtr->nBitmapWidth, infoPtr->nBitmapHeight); + + InvalidateRect(hwnd, NULL, TRUE); + + return (LRESULT)himlTemp; +} + + +static LRESULT +TOOLBAR_SetIndent (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + infoPtr->nIndent = (INT)wParam; + + TRACE("\n"); + + /* process only on indent changing */ + if(infoPtr->nIndent != (INT)wParam) + { + infoPtr->nIndent = (INT)wParam; + TOOLBAR_CalcToolbar (hwnd); + InvalidateRect(hwnd, NULL, FALSE); + } + + return TRUE; +} + + +static LRESULT +TOOLBAR_SetInsertMark (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + TBINSERTMARK *lptbim = (TBINSERTMARK*)lParam; + + TRACE("hwnd = %p, lptbim = { %d, 0x%08lx}\n", hwnd, lptbim->iButton, lptbim->dwFlags); + + if ((lptbim->dwFlags & ~TBIMHT_AFTER) != 0) + { + FIXME("Unrecognized flag(s): 0x%08lx\n", (lptbim->dwFlags & ~TBIMHT_AFTER)); + return 0; + } + + if ((lptbim->iButton == -1) || + ((lptbim->iButton < infoPtr->nNumButtons) && + (lptbim->iButton >= 0))) + { + infoPtr->tbim = *lptbim; + /* FIXME: don't need to update entire toolbar */ + InvalidateRect(hwnd, NULL, TRUE); + } + else + ERR("Invalid button index %d\n", lptbim->iButton); + + return 0; +} + + +static LRESULT +TOOLBAR_SetInsertMarkColor (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + infoPtr->clrInsertMark = (COLORREF)lParam; + + /* FIXME: don't need to update entire toolbar */ + InvalidateRect(hwnd, NULL, TRUE); + + return 0; +} + + +static LRESULT +TOOLBAR_SetMaxTextRows (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + infoPtr->nMaxTextRows = (INT)wParam; + + TOOLBAR_CalcToolbar(hwnd); + return TRUE; +} + + +/* MSDN gives slightly wrong info on padding. + * 1. It is not only used on buttons with the BTNS_AUTOSIZE style + * 2. It is not used to create a blank area between the edge of the button + * and the text or image if TBSTYLE_LIST is set. It is used to control + * the gap between the image and text. + * 3. It is not applied to both sides. If TBSTYLE_LIST is set it is used + * to control the bottom and right borders [with the border being + * szPadding.cx - (GetSystemMetrics(SM_CXEDGE)+1)], otherwise the padding + * is shared evenly on both sides of the button. + * See blueprints in comments above TOOLBAR_MeasureButton for more info. + */ +static LRESULT +TOOLBAR_SetPadding (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + DWORD oldPad; + + oldPad = MAKELONG(infoPtr->szPadding.cx, infoPtr->szPadding.cy); + infoPtr->szPadding.cx = min(LOWORD((DWORD)lParam), GetSystemMetrics(SM_CXEDGE)); + infoPtr->szPadding.cy = min(HIWORD((DWORD)lParam), GetSystemMetrics(SM_CYEDGE)); + TRACE("cx=%ld, cy=%ld\n", + infoPtr->szPadding.cx, infoPtr->szPadding.cy); + return (LRESULT) oldPad; +} + + +static LRESULT +TOOLBAR_SetParent (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + HWND hwndOldNotify; + + TRACE("\n"); + + hwndOldNotify = infoPtr->hwndNotify; + infoPtr->hwndNotify = (HWND)wParam; + + return (LRESULT)hwndOldNotify; +} + + +static LRESULT +TOOLBAR_SetRows (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + LPRECT lprc = (LPRECT)lParam; + + TRACE("\n"); + + if (LOWORD(wParam) > 1) { + FIXME("multiple rows not supported!\n"); + } + + if(infoPtr->nRows != LOWORD(wParam)) + { + infoPtr->nRows = LOWORD(wParam); + + /* recalculate toolbar */ + TOOLBAR_CalcToolbar (hwnd); + + /* repaint toolbar */ + InvalidateRect(hwnd, NULL, TRUE); + } + + /* return bounding rectangle */ + if (lprc) { + lprc->left = infoPtr->rcBound.left; + lprc->right = infoPtr->rcBound.right; + lprc->top = infoPtr->rcBound.top; + lprc->bottom = infoPtr->rcBound.bottom; + } + + return 0; +} + + +static LRESULT +TOOLBAR_SetState (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + TBUTTON_INFO *btnPtr; + INT nIndex; + + nIndex = TOOLBAR_GetButtonIndex (infoPtr, (INT)wParam, FALSE); + if (nIndex == -1) + return FALSE; + + btnPtr = &infoPtr->buttons[nIndex]; + + /* if hidden state has changed the invalidate entire window and recalc */ + if ((btnPtr->fsState & TBSTATE_HIDDEN) != (LOWORD(lParam) & TBSTATE_HIDDEN)) { + btnPtr->fsState = LOWORD(lParam); + TOOLBAR_CalcToolbar (hwnd); + InvalidateRect(hwnd, 0, TRUE); + return TRUE; + } + + /* process state changing if current state doesn't match new state */ + if(btnPtr->fsState != LOWORD(lParam)) + { + btnPtr->fsState = LOWORD(lParam); + InvalidateRect(hwnd, &btnPtr->rect, TRUE); + } + + return TRUE; +} + + +static LRESULT +TOOLBAR_SetStyle (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + SetWindowLongW(hwnd, GWL_STYLE, lParam); + + return TRUE; +} + + +inline static LRESULT +TOOLBAR_SetToolTips (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + TRACE("hwnd=%p, hwndTooltip=%p, lParam=0x%lx\n", hwnd, (HWND)wParam, lParam); + + infoPtr->hwndToolTip = (HWND)wParam; + return 0; +} + + +static LRESULT +TOOLBAR_SetUnicodeFormat (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + BOOL bTemp; + + TRACE("%s hwnd=%p\n", + ((BOOL)wParam) ? "TRUE" : "FALSE", hwnd); + + bTemp = infoPtr->bUnicode; + infoPtr->bUnicode = (BOOL)wParam; + + return bTemp; +} + + +static LRESULT +TOOLBAR_GetColorScheme (HWND hwnd, LPCOLORSCHEME lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + lParam->clrBtnHighlight = (infoPtr->clrBtnHighlight == CLR_DEFAULT) ? + comctl32_color.clrBtnHighlight : + infoPtr->clrBtnHighlight; + lParam->clrBtnShadow = (infoPtr->clrBtnShadow == CLR_DEFAULT) ? + comctl32_color.clrBtnShadow : infoPtr->clrBtnShadow; + return 1; +} + + +static LRESULT +TOOLBAR_SetColorScheme (HWND hwnd, LPCOLORSCHEME lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + TRACE("new colors Hl=%lx Shd=%lx, old colors Hl=%lx Shd=%lx\n", + lParam->clrBtnHighlight, lParam->clrBtnShadow, + infoPtr->clrBtnHighlight, infoPtr->clrBtnShadow); + + infoPtr->clrBtnHighlight = lParam->clrBtnHighlight; + infoPtr->clrBtnShadow = lParam->clrBtnShadow; + InvalidateRect(hwnd, NULL, TRUE); + return 0; +} + + +static LRESULT +TOOLBAR_SetVersion (HWND hwnd, INT iVersion) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + INT iOldVersion = infoPtr->iVersion; + + infoPtr->iVersion = iVersion; + + if (infoPtr->iVersion >= 5) + TOOLBAR_SetUnicodeFormat(hwnd, (WPARAM)TRUE, (LPARAM)0); + + return iOldVersion; +} + + +static LRESULT +TOOLBAR_GetStringA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd); + WORD iString = HIWORD(wParam); + WORD buffersize = LOWORD(wParam); + LPSTR str = (LPSTR)lParam; + LRESULT ret = -1; + + TRACE("hwnd=%p, iString=%d, buffersize=%d, string=%p\n", hwnd, iString, buffersize, str); + + if (iString < infoPtr->nNumStrings) + { + ret = WideCharToMultiByte(CP_ACP, 0, infoPtr->strings[iString], -1, str, buffersize, NULL, NULL); + + TRACE("returning %s\n", debugstr_a(str)); + } + else + ERR("String index %d out of range (largest is %d)\n", iString, infoPtr->nNumStrings - 1); + + return ret; +} + + +static LRESULT +TOOLBAR_GetStringW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd); + WORD iString = HIWORD(wParam); + WORD len = LOWORD(wParam)/sizeof(WCHAR) - 1; + LPWSTR str = (LPWSTR)lParam; + LRESULT ret = -1; + + TRACE("hwnd=%p, iString=%d, buffersize=%d, string=%p\n", hwnd, iString, LOWORD(wParam), str); + + if (iString < infoPtr->nNumStrings) + { + len = min(len, strlenW(infoPtr->strings[iString])); + ret = (len+1)*sizeof(WCHAR); + memcpy(str, infoPtr->strings[iString], ret); + str[len] = '\0'; + + TRACE("returning %s\n", debugstr_w(str)); + } + else + ERR("String index %d out of range (largest is %d)\n", iString, infoPtr->nNumStrings - 1); + + return ret; +} + +/* UNDOCUMENTED MESSAGE: This appears to set some kind of size. Perhaps it + * is the maximum size of the toolbar? */ +static LRESULT TOOLBAR_Unkwn45D(HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + SIZE * pSize = (SIZE*)lParam; + FIXME("hwnd=%p, wParam=0x%08x, size.cx=%ld, size.cy=%ld stub!\n", hwnd, wParam, pSize->cx, pSize->cy); + return 0; +} + + +/* UNDOCUMENTED MESSAGE: This is an extended version of the + * TB_SETHOTITEM message. It allows the caller to specify a reason why the + * hot item changed (rather than just the HICF_OTHER that TB_SETHOTITEM + * sends). */ +static LRESULT +TOOLBAR_Unkwn45E (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd); + INT nOldHotItem = infoPtr->nHotItem; + + TRACE("old item=%d, new item=%d, flags=%08lx\n", + nOldHotItem, infoPtr->nHotItem, (DWORD)lParam); + + if ((INT) wParam < 0 || (INT)wParam > infoPtr->nNumButtons) + wParam = -1; + + /* NOTE: an application can still remove the hot item even if anchor + * highlighting is enabled */ + + TOOLBAR_SetHotItemEx(infoPtr, wParam, lParam); + + GetFocus(); + + return (nOldHotItem < 0) ? -1 : (LRESULT)nOldHotItem; +} + +/* UNDOCUMENTED MESSAGE: This sets the toolbar global iListGap parameter + * which controls the amount of spacing between the image and the text + * of buttons for TBSTYLE_LIST toolbars. */ +static LRESULT TOOLBAR_Unkwn460(HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd); + + TRACE("hwnd=%p iListGap=%d\n", hwnd, wParam); + + if (lParam != 0) + FIXME("lParam = 0x%08lx. Please report\n", lParam); + + infoPtr->iListGap = (INT)wParam; + + InvalidateRect(hwnd, NULL, TRUE); + + return 0; +} + +/* UNDOCUMENTED MESSAGE: This returns the number of maximum number + * of image lists associated with the various states. */ +static LRESULT TOOLBAR_Unkwn462(HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd); + + TRACE("hwnd=%p wParam %08x lParam %08lx\n", hwnd, wParam, lParam); + + return max(infoPtr->cimlDef, max(infoPtr->cimlHot, infoPtr->cimlDis)); +} + +static LRESULT +TOOLBAR_Unkwn463 (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + LPSIZE lpsize = (LPSIZE)lParam; + + if (lpsize == NULL) + return FALSE; + + /* + * Testing shows the following: + * wParam = 0 adjust cx value + * = 1 set cy value to max size. + * lParam pointer to SIZE structure + * + */ + TRACE("[0463] wParam %d, lParam 0x%08lx -> 0x%08lx 0x%08lx\n", + wParam, lParam, lpsize->cx, lpsize->cy); + + switch(wParam) { + case 0: + if (lpsize->cx == -1) { + /* **** this is wrong, native measures each button and sets it */ + lpsize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left; + } + else if(HIWORD(lpsize->cx)) { + RECT rc; + HWND hwndParent = GetParent(hwnd); + + GetWindowRect(hwnd, &rc); + MapWindowPoints(0, hwndParent, (LPPOINT)&rc, 2); + TRACE("mapped to (%ld,%ld)-(%ld,%ld)\n", + rc.left, rc.top, rc.right, rc.bottom); + lpsize->cx = max(rc.right-rc.left, + infoPtr->rcBound.right - infoPtr->rcBound.left); + } + else { + lpsize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left; + } + break; + case 1: + lpsize->cy = infoPtr->rcBound.bottom - infoPtr->rcBound.top; + /* lpsize->cy = infoPtr->nHeight; */ + break; + default: + ERR("Unknown wParam %d for Toolbar message [0463]. Please report\n", + wParam); + return 0; + } + TRACE("[0463] set to -> 0x%08lx 0x%08lx\n", + lpsize->cx, lpsize->cy); + return 1; +} + +static LRESULT TOOLBAR_Unkwn464(HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + FIXME("hwnd=%p wParam %08x lParam %08lx\n", hwnd, wParam, lParam); + + InvalidateRect(hwnd, NULL, TRUE); + return 1; +} + + +static LRESULT +TOOLBAR_Create (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE); + LOGFONTW logFont; + + TRACE("hwnd = %p\n", hwnd); + + /* initialize info structure */ + infoPtr->nButtonHeight = 22; + infoPtr->nButtonWidth = 24; + infoPtr->nBitmapHeight = 15; + infoPtr->nBitmapWidth = 16; + + infoPtr->nHeight = infoPtr->nButtonHeight + TOP_BORDER + BOTTOM_BORDER; + infoPtr->nMaxTextRows = 1; + infoPtr->cxMin = -1; + infoPtr->cxMax = -1; + infoPtr->nNumBitmaps = 0; + infoPtr->nNumStrings = 0; + + infoPtr->bCaptured = FALSE; + infoPtr->nButtonDown = -1; + infoPtr->nButtonDrag = -1; + infoPtr->nOldHit = -1; + infoPtr->nHotItem = -1; + infoPtr->hwndNotify = ((LPCREATESTRUCTW)lParam)->hwndParent; + infoPtr->bBtnTranspnt = (dwStyle & (TBSTYLE_FLAT | TBSTYLE_LIST)); + infoPtr->dwDTFlags = (dwStyle & TBSTYLE_LIST) ? DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS: DT_CENTER | DT_END_ELLIPSIS; + infoPtr->bAnchor = FALSE; /* no anchor highlighting */ + infoPtr->bDragOutSent = FALSE; + infoPtr->iVersion = 0; + infoPtr->hwndSelf = hwnd; + infoPtr->bDoRedraw = TRUE; + infoPtr->clrBtnHighlight = CLR_DEFAULT; + infoPtr->clrBtnShadow = CLR_DEFAULT; + infoPtr->szPadding.cx = DEFPAD_CX; + infoPtr->szPadding.cy = DEFPAD_CY; + infoPtr->iListGap = DEFLISTGAP; + infoPtr->dwStyle = dwStyle; + infoPtr->tbim.iButton = -1; + GetClientRect(hwnd, &infoPtr->client_rect); + infoPtr->bUnicode = infoPtr->hwndNotify && + (NFR_UNICODE == SendMessageW(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwnd, (LPARAM)NF_REQUERY)); + + SystemParametersInfoW (SPI_GETICONTITLELOGFONT, 0, &logFont, 0); + infoPtr->hFont = infoPtr->hDefaultFont = CreateFontIndirectW (&logFont); + + if (dwStyle & TBSTYLE_TOOLTIPS) { + /* Create tooltip control */ + infoPtr->hwndToolTip = + CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, 0, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + hwnd, 0, 0, 0); + + /* Send NM_TOOLTIPSCREATED notification */ + if (infoPtr->hwndToolTip) + { + NMTOOLTIPSCREATED nmttc; + + nmttc.hwndToolTips = infoPtr->hwndToolTip; + + TOOLBAR_SendNotify (&nmttc.hdr, infoPtr, NM_TOOLTIPSCREATED); + } + } + + TOOLBAR_CheckStyle (hwnd, dwStyle); + + TOOLBAR_CalcToolbar(hwnd); + + return 0; +} + + +static LRESULT +TOOLBAR_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + /* delete tooltip control */ + if (infoPtr->hwndToolTip) + DestroyWindow (infoPtr->hwndToolTip); + + /* delete temporary buffer for tooltip text */ + Free (infoPtr->pszTooltipText); + + /* delete button data */ + if (infoPtr->buttons) + Free (infoPtr->buttons); + + /* delete strings */ + if (infoPtr->strings) { + INT i; + for (i = 0; i < infoPtr->nNumStrings; i++) + if (infoPtr->strings[i]) + Free (infoPtr->strings[i]); + + Free (infoPtr->strings); + } + + /* destroy internal image list */ + if (infoPtr->himlInt) + ImageList_Destroy (infoPtr->himlInt); + + TOOLBAR_DeleteImageList(&infoPtr->himlDef, &infoPtr->cimlDef); + TOOLBAR_DeleteImageList(&infoPtr->himlDis, &infoPtr->cimlDis); + TOOLBAR_DeleteImageList(&infoPtr->himlHot, &infoPtr->cimlHot); + + /* delete default font */ + if (infoPtr->hFont) + DeleteObject (infoPtr->hDefaultFont); + + /* free toolbar info data */ + Free (infoPtr); + SetWindowLongPtrW (hwnd, 0, 0); + + return 0; +} + + +static LRESULT +TOOLBAR_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + NMTBCUSTOMDRAW tbcd; + INT ret = FALSE; + DWORD ntfret; + + /* the app has told us not to redraw the toolbar */ + if (!infoPtr->bDoRedraw) + return FALSE; + + if (infoPtr->dwStyle & TBSTYLE_CUSTOMERASE) { + ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW)); + tbcd.nmcd.dwDrawStage = CDDS_PREERASE; + tbcd.nmcd.hdc = (HDC)wParam; + ntfret = TOOLBAR_SendNotify (&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); + infoPtr->dwBaseCustDraw = ntfret & 0xffff; + + /* FIXME: in general the return flags *can* be or'ed together */ + switch (infoPtr->dwBaseCustDraw) + { + case CDRF_DODEFAULT: + break; + case CDRF_SKIPDEFAULT: + return TRUE; + default: + FIXME("[%p] response %ld not handled to NM_CUSTOMDRAW (CDDS_PREERASE)\n", + hwnd, ntfret); + } + } + + /* If the toolbar is "transparent" then pass the WM_ERASEBKGND up + * to my parent for processing. + */ + if (infoPtr->dwStyle & TBSTYLE_TRANSPARENT) { + POINT pt, ptorig; + HDC hdc = (HDC)wParam; + HWND parent; + + pt.x = 0; + pt.y = 0; + parent = GetParent(hwnd); + MapWindowPoints(hwnd, parent, &pt, 1); + OffsetWindowOrgEx (hdc, pt.x, pt.y, &ptorig); + ret = SendMessageW (parent, WM_ERASEBKGND, wParam, lParam); + SetWindowOrgEx (hdc, ptorig.x, ptorig.y, 0); + } + if (!ret) + ret = DefWindowProcW (hwnd, WM_ERASEBKGND, wParam, lParam); + + if ((infoPtr->dwStyle & TBSTYLE_CUSTOMERASE) && + (infoPtr->dwBaseCustDraw & CDRF_NOTIFYPOSTERASE)) { + ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW)); + tbcd.nmcd.dwDrawStage = CDDS_POSTERASE; + tbcd.nmcd.hdc = (HDC)wParam; + ntfret = TOOLBAR_SendNotify (&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); + infoPtr->dwBaseCustDraw = ntfret & 0xffff; + switch (infoPtr->dwBaseCustDraw) + { + case CDRF_DODEFAULT: + break; + case CDRF_SKIPDEFAULT: + return TRUE; + default: + FIXME("[%p] response %ld not handled to NM_CUSTOMDRAW (CDDS_POSTERASE)\n", + hwnd, ntfret); + } + } + return ret; +} + + +static LRESULT +TOOLBAR_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + return (LRESULT)infoPtr->hFont; +} + + +static LRESULT +TOOLBAR_LButtonDblClk (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + POINT pt; + INT nHit; + + pt.x = (INT)LOWORD(lParam); + pt.y = (INT)HIWORD(lParam); + nHit = TOOLBAR_InternalHitTest (hwnd, &pt); + + if (nHit >= 0) + TOOLBAR_LButtonDown (hwnd, wParam, lParam); + else if (GetWindowLongW (hwnd, GWL_STYLE) & CCS_ADJUSTABLE) + TOOLBAR_Customize (hwnd); + + return 0; +} + + +static LRESULT +TOOLBAR_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + TBUTTON_INFO *btnPtr; + POINT pt; + INT nHit; + NMTOOLBARA nmtb; + NMMOUSE nmmouse; + BOOL bDragKeyPressed; + + TRACE("\n"); + + if (infoPtr->dwStyle & TBSTYLE_ALTDRAG) + bDragKeyPressed = (GetKeyState(VK_MENU) < 0); + else + bDragKeyPressed = (wParam & MK_SHIFT); + + if (infoPtr->hwndToolTip) + TOOLBAR_RelayEvent (infoPtr->hwndToolTip, hwnd, + WM_LBUTTONDOWN, wParam, lParam); + + pt.x = (INT)LOWORD(lParam); + pt.y = (INT)HIWORD(lParam); + nHit = TOOLBAR_InternalHitTest (hwnd, &pt); + + btnPtr = &infoPtr->buttons[nHit]; + + if ((nHit >= 0) && bDragKeyPressed && (infoPtr->dwStyle & CCS_ADJUSTABLE)) + { + infoPtr->nButtonDrag = nHit; + SetCapture (hwnd); + + /* If drag cursor has not been loaded, load it. + * Note: it doesn't need to be freed */ + if (!hCursorDrag) + hCursorDrag = LoadCursorW(COMCTL32_hModule, (LPCWSTR)IDC_MOVEBUTTON); + SetCursor(hCursorDrag); + } + else if (nHit >= 0) + { + RECT arrowRect; + infoPtr->nOldHit = nHit; + + CopyRect(&arrowRect, &btnPtr->rect); + arrowRect.left = max(btnPtr->rect.left, btnPtr->rect.right - DDARROW_WIDTH); + + /* for EX_DRAWDDARROWS style, click must be in the drop-down arrow rect */ + if ((btnPtr->fsState & TBSTATE_ENABLED) && + ((btnPtr->fsStyle & BTNS_WHOLEDROPDOWN) || + ((btnPtr->fsStyle & BTNS_DROPDOWN) && + ((TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle) && PtInRect(&arrowRect, pt)) || + (!TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle)))))) + { + LRESULT res; + + /* draw in pressed state */ + if (btnPtr->fsStyle & BTNS_WHOLEDROPDOWN) + btnPtr->fsState |= TBSTATE_PRESSED; + else + btnPtr->bDropDownPressed = TRUE; + RedrawWindow(hwnd,&btnPtr->rect,0, + RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW); + + memset(&nmtb, 0, sizeof(nmtb)); + nmtb.iItem = btnPtr->idCommand; + nmtb.rcButton = btnPtr->rect; + res = TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr, + TBN_DROPDOWN); + TRACE("TBN_DROPDOWN responded with %ld\n", res); + + if (res != TBDDRET_TREATPRESSED) + { + MSG msg; + + /* redraw button in unpressed state */ + if (btnPtr->fsStyle & BTNS_WHOLEDROPDOWN) + btnPtr->fsState &= ~TBSTATE_PRESSED; + else + btnPtr->bDropDownPressed = FALSE; + InvalidateRect(hwnd, &btnPtr->rect, TRUE); + + /* find and set hot item + * NOTE: native doesn't do this, but that is a bug */ + GetCursorPos(&pt); + ScreenToClient(hwnd, &pt); + nHit = TOOLBAR_InternalHitTest(hwnd, &pt); + if (!infoPtr->bAnchor || (nHit >= 0)) + TOOLBAR_SetHotItemEx(infoPtr, nHit, HICF_MOUSE | HICF_LMOUSE); + + /* remove any left mouse button down or double-click messages + * so that we can get a toggle effect on the button */ + while (PeekMessageW(&msg, hwnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE) || + PeekMessageW(&msg, hwnd, WM_LBUTTONDBLCLK, WM_LBUTTONDBLCLK, PM_REMOVE)) + ; + + return 0; + } + /* otherwise drop through and process as pushed */ + } + infoPtr->bCaptured = TRUE; + infoPtr->nButtonDown = nHit; + infoPtr->bDragOutSent = FALSE; + + btnPtr->fsState |= TBSTATE_PRESSED; + + TOOLBAR_SetHotItemEx(infoPtr, nHit, HICF_MOUSE | HICF_LMOUSE); + + if (btnPtr->fsState & TBSTATE_ENABLED) + InvalidateRect(hwnd, &btnPtr->rect, TRUE); + UpdateWindow(hwnd); + SetCapture (hwnd); + } + + if (nHit >=0) + { + memset(&nmtb, 0, sizeof(nmtb)); + nmtb.iItem = btnPtr->idCommand; + TOOLBAR_SendNotify((NMHDR *)&nmtb, infoPtr, TBN_BEGINDRAG); + } + + nmmouse.dwHitInfo = nHit; + + /* !!! Undocumented - sends NM_LDOWN with the NMMOUSE structure. */ + if (nHit < 0) + nmmouse.dwItemSpec = -1; + else + { + nmmouse.dwItemSpec = infoPtr->buttons[nmmouse.dwHitInfo].idCommand; + nmmouse.dwItemData = infoPtr->buttons[nmmouse.dwHitInfo].dwData; + } + + ClientToScreen(hwnd, &pt); + nmmouse.pt = pt; + + if (!TOOLBAR_SendNotify(&nmmouse.hdr, infoPtr, NM_LDOWN)) + return DefWindowProcW(hwnd, WM_LBUTTONDOWN, wParam, lParam); + + return 0; +} + +static LRESULT +TOOLBAR_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + TBUTTON_INFO *btnPtr; + POINT pt; + INT nHit; + INT nOldIndex = -1; + BOOL bSendMessage = TRUE; + NMHDR hdr; + NMMOUSE nmmouse; + NMTOOLBARA nmtb; + + if (infoPtr->hwndToolTip) + TOOLBAR_RelayEvent (infoPtr->hwndToolTip, hwnd, + WM_LBUTTONUP, wParam, lParam); + + pt.x = (INT)LOWORD(lParam); + pt.y = (INT)HIWORD(lParam); + nHit = TOOLBAR_InternalHitTest (hwnd, &pt); + + if (!infoPtr->bAnchor || (nHit >= 0)) + TOOLBAR_SetHotItemEx(infoPtr, nHit, HICF_MOUSE | HICF_LMOUSE); + + if (infoPtr->nButtonDrag >= 0) { + RECT rcClient; + NMHDR hdr; + + btnPtr = &infoPtr->buttons[infoPtr->nButtonDrag]; + ReleaseCapture(); + /* reset cursor */ + SetCursor(LoadCursorW(NULL, (LPCWSTR)IDC_ARROW)); + + GetClientRect(hwnd, &rcClient); + if (PtInRect(&rcClient, pt)) + { + INT nButton = -1; + if (nHit >= 0) + nButton = nHit; + else if (nHit < -1) + nButton = -nHit; + else if ((nHit == -1) && PtInRect(&infoPtr->buttons[-nHit].rect, pt)) + nButton = -nHit; + + if (nButton == infoPtr->nButtonDrag) + { + /* if the button is moved sightly left and we have a + * separator there then remove it */ + if (pt.x < (btnPtr->rect.left + (btnPtr->rect.right - btnPtr->rect.left)/2)) + { + if ((nButton > 0) && (infoPtr->buttons[nButton-1].fsStyle & BTNS_SEP)) + TOOLBAR_DeleteButton(hwnd, nButton - 1, 0); + } + else /* else insert a separator before the dragged button */ + { + TBBUTTON tbb; + memset(&tbb, 0, sizeof(tbb)); + tbb.fsStyle = BTNS_SEP; + tbb.iString = -1; + TOOLBAR_InsertButtonW(hwnd, nButton, (LPARAM)&tbb); + } + } + else + { + if (nButton == -1) + { + if ((infoPtr->nNumButtons > 0) && (pt.x < infoPtr->buttons[0].rect.left)) + TOOLBAR_MoveButton(hwnd, infoPtr->nButtonDrag, 0); + else + TOOLBAR_MoveButton(hwnd, infoPtr->nButtonDrag, infoPtr->nNumButtons); + } + else + TOOLBAR_MoveButton(hwnd, infoPtr->nButtonDrag, nButton); + } + } + else + { + TRACE("button %d dragged out of toolbar\n", infoPtr->nButtonDrag); + TOOLBAR_DeleteButton(hwnd, (WPARAM)infoPtr->nButtonDrag, 0); + } + + /* button under cursor changed so need to re-set hot item */ + TOOLBAR_SetHotItemEx(infoPtr, nHit, HICF_MOUSE | HICF_LMOUSE); + infoPtr->nButtonDrag = -1; + + TOOLBAR_SendNotify(&hdr, infoPtr, TBN_TOOLBARCHANGE); + } + else if (infoPtr->nButtonDown >= 0) { + btnPtr = &infoPtr->buttons[infoPtr->nButtonDown]; + btnPtr->fsState &= ~TBSTATE_PRESSED; + + if (btnPtr->fsStyle & BTNS_CHECK) { + if (btnPtr->fsStyle & BTNS_GROUP) { + nOldIndex = TOOLBAR_GetCheckedGroupButtonIndex (infoPtr, + nHit); + if (nOldIndex == nHit) + bSendMessage = FALSE; + if ((nOldIndex != nHit) && + (nOldIndex != -1)) + infoPtr->buttons[nOldIndex].fsState &= ~TBSTATE_CHECKED; + btnPtr->fsState |= TBSTATE_CHECKED; + } + else { + if (btnPtr->fsState & TBSTATE_CHECKED) + btnPtr->fsState &= ~TBSTATE_CHECKED; + else + btnPtr->fsState |= TBSTATE_CHECKED; + } + } + + if (nOldIndex != -1) + InvalidateRect(hwnd, &infoPtr->buttons[nOldIndex].rect, TRUE); + + /* + * now we can ReleaseCapture, which triggers CAPTURECHANGED msg, + * that resets bCaptured and btn TBSTATE_PRESSED flags, + * and obliterates nButtonDown and nOldHit (see TOOLBAR_CaptureChanged) + */ + if ((infoPtr->bCaptured) && (infoPtr->nButtonDown >= 0)) + ReleaseCapture (); + infoPtr->nButtonDown = -1; + + /* Issue NM_RELEASEDCAPTURE to parent to let him know it is released */ + TOOLBAR_SendNotify ((NMHDR *) &hdr, infoPtr, + NM_RELEASEDCAPTURE); + + /* native issues TBN_ENDDRAG here, if _LBUTTONDOWN issued the + * TBN_BEGINDRAG + */ + memset(&nmtb, 0, sizeof(nmtb)); + nmtb.iItem = btnPtr->idCommand; + TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr, + TBN_ENDDRAG); + + if (btnPtr->fsState & TBSTATE_ENABLED) + { + SendMessageW (infoPtr->hwndNotify, WM_COMMAND, + MAKEWPARAM(infoPtr->buttons[nHit].idCommand, 0), (LPARAM)hwnd); + } + } + + /* !!! Undocumented - toolbar at 4.71 level and above sends + * NM_CLICK with the NMMOUSE structure. */ + nmmouse.dwHitInfo = nHit; + + if (nmmouse.dwHitInfo < 0) + nmmouse.dwItemSpec = -1; + else + { + nmmouse.dwItemSpec = infoPtr->buttons[nmmouse.dwHitInfo].idCommand; + nmmouse.dwItemData = infoPtr->buttons[nmmouse.dwHitInfo].dwData; + } + + ClientToScreen(hwnd, &pt); + nmmouse.pt = pt; + + if (!TOOLBAR_SendNotify((LPNMHDR)&nmmouse, infoPtr, NM_CLICK)) + return DefWindowProcW(hwnd, WM_LBUTTONUP, wParam, lParam); + + return 0; +} + +static LRESULT +TOOLBAR_RButtonUp( HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + INT nHit; + NMMOUSE nmmouse; + POINT pt; + + pt.x = LOWORD(lParam); + pt.y = HIWORD(lParam); + + nHit = TOOLBAR_InternalHitTest(hwnd, &pt); + nmmouse.dwHitInfo = nHit; + + if (nHit < 0) { + nmmouse.dwItemSpec = -1; + } else { + nmmouse.dwItemSpec = infoPtr->buttons[nmmouse.dwHitInfo].idCommand; + nmmouse.dwItemData = infoPtr->buttons[nmmouse.dwHitInfo].dwData; + } + + ClientToScreen(hwnd, &pt); + nmmouse.pt = pt; + + if (!TOOLBAR_SendNotify((LPNMHDR)&nmmouse, infoPtr, NM_RCLICK)) + return DefWindowProcW(hwnd, WM_RBUTTONUP, wParam, lParam); + + return 0; +} + +static LRESULT +TOOLBAR_RButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + NMHDR nmhdr; + + if (!TOOLBAR_SendNotify(&nmhdr, infoPtr, NM_RDBLCLK)) + return DefWindowProcW(hwnd, WM_RBUTTONDBLCLK, wParam, lParam); + + return 0; +} + +static LRESULT +TOOLBAR_CaptureChanged(HWND hwnd) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + TBUTTON_INFO *btnPtr; + + infoPtr->bCaptured = FALSE; + + if (infoPtr->nButtonDown >= 0) + { + btnPtr = &infoPtr->buttons[infoPtr->nButtonDown]; + btnPtr->fsState &= ~TBSTATE_PRESSED; + + infoPtr->nOldHit = -1; + + if (btnPtr->fsState & TBSTATE_ENABLED) + InvalidateRect(hwnd, &btnPtr->rect, TRUE); + } + return 0; +} + +static LRESULT +TOOLBAR_MouseLeave (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + TBUTTON_INFO *hotBtnPtr; + + hotBtnPtr = &infoPtr->buttons[infoPtr->nOldHit]; + + /* don't remove hot effects when in anchor highlighting mode or when a + * drop-down button is pressed */ + if (!infoPtr->bAnchor && (infoPtr->nOldHit < 0 || !hotBtnPtr->bDropDownPressed)) + TOOLBAR_SetHotItemEx(infoPtr, TOOLBAR_NOWHERE, HICF_MOUSE); + + if (infoPtr->nOldHit < 0) + return TRUE; + + /* If the last button we were over is depressed then make it not */ + /* depressed and redraw it */ + if(infoPtr->nOldHit == infoPtr->nButtonDown) + { + TBUTTON_INFO *btnPtr; + RECT rc1; + + btnPtr = &infoPtr->buttons[infoPtr->nButtonDown]; + + btnPtr->fsState &= ~TBSTATE_PRESSED; + + rc1 = hotBtnPtr->rect; + InflateRect (&rc1, 1, 1); + InvalidateRect (hwnd, &rc1, TRUE); + } + + if (infoPtr->bCaptured && !infoPtr->bDragOutSent) + { + NMTOOLBARW nmt; + ZeroMemory(&nmt, sizeof(nmt)); + nmt.iItem = infoPtr->buttons[infoPtr->nButtonDown].idCommand; + TOOLBAR_SendNotify(&nmt.hdr, infoPtr, TBN_DRAGOUT); + infoPtr->bDragOutSent = TRUE; + } + + infoPtr->nOldHit = -1; /* reset the old hit index as we've left the toolbar */ + + return TRUE; +} + +static LRESULT +TOOLBAR_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + POINT pt; + TRACKMOUSEEVENT trackinfo; + INT nHit; + TBUTTON_INFO *btnPtr; + + if (infoPtr->dwStyle & TBSTYLE_FLAT) { + /* fill in the TRACKMOUSEEVENT struct */ + trackinfo.cbSize = sizeof(TRACKMOUSEEVENT); + trackinfo.dwFlags = TME_QUERY; + trackinfo.hwndTrack = hwnd; + trackinfo.dwHoverTime = HOVER_DEFAULT; + + /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */ + _TrackMouseEvent(&trackinfo); + + /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */ + if(!(trackinfo.dwFlags & TME_LEAVE)) { + trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */ + + /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */ + /* and can properly deactivate the hot toolbar button */ + _TrackMouseEvent(&trackinfo); + } + } + + if (infoPtr->hwndToolTip) + TOOLBAR_RelayEvent (infoPtr->hwndToolTip, hwnd, + WM_MOUSEMOVE, wParam, lParam); + + pt.x = (INT)LOWORD(lParam); + pt.y = (INT)HIWORD(lParam); + + nHit = TOOLBAR_InternalHitTest (hwnd, &pt); + + if ((infoPtr->dwStyle & TBSTYLE_FLAT) && (!infoPtr->bAnchor || (nHit >= 0))) + TOOLBAR_SetHotItemEx(infoPtr, nHit, HICF_MOUSE); + + if (infoPtr->nOldHit != nHit) + { + if (infoPtr->bCaptured) + { + if (!infoPtr->bDragOutSent) + { + NMTOOLBARW nmt; + ZeroMemory(&nmt, sizeof(nmt)); + nmt.iItem = infoPtr->buttons[infoPtr->nButtonDown].idCommand; + TOOLBAR_SendNotify(&nmt.hdr, infoPtr, TBN_DRAGOUT); + infoPtr->bDragOutSent = TRUE; + } + + btnPtr = &infoPtr->buttons[infoPtr->nButtonDown]; + if (infoPtr->nOldHit == infoPtr->nButtonDown) { + btnPtr->fsState &= ~TBSTATE_PRESSED; + InvalidateRect(hwnd, &btnPtr->rect, TRUE); + } + else if (nHit == infoPtr->nButtonDown) { + btnPtr->fsState |= TBSTATE_PRESSED; + InvalidateRect(hwnd, &btnPtr->rect, TRUE); + } + infoPtr->nOldHit = nHit; + } + } + + return 0; +} + + +inline static LRESULT +TOOLBAR_NCActivate (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ +/* if (wndPtr->dwStyle & CCS_NODIVIDER) */ + return DefWindowProcW (hwnd, WM_NCACTIVATE, wParam, lParam); +/* else */ +/* return TOOLBAR_NCPaint (wndPtr, wParam, lParam); */ +} + + +inline static LRESULT +TOOLBAR_NCCalcSize (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + if (!(GetWindowLongW(hwnd, GWL_STYLE) & CCS_NODIVIDER)) + ((LPRECT)lParam)->top += GetSystemMetrics(SM_CYEDGE); + + return DefWindowProcW (hwnd, WM_NCCALCSIZE, wParam, lParam); +} + + +static LRESULT +TOOLBAR_NCCreate (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr; + LPCREATESTRUCTA cs = (LPCREATESTRUCTA)lParam; + DWORD styleadd = 0; + + /* allocate memory for info structure */ + infoPtr = (TOOLBAR_INFO *)Alloc (sizeof(TOOLBAR_INFO)); + SetWindowLongPtrW (hwnd, 0, (LONG_PTR)infoPtr); + + /* paranoid!! */ + infoPtr->dwStructSize = sizeof(TBBUTTON); + infoPtr->nRows = 1; + + /* fix instance handle, if the toolbar was created by CreateToolbarEx() */ + if (!GetWindowLongPtrW (hwnd, GWLP_HINSTANCE)) { + HINSTANCE hInst = (HINSTANCE)GetWindowLongPtrW (GetParent (hwnd), GWLP_HINSTANCE); + SetWindowLongPtrW (hwnd, GWLP_HINSTANCE, (LONG_PTR)hInst); + } + + /* native control does: + * Get a lot of colors and brushes + * WM_NOTIFYFORMAT + * SystemParametersInfoW(0x1f, 0x3c, adr1, 0) + * CreateFontIndirectW(adr1) + * CreateBitmap(0x27, 0x24, 1, 1, 0) + * hdc = GetDC(toolbar) + * GetSystemMetrics(0x48) + * fnt2=CreateFontW(0xe, 0, 0, 0, 0x190, 0, 0, 0, 0, 2, + * 0, 0, 0, 0, "MARLETT") + * oldfnt = SelectObject(hdc, fnt2) + * GetCharWidthW(hdc, 0x36, 0x36, adr2) + * GetTextMetricsW(hdc, adr3) + * SelectObject(hdc, oldfnt) + * DeleteObject(fnt2) + * ReleaseDC(hdc) + * InvalidateRect(toolbar, 0, 1) + * SetWindowLongW(toolbar, 0, addr) + * SetWindowLongW(toolbar, -16, xxx) **sometimes** + * WM_STYLECHANGING + * CallWinEx old new + * ie 1 0x56000a4c 0x46000a4c 0x56008a4d + * ie 2 0x4600094c 0x4600094c 0x4600894d + * ie 3 0x56000b4c 0x46000b4c 0x56008b4d + * rebar 0x50008844 0x40008844 0x50008845 + * pager 0x50000844 0x40000844 0x50008845 + * IC35mgr 0x5400084e **nochange** + * on entry to _NCCREATE 0x5400084e + * rowlist 0x5400004e **nochange** + * on entry to _NCCREATE 0x5400004e + * + */ + + /* I think the code below is a bug, but it is the way that the native + * controls seem to work. The effect is that if the user of TBSTYLE_FLAT + * forgets to specify TBSTYLE_TRANSPARENT but does specify either + * CCS_TOP or CCS_BOTTOM (_NOMOVEY and _TOP), then the control + * does *not* set TBSTYLE_TRANSPARENT even though it should!!!! + * Somehow, the only cases of this seem to be MFC programs. + * + * Note also that the addition of _TRANSPARENT occurs *only* here. It + * does not occur in the WM_STYLECHANGING routine. + * (Guy Albertelli 9/2001) + * + */ + if ((cs->style & TBSTYLE_FLAT) && !(cs->style & TBSTYLE_TRANSPARENT)) + styleadd |= TBSTYLE_TRANSPARENT; + if (!(cs->style & (CCS_TOP | CCS_NOMOVEY))) { + styleadd |= CCS_TOP; /* default to top */ + SetWindowLongW (hwnd, GWL_STYLE, cs->style | styleadd); + } + + return DefWindowProcW (hwnd, WM_NCCREATE, wParam, lParam); +} + + +static LRESULT +TOOLBAR_NCPaint (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + DWORD dwStyle = GetWindowLongW(hwnd, GWL_STYLE); + RECT rcWindow; + HDC hdc; + + if (dwStyle & WS_MINIMIZE) + return 0; /* Nothing to do */ + + DefWindowProcW (hwnd, WM_NCPAINT, wParam, lParam); + + if (!(hdc = GetDCEx (hwnd, 0, DCX_USESTYLE | DCX_WINDOW))) + return 0; + + if (!(dwStyle & CCS_NODIVIDER)) + { + GetWindowRect (hwnd, &rcWindow); + OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top); + if( dwStyle & WS_BORDER ) + OffsetRect (&rcWindow, 1, 1); + DrawEdge (hdc, &rcWindow, EDGE_ETCHED, BF_TOP); + } + + ReleaseDC( hwnd, hdc ); + + return 0; +} + + +/* handles requests from the tooltip control on what text to display */ +static LRESULT TOOLBAR_TTGetDispInfo (TOOLBAR_INFO *infoPtr, NMTTDISPINFOW *lpnmtdi) +{ + int index = TOOLBAR_GetButtonIndex(infoPtr, lpnmtdi->hdr.idFrom, FALSE); + + TRACE("button index = %d\n", index); + + Free (infoPtr->pszTooltipText); + infoPtr->pszTooltipText = NULL; + + if (index < 0) + return 0; + + if (infoPtr->bUnicode) + { + WCHAR wszBuffer[INFOTIPSIZE+1]; + NMTBGETINFOTIPW tbgit; + unsigned int len; /* in chars */ + + wszBuffer[0] = '\0'; + wszBuffer[INFOTIPSIZE] = '\0'; + + tbgit.pszText = wszBuffer; + tbgit.cchTextMax = INFOTIPSIZE; + tbgit.iItem = lpnmtdi->hdr.idFrom; + tbgit.lParam = infoPtr->buttons[index].dwData; + + TOOLBAR_SendNotify(&tbgit.hdr, infoPtr, TBN_GETINFOTIPW); + + TRACE("TBN_GETINFOTIPW - got string %s\n", debugstr_w(tbgit.pszText)); + + len = strlenW(tbgit.pszText); + if (len > sizeof(lpnmtdi->szText)/sizeof(lpnmtdi->szText[0])-1) + { + /* need to allocate temporary buffer in infoPtr as there + * isn't enough space in buffer passed to us by the + * tooltip control */ + infoPtr->pszTooltipText = Alloc((len+1)*sizeof(WCHAR)); + if (infoPtr->pszTooltipText) + { + memcpy(infoPtr->pszTooltipText, tbgit.pszText, (len+1)*sizeof(WCHAR)); + lpnmtdi->lpszText = infoPtr->pszTooltipText; + return 0; + } + } + else if (len > 0) + { + memcpy(lpnmtdi->lpszText, tbgit.pszText, (len+1)*sizeof(WCHAR)); + return 0; + } + } + else + { + CHAR szBuffer[INFOTIPSIZE+1]; + NMTBGETINFOTIPA tbgit; + unsigned int len; /* in chars */ + + szBuffer[0] = '\0'; + szBuffer[INFOTIPSIZE] = '\0'; + + tbgit.pszText = szBuffer; + tbgit.cchTextMax = INFOTIPSIZE; + tbgit.iItem = lpnmtdi->hdr.idFrom; + tbgit.lParam = infoPtr->buttons[index].dwData; + + TOOLBAR_SendNotify(&tbgit.hdr, infoPtr, TBN_GETINFOTIPA); + + TRACE("TBN_GETINFOTIPA - got string %s\n", debugstr_a(tbgit.pszText)); + + len = -1 + MultiByteToWideChar(CP_ACP, 0, tbgit.pszText, -1, NULL, 0); + if (len > sizeof(lpnmtdi->szText)/sizeof(lpnmtdi->szText[0])-1) + { + /* need to allocate temporary buffer in infoPtr as there + * isn't enough space in buffer passed to us by the + * tooltip control */ + infoPtr->pszTooltipText = Alloc((len+1)*sizeof(WCHAR)); + if (infoPtr->pszTooltipText) + { + MultiByteToWideChar(CP_ACP, 0, tbgit.pszText, len+1, infoPtr->pszTooltipText, (len+1)*sizeof(WCHAR)); + lpnmtdi->lpszText = infoPtr->pszTooltipText; + return 0; + } + } + else if (len > 0) + { + MultiByteToWideChar(CP_ACP, 0, tbgit.pszText, len+1, lpnmtdi->lpszText, (len+1)*sizeof(WCHAR)); + return 0; + } + } + + /* if button has text, but it is not shown then automatically + * use that text as tooltip */ + if ((infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) && + !(infoPtr->buttons[index].fsStyle & BTNS_SHOWTEXT)) + { + LPWSTR pszText = TOOLBAR_GetText(infoPtr, &infoPtr->buttons[index]); + unsigned int len = pszText ? strlenW(pszText) : 0; + + TRACE("using button hidden text %s\n", debugstr_w(pszText)); + + if (len > sizeof(lpnmtdi->szText)/sizeof(lpnmtdi->szText[0])-1) + { + /* need to allocate temporary buffer in infoPtr as there + * isn't enough space in buffer passed to us by the + * tooltip control */ + infoPtr->pszTooltipText = Alloc((len+1)*sizeof(WCHAR)); + if (infoPtr->pszTooltipText) + { + memcpy(infoPtr->pszTooltipText, pszText, (len+1)*sizeof(WCHAR)); + lpnmtdi->lpszText = infoPtr->pszTooltipText; + return 0; + } + } + else if (len > 0) + { + memcpy(lpnmtdi->lpszText, pszText, (len+1)*sizeof(WCHAR)); + return 0; + } + } + + TRACE("Sending tooltip notification to %p\n", infoPtr->hwndNotify); + + /* last resort: send notification on to app */ + /* FIXME: find out what is really used here */ + return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, 0, (LPARAM)lpnmtdi); +} + + +inline static LRESULT +TOOLBAR_Notify (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + LPNMHDR lpnmh = (LPNMHDR)lParam; + + switch (lpnmh->code) + { + case PGN_CALCSIZE: + { + LPNMPGCALCSIZE lppgc = (LPNMPGCALCSIZE)lParam; + + if (lppgc->dwFlag == PGF_CALCWIDTH) { + lppgc->iWidth = infoPtr->rcBound.right - infoPtr->rcBound.left; + TRACE("processed PGN_CALCSIZE, returning horz size = %d\n", + lppgc->iWidth); + } + else { + lppgc->iHeight = infoPtr->rcBound.bottom - infoPtr->rcBound.top; + TRACE("processed PGN_CALCSIZE, returning vert size = %d\n", + lppgc->iHeight); + } + return 0; + } + + case PGN_SCROLL: + { + LPNMPGSCROLL lppgs = (LPNMPGSCROLL)lParam; + + lppgs->iScroll = (lppgs->iDir & (PGF_SCROLLLEFT | PGF_SCROLLRIGHT)) ? + infoPtr->nButtonWidth : infoPtr->nButtonHeight; + TRACE("processed PGN_SCROLL, returning scroll=%d, dir=%d\n", + lppgs->iScroll, lppgs->iDir); + return 0; + } + + case TTN_GETDISPINFOW: + return TOOLBAR_TTGetDispInfo(infoPtr, (LPNMTTDISPINFOW)lParam); + + case TTN_GETDISPINFOA: + FIXME("TTN_GETDISPINFOA - should not be received; please report\n"); + return 0; + + default: + return 0; + } +} + + +static LRESULT +TOOLBAR_NotifyFormat(TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + LRESULT format; + + TRACE("wParam = 0x%x, lParam = 0x%08lx\n", wParam, lParam); + + if (lParam == NF_QUERY) + return NFR_UNICODE; + + if (lParam == NF_REQUERY) { + format = SendMessageW(infoPtr->hwndNotify, + WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY); + if ((format != NFR_ANSI) && (format != NFR_UNICODE)) { + ERR("wrong response to WM_NOTIFYFORMAT (%ld), assuming ANSI\n", + format); + format = NFR_ANSI; + } + return format; + } + return 0; +} + + +static LRESULT +TOOLBAR_Paint (HWND hwnd, WPARAM wParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr(hwnd); + HDC hdc; + PAINTSTRUCT ps; + + /* fill ps.rcPaint with a default rect */ + memcpy(&(ps.rcPaint), &(infoPtr->rcBound), sizeof(infoPtr->rcBound)); + + hdc = wParam==0 ? BeginPaint(hwnd, &ps) : (HDC)wParam; + + TRACE("psrect=(%ld,%ld)-(%ld,%ld)\n", + ps.rcPaint.left, ps.rcPaint.top, + ps.rcPaint.right, ps.rcPaint.bottom); + + TOOLBAR_Refresh (hwnd, hdc, &ps); + if (!wParam) EndPaint (hwnd, &ps); + + return 0; +} + + +static LRESULT +TOOLBAR_SetRedraw (HWND hwnd, WPARAM wParam, LPARAM lParam) + /***************************************************** + * + * Function; + * Handles the WM_SETREDRAW message. + * + * Documentation: + * According to testing V4.71 of COMCTL32 returns the + * *previous* status of the redraw flag (either 0 or 1) + * instead of the MSDN documented value of 0 if handled. + * (For laughs see the "consistency" with same function + * in rebar.) + * + *****************************************************/ +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + BOOL oldredraw = infoPtr->bDoRedraw; + + TRACE("set to %s\n", + (wParam) ? "TRUE" : "FALSE"); + infoPtr->bDoRedraw = (BOOL) wParam; + if (wParam) { + InvalidateRect (infoPtr->hwndSelf, 0, TRUE); + } + return (oldredraw) ? 1 : 0; +} + + +static LRESULT +TOOLBAR_Size (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + DWORD dwStyle = infoPtr->dwStyle; + RECT parent_rect; + RECT window_rect; + HWND parent; + INT x, y; + INT cx, cy; + INT flags; + UINT uPosFlags = 0; + + /* Resize deadlock check */ + if (infoPtr->bAutoSize) { + infoPtr->bAutoSize = FALSE; + return 0; + } + + /* FIXME: optimize to only update size if the new size doesn't */ + /* match the current size */ + + flags = (INT) wParam; + + /* FIXME for flags = + * SIZE_MAXIMIZED, SIZE_MAXSHOW, SIZE_MINIMIZED + */ + + TRACE("sizing toolbar!\n"); + + if (flags == SIZE_RESTORED) { + /* width and height don't apply */ + parent = GetParent (hwnd); + GetClientRect(parent, &parent_rect); + x = parent_rect.left; + y = parent_rect.top; + + if (dwStyle & CCS_NORESIZE) { + uPosFlags |= (SWP_NOSIZE | SWP_NOMOVE); + + /* + * this sets the working width of the toolbar, and + * Calc Toolbar will not adjust it, only the height + */ + infoPtr->nWidth = parent_rect.right - parent_rect.left; + cy = infoPtr->nHeight; + cx = infoPtr->nWidth; + TOOLBAR_CalcToolbar (hwnd); + infoPtr->nWidth = cx; + infoPtr->nHeight = cy; + } + else { + infoPtr->nWidth = parent_rect.right - parent_rect.left; + TOOLBAR_CalcToolbar (hwnd); + cy = infoPtr->nHeight; + cx = infoPtr->nWidth; + + if ((dwStyle & CCS_BOTTOM) == CCS_NOMOVEY) { + GetWindowRect(hwnd, &window_rect); + ScreenToClient(parent, (LPPOINT)&window_rect.left); + y = window_rect.top; + } + if ((dwStyle & CCS_BOTTOM) == CCS_BOTTOM) { + GetWindowRect(hwnd, &window_rect); + y = parent_rect.bottom - + ( window_rect.bottom - window_rect.top); + } + } + + if (dwStyle & CCS_NOPARENTALIGN) { + uPosFlags |= SWP_NOMOVE; + cy = infoPtr->nHeight; + cx = infoPtr->nWidth; + } + + if (!(dwStyle & CCS_NODIVIDER)) + cy += GetSystemMetrics(SM_CYEDGE); + + if (dwStyle & WS_BORDER) + { + x = y = 1; + cy += GetSystemMetrics(SM_CYEDGE); + cx += GetSystemMetrics(SM_CXEDGE); + } + + if(infoPtr->dwExStyle & TBSTYLE_EX_HIDECLIPPEDBUTTONS) + { + RECT delta_width, delta_height, client, dummy; + DWORD min_x, max_x, min_y, max_y; + TBUTTON_INFO *btnPtr; + INT i; + + GetClientRect(hwnd, &client); + if(client.right > infoPtr->client_rect.right) + { + min_x = infoPtr->client_rect.right; + max_x = client.right; + } + else + { + max_x = infoPtr->client_rect.right; + min_x = client.right; + } + if(client.bottom > infoPtr->client_rect.bottom) + { + min_y = infoPtr->client_rect.bottom; + max_y = client.bottom; + } + else + { + max_y = infoPtr->client_rect.bottom; + min_y = client.bottom; + } + + SetRect(&delta_width, min_x, 0, max_x, min_y); + SetRect(&delta_height, 0, min_y, max_x, max_y); + + TRACE("delta_width %s delta_height %s\n", wine_dbgstr_rect(&delta_width), wine_dbgstr_rect(&delta_height)); + btnPtr = infoPtr->buttons; + for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) + if(IntersectRect(&dummy, &delta_width, &btnPtr->rect) || + IntersectRect(&dummy, &delta_height, &btnPtr->rect)) + InvalidateRect(hwnd, &btnPtr->rect, TRUE); + } + + if((uPosFlags & (SWP_NOSIZE | SWP_NOMOVE)) != (SWP_NOSIZE | SWP_NOMOVE)) + SetWindowPos (hwnd, 0, x, y, cx, cy, uPosFlags | SWP_NOZORDER); + } + GetClientRect(hwnd, &infoPtr->client_rect); + return 0; +} + + +static LRESULT +TOOLBAR_StyleChanged (HWND hwnd, INT nType, LPSTYLESTRUCT lpStyle) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + if (nType == GWL_STYLE) + { + if (lpStyle->styleNew & TBSTYLE_LIST) + infoPtr->dwDTFlags = DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS; + else + infoPtr->dwDTFlags = DT_CENTER | DT_END_ELLIPSIS; + + infoPtr->bBtnTranspnt = (lpStyle->styleNew & + (TBSTYLE_FLAT | TBSTYLE_LIST)); + TOOLBAR_CheckStyle (hwnd, lpStyle->styleNew); + + TRACE("new style 0x%08lx\n", lpStyle->styleNew); + + infoPtr->dwStyle = lpStyle->styleNew; + + /* only resize if one of the CCS_* styles was changed */ + if ((infoPtr->dwStyle ^ lpStyle->styleNew) & COMMON_STYLES) + { + TOOLBAR_AutoSize (hwnd); + + InvalidateRect(hwnd, NULL, TRUE); + } + } + + return 0; +} + + +static LRESULT +TOOLBAR_SysColorChange (HWND hwnd) +{ + COMCTL32_RefreshSysColors(); + + return 0; +} + + + +static LRESULT WINAPI +ToolbarWindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); + + TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", + hwnd, uMsg, /* SPY_GetMsgName(uMsg), */ wParam, lParam); + + if (!infoPtr && (uMsg != WM_NCCREATE)) + return DefWindowProcW( hwnd, uMsg, wParam, lParam ); + + switch (uMsg) + { + case TB_ADDBITMAP: + return TOOLBAR_AddBitmap (hwnd, wParam, lParam); + + case TB_ADDBUTTONSA: + return TOOLBAR_AddButtonsA (hwnd, wParam, lParam); + + case TB_ADDBUTTONSW: + return TOOLBAR_AddButtonsW (hwnd, wParam, lParam); + + case TB_ADDSTRINGA: + return TOOLBAR_AddStringA (hwnd, wParam, lParam); + + case TB_ADDSTRINGW: + return TOOLBAR_AddStringW (hwnd, wParam, lParam); + + case TB_AUTOSIZE: + return TOOLBAR_AutoSize (hwnd); + + case TB_BUTTONCOUNT: + return TOOLBAR_ButtonCount (hwnd, wParam, lParam); + + case TB_BUTTONSTRUCTSIZE: + return TOOLBAR_ButtonStructSize (hwnd, wParam, lParam); + + case TB_CHANGEBITMAP: + return TOOLBAR_ChangeBitmap (hwnd, wParam, lParam); + + case TB_CHECKBUTTON: + return TOOLBAR_CheckButton (hwnd, wParam, lParam); + + case TB_COMMANDTOINDEX: + return TOOLBAR_CommandToIndex (hwnd, wParam, lParam); + + case TB_CUSTOMIZE: + return TOOLBAR_Customize (hwnd); + + case TB_DELETEBUTTON: + return TOOLBAR_DeleteButton (hwnd, wParam, lParam); + + case TB_ENABLEBUTTON: + return TOOLBAR_EnableButton (hwnd, wParam, lParam); + + case TB_GETANCHORHIGHLIGHT: + return TOOLBAR_GetAnchorHighlight (hwnd); + + case TB_GETBITMAP: + return TOOLBAR_GetBitmap (hwnd, wParam, lParam); + + case TB_GETBITMAPFLAGS: + return TOOLBAR_GetBitmapFlags (hwnd, wParam, lParam); + + case TB_GETBUTTON: + return TOOLBAR_GetButton (hwnd, wParam, lParam); + + case TB_GETBUTTONINFOA: + return TOOLBAR_GetButtonInfoA (hwnd, wParam, lParam); + + case TB_GETBUTTONINFOW: + return TOOLBAR_GetButtonInfoW (hwnd, wParam, lParam); + + case TB_GETBUTTONSIZE: + return TOOLBAR_GetButtonSize (hwnd); + + case TB_GETBUTTONTEXTA: + return TOOLBAR_GetButtonTextA (hwnd, wParam, lParam); + + case TB_GETBUTTONTEXTW: + return TOOLBAR_GetButtonTextW (hwnd, wParam, lParam); + + case TB_GETDISABLEDIMAGELIST: + return TOOLBAR_GetDisabledImageList (hwnd, wParam, lParam); + + case TB_GETEXTENDEDSTYLE: + return TOOLBAR_GetExtendedStyle (hwnd); + + case TB_GETHOTIMAGELIST: + return TOOLBAR_GetHotImageList (hwnd, wParam, lParam); + + case TB_GETHOTITEM: + return TOOLBAR_GetHotItem (hwnd); + + case TB_GETIMAGELIST: + return TOOLBAR_GetDefImageList (hwnd, wParam, lParam); + + case TB_GETINSERTMARK: + return TOOLBAR_GetInsertMark (hwnd, wParam, lParam); + + case TB_GETINSERTMARKCOLOR: + return TOOLBAR_GetInsertMarkColor (hwnd, wParam, lParam); + + case TB_GETITEMRECT: + return TOOLBAR_GetItemRect (hwnd, wParam, lParam); + + case TB_GETMAXSIZE: + return TOOLBAR_GetMaxSize (hwnd, wParam, lParam); + +/* case TB_GETOBJECT: */ /* 4.71 */ + + case TB_GETPADDING: + return TOOLBAR_GetPadding (hwnd); + + case TB_GETRECT: + return TOOLBAR_GetRect (hwnd, wParam, lParam); + + case TB_GETROWS: + return TOOLBAR_GetRows (hwnd, wParam, lParam); + + case TB_GETSTATE: + return TOOLBAR_GetState (hwnd, wParam, lParam); + + case TB_GETSTRINGA: + return TOOLBAR_GetStringA (hwnd, wParam, lParam); + + case TB_GETSTRINGW: + return TOOLBAR_GetStringW (hwnd, wParam, lParam); + + case TB_GETSTYLE: + return TOOLBAR_GetStyle (hwnd, wParam, lParam); + + case TB_GETTEXTROWS: + return TOOLBAR_GetTextRows (hwnd, wParam, lParam); + + case TB_GETTOOLTIPS: + return TOOLBAR_GetToolTips (hwnd, wParam, lParam); + + case TB_GETUNICODEFORMAT: + return TOOLBAR_GetUnicodeFormat (hwnd, wParam, lParam); + + case TB_HIDEBUTTON: + return TOOLBAR_HideButton (hwnd, wParam, lParam); + + case TB_HITTEST: + return TOOLBAR_HitTest (hwnd, wParam, lParam); + + case TB_INDETERMINATE: + return TOOLBAR_Indeterminate (hwnd, wParam, lParam); + + case TB_INSERTBUTTONA: + return TOOLBAR_InsertButtonA (hwnd, wParam, lParam); + + case TB_INSERTBUTTONW: + return TOOLBAR_InsertButtonW (hwnd, wParam, lParam); + +/* case TB_INSERTMARKHITTEST: */ /* 4.71 */ + + case TB_ISBUTTONCHECKED: + return TOOLBAR_IsButtonChecked (hwnd, wParam, lParam); + + case TB_ISBUTTONENABLED: + return TOOLBAR_IsButtonEnabled (hwnd, wParam, lParam); + + case TB_ISBUTTONHIDDEN: + return TOOLBAR_IsButtonHidden (hwnd, wParam, lParam); + + case TB_ISBUTTONHIGHLIGHTED: + return TOOLBAR_IsButtonHighlighted (hwnd, wParam, lParam); + + case TB_ISBUTTONINDETERMINATE: + return TOOLBAR_IsButtonIndeterminate (hwnd, wParam, lParam); + + case TB_ISBUTTONPRESSED: + return TOOLBAR_IsButtonPressed (hwnd, wParam, lParam); + + case TB_LOADIMAGES: + return TOOLBAR_LoadImages (hwnd, wParam, lParam); + + case TB_MAPACCELERATORA: + case TB_MAPACCELERATORW: + return TOOLBAR_MapAccelerator (hwnd, wParam, lParam); + + case TB_MARKBUTTON: + return TOOLBAR_MarkButton (hwnd, wParam, lParam); + + case TB_MOVEBUTTON: + return TOOLBAR_MoveButton (hwnd, wParam, lParam); + + case TB_PRESSBUTTON: + return TOOLBAR_PressButton (hwnd, wParam, lParam); + + case TB_REPLACEBITMAP: + return TOOLBAR_ReplaceBitmap (hwnd, wParam, lParam); + + case TB_SAVERESTOREA: + return TOOLBAR_SaveRestoreA (hwnd, wParam, (LPTBSAVEPARAMSA)lParam); + + case TB_SAVERESTOREW: + return TOOLBAR_SaveRestoreW (hwnd, wParam, (LPTBSAVEPARAMSW)lParam); + + case TB_SETANCHORHIGHLIGHT: + return TOOLBAR_SetAnchorHighlight (hwnd, wParam); + + case TB_SETBITMAPSIZE: + return TOOLBAR_SetBitmapSize (hwnd, wParam, lParam); + + case TB_SETBUTTONINFOA: + return TOOLBAR_SetButtonInfoA (hwnd, wParam, lParam); + + case TB_SETBUTTONINFOW: + return TOOLBAR_SetButtonInfoW (hwnd, wParam, lParam); + + case TB_SETBUTTONSIZE: + return TOOLBAR_SetButtonSize (hwnd, wParam, lParam); + + case TB_SETBUTTONWIDTH: + return TOOLBAR_SetButtonWidth (hwnd, wParam, lParam); + + case TB_SETCMDID: + return TOOLBAR_SetCmdId (hwnd, wParam, lParam); + + case TB_SETDISABLEDIMAGELIST: + return TOOLBAR_SetDisabledImageList (hwnd, wParam, lParam); + + case TB_SETDRAWTEXTFLAGS: + return TOOLBAR_SetDrawTextFlags (hwnd, wParam, lParam); + + case TB_SETEXTENDEDSTYLE: + return TOOLBAR_SetExtendedStyle (hwnd, wParam, lParam); + + case TB_SETHOTIMAGELIST: + return TOOLBAR_SetHotImageList (hwnd, wParam, lParam); + + case TB_SETHOTITEM: + return TOOLBAR_SetHotItem (hwnd, wParam); + + case TB_SETIMAGELIST: + return TOOLBAR_SetImageList (hwnd, wParam, lParam); + + case TB_SETINDENT: + return TOOLBAR_SetIndent (hwnd, wParam, lParam); + + case TB_SETINSERTMARK: + return TOOLBAR_SetInsertMark (hwnd, wParam, lParam); + + case TB_SETINSERTMARKCOLOR: + return TOOLBAR_SetInsertMarkColor (hwnd, wParam, lParam); + + case TB_SETMAXTEXTROWS: + return TOOLBAR_SetMaxTextRows (hwnd, wParam, lParam); + + case TB_SETPADDING: + return TOOLBAR_SetPadding (hwnd, wParam, lParam); + + case TB_SETPARENT: + return TOOLBAR_SetParent (hwnd, wParam, lParam); + + case TB_SETROWS: + return TOOLBAR_SetRows (hwnd, wParam, lParam); + + case TB_SETSTATE: + return TOOLBAR_SetState (hwnd, wParam, lParam); + + case TB_SETSTYLE: + return TOOLBAR_SetStyle (hwnd, wParam, lParam); + + case TB_SETTOOLTIPS: + return TOOLBAR_SetToolTips (hwnd, wParam, lParam); + + case TB_SETUNICODEFORMAT: + return TOOLBAR_SetUnicodeFormat (hwnd, wParam, lParam); + + case TB_UNKWN45D: + return TOOLBAR_Unkwn45D(hwnd, wParam, lParam); + + case TB_UNKWN45E: + return TOOLBAR_Unkwn45E (hwnd, wParam, lParam); + + case TB_UNKWN460: + return TOOLBAR_Unkwn460(hwnd, wParam, lParam); + + case TB_UNKWN462: + return TOOLBAR_Unkwn462(hwnd, wParam, lParam); + + case TB_UNKWN463: + return TOOLBAR_Unkwn463 (hwnd, wParam, lParam); + + case TB_UNKWN464: + return TOOLBAR_Unkwn464(hwnd, wParam, lParam); + +/* Common Control Messages */ + +/* case TB_GETCOLORSCHEME: */ /* identical to CCM_ */ + case CCM_GETCOLORSCHEME: + return TOOLBAR_GetColorScheme (hwnd, (LPCOLORSCHEME)lParam); + +/* case TB_SETCOLORSCHEME: */ /* identical to CCM_ */ + case CCM_SETCOLORSCHEME: + return TOOLBAR_SetColorScheme (hwnd, (LPCOLORSCHEME)lParam); + + case CCM_GETVERSION: + return TOOLBAR_GetVersion (hwnd); + + case CCM_SETVERSION: + return TOOLBAR_SetVersion (hwnd, (INT)wParam); + + +/* case WM_CHAR: */ + + case WM_CREATE: + return TOOLBAR_Create (hwnd, wParam, lParam); + + case WM_DESTROY: + return TOOLBAR_Destroy (hwnd, wParam, lParam); + + case WM_ERASEBKGND: + return TOOLBAR_EraseBackground (hwnd, wParam, lParam); + + case WM_GETFONT: + return TOOLBAR_GetFont (hwnd, wParam, lParam); + +/* case WM_KEYDOWN: */ +/* case WM_KILLFOCUS: */ + + case WM_LBUTTONDBLCLK: + return TOOLBAR_LButtonDblClk (hwnd, wParam, lParam); + + case WM_LBUTTONDOWN: + return TOOLBAR_LButtonDown (hwnd, wParam, lParam); + + case WM_LBUTTONUP: + return TOOLBAR_LButtonUp (hwnd, wParam, lParam); + + case WM_RBUTTONUP: + return TOOLBAR_RButtonUp (hwnd, wParam, lParam); + + case WM_RBUTTONDBLCLK: + return TOOLBAR_RButtonDblClk (hwnd, wParam, lParam); + + case WM_MOUSEMOVE: + return TOOLBAR_MouseMove (hwnd, wParam, lParam); + + case WM_MOUSELEAVE: + return TOOLBAR_MouseLeave (hwnd, wParam, lParam); + + case WM_CAPTURECHANGED: + return TOOLBAR_CaptureChanged(hwnd); + + case WM_NCACTIVATE: + return TOOLBAR_NCActivate (hwnd, wParam, lParam); + + case WM_NCCALCSIZE: + return TOOLBAR_NCCalcSize (hwnd, wParam, lParam); + + case WM_NCCREATE: + return TOOLBAR_NCCreate (hwnd, wParam, lParam); + + case WM_NCPAINT: + return TOOLBAR_NCPaint (hwnd, wParam, lParam); + + case WM_NOTIFY: + return TOOLBAR_Notify (hwnd, wParam, lParam); + + case WM_NOTIFYFORMAT: + return TOOLBAR_NotifyFormat (infoPtr, wParam, lParam); + + case WM_PAINT: + return TOOLBAR_Paint (hwnd, wParam); + + case WM_SETREDRAW: + return TOOLBAR_SetRedraw (hwnd, wParam, lParam); + + case WM_SIZE: + return TOOLBAR_Size (hwnd, wParam, lParam); + + case WM_STYLECHANGED: + return TOOLBAR_StyleChanged (hwnd, (INT)wParam, (LPSTYLESTRUCT)lParam); + + case WM_SYSCOLORCHANGE: + return TOOLBAR_SysColorChange (hwnd); + +/* case WM_WININICHANGE: */ + + case WM_CHARTOITEM: + case WM_COMMAND: + case WM_DRAWITEM: + case WM_MEASUREITEM: + case WM_VKEYTOITEM: + return SendMessageW (infoPtr->hwndNotify, uMsg, wParam, lParam); + + /* We see this in Outlook Express 5.x and just does DefWindowProc */ + case PGM_FORWARDMOUSE: + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + + default: + if ((uMsg >= WM_USER) && (uMsg < WM_APP)) + ERR("unknown msg %04x wp=%08x lp=%08lx\n", + uMsg, wParam, lParam); + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + } +} + + +VOID +TOOLBAR_Register (void) +{ + WNDCLASSW wndClass; + + ZeroMemory (&wndClass, sizeof(WNDCLASSW)); + wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS; + wndClass.lpfnWndProc = ToolbarWindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(TOOLBAR_INFO *); + wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); + wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); + wndClass.lpszClassName = TOOLBARCLASSNAMEW; + + RegisterClassW (&wndClass); +} + + +VOID +TOOLBAR_Unregister (void) +{ + UnregisterClassW (TOOLBARCLASSNAMEW, NULL); +} + +static HIMAGELIST TOOLBAR_InsertImageList(PIMLENTRY **pies, INT *cies, HIMAGELIST himl, INT id) +{ + HIMAGELIST himlold; + PIMLENTRY c = NULL; + + /* Check if the entry already exists */ + c = TOOLBAR_GetImageListEntry(*pies, *cies, id); + + /* If this is a new entry we must create it and insert into the array */ + if (!c) + { + PIMLENTRY *pnies; + + c = (PIMLENTRY) Alloc(sizeof(IMLENTRY)); + c->id = id; + + pnies = Alloc((*cies + 1) * sizeof(PIMLENTRY)); + memcpy(pnies, *pies, ((*cies) * sizeof(PIMLENTRY))); + pnies[*cies] = c; + (*cies)++; + + Free(*pies); + *pies = pnies; + } + + himlold = c->himl; + c->himl = himl; + + return himlold; +} + + +static VOID TOOLBAR_DeleteImageList(PIMLENTRY **pies, INT *cies) +{ + int i; + + for (i = 0; i < *cies; i++) + Free((*pies)[i]); + + Free(*pies); + + *cies = 0; + *pies = NULL; +} + + +static PIMLENTRY TOOLBAR_GetImageListEntry(PIMLENTRY *pies, INT cies, INT id) +{ + PIMLENTRY c = NULL; + + if (pies != NULL) + { + int i; + + for (i = 0; i < cies; i++) + { + if (pies[i]->id == id) + { + c = pies[i]; + break; + } + } + } + + return c; +} + + +static HIMAGELIST TOOLBAR_GetImageList(PIMLENTRY *pies, INT cies, INT id) +{ + HIMAGELIST himlDef = 0; + PIMLENTRY pie = TOOLBAR_GetImageListEntry(pies, cies, id); + + if (pie) + himlDef = pie->himl; + + return himlDef; +} + + +static BOOL TOOLBAR_GetButtonInfo(TOOLBAR_INFO *infoPtr, NMTOOLBARW *nmtb) +{ + if (infoPtr->bUnicode) + return TOOLBAR_SendNotify(&nmtb->hdr, infoPtr, TBN_GETBUTTONINFOW); + else + { + CHAR Buffer[256]; + NMTOOLBARA nmtba; + BOOL bRet = FALSE; + + nmtba.iItem = nmtb->iItem; + nmtba.pszText = Buffer; + nmtba.cchText = 256; + ZeroMemory(nmtba.pszText, nmtba.cchText); + + if (TOOLBAR_SendNotify(&nmtba.hdr, infoPtr, TBN_GETBUTTONINFOA)) + { + int ccht = strlen(nmtba.pszText); + if (ccht) + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)nmtba.pszText, -1, + nmtb->pszText, nmtb->cchText); + + memcpy(&nmtb->tbButton, &nmtba.tbButton, sizeof(TBBUTTON)); + bRet = TRUE; + } + + return bRet; + } +} + + +static BOOL TOOLBAR_IsButtonRemovable(TOOLBAR_INFO *infoPtr, + int iItem, PCUSTOMBUTTON btnInfo) +{ + NMTOOLBARW nmtb; + + /* MSDN states that iItem is the index of the button, rather than the + * command ID as used by every other NMTOOLBAR notification */ + nmtb.iItem = iItem; + memcpy(&nmtb.tbButton, &btnInfo->btn, sizeof(TBBUTTON)); + + return TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_QUERYDELETE); +} diff --git a/reactos/lib/comctl32/tooltips.c b/reactos/lib/comctl32/tooltips.c index 7abe894b013..80073d47935 100644 --- a/reactos/lib/comctl32/tooltips.c +++ b/reactos/lib/comctl32/tooltips.c @@ -1,2839 +1,2839 @@ -/* - * Tool tip control - * - * Copyright 1998, 1999 Eric Kohl - * Copyright 2004 Robert Shearman - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTES - * - * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on Sep. 08, 2004, by Robert Shearman. - * - * Unless otherwise noted, we believe this code to be complete, as per - * the specification mentioned above. - * If you discover missing features or bugs please note them below. - * - * TODO: - * - Custom draw support. - * - Animation. - * - Links. - * - Messages: - * o TTM_ADJUSTRECT - * o TTM_GETTITLEA - * o TTM_GETTTILEW - * o TTM_POPUP - * - Styles: - * o TTS_NOANIMATE - * o TTS_NOFADE - * o TTS_CLOSE - * - * Testing: - * - Run tests using Waite Group Windows95 API Bible Volume 2. - * The second cdrom (chapter 3) contains executables activate.exe, - * curtool.exe, deltool.exe, enumtools.exe, getinfo.exe, getiptxt.exe, - * hittest.exe, needtext.exe, newrect.exe, updtext.exe and winfrpt.exe. - * - * Timer logic. - * - * One important point to remember is that tools don't necessarily get - * a WM_MOUSEMOVE once the cursor leaves the tool, an example is when - * a tool sets TTF_IDISHWND (i.e. an entire window is a tool) because - * here WM_MOUSEMOVEs only get sent when the cursor is inside the - * client area. Therefore the only reliable way to know that the - * cursor has left a tool is to keep a timer running and check the - * position every time it expires. This is the role of timer - * ID_TIMERLEAVE. - * - * - * On entering a tool (detected in a relayed WM_MOUSEMOVE) we start - * ID_TIMERSHOW, if this times out and we're still in the tool we show - * the tip. On showing a tip we start both ID_TIMERPOP and - * ID_TIMERLEAVE. On hiding a tooltip we kill ID_TIMERPOP. - * ID_TIMERPOP is restarted on every relayed WM_MOUSEMOVE. If - * ID_TIMERPOP expires the tool is hidden and ID_TIMERPOP is killed. - * ID_TIMERLEAVE remains running - this is important as we need to - * determine when the cursor leaves the tool. - * - * When ID_TIMERLEAVE expires or on a relayed WM_MOUSEMOVE if we're - * still in the tool do nothing (apart from restart ID_TIMERPOP if - * this is a WM_MOUSEMOVE) (ID_TIMERLEAVE remains running). If we've - * left the tool and entered another one then hide the tip and start - * ID_TIMERSHOW with time ReshowTime and kill ID_TIMERLEAVE. If we're - * outside all tools hide the tip and kill ID_TIMERLEAVE. On Relayed - * mouse button messages hide the tip but leave ID_TIMERLEAVE running, - * this again will let us keep track of when the cursor leaves the - * tool. - * - * - * infoPtr->nTool is the tool the mouse was on on the last relayed MM - * or timer expiry or -1 if the mouse was not on a tool. - * - * infoPtr->nCurrentTool is the tool for which the tip is currently - * displaying text for or -1 if the tip is not shown. Actually this - * will only ever be infoPtr-nTool or -1, so it could be changed to a - * BOOL. - * - */ - - - -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "wine/unicode.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "comctl32.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(tooltips); - -static HICON hTooltipIcons[TTI_ERROR+1]; - -typedef struct -{ - UINT uFlags; - HWND hwnd; - BOOL bNotifyUnicode; - UINT uId; - RECT rect; - HINSTANCE hinst; - LPWSTR lpszText; - LPARAM lParam; -} TTTOOL_INFO; - - -typedef struct -{ - WCHAR szTipText[INFOTIPSIZE]; - BOOL bActive; - BOOL bTrackActive; - UINT uNumTools; - COLORREF clrBk; - COLORREF clrText; - HFONT hFont; - HFONT hTitleFont; - INT xTrackPos; - INT yTrackPos; - INT nMaxTipWidth; - INT nTool; /* tool that mouse was on on last relayed mouse move */ - INT nCurrentTool; - INT nTrackTool; - INT nReshowTime; - INT nAutoPopTime; - INT nInitialTime; - RECT rcMargin; - BOOL bToolBelow; - LPWSTR pszTitle; - HICON hTitleIcon; - - TTTOOL_INFO *tools; -} TOOLTIPS_INFO; - -#define ID_TIMERSHOW 1 /* show delay timer */ -#define ID_TIMERPOP 2 /* auto pop timer */ -#define ID_TIMERLEAVE 3 /* tool leave timer */ - - -#define TOOLTIPS_GetInfoPtr(hWindow) ((TOOLTIPS_INFO *)GetWindowLongPtrW (hWindow, 0)) - -/* offsets from window edge to start of text */ -#define NORMAL_TEXT_MARGIN 2 -#define BALLOON_TEXT_MARGIN (NORMAL_TEXT_MARGIN+8) -/* value used for CreateRoundRectRgn that specifies how much - * each corner is curved */ -#define BALLOON_ROUNDEDNESS 20 -#define BALLOON_STEMHEIGHT 13 -#define BALLOON_STEMWIDTH 10 -#define BALLOON_STEMINDENT 20 - -#define BALLOON_ICON_TITLE_SPACING 8 /* horizontal spacing between icon and title */ -#define BALLOON_TITLE_TEXT_SPACING 8 /* vertical spacing between icon/title and main text */ -#define ICON_HEIGHT 16 -#define ICON_WIDTH 16 - -static LRESULT CALLBACK -TOOLTIPS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uId, DWORD_PTR dwRef); - - -inline static UINT_PTR -TOOLTIPS_GetTitleIconIndex(HICON hIcon) -{ - UINT i; - for (i = 0; i <= TTI_ERROR; i++) - if (hTooltipIcons[i] == hIcon) - return i; - return (UINT_PTR)hIcon; -} - -static void -TOOLTIPS_InitSystemSettings (TOOLTIPS_INFO *infoPtr) -{ - NONCLIENTMETRICSW nclm; - - infoPtr->clrBk = GetSysColor (COLOR_INFOBK); - infoPtr->clrText = GetSysColor (COLOR_INFOTEXT); - - DeleteObject (infoPtr->hFont); - nclm.cbSize = sizeof(nclm); - SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, sizeof(nclm), &nclm, 0); - infoPtr->hFont = CreateFontIndirectW (&nclm.lfStatusFont); - - DeleteObject (infoPtr->hTitleFont); - nclm.lfStatusFont.lfWeight = FW_BOLD; - infoPtr->hTitleFont = CreateFontIndirectW (&nclm.lfStatusFont); -} - -static void -TOOLTIPS_Refresh (HWND hwnd, HDC hdc) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(hwnd); - RECT rc; - INT oldBkMode; - HFONT hOldFont; - HBRUSH hBrush; - UINT uFlags = DT_EXTERNALLEADING; - HRGN hRgn = NULL; - DWORD dwStyle = GetWindowLongW(hwnd, GWL_STYLE); - - if (infoPtr->nMaxTipWidth > -1) - uFlags |= DT_WORDBREAK; - if (GetWindowLongW (hwnd, GWL_STYLE) & TTS_NOPREFIX) - uFlags |= DT_NOPREFIX; - GetClientRect (hwnd, &rc); - - hBrush = CreateSolidBrush(infoPtr->clrBk); - - oldBkMode = SetBkMode (hdc, TRANSPARENT); - SetTextColor (hdc, infoPtr->clrText); - - if (dwStyle & TTS_BALLOON) - { - /* create a region to store result into */ - hRgn = CreateRectRgn(0, 0, 0, 0); - - GetWindowRgn(hwnd, hRgn); - - /* fill the background */ - FillRgn(hdc, hRgn, hBrush); - DeleteObject(hBrush); - hBrush = NULL; - } - else - { - /* fill the background */ - FillRect(hdc, &rc, hBrush); - DeleteObject(hBrush); - hBrush = NULL; - } - - if ((dwStyle & TTS_BALLOON) || infoPtr->pszTitle) - { - /* calculate text rectangle */ - rc.left += (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.left); - rc.top += (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.top); - rc.right -= (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.right); - rc.bottom -= (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.bottom); - if(infoPtr->bToolBelow) rc.top += BALLOON_STEMHEIGHT; - - if (infoPtr->pszTitle) - { - RECT rcTitle = {rc.left, rc.top, rc.right, rc.bottom}; - int height; - BOOL icon_present; - - /* draw icon */ - icon_present = infoPtr->hTitleIcon && - DrawIconEx(hdc, rc.left, rc.top, infoPtr->hTitleIcon, - ICON_WIDTH, ICON_HEIGHT, 0, NULL, DI_NORMAL); - if (icon_present) - rcTitle.left += ICON_WIDTH + BALLOON_ICON_TITLE_SPACING; - - rcTitle.bottom = rc.top + ICON_HEIGHT; - - /* draw title text */ - hOldFont = SelectObject (hdc, infoPtr->hTitleFont); - height = DrawTextW(hdc, infoPtr->pszTitle, -1, &rcTitle, DT_BOTTOM | DT_SINGLELINE | DT_NOPREFIX); - SelectObject (hdc, hOldFont); - rc.top += height + BALLOON_TITLE_TEXT_SPACING; - } - } - else - { - /* calculate text rectangle */ - rc.left += (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.left); - rc.top += (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.top); - rc.right -= (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.right); - rc.bottom -= (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.bottom); - } - - /* draw text */ - hOldFont = SelectObject (hdc, infoPtr->hFont); - DrawTextW (hdc, infoPtr->szTipText, -1, &rc, uFlags); - /* be polite and reset the things we changed in the dc */ - SelectObject (hdc, hOldFont); - SetBkMode (hdc, oldBkMode); - - if (dwStyle & TTS_BALLOON) - { - /* frame region because default window proc doesn't do it */ - INT width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE); - INT height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE); - - hBrush = GetSysColorBrush(COLOR_WINDOWFRAME); - FrameRgn(hdc, hRgn, hBrush, width, height); - } - - if (hRgn) - DeleteObject(hRgn); -} - -static void TOOLTIPS_GetDispInfoA(HWND hwnd, TOOLTIPS_INFO *infoPtr, TTTOOL_INFO *toolPtr) -{ - NMTTDISPINFOA ttnmdi; - - /* fill NMHDR struct */ - ZeroMemory (&ttnmdi, sizeof(NMTTDISPINFOA)); - ttnmdi.hdr.hwndFrom = hwnd; - ttnmdi.hdr.idFrom = toolPtr->uId; - ttnmdi.hdr.code = TTN_GETDISPINFOA; - ttnmdi.lpszText = (LPSTR)&ttnmdi.szText; - ttnmdi.uFlags = toolPtr->uFlags; - ttnmdi.lParam = toolPtr->lParam; - - TRACE("hdr.idFrom = %x\n", ttnmdi.hdr.idFrom); - SendMessageW(toolPtr->hwnd, WM_NOTIFY, - (WPARAM)toolPtr->uId, (LPARAM)&ttnmdi); - - if (HIWORD((UINT)ttnmdi.lpszText) == 0) { - LoadStringW(ttnmdi.hinst, (UINT)ttnmdi.lpszText, - infoPtr->szTipText, INFOTIPSIZE); - if (ttnmdi.uFlags & TTF_DI_SETITEM) { - toolPtr->hinst = ttnmdi.hinst; - toolPtr->lpszText = (LPWSTR)ttnmdi.lpszText; - } - } - else if (ttnmdi.lpszText == 0) { - /* no text available */ - infoPtr->szTipText[0] = '\0'; - } - else if (ttnmdi.lpszText != LPSTR_TEXTCALLBACKA) { - INT max_len = (ttnmdi.lpszText == &ttnmdi.szText[0]) ? - sizeof(ttnmdi.szText)/sizeof(ttnmdi.szText[0]) : -1; - MultiByteToWideChar(CP_ACP, 0, ttnmdi.lpszText, max_len, - infoPtr->szTipText, INFOTIPSIZE); - if (ttnmdi.uFlags & TTF_DI_SETITEM) { - INT len = MultiByteToWideChar(CP_ACP, 0, ttnmdi.lpszText, - max_len, NULL, 0); - toolPtr->hinst = 0; - toolPtr->lpszText = Alloc (len * sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, ttnmdi.lpszText, -1, - toolPtr->lpszText, len); - } - } - else { - ERR("recursive text callback!\n"); - infoPtr->szTipText[0] = '\0'; - } -} - -static void TOOLTIPS_GetDispInfoW(HWND hwnd, TOOLTIPS_INFO *infoPtr, TTTOOL_INFO *toolPtr) -{ - NMTTDISPINFOW ttnmdi; - - /* fill NMHDR struct */ - ZeroMemory (&ttnmdi, sizeof(NMTTDISPINFOW)); - ttnmdi.hdr.hwndFrom = hwnd; - ttnmdi.hdr.idFrom = toolPtr->uId; - ttnmdi.hdr.code = TTN_GETDISPINFOW; - ttnmdi.lpszText = (LPWSTR)&ttnmdi.szText; - ttnmdi.uFlags = toolPtr->uFlags; - ttnmdi.lParam = toolPtr->lParam; - - TRACE("hdr.idFrom = %x\n", ttnmdi.hdr.idFrom); - SendMessageW(toolPtr->hwnd, WM_NOTIFY, - (WPARAM)toolPtr->uId, (LPARAM)&ttnmdi); - - if (HIWORD((UINT)ttnmdi.lpszText) == 0) { - LoadStringW(ttnmdi.hinst, (UINT)ttnmdi.lpszText, - infoPtr->szTipText, INFOTIPSIZE); - if (ttnmdi.uFlags & TTF_DI_SETITEM) { - toolPtr->hinst = ttnmdi.hinst; - toolPtr->lpszText = ttnmdi.lpszText; - } - } - else if (ttnmdi.lpszText == 0) { - /* no text available */ - infoPtr->szTipText[0] = '\0'; - } - else if (ttnmdi.lpszText != LPSTR_TEXTCALLBACKW) { - INT max_len = (ttnmdi.lpszText == &ttnmdi.szText[0]) ? - sizeof(ttnmdi.szText)/sizeof(ttnmdi.szText[0]) : INFOTIPSIZE-1; - lstrcpynW(infoPtr->szTipText, ttnmdi.lpszText, max_len); - if (ttnmdi.uFlags & TTF_DI_SETITEM) { - INT len = max(strlenW(ttnmdi.lpszText), max_len); - toolPtr->hinst = 0; - toolPtr->lpszText = Alloc ((len+1) * sizeof(WCHAR)); - memcpy(toolPtr->lpszText, ttnmdi.lpszText, (len+1) * sizeof(WCHAR)); - } - } - else { - ERR("recursive text callback!\n"); - infoPtr->szTipText[0] = '\0'; - } -} - -static void -TOOLTIPS_GetTipText (HWND hwnd, TOOLTIPS_INFO *infoPtr, INT nTool) -{ - TTTOOL_INFO *toolPtr = &infoPtr->tools[nTool]; - - if (HIWORD((UINT)toolPtr->lpszText) == 0 && toolPtr->hinst) { - /* load a resource */ - TRACE("load res string %p %x\n", - toolPtr->hinst, (int)toolPtr->lpszText); - LoadStringW (toolPtr->hinst, (UINT)toolPtr->lpszText, - infoPtr->szTipText, INFOTIPSIZE); - } - else if (toolPtr->lpszText) { - if (toolPtr->lpszText == LPSTR_TEXTCALLBACKW) { - if (toolPtr->bNotifyUnicode) - TOOLTIPS_GetDispInfoW(hwnd, infoPtr, toolPtr); - else - TOOLTIPS_GetDispInfoA(hwnd, infoPtr, toolPtr); - } - else { - /* the item is a usual (unicode) text */ - lstrcpynW (infoPtr->szTipText, toolPtr->lpszText, INFOTIPSIZE); - } - } - else { - /* no text available */ - infoPtr->szTipText[0] = L'\0'; - } - - TRACE("%s\n", debugstr_w(infoPtr->szTipText)); -} - - -static void -TOOLTIPS_CalcTipSize (HWND hwnd, TOOLTIPS_INFO *infoPtr, LPSIZE lpSize) -{ - HDC hdc; - HFONT hOldFont; - DWORD style = GetWindowLongW(hwnd, GWL_STYLE); - UINT uFlags = DT_EXTERNALLEADING | DT_CALCRECT; - RECT rc = {0, 0, 0, 0}; - SIZE title = {0, 0}; - - if (infoPtr->nMaxTipWidth > -1) { - rc.right = infoPtr->nMaxTipWidth; - uFlags |= DT_WORDBREAK; - } - if (style & TTS_NOPREFIX) - uFlags |= DT_NOPREFIX; - TRACE("%s\n", debugstr_w(infoPtr->szTipText)); - - hdc = GetDC (hwnd); - if (infoPtr->pszTitle) - { - RECT rcTitle = {0, 0, 0, 0}; - TRACE("title %s\n", debugstr_w(infoPtr->pszTitle)); - if (infoPtr->hTitleIcon) - { - title.cx = ICON_WIDTH; - title.cy = ICON_HEIGHT; - } - if (title.cx != 0) title.cx += BALLOON_ICON_TITLE_SPACING; - hOldFont = SelectObject (hdc, infoPtr->hTitleFont); - DrawTextW(hdc, infoPtr->pszTitle, -1, &rcTitle, DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT); - SelectObject (hdc, hOldFont); - title.cy = max(title.cy, rcTitle.bottom - rcTitle.top) + BALLOON_TITLE_TEXT_SPACING; - title.cx += (rcTitle.right - rcTitle.left); - } - hOldFont = SelectObject (hdc, infoPtr->hFont); - DrawTextW (hdc, infoPtr->szTipText, -1, &rc, uFlags); - SelectObject (hdc, hOldFont); - ReleaseDC (hwnd, hdc); - - if ((style & TTS_BALLOON) || infoPtr->pszTitle) - { - lpSize->cx = max(rc.right - rc.left, title.cx) + 2*BALLOON_TEXT_MARGIN + - infoPtr->rcMargin.left + infoPtr->rcMargin.right; - lpSize->cy = title.cy + rc.bottom - rc.top + 2*BALLOON_TEXT_MARGIN + - infoPtr->rcMargin.bottom + infoPtr->rcMargin.top + - BALLOON_STEMHEIGHT; - } - else - { - lpSize->cx = rc.right - rc.left + 2*NORMAL_TEXT_MARGIN + - infoPtr->rcMargin.left + infoPtr->rcMargin.right; - lpSize->cy = rc.bottom - rc.top + 2*NORMAL_TEXT_MARGIN + - infoPtr->rcMargin.bottom + infoPtr->rcMargin.top; - } -} - - -static void -TOOLTIPS_Show (HWND hwnd, TOOLTIPS_INFO *infoPtr) -{ - TTTOOL_INFO *toolPtr; - RECT rect, wndrect; - SIZE size; - NMHDR hdr; - int ptfx = 0; - DWORD style = GetWindowLongW(hwnd, GWL_STYLE); - - if (infoPtr->nTool == -1) { - TRACE("invalid tool (-1)!\n"); - return; - } - - infoPtr->nCurrentTool = infoPtr->nTool; - - TRACE("Show tooltip pre %d! (%p)\n", infoPtr->nTool, hwnd); - - TOOLTIPS_GetTipText (hwnd, infoPtr, infoPtr->nCurrentTool); - - if (infoPtr->szTipText[0] == L'\0') { - infoPtr->nCurrentTool = -1; - return; - } - - TRACE("Show tooltip %d!\n", infoPtr->nCurrentTool); - toolPtr = &infoPtr->tools[infoPtr->nCurrentTool]; - - hdr.hwndFrom = hwnd; - hdr.idFrom = toolPtr->uId; - hdr.code = TTN_SHOW; - SendMessageW (toolPtr->hwnd, WM_NOTIFY, - (WPARAM)toolPtr->uId, (LPARAM)&hdr); - - TRACE("%s\n", debugstr_w(infoPtr->szTipText)); - - TOOLTIPS_CalcTipSize (hwnd, infoPtr, &size); - TRACE("size %ld x %ld\n", size.cx, size.cy); - - if (toolPtr->uFlags & TTF_CENTERTIP) { - RECT rc; - - if (toolPtr->uFlags & TTF_IDISHWND) - GetWindowRect ((HWND)toolPtr->uId, &rc); - else { - rc = toolPtr->rect; - MapWindowPoints (toolPtr->hwnd, NULL, (LPPOINT)&rc, 2); - } - rect.left = (rc.left + rc.right - size.cx) / 2; - if (style & TTS_BALLOON) - { - ptfx = rc.left + ((rc.right - rc.left) / 2); - if(rect.top - size.cy >= 0) - { - rect.top -= size.cy; - infoPtr->bToolBelow = FALSE; - } - else - { - infoPtr->bToolBelow = TRUE; - rect.top += 20; - } - rect.left = max(0, rect.left - BALLOON_STEMINDENT); - } - else - { - rect.top = rc.bottom + 2; - infoPtr->bToolBelow = TRUE; - } - } - else { - GetCursorPos ((LPPOINT)&rect); - if (style & TTS_BALLOON) - { - ptfx = rect.left; - if(rect.top - size.cy >= 0) - { - rect.top -= size.cy; - infoPtr->bToolBelow = FALSE; - } - else - { - infoPtr->bToolBelow = TRUE; - rect.top += 20; - } - rect.left = max(0, rect.left - BALLOON_STEMINDENT); - } - else - { - rect.top += 20; - infoPtr->bToolBelow = TRUE; - } - } - - TRACE("pos %ld - %ld\n", rect.left, rect.top); - - rect.right = rect.left + size.cx; - rect.bottom = rect.top + size.cy; - - /* check position */ - wndrect.right = GetSystemMetrics( SM_CXSCREEN ); - if( rect.right > wndrect.right ) { - rect.left -= rect.right - wndrect.right + 2; - rect.right = wndrect.right - 2; - } - wndrect.bottom = GetSystemMetrics( SM_CYSCREEN ); - if( rect.bottom > wndrect.bottom ) { - RECT rc; - - if (toolPtr->uFlags & TTF_IDISHWND) - GetWindowRect ((HWND)toolPtr->uId, &rc); - else { - rc = toolPtr->rect; - MapWindowPoints (toolPtr->hwnd, NULL, (LPPOINT)&rc, 2); - } - rect.bottom = rc.top - 2; - rect.top = rect.bottom - size.cy; - } - - AdjustWindowRectEx (&rect, GetWindowLongW (hwnd, GWL_STYLE), - FALSE, GetWindowLongW (hwnd, GWL_EXSTYLE)); - - if (style & TTS_BALLOON) - { - HRGN hRgn; - HRGN hrStem; - POINT pts[3]; - - ptfx -= rect.left; - - if(infoPtr->bToolBelow) - { - pts[0].x = ptfx; - pts[0].y = 0; - pts[1].x = max(BALLOON_STEMINDENT, ptfx - (BALLOON_STEMWIDTH / 2)); - pts[1].y = BALLOON_STEMHEIGHT; - pts[2].x = pts[1].x + BALLOON_STEMWIDTH; - pts[2].y = pts[1].y; - if(pts[2].x > (rect.right - rect.left) - BALLOON_STEMINDENT) - { - pts[2].x = (rect.right - rect.left) - BALLOON_STEMINDENT; - pts[1].x = pts[2].x - BALLOON_STEMWIDTH; - } - } - else - { - pts[0].x = max(BALLOON_STEMINDENT, ptfx - (BALLOON_STEMWIDTH / 2)); - pts[0].y = (rect.bottom - rect.top) - BALLOON_STEMHEIGHT; - pts[1].x = pts[0].x + BALLOON_STEMWIDTH; - pts[1].y = pts[0].y; - pts[2].x = ptfx; - pts[2].y = (rect.bottom - rect.top); - if(pts[1].x > (rect.right - rect.left) - BALLOON_STEMINDENT) - { - pts[1].x = (rect.right - rect.left) - BALLOON_STEMINDENT; - pts[0].x = pts[1].x - BALLOON_STEMWIDTH; - } - } - - hrStem = CreatePolygonRgn(pts, sizeof(pts) / sizeof(pts[0]), ALTERNATE); - - hRgn = CreateRoundRectRgn(0, - (infoPtr->bToolBelow ? BALLOON_STEMHEIGHT : 0), - rect.right - rect.left, - (infoPtr->bToolBelow ? rect.bottom - rect.top : rect.bottom - rect.top - BALLOON_STEMHEIGHT), - BALLOON_ROUNDEDNESS, BALLOON_ROUNDEDNESS); - - CombineRgn(hRgn, hRgn, hrStem, RGN_OR); - DeleteObject(hrStem); - - SetWindowRgn(hwnd, hRgn, FALSE); - /* we don't free the region handle as the system deletes it when - * it is no longer needed */ - } - - SetWindowPos (hwnd, HWND_TOP, rect.left, rect.top, - rect.right - rect.left, rect.bottom - rect.top, - SWP_SHOWWINDOW | SWP_NOACTIVATE); - - /* repaint the tooltip */ - InvalidateRect(hwnd, NULL, TRUE); - UpdateWindow(hwnd); - - SetTimer (hwnd, ID_TIMERPOP, infoPtr->nAutoPopTime, 0); - TRACE("timer 2 started!\n"); - SetTimer (hwnd, ID_TIMERLEAVE, infoPtr->nReshowTime, 0); - TRACE("timer 3 started!\n"); -} - - -static void -TOOLTIPS_Hide (HWND hwnd, TOOLTIPS_INFO *infoPtr) -{ - TTTOOL_INFO *toolPtr; - NMHDR hdr; - - TRACE("Hide tooltip %d! (%p)\n", infoPtr->nCurrentTool, hwnd); - - if (infoPtr->nCurrentTool == -1) - return; - - toolPtr = &infoPtr->tools[infoPtr->nCurrentTool]; - KillTimer (hwnd, ID_TIMERPOP); - - hdr.hwndFrom = hwnd; - hdr.idFrom = toolPtr->uId; - hdr.code = TTN_POP; - SendMessageW (toolPtr->hwnd, WM_NOTIFY, - (WPARAM)toolPtr->uId, (LPARAM)&hdr); - - infoPtr->nCurrentTool = -1; - - SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, - SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE); -} - - -static void -TOOLTIPS_TrackShow (HWND hwnd, TOOLTIPS_INFO *infoPtr) -{ - TTTOOL_INFO *toolPtr; - RECT rect; - SIZE size; - NMHDR hdr; - - if (infoPtr->nTrackTool == -1) { - TRACE("invalid tracking tool (-1)!\n"); - return; - } - - TRACE("show tracking tooltip pre %d!\n", infoPtr->nTrackTool); - - TOOLTIPS_GetTipText (hwnd, infoPtr, infoPtr->nTrackTool); - - if (infoPtr->szTipText[0] == L'\0') { - infoPtr->nTrackTool = -1; - return; - } - - TRACE("show tracking tooltip %d!\n", infoPtr->nTrackTool); - toolPtr = &infoPtr->tools[infoPtr->nTrackTool]; - - hdr.hwndFrom = hwnd; - hdr.idFrom = toolPtr->uId; - hdr.code = TTN_SHOW; - SendMessageW (toolPtr->hwnd, WM_NOTIFY, - (WPARAM)toolPtr->uId, (LPARAM)&hdr); - - TRACE("%s\n", debugstr_w(infoPtr->szTipText)); - - TOOLTIPS_CalcTipSize (hwnd, infoPtr, &size); - TRACE("size %ld x %ld\n", size.cx, size.cy); - - if (toolPtr->uFlags & TTF_ABSOLUTE) { - rect.left = infoPtr->xTrackPos; - rect.top = infoPtr->yTrackPos; - - if (toolPtr->uFlags & TTF_CENTERTIP) { - rect.left -= (size.cx / 2); - rect.top -= (size.cy / 2); - } - } - else { - RECT rcTool; - - if (toolPtr->uFlags & TTF_IDISHWND) - GetWindowRect ((HWND)toolPtr->uId, &rcTool); - else { - rcTool = toolPtr->rect; - MapWindowPoints (toolPtr->hwnd, NULL, (LPPOINT)&rcTool, 2); - } - - GetCursorPos ((LPPOINT)&rect); - rect.top += 20; - - if (toolPtr->uFlags & TTF_CENTERTIP) { - rect.left -= (size.cx / 2); - rect.top -= (size.cy / 2); - } - - /* smart placement */ - if ((rect.left + size.cx > rcTool.left) && (rect.left < rcTool.right) && - (rect.top + size.cy > rcTool.top) && (rect.top < rcTool.bottom)) - rect.left = rcTool.right; - } - - TRACE("pos %ld - %ld\n", rect.left, rect.top); - - rect.right = rect.left + size.cx; - rect.bottom = rect.top + size.cy; - - AdjustWindowRectEx (&rect, GetWindowLongW (hwnd, GWL_STYLE), - FALSE, GetWindowLongW (hwnd, GWL_EXSTYLE)); - - if (GetWindowLongW(hwnd, GWL_STYLE) & TTS_BALLOON) - { - HRGN hRgn; - - /* FIXME: need to add pointy bit using CreatePolyRgn & CombinRgn */ - hRgn = CreateRoundRectRgn(0, 0, rect.right - rect.left, rect.bottom - rect.top, BALLOON_ROUNDEDNESS, BALLOON_ROUNDEDNESS); - - SetWindowRgn(hwnd, hRgn, FALSE); - /* we don't free the region handle as the system deletes it when - * it is no longer needed */ - } - - SetWindowPos (hwnd, HWND_TOP, rect.left, rect.top, - rect.right - rect.left, rect.bottom - rect.top, - SWP_SHOWWINDOW | SWP_NOACTIVATE ); - - InvalidateRect(hwnd, NULL, TRUE); - UpdateWindow(hwnd); -} - - -static void -TOOLTIPS_TrackHide (HWND hwnd, TOOLTIPS_INFO *infoPtr) -{ - TTTOOL_INFO *toolPtr; - NMHDR hdr; - - TRACE("hide tracking tooltip %d\n", infoPtr->nTrackTool); - - if (infoPtr->nTrackTool == -1) - return; - - toolPtr = &infoPtr->tools[infoPtr->nTrackTool]; - - hdr.hwndFrom = hwnd; - hdr.idFrom = toolPtr->uId; - hdr.code = TTN_POP; - SendMessageW (toolPtr->hwnd, WM_NOTIFY, - (WPARAM)toolPtr->uId, (LPARAM)&hdr); - - SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, - SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE); -} - - -static INT -TOOLTIPS_GetToolFromInfoA (TOOLTIPS_INFO *infoPtr, LPTTTOOLINFOA lpToolInfo) -{ - TTTOOL_INFO *toolPtr; - INT nTool; - - for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) { - toolPtr = &infoPtr->tools[nTool]; - - if (!(toolPtr->uFlags & TTF_IDISHWND) && - (lpToolInfo->hwnd == toolPtr->hwnd) && - (lpToolInfo->uId == toolPtr->uId)) - return nTool; - } - - for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) { - toolPtr = &infoPtr->tools[nTool]; - - if ((toolPtr->uFlags & TTF_IDISHWND) && - (lpToolInfo->uId == toolPtr->uId)) - return nTool; - } - - return -1; -} - - -static INT -TOOLTIPS_GetToolFromInfoW (TOOLTIPS_INFO *infoPtr, LPTTTOOLINFOW lpToolInfo) -{ - TTTOOL_INFO *toolPtr; - INT nTool; - - for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) { - toolPtr = &infoPtr->tools[nTool]; - - if (!(toolPtr->uFlags & TTF_IDISHWND) && - (lpToolInfo->hwnd == toolPtr->hwnd) && - (lpToolInfo->uId == toolPtr->uId)) - return nTool; - } - - for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) { - toolPtr = &infoPtr->tools[nTool]; - - if ((toolPtr->uFlags & TTF_IDISHWND) && - (lpToolInfo->uId == toolPtr->uId)) - return nTool; - } - - return -1; -} - - -static INT -TOOLTIPS_GetToolFromPoint (TOOLTIPS_INFO *infoPtr, HWND hwnd, LPPOINT lpPt) -{ - TTTOOL_INFO *toolPtr; - INT nTool; - - for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) { - toolPtr = &infoPtr->tools[nTool]; - - if (!(toolPtr->uFlags & TTF_IDISHWND)) { - if (hwnd != toolPtr->hwnd) - continue; - if (!PtInRect (&toolPtr->rect, *lpPt)) - continue; - return nTool; - } - } - - for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) { - toolPtr = &infoPtr->tools[nTool]; - - if (toolPtr->uFlags & TTF_IDISHWND) { - if ((HWND)toolPtr->uId == hwnd) - return nTool; - } - } - - return -1; -} - - -static BOOL -TOOLTIPS_IsWindowActive (HWND hwnd) -{ - HWND hwndActive = GetActiveWindow (); - if (!hwndActive) - return FALSE; - if (hwndActive == hwnd) - return TRUE; - return IsChild (hwndActive, hwnd); -} - - -static INT -TOOLTIPS_CheckTool (HWND hwnd, BOOL bShowTest) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - POINT pt; - HWND hwndTool; - INT nTool; - - GetCursorPos (&pt); - hwndTool = (HWND)SendMessageW (hwnd, TTM_WINDOWFROMPOINT, 0, (LPARAM)&pt); - if (hwndTool == 0) - return -1; - - ScreenToClient (hwndTool, &pt); - nTool = TOOLTIPS_GetToolFromPoint (infoPtr, hwndTool, &pt); - if (nTool == -1) - return -1; - - if (!(GetWindowLongW (hwnd, GWL_STYLE) & TTS_ALWAYSTIP) && bShowTest) { - if (!TOOLTIPS_IsWindowActive (GetWindow (hwnd, GW_OWNER))) - return -1; - } - - TRACE("tool %d\n", nTool); - - return nTool; -} - - -static LRESULT -TOOLTIPS_Activate (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - - infoPtr->bActive = (BOOL)wParam; - - if (infoPtr->bActive) - TRACE("activate!\n"); - - if (!(infoPtr->bActive) && (infoPtr->nCurrentTool != -1)) - TOOLTIPS_Hide (hwnd, infoPtr); - - return 0; -} - - -static LRESULT -TOOLTIPS_AddToolA (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam; - TTTOOL_INFO *toolPtr; - INT nResult; - - if (lpToolInfo == NULL) - return FALSE; - if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE) - return FALSE; - - TRACE("add tool (%p) %p %d%s!\n", - hwnd, lpToolInfo->hwnd, lpToolInfo->uId, - (lpToolInfo->uFlags & TTF_IDISHWND) ? " TTF_IDISHWND" : ""); - - if (infoPtr->uNumTools == 0) { - infoPtr->tools = Alloc (sizeof(TTTOOL_INFO)); - toolPtr = infoPtr->tools; - } - else { - TTTOOL_INFO *oldTools = infoPtr->tools; - infoPtr->tools = - Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools + 1)); - memcpy (infoPtr->tools, oldTools, - infoPtr->uNumTools * sizeof(TTTOOL_INFO)); - Free (oldTools); - toolPtr = &infoPtr->tools[infoPtr->uNumTools]; - } - - infoPtr->uNumTools++; - - /* copy tool data */ - toolPtr->uFlags = lpToolInfo->uFlags; - toolPtr->hwnd = lpToolInfo->hwnd; - toolPtr->uId = lpToolInfo->uId; - toolPtr->rect = lpToolInfo->rect; - toolPtr->hinst = lpToolInfo->hinst; - - if (HIWORD(lpToolInfo->lpszText) == 0) { - TRACE("add string id %x!\n", (int)lpToolInfo->lpszText); - toolPtr->lpszText = (LPWSTR)lpToolInfo->lpszText; - } - else if (lpToolInfo->lpszText) { - if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKA) { - TRACE("add CALLBACK!\n"); - toolPtr->lpszText = LPSTR_TEXTCALLBACKW; - } - else { - INT len = MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1, - NULL, 0); - TRACE("add text \"%s\"!\n", lpToolInfo->lpszText); - toolPtr->lpszText = Alloc (len * sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1, - toolPtr->lpszText, len); - } - } - - if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA)) - toolPtr->lParam = lpToolInfo->lParam; - - /* install subclassing hook */ - if (toolPtr->uFlags & TTF_SUBCLASS) { - if (toolPtr->uFlags & TTF_IDISHWND) { - SetWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1, - (DWORD_PTR)hwnd); - } - else { - SetWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1, - (DWORD_PTR)hwnd); - } - TRACE("subclassing installed!\n"); - } - - nResult = (INT) SendMessageW (toolPtr->hwnd, WM_NOTIFYFORMAT, - (WPARAM)hwnd, (LPARAM)NF_QUERY); - if (nResult == NFR_ANSI) { - toolPtr->bNotifyUnicode = FALSE; - TRACE(" -- WM_NOTIFYFORMAT returns: NFR_ANSI\n"); - } else if (nResult == NFR_UNICODE) { - toolPtr->bNotifyUnicode = TRUE; - TRACE(" -- WM_NOTIFYFORMAT returns: NFR_UNICODE\n"); - } else { - TRACE (" -- WM_NOTIFYFORMAT returns: error!\n"); - } - - return TRUE; -} - - -static LRESULT -TOOLTIPS_AddToolW (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam; - TTTOOL_INFO *toolPtr; - INT nResult; - - if (lpToolInfo == NULL) - return FALSE; - if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE) - return FALSE; - - TRACE("add tool (%p) %p %d%s!\n", - hwnd, lpToolInfo->hwnd, lpToolInfo->uId, - (lpToolInfo->uFlags & TTF_IDISHWND) ? " TTF_IDISHWND" : ""); - - if (infoPtr->uNumTools == 0) { - infoPtr->tools = Alloc (sizeof(TTTOOL_INFO)); - toolPtr = infoPtr->tools; - } - else { - TTTOOL_INFO *oldTools = infoPtr->tools; - infoPtr->tools = - Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools + 1)); - memcpy (infoPtr->tools, oldTools, - infoPtr->uNumTools * sizeof(TTTOOL_INFO)); - Free (oldTools); - toolPtr = &infoPtr->tools[infoPtr->uNumTools]; - } - - infoPtr->uNumTools++; - - /* copy tool data */ - toolPtr->uFlags = lpToolInfo->uFlags; - toolPtr->hwnd = lpToolInfo->hwnd; - toolPtr->uId = lpToolInfo->uId; - toolPtr->rect = lpToolInfo->rect; - toolPtr->hinst = lpToolInfo->hinst; - - if (HIWORD(lpToolInfo->lpszText) == 0) { - TRACE("add string id %x!\n", (int)lpToolInfo->lpszText); - toolPtr->lpszText = (LPWSTR)lpToolInfo->lpszText; - } - else if (lpToolInfo->lpszText) { - if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKW) { - TRACE("add CALLBACK!\n"); - toolPtr->lpszText = LPSTR_TEXTCALLBACKW; - } - else { - INT len = lstrlenW (lpToolInfo->lpszText); - TRACE("add text %s!\n", - debugstr_w(lpToolInfo->lpszText)); - toolPtr->lpszText = Alloc ((len + 1)*sizeof(WCHAR)); - strcpyW (toolPtr->lpszText, lpToolInfo->lpszText); - } - } - - if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW)) - toolPtr->lParam = lpToolInfo->lParam; - - /* install subclassing hook */ - if (toolPtr->uFlags & TTF_SUBCLASS) { - if (toolPtr->uFlags & TTF_IDISHWND) { - SetWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1, - (DWORD_PTR)hwnd); - } - else { - SetWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1, - (DWORD_PTR)hwnd); - } - TRACE("subclassing installed!\n"); - } - - nResult = (INT) SendMessageW (toolPtr->hwnd, WM_NOTIFYFORMAT, - (WPARAM)hwnd, (LPARAM)NF_QUERY); - if (nResult == NFR_ANSI) { - toolPtr->bNotifyUnicode = FALSE; - TRACE(" -- WM_NOTIFYFORMAT returns: NFR_ANSI\n"); - } else if (nResult == NFR_UNICODE) { - toolPtr->bNotifyUnicode = TRUE; - TRACE(" -- WM_NOTIFYFORMAT returns: NFR_UNICODE\n"); - } else { - TRACE (" -- WM_NOTIFYFORMAT returns: error!\n"); - } - - return TRUE; -} - - -static void -TOOLTIPS_DelToolCommon (HWND hwnd, TOOLTIPS_INFO *infoPtr, INT nTool) -{ - TTTOOL_INFO *toolPtr; - - TRACE("tool %d\n", nTool); - - if (nTool == -1) - return; - - /* make sure the tooltip has disappeared before deleting it */ - TOOLTIPS_Hide(hwnd, infoPtr); - - /* delete text string */ - toolPtr = &infoPtr->tools[nTool]; - if (toolPtr->lpszText) { - if ( (toolPtr->lpszText != LPSTR_TEXTCALLBACKW) && - (HIWORD((INT)toolPtr->lpszText) != 0) ) - Free (toolPtr->lpszText); - } - - /* remove subclassing */ - if (toolPtr->uFlags & TTF_SUBCLASS) { - if (toolPtr->uFlags & TTF_IDISHWND) { - RemoveWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1); - } - else { - RemoveWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1); - } - } - - /* delete tool from tool list */ - if (infoPtr->uNumTools == 1) { - Free (infoPtr->tools); - infoPtr->tools = NULL; - } - else { - TTTOOL_INFO *oldTools = infoPtr->tools; - infoPtr->tools = - Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools - 1)); - - if (nTool > 0) - memcpy (&infoPtr->tools[0], &oldTools[0], - nTool * sizeof(TTTOOL_INFO)); - - if (nTool < infoPtr->uNumTools - 1) - memcpy (&infoPtr->tools[nTool], &oldTools[nTool + 1], - (infoPtr->uNumTools - nTool - 1) * sizeof(TTTOOL_INFO)); - - Free (oldTools); - } - - /* update any indices affected by delete */ - - /* destroying tool that mouse was on on last relayed mouse move */ - if (infoPtr->nTool == nTool) - /* -1 means no current tool (0 means first tool) */ - infoPtr->nTool = -1; - else if (infoPtr->nTool > nTool) - infoPtr->nTool--; - - if (infoPtr->nTrackTool == nTool) - /* -1 means no current tool (0 means first tool) */ - infoPtr->nTrackTool = -1; - else if (infoPtr->nTrackTool > nTool) - infoPtr->nTrackTool--; - - if (infoPtr->nCurrentTool == nTool) - /* -1 means no current tool (0 means first tool) */ - infoPtr->nCurrentTool = -1; - else if (infoPtr->nCurrentTool > nTool) - infoPtr->nCurrentTool--; - - infoPtr->uNumTools--; -} - -static LRESULT -TOOLTIPS_DelToolA (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam; - INT nTool; - - if (lpToolInfo == NULL) - return 0; - if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE) - return 0; - if (infoPtr->uNumTools == 0) - return 0; - - nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo); - - TOOLTIPS_DelToolCommon (hwnd, infoPtr, nTool); - - return 0; -} - - -static LRESULT -TOOLTIPS_DelToolW (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam; - INT nTool; - - if (lpToolInfo == NULL) - return 0; - if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE) - return 0; - if (infoPtr->uNumTools == 0) - return 0; - - nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo); - - TOOLTIPS_DelToolCommon (hwnd, infoPtr, nTool); - - return 0; -} - - -static LRESULT -TOOLTIPS_EnumToolsA (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - UINT uIndex = (UINT)wParam; - LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam; - TTTOOL_INFO *toolPtr; - - if (lpToolInfo == NULL) - return FALSE; - if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE) - return FALSE; - if (uIndex >= infoPtr->uNumTools) - return FALSE; - - TRACE("index=%u\n", uIndex); - - toolPtr = &infoPtr->tools[uIndex]; - - /* copy tool data */ - lpToolInfo->uFlags = toolPtr->uFlags; - lpToolInfo->hwnd = toolPtr->hwnd; - lpToolInfo->uId = toolPtr->uId; - lpToolInfo->rect = toolPtr->rect; - lpToolInfo->hinst = toolPtr->hinst; -/* lpToolInfo->lpszText = toolPtr->lpszText; */ - lpToolInfo->lpszText = NULL; /* FIXME */ - - if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA)) - lpToolInfo->lParam = toolPtr->lParam; - - return TRUE; -} - - -static LRESULT -TOOLTIPS_EnumToolsW (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - UINT uIndex = (UINT)wParam; - LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam; - TTTOOL_INFO *toolPtr; - - if (lpToolInfo == NULL) - return FALSE; - if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE) - return FALSE; - if (uIndex >= infoPtr->uNumTools) - return FALSE; - - TRACE("index=%u\n", uIndex); - - toolPtr = &infoPtr->tools[uIndex]; - - /* copy tool data */ - lpToolInfo->uFlags = toolPtr->uFlags; - lpToolInfo->hwnd = toolPtr->hwnd; - lpToolInfo->uId = toolPtr->uId; - lpToolInfo->rect = toolPtr->rect; - lpToolInfo->hinst = toolPtr->hinst; -/* lpToolInfo->lpszText = toolPtr->lpszText; */ - lpToolInfo->lpszText = NULL; /* FIXME */ - - if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW)) - lpToolInfo->lParam = toolPtr->lParam; - - return TRUE; -} - -static LRESULT -TOOLTIPS_GetBubbleSize (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam; - INT nTool; - SIZE size; - - if (lpToolInfo == NULL) - return FALSE; - if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE) - return FALSE; - - nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo); - if (nTool == -1) return 0; - - TRACE("tool %d\n", nTool); - - TOOLTIPS_CalcTipSize (hwnd, infoPtr, &size); - TRACE("size %ld x %ld\n", size.cx, size.cy); - - return MAKELRESULT(size.cx, size.cy); -} - -static LRESULT -TOOLTIPS_GetCurrentToolA (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam; - TTTOOL_INFO *toolPtr; - - if (lpToolInfo == NULL) - return FALSE; - if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE) - return FALSE; - - if (lpToolInfo) { - if (infoPtr->nCurrentTool > -1) { - toolPtr = &infoPtr->tools[infoPtr->nCurrentTool]; - - /* copy tool data */ - lpToolInfo->uFlags = toolPtr->uFlags; - lpToolInfo->rect = toolPtr->rect; - lpToolInfo->hinst = toolPtr->hinst; -/* lpToolInfo->lpszText = toolPtr->lpszText; */ - lpToolInfo->lpszText = NULL; /* FIXME */ - - if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA)) - lpToolInfo->lParam = toolPtr->lParam; - - return TRUE; - } - else - return FALSE; - } - else - return (infoPtr->nCurrentTool != -1); -} - - -static LRESULT -TOOLTIPS_GetCurrentToolW (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam; - TTTOOL_INFO *toolPtr; - - if (lpToolInfo == NULL) - return FALSE; - if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE) - return FALSE; - - if (lpToolInfo) { - if (infoPtr->nCurrentTool > -1) { - toolPtr = &infoPtr->tools[infoPtr->nCurrentTool]; - - /* copy tool data */ - lpToolInfo->uFlags = toolPtr->uFlags; - lpToolInfo->rect = toolPtr->rect; - lpToolInfo->hinst = toolPtr->hinst; -/* lpToolInfo->lpszText = toolPtr->lpszText; */ - lpToolInfo->lpszText = NULL; /* FIXME */ - - if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW)) - lpToolInfo->lParam = toolPtr->lParam; - - return TRUE; - } - else - return FALSE; - } - else - return (infoPtr->nCurrentTool != -1); -} - - -static LRESULT -TOOLTIPS_GetDelayTime (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - - switch (wParam) { - case TTDT_RESHOW: - return infoPtr->nReshowTime; - - case TTDT_AUTOPOP: - return infoPtr->nAutoPopTime; - - case TTDT_INITIAL: - case TTDT_AUTOMATIC: /* Apparently TTDT_AUTOMATIC returns TTDT_INITIAL */ - return infoPtr->nInitialTime; - - default: - WARN("Invalid wParam %x\n", wParam); - break; - } - - return -1; -} - - -static LRESULT -TOOLTIPS_GetMargin (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPRECT lpRect = (LPRECT)lParam; - - lpRect->left = infoPtr->rcMargin.left; - lpRect->right = infoPtr->rcMargin.right; - lpRect->bottom = infoPtr->rcMargin.bottom; - lpRect->top = infoPtr->rcMargin.top; - - return 0; -} - - -inline static LRESULT -TOOLTIPS_GetMaxTipWidth (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - - return infoPtr->nMaxTipWidth; -} - - -static LRESULT -TOOLTIPS_GetTextA (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam; - INT nTool; - - if (lpToolInfo == NULL) - return 0; - if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE) - return 0; - - nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo); - if (nTool == -1) return 0; - - /* NB this API is broken, there is no way for the app to determine - what size buffer it requires nor a way to specify how long the - one it supplies is. We'll assume it's upto INFOTIPSIZE */ - - WideCharToMultiByte(CP_ACP, 0, infoPtr->tools[nTool].lpszText, -1, - lpToolInfo->lpszText, INFOTIPSIZE, NULL, NULL); - - return 0; -} - - -static LRESULT -TOOLTIPS_GetTextW (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam; - INT nTool; - - if (lpToolInfo == NULL) - return 0; - if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE) - return 0; - - nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo); - if (nTool == -1) return 0; - - strcpyW (lpToolInfo->lpszText, infoPtr->tools[nTool].lpszText); - - return 0; -} - - -inline static LRESULT -TOOLTIPS_GetTipBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - return infoPtr->clrBk; -} - - -inline static LRESULT -TOOLTIPS_GetTipTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - return infoPtr->clrText; -} - - -inline static LRESULT -TOOLTIPS_GetToolCount (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - return infoPtr->uNumTools; -} - - -static LRESULT -TOOLTIPS_GetToolInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam; - TTTOOL_INFO *toolPtr; - INT nTool; - - if (lpToolInfo == NULL) - return FALSE; - if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE) - return FALSE; - if (infoPtr->uNumTools == 0) - return FALSE; - - nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo); - if (nTool == -1) - return FALSE; - - TRACE("tool %d\n", nTool); - - toolPtr = &infoPtr->tools[nTool]; - - /* copy tool data */ - lpToolInfo->uFlags = toolPtr->uFlags; - lpToolInfo->rect = toolPtr->rect; - lpToolInfo->hinst = toolPtr->hinst; -/* lpToolInfo->lpszText = toolPtr->lpszText; */ - lpToolInfo->lpszText = NULL; /* FIXME */ - - if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA)) - lpToolInfo->lParam = toolPtr->lParam; - - return TRUE; -} - - -static LRESULT -TOOLTIPS_GetToolInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam; - TTTOOL_INFO *toolPtr; - INT nTool; - - if (lpToolInfo == NULL) - return FALSE; - if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE) - return FALSE; - if (infoPtr->uNumTools == 0) - return FALSE; - - nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo); - if (nTool == -1) - return FALSE; - - TRACE("tool %d\n", nTool); - - toolPtr = &infoPtr->tools[nTool]; - - /* copy tool data */ - lpToolInfo->uFlags = toolPtr->uFlags; - lpToolInfo->rect = toolPtr->rect; - lpToolInfo->hinst = toolPtr->hinst; -/* lpToolInfo->lpszText = toolPtr->lpszText; */ - lpToolInfo->lpszText = NULL; /* FIXME */ - - if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW)) - lpToolInfo->lParam = toolPtr->lParam; - - return TRUE; -} - - -static LRESULT -TOOLTIPS_HitTestA (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPTTHITTESTINFOA lptthit = (LPTTHITTESTINFOA)lParam; - TTTOOL_INFO *toolPtr; - INT nTool; - - if (lptthit == 0) - return FALSE; - - nTool = TOOLTIPS_GetToolFromPoint (infoPtr, lptthit->hwnd, &lptthit->pt); - if (nTool == -1) - return FALSE; - - TRACE("tool %d!\n", nTool); - - /* copy tool data */ - if (lptthit->ti.cbSize >= sizeof(TTTOOLINFOA)) { - toolPtr = &infoPtr->tools[nTool]; - - lptthit->ti.uFlags = toolPtr->uFlags; - lptthit->ti.hwnd = toolPtr->hwnd; - lptthit->ti.uId = toolPtr->uId; - lptthit->ti.rect = toolPtr->rect; - lptthit->ti.hinst = toolPtr->hinst; -/* lptthit->ti.lpszText = toolPtr->lpszText; */ - lptthit->ti.lpszText = NULL; /* FIXME */ - lptthit->ti.lParam = toolPtr->lParam; - } - - return TRUE; -} - - -static LRESULT -TOOLTIPS_HitTestW (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPTTHITTESTINFOW lptthit = (LPTTHITTESTINFOW)lParam; - TTTOOL_INFO *toolPtr; - INT nTool; - - if (lptthit == 0) - return FALSE; - - nTool = TOOLTIPS_GetToolFromPoint (infoPtr, lptthit->hwnd, &lptthit->pt); - if (nTool == -1) - return FALSE; - - TRACE("tool %d!\n", nTool); - - /* copy tool data */ - if (lptthit->ti.cbSize >= sizeof(TTTOOLINFOW)) { - toolPtr = &infoPtr->tools[nTool]; - - lptthit->ti.uFlags = toolPtr->uFlags; - lptthit->ti.hwnd = toolPtr->hwnd; - lptthit->ti.uId = toolPtr->uId; - lptthit->ti.rect = toolPtr->rect; - lptthit->ti.hinst = toolPtr->hinst; -/* lptthit->ti.lpszText = toolPtr->lpszText; */ - lptthit->ti.lpszText = NULL; /* FIXME */ - lptthit->ti.lParam = toolPtr->lParam; - } - - return TRUE; -} - - -static LRESULT -TOOLTIPS_NewToolRectA (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPTTTOOLINFOA lpti = (LPTTTOOLINFOA)lParam; - INT nTool; - - if (lpti == NULL) - return 0; - if (lpti->cbSize < TTTOOLINFOA_V1_SIZE) - return FALSE; - - nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpti); - - TRACE("nTool = %d, rect = %s\n", nTool, wine_dbgstr_rect(&lpti->rect)); - - if (nTool == -1) return 0; - - infoPtr->tools[nTool].rect = lpti->rect; - - return 0; -} - - -static LRESULT -TOOLTIPS_NewToolRectW (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPTTTOOLINFOW lpti = (LPTTTOOLINFOW)lParam; - INT nTool; - - if (lpti == NULL) - return 0; - if (lpti->cbSize < TTTOOLINFOW_V1_SIZE) - return FALSE; - - nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpti); - - TRACE("nTool = %d, rect = %s\n", nTool, wine_dbgstr_rect(&lpti->rect)); - - if (nTool == -1) return 0; - - infoPtr->tools[nTool].rect = lpti->rect; - - return 0; -} - - -inline static LRESULT -TOOLTIPS_Pop (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - TOOLTIPS_Hide (hwnd, infoPtr); - - return 0; -} - - -static LRESULT -TOOLTIPS_RelayEvent (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPMSG lpMsg = (LPMSG)lParam; - POINT pt; - INT nOldTool; - - if (lParam == 0) { - ERR("lpMsg == NULL!\n"); - return 0; - } - - switch (lpMsg->message) { - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_MBUTTONDOWN: - case WM_MBUTTONUP: - case WM_RBUTTONDOWN: - case WM_RBUTTONUP: - TOOLTIPS_Hide (hwnd, infoPtr); - break; - - case WM_MOUSEMOVE: - pt.x = LOWORD(lpMsg->lParam); - pt.y = HIWORD(lpMsg->lParam); - nOldTool = infoPtr->nTool; - infoPtr->nTool = TOOLTIPS_GetToolFromPoint(infoPtr, lpMsg->hwnd, - &pt); - TRACE("tool (%p) %d %d %d\n", hwnd, nOldTool, - infoPtr->nTool, infoPtr->nCurrentTool); - TRACE("WM_MOUSEMOVE (%p %ld %ld)\n", hwnd, pt.x, pt.y); - - if (infoPtr->nTool != nOldTool) { - if(infoPtr->nTool == -1) { /* Moved out of all tools */ - TOOLTIPS_Hide(hwnd, infoPtr); - KillTimer(hwnd, ID_TIMERLEAVE); - } else if (nOldTool == -1) { /* Moved from outside */ - if(infoPtr->bActive) { - SetTimer(hwnd, ID_TIMERSHOW, infoPtr->nInitialTime, 0); - TRACE("timer 1 started!\n"); - } - } else { /* Moved from one to another */ - TOOLTIPS_Hide (hwnd, infoPtr); - KillTimer(hwnd, ID_TIMERLEAVE); - if(infoPtr->bActive) { - SetTimer (hwnd, ID_TIMERSHOW, infoPtr->nReshowTime, 0); - TRACE("timer 1 started!\n"); - } - } - } else if(infoPtr->nCurrentTool != -1) { /* restart autopop */ - KillTimer(hwnd, ID_TIMERPOP); - SetTimer(hwnd, ID_TIMERPOP, infoPtr->nAutoPopTime, 0); - TRACE("timer 2 restarted\n"); - } else if(infoPtr->nTool != -1 && infoPtr->bActive) { - /* previous show attempt didn't result in tooltip so try again */ - SetTimer(hwnd, ID_TIMERSHOW, infoPtr->nInitialTime, 0); - TRACE("timer 1 started!\n"); - } - break; - } - - return 0; -} - - -static LRESULT -TOOLTIPS_SetDelayTime (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - INT nTime = (INT)LOWORD(lParam); - - switch (wParam) { - case TTDT_AUTOMATIC: - if (nTime <= 0) - nTime = GetDoubleClickTime(); - infoPtr->nReshowTime = nTime / 5; - infoPtr->nAutoPopTime = nTime * 10; - infoPtr->nInitialTime = nTime; - break; - - case TTDT_RESHOW: - if(nTime < 0) - nTime = GetDoubleClickTime() / 5; - infoPtr->nReshowTime = nTime; - break; - - case TTDT_AUTOPOP: - if(nTime < 0) - nTime = GetDoubleClickTime() * 10; - infoPtr->nAutoPopTime = nTime; - break; - - case TTDT_INITIAL: - if(nTime < 0) - nTime = GetDoubleClickTime(); - infoPtr->nInitialTime = nTime; - break; - - default: - WARN("Invalid wParam %x\n", wParam); - break; - } - - return 0; -} - - -static LRESULT -TOOLTIPS_SetMargin (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPRECT lpRect = (LPRECT)lParam; - - infoPtr->rcMargin.left = lpRect->left; - infoPtr->rcMargin.right = lpRect->right; - infoPtr->rcMargin.bottom = lpRect->bottom; - infoPtr->rcMargin.top = lpRect->top; - - return 0; -} - - -inline static LRESULT -TOOLTIPS_SetMaxTipWidth (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - INT nTemp = infoPtr->nMaxTipWidth; - - infoPtr->nMaxTipWidth = (INT)lParam; - - return nTemp; -} - - -inline static LRESULT -TOOLTIPS_SetTipBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - - infoPtr->clrBk = (COLORREF)wParam; - - return 0; -} - - -inline static LRESULT -TOOLTIPS_SetTipTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - - infoPtr->clrText = (COLORREF)wParam; - - return 0; -} - - -static LRESULT -TOOLTIPS_SetTitleA (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPCSTR pszTitle = (LPCSTR)lParam; - UINT_PTR uTitleIcon = (UINT_PTR)wParam; - UINT size; - - TRACE("hwnd = %p, title = %s, icon = %p\n", hwnd, debugstr_a(pszTitle), - (void*)uTitleIcon); - - Free(infoPtr->pszTitle); - - if (pszTitle) - { - size = sizeof(WCHAR)*MultiByteToWideChar(CP_ACP, 0, pszTitle, -1, NULL, 0); - infoPtr->pszTitle = Alloc(size); - if (!infoPtr->pszTitle) - return FALSE; - MultiByteToWideChar(CP_ACP, 0, pszTitle, -1, infoPtr->pszTitle, size/sizeof(WCHAR)); - } - else - infoPtr->pszTitle = NULL; - - if (uTitleIcon <= TTI_ERROR) - infoPtr->hTitleIcon = hTooltipIcons[uTitleIcon]; - else - infoPtr->hTitleIcon = CopyIcon((HICON)wParam); - - return TRUE; -} - - -static LRESULT -TOOLTIPS_SetTitleW (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPCWSTR pszTitle = (LPCWSTR)lParam; - UINT_PTR uTitleIcon = (UINT_PTR)wParam; - UINT size; - - TRACE("hwnd = %p, title = %s, icon = %p\n", hwnd, debugstr_w(pszTitle), - (void*)uTitleIcon); - - Free(infoPtr->pszTitle); - - if (pszTitle) - { - size = (strlenW(pszTitle)+1)*sizeof(WCHAR); - infoPtr->pszTitle = Alloc(size); - if (!infoPtr->pszTitle) - return FALSE; - memcpy(infoPtr->pszTitle, pszTitle, size); - } - else - infoPtr->pszTitle = NULL; - - if (uTitleIcon <= TTI_ERROR) - infoPtr->hTitleIcon = hTooltipIcons[uTitleIcon]; - else - infoPtr->hTitleIcon = CopyIcon((HICON)wParam); - - TRACE("icon = %p\n", infoPtr->hTitleIcon); - - return TRUE; -} - - -static LRESULT -TOOLTIPS_SetToolInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam; - TTTOOL_INFO *toolPtr; - INT nTool; - - if (lpToolInfo == NULL) - return 0; - if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE) - return 0; - - nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo); - if (nTool == -1) return 0; - - TRACE("tool %d\n", nTool); - - toolPtr = &infoPtr->tools[nTool]; - - /* copy tool data */ - toolPtr->uFlags = lpToolInfo->uFlags; - toolPtr->hwnd = lpToolInfo->hwnd; - toolPtr->uId = lpToolInfo->uId; - toolPtr->rect = lpToolInfo->rect; - toolPtr->hinst = lpToolInfo->hinst; - - if (HIWORD(lpToolInfo->lpszText) == 0) { - TRACE("set string id %x!\n", (INT)lpToolInfo->lpszText); - toolPtr->lpszText = (LPWSTR)lpToolInfo->lpszText; - } - else if (lpToolInfo->lpszText) { - if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKA) - toolPtr->lpszText = LPSTR_TEXTCALLBACKW; - else { - if ( (toolPtr->lpszText) && - (HIWORD((INT)toolPtr->lpszText) != 0) ) { - Free (toolPtr->lpszText); - toolPtr->lpszText = NULL; - } - if (lpToolInfo->lpszText) { - INT len = MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, - -1, NULL, 0); - toolPtr->lpszText = Alloc (len * sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1, - toolPtr->lpszText, len); - } - } - } - - if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA)) - toolPtr->lParam = lpToolInfo->lParam; - - return 0; -} - - -static LRESULT -TOOLTIPS_SetToolInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam; - TTTOOL_INFO *toolPtr; - INT nTool; - - if (lpToolInfo == NULL) - return 0; - if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE) - return 0; - - nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo); - if (nTool == -1) return 0; - - TRACE("tool %d\n", nTool); - - toolPtr = &infoPtr->tools[nTool]; - - /* copy tool data */ - toolPtr->uFlags = lpToolInfo->uFlags; - toolPtr->hwnd = lpToolInfo->hwnd; - toolPtr->uId = lpToolInfo->uId; - toolPtr->rect = lpToolInfo->rect; - toolPtr->hinst = lpToolInfo->hinst; - - if (HIWORD(lpToolInfo->lpszText) == 0) { - TRACE("set string id %x!\n", (INT)lpToolInfo->lpszText); - toolPtr->lpszText = lpToolInfo->lpszText; - } - else { - if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKW) - toolPtr->lpszText = LPSTR_TEXTCALLBACKW; - else { - if ( (toolPtr->lpszText) && - (HIWORD((INT)toolPtr->lpszText) != 0) ) { - Free (toolPtr->lpszText); - toolPtr->lpszText = NULL; - } - if (lpToolInfo->lpszText) { - INT len = lstrlenW (lpToolInfo->lpszText); - toolPtr->lpszText = Alloc ((len+1)*sizeof(WCHAR)); - strcpyW (toolPtr->lpszText, lpToolInfo->lpszText); - } - } - } - - if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW)) - toolPtr->lParam = lpToolInfo->lParam; - - if (infoPtr->nCurrentTool == nTool) - { - TOOLTIPS_GetTipText (hwnd, infoPtr, infoPtr->nCurrentTool); - - if (infoPtr->szTipText[0] == 0) - TOOLTIPS_Hide(hwnd, infoPtr); - else - TOOLTIPS_Show (hwnd, infoPtr); - } - - return 0; -} - - -static LRESULT -TOOLTIPS_TrackActivate (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - - if ((BOOL)wParam) { - LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam; - - if (lpToolInfo == NULL) - return 0; - if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE) - return FALSE; - - /* activate */ - infoPtr->nTrackTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo); - if (infoPtr->nTrackTool != -1) { - TRACE("activated!\n"); - infoPtr->bTrackActive = TRUE; - TOOLTIPS_TrackShow (hwnd, infoPtr); - } - } - else { - /* deactivate */ - TOOLTIPS_TrackHide (hwnd, infoPtr); - - infoPtr->bTrackActive = FALSE; - infoPtr->nTrackTool = -1; - - TRACE("deactivated!\n"); - } - - return 0; -} - - -static LRESULT -TOOLTIPS_TrackPosition (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - - infoPtr->xTrackPos = (INT)LOWORD(lParam); - infoPtr->yTrackPos = (INT)HIWORD(lParam); - - if (infoPtr->bTrackActive) { - TRACE("[%d %d]\n", - infoPtr->xTrackPos, infoPtr->yTrackPos); - - TOOLTIPS_TrackShow (hwnd, infoPtr); - } - - return 0; -} - - -static LRESULT -TOOLTIPS_Update (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - - if (infoPtr->nCurrentTool != -1) - UpdateWindow (hwnd); - - return 0; -} - - -static LRESULT -TOOLTIPS_UpdateTipTextA (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam; - TTTOOL_INFO *toolPtr; - INT nTool; - - if (lpToolInfo == NULL) - return 0; - if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE) - return FALSE; - - nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo); - if (nTool == -1) return 0; - - TRACE("tool %d\n", nTool); - - toolPtr = &infoPtr->tools[nTool]; - - /* copy tool text */ - toolPtr->hinst = lpToolInfo->hinst; - - if (HIWORD(lpToolInfo->lpszText) == 0){ - toolPtr->lpszText = (LPWSTR)lpToolInfo->lpszText; - } - else if (lpToolInfo->lpszText) { - if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKA) - toolPtr->lpszText = LPSTR_TEXTCALLBACKW; - else { - if ( (toolPtr->lpszText) && - (HIWORD((INT)toolPtr->lpszText) != 0) ) { - Free (toolPtr->lpszText); - toolPtr->lpszText = NULL; - } - if (lpToolInfo->lpszText) { - INT len = MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, - -1, NULL, 0); - toolPtr->lpszText = Alloc (len * sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1, - toolPtr->lpszText, len); - } - } - } - - if(infoPtr->nCurrentTool == -1) return 0; - /* force repaint */ - if (infoPtr->bActive) - TOOLTIPS_Show (hwnd, infoPtr); - else if (infoPtr->bTrackActive) - TOOLTIPS_TrackShow (hwnd, infoPtr); - - return 0; -} - - -static LRESULT -TOOLTIPS_UpdateTipTextW (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam; - TTTOOL_INFO *toolPtr; - INT nTool; - - if (lpToolInfo == NULL) - return 0; - if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE) - return FALSE; - - nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo); - if (nTool == -1) - return 0; - - TRACE("tool %d\n", nTool); - - toolPtr = &infoPtr->tools[nTool]; - - /* copy tool text */ - toolPtr->hinst = lpToolInfo->hinst; - - if (HIWORD(lpToolInfo->lpszText) == 0){ - toolPtr->lpszText = lpToolInfo->lpszText; - } - else if (lpToolInfo->lpszText) { - if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKW) - toolPtr->lpszText = LPSTR_TEXTCALLBACKW; - else { - if ( (toolPtr->lpszText) && - (HIWORD((INT)toolPtr->lpszText) != 0) ) { - Free (toolPtr->lpszText); - toolPtr->lpszText = NULL; - } - if (lpToolInfo->lpszText) { - INT len = lstrlenW (lpToolInfo->lpszText); - toolPtr->lpszText = Alloc ((len+1)*sizeof(WCHAR)); - strcpyW (toolPtr->lpszText, lpToolInfo->lpszText); - } - } - } - - if(infoPtr->nCurrentTool == -1) return 0; - /* force repaint */ - if (infoPtr->bActive) - TOOLTIPS_Show (hwnd, infoPtr); - else if (infoPtr->bTrackActive) - TOOLTIPS_TrackShow (hwnd, infoPtr); - - return 0; -} - - -static LRESULT -TOOLTIPS_WindowFromPoint (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - return (LRESULT)WindowFromPoint (*((LPPOINT)lParam)); -} - - - -static LRESULT -TOOLTIPS_Create (HWND hwnd, const CREATESTRUCTW *lpcs) -{ - TOOLTIPS_INFO *infoPtr; - - /* allocate memory for info structure */ - infoPtr = (TOOLTIPS_INFO *)Alloc (sizeof(TOOLTIPS_INFO)); - SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); - - /* initialize info structure */ - infoPtr->bActive = TRUE; - infoPtr->bTrackActive = FALSE; - - infoPtr->nMaxTipWidth = -1; - infoPtr->nTool = -1; - infoPtr->nCurrentTool = -1; - infoPtr->nTrackTool = -1; - - /* initialize colours and fonts */ - TOOLTIPS_InitSystemSettings(infoPtr); - - TOOLTIPS_SetDelayTime(hwnd, TTDT_AUTOMATIC, 0L); - - SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE); - - return 0; -} - - -static LRESULT -TOOLTIPS_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - TTTOOL_INFO *toolPtr; - UINT i; - - /* free tools */ - if (infoPtr->tools) { - for (i = 0; i < infoPtr->uNumTools; i++) { - toolPtr = &infoPtr->tools[i]; - if (toolPtr->lpszText) { - if ( (toolPtr->lpszText != LPSTR_TEXTCALLBACKW) && - (HIWORD((INT)toolPtr->lpszText) != 0) ) - { - Free (toolPtr->lpszText); - toolPtr->lpszText = NULL; - } - } - - /* remove subclassing */ - if (toolPtr->uFlags & TTF_SUBCLASS) { - if (toolPtr->uFlags & TTF_IDISHWND) { - RemoveWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1); - } - else { - RemoveWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1); - } - } - } - Free (infoPtr->tools); - } - - /* free title string */ - Free (infoPtr->pszTitle); - /* free title icon if not a standard one */ - if (TOOLTIPS_GetTitleIconIndex(infoPtr->hTitleIcon) > TTI_ERROR) - DeleteObject(infoPtr->hTitleIcon); - - /* delete fonts */ - DeleteObject (infoPtr->hFont); - DeleteObject (infoPtr->hTitleFont); - - /* free tool tips info data */ - Free (infoPtr); - SetWindowLongPtrW(hwnd, 0, 0); - return 0; -} - - -static LRESULT -TOOLTIPS_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - - return (LRESULT)infoPtr->hFont; -} - - -static LRESULT -TOOLTIPS_MouseMessage (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - - TOOLTIPS_Hide (hwnd, infoPtr); - - return 0; -} - - -static LRESULT -TOOLTIPS_NCCreate (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE); - DWORD dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE); - - dwStyle &= 0x0000FFFF; - dwStyle |= (WS_POPUP | WS_BORDER | WS_CLIPSIBLINGS); - - /* WS_BORDER only draws a border round the window rect, not the - * window region, therefore it is useless to us in balloon mode */ - if (dwStyle & TTS_BALLOON) dwStyle &= ~WS_BORDER; - - SetWindowLongW (hwnd, GWL_STYLE, dwStyle); - - dwExStyle |= WS_EX_TOOLWINDOW; - SetWindowLongW (hwnd, GWL_EXSTYLE, dwExStyle); - - return TRUE; -} - - -static LRESULT -TOOLTIPS_NCHitTest (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - INT nTool = (infoPtr->bTrackActive) ? infoPtr->nTrackTool : infoPtr->nTool; - - TRACE(" nTool=%d\n", nTool); - - if ((nTool > -1) && (nTool < infoPtr->uNumTools)) { - if (infoPtr->tools[nTool].uFlags & TTF_TRANSPARENT) { - TRACE("-- in transparent mode!\n"); - return HTTRANSPARENT; - } - } - - return DefWindowProcW (hwnd, WM_NCHITTEST, wParam, lParam); -} - - -static LRESULT -TOOLTIPS_NotifyFormat (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - FIXME ("hwnd=%p wParam=%x lParam=%lx\n", hwnd, wParam, lParam); - - return 0; -} - - -static LRESULT -TOOLTIPS_Paint (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - HDC hdc; - PAINTSTRUCT ps; - - hdc = (wParam == 0) ? BeginPaint (hwnd, &ps) : (HDC)wParam; - TOOLTIPS_Refresh (hwnd, hdc); - if (!wParam) - EndPaint (hwnd, &ps); - return 0; -} - - -static LRESULT -TOOLTIPS_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LOGFONTW lf; - - if(!GetObjectW((HFONT)wParam, sizeof(lf), &lf)) - return 0; - - DeleteObject (infoPtr->hFont); - infoPtr->hFont = CreateFontIndirectW(&lf); - - DeleteObject (infoPtr->hTitleFont); - lf.lfWeight = FW_BOLD; - infoPtr->hTitleFont = CreateFontIndirectW(&lf); - - if ((LOWORD(lParam)) & (infoPtr->nCurrentTool != -1)) { - FIXME("full redraw needed!\n"); - } - - return 0; -} - -/****************************************************************** - * TOOLTIPS_GetTextLength - * - * This function is called when the tooltip receive a - * WM_GETTEXTLENGTH message. - * wParam : not used - * lParam : not used - * - * returns the length, in characters, of the tip text - */ -static LRESULT -TOOLTIPS_GetTextLength(HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - return strlenW(infoPtr->szTipText); -} - -/****************************************************************** - * TOOLTIPS_OnWMGetText - * - * This function is called when the tooltip receive a - * WM_GETTEXT message. - * wParam : specifies the maximum number of characters to be copied - * lParam : is the pointer to the buffer that will receive - * the tip text - * - * returns the number of characters copied - */ -static LRESULT -TOOLTIPS_OnWMGetText (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - LRESULT res; - LPWSTR pszText = (LPWSTR)lParam; - - if(!infoPtr->szTipText || !wParam) - return 0; - - res = min(strlenW(infoPtr->szTipText)+1, wParam); - memcpy(pszText, infoPtr->szTipText, res*sizeof(WCHAR)); - pszText[res-1] = '\0'; - return res-1; -} - -static LRESULT -TOOLTIPS_Timer (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - INT nOldTool; - - TRACE("timer %d (%p) expired!\n", wParam, hwnd); - - switch (wParam) { - case ID_TIMERSHOW: - KillTimer (hwnd, ID_TIMERSHOW); - nOldTool = infoPtr->nTool; - if ((infoPtr->nTool = TOOLTIPS_CheckTool (hwnd, TRUE)) == nOldTool) - TOOLTIPS_Show (hwnd, infoPtr); - break; - - case ID_TIMERPOP: - TOOLTIPS_Hide (hwnd, infoPtr); - break; - - case ID_TIMERLEAVE: - nOldTool = infoPtr->nTool; - infoPtr->nTool = TOOLTIPS_CheckTool (hwnd, FALSE); - TRACE("tool (%p) %d %d %d\n", hwnd, nOldTool, - infoPtr->nTool, infoPtr->nCurrentTool); - if (infoPtr->nTool != nOldTool) { - if(infoPtr->nTool == -1) { /* Moved out of all tools */ - TOOLTIPS_Hide(hwnd, infoPtr); - KillTimer(hwnd, ID_TIMERLEAVE); - } else if (nOldTool == -1) { /* Moved from outside */ - ERR("How did this happen?\n"); - } else { /* Moved from one to another */ - TOOLTIPS_Hide (hwnd, infoPtr); - KillTimer(hwnd, ID_TIMERLEAVE); - if(infoPtr->bActive) { - SetTimer (hwnd, ID_TIMERSHOW, infoPtr->nReshowTime, 0); - TRACE("timer 1 started!\n"); - } - } - } - break; - - default: - ERR("Unknown timer id %d\n", wParam); - break; - } - return 0; -} - - -static LRESULT -TOOLTIPS_WinIniChange (HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); - - TOOLTIPS_InitSystemSettings (infoPtr); - - return 0; -} - - -static LRESULT CALLBACK -TOOLTIPS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uID, DWORD_PTR dwRef) -{ - MSG msg; - - switch(uMsg) { - case WM_MOUSEMOVE: - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_MBUTTONDOWN: - case WM_MBUTTONUP: - case WM_RBUTTONDOWN: - case WM_RBUTTONUP: - msg.hwnd = hwnd; - msg.message = uMsg; - msg.wParam = wParam; - msg.lParam = lParam; - TOOLTIPS_RelayEvent((HWND)dwRef, 0, (LPARAM)&msg); - break; - - default: - break; - } - return DefSubclassProc(hwnd, uMsg, wParam, lParam); -} - - -static LRESULT CALLBACK -TOOLTIPS_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - TRACE("hwnd=%p msg=%x wparam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam); - if (!TOOLTIPS_GetInfoPtr(hwnd) && (uMsg != WM_CREATE) && (uMsg != WM_NCCREATE)) - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - switch (uMsg) - { - case TTM_ACTIVATE: - return TOOLTIPS_Activate (hwnd, wParam, lParam); - - case TTM_ADDTOOLA: - return TOOLTIPS_AddToolA (hwnd, wParam, lParam); - - case TTM_ADDTOOLW: - return TOOLTIPS_AddToolW (hwnd, wParam, lParam); - - case TTM_DELTOOLA: - return TOOLTIPS_DelToolA (hwnd, wParam, lParam); - - case TTM_DELTOOLW: - return TOOLTIPS_DelToolW (hwnd, wParam, lParam); - - case TTM_ENUMTOOLSA: - return TOOLTIPS_EnumToolsA (hwnd, wParam, lParam); - - case TTM_ENUMTOOLSW: - return TOOLTIPS_EnumToolsW (hwnd, wParam, lParam); - - case TTM_GETBUBBLESIZE: - return TOOLTIPS_GetBubbleSize (hwnd, wParam, lParam); - - case TTM_GETCURRENTTOOLA: - return TOOLTIPS_GetCurrentToolA (hwnd, wParam, lParam); - - case TTM_GETCURRENTTOOLW: - return TOOLTIPS_GetCurrentToolW (hwnd, wParam, lParam); - - case TTM_GETDELAYTIME: - return TOOLTIPS_GetDelayTime (hwnd, wParam, lParam); - - case TTM_GETMARGIN: - return TOOLTIPS_GetMargin (hwnd, wParam, lParam); - - case TTM_GETMAXTIPWIDTH: - return TOOLTIPS_GetMaxTipWidth (hwnd, wParam, lParam); - - case TTM_GETTEXTA: - return TOOLTIPS_GetTextA (hwnd, wParam, lParam); - - case TTM_GETTEXTW: - return TOOLTIPS_GetTextW (hwnd, wParam, lParam); - - case TTM_GETTIPBKCOLOR: - return TOOLTIPS_GetTipBkColor (hwnd, wParam, lParam); - - case TTM_GETTIPTEXTCOLOR: - return TOOLTIPS_GetTipTextColor (hwnd, wParam, lParam); - - case TTM_GETTOOLCOUNT: - return TOOLTIPS_GetToolCount (hwnd, wParam, lParam); - - case TTM_GETTOOLINFOA: - return TOOLTIPS_GetToolInfoA (hwnd, wParam, lParam); - - case TTM_GETTOOLINFOW: - return TOOLTIPS_GetToolInfoW (hwnd, wParam, lParam); - - case TTM_HITTESTA: - return TOOLTIPS_HitTestA (hwnd, wParam, lParam); - - case TTM_HITTESTW: - return TOOLTIPS_HitTestW (hwnd, wParam, lParam); - - case TTM_NEWTOOLRECTA: - return TOOLTIPS_NewToolRectA (hwnd, wParam, lParam); - - case TTM_NEWTOOLRECTW: - return TOOLTIPS_NewToolRectW (hwnd, wParam, lParam); - - case TTM_POP: - return TOOLTIPS_Pop (hwnd, wParam, lParam); - - case TTM_RELAYEVENT: - return TOOLTIPS_RelayEvent (hwnd, wParam, lParam); - - case TTM_SETDELAYTIME: - return TOOLTIPS_SetDelayTime (hwnd, wParam, lParam); - - case TTM_SETMARGIN: - return TOOLTIPS_SetMargin (hwnd, wParam, lParam); - - case TTM_SETMAXTIPWIDTH: - return TOOLTIPS_SetMaxTipWidth (hwnd, wParam, lParam); - - case TTM_SETTIPBKCOLOR: - return TOOLTIPS_SetTipBkColor (hwnd, wParam, lParam); - - case TTM_SETTIPTEXTCOLOR: - return TOOLTIPS_SetTipTextColor (hwnd, wParam, lParam); - - case TTM_SETTITLEA: - return TOOLTIPS_SetTitleA (hwnd, wParam, lParam); - - case TTM_SETTITLEW: - return TOOLTIPS_SetTitleW (hwnd, wParam, lParam); - - case TTM_SETTOOLINFOA: - return TOOLTIPS_SetToolInfoA (hwnd, wParam, lParam); - - case TTM_SETTOOLINFOW: - return TOOLTIPS_SetToolInfoW (hwnd, wParam, lParam); - - case TTM_TRACKACTIVATE: - return TOOLTIPS_TrackActivate (hwnd, wParam, lParam); - - case TTM_TRACKPOSITION: - return TOOLTIPS_TrackPosition (hwnd, wParam, lParam); - - case TTM_UPDATE: - return TOOLTIPS_Update (hwnd, wParam, lParam); - - case TTM_UPDATETIPTEXTA: - return TOOLTIPS_UpdateTipTextA (hwnd, wParam, lParam); - - case TTM_UPDATETIPTEXTW: - return TOOLTIPS_UpdateTipTextW (hwnd, wParam, lParam); - - case TTM_WINDOWFROMPOINT: - return TOOLTIPS_WindowFromPoint (hwnd, wParam, lParam); - - - case WM_CREATE: - return TOOLTIPS_Create (hwnd, (LPCREATESTRUCTW)lParam); - - case WM_DESTROY: - return TOOLTIPS_Destroy (hwnd, wParam, lParam); - - case WM_ERASEBKGND: - /* we draw the background in WM_PAINT */ - return 0; - - case WM_GETFONT: - return TOOLTIPS_GetFont (hwnd, wParam, lParam); - - case WM_GETTEXT: - return TOOLTIPS_OnWMGetText (hwnd, wParam, lParam); - - case WM_GETTEXTLENGTH: - return TOOLTIPS_GetTextLength (hwnd, wParam, lParam); - - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_MBUTTONDOWN: - case WM_MBUTTONUP: - case WM_RBUTTONDOWN: - case WM_RBUTTONUP: - case WM_MOUSEMOVE: - return TOOLTIPS_MouseMessage (hwnd, uMsg, wParam, lParam); - - case WM_NCCREATE: - return TOOLTIPS_NCCreate (hwnd, wParam, lParam); - - case WM_NCHITTEST: - return TOOLTIPS_NCHitTest (hwnd, wParam, lParam); - - case WM_NOTIFYFORMAT: - return TOOLTIPS_NotifyFormat (hwnd, wParam, lParam); - - case WM_PAINT: - return TOOLTIPS_Paint (hwnd, wParam, lParam); - - case WM_SETFONT: - return TOOLTIPS_SetFont (hwnd, wParam, lParam); - - case WM_TIMER: - return TOOLTIPS_Timer (hwnd, wParam, lParam); - - case WM_WININICHANGE: - return TOOLTIPS_WinIniChange (hwnd, wParam, lParam); - - default: - if ((uMsg >= WM_USER) && (uMsg < WM_APP)) - ERR("unknown msg %04x wp=%08x lp=%08lx\n", - uMsg, wParam, lParam); - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - } -} - - -VOID -TOOLTIPS_Register (void) -{ - WNDCLASSW wndClass; - - ZeroMemory (&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS; - wndClass.lpfnWndProc = TOOLTIPS_WindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(TOOLTIPS_INFO *); - wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); - wndClass.hbrBackground = 0; - wndClass.lpszClassName = TOOLTIPS_CLASSW; - - RegisterClassW (&wndClass); - - hTooltipIcons[TTI_NONE] = NULL; - hTooltipIcons[TTI_INFO] = LoadImageW(COMCTL32_hModule, - (LPCWSTR)MAKEINTRESOURCE(IDI_TT_INFO_SM), IMAGE_ICON, 0, 0, 0); - hTooltipIcons[TTI_WARNING] = LoadImageW(COMCTL32_hModule, - (LPCWSTR)MAKEINTRESOURCE(IDI_TT_WARN_SM), IMAGE_ICON, 0, 0, 0); - hTooltipIcons[TTI_ERROR] = LoadImageW(COMCTL32_hModule, - (LPCWSTR)MAKEINTRESOURCE(IDI_TT_ERROR_SM), IMAGE_ICON, 0, 0, 0); -} - - -VOID -TOOLTIPS_Unregister (void) -{ - int i; - for (i = TTI_INFO; i <= TTI_ERROR; i++) - DestroyIcon(hTooltipIcons[i]); - UnregisterClassW (TOOLTIPS_CLASSW, NULL); -} +/* + * Tool tip control + * + * Copyright 1998, 1999 Eric Kohl + * Copyright 2004 Robert Shearman + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES + * + * This code was audited for completeness against the documented features + * of Comctl32.dll version 6.0 on Sep. 08, 2004, by Robert Shearman. + * + * Unless otherwise noted, we believe this code to be complete, as per + * the specification mentioned above. + * If you discover missing features or bugs please note them below. + * + * TODO: + * - Custom draw support. + * - Animation. + * - Links. + * - Messages: + * o TTM_ADJUSTRECT + * o TTM_GETTITLEA + * o TTM_GETTTILEW + * o TTM_POPUP + * - Styles: + * o TTS_NOANIMATE + * o TTS_NOFADE + * o TTS_CLOSE + * + * Testing: + * - Run tests using Waite Group Windows95 API Bible Volume 2. + * The second cdrom (chapter 3) contains executables activate.exe, + * curtool.exe, deltool.exe, enumtools.exe, getinfo.exe, getiptxt.exe, + * hittest.exe, needtext.exe, newrect.exe, updtext.exe and winfrpt.exe. + * + * Timer logic. + * + * One important point to remember is that tools don't necessarily get + * a WM_MOUSEMOVE once the cursor leaves the tool, an example is when + * a tool sets TTF_IDISHWND (i.e. an entire window is a tool) because + * here WM_MOUSEMOVEs only get sent when the cursor is inside the + * client area. Therefore the only reliable way to know that the + * cursor has left a tool is to keep a timer running and check the + * position every time it expires. This is the role of timer + * ID_TIMERLEAVE. + * + * + * On entering a tool (detected in a relayed WM_MOUSEMOVE) we start + * ID_TIMERSHOW, if this times out and we're still in the tool we show + * the tip. On showing a tip we start both ID_TIMERPOP and + * ID_TIMERLEAVE. On hiding a tooltip we kill ID_TIMERPOP. + * ID_TIMERPOP is restarted on every relayed WM_MOUSEMOVE. If + * ID_TIMERPOP expires the tool is hidden and ID_TIMERPOP is killed. + * ID_TIMERLEAVE remains running - this is important as we need to + * determine when the cursor leaves the tool. + * + * When ID_TIMERLEAVE expires or on a relayed WM_MOUSEMOVE if we're + * still in the tool do nothing (apart from restart ID_TIMERPOP if + * this is a WM_MOUSEMOVE) (ID_TIMERLEAVE remains running). If we've + * left the tool and entered another one then hide the tip and start + * ID_TIMERSHOW with time ReshowTime and kill ID_TIMERLEAVE. If we're + * outside all tools hide the tip and kill ID_TIMERLEAVE. On Relayed + * mouse button messages hide the tip but leave ID_TIMERLEAVE running, + * this again will let us keep track of when the cursor leaves the + * tool. + * + * + * infoPtr->nTool is the tool the mouse was on on the last relayed MM + * or timer expiry or -1 if the mouse was not on a tool. + * + * infoPtr->nCurrentTool is the tool for which the tip is currently + * displaying text for or -1 if the tip is not shown. Actually this + * will only ever be infoPtr-nTool or -1, so it could be changed to a + * BOOL. + * + */ + + + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wine/unicode.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "comctl32.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(tooltips); + +static HICON hTooltipIcons[TTI_ERROR+1]; + +typedef struct +{ + UINT uFlags; + HWND hwnd; + BOOL bNotifyUnicode; + UINT uId; + RECT rect; + HINSTANCE hinst; + LPWSTR lpszText; + LPARAM lParam; +} TTTOOL_INFO; + + +typedef struct +{ + WCHAR szTipText[INFOTIPSIZE]; + BOOL bActive; + BOOL bTrackActive; + UINT uNumTools; + COLORREF clrBk; + COLORREF clrText; + HFONT hFont; + HFONT hTitleFont; + INT xTrackPos; + INT yTrackPos; + INT nMaxTipWidth; + INT nTool; /* tool that mouse was on on last relayed mouse move */ + INT nCurrentTool; + INT nTrackTool; + INT nReshowTime; + INT nAutoPopTime; + INT nInitialTime; + RECT rcMargin; + BOOL bToolBelow; + LPWSTR pszTitle; + HICON hTitleIcon; + + TTTOOL_INFO *tools; +} TOOLTIPS_INFO; + +#define ID_TIMERSHOW 1 /* show delay timer */ +#define ID_TIMERPOP 2 /* auto pop timer */ +#define ID_TIMERLEAVE 3 /* tool leave timer */ + + +#define TOOLTIPS_GetInfoPtr(hWindow) ((TOOLTIPS_INFO *)GetWindowLongPtrW (hWindow, 0)) + +/* offsets from window edge to start of text */ +#define NORMAL_TEXT_MARGIN 2 +#define BALLOON_TEXT_MARGIN (NORMAL_TEXT_MARGIN+8) +/* value used for CreateRoundRectRgn that specifies how much + * each corner is curved */ +#define BALLOON_ROUNDEDNESS 20 +#define BALLOON_STEMHEIGHT 13 +#define BALLOON_STEMWIDTH 10 +#define BALLOON_STEMINDENT 20 + +#define BALLOON_ICON_TITLE_SPACING 8 /* horizontal spacing between icon and title */ +#define BALLOON_TITLE_TEXT_SPACING 8 /* vertical spacing between icon/title and main text */ +#define ICON_HEIGHT 16 +#define ICON_WIDTH 16 + +static LRESULT CALLBACK +TOOLTIPS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uId, DWORD_PTR dwRef); + + +inline static UINT_PTR +TOOLTIPS_GetTitleIconIndex(HICON hIcon) +{ + UINT i; + for (i = 0; i <= TTI_ERROR; i++) + if (hTooltipIcons[i] == hIcon) + return i; + return (UINT_PTR)hIcon; +} + +static void +TOOLTIPS_InitSystemSettings (TOOLTIPS_INFO *infoPtr) +{ + NONCLIENTMETRICSW nclm; + + infoPtr->clrBk = GetSysColor (COLOR_INFOBK); + infoPtr->clrText = GetSysColor (COLOR_INFOTEXT); + + DeleteObject (infoPtr->hFont); + nclm.cbSize = sizeof(nclm); + SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, sizeof(nclm), &nclm, 0); + infoPtr->hFont = CreateFontIndirectW (&nclm.lfStatusFont); + + DeleteObject (infoPtr->hTitleFont); + nclm.lfStatusFont.lfWeight = FW_BOLD; + infoPtr->hTitleFont = CreateFontIndirectW (&nclm.lfStatusFont); +} + +static void +TOOLTIPS_Refresh (HWND hwnd, HDC hdc) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr(hwnd); + RECT rc; + INT oldBkMode; + HFONT hOldFont; + HBRUSH hBrush; + UINT uFlags = DT_EXTERNALLEADING; + HRGN hRgn = NULL; + DWORD dwStyle = GetWindowLongW(hwnd, GWL_STYLE); + + if (infoPtr->nMaxTipWidth > -1) + uFlags |= DT_WORDBREAK; + if (GetWindowLongW (hwnd, GWL_STYLE) & TTS_NOPREFIX) + uFlags |= DT_NOPREFIX; + GetClientRect (hwnd, &rc); + + hBrush = CreateSolidBrush(infoPtr->clrBk); + + oldBkMode = SetBkMode (hdc, TRANSPARENT); + SetTextColor (hdc, infoPtr->clrText); + + if (dwStyle & TTS_BALLOON) + { + /* create a region to store result into */ + hRgn = CreateRectRgn(0, 0, 0, 0); + + GetWindowRgn(hwnd, hRgn); + + /* fill the background */ + FillRgn(hdc, hRgn, hBrush); + DeleteObject(hBrush); + hBrush = NULL; + } + else + { + /* fill the background */ + FillRect(hdc, &rc, hBrush); + DeleteObject(hBrush); + hBrush = NULL; + } + + if ((dwStyle & TTS_BALLOON) || infoPtr->pszTitle) + { + /* calculate text rectangle */ + rc.left += (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.left); + rc.top += (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.top); + rc.right -= (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.right); + rc.bottom -= (BALLOON_TEXT_MARGIN + infoPtr->rcMargin.bottom); + if(infoPtr->bToolBelow) rc.top += BALLOON_STEMHEIGHT; + + if (infoPtr->pszTitle) + { + RECT rcTitle = {rc.left, rc.top, rc.right, rc.bottom}; + int height; + BOOL icon_present; + + /* draw icon */ + icon_present = infoPtr->hTitleIcon && + DrawIconEx(hdc, rc.left, rc.top, infoPtr->hTitleIcon, + ICON_WIDTH, ICON_HEIGHT, 0, NULL, DI_NORMAL); + if (icon_present) + rcTitle.left += ICON_WIDTH + BALLOON_ICON_TITLE_SPACING; + + rcTitle.bottom = rc.top + ICON_HEIGHT; + + /* draw title text */ + hOldFont = SelectObject (hdc, infoPtr->hTitleFont); + height = DrawTextW(hdc, infoPtr->pszTitle, -1, &rcTitle, DT_BOTTOM | DT_SINGLELINE | DT_NOPREFIX); + SelectObject (hdc, hOldFont); + rc.top += height + BALLOON_TITLE_TEXT_SPACING; + } + } + else + { + /* calculate text rectangle */ + rc.left += (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.left); + rc.top += (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.top); + rc.right -= (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.right); + rc.bottom -= (NORMAL_TEXT_MARGIN + infoPtr->rcMargin.bottom); + } + + /* draw text */ + hOldFont = SelectObject (hdc, infoPtr->hFont); + DrawTextW (hdc, infoPtr->szTipText, -1, &rc, uFlags); + /* be polite and reset the things we changed in the dc */ + SelectObject (hdc, hOldFont); + SetBkMode (hdc, oldBkMode); + + if (dwStyle & TTS_BALLOON) + { + /* frame region because default window proc doesn't do it */ + INT width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE); + INT height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE); + + hBrush = GetSysColorBrush(COLOR_WINDOWFRAME); + FrameRgn(hdc, hRgn, hBrush, width, height); + } + + if (hRgn) + DeleteObject(hRgn); +} + +static void TOOLTIPS_GetDispInfoA(HWND hwnd, TOOLTIPS_INFO *infoPtr, TTTOOL_INFO *toolPtr) +{ + NMTTDISPINFOA ttnmdi; + + /* fill NMHDR struct */ + ZeroMemory (&ttnmdi, sizeof(NMTTDISPINFOA)); + ttnmdi.hdr.hwndFrom = hwnd; + ttnmdi.hdr.idFrom = toolPtr->uId; + ttnmdi.hdr.code = TTN_GETDISPINFOA; + ttnmdi.lpszText = (LPSTR)&ttnmdi.szText; + ttnmdi.uFlags = toolPtr->uFlags; + ttnmdi.lParam = toolPtr->lParam; + + TRACE("hdr.idFrom = %x\n", ttnmdi.hdr.idFrom); + SendMessageW(toolPtr->hwnd, WM_NOTIFY, + (WPARAM)toolPtr->uId, (LPARAM)&ttnmdi); + + if (HIWORD((UINT)ttnmdi.lpszText) == 0) { + LoadStringW(ttnmdi.hinst, (UINT)ttnmdi.lpszText, + infoPtr->szTipText, INFOTIPSIZE); + if (ttnmdi.uFlags & TTF_DI_SETITEM) { + toolPtr->hinst = ttnmdi.hinst; + toolPtr->lpszText = (LPWSTR)ttnmdi.lpszText; + } + } + else if (ttnmdi.lpszText == 0) { + /* no text available */ + infoPtr->szTipText[0] = '\0'; + } + else if (ttnmdi.lpszText != LPSTR_TEXTCALLBACKA) { + INT max_len = (ttnmdi.lpszText == &ttnmdi.szText[0]) ? + sizeof(ttnmdi.szText)/sizeof(ttnmdi.szText[0]) : -1; + MultiByteToWideChar(CP_ACP, 0, ttnmdi.lpszText, max_len, + infoPtr->szTipText, INFOTIPSIZE); + if (ttnmdi.uFlags & TTF_DI_SETITEM) { + INT len = MultiByteToWideChar(CP_ACP, 0, ttnmdi.lpszText, + max_len, NULL, 0); + toolPtr->hinst = 0; + toolPtr->lpszText = Alloc (len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, ttnmdi.lpszText, -1, + toolPtr->lpszText, len); + } + } + else { + ERR("recursive text callback!\n"); + infoPtr->szTipText[0] = '\0'; + } +} + +static void TOOLTIPS_GetDispInfoW(HWND hwnd, TOOLTIPS_INFO *infoPtr, TTTOOL_INFO *toolPtr) +{ + NMTTDISPINFOW ttnmdi; + + /* fill NMHDR struct */ + ZeroMemory (&ttnmdi, sizeof(NMTTDISPINFOW)); + ttnmdi.hdr.hwndFrom = hwnd; + ttnmdi.hdr.idFrom = toolPtr->uId; + ttnmdi.hdr.code = TTN_GETDISPINFOW; + ttnmdi.lpszText = (LPWSTR)&ttnmdi.szText; + ttnmdi.uFlags = toolPtr->uFlags; + ttnmdi.lParam = toolPtr->lParam; + + TRACE("hdr.idFrom = %x\n", ttnmdi.hdr.idFrom); + SendMessageW(toolPtr->hwnd, WM_NOTIFY, + (WPARAM)toolPtr->uId, (LPARAM)&ttnmdi); + + if (HIWORD((UINT)ttnmdi.lpszText) == 0) { + LoadStringW(ttnmdi.hinst, (UINT)ttnmdi.lpszText, + infoPtr->szTipText, INFOTIPSIZE); + if (ttnmdi.uFlags & TTF_DI_SETITEM) { + toolPtr->hinst = ttnmdi.hinst; + toolPtr->lpszText = ttnmdi.lpszText; + } + } + else if (ttnmdi.lpszText == 0) { + /* no text available */ + infoPtr->szTipText[0] = '\0'; + } + else if (ttnmdi.lpszText != LPSTR_TEXTCALLBACKW) { + INT max_len = (ttnmdi.lpszText == &ttnmdi.szText[0]) ? + sizeof(ttnmdi.szText)/sizeof(ttnmdi.szText[0]) : INFOTIPSIZE-1; + lstrcpynW(infoPtr->szTipText, ttnmdi.lpszText, max_len); + if (ttnmdi.uFlags & TTF_DI_SETITEM) { + INT len = max(strlenW(ttnmdi.lpszText), max_len); + toolPtr->hinst = 0; + toolPtr->lpszText = Alloc ((len+1) * sizeof(WCHAR)); + memcpy(toolPtr->lpszText, ttnmdi.lpszText, (len+1) * sizeof(WCHAR)); + } + } + else { + ERR("recursive text callback!\n"); + infoPtr->szTipText[0] = '\0'; + } +} + +static void +TOOLTIPS_GetTipText (HWND hwnd, TOOLTIPS_INFO *infoPtr, INT nTool) +{ + TTTOOL_INFO *toolPtr = &infoPtr->tools[nTool]; + + if (HIWORD((UINT)toolPtr->lpszText) == 0 && toolPtr->hinst) { + /* load a resource */ + TRACE("load res string %p %x\n", + toolPtr->hinst, (int)toolPtr->lpszText); + LoadStringW (toolPtr->hinst, (UINT)toolPtr->lpszText, + infoPtr->szTipText, INFOTIPSIZE); + } + else if (toolPtr->lpszText) { + if (toolPtr->lpszText == LPSTR_TEXTCALLBACKW) { + if (toolPtr->bNotifyUnicode) + TOOLTIPS_GetDispInfoW(hwnd, infoPtr, toolPtr); + else + TOOLTIPS_GetDispInfoA(hwnd, infoPtr, toolPtr); + } + else { + /* the item is a usual (unicode) text */ + lstrcpynW (infoPtr->szTipText, toolPtr->lpszText, INFOTIPSIZE); + } + } + else { + /* no text available */ + infoPtr->szTipText[0] = L'\0'; + } + + TRACE("%s\n", debugstr_w(infoPtr->szTipText)); +} + + +static void +TOOLTIPS_CalcTipSize (HWND hwnd, TOOLTIPS_INFO *infoPtr, LPSIZE lpSize) +{ + HDC hdc; + HFONT hOldFont; + DWORD style = GetWindowLongW(hwnd, GWL_STYLE); + UINT uFlags = DT_EXTERNALLEADING | DT_CALCRECT; + RECT rc = {0, 0, 0, 0}; + SIZE title = {0, 0}; + + if (infoPtr->nMaxTipWidth > -1) { + rc.right = infoPtr->nMaxTipWidth; + uFlags |= DT_WORDBREAK; + } + if (style & TTS_NOPREFIX) + uFlags |= DT_NOPREFIX; + TRACE("%s\n", debugstr_w(infoPtr->szTipText)); + + hdc = GetDC (hwnd); + if (infoPtr->pszTitle) + { + RECT rcTitle = {0, 0, 0, 0}; + TRACE("title %s\n", debugstr_w(infoPtr->pszTitle)); + if (infoPtr->hTitleIcon) + { + title.cx = ICON_WIDTH; + title.cy = ICON_HEIGHT; + } + if (title.cx != 0) title.cx += BALLOON_ICON_TITLE_SPACING; + hOldFont = SelectObject (hdc, infoPtr->hTitleFont); + DrawTextW(hdc, infoPtr->pszTitle, -1, &rcTitle, DT_SINGLELINE | DT_NOPREFIX | DT_CALCRECT); + SelectObject (hdc, hOldFont); + title.cy = max(title.cy, rcTitle.bottom - rcTitle.top) + BALLOON_TITLE_TEXT_SPACING; + title.cx += (rcTitle.right - rcTitle.left); + } + hOldFont = SelectObject (hdc, infoPtr->hFont); + DrawTextW (hdc, infoPtr->szTipText, -1, &rc, uFlags); + SelectObject (hdc, hOldFont); + ReleaseDC (hwnd, hdc); + + if ((style & TTS_BALLOON) || infoPtr->pszTitle) + { + lpSize->cx = max(rc.right - rc.left, title.cx) + 2*BALLOON_TEXT_MARGIN + + infoPtr->rcMargin.left + infoPtr->rcMargin.right; + lpSize->cy = title.cy + rc.bottom - rc.top + 2*BALLOON_TEXT_MARGIN + + infoPtr->rcMargin.bottom + infoPtr->rcMargin.top + + BALLOON_STEMHEIGHT; + } + else + { + lpSize->cx = rc.right - rc.left + 2*NORMAL_TEXT_MARGIN + + infoPtr->rcMargin.left + infoPtr->rcMargin.right; + lpSize->cy = rc.bottom - rc.top + 2*NORMAL_TEXT_MARGIN + + infoPtr->rcMargin.bottom + infoPtr->rcMargin.top; + } +} + + +static void +TOOLTIPS_Show (HWND hwnd, TOOLTIPS_INFO *infoPtr) +{ + TTTOOL_INFO *toolPtr; + RECT rect, wndrect; + SIZE size; + NMHDR hdr; + int ptfx = 0; + DWORD style = GetWindowLongW(hwnd, GWL_STYLE); + + if (infoPtr->nTool == -1) { + TRACE("invalid tool (-1)!\n"); + return; + } + + infoPtr->nCurrentTool = infoPtr->nTool; + + TRACE("Show tooltip pre %d! (%p)\n", infoPtr->nTool, hwnd); + + TOOLTIPS_GetTipText (hwnd, infoPtr, infoPtr->nCurrentTool); + + if (infoPtr->szTipText[0] == L'\0') { + infoPtr->nCurrentTool = -1; + return; + } + + TRACE("Show tooltip %d!\n", infoPtr->nCurrentTool); + toolPtr = &infoPtr->tools[infoPtr->nCurrentTool]; + + hdr.hwndFrom = hwnd; + hdr.idFrom = toolPtr->uId; + hdr.code = TTN_SHOW; + SendMessageW (toolPtr->hwnd, WM_NOTIFY, + (WPARAM)toolPtr->uId, (LPARAM)&hdr); + + TRACE("%s\n", debugstr_w(infoPtr->szTipText)); + + TOOLTIPS_CalcTipSize (hwnd, infoPtr, &size); + TRACE("size %ld x %ld\n", size.cx, size.cy); + + if (toolPtr->uFlags & TTF_CENTERTIP) { + RECT rc; + + if (toolPtr->uFlags & TTF_IDISHWND) + GetWindowRect ((HWND)toolPtr->uId, &rc); + else { + rc = toolPtr->rect; + MapWindowPoints (toolPtr->hwnd, NULL, (LPPOINT)&rc, 2); + } + rect.left = (rc.left + rc.right - size.cx) / 2; + if (style & TTS_BALLOON) + { + ptfx = rc.left + ((rc.right - rc.left) / 2); + if(rect.top - size.cy >= 0) + { + rect.top -= size.cy; + infoPtr->bToolBelow = FALSE; + } + else + { + infoPtr->bToolBelow = TRUE; + rect.top += 20; + } + rect.left = max(0, rect.left - BALLOON_STEMINDENT); + } + else + { + rect.top = rc.bottom + 2; + infoPtr->bToolBelow = TRUE; + } + } + else { + GetCursorPos ((LPPOINT)&rect); + if (style & TTS_BALLOON) + { + ptfx = rect.left; + if(rect.top - size.cy >= 0) + { + rect.top -= size.cy; + infoPtr->bToolBelow = FALSE; + } + else + { + infoPtr->bToolBelow = TRUE; + rect.top += 20; + } + rect.left = max(0, rect.left - BALLOON_STEMINDENT); + } + else + { + rect.top += 20; + infoPtr->bToolBelow = TRUE; + } + } + + TRACE("pos %ld - %ld\n", rect.left, rect.top); + + rect.right = rect.left + size.cx; + rect.bottom = rect.top + size.cy; + + /* check position */ + wndrect.right = GetSystemMetrics( SM_CXSCREEN ); + if( rect.right > wndrect.right ) { + rect.left -= rect.right - wndrect.right + 2; + rect.right = wndrect.right - 2; + } + wndrect.bottom = GetSystemMetrics( SM_CYSCREEN ); + if( rect.bottom > wndrect.bottom ) { + RECT rc; + + if (toolPtr->uFlags & TTF_IDISHWND) + GetWindowRect ((HWND)toolPtr->uId, &rc); + else { + rc = toolPtr->rect; + MapWindowPoints (toolPtr->hwnd, NULL, (LPPOINT)&rc, 2); + } + rect.bottom = rc.top - 2; + rect.top = rect.bottom - size.cy; + } + + AdjustWindowRectEx (&rect, GetWindowLongW (hwnd, GWL_STYLE), + FALSE, GetWindowLongW (hwnd, GWL_EXSTYLE)); + + if (style & TTS_BALLOON) + { + HRGN hRgn; + HRGN hrStem; + POINT pts[3]; + + ptfx -= rect.left; + + if(infoPtr->bToolBelow) + { + pts[0].x = ptfx; + pts[0].y = 0; + pts[1].x = max(BALLOON_STEMINDENT, ptfx - (BALLOON_STEMWIDTH / 2)); + pts[1].y = BALLOON_STEMHEIGHT; + pts[2].x = pts[1].x + BALLOON_STEMWIDTH; + pts[2].y = pts[1].y; + if(pts[2].x > (rect.right - rect.left) - BALLOON_STEMINDENT) + { + pts[2].x = (rect.right - rect.left) - BALLOON_STEMINDENT; + pts[1].x = pts[2].x - BALLOON_STEMWIDTH; + } + } + else + { + pts[0].x = max(BALLOON_STEMINDENT, ptfx - (BALLOON_STEMWIDTH / 2)); + pts[0].y = (rect.bottom - rect.top) - BALLOON_STEMHEIGHT; + pts[1].x = pts[0].x + BALLOON_STEMWIDTH; + pts[1].y = pts[0].y; + pts[2].x = ptfx; + pts[2].y = (rect.bottom - rect.top); + if(pts[1].x > (rect.right - rect.left) - BALLOON_STEMINDENT) + { + pts[1].x = (rect.right - rect.left) - BALLOON_STEMINDENT; + pts[0].x = pts[1].x - BALLOON_STEMWIDTH; + } + } + + hrStem = CreatePolygonRgn(pts, sizeof(pts) / sizeof(pts[0]), ALTERNATE); + + hRgn = CreateRoundRectRgn(0, + (infoPtr->bToolBelow ? BALLOON_STEMHEIGHT : 0), + rect.right - rect.left, + (infoPtr->bToolBelow ? rect.bottom - rect.top : rect.bottom - rect.top - BALLOON_STEMHEIGHT), + BALLOON_ROUNDEDNESS, BALLOON_ROUNDEDNESS); + + CombineRgn(hRgn, hRgn, hrStem, RGN_OR); + DeleteObject(hrStem); + + SetWindowRgn(hwnd, hRgn, FALSE); + /* we don't free the region handle as the system deletes it when + * it is no longer needed */ + } + + SetWindowPos (hwnd, HWND_TOP, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_SHOWWINDOW | SWP_NOACTIVATE); + + /* repaint the tooltip */ + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); + + SetTimer (hwnd, ID_TIMERPOP, infoPtr->nAutoPopTime, 0); + TRACE("timer 2 started!\n"); + SetTimer (hwnd, ID_TIMERLEAVE, infoPtr->nReshowTime, 0); + TRACE("timer 3 started!\n"); +} + + +static void +TOOLTIPS_Hide (HWND hwnd, TOOLTIPS_INFO *infoPtr) +{ + TTTOOL_INFO *toolPtr; + NMHDR hdr; + + TRACE("Hide tooltip %d! (%p)\n", infoPtr->nCurrentTool, hwnd); + + if (infoPtr->nCurrentTool == -1) + return; + + toolPtr = &infoPtr->tools[infoPtr->nCurrentTool]; + KillTimer (hwnd, ID_TIMERPOP); + + hdr.hwndFrom = hwnd; + hdr.idFrom = toolPtr->uId; + hdr.code = TTN_POP; + SendMessageW (toolPtr->hwnd, WM_NOTIFY, + (WPARAM)toolPtr->uId, (LPARAM)&hdr); + + infoPtr->nCurrentTool = -1; + + SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, + SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE); +} + + +static void +TOOLTIPS_TrackShow (HWND hwnd, TOOLTIPS_INFO *infoPtr) +{ + TTTOOL_INFO *toolPtr; + RECT rect; + SIZE size; + NMHDR hdr; + + if (infoPtr->nTrackTool == -1) { + TRACE("invalid tracking tool (-1)!\n"); + return; + } + + TRACE("show tracking tooltip pre %d!\n", infoPtr->nTrackTool); + + TOOLTIPS_GetTipText (hwnd, infoPtr, infoPtr->nTrackTool); + + if (infoPtr->szTipText[0] == L'\0') { + infoPtr->nTrackTool = -1; + return; + } + + TRACE("show tracking tooltip %d!\n", infoPtr->nTrackTool); + toolPtr = &infoPtr->tools[infoPtr->nTrackTool]; + + hdr.hwndFrom = hwnd; + hdr.idFrom = toolPtr->uId; + hdr.code = TTN_SHOW; + SendMessageW (toolPtr->hwnd, WM_NOTIFY, + (WPARAM)toolPtr->uId, (LPARAM)&hdr); + + TRACE("%s\n", debugstr_w(infoPtr->szTipText)); + + TOOLTIPS_CalcTipSize (hwnd, infoPtr, &size); + TRACE("size %ld x %ld\n", size.cx, size.cy); + + if (toolPtr->uFlags & TTF_ABSOLUTE) { + rect.left = infoPtr->xTrackPos; + rect.top = infoPtr->yTrackPos; + + if (toolPtr->uFlags & TTF_CENTERTIP) { + rect.left -= (size.cx / 2); + rect.top -= (size.cy / 2); + } + } + else { + RECT rcTool; + + if (toolPtr->uFlags & TTF_IDISHWND) + GetWindowRect ((HWND)toolPtr->uId, &rcTool); + else { + rcTool = toolPtr->rect; + MapWindowPoints (toolPtr->hwnd, NULL, (LPPOINT)&rcTool, 2); + } + + GetCursorPos ((LPPOINT)&rect); + rect.top += 20; + + if (toolPtr->uFlags & TTF_CENTERTIP) { + rect.left -= (size.cx / 2); + rect.top -= (size.cy / 2); + } + + /* smart placement */ + if ((rect.left + size.cx > rcTool.left) && (rect.left < rcTool.right) && + (rect.top + size.cy > rcTool.top) && (rect.top < rcTool.bottom)) + rect.left = rcTool.right; + } + + TRACE("pos %ld - %ld\n", rect.left, rect.top); + + rect.right = rect.left + size.cx; + rect.bottom = rect.top + size.cy; + + AdjustWindowRectEx (&rect, GetWindowLongW (hwnd, GWL_STYLE), + FALSE, GetWindowLongW (hwnd, GWL_EXSTYLE)); + + if (GetWindowLongW(hwnd, GWL_STYLE) & TTS_BALLOON) + { + HRGN hRgn; + + /* FIXME: need to add pointy bit using CreatePolyRgn & CombinRgn */ + hRgn = CreateRoundRectRgn(0, 0, rect.right - rect.left, rect.bottom - rect.top, BALLOON_ROUNDEDNESS, BALLOON_ROUNDEDNESS); + + SetWindowRgn(hwnd, hRgn, FALSE); + /* we don't free the region handle as the system deletes it when + * it is no longer needed */ + } + + SetWindowPos (hwnd, HWND_TOP, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_SHOWWINDOW | SWP_NOACTIVATE ); + + InvalidateRect(hwnd, NULL, TRUE); + UpdateWindow(hwnd); +} + + +static void +TOOLTIPS_TrackHide (HWND hwnd, TOOLTIPS_INFO *infoPtr) +{ + TTTOOL_INFO *toolPtr; + NMHDR hdr; + + TRACE("hide tracking tooltip %d\n", infoPtr->nTrackTool); + + if (infoPtr->nTrackTool == -1) + return; + + toolPtr = &infoPtr->tools[infoPtr->nTrackTool]; + + hdr.hwndFrom = hwnd; + hdr.idFrom = toolPtr->uId; + hdr.code = TTN_POP; + SendMessageW (toolPtr->hwnd, WM_NOTIFY, + (WPARAM)toolPtr->uId, (LPARAM)&hdr); + + SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, + SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE); +} + + +static INT +TOOLTIPS_GetToolFromInfoA (TOOLTIPS_INFO *infoPtr, LPTTTOOLINFOA lpToolInfo) +{ + TTTOOL_INFO *toolPtr; + INT nTool; + + for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) { + toolPtr = &infoPtr->tools[nTool]; + + if (!(toolPtr->uFlags & TTF_IDISHWND) && + (lpToolInfo->hwnd == toolPtr->hwnd) && + (lpToolInfo->uId == toolPtr->uId)) + return nTool; + } + + for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) { + toolPtr = &infoPtr->tools[nTool]; + + if ((toolPtr->uFlags & TTF_IDISHWND) && + (lpToolInfo->uId == toolPtr->uId)) + return nTool; + } + + return -1; +} + + +static INT +TOOLTIPS_GetToolFromInfoW (TOOLTIPS_INFO *infoPtr, LPTTTOOLINFOW lpToolInfo) +{ + TTTOOL_INFO *toolPtr; + INT nTool; + + for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) { + toolPtr = &infoPtr->tools[nTool]; + + if (!(toolPtr->uFlags & TTF_IDISHWND) && + (lpToolInfo->hwnd == toolPtr->hwnd) && + (lpToolInfo->uId == toolPtr->uId)) + return nTool; + } + + for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) { + toolPtr = &infoPtr->tools[nTool]; + + if ((toolPtr->uFlags & TTF_IDISHWND) && + (lpToolInfo->uId == toolPtr->uId)) + return nTool; + } + + return -1; +} + + +static INT +TOOLTIPS_GetToolFromPoint (TOOLTIPS_INFO *infoPtr, HWND hwnd, LPPOINT lpPt) +{ + TTTOOL_INFO *toolPtr; + INT nTool; + + for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) { + toolPtr = &infoPtr->tools[nTool]; + + if (!(toolPtr->uFlags & TTF_IDISHWND)) { + if (hwnd != toolPtr->hwnd) + continue; + if (!PtInRect (&toolPtr->rect, *lpPt)) + continue; + return nTool; + } + } + + for (nTool = 0; nTool < infoPtr->uNumTools; nTool++) { + toolPtr = &infoPtr->tools[nTool]; + + if (toolPtr->uFlags & TTF_IDISHWND) { + if ((HWND)toolPtr->uId == hwnd) + return nTool; + } + } + + return -1; +} + + +static BOOL +TOOLTIPS_IsWindowActive (HWND hwnd) +{ + HWND hwndActive = GetActiveWindow (); + if (!hwndActive) + return FALSE; + if (hwndActive == hwnd) + return TRUE; + return IsChild (hwndActive, hwnd); +} + + +static INT +TOOLTIPS_CheckTool (HWND hwnd, BOOL bShowTest) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + POINT pt; + HWND hwndTool; + INT nTool; + + GetCursorPos (&pt); + hwndTool = (HWND)SendMessageW (hwnd, TTM_WINDOWFROMPOINT, 0, (LPARAM)&pt); + if (hwndTool == 0) + return -1; + + ScreenToClient (hwndTool, &pt); + nTool = TOOLTIPS_GetToolFromPoint (infoPtr, hwndTool, &pt); + if (nTool == -1) + return -1; + + if (!(GetWindowLongW (hwnd, GWL_STYLE) & TTS_ALWAYSTIP) && bShowTest) { + if (!TOOLTIPS_IsWindowActive (GetWindow (hwnd, GW_OWNER))) + return -1; + } + + TRACE("tool %d\n", nTool); + + return nTool; +} + + +static LRESULT +TOOLTIPS_Activate (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + + infoPtr->bActive = (BOOL)wParam; + + if (infoPtr->bActive) + TRACE("activate!\n"); + + if (!(infoPtr->bActive) && (infoPtr->nCurrentTool != -1)) + TOOLTIPS_Hide (hwnd, infoPtr); + + return 0; +} + + +static LRESULT +TOOLTIPS_AddToolA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam; + TTTOOL_INFO *toolPtr; + INT nResult; + + if (lpToolInfo == NULL) + return FALSE; + if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE) + return FALSE; + + TRACE("add tool (%p) %p %d%s!\n", + hwnd, lpToolInfo->hwnd, lpToolInfo->uId, + (lpToolInfo->uFlags & TTF_IDISHWND) ? " TTF_IDISHWND" : ""); + + if (infoPtr->uNumTools == 0) { + infoPtr->tools = Alloc (sizeof(TTTOOL_INFO)); + toolPtr = infoPtr->tools; + } + else { + TTTOOL_INFO *oldTools = infoPtr->tools; + infoPtr->tools = + Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools + 1)); + memcpy (infoPtr->tools, oldTools, + infoPtr->uNumTools * sizeof(TTTOOL_INFO)); + Free (oldTools); + toolPtr = &infoPtr->tools[infoPtr->uNumTools]; + } + + infoPtr->uNumTools++; + + /* copy tool data */ + toolPtr->uFlags = lpToolInfo->uFlags; + toolPtr->hwnd = lpToolInfo->hwnd; + toolPtr->uId = lpToolInfo->uId; + toolPtr->rect = lpToolInfo->rect; + toolPtr->hinst = lpToolInfo->hinst; + + if (HIWORD(lpToolInfo->lpszText) == 0) { + TRACE("add string id %x!\n", (int)lpToolInfo->lpszText); + toolPtr->lpszText = (LPWSTR)lpToolInfo->lpszText; + } + else if (lpToolInfo->lpszText) { + if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKA) { + TRACE("add CALLBACK!\n"); + toolPtr->lpszText = LPSTR_TEXTCALLBACKW; + } + else { + INT len = MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1, + NULL, 0); + TRACE("add text \"%s\"!\n", lpToolInfo->lpszText); + toolPtr->lpszText = Alloc (len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1, + toolPtr->lpszText, len); + } + } + + if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA)) + toolPtr->lParam = lpToolInfo->lParam; + + /* install subclassing hook */ + if (toolPtr->uFlags & TTF_SUBCLASS) { + if (toolPtr->uFlags & TTF_IDISHWND) { + SetWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1, + (DWORD_PTR)hwnd); + } + else { + SetWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1, + (DWORD_PTR)hwnd); + } + TRACE("subclassing installed!\n"); + } + + nResult = (INT) SendMessageW (toolPtr->hwnd, WM_NOTIFYFORMAT, + (WPARAM)hwnd, (LPARAM)NF_QUERY); + if (nResult == NFR_ANSI) { + toolPtr->bNotifyUnicode = FALSE; + TRACE(" -- WM_NOTIFYFORMAT returns: NFR_ANSI\n"); + } else if (nResult == NFR_UNICODE) { + toolPtr->bNotifyUnicode = TRUE; + TRACE(" -- WM_NOTIFYFORMAT returns: NFR_UNICODE\n"); + } else { + TRACE (" -- WM_NOTIFYFORMAT returns: error!\n"); + } + + return TRUE; +} + + +static LRESULT +TOOLTIPS_AddToolW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam; + TTTOOL_INFO *toolPtr; + INT nResult; + + if (lpToolInfo == NULL) + return FALSE; + if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE) + return FALSE; + + TRACE("add tool (%p) %p %d%s!\n", + hwnd, lpToolInfo->hwnd, lpToolInfo->uId, + (lpToolInfo->uFlags & TTF_IDISHWND) ? " TTF_IDISHWND" : ""); + + if (infoPtr->uNumTools == 0) { + infoPtr->tools = Alloc (sizeof(TTTOOL_INFO)); + toolPtr = infoPtr->tools; + } + else { + TTTOOL_INFO *oldTools = infoPtr->tools; + infoPtr->tools = + Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools + 1)); + memcpy (infoPtr->tools, oldTools, + infoPtr->uNumTools * sizeof(TTTOOL_INFO)); + Free (oldTools); + toolPtr = &infoPtr->tools[infoPtr->uNumTools]; + } + + infoPtr->uNumTools++; + + /* copy tool data */ + toolPtr->uFlags = lpToolInfo->uFlags; + toolPtr->hwnd = lpToolInfo->hwnd; + toolPtr->uId = lpToolInfo->uId; + toolPtr->rect = lpToolInfo->rect; + toolPtr->hinst = lpToolInfo->hinst; + + if (HIWORD(lpToolInfo->lpszText) == 0) { + TRACE("add string id %x!\n", (int)lpToolInfo->lpszText); + toolPtr->lpszText = (LPWSTR)lpToolInfo->lpszText; + } + else if (lpToolInfo->lpszText) { + if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKW) { + TRACE("add CALLBACK!\n"); + toolPtr->lpszText = LPSTR_TEXTCALLBACKW; + } + else { + INT len = lstrlenW (lpToolInfo->lpszText); + TRACE("add text %s!\n", + debugstr_w(lpToolInfo->lpszText)); + toolPtr->lpszText = Alloc ((len + 1)*sizeof(WCHAR)); + strcpyW (toolPtr->lpszText, lpToolInfo->lpszText); + } + } + + if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW)) + toolPtr->lParam = lpToolInfo->lParam; + + /* install subclassing hook */ + if (toolPtr->uFlags & TTF_SUBCLASS) { + if (toolPtr->uFlags & TTF_IDISHWND) { + SetWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1, + (DWORD_PTR)hwnd); + } + else { + SetWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1, + (DWORD_PTR)hwnd); + } + TRACE("subclassing installed!\n"); + } + + nResult = (INT) SendMessageW (toolPtr->hwnd, WM_NOTIFYFORMAT, + (WPARAM)hwnd, (LPARAM)NF_QUERY); + if (nResult == NFR_ANSI) { + toolPtr->bNotifyUnicode = FALSE; + TRACE(" -- WM_NOTIFYFORMAT returns: NFR_ANSI\n"); + } else if (nResult == NFR_UNICODE) { + toolPtr->bNotifyUnicode = TRUE; + TRACE(" -- WM_NOTIFYFORMAT returns: NFR_UNICODE\n"); + } else { + TRACE (" -- WM_NOTIFYFORMAT returns: error!\n"); + } + + return TRUE; +} + + +static void +TOOLTIPS_DelToolCommon (HWND hwnd, TOOLTIPS_INFO *infoPtr, INT nTool) +{ + TTTOOL_INFO *toolPtr; + + TRACE("tool %d\n", nTool); + + if (nTool == -1) + return; + + /* make sure the tooltip has disappeared before deleting it */ + TOOLTIPS_Hide(hwnd, infoPtr); + + /* delete text string */ + toolPtr = &infoPtr->tools[nTool]; + if (toolPtr->lpszText) { + if ( (toolPtr->lpszText != LPSTR_TEXTCALLBACKW) && + (HIWORD((INT)toolPtr->lpszText) != 0) ) + Free (toolPtr->lpszText); + } + + /* remove subclassing */ + if (toolPtr->uFlags & TTF_SUBCLASS) { + if (toolPtr->uFlags & TTF_IDISHWND) { + RemoveWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1); + } + else { + RemoveWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1); + } + } + + /* delete tool from tool list */ + if (infoPtr->uNumTools == 1) { + Free (infoPtr->tools); + infoPtr->tools = NULL; + } + else { + TTTOOL_INFO *oldTools = infoPtr->tools; + infoPtr->tools = + Alloc (sizeof(TTTOOL_INFO) * (infoPtr->uNumTools - 1)); + + if (nTool > 0) + memcpy (&infoPtr->tools[0], &oldTools[0], + nTool * sizeof(TTTOOL_INFO)); + + if (nTool < infoPtr->uNumTools - 1) + memcpy (&infoPtr->tools[nTool], &oldTools[nTool + 1], + (infoPtr->uNumTools - nTool - 1) * sizeof(TTTOOL_INFO)); + + Free (oldTools); + } + + /* update any indices affected by delete */ + + /* destroying tool that mouse was on on last relayed mouse move */ + if (infoPtr->nTool == nTool) + /* -1 means no current tool (0 means first tool) */ + infoPtr->nTool = -1; + else if (infoPtr->nTool > nTool) + infoPtr->nTool--; + + if (infoPtr->nTrackTool == nTool) + /* -1 means no current tool (0 means first tool) */ + infoPtr->nTrackTool = -1; + else if (infoPtr->nTrackTool > nTool) + infoPtr->nTrackTool--; + + if (infoPtr->nCurrentTool == nTool) + /* -1 means no current tool (0 means first tool) */ + infoPtr->nCurrentTool = -1; + else if (infoPtr->nCurrentTool > nTool) + infoPtr->nCurrentTool--; + + infoPtr->uNumTools--; +} + +static LRESULT +TOOLTIPS_DelToolA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam; + INT nTool; + + if (lpToolInfo == NULL) + return 0; + if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE) + return 0; + if (infoPtr->uNumTools == 0) + return 0; + + nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo); + + TOOLTIPS_DelToolCommon (hwnd, infoPtr, nTool); + + return 0; +} + + +static LRESULT +TOOLTIPS_DelToolW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam; + INT nTool; + + if (lpToolInfo == NULL) + return 0; + if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE) + return 0; + if (infoPtr->uNumTools == 0) + return 0; + + nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo); + + TOOLTIPS_DelToolCommon (hwnd, infoPtr, nTool); + + return 0; +} + + +static LRESULT +TOOLTIPS_EnumToolsA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + UINT uIndex = (UINT)wParam; + LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam; + TTTOOL_INFO *toolPtr; + + if (lpToolInfo == NULL) + return FALSE; + if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE) + return FALSE; + if (uIndex >= infoPtr->uNumTools) + return FALSE; + + TRACE("index=%u\n", uIndex); + + toolPtr = &infoPtr->tools[uIndex]; + + /* copy tool data */ + lpToolInfo->uFlags = toolPtr->uFlags; + lpToolInfo->hwnd = toolPtr->hwnd; + lpToolInfo->uId = toolPtr->uId; + lpToolInfo->rect = toolPtr->rect; + lpToolInfo->hinst = toolPtr->hinst; +/* lpToolInfo->lpszText = toolPtr->lpszText; */ + lpToolInfo->lpszText = NULL; /* FIXME */ + + if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA)) + lpToolInfo->lParam = toolPtr->lParam; + + return TRUE; +} + + +static LRESULT +TOOLTIPS_EnumToolsW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + UINT uIndex = (UINT)wParam; + LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam; + TTTOOL_INFO *toolPtr; + + if (lpToolInfo == NULL) + return FALSE; + if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE) + return FALSE; + if (uIndex >= infoPtr->uNumTools) + return FALSE; + + TRACE("index=%u\n", uIndex); + + toolPtr = &infoPtr->tools[uIndex]; + + /* copy tool data */ + lpToolInfo->uFlags = toolPtr->uFlags; + lpToolInfo->hwnd = toolPtr->hwnd; + lpToolInfo->uId = toolPtr->uId; + lpToolInfo->rect = toolPtr->rect; + lpToolInfo->hinst = toolPtr->hinst; +/* lpToolInfo->lpszText = toolPtr->lpszText; */ + lpToolInfo->lpszText = NULL; /* FIXME */ + + if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW)) + lpToolInfo->lParam = toolPtr->lParam; + + return TRUE; +} + +static LRESULT +TOOLTIPS_GetBubbleSize (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam; + INT nTool; + SIZE size; + + if (lpToolInfo == NULL) + return FALSE; + if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE) + return FALSE; + + nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo); + if (nTool == -1) return 0; + + TRACE("tool %d\n", nTool); + + TOOLTIPS_CalcTipSize (hwnd, infoPtr, &size); + TRACE("size %ld x %ld\n", size.cx, size.cy); + + return MAKELRESULT(size.cx, size.cy); +} + +static LRESULT +TOOLTIPS_GetCurrentToolA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam; + TTTOOL_INFO *toolPtr; + + if (lpToolInfo == NULL) + return FALSE; + if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE) + return FALSE; + + if (lpToolInfo) { + if (infoPtr->nCurrentTool > -1) { + toolPtr = &infoPtr->tools[infoPtr->nCurrentTool]; + + /* copy tool data */ + lpToolInfo->uFlags = toolPtr->uFlags; + lpToolInfo->rect = toolPtr->rect; + lpToolInfo->hinst = toolPtr->hinst; +/* lpToolInfo->lpszText = toolPtr->lpszText; */ + lpToolInfo->lpszText = NULL; /* FIXME */ + + if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA)) + lpToolInfo->lParam = toolPtr->lParam; + + return TRUE; + } + else + return FALSE; + } + else + return (infoPtr->nCurrentTool != -1); +} + + +static LRESULT +TOOLTIPS_GetCurrentToolW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam; + TTTOOL_INFO *toolPtr; + + if (lpToolInfo == NULL) + return FALSE; + if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE) + return FALSE; + + if (lpToolInfo) { + if (infoPtr->nCurrentTool > -1) { + toolPtr = &infoPtr->tools[infoPtr->nCurrentTool]; + + /* copy tool data */ + lpToolInfo->uFlags = toolPtr->uFlags; + lpToolInfo->rect = toolPtr->rect; + lpToolInfo->hinst = toolPtr->hinst; +/* lpToolInfo->lpszText = toolPtr->lpszText; */ + lpToolInfo->lpszText = NULL; /* FIXME */ + + if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW)) + lpToolInfo->lParam = toolPtr->lParam; + + return TRUE; + } + else + return FALSE; + } + else + return (infoPtr->nCurrentTool != -1); +} + + +static LRESULT +TOOLTIPS_GetDelayTime (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + + switch (wParam) { + case TTDT_RESHOW: + return infoPtr->nReshowTime; + + case TTDT_AUTOPOP: + return infoPtr->nAutoPopTime; + + case TTDT_INITIAL: + case TTDT_AUTOMATIC: /* Apparently TTDT_AUTOMATIC returns TTDT_INITIAL */ + return infoPtr->nInitialTime; + + default: + WARN("Invalid wParam %x\n", wParam); + break; + } + + return -1; +} + + +static LRESULT +TOOLTIPS_GetMargin (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPRECT lpRect = (LPRECT)lParam; + + lpRect->left = infoPtr->rcMargin.left; + lpRect->right = infoPtr->rcMargin.right; + lpRect->bottom = infoPtr->rcMargin.bottom; + lpRect->top = infoPtr->rcMargin.top; + + return 0; +} + + +inline static LRESULT +TOOLTIPS_GetMaxTipWidth (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + + return infoPtr->nMaxTipWidth; +} + + +static LRESULT +TOOLTIPS_GetTextA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam; + INT nTool; + + if (lpToolInfo == NULL) + return 0; + if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE) + return 0; + + nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo); + if (nTool == -1) return 0; + + /* NB this API is broken, there is no way for the app to determine + what size buffer it requires nor a way to specify how long the + one it supplies is. We'll assume it's upto INFOTIPSIZE */ + + WideCharToMultiByte(CP_ACP, 0, infoPtr->tools[nTool].lpszText, -1, + lpToolInfo->lpszText, INFOTIPSIZE, NULL, NULL); + + return 0; +} + + +static LRESULT +TOOLTIPS_GetTextW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam; + INT nTool; + + if (lpToolInfo == NULL) + return 0; + if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE) + return 0; + + nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo); + if (nTool == -1) return 0; + + strcpyW (lpToolInfo->lpszText, infoPtr->tools[nTool].lpszText); + + return 0; +} + + +inline static LRESULT +TOOLTIPS_GetTipBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + return infoPtr->clrBk; +} + + +inline static LRESULT +TOOLTIPS_GetTipTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + return infoPtr->clrText; +} + + +inline static LRESULT +TOOLTIPS_GetToolCount (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + return infoPtr->uNumTools; +} + + +static LRESULT +TOOLTIPS_GetToolInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam; + TTTOOL_INFO *toolPtr; + INT nTool; + + if (lpToolInfo == NULL) + return FALSE; + if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE) + return FALSE; + if (infoPtr->uNumTools == 0) + return FALSE; + + nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo); + if (nTool == -1) + return FALSE; + + TRACE("tool %d\n", nTool); + + toolPtr = &infoPtr->tools[nTool]; + + /* copy tool data */ + lpToolInfo->uFlags = toolPtr->uFlags; + lpToolInfo->rect = toolPtr->rect; + lpToolInfo->hinst = toolPtr->hinst; +/* lpToolInfo->lpszText = toolPtr->lpszText; */ + lpToolInfo->lpszText = NULL; /* FIXME */ + + if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA)) + lpToolInfo->lParam = toolPtr->lParam; + + return TRUE; +} + + +static LRESULT +TOOLTIPS_GetToolInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam; + TTTOOL_INFO *toolPtr; + INT nTool; + + if (lpToolInfo == NULL) + return FALSE; + if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE) + return FALSE; + if (infoPtr->uNumTools == 0) + return FALSE; + + nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo); + if (nTool == -1) + return FALSE; + + TRACE("tool %d\n", nTool); + + toolPtr = &infoPtr->tools[nTool]; + + /* copy tool data */ + lpToolInfo->uFlags = toolPtr->uFlags; + lpToolInfo->rect = toolPtr->rect; + lpToolInfo->hinst = toolPtr->hinst; +/* lpToolInfo->lpszText = toolPtr->lpszText; */ + lpToolInfo->lpszText = NULL; /* FIXME */ + + if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW)) + lpToolInfo->lParam = toolPtr->lParam; + + return TRUE; +} + + +static LRESULT +TOOLTIPS_HitTestA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPTTHITTESTINFOA lptthit = (LPTTHITTESTINFOA)lParam; + TTTOOL_INFO *toolPtr; + INT nTool; + + if (lptthit == 0) + return FALSE; + + nTool = TOOLTIPS_GetToolFromPoint (infoPtr, lptthit->hwnd, &lptthit->pt); + if (nTool == -1) + return FALSE; + + TRACE("tool %d!\n", nTool); + + /* copy tool data */ + if (lptthit->ti.cbSize >= sizeof(TTTOOLINFOA)) { + toolPtr = &infoPtr->tools[nTool]; + + lptthit->ti.uFlags = toolPtr->uFlags; + lptthit->ti.hwnd = toolPtr->hwnd; + lptthit->ti.uId = toolPtr->uId; + lptthit->ti.rect = toolPtr->rect; + lptthit->ti.hinst = toolPtr->hinst; +/* lptthit->ti.lpszText = toolPtr->lpszText; */ + lptthit->ti.lpszText = NULL; /* FIXME */ + lptthit->ti.lParam = toolPtr->lParam; + } + + return TRUE; +} + + +static LRESULT +TOOLTIPS_HitTestW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPTTHITTESTINFOW lptthit = (LPTTHITTESTINFOW)lParam; + TTTOOL_INFO *toolPtr; + INT nTool; + + if (lptthit == 0) + return FALSE; + + nTool = TOOLTIPS_GetToolFromPoint (infoPtr, lptthit->hwnd, &lptthit->pt); + if (nTool == -1) + return FALSE; + + TRACE("tool %d!\n", nTool); + + /* copy tool data */ + if (lptthit->ti.cbSize >= sizeof(TTTOOLINFOW)) { + toolPtr = &infoPtr->tools[nTool]; + + lptthit->ti.uFlags = toolPtr->uFlags; + lptthit->ti.hwnd = toolPtr->hwnd; + lptthit->ti.uId = toolPtr->uId; + lptthit->ti.rect = toolPtr->rect; + lptthit->ti.hinst = toolPtr->hinst; +/* lptthit->ti.lpszText = toolPtr->lpszText; */ + lptthit->ti.lpszText = NULL; /* FIXME */ + lptthit->ti.lParam = toolPtr->lParam; + } + + return TRUE; +} + + +static LRESULT +TOOLTIPS_NewToolRectA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPTTTOOLINFOA lpti = (LPTTTOOLINFOA)lParam; + INT nTool; + + if (lpti == NULL) + return 0; + if (lpti->cbSize < TTTOOLINFOA_V1_SIZE) + return FALSE; + + nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpti); + + TRACE("nTool = %d, rect = %s\n", nTool, wine_dbgstr_rect(&lpti->rect)); + + if (nTool == -1) return 0; + + infoPtr->tools[nTool].rect = lpti->rect; + + return 0; +} + + +static LRESULT +TOOLTIPS_NewToolRectW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPTTTOOLINFOW lpti = (LPTTTOOLINFOW)lParam; + INT nTool; + + if (lpti == NULL) + return 0; + if (lpti->cbSize < TTTOOLINFOW_V1_SIZE) + return FALSE; + + nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpti); + + TRACE("nTool = %d, rect = %s\n", nTool, wine_dbgstr_rect(&lpti->rect)); + + if (nTool == -1) return 0; + + infoPtr->tools[nTool].rect = lpti->rect; + + return 0; +} + + +inline static LRESULT +TOOLTIPS_Pop (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + TOOLTIPS_Hide (hwnd, infoPtr); + + return 0; +} + + +static LRESULT +TOOLTIPS_RelayEvent (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPMSG lpMsg = (LPMSG)lParam; + POINT pt; + INT nOldTool; + + if (lParam == 0) { + ERR("lpMsg == NULL!\n"); + return 0; + } + + switch (lpMsg->message) { + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + TOOLTIPS_Hide (hwnd, infoPtr); + break; + + case WM_MOUSEMOVE: + pt.x = LOWORD(lpMsg->lParam); + pt.y = HIWORD(lpMsg->lParam); + nOldTool = infoPtr->nTool; + infoPtr->nTool = TOOLTIPS_GetToolFromPoint(infoPtr, lpMsg->hwnd, + &pt); + TRACE("tool (%p) %d %d %d\n", hwnd, nOldTool, + infoPtr->nTool, infoPtr->nCurrentTool); + TRACE("WM_MOUSEMOVE (%p %ld %ld)\n", hwnd, pt.x, pt.y); + + if (infoPtr->nTool != nOldTool) { + if(infoPtr->nTool == -1) { /* Moved out of all tools */ + TOOLTIPS_Hide(hwnd, infoPtr); + KillTimer(hwnd, ID_TIMERLEAVE); + } else if (nOldTool == -1) { /* Moved from outside */ + if(infoPtr->bActive) { + SetTimer(hwnd, ID_TIMERSHOW, infoPtr->nInitialTime, 0); + TRACE("timer 1 started!\n"); + } + } else { /* Moved from one to another */ + TOOLTIPS_Hide (hwnd, infoPtr); + KillTimer(hwnd, ID_TIMERLEAVE); + if(infoPtr->bActive) { + SetTimer (hwnd, ID_TIMERSHOW, infoPtr->nReshowTime, 0); + TRACE("timer 1 started!\n"); + } + } + } else if(infoPtr->nCurrentTool != -1) { /* restart autopop */ + KillTimer(hwnd, ID_TIMERPOP); + SetTimer(hwnd, ID_TIMERPOP, infoPtr->nAutoPopTime, 0); + TRACE("timer 2 restarted\n"); + } else if(infoPtr->nTool != -1 && infoPtr->bActive) { + /* previous show attempt didn't result in tooltip so try again */ + SetTimer(hwnd, ID_TIMERSHOW, infoPtr->nInitialTime, 0); + TRACE("timer 1 started!\n"); + } + break; + } + + return 0; +} + + +static LRESULT +TOOLTIPS_SetDelayTime (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + INT nTime = (INT)LOWORD(lParam); + + switch (wParam) { + case TTDT_AUTOMATIC: + if (nTime <= 0) + nTime = GetDoubleClickTime(); + infoPtr->nReshowTime = nTime / 5; + infoPtr->nAutoPopTime = nTime * 10; + infoPtr->nInitialTime = nTime; + break; + + case TTDT_RESHOW: + if(nTime < 0) + nTime = GetDoubleClickTime() / 5; + infoPtr->nReshowTime = nTime; + break; + + case TTDT_AUTOPOP: + if(nTime < 0) + nTime = GetDoubleClickTime() * 10; + infoPtr->nAutoPopTime = nTime; + break; + + case TTDT_INITIAL: + if(nTime < 0) + nTime = GetDoubleClickTime(); + infoPtr->nInitialTime = nTime; + break; + + default: + WARN("Invalid wParam %x\n", wParam); + break; + } + + return 0; +} + + +static LRESULT +TOOLTIPS_SetMargin (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPRECT lpRect = (LPRECT)lParam; + + infoPtr->rcMargin.left = lpRect->left; + infoPtr->rcMargin.right = lpRect->right; + infoPtr->rcMargin.bottom = lpRect->bottom; + infoPtr->rcMargin.top = lpRect->top; + + return 0; +} + + +inline static LRESULT +TOOLTIPS_SetMaxTipWidth (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + INT nTemp = infoPtr->nMaxTipWidth; + + infoPtr->nMaxTipWidth = (INT)lParam; + + return nTemp; +} + + +inline static LRESULT +TOOLTIPS_SetTipBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + + infoPtr->clrBk = (COLORREF)wParam; + + return 0; +} + + +inline static LRESULT +TOOLTIPS_SetTipTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + + infoPtr->clrText = (COLORREF)wParam; + + return 0; +} + + +static LRESULT +TOOLTIPS_SetTitleA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPCSTR pszTitle = (LPCSTR)lParam; + UINT_PTR uTitleIcon = (UINT_PTR)wParam; + UINT size; + + TRACE("hwnd = %p, title = %s, icon = %p\n", hwnd, debugstr_a(pszTitle), + (void*)uTitleIcon); + + Free(infoPtr->pszTitle); + + if (pszTitle) + { + size = sizeof(WCHAR)*MultiByteToWideChar(CP_ACP, 0, pszTitle, -1, NULL, 0); + infoPtr->pszTitle = Alloc(size); + if (!infoPtr->pszTitle) + return FALSE; + MultiByteToWideChar(CP_ACP, 0, pszTitle, -1, infoPtr->pszTitle, size/sizeof(WCHAR)); + } + else + infoPtr->pszTitle = NULL; + + if (uTitleIcon <= TTI_ERROR) + infoPtr->hTitleIcon = hTooltipIcons[uTitleIcon]; + else + infoPtr->hTitleIcon = CopyIcon((HICON)wParam); + + return TRUE; +} + + +static LRESULT +TOOLTIPS_SetTitleW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPCWSTR pszTitle = (LPCWSTR)lParam; + UINT_PTR uTitleIcon = (UINT_PTR)wParam; + UINT size; + + TRACE("hwnd = %p, title = %s, icon = %p\n", hwnd, debugstr_w(pszTitle), + (void*)uTitleIcon); + + Free(infoPtr->pszTitle); + + if (pszTitle) + { + size = (strlenW(pszTitle)+1)*sizeof(WCHAR); + infoPtr->pszTitle = Alloc(size); + if (!infoPtr->pszTitle) + return FALSE; + memcpy(infoPtr->pszTitle, pszTitle, size); + } + else + infoPtr->pszTitle = NULL; + + if (uTitleIcon <= TTI_ERROR) + infoPtr->hTitleIcon = hTooltipIcons[uTitleIcon]; + else + infoPtr->hTitleIcon = CopyIcon((HICON)wParam); + + TRACE("icon = %p\n", infoPtr->hTitleIcon); + + return TRUE; +} + + +static LRESULT +TOOLTIPS_SetToolInfoA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam; + TTTOOL_INFO *toolPtr; + INT nTool; + + if (lpToolInfo == NULL) + return 0; + if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE) + return 0; + + nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo); + if (nTool == -1) return 0; + + TRACE("tool %d\n", nTool); + + toolPtr = &infoPtr->tools[nTool]; + + /* copy tool data */ + toolPtr->uFlags = lpToolInfo->uFlags; + toolPtr->hwnd = lpToolInfo->hwnd; + toolPtr->uId = lpToolInfo->uId; + toolPtr->rect = lpToolInfo->rect; + toolPtr->hinst = lpToolInfo->hinst; + + if (HIWORD(lpToolInfo->lpszText) == 0) { + TRACE("set string id %x!\n", (INT)lpToolInfo->lpszText); + toolPtr->lpszText = (LPWSTR)lpToolInfo->lpszText; + } + else if (lpToolInfo->lpszText) { + if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKA) + toolPtr->lpszText = LPSTR_TEXTCALLBACKW; + else { + if ( (toolPtr->lpszText) && + (HIWORD((INT)toolPtr->lpszText) != 0) ) { + Free (toolPtr->lpszText); + toolPtr->lpszText = NULL; + } + if (lpToolInfo->lpszText) { + INT len = MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, + -1, NULL, 0); + toolPtr->lpszText = Alloc (len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1, + toolPtr->lpszText, len); + } + } + } + + if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOA)) + toolPtr->lParam = lpToolInfo->lParam; + + return 0; +} + + +static LRESULT +TOOLTIPS_SetToolInfoW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam; + TTTOOL_INFO *toolPtr; + INT nTool; + + if (lpToolInfo == NULL) + return 0; + if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE) + return 0; + + nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo); + if (nTool == -1) return 0; + + TRACE("tool %d\n", nTool); + + toolPtr = &infoPtr->tools[nTool]; + + /* copy tool data */ + toolPtr->uFlags = lpToolInfo->uFlags; + toolPtr->hwnd = lpToolInfo->hwnd; + toolPtr->uId = lpToolInfo->uId; + toolPtr->rect = lpToolInfo->rect; + toolPtr->hinst = lpToolInfo->hinst; + + if (HIWORD(lpToolInfo->lpszText) == 0) { + TRACE("set string id %x!\n", (INT)lpToolInfo->lpszText); + toolPtr->lpszText = lpToolInfo->lpszText; + } + else { + if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKW) + toolPtr->lpszText = LPSTR_TEXTCALLBACKW; + else { + if ( (toolPtr->lpszText) && + (HIWORD((INT)toolPtr->lpszText) != 0) ) { + Free (toolPtr->lpszText); + toolPtr->lpszText = NULL; + } + if (lpToolInfo->lpszText) { + INT len = lstrlenW (lpToolInfo->lpszText); + toolPtr->lpszText = Alloc ((len+1)*sizeof(WCHAR)); + strcpyW (toolPtr->lpszText, lpToolInfo->lpszText); + } + } + } + + if (lpToolInfo->cbSize >= sizeof(TTTOOLINFOW)) + toolPtr->lParam = lpToolInfo->lParam; + + if (infoPtr->nCurrentTool == nTool) + { + TOOLTIPS_GetTipText (hwnd, infoPtr, infoPtr->nCurrentTool); + + if (infoPtr->szTipText[0] == 0) + TOOLTIPS_Hide(hwnd, infoPtr); + else + TOOLTIPS_Show (hwnd, infoPtr); + } + + return 0; +} + + +static LRESULT +TOOLTIPS_TrackActivate (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + + if ((BOOL)wParam) { + LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam; + + if (lpToolInfo == NULL) + return 0; + if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE) + return FALSE; + + /* activate */ + infoPtr->nTrackTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo); + if (infoPtr->nTrackTool != -1) { + TRACE("activated!\n"); + infoPtr->bTrackActive = TRUE; + TOOLTIPS_TrackShow (hwnd, infoPtr); + } + } + else { + /* deactivate */ + TOOLTIPS_TrackHide (hwnd, infoPtr); + + infoPtr->bTrackActive = FALSE; + infoPtr->nTrackTool = -1; + + TRACE("deactivated!\n"); + } + + return 0; +} + + +static LRESULT +TOOLTIPS_TrackPosition (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + + infoPtr->xTrackPos = (INT)LOWORD(lParam); + infoPtr->yTrackPos = (INT)HIWORD(lParam); + + if (infoPtr->bTrackActive) { + TRACE("[%d %d]\n", + infoPtr->xTrackPos, infoPtr->yTrackPos); + + TOOLTIPS_TrackShow (hwnd, infoPtr); + } + + return 0; +} + + +static LRESULT +TOOLTIPS_Update (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + + if (infoPtr->nCurrentTool != -1) + UpdateWindow (hwnd); + + return 0; +} + + +static LRESULT +TOOLTIPS_UpdateTipTextA (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPTTTOOLINFOA lpToolInfo = (LPTTTOOLINFOA)lParam; + TTTOOL_INFO *toolPtr; + INT nTool; + + if (lpToolInfo == NULL) + return 0; + if (lpToolInfo->cbSize < TTTOOLINFOA_V1_SIZE) + return FALSE; + + nTool = TOOLTIPS_GetToolFromInfoA (infoPtr, lpToolInfo); + if (nTool == -1) return 0; + + TRACE("tool %d\n", nTool); + + toolPtr = &infoPtr->tools[nTool]; + + /* copy tool text */ + toolPtr->hinst = lpToolInfo->hinst; + + if (HIWORD(lpToolInfo->lpszText) == 0){ + toolPtr->lpszText = (LPWSTR)lpToolInfo->lpszText; + } + else if (lpToolInfo->lpszText) { + if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKA) + toolPtr->lpszText = LPSTR_TEXTCALLBACKW; + else { + if ( (toolPtr->lpszText) && + (HIWORD((INT)toolPtr->lpszText) != 0) ) { + Free (toolPtr->lpszText); + toolPtr->lpszText = NULL; + } + if (lpToolInfo->lpszText) { + INT len = MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, + -1, NULL, 0); + toolPtr->lpszText = Alloc (len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, lpToolInfo->lpszText, -1, + toolPtr->lpszText, len); + } + } + } + + if(infoPtr->nCurrentTool == -1) return 0; + /* force repaint */ + if (infoPtr->bActive) + TOOLTIPS_Show (hwnd, infoPtr); + else if (infoPtr->bTrackActive) + TOOLTIPS_TrackShow (hwnd, infoPtr); + + return 0; +} + + +static LRESULT +TOOLTIPS_UpdateTipTextW (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LPTTTOOLINFOW lpToolInfo = (LPTTTOOLINFOW)lParam; + TTTOOL_INFO *toolPtr; + INT nTool; + + if (lpToolInfo == NULL) + return 0; + if (lpToolInfo->cbSize < TTTOOLINFOW_V1_SIZE) + return FALSE; + + nTool = TOOLTIPS_GetToolFromInfoW (infoPtr, lpToolInfo); + if (nTool == -1) + return 0; + + TRACE("tool %d\n", nTool); + + toolPtr = &infoPtr->tools[nTool]; + + /* copy tool text */ + toolPtr->hinst = lpToolInfo->hinst; + + if (HIWORD(lpToolInfo->lpszText) == 0){ + toolPtr->lpszText = lpToolInfo->lpszText; + } + else if (lpToolInfo->lpszText) { + if (lpToolInfo->lpszText == LPSTR_TEXTCALLBACKW) + toolPtr->lpszText = LPSTR_TEXTCALLBACKW; + else { + if ( (toolPtr->lpszText) && + (HIWORD((INT)toolPtr->lpszText) != 0) ) { + Free (toolPtr->lpszText); + toolPtr->lpszText = NULL; + } + if (lpToolInfo->lpszText) { + INT len = lstrlenW (lpToolInfo->lpszText); + toolPtr->lpszText = Alloc ((len+1)*sizeof(WCHAR)); + strcpyW (toolPtr->lpszText, lpToolInfo->lpszText); + } + } + } + + if(infoPtr->nCurrentTool == -1) return 0; + /* force repaint */ + if (infoPtr->bActive) + TOOLTIPS_Show (hwnd, infoPtr); + else if (infoPtr->bTrackActive) + TOOLTIPS_TrackShow (hwnd, infoPtr); + + return 0; +} + + +static LRESULT +TOOLTIPS_WindowFromPoint (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + return (LRESULT)WindowFromPoint (*((LPPOINT)lParam)); +} + + + +static LRESULT +TOOLTIPS_Create (HWND hwnd, const CREATESTRUCTW *lpcs) +{ + TOOLTIPS_INFO *infoPtr; + + /* allocate memory for info structure */ + infoPtr = (TOOLTIPS_INFO *)Alloc (sizeof(TOOLTIPS_INFO)); + SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); + + /* initialize info structure */ + infoPtr->bActive = TRUE; + infoPtr->bTrackActive = FALSE; + + infoPtr->nMaxTipWidth = -1; + infoPtr->nTool = -1; + infoPtr->nCurrentTool = -1; + infoPtr->nTrackTool = -1; + + /* initialize colours and fonts */ + TOOLTIPS_InitSystemSettings(infoPtr); + + TOOLTIPS_SetDelayTime(hwnd, TTDT_AUTOMATIC, 0L); + + SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOZORDER | SWP_HIDEWINDOW | SWP_NOACTIVATE); + + return 0; +} + + +static LRESULT +TOOLTIPS_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + TTTOOL_INFO *toolPtr; + UINT i; + + /* free tools */ + if (infoPtr->tools) { + for (i = 0; i < infoPtr->uNumTools; i++) { + toolPtr = &infoPtr->tools[i]; + if (toolPtr->lpszText) { + if ( (toolPtr->lpszText != LPSTR_TEXTCALLBACKW) && + (HIWORD((INT)toolPtr->lpszText) != 0) ) + { + Free (toolPtr->lpszText); + toolPtr->lpszText = NULL; + } + } + + /* remove subclassing */ + if (toolPtr->uFlags & TTF_SUBCLASS) { + if (toolPtr->uFlags & TTF_IDISHWND) { + RemoveWindowSubclass((HWND)toolPtr->uId, TOOLTIPS_SubclassProc, 1); + } + else { + RemoveWindowSubclass(toolPtr->hwnd, TOOLTIPS_SubclassProc, 1); + } + } + } + Free (infoPtr->tools); + } + + /* free title string */ + Free (infoPtr->pszTitle); + /* free title icon if not a standard one */ + if (TOOLTIPS_GetTitleIconIndex(infoPtr->hTitleIcon) > TTI_ERROR) + DeleteObject(infoPtr->hTitleIcon); + + /* delete fonts */ + DeleteObject (infoPtr->hFont); + DeleteObject (infoPtr->hTitleFont); + + /* free tool tips info data */ + Free (infoPtr); + SetWindowLongPtrW(hwnd, 0, 0); + return 0; +} + + +static LRESULT +TOOLTIPS_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + + return (LRESULT)infoPtr->hFont; +} + + +static LRESULT +TOOLTIPS_MouseMessage (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + + TOOLTIPS_Hide (hwnd, infoPtr); + + return 0; +} + + +static LRESULT +TOOLTIPS_NCCreate (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE); + DWORD dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE); + + dwStyle &= 0x0000FFFF; + dwStyle |= (WS_POPUP | WS_BORDER | WS_CLIPSIBLINGS); + + /* WS_BORDER only draws a border round the window rect, not the + * window region, therefore it is useless to us in balloon mode */ + if (dwStyle & TTS_BALLOON) dwStyle &= ~WS_BORDER; + + SetWindowLongW (hwnd, GWL_STYLE, dwStyle); + + dwExStyle |= WS_EX_TOOLWINDOW; + SetWindowLongW (hwnd, GWL_EXSTYLE, dwExStyle); + + return TRUE; +} + + +static LRESULT +TOOLTIPS_NCHitTest (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + INT nTool = (infoPtr->bTrackActive) ? infoPtr->nTrackTool : infoPtr->nTool; + + TRACE(" nTool=%d\n", nTool); + + if ((nTool > -1) && (nTool < infoPtr->uNumTools)) { + if (infoPtr->tools[nTool].uFlags & TTF_TRANSPARENT) { + TRACE("-- in transparent mode!\n"); + return HTTRANSPARENT; + } + } + + return DefWindowProcW (hwnd, WM_NCHITTEST, wParam, lParam); +} + + +static LRESULT +TOOLTIPS_NotifyFormat (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + FIXME ("hwnd=%p wParam=%x lParam=%lx\n", hwnd, wParam, lParam); + + return 0; +} + + +static LRESULT +TOOLTIPS_Paint (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + HDC hdc; + PAINTSTRUCT ps; + + hdc = (wParam == 0) ? BeginPaint (hwnd, &ps) : (HDC)wParam; + TOOLTIPS_Refresh (hwnd, hdc); + if (!wParam) + EndPaint (hwnd, &ps); + return 0; +} + + +static LRESULT +TOOLTIPS_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LOGFONTW lf; + + if(!GetObjectW((HFONT)wParam, sizeof(lf), &lf)) + return 0; + + DeleteObject (infoPtr->hFont); + infoPtr->hFont = CreateFontIndirectW(&lf); + + DeleteObject (infoPtr->hTitleFont); + lf.lfWeight = FW_BOLD; + infoPtr->hTitleFont = CreateFontIndirectW(&lf); + + if ((LOWORD(lParam)) & (infoPtr->nCurrentTool != -1)) { + FIXME("full redraw needed!\n"); + } + + return 0; +} + +/****************************************************************** + * TOOLTIPS_GetTextLength + * + * This function is called when the tooltip receive a + * WM_GETTEXTLENGTH message. + * wParam : not used + * lParam : not used + * + * returns the length, in characters, of the tip text + */ +static LRESULT +TOOLTIPS_GetTextLength(HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + return strlenW(infoPtr->szTipText); +} + +/****************************************************************** + * TOOLTIPS_OnWMGetText + * + * This function is called when the tooltip receive a + * WM_GETTEXT message. + * wParam : specifies the maximum number of characters to be copied + * lParam : is the pointer to the buffer that will receive + * the tip text + * + * returns the number of characters copied + */ +static LRESULT +TOOLTIPS_OnWMGetText (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + LRESULT res; + LPWSTR pszText = (LPWSTR)lParam; + + if(!infoPtr->szTipText || !wParam) + return 0; + + res = min(strlenW(infoPtr->szTipText)+1, wParam); + memcpy(pszText, infoPtr->szTipText, res*sizeof(WCHAR)); + pszText[res-1] = '\0'; + return res-1; +} + +static LRESULT +TOOLTIPS_Timer (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + INT nOldTool; + + TRACE("timer %d (%p) expired!\n", wParam, hwnd); + + switch (wParam) { + case ID_TIMERSHOW: + KillTimer (hwnd, ID_TIMERSHOW); + nOldTool = infoPtr->nTool; + if ((infoPtr->nTool = TOOLTIPS_CheckTool (hwnd, TRUE)) == nOldTool) + TOOLTIPS_Show (hwnd, infoPtr); + break; + + case ID_TIMERPOP: + TOOLTIPS_Hide (hwnd, infoPtr); + break; + + case ID_TIMERLEAVE: + nOldTool = infoPtr->nTool; + infoPtr->nTool = TOOLTIPS_CheckTool (hwnd, FALSE); + TRACE("tool (%p) %d %d %d\n", hwnd, nOldTool, + infoPtr->nTool, infoPtr->nCurrentTool); + if (infoPtr->nTool != nOldTool) { + if(infoPtr->nTool == -1) { /* Moved out of all tools */ + TOOLTIPS_Hide(hwnd, infoPtr); + KillTimer(hwnd, ID_TIMERLEAVE); + } else if (nOldTool == -1) { /* Moved from outside */ + ERR("How did this happen?\n"); + } else { /* Moved from one to another */ + TOOLTIPS_Hide (hwnd, infoPtr); + KillTimer(hwnd, ID_TIMERLEAVE); + if(infoPtr->bActive) { + SetTimer (hwnd, ID_TIMERSHOW, infoPtr->nReshowTime, 0); + TRACE("timer 1 started!\n"); + } + } + } + break; + + default: + ERR("Unknown timer id %d\n", wParam); + break; + } + return 0; +} + + +static LRESULT +TOOLTIPS_WinIniChange (HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); + + TOOLTIPS_InitSystemSettings (infoPtr); + + return 0; +} + + +static LRESULT CALLBACK +TOOLTIPS_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uID, DWORD_PTR dwRef) +{ + MSG msg; + + switch(uMsg) { + case WM_MOUSEMOVE: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + msg.hwnd = hwnd; + msg.message = uMsg; + msg.wParam = wParam; + msg.lParam = lParam; + TOOLTIPS_RelayEvent((HWND)dwRef, 0, (LPARAM)&msg); + break; + + default: + break; + } + return DefSubclassProc(hwnd, uMsg, wParam, lParam); +} + + +static LRESULT CALLBACK +TOOLTIPS_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + TRACE("hwnd=%p msg=%x wparam=%x lParam=%lx\n", hwnd, uMsg, wParam, lParam); + if (!TOOLTIPS_GetInfoPtr(hwnd) && (uMsg != WM_CREATE) && (uMsg != WM_NCCREATE)) + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + switch (uMsg) + { + case TTM_ACTIVATE: + return TOOLTIPS_Activate (hwnd, wParam, lParam); + + case TTM_ADDTOOLA: + return TOOLTIPS_AddToolA (hwnd, wParam, lParam); + + case TTM_ADDTOOLW: + return TOOLTIPS_AddToolW (hwnd, wParam, lParam); + + case TTM_DELTOOLA: + return TOOLTIPS_DelToolA (hwnd, wParam, lParam); + + case TTM_DELTOOLW: + return TOOLTIPS_DelToolW (hwnd, wParam, lParam); + + case TTM_ENUMTOOLSA: + return TOOLTIPS_EnumToolsA (hwnd, wParam, lParam); + + case TTM_ENUMTOOLSW: + return TOOLTIPS_EnumToolsW (hwnd, wParam, lParam); + + case TTM_GETBUBBLESIZE: + return TOOLTIPS_GetBubbleSize (hwnd, wParam, lParam); + + case TTM_GETCURRENTTOOLA: + return TOOLTIPS_GetCurrentToolA (hwnd, wParam, lParam); + + case TTM_GETCURRENTTOOLW: + return TOOLTIPS_GetCurrentToolW (hwnd, wParam, lParam); + + case TTM_GETDELAYTIME: + return TOOLTIPS_GetDelayTime (hwnd, wParam, lParam); + + case TTM_GETMARGIN: + return TOOLTIPS_GetMargin (hwnd, wParam, lParam); + + case TTM_GETMAXTIPWIDTH: + return TOOLTIPS_GetMaxTipWidth (hwnd, wParam, lParam); + + case TTM_GETTEXTA: + return TOOLTIPS_GetTextA (hwnd, wParam, lParam); + + case TTM_GETTEXTW: + return TOOLTIPS_GetTextW (hwnd, wParam, lParam); + + case TTM_GETTIPBKCOLOR: + return TOOLTIPS_GetTipBkColor (hwnd, wParam, lParam); + + case TTM_GETTIPTEXTCOLOR: + return TOOLTIPS_GetTipTextColor (hwnd, wParam, lParam); + + case TTM_GETTOOLCOUNT: + return TOOLTIPS_GetToolCount (hwnd, wParam, lParam); + + case TTM_GETTOOLINFOA: + return TOOLTIPS_GetToolInfoA (hwnd, wParam, lParam); + + case TTM_GETTOOLINFOW: + return TOOLTIPS_GetToolInfoW (hwnd, wParam, lParam); + + case TTM_HITTESTA: + return TOOLTIPS_HitTestA (hwnd, wParam, lParam); + + case TTM_HITTESTW: + return TOOLTIPS_HitTestW (hwnd, wParam, lParam); + + case TTM_NEWTOOLRECTA: + return TOOLTIPS_NewToolRectA (hwnd, wParam, lParam); + + case TTM_NEWTOOLRECTW: + return TOOLTIPS_NewToolRectW (hwnd, wParam, lParam); + + case TTM_POP: + return TOOLTIPS_Pop (hwnd, wParam, lParam); + + case TTM_RELAYEVENT: + return TOOLTIPS_RelayEvent (hwnd, wParam, lParam); + + case TTM_SETDELAYTIME: + return TOOLTIPS_SetDelayTime (hwnd, wParam, lParam); + + case TTM_SETMARGIN: + return TOOLTIPS_SetMargin (hwnd, wParam, lParam); + + case TTM_SETMAXTIPWIDTH: + return TOOLTIPS_SetMaxTipWidth (hwnd, wParam, lParam); + + case TTM_SETTIPBKCOLOR: + return TOOLTIPS_SetTipBkColor (hwnd, wParam, lParam); + + case TTM_SETTIPTEXTCOLOR: + return TOOLTIPS_SetTipTextColor (hwnd, wParam, lParam); + + case TTM_SETTITLEA: + return TOOLTIPS_SetTitleA (hwnd, wParam, lParam); + + case TTM_SETTITLEW: + return TOOLTIPS_SetTitleW (hwnd, wParam, lParam); + + case TTM_SETTOOLINFOA: + return TOOLTIPS_SetToolInfoA (hwnd, wParam, lParam); + + case TTM_SETTOOLINFOW: + return TOOLTIPS_SetToolInfoW (hwnd, wParam, lParam); + + case TTM_TRACKACTIVATE: + return TOOLTIPS_TrackActivate (hwnd, wParam, lParam); + + case TTM_TRACKPOSITION: + return TOOLTIPS_TrackPosition (hwnd, wParam, lParam); + + case TTM_UPDATE: + return TOOLTIPS_Update (hwnd, wParam, lParam); + + case TTM_UPDATETIPTEXTA: + return TOOLTIPS_UpdateTipTextA (hwnd, wParam, lParam); + + case TTM_UPDATETIPTEXTW: + return TOOLTIPS_UpdateTipTextW (hwnd, wParam, lParam); + + case TTM_WINDOWFROMPOINT: + return TOOLTIPS_WindowFromPoint (hwnd, wParam, lParam); + + + case WM_CREATE: + return TOOLTIPS_Create (hwnd, (LPCREATESTRUCTW)lParam); + + case WM_DESTROY: + return TOOLTIPS_Destroy (hwnd, wParam, lParam); + + case WM_ERASEBKGND: + /* we draw the background in WM_PAINT */ + return 0; + + case WM_GETFONT: + return TOOLTIPS_GetFont (hwnd, wParam, lParam); + + case WM_GETTEXT: + return TOOLTIPS_OnWMGetText (hwnd, wParam, lParam); + + case WM_GETTEXTLENGTH: + return TOOLTIPS_GetTextLength (hwnd, wParam, lParam); + + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_MOUSEMOVE: + return TOOLTIPS_MouseMessage (hwnd, uMsg, wParam, lParam); + + case WM_NCCREATE: + return TOOLTIPS_NCCreate (hwnd, wParam, lParam); + + case WM_NCHITTEST: + return TOOLTIPS_NCHitTest (hwnd, wParam, lParam); + + case WM_NOTIFYFORMAT: + return TOOLTIPS_NotifyFormat (hwnd, wParam, lParam); + + case WM_PAINT: + return TOOLTIPS_Paint (hwnd, wParam, lParam); + + case WM_SETFONT: + return TOOLTIPS_SetFont (hwnd, wParam, lParam); + + case WM_TIMER: + return TOOLTIPS_Timer (hwnd, wParam, lParam); + + case WM_WININICHANGE: + return TOOLTIPS_WinIniChange (hwnd, wParam, lParam); + + default: + if ((uMsg >= WM_USER) && (uMsg < WM_APP)) + ERR("unknown msg %04x wp=%08x lp=%08lx\n", + uMsg, wParam, lParam); + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + } +} + + +VOID +TOOLTIPS_Register (void) +{ + WNDCLASSW wndClass; + + ZeroMemory (&wndClass, sizeof(WNDCLASSW)); + wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS; + wndClass.lpfnWndProc = TOOLTIPS_WindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(TOOLTIPS_INFO *); + wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); + wndClass.hbrBackground = 0; + wndClass.lpszClassName = TOOLTIPS_CLASSW; + + RegisterClassW (&wndClass); + + hTooltipIcons[TTI_NONE] = NULL; + hTooltipIcons[TTI_INFO] = LoadImageW(COMCTL32_hModule, + (LPCWSTR)MAKEINTRESOURCE(IDI_TT_INFO_SM), IMAGE_ICON, 0, 0, 0); + hTooltipIcons[TTI_WARNING] = LoadImageW(COMCTL32_hModule, + (LPCWSTR)MAKEINTRESOURCE(IDI_TT_WARN_SM), IMAGE_ICON, 0, 0, 0); + hTooltipIcons[TTI_ERROR] = LoadImageW(COMCTL32_hModule, + (LPCWSTR)MAKEINTRESOURCE(IDI_TT_ERROR_SM), IMAGE_ICON, 0, 0, 0); +} + + +VOID +TOOLTIPS_Unregister (void) +{ + int i; + for (i = TTI_INFO; i <= TTI_ERROR; i++) + DestroyIcon(hTooltipIcons[i]); + UnregisterClassW (TOOLTIPS_CLASSW, NULL); +} diff --git a/reactos/lib/comctl32/trackbar.c b/reactos/lib/comctl32/trackbar.c index 6c291e55c1f..2972c840842 100644 --- a/reactos/lib/comctl32/trackbar.c +++ b/reactos/lib/comctl32/trackbar.c @@ -1,1827 +1,1827 @@ -/* - * Trackbar control - * - * Copyright 1998, 1999 Eric Kohl - * Copyright 1998, 1999 Alex Priem - * Copyright 2002 Dimitrie O. Paun - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTE - * - * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on Sep. 12, 2002, by Dimitrie O. Paun. - * - * Unless otherwise noted, we believe this code to be complete, as per - * the specification mentioned above. - * If you discover missing features, or bugs, please note them below. - * - */ - -#include -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "wine/debug.h" - -#include "comctl32.h" - -WINE_DEFAULT_DEBUG_CHANNEL(trackbar); - -typedef struct -{ - HWND hwndSelf; - LONG lRangeMin; - LONG lRangeMax; - LONG lLineSize; - LONG lPageSize; - LONG lSelMin; - LONG lSelMax; - LONG lPos; - UINT uThumbLen; - UINT uNumTics; - UINT uTicFreq; - HWND hwndNotify; - HWND hwndToolTip; - HWND hwndBuddyLA; - HWND hwndBuddyRB; - INT fLocation; - INT flags; - BOOL bUnicode; - BOOL bFocussed; - RECT rcChannel; - RECT rcSelection; - RECT rcThumb; - LPLONG tics; -} TRACKBAR_INFO; - -#define TB_REFRESH_TIMER 1 -#define TB_REFRESH_DELAY 500 - -#define TOOLTIP_OFFSET 2 /* distance from ctrl edge to tooltip */ - -/* Used by TRACKBAR_Refresh to find out which parts of the control - need to be recalculated */ - -#define TB_THUMBPOSCHANGED 1 -#define TB_THUMBSIZECHANGED 2 -#define TB_THUMBCHANGED (TB_THUMBPOSCHANGED | TB_THUMBSIZECHANGED) -#define TB_SELECTIONCHANGED 4 -#define TB_DRAG_MODE 8 /* we're dragging the slider */ -#define TB_AUTO_PAGE_LEFT 16 -#define TB_AUTO_PAGE_RIGHT 32 -#define TB_AUTO_PAGE (TB_AUTO_PAGE_LEFT | TB_AUTO_PAGE_RIGHT) - -/* helper defines for TRACKBAR_DrawTic */ -#define TIC_EDGE 0x20 -#define TIC_SELECTIONMARKMAX 0x80 -#define TIC_SELECTIONMARKMIN 0x100 -#define TIC_SELECTIONMARK (TIC_SELECTIONMARKMAX | TIC_SELECTIONMARKMIN) - -static inline int -notify_customdraw(TRACKBAR_INFO *infoPtr, NMCUSTOMDRAW *pnmcd, int stage) -{ - pnmcd->dwDrawStage = stage; - return SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, - pnmcd->hdr.idFrom, (LPARAM)pnmcd); -} - -static LRESULT notify_hdr(TRACKBAR_INFO *infoPtr, INT code, LPNMHDR pnmh) -{ - LRESULT result; - - TRACE("(code=%d)\n", code); - - pnmh->hwndFrom = infoPtr->hwndSelf; - pnmh->idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); - pnmh->code = code; - result = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, - (WPARAM)pnmh->idFrom, (LPARAM)pnmh); - - TRACE(" <= %ld\n", result); - - return result; -} - -static inline int notify(TRACKBAR_INFO *infoPtr, INT code) -{ - NMHDR nmh; - return notify_hdr(infoPtr, code, &nmh); -} - -static BOOL -notify_with_scroll (TRACKBAR_INFO *infoPtr, UINT code) -{ - BOOL bVert = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_VERT; - - TRACE("%x\n", code); - - return (BOOL) SendMessageW (infoPtr->hwndNotify, - bVert ? WM_VSCROLL : WM_HSCROLL, - (WPARAM)code, (LPARAM)infoPtr->hwndSelf); -} - -static void TRACKBAR_RecalculateTics (TRACKBAR_INFO *infoPtr) -{ - int i, tic, nrTics; - - if (infoPtr->uTicFreq && infoPtr->lRangeMax >= infoPtr->lRangeMin) - nrTics=(infoPtr->lRangeMax - infoPtr->lRangeMin)/infoPtr->uTicFreq; - else { - nrTics = 0; - Free (infoPtr->tics); - infoPtr->tics = NULL; - infoPtr->uNumTics = 0; - return; - } - - if (nrTics != infoPtr->uNumTics) { - infoPtr->tics=ReAlloc (infoPtr->tics, - (nrTics+1)*sizeof (DWORD)); - if (!infoPtr->tics) { - infoPtr->uNumTics = 0; - notify(infoPtr, NM_OUTOFMEMORY); - return; - } - infoPtr->uNumTics = nrTics; - } - - tic = infoPtr->lRangeMin + infoPtr->uTicFreq; - for (i = 0; i < nrTics; i++, tic += infoPtr->uTicFreq) - infoPtr->tics[i] = tic; -} - -/* converts from physical (mouse) position to logical position - (in range of trackbar) */ - -static inline LONG -TRACKBAR_ConvertPlaceToPosition (TRACKBAR_INFO *infoPtr, int place, - int vertical) -{ - double range, width, pos, offsetthumb; - - range = infoPtr->lRangeMax - infoPtr->lRangeMin; - if (vertical) { - offsetthumb = (infoPtr->rcThumb.bottom - infoPtr->rcThumb.top)/2; - width = infoPtr->rcChannel.bottom - infoPtr->rcChannel.top - (offsetthumb * 2) - 1; - pos = (range*(place - infoPtr->rcChannel.top - offsetthumb)) / width; - } else { - offsetthumb = (infoPtr->rcThumb.right - infoPtr->rcThumb.left)/2; - width = infoPtr->rcChannel.right - infoPtr->rcChannel.left - (offsetthumb * 2) - 1; - pos = (range*(place - infoPtr->rcChannel.left - offsetthumb)) / width; - } - pos += infoPtr->lRangeMin; - if (pos > infoPtr->lRangeMax) - pos = infoPtr->lRangeMax; - else if (pos < infoPtr->lRangeMin) - pos = infoPtr->lRangeMin; - - TRACE("%.2f\n", pos); - return (LONG)(pos + 0.5); -} - - -/* return: 0> prev, 0 none, >0 next */ -static LONG -TRACKBAR_GetAutoPageDirection (TRACKBAR_INFO *infoPtr, POINT clickPoint) -{ - DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE); - RECT pageRect; - - if (dwStyle & TBS_VERT) { - pageRect.top = infoPtr->rcChannel.top; - pageRect.bottom = infoPtr->rcChannel.bottom; - pageRect.left = infoPtr->rcThumb.left; - pageRect.right = infoPtr->rcThumb.right; - } else { - pageRect.top = infoPtr->rcThumb.top; - pageRect.bottom = infoPtr->rcThumb.bottom; - pageRect.left = infoPtr->rcChannel.left; - pageRect.right = infoPtr->rcChannel.right; - } - - - if (PtInRect(&pageRect, clickPoint)) - { - int clickPlace = (dwStyle & TBS_VERT) ? clickPoint.y : clickPoint.x; - - LONG clickPos = TRACKBAR_ConvertPlaceToPosition(infoPtr, clickPlace, - dwStyle & TBS_VERT); - return clickPos - infoPtr->lPos; - } - - return 0; -} - -static void inline -TRACKBAR_PageDown (TRACKBAR_INFO *infoPtr) -{ - if (infoPtr->lPos == infoPtr->lRangeMax) return; - - infoPtr->lPos += infoPtr->lPageSize; - if (infoPtr->lPos > infoPtr->lRangeMax) - infoPtr->lPos = infoPtr->lRangeMax; - notify_with_scroll (infoPtr, TB_PAGEDOWN); -} - - -static void inline -TRACKBAR_PageUp (TRACKBAR_INFO *infoPtr) -{ - if (infoPtr->lPos == infoPtr->lRangeMin) return; - - infoPtr->lPos -= infoPtr->lPageSize; - if (infoPtr->lPos < infoPtr->lRangeMin) - infoPtr->lPos = infoPtr->lRangeMin; - notify_with_scroll (infoPtr, TB_PAGEUP); -} - -static void inline TRACKBAR_LineUp(TRACKBAR_INFO *infoPtr) -{ - if (infoPtr->lPos == infoPtr->lRangeMin) return; - infoPtr->lPos -= infoPtr->lLineSize; - if (infoPtr->lPos < infoPtr->lRangeMin) - infoPtr->lPos = infoPtr->lRangeMin; - notify_with_scroll (infoPtr, TB_LINEUP); -} - -static void inline TRACKBAR_LineDown(TRACKBAR_INFO *infoPtr) -{ - if (infoPtr->lPos == infoPtr->lRangeMax) return; - infoPtr->lPos += infoPtr->lLineSize; - if (infoPtr->lPos > infoPtr->lRangeMax) - infoPtr->lPos = infoPtr->lRangeMax; - notify_with_scroll (infoPtr, TB_LINEDOWN); -} - -static void -TRACKBAR_CalcChannel (TRACKBAR_INFO *infoPtr) -{ - DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE); - INT cyChannel, offsetthumb, offsetedge; - RECT lpRect, *channel = & infoPtr->rcChannel; - - GetClientRect (infoPtr->hwndSelf, &lpRect); - - offsetthumb = infoPtr->uThumbLen / 4; - offsetedge = offsetthumb + 3; - cyChannel = (dwStyle & TBS_ENABLESELRANGE) ? offsetthumb*3 : 4; - if (dwStyle & TBS_VERT) { - channel->top = lpRect.top + offsetedge; - channel->bottom = lpRect.bottom - offsetedge; - if (dwStyle & TBS_ENABLESELRANGE) - channel->left = lpRect.left + ((infoPtr->uThumbLen - cyChannel + 2) / 2); - else - channel->left = lpRect.left + (infoPtr->uThumbLen / 2) - 1; - if (dwStyle & TBS_BOTH) { - if (dwStyle & TBS_NOTICKS) - channel->left += 1; - else - channel->left += 9; - } - else if (dwStyle & TBS_TOP) { - if (dwStyle & TBS_NOTICKS) - channel->left += 2; - else - channel->left += 10; - } - channel->right = channel->left + cyChannel; - } else { - channel->left = lpRect.left + offsetedge; - channel->right = lpRect.right - offsetedge; - if (dwStyle & TBS_ENABLESELRANGE) - channel->top = lpRect.top + ((infoPtr->uThumbLen - cyChannel + 2) / 2); - else - channel->top = lpRect.top + (infoPtr->uThumbLen / 2) - 1; - if (dwStyle & TBS_BOTH) { - if (dwStyle & TBS_NOTICKS) - channel->top += 1; - else - channel->top += 9; - } - else if (dwStyle & TBS_TOP) { - if (dwStyle & TBS_NOTICKS) - channel->top += 2; - else - channel->top += 10; - } - channel->bottom = channel->top + cyChannel; - } -} - -static void -TRACKBAR_CalcThumb (TRACKBAR_INFO *infoPtr, LONG lPos, RECT *thumb) -{ - int range, width, height, thumbwidth; - DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE); - RECT lpRect; - - range = infoPtr->lRangeMax - infoPtr->lRangeMin; - thumbwidth = (infoPtr->uThumbLen / 2) | 1; - - if (!range) range = 1; - - GetClientRect(infoPtr->hwndSelf, &lpRect); - if (dwStyle & TBS_VERT) - { - height = infoPtr->rcChannel.bottom - infoPtr->rcChannel.top - thumbwidth; - - if ((dwStyle & (TBS_BOTH | TBS_LEFT)) && !(dwStyle & TBS_NOTICKS)) - thumb->left = 10; - else - thumb->left = 2; - thumb->right = thumb->left + infoPtr->uThumbLen; - thumb->top = infoPtr->rcChannel.top + - (height*(lPos - infoPtr->lRangeMin))/range; - thumb->bottom = thumb->top + thumbwidth; - } - else - { - width = infoPtr->rcChannel.right - infoPtr->rcChannel.left - thumbwidth; - - thumb->left = infoPtr->rcChannel.left + - (width*(lPos - infoPtr->lRangeMin))/range; - thumb->right = thumb->left + thumbwidth; - if ((dwStyle & (TBS_BOTH | TBS_TOP)) && !(dwStyle & TBS_NOTICKS)) - thumb->top = 10; - else - thumb->top = 2; - thumb->bottom = thumb->top + infoPtr->uThumbLen; - } -} - -inline static void -TRACKBAR_UpdateThumb (TRACKBAR_INFO *infoPtr) -{ - TRACKBAR_CalcThumb(infoPtr, infoPtr->lPos, &infoPtr->rcThumb); -} - -static inline void -TRACKBAR_InvalidateAll(TRACKBAR_INFO * infoPtr) -{ - InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); -} - -static void -TRACKBAR_InvalidateThumb (TRACKBAR_INFO *infoPtr, LONG thumbPos) -{ - RECT rcThumb; - - TRACKBAR_CalcThumb(infoPtr, thumbPos, &rcThumb); - InflateRect(&rcThumb, 1, 1); - InvalidateRect(infoPtr->hwndSelf, &rcThumb, FALSE); -} - -static inline void -TRACKBAR_InvalidateThumbMove (TRACKBAR_INFO *infoPtr, LONG oldPos, LONG newPos) -{ - TRACKBAR_InvalidateThumb (infoPtr, oldPos); - if (newPos != oldPos) - TRACKBAR_InvalidateThumb (infoPtr, newPos); -} - -static BOOL inline -TRACKBAR_HasSelection (TRACKBAR_INFO *infoPtr) -{ - return infoPtr->lSelMin != infoPtr->lSelMax; -} - -static void -TRACKBAR_CalcSelection (TRACKBAR_INFO *infoPtr) -{ - RECT *selection = &infoPtr->rcSelection; - int range = infoPtr->lRangeMax - infoPtr->lRangeMin; - int offsetthumb, height, width; - - if (range <= 0) { - SetRectEmpty (selection); - } else { - if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_VERT) { - offsetthumb = (infoPtr->rcThumb.bottom - infoPtr->rcThumb.top)/2; - height = infoPtr->rcChannel.bottom - infoPtr->rcChannel.top - offsetthumb*2; - selection->top = infoPtr->rcChannel.top + offsetthumb + - (height*infoPtr->lSelMin)/range; - selection->bottom = infoPtr->rcChannel.top + offsetthumb + - (height*infoPtr->lSelMax)/range; - selection->left = infoPtr->rcChannel.left + 3; - selection->right = infoPtr->rcChannel.right - 3; - } else { - offsetthumb = (infoPtr->rcThumb.right - infoPtr->rcThumb.left)/2; - width = infoPtr->rcChannel.right - infoPtr->rcChannel.left - offsetthumb*2; - selection->left = infoPtr->rcChannel.left + offsetthumb + - (width*infoPtr->lSelMin)/range; - selection->right = infoPtr->rcChannel.left + offsetthumb + - (width*infoPtr->lSelMax)/range; - selection->top = infoPtr->rcChannel.top + 3; - selection->bottom = infoPtr->rcChannel.bottom - 3; - } - } - - TRACE("selection[left=%ld, top=%ld, right=%ld, bottom=%ld]\n", - selection->left, selection->top, selection->right, selection->bottom); -} - -static BOOL -TRACKBAR_AutoPage (TRACKBAR_INFO *infoPtr, POINT clickPoint) -{ - LONG dir = TRACKBAR_GetAutoPageDirection(infoPtr, clickPoint); - LONG prevPos = infoPtr->lPos; - - TRACE("x=%ld, y=%ld, dir=%ld\n", clickPoint.x, clickPoint.y, dir); - - if (dir > 0 && (infoPtr->flags & TB_AUTO_PAGE_RIGHT)) - TRACKBAR_PageDown(infoPtr); - else if (dir < 0 && (infoPtr->flags & TB_AUTO_PAGE_LEFT)) - TRACKBAR_PageUp(infoPtr); - else return FALSE; - - infoPtr->flags |= TB_THUMBPOSCHANGED; - TRACKBAR_InvalidateThumbMove (infoPtr, prevPos, infoPtr->lPos); - - return TRUE; -} - -/* Trackbar drawing code. I like my spaghetti done milanese. */ - -static void -TRACKBAR_DrawChannel (TRACKBAR_INFO *infoPtr, HDC hdc, DWORD dwStyle) -{ - RECT rcChannel = infoPtr->rcChannel; - - DrawEdge (hdc, &rcChannel, EDGE_SUNKEN, BF_RECT | BF_ADJUST); - if (dwStyle & TBS_ENABLESELRANGE) { /* fill the channel */ - FillRect (hdc, &rcChannel, GetStockObject(WHITE_BRUSH)); - if (TRACKBAR_HasSelection(infoPtr)) - FillRect (hdc, &infoPtr->rcSelection, GetSysColorBrush(COLOR_HIGHLIGHT)); - } -} - -static void -TRACKBAR_DrawOneTic (TRACKBAR_INFO *infoPtr, HDC hdc, LONG ticPos, int flags) -{ - int x, y, ox, oy, range, side, indent = 0, len = 3; - int offsetthumb; - RECT rcTics; - - if (flags & TBS_VERT) { - offsetthumb = (infoPtr->rcThumb.bottom - infoPtr->rcThumb.top)/2; - rcTics.left = infoPtr->rcThumb.left - 2; - rcTics.right = infoPtr->rcThumb.right + 2; - rcTics.top = infoPtr->rcChannel.top + offsetthumb + 1; - rcTics.bottom = infoPtr->rcChannel.bottom - offsetthumb; - } else { - offsetthumb = (infoPtr->rcThumb.right - infoPtr->rcThumb.left)/2; - rcTics.left = infoPtr->rcChannel.left + offsetthumb + 1; - rcTics.right = infoPtr->rcChannel.right - offsetthumb; - rcTics.top = infoPtr->rcThumb.top - 2; - rcTics.bottom = infoPtr->rcThumb.bottom + 2; - } - - if (flags & (TBS_TOP | TBS_LEFT)) { - x = rcTics.left; - y = rcTics.top; - side = -1; - } else { - x = rcTics.right; - y = rcTics.bottom; - side = 1; - } - - range = infoPtr->lRangeMax - infoPtr->lRangeMin; - if (range <= 0) - range = 1; /* to avoid division by zero */ - - if (flags & TIC_SELECTIONMARK) { - indent = (flags & TIC_SELECTIONMARKMIN) ? -1 : 1; - } else if (flags & TIC_EDGE) { - len++; - } - - if (flags & TBS_VERT) { - int height = rcTics.bottom - rcTics.top; - y = rcTics.top + (height*(ticPos - infoPtr->lRangeMin))/range; - } else { - int width = rcTics.right - rcTics.left; - x = rcTics.left + (width*(ticPos - infoPtr->lRangeMin))/range; - } - - ox = x; - oy = y; - MoveToEx(hdc, x, y, 0); - if (flags & TBS_VERT) x += len * side; - else y += len * side; - LineTo(hdc, x, y); - - if (flags & TIC_SELECTIONMARK) { - if (flags & TBS_VERT) { - x -= side; - } else { - y -= side; - } - MoveToEx(hdc, x, y, 0); - if (flags & TBS_VERT) { - y += 2 * indent; - } else { - x += 2 * indent; - } - - LineTo(hdc, x, y); - LineTo(hdc, ox, oy); - } -} - - -static inline void -TRACKBAR_DrawTic (TRACKBAR_INFO *infoPtr, HDC hdc, LONG ticPos, int flags) -{ - if ((flags & (TBS_LEFT | TBS_TOP)) || (flags & TBS_BOTH)) - TRACKBAR_DrawOneTic (infoPtr, hdc, ticPos, flags | TBS_LEFT); - - if (!(flags & (TBS_LEFT | TBS_TOP)) || (flags & TBS_BOTH)) - TRACKBAR_DrawOneTic (infoPtr, hdc, ticPos, flags & ~TBS_LEFT); -} - -static void -TRACKBAR_DrawTics (TRACKBAR_INFO *infoPtr, HDC hdc, DWORD dwStyle) -{ - unsigned int i; - int ticFlags = dwStyle & 0x0f; - LOGPEN ticPen = { PS_SOLID, {1, 0}, GetSysColor (COLOR_3DDKSHADOW) }; - HPEN hOldPen, hTicPen; - - /* create the pen to draw the tics with */ - hTicPen = CreatePenIndirect(&ticPen); - hOldPen = hTicPen ? SelectObject(hdc, hTicPen) : 0; - - /* actually draw the tics */ - for (i=0; iuNumTics; i++) - TRACKBAR_DrawTic (infoPtr, hdc, infoPtr->tics[i], ticFlags); - - TRACKBAR_DrawTic (infoPtr, hdc, infoPtr->lRangeMin, ticFlags | TIC_EDGE); - TRACKBAR_DrawTic (infoPtr, hdc, infoPtr->lRangeMax, ticFlags | TIC_EDGE); - - if ((dwStyle & TBS_ENABLESELRANGE) && TRACKBAR_HasSelection(infoPtr)) { - TRACKBAR_DrawTic (infoPtr, hdc, infoPtr->lSelMin, - ticFlags | TIC_SELECTIONMARKMIN); - TRACKBAR_DrawTic (infoPtr, hdc, infoPtr->lSelMax, - ticFlags | TIC_SELECTIONMARKMAX); - } - - /* clean up the pen, if we created one */ - if (hTicPen) { - SelectObject(hdc, hOldPen); - DeleteObject(hTicPen); - } -} - -static void -TRACKBAR_DrawThumb(TRACKBAR_INFO *infoPtr, HDC hdc, DWORD dwStyle) -{ - HBRUSH oldbr; - HPEN oldpen; - RECT thumb = infoPtr->rcThumb; - int BlackUntil = 3; - int PointCount = 6; - POINT points[6]; - int fillClr; - int PointDepth; - - fillClr = infoPtr->flags & TB_DRAG_MODE ? COLOR_BTNHILIGHT : COLOR_BTNFACE; - oldbr = SelectObject (hdc, GetSysColorBrush(fillClr)); - SetPolyFillMode (hdc, WINDING); - - if (dwStyle & TBS_BOTH) - { - points[0].x=thumb.right; - points[0].y=thumb.top; - points[1].x=thumb.right; - points[1].y=thumb.bottom; - points[2].x=thumb.left; - points[2].y=thumb.bottom; - points[3].x=thumb.left; - points[3].y=thumb.top; - points[4].x=points[0].x; - points[4].y=points[0].y; - PointCount = 5; - BlackUntil = 3; - } - else - { - if (dwStyle & TBS_VERT) - { - PointDepth = (thumb.bottom - thumb.top) / 2; - if (dwStyle & TBS_LEFT) - { - points[0].x=thumb.right; - points[0].y=thumb.top; - points[1].x=thumb.right; - points[1].y=thumb.bottom; - points[2].x=thumb.left + PointDepth; - points[2].y=thumb.bottom; - points[3].x=thumb.left; - points[3].y=(thumb.bottom - thumb.top) / 2 + thumb.top + 1; - points[4].x=thumb.left + PointDepth; - points[4].y=thumb.top; - points[5].x=points[0].x; - points[5].y=points[0].y; - BlackUntil = 4; - } - else - { - points[0].x=thumb.right; - points[0].y=(thumb.bottom - thumb.top) / 2 + thumb.top + 1; - points[1].x=thumb.right - PointDepth; - points[1].y=thumb.bottom; - points[2].x=thumb.left; - points[2].y=thumb.bottom; - points[3].x=thumb.left; - points[3].y=thumb.top; - points[4].x=thumb.right - PointDepth; - points[4].y=thumb.top; - points[5].x=points[0].x; - points[5].y=points[0].y; - } - } - else - { - PointDepth = (thumb.right - thumb.left) / 2; - if (dwStyle & TBS_TOP) - { - points[0].x=(thumb.right - thumb.left) / 2 + thumb.left + 1; - points[0].y=thumb.top; - points[1].x=thumb.right; - points[1].y=thumb.top + PointDepth; - points[2].x=thumb.right; - points[2].y=thumb.bottom; - points[3].x=thumb.left; - points[3].y=thumb.bottom; - points[4].x=thumb.left; - points[4].y=thumb.top + PointDepth; - points[5].x=points[0].x; - points[5].y=points[0].y; - BlackUntil = 4; - } - else - { - points[0].x=thumb.right; - points[0].y=thumb.top; - points[1].x=thumb.right; - points[1].y=thumb.bottom - PointDepth; - points[2].x=(thumb.right - thumb.left) / 2 + thumb.left + 1; - points[2].y=thumb.bottom; - points[3].x=thumb.left; - points[3].y=thumb.bottom - PointDepth; - points[4].x=thumb.left; - points[4].y=thumb.top; - points[5].x=points[0].x; - points[5].y=points[0].y; - } - } - - } - - /* Draw the thumb now */ - Polygon (hdc, points, PointCount); - oldpen = SelectObject(hdc, GetStockObject(BLACK_PEN)); - Polyline(hdc,points, BlackUntil); - SelectObject(hdc, GetStockObject(WHITE_PEN)); - Polyline(hdc, &points[BlackUntil-1], PointCount+1-BlackUntil); - SelectObject(hdc, oldpen); - SelectObject(hdc, oldbr); -} - - -static void inline -TRACKBAR_ActivateToolTip (TRACKBAR_INFO *infoPtr, BOOL fShow) -{ - TTTOOLINFOW ti; - - if (!infoPtr->hwndToolTip) return; - - ZeroMemory(&ti, sizeof(ti)); - ti.cbSize = sizeof(ti); - ti.hwnd = infoPtr->hwndSelf; - - SendMessageW (infoPtr->hwndToolTip, TTM_TRACKACTIVATE, fShow, (LPARAM)&ti); -} - - -static void -TRACKBAR_UpdateToolTip (TRACKBAR_INFO *infoPtr) -{ - DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE); - WCHAR buf[80]; - static const WCHAR fmt[] = { '%', 'l', 'd', 0 }; - TTTOOLINFOW ti; - POINT pt; - RECT rcClient; - LRESULT size; - - if (!infoPtr->hwndToolTip) return; - - ZeroMemory(&ti, sizeof(ti)); - ti.cbSize = sizeof(ti); - ti.hwnd = infoPtr->hwndSelf; - ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE; - - wsprintfW (buf, fmt, infoPtr->lPos); - ti.lpszText = buf; - SendMessageW (infoPtr->hwndToolTip, TTM_UPDATETIPTEXTW, 0, (LPARAM)&ti); - - GetClientRect (infoPtr->hwndSelf, &rcClient); - size = SendMessageW (infoPtr->hwndToolTip, TTM_GETBUBBLESIZE, 0, (LPARAM)&ti); - if (dwStyle & TBS_VERT) { - if (infoPtr->fLocation == TBTS_LEFT) - pt.x = 0 - LOWORD(size) - TOOLTIP_OFFSET; - else - pt.x = rcClient.right + TOOLTIP_OFFSET; - pt.y = (infoPtr->rcThumb.top + infoPtr->rcThumb.bottom - HIWORD(size))/2; - } else { - if (infoPtr->fLocation == TBTS_TOP) - pt.y = 0 - HIWORD(size) - TOOLTIP_OFFSET; - else - pt.y = rcClient.bottom + TOOLTIP_OFFSET; - pt.x = (infoPtr->rcThumb.left + infoPtr->rcThumb.right - LOWORD(size))/2; - } - ClientToScreen(infoPtr->hwndSelf, &pt); - - SendMessageW (infoPtr->hwndToolTip, TTM_TRACKPOSITION, - 0, (LPARAM)MAKELPARAM(pt.x, pt.y)); -} - - -static void -TRACKBAR_Refresh (TRACKBAR_INFO *infoPtr, HDC hdcDst) -{ - DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE); - RECT rcClient; - HDC hdc; - HBITMAP hOldBmp = 0, hOffScreenBmp = 0; - NMCUSTOMDRAW nmcd; - int gcdrf, icdrf; - - if (infoPtr->flags & TB_THUMBCHANGED) { - TRACKBAR_UpdateThumb (infoPtr); - if (infoPtr->flags & TB_THUMBSIZECHANGED) - TRACKBAR_CalcChannel (infoPtr); - } - if (infoPtr->flags & TB_SELECTIONCHANGED) - TRACKBAR_CalcSelection (infoPtr); - - if (infoPtr->flags & TB_DRAG_MODE) - TRACKBAR_UpdateToolTip (infoPtr); - - infoPtr->flags &= ~ (TB_THUMBCHANGED | TB_SELECTIONCHANGED); - - GetClientRect (infoPtr->hwndSelf, &rcClient); - - /* try to render offscreen, if we fail, carrry onscreen */ - hdc = CreateCompatibleDC(hdcDst); - if (hdc) { - hOffScreenBmp = CreateCompatibleBitmap(hdcDst, rcClient.right, rcClient.bottom); - if (hOffScreenBmp) { - hOldBmp = SelectObject(hdc, hOffScreenBmp); - } else { - DeleteObject(hdc); - hdc = hdcDst; - } - } else { - hdc = hdcDst; - } - - ZeroMemory(&nmcd, sizeof(nmcd)); - nmcd.hdr.hwndFrom = infoPtr->hwndSelf; - nmcd.hdr.idFrom = GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_ID); - nmcd.hdr.code = NM_CUSTOMDRAW; - nmcd.hdc = hdc; - - /* start the paint cycle */ - nmcd.rc = rcClient; - gcdrf = notify_customdraw(infoPtr, &nmcd, CDDS_PREPAINT); - if (gcdrf & CDRF_SKIPDEFAULT) goto cleanup; - - /* Erase backbround */ - if (gcdrf == CDRF_DODEFAULT || - notify_customdraw(infoPtr, &nmcd, CDDS_PREERASE) != CDRF_SKIPDEFAULT) { - FillRect (hdc, &rcClient, GetSysColorBrush(COLOR_BTNFACE)); - if (gcdrf != CDRF_DODEFAULT) - notify_customdraw(infoPtr, &nmcd, CDDS_POSTERASE); - } - - /* draw channel */ - if (gcdrf & CDRF_NOTIFYITEMDRAW) { - nmcd.dwItemSpec = TBCD_CHANNEL; - nmcd.uItemState = CDIS_DEFAULT; - nmcd.rc = infoPtr->rcChannel; - icdrf = notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPREPAINT); - } else icdrf = CDRF_DODEFAULT; - if ( !(icdrf & CDRF_SKIPDEFAULT) ) { - TRACKBAR_DrawChannel (infoPtr, hdc, dwStyle); - if (icdrf & CDRF_NOTIFYPOSTPAINT) - notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPOSTPAINT); - } - - - /* draw tics */ - if (!(dwStyle & TBS_NOTICKS)) { - if (gcdrf & CDRF_NOTIFYITEMDRAW) { - nmcd.dwItemSpec = TBCD_TICS; - nmcd.uItemState = CDIS_DEFAULT; - nmcd.rc = rcClient; - icdrf = notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPREPAINT); - } else icdrf = CDRF_DODEFAULT; - if ( !(icdrf & CDRF_SKIPDEFAULT) ) { - TRACKBAR_DrawTics (infoPtr, hdc, dwStyle); - if (icdrf & CDRF_NOTIFYPOSTPAINT) - notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPOSTPAINT); - } - } - - /* draw thumb */ - if (!(dwStyle & TBS_NOTHUMB)) { - if (gcdrf & CDRF_NOTIFYITEMDRAW) { - nmcd.dwItemSpec = TBCD_THUMB; - nmcd.uItemState = infoPtr->flags & TB_DRAG_MODE ? CDIS_HOT : CDIS_DEFAULT; - nmcd.rc = infoPtr->rcThumb; - icdrf = notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPREPAINT); - } else icdrf = CDRF_DODEFAULT; - if ( !(icdrf & CDRF_SKIPDEFAULT) ) { - TRACKBAR_DrawThumb(infoPtr, hdc, dwStyle); - if (icdrf & CDRF_NOTIFYPOSTPAINT) - notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPOSTPAINT); - } - } - - /* draw focus rectangle */ - if (infoPtr->bFocussed) { - DrawFocusRect(hdc, &rcClient); - } - - /* finish up the painting */ - if (gcdrf & CDRF_NOTIFYPOSTPAINT) - notify_customdraw(infoPtr, &nmcd, CDDS_POSTPAINT); - -cleanup: - /* cleanup, if we rendered offscreen */ - if (hdc != hdcDst) { - BitBlt(hdcDst, 0, 0, rcClient.right, rcClient.bottom, hdc, 0, 0, SRCCOPY); - SelectObject(hdc, hOldBmp); - DeleteObject(hOffScreenBmp); - DeleteObject(hdc); - } -} - - -static void -TRACKBAR_AlignBuddies (TRACKBAR_INFO *infoPtr) -{ - DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE); - HWND hwndParent = GetParent (infoPtr->hwndSelf); - RECT rcSelf, rcBuddy; - INT x, y; - - GetWindowRect (infoPtr->hwndSelf, &rcSelf); - MapWindowPoints (HWND_DESKTOP, hwndParent, (LPPOINT)&rcSelf, 2); - - /* align buddy left or above */ - if (infoPtr->hwndBuddyLA) { - GetWindowRect (infoPtr->hwndBuddyLA, &rcBuddy); - MapWindowPoints (HWND_DESKTOP, hwndParent, (LPPOINT)&rcBuddy, 2); - - if (dwStyle & TBS_VERT) { - x = (infoPtr->rcChannel.right + infoPtr->rcChannel.left) / 2 - - (rcBuddy.right - rcBuddy.left) / 2 + rcSelf.left; - y = rcSelf.top - (rcBuddy.bottom - rcBuddy.top); - } - else { - x = rcSelf.left - (rcBuddy.right - rcBuddy.left); - y = (infoPtr->rcChannel.bottom + infoPtr->rcChannel.top) / 2 - - (rcBuddy.bottom - rcBuddy.top) / 2 + rcSelf.top; - } - - SetWindowPos (infoPtr->hwndBuddyLA, 0, x, y, 0, 0, - SWP_NOZORDER | SWP_NOSIZE); - } - - - /* align buddy right or below */ - if (infoPtr->hwndBuddyRB) { - GetWindowRect (infoPtr->hwndBuddyRB, &rcBuddy); - MapWindowPoints (HWND_DESKTOP, hwndParent, (LPPOINT)&rcBuddy, 2); - - if (dwStyle & TBS_VERT) { - x = (infoPtr->rcChannel.right + infoPtr->rcChannel.left) / 2 - - (rcBuddy.right - rcBuddy.left) / 2 + rcSelf.left; - y = rcSelf.bottom; - } - else { - x = rcSelf.right; - y = (infoPtr->rcChannel.bottom + infoPtr->rcChannel.top) / 2 - - (rcBuddy.bottom - rcBuddy.top) / 2 + rcSelf.top; - } - SetWindowPos (infoPtr->hwndBuddyRB, 0, x, y, 0, 0, - SWP_NOZORDER | SWP_NOSIZE); - } -} - - -static LRESULT -TRACKBAR_ClearSel (TRACKBAR_INFO *infoPtr, BOOL fRedraw) -{ - infoPtr->lSelMin = 0; - infoPtr->lSelMax = 0; - infoPtr->flags |= TB_SELECTIONCHANGED; - - if (fRedraw) TRACKBAR_InvalidateAll(infoPtr); - - return 0; -} - - -static LRESULT -TRACKBAR_ClearTics (TRACKBAR_INFO *infoPtr, BOOL fRedraw) -{ - if (infoPtr->tics) { - Free (infoPtr->tics); - infoPtr->tics = NULL; - infoPtr->uNumTics = 0; - } - - if (fRedraw) TRACKBAR_InvalidateAll(infoPtr); - - return 0; -} - - -static LRESULT inline -TRACKBAR_GetChannelRect (TRACKBAR_INFO *infoPtr, LPRECT lprc) -{ - if (lprc == NULL) return 0; - - lprc->left = infoPtr->rcChannel.left; - lprc->right = infoPtr->rcChannel.right; - lprc->bottom = infoPtr->rcChannel.bottom; - lprc->top = infoPtr->rcChannel.top; - - return 0; -} - - -static LONG inline -TRACKBAR_GetNumTics (TRACKBAR_INFO *infoPtr) -{ - if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_NOTICKS) - return 0; - - return infoPtr->uNumTics + 2; -} - - -static int comp_tics(const void *ap, const void *bp) -{ - DWORD a = *((DWORD *)ap); - DWORD b = *((DWORD *)bp); - - TRACE("(a=%ld, b=%ld)\n", a, b); - if (a < b) return -1; - if (a > b) return 1; - return 0; -} - - -static LONG inline -TRACKBAR_GetTic (TRACKBAR_INFO *infoPtr, INT iTic) -{ - if ((iTic < 0) || (iTic >= infoPtr->uNumTics) || !infoPtr->tics) - return -1; - - qsort(infoPtr->tics, infoPtr->uNumTics, sizeof(DWORD), comp_tics); - return infoPtr->tics[iTic]; -} - - -static LONG inline -TRACKBAR_GetTicPos (TRACKBAR_INFO *infoPtr, INT iTic) -{ - LONG range, width, pos, tic; - int offsetthumb; - - if ((iTic < 0) || (iTic >= infoPtr->uNumTics) || !infoPtr->tics) - return -1; - - tic = TRACKBAR_GetTic (infoPtr, iTic); - range = infoPtr->lRangeMax - infoPtr->lRangeMin; - if (range <= 0) range = 1; - offsetthumb = (infoPtr->rcThumb.right - infoPtr->rcThumb.left)/2; - width = infoPtr->rcChannel.right - infoPtr->rcChannel.left - offsetthumb*2; - pos = infoPtr->rcChannel.left + offsetthumb + (width * tic) / range; - - return pos; -} - - -static HWND -TRACKBAR_SetBuddy (TRACKBAR_INFO *infoPtr, BOOL fLocation, HWND hwndBuddy) -{ - HWND hwndTemp; - - if (fLocation) { - /* buddy is left or above */ - hwndTemp = infoPtr->hwndBuddyLA; - infoPtr->hwndBuddyLA = hwndBuddy; - } - else { - /* buddy is right or below */ - hwndTemp = infoPtr->hwndBuddyRB; - infoPtr->hwndBuddyRB = hwndBuddy; - } - - TRACKBAR_AlignBuddies (infoPtr); - - return hwndTemp; -} - - -static LONG inline -TRACKBAR_SetLineSize (TRACKBAR_INFO *infoPtr, LONG lLineSize) -{ - LONG lTemp = infoPtr->lLineSize; - - infoPtr->lLineSize = lLineSize; - - return lTemp; -} - - -static LONG inline -TRACKBAR_SetPageSize (TRACKBAR_INFO *infoPtr, LONG lPageSize) -{ - LONG lTemp = infoPtr->lPageSize; - - infoPtr->lPageSize = lPageSize; - - return lTemp; -} - - -static LRESULT inline -TRACKBAR_SetPos (TRACKBAR_INFO *infoPtr, BOOL fPosition, LONG lPosition) -{ - LONG oldPos = infoPtr->lPos; - infoPtr->lPos = lPosition; - - if (infoPtr->lPos < infoPtr->lRangeMin) - infoPtr->lPos = infoPtr->lRangeMin; - - if (infoPtr->lPos > infoPtr->lRangeMax) - infoPtr->lPos = infoPtr->lRangeMax; - infoPtr->flags |= TB_THUMBPOSCHANGED; - - if (fPosition) TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, lPosition); - - return 0; -} - - -static LRESULT inline -TRACKBAR_SetRange (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lRange) -{ - infoPtr->lRangeMin = (SHORT)LOWORD(lRange); - infoPtr->lRangeMax = (SHORT)HIWORD(lRange); - - if (infoPtr->lPos < infoPtr->lRangeMin) { - infoPtr->lPos = infoPtr->lRangeMin; - infoPtr->flags |= TB_THUMBPOSCHANGED; - } - - if (infoPtr->lPos > infoPtr->lRangeMax) { - infoPtr->lPos = infoPtr->lRangeMax; - infoPtr->flags |= TB_THUMBPOSCHANGED; - } - - infoPtr->lPageSize = (infoPtr->lRangeMax - infoPtr->lRangeMin) / 5; - if (infoPtr->lPageSize == 0) infoPtr->lPageSize = 1; - - if (fRedraw) TRACKBAR_InvalidateAll(infoPtr); - - return 0; -} - - -static LRESULT inline -TRACKBAR_SetRangeMax (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lMax) -{ - infoPtr->lRangeMax = lMax; - if (infoPtr->lPos > infoPtr->lRangeMax) { - infoPtr->lPos = infoPtr->lRangeMax; - infoPtr->flags |= TB_THUMBPOSCHANGED; - } - - infoPtr->lPageSize = (infoPtr->lRangeMax - infoPtr->lRangeMin) / 5; - if (infoPtr->lPageSize == 0) infoPtr->lPageSize = 1; - - if (fRedraw) TRACKBAR_InvalidateAll(infoPtr); - - return 0; -} - - -static LRESULT inline -TRACKBAR_SetRangeMin (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lMin) -{ - infoPtr->lRangeMin = lMin; - if (infoPtr->lPos < infoPtr->lRangeMin) { - infoPtr->lPos = infoPtr->lRangeMin; - infoPtr->flags |= TB_THUMBPOSCHANGED; - } - - infoPtr->lPageSize = (infoPtr->lRangeMax - infoPtr->lRangeMin) / 5; - if (infoPtr->lPageSize == 0) infoPtr->lPageSize = 1; - - if (fRedraw) TRACKBAR_InvalidateAll(infoPtr); - - return 0; -} - - -static LRESULT inline -TRACKBAR_SetSel (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lSel) -{ - if (!GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_ENABLESELRANGE) - return 0; - - infoPtr->lSelMin = (SHORT)LOWORD(lSel); - infoPtr->lSelMax = (SHORT)HIWORD(lSel); - infoPtr->flags |= TB_SELECTIONCHANGED; - - if (infoPtr->lSelMin < infoPtr->lRangeMin) - infoPtr->lSelMin = infoPtr->lRangeMin; - if (infoPtr->lSelMax > infoPtr->lRangeMax) - infoPtr->lSelMax = infoPtr->lRangeMax; - - if (fRedraw) TRACKBAR_InvalidateAll(infoPtr); - - return 0; -} - - -static LRESULT inline -TRACKBAR_SetSelEnd (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lEnd) -{ - if (!GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_ENABLESELRANGE) - return 0; - - infoPtr->lSelMax = lEnd; - infoPtr->flags |= TB_SELECTIONCHANGED; - - if (infoPtr->lSelMax > infoPtr->lRangeMax) - infoPtr->lSelMax = infoPtr->lRangeMax; - - if (fRedraw) TRACKBAR_InvalidateAll(infoPtr); - - return 0; -} - - -static LRESULT inline -TRACKBAR_SetSelStart (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lStart) -{ - if (!GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_ENABLESELRANGE) - return 0; - - infoPtr->lSelMin = lStart; - infoPtr->flags |=TB_SELECTIONCHANGED; - - if (infoPtr->lSelMin < infoPtr->lRangeMin) - infoPtr->lSelMin = infoPtr->lRangeMin; - - if (fRedraw) TRACKBAR_InvalidateAll(infoPtr); - - return 0; -} - - -static LRESULT inline -TRACKBAR_SetThumbLength (TRACKBAR_INFO *infoPtr, UINT iLength) -{ - if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_FIXEDLENGTH) { - infoPtr->uThumbLen = iLength; - infoPtr->flags |= TB_THUMBSIZECHANGED; - InvalidateRect (infoPtr->hwndSelf, &infoPtr->rcThumb, FALSE); - } - - return 0; -} - - -static LRESULT inline -TRACKBAR_SetTic (TRACKBAR_INFO *infoPtr, LONG lPos) -{ - if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_AUTOTICKS) - return FALSE; - - if ((lPos < infoPtr->lRangeMin) || (lPos> infoPtr->lRangeMax)) - return FALSE; - - TRACE("lPos=%ld\n", lPos); - - infoPtr->uNumTics++; - infoPtr->tics=ReAlloc( infoPtr->tics, - (infoPtr->uNumTics)*sizeof (DWORD)); - if (!infoPtr->tics) { - infoPtr->uNumTics = 0; - notify(infoPtr, NM_OUTOFMEMORY); - return FALSE; - } - infoPtr->tics[infoPtr->uNumTics-1] = lPos; - - TRACKBAR_InvalidateAll(infoPtr); - - return TRUE; -} - - -static LRESULT inline -TRACKBAR_SetTicFreq (TRACKBAR_INFO *infoPtr, WORD wFreq) -{ - if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_AUTOTICKS) { - infoPtr->uTicFreq = wFreq; - TRACKBAR_RecalculateTics (infoPtr); - TRACKBAR_InvalidateAll(infoPtr); - } - - return 0; -} - - -static INT inline -TRACKBAR_SetTipSide (TRACKBAR_INFO *infoPtr, INT fLocation) -{ - INT fTemp = infoPtr->fLocation; - - infoPtr->fLocation = fLocation; - - return fTemp; -} - - -static LRESULT inline -TRACKBAR_SetToolTips (TRACKBAR_INFO *infoPtr, HWND hwndTT) -{ - infoPtr->hwndToolTip = hwndTT; - - return 0; -} - - -static BOOL inline -TRACKBAR_SetUnicodeFormat (TRACKBAR_INFO *infoPtr, BOOL fUnicode) -{ - BOOL bTemp = infoPtr->bUnicode; - - infoPtr->bUnicode = fUnicode; - - return bTemp; -} - - -static LRESULT -TRACKBAR_InitializeThumb (TRACKBAR_INFO *infoPtr) -{ - DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE); - RECT rect; - int clientWidth, clientMetric; - - /* initial thumb length */ - clientMetric = (dwStyle & TBS_ENABLESELRANGE) ? 23 : 21; - GetClientRect(infoPtr->hwndSelf,&rect); - if (dwStyle & TBS_VERT) { - clientWidth = rect.right - rect.left; - } else { - clientWidth = rect.bottom - rect.top; - } - if (clientWidth >= clientMetric) - infoPtr->uThumbLen = clientMetric; - else - infoPtr->uThumbLen = clientWidth > 9 ? clientWidth - 6 : 4; - - TRACKBAR_CalcChannel (infoPtr); - TRACKBAR_UpdateThumb (infoPtr); - infoPtr->flags &= ~TB_SELECTIONCHANGED; - - return 0; -} - - -static LRESULT -TRACKBAR_Create (HWND hwnd, LPCREATESTRUCTW lpcs) -{ - TRACKBAR_INFO *infoPtr; - DWORD dwStyle; - - infoPtr = (TRACKBAR_INFO *)Alloc (sizeof(TRACKBAR_INFO)); - if (!infoPtr) return -1; - SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); - - /* set default values */ - infoPtr->hwndSelf = hwnd; - infoPtr->lRangeMin = 0; - infoPtr->lRangeMax = 100; - infoPtr->lLineSize = 1; - infoPtr->lPageSize = 20; - infoPtr->lSelMin = 0; - infoPtr->lSelMax = 0; - infoPtr->lPos = 0; - infoPtr->fLocation = -1; - infoPtr->uNumTics = 0; /* start and end tic are not included in count*/ - infoPtr->uTicFreq = 1; - infoPtr->tics = NULL; - infoPtr->hwndNotify= lpcs->hwndParent; - - TRACKBAR_InitializeThumb (infoPtr); - - dwStyle = GetWindowLongW (hwnd, GWL_STYLE); - - /* Create tooltip control */ - if (dwStyle & TBS_TOOLTIPS) { - - infoPtr->hwndToolTip = - CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, 0, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - hwnd, 0, 0, 0); - - if (infoPtr->hwndToolTip) { - TTTOOLINFOW ti; - ZeroMemory (&ti, sizeof(ti)); - ti.cbSize = sizeof(ti); - ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE; - ti.hwnd = hwnd; - - SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, 0, (LPARAM)&ti); - } - } - - return 0; -} - - -static LRESULT -TRACKBAR_Destroy (TRACKBAR_INFO *infoPtr) -{ - /* delete tooltip control */ - if (infoPtr->hwndToolTip) - DestroyWindow (infoPtr->hwndToolTip); - - Free (infoPtr); - SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0); - return 0; -} - - -static LRESULT -TRACKBAR_KillFocus (TRACKBAR_INFO *infoPtr, HWND hwndGetFocus) -{ - TRACE("\n"); - infoPtr->bFocussed = FALSE; - TRACKBAR_InvalidateAll(infoPtr); - - return 0; -} - -static LRESULT -TRACKBAR_LButtonDown (TRACKBAR_INFO *infoPtr, DWORD fwKeys, INT x, INT y) -{ - POINT clickPoint; - - clickPoint.x = x; - clickPoint.y = y; - - SetFocus(infoPtr->hwndSelf); - - if (PtInRect(&infoPtr->rcThumb, clickPoint)) { - infoPtr->flags |= TB_DRAG_MODE; - SetCapture (infoPtr->hwndSelf); - TRACKBAR_UpdateToolTip (infoPtr); - TRACKBAR_ActivateToolTip (infoPtr, TRUE); - TRACKBAR_InvalidateThumb(infoPtr, infoPtr->lPos); - } else { - LONG dir = TRACKBAR_GetAutoPageDirection(infoPtr, clickPoint); - if (dir == 0) return 0; - infoPtr->flags |= (dir < 0) ? TB_AUTO_PAGE_LEFT : TB_AUTO_PAGE_RIGHT; - TRACKBAR_AutoPage (infoPtr, clickPoint); - SetCapture (infoPtr->hwndSelf); - SetTimer(infoPtr->hwndSelf, TB_REFRESH_TIMER, TB_REFRESH_DELAY, 0); - } - - return 0; -} - - -static LRESULT -TRACKBAR_LButtonUp (TRACKBAR_INFO *infoPtr, DWORD fwKeys, INT x, INT y) -{ - if (infoPtr->flags & TB_DRAG_MODE) { - notify_with_scroll (infoPtr, TB_THUMBPOSITION | (infoPtr->lPos<<16)); - notify_with_scroll (infoPtr, TB_ENDTRACK); - infoPtr->flags &= ~TB_DRAG_MODE; - ReleaseCapture (); - notify(infoPtr, NM_RELEASEDCAPTURE); - TRACKBAR_ActivateToolTip(infoPtr, FALSE); - TRACKBAR_InvalidateThumb(infoPtr, infoPtr->lPos); - } - if (infoPtr->flags & TB_AUTO_PAGE) { - KillTimer (infoPtr->hwndSelf, TB_REFRESH_TIMER); - infoPtr->flags &= ~TB_AUTO_PAGE; - notify_with_scroll (infoPtr, TB_ENDTRACK); - ReleaseCapture (); - notify(infoPtr, NM_RELEASEDCAPTURE); - } - - return 0; -} - - -static LRESULT -TRACKBAR_CaptureChanged (TRACKBAR_INFO *infoPtr) -{ - notify_with_scroll (infoPtr, TB_ENDTRACK); - return 0; -} - - -static LRESULT -TRACKBAR_Paint (TRACKBAR_INFO *infoPtr, HDC hdc) -{ - if (hdc) { - TRACKBAR_Refresh(infoPtr, hdc); - } else { - PAINTSTRUCT ps; - hdc = BeginPaint (infoPtr->hwndSelf, &ps); - TRACKBAR_Refresh (infoPtr, hdc); - EndPaint (infoPtr->hwndSelf, &ps); - } - - return 0; -} - - -static LRESULT -TRACKBAR_SetFocus (TRACKBAR_INFO *infoPtr, HWND hwndLoseFocus) -{ - TRACE("\n"); - infoPtr->bFocussed = TRUE; - TRACKBAR_InvalidateAll(infoPtr); - - return 0; -} - - -static LRESULT -TRACKBAR_Size (TRACKBAR_INFO *infoPtr, DWORD fwSizeType, INT nWidth, INT nHeight) -{ - TRACKBAR_InitializeThumb (infoPtr); - TRACKBAR_AlignBuddies (infoPtr); - - return 0; -} - - -static LRESULT -TRACKBAR_Timer (TRACKBAR_INFO *infoPtr, INT wTimerID, TIMERPROC *tmrpc) -{ - if (infoPtr->flags & TB_AUTO_PAGE) { - POINT pt; - if (GetCursorPos(&pt)) - if (ScreenToClient(infoPtr->hwndSelf, &pt)) - TRACKBAR_AutoPage(infoPtr, pt); - } - return 0; -} - - -static LRESULT -TRACKBAR_MouseMove (TRACKBAR_INFO *infoPtr, DWORD fwKeys, INT x, INT y) -{ - DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE); - INT clickPlace = (dwStyle & TBS_VERT) ? y : x; - LONG dragPos, oldPos = infoPtr->lPos; - - TRACE("(x=%d. y=%d)\n", x, y); - - if (infoPtr->flags & TB_AUTO_PAGE) { - POINT pt; - pt.x = x; - pt.y = y; - TRACKBAR_AutoPage (infoPtr, pt); - return TRUE; - } - - if (!(infoPtr->flags & TB_DRAG_MODE)) return TRUE; - - dragPos = TRACKBAR_ConvertPlaceToPosition (infoPtr, clickPlace, - dwStyle & TBS_VERT); - if (dragPos == oldPos) return TRUE; - - infoPtr->lPos = dragPos; - - infoPtr->flags |= TB_THUMBPOSCHANGED; - notify_with_scroll (infoPtr, TB_THUMBTRACK | (infoPtr->lPos<<16)); - - - TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, dragPos); - UpdateWindow (infoPtr->hwndSelf); - - return TRUE; -} - -static BOOL -TRACKBAR_KeyDown (TRACKBAR_INFO *infoPtr, INT nVirtKey, DWORD lKeyData) -{ - DWORD style = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE); - BOOL downIsLeft = style & TBS_DOWNISLEFT; - BOOL vert = style & TBS_VERT; - LONG pos = infoPtr->lPos; - - TRACE("%x\n", nVirtKey); - - switch (nVirtKey) { - case VK_UP: - if (!vert && downIsLeft) TRACKBAR_LineDown(infoPtr); - else TRACKBAR_LineUp(infoPtr); - break; - case VK_LEFT: - if (vert && downIsLeft) TRACKBAR_LineDown(infoPtr); - else TRACKBAR_LineUp(infoPtr); - break; - case VK_DOWN: - if (!vert && downIsLeft) TRACKBAR_LineUp(infoPtr); - else TRACKBAR_LineDown(infoPtr); - break; - case VK_RIGHT: - if (vert && downIsLeft) TRACKBAR_LineUp(infoPtr); - else TRACKBAR_LineDown(infoPtr); - break; - case VK_NEXT: - if (!vert && downIsLeft) TRACKBAR_PageUp(infoPtr); - else TRACKBAR_PageDown(infoPtr); - break; - case VK_PRIOR: - if (!vert && downIsLeft) TRACKBAR_PageDown(infoPtr); - else TRACKBAR_PageUp(infoPtr); - break; - case VK_HOME: - if (infoPtr->lPos == infoPtr->lRangeMin) return FALSE; - infoPtr->lPos = infoPtr->lRangeMin; - notify_with_scroll (infoPtr, TB_TOP); - break; - case VK_END: - if (infoPtr->lPos == infoPtr->lRangeMax) return FALSE; - infoPtr->lPos = infoPtr->lRangeMax; - notify_with_scroll (infoPtr, TB_BOTTOM); - break; - } - - if (pos != infoPtr->lPos) { - infoPtr->flags |=TB_THUMBPOSCHANGED; - TRACKBAR_InvalidateThumbMove (infoPtr, pos, infoPtr->lPos); - } - - return TRUE; -} - - -static BOOL inline -TRACKBAR_KeyUp (TRACKBAR_INFO *infoPtr, INT nVirtKey, DWORD lKeyData) -{ - switch (nVirtKey) { - case VK_LEFT: - case VK_UP: - case VK_RIGHT: - case VK_DOWN: - case VK_NEXT: - case VK_PRIOR: - case VK_HOME: - case VK_END: - notify_with_scroll (infoPtr, TB_ENDTRACK); - } - return TRUE; -} - - -static LRESULT WINAPI -TRACKBAR_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - TRACKBAR_INFO *infoPtr = (TRACKBAR_INFO *)GetWindowLongPtrW (hwnd, 0); - - TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hwnd, uMsg, wParam, lParam); - - if (!infoPtr && (uMsg != WM_CREATE)) - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - - switch (uMsg) - { - case TBM_CLEARSEL: - return TRACKBAR_ClearSel (infoPtr, (BOOL)wParam); - - case TBM_CLEARTICS: - return TRACKBAR_ClearTics (infoPtr, (BOOL)wParam); - - case TBM_GETBUDDY: - return (LRESULT)(wParam ? infoPtr->hwndBuddyLA : infoPtr->hwndBuddyRB); - - case TBM_GETCHANNELRECT: - return TRACKBAR_GetChannelRect (infoPtr, (LPRECT)lParam); - - case TBM_GETLINESIZE: - return infoPtr->lLineSize; - - case TBM_GETNUMTICS: - return TRACKBAR_GetNumTics (infoPtr); - - case TBM_GETPAGESIZE: - return infoPtr->lPageSize; - - case TBM_GETPOS: - return infoPtr->lPos; - - case TBM_GETPTICS: - return (LRESULT)infoPtr->tics; - - case TBM_GETRANGEMAX: - return infoPtr->lRangeMax; - - case TBM_GETRANGEMIN: - return infoPtr->lRangeMin; - - case TBM_GETSELEND: - return infoPtr->lSelMax; - - case TBM_GETSELSTART: - return infoPtr->lSelMin; - - case TBM_GETTHUMBLENGTH: - return infoPtr->uThumbLen; - - case TBM_GETTHUMBRECT: - return CopyRect((LPRECT)lParam, &infoPtr->rcThumb); - - case TBM_GETTIC: - return TRACKBAR_GetTic (infoPtr, (INT)wParam); - - case TBM_GETTICPOS: - return TRACKBAR_GetTicPos (infoPtr, (INT)wParam); - - case TBM_GETTOOLTIPS: - return (LRESULT)infoPtr->hwndToolTip; - - case TBM_GETUNICODEFORMAT: - return infoPtr->bUnicode; - - case TBM_SETBUDDY: - return (LRESULT) TRACKBAR_SetBuddy(infoPtr, (BOOL)wParam, (HWND)lParam); - - case TBM_SETLINESIZE: - return TRACKBAR_SetLineSize (infoPtr, (LONG)lParam); - - case TBM_SETPAGESIZE: - return TRACKBAR_SetPageSize (infoPtr, (LONG)lParam); - - case TBM_SETPOS: - return TRACKBAR_SetPos (infoPtr, (BOOL)wParam, (LONG)lParam); - - case TBM_SETRANGE: - return TRACKBAR_SetRange (infoPtr, (BOOL)wParam, (LONG)lParam); - - case TBM_SETRANGEMAX: - return TRACKBAR_SetRangeMax (infoPtr, (BOOL)wParam, (LONG)lParam); - - case TBM_SETRANGEMIN: - return TRACKBAR_SetRangeMin (infoPtr, (BOOL)wParam, (LONG)lParam); - - case TBM_SETSEL: - return TRACKBAR_SetSel (infoPtr, (BOOL)wParam, (LONG)lParam); - - case TBM_SETSELEND: - return TRACKBAR_SetSelEnd (infoPtr, (BOOL)wParam, (LONG)lParam); - - case TBM_SETSELSTART: - return TRACKBAR_SetSelStart (infoPtr, (BOOL)wParam, (LONG)lParam); - - case TBM_SETTHUMBLENGTH: - return TRACKBAR_SetThumbLength (infoPtr, (UINT)wParam); - - case TBM_SETTIC: - return TRACKBAR_SetTic (infoPtr, (LONG)lParam); - - case TBM_SETTICFREQ: - return TRACKBAR_SetTicFreq (infoPtr, (WORD)wParam); - - case TBM_SETTIPSIDE: - return TRACKBAR_SetTipSide (infoPtr, (INT)wParam); - - case TBM_SETTOOLTIPS: - return TRACKBAR_SetToolTips (infoPtr, (HWND)wParam); - - case TBM_SETUNICODEFORMAT: - return TRACKBAR_SetUnicodeFormat (infoPtr, (BOOL)wParam); - - - case WM_CAPTURECHANGED: - return TRACKBAR_CaptureChanged (infoPtr); - - case WM_CREATE: - return TRACKBAR_Create (hwnd, (LPCREATESTRUCTW)lParam); - - case WM_DESTROY: - return TRACKBAR_Destroy (infoPtr); - -/* case WM_ENABLE: */ - - case WM_ERASEBKGND: - return 0; - - case WM_GETDLGCODE: - return DLGC_WANTARROWS; - - case WM_KEYDOWN: - return TRACKBAR_KeyDown (infoPtr, (INT)wParam, (DWORD)lParam); - - case WM_KEYUP: - return TRACKBAR_KeyUp (infoPtr, (INT)wParam, (DWORD)lParam); - - case WM_KILLFOCUS: - return TRACKBAR_KillFocus (infoPtr, (HWND)wParam); - - case WM_LBUTTONDOWN: - return TRACKBAR_LButtonDown (infoPtr, wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); - - case WM_LBUTTONUP: - return TRACKBAR_LButtonUp (infoPtr, wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); - - case WM_MOUSEMOVE: - return TRACKBAR_MouseMove (infoPtr, wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); - - case WM_PAINT: - return TRACKBAR_Paint (infoPtr, (HDC)wParam); - - case WM_SETFOCUS: - return TRACKBAR_SetFocus (infoPtr, (HWND)wParam); - - case WM_SIZE: - return TRACKBAR_Size (infoPtr, wParam, LOWORD(lParam), HIWORD(lParam)); - - case WM_TIMER: - return TRACKBAR_Timer (infoPtr, (INT)wParam, (TIMERPROC *)lParam); - - case WM_WININICHANGE: - return TRACKBAR_InitializeThumb (infoPtr); - - default: - if ((uMsg >= WM_USER) && (uMsg < WM_APP)) - ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam); - return DefWindowProcW (hwnd, uMsg, wParam, lParam); - } -} - - -void TRACKBAR_Register (void) -{ - WNDCLASSW wndClass; - - ZeroMemory (&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS; - wndClass.lpfnWndProc = TRACKBAR_WindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(TRACKBAR_INFO *); - wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); - wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); - wndClass.lpszClassName = TRACKBAR_CLASSW; - - RegisterClassW (&wndClass); -} - - -void TRACKBAR_Unregister (void) -{ - UnregisterClassW (TRACKBAR_CLASSW, NULL); -} +/* + * Trackbar control + * + * Copyright 1998, 1999 Eric Kohl + * Copyright 1998, 1999 Alex Priem + * Copyright 2002 Dimitrie O. Paun + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTE + * + * This code was audited for completeness against the documented features + * of Comctl32.dll version 6.0 on Sep. 12, 2002, by Dimitrie O. Paun. + * + * Unless otherwise noted, we believe this code to be complete, as per + * the specification mentioned above. + * If you discover missing features, or bugs, please note them below. + * + */ + +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "wine/debug.h" + +#include "comctl32.h" + +WINE_DEFAULT_DEBUG_CHANNEL(trackbar); + +typedef struct +{ + HWND hwndSelf; + LONG lRangeMin; + LONG lRangeMax; + LONG lLineSize; + LONG lPageSize; + LONG lSelMin; + LONG lSelMax; + LONG lPos; + UINT uThumbLen; + UINT uNumTics; + UINT uTicFreq; + HWND hwndNotify; + HWND hwndToolTip; + HWND hwndBuddyLA; + HWND hwndBuddyRB; + INT fLocation; + INT flags; + BOOL bUnicode; + BOOL bFocussed; + RECT rcChannel; + RECT rcSelection; + RECT rcThumb; + LPLONG tics; +} TRACKBAR_INFO; + +#define TB_REFRESH_TIMER 1 +#define TB_REFRESH_DELAY 500 + +#define TOOLTIP_OFFSET 2 /* distance from ctrl edge to tooltip */ + +/* Used by TRACKBAR_Refresh to find out which parts of the control + need to be recalculated */ + +#define TB_THUMBPOSCHANGED 1 +#define TB_THUMBSIZECHANGED 2 +#define TB_THUMBCHANGED (TB_THUMBPOSCHANGED | TB_THUMBSIZECHANGED) +#define TB_SELECTIONCHANGED 4 +#define TB_DRAG_MODE 8 /* we're dragging the slider */ +#define TB_AUTO_PAGE_LEFT 16 +#define TB_AUTO_PAGE_RIGHT 32 +#define TB_AUTO_PAGE (TB_AUTO_PAGE_LEFT | TB_AUTO_PAGE_RIGHT) + +/* helper defines for TRACKBAR_DrawTic */ +#define TIC_EDGE 0x20 +#define TIC_SELECTIONMARKMAX 0x80 +#define TIC_SELECTIONMARKMIN 0x100 +#define TIC_SELECTIONMARK (TIC_SELECTIONMARKMAX | TIC_SELECTIONMARKMIN) + +static inline int +notify_customdraw(TRACKBAR_INFO *infoPtr, NMCUSTOMDRAW *pnmcd, int stage) +{ + pnmcd->dwDrawStage = stage; + return SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, + pnmcd->hdr.idFrom, (LPARAM)pnmcd); +} + +static LRESULT notify_hdr(TRACKBAR_INFO *infoPtr, INT code, LPNMHDR pnmh) +{ + LRESULT result; + + TRACE("(code=%d)\n", code); + + pnmh->hwndFrom = infoPtr->hwndSelf; + pnmh->idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); + pnmh->code = code; + result = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, + (WPARAM)pnmh->idFrom, (LPARAM)pnmh); + + TRACE(" <= %ld\n", result); + + return result; +} + +static inline int notify(TRACKBAR_INFO *infoPtr, INT code) +{ + NMHDR nmh; + return notify_hdr(infoPtr, code, &nmh); +} + +static BOOL +notify_with_scroll (TRACKBAR_INFO *infoPtr, UINT code) +{ + BOOL bVert = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_VERT; + + TRACE("%x\n", code); + + return (BOOL) SendMessageW (infoPtr->hwndNotify, + bVert ? WM_VSCROLL : WM_HSCROLL, + (WPARAM)code, (LPARAM)infoPtr->hwndSelf); +} + +static void TRACKBAR_RecalculateTics (TRACKBAR_INFO *infoPtr) +{ + int i, tic, nrTics; + + if (infoPtr->uTicFreq && infoPtr->lRangeMax >= infoPtr->lRangeMin) + nrTics=(infoPtr->lRangeMax - infoPtr->lRangeMin)/infoPtr->uTicFreq; + else { + nrTics = 0; + Free (infoPtr->tics); + infoPtr->tics = NULL; + infoPtr->uNumTics = 0; + return; + } + + if (nrTics != infoPtr->uNumTics) { + infoPtr->tics=ReAlloc (infoPtr->tics, + (nrTics+1)*sizeof (DWORD)); + if (!infoPtr->tics) { + infoPtr->uNumTics = 0; + notify(infoPtr, NM_OUTOFMEMORY); + return; + } + infoPtr->uNumTics = nrTics; + } + + tic = infoPtr->lRangeMin + infoPtr->uTicFreq; + for (i = 0; i < nrTics; i++, tic += infoPtr->uTicFreq) + infoPtr->tics[i] = tic; +} + +/* converts from physical (mouse) position to logical position + (in range of trackbar) */ + +static inline LONG +TRACKBAR_ConvertPlaceToPosition (TRACKBAR_INFO *infoPtr, int place, + int vertical) +{ + double range, width, pos, offsetthumb; + + range = infoPtr->lRangeMax - infoPtr->lRangeMin; + if (vertical) { + offsetthumb = (infoPtr->rcThumb.bottom - infoPtr->rcThumb.top)/2; + width = infoPtr->rcChannel.bottom - infoPtr->rcChannel.top - (offsetthumb * 2) - 1; + pos = (range*(place - infoPtr->rcChannel.top - offsetthumb)) / width; + } else { + offsetthumb = (infoPtr->rcThumb.right - infoPtr->rcThumb.left)/2; + width = infoPtr->rcChannel.right - infoPtr->rcChannel.left - (offsetthumb * 2) - 1; + pos = (range*(place - infoPtr->rcChannel.left - offsetthumb)) / width; + } + pos += infoPtr->lRangeMin; + if (pos > infoPtr->lRangeMax) + pos = infoPtr->lRangeMax; + else if (pos < infoPtr->lRangeMin) + pos = infoPtr->lRangeMin; + + TRACE("%.2f\n", pos); + return (LONG)(pos + 0.5); +} + + +/* return: 0> prev, 0 none, >0 next */ +static LONG +TRACKBAR_GetAutoPageDirection (TRACKBAR_INFO *infoPtr, POINT clickPoint) +{ + DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE); + RECT pageRect; + + if (dwStyle & TBS_VERT) { + pageRect.top = infoPtr->rcChannel.top; + pageRect.bottom = infoPtr->rcChannel.bottom; + pageRect.left = infoPtr->rcThumb.left; + pageRect.right = infoPtr->rcThumb.right; + } else { + pageRect.top = infoPtr->rcThumb.top; + pageRect.bottom = infoPtr->rcThumb.bottom; + pageRect.left = infoPtr->rcChannel.left; + pageRect.right = infoPtr->rcChannel.right; + } + + + if (PtInRect(&pageRect, clickPoint)) + { + int clickPlace = (dwStyle & TBS_VERT) ? clickPoint.y : clickPoint.x; + + LONG clickPos = TRACKBAR_ConvertPlaceToPosition(infoPtr, clickPlace, + dwStyle & TBS_VERT); + return clickPos - infoPtr->lPos; + } + + return 0; +} + +static void inline +TRACKBAR_PageDown (TRACKBAR_INFO *infoPtr) +{ + if (infoPtr->lPos == infoPtr->lRangeMax) return; + + infoPtr->lPos += infoPtr->lPageSize; + if (infoPtr->lPos > infoPtr->lRangeMax) + infoPtr->lPos = infoPtr->lRangeMax; + notify_with_scroll (infoPtr, TB_PAGEDOWN); +} + + +static void inline +TRACKBAR_PageUp (TRACKBAR_INFO *infoPtr) +{ + if (infoPtr->lPos == infoPtr->lRangeMin) return; + + infoPtr->lPos -= infoPtr->lPageSize; + if (infoPtr->lPos < infoPtr->lRangeMin) + infoPtr->lPos = infoPtr->lRangeMin; + notify_with_scroll (infoPtr, TB_PAGEUP); +} + +static void inline TRACKBAR_LineUp(TRACKBAR_INFO *infoPtr) +{ + if (infoPtr->lPos == infoPtr->lRangeMin) return; + infoPtr->lPos -= infoPtr->lLineSize; + if (infoPtr->lPos < infoPtr->lRangeMin) + infoPtr->lPos = infoPtr->lRangeMin; + notify_with_scroll (infoPtr, TB_LINEUP); +} + +static void inline TRACKBAR_LineDown(TRACKBAR_INFO *infoPtr) +{ + if (infoPtr->lPos == infoPtr->lRangeMax) return; + infoPtr->lPos += infoPtr->lLineSize; + if (infoPtr->lPos > infoPtr->lRangeMax) + infoPtr->lPos = infoPtr->lRangeMax; + notify_with_scroll (infoPtr, TB_LINEDOWN); +} + +static void +TRACKBAR_CalcChannel (TRACKBAR_INFO *infoPtr) +{ + DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE); + INT cyChannel, offsetthumb, offsetedge; + RECT lpRect, *channel = & infoPtr->rcChannel; + + GetClientRect (infoPtr->hwndSelf, &lpRect); + + offsetthumb = infoPtr->uThumbLen / 4; + offsetedge = offsetthumb + 3; + cyChannel = (dwStyle & TBS_ENABLESELRANGE) ? offsetthumb*3 : 4; + if (dwStyle & TBS_VERT) { + channel->top = lpRect.top + offsetedge; + channel->bottom = lpRect.bottom - offsetedge; + if (dwStyle & TBS_ENABLESELRANGE) + channel->left = lpRect.left + ((infoPtr->uThumbLen - cyChannel + 2) / 2); + else + channel->left = lpRect.left + (infoPtr->uThumbLen / 2) - 1; + if (dwStyle & TBS_BOTH) { + if (dwStyle & TBS_NOTICKS) + channel->left += 1; + else + channel->left += 9; + } + else if (dwStyle & TBS_TOP) { + if (dwStyle & TBS_NOTICKS) + channel->left += 2; + else + channel->left += 10; + } + channel->right = channel->left + cyChannel; + } else { + channel->left = lpRect.left + offsetedge; + channel->right = lpRect.right - offsetedge; + if (dwStyle & TBS_ENABLESELRANGE) + channel->top = lpRect.top + ((infoPtr->uThumbLen - cyChannel + 2) / 2); + else + channel->top = lpRect.top + (infoPtr->uThumbLen / 2) - 1; + if (dwStyle & TBS_BOTH) { + if (dwStyle & TBS_NOTICKS) + channel->top += 1; + else + channel->top += 9; + } + else if (dwStyle & TBS_TOP) { + if (dwStyle & TBS_NOTICKS) + channel->top += 2; + else + channel->top += 10; + } + channel->bottom = channel->top + cyChannel; + } +} + +static void +TRACKBAR_CalcThumb (TRACKBAR_INFO *infoPtr, LONG lPos, RECT *thumb) +{ + int range, width, height, thumbwidth; + DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE); + RECT lpRect; + + range = infoPtr->lRangeMax - infoPtr->lRangeMin; + thumbwidth = (infoPtr->uThumbLen / 2) | 1; + + if (!range) range = 1; + + GetClientRect(infoPtr->hwndSelf, &lpRect); + if (dwStyle & TBS_VERT) + { + height = infoPtr->rcChannel.bottom - infoPtr->rcChannel.top - thumbwidth; + + if ((dwStyle & (TBS_BOTH | TBS_LEFT)) && !(dwStyle & TBS_NOTICKS)) + thumb->left = 10; + else + thumb->left = 2; + thumb->right = thumb->left + infoPtr->uThumbLen; + thumb->top = infoPtr->rcChannel.top + + (height*(lPos - infoPtr->lRangeMin))/range; + thumb->bottom = thumb->top + thumbwidth; + } + else + { + width = infoPtr->rcChannel.right - infoPtr->rcChannel.left - thumbwidth; + + thumb->left = infoPtr->rcChannel.left + + (width*(lPos - infoPtr->lRangeMin))/range; + thumb->right = thumb->left + thumbwidth; + if ((dwStyle & (TBS_BOTH | TBS_TOP)) && !(dwStyle & TBS_NOTICKS)) + thumb->top = 10; + else + thumb->top = 2; + thumb->bottom = thumb->top + infoPtr->uThumbLen; + } +} + +inline static void +TRACKBAR_UpdateThumb (TRACKBAR_INFO *infoPtr) +{ + TRACKBAR_CalcThumb(infoPtr, infoPtr->lPos, &infoPtr->rcThumb); +} + +static inline void +TRACKBAR_InvalidateAll(TRACKBAR_INFO * infoPtr) +{ + InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); +} + +static void +TRACKBAR_InvalidateThumb (TRACKBAR_INFO *infoPtr, LONG thumbPos) +{ + RECT rcThumb; + + TRACKBAR_CalcThumb(infoPtr, thumbPos, &rcThumb); + InflateRect(&rcThumb, 1, 1); + InvalidateRect(infoPtr->hwndSelf, &rcThumb, FALSE); +} + +static inline void +TRACKBAR_InvalidateThumbMove (TRACKBAR_INFO *infoPtr, LONG oldPos, LONG newPos) +{ + TRACKBAR_InvalidateThumb (infoPtr, oldPos); + if (newPos != oldPos) + TRACKBAR_InvalidateThumb (infoPtr, newPos); +} + +static BOOL inline +TRACKBAR_HasSelection (TRACKBAR_INFO *infoPtr) +{ + return infoPtr->lSelMin != infoPtr->lSelMax; +} + +static void +TRACKBAR_CalcSelection (TRACKBAR_INFO *infoPtr) +{ + RECT *selection = &infoPtr->rcSelection; + int range = infoPtr->lRangeMax - infoPtr->lRangeMin; + int offsetthumb, height, width; + + if (range <= 0) { + SetRectEmpty (selection); + } else { + if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_VERT) { + offsetthumb = (infoPtr->rcThumb.bottom - infoPtr->rcThumb.top)/2; + height = infoPtr->rcChannel.bottom - infoPtr->rcChannel.top - offsetthumb*2; + selection->top = infoPtr->rcChannel.top + offsetthumb + + (height*infoPtr->lSelMin)/range; + selection->bottom = infoPtr->rcChannel.top + offsetthumb + + (height*infoPtr->lSelMax)/range; + selection->left = infoPtr->rcChannel.left + 3; + selection->right = infoPtr->rcChannel.right - 3; + } else { + offsetthumb = (infoPtr->rcThumb.right - infoPtr->rcThumb.left)/2; + width = infoPtr->rcChannel.right - infoPtr->rcChannel.left - offsetthumb*2; + selection->left = infoPtr->rcChannel.left + offsetthumb + + (width*infoPtr->lSelMin)/range; + selection->right = infoPtr->rcChannel.left + offsetthumb + + (width*infoPtr->lSelMax)/range; + selection->top = infoPtr->rcChannel.top + 3; + selection->bottom = infoPtr->rcChannel.bottom - 3; + } + } + + TRACE("selection[left=%ld, top=%ld, right=%ld, bottom=%ld]\n", + selection->left, selection->top, selection->right, selection->bottom); +} + +static BOOL +TRACKBAR_AutoPage (TRACKBAR_INFO *infoPtr, POINT clickPoint) +{ + LONG dir = TRACKBAR_GetAutoPageDirection(infoPtr, clickPoint); + LONG prevPos = infoPtr->lPos; + + TRACE("x=%ld, y=%ld, dir=%ld\n", clickPoint.x, clickPoint.y, dir); + + if (dir > 0 && (infoPtr->flags & TB_AUTO_PAGE_RIGHT)) + TRACKBAR_PageDown(infoPtr); + else if (dir < 0 && (infoPtr->flags & TB_AUTO_PAGE_LEFT)) + TRACKBAR_PageUp(infoPtr); + else return FALSE; + + infoPtr->flags |= TB_THUMBPOSCHANGED; + TRACKBAR_InvalidateThumbMove (infoPtr, prevPos, infoPtr->lPos); + + return TRUE; +} + +/* Trackbar drawing code. I like my spaghetti done milanese. */ + +static void +TRACKBAR_DrawChannel (TRACKBAR_INFO *infoPtr, HDC hdc, DWORD dwStyle) +{ + RECT rcChannel = infoPtr->rcChannel; + + DrawEdge (hdc, &rcChannel, EDGE_SUNKEN, BF_RECT | BF_ADJUST); + if (dwStyle & TBS_ENABLESELRANGE) { /* fill the channel */ + FillRect (hdc, &rcChannel, GetStockObject(WHITE_BRUSH)); + if (TRACKBAR_HasSelection(infoPtr)) + FillRect (hdc, &infoPtr->rcSelection, GetSysColorBrush(COLOR_HIGHLIGHT)); + } +} + +static void +TRACKBAR_DrawOneTic (TRACKBAR_INFO *infoPtr, HDC hdc, LONG ticPos, int flags) +{ + int x, y, ox, oy, range, side, indent = 0, len = 3; + int offsetthumb; + RECT rcTics; + + if (flags & TBS_VERT) { + offsetthumb = (infoPtr->rcThumb.bottom - infoPtr->rcThumb.top)/2; + rcTics.left = infoPtr->rcThumb.left - 2; + rcTics.right = infoPtr->rcThumb.right + 2; + rcTics.top = infoPtr->rcChannel.top + offsetthumb + 1; + rcTics.bottom = infoPtr->rcChannel.bottom - offsetthumb; + } else { + offsetthumb = (infoPtr->rcThumb.right - infoPtr->rcThumb.left)/2; + rcTics.left = infoPtr->rcChannel.left + offsetthumb + 1; + rcTics.right = infoPtr->rcChannel.right - offsetthumb; + rcTics.top = infoPtr->rcThumb.top - 2; + rcTics.bottom = infoPtr->rcThumb.bottom + 2; + } + + if (flags & (TBS_TOP | TBS_LEFT)) { + x = rcTics.left; + y = rcTics.top; + side = -1; + } else { + x = rcTics.right; + y = rcTics.bottom; + side = 1; + } + + range = infoPtr->lRangeMax - infoPtr->lRangeMin; + if (range <= 0) + range = 1; /* to avoid division by zero */ + + if (flags & TIC_SELECTIONMARK) { + indent = (flags & TIC_SELECTIONMARKMIN) ? -1 : 1; + } else if (flags & TIC_EDGE) { + len++; + } + + if (flags & TBS_VERT) { + int height = rcTics.bottom - rcTics.top; + y = rcTics.top + (height*(ticPos - infoPtr->lRangeMin))/range; + } else { + int width = rcTics.right - rcTics.left; + x = rcTics.left + (width*(ticPos - infoPtr->lRangeMin))/range; + } + + ox = x; + oy = y; + MoveToEx(hdc, x, y, 0); + if (flags & TBS_VERT) x += len * side; + else y += len * side; + LineTo(hdc, x, y); + + if (flags & TIC_SELECTIONMARK) { + if (flags & TBS_VERT) { + x -= side; + } else { + y -= side; + } + MoveToEx(hdc, x, y, 0); + if (flags & TBS_VERT) { + y += 2 * indent; + } else { + x += 2 * indent; + } + + LineTo(hdc, x, y); + LineTo(hdc, ox, oy); + } +} + + +static inline void +TRACKBAR_DrawTic (TRACKBAR_INFO *infoPtr, HDC hdc, LONG ticPos, int flags) +{ + if ((flags & (TBS_LEFT | TBS_TOP)) || (flags & TBS_BOTH)) + TRACKBAR_DrawOneTic (infoPtr, hdc, ticPos, flags | TBS_LEFT); + + if (!(flags & (TBS_LEFT | TBS_TOP)) || (flags & TBS_BOTH)) + TRACKBAR_DrawOneTic (infoPtr, hdc, ticPos, flags & ~TBS_LEFT); +} + +static void +TRACKBAR_DrawTics (TRACKBAR_INFO *infoPtr, HDC hdc, DWORD dwStyle) +{ + unsigned int i; + int ticFlags = dwStyle & 0x0f; + LOGPEN ticPen = { PS_SOLID, {1, 0}, GetSysColor (COLOR_3DDKSHADOW) }; + HPEN hOldPen, hTicPen; + + /* create the pen to draw the tics with */ + hTicPen = CreatePenIndirect(&ticPen); + hOldPen = hTicPen ? SelectObject(hdc, hTicPen) : 0; + + /* actually draw the tics */ + for (i=0; iuNumTics; i++) + TRACKBAR_DrawTic (infoPtr, hdc, infoPtr->tics[i], ticFlags); + + TRACKBAR_DrawTic (infoPtr, hdc, infoPtr->lRangeMin, ticFlags | TIC_EDGE); + TRACKBAR_DrawTic (infoPtr, hdc, infoPtr->lRangeMax, ticFlags | TIC_EDGE); + + if ((dwStyle & TBS_ENABLESELRANGE) && TRACKBAR_HasSelection(infoPtr)) { + TRACKBAR_DrawTic (infoPtr, hdc, infoPtr->lSelMin, + ticFlags | TIC_SELECTIONMARKMIN); + TRACKBAR_DrawTic (infoPtr, hdc, infoPtr->lSelMax, + ticFlags | TIC_SELECTIONMARKMAX); + } + + /* clean up the pen, if we created one */ + if (hTicPen) { + SelectObject(hdc, hOldPen); + DeleteObject(hTicPen); + } +} + +static void +TRACKBAR_DrawThumb(TRACKBAR_INFO *infoPtr, HDC hdc, DWORD dwStyle) +{ + HBRUSH oldbr; + HPEN oldpen; + RECT thumb = infoPtr->rcThumb; + int BlackUntil = 3; + int PointCount = 6; + POINT points[6]; + int fillClr; + int PointDepth; + + fillClr = infoPtr->flags & TB_DRAG_MODE ? COLOR_BTNHILIGHT : COLOR_BTNFACE; + oldbr = SelectObject (hdc, GetSysColorBrush(fillClr)); + SetPolyFillMode (hdc, WINDING); + + if (dwStyle & TBS_BOTH) + { + points[0].x=thumb.right; + points[0].y=thumb.top; + points[1].x=thumb.right; + points[1].y=thumb.bottom; + points[2].x=thumb.left; + points[2].y=thumb.bottom; + points[3].x=thumb.left; + points[3].y=thumb.top; + points[4].x=points[0].x; + points[4].y=points[0].y; + PointCount = 5; + BlackUntil = 3; + } + else + { + if (dwStyle & TBS_VERT) + { + PointDepth = (thumb.bottom - thumb.top) / 2; + if (dwStyle & TBS_LEFT) + { + points[0].x=thumb.right; + points[0].y=thumb.top; + points[1].x=thumb.right; + points[1].y=thumb.bottom; + points[2].x=thumb.left + PointDepth; + points[2].y=thumb.bottom; + points[3].x=thumb.left; + points[3].y=(thumb.bottom - thumb.top) / 2 + thumb.top + 1; + points[4].x=thumb.left + PointDepth; + points[4].y=thumb.top; + points[5].x=points[0].x; + points[5].y=points[0].y; + BlackUntil = 4; + } + else + { + points[0].x=thumb.right; + points[0].y=(thumb.bottom - thumb.top) / 2 + thumb.top + 1; + points[1].x=thumb.right - PointDepth; + points[1].y=thumb.bottom; + points[2].x=thumb.left; + points[2].y=thumb.bottom; + points[3].x=thumb.left; + points[3].y=thumb.top; + points[4].x=thumb.right - PointDepth; + points[4].y=thumb.top; + points[5].x=points[0].x; + points[5].y=points[0].y; + } + } + else + { + PointDepth = (thumb.right - thumb.left) / 2; + if (dwStyle & TBS_TOP) + { + points[0].x=(thumb.right - thumb.left) / 2 + thumb.left + 1; + points[0].y=thumb.top; + points[1].x=thumb.right; + points[1].y=thumb.top + PointDepth; + points[2].x=thumb.right; + points[2].y=thumb.bottom; + points[3].x=thumb.left; + points[3].y=thumb.bottom; + points[4].x=thumb.left; + points[4].y=thumb.top + PointDepth; + points[5].x=points[0].x; + points[5].y=points[0].y; + BlackUntil = 4; + } + else + { + points[0].x=thumb.right; + points[0].y=thumb.top; + points[1].x=thumb.right; + points[1].y=thumb.bottom - PointDepth; + points[2].x=(thumb.right - thumb.left) / 2 + thumb.left + 1; + points[2].y=thumb.bottom; + points[3].x=thumb.left; + points[3].y=thumb.bottom - PointDepth; + points[4].x=thumb.left; + points[4].y=thumb.top; + points[5].x=points[0].x; + points[5].y=points[0].y; + } + } + + } + + /* Draw the thumb now */ + Polygon (hdc, points, PointCount); + oldpen = SelectObject(hdc, GetStockObject(BLACK_PEN)); + Polyline(hdc,points, BlackUntil); + SelectObject(hdc, GetStockObject(WHITE_PEN)); + Polyline(hdc, &points[BlackUntil-1], PointCount+1-BlackUntil); + SelectObject(hdc, oldpen); + SelectObject(hdc, oldbr); +} + + +static void inline +TRACKBAR_ActivateToolTip (TRACKBAR_INFO *infoPtr, BOOL fShow) +{ + TTTOOLINFOW ti; + + if (!infoPtr->hwndToolTip) return; + + ZeroMemory(&ti, sizeof(ti)); + ti.cbSize = sizeof(ti); + ti.hwnd = infoPtr->hwndSelf; + + SendMessageW (infoPtr->hwndToolTip, TTM_TRACKACTIVATE, fShow, (LPARAM)&ti); +} + + +static void +TRACKBAR_UpdateToolTip (TRACKBAR_INFO *infoPtr) +{ + DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE); + WCHAR buf[80]; + static const WCHAR fmt[] = { '%', 'l', 'd', 0 }; + TTTOOLINFOW ti; + POINT pt; + RECT rcClient; + LRESULT size; + + if (!infoPtr->hwndToolTip) return; + + ZeroMemory(&ti, sizeof(ti)); + ti.cbSize = sizeof(ti); + ti.hwnd = infoPtr->hwndSelf; + ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE; + + wsprintfW (buf, fmt, infoPtr->lPos); + ti.lpszText = buf; + SendMessageW (infoPtr->hwndToolTip, TTM_UPDATETIPTEXTW, 0, (LPARAM)&ti); + + GetClientRect (infoPtr->hwndSelf, &rcClient); + size = SendMessageW (infoPtr->hwndToolTip, TTM_GETBUBBLESIZE, 0, (LPARAM)&ti); + if (dwStyle & TBS_VERT) { + if (infoPtr->fLocation == TBTS_LEFT) + pt.x = 0 - LOWORD(size) - TOOLTIP_OFFSET; + else + pt.x = rcClient.right + TOOLTIP_OFFSET; + pt.y = (infoPtr->rcThumb.top + infoPtr->rcThumb.bottom - HIWORD(size))/2; + } else { + if (infoPtr->fLocation == TBTS_TOP) + pt.y = 0 - HIWORD(size) - TOOLTIP_OFFSET; + else + pt.y = rcClient.bottom + TOOLTIP_OFFSET; + pt.x = (infoPtr->rcThumb.left + infoPtr->rcThumb.right - LOWORD(size))/2; + } + ClientToScreen(infoPtr->hwndSelf, &pt); + + SendMessageW (infoPtr->hwndToolTip, TTM_TRACKPOSITION, + 0, (LPARAM)MAKELPARAM(pt.x, pt.y)); +} + + +static void +TRACKBAR_Refresh (TRACKBAR_INFO *infoPtr, HDC hdcDst) +{ + DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE); + RECT rcClient; + HDC hdc; + HBITMAP hOldBmp = 0, hOffScreenBmp = 0; + NMCUSTOMDRAW nmcd; + int gcdrf, icdrf; + + if (infoPtr->flags & TB_THUMBCHANGED) { + TRACKBAR_UpdateThumb (infoPtr); + if (infoPtr->flags & TB_THUMBSIZECHANGED) + TRACKBAR_CalcChannel (infoPtr); + } + if (infoPtr->flags & TB_SELECTIONCHANGED) + TRACKBAR_CalcSelection (infoPtr); + + if (infoPtr->flags & TB_DRAG_MODE) + TRACKBAR_UpdateToolTip (infoPtr); + + infoPtr->flags &= ~ (TB_THUMBCHANGED | TB_SELECTIONCHANGED); + + GetClientRect (infoPtr->hwndSelf, &rcClient); + + /* try to render offscreen, if we fail, carrry onscreen */ + hdc = CreateCompatibleDC(hdcDst); + if (hdc) { + hOffScreenBmp = CreateCompatibleBitmap(hdcDst, rcClient.right, rcClient.bottom); + if (hOffScreenBmp) { + hOldBmp = SelectObject(hdc, hOffScreenBmp); + } else { + DeleteObject(hdc); + hdc = hdcDst; + } + } else { + hdc = hdcDst; + } + + ZeroMemory(&nmcd, sizeof(nmcd)); + nmcd.hdr.hwndFrom = infoPtr->hwndSelf; + nmcd.hdr.idFrom = GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_ID); + nmcd.hdr.code = NM_CUSTOMDRAW; + nmcd.hdc = hdc; + + /* start the paint cycle */ + nmcd.rc = rcClient; + gcdrf = notify_customdraw(infoPtr, &nmcd, CDDS_PREPAINT); + if (gcdrf & CDRF_SKIPDEFAULT) goto cleanup; + + /* Erase backbround */ + if (gcdrf == CDRF_DODEFAULT || + notify_customdraw(infoPtr, &nmcd, CDDS_PREERASE) != CDRF_SKIPDEFAULT) { + FillRect (hdc, &rcClient, GetSysColorBrush(COLOR_BTNFACE)); + if (gcdrf != CDRF_DODEFAULT) + notify_customdraw(infoPtr, &nmcd, CDDS_POSTERASE); + } + + /* draw channel */ + if (gcdrf & CDRF_NOTIFYITEMDRAW) { + nmcd.dwItemSpec = TBCD_CHANNEL; + nmcd.uItemState = CDIS_DEFAULT; + nmcd.rc = infoPtr->rcChannel; + icdrf = notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPREPAINT); + } else icdrf = CDRF_DODEFAULT; + if ( !(icdrf & CDRF_SKIPDEFAULT) ) { + TRACKBAR_DrawChannel (infoPtr, hdc, dwStyle); + if (icdrf & CDRF_NOTIFYPOSTPAINT) + notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPOSTPAINT); + } + + + /* draw tics */ + if (!(dwStyle & TBS_NOTICKS)) { + if (gcdrf & CDRF_NOTIFYITEMDRAW) { + nmcd.dwItemSpec = TBCD_TICS; + nmcd.uItemState = CDIS_DEFAULT; + nmcd.rc = rcClient; + icdrf = notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPREPAINT); + } else icdrf = CDRF_DODEFAULT; + if ( !(icdrf & CDRF_SKIPDEFAULT) ) { + TRACKBAR_DrawTics (infoPtr, hdc, dwStyle); + if (icdrf & CDRF_NOTIFYPOSTPAINT) + notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPOSTPAINT); + } + } + + /* draw thumb */ + if (!(dwStyle & TBS_NOTHUMB)) { + if (gcdrf & CDRF_NOTIFYITEMDRAW) { + nmcd.dwItemSpec = TBCD_THUMB; + nmcd.uItemState = infoPtr->flags & TB_DRAG_MODE ? CDIS_HOT : CDIS_DEFAULT; + nmcd.rc = infoPtr->rcThumb; + icdrf = notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPREPAINT); + } else icdrf = CDRF_DODEFAULT; + if ( !(icdrf & CDRF_SKIPDEFAULT) ) { + TRACKBAR_DrawThumb(infoPtr, hdc, dwStyle); + if (icdrf & CDRF_NOTIFYPOSTPAINT) + notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPOSTPAINT); + } + } + + /* draw focus rectangle */ + if (infoPtr->bFocussed) { + DrawFocusRect(hdc, &rcClient); + } + + /* finish up the painting */ + if (gcdrf & CDRF_NOTIFYPOSTPAINT) + notify_customdraw(infoPtr, &nmcd, CDDS_POSTPAINT); + +cleanup: + /* cleanup, if we rendered offscreen */ + if (hdc != hdcDst) { + BitBlt(hdcDst, 0, 0, rcClient.right, rcClient.bottom, hdc, 0, 0, SRCCOPY); + SelectObject(hdc, hOldBmp); + DeleteObject(hOffScreenBmp); + DeleteObject(hdc); + } +} + + +static void +TRACKBAR_AlignBuddies (TRACKBAR_INFO *infoPtr) +{ + DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE); + HWND hwndParent = GetParent (infoPtr->hwndSelf); + RECT rcSelf, rcBuddy; + INT x, y; + + GetWindowRect (infoPtr->hwndSelf, &rcSelf); + MapWindowPoints (HWND_DESKTOP, hwndParent, (LPPOINT)&rcSelf, 2); + + /* align buddy left or above */ + if (infoPtr->hwndBuddyLA) { + GetWindowRect (infoPtr->hwndBuddyLA, &rcBuddy); + MapWindowPoints (HWND_DESKTOP, hwndParent, (LPPOINT)&rcBuddy, 2); + + if (dwStyle & TBS_VERT) { + x = (infoPtr->rcChannel.right + infoPtr->rcChannel.left) / 2 - + (rcBuddy.right - rcBuddy.left) / 2 + rcSelf.left; + y = rcSelf.top - (rcBuddy.bottom - rcBuddy.top); + } + else { + x = rcSelf.left - (rcBuddy.right - rcBuddy.left); + y = (infoPtr->rcChannel.bottom + infoPtr->rcChannel.top) / 2 - + (rcBuddy.bottom - rcBuddy.top) / 2 + rcSelf.top; + } + + SetWindowPos (infoPtr->hwndBuddyLA, 0, x, y, 0, 0, + SWP_NOZORDER | SWP_NOSIZE); + } + + + /* align buddy right or below */ + if (infoPtr->hwndBuddyRB) { + GetWindowRect (infoPtr->hwndBuddyRB, &rcBuddy); + MapWindowPoints (HWND_DESKTOP, hwndParent, (LPPOINT)&rcBuddy, 2); + + if (dwStyle & TBS_VERT) { + x = (infoPtr->rcChannel.right + infoPtr->rcChannel.left) / 2 - + (rcBuddy.right - rcBuddy.left) / 2 + rcSelf.left; + y = rcSelf.bottom; + } + else { + x = rcSelf.right; + y = (infoPtr->rcChannel.bottom + infoPtr->rcChannel.top) / 2 - + (rcBuddy.bottom - rcBuddy.top) / 2 + rcSelf.top; + } + SetWindowPos (infoPtr->hwndBuddyRB, 0, x, y, 0, 0, + SWP_NOZORDER | SWP_NOSIZE); + } +} + + +static LRESULT +TRACKBAR_ClearSel (TRACKBAR_INFO *infoPtr, BOOL fRedraw) +{ + infoPtr->lSelMin = 0; + infoPtr->lSelMax = 0; + infoPtr->flags |= TB_SELECTIONCHANGED; + + if (fRedraw) TRACKBAR_InvalidateAll(infoPtr); + + return 0; +} + + +static LRESULT +TRACKBAR_ClearTics (TRACKBAR_INFO *infoPtr, BOOL fRedraw) +{ + if (infoPtr->tics) { + Free (infoPtr->tics); + infoPtr->tics = NULL; + infoPtr->uNumTics = 0; + } + + if (fRedraw) TRACKBAR_InvalidateAll(infoPtr); + + return 0; +} + + +static LRESULT inline +TRACKBAR_GetChannelRect (TRACKBAR_INFO *infoPtr, LPRECT lprc) +{ + if (lprc == NULL) return 0; + + lprc->left = infoPtr->rcChannel.left; + lprc->right = infoPtr->rcChannel.right; + lprc->bottom = infoPtr->rcChannel.bottom; + lprc->top = infoPtr->rcChannel.top; + + return 0; +} + + +static LONG inline +TRACKBAR_GetNumTics (TRACKBAR_INFO *infoPtr) +{ + if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_NOTICKS) + return 0; + + return infoPtr->uNumTics + 2; +} + + +static int comp_tics(const void *ap, const void *bp) +{ + DWORD a = *((DWORD *)ap); + DWORD b = *((DWORD *)bp); + + TRACE("(a=%ld, b=%ld)\n", a, b); + if (a < b) return -1; + if (a > b) return 1; + return 0; +} + + +static LONG inline +TRACKBAR_GetTic (TRACKBAR_INFO *infoPtr, INT iTic) +{ + if ((iTic < 0) || (iTic >= infoPtr->uNumTics) || !infoPtr->tics) + return -1; + + qsort(infoPtr->tics, infoPtr->uNumTics, sizeof(DWORD), comp_tics); + return infoPtr->tics[iTic]; +} + + +static LONG inline +TRACKBAR_GetTicPos (TRACKBAR_INFO *infoPtr, INT iTic) +{ + LONG range, width, pos, tic; + int offsetthumb; + + if ((iTic < 0) || (iTic >= infoPtr->uNumTics) || !infoPtr->tics) + return -1; + + tic = TRACKBAR_GetTic (infoPtr, iTic); + range = infoPtr->lRangeMax - infoPtr->lRangeMin; + if (range <= 0) range = 1; + offsetthumb = (infoPtr->rcThumb.right - infoPtr->rcThumb.left)/2; + width = infoPtr->rcChannel.right - infoPtr->rcChannel.left - offsetthumb*2; + pos = infoPtr->rcChannel.left + offsetthumb + (width * tic) / range; + + return pos; +} + + +static HWND +TRACKBAR_SetBuddy (TRACKBAR_INFO *infoPtr, BOOL fLocation, HWND hwndBuddy) +{ + HWND hwndTemp; + + if (fLocation) { + /* buddy is left or above */ + hwndTemp = infoPtr->hwndBuddyLA; + infoPtr->hwndBuddyLA = hwndBuddy; + } + else { + /* buddy is right or below */ + hwndTemp = infoPtr->hwndBuddyRB; + infoPtr->hwndBuddyRB = hwndBuddy; + } + + TRACKBAR_AlignBuddies (infoPtr); + + return hwndTemp; +} + + +static LONG inline +TRACKBAR_SetLineSize (TRACKBAR_INFO *infoPtr, LONG lLineSize) +{ + LONG lTemp = infoPtr->lLineSize; + + infoPtr->lLineSize = lLineSize; + + return lTemp; +} + + +static LONG inline +TRACKBAR_SetPageSize (TRACKBAR_INFO *infoPtr, LONG lPageSize) +{ + LONG lTemp = infoPtr->lPageSize; + + infoPtr->lPageSize = lPageSize; + + return lTemp; +} + + +static LRESULT inline +TRACKBAR_SetPos (TRACKBAR_INFO *infoPtr, BOOL fPosition, LONG lPosition) +{ + LONG oldPos = infoPtr->lPos; + infoPtr->lPos = lPosition; + + if (infoPtr->lPos < infoPtr->lRangeMin) + infoPtr->lPos = infoPtr->lRangeMin; + + if (infoPtr->lPos > infoPtr->lRangeMax) + infoPtr->lPos = infoPtr->lRangeMax; + infoPtr->flags |= TB_THUMBPOSCHANGED; + + if (fPosition) TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, lPosition); + + return 0; +} + + +static LRESULT inline +TRACKBAR_SetRange (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lRange) +{ + infoPtr->lRangeMin = (SHORT)LOWORD(lRange); + infoPtr->lRangeMax = (SHORT)HIWORD(lRange); + + if (infoPtr->lPos < infoPtr->lRangeMin) { + infoPtr->lPos = infoPtr->lRangeMin; + infoPtr->flags |= TB_THUMBPOSCHANGED; + } + + if (infoPtr->lPos > infoPtr->lRangeMax) { + infoPtr->lPos = infoPtr->lRangeMax; + infoPtr->flags |= TB_THUMBPOSCHANGED; + } + + infoPtr->lPageSize = (infoPtr->lRangeMax - infoPtr->lRangeMin) / 5; + if (infoPtr->lPageSize == 0) infoPtr->lPageSize = 1; + + if (fRedraw) TRACKBAR_InvalidateAll(infoPtr); + + return 0; +} + + +static LRESULT inline +TRACKBAR_SetRangeMax (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lMax) +{ + infoPtr->lRangeMax = lMax; + if (infoPtr->lPos > infoPtr->lRangeMax) { + infoPtr->lPos = infoPtr->lRangeMax; + infoPtr->flags |= TB_THUMBPOSCHANGED; + } + + infoPtr->lPageSize = (infoPtr->lRangeMax - infoPtr->lRangeMin) / 5; + if (infoPtr->lPageSize == 0) infoPtr->lPageSize = 1; + + if (fRedraw) TRACKBAR_InvalidateAll(infoPtr); + + return 0; +} + + +static LRESULT inline +TRACKBAR_SetRangeMin (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lMin) +{ + infoPtr->lRangeMin = lMin; + if (infoPtr->lPos < infoPtr->lRangeMin) { + infoPtr->lPos = infoPtr->lRangeMin; + infoPtr->flags |= TB_THUMBPOSCHANGED; + } + + infoPtr->lPageSize = (infoPtr->lRangeMax - infoPtr->lRangeMin) / 5; + if (infoPtr->lPageSize == 0) infoPtr->lPageSize = 1; + + if (fRedraw) TRACKBAR_InvalidateAll(infoPtr); + + return 0; +} + + +static LRESULT inline +TRACKBAR_SetSel (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lSel) +{ + if (!GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_ENABLESELRANGE) + return 0; + + infoPtr->lSelMin = (SHORT)LOWORD(lSel); + infoPtr->lSelMax = (SHORT)HIWORD(lSel); + infoPtr->flags |= TB_SELECTIONCHANGED; + + if (infoPtr->lSelMin < infoPtr->lRangeMin) + infoPtr->lSelMin = infoPtr->lRangeMin; + if (infoPtr->lSelMax > infoPtr->lRangeMax) + infoPtr->lSelMax = infoPtr->lRangeMax; + + if (fRedraw) TRACKBAR_InvalidateAll(infoPtr); + + return 0; +} + + +static LRESULT inline +TRACKBAR_SetSelEnd (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lEnd) +{ + if (!GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_ENABLESELRANGE) + return 0; + + infoPtr->lSelMax = lEnd; + infoPtr->flags |= TB_SELECTIONCHANGED; + + if (infoPtr->lSelMax > infoPtr->lRangeMax) + infoPtr->lSelMax = infoPtr->lRangeMax; + + if (fRedraw) TRACKBAR_InvalidateAll(infoPtr); + + return 0; +} + + +static LRESULT inline +TRACKBAR_SetSelStart (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lStart) +{ + if (!GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_ENABLESELRANGE) + return 0; + + infoPtr->lSelMin = lStart; + infoPtr->flags |=TB_SELECTIONCHANGED; + + if (infoPtr->lSelMin < infoPtr->lRangeMin) + infoPtr->lSelMin = infoPtr->lRangeMin; + + if (fRedraw) TRACKBAR_InvalidateAll(infoPtr); + + return 0; +} + + +static LRESULT inline +TRACKBAR_SetThumbLength (TRACKBAR_INFO *infoPtr, UINT iLength) +{ + if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_FIXEDLENGTH) { + infoPtr->uThumbLen = iLength; + infoPtr->flags |= TB_THUMBSIZECHANGED; + InvalidateRect (infoPtr->hwndSelf, &infoPtr->rcThumb, FALSE); + } + + return 0; +} + + +static LRESULT inline +TRACKBAR_SetTic (TRACKBAR_INFO *infoPtr, LONG lPos) +{ + if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_AUTOTICKS) + return FALSE; + + if ((lPos < infoPtr->lRangeMin) || (lPos> infoPtr->lRangeMax)) + return FALSE; + + TRACE("lPos=%ld\n", lPos); + + infoPtr->uNumTics++; + infoPtr->tics=ReAlloc( infoPtr->tics, + (infoPtr->uNumTics)*sizeof (DWORD)); + if (!infoPtr->tics) { + infoPtr->uNumTics = 0; + notify(infoPtr, NM_OUTOFMEMORY); + return FALSE; + } + infoPtr->tics[infoPtr->uNumTics-1] = lPos; + + TRACKBAR_InvalidateAll(infoPtr); + + return TRUE; +} + + +static LRESULT inline +TRACKBAR_SetTicFreq (TRACKBAR_INFO *infoPtr, WORD wFreq) +{ + if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_AUTOTICKS) { + infoPtr->uTicFreq = wFreq; + TRACKBAR_RecalculateTics (infoPtr); + TRACKBAR_InvalidateAll(infoPtr); + } + + return 0; +} + + +static INT inline +TRACKBAR_SetTipSide (TRACKBAR_INFO *infoPtr, INT fLocation) +{ + INT fTemp = infoPtr->fLocation; + + infoPtr->fLocation = fLocation; + + return fTemp; +} + + +static LRESULT inline +TRACKBAR_SetToolTips (TRACKBAR_INFO *infoPtr, HWND hwndTT) +{ + infoPtr->hwndToolTip = hwndTT; + + return 0; +} + + +static BOOL inline +TRACKBAR_SetUnicodeFormat (TRACKBAR_INFO *infoPtr, BOOL fUnicode) +{ + BOOL bTemp = infoPtr->bUnicode; + + infoPtr->bUnicode = fUnicode; + + return bTemp; +} + + +static LRESULT +TRACKBAR_InitializeThumb (TRACKBAR_INFO *infoPtr) +{ + DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE); + RECT rect; + int clientWidth, clientMetric; + + /* initial thumb length */ + clientMetric = (dwStyle & TBS_ENABLESELRANGE) ? 23 : 21; + GetClientRect(infoPtr->hwndSelf,&rect); + if (dwStyle & TBS_VERT) { + clientWidth = rect.right - rect.left; + } else { + clientWidth = rect.bottom - rect.top; + } + if (clientWidth >= clientMetric) + infoPtr->uThumbLen = clientMetric; + else + infoPtr->uThumbLen = clientWidth > 9 ? clientWidth - 6 : 4; + + TRACKBAR_CalcChannel (infoPtr); + TRACKBAR_UpdateThumb (infoPtr); + infoPtr->flags &= ~TB_SELECTIONCHANGED; + + return 0; +} + + +static LRESULT +TRACKBAR_Create (HWND hwnd, LPCREATESTRUCTW lpcs) +{ + TRACKBAR_INFO *infoPtr; + DWORD dwStyle; + + infoPtr = (TRACKBAR_INFO *)Alloc (sizeof(TRACKBAR_INFO)); + if (!infoPtr) return -1; + SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); + + /* set default values */ + infoPtr->hwndSelf = hwnd; + infoPtr->lRangeMin = 0; + infoPtr->lRangeMax = 100; + infoPtr->lLineSize = 1; + infoPtr->lPageSize = 20; + infoPtr->lSelMin = 0; + infoPtr->lSelMax = 0; + infoPtr->lPos = 0; + infoPtr->fLocation = -1; + infoPtr->uNumTics = 0; /* start and end tic are not included in count*/ + infoPtr->uTicFreq = 1; + infoPtr->tics = NULL; + infoPtr->hwndNotify= lpcs->hwndParent; + + TRACKBAR_InitializeThumb (infoPtr); + + dwStyle = GetWindowLongW (hwnd, GWL_STYLE); + + /* Create tooltip control */ + if (dwStyle & TBS_TOOLTIPS) { + + infoPtr->hwndToolTip = + CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, 0, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + hwnd, 0, 0, 0); + + if (infoPtr->hwndToolTip) { + TTTOOLINFOW ti; + ZeroMemory (&ti, sizeof(ti)); + ti.cbSize = sizeof(ti); + ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE; + ti.hwnd = hwnd; + + SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, 0, (LPARAM)&ti); + } + } + + return 0; +} + + +static LRESULT +TRACKBAR_Destroy (TRACKBAR_INFO *infoPtr) +{ + /* delete tooltip control */ + if (infoPtr->hwndToolTip) + DestroyWindow (infoPtr->hwndToolTip); + + Free (infoPtr); + SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0); + return 0; +} + + +static LRESULT +TRACKBAR_KillFocus (TRACKBAR_INFO *infoPtr, HWND hwndGetFocus) +{ + TRACE("\n"); + infoPtr->bFocussed = FALSE; + TRACKBAR_InvalidateAll(infoPtr); + + return 0; +} + +static LRESULT +TRACKBAR_LButtonDown (TRACKBAR_INFO *infoPtr, DWORD fwKeys, INT x, INT y) +{ + POINT clickPoint; + + clickPoint.x = x; + clickPoint.y = y; + + SetFocus(infoPtr->hwndSelf); + + if (PtInRect(&infoPtr->rcThumb, clickPoint)) { + infoPtr->flags |= TB_DRAG_MODE; + SetCapture (infoPtr->hwndSelf); + TRACKBAR_UpdateToolTip (infoPtr); + TRACKBAR_ActivateToolTip (infoPtr, TRUE); + TRACKBAR_InvalidateThumb(infoPtr, infoPtr->lPos); + } else { + LONG dir = TRACKBAR_GetAutoPageDirection(infoPtr, clickPoint); + if (dir == 0) return 0; + infoPtr->flags |= (dir < 0) ? TB_AUTO_PAGE_LEFT : TB_AUTO_PAGE_RIGHT; + TRACKBAR_AutoPage (infoPtr, clickPoint); + SetCapture (infoPtr->hwndSelf); + SetTimer(infoPtr->hwndSelf, TB_REFRESH_TIMER, TB_REFRESH_DELAY, 0); + } + + return 0; +} + + +static LRESULT +TRACKBAR_LButtonUp (TRACKBAR_INFO *infoPtr, DWORD fwKeys, INT x, INT y) +{ + if (infoPtr->flags & TB_DRAG_MODE) { + notify_with_scroll (infoPtr, TB_THUMBPOSITION | (infoPtr->lPos<<16)); + notify_with_scroll (infoPtr, TB_ENDTRACK); + infoPtr->flags &= ~TB_DRAG_MODE; + ReleaseCapture (); + notify(infoPtr, NM_RELEASEDCAPTURE); + TRACKBAR_ActivateToolTip(infoPtr, FALSE); + TRACKBAR_InvalidateThumb(infoPtr, infoPtr->lPos); + } + if (infoPtr->flags & TB_AUTO_PAGE) { + KillTimer (infoPtr->hwndSelf, TB_REFRESH_TIMER); + infoPtr->flags &= ~TB_AUTO_PAGE; + notify_with_scroll (infoPtr, TB_ENDTRACK); + ReleaseCapture (); + notify(infoPtr, NM_RELEASEDCAPTURE); + } + + return 0; +} + + +static LRESULT +TRACKBAR_CaptureChanged (TRACKBAR_INFO *infoPtr) +{ + notify_with_scroll (infoPtr, TB_ENDTRACK); + return 0; +} + + +static LRESULT +TRACKBAR_Paint (TRACKBAR_INFO *infoPtr, HDC hdc) +{ + if (hdc) { + TRACKBAR_Refresh(infoPtr, hdc); + } else { + PAINTSTRUCT ps; + hdc = BeginPaint (infoPtr->hwndSelf, &ps); + TRACKBAR_Refresh (infoPtr, hdc); + EndPaint (infoPtr->hwndSelf, &ps); + } + + return 0; +} + + +static LRESULT +TRACKBAR_SetFocus (TRACKBAR_INFO *infoPtr, HWND hwndLoseFocus) +{ + TRACE("\n"); + infoPtr->bFocussed = TRUE; + TRACKBAR_InvalidateAll(infoPtr); + + return 0; +} + + +static LRESULT +TRACKBAR_Size (TRACKBAR_INFO *infoPtr, DWORD fwSizeType, INT nWidth, INT nHeight) +{ + TRACKBAR_InitializeThumb (infoPtr); + TRACKBAR_AlignBuddies (infoPtr); + + return 0; +} + + +static LRESULT +TRACKBAR_Timer (TRACKBAR_INFO *infoPtr, INT wTimerID, TIMERPROC *tmrpc) +{ + if (infoPtr->flags & TB_AUTO_PAGE) { + POINT pt; + if (GetCursorPos(&pt)) + if (ScreenToClient(infoPtr->hwndSelf, &pt)) + TRACKBAR_AutoPage(infoPtr, pt); + } + return 0; +} + + +static LRESULT +TRACKBAR_MouseMove (TRACKBAR_INFO *infoPtr, DWORD fwKeys, INT x, INT y) +{ + DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE); + INT clickPlace = (dwStyle & TBS_VERT) ? y : x; + LONG dragPos, oldPos = infoPtr->lPos; + + TRACE("(x=%d. y=%d)\n", x, y); + + if (infoPtr->flags & TB_AUTO_PAGE) { + POINT pt; + pt.x = x; + pt.y = y; + TRACKBAR_AutoPage (infoPtr, pt); + return TRUE; + } + + if (!(infoPtr->flags & TB_DRAG_MODE)) return TRUE; + + dragPos = TRACKBAR_ConvertPlaceToPosition (infoPtr, clickPlace, + dwStyle & TBS_VERT); + if (dragPos == oldPos) return TRUE; + + infoPtr->lPos = dragPos; + + infoPtr->flags |= TB_THUMBPOSCHANGED; + notify_with_scroll (infoPtr, TB_THUMBTRACK | (infoPtr->lPos<<16)); + + + TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, dragPos); + UpdateWindow (infoPtr->hwndSelf); + + return TRUE; +} + +static BOOL +TRACKBAR_KeyDown (TRACKBAR_INFO *infoPtr, INT nVirtKey, DWORD lKeyData) +{ + DWORD style = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE); + BOOL downIsLeft = style & TBS_DOWNISLEFT; + BOOL vert = style & TBS_VERT; + LONG pos = infoPtr->lPos; + + TRACE("%x\n", nVirtKey); + + switch (nVirtKey) { + case VK_UP: + if (!vert && downIsLeft) TRACKBAR_LineDown(infoPtr); + else TRACKBAR_LineUp(infoPtr); + break; + case VK_LEFT: + if (vert && downIsLeft) TRACKBAR_LineDown(infoPtr); + else TRACKBAR_LineUp(infoPtr); + break; + case VK_DOWN: + if (!vert && downIsLeft) TRACKBAR_LineUp(infoPtr); + else TRACKBAR_LineDown(infoPtr); + break; + case VK_RIGHT: + if (vert && downIsLeft) TRACKBAR_LineUp(infoPtr); + else TRACKBAR_LineDown(infoPtr); + break; + case VK_NEXT: + if (!vert && downIsLeft) TRACKBAR_PageUp(infoPtr); + else TRACKBAR_PageDown(infoPtr); + break; + case VK_PRIOR: + if (!vert && downIsLeft) TRACKBAR_PageDown(infoPtr); + else TRACKBAR_PageUp(infoPtr); + break; + case VK_HOME: + if (infoPtr->lPos == infoPtr->lRangeMin) return FALSE; + infoPtr->lPos = infoPtr->lRangeMin; + notify_with_scroll (infoPtr, TB_TOP); + break; + case VK_END: + if (infoPtr->lPos == infoPtr->lRangeMax) return FALSE; + infoPtr->lPos = infoPtr->lRangeMax; + notify_with_scroll (infoPtr, TB_BOTTOM); + break; + } + + if (pos != infoPtr->lPos) { + infoPtr->flags |=TB_THUMBPOSCHANGED; + TRACKBAR_InvalidateThumbMove (infoPtr, pos, infoPtr->lPos); + } + + return TRUE; +} + + +static BOOL inline +TRACKBAR_KeyUp (TRACKBAR_INFO *infoPtr, INT nVirtKey, DWORD lKeyData) +{ + switch (nVirtKey) { + case VK_LEFT: + case VK_UP: + case VK_RIGHT: + case VK_DOWN: + case VK_NEXT: + case VK_PRIOR: + case VK_HOME: + case VK_END: + notify_with_scroll (infoPtr, TB_ENDTRACK); + } + return TRUE; +} + + +static LRESULT WINAPI +TRACKBAR_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + TRACKBAR_INFO *infoPtr = (TRACKBAR_INFO *)GetWindowLongPtrW (hwnd, 0); + + TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hwnd, uMsg, wParam, lParam); + + if (!infoPtr && (uMsg != WM_CREATE)) + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + + switch (uMsg) + { + case TBM_CLEARSEL: + return TRACKBAR_ClearSel (infoPtr, (BOOL)wParam); + + case TBM_CLEARTICS: + return TRACKBAR_ClearTics (infoPtr, (BOOL)wParam); + + case TBM_GETBUDDY: + return (LRESULT)(wParam ? infoPtr->hwndBuddyLA : infoPtr->hwndBuddyRB); + + case TBM_GETCHANNELRECT: + return TRACKBAR_GetChannelRect (infoPtr, (LPRECT)lParam); + + case TBM_GETLINESIZE: + return infoPtr->lLineSize; + + case TBM_GETNUMTICS: + return TRACKBAR_GetNumTics (infoPtr); + + case TBM_GETPAGESIZE: + return infoPtr->lPageSize; + + case TBM_GETPOS: + return infoPtr->lPos; + + case TBM_GETPTICS: + return (LRESULT)infoPtr->tics; + + case TBM_GETRANGEMAX: + return infoPtr->lRangeMax; + + case TBM_GETRANGEMIN: + return infoPtr->lRangeMin; + + case TBM_GETSELEND: + return infoPtr->lSelMax; + + case TBM_GETSELSTART: + return infoPtr->lSelMin; + + case TBM_GETTHUMBLENGTH: + return infoPtr->uThumbLen; + + case TBM_GETTHUMBRECT: + return CopyRect((LPRECT)lParam, &infoPtr->rcThumb); + + case TBM_GETTIC: + return TRACKBAR_GetTic (infoPtr, (INT)wParam); + + case TBM_GETTICPOS: + return TRACKBAR_GetTicPos (infoPtr, (INT)wParam); + + case TBM_GETTOOLTIPS: + return (LRESULT)infoPtr->hwndToolTip; + + case TBM_GETUNICODEFORMAT: + return infoPtr->bUnicode; + + case TBM_SETBUDDY: + return (LRESULT) TRACKBAR_SetBuddy(infoPtr, (BOOL)wParam, (HWND)lParam); + + case TBM_SETLINESIZE: + return TRACKBAR_SetLineSize (infoPtr, (LONG)lParam); + + case TBM_SETPAGESIZE: + return TRACKBAR_SetPageSize (infoPtr, (LONG)lParam); + + case TBM_SETPOS: + return TRACKBAR_SetPos (infoPtr, (BOOL)wParam, (LONG)lParam); + + case TBM_SETRANGE: + return TRACKBAR_SetRange (infoPtr, (BOOL)wParam, (LONG)lParam); + + case TBM_SETRANGEMAX: + return TRACKBAR_SetRangeMax (infoPtr, (BOOL)wParam, (LONG)lParam); + + case TBM_SETRANGEMIN: + return TRACKBAR_SetRangeMin (infoPtr, (BOOL)wParam, (LONG)lParam); + + case TBM_SETSEL: + return TRACKBAR_SetSel (infoPtr, (BOOL)wParam, (LONG)lParam); + + case TBM_SETSELEND: + return TRACKBAR_SetSelEnd (infoPtr, (BOOL)wParam, (LONG)lParam); + + case TBM_SETSELSTART: + return TRACKBAR_SetSelStart (infoPtr, (BOOL)wParam, (LONG)lParam); + + case TBM_SETTHUMBLENGTH: + return TRACKBAR_SetThumbLength (infoPtr, (UINT)wParam); + + case TBM_SETTIC: + return TRACKBAR_SetTic (infoPtr, (LONG)lParam); + + case TBM_SETTICFREQ: + return TRACKBAR_SetTicFreq (infoPtr, (WORD)wParam); + + case TBM_SETTIPSIDE: + return TRACKBAR_SetTipSide (infoPtr, (INT)wParam); + + case TBM_SETTOOLTIPS: + return TRACKBAR_SetToolTips (infoPtr, (HWND)wParam); + + case TBM_SETUNICODEFORMAT: + return TRACKBAR_SetUnicodeFormat (infoPtr, (BOOL)wParam); + + + case WM_CAPTURECHANGED: + return TRACKBAR_CaptureChanged (infoPtr); + + case WM_CREATE: + return TRACKBAR_Create (hwnd, (LPCREATESTRUCTW)lParam); + + case WM_DESTROY: + return TRACKBAR_Destroy (infoPtr); + +/* case WM_ENABLE: */ + + case WM_ERASEBKGND: + return 0; + + case WM_GETDLGCODE: + return DLGC_WANTARROWS; + + case WM_KEYDOWN: + return TRACKBAR_KeyDown (infoPtr, (INT)wParam, (DWORD)lParam); + + case WM_KEYUP: + return TRACKBAR_KeyUp (infoPtr, (INT)wParam, (DWORD)lParam); + + case WM_KILLFOCUS: + return TRACKBAR_KillFocus (infoPtr, (HWND)wParam); + + case WM_LBUTTONDOWN: + return TRACKBAR_LButtonDown (infoPtr, wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); + + case WM_LBUTTONUP: + return TRACKBAR_LButtonUp (infoPtr, wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); + + case WM_MOUSEMOVE: + return TRACKBAR_MouseMove (infoPtr, wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); + + case WM_PAINT: + return TRACKBAR_Paint (infoPtr, (HDC)wParam); + + case WM_SETFOCUS: + return TRACKBAR_SetFocus (infoPtr, (HWND)wParam); + + case WM_SIZE: + return TRACKBAR_Size (infoPtr, wParam, LOWORD(lParam), HIWORD(lParam)); + + case WM_TIMER: + return TRACKBAR_Timer (infoPtr, (INT)wParam, (TIMERPROC *)lParam); + + case WM_WININICHANGE: + return TRACKBAR_InitializeThumb (infoPtr); + + default: + if ((uMsg >= WM_USER) && (uMsg < WM_APP)) + ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam); + return DefWindowProcW (hwnd, uMsg, wParam, lParam); + } +} + + +void TRACKBAR_Register (void) +{ + WNDCLASSW wndClass; + + ZeroMemory (&wndClass, sizeof(WNDCLASSW)); + wndClass.style = CS_GLOBALCLASS; + wndClass.lpfnWndProc = TRACKBAR_WindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(TRACKBAR_INFO *); + wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); + wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); + wndClass.lpszClassName = TRACKBAR_CLASSW; + + RegisterClassW (&wndClass); +} + + +void TRACKBAR_Unregister (void) +{ + UnregisterClassW (TRACKBAR_CLASSW, NULL); +} diff --git a/reactos/lib/comctl32/treeview.c b/reactos/lib/comctl32/treeview.c index 7ed73042ecc..1aa8c678d4e 100644 --- a/reactos/lib/comctl32/treeview.c +++ b/reactos/lib/comctl32/treeview.c @@ -1,5740 +1,5740 @@ -/* Treeview control - * - * Copyright 1998 Eric Kohl - * Copyright 1998,1999 Alex Priem - * Copyright 1999 Sylvain St-Germain - * Copyright 2002 CodeWeavers, Aric Stewart - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTES - * - * Note that TREEVIEW_INFO * and HTREEITEM are the same thing. - * - * Note2: All items always! have valid (allocated) pszText field. - * If item's text == LPSTR_TEXTCALLBACKA we allocate buffer - * of size TEXT_CALLBACK_SIZE in DoSetItem. - * We use callbackMask to keep track of fields to be updated. - * - * TODO: - * missing notifications: NM_SETCURSOR, TVN_GETINFOTIP, TVN_KEYDOWN, - * TVN_SETDISPINFO, TVN_SINGLEEXPAND - * - * missing styles: TVS_FULLROWSELECT, TVS_INFOTIP, TVS_RTLREADING, - * - * missing item styles: TVIS_CUT, TVIS_EXPANDPARTIAL - * - * Make the insertion mark look right. - * Scroll (instead of repaint) as much as possible. - */ - -#include "config.h" -#include "wine/port.h" - -#include -#include -#include -#include -#include -#include - -#define NONAMELESSUNION -#define NONAMELESSSTRUCT -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "comctl32.h" -#include "wine/unicode.h" -#include "wine/debug.h" - -/* internal structures */ - -typedef struct _TREEITEM /* HTREEITEM is a _TREEINFO *. */ -{ - UINT callbackMask; - UINT state; - UINT stateMask; - LPWSTR pszText; - int cchTextMax; - int iImage; - int iSelectedImage; - int cChildren; - LPARAM lParam; - int iIntegral; /* item height multiplier (1 is normal) */ - int iLevel; /* indentation level:0=root level */ - HTREEITEM parent; /* handle to parent or 0 if at root */ - HTREEITEM firstChild; /* handle to first child or 0 if no child */ - HTREEITEM lastChild; - HTREEITEM prevSibling; /* handle to prev item in list, 0 if first */ - HTREEITEM nextSibling; /* handle to next item in list, 0 if last */ - RECT rect; - LONG linesOffset; - LONG stateOffset; - LONG imageOffset; - LONG textOffset; - LONG textWidth; /* horizontal text extent for pszText */ - LONG visibleOrder; /* visible ordering, 0 is first visible item */ -} TREEVIEW_ITEM; - - -typedef struct tagTREEVIEW_INFO -{ - HWND hwnd; - HWND hwndNotify; /* Owner window to send notifications to */ - DWORD dwStyle; - HTREEITEM root; - UINT uInternalStatus; - INT Timer; - UINT uNumItems; /* number of valid TREEVIEW_ITEMs */ - INT cdmode; /* last custom draw setting */ - UINT uScrollTime; /* max. time for scrolling in milliseconds */ - BOOL bRedraw; /* if FALSE we validate but don't redraw in TREEVIEW_Paint() */ - - UINT uItemHeight; /* item height */ - BOOL bHeightSet; - - LONG clientWidth; /* width of control window */ - LONG clientHeight; /* height of control window */ - - LONG treeWidth; /* width of visible tree items */ - LONG treeHeight; /* height of visible tree items */ - - UINT uIndent; /* indentation in pixels */ - HTREEITEM selectedItem; /* handle to selected item or 0 if none */ - HTREEITEM hotItem; /* handle currently under cursor, 0 if none */ - HTREEITEM focusedItem; /* item that was under the cursor when WM_LBUTTONDOWN was received */ - - HTREEITEM firstVisible; /* handle to first visible item */ - LONG maxVisibleOrder; - HTREEITEM dropItem; /* handle to item selected by drag cursor */ - HTREEITEM insertMarkItem; /* item after which insertion mark is placed */ - BOOL insertBeforeorAfter; /* flag used by TVM_SETINSERTMARK */ - HIMAGELIST dragList; /* Bitmap of dragged item */ - LONG scrollX; - COLORREF clrBk; - COLORREF clrText; - COLORREF clrLine; - COLORREF clrInsertMark; - HFONT hFont; - HFONT hDefaultFont; - HFONT hBoldFont; - HFONT hUnderlineFont; - HCURSOR hcurHand; - HWND hwndToolTip; - - HWND hwndEdit; - WNDPROC wpEditOrig; /* orig window proc for subclassing edit */ - BOOL bIgnoreEditKillFocus; - BOOL bLabelChanged; - - BOOL bNtfUnicode; /* TRUE if should send NOTIFY with W */ - HIMAGELIST himlNormal; - int normalImageHeight; - int normalImageWidth; - HIMAGELIST himlState; - int stateImageHeight; - int stateImageWidth; - HDPA items; - - DWORD lastKeyPressTimestamp; /* Added */ - WPARAM charCode; /* Added */ - INT nSearchParamLength; /* Added */ - WCHAR szSearchParam[ MAX_PATH ]; /* Added */ -} TREEVIEW_INFO; - - -/******** Defines that TREEVIEW_ProcessLetterKeys uses ****************/ -#define KEY_DELAY 450 - -/* bitflags for infoPtr->uInternalStatus */ - -#define TV_HSCROLL 0x01 /* treeview too large to fit in window */ -#define TV_VSCROLL 0x02 /* (horizontal/vertical) */ -#define TV_LDRAG 0x04 /* Lbutton pushed to start drag */ -#define TV_LDRAGGING 0x08 /* Lbutton pushed, mouse moved. */ -#define TV_RDRAG 0x10 /* dito Rbutton */ -#define TV_RDRAGGING 0x20 - -/* bitflags for infoPtr->timer */ - -#define TV_EDIT_TIMER 2 -#define TV_EDIT_TIMER_SET 2 - - -VOID TREEVIEW_Register (VOID); -VOID TREEVIEW_Unregister (VOID); - - -WINE_DEFAULT_DEBUG_CHANNEL(treeview); - - -#define TEXT_CALLBACK_SIZE 260 - -#define TREEVIEW_LEFT_MARGIN 8 - -#define MINIMUM_INDENT 19 - -#define CALLBACK_MASK_ALL (TVIF_TEXT|TVIF_CHILDREN|TVIF_IMAGE|TVIF_SELECTEDIMAGE) - -#define STATEIMAGEINDEX(x) (((x) >> 12) & 0x0f) -#define OVERLAYIMAGEINDEX(x) (((x) >> 8) & 0x0f) -#define ISVISIBLE(x) ((x)->visibleOrder >= 0) - - -typedef VOID (*TREEVIEW_ItemEnumFunc)(TREEVIEW_INFO *, TREEVIEW_ITEM *,LPVOID); - - -static VOID TREEVIEW_Invalidate(TREEVIEW_INFO *, TREEVIEW_ITEM *); - -static LRESULT TREEVIEW_DoSelectItem(TREEVIEW_INFO *, INT, HTREEITEM, INT); -static VOID TREEVIEW_SetFirstVisible(TREEVIEW_INFO *, TREEVIEW_ITEM *, BOOL); -static LRESULT TREEVIEW_EnsureVisible(TREEVIEW_INFO *, HTREEITEM, BOOL); -static LRESULT TREEVIEW_RButtonUp(TREEVIEW_INFO *, LPPOINT); -static LRESULT TREEVIEW_EndEditLabelNow(TREEVIEW_INFO *infoPtr, BOOL bCancel); -static VOID TREEVIEW_UpdateScrollBars(TREEVIEW_INFO *infoPtr); -static LRESULT TREEVIEW_HScroll(TREEVIEW_INFO *, WPARAM); -static INT TREEVIEW_NotifyFormat (TREEVIEW_INFO *infoPtr, HWND wParam, UINT lParam); - - -/* Random Utilities *****************************************************/ - -#ifndef NDEBUG -static inline void -TREEVIEW_VerifyTree(TREEVIEW_INFO *infoPtr) -{ - (void)infoPtr; -} -#else -/* The definition is at the end of the file. */ -static void TREEVIEW_VerifyTree(TREEVIEW_INFO *infoPtr); -#endif - -/* Returns the treeview private data if hwnd is a treeview. - * Otherwise returns an undefined value. */ -static TREEVIEW_INFO * -TREEVIEW_GetInfoPtr(HWND hwnd) -{ - return (TREEVIEW_INFO *)GetWindowLongPtrW(hwnd, 0); -} - -/* Don't call this. Nothing wants an item index. */ -static inline int -TREEVIEW_GetItemIndex(TREEVIEW_INFO *infoPtr, HTREEITEM handle) -{ - assert(infoPtr != NULL); - - return DPA_GetPtrIndex(infoPtr->items, handle); -} - -/* Checks if item has changed and needs to be redrawn */ -static inline BOOL item_changed (TREEVIEW_ITEM *tiOld, TREEVIEW_ITEM *tiNew, LPTVITEMEXW tvChange) -{ - /* Number of children has changed */ - if ((tvChange->mask & TVIF_CHILDREN) && (tiOld->cChildren != tiNew->cChildren)) - return TRUE; - - /* Image has changed and it's not a callback */ - if ((tvChange->mask & TVIF_IMAGE) && (tiOld->iImage != tiNew->iImage) && - tiNew->iImage != I_IMAGECALLBACK) - return TRUE; - - /* Selected image has changed and it's not a callback */ - if ((tvChange->mask & TVIF_SELECTEDIMAGE) && (tiOld->iSelectedImage != tiNew->iSelectedImage) && - tiNew->iSelectedImage != I_IMAGECALLBACK) - return TRUE; - - /* Text has changed and it's not a callback */ - if ((tvChange->mask & TVIF_TEXT) && (tiOld->pszText != tiNew->pszText) && - tiNew->pszText != LPSTR_TEXTCALLBACKW) - return TRUE; - - /* Indent has changed */ - if ((tvChange->mask & TVIF_INTEGRAL) && (tiOld->iIntegral != tiNew->iIntegral)) - return TRUE; - - /* Item state has changed */ - if ((tvChange->mask & TVIF_STATE) && ((tiOld->state ^ tiNew->state) & tvChange->stateMask )) - return TRUE; - - return FALSE; -} - -/*************************************************************************** - * This method checks that handle is an item for this tree. - */ -static BOOL -TREEVIEW_ValidItem(TREEVIEW_INFO *infoPtr, HTREEITEM handle) -{ - if (TREEVIEW_GetItemIndex(infoPtr, handle) == -1) - { - TRACE("invalid item %p\n", handle); - return FALSE; - } - else - return TRUE; -} - -static HFONT -TREEVIEW_CreateBoldFont(HFONT hOrigFont) -{ - LOGFONTW font; - - GetObjectW(hOrigFont, sizeof(font), &font); - font.lfWeight = FW_BOLD; - return CreateFontIndirectW(&font); -} - -static HFONT -TREEVIEW_CreateUnderlineFont(HFONT hOrigFont) -{ - LOGFONTW font; - - GetObjectW(hOrigFont, sizeof(font), &font); - font.lfUnderline = TRUE; - return CreateFontIndirectW(&font); -} - -static inline HFONT -TREEVIEW_FontForItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) -{ - if ((infoPtr->dwStyle & TVS_TRACKSELECT) && (item == infoPtr->hotItem)) - return infoPtr->hUnderlineFont; - if (item->state & TVIS_BOLD) - return infoPtr->hBoldFont; - return infoPtr->hFont; -} - -/* for trace/debugging purposes only */ -static const char * -TREEVIEW_ItemName(TREEVIEW_ITEM *item) -{ - if (item == NULL) return ""; - if (item->pszText == LPSTR_TEXTCALLBACKW) return ""; - if (item->pszText == NULL) return ""; - return debugstr_w(item->pszText); -} - -/* An item is not a child of itself. */ -static BOOL -TREEVIEW_IsChildOf(TREEVIEW_ITEM *parent, TREEVIEW_ITEM *child) -{ - do - { - child = child->parent; - if (child == parent) return TRUE; - } while (child != NULL); - - return FALSE; -} - - -/* Tree Traversal *******************************************************/ - -/*************************************************************************** - * This method returns the last expanded sibling or child child item - * of a tree node - */ -static TREEVIEW_ITEM * -TREEVIEW_GetLastListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem) -{ - if (!wineItem) - return NULL; - - while (wineItem->lastChild) - { - if (wineItem->state & TVIS_EXPANDED) - wineItem = wineItem->lastChild; - else - break; - } - - if (wineItem == infoPtr->root) - return NULL; - - return wineItem; -} - -/*************************************************************************** - * This method returns the previous non-hidden item in the list not - * considering the tree hierarchy. - */ -static TREEVIEW_ITEM * -TREEVIEW_GetPrevListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *tvItem) -{ - if (tvItem->prevSibling) - { - /* This item has a prevSibling, get the last item in the sibling's tree. */ - TREEVIEW_ITEM *upItem = tvItem->prevSibling; - - if ((upItem->state & TVIS_EXPANDED) && upItem->lastChild != NULL) - return TREEVIEW_GetLastListItem(infoPtr, upItem->lastChild); - else - return upItem; - } - else - { - /* this item does not have a prevSibling, get the parent */ - return (tvItem->parent != infoPtr->root) ? tvItem->parent : NULL; - } -} - - -/*************************************************************************** - * This method returns the next physical item in the treeview not - * considering the tree hierarchy. - */ -static TREEVIEW_ITEM * -TREEVIEW_GetNextListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *tvItem) -{ - assert(tvItem != NULL); - - /* - * If this item has children and is expanded, return the first child - */ - if ((tvItem->state & TVIS_EXPANDED) && tvItem->firstChild != NULL) - { - return tvItem->firstChild; - } - - - /* - * try to get the sibling - */ - if (tvItem->nextSibling) - return tvItem->nextSibling; - - /* - * Otherwise, get the parent's sibling. - */ - while (tvItem->parent) - { - tvItem = tvItem->parent; - - if (tvItem->nextSibling) - return tvItem->nextSibling; - } - - return NULL; -} - -/*************************************************************************** - * This method returns the nth item starting at the given item. It returns - * the last item (or first) we we run out of items. - * - * Will scroll backward if count is <0. - * forward if count is >0. - */ -static TREEVIEW_ITEM * -TREEVIEW_GetListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, - LONG count) -{ - TREEVIEW_ITEM *(*next_item)(TREEVIEW_INFO *, TREEVIEW_ITEM *); - TREEVIEW_ITEM *previousItem; - - assert(wineItem != NULL); - - if (count > 0) - { - next_item = TREEVIEW_GetNextListItem; - } - else if (count < 0) - { - count = -count; - next_item = TREEVIEW_GetPrevListItem; - } - else - return wineItem; - - do - { - previousItem = wineItem; - wineItem = next_item(infoPtr, wineItem); - - } while (--count && wineItem != NULL); - - - return wineItem ? wineItem : previousItem; -} - -/* Notifications ************************************************************/ - -static INT get_notifycode(TREEVIEW_INFO *infoPtr, INT code) -{ - if (!infoPtr->bNtfUnicode) { - switch (code) { - case TVN_SELCHANGINGW: return TVN_SELCHANGINGA; - case TVN_SELCHANGEDW: return TVN_SELCHANGEDA; - case TVN_GETDISPINFOW: return TVN_GETDISPINFOA; - case TVN_SETDISPINFOW: return TVN_SETDISPINFOA; - case TVN_ITEMEXPANDINGW: return TVN_ITEMEXPANDINGA; - case TVN_ITEMEXPANDEDW: return TVN_ITEMEXPANDEDA; - case TVN_BEGINDRAGW: return TVN_BEGINDRAGA; - case TVN_BEGINRDRAGW: return TVN_BEGINRDRAGA; - case TVN_DELETEITEMW: return TVN_DELETEITEMA; - case TVN_BEGINLABELEDITW: return TVN_BEGINLABELEDITA; - case TVN_ENDLABELEDITW: return TVN_ENDLABELEDITA; - case TVN_GETINFOTIPW: return TVN_GETINFOTIPA; - } - } - return code; -} - -static LRESULT -TREEVIEW_SendRealNotify(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - TRACE("wParam=%d, lParam=%ld\n", wParam, lParam); - return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, wParam, lParam); -} - -static BOOL -TREEVIEW_SendSimpleNotify(TREEVIEW_INFO *infoPtr, UINT code) -{ - NMHDR nmhdr; - HWND hwnd = infoPtr->hwnd; - - TRACE("%d\n", code); - nmhdr.hwndFrom = hwnd; - nmhdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID); - nmhdr.code = get_notifycode(infoPtr, code); - - return (BOOL)TREEVIEW_SendRealNotify(infoPtr, - (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr); -} - -static VOID -TREEVIEW_TVItemFromItem(TREEVIEW_INFO *infoPtr, UINT mask, TVITEMW *tvItem, TREEVIEW_ITEM *item) -{ - tvItem->mask = mask; - tvItem->hItem = item; - tvItem->state = item->state; - tvItem->stateMask = 0; - tvItem->iImage = item->iImage; - tvItem->iSelectedImage = item->iSelectedImage; - tvItem->cChildren = item->cChildren; - tvItem->lParam = item->lParam; - - if(mask & TVIF_TEXT) - { - if (!infoPtr->bNtfUnicode) - { - tvItem->cchTextMax = WideCharToMultiByte( CP_ACP, 0, item->pszText, -1, NULL, 0, NULL, NULL ); - tvItem->pszText = Alloc (tvItem->cchTextMax); - WideCharToMultiByte( CP_ACP, 0, item->pszText, -1, (LPSTR)tvItem->pszText, tvItem->cchTextMax, 0, 0 ); - } - else - { - tvItem->cchTextMax = item->cchTextMax; - tvItem->pszText = item->pszText; - } - } - else - { - tvItem->cchTextMax = 0; - tvItem->pszText = NULL; - } -} - -static BOOL -TREEVIEW_SendTreeviewNotify(TREEVIEW_INFO *infoPtr, UINT code, UINT action, - UINT mask, HTREEITEM oldItem, HTREEITEM newItem) -{ - HWND hwnd = infoPtr->hwnd; - NMTREEVIEWW nmhdr; - BOOL ret; - - TRACE("code:%d action:%x olditem:%p newitem:%p\n", - code, action, oldItem, newItem); - - ZeroMemory(&nmhdr, sizeof(NMTREEVIEWA)); - - nmhdr.hdr.hwndFrom = hwnd; - nmhdr.hdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID); - nmhdr.hdr.code = get_notifycode(infoPtr, code); - nmhdr.action = action; - - if (oldItem) - TREEVIEW_TVItemFromItem(infoPtr, mask, &nmhdr.itemOld, oldItem); - - if (newItem) - TREEVIEW_TVItemFromItem(infoPtr, mask, &nmhdr.itemNew, newItem); - - nmhdr.ptDrag.x = 0; - nmhdr.ptDrag.y = 0; - - ret = (BOOL)TREEVIEW_SendRealNotify(infoPtr, - (WPARAM)nmhdr.hdr.idFrom, - (LPARAM)&nmhdr); - if (!infoPtr->bNtfUnicode) - { - Free(nmhdr.itemOld.pszText); - Free(nmhdr.itemNew.pszText); - } - return ret; -} - -static BOOL -TREEVIEW_SendTreeviewDnDNotify(TREEVIEW_INFO *infoPtr, UINT code, - HTREEITEM dragItem, POINT pt) -{ - HWND hwnd = infoPtr->hwnd; - NMTREEVIEWW nmhdr; - - TRACE("code:%d dragitem:%p\n", code, dragItem); - - nmhdr.hdr.hwndFrom = hwnd; - nmhdr.hdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID); - nmhdr.hdr.code = get_notifycode(infoPtr, code); - nmhdr.action = 0; - nmhdr.itemNew.mask = TVIF_STATE | TVIF_PARAM | TVIF_HANDLE; - nmhdr.itemNew.hItem = dragItem; - nmhdr.itemNew.state = dragItem->state; - nmhdr.itemNew.lParam = dragItem->lParam; - - nmhdr.ptDrag.x = pt.x; - nmhdr.ptDrag.y = pt.y; - - return (BOOL)TREEVIEW_SendRealNotify(infoPtr, - (WPARAM)nmhdr.hdr.idFrom, - (LPARAM)&nmhdr); -} - - -static BOOL -TREEVIEW_SendCustomDrawNotify(TREEVIEW_INFO *infoPtr, DWORD dwDrawStage, - HDC hdc, RECT rc) -{ - HWND hwnd = infoPtr->hwnd; - NMTVCUSTOMDRAW nmcdhdr; - LPNMCUSTOMDRAW nmcd; - - TRACE("drawstage:%lx hdc:%p\n", dwDrawStage, hdc); - - nmcd = &nmcdhdr.nmcd; - nmcd->hdr.hwndFrom = hwnd; - nmcd->hdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID); - nmcd->hdr.code = NM_CUSTOMDRAW; - nmcd->dwDrawStage = dwDrawStage; - nmcd->hdc = hdc; - nmcd->rc = rc; - nmcd->dwItemSpec = 0; - nmcd->uItemState = 0; - nmcd->lItemlParam = 0; - nmcdhdr.clrText = infoPtr->clrText; - nmcdhdr.clrTextBk = infoPtr->clrBk; - nmcdhdr.iLevel = 0; - - return (BOOL)TREEVIEW_SendRealNotify(infoPtr, - (WPARAM)nmcd->hdr.idFrom, - (LPARAM)&nmcdhdr); -} - - - -/* FIXME: need to find out when the flags in uItemState need to be set */ - -static BOOL -TREEVIEW_SendCustomDrawItemNotify(TREEVIEW_INFO *infoPtr, HDC hdc, - TREEVIEW_ITEM *wineItem, UINT uItemDrawState, - NMTVCUSTOMDRAW *nmcdhdr) -{ - HWND hwnd = infoPtr->hwnd; - LPNMCUSTOMDRAW nmcd; - DWORD dwDrawStage, dwItemSpec; - UINT uItemState; - INT retval; - - dwDrawStage = CDDS_ITEM | uItemDrawState; - dwItemSpec = (DWORD)wineItem; - uItemState = 0; - if (wineItem->state & TVIS_SELECTED) - uItemState |= CDIS_SELECTED; - if (wineItem == infoPtr->selectedItem) - uItemState |= CDIS_FOCUS; - if (wineItem == infoPtr->hotItem) - uItemState |= CDIS_HOT; - - nmcd = &nmcdhdr->nmcd; - nmcd->hdr.hwndFrom = hwnd; - nmcd->hdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID); - nmcd->hdr.code = NM_CUSTOMDRAW; - nmcd->dwDrawStage = dwDrawStage; - nmcd->hdc = hdc; - nmcd->rc = wineItem->rect; - nmcd->dwItemSpec = dwItemSpec; - nmcd->uItemState = uItemState; - nmcd->lItemlParam = wineItem->lParam; - nmcdhdr->iLevel = wineItem->iLevel; - - TRACE("drawstage:%lx hdc:%p item:%lx, itemstate:%x, lItemlParam:%lx\n", - nmcd->dwDrawStage, nmcd->hdc, nmcd->dwItemSpec, - nmcd->uItemState, nmcd->lItemlParam); - - retval = TREEVIEW_SendRealNotify(infoPtr, - (WPARAM)nmcd->hdr.idFrom, - (LPARAM)nmcdhdr); - - return (BOOL)retval; -} - -static BOOL -TREEVIEW_BeginLabelEditNotify(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *editItem) -{ - HWND hwnd = infoPtr->hwnd; - NMTVDISPINFOW tvdi; - BOOL ret; - - tvdi.hdr.hwndFrom = hwnd; - tvdi.hdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID); - tvdi.hdr.code = get_notifycode(infoPtr, TVN_BEGINLABELEDITW); - - TREEVIEW_TVItemFromItem(infoPtr, TVIF_HANDLE | TVIF_STATE | TVIF_PARAM | TVIF_TEXT, - &tvdi.item, editItem); - - ret = (BOOL)TREEVIEW_SendRealNotify(infoPtr, tvdi.hdr.idFrom, (LPARAM)&tvdi); - - if (!infoPtr->bNtfUnicode) - Free(tvdi.item.pszText); - - return ret; -} - -static void -TREEVIEW_UpdateDispInfo(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, - UINT mask) -{ - NMTVDISPINFOW callback; - HWND hwnd = infoPtr->hwnd; - - TRACE("mask %x callbackMask %x\n", mask, wineItem->callbackMask); - mask &= wineItem->callbackMask; - - if (mask == 0) return; - - callback.hdr.hwndFrom = hwnd; - callback.hdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID); - callback.hdr.code = get_notifycode(infoPtr, TVN_GETDISPINFOW); - - /* 'state' always contains valid value, as well as 'lParam'. - * All other parameters are uninitialized. - */ - callback.item.pszText = wineItem->pszText; - callback.item.cchTextMax = wineItem->cchTextMax; - callback.item.mask = mask; - callback.item.hItem = wineItem; - callback.item.state = wineItem->state; - callback.item.lParam = wineItem->lParam; - - /* If text is changed we need to recalculate textWidth */ - if (mask & TVIF_TEXT) - wineItem->textWidth = 0; - - TREEVIEW_SendRealNotify(infoPtr, - (WPARAM)callback.hdr.idFrom, (LPARAM)&callback); - - /* It may have changed due to a call to SetItem. */ - mask &= wineItem->callbackMask; - - if ((mask & TVIF_TEXT) && callback.item.pszText != wineItem->pszText) - { - /* Instead of copying text into our buffer user specified its own */ - if (!infoPtr->bNtfUnicode) { - LPWSTR newText; - int buflen; - int len = MultiByteToWideChar( CP_ACP, 0, - (LPSTR)callback.item.pszText, -1, - NULL, 0); - buflen = max((len)*sizeof(WCHAR), TEXT_CALLBACK_SIZE); - newText = (LPWSTR)ReAlloc(wineItem->pszText, buflen); - - TRACE("returned str %s, len=%d, buflen=%d\n", - debugstr_a((LPSTR)callback.item.pszText), len, buflen); - - if (newText) - { - wineItem->pszText = newText; - MultiByteToWideChar( CP_ACP, 0, - (LPSTR)callback.item.pszText, -1, - wineItem->pszText, buflen); - wineItem->cchTextMax = buflen; - } - /* If ReAlloc fails we have nothing to do, but keep original text */ - } - else { - int len = max(lstrlenW(callback.item.pszText) + 1, - TEXT_CALLBACK_SIZE); - LPWSTR newText = ReAlloc(wineItem->pszText, len); - - TRACE("returned wstr %s, len=%d\n", - debugstr_w(callback.item.pszText), len); - - if (newText) - { - wineItem->pszText = newText; - strcpyW(wineItem->pszText, callback.item.pszText); - wineItem->cchTextMax = len; - } - /* If ReAlloc fails we have nothing to do, but keep original text */ - } - } - else if (mask & TVIF_TEXT) { - /* User put text into our buffer, that is ok unless A string */ - if (!infoPtr->bNtfUnicode) { - LPWSTR newText; - LPWSTR oldText = NULL; - int buflen; - int len = MultiByteToWideChar( CP_ACP, 0, - (LPSTR)callback.item.pszText, -1, - NULL, 0); - buflen = max((len)*sizeof(WCHAR), TEXT_CALLBACK_SIZE); - newText = (LPWSTR)Alloc(buflen); - - TRACE("same buffer str %s, len=%d, buflen=%d\n", - debugstr_a((LPSTR)callback.item.pszText), len, buflen); - - if (newText) - { - oldText = wineItem->pszText; - wineItem->pszText = newText; - MultiByteToWideChar( CP_ACP, 0, - (LPSTR)callback.item.pszText, -1, - wineItem->pszText, buflen); - wineItem->cchTextMax = buflen; - if (oldText) - Free(oldText); - } - } - } - - if (mask & TVIF_IMAGE) - wineItem->iImage = callback.item.iImage; - - if (mask & TVIF_SELECTEDIMAGE) - wineItem->iSelectedImage = callback.item.iSelectedImage; - - if (mask & TVIF_CHILDREN) - wineItem->cChildren = callback.item.cChildren; - - /* These members are now permanently set. */ - if (callback.item.mask & TVIF_DI_SETITEM) - wineItem->callbackMask &= ~callback.item.mask; -} - -/*************************************************************************** - * This function uses cChildren field to decide whether the item has - * children or not. - * Note: if this returns TRUE, the child items may not actually exist, - * they could be virtual. - * - * Just use wineItem->firstChild to check for physical children. - */ -static BOOL -TREEVIEW_HasChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem) -{ - TREEVIEW_UpdateDispInfo(infoPtr, wineItem, TVIF_CHILDREN); - - return wineItem->cChildren > 0; -} - - -/* Item Position ********************************************************/ - -/* Compute linesOffset, stateOffset, imageOffset, textOffset of an item. */ -static VOID -TREEVIEW_ComputeItemInternalMetrics(TREEVIEW_INFO *infoPtr, - TREEVIEW_ITEM *item) -{ - /* Same effect, different optimisation. */ -#if 0 - BOOL lar = ((infoPtr->dwStyle & TVS_LINESATROOT) - && (infoPtr->dwStyle & (TVS_HASLINES|TVS_HASBUTTONS))); -#else - BOOL lar = ((infoPtr->dwStyle - & (TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS)) - > TVS_LINESATROOT); -#endif - - item->linesOffset = infoPtr->uIndent * (item->iLevel + lar - 1) - - infoPtr->scrollX; - item->stateOffset = item->linesOffset + infoPtr->uIndent; - item->imageOffset = item->stateOffset - + (STATEIMAGEINDEX(item->state) ? infoPtr->stateImageWidth : 0); - item->textOffset = item->imageOffset + infoPtr->normalImageWidth; -} - -static VOID -TREEVIEW_ComputeTextWidth(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item, HDC hDC) -{ - HDC hdc; - HFONT hOldFont=0; - SIZE sz; - - /* DRAW's OM docker creates items like this */ - if (item->pszText == NULL) - { - item->textWidth = 0; - return; - } - - if (hDC != 0) - { - hdc = hDC; - } - else - { - hdc = GetDC(infoPtr->hwnd); - hOldFont = SelectObject(hdc, TREEVIEW_FontForItem(infoPtr, item)); - } - - GetTextExtentPoint32W(hdc, item->pszText, strlenW(item->pszText), &sz); - item->textWidth = sz.cx; - - if (hDC == 0) - { - SelectObject(hdc, hOldFont); - ReleaseDC(0, hdc); - } -} - -static VOID -TREEVIEW_ComputeItemRect(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) -{ - item->rect.top = infoPtr->uItemHeight * - (item->visibleOrder - infoPtr->firstVisible->visibleOrder); - - item->rect.bottom = item->rect.top - + infoPtr->uItemHeight * item->iIntegral - 1; - - item->rect.left = 0; - item->rect.right = infoPtr->clientWidth; -} - -/* We know that only items after start need their order updated. */ -static void -TREEVIEW_RecalculateVisibleOrder(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *start) -{ - TREEVIEW_ITEM *item; - int order; - - if (!start) - { - start = infoPtr->root->firstChild; - order = 0; - } - else - order = start->visibleOrder; - - for (item = start; item != NULL; - item = TREEVIEW_GetNextListItem(infoPtr, item)) - { - item->visibleOrder = order; - order += item->iIntegral; - } - - infoPtr->maxVisibleOrder = order; - - for (item = start; item != NULL; - item = TREEVIEW_GetNextListItem(infoPtr, item)) - { - TREEVIEW_ComputeItemRect(infoPtr, item); - } -} - - -/* Update metrics of all items in selected subtree. - * root must be expanded - */ -static VOID -TREEVIEW_UpdateSubTree(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *root) -{ - TREEVIEW_ITEM *sibling; - HDC hdc; - HFONT hOldFont; - - if (!root->firstChild || !(root->state & TVIS_EXPANDED)) - return; - - root->state &= ~TVIS_EXPANDED; - sibling = TREEVIEW_GetNextListItem(infoPtr, root); - root->state |= TVIS_EXPANDED; - - hdc = GetDC(infoPtr->hwnd); - hOldFont = SelectObject(hdc, infoPtr->hFont); - - for (; root != sibling; - root = TREEVIEW_GetNextListItem(infoPtr, root)) - { - TREEVIEW_ComputeItemInternalMetrics(infoPtr, root); - - if (root->callbackMask & TVIF_TEXT) - TREEVIEW_UpdateDispInfo(infoPtr, root, TVIF_TEXT); - - if (root->textWidth == 0) - { - SelectObject(hdc, TREEVIEW_FontForItem(infoPtr, root)); - TREEVIEW_ComputeTextWidth(infoPtr, root, hdc); - } - } - - SelectObject(hdc, hOldFont); - ReleaseDC(infoPtr->hwnd, hdc); -} - -/* Item Allocation **********************************************************/ - -static TREEVIEW_ITEM * -TREEVIEW_AllocateItem(TREEVIEW_INFO *infoPtr) -{ - TREEVIEW_ITEM *newItem = Alloc(sizeof(TREEVIEW_ITEM)); - - if (!newItem) - return NULL; - - newItem->iImage = -1; - newItem->iSelectedImage = -1; - - if (DPA_InsertPtr(infoPtr->items, INT_MAX, newItem) == -1) - { - Free(newItem); - return NULL; - } - - return newItem; -} - -/* Exact opposite of TREEVIEW_AllocateItem. In particular, it does not - * free item->pszText. */ -static void -TREEVIEW_FreeItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) -{ - DPA_DeletePtr(infoPtr->items, DPA_GetPtrIndex(infoPtr->items, item)); - Free(item); - if (infoPtr->selectedItem == item) - infoPtr->selectedItem = NULL; - if (infoPtr->hotItem == item) - infoPtr->hotItem = NULL; - if (infoPtr->focusedItem == item) - infoPtr->focusedItem = NULL; - if (infoPtr->firstVisible == item) - infoPtr->firstVisible = NULL; - if (infoPtr->dropItem == item) - infoPtr->dropItem = NULL; - if (infoPtr->insertMarkItem == item) - infoPtr->insertMarkItem = NULL; -} - - -/* Item Insertion *******************************************************/ - -/*************************************************************************** - * This method inserts newItem before sibling as a child of parent. - * sibling can be NULL, but only if parent has no children. - */ -static void -TREEVIEW_InsertBefore(TREEVIEW_ITEM *newItem, TREEVIEW_ITEM *sibling, - TREEVIEW_ITEM *parent) -{ - assert(newItem != NULL); - assert(parent != NULL); - - if (sibling != NULL) - { - assert(sibling->parent == parent); - - if (sibling->prevSibling != NULL) - sibling->prevSibling->nextSibling = newItem; - - newItem->prevSibling = sibling->prevSibling; - sibling->prevSibling = newItem; - } - else - newItem->prevSibling = NULL; - - newItem->nextSibling = sibling; - - if (parent->firstChild == sibling) - parent->firstChild = newItem; - - if (parent->lastChild == NULL) - parent->lastChild = newItem; -} - -/*************************************************************************** - * This method inserts newItem after sibling as a child of parent. - * sibling can be NULL, but only if parent has no children. - */ -static void -TREEVIEW_InsertAfter(TREEVIEW_ITEM *newItem, TREEVIEW_ITEM *sibling, - TREEVIEW_ITEM *parent) -{ - assert(newItem != NULL); - assert(parent != NULL); - - if (sibling != NULL) - { - assert(sibling->parent == parent); - - if (sibling->nextSibling != NULL) - sibling->nextSibling->prevSibling = newItem; - - newItem->nextSibling = sibling->nextSibling; - sibling->nextSibling = newItem; - } - else - newItem->nextSibling = NULL; - - newItem->prevSibling = sibling; - - if (parent->lastChild == sibling) - parent->lastChild = newItem; - - if (parent->firstChild == NULL) - parent->firstChild = newItem; -} - -static BOOL -TREEVIEW_DoSetItemT(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, - const TVITEMEXW *tvItem, BOOL isW) -{ - UINT callbackClear = 0; - UINT callbackSet = 0; - - TRACE("item %p\n", wineItem); - /* Do this first in case it fails. */ - if (tvItem->mask & TVIF_TEXT) - { - wineItem->textWidth = 0; /* force width recalculation */ - if (tvItem->pszText != LPSTR_TEXTCALLBACKW) /* covers != TEXTCALLBACKA too */ - { - int len; - LPWSTR newText; - if (isW) - len = lstrlenW(tvItem->pszText) + 1; - else - len = MultiByteToWideChar(CP_ACP, 0, (LPSTR)tvItem->pszText, -1, NULL, 0); - - newText = ReAlloc(wineItem->pszText, len * sizeof(WCHAR)); - - if (newText == NULL) return FALSE; - - callbackClear |= TVIF_TEXT; - - wineItem->pszText = newText; - wineItem->cchTextMax = len; - if (isW) - lstrcpynW(wineItem->pszText, tvItem->pszText, len); - else - MultiByteToWideChar(CP_ACP, 0, (LPSTR)tvItem->pszText, -1, - wineItem->pszText, len); - - TRACE("setting text %s, item %p\n", debugstr_w(wineItem->pszText), wineItem); - } - else - { - callbackSet |= TVIF_TEXT; - - wineItem->pszText = ReAlloc(wineItem->pszText, - TEXT_CALLBACK_SIZE * sizeof(WCHAR)); - wineItem->cchTextMax = TEXT_CALLBACK_SIZE; - TRACE("setting callback, item %p\n", wineItem); - } - } - - if (tvItem->mask & TVIF_CHILDREN) - { - wineItem->cChildren = tvItem->cChildren; - - if (wineItem->cChildren == I_CHILDRENCALLBACK) - callbackSet |= TVIF_CHILDREN; - else - callbackClear |= TVIF_CHILDREN; - } - - if (tvItem->mask & TVIF_IMAGE) - { - wineItem->iImage = tvItem->iImage; - - if (wineItem->iImage == I_IMAGECALLBACK) - callbackSet |= TVIF_IMAGE; - else - callbackClear |= TVIF_IMAGE; - } - - if (tvItem->mask & TVIF_SELECTEDIMAGE) - { - wineItem->iSelectedImage = tvItem->iSelectedImage; - - if (wineItem->iSelectedImage == I_IMAGECALLBACK) - callbackSet |= TVIF_SELECTEDIMAGE; - else - callbackClear |= TVIF_SELECTEDIMAGE; - } - - if (tvItem->mask & TVIF_PARAM) - wineItem->lParam = tvItem->lParam; - - /* If the application sets TVIF_INTEGRAL without - * supplying a TVITEMEX structure, it's toast. */ - if (tvItem->mask & TVIF_INTEGRAL) - wineItem->iIntegral = tvItem->iIntegral; - - if (tvItem->mask & TVIF_STATE) - { - TRACE("prevstate,state,mask:%x,%x,%x\n", wineItem->state, tvItem->state, - tvItem->stateMask); - wineItem->state &= ~tvItem->stateMask; - wineItem->state |= (tvItem->state & tvItem->stateMask); - } - - wineItem->callbackMask |= callbackSet; - wineItem->callbackMask &= ~callbackClear; - - return TRUE; -} - -/* Note that the new item is pre-zeroed. */ -static LRESULT -TREEVIEW_InsertItemT(TREEVIEW_INFO *infoPtr, const TVINSERTSTRUCTW *ptdi, BOOL isW) -{ - const TVITEMEXW *tvItem = &ptdi->u.itemex; - HTREEITEM insertAfter; - TREEVIEW_ITEM *newItem, *parentItem; - BOOL bTextUpdated = FALSE; - - if (ptdi->hParent == TVI_ROOT || ptdi->hParent == 0) - { - parentItem = infoPtr->root; - } - else - { - parentItem = ptdi->hParent; - - if (!TREEVIEW_ValidItem(infoPtr, parentItem)) - { - WARN("invalid parent %p\n", parentItem); - return (LRESULT)(HTREEITEM)NULL; - } - } - - insertAfter = ptdi->hInsertAfter; - - /* Validate this now for convenience. */ - switch ((DWORD)insertAfter) - { - case (DWORD)TVI_FIRST: - case (DWORD)TVI_LAST: - case (DWORD)TVI_SORT: - break; - - default: - if (!TREEVIEW_ValidItem(infoPtr, insertAfter) || - insertAfter->parent != parentItem) - { - WARN("invalid insert after %p\n", insertAfter); - insertAfter = TVI_LAST; - } - } - - TRACE("parent %p position %p: %s\n", parentItem, insertAfter, - (tvItem->mask & TVIF_TEXT) - ? ((tvItem->pszText == LPSTR_TEXTCALLBACKW) ? "" - : (isW ? debugstr_w(tvItem->pszText) : debugstr_a((LPSTR)tvItem->pszText))) - : ""); - - newItem = TREEVIEW_AllocateItem(infoPtr); - if (newItem == NULL) - return (LRESULT)(HTREEITEM)NULL; - - newItem->parent = parentItem; - newItem->iIntegral = 1; - - if (!TREEVIEW_DoSetItemT(infoPtr, newItem, tvItem, isW)) - return (LRESULT)(HTREEITEM)NULL; - - /* After this point, nothing can fail. (Except for TVI_SORT.) */ - - infoPtr->uNumItems++; - - switch ((DWORD)insertAfter) - { - case (DWORD)TVI_FIRST: - { - TREEVIEW_ITEM *originalFirst = parentItem->firstChild; - TREEVIEW_InsertBefore(newItem, parentItem->firstChild, parentItem); - if (infoPtr->firstVisible == originalFirst) - TREEVIEW_SetFirstVisible(infoPtr, newItem, TRUE); - } - break; - - case (DWORD)TVI_LAST: - TREEVIEW_InsertAfter(newItem, parentItem->lastChild, parentItem); - break; - - /* hInsertAfter names a specific item we want to insert after */ - default: - TREEVIEW_InsertAfter(newItem, insertAfter, insertAfter->parent); - break; - - case (DWORD)TVI_SORT: - { - TREEVIEW_ITEM *aChild; - TREEVIEW_ITEM *previousChild = NULL; - BOOL bItemInserted = FALSE; - - aChild = parentItem->firstChild; - - bTextUpdated = TRUE; - TREEVIEW_UpdateDispInfo(infoPtr, newItem, TVIF_TEXT); - - /* Iterate the parent children to see where we fit in */ - while (aChild != NULL) - { - INT comp; - - TREEVIEW_UpdateDispInfo(infoPtr, aChild, TVIF_TEXT); - comp = lstrcmpW(newItem->pszText, aChild->pszText); - - if (comp < 0) /* we are smaller than the current one */ - { - TREEVIEW_InsertBefore(newItem, aChild, parentItem); - bItemInserted = TRUE; - break; - } - else if (comp > 0) /* we are bigger than the current one */ - { - previousChild = aChild; - - /* This will help us to exit if there is no more sibling */ - aChild = (aChild->nextSibling == 0) - ? NULL - : aChild->nextSibling; - - /* Look at the next item */ - continue; - } - else if (comp == 0) - { - /* - * An item with this name is already existing, therefore, - * we add after the one we found - */ - TREEVIEW_InsertAfter(newItem, aChild, parentItem); - bItemInserted = TRUE; - break; - } - } - - /* - * we reach the end of the child list and the item has not - * yet been inserted, therefore, insert it after the last child. - */ - if ((!bItemInserted) && (aChild == NULL)) - TREEVIEW_InsertAfter(newItem, previousChild, parentItem); - - break; - } - } - - - TRACE("new item %p; parent %p, mask %x\n", newItem, - newItem->parent, tvItem->mask); - - newItem->iLevel = newItem->parent->iLevel + 1; - - if (newItem->parent->cChildren == 0) - newItem->parent->cChildren = 1; - - if (infoPtr->dwStyle & TVS_CHECKBOXES) - { - if (STATEIMAGEINDEX(newItem->state) == 0) - newItem->state |= INDEXTOSTATEIMAGEMASK(1); - } - - if (infoPtr->firstVisible == NULL) - infoPtr->firstVisible = newItem; - - TREEVIEW_VerifyTree(infoPtr); - - if (parentItem == infoPtr->root || - (ISVISIBLE(parentItem) && parentItem->state & TVIS_EXPANDED)) - { - TREEVIEW_ITEM *item; - TREEVIEW_ITEM *prev = TREEVIEW_GetPrevListItem(infoPtr, newItem); - - TREEVIEW_RecalculateVisibleOrder(infoPtr, prev); - TREEVIEW_ComputeItemInternalMetrics(infoPtr, newItem); - - if (!bTextUpdated) - TREEVIEW_UpdateDispInfo(infoPtr, newItem, TVIF_TEXT); - - TREEVIEW_ComputeTextWidth(infoPtr, newItem, 0); - TREEVIEW_UpdateScrollBars(infoPtr); - /* - * if the item was inserted in a visible part of the tree, - * invalidate it, as well as those after it - */ - for (item = newItem; - item != NULL; - item = TREEVIEW_GetNextListItem(infoPtr, item)) - TREEVIEW_Invalidate(infoPtr, item); - } - else - { - newItem->visibleOrder = -1; - - /* refresh treeview if newItem is the first item inserted under parentItem */ - if (ISVISIBLE(parentItem) && newItem->prevSibling == newItem->nextSibling) - { - /* parent got '+' - update it */ - TREEVIEW_Invalidate(infoPtr, parentItem); - } - } - - return (LRESULT)newItem; -} - -/* Item Deletion ************************************************************/ -static void -TREEVIEW_RemoveItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem); - -static void -TREEVIEW_RemoveAllChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *parentItem) -{ - TREEVIEW_ITEM *kill = parentItem->firstChild; - - while (kill != NULL) - { - TREEVIEW_ITEM *next = kill->nextSibling; - - TREEVIEW_RemoveItem(infoPtr, kill); - - kill = next; - } - - assert(parentItem->cChildren <= 0); /* I_CHILDRENCALLBACK or 0 */ - assert(parentItem->firstChild == NULL); - assert(parentItem->lastChild == NULL); -} - -static void -TREEVIEW_UnlinkItem(TREEVIEW_ITEM *item) -{ - TREEVIEW_ITEM *parentItem = item->parent; - - assert(item != NULL); - assert(item->parent != NULL); /* i.e. it must not be the root */ - - if (parentItem->firstChild == item) - parentItem->firstChild = item->nextSibling; - - if (parentItem->lastChild == item) - parentItem->lastChild = item->prevSibling; - - if (parentItem->firstChild == NULL && parentItem->lastChild == NULL - && parentItem->cChildren > 0) - parentItem->cChildren = 0; - - if (item->prevSibling) - item->prevSibling->nextSibling = item->nextSibling; - - if (item->nextSibling) - item->nextSibling->prevSibling = item->prevSibling; -} - -static void -TREEVIEW_RemoveItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem) -{ - TRACE("%p, (%s)\n", wineItem, TREEVIEW_ItemName(wineItem)); - - TREEVIEW_SendTreeviewNotify(infoPtr, TVN_DELETEITEMW, TVC_UNKNOWN, - TVIF_HANDLE | TVIF_PARAM, wineItem, 0); - - if (wineItem->firstChild) - TREEVIEW_RemoveAllChildren(infoPtr, wineItem); - - TREEVIEW_UnlinkItem(wineItem); - - infoPtr->uNumItems--; - - if (wineItem->pszText && wineItem->pszText != LPSTR_TEXTCALLBACKW) - Free(wineItem->pszText); - - TREEVIEW_FreeItem(infoPtr, wineItem); -} - - -/* Empty out the tree. */ -static void -TREEVIEW_RemoveTree(TREEVIEW_INFO *infoPtr) -{ - TREEVIEW_RemoveAllChildren(infoPtr, infoPtr->root); - - assert(infoPtr->uNumItems == 0); /* root isn't counted in uNumItems */ -} - -static LRESULT -TREEVIEW_DeleteItem(TREEVIEW_INFO *infoPtr, HTREEITEM wineItem) -{ - TREEVIEW_ITEM *newSelection = NULL; - TREEVIEW_ITEM *newFirstVisible = NULL; - TREEVIEW_ITEM *parent, *prev = NULL; - BOOL visible = FALSE; - - if (wineItem == TVI_ROOT) - { - TRACE("TVI_ROOT\n"); - parent = infoPtr->root; - newSelection = NULL; - visible = TRUE; - TREEVIEW_RemoveTree(infoPtr); - } - else - { - if (!TREEVIEW_ValidItem(infoPtr, wineItem)) - return FALSE; - - TRACE("%p (%s)\n", wineItem, TREEVIEW_ItemName(wineItem)); - parent = wineItem->parent; - - if (ISVISIBLE(wineItem)) - { - prev = TREEVIEW_GetPrevListItem(infoPtr, wineItem); - visible = TRUE; - } - - if (infoPtr->selectedItem != NULL - && (wineItem == infoPtr->selectedItem - || TREEVIEW_IsChildOf(wineItem, infoPtr->selectedItem))) - { - if (wineItem->nextSibling) - newSelection = wineItem->nextSibling; - else if (wineItem->parent != infoPtr->root) - newSelection = wineItem->parent; - else - newSelection = wineItem->prevSibling; - TRACE("newSelection = %p\n", newSelection); - } - - if (infoPtr->firstVisible == wineItem) - { - if (wineItem->nextSibling) - newFirstVisible = wineItem->nextSibling; - else if (wineItem->prevSibling) - newFirstVisible = wineItem->prevSibling; - else if (wineItem->parent != infoPtr->root) - newFirstVisible = wineItem->parent; - TREEVIEW_SetFirstVisible(infoPtr, NULL, TRUE); - } - else - newFirstVisible = infoPtr->firstVisible; - - TREEVIEW_RemoveItem(infoPtr, wineItem); - } - - /* Don't change if somebody else already has (infoPtr->selectedItem is cleared by FreeItem). */ - if (!infoPtr->selectedItem && newSelection) - { - if (TREEVIEW_ValidItem(infoPtr, newSelection)) - TREEVIEW_DoSelectItem(infoPtr, TVGN_CARET, newSelection, TVC_UNKNOWN); - } - - /* Validate insertMark dropItem. - * hotItem ??? - used for comparison only. - */ - if (!TREEVIEW_ValidItem(infoPtr, infoPtr->insertMarkItem)) - infoPtr->insertMarkItem = 0; - - if (!TREEVIEW_ValidItem(infoPtr, infoPtr->dropItem)) - infoPtr->dropItem = 0; - - if (!TREEVIEW_ValidItem(infoPtr, newFirstVisible)) - newFirstVisible = infoPtr->root->firstChild; - - TREEVIEW_VerifyTree(infoPtr); - - - if (visible) - { - TREEVIEW_SetFirstVisible(infoPtr, newFirstVisible, TRUE); - TREEVIEW_RecalculateVisibleOrder(infoPtr, prev); - TREEVIEW_UpdateScrollBars(infoPtr); - TREEVIEW_Invalidate(infoPtr, NULL); - } - else if (ISVISIBLE(parent) && !TREEVIEW_HasChildren(infoPtr, parent)) - { - /* parent lost '+/-' - update it */ - TREEVIEW_Invalidate(infoPtr, parent); - } - - return TRUE; -} - - -/* Get/Set Messages *********************************************************/ -static LRESULT -TREEVIEW_SetRedraw(TREEVIEW_INFO* infoPtr, WPARAM wParam, LPARAM lParam) -{ - if(wParam) - infoPtr->bRedraw = TRUE; - else - infoPtr->bRedraw = FALSE; - - return 0; -} - -static LRESULT -TREEVIEW_GetIndent(TREEVIEW_INFO *infoPtr) -{ - TRACE("\n"); - return infoPtr->uIndent; -} - -static LRESULT -TREEVIEW_SetIndent(TREEVIEW_INFO *infoPtr, UINT newIndent) -{ - TRACE("\n"); - - if (newIndent < MINIMUM_INDENT) - newIndent = MINIMUM_INDENT; - - if (infoPtr->uIndent != newIndent) - { - infoPtr->uIndent = newIndent; - TREEVIEW_UpdateSubTree(infoPtr, infoPtr->root); - TREEVIEW_UpdateScrollBars(infoPtr); - TREEVIEW_Invalidate(infoPtr, NULL); - } - - return 0; -} - - -static LRESULT -TREEVIEW_GetToolTips(TREEVIEW_INFO *infoPtr) -{ - TRACE("\n"); - return (LRESULT)infoPtr->hwndToolTip; -} - -static LRESULT -TREEVIEW_SetToolTips(TREEVIEW_INFO *infoPtr, HWND hwndTT) -{ - HWND prevToolTip; - - TRACE("\n"); - prevToolTip = infoPtr->hwndToolTip; - infoPtr->hwndToolTip = hwndTT; - - return (LRESULT)prevToolTip; -} - -static LRESULT -TREEVIEW_SetUnicodeFormat(TREEVIEW_INFO *infoPtr, BOOL fUnicode) -{ - BOOL rc = infoPtr->bNtfUnicode; - infoPtr->bNtfUnicode = fUnicode; - return rc; -} - -static LRESULT -TREEVIEW_GetUnicodeFormat(TREEVIEW_INFO *infoPtr) -{ - return infoPtr->bNtfUnicode; -} - -static LRESULT -TREEVIEW_GetScrollTime(TREEVIEW_INFO *infoPtr) -{ - return infoPtr->uScrollTime; -} - -static LRESULT -TREEVIEW_SetScrollTime(TREEVIEW_INFO *infoPtr, UINT uScrollTime) -{ - UINT uOldScrollTime = infoPtr->uScrollTime; - - infoPtr->uScrollTime = min(uScrollTime, 100); - - return uOldScrollTime; -} - - -static LRESULT -TREEVIEW_GetImageList(TREEVIEW_INFO *infoPtr, WPARAM wParam) -{ - TRACE("\n"); - - switch (wParam) - { - case (WPARAM)TVSIL_NORMAL: - return (LRESULT)infoPtr->himlNormal; - - case (WPARAM)TVSIL_STATE: - return (LRESULT)infoPtr->himlState; - - default: - return 0; - } -} - -#define TVHEIGHT_MIN 16 -#define TVHEIGHT_FONT_ADJUST 3 /* 2 for focus border + 1 for margin some apps assume */ - -/* Compute the natural height for items. */ -static UINT -TREEVIEW_NaturalHeight(TREEVIEW_INFO *infoPtr) -{ - TEXTMETRICW tm; - HDC hdc = GetDC(0); - HFONT hOldFont = SelectObject(hdc, infoPtr->hFont); - UINT height; - - /* Height is the maximum of: - * 16 (a hack because our fonts are tiny), and - * The text height + border & margin, and - * The size of the normal image list - */ - GetTextMetricsW(hdc, &tm); - SelectObject(hdc, hOldFont); - ReleaseDC(0, hdc); - - height = TVHEIGHT_MIN; - if (height < tm.tmHeight + tm.tmExternalLeading + TVHEIGHT_FONT_ADJUST) - height = tm.tmHeight + tm.tmExternalLeading + TVHEIGHT_FONT_ADJUST; - if (height < infoPtr->normalImageHeight) - height = infoPtr->normalImageHeight; - return height; -} - -static LRESULT -TREEVIEW_SetImageList(TREEVIEW_INFO *infoPtr, WPARAM wParam, HIMAGELIST himlNew) -{ - HIMAGELIST himlOld = 0; - int oldWidth = infoPtr->normalImageWidth; - int oldHeight = infoPtr->normalImageHeight; - - - TRACE("%x,%p\n", wParam, himlNew); - - switch (wParam) - { - case (WPARAM)TVSIL_NORMAL: - himlOld = infoPtr->himlNormal; - infoPtr->himlNormal = himlNew; - - if (himlNew != NULL) - ImageList_GetIconSize(himlNew, &infoPtr->normalImageWidth, - &infoPtr->normalImageHeight); - else - { - infoPtr->normalImageWidth = 0; - infoPtr->normalImageHeight = 0; - } - - break; - - case (WPARAM)TVSIL_STATE: - himlOld = infoPtr->himlState; - infoPtr->himlState = himlNew; - - if (himlNew != NULL) - ImageList_GetIconSize(himlNew, &infoPtr->stateImageWidth, - &infoPtr->stateImageHeight); - else - { - infoPtr->stateImageWidth = 0; - infoPtr->stateImageHeight = 0; - } - - break; - } - - if (oldWidth != infoPtr->normalImageWidth || - oldHeight != infoPtr->normalImageHeight) - { - BOOL bRecalcVisible = FALSE; - - if (oldHeight != infoPtr->normalImageHeight && - !infoPtr->bHeightSet) - { - infoPtr->uItemHeight = TREEVIEW_NaturalHeight(infoPtr); - bRecalcVisible = TRUE; - } - - if (infoPtr->normalImageWidth > MINIMUM_INDENT && - infoPtr->normalImageWidth != infoPtr->uIndent) - { - infoPtr->uIndent = infoPtr->normalImageWidth; - bRecalcVisible = TRUE; - } - - if (bRecalcVisible) - TREEVIEW_RecalculateVisibleOrder(infoPtr, NULL); - - TREEVIEW_UpdateSubTree(infoPtr, infoPtr->root); - TREEVIEW_UpdateScrollBars(infoPtr); - } - - TREEVIEW_Invalidate(infoPtr, NULL); - - return (LRESULT)himlOld; -} - -static LRESULT -TREEVIEW_SetItemHeight(TREEVIEW_INFO *infoPtr, INT newHeight) -{ - INT prevHeight = infoPtr->uItemHeight; - - TRACE("%d \n", newHeight); - if (newHeight == -1) - { - infoPtr->uItemHeight = TREEVIEW_NaturalHeight(infoPtr); - infoPtr->bHeightSet = FALSE; - } - else - { - infoPtr->uItemHeight = newHeight; - infoPtr->bHeightSet = TRUE; - } - - /* Round down, unless we support odd ("non even") heights. */ - if (!(infoPtr->dwStyle) & TVS_NONEVENHEIGHT) - infoPtr->uItemHeight &= ~1; - - if (infoPtr->uItemHeight != prevHeight) - { - TREEVIEW_RecalculateVisibleOrder(infoPtr, NULL); - TREEVIEW_UpdateScrollBars(infoPtr); - TREEVIEW_Invalidate(infoPtr, NULL); - } - - return prevHeight; -} - -static LRESULT -TREEVIEW_GetItemHeight(TREEVIEW_INFO *infoPtr) -{ - TRACE("\n"); - return infoPtr->uItemHeight; -} - - -static LRESULT -TREEVIEW_GetFont(TREEVIEW_INFO *infoPtr) -{ - TRACE("%p\n", infoPtr->hFont); - return (LRESULT)infoPtr->hFont; -} - - -static INT CALLBACK -TREEVIEW_ResetTextWidth(LPVOID pItem, LPVOID unused) -{ - (void)unused; - - ((TREEVIEW_ITEM *)pItem)->textWidth = 0; - - return 1; -} - -static LRESULT -TREEVIEW_SetFont(TREEVIEW_INFO *infoPtr, HFONT hFont, BOOL bRedraw) -{ - UINT uHeight = infoPtr->uItemHeight; - - TRACE("%p %i\n", hFont, bRedraw); - - infoPtr->hFont = hFont ? hFont : infoPtr->hDefaultFont; - - DeleteObject(infoPtr->hBoldFont); - infoPtr->hBoldFont = TREEVIEW_CreateBoldFont(infoPtr->hFont); - infoPtr->hUnderlineFont = TREEVIEW_CreateUnderlineFont(infoPtr->hFont); - - if (!infoPtr->bHeightSet) - infoPtr->uItemHeight = TREEVIEW_NaturalHeight(infoPtr); - - if (uHeight != infoPtr->uItemHeight) - TREEVIEW_RecalculateVisibleOrder(infoPtr, NULL); - - DPA_EnumCallback(infoPtr->items, TREEVIEW_ResetTextWidth, 0); - - TREEVIEW_UpdateSubTree(infoPtr, infoPtr->root); - TREEVIEW_UpdateScrollBars(infoPtr); - - if (bRedraw) - TREEVIEW_Invalidate(infoPtr, NULL); - - return 0; -} - - -static LRESULT -TREEVIEW_GetLineColor(TREEVIEW_INFO *infoPtr) -{ - TRACE("\n"); - return (LRESULT)infoPtr->clrLine; -} - -static LRESULT -TREEVIEW_SetLineColor(TREEVIEW_INFO *infoPtr, COLORREF color) -{ - COLORREF prevColor = infoPtr->clrLine; - - TRACE("\n"); - infoPtr->clrLine = color; - return (LRESULT)prevColor; -} - - -static LRESULT -TREEVIEW_GetTextColor(TREEVIEW_INFO *infoPtr) -{ - TRACE("\n"); - return (LRESULT)infoPtr->clrText; -} - -static LRESULT -TREEVIEW_SetTextColor(TREEVIEW_INFO *infoPtr, COLORREF color) -{ - COLORREF prevColor = infoPtr->clrText; - - TRACE("\n"); - infoPtr->clrText = color; - - if (infoPtr->clrText != prevColor) - TREEVIEW_Invalidate(infoPtr, NULL); - - return (LRESULT)prevColor; -} - - -static LRESULT -TREEVIEW_GetBkColor(TREEVIEW_INFO *infoPtr) -{ - TRACE("\n"); - return (LRESULT)infoPtr->clrBk; -} - -static LRESULT -TREEVIEW_SetBkColor(TREEVIEW_INFO *infoPtr, COLORREF newColor) -{ - COLORREF prevColor = infoPtr->clrBk; - - TRACE("\n"); - infoPtr->clrBk = newColor; - - if (newColor != prevColor) - TREEVIEW_Invalidate(infoPtr, NULL); - - return (LRESULT)prevColor; -} - - -static LRESULT -TREEVIEW_GetInsertMarkColor(TREEVIEW_INFO *infoPtr) -{ - TRACE("\n"); - return (LRESULT)infoPtr->clrInsertMark; -} - -static LRESULT -TREEVIEW_SetInsertMarkColor(TREEVIEW_INFO *infoPtr, COLORREF color) -{ - COLORREF prevColor = infoPtr->clrInsertMark; - - TRACE("%lx\n", color); - infoPtr->clrInsertMark = color; - - return (LRESULT)prevColor; -} - - -static LRESULT -TREEVIEW_SetInsertMark(TREEVIEW_INFO *infoPtr, BOOL wParam, HTREEITEM item) -{ - TRACE("%d %p\n", wParam, item); - - if (!TREEVIEW_ValidItem(infoPtr, item)) - return 0; - - infoPtr->insertBeforeorAfter = wParam; - infoPtr->insertMarkItem = item; - - TREEVIEW_Invalidate(infoPtr, NULL); - - return 1; -} - - -/************************************************************************ - * Some serious braindamage here. lParam is a pointer to both the - * input HTREEITEM and the output RECT. - */ -static LRESULT -TREEVIEW_GetItemRect(TREEVIEW_INFO *infoPtr, BOOL fTextRect, LPRECT lpRect) -{ - TREEVIEW_ITEM *wineItem; - const HTREEITEM *pItem = (HTREEITEM *)lpRect; - - TRACE("\n"); - /* - * validate parameters - */ - if (pItem == NULL) - return FALSE; - - wineItem = *pItem; - if (!TREEVIEW_ValidItem(infoPtr, wineItem) || !ISVISIBLE(wineItem)) - return FALSE; - - /* - * If wParam is TRUE return the text size otherwise return - * the whole item size - */ - if (fTextRect) - { - /* Windows does not send TVN_GETDISPINFO here. */ - - lpRect->top = wineItem->rect.top; - lpRect->bottom = wineItem->rect.bottom; - - lpRect->left = wineItem->textOffset; - lpRect->right = wineItem->textOffset + wineItem->textWidth; - } - else - { - *lpRect = wineItem->rect; - } - - TRACE("%s [L:%ld R:%ld T:%ld B:%ld]\n", fTextRect ? "text" : "item", - lpRect->left, lpRect->right, lpRect->top, lpRect->bottom); - - return TRUE; -} - -static inline LRESULT -TREEVIEW_GetVisibleCount(TREEVIEW_INFO *infoPtr) -{ - /* Suprise! This does not take integral height into account. */ - return infoPtr->clientHeight / infoPtr->uItemHeight; -} - - -static LRESULT -TREEVIEW_GetItemT(TREEVIEW_INFO *infoPtr, LPTVITEMEXW tvItem, BOOL isW) -{ - TREEVIEW_ITEM *wineItem; - - wineItem = tvItem->hItem; - if (!TREEVIEW_ValidItem(infoPtr, wineItem)) - return FALSE; - - TREEVIEW_UpdateDispInfo(infoPtr, wineItem, tvItem->mask); - - if (tvItem->mask & TVIF_CHILDREN) - { - if (wineItem->cChildren==I_CHILDRENCALLBACK) - FIXME("I_CHILDRENCALLBACK not supported\n"); - tvItem->cChildren = wineItem->cChildren; - } - - if (tvItem->mask & TVIF_HANDLE) - tvItem->hItem = wineItem; - - if (tvItem->mask & TVIF_IMAGE) - tvItem->iImage = wineItem->iImage; - - if (tvItem->mask & TVIF_INTEGRAL) - tvItem->iIntegral = wineItem->iIntegral; - - /* undocumented: windows ignores TVIF_PARAM and - * * always sets lParam - */ - tvItem->lParam = wineItem->lParam; - - if (tvItem->mask & TVIF_SELECTEDIMAGE) - tvItem->iSelectedImage = wineItem->iSelectedImage; - - if (tvItem->mask & TVIF_STATE) - /* Careful here - Windows ignores the stateMask when you get the state - That contradicts the documentation, but makes more common sense, masking - retrieval in this way seems overkill */ - tvItem->state = wineItem->state; - - if (tvItem->mask & TVIF_TEXT) - { - if (isW) - { - if (wineItem->pszText == LPSTR_TEXTCALLBACKW) - { - tvItem->pszText = LPSTR_TEXTCALLBACKW; - FIXME(" GetItem called with LPSTR_TEXTCALLBACK\n"); - } - else - { - lstrcpynW(tvItem->pszText, wineItem->pszText, tvItem->cchTextMax); - } - } - else - { - if (wineItem->pszText == LPSTR_TEXTCALLBACKW) - { - tvItem->pszText = (LPWSTR)LPSTR_TEXTCALLBACKA; - FIXME(" GetItem called with LPSTR_TEXTCALLBACK\n"); - } - else - { - WideCharToMultiByte(CP_ACP, 0, wineItem->pszText, -1, - (LPSTR)tvItem->pszText, tvItem->cchTextMax, NULL, NULL); - } - } - } - TRACE("item <%p>, txt %p, img %p, mask %x\n", - wineItem, tvItem->pszText, &tvItem->iImage, tvItem->mask); - - return TRUE; -} - -/* Beware MSDN Library Visual Studio 6.0. It says -1 on failure, 0 on success, - * which is wrong. */ -static LRESULT -TREEVIEW_SetItemT(TREEVIEW_INFO *infoPtr, LPTVITEMEXW tvItem, BOOL isW) -{ - TREEVIEW_ITEM *wineItem; - TREEVIEW_ITEM originalItem; - - wineItem = tvItem->hItem; - - TRACE("item %d,mask %x\n", TREEVIEW_GetItemIndex(infoPtr, wineItem), - tvItem->mask); - - if (!TREEVIEW_ValidItem(infoPtr, wineItem)) - return FALSE; - - /* store the orignal item values */ - originalItem = *wineItem; - - if (!TREEVIEW_DoSetItemT(infoPtr, wineItem, tvItem, isW)) - return FALSE; - - /* If the text or TVIS_BOLD was changed, and it is visible, recalculate. */ - if ((tvItem->mask & TVIF_TEXT - || (tvItem->mask & TVIF_STATE && tvItem->stateMask & TVIS_BOLD)) - && ISVISIBLE(wineItem)) - { - TREEVIEW_UpdateDispInfo(infoPtr, wineItem, TVIF_TEXT); - TREEVIEW_ComputeTextWidth(infoPtr, wineItem, 0); - } - - if (tvItem->mask != 0 && ISVISIBLE(wineItem)) - { - /* The refresh updates everything, but we can't wait until then. */ - TREEVIEW_ComputeItemInternalMetrics(infoPtr, wineItem); - - /* if any of the item's values changed and it's not a callback, redraw the item */ - if (item_changed(&originalItem, wineItem, tvItem)) - { - if (tvItem->mask & TVIF_INTEGRAL) - { - TREEVIEW_RecalculateVisibleOrder(infoPtr, wineItem); - TREEVIEW_UpdateScrollBars(infoPtr); - - TREEVIEW_Invalidate(infoPtr, NULL); - } - else - { - TREEVIEW_UpdateScrollBars(infoPtr); - TREEVIEW_Invalidate(infoPtr, wineItem); - } - } - } - - return TRUE; -} - -static LRESULT -TREEVIEW_GetItemState(TREEVIEW_INFO *infoPtr, HTREEITEM wineItem, UINT mask) -{ - TRACE("\n"); - - if (!wineItem || !TREEVIEW_ValidItem(infoPtr, wineItem)) - return 0; - - return (wineItem->state & mask); -} - -static LRESULT -TREEVIEW_GetNextItem(TREEVIEW_INFO *infoPtr, UINT which, HTREEITEM wineItem) -{ - TREEVIEW_ITEM *retval; - - retval = 0; - - /* handle all the global data here */ - switch (which) - { - case TVGN_CHILD: /* Special case: child of 0 is root */ - if (wineItem) - break; - /* fall through */ - case TVGN_ROOT: - retval = infoPtr->root->firstChild; - break; - - case TVGN_CARET: - retval = infoPtr->selectedItem; - break; - - case TVGN_FIRSTVISIBLE: - retval = infoPtr->firstVisible; - break; - - case TVGN_DROPHILITE: - retval = infoPtr->dropItem; - break; - - case TVGN_LASTVISIBLE: - retval = TREEVIEW_GetLastListItem(infoPtr, infoPtr->root); - break; - } - - if (retval) - { - TRACE("flags:%x, returns %p\n", which, retval); - return (LRESULT)retval; - } - - if (wineItem == TVI_ROOT) wineItem = infoPtr->root; - - if (!TREEVIEW_ValidItem(infoPtr, wineItem)) - return FALSE; - - switch (which) - { - case TVGN_NEXT: - retval = wineItem->nextSibling; - break; - case TVGN_PREVIOUS: - retval = wineItem->prevSibling; - break; - case TVGN_PARENT: - retval = (wineItem->parent != infoPtr->root) ? wineItem->parent : NULL; - break; - case TVGN_CHILD: - retval = wineItem->firstChild; - break; - case TVGN_NEXTVISIBLE: - retval = TREEVIEW_GetNextListItem(infoPtr, wineItem); - break; - case TVGN_PREVIOUSVISIBLE: - retval = TREEVIEW_GetPrevListItem(infoPtr, wineItem); - break; - default: - TRACE("Unknown msg %x,item %p\n", which, wineItem); - break; - } - - TRACE("flags:%x, item %p;returns %p\n", which, wineItem, retval); - return (LRESULT)retval; -} - - -static LRESULT -TREEVIEW_GetCount(TREEVIEW_INFO *infoPtr) -{ - TRACE(" %d\n", infoPtr->uNumItems); - return (LRESULT)infoPtr->uNumItems; -} - -static VOID -TREEVIEW_ToggleItemState(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) -{ - if (infoPtr->dwStyle & TVS_CHECKBOXES) - { - static const unsigned int state_table[] = { 0, 2, 1 }; - - unsigned int state; - - state = STATEIMAGEINDEX(item->state); - TRACE("state:%x\n", state); - item->state &= ~TVIS_STATEIMAGEMASK; - - if (state < 3) - state = state_table[state]; - - item->state |= INDEXTOSTATEIMAGEMASK(state); - - TRACE("state:%x\n", state); - TREEVIEW_Invalidate(infoPtr, item); - } -} - - -/* Painting *************************************************************/ - -/* Draw the lines and expand button for an item. Also draws one section - * of the line from item's parent to item's parent's next sibling. */ -static void -TREEVIEW_DrawItemLines(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *item) -{ - LONG centerx, centery; - BOOL lar = ((infoPtr->dwStyle - & (TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS)) - > TVS_LINESATROOT); - HBRUSH hbr, hbrOld; - - if (!lar && item->iLevel == 0) - return; - - hbr = CreateSolidBrush(infoPtr->clrBk); - hbrOld = SelectObject(hdc, hbr); - - centerx = (item->linesOffset + item->stateOffset) / 2; - centery = (item->rect.top + item->rect.bottom) / 2; - - if (infoPtr->dwStyle & TVS_HASLINES) - { - HPEN hOldPen, hNewPen; - HTREEITEM parent; - - /* - * Get a dotted grey pen - */ - hNewPen = CreatePen(PS_ALTERNATE, 0, infoPtr->clrLine); - hOldPen = SelectObject(hdc, hNewPen); - - MoveToEx(hdc, item->stateOffset, centery, NULL); - LineTo(hdc, centerx - 1, centery); - - if (item->prevSibling || item->parent != infoPtr->root) - { - MoveToEx(hdc, centerx, item->rect.top, NULL); - LineTo(hdc, centerx, centery); - } - - if (item->nextSibling) - { - MoveToEx(hdc, centerx, centery, NULL); - LineTo(hdc, centerx, item->rect.bottom + 1); - } - - /* Draw the line from our parent to its next sibling. */ - parent = item->parent; - while (parent != infoPtr->root) - { - int pcenterx = (parent->linesOffset + parent->stateOffset) / 2; - - if (parent->nextSibling - /* skip top-levels unless TVS_LINESATROOT */ - && parent->stateOffset > parent->linesOffset) - { - MoveToEx(hdc, pcenterx, item->rect.top, NULL); - LineTo(hdc, pcenterx, item->rect.bottom + 1); - } - - parent = parent->parent; - } - - SelectObject(hdc, hOldPen); - DeleteObject(hNewPen); - } - - /* - * Display the (+/-) signs - */ - - if (infoPtr->dwStyle & TVS_HASBUTTONS) - { - if (item->cChildren) - { - LONG height = item->rect.bottom - item->rect.top; - LONG width = item->stateOffset - item->linesOffset; - LONG rectsize = min(height, width) / 4; - /* plussize = ceil(rectsize * 3/4) */ - LONG plussize = (rectsize + 1) * 3 / 4; - - HPEN hNewPen = CreatePen(PS_SOLID, 0, infoPtr->clrLine); - HPEN hOldPen = SelectObject(hdc, hNewPen); - - Rectangle(hdc, centerx - rectsize - 1, centery - rectsize - 1, - centerx + rectsize + 2, centery + rectsize + 2); - - SelectObject(hdc, hOldPen); - DeleteObject(hNewPen); - - if (height < 18 || width < 18) - { - MoveToEx(hdc, centerx - plussize + 1, centery, NULL); - LineTo(hdc, centerx + plussize, centery); - - if (!(item->state & TVIS_EXPANDED)) - { - MoveToEx(hdc, centerx, centery - plussize + 1, NULL); - LineTo(hdc, centerx, centery + plussize); - } - } - else - { - Rectangle(hdc, centerx - plussize + 1, centery - 1, - centerx + plussize, centery + 2); - - if (!(item->state & TVIS_EXPANDED)) - { - Rectangle(hdc, centerx - 1, centery - plussize + 1, - centerx + 2, centery + plussize); - SetPixel(hdc, centerx - 1, centery, infoPtr->clrBk); - SetPixel(hdc, centerx + 1, centery, infoPtr->clrBk); - } - } - } - } - SelectObject(hdc, hbrOld); - DeleteObject(hbr); -} - -static void -TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *wineItem) -{ - INT cditem; - HFONT hOldFont; - COLORREF oldTextColor, oldTextBkColor; - int centery; - BOOL inFocus = (GetFocus() == infoPtr->hwnd); - NMTVCUSTOMDRAW nmcdhdr; - - TREEVIEW_UpdateDispInfo(infoPtr, wineItem, CALLBACK_MASK_ALL); - - /* - If item is drop target or it is selected and window is in focus - - * use blue background (COLOR_HIGHLIGHT). - * - If item is selected, window is not in focus, but it has style - * TVS_SHOWSELALWAYS - use grey background (COLOR_BTNFACE) - * - Otherwise - use background color - */ - if ((wineItem->state & TVIS_DROPHILITED) || ((wineItem == infoPtr->focusedItem) && !(wineItem->state & TVIS_SELECTED)) || - ((wineItem->state & TVIS_SELECTED) && (!infoPtr->focusedItem) && - (inFocus || (infoPtr->dwStyle & TVS_SHOWSELALWAYS)))) - { - if ((wineItem->state & TVIS_DROPHILITED) || inFocus) - { - nmcdhdr.clrTextBk = GetSysColor(COLOR_HIGHLIGHT); - nmcdhdr.clrText = GetSysColor(COLOR_HIGHLIGHTTEXT); - } - else - { - nmcdhdr.clrTextBk = GetSysColor(COLOR_BTNFACE); - if (infoPtr->clrText == -1) - nmcdhdr.clrText = GetSysColor(COLOR_WINDOWTEXT); - else - nmcdhdr.clrText = infoPtr->clrText; - } - } - else - { - nmcdhdr.clrTextBk = infoPtr->clrBk; - if ((infoPtr->dwStyle & TVS_TRACKSELECT) && (wineItem == infoPtr->hotItem)) - nmcdhdr.clrText = comctl32_color.clrHighlight; - else if (infoPtr->clrText == -1) - nmcdhdr.clrText = GetSysColor(COLOR_WINDOWTEXT); - else - nmcdhdr.clrText = infoPtr->clrText; - } - - hOldFont = SelectObject(hdc, TREEVIEW_FontForItem(infoPtr, wineItem)); - - /* The custom draw handler can query the text rectangle, - * so get ready. */ - /* should already be known, set to 0 when changed */ - if (!wineItem->textWidth) - TREEVIEW_ComputeTextWidth(infoPtr, wineItem, hdc); - - cditem = 0; - - if (infoPtr->cdmode & CDRF_NOTIFYITEMDRAW) - { - cditem = TREEVIEW_SendCustomDrawItemNotify - (infoPtr, hdc, wineItem, CDDS_ITEMPREPAINT, &nmcdhdr); - TRACE("prepaint:cditem-app returns 0x%x\n", cditem); - - if (cditem & CDRF_SKIPDEFAULT) - { - SelectObject(hdc, hOldFont); - return; - } - } - - if (cditem & CDRF_NEWFONT) - TREEVIEW_ComputeTextWidth(infoPtr, wineItem, hdc); - - TREEVIEW_DrawItemLines(infoPtr, hdc, wineItem); - - /* Set colors. Custom draw handler can change these so we do this after it. */ - oldTextColor = SetTextColor(hdc, nmcdhdr.clrText); - oldTextBkColor = SetBkColor(hdc, nmcdhdr.clrTextBk); - - centery = (wineItem->rect.top + wineItem->rect.bottom) / 2; - - /* - * Display the images associated with this item - */ - { - INT imageIndex; - - /* State images are displayed to the left of the Normal image - * image number is in state; zero should be `display no image'. - */ - imageIndex = STATEIMAGEINDEX(wineItem->state); - - if (infoPtr->himlState && imageIndex) - { - ImageList_Draw(infoPtr->himlState, imageIndex, hdc, - wineItem->stateOffset, - centery - infoPtr->stateImageHeight / 2, - ILD_NORMAL); - } - - /* Now, draw the normal image; can be either selected or - * non-selected image. - */ - - if ((wineItem->state & TVIS_SELECTED) && (wineItem->iSelectedImage >= 0)) - { - /* The item is currently selected */ - imageIndex = wineItem->iSelectedImage; - } - else - { - /* The item is not selected */ - imageIndex = wineItem->iImage; - } - - if (infoPtr->himlNormal) - { - int ovlIdx = wineItem->state & TVIS_OVERLAYMASK; - - ImageList_Draw(infoPtr->himlNormal, imageIndex, hdc, - wineItem->imageOffset, - centery - infoPtr->normalImageHeight / 2, - ILD_NORMAL | ovlIdx); - } - } - - - /* - * Display the text associated with this item - */ - - /* Don't paint item's text if it's being edited */ - if (!infoPtr->hwndEdit || (infoPtr->selectedItem != wineItem)) - { - if (wineItem->pszText) - { - RECT rcText; - - rcText.top = wineItem->rect.top; - rcText.bottom = wineItem->rect.bottom; - rcText.left = wineItem->textOffset; - rcText.right = rcText.left + wineItem->textWidth + 4; - - TRACE("drawing text %s at (%ld,%ld)-(%ld,%ld)\n", - debugstr_w(wineItem->pszText), - rcText.left, rcText.top, rcText.right, rcText.bottom); - - /* Draw it */ - ExtTextOutW(hdc, rcText.left + 2, rcText.top + 1, - ETO_CLIPPED | ETO_OPAQUE, - &rcText, - wineItem->pszText, - lstrlenW(wineItem->pszText), - NULL); - - /* Draw the box around the selected item */ - if ((wineItem == infoPtr->selectedItem) && inFocus) - { - DrawFocusRect(hdc,&rcText); - } - - } - } - - /* Draw insertion mark if necessary */ - - if (infoPtr->insertMarkItem) - TRACE("item:%d,mark:%d\n", - TREEVIEW_GetItemIndex(infoPtr, wineItem), - (int)infoPtr->insertMarkItem); - - if (wineItem == infoPtr->insertMarkItem) - { - HPEN hNewPen, hOldPen; - int offset; - int left, right; - - hNewPen = CreatePen(PS_SOLID, 2, infoPtr->clrInsertMark); - hOldPen = SelectObject(hdc, hNewPen); - - if (infoPtr->insertBeforeorAfter) - offset = wineItem->rect.bottom - 1; - else - offset = wineItem->rect.top + 1; - - left = wineItem->textOffset - 2; - right = wineItem->textOffset + wineItem->textWidth + 2; - - MoveToEx(hdc, left, offset - 3, NULL); - LineTo(hdc, left, offset + 4); - - MoveToEx(hdc, left, offset, NULL); - LineTo(hdc, right + 1, offset); - - MoveToEx(hdc, right, offset + 3, NULL); - LineTo(hdc, right, offset - 4); - - SelectObject(hdc, hOldPen); - DeleteObject(hNewPen); - } - - if (cditem & CDRF_NOTIFYPOSTPAINT) - { - cditem = TREEVIEW_SendCustomDrawItemNotify - (infoPtr, hdc, wineItem, CDDS_ITEMPOSTPAINT, &nmcdhdr); - TRACE("postpaint:cditem-app returns 0x%x\n", cditem); - } - - /* Restore the hdc state */ - SetTextColor(hdc, oldTextColor); - SetBkColor(hdc, oldTextBkColor); - SelectObject(hdc, hOldFont); -} - -/* Computes treeHeight and treeWidth and updates the scroll bars. - */ -static void -TREEVIEW_UpdateScrollBars(TREEVIEW_INFO *infoPtr) -{ - TREEVIEW_ITEM *wineItem; - HWND hwnd = infoPtr->hwnd; - BOOL vert = FALSE; - BOOL horz = FALSE; - SCROLLINFO si; - LONG scrollX = infoPtr->scrollX; - - infoPtr->treeWidth = 0; - infoPtr->treeHeight = 0; - - /* We iterate through all visible items in order to get the tree height - * and width */ - wineItem = infoPtr->root->firstChild; - - while (wineItem != NULL) - { - if (ISVISIBLE(wineItem)) - { - /* actually we draw text at textOffset + 2 */ - if (2+wineItem->textOffset+wineItem->textWidth > infoPtr->treeWidth) - infoPtr->treeWidth = wineItem->textOffset+wineItem->textWidth+2; - - /* This is scroll-adjusted, but we fix this below. */ - infoPtr->treeHeight = wineItem->rect.bottom; - } - - wineItem = TREEVIEW_GetNextListItem(infoPtr, wineItem); - } - - /* Fix the scroll adjusted treeHeight and treeWidth. */ - if (infoPtr->root->firstChild) - infoPtr->treeHeight -= infoPtr->root->firstChild->rect.top; - - infoPtr->treeWidth += infoPtr->scrollX; - - if (infoPtr->dwStyle & TVS_NOSCROLL) return; - - /* Adding one scroll bar may take up enough space that it forces us - * to add the other as well. */ - if (infoPtr->treeHeight > infoPtr->clientHeight) - { - vert = TRUE; - - if (infoPtr->treeWidth - > infoPtr->clientWidth - GetSystemMetrics(SM_CXVSCROLL)) - horz = TRUE; - } - else if (infoPtr->treeWidth > infoPtr->clientWidth) - horz = TRUE; - - if (!vert && horz && infoPtr->treeHeight - > infoPtr->clientHeight - GetSystemMetrics(SM_CYVSCROLL)) - vert = TRUE; - - if (horz && (infoPtr->dwStyle & TVS_NOHSCROLL)) horz = FALSE; - - si.cbSize = sizeof(SCROLLINFO); - si.fMask = SIF_POS|SIF_RANGE|SIF_PAGE; - si.nMin = 0; - - if (vert) - { - si.nPage = TREEVIEW_GetVisibleCount(infoPtr); - if ( si.nPage && NULL != infoPtr->firstVisible) - { - si.nPos = infoPtr->firstVisible->visibleOrder; - si.nMax = infoPtr->maxVisibleOrder - 1; - - SetScrollInfo(hwnd, SB_VERT, &si, TRUE); - - if (!(infoPtr->uInternalStatus & TV_VSCROLL)) - ShowScrollBar(hwnd, SB_VERT, TRUE); - infoPtr->uInternalStatus |= TV_VSCROLL; - } - else - { - if (infoPtr->uInternalStatus & TV_VSCROLL) - ShowScrollBar(hwnd, SB_VERT, FALSE); - infoPtr->uInternalStatus &= ~TV_VSCROLL; - } - } - else - { - if (infoPtr->uInternalStatus & TV_VSCROLL) - ShowScrollBar(hwnd, SB_VERT, FALSE); - infoPtr->uInternalStatus &= ~TV_VSCROLL; - } - - if (horz) - { - si.nPage = infoPtr->clientWidth; - si.nPos = infoPtr->scrollX; - si.nMax = infoPtr->treeWidth - 1; - - if (si.nPos > si.nMax - max( si.nPage-1, 0 )) - { - si.nPos = si.nMax - max( si.nPage-1, 0 ); - scrollX = si.nPos; - } - - if (!(infoPtr->uInternalStatus & TV_HSCROLL)) - ShowScrollBar(hwnd, SB_HORZ, TRUE); - infoPtr->uInternalStatus |= TV_HSCROLL; - - SetScrollInfo(hwnd, SB_HORZ, &si, TRUE); - } - else - { - if (infoPtr->uInternalStatus & TV_HSCROLL) - ShowScrollBar(hwnd, SB_HORZ, FALSE); - infoPtr->uInternalStatus &= ~TV_HSCROLL; - - scrollX = 0; - } - - if (infoPtr->scrollX != scrollX) - { - TREEVIEW_HScroll(infoPtr, - MAKEWPARAM(SB_THUMBPOSITION, scrollX)); - } - - if (!horz) - infoPtr->uInternalStatus &= ~TV_HSCROLL; -} - -/* CtrlSpy doesn't mention this, but CorelDRAW's object manager needs it. */ -static LRESULT -TREEVIEW_EraseBackground(TREEVIEW_INFO *infoPtr, HDC hDC) -{ - HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk); - RECT rect; - - GetClientRect(infoPtr->hwnd, &rect); - FillRect(hDC, &rect, hBrush); - DeleteObject(hBrush); - - return 1; -} - -static void -TREEVIEW_Refresh(TREEVIEW_INFO *infoPtr, HDC hdc, RECT *rc) -{ - HWND hwnd = infoPtr->hwnd; - RECT rect = *rc; - TREEVIEW_ITEM *wineItem; - - if (infoPtr->clientHeight == 0 || infoPtr->clientWidth == 0) - { - TRACE("empty window\n"); - return; - } - - infoPtr->cdmode = TREEVIEW_SendCustomDrawNotify(infoPtr, CDDS_PREPAINT, - hdc, rect); - - if (infoPtr->cdmode == CDRF_SKIPDEFAULT) - { - ReleaseDC(hwnd, hdc); - return; - } - - for (wineItem = infoPtr->root->firstChild; - wineItem != NULL; - wineItem = TREEVIEW_GetNextListItem(infoPtr, wineItem)) - { - if (ISVISIBLE(wineItem)) - { - /* Avoid unneeded calculations */ - if (wineItem->rect.top > rect.bottom) - break; - if (wineItem->rect.bottom < rect.top) - continue; - - TREEVIEW_DrawItem(infoPtr, hdc, wineItem); - } - } - - TREEVIEW_UpdateScrollBars(infoPtr); - - if (infoPtr->cdmode & CDRF_NOTIFYPOSTPAINT) - infoPtr->cdmode = - TREEVIEW_SendCustomDrawNotify(infoPtr, CDDS_POSTPAINT, hdc, rect); -} - -static void -TREEVIEW_Invalidate(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) -{ - if (item != NULL) - InvalidateRect(infoPtr->hwnd, &item->rect, TRUE); - else - InvalidateRect(infoPtr->hwnd, NULL, TRUE); -} - -static LRESULT -TREEVIEW_Paint(TREEVIEW_INFO *infoPtr, WPARAM wParam) -{ - HDC hdc; - PAINTSTRUCT ps; - RECT rc; - - TRACE("\n"); - - if (wParam) - { - hdc = (HDC)wParam; - if (!GetUpdateRect(infoPtr->hwnd, &rc, TRUE)) - { - HBITMAP hbitmap; - BITMAP bitmap; - hbitmap = GetCurrentObject(hdc, OBJ_BITMAP); - if (!hbitmap) return 0; - GetObjectW(hbitmap, sizeof(BITMAP), &bitmap); - rc.left = 0; rc.top = 0; - rc.right = bitmap.bmWidth; - rc.bottom = bitmap.bmHeight; - TREEVIEW_EraseBackground(infoPtr, (HDC)wParam); - } - } - else - { - hdc = BeginPaint(infoPtr->hwnd, &ps); - rc = ps.rcPaint; - } - - if(infoPtr->bRedraw) /* WM_SETREDRAW sets bRedraw */ - TREEVIEW_Refresh(infoPtr, hdc, &rc); - - if (!wParam) - EndPaint(infoPtr->hwnd, &ps); - - return 0; -} - - -/* Sorting **************************************************************/ - -/*************************************************************************** - * Forward the DPA local callback to the treeview owner callback - */ -static INT WINAPI -TREEVIEW_CallBackCompare(TREEVIEW_ITEM *first, TREEVIEW_ITEM *second, LPTVSORTCB pCallBackSort) -{ - /* Forward the call to the client-defined callback */ - return pCallBackSort->lpfnCompare(first->lParam, - second->lParam, - pCallBackSort->lParam); -} - -/*************************************************************************** - * Treeview native sort routine: sort on item text. - */ -static INT WINAPI -TREEVIEW_SortOnName(TREEVIEW_ITEM *first, TREEVIEW_ITEM *second, - TREEVIEW_INFO *infoPtr) -{ - TREEVIEW_UpdateDispInfo(infoPtr, first, TVIF_TEXT); - TREEVIEW_UpdateDispInfo(infoPtr, second, TVIF_TEXT); - - if(first->pszText && second->pszText) - return lstrcmpiW(first->pszText, second->pszText); - else if(first->pszText) - return -1; - else if(second->pszText) - return 1; - else - return 0; -} - -/* Returns the number of physical children belonging to item. */ -static INT -TREEVIEW_CountChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) -{ - INT cChildren = 0; - HTREEITEM hti; - - for (hti = item->firstChild; hti != NULL; hti = hti->nextSibling) - cChildren++; - - return cChildren; -} - -/* Returns a DPA containing a pointer to each physical child of item in - * sibling order. If item has no children, an empty DPA is returned. */ -static HDPA -TREEVIEW_BuildChildDPA(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) -{ - HTREEITEM child = item->firstChild; - - HDPA list = DPA_Create(8); - if (list == 0) return NULL; - - for (child = item->firstChild; child != NULL; child = child->nextSibling) - { - if (DPA_InsertPtr(list, INT_MAX, child) == -1) - { - DPA_Destroy(list); - return NULL; - } - } - - return list; -} - -/*************************************************************************** - * Setup the treeview structure with regards of the sort method - * and sort the children of the TV item specified in lParam - * fRecurse: currently unused. Should be zero. - * parent: if pSort!=NULL, should equal pSort->hParent. - * otherwise, item which child items are to be sorted. - * pSort: sort method info. if NULL, sort on item text. - * if non-NULL, sort on item's lParam content, and let the - * application decide what that means. See also TVM_SORTCHILDRENCB. - */ - -static LRESULT -TREEVIEW_Sort(TREEVIEW_INFO *infoPtr, BOOL fRecurse, HTREEITEM parent, - LPTVSORTCB pSort) -{ - INT cChildren; - PFNDPACOMPARE pfnCompare; - LPARAM lpCompare; - - /* undocumented feature: TVI_ROOT or NULL means `sort the whole tree' */ - if (parent == TVI_ROOT || parent == NULL) - parent = infoPtr->root; - - /* Check for a valid handle to the parent item */ - if (!TREEVIEW_ValidItem(infoPtr, parent)) - { - ERR("invalid item hParent=%x\n", (INT)parent); - return FALSE; - } - - if (pSort) - { - pfnCompare = (PFNDPACOMPARE)TREEVIEW_CallBackCompare; - lpCompare = (LPARAM)pSort; - } - else - { - pfnCompare = (PFNDPACOMPARE)TREEVIEW_SortOnName; - lpCompare = (LPARAM)infoPtr; - } - - cChildren = TREEVIEW_CountChildren(infoPtr, parent); - - /* Make sure there is something to sort */ - if (cChildren > 1) - { - /* TREEVIEW_ITEM rechaining */ - INT count = 0; - HTREEITEM item = 0; - HTREEITEM nextItem = 0; - HTREEITEM prevItem = 0; - - HDPA sortList = TREEVIEW_BuildChildDPA(infoPtr, parent); - - if (sortList == NULL) - return FALSE; - - /* let DPA sort the list */ - DPA_Sort(sortList, pfnCompare, lpCompare); - - /* The order of DPA entries has been changed, so fixup the - * nextSibling and prevSibling pointers. */ - - item = (HTREEITEM)DPA_GetPtr(sortList, count++); - while ((nextItem = (HTREEITEM)DPA_GetPtr(sortList, count++)) != NULL) - { - /* link the two current item toghether */ - item->nextSibling = nextItem; - nextItem->prevSibling = item; - - if (prevItem == NULL) - { - /* this is the first item, update the parent */ - parent->firstChild = item; - item->prevSibling = NULL; - } - else - { - /* fix the back chaining */ - item->prevSibling = prevItem; - } - - /* get ready for the next one */ - prevItem = item; - item = nextItem; - } - - /* the last item is pointed to by item and never has a sibling */ - item->nextSibling = NULL; - parent->lastChild = item; - - DPA_Destroy(sortList); - - TREEVIEW_VerifyTree(infoPtr); - - if (parent->state & TVIS_EXPANDED) - { - int visOrder = infoPtr->firstVisible->visibleOrder; - - if (parent == infoPtr->root) - TREEVIEW_RecalculateVisibleOrder(infoPtr, NULL); - else - TREEVIEW_RecalculateVisibleOrder(infoPtr, parent); - - if (TREEVIEW_IsChildOf(parent, infoPtr->firstVisible)) - { - TREEVIEW_ITEM *item; - - for (item = infoPtr->root->firstChild; item != NULL; - item = TREEVIEW_GetNextListItem(infoPtr, item)) - { - if (item->visibleOrder == visOrder) - break; - } - - if (!item) item = parent->firstChild; - TREEVIEW_SetFirstVisible(infoPtr, item, FALSE); - } - - TREEVIEW_Invalidate(infoPtr, NULL); - } - - return TRUE; - } - return FALSE; -} - - -/*************************************************************************** - * Setup the treeview structure with regards of the sort method - * and sort the children of the TV item specified in lParam - */ -static LRESULT -TREEVIEW_SortChildrenCB(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPTVSORTCB pSort) -{ - return TREEVIEW_Sort(infoPtr, wParam, pSort->hParent, pSort); -} - - -/*************************************************************************** - * Sort the children of the TV item specified in lParam. - */ -static LRESULT -TREEVIEW_SortChildren(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - return TREEVIEW_Sort(infoPtr, (BOOL)wParam, (HTREEITEM)lParam, NULL); -} - - -/* Expansion/Collapse ***************************************************/ - -static BOOL -TREEVIEW_SendExpanding(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, - UINT action) -{ - return !TREEVIEW_SendTreeviewNotify(infoPtr, TVN_ITEMEXPANDINGW, action, - TVIF_HANDLE | TVIF_STATE | TVIF_PARAM - | TVIF_IMAGE | TVIF_SELECTEDIMAGE, - 0, wineItem); -} - -static VOID -TREEVIEW_SendExpanded(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, - UINT action) -{ - TREEVIEW_SendTreeviewNotify(infoPtr, TVN_ITEMEXPANDEDW, action, - TVIF_HANDLE | TVIF_STATE | TVIF_PARAM - | TVIF_IMAGE | TVIF_SELECTEDIMAGE, - 0, wineItem); -} - - -/* This corresponds to TVM_EXPAND with TVE_COLLAPSE. - * bRemoveChildren corresponds to TVE_COLLAPSERESET. */ -static BOOL -TREEVIEW_Collapse(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, - BOOL bRemoveChildren, BOOL bUser) -{ - UINT action = TVE_COLLAPSE | (bRemoveChildren ? TVE_COLLAPSERESET : 0); - BOOL bSetSelection, bSetFirstVisible; - RECT scrollRect; - LONG scrollDist = 0; - TREEVIEW_ITEM *nextItem = NULL, *tmpItem; - - TRACE("TVE_COLLAPSE %p %s\n", wineItem, TREEVIEW_ItemName(wineItem)); - - if (!(wineItem->state & TVIS_EXPANDED)) - return FALSE; - - if (bUser || !(wineItem->state & TVIS_EXPANDEDONCE)) - TREEVIEW_SendExpanding(infoPtr, wineItem, action); - - if (wineItem->firstChild == NULL) - return FALSE; - - wineItem->state &= ~TVIS_EXPANDED; - - if (bUser || !(wineItem->state & TVIS_EXPANDEDONCE)) - TREEVIEW_SendExpanded(infoPtr, wineItem, action); - - bSetSelection = (infoPtr->selectedItem != NULL - && TREEVIEW_IsChildOf(wineItem, infoPtr->selectedItem)); - - bSetFirstVisible = (infoPtr->firstVisible != NULL - && TREEVIEW_IsChildOf(wineItem, infoPtr->firstVisible)); - - tmpItem = wineItem; - while (tmpItem) - { - if (tmpItem->nextSibling) - { - nextItem = tmpItem->nextSibling; - break; - } - tmpItem = tmpItem->parent; - } - - if (nextItem) - scrollDist = nextItem->rect.top; - - if (bRemoveChildren) - { - INT old_cChildren = wineItem->cChildren; - TRACE("TVE_COLLAPSERESET\n"); - wineItem->state &= ~TVIS_EXPANDEDONCE; - TREEVIEW_RemoveAllChildren(infoPtr, wineItem); - wineItem->cChildren = old_cChildren; - } - - if (wineItem->firstChild) - { - TREEVIEW_ITEM *item, *sibling; - - sibling = TREEVIEW_GetNextListItem(infoPtr, wineItem); - - for (item = wineItem->firstChild; item != sibling; - item = TREEVIEW_GetNextListItem(infoPtr, item)) - { - item->visibleOrder = -1; - } - } - - TREEVIEW_RecalculateVisibleOrder(infoPtr, wineItem); - - if (nextItem) - scrollDist = -(scrollDist - nextItem->rect.top); - - if (bSetSelection) - { - /* Don't call DoSelectItem, it sends notifications. */ - if (TREEVIEW_ValidItem(infoPtr, infoPtr->selectedItem)) - infoPtr->selectedItem->state &= ~TVIS_SELECTED; - wineItem->state |= TVIS_SELECTED; - infoPtr->selectedItem = wineItem; - } - - TREEVIEW_UpdateScrollBars(infoPtr); - - scrollRect.left = 0; - scrollRect.right = infoPtr->clientWidth; - scrollRect.bottom = infoPtr->clientHeight; - - if (nextItem) - { - scrollRect.top = nextItem->rect.top; - - ScrollWindowEx (infoPtr->hwnd, 0, scrollDist, &scrollRect, NULL, - NULL, NULL, SW_ERASE | SW_INVALIDATE); - TREEVIEW_Invalidate(infoPtr, wineItem); - } else { - scrollRect.top = wineItem->rect.top; - InvalidateRect(infoPtr->hwnd, &scrollRect, TRUE); - } - - TREEVIEW_SetFirstVisible(infoPtr, - bSetFirstVisible ? wineItem : infoPtr->firstVisible, - TRUE); - - return TRUE; -} - -static BOOL -TREEVIEW_Expand(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, - BOOL bExpandPartial, BOOL bUser) -{ - LONG scrollDist; - LONG orgNextTop = 0; - RECT scrollRect; - TREEVIEW_ITEM *nextItem, *tmpItem; - - TRACE("\n"); - - if (wineItem->state & TVIS_EXPANDED) - return TRUE; - - tmpItem = wineItem; nextItem = NULL; - while (tmpItem) - { - if (tmpItem->nextSibling) - { - nextItem = tmpItem->nextSibling; - break; - } - tmpItem = tmpItem->parent; - } - - if (nextItem) - orgNextTop = nextItem->rect.top; - - TRACE("TVE_EXPAND %p %s\n", wineItem, TREEVIEW_ItemName(wineItem)); - - if (bUser || ((wineItem->cChildren != 0) && - !(wineItem->state & TVIS_EXPANDEDONCE))) - { - if (!TREEVIEW_SendExpanding(infoPtr, wineItem, TVE_EXPAND)) - { - TRACE(" TVN_ITEMEXPANDING returned TRUE, exiting...\n"); - return FALSE; - } - - if (!wineItem->firstChild) - return FALSE; - - wineItem->state |= TVIS_EXPANDED; - TREEVIEW_SendExpanded(infoPtr, wineItem, TVE_EXPAND); - wineItem->state |= TVIS_EXPANDEDONCE; - } - else - { - if (!wineItem->firstChild) - return FALSE; - - /* this item has already been expanded */ - wineItem->state |= TVIS_EXPANDED; - } - - if (bExpandPartial) - FIXME("TVE_EXPANDPARTIAL not implemented\n"); - - TREEVIEW_RecalculateVisibleOrder(infoPtr, wineItem); - TREEVIEW_UpdateSubTree(infoPtr, wineItem); - TREEVIEW_UpdateScrollBars(infoPtr); - - scrollRect.left = 0; - scrollRect.bottom = infoPtr->treeHeight; - scrollRect.right = infoPtr->clientWidth; - if (nextItem) - { - scrollDist = nextItem->rect.top - orgNextTop; - scrollRect.top = orgNextTop; - - ScrollWindowEx (infoPtr->hwnd, 0, scrollDist, &scrollRect, NULL, - NULL, NULL, SW_ERASE | SW_INVALIDATE); - TREEVIEW_Invalidate (infoPtr, wineItem); - } else { - scrollRect.top = wineItem->rect.top; - InvalidateRect(infoPtr->hwnd, &scrollRect, FALSE); - } - - /* Scroll up so that as many children as possible are visible. - * This fails when expanding causes an HScroll bar to appear, but we - * don't know that yet, so the last item is obscured. */ - if (wineItem->firstChild != NULL) - { - int nChildren = wineItem->lastChild->visibleOrder - - wineItem->firstChild->visibleOrder + 1; - - int visible_pos = wineItem->visibleOrder - - infoPtr->firstVisible->visibleOrder; - - int rows_below = TREEVIEW_GetVisibleCount(infoPtr) - visible_pos - 1; - - if (visible_pos > 0 && nChildren > rows_below) - { - int scroll = nChildren - rows_below; - - if (scroll > visible_pos) - scroll = visible_pos; - - if (scroll > 0) - { - TREEVIEW_ITEM *newFirstVisible - = TREEVIEW_GetListItem(infoPtr, infoPtr->firstVisible, - scroll); - - - TREEVIEW_SetFirstVisible(infoPtr, newFirstVisible, TRUE); - } - } - } - - return TRUE; -} - -static BOOL -TREEVIEW_Toggle(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, BOOL bUser) -{ - TRACE("\n"); - - if (wineItem->state & TVIS_EXPANDED) - return TREEVIEW_Collapse(infoPtr, wineItem, FALSE, bUser); - else - return TREEVIEW_Expand(infoPtr, wineItem, FALSE, bUser); -} - -static VOID -TREEVIEW_ExpandAll(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) -{ - TREEVIEW_Expand(infoPtr, item, FALSE, TRUE); - - for (item = item->firstChild; item != NULL; item = item->nextSibling) - { - if (TREEVIEW_HasChildren(infoPtr, item)) - TREEVIEW_ExpandAll(infoPtr, item); - } -} - -/* Note:If the specified item is the child of a collapsed parent item, - the parent's list of child items is (recursively) expanded to reveal the - specified item. This is mentioned for TREEVIEW_SelectItem; don't - know if it also applies here. -*/ - -static LRESULT -TREEVIEW_ExpandMsg(TREEVIEW_INFO *infoPtr, UINT flag, HTREEITEM wineItem) -{ - if (!TREEVIEW_ValidItem(infoPtr, wineItem)) - return 0; - - TRACE("For (%s) item:%d, flags %x, state:%d\n", - TREEVIEW_ItemName(wineItem), flag, - TREEVIEW_GetItemIndex(infoPtr, wineItem), wineItem->state); - - switch (flag & TVE_TOGGLE) - { - case TVE_COLLAPSE: - return TREEVIEW_Collapse(infoPtr, wineItem, flag & TVE_COLLAPSERESET, - FALSE); - - case TVE_EXPAND: - return TREEVIEW_Expand(infoPtr, wineItem, flag & TVE_EXPANDPARTIAL, - FALSE); - - case TVE_TOGGLE: - return TREEVIEW_Toggle(infoPtr, wineItem, TRUE); - - default: - return 0; - } - -#if 0 - TRACE("Exiting, Item %p state is now %d...\n", wineItem, wineItem->state); -#endif -} - -/* Hit-Testing **********************************************************/ - -static TREEVIEW_ITEM * -TREEVIEW_HitTestPoint(TREEVIEW_INFO *infoPtr, POINT pt) -{ - TREEVIEW_ITEM *wineItem; - LONG row; - - if (!infoPtr->firstVisible) - return NULL; - - row = pt.y / infoPtr->uItemHeight + infoPtr->firstVisible->visibleOrder; - - for (wineItem = infoPtr->firstVisible; wineItem != NULL; - wineItem = TREEVIEW_GetNextListItem(infoPtr, wineItem)) - { - if (row >= wineItem->visibleOrder - && row < wineItem->visibleOrder + wineItem->iIntegral) - break; - } - - return wineItem; -} - -static LRESULT -TREEVIEW_HitTest(TREEVIEW_INFO *infoPtr, LPTVHITTESTINFO lpht) -{ - TREEVIEW_ITEM *wineItem; - RECT rect; - UINT status; - LONG x, y; - - lpht->hItem = 0; - GetClientRect(infoPtr->hwnd, &rect); - status = 0; - x = lpht->pt.x; - y = lpht->pt.y; - - if (x < rect.left) - { - status |= TVHT_TOLEFT; - } - else if (x > rect.right) - { - status |= TVHT_TORIGHT; - } - - if (y < rect.top) - { - status |= TVHT_ABOVE; - } - else if (y > rect.bottom) - { - status |= TVHT_BELOW; - } - - if (status) - { - lpht->flags = status; - return (LRESULT)(HTREEITEM)NULL; - } - - wineItem = TREEVIEW_HitTestPoint(infoPtr, lpht->pt); - if (!wineItem) - { - lpht->flags = TVHT_NOWHERE; - return (LRESULT)(HTREEITEM)NULL; - } - - if (x >= wineItem->textOffset + wineItem->textWidth) - { - lpht->flags = TVHT_ONITEMRIGHT; - } - else if (x >= wineItem->textOffset) - { - lpht->flags = TVHT_ONITEMLABEL; - } - else if (x >= wineItem->imageOffset) - { - lpht->flags = TVHT_ONITEMICON; - } - else if (x >= wineItem->stateOffset) - { - lpht->flags = TVHT_ONITEMSTATEICON; - } - else if (x >= wineItem->linesOffset && infoPtr->dwStyle & TVS_HASBUTTONS) - { - lpht->flags = TVHT_ONITEMBUTTON; - } - else - { - lpht->flags = TVHT_ONITEMINDENT; - } - - lpht->hItem = wineItem; - TRACE("(%ld,%ld):result %x\n", lpht->pt.x, lpht->pt.y, lpht->flags); - - return (LRESULT)wineItem; -} - -/* Item Label Editing ***************************************************/ - -static LRESULT -TREEVIEW_GetEditControl(TREEVIEW_INFO *infoPtr) -{ - return (LRESULT)infoPtr->hwndEdit; -} - -static LRESULT CALLBACK -TREEVIEW_Edit_SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd)); - BOOL bCancel = FALSE; - LRESULT rc; - - switch (uMsg) - { - case WM_PAINT: - TRACE("WM_PAINT start\n"); - rc = CallWindowProcW(infoPtr->wpEditOrig, hwnd, uMsg, wParam, - lParam); - TRACE("WM_PAINT done\n"); - return rc; - - case WM_KILLFOCUS: - if (infoPtr->bIgnoreEditKillFocus) - return TRUE; - break; - - case WM_GETDLGCODE: - return DLGC_WANTARROWS | DLGC_WANTALLKEYS; - - case WM_KEYDOWN: - if (wParam == (WPARAM)VK_ESCAPE) - { - bCancel = TRUE; - break; - } - else if (wParam == (WPARAM)VK_RETURN) - { - break; - } - - /* fall through */ - default: - return CallWindowProcW(infoPtr->wpEditOrig, hwnd, uMsg, wParam, lParam); - } - - /* Processing TVN_ENDLABELEDIT message could kill the focus */ - /* eg. Using a messagebox */ - - infoPtr->bIgnoreEditKillFocus = TRUE; - TREEVIEW_EndEditLabelNow(infoPtr, bCancel || !infoPtr->bLabelChanged); - infoPtr->bIgnoreEditKillFocus = FALSE; - - return 0; -} - - -/* should handle edit control messages here */ - -static LRESULT -TREEVIEW_Command(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - TRACE("%x %ld\n", wParam, lParam); - - switch (HIWORD(wParam)) - { - case EN_UPDATE: - { - /* - * Adjust the edit window size - */ - WCHAR buffer[1024]; - TREEVIEW_ITEM *editItem = infoPtr->selectedItem; - HDC hdc = GetDC(infoPtr->hwndEdit); - SIZE sz; - int len; - HFONT hFont, hOldFont = 0; - - infoPtr->bLabelChanged = TRUE; - - len = GetWindowTextW(infoPtr->hwndEdit, buffer, sizeof(buffer)); - - /* Select font to get the right dimension of the string */ - hFont = (HFONT)SendMessageW(infoPtr->hwndEdit, WM_GETFONT, 0, 0); - - if (hFont != 0) - { - hOldFont = SelectObject(hdc, hFont); - } - - if (GetTextExtentPoint32W(hdc, buffer, strlenW(buffer), &sz)) - { - TEXTMETRICW textMetric; - - /* Add Extra spacing for the next character */ - GetTextMetricsW(hdc, &textMetric); - sz.cx += (textMetric.tmMaxCharWidth * 2); - - sz.cx = max(sz.cx, textMetric.tmMaxCharWidth * 3); - sz.cx = min(sz.cx, - infoPtr->clientWidth - editItem->textOffset + 2); - - SetWindowPos(infoPtr->hwndEdit, - HWND_TOP, - 0, - 0, - sz.cx, - editItem->rect.bottom - editItem->rect.top + 3, - SWP_NOMOVE | SWP_DRAWFRAME); - } - - if (hFont != 0) - { - SelectObject(hdc, hOldFont); - } - - ReleaseDC(infoPtr->hwnd, hdc); - break; - } - - default: - return SendMessageW(infoPtr->hwndNotify, WM_COMMAND, wParam, lParam); - } - - return 0; -} - -static HWND -TREEVIEW_EditLabel(TREEVIEW_INFO *infoPtr, HTREEITEM hItem) -{ - HWND hwnd = infoPtr->hwnd; - HWND hwndEdit; - SIZE sz; - TREEVIEW_ITEM *editItem = hItem; - HINSTANCE hinst = (HINSTANCE)GetWindowLongPtrW(hwnd, GWLP_HINSTANCE); - HDC hdc; - HFONT hOldFont=0; - TEXTMETRICW textMetric; - static const WCHAR EditW[] = {'E','d','i','t',0}; - - TRACE("%x %p\n", (unsigned)hwnd, hItem); - if (!TREEVIEW_ValidItem(infoPtr, editItem)) - return NULL; - - if (infoPtr->hwndEdit) - return infoPtr->hwndEdit; - - infoPtr->bLabelChanged = FALSE; - - /* Make sure that edit item is selected */ - TREEVIEW_DoSelectItem(infoPtr, TVGN_CARET, hItem, TVC_UNKNOWN); - TREEVIEW_EnsureVisible(infoPtr, hItem, TRUE); - - TREEVIEW_UpdateDispInfo(infoPtr, editItem, TVIF_TEXT); - - hdc = GetDC(hwnd); - /* Select the font to get appropriate metric dimensions */ - if (infoPtr->hFont != 0) - { - hOldFont = SelectObject(hdc, infoPtr->hFont); - } - - /* Get string length in pixels */ - GetTextExtentPoint32W(hdc, editItem->pszText, strlenW(editItem->pszText), - &sz); - - /* Add Extra spacing for the next character */ - GetTextMetricsW(hdc, &textMetric); - sz.cx += (textMetric.tmMaxCharWidth * 2); - - sz.cx = max(sz.cx, textMetric.tmMaxCharWidth * 3); - sz.cx = min(sz.cx, infoPtr->clientWidth - editItem->textOffset + 2); - - if (infoPtr->hFont != 0) - { - SelectObject(hdc, hOldFont); - } - - ReleaseDC(hwnd, hdc); - hwndEdit = CreateWindowExW(WS_EX_LEFT, - EditW, - 0, - WS_CHILD | WS_BORDER | ES_AUTOHSCROLL | - WS_CLIPSIBLINGS | ES_WANTRETURN | - ES_LEFT, editItem->textOffset - 2, - editItem->rect.top - 1, sz.cx + 3, - editItem->rect.bottom - - editItem->rect.top + 3, hwnd, 0, hinst, 0); -/* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0); */ - - infoPtr->hwndEdit = hwndEdit; - - /* Get a 2D border. */ - SetWindowLongW(hwndEdit, GWL_EXSTYLE, - GetWindowLongW(hwndEdit, GWL_EXSTYLE) & ~WS_EX_CLIENTEDGE); - SetWindowLongW(hwndEdit, GWL_STYLE, - GetWindowLongW(hwndEdit, GWL_STYLE) | WS_BORDER); - - SendMessageW(hwndEdit, WM_SETFONT, - (WPARAM)TREEVIEW_FontForItem(infoPtr, editItem), FALSE); - - infoPtr->wpEditOrig = (WNDPROC)SetWindowLongPtrW(hwndEdit, GWLP_WNDPROC, - (DWORD_PTR) - TREEVIEW_Edit_SubclassProc); - - if (TREEVIEW_BeginLabelEditNotify(infoPtr, editItem)) - { - DestroyWindow(hwndEdit); - infoPtr->hwndEdit = 0; - return NULL; - } - - infoPtr->selectedItem = hItem; - SetWindowTextW(hwndEdit, editItem->pszText); - SetFocus(hwndEdit); - SendMessageW(hwndEdit, EM_SETSEL, 0, -1); - ShowWindow(hwndEdit, SW_SHOW); - - return hwndEdit; -} - - -static LRESULT -TREEVIEW_EndEditLabelNow(TREEVIEW_INFO *infoPtr, BOOL bCancel) -{ - HWND hwnd = infoPtr->hwnd; - TREEVIEW_ITEM *editedItem = infoPtr->selectedItem; - NMTVDISPINFOW tvdi; - BOOL bCommit; - WCHAR tmpText[1024] = { '\0' }; - WCHAR *newText = tmpText; - int iLength = 0; - - if (!infoPtr->hwndEdit) - return FALSE; - - tvdi.hdr.hwndFrom = hwnd; - tvdi.hdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID); - tvdi.hdr.code = get_notifycode(infoPtr, TVN_ENDLABELEDITW); - tvdi.item.mask = 0; - tvdi.item.hItem = editedItem; - tvdi.item.state = editedItem->state; - tvdi.item.lParam = editedItem->lParam; - - if (!bCancel) - { - if (!infoPtr->bNtfUnicode) - iLength = GetWindowTextA(infoPtr->hwndEdit, (LPSTR)tmpText, 1023); - else - iLength = GetWindowTextW(infoPtr->hwndEdit, tmpText, 1023); - - if (iLength >= 1023) - { - ERR("Insufficient space to retrieve new item label\n"); - } - - tvdi.item.mask = TVIF_TEXT; - tvdi.item.pszText = tmpText; - tvdi.item.cchTextMax = iLength + 1; - } - else - { - tvdi.item.pszText = NULL; - tvdi.item.cchTextMax = 0; - } - - bCommit = (BOOL)TREEVIEW_SendRealNotify(infoPtr, - (WPARAM)tvdi.hdr.idFrom, (LPARAM)&tvdi); - - if (!bCancel && bCommit) /* Apply the changes */ - { - if (!infoPtr->bNtfUnicode) - { - DWORD len = MultiByteToWideChar( CP_ACP, 0, (LPSTR)tmpText, -1, NULL, 0 ); - newText = Alloc(len * sizeof(WCHAR)); - MultiByteToWideChar( CP_ACP, 0, (LPSTR)tmpText, -1, newText, len ); - iLength = len - 1; - } - - if (strcmpW(newText, editedItem->pszText) != 0) - { - if (NULL == ReAlloc(editedItem->pszText, iLength + 1)) - { - ERR("OutOfMemory, cannot allocate space for label\n"); - DestroyWindow(infoPtr->hwndEdit); - infoPtr->hwndEdit = 0; - return FALSE; - } - else - { - editedItem->cchTextMax = iLength + 1; - strcpyW(editedItem->pszText, newText); - } - } - if(newText != tmpText) Free(newText); - } - - ShowWindow(infoPtr->hwndEdit, SW_HIDE); - DestroyWindow(infoPtr->hwndEdit); - infoPtr->hwndEdit = 0; - return TRUE; -} - -static LRESULT -TREEVIEW_HandleTimer(TREEVIEW_INFO *infoPtr, WPARAM wParam) -{ - if (wParam != TV_EDIT_TIMER) - { - ERR("got unknown timer\n"); - return 1; - } - - KillTimer(infoPtr->hwnd, TV_EDIT_TIMER); - infoPtr->Timer &= ~TV_EDIT_TIMER_SET; - - TREEVIEW_EditLabel(infoPtr, infoPtr->selectedItem); - - return 0; -} - - -/* Mouse Tracking/Drag **************************************************/ - -/*************************************************************************** - * This is quite unusual piece of code, but that's how it's implemented in - * Windows. - */ -static LRESULT -TREEVIEW_TrackMouse(TREEVIEW_INFO *infoPtr, POINT pt) -{ - INT cxDrag = GetSystemMetrics(SM_CXDRAG); - INT cyDrag = GetSystemMetrics(SM_CYDRAG); - RECT r; - MSG msg; - - r.top = pt.y - cyDrag; - r.left = pt.x - cxDrag; - r.bottom = pt.y + cyDrag; - r.right = pt.x + cxDrag; - - SetCapture(infoPtr->hwnd); - - while (1) - { - if (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) - { - if (msg.message == WM_MOUSEMOVE) - { - pt.x = (short)LOWORD(msg.lParam); - pt.y = (short)HIWORD(msg.lParam); - if (PtInRect(&r, pt)) - continue; - else - { - ReleaseCapture(); - return 1; - } - } - else if (msg.message >= WM_LBUTTONDOWN && - msg.message <= WM_RBUTTONDBLCLK) - { - if (msg.message == WM_RBUTTONUP) - TREEVIEW_RButtonUp(infoPtr, &pt); - break; - } - - DispatchMessageW(&msg); - } - - if (GetCapture() != infoPtr->hwnd) - return 0; - } - - ReleaseCapture(); - return 0; -} - - -static LRESULT -TREEVIEW_LButtonDoubleClick(TREEVIEW_INFO *infoPtr, LPARAM lParam) -{ - TREEVIEW_ITEM *wineItem; - TVHITTESTINFO hit; - - TRACE("\n"); - SetFocus(infoPtr->hwnd); - - if (infoPtr->Timer & TV_EDIT_TIMER_SET) - { - /* If there is pending 'edit label' event - kill it now */ - KillTimer(infoPtr->hwnd, TV_EDIT_TIMER); - } - - hit.pt.x = (short)LOWORD(lParam); - hit.pt.y = (short)HIWORD(lParam); - - wineItem = (TREEVIEW_ITEM *)TREEVIEW_HitTest(infoPtr, &hit); - if (!wineItem) - return 0; - TRACE("item %d\n", TREEVIEW_GetItemIndex(infoPtr, wineItem)); - - if (TREEVIEW_SendSimpleNotify(infoPtr, NM_DBLCLK) == FALSE) - { /* FIXME! */ - switch (hit.flags) - { - case TVHT_ONITEMRIGHT: - /* FIXME: we should not have sent NM_DBLCLK in this case. */ - break; - - case TVHT_ONITEMINDENT: - if (!(infoPtr->dwStyle & TVS_HASLINES)) - { - break; - } - else - { - int level = hit.pt.x / infoPtr->uIndent; - if (!(infoPtr->dwStyle & TVS_LINESATROOT)) level++; - - while (wineItem->iLevel > level) - { - wineItem = wineItem->parent; - } - - /* fall through */ - } - - case TVHT_ONITEMLABEL: - case TVHT_ONITEMICON: - case TVHT_ONITEMBUTTON: - TREEVIEW_Toggle(infoPtr, wineItem, TRUE); - break; - - case TVHT_ONITEMSTATEICON: - if (infoPtr->dwStyle & TVS_CHECKBOXES) - TREEVIEW_ToggleItemState(infoPtr, wineItem); - else - TREEVIEW_Toggle(infoPtr, wineItem, TRUE); - break; - } - } - return TRUE; -} - - -static LRESULT -TREEVIEW_LButtonDown(TREEVIEW_INFO *infoPtr, LPARAM lParam) -{ - HWND hwnd = infoPtr->hwnd; - TVHITTESTINFO ht; - BOOL bTrack, bDoLabelEdit; - HTREEITEM tempItem; - - /* If Edit control is active - kill it and return. - * The best way to do it is to set focus to itself. - * Edit control subclassed procedure will automatically call - * EndEditLabelNow. - */ - if (infoPtr->hwndEdit) - { - SetFocus(hwnd); - return 0; - } - - ht.pt.x = (short)LOWORD(lParam); - ht.pt.y = (short)HIWORD(lParam); - - TREEVIEW_HitTest(infoPtr, &ht); - TRACE("item %d\n", TREEVIEW_GetItemIndex(infoPtr, ht.hItem)); - - /* update focusedItem and redraw both items */ - if(ht.hItem && (ht.flags & TVHT_ONITEM)) - { - infoPtr->focusedItem = ht.hItem; - InvalidateRect(hwnd, &(((HTREEITEM)(ht.hItem))->rect), TRUE); - - if(infoPtr->selectedItem) - InvalidateRect(hwnd, &(infoPtr->selectedItem->rect), TRUE); - } - - bTrack = (ht.flags & TVHT_ONITEM) - && !(infoPtr->dwStyle & TVS_DISABLEDRAGDROP); - - /* - * If the style allows editing and the node is already selected - * and the click occurred on the item label... - */ - bDoLabelEdit = (infoPtr->dwStyle & TVS_EDITLABELS) && - (ht.flags & TVHT_ONITEMLABEL) && (infoPtr->selectedItem == ht.hItem); - - /* Send NM_CLICK right away */ - if (!bTrack) - if (TREEVIEW_SendSimpleNotify(infoPtr, NM_CLICK)) - goto setfocus; - - if (ht.flags & TVHT_ONITEMBUTTON) - { - TREEVIEW_Toggle(infoPtr, ht.hItem, TRUE); - goto setfocus; - } - else if (bTrack) - { /* if TREEVIEW_TrackMouse == 1 dragging occurred and the cursor left the dragged item's rectangle */ - if (TREEVIEW_TrackMouse(infoPtr, ht.pt)) - { - TREEVIEW_SendTreeviewDnDNotify(infoPtr, TVN_BEGINDRAGW, ht.hItem, ht.pt); - infoPtr->dropItem = ht.hItem; - - /* clean up focusedItem as we dragged and won't select this item */ - if(infoPtr->focusedItem) - { - /* refresh the item that was focused */ - tempItem = infoPtr->focusedItem; - infoPtr->focusedItem = 0; - InvalidateRect(infoPtr->hwnd, &tempItem->rect, TRUE); - - /* refresh the selected item to return the filled background */ - InvalidateRect(infoPtr->hwnd, &(infoPtr->selectedItem->rect), TRUE); - } - - return 0; - } - } - - if (bTrack && TREEVIEW_SendSimpleNotify(infoPtr, NM_CLICK)) - goto setfocus; - - if (bDoLabelEdit) - { - if (infoPtr->Timer & TV_EDIT_TIMER_SET) - KillTimer(hwnd, TV_EDIT_TIMER); - - SetTimer(hwnd, TV_EDIT_TIMER, GetDoubleClickTime(), 0); - infoPtr->Timer |= TV_EDIT_TIMER_SET; - } - else if (ht.flags & (TVHT_ONITEMICON|TVHT_ONITEMLABEL)) /* select the item if the hit was inside of the icon or text */ - { - /* - * if we are TVS_SINGLEEXPAND then we want this single click to - * do a bunch of things. - */ - if((infoPtr->dwStyle & TVS_SINGLEEXPAND) && - (infoPtr->hwndEdit == 0)) - { - TREEVIEW_ITEM *SelItem; - - /* - * Send the notification - */ - TREEVIEW_SendTreeviewNotify(infoPtr, TVN_SINGLEEXPAND, TVC_UNKNOWN, TVIF_HANDLE | TVIF_PARAM, ht.hItem, 0); - - /* - * Close the previous selection all the way to the root - * as long as the new selection is not a child - */ - if((infoPtr->selectedItem) - && (infoPtr->selectedItem != ht.hItem)) - { - BOOL closeit = TRUE; - SelItem = ht.hItem; - - /* determine if the hitItem is a child of the currently selected item */ - while(closeit && SelItem && TREEVIEW_ValidItem(infoPtr, SelItem) && (SelItem != infoPtr->root)) - { - closeit = (SelItem != infoPtr->selectedItem); - SelItem = SelItem->parent; - } - - if(closeit) - { - if(TREEVIEW_ValidItem(infoPtr, infoPtr->selectedItem)) - SelItem = infoPtr->selectedItem; - - while(SelItem && (SelItem != ht.hItem) && TREEVIEW_ValidItem(infoPtr, SelItem) && (SelItem != infoPtr->root)) - { - TREEVIEW_Collapse(infoPtr, SelItem, FALSE, FALSE); - SelItem = SelItem->parent; - } - } - } - - /* - * Expand the current item - */ - TREEVIEW_Expand(infoPtr, ht.hItem, TVE_TOGGLE, FALSE); - } - - /* Select the current item */ - TREEVIEW_DoSelectItem(infoPtr, TVGN_CARET, ht.hItem, TVC_BYMOUSE); - } - else if (ht.flags & TVHT_ONITEMSTATEICON) - { - /* TVS_CHECKBOXES requires us to toggle the current state */ - if (infoPtr->dwStyle & TVS_CHECKBOXES) - TREEVIEW_ToggleItemState(infoPtr, ht.hItem); - } - - setfocus: - SetFocus(hwnd); - return 0; -} - - -static LRESULT -TREEVIEW_RButtonDown(TREEVIEW_INFO *infoPtr, LPARAM lParam) -{ - TVHITTESTINFO ht; - - if (infoPtr->hwndEdit) - { - SetFocus(infoPtr->hwnd); - return 0; - } - - ht.pt.x = (short)LOWORD(lParam); - ht.pt.y = (short)HIWORD(lParam); - - TREEVIEW_HitTest(infoPtr, &ht); - - if (TREEVIEW_TrackMouse(infoPtr, ht.pt)) - { - if (ht.hItem) - { - TREEVIEW_SendTreeviewDnDNotify(infoPtr, TVN_BEGINRDRAGW, ht.hItem, ht.pt); - infoPtr->dropItem = ht.hItem; - } - } - else - { - SetFocus(infoPtr->hwnd); - TREEVIEW_SendSimpleNotify(infoPtr, NM_RCLICK); - } - - return 0; -} - -static LRESULT -TREEVIEW_RButtonUp(TREEVIEW_INFO *infoPtr, LPPOINT pPt) -{ - return 0; -} - - -static LRESULT -TREEVIEW_CreateDragImage(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - TREEVIEW_ITEM *dragItem = (HTREEITEM)lParam; - INT cx, cy; - HDC hdc, htopdc; - HWND hwtop; - HBITMAP hbmp, hOldbmp; - SIZE size; - RECT rc; - HFONT hOldFont; - - TRACE("\n"); - - if (!(infoPtr->himlNormal)) - return 0; - - if (!dragItem || !TREEVIEW_ValidItem(infoPtr, dragItem)) - return 0; - - TREEVIEW_UpdateDispInfo(infoPtr, dragItem, TVIF_TEXT); - - hwtop = GetDesktopWindow(); - htopdc = GetDC(hwtop); - hdc = CreateCompatibleDC(htopdc); - - hOldFont = SelectObject(hdc, infoPtr->hFont); - GetTextExtentPoint32W(hdc, dragItem->pszText, strlenW(dragItem->pszText), - &size); - TRACE("%ld %ld %s %d\n", size.cx, size.cy, debugstr_w(dragItem->pszText), - strlenW(dragItem->pszText)); - hbmp = CreateCompatibleBitmap(htopdc, size.cx, size.cy); - hOldbmp = SelectObject(hdc, hbmp); - - ImageList_GetIconSize(infoPtr->himlNormal, &cx, &cy); - size.cx += cx; - if (cy > size.cy) - size.cy = cy; - - infoPtr->dragList = ImageList_Create(size.cx, size.cy, ILC_COLOR, 10, 10); - ImageList_Draw(infoPtr->himlNormal, dragItem->iImage, hdc, 0, 0, - ILD_NORMAL); - -/* - ImageList_GetImageInfo (infoPtr->himlNormal, dragItem->hItem, &iminfo); - ImageList_AddMasked (infoPtr->dragList, iminfo.hbmImage, CLR_DEFAULT); -*/ - -/* draw item text */ - - SetRect(&rc, cx, 0, size.cx, size.cy); - DrawTextW(hdc, dragItem->pszText, strlenW(dragItem->pszText), &rc, - DT_LEFT); - SelectObject(hdc, hOldFont); - SelectObject(hdc, hOldbmp); - - ImageList_Add(infoPtr->dragList, hbmp, 0); - - DeleteDC(hdc); - DeleteObject(hbmp); - ReleaseDC(hwtop, htopdc); - - return (LRESULT)infoPtr->dragList; -} - -/* Selection ************************************************************/ - -static LRESULT -TREEVIEW_DoSelectItem(TREEVIEW_INFO *infoPtr, INT action, HTREEITEM newSelect, - INT cause) -{ - TREEVIEW_ITEM *prevSelect; - RECT rcFocused; - - assert(newSelect == NULL || TREEVIEW_ValidItem(infoPtr, newSelect)); - - TRACE("Entering item %p (%s), flag %x, cause %x, state %d\n", - newSelect, TREEVIEW_ItemName(newSelect), action, cause, - newSelect ? newSelect->state : 0); - - /* reset and redraw focusedItem if focusedItem was set so we don't */ - /* have to worry about the previously focused item when we set a new one */ - if(infoPtr->focusedItem) - { - rcFocused = (infoPtr->focusedItem)->rect; - infoPtr->focusedItem = 0; - InvalidateRect(infoPtr->hwnd, &rcFocused, TRUE); - } - - switch (action) - { - case TVGN_CARET: - prevSelect = infoPtr->selectedItem; - - if (prevSelect == newSelect) { - TREEVIEW_EnsureVisible(infoPtr, infoPtr->selectedItem, FALSE); - break; - } - - if (TREEVIEW_SendTreeviewNotify(infoPtr, - TVN_SELCHANGINGW, - cause, - TVIF_HANDLE | TVIF_STATE | TVIF_PARAM, - prevSelect, - newSelect)) - return FALSE; - - if (prevSelect) - prevSelect->state &= ~TVIS_SELECTED; - if (newSelect) - newSelect->state |= TVIS_SELECTED; - - infoPtr->selectedItem = newSelect; - - TREEVIEW_EnsureVisible(infoPtr, infoPtr->selectedItem, FALSE); - - if (prevSelect) - TREEVIEW_Invalidate(infoPtr, prevSelect); - if (newSelect) - TREEVIEW_Invalidate(infoPtr, newSelect); - - TREEVIEW_SendTreeviewNotify(infoPtr, - TVN_SELCHANGEDW, - cause, - TVIF_HANDLE | TVIF_STATE | TVIF_PARAM, - prevSelect, - newSelect); - break; - - case TVGN_DROPHILITE: - prevSelect = infoPtr->dropItem; - - if (prevSelect) - prevSelect->state &= ~TVIS_DROPHILITED; - - infoPtr->dropItem = newSelect; - - if (newSelect) - newSelect->state |= TVIS_DROPHILITED; - - TREEVIEW_Invalidate(infoPtr, prevSelect); - TREEVIEW_Invalidate(infoPtr, newSelect); - break; - - case TVGN_FIRSTVISIBLE: - if (newSelect != NULL) - { - TREEVIEW_EnsureVisible(infoPtr, newSelect, FALSE); - TREEVIEW_SetFirstVisible(infoPtr, newSelect, TRUE); - TREEVIEW_Invalidate(infoPtr, NULL); - } - break; - } - - TRACE("Leaving state %d\n", newSelect ? newSelect->state : 0); - return TRUE; -} - -/* FIXME: handle NM_KILLFOCUS etc */ -static LRESULT -TREEVIEW_SelectItem(TREEVIEW_INFO *infoPtr, INT wParam, HTREEITEM item) -{ - if (item != NULL && !TREEVIEW_ValidItem(infoPtr, item)) - return FALSE; - - TRACE("%p (%s) %d\n", item, TREEVIEW_ItemName(item), wParam); - - if (!TREEVIEW_DoSelectItem(infoPtr, wParam, item, TVC_UNKNOWN)) - return FALSE; - - return TRUE; -} - -/************************************************************************* - * TREEVIEW_ProcessLetterKeys - * - * Processes keyboard messages generated by pressing the letter keys - * on the keyboard. - * What this does is perform a case insensitive search from the - * current position with the following quirks: - * - If two chars or more are pressed in quick succession we search - * for the corresponding string (e.g. 'abc'). - * - If there is a delay we wipe away the current search string and - * restart with just that char. - * - If the user keeps pressing the same character, whether slowly or - * fast, so that the search string is entirely composed of this - * character ('aaaaa' for instance), then we search for first item - * that starting with that character. - * - If the user types the above character in quick succession, then - * we must also search for the corresponding string ('aaaaa'), and - * go to that string if there is a match. - * - * RETURNS - * - * Zero. - * - * BUGS - * - * - The current implementation has a list of characters it will - * accept and it ignores averything else. In particular it will - * ignore accentuated characters which seems to match what - * Windows does. But I'm not sure it makes sense to follow - * Windows there. - * - We don't sound a beep when the search fails. - * - The search should start from the focused item, not from the selected - * item. One reason for this is to allow for multiple selections in trees. - * But currently infoPtr->focusedItem does not seem very usable. - * - * SEE ALSO - * - * TREEVIEW_ProcessLetterKeys - */ -static INT TREEVIEW_ProcessLetterKeys( - HWND hwnd, /* handle to the window */ - WPARAM charCode, /* the character code, the actual character */ - LPARAM keyData /* key data */ - ) -{ - TREEVIEW_INFO *infoPtr; - HTREEITEM nItem; - HTREEITEM endidx,idx; - TVITEMEXW item; - WCHAR buffer[MAX_PATH]; - DWORD timestamp,elapsed; - - /* simple parameter checking */ - if (!hwnd || !charCode || !keyData) - return 0; - - infoPtr=(TREEVIEW_INFO*)GetWindowLongPtrW(hwnd, 0); - if (!infoPtr) - return 0; - - /* only allow the valid WM_CHARs through */ - if (!isalnum(charCode) && - charCode != '.' && charCode != '`' && charCode != '!' && - charCode != '@' && charCode != '#' && charCode != '$' && - charCode != '%' && charCode != '^' && charCode != '&' && - charCode != '*' && charCode != '(' && charCode != ')' && - charCode != '-' && charCode != '_' && charCode != '+' && - charCode != '=' && charCode != '\\'&& charCode != ']' && - charCode != '}' && charCode != '[' && charCode != '{' && - charCode != '/' && charCode != '?' && charCode != '>' && - charCode != '<' && charCode != ',' && charCode != '~') - return 0; - - /* compute how much time elapsed since last keypress */ - timestamp = GetTickCount(); - if (timestamp > infoPtr->lastKeyPressTimestamp) { - elapsed=timestamp-infoPtr->lastKeyPressTimestamp; - } else { - elapsed=infoPtr->lastKeyPressTimestamp-timestamp; - } - - /* update the search parameters */ - infoPtr->lastKeyPressTimestamp=timestamp; - if (elapsed < KEY_DELAY) { - if (infoPtr->nSearchParamLength < sizeof(infoPtr->szSearchParam) / sizeof(WCHAR)) { - infoPtr->szSearchParam[infoPtr->nSearchParamLength++]=charCode; - } - if (infoPtr->charCode != charCode) { - infoPtr->charCode=charCode=0; - } - } else { - infoPtr->charCode=charCode; - infoPtr->szSearchParam[0]=charCode; - infoPtr->nSearchParamLength=1; - /* Redundant with the 1 char string */ - charCode=0; - } - - /* and search from the current position */ - nItem=NULL; - if (infoPtr->selectedItem != NULL) { - endidx=infoPtr->selectedItem; - /* if looking for single character match, - * then we must always move forward - */ - if (infoPtr->nSearchParamLength == 1) - idx=TREEVIEW_GetNextListItem(infoPtr,endidx); - else - idx=endidx; - } else { - endidx=NULL; - idx=infoPtr->root->firstChild; - } - do { - /* At the end point, sort out wrapping */ - if (idx == NULL) { - - /* If endidx is null, stop at the last item (ie top to bottom) */ - if (endidx == NULL) - break; - - /* Otherwise, start again at the very beginning */ - idx=infoPtr->root->firstChild; - - /* But if we are stopping on the first child, end now! */ - if (idx == endidx) break; - } - - /* get item */ - ZeroMemory(&item, sizeof(item)); - item.mask = TVIF_TEXT; - item.hItem = idx; - item.pszText = buffer; - item.cchTextMax = sizeof(buffer); - TREEVIEW_GetItemT( infoPtr, &item, TRUE ); - - /* check for a match */ - if (strncmpiW(item.pszText,infoPtr->szSearchParam,infoPtr->nSearchParamLength) == 0) { - nItem=idx; - break; - } else if ( (charCode != 0) && (nItem == NULL) && - (nItem != infoPtr->selectedItem) && - (strncmpiW(item.pszText,infoPtr->szSearchParam,1) == 0) ) { - /* This would work but we must keep looking for a longer match */ - nItem=idx; - } - idx=TREEVIEW_GetNextListItem(infoPtr,idx); - } while (idx != endidx); - - if (nItem != NULL) { - if (TREEVIEW_DoSelectItem(infoPtr, TVGN_CARET, nItem, TVC_BYKEYBOARD)) { - TREEVIEW_EnsureVisible(infoPtr, nItem, FALSE); - } - } - - return 0; -} - -/* Scrolling ************************************************************/ - -static LRESULT -TREEVIEW_EnsureVisible(TREEVIEW_INFO *infoPtr, HTREEITEM item, BOOL bHScroll) -{ - int viscount; - BOOL hasFirstVisible = infoPtr->firstVisible != NULL; - HTREEITEM newFirstVisible = NULL; - int visible_pos = -1; - - if (!TREEVIEW_ValidItem(infoPtr, item)) - return FALSE; - - if (!ISVISIBLE(item)) - { - /* Expand parents as necessary. */ - HTREEITEM parent; - - /* see if we are trying to ensure that root is vislble */ - if((item != infoPtr->root) && TREEVIEW_ValidItem(infoPtr, item)) - parent = item->parent; - else - parent = item; /* this item is the topmost item */ - - while (parent != infoPtr->root) - { - if (!(parent->state & TVIS_EXPANDED)) - TREEVIEW_Expand(infoPtr, parent, FALSE, FALSE); - - parent = parent->parent; - } - } - - viscount = TREEVIEW_GetVisibleCount(infoPtr); - - TRACE("%p (%s) %ld - %ld viscount(%d)\n", item, TREEVIEW_ItemName(item), item->visibleOrder, - hasFirstVisible ? infoPtr->firstVisible->visibleOrder : -1, viscount); - - if (hasFirstVisible) - visible_pos = item->visibleOrder - infoPtr->firstVisible->visibleOrder; - - if (visible_pos < 0) - { - /* item is before the start of the list: put it at the top. */ - newFirstVisible = item; - } - else if (visible_pos >= viscount - /* Sometimes, before we are displayed, GVC is 0, causing us to - * spuriously scroll up. */ - && visible_pos > 0 && !(infoPtr->dwStyle & TVS_NOSCROLL) ) - { - /* item is past the end of the list. */ - int scroll = visible_pos - viscount; - - newFirstVisible = TREEVIEW_GetListItem(infoPtr, infoPtr->firstVisible, - scroll + 1); - } - - if (bHScroll) - { - /* Scroll window so item's text is visible as much as possible */ - /* Calculation of amount of extra space is taken from EditLabel code */ - INT pos, x; - TEXTMETRICW textMetric; - HDC hdc = GetWindowDC(infoPtr->hwnd); - - x = item->textWidth; - - GetTextMetricsW(hdc, &textMetric); - ReleaseDC(infoPtr->hwnd, hdc); - - x += (textMetric.tmMaxCharWidth * 2); - x = max(x, textMetric.tmMaxCharWidth * 3); - - if (item->textOffset < 0) - pos = item->textOffset; - else if (item->textOffset + x > infoPtr->clientWidth) - { - if (x > infoPtr->clientWidth) - pos = item->textOffset; - else - pos = item->textOffset + x - infoPtr->clientWidth; - } - else - pos = 0; - - TREEVIEW_HScroll(infoPtr, MAKEWPARAM(SB_THUMBPOSITION, infoPtr->scrollX + pos)); - } - - if (newFirstVisible != NULL && newFirstVisible != infoPtr->firstVisible) - { - TREEVIEW_SetFirstVisible(infoPtr, newFirstVisible, TRUE); - - return TRUE; - } - - return FALSE; -} - -static VOID -TREEVIEW_SetFirstVisible(TREEVIEW_INFO *infoPtr, - TREEVIEW_ITEM *newFirstVisible, - BOOL bUpdateScrollPos) -{ - int gap_size; - - TRACE("%p: %s\n", newFirstVisible, TREEVIEW_ItemName(newFirstVisible)); - - if (newFirstVisible != NULL) - { - /* Prevent an empty gap from appearing at the bottom... */ - gap_size = TREEVIEW_GetVisibleCount(infoPtr) - - infoPtr->maxVisibleOrder + newFirstVisible->visibleOrder; - - if (gap_size > 0) - { - newFirstVisible = TREEVIEW_GetListItem(infoPtr, newFirstVisible, - -gap_size); - - /* ... unless we just don't have enough items. */ - if (newFirstVisible == NULL) - newFirstVisible = infoPtr->root->firstChild; - } - } - - if (infoPtr->firstVisible != newFirstVisible) - { - if (infoPtr->firstVisible == NULL || newFirstVisible == NULL) - { - infoPtr->firstVisible = newFirstVisible; - TREEVIEW_Invalidate(infoPtr, NULL); - } - else - { - TREEVIEW_ITEM *item; - int scroll = infoPtr->uItemHeight * - (infoPtr->firstVisible->visibleOrder - - newFirstVisible->visibleOrder); - - infoPtr->firstVisible = newFirstVisible; - - for (item = infoPtr->root->firstChild; item != NULL; - item = TREEVIEW_GetNextListItem(infoPtr, item)) - { - item->rect.top += scroll; - item->rect.bottom += scroll; - } - - if (bUpdateScrollPos) - SetScrollPos(infoPtr->hwnd, SB_VERT, - newFirstVisible->visibleOrder, TRUE); - - ScrollWindowEx(infoPtr->hwnd, 0, scroll, NULL, NULL, NULL, NULL, SW_ERASE | SW_INVALIDATE); - } - } -} - -/************************************************************************ - * VScroll is always in units of visible items. i.e. we always have a - * visible item aligned to the top of the control. (Unless we have no - * items at all.) - */ -static LRESULT -TREEVIEW_VScroll(TREEVIEW_INFO *infoPtr, WPARAM wParam) -{ - TREEVIEW_ITEM *oldFirstVisible = infoPtr->firstVisible; - TREEVIEW_ITEM *newFirstVisible = NULL; - - int nScrollCode = LOWORD(wParam); - - TRACE("wp %x\n", wParam); - - if (!(infoPtr->uInternalStatus & TV_VSCROLL)) - return 0; - - if (infoPtr->hwndEdit) - SetFocus(infoPtr->hwnd); - - if (!oldFirstVisible) - { - assert(infoPtr->root->firstChild == NULL); - return 0; - } - - switch (nScrollCode) - { - case SB_TOP: - newFirstVisible = infoPtr->root->firstChild; - break; - - case SB_BOTTOM: - newFirstVisible = TREEVIEW_GetLastListItem(infoPtr, infoPtr->root); - break; - - case SB_LINEUP: - newFirstVisible = TREEVIEW_GetPrevListItem(infoPtr, oldFirstVisible); - break; - - case SB_LINEDOWN: - newFirstVisible = TREEVIEW_GetNextListItem(infoPtr, oldFirstVisible); - break; - - case SB_PAGEUP: - newFirstVisible = TREEVIEW_GetListItem(infoPtr, oldFirstVisible, - -max(1, TREEVIEW_GetVisibleCount(infoPtr))); - break; - - case SB_PAGEDOWN: - newFirstVisible = TREEVIEW_GetListItem(infoPtr, oldFirstVisible, - max(1, TREEVIEW_GetVisibleCount(infoPtr))); - break; - - case SB_THUMBTRACK: - case SB_THUMBPOSITION: - newFirstVisible = TREEVIEW_GetListItem(infoPtr, - infoPtr->root->firstChild, - (LONG)(SHORT)HIWORD(wParam)); - break; - - case SB_ENDSCROLL: - return 0; - } - - if (newFirstVisible != NULL) - { - if (newFirstVisible != oldFirstVisible) - TREEVIEW_SetFirstVisible(infoPtr, newFirstVisible, - nScrollCode != SB_THUMBTRACK); - else if (nScrollCode == SB_THUMBPOSITION) - SetScrollPos(infoPtr->hwnd, SB_VERT, - newFirstVisible->visibleOrder, TRUE); - } - - return 0; -} - -static LRESULT -TREEVIEW_HScroll(TREEVIEW_INFO *infoPtr, WPARAM wParam) -{ - int maxWidth; - int scrollX = infoPtr->scrollX; - int nScrollCode = LOWORD(wParam); - - TRACE("wp %x\n", wParam); - - if (!(infoPtr->uInternalStatus & TV_HSCROLL)) - return FALSE; - - if (infoPtr->hwndEdit) - SetFocus(infoPtr->hwnd); - - maxWidth = infoPtr->treeWidth - infoPtr->clientWidth; - /* shall never occur */ - if (maxWidth <= 0) - { - scrollX = 0; - goto scroll; - } - - switch (nScrollCode) - { - case SB_LINELEFT: - scrollX -= infoPtr->uItemHeight; - break; - case SB_LINERIGHT: - scrollX += infoPtr->uItemHeight; - break; - case SB_PAGELEFT: - scrollX -= infoPtr->clientWidth; - break; - case SB_PAGERIGHT: - scrollX += infoPtr->clientWidth; - break; - - case SB_THUMBTRACK: - case SB_THUMBPOSITION: - scrollX = (int)(SHORT)HIWORD(wParam); - break; - - case SB_ENDSCROLL: - return 0; - } - - if (scrollX > maxWidth) - scrollX = maxWidth; - else if (scrollX < 0) - scrollX = 0; - -scroll: - if (scrollX != infoPtr->scrollX) - { - TREEVIEW_ITEM *item; - LONG scroll_pixels = infoPtr->scrollX - scrollX; - - for (item = infoPtr->root->firstChild; item != NULL; - item = TREEVIEW_GetNextListItem(infoPtr, item)) - { - item->linesOffset += scroll_pixels; - item->stateOffset += scroll_pixels; - item->imageOffset += scroll_pixels; - item->textOffset += scroll_pixels; - } - - ScrollWindow(infoPtr->hwnd, scroll_pixels, 0, NULL, NULL); - infoPtr->scrollX = scrollX; - UpdateWindow(infoPtr->hwnd); - } - - if (nScrollCode != SB_THUMBTRACK) - SetScrollPos(infoPtr->hwnd, SB_HORZ, scrollX, TRUE); - - return 0; -} - -static LRESULT -TREEVIEW_MouseWheel(TREEVIEW_INFO *infoPtr, WPARAM wParam) -{ - short gcWheelDelta; - UINT pulScrollLines = 3; - - if (infoPtr->firstVisible == NULL) - return TRUE; - - SystemParametersInfoW(SPI_GETWHEELSCROLLLINES, 0, &pulScrollLines, 0); - - gcWheelDelta = -(short)HIWORD(wParam); - pulScrollLines *= (gcWheelDelta / WHEEL_DELTA); - - if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines) - { - int newDy = infoPtr->firstVisible->visibleOrder + pulScrollLines; - int maxDy = infoPtr->maxVisibleOrder; - - if (newDy > maxDy) - newDy = maxDy; - - if (newDy < 0) - newDy = 0; - - TREEVIEW_VScroll(infoPtr, MAKEWPARAM(SB_THUMBPOSITION, newDy)); - } - return TRUE; -} - -/* Create/Destroy *******************************************************/ - -static LRESULT -TREEVIEW_Create(HWND hwnd, const CREATESTRUCTW *lpcs) -{ - static const WCHAR szDisplayW[] = { 'D','I','S','P','L','A','Y','\0' }; - RECT rcClient; - TREEVIEW_INFO *infoPtr; - LOGFONTW lf; - - TRACE("wnd %p, style %lx\n", hwnd, GetWindowLongW(hwnd, GWL_STYLE)); - - infoPtr = (TREEVIEW_INFO *)Alloc(sizeof(TREEVIEW_INFO)); - - if (infoPtr == NULL) - { - ERR("could not allocate info memory!\n"); - return 0; - } - - SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)infoPtr); - - infoPtr->hwnd = hwnd; - infoPtr->dwStyle = GetWindowLongW(hwnd, GWL_STYLE); - infoPtr->Timer = 0; - infoPtr->uNumItems = 0; - infoPtr->cdmode = 0; - infoPtr->uScrollTime = 300; /* milliseconds */ - infoPtr->bRedraw = TRUE; - - GetClientRect(hwnd, &rcClient); - - /* No scroll bars yet. */ - infoPtr->clientWidth = rcClient.right; - infoPtr->clientHeight = rcClient.bottom; - infoPtr->uInternalStatus = 0; - - infoPtr->treeWidth = 0; - infoPtr->treeHeight = 0; - - infoPtr->uIndent = MINIMUM_INDENT; - infoPtr->selectedItem = 0; - infoPtr->focusedItem = 0; - infoPtr->hotItem = 0; - infoPtr->firstVisible = 0; - infoPtr->maxVisibleOrder = 0; - infoPtr->dropItem = 0; - infoPtr->insertMarkItem = 0; - infoPtr->insertBeforeorAfter = 0; - /* dragList */ - - infoPtr->scrollX = 0; - - infoPtr->clrBk = GetSysColor(COLOR_WINDOW); - infoPtr->clrText = -1; /* use system color */ - infoPtr->clrLine = RGB(128, 128, 128); - infoPtr->clrInsertMark = GetSysColor(COLOR_BTNTEXT); - - /* hwndToolTip */ - - infoPtr->hwndEdit = 0; - infoPtr->wpEditOrig = NULL; - infoPtr->bIgnoreEditKillFocus = FALSE; - infoPtr->bLabelChanged = FALSE; - - infoPtr->himlNormal = NULL; - infoPtr->himlState = NULL; - infoPtr->normalImageWidth = 0; - infoPtr->normalImageHeight = 0; - infoPtr->stateImageWidth = 0; - infoPtr->stateImageHeight = 0; - - infoPtr->items = DPA_Create(16); - - SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0); - infoPtr->hFont = infoPtr->hDefaultFont = CreateFontIndirectW(&lf); - infoPtr->hBoldFont = TREEVIEW_CreateBoldFont(infoPtr->hFont); - infoPtr->hUnderlineFont = TREEVIEW_CreateUnderlineFont(infoPtr->hFont); - infoPtr->hcurHand = LoadCursorW(NULL, (LPWSTR)IDC_HAND); - - infoPtr->uItemHeight = TREEVIEW_NaturalHeight(infoPtr); - - infoPtr->root = TREEVIEW_AllocateItem(infoPtr); - infoPtr->root->state = TVIS_EXPANDED; - infoPtr->root->iLevel = -1; - infoPtr->root->visibleOrder = -1; - - infoPtr->hwndNotify = lpcs->hwndParent; -#if 0 - infoPtr->bTransparent = ( GetWindowLongW( hwnd, GWL_STYLE) & TBSTYLE_FLAT); -#endif - - infoPtr->hwndToolTip = 0; - - infoPtr->bNtfUnicode = IsWindowUnicode (hwnd); - - /* Determine what type of notify should be issued */ - /* sets infoPtr->bNtfUnicode */ - TREEVIEW_NotifyFormat(infoPtr, infoPtr->hwndNotify, NF_REQUERY); - - if (!(infoPtr->dwStyle & TVS_NOTOOLTIPS)) - infoPtr->hwndToolTip = COMCTL32_CreateToolTip(hwnd); - - if (infoPtr->dwStyle & TVS_CHECKBOXES) - { - RECT rc; - HBITMAP hbm, hbmOld; - HDC hdc,hdcScreen; - int nIndex; - - infoPtr->himlState = - ImageList_Create(16, 16, ILC_COLOR | ILC_MASK, 3, 0); - - hdcScreen = CreateDCW(szDisplayW, NULL, NULL, NULL); - - /* Create a coloured bitmap compatible with the screen depth - because checkboxes are not black&white */ - hdc = CreateCompatibleDC(hdcScreen); - hbm = CreateCompatibleBitmap(hdcScreen, 48, 16); - hbmOld = SelectObject(hdc, hbm); - - rc.left = 0; rc.top = 0; - rc.right = 48; rc.bottom = 16; - FillRect(hdc, &rc, (HBRUSH)(COLOR_WINDOW+1)); - - rc.left = 18; rc.top = 2; - rc.right = 30; rc.bottom = 14; - DrawFrameControl(hdc, &rc, DFC_BUTTON, - DFCS_BUTTONCHECK|DFCS_FLAT); - - rc.left = 34; rc.right = 46; - DrawFrameControl(hdc, &rc, DFC_BUTTON, - DFCS_BUTTONCHECK|DFCS_FLAT|DFCS_CHECKED); - - SelectObject(hdc, hbmOld); - nIndex = ImageList_AddMasked(infoPtr->himlState, hbm, - GetSysColor(COLOR_WINDOW)); - TRACE("checkbox index %d\n", nIndex); - - DeleteObject(hbm); - DeleteDC(hdc); - DeleteDC(hdcScreen); - - infoPtr->stateImageWidth = 16; - infoPtr->stateImageHeight = 16; - } - - /* Make sure actual scrollbar state is consistent with uInternalStatus */ - ShowScrollBar(hwnd, SB_VERT, FALSE); - ShowScrollBar(hwnd, SB_HORZ, FALSE); - - return 0; -} - - -static LRESULT -TREEVIEW_Destroy(TREEVIEW_INFO *infoPtr) -{ - TRACE("\n"); - - TREEVIEW_RemoveTree(infoPtr); - - /* tool tip is automatically destroyed: we are its owner */ - - /* Restore original wndproc */ - if (infoPtr->hwndEdit) - SetWindowLongPtrW(infoPtr->hwndEdit, GWLP_WNDPROC, - (DWORD_PTR)infoPtr->wpEditOrig); - - /* Deassociate treeview from the window before doing anything drastic. */ - SetWindowLongPtrW(infoPtr->hwnd, 0, (DWORD_PTR)NULL); - - DeleteObject(infoPtr->hDefaultFont); - DeleteObject(infoPtr->hBoldFont); - DeleteObject(infoPtr->hUnderlineFont); - Free(infoPtr); - - return 0; -} - -/* Miscellaneous Messages ***********************************************/ - -static LRESULT -TREEVIEW_ScrollKeyDown(TREEVIEW_INFO *infoPtr, WPARAM key) -{ - static const struct - { - unsigned char code; - } - scroll[] = - { -#define SCROLL_ENTRY(dir, code) { ((dir) << 7) | (code) } - SCROLL_ENTRY(SB_VERT, SB_PAGEUP), /* VK_PRIOR */ - SCROLL_ENTRY(SB_VERT, SB_PAGEDOWN), /* VK_NEXT */ - SCROLL_ENTRY(SB_VERT, SB_BOTTOM), /* VK_END */ - SCROLL_ENTRY(SB_VERT, SB_TOP), /* VK_HOME */ - SCROLL_ENTRY(SB_HORZ, SB_LINEUP), /* VK_LEFT */ - SCROLL_ENTRY(SB_VERT, SB_LINEUP), /* VK_UP */ - SCROLL_ENTRY(SB_HORZ, SB_LINEDOWN), /* VK_RIGHT */ - SCROLL_ENTRY(SB_VERT, SB_LINEDOWN) /* VK_DOWN */ -#undef SCROLL_ENTRY - }; - - if (key >= VK_PRIOR && key <= VK_DOWN) - { - unsigned char code = scroll[key - VK_PRIOR].code; - - (((code & (1 << 7)) == (SB_HORZ << 7)) - ? TREEVIEW_HScroll - : TREEVIEW_VScroll)(infoPtr, code & 0x7F); - } - - return 0; -} - -/************************************************************************ - * TREEVIEW_KeyDown - * - * VK_UP Move selection to the previous non-hidden item. - * VK_DOWN Move selection to the next non-hidden item. - * VK_HOME Move selection to the first item. - * VK_END Move selection to the last item. - * VK_LEFT If expanded then collapse, otherwise move to parent. - * VK_RIGHT If collapsed then expand, otherwise move to first child. - * VK_ADD Expand. - * VK_SUBTRACT Collapse. - * VK_MULTIPLY Expand all. - * VK_PRIOR Move up GetVisibleCount items. - * VK_NEXT Move down GetVisibleCount items. - * VK_BACK Move to parent. - * CTRL-Left,Right,Up,Down,PgUp,PgDown,Home,End: Scroll without changing selection - */ -static LRESULT -TREEVIEW_KeyDown(TREEVIEW_INFO *infoPtr, WPARAM wParam) -{ - /* If it is non-NULL and different, it will be selected and visible. */ - TREEVIEW_ITEM *newSelection = NULL; - - TREEVIEW_ITEM *prevItem = infoPtr->selectedItem; - - TRACE("%x\n", wParam); - - if (prevItem == NULL) - return FALSE; - - if (GetAsyncKeyState(VK_CONTROL) & 0x8000) - return TREEVIEW_ScrollKeyDown(infoPtr, wParam); - - switch (wParam) - { - case VK_UP: - newSelection = TREEVIEW_GetPrevListItem(infoPtr, prevItem); - if (!newSelection) - newSelection = infoPtr->root->firstChild; - break; - - case VK_DOWN: - newSelection = TREEVIEW_GetNextListItem(infoPtr, prevItem); - break; - - case VK_HOME: - newSelection = infoPtr->root->firstChild; - break; - - case VK_END: - newSelection = TREEVIEW_GetLastListItem(infoPtr, infoPtr->root); - break; - - case VK_LEFT: - if (prevItem->state & TVIS_EXPANDED) - { - TREEVIEW_Collapse(infoPtr, prevItem, FALSE, TRUE); - } - else if (prevItem->parent != infoPtr->root) - { - newSelection = prevItem->parent; - } - break; - - case VK_RIGHT: - if (TREEVIEW_HasChildren(infoPtr, prevItem)) - { - if (!(prevItem->state & TVIS_EXPANDED)) - TREEVIEW_Expand(infoPtr, prevItem, FALSE, TRUE); - else - { - newSelection = prevItem->firstChild; - } - } - - break; - - case VK_MULTIPLY: - TREEVIEW_ExpandAll(infoPtr, prevItem); - break; - - case VK_ADD: - if (!(prevItem->state & TVIS_EXPANDED)) - TREEVIEW_Expand(infoPtr, prevItem, FALSE, TRUE); - break; - - case VK_SUBTRACT: - if (prevItem->state & TVIS_EXPANDED) - TREEVIEW_Collapse(infoPtr, prevItem, FALSE, TRUE); - break; - - case VK_PRIOR: - newSelection - = TREEVIEW_GetListItem(infoPtr, prevItem, - -TREEVIEW_GetVisibleCount(infoPtr)); - break; - - case VK_NEXT: - newSelection - = TREEVIEW_GetListItem(infoPtr, prevItem, - TREEVIEW_GetVisibleCount(infoPtr)); - break; - - case VK_BACK: - newSelection = prevItem->parent; - if (newSelection == infoPtr->root) - newSelection = NULL; - break; - - case VK_SPACE: - if (infoPtr->dwStyle & TVS_CHECKBOXES) - TREEVIEW_ToggleItemState(infoPtr, prevItem); - break; - } - - if (newSelection && newSelection != prevItem) - { - if (TREEVIEW_DoSelectItem(infoPtr, TVGN_CARET, newSelection, - TVC_BYKEYBOARD)) - { - TREEVIEW_EnsureVisible(infoPtr, newSelection, FALSE); - } - } - - return FALSE; -} - -static LRESULT -TREEVIEW_MouseLeave (TREEVIEW_INFO * infoPtr) -{ - if (infoPtr->hotItem) - { - /* remove hot effect from item */ - InvalidateRect(infoPtr->hwnd, &infoPtr->hotItem->rect, TRUE); - infoPtr->hotItem = NULL; - } - return 0; -} - -static LRESULT -TREEVIEW_MouseMove (TREEVIEW_INFO * infoPtr, WPARAM wParam, LPARAM lParam) -{ - POINT pt; - TRACKMOUSEEVENT trackinfo; - TREEVIEW_ITEM * item; - - /* fill in the TRACKMOUSEEVENT struct */ - trackinfo.cbSize = sizeof(TRACKMOUSEEVENT); - trackinfo.dwFlags = TME_QUERY; - trackinfo.hwndTrack = infoPtr->hwnd; - trackinfo.dwHoverTime = HOVER_DEFAULT; - - /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */ - _TrackMouseEvent(&trackinfo); - - /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */ - if(!(trackinfo.dwFlags & TME_LEAVE)) - { - trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */ - - /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */ - /* and can properly deactivate the hot item */ - _TrackMouseEvent(&trackinfo); - } - - pt.x = (INT)LOWORD(lParam); - pt.y = (INT)HIWORD(lParam); - - item = TREEVIEW_HitTestPoint(infoPtr, pt); - - if (item != infoPtr->hotItem) - { - /* redraw old hot item */ - if (infoPtr->hotItem) - InvalidateRect(infoPtr->hwnd, &infoPtr->hotItem->rect, TRUE); - infoPtr->hotItem = item; - /* redraw new hot item */ - if (infoPtr->hotItem) - InvalidateRect(infoPtr->hwnd, &infoPtr->hotItem->rect, TRUE); - } - - return 0; -} - -static LRESULT -TREEVIEW_Notify(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - LPNMHDR lpnmh = (LPNMHDR)lParam; - - if (lpnmh->code == PGN_CALCSIZE) { - LPNMPGCALCSIZE lppgc = (LPNMPGCALCSIZE)lParam; - - if (lppgc->dwFlag == PGF_CALCWIDTH) { - lppgc->iWidth = infoPtr->treeWidth; - TRACE("got PGN_CALCSIZE, returning horz size = %ld, client=%ld\n", - infoPtr->treeWidth, infoPtr->clientWidth); - } - else { - lppgc->iHeight = infoPtr->treeHeight; - TRACE("got PGN_CALCSIZE, returning vert size = %ld, client=%ld\n", - infoPtr->treeHeight, infoPtr->clientHeight); - } - return 0; - } - return DefWindowProcW(infoPtr->hwnd, WM_NOTIFY, wParam, lParam); -} - -static INT TREEVIEW_NotifyFormat (TREEVIEW_INFO *infoPtr, HWND hwndFrom, UINT nCommand) -{ - INT format; - - TRACE("(hwndFrom=%p, nCommand=%d)\n", hwndFrom, nCommand); - - if (nCommand != NF_REQUERY) return 0; - - format = SendMessageW(hwndFrom, WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwnd, NF_QUERY); - TRACE("format=%d\n", format); - - if (format != NFR_ANSI && format != NFR_UNICODE) return 0; - - infoPtr->bNtfUnicode = (format == NFR_UNICODE); - - return format; -} - -static LRESULT -TREEVIEW_Size(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - if (wParam == SIZE_RESTORED) - { - infoPtr->clientWidth = (short)LOWORD(lParam); - infoPtr->clientHeight = (short)HIWORD(lParam); - - TREEVIEW_RecalculateVisibleOrder(infoPtr, NULL); - TREEVIEW_SetFirstVisible(infoPtr, infoPtr->firstVisible, TRUE); - TREEVIEW_UpdateScrollBars(infoPtr); - } - else - { - FIXME("WM_SIZE flag %x %lx not handled\n", wParam, lParam); - } - - TREEVIEW_Invalidate(infoPtr, NULL); - return 0; -} - -static LRESULT -TREEVIEW_StyleChanged(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - TRACE("(%x %lx)\n", wParam, lParam); - - if (wParam == GWL_STYLE) - { - DWORD dwNewStyle = ((LPSTYLESTRUCT)lParam)->styleNew; - - /* we have to take special care about tooltips */ - if ((infoPtr->dwStyle ^ dwNewStyle) & TVS_NOTOOLTIPS) - { - if (infoPtr->dwStyle & TVS_NOTOOLTIPS) - { - infoPtr->hwndToolTip = COMCTL32_CreateToolTip(infoPtr->hwnd); - TRACE("\n"); - } - else - { - DestroyWindow(infoPtr->hwndToolTip); - infoPtr->hwndToolTip = 0; - } - } - - infoPtr->dwStyle = dwNewStyle; - } - - TREEVIEW_UpdateSubTree(infoPtr, infoPtr->root); - TREEVIEW_UpdateScrollBars(infoPtr); - TREEVIEW_Invalidate(infoPtr, NULL); - - return 0; -} - -static LRESULT -TREEVIEW_SetCursor(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) -{ - POINT pt; - TREEVIEW_ITEM * item; - - GetCursorPos(&pt); - ScreenToClient(infoPtr->hwnd, &pt); - - item = TREEVIEW_HitTestPoint(infoPtr, pt); - - /* FIXME: send NM_SETCURSOR */ - - if (item && (infoPtr->dwStyle & TVS_TRACKSELECT)) - { - SetCursor(infoPtr->hcurHand); - return 0; - } - else - return DefWindowProcW(infoPtr->hwnd, WM_SETCURSOR, wParam, lParam); -} - -static LRESULT -TREEVIEW_SetFocus(TREEVIEW_INFO *infoPtr) -{ - TRACE("\n"); - - if (!infoPtr->selectedItem) - { - TREEVIEW_DoSelectItem(infoPtr, TVGN_CARET, infoPtr->firstVisible, - TVC_UNKNOWN); - } - - TREEVIEW_Invalidate(infoPtr, infoPtr->selectedItem); - TREEVIEW_SendSimpleNotify(infoPtr, NM_SETFOCUS); - return 0; -} - -static LRESULT -TREEVIEW_KillFocus(TREEVIEW_INFO *infoPtr) -{ - TRACE("\n"); - - TREEVIEW_Invalidate(infoPtr, infoPtr->selectedItem); - UpdateWindow(infoPtr->hwnd); - TREEVIEW_SendSimpleNotify(infoPtr, NM_KILLFOCUS); - return 0; -} - - -static LRESULT WINAPI -TREEVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); - - TRACE("hwnd %p msg %04x wp=%08x lp=%08lx\n", hwnd, uMsg, wParam, lParam); - - if (infoPtr) TREEVIEW_VerifyTree(infoPtr); - else - { - if (uMsg == WM_CREATE) - TREEVIEW_Create(hwnd, (LPCREATESTRUCTW)lParam); - else - goto def; - } - - switch (uMsg) - { - case TVM_CREATEDRAGIMAGE: - return TREEVIEW_CreateDragImage(infoPtr, wParam, lParam); - - case TVM_DELETEITEM: - return TREEVIEW_DeleteItem(infoPtr, (HTREEITEM)lParam); - - case TVM_EDITLABELA: - return (LRESULT)TREEVIEW_EditLabel(infoPtr, (HTREEITEM)lParam); - - case TVM_EDITLABELW: - return (LRESULT)TREEVIEW_EditLabel(infoPtr, (HTREEITEM)lParam); - - case TVM_ENDEDITLABELNOW: - return TREEVIEW_EndEditLabelNow(infoPtr, (BOOL)wParam); - - case TVM_ENSUREVISIBLE: - return TREEVIEW_EnsureVisible(infoPtr, (HTREEITEM)lParam, TRUE); - - case TVM_EXPAND: - return TREEVIEW_ExpandMsg(infoPtr, (UINT)wParam, (HTREEITEM)lParam); - - case TVM_GETBKCOLOR: - return TREEVIEW_GetBkColor(infoPtr); - - case TVM_GETCOUNT: - return TREEVIEW_GetCount(infoPtr); - - case TVM_GETEDITCONTROL: - return TREEVIEW_GetEditControl(infoPtr); - - case TVM_GETIMAGELIST: - return TREEVIEW_GetImageList(infoPtr, wParam); - - case TVM_GETINDENT: - return TREEVIEW_GetIndent(infoPtr); - - case TVM_GETINSERTMARKCOLOR: - return TREEVIEW_GetInsertMarkColor(infoPtr); - - case TVM_GETISEARCHSTRINGA: - FIXME("Unimplemented msg TVM_GETISEARCHSTRINGA\n"); - return 0; - - case TVM_GETISEARCHSTRINGW: - FIXME("Unimplemented msg TVM_GETISEARCHSTRINGW\n"); - return 0; - - case TVM_GETITEMA: - return TREEVIEW_GetItemT(infoPtr, (LPTVITEMEXW)lParam, FALSE); - - case TVM_GETITEMW: - return TREEVIEW_GetItemT(infoPtr, (LPTVITEMEXW)lParam, TRUE); - - case TVM_GETITEMHEIGHT: - return TREEVIEW_GetItemHeight(infoPtr); - - case TVM_GETITEMRECT: - return TREEVIEW_GetItemRect(infoPtr, (BOOL)wParam, (LPRECT)lParam); - - case TVM_GETITEMSTATE: - return TREEVIEW_GetItemState(infoPtr, (HTREEITEM)wParam, (UINT)lParam); - - case TVM_GETLINECOLOR: - return TREEVIEW_GetLineColor(infoPtr); - - case TVM_GETNEXTITEM: - return TREEVIEW_GetNextItem(infoPtr, (UINT)wParam, (HTREEITEM)lParam); - - case TVM_GETSCROLLTIME: - return TREEVIEW_GetScrollTime(infoPtr); - - case TVM_GETTEXTCOLOR: - return TREEVIEW_GetTextColor(infoPtr); - - case TVM_GETTOOLTIPS: - return TREEVIEW_GetToolTips(infoPtr); - - case TVM_GETUNICODEFORMAT: - return TREEVIEW_GetUnicodeFormat(infoPtr); - - case TVM_GETVISIBLECOUNT: - return TREEVIEW_GetVisibleCount(infoPtr); - - case TVM_HITTEST: - return TREEVIEW_HitTest(infoPtr, (LPTVHITTESTINFO)lParam); - - case TVM_INSERTITEMA: - return TREEVIEW_InsertItemT(infoPtr, (LPTVINSERTSTRUCTW)lParam, FALSE); - - case TVM_INSERTITEMW: - return TREEVIEW_InsertItemT(infoPtr, (LPTVINSERTSTRUCTW)lParam, TRUE); - - case TVM_SELECTITEM: - return TREEVIEW_SelectItem(infoPtr, (INT)wParam, (HTREEITEM)lParam); - - case TVM_SETBKCOLOR: - return TREEVIEW_SetBkColor(infoPtr, (COLORREF)lParam); - - case TVM_SETIMAGELIST: - return TREEVIEW_SetImageList(infoPtr, wParam, (HIMAGELIST)lParam); - - case TVM_SETINDENT: - return TREEVIEW_SetIndent(infoPtr, (UINT)wParam); - - case TVM_SETINSERTMARK: - return TREEVIEW_SetInsertMark(infoPtr, (BOOL)wParam, (HTREEITEM)lParam); - - case TVM_SETINSERTMARKCOLOR: - return TREEVIEW_SetInsertMarkColor(infoPtr, (COLORREF)lParam); - - case TVM_SETITEMA: - return TREEVIEW_SetItemT(infoPtr, (LPTVITEMEXW)lParam, FALSE); - - case TVM_SETITEMW: - return TREEVIEW_SetItemT(infoPtr, (LPTVITEMEXW)lParam, TRUE); - - case TVM_SETLINECOLOR: - return TREEVIEW_SetLineColor(infoPtr, (COLORREF)lParam); - - case TVM_SETITEMHEIGHT: - return TREEVIEW_SetItemHeight(infoPtr, (INT)(SHORT)wParam); - - case TVM_SETSCROLLTIME: - return TREEVIEW_SetScrollTime(infoPtr, (UINT)wParam); - - case TVM_SETTEXTCOLOR: - return TREEVIEW_SetTextColor(infoPtr, (COLORREF)lParam); - - case TVM_SETTOOLTIPS: - return TREEVIEW_SetToolTips(infoPtr, (HWND)wParam); - - case TVM_SETUNICODEFORMAT: - return TREEVIEW_SetUnicodeFormat(infoPtr, (BOOL)wParam); - - case TVM_SORTCHILDREN: - return TREEVIEW_SortChildren(infoPtr, wParam, lParam); - - case TVM_SORTCHILDRENCB: - return TREEVIEW_SortChildrenCB(infoPtr, wParam, (LPTVSORTCB)lParam); - - case WM_CHAR: - return TREEVIEW_ProcessLetterKeys( hwnd, wParam, lParam ); - - case WM_COMMAND: - return TREEVIEW_Command(infoPtr, wParam, lParam); - - case WM_DESTROY: - return TREEVIEW_Destroy(infoPtr); - - /* WM_ENABLE */ - - case WM_ERASEBKGND: - return TREEVIEW_EraseBackground(infoPtr, (HDC)wParam); - - case WM_GETDLGCODE: - return DLGC_WANTARROWS | DLGC_WANTCHARS; - - case WM_GETFONT: - return TREEVIEW_GetFont(infoPtr); - - case WM_HSCROLL: - return TREEVIEW_HScroll(infoPtr, wParam); - - case WM_KEYDOWN: - return TREEVIEW_KeyDown(infoPtr, wParam); - - case WM_KILLFOCUS: - return TREEVIEW_KillFocus(infoPtr); - - case WM_LBUTTONDBLCLK: - return TREEVIEW_LButtonDoubleClick(infoPtr, lParam); - - case WM_LBUTTONDOWN: - return TREEVIEW_LButtonDown(infoPtr, lParam); - - /* WM_MBUTTONDOWN */ - - case WM_MOUSELEAVE: - return TREEVIEW_MouseLeave(infoPtr); - - case WM_MOUSEMOVE: - if (infoPtr->dwStyle & TVS_TRACKSELECT) - return TREEVIEW_MouseMove(infoPtr, wParam, lParam); - else - return 0; - - case WM_NOTIFY: - return TREEVIEW_Notify(infoPtr, wParam, lParam); - - case WM_NOTIFYFORMAT: - return TREEVIEW_NotifyFormat(infoPtr, (HWND)wParam, (UINT)lParam); - - case WM_PAINT: - return TREEVIEW_Paint(infoPtr, wParam); - - /* WM_PRINTCLIENT */ - - case WM_RBUTTONDOWN: - return TREEVIEW_RButtonDown(infoPtr, lParam); - - case WM_SETCURSOR: - return TREEVIEW_SetCursor(infoPtr, wParam, lParam); - - case WM_SETFOCUS: - return TREEVIEW_SetFocus(infoPtr); - - case WM_SETFONT: - return TREEVIEW_SetFont(infoPtr, (HFONT)wParam, (BOOL)lParam); - - case WM_SETREDRAW: - return TREEVIEW_SetRedraw(infoPtr, wParam, lParam); - - case WM_SIZE: - return TREEVIEW_Size(infoPtr, wParam, lParam); - - case WM_STYLECHANGED: - return TREEVIEW_StyleChanged(infoPtr, wParam, lParam); - - /* WM_SYSCOLORCHANGE */ - - /* WM_SYSKEYDOWN */ - - case WM_TIMER: - return TREEVIEW_HandleTimer(infoPtr, wParam); - - case WM_VSCROLL: - return TREEVIEW_VScroll(infoPtr, wParam); - - /* WM_WININICHANGE */ - - case WM_MOUSEWHEEL: - if (wParam & (MK_SHIFT | MK_CONTROL)) - goto def; - return TREEVIEW_MouseWheel(infoPtr, wParam); - - case WM_DRAWITEM: - TRACE("drawItem\n"); - goto def; - - default: - /* This mostly catches MFC and Delphi messages. :( */ - if ((uMsg >= WM_USER) && (uMsg < WM_APP)) - TRACE("Unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam); -def: - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - } -} - - -/* Class Registration ***************************************************/ - -VOID -TREEVIEW_Register(void) -{ - WNDCLASSW wndClass; - - TRACE("\n"); - - ZeroMemory(&wndClass, sizeof(WNDCLASSW)); - wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS; - wndClass.lpfnWndProc = TREEVIEW_WindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(TREEVIEW_INFO *); - - wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW); - wndClass.hbrBackground = 0; - wndClass.lpszClassName = WC_TREEVIEWW; - - RegisterClassW(&wndClass); -} - - -VOID -TREEVIEW_Unregister(void) -{ - UnregisterClassW(WC_TREEVIEWW, NULL); -} - - -/* Tree Verification ****************************************************/ - -#ifdef NDEBUG -static inline void -TREEVIEW_VerifyChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item); - -static inline void TREEVIEW_VerifyItemCommon(TREEVIEW_INFO *infoPtr, - TREEVIEW_ITEM *item) -{ - assert(infoPtr != NULL); - assert(item != NULL); - - /* both NULL, or both non-null */ - assert((item->firstChild == NULL) == (item->lastChild == NULL)); - - assert(item->firstChild != item); - assert(item->lastChild != item); - - if (item->firstChild) - { - assert(item->firstChild->parent == item); - assert(item->firstChild->prevSibling == NULL); - } - - if (item->lastChild) - { - assert(item->lastChild->parent == item); - assert(item->lastChild->nextSibling == NULL); - } - - assert(item->nextSibling != item); - if (item->nextSibling) - { - assert(item->nextSibling->parent == item->parent); - assert(item->nextSibling->prevSibling == item); - } - - assert(item->prevSibling != item); - if (item->prevSibling) - { - assert(item->prevSibling->parent == item->parent); - assert(item->prevSibling->nextSibling == item); - } -} - -static inline void -TREEVIEW_VerifyItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) -{ - assert(item != NULL); - - assert(item->parent != NULL); - assert(item->parent != item); - assert(item->iLevel == item->parent->iLevel + 1); - - assert(DPA_GetPtrIndex(infoPtr->items, item) != -1); - - TREEVIEW_VerifyItemCommon(infoPtr, item); - - TREEVIEW_VerifyChildren(infoPtr, item); -} - -static inline void -TREEVIEW_VerifyChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) -{ - TREEVIEW_ITEM *child; - assert(item != NULL); - - for (child = item->firstChild; child != NULL; child = child->nextSibling) - TREEVIEW_VerifyItem(infoPtr, child); -} - -static inline void -TREEVIEW_VerifyRoot(TREEVIEW_INFO *infoPtr) -{ - TREEVIEW_ITEM *root = infoPtr->root; - - assert(root != NULL); - assert(root->iLevel == -1); - assert(root->parent == NULL); - assert(root->prevSibling == NULL); - - TREEVIEW_VerifyItemCommon(infoPtr, root); - - TREEVIEW_VerifyChildren(infoPtr, root); -} - -static void -TREEVIEW_VerifyTree(TREEVIEW_INFO *infoPtr) -{ - assert(infoPtr != NULL); - - TREEVIEW_VerifyRoot(infoPtr); -} -#endif +/* Treeview control + * + * Copyright 1998 Eric Kohl + * Copyright 1998,1999 Alex Priem + * Copyright 1999 Sylvain St-Germain + * Copyright 2002 CodeWeavers, Aric Stewart + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES + * + * Note that TREEVIEW_INFO * and HTREEITEM are the same thing. + * + * Note2: All items always! have valid (allocated) pszText field. + * If item's text == LPSTR_TEXTCALLBACKA we allocate buffer + * of size TEXT_CALLBACK_SIZE in DoSetItem. + * We use callbackMask to keep track of fields to be updated. + * + * TODO: + * missing notifications: NM_SETCURSOR, TVN_GETINFOTIP, TVN_KEYDOWN, + * TVN_SETDISPINFO, TVN_SINGLEEXPAND + * + * missing styles: TVS_FULLROWSELECT, TVS_INFOTIP, TVS_RTLREADING, + * + * missing item styles: TVIS_CUT, TVIS_EXPANDPARTIAL + * + * Make the insertion mark look right. + * Scroll (instead of repaint) as much as possible. + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include +#include +#include +#include + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "comctl32.h" +#include "wine/unicode.h" +#include "wine/debug.h" + +/* internal structures */ + +typedef struct _TREEITEM /* HTREEITEM is a _TREEINFO *. */ +{ + UINT callbackMask; + UINT state; + UINT stateMask; + LPWSTR pszText; + int cchTextMax; + int iImage; + int iSelectedImage; + int cChildren; + LPARAM lParam; + int iIntegral; /* item height multiplier (1 is normal) */ + int iLevel; /* indentation level:0=root level */ + HTREEITEM parent; /* handle to parent or 0 if at root */ + HTREEITEM firstChild; /* handle to first child or 0 if no child */ + HTREEITEM lastChild; + HTREEITEM prevSibling; /* handle to prev item in list, 0 if first */ + HTREEITEM nextSibling; /* handle to next item in list, 0 if last */ + RECT rect; + LONG linesOffset; + LONG stateOffset; + LONG imageOffset; + LONG textOffset; + LONG textWidth; /* horizontal text extent for pszText */ + LONG visibleOrder; /* visible ordering, 0 is first visible item */ +} TREEVIEW_ITEM; + + +typedef struct tagTREEVIEW_INFO +{ + HWND hwnd; + HWND hwndNotify; /* Owner window to send notifications to */ + DWORD dwStyle; + HTREEITEM root; + UINT uInternalStatus; + INT Timer; + UINT uNumItems; /* number of valid TREEVIEW_ITEMs */ + INT cdmode; /* last custom draw setting */ + UINT uScrollTime; /* max. time for scrolling in milliseconds */ + BOOL bRedraw; /* if FALSE we validate but don't redraw in TREEVIEW_Paint() */ + + UINT uItemHeight; /* item height */ + BOOL bHeightSet; + + LONG clientWidth; /* width of control window */ + LONG clientHeight; /* height of control window */ + + LONG treeWidth; /* width of visible tree items */ + LONG treeHeight; /* height of visible tree items */ + + UINT uIndent; /* indentation in pixels */ + HTREEITEM selectedItem; /* handle to selected item or 0 if none */ + HTREEITEM hotItem; /* handle currently under cursor, 0 if none */ + HTREEITEM focusedItem; /* item that was under the cursor when WM_LBUTTONDOWN was received */ + + HTREEITEM firstVisible; /* handle to first visible item */ + LONG maxVisibleOrder; + HTREEITEM dropItem; /* handle to item selected by drag cursor */ + HTREEITEM insertMarkItem; /* item after which insertion mark is placed */ + BOOL insertBeforeorAfter; /* flag used by TVM_SETINSERTMARK */ + HIMAGELIST dragList; /* Bitmap of dragged item */ + LONG scrollX; + COLORREF clrBk; + COLORREF clrText; + COLORREF clrLine; + COLORREF clrInsertMark; + HFONT hFont; + HFONT hDefaultFont; + HFONT hBoldFont; + HFONT hUnderlineFont; + HCURSOR hcurHand; + HWND hwndToolTip; + + HWND hwndEdit; + WNDPROC wpEditOrig; /* orig window proc for subclassing edit */ + BOOL bIgnoreEditKillFocus; + BOOL bLabelChanged; + + BOOL bNtfUnicode; /* TRUE if should send NOTIFY with W */ + HIMAGELIST himlNormal; + int normalImageHeight; + int normalImageWidth; + HIMAGELIST himlState; + int stateImageHeight; + int stateImageWidth; + HDPA items; + + DWORD lastKeyPressTimestamp; /* Added */ + WPARAM charCode; /* Added */ + INT nSearchParamLength; /* Added */ + WCHAR szSearchParam[ MAX_PATH ]; /* Added */ +} TREEVIEW_INFO; + + +/******** Defines that TREEVIEW_ProcessLetterKeys uses ****************/ +#define KEY_DELAY 450 + +/* bitflags for infoPtr->uInternalStatus */ + +#define TV_HSCROLL 0x01 /* treeview too large to fit in window */ +#define TV_VSCROLL 0x02 /* (horizontal/vertical) */ +#define TV_LDRAG 0x04 /* Lbutton pushed to start drag */ +#define TV_LDRAGGING 0x08 /* Lbutton pushed, mouse moved. */ +#define TV_RDRAG 0x10 /* dito Rbutton */ +#define TV_RDRAGGING 0x20 + +/* bitflags for infoPtr->timer */ + +#define TV_EDIT_TIMER 2 +#define TV_EDIT_TIMER_SET 2 + + +VOID TREEVIEW_Register (VOID); +VOID TREEVIEW_Unregister (VOID); + + +WINE_DEFAULT_DEBUG_CHANNEL(treeview); + + +#define TEXT_CALLBACK_SIZE 260 + +#define TREEVIEW_LEFT_MARGIN 8 + +#define MINIMUM_INDENT 19 + +#define CALLBACK_MASK_ALL (TVIF_TEXT|TVIF_CHILDREN|TVIF_IMAGE|TVIF_SELECTEDIMAGE) + +#define STATEIMAGEINDEX(x) (((x) >> 12) & 0x0f) +#define OVERLAYIMAGEINDEX(x) (((x) >> 8) & 0x0f) +#define ISVISIBLE(x) ((x)->visibleOrder >= 0) + + +typedef VOID (*TREEVIEW_ItemEnumFunc)(TREEVIEW_INFO *, TREEVIEW_ITEM *,LPVOID); + + +static VOID TREEVIEW_Invalidate(TREEVIEW_INFO *, TREEVIEW_ITEM *); + +static LRESULT TREEVIEW_DoSelectItem(TREEVIEW_INFO *, INT, HTREEITEM, INT); +static VOID TREEVIEW_SetFirstVisible(TREEVIEW_INFO *, TREEVIEW_ITEM *, BOOL); +static LRESULT TREEVIEW_EnsureVisible(TREEVIEW_INFO *, HTREEITEM, BOOL); +static LRESULT TREEVIEW_RButtonUp(TREEVIEW_INFO *, LPPOINT); +static LRESULT TREEVIEW_EndEditLabelNow(TREEVIEW_INFO *infoPtr, BOOL bCancel); +static VOID TREEVIEW_UpdateScrollBars(TREEVIEW_INFO *infoPtr); +static LRESULT TREEVIEW_HScroll(TREEVIEW_INFO *, WPARAM); +static INT TREEVIEW_NotifyFormat (TREEVIEW_INFO *infoPtr, HWND wParam, UINT lParam); + + +/* Random Utilities *****************************************************/ + +#ifndef NDEBUG +static inline void +TREEVIEW_VerifyTree(TREEVIEW_INFO *infoPtr) +{ + (void)infoPtr; +} +#else +/* The definition is at the end of the file. */ +static void TREEVIEW_VerifyTree(TREEVIEW_INFO *infoPtr); +#endif + +/* Returns the treeview private data if hwnd is a treeview. + * Otherwise returns an undefined value. */ +static TREEVIEW_INFO * +TREEVIEW_GetInfoPtr(HWND hwnd) +{ + return (TREEVIEW_INFO *)GetWindowLongPtrW(hwnd, 0); +} + +/* Don't call this. Nothing wants an item index. */ +static inline int +TREEVIEW_GetItemIndex(TREEVIEW_INFO *infoPtr, HTREEITEM handle) +{ + assert(infoPtr != NULL); + + return DPA_GetPtrIndex(infoPtr->items, handle); +} + +/* Checks if item has changed and needs to be redrawn */ +static inline BOOL item_changed (TREEVIEW_ITEM *tiOld, TREEVIEW_ITEM *tiNew, LPTVITEMEXW tvChange) +{ + /* Number of children has changed */ + if ((tvChange->mask & TVIF_CHILDREN) && (tiOld->cChildren != tiNew->cChildren)) + return TRUE; + + /* Image has changed and it's not a callback */ + if ((tvChange->mask & TVIF_IMAGE) && (tiOld->iImage != tiNew->iImage) && + tiNew->iImage != I_IMAGECALLBACK) + return TRUE; + + /* Selected image has changed and it's not a callback */ + if ((tvChange->mask & TVIF_SELECTEDIMAGE) && (tiOld->iSelectedImage != tiNew->iSelectedImage) && + tiNew->iSelectedImage != I_IMAGECALLBACK) + return TRUE; + + /* Text has changed and it's not a callback */ + if ((tvChange->mask & TVIF_TEXT) && (tiOld->pszText != tiNew->pszText) && + tiNew->pszText != LPSTR_TEXTCALLBACKW) + return TRUE; + + /* Indent has changed */ + if ((tvChange->mask & TVIF_INTEGRAL) && (tiOld->iIntegral != tiNew->iIntegral)) + return TRUE; + + /* Item state has changed */ + if ((tvChange->mask & TVIF_STATE) && ((tiOld->state ^ tiNew->state) & tvChange->stateMask )) + return TRUE; + + return FALSE; +} + +/*************************************************************************** + * This method checks that handle is an item for this tree. + */ +static BOOL +TREEVIEW_ValidItem(TREEVIEW_INFO *infoPtr, HTREEITEM handle) +{ + if (TREEVIEW_GetItemIndex(infoPtr, handle) == -1) + { + TRACE("invalid item %p\n", handle); + return FALSE; + } + else + return TRUE; +} + +static HFONT +TREEVIEW_CreateBoldFont(HFONT hOrigFont) +{ + LOGFONTW font; + + GetObjectW(hOrigFont, sizeof(font), &font); + font.lfWeight = FW_BOLD; + return CreateFontIndirectW(&font); +} + +static HFONT +TREEVIEW_CreateUnderlineFont(HFONT hOrigFont) +{ + LOGFONTW font; + + GetObjectW(hOrigFont, sizeof(font), &font); + font.lfUnderline = TRUE; + return CreateFontIndirectW(&font); +} + +static inline HFONT +TREEVIEW_FontForItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) +{ + if ((infoPtr->dwStyle & TVS_TRACKSELECT) && (item == infoPtr->hotItem)) + return infoPtr->hUnderlineFont; + if (item->state & TVIS_BOLD) + return infoPtr->hBoldFont; + return infoPtr->hFont; +} + +/* for trace/debugging purposes only */ +static const char * +TREEVIEW_ItemName(TREEVIEW_ITEM *item) +{ + if (item == NULL) return ""; + if (item->pszText == LPSTR_TEXTCALLBACKW) return ""; + if (item->pszText == NULL) return ""; + return debugstr_w(item->pszText); +} + +/* An item is not a child of itself. */ +static BOOL +TREEVIEW_IsChildOf(TREEVIEW_ITEM *parent, TREEVIEW_ITEM *child) +{ + do + { + child = child->parent; + if (child == parent) return TRUE; + } while (child != NULL); + + return FALSE; +} + + +/* Tree Traversal *******************************************************/ + +/*************************************************************************** + * This method returns the last expanded sibling or child child item + * of a tree node + */ +static TREEVIEW_ITEM * +TREEVIEW_GetLastListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem) +{ + if (!wineItem) + return NULL; + + while (wineItem->lastChild) + { + if (wineItem->state & TVIS_EXPANDED) + wineItem = wineItem->lastChild; + else + break; + } + + if (wineItem == infoPtr->root) + return NULL; + + return wineItem; +} + +/*************************************************************************** + * This method returns the previous non-hidden item in the list not + * considering the tree hierarchy. + */ +static TREEVIEW_ITEM * +TREEVIEW_GetPrevListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *tvItem) +{ + if (tvItem->prevSibling) + { + /* This item has a prevSibling, get the last item in the sibling's tree. */ + TREEVIEW_ITEM *upItem = tvItem->prevSibling; + + if ((upItem->state & TVIS_EXPANDED) && upItem->lastChild != NULL) + return TREEVIEW_GetLastListItem(infoPtr, upItem->lastChild); + else + return upItem; + } + else + { + /* this item does not have a prevSibling, get the parent */ + return (tvItem->parent != infoPtr->root) ? tvItem->parent : NULL; + } +} + + +/*************************************************************************** + * This method returns the next physical item in the treeview not + * considering the tree hierarchy. + */ +static TREEVIEW_ITEM * +TREEVIEW_GetNextListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *tvItem) +{ + assert(tvItem != NULL); + + /* + * If this item has children and is expanded, return the first child + */ + if ((tvItem->state & TVIS_EXPANDED) && tvItem->firstChild != NULL) + { + return tvItem->firstChild; + } + + + /* + * try to get the sibling + */ + if (tvItem->nextSibling) + return tvItem->nextSibling; + + /* + * Otherwise, get the parent's sibling. + */ + while (tvItem->parent) + { + tvItem = tvItem->parent; + + if (tvItem->nextSibling) + return tvItem->nextSibling; + } + + return NULL; +} + +/*************************************************************************** + * This method returns the nth item starting at the given item. It returns + * the last item (or first) we we run out of items. + * + * Will scroll backward if count is <0. + * forward if count is >0. + */ +static TREEVIEW_ITEM * +TREEVIEW_GetListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, + LONG count) +{ + TREEVIEW_ITEM *(*next_item)(TREEVIEW_INFO *, TREEVIEW_ITEM *); + TREEVIEW_ITEM *previousItem; + + assert(wineItem != NULL); + + if (count > 0) + { + next_item = TREEVIEW_GetNextListItem; + } + else if (count < 0) + { + count = -count; + next_item = TREEVIEW_GetPrevListItem; + } + else + return wineItem; + + do + { + previousItem = wineItem; + wineItem = next_item(infoPtr, wineItem); + + } while (--count && wineItem != NULL); + + + return wineItem ? wineItem : previousItem; +} + +/* Notifications ************************************************************/ + +static INT get_notifycode(TREEVIEW_INFO *infoPtr, INT code) +{ + if (!infoPtr->bNtfUnicode) { + switch (code) { + case TVN_SELCHANGINGW: return TVN_SELCHANGINGA; + case TVN_SELCHANGEDW: return TVN_SELCHANGEDA; + case TVN_GETDISPINFOW: return TVN_GETDISPINFOA; + case TVN_SETDISPINFOW: return TVN_SETDISPINFOA; + case TVN_ITEMEXPANDINGW: return TVN_ITEMEXPANDINGA; + case TVN_ITEMEXPANDEDW: return TVN_ITEMEXPANDEDA; + case TVN_BEGINDRAGW: return TVN_BEGINDRAGA; + case TVN_BEGINRDRAGW: return TVN_BEGINRDRAGA; + case TVN_DELETEITEMW: return TVN_DELETEITEMA; + case TVN_BEGINLABELEDITW: return TVN_BEGINLABELEDITA; + case TVN_ENDLABELEDITW: return TVN_ENDLABELEDITA; + case TVN_GETINFOTIPW: return TVN_GETINFOTIPA; + } + } + return code; +} + +static LRESULT +TREEVIEW_SendRealNotify(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + TRACE("wParam=%d, lParam=%ld\n", wParam, lParam); + return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, wParam, lParam); +} + +static BOOL +TREEVIEW_SendSimpleNotify(TREEVIEW_INFO *infoPtr, UINT code) +{ + NMHDR nmhdr; + HWND hwnd = infoPtr->hwnd; + + TRACE("%d\n", code); + nmhdr.hwndFrom = hwnd; + nmhdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID); + nmhdr.code = get_notifycode(infoPtr, code); + + return (BOOL)TREEVIEW_SendRealNotify(infoPtr, + (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr); +} + +static VOID +TREEVIEW_TVItemFromItem(TREEVIEW_INFO *infoPtr, UINT mask, TVITEMW *tvItem, TREEVIEW_ITEM *item) +{ + tvItem->mask = mask; + tvItem->hItem = item; + tvItem->state = item->state; + tvItem->stateMask = 0; + tvItem->iImage = item->iImage; + tvItem->iSelectedImage = item->iSelectedImage; + tvItem->cChildren = item->cChildren; + tvItem->lParam = item->lParam; + + if(mask & TVIF_TEXT) + { + if (!infoPtr->bNtfUnicode) + { + tvItem->cchTextMax = WideCharToMultiByte( CP_ACP, 0, item->pszText, -1, NULL, 0, NULL, NULL ); + tvItem->pszText = Alloc (tvItem->cchTextMax); + WideCharToMultiByte( CP_ACP, 0, item->pszText, -1, (LPSTR)tvItem->pszText, tvItem->cchTextMax, 0, 0 ); + } + else + { + tvItem->cchTextMax = item->cchTextMax; + tvItem->pszText = item->pszText; + } + } + else + { + tvItem->cchTextMax = 0; + tvItem->pszText = NULL; + } +} + +static BOOL +TREEVIEW_SendTreeviewNotify(TREEVIEW_INFO *infoPtr, UINT code, UINT action, + UINT mask, HTREEITEM oldItem, HTREEITEM newItem) +{ + HWND hwnd = infoPtr->hwnd; + NMTREEVIEWW nmhdr; + BOOL ret; + + TRACE("code:%d action:%x olditem:%p newitem:%p\n", + code, action, oldItem, newItem); + + ZeroMemory(&nmhdr, sizeof(NMTREEVIEWA)); + + nmhdr.hdr.hwndFrom = hwnd; + nmhdr.hdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID); + nmhdr.hdr.code = get_notifycode(infoPtr, code); + nmhdr.action = action; + + if (oldItem) + TREEVIEW_TVItemFromItem(infoPtr, mask, &nmhdr.itemOld, oldItem); + + if (newItem) + TREEVIEW_TVItemFromItem(infoPtr, mask, &nmhdr.itemNew, newItem); + + nmhdr.ptDrag.x = 0; + nmhdr.ptDrag.y = 0; + + ret = (BOOL)TREEVIEW_SendRealNotify(infoPtr, + (WPARAM)nmhdr.hdr.idFrom, + (LPARAM)&nmhdr); + if (!infoPtr->bNtfUnicode) + { + Free(nmhdr.itemOld.pszText); + Free(nmhdr.itemNew.pszText); + } + return ret; +} + +static BOOL +TREEVIEW_SendTreeviewDnDNotify(TREEVIEW_INFO *infoPtr, UINT code, + HTREEITEM dragItem, POINT pt) +{ + HWND hwnd = infoPtr->hwnd; + NMTREEVIEWW nmhdr; + + TRACE("code:%d dragitem:%p\n", code, dragItem); + + nmhdr.hdr.hwndFrom = hwnd; + nmhdr.hdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID); + nmhdr.hdr.code = get_notifycode(infoPtr, code); + nmhdr.action = 0; + nmhdr.itemNew.mask = TVIF_STATE | TVIF_PARAM | TVIF_HANDLE; + nmhdr.itemNew.hItem = dragItem; + nmhdr.itemNew.state = dragItem->state; + nmhdr.itemNew.lParam = dragItem->lParam; + + nmhdr.ptDrag.x = pt.x; + nmhdr.ptDrag.y = pt.y; + + return (BOOL)TREEVIEW_SendRealNotify(infoPtr, + (WPARAM)nmhdr.hdr.idFrom, + (LPARAM)&nmhdr); +} + + +static BOOL +TREEVIEW_SendCustomDrawNotify(TREEVIEW_INFO *infoPtr, DWORD dwDrawStage, + HDC hdc, RECT rc) +{ + HWND hwnd = infoPtr->hwnd; + NMTVCUSTOMDRAW nmcdhdr; + LPNMCUSTOMDRAW nmcd; + + TRACE("drawstage:%lx hdc:%p\n", dwDrawStage, hdc); + + nmcd = &nmcdhdr.nmcd; + nmcd->hdr.hwndFrom = hwnd; + nmcd->hdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID); + nmcd->hdr.code = NM_CUSTOMDRAW; + nmcd->dwDrawStage = dwDrawStage; + nmcd->hdc = hdc; + nmcd->rc = rc; + nmcd->dwItemSpec = 0; + nmcd->uItemState = 0; + nmcd->lItemlParam = 0; + nmcdhdr.clrText = infoPtr->clrText; + nmcdhdr.clrTextBk = infoPtr->clrBk; + nmcdhdr.iLevel = 0; + + return (BOOL)TREEVIEW_SendRealNotify(infoPtr, + (WPARAM)nmcd->hdr.idFrom, + (LPARAM)&nmcdhdr); +} + + + +/* FIXME: need to find out when the flags in uItemState need to be set */ + +static BOOL +TREEVIEW_SendCustomDrawItemNotify(TREEVIEW_INFO *infoPtr, HDC hdc, + TREEVIEW_ITEM *wineItem, UINT uItemDrawState, + NMTVCUSTOMDRAW *nmcdhdr) +{ + HWND hwnd = infoPtr->hwnd; + LPNMCUSTOMDRAW nmcd; + DWORD dwDrawStage, dwItemSpec; + UINT uItemState; + INT retval; + + dwDrawStage = CDDS_ITEM | uItemDrawState; + dwItemSpec = (DWORD)wineItem; + uItemState = 0; + if (wineItem->state & TVIS_SELECTED) + uItemState |= CDIS_SELECTED; + if (wineItem == infoPtr->selectedItem) + uItemState |= CDIS_FOCUS; + if (wineItem == infoPtr->hotItem) + uItemState |= CDIS_HOT; + + nmcd = &nmcdhdr->nmcd; + nmcd->hdr.hwndFrom = hwnd; + nmcd->hdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID); + nmcd->hdr.code = NM_CUSTOMDRAW; + nmcd->dwDrawStage = dwDrawStage; + nmcd->hdc = hdc; + nmcd->rc = wineItem->rect; + nmcd->dwItemSpec = dwItemSpec; + nmcd->uItemState = uItemState; + nmcd->lItemlParam = wineItem->lParam; + nmcdhdr->iLevel = wineItem->iLevel; + + TRACE("drawstage:%lx hdc:%p item:%lx, itemstate:%x, lItemlParam:%lx\n", + nmcd->dwDrawStage, nmcd->hdc, nmcd->dwItemSpec, + nmcd->uItemState, nmcd->lItemlParam); + + retval = TREEVIEW_SendRealNotify(infoPtr, + (WPARAM)nmcd->hdr.idFrom, + (LPARAM)nmcdhdr); + + return (BOOL)retval; +} + +static BOOL +TREEVIEW_BeginLabelEditNotify(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *editItem) +{ + HWND hwnd = infoPtr->hwnd; + NMTVDISPINFOW tvdi; + BOOL ret; + + tvdi.hdr.hwndFrom = hwnd; + tvdi.hdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID); + tvdi.hdr.code = get_notifycode(infoPtr, TVN_BEGINLABELEDITW); + + TREEVIEW_TVItemFromItem(infoPtr, TVIF_HANDLE | TVIF_STATE | TVIF_PARAM | TVIF_TEXT, + &tvdi.item, editItem); + + ret = (BOOL)TREEVIEW_SendRealNotify(infoPtr, tvdi.hdr.idFrom, (LPARAM)&tvdi); + + if (!infoPtr->bNtfUnicode) + Free(tvdi.item.pszText); + + return ret; +} + +static void +TREEVIEW_UpdateDispInfo(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, + UINT mask) +{ + NMTVDISPINFOW callback; + HWND hwnd = infoPtr->hwnd; + + TRACE("mask %x callbackMask %x\n", mask, wineItem->callbackMask); + mask &= wineItem->callbackMask; + + if (mask == 0) return; + + callback.hdr.hwndFrom = hwnd; + callback.hdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID); + callback.hdr.code = get_notifycode(infoPtr, TVN_GETDISPINFOW); + + /* 'state' always contains valid value, as well as 'lParam'. + * All other parameters are uninitialized. + */ + callback.item.pszText = wineItem->pszText; + callback.item.cchTextMax = wineItem->cchTextMax; + callback.item.mask = mask; + callback.item.hItem = wineItem; + callback.item.state = wineItem->state; + callback.item.lParam = wineItem->lParam; + + /* If text is changed we need to recalculate textWidth */ + if (mask & TVIF_TEXT) + wineItem->textWidth = 0; + + TREEVIEW_SendRealNotify(infoPtr, + (WPARAM)callback.hdr.idFrom, (LPARAM)&callback); + + /* It may have changed due to a call to SetItem. */ + mask &= wineItem->callbackMask; + + if ((mask & TVIF_TEXT) && callback.item.pszText != wineItem->pszText) + { + /* Instead of copying text into our buffer user specified its own */ + if (!infoPtr->bNtfUnicode) { + LPWSTR newText; + int buflen; + int len = MultiByteToWideChar( CP_ACP, 0, + (LPSTR)callback.item.pszText, -1, + NULL, 0); + buflen = max((len)*sizeof(WCHAR), TEXT_CALLBACK_SIZE); + newText = (LPWSTR)ReAlloc(wineItem->pszText, buflen); + + TRACE("returned str %s, len=%d, buflen=%d\n", + debugstr_a((LPSTR)callback.item.pszText), len, buflen); + + if (newText) + { + wineItem->pszText = newText; + MultiByteToWideChar( CP_ACP, 0, + (LPSTR)callback.item.pszText, -1, + wineItem->pszText, buflen); + wineItem->cchTextMax = buflen; + } + /* If ReAlloc fails we have nothing to do, but keep original text */ + } + else { + int len = max(lstrlenW(callback.item.pszText) + 1, + TEXT_CALLBACK_SIZE); + LPWSTR newText = ReAlloc(wineItem->pszText, len); + + TRACE("returned wstr %s, len=%d\n", + debugstr_w(callback.item.pszText), len); + + if (newText) + { + wineItem->pszText = newText; + strcpyW(wineItem->pszText, callback.item.pszText); + wineItem->cchTextMax = len; + } + /* If ReAlloc fails we have nothing to do, but keep original text */ + } + } + else if (mask & TVIF_TEXT) { + /* User put text into our buffer, that is ok unless A string */ + if (!infoPtr->bNtfUnicode) { + LPWSTR newText; + LPWSTR oldText = NULL; + int buflen; + int len = MultiByteToWideChar( CP_ACP, 0, + (LPSTR)callback.item.pszText, -1, + NULL, 0); + buflen = max((len)*sizeof(WCHAR), TEXT_CALLBACK_SIZE); + newText = (LPWSTR)Alloc(buflen); + + TRACE("same buffer str %s, len=%d, buflen=%d\n", + debugstr_a((LPSTR)callback.item.pszText), len, buflen); + + if (newText) + { + oldText = wineItem->pszText; + wineItem->pszText = newText; + MultiByteToWideChar( CP_ACP, 0, + (LPSTR)callback.item.pszText, -1, + wineItem->pszText, buflen); + wineItem->cchTextMax = buflen; + if (oldText) + Free(oldText); + } + } + } + + if (mask & TVIF_IMAGE) + wineItem->iImage = callback.item.iImage; + + if (mask & TVIF_SELECTEDIMAGE) + wineItem->iSelectedImage = callback.item.iSelectedImage; + + if (mask & TVIF_CHILDREN) + wineItem->cChildren = callback.item.cChildren; + + /* These members are now permanently set. */ + if (callback.item.mask & TVIF_DI_SETITEM) + wineItem->callbackMask &= ~callback.item.mask; +} + +/*************************************************************************** + * This function uses cChildren field to decide whether the item has + * children or not. + * Note: if this returns TRUE, the child items may not actually exist, + * they could be virtual. + * + * Just use wineItem->firstChild to check for physical children. + */ +static BOOL +TREEVIEW_HasChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem) +{ + TREEVIEW_UpdateDispInfo(infoPtr, wineItem, TVIF_CHILDREN); + + return wineItem->cChildren > 0; +} + + +/* Item Position ********************************************************/ + +/* Compute linesOffset, stateOffset, imageOffset, textOffset of an item. */ +static VOID +TREEVIEW_ComputeItemInternalMetrics(TREEVIEW_INFO *infoPtr, + TREEVIEW_ITEM *item) +{ + /* Same effect, different optimisation. */ +#if 0 + BOOL lar = ((infoPtr->dwStyle & TVS_LINESATROOT) + && (infoPtr->dwStyle & (TVS_HASLINES|TVS_HASBUTTONS))); +#else + BOOL lar = ((infoPtr->dwStyle + & (TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS)) + > TVS_LINESATROOT); +#endif + + item->linesOffset = infoPtr->uIndent * (item->iLevel + lar - 1) + - infoPtr->scrollX; + item->stateOffset = item->linesOffset + infoPtr->uIndent; + item->imageOffset = item->stateOffset + + (STATEIMAGEINDEX(item->state) ? infoPtr->stateImageWidth : 0); + item->textOffset = item->imageOffset + infoPtr->normalImageWidth; +} + +static VOID +TREEVIEW_ComputeTextWidth(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item, HDC hDC) +{ + HDC hdc; + HFONT hOldFont=0; + SIZE sz; + + /* DRAW's OM docker creates items like this */ + if (item->pszText == NULL) + { + item->textWidth = 0; + return; + } + + if (hDC != 0) + { + hdc = hDC; + } + else + { + hdc = GetDC(infoPtr->hwnd); + hOldFont = SelectObject(hdc, TREEVIEW_FontForItem(infoPtr, item)); + } + + GetTextExtentPoint32W(hdc, item->pszText, strlenW(item->pszText), &sz); + item->textWidth = sz.cx; + + if (hDC == 0) + { + SelectObject(hdc, hOldFont); + ReleaseDC(0, hdc); + } +} + +static VOID +TREEVIEW_ComputeItemRect(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) +{ + item->rect.top = infoPtr->uItemHeight * + (item->visibleOrder - infoPtr->firstVisible->visibleOrder); + + item->rect.bottom = item->rect.top + + infoPtr->uItemHeight * item->iIntegral - 1; + + item->rect.left = 0; + item->rect.right = infoPtr->clientWidth; +} + +/* We know that only items after start need their order updated. */ +static void +TREEVIEW_RecalculateVisibleOrder(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *start) +{ + TREEVIEW_ITEM *item; + int order; + + if (!start) + { + start = infoPtr->root->firstChild; + order = 0; + } + else + order = start->visibleOrder; + + for (item = start; item != NULL; + item = TREEVIEW_GetNextListItem(infoPtr, item)) + { + item->visibleOrder = order; + order += item->iIntegral; + } + + infoPtr->maxVisibleOrder = order; + + for (item = start; item != NULL; + item = TREEVIEW_GetNextListItem(infoPtr, item)) + { + TREEVIEW_ComputeItemRect(infoPtr, item); + } +} + + +/* Update metrics of all items in selected subtree. + * root must be expanded + */ +static VOID +TREEVIEW_UpdateSubTree(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *root) +{ + TREEVIEW_ITEM *sibling; + HDC hdc; + HFONT hOldFont; + + if (!root->firstChild || !(root->state & TVIS_EXPANDED)) + return; + + root->state &= ~TVIS_EXPANDED; + sibling = TREEVIEW_GetNextListItem(infoPtr, root); + root->state |= TVIS_EXPANDED; + + hdc = GetDC(infoPtr->hwnd); + hOldFont = SelectObject(hdc, infoPtr->hFont); + + for (; root != sibling; + root = TREEVIEW_GetNextListItem(infoPtr, root)) + { + TREEVIEW_ComputeItemInternalMetrics(infoPtr, root); + + if (root->callbackMask & TVIF_TEXT) + TREEVIEW_UpdateDispInfo(infoPtr, root, TVIF_TEXT); + + if (root->textWidth == 0) + { + SelectObject(hdc, TREEVIEW_FontForItem(infoPtr, root)); + TREEVIEW_ComputeTextWidth(infoPtr, root, hdc); + } + } + + SelectObject(hdc, hOldFont); + ReleaseDC(infoPtr->hwnd, hdc); +} + +/* Item Allocation **********************************************************/ + +static TREEVIEW_ITEM * +TREEVIEW_AllocateItem(TREEVIEW_INFO *infoPtr) +{ + TREEVIEW_ITEM *newItem = Alloc(sizeof(TREEVIEW_ITEM)); + + if (!newItem) + return NULL; + + newItem->iImage = -1; + newItem->iSelectedImage = -1; + + if (DPA_InsertPtr(infoPtr->items, INT_MAX, newItem) == -1) + { + Free(newItem); + return NULL; + } + + return newItem; +} + +/* Exact opposite of TREEVIEW_AllocateItem. In particular, it does not + * free item->pszText. */ +static void +TREEVIEW_FreeItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) +{ + DPA_DeletePtr(infoPtr->items, DPA_GetPtrIndex(infoPtr->items, item)); + Free(item); + if (infoPtr->selectedItem == item) + infoPtr->selectedItem = NULL; + if (infoPtr->hotItem == item) + infoPtr->hotItem = NULL; + if (infoPtr->focusedItem == item) + infoPtr->focusedItem = NULL; + if (infoPtr->firstVisible == item) + infoPtr->firstVisible = NULL; + if (infoPtr->dropItem == item) + infoPtr->dropItem = NULL; + if (infoPtr->insertMarkItem == item) + infoPtr->insertMarkItem = NULL; +} + + +/* Item Insertion *******************************************************/ + +/*************************************************************************** + * This method inserts newItem before sibling as a child of parent. + * sibling can be NULL, but only if parent has no children. + */ +static void +TREEVIEW_InsertBefore(TREEVIEW_ITEM *newItem, TREEVIEW_ITEM *sibling, + TREEVIEW_ITEM *parent) +{ + assert(newItem != NULL); + assert(parent != NULL); + + if (sibling != NULL) + { + assert(sibling->parent == parent); + + if (sibling->prevSibling != NULL) + sibling->prevSibling->nextSibling = newItem; + + newItem->prevSibling = sibling->prevSibling; + sibling->prevSibling = newItem; + } + else + newItem->prevSibling = NULL; + + newItem->nextSibling = sibling; + + if (parent->firstChild == sibling) + parent->firstChild = newItem; + + if (parent->lastChild == NULL) + parent->lastChild = newItem; +} + +/*************************************************************************** + * This method inserts newItem after sibling as a child of parent. + * sibling can be NULL, but only if parent has no children. + */ +static void +TREEVIEW_InsertAfter(TREEVIEW_ITEM *newItem, TREEVIEW_ITEM *sibling, + TREEVIEW_ITEM *parent) +{ + assert(newItem != NULL); + assert(parent != NULL); + + if (sibling != NULL) + { + assert(sibling->parent == parent); + + if (sibling->nextSibling != NULL) + sibling->nextSibling->prevSibling = newItem; + + newItem->nextSibling = sibling->nextSibling; + sibling->nextSibling = newItem; + } + else + newItem->nextSibling = NULL; + + newItem->prevSibling = sibling; + + if (parent->lastChild == sibling) + parent->lastChild = newItem; + + if (parent->firstChild == NULL) + parent->firstChild = newItem; +} + +static BOOL +TREEVIEW_DoSetItemT(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, + const TVITEMEXW *tvItem, BOOL isW) +{ + UINT callbackClear = 0; + UINT callbackSet = 0; + + TRACE("item %p\n", wineItem); + /* Do this first in case it fails. */ + if (tvItem->mask & TVIF_TEXT) + { + wineItem->textWidth = 0; /* force width recalculation */ + if (tvItem->pszText != LPSTR_TEXTCALLBACKW) /* covers != TEXTCALLBACKA too */ + { + int len; + LPWSTR newText; + if (isW) + len = lstrlenW(tvItem->pszText) + 1; + else + len = MultiByteToWideChar(CP_ACP, 0, (LPSTR)tvItem->pszText, -1, NULL, 0); + + newText = ReAlloc(wineItem->pszText, len * sizeof(WCHAR)); + + if (newText == NULL) return FALSE; + + callbackClear |= TVIF_TEXT; + + wineItem->pszText = newText; + wineItem->cchTextMax = len; + if (isW) + lstrcpynW(wineItem->pszText, tvItem->pszText, len); + else + MultiByteToWideChar(CP_ACP, 0, (LPSTR)tvItem->pszText, -1, + wineItem->pszText, len); + + TRACE("setting text %s, item %p\n", debugstr_w(wineItem->pszText), wineItem); + } + else + { + callbackSet |= TVIF_TEXT; + + wineItem->pszText = ReAlloc(wineItem->pszText, + TEXT_CALLBACK_SIZE * sizeof(WCHAR)); + wineItem->cchTextMax = TEXT_CALLBACK_SIZE; + TRACE("setting callback, item %p\n", wineItem); + } + } + + if (tvItem->mask & TVIF_CHILDREN) + { + wineItem->cChildren = tvItem->cChildren; + + if (wineItem->cChildren == I_CHILDRENCALLBACK) + callbackSet |= TVIF_CHILDREN; + else + callbackClear |= TVIF_CHILDREN; + } + + if (tvItem->mask & TVIF_IMAGE) + { + wineItem->iImage = tvItem->iImage; + + if (wineItem->iImage == I_IMAGECALLBACK) + callbackSet |= TVIF_IMAGE; + else + callbackClear |= TVIF_IMAGE; + } + + if (tvItem->mask & TVIF_SELECTEDIMAGE) + { + wineItem->iSelectedImage = tvItem->iSelectedImage; + + if (wineItem->iSelectedImage == I_IMAGECALLBACK) + callbackSet |= TVIF_SELECTEDIMAGE; + else + callbackClear |= TVIF_SELECTEDIMAGE; + } + + if (tvItem->mask & TVIF_PARAM) + wineItem->lParam = tvItem->lParam; + + /* If the application sets TVIF_INTEGRAL without + * supplying a TVITEMEX structure, it's toast. */ + if (tvItem->mask & TVIF_INTEGRAL) + wineItem->iIntegral = tvItem->iIntegral; + + if (tvItem->mask & TVIF_STATE) + { + TRACE("prevstate,state,mask:%x,%x,%x\n", wineItem->state, tvItem->state, + tvItem->stateMask); + wineItem->state &= ~tvItem->stateMask; + wineItem->state |= (tvItem->state & tvItem->stateMask); + } + + wineItem->callbackMask |= callbackSet; + wineItem->callbackMask &= ~callbackClear; + + return TRUE; +} + +/* Note that the new item is pre-zeroed. */ +static LRESULT +TREEVIEW_InsertItemT(TREEVIEW_INFO *infoPtr, const TVINSERTSTRUCTW *ptdi, BOOL isW) +{ + const TVITEMEXW *tvItem = &ptdi->u.itemex; + HTREEITEM insertAfter; + TREEVIEW_ITEM *newItem, *parentItem; + BOOL bTextUpdated = FALSE; + + if (ptdi->hParent == TVI_ROOT || ptdi->hParent == 0) + { + parentItem = infoPtr->root; + } + else + { + parentItem = ptdi->hParent; + + if (!TREEVIEW_ValidItem(infoPtr, parentItem)) + { + WARN("invalid parent %p\n", parentItem); + return (LRESULT)(HTREEITEM)NULL; + } + } + + insertAfter = ptdi->hInsertAfter; + + /* Validate this now for convenience. */ + switch ((DWORD)insertAfter) + { + case (DWORD)TVI_FIRST: + case (DWORD)TVI_LAST: + case (DWORD)TVI_SORT: + break; + + default: + if (!TREEVIEW_ValidItem(infoPtr, insertAfter) || + insertAfter->parent != parentItem) + { + WARN("invalid insert after %p\n", insertAfter); + insertAfter = TVI_LAST; + } + } + + TRACE("parent %p position %p: %s\n", parentItem, insertAfter, + (tvItem->mask & TVIF_TEXT) + ? ((tvItem->pszText == LPSTR_TEXTCALLBACKW) ? "" + : (isW ? debugstr_w(tvItem->pszText) : debugstr_a((LPSTR)tvItem->pszText))) + : ""); + + newItem = TREEVIEW_AllocateItem(infoPtr); + if (newItem == NULL) + return (LRESULT)(HTREEITEM)NULL; + + newItem->parent = parentItem; + newItem->iIntegral = 1; + + if (!TREEVIEW_DoSetItemT(infoPtr, newItem, tvItem, isW)) + return (LRESULT)(HTREEITEM)NULL; + + /* After this point, nothing can fail. (Except for TVI_SORT.) */ + + infoPtr->uNumItems++; + + switch ((DWORD)insertAfter) + { + case (DWORD)TVI_FIRST: + { + TREEVIEW_ITEM *originalFirst = parentItem->firstChild; + TREEVIEW_InsertBefore(newItem, parentItem->firstChild, parentItem); + if (infoPtr->firstVisible == originalFirst) + TREEVIEW_SetFirstVisible(infoPtr, newItem, TRUE); + } + break; + + case (DWORD)TVI_LAST: + TREEVIEW_InsertAfter(newItem, parentItem->lastChild, parentItem); + break; + + /* hInsertAfter names a specific item we want to insert after */ + default: + TREEVIEW_InsertAfter(newItem, insertAfter, insertAfter->parent); + break; + + case (DWORD)TVI_SORT: + { + TREEVIEW_ITEM *aChild; + TREEVIEW_ITEM *previousChild = NULL; + BOOL bItemInserted = FALSE; + + aChild = parentItem->firstChild; + + bTextUpdated = TRUE; + TREEVIEW_UpdateDispInfo(infoPtr, newItem, TVIF_TEXT); + + /* Iterate the parent children to see where we fit in */ + while (aChild != NULL) + { + INT comp; + + TREEVIEW_UpdateDispInfo(infoPtr, aChild, TVIF_TEXT); + comp = lstrcmpW(newItem->pszText, aChild->pszText); + + if (comp < 0) /* we are smaller than the current one */ + { + TREEVIEW_InsertBefore(newItem, aChild, parentItem); + bItemInserted = TRUE; + break; + } + else if (comp > 0) /* we are bigger than the current one */ + { + previousChild = aChild; + + /* This will help us to exit if there is no more sibling */ + aChild = (aChild->nextSibling == 0) + ? NULL + : aChild->nextSibling; + + /* Look at the next item */ + continue; + } + else if (comp == 0) + { + /* + * An item with this name is already existing, therefore, + * we add after the one we found + */ + TREEVIEW_InsertAfter(newItem, aChild, parentItem); + bItemInserted = TRUE; + break; + } + } + + /* + * we reach the end of the child list and the item has not + * yet been inserted, therefore, insert it after the last child. + */ + if ((!bItemInserted) && (aChild == NULL)) + TREEVIEW_InsertAfter(newItem, previousChild, parentItem); + + break; + } + } + + + TRACE("new item %p; parent %p, mask %x\n", newItem, + newItem->parent, tvItem->mask); + + newItem->iLevel = newItem->parent->iLevel + 1; + + if (newItem->parent->cChildren == 0) + newItem->parent->cChildren = 1; + + if (infoPtr->dwStyle & TVS_CHECKBOXES) + { + if (STATEIMAGEINDEX(newItem->state) == 0) + newItem->state |= INDEXTOSTATEIMAGEMASK(1); + } + + if (infoPtr->firstVisible == NULL) + infoPtr->firstVisible = newItem; + + TREEVIEW_VerifyTree(infoPtr); + + if (parentItem == infoPtr->root || + (ISVISIBLE(parentItem) && parentItem->state & TVIS_EXPANDED)) + { + TREEVIEW_ITEM *item; + TREEVIEW_ITEM *prev = TREEVIEW_GetPrevListItem(infoPtr, newItem); + + TREEVIEW_RecalculateVisibleOrder(infoPtr, prev); + TREEVIEW_ComputeItemInternalMetrics(infoPtr, newItem); + + if (!bTextUpdated) + TREEVIEW_UpdateDispInfo(infoPtr, newItem, TVIF_TEXT); + + TREEVIEW_ComputeTextWidth(infoPtr, newItem, 0); + TREEVIEW_UpdateScrollBars(infoPtr); + /* + * if the item was inserted in a visible part of the tree, + * invalidate it, as well as those after it + */ + for (item = newItem; + item != NULL; + item = TREEVIEW_GetNextListItem(infoPtr, item)) + TREEVIEW_Invalidate(infoPtr, item); + } + else + { + newItem->visibleOrder = -1; + + /* refresh treeview if newItem is the first item inserted under parentItem */ + if (ISVISIBLE(parentItem) && newItem->prevSibling == newItem->nextSibling) + { + /* parent got '+' - update it */ + TREEVIEW_Invalidate(infoPtr, parentItem); + } + } + + return (LRESULT)newItem; +} + +/* Item Deletion ************************************************************/ +static void +TREEVIEW_RemoveItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem); + +static void +TREEVIEW_RemoveAllChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *parentItem) +{ + TREEVIEW_ITEM *kill = parentItem->firstChild; + + while (kill != NULL) + { + TREEVIEW_ITEM *next = kill->nextSibling; + + TREEVIEW_RemoveItem(infoPtr, kill); + + kill = next; + } + + assert(parentItem->cChildren <= 0); /* I_CHILDRENCALLBACK or 0 */ + assert(parentItem->firstChild == NULL); + assert(parentItem->lastChild == NULL); +} + +static void +TREEVIEW_UnlinkItem(TREEVIEW_ITEM *item) +{ + TREEVIEW_ITEM *parentItem = item->parent; + + assert(item != NULL); + assert(item->parent != NULL); /* i.e. it must not be the root */ + + if (parentItem->firstChild == item) + parentItem->firstChild = item->nextSibling; + + if (parentItem->lastChild == item) + parentItem->lastChild = item->prevSibling; + + if (parentItem->firstChild == NULL && parentItem->lastChild == NULL + && parentItem->cChildren > 0) + parentItem->cChildren = 0; + + if (item->prevSibling) + item->prevSibling->nextSibling = item->nextSibling; + + if (item->nextSibling) + item->nextSibling->prevSibling = item->prevSibling; +} + +static void +TREEVIEW_RemoveItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem) +{ + TRACE("%p, (%s)\n", wineItem, TREEVIEW_ItemName(wineItem)); + + TREEVIEW_SendTreeviewNotify(infoPtr, TVN_DELETEITEMW, TVC_UNKNOWN, + TVIF_HANDLE | TVIF_PARAM, wineItem, 0); + + if (wineItem->firstChild) + TREEVIEW_RemoveAllChildren(infoPtr, wineItem); + + TREEVIEW_UnlinkItem(wineItem); + + infoPtr->uNumItems--; + + if (wineItem->pszText && wineItem->pszText != LPSTR_TEXTCALLBACKW) + Free(wineItem->pszText); + + TREEVIEW_FreeItem(infoPtr, wineItem); +} + + +/* Empty out the tree. */ +static void +TREEVIEW_RemoveTree(TREEVIEW_INFO *infoPtr) +{ + TREEVIEW_RemoveAllChildren(infoPtr, infoPtr->root); + + assert(infoPtr->uNumItems == 0); /* root isn't counted in uNumItems */ +} + +static LRESULT +TREEVIEW_DeleteItem(TREEVIEW_INFO *infoPtr, HTREEITEM wineItem) +{ + TREEVIEW_ITEM *newSelection = NULL; + TREEVIEW_ITEM *newFirstVisible = NULL; + TREEVIEW_ITEM *parent, *prev = NULL; + BOOL visible = FALSE; + + if (wineItem == TVI_ROOT) + { + TRACE("TVI_ROOT\n"); + parent = infoPtr->root; + newSelection = NULL; + visible = TRUE; + TREEVIEW_RemoveTree(infoPtr); + } + else + { + if (!TREEVIEW_ValidItem(infoPtr, wineItem)) + return FALSE; + + TRACE("%p (%s)\n", wineItem, TREEVIEW_ItemName(wineItem)); + parent = wineItem->parent; + + if (ISVISIBLE(wineItem)) + { + prev = TREEVIEW_GetPrevListItem(infoPtr, wineItem); + visible = TRUE; + } + + if (infoPtr->selectedItem != NULL + && (wineItem == infoPtr->selectedItem + || TREEVIEW_IsChildOf(wineItem, infoPtr->selectedItem))) + { + if (wineItem->nextSibling) + newSelection = wineItem->nextSibling; + else if (wineItem->parent != infoPtr->root) + newSelection = wineItem->parent; + else + newSelection = wineItem->prevSibling; + TRACE("newSelection = %p\n", newSelection); + } + + if (infoPtr->firstVisible == wineItem) + { + if (wineItem->nextSibling) + newFirstVisible = wineItem->nextSibling; + else if (wineItem->prevSibling) + newFirstVisible = wineItem->prevSibling; + else if (wineItem->parent != infoPtr->root) + newFirstVisible = wineItem->parent; + TREEVIEW_SetFirstVisible(infoPtr, NULL, TRUE); + } + else + newFirstVisible = infoPtr->firstVisible; + + TREEVIEW_RemoveItem(infoPtr, wineItem); + } + + /* Don't change if somebody else already has (infoPtr->selectedItem is cleared by FreeItem). */ + if (!infoPtr->selectedItem && newSelection) + { + if (TREEVIEW_ValidItem(infoPtr, newSelection)) + TREEVIEW_DoSelectItem(infoPtr, TVGN_CARET, newSelection, TVC_UNKNOWN); + } + + /* Validate insertMark dropItem. + * hotItem ??? - used for comparison only. + */ + if (!TREEVIEW_ValidItem(infoPtr, infoPtr->insertMarkItem)) + infoPtr->insertMarkItem = 0; + + if (!TREEVIEW_ValidItem(infoPtr, infoPtr->dropItem)) + infoPtr->dropItem = 0; + + if (!TREEVIEW_ValidItem(infoPtr, newFirstVisible)) + newFirstVisible = infoPtr->root->firstChild; + + TREEVIEW_VerifyTree(infoPtr); + + + if (visible) + { + TREEVIEW_SetFirstVisible(infoPtr, newFirstVisible, TRUE); + TREEVIEW_RecalculateVisibleOrder(infoPtr, prev); + TREEVIEW_UpdateScrollBars(infoPtr); + TREEVIEW_Invalidate(infoPtr, NULL); + } + else if (ISVISIBLE(parent) && !TREEVIEW_HasChildren(infoPtr, parent)) + { + /* parent lost '+/-' - update it */ + TREEVIEW_Invalidate(infoPtr, parent); + } + + return TRUE; +} + + +/* Get/Set Messages *********************************************************/ +static LRESULT +TREEVIEW_SetRedraw(TREEVIEW_INFO* infoPtr, WPARAM wParam, LPARAM lParam) +{ + if(wParam) + infoPtr->bRedraw = TRUE; + else + infoPtr->bRedraw = FALSE; + + return 0; +} + +static LRESULT +TREEVIEW_GetIndent(TREEVIEW_INFO *infoPtr) +{ + TRACE("\n"); + return infoPtr->uIndent; +} + +static LRESULT +TREEVIEW_SetIndent(TREEVIEW_INFO *infoPtr, UINT newIndent) +{ + TRACE("\n"); + + if (newIndent < MINIMUM_INDENT) + newIndent = MINIMUM_INDENT; + + if (infoPtr->uIndent != newIndent) + { + infoPtr->uIndent = newIndent; + TREEVIEW_UpdateSubTree(infoPtr, infoPtr->root); + TREEVIEW_UpdateScrollBars(infoPtr); + TREEVIEW_Invalidate(infoPtr, NULL); + } + + return 0; +} + + +static LRESULT +TREEVIEW_GetToolTips(TREEVIEW_INFO *infoPtr) +{ + TRACE("\n"); + return (LRESULT)infoPtr->hwndToolTip; +} + +static LRESULT +TREEVIEW_SetToolTips(TREEVIEW_INFO *infoPtr, HWND hwndTT) +{ + HWND prevToolTip; + + TRACE("\n"); + prevToolTip = infoPtr->hwndToolTip; + infoPtr->hwndToolTip = hwndTT; + + return (LRESULT)prevToolTip; +} + +static LRESULT +TREEVIEW_SetUnicodeFormat(TREEVIEW_INFO *infoPtr, BOOL fUnicode) +{ + BOOL rc = infoPtr->bNtfUnicode; + infoPtr->bNtfUnicode = fUnicode; + return rc; +} + +static LRESULT +TREEVIEW_GetUnicodeFormat(TREEVIEW_INFO *infoPtr) +{ + return infoPtr->bNtfUnicode; +} + +static LRESULT +TREEVIEW_GetScrollTime(TREEVIEW_INFO *infoPtr) +{ + return infoPtr->uScrollTime; +} + +static LRESULT +TREEVIEW_SetScrollTime(TREEVIEW_INFO *infoPtr, UINT uScrollTime) +{ + UINT uOldScrollTime = infoPtr->uScrollTime; + + infoPtr->uScrollTime = min(uScrollTime, 100); + + return uOldScrollTime; +} + + +static LRESULT +TREEVIEW_GetImageList(TREEVIEW_INFO *infoPtr, WPARAM wParam) +{ + TRACE("\n"); + + switch (wParam) + { + case (WPARAM)TVSIL_NORMAL: + return (LRESULT)infoPtr->himlNormal; + + case (WPARAM)TVSIL_STATE: + return (LRESULT)infoPtr->himlState; + + default: + return 0; + } +} + +#define TVHEIGHT_MIN 16 +#define TVHEIGHT_FONT_ADJUST 3 /* 2 for focus border + 1 for margin some apps assume */ + +/* Compute the natural height for items. */ +static UINT +TREEVIEW_NaturalHeight(TREEVIEW_INFO *infoPtr) +{ + TEXTMETRICW tm; + HDC hdc = GetDC(0); + HFONT hOldFont = SelectObject(hdc, infoPtr->hFont); + UINT height; + + /* Height is the maximum of: + * 16 (a hack because our fonts are tiny), and + * The text height + border & margin, and + * The size of the normal image list + */ + GetTextMetricsW(hdc, &tm); + SelectObject(hdc, hOldFont); + ReleaseDC(0, hdc); + + height = TVHEIGHT_MIN; + if (height < tm.tmHeight + tm.tmExternalLeading + TVHEIGHT_FONT_ADJUST) + height = tm.tmHeight + tm.tmExternalLeading + TVHEIGHT_FONT_ADJUST; + if (height < infoPtr->normalImageHeight) + height = infoPtr->normalImageHeight; + return height; +} + +static LRESULT +TREEVIEW_SetImageList(TREEVIEW_INFO *infoPtr, WPARAM wParam, HIMAGELIST himlNew) +{ + HIMAGELIST himlOld = 0; + int oldWidth = infoPtr->normalImageWidth; + int oldHeight = infoPtr->normalImageHeight; + + + TRACE("%x,%p\n", wParam, himlNew); + + switch (wParam) + { + case (WPARAM)TVSIL_NORMAL: + himlOld = infoPtr->himlNormal; + infoPtr->himlNormal = himlNew; + + if (himlNew != NULL) + ImageList_GetIconSize(himlNew, &infoPtr->normalImageWidth, + &infoPtr->normalImageHeight); + else + { + infoPtr->normalImageWidth = 0; + infoPtr->normalImageHeight = 0; + } + + break; + + case (WPARAM)TVSIL_STATE: + himlOld = infoPtr->himlState; + infoPtr->himlState = himlNew; + + if (himlNew != NULL) + ImageList_GetIconSize(himlNew, &infoPtr->stateImageWidth, + &infoPtr->stateImageHeight); + else + { + infoPtr->stateImageWidth = 0; + infoPtr->stateImageHeight = 0; + } + + break; + } + + if (oldWidth != infoPtr->normalImageWidth || + oldHeight != infoPtr->normalImageHeight) + { + BOOL bRecalcVisible = FALSE; + + if (oldHeight != infoPtr->normalImageHeight && + !infoPtr->bHeightSet) + { + infoPtr->uItemHeight = TREEVIEW_NaturalHeight(infoPtr); + bRecalcVisible = TRUE; + } + + if (infoPtr->normalImageWidth > MINIMUM_INDENT && + infoPtr->normalImageWidth != infoPtr->uIndent) + { + infoPtr->uIndent = infoPtr->normalImageWidth; + bRecalcVisible = TRUE; + } + + if (bRecalcVisible) + TREEVIEW_RecalculateVisibleOrder(infoPtr, NULL); + + TREEVIEW_UpdateSubTree(infoPtr, infoPtr->root); + TREEVIEW_UpdateScrollBars(infoPtr); + } + + TREEVIEW_Invalidate(infoPtr, NULL); + + return (LRESULT)himlOld; +} + +static LRESULT +TREEVIEW_SetItemHeight(TREEVIEW_INFO *infoPtr, INT newHeight) +{ + INT prevHeight = infoPtr->uItemHeight; + + TRACE("%d \n", newHeight); + if (newHeight == -1) + { + infoPtr->uItemHeight = TREEVIEW_NaturalHeight(infoPtr); + infoPtr->bHeightSet = FALSE; + } + else + { + infoPtr->uItemHeight = newHeight; + infoPtr->bHeightSet = TRUE; + } + + /* Round down, unless we support odd ("non even") heights. */ + if (!(infoPtr->dwStyle) & TVS_NONEVENHEIGHT) + infoPtr->uItemHeight &= ~1; + + if (infoPtr->uItemHeight != prevHeight) + { + TREEVIEW_RecalculateVisibleOrder(infoPtr, NULL); + TREEVIEW_UpdateScrollBars(infoPtr); + TREEVIEW_Invalidate(infoPtr, NULL); + } + + return prevHeight; +} + +static LRESULT +TREEVIEW_GetItemHeight(TREEVIEW_INFO *infoPtr) +{ + TRACE("\n"); + return infoPtr->uItemHeight; +} + + +static LRESULT +TREEVIEW_GetFont(TREEVIEW_INFO *infoPtr) +{ + TRACE("%p\n", infoPtr->hFont); + return (LRESULT)infoPtr->hFont; +} + + +static INT CALLBACK +TREEVIEW_ResetTextWidth(LPVOID pItem, LPVOID unused) +{ + (void)unused; + + ((TREEVIEW_ITEM *)pItem)->textWidth = 0; + + return 1; +} + +static LRESULT +TREEVIEW_SetFont(TREEVIEW_INFO *infoPtr, HFONT hFont, BOOL bRedraw) +{ + UINT uHeight = infoPtr->uItemHeight; + + TRACE("%p %i\n", hFont, bRedraw); + + infoPtr->hFont = hFont ? hFont : infoPtr->hDefaultFont; + + DeleteObject(infoPtr->hBoldFont); + infoPtr->hBoldFont = TREEVIEW_CreateBoldFont(infoPtr->hFont); + infoPtr->hUnderlineFont = TREEVIEW_CreateUnderlineFont(infoPtr->hFont); + + if (!infoPtr->bHeightSet) + infoPtr->uItemHeight = TREEVIEW_NaturalHeight(infoPtr); + + if (uHeight != infoPtr->uItemHeight) + TREEVIEW_RecalculateVisibleOrder(infoPtr, NULL); + + DPA_EnumCallback(infoPtr->items, TREEVIEW_ResetTextWidth, 0); + + TREEVIEW_UpdateSubTree(infoPtr, infoPtr->root); + TREEVIEW_UpdateScrollBars(infoPtr); + + if (bRedraw) + TREEVIEW_Invalidate(infoPtr, NULL); + + return 0; +} + + +static LRESULT +TREEVIEW_GetLineColor(TREEVIEW_INFO *infoPtr) +{ + TRACE("\n"); + return (LRESULT)infoPtr->clrLine; +} + +static LRESULT +TREEVIEW_SetLineColor(TREEVIEW_INFO *infoPtr, COLORREF color) +{ + COLORREF prevColor = infoPtr->clrLine; + + TRACE("\n"); + infoPtr->clrLine = color; + return (LRESULT)prevColor; +} + + +static LRESULT +TREEVIEW_GetTextColor(TREEVIEW_INFO *infoPtr) +{ + TRACE("\n"); + return (LRESULT)infoPtr->clrText; +} + +static LRESULT +TREEVIEW_SetTextColor(TREEVIEW_INFO *infoPtr, COLORREF color) +{ + COLORREF prevColor = infoPtr->clrText; + + TRACE("\n"); + infoPtr->clrText = color; + + if (infoPtr->clrText != prevColor) + TREEVIEW_Invalidate(infoPtr, NULL); + + return (LRESULT)prevColor; +} + + +static LRESULT +TREEVIEW_GetBkColor(TREEVIEW_INFO *infoPtr) +{ + TRACE("\n"); + return (LRESULT)infoPtr->clrBk; +} + +static LRESULT +TREEVIEW_SetBkColor(TREEVIEW_INFO *infoPtr, COLORREF newColor) +{ + COLORREF prevColor = infoPtr->clrBk; + + TRACE("\n"); + infoPtr->clrBk = newColor; + + if (newColor != prevColor) + TREEVIEW_Invalidate(infoPtr, NULL); + + return (LRESULT)prevColor; +} + + +static LRESULT +TREEVIEW_GetInsertMarkColor(TREEVIEW_INFO *infoPtr) +{ + TRACE("\n"); + return (LRESULT)infoPtr->clrInsertMark; +} + +static LRESULT +TREEVIEW_SetInsertMarkColor(TREEVIEW_INFO *infoPtr, COLORREF color) +{ + COLORREF prevColor = infoPtr->clrInsertMark; + + TRACE("%lx\n", color); + infoPtr->clrInsertMark = color; + + return (LRESULT)prevColor; +} + + +static LRESULT +TREEVIEW_SetInsertMark(TREEVIEW_INFO *infoPtr, BOOL wParam, HTREEITEM item) +{ + TRACE("%d %p\n", wParam, item); + + if (!TREEVIEW_ValidItem(infoPtr, item)) + return 0; + + infoPtr->insertBeforeorAfter = wParam; + infoPtr->insertMarkItem = item; + + TREEVIEW_Invalidate(infoPtr, NULL); + + return 1; +} + + +/************************************************************************ + * Some serious braindamage here. lParam is a pointer to both the + * input HTREEITEM and the output RECT. + */ +static LRESULT +TREEVIEW_GetItemRect(TREEVIEW_INFO *infoPtr, BOOL fTextRect, LPRECT lpRect) +{ + TREEVIEW_ITEM *wineItem; + const HTREEITEM *pItem = (HTREEITEM *)lpRect; + + TRACE("\n"); + /* + * validate parameters + */ + if (pItem == NULL) + return FALSE; + + wineItem = *pItem; + if (!TREEVIEW_ValidItem(infoPtr, wineItem) || !ISVISIBLE(wineItem)) + return FALSE; + + /* + * If wParam is TRUE return the text size otherwise return + * the whole item size + */ + if (fTextRect) + { + /* Windows does not send TVN_GETDISPINFO here. */ + + lpRect->top = wineItem->rect.top; + lpRect->bottom = wineItem->rect.bottom; + + lpRect->left = wineItem->textOffset; + lpRect->right = wineItem->textOffset + wineItem->textWidth; + } + else + { + *lpRect = wineItem->rect; + } + + TRACE("%s [L:%ld R:%ld T:%ld B:%ld]\n", fTextRect ? "text" : "item", + lpRect->left, lpRect->right, lpRect->top, lpRect->bottom); + + return TRUE; +} + +static inline LRESULT +TREEVIEW_GetVisibleCount(TREEVIEW_INFO *infoPtr) +{ + /* Suprise! This does not take integral height into account. */ + return infoPtr->clientHeight / infoPtr->uItemHeight; +} + + +static LRESULT +TREEVIEW_GetItemT(TREEVIEW_INFO *infoPtr, LPTVITEMEXW tvItem, BOOL isW) +{ + TREEVIEW_ITEM *wineItem; + + wineItem = tvItem->hItem; + if (!TREEVIEW_ValidItem(infoPtr, wineItem)) + return FALSE; + + TREEVIEW_UpdateDispInfo(infoPtr, wineItem, tvItem->mask); + + if (tvItem->mask & TVIF_CHILDREN) + { + if (wineItem->cChildren==I_CHILDRENCALLBACK) + FIXME("I_CHILDRENCALLBACK not supported\n"); + tvItem->cChildren = wineItem->cChildren; + } + + if (tvItem->mask & TVIF_HANDLE) + tvItem->hItem = wineItem; + + if (tvItem->mask & TVIF_IMAGE) + tvItem->iImage = wineItem->iImage; + + if (tvItem->mask & TVIF_INTEGRAL) + tvItem->iIntegral = wineItem->iIntegral; + + /* undocumented: windows ignores TVIF_PARAM and + * * always sets lParam + */ + tvItem->lParam = wineItem->lParam; + + if (tvItem->mask & TVIF_SELECTEDIMAGE) + tvItem->iSelectedImage = wineItem->iSelectedImage; + + if (tvItem->mask & TVIF_STATE) + /* Careful here - Windows ignores the stateMask when you get the state + That contradicts the documentation, but makes more common sense, masking + retrieval in this way seems overkill */ + tvItem->state = wineItem->state; + + if (tvItem->mask & TVIF_TEXT) + { + if (isW) + { + if (wineItem->pszText == LPSTR_TEXTCALLBACKW) + { + tvItem->pszText = LPSTR_TEXTCALLBACKW; + FIXME(" GetItem called with LPSTR_TEXTCALLBACK\n"); + } + else + { + lstrcpynW(tvItem->pszText, wineItem->pszText, tvItem->cchTextMax); + } + } + else + { + if (wineItem->pszText == LPSTR_TEXTCALLBACKW) + { + tvItem->pszText = (LPWSTR)LPSTR_TEXTCALLBACKA; + FIXME(" GetItem called with LPSTR_TEXTCALLBACK\n"); + } + else + { + WideCharToMultiByte(CP_ACP, 0, wineItem->pszText, -1, + (LPSTR)tvItem->pszText, tvItem->cchTextMax, NULL, NULL); + } + } + } + TRACE("item <%p>, txt %p, img %p, mask %x\n", + wineItem, tvItem->pszText, &tvItem->iImage, tvItem->mask); + + return TRUE; +} + +/* Beware MSDN Library Visual Studio 6.0. It says -1 on failure, 0 on success, + * which is wrong. */ +static LRESULT +TREEVIEW_SetItemT(TREEVIEW_INFO *infoPtr, LPTVITEMEXW tvItem, BOOL isW) +{ + TREEVIEW_ITEM *wineItem; + TREEVIEW_ITEM originalItem; + + wineItem = tvItem->hItem; + + TRACE("item %d,mask %x\n", TREEVIEW_GetItemIndex(infoPtr, wineItem), + tvItem->mask); + + if (!TREEVIEW_ValidItem(infoPtr, wineItem)) + return FALSE; + + /* store the orignal item values */ + originalItem = *wineItem; + + if (!TREEVIEW_DoSetItemT(infoPtr, wineItem, tvItem, isW)) + return FALSE; + + /* If the text or TVIS_BOLD was changed, and it is visible, recalculate. */ + if ((tvItem->mask & TVIF_TEXT + || (tvItem->mask & TVIF_STATE && tvItem->stateMask & TVIS_BOLD)) + && ISVISIBLE(wineItem)) + { + TREEVIEW_UpdateDispInfo(infoPtr, wineItem, TVIF_TEXT); + TREEVIEW_ComputeTextWidth(infoPtr, wineItem, 0); + } + + if (tvItem->mask != 0 && ISVISIBLE(wineItem)) + { + /* The refresh updates everything, but we can't wait until then. */ + TREEVIEW_ComputeItemInternalMetrics(infoPtr, wineItem); + + /* if any of the item's values changed and it's not a callback, redraw the item */ + if (item_changed(&originalItem, wineItem, tvItem)) + { + if (tvItem->mask & TVIF_INTEGRAL) + { + TREEVIEW_RecalculateVisibleOrder(infoPtr, wineItem); + TREEVIEW_UpdateScrollBars(infoPtr); + + TREEVIEW_Invalidate(infoPtr, NULL); + } + else + { + TREEVIEW_UpdateScrollBars(infoPtr); + TREEVIEW_Invalidate(infoPtr, wineItem); + } + } + } + + return TRUE; +} + +static LRESULT +TREEVIEW_GetItemState(TREEVIEW_INFO *infoPtr, HTREEITEM wineItem, UINT mask) +{ + TRACE("\n"); + + if (!wineItem || !TREEVIEW_ValidItem(infoPtr, wineItem)) + return 0; + + return (wineItem->state & mask); +} + +static LRESULT +TREEVIEW_GetNextItem(TREEVIEW_INFO *infoPtr, UINT which, HTREEITEM wineItem) +{ + TREEVIEW_ITEM *retval; + + retval = 0; + + /* handle all the global data here */ + switch (which) + { + case TVGN_CHILD: /* Special case: child of 0 is root */ + if (wineItem) + break; + /* fall through */ + case TVGN_ROOT: + retval = infoPtr->root->firstChild; + break; + + case TVGN_CARET: + retval = infoPtr->selectedItem; + break; + + case TVGN_FIRSTVISIBLE: + retval = infoPtr->firstVisible; + break; + + case TVGN_DROPHILITE: + retval = infoPtr->dropItem; + break; + + case TVGN_LASTVISIBLE: + retval = TREEVIEW_GetLastListItem(infoPtr, infoPtr->root); + break; + } + + if (retval) + { + TRACE("flags:%x, returns %p\n", which, retval); + return (LRESULT)retval; + } + + if (wineItem == TVI_ROOT) wineItem = infoPtr->root; + + if (!TREEVIEW_ValidItem(infoPtr, wineItem)) + return FALSE; + + switch (which) + { + case TVGN_NEXT: + retval = wineItem->nextSibling; + break; + case TVGN_PREVIOUS: + retval = wineItem->prevSibling; + break; + case TVGN_PARENT: + retval = (wineItem->parent != infoPtr->root) ? wineItem->parent : NULL; + break; + case TVGN_CHILD: + retval = wineItem->firstChild; + break; + case TVGN_NEXTVISIBLE: + retval = TREEVIEW_GetNextListItem(infoPtr, wineItem); + break; + case TVGN_PREVIOUSVISIBLE: + retval = TREEVIEW_GetPrevListItem(infoPtr, wineItem); + break; + default: + TRACE("Unknown msg %x,item %p\n", which, wineItem); + break; + } + + TRACE("flags:%x, item %p;returns %p\n", which, wineItem, retval); + return (LRESULT)retval; +} + + +static LRESULT +TREEVIEW_GetCount(TREEVIEW_INFO *infoPtr) +{ + TRACE(" %d\n", infoPtr->uNumItems); + return (LRESULT)infoPtr->uNumItems; +} + +static VOID +TREEVIEW_ToggleItemState(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) +{ + if (infoPtr->dwStyle & TVS_CHECKBOXES) + { + static const unsigned int state_table[] = { 0, 2, 1 }; + + unsigned int state; + + state = STATEIMAGEINDEX(item->state); + TRACE("state:%x\n", state); + item->state &= ~TVIS_STATEIMAGEMASK; + + if (state < 3) + state = state_table[state]; + + item->state |= INDEXTOSTATEIMAGEMASK(state); + + TRACE("state:%x\n", state); + TREEVIEW_Invalidate(infoPtr, item); + } +} + + +/* Painting *************************************************************/ + +/* Draw the lines and expand button for an item. Also draws one section + * of the line from item's parent to item's parent's next sibling. */ +static void +TREEVIEW_DrawItemLines(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *item) +{ + LONG centerx, centery; + BOOL lar = ((infoPtr->dwStyle + & (TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS)) + > TVS_LINESATROOT); + HBRUSH hbr, hbrOld; + + if (!lar && item->iLevel == 0) + return; + + hbr = CreateSolidBrush(infoPtr->clrBk); + hbrOld = SelectObject(hdc, hbr); + + centerx = (item->linesOffset + item->stateOffset) / 2; + centery = (item->rect.top + item->rect.bottom) / 2; + + if (infoPtr->dwStyle & TVS_HASLINES) + { + HPEN hOldPen, hNewPen; + HTREEITEM parent; + + /* + * Get a dotted grey pen + */ + hNewPen = CreatePen(PS_ALTERNATE, 0, infoPtr->clrLine); + hOldPen = SelectObject(hdc, hNewPen); + + MoveToEx(hdc, item->stateOffset, centery, NULL); + LineTo(hdc, centerx - 1, centery); + + if (item->prevSibling || item->parent != infoPtr->root) + { + MoveToEx(hdc, centerx, item->rect.top, NULL); + LineTo(hdc, centerx, centery); + } + + if (item->nextSibling) + { + MoveToEx(hdc, centerx, centery, NULL); + LineTo(hdc, centerx, item->rect.bottom + 1); + } + + /* Draw the line from our parent to its next sibling. */ + parent = item->parent; + while (parent != infoPtr->root) + { + int pcenterx = (parent->linesOffset + parent->stateOffset) / 2; + + if (parent->nextSibling + /* skip top-levels unless TVS_LINESATROOT */ + && parent->stateOffset > parent->linesOffset) + { + MoveToEx(hdc, pcenterx, item->rect.top, NULL); + LineTo(hdc, pcenterx, item->rect.bottom + 1); + } + + parent = parent->parent; + } + + SelectObject(hdc, hOldPen); + DeleteObject(hNewPen); + } + + /* + * Display the (+/-) signs + */ + + if (infoPtr->dwStyle & TVS_HASBUTTONS) + { + if (item->cChildren) + { + LONG height = item->rect.bottom - item->rect.top; + LONG width = item->stateOffset - item->linesOffset; + LONG rectsize = min(height, width) / 4; + /* plussize = ceil(rectsize * 3/4) */ + LONG plussize = (rectsize + 1) * 3 / 4; + + HPEN hNewPen = CreatePen(PS_SOLID, 0, infoPtr->clrLine); + HPEN hOldPen = SelectObject(hdc, hNewPen); + + Rectangle(hdc, centerx - rectsize - 1, centery - rectsize - 1, + centerx + rectsize + 2, centery + rectsize + 2); + + SelectObject(hdc, hOldPen); + DeleteObject(hNewPen); + + if (height < 18 || width < 18) + { + MoveToEx(hdc, centerx - plussize + 1, centery, NULL); + LineTo(hdc, centerx + plussize, centery); + + if (!(item->state & TVIS_EXPANDED)) + { + MoveToEx(hdc, centerx, centery - plussize + 1, NULL); + LineTo(hdc, centerx, centery + plussize); + } + } + else + { + Rectangle(hdc, centerx - plussize + 1, centery - 1, + centerx + plussize, centery + 2); + + if (!(item->state & TVIS_EXPANDED)) + { + Rectangle(hdc, centerx - 1, centery - plussize + 1, + centerx + 2, centery + plussize); + SetPixel(hdc, centerx - 1, centery, infoPtr->clrBk); + SetPixel(hdc, centerx + 1, centery, infoPtr->clrBk); + } + } + } + } + SelectObject(hdc, hbrOld); + DeleteObject(hbr); +} + +static void +TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *wineItem) +{ + INT cditem; + HFONT hOldFont; + COLORREF oldTextColor, oldTextBkColor; + int centery; + BOOL inFocus = (GetFocus() == infoPtr->hwnd); + NMTVCUSTOMDRAW nmcdhdr; + + TREEVIEW_UpdateDispInfo(infoPtr, wineItem, CALLBACK_MASK_ALL); + + /* - If item is drop target or it is selected and window is in focus - + * use blue background (COLOR_HIGHLIGHT). + * - If item is selected, window is not in focus, but it has style + * TVS_SHOWSELALWAYS - use grey background (COLOR_BTNFACE) + * - Otherwise - use background color + */ + if ((wineItem->state & TVIS_DROPHILITED) || ((wineItem == infoPtr->focusedItem) && !(wineItem->state & TVIS_SELECTED)) || + ((wineItem->state & TVIS_SELECTED) && (!infoPtr->focusedItem) && + (inFocus || (infoPtr->dwStyle & TVS_SHOWSELALWAYS)))) + { + if ((wineItem->state & TVIS_DROPHILITED) || inFocus) + { + nmcdhdr.clrTextBk = GetSysColor(COLOR_HIGHLIGHT); + nmcdhdr.clrText = GetSysColor(COLOR_HIGHLIGHTTEXT); + } + else + { + nmcdhdr.clrTextBk = GetSysColor(COLOR_BTNFACE); + if (infoPtr->clrText == -1) + nmcdhdr.clrText = GetSysColor(COLOR_WINDOWTEXT); + else + nmcdhdr.clrText = infoPtr->clrText; + } + } + else + { + nmcdhdr.clrTextBk = infoPtr->clrBk; + if ((infoPtr->dwStyle & TVS_TRACKSELECT) && (wineItem == infoPtr->hotItem)) + nmcdhdr.clrText = comctl32_color.clrHighlight; + else if (infoPtr->clrText == -1) + nmcdhdr.clrText = GetSysColor(COLOR_WINDOWTEXT); + else + nmcdhdr.clrText = infoPtr->clrText; + } + + hOldFont = SelectObject(hdc, TREEVIEW_FontForItem(infoPtr, wineItem)); + + /* The custom draw handler can query the text rectangle, + * so get ready. */ + /* should already be known, set to 0 when changed */ + if (!wineItem->textWidth) + TREEVIEW_ComputeTextWidth(infoPtr, wineItem, hdc); + + cditem = 0; + + if (infoPtr->cdmode & CDRF_NOTIFYITEMDRAW) + { + cditem = TREEVIEW_SendCustomDrawItemNotify + (infoPtr, hdc, wineItem, CDDS_ITEMPREPAINT, &nmcdhdr); + TRACE("prepaint:cditem-app returns 0x%x\n", cditem); + + if (cditem & CDRF_SKIPDEFAULT) + { + SelectObject(hdc, hOldFont); + return; + } + } + + if (cditem & CDRF_NEWFONT) + TREEVIEW_ComputeTextWidth(infoPtr, wineItem, hdc); + + TREEVIEW_DrawItemLines(infoPtr, hdc, wineItem); + + /* Set colors. Custom draw handler can change these so we do this after it. */ + oldTextColor = SetTextColor(hdc, nmcdhdr.clrText); + oldTextBkColor = SetBkColor(hdc, nmcdhdr.clrTextBk); + + centery = (wineItem->rect.top + wineItem->rect.bottom) / 2; + + /* + * Display the images associated with this item + */ + { + INT imageIndex; + + /* State images are displayed to the left of the Normal image + * image number is in state; zero should be `display no image'. + */ + imageIndex = STATEIMAGEINDEX(wineItem->state); + + if (infoPtr->himlState && imageIndex) + { + ImageList_Draw(infoPtr->himlState, imageIndex, hdc, + wineItem->stateOffset, + centery - infoPtr->stateImageHeight / 2, + ILD_NORMAL); + } + + /* Now, draw the normal image; can be either selected or + * non-selected image. + */ + + if ((wineItem->state & TVIS_SELECTED) && (wineItem->iSelectedImage >= 0)) + { + /* The item is currently selected */ + imageIndex = wineItem->iSelectedImage; + } + else + { + /* The item is not selected */ + imageIndex = wineItem->iImage; + } + + if (infoPtr->himlNormal) + { + int ovlIdx = wineItem->state & TVIS_OVERLAYMASK; + + ImageList_Draw(infoPtr->himlNormal, imageIndex, hdc, + wineItem->imageOffset, + centery - infoPtr->normalImageHeight / 2, + ILD_NORMAL | ovlIdx); + } + } + + + /* + * Display the text associated with this item + */ + + /* Don't paint item's text if it's being edited */ + if (!infoPtr->hwndEdit || (infoPtr->selectedItem != wineItem)) + { + if (wineItem->pszText) + { + RECT rcText; + + rcText.top = wineItem->rect.top; + rcText.bottom = wineItem->rect.bottom; + rcText.left = wineItem->textOffset; + rcText.right = rcText.left + wineItem->textWidth + 4; + + TRACE("drawing text %s at (%ld,%ld)-(%ld,%ld)\n", + debugstr_w(wineItem->pszText), + rcText.left, rcText.top, rcText.right, rcText.bottom); + + /* Draw it */ + ExtTextOutW(hdc, rcText.left + 2, rcText.top + 1, + ETO_CLIPPED | ETO_OPAQUE, + &rcText, + wineItem->pszText, + lstrlenW(wineItem->pszText), + NULL); + + /* Draw the box around the selected item */ + if ((wineItem == infoPtr->selectedItem) && inFocus) + { + DrawFocusRect(hdc,&rcText); + } + + } + } + + /* Draw insertion mark if necessary */ + + if (infoPtr->insertMarkItem) + TRACE("item:%d,mark:%d\n", + TREEVIEW_GetItemIndex(infoPtr, wineItem), + (int)infoPtr->insertMarkItem); + + if (wineItem == infoPtr->insertMarkItem) + { + HPEN hNewPen, hOldPen; + int offset; + int left, right; + + hNewPen = CreatePen(PS_SOLID, 2, infoPtr->clrInsertMark); + hOldPen = SelectObject(hdc, hNewPen); + + if (infoPtr->insertBeforeorAfter) + offset = wineItem->rect.bottom - 1; + else + offset = wineItem->rect.top + 1; + + left = wineItem->textOffset - 2; + right = wineItem->textOffset + wineItem->textWidth + 2; + + MoveToEx(hdc, left, offset - 3, NULL); + LineTo(hdc, left, offset + 4); + + MoveToEx(hdc, left, offset, NULL); + LineTo(hdc, right + 1, offset); + + MoveToEx(hdc, right, offset + 3, NULL); + LineTo(hdc, right, offset - 4); + + SelectObject(hdc, hOldPen); + DeleteObject(hNewPen); + } + + if (cditem & CDRF_NOTIFYPOSTPAINT) + { + cditem = TREEVIEW_SendCustomDrawItemNotify + (infoPtr, hdc, wineItem, CDDS_ITEMPOSTPAINT, &nmcdhdr); + TRACE("postpaint:cditem-app returns 0x%x\n", cditem); + } + + /* Restore the hdc state */ + SetTextColor(hdc, oldTextColor); + SetBkColor(hdc, oldTextBkColor); + SelectObject(hdc, hOldFont); +} + +/* Computes treeHeight and treeWidth and updates the scroll bars. + */ +static void +TREEVIEW_UpdateScrollBars(TREEVIEW_INFO *infoPtr) +{ + TREEVIEW_ITEM *wineItem; + HWND hwnd = infoPtr->hwnd; + BOOL vert = FALSE; + BOOL horz = FALSE; + SCROLLINFO si; + LONG scrollX = infoPtr->scrollX; + + infoPtr->treeWidth = 0; + infoPtr->treeHeight = 0; + + /* We iterate through all visible items in order to get the tree height + * and width */ + wineItem = infoPtr->root->firstChild; + + while (wineItem != NULL) + { + if (ISVISIBLE(wineItem)) + { + /* actually we draw text at textOffset + 2 */ + if (2+wineItem->textOffset+wineItem->textWidth > infoPtr->treeWidth) + infoPtr->treeWidth = wineItem->textOffset+wineItem->textWidth+2; + + /* This is scroll-adjusted, but we fix this below. */ + infoPtr->treeHeight = wineItem->rect.bottom; + } + + wineItem = TREEVIEW_GetNextListItem(infoPtr, wineItem); + } + + /* Fix the scroll adjusted treeHeight and treeWidth. */ + if (infoPtr->root->firstChild) + infoPtr->treeHeight -= infoPtr->root->firstChild->rect.top; + + infoPtr->treeWidth += infoPtr->scrollX; + + if (infoPtr->dwStyle & TVS_NOSCROLL) return; + + /* Adding one scroll bar may take up enough space that it forces us + * to add the other as well. */ + if (infoPtr->treeHeight > infoPtr->clientHeight) + { + vert = TRUE; + + if (infoPtr->treeWidth + > infoPtr->clientWidth - GetSystemMetrics(SM_CXVSCROLL)) + horz = TRUE; + } + else if (infoPtr->treeWidth > infoPtr->clientWidth) + horz = TRUE; + + if (!vert && horz && infoPtr->treeHeight + > infoPtr->clientHeight - GetSystemMetrics(SM_CYVSCROLL)) + vert = TRUE; + + if (horz && (infoPtr->dwStyle & TVS_NOHSCROLL)) horz = FALSE; + + si.cbSize = sizeof(SCROLLINFO); + si.fMask = SIF_POS|SIF_RANGE|SIF_PAGE; + si.nMin = 0; + + if (vert) + { + si.nPage = TREEVIEW_GetVisibleCount(infoPtr); + if ( si.nPage && NULL != infoPtr->firstVisible) + { + si.nPos = infoPtr->firstVisible->visibleOrder; + si.nMax = infoPtr->maxVisibleOrder - 1; + + SetScrollInfo(hwnd, SB_VERT, &si, TRUE); + + if (!(infoPtr->uInternalStatus & TV_VSCROLL)) + ShowScrollBar(hwnd, SB_VERT, TRUE); + infoPtr->uInternalStatus |= TV_VSCROLL; + } + else + { + if (infoPtr->uInternalStatus & TV_VSCROLL) + ShowScrollBar(hwnd, SB_VERT, FALSE); + infoPtr->uInternalStatus &= ~TV_VSCROLL; + } + } + else + { + if (infoPtr->uInternalStatus & TV_VSCROLL) + ShowScrollBar(hwnd, SB_VERT, FALSE); + infoPtr->uInternalStatus &= ~TV_VSCROLL; + } + + if (horz) + { + si.nPage = infoPtr->clientWidth; + si.nPos = infoPtr->scrollX; + si.nMax = infoPtr->treeWidth - 1; + + if (si.nPos > si.nMax - max( si.nPage-1, 0 )) + { + si.nPos = si.nMax - max( si.nPage-1, 0 ); + scrollX = si.nPos; + } + + if (!(infoPtr->uInternalStatus & TV_HSCROLL)) + ShowScrollBar(hwnd, SB_HORZ, TRUE); + infoPtr->uInternalStatus |= TV_HSCROLL; + + SetScrollInfo(hwnd, SB_HORZ, &si, TRUE); + } + else + { + if (infoPtr->uInternalStatus & TV_HSCROLL) + ShowScrollBar(hwnd, SB_HORZ, FALSE); + infoPtr->uInternalStatus &= ~TV_HSCROLL; + + scrollX = 0; + } + + if (infoPtr->scrollX != scrollX) + { + TREEVIEW_HScroll(infoPtr, + MAKEWPARAM(SB_THUMBPOSITION, scrollX)); + } + + if (!horz) + infoPtr->uInternalStatus &= ~TV_HSCROLL; +} + +/* CtrlSpy doesn't mention this, but CorelDRAW's object manager needs it. */ +static LRESULT +TREEVIEW_EraseBackground(TREEVIEW_INFO *infoPtr, HDC hDC) +{ + HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk); + RECT rect; + + GetClientRect(infoPtr->hwnd, &rect); + FillRect(hDC, &rect, hBrush); + DeleteObject(hBrush); + + return 1; +} + +static void +TREEVIEW_Refresh(TREEVIEW_INFO *infoPtr, HDC hdc, RECT *rc) +{ + HWND hwnd = infoPtr->hwnd; + RECT rect = *rc; + TREEVIEW_ITEM *wineItem; + + if (infoPtr->clientHeight == 0 || infoPtr->clientWidth == 0) + { + TRACE("empty window\n"); + return; + } + + infoPtr->cdmode = TREEVIEW_SendCustomDrawNotify(infoPtr, CDDS_PREPAINT, + hdc, rect); + + if (infoPtr->cdmode == CDRF_SKIPDEFAULT) + { + ReleaseDC(hwnd, hdc); + return; + } + + for (wineItem = infoPtr->root->firstChild; + wineItem != NULL; + wineItem = TREEVIEW_GetNextListItem(infoPtr, wineItem)) + { + if (ISVISIBLE(wineItem)) + { + /* Avoid unneeded calculations */ + if (wineItem->rect.top > rect.bottom) + break; + if (wineItem->rect.bottom < rect.top) + continue; + + TREEVIEW_DrawItem(infoPtr, hdc, wineItem); + } + } + + TREEVIEW_UpdateScrollBars(infoPtr); + + if (infoPtr->cdmode & CDRF_NOTIFYPOSTPAINT) + infoPtr->cdmode = + TREEVIEW_SendCustomDrawNotify(infoPtr, CDDS_POSTPAINT, hdc, rect); +} + +static void +TREEVIEW_Invalidate(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) +{ + if (item != NULL) + InvalidateRect(infoPtr->hwnd, &item->rect, TRUE); + else + InvalidateRect(infoPtr->hwnd, NULL, TRUE); +} + +static LRESULT +TREEVIEW_Paint(TREEVIEW_INFO *infoPtr, WPARAM wParam) +{ + HDC hdc; + PAINTSTRUCT ps; + RECT rc; + + TRACE("\n"); + + if (wParam) + { + hdc = (HDC)wParam; + if (!GetUpdateRect(infoPtr->hwnd, &rc, TRUE)) + { + HBITMAP hbitmap; + BITMAP bitmap; + hbitmap = GetCurrentObject(hdc, OBJ_BITMAP); + if (!hbitmap) return 0; + GetObjectW(hbitmap, sizeof(BITMAP), &bitmap); + rc.left = 0; rc.top = 0; + rc.right = bitmap.bmWidth; + rc.bottom = bitmap.bmHeight; + TREEVIEW_EraseBackground(infoPtr, (HDC)wParam); + } + } + else + { + hdc = BeginPaint(infoPtr->hwnd, &ps); + rc = ps.rcPaint; + } + + if(infoPtr->bRedraw) /* WM_SETREDRAW sets bRedraw */ + TREEVIEW_Refresh(infoPtr, hdc, &rc); + + if (!wParam) + EndPaint(infoPtr->hwnd, &ps); + + return 0; +} + + +/* Sorting **************************************************************/ + +/*************************************************************************** + * Forward the DPA local callback to the treeview owner callback + */ +static INT WINAPI +TREEVIEW_CallBackCompare(TREEVIEW_ITEM *first, TREEVIEW_ITEM *second, LPTVSORTCB pCallBackSort) +{ + /* Forward the call to the client-defined callback */ + return pCallBackSort->lpfnCompare(first->lParam, + second->lParam, + pCallBackSort->lParam); +} + +/*************************************************************************** + * Treeview native sort routine: sort on item text. + */ +static INT WINAPI +TREEVIEW_SortOnName(TREEVIEW_ITEM *first, TREEVIEW_ITEM *second, + TREEVIEW_INFO *infoPtr) +{ + TREEVIEW_UpdateDispInfo(infoPtr, first, TVIF_TEXT); + TREEVIEW_UpdateDispInfo(infoPtr, second, TVIF_TEXT); + + if(first->pszText && second->pszText) + return lstrcmpiW(first->pszText, second->pszText); + else if(first->pszText) + return -1; + else if(second->pszText) + return 1; + else + return 0; +} + +/* Returns the number of physical children belonging to item. */ +static INT +TREEVIEW_CountChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) +{ + INT cChildren = 0; + HTREEITEM hti; + + for (hti = item->firstChild; hti != NULL; hti = hti->nextSibling) + cChildren++; + + return cChildren; +} + +/* Returns a DPA containing a pointer to each physical child of item in + * sibling order. If item has no children, an empty DPA is returned. */ +static HDPA +TREEVIEW_BuildChildDPA(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) +{ + HTREEITEM child = item->firstChild; + + HDPA list = DPA_Create(8); + if (list == 0) return NULL; + + for (child = item->firstChild; child != NULL; child = child->nextSibling) + { + if (DPA_InsertPtr(list, INT_MAX, child) == -1) + { + DPA_Destroy(list); + return NULL; + } + } + + return list; +} + +/*************************************************************************** + * Setup the treeview structure with regards of the sort method + * and sort the children of the TV item specified in lParam + * fRecurse: currently unused. Should be zero. + * parent: if pSort!=NULL, should equal pSort->hParent. + * otherwise, item which child items are to be sorted. + * pSort: sort method info. if NULL, sort on item text. + * if non-NULL, sort on item's lParam content, and let the + * application decide what that means. See also TVM_SORTCHILDRENCB. + */ + +static LRESULT +TREEVIEW_Sort(TREEVIEW_INFO *infoPtr, BOOL fRecurse, HTREEITEM parent, + LPTVSORTCB pSort) +{ + INT cChildren; + PFNDPACOMPARE pfnCompare; + LPARAM lpCompare; + + /* undocumented feature: TVI_ROOT or NULL means `sort the whole tree' */ + if (parent == TVI_ROOT || parent == NULL) + parent = infoPtr->root; + + /* Check for a valid handle to the parent item */ + if (!TREEVIEW_ValidItem(infoPtr, parent)) + { + ERR("invalid item hParent=%x\n", (INT)parent); + return FALSE; + } + + if (pSort) + { + pfnCompare = (PFNDPACOMPARE)TREEVIEW_CallBackCompare; + lpCompare = (LPARAM)pSort; + } + else + { + pfnCompare = (PFNDPACOMPARE)TREEVIEW_SortOnName; + lpCompare = (LPARAM)infoPtr; + } + + cChildren = TREEVIEW_CountChildren(infoPtr, parent); + + /* Make sure there is something to sort */ + if (cChildren > 1) + { + /* TREEVIEW_ITEM rechaining */ + INT count = 0; + HTREEITEM item = 0; + HTREEITEM nextItem = 0; + HTREEITEM prevItem = 0; + + HDPA sortList = TREEVIEW_BuildChildDPA(infoPtr, parent); + + if (sortList == NULL) + return FALSE; + + /* let DPA sort the list */ + DPA_Sort(sortList, pfnCompare, lpCompare); + + /* The order of DPA entries has been changed, so fixup the + * nextSibling and prevSibling pointers. */ + + item = (HTREEITEM)DPA_GetPtr(sortList, count++); + while ((nextItem = (HTREEITEM)DPA_GetPtr(sortList, count++)) != NULL) + { + /* link the two current item toghether */ + item->nextSibling = nextItem; + nextItem->prevSibling = item; + + if (prevItem == NULL) + { + /* this is the first item, update the parent */ + parent->firstChild = item; + item->prevSibling = NULL; + } + else + { + /* fix the back chaining */ + item->prevSibling = prevItem; + } + + /* get ready for the next one */ + prevItem = item; + item = nextItem; + } + + /* the last item is pointed to by item and never has a sibling */ + item->nextSibling = NULL; + parent->lastChild = item; + + DPA_Destroy(sortList); + + TREEVIEW_VerifyTree(infoPtr); + + if (parent->state & TVIS_EXPANDED) + { + int visOrder = infoPtr->firstVisible->visibleOrder; + + if (parent == infoPtr->root) + TREEVIEW_RecalculateVisibleOrder(infoPtr, NULL); + else + TREEVIEW_RecalculateVisibleOrder(infoPtr, parent); + + if (TREEVIEW_IsChildOf(parent, infoPtr->firstVisible)) + { + TREEVIEW_ITEM *item; + + for (item = infoPtr->root->firstChild; item != NULL; + item = TREEVIEW_GetNextListItem(infoPtr, item)) + { + if (item->visibleOrder == visOrder) + break; + } + + if (!item) item = parent->firstChild; + TREEVIEW_SetFirstVisible(infoPtr, item, FALSE); + } + + TREEVIEW_Invalidate(infoPtr, NULL); + } + + return TRUE; + } + return FALSE; +} + + +/*************************************************************************** + * Setup the treeview structure with regards of the sort method + * and sort the children of the TV item specified in lParam + */ +static LRESULT +TREEVIEW_SortChildrenCB(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPTVSORTCB pSort) +{ + return TREEVIEW_Sort(infoPtr, wParam, pSort->hParent, pSort); +} + + +/*************************************************************************** + * Sort the children of the TV item specified in lParam. + */ +static LRESULT +TREEVIEW_SortChildren(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + return TREEVIEW_Sort(infoPtr, (BOOL)wParam, (HTREEITEM)lParam, NULL); +} + + +/* Expansion/Collapse ***************************************************/ + +static BOOL +TREEVIEW_SendExpanding(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, + UINT action) +{ + return !TREEVIEW_SendTreeviewNotify(infoPtr, TVN_ITEMEXPANDINGW, action, + TVIF_HANDLE | TVIF_STATE | TVIF_PARAM + | TVIF_IMAGE | TVIF_SELECTEDIMAGE, + 0, wineItem); +} + +static VOID +TREEVIEW_SendExpanded(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, + UINT action) +{ + TREEVIEW_SendTreeviewNotify(infoPtr, TVN_ITEMEXPANDEDW, action, + TVIF_HANDLE | TVIF_STATE | TVIF_PARAM + | TVIF_IMAGE | TVIF_SELECTEDIMAGE, + 0, wineItem); +} + + +/* This corresponds to TVM_EXPAND with TVE_COLLAPSE. + * bRemoveChildren corresponds to TVE_COLLAPSERESET. */ +static BOOL +TREEVIEW_Collapse(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, + BOOL bRemoveChildren, BOOL bUser) +{ + UINT action = TVE_COLLAPSE | (bRemoveChildren ? TVE_COLLAPSERESET : 0); + BOOL bSetSelection, bSetFirstVisible; + RECT scrollRect; + LONG scrollDist = 0; + TREEVIEW_ITEM *nextItem = NULL, *tmpItem; + + TRACE("TVE_COLLAPSE %p %s\n", wineItem, TREEVIEW_ItemName(wineItem)); + + if (!(wineItem->state & TVIS_EXPANDED)) + return FALSE; + + if (bUser || !(wineItem->state & TVIS_EXPANDEDONCE)) + TREEVIEW_SendExpanding(infoPtr, wineItem, action); + + if (wineItem->firstChild == NULL) + return FALSE; + + wineItem->state &= ~TVIS_EXPANDED; + + if (bUser || !(wineItem->state & TVIS_EXPANDEDONCE)) + TREEVIEW_SendExpanded(infoPtr, wineItem, action); + + bSetSelection = (infoPtr->selectedItem != NULL + && TREEVIEW_IsChildOf(wineItem, infoPtr->selectedItem)); + + bSetFirstVisible = (infoPtr->firstVisible != NULL + && TREEVIEW_IsChildOf(wineItem, infoPtr->firstVisible)); + + tmpItem = wineItem; + while (tmpItem) + { + if (tmpItem->nextSibling) + { + nextItem = tmpItem->nextSibling; + break; + } + tmpItem = tmpItem->parent; + } + + if (nextItem) + scrollDist = nextItem->rect.top; + + if (bRemoveChildren) + { + INT old_cChildren = wineItem->cChildren; + TRACE("TVE_COLLAPSERESET\n"); + wineItem->state &= ~TVIS_EXPANDEDONCE; + TREEVIEW_RemoveAllChildren(infoPtr, wineItem); + wineItem->cChildren = old_cChildren; + } + + if (wineItem->firstChild) + { + TREEVIEW_ITEM *item, *sibling; + + sibling = TREEVIEW_GetNextListItem(infoPtr, wineItem); + + for (item = wineItem->firstChild; item != sibling; + item = TREEVIEW_GetNextListItem(infoPtr, item)) + { + item->visibleOrder = -1; + } + } + + TREEVIEW_RecalculateVisibleOrder(infoPtr, wineItem); + + if (nextItem) + scrollDist = -(scrollDist - nextItem->rect.top); + + if (bSetSelection) + { + /* Don't call DoSelectItem, it sends notifications. */ + if (TREEVIEW_ValidItem(infoPtr, infoPtr->selectedItem)) + infoPtr->selectedItem->state &= ~TVIS_SELECTED; + wineItem->state |= TVIS_SELECTED; + infoPtr->selectedItem = wineItem; + } + + TREEVIEW_UpdateScrollBars(infoPtr); + + scrollRect.left = 0; + scrollRect.right = infoPtr->clientWidth; + scrollRect.bottom = infoPtr->clientHeight; + + if (nextItem) + { + scrollRect.top = nextItem->rect.top; + + ScrollWindowEx (infoPtr->hwnd, 0, scrollDist, &scrollRect, NULL, + NULL, NULL, SW_ERASE | SW_INVALIDATE); + TREEVIEW_Invalidate(infoPtr, wineItem); + } else { + scrollRect.top = wineItem->rect.top; + InvalidateRect(infoPtr->hwnd, &scrollRect, TRUE); + } + + TREEVIEW_SetFirstVisible(infoPtr, + bSetFirstVisible ? wineItem : infoPtr->firstVisible, + TRUE); + + return TRUE; +} + +static BOOL +TREEVIEW_Expand(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, + BOOL bExpandPartial, BOOL bUser) +{ + LONG scrollDist; + LONG orgNextTop = 0; + RECT scrollRect; + TREEVIEW_ITEM *nextItem, *tmpItem; + + TRACE("\n"); + + if (wineItem->state & TVIS_EXPANDED) + return TRUE; + + tmpItem = wineItem; nextItem = NULL; + while (tmpItem) + { + if (tmpItem->nextSibling) + { + nextItem = tmpItem->nextSibling; + break; + } + tmpItem = tmpItem->parent; + } + + if (nextItem) + orgNextTop = nextItem->rect.top; + + TRACE("TVE_EXPAND %p %s\n", wineItem, TREEVIEW_ItemName(wineItem)); + + if (bUser || ((wineItem->cChildren != 0) && + !(wineItem->state & TVIS_EXPANDEDONCE))) + { + if (!TREEVIEW_SendExpanding(infoPtr, wineItem, TVE_EXPAND)) + { + TRACE(" TVN_ITEMEXPANDING returned TRUE, exiting...\n"); + return FALSE; + } + + if (!wineItem->firstChild) + return FALSE; + + wineItem->state |= TVIS_EXPANDED; + TREEVIEW_SendExpanded(infoPtr, wineItem, TVE_EXPAND); + wineItem->state |= TVIS_EXPANDEDONCE; + } + else + { + if (!wineItem->firstChild) + return FALSE; + + /* this item has already been expanded */ + wineItem->state |= TVIS_EXPANDED; + } + + if (bExpandPartial) + FIXME("TVE_EXPANDPARTIAL not implemented\n"); + + TREEVIEW_RecalculateVisibleOrder(infoPtr, wineItem); + TREEVIEW_UpdateSubTree(infoPtr, wineItem); + TREEVIEW_UpdateScrollBars(infoPtr); + + scrollRect.left = 0; + scrollRect.bottom = infoPtr->treeHeight; + scrollRect.right = infoPtr->clientWidth; + if (nextItem) + { + scrollDist = nextItem->rect.top - orgNextTop; + scrollRect.top = orgNextTop; + + ScrollWindowEx (infoPtr->hwnd, 0, scrollDist, &scrollRect, NULL, + NULL, NULL, SW_ERASE | SW_INVALIDATE); + TREEVIEW_Invalidate (infoPtr, wineItem); + } else { + scrollRect.top = wineItem->rect.top; + InvalidateRect(infoPtr->hwnd, &scrollRect, FALSE); + } + + /* Scroll up so that as many children as possible are visible. + * This fails when expanding causes an HScroll bar to appear, but we + * don't know that yet, so the last item is obscured. */ + if (wineItem->firstChild != NULL) + { + int nChildren = wineItem->lastChild->visibleOrder + - wineItem->firstChild->visibleOrder + 1; + + int visible_pos = wineItem->visibleOrder + - infoPtr->firstVisible->visibleOrder; + + int rows_below = TREEVIEW_GetVisibleCount(infoPtr) - visible_pos - 1; + + if (visible_pos > 0 && nChildren > rows_below) + { + int scroll = nChildren - rows_below; + + if (scroll > visible_pos) + scroll = visible_pos; + + if (scroll > 0) + { + TREEVIEW_ITEM *newFirstVisible + = TREEVIEW_GetListItem(infoPtr, infoPtr->firstVisible, + scroll); + + + TREEVIEW_SetFirstVisible(infoPtr, newFirstVisible, TRUE); + } + } + } + + return TRUE; +} + +static BOOL +TREEVIEW_Toggle(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, BOOL bUser) +{ + TRACE("\n"); + + if (wineItem->state & TVIS_EXPANDED) + return TREEVIEW_Collapse(infoPtr, wineItem, FALSE, bUser); + else + return TREEVIEW_Expand(infoPtr, wineItem, FALSE, bUser); +} + +static VOID +TREEVIEW_ExpandAll(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) +{ + TREEVIEW_Expand(infoPtr, item, FALSE, TRUE); + + for (item = item->firstChild; item != NULL; item = item->nextSibling) + { + if (TREEVIEW_HasChildren(infoPtr, item)) + TREEVIEW_ExpandAll(infoPtr, item); + } +} + +/* Note:If the specified item is the child of a collapsed parent item, + the parent's list of child items is (recursively) expanded to reveal the + specified item. This is mentioned for TREEVIEW_SelectItem; don't + know if it also applies here. +*/ + +static LRESULT +TREEVIEW_ExpandMsg(TREEVIEW_INFO *infoPtr, UINT flag, HTREEITEM wineItem) +{ + if (!TREEVIEW_ValidItem(infoPtr, wineItem)) + return 0; + + TRACE("For (%s) item:%d, flags %x, state:%d\n", + TREEVIEW_ItemName(wineItem), flag, + TREEVIEW_GetItemIndex(infoPtr, wineItem), wineItem->state); + + switch (flag & TVE_TOGGLE) + { + case TVE_COLLAPSE: + return TREEVIEW_Collapse(infoPtr, wineItem, flag & TVE_COLLAPSERESET, + FALSE); + + case TVE_EXPAND: + return TREEVIEW_Expand(infoPtr, wineItem, flag & TVE_EXPANDPARTIAL, + FALSE); + + case TVE_TOGGLE: + return TREEVIEW_Toggle(infoPtr, wineItem, TRUE); + + default: + return 0; + } + +#if 0 + TRACE("Exiting, Item %p state is now %d...\n", wineItem, wineItem->state); +#endif +} + +/* Hit-Testing **********************************************************/ + +static TREEVIEW_ITEM * +TREEVIEW_HitTestPoint(TREEVIEW_INFO *infoPtr, POINT pt) +{ + TREEVIEW_ITEM *wineItem; + LONG row; + + if (!infoPtr->firstVisible) + return NULL; + + row = pt.y / infoPtr->uItemHeight + infoPtr->firstVisible->visibleOrder; + + for (wineItem = infoPtr->firstVisible; wineItem != NULL; + wineItem = TREEVIEW_GetNextListItem(infoPtr, wineItem)) + { + if (row >= wineItem->visibleOrder + && row < wineItem->visibleOrder + wineItem->iIntegral) + break; + } + + return wineItem; +} + +static LRESULT +TREEVIEW_HitTest(TREEVIEW_INFO *infoPtr, LPTVHITTESTINFO lpht) +{ + TREEVIEW_ITEM *wineItem; + RECT rect; + UINT status; + LONG x, y; + + lpht->hItem = 0; + GetClientRect(infoPtr->hwnd, &rect); + status = 0; + x = lpht->pt.x; + y = lpht->pt.y; + + if (x < rect.left) + { + status |= TVHT_TOLEFT; + } + else if (x > rect.right) + { + status |= TVHT_TORIGHT; + } + + if (y < rect.top) + { + status |= TVHT_ABOVE; + } + else if (y > rect.bottom) + { + status |= TVHT_BELOW; + } + + if (status) + { + lpht->flags = status; + return (LRESULT)(HTREEITEM)NULL; + } + + wineItem = TREEVIEW_HitTestPoint(infoPtr, lpht->pt); + if (!wineItem) + { + lpht->flags = TVHT_NOWHERE; + return (LRESULT)(HTREEITEM)NULL; + } + + if (x >= wineItem->textOffset + wineItem->textWidth) + { + lpht->flags = TVHT_ONITEMRIGHT; + } + else if (x >= wineItem->textOffset) + { + lpht->flags = TVHT_ONITEMLABEL; + } + else if (x >= wineItem->imageOffset) + { + lpht->flags = TVHT_ONITEMICON; + } + else if (x >= wineItem->stateOffset) + { + lpht->flags = TVHT_ONITEMSTATEICON; + } + else if (x >= wineItem->linesOffset && infoPtr->dwStyle & TVS_HASBUTTONS) + { + lpht->flags = TVHT_ONITEMBUTTON; + } + else + { + lpht->flags = TVHT_ONITEMINDENT; + } + + lpht->hItem = wineItem; + TRACE("(%ld,%ld):result %x\n", lpht->pt.x, lpht->pt.y, lpht->flags); + + return (LRESULT)wineItem; +} + +/* Item Label Editing ***************************************************/ + +static LRESULT +TREEVIEW_GetEditControl(TREEVIEW_INFO *infoPtr) +{ + return (LRESULT)infoPtr->hwndEdit; +} + +static LRESULT CALLBACK +TREEVIEW_Edit_SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd)); + BOOL bCancel = FALSE; + LRESULT rc; + + switch (uMsg) + { + case WM_PAINT: + TRACE("WM_PAINT start\n"); + rc = CallWindowProcW(infoPtr->wpEditOrig, hwnd, uMsg, wParam, + lParam); + TRACE("WM_PAINT done\n"); + return rc; + + case WM_KILLFOCUS: + if (infoPtr->bIgnoreEditKillFocus) + return TRUE; + break; + + case WM_GETDLGCODE: + return DLGC_WANTARROWS | DLGC_WANTALLKEYS; + + case WM_KEYDOWN: + if (wParam == (WPARAM)VK_ESCAPE) + { + bCancel = TRUE; + break; + } + else if (wParam == (WPARAM)VK_RETURN) + { + break; + } + + /* fall through */ + default: + return CallWindowProcW(infoPtr->wpEditOrig, hwnd, uMsg, wParam, lParam); + } + + /* Processing TVN_ENDLABELEDIT message could kill the focus */ + /* eg. Using a messagebox */ + + infoPtr->bIgnoreEditKillFocus = TRUE; + TREEVIEW_EndEditLabelNow(infoPtr, bCancel || !infoPtr->bLabelChanged); + infoPtr->bIgnoreEditKillFocus = FALSE; + + return 0; +} + + +/* should handle edit control messages here */ + +static LRESULT +TREEVIEW_Command(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + TRACE("%x %ld\n", wParam, lParam); + + switch (HIWORD(wParam)) + { + case EN_UPDATE: + { + /* + * Adjust the edit window size + */ + WCHAR buffer[1024]; + TREEVIEW_ITEM *editItem = infoPtr->selectedItem; + HDC hdc = GetDC(infoPtr->hwndEdit); + SIZE sz; + int len; + HFONT hFont, hOldFont = 0; + + infoPtr->bLabelChanged = TRUE; + + len = GetWindowTextW(infoPtr->hwndEdit, buffer, sizeof(buffer)); + + /* Select font to get the right dimension of the string */ + hFont = (HFONT)SendMessageW(infoPtr->hwndEdit, WM_GETFONT, 0, 0); + + if (hFont != 0) + { + hOldFont = SelectObject(hdc, hFont); + } + + if (GetTextExtentPoint32W(hdc, buffer, strlenW(buffer), &sz)) + { + TEXTMETRICW textMetric; + + /* Add Extra spacing for the next character */ + GetTextMetricsW(hdc, &textMetric); + sz.cx += (textMetric.tmMaxCharWidth * 2); + + sz.cx = max(sz.cx, textMetric.tmMaxCharWidth * 3); + sz.cx = min(sz.cx, + infoPtr->clientWidth - editItem->textOffset + 2); + + SetWindowPos(infoPtr->hwndEdit, + HWND_TOP, + 0, + 0, + sz.cx, + editItem->rect.bottom - editItem->rect.top + 3, + SWP_NOMOVE | SWP_DRAWFRAME); + } + + if (hFont != 0) + { + SelectObject(hdc, hOldFont); + } + + ReleaseDC(infoPtr->hwnd, hdc); + break; + } + + default: + return SendMessageW(infoPtr->hwndNotify, WM_COMMAND, wParam, lParam); + } + + return 0; +} + +static HWND +TREEVIEW_EditLabel(TREEVIEW_INFO *infoPtr, HTREEITEM hItem) +{ + HWND hwnd = infoPtr->hwnd; + HWND hwndEdit; + SIZE sz; + TREEVIEW_ITEM *editItem = hItem; + HINSTANCE hinst = (HINSTANCE)GetWindowLongPtrW(hwnd, GWLP_HINSTANCE); + HDC hdc; + HFONT hOldFont=0; + TEXTMETRICW textMetric; + static const WCHAR EditW[] = {'E','d','i','t',0}; + + TRACE("%x %p\n", (unsigned)hwnd, hItem); + if (!TREEVIEW_ValidItem(infoPtr, editItem)) + return NULL; + + if (infoPtr->hwndEdit) + return infoPtr->hwndEdit; + + infoPtr->bLabelChanged = FALSE; + + /* Make sure that edit item is selected */ + TREEVIEW_DoSelectItem(infoPtr, TVGN_CARET, hItem, TVC_UNKNOWN); + TREEVIEW_EnsureVisible(infoPtr, hItem, TRUE); + + TREEVIEW_UpdateDispInfo(infoPtr, editItem, TVIF_TEXT); + + hdc = GetDC(hwnd); + /* Select the font to get appropriate metric dimensions */ + if (infoPtr->hFont != 0) + { + hOldFont = SelectObject(hdc, infoPtr->hFont); + } + + /* Get string length in pixels */ + GetTextExtentPoint32W(hdc, editItem->pszText, strlenW(editItem->pszText), + &sz); + + /* Add Extra spacing for the next character */ + GetTextMetricsW(hdc, &textMetric); + sz.cx += (textMetric.tmMaxCharWidth * 2); + + sz.cx = max(sz.cx, textMetric.tmMaxCharWidth * 3); + sz.cx = min(sz.cx, infoPtr->clientWidth - editItem->textOffset + 2); + + if (infoPtr->hFont != 0) + { + SelectObject(hdc, hOldFont); + } + + ReleaseDC(hwnd, hdc); + hwndEdit = CreateWindowExW(WS_EX_LEFT, + EditW, + 0, + WS_CHILD | WS_BORDER | ES_AUTOHSCROLL | + WS_CLIPSIBLINGS | ES_WANTRETURN | + ES_LEFT, editItem->textOffset - 2, + editItem->rect.top - 1, sz.cx + 3, + editItem->rect.bottom - + editItem->rect.top + 3, hwnd, 0, hinst, 0); +/* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0); */ + + infoPtr->hwndEdit = hwndEdit; + + /* Get a 2D border. */ + SetWindowLongW(hwndEdit, GWL_EXSTYLE, + GetWindowLongW(hwndEdit, GWL_EXSTYLE) & ~WS_EX_CLIENTEDGE); + SetWindowLongW(hwndEdit, GWL_STYLE, + GetWindowLongW(hwndEdit, GWL_STYLE) | WS_BORDER); + + SendMessageW(hwndEdit, WM_SETFONT, + (WPARAM)TREEVIEW_FontForItem(infoPtr, editItem), FALSE); + + infoPtr->wpEditOrig = (WNDPROC)SetWindowLongPtrW(hwndEdit, GWLP_WNDPROC, + (DWORD_PTR) + TREEVIEW_Edit_SubclassProc); + + if (TREEVIEW_BeginLabelEditNotify(infoPtr, editItem)) + { + DestroyWindow(hwndEdit); + infoPtr->hwndEdit = 0; + return NULL; + } + + infoPtr->selectedItem = hItem; + SetWindowTextW(hwndEdit, editItem->pszText); + SetFocus(hwndEdit); + SendMessageW(hwndEdit, EM_SETSEL, 0, -1); + ShowWindow(hwndEdit, SW_SHOW); + + return hwndEdit; +} + + +static LRESULT +TREEVIEW_EndEditLabelNow(TREEVIEW_INFO *infoPtr, BOOL bCancel) +{ + HWND hwnd = infoPtr->hwnd; + TREEVIEW_ITEM *editedItem = infoPtr->selectedItem; + NMTVDISPINFOW tvdi; + BOOL bCommit; + WCHAR tmpText[1024] = { '\0' }; + WCHAR *newText = tmpText; + int iLength = 0; + + if (!infoPtr->hwndEdit) + return FALSE; + + tvdi.hdr.hwndFrom = hwnd; + tvdi.hdr.idFrom = GetWindowLongPtrW(hwnd, GWLP_ID); + tvdi.hdr.code = get_notifycode(infoPtr, TVN_ENDLABELEDITW); + tvdi.item.mask = 0; + tvdi.item.hItem = editedItem; + tvdi.item.state = editedItem->state; + tvdi.item.lParam = editedItem->lParam; + + if (!bCancel) + { + if (!infoPtr->bNtfUnicode) + iLength = GetWindowTextA(infoPtr->hwndEdit, (LPSTR)tmpText, 1023); + else + iLength = GetWindowTextW(infoPtr->hwndEdit, tmpText, 1023); + + if (iLength >= 1023) + { + ERR("Insufficient space to retrieve new item label\n"); + } + + tvdi.item.mask = TVIF_TEXT; + tvdi.item.pszText = tmpText; + tvdi.item.cchTextMax = iLength + 1; + } + else + { + tvdi.item.pszText = NULL; + tvdi.item.cchTextMax = 0; + } + + bCommit = (BOOL)TREEVIEW_SendRealNotify(infoPtr, + (WPARAM)tvdi.hdr.idFrom, (LPARAM)&tvdi); + + if (!bCancel && bCommit) /* Apply the changes */ + { + if (!infoPtr->bNtfUnicode) + { + DWORD len = MultiByteToWideChar( CP_ACP, 0, (LPSTR)tmpText, -1, NULL, 0 ); + newText = Alloc(len * sizeof(WCHAR)); + MultiByteToWideChar( CP_ACP, 0, (LPSTR)tmpText, -1, newText, len ); + iLength = len - 1; + } + + if (strcmpW(newText, editedItem->pszText) != 0) + { + if (NULL == ReAlloc(editedItem->pszText, iLength + 1)) + { + ERR("OutOfMemory, cannot allocate space for label\n"); + DestroyWindow(infoPtr->hwndEdit); + infoPtr->hwndEdit = 0; + return FALSE; + } + else + { + editedItem->cchTextMax = iLength + 1; + strcpyW(editedItem->pszText, newText); + } + } + if(newText != tmpText) Free(newText); + } + + ShowWindow(infoPtr->hwndEdit, SW_HIDE); + DestroyWindow(infoPtr->hwndEdit); + infoPtr->hwndEdit = 0; + return TRUE; +} + +static LRESULT +TREEVIEW_HandleTimer(TREEVIEW_INFO *infoPtr, WPARAM wParam) +{ + if (wParam != TV_EDIT_TIMER) + { + ERR("got unknown timer\n"); + return 1; + } + + KillTimer(infoPtr->hwnd, TV_EDIT_TIMER); + infoPtr->Timer &= ~TV_EDIT_TIMER_SET; + + TREEVIEW_EditLabel(infoPtr, infoPtr->selectedItem); + + return 0; +} + + +/* Mouse Tracking/Drag **************************************************/ + +/*************************************************************************** + * This is quite unusual piece of code, but that's how it's implemented in + * Windows. + */ +static LRESULT +TREEVIEW_TrackMouse(TREEVIEW_INFO *infoPtr, POINT pt) +{ + INT cxDrag = GetSystemMetrics(SM_CXDRAG); + INT cyDrag = GetSystemMetrics(SM_CYDRAG); + RECT r; + MSG msg; + + r.top = pt.y - cyDrag; + r.left = pt.x - cxDrag; + r.bottom = pt.y + cyDrag; + r.right = pt.x + cxDrag; + + SetCapture(infoPtr->hwnd); + + while (1) + { + if (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) + { + if (msg.message == WM_MOUSEMOVE) + { + pt.x = (short)LOWORD(msg.lParam); + pt.y = (short)HIWORD(msg.lParam); + if (PtInRect(&r, pt)) + continue; + else + { + ReleaseCapture(); + return 1; + } + } + else if (msg.message >= WM_LBUTTONDOWN && + msg.message <= WM_RBUTTONDBLCLK) + { + if (msg.message == WM_RBUTTONUP) + TREEVIEW_RButtonUp(infoPtr, &pt); + break; + } + + DispatchMessageW(&msg); + } + + if (GetCapture() != infoPtr->hwnd) + return 0; + } + + ReleaseCapture(); + return 0; +} + + +static LRESULT +TREEVIEW_LButtonDoubleClick(TREEVIEW_INFO *infoPtr, LPARAM lParam) +{ + TREEVIEW_ITEM *wineItem; + TVHITTESTINFO hit; + + TRACE("\n"); + SetFocus(infoPtr->hwnd); + + if (infoPtr->Timer & TV_EDIT_TIMER_SET) + { + /* If there is pending 'edit label' event - kill it now */ + KillTimer(infoPtr->hwnd, TV_EDIT_TIMER); + } + + hit.pt.x = (short)LOWORD(lParam); + hit.pt.y = (short)HIWORD(lParam); + + wineItem = (TREEVIEW_ITEM *)TREEVIEW_HitTest(infoPtr, &hit); + if (!wineItem) + return 0; + TRACE("item %d\n", TREEVIEW_GetItemIndex(infoPtr, wineItem)); + + if (TREEVIEW_SendSimpleNotify(infoPtr, NM_DBLCLK) == FALSE) + { /* FIXME! */ + switch (hit.flags) + { + case TVHT_ONITEMRIGHT: + /* FIXME: we should not have sent NM_DBLCLK in this case. */ + break; + + case TVHT_ONITEMINDENT: + if (!(infoPtr->dwStyle & TVS_HASLINES)) + { + break; + } + else + { + int level = hit.pt.x / infoPtr->uIndent; + if (!(infoPtr->dwStyle & TVS_LINESATROOT)) level++; + + while (wineItem->iLevel > level) + { + wineItem = wineItem->parent; + } + + /* fall through */ + } + + case TVHT_ONITEMLABEL: + case TVHT_ONITEMICON: + case TVHT_ONITEMBUTTON: + TREEVIEW_Toggle(infoPtr, wineItem, TRUE); + break; + + case TVHT_ONITEMSTATEICON: + if (infoPtr->dwStyle & TVS_CHECKBOXES) + TREEVIEW_ToggleItemState(infoPtr, wineItem); + else + TREEVIEW_Toggle(infoPtr, wineItem, TRUE); + break; + } + } + return TRUE; +} + + +static LRESULT +TREEVIEW_LButtonDown(TREEVIEW_INFO *infoPtr, LPARAM lParam) +{ + HWND hwnd = infoPtr->hwnd; + TVHITTESTINFO ht; + BOOL bTrack, bDoLabelEdit; + HTREEITEM tempItem; + + /* If Edit control is active - kill it and return. + * The best way to do it is to set focus to itself. + * Edit control subclassed procedure will automatically call + * EndEditLabelNow. + */ + if (infoPtr->hwndEdit) + { + SetFocus(hwnd); + return 0; + } + + ht.pt.x = (short)LOWORD(lParam); + ht.pt.y = (short)HIWORD(lParam); + + TREEVIEW_HitTest(infoPtr, &ht); + TRACE("item %d\n", TREEVIEW_GetItemIndex(infoPtr, ht.hItem)); + + /* update focusedItem and redraw both items */ + if(ht.hItem && (ht.flags & TVHT_ONITEM)) + { + infoPtr->focusedItem = ht.hItem; + InvalidateRect(hwnd, &(((HTREEITEM)(ht.hItem))->rect), TRUE); + + if(infoPtr->selectedItem) + InvalidateRect(hwnd, &(infoPtr->selectedItem->rect), TRUE); + } + + bTrack = (ht.flags & TVHT_ONITEM) + && !(infoPtr->dwStyle & TVS_DISABLEDRAGDROP); + + /* + * If the style allows editing and the node is already selected + * and the click occurred on the item label... + */ + bDoLabelEdit = (infoPtr->dwStyle & TVS_EDITLABELS) && + (ht.flags & TVHT_ONITEMLABEL) && (infoPtr->selectedItem == ht.hItem); + + /* Send NM_CLICK right away */ + if (!bTrack) + if (TREEVIEW_SendSimpleNotify(infoPtr, NM_CLICK)) + goto setfocus; + + if (ht.flags & TVHT_ONITEMBUTTON) + { + TREEVIEW_Toggle(infoPtr, ht.hItem, TRUE); + goto setfocus; + } + else if (bTrack) + { /* if TREEVIEW_TrackMouse == 1 dragging occurred and the cursor left the dragged item's rectangle */ + if (TREEVIEW_TrackMouse(infoPtr, ht.pt)) + { + TREEVIEW_SendTreeviewDnDNotify(infoPtr, TVN_BEGINDRAGW, ht.hItem, ht.pt); + infoPtr->dropItem = ht.hItem; + + /* clean up focusedItem as we dragged and won't select this item */ + if(infoPtr->focusedItem) + { + /* refresh the item that was focused */ + tempItem = infoPtr->focusedItem; + infoPtr->focusedItem = 0; + InvalidateRect(infoPtr->hwnd, &tempItem->rect, TRUE); + + /* refresh the selected item to return the filled background */ + InvalidateRect(infoPtr->hwnd, &(infoPtr->selectedItem->rect), TRUE); + } + + return 0; + } + } + + if (bTrack && TREEVIEW_SendSimpleNotify(infoPtr, NM_CLICK)) + goto setfocus; + + if (bDoLabelEdit) + { + if (infoPtr->Timer & TV_EDIT_TIMER_SET) + KillTimer(hwnd, TV_EDIT_TIMER); + + SetTimer(hwnd, TV_EDIT_TIMER, GetDoubleClickTime(), 0); + infoPtr->Timer |= TV_EDIT_TIMER_SET; + } + else if (ht.flags & (TVHT_ONITEMICON|TVHT_ONITEMLABEL)) /* select the item if the hit was inside of the icon or text */ + { + /* + * if we are TVS_SINGLEEXPAND then we want this single click to + * do a bunch of things. + */ + if((infoPtr->dwStyle & TVS_SINGLEEXPAND) && + (infoPtr->hwndEdit == 0)) + { + TREEVIEW_ITEM *SelItem; + + /* + * Send the notification + */ + TREEVIEW_SendTreeviewNotify(infoPtr, TVN_SINGLEEXPAND, TVC_UNKNOWN, TVIF_HANDLE | TVIF_PARAM, ht.hItem, 0); + + /* + * Close the previous selection all the way to the root + * as long as the new selection is not a child + */ + if((infoPtr->selectedItem) + && (infoPtr->selectedItem != ht.hItem)) + { + BOOL closeit = TRUE; + SelItem = ht.hItem; + + /* determine if the hitItem is a child of the currently selected item */ + while(closeit && SelItem && TREEVIEW_ValidItem(infoPtr, SelItem) && (SelItem != infoPtr->root)) + { + closeit = (SelItem != infoPtr->selectedItem); + SelItem = SelItem->parent; + } + + if(closeit) + { + if(TREEVIEW_ValidItem(infoPtr, infoPtr->selectedItem)) + SelItem = infoPtr->selectedItem; + + while(SelItem && (SelItem != ht.hItem) && TREEVIEW_ValidItem(infoPtr, SelItem) && (SelItem != infoPtr->root)) + { + TREEVIEW_Collapse(infoPtr, SelItem, FALSE, FALSE); + SelItem = SelItem->parent; + } + } + } + + /* + * Expand the current item + */ + TREEVIEW_Expand(infoPtr, ht.hItem, TVE_TOGGLE, FALSE); + } + + /* Select the current item */ + TREEVIEW_DoSelectItem(infoPtr, TVGN_CARET, ht.hItem, TVC_BYMOUSE); + } + else if (ht.flags & TVHT_ONITEMSTATEICON) + { + /* TVS_CHECKBOXES requires us to toggle the current state */ + if (infoPtr->dwStyle & TVS_CHECKBOXES) + TREEVIEW_ToggleItemState(infoPtr, ht.hItem); + } + + setfocus: + SetFocus(hwnd); + return 0; +} + + +static LRESULT +TREEVIEW_RButtonDown(TREEVIEW_INFO *infoPtr, LPARAM lParam) +{ + TVHITTESTINFO ht; + + if (infoPtr->hwndEdit) + { + SetFocus(infoPtr->hwnd); + return 0; + } + + ht.pt.x = (short)LOWORD(lParam); + ht.pt.y = (short)HIWORD(lParam); + + TREEVIEW_HitTest(infoPtr, &ht); + + if (TREEVIEW_TrackMouse(infoPtr, ht.pt)) + { + if (ht.hItem) + { + TREEVIEW_SendTreeviewDnDNotify(infoPtr, TVN_BEGINRDRAGW, ht.hItem, ht.pt); + infoPtr->dropItem = ht.hItem; + } + } + else + { + SetFocus(infoPtr->hwnd); + TREEVIEW_SendSimpleNotify(infoPtr, NM_RCLICK); + } + + return 0; +} + +static LRESULT +TREEVIEW_RButtonUp(TREEVIEW_INFO *infoPtr, LPPOINT pPt) +{ + return 0; +} + + +static LRESULT +TREEVIEW_CreateDragImage(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + TREEVIEW_ITEM *dragItem = (HTREEITEM)lParam; + INT cx, cy; + HDC hdc, htopdc; + HWND hwtop; + HBITMAP hbmp, hOldbmp; + SIZE size; + RECT rc; + HFONT hOldFont; + + TRACE("\n"); + + if (!(infoPtr->himlNormal)) + return 0; + + if (!dragItem || !TREEVIEW_ValidItem(infoPtr, dragItem)) + return 0; + + TREEVIEW_UpdateDispInfo(infoPtr, dragItem, TVIF_TEXT); + + hwtop = GetDesktopWindow(); + htopdc = GetDC(hwtop); + hdc = CreateCompatibleDC(htopdc); + + hOldFont = SelectObject(hdc, infoPtr->hFont); + GetTextExtentPoint32W(hdc, dragItem->pszText, strlenW(dragItem->pszText), + &size); + TRACE("%ld %ld %s %d\n", size.cx, size.cy, debugstr_w(dragItem->pszText), + strlenW(dragItem->pszText)); + hbmp = CreateCompatibleBitmap(htopdc, size.cx, size.cy); + hOldbmp = SelectObject(hdc, hbmp); + + ImageList_GetIconSize(infoPtr->himlNormal, &cx, &cy); + size.cx += cx; + if (cy > size.cy) + size.cy = cy; + + infoPtr->dragList = ImageList_Create(size.cx, size.cy, ILC_COLOR, 10, 10); + ImageList_Draw(infoPtr->himlNormal, dragItem->iImage, hdc, 0, 0, + ILD_NORMAL); + +/* + ImageList_GetImageInfo (infoPtr->himlNormal, dragItem->hItem, &iminfo); + ImageList_AddMasked (infoPtr->dragList, iminfo.hbmImage, CLR_DEFAULT); +*/ + +/* draw item text */ + + SetRect(&rc, cx, 0, size.cx, size.cy); + DrawTextW(hdc, dragItem->pszText, strlenW(dragItem->pszText), &rc, + DT_LEFT); + SelectObject(hdc, hOldFont); + SelectObject(hdc, hOldbmp); + + ImageList_Add(infoPtr->dragList, hbmp, 0); + + DeleteDC(hdc); + DeleteObject(hbmp); + ReleaseDC(hwtop, htopdc); + + return (LRESULT)infoPtr->dragList; +} + +/* Selection ************************************************************/ + +static LRESULT +TREEVIEW_DoSelectItem(TREEVIEW_INFO *infoPtr, INT action, HTREEITEM newSelect, + INT cause) +{ + TREEVIEW_ITEM *prevSelect; + RECT rcFocused; + + assert(newSelect == NULL || TREEVIEW_ValidItem(infoPtr, newSelect)); + + TRACE("Entering item %p (%s), flag %x, cause %x, state %d\n", + newSelect, TREEVIEW_ItemName(newSelect), action, cause, + newSelect ? newSelect->state : 0); + + /* reset and redraw focusedItem if focusedItem was set so we don't */ + /* have to worry about the previously focused item when we set a new one */ + if(infoPtr->focusedItem) + { + rcFocused = (infoPtr->focusedItem)->rect; + infoPtr->focusedItem = 0; + InvalidateRect(infoPtr->hwnd, &rcFocused, TRUE); + } + + switch (action) + { + case TVGN_CARET: + prevSelect = infoPtr->selectedItem; + + if (prevSelect == newSelect) { + TREEVIEW_EnsureVisible(infoPtr, infoPtr->selectedItem, FALSE); + break; + } + + if (TREEVIEW_SendTreeviewNotify(infoPtr, + TVN_SELCHANGINGW, + cause, + TVIF_HANDLE | TVIF_STATE | TVIF_PARAM, + prevSelect, + newSelect)) + return FALSE; + + if (prevSelect) + prevSelect->state &= ~TVIS_SELECTED; + if (newSelect) + newSelect->state |= TVIS_SELECTED; + + infoPtr->selectedItem = newSelect; + + TREEVIEW_EnsureVisible(infoPtr, infoPtr->selectedItem, FALSE); + + if (prevSelect) + TREEVIEW_Invalidate(infoPtr, prevSelect); + if (newSelect) + TREEVIEW_Invalidate(infoPtr, newSelect); + + TREEVIEW_SendTreeviewNotify(infoPtr, + TVN_SELCHANGEDW, + cause, + TVIF_HANDLE | TVIF_STATE | TVIF_PARAM, + prevSelect, + newSelect); + break; + + case TVGN_DROPHILITE: + prevSelect = infoPtr->dropItem; + + if (prevSelect) + prevSelect->state &= ~TVIS_DROPHILITED; + + infoPtr->dropItem = newSelect; + + if (newSelect) + newSelect->state |= TVIS_DROPHILITED; + + TREEVIEW_Invalidate(infoPtr, prevSelect); + TREEVIEW_Invalidate(infoPtr, newSelect); + break; + + case TVGN_FIRSTVISIBLE: + if (newSelect != NULL) + { + TREEVIEW_EnsureVisible(infoPtr, newSelect, FALSE); + TREEVIEW_SetFirstVisible(infoPtr, newSelect, TRUE); + TREEVIEW_Invalidate(infoPtr, NULL); + } + break; + } + + TRACE("Leaving state %d\n", newSelect ? newSelect->state : 0); + return TRUE; +} + +/* FIXME: handle NM_KILLFOCUS etc */ +static LRESULT +TREEVIEW_SelectItem(TREEVIEW_INFO *infoPtr, INT wParam, HTREEITEM item) +{ + if (item != NULL && !TREEVIEW_ValidItem(infoPtr, item)) + return FALSE; + + TRACE("%p (%s) %d\n", item, TREEVIEW_ItemName(item), wParam); + + if (!TREEVIEW_DoSelectItem(infoPtr, wParam, item, TVC_UNKNOWN)) + return FALSE; + + return TRUE; +} + +/************************************************************************* + * TREEVIEW_ProcessLetterKeys + * + * Processes keyboard messages generated by pressing the letter keys + * on the keyboard. + * What this does is perform a case insensitive search from the + * current position with the following quirks: + * - If two chars or more are pressed in quick succession we search + * for the corresponding string (e.g. 'abc'). + * - If there is a delay we wipe away the current search string and + * restart with just that char. + * - If the user keeps pressing the same character, whether slowly or + * fast, so that the search string is entirely composed of this + * character ('aaaaa' for instance), then we search for first item + * that starting with that character. + * - If the user types the above character in quick succession, then + * we must also search for the corresponding string ('aaaaa'), and + * go to that string if there is a match. + * + * RETURNS + * + * Zero. + * + * BUGS + * + * - The current implementation has a list of characters it will + * accept and it ignores averything else. In particular it will + * ignore accentuated characters which seems to match what + * Windows does. But I'm not sure it makes sense to follow + * Windows there. + * - We don't sound a beep when the search fails. + * - The search should start from the focused item, not from the selected + * item. One reason for this is to allow for multiple selections in trees. + * But currently infoPtr->focusedItem does not seem very usable. + * + * SEE ALSO + * + * TREEVIEW_ProcessLetterKeys + */ +static INT TREEVIEW_ProcessLetterKeys( + HWND hwnd, /* handle to the window */ + WPARAM charCode, /* the character code, the actual character */ + LPARAM keyData /* key data */ + ) +{ + TREEVIEW_INFO *infoPtr; + HTREEITEM nItem; + HTREEITEM endidx,idx; + TVITEMEXW item; + WCHAR buffer[MAX_PATH]; + DWORD timestamp,elapsed; + + /* simple parameter checking */ + if (!hwnd || !charCode || !keyData) + return 0; + + infoPtr=(TREEVIEW_INFO*)GetWindowLongPtrW(hwnd, 0); + if (!infoPtr) + return 0; + + /* only allow the valid WM_CHARs through */ + if (!isalnum(charCode) && + charCode != '.' && charCode != '`' && charCode != '!' && + charCode != '@' && charCode != '#' && charCode != '$' && + charCode != '%' && charCode != '^' && charCode != '&' && + charCode != '*' && charCode != '(' && charCode != ')' && + charCode != '-' && charCode != '_' && charCode != '+' && + charCode != '=' && charCode != '\\'&& charCode != ']' && + charCode != '}' && charCode != '[' && charCode != '{' && + charCode != '/' && charCode != '?' && charCode != '>' && + charCode != '<' && charCode != ',' && charCode != '~') + return 0; + + /* compute how much time elapsed since last keypress */ + timestamp = GetTickCount(); + if (timestamp > infoPtr->lastKeyPressTimestamp) { + elapsed=timestamp-infoPtr->lastKeyPressTimestamp; + } else { + elapsed=infoPtr->lastKeyPressTimestamp-timestamp; + } + + /* update the search parameters */ + infoPtr->lastKeyPressTimestamp=timestamp; + if (elapsed < KEY_DELAY) { + if (infoPtr->nSearchParamLength < sizeof(infoPtr->szSearchParam) / sizeof(WCHAR)) { + infoPtr->szSearchParam[infoPtr->nSearchParamLength++]=charCode; + } + if (infoPtr->charCode != charCode) { + infoPtr->charCode=charCode=0; + } + } else { + infoPtr->charCode=charCode; + infoPtr->szSearchParam[0]=charCode; + infoPtr->nSearchParamLength=1; + /* Redundant with the 1 char string */ + charCode=0; + } + + /* and search from the current position */ + nItem=NULL; + if (infoPtr->selectedItem != NULL) { + endidx=infoPtr->selectedItem; + /* if looking for single character match, + * then we must always move forward + */ + if (infoPtr->nSearchParamLength == 1) + idx=TREEVIEW_GetNextListItem(infoPtr,endidx); + else + idx=endidx; + } else { + endidx=NULL; + idx=infoPtr->root->firstChild; + } + do { + /* At the end point, sort out wrapping */ + if (idx == NULL) { + + /* If endidx is null, stop at the last item (ie top to bottom) */ + if (endidx == NULL) + break; + + /* Otherwise, start again at the very beginning */ + idx=infoPtr->root->firstChild; + + /* But if we are stopping on the first child, end now! */ + if (idx == endidx) break; + } + + /* get item */ + ZeroMemory(&item, sizeof(item)); + item.mask = TVIF_TEXT; + item.hItem = idx; + item.pszText = buffer; + item.cchTextMax = sizeof(buffer); + TREEVIEW_GetItemT( infoPtr, &item, TRUE ); + + /* check for a match */ + if (strncmpiW(item.pszText,infoPtr->szSearchParam,infoPtr->nSearchParamLength) == 0) { + nItem=idx; + break; + } else if ( (charCode != 0) && (nItem == NULL) && + (nItem != infoPtr->selectedItem) && + (strncmpiW(item.pszText,infoPtr->szSearchParam,1) == 0) ) { + /* This would work but we must keep looking for a longer match */ + nItem=idx; + } + idx=TREEVIEW_GetNextListItem(infoPtr,idx); + } while (idx != endidx); + + if (nItem != NULL) { + if (TREEVIEW_DoSelectItem(infoPtr, TVGN_CARET, nItem, TVC_BYKEYBOARD)) { + TREEVIEW_EnsureVisible(infoPtr, nItem, FALSE); + } + } + + return 0; +} + +/* Scrolling ************************************************************/ + +static LRESULT +TREEVIEW_EnsureVisible(TREEVIEW_INFO *infoPtr, HTREEITEM item, BOOL bHScroll) +{ + int viscount; + BOOL hasFirstVisible = infoPtr->firstVisible != NULL; + HTREEITEM newFirstVisible = NULL; + int visible_pos = -1; + + if (!TREEVIEW_ValidItem(infoPtr, item)) + return FALSE; + + if (!ISVISIBLE(item)) + { + /* Expand parents as necessary. */ + HTREEITEM parent; + + /* see if we are trying to ensure that root is vislble */ + if((item != infoPtr->root) && TREEVIEW_ValidItem(infoPtr, item)) + parent = item->parent; + else + parent = item; /* this item is the topmost item */ + + while (parent != infoPtr->root) + { + if (!(parent->state & TVIS_EXPANDED)) + TREEVIEW_Expand(infoPtr, parent, FALSE, FALSE); + + parent = parent->parent; + } + } + + viscount = TREEVIEW_GetVisibleCount(infoPtr); + + TRACE("%p (%s) %ld - %ld viscount(%d)\n", item, TREEVIEW_ItemName(item), item->visibleOrder, + hasFirstVisible ? infoPtr->firstVisible->visibleOrder : -1, viscount); + + if (hasFirstVisible) + visible_pos = item->visibleOrder - infoPtr->firstVisible->visibleOrder; + + if (visible_pos < 0) + { + /* item is before the start of the list: put it at the top. */ + newFirstVisible = item; + } + else if (visible_pos >= viscount + /* Sometimes, before we are displayed, GVC is 0, causing us to + * spuriously scroll up. */ + && visible_pos > 0 && !(infoPtr->dwStyle & TVS_NOSCROLL) ) + { + /* item is past the end of the list. */ + int scroll = visible_pos - viscount; + + newFirstVisible = TREEVIEW_GetListItem(infoPtr, infoPtr->firstVisible, + scroll + 1); + } + + if (bHScroll) + { + /* Scroll window so item's text is visible as much as possible */ + /* Calculation of amount of extra space is taken from EditLabel code */ + INT pos, x; + TEXTMETRICW textMetric; + HDC hdc = GetWindowDC(infoPtr->hwnd); + + x = item->textWidth; + + GetTextMetricsW(hdc, &textMetric); + ReleaseDC(infoPtr->hwnd, hdc); + + x += (textMetric.tmMaxCharWidth * 2); + x = max(x, textMetric.tmMaxCharWidth * 3); + + if (item->textOffset < 0) + pos = item->textOffset; + else if (item->textOffset + x > infoPtr->clientWidth) + { + if (x > infoPtr->clientWidth) + pos = item->textOffset; + else + pos = item->textOffset + x - infoPtr->clientWidth; + } + else + pos = 0; + + TREEVIEW_HScroll(infoPtr, MAKEWPARAM(SB_THUMBPOSITION, infoPtr->scrollX + pos)); + } + + if (newFirstVisible != NULL && newFirstVisible != infoPtr->firstVisible) + { + TREEVIEW_SetFirstVisible(infoPtr, newFirstVisible, TRUE); + + return TRUE; + } + + return FALSE; +} + +static VOID +TREEVIEW_SetFirstVisible(TREEVIEW_INFO *infoPtr, + TREEVIEW_ITEM *newFirstVisible, + BOOL bUpdateScrollPos) +{ + int gap_size; + + TRACE("%p: %s\n", newFirstVisible, TREEVIEW_ItemName(newFirstVisible)); + + if (newFirstVisible != NULL) + { + /* Prevent an empty gap from appearing at the bottom... */ + gap_size = TREEVIEW_GetVisibleCount(infoPtr) + - infoPtr->maxVisibleOrder + newFirstVisible->visibleOrder; + + if (gap_size > 0) + { + newFirstVisible = TREEVIEW_GetListItem(infoPtr, newFirstVisible, + -gap_size); + + /* ... unless we just don't have enough items. */ + if (newFirstVisible == NULL) + newFirstVisible = infoPtr->root->firstChild; + } + } + + if (infoPtr->firstVisible != newFirstVisible) + { + if (infoPtr->firstVisible == NULL || newFirstVisible == NULL) + { + infoPtr->firstVisible = newFirstVisible; + TREEVIEW_Invalidate(infoPtr, NULL); + } + else + { + TREEVIEW_ITEM *item; + int scroll = infoPtr->uItemHeight * + (infoPtr->firstVisible->visibleOrder + - newFirstVisible->visibleOrder); + + infoPtr->firstVisible = newFirstVisible; + + for (item = infoPtr->root->firstChild; item != NULL; + item = TREEVIEW_GetNextListItem(infoPtr, item)) + { + item->rect.top += scroll; + item->rect.bottom += scroll; + } + + if (bUpdateScrollPos) + SetScrollPos(infoPtr->hwnd, SB_VERT, + newFirstVisible->visibleOrder, TRUE); + + ScrollWindowEx(infoPtr->hwnd, 0, scroll, NULL, NULL, NULL, NULL, SW_ERASE | SW_INVALIDATE); + } + } +} + +/************************************************************************ + * VScroll is always in units of visible items. i.e. we always have a + * visible item aligned to the top of the control. (Unless we have no + * items at all.) + */ +static LRESULT +TREEVIEW_VScroll(TREEVIEW_INFO *infoPtr, WPARAM wParam) +{ + TREEVIEW_ITEM *oldFirstVisible = infoPtr->firstVisible; + TREEVIEW_ITEM *newFirstVisible = NULL; + + int nScrollCode = LOWORD(wParam); + + TRACE("wp %x\n", wParam); + + if (!(infoPtr->uInternalStatus & TV_VSCROLL)) + return 0; + + if (infoPtr->hwndEdit) + SetFocus(infoPtr->hwnd); + + if (!oldFirstVisible) + { + assert(infoPtr->root->firstChild == NULL); + return 0; + } + + switch (nScrollCode) + { + case SB_TOP: + newFirstVisible = infoPtr->root->firstChild; + break; + + case SB_BOTTOM: + newFirstVisible = TREEVIEW_GetLastListItem(infoPtr, infoPtr->root); + break; + + case SB_LINEUP: + newFirstVisible = TREEVIEW_GetPrevListItem(infoPtr, oldFirstVisible); + break; + + case SB_LINEDOWN: + newFirstVisible = TREEVIEW_GetNextListItem(infoPtr, oldFirstVisible); + break; + + case SB_PAGEUP: + newFirstVisible = TREEVIEW_GetListItem(infoPtr, oldFirstVisible, + -max(1, TREEVIEW_GetVisibleCount(infoPtr))); + break; + + case SB_PAGEDOWN: + newFirstVisible = TREEVIEW_GetListItem(infoPtr, oldFirstVisible, + max(1, TREEVIEW_GetVisibleCount(infoPtr))); + break; + + case SB_THUMBTRACK: + case SB_THUMBPOSITION: + newFirstVisible = TREEVIEW_GetListItem(infoPtr, + infoPtr->root->firstChild, + (LONG)(SHORT)HIWORD(wParam)); + break; + + case SB_ENDSCROLL: + return 0; + } + + if (newFirstVisible != NULL) + { + if (newFirstVisible != oldFirstVisible) + TREEVIEW_SetFirstVisible(infoPtr, newFirstVisible, + nScrollCode != SB_THUMBTRACK); + else if (nScrollCode == SB_THUMBPOSITION) + SetScrollPos(infoPtr->hwnd, SB_VERT, + newFirstVisible->visibleOrder, TRUE); + } + + return 0; +} + +static LRESULT +TREEVIEW_HScroll(TREEVIEW_INFO *infoPtr, WPARAM wParam) +{ + int maxWidth; + int scrollX = infoPtr->scrollX; + int nScrollCode = LOWORD(wParam); + + TRACE("wp %x\n", wParam); + + if (!(infoPtr->uInternalStatus & TV_HSCROLL)) + return FALSE; + + if (infoPtr->hwndEdit) + SetFocus(infoPtr->hwnd); + + maxWidth = infoPtr->treeWidth - infoPtr->clientWidth; + /* shall never occur */ + if (maxWidth <= 0) + { + scrollX = 0; + goto scroll; + } + + switch (nScrollCode) + { + case SB_LINELEFT: + scrollX -= infoPtr->uItemHeight; + break; + case SB_LINERIGHT: + scrollX += infoPtr->uItemHeight; + break; + case SB_PAGELEFT: + scrollX -= infoPtr->clientWidth; + break; + case SB_PAGERIGHT: + scrollX += infoPtr->clientWidth; + break; + + case SB_THUMBTRACK: + case SB_THUMBPOSITION: + scrollX = (int)(SHORT)HIWORD(wParam); + break; + + case SB_ENDSCROLL: + return 0; + } + + if (scrollX > maxWidth) + scrollX = maxWidth; + else if (scrollX < 0) + scrollX = 0; + +scroll: + if (scrollX != infoPtr->scrollX) + { + TREEVIEW_ITEM *item; + LONG scroll_pixels = infoPtr->scrollX - scrollX; + + for (item = infoPtr->root->firstChild; item != NULL; + item = TREEVIEW_GetNextListItem(infoPtr, item)) + { + item->linesOffset += scroll_pixels; + item->stateOffset += scroll_pixels; + item->imageOffset += scroll_pixels; + item->textOffset += scroll_pixels; + } + + ScrollWindow(infoPtr->hwnd, scroll_pixels, 0, NULL, NULL); + infoPtr->scrollX = scrollX; + UpdateWindow(infoPtr->hwnd); + } + + if (nScrollCode != SB_THUMBTRACK) + SetScrollPos(infoPtr->hwnd, SB_HORZ, scrollX, TRUE); + + return 0; +} + +static LRESULT +TREEVIEW_MouseWheel(TREEVIEW_INFO *infoPtr, WPARAM wParam) +{ + short gcWheelDelta; + UINT pulScrollLines = 3; + + if (infoPtr->firstVisible == NULL) + return TRUE; + + SystemParametersInfoW(SPI_GETWHEELSCROLLLINES, 0, &pulScrollLines, 0); + + gcWheelDelta = -(short)HIWORD(wParam); + pulScrollLines *= (gcWheelDelta / WHEEL_DELTA); + + if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines) + { + int newDy = infoPtr->firstVisible->visibleOrder + pulScrollLines; + int maxDy = infoPtr->maxVisibleOrder; + + if (newDy > maxDy) + newDy = maxDy; + + if (newDy < 0) + newDy = 0; + + TREEVIEW_VScroll(infoPtr, MAKEWPARAM(SB_THUMBPOSITION, newDy)); + } + return TRUE; +} + +/* Create/Destroy *******************************************************/ + +static LRESULT +TREEVIEW_Create(HWND hwnd, const CREATESTRUCTW *lpcs) +{ + static const WCHAR szDisplayW[] = { 'D','I','S','P','L','A','Y','\0' }; + RECT rcClient; + TREEVIEW_INFO *infoPtr; + LOGFONTW lf; + + TRACE("wnd %p, style %lx\n", hwnd, GetWindowLongW(hwnd, GWL_STYLE)); + + infoPtr = (TREEVIEW_INFO *)Alloc(sizeof(TREEVIEW_INFO)); + + if (infoPtr == NULL) + { + ERR("could not allocate info memory!\n"); + return 0; + } + + SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)infoPtr); + + infoPtr->hwnd = hwnd; + infoPtr->dwStyle = GetWindowLongW(hwnd, GWL_STYLE); + infoPtr->Timer = 0; + infoPtr->uNumItems = 0; + infoPtr->cdmode = 0; + infoPtr->uScrollTime = 300; /* milliseconds */ + infoPtr->bRedraw = TRUE; + + GetClientRect(hwnd, &rcClient); + + /* No scroll bars yet. */ + infoPtr->clientWidth = rcClient.right; + infoPtr->clientHeight = rcClient.bottom; + infoPtr->uInternalStatus = 0; + + infoPtr->treeWidth = 0; + infoPtr->treeHeight = 0; + + infoPtr->uIndent = MINIMUM_INDENT; + infoPtr->selectedItem = 0; + infoPtr->focusedItem = 0; + infoPtr->hotItem = 0; + infoPtr->firstVisible = 0; + infoPtr->maxVisibleOrder = 0; + infoPtr->dropItem = 0; + infoPtr->insertMarkItem = 0; + infoPtr->insertBeforeorAfter = 0; + /* dragList */ + + infoPtr->scrollX = 0; + + infoPtr->clrBk = GetSysColor(COLOR_WINDOW); + infoPtr->clrText = -1; /* use system color */ + infoPtr->clrLine = RGB(128, 128, 128); + infoPtr->clrInsertMark = GetSysColor(COLOR_BTNTEXT); + + /* hwndToolTip */ + + infoPtr->hwndEdit = 0; + infoPtr->wpEditOrig = NULL; + infoPtr->bIgnoreEditKillFocus = FALSE; + infoPtr->bLabelChanged = FALSE; + + infoPtr->himlNormal = NULL; + infoPtr->himlState = NULL; + infoPtr->normalImageWidth = 0; + infoPtr->normalImageHeight = 0; + infoPtr->stateImageWidth = 0; + infoPtr->stateImageHeight = 0; + + infoPtr->items = DPA_Create(16); + + SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0); + infoPtr->hFont = infoPtr->hDefaultFont = CreateFontIndirectW(&lf); + infoPtr->hBoldFont = TREEVIEW_CreateBoldFont(infoPtr->hFont); + infoPtr->hUnderlineFont = TREEVIEW_CreateUnderlineFont(infoPtr->hFont); + infoPtr->hcurHand = LoadCursorW(NULL, (LPWSTR)IDC_HAND); + + infoPtr->uItemHeight = TREEVIEW_NaturalHeight(infoPtr); + + infoPtr->root = TREEVIEW_AllocateItem(infoPtr); + infoPtr->root->state = TVIS_EXPANDED; + infoPtr->root->iLevel = -1; + infoPtr->root->visibleOrder = -1; + + infoPtr->hwndNotify = lpcs->hwndParent; +#if 0 + infoPtr->bTransparent = ( GetWindowLongW( hwnd, GWL_STYLE) & TBSTYLE_FLAT); +#endif + + infoPtr->hwndToolTip = 0; + + infoPtr->bNtfUnicode = IsWindowUnicode (hwnd); + + /* Determine what type of notify should be issued */ + /* sets infoPtr->bNtfUnicode */ + TREEVIEW_NotifyFormat(infoPtr, infoPtr->hwndNotify, NF_REQUERY); + + if (!(infoPtr->dwStyle & TVS_NOTOOLTIPS)) + infoPtr->hwndToolTip = COMCTL32_CreateToolTip(hwnd); + + if (infoPtr->dwStyle & TVS_CHECKBOXES) + { + RECT rc; + HBITMAP hbm, hbmOld; + HDC hdc,hdcScreen; + int nIndex; + + infoPtr->himlState = + ImageList_Create(16, 16, ILC_COLOR | ILC_MASK, 3, 0); + + hdcScreen = CreateDCW(szDisplayW, NULL, NULL, NULL); + + /* Create a coloured bitmap compatible with the screen depth + because checkboxes are not black&white */ + hdc = CreateCompatibleDC(hdcScreen); + hbm = CreateCompatibleBitmap(hdcScreen, 48, 16); + hbmOld = SelectObject(hdc, hbm); + + rc.left = 0; rc.top = 0; + rc.right = 48; rc.bottom = 16; + FillRect(hdc, &rc, (HBRUSH)(COLOR_WINDOW+1)); + + rc.left = 18; rc.top = 2; + rc.right = 30; rc.bottom = 14; + DrawFrameControl(hdc, &rc, DFC_BUTTON, + DFCS_BUTTONCHECK|DFCS_FLAT); + + rc.left = 34; rc.right = 46; + DrawFrameControl(hdc, &rc, DFC_BUTTON, + DFCS_BUTTONCHECK|DFCS_FLAT|DFCS_CHECKED); + + SelectObject(hdc, hbmOld); + nIndex = ImageList_AddMasked(infoPtr->himlState, hbm, + GetSysColor(COLOR_WINDOW)); + TRACE("checkbox index %d\n", nIndex); + + DeleteObject(hbm); + DeleteDC(hdc); + DeleteDC(hdcScreen); + + infoPtr->stateImageWidth = 16; + infoPtr->stateImageHeight = 16; + } + + /* Make sure actual scrollbar state is consistent with uInternalStatus */ + ShowScrollBar(hwnd, SB_VERT, FALSE); + ShowScrollBar(hwnd, SB_HORZ, FALSE); + + return 0; +} + + +static LRESULT +TREEVIEW_Destroy(TREEVIEW_INFO *infoPtr) +{ + TRACE("\n"); + + TREEVIEW_RemoveTree(infoPtr); + + /* tool tip is automatically destroyed: we are its owner */ + + /* Restore original wndproc */ + if (infoPtr->hwndEdit) + SetWindowLongPtrW(infoPtr->hwndEdit, GWLP_WNDPROC, + (DWORD_PTR)infoPtr->wpEditOrig); + + /* Deassociate treeview from the window before doing anything drastic. */ + SetWindowLongPtrW(infoPtr->hwnd, 0, (DWORD_PTR)NULL); + + DeleteObject(infoPtr->hDefaultFont); + DeleteObject(infoPtr->hBoldFont); + DeleteObject(infoPtr->hUnderlineFont); + Free(infoPtr); + + return 0; +} + +/* Miscellaneous Messages ***********************************************/ + +static LRESULT +TREEVIEW_ScrollKeyDown(TREEVIEW_INFO *infoPtr, WPARAM key) +{ + static const struct + { + unsigned char code; + } + scroll[] = + { +#define SCROLL_ENTRY(dir, code) { ((dir) << 7) | (code) } + SCROLL_ENTRY(SB_VERT, SB_PAGEUP), /* VK_PRIOR */ + SCROLL_ENTRY(SB_VERT, SB_PAGEDOWN), /* VK_NEXT */ + SCROLL_ENTRY(SB_VERT, SB_BOTTOM), /* VK_END */ + SCROLL_ENTRY(SB_VERT, SB_TOP), /* VK_HOME */ + SCROLL_ENTRY(SB_HORZ, SB_LINEUP), /* VK_LEFT */ + SCROLL_ENTRY(SB_VERT, SB_LINEUP), /* VK_UP */ + SCROLL_ENTRY(SB_HORZ, SB_LINEDOWN), /* VK_RIGHT */ + SCROLL_ENTRY(SB_VERT, SB_LINEDOWN) /* VK_DOWN */ +#undef SCROLL_ENTRY + }; + + if (key >= VK_PRIOR && key <= VK_DOWN) + { + unsigned char code = scroll[key - VK_PRIOR].code; + + (((code & (1 << 7)) == (SB_HORZ << 7)) + ? TREEVIEW_HScroll + : TREEVIEW_VScroll)(infoPtr, code & 0x7F); + } + + return 0; +} + +/************************************************************************ + * TREEVIEW_KeyDown + * + * VK_UP Move selection to the previous non-hidden item. + * VK_DOWN Move selection to the next non-hidden item. + * VK_HOME Move selection to the first item. + * VK_END Move selection to the last item. + * VK_LEFT If expanded then collapse, otherwise move to parent. + * VK_RIGHT If collapsed then expand, otherwise move to first child. + * VK_ADD Expand. + * VK_SUBTRACT Collapse. + * VK_MULTIPLY Expand all. + * VK_PRIOR Move up GetVisibleCount items. + * VK_NEXT Move down GetVisibleCount items. + * VK_BACK Move to parent. + * CTRL-Left,Right,Up,Down,PgUp,PgDown,Home,End: Scroll without changing selection + */ +static LRESULT +TREEVIEW_KeyDown(TREEVIEW_INFO *infoPtr, WPARAM wParam) +{ + /* If it is non-NULL and different, it will be selected and visible. */ + TREEVIEW_ITEM *newSelection = NULL; + + TREEVIEW_ITEM *prevItem = infoPtr->selectedItem; + + TRACE("%x\n", wParam); + + if (prevItem == NULL) + return FALSE; + + if (GetAsyncKeyState(VK_CONTROL) & 0x8000) + return TREEVIEW_ScrollKeyDown(infoPtr, wParam); + + switch (wParam) + { + case VK_UP: + newSelection = TREEVIEW_GetPrevListItem(infoPtr, prevItem); + if (!newSelection) + newSelection = infoPtr->root->firstChild; + break; + + case VK_DOWN: + newSelection = TREEVIEW_GetNextListItem(infoPtr, prevItem); + break; + + case VK_HOME: + newSelection = infoPtr->root->firstChild; + break; + + case VK_END: + newSelection = TREEVIEW_GetLastListItem(infoPtr, infoPtr->root); + break; + + case VK_LEFT: + if (prevItem->state & TVIS_EXPANDED) + { + TREEVIEW_Collapse(infoPtr, prevItem, FALSE, TRUE); + } + else if (prevItem->parent != infoPtr->root) + { + newSelection = prevItem->parent; + } + break; + + case VK_RIGHT: + if (TREEVIEW_HasChildren(infoPtr, prevItem)) + { + if (!(prevItem->state & TVIS_EXPANDED)) + TREEVIEW_Expand(infoPtr, prevItem, FALSE, TRUE); + else + { + newSelection = prevItem->firstChild; + } + } + + break; + + case VK_MULTIPLY: + TREEVIEW_ExpandAll(infoPtr, prevItem); + break; + + case VK_ADD: + if (!(prevItem->state & TVIS_EXPANDED)) + TREEVIEW_Expand(infoPtr, prevItem, FALSE, TRUE); + break; + + case VK_SUBTRACT: + if (prevItem->state & TVIS_EXPANDED) + TREEVIEW_Collapse(infoPtr, prevItem, FALSE, TRUE); + break; + + case VK_PRIOR: + newSelection + = TREEVIEW_GetListItem(infoPtr, prevItem, + -TREEVIEW_GetVisibleCount(infoPtr)); + break; + + case VK_NEXT: + newSelection + = TREEVIEW_GetListItem(infoPtr, prevItem, + TREEVIEW_GetVisibleCount(infoPtr)); + break; + + case VK_BACK: + newSelection = prevItem->parent; + if (newSelection == infoPtr->root) + newSelection = NULL; + break; + + case VK_SPACE: + if (infoPtr->dwStyle & TVS_CHECKBOXES) + TREEVIEW_ToggleItemState(infoPtr, prevItem); + break; + } + + if (newSelection && newSelection != prevItem) + { + if (TREEVIEW_DoSelectItem(infoPtr, TVGN_CARET, newSelection, + TVC_BYKEYBOARD)) + { + TREEVIEW_EnsureVisible(infoPtr, newSelection, FALSE); + } + } + + return FALSE; +} + +static LRESULT +TREEVIEW_MouseLeave (TREEVIEW_INFO * infoPtr) +{ + if (infoPtr->hotItem) + { + /* remove hot effect from item */ + InvalidateRect(infoPtr->hwnd, &infoPtr->hotItem->rect, TRUE); + infoPtr->hotItem = NULL; + } + return 0; +} + +static LRESULT +TREEVIEW_MouseMove (TREEVIEW_INFO * infoPtr, WPARAM wParam, LPARAM lParam) +{ + POINT pt; + TRACKMOUSEEVENT trackinfo; + TREEVIEW_ITEM * item; + + /* fill in the TRACKMOUSEEVENT struct */ + trackinfo.cbSize = sizeof(TRACKMOUSEEVENT); + trackinfo.dwFlags = TME_QUERY; + trackinfo.hwndTrack = infoPtr->hwnd; + trackinfo.dwHoverTime = HOVER_DEFAULT; + + /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */ + _TrackMouseEvent(&trackinfo); + + /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */ + if(!(trackinfo.dwFlags & TME_LEAVE)) + { + trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */ + + /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */ + /* and can properly deactivate the hot item */ + _TrackMouseEvent(&trackinfo); + } + + pt.x = (INT)LOWORD(lParam); + pt.y = (INT)HIWORD(lParam); + + item = TREEVIEW_HitTestPoint(infoPtr, pt); + + if (item != infoPtr->hotItem) + { + /* redraw old hot item */ + if (infoPtr->hotItem) + InvalidateRect(infoPtr->hwnd, &infoPtr->hotItem->rect, TRUE); + infoPtr->hotItem = item; + /* redraw new hot item */ + if (infoPtr->hotItem) + InvalidateRect(infoPtr->hwnd, &infoPtr->hotItem->rect, TRUE); + } + + return 0; +} + +static LRESULT +TREEVIEW_Notify(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + LPNMHDR lpnmh = (LPNMHDR)lParam; + + if (lpnmh->code == PGN_CALCSIZE) { + LPNMPGCALCSIZE lppgc = (LPNMPGCALCSIZE)lParam; + + if (lppgc->dwFlag == PGF_CALCWIDTH) { + lppgc->iWidth = infoPtr->treeWidth; + TRACE("got PGN_CALCSIZE, returning horz size = %ld, client=%ld\n", + infoPtr->treeWidth, infoPtr->clientWidth); + } + else { + lppgc->iHeight = infoPtr->treeHeight; + TRACE("got PGN_CALCSIZE, returning vert size = %ld, client=%ld\n", + infoPtr->treeHeight, infoPtr->clientHeight); + } + return 0; + } + return DefWindowProcW(infoPtr->hwnd, WM_NOTIFY, wParam, lParam); +} + +static INT TREEVIEW_NotifyFormat (TREEVIEW_INFO *infoPtr, HWND hwndFrom, UINT nCommand) +{ + INT format; + + TRACE("(hwndFrom=%p, nCommand=%d)\n", hwndFrom, nCommand); + + if (nCommand != NF_REQUERY) return 0; + + format = SendMessageW(hwndFrom, WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwnd, NF_QUERY); + TRACE("format=%d\n", format); + + if (format != NFR_ANSI && format != NFR_UNICODE) return 0; + + infoPtr->bNtfUnicode = (format == NFR_UNICODE); + + return format; +} + +static LRESULT +TREEVIEW_Size(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + if (wParam == SIZE_RESTORED) + { + infoPtr->clientWidth = (short)LOWORD(lParam); + infoPtr->clientHeight = (short)HIWORD(lParam); + + TREEVIEW_RecalculateVisibleOrder(infoPtr, NULL); + TREEVIEW_SetFirstVisible(infoPtr, infoPtr->firstVisible, TRUE); + TREEVIEW_UpdateScrollBars(infoPtr); + } + else + { + FIXME("WM_SIZE flag %x %lx not handled\n", wParam, lParam); + } + + TREEVIEW_Invalidate(infoPtr, NULL); + return 0; +} + +static LRESULT +TREEVIEW_StyleChanged(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + TRACE("(%x %lx)\n", wParam, lParam); + + if (wParam == GWL_STYLE) + { + DWORD dwNewStyle = ((LPSTYLESTRUCT)lParam)->styleNew; + + /* we have to take special care about tooltips */ + if ((infoPtr->dwStyle ^ dwNewStyle) & TVS_NOTOOLTIPS) + { + if (infoPtr->dwStyle & TVS_NOTOOLTIPS) + { + infoPtr->hwndToolTip = COMCTL32_CreateToolTip(infoPtr->hwnd); + TRACE("\n"); + } + else + { + DestroyWindow(infoPtr->hwndToolTip); + infoPtr->hwndToolTip = 0; + } + } + + infoPtr->dwStyle = dwNewStyle; + } + + TREEVIEW_UpdateSubTree(infoPtr, infoPtr->root); + TREEVIEW_UpdateScrollBars(infoPtr); + TREEVIEW_Invalidate(infoPtr, NULL); + + return 0; +} + +static LRESULT +TREEVIEW_SetCursor(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) +{ + POINT pt; + TREEVIEW_ITEM * item; + + GetCursorPos(&pt); + ScreenToClient(infoPtr->hwnd, &pt); + + item = TREEVIEW_HitTestPoint(infoPtr, pt); + + /* FIXME: send NM_SETCURSOR */ + + if (item && (infoPtr->dwStyle & TVS_TRACKSELECT)) + { + SetCursor(infoPtr->hcurHand); + return 0; + } + else + return DefWindowProcW(infoPtr->hwnd, WM_SETCURSOR, wParam, lParam); +} + +static LRESULT +TREEVIEW_SetFocus(TREEVIEW_INFO *infoPtr) +{ + TRACE("\n"); + + if (!infoPtr->selectedItem) + { + TREEVIEW_DoSelectItem(infoPtr, TVGN_CARET, infoPtr->firstVisible, + TVC_UNKNOWN); + } + + TREEVIEW_Invalidate(infoPtr, infoPtr->selectedItem); + TREEVIEW_SendSimpleNotify(infoPtr, NM_SETFOCUS); + return 0; +} + +static LRESULT +TREEVIEW_KillFocus(TREEVIEW_INFO *infoPtr) +{ + TRACE("\n"); + + TREEVIEW_Invalidate(infoPtr, infoPtr->selectedItem); + UpdateWindow(infoPtr->hwnd); + TREEVIEW_SendSimpleNotify(infoPtr, NM_KILLFOCUS); + return 0; +} + + +static LRESULT WINAPI +TREEVIEW_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); + + TRACE("hwnd %p msg %04x wp=%08x lp=%08lx\n", hwnd, uMsg, wParam, lParam); + + if (infoPtr) TREEVIEW_VerifyTree(infoPtr); + else + { + if (uMsg == WM_CREATE) + TREEVIEW_Create(hwnd, (LPCREATESTRUCTW)lParam); + else + goto def; + } + + switch (uMsg) + { + case TVM_CREATEDRAGIMAGE: + return TREEVIEW_CreateDragImage(infoPtr, wParam, lParam); + + case TVM_DELETEITEM: + return TREEVIEW_DeleteItem(infoPtr, (HTREEITEM)lParam); + + case TVM_EDITLABELA: + return (LRESULT)TREEVIEW_EditLabel(infoPtr, (HTREEITEM)lParam); + + case TVM_EDITLABELW: + return (LRESULT)TREEVIEW_EditLabel(infoPtr, (HTREEITEM)lParam); + + case TVM_ENDEDITLABELNOW: + return TREEVIEW_EndEditLabelNow(infoPtr, (BOOL)wParam); + + case TVM_ENSUREVISIBLE: + return TREEVIEW_EnsureVisible(infoPtr, (HTREEITEM)lParam, TRUE); + + case TVM_EXPAND: + return TREEVIEW_ExpandMsg(infoPtr, (UINT)wParam, (HTREEITEM)lParam); + + case TVM_GETBKCOLOR: + return TREEVIEW_GetBkColor(infoPtr); + + case TVM_GETCOUNT: + return TREEVIEW_GetCount(infoPtr); + + case TVM_GETEDITCONTROL: + return TREEVIEW_GetEditControl(infoPtr); + + case TVM_GETIMAGELIST: + return TREEVIEW_GetImageList(infoPtr, wParam); + + case TVM_GETINDENT: + return TREEVIEW_GetIndent(infoPtr); + + case TVM_GETINSERTMARKCOLOR: + return TREEVIEW_GetInsertMarkColor(infoPtr); + + case TVM_GETISEARCHSTRINGA: + FIXME("Unimplemented msg TVM_GETISEARCHSTRINGA\n"); + return 0; + + case TVM_GETISEARCHSTRINGW: + FIXME("Unimplemented msg TVM_GETISEARCHSTRINGW\n"); + return 0; + + case TVM_GETITEMA: + return TREEVIEW_GetItemT(infoPtr, (LPTVITEMEXW)lParam, FALSE); + + case TVM_GETITEMW: + return TREEVIEW_GetItemT(infoPtr, (LPTVITEMEXW)lParam, TRUE); + + case TVM_GETITEMHEIGHT: + return TREEVIEW_GetItemHeight(infoPtr); + + case TVM_GETITEMRECT: + return TREEVIEW_GetItemRect(infoPtr, (BOOL)wParam, (LPRECT)lParam); + + case TVM_GETITEMSTATE: + return TREEVIEW_GetItemState(infoPtr, (HTREEITEM)wParam, (UINT)lParam); + + case TVM_GETLINECOLOR: + return TREEVIEW_GetLineColor(infoPtr); + + case TVM_GETNEXTITEM: + return TREEVIEW_GetNextItem(infoPtr, (UINT)wParam, (HTREEITEM)lParam); + + case TVM_GETSCROLLTIME: + return TREEVIEW_GetScrollTime(infoPtr); + + case TVM_GETTEXTCOLOR: + return TREEVIEW_GetTextColor(infoPtr); + + case TVM_GETTOOLTIPS: + return TREEVIEW_GetToolTips(infoPtr); + + case TVM_GETUNICODEFORMAT: + return TREEVIEW_GetUnicodeFormat(infoPtr); + + case TVM_GETVISIBLECOUNT: + return TREEVIEW_GetVisibleCount(infoPtr); + + case TVM_HITTEST: + return TREEVIEW_HitTest(infoPtr, (LPTVHITTESTINFO)lParam); + + case TVM_INSERTITEMA: + return TREEVIEW_InsertItemT(infoPtr, (LPTVINSERTSTRUCTW)lParam, FALSE); + + case TVM_INSERTITEMW: + return TREEVIEW_InsertItemT(infoPtr, (LPTVINSERTSTRUCTW)lParam, TRUE); + + case TVM_SELECTITEM: + return TREEVIEW_SelectItem(infoPtr, (INT)wParam, (HTREEITEM)lParam); + + case TVM_SETBKCOLOR: + return TREEVIEW_SetBkColor(infoPtr, (COLORREF)lParam); + + case TVM_SETIMAGELIST: + return TREEVIEW_SetImageList(infoPtr, wParam, (HIMAGELIST)lParam); + + case TVM_SETINDENT: + return TREEVIEW_SetIndent(infoPtr, (UINT)wParam); + + case TVM_SETINSERTMARK: + return TREEVIEW_SetInsertMark(infoPtr, (BOOL)wParam, (HTREEITEM)lParam); + + case TVM_SETINSERTMARKCOLOR: + return TREEVIEW_SetInsertMarkColor(infoPtr, (COLORREF)lParam); + + case TVM_SETITEMA: + return TREEVIEW_SetItemT(infoPtr, (LPTVITEMEXW)lParam, FALSE); + + case TVM_SETITEMW: + return TREEVIEW_SetItemT(infoPtr, (LPTVITEMEXW)lParam, TRUE); + + case TVM_SETLINECOLOR: + return TREEVIEW_SetLineColor(infoPtr, (COLORREF)lParam); + + case TVM_SETITEMHEIGHT: + return TREEVIEW_SetItemHeight(infoPtr, (INT)(SHORT)wParam); + + case TVM_SETSCROLLTIME: + return TREEVIEW_SetScrollTime(infoPtr, (UINT)wParam); + + case TVM_SETTEXTCOLOR: + return TREEVIEW_SetTextColor(infoPtr, (COLORREF)lParam); + + case TVM_SETTOOLTIPS: + return TREEVIEW_SetToolTips(infoPtr, (HWND)wParam); + + case TVM_SETUNICODEFORMAT: + return TREEVIEW_SetUnicodeFormat(infoPtr, (BOOL)wParam); + + case TVM_SORTCHILDREN: + return TREEVIEW_SortChildren(infoPtr, wParam, lParam); + + case TVM_SORTCHILDRENCB: + return TREEVIEW_SortChildrenCB(infoPtr, wParam, (LPTVSORTCB)lParam); + + case WM_CHAR: + return TREEVIEW_ProcessLetterKeys( hwnd, wParam, lParam ); + + case WM_COMMAND: + return TREEVIEW_Command(infoPtr, wParam, lParam); + + case WM_DESTROY: + return TREEVIEW_Destroy(infoPtr); + + /* WM_ENABLE */ + + case WM_ERASEBKGND: + return TREEVIEW_EraseBackground(infoPtr, (HDC)wParam); + + case WM_GETDLGCODE: + return DLGC_WANTARROWS | DLGC_WANTCHARS; + + case WM_GETFONT: + return TREEVIEW_GetFont(infoPtr); + + case WM_HSCROLL: + return TREEVIEW_HScroll(infoPtr, wParam); + + case WM_KEYDOWN: + return TREEVIEW_KeyDown(infoPtr, wParam); + + case WM_KILLFOCUS: + return TREEVIEW_KillFocus(infoPtr); + + case WM_LBUTTONDBLCLK: + return TREEVIEW_LButtonDoubleClick(infoPtr, lParam); + + case WM_LBUTTONDOWN: + return TREEVIEW_LButtonDown(infoPtr, lParam); + + /* WM_MBUTTONDOWN */ + + case WM_MOUSELEAVE: + return TREEVIEW_MouseLeave(infoPtr); + + case WM_MOUSEMOVE: + if (infoPtr->dwStyle & TVS_TRACKSELECT) + return TREEVIEW_MouseMove(infoPtr, wParam, lParam); + else + return 0; + + case WM_NOTIFY: + return TREEVIEW_Notify(infoPtr, wParam, lParam); + + case WM_NOTIFYFORMAT: + return TREEVIEW_NotifyFormat(infoPtr, (HWND)wParam, (UINT)lParam); + + case WM_PAINT: + return TREEVIEW_Paint(infoPtr, wParam); + + /* WM_PRINTCLIENT */ + + case WM_RBUTTONDOWN: + return TREEVIEW_RButtonDown(infoPtr, lParam); + + case WM_SETCURSOR: + return TREEVIEW_SetCursor(infoPtr, wParam, lParam); + + case WM_SETFOCUS: + return TREEVIEW_SetFocus(infoPtr); + + case WM_SETFONT: + return TREEVIEW_SetFont(infoPtr, (HFONT)wParam, (BOOL)lParam); + + case WM_SETREDRAW: + return TREEVIEW_SetRedraw(infoPtr, wParam, lParam); + + case WM_SIZE: + return TREEVIEW_Size(infoPtr, wParam, lParam); + + case WM_STYLECHANGED: + return TREEVIEW_StyleChanged(infoPtr, wParam, lParam); + + /* WM_SYSCOLORCHANGE */ + + /* WM_SYSKEYDOWN */ + + case WM_TIMER: + return TREEVIEW_HandleTimer(infoPtr, wParam); + + case WM_VSCROLL: + return TREEVIEW_VScroll(infoPtr, wParam); + + /* WM_WININICHANGE */ + + case WM_MOUSEWHEEL: + if (wParam & (MK_SHIFT | MK_CONTROL)) + goto def; + return TREEVIEW_MouseWheel(infoPtr, wParam); + + case WM_DRAWITEM: + TRACE("drawItem\n"); + goto def; + + default: + /* This mostly catches MFC and Delphi messages. :( */ + if ((uMsg >= WM_USER) && (uMsg < WM_APP)) + TRACE("Unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam); +def: + return DefWindowProcW(hwnd, uMsg, wParam, lParam); + } +} + + +/* Class Registration ***************************************************/ + +VOID +TREEVIEW_Register(void) +{ + WNDCLASSW wndClass; + + TRACE("\n"); + + ZeroMemory(&wndClass, sizeof(WNDCLASSW)); + wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS; + wndClass.lpfnWndProc = TREEVIEW_WindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(TREEVIEW_INFO *); + + wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW); + wndClass.hbrBackground = 0; + wndClass.lpszClassName = WC_TREEVIEWW; + + RegisterClassW(&wndClass); +} + + +VOID +TREEVIEW_Unregister(void) +{ + UnregisterClassW(WC_TREEVIEWW, NULL); +} + + +/* Tree Verification ****************************************************/ + +#ifdef NDEBUG +static inline void +TREEVIEW_VerifyChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item); + +static inline void TREEVIEW_VerifyItemCommon(TREEVIEW_INFO *infoPtr, + TREEVIEW_ITEM *item) +{ + assert(infoPtr != NULL); + assert(item != NULL); + + /* both NULL, or both non-null */ + assert((item->firstChild == NULL) == (item->lastChild == NULL)); + + assert(item->firstChild != item); + assert(item->lastChild != item); + + if (item->firstChild) + { + assert(item->firstChild->parent == item); + assert(item->firstChild->prevSibling == NULL); + } + + if (item->lastChild) + { + assert(item->lastChild->parent == item); + assert(item->lastChild->nextSibling == NULL); + } + + assert(item->nextSibling != item); + if (item->nextSibling) + { + assert(item->nextSibling->parent == item->parent); + assert(item->nextSibling->prevSibling == item); + } + + assert(item->prevSibling != item); + if (item->prevSibling) + { + assert(item->prevSibling->parent == item->parent); + assert(item->prevSibling->nextSibling == item); + } +} + +static inline void +TREEVIEW_VerifyItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) +{ + assert(item != NULL); + + assert(item->parent != NULL); + assert(item->parent != item); + assert(item->iLevel == item->parent->iLevel + 1); + + assert(DPA_GetPtrIndex(infoPtr->items, item) != -1); + + TREEVIEW_VerifyItemCommon(infoPtr, item); + + TREEVIEW_VerifyChildren(infoPtr, item); +} + +static inline void +TREEVIEW_VerifyChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) +{ + TREEVIEW_ITEM *child; + assert(item != NULL); + + for (child = item->firstChild; child != NULL; child = child->nextSibling) + TREEVIEW_VerifyItem(infoPtr, child); +} + +static inline void +TREEVIEW_VerifyRoot(TREEVIEW_INFO *infoPtr) +{ + TREEVIEW_ITEM *root = infoPtr->root; + + assert(root != NULL); + assert(root->iLevel == -1); + assert(root->parent == NULL); + assert(root->prevSibling == NULL); + + TREEVIEW_VerifyItemCommon(infoPtr, root); + + TREEVIEW_VerifyChildren(infoPtr, root); +} + +static void +TREEVIEW_VerifyTree(TREEVIEW_INFO *infoPtr) +{ + assert(infoPtr != NULL); + + TREEVIEW_VerifyRoot(infoPtr); +} +#endif diff --git a/reactos/lib/comctl32/updown.c b/reactos/lib/comctl32/updown.c index bec0fd007a1..5cdc23a5916 100644 --- a/reactos/lib/comctl32/updown.c +++ b/reactos/lib/comctl32/updown.c @@ -1,1015 +1,1015 @@ -/* - * Updown control - * - * Copyright 1997, 2002 Dimitrie O. Paun - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTE - * - * This code was audited for completeness against the documented features - * of Comctl32.dll version 6.0 on Sep. 9, 2002, by Dimitrie O. Paun. - * - * Unless otherwise noted, we believe this code to be complete, as per - * the specification mentioned above. - * If you discover missing features, or bugs, please note them below. - * - */ - -#include -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "comctl32.h" -#include "wine/unicode.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(updown); - -typedef struct -{ - HWND Self; /* Handle to this up-down control */ - HWND Notify; /* Handle to the parent window */ - DWORD dwStyle; /* The GWL_STYLE for this window */ - UINT AccelCount; /* Number of elements in AccelVect */ - UDACCEL* AccelVect; /* Vector containing AccelCount elements */ - INT AccelIndex; /* Current accel index, -1 if not accel'ing */ - INT Base; /* Base to display nr in the buddy window */ - INT CurVal; /* Current up-down value */ - INT MinVal; /* Minimum up-down value */ - INT MaxVal; /* Maximum up-down value */ - HWND Buddy; /* Handle to the buddy window */ - INT BuddyType; /* Remembers the buddy type BUDDY_TYPE_* */ - INT Flags; /* Internal Flags FLAG_* */ - BOOL UnicodeFormat; /* Marks the use of Unicode internally */ -} UPDOWN_INFO; - -/* Control configuration constants */ - -#define INITIAL_DELAY 500 /* initial timer until auto-inc kicks in */ -#define AUTOPRESS_DELAY 250 /* time to keep arrow pressed on KEY_DOWN */ -#define REPEAT_DELAY 50 /* delay between auto-increments */ - -#define DEFAULT_WIDTH 14 /* default width of the ctrl */ -#define DEFAULT_XSEP 0 /* default separation between buddy and ctrl */ -#define DEFAULT_ADDTOP 0 /* amount to extend above the buddy window */ -#define DEFAULT_ADDBOT 0 /* amount to extend below the buddy window */ -#define DEFAULT_BUDDYBORDER 2 /* Width/height of the buddy border */ -#define DEFAULT_BUDDYSPACER 2 /* Spacer between the buddy and the ctrl */ - - -/* Work constants */ - -#define FLAG_INCR 0x01 -#define FLAG_DECR 0x02 -#define FLAG_MOUSEIN 0x04 -#define FLAG_PRESSED 0x08 -#define FLAG_ARROW (FLAG_INCR | FLAG_DECR) - -#define BUDDY_TYPE_UNKNOWN 0 -#define BUDDY_TYPE_LISTBOX 1 -#define BUDDY_TYPE_EDIT 2 - -#define TIMER_AUTOREPEAT 1 -#define TIMER_ACCEL 2 -#define TIMER_AUTOPRESS 3 - -#define UPDOWN_GetInfoPtr(hwnd) ((UPDOWN_INFO *)GetWindowLongPtrW (hwnd,0)) -#define COUNT_OF(a) (sizeof(a)/sizeof(a[0])) - -static const WCHAR BUDDY_UPDOWN_HWND[] = { 'b', 'u', 'd', 'd', 'y', 'U', 'p', 'D', 'o', 'w', 'n', 'H', 'W', 'N', 'D', 0 }; -static const WCHAR BUDDY_SUPERCLASS_WNDPROC[] = { 'b', 'u', 'd', 'd', 'y', 'S', 'u', 'p', 'p', 'e', 'r', - 'C', 'l', 'a', 's', 's', 'W', 'n', 'd', 'P', 'r', 'o', 'c', 0 }; -static void UPDOWN_DoAction (UPDOWN_INFO *infoPtr, int delta, int action); - -/*********************************************************************** - * UPDOWN_IsBuddyEdit - * Tests if our buddy is an edit control. - */ -static inline BOOL UPDOWN_IsBuddyEdit(UPDOWN_INFO *infoPtr) -{ - return infoPtr->BuddyType == BUDDY_TYPE_EDIT; -} - -/*********************************************************************** - * UPDOWN_IsBuddyListbox - * Tests if our buddy is a listbox control. - */ -static inline BOOL UPDOWN_IsBuddyListbox(UPDOWN_INFO *infoPtr) -{ - return infoPtr->BuddyType == BUDDY_TYPE_LISTBOX; -} - -/*********************************************************************** - * UPDOWN_InBounds - * Tests if a given value 'val' is between the Min&Max limits - */ -static BOOL UPDOWN_InBounds(UPDOWN_INFO *infoPtr, int val) -{ - if(infoPtr->MaxVal > infoPtr->MinVal) - return (infoPtr->MinVal <= val) && (val <= infoPtr->MaxVal); - else - return (infoPtr->MaxVal <= val) && (val <= infoPtr->MinVal); -} - -/*********************************************************************** - * UPDOWN_OffsetVal - * Change the current value by delta. - * It returns TRUE is the value was changed successfuly, or FALSE - * if the value was not changed, as it would go out of bounds. - */ -static BOOL UPDOWN_OffsetVal(UPDOWN_INFO *infoPtr, int delta) -{ - /* check if we can do the modification first */ - if(!UPDOWN_InBounds (infoPtr, infoPtr->CurVal+delta)) { - if (infoPtr->dwStyle & UDS_WRAP) { - delta += (delta < 0 ? -1 : 1) * - (infoPtr->MaxVal < infoPtr->MinVal ? -1 : 1) * - (infoPtr->MinVal - infoPtr->MaxVal) + - (delta < 0 ? 1 : -1); - } else return FALSE; - } - - infoPtr->CurVal += delta; - return TRUE; -} - -/*********************************************************************** - * UPDOWN_HasBuddyBorder - * - * When we have a buddy set and that we are aligned on our buddy, we - * want to draw a sunken edge to make like we are part of that control. - */ -static BOOL UPDOWN_HasBuddyBorder(UPDOWN_INFO* infoPtr) -{ - return ( ((infoPtr->dwStyle & (UDS_ALIGNLEFT | UDS_ALIGNRIGHT)) != 0) && - UPDOWN_IsBuddyEdit(infoPtr) ); -} - -/*********************************************************************** - * UPDOWN_GetArrowRect - * wndPtr - pointer to the up-down wnd - * rect - will hold the rectangle - * arrow - FLAG_INCR to get the "increment" rect (up or right) - * FLAG_DECR to get the "decrement" rect (down or left) - * If both flags are pressent, the envelope is returned. - */ -static void UPDOWN_GetArrowRect (UPDOWN_INFO* infoPtr, RECT *rect, int arrow) -{ - GetClientRect (infoPtr->Self, rect); - - /* - * Make sure we calculate the rectangle to fit even if we draw the - * border. - */ - if (UPDOWN_HasBuddyBorder(infoPtr)) { - if (infoPtr->dwStyle & UDS_ALIGNLEFT) - rect->left += DEFAULT_BUDDYBORDER; - else - rect->right -= DEFAULT_BUDDYBORDER; - - InflateRect(rect, 0, -DEFAULT_BUDDYBORDER); - } - - /* now figure out if we need a space away from the buddy */ - if ( IsWindow(infoPtr->Buddy) ) { - if (infoPtr->dwStyle & UDS_ALIGNLEFT) rect->right -= DEFAULT_BUDDYSPACER; - else rect->left += DEFAULT_BUDDYSPACER; - } - - /* - * We're calculating the midpoint to figure-out where the - * separation between the buttons will lay. We make sure that we - * round the uneven numbers by adding 1. - */ - if (infoPtr->dwStyle & UDS_HORZ) { - int len = rect->right - rect->left + 1; /* compute the width */ - if (arrow & FLAG_INCR) - rect->left = rect->left + len/2; - if (arrow & FLAG_DECR) - rect->right = rect->left + len/2 - 1; - } else { - int len = rect->bottom - rect->top + 1; /* compute the height */ - if (arrow & FLAG_INCR) - rect->bottom = rect->top + len/2 - 1; - if (arrow & FLAG_DECR) - rect->top = rect->top + len/2; - } -} - -/*********************************************************************** - * UPDOWN_GetArrowFromPoint - * Returns the rectagle (for the up or down arrow) that contains pt. - * If it returns the up rect, it returns TRUE. - * If it returns the down rect, it returns FALSE. - */ -static BOOL UPDOWN_GetArrowFromPoint (UPDOWN_INFO* infoPtr, RECT *rect, POINT pt) -{ - UPDOWN_GetArrowRect (infoPtr, rect, FLAG_INCR); - if(PtInRect(rect, pt)) return FLAG_INCR; - - UPDOWN_GetArrowRect (infoPtr, rect, FLAG_DECR); - if(PtInRect(rect, pt)) return FLAG_DECR; - - return 0; -} - - -/*********************************************************************** - * UPDOWN_GetThousandSep - * Returns the thousand sep. If an error occurs, it returns ','. - */ -static WCHAR UPDOWN_GetThousandSep(void) -{ - WCHAR sep[2]; - - if(GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, sep, 2) != 1) - sep[0] = ','; - - return sep[0]; -} - -/*********************************************************************** - * UPDOWN_GetBuddyInt - * Tries to read the pos from the buddy window and if it succeeds, - * it stores it in the control's CurVal - * returns: - * TRUE - if it read the integer from the buddy successfully - * FALSE - if an error occurred - */ -static BOOL UPDOWN_GetBuddyInt (UPDOWN_INFO *infoPtr) -{ - WCHAR txt[20], sep, *src, *dst; - int newVal; - - if (!((infoPtr->dwStyle & UDS_SETBUDDYINT) && IsWindow(infoPtr->Buddy))) - return FALSE; - - /*if the buddy is a list window, we must set curr index */ - if (UPDOWN_IsBuddyListbox(infoPtr)) { - newVal = SendMessageW(infoPtr->Buddy, LB_GETCARETINDEX, 0, 0); - if(newVal < 0) return FALSE; - } else { - /* we have a regular window, so will get the text */ - /* note that a zero-length string is a legitimate value for 'txt', - * and ought to result in a successful conversion to '0'. */ - if (GetWindowTextW(infoPtr->Buddy, txt, COUNT_OF(txt)) < 0) - return FALSE; - - sep = UPDOWN_GetThousandSep(); - - /* now get rid of the separators */ - for(src = dst = txt; *src; src++) - if(*src != sep) *dst++ = *src; - *dst = 0; - - /* try to convert the number and validate it */ - newVal = strtolW(txt, &src, infoPtr->Base); - if(*src || !UPDOWN_InBounds (infoPtr, newVal)) return FALSE; - } - - TRACE("new value(%d) from buddy (old=%d)\n", newVal, infoPtr->CurVal); - infoPtr->CurVal = newVal; - return TRUE; -} - - -/*********************************************************************** - * UPDOWN_SetBuddyInt - * Tries to set the pos to the buddy window based on current pos - * returns: - * TRUE - if it set the caption of the buddy successfully - * FALSE - if an error occurred - */ -static BOOL UPDOWN_SetBuddyInt (UPDOWN_INFO *infoPtr) -{ - WCHAR fmt[3] = { '%', 'd', '\0' }; - WCHAR txt[20]; - int len; - - if (!((infoPtr->dwStyle & UDS_SETBUDDYINT) && IsWindow(infoPtr->Buddy))) - return FALSE; - - TRACE("set new value(%d) to buddy.\n", infoPtr->CurVal); - - /*if the buddy is a list window, we must set curr index */ - if (UPDOWN_IsBuddyListbox(infoPtr)) { - return SendMessageW(infoPtr->Buddy, LB_SETCURSEL, infoPtr->CurVal, 0) != LB_ERR; - } - - /* Regular window, so set caption to the number */ - if (infoPtr->Base == 16) fmt[1] = 'X'; - len = wsprintfW(txt, fmt, infoPtr->CurVal); - - - /* Do thousands separation if necessary */ - if (!(infoPtr->dwStyle & UDS_NOTHOUSANDS) && (len > 3)) { - WCHAR tmp[COUNT_OF(txt)], *src = tmp, *dst = txt; - WCHAR sep = UPDOWN_GetThousandSep(); - int start = len % 3; - - memcpy(tmp, txt, sizeof(txt)); - if (start == 0) start = 3; - dst += start; - src += start; - for (len=0; *src; len++) { - if (len % 3 == 0) *dst++ = sep; - *dst++ = *src++; - } - *dst = 0; - } - - return SetWindowTextW(infoPtr->Buddy, txt); -} - -/*********************************************************************** - * UPDOWN_Draw - * - * Draw the arrows. The background need not be erased. - */ -static LRESULT UPDOWN_Draw (UPDOWN_INFO *infoPtr, HDC hdc) -{ - BOOL pressed, hot; - RECT rect; - - /* Draw the common border between ourselves and our buddy */ - if (UPDOWN_HasBuddyBorder(infoPtr)) { - GetClientRect(infoPtr->Self, &rect); - DrawEdge(hdc, &rect, EDGE_SUNKEN, - BF_BOTTOM | BF_TOP | - (infoPtr->dwStyle & UDS_ALIGNLEFT ? BF_LEFT : BF_RIGHT)); - } - - /* Draw the incr button */ - UPDOWN_GetArrowRect (infoPtr, &rect, FLAG_INCR); - pressed = (infoPtr->Flags & FLAG_PRESSED) && (infoPtr->Flags & FLAG_INCR); - hot = (infoPtr->Flags & FLAG_INCR) && (infoPtr->Flags & FLAG_MOUSEIN); - DrawFrameControl(hdc, &rect, DFC_SCROLL, - (infoPtr->dwStyle & UDS_HORZ ? DFCS_SCROLLRIGHT : DFCS_SCROLLUP) | - ((infoPtr->dwStyle & UDS_HOTTRACK) && hot ? DFCS_HOT : 0) | - (pressed ? DFCS_PUSHED : 0) | - (infoPtr->dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) ); - - /* Draw the decr button */ - UPDOWN_GetArrowRect(infoPtr, &rect, FLAG_DECR); - pressed = (infoPtr->Flags & FLAG_PRESSED) && (infoPtr->Flags & FLAG_DECR); - hot = (infoPtr->Flags & FLAG_DECR) && (infoPtr->Flags & FLAG_MOUSEIN); - DrawFrameControl(hdc, &rect, DFC_SCROLL, - (infoPtr->dwStyle & UDS_HORZ ? DFCS_SCROLLLEFT : DFCS_SCROLLDOWN) | - ((infoPtr->dwStyle & UDS_HOTTRACK) && hot ? DFCS_HOT : 0) | - (pressed ? DFCS_PUSHED : 0) | - (infoPtr->dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) ); - - return 0; -} - -/*********************************************************************** - * UPDOWN_Paint - * - * Asynchronous drawing (must ONLY be used in WM_PAINT). - * Calls UPDOWN_Draw. - */ -static LRESULT UPDOWN_Paint (UPDOWN_INFO *infoPtr, HDC hdc) -{ - PAINTSTRUCT ps; - if (hdc) return UPDOWN_Draw (infoPtr, hdc); - hdc = BeginPaint (infoPtr->Self, &ps); - UPDOWN_Draw (infoPtr, hdc); - EndPaint (infoPtr->Self, &ps); - return 0; -} - -/*********************************************************************** - * UPDOWN_KeyPressed - * - * Handle key presses (up & down) when we have to do so - */ -static LRESULT UPDOWN_KeyPressed(UPDOWN_INFO *infoPtr, int key) -{ - int arrow; - - if (key == VK_UP) arrow = FLAG_INCR; - else if (key == VK_DOWN) arrow = FLAG_DECR; - else return 1; - - UPDOWN_GetBuddyInt (infoPtr); - infoPtr->Flags &= ~FLAG_ARROW; - infoPtr->Flags |= FLAG_PRESSED | arrow; - InvalidateRect (infoPtr->Self, NULL, FALSE); - SetTimer(infoPtr->Self, TIMER_AUTOPRESS, AUTOPRESS_DELAY, 0); - UPDOWN_DoAction (infoPtr, 1, arrow); - return 0; -} - -/*********************************************************************** - * UPDOWN_Buddy_SubclassProc used to handle messages sent to the buddy - * control. - */ -static LRESULT CALLBACK -UPDOWN_Buddy_SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - WNDPROC superClassWndProc = (WNDPROC)GetPropW(hwnd, BUDDY_SUPERCLASS_WNDPROC); - - TRACE("hwnd=%p, wndProc=%p, uMsg=%04x, wParam=%08x, lParam=%08lx\n", - hwnd, superClassWndProc, uMsg, wParam, lParam); - - if (uMsg == WM_KEYDOWN) { - HWND upDownHwnd = GetPropW(hwnd, BUDDY_UPDOWN_HWND); - - UPDOWN_KeyPressed(UPDOWN_GetInfoPtr(upDownHwnd), (int)wParam); - } - - return CallWindowProcW( superClassWndProc, hwnd, uMsg, wParam, lParam); -} - -/*********************************************************************** - * UPDOWN_SetBuddy - * - * Sets bud as a new Buddy. - * Then, it should subclass the buddy - * If window has the UDS_ARROWKEYS, it subcalsses the buddy window to - * process the UP/DOWN arrow keys. - * If window has the UDS_ALIGNLEFT or UDS_ALIGNRIGHT style - * the size/pos of the buddy and the control are adjusted accordingly. - */ -static HWND UPDOWN_SetBuddy (UPDOWN_INFO* infoPtr, HWND bud) -{ - static const WCHAR editW[] = { 'E', 'd', 'i', 't', 0 }; - static const WCHAR listboxW[] = { 'L', 'i', 's', 't', 'b', 'o', 'x', 0 }; - RECT budRect; /* new coord for the buddy */ - int x, width; /* new x position and width for the up-down */ - WNDPROC baseWndProc; - WCHAR buddyClass[40]; - HWND ret; - - TRACE("(hwnd=%p, bud=%p)\n", infoPtr->Self, bud); - - ret = infoPtr->Buddy; - - /* there is already a body assigned */ - if (infoPtr->Buddy) RemovePropW(infoPtr->Buddy, BUDDY_UPDOWN_HWND); - - if(!IsWindow(bud)) - bud = 0; - - /* Store buddy window handle */ - infoPtr->Buddy = bud; - - if(bud) { - - /* keep upDown ctrl hwnd in a buddy property */ - SetPropW( bud, BUDDY_UPDOWN_HWND, infoPtr->Self); - - /* Store buddy window class type */ - infoPtr->BuddyType = BUDDY_TYPE_UNKNOWN; - if (GetClassNameW(bud, buddyClass, COUNT_OF(buddyClass))) { - if (lstrcmpiW(buddyClass, editW) == 0) - infoPtr->BuddyType = BUDDY_TYPE_EDIT; - else if (lstrcmpiW(buddyClass, listboxW) == 0) - infoPtr->BuddyType = BUDDY_TYPE_LISTBOX; - } - - if(infoPtr->dwStyle & UDS_ARROWKEYS){ - /* Note that I don't clear the BUDDY_SUPERCLASS_WNDPROC property - when we reset the upDown ctrl buddy to another buddy because it is not - good to break the window proc chain. */ - if (!GetPropW(bud, BUDDY_SUPERCLASS_WNDPROC)) { - baseWndProc = (WNDPROC)SetWindowLongPtrW(bud, GWLP_WNDPROC, (LPARAM)UPDOWN_Buddy_SubclassProc); - SetPropW(bud, BUDDY_SUPERCLASS_WNDPROC, (HANDLE)baseWndProc); - } - } - - /* Get the rect of the buddy relative to its parent */ - GetWindowRect(infoPtr->Buddy, &budRect); - MapWindowPoints(HWND_DESKTOP, GetParent(infoPtr->Buddy), (POINT *)(&budRect.left), 2); - - /* now do the positioning */ - if (infoPtr->dwStyle & UDS_ALIGNLEFT) { - x = budRect.left; - budRect.left += DEFAULT_WIDTH + DEFAULT_XSEP; - } else if (infoPtr->dwStyle & UDS_ALIGNRIGHT) { - budRect.right -= DEFAULT_WIDTH + DEFAULT_XSEP; - x = budRect.right+DEFAULT_XSEP; - } else { - /* nothing to do */ - return ret; - } - - /* first adjust the buddy to accommodate the up/down */ - SetWindowPos(infoPtr->Buddy, 0, budRect.left, budRect.top, - budRect.right - budRect.left, budRect.bottom - budRect.top, - SWP_NOACTIVATE|SWP_NOZORDER); - - /* now position the up/down */ - /* Since the UDS_ALIGN* flags were used, */ - /* we will pick the position and size of the window. */ - width = DEFAULT_WIDTH; - - /* - * If the updown has a buddy border, it has to overlap with the buddy - * to look as if it is integrated with the buddy control. - * We nudge the control or change its size to overlap. - */ - if (UPDOWN_HasBuddyBorder(infoPtr)) { - if(infoPtr->dwStyle & UDS_ALIGNLEFT) - width += DEFAULT_BUDDYBORDER; - else - x -= DEFAULT_BUDDYBORDER; - } - - SetWindowPos(infoPtr->Self, 0, x, - budRect.top - DEFAULT_ADDTOP, width, - budRect.bottom - budRect.top + DEFAULT_ADDTOP + DEFAULT_ADDBOT, - SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOZORDER); - } else { - RECT rect; - GetWindowRect(infoPtr->Self, &rect); - MapWindowPoints(HWND_DESKTOP, GetParent(infoPtr->Self), (POINT *)&rect, 2); - SetWindowPos(infoPtr->Self, 0, rect.left, rect.top, DEFAULT_WIDTH, rect.bottom - rect.top, - SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOZORDER); - } - return ret; -} - -/*********************************************************************** - * UPDOWN_DoAction - * - * This function increments/decrements the CurVal by the - * 'delta' amount according to the 'action' flag which can be a - * combination of FLAG_INCR and FLAG_DECR - * It notifies the parent as required. - * It handles wraping and non-wraping correctly. - * It is assumed that delta>0 - */ -static void UPDOWN_DoAction (UPDOWN_INFO *infoPtr, int delta, int action) -{ - NM_UPDOWN ni; - - TRACE("%d by %d\n", action, delta); - - /* check if we can do the modification first */ - delta *= (action & FLAG_INCR ? 1 : -1) * (infoPtr->MaxVal < infoPtr->MinVal ? -1 : 1); - if ( (action & FLAG_INCR) && (action & FLAG_DECR) ) delta = 0; - - TRACE("current %d, delta: %d\n", infoPtr->CurVal, delta); - - /* We must notify parent now to obtain permission */ - ni.iPos = infoPtr->CurVal; - ni.iDelta = delta; - ni.hdr.hwndFrom = infoPtr->Self; - ni.hdr.idFrom = GetWindowLongPtrW (infoPtr->Self, GWLP_ID); - ni.hdr.code = UDN_DELTAPOS; - if (!SendMessageW(infoPtr->Notify, WM_NOTIFY, (WPARAM)ni.hdr.idFrom, (LPARAM)&ni)) { - /* Parent said: OK to adjust */ - - /* Now adjust value with (maybe new) delta */ - if (UPDOWN_OffsetVal (infoPtr, ni.iDelta)) { - TRACE("new %d, delta: %d\n", infoPtr->CurVal, ni.iDelta); - - /* Now take care about our buddy */ - UPDOWN_SetBuddyInt (infoPtr); - } - } - - /* Also, notify it. This message is sent in any case. */ - SendMessageW( infoPtr->Notify, (infoPtr->dwStyle & UDS_HORZ) ? WM_HSCROLL : WM_VSCROLL, - MAKELONG(SB_THUMBPOSITION, infoPtr->CurVal), (LPARAM)infoPtr->Self); -} - -/*********************************************************************** - * UPDOWN_IsEnabled - * - * Returns TRUE if it is enabled as well as its buddy (if any) - * FALSE otherwise - */ -static BOOL UPDOWN_IsEnabled (UPDOWN_INFO *infoPtr) -{ - if (!IsWindowEnabled(infoPtr->Self)) - return FALSE; - if(infoPtr->Buddy) - return IsWindowEnabled(infoPtr->Buddy); - return TRUE; -} - -/*********************************************************************** - * UPDOWN_CancelMode - * - * Deletes any timers, releases the mouse and does redraw if necessary. - * If the control is not in "capture" mode, it does nothing. - * If the control was not in cancel mode, it returns FALSE. - * If the control was in cancel mode, it returns TRUE. - */ -static BOOL UPDOWN_CancelMode (UPDOWN_INFO *infoPtr) -{ - if (!(infoPtr->Flags & FLAG_PRESSED)) return FALSE; - - KillTimer (infoPtr->Self, TIMER_AUTOREPEAT); - KillTimer (infoPtr->Self, TIMER_ACCEL); - KillTimer (infoPtr->Self, TIMER_AUTOPRESS); - - if (GetCapture() == infoPtr->Self) { - NMHDR hdr; - hdr.hwndFrom = infoPtr->Self; - hdr.idFrom = GetWindowLongPtrW (infoPtr->Self, GWLP_ID); - hdr.code = NM_RELEASEDCAPTURE; - SendMessageW(infoPtr->Notify, WM_NOTIFY, hdr.idFrom, (LPARAM)&hdr); - ReleaseCapture(); - } - - infoPtr->Flags &= ~FLAG_PRESSED; - InvalidateRect (infoPtr->Self, NULL, FALSE); - - return TRUE; -} - -/*********************************************************************** - * UPDOWN_HandleMouseEvent - * - * Handle a mouse event for the updown. - * 'pt' is the location of the mouse event in client or - * windows coordinates. - */ -static void UPDOWN_HandleMouseEvent (UPDOWN_INFO *infoPtr, UINT msg, INT x, INT y) -{ - POINT pt = { x, y }; - RECT rect; - int temp, arrow; - - TRACE("msg %04x point %s\n", msg, wine_dbgstr_point(&pt)); - - switch(msg) - { - case WM_LBUTTONDOWN: /* Initialise mouse tracking */ - - /* If the buddy is an edit, will set focus to it */ - if (UPDOWN_IsBuddyEdit(infoPtr)) SetFocus(infoPtr->Buddy); - - /* Now see which one is the 'active' arrow */ - arrow = UPDOWN_GetArrowFromPoint (infoPtr, &rect, pt); - - /* Update the flags if we are in/out */ - infoPtr->Flags &= ~(FLAG_MOUSEIN | FLAG_ARROW); - if (arrow) - infoPtr->Flags |= FLAG_MOUSEIN | arrow; - else - if (infoPtr->AccelIndex != -1) infoPtr->AccelIndex = 0; - - if (infoPtr->Flags & FLAG_ARROW) { - - /* Update the CurVal if necessary */ - UPDOWN_GetBuddyInt (infoPtr); - - /* Set up the correct flags */ - infoPtr->Flags |= FLAG_PRESSED; - - /* repaint the control */ - InvalidateRect (infoPtr->Self, NULL, FALSE); - - /* process the click */ - temp = (infoPtr->AccelCount && infoPtr->AccelVect) ? infoPtr->AccelVect[0].nInc : 1; - UPDOWN_DoAction (infoPtr, temp, infoPtr->Flags & FLAG_ARROW); - - /* now capture all mouse messages */ - SetCapture (infoPtr->Self); - - /* and startup the first timer */ - SetTimer(infoPtr->Self, TIMER_AUTOREPEAT, INITIAL_DELAY, 0); - } - break; - - case WM_MOUSEMOVE: - /* save the flags to see if any got modified */ - temp = infoPtr->Flags; - - /* Now see which one is the 'active' arrow */ - arrow = UPDOWN_GetArrowFromPoint (infoPtr, &rect, pt); - - /* Update the flags if we are in/out */ - infoPtr->Flags &= ~(FLAG_MOUSEIN | FLAG_ARROW); - if(arrow) { - infoPtr->Flags |= FLAG_MOUSEIN | arrow; - } else { - if(infoPtr->AccelIndex != -1) infoPtr->AccelIndex = 0; - } - - /* If state changed, redraw the control */ - if(temp != infoPtr->Flags) - InvalidateRect (infoPtr->Self, &rect, FALSE); - break; - - default: - ERR("Impossible case (msg=%x)!\n", msg); - } - -} - -/*********************************************************************** - * UpDownWndProc - */ -static LRESULT WINAPI UpDownWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd); - int temp; - - TRACE("hwnd=%p msg=%04x wparam=%08x lparam=%08lx\n", hwnd, message, wParam, lParam); - - if (!infoPtr && (message != WM_CREATE)) - return DefWindowProcW (hwnd, message, wParam, lParam); - - switch(message) - { - case WM_CREATE: - infoPtr = (UPDOWN_INFO*)Alloc (sizeof(UPDOWN_INFO)); - SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); - - /* initialize the info struct */ - infoPtr->Self = hwnd; - infoPtr->Notify = ((LPCREATESTRUCTW)lParam)->hwndParent; - infoPtr->dwStyle = ((LPCREATESTRUCTW)lParam)->style; - infoPtr->AccelCount = 0; - infoPtr->AccelVect = 0; - infoPtr->AccelIndex = -1; - infoPtr->CurVal = 0; - infoPtr->MinVal = 100; - infoPtr->MaxVal = 0; - infoPtr->Base = 10; /* Default to base 10 */ - infoPtr->Buddy = 0; /* No buddy window yet */ - infoPtr->Flags = 0; /* And no flags */ - - SetWindowLongW (hwnd, GWL_STYLE, infoPtr->dwStyle & ~WS_BORDER); - - /* Do we pick the buddy win ourselves? */ - if (infoPtr->dwStyle & UDS_AUTOBUDDY) - UPDOWN_SetBuddy (infoPtr, GetWindow (hwnd, GW_HWNDPREV)); - - TRACE("UpDown Ctrl creation, hwnd=%p\n", hwnd); - break; - - case WM_DESTROY: - if(infoPtr->AccelVect) Free (infoPtr->AccelVect); - - if(infoPtr->Buddy) RemovePropW(infoPtr->Buddy, BUDDY_UPDOWN_HWND); - - Free (infoPtr); - SetWindowLongPtrW (hwnd, 0, 0); - TRACE("UpDown Ctrl destruction, hwnd=%p\n", hwnd); - break; - - case WM_ENABLE: - if (wParam) { - infoPtr->dwStyle &= ~WS_DISABLED; - } else { - infoPtr->dwStyle |= WS_DISABLED; - UPDOWN_CancelMode (infoPtr); - } - InvalidateRect (infoPtr->Self, NULL, FALSE); - break; - - case WM_STYLECHANGED: - if (wParam == GWL_STYLE) { - infoPtr->dwStyle = ((LPSTYLESTRUCT)lParam)->styleNew; - InvalidateRect (infoPtr->Self, NULL, FALSE); - } - break; - - case WM_TIMER: - /* is this the auto-press timer? */ - if(wParam == TIMER_AUTOPRESS) { - KillTimer(hwnd, TIMER_AUTOPRESS); - infoPtr->Flags &= ~(FLAG_PRESSED | FLAG_ARROW); - InvalidateRect(infoPtr->Self, NULL, FALSE); - } - - /* if initial timer, kill it and start the repeat timer */ - if(wParam == TIMER_AUTOREPEAT) { - KillTimer(hwnd, TIMER_AUTOREPEAT); - /* if no accel info given, used default timer */ - if(infoPtr->AccelCount==0 || infoPtr->AccelVect==0) { - infoPtr->AccelIndex = -1; - temp = REPEAT_DELAY; - } else { - infoPtr->AccelIndex = 0; /* otherwise, use it */ - temp = infoPtr->AccelVect[infoPtr->AccelIndex].nSec * 1000 + 1; - } - SetTimer(hwnd, TIMER_ACCEL, temp, 0); - } - - /* now, if the mouse is above us, do the thing...*/ - if(infoPtr->Flags & FLAG_MOUSEIN) { - temp = infoPtr->AccelIndex == -1 ? 1 : infoPtr->AccelVect[infoPtr->AccelIndex].nInc; - UPDOWN_DoAction(infoPtr, temp, infoPtr->Flags & FLAG_ARROW); - - if(infoPtr->AccelIndex != -1 && infoPtr->AccelIndex < infoPtr->AccelCount-1) { - KillTimer(hwnd, TIMER_ACCEL); - infoPtr->AccelIndex++; /* move to the next accel info */ - temp = infoPtr->AccelVect[infoPtr->AccelIndex].nSec * 1000 + 1; - /* make sure we have at least 1ms intervals */ - SetTimer(hwnd, TIMER_ACCEL, temp, 0); - } - } - break; - - case WM_CANCELMODE: - return UPDOWN_CancelMode (infoPtr); - - case WM_LBUTTONUP: - if (GetCapture() != infoPtr->Self) break; - - if ( (infoPtr->Flags & FLAG_MOUSEIN) && - (infoPtr->Flags & FLAG_ARROW) ) { - - SendMessageW( infoPtr->Notify, - (infoPtr->dwStyle & UDS_HORZ) ? WM_HSCROLL : WM_VSCROLL, - MAKELONG(SB_ENDSCROLL, infoPtr->CurVal), - (LPARAM)hwnd); - if (UPDOWN_IsBuddyEdit(infoPtr)) - SendMessageW(infoPtr->Buddy, EM_SETSEL, 0, MAKELONG(0, -1)); - } - UPDOWN_CancelMode(infoPtr); - break; - - case WM_LBUTTONDOWN: - case WM_MOUSEMOVE: - if(UPDOWN_IsEnabled(infoPtr)) - UPDOWN_HandleMouseEvent (infoPtr, message, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); - break; - - case WM_KEYDOWN: - if((infoPtr->dwStyle & UDS_ARROWKEYS) && UPDOWN_IsEnabled(infoPtr)) - return UPDOWN_KeyPressed(infoPtr, (int)wParam); - break; - - case WM_PAINT: - return UPDOWN_Paint (infoPtr, (HDC)wParam); - - case UDM_GETACCEL: - if (wParam==0 && lParam==0) return infoPtr->AccelCount; - if (wParam && lParam) { - temp = min(infoPtr->AccelCount, wParam); - memcpy((void *)lParam, infoPtr->AccelVect, temp*sizeof(UDACCEL)); - return temp; - } - return 0; - - case UDM_SETACCEL: - TRACE("UDM_SETACCEL\n"); - - if(infoPtr->AccelVect) { - Free (infoPtr->AccelVect); - infoPtr->AccelCount = 0; - infoPtr->AccelVect = 0; - } - if(wParam==0) return TRUE; - infoPtr->AccelVect = Alloc (wParam*sizeof(UDACCEL)); - if(infoPtr->AccelVect == 0) return FALSE; - memcpy(infoPtr->AccelVect, (void*)lParam, wParam*sizeof(UDACCEL)); - infoPtr->AccelCount = wParam; - - for (temp = 0; temp < wParam; temp++) - TRACE("%d: nSec %u nInc %u\n", temp, infoPtr->AccelVect[temp].nSec, infoPtr->AccelVect[temp].nInc); - - return TRUE; - - case UDM_GETBASE: - return infoPtr->Base; - - case UDM_SETBASE: - TRACE("UpDown Ctrl new base(%d), hwnd=%p\n", wParam, hwnd); - if (wParam==10 || wParam==16) { - temp = infoPtr->Base; - infoPtr->Base = wParam; - return temp; - } - break; - - case UDM_GETBUDDY: - return (LRESULT)infoPtr->Buddy; - - case UDM_SETBUDDY: - return (LRESULT)UPDOWN_SetBuddy (infoPtr, (HWND)wParam); - - case UDM_GETPOS: - temp = UPDOWN_GetBuddyInt (infoPtr); - return MAKELONG(infoPtr->CurVal, temp ? 0 : 1); - - case UDM_SETPOS: - temp = (short)LOWORD(lParam); - TRACE("UpDown Ctrl new value(%d), hwnd=%p\n", temp, hwnd); - if(!UPDOWN_InBounds(infoPtr, temp)) { - if(temp < infoPtr->MinVal) temp = infoPtr->MinVal; - if(temp > infoPtr->MaxVal) temp = infoPtr->MaxVal; - } - wParam = infoPtr->CurVal; - infoPtr->CurVal = temp; - UPDOWN_SetBuddyInt (infoPtr); - return wParam; /* return prev value */ - - case UDM_GETRANGE: - return MAKELONG(infoPtr->MaxVal, infoPtr->MinVal); - - case UDM_SETRANGE: - /* we must have: */ - infoPtr->MaxVal = (short)(lParam); /* UD_MINVAL <= Max <= UD_MAXVAL */ - infoPtr->MinVal = (short)HIWORD(lParam); /* UD_MINVAL <= Min <= UD_MAXVAL */ - /* |Max-Min| <= UD_MAXVAL */ - TRACE("UpDown Ctrl new range(%d to %d), hwnd=%p\n", - infoPtr->MinVal, infoPtr->MaxVal, hwnd); - break; - - case UDM_GETRANGE32: - if (wParam) *(LPINT)wParam = infoPtr->MinVal; - if (lParam) *(LPINT)lParam = infoPtr->MaxVal; - break; - - case UDM_SETRANGE32: - infoPtr->MinVal = (INT)wParam; - infoPtr->MaxVal = (INT)lParam; - if (infoPtr->MaxVal <= infoPtr->MinVal) - infoPtr->MaxVal = infoPtr->MinVal + 1; - TRACE("UpDown Ctrl new range(%d to %d), hwnd=%p\n", - infoPtr->MinVal, infoPtr->MaxVal, hwnd); - break; - - case UDM_GETPOS32: - if ((LPBOOL)lParam != NULL) *((LPBOOL)lParam) = TRUE; - return infoPtr->CurVal; - - case UDM_SETPOS32: - if(!UPDOWN_InBounds(infoPtr, (int)lParam)) { - if((int)lParam < infoPtr->MinVal) lParam = infoPtr->MinVal; - if((int)lParam > infoPtr->MaxVal) lParam = infoPtr->MaxVal; - } - temp = infoPtr->CurVal; /* save prev value */ - infoPtr->CurVal = (int)lParam; /* set the new value */ - UPDOWN_SetBuddyInt (infoPtr); - return temp; /* return prev value */ - - case UDM_GETUNICODEFORMAT: - /* we lie a bit here, we're always using Unicode internally */ - return infoPtr->UnicodeFormat; - - case UDM_SETUNICODEFORMAT: - /* do we really need to honour this flag? */ - temp = infoPtr->UnicodeFormat; - infoPtr->UnicodeFormat = (BOOL)wParam; - return temp; - - default: - if ((message >= WM_USER) && (message < WM_APP)) - ERR("unknown msg %04x wp=%04x lp=%08lx\n", message, wParam, lParam); - return DefWindowProcW (hwnd, message, wParam, lParam); - } - - return 0; -} - -/*********************************************************************** - * UPDOWN_Register [Internal] - * - * Registers the updown window class. - */ -void UPDOWN_Register(void) -{ - WNDCLASSW wndClass; - - ZeroMemory( &wndClass, sizeof( WNDCLASSW ) ); - wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW; - wndClass.lpfnWndProc = UpDownWindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(UPDOWN_INFO*); - wndClass.hCursor = LoadCursorW( 0, (LPWSTR)IDC_ARROW ); - wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); - wndClass.lpszClassName = UPDOWN_CLASSW; - - RegisterClassW( &wndClass ); -} - - -/*********************************************************************** - * UPDOWN_Unregister [Internal] - * - * Unregisters the updown window class. - */ -void UPDOWN_Unregister (void) -{ - UnregisterClassW (UPDOWN_CLASSW, NULL); -} +/* + * Updown control + * + * Copyright 1997, 2002 Dimitrie O. Paun + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTE + * + * This code was audited for completeness against the documented features + * of Comctl32.dll version 6.0 on Sep. 9, 2002, by Dimitrie O. Paun. + * + * Unless otherwise noted, we believe this code to be complete, as per + * the specification mentioned above. + * If you discover missing features, or bugs, please note them below. + * + */ + +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "comctl32.h" +#include "wine/unicode.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(updown); + +typedef struct +{ + HWND Self; /* Handle to this up-down control */ + HWND Notify; /* Handle to the parent window */ + DWORD dwStyle; /* The GWL_STYLE for this window */ + UINT AccelCount; /* Number of elements in AccelVect */ + UDACCEL* AccelVect; /* Vector containing AccelCount elements */ + INT AccelIndex; /* Current accel index, -1 if not accel'ing */ + INT Base; /* Base to display nr in the buddy window */ + INT CurVal; /* Current up-down value */ + INT MinVal; /* Minimum up-down value */ + INT MaxVal; /* Maximum up-down value */ + HWND Buddy; /* Handle to the buddy window */ + INT BuddyType; /* Remembers the buddy type BUDDY_TYPE_* */ + INT Flags; /* Internal Flags FLAG_* */ + BOOL UnicodeFormat; /* Marks the use of Unicode internally */ +} UPDOWN_INFO; + +/* Control configuration constants */ + +#define INITIAL_DELAY 500 /* initial timer until auto-inc kicks in */ +#define AUTOPRESS_DELAY 250 /* time to keep arrow pressed on KEY_DOWN */ +#define REPEAT_DELAY 50 /* delay between auto-increments */ + +#define DEFAULT_WIDTH 14 /* default width of the ctrl */ +#define DEFAULT_XSEP 0 /* default separation between buddy and ctrl */ +#define DEFAULT_ADDTOP 0 /* amount to extend above the buddy window */ +#define DEFAULT_ADDBOT 0 /* amount to extend below the buddy window */ +#define DEFAULT_BUDDYBORDER 2 /* Width/height of the buddy border */ +#define DEFAULT_BUDDYSPACER 2 /* Spacer between the buddy and the ctrl */ + + +/* Work constants */ + +#define FLAG_INCR 0x01 +#define FLAG_DECR 0x02 +#define FLAG_MOUSEIN 0x04 +#define FLAG_PRESSED 0x08 +#define FLAG_ARROW (FLAG_INCR | FLAG_DECR) + +#define BUDDY_TYPE_UNKNOWN 0 +#define BUDDY_TYPE_LISTBOX 1 +#define BUDDY_TYPE_EDIT 2 + +#define TIMER_AUTOREPEAT 1 +#define TIMER_ACCEL 2 +#define TIMER_AUTOPRESS 3 + +#define UPDOWN_GetInfoPtr(hwnd) ((UPDOWN_INFO *)GetWindowLongPtrW (hwnd,0)) +#define COUNT_OF(a) (sizeof(a)/sizeof(a[0])) + +static const WCHAR BUDDY_UPDOWN_HWND[] = { 'b', 'u', 'd', 'd', 'y', 'U', 'p', 'D', 'o', 'w', 'n', 'H', 'W', 'N', 'D', 0 }; +static const WCHAR BUDDY_SUPERCLASS_WNDPROC[] = { 'b', 'u', 'd', 'd', 'y', 'S', 'u', 'p', 'p', 'e', 'r', + 'C', 'l', 'a', 's', 's', 'W', 'n', 'd', 'P', 'r', 'o', 'c', 0 }; +static void UPDOWN_DoAction (UPDOWN_INFO *infoPtr, int delta, int action); + +/*********************************************************************** + * UPDOWN_IsBuddyEdit + * Tests if our buddy is an edit control. + */ +static inline BOOL UPDOWN_IsBuddyEdit(UPDOWN_INFO *infoPtr) +{ + return infoPtr->BuddyType == BUDDY_TYPE_EDIT; +} + +/*********************************************************************** + * UPDOWN_IsBuddyListbox + * Tests if our buddy is a listbox control. + */ +static inline BOOL UPDOWN_IsBuddyListbox(UPDOWN_INFO *infoPtr) +{ + return infoPtr->BuddyType == BUDDY_TYPE_LISTBOX; +} + +/*********************************************************************** + * UPDOWN_InBounds + * Tests if a given value 'val' is between the Min&Max limits + */ +static BOOL UPDOWN_InBounds(UPDOWN_INFO *infoPtr, int val) +{ + if(infoPtr->MaxVal > infoPtr->MinVal) + return (infoPtr->MinVal <= val) && (val <= infoPtr->MaxVal); + else + return (infoPtr->MaxVal <= val) && (val <= infoPtr->MinVal); +} + +/*********************************************************************** + * UPDOWN_OffsetVal + * Change the current value by delta. + * It returns TRUE is the value was changed successfuly, or FALSE + * if the value was not changed, as it would go out of bounds. + */ +static BOOL UPDOWN_OffsetVal(UPDOWN_INFO *infoPtr, int delta) +{ + /* check if we can do the modification first */ + if(!UPDOWN_InBounds (infoPtr, infoPtr->CurVal+delta)) { + if (infoPtr->dwStyle & UDS_WRAP) { + delta += (delta < 0 ? -1 : 1) * + (infoPtr->MaxVal < infoPtr->MinVal ? -1 : 1) * + (infoPtr->MinVal - infoPtr->MaxVal) + + (delta < 0 ? 1 : -1); + } else return FALSE; + } + + infoPtr->CurVal += delta; + return TRUE; +} + +/*********************************************************************** + * UPDOWN_HasBuddyBorder + * + * When we have a buddy set and that we are aligned on our buddy, we + * want to draw a sunken edge to make like we are part of that control. + */ +static BOOL UPDOWN_HasBuddyBorder(UPDOWN_INFO* infoPtr) +{ + return ( ((infoPtr->dwStyle & (UDS_ALIGNLEFT | UDS_ALIGNRIGHT)) != 0) && + UPDOWN_IsBuddyEdit(infoPtr) ); +} + +/*********************************************************************** + * UPDOWN_GetArrowRect + * wndPtr - pointer to the up-down wnd + * rect - will hold the rectangle + * arrow - FLAG_INCR to get the "increment" rect (up or right) + * FLAG_DECR to get the "decrement" rect (down or left) + * If both flags are pressent, the envelope is returned. + */ +static void UPDOWN_GetArrowRect (UPDOWN_INFO* infoPtr, RECT *rect, int arrow) +{ + GetClientRect (infoPtr->Self, rect); + + /* + * Make sure we calculate the rectangle to fit even if we draw the + * border. + */ + if (UPDOWN_HasBuddyBorder(infoPtr)) { + if (infoPtr->dwStyle & UDS_ALIGNLEFT) + rect->left += DEFAULT_BUDDYBORDER; + else + rect->right -= DEFAULT_BUDDYBORDER; + + InflateRect(rect, 0, -DEFAULT_BUDDYBORDER); + } + + /* now figure out if we need a space away from the buddy */ + if ( IsWindow(infoPtr->Buddy) ) { + if (infoPtr->dwStyle & UDS_ALIGNLEFT) rect->right -= DEFAULT_BUDDYSPACER; + else rect->left += DEFAULT_BUDDYSPACER; + } + + /* + * We're calculating the midpoint to figure-out where the + * separation between the buttons will lay. We make sure that we + * round the uneven numbers by adding 1. + */ + if (infoPtr->dwStyle & UDS_HORZ) { + int len = rect->right - rect->left + 1; /* compute the width */ + if (arrow & FLAG_INCR) + rect->left = rect->left + len/2; + if (arrow & FLAG_DECR) + rect->right = rect->left + len/2 - 1; + } else { + int len = rect->bottom - rect->top + 1; /* compute the height */ + if (arrow & FLAG_INCR) + rect->bottom = rect->top + len/2 - 1; + if (arrow & FLAG_DECR) + rect->top = rect->top + len/2; + } +} + +/*********************************************************************** + * UPDOWN_GetArrowFromPoint + * Returns the rectagle (for the up or down arrow) that contains pt. + * If it returns the up rect, it returns TRUE. + * If it returns the down rect, it returns FALSE. + */ +static BOOL UPDOWN_GetArrowFromPoint (UPDOWN_INFO* infoPtr, RECT *rect, POINT pt) +{ + UPDOWN_GetArrowRect (infoPtr, rect, FLAG_INCR); + if(PtInRect(rect, pt)) return FLAG_INCR; + + UPDOWN_GetArrowRect (infoPtr, rect, FLAG_DECR); + if(PtInRect(rect, pt)) return FLAG_DECR; + + return 0; +} + + +/*********************************************************************** + * UPDOWN_GetThousandSep + * Returns the thousand sep. If an error occurs, it returns ','. + */ +static WCHAR UPDOWN_GetThousandSep(void) +{ + WCHAR sep[2]; + + if(GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, sep, 2) != 1) + sep[0] = ','; + + return sep[0]; +} + +/*********************************************************************** + * UPDOWN_GetBuddyInt + * Tries to read the pos from the buddy window and if it succeeds, + * it stores it in the control's CurVal + * returns: + * TRUE - if it read the integer from the buddy successfully + * FALSE - if an error occurred + */ +static BOOL UPDOWN_GetBuddyInt (UPDOWN_INFO *infoPtr) +{ + WCHAR txt[20], sep, *src, *dst; + int newVal; + + if (!((infoPtr->dwStyle & UDS_SETBUDDYINT) && IsWindow(infoPtr->Buddy))) + return FALSE; + + /*if the buddy is a list window, we must set curr index */ + if (UPDOWN_IsBuddyListbox(infoPtr)) { + newVal = SendMessageW(infoPtr->Buddy, LB_GETCARETINDEX, 0, 0); + if(newVal < 0) return FALSE; + } else { + /* we have a regular window, so will get the text */ + /* note that a zero-length string is a legitimate value for 'txt', + * and ought to result in a successful conversion to '0'. */ + if (GetWindowTextW(infoPtr->Buddy, txt, COUNT_OF(txt)) < 0) + return FALSE; + + sep = UPDOWN_GetThousandSep(); + + /* now get rid of the separators */ + for(src = dst = txt; *src; src++) + if(*src != sep) *dst++ = *src; + *dst = 0; + + /* try to convert the number and validate it */ + newVal = strtolW(txt, &src, infoPtr->Base); + if(*src || !UPDOWN_InBounds (infoPtr, newVal)) return FALSE; + } + + TRACE("new value(%d) from buddy (old=%d)\n", newVal, infoPtr->CurVal); + infoPtr->CurVal = newVal; + return TRUE; +} + + +/*********************************************************************** + * UPDOWN_SetBuddyInt + * Tries to set the pos to the buddy window based on current pos + * returns: + * TRUE - if it set the caption of the buddy successfully + * FALSE - if an error occurred + */ +static BOOL UPDOWN_SetBuddyInt (UPDOWN_INFO *infoPtr) +{ + WCHAR fmt[3] = { '%', 'd', '\0' }; + WCHAR txt[20]; + int len; + + if (!((infoPtr->dwStyle & UDS_SETBUDDYINT) && IsWindow(infoPtr->Buddy))) + return FALSE; + + TRACE("set new value(%d) to buddy.\n", infoPtr->CurVal); + + /*if the buddy is a list window, we must set curr index */ + if (UPDOWN_IsBuddyListbox(infoPtr)) { + return SendMessageW(infoPtr->Buddy, LB_SETCURSEL, infoPtr->CurVal, 0) != LB_ERR; + } + + /* Regular window, so set caption to the number */ + if (infoPtr->Base == 16) fmt[1] = 'X'; + len = wsprintfW(txt, fmt, infoPtr->CurVal); + + + /* Do thousands separation if necessary */ + if (!(infoPtr->dwStyle & UDS_NOTHOUSANDS) && (len > 3)) { + WCHAR tmp[COUNT_OF(txt)], *src = tmp, *dst = txt; + WCHAR sep = UPDOWN_GetThousandSep(); + int start = len % 3; + + memcpy(tmp, txt, sizeof(txt)); + if (start == 0) start = 3; + dst += start; + src += start; + for (len=0; *src; len++) { + if (len % 3 == 0) *dst++ = sep; + *dst++ = *src++; + } + *dst = 0; + } + + return SetWindowTextW(infoPtr->Buddy, txt); +} + +/*********************************************************************** + * UPDOWN_Draw + * + * Draw the arrows. The background need not be erased. + */ +static LRESULT UPDOWN_Draw (UPDOWN_INFO *infoPtr, HDC hdc) +{ + BOOL pressed, hot; + RECT rect; + + /* Draw the common border between ourselves and our buddy */ + if (UPDOWN_HasBuddyBorder(infoPtr)) { + GetClientRect(infoPtr->Self, &rect); + DrawEdge(hdc, &rect, EDGE_SUNKEN, + BF_BOTTOM | BF_TOP | + (infoPtr->dwStyle & UDS_ALIGNLEFT ? BF_LEFT : BF_RIGHT)); + } + + /* Draw the incr button */ + UPDOWN_GetArrowRect (infoPtr, &rect, FLAG_INCR); + pressed = (infoPtr->Flags & FLAG_PRESSED) && (infoPtr->Flags & FLAG_INCR); + hot = (infoPtr->Flags & FLAG_INCR) && (infoPtr->Flags & FLAG_MOUSEIN); + DrawFrameControl(hdc, &rect, DFC_SCROLL, + (infoPtr->dwStyle & UDS_HORZ ? DFCS_SCROLLRIGHT : DFCS_SCROLLUP) | + ((infoPtr->dwStyle & UDS_HOTTRACK) && hot ? DFCS_HOT : 0) | + (pressed ? DFCS_PUSHED : 0) | + (infoPtr->dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) ); + + /* Draw the decr button */ + UPDOWN_GetArrowRect(infoPtr, &rect, FLAG_DECR); + pressed = (infoPtr->Flags & FLAG_PRESSED) && (infoPtr->Flags & FLAG_DECR); + hot = (infoPtr->Flags & FLAG_DECR) && (infoPtr->Flags & FLAG_MOUSEIN); + DrawFrameControl(hdc, &rect, DFC_SCROLL, + (infoPtr->dwStyle & UDS_HORZ ? DFCS_SCROLLLEFT : DFCS_SCROLLDOWN) | + ((infoPtr->dwStyle & UDS_HOTTRACK) && hot ? DFCS_HOT : 0) | + (pressed ? DFCS_PUSHED : 0) | + (infoPtr->dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) ); + + return 0; +} + +/*********************************************************************** + * UPDOWN_Paint + * + * Asynchronous drawing (must ONLY be used in WM_PAINT). + * Calls UPDOWN_Draw. + */ +static LRESULT UPDOWN_Paint (UPDOWN_INFO *infoPtr, HDC hdc) +{ + PAINTSTRUCT ps; + if (hdc) return UPDOWN_Draw (infoPtr, hdc); + hdc = BeginPaint (infoPtr->Self, &ps); + UPDOWN_Draw (infoPtr, hdc); + EndPaint (infoPtr->Self, &ps); + return 0; +} + +/*********************************************************************** + * UPDOWN_KeyPressed + * + * Handle key presses (up & down) when we have to do so + */ +static LRESULT UPDOWN_KeyPressed(UPDOWN_INFO *infoPtr, int key) +{ + int arrow; + + if (key == VK_UP) arrow = FLAG_INCR; + else if (key == VK_DOWN) arrow = FLAG_DECR; + else return 1; + + UPDOWN_GetBuddyInt (infoPtr); + infoPtr->Flags &= ~FLAG_ARROW; + infoPtr->Flags |= FLAG_PRESSED | arrow; + InvalidateRect (infoPtr->Self, NULL, FALSE); + SetTimer(infoPtr->Self, TIMER_AUTOPRESS, AUTOPRESS_DELAY, 0); + UPDOWN_DoAction (infoPtr, 1, arrow); + return 0; +} + +/*********************************************************************** + * UPDOWN_Buddy_SubclassProc used to handle messages sent to the buddy + * control. + */ +static LRESULT CALLBACK +UPDOWN_Buddy_SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + WNDPROC superClassWndProc = (WNDPROC)GetPropW(hwnd, BUDDY_SUPERCLASS_WNDPROC); + + TRACE("hwnd=%p, wndProc=%p, uMsg=%04x, wParam=%08x, lParam=%08lx\n", + hwnd, superClassWndProc, uMsg, wParam, lParam); + + if (uMsg == WM_KEYDOWN) { + HWND upDownHwnd = GetPropW(hwnd, BUDDY_UPDOWN_HWND); + + UPDOWN_KeyPressed(UPDOWN_GetInfoPtr(upDownHwnd), (int)wParam); + } + + return CallWindowProcW( superClassWndProc, hwnd, uMsg, wParam, lParam); +} + +/*********************************************************************** + * UPDOWN_SetBuddy + * + * Sets bud as a new Buddy. + * Then, it should subclass the buddy + * If window has the UDS_ARROWKEYS, it subcalsses the buddy window to + * process the UP/DOWN arrow keys. + * If window has the UDS_ALIGNLEFT or UDS_ALIGNRIGHT style + * the size/pos of the buddy and the control are adjusted accordingly. + */ +static HWND UPDOWN_SetBuddy (UPDOWN_INFO* infoPtr, HWND bud) +{ + static const WCHAR editW[] = { 'E', 'd', 'i', 't', 0 }; + static const WCHAR listboxW[] = { 'L', 'i', 's', 't', 'b', 'o', 'x', 0 }; + RECT budRect; /* new coord for the buddy */ + int x, width; /* new x position and width for the up-down */ + WNDPROC baseWndProc; + WCHAR buddyClass[40]; + HWND ret; + + TRACE("(hwnd=%p, bud=%p)\n", infoPtr->Self, bud); + + ret = infoPtr->Buddy; + + /* there is already a body assigned */ + if (infoPtr->Buddy) RemovePropW(infoPtr->Buddy, BUDDY_UPDOWN_HWND); + + if(!IsWindow(bud)) + bud = 0; + + /* Store buddy window handle */ + infoPtr->Buddy = bud; + + if(bud) { + + /* keep upDown ctrl hwnd in a buddy property */ + SetPropW( bud, BUDDY_UPDOWN_HWND, infoPtr->Self); + + /* Store buddy window class type */ + infoPtr->BuddyType = BUDDY_TYPE_UNKNOWN; + if (GetClassNameW(bud, buddyClass, COUNT_OF(buddyClass))) { + if (lstrcmpiW(buddyClass, editW) == 0) + infoPtr->BuddyType = BUDDY_TYPE_EDIT; + else if (lstrcmpiW(buddyClass, listboxW) == 0) + infoPtr->BuddyType = BUDDY_TYPE_LISTBOX; + } + + if(infoPtr->dwStyle & UDS_ARROWKEYS){ + /* Note that I don't clear the BUDDY_SUPERCLASS_WNDPROC property + when we reset the upDown ctrl buddy to another buddy because it is not + good to break the window proc chain. */ + if (!GetPropW(bud, BUDDY_SUPERCLASS_WNDPROC)) { + baseWndProc = (WNDPROC)SetWindowLongPtrW(bud, GWLP_WNDPROC, (LPARAM)UPDOWN_Buddy_SubclassProc); + SetPropW(bud, BUDDY_SUPERCLASS_WNDPROC, (HANDLE)baseWndProc); + } + } + + /* Get the rect of the buddy relative to its parent */ + GetWindowRect(infoPtr->Buddy, &budRect); + MapWindowPoints(HWND_DESKTOP, GetParent(infoPtr->Buddy), (POINT *)(&budRect.left), 2); + + /* now do the positioning */ + if (infoPtr->dwStyle & UDS_ALIGNLEFT) { + x = budRect.left; + budRect.left += DEFAULT_WIDTH + DEFAULT_XSEP; + } else if (infoPtr->dwStyle & UDS_ALIGNRIGHT) { + budRect.right -= DEFAULT_WIDTH + DEFAULT_XSEP; + x = budRect.right+DEFAULT_XSEP; + } else { + /* nothing to do */ + return ret; + } + + /* first adjust the buddy to accommodate the up/down */ + SetWindowPos(infoPtr->Buddy, 0, budRect.left, budRect.top, + budRect.right - budRect.left, budRect.bottom - budRect.top, + SWP_NOACTIVATE|SWP_NOZORDER); + + /* now position the up/down */ + /* Since the UDS_ALIGN* flags were used, */ + /* we will pick the position and size of the window. */ + width = DEFAULT_WIDTH; + + /* + * If the updown has a buddy border, it has to overlap with the buddy + * to look as if it is integrated with the buddy control. + * We nudge the control or change its size to overlap. + */ + if (UPDOWN_HasBuddyBorder(infoPtr)) { + if(infoPtr->dwStyle & UDS_ALIGNLEFT) + width += DEFAULT_BUDDYBORDER; + else + x -= DEFAULT_BUDDYBORDER; + } + + SetWindowPos(infoPtr->Self, 0, x, + budRect.top - DEFAULT_ADDTOP, width, + budRect.bottom - budRect.top + DEFAULT_ADDTOP + DEFAULT_ADDBOT, + SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOZORDER); + } else { + RECT rect; + GetWindowRect(infoPtr->Self, &rect); + MapWindowPoints(HWND_DESKTOP, GetParent(infoPtr->Self), (POINT *)&rect, 2); + SetWindowPos(infoPtr->Self, 0, rect.left, rect.top, DEFAULT_WIDTH, rect.bottom - rect.top, + SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOZORDER); + } + return ret; +} + +/*********************************************************************** + * UPDOWN_DoAction + * + * This function increments/decrements the CurVal by the + * 'delta' amount according to the 'action' flag which can be a + * combination of FLAG_INCR and FLAG_DECR + * It notifies the parent as required. + * It handles wraping and non-wraping correctly. + * It is assumed that delta>0 + */ +static void UPDOWN_DoAction (UPDOWN_INFO *infoPtr, int delta, int action) +{ + NM_UPDOWN ni; + + TRACE("%d by %d\n", action, delta); + + /* check if we can do the modification first */ + delta *= (action & FLAG_INCR ? 1 : -1) * (infoPtr->MaxVal < infoPtr->MinVal ? -1 : 1); + if ( (action & FLAG_INCR) && (action & FLAG_DECR) ) delta = 0; + + TRACE("current %d, delta: %d\n", infoPtr->CurVal, delta); + + /* We must notify parent now to obtain permission */ + ni.iPos = infoPtr->CurVal; + ni.iDelta = delta; + ni.hdr.hwndFrom = infoPtr->Self; + ni.hdr.idFrom = GetWindowLongPtrW (infoPtr->Self, GWLP_ID); + ni.hdr.code = UDN_DELTAPOS; + if (!SendMessageW(infoPtr->Notify, WM_NOTIFY, (WPARAM)ni.hdr.idFrom, (LPARAM)&ni)) { + /* Parent said: OK to adjust */ + + /* Now adjust value with (maybe new) delta */ + if (UPDOWN_OffsetVal (infoPtr, ni.iDelta)) { + TRACE("new %d, delta: %d\n", infoPtr->CurVal, ni.iDelta); + + /* Now take care about our buddy */ + UPDOWN_SetBuddyInt (infoPtr); + } + } + + /* Also, notify it. This message is sent in any case. */ + SendMessageW( infoPtr->Notify, (infoPtr->dwStyle & UDS_HORZ) ? WM_HSCROLL : WM_VSCROLL, + MAKELONG(SB_THUMBPOSITION, infoPtr->CurVal), (LPARAM)infoPtr->Self); +} + +/*********************************************************************** + * UPDOWN_IsEnabled + * + * Returns TRUE if it is enabled as well as its buddy (if any) + * FALSE otherwise + */ +static BOOL UPDOWN_IsEnabled (UPDOWN_INFO *infoPtr) +{ + if (!IsWindowEnabled(infoPtr->Self)) + return FALSE; + if(infoPtr->Buddy) + return IsWindowEnabled(infoPtr->Buddy); + return TRUE; +} + +/*********************************************************************** + * UPDOWN_CancelMode + * + * Deletes any timers, releases the mouse and does redraw if necessary. + * If the control is not in "capture" mode, it does nothing. + * If the control was not in cancel mode, it returns FALSE. + * If the control was in cancel mode, it returns TRUE. + */ +static BOOL UPDOWN_CancelMode (UPDOWN_INFO *infoPtr) +{ + if (!(infoPtr->Flags & FLAG_PRESSED)) return FALSE; + + KillTimer (infoPtr->Self, TIMER_AUTOREPEAT); + KillTimer (infoPtr->Self, TIMER_ACCEL); + KillTimer (infoPtr->Self, TIMER_AUTOPRESS); + + if (GetCapture() == infoPtr->Self) { + NMHDR hdr; + hdr.hwndFrom = infoPtr->Self; + hdr.idFrom = GetWindowLongPtrW (infoPtr->Self, GWLP_ID); + hdr.code = NM_RELEASEDCAPTURE; + SendMessageW(infoPtr->Notify, WM_NOTIFY, hdr.idFrom, (LPARAM)&hdr); + ReleaseCapture(); + } + + infoPtr->Flags &= ~FLAG_PRESSED; + InvalidateRect (infoPtr->Self, NULL, FALSE); + + return TRUE; +} + +/*********************************************************************** + * UPDOWN_HandleMouseEvent + * + * Handle a mouse event for the updown. + * 'pt' is the location of the mouse event in client or + * windows coordinates. + */ +static void UPDOWN_HandleMouseEvent (UPDOWN_INFO *infoPtr, UINT msg, INT x, INT y) +{ + POINT pt = { x, y }; + RECT rect; + int temp, arrow; + + TRACE("msg %04x point %s\n", msg, wine_dbgstr_point(&pt)); + + switch(msg) + { + case WM_LBUTTONDOWN: /* Initialise mouse tracking */ + + /* If the buddy is an edit, will set focus to it */ + if (UPDOWN_IsBuddyEdit(infoPtr)) SetFocus(infoPtr->Buddy); + + /* Now see which one is the 'active' arrow */ + arrow = UPDOWN_GetArrowFromPoint (infoPtr, &rect, pt); + + /* Update the flags if we are in/out */ + infoPtr->Flags &= ~(FLAG_MOUSEIN | FLAG_ARROW); + if (arrow) + infoPtr->Flags |= FLAG_MOUSEIN | arrow; + else + if (infoPtr->AccelIndex != -1) infoPtr->AccelIndex = 0; + + if (infoPtr->Flags & FLAG_ARROW) { + + /* Update the CurVal if necessary */ + UPDOWN_GetBuddyInt (infoPtr); + + /* Set up the correct flags */ + infoPtr->Flags |= FLAG_PRESSED; + + /* repaint the control */ + InvalidateRect (infoPtr->Self, NULL, FALSE); + + /* process the click */ + temp = (infoPtr->AccelCount && infoPtr->AccelVect) ? infoPtr->AccelVect[0].nInc : 1; + UPDOWN_DoAction (infoPtr, temp, infoPtr->Flags & FLAG_ARROW); + + /* now capture all mouse messages */ + SetCapture (infoPtr->Self); + + /* and startup the first timer */ + SetTimer(infoPtr->Self, TIMER_AUTOREPEAT, INITIAL_DELAY, 0); + } + break; + + case WM_MOUSEMOVE: + /* save the flags to see if any got modified */ + temp = infoPtr->Flags; + + /* Now see which one is the 'active' arrow */ + arrow = UPDOWN_GetArrowFromPoint (infoPtr, &rect, pt); + + /* Update the flags if we are in/out */ + infoPtr->Flags &= ~(FLAG_MOUSEIN | FLAG_ARROW); + if(arrow) { + infoPtr->Flags |= FLAG_MOUSEIN | arrow; + } else { + if(infoPtr->AccelIndex != -1) infoPtr->AccelIndex = 0; + } + + /* If state changed, redraw the control */ + if(temp != infoPtr->Flags) + InvalidateRect (infoPtr->Self, &rect, FALSE); + break; + + default: + ERR("Impossible case (msg=%x)!\n", msg); + } + +} + +/*********************************************************************** + * UpDownWndProc + */ +static LRESULT WINAPI UpDownWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd); + int temp; + + TRACE("hwnd=%p msg=%04x wparam=%08x lparam=%08lx\n", hwnd, message, wParam, lParam); + + if (!infoPtr && (message != WM_CREATE)) + return DefWindowProcW (hwnd, message, wParam, lParam); + + switch(message) + { + case WM_CREATE: + infoPtr = (UPDOWN_INFO*)Alloc (sizeof(UPDOWN_INFO)); + SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); + + /* initialize the info struct */ + infoPtr->Self = hwnd; + infoPtr->Notify = ((LPCREATESTRUCTW)lParam)->hwndParent; + infoPtr->dwStyle = ((LPCREATESTRUCTW)lParam)->style; + infoPtr->AccelCount = 0; + infoPtr->AccelVect = 0; + infoPtr->AccelIndex = -1; + infoPtr->CurVal = 0; + infoPtr->MinVal = 100; + infoPtr->MaxVal = 0; + infoPtr->Base = 10; /* Default to base 10 */ + infoPtr->Buddy = 0; /* No buddy window yet */ + infoPtr->Flags = 0; /* And no flags */ + + SetWindowLongW (hwnd, GWL_STYLE, infoPtr->dwStyle & ~WS_BORDER); + + /* Do we pick the buddy win ourselves? */ + if (infoPtr->dwStyle & UDS_AUTOBUDDY) + UPDOWN_SetBuddy (infoPtr, GetWindow (hwnd, GW_HWNDPREV)); + + TRACE("UpDown Ctrl creation, hwnd=%p\n", hwnd); + break; + + case WM_DESTROY: + if(infoPtr->AccelVect) Free (infoPtr->AccelVect); + + if(infoPtr->Buddy) RemovePropW(infoPtr->Buddy, BUDDY_UPDOWN_HWND); + + Free (infoPtr); + SetWindowLongPtrW (hwnd, 0, 0); + TRACE("UpDown Ctrl destruction, hwnd=%p\n", hwnd); + break; + + case WM_ENABLE: + if (wParam) { + infoPtr->dwStyle &= ~WS_DISABLED; + } else { + infoPtr->dwStyle |= WS_DISABLED; + UPDOWN_CancelMode (infoPtr); + } + InvalidateRect (infoPtr->Self, NULL, FALSE); + break; + + case WM_STYLECHANGED: + if (wParam == GWL_STYLE) { + infoPtr->dwStyle = ((LPSTYLESTRUCT)lParam)->styleNew; + InvalidateRect (infoPtr->Self, NULL, FALSE); + } + break; + + case WM_TIMER: + /* is this the auto-press timer? */ + if(wParam == TIMER_AUTOPRESS) { + KillTimer(hwnd, TIMER_AUTOPRESS); + infoPtr->Flags &= ~(FLAG_PRESSED | FLAG_ARROW); + InvalidateRect(infoPtr->Self, NULL, FALSE); + } + + /* if initial timer, kill it and start the repeat timer */ + if(wParam == TIMER_AUTOREPEAT) { + KillTimer(hwnd, TIMER_AUTOREPEAT); + /* if no accel info given, used default timer */ + if(infoPtr->AccelCount==0 || infoPtr->AccelVect==0) { + infoPtr->AccelIndex = -1; + temp = REPEAT_DELAY; + } else { + infoPtr->AccelIndex = 0; /* otherwise, use it */ + temp = infoPtr->AccelVect[infoPtr->AccelIndex].nSec * 1000 + 1; + } + SetTimer(hwnd, TIMER_ACCEL, temp, 0); + } + + /* now, if the mouse is above us, do the thing...*/ + if(infoPtr->Flags & FLAG_MOUSEIN) { + temp = infoPtr->AccelIndex == -1 ? 1 : infoPtr->AccelVect[infoPtr->AccelIndex].nInc; + UPDOWN_DoAction(infoPtr, temp, infoPtr->Flags & FLAG_ARROW); + + if(infoPtr->AccelIndex != -1 && infoPtr->AccelIndex < infoPtr->AccelCount-1) { + KillTimer(hwnd, TIMER_ACCEL); + infoPtr->AccelIndex++; /* move to the next accel info */ + temp = infoPtr->AccelVect[infoPtr->AccelIndex].nSec * 1000 + 1; + /* make sure we have at least 1ms intervals */ + SetTimer(hwnd, TIMER_ACCEL, temp, 0); + } + } + break; + + case WM_CANCELMODE: + return UPDOWN_CancelMode (infoPtr); + + case WM_LBUTTONUP: + if (GetCapture() != infoPtr->Self) break; + + if ( (infoPtr->Flags & FLAG_MOUSEIN) && + (infoPtr->Flags & FLAG_ARROW) ) { + + SendMessageW( infoPtr->Notify, + (infoPtr->dwStyle & UDS_HORZ) ? WM_HSCROLL : WM_VSCROLL, + MAKELONG(SB_ENDSCROLL, infoPtr->CurVal), + (LPARAM)hwnd); + if (UPDOWN_IsBuddyEdit(infoPtr)) + SendMessageW(infoPtr->Buddy, EM_SETSEL, 0, MAKELONG(0, -1)); + } + UPDOWN_CancelMode(infoPtr); + break; + + case WM_LBUTTONDOWN: + case WM_MOUSEMOVE: + if(UPDOWN_IsEnabled(infoPtr)) + UPDOWN_HandleMouseEvent (infoPtr, message, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); + break; + + case WM_KEYDOWN: + if((infoPtr->dwStyle & UDS_ARROWKEYS) && UPDOWN_IsEnabled(infoPtr)) + return UPDOWN_KeyPressed(infoPtr, (int)wParam); + break; + + case WM_PAINT: + return UPDOWN_Paint (infoPtr, (HDC)wParam); + + case UDM_GETACCEL: + if (wParam==0 && lParam==0) return infoPtr->AccelCount; + if (wParam && lParam) { + temp = min(infoPtr->AccelCount, wParam); + memcpy((void *)lParam, infoPtr->AccelVect, temp*sizeof(UDACCEL)); + return temp; + } + return 0; + + case UDM_SETACCEL: + TRACE("UDM_SETACCEL\n"); + + if(infoPtr->AccelVect) { + Free (infoPtr->AccelVect); + infoPtr->AccelCount = 0; + infoPtr->AccelVect = 0; + } + if(wParam==0) return TRUE; + infoPtr->AccelVect = Alloc (wParam*sizeof(UDACCEL)); + if(infoPtr->AccelVect == 0) return FALSE; + memcpy(infoPtr->AccelVect, (void*)lParam, wParam*sizeof(UDACCEL)); + infoPtr->AccelCount = wParam; + + for (temp = 0; temp < wParam; temp++) + TRACE("%d: nSec %u nInc %u\n", temp, infoPtr->AccelVect[temp].nSec, infoPtr->AccelVect[temp].nInc); + + return TRUE; + + case UDM_GETBASE: + return infoPtr->Base; + + case UDM_SETBASE: + TRACE("UpDown Ctrl new base(%d), hwnd=%p\n", wParam, hwnd); + if (wParam==10 || wParam==16) { + temp = infoPtr->Base; + infoPtr->Base = wParam; + return temp; + } + break; + + case UDM_GETBUDDY: + return (LRESULT)infoPtr->Buddy; + + case UDM_SETBUDDY: + return (LRESULT)UPDOWN_SetBuddy (infoPtr, (HWND)wParam); + + case UDM_GETPOS: + temp = UPDOWN_GetBuddyInt (infoPtr); + return MAKELONG(infoPtr->CurVal, temp ? 0 : 1); + + case UDM_SETPOS: + temp = (short)LOWORD(lParam); + TRACE("UpDown Ctrl new value(%d), hwnd=%p\n", temp, hwnd); + if(!UPDOWN_InBounds(infoPtr, temp)) { + if(temp < infoPtr->MinVal) temp = infoPtr->MinVal; + if(temp > infoPtr->MaxVal) temp = infoPtr->MaxVal; + } + wParam = infoPtr->CurVal; + infoPtr->CurVal = temp; + UPDOWN_SetBuddyInt (infoPtr); + return wParam; /* return prev value */ + + case UDM_GETRANGE: + return MAKELONG(infoPtr->MaxVal, infoPtr->MinVal); + + case UDM_SETRANGE: + /* we must have: */ + infoPtr->MaxVal = (short)(lParam); /* UD_MINVAL <= Max <= UD_MAXVAL */ + infoPtr->MinVal = (short)HIWORD(lParam); /* UD_MINVAL <= Min <= UD_MAXVAL */ + /* |Max-Min| <= UD_MAXVAL */ + TRACE("UpDown Ctrl new range(%d to %d), hwnd=%p\n", + infoPtr->MinVal, infoPtr->MaxVal, hwnd); + break; + + case UDM_GETRANGE32: + if (wParam) *(LPINT)wParam = infoPtr->MinVal; + if (lParam) *(LPINT)lParam = infoPtr->MaxVal; + break; + + case UDM_SETRANGE32: + infoPtr->MinVal = (INT)wParam; + infoPtr->MaxVal = (INT)lParam; + if (infoPtr->MaxVal <= infoPtr->MinVal) + infoPtr->MaxVal = infoPtr->MinVal + 1; + TRACE("UpDown Ctrl new range(%d to %d), hwnd=%p\n", + infoPtr->MinVal, infoPtr->MaxVal, hwnd); + break; + + case UDM_GETPOS32: + if ((LPBOOL)lParam != NULL) *((LPBOOL)lParam) = TRUE; + return infoPtr->CurVal; + + case UDM_SETPOS32: + if(!UPDOWN_InBounds(infoPtr, (int)lParam)) { + if((int)lParam < infoPtr->MinVal) lParam = infoPtr->MinVal; + if((int)lParam > infoPtr->MaxVal) lParam = infoPtr->MaxVal; + } + temp = infoPtr->CurVal; /* save prev value */ + infoPtr->CurVal = (int)lParam; /* set the new value */ + UPDOWN_SetBuddyInt (infoPtr); + return temp; /* return prev value */ + + case UDM_GETUNICODEFORMAT: + /* we lie a bit here, we're always using Unicode internally */ + return infoPtr->UnicodeFormat; + + case UDM_SETUNICODEFORMAT: + /* do we really need to honour this flag? */ + temp = infoPtr->UnicodeFormat; + infoPtr->UnicodeFormat = (BOOL)wParam; + return temp; + + default: + if ((message >= WM_USER) && (message < WM_APP)) + ERR("unknown msg %04x wp=%04x lp=%08lx\n", message, wParam, lParam); + return DefWindowProcW (hwnd, message, wParam, lParam); + } + + return 0; +} + +/*********************************************************************** + * UPDOWN_Register [Internal] + * + * Registers the updown window class. + */ +void UPDOWN_Register(void) +{ + WNDCLASSW wndClass; + + ZeroMemory( &wndClass, sizeof( WNDCLASSW ) ); + wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW; + wndClass.lpfnWndProc = UpDownWindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(UPDOWN_INFO*); + wndClass.hCursor = LoadCursorW( 0, (LPWSTR)IDC_ARROW ); + wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); + wndClass.lpszClassName = UPDOWN_CLASSW; + + RegisterClassW( &wndClass ); +} + + +/*********************************************************************** + * UPDOWN_Unregister [Internal] + * + * Unregisters the updown window class. + */ +void UPDOWN_Unregister (void) +{ + UnregisterClassW (UPDOWN_CLASSW, NULL); +} diff --git a/reactos/lib/comdlg32/cdlg.h b/reactos/lib/comdlg32/cdlg.h index 4a470f20834..2696199af3a 100644 --- a/reactos/lib/comdlg32/cdlg.h +++ b/reactos/lib/comdlg32/cdlg.h @@ -1,232 +1,232 @@ -/* - * Common Dialog Boxes interface (32 bit) - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _WINE_DLL_CDLG_H -#define _WINE_DLL_CDLG_H - -#define COM_NO_WINDOWS_H -#include "dlgs.h" -#include "wownt32.h" - -/* Common dialogs implementation globals */ -#define COMDLG32_Atom ((ATOM)0xa000) /* MS uses this one to identify props */ - -extern HINSTANCE COMDLG32_hInstance; - -void COMDLG32_SetCommDlgExtendedError(DWORD err); -LPVOID COMDLG32_AllocMem(int size); - -/* handle<-handle16 conversion */ -#define HINSTANCE_32(h16) ((HINSTANCE)(ULONG_PTR)(h16)) - -/* Find/Replace local definitions */ - -#define FR_WINE_UNICODE 0x80000000 -#define FR_WINE_REPLACE 0x40000000 - -typedef struct { - FINDREPLACEA fr; /* Internally used structure */ - union { - FINDREPLACEA *fra; /* Reference to the user supplied structure */ - FINDREPLACEW *frw; - } user_fr; -} COMDLG32_FR_Data; - -#define PD32_PRINT_TITLE 7000 - -#define PD32_VALUE_UREADABLE 1104 -#define PD32_INVALID_PAGE_RANGE 1105 -#define PD32_FROM_NOT_ABOVE_TO 1106 -#define PD32_MARGINS_OVERLAP 1107 -#define PD32_NR_OF_COPIES_EMPTY 1108 -#define PD32_TOO_LARGE_COPIES 1109 -#define PD32_PRINT_ERROR 1110 -#define PD32_NO_DEFAULT_PRINTER 1111 -#define PD32_CANT_FIND_PRINTER 1112 -#define PD32_OUT_OF_MEMORY 1113 -#define PD32_GENERIC_ERROR 1114 -#define PD32_DRIVER_UNKNOWN 1115 - -#define PD32_PRINTER_STATUS_READY 1536 -#define PD32_PRINTER_STATUS_PAUSED 1537 -#define PD32_PRINTER_STATUS_ERROR 1538 -#define PD32_PRINTER_STATUS_PENDING_DELETION 1539 -#define PD32_PRINTER_STATUS_PAPER_JAM 1540 -#define PD32_PRINTER_STATUS_PAPER_OUT 1541 -#define PD32_PRINTER_STATUS_MANUAL_FEED 1542 -#define PD32_PRINTER_STATUS_PAPER_PROBLEM 1543 -#define PD32_PRINTER_STATUS_OFFLINE 1544 -#define PD32_PRINTER_STATUS_IO_ACTIVE 1545 -#define PD32_PRINTER_STATUS_BUSY 1546 -#define PD32_PRINTER_STATUS_PRINTING 1547 -#define PD32_PRINTER_STATUS_OUTPUT_BIN_FULL 1548 -#define PD32_PRINTER_STATUS_NOT_AVAILABLE 1549 -#define PD32_PRINTER_STATUS_WAITING 1550 -#define PD32_PRINTER_STATUS_PROCESSING 1551 -#define PD32_PRINTER_STATUS_INITIALIZING 1552 -#define PD32_PRINTER_STATUS_WARMING_UP 1553 -#define PD32_PRINTER_STATUS_TONER_LOW 1554 -#define PD32_PRINTER_STATUS_NO_TONER 1555 -#define PD32_PRINTER_STATUS_PAGE_PUNT 1556 -#define PD32_PRINTER_STATUS_USER_INTERVENTION 1557 -#define PD32_PRINTER_STATUS_OUT_OF_MEMORY 1558 -#define PD32_PRINTER_STATUS_DOOR_OPEN 1559 -#define PD32_PRINTER_STATUS_SERVER_UNKNOWN 1560 -#define PD32_PRINTER_STATUS_POWER_SAVE 1561 - -#define PD32_DEFAULT_PRINTER 1582 -#define PD32_NR_OF_DOCUMENTS_IN_QUEUE 1583 - -#define PD32_MARGINS_IN_INCHES 1585 -#define PD32_MARGINS_IN_MILIMETERS 1586 -#define PD32_MILIMETERS 1587 - -/* Charset names string IDs */ - -#define IDS_CHARSET_ANSI 200 -#define IDS_CHARSET_SYMBOL 201 -#define IDS_CHARSET_JIS 202 -#define IDS_CHARSET_HANGUL 203 -#define IDS_CHARSET_GB2312 204 -#define IDS_CHARSET_BIG5 205 -#define IDS_CHARSET_GREEK 206 -#define IDS_CHARSET_TURKISH 207 -#define IDS_CHARSET_HEBREW 208 -#define IDS_CHARSET_ARABIC 209 -#define IDS_CHARSET_BALTIC 210 -#define IDS_CHARSET_VIETNAMESE 211 -#define IDS_CHARSET_RUSSIAN 212 -#define IDS_CHARSET_EE 213 -#define IDS_CHARSET_THAI 214 -#define IDS_CHARSET_JOHAB 215 -#define IDS_CHARSET_MAC 216 -#define IDS_CHARSET_OEM 217 -#define IDS_CHARSET_VISCII 218 -#define IDS_CHARSET_TCVN 219 -#define IDS_CHARSET_KOI8 220 -#define IDS_CHARSET_ISO3 221 -#define IDS_CHARSET_ISO4 222 -#define IDS_CHARSET_ISO10 223 -#define IDS_CHARSET_CELTIC 224 - -/* Color names string IDs */ - -#define IDS_COLOR_BLACK 1040 -#define IDS_COLOR_MAROON 1041 -#define IDS_COLOR_GREEN 1042 -#define IDS_COLOR_OLIVE 1043 -#define IDS_COLOR_NAVY 1044 -#define IDS_COLOR_PURPLE 1045 -#define IDS_COLOR_TEAL 1046 -#define IDS_COLOR_GRAY 1047 -#define IDS_COLOR_SILVER 1048 -#define IDS_COLOR_RED 1049 -#define IDS_COLOR_LIME 1050 -#define IDS_COLOR_YELLOW 1051 -#define IDS_COLOR_BLUE 1052 -#define IDS_COLOR_FUCHSIA 1053 -#define IDS_COLOR_AQUA 1054 -#define IDS_COLOR_WHITE 1055 - -#define IDS_FONT_SIZE 1200 -#define IDS_SAVE_BUTTON 1201 -#define IDS_SAVE_IN 1202 -#define IDS_SAVE 1203 -#define IDS_SAVE_AS 1204 -#define IDS_OPEN_FILE 1205 - -#define IDS_FAKEDOCTEXT 1300 - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "shlobj.h" -#include "shellapi.h" - -/* ITEMIDLIST */ - -extern LPITEMIDLIST (WINAPI *COMDLG32_PIDL_ILClone) (LPCITEMIDLIST); -extern LPITEMIDLIST (WINAPI *COMDLG32_PIDL_ILCombine)(LPCITEMIDLIST,LPCITEMIDLIST); -extern LPITEMIDLIST (WINAPI *COMDLG32_PIDL_ILGetNext)(LPITEMIDLIST); -extern BOOL (WINAPI *COMDLG32_PIDL_ILRemoveLastID)(LPCITEMIDLIST); -extern BOOL (WINAPI *COMDLG32_PIDL_ILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST); - -/* SHELL */ -extern LPVOID (WINAPI *COMDLG32_SHAlloc)(DWORD); -extern DWORD (WINAPI *COMDLG32_SHFree)(LPVOID); -extern BOOL (WINAPI *COMDLG32_SHGetFolderPathA)(HWND,int,HANDLE,DWORD,LPSTR); -extern BOOL (WINAPI *COMDLG32_SHGetFolderPathW)(HWND,int,HANDLE,DWORD,LPWSTR); - -extern BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType); -extern BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType); - -/* - * Internal Functions - * Do NOT Export to other programs and dlls - */ - -BOOL CC_HookCallChk( LPCHOOSECOLORW lpcc ); -int CC_MouseCheckResultWindow( HWND hDlg, LPARAM lParam ); -LRESULT CC_WMLButtonDown( HWND hDlg, WPARAM wParam, LPARAM lParam ); -LRESULT CC_WMLButtonUp( HWND hDlg, WPARAM wParam, LPARAM lParam ); -LRESULT CC_WMCommand( HWND hDlg, WPARAM wParam, LPARAM lParam, WORD - notifyCode, HWND hwndCtl ); -LRESULT CC_WMMouseMove( HWND hDlg, LPARAM lParam ); -LRESULT CC_WMPaint( HWND hDlg, WPARAM wParam, LPARAM lParam ); -void CC_SwitchToFullSize( HWND hDlg, COLORREF result, LPRECT lprect ); -void CC_PaintSelectedColor( HWND hDlg, COLORREF cr ); -int CC_RGBtoHSL(char c, int r, int g, int b); -void CC_PaintCross( HWND hDlg, int x, int y); -void CC_PaintTriangle( HWND hDlg, int y); -int CC_CheckDigitsInEdit( HWND hwnd, int maxval ); -void CC_EditSetHSL( HWND hDlg, int h, int s, int l ); -int CC_HSLtoRGB(char c, int hue, int sat, int lum); -void CC_EditSetRGB( HWND hDlg, COLORREF cr ); -void CC_PaintUserColorArray( HWND hDlg, int rows, int cols, COLORREF* lpcr ); - -typedef struct -{ - HWND hWnd1; - HWND hWnd2; - LPCHOOSEFONTW lpcf32w; - int added; -} CFn_ENUMSTRUCT, *LPCFn_ENUMSTRUCT; - -INT AddFontFamily(const ENUMLOGFONTEXW *lpElfex, const NEWTEXTMETRICEXW *lpNTM, - UINT nFontType, LPCHOOSEFONTW lpcf, HWND hwnd, - LPCFn_ENUMSTRUCT e); -INT AddFontStyle(const ENUMLOGFONTEXW *lpElfex, const NEWTEXTMETRICEXW *metrics, - UINT nFontType, LPCHOOSEFONTW lpcf, HWND hcmb2, HWND hcmb3, - HWND hDlg, BOOL iswin16); -void _dump_cf_flags(DWORD cflags); - -LRESULT CFn_WMInitDialog(HWND hDlg, WPARAM wParam, LPARAM lParam, - LPCHOOSEFONTW lpcf); -LRESULT CFn_WMMeasureItem(HWND hDlg, WPARAM wParam, LPARAM lParam); -LRESULT CFn_WMDrawItem(HWND hDlg, WPARAM wParam, LPARAM lParam); -LRESULT CFn_WMCommand(HWND hDlg, WPARAM wParam, LPARAM lParam, - LPCHOOSEFONTW lpcf); -LRESULT CFn_WMPaint(HWND hDlg, WPARAM wParam, LPARAM lParam, - LPCHOOSEFONTW lpcf); - -#endif /* _WINE_DLL_CDLG_H */ +/* + * Common Dialog Boxes interface (32 bit) + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _WINE_DLL_CDLG_H +#define _WINE_DLL_CDLG_H + +#define COM_NO_WINDOWS_H +#include "dlgs.h" +#include "wownt32.h" + +/* Common dialogs implementation globals */ +#define COMDLG32_Atom ((ATOM)0xa000) /* MS uses this one to identify props */ + +extern HINSTANCE COMDLG32_hInstance; + +void COMDLG32_SetCommDlgExtendedError(DWORD err); +LPVOID COMDLG32_AllocMem(int size); + +/* handle<-handle16 conversion */ +#define HINSTANCE_32(h16) ((HINSTANCE)(ULONG_PTR)(h16)) + +/* Find/Replace local definitions */ + +#define FR_WINE_UNICODE 0x80000000 +#define FR_WINE_REPLACE 0x40000000 + +typedef struct { + FINDREPLACEA fr; /* Internally used structure */ + union { + FINDREPLACEA *fra; /* Reference to the user supplied structure */ + FINDREPLACEW *frw; + } user_fr; +} COMDLG32_FR_Data; + +#define PD32_PRINT_TITLE 7000 + +#define PD32_VALUE_UREADABLE 1104 +#define PD32_INVALID_PAGE_RANGE 1105 +#define PD32_FROM_NOT_ABOVE_TO 1106 +#define PD32_MARGINS_OVERLAP 1107 +#define PD32_NR_OF_COPIES_EMPTY 1108 +#define PD32_TOO_LARGE_COPIES 1109 +#define PD32_PRINT_ERROR 1110 +#define PD32_NO_DEFAULT_PRINTER 1111 +#define PD32_CANT_FIND_PRINTER 1112 +#define PD32_OUT_OF_MEMORY 1113 +#define PD32_GENERIC_ERROR 1114 +#define PD32_DRIVER_UNKNOWN 1115 + +#define PD32_PRINTER_STATUS_READY 1536 +#define PD32_PRINTER_STATUS_PAUSED 1537 +#define PD32_PRINTER_STATUS_ERROR 1538 +#define PD32_PRINTER_STATUS_PENDING_DELETION 1539 +#define PD32_PRINTER_STATUS_PAPER_JAM 1540 +#define PD32_PRINTER_STATUS_PAPER_OUT 1541 +#define PD32_PRINTER_STATUS_MANUAL_FEED 1542 +#define PD32_PRINTER_STATUS_PAPER_PROBLEM 1543 +#define PD32_PRINTER_STATUS_OFFLINE 1544 +#define PD32_PRINTER_STATUS_IO_ACTIVE 1545 +#define PD32_PRINTER_STATUS_BUSY 1546 +#define PD32_PRINTER_STATUS_PRINTING 1547 +#define PD32_PRINTER_STATUS_OUTPUT_BIN_FULL 1548 +#define PD32_PRINTER_STATUS_NOT_AVAILABLE 1549 +#define PD32_PRINTER_STATUS_WAITING 1550 +#define PD32_PRINTER_STATUS_PROCESSING 1551 +#define PD32_PRINTER_STATUS_INITIALIZING 1552 +#define PD32_PRINTER_STATUS_WARMING_UP 1553 +#define PD32_PRINTER_STATUS_TONER_LOW 1554 +#define PD32_PRINTER_STATUS_NO_TONER 1555 +#define PD32_PRINTER_STATUS_PAGE_PUNT 1556 +#define PD32_PRINTER_STATUS_USER_INTERVENTION 1557 +#define PD32_PRINTER_STATUS_OUT_OF_MEMORY 1558 +#define PD32_PRINTER_STATUS_DOOR_OPEN 1559 +#define PD32_PRINTER_STATUS_SERVER_UNKNOWN 1560 +#define PD32_PRINTER_STATUS_POWER_SAVE 1561 + +#define PD32_DEFAULT_PRINTER 1582 +#define PD32_NR_OF_DOCUMENTS_IN_QUEUE 1583 + +#define PD32_MARGINS_IN_INCHES 1585 +#define PD32_MARGINS_IN_MILIMETERS 1586 +#define PD32_MILIMETERS 1587 + +/* Charset names string IDs */ + +#define IDS_CHARSET_ANSI 200 +#define IDS_CHARSET_SYMBOL 201 +#define IDS_CHARSET_JIS 202 +#define IDS_CHARSET_HANGUL 203 +#define IDS_CHARSET_GB2312 204 +#define IDS_CHARSET_BIG5 205 +#define IDS_CHARSET_GREEK 206 +#define IDS_CHARSET_TURKISH 207 +#define IDS_CHARSET_HEBREW 208 +#define IDS_CHARSET_ARABIC 209 +#define IDS_CHARSET_BALTIC 210 +#define IDS_CHARSET_VIETNAMESE 211 +#define IDS_CHARSET_RUSSIAN 212 +#define IDS_CHARSET_EE 213 +#define IDS_CHARSET_THAI 214 +#define IDS_CHARSET_JOHAB 215 +#define IDS_CHARSET_MAC 216 +#define IDS_CHARSET_OEM 217 +#define IDS_CHARSET_VISCII 218 +#define IDS_CHARSET_TCVN 219 +#define IDS_CHARSET_KOI8 220 +#define IDS_CHARSET_ISO3 221 +#define IDS_CHARSET_ISO4 222 +#define IDS_CHARSET_ISO10 223 +#define IDS_CHARSET_CELTIC 224 + +/* Color names string IDs */ + +#define IDS_COLOR_BLACK 1040 +#define IDS_COLOR_MAROON 1041 +#define IDS_COLOR_GREEN 1042 +#define IDS_COLOR_OLIVE 1043 +#define IDS_COLOR_NAVY 1044 +#define IDS_COLOR_PURPLE 1045 +#define IDS_COLOR_TEAL 1046 +#define IDS_COLOR_GRAY 1047 +#define IDS_COLOR_SILVER 1048 +#define IDS_COLOR_RED 1049 +#define IDS_COLOR_LIME 1050 +#define IDS_COLOR_YELLOW 1051 +#define IDS_COLOR_BLUE 1052 +#define IDS_COLOR_FUCHSIA 1053 +#define IDS_COLOR_AQUA 1054 +#define IDS_COLOR_WHITE 1055 + +#define IDS_FONT_SIZE 1200 +#define IDS_SAVE_BUTTON 1201 +#define IDS_SAVE_IN 1202 +#define IDS_SAVE 1203 +#define IDS_SAVE_AS 1204 +#define IDS_OPEN_FILE 1205 + +#define IDS_FAKEDOCTEXT 1300 + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "shlobj.h" +#include "shellapi.h" + +/* ITEMIDLIST */ + +extern LPITEMIDLIST (WINAPI *COMDLG32_PIDL_ILClone) (LPCITEMIDLIST); +extern LPITEMIDLIST (WINAPI *COMDLG32_PIDL_ILCombine)(LPCITEMIDLIST,LPCITEMIDLIST); +extern LPITEMIDLIST (WINAPI *COMDLG32_PIDL_ILGetNext)(LPITEMIDLIST); +extern BOOL (WINAPI *COMDLG32_PIDL_ILRemoveLastID)(LPCITEMIDLIST); +extern BOOL (WINAPI *COMDLG32_PIDL_ILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST); + +/* SHELL */ +extern LPVOID (WINAPI *COMDLG32_SHAlloc)(DWORD); +extern DWORD (WINAPI *COMDLG32_SHFree)(LPVOID); +extern BOOL (WINAPI *COMDLG32_SHGetFolderPathA)(HWND,int,HANDLE,DWORD,LPSTR); +extern BOOL (WINAPI *COMDLG32_SHGetFolderPathW)(HWND,int,HANDLE,DWORD,LPWSTR); + +extern BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType); +extern BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType); + +/* + * Internal Functions + * Do NOT Export to other programs and dlls + */ + +BOOL CC_HookCallChk( LPCHOOSECOLORW lpcc ); +int CC_MouseCheckResultWindow( HWND hDlg, LPARAM lParam ); +LRESULT CC_WMLButtonDown( HWND hDlg, WPARAM wParam, LPARAM lParam ); +LRESULT CC_WMLButtonUp( HWND hDlg, WPARAM wParam, LPARAM lParam ); +LRESULT CC_WMCommand( HWND hDlg, WPARAM wParam, LPARAM lParam, WORD + notifyCode, HWND hwndCtl ); +LRESULT CC_WMMouseMove( HWND hDlg, LPARAM lParam ); +LRESULT CC_WMPaint( HWND hDlg, WPARAM wParam, LPARAM lParam ); +void CC_SwitchToFullSize( HWND hDlg, COLORREF result, LPRECT lprect ); +void CC_PaintSelectedColor( HWND hDlg, COLORREF cr ); +int CC_RGBtoHSL(char c, int r, int g, int b); +void CC_PaintCross( HWND hDlg, int x, int y); +void CC_PaintTriangle( HWND hDlg, int y); +int CC_CheckDigitsInEdit( HWND hwnd, int maxval ); +void CC_EditSetHSL( HWND hDlg, int h, int s, int l ); +int CC_HSLtoRGB(char c, int hue, int sat, int lum); +void CC_EditSetRGB( HWND hDlg, COLORREF cr ); +void CC_PaintUserColorArray( HWND hDlg, int rows, int cols, COLORREF* lpcr ); + +typedef struct +{ + HWND hWnd1; + HWND hWnd2; + LPCHOOSEFONTW lpcf32w; + int added; +} CFn_ENUMSTRUCT, *LPCFn_ENUMSTRUCT; + +INT AddFontFamily(const ENUMLOGFONTEXW *lpElfex, const NEWTEXTMETRICEXW *lpNTM, + UINT nFontType, LPCHOOSEFONTW lpcf, HWND hwnd, + LPCFn_ENUMSTRUCT e); +INT AddFontStyle(const ENUMLOGFONTEXW *lpElfex, const NEWTEXTMETRICEXW *metrics, + UINT nFontType, LPCHOOSEFONTW lpcf, HWND hcmb2, HWND hcmb3, + HWND hDlg, BOOL iswin16); +void _dump_cf_flags(DWORD cflags); + +LRESULT CFn_WMInitDialog(HWND hDlg, WPARAM wParam, LPARAM lParam, + LPCHOOSEFONTW lpcf); +LRESULT CFn_WMMeasureItem(HWND hDlg, WPARAM wParam, LPARAM lParam); +LRESULT CFn_WMDrawItem(HWND hDlg, WPARAM wParam, LPARAM lParam); +LRESULT CFn_WMCommand(HWND hDlg, WPARAM wParam, LPARAM lParam, + LPCHOOSEFONTW lpcf); +LRESULT CFn_WMPaint(HWND hDlg, WPARAM wParam, LPARAM lParam, + LPCHOOSEFONTW lpcf); + +#endif /* _WINE_DLL_CDLG_H */ diff --git a/reactos/lib/comdlg32/cdlg16.h b/reactos/lib/comdlg32/cdlg16.h index 9142d74f4e4..76b05f54643 100644 --- a/reactos/lib/comdlg32/cdlg16.h +++ b/reactos/lib/comdlg32/cdlg16.h @@ -1,155 +1,155 @@ -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _WINE_DLL_CDLG16_H -#define _WINE_DLL_CDLG16_H - -#define COM_NO_WINDOWS_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); -INT16 WINAPI GetFileTitle16(LPCSTR lpFile, LPSTR lpTitle, UINT16 cbBuf); -BOOL16 WINAPI GetOpenFileName16(SEGPTR ofn); -BOOL16 WINAPI GetSaveFileName16(SEGPTR ofn); -BOOL16 WINAPI PrintDlg16( LPPRINTDLG16 print); -HWND16 WINAPI ReplaceText16( SEGPTR find); -BOOL16 WINAPI ChooseFont16(LPCHOOSEFONT16); - -#include "poppack.h" - -#endif /* _WINE_DLL_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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _WINE_DLL_CDLG16_H +#define _WINE_DLL_CDLG16_H + +#define COM_NO_WINDOWS_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); +INT16 WINAPI GetFileTitle16(LPCSTR lpFile, LPSTR lpTitle, UINT16 cbBuf); +BOOL16 WINAPI GetOpenFileName16(SEGPTR ofn); +BOOL16 WINAPI GetSaveFileName16(SEGPTR ofn); +BOOL16 WINAPI PrintDlg16( LPPRINTDLG16 print); +HWND16 WINAPI ReplaceText16( SEGPTR find); +BOOL16 WINAPI ChooseFont16(LPCHOOSEFONT16); + +#include "poppack.h" + +#endif /* _WINE_DLL_CDLG16_H */ diff --git a/reactos/lib/comdlg32/cdlg32.c b/reactos/lib/comdlg32/cdlg32.c index d351dbd9947..f52c6f6965a 100644 --- a/reactos/lib/comdlg32/cdlg32.c +++ b/reactos/lib/comdlg32/cdlg32.c @@ -1,182 +1,182 @@ -/* - * Common Dialog Boxes interface (32 bit) - * Find/Replace - * - * Copyright 1999 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "commdlg.h" -#include "cderr.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(commdlg); - -#include "cdlg.h" - - -HINSTANCE COMDLG32_hInstance = 0; - -static DWORD COMDLG32_TlsIndex = TLS_OUT_OF_INDEXES; - -HINSTANCE SHELL32_hInstance = 0; -HINSTANCE SHFOLDER_hInstance = 0; - -/* ITEMIDLIST */ -LPITEMIDLIST (WINAPI *COMDLG32_PIDL_ILClone) (LPCITEMIDLIST); -LPITEMIDLIST (WINAPI *COMDLG32_PIDL_ILCombine)(LPCITEMIDLIST,LPCITEMIDLIST); -LPITEMIDLIST (WINAPI *COMDLG32_PIDL_ILGetNext)(LPITEMIDLIST); -BOOL (WINAPI *COMDLG32_PIDL_ILRemoveLastID)(LPCITEMIDLIST); -BOOL (WINAPI *COMDLG32_PIDL_ILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST); - -/* SHELL */ -LPVOID (WINAPI *COMDLG32_SHAlloc)(DWORD); -DWORD (WINAPI *COMDLG32_SHFree)(LPVOID); -BOOL (WINAPI *COMDLG32_SHGetFolderPathA)(HWND,int,HANDLE,DWORD,LPSTR); -BOOL (WINAPI *COMDLG32_SHGetFolderPathW)(HWND,int,HANDLE,DWORD,LPWSTR); - -/*********************************************************************** - * DllMain (COMDLG32.init) - * - * Initialization code for the COMDLG32 DLL - * - * RETURNS: - * FALSE if sibling could not be loaded or instantiated twice, TRUE - * otherwise. - */ -static const char * GPA_string = "Failed to get entry point %s for hinst = 0x%08x\n"; -#define GPA(dest, hinst, name) \ - if(!(dest = (void*)GetProcAddress(hinst,name)))\ - { \ - ERR((LPSTR)GPA_string, debugstr_a(name), hinst); \ - return FALSE; \ - } - -BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD Reason, LPVOID Reserved) -{ - TRACE("(%p, %08lx, %p)\n", hInstance, Reason, Reserved); - - switch(Reason) - { - case DLL_PROCESS_ATTACH: - COMDLG32_hInstance = hInstance; - DisableThreadLibraryCalls(hInstance); - - SHELL32_hInstance = GetModuleHandleA("SHELL32.DLL"); - - if (!SHELL32_hInstance) - { - ERR("loading of shell32 failed\n"); - return FALSE; - } - - /* ITEMIDLIST */ - GPA(COMDLG32_PIDL_ILIsEqual, SHELL32_hInstance, (LPCSTR)21L); - GPA(COMDLG32_PIDL_ILCombine, SHELL32_hInstance, (LPCSTR)25L); - GPA(COMDLG32_PIDL_ILGetNext, SHELL32_hInstance, (LPCSTR)153L); - GPA(COMDLG32_PIDL_ILClone, SHELL32_hInstance, (LPCSTR)18L); - GPA(COMDLG32_PIDL_ILRemoveLastID, SHELL32_hInstance, (LPCSTR)17L); - - /* SHELL */ - - GPA(COMDLG32_SHAlloc, SHELL32_hInstance, (LPCSTR)196L); - GPA(COMDLG32_SHFree, SHELL32_hInstance, (LPCSTR)195L); - /* for the first versions of shell32 SHGetFolderPathA is in SHFOLDER.DLL */ - COMDLG32_SHGetFolderPathA = (void*)GetProcAddress(SHELL32_hInstance,"SHGetFolderPathA"); - if (!COMDLG32_SHGetFolderPathA) - { - SHFOLDER_hInstance = LoadLibraryA("SHFOLDER.DLL"); - GPA(COMDLG32_SHGetFolderPathA, SHFOLDER_hInstance,"SHGetFolderPathA"); - } - - /* for the first versions of shell32 SHGetFolderPathW is in SHFOLDER.DLL */ - COMDLG32_SHGetFolderPathW = (void*)GetProcAddress(SHELL32_hInstance,"SHGetFolderPathW"); - if (!COMDLG32_SHGetFolderPathW) - { - SHFOLDER_hInstance = LoadLibraryA("SHFOLDER.DLL"); - GPA(COMDLG32_SHGetFolderPathW, SHFOLDER_hInstance,"SHGetFolderPathW"); - } - - break; - - case DLL_PROCESS_DETACH: - if (COMDLG32_TlsIndex != TLS_OUT_OF_INDEXES) TlsFree(COMDLG32_TlsIndex); - if(SHFOLDER_hInstance) FreeLibrary(SHFOLDER_hInstance); - break; - } - return TRUE; -} -#undef GPA - -/*********************************************************************** - * COMDLG32_AllocMem (internal) - * Get memory for internal datastructure plus stringspace etc. - * RETURNS - * Success: Pointer to a heap block - * Failure: null - */ -LPVOID COMDLG32_AllocMem( - int size /* [in] Block size to allocate */ -) { - LPVOID ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); - if(!ptr) - { - COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE); - return NULL; - } - return ptr; -} - - -/*********************************************************************** - * COMDLG32_SetCommDlgExtendedError (internal) - * - * Used to set the thread's local error value if a comdlg32 function fails. - */ -void COMDLG32_SetCommDlgExtendedError(DWORD err) -{ - TRACE("(%08lx)\n", err); - if (COMDLG32_TlsIndex == TLS_OUT_OF_INDEXES) - COMDLG32_TlsIndex = TlsAlloc(); - if (COMDLG32_TlsIndex != TLS_OUT_OF_INDEXES) - TlsSetValue(COMDLG32_TlsIndex, (void *)err); - else - FIXME("No Tls Space\n"); -} - - -/*********************************************************************** - * CommDlgExtendedError (COMMDLG.26) - * CommDlgExtendedError (COMDLG32.@) - * - * Get the thread's local error value if a comdlg32 function fails. - * RETURNS - * Current error value which might not be valid - * if a previous call succeeded. - */ -DWORD WINAPI CommDlgExtendedError(void) -{ - if (COMDLG32_TlsIndex != TLS_OUT_OF_INDEXES) - return (DWORD)TlsGetValue(COMDLG32_TlsIndex); - else - return 0; /* we never set an error, so there isn't one */ -} +/* + * Common Dialog Boxes interface (32 bit) + * Find/Replace + * + * Copyright 1999 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "commdlg.h" +#include "cderr.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(commdlg); + +#include "cdlg.h" + + +HINSTANCE COMDLG32_hInstance = 0; + +static DWORD COMDLG32_TlsIndex = TLS_OUT_OF_INDEXES; + +HINSTANCE SHELL32_hInstance = 0; +HINSTANCE SHFOLDER_hInstance = 0; + +/* ITEMIDLIST */ +LPITEMIDLIST (WINAPI *COMDLG32_PIDL_ILClone) (LPCITEMIDLIST); +LPITEMIDLIST (WINAPI *COMDLG32_PIDL_ILCombine)(LPCITEMIDLIST,LPCITEMIDLIST); +LPITEMIDLIST (WINAPI *COMDLG32_PIDL_ILGetNext)(LPITEMIDLIST); +BOOL (WINAPI *COMDLG32_PIDL_ILRemoveLastID)(LPCITEMIDLIST); +BOOL (WINAPI *COMDLG32_PIDL_ILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST); + +/* SHELL */ +LPVOID (WINAPI *COMDLG32_SHAlloc)(DWORD); +DWORD (WINAPI *COMDLG32_SHFree)(LPVOID); +BOOL (WINAPI *COMDLG32_SHGetFolderPathA)(HWND,int,HANDLE,DWORD,LPSTR); +BOOL (WINAPI *COMDLG32_SHGetFolderPathW)(HWND,int,HANDLE,DWORD,LPWSTR); + +/*********************************************************************** + * DllMain (COMDLG32.init) + * + * Initialization code for the COMDLG32 DLL + * + * RETURNS: + * FALSE if sibling could not be loaded or instantiated twice, TRUE + * otherwise. + */ +static const char * GPA_string = "Failed to get entry point %s for hinst = 0x%08x\n"; +#define GPA(dest, hinst, name) \ + if(!(dest = (void*)GetProcAddress(hinst,name)))\ + { \ + ERR((LPSTR)GPA_string, debugstr_a(name), hinst); \ + return FALSE; \ + } + +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD Reason, LPVOID Reserved) +{ + TRACE("(%p, %08lx, %p)\n", hInstance, Reason, Reserved); + + switch(Reason) + { + case DLL_PROCESS_ATTACH: + COMDLG32_hInstance = hInstance; + DisableThreadLibraryCalls(hInstance); + + SHELL32_hInstance = GetModuleHandleA("SHELL32.DLL"); + + if (!SHELL32_hInstance) + { + ERR("loading of shell32 failed\n"); + return FALSE; + } + + /* ITEMIDLIST */ + GPA(COMDLG32_PIDL_ILIsEqual, SHELL32_hInstance, (LPCSTR)21L); + GPA(COMDLG32_PIDL_ILCombine, SHELL32_hInstance, (LPCSTR)25L); + GPA(COMDLG32_PIDL_ILGetNext, SHELL32_hInstance, (LPCSTR)153L); + GPA(COMDLG32_PIDL_ILClone, SHELL32_hInstance, (LPCSTR)18L); + GPA(COMDLG32_PIDL_ILRemoveLastID, SHELL32_hInstance, (LPCSTR)17L); + + /* SHELL */ + + GPA(COMDLG32_SHAlloc, SHELL32_hInstance, (LPCSTR)196L); + GPA(COMDLG32_SHFree, SHELL32_hInstance, (LPCSTR)195L); + /* for the first versions of shell32 SHGetFolderPathA is in SHFOLDER.DLL */ + COMDLG32_SHGetFolderPathA = (void*)GetProcAddress(SHELL32_hInstance,"SHGetFolderPathA"); + if (!COMDLG32_SHGetFolderPathA) + { + SHFOLDER_hInstance = LoadLibraryA("SHFOLDER.DLL"); + GPA(COMDLG32_SHGetFolderPathA, SHFOLDER_hInstance,"SHGetFolderPathA"); + } + + /* for the first versions of shell32 SHGetFolderPathW is in SHFOLDER.DLL */ + COMDLG32_SHGetFolderPathW = (void*)GetProcAddress(SHELL32_hInstance,"SHGetFolderPathW"); + if (!COMDLG32_SHGetFolderPathW) + { + SHFOLDER_hInstance = LoadLibraryA("SHFOLDER.DLL"); + GPA(COMDLG32_SHGetFolderPathW, SHFOLDER_hInstance,"SHGetFolderPathW"); + } + + break; + + case DLL_PROCESS_DETACH: + if (COMDLG32_TlsIndex != TLS_OUT_OF_INDEXES) TlsFree(COMDLG32_TlsIndex); + if(SHFOLDER_hInstance) FreeLibrary(SHFOLDER_hInstance); + break; + } + return TRUE; +} +#undef GPA + +/*********************************************************************** + * COMDLG32_AllocMem (internal) + * Get memory for internal datastructure plus stringspace etc. + * RETURNS + * Success: Pointer to a heap block + * Failure: null + */ +LPVOID COMDLG32_AllocMem( + int size /* [in] Block size to allocate */ +) { + LPVOID ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); + if(!ptr) + { + COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE); + return NULL; + } + return ptr; +} + + +/*********************************************************************** + * COMDLG32_SetCommDlgExtendedError (internal) + * + * Used to set the thread's local error value if a comdlg32 function fails. + */ +void COMDLG32_SetCommDlgExtendedError(DWORD err) +{ + TRACE("(%08lx)\n", err); + if (COMDLG32_TlsIndex == TLS_OUT_OF_INDEXES) + COMDLG32_TlsIndex = TlsAlloc(); + if (COMDLG32_TlsIndex != TLS_OUT_OF_INDEXES) + TlsSetValue(COMDLG32_TlsIndex, (void *)err); + else + FIXME("No Tls Space\n"); +} + + +/*********************************************************************** + * CommDlgExtendedError (COMMDLG.26) + * CommDlgExtendedError (COMDLG32.@) + * + * Get the thread's local error value if a comdlg32 function fails. + * RETURNS + * Current error value which might not be valid + * if a previous call succeeded. + */ +DWORD WINAPI CommDlgExtendedError(void) +{ + if (COMDLG32_TlsIndex != TLS_OUT_OF_INDEXES) + return (DWORD)TlsGetValue(COMDLG32_TlsIndex); + else + return 0; /* we never set an error, so there isn't one */ +} diff --git a/reactos/lib/comdlg32/colordlg.c b/reactos/lib/comdlg32/colordlg.c index 096e1bb9c08..9a2dfced031 100644 --- a/reactos/lib/comdlg32/colordlg.c +++ b/reactos/lib/comdlg32/colordlg.c @@ -1,1343 +1,1343 @@ -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "dlgs.h" -#include "wine/debug.h" -#include "cderr.h" -#include "cdlg.h" - -WINE_DEFAULT_DEBUG_CHANNEL(commdlg); - -static INT_PTR CALLBACK ColorDlgProc( HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam ); - -#define CONV_LPARAMTOPOINT(lp,p) do { (p)->x = (short)LOWORD(lp); (p)->y = (short)HIWORD(lp); } while(0) - -static const COLORREF predefcolors[6][8]= -{ - { 0x008080FFL, 0x0080FFFFL, 0x0080FF80L, 0x0080FF00L, - 0x00FFFF80L, 0x00FF8000L, 0x00C080FFL, 0x00FF80FFL }, - { 0x000000FFL, 0x0000FFFFL, 0x0000FF80L, 0x0040FF00L, - 0x00FFFF00L, 0x00C08000L, 0x00C08080L, 0x00FF00FFL }, - - { 0x00404080L, 0x004080FFL, 0x0000FF00L, 0x00808000L, - 0x00804000L, 0x00FF8080L, 0x00400080L, 0x008000FFL }, - { 0x00000080L, 0x000080FFL, 0x00008000L, 0x00408000L, - 0x00FF0000L, 0x00A00000L, 0x00800080L, 0x00FF0080L }, - - { 0x00000040L, 0x00004080L, 0x00004000L, 0x00404000L, - 0x00800000L, 0x00400000L, 0x00400040L, 0x00800040L }, - { 0x00000000L, 0x00008080L, 0x00408080L, 0x00808080L, - 0x00808040L, 0x00C0C0C0L, 0x00400040L, 0x00FFFFFFL }, -}; - -/* Chose Color PRIVATE Structure: - * - * This structure is duplicated in the 16 bit code with - * an extra member - */ - -typedef struct CCPRIVATE -{ - LPCHOOSECOLORW lpcc; /* points to public known data structure */ - int nextuserdef; /* next free place in user defined color array */ - HDC hdcMem; /* color graph used for BitBlt() */ - HBITMAP hbmMem; /* color graph bitmap */ - RECT fullsize; /* original dialog window size */ - UINT msetrgb; /* # of SETRGBSTRING message (today not used) */ - RECT old3angle; /* last position of l-marker */ - RECT oldcross; /* last position of color/satuation marker */ - BOOL updating; /* to prevent recursive WM_COMMAND/EN_UPDATE processing */ - int h; - int s; - int l; /* for temporary storing of hue,sat,lum */ - int capturedGraph; /* control mouse captured */ - RECT focusRect; /* rectangle last focused item */ - HWND hwndFocus; /* handle last focused item */ -} *LCCPRIV; - -/*********************************************************************** - * CC_HSLtoRGB [internal] - */ -int CC_HSLtoRGB(char c, int hue, int sat, int lum) -{ - int res = 0, maxrgb; - - /* hue */ - switch(c) - { - case 'R': if (hue > 80) hue -= 80; else hue += 160; break; - case 'G': if (hue > 160) hue -= 160; else hue += 80; break; - case 'B': break; - } - - /* l below 120 */ - maxrgb = (256 * min(120,lum)) / 120; /* 0 .. 256 */ - if (hue < 80) - res = 0; - else - if (hue < 120) - { - res = (hue - 80) * maxrgb; /* 0...10240 */ - res /= 40; /* 0...256 */ - } - else - if (hue < 200) - res = maxrgb; - else - { - res= (240 - hue) * maxrgb; - res /= 40; - } - res = res - maxrgb / 2; /* -128...128 */ - - /* saturation */ - res = maxrgb / 2 + (sat * res) / 240; /* 0..256 */ - - /* lum above 120 */ - if (lum > 120 && res < 256) - res += ((lum - 120) * (256 - res)) / 120; - - return min(res, 255); -} - -/*********************************************************************** - * CC_RGBtoHSL [internal] - */ -int CC_RGBtoHSL(char c, int r, int g, int b) -{ - WORD maxi, mini, mmsum, mmdif, result = 0; - int iresult = 0; - - maxi = max(r, b); - maxi = max(maxi, g); - mini = min(r, b); - mini = min(mini, g); - - mmsum = maxi + mini; - mmdif = maxi - mini; - - switch(c) - { - /* lum */ - case 'L': mmsum *= 120; /* 0...61200=(255+255)*120 */ - result = mmsum / 255; /* 0...240 */ - break; - /* saturation */ - case 'S': if (!mmsum) - result = 0; - else - if (!mini || maxi == 255) - result = 240; - else - { - result = mmdif * 240; /* 0...61200=255*240 */ - result /= (mmsum > 255 ? mmsum = 510 - mmsum : mmsum); /* 0..255 */ - } - break; - /* hue */ - case 'H': if (!mmdif) - result = 160; - else - { - if (maxi == r) - { - iresult = 40 * (g - b); /* -10200 ... 10200 */ - iresult /= (int) mmdif; /* -40 .. 40 */ - if (iresult < 0) - iresult += 240; /* 0..40 and 200..240 */ - } - else - if (maxi == g) - { - iresult = 40 * (b - r); - iresult /= (int) mmdif; - iresult += 80; /* 40 .. 120 */ - } - else - if (maxi == b) - { - iresult = 40 * (r - g); - iresult /= (int) mmdif; - iresult += 160; /* 120 .. 200 */ - } - result = iresult; - } - break; - } - return result; /* is this integer arithmetic precise enough ? */ -} - - -/*********************************************************************** - * CC_DrawCurrentFocusRect [internal] - */ -void CC_DrawCurrentFocusRect( LCCPRIV lpp ) -{ - if (lpp->hwndFocus) - { - HDC hdc = GetDC(lpp->hwndFocus); - DrawFocusRect(hdc, &lpp->focusRect); - ReleaseDC(lpp->hwndFocus, hdc); - } -} - -/*********************************************************************** - * CC_DrawFocusRect [internal] - */ -void CC_DrawFocusRect( LCCPRIV lpp, HWND hwnd, int x, int y, int rows, int cols) -{ - RECT rect; - int dx, dy; - HDC hdc; - - CC_DrawCurrentFocusRect(lpp); /* remove current focus rect */ - /* calculate new rect */ - GetClientRect(hwnd, &rect); - dx = (rect.right - rect.left) / cols; - dy = (rect.bottom - rect.top) / rows; - rect.left += (x * dx) - 2; - rect.top += (y * dy) - 2; - rect.right = rect.left + dx; - rect.bottom = rect.top + dy; - /* draw it */ - hdc = GetDC(hwnd); - DrawFocusRect(hdc, &rect); - CopyRect(&lpp->focusRect, &rect); - lpp->hwndFocus = hwnd; - ReleaseDC(hwnd, hdc); -} - -#define DISTANCE 4 - -/*********************************************************************** - * CC_MouseCheckPredefColorArray [internal] - * returns 1 if one of the predefined colors is clicked - */ -static int CC_MouseCheckPredefColorArray( LCCPRIV lpp, HWND hDlg, int dlgitem, int rows, int cols, - LPARAM lParam ) -{ - HWND hwnd; - POINT point; - RECT rect; - int dx, dy, x, y; - - CONV_LPARAMTOPOINT(lParam, &point); - ClientToScreen(hDlg, &point); - hwnd = GetDlgItem(hDlg, dlgitem); - GetWindowRect(hwnd, &rect); - if (PtInRect(&rect, point)) - { - dx = (rect.right - rect.left) / cols; - dy = (rect.bottom - rect.top) / rows; - ScreenToClient(hwnd, &point); - - if (point.x % dx < ( dx - DISTANCE) && point.y % dy < ( dy - DISTANCE)) - { - x = point.x / dx; - y = point.y / dy; - lpp->lpcc->rgbResult = predefcolors[y][x]; - CC_DrawFocusRect(lpp, hwnd, x, y, rows, cols); - return 1; - } - } - return 0; -} - -/*********************************************************************** - * CC_MouseCheckUserColorArray [internal] - * return 1 if the user clicked a color - */ -static int CC_MouseCheckUserColorArray( LCCPRIV lpp, HWND hDlg, int dlgitem, int rows, int cols, - LPARAM lParam ) -{ - HWND hwnd; - POINT point; - RECT rect; - int dx, dy, x, y; - COLORREF *crarr = lpp->lpcc->lpCustColors; - - CONV_LPARAMTOPOINT(lParam, &point); - ClientToScreen(hDlg, &point); - hwnd = GetDlgItem(hDlg, dlgitem); - GetWindowRect(hwnd, &rect); - if (PtInRect(&rect, point)) - { - dx = (rect.right - rect.left) / cols; - dy = (rect.bottom - rect.top) / rows; - ScreenToClient(hwnd, &point); - - if (point.x % dx < (dx - DISTANCE) && point.y % dy < (dy - DISTANCE)) - { - x = point.x / dx; - y = point.y / dy; - lpp->lpcc->rgbResult = crarr[x + (cols * y) ]; - CC_DrawFocusRect(lpp, hwnd, x, y, rows, cols); - return 1; - } - } - return 0; -} - -#define MAXVERT 240 -#define MAXHORI 239 - -/* 240 ^...... ^^ 240 - | . || - SAT | . || LUM - | . || - +-----> 239 ---- - HUE -*/ -/*********************************************************************** - * CC_MouseCheckColorGraph [internal] - */ -static int CC_MouseCheckColorGraph( HWND hDlg, int dlgitem, int *hori, int *vert, LPARAM lParam ) -{ - HWND hwnd; - POINT point; - RECT rect; - long x,y; - - CONV_LPARAMTOPOINT(lParam, &point); - ClientToScreen(hDlg, &point); - hwnd = GetDlgItem( hDlg, dlgitem ); - GetWindowRect(hwnd, &rect); - if (PtInRect(&rect, point)) - { - GetClientRect(hwnd, &rect); - ScreenToClient(hwnd, &point); - - x = (long) point.x * MAXHORI; - x /= rect.right; - y = (long) (rect.bottom - point.y) * MAXVERT; - y /= rect.bottom; - - if (hori) - *hori = x; - if (vert) - *vert = y; - return 1; - } - else - return 0; -} -/*********************************************************************** - * CC_MouseCheckResultWindow [internal] - * test if double click one of the result colors - */ -int CC_MouseCheckResultWindow( HWND hDlg, LPARAM lParam ) -{ - HWND hwnd; - POINT point; - RECT rect; - - CONV_LPARAMTOPOINT(lParam, &point); - ClientToScreen(hDlg, &point); - hwnd = GetDlgItem(hDlg, 0x2c5); - GetWindowRect(hwnd, &rect); - if (PtInRect(&rect, point)) - { - PostMessageA(hDlg, WM_COMMAND, 0x2c9, 0); - return 1; - } - return 0; -} - -/*********************************************************************** - * CC_CheckDigitsInEdit [internal] - */ -int CC_CheckDigitsInEdit( HWND hwnd, int maxval ) -{ - int i, k, m, result, value; - long editpos; - char buffer[30]; - - GetWindowTextA(hwnd, buffer, sizeof(buffer)); - m = strlen(buffer); - result = 0; - - for (i = 0 ; i < m ; i++) - if (buffer[i] < '0' || buffer[i] > '9') - { - for (k = i + 1; k <= m; k++) /* delete bad character */ - { - buffer[i] = buffer[k]; - m--; - } - buffer[m] = 0; - result = 1; - } - - value = atoi(buffer); - if (value > maxval) /* build a new string */ - { - sprintf(buffer, "%d", maxval); - result = 2; - } - if (result) - { - editpos = SendMessageA(hwnd, EM_GETSEL, 0, 0); - SetWindowTextA(hwnd, buffer ); - SendMessageA(hwnd, EM_SETSEL, 0, editpos); - } - return value; -} - - - -/*********************************************************************** - * CC_PaintSelectedColor [internal] - */ -void CC_PaintSelectedColor( HWND hDlg, COLORREF cr ) -{ - RECT rect; - HDC hdc; - HBRUSH hBrush; - HWND hwnd = GetDlgItem(hDlg, 0x2c5); - if (IsWindowVisible( GetDlgItem(hDlg, 0x2c6) )) /* if full size */ - { - hdc = GetDC(hwnd); - GetClientRect(hwnd, &rect) ; - hBrush = CreateSolidBrush(cr); - if (hBrush) - { - hBrush = SelectObject(hdc, hBrush) ; - Rectangle(hdc, rect.left, rect.top, rect.right/2, rect.bottom); - DeleteObject ( SelectObject(hdc, hBrush) ) ; - hBrush = CreateSolidBrush( GetNearestColor(hdc, cr) ); - if (hBrush) - { - hBrush = SelectObject(hdc, hBrush) ; - Rectangle(hdc, rect.right/2-1, rect.top, rect.right, rect.bottom); - DeleteObject(SelectObject(hdc, hBrush)) ; - } - } - ReleaseDC(hwnd, hdc); - } -} - -/*********************************************************************** - * CC_PaintTriangle [internal] - */ -void CC_PaintTriangle( HWND hDlg, int y) -{ - HDC hDC; - long temp; - int w = LOWORD(GetDialogBaseUnits()); - POINT points[3]; - int height; - int oben; - RECT rect; - HWND hwnd = GetDlgItem(hDlg, 0x2be); - LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW( hDlg, DWLP_USER); - - if (IsWindowVisible( GetDlgItem(hDlg, 0x2c6))) /* if full size */ - { - GetClientRect(hwnd, &rect); - height = rect.bottom; - hDC = GetDC(hDlg); - points[0].y = rect.top; - points[0].x = rect.right; /* | /| */ - ClientToScreen(hwnd, points); /* | / | */ - ScreenToClient(hDlg, points); /* |< | */ - oben = points[0].y; /* | \ | */ - /* | \| */ - temp = (long)height * (long)y; - points[0].y = oben + height - temp / (long)MAXVERT; - points[1].y = points[0].y + w; - points[2].y = points[0].y - w; - points[2].x = points[1].x = points[0].x + w; - - FillRect(hDC, &lpp->old3angle, (HBRUSH)GetClassLongPtrW( hwnd, GCLP_HBRBACKGROUND)); - lpp->old3angle.left = points[0].x; - lpp->old3angle.right = points[1].x + 1; - lpp->old3angle.top = points[2].y - 1; - lpp->old3angle.bottom= points[1].y + 1; - Polygon(hDC, points, 3); - ReleaseDC(hDlg, hDC); - } -} - - -/*********************************************************************** - * CC_PaintCross [internal] - */ -void CC_PaintCross( HWND hDlg, int x, int y) -{ - HDC hDC; - int w = GetDialogBaseUnits(); - HWND hwnd = GetDlgItem(hDlg, 0x2c6); - LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW( hDlg, DWLP_USER ); - RECT rect; - POINT point, p; - HPEN hPen; - - if (IsWindowVisible( GetDlgItem(hDlg, 0x2c6) )) /* if full size */ - { - GetClientRect(hwnd, &rect); - hDC = GetDC(hwnd); - SelectClipRgn( hDC, CreateRectRgnIndirect(&rect)); - hPen = CreatePen(PS_SOLID, 2, 0xffffff); /* -white- color */ - hPen = SelectObject(hDC, hPen); - point.x = ((long)rect.right * (long)x) / (long)MAXHORI; - point.y = rect.bottom - ((long)rect.bottom * (long)y) / (long)MAXVERT; - if ( lpp->oldcross.left != lpp->oldcross.right ) - BitBlt(hDC, lpp->oldcross.left, lpp->oldcross.top, - lpp->oldcross.right - lpp->oldcross.left, - lpp->oldcross.bottom - lpp->oldcross.top, - lpp->hdcMem, lpp->oldcross.left, lpp->oldcross.top, SRCCOPY); - lpp->oldcross.left = point.x - w - 1; - lpp->oldcross.right = point.x + w + 1; - lpp->oldcross.top = point.y - w - 1; - lpp->oldcross.bottom = point.y + w + 1; - - MoveToEx(hDC, point.x - w, point.y, &p); - LineTo(hDC, point.x + w, point.y); - MoveToEx(hDC, point.x, point.y - w, &p); - LineTo(hDC, point.x, point.y + w); - DeleteObject( SelectObject(hDC, hPen)) ; - ReleaseDC(hwnd, hDC); - } -} - - -#define XSTEPS 48 -#define YSTEPS 24 - - -/*********************************************************************** - * CC_PrepareColorGraph [internal] - */ -static void CC_PrepareColorGraph( HWND hDlg ) -{ - int sdif, hdif, xdif, ydif, r, g, b, hue, sat; - HWND hwnd = GetDlgItem(hDlg, 0x2c6); - LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); - HBRUSH hbrush; - HDC hdc ; - RECT rect, client; - HCURSOR hcursor = SetCursor( LoadCursorW(0, (LPCWSTR)IDC_WAIT) ); - - GetClientRect(hwnd, &client); - hdc = GetDC(hwnd); - lpp->hdcMem = CreateCompatibleDC(hdc); - lpp->hbmMem = CreateCompatibleBitmap(hdc, client.right, client.bottom); - SelectObject(lpp->hdcMem, lpp->hbmMem); - - xdif = client.right / XSTEPS; - ydif = client.bottom / YSTEPS+1; - hdif = 239 / XSTEPS; - sdif = 240 / YSTEPS; - for (rect.left = hue = 0; hue < 239 + hdif; hue += hdif) - { - rect.right = rect.left + xdif; - rect.bottom = client.bottom; - for(sat = 0; sat < 240 + sdif; sat += sdif) - { - rect.top = rect.bottom - ydif; - r = CC_HSLtoRGB('R', hue, sat, 120); - g = CC_HSLtoRGB('G', hue, sat, 120); - b = CC_HSLtoRGB('B', hue, sat, 120); - hbrush = CreateSolidBrush( RGB(r, g, b)); - FillRect(lpp->hdcMem, &rect, hbrush); - DeleteObject(hbrush); - rect.bottom = rect.top; - } - rect.left = rect.right; - } - ReleaseDC(hwnd, hdc); - SetCursor(hcursor); -} - -/*********************************************************************** - * CC_PaintColorGraph [internal] - */ -static void CC_PaintColorGraph( HWND hDlg ) -{ - HWND hwnd = GetDlgItem( hDlg, 0x2c6 ); - LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); - HDC hDC; - RECT rect; - if (IsWindowVisible(hwnd)) /* if full size */ - { - if (!lpp->hdcMem) - CC_PrepareColorGraph(hDlg); /* should not be necessary */ - - hDC = GetDC(hwnd); - GetClientRect(hwnd, &rect); - if (lpp->hdcMem) - BitBlt(hDC, 0, 0, rect.right, rect.bottom, lpp->hdcMem, 0, 0, SRCCOPY); - else - WARN("choose color: hdcMem is not defined\n"); - ReleaseDC(hwnd, hDC); - } -} - -/*********************************************************************** - * CC_PaintLumBar [internal] - */ -static void CC_PaintLumBar( HWND hDlg, int hue, int sat ) -{ - HWND hwnd = GetDlgItem(hDlg, 0x2be); - RECT rect, client; - int lum, ldif, ydif, r, g, b; - HBRUSH hbrush; - HDC hDC; - - if (IsWindowVisible(hwnd)) - { - hDC = GetDC(hwnd); - GetClientRect(hwnd, &client); - rect = client; - - ldif = 240 / YSTEPS; - ydif = client.bottom / YSTEPS+1; - for (lum = 0; lum < 240 + ldif; lum += ldif) - { - rect.top = max(0, rect.bottom - ydif); - r = CC_HSLtoRGB('R', hue, sat, lum); - g = CC_HSLtoRGB('G', hue, sat, lum); - b = CC_HSLtoRGB('B', hue, sat, lum); - hbrush = CreateSolidBrush( RGB(r, g, b) ); - FillRect(hDC, &rect, hbrush); - DeleteObject(hbrush); - rect.bottom = rect.top; - } - GetClientRect(hwnd, &rect); - FrameRect(hDC, &rect, GetStockObject(BLACK_BRUSH) ); - ReleaseDC(hwnd, hDC); - } -} - -/*********************************************************************** - * CC_EditSetRGB [internal] - */ -void CC_EditSetRGB( HWND hDlg, COLORREF cr ) -{ - char buffer[10]; - LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); - int r = GetRValue(cr); - int g = GetGValue(cr); - int b = GetBValue(cr); - if (IsWindowVisible( GetDlgItem(hDlg, 0x2c6) )) /* if full size */ - { - lpp->updating = TRUE; - sprintf(buffer, "%d", r); - SetWindowTextA( GetDlgItem(hDlg, 0x2c2), buffer); - sprintf(buffer, "%d", g); - SetWindowTextA( GetDlgItem(hDlg, 0x2c3), buffer); - sprintf( buffer, "%d", b ); - SetWindowTextA( GetDlgItem(hDlg, 0x2c4),buffer); - lpp->updating = FALSE; - } -} - -/*********************************************************************** - * CC_EditSetHSL [internal] - */ -void CC_EditSetHSL( HWND hDlg, int h, int s, int l ) -{ - char buffer[10]; - LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); - lpp->updating = TRUE; - if (IsWindowVisible( GetDlgItem(hDlg, 0x2c6) )) /* if full size */ - { - lpp->updating = TRUE; - sprintf(buffer, "%d", h); - SetWindowTextA( GetDlgItem(hDlg, 0x2bf), buffer); - sprintf(buffer, "%d", s); - SetWindowTextA( GetDlgItem(hDlg, 0x2c0), buffer); - sprintf(buffer, "%d", l); - SetWindowTextA( GetDlgItem(hDlg, 0x2c1), buffer); - lpp->updating = FALSE; - } - CC_PaintLumBar(hDlg, h, s); -} - -/*********************************************************************** - * CC_SwitchToFullSize [internal] - */ -void CC_SwitchToFullSize( HWND hDlg, COLORREF result, LPRECT lprect ) -{ - int i; - LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); - - EnableWindow( GetDlgItem(hDlg, 0x2cf), FALSE); - CC_PrepareColorGraph(hDlg); - for (i = 0x2bf; i < 0x2c5; i++) - ShowWindow( GetDlgItem(hDlg, i), SW_SHOW); - for (i = 0x2d3; i < 0x2d9; i++) - ShowWindow( GetDlgItem(hDlg, i), SW_SHOW); - ShowWindow( GetDlgItem(hDlg, 0x2c9), SW_SHOW); - ShowWindow( GetDlgItem(hDlg, 0x2c8), SW_SHOW); - ShowWindow( GetDlgItem(hDlg, 1090), SW_SHOW); - - if (lprect) - SetWindowPos(hDlg, 0, 0, 0, lprect->right-lprect->left, - lprect->bottom-lprect->top, SWP_NOMOVE|SWP_NOZORDER); - - ShowWindow( GetDlgItem(hDlg, 0x2be), SW_SHOW); - ShowWindow( GetDlgItem(hDlg, 0x2c5), SW_SHOW); - - CC_EditSetRGB(hDlg, result); - CC_EditSetHSL(hDlg, lpp->h, lpp->s, lpp->l); - ShowWindow( GetDlgItem( hDlg, 0x2c6), SW_SHOW); - UpdateWindow( GetDlgItem(hDlg, 0x2c6) ); -} - -/*********************************************************************** - * CC_PaintPredefColorArray [internal] - * Paints the default standard 48 colors - */ -static void CC_PaintPredefColorArray( HWND hDlg, int rows, int cols) -{ - HWND hwnd = GetDlgItem(hDlg, 0x2d0); - RECT rect; - HDC hdc; - HBRUSH hBrush; - int dx, dy, i, j, k; - LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); - - GetClientRect(hwnd, &rect); - dx = rect.right / cols; - dy = rect.bottom / rows; - k = rect.left; - - hdc = GetDC(hwnd); - GetClientRect(hwnd, &rect); - FillRect(hdc, &rect, (HBRUSH)GetClassLongPtrW(hwnd, GCLP_HBRBACKGROUND)); - for ( j = 0; j < rows; j++ ) - { - for ( i = 0; i < cols; i++ ) - { - hBrush = CreateSolidBrush(predefcolors[j][i]); - if (hBrush) - { - hBrush = SelectObject(hdc, hBrush); - Rectangle(hdc, rect.left, rect.top, - rect.left + dx - DISTANCE, rect.top + dy - DISTANCE); - rect.left = rect.left + dx; - DeleteObject(SelectObject(hdc, hBrush)) ; - } - } - rect.top = rect.top + dy; - rect.left = k; - } - ReleaseDC(hwnd, hdc); - if (lpp->hwndFocus == hwnd) - CC_DrawCurrentFocusRect(lpp); -} -/*********************************************************************** - * CC_PaintUserColorArray [internal] - * Paint the 16 user-selected colors - */ -void CC_PaintUserColorArray( HWND hDlg, int rows, int cols, COLORREF* lpcr ) -{ - HWND hwnd = GetDlgItem(hDlg, 0x2d1); - RECT rect; - HDC hdc; - HBRUSH hBrush; - int dx, dy, i, j, k; - LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); - - GetClientRect(hwnd, &rect); - - dx = rect.right / cols; - dy = rect.bottom / rows; - k = rect.left; - - hdc = GetDC(hwnd); - if (hdc) - { - FillRect(hdc, &rect, (HBRUSH)GetClassLongPtrW(hwnd, GCLP_HBRBACKGROUND) ); - for (j = 0; j < rows; j++) - { - for (i = 0; i < cols; i++) - { - hBrush = CreateSolidBrush(lpcr[i+j*cols]); - if (hBrush) - { - hBrush = SelectObject(hdc, hBrush) ; - Rectangle(hdc, rect.left, rect.top, - rect.left + dx - DISTANCE, rect.top + dy - DISTANCE); - rect.left = rect.left + dx; - DeleteObject( SelectObject(hdc, hBrush) ) ; - } - } - rect.top = rect.top + dy; - rect.left = k; - } - ReleaseDC(hwnd, hdc); - } - if (lpp->hwndFocus == hwnd) - CC_DrawCurrentFocusRect(lpp); -} - - - -/*********************************************************************** - * CC_HookCallChk [internal] - */ -BOOL CC_HookCallChk( LPCHOOSECOLORW lpcc ) -{ - if (lpcc) - if(lpcc->Flags & CC_ENABLEHOOK) - if (lpcc->lpfnHook) - return TRUE; - return FALSE; -} - -/*********************************************************************** - * CC_WMInitDialog [internal] - */ -LONG CC_WMInitDialog( HWND hDlg, WPARAM wParam, LPARAM lParam ) -{ - int i, res; - int r, g, b; - HWND hwnd; - RECT rect; - POINT point; - LCCPRIV lpp; - - TRACE("WM_INITDIALOG lParam=%08lX\n", lParam); - lpp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct CCPRIVATE) ); - - lpp->lpcc = (LPCHOOSECOLORW) lParam; - if (lpp->lpcc->lStructSize != sizeof(CHOOSECOLORW) ) - { - HeapFree(GetProcessHeap(), 0, lpp); - EndDialog (hDlg, 0) ; - return FALSE; - } - - SetWindowLongPtrW(hDlg, DWLP_USER, (LONG_PTR)lpp); - - if (!(lpp->lpcc->Flags & CC_SHOWHELP)) - ShowWindow( GetDlgItem(hDlg,0x40e), SW_HIDE); - lpp->msetrgb = RegisterWindowMessageA(SETRGBSTRINGA); - -#if 0 - cpos = MAKELONG(5,7); /* init */ - if (lpp->lpcc->Flags & CC_RGBINIT) - { - for (i = 0; i < 6; i++) - for (j = 0; j < 8; j++) - if (predefcolors[i][j] == lpp->lpcc->rgbResult) - { - cpos = MAKELONG(i,j); - goto found; - } - } - found: - /* FIXME: Draw_a_focus_rect & set_init_values */ -#endif - - GetWindowRect(hDlg, &lpp->fullsize); - if (lpp->lpcc->Flags & CC_FULLOPEN || lpp->lpcc->Flags & CC_PREVENTFULLOPEN) - { - hwnd = GetDlgItem(hDlg, 0x2cf); - EnableWindow(hwnd, FALSE); - } - if (!(lpp->lpcc->Flags & CC_FULLOPEN ) || lpp->lpcc->Flags & CC_PREVENTFULLOPEN) - { - rect = lpp->fullsize; - res = rect.bottom - rect.top; - hwnd = GetDlgItem(hDlg, 0x2c6); /* cut at left border */ - point.x = point.y = 0; - ClientToScreen(hwnd, &point); - ScreenToClient(hDlg,&point); - GetClientRect(hDlg, &rect); - point.x += GetSystemMetrics(SM_CXDLGFRAME); - SetWindowPos(hDlg, 0, 0, 0, point.x, res, SWP_NOMOVE|SWP_NOZORDER); - - for (i = 0x2bf; i < 0x2c5; i++) - ShowWindow( GetDlgItem(hDlg, i), SW_HIDE); - for (i = 0x2d3; i < 0x2d9; i++) - ShowWindow( GetDlgItem(hDlg, i), SW_HIDE); - ShowWindow( GetDlgItem(hDlg, 0x2c9), SW_HIDE); - ShowWindow( GetDlgItem(hDlg, 0x2c8), SW_HIDE); - ShowWindow( GetDlgItem(hDlg, 0x2c6), SW_HIDE); - ShowWindow( GetDlgItem(hDlg, 0x2c5), SW_HIDE); - ShowWindow( GetDlgItem(hDlg, 1090 ), SW_HIDE); - } - else - CC_SwitchToFullSize(hDlg, lpp->lpcc->rgbResult, NULL); - res = TRUE; - for (i = 0x2bf; i < 0x2c5; i++) - SendMessageA( GetDlgItem(hDlg, i), EM_LIMITTEXT, 3, 0); /* max 3 digits: xyz */ - if (CC_HookCallChk(lpp->lpcc)) - { - res = CallWindowProcA( (WNDPROC)lpp->lpcc->lpfnHook, hDlg, WM_INITDIALOG, wParam, lParam); - } - - /* Set the initial values of the color chooser dialog */ - r = GetRValue(lpp->lpcc->rgbResult); - g = GetGValue(lpp->lpcc->rgbResult); - b = GetBValue(lpp->lpcc->rgbResult); - - CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); - lpp->h = CC_RGBtoHSL('H', r, g, b); - lpp->s = CC_RGBtoHSL('S', r, g, b); - lpp->l = CC_RGBtoHSL('L', r, g, b); - - /* Doing it the long way because CC_EditSetRGB/HSL doesn't seem to work */ - SetDlgItemInt(hDlg, 703, lpp->h, TRUE); - SetDlgItemInt(hDlg, 704, lpp->s, TRUE); - SetDlgItemInt(hDlg, 705, lpp->l, TRUE); - SetDlgItemInt(hDlg, 706, r, TRUE); - SetDlgItemInt(hDlg, 707, g, TRUE); - SetDlgItemInt(hDlg, 708, b, TRUE); - - CC_PaintCross(hDlg, lpp->h, lpp->s); - CC_PaintTriangle(hDlg, lpp->l); - - return res; -} - - -/*********************************************************************** - * CC_WMCommand [internal] - */ -LRESULT CC_WMCommand( HWND hDlg, WPARAM wParam, LPARAM lParam, WORD notifyCode, HWND hwndCtl ) -{ - int r, g, b, i, xx; - UINT cokmsg; - HDC hdc; - COLORREF *cr; - LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); - TRACE("CC_WMCommand wParam=%x lParam=%lx\n", wParam, lParam); - switch (wParam) - { - case 0x2c2: /* edit notify RGB */ - case 0x2c3: - case 0x2c4: - if (notifyCode == EN_UPDATE && !lpp->updating) - { - i = CC_CheckDigitsInEdit(hwndCtl, 255); - r = GetRValue(lpp->lpcc->rgbResult); - g = GetGValue(lpp->lpcc->rgbResult); - b= GetBValue(lpp->lpcc->rgbResult); - xx = 0; - switch (wParam) - { - case 0x2c2: if ((xx = (i != r))) r = i; break; - case 0x2c3: if ((xx = (i != g))) g = i; break; - case 0x2c4: if ((xx = (i != b))) b = i; break; - } - if (xx) /* something has changed */ - { - lpp->lpcc->rgbResult = RGB(r, g, b); - CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); - lpp->h = CC_RGBtoHSL('H', r, g, b); - lpp->s = CC_RGBtoHSL('S', r, g, b); - lpp->l = CC_RGBtoHSL('L', r, g, b); - CC_EditSetHSL(hDlg, lpp->h, lpp->s, lpp->l); - CC_PaintCross(hDlg, lpp->h, lpp->s); - CC_PaintTriangle(hDlg, lpp->l); - } - } - break; - - case 0x2bf: /* edit notify HSL */ - case 0x2c0: - case 0x2c1: - if (notifyCode == EN_UPDATE && !lpp->updating) - { - i = CC_CheckDigitsInEdit(hwndCtl , wParam == 0x2bf ? 239:240); - xx = 0; - switch (wParam) - { - case 0x2bf: if ((xx = ( i != lpp->h))) lpp->h = i; break; - case 0x2c0: if ((xx = ( i != lpp->s))) lpp->s = i; break; - case 0x2c1: if ((xx = ( i != lpp->l))) lpp->l = i; break; - } - if (xx) /* something has changed */ - { - r = CC_HSLtoRGB('R', lpp->h, lpp->s, lpp->l); - g = CC_HSLtoRGB('G', lpp->h, lpp->s, lpp->l); - b = CC_HSLtoRGB('B', lpp->h, lpp->s, lpp->l); - lpp->lpcc->rgbResult = RGB(r, g, b); - CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); - CC_EditSetRGB(hDlg, lpp->lpcc->rgbResult); - CC_PaintCross(hDlg, lpp->h, lpp->s); - CC_PaintTriangle(hDlg, lpp->l); - } - } - break; - - case 0x2cf: - CC_SwitchToFullSize(hDlg, lpp->lpcc->rgbResult, &lpp->fullsize); - SetFocus( GetDlgItem(hDlg, 0x2bf)); - break; - - case 0x2c8: /* add colors ... column by column */ - cr = lpp->lpcc->lpCustColors; - cr[(lpp->nextuserdef % 2) * 8 + lpp->nextuserdef / 2] = lpp->lpcc->rgbResult; - if (++lpp->nextuserdef == 16) - lpp->nextuserdef = 0; - CC_PaintUserColorArray(hDlg, 2, 8, lpp->lpcc->lpCustColors); - break; - - case 0x2c9: /* resulting color */ - hdc = GetDC(hDlg); - lpp->lpcc->rgbResult = GetNearestColor(hdc, lpp->lpcc->rgbResult); - ReleaseDC(hDlg, hdc); - CC_EditSetRGB(hDlg, lpp->lpcc->rgbResult); - CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); - r = GetRValue(lpp->lpcc->rgbResult); - g = GetGValue(lpp->lpcc->rgbResult); - b = GetBValue(lpp->lpcc->rgbResult); - lpp->h = CC_RGBtoHSL('H', r, g, b); - lpp->s = CC_RGBtoHSL('S', r, g, b); - lpp->l = CC_RGBtoHSL('L', r, g, b); - CC_EditSetHSL(hDlg, lpp->h, lpp->s, lpp->l); - CC_PaintCross(hDlg, lpp->h, lpp->s); - CC_PaintTriangle(hDlg, lpp->l); - break; - - case 0x40e: /* Help! */ /* The Beatles, 1965 ;-) */ - i = RegisterWindowMessageA(HELPMSGSTRINGA); - if (lpp->lpcc->hwndOwner) - SendMessageA(lpp->lpcc->hwndOwner, i, 0, (LPARAM)lpp->lpcc); - if ( CC_HookCallChk(lpp->lpcc)) - CallWindowProcA( (WNDPROC) lpp->lpcc->lpfnHook, hDlg, - WM_COMMAND, psh15, (LPARAM)lpp->lpcc); - break; - - case IDOK : - cokmsg = RegisterWindowMessageA(COLOROKSTRINGA); - if (lpp->lpcc->hwndOwner) - if (SendMessageA(lpp->lpcc->hwndOwner, cokmsg, 0, (LPARAM)lpp->lpcc)) - break; /* do NOT close */ - EndDialog(hDlg, 1) ; - return TRUE ; - - case IDCANCEL : - EndDialog(hDlg, 0) ; - return TRUE ; - - } - return FALSE; -} - -/*********************************************************************** - * CC_WMPaint [internal] - */ -LRESULT CC_WMPaint( HWND hDlg, WPARAM wParam, LPARAM lParam ) -{ - PAINTSTRUCT ps; - LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); - - BeginPaint(hDlg, &ps); - /* we have to paint dialog children except text and buttons */ - CC_PaintPredefColorArray(hDlg, 6, 8); - CC_PaintUserColorArray(hDlg, 2, 8, lpp->lpcc->lpCustColors); - CC_PaintLumBar(hDlg, lpp->h, lpp->s); - CC_PaintCross(hDlg, lpp->h, lpp->s); - CC_PaintTriangle(hDlg, lpp->l); - CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); - CC_PaintColorGraph(hDlg); - EndPaint(hDlg, &ps); - - return TRUE; -} - -/*********************************************************************** - * CC_WMLButtonUp [internal] - */ -LRESULT CC_WMLButtonUp( HWND hDlg, WPARAM wParam, LPARAM lParam ) -{ - LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); - if (lpp->capturedGraph) - { - lpp->capturedGraph = 0; - ReleaseCapture(); - CC_PaintCross(hDlg, lpp->h, lpp->s); - return 1; - } - return 0; -} - -/*********************************************************************** - * CC_WMMouseMove [internal] - */ -LRESULT CC_WMMouseMove( HWND hDlg, LPARAM lParam ) -{ - LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); - int r, g, b; - - if (lpp->capturedGraph) - { - int *ptrh = NULL, *ptrs = &lpp->l; - if (lpp->capturedGraph == 0x2c6) - { - ptrh = &lpp->h; - ptrs = &lpp->s; - } - if (CC_MouseCheckColorGraph( hDlg, lpp->capturedGraph, ptrh, ptrs, lParam)) - { - r = CC_HSLtoRGB('R', lpp->h, lpp->s, lpp->l); - g = CC_HSLtoRGB('G', lpp->h, lpp->s, lpp->l); - b = CC_HSLtoRGB('B', lpp->h, lpp->s, lpp->l); - lpp->lpcc->rgbResult = RGB(r, g, b); - CC_EditSetRGB(hDlg, lpp->lpcc->rgbResult); - CC_EditSetHSL(hDlg,lpp->h, lpp->s, lpp->l); - CC_PaintCross(hDlg, lpp->h, lpp->s); - CC_PaintTriangle(hDlg, lpp->l); - CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); - } - else - { - ReleaseCapture(); - lpp->capturedGraph = 0; - } - return 1; - } - return 0; -} - -/*********************************************************************** - * CC_WMLButtonDown [internal] - */ -LRESULT CC_WMLButtonDown( HWND hDlg, WPARAM wParam, LPARAM lParam ) -{ - LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); - int r, g, b, i; - i = 0; - - if (CC_MouseCheckPredefColorArray(lpp, hDlg, 0x2d0, 6, 8, lParam)) - i = 1; - else - if (CC_MouseCheckUserColorArray(lpp, hDlg, 0x2d1, 2, 8, lParam)) - i = 1; - else - if (CC_MouseCheckColorGraph(hDlg, 0x2c6, &lpp->h, &lpp->s, lParam)) - { - i = 2; - lpp->capturedGraph = 0x2c6; - } - else - if (CC_MouseCheckColorGraph(hDlg, 0x2be, NULL, &lpp->l, lParam)) - { - i = 2; - lpp->capturedGraph = 0x2be; - } - if ( i == 2 ) - { - SetCapture(hDlg); - r = CC_HSLtoRGB('R', lpp->h, lpp->s, lpp->l); - g = CC_HSLtoRGB('G', lpp->h, lpp->s, lpp->l); - b = CC_HSLtoRGB('B', lpp->h, lpp->s, lpp->l); - lpp->lpcc->rgbResult = RGB(r, g, b); - } - if ( i == 1 ) - { - r = GetRValue(lpp->lpcc->rgbResult); - g = GetGValue(lpp->lpcc->rgbResult); - b = GetBValue(lpp->lpcc->rgbResult); - lpp->h = CC_RGBtoHSL('H', r, g, b); - lpp->s = CC_RGBtoHSL('S', r, g, b); - lpp->l = CC_RGBtoHSL('L', r, g, b); - } - if (i) - { - CC_EditSetRGB(hDlg, lpp->lpcc->rgbResult); - CC_EditSetHSL(hDlg,lpp->h, lpp->s, lpp->l); - CC_PaintCross(hDlg, lpp->h, lpp->s); - CC_PaintTriangle(hDlg, lpp->l); - CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); - return TRUE; - } - return FALSE; -} - -/*********************************************************************** - * ColorDlgProc32 [internal] - * - */ -static INT_PTR CALLBACK ColorDlgProc( HWND hDlg, UINT message, - WPARAM wParam, LPARAM lParam ) -{ - - int res; - LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); - if (message != WM_INITDIALOG) - { - if (!lpp) - return FALSE; - res = 0; - if (CC_HookCallChk(lpp->lpcc)) - res = CallWindowProcA( (WNDPROC)lpp->lpcc->lpfnHook, hDlg, message, wParam, lParam); - if ( res ) - return res; - } - - /* FIXME: SetRGB message - if (message && message == msetrgb) - return HandleSetRGB(hDlg, lParam); - */ - - switch (message) - { - case WM_INITDIALOG: - return CC_WMInitDialog(hDlg, wParam, lParam); - case WM_NCDESTROY: - DeleteDC(lpp->hdcMem); - DeleteObject(lpp->hbmMem); - HeapFree(GetProcessHeap(), 0, lpp); - SetWindowLongPtrW(hDlg, DWLP_USER, 0); /* we don't need it anymore */ - break; - case WM_COMMAND: - if (CC_WMCommand( hDlg, wParam, lParam, HIWORD(wParam), (HWND) lParam)) - return TRUE; - break; - case WM_PAINT: - if ( CC_WMPaint(hDlg, wParam, lParam)) - return TRUE; - break; - case WM_LBUTTONDBLCLK: - if (CC_MouseCheckResultWindow(hDlg, lParam)) - return TRUE; - break; - case WM_MOUSEMOVE: - if (CC_WMMouseMove(hDlg, lParam)) - return TRUE; - break; - case WM_LBUTTONUP: /* FIXME: ClipCursor off (if in color graph)*/ - if (CC_WMLButtonUp(hDlg, wParam, lParam)) - return TRUE; - break; - case WM_LBUTTONDOWN:/* FIXME: ClipCursor on (if in color graph)*/ - if (CC_WMLButtonDown(hDlg, wParam, lParam)) - return TRUE; - break; - } - return FALSE ; -} - -/*********************************************************************** - * ChooseColorW (COMDLG32.@) - */ -BOOL WINAPI ChooseColorW( LPCHOOSECOLORW lpChCol ) -{ - HANDLE hDlgTmpl = 0; - BOOL bRet = FALSE; - LPCVOID template; - - TRACE("ChooseColor\n"); - if (!lpChCol) return FALSE; - - if (lpChCol->Flags & CC_ENABLETEMPLATEHANDLE) - { - if (!(template = LockResource(lpChCol->hInstance))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - } - else if (lpChCol->Flags & CC_ENABLETEMPLATE) - { - HRSRC hResInfo; - if (!(hResInfo = FindResourceW((HINSTANCE)lpChCol->hInstance, - lpChCol->lpTemplateName, - (LPWSTR)RT_DIALOG))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); - return FALSE; - } - if (!(hDlgTmpl = LoadResource((HINSTANCE)lpChCol->hInstance, hResInfo)) || - !(template = LockResource(hDlgTmpl))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - } - else - { - HRSRC hResInfo; - HGLOBAL hDlgTmpl; - static const WCHAR wszCHOOSE_COLOR[] = {'C','H','O','O','S','E','_','C','O','L','O','R',0}; - if (!(hResInfo = FindResourceW(COMDLG32_hInstance, wszCHOOSE_COLOR, (LPWSTR)RT_DIALOG))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); - return FALSE; - } - if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) || - !(template = LockResource(hDlgTmpl))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - } - - bRet = DialogBoxIndirectParamW(COMDLG32_hInstance, template, lpChCol->hwndOwner, - ColorDlgProc, (DWORD)lpChCol); - return bRet; -} - -/*********************************************************************** - * ChooseColorA (COMDLG32.@) - */ -BOOL WINAPI ChooseColorA( LPCHOOSECOLORA lpChCol ) - -{ - BOOL ret; - LPCHOOSECOLORW lpcc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHOOSECOLORW)); - lpcc->lStructSize = sizeof(*lpcc); - lpcc->hwndOwner = lpChCol->hwndOwner; - lpcc->hInstance = lpChCol->hInstance; - lpcc->rgbResult = lpChCol->rgbResult; - lpcc->lpCustColors = lpChCol->lpCustColors; - lpcc->Flags = lpChCol->Flags; - lpcc->lCustData = lpChCol->lCustData; - lpcc->lpfnHook = (LPCCHOOKPROC) lpChCol->lpfnHook; - if ((lpcc->Flags & CC_ENABLETEMPLATE) && (lpChCol->lpTemplateName)) { - if (HIWORD(lpChCol->lpTemplateName)) { - INT len = MultiByteToWideChar( CP_ACP, 0, lpChCol->lpTemplateName, -1, NULL, 0); - lpcc->lpTemplateName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, lpChCol->lpTemplateName, -1, (LPWSTR)lpcc->lpTemplateName, len ); - } else { - lpcc->lpTemplateName = (LPWSTR)lpChCol->lpTemplateName; - } - } - - ret = ChooseColorW(lpcc); - - if (ret) - lpChCol->rgbResult = lpcc->rgbResult; - if (HIWORD(lpcc->lpTemplateName)) HeapFree(GetProcessHeap(), 0, (LPSTR)lpcc->lpTemplateName); - HeapFree(GetProcessHeap(), 0, lpcc); - return ret; -} +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "dlgs.h" +#include "wine/debug.h" +#include "cderr.h" +#include "cdlg.h" + +WINE_DEFAULT_DEBUG_CHANNEL(commdlg); + +static INT_PTR CALLBACK ColorDlgProc( HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam ); + +#define CONV_LPARAMTOPOINT(lp,p) do { (p)->x = (short)LOWORD(lp); (p)->y = (short)HIWORD(lp); } while(0) + +static const COLORREF predefcolors[6][8]= +{ + { 0x008080FFL, 0x0080FFFFL, 0x0080FF80L, 0x0080FF00L, + 0x00FFFF80L, 0x00FF8000L, 0x00C080FFL, 0x00FF80FFL }, + { 0x000000FFL, 0x0000FFFFL, 0x0000FF80L, 0x0040FF00L, + 0x00FFFF00L, 0x00C08000L, 0x00C08080L, 0x00FF00FFL }, + + { 0x00404080L, 0x004080FFL, 0x0000FF00L, 0x00808000L, + 0x00804000L, 0x00FF8080L, 0x00400080L, 0x008000FFL }, + { 0x00000080L, 0x000080FFL, 0x00008000L, 0x00408000L, + 0x00FF0000L, 0x00A00000L, 0x00800080L, 0x00FF0080L }, + + { 0x00000040L, 0x00004080L, 0x00004000L, 0x00404000L, + 0x00800000L, 0x00400000L, 0x00400040L, 0x00800040L }, + { 0x00000000L, 0x00008080L, 0x00408080L, 0x00808080L, + 0x00808040L, 0x00C0C0C0L, 0x00400040L, 0x00FFFFFFL }, +}; + +/* Chose Color PRIVATE Structure: + * + * This structure is duplicated in the 16 bit code with + * an extra member + */ + +typedef struct CCPRIVATE +{ + LPCHOOSECOLORW lpcc; /* points to public known data structure */ + int nextuserdef; /* next free place in user defined color array */ + HDC hdcMem; /* color graph used for BitBlt() */ + HBITMAP hbmMem; /* color graph bitmap */ + RECT fullsize; /* original dialog window size */ + UINT msetrgb; /* # of SETRGBSTRING message (today not used) */ + RECT old3angle; /* last position of l-marker */ + RECT oldcross; /* last position of color/satuation marker */ + BOOL updating; /* to prevent recursive WM_COMMAND/EN_UPDATE processing */ + int h; + int s; + int l; /* for temporary storing of hue,sat,lum */ + int capturedGraph; /* control mouse captured */ + RECT focusRect; /* rectangle last focused item */ + HWND hwndFocus; /* handle last focused item */ +} *LCCPRIV; + +/*********************************************************************** + * CC_HSLtoRGB [internal] + */ +int CC_HSLtoRGB(char c, int hue, int sat, int lum) +{ + int res = 0, maxrgb; + + /* hue */ + switch(c) + { + case 'R': if (hue > 80) hue -= 80; else hue += 160; break; + case 'G': if (hue > 160) hue -= 160; else hue += 80; break; + case 'B': break; + } + + /* l below 120 */ + maxrgb = (256 * min(120,lum)) / 120; /* 0 .. 256 */ + if (hue < 80) + res = 0; + else + if (hue < 120) + { + res = (hue - 80) * maxrgb; /* 0...10240 */ + res /= 40; /* 0...256 */ + } + else + if (hue < 200) + res = maxrgb; + else + { + res= (240 - hue) * maxrgb; + res /= 40; + } + res = res - maxrgb / 2; /* -128...128 */ + + /* saturation */ + res = maxrgb / 2 + (sat * res) / 240; /* 0..256 */ + + /* lum above 120 */ + if (lum > 120 && res < 256) + res += ((lum - 120) * (256 - res)) / 120; + + return min(res, 255); +} + +/*********************************************************************** + * CC_RGBtoHSL [internal] + */ +int CC_RGBtoHSL(char c, int r, int g, int b) +{ + WORD maxi, mini, mmsum, mmdif, result = 0; + int iresult = 0; + + maxi = max(r, b); + maxi = max(maxi, g); + mini = min(r, b); + mini = min(mini, g); + + mmsum = maxi + mini; + mmdif = maxi - mini; + + switch(c) + { + /* lum */ + case 'L': mmsum *= 120; /* 0...61200=(255+255)*120 */ + result = mmsum / 255; /* 0...240 */ + break; + /* saturation */ + case 'S': if (!mmsum) + result = 0; + else + if (!mini || maxi == 255) + result = 240; + else + { + result = mmdif * 240; /* 0...61200=255*240 */ + result /= (mmsum > 255 ? mmsum = 510 - mmsum : mmsum); /* 0..255 */ + } + break; + /* hue */ + case 'H': if (!mmdif) + result = 160; + else + { + if (maxi == r) + { + iresult = 40 * (g - b); /* -10200 ... 10200 */ + iresult /= (int) mmdif; /* -40 .. 40 */ + if (iresult < 0) + iresult += 240; /* 0..40 and 200..240 */ + } + else + if (maxi == g) + { + iresult = 40 * (b - r); + iresult /= (int) mmdif; + iresult += 80; /* 40 .. 120 */ + } + else + if (maxi == b) + { + iresult = 40 * (r - g); + iresult /= (int) mmdif; + iresult += 160; /* 120 .. 200 */ + } + result = iresult; + } + break; + } + return result; /* is this integer arithmetic precise enough ? */ +} + + +/*********************************************************************** + * CC_DrawCurrentFocusRect [internal] + */ +void CC_DrawCurrentFocusRect( LCCPRIV lpp ) +{ + if (lpp->hwndFocus) + { + HDC hdc = GetDC(lpp->hwndFocus); + DrawFocusRect(hdc, &lpp->focusRect); + ReleaseDC(lpp->hwndFocus, hdc); + } +} + +/*********************************************************************** + * CC_DrawFocusRect [internal] + */ +void CC_DrawFocusRect( LCCPRIV lpp, HWND hwnd, int x, int y, int rows, int cols) +{ + RECT rect; + int dx, dy; + HDC hdc; + + CC_DrawCurrentFocusRect(lpp); /* remove current focus rect */ + /* calculate new rect */ + GetClientRect(hwnd, &rect); + dx = (rect.right - rect.left) / cols; + dy = (rect.bottom - rect.top) / rows; + rect.left += (x * dx) - 2; + rect.top += (y * dy) - 2; + rect.right = rect.left + dx; + rect.bottom = rect.top + dy; + /* draw it */ + hdc = GetDC(hwnd); + DrawFocusRect(hdc, &rect); + CopyRect(&lpp->focusRect, &rect); + lpp->hwndFocus = hwnd; + ReleaseDC(hwnd, hdc); +} + +#define DISTANCE 4 + +/*********************************************************************** + * CC_MouseCheckPredefColorArray [internal] + * returns 1 if one of the predefined colors is clicked + */ +static int CC_MouseCheckPredefColorArray( LCCPRIV lpp, HWND hDlg, int dlgitem, int rows, int cols, + LPARAM lParam ) +{ + HWND hwnd; + POINT point; + RECT rect; + int dx, dy, x, y; + + CONV_LPARAMTOPOINT(lParam, &point); + ClientToScreen(hDlg, &point); + hwnd = GetDlgItem(hDlg, dlgitem); + GetWindowRect(hwnd, &rect); + if (PtInRect(&rect, point)) + { + dx = (rect.right - rect.left) / cols; + dy = (rect.bottom - rect.top) / rows; + ScreenToClient(hwnd, &point); + + if (point.x % dx < ( dx - DISTANCE) && point.y % dy < ( dy - DISTANCE)) + { + x = point.x / dx; + y = point.y / dy; + lpp->lpcc->rgbResult = predefcolors[y][x]; + CC_DrawFocusRect(lpp, hwnd, x, y, rows, cols); + return 1; + } + } + return 0; +} + +/*********************************************************************** + * CC_MouseCheckUserColorArray [internal] + * return 1 if the user clicked a color + */ +static int CC_MouseCheckUserColorArray( LCCPRIV lpp, HWND hDlg, int dlgitem, int rows, int cols, + LPARAM lParam ) +{ + HWND hwnd; + POINT point; + RECT rect; + int dx, dy, x, y; + COLORREF *crarr = lpp->lpcc->lpCustColors; + + CONV_LPARAMTOPOINT(lParam, &point); + ClientToScreen(hDlg, &point); + hwnd = GetDlgItem(hDlg, dlgitem); + GetWindowRect(hwnd, &rect); + if (PtInRect(&rect, point)) + { + dx = (rect.right - rect.left) / cols; + dy = (rect.bottom - rect.top) / rows; + ScreenToClient(hwnd, &point); + + if (point.x % dx < (dx - DISTANCE) && point.y % dy < (dy - DISTANCE)) + { + x = point.x / dx; + y = point.y / dy; + lpp->lpcc->rgbResult = crarr[x + (cols * y) ]; + CC_DrawFocusRect(lpp, hwnd, x, y, rows, cols); + return 1; + } + } + return 0; +} + +#define MAXVERT 240 +#define MAXHORI 239 + +/* 240 ^...... ^^ 240 + | . || + SAT | . || LUM + | . || + +-----> 239 ---- + HUE +*/ +/*********************************************************************** + * CC_MouseCheckColorGraph [internal] + */ +static int CC_MouseCheckColorGraph( HWND hDlg, int dlgitem, int *hori, int *vert, LPARAM lParam ) +{ + HWND hwnd; + POINT point; + RECT rect; + long x,y; + + CONV_LPARAMTOPOINT(lParam, &point); + ClientToScreen(hDlg, &point); + hwnd = GetDlgItem( hDlg, dlgitem ); + GetWindowRect(hwnd, &rect); + if (PtInRect(&rect, point)) + { + GetClientRect(hwnd, &rect); + ScreenToClient(hwnd, &point); + + x = (long) point.x * MAXHORI; + x /= rect.right; + y = (long) (rect.bottom - point.y) * MAXVERT; + y /= rect.bottom; + + if (hori) + *hori = x; + if (vert) + *vert = y; + return 1; + } + else + return 0; +} +/*********************************************************************** + * CC_MouseCheckResultWindow [internal] + * test if double click one of the result colors + */ +int CC_MouseCheckResultWindow( HWND hDlg, LPARAM lParam ) +{ + HWND hwnd; + POINT point; + RECT rect; + + CONV_LPARAMTOPOINT(lParam, &point); + ClientToScreen(hDlg, &point); + hwnd = GetDlgItem(hDlg, 0x2c5); + GetWindowRect(hwnd, &rect); + if (PtInRect(&rect, point)) + { + PostMessageA(hDlg, WM_COMMAND, 0x2c9, 0); + return 1; + } + return 0; +} + +/*********************************************************************** + * CC_CheckDigitsInEdit [internal] + */ +int CC_CheckDigitsInEdit( HWND hwnd, int maxval ) +{ + int i, k, m, result, value; + long editpos; + char buffer[30]; + + GetWindowTextA(hwnd, buffer, sizeof(buffer)); + m = strlen(buffer); + result = 0; + + for (i = 0 ; i < m ; i++) + if (buffer[i] < '0' || buffer[i] > '9') + { + for (k = i + 1; k <= m; k++) /* delete bad character */ + { + buffer[i] = buffer[k]; + m--; + } + buffer[m] = 0; + result = 1; + } + + value = atoi(buffer); + if (value > maxval) /* build a new string */ + { + sprintf(buffer, "%d", maxval); + result = 2; + } + if (result) + { + editpos = SendMessageA(hwnd, EM_GETSEL, 0, 0); + SetWindowTextA(hwnd, buffer ); + SendMessageA(hwnd, EM_SETSEL, 0, editpos); + } + return value; +} + + + +/*********************************************************************** + * CC_PaintSelectedColor [internal] + */ +void CC_PaintSelectedColor( HWND hDlg, COLORREF cr ) +{ + RECT rect; + HDC hdc; + HBRUSH hBrush; + HWND hwnd = GetDlgItem(hDlg, 0x2c5); + if (IsWindowVisible( GetDlgItem(hDlg, 0x2c6) )) /* if full size */ + { + hdc = GetDC(hwnd); + GetClientRect(hwnd, &rect) ; + hBrush = CreateSolidBrush(cr); + if (hBrush) + { + hBrush = SelectObject(hdc, hBrush) ; + Rectangle(hdc, rect.left, rect.top, rect.right/2, rect.bottom); + DeleteObject ( SelectObject(hdc, hBrush) ) ; + hBrush = CreateSolidBrush( GetNearestColor(hdc, cr) ); + if (hBrush) + { + hBrush = SelectObject(hdc, hBrush) ; + Rectangle(hdc, rect.right/2-1, rect.top, rect.right, rect.bottom); + DeleteObject(SelectObject(hdc, hBrush)) ; + } + } + ReleaseDC(hwnd, hdc); + } +} + +/*********************************************************************** + * CC_PaintTriangle [internal] + */ +void CC_PaintTriangle( HWND hDlg, int y) +{ + HDC hDC; + long temp; + int w = LOWORD(GetDialogBaseUnits()); + POINT points[3]; + int height; + int oben; + RECT rect; + HWND hwnd = GetDlgItem(hDlg, 0x2be); + LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW( hDlg, DWLP_USER); + + if (IsWindowVisible( GetDlgItem(hDlg, 0x2c6))) /* if full size */ + { + GetClientRect(hwnd, &rect); + height = rect.bottom; + hDC = GetDC(hDlg); + points[0].y = rect.top; + points[0].x = rect.right; /* | /| */ + ClientToScreen(hwnd, points); /* | / | */ + ScreenToClient(hDlg, points); /* |< | */ + oben = points[0].y; /* | \ | */ + /* | \| */ + temp = (long)height * (long)y; + points[0].y = oben + height - temp / (long)MAXVERT; + points[1].y = points[0].y + w; + points[2].y = points[0].y - w; + points[2].x = points[1].x = points[0].x + w; + + FillRect(hDC, &lpp->old3angle, (HBRUSH)GetClassLongPtrW( hwnd, GCLP_HBRBACKGROUND)); + lpp->old3angle.left = points[0].x; + lpp->old3angle.right = points[1].x + 1; + lpp->old3angle.top = points[2].y - 1; + lpp->old3angle.bottom= points[1].y + 1; + Polygon(hDC, points, 3); + ReleaseDC(hDlg, hDC); + } +} + + +/*********************************************************************** + * CC_PaintCross [internal] + */ +void CC_PaintCross( HWND hDlg, int x, int y) +{ + HDC hDC; + int w = GetDialogBaseUnits(); + HWND hwnd = GetDlgItem(hDlg, 0x2c6); + LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW( hDlg, DWLP_USER ); + RECT rect; + POINT point, p; + HPEN hPen; + + if (IsWindowVisible( GetDlgItem(hDlg, 0x2c6) )) /* if full size */ + { + GetClientRect(hwnd, &rect); + hDC = GetDC(hwnd); + SelectClipRgn( hDC, CreateRectRgnIndirect(&rect)); + hPen = CreatePen(PS_SOLID, 2, 0xffffff); /* -white- color */ + hPen = SelectObject(hDC, hPen); + point.x = ((long)rect.right * (long)x) / (long)MAXHORI; + point.y = rect.bottom - ((long)rect.bottom * (long)y) / (long)MAXVERT; + if ( lpp->oldcross.left != lpp->oldcross.right ) + BitBlt(hDC, lpp->oldcross.left, lpp->oldcross.top, + lpp->oldcross.right - lpp->oldcross.left, + lpp->oldcross.bottom - lpp->oldcross.top, + lpp->hdcMem, lpp->oldcross.left, lpp->oldcross.top, SRCCOPY); + lpp->oldcross.left = point.x - w - 1; + lpp->oldcross.right = point.x + w + 1; + lpp->oldcross.top = point.y - w - 1; + lpp->oldcross.bottom = point.y + w + 1; + + MoveToEx(hDC, point.x - w, point.y, &p); + LineTo(hDC, point.x + w, point.y); + MoveToEx(hDC, point.x, point.y - w, &p); + LineTo(hDC, point.x, point.y + w); + DeleteObject( SelectObject(hDC, hPen)) ; + ReleaseDC(hwnd, hDC); + } +} + + +#define XSTEPS 48 +#define YSTEPS 24 + + +/*********************************************************************** + * CC_PrepareColorGraph [internal] + */ +static void CC_PrepareColorGraph( HWND hDlg ) +{ + int sdif, hdif, xdif, ydif, r, g, b, hue, sat; + HWND hwnd = GetDlgItem(hDlg, 0x2c6); + LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); + HBRUSH hbrush; + HDC hdc ; + RECT rect, client; + HCURSOR hcursor = SetCursor( LoadCursorW(0, (LPCWSTR)IDC_WAIT) ); + + GetClientRect(hwnd, &client); + hdc = GetDC(hwnd); + lpp->hdcMem = CreateCompatibleDC(hdc); + lpp->hbmMem = CreateCompatibleBitmap(hdc, client.right, client.bottom); + SelectObject(lpp->hdcMem, lpp->hbmMem); + + xdif = client.right / XSTEPS; + ydif = client.bottom / YSTEPS+1; + hdif = 239 / XSTEPS; + sdif = 240 / YSTEPS; + for (rect.left = hue = 0; hue < 239 + hdif; hue += hdif) + { + rect.right = rect.left + xdif; + rect.bottom = client.bottom; + for(sat = 0; sat < 240 + sdif; sat += sdif) + { + rect.top = rect.bottom - ydif; + r = CC_HSLtoRGB('R', hue, sat, 120); + g = CC_HSLtoRGB('G', hue, sat, 120); + b = CC_HSLtoRGB('B', hue, sat, 120); + hbrush = CreateSolidBrush( RGB(r, g, b)); + FillRect(lpp->hdcMem, &rect, hbrush); + DeleteObject(hbrush); + rect.bottom = rect.top; + } + rect.left = rect.right; + } + ReleaseDC(hwnd, hdc); + SetCursor(hcursor); +} + +/*********************************************************************** + * CC_PaintColorGraph [internal] + */ +static void CC_PaintColorGraph( HWND hDlg ) +{ + HWND hwnd = GetDlgItem( hDlg, 0x2c6 ); + LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); + HDC hDC; + RECT rect; + if (IsWindowVisible(hwnd)) /* if full size */ + { + if (!lpp->hdcMem) + CC_PrepareColorGraph(hDlg); /* should not be necessary */ + + hDC = GetDC(hwnd); + GetClientRect(hwnd, &rect); + if (lpp->hdcMem) + BitBlt(hDC, 0, 0, rect.right, rect.bottom, lpp->hdcMem, 0, 0, SRCCOPY); + else + WARN("choose color: hdcMem is not defined\n"); + ReleaseDC(hwnd, hDC); + } +} + +/*********************************************************************** + * CC_PaintLumBar [internal] + */ +static void CC_PaintLumBar( HWND hDlg, int hue, int sat ) +{ + HWND hwnd = GetDlgItem(hDlg, 0x2be); + RECT rect, client; + int lum, ldif, ydif, r, g, b; + HBRUSH hbrush; + HDC hDC; + + if (IsWindowVisible(hwnd)) + { + hDC = GetDC(hwnd); + GetClientRect(hwnd, &client); + rect = client; + + ldif = 240 / YSTEPS; + ydif = client.bottom / YSTEPS+1; + for (lum = 0; lum < 240 + ldif; lum += ldif) + { + rect.top = max(0, rect.bottom - ydif); + r = CC_HSLtoRGB('R', hue, sat, lum); + g = CC_HSLtoRGB('G', hue, sat, lum); + b = CC_HSLtoRGB('B', hue, sat, lum); + hbrush = CreateSolidBrush( RGB(r, g, b) ); + FillRect(hDC, &rect, hbrush); + DeleteObject(hbrush); + rect.bottom = rect.top; + } + GetClientRect(hwnd, &rect); + FrameRect(hDC, &rect, GetStockObject(BLACK_BRUSH) ); + ReleaseDC(hwnd, hDC); + } +} + +/*********************************************************************** + * CC_EditSetRGB [internal] + */ +void CC_EditSetRGB( HWND hDlg, COLORREF cr ) +{ + char buffer[10]; + LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); + int r = GetRValue(cr); + int g = GetGValue(cr); + int b = GetBValue(cr); + if (IsWindowVisible( GetDlgItem(hDlg, 0x2c6) )) /* if full size */ + { + lpp->updating = TRUE; + sprintf(buffer, "%d", r); + SetWindowTextA( GetDlgItem(hDlg, 0x2c2), buffer); + sprintf(buffer, "%d", g); + SetWindowTextA( GetDlgItem(hDlg, 0x2c3), buffer); + sprintf( buffer, "%d", b ); + SetWindowTextA( GetDlgItem(hDlg, 0x2c4),buffer); + lpp->updating = FALSE; + } +} + +/*********************************************************************** + * CC_EditSetHSL [internal] + */ +void CC_EditSetHSL( HWND hDlg, int h, int s, int l ) +{ + char buffer[10]; + LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); + lpp->updating = TRUE; + if (IsWindowVisible( GetDlgItem(hDlg, 0x2c6) )) /* if full size */ + { + lpp->updating = TRUE; + sprintf(buffer, "%d", h); + SetWindowTextA( GetDlgItem(hDlg, 0x2bf), buffer); + sprintf(buffer, "%d", s); + SetWindowTextA( GetDlgItem(hDlg, 0x2c0), buffer); + sprintf(buffer, "%d", l); + SetWindowTextA( GetDlgItem(hDlg, 0x2c1), buffer); + lpp->updating = FALSE; + } + CC_PaintLumBar(hDlg, h, s); +} + +/*********************************************************************** + * CC_SwitchToFullSize [internal] + */ +void CC_SwitchToFullSize( HWND hDlg, COLORREF result, LPRECT lprect ) +{ + int i; + LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); + + EnableWindow( GetDlgItem(hDlg, 0x2cf), FALSE); + CC_PrepareColorGraph(hDlg); + for (i = 0x2bf; i < 0x2c5; i++) + ShowWindow( GetDlgItem(hDlg, i), SW_SHOW); + for (i = 0x2d3; i < 0x2d9; i++) + ShowWindow( GetDlgItem(hDlg, i), SW_SHOW); + ShowWindow( GetDlgItem(hDlg, 0x2c9), SW_SHOW); + ShowWindow( GetDlgItem(hDlg, 0x2c8), SW_SHOW); + ShowWindow( GetDlgItem(hDlg, 1090), SW_SHOW); + + if (lprect) + SetWindowPos(hDlg, 0, 0, 0, lprect->right-lprect->left, + lprect->bottom-lprect->top, SWP_NOMOVE|SWP_NOZORDER); + + ShowWindow( GetDlgItem(hDlg, 0x2be), SW_SHOW); + ShowWindow( GetDlgItem(hDlg, 0x2c5), SW_SHOW); + + CC_EditSetRGB(hDlg, result); + CC_EditSetHSL(hDlg, lpp->h, lpp->s, lpp->l); + ShowWindow( GetDlgItem( hDlg, 0x2c6), SW_SHOW); + UpdateWindow( GetDlgItem(hDlg, 0x2c6) ); +} + +/*********************************************************************** + * CC_PaintPredefColorArray [internal] + * Paints the default standard 48 colors + */ +static void CC_PaintPredefColorArray( HWND hDlg, int rows, int cols) +{ + HWND hwnd = GetDlgItem(hDlg, 0x2d0); + RECT rect; + HDC hdc; + HBRUSH hBrush; + int dx, dy, i, j, k; + LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); + + GetClientRect(hwnd, &rect); + dx = rect.right / cols; + dy = rect.bottom / rows; + k = rect.left; + + hdc = GetDC(hwnd); + GetClientRect(hwnd, &rect); + FillRect(hdc, &rect, (HBRUSH)GetClassLongPtrW(hwnd, GCLP_HBRBACKGROUND)); + for ( j = 0; j < rows; j++ ) + { + for ( i = 0; i < cols; i++ ) + { + hBrush = CreateSolidBrush(predefcolors[j][i]); + if (hBrush) + { + hBrush = SelectObject(hdc, hBrush); + Rectangle(hdc, rect.left, rect.top, + rect.left + dx - DISTANCE, rect.top + dy - DISTANCE); + rect.left = rect.left + dx; + DeleteObject(SelectObject(hdc, hBrush)) ; + } + } + rect.top = rect.top + dy; + rect.left = k; + } + ReleaseDC(hwnd, hdc); + if (lpp->hwndFocus == hwnd) + CC_DrawCurrentFocusRect(lpp); +} +/*********************************************************************** + * CC_PaintUserColorArray [internal] + * Paint the 16 user-selected colors + */ +void CC_PaintUserColorArray( HWND hDlg, int rows, int cols, COLORREF* lpcr ) +{ + HWND hwnd = GetDlgItem(hDlg, 0x2d1); + RECT rect; + HDC hdc; + HBRUSH hBrush; + int dx, dy, i, j, k; + LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); + + GetClientRect(hwnd, &rect); + + dx = rect.right / cols; + dy = rect.bottom / rows; + k = rect.left; + + hdc = GetDC(hwnd); + if (hdc) + { + FillRect(hdc, &rect, (HBRUSH)GetClassLongPtrW(hwnd, GCLP_HBRBACKGROUND) ); + for (j = 0; j < rows; j++) + { + for (i = 0; i < cols; i++) + { + hBrush = CreateSolidBrush(lpcr[i+j*cols]); + if (hBrush) + { + hBrush = SelectObject(hdc, hBrush) ; + Rectangle(hdc, rect.left, rect.top, + rect.left + dx - DISTANCE, rect.top + dy - DISTANCE); + rect.left = rect.left + dx; + DeleteObject( SelectObject(hdc, hBrush) ) ; + } + } + rect.top = rect.top + dy; + rect.left = k; + } + ReleaseDC(hwnd, hdc); + } + if (lpp->hwndFocus == hwnd) + CC_DrawCurrentFocusRect(lpp); +} + + + +/*********************************************************************** + * CC_HookCallChk [internal] + */ +BOOL CC_HookCallChk( LPCHOOSECOLORW lpcc ) +{ + if (lpcc) + if(lpcc->Flags & CC_ENABLEHOOK) + if (lpcc->lpfnHook) + return TRUE; + return FALSE; +} + +/*********************************************************************** + * CC_WMInitDialog [internal] + */ +LONG CC_WMInitDialog( HWND hDlg, WPARAM wParam, LPARAM lParam ) +{ + int i, res; + int r, g, b; + HWND hwnd; + RECT rect; + POINT point; + LCCPRIV lpp; + + TRACE("WM_INITDIALOG lParam=%08lX\n", lParam); + lpp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct CCPRIVATE) ); + + lpp->lpcc = (LPCHOOSECOLORW) lParam; + if (lpp->lpcc->lStructSize != sizeof(CHOOSECOLORW) ) + { + HeapFree(GetProcessHeap(), 0, lpp); + EndDialog (hDlg, 0) ; + return FALSE; + } + + SetWindowLongPtrW(hDlg, DWLP_USER, (LONG_PTR)lpp); + + if (!(lpp->lpcc->Flags & CC_SHOWHELP)) + ShowWindow( GetDlgItem(hDlg,0x40e), SW_HIDE); + lpp->msetrgb = RegisterWindowMessageA(SETRGBSTRINGA); + +#if 0 + cpos = MAKELONG(5,7); /* init */ + if (lpp->lpcc->Flags & CC_RGBINIT) + { + for (i = 0; i < 6; i++) + for (j = 0; j < 8; j++) + if (predefcolors[i][j] == lpp->lpcc->rgbResult) + { + cpos = MAKELONG(i,j); + goto found; + } + } + found: + /* FIXME: Draw_a_focus_rect & set_init_values */ +#endif + + GetWindowRect(hDlg, &lpp->fullsize); + if (lpp->lpcc->Flags & CC_FULLOPEN || lpp->lpcc->Flags & CC_PREVENTFULLOPEN) + { + hwnd = GetDlgItem(hDlg, 0x2cf); + EnableWindow(hwnd, FALSE); + } + if (!(lpp->lpcc->Flags & CC_FULLOPEN ) || lpp->lpcc->Flags & CC_PREVENTFULLOPEN) + { + rect = lpp->fullsize; + res = rect.bottom - rect.top; + hwnd = GetDlgItem(hDlg, 0x2c6); /* cut at left border */ + point.x = point.y = 0; + ClientToScreen(hwnd, &point); + ScreenToClient(hDlg,&point); + GetClientRect(hDlg, &rect); + point.x += GetSystemMetrics(SM_CXDLGFRAME); + SetWindowPos(hDlg, 0, 0, 0, point.x, res, SWP_NOMOVE|SWP_NOZORDER); + + for (i = 0x2bf; i < 0x2c5; i++) + ShowWindow( GetDlgItem(hDlg, i), SW_HIDE); + for (i = 0x2d3; i < 0x2d9; i++) + ShowWindow( GetDlgItem(hDlg, i), SW_HIDE); + ShowWindow( GetDlgItem(hDlg, 0x2c9), SW_HIDE); + ShowWindow( GetDlgItem(hDlg, 0x2c8), SW_HIDE); + ShowWindow( GetDlgItem(hDlg, 0x2c6), SW_HIDE); + ShowWindow( GetDlgItem(hDlg, 0x2c5), SW_HIDE); + ShowWindow( GetDlgItem(hDlg, 1090 ), SW_HIDE); + } + else + CC_SwitchToFullSize(hDlg, lpp->lpcc->rgbResult, NULL); + res = TRUE; + for (i = 0x2bf; i < 0x2c5; i++) + SendMessageA( GetDlgItem(hDlg, i), EM_LIMITTEXT, 3, 0); /* max 3 digits: xyz */ + if (CC_HookCallChk(lpp->lpcc)) + { + res = CallWindowProcA( (WNDPROC)lpp->lpcc->lpfnHook, hDlg, WM_INITDIALOG, wParam, lParam); + } + + /* Set the initial values of the color chooser dialog */ + r = GetRValue(lpp->lpcc->rgbResult); + g = GetGValue(lpp->lpcc->rgbResult); + b = GetBValue(lpp->lpcc->rgbResult); + + CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); + lpp->h = CC_RGBtoHSL('H', r, g, b); + lpp->s = CC_RGBtoHSL('S', r, g, b); + lpp->l = CC_RGBtoHSL('L', r, g, b); + + /* Doing it the long way because CC_EditSetRGB/HSL doesn't seem to work */ + SetDlgItemInt(hDlg, 703, lpp->h, TRUE); + SetDlgItemInt(hDlg, 704, lpp->s, TRUE); + SetDlgItemInt(hDlg, 705, lpp->l, TRUE); + SetDlgItemInt(hDlg, 706, r, TRUE); + SetDlgItemInt(hDlg, 707, g, TRUE); + SetDlgItemInt(hDlg, 708, b, TRUE); + + CC_PaintCross(hDlg, lpp->h, lpp->s); + CC_PaintTriangle(hDlg, lpp->l); + + return res; +} + + +/*********************************************************************** + * CC_WMCommand [internal] + */ +LRESULT CC_WMCommand( HWND hDlg, WPARAM wParam, LPARAM lParam, WORD notifyCode, HWND hwndCtl ) +{ + int r, g, b, i, xx; + UINT cokmsg; + HDC hdc; + COLORREF *cr; + LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); + TRACE("CC_WMCommand wParam=%x lParam=%lx\n", wParam, lParam); + switch (wParam) + { + case 0x2c2: /* edit notify RGB */ + case 0x2c3: + case 0x2c4: + if (notifyCode == EN_UPDATE && !lpp->updating) + { + i = CC_CheckDigitsInEdit(hwndCtl, 255); + r = GetRValue(lpp->lpcc->rgbResult); + g = GetGValue(lpp->lpcc->rgbResult); + b= GetBValue(lpp->lpcc->rgbResult); + xx = 0; + switch (wParam) + { + case 0x2c2: if ((xx = (i != r))) r = i; break; + case 0x2c3: if ((xx = (i != g))) g = i; break; + case 0x2c4: if ((xx = (i != b))) b = i; break; + } + if (xx) /* something has changed */ + { + lpp->lpcc->rgbResult = RGB(r, g, b); + CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); + lpp->h = CC_RGBtoHSL('H', r, g, b); + lpp->s = CC_RGBtoHSL('S', r, g, b); + lpp->l = CC_RGBtoHSL('L', r, g, b); + CC_EditSetHSL(hDlg, lpp->h, lpp->s, lpp->l); + CC_PaintCross(hDlg, lpp->h, lpp->s); + CC_PaintTriangle(hDlg, lpp->l); + } + } + break; + + case 0x2bf: /* edit notify HSL */ + case 0x2c0: + case 0x2c1: + if (notifyCode == EN_UPDATE && !lpp->updating) + { + i = CC_CheckDigitsInEdit(hwndCtl , wParam == 0x2bf ? 239:240); + xx = 0; + switch (wParam) + { + case 0x2bf: if ((xx = ( i != lpp->h))) lpp->h = i; break; + case 0x2c0: if ((xx = ( i != lpp->s))) lpp->s = i; break; + case 0x2c1: if ((xx = ( i != lpp->l))) lpp->l = i; break; + } + if (xx) /* something has changed */ + { + r = CC_HSLtoRGB('R', lpp->h, lpp->s, lpp->l); + g = CC_HSLtoRGB('G', lpp->h, lpp->s, lpp->l); + b = CC_HSLtoRGB('B', lpp->h, lpp->s, lpp->l); + lpp->lpcc->rgbResult = RGB(r, g, b); + CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); + CC_EditSetRGB(hDlg, lpp->lpcc->rgbResult); + CC_PaintCross(hDlg, lpp->h, lpp->s); + CC_PaintTriangle(hDlg, lpp->l); + } + } + break; + + case 0x2cf: + CC_SwitchToFullSize(hDlg, lpp->lpcc->rgbResult, &lpp->fullsize); + SetFocus( GetDlgItem(hDlg, 0x2bf)); + break; + + case 0x2c8: /* add colors ... column by column */ + cr = lpp->lpcc->lpCustColors; + cr[(lpp->nextuserdef % 2) * 8 + lpp->nextuserdef / 2] = lpp->lpcc->rgbResult; + if (++lpp->nextuserdef == 16) + lpp->nextuserdef = 0; + CC_PaintUserColorArray(hDlg, 2, 8, lpp->lpcc->lpCustColors); + break; + + case 0x2c9: /* resulting color */ + hdc = GetDC(hDlg); + lpp->lpcc->rgbResult = GetNearestColor(hdc, lpp->lpcc->rgbResult); + ReleaseDC(hDlg, hdc); + CC_EditSetRGB(hDlg, lpp->lpcc->rgbResult); + CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); + r = GetRValue(lpp->lpcc->rgbResult); + g = GetGValue(lpp->lpcc->rgbResult); + b = GetBValue(lpp->lpcc->rgbResult); + lpp->h = CC_RGBtoHSL('H', r, g, b); + lpp->s = CC_RGBtoHSL('S', r, g, b); + lpp->l = CC_RGBtoHSL('L', r, g, b); + CC_EditSetHSL(hDlg, lpp->h, lpp->s, lpp->l); + CC_PaintCross(hDlg, lpp->h, lpp->s); + CC_PaintTriangle(hDlg, lpp->l); + break; + + case 0x40e: /* Help! */ /* The Beatles, 1965 ;-) */ + i = RegisterWindowMessageA(HELPMSGSTRINGA); + if (lpp->lpcc->hwndOwner) + SendMessageA(lpp->lpcc->hwndOwner, i, 0, (LPARAM)lpp->lpcc); + if ( CC_HookCallChk(lpp->lpcc)) + CallWindowProcA( (WNDPROC) lpp->lpcc->lpfnHook, hDlg, + WM_COMMAND, psh15, (LPARAM)lpp->lpcc); + break; + + case IDOK : + cokmsg = RegisterWindowMessageA(COLOROKSTRINGA); + if (lpp->lpcc->hwndOwner) + if (SendMessageA(lpp->lpcc->hwndOwner, cokmsg, 0, (LPARAM)lpp->lpcc)) + break; /* do NOT close */ + EndDialog(hDlg, 1) ; + return TRUE ; + + case IDCANCEL : + EndDialog(hDlg, 0) ; + return TRUE ; + + } + return FALSE; +} + +/*********************************************************************** + * CC_WMPaint [internal] + */ +LRESULT CC_WMPaint( HWND hDlg, WPARAM wParam, LPARAM lParam ) +{ + PAINTSTRUCT ps; + LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); + + BeginPaint(hDlg, &ps); + /* we have to paint dialog children except text and buttons */ + CC_PaintPredefColorArray(hDlg, 6, 8); + CC_PaintUserColorArray(hDlg, 2, 8, lpp->lpcc->lpCustColors); + CC_PaintLumBar(hDlg, lpp->h, lpp->s); + CC_PaintCross(hDlg, lpp->h, lpp->s); + CC_PaintTriangle(hDlg, lpp->l); + CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); + CC_PaintColorGraph(hDlg); + EndPaint(hDlg, &ps); + + return TRUE; +} + +/*********************************************************************** + * CC_WMLButtonUp [internal] + */ +LRESULT CC_WMLButtonUp( HWND hDlg, WPARAM wParam, LPARAM lParam ) +{ + LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); + if (lpp->capturedGraph) + { + lpp->capturedGraph = 0; + ReleaseCapture(); + CC_PaintCross(hDlg, lpp->h, lpp->s); + return 1; + } + return 0; +} + +/*********************************************************************** + * CC_WMMouseMove [internal] + */ +LRESULT CC_WMMouseMove( HWND hDlg, LPARAM lParam ) +{ + LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); + int r, g, b; + + if (lpp->capturedGraph) + { + int *ptrh = NULL, *ptrs = &lpp->l; + if (lpp->capturedGraph == 0x2c6) + { + ptrh = &lpp->h; + ptrs = &lpp->s; + } + if (CC_MouseCheckColorGraph( hDlg, lpp->capturedGraph, ptrh, ptrs, lParam)) + { + r = CC_HSLtoRGB('R', lpp->h, lpp->s, lpp->l); + g = CC_HSLtoRGB('G', lpp->h, lpp->s, lpp->l); + b = CC_HSLtoRGB('B', lpp->h, lpp->s, lpp->l); + lpp->lpcc->rgbResult = RGB(r, g, b); + CC_EditSetRGB(hDlg, lpp->lpcc->rgbResult); + CC_EditSetHSL(hDlg,lpp->h, lpp->s, lpp->l); + CC_PaintCross(hDlg, lpp->h, lpp->s); + CC_PaintTriangle(hDlg, lpp->l); + CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); + } + else + { + ReleaseCapture(); + lpp->capturedGraph = 0; + } + return 1; + } + return 0; +} + +/*********************************************************************** + * CC_WMLButtonDown [internal] + */ +LRESULT CC_WMLButtonDown( HWND hDlg, WPARAM wParam, LPARAM lParam ) +{ + LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); + int r, g, b, i; + i = 0; + + if (CC_MouseCheckPredefColorArray(lpp, hDlg, 0x2d0, 6, 8, lParam)) + i = 1; + else + if (CC_MouseCheckUserColorArray(lpp, hDlg, 0x2d1, 2, 8, lParam)) + i = 1; + else + if (CC_MouseCheckColorGraph(hDlg, 0x2c6, &lpp->h, &lpp->s, lParam)) + { + i = 2; + lpp->capturedGraph = 0x2c6; + } + else + if (CC_MouseCheckColorGraph(hDlg, 0x2be, NULL, &lpp->l, lParam)) + { + i = 2; + lpp->capturedGraph = 0x2be; + } + if ( i == 2 ) + { + SetCapture(hDlg); + r = CC_HSLtoRGB('R', lpp->h, lpp->s, lpp->l); + g = CC_HSLtoRGB('G', lpp->h, lpp->s, lpp->l); + b = CC_HSLtoRGB('B', lpp->h, lpp->s, lpp->l); + lpp->lpcc->rgbResult = RGB(r, g, b); + } + if ( i == 1 ) + { + r = GetRValue(lpp->lpcc->rgbResult); + g = GetGValue(lpp->lpcc->rgbResult); + b = GetBValue(lpp->lpcc->rgbResult); + lpp->h = CC_RGBtoHSL('H', r, g, b); + lpp->s = CC_RGBtoHSL('S', r, g, b); + lpp->l = CC_RGBtoHSL('L', r, g, b); + } + if (i) + { + CC_EditSetRGB(hDlg, lpp->lpcc->rgbResult); + CC_EditSetHSL(hDlg,lpp->h, lpp->s, lpp->l); + CC_PaintCross(hDlg, lpp->h, lpp->s); + CC_PaintTriangle(hDlg, lpp->l); + CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); + return TRUE; + } + return FALSE; +} + +/*********************************************************************** + * ColorDlgProc32 [internal] + * + */ +static INT_PTR CALLBACK ColorDlgProc( HWND hDlg, UINT message, + WPARAM wParam, LPARAM lParam ) +{ + + int res; + LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); + if (message != WM_INITDIALOG) + { + if (!lpp) + return FALSE; + res = 0; + if (CC_HookCallChk(lpp->lpcc)) + res = CallWindowProcA( (WNDPROC)lpp->lpcc->lpfnHook, hDlg, message, wParam, lParam); + if ( res ) + return res; + } + + /* FIXME: SetRGB message + if (message && message == msetrgb) + return HandleSetRGB(hDlg, lParam); + */ + + switch (message) + { + case WM_INITDIALOG: + return CC_WMInitDialog(hDlg, wParam, lParam); + case WM_NCDESTROY: + DeleteDC(lpp->hdcMem); + DeleteObject(lpp->hbmMem); + HeapFree(GetProcessHeap(), 0, lpp); + SetWindowLongPtrW(hDlg, DWLP_USER, 0); /* we don't need it anymore */ + break; + case WM_COMMAND: + if (CC_WMCommand( hDlg, wParam, lParam, HIWORD(wParam), (HWND) lParam)) + return TRUE; + break; + case WM_PAINT: + if ( CC_WMPaint(hDlg, wParam, lParam)) + return TRUE; + break; + case WM_LBUTTONDBLCLK: + if (CC_MouseCheckResultWindow(hDlg, lParam)) + return TRUE; + break; + case WM_MOUSEMOVE: + if (CC_WMMouseMove(hDlg, lParam)) + return TRUE; + break; + case WM_LBUTTONUP: /* FIXME: ClipCursor off (if in color graph)*/ + if (CC_WMLButtonUp(hDlg, wParam, lParam)) + return TRUE; + break; + case WM_LBUTTONDOWN:/* FIXME: ClipCursor on (if in color graph)*/ + if (CC_WMLButtonDown(hDlg, wParam, lParam)) + return TRUE; + break; + } + return FALSE ; +} + +/*********************************************************************** + * ChooseColorW (COMDLG32.@) + */ +BOOL WINAPI ChooseColorW( LPCHOOSECOLORW lpChCol ) +{ + HANDLE hDlgTmpl = 0; + BOOL bRet = FALSE; + LPCVOID template; + + TRACE("ChooseColor\n"); + if (!lpChCol) return FALSE; + + if (lpChCol->Flags & CC_ENABLETEMPLATEHANDLE) + { + if (!(template = LockResource(lpChCol->hInstance))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + } + else if (lpChCol->Flags & CC_ENABLETEMPLATE) + { + HRSRC hResInfo; + if (!(hResInfo = FindResourceW((HINSTANCE)lpChCol->hInstance, + lpChCol->lpTemplateName, + (LPWSTR)RT_DIALOG))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); + return FALSE; + } + if (!(hDlgTmpl = LoadResource((HINSTANCE)lpChCol->hInstance, hResInfo)) || + !(template = LockResource(hDlgTmpl))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + } + else + { + HRSRC hResInfo; + HGLOBAL hDlgTmpl; + static const WCHAR wszCHOOSE_COLOR[] = {'C','H','O','O','S','E','_','C','O','L','O','R',0}; + if (!(hResInfo = FindResourceW(COMDLG32_hInstance, wszCHOOSE_COLOR, (LPWSTR)RT_DIALOG))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); + return FALSE; + } + if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) || + !(template = LockResource(hDlgTmpl))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + } + + bRet = DialogBoxIndirectParamW(COMDLG32_hInstance, template, lpChCol->hwndOwner, + ColorDlgProc, (DWORD)lpChCol); + return bRet; +} + +/*********************************************************************** + * ChooseColorA (COMDLG32.@) + */ +BOOL WINAPI ChooseColorA( LPCHOOSECOLORA lpChCol ) + +{ + BOOL ret; + LPCHOOSECOLORW lpcc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHOOSECOLORW)); + lpcc->lStructSize = sizeof(*lpcc); + lpcc->hwndOwner = lpChCol->hwndOwner; + lpcc->hInstance = lpChCol->hInstance; + lpcc->rgbResult = lpChCol->rgbResult; + lpcc->lpCustColors = lpChCol->lpCustColors; + lpcc->Flags = lpChCol->Flags; + lpcc->lCustData = lpChCol->lCustData; + lpcc->lpfnHook = (LPCCHOOKPROC) lpChCol->lpfnHook; + if ((lpcc->Flags & CC_ENABLETEMPLATE) && (lpChCol->lpTemplateName)) { + if (HIWORD(lpChCol->lpTemplateName)) { + INT len = MultiByteToWideChar( CP_ACP, 0, lpChCol->lpTemplateName, -1, NULL, 0); + lpcc->lpTemplateName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, lpChCol->lpTemplateName, -1, (LPWSTR)lpcc->lpTemplateName, len ); + } else { + lpcc->lpTemplateName = (LPWSTR)lpChCol->lpTemplateName; + } + } + + ret = ChooseColorW(lpcc); + + if (ret) + lpChCol->rgbResult = lpcc->rgbResult; + if (HIWORD(lpcc->lpTemplateName)) HeapFree(GetProcessHeap(), 0, (LPSTR)lpcc->lpTemplateName); + HeapFree(GetProcessHeap(), 0, lpcc); + return ret; +} diff --git a/reactos/lib/comdlg32/colordlg16.c b/reactos/lib/comdlg32/colordlg16.c index 0e70485d979..fea848821d7 100644 --- a/reactos/lib/comdlg32/colordlg16.c +++ b/reactos/lib/comdlg32/colordlg16.c @@ -1,476 +1,476 @@ -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "wine/winbase16.h" -#include "wine/winuser16.h" -#include "winuser.h" -#include "commdlg.h" -#include "dlgs.h" -#include "wine/debug.h" -#include "cderr.h" -#include "cdlg.h" -#include "cdlg16.h" - -WINE_DEFAULT_DEBUG_CHANNEL(commdlg); - -/* Chose Color PRIVATE Structure: - * - * This is a duplicate of the 32bit code with - * an extra member - */ -typedef struct CCPRIVATE -{ - LPCHOOSECOLORW lpcc; /* points to public known data structure */ - LPCHOOSECOLOR16 lpcc16; /* save the 16 bits pointer */ - int nextuserdef; /* next free place in user defined color array */ - HDC hdcMem; /* color graph used for BitBlt() */ - HBITMAP hbmMem; /* color graph bitmap */ - RECT fullsize; /* original dialog window size */ - UINT msetrgb; /* # of SETRGBSTRING message (today not used) */ - RECT old3angle; /* last position of l-marker */ - RECT oldcross; /* last position of color/satuation marker */ - BOOL updating; /* to prevent recursive WM_COMMAND/EN_UPDATE processing */ - int h; - int s; - int l; /* for temporary storing of hue,sat,lum */ - int capturedGraph; /* control mouse captured */ - RECT focusRect; /* rectangle last focused item */ - HWND hwndFocus; /* handle last focused item */ -} *LCCPRIV; - -/*********************************************************************** - * CC_WMInitDialog16 [internal] - */ -LONG CC_WMInitDialog16( HWND hDlg, WPARAM wParam, LPARAM lParam ) -{ - int i, res; - int r, g, b; - HWND hwnd; - RECT rect; - POINT point; - LCCPRIV lpp; - CHOOSECOLORW *ch32; - CHOOSECOLOR16 *ch16 = (CHOOSECOLOR16 *) lParam; - - TRACE("WM_INITDIALOG lParam=%08lX\n", lParam); - lpp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct CCPRIVATE) ); - - if (ch16->lStructSize != sizeof(CHOOSECOLOR16) ) - { - HeapFree(GetProcessHeap(), 0, lpp); - EndDialog (hDlg, 0) ; - return FALSE; - } - ch32 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHOOSECOLORW) ); - lpp->lpcc = ch32; - lpp->lpcc16 = ch16; - ch32->lStructSize = sizeof(CHOOSECOLORW); - ch32->hwndOwner = HWND_32(ch16->hwndOwner); - /* Should be an HINSTANCE but MS made a typo */ - ch32->hInstance = HWND_32(ch16->hInstance); - ch32->lpCustColors = MapSL(ch16->lpCustColors); - ch32->lpfnHook = (LPCCHOOKPROC) ch16->lpfnHook; /* only used as flag */ - ch32->Flags = ch16->Flags; - - SetWindowLongPtrW(hDlg, DWLP_USER, (LONG_PTR)lpp); - - if (!(lpp->lpcc->Flags & CC_SHOWHELP)) - ShowWindow( GetDlgItem(hDlg,0x40e), SW_HIDE); - lpp->msetrgb = RegisterWindowMessageA(SETRGBSTRINGA); - -#if 0 - cpos = MAKELONG(5,7); /* init */ - if (lpp->lpcc->Flags & CC_RGBINIT) - { - for (i = 0; i < 6; i++) - for (j = 0; j < 8; j++) - if (predefcolors[i][j] == lpp->lpcc->rgbResult) - { - cpos = MAKELONG(i,j); - goto found; - } - } - found: - /* FIXME: Draw_a_focus_rect & set_init_values */ -#endif - - GetWindowRect(hDlg, &lpp->fullsize); - if (lpp->lpcc->Flags & CC_FULLOPEN || lpp->lpcc->Flags & CC_PREVENTFULLOPEN) - { - hwnd = GetDlgItem(hDlg, 0x2cf); - EnableWindow(hwnd, FALSE); - } - if (!(lpp->lpcc->Flags & CC_FULLOPEN ) || lpp->lpcc->Flags & CC_PREVENTFULLOPEN) - { - rect = lpp->fullsize; - res = rect.bottom - rect.top; - hwnd = GetDlgItem(hDlg, 0x2c6); /* cut at left border */ - point.x = point.y = 0; - ClientToScreen(hwnd, &point); - ScreenToClient(hDlg,&point); - GetClientRect(hDlg, &rect); - point.x += GetSystemMetrics(SM_CXDLGFRAME); - SetWindowPos(hDlg, 0, 0, 0, point.x, res, SWP_NOMOVE|SWP_NOZORDER); - - for (i = 0x2bf; i < 0x2c5; i++) - ShowWindow( GetDlgItem(hDlg, i), SW_HIDE); - for (i = 0x2d3; i < 0x2d9; i++) - ShowWindow( GetDlgItem(hDlg, i), SW_HIDE); - ShowWindow( GetDlgItem(hDlg, 0x2c9), SW_HIDE); - ShowWindow( GetDlgItem(hDlg, 0x2c8), SW_HIDE); - ShowWindow( GetDlgItem(hDlg, 0x2c6), SW_HIDE); - ShowWindow( GetDlgItem(hDlg, 0x2c5), SW_HIDE); - ShowWindow( GetDlgItem(hDlg, 1090 ), SW_HIDE); - } - else - CC_SwitchToFullSize(hDlg, lpp->lpcc->rgbResult, NULL); - res = TRUE; - for (i = 0x2bf; i < 0x2c5; i++) - SendMessageA( GetDlgItem(hDlg, i), EM_LIMITTEXT, 3, 0); /* max 3 digits: xyz */ - if (CC_HookCallChk(lpp->lpcc)) - { - res = CallWindowProc16( (WNDPROC16)lpp->lpcc16->lpfnHook, - HWND_16(hDlg), WM_INITDIALOG, wParam, lParam); - } - - /* Set the initial values of the color chooser dialog */ - r = GetRValue(lpp->lpcc->rgbResult); - g = GetGValue(lpp->lpcc->rgbResult); - b = GetBValue(lpp->lpcc->rgbResult); - - CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); - lpp->h = CC_RGBtoHSL('H', r, g, b); - lpp->s = CC_RGBtoHSL('S', r, g, b); - lpp->l = CC_RGBtoHSL('L', r, g, b); - - /* Doing it the long way because CC_EditSetRGB/HSL doesn't seem to work */ - SetDlgItemInt(hDlg, 703, lpp->h, TRUE); - SetDlgItemInt(hDlg, 704, lpp->s, TRUE); - SetDlgItemInt(hDlg, 705, lpp->l, TRUE); - SetDlgItemInt(hDlg, 706, r, TRUE); - SetDlgItemInt(hDlg, 707, g, TRUE); - SetDlgItemInt(hDlg, 708, b, TRUE); - - CC_PaintCross(hDlg, lpp->h, lpp->s); - CC_PaintTriangle(hDlg, lpp->l); - - return res; -} - -/*********************************************************************** - * CC_WMCommand16 [internal] - */ -LRESULT CC_WMCommand16( HWND hDlg, WPARAM wParam, LPARAM lParam, WORD notifyCode, HWND hwndCtl ) -{ - int r, g, b, i, xx; - UINT cokmsg; - HDC hdc; - COLORREF *cr; - LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); - TRACE("CC_WMCommand wParam=%x lParam=%lx\n", wParam, lParam); - switch (wParam) - { - case 0x2c2: /* edit notify RGB */ - case 0x2c3: - case 0x2c4: - if (notifyCode == EN_UPDATE && !lpp->updating) - { - i = CC_CheckDigitsInEdit(hwndCtl, 255); - r = GetRValue(lpp->lpcc->rgbResult); - g = GetGValue(lpp->lpcc->rgbResult); - b= GetBValue(lpp->lpcc->rgbResult); - xx = 0; - switch (wParam) - { - case 0x2c2: if ((xx = (i != r))) r = i; break; - case 0x2c3: if ((xx = (i != g))) g = i; break; - case 0x2c4: if ((xx = (i != b))) b = i; break; - } - if (xx) /* something has changed */ - { - lpp->lpcc->rgbResult = RGB(r, g, b); - CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); - lpp->h = CC_RGBtoHSL('H', r, g, b); - lpp->s = CC_RGBtoHSL('S', r, g, b); - lpp->l = CC_RGBtoHSL('L', r, g, b); - CC_EditSetHSL(hDlg, lpp->h, lpp->s, lpp->l); - CC_PaintCross(hDlg, lpp->h, lpp->s); - CC_PaintTriangle(hDlg, lpp->l); - } - } - break; - - case 0x2bf: /* edit notify HSL */ - case 0x2c0: - case 0x2c1: - if (notifyCode == EN_UPDATE && !lpp->updating) - { - i = CC_CheckDigitsInEdit(hwndCtl , wParam == 0x2bf ? 239:240); - xx = 0; - switch (wParam) - { - case 0x2bf: if ((xx = ( i != lpp->h))) lpp->h = i; break; - case 0x2c0: if ((xx = ( i != lpp->s))) lpp->s = i; break; - case 0x2c1: if ((xx = ( i != lpp->l))) lpp->l = i; break; - } - if (xx) /* something has changed */ - { - r = CC_HSLtoRGB('R', lpp->h, lpp->s, lpp->l); - g = CC_HSLtoRGB('G', lpp->h, lpp->s, lpp->l); - b = CC_HSLtoRGB('B', lpp->h, lpp->s, lpp->l); - lpp->lpcc->rgbResult = RGB(r, g, b); - CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); - CC_EditSetRGB(hDlg, lpp->lpcc->rgbResult); - CC_PaintCross(hDlg, lpp->h, lpp->s); - CC_PaintTriangle(hDlg, lpp->l); - } - } - break; - - case 0x2cf: - CC_SwitchToFullSize(hDlg, lpp->lpcc->rgbResult, &lpp->fullsize); - SetFocus( GetDlgItem(hDlg, 0x2bf)); - break; - - case 0x2c8: /* add colors ... column by column */ - cr = lpp->lpcc->lpCustColors; - cr[(lpp->nextuserdef % 2) * 8 + lpp->nextuserdef / 2] = lpp->lpcc->rgbResult; - if (++lpp->nextuserdef == 16) - lpp->nextuserdef = 0; - CC_PaintUserColorArray(hDlg, 2, 8, lpp->lpcc->lpCustColors); - break; - - case 0x2c9: /* resulting color */ - hdc = GetDC(hDlg); - lpp->lpcc->rgbResult = GetNearestColor(hdc, lpp->lpcc->rgbResult); - ReleaseDC(hDlg, hdc); - CC_EditSetRGB(hDlg, lpp->lpcc->rgbResult); - CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); - r = GetRValue(lpp->lpcc->rgbResult); - g = GetGValue(lpp->lpcc->rgbResult); - b = GetBValue(lpp->lpcc->rgbResult); - lpp->h = CC_RGBtoHSL('H', r, g, b); - lpp->s = CC_RGBtoHSL('S', r, g, b); - lpp->l = CC_RGBtoHSL('L', r, g, b); - CC_EditSetHSL(hDlg, lpp->h, lpp->s, lpp->l); - CC_PaintCross(hDlg, lpp->h, lpp->s); - CC_PaintTriangle(hDlg, lpp->l); - break; - - case 0x40e: /* Help! */ /* The Beatles, 1965 ;-) */ - i = RegisterWindowMessageA(HELPMSGSTRINGA); - if (lpp->lpcc16) - { - if (lpp->lpcc->hwndOwner) - SendMessageA(lpp->lpcc->hwndOwner, i, 0, (LPARAM)lpp->lpcc16); - if ( CC_HookCallChk(lpp->lpcc)) - CallWindowProc16( (WNDPROC16) lpp->lpcc16->lpfnHook, - HWND_16(hDlg), WM_COMMAND, psh15, - (LPARAM)lpp->lpcc16); - } - break; - - case IDOK : - cokmsg = RegisterWindowMessageA(COLOROKSTRINGA); - if (lpp->lpcc16) - { - if (lpp->lpcc->hwndOwner) - if (SendMessageA(lpp->lpcc->hwndOwner, cokmsg, 0, (LPARAM)lpp->lpcc16)) - break; /* do NOT close */ - } - if (lpp->lpcc16) - { - BYTE *ptr = MapSL(lpp->lpcc16->lpCustColors); - memcpy(ptr, lpp->lpcc->lpCustColors, sizeof(COLORREF)*16); - lpp->lpcc16->rgbResult = lpp->lpcc->rgbResult; - } - EndDialog(hDlg, 1) ; - return TRUE ; - - case IDCANCEL : - EndDialog(hDlg, 0) ; - return TRUE ; - - } - return FALSE; -} - -/*********************************************************************** - * ColorDlgProc (COMMDLG.8) - */ -BOOL16 CALLBACK ColorDlgProc16( HWND16 hDlg16, UINT16 message, - WPARAM16 wParam, LONG lParam ) -{ - BOOL16 res; - HWND hDlg = HWND_32(hDlg16); - - LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); - if (message != WM_INITDIALOG) - { - if (!lpp) - return FALSE; - res=0; - if (CC_HookCallChk(lpp->lpcc)) - res = CallWindowProc16( (WNDPROC16)lpp->lpcc16->lpfnHook, hDlg16, message, wParam, lParam); - if (res) - return res; - } - - /* FIXME: SetRGB message - if (message && message == msetrgb) - return HandleSetRGB(hDlg, lParam); - */ - - switch (message) - { - case WM_INITDIALOG: - return CC_WMInitDialog16(hDlg, wParam, lParam); - case WM_NCDESTROY: - DeleteDC(lpp->hdcMem); - DeleteObject(lpp->hbmMem); - HeapFree(GetProcessHeap(), 0, lpp->lpcc); - HeapFree(GetProcessHeap(), 0, lpp); - SetWindowLongPtrW(hDlg, DWLP_USER, 0); /* we don't need it anymore */ - break; - case WM_COMMAND: - if (CC_WMCommand16(hDlg, wParam, lParam, - HIWORD(lParam), HWND_32(LOWORD(lParam)))) - return TRUE; - break; - case WM_PAINT: - if (CC_WMPaint(hDlg, wParam, lParam)) - return TRUE; - break; - case WM_LBUTTONDBLCLK: - if (CC_MouseCheckResultWindow(hDlg,lParam)) - return TRUE; - break; - case WM_MOUSEMOVE: - if (CC_WMMouseMove(hDlg, lParam)) - return TRUE; - break; - case WM_LBUTTONUP: /* FIXME: ClipCursor off (if in color graph)*/ - if (CC_WMLButtonUp(hDlg, wParam, lParam)) - return TRUE; - break; - case WM_LBUTTONDOWN:/* FIXME: ClipCursor on (if in color graph)*/ - if (CC_WMLButtonDown(hDlg, wParam, lParam)) - return TRUE; - break; - } - return FALSE ; -} - -/*********************************************************************** - * ChooseColor (COMMDLG.5) - */ -BOOL16 WINAPI ChooseColor16( LPCHOOSECOLOR16 lpChCol ) -{ - HINSTANCE16 hInst; - HANDLE16 hDlgTmpl16 = 0, hResource16 = 0; - HGLOBAL16 hGlobal16 = 0; - BOOL16 bRet = FALSE; - LPCVOID template; - FARPROC16 ptr; - - TRACE("ChooseColor\n"); - if (!lpChCol) return FALSE; - - if (lpChCol->Flags & CC_ENABLETEMPLATEHANDLE) - hDlgTmpl16 = lpChCol->hInstance; - else if (lpChCol->Flags & CC_ENABLETEMPLATE) - { - HANDLE16 hResInfo; - if (!(hResInfo = FindResource16(lpChCol->hInstance, - MapSL(lpChCol->lpTemplateName), - (LPSTR)RT_DIALOG))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); - return FALSE; - } - if (!(hDlgTmpl16 = LoadResource16(lpChCol->hInstance, hResInfo))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - hResource16 = hDlgTmpl16; - } - else - { - HRSRC hResInfo; - HGLOBAL hDlgTmpl32; - LPCVOID template32; - DWORD size; - if (!(hResInfo = FindResourceA(COMDLG32_hInstance, "CHOOSE_COLOR", (LPSTR)RT_DIALOG))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); - return FALSE; - } - if (!(hDlgTmpl32 = LoadResource(COMDLG32_hInstance, hResInfo)) || - !(template32 = LockResource(hDlgTmpl32))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - size = SizeofResource(COMDLG32_hInstance, hResInfo); - hGlobal16 = GlobalAlloc16(0, size); - if (!hGlobal16) - { - COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE); - ERR("alloc failure for %ld bytes\n", size); - return FALSE; - } - template = GlobalLock16(hGlobal16); - if (!template) - { - COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE); - ERR("global lock failure for %x handle\n", hDlgTmpl16); - GlobalFree16(hGlobal16); - return FALSE; - } - ConvertDialog32To16((LPVOID)template32, size, (LPVOID)template); - hDlgTmpl16 = hGlobal16; - } - - ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 8); - hInst = GetWindowLongPtrA(HWND_32(lpChCol->hwndOwner), GWLP_HINSTANCE); - bRet = DialogBoxIndirectParam16(hInst, hDlgTmpl16, lpChCol->hwndOwner, - (DLGPROC16) ptr, (DWORD)lpChCol); - if (hResource16) FreeResource16(hDlgTmpl16); - if (hGlobal16) - { - GlobalUnlock16(hGlobal16); - GlobalFree16(hGlobal16); - } - return bRet; -} +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "wine/winbase16.h" +#include "wine/winuser16.h" +#include "winuser.h" +#include "commdlg.h" +#include "dlgs.h" +#include "wine/debug.h" +#include "cderr.h" +#include "cdlg.h" +#include "cdlg16.h" + +WINE_DEFAULT_DEBUG_CHANNEL(commdlg); + +/* Chose Color PRIVATE Structure: + * + * This is a duplicate of the 32bit code with + * an extra member + */ +typedef struct CCPRIVATE +{ + LPCHOOSECOLORW lpcc; /* points to public known data structure */ + LPCHOOSECOLOR16 lpcc16; /* save the 16 bits pointer */ + int nextuserdef; /* next free place in user defined color array */ + HDC hdcMem; /* color graph used for BitBlt() */ + HBITMAP hbmMem; /* color graph bitmap */ + RECT fullsize; /* original dialog window size */ + UINT msetrgb; /* # of SETRGBSTRING message (today not used) */ + RECT old3angle; /* last position of l-marker */ + RECT oldcross; /* last position of color/satuation marker */ + BOOL updating; /* to prevent recursive WM_COMMAND/EN_UPDATE processing */ + int h; + int s; + int l; /* for temporary storing of hue,sat,lum */ + int capturedGraph; /* control mouse captured */ + RECT focusRect; /* rectangle last focused item */ + HWND hwndFocus; /* handle last focused item */ +} *LCCPRIV; + +/*********************************************************************** + * CC_WMInitDialog16 [internal] + */ +LONG CC_WMInitDialog16( HWND hDlg, WPARAM wParam, LPARAM lParam ) +{ + int i, res; + int r, g, b; + HWND hwnd; + RECT rect; + POINT point; + LCCPRIV lpp; + CHOOSECOLORW *ch32; + CHOOSECOLOR16 *ch16 = (CHOOSECOLOR16 *) lParam; + + TRACE("WM_INITDIALOG lParam=%08lX\n", lParam); + lpp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct CCPRIVATE) ); + + if (ch16->lStructSize != sizeof(CHOOSECOLOR16) ) + { + HeapFree(GetProcessHeap(), 0, lpp); + EndDialog (hDlg, 0) ; + return FALSE; + } + ch32 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHOOSECOLORW) ); + lpp->lpcc = ch32; + lpp->lpcc16 = ch16; + ch32->lStructSize = sizeof(CHOOSECOLORW); + ch32->hwndOwner = HWND_32(ch16->hwndOwner); + /* Should be an HINSTANCE but MS made a typo */ + ch32->hInstance = HWND_32(ch16->hInstance); + ch32->lpCustColors = MapSL(ch16->lpCustColors); + ch32->lpfnHook = (LPCCHOOKPROC) ch16->lpfnHook; /* only used as flag */ + ch32->Flags = ch16->Flags; + + SetWindowLongPtrW(hDlg, DWLP_USER, (LONG_PTR)lpp); + + if (!(lpp->lpcc->Flags & CC_SHOWHELP)) + ShowWindow( GetDlgItem(hDlg,0x40e), SW_HIDE); + lpp->msetrgb = RegisterWindowMessageA(SETRGBSTRINGA); + +#if 0 + cpos = MAKELONG(5,7); /* init */ + if (lpp->lpcc->Flags & CC_RGBINIT) + { + for (i = 0; i < 6; i++) + for (j = 0; j < 8; j++) + if (predefcolors[i][j] == lpp->lpcc->rgbResult) + { + cpos = MAKELONG(i,j); + goto found; + } + } + found: + /* FIXME: Draw_a_focus_rect & set_init_values */ +#endif + + GetWindowRect(hDlg, &lpp->fullsize); + if (lpp->lpcc->Flags & CC_FULLOPEN || lpp->lpcc->Flags & CC_PREVENTFULLOPEN) + { + hwnd = GetDlgItem(hDlg, 0x2cf); + EnableWindow(hwnd, FALSE); + } + if (!(lpp->lpcc->Flags & CC_FULLOPEN ) || lpp->lpcc->Flags & CC_PREVENTFULLOPEN) + { + rect = lpp->fullsize; + res = rect.bottom - rect.top; + hwnd = GetDlgItem(hDlg, 0x2c6); /* cut at left border */ + point.x = point.y = 0; + ClientToScreen(hwnd, &point); + ScreenToClient(hDlg,&point); + GetClientRect(hDlg, &rect); + point.x += GetSystemMetrics(SM_CXDLGFRAME); + SetWindowPos(hDlg, 0, 0, 0, point.x, res, SWP_NOMOVE|SWP_NOZORDER); + + for (i = 0x2bf; i < 0x2c5; i++) + ShowWindow( GetDlgItem(hDlg, i), SW_HIDE); + for (i = 0x2d3; i < 0x2d9; i++) + ShowWindow( GetDlgItem(hDlg, i), SW_HIDE); + ShowWindow( GetDlgItem(hDlg, 0x2c9), SW_HIDE); + ShowWindow( GetDlgItem(hDlg, 0x2c8), SW_HIDE); + ShowWindow( GetDlgItem(hDlg, 0x2c6), SW_HIDE); + ShowWindow( GetDlgItem(hDlg, 0x2c5), SW_HIDE); + ShowWindow( GetDlgItem(hDlg, 1090 ), SW_HIDE); + } + else + CC_SwitchToFullSize(hDlg, lpp->lpcc->rgbResult, NULL); + res = TRUE; + for (i = 0x2bf; i < 0x2c5; i++) + SendMessageA( GetDlgItem(hDlg, i), EM_LIMITTEXT, 3, 0); /* max 3 digits: xyz */ + if (CC_HookCallChk(lpp->lpcc)) + { + res = CallWindowProc16( (WNDPROC16)lpp->lpcc16->lpfnHook, + HWND_16(hDlg), WM_INITDIALOG, wParam, lParam); + } + + /* Set the initial values of the color chooser dialog */ + r = GetRValue(lpp->lpcc->rgbResult); + g = GetGValue(lpp->lpcc->rgbResult); + b = GetBValue(lpp->lpcc->rgbResult); + + CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); + lpp->h = CC_RGBtoHSL('H', r, g, b); + lpp->s = CC_RGBtoHSL('S', r, g, b); + lpp->l = CC_RGBtoHSL('L', r, g, b); + + /* Doing it the long way because CC_EditSetRGB/HSL doesn't seem to work */ + SetDlgItemInt(hDlg, 703, lpp->h, TRUE); + SetDlgItemInt(hDlg, 704, lpp->s, TRUE); + SetDlgItemInt(hDlg, 705, lpp->l, TRUE); + SetDlgItemInt(hDlg, 706, r, TRUE); + SetDlgItemInt(hDlg, 707, g, TRUE); + SetDlgItemInt(hDlg, 708, b, TRUE); + + CC_PaintCross(hDlg, lpp->h, lpp->s); + CC_PaintTriangle(hDlg, lpp->l); + + return res; +} + +/*********************************************************************** + * CC_WMCommand16 [internal] + */ +LRESULT CC_WMCommand16( HWND hDlg, WPARAM wParam, LPARAM lParam, WORD notifyCode, HWND hwndCtl ) +{ + int r, g, b, i, xx; + UINT cokmsg; + HDC hdc; + COLORREF *cr; + LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); + TRACE("CC_WMCommand wParam=%x lParam=%lx\n", wParam, lParam); + switch (wParam) + { + case 0x2c2: /* edit notify RGB */ + case 0x2c3: + case 0x2c4: + if (notifyCode == EN_UPDATE && !lpp->updating) + { + i = CC_CheckDigitsInEdit(hwndCtl, 255); + r = GetRValue(lpp->lpcc->rgbResult); + g = GetGValue(lpp->lpcc->rgbResult); + b= GetBValue(lpp->lpcc->rgbResult); + xx = 0; + switch (wParam) + { + case 0x2c2: if ((xx = (i != r))) r = i; break; + case 0x2c3: if ((xx = (i != g))) g = i; break; + case 0x2c4: if ((xx = (i != b))) b = i; break; + } + if (xx) /* something has changed */ + { + lpp->lpcc->rgbResult = RGB(r, g, b); + CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); + lpp->h = CC_RGBtoHSL('H', r, g, b); + lpp->s = CC_RGBtoHSL('S', r, g, b); + lpp->l = CC_RGBtoHSL('L', r, g, b); + CC_EditSetHSL(hDlg, lpp->h, lpp->s, lpp->l); + CC_PaintCross(hDlg, lpp->h, lpp->s); + CC_PaintTriangle(hDlg, lpp->l); + } + } + break; + + case 0x2bf: /* edit notify HSL */ + case 0x2c0: + case 0x2c1: + if (notifyCode == EN_UPDATE && !lpp->updating) + { + i = CC_CheckDigitsInEdit(hwndCtl , wParam == 0x2bf ? 239:240); + xx = 0; + switch (wParam) + { + case 0x2bf: if ((xx = ( i != lpp->h))) lpp->h = i; break; + case 0x2c0: if ((xx = ( i != lpp->s))) lpp->s = i; break; + case 0x2c1: if ((xx = ( i != lpp->l))) lpp->l = i; break; + } + if (xx) /* something has changed */ + { + r = CC_HSLtoRGB('R', lpp->h, lpp->s, lpp->l); + g = CC_HSLtoRGB('G', lpp->h, lpp->s, lpp->l); + b = CC_HSLtoRGB('B', lpp->h, lpp->s, lpp->l); + lpp->lpcc->rgbResult = RGB(r, g, b); + CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); + CC_EditSetRGB(hDlg, lpp->lpcc->rgbResult); + CC_PaintCross(hDlg, lpp->h, lpp->s); + CC_PaintTriangle(hDlg, lpp->l); + } + } + break; + + case 0x2cf: + CC_SwitchToFullSize(hDlg, lpp->lpcc->rgbResult, &lpp->fullsize); + SetFocus( GetDlgItem(hDlg, 0x2bf)); + break; + + case 0x2c8: /* add colors ... column by column */ + cr = lpp->lpcc->lpCustColors; + cr[(lpp->nextuserdef % 2) * 8 + lpp->nextuserdef / 2] = lpp->lpcc->rgbResult; + if (++lpp->nextuserdef == 16) + lpp->nextuserdef = 0; + CC_PaintUserColorArray(hDlg, 2, 8, lpp->lpcc->lpCustColors); + break; + + case 0x2c9: /* resulting color */ + hdc = GetDC(hDlg); + lpp->lpcc->rgbResult = GetNearestColor(hdc, lpp->lpcc->rgbResult); + ReleaseDC(hDlg, hdc); + CC_EditSetRGB(hDlg, lpp->lpcc->rgbResult); + CC_PaintSelectedColor(hDlg, lpp->lpcc->rgbResult); + r = GetRValue(lpp->lpcc->rgbResult); + g = GetGValue(lpp->lpcc->rgbResult); + b = GetBValue(lpp->lpcc->rgbResult); + lpp->h = CC_RGBtoHSL('H', r, g, b); + lpp->s = CC_RGBtoHSL('S', r, g, b); + lpp->l = CC_RGBtoHSL('L', r, g, b); + CC_EditSetHSL(hDlg, lpp->h, lpp->s, lpp->l); + CC_PaintCross(hDlg, lpp->h, lpp->s); + CC_PaintTriangle(hDlg, lpp->l); + break; + + case 0x40e: /* Help! */ /* The Beatles, 1965 ;-) */ + i = RegisterWindowMessageA(HELPMSGSTRINGA); + if (lpp->lpcc16) + { + if (lpp->lpcc->hwndOwner) + SendMessageA(lpp->lpcc->hwndOwner, i, 0, (LPARAM)lpp->lpcc16); + if ( CC_HookCallChk(lpp->lpcc)) + CallWindowProc16( (WNDPROC16) lpp->lpcc16->lpfnHook, + HWND_16(hDlg), WM_COMMAND, psh15, + (LPARAM)lpp->lpcc16); + } + break; + + case IDOK : + cokmsg = RegisterWindowMessageA(COLOROKSTRINGA); + if (lpp->lpcc16) + { + if (lpp->lpcc->hwndOwner) + if (SendMessageA(lpp->lpcc->hwndOwner, cokmsg, 0, (LPARAM)lpp->lpcc16)) + break; /* do NOT close */ + } + if (lpp->lpcc16) + { + BYTE *ptr = MapSL(lpp->lpcc16->lpCustColors); + memcpy(ptr, lpp->lpcc->lpCustColors, sizeof(COLORREF)*16); + lpp->lpcc16->rgbResult = lpp->lpcc->rgbResult; + } + EndDialog(hDlg, 1) ; + return TRUE ; + + case IDCANCEL : + EndDialog(hDlg, 0) ; + return TRUE ; + + } + return FALSE; +} + +/*********************************************************************** + * ColorDlgProc (COMMDLG.8) + */ +BOOL16 CALLBACK ColorDlgProc16( HWND16 hDlg16, UINT16 message, + WPARAM16 wParam, LONG lParam ) +{ + BOOL16 res; + HWND hDlg = HWND_32(hDlg16); + + LCCPRIV lpp = (LCCPRIV)GetWindowLongPtrW(hDlg, DWLP_USER); + if (message != WM_INITDIALOG) + { + if (!lpp) + return FALSE; + res=0; + if (CC_HookCallChk(lpp->lpcc)) + res = CallWindowProc16( (WNDPROC16)lpp->lpcc16->lpfnHook, hDlg16, message, wParam, lParam); + if (res) + return res; + } + + /* FIXME: SetRGB message + if (message && message == msetrgb) + return HandleSetRGB(hDlg, lParam); + */ + + switch (message) + { + case WM_INITDIALOG: + return CC_WMInitDialog16(hDlg, wParam, lParam); + case WM_NCDESTROY: + DeleteDC(lpp->hdcMem); + DeleteObject(lpp->hbmMem); + HeapFree(GetProcessHeap(), 0, lpp->lpcc); + HeapFree(GetProcessHeap(), 0, lpp); + SetWindowLongPtrW(hDlg, DWLP_USER, 0); /* we don't need it anymore */ + break; + case WM_COMMAND: + if (CC_WMCommand16(hDlg, wParam, lParam, + HIWORD(lParam), HWND_32(LOWORD(lParam)))) + return TRUE; + break; + case WM_PAINT: + if (CC_WMPaint(hDlg, wParam, lParam)) + return TRUE; + break; + case WM_LBUTTONDBLCLK: + if (CC_MouseCheckResultWindow(hDlg,lParam)) + return TRUE; + break; + case WM_MOUSEMOVE: + if (CC_WMMouseMove(hDlg, lParam)) + return TRUE; + break; + case WM_LBUTTONUP: /* FIXME: ClipCursor off (if in color graph)*/ + if (CC_WMLButtonUp(hDlg, wParam, lParam)) + return TRUE; + break; + case WM_LBUTTONDOWN:/* FIXME: ClipCursor on (if in color graph)*/ + if (CC_WMLButtonDown(hDlg, wParam, lParam)) + return TRUE; + break; + } + return FALSE ; +} + +/*********************************************************************** + * ChooseColor (COMMDLG.5) + */ +BOOL16 WINAPI ChooseColor16( LPCHOOSECOLOR16 lpChCol ) +{ + HINSTANCE16 hInst; + HANDLE16 hDlgTmpl16 = 0, hResource16 = 0; + HGLOBAL16 hGlobal16 = 0; + BOOL16 bRet = FALSE; + LPCVOID template; + FARPROC16 ptr; + + TRACE("ChooseColor\n"); + if (!lpChCol) return FALSE; + + if (lpChCol->Flags & CC_ENABLETEMPLATEHANDLE) + hDlgTmpl16 = lpChCol->hInstance; + else if (lpChCol->Flags & CC_ENABLETEMPLATE) + { + HANDLE16 hResInfo; + if (!(hResInfo = FindResource16(lpChCol->hInstance, + MapSL(lpChCol->lpTemplateName), + (LPSTR)RT_DIALOG))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); + return FALSE; + } + if (!(hDlgTmpl16 = LoadResource16(lpChCol->hInstance, hResInfo))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + hResource16 = hDlgTmpl16; + } + else + { + HRSRC hResInfo; + HGLOBAL hDlgTmpl32; + LPCVOID template32; + DWORD size; + if (!(hResInfo = FindResourceA(COMDLG32_hInstance, "CHOOSE_COLOR", (LPSTR)RT_DIALOG))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); + return FALSE; + } + if (!(hDlgTmpl32 = LoadResource(COMDLG32_hInstance, hResInfo)) || + !(template32 = LockResource(hDlgTmpl32))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + size = SizeofResource(COMDLG32_hInstance, hResInfo); + hGlobal16 = GlobalAlloc16(0, size); + if (!hGlobal16) + { + COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE); + ERR("alloc failure for %ld bytes\n", size); + return FALSE; + } + template = GlobalLock16(hGlobal16); + if (!template) + { + COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE); + ERR("global lock failure for %x handle\n", hDlgTmpl16); + GlobalFree16(hGlobal16); + return FALSE; + } + ConvertDialog32To16((LPVOID)template32, size, (LPVOID)template); + hDlgTmpl16 = hGlobal16; + } + + ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 8); + hInst = GetWindowLongPtrA(HWND_32(lpChCol->hwndOwner), GWLP_HINSTANCE); + bRet = DialogBoxIndirectParam16(hInst, hDlgTmpl16, lpChCol->hwndOwner, + (DLGPROC16) ptr, (DWORD)lpChCol); + if (hResource16) FreeResource16(hDlgTmpl16); + if (hGlobal16) + { + GlobalUnlock16(hGlobal16); + GlobalFree16(hGlobal16); + } + return bRet; +} diff --git a/reactos/lib/comdlg32/filedlg.c b/reactos/lib/comdlg32/filedlg.c index 2d8650dfc3c..8d92e4505ff 100644 --- a/reactos/lib/comdlg32/filedlg.c +++ b/reactos/lib/comdlg32/filedlg.c @@ -1,3826 +1,3826 @@ -/* - * COMMDLG - File Open Dialogs Win95 look and feel - * - * Copyright 1999 Francois Boisvert - * Copyright 1999, 2000 Juergen Schmied - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * FIXME: The whole concept of handling unicode is badly broken. - * many hook-messages expect a pointer to a - * OPENFILENAMEA or W structure. With the current architecture - * we would have to convert the beast at every call to a hook. - * we have to find a better solution but it would likely cause - * a complete rewrite after which we should handle the - * OPENFILENAME structure without any converting (jsch). - * - * FIXME: any hook gets a OPENFILENAMEA structure - * - * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too - * - * FIXME: old style hook messages are not implemented (except FILEOKSTRING) - * - * FIXME: algorithm for selecting the initial directory is too simple - * - * FIXME: add to recent docs - * - * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT, - * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING, - * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN, - * OFN_NOTESTFILECREATE, OFN_USEMONIKERS - * - * FIXME: lCustData for lpfnHook (WM_INITDIALOG) - * - * - */ - -#include "config.h" -#include "wine/port.h" - -#include -#include -#include -#include -#include - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "winternl.h" -#include "winnls.h" -#include "wine/unicode.h" -#include "wingdi.h" -#include "winuser.h" -#include "commdlg.h" -#include "dlgs.h" -#include "cdlg.h" -#include "filedlg31.h" -#include "wine/debug.h" -#include "cderr.h" -#include "shellapi.h" -#include "shlguid.h" -#include "shlobj.h" -#include "filedlgbrowser.h" -#include "shlwapi.h" - -WINE_DEFAULT_DEBUG_CHANNEL(commdlg); - -#define UNIMPLEMENTED_FLAGS \ -(OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\ -OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\ -OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\ -OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/) - -#define IsHooked(fodInfos) \ - ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook) -/*********************************************************************** - * Data structure and global variables - */ -typedef struct SFolder -{ - int m_iImageIndex; /* Index of picture in image list */ - HIMAGELIST hImgList; - int m_iIndent; /* Indentation index */ - LPITEMIDLIST pidlItem; /* absolute pidl of the item */ - -} SFOLDER,*LPSFOLDER; - -typedef struct tagLookInInfo -{ - int iMaxIndentation; - UINT uSelectedItem; -} LookInInfos; - -typedef struct tagFD32_PRIVATE -{ - OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */ -} FD32_PRIVATE, *PFD32_PRIVATE; - - -/*********************************************************************** - * Defines and global variables - */ - -/* Draw item constant */ -#define ICONWIDTH 18 -#define XTEXTOFFSET 3 - -/* AddItem flags*/ -#define LISTEND -1 - -/* SearchItem methods */ -#define SEARCH_PIDL 1 -#define SEARCH_EXP 2 -#define ITEM_NOTFOUND -1 - -/* Undefined windows message sent by CreateViewObject*/ -#define WM_GETISHELLBROWSER WM_USER+7 - -/* NOTE - * Those macros exist in windowsx.h. However, you can't really use them since - * they rely on the UNICODE defines and can't be used inside Wine itself. - */ - -/* Combo box macros */ -#define CBAddString(hwnd,str) \ - SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str); -#define CBAddStringW(hwnd,str) \ - SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str); - -#define CBInsertString(hwnd,str,pos) \ - SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str); - -#define CBDeleteString(hwnd,pos) \ - SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0); - -#define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \ - SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr); - -#define CBGetItemDataPtr(hwnd,iItemId) \ - SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0) - -#define CBGetLBText(hwnd,iItemId,str) \ - SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str); - -#define CBGetCurSel(hwnd) \ - SendMessageA(hwnd,CB_GETCURSEL,0,0); - -#define CBSetCurSel(hwnd,pos) \ - SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0); - -#define CBGetCount(hwnd) \ - SendMessageA(hwnd,CB_GETCOUNT,0,0); -#define CBShowDropDown(hwnd,show) \ - SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0); -#define CBSetItemHeight(hwnd,index,height) \ - SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height); - -#define CBSetExtendedUI(hwnd,flag) \ - SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0) - -const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */ -const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */ - -/*********************************************************************** - * Prototypes - */ - -/* Internal functions used by the dialog */ -static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam); -static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam); -static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd); - BOOL FILEDLG95_OnOpen(HWND hwnd); -static LRESULT FILEDLG95_InitControls(HWND hwnd); -static void FILEDLG95_Clean(HWND hwnd); - -/* Functions used by the shell navigation */ -static LRESULT FILEDLG95_SHELL_Init(HWND hwnd); -static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd); -static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb); -static void FILEDLG95_SHELL_Clean(HWND hwnd); -static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd); - -/* Functions used by the EDIT box */ -static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator); - -/* Functions used by the filetype combo box */ -static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd); -static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode); -static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt); -static void FILEDLG95_FILETYPE_Clean(HWND hwnd); - -/* Functions used by the Look In combo box */ -static void FILEDLG95_LOOKIN_Init(HWND hwndCombo); -static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct); -static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode); -static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId); -static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod); -static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl); -static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd); - int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl); -static void FILEDLG95_LOOKIN_Clean(HWND hwnd); - -/* Miscellaneous tool functions */ -static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName); -IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs); -LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl); -LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName); - -/* Shell memory allocation */ -static void *MemAlloc(UINT size); -static void MemFree(void *mem); - -INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); -void SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode); -static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); -static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed); -static BOOL BrowseSelectedFolder(HWND hwnd); - -/*********************************************************************** - * GetFileName95 - * - * Creates an Open common dialog box that lets the user select - * the drive, directory, and the name of a file or set of files to open. - * - * IN : The FileOpenDlgInfos structure associated with the dialog - * OUT : TRUE on success - * FALSE on cancel, error, close or filename-does-not-fit-in-buffer. - */ -static BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos) -{ - - LRESULT lRes; - LPCVOID template; - HRSRC hRes; - HANDLE hDlgTmpl = 0; - - /* test for missing functionality */ - if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS) - { - FIXME("Flags 0x%08lx not yet implemented\n", - fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS); - } - - /* Create the dialog from a template */ - - if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),(LPSTR)RT_DIALOG))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); - return FALSE; - } - if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) || - !(template = LockResource( hDlgTmpl ))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - - /* old style hook messages */ - if (IsHooked(fodInfos)) - { - fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA); - fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA); - fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA); - fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA); - } - - lRes = DialogBoxIndirectParamA(COMDLG32_hInstance, - (LPDLGTEMPLATEA) template, - fodInfos->ofnInfos->hwndOwner, - FileOpenDlgProc95, - (LPARAM) fodInfos); - - /* Unable to create the dialog */ - if( lRes == -1) - return FALSE; - - return lRes; -} - -/*********************************************************************** - * GetFileDialog95A - * - * Call GetFileName95 with this structure and clean the memory. - * - * IN : The OPENFILENAMEA initialisation structure passed to - * GetOpenFileNameA win api function (see filedlg.c) - */ -BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType) -{ - BOOL ret; - FileOpenDlgInfos fodInfos; - LPSTR lpstrSavDir = NULL; - LPWSTR title = NULL; - LPWSTR defext = NULL; - LPWSTR filter = NULL; - LPWSTR customfilter = NULL; - - /* Initialize FileOpenDlgInfos structure */ - ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos)); - - /* Pass in the original ofn */ - fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn; - - /* save current directory */ - if (ofn->Flags & OFN_NOCHANGEDIR) - { - lpstrSavDir = MemAlloc(MAX_PATH); - GetCurrentDirectoryA(MAX_PATH, lpstrSavDir); - } - - fodInfos.unicode = FALSE; - - /* convert all the input strings to unicode */ - if(ofn->lpstrInitialDir) - { - DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 ); - fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR)); - MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len); - } - else - fodInfos.initdir = NULL; - - if(ofn->lpstrFile) - { - fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR)); - MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile); - } - else - fodInfos.filename = NULL; - - if(ofn->lpstrDefExt) - { - DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 ); - defext = MemAlloc((len+1)*sizeof(WCHAR)); - MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len); - } - fodInfos.defext = defext; - - if(ofn->lpstrTitle) - { - DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 ); - title = MemAlloc((len+1)*sizeof(WCHAR)); - MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len); - } - fodInfos.title = title; - - if (ofn->lpstrFilter) - { - LPCSTR s; - int n, len; - - /* filter is a list... title\0ext\0......\0\0 */ - s = ofn->lpstrFilter; - while (*s) s = s+strlen(s)+1; - s++; - n = s - ofn->lpstrFilter; - len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 ); - filter = MemAlloc(len*sizeof(WCHAR)); - MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len ); - } - fodInfos.filter = filter; - - /* convert lpstrCustomFilter */ - if (ofn->lpstrCustomFilter) - { - LPCSTR s; - int n, len; - - /* customfilter contains a pair of strings... title\0ext\0 */ - s = ofn->lpstrCustomFilter; - if (*s) s = s+strlen(s)+1; - if (*s) s = s+strlen(s)+1; - n = s - ofn->lpstrCustomFilter; - len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 ); - customfilter = MemAlloc(len*sizeof(WCHAR)); - MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len ); - } - fodInfos.customfilter = customfilter; - - /* Initialize the dialog property */ - fodInfos.DlgInfos.dwDlgProp = 0; - fodInfos.DlgInfos.hwndCustomDlg = NULL; - - switch(iDlgType) - { - case OPEN_DIALOG : - ret = GetFileName95(&fodInfos); - break; - case SAVE_DIALOG : - fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG; - ret = GetFileName95(&fodInfos); - break; - default : - ret = 0; - } - - if (lpstrSavDir) - { - SetCurrentDirectoryA(lpstrSavDir); - MemFree(lpstrSavDir); - } - - if(title) - MemFree(title); - if(defext) - MemFree(defext); - if(filter) - MemFree(filter); - if(customfilter) - MemFree(customfilter); - if(fodInfos.initdir) - MemFree(fodInfos.initdir); - - if(fodInfos.filename) - MemFree(fodInfos.filename); - - TRACE("selected file: %s\n",ofn->lpstrFile); - - return ret; -} - -/*********************************************************************** - * GetFileDialog95W - * - * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure. - * Call GetFileName95 with this structure and clean the memory. - * - */ -BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType) -{ - BOOL ret; - FileOpenDlgInfos fodInfos; - LPWSTR lpstrSavDir = NULL; - - /* Initialize FileOpenDlgInfos structure */ - ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos)); - - /* Pass in the original ofn */ - fodInfos.ofnInfos = ofn; - - fodInfos.title = ofn->lpstrTitle; - fodInfos.defext = ofn->lpstrDefExt; - fodInfos.filter = ofn->lpstrFilter; - fodInfos.customfilter = ofn->lpstrCustomFilter; - - /* convert string arguments, save others */ - if(ofn->lpstrFile) - { - fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR)); - lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile); - } - else - fodInfos.filename = NULL; - - if(ofn->lpstrInitialDir) - { - /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */ - DWORD len = strlenW(ofn->lpstrInitialDir)+1; - fodInfos.initdir = MemAlloc(len*sizeof(WCHAR)); - memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR)); - } - else - fodInfos.initdir = NULL; - - /* save current directory */ - if (ofn->Flags & OFN_NOCHANGEDIR) - { - lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR)); - GetCurrentDirectoryW(MAX_PATH, lpstrSavDir); - } - - fodInfos.unicode = TRUE; - - switch(iDlgType) - { - case OPEN_DIALOG : - ret = GetFileName95(&fodInfos); - break; - case SAVE_DIALOG : - fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG; - ret = GetFileName95(&fodInfos); - break; - default : - ret = 0; - } - - if (lpstrSavDir) - { - SetCurrentDirectoryW(lpstrSavDir); - MemFree(lpstrSavDir); - } - - /* restore saved IN arguments and convert OUT arguments back */ - MemFree(fodInfos.filename); - MemFree(fodInfos.initdir); - return ret; -} - -/****************************************************************************** - * COMDLG32_GetDisplayNameOf [internal] - * - * Helper function to get the display name for a pidl. - */ -static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) { - LPSHELLFOLDER psfDesktop; - STRRET strret; - - if (FAILED(SHGetDesktopFolder(&psfDesktop))) - return FALSE; - - if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) { - IShellFolder_Release(psfDesktop); - return FALSE; - } - - IShellFolder_Release(psfDesktop); - return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH)); -} - -/*********************************************************************** - * ArrangeCtrlPositions [internal] - * - * NOTE: Do not change anything here without a lot of testing. - */ -static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help) -{ - HWND hwndChild, hwndStc32; - RECT rectParent, rectChild, rectStc32; - INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0; - - /* Take into account if open as read only checkbox and help button - * are hidden - */ - if (hide_help) - { - RECT rectHelp, rectCancel; - GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp); - GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel); - /* subtract the height of the help button plus the space between - * the help button and the cancel button to the height of the dialog - */ - help_fixup = rectHelp.bottom - rectCancel.bottom; - } - - /* - There are two possibilities to add components to the default file dialog box. - - By default, all the new components are added below the standard dialog box (the else case). - - However, if there is a static text component with the stc32 id, a special case happens. - The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box - in the window and the cx and cy indicate how to size the window. - Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left - of the standard file dialog box. If they are above the stc32 component, it is placed above and so on.... - - */ - - GetClientRect(hwndParentDlg, &rectParent); - - /* when arranging controls we have to use fixed parent size */ - rectParent.bottom -= help_fixup; - - hwndStc32 = GetDlgItem(hwndChildDlg, stc32); - if (hwndStc32) - { - GetWindowRect(hwndStc32, &rectStc32); - MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2); - - /* set the size of the stc32 control according to the size of - * client area of the parent dialog - */ - SetWindowPos(hwndStc32, 0, - 0, 0, - rectParent.right, rectParent.bottom, - SWP_NOMOVE | SWP_NOZORDER); - } - else - SetRectEmpty(&rectStc32); - - /* this part moves controls of the child dialog */ - hwndChild = GetWindow(hwndChildDlg, GW_CHILD); - while (hwndChild) - { - if (hwndChild != hwndStc32) - { - GetWindowRect(hwndChild, &rectChild); - MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2); - - /* move only if stc32 exist */ - if (hwndStc32 && rectChild.left > rectStc32.right) - { - LONG old_left = rectChild.left; - - /* move to the right of visible controls of the parent dialog */ - rectChild.left += rectParent.right; - rectChild.left -= rectStc32.right; - - child_width_fixup = rectChild.left - old_left; - } - /* move even if stc32 doesn't exist */ - if (rectChild.top >= rectStc32.bottom) - { - LONG old_top = rectChild.top; - - /* move below visible controls of the parent dialog */ - rectChild.top += rectParent.bottom; - rectChild.top -= rectStc32.bottom - rectStc32.top; - - child_height_fixup = rectChild.top - old_top; - } - - SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top, - 0, 0, SWP_NOSIZE | SWP_NOZORDER); - } - hwndChild = GetWindow(hwndChild, GW_HWNDNEXT); - } - - /* this part moves controls of the parent dialog */ - hwndChild = GetWindow(hwndParentDlg, GW_CHILD); - while (hwndChild) - { - if (hwndChild != hwndChildDlg) - { - GetWindowRect(hwndChild, &rectChild); - MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2); - - /* left,top of stc32 marks the position of controls - * from the parent dialog - */ - rectChild.left += rectStc32.left; - rectChild.top += rectStc32.top; - - SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top, - 0, 0, SWP_NOSIZE | SWP_NOZORDER); - } - hwndChild = GetWindow(hwndChild, GW_HWNDNEXT); - } - - /* calculate the size of the resulting dialog */ - - /* here we have to use original parent size */ - GetClientRect(hwndParentDlg, &rectParent); - GetClientRect(hwndChildDlg, &rectChild); - - if (hwndStc32) - { - rectChild.right += child_width_fixup; - rectChild.bottom += child_height_fixup; - - if (rectParent.right > rectChild.right) - { - rectParent.right += rectChild.right; - rectParent.right -= rectStc32.right - rectStc32.left; - } - else - { - rectParent.right = rectChild.right; - } - - if (rectParent.bottom > rectChild.bottom) - { - rectParent.bottom += rectChild.bottom; - rectParent.bottom -= rectStc32.bottom - rectStc32.top; - } - else - { - /* child dialog is higher, unconditionally set new dialog - * height to its size (help_fixup will be subtracted below) - */ - rectParent.bottom = rectChild.bottom + help_fixup; - } - } - else - { - rectParent.bottom += rectChild.bottom; - } - - /* finally use fixed parent size */ - rectParent.bottom -= help_fixup; - - /* save the size of the parent's client area */ - rectChild.right = rectParent.right; - rectChild.bottom = rectParent.bottom; - - /* set the size of the parent dialog */ - AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE), - FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE)); - SetWindowPos(hwndParentDlg, 0, - 0, 0, - rectParent.right - rectParent.left, - rectParent.bottom - rectParent.top, - SWP_NOMOVE | SWP_NOZORDER); - - /* set the size of the child dialog */ - SetWindowPos(hwndChildDlg, HWND_BOTTOM, - 0, 0, rectChild.right, rectChild.bottom, SWP_NOACTIVATE); -} - -INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch(uMsg) { - case WM_INITDIALOG: - return TRUE; - } - return FALSE; -} - -HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd) -{ - LPCVOID template; - HRSRC hRes; - HANDLE hDlgTmpl = 0; - HWND hChildDlg = 0; - - TRACE("\n"); - - /* - * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME - * structure's hInstance parameter is not a HINSTANCE, but - * instead a pointer to a template resource to use. - */ - if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)) - { - HINSTANCE hinst; - if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE) - { - hinst = 0; - if( !(template = LockResource( fodInfos->ofnInfos->hInstance))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return NULL; - } - } - else - { - hinst = fodInfos->ofnInfos->hInstance; - if(fodInfos->unicode) - { - LPOPENFILENAMEW ofn = fodInfos->ofnInfos; - hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG); - } - else - { - LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos; - hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG); - } - if (!hRes) - { - COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); - return NULL; - } - if (!(hDlgTmpl = LoadResource( hinst, hRes )) || - !(template = LockResource( hDlgTmpl ))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return NULL; - } - } - hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, template, hwnd, - IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate, - (LPARAM)fodInfos->ofnInfos); - if(hChildDlg) - { - ShowWindow(hChildDlg,SW_SHOW); - return hChildDlg; - } - } - else if( IsHooked(fodInfos)) - { - RECT rectHwnd; - struct { - DLGTEMPLATE tmplate; - WORD menu,class,title; - } temp; - GetClientRect(hwnd,&rectHwnd); - temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK; - temp.tmplate.dwExtendedStyle = 0; - temp.tmplate.cdit = 0; - temp.tmplate.x = 0; - temp.tmplate.y = 0; - temp.tmplate.cx = 0; - temp.tmplate.cy = 0; - temp.menu = temp.class = temp.title = 0; - - hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate, - hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos); - - return hChildDlg; - } - return NULL; -} - -/*********************************************************************** -* SendCustomDlgNotificationMessage -* -* Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog -*/ - -void SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode) -{ - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr); - - TRACE("%p 0x%04x\n",hwndParentDlg, uCode); - - if(!fodInfos) return; - - if(fodInfos->DlgInfos.hwndCustomDlg) - { - TRACE("CALL NOTIFY for %x\n", uCode); - if(fodInfos->unicode) - { - OFNOTIFYW ofnNotify; - ofnNotify.hdr.hwndFrom=hwndParentDlg; - ofnNotify.hdr.idFrom=0; - ofnNotify.hdr.code = uCode; - ofnNotify.lpOFN = fodInfos->ofnInfos; - ofnNotify.pszFile = NULL; - SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify); - } - else - { - OFNOTIFYA ofnNotify; - ofnNotify.hdr.hwndFrom=hwndParentDlg; - ofnNotify.hdr.idFrom=0; - ofnNotify.hdr.code = uCode; - ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos; - ofnNotify.pszFile = NULL; - SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify); - } - TRACE("RET NOTIFY\n"); - } -} - -static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer) -{ - INT_PTR sizeUsed = 0, n, total; - LPWSTR lpstrFileList = NULL; - WCHAR lpstrCurrentDir[MAX_PATH]; - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); - - TRACE("CDM_GETFILEPATH:\n"); - - if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) ) - return -1; - - /* get path and filenames */ - COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrCurrentDir); - n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' '); - - TRACE("path >%s< filespec >%s< %d files\n", - debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n); - - if( fodInfos->unicode ) - { - LPWSTR bufW = buffer; - total = strlenW(lpstrCurrentDir) + 1 + sizeUsed; - - /* Prepend the current path */ - n = strlenW(lpstrCurrentDir) + 1; - memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR)); - if(n %s\n",debugstr_wn(bufW, total)); - } - else - { - LPSTR bufA = buffer; - total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1, - NULL, 0, NULL, NULL); - total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed, - NULL, 0, NULL, NULL); - - /* Prepend the current path */ - n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1, - bufA, size, NULL, NULL); - - if(n %s\n",debugstr_an(bufA, total)); - } - MemFree(lpstrFileList); - - return total; -} - -static INT_PTR FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer) -{ - INT_PTR sizeUsed = 0; - LPWSTR lpstrFileList = NULL; - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); - - TRACE("CDM_GETSPEC:\n"); - - FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' '); - if( fodInfos->unicode ) - { - LPWSTR bufW = buffer; - memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed ); - } - else - { - LPSTR bufA = buffer; - sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed, - NULL, 0, NULL, NULL); - WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed, - bufA, size, NULL, NULL); - } - MemFree(lpstrFileList); - - return sizeUsed; -} - -/*********************************************************************** -* FILEDLG95_HandleCustomDialogMessages -* -* Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages -*/ -static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); - WCHAR lpstrPath[MAX_PATH]; - INT_PTR retval; - - if(!fodInfos) return FALSE; - - switch(uMsg) - { - case CDM_GETFILEPATH: - retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam); - break; - - case CDM_GETFOLDERPATH: - TRACE("CDM_GETFOLDERPATH:\n"); - COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath); - if (lParam) - { - if (fodInfos->unicode) - lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam); - else - WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1, - (LPSTR)lParam, (int)wParam, NULL, NULL); - } - retval = strlenW(lpstrPath); - break; - - case CDM_GETSPEC: - retval = FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam); - break; - - case CDM_SETCONTROLTEXT: - TRACE("CDM_SETCONTROLTEXT:\n"); - if ( lParam ) - { - if( fodInfos->unicode ) - SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam ); - else - SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam ); - } - retval = TRUE; - break; - - case CDM_HIDECONTROL: - case CDM_SETDEFEXT: - FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n"); - retval = -1; - break; - - default: - return FALSE; - } - SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval); - return TRUE; -} - -/*********************************************************************** - * FileOpenDlgProc95 - * - * File open dialog procedure - */ -INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ -#if 0 - TRACE("0x%04x 0x%04x\n", hwnd, uMsg); -#endif - - switch(uMsg) - { - case WM_INITDIALOG: - { - FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam; - - /* Adds the FileOpenDlgInfos in the property list of the dialog - so it will be easily accessible through a GetPropA(...) */ - SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos); - - fodInfos->DlgInfos.hwndCustomDlg = - CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd); - - FILEDLG95_InitControls(hwnd); - - if (fodInfos->DlgInfos.hwndCustomDlg) - ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd, - (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY); - - FILEDLG95_FillControls(hwnd, wParam, lParam); - - SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE); - SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE); - SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE); - return 0; - } - case WM_COMMAND: - return FILEDLG95_OnWMCommand(hwnd, wParam, lParam); - case WM_DRAWITEM: - { - switch(((LPDRAWITEMSTRUCT)lParam)->CtlID) - { - case IDC_LOOKIN: - FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam); - return TRUE; - } - } - return FALSE; - - case WM_GETISHELLBROWSER: - return FILEDLG95_OnWMGetIShellBrowser(hwnd); - - case WM_DESTROY: - RemovePropA(hwnd, FileOpenDlgInfosStr); - return FALSE; - - case WM_NOTIFY: - { - LPNMHDR lpnmh = (LPNMHDR)lParam; - UINT stringId = -1; - - /* set up the button tooltips strings */ - if(TTN_GETDISPINFOA == lpnmh->code ) - { - LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam; - switch(lpnmh->idFrom ) - { - /* Up folder button */ - case FCIDM_TB_UPFOLDER: - stringId = IDS_UPFOLDER; - break; - /* New folder button */ - case FCIDM_TB_NEWFOLDER: - stringId = IDS_NEWFOLDER; - break; - /* List option button */ - case FCIDM_TB_SMALLICON: - stringId = IDS_LISTVIEW; - break; - /* Details option button */ - case FCIDM_TB_REPORTVIEW: - stringId = IDS_REPORTVIEW; - break; - /* Desktop button */ - case FCIDM_TB_DESKTOP: - stringId = IDS_TODESKTOP; - break; - default: - stringId = 0; - } - lpdi->hinst = COMDLG32_hInstance; - lpdi->lpszText = (LPSTR) stringId; - } - return FALSE; - } - default : - if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST) - return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam); - return FALSE; - } -} - -/*********************************************************************** - * FILEDLG95_InitControls - * - * WM_INITDIALOG message handler (before hook notification) - */ -static LRESULT FILEDLG95_InitControls(HWND hwnd) -{ - int win2000plus = 0; - int win98plus = 0; - int handledPath = FALSE; - OSVERSIONINFOA osVi; - static const WCHAR szwSlash[] = { '\\', 0 }; - static const WCHAR szwStar[] = { '*',0 }; - - TBBUTTON tbb[] = - { - {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 }, - {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 }, - {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 }, - {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 }, - {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 }, - {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 }, - {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 }, - {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 }, - {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 }, - }; - TBADDBITMAP tba[2]; - RECT rectTB; - RECT rectlook; - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); - - tba[0].hInst = HINST_COMMCTRL; - tba[0].nID = IDB_VIEW_SMALL_COLOR; - tba[1].hInst = COMDLG32_hInstance; - tba[1].nID = 800; - - TRACE("%p\n", fodInfos); - - /* Get windows version emulating */ - osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); - GetVersionExA(&osVi); - if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { - win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0))); - } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) { - win2000plus = (osVi.dwMajorVersion > 4); - if (win2000plus) win98plus = TRUE; - } - TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus); - - /* Get the hwnd of the controls */ - fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME); - fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE); - fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN); - - GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook); - MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2); - - /* construct the toolbar */ - GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB); - MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2); - - rectTB.right = rectlook.right + rectTB.right - rectTB.left; - rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top; - rectTB.left = rectlook.right; - rectTB.top = rectlook.top-1; - - fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL, - WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE, - rectTB.left, rectTB.top, - rectTB.right - rectTB.left, rectTB.bottom - rectTB.top, - hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL); - - SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0); - -/* FIXME: use TB_LOADIMAGES when implemented */ -/* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/ - SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]); - SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]); - - SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb); - SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0); - - /* Set the window text with the text specified in the OPENFILENAME structure */ - if(fodInfos->title) - { - SetWindowTextW(hwnd,fodInfos->title); - } - else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) - { - WCHAR buf[16]; - LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR)); - SetWindowTextW(hwnd, buf); - } - - /* Initialise the file name edit control */ - handledPath = FALSE; - TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir)); - - if(fodInfos->filename) - { - /* 1. If win2000 or higher and filename contains a path, use it - in preference over the lpstrInitialDir */ - if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) { - WCHAR tmpBuf[MAX_PATH]; - WCHAR *nameBit; - DWORD result; - - result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit); - if (result) { - - /* nameBit is always shorter than the original filename */ - strcpyW(fodInfos->filename,nameBit); - - *nameBit = 0x00; - if (fodInfos->initdir == NULL) - MemFree(fodInfos->initdir); - fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR)); - strcpyW(fodInfos->initdir, tmpBuf); - handledPath = TRUE; - TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n", - debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir)); - } - SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename); - - } else { - SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename); - } - } - - /* 2. (All platforms) If initdir is not null, then use it */ - if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) && - (*fodInfos->initdir!=0x00)) - { - /* Work out the proper path as supplied one might be relative */ - /* (Here because supplying '.' as dir browses to My Computer) */ - if (handledPath==FALSE) { - WCHAR tmpBuf[MAX_PATH]; - WCHAR tmpBuf2[MAX_PATH]; - WCHAR *nameBit; - DWORD result; - - strcpyW(tmpBuf, fodInfos->initdir); - if( PathFileExistsW(tmpBuf) ) { - /* initdir does not have to be a directory. If a file is - * specified, the dir part is taken */ - if( PathIsDirectoryW(tmpBuf)) { - if (tmpBuf[strlenW(tmpBuf)-1] != '\\') { - strcatW(tmpBuf, szwSlash); - } - strcatW(tmpBuf, szwStar); - } - result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit); - if (result) { - *nameBit = 0x00; - if (fodInfos->initdir) - MemFree(fodInfos->initdir); - fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR)); - strcpyW(fodInfos->initdir, tmpBuf2); - handledPath = TRUE; - TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir)); - } - } - else if (fodInfos->initdir) - { - MemFree(fodInfos->initdir); - fodInfos->initdir = NULL; - TRACE("Value in InitDir is not an existing path, changed to (nil)\n"); - } - } - } - - if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) || - (*fodInfos->initdir==0x00))) - { - /* 3. All except w2k+: if filename contains a path use it */ - if (!win2000plus && fodInfos->filename && - *fodInfos->filename && - strpbrkW(fodInfos->filename, szwSlash)) { - WCHAR tmpBuf[MAX_PATH]; - WCHAR *nameBit; - DWORD result; - - result = GetFullPathNameW(fodInfos->filename, MAX_PATH, - tmpBuf, &nameBit); - if (result) { - int len; - - /* nameBit is always shorter than the original filename */ - strcpyW(fodInfos->filename, nameBit); - *nameBit = 0x00; - - len = strlenW(tmpBuf); - if(fodInfos->initdir) - MemFree(fodInfos->initdir); - fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR)); - strcpyW(fodInfos->initdir, tmpBuf); - - handledPath = TRUE; - TRACE("Value in Filename includes path, overriding initdir: %s, %s\n", - debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir)); - } - SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename); - } - - /* 4. win98+ and win2000+ if any files of specified filter types in - current directory, use it */ - if ( win98plus && handledPath == FALSE && - fodInfos->filter && *fodInfos->filter) { - - BOOL searchMore = TRUE; - LPCWSTR lpstrPos = fodInfos->filter; - WIN32_FIND_DATAW FindFileData; - HANDLE hFind; - - while (searchMore) - { - /* filter is a list... title\0ext\0......\0\0 */ - - /* Skip the title */ - if(! *lpstrPos) break; /* end */ - lpstrPos += strlenW(lpstrPos) + 1; - - /* See if any files exist in the current dir with this extension */ - if(! *lpstrPos) break; /* end */ - - hFind = FindFirstFileW(lpstrPos, &FindFileData); - - if (hFind == INVALID_HANDLE_VALUE) { - /* None found - continue search */ - lpstrPos += strlenW(lpstrPos) + 1; - - } else { - searchMore = FALSE; - - if(fodInfos->initdir) - MemFree(fodInfos->initdir); - fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR)); - GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir); - - handledPath = TRUE; - TRACE("No initial dir specified, but files of type %s found in current, so using it\n", - debugstr_w(lpstrPos)); - break; - } - } - } - - /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */ - - /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */ - if (handledPath == FALSE && (win2000plus || win98plus)) { - fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR)); - - if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))) - { - if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))) - { - /* last fallback */ - GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir); - TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir)); - } else { - TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir)); - } - } else { - TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir)); - } - handledPath = TRUE; - } else if (handledPath==FALSE) { - fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR)); - GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir); - handledPath = TRUE; - TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir)); - } - } - SetFocus(GetDlgItem(hwnd, IDC_FILENAME)); - TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir)); - - /* Must the open as read only check box be checked ?*/ - if(fodInfos->ofnInfos->Flags & OFN_READONLY) - { - SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0); - } - - /* Must the open as read only check box be hidden? */ - if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) - { - ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE); - EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE); - } - - /* Must the help button be hidden? */ - if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP)) - { - ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE); - EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE); - } - - /* Resize the height, if open as read only checkbox ad help button - are hidden and we are not using a custom template nor a customDialog - */ - if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) && - (!(fodInfos->ofnInfos->Flags & - (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) && - (!fodInfos->DlgInfos.hwndCustomDlg )) - { - RECT rectDlg, rectHelp, rectCancel; - GetWindowRect(hwnd, &rectDlg); - GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp); - GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel); - /* subtract the height of the help button plus the space between - the help button and the cancel button to the height of the dialog */ - SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left, - (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom), - SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER); - } - /* change Open to Save */ - if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) - { - WCHAR buf[16]; - LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR)); - SetDlgItemTextW(hwnd, IDOK, buf); - LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR)); - SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf); - } - return 0; -} - -/*********************************************************************** - * FILEDLG95_FillControls - * - * WM_INITDIALOG message handler (after hook notification) - */ -static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - LPITEMIDLIST pidlItemId = NULL; - - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam; - - TRACE("dir=%s file=%s\n", - debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename)); - - /* Get the initial directory pidl */ - - if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir))) - { - WCHAR path[MAX_PATH]; - - GetCurrentDirectoryW(MAX_PATH,path); - pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path); - } - - /* Initialise shell objects */ - FILEDLG95_SHELL_Init(hwnd); - - /* Initialize the Look In combo box */ - FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB); - - /* Initialize the filter combo box */ - FILEDLG95_FILETYPE_Init(hwnd); - - /* Browse to the initial directory */ - IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE); - - /* Free pidlItem memory */ - COMDLG32_SHFree(pidlItemId); - - return TRUE; -} -/*********************************************************************** - * FILEDLG95_Clean - * - * Regroups all the cleaning functions of the filedlg - */ -void FILEDLG95_Clean(HWND hwnd) -{ - FILEDLG95_FILETYPE_Clean(hwnd); - FILEDLG95_LOOKIN_Clean(hwnd); - FILEDLG95_SHELL_Clean(hwnd); -} -/*********************************************************************** - * FILEDLG95_OnWMCommand - * - * WM_COMMAND message handler - */ -static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - WORD wNotifyCode = HIWORD(wParam); /* notification code */ - WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */ - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); - - switch(wID) - { - /* OK button */ - case IDOK: - FILEDLG95_OnOpen(hwnd); - break; - /* Cancel button */ - case IDCANCEL: - FILEDLG95_Clean(hwnd); - EndDialog(hwnd, FALSE); - break; - /* Filetype combo box */ - case IDC_FILETYPE: - FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode); - break; - /* LookIn combo box */ - case IDC_LOOKIN: - FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode); - break; - - /* --- toolbar --- */ - /* Up folder button */ - case FCIDM_TB_UPFOLDER: - FILEDLG95_SHELL_UpFolder(hwnd); - break; - /* New folder button */ - case FCIDM_TB_NEWFOLDER: - FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA); - break; - /* List option button */ - case FCIDM_TB_SMALLICON: - FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA); - break; - /* Details option button */ - case FCIDM_TB_REPORTVIEW: - FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA); - break; - /* Details option button */ - case FCIDM_TB_DESKTOP: - FILEDLG95_SHELL_BrowseToDesktop(hwnd); - break; - - case IDC_FILENAME: - break; - - } - /* Do not use the listview selection anymore */ - fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW; - return 0; -} - -/*********************************************************************** - * FILEDLG95_OnWMGetIShellBrowser - * - * WM_GETISHELLBROWSER message handler - */ -static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd) -{ - - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); - - TRACE("\n"); - - SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser); - - return TRUE; -} - - -/*********************************************************************** - * FILEDLG95_SendFileOK - * - * Sends the CDN_FILEOK notification if required - * - * RETURNS - * TRUE if the dialog should close - * FALSE if the dialog should not be closed - */ -static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos ) -{ - /* ask the hook if we can close */ - if(IsHooked(fodInfos)) - { - TRACE("---\n"); - /* First send CDN_FILEOK as MSDN doc says */ - SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK); - if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT)) - { - TRACE("canceled\n"); - return FALSE; - } - - /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */ - SendMessageW(fodInfos->DlgInfos.hwndCustomDlg, - fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos); - if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT)) - { - TRACE("canceled\n"); - return FALSE; - } - } - return TRUE; -} - -/*********************************************************************** - * FILEDLG95_OnOpenMultipleFiles - * - * Handles the opening of multiple files. - * - * FIXME - * check destination buffer size - */ -BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed) -{ - WCHAR lpstrPathSpec[MAX_PATH] = {0}; - UINT nCount, nSizePath; - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); - - TRACE("\n"); - - if(fodInfos->unicode) - { - LPOPENFILENAMEW ofn = fodInfos->ofnInfos; - ofn->lpstrFile[0] = '\0'; - } - else - { - LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos; - ofn->lpstrFile[0] = '\0'; - } - - COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec ); - - if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) && - ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) && - ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) ) - { - LPWSTR lpstrTemp = lpstrFileList; - - for ( nCount = 0; nCount < nFileCount; nCount++ ) - { - LPITEMIDLIST pidl; - - pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp); - if (!pidl) - { - WCHAR lpstrNotFound[100]; - WCHAR lpstrMsg[100]; - WCHAR tmp[400]; - static const WCHAR nl[] = {'\n',0}; - - LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100); - LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100); - - strcpyW(tmp, lpstrTemp); - strcatW(tmp, nl); - strcatW(tmp, lpstrNotFound); - strcatW(tmp, nl); - strcatW(tmp, lpstrMsg); - - MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION); - return FALSE; - } - - /* move to the next file in the list of files */ - lpstrTemp += strlenW(lpstrTemp) + 1; - COMDLG32_SHFree(pidl); - } - } - - nSizePath = strlenW(lpstrPathSpec) + 1; - if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) ) - { - /* For "oldstyle" dialog the components have to - be separated by blanks (not '\0'!) and short - filenames have to be used! */ - FIXME("Components have to be separated by blanks\n"); - } - if(fodInfos->unicode) - { - LPOPENFILENAMEW ofn = fodInfos->ofnInfos; - strcpyW( ofn->lpstrFile, lpstrPathSpec); - memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) ); - } - else - { - LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos; - - if (ofn->lpstrFile != NULL) - { - nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1, - ofn->lpstrFile, ofn->nMaxFile, NULL, NULL); - if (ofn->nMaxFile > nSizePath) - { - WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed, - ofn->lpstrFile + nSizePath, - ofn->nMaxFile - nSizePath, NULL, NULL); - } - } - } - - fodInfos->ofnInfos->nFileOffset = nSizePath; - fodInfos->ofnInfos->nFileExtension = 0; - - if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) ) - return FALSE; - - /* clean and exit */ - FILEDLG95_Clean(hwnd); - return EndDialog(hwnd,TRUE); -} - -/*********************************************************************** - * FILEDLG95_OnOpen - * - * Ok button WM_COMMAND message handler - * - * If the function succeeds, the return value is nonzero. - */ -#define ONOPEN_OPEN 1 -#define ONOPEN_SEARCH 2 -static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText) -{ - WCHAR strMsgTitle[MAX_PATH]; - WCHAR strMsgText [MAX_PATH]; - if (idCaption) - LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR)); - else - strMsgTitle[0] = '\0'; - LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR)); - MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND); -} - -BOOL FILEDLG95_OnOpen(HWND hwnd) -{ - LPWSTR lpstrFileList; - UINT nFileCount = 0; - UINT sizeUsed = 0; - BOOL ret = TRUE; - WCHAR lpstrPathAndFile[MAX_PATH]; - WCHAR lpstrTemp[MAX_PATH]; - LPSHELLFOLDER lpsf = NULL; - int nOpenAction; - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); - - TRACE("hwnd=%p\n", hwnd); - - if(BrowseSelectedFolder(hwnd)) - return FALSE; - - /* get the files from the edit control */ - nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0'); - - /* try if the user selected a folder in the shellview */ - if(nFileCount == 0) - return FALSE; - - if(nFileCount > 1) - { - ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed); - goto ret; - } - - TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList)); - -/* - Step 1: Build a complete path name from the current folder and - the filename or path in the edit box. - Special cases: - - the path in the edit box is a root path - (with or without drive letter) - - the edit box contains ".." (or a path with ".." in it) -*/ - - /* Get the current directory name */ - if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile)) - { - /* last fallback */ - GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile); - } - PathAddBackslashW(lpstrPathAndFile); - - TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile)); - - /* if the user specifyed a fully qualified path use it */ - if(PathIsRelativeW(lpstrFileList)) - { - strcatW(lpstrPathAndFile, lpstrFileList); - } - else - { - /* does the path have a drive letter? */ - if (PathGetDriveNumberW(lpstrFileList) == -1) - strcpyW(lpstrPathAndFile+2, lpstrFileList); - else - strcpyW(lpstrPathAndFile, lpstrFileList); - } - - /* resolve "." and ".." */ - PathCanonicalizeW(lpstrTemp, lpstrPathAndFile ); - strcpyW(lpstrPathAndFile, lpstrTemp); - TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile)); - - MemFree(lpstrFileList); - -/* - Step 2: here we have a cleaned up path - - We have to parse the path step by step to see if we have to browse - to a folder if the path points to a directory or the last - valid element is a directory. - - valid variables: - lpstrPathAndFile: cleaned up path - */ - - nOpenAction = ONOPEN_OPEN; - - /* don't apply any checks with OFN_NOVALIDATE */ - { - LPWSTR lpszTemp, lpszTemp1; - LPITEMIDLIST pidl = NULL; - static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0}; - - /* check for invalid chars */ - if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE)) - { - FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME); - ret = FALSE; - goto ret; - } - - if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE; - - lpszTemp1 = lpszTemp = lpstrPathAndFile; - while (lpszTemp1) - { - LPSHELLFOLDER lpsfChild; - WCHAR lpwstrTemp[MAX_PATH]; - DWORD dwEaten, dwAttributes; - LPWSTR p; - - strcpyW(lpwstrTemp, lpszTemp); - p = PathFindNextComponentW(lpwstrTemp); - - if (!p) break; /* end of path */ - - *p = 0; - lpszTemp = lpszTemp + strlenW(lpwstrTemp); - - if(*lpszTemp==0) - { - static const WCHAR wszWild[] = { '*', '?', 0 }; - /* if the last element is a wildcard do a search */ - if(strpbrkW(lpszTemp1, wszWild) != NULL) - { - nOpenAction = ONOPEN_SEARCH; - break; - } - } - lpszTemp1 = lpszTemp; - - TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf); - - /* append a backslash to drive letters */ - if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' && - ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') || - (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z'))) - { - PathAddBackslashW(lpwstrTemp); - } - - dwAttributes = SFGAO_FOLDER; - if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes))) - { - /* the path component is valid, we have a pidl of the next path component */ - TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl); - if(dwAttributes & SFGAO_FOLDER) - { - if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild))) - { - ERR("bind to failed\n"); /* should not fail */ - break; - } - IShellFolder_Release(lpsf); - lpsf = lpsfChild; - lpsfChild = NULL; - } - else - { - TRACE("value\n"); - - /* end dialog, return value */ - nOpenAction = ONOPEN_OPEN; - break; - } - COMDLG32_SHFree(pidl); - pidl = NULL; - } - else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE)) - { - if(*lpszTemp) /* points to trailing null for last path element */ - { - if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST) - { - FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING); - break; - } - } - else - { - if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) && - !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) ) - { - FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING); - break; - } - } - /* change to the current folder */ - nOpenAction = ONOPEN_OPEN; - break; - } - else - { - nOpenAction = ONOPEN_OPEN; - break; - } - } - if(pidl) COMDLG32_SHFree(pidl); - } - -/* - Step 3: here we have a cleaned up and validated path - - valid variables: - lpsf: ShellFolder bound to the rightmost valid path component - lpstrPathAndFile: cleaned up path - nOpenAction: action to do -*/ - TRACE("end validate sf=%p\n", lpsf); - - switch(nOpenAction) - { - case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */ - TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile)); - { - int iPos; - LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile); - DWORD len; - IPersistFolder2 * ppf2; - - /* replace the current filter */ - if(fodInfos->ShellInfos.lpstrCurrentFilter) - MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter); - len = strlenW(lpszTemp)+1; - fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR)); - strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp); - - /* set the filter cb to the extension when possible */ - if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp))) - CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos); - - if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2))) - { - LPITEMIDLIST pidlCurrent; - IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent); - IPersistFolder2_Release(ppf2); - if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent)) - { - IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE); - } - else - { - IShellView_Refresh(fodInfos->Shell.FOIShellView); - } - SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE); - COMDLG32_SHFree(pidlCurrent); - } - } - ret = FALSE; - break; - case ONOPEN_OPEN: /* fill in the return struct and close the dialog */ - TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile)); - { - WCHAR *ext = NULL; - - /* update READONLY check box flag */ - if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED) - fodInfos->ofnInfos->Flags |= OFN_READONLY; - else - fodInfos->ofnInfos->Flags &= ~OFN_READONLY; - - /* Attach the file extension with file name*/ - - if(!PathIsDirectoryW(lpstrPathAndFile)) - { - if((ext = PathFindExtensionW(lpstrPathAndFile)) == NULL) - { - /* if no extension is specified with file name, then */ - /* attach the extension from file filter or default one */ - - WCHAR *filterExt = NULL; - LPWSTR lpstrFilter = NULL; - static const WCHAR szwDot[] = {'.',0}; - int PathLength = strlenW(lpstrPathAndFile); - - /* Attach the dot*/ - strcatW(lpstrPathAndFile, szwDot); - - /*Get the file extension from file type filter*/ - lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, - fodInfos->ofnInfos->nFilterIndex-1); - - if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */ - filterExt = PathFindExtensionW(lpstrFilter); - - if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/ - strcatW(lpstrPathAndFile, filterExt + 1); - else if ( fodInfos->defext ) /* attach the default file extension*/ - strcatW(lpstrPathAndFile, fodInfos->defext); - - /* In Open dialog: if file does not exist try without extension */ - if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile)) - lpstrPathAndFile[PathLength] = '\0'; - } - - if (fodInfos->defext) /* add default extension */ - { - /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */ - if (*ext) - ext++; - if (!lstrcmpiW(fodInfos->defext, ext)) - fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT; - else - fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT; - } - } - - /* In Save dialog: check if the file already exists */ - if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG - && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT - && PathFileExistsW(lpstrPathAndFile)) - { - WCHAR lpstrOverwrite[100]; - int answer; - - LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100); - answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title, - MB_YESNO | MB_ICONEXCLAMATION); - if (answer == IDNO) - { - ret = FALSE; - goto ret; - } - } - - /* Check that the size of the file does not exceed buffer size. - (Allow for extra \0 if OFN_MULTISELECT is set.) */ - if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile - - ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0)) - { - LPWSTR lpszTemp; - - /* fill destination buffer */ - if (fodInfos->ofnInfos->lpstrFile) - { - if(fodInfos->unicode) - { - LPOPENFILENAMEW ofn = fodInfos->ofnInfos; - - lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile); - if (ofn->Flags & OFN_ALLOWMULTISELECT) - ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0'; - } - else - { - LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos; - - WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1, - ofn->lpstrFile, ofn->nMaxFile, NULL, NULL); - if (ofn->Flags & OFN_ALLOWMULTISELECT) - ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0'; - } - } - - /* set filename offset */ - lpszTemp = PathFindFileNameW(lpstrPathAndFile); - fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile); - - /* set extension offset */ - lpszTemp = PathFindExtensionW(lpstrPathAndFile); - fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0; - - /* set the lpstrFileTitle */ - if(fodInfos->ofnInfos->lpstrFileTitle) - { - LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile); - if(fodInfos->unicode) - { - LPOPENFILENAMEW ofn = fodInfos->ofnInfos; - lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle); - } - else - { - LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos; - WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1, - ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL); - } - } - - /* copy currently selected filter to lpstrCustomFilter */ - if (fodInfos->ofnInfos->lpstrCustomFilter) - { - LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos; - int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1, - NULL, 0, NULL, NULL); - if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter) - { - LPSTR s = ofn->lpstrCustomFilter; - s += strlen(ofn->lpstrCustomFilter)+1; - WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1, - s, len, NULL, NULL); - } - } - - - if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) ) - goto ret; - - TRACE("close\n"); - FILEDLG95_Clean(hwnd); - ret = EndDialog(hwnd, TRUE); - } - else - { - WORD size; - - size = strlenW(lpstrPathAndFile) + 1; - if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) - size += 1; - /* return needed size in first two bytes of lpstrFile */ - *(WORD *)fodInfos->ofnInfos->lpstrFile = size; - FILEDLG95_Clean(hwnd); - ret = EndDialog(hwnd, FALSE); - COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL); - } - goto ret; - } - break; - } - -ret: - if(lpsf) IShellFolder_Release(lpsf); - return ret; -} - -/*********************************************************************** - * FILEDLG95_SHELL_Init - * - * Initialisation of the shell objects - */ -static LRESULT FILEDLG95_SHELL_Init(HWND hwnd) -{ - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); - - TRACE("\n"); - - /* - * Initialisation of the FileOpenDialogInfos structure - */ - - /* Shell */ - - /*ShellInfos */ - fodInfos->ShellInfos.hwndOwner = hwnd; - - /* Disable multi-select if flag not set */ - if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)) - { - fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL; - } - fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT; - fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST; - - /* Construct the IShellBrowser interface */ - fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd); - - return NOERROR; -} - -/*********************************************************************** - * FILEDLG95_SHELL_ExecuteCommand - * - * Change the folder option and refresh the view - * If the function succeeds, the return value is nonzero. - */ -static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb) -{ - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); - - IContextMenu * pcm; - TRACE("(%p,%p)\n", hwnd, lpVerb); - - if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView, - SVGIO_BACKGROUND, - &IID_IContextMenu, - (LPVOID*)&pcm))) - { - CMINVOKECOMMANDINFO ci; - ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO)); - ci.cbSize = sizeof(CMINVOKECOMMANDINFO); - ci.lpVerb = lpVerb; - ci.hwnd = hwnd; - - IContextMenu_InvokeCommand(pcm, &ci); - IContextMenu_Release(pcm); - } - - return FALSE; -} - -/*********************************************************************** - * FILEDLG95_SHELL_UpFolder - * - * Browse to the specified object - * If the function succeeds, the return value is nonzero. - */ -static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd) -{ - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); - - TRACE("\n"); - - if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, - NULL, - SBSP_PARENT))) - { - SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE); - return TRUE; - } - return FALSE; -} - -/*********************************************************************** - * FILEDLG95_SHELL_BrowseToDesktop - * - * Browse to the Desktop - * If the function succeeds, the return value is nonzero. - */ -static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd) -{ - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); - LPITEMIDLIST pidl; - HRESULT hres; - - TRACE("\n"); - - SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl); - hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE); - SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE); - COMDLG32_SHFree(pidl); - return SUCCEEDED(hres); -} -/*********************************************************************** - * FILEDLG95_SHELL_Clean - * - * Cleans the memory used by shell objects - */ -static void FILEDLG95_SHELL_Clean(HWND hwnd) -{ - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); - - TRACE("\n"); - - COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent); - - /* clean Shell interfaces */ - IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView); - IShellView_Release(fodInfos->Shell.FOIShellView); - IShellFolder_Release(fodInfos->Shell.FOIShellFolder); - IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser); - if (fodInfos->Shell.FOIDataObject) - IDataObject_Release(fodInfos->Shell.FOIDataObject); -} - -/*********************************************************************** - * FILEDLG95_FILETYPE_Init - * - * Initialisation of the file type combo box - */ -static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd) -{ - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); - int nFilters = 0; /* number of filters */ - int nFilterIndexCB; - - TRACE("\n"); - - if(fodInfos->customfilter) - { - /* customfilter has one entry... title\0ext\0 - * Set first entry of combo box item with customfilter - */ - LPWSTR lpstrExt; - LPCWSTR lpstrPos = fodInfos->customfilter; - - /* Get the title */ - lpstrPos += strlenW(fodInfos->customfilter) + 1; - - /* Copy the extensions */ - if (! *lpstrPos) return E_FAIL; /* malformed filter */ - if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL; - strcpyW(lpstrExt,lpstrPos); - - /* Add the item at the end of the combo */ - CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter); - CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt); - nFilters++; - } - if(fodInfos->filter) - { - LPCWSTR lpstrPos = fodInfos->filter; - - for(;;) - { - /* filter is a list... title\0ext\0......\0\0 - * Set the combo item text to the title and the item data - * to the ext - */ - LPCWSTR lpstrDisplay; - LPWSTR lpstrExt; - - /* Get the title */ - if(! *lpstrPos) break; /* end */ - lpstrDisplay = lpstrPos; - lpstrPos += strlenW(lpstrPos) + 1; - - /* Copy the extensions */ - if (! *lpstrPos) return E_FAIL; /* malformed filter */ - if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL; - strcpyW(lpstrExt,lpstrPos); - lpstrPos += strlenW(lpstrPos) + 1; - - /* Add the item at the end of the combo */ - CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay); - CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt); - nFilters++; - } - } - - /* - * Set the current filter to the one specified - * in the initialisation structure - */ - if (fodInfos->filter || fodInfos->customfilter) - { - LPWSTR lpstrFilter; - - /* Check to make sure our index isn't out of bounds. */ - if ( fodInfos->ofnInfos->nFilterIndex > - nFilters - (fodInfos->customfilter == NULL ? 0 : 1) ) - fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0); - - /* set default filter index */ - if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL) - fodInfos->ofnInfos->nFilterIndex = 1; - - /* calculate index of Combo Box item */ - nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex; - if (fodInfos->customfilter == NULL) - nFilterIndexCB--; - - /* Set the current index selection. */ - CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB); - - /* Get the corresponding text string from the combo box. */ - lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, - nFilterIndexCB); - - if ((INT)lpstrFilter == CB_ERR) /* control is empty */ - lpstrFilter = NULL; - - if(lpstrFilter) - { - DWORD len; - CharLowerW(lpstrFilter); /* lowercase */ - len = strlenW(lpstrFilter)+1; - fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) ); - strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter); - } - } else - fodInfos->ofnInfos->nFilterIndex = 0; - return S_OK; -} - -/*********************************************************************** - * FILEDLG95_FILETYPE_OnCommand - * - * WM_COMMAND of the file type combo box - * If the function succeeds, the return value is nonzero. - */ -static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode) -{ - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); - - switch(wNotifyCode) - { - case CBN_SELENDOK: - { - LPWSTR lpstrFilter; - - /* Get the current item of the filetype combo box */ - int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB); - - /* set the current filter index */ - fodInfos->ofnInfos->nFilterIndex = iItem + - (fodInfos->customfilter == NULL ? 1 : 0); - - /* Set the current filter with the current selection */ - if(fodInfos->ShellInfos.lpstrCurrentFilter) - MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter); - - lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, - iItem); - if((int)lpstrFilter != CB_ERR) - { - DWORD len; - CharLowerW(lpstrFilter); /* lowercase */ - len = strlenW(lpstrFilter)+1; - fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) ); - strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter); - SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE); - } - - /* Refresh the actual view to display the included items*/ - IShellView_Refresh(fodInfos->Shell.FOIShellView); - } - } - return FALSE; -} -/*********************************************************************** - * FILEDLG95_FILETYPE_SearchExt - * - * searches for an extension in the filetype box - */ -static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt) -{ - int i, iCount = CBGetCount(hwnd); - - TRACE("%s\n", debugstr_w(lpstrExt)); - - if(iCount != CB_ERR) - { - for(i=0;iDlgInfos.hwndFileTypeCB); - - TRACE("\n"); - - /* Delete each string of the combo and their associated data */ - if(iCount != CB_ERR) - { - for(iPos = iCount-1;iPos>=0;iPos--) - { - MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos)); - CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos); - } - } - /* Current filter */ - if(fodInfos->ShellInfos.lpstrCurrentFilter) - MemFree(fodInfos->ShellInfos.lpstrCurrentFilter); - -} - -/*********************************************************************** - * FILEDLG95_LOOKIN_Init - * - * Initialisation of the look in combo box - */ -static void FILEDLG95_LOOKIN_Init(HWND hwndCombo) -{ - IShellFolder *psfRoot, *psfDrives; - IEnumIDList *lpeRoot, *lpeDrives; - LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp; - - LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos)); - - TRACE("\n"); - - liInfos->iMaxIndentation = 0; - - SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos); - - /* set item height for both text field and listbox */ - CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON)); - CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON)); - - /* Turn on the extended UI for the combo box like Windows does */ - CBSetExtendedUI(hwndCombo, TRUE); - - /* Initialise data of Desktop folder */ - SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp); - FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND); - COMDLG32_SHFree(pidlTmp); - - SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives); - - SHGetDesktopFolder(&psfRoot); - - if (psfRoot) - { - /* enumerate the contents of the desktop */ - if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot))) - { - while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL)) - { - FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND); - - /* special handling for CSIDL_DRIVES */ - if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives)) - { - if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives))) - { - /* enumerate the drives */ - if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives))) - { - while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL)) - { - pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1); - FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND); - COMDLG32_SHFree(pidlAbsTmp); - COMDLG32_SHFree(pidlTmp1); - } - IEnumIDList_Release(lpeDrives); - } - IShellFolder_Release(psfDrives); - } - } - COMDLG32_SHFree(pidlTmp); - } - IEnumIDList_Release(lpeRoot); - } - IShellFolder_Release(psfRoot); - } - - COMDLG32_SHFree(pidlDrives); -} - -/*********************************************************************** - * FILEDLG95_LOOKIN_DrawItem - * - * WM_DRAWITEM message handler - */ -static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct) -{ - COLORREF crWin = GetSysColor(COLOR_WINDOW); - COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT); - COLORREF crText = GetSysColor(COLOR_WINDOWTEXT); - RECT rectText; - RECT rectIcon; - SHFILEINFOA sfi; - HIMAGELIST ilItemImage; - int iIndentation; - TEXTMETRICA tm; - LPSFOLDER tmpFolder; - - - LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr); - - TRACE("\n"); - - if(pDIStruct->itemID == -1) - return 0; - - if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem, - pDIStruct->itemID))) - return 0; - - - if(pDIStruct->itemID == liInfos->uSelectedItem) - { - ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem, - 0, - &sfi, - sizeof (SHFILEINFOA), - SHGFI_PIDL | SHGFI_SMALLICON | - SHGFI_OPENICON | SHGFI_SYSICONINDEX | - SHGFI_DISPLAYNAME ); - } - else - { - ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem, - 0, - &sfi, - sizeof (SHFILEINFOA), - SHGFI_PIDL | SHGFI_SMALLICON | - SHGFI_SYSICONINDEX | - SHGFI_DISPLAYNAME); - } - - /* Is this item selected ? */ - if(pDIStruct->itemState & ODS_SELECTED) - { - SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText))); - SetBkColor(pDIStruct->hDC,crHighLight); - FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT)); - } - else - { - SetTextColor(pDIStruct->hDC,crText); - SetBkColor(pDIStruct->hDC,crWin); - FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW)); - } - - /* Do not indent item if drawing in the edit of the combo */ - if(pDIStruct->itemState & ODS_COMBOBOXEDIT) - { - iIndentation = 0; - ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem, - 0, - &sfi, - sizeof (SHFILEINFOA), - SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON - | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME ); - - } - else - { - iIndentation = tmpFolder->m_iIndent; - } - /* Draw text and icon */ - - /* Initialise the icon display area */ - rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation; - rectIcon.top = pDIStruct->rcItem.top; - rectIcon.right = rectIcon.left + ICONWIDTH; - rectIcon.bottom = pDIStruct->rcItem.bottom; - - /* Initialise the text display area */ - GetTextMetricsA(pDIStruct->hDC, &tm); - rectText.left = rectIcon.right; - rectText.top = - (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2; - rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET; - rectText.bottom = - (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2; - - /* Draw the icon from the image list */ - ImageList_Draw(ilItemImage, - sfi.iIcon, - pDIStruct->hDC, - rectIcon.left, - rectIcon.top, - ILD_TRANSPARENT ); - - /* Draw the associated text */ - if(sfi.szDisplayName) - TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName)); - - - return NOERROR; -} - -/*********************************************************************** - * FILEDLG95_LOOKIN_OnCommand - * - * LookIn combo box WM_COMMAND message handler - * If the function succeeds, the return value is nonzero. - */ -static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode) -{ - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); - - TRACE("%p\n", fodInfos); - - switch(wNotifyCode) - { - case CBN_SELENDOK: - { - LPSFOLDER tmpFolder; - int iItem; - - iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB); - - if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB, - iItem))) - return FALSE; - - - if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, - tmpFolder->pidlItem, - SBSP_ABSOLUTE))) - { - SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE); - return TRUE; - } - break; - } - - } - return FALSE; -} - -/*********************************************************************** - * FILEDLG95_LOOKIN_AddItem - * - * Adds an absolute pidl item to the lookin combo box - * returns the index of the inserted item - */ -static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId) -{ - LPITEMIDLIST pidlNext; - SHFILEINFOA sfi; - SFOLDER *tmpFolder; - LookInInfos *liInfos; - - TRACE("%08x\n", iInsertId); - - if(!pidl) - return -1; - - if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr))) - return -1; - - tmpFolder = MemAlloc(sizeof(SFOLDER)); - tmpFolder->m_iIndent = 0; - - /* Calculate the indentation of the item in the lookin*/ - pidlNext = pidl; - while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) ) - { - tmpFolder->m_iIndent++; - } - - tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl); - - if(tmpFolder->m_iIndent > liInfos->iMaxIndentation) - liInfos->iMaxIndentation = tmpFolder->m_iIndent; - - sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM; - SHGetFileInfoA((LPSTR)pidl, - 0, - &sfi, - sizeof(sfi), - SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX - | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED); - - TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes); - - if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM)) - { - int iItemID; - - TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent); - - /* Add the item at the end of the list */ - if(iInsertId < 0) - { - iItemID = CBAddString(hwnd,sfi.szDisplayName); - } - /* Insert the item at the iInsertId position*/ - else - { - iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId); - } - - CBSetItemDataPtr(hwnd,iItemID,tmpFolder); - return iItemID; - } - - COMDLG32_SHFree( tmpFolder->pidlItem ); - MemFree( tmpFolder ); - return -1; - -} - -/*********************************************************************** - * FILEDLG95_LOOKIN_InsertItemAfterParent - * - * Insert an item below its parent - */ -static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl) -{ - - LPITEMIDLIST pidlParent = GetParentPidl(pidl); - int iParentPos; - - TRACE("\n"); - - iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL); - - if(iParentPos < 0) - { - iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent); - } - - /* Free pidlParent memory */ - COMDLG32_SHFree((LPVOID)pidlParent); - - return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1); -} - -/*********************************************************************** - * FILEDLG95_LOOKIN_SelectItem - * - * Adds an absolute pidl item to the lookin combo box - * returns the index of the inserted item - */ -int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl) -{ - int iItemPos; - LookInInfos *liInfos; - - TRACE("\n"); - - iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL); - - liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr); - - if(iItemPos < 0) - { - while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1); - iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl); - } - - else - { - SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos); - while(liInfos->iMaxIndentation > tmpFolder->m_iIndent) - { - int iRemovedItem; - - if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd))) - break; - if(iRemovedItem < iItemPos) - iItemPos--; - } - } - - CBSetCurSel(hwnd,iItemPos); - liInfos->uSelectedItem = iItemPos; - - return 0; - -} - -/*********************************************************************** - * FILEDLG95_LOOKIN_RemoveMostExpandedItem - * - * Remove the item with an expansion level over iExpansionLevel - */ -static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd) -{ - int iItemPos; - - LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr); - - TRACE("\n"); - - if(liInfos->iMaxIndentation <= 2) - return -1; - - if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0) - { - SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos); - COMDLG32_SHFree(tmpFolder->pidlItem); - MemFree(tmpFolder); - CBDeleteString(hwnd,iItemPos); - liInfos->iMaxIndentation--; - - return iItemPos; - } - - return -1; -} - -/*********************************************************************** - * FILEDLG95_LOOKIN_SearchItem - * - * Search for pidl in the lookin combo box - * returns the index of the found item - */ -static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod) -{ - int i = 0; - int iCount = CBGetCount(hwnd); - - TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod); - - if (iCount != CB_ERR) - { - for(;ipidlItem)) - return i; - if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg) - return i; - } - } - - return -1; -} - -/*********************************************************************** - * FILEDLG95_LOOKIN_Clean - * - * Clean the memory used by the lookin combo box - */ -static void FILEDLG95_LOOKIN_Clean(HWND hwnd) -{ - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); - int iPos; - int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB); - - TRACE("\n"); - - /* Delete each string of the combo and their associated data */ - if (iCount != CB_ERR) - { - for(iPos = iCount-1;iPos>=0;iPos--) - { - SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos); - COMDLG32_SHFree(tmpFolder->pidlItem); - MemFree(tmpFolder); - CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos); - } - } - - /* LookInInfos structure */ - RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr); - -} -/*********************************************************************** - * FILEDLG95_FILENAME_FillFromSelection - * - * fills the edit box from the cached DataObject - */ -void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd) -{ - FileOpenDlgInfos *fodInfos; - LPITEMIDLIST pidl; - UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0; - char lpstrTemp[MAX_PATH]; - LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL; - - TRACE("\n"); - fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); - - /* Count how many files we have */ - nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject ); - - /* calculate the string length, count files */ - if (nFileSelected >= 1) - { - nLength += 3; /* first and last quotes, trailing \0 */ - for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ ) - { - pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 ); - - if (pidl) - { - /* get the total length of the selected file names */ - lpstrTemp[0] = '\0'; - GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp ); - - if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */ - { - nLength += strlen( lpstrTemp ) + 3; - nFiles++; - } - COMDLG32_SHFree( pidl ); - } - } - } - - /* allocate the buffer */ - if (nFiles <= 1) nLength = MAX_PATH; - lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength); - lpstrAllFile[0] = '\0'; - - /* Generate the string for the edit control */ - if(nFiles >= 1) - { - lpstrCurrFile = lpstrAllFile; - for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ ) - { - pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 ); - - if (pidl) - { - /* get the file name */ - lpstrTemp[0] = '\0'; - GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp ); - - if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */ - { - if ( nFiles > 1) - { - *lpstrCurrFile++ = '\"'; - strcpy( lpstrCurrFile, lpstrTemp ); - lpstrCurrFile += strlen( lpstrTemp ); - strcpy( lpstrCurrFile, "\" " ); - lpstrCurrFile += 2; - } - else - { - strcpy( lpstrAllFile, lpstrTemp ); - } - } - COMDLG32_SHFree( (LPVOID) pidl ); - } - } - SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile ); - - /* Select the file name like Windows does */ - SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1); - } - HeapFree(GetProcessHeap(),0, lpstrAllFile ); -} - - -/* copied from shell32 to avoid linking to it - * FIXME: why? shell32 is already linked - */ -static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl) -{ - switch (src->uType) - { - case STRRET_WSTR: - WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL); - COMDLG32_SHFree(src->u.pOleStr); - break; - - case STRRET_CSTR: - lstrcpynA((LPSTR)dest, src->u.cStr, len); - break; - - case STRRET_OFFSET: - lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len); - break; - - default: - FIXME("unknown type!\n"); - if (len) - { - *(LPSTR)dest = '\0'; - } - return(E_FAIL); - } - return S_OK; -} - -/*********************************************************************** - * FILEDLG95_FILENAME_GetFileNames - * - * Copies the filenames to a delimited string list. - * The delimiter is specified by the parameter 'separator', - * usually either a space or a nul - */ -static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator) -{ - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); - UINT nStrCharCount = 0; /* index in src buffer */ - UINT nFileIndex = 0; /* index in dest buffer */ - UINT nFileCount = 0; /* number of files */ - UINT nStrLen = 0; /* length of string in edit control */ - LPWSTR lpstrEdit; /* buffer for string from edit control */ - - TRACE("\n"); - - /* get the filenames from the edit control */ - nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0); - lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) ); - GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1); - - TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit)); - - /* we might get single filename without any '"', - * so we need nStrLen + terminating \0 + end-of-list \0 */ - *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) ); - *sizeUsed = 0; - - /* build delimited file list from filenames */ - while ( nStrCharCount <= nStrLen ) - { - if ( lpstrEdit[nStrCharCount]=='"' ) - { - nStrCharCount++; - while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen)) - { - (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount]; - (*sizeUsed)++; - nStrCharCount++; - } - (*lpstrFileList)[nFileIndex++] = separator; - (*sizeUsed)++; - nFileCount++; - } - nStrCharCount++; - } - - /* single, unquoted string */ - if ((nStrLen > 0) && (*sizeUsed == 0) ) - { - strcpyW(*lpstrFileList, lpstrEdit); - nFileIndex = strlenW(lpstrEdit) + 1; - (*sizeUsed) = nFileIndex; - nFileCount = 1; - } - - /* trailing \0 */ - (*lpstrFileList)[nFileIndex] = '\0'; - (*sizeUsed)++; - - MemFree(lpstrEdit); - return nFileCount; -} - -#define SETDefFormatEtc(fe,cf,med) \ -{ \ - (fe).cfFormat = cf;\ - (fe).dwAspect = DVASPECT_CONTENT; \ - (fe).ptd =NULL;\ - (fe).tymed = med;\ - (fe).lindex = -1;\ -}; - -/* - * DATAOBJECT Helper functions - */ - -/*********************************************************************** - * COMCTL32_ReleaseStgMedium - * - * like ReleaseStgMedium from ole32 - */ -static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium) -{ - if(medium.pUnkForRelease) - { - IUnknown_Release(medium.pUnkForRelease); - } - else - { - GlobalUnlock(medium.u.hGlobal); - GlobalFree(medium.u.hGlobal); - } -} - -/*********************************************************************** - * GetPidlFromDataObject - * - * Return pidl(s) by number from the cached DataObject - * - * nPidlIndex=0 gets the fully qualified root path - */ -LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex) -{ - - STGMEDIUM medium; - FORMATETC formatetc; - LPITEMIDLIST pidl = NULL; - - TRACE("sv=%p index=%u\n", doSelected, nPidlIndex); - - /* Set the FORMATETC structure*/ - SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL); - - /* Get the pidls from IDataObject */ - if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium))) - { - LPIDA cida = GlobalLock(medium.u.hGlobal); - if(nPidlIndex <= cida->cidl) - { - pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]])); - } - COMCTL32_ReleaseStgMedium(medium); - } - return pidl; -} - -/*********************************************************************** - * GetNumSelected - * - * Return the number of selected items in the DataObject. - * -*/ -UINT GetNumSelected( IDataObject *doSelected ) -{ - UINT retVal = 0; - STGMEDIUM medium; - FORMATETC formatetc; - - TRACE("sv=%p\n", doSelected); - - if (!doSelected) return 0; - - /* Set the FORMATETC structure*/ - SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL); - - /* Get the pidls from IDataObject */ - if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium))) - { - LPIDA cida = GlobalLock(medium.u.hGlobal); - retVal = cida->cidl; - COMCTL32_ReleaseStgMedium(medium); - return retVal; - } - return 0; -} - -/* - * TOOLS - */ - -/*********************************************************************** - * GetName - * - * Get the pidl's display name (relative to folder) and - * put it in lpstrFileName. - * - * Return NOERROR on success, - * E_FAIL otherwise - */ - -static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName) -{ - STRRET str; - HRESULT hRes; - - TRACE("sf=%p pidl=%p\n", lpsf, pidl); - - if(!lpsf) - { - SHGetDesktopFolder(&lpsf); - hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName); - IShellFolder_Release(lpsf); - return hRes; - } - - /* Get the display name of the pidl relative to the folder */ - if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str))) - { - return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl); - } - return E_FAIL; -} - -/*********************************************************************** - * GetShellFolderFromPidl - * - * pidlRel is the item pidl relative - * Return the IShellFolder of the absolute pidl - */ -IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs) -{ - IShellFolder *psf = NULL,*psfParent; - - TRACE("%p\n", pidlAbs); - - if(SUCCEEDED(SHGetDesktopFolder(&psfParent))) - { - psf = psfParent; - if(pidlAbs && pidlAbs->mkid.cb) - { - if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf))) - { - IShellFolder_Release(psfParent); - return psf; - } - } - /* return the desktop */ - return psfParent; - } - return NULL; -} - -/*********************************************************************** - * GetParentPidl - * - * Return the LPITEMIDLIST to the parent of the pidl in the list - */ -LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl) -{ - LPITEMIDLIST pidlParent; - - TRACE("%p\n", pidl); - - pidlParent = COMDLG32_PIDL_ILClone(pidl); - COMDLG32_PIDL_ILRemoveLastID(pidlParent); - - return pidlParent; -} - -/*********************************************************************** - * GetPidlFromName - * - * returns the pidl of the file name relative to folder - * NULL if an error occurred - */ -LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName) -{ - LPITEMIDLIST pidl = NULL; - ULONG ulEaten; - - TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName)); - - if(!lpcstrFileName) return NULL; - if(!*lpcstrFileName) return NULL; - - if(!lpsf) - { - if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) { - IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL); - IShellFolder_Release(lpsf); - } - } - else - { - IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL); - } - return pidl; -} - -/* -*/ -BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl) -{ - ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER; - HRESULT ret; - - TRACE("%p, %p\n", psf, pidl); - - ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr ); - - TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret); - /* see documentation shell 4.1*/ - return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER); -} - -/*********************************************************************** - * BrowseSelectedFolder - */ -static BOOL BrowseSelectedFolder(HWND hwnd) -{ - BOOL bBrowseSelFolder = FALSE; - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); - - TRACE("\n"); - - if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1) - { - LPITEMIDLIST pidlSelection; - - /* get the file selected */ - pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1); - if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection)) - { - if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser, - pidlSelection, SBSP_RELATIVE ) ) ) - { - static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s', - ' ','n','o','t',' ','e','x','i','s','t',0}; - MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION ); - } - bBrowseSelFolder = TRUE; - SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE); - } - COMDLG32_SHFree( pidlSelection ); - } - - return bBrowseSelFolder; -} - -/* - * Memory allocation methods */ -static void *MemAlloc(UINT size) -{ - return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size); -} - -static void MemFree(void *mem) -{ - HeapFree(GetProcessHeap(),0,mem); -} - -/* - * Old-style (win3.1) dialogs */ - -/*********************************************************************** - * FD32_GetTemplate [internal] - * - * Get a template (or FALSE if failure) when 16 bits dialogs are used - * by a 32 bits application - * - */ -static BOOL FD32_GetTemplate(PFD31_DATA lfs) -{ - LPOPENFILENAMEW ofnW = lfs->ofnW; - PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632; - HANDLE hDlgTmpl; - - if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE) - { - if (!(lfs->template = LockResource( ofnW->hInstance ))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - } - else if (ofnW->Flags & OFN_ENABLETEMPLATE) - { - HRSRC hResInfo; - if (priv->ofnA) - hResInfo = FindResourceA(priv->ofnA->hInstance, - priv->ofnA->lpTemplateName, - (LPSTR)RT_DIALOG); - else - hResInfo = FindResourceW(ofnW->hInstance, - ofnW->lpTemplateName, - (LPWSTR)RT_DIALOG); - if (!hResInfo) - { - COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); - return FALSE; - } - if (!(hDlgTmpl = LoadResource(ofnW->hInstance, - hResInfo)) || - !(lfs->template = LockResource(hDlgTmpl))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - } else { /* get it from internal Wine resource */ - HRSRC hResInfo; - if (!(hResInfo = FindResourceA(COMDLG32_hInstance, - lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); - return FALSE; - } - if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) || - !(lfs->template = LockResource( hDlgTmpl ))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - } - return TRUE; -} - - -/************************************************************************ - * FD32_Init [internal] - * called from the common 16/32 code to initialize 32 bit data - */ -static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data) -{ - BOOL IsUnicode = (BOOL) data; - PFD32_PRIVATE priv; - - priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE)); - lfs->private1632 = priv; - if (NULL == lfs->private1632) return FALSE; - if (IsUnicode) - { - lfs->ofnW = (LPOPENFILENAMEW) lParam; - if (lfs->ofnW->Flags & OFN_ENABLEHOOK) - if (lfs->ofnW->lpfnHook) - lfs->hook = TRUE; - } - else - { - priv->ofnA = (LPOPENFILENAMEA) lParam; - if (priv->ofnA->Flags & OFN_ENABLEHOOK) - if (priv->ofnA->lpfnHook) - lfs->hook = TRUE; - lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW)); - FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open); - } - - if (! FD32_GetTemplate(lfs)) return FALSE; - - return TRUE; -} - -/*********************************************************************** - * FD32_CallWindowProc [internal] - * - * called from the common 16/32 code to call the appropriate hook - */ -BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam, - LPARAM lParam) -{ - BOOL ret; - PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632; - - if (priv->ofnA) - { - TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n", - priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam); - ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam); - TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n", - priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam); - return ret; - } - - TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n", - lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam); - ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam); - TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n", - lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam); - return ret; -} - -/*********************************************************************** - * FD32_UpdateResult [internal] - * update the real client structures if any - */ -static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs) -{ - PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632; - LPOPENFILENAMEW ofnW = lfs->ofnW; - - if (priv->ofnA) - { - if (ofnW->nMaxFile && - !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1, - priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL )) - priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0; - priv->ofnA->nFileOffset = ofnW->nFileOffset; - priv->ofnA->nFileExtension = ofnW->nFileExtension; - } -} - -/*********************************************************************** - * FD32_UpdateFileTitle [internal] - * update the real client structures if any - */ -static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs) -{ - PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632; - LPOPENFILENAMEW ofnW = lfs->ofnW; - - if (priv->ofnA) - { - if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1, - priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL )) - priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0; - } -} - - -/*********************************************************************** - * FD32_SendLbGetCurSel [internal] - * retrieve selected listbox item - */ -static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs) -{ - return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0); -} - - -/************************************************************************ - * FD32_Destroy [internal] - * called from the common 16/32 code to cleanup 32 bit data - */ -static void CALLBACK FD32_Destroy(PFD31_DATA lfs) -{ - PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632; - - /* if ofnW has been allocated, have to free everything in it */ - if (NULL != priv && NULL != priv->ofnA) - { - FD31_FreeOfnW(lfs->ofnW); - HeapFree(GetProcessHeap(), 0, lfs->ofnW); - } -} - -static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks) -{ - callbacks->Init = FD32_Init; - callbacks->CWP = FD32_CallWindowProc; - callbacks->UpdateResult = FD32_UpdateResult; - callbacks->UpdateFileTitle = FD32_UpdateFileTitle; - callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel; - callbacks->Destroy = FD32_Destroy; -} - -/*********************************************************************** - * FD32_WMMeasureItem [internal] - */ -static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam) -{ - LPMEASUREITEMSTRUCT lpmeasure; - - lpmeasure = (LPMEASUREITEMSTRUCT)lParam; - lpmeasure->itemHeight = FD31_GetFldrHeight(); - return TRUE; -} - - -/*********************************************************************** - * FileOpenDlgProc [internal] - * Used for open and save, in fact. - */ -static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg, - WPARAM wParam, LPARAM lParam) -{ - PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP); - - TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam); - if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook) - { - INT_PTR lRet; - lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam); - if (lRet) - return lRet; /* else continue message processing */ - } - switch (wMsg) - { - case WM_INITDIALOG: - return FD31_WMInitDialog(hWnd, wParam, lParam); - - case WM_MEASUREITEM: - return FD32_WMMeasureItem(hWnd, wParam, lParam); - - case WM_DRAWITEM: - return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam); - - case WM_COMMAND: - return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs); -#if 0 - case WM_CTLCOLOR: - SetBkColor((HDC16)wParam, 0x00C0C0C0); - switch (HIWORD(lParam)) - { - case CTLCOLOR_BTN: - SetTextColor((HDC16)wParam, 0x00000000); - return hGRAYBrush; - case CTLCOLOR_STATIC: - SetTextColor((HDC16)wParam, 0x00000000); - return hGRAYBrush; - } - break; -#endif - } - return FALSE; -} - - -/*********************************************************************** - * GetFileName31A [internal] - * - * Creates a win31 style dialog box for the user to select a file to open/save. - */ -static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/ - UINT dlgType /* type dialogue : open/save */ - ) -{ - HINSTANCE hInst; - BOOL bRet = FALSE; - PFD31_DATA lfs; - FD31_CALLBACKS callbacks; - - if (!lpofn || !FD31_Init()) return FALSE; - - TRACE("ofn flags %08lx\n", lpofn->Flags); - FD32_SetupCallbacks(&callbacks); - lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE); - if (lfs) - { - hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE ); - bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner, - FD32_FileOpenDlgProc, (LPARAM)lfs); - FD31_DestroyPrivate(lfs); - } - - TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile); - return bRet; -} - -/*********************************************************************** - * GetFileName31W [internal] - * - * Creates a win31 style dialog box for the user to select a file to open/save - */ -static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/ - UINT dlgType /* type dialogue : open/save */ - ) -{ - HINSTANCE hInst; - BOOL bRet = FALSE; - PFD31_DATA lfs; - FD31_CALLBACKS callbacks; - - if (!lpofn || !FD31_Init()) return FALSE; - - FD32_SetupCallbacks(&callbacks); - lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE); - if (lfs) - { - hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE ); - bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner, - FD32_FileOpenDlgProc, (LPARAM)lfs); - FD31_DestroyPrivate(lfs); - } - - TRACE("file %s, file offset %d, ext offset %d\n", - debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension); - return bRet; -} - -/* ------------------ APIs ---------------------- */ - -/*********************************************************************** - * GetOpenFileNameA (COMDLG32.@) - * - * Creates a dialog box for the user to select a file to open. - * - * RETURNS - * TRUE on success: user enters a valid file - * FALSE on cancel, error, close or filename-does-not-fit-in-buffer. - * - */ -BOOL WINAPI GetOpenFileNameA( - LPOPENFILENAMEA ofn) /* [in/out] address of init structure */ -{ - BOOL win16look = FALSE; - - /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */ - if (ofn->Flags & OFN_FILEMUSTEXIST) - ofn->Flags |= OFN_PATHMUSTEXIST; - - if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE)) - win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE; - - if (win16look) - return GetFileName31A(ofn, OPEN_DIALOG); - else - return GetFileDialog95A(ofn, OPEN_DIALOG); -} - -/*********************************************************************** - * GetOpenFileNameW (COMDLG32.@) - * - * Creates a dialog box for the user to select a file to open. - * - * RETURNS - * TRUE on success: user enters a valid file - * FALSE on cancel, error, close or filename-does-not-fit-in-buffer. - * - */ -BOOL WINAPI GetOpenFileNameW( - LPOPENFILENAMEW ofn) /* [in/out] address of init structure */ -{ - BOOL win16look = FALSE; - - if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE)) - win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE; - - if (win16look) - return GetFileName31W(ofn, OPEN_DIALOG); - else - return GetFileDialog95W(ofn, OPEN_DIALOG); -} - - -/*********************************************************************** - * GetSaveFileNameA (COMDLG32.@) - * - * 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. - * - */ -BOOL WINAPI GetSaveFileNameA( - LPOPENFILENAMEA ofn) /* [in/out] address of init structure */ -{ - BOOL win16look = FALSE; - - if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE)) - win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE; - - if (win16look) - return GetFileName31A(ofn, SAVE_DIALOG); - else - return GetFileDialog95A(ofn, SAVE_DIALOG); -} - -/*********************************************************************** - * GetSaveFileNameW (COMDLG32.@) - * - * 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. - * - */ -BOOL WINAPI GetSaveFileNameW( - LPOPENFILENAMEW ofn) /* [in/out] address of init structure */ -{ - BOOL win16look = FALSE; - - if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE)) - win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE; - - if (win16look) - return GetFileName31W(ofn, SAVE_DIALOG); - else - return GetFileDialog95W(ofn, SAVE_DIALOG); -} +/* + * COMMDLG - File Open Dialogs Win95 look and feel + * + * Copyright 1999 Francois Boisvert + * Copyright 1999, 2000 Juergen Schmied + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * FIXME: The whole concept of handling unicode is badly broken. + * many hook-messages expect a pointer to a + * OPENFILENAMEA or W structure. With the current architecture + * we would have to convert the beast at every call to a hook. + * we have to find a better solution but it would likely cause + * a complete rewrite after which we should handle the + * OPENFILENAME structure without any converting (jsch). + * + * FIXME: any hook gets a OPENFILENAMEA structure + * + * FIXME: CDN_FILEOK is wrong implemented, other CDN_ messages likely too + * + * FIXME: old style hook messages are not implemented (except FILEOKSTRING) + * + * FIXME: algorithm for selecting the initial directory is too simple + * + * FIXME: add to recent docs + * + * FIXME: flags not implemented: OFN_CREATEPROMPT, OFN_DONTADDTORECENT, + * OFN_ENABLEINCLUDENOTIFY, OFN_ENABLESIZING, + * OFN_NODEREFERENCELINKS, OFN_NOREADONLYRETURN, + * OFN_NOTESTFILECREATE, OFN_USEMONIKERS + * + * FIXME: lCustData for lpfnHook (WM_INITDIALOG) + * + * + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include +#include +#include + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winternl.h" +#include "winnls.h" +#include "wine/unicode.h" +#include "wingdi.h" +#include "winuser.h" +#include "commdlg.h" +#include "dlgs.h" +#include "cdlg.h" +#include "filedlg31.h" +#include "wine/debug.h" +#include "cderr.h" +#include "shellapi.h" +#include "shlguid.h" +#include "shlobj.h" +#include "filedlgbrowser.h" +#include "shlwapi.h" + +WINE_DEFAULT_DEBUG_CHANNEL(commdlg); + +#define UNIMPLEMENTED_FLAGS \ +(OFN_CREATEPROMPT | OFN_DONTADDTORECENT |\ +OFN_ENABLEINCLUDENOTIFY | OFN_ENABLESIZING |\ +OFN_NODEREFERENCELINKS | OFN_NOREADONLYRETURN |\ +OFN_NOTESTFILECREATE /*| OFN_USEMONIKERS*/) + +#define IsHooked(fodInfos) \ + ((fodInfos->ofnInfos->Flags & OFN_ENABLEHOOK) && fodInfos->ofnInfos->lpfnHook) +/*********************************************************************** + * Data structure and global variables + */ +typedef struct SFolder +{ + int m_iImageIndex; /* Index of picture in image list */ + HIMAGELIST hImgList; + int m_iIndent; /* Indentation index */ + LPITEMIDLIST pidlItem; /* absolute pidl of the item */ + +} SFOLDER,*LPSFOLDER; + +typedef struct tagLookInInfo +{ + int iMaxIndentation; + UINT uSelectedItem; +} LookInInfos; + +typedef struct tagFD32_PRIVATE +{ + OPENFILENAMEA *ofnA; /* original structure if 32bits ansi dialog */ +} FD32_PRIVATE, *PFD32_PRIVATE; + + +/*********************************************************************** + * Defines and global variables + */ + +/* Draw item constant */ +#define ICONWIDTH 18 +#define XTEXTOFFSET 3 + +/* AddItem flags*/ +#define LISTEND -1 + +/* SearchItem methods */ +#define SEARCH_PIDL 1 +#define SEARCH_EXP 2 +#define ITEM_NOTFOUND -1 + +/* Undefined windows message sent by CreateViewObject*/ +#define WM_GETISHELLBROWSER WM_USER+7 + +/* NOTE + * Those macros exist in windowsx.h. However, you can't really use them since + * they rely on the UNICODE defines and can't be used inside Wine itself. + */ + +/* Combo box macros */ +#define CBAddString(hwnd,str) \ + SendMessageA(hwnd,CB_ADDSTRING,0,(LPARAM)str); +#define CBAddStringW(hwnd,str) \ + SendMessageW(hwnd,CB_ADDSTRING,0,(LPARAM)str); + +#define CBInsertString(hwnd,str,pos) \ + SendMessageA(hwnd,CB_INSERTSTRING,(WPARAM)pos,(LPARAM)str); + +#define CBDeleteString(hwnd,pos) \ + SendMessageA(hwnd,CB_DELETESTRING,(WPARAM)pos,0); + +#define CBSetItemDataPtr(hwnd,iItemId,dataPtr) \ + SendMessageA(hwnd,CB_SETITEMDATA,(WPARAM)iItemId,(LPARAM)dataPtr); + +#define CBGetItemDataPtr(hwnd,iItemId) \ + SendMessageA(hwnd,CB_GETITEMDATA,(WPARAM)iItemId,0) + +#define CBGetLBText(hwnd,iItemId,str) \ + SendMessageA(hwnd,CB_GETLBTEXT,(WPARAM)iItemId,(LPARAM)str); + +#define CBGetCurSel(hwnd) \ + SendMessageA(hwnd,CB_GETCURSEL,0,0); + +#define CBSetCurSel(hwnd,pos) \ + SendMessageA(hwnd,CB_SETCURSEL,(WPARAM)pos,0); + +#define CBGetCount(hwnd) \ + SendMessageA(hwnd,CB_GETCOUNT,0,0); +#define CBShowDropDown(hwnd,show) \ + SendMessageA(hwnd,CB_SHOWDROPDOWN,(WPARAM)show,0); +#define CBSetItemHeight(hwnd,index,height) \ + SendMessageA(hwnd,CB_SETITEMHEIGHT,(WPARAM)index,(LPARAM)height); + +#define CBSetExtendedUI(hwnd,flag) \ + SendMessageA(hwnd,CB_SETEXTENDEDUI,(WPARAM)(flag),0) + +const char *FileOpenDlgInfosStr = "FileOpenDlgInfos"; /* windows property description string */ +const char *LookInInfosStr = "LookInInfos"; /* LOOKIN combo box property */ + +/*********************************************************************** + * Prototypes + */ + +/* Internal functions used by the dialog */ +static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam); +static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam); +static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd); + BOOL FILEDLG95_OnOpen(HWND hwnd); +static LRESULT FILEDLG95_InitControls(HWND hwnd); +static void FILEDLG95_Clean(HWND hwnd); + +/* Functions used by the shell navigation */ +static LRESULT FILEDLG95_SHELL_Init(HWND hwnd); +static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd); +static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb); +static void FILEDLG95_SHELL_Clean(HWND hwnd); +static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd); + +/* Functions used by the EDIT box */ +static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator); + +/* Functions used by the filetype combo box */ +static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd); +static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode); +static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt); +static void FILEDLG95_FILETYPE_Clean(HWND hwnd); + +/* Functions used by the Look In combo box */ +static void FILEDLG95_LOOKIN_Init(HWND hwndCombo); +static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct); +static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode); +static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId); +static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod); +static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl); +static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd); + int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl); +static void FILEDLG95_LOOKIN_Clean(HWND hwnd); + +/* Miscellaneous tool functions */ +static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName); +IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs); +LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl); +LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPWSTR lpcstrFileName); + +/* Shell memory allocation */ +static void *MemAlloc(UINT size); +static void MemFree(void *mem); + +INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +void SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode); +static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +static BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed); +static BOOL BrowseSelectedFolder(HWND hwnd); + +/*********************************************************************** + * GetFileName95 + * + * Creates an Open common dialog box that lets the user select + * the drive, directory, and the name of a file or set of files to open. + * + * IN : The FileOpenDlgInfos structure associated with the dialog + * OUT : TRUE on success + * FALSE on cancel, error, close or filename-does-not-fit-in-buffer. + */ +static BOOL WINAPI GetFileName95(FileOpenDlgInfos *fodInfos) +{ + + LRESULT lRes; + LPCVOID template; + HRSRC hRes; + HANDLE hDlgTmpl = 0; + + /* test for missing functionality */ + if (fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS) + { + FIXME("Flags 0x%08lx not yet implemented\n", + fodInfos->ofnInfos->Flags & UNIMPLEMENTED_FLAGS); + } + + /* Create the dialog from a template */ + + if(!(hRes = FindResourceA(COMDLG32_hInstance,MAKEINTRESOURCEA(NEWFILEOPENORD),(LPSTR)RT_DIALOG))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); + return FALSE; + } + if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hRes )) || + !(template = LockResource( hDlgTmpl ))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + + /* old style hook messages */ + if (IsHooked(fodInfos)) + { + fodInfos->HookMsg.fileokstring = RegisterWindowMessageA(FILEOKSTRINGA); + fodInfos->HookMsg.lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA); + fodInfos->HookMsg.helpmsgstring = RegisterWindowMessageA(HELPMSGSTRINGA); + fodInfos->HookMsg.sharevistring = RegisterWindowMessageA(SHAREVISTRINGA); + } + + lRes = DialogBoxIndirectParamA(COMDLG32_hInstance, + (LPDLGTEMPLATEA) template, + fodInfos->ofnInfos->hwndOwner, + FileOpenDlgProc95, + (LPARAM) fodInfos); + + /* Unable to create the dialog */ + if( lRes == -1) + return FALSE; + + return lRes; +} + +/*********************************************************************** + * GetFileDialog95A + * + * Call GetFileName95 with this structure and clean the memory. + * + * IN : The OPENFILENAMEA initialisation structure passed to + * GetOpenFileNameA win api function (see filedlg.c) + */ +BOOL WINAPI GetFileDialog95A(LPOPENFILENAMEA ofn,UINT iDlgType) +{ + BOOL ret; + FileOpenDlgInfos fodInfos; + LPSTR lpstrSavDir = NULL; + LPWSTR title = NULL; + LPWSTR defext = NULL; + LPWSTR filter = NULL; + LPWSTR customfilter = NULL; + + /* Initialize FileOpenDlgInfos structure */ + ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos)); + + /* Pass in the original ofn */ + fodInfos.ofnInfos = (LPOPENFILENAMEW)ofn; + + /* save current directory */ + if (ofn->Flags & OFN_NOCHANGEDIR) + { + lpstrSavDir = MemAlloc(MAX_PATH); + GetCurrentDirectoryA(MAX_PATH, lpstrSavDir); + } + + fodInfos.unicode = FALSE; + + /* convert all the input strings to unicode */ + if(ofn->lpstrInitialDir) + { + DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, NULL, 0 ); + fodInfos.initdir = MemAlloc((len+1)*sizeof(WCHAR)); + MultiByteToWideChar( CP_ACP, 0, ofn->lpstrInitialDir, -1, fodInfos.initdir, len); + } + else + fodInfos.initdir = NULL; + + if(ofn->lpstrFile) + { + fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR)); + MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFile, -1, fodInfos.filename, ofn->nMaxFile); + } + else + fodInfos.filename = NULL; + + if(ofn->lpstrDefExt) + { + DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, NULL, 0 ); + defext = MemAlloc((len+1)*sizeof(WCHAR)); + MultiByteToWideChar( CP_ACP, 0, ofn->lpstrDefExt, -1, defext, len); + } + fodInfos.defext = defext; + + if(ofn->lpstrTitle) + { + DWORD len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, NULL, 0 ); + title = MemAlloc((len+1)*sizeof(WCHAR)); + MultiByteToWideChar( CP_ACP, 0, ofn->lpstrTitle, -1, title, len); + } + fodInfos.title = title; + + if (ofn->lpstrFilter) + { + LPCSTR s; + int n, len; + + /* filter is a list... title\0ext\0......\0\0 */ + s = ofn->lpstrFilter; + while (*s) s = s+strlen(s)+1; + s++; + n = s - ofn->lpstrFilter; + len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, NULL, 0 ); + filter = MemAlloc(len*sizeof(WCHAR)); + MultiByteToWideChar( CP_ACP, 0, ofn->lpstrFilter, n, filter, len ); + } + fodInfos.filter = filter; + + /* convert lpstrCustomFilter */ + if (ofn->lpstrCustomFilter) + { + LPCSTR s; + int n, len; + + /* customfilter contains a pair of strings... title\0ext\0 */ + s = ofn->lpstrCustomFilter; + if (*s) s = s+strlen(s)+1; + if (*s) s = s+strlen(s)+1; + n = s - ofn->lpstrCustomFilter; + len = MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, NULL, 0 ); + customfilter = MemAlloc(len*sizeof(WCHAR)); + MultiByteToWideChar( CP_ACP, 0, ofn->lpstrCustomFilter, n, customfilter, len ); + } + fodInfos.customfilter = customfilter; + + /* Initialize the dialog property */ + fodInfos.DlgInfos.dwDlgProp = 0; + fodInfos.DlgInfos.hwndCustomDlg = NULL; + + switch(iDlgType) + { + case OPEN_DIALOG : + ret = GetFileName95(&fodInfos); + break; + case SAVE_DIALOG : + fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG; + ret = GetFileName95(&fodInfos); + break; + default : + ret = 0; + } + + if (lpstrSavDir) + { + SetCurrentDirectoryA(lpstrSavDir); + MemFree(lpstrSavDir); + } + + if(title) + MemFree(title); + if(defext) + MemFree(defext); + if(filter) + MemFree(filter); + if(customfilter) + MemFree(customfilter); + if(fodInfos.initdir) + MemFree(fodInfos.initdir); + + if(fodInfos.filename) + MemFree(fodInfos.filename); + + TRACE("selected file: %s\n",ofn->lpstrFile); + + return ret; +} + +/*********************************************************************** + * GetFileDialog95W + * + * Copy the OPENFILENAMEW structure in a FileOpenDlgInfos structure. + * Call GetFileName95 with this structure and clean the memory. + * + */ +BOOL WINAPI GetFileDialog95W(LPOPENFILENAMEW ofn,UINT iDlgType) +{ + BOOL ret; + FileOpenDlgInfos fodInfos; + LPWSTR lpstrSavDir = NULL; + + /* Initialize FileOpenDlgInfos structure */ + ZeroMemory(&fodInfos, sizeof(FileOpenDlgInfos)); + + /* Pass in the original ofn */ + fodInfos.ofnInfos = ofn; + + fodInfos.title = ofn->lpstrTitle; + fodInfos.defext = ofn->lpstrDefExt; + fodInfos.filter = ofn->lpstrFilter; + fodInfos.customfilter = ofn->lpstrCustomFilter; + + /* convert string arguments, save others */ + if(ofn->lpstrFile) + { + fodInfos.filename = MemAlloc(ofn->nMaxFile*sizeof(WCHAR)); + lstrcpynW(fodInfos.filename,ofn->lpstrFile,ofn->nMaxFile); + } + else + fodInfos.filename = NULL; + + if(ofn->lpstrInitialDir) + { + /* fodInfos.initdir = strdupW(ofn->lpstrInitialDir); */ + DWORD len = strlenW(ofn->lpstrInitialDir)+1; + fodInfos.initdir = MemAlloc(len*sizeof(WCHAR)); + memcpy(fodInfos.initdir,ofn->lpstrInitialDir,len*sizeof(WCHAR)); + } + else + fodInfos.initdir = NULL; + + /* save current directory */ + if (ofn->Flags & OFN_NOCHANGEDIR) + { + lpstrSavDir = MemAlloc(MAX_PATH*sizeof(WCHAR)); + GetCurrentDirectoryW(MAX_PATH, lpstrSavDir); + } + + fodInfos.unicode = TRUE; + + switch(iDlgType) + { + case OPEN_DIALOG : + ret = GetFileName95(&fodInfos); + break; + case SAVE_DIALOG : + fodInfos.DlgInfos.dwDlgProp |= FODPROP_SAVEDLG; + ret = GetFileName95(&fodInfos); + break; + default : + ret = 0; + } + + if (lpstrSavDir) + { + SetCurrentDirectoryW(lpstrSavDir); + MemFree(lpstrSavDir); + } + + /* restore saved IN arguments and convert OUT arguments back */ + MemFree(fodInfos.filename); + MemFree(fodInfos.initdir); + return ret; +} + +/****************************************************************************** + * COMDLG32_GetDisplayNameOf [internal] + * + * Helper function to get the display name for a pidl. + */ +static BOOL COMDLG32_GetDisplayNameOf(LPCITEMIDLIST pidl, LPWSTR pwszPath) { + LPSHELLFOLDER psfDesktop; + STRRET strret; + + if (FAILED(SHGetDesktopFolder(&psfDesktop))) + return FALSE; + + if (FAILED(IShellFolder_GetDisplayNameOf(psfDesktop, pidl, SHGDN_FORPARSING, &strret))) { + IShellFolder_Release(psfDesktop); + return FALSE; + } + + IShellFolder_Release(psfDesktop); + return SUCCEEDED(StrRetToBufW(&strret, pidl, pwszPath, MAX_PATH)); +} + +/*********************************************************************** + * ArrangeCtrlPositions [internal] + * + * NOTE: Do not change anything here without a lot of testing. + */ +static void ArrangeCtrlPositions(HWND hwndChildDlg, HWND hwndParentDlg, BOOL hide_help) +{ + HWND hwndChild, hwndStc32; + RECT rectParent, rectChild, rectStc32; + INT help_fixup = 0, child_height_fixup = 0, child_width_fixup = 0; + + /* Take into account if open as read only checkbox and help button + * are hidden + */ + if (hide_help) + { + RECT rectHelp, rectCancel; + GetWindowRect(GetDlgItem(hwndParentDlg, pshHelp), &rectHelp); + GetWindowRect(GetDlgItem(hwndParentDlg, IDCANCEL), &rectCancel); + /* subtract the height of the help button plus the space between + * the help button and the cancel button to the height of the dialog + */ + help_fixup = rectHelp.bottom - rectCancel.bottom; + } + + /* + There are two possibilities to add components to the default file dialog box. + + By default, all the new components are added below the standard dialog box (the else case). + + However, if there is a static text component with the stc32 id, a special case happens. + The x and y coordinates of stc32 indicate the top left corner where to place the standard file dialog box + in the window and the cx and cy indicate how to size the window. + Moreover, if the new component's coordinates are on the left of the stc32 , it is placed on the left + of the standard file dialog box. If they are above the stc32 component, it is placed above and so on.... + + */ + + GetClientRect(hwndParentDlg, &rectParent); + + /* when arranging controls we have to use fixed parent size */ + rectParent.bottom -= help_fixup; + + hwndStc32 = GetDlgItem(hwndChildDlg, stc32); + if (hwndStc32) + { + GetWindowRect(hwndStc32, &rectStc32); + MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectStc32, 2); + + /* set the size of the stc32 control according to the size of + * client area of the parent dialog + */ + SetWindowPos(hwndStc32, 0, + 0, 0, + rectParent.right, rectParent.bottom, + SWP_NOMOVE | SWP_NOZORDER); + } + else + SetRectEmpty(&rectStc32); + + /* this part moves controls of the child dialog */ + hwndChild = GetWindow(hwndChildDlg, GW_CHILD); + while (hwndChild) + { + if (hwndChild != hwndStc32) + { + GetWindowRect(hwndChild, &rectChild); + MapWindowPoints(0, hwndChildDlg, (LPPOINT)&rectChild, 2); + + /* move only if stc32 exist */ + if (hwndStc32 && rectChild.left > rectStc32.right) + { + LONG old_left = rectChild.left; + + /* move to the right of visible controls of the parent dialog */ + rectChild.left += rectParent.right; + rectChild.left -= rectStc32.right; + + child_width_fixup = rectChild.left - old_left; + } + /* move even if stc32 doesn't exist */ + if (rectChild.top >= rectStc32.bottom) + { + LONG old_top = rectChild.top; + + /* move below visible controls of the parent dialog */ + rectChild.top += rectParent.bottom; + rectChild.top -= rectStc32.bottom - rectStc32.top; + + child_height_fixup = rectChild.top - old_top; + } + + SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top, + 0, 0, SWP_NOSIZE | SWP_NOZORDER); + } + hwndChild = GetWindow(hwndChild, GW_HWNDNEXT); + } + + /* this part moves controls of the parent dialog */ + hwndChild = GetWindow(hwndParentDlg, GW_CHILD); + while (hwndChild) + { + if (hwndChild != hwndChildDlg) + { + GetWindowRect(hwndChild, &rectChild); + MapWindowPoints(0, hwndParentDlg, (LPPOINT)&rectChild, 2); + + /* left,top of stc32 marks the position of controls + * from the parent dialog + */ + rectChild.left += rectStc32.left; + rectChild.top += rectStc32.top; + + SetWindowPos(hwndChild, 0, rectChild.left, rectChild.top, + 0, 0, SWP_NOSIZE | SWP_NOZORDER); + } + hwndChild = GetWindow(hwndChild, GW_HWNDNEXT); + } + + /* calculate the size of the resulting dialog */ + + /* here we have to use original parent size */ + GetClientRect(hwndParentDlg, &rectParent); + GetClientRect(hwndChildDlg, &rectChild); + + if (hwndStc32) + { + rectChild.right += child_width_fixup; + rectChild.bottom += child_height_fixup; + + if (rectParent.right > rectChild.right) + { + rectParent.right += rectChild.right; + rectParent.right -= rectStc32.right - rectStc32.left; + } + else + { + rectParent.right = rectChild.right; + } + + if (rectParent.bottom > rectChild.bottom) + { + rectParent.bottom += rectChild.bottom; + rectParent.bottom -= rectStc32.bottom - rectStc32.top; + } + else + { + /* child dialog is higher, unconditionally set new dialog + * height to its size (help_fixup will be subtracted below) + */ + rectParent.bottom = rectChild.bottom + help_fixup; + } + } + else + { + rectParent.bottom += rectChild.bottom; + } + + /* finally use fixed parent size */ + rectParent.bottom -= help_fixup; + + /* save the size of the parent's client area */ + rectChild.right = rectParent.right; + rectChild.bottom = rectParent.bottom; + + /* set the size of the parent dialog */ + AdjustWindowRectEx(&rectParent, GetWindowLongW(hwndParentDlg, GWL_STYLE), + FALSE, GetWindowLongW(hwndParentDlg, GWL_EXSTYLE)); + SetWindowPos(hwndParentDlg, 0, + 0, 0, + rectParent.right - rectParent.left, + rectParent.bottom - rectParent.top, + SWP_NOMOVE | SWP_NOZORDER); + + /* set the size of the child dialog */ + SetWindowPos(hwndChildDlg, HWND_BOTTOM, + 0, 0, rectChild.right, rectChild.bottom, SWP_NOACTIVATE); +} + +INT_PTR CALLBACK FileOpenDlgProcUserTemplate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) { + case WM_INITDIALOG: + return TRUE; + } + return FALSE; +} + +HWND CreateTemplateDialog(FileOpenDlgInfos *fodInfos, HWND hwnd) +{ + LPCVOID template; + HRSRC hRes; + HANDLE hDlgTmpl = 0; + HWND hChildDlg = 0; + + TRACE("\n"); + + /* + * If OFN_ENABLETEMPLATEHANDLE is specified, the OPENFILENAME + * structure's hInstance parameter is not a HINSTANCE, but + * instead a pointer to a template resource to use. + */ + if (fodInfos->ofnInfos->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)) + { + HINSTANCE hinst; + if (fodInfos->ofnInfos->Flags & OFN_ENABLETEMPLATEHANDLE) + { + hinst = 0; + if( !(template = LockResource( fodInfos->ofnInfos->hInstance))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return NULL; + } + } + else + { + hinst = fodInfos->ofnInfos->hInstance; + if(fodInfos->unicode) + { + LPOPENFILENAMEW ofn = fodInfos->ofnInfos; + hRes = FindResourceW( hinst, ofn->lpTemplateName, (LPWSTR)RT_DIALOG); + } + else + { + LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos; + hRes = FindResourceA( hinst, ofn->lpTemplateName, (LPSTR)RT_DIALOG); + } + if (!hRes) + { + COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); + return NULL; + } + if (!(hDlgTmpl = LoadResource( hinst, hRes )) || + !(template = LockResource( hDlgTmpl ))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return NULL; + } + } + hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, template, hwnd, + IsHooked(fodInfos) ? (DLGPROC)fodInfos->ofnInfos->lpfnHook : FileOpenDlgProcUserTemplate, + (LPARAM)fodInfos->ofnInfos); + if(hChildDlg) + { + ShowWindow(hChildDlg,SW_SHOW); + return hChildDlg; + } + } + else if( IsHooked(fodInfos)) + { + RECT rectHwnd; + struct { + DLGTEMPLATE tmplate; + WORD menu,class,title; + } temp; + GetClientRect(hwnd,&rectHwnd); + temp.tmplate.style = WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | DS_CONTROL | DS_3DLOOK; + temp.tmplate.dwExtendedStyle = 0; + temp.tmplate.cdit = 0; + temp.tmplate.x = 0; + temp.tmplate.y = 0; + temp.tmplate.cx = 0; + temp.tmplate.cy = 0; + temp.menu = temp.class = temp.title = 0; + + hChildDlg = CreateDialogIndirectParamA(COMDLG32_hInstance, &temp.tmplate, + hwnd, (DLGPROC)fodInfos->ofnInfos->lpfnHook, (LPARAM)fodInfos->ofnInfos); + + return hChildDlg; + } + return NULL; +} + +/*********************************************************************** +* SendCustomDlgNotificationMessage +* +* Send CustomDialogNotification (CDN_FIRST -- CDN_LAST) message to the custom template dialog +*/ + +void SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode) +{ + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndParentDlg,FileOpenDlgInfosStr); + + TRACE("%p 0x%04x\n",hwndParentDlg, uCode); + + if(!fodInfos) return; + + if(fodInfos->DlgInfos.hwndCustomDlg) + { + TRACE("CALL NOTIFY for %x\n", uCode); + if(fodInfos->unicode) + { + OFNOTIFYW ofnNotify; + ofnNotify.hdr.hwndFrom=hwndParentDlg; + ofnNotify.hdr.idFrom=0; + ofnNotify.hdr.code = uCode; + ofnNotify.lpOFN = fodInfos->ofnInfos; + ofnNotify.pszFile = NULL; + SendMessageW(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify); + } + else + { + OFNOTIFYA ofnNotify; + ofnNotify.hdr.hwndFrom=hwndParentDlg; + ofnNotify.hdr.idFrom=0; + ofnNotify.hdr.code = uCode; + ofnNotify.lpOFN = (LPOPENFILENAMEA)fodInfos->ofnInfos; + ofnNotify.pszFile = NULL; + SendMessageA(fodInfos->DlgInfos.hwndCustomDlg,WM_NOTIFY,0,(LPARAM)&ofnNotify); + } + TRACE("RET NOTIFY\n"); + } +} + +static INT_PTR FILEDLG95_Handle_GetFilePath(HWND hwnd, DWORD size, LPVOID buffer) +{ + INT_PTR sizeUsed = 0, n, total; + LPWSTR lpstrFileList = NULL; + WCHAR lpstrCurrentDir[MAX_PATH]; + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); + + TRACE("CDM_GETFILEPATH:\n"); + + if ( ! (fodInfos->ofnInfos->Flags & OFN_EXPLORER ) ) + return -1; + + /* get path and filenames */ + COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrCurrentDir); + n = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' '); + + TRACE("path >%s< filespec >%s< %d files\n", + debugstr_w(lpstrCurrentDir),debugstr_w(lpstrFileList),n); + + if( fodInfos->unicode ) + { + LPWSTR bufW = buffer; + total = strlenW(lpstrCurrentDir) + 1 + sizeUsed; + + /* Prepend the current path */ + n = strlenW(lpstrCurrentDir) + 1; + memcpy( bufW, lpstrCurrentDir, min(n,size) * sizeof(WCHAR)); + if(n %s\n",debugstr_wn(bufW, total)); + } + else + { + LPSTR bufA = buffer; + total = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1, + NULL, 0, NULL, NULL); + total += WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed, + NULL, 0, NULL, NULL); + + /* Prepend the current path */ + n = WideCharToMultiByte(CP_ACP, 0, lpstrCurrentDir, -1, + bufA, size, NULL, NULL); + + if(n %s\n",debugstr_an(bufA, total)); + } + MemFree(lpstrFileList); + + return total; +} + +static INT_PTR FILEDLG95_Handle_GetFileSpec(HWND hwnd, DWORD size, LPVOID buffer) +{ + INT_PTR sizeUsed = 0; + LPWSTR lpstrFileList = NULL; + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); + + TRACE("CDM_GETSPEC:\n"); + + FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, ' '); + if( fodInfos->unicode ) + { + LPWSTR bufW = buffer; + memcpy( bufW, lpstrFileList, sizeof(WCHAR)*sizeUsed ); + } + else + { + LPSTR bufA = buffer; + sizeUsed = WideCharToMultiByte( CP_ACP, 0, lpstrFileList, sizeUsed, + NULL, 0, NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed, + bufA, size, NULL, NULL); + } + MemFree(lpstrFileList); + + return sizeUsed; +} + +/*********************************************************************** +* FILEDLG95_HandleCustomDialogMessages +* +* Handle Custom Dialog Messages (CDM_FIRST -- CDM_LAST) messages +*/ +static INT_PTR FILEDLG95_HandleCustomDialogMessages(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); + WCHAR lpstrPath[MAX_PATH]; + INT_PTR retval; + + if(!fodInfos) return FALSE; + + switch(uMsg) + { + case CDM_GETFILEPATH: + retval = FILEDLG95_Handle_GetFilePath(hwnd, (UINT)wParam, (LPVOID)lParam); + break; + + case CDM_GETFOLDERPATH: + TRACE("CDM_GETFOLDERPATH:\n"); + COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPath); + if (lParam) + { + if (fodInfos->unicode) + lstrcpynW((LPWSTR)lParam, lpstrPath, (int)wParam); + else + WideCharToMultiByte(CP_ACP, 0, lpstrPath, -1, + (LPSTR)lParam, (int)wParam, NULL, NULL); + } + retval = strlenW(lpstrPath); + break; + + case CDM_GETSPEC: + retval = FILEDLG95_Handle_GetFileSpec(hwnd, (UINT)wParam, (LPSTR)lParam); + break; + + case CDM_SETCONTROLTEXT: + TRACE("CDM_SETCONTROLTEXT:\n"); + if ( lParam ) + { + if( fodInfos->unicode ) + SetDlgItemTextW( hwnd, (UINT) wParam, (LPWSTR) lParam ); + else + SetDlgItemTextA( hwnd, (UINT) wParam, (LPSTR) lParam ); + } + retval = TRUE; + break; + + case CDM_HIDECONTROL: + case CDM_SETDEFEXT: + FIXME("CDM_HIDECONTROL,CDM_SETCONTROLTEXT,CDM_SETDEFEXT not implemented\n"); + retval = -1; + break; + + default: + return FALSE; + } + SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, retval); + return TRUE; +} + +/*********************************************************************** + * FileOpenDlgProc95 + * + * File open dialog procedure + */ +INT_PTR CALLBACK FileOpenDlgProc95(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ +#if 0 + TRACE("0x%04x 0x%04x\n", hwnd, uMsg); +#endif + + switch(uMsg) + { + case WM_INITDIALOG: + { + FileOpenDlgInfos * fodInfos = (FileOpenDlgInfos *)lParam; + + /* Adds the FileOpenDlgInfos in the property list of the dialog + so it will be easily accessible through a GetPropA(...) */ + SetPropA(hwnd, FileOpenDlgInfosStr, (HANDLE) fodInfos); + + fodInfos->DlgInfos.hwndCustomDlg = + CreateTemplateDialog((FileOpenDlgInfos *)lParam, hwnd); + + FILEDLG95_InitControls(hwnd); + + if (fodInfos->DlgInfos.hwndCustomDlg) + ArrangeCtrlPositions(fodInfos->DlgInfos.hwndCustomDlg, hwnd, + (fodInfos->ofnInfos->Flags & (OFN_HIDEREADONLY | OFN_SHOWHELP)) == OFN_HIDEREADONLY); + + FILEDLG95_FillControls(hwnd, wParam, lParam); + + SendCustomDlgNotificationMessage(hwnd,CDN_INITDONE); + SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE); + SendCustomDlgNotificationMessage(hwnd,CDN_SELCHANGE); + return 0; + } + case WM_COMMAND: + return FILEDLG95_OnWMCommand(hwnd, wParam, lParam); + case WM_DRAWITEM: + { + switch(((LPDRAWITEMSTRUCT)lParam)->CtlID) + { + case IDC_LOOKIN: + FILEDLG95_LOOKIN_DrawItem((LPDRAWITEMSTRUCT) lParam); + return TRUE; + } + } + return FALSE; + + case WM_GETISHELLBROWSER: + return FILEDLG95_OnWMGetIShellBrowser(hwnd); + + case WM_DESTROY: + RemovePropA(hwnd, FileOpenDlgInfosStr); + return FALSE; + + case WM_NOTIFY: + { + LPNMHDR lpnmh = (LPNMHDR)lParam; + UINT stringId = -1; + + /* set up the button tooltips strings */ + if(TTN_GETDISPINFOA == lpnmh->code ) + { + LPNMTTDISPINFOA lpdi = (LPNMTTDISPINFOA)lParam; + switch(lpnmh->idFrom ) + { + /* Up folder button */ + case FCIDM_TB_UPFOLDER: + stringId = IDS_UPFOLDER; + break; + /* New folder button */ + case FCIDM_TB_NEWFOLDER: + stringId = IDS_NEWFOLDER; + break; + /* List option button */ + case FCIDM_TB_SMALLICON: + stringId = IDS_LISTVIEW; + break; + /* Details option button */ + case FCIDM_TB_REPORTVIEW: + stringId = IDS_REPORTVIEW; + break; + /* Desktop button */ + case FCIDM_TB_DESKTOP: + stringId = IDS_TODESKTOP; + break; + default: + stringId = 0; + } + lpdi->hinst = COMDLG32_hInstance; + lpdi->lpszText = (LPSTR) stringId; + } + return FALSE; + } + default : + if(uMsg >= CDM_FIRST && uMsg <= CDM_LAST) + return FILEDLG95_HandleCustomDialogMessages(hwnd, uMsg, wParam, lParam); + return FALSE; + } +} + +/*********************************************************************** + * FILEDLG95_InitControls + * + * WM_INITDIALOG message handler (before hook notification) + */ +static LRESULT FILEDLG95_InitControls(HWND hwnd) +{ + int win2000plus = 0; + int win98plus = 0; + int handledPath = FALSE; + OSVERSIONINFOA osVi; + static const WCHAR szwSlash[] = { '\\', 0 }; + static const WCHAR szwStar[] = { '*',0 }; + + TBBUTTON tbb[] = + { + {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 }, + {VIEW_PARENTFOLDER, FCIDM_TB_UPFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 }, + {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 }, + {VIEW_NEWFOLDER+1, FCIDM_TB_DESKTOP, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 }, + {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 }, + {VIEW_NEWFOLDER, FCIDM_TB_NEWFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 }, + {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0 }, + {VIEW_LIST, FCIDM_TB_SMALLICON, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 }, + {VIEW_DETAILS, FCIDM_TB_REPORTVIEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0 }, + }; + TBADDBITMAP tba[2]; + RECT rectTB; + RECT rectlook; + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); + + tba[0].hInst = HINST_COMMCTRL; + tba[0].nID = IDB_VIEW_SMALL_COLOR; + tba[1].hInst = COMDLG32_hInstance; + tba[1].nID = 800; + + TRACE("%p\n", fodInfos); + + /* Get windows version emulating */ + osVi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); + GetVersionExA(&osVi); + if (osVi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { + win98plus = ((osVi.dwMajorVersion > 4) || ((osVi.dwMajorVersion == 4) && (osVi.dwMinorVersion > 0))); + } else if (osVi.dwPlatformId == VER_PLATFORM_WIN32_NT) { + win2000plus = (osVi.dwMajorVersion > 4); + if (win2000plus) win98plus = TRUE; + } + TRACE("Running on 2000+ %d, 98+ %d\n", win2000plus, win98plus); + + /* Get the hwnd of the controls */ + fodInfos->DlgInfos.hwndFileName = GetDlgItem(hwnd,IDC_FILENAME); + fodInfos->DlgInfos.hwndFileTypeCB = GetDlgItem(hwnd,IDC_FILETYPE); + fodInfos->DlgInfos.hwndLookInCB = GetDlgItem(hwnd,IDC_LOOKIN); + + GetWindowRect( fodInfos->DlgInfos.hwndLookInCB,&rectlook); + MapWindowPoints( 0, hwnd,(LPPOINT)&rectlook,2); + + /* construct the toolbar */ + GetWindowRect(GetDlgItem(hwnd,IDC_TOOLBARSTATIC),&rectTB); + MapWindowPoints( 0, hwnd,(LPPOINT)&rectTB,2); + + rectTB.right = rectlook.right + rectTB.right - rectTB.left; + rectTB.bottom = rectlook.top - 1 + rectTB.bottom - rectTB.top; + rectTB.left = rectlook.right; + rectTB.top = rectlook.top-1; + + fodInfos->DlgInfos.hwndTB = CreateWindowExA(0, TOOLBARCLASSNAMEA, NULL, + WS_CHILD | WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS | CCS_NODIVIDER | CCS_NORESIZE, + rectTB.left, rectTB.top, + rectTB.right - rectTB.left, rectTB.bottom - rectTB.top, + hwnd, (HMENU)IDC_TOOLBAR, COMDLG32_hInstance, NULL); + + SendMessageA(fodInfos->DlgInfos.hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0); + +/* FIXME: use TB_LOADIMAGES when implemented */ +/* SendMessageA(fodInfos->DlgInfos.hwndTB, TB_LOADIMAGES, (WPARAM) IDB_VIEW_SMALL_COLOR, HINST_COMMCTRL);*/ + SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 12, (LPARAM) &tba[0]); + SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBITMAP, (WPARAM) 1, (LPARAM) &tba[1]); + + SendMessageA(fodInfos->DlgInfos.hwndTB, TB_ADDBUTTONSA, (WPARAM) 9,(LPARAM) &tbb); + SendMessageA(fodInfos->DlgInfos.hwndTB, TB_AUTOSIZE, 0, 0); + + /* Set the window text with the text specified in the OPENFILENAME structure */ + if(fodInfos->title) + { + SetWindowTextW(hwnd,fodInfos->title); + } + else if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) + { + WCHAR buf[16]; + LoadStringW(COMDLG32_hInstance, IDS_SAVE, buf, sizeof(buf)/sizeof(WCHAR)); + SetWindowTextW(hwnd, buf); + } + + /* Initialise the file name edit control */ + handledPath = FALSE; + TRACE("Before manipilation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir)); + + if(fodInfos->filename) + { + /* 1. If win2000 or higher and filename contains a path, use it + in preference over the lpstrInitialDir */ + if (win2000plus && *fodInfos->filename && strpbrkW(fodInfos->filename, szwSlash)) { + WCHAR tmpBuf[MAX_PATH]; + WCHAR *nameBit; + DWORD result; + + result = GetFullPathNameW(fodInfos->filename, MAX_PATH, tmpBuf, &nameBit); + if (result) { + + /* nameBit is always shorter than the original filename */ + strcpyW(fodInfos->filename,nameBit); + + *nameBit = 0x00; + if (fodInfos->initdir == NULL) + MemFree(fodInfos->initdir); + fodInfos->initdir = MemAlloc((strlenW(tmpBuf) + 1)*sizeof(WCHAR)); + strcpyW(fodInfos->initdir, tmpBuf); + handledPath = TRUE; + TRACE("Value in Filename includes path, overriding InitialDir: %s, %s\n", + debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir)); + } + SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename); + + } else { + SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename); + } + } + + /* 2. (All platforms) If initdir is not null, then use it */ + if ((handledPath == FALSE) && (fodInfos->initdir!=NULL) && + (*fodInfos->initdir!=0x00)) + { + /* Work out the proper path as supplied one might be relative */ + /* (Here because supplying '.' as dir browses to My Computer) */ + if (handledPath==FALSE) { + WCHAR tmpBuf[MAX_PATH]; + WCHAR tmpBuf2[MAX_PATH]; + WCHAR *nameBit; + DWORD result; + + strcpyW(tmpBuf, fodInfos->initdir); + if( PathFileExistsW(tmpBuf) ) { + /* initdir does not have to be a directory. If a file is + * specified, the dir part is taken */ + if( PathIsDirectoryW(tmpBuf)) { + if (tmpBuf[strlenW(tmpBuf)-1] != '\\') { + strcatW(tmpBuf, szwSlash); + } + strcatW(tmpBuf, szwStar); + } + result = GetFullPathNameW(tmpBuf, MAX_PATH, tmpBuf2, &nameBit); + if (result) { + *nameBit = 0x00; + if (fodInfos->initdir) + MemFree(fodInfos->initdir); + fodInfos->initdir = MemAlloc((strlenW(tmpBuf2) + 1)*sizeof(WCHAR)); + strcpyW(fodInfos->initdir, tmpBuf2); + handledPath = TRUE; + TRACE("Value in InitDir changed to %s\n", debugstr_w(fodInfos->initdir)); + } + } + else if (fodInfos->initdir) + { + MemFree(fodInfos->initdir); + fodInfos->initdir = NULL; + TRACE("Value in InitDir is not an existing path, changed to (nil)\n"); + } + } + } + + if ((handledPath == FALSE) && ((fodInfos->initdir==NULL) || + (*fodInfos->initdir==0x00))) + { + /* 3. All except w2k+: if filename contains a path use it */ + if (!win2000plus && fodInfos->filename && + *fodInfos->filename && + strpbrkW(fodInfos->filename, szwSlash)) { + WCHAR tmpBuf[MAX_PATH]; + WCHAR *nameBit; + DWORD result; + + result = GetFullPathNameW(fodInfos->filename, MAX_PATH, + tmpBuf, &nameBit); + if (result) { + int len; + + /* nameBit is always shorter than the original filename */ + strcpyW(fodInfos->filename, nameBit); + *nameBit = 0x00; + + len = strlenW(tmpBuf); + if(fodInfos->initdir) + MemFree(fodInfos->initdir); + fodInfos->initdir = MemAlloc((len+1)*sizeof(WCHAR)); + strcpyW(fodInfos->initdir, tmpBuf); + + handledPath = TRUE; + TRACE("Value in Filename includes path, overriding initdir: %s, %s\n", + debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir)); + } + SetDlgItemTextW(hwnd, IDC_FILENAME, fodInfos->filename); + } + + /* 4. win98+ and win2000+ if any files of specified filter types in + current directory, use it */ + if ( win98plus && handledPath == FALSE && + fodInfos->filter && *fodInfos->filter) { + + BOOL searchMore = TRUE; + LPCWSTR lpstrPos = fodInfos->filter; + WIN32_FIND_DATAW FindFileData; + HANDLE hFind; + + while (searchMore) + { + /* filter is a list... title\0ext\0......\0\0 */ + + /* Skip the title */ + if(! *lpstrPos) break; /* end */ + lpstrPos += strlenW(lpstrPos) + 1; + + /* See if any files exist in the current dir with this extension */ + if(! *lpstrPos) break; /* end */ + + hFind = FindFirstFileW(lpstrPos, &FindFileData); + + if (hFind == INVALID_HANDLE_VALUE) { + /* None found - continue search */ + lpstrPos += strlenW(lpstrPos) + 1; + + } else { + searchMore = FALSE; + + if(fodInfos->initdir) + MemFree(fodInfos->initdir); + fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR)); + GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir); + + handledPath = TRUE; + TRACE("No initial dir specified, but files of type %s found in current, so using it\n", + debugstr_w(lpstrPos)); + break; + } + } + } + + /* 5. Win2000+: FIXME: Next, Recently used? Not sure how windows does this */ + + /* 6. Win98+ and 2000+: Use personal files dir, others use current dir */ + if (handledPath == FALSE && (win2000plus || win98plus)) { + fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR)); + + if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_PERSONAL, 0, 0, fodInfos->initdir))) + { + if(FAILED(COMDLG32_SHGetFolderPathW(hwnd, CSIDL_DESKTOPDIRECTORY|CSIDL_FLAG_CREATE, 0, 0, fodInfos->initdir))) + { + /* last fallback */ + GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir); + TRACE("No personal or desktop dir, using cwd as failsafe: %s\n", debugstr_w(fodInfos->initdir)); + } else { + TRACE("No personal dir, using desktop instead: %s\n", debugstr_w(fodInfos->initdir)); + } + } else { + TRACE("No initial dir specified, using personal files dir of %s\n", debugstr_w(fodInfos->initdir)); + } + handledPath = TRUE; + } else if (handledPath==FALSE) { + fodInfos->initdir = MemAlloc(MAX_PATH*sizeof(WCHAR)); + GetCurrentDirectoryW(MAX_PATH, fodInfos->initdir); + handledPath = TRUE; + TRACE("No initial dir specified, using current dir of %s\n", debugstr_w(fodInfos->initdir)); + } + } + SetFocus(GetDlgItem(hwnd, IDC_FILENAME)); + TRACE("After manipulation, file = %s, dir = %s\n", debugstr_w(fodInfos->filename), debugstr_w(fodInfos->initdir)); + + /* Must the open as read only check box be checked ?*/ + if(fodInfos->ofnInfos->Flags & OFN_READONLY) + { + SendDlgItemMessageA(hwnd,IDC_OPENREADONLY,BM_SETCHECK,(WPARAM)TRUE,0); + } + + /* Must the open as read only check box be hidden? */ + if(fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) + { + ShowWindow(GetDlgItem(hwnd,IDC_OPENREADONLY),SW_HIDE); + EnableWindow(GetDlgItem(hwnd, IDC_OPENREADONLY), FALSE); + } + + /* Must the help button be hidden? */ + if (!(fodInfos->ofnInfos->Flags & OFN_SHOWHELP)) + { + ShowWindow(GetDlgItem(hwnd, pshHelp), SW_HIDE); + EnableWindow(GetDlgItem(hwnd, pshHelp), FALSE); + } + + /* Resize the height, if open as read only checkbox ad help button + are hidden and we are not using a custom template nor a customDialog + */ + if ( (fodInfos->ofnInfos->Flags & OFN_HIDEREADONLY) && + (!(fodInfos->ofnInfos->Flags & + (OFN_SHOWHELP|OFN_ENABLETEMPLATE|OFN_ENABLETEMPLATEHANDLE))) && + (!fodInfos->DlgInfos.hwndCustomDlg )) + { + RECT rectDlg, rectHelp, rectCancel; + GetWindowRect(hwnd, &rectDlg); + GetWindowRect(GetDlgItem(hwnd, pshHelp), &rectHelp); + GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rectCancel); + /* subtract the height of the help button plus the space between + the help button and the cancel button to the height of the dialog */ + SetWindowPos(hwnd, 0, 0, 0, rectDlg.right-rectDlg.left, + (rectDlg.bottom-rectDlg.top) - (rectHelp.bottom - rectCancel.bottom), + SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER); + } + /* change Open to Save */ + if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) + { + WCHAR buf[16]; + LoadStringW(COMDLG32_hInstance, IDS_SAVE_BUTTON, buf, sizeof(buf)/sizeof(WCHAR)); + SetDlgItemTextW(hwnd, IDOK, buf); + LoadStringW(COMDLG32_hInstance, IDS_SAVE_IN, buf, sizeof(buf)/sizeof(WCHAR)); + SetDlgItemTextW(hwnd, IDC_LOOKINSTATIC, buf); + } + return 0; +} + +/*********************************************************************** + * FILEDLG95_FillControls + * + * WM_INITDIALOG message handler (after hook notification) + */ +static LRESULT FILEDLG95_FillControls(HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + LPITEMIDLIST pidlItemId = NULL; + + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) lParam; + + TRACE("dir=%s file=%s\n", + debugstr_w(fodInfos->initdir), debugstr_w(fodInfos->filename)); + + /* Get the initial directory pidl */ + + if(!(pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder,fodInfos->initdir))) + { + WCHAR path[MAX_PATH]; + + GetCurrentDirectoryW(MAX_PATH,path); + pidlItemId = GetPidlFromName(fodInfos->Shell.FOIShellFolder, path); + } + + /* Initialise shell objects */ + FILEDLG95_SHELL_Init(hwnd); + + /* Initialize the Look In combo box */ + FILEDLG95_LOOKIN_Init(fodInfos->DlgInfos.hwndLookInCB); + + /* Initialize the filter combo box */ + FILEDLG95_FILETYPE_Init(hwnd); + + /* Browse to the initial directory */ + IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser,pidlItemId, SBSP_ABSOLUTE); + + /* Free pidlItem memory */ + COMDLG32_SHFree(pidlItemId); + + return TRUE; +} +/*********************************************************************** + * FILEDLG95_Clean + * + * Regroups all the cleaning functions of the filedlg + */ +void FILEDLG95_Clean(HWND hwnd) +{ + FILEDLG95_FILETYPE_Clean(hwnd); + FILEDLG95_LOOKIN_Clean(hwnd); + FILEDLG95_SHELL_Clean(hwnd); +} +/*********************************************************************** + * FILEDLG95_OnWMCommand + * + * WM_COMMAND message handler + */ +static LRESULT FILEDLG95_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + WORD wNotifyCode = HIWORD(wParam); /* notification code */ + WORD wID = LOWORD(wParam); /* item, control, or accelerator identifier */ + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); + + switch(wID) + { + /* OK button */ + case IDOK: + FILEDLG95_OnOpen(hwnd); + break; + /* Cancel button */ + case IDCANCEL: + FILEDLG95_Clean(hwnd); + EndDialog(hwnd, FALSE); + break; + /* Filetype combo box */ + case IDC_FILETYPE: + FILEDLG95_FILETYPE_OnCommand(hwnd,wNotifyCode); + break; + /* LookIn combo box */ + case IDC_LOOKIN: + FILEDLG95_LOOKIN_OnCommand(hwnd,wNotifyCode); + break; + + /* --- toolbar --- */ + /* Up folder button */ + case FCIDM_TB_UPFOLDER: + FILEDLG95_SHELL_UpFolder(hwnd); + break; + /* New folder button */ + case FCIDM_TB_NEWFOLDER: + FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_NEWFOLDERA); + break; + /* List option button */ + case FCIDM_TB_SMALLICON: + FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWLISTA); + break; + /* Details option button */ + case FCIDM_TB_REPORTVIEW: + FILEDLG95_SHELL_ExecuteCommand(hwnd,CMDSTR_VIEWDETAILSA); + break; + /* Details option button */ + case FCIDM_TB_DESKTOP: + FILEDLG95_SHELL_BrowseToDesktop(hwnd); + break; + + case IDC_FILENAME: + break; + + } + /* Do not use the listview selection anymore */ + fodInfos->DlgInfos.dwDlgProp &= ~FODPROP_USEVIEW; + return 0; +} + +/*********************************************************************** + * FILEDLG95_OnWMGetIShellBrowser + * + * WM_GETISHELLBROWSER message handler + */ +static LRESULT FILEDLG95_OnWMGetIShellBrowser(HWND hwnd) +{ + + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); + + TRACE("\n"); + + SetWindowLongPtrW(hwnd,DWLP_MSGRESULT,(LONG_PTR)fodInfos->Shell.FOIShellBrowser); + + return TRUE; +} + + +/*********************************************************************** + * FILEDLG95_SendFileOK + * + * Sends the CDN_FILEOK notification if required + * + * RETURNS + * TRUE if the dialog should close + * FALSE if the dialog should not be closed + */ +static BOOL FILEDLG95_SendFileOK( HWND hwnd, FileOpenDlgInfos *fodInfos ) +{ + /* ask the hook if we can close */ + if(IsHooked(fodInfos)) + { + TRACE("---\n"); + /* First send CDN_FILEOK as MSDN doc says */ + SendCustomDlgNotificationMessage(hwnd,CDN_FILEOK); + if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT)) + { + TRACE("canceled\n"); + return FALSE; + } + + /* fodInfos->ofnInfos points to an ASCII or UNICODE structure as appropriate */ + SendMessageW(fodInfos->DlgInfos.hwndCustomDlg, + fodInfos->HookMsg.fileokstring, 0, (LPARAM)fodInfos->ofnInfos); + if (GetWindowLongPtrW(fodInfos->DlgInfos.hwndCustomDlg, DWLP_MSGRESULT)) + { + TRACE("canceled\n"); + return FALSE; + } + } + return TRUE; +} + +/*********************************************************************** + * FILEDLG95_OnOpenMultipleFiles + * + * Handles the opening of multiple files. + * + * FIXME + * check destination buffer size + */ +BOOL FILEDLG95_OnOpenMultipleFiles(HWND hwnd, LPWSTR lpstrFileList, UINT nFileCount, UINT sizeUsed) +{ + WCHAR lpstrPathSpec[MAX_PATH] = {0}; + UINT nCount, nSizePath; + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); + + TRACE("\n"); + + if(fodInfos->unicode) + { + LPOPENFILENAMEW ofn = fodInfos->ofnInfos; + ofn->lpstrFile[0] = '\0'; + } + else + { + LPOPENFILENAMEA ofn = (LPOPENFILENAMEA) fodInfos->ofnInfos; + ofn->lpstrFile[0] = '\0'; + } + + COMDLG32_GetDisplayNameOf( fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathSpec ); + + if ( !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE) && + ( fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) && + ! ( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) ) + { + LPWSTR lpstrTemp = lpstrFileList; + + for ( nCount = 0; nCount < nFileCount; nCount++ ) + { + LPITEMIDLIST pidl; + + pidl = GetPidlFromName(fodInfos->Shell.FOIShellFolder, lpstrTemp); + if (!pidl) + { + WCHAR lpstrNotFound[100]; + WCHAR lpstrMsg[100]; + WCHAR tmp[400]; + static const WCHAR nl[] = {'\n',0}; + + LoadStringW(COMDLG32_hInstance, IDS_FILENOTFOUND, lpstrNotFound, 100); + LoadStringW(COMDLG32_hInstance, IDS_VERIFYFILE, lpstrMsg, 100); + + strcpyW(tmp, lpstrTemp); + strcatW(tmp, nl); + strcatW(tmp, lpstrNotFound); + strcatW(tmp, nl); + strcatW(tmp, lpstrMsg); + + MessageBoxW(hwnd, tmp, fodInfos->title, MB_OK | MB_ICONEXCLAMATION); + return FALSE; + } + + /* move to the next file in the list of files */ + lpstrTemp += strlenW(lpstrTemp) + 1; + COMDLG32_SHFree(pidl); + } + } + + nSizePath = strlenW(lpstrPathSpec) + 1; + if ( !(fodInfos->ofnInfos->Flags & OFN_EXPLORER) ) + { + /* For "oldstyle" dialog the components have to + be separated by blanks (not '\0'!) and short + filenames have to be used! */ + FIXME("Components have to be separated by blanks\n"); + } + if(fodInfos->unicode) + { + LPOPENFILENAMEW ofn = fodInfos->ofnInfos; + strcpyW( ofn->lpstrFile, lpstrPathSpec); + memcpy( ofn->lpstrFile + nSizePath, lpstrFileList, sizeUsed*sizeof(WCHAR) ); + } + else + { + LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos; + + if (ofn->lpstrFile != NULL) + { + nSizePath = WideCharToMultiByte(CP_ACP, 0, lpstrPathSpec, -1, + ofn->lpstrFile, ofn->nMaxFile, NULL, NULL); + if (ofn->nMaxFile > nSizePath) + { + WideCharToMultiByte(CP_ACP, 0, lpstrFileList, sizeUsed, + ofn->lpstrFile + nSizePath, + ofn->nMaxFile - nSizePath, NULL, NULL); + } + } + } + + fodInfos->ofnInfos->nFileOffset = nSizePath; + fodInfos->ofnInfos->nFileExtension = 0; + + if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) ) + return FALSE; + + /* clean and exit */ + FILEDLG95_Clean(hwnd); + return EndDialog(hwnd,TRUE); +} + +/*********************************************************************** + * FILEDLG95_OnOpen + * + * Ok button WM_COMMAND message handler + * + * If the function succeeds, the return value is nonzero. + */ +#define ONOPEN_OPEN 1 +#define ONOPEN_SEARCH 2 +static void FILEDLG95_OnOpenMessage(HWND hwnd, int idCaption, int idText) +{ + WCHAR strMsgTitle[MAX_PATH]; + WCHAR strMsgText [MAX_PATH]; + if (idCaption) + LoadStringW(COMDLG32_hInstance, idCaption, strMsgTitle, sizeof(strMsgTitle)/sizeof(WCHAR)); + else + strMsgTitle[0] = '\0'; + LoadStringW(COMDLG32_hInstance, idText, strMsgText, sizeof(strMsgText)/sizeof(WCHAR)); + MessageBoxW(hwnd,strMsgText, strMsgTitle, MB_OK | MB_ICONHAND); +} + +BOOL FILEDLG95_OnOpen(HWND hwnd) +{ + LPWSTR lpstrFileList; + UINT nFileCount = 0; + UINT sizeUsed = 0; + BOOL ret = TRUE; + WCHAR lpstrPathAndFile[MAX_PATH]; + WCHAR lpstrTemp[MAX_PATH]; + LPSHELLFOLDER lpsf = NULL; + int nOpenAction; + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); + + TRACE("hwnd=%p\n", hwnd); + + if(BrowseSelectedFolder(hwnd)) + return FALSE; + + /* get the files from the edit control */ + nFileCount = FILEDLG95_FILENAME_GetFileNames(hwnd, &lpstrFileList, &sizeUsed, '\0'); + + /* try if the user selected a folder in the shellview */ + if(nFileCount == 0) + return FALSE; + + if(nFileCount > 1) + { + ret = FILEDLG95_OnOpenMultipleFiles(hwnd, lpstrFileList, nFileCount, sizeUsed); + goto ret; + } + + TRACE("count=%u len=%u file=%s\n", nFileCount, sizeUsed, debugstr_w(lpstrFileList)); + +/* + Step 1: Build a complete path name from the current folder and + the filename or path in the edit box. + Special cases: + - the path in the edit box is a root path + (with or without drive letter) + - the edit box contains ".." (or a path with ".." in it) +*/ + + /* Get the current directory name */ + if (!COMDLG32_GetDisplayNameOf(fodInfos->ShellInfos.pidlAbsCurrent, lpstrPathAndFile)) + { + /* last fallback */ + GetCurrentDirectoryW(MAX_PATH, lpstrPathAndFile); + } + PathAddBackslashW(lpstrPathAndFile); + + TRACE("current directory=%s\n", debugstr_w(lpstrPathAndFile)); + + /* if the user specifyed a fully qualified path use it */ + if(PathIsRelativeW(lpstrFileList)) + { + strcatW(lpstrPathAndFile, lpstrFileList); + } + else + { + /* does the path have a drive letter? */ + if (PathGetDriveNumberW(lpstrFileList) == -1) + strcpyW(lpstrPathAndFile+2, lpstrFileList); + else + strcpyW(lpstrPathAndFile, lpstrFileList); + } + + /* resolve "." and ".." */ + PathCanonicalizeW(lpstrTemp, lpstrPathAndFile ); + strcpyW(lpstrPathAndFile, lpstrTemp); + TRACE("canon=%s\n", debugstr_w(lpstrPathAndFile)); + + MemFree(lpstrFileList); + +/* + Step 2: here we have a cleaned up path + + We have to parse the path step by step to see if we have to browse + to a folder if the path points to a directory or the last + valid element is a directory. + + valid variables: + lpstrPathAndFile: cleaned up path + */ + + nOpenAction = ONOPEN_OPEN; + + /* don't apply any checks with OFN_NOVALIDATE */ + { + LPWSTR lpszTemp, lpszTemp1; + LPITEMIDLIST pidl = NULL; + static const WCHAR szwInvalid[] = { '/',':','<','>','|', 0}; + + /* check for invalid chars */ + if((strpbrkW(lpstrPathAndFile+3, szwInvalid) != NULL) && !(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE)) + { + FILEDLG95_OnOpenMessage(hwnd, IDS_INVALID_FILENAME_TITLE, IDS_INVALID_FILENAME); + ret = FALSE; + goto ret; + } + + if (FAILED (SHGetDesktopFolder(&lpsf))) return FALSE; + + lpszTemp1 = lpszTemp = lpstrPathAndFile; + while (lpszTemp1) + { + LPSHELLFOLDER lpsfChild; + WCHAR lpwstrTemp[MAX_PATH]; + DWORD dwEaten, dwAttributes; + LPWSTR p; + + strcpyW(lpwstrTemp, lpszTemp); + p = PathFindNextComponentW(lpwstrTemp); + + if (!p) break; /* end of path */ + + *p = 0; + lpszTemp = lpszTemp + strlenW(lpwstrTemp); + + if(*lpszTemp==0) + { + static const WCHAR wszWild[] = { '*', '?', 0 }; + /* if the last element is a wildcard do a search */ + if(strpbrkW(lpszTemp1, wszWild) != NULL) + { + nOpenAction = ONOPEN_SEARCH; + break; + } + } + lpszTemp1 = lpszTemp; + + TRACE("parse now=%s next=%s sf=%p\n",debugstr_w(lpwstrTemp), debugstr_w(lpszTemp), lpsf); + + /* append a backslash to drive letters */ + if(lstrlenW(lpwstrTemp)==2 && lpwstrTemp[1] == ':' && + ((lpwstrTemp[0] >= 'a' && lpwstrTemp[0] <= 'z') || + (lpwstrTemp[0] >= 'A' && lpwstrTemp[0] <= 'Z'))) + { + PathAddBackslashW(lpwstrTemp); + } + + dwAttributes = SFGAO_FOLDER; + if(SUCCEEDED(IShellFolder_ParseDisplayName(lpsf, hwnd, NULL, lpwstrTemp, &dwEaten, &pidl, &dwAttributes))) + { + /* the path component is valid, we have a pidl of the next path component */ + TRACE("parse OK attr=0x%08lx pidl=%p\n", dwAttributes, pidl); + if(dwAttributes & SFGAO_FOLDER) + { + if(FAILED(IShellFolder_BindToObject(lpsf, pidl, 0, &IID_IShellFolder, (LPVOID*)&lpsfChild))) + { + ERR("bind to failed\n"); /* should not fail */ + break; + } + IShellFolder_Release(lpsf); + lpsf = lpsfChild; + lpsfChild = NULL; + } + else + { + TRACE("value\n"); + + /* end dialog, return value */ + nOpenAction = ONOPEN_OPEN; + break; + } + COMDLG32_SHFree(pidl); + pidl = NULL; + } + else if (!(fodInfos->ofnInfos->Flags & OFN_NOVALIDATE)) + { + if(*lpszTemp) /* points to trailing null for last path element */ + { + if(fodInfos->ofnInfos->Flags & OFN_PATHMUSTEXIST) + { + FILEDLG95_OnOpenMessage(hwnd, 0, IDS_PATHNOTEXISTING); + break; + } + } + else + { + if( (fodInfos->ofnInfos->Flags & OFN_FILEMUSTEXIST) && + !( fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG ) ) + { + FILEDLG95_OnOpenMessage(hwnd, 0, IDS_FILENOTEXISTING); + break; + } + } + /* change to the current folder */ + nOpenAction = ONOPEN_OPEN; + break; + } + else + { + nOpenAction = ONOPEN_OPEN; + break; + } + } + if(pidl) COMDLG32_SHFree(pidl); + } + +/* + Step 3: here we have a cleaned up and validated path + + valid variables: + lpsf: ShellFolder bound to the rightmost valid path component + lpstrPathAndFile: cleaned up path + nOpenAction: action to do +*/ + TRACE("end validate sf=%p\n", lpsf); + + switch(nOpenAction) + { + case ONOPEN_SEARCH: /* set the current filter to the file mask and refresh */ + TRACE("ONOPEN_SEARCH %s\n", debugstr_w(lpstrPathAndFile)); + { + int iPos; + LPWSTR lpszTemp = PathFindFileNameW(lpstrPathAndFile); + DWORD len; + IPersistFolder2 * ppf2; + + /* replace the current filter */ + if(fodInfos->ShellInfos.lpstrCurrentFilter) + MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter); + len = strlenW(lpszTemp)+1; + fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc(len * sizeof(WCHAR)); + strcpyW( fodInfos->ShellInfos.lpstrCurrentFilter, lpszTemp); + + /* set the filter cb to the extension when possible */ + if(-1 < (iPos = FILEDLG95_FILETYPE_SearchExt(fodInfos->DlgInfos.hwndFileTypeCB, lpszTemp))) + CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, iPos); + + if(SUCCEEDED(IShellFolder_QueryInterface( lpsf, &IID_IPersistFolder2, (LPVOID*)&ppf2))) + { + LPITEMIDLIST pidlCurrent; + IPersistFolder2_GetCurFolder(ppf2, &pidlCurrent); + IPersistFolder2_Release(ppf2); + if( ! COMDLG32_PIDL_ILIsEqual(pidlCurrent, fodInfos->ShellInfos.pidlAbsCurrent)) + { + IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidlCurrent, SBSP_ABSOLUTE); + } + else + { + IShellView_Refresh(fodInfos->Shell.FOIShellView); + } + SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE); + COMDLG32_SHFree(pidlCurrent); + } + } + ret = FALSE; + break; + case ONOPEN_OPEN: /* fill in the return struct and close the dialog */ + TRACE("ONOPEN_OPEN %s\n", debugstr_w(lpstrPathAndFile)); + { + WCHAR *ext = NULL; + + /* update READONLY check box flag */ + if ((SendMessageA(GetDlgItem(hwnd,IDC_OPENREADONLY),BM_GETCHECK,0,0) & 0x03) == BST_CHECKED) + fodInfos->ofnInfos->Flags |= OFN_READONLY; + else + fodInfos->ofnInfos->Flags &= ~OFN_READONLY; + + /* Attach the file extension with file name*/ + + if(!PathIsDirectoryW(lpstrPathAndFile)) + { + if((ext = PathFindExtensionW(lpstrPathAndFile)) == NULL) + { + /* if no extension is specified with file name, then */ + /* attach the extension from file filter or default one */ + + WCHAR *filterExt = NULL; + LPWSTR lpstrFilter = NULL; + static const WCHAR szwDot[] = {'.',0}; + int PathLength = strlenW(lpstrPathAndFile); + + /* Attach the dot*/ + strcatW(lpstrPathAndFile, szwDot); + + /*Get the file extension from file type filter*/ + lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, + fodInfos->ofnInfos->nFilterIndex-1); + + if (lpstrFilter != (LPWSTR)CB_ERR) /* control is not empty */ + filterExt = PathFindExtensionW(lpstrFilter); + + if ( filterExt && *filterExt ) /* attach the file extension from file type filter*/ + strcatW(lpstrPathAndFile, filterExt + 1); + else if ( fodInfos->defext ) /* attach the default file extension*/ + strcatW(lpstrPathAndFile, fodInfos->defext); + + /* In Open dialog: if file does not exist try without extension */ + if (!(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) && !PathFileExistsW(lpstrPathAndFile)) + lpstrPathAndFile[PathLength] = '\0'; + } + + if (fodInfos->defext) /* add default extension */ + { + /* Set/clear the output OFN_EXTENSIONDIFFERENT flag */ + if (*ext) + ext++; + if (!lstrcmpiW(fodInfos->defext, ext)) + fodInfos->ofnInfos->Flags &= ~OFN_EXTENSIONDIFFERENT; + else + fodInfos->ofnInfos->Flags |= OFN_EXTENSIONDIFFERENT; + } + } + + /* In Save dialog: check if the file already exists */ + if (fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG + && fodInfos->ofnInfos->Flags & OFN_OVERWRITEPROMPT + && PathFileExistsW(lpstrPathAndFile)) + { + WCHAR lpstrOverwrite[100]; + int answer; + + LoadStringW(COMDLG32_hInstance, IDS_OVERWRITEFILE, lpstrOverwrite, 100); + answer = MessageBoxW(hwnd, lpstrOverwrite, fodInfos->title, + MB_YESNO | MB_ICONEXCLAMATION); + if (answer == IDNO) + { + ret = FALSE; + goto ret; + } + } + + /* Check that the size of the file does not exceed buffer size. + (Allow for extra \0 if OFN_MULTISELECT is set.) */ + if(strlenW(lpstrPathAndFile) < fodInfos->ofnInfos->nMaxFile - + ((fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) ? 1 : 0)) + { + LPWSTR lpszTemp; + + /* fill destination buffer */ + if (fodInfos->ofnInfos->lpstrFile) + { + if(fodInfos->unicode) + { + LPOPENFILENAMEW ofn = fodInfos->ofnInfos; + + lstrcpynW(ofn->lpstrFile, lpstrPathAndFile, ofn->nMaxFile); + if (ofn->Flags & OFN_ALLOWMULTISELECT) + ofn->lpstrFile[lstrlenW(ofn->lpstrFile) + 1] = '\0'; + } + else + { + LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos; + + WideCharToMultiByte(CP_ACP, 0, lpstrPathAndFile, -1, + ofn->lpstrFile, ofn->nMaxFile, NULL, NULL); + if (ofn->Flags & OFN_ALLOWMULTISELECT) + ofn->lpstrFile[lstrlenA(ofn->lpstrFile) + 1] = '\0'; + } + } + + /* set filename offset */ + lpszTemp = PathFindFileNameW(lpstrPathAndFile); + fodInfos->ofnInfos->nFileOffset = (lpszTemp - lpstrPathAndFile); + + /* set extension offset */ + lpszTemp = PathFindExtensionW(lpstrPathAndFile); + fodInfos->ofnInfos->nFileExtension = (*lpszTemp) ? (lpszTemp - lpstrPathAndFile) + 1 : 0; + + /* set the lpstrFileTitle */ + if(fodInfos->ofnInfos->lpstrFileTitle) + { + LPWSTR lpstrFileTitle = PathFindFileNameW(lpstrPathAndFile); + if(fodInfos->unicode) + { + LPOPENFILENAMEW ofn = fodInfos->ofnInfos; + lstrcpynW(ofn->lpstrFileTitle, lpstrFileTitle, ofn->nMaxFileTitle); + } + else + { + LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos; + WideCharToMultiByte(CP_ACP, 0, lpstrFileTitle, -1, + ofn->lpstrFileTitle, ofn->nMaxFileTitle, NULL, NULL); + } + } + + /* copy currently selected filter to lpstrCustomFilter */ + if (fodInfos->ofnInfos->lpstrCustomFilter) + { + LPOPENFILENAMEA ofn = (LPOPENFILENAMEA)fodInfos->ofnInfos; + int len = WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1, + NULL, 0, NULL, NULL); + if (len + strlen(ofn->lpstrCustomFilter) + 1 <= ofn->nMaxCustFilter) + { + LPSTR s = ofn->lpstrCustomFilter; + s += strlen(ofn->lpstrCustomFilter)+1; + WideCharToMultiByte(CP_ACP, 0, fodInfos->ShellInfos.lpstrCurrentFilter, -1, + s, len, NULL, NULL); + } + } + + + if ( !FILEDLG95_SendFileOK(hwnd, fodInfos) ) + goto ret; + + TRACE("close\n"); + FILEDLG95_Clean(hwnd); + ret = EndDialog(hwnd, TRUE); + } + else + { + WORD size; + + size = strlenW(lpstrPathAndFile) + 1; + if (fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT) + size += 1; + /* return needed size in first two bytes of lpstrFile */ + *(WORD *)fodInfos->ofnInfos->lpstrFile = size; + FILEDLG95_Clean(hwnd); + ret = EndDialog(hwnd, FALSE); + COMDLG32_SetCommDlgExtendedError(FNERR_BUFFERTOOSMALL); + } + goto ret; + } + break; + } + +ret: + if(lpsf) IShellFolder_Release(lpsf); + return ret; +} + +/*********************************************************************** + * FILEDLG95_SHELL_Init + * + * Initialisation of the shell objects + */ +static LRESULT FILEDLG95_SHELL_Init(HWND hwnd) +{ + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); + + TRACE("\n"); + + /* + * Initialisation of the FileOpenDialogInfos structure + */ + + /* Shell */ + + /*ShellInfos */ + fodInfos->ShellInfos.hwndOwner = hwnd; + + /* Disable multi-select if flag not set */ + if (!(fodInfos->ofnInfos->Flags & OFN_ALLOWMULTISELECT)) + { + fodInfos->ShellInfos.folderSettings.fFlags |= FWF_SINGLESEL; + } + fodInfos->ShellInfos.folderSettings.fFlags |= FWF_AUTOARRANGE | FWF_ALIGNLEFT; + fodInfos->ShellInfos.folderSettings.ViewMode = FVM_LIST; + + /* Construct the IShellBrowser interface */ + fodInfos->Shell.FOIShellBrowser = IShellBrowserImpl_Construct(hwnd); + + return NOERROR; +} + +/*********************************************************************** + * FILEDLG95_SHELL_ExecuteCommand + * + * Change the folder option and refresh the view + * If the function succeeds, the return value is nonzero. + */ +static BOOL FILEDLG95_SHELL_ExecuteCommand(HWND hwnd, LPCSTR lpVerb) +{ + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); + + IContextMenu * pcm; + TRACE("(%p,%p)\n", hwnd, lpVerb); + + if(SUCCEEDED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView, + SVGIO_BACKGROUND, + &IID_IContextMenu, + (LPVOID*)&pcm))) + { + CMINVOKECOMMANDINFO ci; + ZeroMemory(&ci, sizeof(CMINVOKECOMMANDINFO)); + ci.cbSize = sizeof(CMINVOKECOMMANDINFO); + ci.lpVerb = lpVerb; + ci.hwnd = hwnd; + + IContextMenu_InvokeCommand(pcm, &ci); + IContextMenu_Release(pcm); + } + + return FALSE; +} + +/*********************************************************************** + * FILEDLG95_SHELL_UpFolder + * + * Browse to the specified object + * If the function succeeds, the return value is nonzero. + */ +static BOOL FILEDLG95_SHELL_UpFolder(HWND hwnd) +{ + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); + + TRACE("\n"); + + if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, + NULL, + SBSP_PARENT))) + { + SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE); + return TRUE; + } + return FALSE; +} + +/*********************************************************************** + * FILEDLG95_SHELL_BrowseToDesktop + * + * Browse to the Desktop + * If the function succeeds, the return value is nonzero. + */ +static BOOL FILEDLG95_SHELL_BrowseToDesktop(HWND hwnd) +{ + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); + LPITEMIDLIST pidl; + HRESULT hres; + + TRACE("\n"); + + SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidl); + hres = IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, pidl, SBSP_ABSOLUTE); + SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE); + COMDLG32_SHFree(pidl); + return SUCCEEDED(hres); +} +/*********************************************************************** + * FILEDLG95_SHELL_Clean + * + * Cleans the memory used by shell objects + */ +static void FILEDLG95_SHELL_Clean(HWND hwnd) +{ + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); + + TRACE("\n"); + + COMDLG32_SHFree(fodInfos->ShellInfos.pidlAbsCurrent); + + /* clean Shell interfaces */ + IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView); + IShellView_Release(fodInfos->Shell.FOIShellView); + IShellFolder_Release(fodInfos->Shell.FOIShellFolder); + IShellBrowser_Release(fodInfos->Shell.FOIShellBrowser); + if (fodInfos->Shell.FOIDataObject) + IDataObject_Release(fodInfos->Shell.FOIDataObject); +} + +/*********************************************************************** + * FILEDLG95_FILETYPE_Init + * + * Initialisation of the file type combo box + */ +static HRESULT FILEDLG95_FILETYPE_Init(HWND hwnd) +{ + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); + int nFilters = 0; /* number of filters */ + int nFilterIndexCB; + + TRACE("\n"); + + if(fodInfos->customfilter) + { + /* customfilter has one entry... title\0ext\0 + * Set first entry of combo box item with customfilter + */ + LPWSTR lpstrExt; + LPCWSTR lpstrPos = fodInfos->customfilter; + + /* Get the title */ + lpstrPos += strlenW(fodInfos->customfilter) + 1; + + /* Copy the extensions */ + if (! *lpstrPos) return E_FAIL; /* malformed filter */ + if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL; + strcpyW(lpstrExt,lpstrPos); + + /* Add the item at the end of the combo */ + CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, fodInfos->customfilter); + CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt); + nFilters++; + } + if(fodInfos->filter) + { + LPCWSTR lpstrPos = fodInfos->filter; + + for(;;) + { + /* filter is a list... title\0ext\0......\0\0 + * Set the combo item text to the title and the item data + * to the ext + */ + LPCWSTR lpstrDisplay; + LPWSTR lpstrExt; + + /* Get the title */ + if(! *lpstrPos) break; /* end */ + lpstrDisplay = lpstrPos; + lpstrPos += strlenW(lpstrPos) + 1; + + /* Copy the extensions */ + if (! *lpstrPos) return E_FAIL; /* malformed filter */ + if (!(lpstrExt = MemAlloc((strlenW(lpstrPos)+1)*sizeof(WCHAR)))) return E_FAIL; + strcpyW(lpstrExt,lpstrPos); + lpstrPos += strlenW(lpstrPos) + 1; + + /* Add the item at the end of the combo */ + CBAddStringW(fodInfos->DlgInfos.hwndFileTypeCB, lpstrDisplay); + CBSetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, nFilters, lpstrExt); + nFilters++; + } + } + + /* + * Set the current filter to the one specified + * in the initialisation structure + */ + if (fodInfos->filter || fodInfos->customfilter) + { + LPWSTR lpstrFilter; + + /* Check to make sure our index isn't out of bounds. */ + if ( fodInfos->ofnInfos->nFilterIndex > + nFilters - (fodInfos->customfilter == NULL ? 0 : 1) ) + fodInfos->ofnInfos->nFilterIndex = (fodInfos->customfilter == NULL ? 1 : 0); + + /* set default filter index */ + if(fodInfos->ofnInfos->nFilterIndex == 0 && fodInfos->customfilter == NULL) + fodInfos->ofnInfos->nFilterIndex = 1; + + /* calculate index of Combo Box item */ + nFilterIndexCB = fodInfos->ofnInfos->nFilterIndex; + if (fodInfos->customfilter == NULL) + nFilterIndexCB--; + + /* Set the current index selection. */ + CBSetCurSel(fodInfos->DlgInfos.hwndFileTypeCB, nFilterIndexCB); + + /* Get the corresponding text string from the combo box. */ + lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, + nFilterIndexCB); + + if ((INT)lpstrFilter == CB_ERR) /* control is empty */ + lpstrFilter = NULL; + + if(lpstrFilter) + { + DWORD len; + CharLowerW(lpstrFilter); /* lowercase */ + len = strlenW(lpstrFilter)+1; + fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) ); + strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter); + } + } else + fodInfos->ofnInfos->nFilterIndex = 0; + return S_OK; +} + +/*********************************************************************** + * FILEDLG95_FILETYPE_OnCommand + * + * WM_COMMAND of the file type combo box + * If the function succeeds, the return value is nonzero. + */ +static BOOL FILEDLG95_FILETYPE_OnCommand(HWND hwnd, WORD wNotifyCode) +{ + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); + + switch(wNotifyCode) + { + case CBN_SELENDOK: + { + LPWSTR lpstrFilter; + + /* Get the current item of the filetype combo box */ + int iItem = CBGetCurSel(fodInfos->DlgInfos.hwndFileTypeCB); + + /* set the current filter index */ + fodInfos->ofnInfos->nFilterIndex = iItem + + (fodInfos->customfilter == NULL ? 1 : 0); + + /* Set the current filter with the current selection */ + if(fodInfos->ShellInfos.lpstrCurrentFilter) + MemFree((LPVOID)fodInfos->ShellInfos.lpstrCurrentFilter); + + lpstrFilter = (LPWSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB, + iItem); + if((int)lpstrFilter != CB_ERR) + { + DWORD len; + CharLowerW(lpstrFilter); /* lowercase */ + len = strlenW(lpstrFilter)+1; + fodInfos->ShellInfos.lpstrCurrentFilter = MemAlloc( len * sizeof(WCHAR) ); + strcpyW(fodInfos->ShellInfos.lpstrCurrentFilter,lpstrFilter); + SendCustomDlgNotificationMessage(hwnd,CDN_TYPECHANGE); + } + + /* Refresh the actual view to display the included items*/ + IShellView_Refresh(fodInfos->Shell.FOIShellView); + } + } + return FALSE; +} +/*********************************************************************** + * FILEDLG95_FILETYPE_SearchExt + * + * searches for an extension in the filetype box + */ +static int FILEDLG95_FILETYPE_SearchExt(HWND hwnd,LPCWSTR lpstrExt) +{ + int i, iCount = CBGetCount(hwnd); + + TRACE("%s\n", debugstr_w(lpstrExt)); + + if(iCount != CB_ERR) + { + for(i=0;iDlgInfos.hwndFileTypeCB); + + TRACE("\n"); + + /* Delete each string of the combo and their associated data */ + if(iCount != CB_ERR) + { + for(iPos = iCount-1;iPos>=0;iPos--) + { + MemFree((LPSTR) CBGetItemDataPtr(fodInfos->DlgInfos.hwndFileTypeCB,iPos)); + CBDeleteString(fodInfos->DlgInfos.hwndFileTypeCB,iPos); + } + } + /* Current filter */ + if(fodInfos->ShellInfos.lpstrCurrentFilter) + MemFree(fodInfos->ShellInfos.lpstrCurrentFilter); + +} + +/*********************************************************************** + * FILEDLG95_LOOKIN_Init + * + * Initialisation of the look in combo box + */ +static void FILEDLG95_LOOKIN_Init(HWND hwndCombo) +{ + IShellFolder *psfRoot, *psfDrives; + IEnumIDList *lpeRoot, *lpeDrives; + LPITEMIDLIST pidlDrives, pidlTmp, pidlTmp1, pidlAbsTmp; + + LookInInfos *liInfos = MemAlloc(sizeof(LookInInfos)); + + TRACE("\n"); + + liInfos->iMaxIndentation = 0; + + SetPropA(hwndCombo, LookInInfosStr, (HANDLE) liInfos); + + /* set item height for both text field and listbox */ + CBSetItemHeight(hwndCombo,-1,GetSystemMetrics(SM_CYSMICON)); + CBSetItemHeight(hwndCombo,0,GetSystemMetrics(SM_CYSMICON)); + + /* Turn on the extended UI for the combo box like Windows does */ + CBSetExtendedUI(hwndCombo, TRUE); + + /* Initialise data of Desktop folder */ + SHGetSpecialFolderLocation(0,CSIDL_DESKTOP,&pidlTmp); + FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND); + COMDLG32_SHFree(pidlTmp); + + SHGetSpecialFolderLocation(0,CSIDL_DRIVES,&pidlDrives); + + SHGetDesktopFolder(&psfRoot); + + if (psfRoot) + { + /* enumerate the contents of the desktop */ + if(SUCCEEDED(IShellFolder_EnumObjects(psfRoot, hwndCombo, SHCONTF_FOLDERS, &lpeRoot))) + { + while (S_OK == IEnumIDList_Next(lpeRoot, 1, &pidlTmp, NULL)) + { + FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlTmp,LISTEND); + + /* special handling for CSIDL_DRIVES */ + if (COMDLG32_PIDL_ILIsEqual(pidlTmp, pidlDrives)) + { + if(SUCCEEDED(IShellFolder_BindToObject(psfRoot, pidlTmp, NULL, &IID_IShellFolder, (LPVOID*)&psfDrives))) + { + /* enumerate the drives */ + if(SUCCEEDED(IShellFolder_EnumObjects(psfDrives, hwndCombo,SHCONTF_FOLDERS, &lpeDrives))) + { + while (S_OK == IEnumIDList_Next(lpeDrives, 1, &pidlTmp1, NULL)) + { + pidlAbsTmp = COMDLG32_PIDL_ILCombine(pidlTmp, pidlTmp1); + FILEDLG95_LOOKIN_AddItem(hwndCombo, pidlAbsTmp,LISTEND); + COMDLG32_SHFree(pidlAbsTmp); + COMDLG32_SHFree(pidlTmp1); + } + IEnumIDList_Release(lpeDrives); + } + IShellFolder_Release(psfDrives); + } + } + COMDLG32_SHFree(pidlTmp); + } + IEnumIDList_Release(lpeRoot); + } + IShellFolder_Release(psfRoot); + } + + COMDLG32_SHFree(pidlDrives); +} + +/*********************************************************************** + * FILEDLG95_LOOKIN_DrawItem + * + * WM_DRAWITEM message handler + */ +static LRESULT FILEDLG95_LOOKIN_DrawItem(LPDRAWITEMSTRUCT pDIStruct) +{ + COLORREF crWin = GetSysColor(COLOR_WINDOW); + COLORREF crHighLight = GetSysColor(COLOR_HIGHLIGHT); + COLORREF crText = GetSysColor(COLOR_WINDOWTEXT); + RECT rectText; + RECT rectIcon; + SHFILEINFOA sfi; + HIMAGELIST ilItemImage; + int iIndentation; + TEXTMETRICA tm; + LPSFOLDER tmpFolder; + + + LookInInfos *liInfos = (LookInInfos *)GetPropA(pDIStruct->hwndItem,LookInInfosStr); + + TRACE("\n"); + + if(pDIStruct->itemID == -1) + return 0; + + if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(pDIStruct->hwndItem, + pDIStruct->itemID))) + return 0; + + + if(pDIStruct->itemID == liInfos->uSelectedItem) + { + ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem, + 0, + &sfi, + sizeof (SHFILEINFOA), + SHGFI_PIDL | SHGFI_SMALLICON | + SHGFI_OPENICON | SHGFI_SYSICONINDEX | + SHGFI_DISPLAYNAME ); + } + else + { + ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem, + 0, + &sfi, + sizeof (SHFILEINFOA), + SHGFI_PIDL | SHGFI_SMALLICON | + SHGFI_SYSICONINDEX | + SHGFI_DISPLAYNAME); + } + + /* Is this item selected ? */ + if(pDIStruct->itemState & ODS_SELECTED) + { + SetTextColor(pDIStruct->hDC,(0x00FFFFFF & ~(crText))); + SetBkColor(pDIStruct->hDC,crHighLight); + FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_HIGHLIGHT)); + } + else + { + SetTextColor(pDIStruct->hDC,crText); + SetBkColor(pDIStruct->hDC,crWin); + FillRect(pDIStruct->hDC,&pDIStruct->rcItem,GetSysColorBrush(COLOR_WINDOW)); + } + + /* Do not indent item if drawing in the edit of the combo */ + if(pDIStruct->itemState & ODS_COMBOBOXEDIT) + { + iIndentation = 0; + ilItemImage = (HIMAGELIST) SHGetFileInfoA ((LPCSTR) tmpFolder->pidlItem, + 0, + &sfi, + sizeof (SHFILEINFOA), + SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_OPENICON + | SHGFI_SYSICONINDEX | SHGFI_DISPLAYNAME ); + + } + else + { + iIndentation = tmpFolder->m_iIndent; + } + /* Draw text and icon */ + + /* Initialise the icon display area */ + rectIcon.left = pDIStruct->rcItem.left + ICONWIDTH/2 * iIndentation; + rectIcon.top = pDIStruct->rcItem.top; + rectIcon.right = rectIcon.left + ICONWIDTH; + rectIcon.bottom = pDIStruct->rcItem.bottom; + + /* Initialise the text display area */ + GetTextMetricsA(pDIStruct->hDC, &tm); + rectText.left = rectIcon.right; + rectText.top = + (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom - tm.tmHeight) / 2; + rectText.right = pDIStruct->rcItem.right + XTEXTOFFSET; + rectText.bottom = + (pDIStruct->rcItem.top + pDIStruct->rcItem.bottom + tm.tmHeight) / 2; + + /* Draw the icon from the image list */ + ImageList_Draw(ilItemImage, + sfi.iIcon, + pDIStruct->hDC, + rectIcon.left, + rectIcon.top, + ILD_TRANSPARENT ); + + /* Draw the associated text */ + if(sfi.szDisplayName) + TextOutA(pDIStruct->hDC,rectText.left,rectText.top,sfi.szDisplayName,strlen(sfi.szDisplayName)); + + + return NOERROR; +} + +/*********************************************************************** + * FILEDLG95_LOOKIN_OnCommand + * + * LookIn combo box WM_COMMAND message handler + * If the function succeeds, the return value is nonzero. + */ +static BOOL FILEDLG95_LOOKIN_OnCommand(HWND hwnd, WORD wNotifyCode) +{ + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); + + TRACE("%p\n", fodInfos); + + switch(wNotifyCode) + { + case CBN_SELENDOK: + { + LPSFOLDER tmpFolder; + int iItem; + + iItem = CBGetCurSel(fodInfos->DlgInfos.hwndLookInCB); + + if(!(tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB, + iItem))) + return FALSE; + + + if(SUCCEEDED(IShellBrowser_BrowseObject(fodInfos->Shell.FOIShellBrowser, + tmpFolder->pidlItem, + SBSP_ABSOLUTE))) + { + SendCustomDlgNotificationMessage(hwnd, CDN_FOLDERCHANGE); + return TRUE; + } + break; + } + + } + return FALSE; +} + +/*********************************************************************** + * FILEDLG95_LOOKIN_AddItem + * + * Adds an absolute pidl item to the lookin combo box + * returns the index of the inserted item + */ +static int FILEDLG95_LOOKIN_AddItem(HWND hwnd,LPITEMIDLIST pidl, int iInsertId) +{ + LPITEMIDLIST pidlNext; + SHFILEINFOA sfi; + SFOLDER *tmpFolder; + LookInInfos *liInfos; + + TRACE("%08x\n", iInsertId); + + if(!pidl) + return -1; + + if(!(liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr))) + return -1; + + tmpFolder = MemAlloc(sizeof(SFOLDER)); + tmpFolder->m_iIndent = 0; + + /* Calculate the indentation of the item in the lookin*/ + pidlNext = pidl; + while( (pidlNext=COMDLG32_PIDL_ILGetNext(pidlNext)) ) + { + tmpFolder->m_iIndent++; + } + + tmpFolder->pidlItem = COMDLG32_PIDL_ILClone(pidl); + + if(tmpFolder->m_iIndent > liInfos->iMaxIndentation) + liInfos->iMaxIndentation = tmpFolder->m_iIndent; + + sfi.dwAttributes = SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM; + SHGetFileInfoA((LPSTR)pidl, + 0, + &sfi, + sizeof(sfi), + SHGFI_DISPLAYNAME | SHGFI_SYSICONINDEX + | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED); + + TRACE("-- Add %s attr=%08lx\n", sfi.szDisplayName, sfi.dwAttributes); + + if((sfi.dwAttributes & SFGAO_FILESYSANCESTOR) || (sfi.dwAttributes & SFGAO_FILESYSTEM)) + { + int iItemID; + + TRACE("-- Add %s at %u\n", sfi.szDisplayName, tmpFolder->m_iIndent); + + /* Add the item at the end of the list */ + if(iInsertId < 0) + { + iItemID = CBAddString(hwnd,sfi.szDisplayName); + } + /* Insert the item at the iInsertId position*/ + else + { + iItemID = CBInsertString(hwnd,sfi.szDisplayName,iInsertId); + } + + CBSetItemDataPtr(hwnd,iItemID,tmpFolder); + return iItemID; + } + + COMDLG32_SHFree( tmpFolder->pidlItem ); + MemFree( tmpFolder ); + return -1; + +} + +/*********************************************************************** + * FILEDLG95_LOOKIN_InsertItemAfterParent + * + * Insert an item below its parent + */ +static int FILEDLG95_LOOKIN_InsertItemAfterParent(HWND hwnd,LPITEMIDLIST pidl) +{ + + LPITEMIDLIST pidlParent = GetParentPidl(pidl); + int iParentPos; + + TRACE("\n"); + + iParentPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidlParent,SEARCH_PIDL); + + if(iParentPos < 0) + { + iParentPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidlParent); + } + + /* Free pidlParent memory */ + COMDLG32_SHFree((LPVOID)pidlParent); + + return FILEDLG95_LOOKIN_AddItem(hwnd,pidl,iParentPos + 1); +} + +/*********************************************************************** + * FILEDLG95_LOOKIN_SelectItem + * + * Adds an absolute pidl item to the lookin combo box + * returns the index of the inserted item + */ +int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl) +{ + int iItemPos; + LookInInfos *liInfos; + + TRACE("\n"); + + iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)pidl,SEARCH_PIDL); + + liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr); + + if(iItemPos < 0) + { + while(FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd) > -1); + iItemPos = FILEDLG95_LOOKIN_InsertItemAfterParent(hwnd,pidl); + } + + else + { + SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos); + while(liInfos->iMaxIndentation > tmpFolder->m_iIndent) + { + int iRemovedItem; + + if(-1 == (iRemovedItem = FILEDLG95_LOOKIN_RemoveMostExpandedItem(hwnd))) + break; + if(iRemovedItem < iItemPos) + iItemPos--; + } + } + + CBSetCurSel(hwnd,iItemPos); + liInfos->uSelectedItem = iItemPos; + + return 0; + +} + +/*********************************************************************** + * FILEDLG95_LOOKIN_RemoveMostExpandedItem + * + * Remove the item with an expansion level over iExpansionLevel + */ +static int FILEDLG95_LOOKIN_RemoveMostExpandedItem(HWND hwnd) +{ + int iItemPos; + + LookInInfos *liInfos = (LookInInfos *)GetPropA(hwnd,LookInInfosStr); + + TRACE("\n"); + + if(liInfos->iMaxIndentation <= 2) + return -1; + + if((iItemPos = FILEDLG95_LOOKIN_SearchItem(hwnd,(WPARAM)liInfos->iMaxIndentation,SEARCH_EXP)) >=0) + { + SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(hwnd,iItemPos); + COMDLG32_SHFree(tmpFolder->pidlItem); + MemFree(tmpFolder); + CBDeleteString(hwnd,iItemPos); + liInfos->iMaxIndentation--; + + return iItemPos; + } + + return -1; +} + +/*********************************************************************** + * FILEDLG95_LOOKIN_SearchItem + * + * Search for pidl in the lookin combo box + * returns the index of the found item + */ +static int FILEDLG95_LOOKIN_SearchItem(HWND hwnd,WPARAM searchArg,int iSearchMethod) +{ + int i = 0; + int iCount = CBGetCount(hwnd); + + TRACE("0x%08x 0x%x\n",searchArg, iSearchMethod); + + if (iCount != CB_ERR) + { + for(;ipidlItem)) + return i; + if(iSearchMethod == SEARCH_EXP && tmpFolder->m_iIndent == (int)searchArg) + return i; + } + } + + return -1; +} + +/*********************************************************************** + * FILEDLG95_LOOKIN_Clean + * + * Clean the memory used by the lookin combo box + */ +static void FILEDLG95_LOOKIN_Clean(HWND hwnd) +{ + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); + int iPos; + int iCount = CBGetCount(fodInfos->DlgInfos.hwndLookInCB); + + TRACE("\n"); + + /* Delete each string of the combo and their associated data */ + if (iCount != CB_ERR) + { + for(iPos = iCount-1;iPos>=0;iPos--) + { + SFOLDER *tmpFolder = (LPSFOLDER) CBGetItemDataPtr(fodInfos->DlgInfos.hwndLookInCB,iPos); + COMDLG32_SHFree(tmpFolder->pidlItem); + MemFree(tmpFolder); + CBDeleteString(fodInfos->DlgInfos.hwndLookInCB,iPos); + } + } + + /* LookInInfos structure */ + RemovePropA(fodInfos->DlgInfos.hwndLookInCB,LookInInfosStr); + +} +/*********************************************************************** + * FILEDLG95_FILENAME_FillFromSelection + * + * fills the edit box from the cached DataObject + */ +void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd) +{ + FileOpenDlgInfos *fodInfos; + LPITEMIDLIST pidl; + UINT nFiles = 0, nFileToOpen, nFileSelected, nLength = 0; + char lpstrTemp[MAX_PATH]; + LPSTR lpstrAllFile = NULL, lpstrCurrFile = NULL; + + TRACE("\n"); + fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); + + /* Count how many files we have */ + nFileSelected = GetNumSelected( fodInfos->Shell.FOIDataObject ); + + /* calculate the string length, count files */ + if (nFileSelected >= 1) + { + nLength += 3; /* first and last quotes, trailing \0 */ + for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ ) + { + pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 ); + + if (pidl) + { + /* get the total length of the selected file names */ + lpstrTemp[0] = '\0'; + GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp ); + + if ( ! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl) ) /* Ignore folders */ + { + nLength += strlen( lpstrTemp ) + 3; + nFiles++; + } + COMDLG32_SHFree( pidl ); + } + } + } + + /* allocate the buffer */ + if (nFiles <= 1) nLength = MAX_PATH; + lpstrAllFile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nLength); + lpstrAllFile[0] = '\0'; + + /* Generate the string for the edit control */ + if(nFiles >= 1) + { + lpstrCurrFile = lpstrAllFile; + for ( nFileToOpen = 0; nFileToOpen < nFileSelected; nFileToOpen++ ) + { + pidl = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, nFileToOpen+1 ); + + if (pidl) + { + /* get the file name */ + lpstrTemp[0] = '\0'; + GetName( fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER|SHGDN_FORPARSING, lpstrTemp ); + + if (! IsPidlFolder(fodInfos->Shell.FOIShellFolder, pidl)) /* Ignore folders */ + { + if ( nFiles > 1) + { + *lpstrCurrFile++ = '\"'; + strcpy( lpstrCurrFile, lpstrTemp ); + lpstrCurrFile += strlen( lpstrTemp ); + strcpy( lpstrCurrFile, "\" " ); + lpstrCurrFile += 2; + } + else + { + strcpy( lpstrAllFile, lpstrTemp ); + } + } + COMDLG32_SHFree( (LPVOID) pidl ); + } + } + SetWindowTextA( fodInfos->DlgInfos.hwndFileName, lpstrAllFile ); + + /* Select the file name like Windows does */ + SendMessageA(fodInfos->DlgInfos.hwndFileName, EM_SETSEL, (WPARAM)0, (LPARAM)-1); + } + HeapFree(GetProcessHeap(),0, lpstrAllFile ); +} + + +/* copied from shell32 to avoid linking to it + * FIXME: why? shell32 is already linked + */ +static HRESULT COMDLG32_StrRetToStrNA (LPVOID dest, DWORD len, LPSTRRET src, LPITEMIDLIST pidl) +{ + switch (src->uType) + { + case STRRET_WSTR: + WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, (LPSTR)dest, len, NULL, NULL); + COMDLG32_SHFree(src->u.pOleStr); + break; + + case STRRET_CSTR: + lstrcpynA((LPSTR)dest, src->u.cStr, len); + break; + + case STRRET_OFFSET: + lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len); + break; + + default: + FIXME("unknown type!\n"); + if (len) + { + *(LPSTR)dest = '\0'; + } + return(E_FAIL); + } + return S_OK; +} + +/*********************************************************************** + * FILEDLG95_FILENAME_GetFileNames + * + * Copies the filenames to a delimited string list. + * The delimiter is specified by the parameter 'separator', + * usually either a space or a nul + */ +static int FILEDLG95_FILENAME_GetFileNames (HWND hwnd, LPWSTR * lpstrFileList, UINT * sizeUsed, char separator) +{ + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); + UINT nStrCharCount = 0; /* index in src buffer */ + UINT nFileIndex = 0; /* index in dest buffer */ + UINT nFileCount = 0; /* number of files */ + UINT nStrLen = 0; /* length of string in edit control */ + LPWSTR lpstrEdit; /* buffer for string from edit control */ + + TRACE("\n"); + + /* get the filenames from the edit control */ + nStrLen = SendMessageW(fodInfos->DlgInfos.hwndFileName, WM_GETTEXTLENGTH, 0, 0); + lpstrEdit = MemAlloc( (nStrLen+1)*sizeof(WCHAR) ); + GetDlgItemTextW(hwnd, IDC_FILENAME, lpstrEdit, nStrLen+1); + + TRACE("nStrLen=%u str=%s\n", nStrLen, debugstr_w(lpstrEdit)); + + /* we might get single filename without any '"', + * so we need nStrLen + terminating \0 + end-of-list \0 */ + *lpstrFileList = MemAlloc( (nStrLen+2)*sizeof(WCHAR) ); + *sizeUsed = 0; + + /* build delimited file list from filenames */ + while ( nStrCharCount <= nStrLen ) + { + if ( lpstrEdit[nStrCharCount]=='"' ) + { + nStrCharCount++; + while ((lpstrEdit[nStrCharCount]!='"') && (nStrCharCount <= nStrLen)) + { + (*lpstrFileList)[nFileIndex++] = lpstrEdit[nStrCharCount]; + (*sizeUsed)++; + nStrCharCount++; + } + (*lpstrFileList)[nFileIndex++] = separator; + (*sizeUsed)++; + nFileCount++; + } + nStrCharCount++; + } + + /* single, unquoted string */ + if ((nStrLen > 0) && (*sizeUsed == 0) ) + { + strcpyW(*lpstrFileList, lpstrEdit); + nFileIndex = strlenW(lpstrEdit) + 1; + (*sizeUsed) = nFileIndex; + nFileCount = 1; + } + + /* trailing \0 */ + (*lpstrFileList)[nFileIndex] = '\0'; + (*sizeUsed)++; + + MemFree(lpstrEdit); + return nFileCount; +} + +#define SETDefFormatEtc(fe,cf,med) \ +{ \ + (fe).cfFormat = cf;\ + (fe).dwAspect = DVASPECT_CONTENT; \ + (fe).ptd =NULL;\ + (fe).tymed = med;\ + (fe).lindex = -1;\ +}; + +/* + * DATAOBJECT Helper functions + */ + +/*********************************************************************** + * COMCTL32_ReleaseStgMedium + * + * like ReleaseStgMedium from ole32 + */ +static void COMCTL32_ReleaseStgMedium (STGMEDIUM medium) +{ + if(medium.pUnkForRelease) + { + IUnknown_Release(medium.pUnkForRelease); + } + else + { + GlobalUnlock(medium.u.hGlobal); + GlobalFree(medium.u.hGlobal); + } +} + +/*********************************************************************** + * GetPidlFromDataObject + * + * Return pidl(s) by number from the cached DataObject + * + * nPidlIndex=0 gets the fully qualified root path + */ +LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex) +{ + + STGMEDIUM medium; + FORMATETC formatetc; + LPITEMIDLIST pidl = NULL; + + TRACE("sv=%p index=%u\n", doSelected, nPidlIndex); + + /* Set the FORMATETC structure*/ + SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL); + + /* Get the pidls from IDataObject */ + if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium))) + { + LPIDA cida = GlobalLock(medium.u.hGlobal); + if(nPidlIndex <= cida->cidl) + { + pidl = COMDLG32_PIDL_ILClone((LPITEMIDLIST)(&((LPBYTE)cida)[cida->aoffset[nPidlIndex]])); + } + COMCTL32_ReleaseStgMedium(medium); + } + return pidl; +} + +/*********************************************************************** + * GetNumSelected + * + * Return the number of selected items in the DataObject. + * +*/ +UINT GetNumSelected( IDataObject *doSelected ) +{ + UINT retVal = 0; + STGMEDIUM medium; + FORMATETC formatetc; + + TRACE("sv=%p\n", doSelected); + + if (!doSelected) return 0; + + /* Set the FORMATETC structure*/ + SETDefFormatEtc(formatetc, RegisterClipboardFormatA(CFSTR_SHELLIDLIST), TYMED_HGLOBAL); + + /* Get the pidls from IDataObject */ + if(SUCCEEDED(IDataObject_GetData(doSelected,&formatetc,&medium))) + { + LPIDA cida = GlobalLock(medium.u.hGlobal); + retVal = cida->cidl; + COMCTL32_ReleaseStgMedium(medium); + return retVal; + } + return 0; +} + +/* + * TOOLS + */ + +/*********************************************************************** + * GetName + * + * Get the pidl's display name (relative to folder) and + * put it in lpstrFileName. + * + * Return NOERROR on success, + * E_FAIL otherwise + */ + +static HRESULT GetName(LPSHELLFOLDER lpsf, LPITEMIDLIST pidl,DWORD dwFlags,LPSTR lpstrFileName) +{ + STRRET str; + HRESULT hRes; + + TRACE("sf=%p pidl=%p\n", lpsf, pidl); + + if(!lpsf) + { + SHGetDesktopFolder(&lpsf); + hRes = GetName(lpsf,pidl,dwFlags,lpstrFileName); + IShellFolder_Release(lpsf); + return hRes; + } + + /* Get the display name of the pidl relative to the folder */ + if (SUCCEEDED(hRes = IShellFolder_GetDisplayNameOf(lpsf, pidl, dwFlags, &str))) + { + return COMDLG32_StrRetToStrNA(lpstrFileName, MAX_PATH, &str, pidl); + } + return E_FAIL; +} + +/*********************************************************************** + * GetShellFolderFromPidl + * + * pidlRel is the item pidl relative + * Return the IShellFolder of the absolute pidl + */ +IShellFolder *GetShellFolderFromPidl(LPITEMIDLIST pidlAbs) +{ + IShellFolder *psf = NULL,*psfParent; + + TRACE("%p\n", pidlAbs); + + if(SUCCEEDED(SHGetDesktopFolder(&psfParent))) + { + psf = psfParent; + if(pidlAbs && pidlAbs->mkid.cb) + { + if(SUCCEEDED(IShellFolder_BindToObject(psfParent, pidlAbs, NULL, &IID_IShellFolder, (LPVOID*)&psf))) + { + IShellFolder_Release(psfParent); + return psf; + } + } + /* return the desktop */ + return psfParent; + } + return NULL; +} + +/*********************************************************************** + * GetParentPidl + * + * Return the LPITEMIDLIST to the parent of the pidl in the list + */ +LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl) +{ + LPITEMIDLIST pidlParent; + + TRACE("%p\n", pidl); + + pidlParent = COMDLG32_PIDL_ILClone(pidl); + COMDLG32_PIDL_ILRemoveLastID(pidlParent); + + return pidlParent; +} + +/*********************************************************************** + * GetPidlFromName + * + * returns the pidl of the file name relative to folder + * NULL if an error occurred + */ +LPITEMIDLIST GetPidlFromName(IShellFolder *lpsf,LPWSTR lpcstrFileName) +{ + LPITEMIDLIST pidl = NULL; + ULONG ulEaten; + + TRACE("sf=%p file=%s\n", lpsf, debugstr_w(lpcstrFileName)); + + if(!lpcstrFileName) return NULL; + if(!*lpcstrFileName) return NULL; + + if(!lpsf) + { + if (SUCCEEDED(SHGetDesktopFolder(&lpsf))) { + IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL); + IShellFolder_Release(lpsf); + } + } + else + { + IShellFolder_ParseDisplayName(lpsf, 0, NULL, lpcstrFileName, &ulEaten, &pidl, NULL); + } + return pidl; +} + +/* +*/ +BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl) +{ + ULONG uAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER; + HRESULT ret; + + TRACE("%p, %p\n", psf, pidl); + + ret = IShellFolder_GetAttributesOf( psf, 1, &pidl, &uAttr ); + + TRACE("-- 0x%08lx 0x%08lx\n", uAttr, ret); + /* see documentation shell 4.1*/ + return uAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER); +} + +/*********************************************************************** + * BrowseSelectedFolder + */ +static BOOL BrowseSelectedFolder(HWND hwnd) +{ + BOOL bBrowseSelFolder = FALSE; + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwnd,FileOpenDlgInfosStr); + + TRACE("\n"); + + if (GetNumSelected(fodInfos->Shell.FOIDataObject) == 1) + { + LPITEMIDLIST pidlSelection; + + /* get the file selected */ + pidlSelection = GetPidlFromDataObject( fodInfos->Shell.FOIDataObject, 1); + if (IsPidlFolder (fodInfos->Shell.FOIShellFolder, pidlSelection)) + { + if ( FAILED( IShellBrowser_BrowseObject( fodInfos->Shell.FOIShellBrowser, + pidlSelection, SBSP_RELATIVE ) ) ) + { + static const WCHAR notexist[] = {'P','a','t','h',' ','d','o','e','s', + ' ','n','o','t',' ','e','x','i','s','t',0}; + MessageBoxW( hwnd, notexist, fodInfos->title, MB_OK | MB_ICONEXCLAMATION ); + } + bBrowseSelFolder = TRUE; + SendCustomDlgNotificationMessage(hwnd,CDN_FOLDERCHANGE); + } + COMDLG32_SHFree( pidlSelection ); + } + + return bBrowseSelFolder; +} + +/* + * Memory allocation methods */ +static void *MemAlloc(UINT size) +{ + return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size); +} + +static void MemFree(void *mem) +{ + HeapFree(GetProcessHeap(),0,mem); +} + +/* + * Old-style (win3.1) dialogs */ + +/*********************************************************************** + * FD32_GetTemplate [internal] + * + * Get a template (or FALSE if failure) when 16 bits dialogs are used + * by a 32 bits application + * + */ +static BOOL FD32_GetTemplate(PFD31_DATA lfs) +{ + LPOPENFILENAMEW ofnW = lfs->ofnW; + PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632; + HANDLE hDlgTmpl; + + if (ofnW->Flags & OFN_ENABLETEMPLATEHANDLE) + { + if (!(lfs->template = LockResource( ofnW->hInstance ))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + } + else if (ofnW->Flags & OFN_ENABLETEMPLATE) + { + HRSRC hResInfo; + if (priv->ofnA) + hResInfo = FindResourceA(priv->ofnA->hInstance, + priv->ofnA->lpTemplateName, + (LPSTR)RT_DIALOG); + else + hResInfo = FindResourceW(ofnW->hInstance, + ofnW->lpTemplateName, + (LPWSTR)RT_DIALOG); + if (!hResInfo) + { + COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); + return FALSE; + } + if (!(hDlgTmpl = LoadResource(ofnW->hInstance, + hResInfo)) || + !(lfs->template = LockResource(hDlgTmpl))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + } else { /* get it from internal Wine resource */ + HRSRC hResInfo; + if (!(hResInfo = FindResourceA(COMDLG32_hInstance, + lfs->open? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); + return FALSE; + } + if (!(hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo )) || + !(lfs->template = LockResource( hDlgTmpl ))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + } + return TRUE; +} + + +/************************************************************************ + * FD32_Init [internal] + * called from the common 16/32 code to initialize 32 bit data + */ +static BOOL CALLBACK FD32_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data) +{ + BOOL IsUnicode = (BOOL) data; + PFD32_PRIVATE priv; + + priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD32_PRIVATE)); + lfs->private1632 = priv; + if (NULL == lfs->private1632) return FALSE; + if (IsUnicode) + { + lfs->ofnW = (LPOPENFILENAMEW) lParam; + if (lfs->ofnW->Flags & OFN_ENABLEHOOK) + if (lfs->ofnW->lpfnHook) + lfs->hook = TRUE; + } + else + { + priv->ofnA = (LPOPENFILENAMEA) lParam; + if (priv->ofnA->Flags & OFN_ENABLEHOOK) + if (priv->ofnA->lpfnHook) + lfs->hook = TRUE; + lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW)); + FD31_MapOfnStructA(priv->ofnA, lfs->ofnW, lfs->open); + } + + if (! FD32_GetTemplate(lfs)) return FALSE; + + return TRUE; +} + +/*********************************************************************** + * FD32_CallWindowProc [internal] + * + * called from the common 16/32 code to call the appropriate hook + */ +BOOL CALLBACK FD32_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam, + LPARAM lParam) +{ + BOOL ret; + PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632; + + if (priv->ofnA) + { + TRACE("Call hookA %p (%p, %04x, %08x, %08lx)\n", + priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam); + ret = priv->ofnA->lpfnHook(lfs->hwnd, wMsg, wParam, lParam); + TRACE("ret hookA %p (%p, %04x, %08x, %08lx)\n", + priv->ofnA->lpfnHook, lfs->hwnd, wMsg, wParam, lParam); + return ret; + } + + TRACE("Call hookW %p (%p, %04x, %08x, %08lx)\n", + lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam); + ret = lfs->ofnW->lpfnHook(lfs->hwnd, wMsg, wParam, lParam); + TRACE("Ret hookW %p (%p, %04x, %08x, %08lx)\n", + lfs->ofnW->lpfnHook, lfs->hwnd, wMsg, wParam, lParam); + return ret; +} + +/*********************************************************************** + * FD32_UpdateResult [internal] + * update the real client structures if any + */ +static void CALLBACK FD32_UpdateResult(PFD31_DATA lfs) +{ + PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632; + LPOPENFILENAMEW ofnW = lfs->ofnW; + + if (priv->ofnA) + { + if (ofnW->nMaxFile && + !WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1, + priv->ofnA->lpstrFile, ofnW->nMaxFile, NULL, NULL )) + priv->ofnA->lpstrFile[ofnW->nMaxFile-1] = 0; + priv->ofnA->nFileOffset = ofnW->nFileOffset; + priv->ofnA->nFileExtension = ofnW->nFileExtension; + } +} + +/*********************************************************************** + * FD32_UpdateFileTitle [internal] + * update the real client structures if any + */ +static void CALLBACK FD32_UpdateFileTitle(PFD31_DATA lfs) +{ + PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632; + LPOPENFILENAMEW ofnW = lfs->ofnW; + + if (priv->ofnA) + { + if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1, + priv->ofnA->lpstrFileTitle, ofnW->nMaxFileTitle, NULL, NULL )) + priv->ofnA->lpstrFileTitle[ofnW->nMaxFileTitle-1] = 0; + } +} + + +/*********************************************************************** + * FD32_SendLbGetCurSel [internal] + * retrieve selected listbox item + */ +static LRESULT CALLBACK FD32_SendLbGetCurSel(PFD31_DATA lfs) +{ + return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0); +} + + +/************************************************************************ + * FD32_Destroy [internal] + * called from the common 16/32 code to cleanup 32 bit data + */ +static void CALLBACK FD32_Destroy(PFD31_DATA lfs) +{ + PFD32_PRIVATE priv = (PFD32_PRIVATE) lfs->private1632; + + /* if ofnW has been allocated, have to free everything in it */ + if (NULL != priv && NULL != priv->ofnA) + { + FD31_FreeOfnW(lfs->ofnW); + HeapFree(GetProcessHeap(), 0, lfs->ofnW); + } +} + +static void FD32_SetupCallbacks(PFD31_CALLBACKS callbacks) +{ + callbacks->Init = FD32_Init; + callbacks->CWP = FD32_CallWindowProc; + callbacks->UpdateResult = FD32_UpdateResult; + callbacks->UpdateFileTitle = FD32_UpdateFileTitle; + callbacks->SendLbGetCurSel = FD32_SendLbGetCurSel; + callbacks->Destroy = FD32_Destroy; +} + +/*********************************************************************** + * FD32_WMMeasureItem [internal] + */ +static LONG FD32_WMMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam) +{ + LPMEASUREITEMSTRUCT lpmeasure; + + lpmeasure = (LPMEASUREITEMSTRUCT)lParam; + lpmeasure->itemHeight = FD31_GetFldrHeight(); + return TRUE; +} + + +/*********************************************************************** + * FileOpenDlgProc [internal] + * Used for open and save, in fact. + */ +static INT_PTR CALLBACK FD32_FileOpenDlgProc(HWND hWnd, UINT wMsg, + WPARAM wParam, LPARAM lParam) +{ + PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP); + + TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam); + if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook) + { + INT_PTR lRet; + lRet = (INT_PTR)FD31_CallWindowProc(lfs, wMsg, wParam, lParam); + if (lRet) + return lRet; /* else continue message processing */ + } + switch (wMsg) + { + case WM_INITDIALOG: + return FD31_WMInitDialog(hWnd, wParam, lParam); + + case WM_MEASUREITEM: + return FD32_WMMeasureItem(hWnd, wParam, lParam); + + case WM_DRAWITEM: + return FD31_WMDrawItem(hWnd, wParam, lParam, !lfs->open, (DRAWITEMSTRUCT *)lParam); + + case WM_COMMAND: + return FD31_WMCommand(hWnd, lParam, HIWORD(wParam), LOWORD(wParam), lfs); +#if 0 + case WM_CTLCOLOR: + SetBkColor((HDC16)wParam, 0x00C0C0C0); + switch (HIWORD(lParam)) + { + case CTLCOLOR_BTN: + SetTextColor((HDC16)wParam, 0x00000000); + return hGRAYBrush; + case CTLCOLOR_STATIC: + SetTextColor((HDC16)wParam, 0x00000000); + return hGRAYBrush; + } + break; +#endif + } + return FALSE; +} + + +/*********************************************************************** + * GetFileName31A [internal] + * + * Creates a win31 style dialog box for the user to select a file to open/save. + */ +static BOOL GetFileName31A(LPOPENFILENAMEA lpofn, /* addess of structure with data*/ + UINT dlgType /* type dialogue : open/save */ + ) +{ + HINSTANCE hInst; + BOOL bRet = FALSE; + PFD31_DATA lfs; + FD31_CALLBACKS callbacks; + + if (!lpofn || !FD31_Init()) return FALSE; + + TRACE("ofn flags %08lx\n", lpofn->Flags); + FD32_SetupCallbacks(&callbacks); + lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) FALSE); + if (lfs) + { + hInst = (HINSTANCE)GetWindowLongPtrA( lpofn->hwndOwner, GWLP_HINSTANCE ); + bRet = DialogBoxIndirectParamA( hInst, lfs->template, lpofn->hwndOwner, + FD32_FileOpenDlgProc, (LPARAM)lfs); + FD31_DestroyPrivate(lfs); + } + + TRACE("return lpstrFile='%s' !\n", lpofn->lpstrFile); + return bRet; +} + +/*********************************************************************** + * GetFileName31W [internal] + * + * Creates a win31 style dialog box for the user to select a file to open/save + */ +static BOOL GetFileName31W(LPOPENFILENAMEW lpofn, /* addess of structure with data*/ + UINT dlgType /* type dialogue : open/save */ + ) +{ + HINSTANCE hInst; + BOOL bRet = FALSE; + PFD31_DATA lfs; + FD31_CALLBACKS callbacks; + + if (!lpofn || !FD31_Init()) return FALSE; + + FD32_SetupCallbacks(&callbacks); + lfs = FD31_AllocPrivate((LPARAM) lpofn, dlgType, &callbacks, (DWORD) TRUE); + if (lfs) + { + hInst = (HINSTANCE)GetWindowLongPtrW( lpofn->hwndOwner, GWLP_HINSTANCE ); + bRet = DialogBoxIndirectParamW( hInst, lfs->template, lpofn->hwndOwner, + FD32_FileOpenDlgProc, (LPARAM)lfs); + FD31_DestroyPrivate(lfs); + } + + TRACE("file %s, file offset %d, ext offset %d\n", + debugstr_w(lpofn->lpstrFile), lpofn->nFileOffset, lpofn->nFileExtension); + return bRet; +} + +/* ------------------ APIs ---------------------- */ + +/*********************************************************************** + * GetOpenFileNameA (COMDLG32.@) + * + * Creates a dialog box for the user to select a file to open. + * + * RETURNS + * TRUE on success: user enters a valid file + * FALSE on cancel, error, close or filename-does-not-fit-in-buffer. + * + */ +BOOL WINAPI GetOpenFileNameA( + LPOPENFILENAMEA ofn) /* [in/out] address of init structure */ +{ + BOOL win16look = FALSE; + + /* OFN_FILEMUSTEXIST implies OFN_PATHMUSTEXIST */ + if (ofn->Flags & OFN_FILEMUSTEXIST) + ofn->Flags |= OFN_PATHMUSTEXIST; + + if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE)) + win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE; + + if (win16look) + return GetFileName31A(ofn, OPEN_DIALOG); + else + return GetFileDialog95A(ofn, OPEN_DIALOG); +} + +/*********************************************************************** + * GetOpenFileNameW (COMDLG32.@) + * + * Creates a dialog box for the user to select a file to open. + * + * RETURNS + * TRUE on success: user enters a valid file + * FALSE on cancel, error, close or filename-does-not-fit-in-buffer. + * + */ +BOOL WINAPI GetOpenFileNameW( + LPOPENFILENAMEW ofn) /* [in/out] address of init structure */ +{ + BOOL win16look = FALSE; + + if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE)) + win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE; + + if (win16look) + return GetFileName31W(ofn, OPEN_DIALOG); + else + return GetFileDialog95W(ofn, OPEN_DIALOG); +} + + +/*********************************************************************** + * GetSaveFileNameA (COMDLG32.@) + * + * 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. + * + */ +BOOL WINAPI GetSaveFileNameA( + LPOPENFILENAMEA ofn) /* [in/out] address of init structure */ +{ + BOOL win16look = FALSE; + + if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE)) + win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE; + + if (win16look) + return GetFileName31A(ofn, SAVE_DIALOG); + else + return GetFileDialog95A(ofn, SAVE_DIALOG); +} + +/*********************************************************************** + * GetSaveFileNameW (COMDLG32.@) + * + * 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. + * + */ +BOOL WINAPI GetSaveFileNameW( + LPOPENFILENAMEW ofn) /* [in/out] address of init structure */ +{ + BOOL win16look = FALSE; + + if (ofn->Flags & (OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLETEMPLATE)) + win16look = (ofn->Flags & OFN_EXPLORER) ? FALSE : TRUE; + + if (win16look) + return GetFileName31W(ofn, SAVE_DIALOG); + else + return GetFileDialog95W(ofn, SAVE_DIALOG); +} diff --git a/reactos/lib/comdlg32/filedlg16.c b/reactos/lib/comdlg32/filedlg16.c index d2d34804ff7..f3a9a31e4b4 100644 --- a/reactos/lib/comdlg32/filedlg16.c +++ b/reactos/lib/comdlg32/filedlg16.c @@ -1,515 +1,515 @@ -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include "windef.h" -#include "winbase.h" -#include "wine/winbase16.h" -#include "winuser.h" -#include "wine/winuser16.h" -#include "wine/debug.h" -#include "cderr.h" -#include "commdlg.h" - -WINE_DEFAULT_DEBUG_CHANNEL(commdlg); - -#include "cdlg.h" -#include "cdlg16.h" -#include "filedlg31.h" - -typedef struct tagFD16_PRIVATE -{ - HANDLE16 hDlgTmpl16; /* handle for resource 16 */ - HANDLE16 hResource16; /* handle for allocated resource 16 */ - HANDLE16 hGlobal16; /* 16 bits mem block (resources) */ - OPENFILENAME16 *ofn16; /* original structure if 16 bits dialog */ -} FD16_PRIVATE, *PFD16_PRIVATE; - -/************************************************************************ - * FD16_MapOfnStruct16 [internal] - * map a 16 bits structure to an Unicode one - */ -void FD16_MapOfnStruct16(LPOPENFILENAME16 ofn16, LPOPENFILENAMEW ofnW, BOOL open) -{ - OPENFILENAMEA ofnA; - /* first convert to linear pointers */ - memset(&ofnA, 0, sizeof(OPENFILENAMEA)); - ofnA.lStructSize = sizeof(OPENFILENAMEA); - ofnA.hwndOwner = HWND_32(ofn16->hwndOwner); - ofnA.hInstance = HINSTANCE_32(ofn16->hInstance); - if (ofn16->lpstrFilter) - ofnA.lpstrFilter = MapSL(ofn16->lpstrFilter); - if (ofn16->lpstrCustomFilter) - ofnA.lpstrCustomFilter = MapSL(ofn16->lpstrCustomFilter); - ofnA.nMaxCustFilter = ofn16->nMaxCustFilter; - ofnA.nFilterIndex = ofn16->nFilterIndex; - ofnA.lpstrFile = MapSL(ofn16->lpstrFile); - ofnA.nMaxFile = ofn16->nMaxFile; - ofnA.lpstrFileTitle = MapSL(ofn16->lpstrFileTitle); - ofnA.nMaxFileTitle = ofn16->nMaxFileTitle; - ofnA.lpstrInitialDir = MapSL(ofn16->lpstrInitialDir); - ofnA.lpstrTitle = MapSL(ofn16->lpstrTitle); - ofnA.Flags = ofn16->Flags; - ofnA.nFileOffset = ofn16->nFileOffset; - ofnA.nFileExtension = ofn16->nFileExtension; - ofnA.lpstrDefExt = MapSL(ofn16->lpstrDefExt); - if (HIWORD(ofn16->lpTemplateName)) - ofnA.lpTemplateName = MapSL(ofn16->lpTemplateName); - else - ofnA.lpTemplateName = (LPSTR) ofn16->lpTemplateName; /* ressource number */ - /* now calls the 32 bits Ansi to Unicode version to complete the job */ - FD31_MapOfnStructA(&ofnA, ofnW, open); -} - -/*********************************************************************** - * FD16_GetTemplate [internal] - * - * Get a template (FALSE if failure) when 16 bits dialogs are used - * by a 16 bits application - * - */ -BOOL FD16_GetTemplate(PFD31_DATA lfs) -{ - PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632; - LPOPENFILENAME16 ofn16 = priv->ofn16; - LPCVOID template; - HGLOBAL16 hGlobal16 = 0; - - if (ofn16->Flags & OFN_ENABLETEMPLATEHANDLE) - priv->hDlgTmpl16 = ofn16->hInstance; - else if (ofn16->Flags & OFN_ENABLETEMPLATE) - { - HANDLE16 hResInfo; - if (!(hResInfo = FindResource16(ofn16->hInstance, - MapSL(ofn16->lpTemplateName), - (LPSTR)RT_DIALOG))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); - return FALSE; - } - if (!(priv->hDlgTmpl16 = LoadResource16( ofn16->hInstance, hResInfo ))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - priv->hResource16 = priv->hDlgTmpl16; - } - else - { /* get resource from (32 bits) own Wine resource; convert it to 16 */ - HRSRC hResInfo; - HGLOBAL hDlgTmpl32; - LPCVOID template32; - DWORD size; - - if (!(hResInfo = FindResourceA(COMDLG32_hInstance, - lfs->open ? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); - return FALSE; - } - if (!(hDlgTmpl32 = LoadResource(COMDLG32_hInstance, hResInfo )) || - !(template32 = LockResource( hDlgTmpl32 ))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - size = SizeofResource(COMDLG32_hInstance, hResInfo); - hGlobal16 = GlobalAlloc16(0, size); - if (!hGlobal16) - { - COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE); - ERR("alloc failure for %ld bytes\n", size); - return FALSE; - } - template = GlobalLock16(hGlobal16); - if (!template) - { - COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE); - ERR("global lock failure for %x handle\n", hGlobal16); - GlobalFree16(hGlobal16); - return FALSE; - } - ConvertDialog32To16((LPVOID)template32, size, (LPVOID)template); - priv->hDlgTmpl16 = hGlobal16; - priv->hGlobal16 = hGlobal16; - } - return TRUE; -} - -/************************************************************************ - * FD16_Init [internal] - * called from the common 16/32 code to initialize 16 bit data - */ -static BOOL CALLBACK FD16_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data) -{ - PFD16_PRIVATE priv; - - priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD16_PRIVATE)); - lfs->private1632 = priv; - if (NULL == lfs->private1632) return FALSE; - - priv->ofn16 = MapSL(lParam); - if (priv->ofn16->Flags & OFN_ENABLEHOOK) - if (priv->ofn16->lpfnHook) - lfs->hook = TRUE; - - lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW)); - FD16_MapOfnStruct16(priv->ofn16, lfs->ofnW, lfs->open); - - if (! FD16_GetTemplate(lfs)) return FALSE; - - return TRUE; -} - -/*********************************************************************** - * FD16_CallWindowProc [internal] - * - * called from the common 16/32 code to call the appropriate hook - */ -BOOL CALLBACK FD16_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam, - LPARAM lParam) -{ - PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632; - - if (priv->ofn16) - { - return (BOOL16) CallWindowProc16( - (WNDPROC16)priv->ofn16->lpfnHook, HWND_16(lfs->hwnd), - (UINT16)wMsg, (WPARAM16)wParam, lParam); - } - return FALSE; -} - - -/*********************************************************************** - * FD31_UpdateResult [internal] - * update the real client structures - */ -static void CALLBACK FD16_UpdateResult(PFD31_DATA lfs) -{ - PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632; - LPOPENFILENAMEW ofnW = lfs->ofnW; - - if (priv->ofn16) - { /* we have to convert to short (8.3) path */ - char tmp[1024]; /* MAX_PATHNAME_LEN */ - LPOPENFILENAME16 ofn16 = priv->ofn16; - char *dest = MapSL(ofn16->lpstrFile); - char *bs16; - if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1, - tmp, sizeof(tmp), NULL, NULL )) - tmp[sizeof(tmp)-1] = 0; - GetShortPathNameA(tmp, dest, ofn16->nMaxFile); - - /* the same procedure as every year... */ - if((bs16 = strrchr(dest, '\\')) != NULL) - ofn16->nFileOffset = bs16 - dest +1; - else - ofn16->nFileOffset = 0; - ofn16->nFileExtension = 0; - while(dest[ofn16->nFileExtension] != '.' && dest[ofn16->nFileExtension] != '\0') - ofn16->nFileExtension++; - if (dest[ofn16->nFileExtension] == '\0') - ofn16->nFileExtension = 0; - else - ofn16->nFileExtension++; - } -} - - -/*********************************************************************** - * FD16_UpdateFileTitle [internal] - * update the real client structures - */ -static void CALLBACK FD16_UpdateFileTitle(PFD31_DATA lfs) -{ - PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632; - LPOPENFILENAMEW ofnW = lfs->ofnW; - - if (priv->ofn16) - { - char *dest = MapSL(priv->ofn16->lpstrFileTitle); - if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1, - dest, ofnW->nMaxFileTitle, NULL, NULL )) - dest[ofnW->nMaxFileTitle-1] = 0; - } -} - - -/*********************************************************************** - * FD16_SendLbGetCurSel [internal] - * retrieve selected listbox item - */ -static LRESULT CALLBACK FD16_SendLbGetCurSel(PFD31_DATA lfs) -{ - return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL16, 0, 0); -} - - -/************************************************************************ - * FD16_Destroy [internal] - * called from the common 16/32 code to cleanup 32 bit data - */ -static void CALLBACK FD16_Destroy(PFD31_DATA lfs) -{ - PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632; - - /* free resources for a 16 bits dialog */ - if (NULL != priv) - { - if (priv->hResource16) FreeResource16(priv->hResource16); - if (priv->hGlobal16) - { - GlobalUnlock16(priv->hGlobal16); - GlobalFree16(priv->hGlobal16); - } - FD31_FreeOfnW(lfs->ofnW); - HeapFree(GetProcessHeap(), 0, lfs->ofnW); - } -} - -static void FD16_SetupCallbacks(PFD31_CALLBACKS callbacks) -{ - callbacks->Init = FD16_Init; - callbacks->CWP = FD16_CallWindowProc; - callbacks->UpdateResult = FD16_UpdateResult; - callbacks->UpdateFileTitle = FD16_UpdateFileTitle; - callbacks->SendLbGetCurSel = FD16_SendLbGetCurSel; - callbacks->Destroy = FD16_Destroy; -} - -/*********************************************************************** - * FD16_MapDrawItemStruct [internal] - * map a 16 bits drawitem struct to 32 - */ -static void FD16_MapDrawItemStruct(LPDRAWITEMSTRUCT16 lpdis16, LPDRAWITEMSTRUCT lpdis) -{ - lpdis->CtlType = lpdis16->CtlType; - lpdis->CtlID = lpdis16->CtlID; - lpdis->itemID = lpdis16->itemID; - lpdis->itemAction = lpdis16->itemAction; - lpdis->itemState = lpdis16->itemState; - lpdis->hwndItem = HWND_32(lpdis16->hwndItem); - lpdis->hDC = HDC_32(lpdis16->hDC); - lpdis->rcItem.right = lpdis16->rcItem.right; - lpdis->rcItem.left = lpdis16->rcItem.left; - lpdis->rcItem.top = lpdis16->rcItem.top; - lpdis->rcItem.bottom = lpdis16->rcItem.bottom; - lpdis->itemData = lpdis16->itemData; -} - - -/*********************************************************************** - * FD16_WMMeasureItem16 [internal] - */ -static LONG FD16_WMMeasureItem(HWND16 hWnd, WPARAM16 wParam, LPARAM lParam) -{ - LPMEASUREITEMSTRUCT16 lpmeasure; - - lpmeasure = MapSL(lParam); - lpmeasure->itemHeight = FD31_GetFldrHeight(); - return TRUE; -} - -/* ------------------ Dialog procedures ---------------------- */ - -/*********************************************************************** - * FileOpenDlgProc (COMMDLG.6) - */ -BOOL16 CALLBACK FileOpenDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam, LPARAM lParam) -{ - HWND hWnd = HWND_32(hWnd16); - PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP); - DRAWITEMSTRUCT dis; - - TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam); - if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook) - { - LRESULT lRet = (BOOL16)FD31_CallWindowProc(lfs, wMsg, wParam, lParam); - if (lRet) - return lRet; /* else continue message processing */ - } - switch (wMsg) - { - case WM_INITDIALOG: - return FD31_WMInitDialog(hWnd, wParam, lParam); - - case WM_MEASUREITEM: - return FD16_WMMeasureItem(hWnd16, wParam, lParam); - - case WM_DRAWITEM: - FD16_MapDrawItemStruct(MapSL(lParam), &dis); - return FD31_WMDrawItem(hWnd, wParam, lParam, FALSE, &dis); - - case WM_COMMAND: - return FD31_WMCommand(hWnd, lParam, HIWORD(lParam),wParam, lfs); -#if 0 - case WM_CTLCOLOR: - SetBkColor((HDC16)wParam, 0x00C0C0C0); - switch (HIWORD(lParam)) - { - case CTLCOLOR_BTN: - SetTextColor((HDC16)wParam, 0x00000000); - return hGRAYBrush; - case CTLCOLOR_STATIC: - SetTextColor((HDC16)wParam, 0x00000000); - return hGRAYBrush; - } - break; -#endif - } - return FALSE; -} - -/*********************************************************************** - * FileSaveDlgProc (COMMDLG.7) - */ -BOOL16 CALLBACK FileSaveDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam, LPARAM lParam) -{ - HWND hWnd = HWND_32(hWnd16); - PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP); - DRAWITEMSTRUCT dis; - - TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam); - if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook) - { - LRESULT lRet; - lRet = (BOOL16)FD31_CallWindowProc(lfs, wMsg, wParam, lParam); - if (lRet) - return lRet; /* else continue message processing */ - } - switch (wMsg) { - case WM_INITDIALOG: - return FD31_WMInitDialog(hWnd, wParam, lParam); - - case WM_MEASUREITEM: - return FD16_WMMeasureItem(hWnd16, wParam, lParam); - - case WM_DRAWITEM: - FD16_MapDrawItemStruct(MapSL(lParam), &dis); - return FD31_WMDrawItem(hWnd, wParam, lParam, TRUE, &dis); - - case WM_COMMAND: - return FD31_WMCommand(hWnd, lParam, HIWORD(lParam), wParam, lfs); - } - - /* - case WM_CTLCOLOR: - SetBkColor((HDC16)wParam, 0x00C0C0C0); - switch (HIWORD(lParam)) - { - case CTLCOLOR_BTN: - SetTextColor((HDC16)wParam, 0x00000000); - return hGRAYBrush; - case CTLCOLOR_STATIC: - SetTextColor((HDC16)wParam, 0x00000000); - return hGRAYBrush; - } - return FALSE; - - */ - return FALSE; -} - -/* ------------------ APIs ---------------------- */ - -/*********************************************************************** - * 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 FIXME's left. - */ -BOOL16 WINAPI GetOpenFileName16( - SEGPTR ofn /* [in/out] address of structure with data*/ - ) -{ - HINSTANCE16 hInst; - BOOL bRet = FALSE; - LPOPENFILENAME16 lpofn = MapSL(ofn); - PFD31_DATA lfs; - FARPROC16 ptr; - FD31_CALLBACKS callbacks; - PFD16_PRIVATE priv; - - if (!lpofn || !FD31_Init()) return FALSE; - - FD16_SetupCallbacks(&callbacks); - lfs = FD31_AllocPrivate((LPARAM) ofn, OPEN_DIALOG, &callbacks, 0); - if (lfs) - { - priv = (PFD16_PRIVATE) lfs->private1632; - hInst = GetWindowLongPtrA( HWND_32(lpofn->hwndOwner), GWLP_HINSTANCE ); - ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 6); - bRet = DialogBoxIndirectParam16( hInst, priv->hDlgTmpl16, lpofn->hwndOwner, - (DLGPROC16) ptr, (LPARAM) lfs); - FD31_DestroyPrivate(lfs); - } - - TRACE("return lpstrFile='%s' !\n", (char *)MapSL(lpofn->lpstrFile)); - return bRet; -} - -/*********************************************************************** - * 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 FIXME's left. - */ -BOOL16 WINAPI GetSaveFileName16( - SEGPTR ofn /* [in/out] addess of structure with data*/ - ) -{ - HINSTANCE16 hInst; - BOOL bRet = FALSE; - LPOPENFILENAME16 lpofn = MapSL(ofn); - PFD31_DATA lfs; - FARPROC16 ptr; - FD31_CALLBACKS callbacks; - PFD16_PRIVATE priv; - - if (!lpofn || !FD31_Init()) return FALSE; - - FD16_SetupCallbacks(&callbacks); - lfs = FD31_AllocPrivate((LPARAM) ofn, SAVE_DIALOG, &callbacks, 0); - if (lfs) - { - priv = (PFD16_PRIVATE) lfs->private1632; - hInst = GetWindowLongPtrA( HWND_32(lpofn->hwndOwner), GWLP_HINSTANCE ); - ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 7); - bRet = DialogBoxIndirectParam16( hInst, priv->hDlgTmpl16, lpofn->hwndOwner, - (DLGPROC16) ptr, (LPARAM) lfs); - FD31_DestroyPrivate(lfs); - } - - TRACE("return lpstrFile='%s' !\n", (char *)MapSL(lpofn->lpstrFile)); - return bRet; -} +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include "windef.h" +#include "winbase.h" +#include "wine/winbase16.h" +#include "winuser.h" +#include "wine/winuser16.h" +#include "wine/debug.h" +#include "cderr.h" +#include "commdlg.h" + +WINE_DEFAULT_DEBUG_CHANNEL(commdlg); + +#include "cdlg.h" +#include "cdlg16.h" +#include "filedlg31.h" + +typedef struct tagFD16_PRIVATE +{ + HANDLE16 hDlgTmpl16; /* handle for resource 16 */ + HANDLE16 hResource16; /* handle for allocated resource 16 */ + HANDLE16 hGlobal16; /* 16 bits mem block (resources) */ + OPENFILENAME16 *ofn16; /* original structure if 16 bits dialog */ +} FD16_PRIVATE, *PFD16_PRIVATE; + +/************************************************************************ + * FD16_MapOfnStruct16 [internal] + * map a 16 bits structure to an Unicode one + */ +void FD16_MapOfnStruct16(LPOPENFILENAME16 ofn16, LPOPENFILENAMEW ofnW, BOOL open) +{ + OPENFILENAMEA ofnA; + /* first convert to linear pointers */ + memset(&ofnA, 0, sizeof(OPENFILENAMEA)); + ofnA.lStructSize = sizeof(OPENFILENAMEA); + ofnA.hwndOwner = HWND_32(ofn16->hwndOwner); + ofnA.hInstance = HINSTANCE_32(ofn16->hInstance); + if (ofn16->lpstrFilter) + ofnA.lpstrFilter = MapSL(ofn16->lpstrFilter); + if (ofn16->lpstrCustomFilter) + ofnA.lpstrCustomFilter = MapSL(ofn16->lpstrCustomFilter); + ofnA.nMaxCustFilter = ofn16->nMaxCustFilter; + ofnA.nFilterIndex = ofn16->nFilterIndex; + ofnA.lpstrFile = MapSL(ofn16->lpstrFile); + ofnA.nMaxFile = ofn16->nMaxFile; + ofnA.lpstrFileTitle = MapSL(ofn16->lpstrFileTitle); + ofnA.nMaxFileTitle = ofn16->nMaxFileTitle; + ofnA.lpstrInitialDir = MapSL(ofn16->lpstrInitialDir); + ofnA.lpstrTitle = MapSL(ofn16->lpstrTitle); + ofnA.Flags = ofn16->Flags; + ofnA.nFileOffset = ofn16->nFileOffset; + ofnA.nFileExtension = ofn16->nFileExtension; + ofnA.lpstrDefExt = MapSL(ofn16->lpstrDefExt); + if (HIWORD(ofn16->lpTemplateName)) + ofnA.lpTemplateName = MapSL(ofn16->lpTemplateName); + else + ofnA.lpTemplateName = (LPSTR) ofn16->lpTemplateName; /* ressource number */ + /* now calls the 32 bits Ansi to Unicode version to complete the job */ + FD31_MapOfnStructA(&ofnA, ofnW, open); +} + +/*********************************************************************** + * FD16_GetTemplate [internal] + * + * Get a template (FALSE if failure) when 16 bits dialogs are used + * by a 16 bits application + * + */ +BOOL FD16_GetTemplate(PFD31_DATA lfs) +{ + PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632; + LPOPENFILENAME16 ofn16 = priv->ofn16; + LPCVOID template; + HGLOBAL16 hGlobal16 = 0; + + if (ofn16->Flags & OFN_ENABLETEMPLATEHANDLE) + priv->hDlgTmpl16 = ofn16->hInstance; + else if (ofn16->Flags & OFN_ENABLETEMPLATE) + { + HANDLE16 hResInfo; + if (!(hResInfo = FindResource16(ofn16->hInstance, + MapSL(ofn16->lpTemplateName), + (LPSTR)RT_DIALOG))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); + return FALSE; + } + if (!(priv->hDlgTmpl16 = LoadResource16( ofn16->hInstance, hResInfo ))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + priv->hResource16 = priv->hDlgTmpl16; + } + else + { /* get resource from (32 bits) own Wine resource; convert it to 16 */ + HRSRC hResInfo; + HGLOBAL hDlgTmpl32; + LPCVOID template32; + DWORD size; + + if (!(hResInfo = FindResourceA(COMDLG32_hInstance, + lfs->open ? "OPEN_FILE":"SAVE_FILE", (LPSTR)RT_DIALOG))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); + return FALSE; + } + if (!(hDlgTmpl32 = LoadResource(COMDLG32_hInstance, hResInfo )) || + !(template32 = LockResource( hDlgTmpl32 ))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + size = SizeofResource(COMDLG32_hInstance, hResInfo); + hGlobal16 = GlobalAlloc16(0, size); + if (!hGlobal16) + { + COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE); + ERR("alloc failure for %ld bytes\n", size); + return FALSE; + } + template = GlobalLock16(hGlobal16); + if (!template) + { + COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE); + ERR("global lock failure for %x handle\n", hGlobal16); + GlobalFree16(hGlobal16); + return FALSE; + } + ConvertDialog32To16((LPVOID)template32, size, (LPVOID)template); + priv->hDlgTmpl16 = hGlobal16; + priv->hGlobal16 = hGlobal16; + } + return TRUE; +} + +/************************************************************************ + * FD16_Init [internal] + * called from the common 16/32 code to initialize 16 bit data + */ +static BOOL CALLBACK FD16_Init(LPARAM lParam, PFD31_DATA lfs, DWORD data) +{ + PFD16_PRIVATE priv; + + priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD16_PRIVATE)); + lfs->private1632 = priv; + if (NULL == lfs->private1632) return FALSE; + + priv->ofn16 = MapSL(lParam); + if (priv->ofn16->Flags & OFN_ENABLEHOOK) + if (priv->ofn16->lpfnHook) + lfs->hook = TRUE; + + lfs->ofnW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lfs->ofnW)); + FD16_MapOfnStruct16(priv->ofn16, lfs->ofnW, lfs->open); + + if (! FD16_GetTemplate(lfs)) return FALSE; + + return TRUE; +} + +/*********************************************************************** + * FD16_CallWindowProc [internal] + * + * called from the common 16/32 code to call the appropriate hook + */ +BOOL CALLBACK FD16_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam, + LPARAM lParam) +{ + PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632; + + if (priv->ofn16) + { + return (BOOL16) CallWindowProc16( + (WNDPROC16)priv->ofn16->lpfnHook, HWND_16(lfs->hwnd), + (UINT16)wMsg, (WPARAM16)wParam, lParam); + } + return FALSE; +} + + +/*********************************************************************** + * FD31_UpdateResult [internal] + * update the real client structures + */ +static void CALLBACK FD16_UpdateResult(PFD31_DATA lfs) +{ + PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632; + LPOPENFILENAMEW ofnW = lfs->ofnW; + + if (priv->ofn16) + { /* we have to convert to short (8.3) path */ + char tmp[1024]; /* MAX_PATHNAME_LEN */ + LPOPENFILENAME16 ofn16 = priv->ofn16; + char *dest = MapSL(ofn16->lpstrFile); + char *bs16; + if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFile, -1, + tmp, sizeof(tmp), NULL, NULL )) + tmp[sizeof(tmp)-1] = 0; + GetShortPathNameA(tmp, dest, ofn16->nMaxFile); + + /* the same procedure as every year... */ + if((bs16 = strrchr(dest, '\\')) != NULL) + ofn16->nFileOffset = bs16 - dest +1; + else + ofn16->nFileOffset = 0; + ofn16->nFileExtension = 0; + while(dest[ofn16->nFileExtension] != '.' && dest[ofn16->nFileExtension] != '\0') + ofn16->nFileExtension++; + if (dest[ofn16->nFileExtension] == '\0') + ofn16->nFileExtension = 0; + else + ofn16->nFileExtension++; + } +} + + +/*********************************************************************** + * FD16_UpdateFileTitle [internal] + * update the real client structures + */ +static void CALLBACK FD16_UpdateFileTitle(PFD31_DATA lfs) +{ + PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632; + LPOPENFILENAMEW ofnW = lfs->ofnW; + + if (priv->ofn16) + { + char *dest = MapSL(priv->ofn16->lpstrFileTitle); + if (!WideCharToMultiByte( CP_ACP, 0, ofnW->lpstrFileTitle, -1, + dest, ofnW->nMaxFileTitle, NULL, NULL )) + dest[ofnW->nMaxFileTitle-1] = 0; + } +} + + +/*********************************************************************** + * FD16_SendLbGetCurSel [internal] + * retrieve selected listbox item + */ +static LRESULT CALLBACK FD16_SendLbGetCurSel(PFD31_DATA lfs) +{ + return SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL16, 0, 0); +} + + +/************************************************************************ + * FD16_Destroy [internal] + * called from the common 16/32 code to cleanup 32 bit data + */ +static void CALLBACK FD16_Destroy(PFD31_DATA lfs) +{ + PFD16_PRIVATE priv = (PFD16_PRIVATE) lfs->private1632; + + /* free resources for a 16 bits dialog */ + if (NULL != priv) + { + if (priv->hResource16) FreeResource16(priv->hResource16); + if (priv->hGlobal16) + { + GlobalUnlock16(priv->hGlobal16); + GlobalFree16(priv->hGlobal16); + } + FD31_FreeOfnW(lfs->ofnW); + HeapFree(GetProcessHeap(), 0, lfs->ofnW); + } +} + +static void FD16_SetupCallbacks(PFD31_CALLBACKS callbacks) +{ + callbacks->Init = FD16_Init; + callbacks->CWP = FD16_CallWindowProc; + callbacks->UpdateResult = FD16_UpdateResult; + callbacks->UpdateFileTitle = FD16_UpdateFileTitle; + callbacks->SendLbGetCurSel = FD16_SendLbGetCurSel; + callbacks->Destroy = FD16_Destroy; +} + +/*********************************************************************** + * FD16_MapDrawItemStruct [internal] + * map a 16 bits drawitem struct to 32 + */ +static void FD16_MapDrawItemStruct(LPDRAWITEMSTRUCT16 lpdis16, LPDRAWITEMSTRUCT lpdis) +{ + lpdis->CtlType = lpdis16->CtlType; + lpdis->CtlID = lpdis16->CtlID; + lpdis->itemID = lpdis16->itemID; + lpdis->itemAction = lpdis16->itemAction; + lpdis->itemState = lpdis16->itemState; + lpdis->hwndItem = HWND_32(lpdis16->hwndItem); + lpdis->hDC = HDC_32(lpdis16->hDC); + lpdis->rcItem.right = lpdis16->rcItem.right; + lpdis->rcItem.left = lpdis16->rcItem.left; + lpdis->rcItem.top = lpdis16->rcItem.top; + lpdis->rcItem.bottom = lpdis16->rcItem.bottom; + lpdis->itemData = lpdis16->itemData; +} + + +/*********************************************************************** + * FD16_WMMeasureItem16 [internal] + */ +static LONG FD16_WMMeasureItem(HWND16 hWnd, WPARAM16 wParam, LPARAM lParam) +{ + LPMEASUREITEMSTRUCT16 lpmeasure; + + lpmeasure = MapSL(lParam); + lpmeasure->itemHeight = FD31_GetFldrHeight(); + return TRUE; +} + +/* ------------------ Dialog procedures ---------------------- */ + +/*********************************************************************** + * FileOpenDlgProc (COMMDLG.6) + */ +BOOL16 CALLBACK FileOpenDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam, LPARAM lParam) +{ + HWND hWnd = HWND_32(hWnd16); + PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP); + DRAWITEMSTRUCT dis; + + TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam); + if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook) + { + LRESULT lRet = (BOOL16)FD31_CallWindowProc(lfs, wMsg, wParam, lParam); + if (lRet) + return lRet; /* else continue message processing */ + } + switch (wMsg) + { + case WM_INITDIALOG: + return FD31_WMInitDialog(hWnd, wParam, lParam); + + case WM_MEASUREITEM: + return FD16_WMMeasureItem(hWnd16, wParam, lParam); + + case WM_DRAWITEM: + FD16_MapDrawItemStruct(MapSL(lParam), &dis); + return FD31_WMDrawItem(hWnd, wParam, lParam, FALSE, &dis); + + case WM_COMMAND: + return FD31_WMCommand(hWnd, lParam, HIWORD(lParam),wParam, lfs); +#if 0 + case WM_CTLCOLOR: + SetBkColor((HDC16)wParam, 0x00C0C0C0); + switch (HIWORD(lParam)) + { + case CTLCOLOR_BTN: + SetTextColor((HDC16)wParam, 0x00000000); + return hGRAYBrush; + case CTLCOLOR_STATIC: + SetTextColor((HDC16)wParam, 0x00000000); + return hGRAYBrush; + } + break; +#endif + } + return FALSE; +} + +/*********************************************************************** + * FileSaveDlgProc (COMMDLG.7) + */ +BOOL16 CALLBACK FileSaveDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam, LPARAM lParam) +{ + HWND hWnd = HWND_32(hWnd16); + PFD31_DATA lfs = (PFD31_DATA)GetPropA(hWnd,FD31_OFN_PROP); + DRAWITEMSTRUCT dis; + + TRACE("msg=%x wparam=%x lParam=%lx\n", wMsg, wParam, lParam); + if ((wMsg != WM_INITDIALOG) && lfs && lfs->hook) + { + LRESULT lRet; + lRet = (BOOL16)FD31_CallWindowProc(lfs, wMsg, wParam, lParam); + if (lRet) + return lRet; /* else continue message processing */ + } + switch (wMsg) { + case WM_INITDIALOG: + return FD31_WMInitDialog(hWnd, wParam, lParam); + + case WM_MEASUREITEM: + return FD16_WMMeasureItem(hWnd16, wParam, lParam); + + case WM_DRAWITEM: + FD16_MapDrawItemStruct(MapSL(lParam), &dis); + return FD31_WMDrawItem(hWnd, wParam, lParam, TRUE, &dis); + + case WM_COMMAND: + return FD31_WMCommand(hWnd, lParam, HIWORD(lParam), wParam, lfs); + } + + /* + case WM_CTLCOLOR: + SetBkColor((HDC16)wParam, 0x00C0C0C0); + switch (HIWORD(lParam)) + { + case CTLCOLOR_BTN: + SetTextColor((HDC16)wParam, 0x00000000); + return hGRAYBrush; + case CTLCOLOR_STATIC: + SetTextColor((HDC16)wParam, 0x00000000); + return hGRAYBrush; + } + return FALSE; + + */ + return FALSE; +} + +/* ------------------ APIs ---------------------- */ + +/*********************************************************************** + * 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 FIXME's left. + */ +BOOL16 WINAPI GetOpenFileName16( + SEGPTR ofn /* [in/out] address of structure with data*/ + ) +{ + HINSTANCE16 hInst; + BOOL bRet = FALSE; + LPOPENFILENAME16 lpofn = MapSL(ofn); + PFD31_DATA lfs; + FARPROC16 ptr; + FD31_CALLBACKS callbacks; + PFD16_PRIVATE priv; + + if (!lpofn || !FD31_Init()) return FALSE; + + FD16_SetupCallbacks(&callbacks); + lfs = FD31_AllocPrivate((LPARAM) ofn, OPEN_DIALOG, &callbacks, 0); + if (lfs) + { + priv = (PFD16_PRIVATE) lfs->private1632; + hInst = GetWindowLongPtrA( HWND_32(lpofn->hwndOwner), GWLP_HINSTANCE ); + ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 6); + bRet = DialogBoxIndirectParam16( hInst, priv->hDlgTmpl16, lpofn->hwndOwner, + (DLGPROC16) ptr, (LPARAM) lfs); + FD31_DestroyPrivate(lfs); + } + + TRACE("return lpstrFile='%s' !\n", (char *)MapSL(lpofn->lpstrFile)); + return bRet; +} + +/*********************************************************************** + * 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 FIXME's left. + */ +BOOL16 WINAPI GetSaveFileName16( + SEGPTR ofn /* [in/out] addess of structure with data*/ + ) +{ + HINSTANCE16 hInst; + BOOL bRet = FALSE; + LPOPENFILENAME16 lpofn = MapSL(ofn); + PFD31_DATA lfs; + FARPROC16 ptr; + FD31_CALLBACKS callbacks; + PFD16_PRIVATE priv; + + if (!lpofn || !FD31_Init()) return FALSE; + + FD16_SetupCallbacks(&callbacks); + lfs = FD31_AllocPrivate((LPARAM) ofn, SAVE_DIALOG, &callbacks, 0); + if (lfs) + { + priv = (PFD16_PRIVATE) lfs->private1632; + hInst = GetWindowLongPtrA( HWND_32(lpofn->hwndOwner), GWLP_HINSTANCE ); + ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 7); + bRet = DialogBoxIndirectParam16( hInst, priv->hDlgTmpl16, lpofn->hwndOwner, + (DLGPROC16) ptr, (LPARAM) lfs); + FD31_DestroyPrivate(lfs); + } + + TRACE("return lpstrFile='%s' !\n", (char *)MapSL(lpofn->lpstrFile)); + return bRet; +} diff --git a/reactos/lib/comdlg32/filedlg31.c b/reactos/lib/comdlg32/filedlg31.c index 9542e557854..735e4252b65 100644 --- a/reactos/lib/comdlg32/filedlg31.c +++ b/reactos/lib/comdlg32/filedlg31.c @@ -1,932 +1,932 @@ -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "wingdi.h" -#include "winuser.h" -#include "wine/unicode.h" -#include "wine/debug.h" -#include "cderr.h" -#include "winreg.h" -#include "winternl.h" -#include "winuser.h" -#include "commdlg.h" -#include "cderr.h" -#include "winreg.h" -#include "winternl.h" -#include "shlwapi.h" - -WINE_DEFAULT_DEBUG_CHANNEL(commdlg); - -#include "cdlg.h" -#include "filedlg31.h" - -#define BUFFILE 512 -#define BUFFILEALLOC 512 * sizeof(WCHAR) - -static const WCHAR FILE_star[] = {'*','.','*', 0}; -static const WCHAR FILE_bslash[] = {'\\', 0}; -static const WCHAR FILE_specc[] = {'%','c',':', 0}; -static const int fldrHeight = 16; -static const int fldrWidth = 20; - -static HICON hFolder = 0; -static HICON hFolder2 = 0; -static HICON hFloppy = 0; -static HICON hHDisk = 0; -static HICON hCDRom = 0; -static HICON hNet = 0; - -/*********************************************************************** - * FD31_Init [internal] - */ -BOOL FD31_Init(void) -{ - static BOOL initialized = 0; - - if (!initialized) { - hFolder = LoadImageA( COMDLG32_hInstance, "FOLDER", IMAGE_ICON, 16, 16, LR_SHARED ); - hFolder2 = LoadImageA( COMDLG32_hInstance, "FOLDER2", IMAGE_ICON, 16, 16, LR_SHARED ); - hFloppy = LoadImageA( COMDLG32_hInstance, "FLOPPY", IMAGE_ICON, 16, 16, LR_SHARED ); - hHDisk = LoadImageA( COMDLG32_hInstance, "HDISK", IMAGE_ICON, 16, 16, LR_SHARED ); - hCDRom = LoadImageA( COMDLG32_hInstance, "CDROM", IMAGE_ICON, 16, 16, LR_SHARED ); - hNet = LoadImageA( COMDLG32_hInstance, "NETWORK", IMAGE_ICON, 16, 16, LR_SHARED ); - if (hFolder == 0 || hFolder2 == 0 || hFloppy == 0 || - hHDisk == 0 || hCDRom == 0 || hNet == 0) - { - ERR("Error loading icons !\n"); - return FALSE; - } - initialized = TRUE; - } - return TRUE; -} - -/*********************************************************************** - * FD31_StripEditControl [internal] - * Strip pathnames off the contents of the edit control. - */ -static void FD31_StripEditControl(HWND hwnd) -{ - WCHAR temp[BUFFILE], *cp; - - GetDlgItemTextW( hwnd, edt1, temp, sizeof(temp)/sizeof(WCHAR)); - cp = strrchrW(temp, '\\'); - if (cp != NULL) { - strcpyW(temp, cp+1); - } - cp = strrchrW(temp, ':'); - if (cp != NULL) { - strcpyW(temp, cp+1); - } - /* FIXME: shouldn't we do something with the result here? ;-) */ -} - -/*********************************************************************** - * FD31_CallWindowProc [internal] - * - * Call the appropriate hook - */ -BOOL FD31_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam, - LPARAM lParam) -{ - return lfs->callbacks->CWP(lfs, wMsg, wParam, lParam); -} - -/*********************************************************************** - * FD31_ScanDir [internal] - */ -static BOOL FD31_ScanDir(HWND hWnd, LPWSTR newPath) -{ - WCHAR buffer[BUFFILE]; - HWND hdlg, hdlgDir; - LRESULT lRet = TRUE; - HCURSOR hCursorWait, oldCursor; - - TRACE("Trying to change to %s\n", debugstr_w(newPath)); - if ( newPath[0] && !SetCurrentDirectoryW( newPath )) - return FALSE; - lstrcpynW(buffer, newPath, sizeof(buffer)/sizeof(WCHAR)); - - /* get the list of spec files */ - GetDlgItemTextW(hWnd, edt1, buffer, sizeof(buffer)/sizeof(WCHAR)); - - hCursorWait = LoadCursorA(0, (LPSTR)IDC_WAIT); - oldCursor = SetCursor(hCursorWait); - - /* list of files */ - if ((hdlg = GetDlgItem(hWnd, lst1)) != 0) { - WCHAR* scptr; /* ptr on semi-colon */ - WCHAR* filter = buffer; - - TRACE("Using filter %s\n", debugstr_w(filter)); - SendMessageW(hdlg, LB_RESETCONTENT, 0, 0); - while (filter) { - scptr = strchrW(filter, ';'); - if (scptr) *scptr = 0; - while (*filter == ' ') filter++; - TRACE("Using file spec %s\n", debugstr_w(filter)); - if (SendMessageW(hdlg, LB_DIR, 0, (LPARAM)filter) == LB_ERR) - return FALSE; - if (scptr) *scptr = ';'; - filter = (scptr) ? (scptr + 1) : 0; - } - } - - /* list of directories */ - strcpyW(buffer, FILE_star); - - if ((hdlgDir = GetDlgItem(hWnd, lst2)) != 0) { - lRet = DlgDirListW(hWnd, buffer, lst2, stc1, DDL_EXCLUSIVE | DDL_DIRECTORY); - } - SetCursor(oldCursor); - return lRet; -} - -/*********************************************************************** - * FD31_GetFileType [internal] - */ - -static LPWSTR FD31_GetFileType(LPWSTR cfptr, LPWSTR fptr, WORD index) -{ - int n, i; - i = 0; - if (cfptr) - for ( ;(n = lstrlenW(cfptr)) != 0; i++) - { - cfptr += n + 1; - if (i == index) - return cfptr; - cfptr += lstrlenW(cfptr) + 1; - } - if (fptr) - for ( ;(n = lstrlenW(fptr)) != 0; i++) - { - fptr += n + 1; - if (i == index) - return fptr; - fptr += lstrlenW(fptr) + 1; - } - return (LPWSTR) FILE_star; /* FIXME */ -} - -/*********************************************************************** - * FD31_WMDrawItem [internal] - */ -LONG FD31_WMDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam, - int savedlg, LPDRAWITEMSTRUCT lpdis) -{ - WCHAR *str; - HICON hIcon; - COLORREF oldText = 0, oldBk = 0; - - if (lpdis->CtlType == ODT_LISTBOX && lpdis->CtlID == lst1) - { - if (!(str = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC))) return FALSE; - SendMessageW(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID, - (LPARAM)str); - - if ((lpdis->itemState & ODS_SELECTED) && !savedlg) - { - oldBk = SetBkColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) ); - oldText = SetTextColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); - } - if (savedlg) - SetTextColor(lpdis->hDC,GetSysColor(COLOR_GRAYTEXT) ); - - ExtTextOutW(lpdis->hDC, lpdis->rcItem.left + 1, - lpdis->rcItem.top + 1, ETO_OPAQUE | ETO_CLIPPED, - &(lpdis->rcItem), str, lstrlenW(str), NULL); - - if (lpdis->itemState & ODS_SELECTED) - DrawFocusRect( lpdis->hDC, &(lpdis->rcItem) ); - - if ((lpdis->itemState & ODS_SELECTED) && !savedlg) - { - SetBkColor( lpdis->hDC, oldBk ); - SetTextColor( lpdis->hDC, oldText ); - } - HeapFree(GetProcessHeap(), 0, str); - return TRUE; - } - - if (lpdis->CtlType == ODT_LISTBOX && lpdis->CtlID == lst2) - { - if (!(str = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC))) - return FALSE; - SendMessageW(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID, - (LPARAM)str); - - if (lpdis->itemState & ODS_SELECTED) - { - oldBk = SetBkColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) ); - oldText = SetTextColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); - } - ExtTextOutW(lpdis->hDC, lpdis->rcItem.left + fldrWidth, - lpdis->rcItem.top + 1, ETO_OPAQUE | ETO_CLIPPED, - &(lpdis->rcItem), str, lstrlenW(str), NULL); - - if (lpdis->itemState & ODS_SELECTED) - DrawFocusRect( lpdis->hDC, &(lpdis->rcItem) ); - - if (lpdis->itemState & ODS_SELECTED) - { - SetBkColor( lpdis->hDC, oldBk ); - SetTextColor( lpdis->hDC, oldText ); - } - DrawIcon(lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, hFolder); - HeapFree(GetProcessHeap(), 0, str); - return TRUE; - } - if (lpdis->CtlType == ODT_COMBOBOX && lpdis->CtlID == cmb2) - { - char root[] = "a:"; - if (!(str = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC))) - return FALSE; - SendMessageW(lpdis->hwndItem, CB_GETLBTEXT, lpdis->itemID, - (LPARAM)str); - root[0] += str[2] - 'a'; - switch(GetDriveTypeA(root)) - { - case DRIVE_REMOVABLE: hIcon = hFloppy; break; - case DRIVE_CDROM: hIcon = hCDRom; break; - case DRIVE_REMOTE: hIcon = hNet; break; - case DRIVE_FIXED: - default: hIcon = hHDisk; break; - } - if (lpdis->itemState & ODS_SELECTED) - { - oldBk = SetBkColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) ); - oldText = SetTextColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); - } - ExtTextOutW(lpdis->hDC, lpdis->rcItem.left + fldrWidth, - lpdis->rcItem.top + 1, ETO_OPAQUE | ETO_CLIPPED, - &(lpdis->rcItem), str, lstrlenW(str), NULL); - - if (lpdis->itemState & ODS_SELECTED) - { - SetBkColor( lpdis->hDC, oldBk ); - SetTextColor( lpdis->hDC, oldText ); - } - DrawIcon(lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, hIcon); - HeapFree(GetProcessHeap(), 0, str); - return TRUE; - } - return FALSE; -} - -/*********************************************************************** - * FD31_UpdateResult [internal] - * update the displayed file name (with path) - */ -void FD31_UpdateResult(PFD31_DATA lfs, WCHAR *tmpstr) -{ - int lenstr2; - LPOPENFILENAMEW ofnW = lfs->ofnW; - WCHAR tmpstr2[BUFFILE]; - WCHAR *p; - - TRACE("%s\n", debugstr_w(tmpstr)); - if(ofnW->Flags & OFN_NOVALIDATE) - tmpstr2[0] = '\0'; - else - GetCurrentDirectoryW(BUFFILE, tmpstr2); - lenstr2 = strlenW(tmpstr2); - if (lenstr2 > 3) - tmpstr2[lenstr2++]='\\'; - lstrcpynW(tmpstr2+lenstr2, tmpstr, BUFFILE-lenstr2); - if (ofnW->lpstrFile) - lstrcpynW(ofnW->lpstrFile, tmpstr2, ofnW->nMaxFile); - - /* set filename offset */ - p = PathFindFileNameW(ofnW->lpstrFile); - ofnW->nFileOffset = (p - ofnW->lpstrFile); - - /* set extension offset */ - p = PathFindExtensionW(ofnW->lpstrFile); - ofnW->nFileExtension = (*p) ? (p - ofnW->lpstrFile) + 1 : 0; - - TRACE("file %s, file offset %d, ext offset %d\n", - debugstr_w(ofnW->lpstrFile), ofnW->nFileOffset, ofnW->nFileExtension); - - /* update the real client structures if any */ - lfs->callbacks->UpdateResult(lfs); -} - -/*********************************************************************** - * FD31_UpdateFileTitle [internal] - * update the displayed file name (without path) - */ -void FD31_UpdateFileTitle(PFD31_DATA lfs) -{ - LONG lRet; - LPOPENFILENAMEW ofnW = lfs->ofnW; - if (ofnW->lpstrFileTitle != NULL) - { - lRet = SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0); - SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETTEXT, lRet, - (LPARAM)ofnW->lpstrFileTitle ); - lfs->callbacks->UpdateFileTitle(lfs); - } -} - -/*********************************************************************** - * FD31_DirListDblClick [internal] - */ -static LRESULT FD31_DirListDblClick( PFD31_DATA lfs ) -{ - LONG lRet; - HWND hWnd = lfs->hwnd; - LPWSTR pstr; - WCHAR tmpstr[BUFFILE]; - - /* get the raw string (with brackets) */ - lRet = SendDlgItemMessageW(hWnd, lst2, LB_GETCURSEL, 0, 0); - if (lRet == LB_ERR) return TRUE; - pstr = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC); - SendDlgItemMessageW(hWnd, lst2, LB_GETTEXT, lRet, - (LPARAM)pstr); - strcpyW( tmpstr, pstr ); - HeapFree(GetProcessHeap(), 0, pstr); - /* get the selected directory in tmpstr */ - if (tmpstr[0] == '[') - { - tmpstr[lstrlenW(tmpstr) - 1] = 0; - strcpyW(tmpstr,tmpstr+1); - } - strcatW(tmpstr, FILE_bslash); - - FD31_ScanDir(hWnd, tmpstr); - /* notify the app */ - if (lfs->hook) - { - if (FD31_CallWindowProc(lfs, lfs->lbselchstring, lst2, - MAKELONG(lRet,CD_LBSELCHANGE))) - return TRUE; - } - return TRUE; -} - -/*********************************************************************** - * FD31_FileListSelect [internal] - * called when a new item is picked in the file list - */ -static LRESULT FD31_FileListSelect( PFD31_DATA lfs ) -{ - LONG lRet; - HWND hWnd = lfs->hwnd; - LPWSTR pstr; - - lRet = lfs->callbacks->SendLbGetCurSel(lfs); - if (lRet == LB_ERR) - return TRUE; - - /* set the edit control to the choosen file */ - if ((pstr = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC))) - { - SendDlgItemMessageW(hWnd, lst1, LB_GETTEXT, lRet, - (LPARAM)pstr); - SetDlgItemTextW( hWnd, edt1, pstr ); - HeapFree(GetProcessHeap(), 0, pstr); - } - if (lfs->hook) - { - FD31_CallWindowProc(lfs, lfs->lbselchstring, lst1, - MAKELONG(lRet,CD_LBSELCHANGE)); - } - /* FIXME: for OFN_ALLOWMULTISELECT we need CD_LBSELSUB, CD_SELADD, - CD_LBSELNOITEMS */ - return TRUE; -} - -/*********************************************************************** - * FD31_TestPath [internal] - * before accepting the file name, test if it includes wild cards - * tries to scan the directory and returns TRUE if no error. - */ -static LRESULT FD31_TestPath( PFD31_DATA lfs, LPWSTR path ) -{ - HWND hWnd = lfs->hwnd; - LPWSTR pBeginFileName, pstr2; - WCHAR tmpstr2[BUFFILE]; - - pBeginFileName = strrchrW(path, '\\'); - if (pBeginFileName == NULL) - pBeginFileName = strrchrW(path, ':'); - - if (strchrW(path,'*') != NULL || strchrW(path,'?') != NULL) - { - /* edit control contains wildcards */ - if (pBeginFileName != NULL) - { - lstrcpynW(tmpstr2, pBeginFileName + 1, BUFFILE); - *(pBeginFileName + 1) = 0; - } - else - { - strcpyW(tmpstr2, path); - if(!(lfs->ofnW->Flags & OFN_NOVALIDATE)) - *path = 0; - } - - TRACE("path=%s, tmpstr2=%s\n", debugstr_w(path), debugstr_w(tmpstr2)); - SetDlgItemTextW( hWnd, edt1, tmpstr2 ); - FD31_ScanDir(hWnd, path); - return (lfs->ofnW->Flags & OFN_NOVALIDATE) ? TRUE : FALSE; - } - - /* no wildcards, we might have a directory or a filename */ - /* try appending a wildcard and reading the directory */ - - pstr2 = path + lstrlenW(path); - if (pBeginFileName == NULL || *(pBeginFileName + 1) != 0) - strcatW(path, FILE_bslash); - - /* if ScanDir succeeds, we have changed the directory */ - if (FD31_ScanDir(hWnd, path)) - return FALSE; /* and path is not a valid file name */ - - /* if not, this must be a filename */ - - *pstr2 = 0; /* remove the wildcard added before */ - - if (pBeginFileName != NULL) - { - /* strip off the pathname */ - *pBeginFileName = 0; - SetDlgItemTextW( hWnd, edt1, pBeginFileName + 1 ); - - lstrcpynW(tmpstr2, pBeginFileName + 1, sizeof(tmpstr2)/sizeof(WCHAR) ); - /* Should we MessageBox() if this fails? */ - if (!FD31_ScanDir(hWnd, path)) - { - return FALSE; - } - strcpyW(path, tmpstr2); - } - else - SetDlgItemTextW( hWnd, edt1, path ); - return TRUE; -} - -/*********************************************************************** - * FD31_Validate [internal] - * called on: click Ok button, Enter in edit, DoubleClick in file list - */ -static LRESULT FD31_Validate( PFD31_DATA lfs, LPWSTR path, UINT control, INT itemIndex, - BOOL internalUse ) -{ - LONG lRet; - HWND hWnd = lfs->hwnd; - OPENFILENAMEW ofnsav; - LPOPENFILENAMEW ofnW = lfs->ofnW; - WCHAR filename[BUFFILE]; - - ofnsav = *ofnW; /* for later restoring */ - - /* get current file name */ - if (path) - lstrcpynW(filename, path, sizeof(filename)/sizeof(WCHAR)); - else - GetDlgItemTextW( hWnd, edt1, filename, sizeof(filename)/sizeof(WCHAR)); - - TRACE("got filename = %s\n", debugstr_w(filename)); - /* if we did not click in file list to get there */ - if (control != lst1) - { - if (!FD31_TestPath( lfs, filename) ) - return FALSE; - } - FD31_UpdateResult(lfs, filename); - - if (internalUse) - { /* called internally after a change in a combo */ - if (lfs->hook) - { - FD31_CallWindowProc(lfs, lfs->lbselchstring, control, - MAKELONG(itemIndex,CD_LBSELCHANGE)); - } - return TRUE; - } - - FD31_UpdateFileTitle(lfs); - if (lfs->hook) - { - lRet = (BOOL)FD31_CallWindowProc(lfs, lfs->fileokstring, - 0, lfs->lParam ); - if (lRet) - { - *ofnW = ofnsav; /* restore old state */ - return FALSE; - } - } - if ((ofnW->Flags & OFN_ALLOWMULTISELECT) && (ofnW->Flags & OFN_EXPLORER)) - { - if (ofnW->lpstrFile) - { - LPWSTR str = (LPWSTR)ofnW->lpstrFile; - LPWSTR ptr = strrchrW(str, '\\'); - str[lstrlenW(str) + 1] = '\0'; - *ptr = 0; - } - } - return TRUE; -} - -/*********************************************************************** - * FD31_DiskChange [internal] - * called when a new item is picked in the disk selection combo - */ -static LRESULT FD31_DiskChange( PFD31_DATA lfs ) -{ - LONG lRet; - HWND hWnd = lfs->hwnd; - LPWSTR pstr; - WCHAR diskname[BUFFILE]; - - FD31_StripEditControl(hWnd); - lRet = SendDlgItemMessageW(hWnd, cmb2, CB_GETCURSEL, 0, 0L); - if (lRet == LB_ERR) - return 0; - pstr = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC); - SendDlgItemMessageW(hWnd, cmb2, CB_GETLBTEXT, lRet, - (LPARAM)pstr); - wsprintfW(diskname, FILE_specc, pstr[2]); - HeapFree(GetProcessHeap(), 0, pstr); - - return FD31_Validate( lfs, diskname, cmb2, lRet, TRUE ); -} - -/*********************************************************************** - * FD31_FileTypeChange [internal] - * called when a new item is picked in the file type combo - */ -static LRESULT FD31_FileTypeChange( PFD31_DATA lfs ) -{ - LONG lRet; - LPWSTR pstr; - - lRet = SendDlgItemMessageW(lfs->hwnd, cmb1, CB_GETCURSEL, 0, 0); - if (lRet == LB_ERR) - return TRUE; - pstr = (LPWSTR)SendDlgItemMessageW(lfs->hwnd, cmb1, CB_GETITEMDATA, lRet, 0); - TRACE("Selected filter : %s\n", debugstr_w(pstr)); - SetDlgItemTextW( lfs->hwnd, edt1, pstr ); - - return FD31_Validate( lfs, NULL, cmb1, lRet, TRUE ); -} - -/*********************************************************************** - * FD31_WMCommand [internal] - */ -LRESULT FD31_WMCommand(HWND hWnd, LPARAM lParam, UINT notification, - UINT control, PFD31_DATA lfs ) -{ - switch (control) - { - case lst1: /* file list */ - FD31_StripEditControl(hWnd); - if (notification == LBN_DBLCLK) - { - return SendMessageW(hWnd, WM_COMMAND, IDOK, 0); - } - else if (notification == LBN_SELCHANGE) - return FD31_FileListSelect( lfs ); - break; - - case lst2: /* directory list */ - FD31_StripEditControl(hWnd); - if (notification == LBN_DBLCLK) - return FD31_DirListDblClick( lfs ); - break; - - case cmb1: /* file type drop list */ - if (notification == CBN_SELCHANGE) - return FD31_FileTypeChange( lfs ); - break; - - case chx1: - break; - - case pshHelp: - break; - - case cmb2: /* disk dropdown combo */ - if (notification == CBN_SELCHANGE) - return FD31_DiskChange( lfs ); - break; - - case IDOK: - TRACE("OK pressed\n"); - if (FD31_Validate( lfs, NULL, control, 0, FALSE )) - EndDialog(hWnd, TRUE); - return TRUE; - - case IDCANCEL: - EndDialog(hWnd, FALSE); - return TRUE; - - case IDABORT: /* can be sent by the hook procedure */ - EndDialog(hWnd, TRUE); - return TRUE; - } - return FALSE; -} - -/************************************************************************ - * FD31_MapStringPairsToW [internal] - * map string pairs to Unicode - */ -static LPWSTR FD31_MapStringPairsToW(LPCSTR strA, UINT size) -{ - LPCSTR s; - LPWSTR x; - unsigned int n, len; - - s = strA; - while (*s) - s = s+strlen(s)+1; - s++; - n = s + 1 - strA; /* Don't forget the other \0 */ - if (n < size) n = size; - - len = MultiByteToWideChar( CP_ACP, 0, strA, n, NULL, 0 ); - x = HeapAlloc(GetProcessHeap(),0, len * sizeof(WCHAR)); - MultiByteToWideChar( CP_ACP, 0, strA, n, x, len ); - return x; -} - - -/************************************************************************ - * FD31_DupToW [internal] - * duplicates an Ansi string to unicode, with a buffer size - */ -static LPWSTR FD31_DupToW(LPCSTR str, DWORD size) -{ - LPWSTR strW = NULL; - if (str && (size > 0)) - { - strW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); - if (strW) MultiByteToWideChar( CP_ACP, 0, str, -1, strW, size ); - } - return strW; -} - -/************************************************************************ - * FD31_MapOfnStructA [internal] - * map a 32 bits Ansi structure to an Unicode one - */ -void FD31_MapOfnStructA(const LPOPENFILENAMEA ofnA, LPOPENFILENAMEW ofnW, BOOL open) -{ - UNICODE_STRING usBuffer; - - ofnW->lStructSize = sizeof(OPENFILENAMEW); - ofnW->hwndOwner = ofnA->hwndOwner; - ofnW->hInstance = ofnA->hInstance; - if (ofnA->lpstrFilter) - ofnW->lpstrFilter = FD31_MapStringPairsToW(ofnA->lpstrFilter, 0); - - if ((ofnA->lpstrCustomFilter) && (*(ofnA->lpstrCustomFilter))) - ofnW->lpstrCustomFilter = FD31_MapStringPairsToW(ofnA->lpstrCustomFilter, ofnA->nMaxCustFilter); - ofnW->nMaxCustFilter = ofnA->nMaxCustFilter; - ofnW->nFilterIndex = ofnA->nFilterIndex; - ofnW->nMaxFile = ofnA->nMaxFile; - ofnW->lpstrFile = FD31_DupToW(ofnA->lpstrFile, ofnW->nMaxFile); - ofnW->nMaxFileTitle = ofnA->nMaxFileTitle; - ofnW->lpstrFileTitle = FD31_DupToW(ofnA->lpstrFileTitle, ofnW->nMaxFileTitle); - if (ofnA->lpstrInitialDir) - { - RtlCreateUnicodeStringFromAsciiz (&usBuffer,ofnA->lpstrInitialDir); - ofnW->lpstrInitialDir = usBuffer.Buffer; - } - if (ofnA->lpstrTitle) { - RtlCreateUnicodeStringFromAsciiz (&usBuffer, ofnA->lpstrTitle); - ofnW->lpstrTitle = usBuffer.Buffer; - } else { - WCHAR buf[16]; - int len; - LoadStringW(COMDLG32_hInstance, open ? IDS_OPEN_FILE : IDS_SAVE_AS, - buf, sizeof(buf)/sizeof(WCHAR)); - len = lstrlenW(buf)+1; - ofnW->lpstrTitle = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - memcpy((void*)ofnW->lpstrTitle, buf, len*sizeof(WCHAR)); - } - ofnW->Flags = ofnA->Flags; - ofnW->nFileOffset = ofnA->nFileOffset; - ofnW->nFileExtension = ofnA->nFileExtension; - ofnW->lpstrDefExt = FD31_DupToW(ofnA->lpstrDefExt, 3); - if ((ofnA->Flags & OFN_ENABLETEMPLATE) && (ofnA->lpTemplateName)) - { - if (HIWORD(ofnA->lpTemplateName)) - { - RtlCreateUnicodeStringFromAsciiz (&usBuffer,ofnA->lpTemplateName); - ofnW->lpTemplateName = usBuffer.Buffer; - } - else /* numbered resource */ - ofnW->lpTemplateName = (LPWSTR) ofnA->lpTemplateName; - } -} - - -/************************************************************************ - * FD31_FreeOfnW [internal] - * Undo all allocations done by FD31_MapOfnStructA - */ -void FD31_FreeOfnW(LPOPENFILENAMEW ofnW) -{ - HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpstrFilter); - HeapFree(GetProcessHeap(), 0, ofnW->lpstrCustomFilter); - HeapFree(GetProcessHeap(), 0, ofnW->lpstrFile); - HeapFree(GetProcessHeap(), 0, ofnW->lpstrFileTitle); - HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpstrInitialDir); - HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpstrTitle); - if ((ofnW->lpTemplateName) && (HIWORD(ofnW->lpTemplateName))) - HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpTemplateName); -} - -/************************************************************************ - * FD31_DestroyPrivate [internal] - * destroys the private object - */ -void FD31_DestroyPrivate(PFD31_DATA lfs) -{ - HWND hwnd; - if (!lfs) return; - hwnd = lfs->hwnd; - TRACE("destroying private allocation %p\n", lfs); - lfs->callbacks->Destroy(lfs); - HeapFree(GetProcessHeap(), 0, lfs); - RemovePropA(hwnd, FD31_OFN_PROP); -} - -/************************************************************************ - * FD31_AllocPrivate [internal] - * allocate a private object to hold 32 bits Unicode - * structure that will be used throughtout the calls, while - * keeping available the original structures and a few variables - * On entry : type = dialog procedure type (16,32A,32W) - * dlgType = dialog type (open or save) - */ -PFD31_DATA FD31_AllocPrivate(LPARAM lParam, UINT dlgType, - PFD31_CALLBACKS callbacks, DWORD data) -{ - PFD31_DATA lfs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD31_DATA)); - - TRACE("alloc private buf %p\n", lfs); - if (!lfs) return NULL; - lfs->hook = FALSE; - lfs->lParam = lParam; - lfs->open = (dlgType == OPEN_DIALOG); - lfs->callbacks = callbacks; - if (! lfs->callbacks->Init(lParam, lfs, data)) - { - FD31_DestroyPrivate(lfs); - return NULL; - } - lfs->lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA); - lfs->fileokstring = RegisterWindowMessageA(FILEOKSTRINGA); - - return lfs; -} - -/*********************************************************************** - * FD31_WMInitDialog [internal] - */ - -LONG FD31_WMInitDialog(HWND hWnd, WPARAM wParam, LPARAM lParam) -{ - int i, n; - WCHAR tmpstr[BUFFILE]; - LPWSTR pstr, old_pstr; - LPOPENFILENAMEW ofn; - PFD31_DATA lfs = (PFD31_DATA) lParam; - - if (!lfs) return FALSE; - SetPropA(hWnd, FD31_OFN_PROP, (HANDLE)lfs); - lfs->hwnd = hWnd; - ofn = lfs->ofnW; - - TRACE("flags=%lx initialdir=%s\n", ofn->Flags, debugstr_w(ofn->lpstrInitialDir)); - - SetWindowTextW( hWnd, ofn->lpstrTitle ); - /* read custom filter information */ - if (ofn->lpstrCustomFilter) - { - pstr = ofn->lpstrCustomFilter; - n = 0; - TRACE("lpstrCustomFilter = %p\n", pstr); - while(*pstr) - { - old_pstr = pstr; - i = SendDlgItemMessageW(hWnd, cmb1, CB_ADDSTRING, 0, - (LPARAM)(ofn->lpstrCustomFilter) + n ); - n += lstrlenW(pstr) + 1; - pstr += lstrlenW(pstr) + 1; - TRACE("add str=%s associated to %s\n", - debugstr_w(old_pstr), debugstr_w(pstr)); - SendDlgItemMessageW(hWnd, cmb1, CB_SETITEMDATA, i, (LPARAM)pstr); - n += lstrlenW(pstr) + 1; - pstr += lstrlenW(pstr) + 1; - } - } - /* read filter information */ - if (ofn->lpstrFilter) { - pstr = (LPWSTR) ofn->lpstrFilter; - n = 0; - while(*pstr) { - old_pstr = pstr; - i = SendDlgItemMessageW(hWnd, cmb1, CB_ADDSTRING, 0, - (LPARAM)(ofn->lpstrFilter + n) ); - n += lstrlenW(pstr) + 1; - pstr += lstrlenW(pstr) + 1; - TRACE("add str=%s associated to %s\n", - debugstr_w(old_pstr), debugstr_w(pstr)); - SendDlgItemMessageW(hWnd, cmb1, CB_SETITEMDATA, i, (LPARAM)pstr); - n += lstrlenW(pstr) + 1; - pstr += lstrlenW(pstr) + 1; - } - } - /* set default filter */ - if (ofn->nFilterIndex == 0 && ofn->lpstrCustomFilter == NULL) - ofn->nFilterIndex = 1; - SendDlgItemMessageW(hWnd, cmb1, CB_SETCURSEL, ofn->nFilterIndex - 1, 0); - lstrcpynW(tmpstr, FD31_GetFileType(ofn->lpstrCustomFilter, - (LPWSTR)ofn->lpstrFilter, ofn->nFilterIndex - 1),BUFFILE); - TRACE("nFilterIndex = %ld, SetText of edt1 to %s\n", - ofn->nFilterIndex, debugstr_w(tmpstr)); - SetDlgItemTextW( hWnd, edt1, tmpstr ); - /* get drive list */ - *tmpstr = 0; - DlgDirListComboBoxW(hWnd, tmpstr, cmb2, 0, DDL_DRIVES | DDL_EXCLUSIVE); - /* read initial directory */ - /* FIXME: Note that this is now very version-specific (See MSDN description of - * the OPENFILENAME structure). For example under 2000/XP any path in the - * lpstrFile overrides the lpstrInitialDir, but not under 95/98/ME - */ - if (ofn->lpstrInitialDir != NULL) - { - int len; - lstrcpynW(tmpstr, ofn->lpstrInitialDir, 511); - len = lstrlenW(tmpstr); - if (len > 0 && tmpstr[len-1] != '\\' && tmpstr[len-1] != ':') { - tmpstr[len]='\\'; - tmpstr[len+1]='\0'; - } - } - else - *tmpstr = 0; - if (!FD31_ScanDir(hWnd, tmpstr)) { - *tmpstr = 0; - if (!FD31_ScanDir(hWnd, tmpstr)) - WARN("Couldn't read initial directory %s!\n", debugstr_w(tmpstr)); - } - /* select current drive in combo 2, omit missing drives */ - { - char dir[MAX_PATH]; - char str[4] = "a:\\"; - GetCurrentDirectoryA( sizeof(dir), dir ); - for(i = 0, n = -1; i < 26; i++) - { - str[0] = 'a' + i; - if (GetDriveTypeA(str) > DRIVE_NO_ROOT_DIR) n++; - if (toupper(str[0]) == toupper(dir[0])) break; - } - } - SendDlgItemMessageW(hWnd, cmb2, CB_SETCURSEL, n, 0); - if (!(ofn->Flags & OFN_SHOWHELP)) - ShowWindow(GetDlgItem(hWnd, pshHelp), SW_HIDE); - if (ofn->Flags & OFN_HIDEREADONLY) - ShowWindow(GetDlgItem(hWnd, chx1), SW_HIDE); - if (lfs->hook) - return (BOOL) FD31_CallWindowProc(lfs, WM_INITDIALOG, wParam, lfs->lParam); - return TRUE; -} - -int FD31_GetFldrHeight(void) -{ - return fldrHeight; -} +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "wingdi.h" +#include "winuser.h" +#include "wine/unicode.h" +#include "wine/debug.h" +#include "cderr.h" +#include "winreg.h" +#include "winternl.h" +#include "winuser.h" +#include "commdlg.h" +#include "cderr.h" +#include "winreg.h" +#include "winternl.h" +#include "shlwapi.h" + +WINE_DEFAULT_DEBUG_CHANNEL(commdlg); + +#include "cdlg.h" +#include "filedlg31.h" + +#define BUFFILE 512 +#define BUFFILEALLOC 512 * sizeof(WCHAR) + +static const WCHAR FILE_star[] = {'*','.','*', 0}; +static const WCHAR FILE_bslash[] = {'\\', 0}; +static const WCHAR FILE_specc[] = {'%','c',':', 0}; +static const int fldrHeight = 16; +static const int fldrWidth = 20; + +static HICON hFolder = 0; +static HICON hFolder2 = 0; +static HICON hFloppy = 0; +static HICON hHDisk = 0; +static HICON hCDRom = 0; +static HICON hNet = 0; + +/*********************************************************************** + * FD31_Init [internal] + */ +BOOL FD31_Init(void) +{ + static BOOL initialized = 0; + + if (!initialized) { + hFolder = LoadImageA( COMDLG32_hInstance, "FOLDER", IMAGE_ICON, 16, 16, LR_SHARED ); + hFolder2 = LoadImageA( COMDLG32_hInstance, "FOLDER2", IMAGE_ICON, 16, 16, LR_SHARED ); + hFloppy = LoadImageA( COMDLG32_hInstance, "FLOPPY", IMAGE_ICON, 16, 16, LR_SHARED ); + hHDisk = LoadImageA( COMDLG32_hInstance, "HDISK", IMAGE_ICON, 16, 16, LR_SHARED ); + hCDRom = LoadImageA( COMDLG32_hInstance, "CDROM", IMAGE_ICON, 16, 16, LR_SHARED ); + hNet = LoadImageA( COMDLG32_hInstance, "NETWORK", IMAGE_ICON, 16, 16, LR_SHARED ); + if (hFolder == 0 || hFolder2 == 0 || hFloppy == 0 || + hHDisk == 0 || hCDRom == 0 || hNet == 0) + { + ERR("Error loading icons !\n"); + return FALSE; + } + initialized = TRUE; + } + return TRUE; +} + +/*********************************************************************** + * FD31_StripEditControl [internal] + * Strip pathnames off the contents of the edit control. + */ +static void FD31_StripEditControl(HWND hwnd) +{ + WCHAR temp[BUFFILE], *cp; + + GetDlgItemTextW( hwnd, edt1, temp, sizeof(temp)/sizeof(WCHAR)); + cp = strrchrW(temp, '\\'); + if (cp != NULL) { + strcpyW(temp, cp+1); + } + cp = strrchrW(temp, ':'); + if (cp != NULL) { + strcpyW(temp, cp+1); + } + /* FIXME: shouldn't we do something with the result here? ;-) */ +} + +/*********************************************************************** + * FD31_CallWindowProc [internal] + * + * Call the appropriate hook + */ +BOOL FD31_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam, + LPARAM lParam) +{ + return lfs->callbacks->CWP(lfs, wMsg, wParam, lParam); +} + +/*********************************************************************** + * FD31_ScanDir [internal] + */ +static BOOL FD31_ScanDir(HWND hWnd, LPWSTR newPath) +{ + WCHAR buffer[BUFFILE]; + HWND hdlg, hdlgDir; + LRESULT lRet = TRUE; + HCURSOR hCursorWait, oldCursor; + + TRACE("Trying to change to %s\n", debugstr_w(newPath)); + if ( newPath[0] && !SetCurrentDirectoryW( newPath )) + return FALSE; + lstrcpynW(buffer, newPath, sizeof(buffer)/sizeof(WCHAR)); + + /* get the list of spec files */ + GetDlgItemTextW(hWnd, edt1, buffer, sizeof(buffer)/sizeof(WCHAR)); + + hCursorWait = LoadCursorA(0, (LPSTR)IDC_WAIT); + oldCursor = SetCursor(hCursorWait); + + /* list of files */ + if ((hdlg = GetDlgItem(hWnd, lst1)) != 0) { + WCHAR* scptr; /* ptr on semi-colon */ + WCHAR* filter = buffer; + + TRACE("Using filter %s\n", debugstr_w(filter)); + SendMessageW(hdlg, LB_RESETCONTENT, 0, 0); + while (filter) { + scptr = strchrW(filter, ';'); + if (scptr) *scptr = 0; + while (*filter == ' ') filter++; + TRACE("Using file spec %s\n", debugstr_w(filter)); + if (SendMessageW(hdlg, LB_DIR, 0, (LPARAM)filter) == LB_ERR) + return FALSE; + if (scptr) *scptr = ';'; + filter = (scptr) ? (scptr + 1) : 0; + } + } + + /* list of directories */ + strcpyW(buffer, FILE_star); + + if ((hdlgDir = GetDlgItem(hWnd, lst2)) != 0) { + lRet = DlgDirListW(hWnd, buffer, lst2, stc1, DDL_EXCLUSIVE | DDL_DIRECTORY); + } + SetCursor(oldCursor); + return lRet; +} + +/*********************************************************************** + * FD31_GetFileType [internal] + */ + +static LPWSTR FD31_GetFileType(LPWSTR cfptr, LPWSTR fptr, WORD index) +{ + int n, i; + i = 0; + if (cfptr) + for ( ;(n = lstrlenW(cfptr)) != 0; i++) + { + cfptr += n + 1; + if (i == index) + return cfptr; + cfptr += lstrlenW(cfptr) + 1; + } + if (fptr) + for ( ;(n = lstrlenW(fptr)) != 0; i++) + { + fptr += n + 1; + if (i == index) + return fptr; + fptr += lstrlenW(fptr) + 1; + } + return (LPWSTR) FILE_star; /* FIXME */ +} + +/*********************************************************************** + * FD31_WMDrawItem [internal] + */ +LONG FD31_WMDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam, + int savedlg, LPDRAWITEMSTRUCT lpdis) +{ + WCHAR *str; + HICON hIcon; + COLORREF oldText = 0, oldBk = 0; + + if (lpdis->CtlType == ODT_LISTBOX && lpdis->CtlID == lst1) + { + if (!(str = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC))) return FALSE; + SendMessageW(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID, + (LPARAM)str); + + if ((lpdis->itemState & ODS_SELECTED) && !savedlg) + { + oldBk = SetBkColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) ); + oldText = SetTextColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); + } + if (savedlg) + SetTextColor(lpdis->hDC,GetSysColor(COLOR_GRAYTEXT) ); + + ExtTextOutW(lpdis->hDC, lpdis->rcItem.left + 1, + lpdis->rcItem.top + 1, ETO_OPAQUE | ETO_CLIPPED, + &(lpdis->rcItem), str, lstrlenW(str), NULL); + + if (lpdis->itemState & ODS_SELECTED) + DrawFocusRect( lpdis->hDC, &(lpdis->rcItem) ); + + if ((lpdis->itemState & ODS_SELECTED) && !savedlg) + { + SetBkColor( lpdis->hDC, oldBk ); + SetTextColor( lpdis->hDC, oldText ); + } + HeapFree(GetProcessHeap(), 0, str); + return TRUE; + } + + if (lpdis->CtlType == ODT_LISTBOX && lpdis->CtlID == lst2) + { + if (!(str = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC))) + return FALSE; + SendMessageW(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID, + (LPARAM)str); + + if (lpdis->itemState & ODS_SELECTED) + { + oldBk = SetBkColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) ); + oldText = SetTextColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); + } + ExtTextOutW(lpdis->hDC, lpdis->rcItem.left + fldrWidth, + lpdis->rcItem.top + 1, ETO_OPAQUE | ETO_CLIPPED, + &(lpdis->rcItem), str, lstrlenW(str), NULL); + + if (lpdis->itemState & ODS_SELECTED) + DrawFocusRect( lpdis->hDC, &(lpdis->rcItem) ); + + if (lpdis->itemState & ODS_SELECTED) + { + SetBkColor( lpdis->hDC, oldBk ); + SetTextColor( lpdis->hDC, oldText ); + } + DrawIcon(lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, hFolder); + HeapFree(GetProcessHeap(), 0, str); + return TRUE; + } + if (lpdis->CtlType == ODT_COMBOBOX && lpdis->CtlID == cmb2) + { + char root[] = "a:"; + if (!(str = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC))) + return FALSE; + SendMessageW(lpdis->hwndItem, CB_GETLBTEXT, lpdis->itemID, + (LPARAM)str); + root[0] += str[2] - 'a'; + switch(GetDriveTypeA(root)) + { + case DRIVE_REMOVABLE: hIcon = hFloppy; break; + case DRIVE_CDROM: hIcon = hCDRom; break; + case DRIVE_REMOTE: hIcon = hNet; break; + case DRIVE_FIXED: + default: hIcon = hHDisk; break; + } + if (lpdis->itemState & ODS_SELECTED) + { + oldBk = SetBkColor( lpdis->hDC, GetSysColor( COLOR_HIGHLIGHT ) ); + oldText = SetTextColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); + } + ExtTextOutW(lpdis->hDC, lpdis->rcItem.left + fldrWidth, + lpdis->rcItem.top + 1, ETO_OPAQUE | ETO_CLIPPED, + &(lpdis->rcItem), str, lstrlenW(str), NULL); + + if (lpdis->itemState & ODS_SELECTED) + { + SetBkColor( lpdis->hDC, oldBk ); + SetTextColor( lpdis->hDC, oldText ); + } + DrawIcon(lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, hIcon); + HeapFree(GetProcessHeap(), 0, str); + return TRUE; + } + return FALSE; +} + +/*********************************************************************** + * FD31_UpdateResult [internal] + * update the displayed file name (with path) + */ +void FD31_UpdateResult(PFD31_DATA lfs, WCHAR *tmpstr) +{ + int lenstr2; + LPOPENFILENAMEW ofnW = lfs->ofnW; + WCHAR tmpstr2[BUFFILE]; + WCHAR *p; + + TRACE("%s\n", debugstr_w(tmpstr)); + if(ofnW->Flags & OFN_NOVALIDATE) + tmpstr2[0] = '\0'; + else + GetCurrentDirectoryW(BUFFILE, tmpstr2); + lenstr2 = strlenW(tmpstr2); + if (lenstr2 > 3) + tmpstr2[lenstr2++]='\\'; + lstrcpynW(tmpstr2+lenstr2, tmpstr, BUFFILE-lenstr2); + if (ofnW->lpstrFile) + lstrcpynW(ofnW->lpstrFile, tmpstr2, ofnW->nMaxFile); + + /* set filename offset */ + p = PathFindFileNameW(ofnW->lpstrFile); + ofnW->nFileOffset = (p - ofnW->lpstrFile); + + /* set extension offset */ + p = PathFindExtensionW(ofnW->lpstrFile); + ofnW->nFileExtension = (*p) ? (p - ofnW->lpstrFile) + 1 : 0; + + TRACE("file %s, file offset %d, ext offset %d\n", + debugstr_w(ofnW->lpstrFile), ofnW->nFileOffset, ofnW->nFileExtension); + + /* update the real client structures if any */ + lfs->callbacks->UpdateResult(lfs); +} + +/*********************************************************************** + * FD31_UpdateFileTitle [internal] + * update the displayed file name (without path) + */ +void FD31_UpdateFileTitle(PFD31_DATA lfs) +{ + LONG lRet; + LPOPENFILENAMEW ofnW = lfs->ofnW; + if (ofnW->lpstrFileTitle != NULL) + { + lRet = SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETCURSEL, 0, 0); + SendDlgItemMessageW(lfs->hwnd, lst1, LB_GETTEXT, lRet, + (LPARAM)ofnW->lpstrFileTitle ); + lfs->callbacks->UpdateFileTitle(lfs); + } +} + +/*********************************************************************** + * FD31_DirListDblClick [internal] + */ +static LRESULT FD31_DirListDblClick( PFD31_DATA lfs ) +{ + LONG lRet; + HWND hWnd = lfs->hwnd; + LPWSTR pstr; + WCHAR tmpstr[BUFFILE]; + + /* get the raw string (with brackets) */ + lRet = SendDlgItemMessageW(hWnd, lst2, LB_GETCURSEL, 0, 0); + if (lRet == LB_ERR) return TRUE; + pstr = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC); + SendDlgItemMessageW(hWnd, lst2, LB_GETTEXT, lRet, + (LPARAM)pstr); + strcpyW( tmpstr, pstr ); + HeapFree(GetProcessHeap(), 0, pstr); + /* get the selected directory in tmpstr */ + if (tmpstr[0] == '[') + { + tmpstr[lstrlenW(tmpstr) - 1] = 0; + strcpyW(tmpstr,tmpstr+1); + } + strcatW(tmpstr, FILE_bslash); + + FD31_ScanDir(hWnd, tmpstr); + /* notify the app */ + if (lfs->hook) + { + if (FD31_CallWindowProc(lfs, lfs->lbselchstring, lst2, + MAKELONG(lRet,CD_LBSELCHANGE))) + return TRUE; + } + return TRUE; +} + +/*********************************************************************** + * FD31_FileListSelect [internal] + * called when a new item is picked in the file list + */ +static LRESULT FD31_FileListSelect( PFD31_DATA lfs ) +{ + LONG lRet; + HWND hWnd = lfs->hwnd; + LPWSTR pstr; + + lRet = lfs->callbacks->SendLbGetCurSel(lfs); + if (lRet == LB_ERR) + return TRUE; + + /* set the edit control to the choosen file */ + if ((pstr = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC))) + { + SendDlgItemMessageW(hWnd, lst1, LB_GETTEXT, lRet, + (LPARAM)pstr); + SetDlgItemTextW( hWnd, edt1, pstr ); + HeapFree(GetProcessHeap(), 0, pstr); + } + if (lfs->hook) + { + FD31_CallWindowProc(lfs, lfs->lbselchstring, lst1, + MAKELONG(lRet,CD_LBSELCHANGE)); + } + /* FIXME: for OFN_ALLOWMULTISELECT we need CD_LBSELSUB, CD_SELADD, + CD_LBSELNOITEMS */ + return TRUE; +} + +/*********************************************************************** + * FD31_TestPath [internal] + * before accepting the file name, test if it includes wild cards + * tries to scan the directory and returns TRUE if no error. + */ +static LRESULT FD31_TestPath( PFD31_DATA lfs, LPWSTR path ) +{ + HWND hWnd = lfs->hwnd; + LPWSTR pBeginFileName, pstr2; + WCHAR tmpstr2[BUFFILE]; + + pBeginFileName = strrchrW(path, '\\'); + if (pBeginFileName == NULL) + pBeginFileName = strrchrW(path, ':'); + + if (strchrW(path,'*') != NULL || strchrW(path,'?') != NULL) + { + /* edit control contains wildcards */ + if (pBeginFileName != NULL) + { + lstrcpynW(tmpstr2, pBeginFileName + 1, BUFFILE); + *(pBeginFileName + 1) = 0; + } + else + { + strcpyW(tmpstr2, path); + if(!(lfs->ofnW->Flags & OFN_NOVALIDATE)) + *path = 0; + } + + TRACE("path=%s, tmpstr2=%s\n", debugstr_w(path), debugstr_w(tmpstr2)); + SetDlgItemTextW( hWnd, edt1, tmpstr2 ); + FD31_ScanDir(hWnd, path); + return (lfs->ofnW->Flags & OFN_NOVALIDATE) ? TRUE : FALSE; + } + + /* no wildcards, we might have a directory or a filename */ + /* try appending a wildcard and reading the directory */ + + pstr2 = path + lstrlenW(path); + if (pBeginFileName == NULL || *(pBeginFileName + 1) != 0) + strcatW(path, FILE_bslash); + + /* if ScanDir succeeds, we have changed the directory */ + if (FD31_ScanDir(hWnd, path)) + return FALSE; /* and path is not a valid file name */ + + /* if not, this must be a filename */ + + *pstr2 = 0; /* remove the wildcard added before */ + + if (pBeginFileName != NULL) + { + /* strip off the pathname */ + *pBeginFileName = 0; + SetDlgItemTextW( hWnd, edt1, pBeginFileName + 1 ); + + lstrcpynW(tmpstr2, pBeginFileName + 1, sizeof(tmpstr2)/sizeof(WCHAR) ); + /* Should we MessageBox() if this fails? */ + if (!FD31_ScanDir(hWnd, path)) + { + return FALSE; + } + strcpyW(path, tmpstr2); + } + else + SetDlgItemTextW( hWnd, edt1, path ); + return TRUE; +} + +/*********************************************************************** + * FD31_Validate [internal] + * called on: click Ok button, Enter in edit, DoubleClick in file list + */ +static LRESULT FD31_Validate( PFD31_DATA lfs, LPWSTR path, UINT control, INT itemIndex, + BOOL internalUse ) +{ + LONG lRet; + HWND hWnd = lfs->hwnd; + OPENFILENAMEW ofnsav; + LPOPENFILENAMEW ofnW = lfs->ofnW; + WCHAR filename[BUFFILE]; + + ofnsav = *ofnW; /* for later restoring */ + + /* get current file name */ + if (path) + lstrcpynW(filename, path, sizeof(filename)/sizeof(WCHAR)); + else + GetDlgItemTextW( hWnd, edt1, filename, sizeof(filename)/sizeof(WCHAR)); + + TRACE("got filename = %s\n", debugstr_w(filename)); + /* if we did not click in file list to get there */ + if (control != lst1) + { + if (!FD31_TestPath( lfs, filename) ) + return FALSE; + } + FD31_UpdateResult(lfs, filename); + + if (internalUse) + { /* called internally after a change in a combo */ + if (lfs->hook) + { + FD31_CallWindowProc(lfs, lfs->lbselchstring, control, + MAKELONG(itemIndex,CD_LBSELCHANGE)); + } + return TRUE; + } + + FD31_UpdateFileTitle(lfs); + if (lfs->hook) + { + lRet = (BOOL)FD31_CallWindowProc(lfs, lfs->fileokstring, + 0, lfs->lParam ); + if (lRet) + { + *ofnW = ofnsav; /* restore old state */ + return FALSE; + } + } + if ((ofnW->Flags & OFN_ALLOWMULTISELECT) && (ofnW->Flags & OFN_EXPLORER)) + { + if (ofnW->lpstrFile) + { + LPWSTR str = (LPWSTR)ofnW->lpstrFile; + LPWSTR ptr = strrchrW(str, '\\'); + str[lstrlenW(str) + 1] = '\0'; + *ptr = 0; + } + } + return TRUE; +} + +/*********************************************************************** + * FD31_DiskChange [internal] + * called when a new item is picked in the disk selection combo + */ +static LRESULT FD31_DiskChange( PFD31_DATA lfs ) +{ + LONG lRet; + HWND hWnd = lfs->hwnd; + LPWSTR pstr; + WCHAR diskname[BUFFILE]; + + FD31_StripEditControl(hWnd); + lRet = SendDlgItemMessageW(hWnd, cmb2, CB_GETCURSEL, 0, 0L); + if (lRet == LB_ERR) + return 0; + pstr = HeapAlloc(GetProcessHeap(), 0, BUFFILEALLOC); + SendDlgItemMessageW(hWnd, cmb2, CB_GETLBTEXT, lRet, + (LPARAM)pstr); + wsprintfW(diskname, FILE_specc, pstr[2]); + HeapFree(GetProcessHeap(), 0, pstr); + + return FD31_Validate( lfs, diskname, cmb2, lRet, TRUE ); +} + +/*********************************************************************** + * FD31_FileTypeChange [internal] + * called when a new item is picked in the file type combo + */ +static LRESULT FD31_FileTypeChange( PFD31_DATA lfs ) +{ + LONG lRet; + LPWSTR pstr; + + lRet = SendDlgItemMessageW(lfs->hwnd, cmb1, CB_GETCURSEL, 0, 0); + if (lRet == LB_ERR) + return TRUE; + pstr = (LPWSTR)SendDlgItemMessageW(lfs->hwnd, cmb1, CB_GETITEMDATA, lRet, 0); + TRACE("Selected filter : %s\n", debugstr_w(pstr)); + SetDlgItemTextW( lfs->hwnd, edt1, pstr ); + + return FD31_Validate( lfs, NULL, cmb1, lRet, TRUE ); +} + +/*********************************************************************** + * FD31_WMCommand [internal] + */ +LRESULT FD31_WMCommand(HWND hWnd, LPARAM lParam, UINT notification, + UINT control, PFD31_DATA lfs ) +{ + switch (control) + { + case lst1: /* file list */ + FD31_StripEditControl(hWnd); + if (notification == LBN_DBLCLK) + { + return SendMessageW(hWnd, WM_COMMAND, IDOK, 0); + } + else if (notification == LBN_SELCHANGE) + return FD31_FileListSelect( lfs ); + break; + + case lst2: /* directory list */ + FD31_StripEditControl(hWnd); + if (notification == LBN_DBLCLK) + return FD31_DirListDblClick( lfs ); + break; + + case cmb1: /* file type drop list */ + if (notification == CBN_SELCHANGE) + return FD31_FileTypeChange( lfs ); + break; + + case chx1: + break; + + case pshHelp: + break; + + case cmb2: /* disk dropdown combo */ + if (notification == CBN_SELCHANGE) + return FD31_DiskChange( lfs ); + break; + + case IDOK: + TRACE("OK pressed\n"); + if (FD31_Validate( lfs, NULL, control, 0, FALSE )) + EndDialog(hWnd, TRUE); + return TRUE; + + case IDCANCEL: + EndDialog(hWnd, FALSE); + return TRUE; + + case IDABORT: /* can be sent by the hook procedure */ + EndDialog(hWnd, TRUE); + return TRUE; + } + return FALSE; +} + +/************************************************************************ + * FD31_MapStringPairsToW [internal] + * map string pairs to Unicode + */ +static LPWSTR FD31_MapStringPairsToW(LPCSTR strA, UINT size) +{ + LPCSTR s; + LPWSTR x; + unsigned int n, len; + + s = strA; + while (*s) + s = s+strlen(s)+1; + s++; + n = s + 1 - strA; /* Don't forget the other \0 */ + if (n < size) n = size; + + len = MultiByteToWideChar( CP_ACP, 0, strA, n, NULL, 0 ); + x = HeapAlloc(GetProcessHeap(),0, len * sizeof(WCHAR)); + MultiByteToWideChar( CP_ACP, 0, strA, n, x, len ); + return x; +} + + +/************************************************************************ + * FD31_DupToW [internal] + * duplicates an Ansi string to unicode, with a buffer size + */ +static LPWSTR FD31_DupToW(LPCSTR str, DWORD size) +{ + LPWSTR strW = NULL; + if (str && (size > 0)) + { + strW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); + if (strW) MultiByteToWideChar( CP_ACP, 0, str, -1, strW, size ); + } + return strW; +} + +/************************************************************************ + * FD31_MapOfnStructA [internal] + * map a 32 bits Ansi structure to an Unicode one + */ +void FD31_MapOfnStructA(const LPOPENFILENAMEA ofnA, LPOPENFILENAMEW ofnW, BOOL open) +{ + UNICODE_STRING usBuffer; + + ofnW->lStructSize = sizeof(OPENFILENAMEW); + ofnW->hwndOwner = ofnA->hwndOwner; + ofnW->hInstance = ofnA->hInstance; + if (ofnA->lpstrFilter) + ofnW->lpstrFilter = FD31_MapStringPairsToW(ofnA->lpstrFilter, 0); + + if ((ofnA->lpstrCustomFilter) && (*(ofnA->lpstrCustomFilter))) + ofnW->lpstrCustomFilter = FD31_MapStringPairsToW(ofnA->lpstrCustomFilter, ofnA->nMaxCustFilter); + ofnW->nMaxCustFilter = ofnA->nMaxCustFilter; + ofnW->nFilterIndex = ofnA->nFilterIndex; + ofnW->nMaxFile = ofnA->nMaxFile; + ofnW->lpstrFile = FD31_DupToW(ofnA->lpstrFile, ofnW->nMaxFile); + ofnW->nMaxFileTitle = ofnA->nMaxFileTitle; + ofnW->lpstrFileTitle = FD31_DupToW(ofnA->lpstrFileTitle, ofnW->nMaxFileTitle); + if (ofnA->lpstrInitialDir) + { + RtlCreateUnicodeStringFromAsciiz (&usBuffer,ofnA->lpstrInitialDir); + ofnW->lpstrInitialDir = usBuffer.Buffer; + } + if (ofnA->lpstrTitle) { + RtlCreateUnicodeStringFromAsciiz (&usBuffer, ofnA->lpstrTitle); + ofnW->lpstrTitle = usBuffer.Buffer; + } else { + WCHAR buf[16]; + int len; + LoadStringW(COMDLG32_hInstance, open ? IDS_OPEN_FILE : IDS_SAVE_AS, + buf, sizeof(buf)/sizeof(WCHAR)); + len = lstrlenW(buf)+1; + ofnW->lpstrTitle = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); + memcpy((void*)ofnW->lpstrTitle, buf, len*sizeof(WCHAR)); + } + ofnW->Flags = ofnA->Flags; + ofnW->nFileOffset = ofnA->nFileOffset; + ofnW->nFileExtension = ofnA->nFileExtension; + ofnW->lpstrDefExt = FD31_DupToW(ofnA->lpstrDefExt, 3); + if ((ofnA->Flags & OFN_ENABLETEMPLATE) && (ofnA->lpTemplateName)) + { + if (HIWORD(ofnA->lpTemplateName)) + { + RtlCreateUnicodeStringFromAsciiz (&usBuffer,ofnA->lpTemplateName); + ofnW->lpTemplateName = usBuffer.Buffer; + } + else /* numbered resource */ + ofnW->lpTemplateName = (LPWSTR) ofnA->lpTemplateName; + } +} + + +/************************************************************************ + * FD31_FreeOfnW [internal] + * Undo all allocations done by FD31_MapOfnStructA + */ +void FD31_FreeOfnW(LPOPENFILENAMEW ofnW) +{ + HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpstrFilter); + HeapFree(GetProcessHeap(), 0, ofnW->lpstrCustomFilter); + HeapFree(GetProcessHeap(), 0, ofnW->lpstrFile); + HeapFree(GetProcessHeap(), 0, ofnW->lpstrFileTitle); + HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpstrInitialDir); + HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpstrTitle); + if ((ofnW->lpTemplateName) && (HIWORD(ofnW->lpTemplateName))) + HeapFree(GetProcessHeap(), 0, (LPWSTR) ofnW->lpTemplateName); +} + +/************************************************************************ + * FD31_DestroyPrivate [internal] + * destroys the private object + */ +void FD31_DestroyPrivate(PFD31_DATA lfs) +{ + HWND hwnd; + if (!lfs) return; + hwnd = lfs->hwnd; + TRACE("destroying private allocation %p\n", lfs); + lfs->callbacks->Destroy(lfs); + HeapFree(GetProcessHeap(), 0, lfs); + RemovePropA(hwnd, FD31_OFN_PROP); +} + +/************************************************************************ + * FD31_AllocPrivate [internal] + * allocate a private object to hold 32 bits Unicode + * structure that will be used throughtout the calls, while + * keeping available the original structures and a few variables + * On entry : type = dialog procedure type (16,32A,32W) + * dlgType = dialog type (open or save) + */ +PFD31_DATA FD31_AllocPrivate(LPARAM lParam, UINT dlgType, + PFD31_CALLBACKS callbacks, DWORD data) +{ + PFD31_DATA lfs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FD31_DATA)); + + TRACE("alloc private buf %p\n", lfs); + if (!lfs) return NULL; + lfs->hook = FALSE; + lfs->lParam = lParam; + lfs->open = (dlgType == OPEN_DIALOG); + lfs->callbacks = callbacks; + if (! lfs->callbacks->Init(lParam, lfs, data)) + { + FD31_DestroyPrivate(lfs); + return NULL; + } + lfs->lbselchstring = RegisterWindowMessageA(LBSELCHSTRINGA); + lfs->fileokstring = RegisterWindowMessageA(FILEOKSTRINGA); + + return lfs; +} + +/*********************************************************************** + * FD31_WMInitDialog [internal] + */ + +LONG FD31_WMInitDialog(HWND hWnd, WPARAM wParam, LPARAM lParam) +{ + int i, n; + WCHAR tmpstr[BUFFILE]; + LPWSTR pstr, old_pstr; + LPOPENFILENAMEW ofn; + PFD31_DATA lfs = (PFD31_DATA) lParam; + + if (!lfs) return FALSE; + SetPropA(hWnd, FD31_OFN_PROP, (HANDLE)lfs); + lfs->hwnd = hWnd; + ofn = lfs->ofnW; + + TRACE("flags=%lx initialdir=%s\n", ofn->Flags, debugstr_w(ofn->lpstrInitialDir)); + + SetWindowTextW( hWnd, ofn->lpstrTitle ); + /* read custom filter information */ + if (ofn->lpstrCustomFilter) + { + pstr = ofn->lpstrCustomFilter; + n = 0; + TRACE("lpstrCustomFilter = %p\n", pstr); + while(*pstr) + { + old_pstr = pstr; + i = SendDlgItemMessageW(hWnd, cmb1, CB_ADDSTRING, 0, + (LPARAM)(ofn->lpstrCustomFilter) + n ); + n += lstrlenW(pstr) + 1; + pstr += lstrlenW(pstr) + 1; + TRACE("add str=%s associated to %s\n", + debugstr_w(old_pstr), debugstr_w(pstr)); + SendDlgItemMessageW(hWnd, cmb1, CB_SETITEMDATA, i, (LPARAM)pstr); + n += lstrlenW(pstr) + 1; + pstr += lstrlenW(pstr) + 1; + } + } + /* read filter information */ + if (ofn->lpstrFilter) { + pstr = (LPWSTR) ofn->lpstrFilter; + n = 0; + while(*pstr) { + old_pstr = pstr; + i = SendDlgItemMessageW(hWnd, cmb1, CB_ADDSTRING, 0, + (LPARAM)(ofn->lpstrFilter + n) ); + n += lstrlenW(pstr) + 1; + pstr += lstrlenW(pstr) + 1; + TRACE("add str=%s associated to %s\n", + debugstr_w(old_pstr), debugstr_w(pstr)); + SendDlgItemMessageW(hWnd, cmb1, CB_SETITEMDATA, i, (LPARAM)pstr); + n += lstrlenW(pstr) + 1; + pstr += lstrlenW(pstr) + 1; + } + } + /* set default filter */ + if (ofn->nFilterIndex == 0 && ofn->lpstrCustomFilter == NULL) + ofn->nFilterIndex = 1; + SendDlgItemMessageW(hWnd, cmb1, CB_SETCURSEL, ofn->nFilterIndex - 1, 0); + lstrcpynW(tmpstr, FD31_GetFileType(ofn->lpstrCustomFilter, + (LPWSTR)ofn->lpstrFilter, ofn->nFilterIndex - 1),BUFFILE); + TRACE("nFilterIndex = %ld, SetText of edt1 to %s\n", + ofn->nFilterIndex, debugstr_w(tmpstr)); + SetDlgItemTextW( hWnd, edt1, tmpstr ); + /* get drive list */ + *tmpstr = 0; + DlgDirListComboBoxW(hWnd, tmpstr, cmb2, 0, DDL_DRIVES | DDL_EXCLUSIVE); + /* read initial directory */ + /* FIXME: Note that this is now very version-specific (See MSDN description of + * the OPENFILENAME structure). For example under 2000/XP any path in the + * lpstrFile overrides the lpstrInitialDir, but not under 95/98/ME + */ + if (ofn->lpstrInitialDir != NULL) + { + int len; + lstrcpynW(tmpstr, ofn->lpstrInitialDir, 511); + len = lstrlenW(tmpstr); + if (len > 0 && tmpstr[len-1] != '\\' && tmpstr[len-1] != ':') { + tmpstr[len]='\\'; + tmpstr[len+1]='\0'; + } + } + else + *tmpstr = 0; + if (!FD31_ScanDir(hWnd, tmpstr)) { + *tmpstr = 0; + if (!FD31_ScanDir(hWnd, tmpstr)) + WARN("Couldn't read initial directory %s!\n", debugstr_w(tmpstr)); + } + /* select current drive in combo 2, omit missing drives */ + { + char dir[MAX_PATH]; + char str[4] = "a:\\"; + GetCurrentDirectoryA( sizeof(dir), dir ); + for(i = 0, n = -1; i < 26; i++) + { + str[0] = 'a' + i; + if (GetDriveTypeA(str) > DRIVE_NO_ROOT_DIR) n++; + if (toupper(str[0]) == toupper(dir[0])) break; + } + } + SendDlgItemMessageW(hWnd, cmb2, CB_SETCURSEL, n, 0); + if (!(ofn->Flags & OFN_SHOWHELP)) + ShowWindow(GetDlgItem(hWnd, pshHelp), SW_HIDE); + if (ofn->Flags & OFN_HIDEREADONLY) + ShowWindow(GetDlgItem(hWnd, chx1), SW_HIDE); + if (lfs->hook) + return (BOOL) FD31_CallWindowProc(lfs, WM_INITDIALOG, wParam, lfs->lParam); + return TRUE; +} + +int FD31_GetFldrHeight(void) +{ + return fldrHeight; +} diff --git a/reactos/lib/comdlg32/filedlg31.h b/reactos/lib/comdlg32/filedlg31.h index 2329eea7ae2..2506a7d8fc0 100644 --- a/reactos/lib/comdlg32/filedlg31.h +++ b/reactos/lib/comdlg32/filedlg31.h @@ -1,68 +1,68 @@ -/* - * Win3.1 style File Dialog interface (32 bit) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _WINE_DLL_FILEDLG31_H -#define _WINE_DLL_FILEDLG31_H - -#define FD31_OFN_PROP "FILEDLG_OFN" - -/* Forward declare */ -typedef struct tagFD31_DATA *PFD31_DATA; - -typedef struct tagFD31_CALLBACKS -{ - BOOL (CALLBACK *Init)(LPARAM lParam, PFD31_DATA lfs, DWORD data); - BOOL (CALLBACK *CWP)(PFD31_DATA lfs, UINT wMsg, WPARAM wParam, - LPARAM lParam); /* CWP instead of CallWindowProc to avoid macro expansion */ - void (CALLBACK *UpdateResult)(PFD31_DATA lfs); - void (CALLBACK *UpdateFileTitle)(PFD31_DATA lfs); - LRESULT (CALLBACK *SendLbGetCurSel)(PFD31_DATA lfs); - void (CALLBACK *Destroy)(PFD31_DATA lfs); -} FD31_CALLBACKS, *PFD31_CALLBACKS; - -typedef struct tagFD31_DATA -{ - HWND hwnd; /* file dialog window handle */ - BOOL hook; /* TRUE if the dialog is hooked */ - UINT lbselchstring; /* registered message id */ - UINT fileokstring; /* registered message id */ - LPARAM lParam; /* save original lparam */ - LPCVOID template; /* template for 32 bits resource */ - BOOL open; /* TRUE if open dialog, FALSE if save dialog */ - LPOPENFILENAMEW ofnW; /* pointer either to the original structure or - a W copy for A/16 API */ - LPVOID private1632; /* 16/32 bit caller private data */ - PFD31_CALLBACKS callbacks; /* callbacks to handle 16/32 bit differences */ -} FD31_DATA; - -extern BOOL FD31_Init(void); -extern PFD31_DATA FD31_AllocPrivate(LPARAM lParam, UINT dlgType, - PFD31_CALLBACKS callbacks, DWORD data); -extern void FD31_DestroyPrivate(PFD31_DATA lfs); -extern void FD31_MapOfnStructA(LPOPENFILENAMEA ofnA, LPOPENFILENAMEW ofnW, BOOL open); -extern void FD31_FreeOfnW(LPOPENFILENAMEW ofnW); -extern BOOL FD31_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam, - LPARAM lParam); -extern LONG FD31_WMInitDialog(HWND hWnd, WPARAM wParam, LPARAM lParam); -extern LONG FD31_WMDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam, - int savedlg, LPDRAWITEMSTRUCT lpdis); -extern LRESULT FD31_WMCommand(HWND hWnd, LPARAM lParam, UINT notification, - UINT control, PFD31_DATA lfs); -extern int FD31_GetFldrHeight(void); - -#endif /* _WINE_DLL_FILEDLG31_H */ +/* + * Win3.1 style File Dialog interface (32 bit) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _WINE_DLL_FILEDLG31_H +#define _WINE_DLL_FILEDLG31_H + +#define FD31_OFN_PROP "FILEDLG_OFN" + +/* Forward declare */ +typedef struct tagFD31_DATA *PFD31_DATA; + +typedef struct tagFD31_CALLBACKS +{ + BOOL (CALLBACK *Init)(LPARAM lParam, PFD31_DATA lfs, DWORD data); + BOOL (CALLBACK *CWP)(PFD31_DATA lfs, UINT wMsg, WPARAM wParam, + LPARAM lParam); /* CWP instead of CallWindowProc to avoid macro expansion */ + void (CALLBACK *UpdateResult)(PFD31_DATA lfs); + void (CALLBACK *UpdateFileTitle)(PFD31_DATA lfs); + LRESULT (CALLBACK *SendLbGetCurSel)(PFD31_DATA lfs); + void (CALLBACK *Destroy)(PFD31_DATA lfs); +} FD31_CALLBACKS, *PFD31_CALLBACKS; + +typedef struct tagFD31_DATA +{ + HWND hwnd; /* file dialog window handle */ + BOOL hook; /* TRUE if the dialog is hooked */ + UINT lbselchstring; /* registered message id */ + UINT fileokstring; /* registered message id */ + LPARAM lParam; /* save original lparam */ + LPCVOID template; /* template for 32 bits resource */ + BOOL open; /* TRUE if open dialog, FALSE if save dialog */ + LPOPENFILENAMEW ofnW; /* pointer either to the original structure or + a W copy for A/16 API */ + LPVOID private1632; /* 16/32 bit caller private data */ + PFD31_CALLBACKS callbacks; /* callbacks to handle 16/32 bit differences */ +} FD31_DATA; + +extern BOOL FD31_Init(void); +extern PFD31_DATA FD31_AllocPrivate(LPARAM lParam, UINT dlgType, + PFD31_CALLBACKS callbacks, DWORD data); +extern void FD31_DestroyPrivate(PFD31_DATA lfs); +extern void FD31_MapOfnStructA(LPOPENFILENAMEA ofnA, LPOPENFILENAMEW ofnW, BOOL open); +extern void FD31_FreeOfnW(LPOPENFILENAMEW ofnW); +extern BOOL FD31_CallWindowProc(PFD31_DATA lfs, UINT wMsg, WPARAM wParam, + LPARAM lParam); +extern LONG FD31_WMInitDialog(HWND hWnd, WPARAM wParam, LPARAM lParam); +extern LONG FD31_WMDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam, + int savedlg, LPDRAWITEMSTRUCT lpdis); +extern LRESULT FD31_WMCommand(HWND hWnd, LPARAM lParam, UINT notification, + UINT control, PFD31_DATA lfs); +extern int FD31_GetFldrHeight(void); + +#endif /* _WINE_DLL_FILEDLG31_H */ diff --git a/reactos/lib/comdlg32/filedlgbrowser.c b/reactos/lib/comdlg32/filedlgbrowser.c index 7b9173a03ea..0287a6fa70d 100644 --- a/reactos/lib/comdlg32/filedlgbrowser.c +++ b/reactos/lib/comdlg32/filedlgbrowser.c @@ -1,1007 +1,1007 @@ -/* - * Implementation of IShellBrowser for the File Open common dialog - * - * Copyright 1999 Francois Boisvert - * Copyright 1999, 2000 Juergen Schmied - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "wingdi.h" -#include "winuser.h" -#include "winreg.h" - -#define NO_SHLWAPI_STREAM -#include "shlwapi.h" -#include "filedlgbrowser.h" -#include "cdlg.h" -#include "shlguid.h" -#include "servprov.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(commdlg); - -typedef struct -{ - - const IShellBrowserVtbl *lpVtbl; - const ICommDlgBrowserVtbl *lpVtblCommDlgBrowser; - const IServiceProviderVtbl *lpVtblServiceProvider; - DWORD ref; /* Reference counter */ - HWND hwndOwner; /* Owner dialog of the interface */ - -} IShellBrowserImpl; - -/************************************************************************** -* vtable -*/ -static const IShellBrowserVtbl IShellBrowserImpl_Vtbl; -static const ICommDlgBrowserVtbl IShellBrowserImpl_ICommDlgBrowser_Vtbl; -static const IServiceProviderVtbl IShellBrowserImpl_IServiceProvider_Vtbl; - -/************************************************************************** -* Local Prototypes -*/ - -HRESULT IShellBrowserImpl_ICommDlgBrowser_OnSelChange(ICommDlgBrowser *iface, IShellView *ppshv); -#if 0 -LPITEMIDLIST GetSelectedPidl(IShellView *ppshv); -#endif - -/************************************************************************** -* External Prototypes -*/ -extern const char *FileOpenDlgInfosStr; - -extern IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs); -extern LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl); -extern LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPCSTR lpcstrFileName); - -extern int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl); -extern void SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode); - - -/* - * Helper functions - */ - -#define add_flag(a) if (flags & a) {strcat(str, #a );strcat(str," ");} -static void COMDLG32_DumpSBSPFlags(UINT uflags) -{ - if (TRACE_ON(commdlg)) - { - unsigned int i; - static const struct { - DWORD mask; - const char *name; - } flags[] = { -#define FE(x) { x, #x} - /* SBSP_DEFBROWSER == 0 */ - FE(SBSP_SAMEBROWSER), - FE(SBSP_NEWBROWSER), - - /* SBSP_DEFMODE == 0 */ - FE(SBSP_OPENMODE), - FE(SBSP_EXPLOREMODE), - FE(SBSP_HELPMODE), - FE(SBSP_NOTRANSFERHIST), - - /* SBSP_ABSOLUTE == 0 */ - FE(SBSP_RELATIVE), - FE(SBSP_PARENT), - FE(SBSP_NAVIGATEBACK), - FE(SBSP_NAVIGATEFORWARD), - FE(SBSP_ALLOW_AUTONAVIGATE), - - FE(SBSP_NOAUTOSELECT), - FE(SBSP_WRITENOHISTORY), - - FE(SBSP_REDIRECT), - FE(SBSP_INITIATEDBYHLINKFRAME), - }; -#undef FE - DPRINTF("SBSP Flags: %08x =", uflags); - for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) - if (flags[i].mask & uflags) - DPRINTF("%s ", flags[i].name); - DPRINTF("\n"); - } -} - -static void COMDLG32_UpdateCurrentDir(FileOpenDlgInfos *fodInfos) -{ - LPSHELLFOLDER psfDesktop; - STRRET strret; - HRESULT res; - - res = SHGetDesktopFolder(&psfDesktop); - if (FAILED(res)) - return; - - res = IShellFolder_GetDisplayNameOf(psfDesktop, fodInfos->ShellInfos.pidlAbsCurrent, - SHGDN_FORPARSING, &strret); - if (SUCCEEDED(res)) { - WCHAR wszCurrentDir[MAX_PATH]; - - res = StrRetToBufW(&strret, fodInfos->ShellInfos.pidlAbsCurrent, wszCurrentDir, MAX_PATH); - if (SUCCEEDED(res)) - SetCurrentDirectoryW(wszCurrentDir); - } - - IShellFolder_Release(psfDesktop); -} - -/* copied from shell32 to avoid linking to it */ -static HRESULT COMDLG32_StrRetToStrNW (LPVOID dest, DWORD len, LPSTRRET src, LPCITEMIDLIST pidl) -{ - TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl); - - switch (src->uType) - { - case STRRET_WSTR: - lstrcpynW((LPWSTR)dest, src->u.pOleStr, len); - COMDLG32_SHFree(src->u.pOleStr); - break; - - case STRRET_CSTR: - if (len && !MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, (LPWSTR)dest, len )) - ((LPWSTR)dest)[len-1] = 0; - break; - - case STRRET_OFFSET: - if (pidl) - { - if (len && !MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, - -1, (LPWSTR)dest, len )) - ((LPWSTR)dest)[len-1] = 0; - } - break; - - default: - FIXME("unknown type!\n"); - if (len) - { *(LPWSTR)dest = '\0'; - } - return(FALSE); - } - return S_OK; -} - -/* - * IShellBrowser - */ - -/************************************************************************** -* IShellBrowserImpl_Construct -*/ -IShellBrowser * IShellBrowserImpl_Construct(HWND hwndOwner) -{ - IShellBrowserImpl *sb; - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndOwner,FileOpenDlgInfosStr); - - sb=(IShellBrowserImpl*)COMDLG32_SHAlloc(sizeof(IShellBrowserImpl)); - - /* Initialisation of the member variables */ - sb->ref=1; - sb->hwndOwner = hwndOwner; - - /* Initialisation of the vTables */ - sb->lpVtbl = &IShellBrowserImpl_Vtbl; - sb->lpVtblCommDlgBrowser = &IShellBrowserImpl_ICommDlgBrowser_Vtbl; - sb->lpVtblServiceProvider = &IShellBrowserImpl_IServiceProvider_Vtbl; - SHGetSpecialFolderLocation(hwndOwner, CSIDL_DESKTOP, - &fodInfos->ShellInfos.pidlAbsCurrent); - - TRACE("%p\n", sb); - - return (IShellBrowser *) sb; -} - -/*************************************************************************** -* IShellBrowserImpl_QueryInterface -*/ -HRESULT WINAPI IShellBrowserImpl_QueryInterface(IShellBrowser *iface, - REFIID riid, - LPVOID *ppvObj) -{ - IShellBrowserImpl *This = (IShellBrowserImpl *)iface; - - TRACE("(%p)\n\t%s\n", This, debugstr_guid(riid)); - - *ppvObj = NULL; - - if(IsEqualIID(riid, &IID_IUnknown)) /*IUnknown*/ - { *ppvObj = This; - } - else if(IsEqualIID(riid, &IID_IOleWindow)) /*IOleWindow*/ - { *ppvObj = (IOleWindow*)This; - } - - else if(IsEqualIID(riid, &IID_IShellBrowser)) /*IShellBrowser*/ - { *ppvObj = (IShellBrowser*)This; - } - - else if(IsEqualIID(riid, &IID_ICommDlgBrowser)) /*ICommDlgBrowser*/ - { *ppvObj = (ICommDlgBrowser*) &(This->lpVtblCommDlgBrowser); - } - - else if(IsEqualIID(riid, &IID_IServiceProvider)) /* IServiceProvider */ - { *ppvObj = (ICommDlgBrowser*) &(This->lpVtblServiceProvider); - } - - if(*ppvObj) - { IUnknown_AddRef( (IShellBrowser*) *ppvObj); - return S_OK; - } - FIXME("Unknown interface requested\n"); - return E_NOINTERFACE; -} - -/************************************************************************** -* IShellBrowser::AddRef -*/ -ULONG WINAPI IShellBrowserImpl_AddRef(IShellBrowser * iface) -{ - IShellBrowserImpl *This = (IShellBrowserImpl *)iface; - ULONG ref = InterlockedIncrement(&This->ref); - - TRACE("(%p,%lu)\n", This, ref - 1); - - return ref; -} - -/************************************************************************** -* IShellBrowserImpl_Release -*/ -ULONG WINAPI IShellBrowserImpl_Release(IShellBrowser * iface) -{ - IShellBrowserImpl *This = (IShellBrowserImpl *)iface; - ULONG ref = InterlockedDecrement(&This->ref); - - TRACE("(%p,%lu)\n", This, ref + 1); - - if (!ref) - { - COMDLG32_SHFree(This); - TRACE("-- destroyed\n"); - return 0; - } - return ref; -} - -/* - * IOleWindow - */ - -/************************************************************************** -* IShellBrowserImpl_GetWindow (IOleWindow) -* -* Inherited from IOleWindow::GetWindow -* -* See Windows documentation for more details -* -* Note : We will never be window less in the File Open dialog -* -*/ -HRESULT WINAPI IShellBrowserImpl_GetWindow(IShellBrowser * iface, - HWND * phwnd) -{ - IShellBrowserImpl *This = (IShellBrowserImpl *)iface; - - TRACE("(%p)\n", This); - - if(!This->hwndOwner) - return E_FAIL; - - *phwnd = This->hwndOwner; - - return (*phwnd) ? S_OK : E_UNEXPECTED; - -} - -/************************************************************************** -* IShellBrowserImpl_ContextSensitiveHelp -*/ -HRESULT WINAPI IShellBrowserImpl_ContextSensitiveHelp(IShellBrowser * iface, - BOOL fEnterMode) -{ - IShellBrowserImpl *This = (IShellBrowserImpl *)iface; - - TRACE("(%p)\n", This); - - /* Feature not implemented */ - return E_NOTIMPL; -} - -/* - * IShellBrowser - */ - -/************************************************************************** -* IShellBrowserImpl_BrowseObject -* -* See Windows documentation on IShellBrowser::BrowseObject for more details -* -* This function will override user specified flags and will always -* use SBSP_DEFBROWSER and SBSP_DEFMODE. -*/ -HRESULT WINAPI IShellBrowserImpl_BrowseObject(IShellBrowser *iface, - LPCITEMIDLIST pidl, - UINT wFlags) -{ - HRESULT hRes; - IShellFolder *psfTmp; - IShellView *psvTmp; - FileOpenDlgInfos *fodInfos; - LPITEMIDLIST pidlTmp; - HWND hwndView; - HWND hDlgWnd; - BOOL bViewHasFocus; - RECT rectView; - - IShellBrowserImpl *This = (IShellBrowserImpl *)iface; - - TRACE("(%p)(pidl=%p,flags=0x%08x)\n", This, pidl, wFlags); - COMDLG32_DumpSBSPFlags(wFlags); - - fodInfos = (FileOpenDlgInfos *) GetPropA(This->hwndOwner,FileOpenDlgInfosStr); - - /* Format the pidl according to its parameter's category */ - if(wFlags & SBSP_RELATIVE) - { - - /* SBSP_RELATIVE A relative pidl (relative from the current folder) */ - if(FAILED(hRes = IShellFolder_BindToObject(fodInfos->Shell.FOIShellFolder, - pidl, NULL, &IID_IShellFolder, (LPVOID *)&psfTmp))) - { - ERR("bind to object failed\n"); - return hRes; - } - /* create an absolute pidl */ - pidlTmp = COMDLG32_PIDL_ILCombine(fodInfos->ShellInfos.pidlAbsCurrent, - (LPITEMIDLIST)pidl); - } - else if(wFlags & SBSP_PARENT) - { - /* Browse the parent folder (ignores the pidl) */ - pidlTmp = GetParentPidl(fodInfos->ShellInfos.pidlAbsCurrent); - psfTmp = GetShellFolderFromPidl(pidlTmp); - - } - else /* SBSP_ABSOLUTE is 0x0000 */ - { - /* An absolute pidl (relative from the desktop) */ - pidlTmp = COMDLG32_PIDL_ILClone((LPITEMIDLIST)pidl); - psfTmp = GetShellFolderFromPidl(pidlTmp); - } - - if(!psfTmp) - { - ERR("could not browse to folder\n"); - return E_FAIL; - } - - /* If the pidl to browse to is equal to the actual pidl ... - do nothing and pretend you did it*/ - if(COMDLG32_PIDL_ILIsEqual(pidlTmp,fodInfos->ShellInfos.pidlAbsCurrent)) - { - IShellFolder_Release(psfTmp); - COMDLG32_SHFree(pidlTmp); - TRACE("keep current folder\n"); - return NOERROR; - } - - /* Release the current DataObject */ - if (fodInfos->Shell.FOIDataObject) - { - IDataObject_Release(fodInfos->Shell.FOIDataObject); - fodInfos->Shell.FOIDataObject = NULL; - } - - /* Create the associated view */ - TRACE("create view object\n"); - if(FAILED(hRes = IShellFolder_CreateViewObject(psfTmp, fodInfos->ShellInfos.hwndOwner, - &IID_IShellView, (LPVOID *)&psvTmp))) goto error; - - /* Check if listview has focus */ - bViewHasFocus = IsChild(fodInfos->ShellInfos.hwndView,GetFocus()); - - /* Get the foldersettings from the old view */ - if(fodInfos->Shell.FOIShellView) - IShellView_GetCurrentInfo(fodInfos->Shell.FOIShellView, &fodInfos->ShellInfos.folderSettings); - - /* Release the old fodInfos->Shell.FOIShellView and update its value. - We have to update this early since ShellView_CreateViewWindow of native - shell32 calls OnStateChange and needs the correct view here.*/ - if(fodInfos->Shell.FOIShellView) - { - IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView); - IShellView_Release(fodInfos->Shell.FOIShellView); - } - fodInfos->Shell.FOIShellView = psvTmp; - - /* Release old FOIShellFolder and update its value */ - if (fodInfos->Shell.FOIShellFolder) - IShellFolder_Release(fodInfos->Shell.FOIShellFolder); - fodInfos->Shell.FOIShellFolder = psfTmp; - - /* Release old pidlAbsCurrent and update its value */ - COMDLG32_SHFree((LPVOID)fodInfos->ShellInfos.pidlAbsCurrent); - fodInfos->ShellInfos.pidlAbsCurrent = pidlTmp; - - COMDLG32_UpdateCurrentDir(fodInfos); - - GetWindowRect(GetDlgItem(This->hwndOwner, IDC_SHELLSTATIC), &rectView); - MapWindowPoints(0, This->hwndOwner, (LPPOINT)&rectView, 2); - - /* Create the window */ - TRACE("create view window\n"); - if(FAILED(hRes = IShellView_CreateViewWindow(psvTmp, NULL, - &fodInfos->ShellInfos.folderSettings, fodInfos->Shell.FOIShellBrowser, - &rectView, &hwndView))) goto error; - - fodInfos->ShellInfos.hwndView = hwndView; - - /* Select the new folder in the Look In combo box of the Open file dialog */ - FILEDLG95_LOOKIN_SelectItem(fodInfos->DlgInfos.hwndLookInCB,fodInfos->ShellInfos.pidlAbsCurrent); - - /* changes the tab order of the ListView to reflect the window's File Dialog */ - hDlgWnd = GetDlgItem(GetParent(hwndView), IDC_LOOKIN); - SetWindowPos(hwndView, hDlgWnd, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE); - - /* Since we destroyed the old view if it had focus set focus to the newly created view */ - if (bViewHasFocus) - SetFocus(fodInfos->ShellInfos.hwndView); - - return hRes; -error: - ERR("Failed with error 0x%08lx\n", hRes); - return hRes; -} - -/************************************************************************** -* IShellBrowserImpl_EnableModelessSB -*/ -HRESULT WINAPI IShellBrowserImpl_EnableModelessSB(IShellBrowser *iface, - BOOL fEnable) - -{ - IShellBrowserImpl *This = (IShellBrowserImpl *)iface; - - TRACE("(%p)\n", This); - - /* Feature not implemented */ - return E_NOTIMPL; -} - -/************************************************************************** -* IShellBrowserImpl_GetControlWindow -*/ -HRESULT WINAPI IShellBrowserImpl_GetControlWindow(IShellBrowser *iface, - UINT id, - HWND *lphwnd) - -{ - IShellBrowserImpl *This = (IShellBrowserImpl *)iface; - - TRACE("(%p)\n", This); - - /* Feature not implemented */ - return E_NOTIMPL; -} -/************************************************************************** -* IShellBrowserImpl_GetViewStateStream -*/ -HRESULT WINAPI IShellBrowserImpl_GetViewStateStream(IShellBrowser *iface, - DWORD grfMode, - LPSTREAM *ppStrm) - -{ - IShellBrowserImpl *This = (IShellBrowserImpl *)iface; - - FIXME("(%p 0x%08lx %p)\n", This, grfMode, ppStrm); - - /* Feature not implemented */ - return E_NOTIMPL; -} -/************************************************************************** -* IShellBrowserImpl_InsertMenusSB -*/ -HRESULT WINAPI IShellBrowserImpl_InsertMenusSB(IShellBrowser *iface, - HMENU hmenuShared, - LPOLEMENUGROUPWIDTHS lpMenuWidths) - -{ - IShellBrowserImpl *This = (IShellBrowserImpl *)iface; - - TRACE("(%p)\n", This); - - /* Feature not implemented */ - return E_NOTIMPL; -} -/************************************************************************** -* IShellBrowserImpl_OnViewWindowActive -*/ -HRESULT WINAPI IShellBrowserImpl_OnViewWindowActive(IShellBrowser *iface, - IShellView *ppshv) - -{ - IShellBrowserImpl *This = (IShellBrowserImpl *)iface; - - TRACE("(%p)\n", This); - - /* Feature not implemented */ - return E_NOTIMPL; -} -/************************************************************************** -* IShellBrowserImpl_QueryActiveShellView -*/ -HRESULT WINAPI IShellBrowserImpl_QueryActiveShellView(IShellBrowser *iface, - IShellView **ppshv) - -{ - IShellBrowserImpl *This = (IShellBrowserImpl *)iface; - - FileOpenDlgInfos *fodInfos; - - TRACE("(%p)\n", This); - - fodInfos = (FileOpenDlgInfos *) GetPropA(This->hwndOwner,FileOpenDlgInfosStr); - - if(!(*ppshv = fodInfos->Shell.FOIShellView)) - { - return E_FAIL; - } - IShellView_AddRef(fodInfos->Shell.FOIShellView); - return NOERROR; -} -/************************************************************************** -* IShellBrowserImpl_RemoveMenusSB -*/ -HRESULT WINAPI IShellBrowserImpl_RemoveMenusSB(IShellBrowser *iface, - HMENU hmenuShared) - -{ - IShellBrowserImpl *This = (IShellBrowserImpl *)iface; - - TRACE("(%p)\n", This); - - /* Feature not implemented */ - return E_NOTIMPL; -} -/************************************************************************** -* IShellBrowserImpl_SendControlMsg -*/ -HRESULT WINAPI IShellBrowserImpl_SendControlMsg(IShellBrowser *iface, - UINT id, - UINT uMsg, - WPARAM wParam, - LPARAM lParam, - LRESULT *pret) - -{ - IShellBrowserImpl *This = (IShellBrowserImpl *)iface; - LRESULT lres; - - TRACE("(%p)->(0x%08x 0x%08x 0x%08x 0x%08lx %p)\n", This, id, uMsg, wParam, lParam, pret); - - switch (id) - { - case FCW_TOOLBAR: - lres = SendDlgItemMessageA( This->hwndOwner, IDC_TOOLBAR, uMsg, wParam, lParam); - break; - default: - FIXME("ctrl id: %x\n", id); - return E_NOTIMPL; - } - if (pret) *pret = lres; - return S_OK; -} -/************************************************************************** -* IShellBrowserImpl_SetMenuSB -*/ -HRESULT WINAPI IShellBrowserImpl_SetMenuSB(IShellBrowser *iface, - HMENU hmenuShared, - HOLEMENU holemenuReserved, - HWND hwndActiveObject) - -{ - IShellBrowserImpl *This = (IShellBrowserImpl *)iface; - - TRACE("(%p)\n", This); - - /* Feature not implemented */ - return E_NOTIMPL; -} -/************************************************************************** -* IShellBrowserImpl_SetStatusTextSB -*/ -HRESULT WINAPI IShellBrowserImpl_SetStatusTextSB(IShellBrowser *iface, - LPCOLESTR lpszStatusText) - -{ - IShellBrowserImpl *This = (IShellBrowserImpl *)iface; - - TRACE("(%p)\n", This); - - /* Feature not implemented */ - return E_NOTIMPL; -} -/************************************************************************** -* IShellBrowserImpl_SetToolbarItems -*/ -HRESULT WINAPI IShellBrowserImpl_SetToolbarItems(IShellBrowser *iface, - LPTBBUTTON lpButtons, - UINT nButtons, - UINT uFlags) - -{ - IShellBrowserImpl *This = (IShellBrowserImpl *)iface; - - TRACE("(%p)\n", This); - - /* Feature not implemented */ - return E_NOTIMPL; -} -/************************************************************************** -* IShellBrowserImpl_TranslateAcceleratorSB -*/ -HRESULT WINAPI IShellBrowserImpl_TranslateAcceleratorSB(IShellBrowser *iface, - LPMSG lpmsg, - WORD wID) - -{ - IShellBrowserImpl *This = (IShellBrowserImpl *)iface; - - TRACE("(%p)\n", This); - - /* Feature not implemented */ - return E_NOTIMPL; -} - -static const IShellBrowserVtbl IShellBrowserImpl_Vtbl = -{ - /* IUnknown */ - IShellBrowserImpl_QueryInterface, - IShellBrowserImpl_AddRef, - IShellBrowserImpl_Release, - /* IOleWindow */ - IShellBrowserImpl_GetWindow, - IShellBrowserImpl_ContextSensitiveHelp, - /* IShellBrowser */ - IShellBrowserImpl_InsertMenusSB, - IShellBrowserImpl_SetMenuSB, - IShellBrowserImpl_RemoveMenusSB, - IShellBrowserImpl_SetStatusTextSB, - IShellBrowserImpl_EnableModelessSB, - IShellBrowserImpl_TranslateAcceleratorSB, - IShellBrowserImpl_BrowseObject, - IShellBrowserImpl_GetViewStateStream, - IShellBrowserImpl_GetControlWindow, - IShellBrowserImpl_SendControlMsg, - IShellBrowserImpl_QueryActiveShellView, - IShellBrowserImpl_OnViewWindowActive, - IShellBrowserImpl_SetToolbarItems -}; - - - -/* - * ICommDlgBrowser - */ - -/*************************************************************************** -* IShellBrowserImpl_ICommDlgBrowser_QueryInterface -*/ -HRESULT WINAPI IShellBrowserImpl_ICommDlgBrowser_QueryInterface( - ICommDlgBrowser *iface, - REFIID riid, - LPVOID *ppvObj) -{ - _ICOM_THIS_FromICommDlgBrowser(IShellBrowser,iface); - - TRACE("(%p)\n", This); - - return IShellBrowserImpl_QueryInterface(This,riid,ppvObj); -} - -/************************************************************************** -* IShellBrowserImpl_ICommDlgBrowser_AddRef -*/ -ULONG WINAPI IShellBrowserImpl_ICommDlgBrowser_AddRef(ICommDlgBrowser * iface) -{ - _ICOM_THIS_FromICommDlgBrowser(IShellBrowser,iface); - - TRACE("(%p)\n", This); - - return IShellBrowserImpl_AddRef(This); -} - -/************************************************************************** -* IShellBrowserImpl_ICommDlgBrowser_Release -*/ -ULONG WINAPI IShellBrowserImpl_ICommDlgBrowser_Release(ICommDlgBrowser * iface) -{ - _ICOM_THIS_FromICommDlgBrowser(IShellBrowser,iface); - - TRACE("(%p)\n", This); - - return IShellBrowserImpl_Release(This); -} -/************************************************************************** -* IShellBrowserImpl_ICommDlgBrowser_OnDefaultCommand -* -* Called when a user double-clicks in the view or presses the ENTER key -*/ -HRESULT WINAPI IShellBrowserImpl_ICommDlgBrowser_OnDefaultCommand(ICommDlgBrowser *iface, - IShellView *ppshv) -{ - LPITEMIDLIST pidl; - FileOpenDlgInfos *fodInfos; - - _ICOM_THIS_FromICommDlgBrowser(IShellBrowserImpl,iface); - - TRACE("(%p)\n", This); - - fodInfos = (FileOpenDlgInfos *) GetPropA(This->hwndOwner,FileOpenDlgInfosStr); - - /* If the selected object is not a folder, send an IDOK command to parent window */ - if((pidl = GetPidlFromDataObject(fodInfos->Shell.FOIDataObject, 1))) - { - HRESULT hRes; - - ULONG ulAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER; - IShellFolder_GetAttributesOf(fodInfos->Shell.FOIShellFolder, 1, (LPCITEMIDLIST *)&pidl, &ulAttr); - if (ulAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER) ) - { - hRes = IShellBrowser_BrowseObject((IShellBrowser *)This,pidl,SBSP_RELATIVE); - SendCustomDlgNotificationMessage(This->hwndOwner, CDN_FOLDERCHANGE); - } - else - { - /* Tell the dialog that the user selected a file */ - PostMessageA(This->hwndOwner, WM_COMMAND, IDOK, 0L); - hRes = S_OK; - } - - /* Free memory used by pidl */ - COMDLG32_SHFree((LPVOID)pidl); - - return hRes; - } - - return E_FAIL; -} - -/************************************************************************** -* IShellBrowserImpl_ICommDlgBrowser_OnStateChange -*/ -HRESULT WINAPI IShellBrowserImpl_ICommDlgBrowser_OnStateChange(ICommDlgBrowser *iface, - IShellView *ppshv, - ULONG uChange) -{ - - _ICOM_THIS_FromICommDlgBrowser(IShellBrowserImpl,iface); - - TRACE("(%p shv=%p)\n", This, ppshv); - - switch (uChange) - { - case CDBOSC_SETFOCUS: - /* FIXME: Reset the default button. - This should be taken care of by defdlg. If control - other than button receives focus the default button - should be restored. */ - SendMessageA(This->hwndOwner, DM_SETDEFID, IDOK, 0); - - break; - case CDBOSC_KILLFOCUS: - { - FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(This->hwndOwner,FileOpenDlgInfosStr); - if(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) - SetDlgItemTextA(fodInfos->ShellInfos.hwndOwner,IDOK,"&Save"); - } - break; - case CDBOSC_SELCHANGE: - return IShellBrowserImpl_ICommDlgBrowser_OnSelChange(iface,ppshv); - case CDBOSC_RENAME: - /* nothing to do */ - break; - } - - return NOERROR; -} - -/************************************************************************** -* IShellBrowserImpl_ICommDlgBrowser_IncludeObject -*/ -HRESULT WINAPI IShellBrowserImpl_ICommDlgBrowser_IncludeObject(ICommDlgBrowser *iface, - IShellView * ppshv, - LPCITEMIDLIST pidl) -{ - FileOpenDlgInfos *fodInfos; - ULONG ulAttr; - STRRET str; - WCHAR szPathW[MAX_PATH]; - - _ICOM_THIS_FromICommDlgBrowser(IShellBrowserImpl,iface); - - TRACE("(%p)\n", This); - - fodInfos = (FileOpenDlgInfos *) GetPropA(This->hwndOwner,FileOpenDlgInfosStr); - - ulAttr = SFGAO_HIDDEN | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_FILESYSANCESTOR | SFGAO_LINK; - IShellFolder_GetAttributesOf(fodInfos->Shell.FOIShellFolder, 1, &pidl, &ulAttr); - - if( (ulAttr & SFGAO_HIDDEN) /* hidden */ - | !(ulAttr & (SFGAO_FILESYSTEM | SFGAO_FILESYSANCESTOR))) /* special folder */ - return S_FALSE; - - /* always include directories and links */ - if(ulAttr & (SFGAO_FOLDER | SFGAO_LINK)) - return S_OK; - - /* Check if there is a mask to apply if not */ - if(!fodInfos->ShellInfos.lpstrCurrentFilter || !lstrlenW(fodInfos->ShellInfos.lpstrCurrentFilter)) - return S_OK; - - if (SUCCEEDED(IShellFolder_GetDisplayNameOf(fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, &str))) - { - if (SUCCEEDED(COMDLG32_StrRetToStrNW(szPathW, MAX_PATH, &str, pidl))) - { - if (PathMatchSpecW(szPathW, fodInfos->ShellInfos.lpstrCurrentFilter)) - return S_OK; - } - } - return S_FALSE; - -} - -/************************************************************************** -* IShellBrowserImpl_ICommDlgBrowser_OnSelChange -*/ -HRESULT IShellBrowserImpl_ICommDlgBrowser_OnSelChange(ICommDlgBrowser *iface, IShellView *ppshv) -{ - FileOpenDlgInfos *fodInfos; - - _ICOM_THIS_FromICommDlgBrowser(IShellBrowserImpl,iface); - - fodInfos = (FileOpenDlgInfos *) GetPropA(This->hwndOwner,FileOpenDlgInfosStr); - TRACE("(%p do=%p view=%p)\n", This, fodInfos->Shell.FOIDataObject, fodInfos->Shell.FOIShellView); - - /* release old selections */ - if (fodInfos->Shell.FOIDataObject) - IDataObject_Release(fodInfos->Shell.FOIDataObject); - - /* get a new DataObject from the ShellView */ - if(FAILED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView, SVGIO_SELECTION, - &IID_IDataObject, (LPVOID*)&fodInfos->Shell.FOIDataObject))) - return E_FAIL; - - FILEDLG95_FILENAME_FillFromSelection(This->hwndOwner); - - SendCustomDlgNotificationMessage(This->hwndOwner, CDN_SELCHANGE); - return S_OK; -} - -static const ICommDlgBrowserVtbl IShellBrowserImpl_ICommDlgBrowser_Vtbl = -{ - /* IUnknown */ - IShellBrowserImpl_ICommDlgBrowser_QueryInterface, - IShellBrowserImpl_ICommDlgBrowser_AddRef, - IShellBrowserImpl_ICommDlgBrowser_Release, - /* ICommDlgBrowser */ - IShellBrowserImpl_ICommDlgBrowser_OnDefaultCommand, - IShellBrowserImpl_ICommDlgBrowser_OnStateChange, - IShellBrowserImpl_ICommDlgBrowser_IncludeObject -}; - - - - -/* - * IServiceProvider - */ - -/*************************************************************************** -* IShellBrowserImpl_IServiceProvider_QueryInterface -*/ -HRESULT WINAPI IShellBrowserImpl_IServiceProvider_QueryInterface( - IServiceProvider *iface, - REFIID riid, - LPVOID *ppvObj) -{ - _ICOM_THIS_FromIServiceProvider(IShellBrowser,iface); - - FIXME("(%p)\n", This); - - return IShellBrowserImpl_QueryInterface(This,riid,ppvObj); -} - -/************************************************************************** -* IShellBrowserImpl_IServiceProvider_AddRef -*/ -ULONG WINAPI IShellBrowserImpl_IServiceProvider_AddRef(IServiceProvider * iface) -{ - _ICOM_THIS_FromIServiceProvider(IShellBrowser,iface); - - FIXME("(%p)\n", This); - - return IShellBrowserImpl_AddRef(This); -} - -/************************************************************************** -* IShellBrowserImpl_IServiceProvider_Release -*/ -ULONG WINAPI IShellBrowserImpl_IServiceProvider_Release(IServiceProvider * iface) -{ - _ICOM_THIS_FromIServiceProvider(IShellBrowser,iface); - - FIXME("(%p)\n", This); - - return IShellBrowserImpl_Release(This); -} - -/************************************************************************** -* IShellBrowserImpl_IServiceProvider_Release -* -* NOTES -* the w2k shellview asks for (guidService = SID_STopLevelBrowser, -* riid = IShellBrowser) to call SendControlMsg (). -* -* FIXME -* this is a hack! -*/ - -HRESULT WINAPI IShellBrowserImpl_IServiceProvider_QueryService( - IServiceProvider * iface, - REFGUID guidService, - REFIID riid, - void** ppv) -{ - _ICOM_THIS_FromIServiceProvider(IShellBrowser,iface); - - FIXME("(%p)\n\t%s\n\t%s\n", This,debugstr_guid(guidService), debugstr_guid(riid) ); - - *ppv = NULL; - if(guidService && IsEqualIID(guidService, &SID_STopLevelBrowser)) - { - return IShellBrowserImpl_QueryInterface(This,riid,ppv); - } - FIXME("(%p) unknown interface requested\n", This); - return E_NOINTERFACE; - -} - -static const IServiceProviderVtbl IShellBrowserImpl_IServiceProvider_Vtbl = -{ - /* IUnknown */ - IShellBrowserImpl_IServiceProvider_QueryInterface, - IShellBrowserImpl_IServiceProvider_AddRef, - IShellBrowserImpl_IServiceProvider_Release, - /* IServiceProvider */ - IShellBrowserImpl_IServiceProvider_QueryService -}; +/* + * Implementation of IShellBrowser for the File Open common dialog + * + * Copyright 1999 Francois Boisvert + * Copyright 1999, 2000 Juergen Schmied + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "wingdi.h" +#include "winuser.h" +#include "winreg.h" + +#define NO_SHLWAPI_STREAM +#include "shlwapi.h" +#include "filedlgbrowser.h" +#include "cdlg.h" +#include "shlguid.h" +#include "servprov.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(commdlg); + +typedef struct +{ + + const IShellBrowserVtbl *lpVtbl; + const ICommDlgBrowserVtbl *lpVtblCommDlgBrowser; + const IServiceProviderVtbl *lpVtblServiceProvider; + DWORD ref; /* Reference counter */ + HWND hwndOwner; /* Owner dialog of the interface */ + +} IShellBrowserImpl; + +/************************************************************************** +* vtable +*/ +static const IShellBrowserVtbl IShellBrowserImpl_Vtbl; +static const ICommDlgBrowserVtbl IShellBrowserImpl_ICommDlgBrowser_Vtbl; +static const IServiceProviderVtbl IShellBrowserImpl_IServiceProvider_Vtbl; + +/************************************************************************** +* Local Prototypes +*/ + +HRESULT IShellBrowserImpl_ICommDlgBrowser_OnSelChange(ICommDlgBrowser *iface, IShellView *ppshv); +#if 0 +LPITEMIDLIST GetSelectedPidl(IShellView *ppshv); +#endif + +/************************************************************************** +* External Prototypes +*/ +extern const char *FileOpenDlgInfosStr; + +extern IShellFolder* GetShellFolderFromPidl(LPITEMIDLIST pidlAbs); +extern LPITEMIDLIST GetParentPidl(LPITEMIDLIST pidl); +extern LPITEMIDLIST GetPidlFromName(IShellFolder *psf,LPCSTR lpcstrFileName); + +extern int FILEDLG95_LOOKIN_SelectItem(HWND hwnd,LPITEMIDLIST pidl); +extern void SendCustomDlgNotificationMessage(HWND hwndParentDlg, UINT uCode); + + +/* + * Helper functions + */ + +#define add_flag(a) if (flags & a) {strcat(str, #a );strcat(str," ");} +static void COMDLG32_DumpSBSPFlags(UINT uflags) +{ + if (TRACE_ON(commdlg)) + { + unsigned int i; + static const struct { + DWORD mask; + const char *name; + } flags[] = { +#define FE(x) { x, #x} + /* SBSP_DEFBROWSER == 0 */ + FE(SBSP_SAMEBROWSER), + FE(SBSP_NEWBROWSER), + + /* SBSP_DEFMODE == 0 */ + FE(SBSP_OPENMODE), + FE(SBSP_EXPLOREMODE), + FE(SBSP_HELPMODE), + FE(SBSP_NOTRANSFERHIST), + + /* SBSP_ABSOLUTE == 0 */ + FE(SBSP_RELATIVE), + FE(SBSP_PARENT), + FE(SBSP_NAVIGATEBACK), + FE(SBSP_NAVIGATEFORWARD), + FE(SBSP_ALLOW_AUTONAVIGATE), + + FE(SBSP_NOAUTOSELECT), + FE(SBSP_WRITENOHISTORY), + + FE(SBSP_REDIRECT), + FE(SBSP_INITIATEDBYHLINKFRAME), + }; +#undef FE + DPRINTF("SBSP Flags: %08x =", uflags); + for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) + if (flags[i].mask & uflags) + DPRINTF("%s ", flags[i].name); + DPRINTF("\n"); + } +} + +static void COMDLG32_UpdateCurrentDir(FileOpenDlgInfos *fodInfos) +{ + LPSHELLFOLDER psfDesktop; + STRRET strret; + HRESULT res; + + res = SHGetDesktopFolder(&psfDesktop); + if (FAILED(res)) + return; + + res = IShellFolder_GetDisplayNameOf(psfDesktop, fodInfos->ShellInfos.pidlAbsCurrent, + SHGDN_FORPARSING, &strret); + if (SUCCEEDED(res)) { + WCHAR wszCurrentDir[MAX_PATH]; + + res = StrRetToBufW(&strret, fodInfos->ShellInfos.pidlAbsCurrent, wszCurrentDir, MAX_PATH); + if (SUCCEEDED(res)) + SetCurrentDirectoryW(wszCurrentDir); + } + + IShellFolder_Release(psfDesktop); +} + +/* copied from shell32 to avoid linking to it */ +static HRESULT COMDLG32_StrRetToStrNW (LPVOID dest, DWORD len, LPSTRRET src, LPCITEMIDLIST pidl) +{ + TRACE("dest=%p len=0x%lx strret=%p pidl=%p stub\n",dest,len,src,pidl); + + switch (src->uType) + { + case STRRET_WSTR: + lstrcpynW((LPWSTR)dest, src->u.pOleStr, len); + COMDLG32_SHFree(src->u.pOleStr); + break; + + case STRRET_CSTR: + if (len && !MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, (LPWSTR)dest, len )) + ((LPWSTR)dest)[len-1] = 0; + break; + + case STRRET_OFFSET: + if (pidl) + { + if (len && !MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, + -1, (LPWSTR)dest, len )) + ((LPWSTR)dest)[len-1] = 0; + } + break; + + default: + FIXME("unknown type!\n"); + if (len) + { *(LPWSTR)dest = '\0'; + } + return(FALSE); + } + return S_OK; +} + +/* + * IShellBrowser + */ + +/************************************************************************** +* IShellBrowserImpl_Construct +*/ +IShellBrowser * IShellBrowserImpl_Construct(HWND hwndOwner) +{ + IShellBrowserImpl *sb; + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(hwndOwner,FileOpenDlgInfosStr); + + sb=(IShellBrowserImpl*)COMDLG32_SHAlloc(sizeof(IShellBrowserImpl)); + + /* Initialisation of the member variables */ + sb->ref=1; + sb->hwndOwner = hwndOwner; + + /* Initialisation of the vTables */ + sb->lpVtbl = &IShellBrowserImpl_Vtbl; + sb->lpVtblCommDlgBrowser = &IShellBrowserImpl_ICommDlgBrowser_Vtbl; + sb->lpVtblServiceProvider = &IShellBrowserImpl_IServiceProvider_Vtbl; + SHGetSpecialFolderLocation(hwndOwner, CSIDL_DESKTOP, + &fodInfos->ShellInfos.pidlAbsCurrent); + + TRACE("%p\n", sb); + + return (IShellBrowser *) sb; +} + +/*************************************************************************** +* IShellBrowserImpl_QueryInterface +*/ +HRESULT WINAPI IShellBrowserImpl_QueryInterface(IShellBrowser *iface, + REFIID riid, + LPVOID *ppvObj) +{ + IShellBrowserImpl *This = (IShellBrowserImpl *)iface; + + TRACE("(%p)\n\t%s\n", This, debugstr_guid(riid)); + + *ppvObj = NULL; + + if(IsEqualIID(riid, &IID_IUnknown)) /*IUnknown*/ + { *ppvObj = This; + } + else if(IsEqualIID(riid, &IID_IOleWindow)) /*IOleWindow*/ + { *ppvObj = (IOleWindow*)This; + } + + else if(IsEqualIID(riid, &IID_IShellBrowser)) /*IShellBrowser*/ + { *ppvObj = (IShellBrowser*)This; + } + + else if(IsEqualIID(riid, &IID_ICommDlgBrowser)) /*ICommDlgBrowser*/ + { *ppvObj = (ICommDlgBrowser*) &(This->lpVtblCommDlgBrowser); + } + + else if(IsEqualIID(riid, &IID_IServiceProvider)) /* IServiceProvider */ + { *ppvObj = (ICommDlgBrowser*) &(This->lpVtblServiceProvider); + } + + if(*ppvObj) + { IUnknown_AddRef( (IShellBrowser*) *ppvObj); + return S_OK; + } + FIXME("Unknown interface requested\n"); + return E_NOINTERFACE; +} + +/************************************************************************** +* IShellBrowser::AddRef +*/ +ULONG WINAPI IShellBrowserImpl_AddRef(IShellBrowser * iface) +{ + IShellBrowserImpl *This = (IShellBrowserImpl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p,%lu)\n", This, ref - 1); + + return ref; +} + +/************************************************************************** +* IShellBrowserImpl_Release +*/ +ULONG WINAPI IShellBrowserImpl_Release(IShellBrowser * iface) +{ + IShellBrowserImpl *This = (IShellBrowserImpl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p,%lu)\n", This, ref + 1); + + if (!ref) + { + COMDLG32_SHFree(This); + TRACE("-- destroyed\n"); + return 0; + } + return ref; +} + +/* + * IOleWindow + */ + +/************************************************************************** +* IShellBrowserImpl_GetWindow (IOleWindow) +* +* Inherited from IOleWindow::GetWindow +* +* See Windows documentation for more details +* +* Note : We will never be window less in the File Open dialog +* +*/ +HRESULT WINAPI IShellBrowserImpl_GetWindow(IShellBrowser * iface, + HWND * phwnd) +{ + IShellBrowserImpl *This = (IShellBrowserImpl *)iface; + + TRACE("(%p)\n", This); + + if(!This->hwndOwner) + return E_FAIL; + + *phwnd = This->hwndOwner; + + return (*phwnd) ? S_OK : E_UNEXPECTED; + +} + +/************************************************************************** +* IShellBrowserImpl_ContextSensitiveHelp +*/ +HRESULT WINAPI IShellBrowserImpl_ContextSensitiveHelp(IShellBrowser * iface, + BOOL fEnterMode) +{ + IShellBrowserImpl *This = (IShellBrowserImpl *)iface; + + TRACE("(%p)\n", This); + + /* Feature not implemented */ + return E_NOTIMPL; +} + +/* + * IShellBrowser + */ + +/************************************************************************** +* IShellBrowserImpl_BrowseObject +* +* See Windows documentation on IShellBrowser::BrowseObject for more details +* +* This function will override user specified flags and will always +* use SBSP_DEFBROWSER and SBSP_DEFMODE. +*/ +HRESULT WINAPI IShellBrowserImpl_BrowseObject(IShellBrowser *iface, + LPCITEMIDLIST pidl, + UINT wFlags) +{ + HRESULT hRes; + IShellFolder *psfTmp; + IShellView *psvTmp; + FileOpenDlgInfos *fodInfos; + LPITEMIDLIST pidlTmp; + HWND hwndView; + HWND hDlgWnd; + BOOL bViewHasFocus; + RECT rectView; + + IShellBrowserImpl *This = (IShellBrowserImpl *)iface; + + TRACE("(%p)(pidl=%p,flags=0x%08x)\n", This, pidl, wFlags); + COMDLG32_DumpSBSPFlags(wFlags); + + fodInfos = (FileOpenDlgInfos *) GetPropA(This->hwndOwner,FileOpenDlgInfosStr); + + /* Format the pidl according to its parameter's category */ + if(wFlags & SBSP_RELATIVE) + { + + /* SBSP_RELATIVE A relative pidl (relative from the current folder) */ + if(FAILED(hRes = IShellFolder_BindToObject(fodInfos->Shell.FOIShellFolder, + pidl, NULL, &IID_IShellFolder, (LPVOID *)&psfTmp))) + { + ERR("bind to object failed\n"); + return hRes; + } + /* create an absolute pidl */ + pidlTmp = COMDLG32_PIDL_ILCombine(fodInfos->ShellInfos.pidlAbsCurrent, + (LPITEMIDLIST)pidl); + } + else if(wFlags & SBSP_PARENT) + { + /* Browse the parent folder (ignores the pidl) */ + pidlTmp = GetParentPidl(fodInfos->ShellInfos.pidlAbsCurrent); + psfTmp = GetShellFolderFromPidl(pidlTmp); + + } + else /* SBSP_ABSOLUTE is 0x0000 */ + { + /* An absolute pidl (relative from the desktop) */ + pidlTmp = COMDLG32_PIDL_ILClone((LPITEMIDLIST)pidl); + psfTmp = GetShellFolderFromPidl(pidlTmp); + } + + if(!psfTmp) + { + ERR("could not browse to folder\n"); + return E_FAIL; + } + + /* If the pidl to browse to is equal to the actual pidl ... + do nothing and pretend you did it*/ + if(COMDLG32_PIDL_ILIsEqual(pidlTmp,fodInfos->ShellInfos.pidlAbsCurrent)) + { + IShellFolder_Release(psfTmp); + COMDLG32_SHFree(pidlTmp); + TRACE("keep current folder\n"); + return NOERROR; + } + + /* Release the current DataObject */ + if (fodInfos->Shell.FOIDataObject) + { + IDataObject_Release(fodInfos->Shell.FOIDataObject); + fodInfos->Shell.FOIDataObject = NULL; + } + + /* Create the associated view */ + TRACE("create view object\n"); + if(FAILED(hRes = IShellFolder_CreateViewObject(psfTmp, fodInfos->ShellInfos.hwndOwner, + &IID_IShellView, (LPVOID *)&psvTmp))) goto error; + + /* Check if listview has focus */ + bViewHasFocus = IsChild(fodInfos->ShellInfos.hwndView,GetFocus()); + + /* Get the foldersettings from the old view */ + if(fodInfos->Shell.FOIShellView) + IShellView_GetCurrentInfo(fodInfos->Shell.FOIShellView, &fodInfos->ShellInfos.folderSettings); + + /* Release the old fodInfos->Shell.FOIShellView and update its value. + We have to update this early since ShellView_CreateViewWindow of native + shell32 calls OnStateChange and needs the correct view here.*/ + if(fodInfos->Shell.FOIShellView) + { + IShellView_DestroyViewWindow(fodInfos->Shell.FOIShellView); + IShellView_Release(fodInfos->Shell.FOIShellView); + } + fodInfos->Shell.FOIShellView = psvTmp; + + /* Release old FOIShellFolder and update its value */ + if (fodInfos->Shell.FOIShellFolder) + IShellFolder_Release(fodInfos->Shell.FOIShellFolder); + fodInfos->Shell.FOIShellFolder = psfTmp; + + /* Release old pidlAbsCurrent and update its value */ + COMDLG32_SHFree((LPVOID)fodInfos->ShellInfos.pidlAbsCurrent); + fodInfos->ShellInfos.pidlAbsCurrent = pidlTmp; + + COMDLG32_UpdateCurrentDir(fodInfos); + + GetWindowRect(GetDlgItem(This->hwndOwner, IDC_SHELLSTATIC), &rectView); + MapWindowPoints(0, This->hwndOwner, (LPPOINT)&rectView, 2); + + /* Create the window */ + TRACE("create view window\n"); + if(FAILED(hRes = IShellView_CreateViewWindow(psvTmp, NULL, + &fodInfos->ShellInfos.folderSettings, fodInfos->Shell.FOIShellBrowser, + &rectView, &hwndView))) goto error; + + fodInfos->ShellInfos.hwndView = hwndView; + + /* Select the new folder in the Look In combo box of the Open file dialog */ + FILEDLG95_LOOKIN_SelectItem(fodInfos->DlgInfos.hwndLookInCB,fodInfos->ShellInfos.pidlAbsCurrent); + + /* changes the tab order of the ListView to reflect the window's File Dialog */ + hDlgWnd = GetDlgItem(GetParent(hwndView), IDC_LOOKIN); + SetWindowPos(hwndView, hDlgWnd, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE); + + /* Since we destroyed the old view if it had focus set focus to the newly created view */ + if (bViewHasFocus) + SetFocus(fodInfos->ShellInfos.hwndView); + + return hRes; +error: + ERR("Failed with error 0x%08lx\n", hRes); + return hRes; +} + +/************************************************************************** +* IShellBrowserImpl_EnableModelessSB +*/ +HRESULT WINAPI IShellBrowserImpl_EnableModelessSB(IShellBrowser *iface, + BOOL fEnable) + +{ + IShellBrowserImpl *This = (IShellBrowserImpl *)iface; + + TRACE("(%p)\n", This); + + /* Feature not implemented */ + return E_NOTIMPL; +} + +/************************************************************************** +* IShellBrowserImpl_GetControlWindow +*/ +HRESULT WINAPI IShellBrowserImpl_GetControlWindow(IShellBrowser *iface, + UINT id, + HWND *lphwnd) + +{ + IShellBrowserImpl *This = (IShellBrowserImpl *)iface; + + TRACE("(%p)\n", This); + + /* Feature not implemented */ + return E_NOTIMPL; +} +/************************************************************************** +* IShellBrowserImpl_GetViewStateStream +*/ +HRESULT WINAPI IShellBrowserImpl_GetViewStateStream(IShellBrowser *iface, + DWORD grfMode, + LPSTREAM *ppStrm) + +{ + IShellBrowserImpl *This = (IShellBrowserImpl *)iface; + + FIXME("(%p 0x%08lx %p)\n", This, grfMode, ppStrm); + + /* Feature not implemented */ + return E_NOTIMPL; +} +/************************************************************************** +* IShellBrowserImpl_InsertMenusSB +*/ +HRESULT WINAPI IShellBrowserImpl_InsertMenusSB(IShellBrowser *iface, + HMENU hmenuShared, + LPOLEMENUGROUPWIDTHS lpMenuWidths) + +{ + IShellBrowserImpl *This = (IShellBrowserImpl *)iface; + + TRACE("(%p)\n", This); + + /* Feature not implemented */ + return E_NOTIMPL; +} +/************************************************************************** +* IShellBrowserImpl_OnViewWindowActive +*/ +HRESULT WINAPI IShellBrowserImpl_OnViewWindowActive(IShellBrowser *iface, + IShellView *ppshv) + +{ + IShellBrowserImpl *This = (IShellBrowserImpl *)iface; + + TRACE("(%p)\n", This); + + /* Feature not implemented */ + return E_NOTIMPL; +} +/************************************************************************** +* IShellBrowserImpl_QueryActiveShellView +*/ +HRESULT WINAPI IShellBrowserImpl_QueryActiveShellView(IShellBrowser *iface, + IShellView **ppshv) + +{ + IShellBrowserImpl *This = (IShellBrowserImpl *)iface; + + FileOpenDlgInfos *fodInfos; + + TRACE("(%p)\n", This); + + fodInfos = (FileOpenDlgInfos *) GetPropA(This->hwndOwner,FileOpenDlgInfosStr); + + if(!(*ppshv = fodInfos->Shell.FOIShellView)) + { + return E_FAIL; + } + IShellView_AddRef(fodInfos->Shell.FOIShellView); + return NOERROR; +} +/************************************************************************** +* IShellBrowserImpl_RemoveMenusSB +*/ +HRESULT WINAPI IShellBrowserImpl_RemoveMenusSB(IShellBrowser *iface, + HMENU hmenuShared) + +{ + IShellBrowserImpl *This = (IShellBrowserImpl *)iface; + + TRACE("(%p)\n", This); + + /* Feature not implemented */ + return E_NOTIMPL; +} +/************************************************************************** +* IShellBrowserImpl_SendControlMsg +*/ +HRESULT WINAPI IShellBrowserImpl_SendControlMsg(IShellBrowser *iface, + UINT id, + UINT uMsg, + WPARAM wParam, + LPARAM lParam, + LRESULT *pret) + +{ + IShellBrowserImpl *This = (IShellBrowserImpl *)iface; + LRESULT lres; + + TRACE("(%p)->(0x%08x 0x%08x 0x%08x 0x%08lx %p)\n", This, id, uMsg, wParam, lParam, pret); + + switch (id) + { + case FCW_TOOLBAR: + lres = SendDlgItemMessageA( This->hwndOwner, IDC_TOOLBAR, uMsg, wParam, lParam); + break; + default: + FIXME("ctrl id: %x\n", id); + return E_NOTIMPL; + } + if (pret) *pret = lres; + return S_OK; +} +/************************************************************************** +* IShellBrowserImpl_SetMenuSB +*/ +HRESULT WINAPI IShellBrowserImpl_SetMenuSB(IShellBrowser *iface, + HMENU hmenuShared, + HOLEMENU holemenuReserved, + HWND hwndActiveObject) + +{ + IShellBrowserImpl *This = (IShellBrowserImpl *)iface; + + TRACE("(%p)\n", This); + + /* Feature not implemented */ + return E_NOTIMPL; +} +/************************************************************************** +* IShellBrowserImpl_SetStatusTextSB +*/ +HRESULT WINAPI IShellBrowserImpl_SetStatusTextSB(IShellBrowser *iface, + LPCOLESTR lpszStatusText) + +{ + IShellBrowserImpl *This = (IShellBrowserImpl *)iface; + + TRACE("(%p)\n", This); + + /* Feature not implemented */ + return E_NOTIMPL; +} +/************************************************************************** +* IShellBrowserImpl_SetToolbarItems +*/ +HRESULT WINAPI IShellBrowserImpl_SetToolbarItems(IShellBrowser *iface, + LPTBBUTTON lpButtons, + UINT nButtons, + UINT uFlags) + +{ + IShellBrowserImpl *This = (IShellBrowserImpl *)iface; + + TRACE("(%p)\n", This); + + /* Feature not implemented */ + return E_NOTIMPL; +} +/************************************************************************** +* IShellBrowserImpl_TranslateAcceleratorSB +*/ +HRESULT WINAPI IShellBrowserImpl_TranslateAcceleratorSB(IShellBrowser *iface, + LPMSG lpmsg, + WORD wID) + +{ + IShellBrowserImpl *This = (IShellBrowserImpl *)iface; + + TRACE("(%p)\n", This); + + /* Feature not implemented */ + return E_NOTIMPL; +} + +static const IShellBrowserVtbl IShellBrowserImpl_Vtbl = +{ + /* IUnknown */ + IShellBrowserImpl_QueryInterface, + IShellBrowserImpl_AddRef, + IShellBrowserImpl_Release, + /* IOleWindow */ + IShellBrowserImpl_GetWindow, + IShellBrowserImpl_ContextSensitiveHelp, + /* IShellBrowser */ + IShellBrowserImpl_InsertMenusSB, + IShellBrowserImpl_SetMenuSB, + IShellBrowserImpl_RemoveMenusSB, + IShellBrowserImpl_SetStatusTextSB, + IShellBrowserImpl_EnableModelessSB, + IShellBrowserImpl_TranslateAcceleratorSB, + IShellBrowserImpl_BrowseObject, + IShellBrowserImpl_GetViewStateStream, + IShellBrowserImpl_GetControlWindow, + IShellBrowserImpl_SendControlMsg, + IShellBrowserImpl_QueryActiveShellView, + IShellBrowserImpl_OnViewWindowActive, + IShellBrowserImpl_SetToolbarItems +}; + + + +/* + * ICommDlgBrowser + */ + +/*************************************************************************** +* IShellBrowserImpl_ICommDlgBrowser_QueryInterface +*/ +HRESULT WINAPI IShellBrowserImpl_ICommDlgBrowser_QueryInterface( + ICommDlgBrowser *iface, + REFIID riid, + LPVOID *ppvObj) +{ + _ICOM_THIS_FromICommDlgBrowser(IShellBrowser,iface); + + TRACE("(%p)\n", This); + + return IShellBrowserImpl_QueryInterface(This,riid,ppvObj); +} + +/************************************************************************** +* IShellBrowserImpl_ICommDlgBrowser_AddRef +*/ +ULONG WINAPI IShellBrowserImpl_ICommDlgBrowser_AddRef(ICommDlgBrowser * iface) +{ + _ICOM_THIS_FromICommDlgBrowser(IShellBrowser,iface); + + TRACE("(%p)\n", This); + + return IShellBrowserImpl_AddRef(This); +} + +/************************************************************************** +* IShellBrowserImpl_ICommDlgBrowser_Release +*/ +ULONG WINAPI IShellBrowserImpl_ICommDlgBrowser_Release(ICommDlgBrowser * iface) +{ + _ICOM_THIS_FromICommDlgBrowser(IShellBrowser,iface); + + TRACE("(%p)\n", This); + + return IShellBrowserImpl_Release(This); +} +/************************************************************************** +* IShellBrowserImpl_ICommDlgBrowser_OnDefaultCommand +* +* Called when a user double-clicks in the view or presses the ENTER key +*/ +HRESULT WINAPI IShellBrowserImpl_ICommDlgBrowser_OnDefaultCommand(ICommDlgBrowser *iface, + IShellView *ppshv) +{ + LPITEMIDLIST pidl; + FileOpenDlgInfos *fodInfos; + + _ICOM_THIS_FromICommDlgBrowser(IShellBrowserImpl,iface); + + TRACE("(%p)\n", This); + + fodInfos = (FileOpenDlgInfos *) GetPropA(This->hwndOwner,FileOpenDlgInfosStr); + + /* If the selected object is not a folder, send an IDOK command to parent window */ + if((pidl = GetPidlFromDataObject(fodInfos->Shell.FOIDataObject, 1))) + { + HRESULT hRes; + + ULONG ulAttr = SFGAO_FOLDER | SFGAO_HASSUBFOLDER; + IShellFolder_GetAttributesOf(fodInfos->Shell.FOIShellFolder, 1, (LPCITEMIDLIST *)&pidl, &ulAttr); + if (ulAttr & (SFGAO_FOLDER | SFGAO_HASSUBFOLDER) ) + { + hRes = IShellBrowser_BrowseObject((IShellBrowser *)This,pidl,SBSP_RELATIVE); + SendCustomDlgNotificationMessage(This->hwndOwner, CDN_FOLDERCHANGE); + } + else + { + /* Tell the dialog that the user selected a file */ + PostMessageA(This->hwndOwner, WM_COMMAND, IDOK, 0L); + hRes = S_OK; + } + + /* Free memory used by pidl */ + COMDLG32_SHFree((LPVOID)pidl); + + return hRes; + } + + return E_FAIL; +} + +/************************************************************************** +* IShellBrowserImpl_ICommDlgBrowser_OnStateChange +*/ +HRESULT WINAPI IShellBrowserImpl_ICommDlgBrowser_OnStateChange(ICommDlgBrowser *iface, + IShellView *ppshv, + ULONG uChange) +{ + + _ICOM_THIS_FromICommDlgBrowser(IShellBrowserImpl,iface); + + TRACE("(%p shv=%p)\n", This, ppshv); + + switch (uChange) + { + case CDBOSC_SETFOCUS: + /* FIXME: Reset the default button. + This should be taken care of by defdlg. If control + other than button receives focus the default button + should be restored. */ + SendMessageA(This->hwndOwner, DM_SETDEFID, IDOK, 0); + + break; + case CDBOSC_KILLFOCUS: + { + FileOpenDlgInfos *fodInfos = (FileOpenDlgInfos *) GetPropA(This->hwndOwner,FileOpenDlgInfosStr); + if(fodInfos->DlgInfos.dwDlgProp & FODPROP_SAVEDLG) + SetDlgItemTextA(fodInfos->ShellInfos.hwndOwner,IDOK,"&Save"); + } + break; + case CDBOSC_SELCHANGE: + return IShellBrowserImpl_ICommDlgBrowser_OnSelChange(iface,ppshv); + case CDBOSC_RENAME: + /* nothing to do */ + break; + } + + return NOERROR; +} + +/************************************************************************** +* IShellBrowserImpl_ICommDlgBrowser_IncludeObject +*/ +HRESULT WINAPI IShellBrowserImpl_ICommDlgBrowser_IncludeObject(ICommDlgBrowser *iface, + IShellView * ppshv, + LPCITEMIDLIST pidl) +{ + FileOpenDlgInfos *fodInfos; + ULONG ulAttr; + STRRET str; + WCHAR szPathW[MAX_PATH]; + + _ICOM_THIS_FromICommDlgBrowser(IShellBrowserImpl,iface); + + TRACE("(%p)\n", This); + + fodInfos = (FileOpenDlgInfos *) GetPropA(This->hwndOwner,FileOpenDlgInfosStr); + + ulAttr = SFGAO_HIDDEN | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_FILESYSANCESTOR | SFGAO_LINK; + IShellFolder_GetAttributesOf(fodInfos->Shell.FOIShellFolder, 1, &pidl, &ulAttr); + + if( (ulAttr & SFGAO_HIDDEN) /* hidden */ + | !(ulAttr & (SFGAO_FILESYSTEM | SFGAO_FILESYSANCESTOR))) /* special folder */ + return S_FALSE; + + /* always include directories and links */ + if(ulAttr & (SFGAO_FOLDER | SFGAO_LINK)) + return S_OK; + + /* Check if there is a mask to apply if not */ + if(!fodInfos->ShellInfos.lpstrCurrentFilter || !lstrlenW(fodInfos->ShellInfos.lpstrCurrentFilter)) + return S_OK; + + if (SUCCEEDED(IShellFolder_GetDisplayNameOf(fodInfos->Shell.FOIShellFolder, pidl, SHGDN_INFOLDER | SHGDN_FORPARSING, &str))) + { + if (SUCCEEDED(COMDLG32_StrRetToStrNW(szPathW, MAX_PATH, &str, pidl))) + { + if (PathMatchSpecW(szPathW, fodInfos->ShellInfos.lpstrCurrentFilter)) + return S_OK; + } + } + return S_FALSE; + +} + +/************************************************************************** +* IShellBrowserImpl_ICommDlgBrowser_OnSelChange +*/ +HRESULT IShellBrowserImpl_ICommDlgBrowser_OnSelChange(ICommDlgBrowser *iface, IShellView *ppshv) +{ + FileOpenDlgInfos *fodInfos; + + _ICOM_THIS_FromICommDlgBrowser(IShellBrowserImpl,iface); + + fodInfos = (FileOpenDlgInfos *) GetPropA(This->hwndOwner,FileOpenDlgInfosStr); + TRACE("(%p do=%p view=%p)\n", This, fodInfos->Shell.FOIDataObject, fodInfos->Shell.FOIShellView); + + /* release old selections */ + if (fodInfos->Shell.FOIDataObject) + IDataObject_Release(fodInfos->Shell.FOIDataObject); + + /* get a new DataObject from the ShellView */ + if(FAILED(IShellView_GetItemObject(fodInfos->Shell.FOIShellView, SVGIO_SELECTION, + &IID_IDataObject, (LPVOID*)&fodInfos->Shell.FOIDataObject))) + return E_FAIL; + + FILEDLG95_FILENAME_FillFromSelection(This->hwndOwner); + + SendCustomDlgNotificationMessage(This->hwndOwner, CDN_SELCHANGE); + return S_OK; +} + +static const ICommDlgBrowserVtbl IShellBrowserImpl_ICommDlgBrowser_Vtbl = +{ + /* IUnknown */ + IShellBrowserImpl_ICommDlgBrowser_QueryInterface, + IShellBrowserImpl_ICommDlgBrowser_AddRef, + IShellBrowserImpl_ICommDlgBrowser_Release, + /* ICommDlgBrowser */ + IShellBrowserImpl_ICommDlgBrowser_OnDefaultCommand, + IShellBrowserImpl_ICommDlgBrowser_OnStateChange, + IShellBrowserImpl_ICommDlgBrowser_IncludeObject +}; + + + + +/* + * IServiceProvider + */ + +/*************************************************************************** +* IShellBrowserImpl_IServiceProvider_QueryInterface +*/ +HRESULT WINAPI IShellBrowserImpl_IServiceProvider_QueryInterface( + IServiceProvider *iface, + REFIID riid, + LPVOID *ppvObj) +{ + _ICOM_THIS_FromIServiceProvider(IShellBrowser,iface); + + FIXME("(%p)\n", This); + + return IShellBrowserImpl_QueryInterface(This,riid,ppvObj); +} + +/************************************************************************** +* IShellBrowserImpl_IServiceProvider_AddRef +*/ +ULONG WINAPI IShellBrowserImpl_IServiceProvider_AddRef(IServiceProvider * iface) +{ + _ICOM_THIS_FromIServiceProvider(IShellBrowser,iface); + + FIXME("(%p)\n", This); + + return IShellBrowserImpl_AddRef(This); +} + +/************************************************************************** +* IShellBrowserImpl_IServiceProvider_Release +*/ +ULONG WINAPI IShellBrowserImpl_IServiceProvider_Release(IServiceProvider * iface) +{ + _ICOM_THIS_FromIServiceProvider(IShellBrowser,iface); + + FIXME("(%p)\n", This); + + return IShellBrowserImpl_Release(This); +} + +/************************************************************************** +* IShellBrowserImpl_IServiceProvider_Release +* +* NOTES +* the w2k shellview asks for (guidService = SID_STopLevelBrowser, +* riid = IShellBrowser) to call SendControlMsg (). +* +* FIXME +* this is a hack! +*/ + +HRESULT WINAPI IShellBrowserImpl_IServiceProvider_QueryService( + IServiceProvider * iface, + REFGUID guidService, + REFIID riid, + void** ppv) +{ + _ICOM_THIS_FromIServiceProvider(IShellBrowser,iface); + + FIXME("(%p)\n\t%s\n\t%s\n", This,debugstr_guid(guidService), debugstr_guid(riid) ); + + *ppv = NULL; + if(guidService && IsEqualIID(guidService, &SID_STopLevelBrowser)) + { + return IShellBrowserImpl_QueryInterface(This,riid,ppv); + } + FIXME("(%p) unknown interface requested\n", This); + return E_NOINTERFACE; + +} + +static const IServiceProviderVtbl IShellBrowserImpl_IServiceProvider_Vtbl = +{ + /* IUnknown */ + IShellBrowserImpl_IServiceProvider_QueryInterface, + IShellBrowserImpl_IServiceProvider_AddRef, + IShellBrowserImpl_IServiceProvider_Release, + /* IServiceProvider */ + IShellBrowserImpl_IServiceProvider_QueryService +}; diff --git a/reactos/lib/comdlg32/filedlgbrowser.h b/reactos/lib/comdlg32/filedlgbrowser.h index f537045c65f..4e2a30aa161 100644 --- a/reactos/lib/comdlg32/filedlgbrowser.h +++ b/reactos/lib/comdlg32/filedlgbrowser.h @@ -1,165 +1,165 @@ -/* - * Implementation of IShellBrowser for the File Open common dialog - * - * Copyright 1999 Francois Boisvert - * Copyright 1999, 2000 Juergen Schmied - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef SHBROWSER_H -#define SHBROWSER_H - -#ifndef RC_INVOKED -#include -#endif - -#define COM_NO_WINDOWS_H -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "shlobj.h" -#include "objbase.h" -#include "commdlg.h" - -/*********************************************************************** - * Defines and global variables - */ -#define _ICommDlgBrowser_Offset ((int)(&(((IShellBrowserImpl*)0)->lpVtblCommDlgBrowser))) -#define _ICOM_THIS_FromICommDlgBrowser(class, name) class* This = (class*)(((char*)name)-_ICommDlgBrowser_Offset); - -#define _IServiceProvider_Offset ((int)(&(((IShellBrowserImpl*)0)->lpVtblServiceProvider))) -#define _ICOM_THIS_FromIServiceProvider(class, name) class* This = (class*)(((char*)name)-_IServiceProvider_Offset); - -/* dialog internal property */ - -#define FODPROP_SAVEDLG 0x0001 /* File dialog is a Save file dialog */ -#define FODPROP_USEVIEW 0x0002 /* Indicates the user selection must be taken - from the IShellView */ - -/*********************************************************************** - * Data structure - */ - - -typedef struct -{ - LPOPENFILENAMEW ofnInfos; - BOOL unicode; - LPWSTR initdir; - LPWSTR filename; - LPCWSTR title; - LPCWSTR defext; - LPCWSTR filter; - LPCWSTR customfilter; - struct { - IShellBrowser *FOIShellBrowser; - IShellFolder *FOIShellFolder; - IShellView *FOIShellView; - IDataObject *FOIDataObject; - } Shell; - - struct { - HWND hwndOwner; - HWND hwndView; - FOLDERSETTINGS folderSettings; - LPITEMIDLIST pidlAbsCurrent; - LPWSTR lpstrCurrentFilter; - } ShellInfos; - - struct { - HWND hwndFileTypeCB; - HWND hwndLookInCB; - HWND hwndFileName; - HWND hwndTB; - HWND hwndCustomDlg; - DWORD dwDlgProp; - } DlgInfos; - - struct { - UINT fileokstring; - UINT lbselchstring; - UINT helpmsgstring; - UINT sharevistring; - } HookMsg; - -} FileOpenDlgInfos; - -/*********************************************************************** - * Control ID's - */ -#define IDS_ABOUTBOX 101 -#define IDS_DOCUMENTFOLDERS 102 -#define IDS_PERSONAL 103 -#define IDS_FAVORITES 104 -#define IDS_PATH 105 -#define IDS_DESKTOP 106 - -#define IDS_FONTS 108 -#define IDS_MYCOMPUTER 110 -#define IDS_SYSTEMFOLDERS 112 -#define IDS_LOCALHARDRIVES 113 -#define IDS_FILENOTFOUND 114 -#define IDS_VERIFYFILE 115 -#define IDS_CREATEFILE 116 -#define IDS_CREATEFOLDER_DENIED 117 -#define IDS_FILEOPEN_CAPTION 118 -#define IDS_OVERWRITEFILE 119 -#define IDS_INVALID_FILENAME_TITLE 120 -#define IDS_INVALID_FILENAME 121 -#define IDS_PATHNOTEXISTING 122 -#define IDS_FILENOTEXISTING 123 - -/* File Dialog Tooltips string IDs */ - -#define IDS_UPFOLDER 150 -#define IDS_NEWFOLDER 151 -#define IDS_LISTVIEW 152 -#define IDS_REPORTVIEW 153 -#define IDS_TODESKTOP 154 - -#define IDC_OPENREADONLY chx1 - -#define IDC_TOOLBARSTATIC stc1 -#define IDC_FILETYPESTATIC stc2 -#define IDC_FILENAMESTATIC stc3 -#define IDC_LOOKINSTATIC stc4 - -#define IDC_SHELLSTATIC lst1 - -#define IDC_FILETYPE cmb1 -#define IDC_LOOKIN cmb2 - -#define IDC_FILENAME edt1 - -#define IDC_TOOLBAR 1 - -/*********************************************************************** - * Prototypes for the methods of the IShellBrowserImpl class - */ -/* Constructor */ -IShellBrowser * IShellBrowserImpl_Construct(HWND hwndOwner); - - -LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex); -UINT GetNumSelected(IDataObject *doSelected); - -/* pidl handling */ -BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl); - -/* Functions used by the EDIT box */ -void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd); - -#endif /*SHBROWSER_H*/ +/* + * Implementation of IShellBrowser for the File Open common dialog + * + * Copyright 1999 Francois Boisvert + * Copyright 1999, 2000 Juergen Schmied + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef SHBROWSER_H +#define SHBROWSER_H + +#ifndef RC_INVOKED +#include +#endif + +#define COM_NO_WINDOWS_H +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "shlobj.h" +#include "objbase.h" +#include "commdlg.h" + +/*********************************************************************** + * Defines and global variables + */ +#define _ICommDlgBrowser_Offset ((int)(&(((IShellBrowserImpl*)0)->lpVtblCommDlgBrowser))) +#define _ICOM_THIS_FromICommDlgBrowser(class, name) class* This = (class*)(((char*)name)-_ICommDlgBrowser_Offset); + +#define _IServiceProvider_Offset ((int)(&(((IShellBrowserImpl*)0)->lpVtblServiceProvider))) +#define _ICOM_THIS_FromIServiceProvider(class, name) class* This = (class*)(((char*)name)-_IServiceProvider_Offset); + +/* dialog internal property */ + +#define FODPROP_SAVEDLG 0x0001 /* File dialog is a Save file dialog */ +#define FODPROP_USEVIEW 0x0002 /* Indicates the user selection must be taken + from the IShellView */ + +/*********************************************************************** + * Data structure + */ + + +typedef struct +{ + LPOPENFILENAMEW ofnInfos; + BOOL unicode; + LPWSTR initdir; + LPWSTR filename; + LPCWSTR title; + LPCWSTR defext; + LPCWSTR filter; + LPCWSTR customfilter; + struct { + IShellBrowser *FOIShellBrowser; + IShellFolder *FOIShellFolder; + IShellView *FOIShellView; + IDataObject *FOIDataObject; + } Shell; + + struct { + HWND hwndOwner; + HWND hwndView; + FOLDERSETTINGS folderSettings; + LPITEMIDLIST pidlAbsCurrent; + LPWSTR lpstrCurrentFilter; + } ShellInfos; + + struct { + HWND hwndFileTypeCB; + HWND hwndLookInCB; + HWND hwndFileName; + HWND hwndTB; + HWND hwndCustomDlg; + DWORD dwDlgProp; + } DlgInfos; + + struct { + UINT fileokstring; + UINT lbselchstring; + UINT helpmsgstring; + UINT sharevistring; + } HookMsg; + +} FileOpenDlgInfos; + +/*********************************************************************** + * Control ID's + */ +#define IDS_ABOUTBOX 101 +#define IDS_DOCUMENTFOLDERS 102 +#define IDS_PERSONAL 103 +#define IDS_FAVORITES 104 +#define IDS_PATH 105 +#define IDS_DESKTOP 106 + +#define IDS_FONTS 108 +#define IDS_MYCOMPUTER 110 +#define IDS_SYSTEMFOLDERS 112 +#define IDS_LOCALHARDRIVES 113 +#define IDS_FILENOTFOUND 114 +#define IDS_VERIFYFILE 115 +#define IDS_CREATEFILE 116 +#define IDS_CREATEFOLDER_DENIED 117 +#define IDS_FILEOPEN_CAPTION 118 +#define IDS_OVERWRITEFILE 119 +#define IDS_INVALID_FILENAME_TITLE 120 +#define IDS_INVALID_FILENAME 121 +#define IDS_PATHNOTEXISTING 122 +#define IDS_FILENOTEXISTING 123 + +/* File Dialog Tooltips string IDs */ + +#define IDS_UPFOLDER 150 +#define IDS_NEWFOLDER 151 +#define IDS_LISTVIEW 152 +#define IDS_REPORTVIEW 153 +#define IDS_TODESKTOP 154 + +#define IDC_OPENREADONLY chx1 + +#define IDC_TOOLBARSTATIC stc1 +#define IDC_FILETYPESTATIC stc2 +#define IDC_FILENAMESTATIC stc3 +#define IDC_LOOKINSTATIC stc4 + +#define IDC_SHELLSTATIC lst1 + +#define IDC_FILETYPE cmb1 +#define IDC_LOOKIN cmb2 + +#define IDC_FILENAME edt1 + +#define IDC_TOOLBAR 1 + +/*********************************************************************** + * Prototypes for the methods of the IShellBrowserImpl class + */ +/* Constructor */ +IShellBrowser * IShellBrowserImpl_Construct(HWND hwndOwner); + + +LPITEMIDLIST GetPidlFromDataObject ( IDataObject *doSelected, UINT nPidlIndex); +UINT GetNumSelected(IDataObject *doSelected); + +/* pidl handling */ +BOOL IsPidlFolder (LPSHELLFOLDER psf, LPCITEMIDLIST pidl); + +/* Functions used by the EDIT box */ +void FILEDLG95_FILENAME_FillFromSelection (HWND hwnd); + +#endif /*SHBROWSER_H*/ diff --git a/reactos/lib/comdlg32/filetitle.c b/reactos/lib/comdlg32/filetitle.c index f2e8bddd030..6d2b9fe6c0b 100644 --- a/reactos/lib/comdlg32/filetitle.c +++ b/reactos/lib/comdlg32/filetitle.c @@ -1,114 +1,114 @@ -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "winreg.h" -#include "winternl.h" -#include "wingdi.h" -#include "winuser.h" -#include "commdlg.h" -#include "cdlg.h" -#include "wine/unicode.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(commdlg); - -/*********************************************************************** - * GetFileTitleA (COMDLG32.@) - * - */ -short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf) -{ - int ret; - UNICODE_STRING strWFile; - LPWSTR lpWTitle; - - RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile); - lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR)); - ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf); - if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL ); - RtlFreeUnicodeString( &strWFile ); - RtlFreeHeap( GetProcessHeap(), 0, lpWTitle ); - return ret; -} - - -/*********************************************************************** - * GetFileTitleW (COMDLG32.@) - * - */ -short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf) -{ - int i, len; - static const WCHAR brkpoint[] = {'*','[',']',0}; - TRACE("(%p %p %d); \n", lpFile, lpTitle, cbBuf); - - if(lpFile == NULL || lpTitle == NULL) - return -1; - - len = strlenW(lpFile); - - if (len == 0) - return -1; - - if(strpbrkW(lpFile, brkpoint)) - return -1; - - len--; - - if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':') - return -1; - - for(i = len; i >= 0; i--) - { - if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':') - { - i++; - break; - } - } - - if(i == -1) - i++; - - TRACE("---> '%s' \n", debugstr_w(&lpFile[i])); - - len = strlenW(lpFile+i)+1; - if(cbBuf < len) - return len; - - strcpyW(lpTitle, &lpFile[i]); - return 0; -} - - -/*********************************************************************** - * GetFileTitle (COMMDLG.27) - */ -short WINAPI GetFileTitle16(LPCSTR lpFile, LPSTR lpTitle, UINT16 cbBuf) -{ - return GetFileTitleA(lpFile, lpTitle, cbBuf); -} +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winreg.h" +#include "winternl.h" +#include "wingdi.h" +#include "winuser.h" +#include "commdlg.h" +#include "cdlg.h" +#include "wine/unicode.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(commdlg); + +/*********************************************************************** + * GetFileTitleA (COMDLG32.@) + * + */ +short WINAPI GetFileTitleA(LPCSTR lpFile, LPSTR lpTitle, WORD cbBuf) +{ + int ret; + UNICODE_STRING strWFile; + LPWSTR lpWTitle; + + RtlCreateUnicodeStringFromAsciiz(&strWFile, lpFile); + lpWTitle = RtlAllocateHeap( GetProcessHeap(), 0, cbBuf*sizeof(WCHAR)); + ret = GetFileTitleW(strWFile.Buffer, lpWTitle, cbBuf); + if (!ret) WideCharToMultiByte( CP_ACP, 0, lpWTitle, -1, lpTitle, cbBuf, NULL, NULL ); + RtlFreeUnicodeString( &strWFile ); + RtlFreeHeap( GetProcessHeap(), 0, lpWTitle ); + return ret; +} + + +/*********************************************************************** + * GetFileTitleW (COMDLG32.@) + * + */ +short WINAPI GetFileTitleW(LPCWSTR lpFile, LPWSTR lpTitle, WORD cbBuf) +{ + int i, len; + static const WCHAR brkpoint[] = {'*','[',']',0}; + TRACE("(%p %p %d); \n", lpFile, lpTitle, cbBuf); + + if(lpFile == NULL || lpTitle == NULL) + return -1; + + len = strlenW(lpFile); + + if (len == 0) + return -1; + + if(strpbrkW(lpFile, brkpoint)) + return -1; + + len--; + + if(lpFile[len] == '/' || lpFile[len] == '\\' || lpFile[len] == ':') + return -1; + + for(i = len; i >= 0; i--) + { + if (lpFile[i] == '/' || lpFile[i] == '\\' || lpFile[i] == ':') + { + i++; + break; + } + } + + if(i == -1) + i++; + + TRACE("---> '%s' \n", debugstr_w(&lpFile[i])); + + len = strlenW(lpFile+i)+1; + if(cbBuf < len) + return len; + + strcpyW(lpTitle, &lpFile[i]); + return 0; +} + + +/*********************************************************************** + * GetFileTitle (COMMDLG.27) + */ +short WINAPI GetFileTitle16(LPCSTR lpFile, LPSTR lpTitle, UINT16 cbBuf) +{ + return GetFileTitleA(lpFile, lpTitle, cbBuf); +} diff --git a/reactos/lib/comdlg32/finddlg.c b/reactos/lib/comdlg32/finddlg.c index b59c8414683..712b051ed36 100644 --- a/reactos/lib/comdlg32/finddlg.c +++ b/reactos/lib/comdlg32/finddlg.c @@ -1,496 +1,496 @@ -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "wine/debug.h" -#include "cderr.h" - -WINE_DEFAULT_DEBUG_CHANNEL(commdlg); - -#include "cdlg.h" -#include "cdlg16.h" - -struct FRPRIVATE -{ - HANDLE16 hDlgTmpl16; /* handle for resource 16 */ - HANDLE16 hResource16; /* handle for allocated resource 16 */ - HANDLE16 hGlobal16; /* 16 bits mem block (resources) */ - LPCVOID template; /* template for 32 bits resource */ - BOOL find; /* TRUE if find dialog, FALSE if replace dialog */ - FINDREPLACE16 *fr16; -}; - -#define LFRPRIVATE struct FRPRIVATE * - -BOOL16 CALLBACK FindTextDlgProc16(HWND16 hWnd, UINT16 wMsg, WPARAM16 wParam, - LPARAM lParam); -BOOL16 CALLBACK ReplaceTextDlgProc16(HWND16 hWnd, UINT16 wMsg, WPARAM16 wParam, - LPARAM lParam); - -/*********************************************************************** - * FINDDLG_Get16BitsTemplate [internal] - * - * Get a template (FALSE if failure) when 16 bits dialogs are used - * by a 16 bits application - * FIXME : no test was done for the user-provided template cases - */ -BOOL FINDDLG_Get16BitsTemplate(LFRPRIVATE lfr) -{ - LPFINDREPLACE16 fr16 = lfr->fr16; - - if (fr16->Flags & FR_ENABLETEMPLATEHANDLE) - { - lfr->template = GlobalLock16(fr16->hInstance); - if (!lfr->template) - { - COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE); - return FALSE; - } - } - else if (fr16->Flags & FR_ENABLETEMPLATE) - { - HANDLE16 hResInfo; - if (!(hResInfo = FindResource16(fr16->hInstance, - MapSL(fr16->lpTemplateName), - (LPSTR)RT_DIALOG))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); - return FALSE; - } - if (!(lfr->hDlgTmpl16 = LoadResource16( fr16->hInstance, hResInfo ))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - lfr->hResource16 = lfr->hDlgTmpl16; - lfr->template = LockResource16(lfr->hResource16); - if (!lfr->template) - { - FreeResource16(lfr->hResource16); - COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE); - return FALSE; - } - } - else - { /* get resource from (32 bits) own Wine resource; convert it to 16 */ - HRSRC hResInfo; - HGLOBAL hDlgTmpl32; - LPCVOID template32; - DWORD size; - HGLOBAL16 hGlobal16; - - if (!(hResInfo = FindResourceA(COMDLG32_hInstance, - lfr->find ? - MAKEINTRESOURCEA(FINDDLGORD):MAKEINTRESOURCEA(REPLACEDLGORD), - (LPSTR)RT_DIALOG))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); - return FALSE; - } - if (!(hDlgTmpl32 = LoadResource(COMDLG32_hInstance, hResInfo )) || - !(template32 = LockResource( hDlgTmpl32 ))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - size = SizeofResource(COMDLG32_hInstance, hResInfo); - hGlobal16 = GlobalAlloc16(0, size); - if (!hGlobal16) - { - COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE); - ERR("alloc failure for %ld bytes\n", size); - return FALSE; - } - lfr->template = GlobalLock16(hGlobal16); - if (!lfr->template) - { - COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE); - ERR("global lock failure for %x handle\n", hGlobal16); - GlobalFree16(hGlobal16); - return FALSE; - } - ConvertDialog32To16((LPVOID)template32, size, (LPVOID)lfr->template); - lfr->hDlgTmpl16 = hGlobal16; - lfr->hGlobal16 = hGlobal16; - } - return TRUE; -} - - -/*********************************************************************** - * FINDDLG_FreeResources [internal] - * - * Free resources allocated - */ -void FINDDLG_FreeResources(LFRPRIVATE lfr) -{ - /* free resources */ - if (lfr->fr16->Flags & FR_ENABLETEMPLATEHANDLE) - GlobalUnlock16(lfr->fr16->hInstance); - if (lfr->hResource16) - { - GlobalUnlock16(lfr->hResource16); - FreeResource16(lfr->hResource16); - } - if (lfr->hGlobal16) - { - GlobalUnlock16(lfr->hGlobal16); - GlobalFree16(lfr->hGlobal16); - } -} - -/*********************************************************************** - * FindText (COMMDLG.11) - */ -HWND16 WINAPI FindText16( SEGPTR find ) -{ - HANDLE16 hInst; - HWND16 ret = 0; - FARPROC16 ptr; - LFRPRIVATE lfr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct FRPRIVATE)); - - if (!lfr) return 0; - lfr->fr16 = MapSL(find); - lfr->find = TRUE; - if (FINDDLG_Get16BitsTemplate(lfr)) - { - hInst = GetWindowLongPtrA( HWND_32(lfr->fr16->hwndOwner), GWLP_HINSTANCE); - ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 13); - ret = CreateDialogIndirectParam16( hInst, lfr->template, - lfr->fr16->hwndOwner, (DLGPROC16) ptr, find); - FINDDLG_FreeResources(lfr); - } - HeapFree(GetProcessHeap(), 0, lfr); - return ret; -} - - -/*********************************************************************** - * ReplaceText (COMMDLG.12) - */ -HWND16 WINAPI ReplaceText16( SEGPTR find ) -{ - HANDLE16 hInst; - HWND16 ret = 0; - FARPROC16 ptr; - LFRPRIVATE lfr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct FRPRIVATE)); - - if (!lfr) return 0; - /* - * FIXME : We should do error checking on the lpFind structure here - * and make CommDlgExtendedError() return the error condition. - */ - lfr->fr16 = MapSL(find); - lfr->find = FALSE; - if (FINDDLG_Get16BitsTemplate(lfr)) - { - hInst = GetWindowLongPtrA( HWND_32(lfr->fr16->hwndOwner), GWLP_HINSTANCE); - ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 14); - ret = CreateDialogIndirectParam16( hInst, lfr->template, - lfr->fr16->hwndOwner, (DLGPROC16) ptr, find); - - FINDDLG_FreeResources(lfr); - } - HeapFree(GetProcessHeap(), 0, lfr); - return ret; -} - - -/*********************************************************************** - * FINDDLG_WMInitDialog [internal] - */ -static LRESULT FINDDLG_WMInitDialog(HWND hWnd, LPARAM lParam, LPDWORD lpFlags, - LPSTR lpstrFindWhat, BOOL fUnicode) -{ - SetWindowLongPtrW(hWnd, DWLP_USER, lParam); - *lpFlags &= ~(FR_FINDNEXT | FR_REPLACE | FR_REPLACEALL | FR_DIALOGTERM); - /* - * 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. - */ - if (fUnicode) SetDlgItemTextW(hWnd, edt1, (LPWSTR)lpstrFindWhat); - else SetDlgItemTextA(hWnd, edt1, 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); - } - ShowWindow(hWnd, SW_SHOWNORMAL); - return TRUE; -} - - -/*********************************************************************** - * FINDDLG_WMCommand [internal] - */ -static LRESULT FINDDLG_WMCommand(HWND hWnd, WPARAM wParam, - HWND hwndOwner, LPDWORD lpFlags, - LPSTR lpstrFindWhat, WORD wFindWhatLen, - BOOL fUnicode) -{ - int uFindReplaceMessage = RegisterWindowMessageA( FINDMSGSTRINGA ); - int uHelpMessage = RegisterWindowMessageA( HELPMSGSTRINGA ); - - switch (wParam) { - case IDOK: - if (fUnicode) - GetDlgItemTextW(hWnd, edt1, (LPWSTR)lpstrFindWhat, wFindWhatLen/2); - else 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; -} - - -/*********************************************************************** - * FindTextDlgProc (COMMDLG.13) - */ -BOOL16 CALLBACK FindTextDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam, - LPARAM lParam) -{ - HWND hWnd = HWND_32(hWnd16); - LPFINDREPLACE16 lpfr; - switch (wMsg) { - case WM_INITDIALOG: - lpfr=MapSL(lParam); - return FINDDLG_WMInitDialog(hWnd, lParam, &(lpfr->Flags), - MapSL(lpfr->lpstrFindWhat), FALSE); - case WM_COMMAND: - lpfr=MapSL(GetWindowLongPtrW(hWnd, DWLP_USER)); - return FINDDLG_WMCommand(hWnd, wParam, HWND_32(lpfr->hwndOwner), - &lpfr->Flags, MapSL(lpfr->lpstrFindWhat), - lpfr->wFindWhatLen, FALSE); - } - return FALSE; -} - - -/*********************************************************************** - * REPLACEDLG_WMInitDialog [internal] - */ -static LRESULT REPLACEDLG_WMInitDialog(HWND hWnd, LPARAM lParam, - LPDWORD lpFlags, LPSTR lpstrFindWhat, - LPSTR lpstrReplaceWith, BOOL fUnicode) -{ - SetWindowLongPtrW(hWnd, DWLP_USER, lParam); - *lpFlags &= ~(FR_FINDNEXT | FR_REPLACE | FR_REPLACEALL | FR_DIALOGTERM); - /* - * FIXME : If the initial FindWhat string is empty, we should disable the FinNext / - * Replace / ReplaceAll buttons. Only after typing some text, the buttons should be - * enabled. - */ - if (fUnicode) - { - SetDlgItemTextW(hWnd, edt1, (LPWSTR)lpstrFindWhat); - SetDlgItemTextW(hWnd, edt2, (LPWSTR)lpstrReplaceWith); - } else - { - SetDlgItemTextA(hWnd, edt1, lpstrFindWhat); - SetDlgItemTextA(hWnd, edt2, 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); - } - ShowWindow(hWnd, SW_SHOWNORMAL); - return TRUE; -} - - -/*********************************************************************** - * REPLACEDLG_WMCommand [internal] - */ -static LRESULT REPLACEDLG_WMCommand(HWND hWnd, WPARAM16 wParam, - HWND hwndOwner, LPDWORD lpFlags, - LPSTR lpstrFindWhat, WORD wFindWhatLen, - LPSTR lpstrReplaceWith, WORD wReplaceWithLen, - BOOL fUnicode) -{ - int uFindReplaceMessage = RegisterWindowMessageA( FINDMSGSTRINGA ); - int uHelpMessage = RegisterWindowMessageA( HELPMSGSTRINGA ); - - switch (wParam) { - case IDOK: - if (fUnicode) - { - GetDlgItemTextW(hWnd, edt1, (LPWSTR)lpstrFindWhat, wFindWhatLen/2); - GetDlgItemTextW(hWnd, edt2, (LPWSTR)lpstrReplaceWith, wReplaceWithLen/2); - } else - { - 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: - if (fUnicode) - { - GetDlgItemTextW(hWnd, edt1, (LPWSTR)lpstrFindWhat, wFindWhatLen/2); - GetDlgItemTextW(hWnd, edt2, (LPWSTR)lpstrReplaceWith, wReplaceWithLen/2); - } else - { - 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: - if (fUnicode) - { - GetDlgItemTextW(hWnd, edt1, (LPWSTR)lpstrFindWhat, wFindWhatLen/2); - GetDlgItemTextW(hWnd, edt2, (LPWSTR)lpstrReplaceWith, wReplaceWithLen/2); - } else - { - 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; -} - - -/*********************************************************************** - * ReplaceTextDlgProc (COMMDLG.14) - */ -BOOL16 CALLBACK ReplaceTextDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam, - LPARAM lParam) -{ - HWND hWnd = HWND_32(hWnd16); - LPFINDREPLACE16 lpfr; - switch (wMsg) { - case WM_INITDIALOG: - lpfr=MapSL(lParam); - return REPLACEDLG_WMInitDialog(hWnd, lParam, &lpfr->Flags, - MapSL(lpfr->lpstrFindWhat), - MapSL(lpfr->lpstrReplaceWith), FALSE); - case WM_COMMAND: - lpfr=MapSL(GetWindowLongPtrW(hWnd, DWLP_USER)); - return REPLACEDLG_WMCommand(hWnd, wParam, HWND_32(lpfr->hwndOwner), - &lpfr->Flags, MapSL(lpfr->lpstrFindWhat), - lpfr->wFindWhatLen, MapSL(lpfr->lpstrReplaceWith), - lpfr->wReplaceWithLen, FALSE); - } - return FALSE; -} +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "wine/debug.h" +#include "cderr.h" + +WINE_DEFAULT_DEBUG_CHANNEL(commdlg); + +#include "cdlg.h" +#include "cdlg16.h" + +struct FRPRIVATE +{ + HANDLE16 hDlgTmpl16; /* handle for resource 16 */ + HANDLE16 hResource16; /* handle for allocated resource 16 */ + HANDLE16 hGlobal16; /* 16 bits mem block (resources) */ + LPCVOID template; /* template for 32 bits resource */ + BOOL find; /* TRUE if find dialog, FALSE if replace dialog */ + FINDREPLACE16 *fr16; +}; + +#define LFRPRIVATE struct FRPRIVATE * + +BOOL16 CALLBACK FindTextDlgProc16(HWND16 hWnd, UINT16 wMsg, WPARAM16 wParam, + LPARAM lParam); +BOOL16 CALLBACK ReplaceTextDlgProc16(HWND16 hWnd, UINT16 wMsg, WPARAM16 wParam, + LPARAM lParam); + +/*********************************************************************** + * FINDDLG_Get16BitsTemplate [internal] + * + * Get a template (FALSE if failure) when 16 bits dialogs are used + * by a 16 bits application + * FIXME : no test was done for the user-provided template cases + */ +BOOL FINDDLG_Get16BitsTemplate(LFRPRIVATE lfr) +{ + LPFINDREPLACE16 fr16 = lfr->fr16; + + if (fr16->Flags & FR_ENABLETEMPLATEHANDLE) + { + lfr->template = GlobalLock16(fr16->hInstance); + if (!lfr->template) + { + COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE); + return FALSE; + } + } + else if (fr16->Flags & FR_ENABLETEMPLATE) + { + HANDLE16 hResInfo; + if (!(hResInfo = FindResource16(fr16->hInstance, + MapSL(fr16->lpTemplateName), + (LPSTR)RT_DIALOG))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); + return FALSE; + } + if (!(lfr->hDlgTmpl16 = LoadResource16( fr16->hInstance, hResInfo ))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + lfr->hResource16 = lfr->hDlgTmpl16; + lfr->template = LockResource16(lfr->hResource16); + if (!lfr->template) + { + FreeResource16(lfr->hResource16); + COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE); + return FALSE; + } + } + else + { /* get resource from (32 bits) own Wine resource; convert it to 16 */ + HRSRC hResInfo; + HGLOBAL hDlgTmpl32; + LPCVOID template32; + DWORD size; + HGLOBAL16 hGlobal16; + + if (!(hResInfo = FindResourceA(COMDLG32_hInstance, + lfr->find ? + MAKEINTRESOURCEA(FINDDLGORD):MAKEINTRESOURCEA(REPLACEDLGORD), + (LPSTR)RT_DIALOG))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); + return FALSE; + } + if (!(hDlgTmpl32 = LoadResource(COMDLG32_hInstance, hResInfo )) || + !(template32 = LockResource( hDlgTmpl32 ))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + size = SizeofResource(COMDLG32_hInstance, hResInfo); + hGlobal16 = GlobalAlloc16(0, size); + if (!hGlobal16) + { + COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE); + ERR("alloc failure for %ld bytes\n", size); + return FALSE; + } + lfr->template = GlobalLock16(hGlobal16); + if (!lfr->template) + { + COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE); + ERR("global lock failure for %x handle\n", hGlobal16); + GlobalFree16(hGlobal16); + return FALSE; + } + ConvertDialog32To16((LPVOID)template32, size, (LPVOID)lfr->template); + lfr->hDlgTmpl16 = hGlobal16; + lfr->hGlobal16 = hGlobal16; + } + return TRUE; +} + + +/*********************************************************************** + * FINDDLG_FreeResources [internal] + * + * Free resources allocated + */ +void FINDDLG_FreeResources(LFRPRIVATE lfr) +{ + /* free resources */ + if (lfr->fr16->Flags & FR_ENABLETEMPLATEHANDLE) + GlobalUnlock16(lfr->fr16->hInstance); + if (lfr->hResource16) + { + GlobalUnlock16(lfr->hResource16); + FreeResource16(lfr->hResource16); + } + if (lfr->hGlobal16) + { + GlobalUnlock16(lfr->hGlobal16); + GlobalFree16(lfr->hGlobal16); + } +} + +/*********************************************************************** + * FindText (COMMDLG.11) + */ +HWND16 WINAPI FindText16( SEGPTR find ) +{ + HANDLE16 hInst; + HWND16 ret = 0; + FARPROC16 ptr; + LFRPRIVATE lfr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct FRPRIVATE)); + + if (!lfr) return 0; + lfr->fr16 = MapSL(find); + lfr->find = TRUE; + if (FINDDLG_Get16BitsTemplate(lfr)) + { + hInst = GetWindowLongPtrA( HWND_32(lfr->fr16->hwndOwner), GWLP_HINSTANCE); + ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 13); + ret = CreateDialogIndirectParam16( hInst, lfr->template, + lfr->fr16->hwndOwner, (DLGPROC16) ptr, find); + FINDDLG_FreeResources(lfr); + } + HeapFree(GetProcessHeap(), 0, lfr); + return ret; +} + + +/*********************************************************************** + * ReplaceText (COMMDLG.12) + */ +HWND16 WINAPI ReplaceText16( SEGPTR find ) +{ + HANDLE16 hInst; + HWND16 ret = 0; + FARPROC16 ptr; + LFRPRIVATE lfr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct FRPRIVATE)); + + if (!lfr) return 0; + /* + * FIXME : We should do error checking on the lpFind structure here + * and make CommDlgExtendedError() return the error condition. + */ + lfr->fr16 = MapSL(find); + lfr->find = FALSE; + if (FINDDLG_Get16BitsTemplate(lfr)) + { + hInst = GetWindowLongPtrA( HWND_32(lfr->fr16->hwndOwner), GWLP_HINSTANCE); + ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 14); + ret = CreateDialogIndirectParam16( hInst, lfr->template, + lfr->fr16->hwndOwner, (DLGPROC16) ptr, find); + + FINDDLG_FreeResources(lfr); + } + HeapFree(GetProcessHeap(), 0, lfr); + return ret; +} + + +/*********************************************************************** + * FINDDLG_WMInitDialog [internal] + */ +static LRESULT FINDDLG_WMInitDialog(HWND hWnd, LPARAM lParam, LPDWORD lpFlags, + LPSTR lpstrFindWhat, BOOL fUnicode) +{ + SetWindowLongPtrW(hWnd, DWLP_USER, lParam); + *lpFlags &= ~(FR_FINDNEXT | FR_REPLACE | FR_REPLACEALL | FR_DIALOGTERM); + /* + * 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. + */ + if (fUnicode) SetDlgItemTextW(hWnd, edt1, (LPWSTR)lpstrFindWhat); + else SetDlgItemTextA(hWnd, edt1, 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); + } + ShowWindow(hWnd, SW_SHOWNORMAL); + return TRUE; +} + + +/*********************************************************************** + * FINDDLG_WMCommand [internal] + */ +static LRESULT FINDDLG_WMCommand(HWND hWnd, WPARAM wParam, + HWND hwndOwner, LPDWORD lpFlags, + LPSTR lpstrFindWhat, WORD wFindWhatLen, + BOOL fUnicode) +{ + int uFindReplaceMessage = RegisterWindowMessageA( FINDMSGSTRINGA ); + int uHelpMessage = RegisterWindowMessageA( HELPMSGSTRINGA ); + + switch (wParam) { + case IDOK: + if (fUnicode) + GetDlgItemTextW(hWnd, edt1, (LPWSTR)lpstrFindWhat, wFindWhatLen/2); + else 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; +} + + +/*********************************************************************** + * FindTextDlgProc (COMMDLG.13) + */ +BOOL16 CALLBACK FindTextDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam, + LPARAM lParam) +{ + HWND hWnd = HWND_32(hWnd16); + LPFINDREPLACE16 lpfr; + switch (wMsg) { + case WM_INITDIALOG: + lpfr=MapSL(lParam); + return FINDDLG_WMInitDialog(hWnd, lParam, &(lpfr->Flags), + MapSL(lpfr->lpstrFindWhat), FALSE); + case WM_COMMAND: + lpfr=MapSL(GetWindowLongPtrW(hWnd, DWLP_USER)); + return FINDDLG_WMCommand(hWnd, wParam, HWND_32(lpfr->hwndOwner), + &lpfr->Flags, MapSL(lpfr->lpstrFindWhat), + lpfr->wFindWhatLen, FALSE); + } + return FALSE; +} + + +/*********************************************************************** + * REPLACEDLG_WMInitDialog [internal] + */ +static LRESULT REPLACEDLG_WMInitDialog(HWND hWnd, LPARAM lParam, + LPDWORD lpFlags, LPSTR lpstrFindWhat, + LPSTR lpstrReplaceWith, BOOL fUnicode) +{ + SetWindowLongPtrW(hWnd, DWLP_USER, lParam); + *lpFlags &= ~(FR_FINDNEXT | FR_REPLACE | FR_REPLACEALL | FR_DIALOGTERM); + /* + * FIXME : If the initial FindWhat string is empty, we should disable the FinNext / + * Replace / ReplaceAll buttons. Only after typing some text, the buttons should be + * enabled. + */ + if (fUnicode) + { + SetDlgItemTextW(hWnd, edt1, (LPWSTR)lpstrFindWhat); + SetDlgItemTextW(hWnd, edt2, (LPWSTR)lpstrReplaceWith); + } else + { + SetDlgItemTextA(hWnd, edt1, lpstrFindWhat); + SetDlgItemTextA(hWnd, edt2, 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); + } + ShowWindow(hWnd, SW_SHOWNORMAL); + return TRUE; +} + + +/*********************************************************************** + * REPLACEDLG_WMCommand [internal] + */ +static LRESULT REPLACEDLG_WMCommand(HWND hWnd, WPARAM16 wParam, + HWND hwndOwner, LPDWORD lpFlags, + LPSTR lpstrFindWhat, WORD wFindWhatLen, + LPSTR lpstrReplaceWith, WORD wReplaceWithLen, + BOOL fUnicode) +{ + int uFindReplaceMessage = RegisterWindowMessageA( FINDMSGSTRINGA ); + int uHelpMessage = RegisterWindowMessageA( HELPMSGSTRINGA ); + + switch (wParam) { + case IDOK: + if (fUnicode) + { + GetDlgItemTextW(hWnd, edt1, (LPWSTR)lpstrFindWhat, wFindWhatLen/2); + GetDlgItemTextW(hWnd, edt2, (LPWSTR)lpstrReplaceWith, wReplaceWithLen/2); + } else + { + 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: + if (fUnicode) + { + GetDlgItemTextW(hWnd, edt1, (LPWSTR)lpstrFindWhat, wFindWhatLen/2); + GetDlgItemTextW(hWnd, edt2, (LPWSTR)lpstrReplaceWith, wReplaceWithLen/2); + } else + { + 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: + if (fUnicode) + { + GetDlgItemTextW(hWnd, edt1, (LPWSTR)lpstrFindWhat, wFindWhatLen/2); + GetDlgItemTextW(hWnd, edt2, (LPWSTR)lpstrReplaceWith, wReplaceWithLen/2); + } else + { + 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; +} + + +/*********************************************************************** + * ReplaceTextDlgProc (COMMDLG.14) + */ +BOOL16 CALLBACK ReplaceTextDlgProc16(HWND16 hWnd16, UINT16 wMsg, WPARAM16 wParam, + LPARAM lParam) +{ + HWND hWnd = HWND_32(hWnd16); + LPFINDREPLACE16 lpfr; + switch (wMsg) { + case WM_INITDIALOG: + lpfr=MapSL(lParam); + return REPLACEDLG_WMInitDialog(hWnd, lParam, &lpfr->Flags, + MapSL(lpfr->lpstrFindWhat), + MapSL(lpfr->lpstrReplaceWith), FALSE); + case WM_COMMAND: + lpfr=MapSL(GetWindowLongPtrW(hWnd, DWLP_USER)); + return REPLACEDLG_WMCommand(hWnd, wParam, HWND_32(lpfr->hwndOwner), + &lpfr->Flags, MapSL(lpfr->lpstrFindWhat), + lpfr->wFindWhatLen, MapSL(lpfr->lpstrReplaceWith), + lpfr->wReplaceWithLen, FALSE); + } + return FALSE; +} diff --git a/reactos/lib/comdlg32/finddlg32.c b/reactos/lib/comdlg32/finddlg32.c index 04f8bdf8389..6863ef7af36 100644 --- a/reactos/lib/comdlg32/finddlg32.c +++ b/reactos/lib/comdlg32/finddlg32.c @@ -1,557 +1,557 @@ -/* - * Common Dialog Boxes interface (32 bit) - * Find/Replace - * - * Copyright 1998,1999 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "wingdi.h" -#include "winuser.h" -#include "commdlg.h" -#include "cderr.h" -#include "dlgs.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(commdlg); - -#include "cdlg.h" - - -/*-----------------------------------------------------------------------*/ - -static UINT FindReplaceMessage; -static UINT HelpMessage; - -#define FR_MASK (FR_DOWN | FR_MATCHCASE | FR_WHOLEWORD | FR_REPLACEALL | FR_REPLACE | FR_FINDNEXT | FR_DIALOGTERM) -/* CRITICAL_SECTION COMDLG32_CritSect; */ - -/* Notes: - * MS uses a critical section at a few locations. However, I fail to - * see the reason for this. Their comdlg32.dll has a few race conditions - * but _not_ at those places that are protected with the mutex (there are - * globals that seem to hold info for the wndproc). - * - * FindText[AW]/ReplaceText[AW] - * The find/replace calls are passed a structure that is _not_ used - * internally. There is a local copy that holds the running info to - * be able to combine xxxA and xxxW calls. The passed pointer is - * returned upon sendmessage. Apps won't break this way when they rely - * on the original pointer. This will work as long as the sizes of - * FINDREPLACEA == FINDREPLACEW. The local copy will also prevent - * the app to see the wine-specific extra flags to distinguish between - * A/W and Find/Replace. - */ - - -/*********************************************************************** - * COMDLG32_FR_GetFlags [internal] - * Returns the button state that needs to be reported to the caller. - * RETURNS - * Current state of check and radio buttons - */ -static DWORD COMDLG32_FR_GetFlags(HWND hDlgWnd) -{ - DWORD flags = 0; - if(IsDlgButtonChecked(hDlgWnd, rad2) == BST_CHECKED) - flags |= FR_DOWN; - if(IsDlgButtonChecked(hDlgWnd, chx1) == BST_CHECKED) - flags |= FR_WHOLEWORD; - if(IsDlgButtonChecked(hDlgWnd, chx2) == BST_CHECKED) - flags |= FR_MATCHCASE; - return flags; -} - -/*********************************************************************** - * COMDLG32_FR_HandleWMCommand [internal] - * Handle WM_COMMAND messages... - */ -static void COMDLG32_FR_HandleWMCommand(HWND hDlgWnd, COMDLG32_FR_Data *pData, int Id, int NotifyCode) -{ - DWORD flag; - - pData->user_fr.fra->Flags &= ~FR_MASK; /* Clear return flags */ - if(pData->fr.Flags & FR_WINE_REPLACE) /* Replace always goes down... */ - pData->user_fr.fra->Flags |= FR_DOWN; - - if(NotifyCode == BN_CLICKED) - { - switch(Id) - { - case IDOK: /* Find Next */ - if(GetDlgItemTextA(hDlgWnd, edt1, pData->fr.lpstrFindWhat, pData->fr.wFindWhatLen) > 0) - { - pData->user_fr.fra->Flags |= COMDLG32_FR_GetFlags(hDlgWnd) | FR_FINDNEXT; - if(pData->fr.Flags & FR_WINE_UNICODE) - { - MultiByteToWideChar( CP_ACP, 0, pData->fr.lpstrFindWhat, -1, - pData->user_fr.frw->lpstrFindWhat, - 0x7fffffff ); - } - else - { - strcpy(pData->user_fr.fra->lpstrFindWhat, pData->fr.lpstrFindWhat); - } - SendMessageA(pData->fr.hwndOwner, FindReplaceMessage, 0, (LPARAM)pData->user_fr.fra); - } - break; - - case IDCANCEL: - pData->user_fr.fra->Flags |= COMDLG32_FR_GetFlags(hDlgWnd) | FR_DIALOGTERM; - SendMessageA(pData->fr.hwndOwner, FindReplaceMessage, 0, (LPARAM)pData->user_fr.fra); - DestroyWindow(hDlgWnd); - break; - - case psh2: /* Replace All */ - flag = FR_REPLACEALL; - goto Replace; - - case psh1: /* Replace */ - flag = FR_REPLACE; -Replace: - if((pData->fr.Flags & FR_WINE_REPLACE) - && GetDlgItemTextA(hDlgWnd, edt1, pData->fr.lpstrFindWhat, pData->fr.wFindWhatLen) > 0) - { - pData->fr.lpstrReplaceWith[0] = 0; /* In case the next GetDlgItemText Fails */ - GetDlgItemTextA(hDlgWnd, edt2, pData->fr.lpstrReplaceWith, pData->fr.wReplaceWithLen); - pData->user_fr.fra->Flags |= COMDLG32_FR_GetFlags(hDlgWnd) | flag; - if(pData->fr.Flags & FR_WINE_UNICODE) - { - MultiByteToWideChar( CP_ACP, 0, pData->fr.lpstrFindWhat, -1, - pData->user_fr.frw->lpstrFindWhat, - 0x7fffffff ); - MultiByteToWideChar( CP_ACP, 0, pData->fr.lpstrReplaceWith, -1, - pData->user_fr.frw->lpstrReplaceWith, - 0x7fffffff ); - } - else - { - strcpy(pData->user_fr.fra->lpstrFindWhat, pData->fr.lpstrFindWhat); - strcpy(pData->user_fr.fra->lpstrReplaceWith, pData->fr.lpstrReplaceWith); - } - SendMessageA(pData->fr.hwndOwner, FindReplaceMessage, 0, (LPARAM)pData->user_fr.fra); - } - break; - - case pshHelp: - pData->user_fr.fra->Flags |= COMDLG32_FR_GetFlags(hDlgWnd); - SendMessageA(pData->fr.hwndOwner, HelpMessage, (WPARAM)hDlgWnd, (LPARAM)pData->user_fr.fra); - break; - } - } - else if(NotifyCode == EN_CHANGE && Id == edt1) - { - BOOL enable = SendDlgItemMessageA(hDlgWnd, edt1, WM_GETTEXTLENGTH, 0, 0) > 0; - EnableWindow(GetDlgItem(hDlgWnd, IDOK), enable); - if(pData->fr.Flags & FR_WINE_REPLACE) - { - EnableWindow(GetDlgItem(hDlgWnd, psh1), enable); - EnableWindow(GetDlgItem(hDlgWnd, psh2), enable); - } - } -} - -/*********************************************************************** - * COMDLG32_FindReplaceDlgProc [internal] - * [Find/Replace]Text32[A/W] window procedure. - */ -static INT_PTR CALLBACK COMDLG32_FindReplaceDlgProc(HWND hDlgWnd, UINT iMsg, WPARAM wParam, LPARAM lParam) -{ - COMDLG32_FR_Data *pdata = (COMDLG32_FR_Data *)GetPropA(hDlgWnd, (LPSTR)COMDLG32_Atom); - INT_PTR retval = TRUE; - - if(iMsg == WM_INITDIALOG) - { - pdata = (COMDLG32_FR_Data *)lParam; - if(!SetPropA(hDlgWnd, (LPSTR)COMDLG32_Atom, (HANDLE)pdata)) - { - ERR("Could not Set prop; invent a gracefull exit?...\n"); - DestroyWindow(hDlgWnd); - return FALSE; - } - SendDlgItemMessageA(hDlgWnd, edt1, EM_SETLIMITTEXT, (WPARAM)pdata->fr.wFindWhatLen, 0); - SendDlgItemMessageA(hDlgWnd, edt1, WM_SETTEXT, 0, (LPARAM)pdata->fr.lpstrFindWhat); - if(pdata->fr.Flags & FR_WINE_REPLACE) - { - SendDlgItemMessageA(hDlgWnd, edt2, EM_SETLIMITTEXT, (WPARAM)pdata->fr.wReplaceWithLen, 0); - SendDlgItemMessageA(hDlgWnd, edt2, WM_SETTEXT, 0, (LPARAM)pdata->fr.lpstrReplaceWith); - } - - if(!(pdata->fr.Flags & FR_SHOWHELP)) - ShowWindow(GetDlgItem(hDlgWnd, pshHelp), SW_HIDE); - if(pdata->fr.Flags & FR_HIDEUPDOWN) - { - ShowWindow(GetDlgItem(hDlgWnd, rad1), SW_HIDE); - ShowWindow(GetDlgItem(hDlgWnd, rad2), SW_HIDE); - ShowWindow(GetDlgItem(hDlgWnd, grp1), SW_HIDE); - } - else if(pdata->fr.Flags & FR_NOUPDOWN) - { - EnableWindow(GetDlgItem(hDlgWnd, rad1), FALSE); - EnableWindow(GetDlgItem(hDlgWnd, rad2), FALSE); - EnableWindow(GetDlgItem(hDlgWnd, grp1), FALSE); - } - else - { - SendDlgItemMessageA(hDlgWnd, rad1, BM_SETCHECK, pdata->fr.Flags & FR_DOWN ? 0 : BST_CHECKED, 0); - SendDlgItemMessageA(hDlgWnd, rad2, BM_SETCHECK, pdata->fr.Flags & FR_DOWN ? BST_CHECKED : 0, 0); - } - - if(pdata->fr.Flags & FR_HIDEMATCHCASE) - ShowWindow(GetDlgItem(hDlgWnd, chx2), SW_HIDE); - else if(pdata->fr.Flags & FR_NOMATCHCASE) - EnableWindow(GetDlgItem(hDlgWnd, chx2), FALSE); - else - SendDlgItemMessageA(hDlgWnd, chx2, BM_SETCHECK, pdata->fr.Flags & FR_MATCHCASE ? BST_CHECKED : 0, 0); - - if(pdata->fr.Flags & FR_HIDEWHOLEWORD) - ShowWindow(GetDlgItem(hDlgWnd, chx1), SW_HIDE); - else if(pdata->fr.Flags & FR_NOWHOLEWORD) - EnableWindow(GetDlgItem(hDlgWnd, chx1), FALSE); - else - SendDlgItemMessageA(hDlgWnd, chx1, BM_SETCHECK, pdata->fr.Flags & FR_WHOLEWORD ? BST_CHECKED : 0, 0); - - /* We did the init here, now call the hook if requested */ - - /* We do not do ShowWindow if hook exists and is FALSE */ - /* per MSDN Article Q96135 */ - if((pdata->fr.Flags & FR_ENABLEHOOK) - && ! pdata->fr.lpfnHook(hDlgWnd, iMsg, wParam, (LPARAM) &pdata->fr)) - return TRUE; - ShowWindow(hDlgWnd, SW_SHOWNORMAL); - UpdateWindow(hDlgWnd); - return TRUE; - } - - if(pdata && (pdata->fr.Flags & FR_ENABLEHOOK)) - { - retval = pdata->fr.lpfnHook(hDlgWnd, iMsg, wParam, lParam); - } - else - retval = FALSE; - - if(pdata && !retval) - { - retval = TRUE; - switch(iMsg) - { - case WM_COMMAND: - COMDLG32_FR_HandleWMCommand(hDlgWnd, pdata, LOWORD(wParam), HIWORD(wParam)); - break; - - case WM_CLOSE: - COMDLG32_FR_HandleWMCommand(hDlgWnd, pdata, IDCANCEL, BN_CLICKED); - break; - - case WM_HELP: - /* Heeeeelp! */ - FIXME("Got WM_HELP. Who is gonna supply it?\n"); - break; - - case WM_CONTEXTMENU: - /* Heeeeelp! */ - FIXME("Got WM_CONTEXTMENU. Who is gonna supply it?\n"); - break; - /* FIXME: Handle F1 help */ - - default: - retval = FALSE; /* We did not handle the message */ - } - } - - /* WM_DESTROY is a special case. - * We need to ensure that the allocated memory is freed just before - * the dialog is killed. We also need to remove the added prop. - */ - if(iMsg == WM_DESTROY) - { - RemovePropA(hDlgWnd, (LPSTR)COMDLG32_Atom); - HeapFree(GetProcessHeap(), 0, pdata); - } - - return retval; -} - -/*********************************************************************** - * COMDLG32_FR_CheckPartial [internal] - * Check various fault conditions in the supplied parameters that - * cause an extended error to be reported. - * RETURNS - * TRUE: Success - * FALSE: Failure - */ -static BOOL COMDLG32_FR_CheckPartial( - LPFINDREPLACEA pfr, /* [in] Find structure */ - BOOL Replace /* [in] True if called as replace */ -) { - if(!pfr) - { - COMDLG32_SetCommDlgExtendedError(CDERR_GENERALCODES); - return FALSE; - } - - if(pfr->lStructSize != sizeof(FINDREPLACEA)) - { - COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE); - return FALSE; - } - - if(!IsWindow(pfr->hwndOwner)) - { - COMDLG32_SetCommDlgExtendedError(CDERR_DIALOGFAILURE); - return FALSE; - } - - if((pfr->wFindWhatLen < 1 || !pfr->lpstrFindWhat) - ||(Replace && (pfr->wReplaceWithLen < 1 || !pfr->lpstrReplaceWith))) - { - COMDLG32_SetCommDlgExtendedError(FRERR_BUFFERLENGTHZERO); - return FALSE; - } - - if((FindReplaceMessage = RegisterWindowMessageA(FINDMSGSTRINGA)) == 0) - { - COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL); - return FALSE; - } - if((HelpMessage = RegisterWindowMessageA(HELPMSGSTRINGA)) == 0) - { - COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL); - return FALSE; - } - - if((pfr->Flags & FR_ENABLEHOOK) && !pfr->lpfnHook) - { - COMDLG32_SetCommDlgExtendedError(CDERR_NOHOOK); - return FALSE; - } - - if((pfr->Flags & (FR_ENABLETEMPLATE | FR_ENABLETEMPLATEHANDLE)) && !pfr->hInstance) - { - COMDLG32_SetCommDlgExtendedError(CDERR_NOHINSTANCE); - return FALSE; - } - - if((pfr->Flags & FR_ENABLETEMPLATE) && !pfr->lpTemplateName) - { - COMDLG32_SetCommDlgExtendedError(CDERR_NOTEMPLATE); - return FALSE; - } - - return TRUE; -} - -/*********************************************************************** - * COMDLG32_FR_DoFindReplace [internal] - * Actual load and creation of the Find/Replace dialog. - * RETURNS - * Window handle to created dialog:Success - * NULL:Failure - */ -static HWND COMDLG32_FR_DoFindReplace( - COMDLG32_FR_Data *pdata /* [in] Internal data structure */ -) { - HWND hdlgwnd = 0; - HGLOBAL loadrc; - DWORD error; - LPDLGTEMPLATEW rcs; - - TRACE("hInst=%p, Flags=%08lx\n", pdata->fr.hInstance, pdata->fr.Flags); - - if(!(pdata->fr.Flags & FR_ENABLETEMPLATEHANDLE)) - { - HMODULE hmod = COMDLG32_hInstance; - HRSRC htemplate; - if(pdata->fr.Flags & FR_ENABLETEMPLATE) - { - hmod = (HMODULE)pdata->fr.hInstance; - if(pdata->fr.Flags & FR_WINE_UNICODE) - { - htemplate = FindResourceW(hmod, (LPWSTR)pdata->fr.lpTemplateName, (LPWSTR)RT_DIALOG); - } - else - { - htemplate = FindResourceA(hmod, pdata->fr.lpTemplateName, (LPCSTR)RT_DIALOG); - } - } - else - { - int rcid = pdata->fr.Flags & FR_WINE_REPLACE ? REPLACEDLGORD - : FINDDLGORD; - htemplate = FindResourceA(hmod, MAKEINTRESOURCEA(rcid), (LPCSTR)RT_DIALOG); - } - if(!htemplate) - { - error = CDERR_FINDRESFAILURE; - goto cleanup; - } - - loadrc = LoadResource(hmod, htemplate); - } - else - { - loadrc = (HGLOBAL)pdata->fr.hInstance; - } - - if(!loadrc) - { - error = CDERR_LOADRESFAILURE; - goto cleanup; - } - - if((rcs = (LPDLGTEMPLATEW)LockResource(loadrc)) == NULL) - { - error = CDERR_LOCKRESFAILURE; - goto cleanup; - } - - hdlgwnd = CreateDialogIndirectParamA(COMDLG32_hInstance, - rcs, - pdata->fr.hwndOwner, - COMDLG32_FindReplaceDlgProc, - (LPARAM)pdata); - if(!hdlgwnd) - { - error = CDERR_DIALOGFAILURE; -cleanup: - COMDLG32_SetCommDlgExtendedError(error); - HeapFree(GetProcessHeap(), 0, pdata); - } - return hdlgwnd; -} - -/*********************************************************************** - * FindTextA [COMDLG32.@] - * RETURNS - * Window handle to created dialog: Success - * NULL: Failure - */ -HWND WINAPI FindTextA( - LPFINDREPLACEA pfr /* [in] Find/replace structure*/ -) { - COMDLG32_FR_Data *pdata; - - TRACE("LPFINDREPLACE=%p\n", pfr); - - if(!COMDLG32_FR_CheckPartial(pfr, FALSE)) - return 0; - - if((pdata = (COMDLG32_FR_Data *)COMDLG32_AllocMem(sizeof(COMDLG32_FR_Data))) == NULL) - return 0; /* Error has been set */ - - pdata->user_fr.fra = pfr; - pdata->fr = *pfr; - return COMDLG32_FR_DoFindReplace(pdata); -} - -/*********************************************************************** - * ReplaceTextA [COMDLG32.@] - * RETURNS - * Window handle to created dialog: Success - * NULL: Failure - */ -HWND WINAPI ReplaceTextA( - LPFINDREPLACEA pfr /* [in] Find/replace structure*/ -) { - COMDLG32_FR_Data *pdata; - - TRACE("LPFINDREPLACE=%p\n", pfr); - - if(!COMDLG32_FR_CheckPartial(pfr, TRUE)) - return 0; - - if((pdata = (COMDLG32_FR_Data *)COMDLG32_AllocMem(sizeof(COMDLG32_FR_Data))) == NULL) - return 0; /* Error has been set */ - - pdata->user_fr.fra = pfr; - pdata->fr = *pfr; - pdata->fr.Flags |= FR_WINE_REPLACE; - return COMDLG32_FR_DoFindReplace(pdata); -} - -/*********************************************************************** - * FindTextW [COMDLG32.@] - * RETURNS - * Window handle to created dialog: Success - * NULL: Failure - */ -HWND WINAPI FindTextW( - LPFINDREPLACEW pfr /* [in] Find/replace structure*/ -) { - COMDLG32_FR_Data *pdata; - DWORD len; - - TRACE("LPFINDREPLACE=%p\n", pfr); - - if(!COMDLG32_FR_CheckPartial((LPFINDREPLACEA)pfr, FALSE)) - return 0; - - len = WideCharToMultiByte( CP_ACP, 0, pfr->lpstrFindWhat, pfr->wFindWhatLen, - NULL, 0, NULL, NULL ); - if((pdata = (COMDLG32_FR_Data *)COMDLG32_AllocMem(sizeof(COMDLG32_FR_Data) + len)) == NULL) - return 0; /* Error has been set */ - - pdata->user_fr.frw = pfr; - pdata->fr = *(LPFINDREPLACEA)pfr; /* FINDREPLACEx have same size */ - pdata->fr.Flags |= FR_WINE_UNICODE; - pdata->fr.lpstrFindWhat = (LPSTR)(pdata + 1); /* Set string pointer */ - WideCharToMultiByte( CP_ACP, 0, pfr->lpstrFindWhat, pfr->wFindWhatLen, - pdata->fr.lpstrFindWhat, len, NULL, NULL ); - return COMDLG32_FR_DoFindReplace(pdata); -} - -/*********************************************************************** - * ReplaceTextW [COMDLG32.@] - * RETURNS - * Window handle to created dialog: Success - * NULL: Failure - */ -HWND WINAPI ReplaceTextW( - LPFINDREPLACEW pfr /* [in] Find/replace structure*/ -) { - COMDLG32_FR_Data *pdata; - DWORD len1, len2; - - TRACE("LPFINDREPLACE=%p\n", pfr); - - if(!COMDLG32_FR_CheckPartial((LPFINDREPLACEA)pfr, FALSE)) - return 0; - - len1 = WideCharToMultiByte( CP_ACP, 0, pfr->lpstrFindWhat, pfr->wFindWhatLen, - NULL, 0, NULL, NULL ); - len2 = WideCharToMultiByte( CP_ACP, 0, pfr->lpstrReplaceWith, pfr->wReplaceWithLen, - NULL, 0, NULL, NULL ); - if((pdata = (COMDLG32_FR_Data *)COMDLG32_AllocMem(sizeof(COMDLG32_FR_Data) - + len1 + len2)) == NULL) - return 0; /* Error has been set */ - - pdata->user_fr.frw = pfr; - pdata->fr = *(LPFINDREPLACEA)pfr; /* FINDREPLACEx have same size */ - pdata->fr.Flags |= FR_WINE_REPLACE | FR_WINE_UNICODE; - pdata->fr.lpstrFindWhat = (LPSTR)(pdata + 1); /* Set string pointer */ - pdata->fr.lpstrReplaceWith = pdata->fr.lpstrFindWhat + len1; - - WideCharToMultiByte( CP_ACP, 0, pfr->lpstrFindWhat, pfr->wFindWhatLen, - pdata->fr.lpstrFindWhat, len1, NULL, NULL ); - WideCharToMultiByte( CP_ACP, 0, pfr->lpstrReplaceWith, pfr->wReplaceWithLen, - pdata->fr.lpstrReplaceWith, len2, NULL, NULL ); - return COMDLG32_FR_DoFindReplace(pdata); -} +/* + * Common Dialog Boxes interface (32 bit) + * Find/Replace + * + * Copyright 1998,1999 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "wingdi.h" +#include "winuser.h" +#include "commdlg.h" +#include "cderr.h" +#include "dlgs.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(commdlg); + +#include "cdlg.h" + + +/*-----------------------------------------------------------------------*/ + +static UINT FindReplaceMessage; +static UINT HelpMessage; + +#define FR_MASK (FR_DOWN | FR_MATCHCASE | FR_WHOLEWORD | FR_REPLACEALL | FR_REPLACE | FR_FINDNEXT | FR_DIALOGTERM) +/* CRITICAL_SECTION COMDLG32_CritSect; */ + +/* Notes: + * MS uses a critical section at a few locations. However, I fail to + * see the reason for this. Their comdlg32.dll has a few race conditions + * but _not_ at those places that are protected with the mutex (there are + * globals that seem to hold info for the wndproc). + * + * FindText[AW]/ReplaceText[AW] + * The find/replace calls are passed a structure that is _not_ used + * internally. There is a local copy that holds the running info to + * be able to combine xxxA and xxxW calls. The passed pointer is + * returned upon sendmessage. Apps won't break this way when they rely + * on the original pointer. This will work as long as the sizes of + * FINDREPLACEA == FINDREPLACEW. The local copy will also prevent + * the app to see the wine-specific extra flags to distinguish between + * A/W and Find/Replace. + */ + + +/*********************************************************************** + * COMDLG32_FR_GetFlags [internal] + * Returns the button state that needs to be reported to the caller. + * RETURNS + * Current state of check and radio buttons + */ +static DWORD COMDLG32_FR_GetFlags(HWND hDlgWnd) +{ + DWORD flags = 0; + if(IsDlgButtonChecked(hDlgWnd, rad2) == BST_CHECKED) + flags |= FR_DOWN; + if(IsDlgButtonChecked(hDlgWnd, chx1) == BST_CHECKED) + flags |= FR_WHOLEWORD; + if(IsDlgButtonChecked(hDlgWnd, chx2) == BST_CHECKED) + flags |= FR_MATCHCASE; + return flags; +} + +/*********************************************************************** + * COMDLG32_FR_HandleWMCommand [internal] + * Handle WM_COMMAND messages... + */ +static void COMDLG32_FR_HandleWMCommand(HWND hDlgWnd, COMDLG32_FR_Data *pData, int Id, int NotifyCode) +{ + DWORD flag; + + pData->user_fr.fra->Flags &= ~FR_MASK; /* Clear return flags */ + if(pData->fr.Flags & FR_WINE_REPLACE) /* Replace always goes down... */ + pData->user_fr.fra->Flags |= FR_DOWN; + + if(NotifyCode == BN_CLICKED) + { + switch(Id) + { + case IDOK: /* Find Next */ + if(GetDlgItemTextA(hDlgWnd, edt1, pData->fr.lpstrFindWhat, pData->fr.wFindWhatLen) > 0) + { + pData->user_fr.fra->Flags |= COMDLG32_FR_GetFlags(hDlgWnd) | FR_FINDNEXT; + if(pData->fr.Flags & FR_WINE_UNICODE) + { + MultiByteToWideChar( CP_ACP, 0, pData->fr.lpstrFindWhat, -1, + pData->user_fr.frw->lpstrFindWhat, + 0x7fffffff ); + } + else + { + strcpy(pData->user_fr.fra->lpstrFindWhat, pData->fr.lpstrFindWhat); + } + SendMessageA(pData->fr.hwndOwner, FindReplaceMessage, 0, (LPARAM)pData->user_fr.fra); + } + break; + + case IDCANCEL: + pData->user_fr.fra->Flags |= COMDLG32_FR_GetFlags(hDlgWnd) | FR_DIALOGTERM; + SendMessageA(pData->fr.hwndOwner, FindReplaceMessage, 0, (LPARAM)pData->user_fr.fra); + DestroyWindow(hDlgWnd); + break; + + case psh2: /* Replace All */ + flag = FR_REPLACEALL; + goto Replace; + + case psh1: /* Replace */ + flag = FR_REPLACE; +Replace: + if((pData->fr.Flags & FR_WINE_REPLACE) + && GetDlgItemTextA(hDlgWnd, edt1, pData->fr.lpstrFindWhat, pData->fr.wFindWhatLen) > 0) + { + pData->fr.lpstrReplaceWith[0] = 0; /* In case the next GetDlgItemText Fails */ + GetDlgItemTextA(hDlgWnd, edt2, pData->fr.lpstrReplaceWith, pData->fr.wReplaceWithLen); + pData->user_fr.fra->Flags |= COMDLG32_FR_GetFlags(hDlgWnd) | flag; + if(pData->fr.Flags & FR_WINE_UNICODE) + { + MultiByteToWideChar( CP_ACP, 0, pData->fr.lpstrFindWhat, -1, + pData->user_fr.frw->lpstrFindWhat, + 0x7fffffff ); + MultiByteToWideChar( CP_ACP, 0, pData->fr.lpstrReplaceWith, -1, + pData->user_fr.frw->lpstrReplaceWith, + 0x7fffffff ); + } + else + { + strcpy(pData->user_fr.fra->lpstrFindWhat, pData->fr.lpstrFindWhat); + strcpy(pData->user_fr.fra->lpstrReplaceWith, pData->fr.lpstrReplaceWith); + } + SendMessageA(pData->fr.hwndOwner, FindReplaceMessage, 0, (LPARAM)pData->user_fr.fra); + } + break; + + case pshHelp: + pData->user_fr.fra->Flags |= COMDLG32_FR_GetFlags(hDlgWnd); + SendMessageA(pData->fr.hwndOwner, HelpMessage, (WPARAM)hDlgWnd, (LPARAM)pData->user_fr.fra); + break; + } + } + else if(NotifyCode == EN_CHANGE && Id == edt1) + { + BOOL enable = SendDlgItemMessageA(hDlgWnd, edt1, WM_GETTEXTLENGTH, 0, 0) > 0; + EnableWindow(GetDlgItem(hDlgWnd, IDOK), enable); + if(pData->fr.Flags & FR_WINE_REPLACE) + { + EnableWindow(GetDlgItem(hDlgWnd, psh1), enable); + EnableWindow(GetDlgItem(hDlgWnd, psh2), enable); + } + } +} + +/*********************************************************************** + * COMDLG32_FindReplaceDlgProc [internal] + * [Find/Replace]Text32[A/W] window procedure. + */ +static INT_PTR CALLBACK COMDLG32_FindReplaceDlgProc(HWND hDlgWnd, UINT iMsg, WPARAM wParam, LPARAM lParam) +{ + COMDLG32_FR_Data *pdata = (COMDLG32_FR_Data *)GetPropA(hDlgWnd, (LPSTR)COMDLG32_Atom); + INT_PTR retval = TRUE; + + if(iMsg == WM_INITDIALOG) + { + pdata = (COMDLG32_FR_Data *)lParam; + if(!SetPropA(hDlgWnd, (LPSTR)COMDLG32_Atom, (HANDLE)pdata)) + { + ERR("Could not Set prop; invent a gracefull exit?...\n"); + DestroyWindow(hDlgWnd); + return FALSE; + } + SendDlgItemMessageA(hDlgWnd, edt1, EM_SETLIMITTEXT, (WPARAM)pdata->fr.wFindWhatLen, 0); + SendDlgItemMessageA(hDlgWnd, edt1, WM_SETTEXT, 0, (LPARAM)pdata->fr.lpstrFindWhat); + if(pdata->fr.Flags & FR_WINE_REPLACE) + { + SendDlgItemMessageA(hDlgWnd, edt2, EM_SETLIMITTEXT, (WPARAM)pdata->fr.wReplaceWithLen, 0); + SendDlgItemMessageA(hDlgWnd, edt2, WM_SETTEXT, 0, (LPARAM)pdata->fr.lpstrReplaceWith); + } + + if(!(pdata->fr.Flags & FR_SHOWHELP)) + ShowWindow(GetDlgItem(hDlgWnd, pshHelp), SW_HIDE); + if(pdata->fr.Flags & FR_HIDEUPDOWN) + { + ShowWindow(GetDlgItem(hDlgWnd, rad1), SW_HIDE); + ShowWindow(GetDlgItem(hDlgWnd, rad2), SW_HIDE); + ShowWindow(GetDlgItem(hDlgWnd, grp1), SW_HIDE); + } + else if(pdata->fr.Flags & FR_NOUPDOWN) + { + EnableWindow(GetDlgItem(hDlgWnd, rad1), FALSE); + EnableWindow(GetDlgItem(hDlgWnd, rad2), FALSE); + EnableWindow(GetDlgItem(hDlgWnd, grp1), FALSE); + } + else + { + SendDlgItemMessageA(hDlgWnd, rad1, BM_SETCHECK, pdata->fr.Flags & FR_DOWN ? 0 : BST_CHECKED, 0); + SendDlgItemMessageA(hDlgWnd, rad2, BM_SETCHECK, pdata->fr.Flags & FR_DOWN ? BST_CHECKED : 0, 0); + } + + if(pdata->fr.Flags & FR_HIDEMATCHCASE) + ShowWindow(GetDlgItem(hDlgWnd, chx2), SW_HIDE); + else if(pdata->fr.Flags & FR_NOMATCHCASE) + EnableWindow(GetDlgItem(hDlgWnd, chx2), FALSE); + else + SendDlgItemMessageA(hDlgWnd, chx2, BM_SETCHECK, pdata->fr.Flags & FR_MATCHCASE ? BST_CHECKED : 0, 0); + + if(pdata->fr.Flags & FR_HIDEWHOLEWORD) + ShowWindow(GetDlgItem(hDlgWnd, chx1), SW_HIDE); + else if(pdata->fr.Flags & FR_NOWHOLEWORD) + EnableWindow(GetDlgItem(hDlgWnd, chx1), FALSE); + else + SendDlgItemMessageA(hDlgWnd, chx1, BM_SETCHECK, pdata->fr.Flags & FR_WHOLEWORD ? BST_CHECKED : 0, 0); + + /* We did the init here, now call the hook if requested */ + + /* We do not do ShowWindow if hook exists and is FALSE */ + /* per MSDN Article Q96135 */ + if((pdata->fr.Flags & FR_ENABLEHOOK) + && ! pdata->fr.lpfnHook(hDlgWnd, iMsg, wParam, (LPARAM) &pdata->fr)) + return TRUE; + ShowWindow(hDlgWnd, SW_SHOWNORMAL); + UpdateWindow(hDlgWnd); + return TRUE; + } + + if(pdata && (pdata->fr.Flags & FR_ENABLEHOOK)) + { + retval = pdata->fr.lpfnHook(hDlgWnd, iMsg, wParam, lParam); + } + else + retval = FALSE; + + if(pdata && !retval) + { + retval = TRUE; + switch(iMsg) + { + case WM_COMMAND: + COMDLG32_FR_HandleWMCommand(hDlgWnd, pdata, LOWORD(wParam), HIWORD(wParam)); + break; + + case WM_CLOSE: + COMDLG32_FR_HandleWMCommand(hDlgWnd, pdata, IDCANCEL, BN_CLICKED); + break; + + case WM_HELP: + /* Heeeeelp! */ + FIXME("Got WM_HELP. Who is gonna supply it?\n"); + break; + + case WM_CONTEXTMENU: + /* Heeeeelp! */ + FIXME("Got WM_CONTEXTMENU. Who is gonna supply it?\n"); + break; + /* FIXME: Handle F1 help */ + + default: + retval = FALSE; /* We did not handle the message */ + } + } + + /* WM_DESTROY is a special case. + * We need to ensure that the allocated memory is freed just before + * the dialog is killed. We also need to remove the added prop. + */ + if(iMsg == WM_DESTROY) + { + RemovePropA(hDlgWnd, (LPSTR)COMDLG32_Atom); + HeapFree(GetProcessHeap(), 0, pdata); + } + + return retval; +} + +/*********************************************************************** + * COMDLG32_FR_CheckPartial [internal] + * Check various fault conditions in the supplied parameters that + * cause an extended error to be reported. + * RETURNS + * TRUE: Success + * FALSE: Failure + */ +static BOOL COMDLG32_FR_CheckPartial( + LPFINDREPLACEA pfr, /* [in] Find structure */ + BOOL Replace /* [in] True if called as replace */ +) { + if(!pfr) + { + COMDLG32_SetCommDlgExtendedError(CDERR_GENERALCODES); + return FALSE; + } + + if(pfr->lStructSize != sizeof(FINDREPLACEA)) + { + COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE); + return FALSE; + } + + if(!IsWindow(pfr->hwndOwner)) + { + COMDLG32_SetCommDlgExtendedError(CDERR_DIALOGFAILURE); + return FALSE; + } + + if((pfr->wFindWhatLen < 1 || !pfr->lpstrFindWhat) + ||(Replace && (pfr->wReplaceWithLen < 1 || !pfr->lpstrReplaceWith))) + { + COMDLG32_SetCommDlgExtendedError(FRERR_BUFFERLENGTHZERO); + return FALSE; + } + + if((FindReplaceMessage = RegisterWindowMessageA(FINDMSGSTRINGA)) == 0) + { + COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL); + return FALSE; + } + if((HelpMessage = RegisterWindowMessageA(HELPMSGSTRINGA)) == 0) + { + COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL); + return FALSE; + } + + if((pfr->Flags & FR_ENABLEHOOK) && !pfr->lpfnHook) + { + COMDLG32_SetCommDlgExtendedError(CDERR_NOHOOK); + return FALSE; + } + + if((pfr->Flags & (FR_ENABLETEMPLATE | FR_ENABLETEMPLATEHANDLE)) && !pfr->hInstance) + { + COMDLG32_SetCommDlgExtendedError(CDERR_NOHINSTANCE); + return FALSE; + } + + if((pfr->Flags & FR_ENABLETEMPLATE) && !pfr->lpTemplateName) + { + COMDLG32_SetCommDlgExtendedError(CDERR_NOTEMPLATE); + return FALSE; + } + + return TRUE; +} + +/*********************************************************************** + * COMDLG32_FR_DoFindReplace [internal] + * Actual load and creation of the Find/Replace dialog. + * RETURNS + * Window handle to created dialog:Success + * NULL:Failure + */ +static HWND COMDLG32_FR_DoFindReplace( + COMDLG32_FR_Data *pdata /* [in] Internal data structure */ +) { + HWND hdlgwnd = 0; + HGLOBAL loadrc; + DWORD error; + LPDLGTEMPLATEW rcs; + + TRACE("hInst=%p, Flags=%08lx\n", pdata->fr.hInstance, pdata->fr.Flags); + + if(!(pdata->fr.Flags & FR_ENABLETEMPLATEHANDLE)) + { + HMODULE hmod = COMDLG32_hInstance; + HRSRC htemplate; + if(pdata->fr.Flags & FR_ENABLETEMPLATE) + { + hmod = (HMODULE)pdata->fr.hInstance; + if(pdata->fr.Flags & FR_WINE_UNICODE) + { + htemplate = FindResourceW(hmod, (LPWSTR)pdata->fr.lpTemplateName, (LPWSTR)RT_DIALOG); + } + else + { + htemplate = FindResourceA(hmod, pdata->fr.lpTemplateName, (LPCSTR)RT_DIALOG); + } + } + else + { + int rcid = pdata->fr.Flags & FR_WINE_REPLACE ? REPLACEDLGORD + : FINDDLGORD; + htemplate = FindResourceA(hmod, MAKEINTRESOURCEA(rcid), (LPCSTR)RT_DIALOG); + } + if(!htemplate) + { + error = CDERR_FINDRESFAILURE; + goto cleanup; + } + + loadrc = LoadResource(hmod, htemplate); + } + else + { + loadrc = (HGLOBAL)pdata->fr.hInstance; + } + + if(!loadrc) + { + error = CDERR_LOADRESFAILURE; + goto cleanup; + } + + if((rcs = (LPDLGTEMPLATEW)LockResource(loadrc)) == NULL) + { + error = CDERR_LOCKRESFAILURE; + goto cleanup; + } + + hdlgwnd = CreateDialogIndirectParamA(COMDLG32_hInstance, + rcs, + pdata->fr.hwndOwner, + COMDLG32_FindReplaceDlgProc, + (LPARAM)pdata); + if(!hdlgwnd) + { + error = CDERR_DIALOGFAILURE; +cleanup: + COMDLG32_SetCommDlgExtendedError(error); + HeapFree(GetProcessHeap(), 0, pdata); + } + return hdlgwnd; +} + +/*********************************************************************** + * FindTextA [COMDLG32.@] + * RETURNS + * Window handle to created dialog: Success + * NULL: Failure + */ +HWND WINAPI FindTextA( + LPFINDREPLACEA pfr /* [in] Find/replace structure*/ +) { + COMDLG32_FR_Data *pdata; + + TRACE("LPFINDREPLACE=%p\n", pfr); + + if(!COMDLG32_FR_CheckPartial(pfr, FALSE)) + return 0; + + if((pdata = (COMDLG32_FR_Data *)COMDLG32_AllocMem(sizeof(COMDLG32_FR_Data))) == NULL) + return 0; /* Error has been set */ + + pdata->user_fr.fra = pfr; + pdata->fr = *pfr; + return COMDLG32_FR_DoFindReplace(pdata); +} + +/*********************************************************************** + * ReplaceTextA [COMDLG32.@] + * RETURNS + * Window handle to created dialog: Success + * NULL: Failure + */ +HWND WINAPI ReplaceTextA( + LPFINDREPLACEA pfr /* [in] Find/replace structure*/ +) { + COMDLG32_FR_Data *pdata; + + TRACE("LPFINDREPLACE=%p\n", pfr); + + if(!COMDLG32_FR_CheckPartial(pfr, TRUE)) + return 0; + + if((pdata = (COMDLG32_FR_Data *)COMDLG32_AllocMem(sizeof(COMDLG32_FR_Data))) == NULL) + return 0; /* Error has been set */ + + pdata->user_fr.fra = pfr; + pdata->fr = *pfr; + pdata->fr.Flags |= FR_WINE_REPLACE; + return COMDLG32_FR_DoFindReplace(pdata); +} + +/*********************************************************************** + * FindTextW [COMDLG32.@] + * RETURNS + * Window handle to created dialog: Success + * NULL: Failure + */ +HWND WINAPI FindTextW( + LPFINDREPLACEW pfr /* [in] Find/replace structure*/ +) { + COMDLG32_FR_Data *pdata; + DWORD len; + + TRACE("LPFINDREPLACE=%p\n", pfr); + + if(!COMDLG32_FR_CheckPartial((LPFINDREPLACEA)pfr, FALSE)) + return 0; + + len = WideCharToMultiByte( CP_ACP, 0, pfr->lpstrFindWhat, pfr->wFindWhatLen, + NULL, 0, NULL, NULL ); + if((pdata = (COMDLG32_FR_Data *)COMDLG32_AllocMem(sizeof(COMDLG32_FR_Data) + len)) == NULL) + return 0; /* Error has been set */ + + pdata->user_fr.frw = pfr; + pdata->fr = *(LPFINDREPLACEA)pfr; /* FINDREPLACEx have same size */ + pdata->fr.Flags |= FR_WINE_UNICODE; + pdata->fr.lpstrFindWhat = (LPSTR)(pdata + 1); /* Set string pointer */ + WideCharToMultiByte( CP_ACP, 0, pfr->lpstrFindWhat, pfr->wFindWhatLen, + pdata->fr.lpstrFindWhat, len, NULL, NULL ); + return COMDLG32_FR_DoFindReplace(pdata); +} + +/*********************************************************************** + * ReplaceTextW [COMDLG32.@] + * RETURNS + * Window handle to created dialog: Success + * NULL: Failure + */ +HWND WINAPI ReplaceTextW( + LPFINDREPLACEW pfr /* [in] Find/replace structure*/ +) { + COMDLG32_FR_Data *pdata; + DWORD len1, len2; + + TRACE("LPFINDREPLACE=%p\n", pfr); + + if(!COMDLG32_FR_CheckPartial((LPFINDREPLACEA)pfr, FALSE)) + return 0; + + len1 = WideCharToMultiByte( CP_ACP, 0, pfr->lpstrFindWhat, pfr->wFindWhatLen, + NULL, 0, NULL, NULL ); + len2 = WideCharToMultiByte( CP_ACP, 0, pfr->lpstrReplaceWith, pfr->wReplaceWithLen, + NULL, 0, NULL, NULL ); + if((pdata = (COMDLG32_FR_Data *)COMDLG32_AllocMem(sizeof(COMDLG32_FR_Data) + + len1 + len2)) == NULL) + return 0; /* Error has been set */ + + pdata->user_fr.frw = pfr; + pdata->fr = *(LPFINDREPLACEA)pfr; /* FINDREPLACEx have same size */ + pdata->fr.Flags |= FR_WINE_REPLACE | FR_WINE_UNICODE; + pdata->fr.lpstrFindWhat = (LPSTR)(pdata + 1); /* Set string pointer */ + pdata->fr.lpstrReplaceWith = pdata->fr.lpstrFindWhat + len1; + + WideCharToMultiByte( CP_ACP, 0, pfr->lpstrFindWhat, pfr->wFindWhatLen, + pdata->fr.lpstrFindWhat, len1, NULL, NULL ); + WideCharToMultiByte( CP_ACP, 0, pfr->lpstrReplaceWith, pfr->wReplaceWithLen, + pdata->fr.lpstrReplaceWith, len2, NULL, NULL ); + return COMDLG32_FR_DoFindReplace(pdata); +} diff --git a/reactos/lib/comdlg32/fontdlg.c b/reactos/lib/comdlg32/fontdlg.c index 829c89bcc4e..2593b4a8f84 100644 --- a/reactos/lib/comdlg32/fontdlg.c +++ b/reactos/lib/comdlg32/fontdlg.c @@ -1,1217 +1,1217 @@ -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "wingdi.h" -#include "winuser.h" -#include "commdlg.h" -#include "dlgs.h" -#include "wine/debug.h" -#include "cderr.h" - -WINE_DEFAULT_DEBUG_CHANNEL(commdlg); - -static const WCHAR strWineFontData[] = {'_','_','W','I','N','E','_','F','O','N','T','D','L','G','D','A','T','A',0}; -static const WCHAR strWineFontData_a[] = - {'_','_','W','I','N','E','_','F','O','N','T','D','L','G','D','A','T','A','_','A',0}; -static const WCHAR chooseFontW[] = {'C','H','O','O','S','E','_','F','O','N','T',0}; - -#include "cdlg.h" - -/* image list with TrueType bitmaps and more */ -static HIMAGELIST himlTT = 0; -#define TTBITMAP_XSIZE 20 /* x-size of the bitmaps */ - -INT_PTR CALLBACK FormatCharDlgProcA(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); -INT_PTR CALLBACK FormatCharDlgProcW(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); - -/* There is a table here of all charsets, and the sample text for each. - * There is a second table that translates a charset into an index into - * the first table. - */ - -#define CI(cs) ((IDS_CHARSET_##cs)-IDS_CHARSET_ANSI) - - -static const WCHAR stWestern[]={'A','a','B','b','Y','y','Z','z',0}; /* Western and default */ -static const WCHAR stSymbol[]={'S','y','m','b','o','l',0}; /* Symbol */ -static const WCHAR stShiftJis[]={'A','a',0x3042,0x3041,0x30a2,0x30a1,0x4e9c,0x5b87,0}; /* Shift JIS */ -static const WCHAR stHangul[]={0xac00,0xb098,0xb2e4,'A','a','B','Y','y','Z','z',0}; /* Hangul */ -static const WCHAR stGB2312[]={0x5fae,0x8f6f,0x4e2d,0x6587,0x8f6f,0x4ef6,0}; /* GB2312 */ -static const WCHAR stBIG5[]={0x4e2d,0x6587,0x5b57,0x578b,0x7bc4,0x4f8b,0}; /* BIG5 */ -static const WCHAR stGreek[]={'A','a','B','b',0x0391,0x03b1,0x0392,0x03b2,0}; /* Greek */ -static const WCHAR stTurkish[]={'A','a','B','b',0x011e,0x011f,0x015e,0x015f,0}; /* Turkish */ -static const WCHAR stHebrew[]={'A','a','B','b',0x05e0,0x05e1,0x05e9,0x05ea,0}; /* Hebrew */ -static const WCHAR stArabic[]={'A','a','B','b',0x0627,0x0628,0x062c,0x062f,0x0647,0x0648,0x0632,0};/* Arabic */ -static const WCHAR stBaltic[]={'A','a','B','b','Y','y','Z','z',0}; /* Baltic */ -static const WCHAR stVietname[]={'A','a','B','b',0x01a0,0x01a1,0x01af,0x01b0,0}; /* Vietnamese */ -static const WCHAR stCyrillic[]={'A','a','B','b',0x0411,0x0431,0x0424,0x0444,0}; /* Cyrillic */ -static const WCHAR stEastEur[]={'A','a','B','b',0xc1,0xe1,0xd4,0xf4,0}; /* East European */ -static const WCHAR stThai[]={'A','a','B','b',0x0e2d,0x0e31,0x0e01,0x0e29,0x0e23,0x0e44,0x0e17,0x0e22,0}; /* Thai */ -static const WCHAR stJohab[]={0xac00,0xb098,0xb2e4,'A','a','B','Y','y','Z','z',0}; /* Johab */ -static const WCHAR stMac[]={'A','a','B','b','Y','y','Z','z',0}; /* Mac */ -static const WCHAR stOEM[]={'A','a','B','b',0xf8,0xf1,0xfd,0}; /* OEM */ -/* the following character sets actually behave different (Win2K observation): - * the sample string is 'sticky': it uses the sample string of the previous - * selected character set. That behaviour looks like some default, which is - * not (yet) implemented. */ -static const WCHAR stVISCII[]={'A','a','B','b',0}; /* VISCII */ -static const WCHAR stTCVN[]={'A','a','B','b',0}; /* TCVN */ -static const WCHAR stKOI8[]={'A','a','B','b',0}; /* KOI-8 */ -static const WCHAR stIso88593[]={'A','a','B','b',0}; /* ISO-8859-3 */ -static const WCHAR stIso88594[]={'A','a','B','b',0}; /* ISO-8859-4 */ -static const WCHAR stIso885910[]={'A','a','B','b',0}; /* ISO-8859-10 */ -static const WCHAR stCeltic[]={'A','a','B','b',0};/* Celtic */ - -static const WCHAR *sample_lang_text[]={ - stWestern,stSymbol,stShiftJis,stHangul,stGB2312, - stBIG5,stGreek,stTurkish,stHebrew,stArabic, - stBaltic,stVietname,stCyrillic,stEastEur,stThai, - stJohab,stMac,stOEM,stVISCII,stTCVN, - stKOI8,stIso88593,stIso88594,stIso885910,stCeltic}; - - -static const BYTE CHARSET_ORDER[256]={ - CI(ANSI), 0, CI(SYMBOL), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, CI(MAC), 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - CI(JIS), CI(HANGUL), CI(JOHAB), 0, 0, 0, CI(GB2312), 0, CI(BIG5), 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, CI(GREEK), CI(TURKISH), CI(VIETNAMESE), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, CI(HEBREW), CI(ARABIC), 0, 0, 0, 0, 0, 0, 0, CI(BALTIC), 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, CI(RUSSIAN), 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, CI(THAI), 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, CI(EE), 0, - CI(VISCII), CI(TCVN), CI(KOI8), CI(ISO3), CI(ISO4), CI(ISO10), CI(CELTIC), 0, 0, 0, 0, 0, 0, 0, 0, CI(OEM), -}; - -static const struct { - DWORD mask; - const char *name; -} cfflags[] = { -#define XX(x) { x, #x }, - XX(CF_SCREENFONTS) - XX(CF_PRINTERFONTS) - XX(CF_SHOWHELP) - XX(CF_ENABLEHOOK) - XX(CF_ENABLETEMPLATE) - XX(CF_ENABLETEMPLATEHANDLE) - XX(CF_INITTOLOGFONTSTRUCT) - XX(CF_USESTYLE) - XX(CF_EFFECTS) - XX(CF_APPLY) - XX(CF_ANSIONLY) - XX(CF_NOVECTORFONTS) - XX(CF_NOSIMULATIONS) - XX(CF_LIMITSIZE) - XX(CF_FIXEDPITCHONLY) - XX(CF_WYSIWYG) - XX(CF_FORCEFONTEXIST) - XX(CF_SCALABLEONLY) - XX(CF_TTONLY) - XX(CF_NOFACESEL) - XX(CF_NOSTYLESEL) - XX(CF_NOSIZESEL) - XX(CF_SELECTSCRIPT) - XX(CF_NOSCRIPTSEL) - XX(CF_NOVERTFONTS) -#undef XX -}; - -void _dump_cf_flags(DWORD cflags) -{ - int i; - - for (i = 0; i < sizeof(cfflags)/sizeof(cfflags[0]); i++) - if (cfflags[i].mask & cflags) - TRACE("%s|",cfflags[i].name); - TRACE("\n"); -} - -/*********************************************************************** - * ChooseFontW (COMDLG32.@) - */ -BOOL WINAPI ChooseFontW(LPCHOOSEFONTW lpChFont) -{ - LPCVOID template; - HRSRC hResInfo; - HINSTANCE hDlginst; - HGLOBAL hDlgTmpl; - - TRACE("(%p)\n", lpChFont); - - if ( (lpChFont->Flags&CF_ENABLETEMPLATEHANDLE)!=0 ) - { - template=(LPCVOID)lpChFont->hInstance; - } else - { - if ( (lpChFont->Flags&CF_ENABLETEMPLATE)!=0 ) - { - hDlginst=lpChFont->hInstance; - if( !(hResInfo = FindResourceW(hDlginst, lpChFont->lpTemplateName, - (LPWSTR)RT_DIALOG))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); - return FALSE; - } - } else - { - hDlginst=COMDLG32_hInstance; - if (!(hResInfo = FindResourceW(hDlginst, chooseFontW, (LPWSTR)RT_DIALOG))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); - return FALSE; - } - } - if (!(hDlgTmpl = LoadResource(hDlginst, hResInfo )) || - !(template = LockResource( hDlgTmpl ))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - } - if (TRACE_ON(commdlg)) - _dump_cf_flags(lpChFont->Flags); - - if (lpChFont->Flags & (CF_SELECTSCRIPT | CF_NOVERTFONTS )) - FIXME(": unimplemented flag (ignored)\n"); - - return DialogBoxIndirectParamW(COMDLG32_hInstance, template, - lpChFont->hwndOwner, FormatCharDlgProcW, (LPARAM)lpChFont ); -} - -/*********************************************************************** - * ChooseFontA (COMDLG32.@) - */ -BOOL WINAPI ChooseFontA(LPCHOOSEFONTA lpChFont) -{ - LPCVOID template; - HRSRC hResInfo; - HINSTANCE hDlginst; - HGLOBAL hDlgTmpl; - - TRACE("(%p)\n", lpChFont); - - if ( (lpChFont->Flags&CF_ENABLETEMPLATEHANDLE)!=0 ) - { - template=(LPCVOID)lpChFont->hInstance; - } else - { - if ( (lpChFont->Flags&CF_ENABLETEMPLATE)!=0 ) - { - hDlginst=lpChFont->hInstance; - if( !(hResInfo = FindResourceA(hDlginst, lpChFont->lpTemplateName, - (LPSTR)RT_DIALOG))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); - return FALSE; - } - } else - { - hDlginst=COMDLG32_hInstance; - if (!(hResInfo = FindResourceW(hDlginst, chooseFontW, (LPWSTR)RT_DIALOG))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); - return FALSE; - } - } - if (!(hDlgTmpl = LoadResource(hDlginst, hResInfo )) || - !(template = LockResource( hDlgTmpl ))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - } - if (TRACE_ON(commdlg)) - _dump_cf_flags(lpChFont->Flags); - if (lpChFont->Flags & (CF_SELECTSCRIPT | CF_NOVERTFONTS )) - FIXME(": unimplemented flag (ignored)\n"); - - return DialogBoxIndirectParamA(COMDLG32_hInstance, template, - lpChFont->hwndOwner, FormatCharDlgProcA, (LPARAM)lpChFont ); -} - -#define TEXT_EXTRAS 4 -#define TEXT_COLORS 16 - -static const COLORREF textcolors[TEXT_COLORS]= -{ - 0x00000000L,0x00000080L,0x00008000L,0x00008080L, - 0x00800000L,0x00800080L,0x00808000L,0x00808080L, - 0x00c0c0c0L,0x000000ffL,0x0000ff00L,0x0000ffffL, - 0x00ff0000L,0x00ff00ffL,0x00ffff00L,0x00FFFFFFL -}; - -/*********************************************************************** - * CFn_HookCallChk32 [internal] - */ -static BOOL CFn_HookCallChk32(LPCHOOSEFONTW lpcf) -{ - if (lpcf) - if(lpcf->Flags & CF_ENABLEHOOK) - if (lpcf->lpfnHook) - return TRUE; - return FALSE; -} - -/************************************************************************* - * AddFontFamily [internal] - */ -INT AddFontFamily(const ENUMLOGFONTEXW *lpElfex, const NEWTEXTMETRICEXW *lpNTM, - UINT nFontType, LPCHOOSEFONTW lpcf, HWND hwnd, LPCFn_ENUMSTRUCT e) -{ - int i; - WORD w; - const LOGFONTW *lplf = &(lpElfex->elfLogFont); - - TRACE("font=%s (nFontType=%d)\n", debugstr_w(lplf->lfFaceName), nFontType); - - if (lpcf->Flags & CF_FIXEDPITCHONLY) - if (!(lplf->lfPitchAndFamily & FIXED_PITCH)) - return 1; - if (lpcf->Flags & CF_ANSIONLY) - if (lplf->lfCharSet != ANSI_CHARSET) - return 1; - if (lpcf->Flags & CF_TTONLY) - if (!(nFontType & TRUETYPE_FONTTYPE)) - return 1; - - if (e) e->added++; - - i=SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)lplf->lfFaceName); - if (i == CB_ERR) { - i = SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)lplf->lfFaceName); - if( i != CB_ERR) { - /* store some important font information */ - w = (lplf->lfPitchAndFamily) << 8 | - (HIWORD(lpNTM->ntmTm.ntmFlags) & 0xff); - SendMessageW(hwnd, CB_SETITEMDATA, i, MAKELONG(nFontType,w)); - } - } - return 1; -} - -/************************************************************************* - * FontFamilyEnumProc32 [internal] - */ -static INT WINAPI FontFamilyEnumProc(const ENUMLOGFONTEXW *lpElfex, - const TEXTMETRICW *metrics, DWORD dwFontType, LPARAM lParam) -{ - LPCFn_ENUMSTRUCT e; - e=(LPCFn_ENUMSTRUCT)lParam; - return AddFontFamily( lpElfex, (NEWTEXTMETRICEXW *) metrics, - dwFontType, e->lpcf32w, e->hWnd1, e); -} - -/************************************************************************* - * SetFontStylesToCombo2 [internal] - * - * Fill font style information into combobox (without using font.c directly) - */ -static int SetFontStylesToCombo2(HWND hwnd, HDC hdc, const LOGFONTW *lplf) -{ -#define FSTYLES 4 - struct FONTSTYLE - { - int italic; - int weight; - const WCHAR *stname; - }; - static const WCHAR strRegular[] = {'R','e','g','u','l','a','r',0}; - static const WCHAR strItalic[] = {'I','t','a','l','i','c',0}; - static const WCHAR strBold[] = {'B','o','l','d',0}; - static const WCHAR strBoldItalic[] = {'B','o','l','d',' ','I','t','a','l','i','c',0}; - static const struct FONTSTYLE fontstyles[FSTYLES]={ - { 0, FW_NORMAL, strRegular }, - { 1, FW_NORMAL, strItalic }, - { 0, FW_BOLD, strBold }, - { 1, FW_BOLD, strBoldItalic } - }; - HFONT hf; - TEXTMETRICW tm; - int i,j; - LOGFONTW lf; - - memcpy(&lf, lplf, sizeof(LOGFONTW)); - - for (i=0;iFlags & CF_LIMITSIZE)) || - ((lpcf->Flags & CF_LIMITSIZE) && (h >= lpcf->nSizeMin) && (h <= lpcf->nSizeMax))) - { - wsprintfW(buffer, strFormat, h); - j=SendMessageW(hwnd, CB_FINDSTRINGEXACT, -1, (LPARAM)buffer); - if (j==CB_ERR) - { - j=SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)buffer); - if (j!=CB_ERR) j = SendMessageW(hwnd, CB_SETITEMDATA, j, h); - if (j==CB_ERR) return 1; - } - } - return 0; -} - -/************************************************************************* - * SetFontSizesToCombo3 [internal] - */ -static int SetFontSizesToCombo3(HWND hwnd, LPCHOOSEFONTW lpcf) -{ - static const BYTE sizes[]={8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72}; - int i; - - for (i = 0; i < sizeof(sizes)/sizeof(sizes[0]); i++) - if (AddFontSizeToCombo3(hwnd, sizes[i], lpcf)) return 1; - return 0; -} - -/************************************************************************* - * CFn_GetDC [internal] - */ -inline HDC CFn_GetDC(LPCHOOSEFONTW lpcf) -{ - HDC ret = ((lpcf->Flags & CF_PRINTERFONTS) && lpcf->hDC) ? - lpcf->hDC : - GetDC(0); - if(!ret) ERR("HDC failure!!!\n"); - return ret; -} - -/************************************************************************* - * CFn_ReleaseDC [internal] - */ -inline void CFn_ReleaseDC(LPCHOOSEFONTW lpcf, HDC hdc) -{ - if(!((lpcf->Flags & CF_PRINTERFONTS) && lpcf->hDC)) - ReleaseDC(0, hdc); -} - -/*********************************************************************** - * AddFontStyle [internal] - */ -INT AddFontStyle( const ENUMLOGFONTEXW *lpElfex, const NEWTEXTMETRICEXW *lpNTM, - UINT nFontType, LPCHOOSEFONTW lpcf, HWND hcmb2, HWND hcmb3, - HWND hDlg, BOOL iswin16) -{ - int i; - const LOGFONTW *lplf = &(lpElfex->elfLogFont); - HWND hcmb5; - HDC hdc; - - TRACE("(nFontType=%d)\n",nFontType); - TRACE(" %s h=%ld w=%ld e=%ld o=%ld wg=%ld i=%d u=%d s=%d" - " ch=%d op=%d cp=%d q=%d pf=%xh\n", - debugstr_w(lplf->lfFaceName),lplf->lfHeight,lplf->lfWidth, - lplf->lfEscapement,lplf->lfOrientation, - lplf->lfWeight,lplf->lfItalic,lplf->lfUnderline, - lplf->lfStrikeOut,lplf->lfCharSet, lplf->lfOutPrecision, - lplf->lfClipPrecision,lplf->lfQuality, lplf->lfPitchAndFamily); - if (nFontType & RASTER_FONTTYPE) - { - INT points; - if(!(hdc = CFn_GetDC(lpcf))) return 0; - points = MulDiv( lpNTM->ntmTm.tmHeight - lpNTM->ntmTm.tmInternalLeading, - 72, GetDeviceCaps(hdc, LOGPIXELSY)); - CFn_ReleaseDC(lpcf, hdc); - i = AddFontSizeToCombo3(hcmb3, points, lpcf); - if(i) return 0; - } else if (SetFontSizesToCombo3(hcmb3, lpcf)) return 0; - - if (!SendMessageW(hcmb2, CB_GETCOUNT, 0, 0)) - { - if(!(hdc = CFn_GetDC(lpcf))) return 0; - i=SetFontStylesToCombo2(hcmb2,hdc,lplf); - CFn_ReleaseDC(lpcf, hdc); - if (i) - return 0; - } - if( iswin16 || !( hcmb5 = GetDlgItem(hDlg, cmb5))) return 1; - i = SendMessageW( hcmb5, CB_FINDSTRINGEXACT, 0, - (LPARAM)lpElfex->elfScript); - if( i == CB_ERR) { - i = SendMessageW( hcmb5, CB_ADDSTRING, 0, - (LPARAM)lpElfex->elfScript); - if( i != CB_ERR) - SendMessageW( hcmb5, CB_SETITEMDATA, i, lplf->lfCharSet); - } - return 1 ; -} - -static INT CFn_FitFontSize( HWND hDlg, int points) -{ - int i,n; - int ret = 0; - /* look for fitting font size in combobox3 */ - n=SendDlgItemMessageW(hDlg, cmb3, CB_GETCOUNT, 0, 0); - for (i=0;ihWnd1; - HWND hcmb3=s->hWnd2; - HWND hDlg=GetParent(hcmb3); - return AddFontStyle( lpElfex, (const NEWTEXTMETRICEXW *) metrics, - dwFontType, s->lpcf32w, hcmb2, hcmb3, hDlg, FALSE); -} - -/*********************************************************************** - * CFn_WMInitDialog [internal] - */ -LRESULT CFn_WMInitDialog(HWND hDlg, WPARAM wParam, LPARAM lParam, - LPCHOOSEFONTW lpcf) -{ - HDC hdc; - int i,j,init=0; - long pstyle; - CFn_ENUMSTRUCT s; - LPLOGFONTW lpxx; - HCURSOR hcursor=SetCursor(LoadCursorW(0,(LPWSTR)IDC_WAIT)); - static const WCHAR strColorName[] = {'[','c','o','l','o','r',' ','n','a','m','e',']',0}; - - SetPropW(hDlg, strWineFontData, (HANDLE)lpcf); - lpxx=lpcf->lpLogFont; - TRACE("WM_INITDIALOG lParam=%08lX\n", lParam); - - if (lpcf->lStructSize != sizeof(CHOOSEFONTW)) - { - ERR("structure size failure !!!\n"); - EndDialog (hDlg, 0); - return FALSE; - } - if (!himlTT) - himlTT = ImageList_LoadImageW( COMDLG32_hInstance, MAKEINTRESOURCEW(38), - TTBITMAP_XSIZE, 0, CLR_DEFAULT, IMAGE_BITMAP, 0); - - if (!(lpcf->Flags & CF_SHOWHELP) || !IsWindow(lpcf->hwndOwner)) - ShowWindow(GetDlgItem(hDlg,pshHelp),SW_HIDE); - if (!(lpcf->Flags & CF_APPLY)) - ShowWindow(GetDlgItem(hDlg,psh3),SW_HIDE); - if (lpcf->Flags & CF_EFFECTS) - { - for (i=0;irgbColors) - SendDlgItemMessageW(hDlg,cmb4, CB_SETCURSEL,j,0); - } - } - else - { - ShowWindow(GetDlgItem(hDlg,cmb4),SW_HIDE); - ShowWindow(GetDlgItem(hDlg,chx1),SW_HIDE); - ShowWindow(GetDlgItem(hDlg,chx2),SW_HIDE); - ShowWindow(GetDlgItem(hDlg,grp1),SW_HIDE); - ShowWindow(GetDlgItem(hDlg,stc4),SW_HIDE); - } - if(!(hdc = CFn_GetDC(lpcf))) - { - EndDialog (hDlg, 0); - return FALSE; - } - s.hWnd1=GetDlgItem(hDlg,cmb1); - s.lpcf32w=lpcf; - do { - LOGFONTW elf; - s.added = 0; - elf.lfCharSet = DEFAULT_CHARSET; /* enum all charsets */ - elf.lfPitchAndFamily = 0; - elf.lfFaceName[0] = '\0'; /* enum all fonts */ - if (!EnumFontFamiliesExW(hdc, &elf, (FONTENUMPROCW)FontFamilyEnumProc, (LPARAM)&s, 0)) - { - TRACE("EnumFontFamiliesEx returns 0\n"); - break; - } - if (s.added) break; - if (lpcf->Flags & CF_FIXEDPITCHONLY) { - FIXME("No font found with fixed pitch only, dropping flag.\n"); - lpcf->Flags &= ~CF_FIXEDPITCHONLY; - continue; - } - if (lpcf->Flags & CF_TTONLY) { - FIXME("No font found with truetype only, dropping flag.\n"); - lpcf->Flags &= ~CF_TTONLY; - continue; - } - break; - } while (1); - - - if (lpcf->Flags & CF_INITTOLOGFONTSTRUCT) - { - /* look for fitting font name in combobox1 */ - j=SendDlgItemMessageW(hDlg,cmb1,CB_FINDSTRING,-1,(LONG)lpxx->lfFaceName); - if (j!=CB_ERR) - { - INT height = lpxx->lfHeight < 0 ? -lpxx->lfHeight : - lpxx->lfHeight; - INT points; - int charset = lpxx->lfCharSet; - points = MulDiv( height, 72, GetDeviceCaps(hdc, LOGPIXELSY)); - pstyle = MAKELONG(lpxx->lfWeight > FW_MEDIUM ? FW_BOLD: - FW_NORMAL,lpxx->lfItalic !=0); - SendDlgItemMessageW(hDlg, cmb1, CB_SETCURSEL, j, 0); - SendMessageW(hDlg, WM_COMMAND, MAKEWPARAM(cmb1, CBN_SELCHANGE), - (LPARAM)GetDlgItem(hDlg,cmb1)); - init=1; - /* look for fitting font style in combobox2 */ - CFn_FitFontStyle(hDlg, pstyle); - /* look for fitting font size in combobox3 */ - CFn_FitFontSize(hDlg, points); - CFn_FitCharSet( hDlg, charset ); - } - } - if (!init) - { - SendDlgItemMessageW(hDlg,cmb1,CB_SETCURSEL,0,0); - SendMessageW(hDlg, WM_COMMAND, MAKEWPARAM(cmb1, CBN_SELCHANGE), - (LPARAM)GetDlgItem(hDlg,cmb1)); - } - if ((lpcf->Flags & CF_USESTYLE) && lpcf->lpszStyle) - { - j=SendDlgItemMessageW(hDlg,cmb2,CB_FINDSTRING,-1,(LONG)lpcf->lpszStyle); - if (j!=CB_ERR) - { - j=SendDlgItemMessageW(hDlg,cmb2,CB_SETCURSEL,j,0); - SendMessageW(hDlg,WM_COMMAND,cmb2, - MAKELONG(HWND_16(GetDlgItem(hDlg,cmb2)),CBN_SELCHANGE)); - } - } - CFn_ReleaseDC(lpcf, hdc); - SetCursor(hcursor); - return TRUE; -} - - -/*********************************************************************** - * CFn_WMMeasureItem [internal] - */ -LRESULT CFn_WMMeasureItem(HWND hDlg, WPARAM wParam, LPARAM lParam) -{ - HDC hdc; - HFONT hfontprev; - TEXTMETRICW tm; - LPMEASUREITEMSTRUCT lpmi=(LPMEASUREITEMSTRUCT)lParam; - if (!himlTT) - himlTT = ImageList_LoadImageW( COMDLG32_hInstance, MAKEINTRESOURCEW(38), - TTBITMAP_XSIZE, 0, CLR_DEFAULT, IMAGE_BITMAP, 0); - ImageList_GetIconSize( himlTT, 0, &lpmi->itemHeight); - lpmi->itemHeight += 2; - /* use MAX of bitmap height and tm.tmHeight .*/ - hdc=GetDC(hDlg); - if(!hdc) return 0; - hfontprev = SelectObject( hdc, GetStockObject( SYSTEM_FONT)); - GetTextMetricsW(hdc, &tm); - if( tm.tmHeight > lpmi->itemHeight) lpmi->itemHeight = tm.tmHeight; - SelectObject(hdc, hfontprev); - ReleaseDC(hDlg, hdc); - return 0; -} - - -/*********************************************************************** - * CFn_WMDrawItem [internal] - */ -LRESULT CFn_WMDrawItem(HWND hDlg, WPARAM wParam, LPARAM lParam) -{ - HBRUSH hBrush; - WCHAR buffer[40]; - COLORREF cr, oldText=0, oldBk=0; - RECT rect; - int nFontType; - int idx; - LPDRAWITEMSTRUCT lpdi = (LPDRAWITEMSTRUCT)lParam; - - if (lpdi->itemID == (UINT)-1) /* got no items */ - DrawFocusRect(lpdi->hDC, &lpdi->rcItem); - else - { - if (lpdi->CtlType == ODT_COMBOBOX) - { - if (lpdi->itemState & ODS_SELECTED) - { - hBrush=GetSysColorBrush(COLOR_HIGHLIGHT); - oldText=SetTextColor(lpdi->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); - oldBk=SetBkColor(lpdi->hDC, GetSysColor(COLOR_HIGHLIGHT)); - } else - { - hBrush = SelectObject(lpdi->hDC, GetStockObject(LTGRAY_BRUSH)); - SelectObject(lpdi->hDC, hBrush); - } - FillRect(lpdi->hDC, &lpdi->rcItem, hBrush); - } - else - return TRUE; /* this should never happen */ - - rect=lpdi->rcItem; - switch (lpdi->CtlID) - { - case cmb1: - /* TRACE(commdlg,"WM_Drawitem cmb1\n"); */ - SendMessageW(lpdi->hwndItem, CB_GETLBTEXT, lpdi->itemID, - (LPARAM)buffer); - TextOutW(lpdi->hDC, lpdi->rcItem.left + TTBITMAP_XSIZE + 10, - lpdi->rcItem.top, buffer, lstrlenW(buffer)); - nFontType = SendMessageW(lpdi->hwndItem, CB_GETITEMDATA, lpdi->itemID,0L); - idx = -1; - if (nFontType & TRUETYPE_FONTTYPE) { - idx = 0; /* picture: TT */ - if( nFontType & NTM_TT_OPENTYPE) - idx = 2; /* picture: O */ - } else if( nFontType & NTM_PS_OPENTYPE) - idx = 3; /* picture: O+ps */ - else if( nFontType & NTM_TYPE1) - idx = 4; /* picture: a */ - else if( nFontType & DEVICE_FONTTYPE) - idx = 1; /* picture: printer */ - if( idx >= 0) - ImageList_Draw( himlTT, idx, lpdi->hDC, lpdi->rcItem.left, - lpdi->rcItem.top, ILD_TRANSPARENT); - break; - case cmb2: - case cmb3: - /* TRACE(commdlg,"WM_DRAWITEN cmb2,cmb3\n"); */ - case cmb5: - SendMessageW(lpdi->hwndItem, CB_GETLBTEXT, lpdi->itemID, - (LPARAM)buffer); - TextOutW(lpdi->hDC, lpdi->rcItem.left, - lpdi->rcItem.top, buffer, lstrlenW(buffer)); - break; - - case cmb4: - /* TRACE(commdlg,"WM_DRAWITEM cmb4 (=COLOR)\n"); */ - SendMessageW(lpdi->hwndItem, CB_GETLBTEXT, lpdi->itemID, - (LPARAM)buffer); - TextOutW(lpdi->hDC, lpdi->rcItem.left + 25+5, - lpdi->rcItem.top, buffer, lstrlenW(buffer)); - cr = SendMessageW(lpdi->hwndItem, CB_GETITEMDATA, lpdi->itemID,0L); - hBrush = CreateSolidBrush(cr); - if (hBrush) - { - hBrush = SelectObject (lpdi->hDC, hBrush) ; - rect.right=rect.left+25; - rect.top++; - rect.left+=5; - rect.bottom--; - Rectangle( lpdi->hDC, rect.left, rect.top, - rect.right, rect.bottom ); - DeleteObject( SelectObject (lpdi->hDC, hBrush)) ; - } - rect=lpdi->rcItem; - rect.left+=25+5; - break; - - default: - return TRUE; /* this should never happen */ - } - if (lpdi->itemState & ODS_SELECTED) - { - SetTextColor(lpdi->hDC, oldText); - SetBkColor(lpdi->hDC, oldBk); - } - } - return TRUE; -} - -/*********************************************************************** - * CFn_WMCommand [internal] - */ -LRESULT CFn_WMCommand(HWND hDlg, WPARAM wParam, LPARAM lParam, - LPCHOOSEFONTW lpcf) -{ - int i; - long l; - HDC hdc; - LPLOGFONTW lpxx=lpcf->lpLogFont; - - TRACE("WM_COMMAND wParam=%08lX lParam=%08lX\n", (LONG)wParam, lParam); - switch (LOWORD(wParam)) - { - case cmb1: - if (HIWORD(wParam)==CBN_SELCHANGE) - { - INT pointsize; /* save current pointsize */ - LONG pstyle; /* save current style */ - int charset; - int idx; - if(!(hdc = CFn_GetDC(lpcf))) - { - EndDialog (hDlg, 0); - return TRUE; - } - idx = SendDlgItemMessageW(hDlg, cmb3, CB_GETCURSEL, 0, 0); - pointsize = (int)SendDlgItemMessageW( hDlg, cmb3, CB_GETITEMDATA, - idx, 0); - idx = SendDlgItemMessageW(hDlg, cmb2, CB_GETCURSEL, 0, 0); - pstyle = SendDlgItemMessageW(hDlg, cmb2, CB_GETITEMDATA, idx, 0); - idx = SendDlgItemMessageW(hDlg, cmb5, CB_GETCURSEL, 0, 0); - charset = SendDlgItemMessageW(hDlg, cmb5, CB_GETITEMDATA, idx, 0); - - SendDlgItemMessageW(hDlg, cmb2, CB_RESETCONTENT, 0, 0); - SendDlgItemMessageW(hDlg, cmb3, CB_RESETCONTENT, 0, 0); - SendDlgItemMessageW(hDlg, cmb5, CB_RESETCONTENT, 0, 0); - i=SendDlgItemMessageW(hDlg, cmb1, CB_GETCURSEL, 0, 0); - if (i!=CB_ERR) - { - HCURSOR hcursor=SetCursor(LoadCursorW(0,(LPWSTR)IDC_WAIT)); - CFn_ENUMSTRUCT s; - LOGFONTW enumlf; - SendDlgItemMessageW(hDlg, cmb1, CB_GETLBTEXT, i, - (LPARAM)enumlf.lfFaceName); - TRACE("WM_COMMAND/cmb1 =>%s\n", debugstr_w(enumlf.lfFaceName)); - s.hWnd1=GetDlgItem(hDlg, cmb2); - s.hWnd2=GetDlgItem(hDlg, cmb3); - s.lpcf32w=lpcf; - enumlf.lfCharSet = DEFAULT_CHARSET; /* enum all charsets */ - enumlf.lfPitchAndFamily = 0; - EnumFontFamiliesExW(hdc, &enumlf, - (FONTENUMPROCW)FontStyleEnumProc, (LPARAM)&s, 0); - CFn_FitFontStyle(hDlg, pstyle); - if( pointsize != CB_ERR) CFn_FitFontSize(hDlg, pointsize); - if( charset != CB_ERR) CFn_FitCharSet( hDlg, charset ); - SetCursor(hcursor); - } - CFn_ReleaseDC(lpcf, hdc); - } - case chx1: - case chx2: - case cmb2: - case cmb3: - case cmb5: - if (HIWORD(wParam)==CBN_SELCHANGE || HIWORD(wParam)== BN_CLICKED ) - { - WCHAR str[256]; - WINDOWINFO wininfo; - - TRACE("WM_COMMAND/cmb2,3 =%08lX\n", lParam); - i=SendDlgItemMessageW(hDlg,cmb1,CB_GETCURSEL,0,0); - if (i==CB_ERR) - i=GetDlgItemTextW( hDlg, cmb1, str, 256 ); - else - { - SendDlgItemMessageW(hDlg,cmb1,CB_GETLBTEXT,i, - (LPARAM)str); - l=SendDlgItemMessageW(hDlg,cmb1,CB_GETITEMDATA,i,0); - lpcf->nFontType = LOWORD(l); - /* FIXME: lpcf->nFontType |= .... SIMULATED_FONTTYPE and so */ - /* same value reported to the EnumFonts - call back with the extra FONTTYPE_... bits added */ - lpxx->lfPitchAndFamily = HIWORD(l) >> 8; - } - lstrcpyW(lpxx->lfFaceName,str); - i=SendDlgItemMessageW(hDlg, cmb2, CB_GETCURSEL, 0, 0); - if (i!=CB_ERR) - { - l=SendDlgItemMessageW(hDlg, cmb2, CB_GETITEMDATA, i, 0); - if (0!=(lpxx->lfItalic=HIWORD(l))) - lpcf->nFontType |= ITALIC_FONTTYPE; - if ((lpxx->lfWeight=LOWORD(l)) > FW_MEDIUM) - lpcf->nFontType |= BOLD_FONTTYPE; - } - i=SendDlgItemMessageW(hDlg, cmb3, CB_GETCURSEL, 0, 0); - if( i != CB_ERR) - lpcf->iPointSize = 10 * LOWORD(SendDlgItemMessageW(hDlg, cmb3, - CB_GETITEMDATA , i, 0)); - else - lpcf->iPointSize = 100; - hdc = CFn_GetDC(lpcf); - if( hdc) - { - lpxx->lfHeight = - MulDiv( lpcf->iPointSize , - GetDeviceCaps(hdc, LOGPIXELSY), 720); - CFn_ReleaseDC(lpcf, hdc); - } else - lpxx->lfHeight = -lpcf->iPointSize / 10; - i=SendDlgItemMessageW(hDlg, cmb5, CB_GETCURSEL, 0, 0); - if (i!=CB_ERR) - lpxx->lfCharSet=SendDlgItemMessageW(hDlg, cmb5, CB_GETITEMDATA, i, 0); - else - lpxx->lfCharSet = DEFAULT_CHARSET; - lpxx->lfStrikeOut=IsDlgButtonChecked(hDlg,chx1); - lpxx->lfUnderline=IsDlgButtonChecked(hDlg,chx2); - lpxx->lfWidth=lpxx->lfOrientation=lpxx->lfEscapement=0; - lpxx->lfOutPrecision=OUT_DEFAULT_PRECIS; - lpxx->lfClipPrecision=CLIP_DEFAULT_PRECIS; - lpxx->lfQuality=DEFAULT_QUALITY; - - wininfo.cbSize=sizeof(wininfo); - - if( GetWindowInfo( GetDlgItem( hDlg, stc5), &wininfo ) ) - { - MapWindowPoints( 0, hDlg, (LPPOINT) &wininfo.rcWindow, 2); - InvalidateRect( hDlg, &wininfo.rcWindow, TRUE ); - } - } - break; - - case cmb4: - i=SendDlgItemMessageW(hDlg, cmb4, CB_GETCURSEL, 0, 0); - if (i!=CB_ERR) - { - WINDOWINFO wininfo; - - lpcf->rgbColors=textcolors[i]; - wininfo.cbSize=sizeof(wininfo); - - if( GetWindowInfo( GetDlgItem( hDlg, stc5), &wininfo ) ) - { - MapWindowPoints( 0, hDlg, (LPPOINT) &wininfo.rcWindow, 2); - InvalidateRect( hDlg, &wininfo.rcWindow, TRUE ); - } - } - break; - - case psh15: - i=RegisterWindowMessageW( HELPMSGSTRINGW ); - if (lpcf->hwndOwner) - SendMessageW(lpcf->hwndOwner, i, 0, (LPARAM)GetPropW(hDlg, strWineFontData)); - /* if (CFn_HookCallChk(lpcf)) - CallWindowProc16(lpcf->lpfnHook,hDlg,WM_COMMAND,psh15,(LPARAM)lpcf);*/ - break; - - case IDOK: - if ( (!(lpcf->Flags & CF_LIMITSIZE)) || - ( (lpcf->Flags & CF_LIMITSIZE) && - (lpcf->iPointSize >= 10 * lpcf->nSizeMin) && - (lpcf->iPointSize <= 10 * lpcf->nSizeMax))) - EndDialog(hDlg, TRUE); - else - { - WCHAR buffer[80]; - WCHAR format[80]; - LoadStringW(COMDLG32_hInstance, IDS_FONT_SIZE, format, sizeof(format)/sizeof(WCHAR)); - wsprintfW(buffer, format, lpcf->nSizeMin,lpcf->nSizeMax); - MessageBoxW(hDlg, buffer, NULL, MB_OK); - } - return(TRUE); - case IDCANCEL: - EndDialog(hDlg, FALSE); - return(TRUE); - } - return(FALSE); -} - -LRESULT CFn_WMDestroy(HWND hwnd, WPARAM wParam, LPARAM lParam, LPCHOOSEFONTW lpcfw) -{ - LPCHOOSEFONTA lpcfa; - LPSTR lpszStyle; - LPLOGFONTA lpLogFonta; - int len; - - lpcfa = GetPropW(hwnd, strWineFontData_a); - lpLogFonta = lpcfa->lpLogFont; - lpszStyle = lpcfa->lpszStyle; - memcpy(lpcfa, lpcfw, sizeof(CHOOSEFONTA)); - lpcfa->lpLogFont = lpLogFonta; - lpcfa->lpszStyle = lpszStyle; - memcpy(lpcfa->lpLogFont, lpcfw->lpLogFont, sizeof(LOGFONTA)); - WideCharToMultiByte(CP_ACP, 0, lpcfw->lpLogFont->lfFaceName, - LF_FACESIZE, lpcfa->lpLogFont->lfFaceName, LF_FACESIZE, 0, 0); - - if((lpcfw->Flags & CF_USESTYLE) && lpcfw->lpszStyle) { - len = WideCharToMultiByte(CP_ACP, 0, lpcfw->lpszStyle, -1, NULL, -1, 0, 0); - WideCharToMultiByte(CP_ACP, 0, lpcfw->lpszStyle, -1, lpcfa->lpszStyle, len, 0, 0); - HeapFree(GetProcessHeap(), 0, lpcfw->lpszStyle); - } - - HeapFree(GetProcessHeap(), 0, lpcfw->lpLogFont); - HeapFree(GetProcessHeap(), 0, lpcfw); - SetPropW(hwnd, strWineFontData, 0); - - return TRUE; -} - -LRESULT CFn_WMPaint(HWND hDlg, WPARAM wParam, LPARAM lParam, LPCHOOSEFONTW lpcf) -{ - WINDOWINFO info; - - info.cbSize=sizeof(info); - if( GetWindowInfo( GetDlgItem( hDlg, stc5), &info ) ) - { - PAINTSTRUCT ps; - HDC hdc; - HPEN hOrigPen; - HFONT hOrigFont; - COLORREF rgbPrev; - LOGFONTW lf = *(lpcf->lpLogFont); - - MapWindowPoints( 0, hDlg, (LPPOINT) &info.rcWindow, 2); - hdc = BeginPaint( hDlg, &ps ); - - TRACE("erase %d, rect=(%ld,%ld)-(%ld,%ld)\n", ps.fErase, - ps.rcPaint.left, ps.rcPaint.top, - ps.rcPaint.right, ps.rcPaint.bottom); - - /* Paint frame */ - MoveToEx( hdc, info.rcWindow.left, info.rcWindow.bottom, NULL ); - hOrigPen=SelectObject( hdc, CreatePen( PS_SOLID, 2, - GetSysColor( COLOR_3DSHADOW ) )); - LineTo( hdc, info.rcWindow.left, info.rcWindow.top ); - LineTo( hdc, info.rcWindow.right, info.rcWindow.top ); - DeleteObject(SelectObject( hdc, CreatePen( PS_SOLID, 2, - GetSysColor( COLOR_3DLIGHT ) ))); - LineTo( hdc, info.rcWindow.right, info.rcWindow.bottom ); - LineTo( hdc, info.rcWindow.left, info.rcWindow.bottom ); - DeleteObject(SelectObject( hdc, hOrigPen )); - - /* Draw the sample text itself */ - info.rcWindow.right--; - info.rcWindow.bottom--; - info.rcWindow.top++; - info.rcWindow.left++; - hOrigFont = SelectObject( hdc, CreateFontIndirectW( &lf ) ); - rgbPrev=SetTextColor( hdc, lpcf->rgbColors ); - - DrawTextW( hdc, - sample_lang_text[CHARSET_ORDER[lpcf->lpLogFont->lfCharSet]], - -1, &info.rcWindow, DT_CENTER|DT_VCENTER|DT_SINGLELINE ); - - DeleteObject(SelectObject( hdc, hOrigFont )); - EndPaint( hDlg, &ps ); - } - return FALSE; -} - -/*********************************************************************** - * FormatCharDlgProcA [internal] - */ -INT_PTR CALLBACK FormatCharDlgProcA(HWND hDlg, UINT uMsg, WPARAM wParam, - LPARAM lParam) -{ - LPCHOOSEFONTW lpcfw; - LPCHOOSEFONTA lpcfa; - INT_PTR res = FALSE; - int len; - - if (uMsg!=WM_INITDIALOG) { - lpcfw = (LPCHOOSEFONTW)GetPropW(hDlg, strWineFontData); - if (!lpcfw) - return FALSE; - if (CFn_HookCallChk32(lpcfw)) - res=CallWindowProcA((WNDPROC)lpcfw->lpfnHook, hDlg, uMsg, wParam, lParam); - if (res) - return res; - } else { - lpcfa=(LPCHOOSEFONTA)lParam; - SetPropW(hDlg, strWineFontData_a, (HANDLE)lParam); - - lpcfw = HeapAlloc(GetProcessHeap(), 0, sizeof(CHOOSEFONTW)); - memcpy(lpcfw, lpcfa, sizeof(CHOOSEFONTA)); - lpcfw->lpLogFont = HeapAlloc(GetProcessHeap(), 0, sizeof(LOGFONTW)); - memcpy(lpcfw->lpLogFont, lpcfa->lpLogFont, sizeof(LOGFONTA)); - MultiByteToWideChar(CP_ACP, 0, lpcfa->lpLogFont->lfFaceName, - LF_FACESIZE, lpcfw->lpLogFont->lfFaceName, LF_FACESIZE); - - if((lpcfa->Flags & CF_USESTYLE) && lpcfa->lpszStyle) { - len = MultiByteToWideChar(CP_ACP, 0, lpcfa->lpszStyle, -1, NULL, 0); - lpcfw->lpszStyle = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpcfa->lpszStyle, -1, lpcfw->lpszStyle, len); - } - - if (!CFn_WMInitDialog(hDlg, wParam, lParam, lpcfw)) - { - TRACE("CFn_WMInitDialog returned FALSE\n"); - return FALSE; - } - if (CFn_HookCallChk32(lpcfw)) - return CallWindowProcA((WNDPROC)lpcfa->lpfnHook,hDlg,WM_INITDIALOG,wParam,lParam); - } - switch (uMsg) - { - case WM_MEASUREITEM: - return CFn_WMMeasureItem(hDlg, wParam, lParam); - case WM_DRAWITEM: - return CFn_WMDrawItem(hDlg, wParam, lParam); - case WM_COMMAND: - return CFn_WMCommand(hDlg, wParam, lParam, lpcfw); - case WM_DESTROY: - return CFn_WMDestroy(hDlg, wParam, lParam, lpcfw); - case WM_CHOOSEFONT_GETLOGFONT: - TRACE("WM_CHOOSEFONT_GETLOGFONT lParam=%08lX\n", lParam); - FIXME("current logfont back to caller\n"); - break; - case WM_PAINT: - return CFn_WMPaint(hDlg, wParam, lParam, lpcfw); - } - return res; -} - -/*********************************************************************** - * FormatCharDlgProcW [internal] - */ -INT_PTR CALLBACK FormatCharDlgProcW(HWND hDlg, UINT uMsg, WPARAM wParam, - LPARAM lParam) -{ - LPCHOOSEFONTW lpcf; - INT_PTR res = FALSE; - - if (uMsg!=WM_INITDIALOG) - { - lpcf=(LPCHOOSEFONTW)GetPropW(hDlg, strWineFontData); - if (!lpcf) - return FALSE; - if (CFn_HookCallChk32(lpcf)) - res=CallWindowProcW((WNDPROC)lpcf->lpfnHook, hDlg, uMsg, wParam, lParam); - if (res) - return res; - } - else - { - lpcf=(LPCHOOSEFONTW)lParam; - if (!CFn_WMInitDialog(hDlg, wParam, lParam, lpcf)) - { - TRACE("CFn_WMInitDialog returned FALSE\n"); - return FALSE; - } - if (CFn_HookCallChk32(lpcf)) - return CallWindowProcW((WNDPROC)lpcf->lpfnHook,hDlg,WM_INITDIALOG,wParam,lParam); - } - switch (uMsg) - { - case WM_MEASUREITEM: - return CFn_WMMeasureItem(hDlg, wParam, lParam); - case WM_DRAWITEM: - return CFn_WMDrawItem(hDlg, wParam, lParam); - case WM_COMMAND: - return CFn_WMCommand(hDlg, wParam, lParam, lpcf); - case WM_DESTROY: - return TRUE; - case WM_CHOOSEFONT_GETLOGFONT: - TRACE("WM_CHOOSEFONT_GETLOGFONT lParam=%08lX\n", lParam); - FIXME("current logfont back to caller\n"); - break; - case WM_PAINT: - return CFn_WMPaint(hDlg, wParam, lParam, lpcf); - } - return res; -} +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "wingdi.h" +#include "winuser.h" +#include "commdlg.h" +#include "dlgs.h" +#include "wine/debug.h" +#include "cderr.h" + +WINE_DEFAULT_DEBUG_CHANNEL(commdlg); + +static const WCHAR strWineFontData[] = {'_','_','W','I','N','E','_','F','O','N','T','D','L','G','D','A','T','A',0}; +static const WCHAR strWineFontData_a[] = + {'_','_','W','I','N','E','_','F','O','N','T','D','L','G','D','A','T','A','_','A',0}; +static const WCHAR chooseFontW[] = {'C','H','O','O','S','E','_','F','O','N','T',0}; + +#include "cdlg.h" + +/* image list with TrueType bitmaps and more */ +static HIMAGELIST himlTT = 0; +#define TTBITMAP_XSIZE 20 /* x-size of the bitmaps */ + +INT_PTR CALLBACK FormatCharDlgProcA(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +INT_PTR CALLBACK FormatCharDlgProcW(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); + +/* There is a table here of all charsets, and the sample text for each. + * There is a second table that translates a charset into an index into + * the first table. + */ + +#define CI(cs) ((IDS_CHARSET_##cs)-IDS_CHARSET_ANSI) + + +static const WCHAR stWestern[]={'A','a','B','b','Y','y','Z','z',0}; /* Western and default */ +static const WCHAR stSymbol[]={'S','y','m','b','o','l',0}; /* Symbol */ +static const WCHAR stShiftJis[]={'A','a',0x3042,0x3041,0x30a2,0x30a1,0x4e9c,0x5b87,0}; /* Shift JIS */ +static const WCHAR stHangul[]={0xac00,0xb098,0xb2e4,'A','a','B','Y','y','Z','z',0}; /* Hangul */ +static const WCHAR stGB2312[]={0x5fae,0x8f6f,0x4e2d,0x6587,0x8f6f,0x4ef6,0}; /* GB2312 */ +static const WCHAR stBIG5[]={0x4e2d,0x6587,0x5b57,0x578b,0x7bc4,0x4f8b,0}; /* BIG5 */ +static const WCHAR stGreek[]={'A','a','B','b',0x0391,0x03b1,0x0392,0x03b2,0}; /* Greek */ +static const WCHAR stTurkish[]={'A','a','B','b',0x011e,0x011f,0x015e,0x015f,0}; /* Turkish */ +static const WCHAR stHebrew[]={'A','a','B','b',0x05e0,0x05e1,0x05e9,0x05ea,0}; /* Hebrew */ +static const WCHAR stArabic[]={'A','a','B','b',0x0627,0x0628,0x062c,0x062f,0x0647,0x0648,0x0632,0};/* Arabic */ +static const WCHAR stBaltic[]={'A','a','B','b','Y','y','Z','z',0}; /* Baltic */ +static const WCHAR stVietname[]={'A','a','B','b',0x01a0,0x01a1,0x01af,0x01b0,0}; /* Vietnamese */ +static const WCHAR stCyrillic[]={'A','a','B','b',0x0411,0x0431,0x0424,0x0444,0}; /* Cyrillic */ +static const WCHAR stEastEur[]={'A','a','B','b',0xc1,0xe1,0xd4,0xf4,0}; /* East European */ +static const WCHAR stThai[]={'A','a','B','b',0x0e2d,0x0e31,0x0e01,0x0e29,0x0e23,0x0e44,0x0e17,0x0e22,0}; /* Thai */ +static const WCHAR stJohab[]={0xac00,0xb098,0xb2e4,'A','a','B','Y','y','Z','z',0}; /* Johab */ +static const WCHAR stMac[]={'A','a','B','b','Y','y','Z','z',0}; /* Mac */ +static const WCHAR stOEM[]={'A','a','B','b',0xf8,0xf1,0xfd,0}; /* OEM */ +/* the following character sets actually behave different (Win2K observation): + * the sample string is 'sticky': it uses the sample string of the previous + * selected character set. That behaviour looks like some default, which is + * not (yet) implemented. */ +static const WCHAR stVISCII[]={'A','a','B','b',0}; /* VISCII */ +static const WCHAR stTCVN[]={'A','a','B','b',0}; /* TCVN */ +static const WCHAR stKOI8[]={'A','a','B','b',0}; /* KOI-8 */ +static const WCHAR stIso88593[]={'A','a','B','b',0}; /* ISO-8859-3 */ +static const WCHAR stIso88594[]={'A','a','B','b',0}; /* ISO-8859-4 */ +static const WCHAR stIso885910[]={'A','a','B','b',0}; /* ISO-8859-10 */ +static const WCHAR stCeltic[]={'A','a','B','b',0};/* Celtic */ + +static const WCHAR *sample_lang_text[]={ + stWestern,stSymbol,stShiftJis,stHangul,stGB2312, + stBIG5,stGreek,stTurkish,stHebrew,stArabic, + stBaltic,stVietname,stCyrillic,stEastEur,stThai, + stJohab,stMac,stOEM,stVISCII,stTCVN, + stKOI8,stIso88593,stIso88594,stIso885910,stCeltic}; + + +static const BYTE CHARSET_ORDER[256]={ + CI(ANSI), 0, CI(SYMBOL), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, CI(MAC), 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + CI(JIS), CI(HANGUL), CI(JOHAB), 0, 0, 0, CI(GB2312), 0, CI(BIG5), 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, CI(GREEK), CI(TURKISH), CI(VIETNAMESE), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, CI(HEBREW), CI(ARABIC), 0, 0, 0, 0, 0, 0, 0, CI(BALTIC), 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, CI(RUSSIAN), 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, CI(THAI), 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, CI(EE), 0, + CI(VISCII), CI(TCVN), CI(KOI8), CI(ISO3), CI(ISO4), CI(ISO10), CI(CELTIC), 0, 0, 0, 0, 0, 0, 0, 0, CI(OEM), +}; + +static const struct { + DWORD mask; + const char *name; +} cfflags[] = { +#define XX(x) { x, #x }, + XX(CF_SCREENFONTS) + XX(CF_PRINTERFONTS) + XX(CF_SHOWHELP) + XX(CF_ENABLEHOOK) + XX(CF_ENABLETEMPLATE) + XX(CF_ENABLETEMPLATEHANDLE) + XX(CF_INITTOLOGFONTSTRUCT) + XX(CF_USESTYLE) + XX(CF_EFFECTS) + XX(CF_APPLY) + XX(CF_ANSIONLY) + XX(CF_NOVECTORFONTS) + XX(CF_NOSIMULATIONS) + XX(CF_LIMITSIZE) + XX(CF_FIXEDPITCHONLY) + XX(CF_WYSIWYG) + XX(CF_FORCEFONTEXIST) + XX(CF_SCALABLEONLY) + XX(CF_TTONLY) + XX(CF_NOFACESEL) + XX(CF_NOSTYLESEL) + XX(CF_NOSIZESEL) + XX(CF_SELECTSCRIPT) + XX(CF_NOSCRIPTSEL) + XX(CF_NOVERTFONTS) +#undef XX +}; + +void _dump_cf_flags(DWORD cflags) +{ + int i; + + for (i = 0; i < sizeof(cfflags)/sizeof(cfflags[0]); i++) + if (cfflags[i].mask & cflags) + TRACE("%s|",cfflags[i].name); + TRACE("\n"); +} + +/*********************************************************************** + * ChooseFontW (COMDLG32.@) + */ +BOOL WINAPI ChooseFontW(LPCHOOSEFONTW lpChFont) +{ + LPCVOID template; + HRSRC hResInfo; + HINSTANCE hDlginst; + HGLOBAL hDlgTmpl; + + TRACE("(%p)\n", lpChFont); + + if ( (lpChFont->Flags&CF_ENABLETEMPLATEHANDLE)!=0 ) + { + template=(LPCVOID)lpChFont->hInstance; + } else + { + if ( (lpChFont->Flags&CF_ENABLETEMPLATE)!=0 ) + { + hDlginst=lpChFont->hInstance; + if( !(hResInfo = FindResourceW(hDlginst, lpChFont->lpTemplateName, + (LPWSTR)RT_DIALOG))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); + return FALSE; + } + } else + { + hDlginst=COMDLG32_hInstance; + if (!(hResInfo = FindResourceW(hDlginst, chooseFontW, (LPWSTR)RT_DIALOG))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); + return FALSE; + } + } + if (!(hDlgTmpl = LoadResource(hDlginst, hResInfo )) || + !(template = LockResource( hDlgTmpl ))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + } + if (TRACE_ON(commdlg)) + _dump_cf_flags(lpChFont->Flags); + + if (lpChFont->Flags & (CF_SELECTSCRIPT | CF_NOVERTFONTS )) + FIXME(": unimplemented flag (ignored)\n"); + + return DialogBoxIndirectParamW(COMDLG32_hInstance, template, + lpChFont->hwndOwner, FormatCharDlgProcW, (LPARAM)lpChFont ); +} + +/*********************************************************************** + * ChooseFontA (COMDLG32.@) + */ +BOOL WINAPI ChooseFontA(LPCHOOSEFONTA lpChFont) +{ + LPCVOID template; + HRSRC hResInfo; + HINSTANCE hDlginst; + HGLOBAL hDlgTmpl; + + TRACE("(%p)\n", lpChFont); + + if ( (lpChFont->Flags&CF_ENABLETEMPLATEHANDLE)!=0 ) + { + template=(LPCVOID)lpChFont->hInstance; + } else + { + if ( (lpChFont->Flags&CF_ENABLETEMPLATE)!=0 ) + { + hDlginst=lpChFont->hInstance; + if( !(hResInfo = FindResourceA(hDlginst, lpChFont->lpTemplateName, + (LPSTR)RT_DIALOG))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); + return FALSE; + } + } else + { + hDlginst=COMDLG32_hInstance; + if (!(hResInfo = FindResourceW(hDlginst, chooseFontW, (LPWSTR)RT_DIALOG))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); + return FALSE; + } + } + if (!(hDlgTmpl = LoadResource(hDlginst, hResInfo )) || + !(template = LockResource( hDlgTmpl ))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + } + if (TRACE_ON(commdlg)) + _dump_cf_flags(lpChFont->Flags); + if (lpChFont->Flags & (CF_SELECTSCRIPT | CF_NOVERTFONTS )) + FIXME(": unimplemented flag (ignored)\n"); + + return DialogBoxIndirectParamA(COMDLG32_hInstance, template, + lpChFont->hwndOwner, FormatCharDlgProcA, (LPARAM)lpChFont ); +} + +#define TEXT_EXTRAS 4 +#define TEXT_COLORS 16 + +static const COLORREF textcolors[TEXT_COLORS]= +{ + 0x00000000L,0x00000080L,0x00008000L,0x00008080L, + 0x00800000L,0x00800080L,0x00808000L,0x00808080L, + 0x00c0c0c0L,0x000000ffL,0x0000ff00L,0x0000ffffL, + 0x00ff0000L,0x00ff00ffL,0x00ffff00L,0x00FFFFFFL +}; + +/*********************************************************************** + * CFn_HookCallChk32 [internal] + */ +static BOOL CFn_HookCallChk32(LPCHOOSEFONTW lpcf) +{ + if (lpcf) + if(lpcf->Flags & CF_ENABLEHOOK) + if (lpcf->lpfnHook) + return TRUE; + return FALSE; +} + +/************************************************************************* + * AddFontFamily [internal] + */ +INT AddFontFamily(const ENUMLOGFONTEXW *lpElfex, const NEWTEXTMETRICEXW *lpNTM, + UINT nFontType, LPCHOOSEFONTW lpcf, HWND hwnd, LPCFn_ENUMSTRUCT e) +{ + int i; + WORD w; + const LOGFONTW *lplf = &(lpElfex->elfLogFont); + + TRACE("font=%s (nFontType=%d)\n", debugstr_w(lplf->lfFaceName), nFontType); + + if (lpcf->Flags & CF_FIXEDPITCHONLY) + if (!(lplf->lfPitchAndFamily & FIXED_PITCH)) + return 1; + if (lpcf->Flags & CF_ANSIONLY) + if (lplf->lfCharSet != ANSI_CHARSET) + return 1; + if (lpcf->Flags & CF_TTONLY) + if (!(nFontType & TRUETYPE_FONTTYPE)) + return 1; + + if (e) e->added++; + + i=SendMessageW(hwnd, CB_FINDSTRINGEXACT, 0, (LPARAM)lplf->lfFaceName); + if (i == CB_ERR) { + i = SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)lplf->lfFaceName); + if( i != CB_ERR) { + /* store some important font information */ + w = (lplf->lfPitchAndFamily) << 8 | + (HIWORD(lpNTM->ntmTm.ntmFlags) & 0xff); + SendMessageW(hwnd, CB_SETITEMDATA, i, MAKELONG(nFontType,w)); + } + } + return 1; +} + +/************************************************************************* + * FontFamilyEnumProc32 [internal] + */ +static INT WINAPI FontFamilyEnumProc(const ENUMLOGFONTEXW *lpElfex, + const TEXTMETRICW *metrics, DWORD dwFontType, LPARAM lParam) +{ + LPCFn_ENUMSTRUCT e; + e=(LPCFn_ENUMSTRUCT)lParam; + return AddFontFamily( lpElfex, (NEWTEXTMETRICEXW *) metrics, + dwFontType, e->lpcf32w, e->hWnd1, e); +} + +/************************************************************************* + * SetFontStylesToCombo2 [internal] + * + * Fill font style information into combobox (without using font.c directly) + */ +static int SetFontStylesToCombo2(HWND hwnd, HDC hdc, const LOGFONTW *lplf) +{ +#define FSTYLES 4 + struct FONTSTYLE + { + int italic; + int weight; + const WCHAR *stname; + }; + static const WCHAR strRegular[] = {'R','e','g','u','l','a','r',0}; + static const WCHAR strItalic[] = {'I','t','a','l','i','c',0}; + static const WCHAR strBold[] = {'B','o','l','d',0}; + static const WCHAR strBoldItalic[] = {'B','o','l','d',' ','I','t','a','l','i','c',0}; + static const struct FONTSTYLE fontstyles[FSTYLES]={ + { 0, FW_NORMAL, strRegular }, + { 1, FW_NORMAL, strItalic }, + { 0, FW_BOLD, strBold }, + { 1, FW_BOLD, strBoldItalic } + }; + HFONT hf; + TEXTMETRICW tm; + int i,j; + LOGFONTW lf; + + memcpy(&lf, lplf, sizeof(LOGFONTW)); + + for (i=0;iFlags & CF_LIMITSIZE)) || + ((lpcf->Flags & CF_LIMITSIZE) && (h >= lpcf->nSizeMin) && (h <= lpcf->nSizeMax))) + { + wsprintfW(buffer, strFormat, h); + j=SendMessageW(hwnd, CB_FINDSTRINGEXACT, -1, (LPARAM)buffer); + if (j==CB_ERR) + { + j=SendMessageW(hwnd, CB_ADDSTRING, 0, (LPARAM)buffer); + if (j!=CB_ERR) j = SendMessageW(hwnd, CB_SETITEMDATA, j, h); + if (j==CB_ERR) return 1; + } + } + return 0; +} + +/************************************************************************* + * SetFontSizesToCombo3 [internal] + */ +static int SetFontSizesToCombo3(HWND hwnd, LPCHOOSEFONTW lpcf) +{ + static const BYTE sizes[]={8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72}; + int i; + + for (i = 0; i < sizeof(sizes)/sizeof(sizes[0]); i++) + if (AddFontSizeToCombo3(hwnd, sizes[i], lpcf)) return 1; + return 0; +} + +/************************************************************************* + * CFn_GetDC [internal] + */ +inline HDC CFn_GetDC(LPCHOOSEFONTW lpcf) +{ + HDC ret = ((lpcf->Flags & CF_PRINTERFONTS) && lpcf->hDC) ? + lpcf->hDC : + GetDC(0); + if(!ret) ERR("HDC failure!!!\n"); + return ret; +} + +/************************************************************************* + * CFn_ReleaseDC [internal] + */ +inline void CFn_ReleaseDC(LPCHOOSEFONTW lpcf, HDC hdc) +{ + if(!((lpcf->Flags & CF_PRINTERFONTS) && lpcf->hDC)) + ReleaseDC(0, hdc); +} + +/*********************************************************************** + * AddFontStyle [internal] + */ +INT AddFontStyle( const ENUMLOGFONTEXW *lpElfex, const NEWTEXTMETRICEXW *lpNTM, + UINT nFontType, LPCHOOSEFONTW lpcf, HWND hcmb2, HWND hcmb3, + HWND hDlg, BOOL iswin16) +{ + int i; + const LOGFONTW *lplf = &(lpElfex->elfLogFont); + HWND hcmb5; + HDC hdc; + + TRACE("(nFontType=%d)\n",nFontType); + TRACE(" %s h=%ld w=%ld e=%ld o=%ld wg=%ld i=%d u=%d s=%d" + " ch=%d op=%d cp=%d q=%d pf=%xh\n", + debugstr_w(lplf->lfFaceName),lplf->lfHeight,lplf->lfWidth, + lplf->lfEscapement,lplf->lfOrientation, + lplf->lfWeight,lplf->lfItalic,lplf->lfUnderline, + lplf->lfStrikeOut,lplf->lfCharSet, lplf->lfOutPrecision, + lplf->lfClipPrecision,lplf->lfQuality, lplf->lfPitchAndFamily); + if (nFontType & RASTER_FONTTYPE) + { + INT points; + if(!(hdc = CFn_GetDC(lpcf))) return 0; + points = MulDiv( lpNTM->ntmTm.tmHeight - lpNTM->ntmTm.tmInternalLeading, + 72, GetDeviceCaps(hdc, LOGPIXELSY)); + CFn_ReleaseDC(lpcf, hdc); + i = AddFontSizeToCombo3(hcmb3, points, lpcf); + if(i) return 0; + } else if (SetFontSizesToCombo3(hcmb3, lpcf)) return 0; + + if (!SendMessageW(hcmb2, CB_GETCOUNT, 0, 0)) + { + if(!(hdc = CFn_GetDC(lpcf))) return 0; + i=SetFontStylesToCombo2(hcmb2,hdc,lplf); + CFn_ReleaseDC(lpcf, hdc); + if (i) + return 0; + } + if( iswin16 || !( hcmb5 = GetDlgItem(hDlg, cmb5))) return 1; + i = SendMessageW( hcmb5, CB_FINDSTRINGEXACT, 0, + (LPARAM)lpElfex->elfScript); + if( i == CB_ERR) { + i = SendMessageW( hcmb5, CB_ADDSTRING, 0, + (LPARAM)lpElfex->elfScript); + if( i != CB_ERR) + SendMessageW( hcmb5, CB_SETITEMDATA, i, lplf->lfCharSet); + } + return 1 ; +} + +static INT CFn_FitFontSize( HWND hDlg, int points) +{ + int i,n; + int ret = 0; + /* look for fitting font size in combobox3 */ + n=SendDlgItemMessageW(hDlg, cmb3, CB_GETCOUNT, 0, 0); + for (i=0;ihWnd1; + HWND hcmb3=s->hWnd2; + HWND hDlg=GetParent(hcmb3); + return AddFontStyle( lpElfex, (const NEWTEXTMETRICEXW *) metrics, + dwFontType, s->lpcf32w, hcmb2, hcmb3, hDlg, FALSE); +} + +/*********************************************************************** + * CFn_WMInitDialog [internal] + */ +LRESULT CFn_WMInitDialog(HWND hDlg, WPARAM wParam, LPARAM lParam, + LPCHOOSEFONTW lpcf) +{ + HDC hdc; + int i,j,init=0; + long pstyle; + CFn_ENUMSTRUCT s; + LPLOGFONTW lpxx; + HCURSOR hcursor=SetCursor(LoadCursorW(0,(LPWSTR)IDC_WAIT)); + static const WCHAR strColorName[] = {'[','c','o','l','o','r',' ','n','a','m','e',']',0}; + + SetPropW(hDlg, strWineFontData, (HANDLE)lpcf); + lpxx=lpcf->lpLogFont; + TRACE("WM_INITDIALOG lParam=%08lX\n", lParam); + + if (lpcf->lStructSize != sizeof(CHOOSEFONTW)) + { + ERR("structure size failure !!!\n"); + EndDialog (hDlg, 0); + return FALSE; + } + if (!himlTT) + himlTT = ImageList_LoadImageW( COMDLG32_hInstance, MAKEINTRESOURCEW(38), + TTBITMAP_XSIZE, 0, CLR_DEFAULT, IMAGE_BITMAP, 0); + + if (!(lpcf->Flags & CF_SHOWHELP) || !IsWindow(lpcf->hwndOwner)) + ShowWindow(GetDlgItem(hDlg,pshHelp),SW_HIDE); + if (!(lpcf->Flags & CF_APPLY)) + ShowWindow(GetDlgItem(hDlg,psh3),SW_HIDE); + if (lpcf->Flags & CF_EFFECTS) + { + for (i=0;irgbColors) + SendDlgItemMessageW(hDlg,cmb4, CB_SETCURSEL,j,0); + } + } + else + { + ShowWindow(GetDlgItem(hDlg,cmb4),SW_HIDE); + ShowWindow(GetDlgItem(hDlg,chx1),SW_HIDE); + ShowWindow(GetDlgItem(hDlg,chx2),SW_HIDE); + ShowWindow(GetDlgItem(hDlg,grp1),SW_HIDE); + ShowWindow(GetDlgItem(hDlg,stc4),SW_HIDE); + } + if(!(hdc = CFn_GetDC(lpcf))) + { + EndDialog (hDlg, 0); + return FALSE; + } + s.hWnd1=GetDlgItem(hDlg,cmb1); + s.lpcf32w=lpcf; + do { + LOGFONTW elf; + s.added = 0; + elf.lfCharSet = DEFAULT_CHARSET; /* enum all charsets */ + elf.lfPitchAndFamily = 0; + elf.lfFaceName[0] = '\0'; /* enum all fonts */ + if (!EnumFontFamiliesExW(hdc, &elf, (FONTENUMPROCW)FontFamilyEnumProc, (LPARAM)&s, 0)) + { + TRACE("EnumFontFamiliesEx returns 0\n"); + break; + } + if (s.added) break; + if (lpcf->Flags & CF_FIXEDPITCHONLY) { + FIXME("No font found with fixed pitch only, dropping flag.\n"); + lpcf->Flags &= ~CF_FIXEDPITCHONLY; + continue; + } + if (lpcf->Flags & CF_TTONLY) { + FIXME("No font found with truetype only, dropping flag.\n"); + lpcf->Flags &= ~CF_TTONLY; + continue; + } + break; + } while (1); + + + if (lpcf->Flags & CF_INITTOLOGFONTSTRUCT) + { + /* look for fitting font name in combobox1 */ + j=SendDlgItemMessageW(hDlg,cmb1,CB_FINDSTRING,-1,(LONG)lpxx->lfFaceName); + if (j!=CB_ERR) + { + INT height = lpxx->lfHeight < 0 ? -lpxx->lfHeight : + lpxx->lfHeight; + INT points; + int charset = lpxx->lfCharSet; + points = MulDiv( height, 72, GetDeviceCaps(hdc, LOGPIXELSY)); + pstyle = MAKELONG(lpxx->lfWeight > FW_MEDIUM ? FW_BOLD: + FW_NORMAL,lpxx->lfItalic !=0); + SendDlgItemMessageW(hDlg, cmb1, CB_SETCURSEL, j, 0); + SendMessageW(hDlg, WM_COMMAND, MAKEWPARAM(cmb1, CBN_SELCHANGE), + (LPARAM)GetDlgItem(hDlg,cmb1)); + init=1; + /* look for fitting font style in combobox2 */ + CFn_FitFontStyle(hDlg, pstyle); + /* look for fitting font size in combobox3 */ + CFn_FitFontSize(hDlg, points); + CFn_FitCharSet( hDlg, charset ); + } + } + if (!init) + { + SendDlgItemMessageW(hDlg,cmb1,CB_SETCURSEL,0,0); + SendMessageW(hDlg, WM_COMMAND, MAKEWPARAM(cmb1, CBN_SELCHANGE), + (LPARAM)GetDlgItem(hDlg,cmb1)); + } + if ((lpcf->Flags & CF_USESTYLE) && lpcf->lpszStyle) + { + j=SendDlgItemMessageW(hDlg,cmb2,CB_FINDSTRING,-1,(LONG)lpcf->lpszStyle); + if (j!=CB_ERR) + { + j=SendDlgItemMessageW(hDlg,cmb2,CB_SETCURSEL,j,0); + SendMessageW(hDlg,WM_COMMAND,cmb2, + MAKELONG(HWND_16(GetDlgItem(hDlg,cmb2)),CBN_SELCHANGE)); + } + } + CFn_ReleaseDC(lpcf, hdc); + SetCursor(hcursor); + return TRUE; +} + + +/*********************************************************************** + * CFn_WMMeasureItem [internal] + */ +LRESULT CFn_WMMeasureItem(HWND hDlg, WPARAM wParam, LPARAM lParam) +{ + HDC hdc; + HFONT hfontprev; + TEXTMETRICW tm; + LPMEASUREITEMSTRUCT lpmi=(LPMEASUREITEMSTRUCT)lParam; + if (!himlTT) + himlTT = ImageList_LoadImageW( COMDLG32_hInstance, MAKEINTRESOURCEW(38), + TTBITMAP_XSIZE, 0, CLR_DEFAULT, IMAGE_BITMAP, 0); + ImageList_GetIconSize( himlTT, 0, &lpmi->itemHeight); + lpmi->itemHeight += 2; + /* use MAX of bitmap height and tm.tmHeight .*/ + hdc=GetDC(hDlg); + if(!hdc) return 0; + hfontprev = SelectObject( hdc, GetStockObject( SYSTEM_FONT)); + GetTextMetricsW(hdc, &tm); + if( tm.tmHeight > lpmi->itemHeight) lpmi->itemHeight = tm.tmHeight; + SelectObject(hdc, hfontprev); + ReleaseDC(hDlg, hdc); + return 0; +} + + +/*********************************************************************** + * CFn_WMDrawItem [internal] + */ +LRESULT CFn_WMDrawItem(HWND hDlg, WPARAM wParam, LPARAM lParam) +{ + HBRUSH hBrush; + WCHAR buffer[40]; + COLORREF cr, oldText=0, oldBk=0; + RECT rect; + int nFontType; + int idx; + LPDRAWITEMSTRUCT lpdi = (LPDRAWITEMSTRUCT)lParam; + + if (lpdi->itemID == (UINT)-1) /* got no items */ + DrawFocusRect(lpdi->hDC, &lpdi->rcItem); + else + { + if (lpdi->CtlType == ODT_COMBOBOX) + { + if (lpdi->itemState & ODS_SELECTED) + { + hBrush=GetSysColorBrush(COLOR_HIGHLIGHT); + oldText=SetTextColor(lpdi->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT)); + oldBk=SetBkColor(lpdi->hDC, GetSysColor(COLOR_HIGHLIGHT)); + } else + { + hBrush = SelectObject(lpdi->hDC, GetStockObject(LTGRAY_BRUSH)); + SelectObject(lpdi->hDC, hBrush); + } + FillRect(lpdi->hDC, &lpdi->rcItem, hBrush); + } + else + return TRUE; /* this should never happen */ + + rect=lpdi->rcItem; + switch (lpdi->CtlID) + { + case cmb1: + /* TRACE(commdlg,"WM_Drawitem cmb1\n"); */ + SendMessageW(lpdi->hwndItem, CB_GETLBTEXT, lpdi->itemID, + (LPARAM)buffer); + TextOutW(lpdi->hDC, lpdi->rcItem.left + TTBITMAP_XSIZE + 10, + lpdi->rcItem.top, buffer, lstrlenW(buffer)); + nFontType = SendMessageW(lpdi->hwndItem, CB_GETITEMDATA, lpdi->itemID,0L); + idx = -1; + if (nFontType & TRUETYPE_FONTTYPE) { + idx = 0; /* picture: TT */ + if( nFontType & NTM_TT_OPENTYPE) + idx = 2; /* picture: O */ + } else if( nFontType & NTM_PS_OPENTYPE) + idx = 3; /* picture: O+ps */ + else if( nFontType & NTM_TYPE1) + idx = 4; /* picture: a */ + else if( nFontType & DEVICE_FONTTYPE) + idx = 1; /* picture: printer */ + if( idx >= 0) + ImageList_Draw( himlTT, idx, lpdi->hDC, lpdi->rcItem.left, + lpdi->rcItem.top, ILD_TRANSPARENT); + break; + case cmb2: + case cmb3: + /* TRACE(commdlg,"WM_DRAWITEN cmb2,cmb3\n"); */ + case cmb5: + SendMessageW(lpdi->hwndItem, CB_GETLBTEXT, lpdi->itemID, + (LPARAM)buffer); + TextOutW(lpdi->hDC, lpdi->rcItem.left, + lpdi->rcItem.top, buffer, lstrlenW(buffer)); + break; + + case cmb4: + /* TRACE(commdlg,"WM_DRAWITEM cmb4 (=COLOR)\n"); */ + SendMessageW(lpdi->hwndItem, CB_GETLBTEXT, lpdi->itemID, + (LPARAM)buffer); + TextOutW(lpdi->hDC, lpdi->rcItem.left + 25+5, + lpdi->rcItem.top, buffer, lstrlenW(buffer)); + cr = SendMessageW(lpdi->hwndItem, CB_GETITEMDATA, lpdi->itemID,0L); + hBrush = CreateSolidBrush(cr); + if (hBrush) + { + hBrush = SelectObject (lpdi->hDC, hBrush) ; + rect.right=rect.left+25; + rect.top++; + rect.left+=5; + rect.bottom--; + Rectangle( lpdi->hDC, rect.left, rect.top, + rect.right, rect.bottom ); + DeleteObject( SelectObject (lpdi->hDC, hBrush)) ; + } + rect=lpdi->rcItem; + rect.left+=25+5; + break; + + default: + return TRUE; /* this should never happen */ + } + if (lpdi->itemState & ODS_SELECTED) + { + SetTextColor(lpdi->hDC, oldText); + SetBkColor(lpdi->hDC, oldBk); + } + } + return TRUE; +} + +/*********************************************************************** + * CFn_WMCommand [internal] + */ +LRESULT CFn_WMCommand(HWND hDlg, WPARAM wParam, LPARAM lParam, + LPCHOOSEFONTW lpcf) +{ + int i; + long l; + HDC hdc; + LPLOGFONTW lpxx=lpcf->lpLogFont; + + TRACE("WM_COMMAND wParam=%08lX lParam=%08lX\n", (LONG)wParam, lParam); + switch (LOWORD(wParam)) + { + case cmb1: + if (HIWORD(wParam)==CBN_SELCHANGE) + { + INT pointsize; /* save current pointsize */ + LONG pstyle; /* save current style */ + int charset; + int idx; + if(!(hdc = CFn_GetDC(lpcf))) + { + EndDialog (hDlg, 0); + return TRUE; + } + idx = SendDlgItemMessageW(hDlg, cmb3, CB_GETCURSEL, 0, 0); + pointsize = (int)SendDlgItemMessageW( hDlg, cmb3, CB_GETITEMDATA, + idx, 0); + idx = SendDlgItemMessageW(hDlg, cmb2, CB_GETCURSEL, 0, 0); + pstyle = SendDlgItemMessageW(hDlg, cmb2, CB_GETITEMDATA, idx, 0); + idx = SendDlgItemMessageW(hDlg, cmb5, CB_GETCURSEL, 0, 0); + charset = SendDlgItemMessageW(hDlg, cmb5, CB_GETITEMDATA, idx, 0); + + SendDlgItemMessageW(hDlg, cmb2, CB_RESETCONTENT, 0, 0); + SendDlgItemMessageW(hDlg, cmb3, CB_RESETCONTENT, 0, 0); + SendDlgItemMessageW(hDlg, cmb5, CB_RESETCONTENT, 0, 0); + i=SendDlgItemMessageW(hDlg, cmb1, CB_GETCURSEL, 0, 0); + if (i!=CB_ERR) + { + HCURSOR hcursor=SetCursor(LoadCursorW(0,(LPWSTR)IDC_WAIT)); + CFn_ENUMSTRUCT s; + LOGFONTW enumlf; + SendDlgItemMessageW(hDlg, cmb1, CB_GETLBTEXT, i, + (LPARAM)enumlf.lfFaceName); + TRACE("WM_COMMAND/cmb1 =>%s\n", debugstr_w(enumlf.lfFaceName)); + s.hWnd1=GetDlgItem(hDlg, cmb2); + s.hWnd2=GetDlgItem(hDlg, cmb3); + s.lpcf32w=lpcf; + enumlf.lfCharSet = DEFAULT_CHARSET; /* enum all charsets */ + enumlf.lfPitchAndFamily = 0; + EnumFontFamiliesExW(hdc, &enumlf, + (FONTENUMPROCW)FontStyleEnumProc, (LPARAM)&s, 0); + CFn_FitFontStyle(hDlg, pstyle); + if( pointsize != CB_ERR) CFn_FitFontSize(hDlg, pointsize); + if( charset != CB_ERR) CFn_FitCharSet( hDlg, charset ); + SetCursor(hcursor); + } + CFn_ReleaseDC(lpcf, hdc); + } + case chx1: + case chx2: + case cmb2: + case cmb3: + case cmb5: + if (HIWORD(wParam)==CBN_SELCHANGE || HIWORD(wParam)== BN_CLICKED ) + { + WCHAR str[256]; + WINDOWINFO wininfo; + + TRACE("WM_COMMAND/cmb2,3 =%08lX\n", lParam); + i=SendDlgItemMessageW(hDlg,cmb1,CB_GETCURSEL,0,0); + if (i==CB_ERR) + i=GetDlgItemTextW( hDlg, cmb1, str, 256 ); + else + { + SendDlgItemMessageW(hDlg,cmb1,CB_GETLBTEXT,i, + (LPARAM)str); + l=SendDlgItemMessageW(hDlg,cmb1,CB_GETITEMDATA,i,0); + lpcf->nFontType = LOWORD(l); + /* FIXME: lpcf->nFontType |= .... SIMULATED_FONTTYPE and so */ + /* same value reported to the EnumFonts + call back with the extra FONTTYPE_... bits added */ + lpxx->lfPitchAndFamily = HIWORD(l) >> 8; + } + lstrcpyW(lpxx->lfFaceName,str); + i=SendDlgItemMessageW(hDlg, cmb2, CB_GETCURSEL, 0, 0); + if (i!=CB_ERR) + { + l=SendDlgItemMessageW(hDlg, cmb2, CB_GETITEMDATA, i, 0); + if (0!=(lpxx->lfItalic=HIWORD(l))) + lpcf->nFontType |= ITALIC_FONTTYPE; + if ((lpxx->lfWeight=LOWORD(l)) > FW_MEDIUM) + lpcf->nFontType |= BOLD_FONTTYPE; + } + i=SendDlgItemMessageW(hDlg, cmb3, CB_GETCURSEL, 0, 0); + if( i != CB_ERR) + lpcf->iPointSize = 10 * LOWORD(SendDlgItemMessageW(hDlg, cmb3, + CB_GETITEMDATA , i, 0)); + else + lpcf->iPointSize = 100; + hdc = CFn_GetDC(lpcf); + if( hdc) + { + lpxx->lfHeight = - MulDiv( lpcf->iPointSize , + GetDeviceCaps(hdc, LOGPIXELSY), 720); + CFn_ReleaseDC(lpcf, hdc); + } else + lpxx->lfHeight = -lpcf->iPointSize / 10; + i=SendDlgItemMessageW(hDlg, cmb5, CB_GETCURSEL, 0, 0); + if (i!=CB_ERR) + lpxx->lfCharSet=SendDlgItemMessageW(hDlg, cmb5, CB_GETITEMDATA, i, 0); + else + lpxx->lfCharSet = DEFAULT_CHARSET; + lpxx->lfStrikeOut=IsDlgButtonChecked(hDlg,chx1); + lpxx->lfUnderline=IsDlgButtonChecked(hDlg,chx2); + lpxx->lfWidth=lpxx->lfOrientation=lpxx->lfEscapement=0; + lpxx->lfOutPrecision=OUT_DEFAULT_PRECIS; + lpxx->lfClipPrecision=CLIP_DEFAULT_PRECIS; + lpxx->lfQuality=DEFAULT_QUALITY; + + wininfo.cbSize=sizeof(wininfo); + + if( GetWindowInfo( GetDlgItem( hDlg, stc5), &wininfo ) ) + { + MapWindowPoints( 0, hDlg, (LPPOINT) &wininfo.rcWindow, 2); + InvalidateRect( hDlg, &wininfo.rcWindow, TRUE ); + } + } + break; + + case cmb4: + i=SendDlgItemMessageW(hDlg, cmb4, CB_GETCURSEL, 0, 0); + if (i!=CB_ERR) + { + WINDOWINFO wininfo; + + lpcf->rgbColors=textcolors[i]; + wininfo.cbSize=sizeof(wininfo); + + if( GetWindowInfo( GetDlgItem( hDlg, stc5), &wininfo ) ) + { + MapWindowPoints( 0, hDlg, (LPPOINT) &wininfo.rcWindow, 2); + InvalidateRect( hDlg, &wininfo.rcWindow, TRUE ); + } + } + break; + + case psh15: + i=RegisterWindowMessageW( HELPMSGSTRINGW ); + if (lpcf->hwndOwner) + SendMessageW(lpcf->hwndOwner, i, 0, (LPARAM)GetPropW(hDlg, strWineFontData)); + /* if (CFn_HookCallChk(lpcf)) + CallWindowProc16(lpcf->lpfnHook,hDlg,WM_COMMAND,psh15,(LPARAM)lpcf);*/ + break; + + case IDOK: + if ( (!(lpcf->Flags & CF_LIMITSIZE)) || + ( (lpcf->Flags & CF_LIMITSIZE) && + (lpcf->iPointSize >= 10 * lpcf->nSizeMin) && + (lpcf->iPointSize <= 10 * lpcf->nSizeMax))) + EndDialog(hDlg, TRUE); + else + { + WCHAR buffer[80]; + WCHAR format[80]; + LoadStringW(COMDLG32_hInstance, IDS_FONT_SIZE, format, sizeof(format)/sizeof(WCHAR)); + wsprintfW(buffer, format, lpcf->nSizeMin,lpcf->nSizeMax); + MessageBoxW(hDlg, buffer, NULL, MB_OK); + } + return(TRUE); + case IDCANCEL: + EndDialog(hDlg, FALSE); + return(TRUE); + } + return(FALSE); +} + +LRESULT CFn_WMDestroy(HWND hwnd, WPARAM wParam, LPARAM lParam, LPCHOOSEFONTW lpcfw) +{ + LPCHOOSEFONTA lpcfa; + LPSTR lpszStyle; + LPLOGFONTA lpLogFonta; + int len; + + lpcfa = GetPropW(hwnd, strWineFontData_a); + lpLogFonta = lpcfa->lpLogFont; + lpszStyle = lpcfa->lpszStyle; + memcpy(lpcfa, lpcfw, sizeof(CHOOSEFONTA)); + lpcfa->lpLogFont = lpLogFonta; + lpcfa->lpszStyle = lpszStyle; + memcpy(lpcfa->lpLogFont, lpcfw->lpLogFont, sizeof(LOGFONTA)); + WideCharToMultiByte(CP_ACP, 0, lpcfw->lpLogFont->lfFaceName, + LF_FACESIZE, lpcfa->lpLogFont->lfFaceName, LF_FACESIZE, 0, 0); + + if((lpcfw->Flags & CF_USESTYLE) && lpcfw->lpszStyle) { + len = WideCharToMultiByte(CP_ACP, 0, lpcfw->lpszStyle, -1, NULL, -1, 0, 0); + WideCharToMultiByte(CP_ACP, 0, lpcfw->lpszStyle, -1, lpcfa->lpszStyle, len, 0, 0); + HeapFree(GetProcessHeap(), 0, lpcfw->lpszStyle); + } + + HeapFree(GetProcessHeap(), 0, lpcfw->lpLogFont); + HeapFree(GetProcessHeap(), 0, lpcfw); + SetPropW(hwnd, strWineFontData, 0); + + return TRUE; +} + +LRESULT CFn_WMPaint(HWND hDlg, WPARAM wParam, LPARAM lParam, LPCHOOSEFONTW lpcf) +{ + WINDOWINFO info; + + info.cbSize=sizeof(info); + if( GetWindowInfo( GetDlgItem( hDlg, stc5), &info ) ) + { + PAINTSTRUCT ps; + HDC hdc; + HPEN hOrigPen; + HFONT hOrigFont; + COLORREF rgbPrev; + LOGFONTW lf = *(lpcf->lpLogFont); + + MapWindowPoints( 0, hDlg, (LPPOINT) &info.rcWindow, 2); + hdc = BeginPaint( hDlg, &ps ); + + TRACE("erase %d, rect=(%ld,%ld)-(%ld,%ld)\n", ps.fErase, + ps.rcPaint.left, ps.rcPaint.top, + ps.rcPaint.right, ps.rcPaint.bottom); + + /* Paint frame */ + MoveToEx( hdc, info.rcWindow.left, info.rcWindow.bottom, NULL ); + hOrigPen=SelectObject( hdc, CreatePen( PS_SOLID, 2, + GetSysColor( COLOR_3DSHADOW ) )); + LineTo( hdc, info.rcWindow.left, info.rcWindow.top ); + LineTo( hdc, info.rcWindow.right, info.rcWindow.top ); + DeleteObject(SelectObject( hdc, CreatePen( PS_SOLID, 2, + GetSysColor( COLOR_3DLIGHT ) ))); + LineTo( hdc, info.rcWindow.right, info.rcWindow.bottom ); + LineTo( hdc, info.rcWindow.left, info.rcWindow.bottom ); + DeleteObject(SelectObject( hdc, hOrigPen )); + + /* Draw the sample text itself */ + info.rcWindow.right--; + info.rcWindow.bottom--; + info.rcWindow.top++; + info.rcWindow.left++; + hOrigFont = SelectObject( hdc, CreateFontIndirectW( &lf ) ); + rgbPrev=SetTextColor( hdc, lpcf->rgbColors ); + + DrawTextW( hdc, + sample_lang_text[CHARSET_ORDER[lpcf->lpLogFont->lfCharSet]], + -1, &info.rcWindow, DT_CENTER|DT_VCENTER|DT_SINGLELINE ); + + DeleteObject(SelectObject( hdc, hOrigFont )); + EndPaint( hDlg, &ps ); + } + return FALSE; +} + +/*********************************************************************** + * FormatCharDlgProcA [internal] + */ +INT_PTR CALLBACK FormatCharDlgProcA(HWND hDlg, UINT uMsg, WPARAM wParam, + LPARAM lParam) +{ + LPCHOOSEFONTW lpcfw; + LPCHOOSEFONTA lpcfa; + INT_PTR res = FALSE; + int len; + + if (uMsg!=WM_INITDIALOG) { + lpcfw = (LPCHOOSEFONTW)GetPropW(hDlg, strWineFontData); + if (!lpcfw) + return FALSE; + if (CFn_HookCallChk32(lpcfw)) + res=CallWindowProcA((WNDPROC)lpcfw->lpfnHook, hDlg, uMsg, wParam, lParam); + if (res) + return res; + } else { + lpcfa=(LPCHOOSEFONTA)lParam; + SetPropW(hDlg, strWineFontData_a, (HANDLE)lParam); + + lpcfw = HeapAlloc(GetProcessHeap(), 0, sizeof(CHOOSEFONTW)); + memcpy(lpcfw, lpcfa, sizeof(CHOOSEFONTA)); + lpcfw->lpLogFont = HeapAlloc(GetProcessHeap(), 0, sizeof(LOGFONTW)); + memcpy(lpcfw->lpLogFont, lpcfa->lpLogFont, sizeof(LOGFONTA)); + MultiByteToWideChar(CP_ACP, 0, lpcfa->lpLogFont->lfFaceName, + LF_FACESIZE, lpcfw->lpLogFont->lfFaceName, LF_FACESIZE); + + if((lpcfa->Flags & CF_USESTYLE) && lpcfa->lpszStyle) { + len = MultiByteToWideChar(CP_ACP, 0, lpcfa->lpszStyle, -1, NULL, 0); + lpcfw->lpszStyle = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, lpcfa->lpszStyle, -1, lpcfw->lpszStyle, len); + } + + if (!CFn_WMInitDialog(hDlg, wParam, lParam, lpcfw)) + { + TRACE("CFn_WMInitDialog returned FALSE\n"); + return FALSE; + } + if (CFn_HookCallChk32(lpcfw)) + return CallWindowProcA((WNDPROC)lpcfa->lpfnHook,hDlg,WM_INITDIALOG,wParam,lParam); + } + switch (uMsg) + { + case WM_MEASUREITEM: + return CFn_WMMeasureItem(hDlg, wParam, lParam); + case WM_DRAWITEM: + return CFn_WMDrawItem(hDlg, wParam, lParam); + case WM_COMMAND: + return CFn_WMCommand(hDlg, wParam, lParam, lpcfw); + case WM_DESTROY: + return CFn_WMDestroy(hDlg, wParam, lParam, lpcfw); + case WM_CHOOSEFONT_GETLOGFONT: + TRACE("WM_CHOOSEFONT_GETLOGFONT lParam=%08lX\n", lParam); + FIXME("current logfont back to caller\n"); + break; + case WM_PAINT: + return CFn_WMPaint(hDlg, wParam, lParam, lpcfw); + } + return res; +} + +/*********************************************************************** + * FormatCharDlgProcW [internal] + */ +INT_PTR CALLBACK FormatCharDlgProcW(HWND hDlg, UINT uMsg, WPARAM wParam, + LPARAM lParam) +{ + LPCHOOSEFONTW lpcf; + INT_PTR res = FALSE; + + if (uMsg!=WM_INITDIALOG) + { + lpcf=(LPCHOOSEFONTW)GetPropW(hDlg, strWineFontData); + if (!lpcf) + return FALSE; + if (CFn_HookCallChk32(lpcf)) + res=CallWindowProcW((WNDPROC)lpcf->lpfnHook, hDlg, uMsg, wParam, lParam); + if (res) + return res; + } + else + { + lpcf=(LPCHOOSEFONTW)lParam; + if (!CFn_WMInitDialog(hDlg, wParam, lParam, lpcf)) + { + TRACE("CFn_WMInitDialog returned FALSE\n"); + return FALSE; + } + if (CFn_HookCallChk32(lpcf)) + return CallWindowProcW((WNDPROC)lpcf->lpfnHook,hDlg,WM_INITDIALOG,wParam,lParam); + } + switch (uMsg) + { + case WM_MEASUREITEM: + return CFn_WMMeasureItem(hDlg, wParam, lParam); + case WM_DRAWITEM: + return CFn_WMDrawItem(hDlg, wParam, lParam); + case WM_COMMAND: + return CFn_WMCommand(hDlg, wParam, lParam, lpcf); + case WM_DESTROY: + return TRUE; + case WM_CHOOSEFONT_GETLOGFONT: + TRACE("WM_CHOOSEFONT_GETLOGFONT lParam=%08lX\n", lParam); + FIXME("current logfont back to caller\n"); + break; + case WM_PAINT: + return CFn_WMPaint(hDlg, wParam, lParam, lpcf); + } + return res; +} diff --git a/reactos/lib/comdlg32/fontdlg16.c b/reactos/lib/comdlg32/fontdlg16.c index 9bfcb77284c..84a51e929b4 100644 --- a/reactos/lib/comdlg32/fontdlg16.c +++ b/reactos/lib/comdlg32/fontdlg16.c @@ -1,373 +1,373 @@ -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "wine/winbase16.h" -#include "wine/winuser16.h" -#include "commdlg.h" -#include "dlgs.h" -#include "wine/debug.h" -#include "cderr.h" - -WINE_DEFAULT_DEBUG_CHANNEL(commdlg); - -#include "cdlg.h" -#include "cdlg16.h" - -static void FONT_LogFont16To32W( const LPLOGFONT16 font16, LPLOGFONTW 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 = font16->lfCharSet; - font32->lfOutPrecision = font16->lfOutPrecision; - font32->lfClipPrecision = font16->lfClipPrecision; - font32->lfQuality = font16->lfQuality; - font32->lfPitchAndFamily = font16->lfPitchAndFamily; - MultiByteToWideChar(CP_ACP, 0, font16->lfFaceName, - LF_FACESIZE, font32->lfFaceName, LF_FACESIZE); -}; - -static void FONT_Metrics16To32W( const TEXTMETRIC16 *pm16, - NEWTEXTMETRICEXW *pnm32w) -{ - ZeroMemory( pnm32w, sizeof(NEWTEXTMETRICEXW)); - /* NOTE: only the fields used by AddFontStyle() are filled in */ - pnm32w->ntmTm.tmHeight = pm16->tmHeight; - pnm32w->ntmTm.tmExternalLeading = pm16->tmExternalLeading; -}; - -static void CFn_CHOOSEFONT16to32W(LPCHOOSEFONT16 chf16, LPCHOOSEFONTW chf32w) -{ - int len; - if(chf16->lpTemplateName) - { - len = MultiByteToWideChar(CP_ACP, 0, (LPBYTE)chf16->lpTemplateName, -1, NULL, 0); - chf32w->lpTemplateName = HeapAlloc(GetProcessHeap(), 0,len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, (LPSTR)MapSL(chf16->lpTemplateName), - -1, (LPWSTR)chf32w->lpTemplateName, len); - } - if(chf16->lpszStyle) - { - len = MultiByteToWideChar(CP_ACP, 0, (LPBYTE)chf16->lpszStyle, -1, NULL, 0); - chf32w->lpszStyle = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, (LPSTR)MapSL(chf16->lpTemplateName), - -1, chf32w->lpszStyle, len); - } - chf32w->lStructSize=sizeof(CHOOSEFONTW); - chf32w->hwndOwner=HWND_32(chf16->hwndOwner); - chf32w->hDC=HDC_32(chf16->hDC); - chf32w->iPointSize=chf16->iPointSize; - chf32w->Flags=chf16->Flags; - chf32w->rgbColors=chf16->rgbColors; - chf32w->lCustData=chf16->lCustData; - chf32w->lpfnHook=NULL; - chf32w->hInstance=HINSTANCE_32(chf16->hInstance); - chf32w->lpszStyle=MapSL(chf16->lpszStyle); - chf32w->nFontType=chf16->nFontType; - chf32w->nSizeMax=chf16->nSizeMax; - chf32w->nSizeMin=chf16->nSizeMin; - FONT_LogFont16To32W(MapSL(chf16->lpLogFont), chf32w->lpLogFont); -}; - -/*********************************************************************** - * CFn_HookCallChk [internal] - */ -static BOOL CFn_HookCallChk(LPCHOOSEFONT16 lpcf) -{ - if (lpcf) - if(lpcf->Flags & CF_ENABLEHOOK) - if (lpcf->lpfnHook) - return TRUE; - return FALSE; -} - -/*********************************************************************** - * FontFamilyEnumProc (COMMDLG.19) - */ -INT16 WINAPI FontFamilyEnumProc16( SEGPTR logfont, SEGPTR metrics, - UINT16 nFontType, LPARAM lParam ) -{ - HWND hwnd=HWND_32(LOWORD(lParam)); - HWND hDlg=GetParent(hwnd); - LPCHOOSEFONT16 lpcf=(LPCHOOSEFONT16)GetWindowLongPtrW(hDlg, DWLP_USER); - LOGFONT16 *lplf = MapSL( logfont ); - TEXTMETRIC16 *lpmtrx16 = MapSL(metrics); - ENUMLOGFONTEXW elf32w; - NEWTEXTMETRICEXW nmtrx32w; - FONT_LogFont16To32W(lplf, &(elf32w.elfLogFont)); - FONT_Metrics16To32W(lpmtrx16, &nmtrx32w); - return AddFontFamily(&elf32w, &nmtrx32w, nFontType, - (LPCHOOSEFONTW)lpcf->lpTemplateName, hwnd,NULL); -} - -/*********************************************************************** - * FontStyleEnumProc (COMMDLG.18) - */ -INT16 WINAPI FontStyleEnumProc16( SEGPTR logfont, SEGPTR metrics, - UINT16 nFontType, LPARAM lParam ) -{ - HWND hcmb2=HWND_32(LOWORD(lParam)); - HWND hcmb3=HWND_32(HIWORD(lParam)); - HWND hDlg=GetParent(hcmb3); - LPCHOOSEFONT16 lpcf=(LPCHOOSEFONT16)GetWindowLongPtrW(hDlg, DWLP_USER); - LOGFONT16 *lplf = MapSL(logfont); - TEXTMETRIC16 *lpmtrx16 = MapSL(metrics); - ENUMLOGFONTEXW elf32w; - NEWTEXTMETRICEXW nmtrx32w; - FONT_LogFont16To32W(lplf, &(elf32w.elfLogFont)); - FONT_Metrics16To32W(lpmtrx16, &nmtrx32w); - return AddFontStyle(&elf32w, &nmtrx32w, nFontType, - (LPCHOOSEFONTW)lpcf->lpTemplateName, hcmb2, hcmb3, hDlg, TRUE); -} - -/*********************************************************************** - * ChooseFont (COMMDLG.15) - */ -BOOL16 WINAPI ChooseFont16(LPCHOOSEFONT16 lpChFont) -{ - HINSTANCE16 hInst; - HANDLE16 hDlgTmpl16 = 0, hResource16 = 0; - HGLOBAL16 hGlobal16 = 0; - BOOL16 bRet = FALSE; - LPCVOID template; - FARPROC16 ptr; - CHOOSEFONTW cf32w; - LOGFONTW lf32w; - LOGFONT16 *font16; - SEGPTR lpTemplateName; - - cf32w.lpLogFont=&lf32w; - CFn_CHOOSEFONT16to32W(lpChFont, &cf32w); - - TRACE("ChooseFont\n"); - if (!lpChFont) return FALSE; - - if (TRACE_ON(commdlg)) - _dump_cf_flags(lpChFont->Flags); - - if (lpChFont->Flags & CF_ENABLETEMPLATEHANDLE) - { - if (!(template = LockResource16( lpChFont->hInstance ))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - } - else if (lpChFont->Flags & CF_ENABLETEMPLATE) - { - HANDLE16 hResInfo; - if (!(hResInfo = FindResource16( lpChFont->hInstance, - MapSL(lpChFont->lpTemplateName), - (LPSTR)RT_DIALOG))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); - return FALSE; - } - if (!(hDlgTmpl16 = LoadResource16( lpChFont->hInstance, hResInfo )) || - !(template = LockResource16( hDlgTmpl16 ))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - } - else - { - HRSRC hResInfo; - HGLOBAL hDlgTmpl32; - LPCVOID template32; - DWORD size; - if (!(hResInfo = FindResourceA(COMDLG32_hInstance, "CHOOSE_FONT", (LPSTR)RT_DIALOG))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); - return FALSE; - } - if (!(hDlgTmpl32 = LoadResource(COMDLG32_hInstance, hResInfo)) || - !(template32 = LockResource(hDlgTmpl32))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - size = SizeofResource(COMDLG32_hInstance, hResInfo); - hGlobal16 = GlobalAlloc16(0, size); - if (!hGlobal16) - { - COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE); - ERR("alloc failure for %ld bytes\n", size); - return FALSE; - } - template = GlobalLock16(hGlobal16); - if (!template) - { - COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE); - ERR("global lock failure for %x handle\n", hGlobal16); - GlobalFree16(hGlobal16); - return FALSE; - } - ConvertDialog32To16((LPVOID)template32, size, (LPVOID)template); - hDlgTmpl16 = hGlobal16; - - } - - /* lpTemplateName is not used in the dialog */ - lpTemplateName=lpChFont->lpTemplateName; - lpChFont->lpTemplateName=(SEGPTR)&cf32w; - - ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 16); - hInst = GetWindowLongPtrA(HWND_32(lpChFont->hwndOwner), GWLP_HINSTANCE); - bRet = DialogBoxIndirectParam16(hInst, hDlgTmpl16, lpChFont->hwndOwner, - (DLGPROC16) ptr, (DWORD)lpChFont); - if (hResource16) FreeResource16(hDlgTmpl16); - if (hGlobal16) - { - GlobalUnlock16(hGlobal16); - GlobalFree16(hGlobal16); - } - lpChFont->lpTemplateName=lpTemplateName; - - lpChFont->iPointSize = cf32w.iPointSize; - lpChFont->Flags = cf32w.Flags; - lpChFont->rgbColors = cf32w.rgbColors; - lpChFont->lCustData = cf32w.lCustData; - lpChFont->nFontType = cf32w.nFontType; - - font16 = MapSL(lpChFont->lpLogFont); - font16->lfHeight = cf32w.lpLogFont->lfHeight; - font16->lfWidth = cf32w.lpLogFont->lfWidth; - font16->lfEscapement = cf32w.lpLogFont->lfEscapement; - font16->lfOrientation = cf32w.lpLogFont->lfOrientation; - font16->lfWeight = cf32w.lpLogFont->lfWeight; - font16->lfItalic = cf32w.lpLogFont->lfItalic; - font16->lfUnderline = cf32w.lpLogFont->lfUnderline; - font16->lfStrikeOut = cf32w.lpLogFont->lfStrikeOut; - font16->lfCharSet = cf32w.lpLogFont->lfCharSet; - font16->lfOutPrecision = cf32w.lpLogFont->lfOutPrecision; - font16->lfClipPrecision = cf32w.lpLogFont->lfClipPrecision; - font16->lfQuality = cf32w.lpLogFont->lfQuality; - font16->lfPitchAndFamily = cf32w.lpLogFont->lfPitchAndFamily; - WideCharToMultiByte(CP_ACP, 0, cf32w.lpLogFont->lfFaceName, - LF_FACESIZE, font16->lfFaceName, LF_FACESIZE, 0, 0); - - HeapFree(GetProcessHeap(), 0, (LPBYTE)cf32w.lpTemplateName); - HeapFree(GetProcessHeap(), 0, cf32w.lpszStyle); - - return bRet; -} - -/*********************************************************************** - * 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) -{ - HWND hDlg = HWND_32(hDlg16); - LPCHOOSEFONT16 lpcf; - BOOL16 res=0; - if (message!=WM_INITDIALOG) - { - lpcf=(LPCHOOSEFONT16)GetWindowLongPtrW(hDlg, DWLP_USER); - if (!lpcf && message != WM_MEASUREITEM) - return FALSE; - if (CFn_HookCallChk(lpcf)) - res=CallWindowProc16((WNDPROC16)lpcf->lpfnHook,hDlg16,message,wParam,lParam); - if (res) - return res; - } - else - { - lpcf=(LPCHOOSEFONT16)lParam; - if (!CFn_WMInitDialog(hDlg, wParam, lParam, (LPCHOOSEFONTW)lpcf->lpTemplateName)) - { - TRACE("CFn_WMInitDialog returned FALSE\n"); - return FALSE; - } - if (CFn_HookCallChk(lpcf)) - return CallWindowProc16((WNDPROC16)lpcf->lpfnHook,hDlg16,WM_INITDIALOG,wParam,lParam); - } - switch (message) - { - case WM_MEASUREITEM: - { - MEASUREITEMSTRUCT16* mis16 = MapSL(lParam); - MEASUREITEMSTRUCT mis; - mis.CtlType = mis16->CtlType; - mis.CtlID = mis16->CtlID; - mis.itemID = mis16->itemID; - mis.itemWidth = mis16->itemWidth; - mis.itemHeight = mis16->itemHeight; - mis.itemData = mis16->itemData; - res = CFn_WMMeasureItem(hDlg, wParam, (LPARAM)&mis); - mis16->itemWidth = (UINT16)mis.itemWidth; - mis16->itemHeight = (UINT16)mis.itemHeight; - } - break; - case WM_DRAWITEM: - { - DRAWITEMSTRUCT16* dis16 = MapSL(lParam); - DRAWITEMSTRUCT dis; - dis.CtlType = dis16->CtlType; - dis.CtlID = dis16->CtlID; - dis.itemID = dis16->itemID; - dis.itemAction = dis16->itemAction; - dis.itemState = dis16->itemState; - dis.hwndItem = HWND_32(dis16->hwndItem); - dis.hDC = HDC_32(dis16->hDC); - dis.itemData = dis16->itemData; - dis.rcItem.left = dis16->rcItem.left; - dis.rcItem.top = dis16->rcItem.top; - dis.rcItem.right = dis16->rcItem.right; - dis.rcItem.bottom = dis16->rcItem.bottom; - res = CFn_WMDrawItem(hDlg, wParam, (LPARAM)&dis); - } - break; - case WM_COMMAND: - res=CFn_WMCommand(hDlg, MAKEWPARAM( wParam, HIWORD(lParam) ), LOWORD(lParam), - (LPCHOOSEFONTW)lpcf->lpTemplateName); - break; - case WM_DESTROY: - return TRUE; - case WM_CHOOSEFONT_GETLOGFONT: - TRACE("WM_CHOOSEFONT_GETLOGFONT lParam=%08lX\n", lParam); - FIXME("current logfont back to caller\n"); - break; - case WM_PAINT: - res= CFn_WMPaint(hDlg, wParam, lParam, (LPCHOOSEFONTW)lpcf->lpTemplateName); - break; - } - return res; -} +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "wine/winbase16.h" +#include "wine/winuser16.h" +#include "commdlg.h" +#include "dlgs.h" +#include "wine/debug.h" +#include "cderr.h" + +WINE_DEFAULT_DEBUG_CHANNEL(commdlg); + +#include "cdlg.h" +#include "cdlg16.h" + +static void FONT_LogFont16To32W( const LPLOGFONT16 font16, LPLOGFONTW 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 = font16->lfCharSet; + font32->lfOutPrecision = font16->lfOutPrecision; + font32->lfClipPrecision = font16->lfClipPrecision; + font32->lfQuality = font16->lfQuality; + font32->lfPitchAndFamily = font16->lfPitchAndFamily; + MultiByteToWideChar(CP_ACP, 0, font16->lfFaceName, + LF_FACESIZE, font32->lfFaceName, LF_FACESIZE); +}; + +static void FONT_Metrics16To32W( const TEXTMETRIC16 *pm16, + NEWTEXTMETRICEXW *pnm32w) +{ + ZeroMemory( pnm32w, sizeof(NEWTEXTMETRICEXW)); + /* NOTE: only the fields used by AddFontStyle() are filled in */ + pnm32w->ntmTm.tmHeight = pm16->tmHeight; + pnm32w->ntmTm.tmExternalLeading = pm16->tmExternalLeading; +}; + +static void CFn_CHOOSEFONT16to32W(LPCHOOSEFONT16 chf16, LPCHOOSEFONTW chf32w) +{ + int len; + if(chf16->lpTemplateName) + { + len = MultiByteToWideChar(CP_ACP, 0, (LPBYTE)chf16->lpTemplateName, -1, NULL, 0); + chf32w->lpTemplateName = HeapAlloc(GetProcessHeap(), 0,len*sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, (LPSTR)MapSL(chf16->lpTemplateName), + -1, (LPWSTR)chf32w->lpTemplateName, len); + } + if(chf16->lpszStyle) + { + len = MultiByteToWideChar(CP_ACP, 0, (LPBYTE)chf16->lpszStyle, -1, NULL, 0); + chf32w->lpszStyle = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, (LPSTR)MapSL(chf16->lpTemplateName), + -1, chf32w->lpszStyle, len); + } + chf32w->lStructSize=sizeof(CHOOSEFONTW); + chf32w->hwndOwner=HWND_32(chf16->hwndOwner); + chf32w->hDC=HDC_32(chf16->hDC); + chf32w->iPointSize=chf16->iPointSize; + chf32w->Flags=chf16->Flags; + chf32w->rgbColors=chf16->rgbColors; + chf32w->lCustData=chf16->lCustData; + chf32w->lpfnHook=NULL; + chf32w->hInstance=HINSTANCE_32(chf16->hInstance); + chf32w->lpszStyle=MapSL(chf16->lpszStyle); + chf32w->nFontType=chf16->nFontType; + chf32w->nSizeMax=chf16->nSizeMax; + chf32w->nSizeMin=chf16->nSizeMin; + FONT_LogFont16To32W(MapSL(chf16->lpLogFont), chf32w->lpLogFont); +}; + +/*********************************************************************** + * CFn_HookCallChk [internal] + */ +static BOOL CFn_HookCallChk(LPCHOOSEFONT16 lpcf) +{ + if (lpcf) + if(lpcf->Flags & CF_ENABLEHOOK) + if (lpcf->lpfnHook) + return TRUE; + return FALSE; +} + +/*********************************************************************** + * FontFamilyEnumProc (COMMDLG.19) + */ +INT16 WINAPI FontFamilyEnumProc16( SEGPTR logfont, SEGPTR metrics, + UINT16 nFontType, LPARAM lParam ) +{ + HWND hwnd=HWND_32(LOWORD(lParam)); + HWND hDlg=GetParent(hwnd); + LPCHOOSEFONT16 lpcf=(LPCHOOSEFONT16)GetWindowLongPtrW(hDlg, DWLP_USER); + LOGFONT16 *lplf = MapSL( logfont ); + TEXTMETRIC16 *lpmtrx16 = MapSL(metrics); + ENUMLOGFONTEXW elf32w; + NEWTEXTMETRICEXW nmtrx32w; + FONT_LogFont16To32W(lplf, &(elf32w.elfLogFont)); + FONT_Metrics16To32W(lpmtrx16, &nmtrx32w); + return AddFontFamily(&elf32w, &nmtrx32w, nFontType, + (LPCHOOSEFONTW)lpcf->lpTemplateName, hwnd,NULL); +} + +/*********************************************************************** + * FontStyleEnumProc (COMMDLG.18) + */ +INT16 WINAPI FontStyleEnumProc16( SEGPTR logfont, SEGPTR metrics, + UINT16 nFontType, LPARAM lParam ) +{ + HWND hcmb2=HWND_32(LOWORD(lParam)); + HWND hcmb3=HWND_32(HIWORD(lParam)); + HWND hDlg=GetParent(hcmb3); + LPCHOOSEFONT16 lpcf=(LPCHOOSEFONT16)GetWindowLongPtrW(hDlg, DWLP_USER); + LOGFONT16 *lplf = MapSL(logfont); + TEXTMETRIC16 *lpmtrx16 = MapSL(metrics); + ENUMLOGFONTEXW elf32w; + NEWTEXTMETRICEXW nmtrx32w; + FONT_LogFont16To32W(lplf, &(elf32w.elfLogFont)); + FONT_Metrics16To32W(lpmtrx16, &nmtrx32w); + return AddFontStyle(&elf32w, &nmtrx32w, nFontType, + (LPCHOOSEFONTW)lpcf->lpTemplateName, hcmb2, hcmb3, hDlg, TRUE); +} + +/*********************************************************************** + * ChooseFont (COMMDLG.15) + */ +BOOL16 WINAPI ChooseFont16(LPCHOOSEFONT16 lpChFont) +{ + HINSTANCE16 hInst; + HANDLE16 hDlgTmpl16 = 0, hResource16 = 0; + HGLOBAL16 hGlobal16 = 0; + BOOL16 bRet = FALSE; + LPCVOID template; + FARPROC16 ptr; + CHOOSEFONTW cf32w; + LOGFONTW lf32w; + LOGFONT16 *font16; + SEGPTR lpTemplateName; + + cf32w.lpLogFont=&lf32w; + CFn_CHOOSEFONT16to32W(lpChFont, &cf32w); + + TRACE("ChooseFont\n"); + if (!lpChFont) return FALSE; + + if (TRACE_ON(commdlg)) + _dump_cf_flags(lpChFont->Flags); + + if (lpChFont->Flags & CF_ENABLETEMPLATEHANDLE) + { + if (!(template = LockResource16( lpChFont->hInstance ))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + } + else if (lpChFont->Flags & CF_ENABLETEMPLATE) + { + HANDLE16 hResInfo; + if (!(hResInfo = FindResource16( lpChFont->hInstance, + MapSL(lpChFont->lpTemplateName), + (LPSTR)RT_DIALOG))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); + return FALSE; + } + if (!(hDlgTmpl16 = LoadResource16( lpChFont->hInstance, hResInfo )) || + !(template = LockResource16( hDlgTmpl16 ))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + } + else + { + HRSRC hResInfo; + HGLOBAL hDlgTmpl32; + LPCVOID template32; + DWORD size; + if (!(hResInfo = FindResourceA(COMDLG32_hInstance, "CHOOSE_FONT", (LPSTR)RT_DIALOG))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); + return FALSE; + } + if (!(hDlgTmpl32 = LoadResource(COMDLG32_hInstance, hResInfo)) || + !(template32 = LockResource(hDlgTmpl32))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + size = SizeofResource(COMDLG32_hInstance, hResInfo); + hGlobal16 = GlobalAlloc16(0, size); + if (!hGlobal16) + { + COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE); + ERR("alloc failure for %ld bytes\n", size); + return FALSE; + } + template = GlobalLock16(hGlobal16); + if (!template) + { + COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE); + ERR("global lock failure for %x handle\n", hGlobal16); + GlobalFree16(hGlobal16); + return FALSE; + } + ConvertDialog32To16((LPVOID)template32, size, (LPVOID)template); + hDlgTmpl16 = hGlobal16; + + } + + /* lpTemplateName is not used in the dialog */ + lpTemplateName=lpChFont->lpTemplateName; + lpChFont->lpTemplateName=(SEGPTR)&cf32w; + + ptr = GetProcAddress16(GetModuleHandle16("COMMDLG"), (LPCSTR) 16); + hInst = GetWindowLongPtrA(HWND_32(lpChFont->hwndOwner), GWLP_HINSTANCE); + bRet = DialogBoxIndirectParam16(hInst, hDlgTmpl16, lpChFont->hwndOwner, + (DLGPROC16) ptr, (DWORD)lpChFont); + if (hResource16) FreeResource16(hDlgTmpl16); + if (hGlobal16) + { + GlobalUnlock16(hGlobal16); + GlobalFree16(hGlobal16); + } + lpChFont->lpTemplateName=lpTemplateName; + + lpChFont->iPointSize = cf32w.iPointSize; + lpChFont->Flags = cf32w.Flags; + lpChFont->rgbColors = cf32w.rgbColors; + lpChFont->lCustData = cf32w.lCustData; + lpChFont->nFontType = cf32w.nFontType; + + font16 = MapSL(lpChFont->lpLogFont); + font16->lfHeight = cf32w.lpLogFont->lfHeight; + font16->lfWidth = cf32w.lpLogFont->lfWidth; + font16->lfEscapement = cf32w.lpLogFont->lfEscapement; + font16->lfOrientation = cf32w.lpLogFont->lfOrientation; + font16->lfWeight = cf32w.lpLogFont->lfWeight; + font16->lfItalic = cf32w.lpLogFont->lfItalic; + font16->lfUnderline = cf32w.lpLogFont->lfUnderline; + font16->lfStrikeOut = cf32w.lpLogFont->lfStrikeOut; + font16->lfCharSet = cf32w.lpLogFont->lfCharSet; + font16->lfOutPrecision = cf32w.lpLogFont->lfOutPrecision; + font16->lfClipPrecision = cf32w.lpLogFont->lfClipPrecision; + font16->lfQuality = cf32w.lpLogFont->lfQuality; + font16->lfPitchAndFamily = cf32w.lpLogFont->lfPitchAndFamily; + WideCharToMultiByte(CP_ACP, 0, cf32w.lpLogFont->lfFaceName, + LF_FACESIZE, font16->lfFaceName, LF_FACESIZE, 0, 0); + + HeapFree(GetProcessHeap(), 0, (LPBYTE)cf32w.lpTemplateName); + HeapFree(GetProcessHeap(), 0, cf32w.lpszStyle); + + return bRet; +} + +/*********************************************************************** + * 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) +{ + HWND hDlg = HWND_32(hDlg16); + LPCHOOSEFONT16 lpcf; + BOOL16 res=0; + if (message!=WM_INITDIALOG) + { + lpcf=(LPCHOOSEFONT16)GetWindowLongPtrW(hDlg, DWLP_USER); + if (!lpcf && message != WM_MEASUREITEM) + return FALSE; + if (CFn_HookCallChk(lpcf)) + res=CallWindowProc16((WNDPROC16)lpcf->lpfnHook,hDlg16,message,wParam,lParam); + if (res) + return res; + } + else + { + lpcf=(LPCHOOSEFONT16)lParam; + if (!CFn_WMInitDialog(hDlg, wParam, lParam, (LPCHOOSEFONTW)lpcf->lpTemplateName)) + { + TRACE("CFn_WMInitDialog returned FALSE\n"); + return FALSE; + } + if (CFn_HookCallChk(lpcf)) + return CallWindowProc16((WNDPROC16)lpcf->lpfnHook,hDlg16,WM_INITDIALOG,wParam,lParam); + } + switch (message) + { + case WM_MEASUREITEM: + { + MEASUREITEMSTRUCT16* mis16 = MapSL(lParam); + MEASUREITEMSTRUCT mis; + mis.CtlType = mis16->CtlType; + mis.CtlID = mis16->CtlID; + mis.itemID = mis16->itemID; + mis.itemWidth = mis16->itemWidth; + mis.itemHeight = mis16->itemHeight; + mis.itemData = mis16->itemData; + res = CFn_WMMeasureItem(hDlg, wParam, (LPARAM)&mis); + mis16->itemWidth = (UINT16)mis.itemWidth; + mis16->itemHeight = (UINT16)mis.itemHeight; + } + break; + case WM_DRAWITEM: + { + DRAWITEMSTRUCT16* dis16 = MapSL(lParam); + DRAWITEMSTRUCT dis; + dis.CtlType = dis16->CtlType; + dis.CtlID = dis16->CtlID; + dis.itemID = dis16->itemID; + dis.itemAction = dis16->itemAction; + dis.itemState = dis16->itemState; + dis.hwndItem = HWND_32(dis16->hwndItem); + dis.hDC = HDC_32(dis16->hDC); + dis.itemData = dis16->itemData; + dis.rcItem.left = dis16->rcItem.left; + dis.rcItem.top = dis16->rcItem.top; + dis.rcItem.right = dis16->rcItem.right; + dis.rcItem.bottom = dis16->rcItem.bottom; + res = CFn_WMDrawItem(hDlg, wParam, (LPARAM)&dis); + } + break; + case WM_COMMAND: + res=CFn_WMCommand(hDlg, MAKEWPARAM( wParam, HIWORD(lParam) ), LOWORD(lParam), + (LPCHOOSEFONTW)lpcf->lpTemplateName); + break; + case WM_DESTROY: + return TRUE; + case WM_CHOOSEFONT_GETLOGFONT: + TRACE("WM_CHOOSEFONT_GETLOGFONT lParam=%08lX\n", lParam); + FIXME("current logfont back to caller\n"); + break; + case WM_PAINT: + res= CFn_WMPaint(hDlg, wParam, lParam, (LPCHOOSEFONTW)lpcf->lpTemplateName); + break; + } + return res; +} diff --git a/reactos/lib/comdlg32/printdlg.c b/reactos/lib/comdlg32/printdlg.c index c7635138a41..5cdbfa38750 100644 --- a/reactos/lib/comdlg32/printdlg.c +++ b/reactos/lib/comdlg32/printdlg.c @@ -1,3160 +1,3160 @@ -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include - -#define NONAMELESSUNION -#define NONAMELESSSTRUCT -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winspool.h" -#include "winerror.h" - -#include "wine/debug.h" - -#include "commdlg.h" -#include "dlgs.h" -#include "cderr.h" - -WINE_DEFAULT_DEBUG_CHANNEL(commdlg); - -#include "cdlg.h" -#include "printdlg.h" - -/* Yes these constants are the same, but we're just copying win98 */ -#define UPDOWN_ID 0x270f -#define MAX_COPIES 9999 - -/* Debugging info */ -static struct pd_flags psd_flags[] = { - {PSD_MINMARGINS,"PSD_MINMARGINS"}, - {PSD_MARGINS,"PSD_MARGINS"}, - {PSD_INTHOUSANDTHSOFINCHES,"PSD_INTHOUSANDTHSOFINCHES"}, - {PSD_INHUNDREDTHSOFMILLIMETERS,"PSD_INHUNDREDTHSOFMILLIMETERS"}, - {PSD_DISABLEMARGINS,"PSD_DISABLEMARGINS"}, - {PSD_DISABLEPRINTER,"PSD_DISABLEPRINTER"}, - {PSD_NOWARNING,"PSD_NOWARNING"}, - {PSD_DISABLEORIENTATION,"PSD_DISABLEORIENTATION"}, - {PSD_RETURNDEFAULT,"PSD_RETURNDEFAULT"}, - {PSD_DISABLEPAPER,"PSD_DISABLEPAPER"}, - {PSD_SHOWHELP,"PSD_SHOWHELP"}, - {PSD_ENABLEPAGESETUPHOOK,"PSD_ENABLEPAGESETUPHOOK"}, - {PSD_ENABLEPAGESETUPTEMPLATE,"PSD_ENABLEPAGESETUPTEMPLATE"}, - {PSD_ENABLEPAGESETUPTEMPLATEHANDLE,"PSD_ENABLEPAGESETUPTEMPLATEHANDLE"}, - {PSD_ENABLEPAGEPAINTHOOK,"PSD_ENABLEPAGEPAINTHOOK"}, - {PSD_DISABLEPAGEPAINTING,"PSD_DISABLEPAGEPAINTING"}, - {-1, NULL} -}; - -/* address of wndproc for subclassed Static control */ -static WNDPROC lpfnStaticWndProc; -/* the text of the fake document to render for the Page Setup dialog */ -static WCHAR wszFakeDocumentText[1024]; - -/*********************************************************************** - * PRINTDLG_OpenDefaultPrinter - * - * Returns a winspool printer handle to the default printer in *hprn - * Caller must call ClosePrinter on the handle - * - * Returns TRUE on success else FALSE - */ -BOOL PRINTDLG_OpenDefaultPrinter(HANDLE *hprn) -{ - WCHAR buf[260]; - DWORD dwBufLen = sizeof(buf) / sizeof(buf[0]); - BOOL res; - if(!GetDefaultPrinterW(buf, &dwBufLen)) - return FALSE; - res = OpenPrinterW(buf, hprn, NULL); - if (!res) - WARN("Could not open printer %s\n", debugstr_w(buf)); - return res; -} - -/*********************************************************************** - * PRINTDLG_SetUpPrinterListCombo - * - * Initializes printer list combox. - * hDlg: HWND of dialog - * id: Control id of combo - * name: Name of printer to select - * - * Initializes combo with list of available printers. Selects printer 'name' - * If name is NULL or does not exist select the default printer. - * - * Returns number of printers added to list. - */ -INT PRINTDLG_SetUpPrinterListComboA(HWND hDlg, UINT id, LPCSTR name) -{ - DWORD needed, num; - INT i; - LPPRINTER_INFO_2A pi; - EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num); - pi = HeapAlloc(GetProcessHeap(), 0, needed); - EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pi, needed, &needed, - &num); - - for(i = 0; i < num; i++) { - SendDlgItemMessageA(hDlg, id, CB_ADDSTRING, 0, - (LPARAM)pi[i].pPrinterName ); - } - HeapFree(GetProcessHeap(), 0, pi); - if(!name || - (i = SendDlgItemMessageA(hDlg, id, CB_FINDSTRINGEXACT, -1, - (LPARAM)name)) == CB_ERR) { - - char buf[260]; - DWORD dwBufLen = sizeof(buf); - FIXME("Can't find '%s' in printer list so trying to find default\n", - name); - if(!GetDefaultPrinterA(buf, &dwBufLen)) - return num; - i = SendDlgItemMessageA(hDlg, id, CB_FINDSTRINGEXACT, -1, (LPARAM)buf); - if(i == CB_ERR) - FIXME("Can't find default printer in printer list\n"); - } - SendDlgItemMessageA(hDlg, id, CB_SETCURSEL, i, 0); - return num; -} - -static INT PRINTDLG_SetUpPrinterListComboW(HWND hDlg, UINT id, LPCWSTR name) -{ - DWORD needed, num; - INT i; - LPPRINTER_INFO_2W pi; - EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num); - pi = HeapAlloc(GetProcessHeap(), 0, needed); - EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pi, needed, &needed, - &num); - - for(i = 0; i < num; i++) { - SendDlgItemMessageW(hDlg, id, CB_ADDSTRING, 0, - (LPARAM)pi[i].pPrinterName ); - } - HeapFree(GetProcessHeap(), 0, pi); - if(!name || - (i = SendDlgItemMessageW(hDlg, id, CB_FINDSTRINGEXACT, -1, - (LPARAM)name)) == CB_ERR) { - WCHAR buf[260]; - DWORD dwBufLen = sizeof(buf)/sizeof(buf[0]); - TRACE("Can't find '%s' in printer list so trying to find default\n", - debugstr_w(name)); - if(!GetDefaultPrinterW(buf, &dwBufLen)) - return num; - i = SendDlgItemMessageW(hDlg, id, CB_FINDSTRINGEXACT, -1, (LPARAM)buf); - if(i == CB_ERR) - TRACE("Can't find default printer in printer list\n"); - } - SendDlgItemMessageW(hDlg, id, CB_SETCURSEL, i, 0); - return num; -} - -/*********************************************************************** - * PRINTDLG_CreateDevNames [internal] - * - * - * creates a DevNames structure. - * - * (NB. when we handle unicode the offsets will be in wchars). - */ -static BOOL PRINTDLG_CreateDevNames(HGLOBAL *hmem, char* DeviceDriverName, - char* DeviceName, char* OutputPort) -{ - long size; - char* pDevNamesSpace; - char* pTempPtr; - LPDEVNAMES lpDevNames; - char buf[260]; - DWORD dwBufLen = sizeof(buf); - - size = strlen(DeviceDriverName) + 1 - + strlen(DeviceName) + 1 - + strlen(OutputPort) + 1 - + sizeof(DEVNAMES); - - if(*hmem) - *hmem = GlobalReAlloc(*hmem, size, GMEM_MOVEABLE); - else - *hmem = GlobalAlloc(GMEM_MOVEABLE, size); - if (*hmem == 0) - return FALSE; - - pDevNamesSpace = GlobalLock(*hmem); - lpDevNames = (LPDEVNAMES) pDevNamesSpace; - - pTempPtr = pDevNamesSpace + sizeof(DEVNAMES); - strcpy(pTempPtr, DeviceDriverName); - lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace; - - pTempPtr += strlen(DeviceDriverName) + 1; - strcpy(pTempPtr, DeviceName); - lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace; - - pTempPtr += strlen(DeviceName) + 1; - strcpy(pTempPtr, OutputPort); - lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace; - - GetDefaultPrinterA(buf, &dwBufLen); - lpDevNames->wDefault = (strcmp(buf, DeviceName) == 0) ? 1 : 0; - GlobalUnlock(*hmem); - return TRUE; -} - -static BOOL PRINTDLG_CreateDevNamesW(HGLOBAL *hmem, LPCWSTR DeviceDriverName, - LPCWSTR DeviceName, LPCWSTR OutputPort) -{ - long size; - LPWSTR pDevNamesSpace; - LPWSTR pTempPtr; - LPDEVNAMES lpDevNames; - WCHAR bufW[260]; - DWORD dwBufLen = sizeof(bufW) / sizeof(WCHAR); - - size = sizeof(WCHAR)*lstrlenW(DeviceDriverName) + 2 - + sizeof(WCHAR)*lstrlenW(DeviceName) + 2 - + sizeof(WCHAR)*lstrlenW(OutputPort) + 2 - + sizeof(DEVNAMES); - - if(*hmem) - *hmem = GlobalReAlloc(*hmem, size, GMEM_MOVEABLE); - else - *hmem = GlobalAlloc(GMEM_MOVEABLE, size); - if (*hmem == 0) - return FALSE; - - pDevNamesSpace = GlobalLock(*hmem); - lpDevNames = (LPDEVNAMES) pDevNamesSpace; - - pTempPtr = (LPWSTR)((LPDEVNAMES)pDevNamesSpace + 1); - lstrcpyW(pTempPtr, DeviceDriverName); - lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace; - - pTempPtr += lstrlenW(DeviceDriverName) + 1; - lstrcpyW(pTempPtr, DeviceName); - lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace; - - pTempPtr += lstrlenW(DeviceName) + 1; - lstrcpyW(pTempPtr, OutputPort); - lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace; - - GetDefaultPrinterW(bufW, &dwBufLen); - lpDevNames->wDefault = (lstrcmpW(bufW, DeviceName) == 0) ? 1 : 0; - GlobalUnlock(*hmem); - return TRUE; -} - -/*********************************************************************** - * PRINTDLG_UpdatePrintDlg [internal] - * - * - * updates the PrintDlg structure for return values. - * - * RETURNS - * FALSE if user is not allowed to close (i.e. wrong nTo or nFrom values) - * TRUE if successful. - */ -static BOOL PRINTDLG_UpdatePrintDlgA(HWND hDlg, - PRINT_PTRA* PrintStructures) -{ - LPPRINTDLGA lppd = PrintStructures->lpPrintDlg; - PDEVMODEA lpdm = PrintStructures->lpDevMode; - LPPRINTER_INFO_2A pi = PrintStructures->lpPrinterInfo; - - - if(!lpdm) { - FIXME("No lpdm ptr?\n"); - return FALSE; - } - - - if(!(lppd->Flags & PD_PRINTSETUP)) { - /* check whether nFromPage and nToPage are within range defined by - * nMinPage and nMaxPage - */ - if (IsDlgButtonChecked(hDlg, rad3) == BST_CHECKED) { /* Pages */ - WORD nToPage; - WORD nFromPage; - nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE); - nToPage = GetDlgItemInt(hDlg, edt2, NULL, FALSE); - if (nFromPage < lppd->nMinPage || nFromPage > lppd->nMaxPage || - nToPage < lppd->nMinPage || nToPage > lppd->nMaxPage) { - char resourcestr[256]; - char resultstr[256]; - LoadStringA(COMDLG32_hInstance, PD32_INVALID_PAGE_RANGE, - resourcestr, 255); - sprintf(resultstr,resourcestr, lppd->nMinPage, lppd->nMaxPage); - LoadStringA(COMDLG32_hInstance, PD32_PRINT_TITLE, - resourcestr, 255); - MessageBoxA(hDlg, resultstr, resourcestr, - MB_OK | MB_ICONWARNING); - return FALSE; - } - lppd->nFromPage = nFromPage; - lppd->nToPage = nToPage; - lppd->Flags |= PD_PAGENUMS; - } - else - lppd->Flags &= ~PD_PAGENUMS; - - if (IsDlgButtonChecked(hDlg, chx1) == BST_CHECKED) {/* Print to file */ - lppd->Flags |= PD_PRINTTOFILE; - pi->pPortName = "FILE:"; - } - - if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) { /* Collate */ - FIXME("Collate lppd not yet implemented as output\n"); - } - - /* set PD_Collate and nCopies */ - if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { - /* The application doesn't support multiple copies or collate... - */ - lppd->Flags &= ~PD_COLLATE; - lppd->nCopies = 1; - /* if the printer driver supports it... store info there - * otherwise no collate & multiple copies ! - */ - if (lpdm->dmFields & DM_COLLATE) - lpdm->dmCollate = - (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED); - if (lpdm->dmFields & DM_COPIES) - lpdm->u.s.dmCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); - } else { - if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) - lppd->Flags |= PD_COLLATE; - else - lppd->Flags &= ~PD_COLLATE; - lppd->nCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); - } - } - return TRUE; -} - -static BOOL PRINTDLG_UpdatePrintDlgW(HWND hDlg, - PRINT_PTRW* PrintStructures) -{ - LPPRINTDLGW lppd = PrintStructures->lpPrintDlg; - PDEVMODEW lpdm = PrintStructures->lpDevMode; - LPPRINTER_INFO_2W pi = PrintStructures->lpPrinterInfo; - - - if(!lpdm) { - FIXME("No lpdm ptr?\n"); - return FALSE; - } - - - if(!(lppd->Flags & PD_PRINTSETUP)) { - /* check whether nFromPage and nToPage are within range defined by - * nMinPage and nMaxPage - */ - if (IsDlgButtonChecked(hDlg, rad3) == BST_CHECKED) { /* Pages */ - WORD nToPage; - WORD nFromPage; - nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE); - nToPage = GetDlgItemInt(hDlg, edt2, NULL, FALSE); - if (nFromPage < lppd->nMinPage || nFromPage > lppd->nMaxPage || - nToPage < lppd->nMinPage || nToPage > lppd->nMaxPage) { - WCHAR resourcestr[256]; - WCHAR resultstr[256]; - LoadStringW(COMDLG32_hInstance, PD32_INVALID_PAGE_RANGE, - resourcestr, 255); - wsprintfW(resultstr,resourcestr, lppd->nMinPage, lppd->nMaxPage); - LoadStringW(COMDLG32_hInstance, PD32_PRINT_TITLE, - resourcestr, 255); - MessageBoxW(hDlg, resultstr, resourcestr, - MB_OK | MB_ICONWARNING); - return FALSE; - } - lppd->nFromPage = nFromPage; - lppd->nToPage = nToPage; - } - - if (IsDlgButtonChecked(hDlg, chx1) == BST_CHECKED) {/* Print to file */ - static WCHAR file[] = {'F','I','L','E',':',0}; - lppd->Flags |= PD_PRINTTOFILE; - pi->pPortName = file; - } - - if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) { /* Collate */ - FIXME("Collate lppd not yet implemented as output\n"); - } - - /* set PD_Collate and nCopies */ - if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { - /* The application doesn't support multiple copies or collate... - */ - lppd->Flags &= ~PD_COLLATE; - lppd->nCopies = 1; - /* if the printer driver supports it... store info there - * otherwise no collate & multiple copies ! - */ - if (lpdm->dmFields & DM_COLLATE) - lpdm->dmCollate = - (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED); - if (lpdm->dmFields & DM_COPIES) - lpdm->u.s.dmCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); - } else { - if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) - lppd->Flags |= PD_COLLATE; - else - lppd->Flags &= ~PD_COLLATE; - lppd->nCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); - } - } - return TRUE; -} - -static BOOL PRINTDLG_PaperSizeA( - PRINTDLGA *pdlga,const char *PaperSize,LPPOINT size -) { - DEVNAMES *dn; - DEVMODEA *dm; - LPSTR devname,portname; - int i; - INT NrOfEntries,ret; - char *Names = NULL; - POINT *points = NULL; - BOOL retval = FALSE; - - dn = GlobalLock(pdlga->hDevNames); - dm = GlobalLock(pdlga->hDevMode); - devname = ((char*)dn)+dn->wDeviceOffset; - portname = ((char*)dn)+dn->wOutputOffset; - - - NrOfEntries = DeviceCapabilitiesA(devname,portname,DC_PAPERNAMES,NULL,dm); - if (!NrOfEntries) { - FIXME("No papernames found for %s/%s\n",devname,portname); - goto out; - } - if (NrOfEntries == -1) { - ERR("Hmm ? DeviceCapabilities() DC_PAPERNAMES failed, ret -1 !\n"); - goto out; - } - - Names = HeapAlloc(GetProcessHeap(),0,NrOfEntries*64); - if (NrOfEntries != (ret=DeviceCapabilitiesA(devname,portname,DC_PAPERNAMES,Names,dm))) { - FIXME("Number of returned vals %d is not %d\n",NrOfEntries,ret); - goto out; - } - for (i=0;ix=points[i].x; - size->y=points[i].y; - retval = TRUE; -out: - GlobalUnlock(pdlga->hDevNames); - GlobalUnlock(pdlga->hDevMode); - HeapFree(GetProcessHeap(),0,Names); - HeapFree(GetProcessHeap(),0,points); - return retval; -} - -static BOOL PRINTDLG_PaperSizeW( - PRINTDLGW *pdlga,const WCHAR *PaperSize,LPPOINT size -) { - DEVNAMES *dn; - DEVMODEW *dm; - LPWSTR devname,portname; - int i; - INT NrOfEntries,ret; - WCHAR *Names = NULL; - POINT *points = NULL; - BOOL retval = FALSE; - - dn = GlobalLock(pdlga->hDevNames); - dm = GlobalLock(pdlga->hDevMode); - devname = ((WCHAR*)dn)+dn->wDeviceOffset; - portname = ((WCHAR*)dn)+dn->wOutputOffset; - - - NrOfEntries = DeviceCapabilitiesW(devname,portname,DC_PAPERNAMES,NULL,dm); - if (!NrOfEntries) { - FIXME("No papernames found for %s/%s\n",debugstr_w(devname),debugstr_w(portname)); - goto out; - } - if (NrOfEntries == -1) { - ERR("Hmm ? DeviceCapabilities() DC_PAPERNAMES failed, ret -1 !\n"); - goto out; - } - - Names = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*NrOfEntries*64); - if (NrOfEntries != (ret=DeviceCapabilitiesW(devname,portname,DC_PAPERNAMES,Names,dm))) { - FIXME("Number of returned vals %d is not %d\n",NrOfEntries,ret); - goto out; - } - for (i=0;ix=points[i].x; - size->y=points[i].y; - retval = TRUE; -out: - GlobalUnlock(pdlga->hDevNames); - GlobalUnlock(pdlga->hDevMode); - HeapFree(GetProcessHeap(),0,Names); - HeapFree(GetProcessHeap(),0,points); - return retval; -} - - -/************************************************************************ - * PRINTDLG_SetUpPaperComboBox - * - * Initialize either the papersize or inputslot combos of the Printer Setup - * dialog. We store the associated word (eg DMPAPER_A4) as the item data. - * We also try to re-select the old selection. - */ -static BOOL PRINTDLG_SetUpPaperComboBoxA(HWND hDlg, - int nIDComboBox, - char* PrinterName, - char* PortName, - LPDEVMODEA dm) -{ - int i; - int NrOfEntries; - char* Names; - WORD* Words; - DWORD Sel; - WORD oldWord = 0; - int NamesSize; - int fwCapability_Names; - int fwCapability_Words; - - TRACE(" Printer: %s, Port: %s, ComboID: %d\n",PrinterName,PortName,nIDComboBox); - - /* query the dialog box for the current selected value */ - Sel = SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETCURSEL, 0, 0); - if(Sel != CB_ERR) { - /* we enter here only if a different printer is selected after - * the Print Setup dialog is opened. The current settings are - * stored into the newly selected printer. - */ - oldWord = SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, - Sel, 0); - if (dm) { - if (nIDComboBox == cmb2) - dm->u.s.dmPaperSize = oldWord; - else - dm->u.s.dmDefaultSource = oldWord; - } - } - else { - /* we enter here only when the Print setup dialog is initially - * opened. In this case the settings are restored from when - * the dialog was last closed. - */ - if (dm) { - if (nIDComboBox == cmb2) - oldWord = dm->u.s.dmPaperSize; - else - oldWord = dm->u.s.dmDefaultSource; - } - } - - if (nIDComboBox == cmb2) { - NamesSize = 64; - fwCapability_Names = DC_PAPERNAMES; - fwCapability_Words = DC_PAPERS; - } else { - nIDComboBox = cmb3; - NamesSize = 24; - fwCapability_Names = DC_BINNAMES; - fwCapability_Words = DC_BINS; - } - - /* for some printer drivers, DeviceCapabilities calls a VXD to obtain the - * paper settings. As Wine doesn't allow VXDs, this results in a crash. - */ - WARN(" if your printer driver uses VXDs, expect a crash now!\n"); - NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName, - fwCapability_Names, NULL, dm); - if (NrOfEntries == 0) - WARN("no Name Entries found!\n"); - else if (NrOfEntries < 0) - return FALSE; - - if(DeviceCapabilitiesA(PrinterName, PortName, fwCapability_Words, NULL, dm) - != NrOfEntries) { - ERR("Number of caps is different\n"); - NrOfEntries = 0; - } - - Names = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(char)*NamesSize); - Words = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WORD)); - NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName, - fwCapability_Names, Names, dm); - NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName, - fwCapability_Words, (LPSTR)Words, dm); - - /* reset any current content in the combobox */ - SendDlgItemMessageA(hDlg, nIDComboBox, CB_RESETCONTENT, 0, 0); - - /* store new content */ - for (i = 0; i < NrOfEntries; i++) { - DWORD pos = SendDlgItemMessageA(hDlg, nIDComboBox, CB_ADDSTRING, 0, - (LPARAM)(&Names[i*NamesSize]) ); - SendDlgItemMessageA(hDlg, nIDComboBox, CB_SETITEMDATA, pos, - Words[i]); - } - - /* Look for old selection - can't do this is previous loop since - item order will change as more items are added */ - Sel = 0; - for (i = 0; i < NrOfEntries; i++) { - if(SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) == - oldWord) { - Sel = i; - break; - } - } - SendDlgItemMessageA(hDlg, nIDComboBox, CB_SETCURSEL, Sel, 0); - - HeapFree(GetProcessHeap(),0,Words); - HeapFree(GetProcessHeap(),0,Names); - return TRUE; -} - -static BOOL PRINTDLG_SetUpPaperComboBoxW(HWND hDlg, - int nIDComboBox, - WCHAR* PrinterName, - WCHAR* PortName, - LPDEVMODEW dm) -{ - int i; - int NrOfEntries; - WCHAR* Names; - WORD* Words; - DWORD Sel; - WORD oldWord = 0; - int NamesSize; - int fwCapability_Names; - int fwCapability_Words; - - TRACE(" Printer: %s, Port: %s, ComboID: %d\n",debugstr_w(PrinterName),debugstr_w(PortName),nIDComboBox); - - /* query the dialog box for the current selected value */ - Sel = SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETCURSEL, 0, 0); - if(Sel != CB_ERR) { - /* we enter here only if a different printer is selected after - * the Print Setup dialog is opened. The current settings are - * stored into the newly selected printer. - */ - oldWord = SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETITEMDATA, - Sel, 0); - if (dm) { - if (nIDComboBox == cmb2) - dm->u.s.dmPaperSize = oldWord; - else - dm->u.s.dmDefaultSource = oldWord; - } - } - else { - /* we enter here only when the Print setup dialog is initially - * opened. In this case the settings are restored from when - * the dialog was last closed. - */ - if (dm) { - if (nIDComboBox == cmb2) - oldWord = dm->u.s.dmPaperSize; - else - oldWord = dm->u.s.dmDefaultSource; - } - } - - if (nIDComboBox == cmb2) { - NamesSize = 64; - fwCapability_Names = DC_PAPERNAMES; - fwCapability_Words = DC_PAPERS; - } else { - nIDComboBox = cmb3; - NamesSize = 24; - fwCapability_Names = DC_BINNAMES; - fwCapability_Words = DC_BINS; - } - - /* for some printer drivers, DeviceCapabilities calls a VXD to obtain the - * paper settings. As Wine doesn't allow VXDs, this results in a crash. - */ - WARN(" if your printer driver uses VXDs, expect a crash now!\n"); - NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName, - fwCapability_Names, NULL, dm); - if (NrOfEntries == 0) - WARN("no Name Entries found!\n"); - else if (NrOfEntries < 0) - return FALSE; - - if(DeviceCapabilitiesW(PrinterName, PortName, fwCapability_Words, NULL, dm) - != NrOfEntries) { - ERR("Number of caps is different\n"); - NrOfEntries = 0; - } - - Names = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WCHAR)*NamesSize); - Words = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WORD)); - NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName, - fwCapability_Names, Names, dm); - NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName, - fwCapability_Words, (LPWSTR)Words, dm); - - /* reset any current content in the combobox */ - SendDlgItemMessageW(hDlg, nIDComboBox, CB_RESETCONTENT, 0, 0); - - /* store new content */ - for (i = 0; i < NrOfEntries; i++) { - DWORD pos = SendDlgItemMessageW(hDlg, nIDComboBox, CB_ADDSTRING, 0, - (LPARAM)(&Names[i*NamesSize]) ); - SendDlgItemMessageW(hDlg, nIDComboBox, CB_SETITEMDATA, pos, - Words[i]); - } - - /* Look for old selection - can't do this is previous loop since - item order will change as more items are added */ - Sel = 0; - for (i = 0; i < NrOfEntries; i++) { - if(SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) == - oldWord) { - Sel = i; - break; - } - } - SendDlgItemMessageW(hDlg, nIDComboBox, CB_SETCURSEL, Sel, 0); - - HeapFree(GetProcessHeap(),0,Words); - HeapFree(GetProcessHeap(),0,Names); - return TRUE; -} - - -/*********************************************************************** - * PRINTDLG_UpdatePrinterInfoTexts [internal] - */ -static void PRINTDLG_UpdatePrinterInfoTextsA(HWND hDlg, LPPRINTER_INFO_2A pi) -{ - char StatusMsg[256]; - char ResourceString[256]; - int i; - - /* Status Message */ - StatusMsg[0]='\0'; - - /* add all status messages */ - for (i = 0; i < 25; i++) { - if (pi->Status & (1<pDriverName); - - if (pi->pLocation != NULL && pi->pLocation[0] != '\0') - SetDlgItemTextA(hDlg, stc14, pi->pLocation); - else - SetDlgItemTextA(hDlg, stc14, pi->pPortName); - SetDlgItemTextA(hDlg, stc13, pi->pComment ? pi->pComment : ""); - return; -} - -static void PRINTDLG_UpdatePrinterInfoTextsW(HWND hDlg, LPPRINTER_INFO_2W pi) -{ - WCHAR StatusMsg[256]; - WCHAR ResourceString[256]; - static const WCHAR emptyW[] = {0}; - int i; - - /* Status Message */ - StatusMsg[0]='\0'; - - /* add all status messages */ - for (i = 0; i < 25; i++) { - if (pi->Status & (1<pDriverName); - if (pi->pLocation != NULL && pi->pLocation[0] != '\0') - SetDlgItemTextW(hDlg, stc14, pi->pLocation); - else - SetDlgItemTextW(hDlg, stc14, pi->pPortName); - SetDlgItemTextW(hDlg, stc13, pi->pComment ? pi->pComment : emptyW); -} - - -/******************************************************************* - * - * PRINTDLG_ChangePrinter - * - */ -BOOL PRINTDLG_ChangePrinterA(HWND hDlg, char *name, - PRINT_PTRA *PrintStructures) -{ - LPPRINTDLGA lppd = PrintStructures->lpPrintDlg; - LPDEVMODEA lpdm = NULL; - LONG dmSize; - DWORD needed; - HANDLE hprn; - - HeapFree(GetProcessHeap(),0, PrintStructures->lpPrinterInfo); - HeapFree(GetProcessHeap(),0, PrintStructures->lpDriverInfo); - if(!OpenPrinterA(name, &hprn, NULL)) { - ERR("Can't open printer %s\n", name); - return FALSE; - } - GetPrinterA(hprn, 2, NULL, 0, &needed); - PrintStructures->lpPrinterInfo = HeapAlloc(GetProcessHeap(),0,needed); - GetPrinterA(hprn, 2, (LPBYTE)PrintStructures->lpPrinterInfo, needed, - &needed); - GetPrinterDriverA(hprn, NULL, 3, NULL, 0, &needed); - PrintStructures->lpDriverInfo = HeapAlloc(GetProcessHeap(),0,needed); - if (!GetPrinterDriverA(hprn, NULL, 3, (LPBYTE)PrintStructures->lpDriverInfo, - needed, &needed)) { - ERR("GetPrinterDriverA failed for %s, fix your config!\n",PrintStructures->lpPrinterInfo->pPrinterName); - return FALSE; - } - ClosePrinter(hprn); - - PRINTDLG_UpdatePrinterInfoTextsA(hDlg, PrintStructures->lpPrinterInfo); - - HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode); - PrintStructures->lpDevMode = NULL; - - dmSize = DocumentPropertiesA(0, 0, name, NULL, NULL, 0); - if(dmSize == -1) { - ERR("DocumentProperties fails on %s\n", debugstr_a(name)); - return FALSE; - } - PrintStructures->lpDevMode = HeapAlloc(GetProcessHeap(), 0, dmSize); - dmSize = DocumentPropertiesA(0, 0, name, PrintStructures->lpDevMode, NULL, - DM_OUT_BUFFER); - if(lppd->hDevMode && (lpdm = GlobalLock(lppd->hDevMode)) && - !strcmp(lpdm->dmDeviceName, - PrintStructures->lpDevMode->dmDeviceName)) { - /* Supplied devicemode matches current printer so try to use it */ - DocumentPropertiesA(0, 0, name, PrintStructures->lpDevMode, lpdm, - DM_OUT_BUFFER | DM_IN_BUFFER); - } - if(lpdm) - GlobalUnlock(lppd->hDevMode); - - lpdm = PrintStructures->lpDevMode; /* use this as a shortcut */ - - if(!(lppd->Flags & PD_PRINTSETUP)) { - /* Print range (All/Range/Selection) */ - SetDlgItemInt(hDlg, edt1, lppd->nFromPage, FALSE); - SetDlgItemInt(hDlg, edt2, lppd->nToPage, FALSE); - CheckRadioButton(hDlg, rad1, rad3, rad1); /* default */ - if (lppd->Flags & PD_NOSELECTION) - EnableWindow(GetDlgItem(hDlg, rad2), FALSE); - else - if (lppd->Flags & PD_SELECTION) - CheckRadioButton(hDlg, rad1, rad3, rad2); - if (lppd->Flags & PD_NOPAGENUMS) { - EnableWindow(GetDlgItem(hDlg, rad3), FALSE); - EnableWindow(GetDlgItem(hDlg, stc2),FALSE); - EnableWindow(GetDlgItem(hDlg, edt1), FALSE); - EnableWindow(GetDlgItem(hDlg, stc3),FALSE); - EnableWindow(GetDlgItem(hDlg, edt2), FALSE); - } else { - if (lppd->Flags & PD_PAGENUMS) - CheckRadioButton(hDlg, rad1, rad3, rad3); - } - - /* Collate pages - * - * FIXME: The ico3 is not displayed for some reason. I don't know why. - */ - if (lppd->Flags & PD_COLLATE) { - SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, - (LPARAM)PrintStructures->hCollateIcon); - CheckDlgButton(hDlg, chx2, 1); - } else { - SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, - (LPARAM)PrintStructures->hNoCollateIcon); - CheckDlgButton(hDlg, chx2, 0); - } - - if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { - /* if printer doesn't support it: no Collate */ - if (!(lpdm->dmFields & DM_COLLATE)) { - EnableWindow(GetDlgItem(hDlg, chx2), FALSE); - EnableWindow(GetDlgItem(hDlg, ico3), FALSE); - } - } - - /* nCopies */ - { - INT copies; - if (lppd->hDevMode == 0) - copies = lppd->nCopies; - else - copies = lpdm->u.s.dmCopies; - if(copies == 0) copies = 1; - else if(copies < 0) copies = MAX_COPIES; - SetDlgItemInt(hDlg, edt3, copies, FALSE); - } - - if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { - /* if printer doesn't support it: no nCopies */ - if (!(lpdm->dmFields & DM_COPIES)) { - EnableWindow(GetDlgItem(hDlg, edt3), FALSE); - EnableWindow(GetDlgItem(hDlg, stc5), FALSE); - } - } - - /* print to file */ - CheckDlgButton(hDlg, chx1, (lppd->Flags & PD_PRINTTOFILE) ? 1 : 0); - if (lppd->Flags & PD_DISABLEPRINTTOFILE) - EnableWindow(GetDlgItem(hDlg, chx1), FALSE); - if (lppd->Flags & PD_HIDEPRINTTOFILE) - ShowWindow(GetDlgItem(hDlg, chx1), SW_HIDE); - - } else { /* PD_PRINTSETUP */ - BOOL bPortrait = (lpdm->u.s.dmOrientation == DMORIENT_PORTRAIT); - - PRINTDLG_SetUpPaperComboBoxA(hDlg, cmb2, - PrintStructures->lpPrinterInfo->pPrinterName, - PrintStructures->lpPrinterInfo->pPortName, - lpdm); - PRINTDLG_SetUpPaperComboBoxA(hDlg, cmb3, - PrintStructures->lpPrinterInfo->pPrinterName, - PrintStructures->lpPrinterInfo->pPortName, - lpdm); - CheckRadioButton(hDlg, rad1, rad2, bPortrait ? rad1: rad2); - SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, (WPARAM) IMAGE_ICON, - (LPARAM)(bPortrait ? PrintStructures->hPortraitIcon : - PrintStructures->hLandscapeIcon)); - - } - - /* help button */ - if ((lppd->Flags & PD_SHOWHELP)==0) { - /* hide if PD_SHOWHELP not specified */ - ShowWindow(GetDlgItem(hDlg, pshHelp), SW_HIDE); - } - return TRUE; -} - -static BOOL PRINTDLG_ChangePrinterW(HWND hDlg, WCHAR *name, - PRINT_PTRW *PrintStructures) -{ - LPPRINTDLGW lppd = PrintStructures->lpPrintDlg; - LPDEVMODEW lpdm = NULL; - LONG dmSize; - DWORD needed; - HANDLE hprn; - - HeapFree(GetProcessHeap(),0, PrintStructures->lpPrinterInfo); - HeapFree(GetProcessHeap(),0, PrintStructures->lpDriverInfo); - if(!OpenPrinterW(name, &hprn, NULL)) { - ERR("Can't open printer %s\n", debugstr_w(name)); - return FALSE; - } - GetPrinterW(hprn, 2, NULL, 0, &needed); - PrintStructures->lpPrinterInfo = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*needed); - GetPrinterW(hprn, 2, (LPBYTE)PrintStructures->lpPrinterInfo, needed, - &needed); - GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed); - PrintStructures->lpDriverInfo = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*needed); - if (!GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)PrintStructures->lpDriverInfo, - needed, &needed)) { - ERR("GetPrinterDriverA failed for %s, fix your config!\n",debugstr_w(PrintStructures->lpPrinterInfo->pPrinterName)); - return FALSE; - } - ClosePrinter(hprn); - - PRINTDLG_UpdatePrinterInfoTextsW(hDlg, PrintStructures->lpPrinterInfo); - - HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode); - PrintStructures->lpDevMode = NULL; - - dmSize = DocumentPropertiesW(0, 0, name, NULL, NULL, 0); - if(dmSize == -1) { - ERR("DocumentProperties fails on %s\n", debugstr_w(name)); - return FALSE; - } - PrintStructures->lpDevMode = HeapAlloc(GetProcessHeap(), 0, dmSize); - dmSize = DocumentPropertiesW(0, 0, name, PrintStructures->lpDevMode, NULL, - DM_OUT_BUFFER); - if(lppd->hDevMode && (lpdm = GlobalLock(lppd->hDevMode)) && - !lstrcmpW(lpdm->dmDeviceName, - PrintStructures->lpDevMode->dmDeviceName)) { - /* Supplied devicemode matches current printer so try to use it */ - DocumentPropertiesW(0, 0, name, PrintStructures->lpDevMode, lpdm, - DM_OUT_BUFFER | DM_IN_BUFFER); - } - if(lpdm) - GlobalUnlock(lppd->hDevMode); - - lpdm = PrintStructures->lpDevMode; /* use this as a shortcut */ - - if(!(lppd->Flags & PD_PRINTSETUP)) { - /* Print range (All/Range/Selection) */ - SetDlgItemInt(hDlg, edt1, lppd->nFromPage, FALSE); - SetDlgItemInt(hDlg, edt2, lppd->nToPage, FALSE); - CheckRadioButton(hDlg, rad1, rad3, rad1); /* default */ - if (lppd->Flags & PD_NOSELECTION) - EnableWindow(GetDlgItem(hDlg, rad2), FALSE); - else - if (lppd->Flags & PD_SELECTION) - CheckRadioButton(hDlg, rad1, rad3, rad2); - if (lppd->Flags & PD_NOPAGENUMS) { - EnableWindow(GetDlgItem(hDlg, rad3), FALSE); - EnableWindow(GetDlgItem(hDlg, stc2),FALSE); - EnableWindow(GetDlgItem(hDlg, edt1), FALSE); - EnableWindow(GetDlgItem(hDlg, stc3),FALSE); - EnableWindow(GetDlgItem(hDlg, edt2), FALSE); - } else { - if (lppd->Flags & PD_PAGENUMS) - CheckRadioButton(hDlg, rad1, rad3, rad3); - } - - /* Collate pages - * - * FIXME: The ico3 is not displayed for some reason. I don't know why. - */ - if (lppd->Flags & PD_COLLATE) { - SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, - (LPARAM)PrintStructures->hCollateIcon); - CheckDlgButton(hDlg, chx2, 1); - } else { - SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, - (LPARAM)PrintStructures->hNoCollateIcon); - CheckDlgButton(hDlg, chx2, 0); - } - - if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { - /* if printer doesn't support it: no Collate */ - if (!(lpdm->dmFields & DM_COLLATE)) { - EnableWindow(GetDlgItem(hDlg, chx2), FALSE); - EnableWindow(GetDlgItem(hDlg, ico3), FALSE); - } - } - - /* nCopies */ - { - INT copies; - if (lppd->hDevMode == 0) - copies = lppd->nCopies; - else - copies = lpdm->u.s.dmCopies; - if(copies == 0) copies = 1; - else if(copies < 0) copies = MAX_COPIES; - SetDlgItemInt(hDlg, edt3, copies, FALSE); - } - - if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { - /* if printer doesn't support it: no nCopies */ - if (!(lpdm->dmFields & DM_COPIES)) { - EnableWindow(GetDlgItem(hDlg, edt3), FALSE); - EnableWindow(GetDlgItem(hDlg, stc5), FALSE); - } - } - - /* print to file */ - CheckDlgButton(hDlg, chx1, (lppd->Flags & PD_PRINTTOFILE) ? 1 : 0); - if (lppd->Flags & PD_DISABLEPRINTTOFILE) - EnableWindow(GetDlgItem(hDlg, chx1), FALSE); - if (lppd->Flags & PD_HIDEPRINTTOFILE) - ShowWindow(GetDlgItem(hDlg, chx1), SW_HIDE); - - } else { /* PD_PRINTSETUP */ - BOOL bPortrait = (lpdm->u.s.dmOrientation == DMORIENT_PORTRAIT); - - PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb2, - PrintStructures->lpPrinterInfo->pPrinterName, - PrintStructures->lpPrinterInfo->pPortName, - lpdm); - PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb3, - PrintStructures->lpPrinterInfo->pPrinterName, - PrintStructures->lpPrinterInfo->pPortName, - lpdm); - CheckRadioButton(hDlg, rad1, rad2, bPortrait ? rad1: rad2); - SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, (WPARAM) IMAGE_ICON, - (LPARAM)(bPortrait ? PrintStructures->hPortraitIcon : - PrintStructures->hLandscapeIcon)); - - } - - /* help button */ - if ((lppd->Flags & PD_SHOWHELP)==0) { - /* hide if PD_SHOWHELP not specified */ - ShowWindow(GetDlgItem(hDlg, pshHelp), SW_HIDE); - } - return TRUE; -} - -/*********************************************************************** - * PRINTDLG_WMInitDialog [internal] - */ -static LRESULT PRINTDLG_WMInitDialog(HWND hDlg, WPARAM wParam, - PRINT_PTRA* PrintStructures) -{ - LPPRINTDLGA lppd = PrintStructures->lpPrintDlg; - DEVNAMES *pdn; - DEVMODEA *pdm; - char *name = NULL; - UINT comboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4; - - /* load Collate ICONs */ - /* We load these with LoadImage because they are not a standard - size and we don't want them rescaled */ - PrintStructures->hCollateIcon = - LoadImageA(COMDLG32_hInstance, "PD32_COLLATE", IMAGE_ICON, 0, 0, 0); - PrintStructures->hNoCollateIcon = - LoadImageA(COMDLG32_hInstance, "PD32_NOCOLLATE", IMAGE_ICON, 0, 0, 0); - - /* These can be done with LoadIcon */ - PrintStructures->hPortraitIcon = - LoadIconA(COMDLG32_hInstance, "PD32_PORTRAIT"); - PrintStructures->hLandscapeIcon = - LoadIconA(COMDLG32_hInstance, "PD32_LANDSCAPE"); - - /* display the collate/no_collate icon */ - SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, - (LPARAM)PrintStructures->hNoCollateIcon); - - if(PrintStructures->hCollateIcon == 0 || - PrintStructures->hNoCollateIcon == 0 || - PrintStructures->hPortraitIcon == 0 || - PrintStructures->hLandscapeIcon == 0) { - ERR("no icon in resourcefile\n"); - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - EndDialog(hDlg, FALSE); - } - - /* - * if lppd->Flags PD_SHOWHELP is specified, a HELPMESGSTRING message - * must be registered and the Help button must be shown. - */ - if (lppd->Flags & PD_SHOWHELP) { - if((PrintStructures->HelpMessageID = - RegisterWindowMessageA(HELPMSGSTRINGA)) == 0) { - COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL); - return FALSE; - } - } else - PrintStructures->HelpMessageID = 0; - - if(!(lppd->Flags &PD_PRINTSETUP)) { - PrintStructures->hwndUpDown = - CreateUpDownControl(WS_CHILD | WS_VISIBLE | WS_BORDER | - UDS_NOTHOUSANDS | UDS_ARROWKEYS | - UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 0, 0, 0, 0, - hDlg, UPDOWN_ID, COMDLG32_hInstance, - GetDlgItem(hDlg, edt3), MAX_COPIES, 1, 1); - } - - /* FIXME: I allow more freedom than either Win95 or WinNT, - * which do not agree to what errors should be thrown or not - * in case nToPage or nFromPage is out-of-range. - */ - if (lppd->nMaxPage < lppd->nMinPage) - lppd->nMaxPage = lppd->nMinPage; - if (lppd->nMinPage == lppd->nMaxPage) - lppd->Flags |= PD_NOPAGENUMS; - if (lppd->nToPage < lppd->nMinPage) - lppd->nToPage = lppd->nMinPage; - if (lppd->nToPage > lppd->nMaxPage) - lppd->nToPage = lppd->nMaxPage; - if (lppd->nFromPage < lppd->nMinPage) - lppd->nFromPage = lppd->nMinPage; - if (lppd->nFromPage > lppd->nMaxPage) - lppd->nFromPage = lppd->nMaxPage; - - /* if we have the combo box, fill it */ - if (GetDlgItem(hDlg,comboID)) { - /* Fill Combobox - */ - pdn = GlobalLock(lppd->hDevNames); - pdm = GlobalLock(lppd->hDevMode); - if(pdn) - name = (char*)pdn + pdn->wDeviceOffset; - else if(pdm) - name = pdm->dmDeviceName; - PRINTDLG_SetUpPrinterListComboA(hDlg, comboID, name); - if(pdm) GlobalUnlock(lppd->hDevMode); - if(pdn) GlobalUnlock(lppd->hDevNames); - - /* Now find selected printer and update rest of dlg */ - name = HeapAlloc(GetProcessHeap(),0,256); - if (GetDlgItemTextA(hDlg, comboID, name, 255)) - PRINTDLG_ChangePrinterA(hDlg, name, PrintStructures); - HeapFree(GetProcessHeap(),0,name); - } else { - /* else use default printer */ - char name[200]; - DWORD dwBufLen = sizeof(name); - BOOL ret = GetDefaultPrinterA(name, &dwBufLen); - - if (ret) - PRINTDLG_ChangePrinterA(hDlg, name, PrintStructures); - else - FIXME("No default printer found, expect problems!\n"); - } - return TRUE; -} - -static LRESULT PRINTDLG_WMInitDialogW(HWND hDlg, WPARAM wParam, - PRINT_PTRW* PrintStructures) -{ - const static WCHAR PD32_COLLATE[] = { 'P', 'D', '3', '2', '_', 'C', 'O', 'L', 'L', 'A', 'T', 'E', 0 }; - const static WCHAR PD32_NOCOLLATE[] = { 'P', 'D', '3', '2', '_', 'N', 'O', 'C', 'O', 'L', 'L', 'A', 'T', 'E', 0 }; - const static WCHAR PD32_PORTRAIT[] = { 'P', 'D', '3', '2', '_', 'P', 'O', 'R', 'T', 'R', 'A', 'I', 'T', 0 }; - const static WCHAR PD32_LANDSCAPE[] = { 'P', 'D', '3', '2', '_', 'L', 'A', 'N', 'D', 'S', 'C', 'A', 'P', 'E', 0 }; - LPPRINTDLGW lppd = PrintStructures->lpPrintDlg; - DEVNAMES *pdn; - DEVMODEW *pdm; - WCHAR *name = NULL; - UINT comboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4; - - /* load Collate ICONs */ - /* We load these with LoadImage because they are not a standard - size and we don't want them rescaled */ - PrintStructures->hCollateIcon = - LoadImageW(COMDLG32_hInstance, PD32_COLLATE, IMAGE_ICON, 0, 0, 0); - PrintStructures->hNoCollateIcon = - LoadImageW(COMDLG32_hInstance, PD32_NOCOLLATE, IMAGE_ICON, 0, 0, 0); - - /* These can be done with LoadIcon */ - PrintStructures->hPortraitIcon = - LoadIconW(COMDLG32_hInstance, PD32_PORTRAIT); - PrintStructures->hLandscapeIcon = - LoadIconW(COMDLG32_hInstance, PD32_LANDSCAPE); - - /* display the collate/no_collate icon */ - SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, - (LPARAM)PrintStructures->hNoCollateIcon); - - if(PrintStructures->hCollateIcon == 0 || - PrintStructures->hNoCollateIcon == 0 || - PrintStructures->hPortraitIcon == 0 || - PrintStructures->hLandscapeIcon == 0) { - ERR("no icon in resourcefile\n"); - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - EndDialog(hDlg, FALSE); - } - - /* - * if lppd->Flags PD_SHOWHELP is specified, a HELPMESGSTRING message - * must be registered and the Help button must be shown. - */ - if (lppd->Flags & PD_SHOWHELP) { - if((PrintStructures->HelpMessageID = - RegisterWindowMessageW(HELPMSGSTRINGW)) == 0) { - COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL); - return FALSE; - } - } else - PrintStructures->HelpMessageID = 0; - - if(!(lppd->Flags &PD_PRINTSETUP)) { - PrintStructures->hwndUpDown = - CreateUpDownControl(WS_CHILD | WS_VISIBLE | WS_BORDER | - UDS_NOTHOUSANDS | UDS_ARROWKEYS | - UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 0, 0, 0, 0, - hDlg, UPDOWN_ID, COMDLG32_hInstance, - GetDlgItem(hDlg, edt3), MAX_COPIES, 1, 1); - } - - /* FIXME: I allow more freedom than either Win95 or WinNT, - * which do not agree to what errors should be thrown or not - * in case nToPage or nFromPage is out-of-range. - */ - if (lppd->nMaxPage < lppd->nMinPage) - lppd->nMaxPage = lppd->nMinPage; - if (lppd->nMinPage == lppd->nMaxPage) - lppd->Flags |= PD_NOPAGENUMS; - if (lppd->nToPage < lppd->nMinPage) - lppd->nToPage = lppd->nMinPage; - if (lppd->nToPage > lppd->nMaxPage) - lppd->nToPage = lppd->nMaxPage; - if (lppd->nFromPage < lppd->nMinPage) - lppd->nFromPage = lppd->nMinPage; - if (lppd->nFromPage > lppd->nMaxPage) - lppd->nFromPage = lppd->nMaxPage; - - /* if we have the combo box, fill it */ - if (GetDlgItem(hDlg,comboID)) { - /* Fill Combobox - */ - pdn = GlobalLock(lppd->hDevNames); - pdm = GlobalLock(lppd->hDevMode); - if(pdn) - name = (WCHAR*)pdn + pdn->wDeviceOffset; - else if(pdm) - name = pdm->dmDeviceName; - PRINTDLG_SetUpPrinterListComboW(hDlg, comboID, name); - if(pdm) GlobalUnlock(lppd->hDevMode); - if(pdn) GlobalUnlock(lppd->hDevNames); - - /* Now find selected printer and update rest of dlg */ - /* ansi is ok here */ - name = HeapAlloc(GetProcessHeap(),0,256*sizeof(WCHAR)); - if (GetDlgItemTextW(hDlg, comboID, name, 255)) - PRINTDLG_ChangePrinterW(hDlg, name, PrintStructures); - HeapFree(GetProcessHeap(),0,name); - } else { - /* else use default printer */ - WCHAR name[200]; - DWORD dwBufLen = sizeof(name) / sizeof(WCHAR); - BOOL ret = GetDefaultPrinterW(name, &dwBufLen); - - if (ret) - PRINTDLG_ChangePrinterW(hDlg, name, PrintStructures); - else - FIXME("No default printer found, expect problems!\n"); - } - return TRUE; -} - -/*********************************************************************** - * PRINTDLG_WMCommand [internal] - */ -LRESULT PRINTDLG_WMCommandA(HWND hDlg, WPARAM wParam, - LPARAM lParam, PRINT_PTRA* PrintStructures) -{ - LPPRINTDLGA lppd = PrintStructures->lpPrintDlg; - UINT PrinterComboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4; - LPDEVMODEA lpdm = PrintStructures->lpDevMode; - - switch (LOWORD(wParam)) { - case IDOK: - TRACE(" OK button was hit\n"); - if (!PRINTDLG_UpdatePrintDlgA(hDlg, PrintStructures)) { - FIXME("Update printdlg was not successful!\n"); - return(FALSE); - } - EndDialog(hDlg, TRUE); - return(TRUE); - - case IDCANCEL: - TRACE(" CANCEL button was hit\n"); - EndDialog(hDlg, FALSE); - return(FALSE); - - case pshHelp: - TRACE(" HELP button was hit\n"); - SendMessageA(lppd->hwndOwner, PrintStructures->HelpMessageID, - (WPARAM) hDlg, (LPARAM) lppd); - break; - - case chx2: /* collate pages checkbox */ - if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) - SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, - (LPARAM)PrintStructures->hCollateIcon); - else - SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, - (LPARAM)PrintStructures->hNoCollateIcon); - break; - case edt1: /* from page nr editbox */ - case edt2: /* to page nr editbox */ - if (HIWORD(wParam)==EN_CHANGE) { - WORD nToPage; - WORD nFromPage; - nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE); - nToPage = GetDlgItemInt(hDlg, edt2, NULL, FALSE); - if (nFromPage != lppd->nFromPage || nToPage != lppd->nToPage) - CheckRadioButton(hDlg, rad1, rad3, rad3); - } - break; - - case edt3: - if(HIWORD(wParam) == EN_CHANGE) { - INT copies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); - if(copies <= 1) - EnableWindow(GetDlgItem(hDlg, chx2), FALSE); - else - EnableWindow(GetDlgItem(hDlg, chx2), TRUE); - } - break; - -#if 0 - case psh1: /* Print Setup */ - { - PRINTDLG16 pdlg; - - if (!PrintStructures->dlg.lpPrintDlg16) { - FIXME("The 32bit print dialog does not have this button!?\n"); - break; - } - - memcpy(&pdlg,PrintStructures->dlg.lpPrintDlg16,sizeof(pdlg)); - pdlg.Flags |= PD_PRINTSETUP; - pdlg.hwndOwner = HWND_16(hDlg); - if (!PrintDlg16(&pdlg)) - break; - } - break; -#endif - case psh2: /* Properties button */ - { - HANDLE hPrinter; - char PrinterName[256]; - - GetDlgItemTextA(hDlg, PrinterComboID, PrinterName, 255); - if (!OpenPrinterA(PrinterName, &hPrinter, NULL)) { - FIXME(" Call to OpenPrinter did not succeed!\n"); - break; - } - DocumentPropertiesA(hDlg, hPrinter, PrinterName, - PrintStructures->lpDevMode, - PrintStructures->lpDevMode, - DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT); - ClosePrinter(hPrinter); - break; - } - - case rad1: /* Paperorientation */ - if (lppd->Flags & PD_PRINTSETUP) - { - lpdm->u.s.dmOrientation = DMORIENT_PORTRAIT; - SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, (WPARAM) IMAGE_ICON, - (LPARAM)(PrintStructures->hPortraitIcon)); - } - break; - - case rad2: /* Paperorientation */ - if (lppd->Flags & PD_PRINTSETUP) - { - lpdm->u.s.dmOrientation = DMORIENT_LANDSCAPE; - SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, (WPARAM) IMAGE_ICON, - (LPARAM)(PrintStructures->hLandscapeIcon)); - } - break; - - case cmb1: /* Printer Combobox in PRINT SETUP, quality combobox in PRINT */ - if (PrinterComboID != LOWORD(wParam)) { - FIXME("No handling for print quality combo box yet.\n"); - break; - } - /* FALLTHROUGH */ - case cmb4: /* Printer combobox */ - if (HIWORD(wParam)==CBN_SELCHANGE) { - char PrinterName[256]; - GetDlgItemTextA(hDlg, LOWORD(wParam), PrinterName, 255); - PRINTDLG_ChangePrinterA(hDlg, PrinterName, PrintStructures); - } - break; - - case cmb2: /* Papersize */ - { - DWORD Sel = SendDlgItemMessageA(hDlg, cmb2, CB_GETCURSEL, 0, 0); - if(Sel != CB_ERR) - lpdm->u.s.dmPaperSize = SendDlgItemMessageA(hDlg, cmb2, - CB_GETITEMDATA, - Sel, 0); - } - break; - - case cmb3: /* Bin */ - { - DWORD Sel = SendDlgItemMessageA(hDlg, cmb3, CB_GETCURSEL, 0, 0); - if(Sel != CB_ERR) - lpdm->u.s.dmDefaultSource = SendDlgItemMessageA(hDlg, cmb3, - CB_GETITEMDATA, Sel, - 0); - } - break; - } - if(lppd->Flags & PD_PRINTSETUP) { - switch (LOWORD(wParam)) { - case rad1: /* orientation */ - case rad2: - if (IsDlgButtonChecked(hDlg, rad1) == BST_CHECKED) { - if(lpdm->u.s.dmOrientation != DMORIENT_PORTRAIT) { - lpdm->u.s.dmOrientation = DMORIENT_PORTRAIT; - SendDlgItemMessageA(hDlg, stc10, STM_SETIMAGE, - (WPARAM)IMAGE_ICON, - (LPARAM)PrintStructures->hPortraitIcon); - SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, - (WPARAM)IMAGE_ICON, - (LPARAM)PrintStructures->hPortraitIcon); - } - } else { - if(lpdm->u.s.dmOrientation != DMORIENT_LANDSCAPE) { - lpdm->u.s.dmOrientation = DMORIENT_LANDSCAPE; - SendDlgItemMessageA(hDlg, stc10, STM_SETIMAGE, - (WPARAM)IMAGE_ICON, - (LPARAM)PrintStructures->hLandscapeIcon); - SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, - (WPARAM)IMAGE_ICON, - (LPARAM)PrintStructures->hLandscapeIcon); - } - } - break; - } - } - return FALSE; -} - -static LRESULT PRINTDLG_WMCommandW(HWND hDlg, WPARAM wParam, - LPARAM lParam, PRINT_PTRW* PrintStructures) -{ - LPPRINTDLGW lppd = PrintStructures->lpPrintDlg; - UINT PrinterComboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4; - LPDEVMODEW lpdm = PrintStructures->lpDevMode; - - switch (LOWORD(wParam)) { - case IDOK: - TRACE(" OK button was hit\n"); - if (!PRINTDLG_UpdatePrintDlgW(hDlg, PrintStructures)) { - FIXME("Update printdlg was not successful!\n"); - return(FALSE); - } - EndDialog(hDlg, TRUE); - return(TRUE); - - case IDCANCEL: - TRACE(" CANCEL button was hit\n"); - EndDialog(hDlg, FALSE); - return(FALSE); - - case pshHelp: - TRACE(" HELP button was hit\n"); - SendMessageW(lppd->hwndOwner, PrintStructures->HelpMessageID, - (WPARAM) hDlg, (LPARAM) lppd); - break; - - case chx2: /* collate pages checkbox */ - if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) - SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, - (LPARAM)PrintStructures->hCollateIcon); - else - SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, - (LPARAM)PrintStructures->hNoCollateIcon); - break; - case edt1: /* from page nr editbox */ - case edt2: /* to page nr editbox */ - if (HIWORD(wParam)==EN_CHANGE) { - WORD nToPage; - WORD nFromPage; - nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE); - nToPage = GetDlgItemInt(hDlg, edt2, NULL, FALSE); - if (nFromPage != lppd->nFromPage || nToPage != lppd->nToPage) - CheckRadioButton(hDlg, rad1, rad3, rad3); - } - break; - - case edt3: - if(HIWORD(wParam) == EN_CHANGE) { - INT copies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); - if(copies <= 1) - EnableWindow(GetDlgItem(hDlg, chx2), FALSE); - else - EnableWindow(GetDlgItem(hDlg, chx2), TRUE); - } - break; - - case psh1: /* Print Setup */ - { - ERR("psh1 is called from 16bit code only, we should not get here.\n"); - } - break; - case psh2: /* Properties button */ - { - HANDLE hPrinter; - WCHAR PrinterName[256]; - - if (!GetDlgItemTextW(hDlg, PrinterComboID, PrinterName, 255)) break; - if (!OpenPrinterW(PrinterName, &hPrinter, NULL)) { - FIXME(" Call to OpenPrinter did not succeed!\n"); - break; - } - DocumentPropertiesW(hDlg, hPrinter, PrinterName, - PrintStructures->lpDevMode, - PrintStructures->lpDevMode, - DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT); - ClosePrinter(hPrinter); - break; - } - - case rad1: /* Paperorientation */ - if (lppd->Flags & PD_PRINTSETUP) - { - lpdm->u.s.dmOrientation = DMORIENT_PORTRAIT; - SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, (WPARAM) IMAGE_ICON, - (LPARAM)(PrintStructures->hPortraitIcon)); - } - break; - - case rad2: /* Paperorientation */ - if (lppd->Flags & PD_PRINTSETUP) - { - lpdm->u.s.dmOrientation = DMORIENT_LANDSCAPE; - SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, (WPARAM) IMAGE_ICON, - (LPARAM)(PrintStructures->hLandscapeIcon)); - } - break; - - case cmb1: /* Printer Combobox in PRINT SETUP, quality combobox in PRINT */ - if (PrinterComboID != LOWORD(wParam)) { - FIXME("No handling for print quality combo box yet.\n"); - break; - } - /* FALLTHROUGH */ - case cmb4: /* Printer combobox */ - if (HIWORD(wParam)==CBN_SELCHANGE) { - WCHAR PrinterName[256]; - GetDlgItemTextW(hDlg, LOWORD(wParam), PrinterName, 255); - PRINTDLG_ChangePrinterW(hDlg, PrinterName, PrintStructures); - } - break; - - case cmb2: /* Papersize */ - { - DWORD Sel = SendDlgItemMessageW(hDlg, cmb2, CB_GETCURSEL, 0, 0); - if(Sel != CB_ERR) - lpdm->u.s.dmPaperSize = SendDlgItemMessageW(hDlg, cmb2, - CB_GETITEMDATA, - Sel, 0); - } - break; - - case cmb3: /* Bin */ - { - DWORD Sel = SendDlgItemMessageW(hDlg, cmb3, CB_GETCURSEL, 0, 0); - if(Sel != CB_ERR) - lpdm->u.s.dmDefaultSource = SendDlgItemMessageW(hDlg, cmb3, - CB_GETITEMDATA, Sel, - 0); - } - break; - } - if(lppd->Flags & PD_PRINTSETUP) { - switch (LOWORD(wParam)) { - case rad1: /* orientation */ - case rad2: - if (IsDlgButtonChecked(hDlg, rad1) == BST_CHECKED) { - if(lpdm->u.s.dmOrientation != DMORIENT_PORTRAIT) { - lpdm->u.s.dmOrientation = DMORIENT_PORTRAIT; - SendDlgItemMessageW(hDlg, stc10, STM_SETIMAGE, - (WPARAM)IMAGE_ICON, - (LPARAM)PrintStructures->hPortraitIcon); - SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, - (WPARAM)IMAGE_ICON, - (LPARAM)PrintStructures->hPortraitIcon); - } - } else { - if(lpdm->u.s.dmOrientation != DMORIENT_LANDSCAPE) { - lpdm->u.s.dmOrientation = DMORIENT_LANDSCAPE; - SendDlgItemMessageW(hDlg, stc10, STM_SETIMAGE, - (WPARAM)IMAGE_ICON, - (LPARAM)PrintStructures->hLandscapeIcon); - SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, - (WPARAM)IMAGE_ICON, - (LPARAM)PrintStructures->hLandscapeIcon); - } - } - break; - } - } - return FALSE; -} - -/*********************************************************************** - * PrintDlgProcA [internal] - */ -static INT_PTR CALLBACK PrintDlgProcA(HWND hDlg, UINT uMsg, WPARAM wParam, - LPARAM lParam) -{ - PRINT_PTRA* PrintStructures; - INT_PTR res = FALSE; - - if (uMsg!=WM_INITDIALOG) { - PrintStructures = (PRINT_PTRA*)GetPropA(hDlg,"__WINE_PRINTDLGDATA"); - if (!PrintStructures) - return FALSE; - } else { - PrintStructures = (PRINT_PTRA*) lParam; - SetPropA(hDlg,"__WINE_PRINTDLGDATA",PrintStructures); - res = PRINTDLG_WMInitDialog(hDlg, wParam, PrintStructures); - - if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) - res = PrintStructures->lpPrintDlg->lpfnPrintHook( - hDlg, uMsg, wParam, (LPARAM)PrintStructures->lpPrintDlg - ); - return res; - } - - if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) { - res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg,uMsg,wParam, - lParam); - if(res) return res; - } - - switch (uMsg) { - case WM_COMMAND: - return PRINTDLG_WMCommandA(hDlg, wParam, lParam, PrintStructures); - - case WM_DESTROY: - DestroyIcon(PrintStructures->hCollateIcon); - DestroyIcon(PrintStructures->hNoCollateIcon); - DestroyIcon(PrintStructures->hPortraitIcon); - DestroyIcon(PrintStructures->hLandscapeIcon); - if(PrintStructures->hwndUpDown) - DestroyWindow(PrintStructures->hwndUpDown); - return FALSE; - } - return res; -} - -static INT_PTR CALLBACK PrintDlgProcW(HWND hDlg, UINT uMsg, WPARAM wParam, - LPARAM lParam) -{ - static const WCHAR propW[] = {'_','_','W','I','N','E','_','P','R','I','N','T','D','L','G','D','A','T','A',0}; - PRINT_PTRW* PrintStructures; - INT_PTR res = FALSE; - - if (uMsg!=WM_INITDIALOG) { - PrintStructures = (PRINT_PTRW*) GetPropW(hDlg, propW); - if (!PrintStructures) - return FALSE; - } else { - PrintStructures = (PRINT_PTRW*) lParam; - SetPropW(hDlg, propW, PrintStructures); - res = PRINTDLG_WMInitDialogW(hDlg, wParam, PrintStructures); - - if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) - res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg, uMsg, wParam, (LPARAM)PrintStructures->lpPrintDlg); - return res; - } - - if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) { - res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg,uMsg,wParam, lParam); - if(res) return res; - } - - switch (uMsg) { - case WM_COMMAND: - return PRINTDLG_WMCommandW(hDlg, wParam, lParam, PrintStructures); - - case WM_DESTROY: - DestroyIcon(PrintStructures->hCollateIcon); - DestroyIcon(PrintStructures->hNoCollateIcon); - DestroyIcon(PrintStructures->hPortraitIcon); - DestroyIcon(PrintStructures->hLandscapeIcon); - if(PrintStructures->hwndUpDown) - DestroyWindow(PrintStructures->hwndUpDown); - return FALSE; - } - return res; -} - -/************************************************************ - * - * PRINTDLG_GetDlgTemplate - * - */ -static HGLOBAL PRINTDLG_GetDlgTemplateA(PRINTDLGA *lppd) -{ - HRSRC hResInfo; - HGLOBAL hDlgTmpl; - - if (lppd->Flags & PD_PRINTSETUP) { - if(lppd->Flags & PD_ENABLESETUPTEMPLATEHANDLE) { - hDlgTmpl = lppd->hSetupTemplate; - } else if(lppd->Flags & PD_ENABLESETUPTEMPLATE) { - hResInfo = FindResourceA(lppd->hInstance, - lppd->lpSetupTemplateName, (LPSTR)RT_DIALOG); - hDlgTmpl = LoadResource(lppd->hInstance, hResInfo); - } else { - hResInfo = FindResourceA(COMDLG32_hInstance, "PRINT32_SETUP", - (LPSTR)RT_DIALOG); - hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo); - } - } else { - if(lppd->Flags & PD_ENABLEPRINTTEMPLATEHANDLE) { - hDlgTmpl = lppd->hPrintTemplate; - } else if(lppd->Flags & PD_ENABLEPRINTTEMPLATE) { - hResInfo = FindResourceA(lppd->hInstance, - lppd->lpPrintTemplateName, - (LPSTR)RT_DIALOG); - hDlgTmpl = LoadResource(lppd->hInstance, hResInfo); - } else { - hResInfo = FindResourceA(COMDLG32_hInstance, "PRINT32", - (LPSTR)RT_DIALOG); - hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo); - } - } - return hDlgTmpl; -} - -static HGLOBAL PRINTDLG_GetDlgTemplateW(PRINTDLGW *lppd) -{ - HRSRC hResInfo; - HGLOBAL hDlgTmpl; - static const WCHAR xpsetup[] = { 'P','R','I','N','T','3','2','_','S','E','T','U','P',0}; - static const WCHAR xprint[] = { 'P','R','I','N','T','3','2',0}; - - if (lppd->Flags & PD_PRINTSETUP) { - if(lppd->Flags & PD_ENABLESETUPTEMPLATEHANDLE) { - hDlgTmpl = lppd->hSetupTemplate; - } else if(lppd->Flags & PD_ENABLESETUPTEMPLATE) { - hResInfo = FindResourceW(lppd->hInstance, - lppd->lpSetupTemplateName, (LPWSTR)RT_DIALOG); - hDlgTmpl = LoadResource(lppd->hInstance, hResInfo); - } else { - hResInfo = FindResourceW(COMDLG32_hInstance, xpsetup, (LPWSTR)RT_DIALOG); - hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo); - } - } else { - if(lppd->Flags & PD_ENABLEPRINTTEMPLATEHANDLE) { - hDlgTmpl = lppd->hPrintTemplate; - } else if(lppd->Flags & PD_ENABLEPRINTTEMPLATE) { - hResInfo = FindResourceW(lppd->hInstance, - lppd->lpPrintTemplateName, - (LPWSTR)RT_DIALOG); - hDlgTmpl = LoadResource(lppd->hInstance, hResInfo); - } else { - hResInfo = FindResourceW(COMDLG32_hInstance, xprint, (LPWSTR)RT_DIALOG); - hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo); - } - } - return hDlgTmpl; -} - -/*********************************************************************** - * - * PRINTDLG_CreateDC - * - */ -static BOOL PRINTDLG_CreateDCA(LPPRINTDLGA lppd) -{ - DEVNAMES *pdn = GlobalLock(lppd->hDevNames); - DEVMODEA *pdm = GlobalLock(lppd->hDevMode); - - if(lppd->Flags & PD_RETURNDC) { - lppd->hDC = CreateDCA((char*)pdn + pdn->wDriverOffset, - (char*)pdn + pdn->wDeviceOffset, - (char*)pdn + pdn->wOutputOffset, - pdm ); - } else if(lppd->Flags & PD_RETURNIC) { - lppd->hDC = CreateICA((char*)pdn + pdn->wDriverOffset, - (char*)pdn + pdn->wDeviceOffset, - (char*)pdn + pdn->wOutputOffset, - pdm ); - } - GlobalUnlock(lppd->hDevNames); - GlobalUnlock(lppd->hDevMode); - return lppd->hDC ? TRUE : FALSE; -} - -static BOOL PRINTDLG_CreateDCW(LPPRINTDLGW lppd) -{ - DEVNAMES *pdn = GlobalLock(lppd->hDevNames); - DEVMODEW *pdm = GlobalLock(lppd->hDevMode); - - if(lppd->Flags & PD_RETURNDC) { - lppd->hDC = CreateDCW((WCHAR*)pdn + pdn->wDriverOffset, - (WCHAR*)pdn + pdn->wDeviceOffset, - (WCHAR*)pdn + pdn->wOutputOffset, - pdm ); - } else if(lppd->Flags & PD_RETURNIC) { - lppd->hDC = CreateICW((WCHAR*)pdn + pdn->wDriverOffset, - (WCHAR*)pdn + pdn->wDeviceOffset, - (WCHAR*)pdn + pdn->wOutputOffset, - pdm ); - } - GlobalUnlock(lppd->hDevNames); - GlobalUnlock(lppd->hDevMode); - return lppd->hDC ? TRUE : FALSE; -} - -/*********************************************************************** - * PrintDlgA (COMDLG32.@) - * - * Displays the 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 - * PrintDlg: - * * The Collate Icons do not display, even though they are in the code. - * * The Properties Button(s) should call DocumentPropertiesA(). - */ - -BOOL WINAPI PrintDlgA( - LPPRINTDLGA lppd /* [in/out] ptr to PRINTDLG32 struct */ - ) -{ - BOOL bRet = FALSE; - LPVOID ptr; - HINSTANCE hInst = (HINSTANCE)GetWindowLongPtrA( lppd->hwndOwner, GWLP_HINSTANCE ); - - if(TRACE_ON(commdlg)) { - char flagstr[1000] = ""; - struct pd_flags *pflag = pd_flags; - for( ; pflag->name; pflag++) { - if(lppd->Flags & pflag->flag) - strcat(flagstr, pflag->name); - } - TRACE("(%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n" - "pp. %d-%d, min p %d, max p %d, copies %d, hinst %p\n" - "flags %08lx (%s)\n", - lppd, lppd->hwndOwner, lppd->hDevMode, lppd->hDevNames, - lppd->nFromPage, lppd->nToPage, lppd->nMinPage, lppd->nMaxPage, - lppd->nCopies, lppd->hInstance, lppd->Flags, flagstr); - } - - if(lppd->lStructSize != sizeof(PRINTDLGA)) { - WARN("structure size failure !!!\n"); - COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE); - return FALSE; - } - - if(lppd->Flags & PD_RETURNDEFAULT) { - PRINTER_INFO_2A *pbuf; - DRIVER_INFO_3A *dbuf; - HANDLE hprn; - DWORD needed; - - if(lppd->hDevMode || lppd->hDevNames) { - WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n"); - COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); - return FALSE; - } - if(!PRINTDLG_OpenDefaultPrinter(&hprn)) { - WARN("Can't find default printer\n"); - COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN); - return FALSE; - } - - GetPrinterA(hprn, 2, NULL, 0, &needed); - pbuf = HeapAlloc(GetProcessHeap(), 0, needed); - GetPrinterA(hprn, 2, (LPBYTE)pbuf, needed, &needed); - - GetPrinterDriverA(hprn, NULL, 3, NULL, 0, &needed); - dbuf = HeapAlloc(GetProcessHeap(),0,needed); - if (!GetPrinterDriverA(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed)) { - ERR("GetPrinterDriverA failed, le %ld, fix your config for printer %s!\n",GetLastError(),pbuf->pPrinterName); - COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); - return FALSE; - } - ClosePrinter(hprn); - - PRINTDLG_CreateDevNames(&(lppd->hDevNames), - dbuf->pDriverPath, - pbuf->pPrinterName, - pbuf->pPortName); - lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, pbuf->pDevMode->dmSize + - pbuf->pDevMode->dmDriverExtra); - ptr = GlobalLock(lppd->hDevMode); - memcpy(ptr, pbuf->pDevMode, pbuf->pDevMode->dmSize + - pbuf->pDevMode->dmDriverExtra); - GlobalUnlock(lppd->hDevMode); - HeapFree(GetProcessHeap(), 0, pbuf); - HeapFree(GetProcessHeap(), 0, dbuf); - bRet = TRUE; - } else { - HGLOBAL hDlgTmpl; - PRINT_PTRA *PrintStructures; - - /* load Dialog resources, - * depending on Flags indicates Print32 or Print32_setup dialog - */ - hDlgTmpl = PRINTDLG_GetDlgTemplateA(lppd); - if (!hDlgTmpl) { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - ptr = LockResource( hDlgTmpl ); - if (!ptr) { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - - PrintStructures = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(PRINT_PTRA)); - PrintStructures->lpPrintDlg = lppd; - - /* and create & process the dialog . - * -1 is failure, 0 is broken hwnd, everything else is ok. - */ - bRet = (0hwndOwner, - PrintDlgProcA, - (LPARAM)PrintStructures)); - - if(bRet) { - DEVMODEA *lpdm = PrintStructures->lpDevMode, *lpdmReturn; - PRINTER_INFO_2A *pi = PrintStructures->lpPrinterInfo; - DRIVER_INFO_3A *di = PrintStructures->lpDriverInfo; - - if (lppd->hDevMode == 0) { - TRACE(" No hDevMode yet... Need to create my own\n"); - lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, - lpdm->dmSize + lpdm->dmDriverExtra); - } else { - WORD locks; - if((locks = (GlobalFlags(lppd->hDevMode) & GMEM_LOCKCOUNT))) { - WARN("hDevMode has %d locks on it. Unlocking it now\n", locks); - while(locks--) { - GlobalUnlock(lppd->hDevMode); - TRACE("Now got %d locks\n", locks); - } - } - lppd->hDevMode = GlobalReAlloc(lppd->hDevMode, - lpdm->dmSize + lpdm->dmDriverExtra, - GMEM_MOVEABLE); - } - lpdmReturn = GlobalLock(lppd->hDevMode); - memcpy(lpdmReturn, lpdm, lpdm->dmSize + lpdm->dmDriverExtra); - - if (lppd->hDevNames != 0) { - WORD locks; - if((locks = (GlobalFlags(lppd->hDevNames) & GMEM_LOCKCOUNT))) { - WARN("hDevNames has %d locks on it. Unlocking it now\n", locks); - while(locks--) - GlobalUnlock(lppd->hDevNames); - } - } - PRINTDLG_CreateDevNames(&(lppd->hDevNames), - di->pDriverPath, - pi->pPrinterName, - pi->pPortName - ); - GlobalUnlock(lppd->hDevMode); - } - HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode); - HeapFree(GetProcessHeap(), 0, PrintStructures->lpPrinterInfo); - HeapFree(GetProcessHeap(), 0, PrintStructures->lpDriverInfo); - HeapFree(GetProcessHeap(), 0, PrintStructures); - } - if(bRet && (lppd->Flags & PD_RETURNDC || lppd->Flags & PD_RETURNIC)) - bRet = PRINTDLG_CreateDCA(lppd); - - TRACE("exit! (%d)\n", bRet); - return bRet; -} - -/*********************************************************************** - * PrintDlgW (COMDLG32.@) - */ -BOOL WINAPI PrintDlgW( - LPPRINTDLGW lppd /* [in/out] ptr to PRINTDLG32 struct */ - ) -{ - BOOL bRet = FALSE; - LPVOID ptr; - HINSTANCE hInst = (HINSTANCE)GetWindowLongPtrW( lppd->hwndOwner, GWLP_HINSTANCE ); - - if(TRACE_ON(commdlg)) { - char flagstr[1000] = ""; - struct pd_flags *pflag = pd_flags; - for( ; pflag->name; pflag++) { - if(lppd->Flags & pflag->flag) - strcat(flagstr, pflag->name); - } - TRACE("(%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n" - "pp. %d-%d, min p %d, max p %d, copies %d, hinst %p\n" - "flags %08lx (%s)\n", - lppd, lppd->hwndOwner, lppd->hDevMode, lppd->hDevNames, - lppd->nFromPage, lppd->nToPage, lppd->nMinPage, lppd->nMaxPage, - lppd->nCopies, lppd->hInstance, lppd->Flags, flagstr); - } - - if(lppd->lStructSize != sizeof(PRINTDLGW)) { - WARN("structure size failure !!!\n"); - COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE); - return FALSE; - } - - if(lppd->Flags & PD_RETURNDEFAULT) { - PRINTER_INFO_2W *pbuf; - DRIVER_INFO_3W *dbuf; - HANDLE hprn; - DWORD needed; - - if(lppd->hDevMode || lppd->hDevNames) { - WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n"); - COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); - return FALSE; - } - if(!PRINTDLG_OpenDefaultPrinter(&hprn)) { - WARN("Can't find default printer\n"); - COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN); - return FALSE; - } - - GetPrinterW(hprn, 2, NULL, 0, &needed); - pbuf = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*needed); - GetPrinterW(hprn, 2, (LPBYTE)pbuf, needed, &needed); - - GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed); - dbuf = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*needed); - if (!GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed)) { - ERR("GetPrinterDriverA failed, le %ld, fix your config for printer %s!\n",GetLastError(),debugstr_w(pbuf->pPrinterName)); - COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); - return FALSE; - } - ClosePrinter(hprn); - - PRINTDLG_CreateDevNamesW(&(lppd->hDevNames), - dbuf->pDriverPath, - pbuf->pPrinterName, - pbuf->pPortName); - lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, pbuf->pDevMode->dmSize + - pbuf->pDevMode->dmDriverExtra); - ptr = GlobalLock(lppd->hDevMode); - memcpy(ptr, pbuf->pDevMode, pbuf->pDevMode->dmSize + - pbuf->pDevMode->dmDriverExtra); - GlobalUnlock(lppd->hDevMode); - HeapFree(GetProcessHeap(), 0, pbuf); - HeapFree(GetProcessHeap(), 0, dbuf); - bRet = TRUE; - } else { - HGLOBAL hDlgTmpl; - PRINT_PTRW *PrintStructures; - - /* load Dialog resources, - * depending on Flags indicates Print32 or Print32_setup dialog - */ - hDlgTmpl = PRINTDLG_GetDlgTemplateW(lppd); - if (!hDlgTmpl) { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - ptr = LockResource( hDlgTmpl ); - if (!ptr) { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - - PrintStructures = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(PRINT_PTRW)); - PrintStructures->lpPrintDlg = lppd; - - /* and create & process the dialog . - * -1 is failure, 0 is broken hwnd, everything else is ok. - */ - bRet = (0hwndOwner, - PrintDlgProcW, - (LPARAM)PrintStructures)); - - if(bRet) { - DEVMODEW *lpdm = PrintStructures->lpDevMode, *lpdmReturn; - PRINTER_INFO_2W *pi = PrintStructures->lpPrinterInfo; - DRIVER_INFO_3W *di = PrintStructures->lpDriverInfo; - - if (lppd->hDevMode == 0) { - TRACE(" No hDevMode yet... Need to create my own\n"); - lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, - lpdm->dmSize + lpdm->dmDriverExtra); - } else { - WORD locks; - if((locks = (GlobalFlags(lppd->hDevMode) & GMEM_LOCKCOUNT))) { - WARN("hDevMode has %d locks on it. Unlocking it now\n", locks); - while(locks--) { - GlobalUnlock(lppd->hDevMode); - TRACE("Now got %d locks\n", locks); - } - } - lppd->hDevMode = GlobalReAlloc(lppd->hDevMode, - lpdm->dmSize + lpdm->dmDriverExtra, - GMEM_MOVEABLE); - } - lpdmReturn = GlobalLock(lppd->hDevMode); - memcpy(lpdmReturn, lpdm, lpdm->dmSize + lpdm->dmDriverExtra); - - if (lppd->hDevNames != 0) { - WORD locks; - if((locks = (GlobalFlags(lppd->hDevNames) & GMEM_LOCKCOUNT))) { - WARN("hDevNames has %d locks on it. Unlocking it now\n", locks); - while(locks--) - GlobalUnlock(lppd->hDevNames); - } - } - PRINTDLG_CreateDevNamesW(&(lppd->hDevNames), - di->pDriverPath, - pi->pPrinterName, - pi->pPortName - ); - GlobalUnlock(lppd->hDevMode); - } - HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode); - HeapFree(GetProcessHeap(), 0, PrintStructures->lpPrinterInfo); - HeapFree(GetProcessHeap(), 0, PrintStructures->lpDriverInfo); - HeapFree(GetProcessHeap(), 0, PrintStructures); - } - if(bRet && (lppd->Flags & PD_RETURNDC || lppd->Flags & PD_RETURNIC)) - bRet = PRINTDLG_CreateDCW(lppd); - - TRACE("exit! (%d)\n", bRet); - return bRet; -} - -/*********************************************************************** - * - * PageSetupDlg - * rad1 - portrait - * rad2 - landscape - * cmb1 - printer select (not in standart dialog template) - * cmb2 - paper size - * cmb3 - source (tray?) - * edt4 - border left - * edt5 - border top - * edt6 - border right - * edt7 - border bottom - * psh3 - "Printer..." - */ - -typedef struct { - LPPAGESETUPDLGA dlga; - PRINTDLGA pdlg; -} PageSetupDataA; - -typedef struct { - LPPAGESETUPDLGW dlga; - PRINTDLGW pdlg; -} PageSetupDataW; - -static HGLOBAL PRINTDLG_GetPGSTemplateA(PAGESETUPDLGA *lppd) -{ - HRSRC hResInfo; - HGLOBAL hDlgTmpl; - - if(lppd->Flags & PSD_ENABLEPAGESETUPTEMPLATEHANDLE) { - hDlgTmpl = lppd->hPageSetupTemplate; - } else if(lppd->Flags & PSD_ENABLEPAGESETUPTEMPLATE) { - hResInfo = FindResourceA(lppd->hInstance, - lppd->lpPageSetupTemplateName, (LPSTR)RT_DIALOG); - hDlgTmpl = LoadResource(lppd->hInstance, hResInfo); - } else { - hResInfo = FindResourceA(COMDLG32_hInstance,(LPCSTR)PAGESETUPDLGORD,(LPSTR)RT_DIALOG); - hDlgTmpl = LoadResource(COMDLG32_hInstance,hResInfo); - } - return hDlgTmpl; -} - -static HGLOBAL PRINTDLG_GetPGSTemplateW(PAGESETUPDLGW *lppd) -{ - HRSRC hResInfo; - HGLOBAL hDlgTmpl; - - if(lppd->Flags & PSD_ENABLEPAGESETUPTEMPLATEHANDLE) { - hDlgTmpl = lppd->hPageSetupTemplate; - } else if(lppd->Flags & PSD_ENABLEPAGESETUPTEMPLATE) { - hResInfo = FindResourceW(lppd->hInstance, - lppd->lpPageSetupTemplateName, (LPWSTR)RT_DIALOG); - hDlgTmpl = LoadResource(lppd->hInstance, hResInfo); - } else { - hResInfo = FindResourceW(COMDLG32_hInstance,(LPCWSTR)PAGESETUPDLGORD,(LPWSTR)RT_DIALOG); - hDlgTmpl = LoadResource(COMDLG32_hInstance,hResInfo); - } - return hDlgTmpl; -} - -static DWORD -_c_10mm2size(PAGESETUPDLGA *dlga,DWORD size) { - if (dlga->Flags & PSD_INTHOUSANDTHSOFINCHES) - return 10*size*10/25.4; - /* If we don't have a flag, we can choose one. Use millimeters - * to avoid confusing me - */ - dlga->Flags |= PSD_INHUNDREDTHSOFMILLIMETERS; - return 10*size; -} - - -static DWORD -_c_inch2size(PAGESETUPDLGA *dlga,DWORD size) { - if (dlga->Flags & PSD_INTHOUSANDTHSOFINCHES) - return size; - if (dlga->Flags & PSD_INHUNDREDTHSOFMILLIMETERS) - return (size*254)/10; - /* if we don't have a flag, we can choose one. Use millimeters - * to avoid confusing me - */ - dlga->Flags |= PSD_INHUNDREDTHSOFMILLIMETERS; - return (size*254)/10; -} - -static void -_c_size2strA(PageSetupDataA *pda,DWORD size,LPSTR strout) { - strcpy(strout,""); - if (pda->dlga->Flags & PSD_INHUNDREDTHSOFMILLIMETERS) { - sprintf(strout,"%.2fmm",(size*1.0)/100.0); - return; - } - if (pda->dlga->Flags & PSD_INTHOUSANDTHSOFINCHES) { - sprintf(strout,"%.2fin",(size*1.0)/1000.0); - return; - } - pda->dlga->Flags |= PSD_INHUNDREDTHSOFMILLIMETERS; - sprintf(strout,"%.2fmm",(size*1.0)/100.0); - return; -} -static void -_c_size2strW(PageSetupDataW *pda,DWORD size,LPWSTR strout) { - const static WCHAR UNDEF[] = { '<', 'u', 'n', 'd', 'e', 'f', '>', 0 }; - const static WCHAR mm_fmt[] = { '%', '.', '2', 'f', 'm', 'm', 0 }; - const static WCHAR in_fmt[] = { '%', '.', '2', 'f', 'i', 'n', 0 }; - lstrcpyW(strout, UNDEF); - if (pda->dlga->Flags & PSD_INHUNDREDTHSOFMILLIMETERS) { - wsprintfW(strout,mm_fmt,(size*1.0)/100.0); - return; - } - if (pda->dlga->Flags & PSD_INTHOUSANDTHSOFINCHES) { - wsprintfW(strout,in_fmt,(size*1.0)/1000.0); - return; - } - pda->dlga->Flags |= PSD_INHUNDREDTHSOFMILLIMETERS; - wsprintfW(strout,mm_fmt,(size*1.0)/100.0); - return; -} - -static DWORD -_c_str2sizeA(PAGESETUPDLGA *dlga,LPCSTR strin) { - float val; - char rest[200]; - - rest[0]='\0'; - if (!sscanf(strin,"%f%s",&val,rest)) - return 0; - - if (!strcmp(rest,"in") || !strcmp(rest,"inch")) { - if (dlga->Flags & PSD_INTHOUSANDTHSOFINCHES) - return 1000*val; - else - return val*25.4*100; - } - if (!strcmp(rest,"cm")) { rest[0]='m'; val = val*10.0; } - if (!strcmp(rest,"m")) { strcpy(rest,"mm"); val = val*1000.0; } - - if (!strcmp(rest,"mm")) { - if (dlga->Flags & PSD_INHUNDREDTHSOFMILLIMETERS) - return 100*val; - else - return 1000.0*val/25.4; - } - if (rest[0]=='\0') { - /* use application supplied default */ - if (dlga->Flags & PSD_INHUNDREDTHSOFMILLIMETERS) { - /* 100*mm */ - return 100.0*val; - } - if (dlga->Flags & PSD_INTHOUSANDTHSOFINCHES) { - /* 1000*inch */ - return 1000.0*val; - } - } - ERR("Did not find a conversion for type '%s'!\n",rest); - return 0; -} - - -static DWORD -_c_str2sizeW(PAGESETUPDLGW *dlga, LPCWSTR strin) { - char buf[200]; - - /* this W -> A transition is OK */ - /* we need a unicode version of sscanf to avoid it */ - WideCharToMultiByte(CP_ACP, 0, strin, -1, buf, sizeof(buf), NULL, NULL); - return _c_str2sizeA((PAGESETUPDLGA *)dlga, buf); -} - - -/* - * This is called on finish and will update the output fields of the - * struct. - */ -static BOOL -PRINTDLG_PS_UpdateDlgStructA(HWND hDlg, PageSetupDataA *pda) { - DEVNAMES *dn; - DEVMODEA *dm; - LPSTR devname,portname; - char papername[64]; - char buf[200]; - - dn = GlobalLock(pda->pdlg.hDevNames); - dm = GlobalLock(pda->pdlg.hDevMode); - devname = ((char*)dn)+dn->wDeviceOffset; - portname = ((char*)dn)+dn->wOutputOffset; - PRINTDLG_SetUpPaperComboBoxA(hDlg,cmb2,devname,portname,dm); - PRINTDLG_SetUpPaperComboBoxA(hDlg,cmb3,devname,portname,dm); - - if (GetDlgItemTextA(hDlg,cmb2,papername,sizeof(papername))>0) { - PRINTDLG_PaperSizeA(&(pda->pdlg),papername,&(pda->dlga->ptPaperSize)); - pda->dlga->ptPaperSize.x = _c_10mm2size(pda->dlga,pda->dlga->ptPaperSize.x); - pda->dlga->ptPaperSize.y = _c_10mm2size(pda->dlga,pda->dlga->ptPaperSize.y); - } else - FIXME("could not get dialog text for papersize cmbbox?\n"); -#define GETVAL(id,val) if (GetDlgItemTextA(hDlg,id,buf,sizeof(buf))>0) { val = _c_str2sizeA(pda->dlga,buf); } else { FIXME("could not get dlgitemtexta for %x\n",id); } - GETVAL(edt4,pda->dlga->rtMargin.left); - GETVAL(edt5,pda->dlga->rtMargin.top); - GETVAL(edt6,pda->dlga->rtMargin.right); - GETVAL(edt7,pda->dlga->rtMargin.bottom); -#undef GETVAL - - /* If we are in landscape, swap x and y of page size */ - if (IsDlgButtonChecked(hDlg, rad2)) { - DWORD tmp; - tmp = pda->dlga->ptPaperSize.x; - pda->dlga->ptPaperSize.x = pda->dlga->ptPaperSize.y; - pda->dlga->ptPaperSize.y = tmp; - } - GlobalUnlock(pda->pdlg.hDevNames); - GlobalUnlock(pda->pdlg.hDevMode); - return TRUE; -} - -static BOOL -PRINTDLG_PS_UpdateDlgStructW(HWND hDlg, PageSetupDataW *pda) { - DEVNAMES *dn; - DEVMODEW *dm; - LPWSTR devname,portname; - WCHAR papername[64]; - WCHAR buf[200]; - - dn = GlobalLock(pda->pdlg.hDevNames); - dm = GlobalLock(pda->pdlg.hDevMode); - devname = ((WCHAR*)dn)+dn->wDeviceOffset; - portname = ((WCHAR*)dn)+dn->wOutputOffset; - PRINTDLG_SetUpPaperComboBoxW(hDlg,cmb2,devname,portname,dm); - PRINTDLG_SetUpPaperComboBoxW(hDlg,cmb3,devname,portname,dm); - - if (GetDlgItemTextW(hDlg,cmb2,papername,sizeof(papername))>0) { - PRINTDLG_PaperSizeW(&(pda->pdlg),papername,&(pda->dlga->ptPaperSize)); - pda->dlga->ptPaperSize.x = _c_10mm2size((LPPAGESETUPDLGA)pda->dlga,pda->dlga->ptPaperSize.x); - pda->dlga->ptPaperSize.y = _c_10mm2size((LPPAGESETUPDLGA)pda->dlga,pda->dlga->ptPaperSize.y); - } else - FIXME("could not get dialog text for papersize cmbbox?\n"); -#define GETVAL(id,val) if (GetDlgItemTextW(hDlg,id,buf,sizeof(buf)/sizeof(buf[0]))>0) { val = _c_str2sizeW(pda->dlga,buf); } else { FIXME("could not get dlgitemtextw for %x\n",id); } - GETVAL(edt4,pda->dlga->rtMargin.left); - GETVAL(edt5,pda->dlga->rtMargin.top); - GETVAL(edt6,pda->dlga->rtMargin.right); - GETVAL(edt7,pda->dlga->rtMargin.bottom); -#undef GETVAL - - /* If we are in landscape, swap x and y of page size */ - if (IsDlgButtonChecked(hDlg, rad2)) { - DWORD tmp; - tmp = pda->dlga->ptPaperSize.x; - pda->dlga->ptPaperSize.x = pda->dlga->ptPaperSize.y; - pda->dlga->ptPaperSize.y = tmp; - } - GlobalUnlock(pda->pdlg.hDevNames); - GlobalUnlock(pda->pdlg.hDevMode); - return TRUE; -} - -/* - * This is called after returning from PrintDlg(). - */ -static BOOL -PRINTDLG_PS_ChangePrinterA(HWND hDlg, PageSetupDataA *pda) { - DEVNAMES *dn; - DEVMODEA *dm; - LPSTR devname,portname; - - dn = GlobalLock(pda->pdlg.hDevNames); - dm = GlobalLock(pda->pdlg.hDevMode); - devname = ((char*)dn)+dn->wDeviceOffset; - portname = ((char*)dn)+dn->wOutputOffset; - PRINTDLG_SetUpPaperComboBoxA(hDlg,cmb2,devname,portname,dm); - PRINTDLG_SetUpPaperComboBoxA(hDlg,cmb3,devname,portname,dm); - GlobalUnlock(pda->pdlg.hDevNames); - GlobalUnlock(pda->pdlg.hDevMode); - return TRUE; -} - -static BOOL -PRINTDLG_PS_ChangePrinterW(HWND hDlg, PageSetupDataW *pda) { - DEVNAMES *dn; - DEVMODEW *dm; - LPWSTR devname,portname; - - dn = GlobalLock(pda->pdlg.hDevNames); - dm = GlobalLock(pda->pdlg.hDevMode); - devname = ((WCHAR*)dn)+dn->wDeviceOffset; - portname = ((WCHAR*)dn)+dn->wOutputOffset; - PRINTDLG_SetUpPaperComboBoxW(hDlg,cmb2,devname,portname,dm); - PRINTDLG_SetUpPaperComboBoxW(hDlg,cmb3,devname,portname,dm); - GlobalUnlock(pda->pdlg.hDevNames); - GlobalUnlock(pda->pdlg.hDevMode); - return TRUE; -} - -static BOOL -PRINTDLG_PS_WMCommandA( - HWND hDlg, WPARAM wParam, LPARAM lParam, PageSetupDataA *pda -) { - TRACE("loword (lparam) %d, wparam 0x%x, lparam %08lx\n", - LOWORD(lParam),wParam,lParam); - switch (LOWORD(wParam)) { - case IDOK: - if (!PRINTDLG_PS_UpdateDlgStructA(hDlg, pda)) - return(FALSE); - EndDialog(hDlg, TRUE); - return TRUE ; - - case IDCANCEL: - EndDialog(hDlg, FALSE); - return FALSE ; - - case psh3: { - pda->pdlg.Flags = 0; - pda->pdlg.hwndOwner = hDlg; - if (PrintDlgA(&(pda->pdlg))) - PRINTDLG_PS_ChangePrinterA(hDlg,pda); - return TRUE; - } - } - return FALSE; -} - -static BOOL -PRINTDLG_PS_WMCommandW( - HWND hDlg, WPARAM wParam, LPARAM lParam, PageSetupDataW *pda -) { - TRACE("loword (lparam) %d, wparam 0x%x, lparam %08lx\n", - LOWORD(lParam),wParam,lParam); - switch (LOWORD(wParam)) { - case IDOK: - if (!PRINTDLG_PS_UpdateDlgStructW(hDlg, pda)) - return(FALSE); - EndDialog(hDlg, TRUE); - return TRUE ; - - case IDCANCEL: - EndDialog(hDlg, FALSE); - return FALSE ; - - case psh3: { - pda->pdlg.Flags = 0; - pda->pdlg.hwndOwner = hDlg; - if (PrintDlgW(&(pda->pdlg))) - PRINTDLG_PS_ChangePrinterW(hDlg,pda); - return TRUE; - } - } - return FALSE; -} - - -/*********************************************************************** - * DefaultPagePaintHook - * Default hook paint procedure that receives WM_PSD_* messages from the dialog box - * whenever the sample page is redrawn. -*/ - -static UINT_PTR -PRINTDLG_DefaultPagePaintHook(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam, PageSetupDataA *pda) -{ - LPRECT lprc = (LPRECT) lParam; - HDC hdc = (HDC) wParam; - HPEN hpen, holdpen; - LOGFONTW lf; - HFONT hfont, holdfont; - INT oldbkmode; - TRACE("uMsg: WM_USER+%d\n",uMsg-WM_USER); - - /* Call user paint hook if enable */ - if (pda->dlga->Flags & PSD_ENABLEPAGEPAINTHOOK) - if (pda->dlga->lpfnPagePaintHook(hwndDlg, uMsg, wParam, lParam)) - return TRUE; - - switch (uMsg) { - /* LPPAGESETUPDLG in lParam */ - case WM_PSD_PAGESETUPDLG: - /* Inform about the sample page rectangle */ - case WM_PSD_FULLPAGERECT: - /* Inform about the margin rectangle */ - case WM_PSD_MINMARGINRECT: - return FALSE; - - /* Draw dashed rectangle showing margins */ - case WM_PSD_MARGINRECT: - hpen = CreatePen(PS_DASH, 1, GetSysColor(COLOR_3DSHADOW)); - holdpen = SelectObject(hdc, hpen); - Rectangle(hdc, lprc->left, lprc->top, lprc->right, lprc->bottom); - DeleteObject(SelectObject(hdc, holdpen)); - return TRUE; - - - /* Draw the fake document */ - case WM_PSD_GREEKTEXTRECT: - /* select a nice scalable font, because we want the text really small */ - SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0); - lf.lfHeight = 6; /* value chosen based on visual effect */ - hfont = CreateFontIndirectW(&lf); - holdfont = SelectObject(hdc, hfont); - - /* if text not loaded, then do so now */ - if (wszFakeDocumentText[0] == '\0') - LoadStringW(COMDLG32_hInstance, - IDS_FAKEDOCTEXT, - wszFakeDocumentText, - sizeof(wszFakeDocumentText)/sizeof(wszFakeDocumentText[0])); - - oldbkmode = SetBkMode(hdc, TRANSPARENT); - DrawTextW(hdc, wszFakeDocumentText, -1, lprc, DT_TOP|DT_LEFT|DT_NOPREFIX|DT_WORDBREAK); - SetBkMode(hdc, oldbkmode); - - DeleteObject(SelectObject(hdc, holdfont)); - return TRUE; - - /* Envelope stamp */ - case WM_PSD_ENVSTAMPRECT: - /* Return address */ - case WM_PSD_YAFULLPAGERECT: - FIXME("envelope/stamp is not implemented\n"); - return FALSE; - default: - FIXME("Unknown message %x\n",uMsg); - return FALSE; - } - return TRUE; -} - -/*********************************************************************** - * PagePaintProc - * The main paint procedure for the PageSetupDlg function. - * The Page Setup dialog box includes an image of a sample page that shows how - * the user's selections affect the appearance of the printed output. - * The image consists of a rectangle that represents the selected paper - * or envelope type, with a dotted-line rectangle representing - * the current margins, and partial (Greek text) characters - * to show how text looks on the printed page. - * - * The following messages in the order sends to user hook procedure: - * WM_PSD_PAGESETUPDLG Draw the contents of the sample page - * WM_PSD_FULLPAGERECT Inform about the bounding rectangle - * WM_PSD_MINMARGINRECT Inform about the margin rectangle (min margin?) - * WM_PSD_MARGINRECT Draw the margin rectangle - * WM_PSD_GREEKTEXTRECT Draw the Greek text inside the margin rectangle - * If any of first three messages returns TRUE, painting done. - * - * PARAMS: - * hWnd [in] Handle to the Page Setup dialog box - * uMsg [in] Received message - * - * TODO: - * WM_PSD_ENVSTAMPRECT Draw in the envelope-stamp rectangle (for envelopes only) - * WM_PSD_YAFULLPAGERECT Draw the return address portion (for envelopes and other paper sizes) - * - * RETURNS: - * FALSE if all done correctly - * - */ -static LRESULT CALLBACK -PRINTDLG_PagePaintProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - PAINTSTRUCT ps; - RECT rcClient, rcMargin; - HPEN hpen, holdpen; - HDC hdc; - HBRUSH hbrush, holdbrush; - PageSetupDataA *pda; - int papersize=0, orientation=0; /* FIXME: set this values */ - -#define CALLPAINTHOOK(msg,lprc) PRINTDLG_DefaultPagePaintHook( hWnd, msg, (WPARAM)hdc, (LPARAM)lprc, pda) - - if (uMsg != WM_PAINT) - return CallWindowProcA(lpfnStaticWndProc, hWnd, uMsg, wParam, lParam); - - /* Processing WM_PAINT message */ - pda = (PageSetupDataA*)GetPropA(hWnd, "__WINE_PAGESETUPDLGDATA"); - if (!pda) { - WARN("__WINE_PAGESETUPDLGDATA prop not set?\n"); - return FALSE; - } - if (PRINTDLG_DefaultPagePaintHook(hWnd, WM_PSD_PAGESETUPDLG, MAKELONG(papersize, orientation), (LPARAM)pda->dlga, pda)) - return FALSE; - - hdc = BeginPaint(hWnd, &ps); - GetClientRect(hWnd, &rcClient); - - /* FIXME: use real margin values */ - rcMargin = rcClient; - rcMargin.left += 5; - rcMargin.top += 5; - rcMargin.right -= 5; - rcMargin.bottom -= 5; - - /* if the space is too small then we make sure to not draw anything */ - rcMargin.left = min(rcMargin.left, rcMargin.right); - rcMargin.top = min(rcMargin.top, rcMargin.bottom); - - if (!CALLPAINTHOOK(WM_PSD_FULLPAGERECT, &rcClient) && - !CALLPAINTHOOK(WM_PSD_MINMARGINRECT, &rcMargin) ) - { - /* fill background */ - hbrush = GetSysColorBrush(COLOR_3DHIGHLIGHT); - FillRect(hdc, &rcClient, hbrush); - holdbrush = SelectObject(hdc, hbrush); - - hpen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW)); - holdpen = SelectObject(hdc, hpen); - - - /* paint left edge */ - MoveToEx(hdc, rcClient.left, rcClient.top, NULL); - LineTo(hdc, rcClient.left, rcClient.bottom-1); - - /* paint top edge */ - MoveToEx(hdc, rcClient.left, rcClient.top, NULL); - LineTo(hdc, rcClient.right, rcClient.top); - - hpen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DDKSHADOW)); - DeleteObject(SelectObject(hdc, hpen)); - - /* paint right edge */ - MoveToEx(hdc, rcClient.right-1, rcClient.top, NULL); - LineTo(hdc, rcClient.right-1, rcClient.bottom); - - /* paint bottom edge */ - MoveToEx(hdc, rcClient.left, rcClient.bottom-1, NULL); - LineTo(hdc, rcClient.right, rcClient.bottom-1); - - DeleteObject(SelectObject(hdc, holdpen)); - DeleteObject(SelectObject(hdc, holdbrush)); - - - CALLPAINTHOOK(WM_PSD_MARGINRECT, &rcMargin); - - - /* give text a bit of a space from the frame */ - rcMargin.left += 2; - rcMargin.top += 2; - rcMargin.right -= 2; - rcMargin.bottom -= 2; - - /* if the space is too small then we make sure to not draw anything */ - rcMargin.left = min(rcMargin.left, rcMargin.right); - rcMargin.top = min(rcMargin.top, rcMargin.bottom); - - CALLPAINTHOOK(WM_PSD_GREEKTEXTRECT, &rcMargin); - } - - EndPaint(hWnd, &ps); - return FALSE; -#undef CALLPAINTHOOK -} - -/*********************************************************************** - * PRINTDLG_PageDlgProcA - * Message handler - */ -static INT_PTR CALLBACK -PRINTDLG_PageDlgProcA(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - PageSetupDataA *pda; - INT_PTR res = FALSE; - - if (uMsg == WM_INITDIALOG) { - pda = (PageSetupDataA*)lParam; - TRACE("set property to %p", pda); - SetPropA(hDlg, "__WINE_PAGESETUPDLGDATA", pda); - SetPropA(GetDlgItem(hDlg, rct1), "__WINE_PAGESETUPDLGDATA", pda); - lpfnStaticWndProc = (WNDPROC)SetWindowLongPtrW( - GetDlgItem(hDlg, rct1), - GWLP_WNDPROC, - (ULONG_PTR)PRINTDLG_PagePaintProc); - res = TRUE; - if (pda->dlga->Flags & PSD_ENABLEPAGESETUPHOOK) { - res = pda->dlga->lpfnPageSetupHook(hDlg,uMsg,wParam,(LPARAM)pda->dlga); - if (!res) { - FIXME("Setup page hook failed?\n"); - res = TRUE; - } - } - - if (pda->dlga->Flags & PSD_DISABLEPRINTER) - EnableWindow(GetDlgItem(hDlg, psh3), FALSE); - if (pda->dlga->Flags & PSD_DISABLEMARGINS) { - EnableWindow(GetDlgItem(hDlg, edt4), FALSE); - EnableWindow(GetDlgItem(hDlg, edt5), FALSE); - EnableWindow(GetDlgItem(hDlg, edt6), FALSE); - EnableWindow(GetDlgItem(hDlg, edt7), FALSE); - } - /* width larger as height -> landscape */ - if (pda->dlga->ptPaperSize.x > pda->dlga->ptPaperSize.y) - CheckRadioButton(hDlg, rad1, rad2, rad2); - else /* this is default if papersize is not set */ - CheckRadioButton(hDlg, rad1, rad2, rad1); - if (pda->dlga->Flags & PSD_DISABLEORIENTATION) { - EnableWindow(GetDlgItem(hDlg,rad1),FALSE); - EnableWindow(GetDlgItem(hDlg,rad2),FALSE); - } - /* We fill them out enabled or not */ - if (pda->dlga->Flags & PSD_MARGINS) { - char str[100]; - _c_size2strA(pda,pda->dlga->rtMargin.left,str); - SetDlgItemTextA(hDlg,edt4,str); - _c_size2strA(pda,pda->dlga->rtMargin.top,str); - SetDlgItemTextA(hDlg,edt5,str); - _c_size2strA(pda,pda->dlga->rtMargin.right,str); - SetDlgItemTextA(hDlg,edt6,str); - _c_size2strA(pda,pda->dlga->rtMargin.bottom,str); - SetDlgItemTextA(hDlg,edt7,str); - } else { - /* default is 1 inch */ - DWORD size = _c_inch2size(pda->dlga,1000); - char str[20]; - _c_size2strA(pda,size,str); - SetDlgItemTextA(hDlg,edt4,str); - SetDlgItemTextA(hDlg,edt5,str); - SetDlgItemTextA(hDlg,edt6,str); - SetDlgItemTextA(hDlg,edt7,str); - } - PRINTDLG_PS_ChangePrinterA(hDlg,pda); - if (pda->dlga->Flags & PSD_DISABLEPAPER) { - EnableWindow(GetDlgItem(hDlg,cmb2),FALSE); - EnableWindow(GetDlgItem(hDlg,cmb3),FALSE); - } - return TRUE; - } else { - pda = (PageSetupDataA*)GetPropA(hDlg,"__WINE_PAGESETUPDLGDATA"); - if (!pda) { - WARN("__WINE_PAGESETUPDLGDATA prop not set?\n"); - return FALSE; - } - if (pda->dlga->Flags & PSD_ENABLEPAGESETUPHOOK) { - res = pda->dlga->lpfnPageSetupHook(hDlg,uMsg,wParam,lParam); - if (res) return res; - } - } - switch (uMsg) { - case WM_COMMAND: - return PRINTDLG_PS_WMCommandA(hDlg, wParam, lParam, pda); - } - return FALSE; -} - -static INT_PTR CALLBACK -PageDlgProcW(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - const static WCHAR __WINE_PAGESETUPDLGDATA[] = - { '_', '_', 'W', 'I', 'N', 'E', '_', 'P', 'A', 'G', 'E', - 'S', 'E', 'T', 'U', 'P', 'D', 'L', 'G', 'D', 'A', 'T', 'A', 0 }; - PageSetupDataW *pda; - BOOL res = FALSE; - - if (uMsg==WM_INITDIALOG) { - res = TRUE; - pda = (PageSetupDataW*)lParam; - SetPropW(hDlg, __WINE_PAGESETUPDLGDATA, pda); - if (pda->dlga->Flags & PSD_ENABLEPAGESETUPHOOK) { - res = pda->dlga->lpfnPageSetupHook(hDlg,uMsg,wParam,(LPARAM)pda->dlga); - if (!res) { - FIXME("Setup page hook failed?\n"); - res = TRUE; - } - } - if (pda->dlga->Flags & PSD_ENABLEPAGEPAINTHOOK) { - FIXME("PagePaintHook not yet implemented!\n"); - } - if (pda->dlga->Flags & PSD_DISABLEPRINTER) - EnableWindow(GetDlgItem(hDlg, psh3), FALSE); - if (pda->dlga->Flags & PSD_DISABLEMARGINS) { - EnableWindow(GetDlgItem(hDlg, edt4), FALSE); - EnableWindow(GetDlgItem(hDlg, edt5), FALSE); - EnableWindow(GetDlgItem(hDlg, edt6), FALSE); - EnableWindow(GetDlgItem(hDlg, edt7), FALSE); - } - /* width larger as height -> landscape */ - if (pda->dlga->ptPaperSize.x > pda->dlga->ptPaperSize.y) - CheckRadioButton(hDlg, rad1, rad2, rad2); - else /* this is default if papersize is not set */ - CheckRadioButton(hDlg, rad1, rad2, rad1); - if (pda->dlga->Flags & PSD_DISABLEORIENTATION) { - EnableWindow(GetDlgItem(hDlg,rad1),FALSE); - EnableWindow(GetDlgItem(hDlg,rad2),FALSE); - } - /* We fill them out enabled or not */ - if (pda->dlga->Flags & PSD_MARGINS) { - WCHAR str[100]; - _c_size2strW(pda,pda->dlga->rtMargin.left,str); - SetDlgItemTextW(hDlg,edt4,str); - _c_size2strW(pda,pda->dlga->rtMargin.top,str); - SetDlgItemTextW(hDlg,edt5,str); - _c_size2strW(pda,pda->dlga->rtMargin.right,str); - SetDlgItemTextW(hDlg,edt6,str); - _c_size2strW(pda,pda->dlga->rtMargin.bottom,str); - SetDlgItemTextW(hDlg,edt7,str); - } else { - /* default is 1 inch */ - DWORD size = _c_inch2size((LPPAGESETUPDLGA)pda->dlga,1000); - WCHAR str[20]; - _c_size2strW(pda,size,str); - SetDlgItemTextW(hDlg,edt4,str); - SetDlgItemTextW(hDlg,edt5,str); - SetDlgItemTextW(hDlg,edt6,str); - SetDlgItemTextW(hDlg,edt7,str); - } - PRINTDLG_PS_ChangePrinterW(hDlg,pda); - if (pda->dlga->Flags & PSD_DISABLEPAPER) { - EnableWindow(GetDlgItem(hDlg,cmb2),FALSE); - EnableWindow(GetDlgItem(hDlg,cmb3),FALSE); - } - return TRUE; - } else { - pda = (PageSetupDataW*)GetPropW(hDlg, __WINE_PAGESETUPDLGDATA); - if (!pda) { - WARN("__WINE_PAGESETUPDLGDATA prop not set?\n"); - return FALSE; - } - if (pda->dlga->Flags & PSD_ENABLEPAGESETUPHOOK) { - res = pda->dlga->lpfnPageSetupHook(hDlg,uMsg,wParam,lParam); - if (res) return res; - } - } - switch (uMsg) { - case WM_COMMAND: - return PRINTDLG_PS_WMCommandW(hDlg, wParam, lParam, pda); - } - return FALSE; -} - -/*********************************************************************** - * PageSetupDlgA (COMDLG32.@) - * - * Displays the the PAGE SETUP dialog box, which enables the user to specify - * specific properties of a printed page such as - * size, source, orientation and the width of the page margins. - * - * PARAMS - * setupdlg [in] PAGESETUPDLGA struct - * - * RETURNS - * TRUE if the user pressed the OK button - * FALSE if the user cancelled the window or an error occurred - * - * NOTES - * The values of hDevMode and hDevNames are filled on output and can be - * changed in PAGESETUPDLG when they are passed in PageSetupDlg. - * BUGS - * PrintSetupDlg: - * * The Paper Orientation Icons are not implemented yet. - * * The Properties Button(s) should call DocumentPropertiesA(). - * * Settings are not yet taken from a provided DevMode or - * default printer settings. - */ - -BOOL WINAPI PageSetupDlgA(LPPAGESETUPDLGA setupdlg) { - HGLOBAL hDlgTmpl; - LPVOID ptr; - BOOL bRet; - PageSetupDataA *pda; - PRINTDLGA pdlg; - - if(TRACE_ON(commdlg)) { - char flagstr[1000] = ""; - struct pd_flags *pflag = psd_flags; - for( ; pflag->name; pflag++) { - if(setupdlg->Flags & pflag->flag) { - strcat(flagstr, pflag->name); - strcat(flagstr, "|"); - } - } - TRACE("(%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n" - "hinst %p, flags %08lx (%s)\n", - setupdlg, setupdlg->hwndOwner, setupdlg->hDevMode, - setupdlg->hDevNames, - setupdlg->hInstance, setupdlg->Flags, flagstr); - } - if (setupdlg->Flags & PSD_ENABLEPAGEPAINTHOOK) - if (setupdlg->lpfnPagePaintHook == NULL) { - COMDLG32_SetCommDlgExtendedError(CDERR_NOHOOK); - return FALSE; - } - - /* First get default printer data, we need it right after that. */ - memset(&pdlg,0,sizeof(pdlg)); - pdlg.lStructSize = sizeof(pdlg); - pdlg.Flags = PD_RETURNDEFAULT; - bRet = PrintDlgA(&pdlg); - if (!bRet) return FALSE; - - /* short cut exit, just return default values */ - if (setupdlg->Flags & PSD_RETURNDEFAULT) { - setupdlg->hDevMode = pdlg.hDevMode; - setupdlg->hDevNames = pdlg.hDevNames; - /* FIXME: Just return "A4" for now. */ - PRINTDLG_PaperSizeA(&pdlg,"A4",&setupdlg->ptPaperSize); - setupdlg->ptPaperSize.x=_c_10mm2size(setupdlg,setupdlg->ptPaperSize.x); - setupdlg->ptPaperSize.y=_c_10mm2size(setupdlg,setupdlg->ptPaperSize.y); - return TRUE; - } - hDlgTmpl = PRINTDLG_GetPGSTemplateA(setupdlg); - if (!hDlgTmpl) { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - ptr = LockResource( hDlgTmpl ); - if (!ptr) { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - pda = HeapAlloc(GetProcessHeap(),0,sizeof(*pda)); - pda->dlga = setupdlg; - memcpy(&pda->pdlg,&pdlg,sizeof(pdlg)); - - bRet = (0hInstance, - ptr, - setupdlg->hwndOwner, - PRINTDLG_PageDlgProcA, - (LPARAM)pda) - ); - return bRet; -} -/*********************************************************************** - * PageSetupDlgW (COMDLG32.@) - */ -BOOL WINAPI PageSetupDlgW(LPPAGESETUPDLGW setupdlg) { - HGLOBAL hDlgTmpl; - LPVOID ptr; - BOOL bRet; - PageSetupDataW *pdw; - PRINTDLGW pdlg; - FIXME("Unicode implementation is not done yet\n"); - if(TRACE_ON(commdlg)) { - char flagstr[1000] = ""; - struct pd_flags *pflag = psd_flags; - for( ; pflag->name; pflag++) { - if(setupdlg->Flags & pflag->flag) { - strcat(flagstr, pflag->name); - strcat(flagstr, "|"); - } - } - TRACE("(%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n" - "hinst %p, flags %08lx (%s)\n", - setupdlg, setupdlg->hwndOwner, setupdlg->hDevMode, - setupdlg->hDevNames, - setupdlg->hInstance, setupdlg->Flags, flagstr); - } - - /* First get default printer data, we need it right after that. */ - memset(&pdlg,0,sizeof(pdlg)); - pdlg.lStructSize = sizeof(pdlg); - pdlg.Flags = PD_RETURNDEFAULT; - bRet = PrintDlgW(&pdlg); - if (!bRet) return FALSE; - - /* short cut exit, just return default values */ - if (setupdlg->Flags & PSD_RETURNDEFAULT) { - static const WCHAR a4[] = {'A','4',0}; - setupdlg->hDevMode = pdlg.hDevMode; - setupdlg->hDevNames = pdlg.hDevNames; - /* FIXME: Just return "A4" for now. */ - PRINTDLG_PaperSizeW(&pdlg,a4,&setupdlg->ptPaperSize); - setupdlg->ptPaperSize.x=_c_10mm2size((LPPAGESETUPDLGA)setupdlg,setupdlg->ptPaperSize.x); - setupdlg->ptPaperSize.y=_c_10mm2size((LPPAGESETUPDLGA)setupdlg,setupdlg->ptPaperSize.y); - return TRUE; - } - hDlgTmpl = PRINTDLG_GetPGSTemplateW(setupdlg); - if (!hDlgTmpl) { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - ptr = LockResource( hDlgTmpl ); - if (!ptr) { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - pdw = HeapAlloc(GetProcessHeap(),0,sizeof(*pdw)); - pdw->dlga = setupdlg; - memcpy(&pdw->pdlg,&pdlg,sizeof(pdlg)); - - bRet = (0hInstance, - ptr, - setupdlg->hwndOwner, - PageDlgProcW, - (LPARAM)pdw) - ); - return bRet; -} - -/*********************************************************************** - * PrintDlgExA (COMDLG32.@) - */ -HRESULT WINAPI PrintDlgExA(LPPRINTDLGEXA lpPrintDlgExA) -{ - FIXME("stub\n"); - return E_NOTIMPL; -} - -/*********************************************************************** - * PrintDlgExW (COMDLG32.@) - */ -HRESULT WINAPI PrintDlgExW(LPPRINTDLGEXW lpPrintDlgExW) -{ - FIXME("stub\n"); - return E_NOTIMPL; -} +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winspool.h" +#include "winerror.h" + +#include "wine/debug.h" + +#include "commdlg.h" +#include "dlgs.h" +#include "cderr.h" + +WINE_DEFAULT_DEBUG_CHANNEL(commdlg); + +#include "cdlg.h" +#include "printdlg.h" + +/* Yes these constants are the same, but we're just copying win98 */ +#define UPDOWN_ID 0x270f +#define MAX_COPIES 9999 + +/* Debugging info */ +static struct pd_flags psd_flags[] = { + {PSD_MINMARGINS,"PSD_MINMARGINS"}, + {PSD_MARGINS,"PSD_MARGINS"}, + {PSD_INTHOUSANDTHSOFINCHES,"PSD_INTHOUSANDTHSOFINCHES"}, + {PSD_INHUNDREDTHSOFMILLIMETERS,"PSD_INHUNDREDTHSOFMILLIMETERS"}, + {PSD_DISABLEMARGINS,"PSD_DISABLEMARGINS"}, + {PSD_DISABLEPRINTER,"PSD_DISABLEPRINTER"}, + {PSD_NOWARNING,"PSD_NOWARNING"}, + {PSD_DISABLEORIENTATION,"PSD_DISABLEORIENTATION"}, + {PSD_RETURNDEFAULT,"PSD_RETURNDEFAULT"}, + {PSD_DISABLEPAPER,"PSD_DISABLEPAPER"}, + {PSD_SHOWHELP,"PSD_SHOWHELP"}, + {PSD_ENABLEPAGESETUPHOOK,"PSD_ENABLEPAGESETUPHOOK"}, + {PSD_ENABLEPAGESETUPTEMPLATE,"PSD_ENABLEPAGESETUPTEMPLATE"}, + {PSD_ENABLEPAGESETUPTEMPLATEHANDLE,"PSD_ENABLEPAGESETUPTEMPLATEHANDLE"}, + {PSD_ENABLEPAGEPAINTHOOK,"PSD_ENABLEPAGEPAINTHOOK"}, + {PSD_DISABLEPAGEPAINTING,"PSD_DISABLEPAGEPAINTING"}, + {-1, NULL} +}; + +/* address of wndproc for subclassed Static control */ +static WNDPROC lpfnStaticWndProc; +/* the text of the fake document to render for the Page Setup dialog */ +static WCHAR wszFakeDocumentText[1024]; + +/*********************************************************************** + * PRINTDLG_OpenDefaultPrinter + * + * Returns a winspool printer handle to the default printer in *hprn + * Caller must call ClosePrinter on the handle + * + * Returns TRUE on success else FALSE + */ +BOOL PRINTDLG_OpenDefaultPrinter(HANDLE *hprn) +{ + WCHAR buf[260]; + DWORD dwBufLen = sizeof(buf) / sizeof(buf[0]); + BOOL res; + if(!GetDefaultPrinterW(buf, &dwBufLen)) + return FALSE; + res = OpenPrinterW(buf, hprn, NULL); + if (!res) + WARN("Could not open printer %s\n", debugstr_w(buf)); + return res; +} + +/*********************************************************************** + * PRINTDLG_SetUpPrinterListCombo + * + * Initializes printer list combox. + * hDlg: HWND of dialog + * id: Control id of combo + * name: Name of printer to select + * + * Initializes combo with list of available printers. Selects printer 'name' + * If name is NULL or does not exist select the default printer. + * + * Returns number of printers added to list. + */ +INT PRINTDLG_SetUpPrinterListComboA(HWND hDlg, UINT id, LPCSTR name) +{ + DWORD needed, num; + INT i; + LPPRINTER_INFO_2A pi; + EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num); + pi = HeapAlloc(GetProcessHeap(), 0, needed); + EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pi, needed, &needed, + &num); + + for(i = 0; i < num; i++) { + SendDlgItemMessageA(hDlg, id, CB_ADDSTRING, 0, + (LPARAM)pi[i].pPrinterName ); + } + HeapFree(GetProcessHeap(), 0, pi); + if(!name || + (i = SendDlgItemMessageA(hDlg, id, CB_FINDSTRINGEXACT, -1, + (LPARAM)name)) == CB_ERR) { + + char buf[260]; + DWORD dwBufLen = sizeof(buf); + FIXME("Can't find '%s' in printer list so trying to find default\n", + name); + if(!GetDefaultPrinterA(buf, &dwBufLen)) + return num; + i = SendDlgItemMessageA(hDlg, id, CB_FINDSTRINGEXACT, -1, (LPARAM)buf); + if(i == CB_ERR) + FIXME("Can't find default printer in printer list\n"); + } + SendDlgItemMessageA(hDlg, id, CB_SETCURSEL, i, 0); + return num; +} + +static INT PRINTDLG_SetUpPrinterListComboW(HWND hDlg, UINT id, LPCWSTR name) +{ + DWORD needed, num; + INT i; + LPPRINTER_INFO_2W pi; + EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &needed, &num); + pi = HeapAlloc(GetProcessHeap(), 0, needed); + EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pi, needed, &needed, + &num); + + for(i = 0; i < num; i++) { + SendDlgItemMessageW(hDlg, id, CB_ADDSTRING, 0, + (LPARAM)pi[i].pPrinterName ); + } + HeapFree(GetProcessHeap(), 0, pi); + if(!name || + (i = SendDlgItemMessageW(hDlg, id, CB_FINDSTRINGEXACT, -1, + (LPARAM)name)) == CB_ERR) { + WCHAR buf[260]; + DWORD dwBufLen = sizeof(buf)/sizeof(buf[0]); + TRACE("Can't find '%s' in printer list so trying to find default\n", + debugstr_w(name)); + if(!GetDefaultPrinterW(buf, &dwBufLen)) + return num; + i = SendDlgItemMessageW(hDlg, id, CB_FINDSTRINGEXACT, -1, (LPARAM)buf); + if(i == CB_ERR) + TRACE("Can't find default printer in printer list\n"); + } + SendDlgItemMessageW(hDlg, id, CB_SETCURSEL, i, 0); + return num; +} + +/*********************************************************************** + * PRINTDLG_CreateDevNames [internal] + * + * + * creates a DevNames structure. + * + * (NB. when we handle unicode the offsets will be in wchars). + */ +static BOOL PRINTDLG_CreateDevNames(HGLOBAL *hmem, char* DeviceDriverName, + char* DeviceName, char* OutputPort) +{ + long size; + char* pDevNamesSpace; + char* pTempPtr; + LPDEVNAMES lpDevNames; + char buf[260]; + DWORD dwBufLen = sizeof(buf); + + size = strlen(DeviceDriverName) + 1 + + strlen(DeviceName) + 1 + + strlen(OutputPort) + 1 + + sizeof(DEVNAMES); + + if(*hmem) + *hmem = GlobalReAlloc(*hmem, size, GMEM_MOVEABLE); + else + *hmem = GlobalAlloc(GMEM_MOVEABLE, size); + if (*hmem == 0) + return FALSE; + + pDevNamesSpace = GlobalLock(*hmem); + lpDevNames = (LPDEVNAMES) pDevNamesSpace; + + pTempPtr = pDevNamesSpace + sizeof(DEVNAMES); + strcpy(pTempPtr, DeviceDriverName); + lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace; + + pTempPtr += strlen(DeviceDriverName) + 1; + strcpy(pTempPtr, DeviceName); + lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace; + + pTempPtr += strlen(DeviceName) + 1; + strcpy(pTempPtr, OutputPort); + lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace; + + GetDefaultPrinterA(buf, &dwBufLen); + lpDevNames->wDefault = (strcmp(buf, DeviceName) == 0) ? 1 : 0; + GlobalUnlock(*hmem); + return TRUE; +} + +static BOOL PRINTDLG_CreateDevNamesW(HGLOBAL *hmem, LPCWSTR DeviceDriverName, + LPCWSTR DeviceName, LPCWSTR OutputPort) +{ + long size; + LPWSTR pDevNamesSpace; + LPWSTR pTempPtr; + LPDEVNAMES lpDevNames; + WCHAR bufW[260]; + DWORD dwBufLen = sizeof(bufW) / sizeof(WCHAR); + + size = sizeof(WCHAR)*lstrlenW(DeviceDriverName) + 2 + + sizeof(WCHAR)*lstrlenW(DeviceName) + 2 + + sizeof(WCHAR)*lstrlenW(OutputPort) + 2 + + sizeof(DEVNAMES); + + if(*hmem) + *hmem = GlobalReAlloc(*hmem, size, GMEM_MOVEABLE); + else + *hmem = GlobalAlloc(GMEM_MOVEABLE, size); + if (*hmem == 0) + return FALSE; + + pDevNamesSpace = GlobalLock(*hmem); + lpDevNames = (LPDEVNAMES) pDevNamesSpace; + + pTempPtr = (LPWSTR)((LPDEVNAMES)pDevNamesSpace + 1); + lstrcpyW(pTempPtr, DeviceDriverName); + lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace; + + pTempPtr += lstrlenW(DeviceDriverName) + 1; + lstrcpyW(pTempPtr, DeviceName); + lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace; + + pTempPtr += lstrlenW(DeviceName) + 1; + lstrcpyW(pTempPtr, OutputPort); + lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace; + + GetDefaultPrinterW(bufW, &dwBufLen); + lpDevNames->wDefault = (lstrcmpW(bufW, DeviceName) == 0) ? 1 : 0; + GlobalUnlock(*hmem); + return TRUE; +} + +/*********************************************************************** + * PRINTDLG_UpdatePrintDlg [internal] + * + * + * updates the PrintDlg structure for return values. + * + * RETURNS + * FALSE if user is not allowed to close (i.e. wrong nTo or nFrom values) + * TRUE if successful. + */ +static BOOL PRINTDLG_UpdatePrintDlgA(HWND hDlg, + PRINT_PTRA* PrintStructures) +{ + LPPRINTDLGA lppd = PrintStructures->lpPrintDlg; + PDEVMODEA lpdm = PrintStructures->lpDevMode; + LPPRINTER_INFO_2A pi = PrintStructures->lpPrinterInfo; + + + if(!lpdm) { + FIXME("No lpdm ptr?\n"); + return FALSE; + } + + + if(!(lppd->Flags & PD_PRINTSETUP)) { + /* check whether nFromPage and nToPage are within range defined by + * nMinPage and nMaxPage + */ + if (IsDlgButtonChecked(hDlg, rad3) == BST_CHECKED) { /* Pages */ + WORD nToPage; + WORD nFromPage; + nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE); + nToPage = GetDlgItemInt(hDlg, edt2, NULL, FALSE); + if (nFromPage < lppd->nMinPage || nFromPage > lppd->nMaxPage || + nToPage < lppd->nMinPage || nToPage > lppd->nMaxPage) { + char resourcestr[256]; + char resultstr[256]; + LoadStringA(COMDLG32_hInstance, PD32_INVALID_PAGE_RANGE, + resourcestr, 255); + sprintf(resultstr,resourcestr, lppd->nMinPage, lppd->nMaxPage); + LoadStringA(COMDLG32_hInstance, PD32_PRINT_TITLE, + resourcestr, 255); + MessageBoxA(hDlg, resultstr, resourcestr, + MB_OK | MB_ICONWARNING); + return FALSE; + } + lppd->nFromPage = nFromPage; + lppd->nToPage = nToPage; + lppd->Flags |= PD_PAGENUMS; + } + else + lppd->Flags &= ~PD_PAGENUMS; + + if (IsDlgButtonChecked(hDlg, chx1) == BST_CHECKED) {/* Print to file */ + lppd->Flags |= PD_PRINTTOFILE; + pi->pPortName = "FILE:"; + } + + if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) { /* Collate */ + FIXME("Collate lppd not yet implemented as output\n"); + } + + /* set PD_Collate and nCopies */ + if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { + /* The application doesn't support multiple copies or collate... + */ + lppd->Flags &= ~PD_COLLATE; + lppd->nCopies = 1; + /* if the printer driver supports it... store info there + * otherwise no collate & multiple copies ! + */ + if (lpdm->dmFields & DM_COLLATE) + lpdm->dmCollate = + (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED); + if (lpdm->dmFields & DM_COPIES) + lpdm->u.s.dmCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); + } else { + if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) + lppd->Flags |= PD_COLLATE; + else + lppd->Flags &= ~PD_COLLATE; + lppd->nCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); + } + } + return TRUE; +} + +static BOOL PRINTDLG_UpdatePrintDlgW(HWND hDlg, + PRINT_PTRW* PrintStructures) +{ + LPPRINTDLGW lppd = PrintStructures->lpPrintDlg; + PDEVMODEW lpdm = PrintStructures->lpDevMode; + LPPRINTER_INFO_2W pi = PrintStructures->lpPrinterInfo; + + + if(!lpdm) { + FIXME("No lpdm ptr?\n"); + return FALSE; + } + + + if(!(lppd->Flags & PD_PRINTSETUP)) { + /* check whether nFromPage and nToPage are within range defined by + * nMinPage and nMaxPage + */ + if (IsDlgButtonChecked(hDlg, rad3) == BST_CHECKED) { /* Pages */ + WORD nToPage; + WORD nFromPage; + nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE); + nToPage = GetDlgItemInt(hDlg, edt2, NULL, FALSE); + if (nFromPage < lppd->nMinPage || nFromPage > lppd->nMaxPage || + nToPage < lppd->nMinPage || nToPage > lppd->nMaxPage) { + WCHAR resourcestr[256]; + WCHAR resultstr[256]; + LoadStringW(COMDLG32_hInstance, PD32_INVALID_PAGE_RANGE, + resourcestr, 255); + wsprintfW(resultstr,resourcestr, lppd->nMinPage, lppd->nMaxPage); + LoadStringW(COMDLG32_hInstance, PD32_PRINT_TITLE, + resourcestr, 255); + MessageBoxW(hDlg, resultstr, resourcestr, + MB_OK | MB_ICONWARNING); + return FALSE; + } + lppd->nFromPage = nFromPage; + lppd->nToPage = nToPage; + } + + if (IsDlgButtonChecked(hDlg, chx1) == BST_CHECKED) {/* Print to file */ + static WCHAR file[] = {'F','I','L','E',':',0}; + lppd->Flags |= PD_PRINTTOFILE; + pi->pPortName = file; + } + + if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) { /* Collate */ + FIXME("Collate lppd not yet implemented as output\n"); + } + + /* set PD_Collate and nCopies */ + if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { + /* The application doesn't support multiple copies or collate... + */ + lppd->Flags &= ~PD_COLLATE; + lppd->nCopies = 1; + /* if the printer driver supports it... store info there + * otherwise no collate & multiple copies ! + */ + if (lpdm->dmFields & DM_COLLATE) + lpdm->dmCollate = + (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED); + if (lpdm->dmFields & DM_COPIES) + lpdm->u.s.dmCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); + } else { + if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) + lppd->Flags |= PD_COLLATE; + else + lppd->Flags &= ~PD_COLLATE; + lppd->nCopies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); + } + } + return TRUE; +} + +static BOOL PRINTDLG_PaperSizeA( + PRINTDLGA *pdlga,const char *PaperSize,LPPOINT size +) { + DEVNAMES *dn; + DEVMODEA *dm; + LPSTR devname,portname; + int i; + INT NrOfEntries,ret; + char *Names = NULL; + POINT *points = NULL; + BOOL retval = FALSE; + + dn = GlobalLock(pdlga->hDevNames); + dm = GlobalLock(pdlga->hDevMode); + devname = ((char*)dn)+dn->wDeviceOffset; + portname = ((char*)dn)+dn->wOutputOffset; + + + NrOfEntries = DeviceCapabilitiesA(devname,portname,DC_PAPERNAMES,NULL,dm); + if (!NrOfEntries) { + FIXME("No papernames found for %s/%s\n",devname,portname); + goto out; + } + if (NrOfEntries == -1) { + ERR("Hmm ? DeviceCapabilities() DC_PAPERNAMES failed, ret -1 !\n"); + goto out; + } + + Names = HeapAlloc(GetProcessHeap(),0,NrOfEntries*64); + if (NrOfEntries != (ret=DeviceCapabilitiesA(devname,portname,DC_PAPERNAMES,Names,dm))) { + FIXME("Number of returned vals %d is not %d\n",NrOfEntries,ret); + goto out; + } + for (i=0;ix=points[i].x; + size->y=points[i].y; + retval = TRUE; +out: + GlobalUnlock(pdlga->hDevNames); + GlobalUnlock(pdlga->hDevMode); + HeapFree(GetProcessHeap(),0,Names); + HeapFree(GetProcessHeap(),0,points); + return retval; +} + +static BOOL PRINTDLG_PaperSizeW( + PRINTDLGW *pdlga,const WCHAR *PaperSize,LPPOINT size +) { + DEVNAMES *dn; + DEVMODEW *dm; + LPWSTR devname,portname; + int i; + INT NrOfEntries,ret; + WCHAR *Names = NULL; + POINT *points = NULL; + BOOL retval = FALSE; + + dn = GlobalLock(pdlga->hDevNames); + dm = GlobalLock(pdlga->hDevMode); + devname = ((WCHAR*)dn)+dn->wDeviceOffset; + portname = ((WCHAR*)dn)+dn->wOutputOffset; + + + NrOfEntries = DeviceCapabilitiesW(devname,portname,DC_PAPERNAMES,NULL,dm); + if (!NrOfEntries) { + FIXME("No papernames found for %s/%s\n",debugstr_w(devname),debugstr_w(portname)); + goto out; + } + if (NrOfEntries == -1) { + ERR("Hmm ? DeviceCapabilities() DC_PAPERNAMES failed, ret -1 !\n"); + goto out; + } + + Names = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*NrOfEntries*64); + if (NrOfEntries != (ret=DeviceCapabilitiesW(devname,portname,DC_PAPERNAMES,Names,dm))) { + FIXME("Number of returned vals %d is not %d\n",NrOfEntries,ret); + goto out; + } + for (i=0;ix=points[i].x; + size->y=points[i].y; + retval = TRUE; +out: + GlobalUnlock(pdlga->hDevNames); + GlobalUnlock(pdlga->hDevMode); + HeapFree(GetProcessHeap(),0,Names); + HeapFree(GetProcessHeap(),0,points); + return retval; +} + + +/************************************************************************ + * PRINTDLG_SetUpPaperComboBox + * + * Initialize either the papersize or inputslot combos of the Printer Setup + * dialog. We store the associated word (eg DMPAPER_A4) as the item data. + * We also try to re-select the old selection. + */ +static BOOL PRINTDLG_SetUpPaperComboBoxA(HWND hDlg, + int nIDComboBox, + char* PrinterName, + char* PortName, + LPDEVMODEA dm) +{ + int i; + int NrOfEntries; + char* Names; + WORD* Words; + DWORD Sel; + WORD oldWord = 0; + int NamesSize; + int fwCapability_Names; + int fwCapability_Words; + + TRACE(" Printer: %s, Port: %s, ComboID: %d\n",PrinterName,PortName,nIDComboBox); + + /* query the dialog box for the current selected value */ + Sel = SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETCURSEL, 0, 0); + if(Sel != CB_ERR) { + /* we enter here only if a different printer is selected after + * the Print Setup dialog is opened. The current settings are + * stored into the newly selected printer. + */ + oldWord = SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, + Sel, 0); + if (dm) { + if (nIDComboBox == cmb2) + dm->u.s.dmPaperSize = oldWord; + else + dm->u.s.dmDefaultSource = oldWord; + } + } + else { + /* we enter here only when the Print setup dialog is initially + * opened. In this case the settings are restored from when + * the dialog was last closed. + */ + if (dm) { + if (nIDComboBox == cmb2) + oldWord = dm->u.s.dmPaperSize; + else + oldWord = dm->u.s.dmDefaultSource; + } + } + + if (nIDComboBox == cmb2) { + NamesSize = 64; + fwCapability_Names = DC_PAPERNAMES; + fwCapability_Words = DC_PAPERS; + } else { + nIDComboBox = cmb3; + NamesSize = 24; + fwCapability_Names = DC_BINNAMES; + fwCapability_Words = DC_BINS; + } + + /* for some printer drivers, DeviceCapabilities calls a VXD to obtain the + * paper settings. As Wine doesn't allow VXDs, this results in a crash. + */ + WARN(" if your printer driver uses VXDs, expect a crash now!\n"); + NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName, + fwCapability_Names, NULL, dm); + if (NrOfEntries == 0) + WARN("no Name Entries found!\n"); + else if (NrOfEntries < 0) + return FALSE; + + if(DeviceCapabilitiesA(PrinterName, PortName, fwCapability_Words, NULL, dm) + != NrOfEntries) { + ERR("Number of caps is different\n"); + NrOfEntries = 0; + } + + Names = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(char)*NamesSize); + Words = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WORD)); + NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName, + fwCapability_Names, Names, dm); + NrOfEntries = DeviceCapabilitiesA(PrinterName, PortName, + fwCapability_Words, (LPSTR)Words, dm); + + /* reset any current content in the combobox */ + SendDlgItemMessageA(hDlg, nIDComboBox, CB_RESETCONTENT, 0, 0); + + /* store new content */ + for (i = 0; i < NrOfEntries; i++) { + DWORD pos = SendDlgItemMessageA(hDlg, nIDComboBox, CB_ADDSTRING, 0, + (LPARAM)(&Names[i*NamesSize]) ); + SendDlgItemMessageA(hDlg, nIDComboBox, CB_SETITEMDATA, pos, + Words[i]); + } + + /* Look for old selection - can't do this is previous loop since + item order will change as more items are added */ + Sel = 0; + for (i = 0; i < NrOfEntries; i++) { + if(SendDlgItemMessageA(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) == + oldWord) { + Sel = i; + break; + } + } + SendDlgItemMessageA(hDlg, nIDComboBox, CB_SETCURSEL, Sel, 0); + + HeapFree(GetProcessHeap(),0,Words); + HeapFree(GetProcessHeap(),0,Names); + return TRUE; +} + +static BOOL PRINTDLG_SetUpPaperComboBoxW(HWND hDlg, + int nIDComboBox, + WCHAR* PrinterName, + WCHAR* PortName, + LPDEVMODEW dm) +{ + int i; + int NrOfEntries; + WCHAR* Names; + WORD* Words; + DWORD Sel; + WORD oldWord = 0; + int NamesSize; + int fwCapability_Names; + int fwCapability_Words; + + TRACE(" Printer: %s, Port: %s, ComboID: %d\n",debugstr_w(PrinterName),debugstr_w(PortName),nIDComboBox); + + /* query the dialog box for the current selected value */ + Sel = SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETCURSEL, 0, 0); + if(Sel != CB_ERR) { + /* we enter here only if a different printer is selected after + * the Print Setup dialog is opened. The current settings are + * stored into the newly selected printer. + */ + oldWord = SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETITEMDATA, + Sel, 0); + if (dm) { + if (nIDComboBox == cmb2) + dm->u.s.dmPaperSize = oldWord; + else + dm->u.s.dmDefaultSource = oldWord; + } + } + else { + /* we enter here only when the Print setup dialog is initially + * opened. In this case the settings are restored from when + * the dialog was last closed. + */ + if (dm) { + if (nIDComboBox == cmb2) + oldWord = dm->u.s.dmPaperSize; + else + oldWord = dm->u.s.dmDefaultSource; + } + } + + if (nIDComboBox == cmb2) { + NamesSize = 64; + fwCapability_Names = DC_PAPERNAMES; + fwCapability_Words = DC_PAPERS; + } else { + nIDComboBox = cmb3; + NamesSize = 24; + fwCapability_Names = DC_BINNAMES; + fwCapability_Words = DC_BINS; + } + + /* for some printer drivers, DeviceCapabilities calls a VXD to obtain the + * paper settings. As Wine doesn't allow VXDs, this results in a crash. + */ + WARN(" if your printer driver uses VXDs, expect a crash now!\n"); + NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName, + fwCapability_Names, NULL, dm); + if (NrOfEntries == 0) + WARN("no Name Entries found!\n"); + else if (NrOfEntries < 0) + return FALSE; + + if(DeviceCapabilitiesW(PrinterName, PortName, fwCapability_Words, NULL, dm) + != NrOfEntries) { + ERR("Number of caps is different\n"); + NrOfEntries = 0; + } + + Names = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WCHAR)*NamesSize); + Words = HeapAlloc(GetProcessHeap(),0, NrOfEntries*sizeof(WORD)); + NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName, + fwCapability_Names, Names, dm); + NrOfEntries = DeviceCapabilitiesW(PrinterName, PortName, + fwCapability_Words, (LPWSTR)Words, dm); + + /* reset any current content in the combobox */ + SendDlgItemMessageW(hDlg, nIDComboBox, CB_RESETCONTENT, 0, 0); + + /* store new content */ + for (i = 0; i < NrOfEntries; i++) { + DWORD pos = SendDlgItemMessageW(hDlg, nIDComboBox, CB_ADDSTRING, 0, + (LPARAM)(&Names[i*NamesSize]) ); + SendDlgItemMessageW(hDlg, nIDComboBox, CB_SETITEMDATA, pos, + Words[i]); + } + + /* Look for old selection - can't do this is previous loop since + item order will change as more items are added */ + Sel = 0; + for (i = 0; i < NrOfEntries; i++) { + if(SendDlgItemMessageW(hDlg, nIDComboBox, CB_GETITEMDATA, i, 0) == + oldWord) { + Sel = i; + break; + } + } + SendDlgItemMessageW(hDlg, nIDComboBox, CB_SETCURSEL, Sel, 0); + + HeapFree(GetProcessHeap(),0,Words); + HeapFree(GetProcessHeap(),0,Names); + return TRUE; +} + + +/*********************************************************************** + * PRINTDLG_UpdatePrinterInfoTexts [internal] + */ +static void PRINTDLG_UpdatePrinterInfoTextsA(HWND hDlg, LPPRINTER_INFO_2A pi) +{ + char StatusMsg[256]; + char ResourceString[256]; + int i; + + /* Status Message */ + StatusMsg[0]='\0'; + + /* add all status messages */ + for (i = 0; i < 25; i++) { + if (pi->Status & (1<pDriverName); + + if (pi->pLocation != NULL && pi->pLocation[0] != '\0') + SetDlgItemTextA(hDlg, stc14, pi->pLocation); + else + SetDlgItemTextA(hDlg, stc14, pi->pPortName); + SetDlgItemTextA(hDlg, stc13, pi->pComment ? pi->pComment : ""); + return; +} + +static void PRINTDLG_UpdatePrinterInfoTextsW(HWND hDlg, LPPRINTER_INFO_2W pi) +{ + WCHAR StatusMsg[256]; + WCHAR ResourceString[256]; + static const WCHAR emptyW[] = {0}; + int i; + + /* Status Message */ + StatusMsg[0]='\0'; + + /* add all status messages */ + for (i = 0; i < 25; i++) { + if (pi->Status & (1<pDriverName); + if (pi->pLocation != NULL && pi->pLocation[0] != '\0') + SetDlgItemTextW(hDlg, stc14, pi->pLocation); + else + SetDlgItemTextW(hDlg, stc14, pi->pPortName); + SetDlgItemTextW(hDlg, stc13, pi->pComment ? pi->pComment : emptyW); +} + + +/******************************************************************* + * + * PRINTDLG_ChangePrinter + * + */ +BOOL PRINTDLG_ChangePrinterA(HWND hDlg, char *name, + PRINT_PTRA *PrintStructures) +{ + LPPRINTDLGA lppd = PrintStructures->lpPrintDlg; + LPDEVMODEA lpdm = NULL; + LONG dmSize; + DWORD needed; + HANDLE hprn; + + HeapFree(GetProcessHeap(),0, PrintStructures->lpPrinterInfo); + HeapFree(GetProcessHeap(),0, PrintStructures->lpDriverInfo); + if(!OpenPrinterA(name, &hprn, NULL)) { + ERR("Can't open printer %s\n", name); + return FALSE; + } + GetPrinterA(hprn, 2, NULL, 0, &needed); + PrintStructures->lpPrinterInfo = HeapAlloc(GetProcessHeap(),0,needed); + GetPrinterA(hprn, 2, (LPBYTE)PrintStructures->lpPrinterInfo, needed, + &needed); + GetPrinterDriverA(hprn, NULL, 3, NULL, 0, &needed); + PrintStructures->lpDriverInfo = HeapAlloc(GetProcessHeap(),0,needed); + if (!GetPrinterDriverA(hprn, NULL, 3, (LPBYTE)PrintStructures->lpDriverInfo, + needed, &needed)) { + ERR("GetPrinterDriverA failed for %s, fix your config!\n",PrintStructures->lpPrinterInfo->pPrinterName); + return FALSE; + } + ClosePrinter(hprn); + + PRINTDLG_UpdatePrinterInfoTextsA(hDlg, PrintStructures->lpPrinterInfo); + + HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode); + PrintStructures->lpDevMode = NULL; + + dmSize = DocumentPropertiesA(0, 0, name, NULL, NULL, 0); + if(dmSize == -1) { + ERR("DocumentProperties fails on %s\n", debugstr_a(name)); + return FALSE; + } + PrintStructures->lpDevMode = HeapAlloc(GetProcessHeap(), 0, dmSize); + dmSize = DocumentPropertiesA(0, 0, name, PrintStructures->lpDevMode, NULL, + DM_OUT_BUFFER); + if(lppd->hDevMode && (lpdm = GlobalLock(lppd->hDevMode)) && + !strcmp(lpdm->dmDeviceName, + PrintStructures->lpDevMode->dmDeviceName)) { + /* Supplied devicemode matches current printer so try to use it */ + DocumentPropertiesA(0, 0, name, PrintStructures->lpDevMode, lpdm, + DM_OUT_BUFFER | DM_IN_BUFFER); + } + if(lpdm) + GlobalUnlock(lppd->hDevMode); + + lpdm = PrintStructures->lpDevMode; /* use this as a shortcut */ + + if(!(lppd->Flags & PD_PRINTSETUP)) { + /* Print range (All/Range/Selection) */ + SetDlgItemInt(hDlg, edt1, lppd->nFromPage, FALSE); + SetDlgItemInt(hDlg, edt2, lppd->nToPage, FALSE); + CheckRadioButton(hDlg, rad1, rad3, rad1); /* default */ + if (lppd->Flags & PD_NOSELECTION) + EnableWindow(GetDlgItem(hDlg, rad2), FALSE); + else + if (lppd->Flags & PD_SELECTION) + CheckRadioButton(hDlg, rad1, rad3, rad2); + if (lppd->Flags & PD_NOPAGENUMS) { + EnableWindow(GetDlgItem(hDlg, rad3), FALSE); + EnableWindow(GetDlgItem(hDlg, stc2),FALSE); + EnableWindow(GetDlgItem(hDlg, edt1), FALSE); + EnableWindow(GetDlgItem(hDlg, stc3),FALSE); + EnableWindow(GetDlgItem(hDlg, edt2), FALSE); + } else { + if (lppd->Flags & PD_PAGENUMS) + CheckRadioButton(hDlg, rad1, rad3, rad3); + } + + /* Collate pages + * + * FIXME: The ico3 is not displayed for some reason. I don't know why. + */ + if (lppd->Flags & PD_COLLATE) { + SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, + (LPARAM)PrintStructures->hCollateIcon); + CheckDlgButton(hDlg, chx2, 1); + } else { + SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, + (LPARAM)PrintStructures->hNoCollateIcon); + CheckDlgButton(hDlg, chx2, 0); + } + + if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { + /* if printer doesn't support it: no Collate */ + if (!(lpdm->dmFields & DM_COLLATE)) { + EnableWindow(GetDlgItem(hDlg, chx2), FALSE); + EnableWindow(GetDlgItem(hDlg, ico3), FALSE); + } + } + + /* nCopies */ + { + INT copies; + if (lppd->hDevMode == 0) + copies = lppd->nCopies; + else + copies = lpdm->u.s.dmCopies; + if(copies == 0) copies = 1; + else if(copies < 0) copies = MAX_COPIES; + SetDlgItemInt(hDlg, edt3, copies, FALSE); + } + + if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { + /* if printer doesn't support it: no nCopies */ + if (!(lpdm->dmFields & DM_COPIES)) { + EnableWindow(GetDlgItem(hDlg, edt3), FALSE); + EnableWindow(GetDlgItem(hDlg, stc5), FALSE); + } + } + + /* print to file */ + CheckDlgButton(hDlg, chx1, (lppd->Flags & PD_PRINTTOFILE) ? 1 : 0); + if (lppd->Flags & PD_DISABLEPRINTTOFILE) + EnableWindow(GetDlgItem(hDlg, chx1), FALSE); + if (lppd->Flags & PD_HIDEPRINTTOFILE) + ShowWindow(GetDlgItem(hDlg, chx1), SW_HIDE); + + } else { /* PD_PRINTSETUP */ + BOOL bPortrait = (lpdm->u.s.dmOrientation == DMORIENT_PORTRAIT); + + PRINTDLG_SetUpPaperComboBoxA(hDlg, cmb2, + PrintStructures->lpPrinterInfo->pPrinterName, + PrintStructures->lpPrinterInfo->pPortName, + lpdm); + PRINTDLG_SetUpPaperComboBoxA(hDlg, cmb3, + PrintStructures->lpPrinterInfo->pPrinterName, + PrintStructures->lpPrinterInfo->pPortName, + lpdm); + CheckRadioButton(hDlg, rad1, rad2, bPortrait ? rad1: rad2); + SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, (WPARAM) IMAGE_ICON, + (LPARAM)(bPortrait ? PrintStructures->hPortraitIcon : + PrintStructures->hLandscapeIcon)); + + } + + /* help button */ + if ((lppd->Flags & PD_SHOWHELP)==0) { + /* hide if PD_SHOWHELP not specified */ + ShowWindow(GetDlgItem(hDlg, pshHelp), SW_HIDE); + } + return TRUE; +} + +static BOOL PRINTDLG_ChangePrinterW(HWND hDlg, WCHAR *name, + PRINT_PTRW *PrintStructures) +{ + LPPRINTDLGW lppd = PrintStructures->lpPrintDlg; + LPDEVMODEW lpdm = NULL; + LONG dmSize; + DWORD needed; + HANDLE hprn; + + HeapFree(GetProcessHeap(),0, PrintStructures->lpPrinterInfo); + HeapFree(GetProcessHeap(),0, PrintStructures->lpDriverInfo); + if(!OpenPrinterW(name, &hprn, NULL)) { + ERR("Can't open printer %s\n", debugstr_w(name)); + return FALSE; + } + GetPrinterW(hprn, 2, NULL, 0, &needed); + PrintStructures->lpPrinterInfo = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*needed); + GetPrinterW(hprn, 2, (LPBYTE)PrintStructures->lpPrinterInfo, needed, + &needed); + GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed); + PrintStructures->lpDriverInfo = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*needed); + if (!GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)PrintStructures->lpDriverInfo, + needed, &needed)) { + ERR("GetPrinterDriverA failed for %s, fix your config!\n",debugstr_w(PrintStructures->lpPrinterInfo->pPrinterName)); + return FALSE; + } + ClosePrinter(hprn); + + PRINTDLG_UpdatePrinterInfoTextsW(hDlg, PrintStructures->lpPrinterInfo); + + HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode); + PrintStructures->lpDevMode = NULL; + + dmSize = DocumentPropertiesW(0, 0, name, NULL, NULL, 0); + if(dmSize == -1) { + ERR("DocumentProperties fails on %s\n", debugstr_w(name)); + return FALSE; + } + PrintStructures->lpDevMode = HeapAlloc(GetProcessHeap(), 0, dmSize); + dmSize = DocumentPropertiesW(0, 0, name, PrintStructures->lpDevMode, NULL, + DM_OUT_BUFFER); + if(lppd->hDevMode && (lpdm = GlobalLock(lppd->hDevMode)) && + !lstrcmpW(lpdm->dmDeviceName, + PrintStructures->lpDevMode->dmDeviceName)) { + /* Supplied devicemode matches current printer so try to use it */ + DocumentPropertiesW(0, 0, name, PrintStructures->lpDevMode, lpdm, + DM_OUT_BUFFER | DM_IN_BUFFER); + } + if(lpdm) + GlobalUnlock(lppd->hDevMode); + + lpdm = PrintStructures->lpDevMode; /* use this as a shortcut */ + + if(!(lppd->Flags & PD_PRINTSETUP)) { + /* Print range (All/Range/Selection) */ + SetDlgItemInt(hDlg, edt1, lppd->nFromPage, FALSE); + SetDlgItemInt(hDlg, edt2, lppd->nToPage, FALSE); + CheckRadioButton(hDlg, rad1, rad3, rad1); /* default */ + if (lppd->Flags & PD_NOSELECTION) + EnableWindow(GetDlgItem(hDlg, rad2), FALSE); + else + if (lppd->Flags & PD_SELECTION) + CheckRadioButton(hDlg, rad1, rad3, rad2); + if (lppd->Flags & PD_NOPAGENUMS) { + EnableWindow(GetDlgItem(hDlg, rad3), FALSE); + EnableWindow(GetDlgItem(hDlg, stc2),FALSE); + EnableWindow(GetDlgItem(hDlg, edt1), FALSE); + EnableWindow(GetDlgItem(hDlg, stc3),FALSE); + EnableWindow(GetDlgItem(hDlg, edt2), FALSE); + } else { + if (lppd->Flags & PD_PAGENUMS) + CheckRadioButton(hDlg, rad1, rad3, rad3); + } + + /* Collate pages + * + * FIXME: The ico3 is not displayed for some reason. I don't know why. + */ + if (lppd->Flags & PD_COLLATE) { + SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, + (LPARAM)PrintStructures->hCollateIcon); + CheckDlgButton(hDlg, chx2, 1); + } else { + SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, + (LPARAM)PrintStructures->hNoCollateIcon); + CheckDlgButton(hDlg, chx2, 0); + } + + if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { + /* if printer doesn't support it: no Collate */ + if (!(lpdm->dmFields & DM_COLLATE)) { + EnableWindow(GetDlgItem(hDlg, chx2), FALSE); + EnableWindow(GetDlgItem(hDlg, ico3), FALSE); + } + } + + /* nCopies */ + { + INT copies; + if (lppd->hDevMode == 0) + copies = lppd->nCopies; + else + copies = lpdm->u.s.dmCopies; + if(copies == 0) copies = 1; + else if(copies < 0) copies = MAX_COPIES; + SetDlgItemInt(hDlg, edt3, copies, FALSE); + } + + if (lppd->Flags & PD_USEDEVMODECOPIESANDCOLLATE) { + /* if printer doesn't support it: no nCopies */ + if (!(lpdm->dmFields & DM_COPIES)) { + EnableWindow(GetDlgItem(hDlg, edt3), FALSE); + EnableWindow(GetDlgItem(hDlg, stc5), FALSE); + } + } + + /* print to file */ + CheckDlgButton(hDlg, chx1, (lppd->Flags & PD_PRINTTOFILE) ? 1 : 0); + if (lppd->Flags & PD_DISABLEPRINTTOFILE) + EnableWindow(GetDlgItem(hDlg, chx1), FALSE); + if (lppd->Flags & PD_HIDEPRINTTOFILE) + ShowWindow(GetDlgItem(hDlg, chx1), SW_HIDE); + + } else { /* PD_PRINTSETUP */ + BOOL bPortrait = (lpdm->u.s.dmOrientation == DMORIENT_PORTRAIT); + + PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb2, + PrintStructures->lpPrinterInfo->pPrinterName, + PrintStructures->lpPrinterInfo->pPortName, + lpdm); + PRINTDLG_SetUpPaperComboBoxW(hDlg, cmb3, + PrintStructures->lpPrinterInfo->pPrinterName, + PrintStructures->lpPrinterInfo->pPortName, + lpdm); + CheckRadioButton(hDlg, rad1, rad2, bPortrait ? rad1: rad2); + SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, (WPARAM) IMAGE_ICON, + (LPARAM)(bPortrait ? PrintStructures->hPortraitIcon : + PrintStructures->hLandscapeIcon)); + + } + + /* help button */ + if ((lppd->Flags & PD_SHOWHELP)==0) { + /* hide if PD_SHOWHELP not specified */ + ShowWindow(GetDlgItem(hDlg, pshHelp), SW_HIDE); + } + return TRUE; +} + +/*********************************************************************** + * PRINTDLG_WMInitDialog [internal] + */ +static LRESULT PRINTDLG_WMInitDialog(HWND hDlg, WPARAM wParam, + PRINT_PTRA* PrintStructures) +{ + LPPRINTDLGA lppd = PrintStructures->lpPrintDlg; + DEVNAMES *pdn; + DEVMODEA *pdm; + char *name = NULL; + UINT comboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4; + + /* load Collate ICONs */ + /* We load these with LoadImage because they are not a standard + size and we don't want them rescaled */ + PrintStructures->hCollateIcon = + LoadImageA(COMDLG32_hInstance, "PD32_COLLATE", IMAGE_ICON, 0, 0, 0); + PrintStructures->hNoCollateIcon = + LoadImageA(COMDLG32_hInstance, "PD32_NOCOLLATE", IMAGE_ICON, 0, 0, 0); + + /* These can be done with LoadIcon */ + PrintStructures->hPortraitIcon = + LoadIconA(COMDLG32_hInstance, "PD32_PORTRAIT"); + PrintStructures->hLandscapeIcon = + LoadIconA(COMDLG32_hInstance, "PD32_LANDSCAPE"); + + /* display the collate/no_collate icon */ + SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, + (LPARAM)PrintStructures->hNoCollateIcon); + + if(PrintStructures->hCollateIcon == 0 || + PrintStructures->hNoCollateIcon == 0 || + PrintStructures->hPortraitIcon == 0 || + PrintStructures->hLandscapeIcon == 0) { + ERR("no icon in resourcefile\n"); + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + EndDialog(hDlg, FALSE); + } + + /* + * if lppd->Flags PD_SHOWHELP is specified, a HELPMESGSTRING message + * must be registered and the Help button must be shown. + */ + if (lppd->Flags & PD_SHOWHELP) { + if((PrintStructures->HelpMessageID = + RegisterWindowMessageA(HELPMSGSTRINGA)) == 0) { + COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL); + return FALSE; + } + } else + PrintStructures->HelpMessageID = 0; + + if(!(lppd->Flags &PD_PRINTSETUP)) { + PrintStructures->hwndUpDown = + CreateUpDownControl(WS_CHILD | WS_VISIBLE | WS_BORDER | + UDS_NOTHOUSANDS | UDS_ARROWKEYS | + UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 0, 0, 0, 0, + hDlg, UPDOWN_ID, COMDLG32_hInstance, + GetDlgItem(hDlg, edt3), MAX_COPIES, 1, 1); + } + + /* FIXME: I allow more freedom than either Win95 or WinNT, + * which do not agree to what errors should be thrown or not + * in case nToPage or nFromPage is out-of-range. + */ + if (lppd->nMaxPage < lppd->nMinPage) + lppd->nMaxPage = lppd->nMinPage; + if (lppd->nMinPage == lppd->nMaxPage) + lppd->Flags |= PD_NOPAGENUMS; + if (lppd->nToPage < lppd->nMinPage) + lppd->nToPage = lppd->nMinPage; + if (lppd->nToPage > lppd->nMaxPage) + lppd->nToPage = lppd->nMaxPage; + if (lppd->nFromPage < lppd->nMinPage) + lppd->nFromPage = lppd->nMinPage; + if (lppd->nFromPage > lppd->nMaxPage) + lppd->nFromPage = lppd->nMaxPage; + + /* if we have the combo box, fill it */ + if (GetDlgItem(hDlg,comboID)) { + /* Fill Combobox + */ + pdn = GlobalLock(lppd->hDevNames); + pdm = GlobalLock(lppd->hDevMode); + if(pdn) + name = (char*)pdn + pdn->wDeviceOffset; + else if(pdm) + name = pdm->dmDeviceName; + PRINTDLG_SetUpPrinterListComboA(hDlg, comboID, name); + if(pdm) GlobalUnlock(lppd->hDevMode); + if(pdn) GlobalUnlock(lppd->hDevNames); + + /* Now find selected printer and update rest of dlg */ + name = HeapAlloc(GetProcessHeap(),0,256); + if (GetDlgItemTextA(hDlg, comboID, name, 255)) + PRINTDLG_ChangePrinterA(hDlg, name, PrintStructures); + HeapFree(GetProcessHeap(),0,name); + } else { + /* else use default printer */ + char name[200]; + DWORD dwBufLen = sizeof(name); + BOOL ret = GetDefaultPrinterA(name, &dwBufLen); + + if (ret) + PRINTDLG_ChangePrinterA(hDlg, name, PrintStructures); + else + FIXME("No default printer found, expect problems!\n"); + } + return TRUE; +} + +static LRESULT PRINTDLG_WMInitDialogW(HWND hDlg, WPARAM wParam, + PRINT_PTRW* PrintStructures) +{ + const static WCHAR PD32_COLLATE[] = { 'P', 'D', '3', '2', '_', 'C', 'O', 'L', 'L', 'A', 'T', 'E', 0 }; + const static WCHAR PD32_NOCOLLATE[] = { 'P', 'D', '3', '2', '_', 'N', 'O', 'C', 'O', 'L', 'L', 'A', 'T', 'E', 0 }; + const static WCHAR PD32_PORTRAIT[] = { 'P', 'D', '3', '2', '_', 'P', 'O', 'R', 'T', 'R', 'A', 'I', 'T', 0 }; + const static WCHAR PD32_LANDSCAPE[] = { 'P', 'D', '3', '2', '_', 'L', 'A', 'N', 'D', 'S', 'C', 'A', 'P', 'E', 0 }; + LPPRINTDLGW lppd = PrintStructures->lpPrintDlg; + DEVNAMES *pdn; + DEVMODEW *pdm; + WCHAR *name = NULL; + UINT comboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4; + + /* load Collate ICONs */ + /* We load these with LoadImage because they are not a standard + size and we don't want them rescaled */ + PrintStructures->hCollateIcon = + LoadImageW(COMDLG32_hInstance, PD32_COLLATE, IMAGE_ICON, 0, 0, 0); + PrintStructures->hNoCollateIcon = + LoadImageW(COMDLG32_hInstance, PD32_NOCOLLATE, IMAGE_ICON, 0, 0, 0); + + /* These can be done with LoadIcon */ + PrintStructures->hPortraitIcon = + LoadIconW(COMDLG32_hInstance, PD32_PORTRAIT); + PrintStructures->hLandscapeIcon = + LoadIconW(COMDLG32_hInstance, PD32_LANDSCAPE); + + /* display the collate/no_collate icon */ + SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, + (LPARAM)PrintStructures->hNoCollateIcon); + + if(PrintStructures->hCollateIcon == 0 || + PrintStructures->hNoCollateIcon == 0 || + PrintStructures->hPortraitIcon == 0 || + PrintStructures->hLandscapeIcon == 0) { + ERR("no icon in resourcefile\n"); + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + EndDialog(hDlg, FALSE); + } + + /* + * if lppd->Flags PD_SHOWHELP is specified, a HELPMESGSTRING message + * must be registered and the Help button must be shown. + */ + if (lppd->Flags & PD_SHOWHELP) { + if((PrintStructures->HelpMessageID = + RegisterWindowMessageW(HELPMSGSTRINGW)) == 0) { + COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL); + return FALSE; + } + } else + PrintStructures->HelpMessageID = 0; + + if(!(lppd->Flags &PD_PRINTSETUP)) { + PrintStructures->hwndUpDown = + CreateUpDownControl(WS_CHILD | WS_VISIBLE | WS_BORDER | + UDS_NOTHOUSANDS | UDS_ARROWKEYS | + UDS_ALIGNRIGHT | UDS_SETBUDDYINT, 0, 0, 0, 0, + hDlg, UPDOWN_ID, COMDLG32_hInstance, + GetDlgItem(hDlg, edt3), MAX_COPIES, 1, 1); + } + + /* FIXME: I allow more freedom than either Win95 or WinNT, + * which do not agree to what errors should be thrown or not + * in case nToPage or nFromPage is out-of-range. + */ + if (lppd->nMaxPage < lppd->nMinPage) + lppd->nMaxPage = lppd->nMinPage; + if (lppd->nMinPage == lppd->nMaxPage) + lppd->Flags |= PD_NOPAGENUMS; + if (lppd->nToPage < lppd->nMinPage) + lppd->nToPage = lppd->nMinPage; + if (lppd->nToPage > lppd->nMaxPage) + lppd->nToPage = lppd->nMaxPage; + if (lppd->nFromPage < lppd->nMinPage) + lppd->nFromPage = lppd->nMinPage; + if (lppd->nFromPage > lppd->nMaxPage) + lppd->nFromPage = lppd->nMaxPage; + + /* if we have the combo box, fill it */ + if (GetDlgItem(hDlg,comboID)) { + /* Fill Combobox + */ + pdn = GlobalLock(lppd->hDevNames); + pdm = GlobalLock(lppd->hDevMode); + if(pdn) + name = (WCHAR*)pdn + pdn->wDeviceOffset; + else if(pdm) + name = pdm->dmDeviceName; + PRINTDLG_SetUpPrinterListComboW(hDlg, comboID, name); + if(pdm) GlobalUnlock(lppd->hDevMode); + if(pdn) GlobalUnlock(lppd->hDevNames); + + /* Now find selected printer and update rest of dlg */ + /* ansi is ok here */ + name = HeapAlloc(GetProcessHeap(),0,256*sizeof(WCHAR)); + if (GetDlgItemTextW(hDlg, comboID, name, 255)) + PRINTDLG_ChangePrinterW(hDlg, name, PrintStructures); + HeapFree(GetProcessHeap(),0,name); + } else { + /* else use default printer */ + WCHAR name[200]; + DWORD dwBufLen = sizeof(name) / sizeof(WCHAR); + BOOL ret = GetDefaultPrinterW(name, &dwBufLen); + + if (ret) + PRINTDLG_ChangePrinterW(hDlg, name, PrintStructures); + else + FIXME("No default printer found, expect problems!\n"); + } + return TRUE; +} + +/*********************************************************************** + * PRINTDLG_WMCommand [internal] + */ +LRESULT PRINTDLG_WMCommandA(HWND hDlg, WPARAM wParam, + LPARAM lParam, PRINT_PTRA* PrintStructures) +{ + LPPRINTDLGA lppd = PrintStructures->lpPrintDlg; + UINT PrinterComboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4; + LPDEVMODEA lpdm = PrintStructures->lpDevMode; + + switch (LOWORD(wParam)) { + case IDOK: + TRACE(" OK button was hit\n"); + if (!PRINTDLG_UpdatePrintDlgA(hDlg, PrintStructures)) { + FIXME("Update printdlg was not successful!\n"); + return(FALSE); + } + EndDialog(hDlg, TRUE); + return(TRUE); + + case IDCANCEL: + TRACE(" CANCEL button was hit\n"); + EndDialog(hDlg, FALSE); + return(FALSE); + + case pshHelp: + TRACE(" HELP button was hit\n"); + SendMessageA(lppd->hwndOwner, PrintStructures->HelpMessageID, + (WPARAM) hDlg, (LPARAM) lppd); + break; + + case chx2: /* collate pages checkbox */ + if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) + SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, + (LPARAM)PrintStructures->hCollateIcon); + else + SendDlgItemMessageA(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, + (LPARAM)PrintStructures->hNoCollateIcon); + break; + case edt1: /* from page nr editbox */ + case edt2: /* to page nr editbox */ + if (HIWORD(wParam)==EN_CHANGE) { + WORD nToPage; + WORD nFromPage; + nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE); + nToPage = GetDlgItemInt(hDlg, edt2, NULL, FALSE); + if (nFromPage != lppd->nFromPage || nToPage != lppd->nToPage) + CheckRadioButton(hDlg, rad1, rad3, rad3); + } + break; + + case edt3: + if(HIWORD(wParam) == EN_CHANGE) { + INT copies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); + if(copies <= 1) + EnableWindow(GetDlgItem(hDlg, chx2), FALSE); + else + EnableWindow(GetDlgItem(hDlg, chx2), TRUE); + } + break; + +#if 0 + case psh1: /* Print Setup */ + { + PRINTDLG16 pdlg; + + if (!PrintStructures->dlg.lpPrintDlg16) { + FIXME("The 32bit print dialog does not have this button!?\n"); + break; + } + + memcpy(&pdlg,PrintStructures->dlg.lpPrintDlg16,sizeof(pdlg)); + pdlg.Flags |= PD_PRINTSETUP; + pdlg.hwndOwner = HWND_16(hDlg); + if (!PrintDlg16(&pdlg)) + break; + } + break; +#endif + case psh2: /* Properties button */ + { + HANDLE hPrinter; + char PrinterName[256]; + + GetDlgItemTextA(hDlg, PrinterComboID, PrinterName, 255); + if (!OpenPrinterA(PrinterName, &hPrinter, NULL)) { + FIXME(" Call to OpenPrinter did not succeed!\n"); + break; + } + DocumentPropertiesA(hDlg, hPrinter, PrinterName, + PrintStructures->lpDevMode, + PrintStructures->lpDevMode, + DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT); + ClosePrinter(hPrinter); + break; + } + + case rad1: /* Paperorientation */ + if (lppd->Flags & PD_PRINTSETUP) + { + lpdm->u.s.dmOrientation = DMORIENT_PORTRAIT; + SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, (WPARAM) IMAGE_ICON, + (LPARAM)(PrintStructures->hPortraitIcon)); + } + break; + + case rad2: /* Paperorientation */ + if (lppd->Flags & PD_PRINTSETUP) + { + lpdm->u.s.dmOrientation = DMORIENT_LANDSCAPE; + SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, (WPARAM) IMAGE_ICON, + (LPARAM)(PrintStructures->hLandscapeIcon)); + } + break; + + case cmb1: /* Printer Combobox in PRINT SETUP, quality combobox in PRINT */ + if (PrinterComboID != LOWORD(wParam)) { + FIXME("No handling for print quality combo box yet.\n"); + break; + } + /* FALLTHROUGH */ + case cmb4: /* Printer combobox */ + if (HIWORD(wParam)==CBN_SELCHANGE) { + char PrinterName[256]; + GetDlgItemTextA(hDlg, LOWORD(wParam), PrinterName, 255); + PRINTDLG_ChangePrinterA(hDlg, PrinterName, PrintStructures); + } + break; + + case cmb2: /* Papersize */ + { + DWORD Sel = SendDlgItemMessageA(hDlg, cmb2, CB_GETCURSEL, 0, 0); + if(Sel != CB_ERR) + lpdm->u.s.dmPaperSize = SendDlgItemMessageA(hDlg, cmb2, + CB_GETITEMDATA, + Sel, 0); + } + break; + + case cmb3: /* Bin */ + { + DWORD Sel = SendDlgItemMessageA(hDlg, cmb3, CB_GETCURSEL, 0, 0); + if(Sel != CB_ERR) + lpdm->u.s.dmDefaultSource = SendDlgItemMessageA(hDlg, cmb3, + CB_GETITEMDATA, Sel, + 0); + } + break; + } + if(lppd->Flags & PD_PRINTSETUP) { + switch (LOWORD(wParam)) { + case rad1: /* orientation */ + case rad2: + if (IsDlgButtonChecked(hDlg, rad1) == BST_CHECKED) { + if(lpdm->u.s.dmOrientation != DMORIENT_PORTRAIT) { + lpdm->u.s.dmOrientation = DMORIENT_PORTRAIT; + SendDlgItemMessageA(hDlg, stc10, STM_SETIMAGE, + (WPARAM)IMAGE_ICON, + (LPARAM)PrintStructures->hPortraitIcon); + SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, + (WPARAM)IMAGE_ICON, + (LPARAM)PrintStructures->hPortraitIcon); + } + } else { + if(lpdm->u.s.dmOrientation != DMORIENT_LANDSCAPE) { + lpdm->u.s.dmOrientation = DMORIENT_LANDSCAPE; + SendDlgItemMessageA(hDlg, stc10, STM_SETIMAGE, + (WPARAM)IMAGE_ICON, + (LPARAM)PrintStructures->hLandscapeIcon); + SendDlgItemMessageA(hDlg, ico1, STM_SETIMAGE, + (WPARAM)IMAGE_ICON, + (LPARAM)PrintStructures->hLandscapeIcon); + } + } + break; + } + } + return FALSE; +} + +static LRESULT PRINTDLG_WMCommandW(HWND hDlg, WPARAM wParam, + LPARAM lParam, PRINT_PTRW* PrintStructures) +{ + LPPRINTDLGW lppd = PrintStructures->lpPrintDlg; + UINT PrinterComboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4; + LPDEVMODEW lpdm = PrintStructures->lpDevMode; + + switch (LOWORD(wParam)) { + case IDOK: + TRACE(" OK button was hit\n"); + if (!PRINTDLG_UpdatePrintDlgW(hDlg, PrintStructures)) { + FIXME("Update printdlg was not successful!\n"); + return(FALSE); + } + EndDialog(hDlg, TRUE); + return(TRUE); + + case IDCANCEL: + TRACE(" CANCEL button was hit\n"); + EndDialog(hDlg, FALSE); + return(FALSE); + + case pshHelp: + TRACE(" HELP button was hit\n"); + SendMessageW(lppd->hwndOwner, PrintStructures->HelpMessageID, + (WPARAM) hDlg, (LPARAM) lppd); + break; + + case chx2: /* collate pages checkbox */ + if (IsDlgButtonChecked(hDlg, chx2) == BST_CHECKED) + SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, + (LPARAM)PrintStructures->hCollateIcon); + else + SendDlgItemMessageW(hDlg, ico3, STM_SETIMAGE, (WPARAM) IMAGE_ICON, + (LPARAM)PrintStructures->hNoCollateIcon); + break; + case edt1: /* from page nr editbox */ + case edt2: /* to page nr editbox */ + if (HIWORD(wParam)==EN_CHANGE) { + WORD nToPage; + WORD nFromPage; + nFromPage = GetDlgItemInt(hDlg, edt1, NULL, FALSE); + nToPage = GetDlgItemInt(hDlg, edt2, NULL, FALSE); + if (nFromPage != lppd->nFromPage || nToPage != lppd->nToPage) + CheckRadioButton(hDlg, rad1, rad3, rad3); + } + break; + + case edt3: + if(HIWORD(wParam) == EN_CHANGE) { + INT copies = GetDlgItemInt(hDlg, edt3, NULL, FALSE); + if(copies <= 1) + EnableWindow(GetDlgItem(hDlg, chx2), FALSE); + else + EnableWindow(GetDlgItem(hDlg, chx2), TRUE); + } + break; + + case psh1: /* Print Setup */ + { + ERR("psh1 is called from 16bit code only, we should not get here.\n"); + } + break; + case psh2: /* Properties button */ + { + HANDLE hPrinter; + WCHAR PrinterName[256]; + + if (!GetDlgItemTextW(hDlg, PrinterComboID, PrinterName, 255)) break; + if (!OpenPrinterW(PrinterName, &hPrinter, NULL)) { + FIXME(" Call to OpenPrinter did not succeed!\n"); + break; + } + DocumentPropertiesW(hDlg, hPrinter, PrinterName, + PrintStructures->lpDevMode, + PrintStructures->lpDevMode, + DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT); + ClosePrinter(hPrinter); + break; + } + + case rad1: /* Paperorientation */ + if (lppd->Flags & PD_PRINTSETUP) + { + lpdm->u.s.dmOrientation = DMORIENT_PORTRAIT; + SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, (WPARAM) IMAGE_ICON, + (LPARAM)(PrintStructures->hPortraitIcon)); + } + break; + + case rad2: /* Paperorientation */ + if (lppd->Flags & PD_PRINTSETUP) + { + lpdm->u.s.dmOrientation = DMORIENT_LANDSCAPE; + SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, (WPARAM) IMAGE_ICON, + (LPARAM)(PrintStructures->hLandscapeIcon)); + } + break; + + case cmb1: /* Printer Combobox in PRINT SETUP, quality combobox in PRINT */ + if (PrinterComboID != LOWORD(wParam)) { + FIXME("No handling for print quality combo box yet.\n"); + break; + } + /* FALLTHROUGH */ + case cmb4: /* Printer combobox */ + if (HIWORD(wParam)==CBN_SELCHANGE) { + WCHAR PrinterName[256]; + GetDlgItemTextW(hDlg, LOWORD(wParam), PrinterName, 255); + PRINTDLG_ChangePrinterW(hDlg, PrinterName, PrintStructures); + } + break; + + case cmb2: /* Papersize */ + { + DWORD Sel = SendDlgItemMessageW(hDlg, cmb2, CB_GETCURSEL, 0, 0); + if(Sel != CB_ERR) + lpdm->u.s.dmPaperSize = SendDlgItemMessageW(hDlg, cmb2, + CB_GETITEMDATA, + Sel, 0); + } + break; + + case cmb3: /* Bin */ + { + DWORD Sel = SendDlgItemMessageW(hDlg, cmb3, CB_GETCURSEL, 0, 0); + if(Sel != CB_ERR) + lpdm->u.s.dmDefaultSource = SendDlgItemMessageW(hDlg, cmb3, + CB_GETITEMDATA, Sel, + 0); + } + break; + } + if(lppd->Flags & PD_PRINTSETUP) { + switch (LOWORD(wParam)) { + case rad1: /* orientation */ + case rad2: + if (IsDlgButtonChecked(hDlg, rad1) == BST_CHECKED) { + if(lpdm->u.s.dmOrientation != DMORIENT_PORTRAIT) { + lpdm->u.s.dmOrientation = DMORIENT_PORTRAIT; + SendDlgItemMessageW(hDlg, stc10, STM_SETIMAGE, + (WPARAM)IMAGE_ICON, + (LPARAM)PrintStructures->hPortraitIcon); + SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, + (WPARAM)IMAGE_ICON, + (LPARAM)PrintStructures->hPortraitIcon); + } + } else { + if(lpdm->u.s.dmOrientation != DMORIENT_LANDSCAPE) { + lpdm->u.s.dmOrientation = DMORIENT_LANDSCAPE; + SendDlgItemMessageW(hDlg, stc10, STM_SETIMAGE, + (WPARAM)IMAGE_ICON, + (LPARAM)PrintStructures->hLandscapeIcon); + SendDlgItemMessageW(hDlg, ico1, STM_SETIMAGE, + (WPARAM)IMAGE_ICON, + (LPARAM)PrintStructures->hLandscapeIcon); + } + } + break; + } + } + return FALSE; +} + +/*********************************************************************** + * PrintDlgProcA [internal] + */ +static INT_PTR CALLBACK PrintDlgProcA(HWND hDlg, UINT uMsg, WPARAM wParam, + LPARAM lParam) +{ + PRINT_PTRA* PrintStructures; + INT_PTR res = FALSE; + + if (uMsg!=WM_INITDIALOG) { + PrintStructures = (PRINT_PTRA*)GetPropA(hDlg,"__WINE_PRINTDLGDATA"); + if (!PrintStructures) + return FALSE; + } else { + PrintStructures = (PRINT_PTRA*) lParam; + SetPropA(hDlg,"__WINE_PRINTDLGDATA",PrintStructures); + res = PRINTDLG_WMInitDialog(hDlg, wParam, PrintStructures); + + if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) + res = PrintStructures->lpPrintDlg->lpfnPrintHook( + hDlg, uMsg, wParam, (LPARAM)PrintStructures->lpPrintDlg + ); + return res; + } + + if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) { + res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg,uMsg,wParam, + lParam); + if(res) return res; + } + + switch (uMsg) { + case WM_COMMAND: + return PRINTDLG_WMCommandA(hDlg, wParam, lParam, PrintStructures); + + case WM_DESTROY: + DestroyIcon(PrintStructures->hCollateIcon); + DestroyIcon(PrintStructures->hNoCollateIcon); + DestroyIcon(PrintStructures->hPortraitIcon); + DestroyIcon(PrintStructures->hLandscapeIcon); + if(PrintStructures->hwndUpDown) + DestroyWindow(PrintStructures->hwndUpDown); + return FALSE; + } + return res; +} + +static INT_PTR CALLBACK PrintDlgProcW(HWND hDlg, UINT uMsg, WPARAM wParam, + LPARAM lParam) +{ + static const WCHAR propW[] = {'_','_','W','I','N','E','_','P','R','I','N','T','D','L','G','D','A','T','A',0}; + PRINT_PTRW* PrintStructures; + INT_PTR res = FALSE; + + if (uMsg!=WM_INITDIALOG) { + PrintStructures = (PRINT_PTRW*) GetPropW(hDlg, propW); + if (!PrintStructures) + return FALSE; + } else { + PrintStructures = (PRINT_PTRW*) lParam; + SetPropW(hDlg, propW, PrintStructures); + res = PRINTDLG_WMInitDialogW(hDlg, wParam, PrintStructures); + + if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) + res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg, uMsg, wParam, (LPARAM)PrintStructures->lpPrintDlg); + return res; + } + + if(PrintStructures->lpPrintDlg->Flags & PD_ENABLEPRINTHOOK) { + res = PrintStructures->lpPrintDlg->lpfnPrintHook(hDlg,uMsg,wParam, lParam); + if(res) return res; + } + + switch (uMsg) { + case WM_COMMAND: + return PRINTDLG_WMCommandW(hDlg, wParam, lParam, PrintStructures); + + case WM_DESTROY: + DestroyIcon(PrintStructures->hCollateIcon); + DestroyIcon(PrintStructures->hNoCollateIcon); + DestroyIcon(PrintStructures->hPortraitIcon); + DestroyIcon(PrintStructures->hLandscapeIcon); + if(PrintStructures->hwndUpDown) + DestroyWindow(PrintStructures->hwndUpDown); + return FALSE; + } + return res; +} + +/************************************************************ + * + * PRINTDLG_GetDlgTemplate + * + */ +static HGLOBAL PRINTDLG_GetDlgTemplateA(PRINTDLGA *lppd) +{ + HRSRC hResInfo; + HGLOBAL hDlgTmpl; + + if (lppd->Flags & PD_PRINTSETUP) { + if(lppd->Flags & PD_ENABLESETUPTEMPLATEHANDLE) { + hDlgTmpl = lppd->hSetupTemplate; + } else if(lppd->Flags & PD_ENABLESETUPTEMPLATE) { + hResInfo = FindResourceA(lppd->hInstance, + lppd->lpSetupTemplateName, (LPSTR)RT_DIALOG); + hDlgTmpl = LoadResource(lppd->hInstance, hResInfo); + } else { + hResInfo = FindResourceA(COMDLG32_hInstance, "PRINT32_SETUP", + (LPSTR)RT_DIALOG); + hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo); + } + } else { + if(lppd->Flags & PD_ENABLEPRINTTEMPLATEHANDLE) { + hDlgTmpl = lppd->hPrintTemplate; + } else if(lppd->Flags & PD_ENABLEPRINTTEMPLATE) { + hResInfo = FindResourceA(lppd->hInstance, + lppd->lpPrintTemplateName, + (LPSTR)RT_DIALOG); + hDlgTmpl = LoadResource(lppd->hInstance, hResInfo); + } else { + hResInfo = FindResourceA(COMDLG32_hInstance, "PRINT32", + (LPSTR)RT_DIALOG); + hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo); + } + } + return hDlgTmpl; +} + +static HGLOBAL PRINTDLG_GetDlgTemplateW(PRINTDLGW *lppd) +{ + HRSRC hResInfo; + HGLOBAL hDlgTmpl; + static const WCHAR xpsetup[] = { 'P','R','I','N','T','3','2','_','S','E','T','U','P',0}; + static const WCHAR xprint[] = { 'P','R','I','N','T','3','2',0}; + + if (lppd->Flags & PD_PRINTSETUP) { + if(lppd->Flags & PD_ENABLESETUPTEMPLATEHANDLE) { + hDlgTmpl = lppd->hSetupTemplate; + } else if(lppd->Flags & PD_ENABLESETUPTEMPLATE) { + hResInfo = FindResourceW(lppd->hInstance, + lppd->lpSetupTemplateName, (LPWSTR)RT_DIALOG); + hDlgTmpl = LoadResource(lppd->hInstance, hResInfo); + } else { + hResInfo = FindResourceW(COMDLG32_hInstance, xpsetup, (LPWSTR)RT_DIALOG); + hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo); + } + } else { + if(lppd->Flags & PD_ENABLEPRINTTEMPLATEHANDLE) { + hDlgTmpl = lppd->hPrintTemplate; + } else if(lppd->Flags & PD_ENABLEPRINTTEMPLATE) { + hResInfo = FindResourceW(lppd->hInstance, + lppd->lpPrintTemplateName, + (LPWSTR)RT_DIALOG); + hDlgTmpl = LoadResource(lppd->hInstance, hResInfo); + } else { + hResInfo = FindResourceW(COMDLG32_hInstance, xprint, (LPWSTR)RT_DIALOG); + hDlgTmpl = LoadResource(COMDLG32_hInstance, hResInfo); + } + } + return hDlgTmpl; +} + +/*********************************************************************** + * + * PRINTDLG_CreateDC + * + */ +static BOOL PRINTDLG_CreateDCA(LPPRINTDLGA lppd) +{ + DEVNAMES *pdn = GlobalLock(lppd->hDevNames); + DEVMODEA *pdm = GlobalLock(lppd->hDevMode); + + if(lppd->Flags & PD_RETURNDC) { + lppd->hDC = CreateDCA((char*)pdn + pdn->wDriverOffset, + (char*)pdn + pdn->wDeviceOffset, + (char*)pdn + pdn->wOutputOffset, + pdm ); + } else if(lppd->Flags & PD_RETURNIC) { + lppd->hDC = CreateICA((char*)pdn + pdn->wDriverOffset, + (char*)pdn + pdn->wDeviceOffset, + (char*)pdn + pdn->wOutputOffset, + pdm ); + } + GlobalUnlock(lppd->hDevNames); + GlobalUnlock(lppd->hDevMode); + return lppd->hDC ? TRUE : FALSE; +} + +static BOOL PRINTDLG_CreateDCW(LPPRINTDLGW lppd) +{ + DEVNAMES *pdn = GlobalLock(lppd->hDevNames); + DEVMODEW *pdm = GlobalLock(lppd->hDevMode); + + if(lppd->Flags & PD_RETURNDC) { + lppd->hDC = CreateDCW((WCHAR*)pdn + pdn->wDriverOffset, + (WCHAR*)pdn + pdn->wDeviceOffset, + (WCHAR*)pdn + pdn->wOutputOffset, + pdm ); + } else if(lppd->Flags & PD_RETURNIC) { + lppd->hDC = CreateICW((WCHAR*)pdn + pdn->wDriverOffset, + (WCHAR*)pdn + pdn->wDeviceOffset, + (WCHAR*)pdn + pdn->wOutputOffset, + pdm ); + } + GlobalUnlock(lppd->hDevNames); + GlobalUnlock(lppd->hDevMode); + return lppd->hDC ? TRUE : FALSE; +} + +/*********************************************************************** + * PrintDlgA (COMDLG32.@) + * + * Displays the 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 + * PrintDlg: + * * The Collate Icons do not display, even though they are in the code. + * * The Properties Button(s) should call DocumentPropertiesA(). + */ + +BOOL WINAPI PrintDlgA( + LPPRINTDLGA lppd /* [in/out] ptr to PRINTDLG32 struct */ + ) +{ + BOOL bRet = FALSE; + LPVOID ptr; + HINSTANCE hInst = (HINSTANCE)GetWindowLongPtrA( lppd->hwndOwner, GWLP_HINSTANCE ); + + if(TRACE_ON(commdlg)) { + char flagstr[1000] = ""; + struct pd_flags *pflag = pd_flags; + for( ; pflag->name; pflag++) { + if(lppd->Flags & pflag->flag) + strcat(flagstr, pflag->name); + } + TRACE("(%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n" + "pp. %d-%d, min p %d, max p %d, copies %d, hinst %p\n" + "flags %08lx (%s)\n", + lppd, lppd->hwndOwner, lppd->hDevMode, lppd->hDevNames, + lppd->nFromPage, lppd->nToPage, lppd->nMinPage, lppd->nMaxPage, + lppd->nCopies, lppd->hInstance, lppd->Flags, flagstr); + } + + if(lppd->lStructSize != sizeof(PRINTDLGA)) { + WARN("structure size failure !!!\n"); + COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE); + return FALSE; + } + + if(lppd->Flags & PD_RETURNDEFAULT) { + PRINTER_INFO_2A *pbuf; + DRIVER_INFO_3A *dbuf; + HANDLE hprn; + DWORD needed; + + if(lppd->hDevMode || lppd->hDevNames) { + WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n"); + COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); + return FALSE; + } + if(!PRINTDLG_OpenDefaultPrinter(&hprn)) { + WARN("Can't find default printer\n"); + COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN); + return FALSE; + } + + GetPrinterA(hprn, 2, NULL, 0, &needed); + pbuf = HeapAlloc(GetProcessHeap(), 0, needed); + GetPrinterA(hprn, 2, (LPBYTE)pbuf, needed, &needed); + + GetPrinterDriverA(hprn, NULL, 3, NULL, 0, &needed); + dbuf = HeapAlloc(GetProcessHeap(),0,needed); + if (!GetPrinterDriverA(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed)) { + ERR("GetPrinterDriverA failed, le %ld, fix your config for printer %s!\n",GetLastError(),pbuf->pPrinterName); + COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); + return FALSE; + } + ClosePrinter(hprn); + + PRINTDLG_CreateDevNames(&(lppd->hDevNames), + dbuf->pDriverPath, + pbuf->pPrinterName, + pbuf->pPortName); + lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, pbuf->pDevMode->dmSize + + pbuf->pDevMode->dmDriverExtra); + ptr = GlobalLock(lppd->hDevMode); + memcpy(ptr, pbuf->pDevMode, pbuf->pDevMode->dmSize + + pbuf->pDevMode->dmDriverExtra); + GlobalUnlock(lppd->hDevMode); + HeapFree(GetProcessHeap(), 0, pbuf); + HeapFree(GetProcessHeap(), 0, dbuf); + bRet = TRUE; + } else { + HGLOBAL hDlgTmpl; + PRINT_PTRA *PrintStructures; + + /* load Dialog resources, + * depending on Flags indicates Print32 or Print32_setup dialog + */ + hDlgTmpl = PRINTDLG_GetDlgTemplateA(lppd); + if (!hDlgTmpl) { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + ptr = LockResource( hDlgTmpl ); + if (!ptr) { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + + PrintStructures = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(PRINT_PTRA)); + PrintStructures->lpPrintDlg = lppd; + + /* and create & process the dialog . + * -1 is failure, 0 is broken hwnd, everything else is ok. + */ + bRet = (0hwndOwner, + PrintDlgProcA, + (LPARAM)PrintStructures)); + + if(bRet) { + DEVMODEA *lpdm = PrintStructures->lpDevMode, *lpdmReturn; + PRINTER_INFO_2A *pi = PrintStructures->lpPrinterInfo; + DRIVER_INFO_3A *di = PrintStructures->lpDriverInfo; + + if (lppd->hDevMode == 0) { + TRACE(" No hDevMode yet... Need to create my own\n"); + lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, + lpdm->dmSize + lpdm->dmDriverExtra); + } else { + WORD locks; + if((locks = (GlobalFlags(lppd->hDevMode) & GMEM_LOCKCOUNT))) { + WARN("hDevMode has %d locks on it. Unlocking it now\n", locks); + while(locks--) { + GlobalUnlock(lppd->hDevMode); + TRACE("Now got %d locks\n", locks); + } + } + lppd->hDevMode = GlobalReAlloc(lppd->hDevMode, + lpdm->dmSize + lpdm->dmDriverExtra, + GMEM_MOVEABLE); + } + lpdmReturn = GlobalLock(lppd->hDevMode); + memcpy(lpdmReturn, lpdm, lpdm->dmSize + lpdm->dmDriverExtra); + + if (lppd->hDevNames != 0) { + WORD locks; + if((locks = (GlobalFlags(lppd->hDevNames) & GMEM_LOCKCOUNT))) { + WARN("hDevNames has %d locks on it. Unlocking it now\n", locks); + while(locks--) + GlobalUnlock(lppd->hDevNames); + } + } + PRINTDLG_CreateDevNames(&(lppd->hDevNames), + di->pDriverPath, + pi->pPrinterName, + pi->pPortName + ); + GlobalUnlock(lppd->hDevMode); + } + HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode); + HeapFree(GetProcessHeap(), 0, PrintStructures->lpPrinterInfo); + HeapFree(GetProcessHeap(), 0, PrintStructures->lpDriverInfo); + HeapFree(GetProcessHeap(), 0, PrintStructures); + } + if(bRet && (lppd->Flags & PD_RETURNDC || lppd->Flags & PD_RETURNIC)) + bRet = PRINTDLG_CreateDCA(lppd); + + TRACE("exit! (%d)\n", bRet); + return bRet; +} + +/*********************************************************************** + * PrintDlgW (COMDLG32.@) + */ +BOOL WINAPI PrintDlgW( + LPPRINTDLGW lppd /* [in/out] ptr to PRINTDLG32 struct */ + ) +{ + BOOL bRet = FALSE; + LPVOID ptr; + HINSTANCE hInst = (HINSTANCE)GetWindowLongPtrW( lppd->hwndOwner, GWLP_HINSTANCE ); + + if(TRACE_ON(commdlg)) { + char flagstr[1000] = ""; + struct pd_flags *pflag = pd_flags; + for( ; pflag->name; pflag++) { + if(lppd->Flags & pflag->flag) + strcat(flagstr, pflag->name); + } + TRACE("(%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n" + "pp. %d-%d, min p %d, max p %d, copies %d, hinst %p\n" + "flags %08lx (%s)\n", + lppd, lppd->hwndOwner, lppd->hDevMode, lppd->hDevNames, + lppd->nFromPage, lppd->nToPage, lppd->nMinPage, lppd->nMaxPage, + lppd->nCopies, lppd->hInstance, lppd->Flags, flagstr); + } + + if(lppd->lStructSize != sizeof(PRINTDLGW)) { + WARN("structure size failure !!!\n"); + COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE); + return FALSE; + } + + if(lppd->Flags & PD_RETURNDEFAULT) { + PRINTER_INFO_2W *pbuf; + DRIVER_INFO_3W *dbuf; + HANDLE hprn; + DWORD needed; + + if(lppd->hDevMode || lppd->hDevNames) { + WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n"); + COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); + return FALSE; + } + if(!PRINTDLG_OpenDefaultPrinter(&hprn)) { + WARN("Can't find default printer\n"); + COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN); + return FALSE; + } + + GetPrinterW(hprn, 2, NULL, 0, &needed); + pbuf = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*needed); + GetPrinterW(hprn, 2, (LPBYTE)pbuf, needed, &needed); + + GetPrinterDriverW(hprn, NULL, 3, NULL, 0, &needed); + dbuf = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*needed); + if (!GetPrinterDriverW(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed)) { + ERR("GetPrinterDriverA failed, le %ld, fix your config for printer %s!\n",GetLastError(),debugstr_w(pbuf->pPrinterName)); + COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); + return FALSE; + } + ClosePrinter(hprn); + + PRINTDLG_CreateDevNamesW(&(lppd->hDevNames), + dbuf->pDriverPath, + pbuf->pPrinterName, + pbuf->pPortName); + lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, pbuf->pDevMode->dmSize + + pbuf->pDevMode->dmDriverExtra); + ptr = GlobalLock(lppd->hDevMode); + memcpy(ptr, pbuf->pDevMode, pbuf->pDevMode->dmSize + + pbuf->pDevMode->dmDriverExtra); + GlobalUnlock(lppd->hDevMode); + HeapFree(GetProcessHeap(), 0, pbuf); + HeapFree(GetProcessHeap(), 0, dbuf); + bRet = TRUE; + } else { + HGLOBAL hDlgTmpl; + PRINT_PTRW *PrintStructures; + + /* load Dialog resources, + * depending on Flags indicates Print32 or Print32_setup dialog + */ + hDlgTmpl = PRINTDLG_GetDlgTemplateW(lppd); + if (!hDlgTmpl) { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + ptr = LockResource( hDlgTmpl ); + if (!ptr) { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + + PrintStructures = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(PRINT_PTRW)); + PrintStructures->lpPrintDlg = lppd; + + /* and create & process the dialog . + * -1 is failure, 0 is broken hwnd, everything else is ok. + */ + bRet = (0hwndOwner, + PrintDlgProcW, + (LPARAM)PrintStructures)); + + if(bRet) { + DEVMODEW *lpdm = PrintStructures->lpDevMode, *lpdmReturn; + PRINTER_INFO_2W *pi = PrintStructures->lpPrinterInfo; + DRIVER_INFO_3W *di = PrintStructures->lpDriverInfo; + + if (lppd->hDevMode == 0) { + TRACE(" No hDevMode yet... Need to create my own\n"); + lppd->hDevMode = GlobalAlloc(GMEM_MOVEABLE, + lpdm->dmSize + lpdm->dmDriverExtra); + } else { + WORD locks; + if((locks = (GlobalFlags(lppd->hDevMode) & GMEM_LOCKCOUNT))) { + WARN("hDevMode has %d locks on it. Unlocking it now\n", locks); + while(locks--) { + GlobalUnlock(lppd->hDevMode); + TRACE("Now got %d locks\n", locks); + } + } + lppd->hDevMode = GlobalReAlloc(lppd->hDevMode, + lpdm->dmSize + lpdm->dmDriverExtra, + GMEM_MOVEABLE); + } + lpdmReturn = GlobalLock(lppd->hDevMode); + memcpy(lpdmReturn, lpdm, lpdm->dmSize + lpdm->dmDriverExtra); + + if (lppd->hDevNames != 0) { + WORD locks; + if((locks = (GlobalFlags(lppd->hDevNames) & GMEM_LOCKCOUNT))) { + WARN("hDevNames has %d locks on it. Unlocking it now\n", locks); + while(locks--) + GlobalUnlock(lppd->hDevNames); + } + } + PRINTDLG_CreateDevNamesW(&(lppd->hDevNames), + di->pDriverPath, + pi->pPrinterName, + pi->pPortName + ); + GlobalUnlock(lppd->hDevMode); + } + HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode); + HeapFree(GetProcessHeap(), 0, PrintStructures->lpPrinterInfo); + HeapFree(GetProcessHeap(), 0, PrintStructures->lpDriverInfo); + HeapFree(GetProcessHeap(), 0, PrintStructures); + } + if(bRet && (lppd->Flags & PD_RETURNDC || lppd->Flags & PD_RETURNIC)) + bRet = PRINTDLG_CreateDCW(lppd); + + TRACE("exit! (%d)\n", bRet); + return bRet; +} + +/*********************************************************************** + * + * PageSetupDlg + * rad1 - portrait + * rad2 - landscape + * cmb1 - printer select (not in standart dialog template) + * cmb2 - paper size + * cmb3 - source (tray?) + * edt4 - border left + * edt5 - border top + * edt6 - border right + * edt7 - border bottom + * psh3 - "Printer..." + */ + +typedef struct { + LPPAGESETUPDLGA dlga; + PRINTDLGA pdlg; +} PageSetupDataA; + +typedef struct { + LPPAGESETUPDLGW dlga; + PRINTDLGW pdlg; +} PageSetupDataW; + +static HGLOBAL PRINTDLG_GetPGSTemplateA(PAGESETUPDLGA *lppd) +{ + HRSRC hResInfo; + HGLOBAL hDlgTmpl; + + if(lppd->Flags & PSD_ENABLEPAGESETUPTEMPLATEHANDLE) { + hDlgTmpl = lppd->hPageSetupTemplate; + } else if(lppd->Flags & PSD_ENABLEPAGESETUPTEMPLATE) { + hResInfo = FindResourceA(lppd->hInstance, + lppd->lpPageSetupTemplateName, (LPSTR)RT_DIALOG); + hDlgTmpl = LoadResource(lppd->hInstance, hResInfo); + } else { + hResInfo = FindResourceA(COMDLG32_hInstance,(LPCSTR)PAGESETUPDLGORD,(LPSTR)RT_DIALOG); + hDlgTmpl = LoadResource(COMDLG32_hInstance,hResInfo); + } + return hDlgTmpl; +} + +static HGLOBAL PRINTDLG_GetPGSTemplateW(PAGESETUPDLGW *lppd) +{ + HRSRC hResInfo; + HGLOBAL hDlgTmpl; + + if(lppd->Flags & PSD_ENABLEPAGESETUPTEMPLATEHANDLE) { + hDlgTmpl = lppd->hPageSetupTemplate; + } else if(lppd->Flags & PSD_ENABLEPAGESETUPTEMPLATE) { + hResInfo = FindResourceW(lppd->hInstance, + lppd->lpPageSetupTemplateName, (LPWSTR)RT_DIALOG); + hDlgTmpl = LoadResource(lppd->hInstance, hResInfo); + } else { + hResInfo = FindResourceW(COMDLG32_hInstance,(LPCWSTR)PAGESETUPDLGORD,(LPWSTR)RT_DIALOG); + hDlgTmpl = LoadResource(COMDLG32_hInstance,hResInfo); + } + return hDlgTmpl; +} + +static DWORD +_c_10mm2size(PAGESETUPDLGA *dlga,DWORD size) { + if (dlga->Flags & PSD_INTHOUSANDTHSOFINCHES) + return 10*size*10/25.4; + /* If we don't have a flag, we can choose one. Use millimeters + * to avoid confusing me + */ + dlga->Flags |= PSD_INHUNDREDTHSOFMILLIMETERS; + return 10*size; +} + + +static DWORD +_c_inch2size(PAGESETUPDLGA *dlga,DWORD size) { + if (dlga->Flags & PSD_INTHOUSANDTHSOFINCHES) + return size; + if (dlga->Flags & PSD_INHUNDREDTHSOFMILLIMETERS) + return (size*254)/10; + /* if we don't have a flag, we can choose one. Use millimeters + * to avoid confusing me + */ + dlga->Flags |= PSD_INHUNDREDTHSOFMILLIMETERS; + return (size*254)/10; +} + +static void +_c_size2strA(PageSetupDataA *pda,DWORD size,LPSTR strout) { + strcpy(strout,""); + if (pda->dlga->Flags & PSD_INHUNDREDTHSOFMILLIMETERS) { + sprintf(strout,"%.2fmm",(size*1.0)/100.0); + return; + } + if (pda->dlga->Flags & PSD_INTHOUSANDTHSOFINCHES) { + sprintf(strout,"%.2fin",(size*1.0)/1000.0); + return; + } + pda->dlga->Flags |= PSD_INHUNDREDTHSOFMILLIMETERS; + sprintf(strout,"%.2fmm",(size*1.0)/100.0); + return; +} +static void +_c_size2strW(PageSetupDataW *pda,DWORD size,LPWSTR strout) { + const static WCHAR UNDEF[] = { '<', 'u', 'n', 'd', 'e', 'f', '>', 0 }; + const static WCHAR mm_fmt[] = { '%', '.', '2', 'f', 'm', 'm', 0 }; + const static WCHAR in_fmt[] = { '%', '.', '2', 'f', 'i', 'n', 0 }; + lstrcpyW(strout, UNDEF); + if (pda->dlga->Flags & PSD_INHUNDREDTHSOFMILLIMETERS) { + wsprintfW(strout,mm_fmt,(size*1.0)/100.0); + return; + } + if (pda->dlga->Flags & PSD_INTHOUSANDTHSOFINCHES) { + wsprintfW(strout,in_fmt,(size*1.0)/1000.0); + return; + } + pda->dlga->Flags |= PSD_INHUNDREDTHSOFMILLIMETERS; + wsprintfW(strout,mm_fmt,(size*1.0)/100.0); + return; +} + +static DWORD +_c_str2sizeA(PAGESETUPDLGA *dlga,LPCSTR strin) { + float val; + char rest[200]; + + rest[0]='\0'; + if (!sscanf(strin,"%f%s",&val,rest)) + return 0; + + if (!strcmp(rest,"in") || !strcmp(rest,"inch")) { + if (dlga->Flags & PSD_INTHOUSANDTHSOFINCHES) + return 1000*val; + else + return val*25.4*100; + } + if (!strcmp(rest,"cm")) { rest[0]='m'; val = val*10.0; } + if (!strcmp(rest,"m")) { strcpy(rest,"mm"); val = val*1000.0; } + + if (!strcmp(rest,"mm")) { + if (dlga->Flags & PSD_INHUNDREDTHSOFMILLIMETERS) + return 100*val; + else + return 1000.0*val/25.4; + } + if (rest[0]=='\0') { + /* use application supplied default */ + if (dlga->Flags & PSD_INHUNDREDTHSOFMILLIMETERS) { + /* 100*mm */ + return 100.0*val; + } + if (dlga->Flags & PSD_INTHOUSANDTHSOFINCHES) { + /* 1000*inch */ + return 1000.0*val; + } + } + ERR("Did not find a conversion for type '%s'!\n",rest); + return 0; +} + + +static DWORD +_c_str2sizeW(PAGESETUPDLGW *dlga, LPCWSTR strin) { + char buf[200]; + + /* this W -> A transition is OK */ + /* we need a unicode version of sscanf to avoid it */ + WideCharToMultiByte(CP_ACP, 0, strin, -1, buf, sizeof(buf), NULL, NULL); + return _c_str2sizeA((PAGESETUPDLGA *)dlga, buf); +} + + +/* + * This is called on finish and will update the output fields of the + * struct. + */ +static BOOL +PRINTDLG_PS_UpdateDlgStructA(HWND hDlg, PageSetupDataA *pda) { + DEVNAMES *dn; + DEVMODEA *dm; + LPSTR devname,portname; + char papername[64]; + char buf[200]; + + dn = GlobalLock(pda->pdlg.hDevNames); + dm = GlobalLock(pda->pdlg.hDevMode); + devname = ((char*)dn)+dn->wDeviceOffset; + portname = ((char*)dn)+dn->wOutputOffset; + PRINTDLG_SetUpPaperComboBoxA(hDlg,cmb2,devname,portname,dm); + PRINTDLG_SetUpPaperComboBoxA(hDlg,cmb3,devname,portname,dm); + + if (GetDlgItemTextA(hDlg,cmb2,papername,sizeof(papername))>0) { + PRINTDLG_PaperSizeA(&(pda->pdlg),papername,&(pda->dlga->ptPaperSize)); + pda->dlga->ptPaperSize.x = _c_10mm2size(pda->dlga,pda->dlga->ptPaperSize.x); + pda->dlga->ptPaperSize.y = _c_10mm2size(pda->dlga,pda->dlga->ptPaperSize.y); + } else + FIXME("could not get dialog text for papersize cmbbox?\n"); +#define GETVAL(id,val) if (GetDlgItemTextA(hDlg,id,buf,sizeof(buf))>0) { val = _c_str2sizeA(pda->dlga,buf); } else { FIXME("could not get dlgitemtexta for %x\n",id); } + GETVAL(edt4,pda->dlga->rtMargin.left); + GETVAL(edt5,pda->dlga->rtMargin.top); + GETVAL(edt6,pda->dlga->rtMargin.right); + GETVAL(edt7,pda->dlga->rtMargin.bottom); +#undef GETVAL + + /* If we are in landscape, swap x and y of page size */ + if (IsDlgButtonChecked(hDlg, rad2)) { + DWORD tmp; + tmp = pda->dlga->ptPaperSize.x; + pda->dlga->ptPaperSize.x = pda->dlga->ptPaperSize.y; + pda->dlga->ptPaperSize.y = tmp; + } + GlobalUnlock(pda->pdlg.hDevNames); + GlobalUnlock(pda->pdlg.hDevMode); + return TRUE; +} + +static BOOL +PRINTDLG_PS_UpdateDlgStructW(HWND hDlg, PageSetupDataW *pda) { + DEVNAMES *dn; + DEVMODEW *dm; + LPWSTR devname,portname; + WCHAR papername[64]; + WCHAR buf[200]; + + dn = GlobalLock(pda->pdlg.hDevNames); + dm = GlobalLock(pda->pdlg.hDevMode); + devname = ((WCHAR*)dn)+dn->wDeviceOffset; + portname = ((WCHAR*)dn)+dn->wOutputOffset; + PRINTDLG_SetUpPaperComboBoxW(hDlg,cmb2,devname,portname,dm); + PRINTDLG_SetUpPaperComboBoxW(hDlg,cmb3,devname,portname,dm); + + if (GetDlgItemTextW(hDlg,cmb2,papername,sizeof(papername))>0) { + PRINTDLG_PaperSizeW(&(pda->pdlg),papername,&(pda->dlga->ptPaperSize)); + pda->dlga->ptPaperSize.x = _c_10mm2size((LPPAGESETUPDLGA)pda->dlga,pda->dlga->ptPaperSize.x); + pda->dlga->ptPaperSize.y = _c_10mm2size((LPPAGESETUPDLGA)pda->dlga,pda->dlga->ptPaperSize.y); + } else + FIXME("could not get dialog text for papersize cmbbox?\n"); +#define GETVAL(id,val) if (GetDlgItemTextW(hDlg,id,buf,sizeof(buf)/sizeof(buf[0]))>0) { val = _c_str2sizeW(pda->dlga,buf); } else { FIXME("could not get dlgitemtextw for %x\n",id); } + GETVAL(edt4,pda->dlga->rtMargin.left); + GETVAL(edt5,pda->dlga->rtMargin.top); + GETVAL(edt6,pda->dlga->rtMargin.right); + GETVAL(edt7,pda->dlga->rtMargin.bottom); +#undef GETVAL + + /* If we are in landscape, swap x and y of page size */ + if (IsDlgButtonChecked(hDlg, rad2)) { + DWORD tmp; + tmp = pda->dlga->ptPaperSize.x; + pda->dlga->ptPaperSize.x = pda->dlga->ptPaperSize.y; + pda->dlga->ptPaperSize.y = tmp; + } + GlobalUnlock(pda->pdlg.hDevNames); + GlobalUnlock(pda->pdlg.hDevMode); + return TRUE; +} + +/* + * This is called after returning from PrintDlg(). + */ +static BOOL +PRINTDLG_PS_ChangePrinterA(HWND hDlg, PageSetupDataA *pda) { + DEVNAMES *dn; + DEVMODEA *dm; + LPSTR devname,portname; + + dn = GlobalLock(pda->pdlg.hDevNames); + dm = GlobalLock(pda->pdlg.hDevMode); + devname = ((char*)dn)+dn->wDeviceOffset; + portname = ((char*)dn)+dn->wOutputOffset; + PRINTDLG_SetUpPaperComboBoxA(hDlg,cmb2,devname,portname,dm); + PRINTDLG_SetUpPaperComboBoxA(hDlg,cmb3,devname,portname,dm); + GlobalUnlock(pda->pdlg.hDevNames); + GlobalUnlock(pda->pdlg.hDevMode); + return TRUE; +} + +static BOOL +PRINTDLG_PS_ChangePrinterW(HWND hDlg, PageSetupDataW *pda) { + DEVNAMES *dn; + DEVMODEW *dm; + LPWSTR devname,portname; + + dn = GlobalLock(pda->pdlg.hDevNames); + dm = GlobalLock(pda->pdlg.hDevMode); + devname = ((WCHAR*)dn)+dn->wDeviceOffset; + portname = ((WCHAR*)dn)+dn->wOutputOffset; + PRINTDLG_SetUpPaperComboBoxW(hDlg,cmb2,devname,portname,dm); + PRINTDLG_SetUpPaperComboBoxW(hDlg,cmb3,devname,portname,dm); + GlobalUnlock(pda->pdlg.hDevNames); + GlobalUnlock(pda->pdlg.hDevMode); + return TRUE; +} + +static BOOL +PRINTDLG_PS_WMCommandA( + HWND hDlg, WPARAM wParam, LPARAM lParam, PageSetupDataA *pda +) { + TRACE("loword (lparam) %d, wparam 0x%x, lparam %08lx\n", + LOWORD(lParam),wParam,lParam); + switch (LOWORD(wParam)) { + case IDOK: + if (!PRINTDLG_PS_UpdateDlgStructA(hDlg, pda)) + return(FALSE); + EndDialog(hDlg, TRUE); + return TRUE ; + + case IDCANCEL: + EndDialog(hDlg, FALSE); + return FALSE ; + + case psh3: { + pda->pdlg.Flags = 0; + pda->pdlg.hwndOwner = hDlg; + if (PrintDlgA(&(pda->pdlg))) + PRINTDLG_PS_ChangePrinterA(hDlg,pda); + return TRUE; + } + } + return FALSE; +} + +static BOOL +PRINTDLG_PS_WMCommandW( + HWND hDlg, WPARAM wParam, LPARAM lParam, PageSetupDataW *pda +) { + TRACE("loword (lparam) %d, wparam 0x%x, lparam %08lx\n", + LOWORD(lParam),wParam,lParam); + switch (LOWORD(wParam)) { + case IDOK: + if (!PRINTDLG_PS_UpdateDlgStructW(hDlg, pda)) + return(FALSE); + EndDialog(hDlg, TRUE); + return TRUE ; + + case IDCANCEL: + EndDialog(hDlg, FALSE); + return FALSE ; + + case psh3: { + pda->pdlg.Flags = 0; + pda->pdlg.hwndOwner = hDlg; + if (PrintDlgW(&(pda->pdlg))) + PRINTDLG_PS_ChangePrinterW(hDlg,pda); + return TRUE; + } + } + return FALSE; +} + + +/*********************************************************************** + * DefaultPagePaintHook + * Default hook paint procedure that receives WM_PSD_* messages from the dialog box + * whenever the sample page is redrawn. +*/ + +static UINT_PTR +PRINTDLG_DefaultPagePaintHook(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam, PageSetupDataA *pda) +{ + LPRECT lprc = (LPRECT) lParam; + HDC hdc = (HDC) wParam; + HPEN hpen, holdpen; + LOGFONTW lf; + HFONT hfont, holdfont; + INT oldbkmode; + TRACE("uMsg: WM_USER+%d\n",uMsg-WM_USER); + + /* Call user paint hook if enable */ + if (pda->dlga->Flags & PSD_ENABLEPAGEPAINTHOOK) + if (pda->dlga->lpfnPagePaintHook(hwndDlg, uMsg, wParam, lParam)) + return TRUE; + + switch (uMsg) { + /* LPPAGESETUPDLG in lParam */ + case WM_PSD_PAGESETUPDLG: + /* Inform about the sample page rectangle */ + case WM_PSD_FULLPAGERECT: + /* Inform about the margin rectangle */ + case WM_PSD_MINMARGINRECT: + return FALSE; + + /* Draw dashed rectangle showing margins */ + case WM_PSD_MARGINRECT: + hpen = CreatePen(PS_DASH, 1, GetSysColor(COLOR_3DSHADOW)); + holdpen = SelectObject(hdc, hpen); + Rectangle(hdc, lprc->left, lprc->top, lprc->right, lprc->bottom); + DeleteObject(SelectObject(hdc, holdpen)); + return TRUE; + + + /* Draw the fake document */ + case WM_PSD_GREEKTEXTRECT: + /* select a nice scalable font, because we want the text really small */ + SystemParametersInfoW(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0); + lf.lfHeight = 6; /* value chosen based on visual effect */ + hfont = CreateFontIndirectW(&lf); + holdfont = SelectObject(hdc, hfont); + + /* if text not loaded, then do so now */ + if (wszFakeDocumentText[0] == '\0') + LoadStringW(COMDLG32_hInstance, + IDS_FAKEDOCTEXT, + wszFakeDocumentText, + sizeof(wszFakeDocumentText)/sizeof(wszFakeDocumentText[0])); + + oldbkmode = SetBkMode(hdc, TRANSPARENT); + DrawTextW(hdc, wszFakeDocumentText, -1, lprc, DT_TOP|DT_LEFT|DT_NOPREFIX|DT_WORDBREAK); + SetBkMode(hdc, oldbkmode); + + DeleteObject(SelectObject(hdc, holdfont)); + return TRUE; + + /* Envelope stamp */ + case WM_PSD_ENVSTAMPRECT: + /* Return address */ + case WM_PSD_YAFULLPAGERECT: + FIXME("envelope/stamp is not implemented\n"); + return FALSE; + default: + FIXME("Unknown message %x\n",uMsg); + return FALSE; + } + return TRUE; +} + +/*********************************************************************** + * PagePaintProc + * The main paint procedure for the PageSetupDlg function. + * The Page Setup dialog box includes an image of a sample page that shows how + * the user's selections affect the appearance of the printed output. + * The image consists of a rectangle that represents the selected paper + * or envelope type, with a dotted-line rectangle representing + * the current margins, and partial (Greek text) characters + * to show how text looks on the printed page. + * + * The following messages in the order sends to user hook procedure: + * WM_PSD_PAGESETUPDLG Draw the contents of the sample page + * WM_PSD_FULLPAGERECT Inform about the bounding rectangle + * WM_PSD_MINMARGINRECT Inform about the margin rectangle (min margin?) + * WM_PSD_MARGINRECT Draw the margin rectangle + * WM_PSD_GREEKTEXTRECT Draw the Greek text inside the margin rectangle + * If any of first three messages returns TRUE, painting done. + * + * PARAMS: + * hWnd [in] Handle to the Page Setup dialog box + * uMsg [in] Received message + * + * TODO: + * WM_PSD_ENVSTAMPRECT Draw in the envelope-stamp rectangle (for envelopes only) + * WM_PSD_YAFULLPAGERECT Draw the return address portion (for envelopes and other paper sizes) + * + * RETURNS: + * FALSE if all done correctly + * + */ +static LRESULT CALLBACK +PRINTDLG_PagePaintProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + PAINTSTRUCT ps; + RECT rcClient, rcMargin; + HPEN hpen, holdpen; + HDC hdc; + HBRUSH hbrush, holdbrush; + PageSetupDataA *pda; + int papersize=0, orientation=0; /* FIXME: set this values */ + +#define CALLPAINTHOOK(msg,lprc) PRINTDLG_DefaultPagePaintHook( hWnd, msg, (WPARAM)hdc, (LPARAM)lprc, pda) + + if (uMsg != WM_PAINT) + return CallWindowProcA(lpfnStaticWndProc, hWnd, uMsg, wParam, lParam); + + /* Processing WM_PAINT message */ + pda = (PageSetupDataA*)GetPropA(hWnd, "__WINE_PAGESETUPDLGDATA"); + if (!pda) { + WARN("__WINE_PAGESETUPDLGDATA prop not set?\n"); + return FALSE; + } + if (PRINTDLG_DefaultPagePaintHook(hWnd, WM_PSD_PAGESETUPDLG, MAKELONG(papersize, orientation), (LPARAM)pda->dlga, pda)) + return FALSE; + + hdc = BeginPaint(hWnd, &ps); + GetClientRect(hWnd, &rcClient); + + /* FIXME: use real margin values */ + rcMargin = rcClient; + rcMargin.left += 5; + rcMargin.top += 5; + rcMargin.right -= 5; + rcMargin.bottom -= 5; + + /* if the space is too small then we make sure to not draw anything */ + rcMargin.left = min(rcMargin.left, rcMargin.right); + rcMargin.top = min(rcMargin.top, rcMargin.bottom); + + if (!CALLPAINTHOOK(WM_PSD_FULLPAGERECT, &rcClient) && + !CALLPAINTHOOK(WM_PSD_MINMARGINRECT, &rcMargin) ) + { + /* fill background */ + hbrush = GetSysColorBrush(COLOR_3DHIGHLIGHT); + FillRect(hdc, &rcClient, hbrush); + holdbrush = SelectObject(hdc, hbrush); + + hpen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW)); + holdpen = SelectObject(hdc, hpen); + + + /* paint left edge */ + MoveToEx(hdc, rcClient.left, rcClient.top, NULL); + LineTo(hdc, rcClient.left, rcClient.bottom-1); + + /* paint top edge */ + MoveToEx(hdc, rcClient.left, rcClient.top, NULL); + LineTo(hdc, rcClient.right, rcClient.top); + + hpen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_3DDKSHADOW)); + DeleteObject(SelectObject(hdc, hpen)); + + /* paint right edge */ + MoveToEx(hdc, rcClient.right-1, rcClient.top, NULL); + LineTo(hdc, rcClient.right-1, rcClient.bottom); + + /* paint bottom edge */ + MoveToEx(hdc, rcClient.left, rcClient.bottom-1, NULL); + LineTo(hdc, rcClient.right, rcClient.bottom-1); + + DeleteObject(SelectObject(hdc, holdpen)); + DeleteObject(SelectObject(hdc, holdbrush)); + + + CALLPAINTHOOK(WM_PSD_MARGINRECT, &rcMargin); + + + /* give text a bit of a space from the frame */ + rcMargin.left += 2; + rcMargin.top += 2; + rcMargin.right -= 2; + rcMargin.bottom -= 2; + + /* if the space is too small then we make sure to not draw anything */ + rcMargin.left = min(rcMargin.left, rcMargin.right); + rcMargin.top = min(rcMargin.top, rcMargin.bottom); + + CALLPAINTHOOK(WM_PSD_GREEKTEXTRECT, &rcMargin); + } + + EndPaint(hWnd, &ps); + return FALSE; +#undef CALLPAINTHOOK +} + +/*********************************************************************** + * PRINTDLG_PageDlgProcA + * Message handler + */ +static INT_PTR CALLBACK +PRINTDLG_PageDlgProcA(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + PageSetupDataA *pda; + INT_PTR res = FALSE; + + if (uMsg == WM_INITDIALOG) { + pda = (PageSetupDataA*)lParam; + TRACE("set property to %p", pda); + SetPropA(hDlg, "__WINE_PAGESETUPDLGDATA", pda); + SetPropA(GetDlgItem(hDlg, rct1), "__WINE_PAGESETUPDLGDATA", pda); + lpfnStaticWndProc = (WNDPROC)SetWindowLongPtrW( + GetDlgItem(hDlg, rct1), + GWLP_WNDPROC, + (ULONG_PTR)PRINTDLG_PagePaintProc); + res = TRUE; + if (pda->dlga->Flags & PSD_ENABLEPAGESETUPHOOK) { + res = pda->dlga->lpfnPageSetupHook(hDlg,uMsg,wParam,(LPARAM)pda->dlga); + if (!res) { + FIXME("Setup page hook failed?\n"); + res = TRUE; + } + } + + if (pda->dlga->Flags & PSD_DISABLEPRINTER) + EnableWindow(GetDlgItem(hDlg, psh3), FALSE); + if (pda->dlga->Flags & PSD_DISABLEMARGINS) { + EnableWindow(GetDlgItem(hDlg, edt4), FALSE); + EnableWindow(GetDlgItem(hDlg, edt5), FALSE); + EnableWindow(GetDlgItem(hDlg, edt6), FALSE); + EnableWindow(GetDlgItem(hDlg, edt7), FALSE); + } + /* width larger as height -> landscape */ + if (pda->dlga->ptPaperSize.x > pda->dlga->ptPaperSize.y) + CheckRadioButton(hDlg, rad1, rad2, rad2); + else /* this is default if papersize is not set */ + CheckRadioButton(hDlg, rad1, rad2, rad1); + if (pda->dlga->Flags & PSD_DISABLEORIENTATION) { + EnableWindow(GetDlgItem(hDlg,rad1),FALSE); + EnableWindow(GetDlgItem(hDlg,rad2),FALSE); + } + /* We fill them out enabled or not */ + if (pda->dlga->Flags & PSD_MARGINS) { + char str[100]; + _c_size2strA(pda,pda->dlga->rtMargin.left,str); + SetDlgItemTextA(hDlg,edt4,str); + _c_size2strA(pda,pda->dlga->rtMargin.top,str); + SetDlgItemTextA(hDlg,edt5,str); + _c_size2strA(pda,pda->dlga->rtMargin.right,str); + SetDlgItemTextA(hDlg,edt6,str); + _c_size2strA(pda,pda->dlga->rtMargin.bottom,str); + SetDlgItemTextA(hDlg,edt7,str); + } else { + /* default is 1 inch */ + DWORD size = _c_inch2size(pda->dlga,1000); + char str[20]; + _c_size2strA(pda,size,str); + SetDlgItemTextA(hDlg,edt4,str); + SetDlgItemTextA(hDlg,edt5,str); + SetDlgItemTextA(hDlg,edt6,str); + SetDlgItemTextA(hDlg,edt7,str); + } + PRINTDLG_PS_ChangePrinterA(hDlg,pda); + if (pda->dlga->Flags & PSD_DISABLEPAPER) { + EnableWindow(GetDlgItem(hDlg,cmb2),FALSE); + EnableWindow(GetDlgItem(hDlg,cmb3),FALSE); + } + return TRUE; + } else { + pda = (PageSetupDataA*)GetPropA(hDlg,"__WINE_PAGESETUPDLGDATA"); + if (!pda) { + WARN("__WINE_PAGESETUPDLGDATA prop not set?\n"); + return FALSE; + } + if (pda->dlga->Flags & PSD_ENABLEPAGESETUPHOOK) { + res = pda->dlga->lpfnPageSetupHook(hDlg,uMsg,wParam,lParam); + if (res) return res; + } + } + switch (uMsg) { + case WM_COMMAND: + return PRINTDLG_PS_WMCommandA(hDlg, wParam, lParam, pda); + } + return FALSE; +} + +static INT_PTR CALLBACK +PageDlgProcW(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + const static WCHAR __WINE_PAGESETUPDLGDATA[] = + { '_', '_', 'W', 'I', 'N', 'E', '_', 'P', 'A', 'G', 'E', + 'S', 'E', 'T', 'U', 'P', 'D', 'L', 'G', 'D', 'A', 'T', 'A', 0 }; + PageSetupDataW *pda; + BOOL res = FALSE; + + if (uMsg==WM_INITDIALOG) { + res = TRUE; + pda = (PageSetupDataW*)lParam; + SetPropW(hDlg, __WINE_PAGESETUPDLGDATA, pda); + if (pda->dlga->Flags & PSD_ENABLEPAGESETUPHOOK) { + res = pda->dlga->lpfnPageSetupHook(hDlg,uMsg,wParam,(LPARAM)pda->dlga); + if (!res) { + FIXME("Setup page hook failed?\n"); + res = TRUE; + } + } + if (pda->dlga->Flags & PSD_ENABLEPAGEPAINTHOOK) { + FIXME("PagePaintHook not yet implemented!\n"); + } + if (pda->dlga->Flags & PSD_DISABLEPRINTER) + EnableWindow(GetDlgItem(hDlg, psh3), FALSE); + if (pda->dlga->Flags & PSD_DISABLEMARGINS) { + EnableWindow(GetDlgItem(hDlg, edt4), FALSE); + EnableWindow(GetDlgItem(hDlg, edt5), FALSE); + EnableWindow(GetDlgItem(hDlg, edt6), FALSE); + EnableWindow(GetDlgItem(hDlg, edt7), FALSE); + } + /* width larger as height -> landscape */ + if (pda->dlga->ptPaperSize.x > pda->dlga->ptPaperSize.y) + CheckRadioButton(hDlg, rad1, rad2, rad2); + else /* this is default if papersize is not set */ + CheckRadioButton(hDlg, rad1, rad2, rad1); + if (pda->dlga->Flags & PSD_DISABLEORIENTATION) { + EnableWindow(GetDlgItem(hDlg,rad1),FALSE); + EnableWindow(GetDlgItem(hDlg,rad2),FALSE); + } + /* We fill them out enabled or not */ + if (pda->dlga->Flags & PSD_MARGINS) { + WCHAR str[100]; + _c_size2strW(pda,pda->dlga->rtMargin.left,str); + SetDlgItemTextW(hDlg,edt4,str); + _c_size2strW(pda,pda->dlga->rtMargin.top,str); + SetDlgItemTextW(hDlg,edt5,str); + _c_size2strW(pda,pda->dlga->rtMargin.right,str); + SetDlgItemTextW(hDlg,edt6,str); + _c_size2strW(pda,pda->dlga->rtMargin.bottom,str); + SetDlgItemTextW(hDlg,edt7,str); + } else { + /* default is 1 inch */ + DWORD size = _c_inch2size((LPPAGESETUPDLGA)pda->dlga,1000); + WCHAR str[20]; + _c_size2strW(pda,size,str); + SetDlgItemTextW(hDlg,edt4,str); + SetDlgItemTextW(hDlg,edt5,str); + SetDlgItemTextW(hDlg,edt6,str); + SetDlgItemTextW(hDlg,edt7,str); + } + PRINTDLG_PS_ChangePrinterW(hDlg,pda); + if (pda->dlga->Flags & PSD_DISABLEPAPER) { + EnableWindow(GetDlgItem(hDlg,cmb2),FALSE); + EnableWindow(GetDlgItem(hDlg,cmb3),FALSE); + } + return TRUE; + } else { + pda = (PageSetupDataW*)GetPropW(hDlg, __WINE_PAGESETUPDLGDATA); + if (!pda) { + WARN("__WINE_PAGESETUPDLGDATA prop not set?\n"); + return FALSE; + } + if (pda->dlga->Flags & PSD_ENABLEPAGESETUPHOOK) { + res = pda->dlga->lpfnPageSetupHook(hDlg,uMsg,wParam,lParam); + if (res) return res; + } + } + switch (uMsg) { + case WM_COMMAND: + return PRINTDLG_PS_WMCommandW(hDlg, wParam, lParam, pda); + } + return FALSE; +} + +/*********************************************************************** + * PageSetupDlgA (COMDLG32.@) + * + * Displays the the PAGE SETUP dialog box, which enables the user to specify + * specific properties of a printed page such as + * size, source, orientation and the width of the page margins. + * + * PARAMS + * setupdlg [in] PAGESETUPDLGA struct + * + * RETURNS + * TRUE if the user pressed the OK button + * FALSE if the user cancelled the window or an error occurred + * + * NOTES + * The values of hDevMode and hDevNames are filled on output and can be + * changed in PAGESETUPDLG when they are passed in PageSetupDlg. + * BUGS + * PrintSetupDlg: + * * The Paper Orientation Icons are not implemented yet. + * * The Properties Button(s) should call DocumentPropertiesA(). + * * Settings are not yet taken from a provided DevMode or + * default printer settings. + */ + +BOOL WINAPI PageSetupDlgA(LPPAGESETUPDLGA setupdlg) { + HGLOBAL hDlgTmpl; + LPVOID ptr; + BOOL bRet; + PageSetupDataA *pda; + PRINTDLGA pdlg; + + if(TRACE_ON(commdlg)) { + char flagstr[1000] = ""; + struct pd_flags *pflag = psd_flags; + for( ; pflag->name; pflag++) { + if(setupdlg->Flags & pflag->flag) { + strcat(flagstr, pflag->name); + strcat(flagstr, "|"); + } + } + TRACE("(%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n" + "hinst %p, flags %08lx (%s)\n", + setupdlg, setupdlg->hwndOwner, setupdlg->hDevMode, + setupdlg->hDevNames, + setupdlg->hInstance, setupdlg->Flags, flagstr); + } + if (setupdlg->Flags & PSD_ENABLEPAGEPAINTHOOK) + if (setupdlg->lpfnPagePaintHook == NULL) { + COMDLG32_SetCommDlgExtendedError(CDERR_NOHOOK); + return FALSE; + } + + /* First get default printer data, we need it right after that. */ + memset(&pdlg,0,sizeof(pdlg)); + pdlg.lStructSize = sizeof(pdlg); + pdlg.Flags = PD_RETURNDEFAULT; + bRet = PrintDlgA(&pdlg); + if (!bRet) return FALSE; + + /* short cut exit, just return default values */ + if (setupdlg->Flags & PSD_RETURNDEFAULT) { + setupdlg->hDevMode = pdlg.hDevMode; + setupdlg->hDevNames = pdlg.hDevNames; + /* FIXME: Just return "A4" for now. */ + PRINTDLG_PaperSizeA(&pdlg,"A4",&setupdlg->ptPaperSize); + setupdlg->ptPaperSize.x=_c_10mm2size(setupdlg,setupdlg->ptPaperSize.x); + setupdlg->ptPaperSize.y=_c_10mm2size(setupdlg,setupdlg->ptPaperSize.y); + return TRUE; + } + hDlgTmpl = PRINTDLG_GetPGSTemplateA(setupdlg); + if (!hDlgTmpl) { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + ptr = LockResource( hDlgTmpl ); + if (!ptr) { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + pda = HeapAlloc(GetProcessHeap(),0,sizeof(*pda)); + pda->dlga = setupdlg; + memcpy(&pda->pdlg,&pdlg,sizeof(pdlg)); + + bRet = (0hInstance, + ptr, + setupdlg->hwndOwner, + PRINTDLG_PageDlgProcA, + (LPARAM)pda) + ); + return bRet; +} +/*********************************************************************** + * PageSetupDlgW (COMDLG32.@) + */ +BOOL WINAPI PageSetupDlgW(LPPAGESETUPDLGW setupdlg) { + HGLOBAL hDlgTmpl; + LPVOID ptr; + BOOL bRet; + PageSetupDataW *pdw; + PRINTDLGW pdlg; + FIXME("Unicode implementation is not done yet\n"); + if(TRACE_ON(commdlg)) { + char flagstr[1000] = ""; + struct pd_flags *pflag = psd_flags; + for( ; pflag->name; pflag++) { + if(setupdlg->Flags & pflag->flag) { + strcat(flagstr, pflag->name); + strcat(flagstr, "|"); + } + } + TRACE("(%p): hwndOwner = %p, hDevMode = %p, hDevNames = %p\n" + "hinst %p, flags %08lx (%s)\n", + setupdlg, setupdlg->hwndOwner, setupdlg->hDevMode, + setupdlg->hDevNames, + setupdlg->hInstance, setupdlg->Flags, flagstr); + } + + /* First get default printer data, we need it right after that. */ + memset(&pdlg,0,sizeof(pdlg)); + pdlg.lStructSize = sizeof(pdlg); + pdlg.Flags = PD_RETURNDEFAULT; + bRet = PrintDlgW(&pdlg); + if (!bRet) return FALSE; + + /* short cut exit, just return default values */ + if (setupdlg->Flags & PSD_RETURNDEFAULT) { + static const WCHAR a4[] = {'A','4',0}; + setupdlg->hDevMode = pdlg.hDevMode; + setupdlg->hDevNames = pdlg.hDevNames; + /* FIXME: Just return "A4" for now. */ + PRINTDLG_PaperSizeW(&pdlg,a4,&setupdlg->ptPaperSize); + setupdlg->ptPaperSize.x=_c_10mm2size((LPPAGESETUPDLGA)setupdlg,setupdlg->ptPaperSize.x); + setupdlg->ptPaperSize.y=_c_10mm2size((LPPAGESETUPDLGA)setupdlg,setupdlg->ptPaperSize.y); + return TRUE; + } + hDlgTmpl = PRINTDLG_GetPGSTemplateW(setupdlg); + if (!hDlgTmpl) { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + ptr = LockResource( hDlgTmpl ); + if (!ptr) { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + pdw = HeapAlloc(GetProcessHeap(),0,sizeof(*pdw)); + pdw->dlga = setupdlg; + memcpy(&pdw->pdlg,&pdlg,sizeof(pdlg)); + + bRet = (0hInstance, + ptr, + setupdlg->hwndOwner, + PageDlgProcW, + (LPARAM)pdw) + ); + return bRet; +} + +/*********************************************************************** + * PrintDlgExA (COMDLG32.@) + */ +HRESULT WINAPI PrintDlgExA(LPPRINTDLGEXA lpPrintDlgExA) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + +/*********************************************************************** + * PrintDlgExW (COMDLG32.@) + */ +HRESULT WINAPI PrintDlgExW(LPPRINTDLGEXW lpPrintDlgExW) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} diff --git a/reactos/lib/comdlg32/printdlg.h b/reactos/lib/comdlg32/printdlg.h index 73ed2ac1b33..748e5c033fc 100644 --- a/reactos/lib/comdlg32/printdlg.h +++ b/reactos/lib/comdlg32/printdlg.h @@ -1,102 +1,102 @@ -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _WINE_PRINTDLG_H -#define _WINE_PRINTDLG_H - -#include "cdlg.h" - -/* This PRINTDLGA internal structure stores - * pointers to several throughout useful structures. - */ - -typedef struct -{ - LPDEVMODEA lpDevMode; - LPPRINTDLGA lpPrintDlg; - LPPRINTER_INFO_2A lpPrinterInfo; - LPDRIVER_INFO_3A lpDriverInfo; - UINT HelpMessageID; - HICON hCollateIcon; /* PrintDlg only */ - HICON hNoCollateIcon; /* PrintDlg only */ - HICON hPortraitIcon; /* PrintSetupDlg only */ - HICON hLandscapeIcon; /* PrintSetupDlg only */ - HWND hwndUpDown; -} PRINT_PTRA; - -typedef struct -{ - LPDEVMODEW lpDevMode; - LPPRINTDLGW lpPrintDlg; - LPPRINTER_INFO_2W lpPrinterInfo; - LPDRIVER_INFO_3W lpDriverInfo; - UINT HelpMessageID; - HICON hCollateIcon; /* PrintDlg only */ - HICON hNoCollateIcon; /* PrintDlg only */ - HICON hPortraitIcon; /* PrintSetupDlg only */ - HICON hLandscapeIcon; /* PrintSetupDlg only */ - HWND hwndUpDown; -} PRINT_PTRW; - -/* Debugging info */ -static struct pd_flags { - DWORD flag; - LPCSTR name; -} pd_flags[] = { - {PD_SELECTION, "PD_SELECTION "}, - {PD_PAGENUMS, "PD_PAGENUMS "}, - {PD_NOSELECTION, "PD_NOSELECTION "}, - {PD_NOPAGENUMS, "PD_NOPAGENUMS "}, - {PD_COLLATE, "PD_COLLATE "}, - {PD_PRINTTOFILE, "PD_PRINTTOFILE "}, - {PD_PRINTSETUP, "PD_PRINTSETUP "}, - {PD_NOWARNING, "PD_NOWARNING "}, - {PD_RETURNDC, "PD_RETURNDC "}, - {PD_RETURNIC, "PD_RETURNIC "}, - {PD_RETURNDEFAULT, "PD_RETURNDEFAULT "}, - {PD_SHOWHELP, "PD_SHOWHELP "}, - {PD_ENABLEPRINTHOOK, "PD_ENABLEPRINTHOOK "}, - {PD_ENABLESETUPHOOK, "PD_ENABLESETUPHOOK "}, - {PD_ENABLEPRINTTEMPLATE, "PD_ENABLEPRINTTEMPLATE "}, - {PD_ENABLESETUPTEMPLATE, "PD_ENABLESETUPTEMPLATE "}, - {PD_ENABLEPRINTTEMPLATEHANDLE, "PD_ENABLEPRINTTEMPLATEHANDLE "}, - {PD_ENABLESETUPTEMPLATEHANDLE, "PD_ENABLESETUPTEMPLATEHANDLE "}, - {PD_USEDEVMODECOPIES, "PD_USEDEVMODECOPIES[ANDCOLLATE] "}, - {PD_DISABLEPRINTTOFILE, "PD_DISABLEPRINTTOFILE "}, - {PD_HIDEPRINTTOFILE, "PD_HIDEPRINTTOFILE "}, - {PD_NONETWORKBUTTON, "PD_NONETWORKBUTTON "}, - {-1, NULL} -}; - -/* Internal Functions - * Do not Export to other applications or dlls - */ - -INT PRINTDLG_SetUpPrinterListComboA(HWND hDlg, UINT id, LPCSTR name); -BOOL PRINTDLG_ChangePrinterA(HWND hDlg, char *name, - PRINT_PTRA *PrintStructures); -BOOL PRINTDLG_OpenDefaultPrinter(HANDLE *hprn); -LRESULT PRINTDLG_WMCommandA(HWND hDlg, WPARAM wParam, - LPARAM lParam, PRINT_PTRA* PrintStructures); - -#endif /* _WINE_PRINTDLG_H */ +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _WINE_PRINTDLG_H +#define _WINE_PRINTDLG_H + +#include "cdlg.h" + +/* This PRINTDLGA internal structure stores + * pointers to several throughout useful structures. + */ + +typedef struct +{ + LPDEVMODEA lpDevMode; + LPPRINTDLGA lpPrintDlg; + LPPRINTER_INFO_2A lpPrinterInfo; + LPDRIVER_INFO_3A lpDriverInfo; + UINT HelpMessageID; + HICON hCollateIcon; /* PrintDlg only */ + HICON hNoCollateIcon; /* PrintDlg only */ + HICON hPortraitIcon; /* PrintSetupDlg only */ + HICON hLandscapeIcon; /* PrintSetupDlg only */ + HWND hwndUpDown; +} PRINT_PTRA; + +typedef struct +{ + LPDEVMODEW lpDevMode; + LPPRINTDLGW lpPrintDlg; + LPPRINTER_INFO_2W lpPrinterInfo; + LPDRIVER_INFO_3W lpDriverInfo; + UINT HelpMessageID; + HICON hCollateIcon; /* PrintDlg only */ + HICON hNoCollateIcon; /* PrintDlg only */ + HICON hPortraitIcon; /* PrintSetupDlg only */ + HICON hLandscapeIcon; /* PrintSetupDlg only */ + HWND hwndUpDown; +} PRINT_PTRW; + +/* Debugging info */ +static struct pd_flags { + DWORD flag; + LPCSTR name; +} pd_flags[] = { + {PD_SELECTION, "PD_SELECTION "}, + {PD_PAGENUMS, "PD_PAGENUMS "}, + {PD_NOSELECTION, "PD_NOSELECTION "}, + {PD_NOPAGENUMS, "PD_NOPAGENUMS "}, + {PD_COLLATE, "PD_COLLATE "}, + {PD_PRINTTOFILE, "PD_PRINTTOFILE "}, + {PD_PRINTSETUP, "PD_PRINTSETUP "}, + {PD_NOWARNING, "PD_NOWARNING "}, + {PD_RETURNDC, "PD_RETURNDC "}, + {PD_RETURNIC, "PD_RETURNIC "}, + {PD_RETURNDEFAULT, "PD_RETURNDEFAULT "}, + {PD_SHOWHELP, "PD_SHOWHELP "}, + {PD_ENABLEPRINTHOOK, "PD_ENABLEPRINTHOOK "}, + {PD_ENABLESETUPHOOK, "PD_ENABLESETUPHOOK "}, + {PD_ENABLEPRINTTEMPLATE, "PD_ENABLEPRINTTEMPLATE "}, + {PD_ENABLESETUPTEMPLATE, "PD_ENABLESETUPTEMPLATE "}, + {PD_ENABLEPRINTTEMPLATEHANDLE, "PD_ENABLEPRINTTEMPLATEHANDLE "}, + {PD_ENABLESETUPTEMPLATEHANDLE, "PD_ENABLESETUPTEMPLATEHANDLE "}, + {PD_USEDEVMODECOPIES, "PD_USEDEVMODECOPIES[ANDCOLLATE] "}, + {PD_DISABLEPRINTTOFILE, "PD_DISABLEPRINTTOFILE "}, + {PD_HIDEPRINTTOFILE, "PD_HIDEPRINTTOFILE "}, + {PD_NONETWORKBUTTON, "PD_NONETWORKBUTTON "}, + {-1, NULL} +}; + +/* Internal Functions + * Do not Export to other applications or dlls + */ + +INT PRINTDLG_SetUpPrinterListComboA(HWND hDlg, UINT id, LPCSTR name); +BOOL PRINTDLG_ChangePrinterA(HWND hDlg, char *name, + PRINT_PTRA *PrintStructures); +BOOL PRINTDLG_OpenDefaultPrinter(HANDLE *hprn); +LRESULT PRINTDLG_WMCommandA(HWND hDlg, WPARAM wParam, + LPARAM lParam, PRINT_PTRA* PrintStructures); + +#endif /* _WINE_PRINTDLG_H */ diff --git a/reactos/lib/comdlg32/printdlg16.c b/reactos/lib/comdlg32/printdlg16.c index 95af3ed63ae..0f665e74072 100644 --- a/reactos/lib/comdlg32/printdlg16.c +++ b/reactos/lib/comdlg32/printdlg16.c @@ -1,594 +1,594 @@ -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include - -#define NONAMELESSUNION -#define NONAMELESSSTRUCT -#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 "winerror.h" - -WINE_DEFAULT_DEBUG_CHANNEL(commdlg); - -#include "cdlg.h" -#include "cdlg16.h" -#include "printdlg.h" - -typedef struct -{ - PRINT_PTRA print32; - LPPRINTDLG16 lpPrintDlg16; -} PRINT_PTRA16; - -/* Internal Functions */ - -static BOOL PRINTDLG_CreateDevNames16(HGLOBAL16 *hmem, char* DeviceDriverName, - char* DeviceName, char* OutputPort) -{ - long size; - char* pDevNamesSpace; - char* pTempPtr; - LPDEVNAMES lpDevNames; - char buf[260]; - DWORD dwBufLen = sizeof(buf); - - size = strlen(DeviceDriverName) + 1 - + strlen(DeviceName) + 1 - + strlen(OutputPort) + 1 - + sizeof(DEVNAMES); - - if(*hmem) - *hmem = GlobalReAlloc16(*hmem, size, GMEM_MOVEABLE); - else - *hmem = GlobalAlloc16(GMEM_MOVEABLE, size); - if (*hmem == 0) - return FALSE; - - pDevNamesSpace = GlobalLock16(*hmem); - lpDevNames = (LPDEVNAMES) pDevNamesSpace; - - pTempPtr = pDevNamesSpace + sizeof(DEVNAMES); - strcpy(pTempPtr, DeviceDriverName); - lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace; - - pTempPtr += strlen(DeviceDriverName) + 1; - strcpy(pTempPtr, DeviceName); - lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace; - - pTempPtr += strlen(DeviceName) + 1; - strcpy(pTempPtr, OutputPort); - lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace; - - GetDefaultPrinterA(buf, &dwBufLen); - lpDevNames->wDefault = (strcmp(buf, DeviceName) == 0) ? 1 : 0; - GlobalUnlock16(*hmem); - return TRUE; -} - - -/*********************************************************************** - * PRINTDLG_WMInitDialog [internal] - */ -static LRESULT PRINTDLG_WMInitDialog16(HWND hDlg, WPARAM wParam, PRINT_PTRA16* ptr16) -{ - PRINT_PTRA *PrintStructures = &ptr16->print32; - LPPRINTDLG16 lppd = ptr16->lpPrintDlg16; - DEVNAMES *pdn; - DEVMODEA *pdm; - char *name = NULL; - UINT comboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4; - - /* load Collate ICONs */ - PrintStructures->hCollateIcon = - LoadIconA(COMDLG32_hInstance, "PD32_COLLATE"); - PrintStructures->hNoCollateIcon = - LoadIconA(COMDLG32_hInstance, "PD32_NOCOLLATE"); - if(PrintStructures->hCollateIcon == 0 || - PrintStructures->hNoCollateIcon == 0) { - ERR("no icon in resourcefile\n"); - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - EndDialog(hDlg, FALSE); - } - - /* load Paper Orientation ICON */ - /* FIXME: not implemented yet */ - - /* - * if lppd->Flags PD_SHOWHELP is specified, a HELPMESGSTRING message - * must be registered and the Help button must be shown. - */ - if (lppd->Flags & PD_SHOWHELP) { - if((PrintStructures->HelpMessageID = - RegisterWindowMessageA(HELPMSGSTRINGA)) == 0) { - COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL); - return FALSE; - } - } else - PrintStructures->HelpMessageID = 0; - - if (!(lppd->Flags & PD_PRINTSETUP)) { - /* We have a print quality combo box. What shall we do? */ - if (GetDlgItem(hDlg,cmb1)) { - char buf [20]; - - FIXME("Print quality only displaying currently.\n"); - - pdm = GlobalLock16(lppd->hDevMode); - if(pdm) { - switch (pdm->dmPrintQuality) { - case DMRES_HIGH : strcpy(buf,"High");break; - case DMRES_MEDIUM : strcpy(buf,"Medium");break; - case DMRES_LOW : strcpy(buf,"Low");break; - case DMRES_DRAFT : strcpy(buf,"Draft");break; - case 0 : strcpy(buf,"Default");break; - default : sprintf(buf,"%ddpi",pdm->dmPrintQuality);break; - } - GlobalUnlock16(lppd->hDevMode); - } else - strcpy(buf,"Default"); - SendDlgItemMessageA(hDlg,cmb1,CB_ADDSTRING,0,(LPARAM)buf); - SendDlgItemMessageA(hDlg,cmb1,CB_SETCURSEL,0,0); - EnableWindow(GetDlgItem(hDlg,cmb1),FALSE); - } - } - - /* FIXME: I allow more freedom than either Win95 or WinNT, - * which do not agree to what errors should be thrown or not - * in case nToPage or nFromPage is out-of-range. - */ - if (lppd->nMaxPage < lppd->nMinPage) - lppd->nMaxPage = lppd->nMinPage; - if (lppd->nMinPage == lppd->nMaxPage) - lppd->Flags |= PD_NOPAGENUMS; - if (lppd->nToPage < lppd->nMinPage) - lppd->nToPage = lppd->nMinPage; - if (lppd->nToPage > lppd->nMaxPage) - lppd->nToPage = lppd->nMaxPage; - if (lppd->nFromPage < lppd->nMinPage) - lppd->nFromPage = lppd->nMinPage; - if (lppd->nFromPage > lppd->nMaxPage) - lppd->nFromPage = lppd->nMaxPage; - - /* If the printer combo box is in the dialog, fill it */ - if (GetDlgItem(hDlg,comboID)) { - /* Fill Combobox - */ - pdn = GlobalLock16(lppd->hDevNames); - pdm = GlobalLock16(lppd->hDevMode); - if(pdn) - name = (char*)pdn + pdn->wDeviceOffset; - else if(pdm) - name = pdm->dmDeviceName; - PRINTDLG_SetUpPrinterListComboA(hDlg, comboID, name); - if(pdm) GlobalUnlock16(lppd->hDevMode); - if(pdn) GlobalUnlock16(lppd->hDevNames); - - /* Now find selected printer and update rest of dlg */ - name = HeapAlloc(GetProcessHeap(),0,256); - if (GetDlgItemTextA(hDlg, comboID, name, 255)) - PRINTDLG_ChangePrinterA(hDlg, name, PrintStructures); - } else { - /* else just use default printer */ - char name[200]; - DWORD dwBufLen = sizeof(name); - BOOL ret = GetDefaultPrinterA(name, &dwBufLen); - - if (ret) - PRINTDLG_ChangePrinterA(hDlg, name, PrintStructures); - else - FIXME("No default printer found, expect problems!\n"); - } - HeapFree(GetProcessHeap(),0,name); - - return TRUE; -} - -/************************************************************ - * - * PRINTDLG_Get16TemplateFrom32 [Internal] - * Generates a 16 bits template from the Wine 32 bits resource - * - */ -static HGLOBAL16 PRINTDLG_Get16TemplateFrom32(LPCSTR PrintResourceName) -{ - HRSRC hResInfo; - HGLOBAL hDlgTmpl32; - LPCVOID template32; - DWORD size; - HGLOBAL16 hGlobal16; - LPVOID template; - - if (!(hResInfo = FindResourceA(COMDLG32_hInstance, - PrintResourceName, (LPSTR)RT_DIALOG))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); - return 0; - } - if (!(hDlgTmpl32 = LoadResource(COMDLG32_hInstance, hResInfo )) || - !(template32 = LockResource( hDlgTmpl32 ))) - { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return 0; - } - size = SizeofResource(COMDLG32_hInstance, hResInfo); - hGlobal16 = GlobalAlloc16(0, size); - if (!hGlobal16) - { - COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE); - ERR("alloc failure for %ld bytes\n", size); - return 0; - } - template = GlobalLock16(hGlobal16); - if (!template) - { - COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE); - ERR("global lock failure for %x handle\n", hGlobal16); - GlobalFree16(hGlobal16); - return 0; - } - ConvertDialog32To16((LPVOID)template32, size, (LPVOID)template); - GlobalUnlock16(hGlobal16); - return hGlobal16; -} - -static BOOL PRINTDLG_CreateDC16(LPPRINTDLG16 lppd) -{ - DEVNAMES *pdn = GlobalLock16(lppd->hDevNames); - DEVMODEA *pdm = GlobalLock16(lppd->hDevMode); - - if(lppd->Flags & PD_RETURNDC) { - lppd->hDC = HDC_16(CreateDCA((char*)pdn + pdn->wDriverOffset, - (char*)pdn + pdn->wDeviceOffset, - (char*)pdn + pdn->wOutputOffset, - pdm )); - } else if(lppd->Flags & PD_RETURNIC) { - lppd->hDC = HDC_16(CreateICA((char*)pdn + pdn->wDriverOffset, - (char*)pdn + pdn->wDeviceOffset, - (char*)pdn + pdn->wOutputOffset, - pdm )); - } - GlobalUnlock16(lppd->hDevNames); - GlobalUnlock16(lppd->hDevMode); - return lppd->hDC ? TRUE : FALSE; -} - -/************************************************************ - * - * PRINTDLG_GetDlgTemplate - * - */ -static HGLOBAL16 PRINTDLG_GetDlgTemplate16(PRINTDLG16 *lppd) -{ - HGLOBAL16 hDlgTmpl, hResInfo; - - if (lppd->Flags & PD_PRINTSETUP) { - if(lppd->Flags & PD_ENABLESETUPTEMPLATEHANDLE) { - hDlgTmpl = lppd->hSetupTemplate; - } else if(lppd->Flags & PD_ENABLESETUPTEMPLATE) { - hResInfo = FindResource16(lppd->hInstance, - MapSL(lppd->lpSetupTemplateName), (LPSTR)RT_DIALOG); - hDlgTmpl = LoadResource16(lppd->hInstance, hResInfo); - } else { - hDlgTmpl = PRINTDLG_Get16TemplateFrom32("PRINT32_SETUP"); - } - } else { - if(lppd->Flags & PD_ENABLEPRINTTEMPLATEHANDLE) { - hDlgTmpl = lppd->hPrintTemplate; - } else if(lppd->Flags & PD_ENABLEPRINTTEMPLATE) { - hResInfo = FindResource16(lppd->hInstance, - MapSL(lppd->lpPrintTemplateName), - (LPSTR)RT_DIALOG); - hDlgTmpl = LoadResource16(lppd->hInstance, hResInfo); - } else { - hDlgTmpl = PRINTDLG_Get16TemplateFrom32("PRINT32"); - } - } - return hDlgTmpl; -} - -/********************************************************************** - * - * 16 bit commdlg - */ - -/*********************************************************************** - * PrintDlg (COMMDLG.20) - * - * Displays the 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( - LPPRINTDLG16 lppd /* [in/out] ptr to PRINTDLG struct */ -) { - BOOL bRet = FALSE; - LPVOID ptr; - HINSTANCE16 hInst = GetWindowLongPtrW( HWND_32(lppd->hwndOwner), GWLP_HINSTANCE ); - - if(TRACE_ON(commdlg)) { - char flagstr[1000] = ""; - struct pd_flags *pflag = pd_flags; - for( ; pflag->name; pflag++) { - if(lppd->Flags & pflag->flag) - strcat(flagstr, pflag->name); - } - TRACE("(%p): hwndOwner = %08x, hDevMode = %08x, hDevNames = %08x\n" - "pp. %d-%d, min p %d, max p %d, copies %d, hinst %08x\n" - "flags %08lx (%s)\n", - lppd, lppd->hwndOwner, lppd->hDevMode, lppd->hDevNames, - lppd->nFromPage, lppd->nToPage, lppd->nMinPage, lppd->nMaxPage, - lppd->nCopies, lppd->hInstance, lppd->Flags, flagstr); - } - - if(lppd->lStructSize != sizeof(PRINTDLG16)) { - ERR("structure size (%ld/%d)\n",lppd->lStructSize,sizeof(PRINTDLG16)); - COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE); - return FALSE; - } - - if(lppd->Flags & PD_RETURNDEFAULT) { - PRINTER_INFO_2A *pbuf; - DRIVER_INFO_3A *dbuf; - HANDLE hprn; - DWORD needed; - - if(lppd->hDevMode || lppd->hDevNames) { - WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n"); - COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); - return FALSE; - } - if(!PRINTDLG_OpenDefaultPrinter(&hprn)) { - WARN("Can't find default printer\n"); - COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN); - return FALSE; - } - - GetPrinterA(hprn, 2, NULL, 0, &needed); - pbuf = HeapAlloc(GetProcessHeap(), 0, needed); - GetPrinterA(hprn, 2, (LPBYTE)pbuf, needed, &needed); - GetPrinterDriverA(hprn, NULL, 3, NULL, 0, &needed); - dbuf = HeapAlloc(GetProcessHeap(),0,needed); - if (!GetPrinterDriverA(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed)) { - ERR("GetPrinterDriverA failed for %s, le %ld, fix your config!\n", - pbuf->pPrinterName,GetLastError()); - HeapFree(GetProcessHeap(), 0, dbuf); - COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); - return FALSE; - } - ClosePrinter(hprn); - PRINTDLG_CreateDevNames16(&(lppd->hDevNames), - dbuf->pDriverPath, - pbuf->pPrinterName, - pbuf->pPortName); - lppd->hDevMode = GlobalAlloc16(GMEM_MOVEABLE,pbuf->pDevMode->dmSize+ - pbuf->pDevMode->dmDriverExtra); - ptr = GlobalLock16(lppd->hDevMode); - memcpy(ptr, pbuf->pDevMode, pbuf->pDevMode->dmSize + - pbuf->pDevMode->dmDriverExtra); - GlobalUnlock16(lppd->hDevMode); - HeapFree(GetProcessHeap(), 0, pbuf); - HeapFree(GetProcessHeap(), 0, dbuf); - bRet = TRUE; - } else { - HGLOBAL16 hDlgTmpl; - PRINT_PTRA *PrintStructures; - PRINT_PTRA16 *ptr16; - - /* load Dialog resources, - * depending on Flags indicates Print32 or Print32_setup dialog - */ - hDlgTmpl = PRINTDLG_GetDlgTemplate16(lppd); - if (!hDlgTmpl) { - COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); - return FALSE; - } - ptr16 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PRINT_PTRA16)); - ptr16->lpPrintDlg16 = lppd; - PrintStructures = &ptr16->print32; - PrintStructures->lpPrintDlg = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(PRINTDLGA)); -#define CVAL(x) PrintStructures->lpPrintDlg->x = lppd->x; -#define MVAL(x) PrintStructures->lpPrintDlg->x = MapSL(lppd->x); - CVAL(Flags); - PrintStructures->lpPrintDlg->hwndOwner = HWND_32(lppd->hwndOwner); - PrintStructures->lpPrintDlg->hDC = HDC_32(lppd->hDC); - CVAL(nFromPage);CVAL(nToPage);CVAL(nMinPage);CVAL(nMaxPage); - CVAL(nCopies); - PrintStructures->lpPrintDlg->hInstance = HINSTANCE_32(lppd->hInstance); - CVAL(lCustData); - MVAL(lpPrintTemplateName);MVAL(lpSetupTemplateName); - /* Don't copy rest, it is 16 bit specific */ -#undef MVAL -#undef CVAL - - PrintStructures->lpDevMode = HeapAlloc(GetProcessHeap(),0,sizeof(DEVMODEA)); - - /* and create & process the dialog . - * -1 is failure, 0 is broken hwnd, everything else is ok. - */ - bRet = (0hwndOwner, - (DLGPROC16)GetProcAddress16(GetModuleHandle16("COMMDLG"),(LPCSTR)21), - (LPARAM)PrintStructures - ) - ); - if (!PrintStructures->lpPrinterInfo) bRet = FALSE; - if(bRet) { - DEVMODEA *lpdm = PrintStructures->lpDevMode, *lpdmReturn; - PRINTER_INFO_2A *pi = PrintStructures->lpPrinterInfo; - DRIVER_INFO_3A *di = PrintStructures->lpDriverInfo; - - if (lppd->hDevMode == 0) { - TRACE(" No hDevMode yet... Need to create my own\n"); - lppd->hDevMode = GlobalAlloc16(GMEM_MOVEABLE, - lpdm->dmSize + lpdm->dmDriverExtra); - } else { - WORD locks; - if((locks = (GlobalFlags16(lppd->hDevMode)&GMEM_LOCKCOUNT))) { - WARN("hDevMode has %d locks on it. Unlocking it now\n", locks); - while(locks--) { - GlobalUnlock16(lppd->hDevMode); - TRACE("Now got %d locks\n", locks); - } - } - lppd->hDevMode = GlobalReAlloc16(lppd->hDevMode, - lpdm->dmSize + lpdm->dmDriverExtra, - GMEM_MOVEABLE); - } - lpdmReturn = GlobalLock16(lppd->hDevMode); - memcpy(lpdmReturn, lpdm, lpdm->dmSize + lpdm->dmDriverExtra); - - if (lppd->hDevNames != 0) { - WORD locks; - if((locks = (GlobalFlags16(lppd->hDevNames)&GMEM_LOCKCOUNT))) { - WARN("hDevNames has %d locks on it. Unlocking it now\n", locks); - while(locks--) - GlobalUnlock16(lppd->hDevNames); - } - } - PRINTDLG_CreateDevNames16(&(lppd->hDevNames), - di->pDriverPath, - pi->pPrinterName, - pi->pPortName - ); - GlobalUnlock16(lppd->hDevMode); - } - if (!(lppd->Flags & (PD_ENABLESETUPTEMPLATEHANDLE | PD_ENABLESETUPTEMPLATE))) - GlobalFree16(hDlgTmpl); /* created from the 32 bits resource */ - HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode); - HeapFree(GetProcessHeap(), 0, PrintStructures->lpPrinterInfo); - HeapFree(GetProcessHeap(), 0, PrintStructures->lpDriverInfo); - HeapFree(GetProcessHeap(), 0, PrintStructures); - } - if(bRet && (lppd->Flags & PD_RETURNDC || lppd->Flags & PD_RETURNIC)) - bRet = PRINTDLG_CreateDC16(lppd); - - TRACE("exit! (%d)\n", bRet); - return bRet; -} - -/*********************************************************************** - * PrintDlgProc (COMMDLG.21) - */ -BOOL16 CALLBACK PrintDlgProc16(HWND16 hDlg16, UINT16 uMsg, WPARAM16 wParam, - LPARAM lParam) -{ - HWND hDlg = HWND_32(hDlg16); - PRINT_PTRA16 *PrintStructures; - BOOL16 res = FALSE; - - if (uMsg!=WM_INITDIALOG) { - PrintStructures = (PRINT_PTRA16*)GetPropA(hDlg,"__WINE_PRINTDLGDATA"); - if (!PrintStructures) - return FALSE; - } else { - PrintStructures = (PRINT_PTRA16*) lParam; - SetPropA(hDlg,"__WINE_PRINTDLGDATA",PrintStructures); - res = PRINTDLG_WMInitDialog16(hDlg, wParam, PrintStructures); - - if(PrintStructures->lpPrintDlg16->Flags & PD_ENABLEPRINTHOOK) { - res = CallWindowProc16( - (WNDPROC16)PrintStructures->lpPrintDlg16->lpfnPrintHook, - hDlg16, uMsg, wParam, (LPARAM)PrintStructures->lpPrintDlg16 - ); - } - return res; - } - - if(PrintStructures->lpPrintDlg16->Flags & PD_ENABLEPRINTHOOK) { - res = CallWindowProc16( - (WNDPROC16)PrintStructures->lpPrintDlg16->lpfnPrintHook, - hDlg16,uMsg, wParam, lParam - ); - if(LOWORD(res)) return res; - } - - switch (uMsg) { - case WM_COMMAND: { - /* We need to map those for the 32bit window procedure, compare - * with 32Ato16 mapper in winproc.c - */ - return PRINTDLG_WMCommandA( - hDlg, - MAKEWPARAM(wParam,HIWORD(lParam)), - LOWORD(lParam), - &PrintStructures->print32 - ); - } - case WM_DESTROY: - DestroyIcon(PrintStructures->print32.hCollateIcon); - DestroyIcon(PrintStructures->print32.hNoCollateIcon); - /* FIXME: don't forget to delete the paper orientation icons here! */ - - return FALSE; - } - return res; -} - -/*********************************************************************** - * 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; -} +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#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 "winerror.h" + +WINE_DEFAULT_DEBUG_CHANNEL(commdlg); + +#include "cdlg.h" +#include "cdlg16.h" +#include "printdlg.h" + +typedef struct +{ + PRINT_PTRA print32; + LPPRINTDLG16 lpPrintDlg16; +} PRINT_PTRA16; + +/* Internal Functions */ + +static BOOL PRINTDLG_CreateDevNames16(HGLOBAL16 *hmem, char* DeviceDriverName, + char* DeviceName, char* OutputPort) +{ + long size; + char* pDevNamesSpace; + char* pTempPtr; + LPDEVNAMES lpDevNames; + char buf[260]; + DWORD dwBufLen = sizeof(buf); + + size = strlen(DeviceDriverName) + 1 + + strlen(DeviceName) + 1 + + strlen(OutputPort) + 1 + + sizeof(DEVNAMES); + + if(*hmem) + *hmem = GlobalReAlloc16(*hmem, size, GMEM_MOVEABLE); + else + *hmem = GlobalAlloc16(GMEM_MOVEABLE, size); + if (*hmem == 0) + return FALSE; + + pDevNamesSpace = GlobalLock16(*hmem); + lpDevNames = (LPDEVNAMES) pDevNamesSpace; + + pTempPtr = pDevNamesSpace + sizeof(DEVNAMES); + strcpy(pTempPtr, DeviceDriverName); + lpDevNames->wDriverOffset = pTempPtr - pDevNamesSpace; + + pTempPtr += strlen(DeviceDriverName) + 1; + strcpy(pTempPtr, DeviceName); + lpDevNames->wDeviceOffset = pTempPtr - pDevNamesSpace; + + pTempPtr += strlen(DeviceName) + 1; + strcpy(pTempPtr, OutputPort); + lpDevNames->wOutputOffset = pTempPtr - pDevNamesSpace; + + GetDefaultPrinterA(buf, &dwBufLen); + lpDevNames->wDefault = (strcmp(buf, DeviceName) == 0) ? 1 : 0; + GlobalUnlock16(*hmem); + return TRUE; +} + + +/*********************************************************************** + * PRINTDLG_WMInitDialog [internal] + */ +static LRESULT PRINTDLG_WMInitDialog16(HWND hDlg, WPARAM wParam, PRINT_PTRA16* ptr16) +{ + PRINT_PTRA *PrintStructures = &ptr16->print32; + LPPRINTDLG16 lppd = ptr16->lpPrintDlg16; + DEVNAMES *pdn; + DEVMODEA *pdm; + char *name = NULL; + UINT comboID = (lppd->Flags & PD_PRINTSETUP) ? cmb1 : cmb4; + + /* load Collate ICONs */ + PrintStructures->hCollateIcon = + LoadIconA(COMDLG32_hInstance, "PD32_COLLATE"); + PrintStructures->hNoCollateIcon = + LoadIconA(COMDLG32_hInstance, "PD32_NOCOLLATE"); + if(PrintStructures->hCollateIcon == 0 || + PrintStructures->hNoCollateIcon == 0) { + ERR("no icon in resourcefile\n"); + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + EndDialog(hDlg, FALSE); + } + + /* load Paper Orientation ICON */ + /* FIXME: not implemented yet */ + + /* + * if lppd->Flags PD_SHOWHELP is specified, a HELPMESGSTRING message + * must be registered and the Help button must be shown. + */ + if (lppd->Flags & PD_SHOWHELP) { + if((PrintStructures->HelpMessageID = + RegisterWindowMessageA(HELPMSGSTRINGA)) == 0) { + COMDLG32_SetCommDlgExtendedError(CDERR_REGISTERMSGFAIL); + return FALSE; + } + } else + PrintStructures->HelpMessageID = 0; + + if (!(lppd->Flags & PD_PRINTSETUP)) { + /* We have a print quality combo box. What shall we do? */ + if (GetDlgItem(hDlg,cmb1)) { + char buf [20]; + + FIXME("Print quality only displaying currently.\n"); + + pdm = GlobalLock16(lppd->hDevMode); + if(pdm) { + switch (pdm->dmPrintQuality) { + case DMRES_HIGH : strcpy(buf,"High");break; + case DMRES_MEDIUM : strcpy(buf,"Medium");break; + case DMRES_LOW : strcpy(buf,"Low");break; + case DMRES_DRAFT : strcpy(buf,"Draft");break; + case 0 : strcpy(buf,"Default");break; + default : sprintf(buf,"%ddpi",pdm->dmPrintQuality);break; + } + GlobalUnlock16(lppd->hDevMode); + } else + strcpy(buf,"Default"); + SendDlgItemMessageA(hDlg,cmb1,CB_ADDSTRING,0,(LPARAM)buf); + SendDlgItemMessageA(hDlg,cmb1,CB_SETCURSEL,0,0); + EnableWindow(GetDlgItem(hDlg,cmb1),FALSE); + } + } + + /* FIXME: I allow more freedom than either Win95 or WinNT, + * which do not agree to what errors should be thrown or not + * in case nToPage or nFromPage is out-of-range. + */ + if (lppd->nMaxPage < lppd->nMinPage) + lppd->nMaxPage = lppd->nMinPage; + if (lppd->nMinPage == lppd->nMaxPage) + lppd->Flags |= PD_NOPAGENUMS; + if (lppd->nToPage < lppd->nMinPage) + lppd->nToPage = lppd->nMinPage; + if (lppd->nToPage > lppd->nMaxPage) + lppd->nToPage = lppd->nMaxPage; + if (lppd->nFromPage < lppd->nMinPage) + lppd->nFromPage = lppd->nMinPage; + if (lppd->nFromPage > lppd->nMaxPage) + lppd->nFromPage = lppd->nMaxPage; + + /* If the printer combo box is in the dialog, fill it */ + if (GetDlgItem(hDlg,comboID)) { + /* Fill Combobox + */ + pdn = GlobalLock16(lppd->hDevNames); + pdm = GlobalLock16(lppd->hDevMode); + if(pdn) + name = (char*)pdn + pdn->wDeviceOffset; + else if(pdm) + name = pdm->dmDeviceName; + PRINTDLG_SetUpPrinterListComboA(hDlg, comboID, name); + if(pdm) GlobalUnlock16(lppd->hDevMode); + if(pdn) GlobalUnlock16(lppd->hDevNames); + + /* Now find selected printer and update rest of dlg */ + name = HeapAlloc(GetProcessHeap(),0,256); + if (GetDlgItemTextA(hDlg, comboID, name, 255)) + PRINTDLG_ChangePrinterA(hDlg, name, PrintStructures); + } else { + /* else just use default printer */ + char name[200]; + DWORD dwBufLen = sizeof(name); + BOOL ret = GetDefaultPrinterA(name, &dwBufLen); + + if (ret) + PRINTDLG_ChangePrinterA(hDlg, name, PrintStructures); + else + FIXME("No default printer found, expect problems!\n"); + } + HeapFree(GetProcessHeap(),0,name); + + return TRUE; +} + +/************************************************************ + * + * PRINTDLG_Get16TemplateFrom32 [Internal] + * Generates a 16 bits template from the Wine 32 bits resource + * + */ +static HGLOBAL16 PRINTDLG_Get16TemplateFrom32(LPCSTR PrintResourceName) +{ + HRSRC hResInfo; + HGLOBAL hDlgTmpl32; + LPCVOID template32; + DWORD size; + HGLOBAL16 hGlobal16; + LPVOID template; + + if (!(hResInfo = FindResourceA(COMDLG32_hInstance, + PrintResourceName, (LPSTR)RT_DIALOG))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_FINDRESFAILURE); + return 0; + } + if (!(hDlgTmpl32 = LoadResource(COMDLG32_hInstance, hResInfo )) || + !(template32 = LockResource( hDlgTmpl32 ))) + { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return 0; + } + size = SizeofResource(COMDLG32_hInstance, hResInfo); + hGlobal16 = GlobalAlloc16(0, size); + if (!hGlobal16) + { + COMDLG32_SetCommDlgExtendedError(CDERR_MEMALLOCFAILURE); + ERR("alloc failure for %ld bytes\n", size); + return 0; + } + template = GlobalLock16(hGlobal16); + if (!template) + { + COMDLG32_SetCommDlgExtendedError(CDERR_MEMLOCKFAILURE); + ERR("global lock failure for %x handle\n", hGlobal16); + GlobalFree16(hGlobal16); + return 0; + } + ConvertDialog32To16((LPVOID)template32, size, (LPVOID)template); + GlobalUnlock16(hGlobal16); + return hGlobal16; +} + +static BOOL PRINTDLG_CreateDC16(LPPRINTDLG16 lppd) +{ + DEVNAMES *pdn = GlobalLock16(lppd->hDevNames); + DEVMODEA *pdm = GlobalLock16(lppd->hDevMode); + + if(lppd->Flags & PD_RETURNDC) { + lppd->hDC = HDC_16(CreateDCA((char*)pdn + pdn->wDriverOffset, + (char*)pdn + pdn->wDeviceOffset, + (char*)pdn + pdn->wOutputOffset, + pdm )); + } else if(lppd->Flags & PD_RETURNIC) { + lppd->hDC = HDC_16(CreateICA((char*)pdn + pdn->wDriverOffset, + (char*)pdn + pdn->wDeviceOffset, + (char*)pdn + pdn->wOutputOffset, + pdm )); + } + GlobalUnlock16(lppd->hDevNames); + GlobalUnlock16(lppd->hDevMode); + return lppd->hDC ? TRUE : FALSE; +} + +/************************************************************ + * + * PRINTDLG_GetDlgTemplate + * + */ +static HGLOBAL16 PRINTDLG_GetDlgTemplate16(PRINTDLG16 *lppd) +{ + HGLOBAL16 hDlgTmpl, hResInfo; + + if (lppd->Flags & PD_PRINTSETUP) { + if(lppd->Flags & PD_ENABLESETUPTEMPLATEHANDLE) { + hDlgTmpl = lppd->hSetupTemplate; + } else if(lppd->Flags & PD_ENABLESETUPTEMPLATE) { + hResInfo = FindResource16(lppd->hInstance, + MapSL(lppd->lpSetupTemplateName), (LPSTR)RT_DIALOG); + hDlgTmpl = LoadResource16(lppd->hInstance, hResInfo); + } else { + hDlgTmpl = PRINTDLG_Get16TemplateFrom32("PRINT32_SETUP"); + } + } else { + if(lppd->Flags & PD_ENABLEPRINTTEMPLATEHANDLE) { + hDlgTmpl = lppd->hPrintTemplate; + } else if(lppd->Flags & PD_ENABLEPRINTTEMPLATE) { + hResInfo = FindResource16(lppd->hInstance, + MapSL(lppd->lpPrintTemplateName), + (LPSTR)RT_DIALOG); + hDlgTmpl = LoadResource16(lppd->hInstance, hResInfo); + } else { + hDlgTmpl = PRINTDLG_Get16TemplateFrom32("PRINT32"); + } + } + return hDlgTmpl; +} + +/********************************************************************** + * + * 16 bit commdlg + */ + +/*********************************************************************** + * PrintDlg (COMMDLG.20) + * + * Displays the 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( + LPPRINTDLG16 lppd /* [in/out] ptr to PRINTDLG struct */ +) { + BOOL bRet = FALSE; + LPVOID ptr; + HINSTANCE16 hInst = GetWindowLongPtrW( HWND_32(lppd->hwndOwner), GWLP_HINSTANCE ); + + if(TRACE_ON(commdlg)) { + char flagstr[1000] = ""; + struct pd_flags *pflag = pd_flags; + for( ; pflag->name; pflag++) { + if(lppd->Flags & pflag->flag) + strcat(flagstr, pflag->name); + } + TRACE("(%p): hwndOwner = %08x, hDevMode = %08x, hDevNames = %08x\n" + "pp. %d-%d, min p %d, max p %d, copies %d, hinst %08x\n" + "flags %08lx (%s)\n", + lppd, lppd->hwndOwner, lppd->hDevMode, lppd->hDevNames, + lppd->nFromPage, lppd->nToPage, lppd->nMinPage, lppd->nMaxPage, + lppd->nCopies, lppd->hInstance, lppd->Flags, flagstr); + } + + if(lppd->lStructSize != sizeof(PRINTDLG16)) { + ERR("structure size (%ld/%d)\n",lppd->lStructSize,sizeof(PRINTDLG16)); + COMDLG32_SetCommDlgExtendedError(CDERR_STRUCTSIZE); + return FALSE; + } + + if(lppd->Flags & PD_RETURNDEFAULT) { + PRINTER_INFO_2A *pbuf; + DRIVER_INFO_3A *dbuf; + HANDLE hprn; + DWORD needed; + + if(lppd->hDevMode || lppd->hDevNames) { + WARN("hDevMode or hDevNames non-zero for PD_RETURNDEFAULT\n"); + COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); + return FALSE; + } + if(!PRINTDLG_OpenDefaultPrinter(&hprn)) { + WARN("Can't find default printer\n"); + COMDLG32_SetCommDlgExtendedError(PDERR_NODEFAULTPRN); + return FALSE; + } + + GetPrinterA(hprn, 2, NULL, 0, &needed); + pbuf = HeapAlloc(GetProcessHeap(), 0, needed); + GetPrinterA(hprn, 2, (LPBYTE)pbuf, needed, &needed); + GetPrinterDriverA(hprn, NULL, 3, NULL, 0, &needed); + dbuf = HeapAlloc(GetProcessHeap(),0,needed); + if (!GetPrinterDriverA(hprn, NULL, 3, (LPBYTE)dbuf, needed, &needed)) { + ERR("GetPrinterDriverA failed for %s, le %ld, fix your config!\n", + pbuf->pPrinterName,GetLastError()); + HeapFree(GetProcessHeap(), 0, dbuf); + COMDLG32_SetCommDlgExtendedError(PDERR_RETDEFFAILURE); + return FALSE; + } + ClosePrinter(hprn); + PRINTDLG_CreateDevNames16(&(lppd->hDevNames), + dbuf->pDriverPath, + pbuf->pPrinterName, + pbuf->pPortName); + lppd->hDevMode = GlobalAlloc16(GMEM_MOVEABLE,pbuf->pDevMode->dmSize+ + pbuf->pDevMode->dmDriverExtra); + ptr = GlobalLock16(lppd->hDevMode); + memcpy(ptr, pbuf->pDevMode, pbuf->pDevMode->dmSize + + pbuf->pDevMode->dmDriverExtra); + GlobalUnlock16(lppd->hDevMode); + HeapFree(GetProcessHeap(), 0, pbuf); + HeapFree(GetProcessHeap(), 0, dbuf); + bRet = TRUE; + } else { + HGLOBAL16 hDlgTmpl; + PRINT_PTRA *PrintStructures; + PRINT_PTRA16 *ptr16; + + /* load Dialog resources, + * depending on Flags indicates Print32 or Print32_setup dialog + */ + hDlgTmpl = PRINTDLG_GetDlgTemplate16(lppd); + if (!hDlgTmpl) { + COMDLG32_SetCommDlgExtendedError(CDERR_LOADRESFAILURE); + return FALSE; + } + ptr16 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PRINT_PTRA16)); + ptr16->lpPrintDlg16 = lppd; + PrintStructures = &ptr16->print32; + PrintStructures->lpPrintDlg = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(PRINTDLGA)); +#define CVAL(x) PrintStructures->lpPrintDlg->x = lppd->x; +#define MVAL(x) PrintStructures->lpPrintDlg->x = MapSL(lppd->x); + CVAL(Flags); + PrintStructures->lpPrintDlg->hwndOwner = HWND_32(lppd->hwndOwner); + PrintStructures->lpPrintDlg->hDC = HDC_32(lppd->hDC); + CVAL(nFromPage);CVAL(nToPage);CVAL(nMinPage);CVAL(nMaxPage); + CVAL(nCopies); + PrintStructures->lpPrintDlg->hInstance = HINSTANCE_32(lppd->hInstance); + CVAL(lCustData); + MVAL(lpPrintTemplateName);MVAL(lpSetupTemplateName); + /* Don't copy rest, it is 16 bit specific */ +#undef MVAL +#undef CVAL + + PrintStructures->lpDevMode = HeapAlloc(GetProcessHeap(),0,sizeof(DEVMODEA)); + + /* and create & process the dialog . + * -1 is failure, 0 is broken hwnd, everything else is ok. + */ + bRet = (0hwndOwner, + (DLGPROC16)GetProcAddress16(GetModuleHandle16("COMMDLG"),(LPCSTR)21), + (LPARAM)PrintStructures + ) + ); + if (!PrintStructures->lpPrinterInfo) bRet = FALSE; + if(bRet) { + DEVMODEA *lpdm = PrintStructures->lpDevMode, *lpdmReturn; + PRINTER_INFO_2A *pi = PrintStructures->lpPrinterInfo; + DRIVER_INFO_3A *di = PrintStructures->lpDriverInfo; + + if (lppd->hDevMode == 0) { + TRACE(" No hDevMode yet... Need to create my own\n"); + lppd->hDevMode = GlobalAlloc16(GMEM_MOVEABLE, + lpdm->dmSize + lpdm->dmDriverExtra); + } else { + WORD locks; + if((locks = (GlobalFlags16(lppd->hDevMode)&GMEM_LOCKCOUNT))) { + WARN("hDevMode has %d locks on it. Unlocking it now\n", locks); + while(locks--) { + GlobalUnlock16(lppd->hDevMode); + TRACE("Now got %d locks\n", locks); + } + } + lppd->hDevMode = GlobalReAlloc16(lppd->hDevMode, + lpdm->dmSize + lpdm->dmDriverExtra, + GMEM_MOVEABLE); + } + lpdmReturn = GlobalLock16(lppd->hDevMode); + memcpy(lpdmReturn, lpdm, lpdm->dmSize + lpdm->dmDriverExtra); + + if (lppd->hDevNames != 0) { + WORD locks; + if((locks = (GlobalFlags16(lppd->hDevNames)&GMEM_LOCKCOUNT))) { + WARN("hDevNames has %d locks on it. Unlocking it now\n", locks); + while(locks--) + GlobalUnlock16(lppd->hDevNames); + } + } + PRINTDLG_CreateDevNames16(&(lppd->hDevNames), + di->pDriverPath, + pi->pPrinterName, + pi->pPortName + ); + GlobalUnlock16(lppd->hDevMode); + } + if (!(lppd->Flags & (PD_ENABLESETUPTEMPLATEHANDLE | PD_ENABLESETUPTEMPLATE))) + GlobalFree16(hDlgTmpl); /* created from the 32 bits resource */ + HeapFree(GetProcessHeap(), 0, PrintStructures->lpDevMode); + HeapFree(GetProcessHeap(), 0, PrintStructures->lpPrinterInfo); + HeapFree(GetProcessHeap(), 0, PrintStructures->lpDriverInfo); + HeapFree(GetProcessHeap(), 0, PrintStructures); + } + if(bRet && (lppd->Flags & PD_RETURNDC || lppd->Flags & PD_RETURNIC)) + bRet = PRINTDLG_CreateDC16(lppd); + + TRACE("exit! (%d)\n", bRet); + return bRet; +} + +/*********************************************************************** + * PrintDlgProc (COMMDLG.21) + */ +BOOL16 CALLBACK PrintDlgProc16(HWND16 hDlg16, UINT16 uMsg, WPARAM16 wParam, + LPARAM lParam) +{ + HWND hDlg = HWND_32(hDlg16); + PRINT_PTRA16 *PrintStructures; + BOOL16 res = FALSE; + + if (uMsg!=WM_INITDIALOG) { + PrintStructures = (PRINT_PTRA16*)GetPropA(hDlg,"__WINE_PRINTDLGDATA"); + if (!PrintStructures) + return FALSE; + } else { + PrintStructures = (PRINT_PTRA16*) lParam; + SetPropA(hDlg,"__WINE_PRINTDLGDATA",PrintStructures); + res = PRINTDLG_WMInitDialog16(hDlg, wParam, PrintStructures); + + if(PrintStructures->lpPrintDlg16->Flags & PD_ENABLEPRINTHOOK) { + res = CallWindowProc16( + (WNDPROC16)PrintStructures->lpPrintDlg16->lpfnPrintHook, + hDlg16, uMsg, wParam, (LPARAM)PrintStructures->lpPrintDlg16 + ); + } + return res; + } + + if(PrintStructures->lpPrintDlg16->Flags & PD_ENABLEPRINTHOOK) { + res = CallWindowProc16( + (WNDPROC16)PrintStructures->lpPrintDlg16->lpfnPrintHook, + hDlg16,uMsg, wParam, lParam + ); + if(LOWORD(res)) return res; + } + + switch (uMsg) { + case WM_COMMAND: { + /* We need to map those for the 32bit window procedure, compare + * with 32Ato16 mapper in winproc.c + */ + return PRINTDLG_WMCommandA( + hDlg, + MAKEWPARAM(wParam,HIWORD(lParam)), + LOWORD(lParam), + &PrintStructures->print32 + ); + } + case WM_DESTROY: + DestroyIcon(PrintStructures->print32.hCollateIcon); + DestroyIcon(PrintStructures->print32.hNoCollateIcon); + /* FIXME: don't forget to delete the paper orientation icons here! */ + + return FALSE; + } + return res; +} + +/*********************************************************************** + * 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; +} diff --git a/reactos/lib/cpl/liccpa/liccpa.c b/reactos/lib/cpl/liccpa/liccpa.c index 7e82e3eb694..dc2440c62e1 100644 --- a/reactos/lib/cpl/liccpa/liccpa.c +++ b/reactos/lib/cpl/liccpa/liccpa.c @@ -1,127 +1,127 @@ -/* $Id: appearance.c 13406 2005-02-04 20:39:10Z weiden $ - * - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS License Manager - * FILE: lib/cpl/liccpa - * PURPOSE: License Manager GUI - * - * PROGRAMMERS: Steven Edwards (steven_ed4153@yahoo.com) - * - * NOTES: - * This application does almost nothing and its really good at it. - */ - -#include -#include -#include - -#include "resource.h" -#include "liccpa.h" - -HINSTANCE hApplet = 0; - -INT_PTR CALLBACK -DlgMainProc( - HWND hwndDlg, - UINT uMsg, - WPARAM wParam, - LPARAM lParam -) -{ - TCHAR szString[256]; - - switch(uMsg) - { - case WM_INITDIALOG: - break; - - case WM_COMMAND: - { - switch(HIWORD(wParam)) - { - case LBN_DBLCLK: - { - switch(LOWORD(wParam)) - { - } - break; - } - default: - { - switch(LOWORD(wParam)) - { - case IDC_OK: - { - break; - } - case IDC_CANCEL: - { - EndDialog(hwndDlg, IDC_CANCEL); - break; - } - } - break; - } - } - break; - } - case WM_CLOSE: - { - EndDialog(hwndDlg, IDC_CANCEL); - return TRUE; - } - } - return FALSE; -} - -LONG CALLBACK -CPlApplet( - HWND hwndCPl, - UINT uMsg, - LPARAM lParam1, - LPARAM lParam2) -{ - switch(uMsg) - { - case CPL_INIT: - { - return TRUE; - } - case CPL_GETCOUNT: - { - return 1; - } - case CPL_INQUIRE: - { - CPLINFO *CPlInfo = (CPLINFO*)lParam2; - CPlInfo->lData = 0; - CPlInfo->idIcon = IDC_CPLICON_1; - CPlInfo->idName = IDS_CPLNAME_1; - CPlInfo->idInfo = IDS_CPLDESCRIPTION_1; - break; - } - case CPL_DBLCLK: - { - DialogBoxParam(hApplet, MAKEINTRESOURCE(IDD_PROPPAGE1), hwndCPl, DlgMainProc, WM_INITDIALOG); - break; - } - } - return FALSE; -} - - -BOOL STDCALL -DllMain( - HINSTANCE hinstDLL, - DWORD dwReason, - LPVOID lpvReserved) -{ - switch(dwReason) - { - case DLL_PROCESS_ATTACH: - case DLL_THREAD_ATTACH: - hApplet = hinstDLL; - break; - } - return TRUE; -} +/* $Id: appearance.c 13406 2005-02-04 20:39:10Z weiden $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS License Manager + * FILE: lib/cpl/liccpa + * PURPOSE: License Manager GUI + * + * PROGRAMMERS: Steven Edwards (steven_ed4153@yahoo.com) + * + * NOTES: + * This application does almost nothing and its really good at it. + */ + +#include +#include +#include + +#include "resource.h" +#include "liccpa.h" + +HINSTANCE hApplet = 0; + +INT_PTR CALLBACK +DlgMainProc( + HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam +) +{ + TCHAR szString[256]; + + switch(uMsg) + { + case WM_INITDIALOG: + break; + + case WM_COMMAND: + { + switch(HIWORD(wParam)) + { + case LBN_DBLCLK: + { + switch(LOWORD(wParam)) + { + } + break; + } + default: + { + switch(LOWORD(wParam)) + { + case IDC_OK: + { + break; + } + case IDC_CANCEL: + { + EndDialog(hwndDlg, IDC_CANCEL); + break; + } + } + break; + } + } + break; + } + case WM_CLOSE: + { + EndDialog(hwndDlg, IDC_CANCEL); + return TRUE; + } + } + return FALSE; +} + +LONG CALLBACK +CPlApplet( + HWND hwndCPl, + UINT uMsg, + LPARAM lParam1, + LPARAM lParam2) +{ + switch(uMsg) + { + case CPL_INIT: + { + return TRUE; + } + case CPL_GETCOUNT: + { + return 1; + } + case CPL_INQUIRE: + { + CPLINFO *CPlInfo = (CPLINFO*)lParam2; + CPlInfo->lData = 0; + CPlInfo->idIcon = IDC_CPLICON_1; + CPlInfo->idName = IDS_CPLNAME_1; + CPlInfo->idInfo = IDS_CPLDESCRIPTION_1; + break; + } + case CPL_DBLCLK: + { + DialogBoxParam(hApplet, MAKEINTRESOURCE(IDD_PROPPAGE1), hwndCPl, DlgMainProc, WM_INITDIALOG); + break; + } + } + return FALSE; +} + + +BOOL STDCALL +DllMain( + HINSTANCE hinstDLL, + DWORD dwReason, + LPVOID lpvReserved) +{ + switch(dwReason) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + hApplet = hinstDLL; + break; + } + return TRUE; +} diff --git a/reactos/lib/cpl/liccpa/liccpa.h b/reactos/lib/cpl/liccpa/liccpa.h index b98d0a95882..817bd4fc80a 100644 --- a/reactos/lib/cpl/liccpa/liccpa.h +++ b/reactos/lib/cpl/liccpa/liccpa.h @@ -1,16 +1,16 @@ -#ifndef __CPL_SAMPLE_H -#define __CPL_SAMPLE_H - -typedef struct -{ - int idIcon; - int idName; - int idDescription; - APPLET_PROC AppletProc; -} APPLET, *PAPPLET; - -extern HINSTANCE hApplet; - -#endif /* __CPL_SAMPLE_H */ - -/* EOF */ +#ifndef __CPL_SAMPLE_H +#define __CPL_SAMPLE_H + +typedef struct +{ + int idIcon; + int idName; + int idDescription; + APPLET_PROC AppletProc; +} APPLET, *PAPPLET; + +extern HINSTANCE hApplet; + +#endif /* __CPL_SAMPLE_H */ + +/* EOF */ diff --git a/reactos/lib/cpl/liccpa/resource.h b/reactos/lib/cpl/liccpa/resource.h index ee937b15b86..917dc15c69f 100644 --- a/reactos/lib/cpl/liccpa/resource.h +++ b/reactos/lib/cpl/liccpa/resource.h @@ -1,18 +1,18 @@ -#ifndef __CPL_RESOURCE_H -#define __CPL_RESOURCE_H - -/* ids */ - -#define IDC_CPLICON_1 1 -#define IDD_PROPPAGE1 100 -#define IDS_CPLNAME_1 1001 -#define IDS_CPLDESCRIPTION_1 2001 -#define IDS_REACTOS 2002 - -#define IDC_LICENSE 106 -#define IDC_OK 107 -#define IDC_CANCEL 108 - -#endif /* __CPL_RESOURCE_H */ - -/* EOF */ +#ifndef __CPL_RESOURCE_H +#define __CPL_RESOURCE_H + +/* ids */ + +#define IDC_CPLICON_1 1 +#define IDD_PROPPAGE1 100 +#define IDS_CPLNAME_1 1001 +#define IDS_CPLDESCRIPTION_1 2001 +#define IDS_REACTOS 2002 + +#define IDC_LICENSE 106 +#define IDC_OK 107 +#define IDC_CANCEL 108 + +#endif /* __CPL_RESOURCE_H */ + +/* EOF */ diff --git a/reactos/lib/crt/include/internal/math.h b/reactos/lib/crt/include/internal/math.h index 1102524059a..c08defdb772 100644 --- a/reactos/lib/crt/include/internal/math.h +++ b/reactos/lib/crt/include/internal/math.h @@ -1,10 +1,10 @@ - -#ifndef __CRT_INTERNAL_MATH_H -#define __CRT_INTERNAL_MATH_H - - -int _isinf (double); /* not exported */ -int _isnanl (long double); /* not exported */ -int _isinfl (long double); /* not exported */ - -#endif + +#ifndef __CRT_INTERNAL_MATH_H +#define __CRT_INTERNAL_MATH_H + + +int _isinf (double); /* not exported */ +int _isnanl (long double); /* not exported */ +int _isinfl (long double); /* not exported */ + +#endif diff --git a/reactos/lib/crt/include/internal/mbstring.h b/reactos/lib/crt/include/internal/mbstring.h index f5f167d639e..5025b441899 100644 --- a/reactos/lib/crt/include/internal/mbstring.h +++ b/reactos/lib/crt/include/internal/mbstring.h @@ -1,20 +1,20 @@ -#ifndef __CRT_INTERNAL_MBSTRING_H -#define __CRT_INTERNAL_MBSTRING_H - -#define _KNJ_M ((char)0x01) /* Non-punctuation of Kana-set */ -#define _KNJ_P ((char)0x02) /* Punctuation of Kana-set */ -#define _KNJ_1 ((char)0x04) /* Legal 1st byte of double byte stream */ -#define _KNJ_2 ((char)0x08) /* Legal 2nd btye of double byte stream */ - - -#define ___ 0 -#define _1_ _KNJ_1 /* Legal 1st byte of double byte code */ -#define __2 _KNJ_2 /* Legal 2nd byte of double byte code */ -#define _M_ _KNJ_M /* Non-puntuation in Kana-set */ -#define _P_ _KNJ_P /* Punctuation of Kana-set */ -#define _12 (_1_|__2) -#define _M2 (_M_|__2) -#define _P2 (_P_|__2) - - -#endif +#ifndef __CRT_INTERNAL_MBSTRING_H +#define __CRT_INTERNAL_MBSTRING_H + +#define _KNJ_M ((char)0x01) /* Non-punctuation of Kana-set */ +#define _KNJ_P ((char)0x02) /* Punctuation of Kana-set */ +#define _KNJ_1 ((char)0x04) /* Legal 1st byte of double byte stream */ +#define _KNJ_2 ((char)0x08) /* Legal 2nd btye of double byte stream */ + + +#define ___ 0 +#define _1_ _KNJ_1 /* Legal 1st byte of double byte code */ +#define __2 _KNJ_2 /* Legal 2nd byte of double byte code */ +#define _M_ _KNJ_M /* Non-puntuation in Kana-set */ +#define _P_ _KNJ_P /* Punctuation of Kana-set */ +#define _12 (_1_|__2) +#define _M2 (_M_|__2) +#define _P2 (_P_|__2) + + +#endif diff --git a/reactos/lib/crt/precomp.h b/reactos/lib/crt/precomp.h index f6d254553a6..776a87ce358 100644 --- a/reactos/lib/crt/precomp.h +++ b/reactos/lib/crt/precomp.h @@ -1 +1 @@ -#include +#include diff --git a/reactos/lib/crt/process/wprocess.c b/reactos/lib/crt/process/wprocess.c index 9bee2c8df4e..8b7a08a4441 100644 --- a/reactos/lib/crt/process/wprocess.c +++ b/reactos/lib/crt/process/wprocess.c @@ -1,4 +1,4 @@ -#define _UNICODE -#define UNICODE - -#include "process.c" +#define _UNICODE +#define UNICODE + +#include "process.c" diff --git a/reactos/lib/crt/signal/xcptinfo.c b/reactos/lib/crt/signal/xcptinfo.c index d6c9894e6ca..0d14df09afb 100644 --- a/reactos/lib/crt/signal/xcptinfo.c +++ b/reactos/lib/crt/signal/xcptinfo.c @@ -1,9 +1,9 @@ -#include - -/* - * @unimplemented - */ -void **__pxcptinfoptrs (void) -{ - return NULL; -} +#include + +/* + * @unimplemented + */ +void **__pxcptinfoptrs (void) +{ + return NULL; +} diff --git a/reactos/lib/crt/stdio/fputws.c b/reactos/lib/crt/stdio/fputws.c index e024d58220c..06a0a2631f0 100644 --- a/reactos/lib/crt/stdio/fputws.c +++ b/reactos/lib/crt/stdio/fputws.c @@ -1,5 +1,5 @@ - -#define UNICODE -#define _UNICODE - -#include "fputs.c" + +#define UNICODE +#define _UNICODE + +#include "fputs.c" diff --git a/reactos/lib/crt/stdio/fwprintf.c b/reactos/lib/crt/stdio/fwprintf.c index dd273a26bba..e25b3bcc387 100644 --- a/reactos/lib/crt/stdio/fwprintf.c +++ b/reactos/lib/crt/stdio/fwprintf.c @@ -1,4 +1,4 @@ -#define UNICODE -#define _UNICODE - -#include "fprintf.c" +#define UNICODE +#define _UNICODE + +#include "fprintf.c" diff --git a/reactos/lib/crt/stdio/putwchar.c b/reactos/lib/crt/stdio/putwchar.c index cdf1386ce75..e6f31b8add2 100644 --- a/reactos/lib/crt/stdio/putwchar.c +++ b/reactos/lib/crt/stdio/putwchar.c @@ -1,4 +1,4 @@ -#define UNICODE -#define _UNICODE - -#include "putchar.c" +#define UNICODE +#define _UNICODE + +#include "putchar.c" diff --git a/reactos/lib/crt/stdio/swprintf.c b/reactos/lib/crt/stdio/swprintf.c index 16a19269ec5..f877189ed82 100644 --- a/reactos/lib/crt/stdio/swprintf.c +++ b/reactos/lib/crt/stdio/swprintf.c @@ -1,60 +1,60 @@ -/* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */ - -/* Copyright (C) 1991, 1995 Free Software Foundation, Inc. -This file is part of the GNU C Library. - -The GNU C Library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -The GNU C 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 -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with the GNU C Library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. */ - -#define UNICODE -#define _UNICODE -#include -#include -#include -#include -#include -#include - -#undef sprintf -#undef wsprintf - -int -crt_swprintf(_TCHAR *str, const _TCHAR *fmt, ...) -{ - va_list arg; - int done; - - va_start (arg, fmt); - done = _vstprintf (str, fmt, arg); - va_end (arg); - return done; -} - - -/* Write formatted output into S, according to the format - string FORMAT, writing no more than MAXLEN characters. */ -/* VARARGS3 */ -int -crt__snwprintf (_TCHAR *s, size_t maxlen,const _TCHAR *format, ...) -{ - va_list arg; - int done; - - va_start (arg, format); - done = _vsntprintf(s, maxlen, format, arg); - va_end (arg); - - return done; -} +/* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */ + +/* Copyright (C) 1991, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C 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 +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#define UNICODE +#define _UNICODE +#include +#include +#include +#include +#include +#include + +#undef sprintf +#undef wsprintf + +int +crt_swprintf(_TCHAR *str, const _TCHAR *fmt, ...) +{ + va_list arg; + int done; + + va_start (arg, fmt); + done = _vstprintf (str, fmt, arg); + va_end (arg); + return done; +} + + +/* Write formatted output into S, according to the format + string FORMAT, writing no more than MAXLEN characters. */ +/* VARARGS3 */ +int +crt__snwprintf (_TCHAR *s, size_t maxlen,const _TCHAR *format, ...) +{ + va_list arg; + int done; + + va_start (arg, format); + done = _vsntprintf(s, maxlen, format, arg); + va_end (arg); + + return done; +} diff --git a/reactos/lib/crt/stdio/ungetwc.c b/reactos/lib/crt/stdio/ungetwc.c index 1ff851fca98..fe8f7fd1e9c 100644 --- a/reactos/lib/crt/stdio/ungetwc.c +++ b/reactos/lib/crt/stdio/ungetwc.c @@ -1,4 +1,4 @@ -#define UNICODE -#define _UNICODE - -#include "ungetc.c" +#define UNICODE +#define _UNICODE + +#include "ungetc.c" diff --git a/reactos/lib/crt/stdio/vswprintf.c b/reactos/lib/crt/stdio/vswprintf.c index 646e937fee7..94da15ff9e7 100644 --- a/reactos/lib/crt/stdio/vswprintf.c +++ b/reactos/lib/crt/stdio/vswprintf.c @@ -1,4 +1,4 @@ -#define UNICODE -#define _UNICODE - -#include "vsprintf.c" +#define UNICODE +#define _UNICODE + +#include "vsprintf.c" diff --git a/reactos/lib/crt/stdio/vwprintf.c b/reactos/lib/crt/stdio/vwprintf.c index 80e54674f88..c578db04da1 100644 --- a/reactos/lib/crt/stdio/vwprintf.c +++ b/reactos/lib/crt/stdio/vwprintf.c @@ -1,5 +1,5 @@ -#define _UNICODE -#define UNICODE - -#include "vprintf.c" - +#define _UNICODE +#define UNICODE + +#include "vprintf.c" + diff --git a/reactos/lib/crt/stdio/wfopen.c b/reactos/lib/crt/stdio/wfopen.c index 1e134f7a1a3..f0175d84959 100644 --- a/reactos/lib/crt/stdio/wfopen.c +++ b/reactos/lib/crt/stdio/wfopen.c @@ -1,4 +1,4 @@ -#define UNICODE -#define _UNICODE - -#include "fopen.c" +#define UNICODE +#define _UNICODE + +#include "fopen.c" diff --git a/reactos/lib/crt/stdio/wfreopen.c b/reactos/lib/crt/stdio/wfreopen.c index 933968368c0..0453bfb6905 100644 --- a/reactos/lib/crt/stdio/wfreopen.c +++ b/reactos/lib/crt/stdio/wfreopen.c @@ -1,6 +1,6 @@ - -#define UNICODE -#define _UNICODE - -#include "freopen.c" - + +#define UNICODE +#define _UNICODE + +#include "freopen.c" + diff --git a/reactos/lib/crt/stdio/wfsopen.c b/reactos/lib/crt/stdio/wfsopen.c index 90020ae9f1d..8a3266cb4ca 100644 --- a/reactos/lib/crt/stdio/wfsopen.c +++ b/reactos/lib/crt/stdio/wfsopen.c @@ -1,5 +1,5 @@ -#define _UNICODE -#define UNICODE - -#include "fsopen.c" - +#define _UNICODE +#define UNICODE + +#include "fsopen.c" + diff --git a/reactos/lib/crt/stdio/wpopen.c b/reactos/lib/crt/stdio/wpopen.c index bf1d111475f..900d1d8bb8f 100644 --- a/reactos/lib/crt/stdio/wpopen.c +++ b/reactos/lib/crt/stdio/wpopen.c @@ -1,5 +1,5 @@ -#define _UNICODE -#define UNICODE - -#include "popen.c" - +#define _UNICODE +#define UNICODE + +#include "popen.c" + diff --git a/reactos/lib/crt/stdio/wprintf.c b/reactos/lib/crt/stdio/wprintf.c index 5bf927f20e8..65419d3339d 100644 --- a/reactos/lib/crt/stdio/wprintf.c +++ b/reactos/lib/crt/stdio/wprintf.c @@ -1,5 +1,5 @@ -#define _UNICODE -#define UNICODE - -#include "printf.c" - +#define _UNICODE +#define UNICODE + +#include "printf.c" + diff --git a/reactos/lib/crt/stdio/wremove.c b/reactos/lib/crt/stdio/wremove.c index 959802a67a1..ce56997314c 100644 --- a/reactos/lib/crt/stdio/wremove.c +++ b/reactos/lib/crt/stdio/wremove.c @@ -1,4 +1,4 @@ -#define UNICODE -#define _UNICODE - -#include "remove.c" +#define UNICODE +#define _UNICODE + +#include "remove.c" diff --git a/reactos/lib/crt/stdlib/wtol.c b/reactos/lib/crt/stdlib/wtol.c index e47cbbde33f..1d56c7d7076 100644 --- a/reactos/lib/crt/stdlib/wtol.c +++ b/reactos/lib/crt/stdlib/wtol.c @@ -1,6 +1,6 @@ - -#define _UNICODE -#define UNICODE - -#include "atol.c" - + +#define _UNICODE +#define UNICODE + +#include "atol.c" + diff --git a/reactos/lib/crt/sys_stat/systime.c b/reactos/lib/crt/sys_stat/systime.c index 680270d31e3..c9de9b2e905 100644 --- a/reactos/lib/crt/sys_stat/systime.c +++ b/reactos/lib/crt/sys_stat/systime.c @@ -1,70 +1,70 @@ -#include "precomp.h" -#include - - -int month[12] = { 31,28,31,30,31,30,31,31,30,31,30,31}; - -/* - * @unimplemented - */ -unsigned int _getsystime(struct tm* tp) -{ - SYSTEMTIME Time; - int i; - - GetLocalTime(&Time); - - tp->tm_year = Time.wYear - 1900; - tp->tm_mon = Time.wMonth - 1; - tp->tm_wday = Time.wDayOfWeek; - tp->tm_mday = Time.wDay; - tp->tm_hour = Time.wHour; - tp->tm_min = Time.wMinute; - tp->tm_sec = Time.wSecond; - - tp->tm_isdst = -1; - - //FIXME GetTimeZoneInformation currently not in kernel32 - - //TimeZoneId = GetTimeZoneInformation(&TimeZoneInformation ); - //if ( TimeZoneId == TIME_ZONE_ID_DAYLIGHT ) { - // tp->tm_isdst = 1; - //} - //else - // tp->tm_isdst = 0; - - if (tp->tm_year % 4 == 0) { - if (tp->tm_year % 100 != 0) - tp->tm_yday = 1; - else if ((tp->tm_year-100) % 1000 == 0) - tp->tm_yday = 1; - } - - for (i = 0; i <= tp->tm_mon; i++) - tp->tm_yday += month[i]; - - return Time.wMilliseconds; -} - - -/* - * @implemented - */ -unsigned int _setsystime(struct tm* tp, unsigned int ms) -{ - SYSTEMTIME Time; - - Time.wYear = tp->tm_year + 1900; - Time.wMonth = tp->tm_mon + 1; - Time.wDayOfWeek = tp->tm_wday; - Time.wDay = tp->tm_mday; - Time.wHour = tp->tm_hour; - Time.wMinute = tp->tm_min; - Time.wSecond = tp->tm_sec; - Time.wMilliseconds = ms; - - if (!SetLocalTime(&Time)) - return -1; - - return 0; -} +#include "precomp.h" +#include + + +int month[12] = { 31,28,31,30,31,30,31,31,30,31,30,31}; + +/* + * @unimplemented + */ +unsigned int _getsystime(struct tm* tp) +{ + SYSTEMTIME Time; + int i; + + GetLocalTime(&Time); + + tp->tm_year = Time.wYear - 1900; + tp->tm_mon = Time.wMonth - 1; + tp->tm_wday = Time.wDayOfWeek; + tp->tm_mday = Time.wDay; + tp->tm_hour = Time.wHour; + tp->tm_min = Time.wMinute; + tp->tm_sec = Time.wSecond; + + tp->tm_isdst = -1; + + //FIXME GetTimeZoneInformation currently not in kernel32 + + //TimeZoneId = GetTimeZoneInformation(&TimeZoneInformation ); + //if ( TimeZoneId == TIME_ZONE_ID_DAYLIGHT ) { + // tp->tm_isdst = 1; + //} + //else + // tp->tm_isdst = 0; + + if (tp->tm_year % 4 == 0) { + if (tp->tm_year % 100 != 0) + tp->tm_yday = 1; + else if ((tp->tm_year-100) % 1000 == 0) + tp->tm_yday = 1; + } + + for (i = 0; i <= tp->tm_mon; i++) + tp->tm_yday += month[i]; + + return Time.wMilliseconds; +} + + +/* + * @implemented + */ +unsigned int _setsystime(struct tm* tp, unsigned int ms) +{ + SYSTEMTIME Time; + + Time.wYear = tp->tm_year + 1900; + Time.wMonth = tp->tm_mon + 1; + Time.wDayOfWeek = tp->tm_wday; + Time.wDay = tp->tm_mday; + Time.wHour = tp->tm_hour; + Time.wMinute = tp->tm_min; + Time.wSecond = tp->tm_sec; + Time.wMilliseconds = ms; + + if (!SetLocalTime(&Time)) + return -1; + + return 0; +} diff --git a/reactos/lib/crt/wine/scanf.c b/reactos/lib/crt/wine/scanf.c index d2c5f7ce1df..36d76db7f42 100644 --- a/reactos/lib/crt/wine/scanf.c +++ b/reactos/lib/crt/wine/scanf.c @@ -1,211 +1,211 @@ -/* - * general implementation of scanf used by scanf, sscanf, fscanf, - * _cscanf, wscanf, swscanf and fwscanf - * - * Copyright 1996,1998 Marcus Meissner - * Copyright 1996 Jukka Iivonen - * Copyright 1997,2000 Uwe Bonnes - * Copyright 2000 Jon Griffiths - * Copyright 2002 Daniel Gudbjartsson - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -/* -#include - -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "winternl.h" -#include "msvcrt.h" -*/ - -#include -#include -#include -#include -#include -#include - -#define NTOS_MODE_USER -#include - -#define NDEBUG -#include - -//#include "wine/debug.h" - -#define WARN DPRINT1 - -//WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); - -extern FILE _iob[]; - -/* helper function for *scanf. Returns the value of character c in the - * given base, or -1 if the given character is not a digit of the base. - */ -static int char2digit(char c, int base) { - if ((c>='0') && (c<='9') && (c<='0'+base-1)) return (c-'0'); - if (base<=10) return -1; - if ((c>='A') && (c<='Z') && (c<='A'+base-11)) return (c-'A'+10); - if ((c>='a') && (c<='z') && (c<='a'+base-11)) return (c-'a'+10); - return -1; -} - -/* helper function for *wscanf. Returns the value of character c in the - * given base, or -1 if the given character is not a digit of the base. - */ -static int wchar2digit(wchar_t c, int base) { - if ((c>=L'0') && (c<=L'9') && (c<=L'0'+base-1)) return (c-L'0'); - if (base<=10) return -1; - if ((c>=L'A') && (c<=L'Z') && (c<=L'A'+base-11)) return (c-L'A'+10); - if ((c>=L'a') && (c<=L'z') && (c<=L'a'+base-11)) return (c-L'a'+10); - return -1; -} - -/* vfscanf */ -#undef WIDE_SCANF -#undef CONSOLE -#undef STRING -#include "scanf.h" - -/* vfwscanf */ -#define WIDE_SCANF 1 -#undef CONSOLE -#undef STRING -#include "scanf.h" - -/* vsscanf */ -#undef WIDE_SCANF -#undef CONSOLE -#define STRING 1 -#include "scanf.h" - -/* vswscanf */ -#define WIDE_SCANF 1 -#undef CONSOLE -#define STRING 1 -#include "scanf.h" - -/* vcscanf */ -#undef WIDE_SCANF -#define CONSOLE 1 -#undef STRING -#include "scanf.h" - - -/********************************************************************* - * fscanf (MSVCRT.@) - */ -int fscanf(FILE *file, const char *format, ...) -{ - va_list valist; - int res; - - va_start(valist, format); - res = vfscanf(file, format, valist); - va_end(valist); - return res; -} - -/********************************************************************* - * scanf (MSVCRT.@) - */ -int scanf(const char *format, ...) -{ - va_list valist; - int res; - - va_start(valist, format); - res = vfscanf(stdin, format, valist); - va_end(valist); - return res; -} - -/********************************************************************* - * fwscanf (MSVCRT.@) - */ -int fwscanf(FILE *file, const wchar_t *format, ...) -{ - va_list valist; - int res; - - va_start(valist, format); - res = vfwscanf(file, format, valist); - va_end(valist); - return res; -} - - -/********************************************************************* - * wscanf (MSVCRT.@) - */ -int wscanf(const wchar_t *format, ...) -{ - va_list valist; - int res; - - va_start(valist, format); - res = vfwscanf(stdin, format, valist); - va_end(valist); - return res; -} - - -/********************************************************************* - * sscanf (MSVCRT.@) - */ -int crt_sscanf(const char *str, const char *format, ...) -{ - va_list valist; - int res; - - va_start(valist, format); - res = vsscanf(str, format, valist); - va_end(valist); - return res; -} - - -/********************************************************************* - * swscanf (MSVCRT.@) - */ -int swscanf(const wchar_t *str, const wchar_t *format, ...) -{ - va_list valist; - int res; - - va_start(valist, format); - res = vswscanf(str, format, valist); - va_end(valist); - return res; -} - - -/********************************************************************* - * _cscanf (MSVCRT.@) - */ -int _cscanf(/*const*/ char *format, ...) -{ - va_list valist; - int res; - - va_start(valist, format); - res = vcscanf(format, valist); - va_end(valist); - return res; -} +/* + * general implementation of scanf used by scanf, sscanf, fscanf, + * _cscanf, wscanf, swscanf and fwscanf + * + * Copyright 1996,1998 Marcus Meissner + * Copyright 1996 Jukka Iivonen + * Copyright 1997,2000 Uwe Bonnes + * Copyright 2000 Jon Griffiths + * Copyright 2002 Daniel Gudbjartsson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* +#include + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winternl.h" +#include "msvcrt.h" +*/ + +#include +#include +#include +#include +#include +#include + +#define NTOS_MODE_USER +#include + +#define NDEBUG +#include + +//#include "wine/debug.h" + +#define WARN DPRINT1 + +//WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); + +extern FILE _iob[]; + +/* helper function for *scanf. Returns the value of character c in the + * given base, or -1 if the given character is not a digit of the base. + */ +static int char2digit(char c, int base) { + if ((c>='0') && (c<='9') && (c<='0'+base-1)) return (c-'0'); + if (base<=10) return -1; + if ((c>='A') && (c<='Z') && (c<='A'+base-11)) return (c-'A'+10); + if ((c>='a') && (c<='z') && (c<='a'+base-11)) return (c-'a'+10); + return -1; +} + +/* helper function for *wscanf. Returns the value of character c in the + * given base, or -1 if the given character is not a digit of the base. + */ +static int wchar2digit(wchar_t c, int base) { + if ((c>=L'0') && (c<=L'9') && (c<=L'0'+base-1)) return (c-L'0'); + if (base<=10) return -1; + if ((c>=L'A') && (c<=L'Z') && (c<=L'A'+base-11)) return (c-L'A'+10); + if ((c>=L'a') && (c<=L'z') && (c<=L'a'+base-11)) return (c-L'a'+10); + return -1; +} + +/* vfscanf */ +#undef WIDE_SCANF +#undef CONSOLE +#undef STRING +#include "scanf.h" + +/* vfwscanf */ +#define WIDE_SCANF 1 +#undef CONSOLE +#undef STRING +#include "scanf.h" + +/* vsscanf */ +#undef WIDE_SCANF +#undef CONSOLE +#define STRING 1 +#include "scanf.h" + +/* vswscanf */ +#define WIDE_SCANF 1 +#undef CONSOLE +#define STRING 1 +#include "scanf.h" + +/* vcscanf */ +#undef WIDE_SCANF +#define CONSOLE 1 +#undef STRING +#include "scanf.h" + + +/********************************************************************* + * fscanf (MSVCRT.@) + */ +int fscanf(FILE *file, const char *format, ...) +{ + va_list valist; + int res; + + va_start(valist, format); + res = vfscanf(file, format, valist); + va_end(valist); + return res; +} + +/********************************************************************* + * scanf (MSVCRT.@) + */ +int scanf(const char *format, ...) +{ + va_list valist; + int res; + + va_start(valist, format); + res = vfscanf(stdin, format, valist); + va_end(valist); + return res; +} + +/********************************************************************* + * fwscanf (MSVCRT.@) + */ +int fwscanf(FILE *file, const wchar_t *format, ...) +{ + va_list valist; + int res; + + va_start(valist, format); + res = vfwscanf(file, format, valist); + va_end(valist); + return res; +} + + +/********************************************************************* + * wscanf (MSVCRT.@) + */ +int wscanf(const wchar_t *format, ...) +{ + va_list valist; + int res; + + va_start(valist, format); + res = vfwscanf(stdin, format, valist); + va_end(valist); + return res; +} + + +/********************************************************************* + * sscanf (MSVCRT.@) + */ +int crt_sscanf(const char *str, const char *format, ...) +{ + va_list valist; + int res; + + va_start(valist, format); + res = vsscanf(str, format, valist); + va_end(valist); + return res; +} + + +/********************************************************************* + * swscanf (MSVCRT.@) + */ +int swscanf(const wchar_t *str, const wchar_t *format, ...) +{ + va_list valist; + int res; + + va_start(valist, format); + res = vswscanf(str, format, valist); + va_end(valist); + return res; +} + + +/********************************************************************* + * _cscanf (MSVCRT.@) + */ +int _cscanf(/*const*/ char *format, ...) +{ + va_list valist; + int res; + + va_start(valist, format); + res = vcscanf(format, valist); + va_end(valist); + return res; +} diff --git a/reactos/lib/crt/wine/scanf.h b/reactos/lib/crt/wine/scanf.h index 6bffbdd4a85..e73719a437c 100644 --- a/reactos/lib/crt/wine/scanf.h +++ b/reactos/lib/crt/wine/scanf.h @@ -1,560 +1,560 @@ -/* - * general implementation of scanf used by scanf, sscanf, fscanf, - * _cscanf, wscanf, swscanf and fwscanf - * - * Copyright 1996,1998 Marcus Meissner - * Copyright 1996 Jukka Iivonen - * Copyright 1997,2000, 2003 Uwe Bonnes - * Copyright 2000 Jon Griffiths - * Copyright 2002 Daniel Gudbjartsson - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef WIDE_SCANF -#define _CHAR_ wchar_t -#define _EOF_ WEOF -#define _EOF_RET WEOF -#define _ISSPACE_(c) iswspace(c) -#define _ISDIGIT_(c) iswdigit(c) -#define _WIDE2SUPPORTED_(c) c /* No conversion needed (wide to wide) */ -#define _CHAR2SUPPORTED_(c) c /* FIXME: convert char to wide char */ -#define _CHAR2DIGIT_(c, base) wchar2digit((c), (base)) -#define _BITMAPSIZE_ 256*256 -#else /* WIDE_SCANF */ -#define _CHAR_ char -#define _EOF_ EOF -#define _EOF_RET EOF -#define _ISSPACE_(c) isspace(c) -#define _ISDIGIT_(c) isdigit(c) -#define _WIDE2SUPPORTED_(c) c /* FIXME: convert wide char to char */ -#define _CHAR2SUPPORTED_(c) c /* No conversion needed (char to char) */ -#define _CHAR2DIGIT_(c, base) char2digit((c), (base)) -#define _BITMAPSIZE_ 256 -#endif /* WIDE_SCANF */ - -#ifdef CONSOLE -#define _GETC_(file) (consumed++, _getch()) -#define _UNGETC_(nch, file) do { _ungetch(nch); consumed--; } while(0) -#define _FUNCTION_ int vcscanf(const char *format, va_list ap) -#else -#ifdef STRING -#undef _EOF_ -#define _EOF_ 0 -#define _GETC_(file) (consumed++, *file++) -#define _UNGETC_(nch, file) do { file--; consumed--; } while(0) -#ifdef WIDE_SCANF -#define _FUNCTION_ int vswscanf(const wchar_t *file, const wchar_t *format, va_list ap) -#else /* WIDE_SCANF */ -#define _FUNCTION_ int vsscanf(const char *file, const char *format, va_list ap) -#endif /* WIDE_SCANF */ -#else /* STRING */ -#ifdef WIDE_SCANF -#define _GETC_(file) (consumed++, fgetwc(file)) -#define _UNGETC_(nch, file) do { ungetwc(nch, file); consumed--; } while(0) -#define _FUNCTION_ int vfwscanf(FILE* file, const wchar_t *format, va_list ap) -#else /* WIDE_SCANF */ -#define _GETC_(file) (consumed++, fgetc(file)) -#define _UNGETC_(nch, file) do { ungetc(nch, file); consumed--; } while(0) -#define _FUNCTION_ int vfscanf(FILE* file, const char *format, va_list ap) -#endif /* WIDE_SCANF */ -#endif /* STRING */ -#endif /* CONSOLE */ - -/********************************************************************* - * Implemented based on - * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_crt_format_specification_fields_.2d_.scanf_and_wscanf_functions.asp - * Extended by C. Scott Ananian to handle - * more types of format spec. - */ -_FUNCTION_ { - int rd = 0, consumed = 0; - int nch; - if (!*format) return 0; -#ifndef WIDE_SCANF -#ifdef CONSOLE - TRACE("(%s): \n", debugstr_a(format)); -#else /* CONSOLE */ -#ifdef STRING - TRACE("%s (%s)\n", file, debugstr_a(format)); -#else /* STRING */ - TRACE("%p (%s)\n", file, debugstr_a(format)); -#endif /* STRING */ -#endif /* CONSOLE */ -#endif /* WIDE_SCANF */ - nch = _GETC_(file); - if (nch == _EOF_) return _EOF_RET; - - while (*format) { - /* a whitespace character in the format string causes scanf to read, - * but not store, all consecutive white-space characters in the input - * up to the next non-white-space character. One white space character - * in the input matches any number (including zero) and combination of - * white-space characters in the input. */ - if (_ISSPACE_(*format)) { - /* skip whitespace */ - while ((nch!=_EOF_) && _ISSPACE_(nch)) - nch = _GETC_(file); - } - /* a format specification causes scanf to read and convert characters - * in the input into values of a specified type. The value is assigned - * to an argument in the argument list. Format specifications have - * the form %[*][width][{h | l | I64 | L}]type */ - else if (*format == '%') { - int st = 0; int suppress = 0; int width = 0; - int base, number_signed; - int h_prefix = 0; - int l_prefix = 0; - int L_prefix = 0; - int w_prefix = 0; - int prefix_finished = 0; - int I64_prefix = 0; - format++; - /* look for leading asterisk, which means 'suppress assignment of - * this field'. */ - if (*format=='*') { - format++; - suppress=1; - } - /* look for width specification */ - while (_ISDIGIT_(*format)) { - width*=10; - width+=*format++ - '0'; - } - if (width==0) width=-1; /* no width spec seen */ - /* read prefix (if any) */ - while (!prefix_finished) { - switch(*format) { - case 'h': h_prefix = 1; break; - case 'l': l_prefix = 1; break; - case 'w': w_prefix = 1; break; - case 'L': L_prefix = 1; break; - case 'I': - if (*(format + 1) == '6' && - *(format + 2) == '4') { - I64_prefix = 1; - format += 2; - } - break; - default: - prefix_finished = 1; - } - if (!prefix_finished) format++; - } - /* read type */ - switch(*format) { - case 'x': - case 'X': /* hexadecimal integer. */ - base = 16; number_signed = 0; - goto number; - case 'o': /* octal integer */ - base = 8; number_signed = 0; - goto number; - case 'u': /* unsigned decimal integer */ - base = 10; number_signed = 0; - goto number; - case 'd': /* signed decimal integer */ - base = 10; number_signed = 1; - goto number; - case 'i': /* generic integer */ - base = 10; number_signed = 1; - number: { - /* read an integer */ - ULONGLONG cur = 0; - int negative = 0; - int seendigit=0; - /* skip initial whitespace */ - while ((nch!=_EOF_) && _ISSPACE_(nch)) - nch = _GETC_(file); - /* get sign */ - if (number_signed && (nch == '-' || - nch == '+')) { - negative = (nch=='-'); - nch = _GETC_(file); - if (width>0) width--; - } - /* look for leading indication of base */ - if (width!=0 && nch == '0') { - nch = _GETC_(file); - if (width>0) width--; - seendigit=1; - if (width!=0 && (nch=='x' || nch=='X')) { - if (base==0) - base=16; - if (base==16) { - nch = _GETC_(file); - if (width>0) width--; - seendigit=0; - } - } else if (base==0) - base = 8; - } - /* throw away leading zeros */ - while (width!=0 && nch=='0') { - nch = _GETC_(file); - if (width>0) width--; - seendigit=1; - } - if (width!=0 && _CHAR2DIGIT_(nch, base)!=-1) { - cur = _CHAR2DIGIT_(nch, base); - nch = _GETC_(file); - if (width>0) width--; - seendigit=1; - } - /* read until no more digits */ - while (width!=0 && (nch!=_EOF_) && _CHAR2DIGIT_(nch, base)!=-1) { - cur = cur*base + _CHAR2DIGIT_(nch, base); - nch = _GETC_(file); - if (width>0) width--; - seendigit=1; - } - /* okay, done! */ - if (!seendigit) break; /* not a valid number */ - st = 1; - if (!suppress) { -#define _SET_NUMBER_(type) *va_arg(ap, type*) = negative ? -cur : cur - if (number_signed) { - if (I64_prefix) _SET_NUMBER_(LONGLONG); - else if (l_prefix) _SET_NUMBER_(long int); - else if (h_prefix) _SET_NUMBER_(short int); - else _SET_NUMBER_(int); - } else { - if (negative) { - WARN("Dropping sign in reading a negative number into an unsigned value"); - negative = 0; - } - if (I64_prefix) _SET_NUMBER_(ULONGLONG); - else if (l_prefix) _SET_NUMBER_(unsigned long int); - else if (h_prefix) - _SET_NUMBER_(unsigned short int); - else _SET_NUMBER_(unsigned int); - } - } - } - break; - case 'e': - case 'E': - case 'f': - case 'g': - case 'G': { /* read a float */ - long double cur = 0; - int negative = 0; - /* skip initial whitespace */ - while ((nch!=_EOF_) && _ISSPACE_(nch)) - nch = _GETC_(file); - /* get sign. */ - if (nch == '-' || nch == '+') { - negative = (nch=='-'); - if (width>0) width--; - if (width==0) break; - nch = _GETC_(file); - } - /* get first digit. */ - if ('.' != nch) { - if (!_ISDIGIT_(nch)) break; - cur = (nch - '0'); - nch = _GETC_(file); - if (width>0) width--; - /* read until no more digits */ - while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { - cur = cur*10 + (nch - '0'); - nch = _GETC_(file); - if (width>0) width--; - } - } else { - cur = 0; /* MaxPayneDemo Fix: .8 -> 0.8 */ - } - /* handle decimals */ - if (width!=0 && nch == '.') { - float dec = 1; - nch = _GETC_(file); - if (width>0) width--; - while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { - dec /= 10; - cur += dec * (nch - '0'); - nch = _GETC_(file); - if (width>0) width--; - } - } - /* handle exponent */ - if (width!=0 && (nch == 'e' || nch == 'E')) { - int exponent = 0, negexp = 0; - float expcnt; - nch = _GETC_(file); - if (width>0) width--; - /* possible sign on the exponent */ - if (width!=0 && (nch=='+' || nch=='-')) { - negexp = (nch=='-'); - nch = _GETC_(file); - if (width>0) width--; - } - /* exponent digits */ - while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { - exponent *= 10; - exponent += (nch - '0'); - nch = _GETC_(file); - if (width>0) width--; - } - /* update 'cur' with this exponent. */ - expcnt = negexp ? .1 : 10; - while (exponent!=0) { - if (exponent&1) - cur*=expcnt; - exponent/=2; - expcnt=expcnt*expcnt; - } - } - st = 1; - if (!suppress) { - if (L_prefix) _SET_NUMBER_(long double); - else if (l_prefix) _SET_NUMBER_(double); - else _SET_NUMBER_(float); - } - } - break; - /* According to - * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt_scanf_type_field_characters.asp - * 's' reads a character string in a call to fscanf - * and 'S' a wide character string and vice versa in a - * call to fwscanf. The 'h', 'w' and 'l' prefixes override - * this behaviour. 'h' forces reading char * but 'l' and 'w' - * force reading WCHAR. */ - case 's': - if (w_prefix || l_prefix) goto widecharstring; - else if (h_prefix) goto charstring; -#ifdef WIDE_SCANF - else goto widecharstring; -#else /* WIDE_SCANF */ - else goto charstring; -#endif /* WIDE_SCANF */ - case 'S': - if (w_prefix || l_prefix) goto widecharstring; - else if (h_prefix) goto charstring; -#ifdef WIDE_SCANF - else goto charstring; -#else /* WIDE_SCANF */ - else goto widecharstring; -#endif /* WIDE_SCANF */ - charstring: { /* read a word into a char */ - char*str = suppress ? NULL : va_arg(ap, char*); - char*sptr = str; - /* skip initial whitespace */ - while ((nch!=_EOF_) && _ISSPACE_(nch)) - nch = _GETC_(file); - /* read until whitespace */ - while (width!=0 && (nch!=_EOF_) && !_ISSPACE_(nch)) { - if (!suppress) *sptr++ = _CHAR2SUPPORTED_(nch); - st++; - nch = _GETC_(file); - if (width>0) width--; - } - /* terminate */ - if (!suppress) *sptr = 0; - } - break; - widecharstring: { /* read a word into a wchar_t* */ - wchar_t*str = - suppress ? NULL : va_arg(ap, wchar_t*); - wchar_t*sptr = str; - /* skip initial whitespace */ - while ((nch!=_EOF_) && _ISSPACE_(nch)) - nch = _GETC_(file); - /* read until whitespace */ - while (width!=0 && (nch!=_EOF_) && !_ISSPACE_(nch)) { - if (!suppress) *sptr++ = _WIDE2SUPPORTED_(nch); - st++; - nch = _GETC_(file); - if (width>0) width--; - } - /* terminate */ - if (!suppress) *sptr = 0; - } - break; - /* 'c' and 'C work analogously to 's' and 'S' as described - * above */ - case 'c': - if (w_prefix || l_prefix) goto widecharacter; - else if (h_prefix) goto character; -#ifdef WIDE_SCANF - else goto widecharacter; -#else /* WIDE_SCANF */ - else goto character; -#endif /* WIDE_SCANF */ - case 'C': - if (w_prefix || l_prefix) goto widecharacter; - else if (h_prefix) goto character; -#ifdef WIDE_SCANF - else goto character; -#else /* WIDE_SCANF */ - else goto widecharacter; -#endif /* WIDE_SCANF */ - character: { /* read single character into char */ - if (nch!=_EOF_) { - if (!suppress) { - char*c = va_arg(ap, char*); - *c = _CHAR2SUPPORTED_(nch); - } - st = 1; - nch = _GETC_(file); - } - } - break; - widecharacter: { /* read single character into a wchar_t */ - if (nch!=_EOF_) { - if (!suppress) { - wchar_t*c = va_arg(ap, wchar_t*); - *c = _WIDE2SUPPORTED_(nch); - } - nch = _GETC_(file); - st = 1; - } - } - break; - case 'n': { - if (!suppress) { - int*n = va_arg(ap, int*); - - /* - *n = consumed - (nch!=_EOF_); - - FIXME: The above is the Wine version and it doesnt work in ros - when %n is at end of input string (return one too many). - But does it fail in Wine too?? If so wine also needs fixin. - -Gunnar - */ - - *n = consumed - 1; - } - /* This is an odd one: according to the standard, - * "Execution of a %n directive does not increment the - * assignment count returned at the completion of - * execution" even if it wasn't suppressed with the - * '*' flag. The Corrigendum to the standard seems - * to contradict this (comment out the assignment to - * suppress below if you want to implement these - * alternate semantics) but the windows program I'm - * looking at expects the behavior I've coded here - * (which happens to be what glibc does as well). - */ - suppress = 1; - st = 1; - } - break; - case '[': { - _CHAR_ *str = suppress ? NULL : va_arg(ap, _CHAR_*); - _CHAR_ *sptr = str; - RTL_BITMAP bitMask; - ULONG *Mask; - int invert = 0; /* Set if we are NOT to find the chars */ - - /* Init our bitmap */ - Mask = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _BITMAPSIZE_/8); - RtlInitializeBitMap(&bitMask, Mask, _BITMAPSIZE_); - - /* Read the format */ - format++; - if(*format == '^') { - invert = 1; - format++; - } - if(*format == ']') { - RtlSetBits(&bitMask, ']', 1); - format++; - } - while(*format && (*format != ']')) { - /* According to: - * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_crt_scanf_width_specification.asp - * "Note that %[a-z] and %[z-a] are interpreted as equivalent to %[abcde...z]." */ - if((*format == '-') && (*(format + 1) != ']')) { - if ((*(format - 1)) < *(format + 1)) - RtlSetBits(&bitMask, *(format - 1) +1 , *(format + 1) - *(format - 1)); - else - RtlSetBits(&bitMask, *(format + 1) , *(format - 1) - *(format + 1)); - format++; - } else - RtlSetBits(&bitMask, *format, 1); - format++; - } - /* read until char is not suitable */ - while ((width != 0) && (nch != _EOF_)) { - if(!invert) { - if(RtlAreBitsSet(&bitMask, nch, 1)) { - if (!suppress) *sptr++ = _CHAR2SUPPORTED_(nch); - } else - break; - } else { - if(RtlAreBitsClear(&bitMask, nch, 1)) { - if (!suppress) *sptr++ = _CHAR2SUPPORTED_(nch); - } else - break; - } - st++; - nch = _GETC_(file); - if (width>0) width--; - } - /* terminate */ - if (!suppress) *sptr = 0; - HeapFree(GetProcessHeap(), 0, Mask); - } - break; - default: - /* From spec: "if a percent sign is followed by a character - * that has no meaning as a format-control character, that - * character and the following characters are treated as - * an ordinary sequence of characters, that is, a sequence - * of characters that must match the input. For example, - * to specify that a percent-sign character is to be input, - * use %%." */ - while ((nch!=_EOF_) && _ISSPACE_(nch)) - nch = _GETC_(file); - if (nch==*format) { - suppress = 1; /* whoops no field to be read */ - st = 1; /* but we got what we expected */ - nch = _GETC_(file); - } - break; - } - if (st && !suppress) rd++; - else if (!st) break; - } - /* a non-white-space character causes scanf to read, but not store, - * a matching non-white-space character. */ - else { - /* check for character match */ - if (nch == *format) { - nch = _GETC_(file); - } else break; - } - format++; - } - if (nch!=_EOF_) { - _UNGETC_(nch, file); - } - TRACE("returning %d\n", rd); - return rd; -} - -#undef _CHAR_ -#undef _EOF_ -#undef _EOF_RET -#undef _ISSPACE_ -#undef _ISDIGIT_ -#undef _CHAR2SUPPORTED_ -#undef _WIDE2SUPPORTED_ -#undef _CHAR2DIGIT_ -#undef _GETC_ -#undef _UNGETC_ -#undef _FUNCTION_ -#undef _BITMAPSIZE_ +/* + * general implementation of scanf used by scanf, sscanf, fscanf, + * _cscanf, wscanf, swscanf and fwscanf + * + * Copyright 1996,1998 Marcus Meissner + * Copyright 1996 Jukka Iivonen + * Copyright 1997,2000, 2003 Uwe Bonnes + * Copyright 2000 Jon Griffiths + * Copyright 2002 Daniel Gudbjartsson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef WIDE_SCANF +#define _CHAR_ wchar_t +#define _EOF_ WEOF +#define _EOF_RET WEOF +#define _ISSPACE_(c) iswspace(c) +#define _ISDIGIT_(c) iswdigit(c) +#define _WIDE2SUPPORTED_(c) c /* No conversion needed (wide to wide) */ +#define _CHAR2SUPPORTED_(c) c /* FIXME: convert char to wide char */ +#define _CHAR2DIGIT_(c, base) wchar2digit((c), (base)) +#define _BITMAPSIZE_ 256*256 +#else /* WIDE_SCANF */ +#define _CHAR_ char +#define _EOF_ EOF +#define _EOF_RET EOF +#define _ISSPACE_(c) isspace(c) +#define _ISDIGIT_(c) isdigit(c) +#define _WIDE2SUPPORTED_(c) c /* FIXME: convert wide char to char */ +#define _CHAR2SUPPORTED_(c) c /* No conversion needed (char to char) */ +#define _CHAR2DIGIT_(c, base) char2digit((c), (base)) +#define _BITMAPSIZE_ 256 +#endif /* WIDE_SCANF */ + +#ifdef CONSOLE +#define _GETC_(file) (consumed++, _getch()) +#define _UNGETC_(nch, file) do { _ungetch(nch); consumed--; } while(0) +#define _FUNCTION_ int vcscanf(const char *format, va_list ap) +#else +#ifdef STRING +#undef _EOF_ +#define _EOF_ 0 +#define _GETC_(file) (consumed++, *file++) +#define _UNGETC_(nch, file) do { file--; consumed--; } while(0) +#ifdef WIDE_SCANF +#define _FUNCTION_ int vswscanf(const wchar_t *file, const wchar_t *format, va_list ap) +#else /* WIDE_SCANF */ +#define _FUNCTION_ int vsscanf(const char *file, const char *format, va_list ap) +#endif /* WIDE_SCANF */ +#else /* STRING */ +#ifdef WIDE_SCANF +#define _GETC_(file) (consumed++, fgetwc(file)) +#define _UNGETC_(nch, file) do { ungetwc(nch, file); consumed--; } while(0) +#define _FUNCTION_ int vfwscanf(FILE* file, const wchar_t *format, va_list ap) +#else /* WIDE_SCANF */ +#define _GETC_(file) (consumed++, fgetc(file)) +#define _UNGETC_(nch, file) do { ungetc(nch, file); consumed--; } while(0) +#define _FUNCTION_ int vfscanf(FILE* file, const char *format, va_list ap) +#endif /* WIDE_SCANF */ +#endif /* STRING */ +#endif /* CONSOLE */ + +/********************************************************************* + * Implemented based on + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_crt_format_specification_fields_.2d_.scanf_and_wscanf_functions.asp + * Extended by C. Scott Ananian to handle + * more types of format spec. + */ +_FUNCTION_ { + int rd = 0, consumed = 0; + int nch; + if (!*format) return 0; +#ifndef WIDE_SCANF +#ifdef CONSOLE + TRACE("(%s): \n", debugstr_a(format)); +#else /* CONSOLE */ +#ifdef STRING + TRACE("%s (%s)\n", file, debugstr_a(format)); +#else /* STRING */ + TRACE("%p (%s)\n", file, debugstr_a(format)); +#endif /* STRING */ +#endif /* CONSOLE */ +#endif /* WIDE_SCANF */ + nch = _GETC_(file); + if (nch == _EOF_) return _EOF_RET; + + while (*format) { + /* a whitespace character in the format string causes scanf to read, + * but not store, all consecutive white-space characters in the input + * up to the next non-white-space character. One white space character + * in the input matches any number (including zero) and combination of + * white-space characters in the input. */ + if (_ISSPACE_(*format)) { + /* skip whitespace */ + while ((nch!=_EOF_) && _ISSPACE_(nch)) + nch = _GETC_(file); + } + /* a format specification causes scanf to read and convert characters + * in the input into values of a specified type. The value is assigned + * to an argument in the argument list. Format specifications have + * the form %[*][width][{h | l | I64 | L}]type */ + else if (*format == '%') { + int st = 0; int suppress = 0; int width = 0; + int base, number_signed; + int h_prefix = 0; + int l_prefix = 0; + int L_prefix = 0; + int w_prefix = 0; + int prefix_finished = 0; + int I64_prefix = 0; + format++; + /* look for leading asterisk, which means 'suppress assignment of + * this field'. */ + if (*format=='*') { + format++; + suppress=1; + } + /* look for width specification */ + while (_ISDIGIT_(*format)) { + width*=10; + width+=*format++ - '0'; + } + if (width==0) width=-1; /* no width spec seen */ + /* read prefix (if any) */ + while (!prefix_finished) { + switch(*format) { + case 'h': h_prefix = 1; break; + case 'l': l_prefix = 1; break; + case 'w': w_prefix = 1; break; + case 'L': L_prefix = 1; break; + case 'I': + if (*(format + 1) == '6' && + *(format + 2) == '4') { + I64_prefix = 1; + format += 2; + } + break; + default: + prefix_finished = 1; + } + if (!prefix_finished) format++; + } + /* read type */ + switch(*format) { + case 'x': + case 'X': /* hexadecimal integer. */ + base = 16; number_signed = 0; + goto number; + case 'o': /* octal integer */ + base = 8; number_signed = 0; + goto number; + case 'u': /* unsigned decimal integer */ + base = 10; number_signed = 0; + goto number; + case 'd': /* signed decimal integer */ + base = 10; number_signed = 1; + goto number; + case 'i': /* generic integer */ + base = 10; number_signed = 1; + number: { + /* read an integer */ + ULONGLONG cur = 0; + int negative = 0; + int seendigit=0; + /* skip initial whitespace */ + while ((nch!=_EOF_) && _ISSPACE_(nch)) + nch = _GETC_(file); + /* get sign */ + if (number_signed && (nch == '-' || + nch == '+')) { + negative = (nch=='-'); + nch = _GETC_(file); + if (width>0) width--; + } + /* look for leading indication of base */ + if (width!=0 && nch == '0') { + nch = _GETC_(file); + if (width>0) width--; + seendigit=1; + if (width!=0 && (nch=='x' || nch=='X')) { + if (base==0) + base=16; + if (base==16) { + nch = _GETC_(file); + if (width>0) width--; + seendigit=0; + } + } else if (base==0) + base = 8; + } + /* throw away leading zeros */ + while (width!=0 && nch=='0') { + nch = _GETC_(file); + if (width>0) width--; + seendigit=1; + } + if (width!=0 && _CHAR2DIGIT_(nch, base)!=-1) { + cur = _CHAR2DIGIT_(nch, base); + nch = _GETC_(file); + if (width>0) width--; + seendigit=1; + } + /* read until no more digits */ + while (width!=0 && (nch!=_EOF_) && _CHAR2DIGIT_(nch, base)!=-1) { + cur = cur*base + _CHAR2DIGIT_(nch, base); + nch = _GETC_(file); + if (width>0) width--; + seendigit=1; + } + /* okay, done! */ + if (!seendigit) break; /* not a valid number */ + st = 1; + if (!suppress) { +#define _SET_NUMBER_(type) *va_arg(ap, type*) = negative ? -cur : cur + if (number_signed) { + if (I64_prefix) _SET_NUMBER_(LONGLONG); + else if (l_prefix) _SET_NUMBER_(long int); + else if (h_prefix) _SET_NUMBER_(short int); + else _SET_NUMBER_(int); + } else { + if (negative) { + WARN("Dropping sign in reading a negative number into an unsigned value"); + negative = 0; + } + if (I64_prefix) _SET_NUMBER_(ULONGLONG); + else if (l_prefix) _SET_NUMBER_(unsigned long int); + else if (h_prefix) + _SET_NUMBER_(unsigned short int); + else _SET_NUMBER_(unsigned int); + } + } + } + break; + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': { /* read a float */ + long double cur = 0; + int negative = 0; + /* skip initial whitespace */ + while ((nch!=_EOF_) && _ISSPACE_(nch)) + nch = _GETC_(file); + /* get sign. */ + if (nch == '-' || nch == '+') { + negative = (nch=='-'); + if (width>0) width--; + if (width==0) break; + nch = _GETC_(file); + } + /* get first digit. */ + if ('.' != nch) { + if (!_ISDIGIT_(nch)) break; + cur = (nch - '0'); + nch = _GETC_(file); + if (width>0) width--; + /* read until no more digits */ + while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { + cur = cur*10 + (nch - '0'); + nch = _GETC_(file); + if (width>0) width--; + } + } else { + cur = 0; /* MaxPayneDemo Fix: .8 -> 0.8 */ + } + /* handle decimals */ + if (width!=0 && nch == '.') { + float dec = 1; + nch = _GETC_(file); + if (width>0) width--; + while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { + dec /= 10; + cur += dec * (nch - '0'); + nch = _GETC_(file); + if (width>0) width--; + } + } + /* handle exponent */ + if (width!=0 && (nch == 'e' || nch == 'E')) { + int exponent = 0, negexp = 0; + float expcnt; + nch = _GETC_(file); + if (width>0) width--; + /* possible sign on the exponent */ + if (width!=0 && (nch=='+' || nch=='-')) { + negexp = (nch=='-'); + nch = _GETC_(file); + if (width>0) width--; + } + /* exponent digits */ + while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { + exponent *= 10; + exponent += (nch - '0'); + nch = _GETC_(file); + if (width>0) width--; + } + /* update 'cur' with this exponent. */ + expcnt = negexp ? .1 : 10; + while (exponent!=0) { + if (exponent&1) + cur*=expcnt; + exponent/=2; + expcnt=expcnt*expcnt; + } + } + st = 1; + if (!suppress) { + if (L_prefix) _SET_NUMBER_(long double); + else if (l_prefix) _SET_NUMBER_(double); + else _SET_NUMBER_(float); + } + } + break; + /* According to + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt_scanf_type_field_characters.asp + * 's' reads a character string in a call to fscanf + * and 'S' a wide character string and vice versa in a + * call to fwscanf. The 'h', 'w' and 'l' prefixes override + * this behaviour. 'h' forces reading char * but 'l' and 'w' + * force reading WCHAR. */ + case 's': + if (w_prefix || l_prefix) goto widecharstring; + else if (h_prefix) goto charstring; +#ifdef WIDE_SCANF + else goto widecharstring; +#else /* WIDE_SCANF */ + else goto charstring; +#endif /* WIDE_SCANF */ + case 'S': + if (w_prefix || l_prefix) goto widecharstring; + else if (h_prefix) goto charstring; +#ifdef WIDE_SCANF + else goto charstring; +#else /* WIDE_SCANF */ + else goto widecharstring; +#endif /* WIDE_SCANF */ + charstring: { /* read a word into a char */ + char*str = suppress ? NULL : va_arg(ap, char*); + char*sptr = str; + /* skip initial whitespace */ + while ((nch!=_EOF_) && _ISSPACE_(nch)) + nch = _GETC_(file); + /* read until whitespace */ + while (width!=0 && (nch!=_EOF_) && !_ISSPACE_(nch)) { + if (!suppress) *sptr++ = _CHAR2SUPPORTED_(nch); + st++; + nch = _GETC_(file); + if (width>0) width--; + } + /* terminate */ + if (!suppress) *sptr = 0; + } + break; + widecharstring: { /* read a word into a wchar_t* */ + wchar_t*str = + suppress ? NULL : va_arg(ap, wchar_t*); + wchar_t*sptr = str; + /* skip initial whitespace */ + while ((nch!=_EOF_) && _ISSPACE_(nch)) + nch = _GETC_(file); + /* read until whitespace */ + while (width!=0 && (nch!=_EOF_) && !_ISSPACE_(nch)) { + if (!suppress) *sptr++ = _WIDE2SUPPORTED_(nch); + st++; + nch = _GETC_(file); + if (width>0) width--; + } + /* terminate */ + if (!suppress) *sptr = 0; + } + break; + /* 'c' and 'C work analogously to 's' and 'S' as described + * above */ + case 'c': + if (w_prefix || l_prefix) goto widecharacter; + else if (h_prefix) goto character; +#ifdef WIDE_SCANF + else goto widecharacter; +#else /* WIDE_SCANF */ + else goto character; +#endif /* WIDE_SCANF */ + case 'C': + if (w_prefix || l_prefix) goto widecharacter; + else if (h_prefix) goto character; +#ifdef WIDE_SCANF + else goto character; +#else /* WIDE_SCANF */ + else goto widecharacter; +#endif /* WIDE_SCANF */ + character: { /* read single character into char */ + if (nch!=_EOF_) { + if (!suppress) { + char*c = va_arg(ap, char*); + *c = _CHAR2SUPPORTED_(nch); + } + st = 1; + nch = _GETC_(file); + } + } + break; + widecharacter: { /* read single character into a wchar_t */ + if (nch!=_EOF_) { + if (!suppress) { + wchar_t*c = va_arg(ap, wchar_t*); + *c = _WIDE2SUPPORTED_(nch); + } + nch = _GETC_(file); + st = 1; + } + } + break; + case 'n': { + if (!suppress) { + int*n = va_arg(ap, int*); + + /* + *n = consumed - (nch!=_EOF_); + + FIXME: The above is the Wine version and it doesnt work in ros + when %n is at end of input string (return one too many). + But does it fail in Wine too?? If so wine also needs fixin. + -Gunnar + */ + + *n = consumed - 1; + } + /* This is an odd one: according to the standard, + * "Execution of a %n directive does not increment the + * assignment count returned at the completion of + * execution" even if it wasn't suppressed with the + * '*' flag. The Corrigendum to the standard seems + * to contradict this (comment out the assignment to + * suppress below if you want to implement these + * alternate semantics) but the windows program I'm + * looking at expects the behavior I've coded here + * (which happens to be what glibc does as well). + */ + suppress = 1; + st = 1; + } + break; + case '[': { + _CHAR_ *str = suppress ? NULL : va_arg(ap, _CHAR_*); + _CHAR_ *sptr = str; + RTL_BITMAP bitMask; + ULONG *Mask; + int invert = 0; /* Set if we are NOT to find the chars */ + + /* Init our bitmap */ + Mask = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _BITMAPSIZE_/8); + RtlInitializeBitMap(&bitMask, Mask, _BITMAPSIZE_); + + /* Read the format */ + format++; + if(*format == '^') { + invert = 1; + format++; + } + if(*format == ']') { + RtlSetBits(&bitMask, ']', 1); + format++; + } + while(*format && (*format != ']')) { + /* According to: + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_crt_scanf_width_specification.asp + * "Note that %[a-z] and %[z-a] are interpreted as equivalent to %[abcde...z]." */ + if((*format == '-') && (*(format + 1) != ']')) { + if ((*(format - 1)) < *(format + 1)) + RtlSetBits(&bitMask, *(format - 1) +1 , *(format + 1) - *(format - 1)); + else + RtlSetBits(&bitMask, *(format + 1) , *(format - 1) - *(format + 1)); + format++; + } else + RtlSetBits(&bitMask, *format, 1); + format++; + } + /* read until char is not suitable */ + while ((width != 0) && (nch != _EOF_)) { + if(!invert) { + if(RtlAreBitsSet(&bitMask, nch, 1)) { + if (!suppress) *sptr++ = _CHAR2SUPPORTED_(nch); + } else + break; + } else { + if(RtlAreBitsClear(&bitMask, nch, 1)) { + if (!suppress) *sptr++ = _CHAR2SUPPORTED_(nch); + } else + break; + } + st++; + nch = _GETC_(file); + if (width>0) width--; + } + /* terminate */ + if (!suppress) *sptr = 0; + HeapFree(GetProcessHeap(), 0, Mask); + } + break; + default: + /* From spec: "if a percent sign is followed by a character + * that has no meaning as a format-control character, that + * character and the following characters are treated as + * an ordinary sequence of characters, that is, a sequence + * of characters that must match the input. For example, + * to specify that a percent-sign character is to be input, + * use %%." */ + while ((nch!=_EOF_) && _ISSPACE_(nch)) + nch = _GETC_(file); + if (nch==*format) { + suppress = 1; /* whoops no field to be read */ + st = 1; /* but we got what we expected */ + nch = _GETC_(file); + } + break; + } + if (st && !suppress) rd++; + else if (!st) break; + } + /* a non-white-space character causes scanf to read, but not store, + * a matching non-white-space character. */ + else { + /* check for character match */ + if (nch == *format) { + nch = _GETC_(file); + } else break; + } + format++; + } + if (nch!=_EOF_) { + _UNGETC_(nch, file); + } + TRACE("returning %d\n", rd); + return rd; +} + +#undef _CHAR_ +#undef _EOF_ +#undef _EOF_RET +#undef _ISSPACE_ +#undef _ISDIGIT_ +#undef _CHAR2SUPPORTED_ +#undef _WIDE2SUPPORTED_ +#undef _CHAR2DIGIT_ +#undef _GETC_ +#undef _UNGETC_ +#undef _FUNCTION_ +#undef _BITMAPSIZE_ diff --git a/reactos/lib/crtdll/dllmain.c b/reactos/lib/crtdll/dllmain.c index 902fd9d74b1..0b384249b42 100644 --- a/reactos/lib/crtdll/dllmain.c +++ b/reactos/lib/crtdll/dllmain.c @@ -1,297 +1,297 @@ -/* $Id: dllmain.c 12852 2005-01-06 13:58:04Z mf $ - * - * dllmain.c - * - * ReactOS MSVCRT.DLL Compatibility Library - * - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRENTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAMED. This includes but is not limited to warrenties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Revision: 1.24 $ - * $Author: mf $ - * $Date: 2005-01-06 14:58:04 +0100 (Thu, 06 Jan 2005) $ - * - */ - -#include "precomp.h" -#include -#include -#include -#include -#include - -#define NDEBUG -#include - - -/* EXTERNAL PROTOTYPES ********************************************************/ - -//void __fileno_init(void); -extern BOOL __fileno_init(void); -extern int BlockEnvToEnvironA(void); -extern int BlockEnvToEnvironW(void); -extern void FreeEnvironment(char **environment); - -extern unsigned int _osver; -extern unsigned int _winminor; -extern unsigned int _winmajor; -extern unsigned int _winver; - -unsigned int CRTDLL__basemajor_dll; -unsigned int CRTDLL__baseminor_dll; -unsigned int CRTDLL__baseversion_dll; -unsigned int CRTDLL__cpumode_dll; -unsigned int CRTDLL__osmajor_dll; -unsigned int CRTDLL__osminor_dll; -unsigned int CRTDLL__osmode_dll; -unsigned int CRTDLL__osversion_dll; - -extern char* _acmdln; /* pointer to ascii command line */ -extern wchar_t* _wcmdln; /* pointer to wide character command line */ -#undef _environ -extern char** _environ; /* pointer to environment block */ -extern char** __initenv; /* pointer to initial environment block */ -extern wchar_t** _wenviron; /* pointer to environment block */ -extern wchar_t** __winitenv; /* pointer to initial environment block */ - - - -/* dev_t is a short in crtdll but an unsigned int in msvcrt */ -typedef short crtdll_dev_t; - -struct crtdll_stat -{ - crtdll_dev_t st_dev; - _ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - crtdll_dev_t st_rdev; - _off_t st_size; - time_t st_atime; - time_t st_mtime; - time_t st_ctime; -}; - -/* convert struct _stat from crtdll format to msvcrt format */ -static void convert_struct_stat( struct crtdll_stat *dst, const struct _stat *src ) -{ - dst->st_dev = src->st_dev; - dst->st_ino = src->st_ino; - dst->st_mode = src->st_mode; - dst->st_nlink = src->st_nlink; - dst->st_uid = src->st_uid; - dst->st_gid = src->st_gid; - dst->st_rdev = src->st_rdev; - dst->st_size = src->st_size; - dst->st_atime = src->st_atime; - dst->st_mtime = src->st_mtime; - dst->st_ctime = src->st_ctime; -} - -/* from msvcrt */ -extern void __getmainargs( int *argc, char ***argv, char ***envp, - int expand_wildcards, int *new_mode ); - -/* LIBRARY GLOBAL VARIABLES ***************************************************/ - -HANDLE hHeap = NULL; /* handle for heap */ - - -/* LIBRARY ENTRY POINT ********************************************************/ - -BOOL -STDCALL -DllMain(PVOID hinstDll, ULONG dwReason, PVOID reserved) -{ - switch (dwReason) - { - case DLL_PROCESS_ATTACH://1 - /* initialize version info */ - DPRINT("Attach %d\n", nAttachCount); - - _osver = GetVersion(); - - CRTDLL__basemajor_dll = (_osver >> 24) & 0xFF; - CRTDLL__baseminor_dll = (_osver >> 16) & 0xFF; - CRTDLL__baseversion_dll = (_osver >> 16); - CRTDLL__cpumode_dll = 1; /* FIXME */ - CRTDLL__osmajor_dll = (_osver >>8) & 0xFF; - CRTDLL__osminor_dll = (_osver & 0xFF); - CRTDLL__osmode_dll = 1; /* FIXME */ - CRTDLL__osversion_dll = (_osver & 0xFFFF); - - _winmajor = (_osver >> 8) & 0xFF; - _winminor = _osver & 0xFF; - _winver = (_winmajor << 8) + _winminor; - _osver = (_osver >> 16) & 0xFFFF; - hHeap = HeapCreate(0, 100000, 0); - if (hHeap == NULL) - return FALSE; - if (!__fileno_init()) - return FALSE; - - /* create tls stuff */ - if (!CreateThreadData()) - return FALSE; - - if (BlockEnvToEnvironA() < 0) - return FALSE; - - if (BlockEnvToEnvironW() < 0) - { - FreeEnvironment((char**)_wenviron); - return FALSE; - } - - _acmdln = _strdup(GetCommandLineA()); - _wcmdln = _wcsdup(GetCommandLineW()); - - /* FIXME: more initializations... */ - - /* FIXME: Initialization of the WINE code */ - msvcrt_init_mt_locks(); - - DPRINT("Attach done\n"); - break; - - case DLL_THREAD_ATTACH://2 - break; - - case DLL_THREAD_DETACH://4 - FreeThreadData(NULL); - break; - - case DLL_PROCESS_DETACH://0 - DPRINT("Detach %d\n", nAttachCount); - /* FIXME: more cleanup... */ - _fcloseall(); - - /* destroy tls stuff */ - DestroyThreadData(); - - if (__winitenv && __winitenv != _wenviron) - FreeEnvironment((char**)__winitenv); - if (_wenviron) - FreeEnvironment((char**)_wenviron); - - if (__initenv && __initenv != _environ) - FreeEnvironment(__initenv); - if (_environ) - FreeEnvironment(_environ); - - /* destroy heap */ - HeapDestroy(hHeap); - - DPRINT("Detach done\n"); - break; - } - - return TRUE; -} - - - - -/********************************************************************* - * __GetMainArgs (CRTDLL.@) - */ -void __GetMainArgs( int *argc, char ***argv, char ***envp, int expand_wildcards ) -{ - int new_mode = 0; - __getmainargs( argc, argv, envp, expand_wildcards, &new_mode ); -} - - -/********************************************************************* - * _fstat (CRTDLL.@) - */ -int CRTDLL__fstat(int fd, struct crtdll_stat* buf) -{ - extern int _fstat(int,struct _stat*); - struct _stat st; - int ret; - - if (!(ret = _fstat( fd, &st ))) convert_struct_stat( buf, &st ); - return ret; -} - - -/********************************************************************* - * _stat (CRTDLL.@) - */ -int CRTDLL__stat(const char* path, struct crtdll_stat * buf) -{ - extern int _stat(const char*,struct _stat*); - struct _stat st; - int ret; - - if (!(ret = _stat( path, &st ))) convert_struct_stat( buf, &st ); - return ret; -} - - -/********************************************************************* - * _strdec (CRTDLL.@) - */ -char *_strdec(const char *str1, const char *str2) -{ - return (char *)(str2 - 1); -} - - -/********************************************************************* - * _strinc (CRTDLL.@) - */ -char *_strinc(const char *str) -{ - return (char *)(str + 1); -} - - -/********************************************************************* - * _strncnt (CRTDLL.@) - */ -size_t _strncnt(const char *str, size_t maxlen) -{ - size_t len = strlen(str); - return (len > maxlen) ? maxlen : len; -} - - -/********************************************************************* - * _strnextc (CRTDLL.@) - */ -unsigned int _strnextc(const char *str) -{ - return (unsigned int)str[0]; -} - - -/********************************************************************* - * _strninc (CRTDLL.@) - */ -char *_strninc(const char *str, size_t len) -{ - return (char *)(str + len); -} - - -/********************************************************************* - * _strspnp (CRTDLL.@) - */ -char *_strspnp( const char *str1, const char *str2) -{ - str1 += strspn( str1, str2 ); - return *str1 ? (char*)str1 : NULL; -} - -/* EOF */ +/* $Id: dllmain.c 12852 2005-01-06 13:58:04Z mf $ + * + * dllmain.c + * + * ReactOS MSVCRT.DLL Compatibility Library + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRENTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAMED. This includes but is not limited to warrenties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * $Revision: 1.24 $ + * $Author: mf $ + * $Date: 2005-01-06 14:58:04 +0100 (Thu, 06 Jan 2005) $ + * + */ + +#include "precomp.h" +#include +#include +#include +#include +#include + +#define NDEBUG +#include + + +/* EXTERNAL PROTOTYPES ********************************************************/ + +//void __fileno_init(void); +extern BOOL __fileno_init(void); +extern int BlockEnvToEnvironA(void); +extern int BlockEnvToEnvironW(void); +extern void FreeEnvironment(char **environment); + +extern unsigned int _osver; +extern unsigned int _winminor; +extern unsigned int _winmajor; +extern unsigned int _winver; + +unsigned int CRTDLL__basemajor_dll; +unsigned int CRTDLL__baseminor_dll; +unsigned int CRTDLL__baseversion_dll; +unsigned int CRTDLL__cpumode_dll; +unsigned int CRTDLL__osmajor_dll; +unsigned int CRTDLL__osminor_dll; +unsigned int CRTDLL__osmode_dll; +unsigned int CRTDLL__osversion_dll; + +extern char* _acmdln; /* pointer to ascii command line */ +extern wchar_t* _wcmdln; /* pointer to wide character command line */ +#undef _environ +extern char** _environ; /* pointer to environment block */ +extern char** __initenv; /* pointer to initial environment block */ +extern wchar_t** _wenviron; /* pointer to environment block */ +extern wchar_t** __winitenv; /* pointer to initial environment block */ + + + +/* dev_t is a short in crtdll but an unsigned int in msvcrt */ +typedef short crtdll_dev_t; + +struct crtdll_stat +{ + crtdll_dev_t st_dev; + _ino_t st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + crtdll_dev_t st_rdev; + _off_t st_size; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; +}; + +/* convert struct _stat from crtdll format to msvcrt format */ +static void convert_struct_stat( struct crtdll_stat *dst, const struct _stat *src ) +{ + dst->st_dev = src->st_dev; + dst->st_ino = src->st_ino; + dst->st_mode = src->st_mode; + dst->st_nlink = src->st_nlink; + dst->st_uid = src->st_uid; + dst->st_gid = src->st_gid; + dst->st_rdev = src->st_rdev; + dst->st_size = src->st_size; + dst->st_atime = src->st_atime; + dst->st_mtime = src->st_mtime; + dst->st_ctime = src->st_ctime; +} + +/* from msvcrt */ +extern void __getmainargs( int *argc, char ***argv, char ***envp, + int expand_wildcards, int *new_mode ); + +/* LIBRARY GLOBAL VARIABLES ***************************************************/ + +HANDLE hHeap = NULL; /* handle for heap */ + + +/* LIBRARY ENTRY POINT ********************************************************/ + +BOOL +STDCALL +DllMain(PVOID hinstDll, ULONG dwReason, PVOID reserved) +{ + switch (dwReason) + { + case DLL_PROCESS_ATTACH://1 + /* initialize version info */ + DPRINT("Attach %d\n", nAttachCount); + + _osver = GetVersion(); + + CRTDLL__basemajor_dll = (_osver >> 24) & 0xFF; + CRTDLL__baseminor_dll = (_osver >> 16) & 0xFF; + CRTDLL__baseversion_dll = (_osver >> 16); + CRTDLL__cpumode_dll = 1; /* FIXME */ + CRTDLL__osmajor_dll = (_osver >>8) & 0xFF; + CRTDLL__osminor_dll = (_osver & 0xFF); + CRTDLL__osmode_dll = 1; /* FIXME */ + CRTDLL__osversion_dll = (_osver & 0xFFFF); + + _winmajor = (_osver >> 8) & 0xFF; + _winminor = _osver & 0xFF; + _winver = (_winmajor << 8) + _winminor; + _osver = (_osver >> 16) & 0xFFFF; + hHeap = HeapCreate(0, 100000, 0); + if (hHeap == NULL) + return FALSE; + if (!__fileno_init()) + return FALSE; + + /* create tls stuff */ + if (!CreateThreadData()) + return FALSE; + + if (BlockEnvToEnvironA() < 0) + return FALSE; + + if (BlockEnvToEnvironW() < 0) + { + FreeEnvironment((char**)_wenviron); + return FALSE; + } + + _acmdln = _strdup(GetCommandLineA()); + _wcmdln = _wcsdup(GetCommandLineW()); + + /* FIXME: more initializations... */ + + /* FIXME: Initialization of the WINE code */ + msvcrt_init_mt_locks(); + + DPRINT("Attach done\n"); + break; + + case DLL_THREAD_ATTACH://2 + break; + + case DLL_THREAD_DETACH://4 + FreeThreadData(NULL); + break; + + case DLL_PROCESS_DETACH://0 + DPRINT("Detach %d\n", nAttachCount); + /* FIXME: more cleanup... */ + _fcloseall(); + + /* destroy tls stuff */ + DestroyThreadData(); + + if (__winitenv && __winitenv != _wenviron) + FreeEnvironment((char**)__winitenv); + if (_wenviron) + FreeEnvironment((char**)_wenviron); + + if (__initenv && __initenv != _environ) + FreeEnvironment(__initenv); + if (_environ) + FreeEnvironment(_environ); + + /* destroy heap */ + HeapDestroy(hHeap); + + DPRINT("Detach done\n"); + break; + } + + return TRUE; +} + + + + +/********************************************************************* + * __GetMainArgs (CRTDLL.@) + */ +void __GetMainArgs( int *argc, char ***argv, char ***envp, int expand_wildcards ) +{ + int new_mode = 0; + __getmainargs( argc, argv, envp, expand_wildcards, &new_mode ); +} + + +/********************************************************************* + * _fstat (CRTDLL.@) + */ +int CRTDLL__fstat(int fd, struct crtdll_stat* buf) +{ + extern int _fstat(int,struct _stat*); + struct _stat st; + int ret; + + if (!(ret = _fstat( fd, &st ))) convert_struct_stat( buf, &st ); + return ret; +} + + +/********************************************************************* + * _stat (CRTDLL.@) + */ +int CRTDLL__stat(const char* path, struct crtdll_stat * buf) +{ + extern int _stat(const char*,struct _stat*); + struct _stat st; + int ret; + + if (!(ret = _stat( path, &st ))) convert_struct_stat( buf, &st ); + return ret; +} + + +/********************************************************************* + * _strdec (CRTDLL.@) + */ +char *_strdec(const char *str1, const char *str2) +{ + return (char *)(str2 - 1); +} + + +/********************************************************************* + * _strinc (CRTDLL.@) + */ +char *_strinc(const char *str) +{ + return (char *)(str + 1); +} + + +/********************************************************************* + * _strncnt (CRTDLL.@) + */ +size_t _strncnt(const char *str, size_t maxlen) +{ + size_t len = strlen(str); + return (len > maxlen) ? maxlen : len; +} + + +/********************************************************************* + * _strnextc (CRTDLL.@) + */ +unsigned int _strnextc(const char *str) +{ + return (unsigned int)str[0]; +} + + +/********************************************************************* + * _strninc (CRTDLL.@) + */ +char *_strninc(const char *str, size_t len) +{ + return (char *)(str + len); +} + + +/********************************************************************* + * _strspnp (CRTDLL.@) + */ +char *_strspnp( const char *str1, const char *str2) +{ + str1 += strspn( str1, str2 ); + return *str1 ? (char*)str1 : NULL; +} + +/* EOF */ diff --git a/reactos/lib/ddraw/ddraw_hal.c b/reactos/lib/ddraw/ddraw_hal.c index cd93a1ba88a..e54c5b3eca2 100644 --- a/reactos/lib/ddraw/ddraw_hal.c +++ b/reactos/lib/ddraw/ddraw_hal.c @@ -1,342 +1,342 @@ - - - -#include -#include "ddraw.h" -#include "rosddraw.h" -#include "ddraw_private.h" - -static IDirectDraw7Vtbl HAL_DirectDraw_VTable; - - -HRESULT HAL_DirectDraw_Construct(IDirectDrawImpl *This, BOOL ex) -{ - //This->local.lpGbl = &dd_gbl; - - This->final_release = HAL_DirectDraw_final_release; - This->set_exclusive_mode = HAL_DirectDrawSet_exclusive_mode; - // This->create_palette = HAL_DirectDrawPalette_Create; - - This->create_primary = HAL_DirectDraw_create_primary; - This->create_backbuffer = HAL_DirectDraw_create_backbuffer; - This->create_texture = HAL_DirectDraw_create_texture; - - // ICOM_INIT_INTERFACE(This, IDirectDraw7, HAL_DirectDraw_VTable); - return S_OK; -} - -void HAL_DirectDraw_final_release(IDirectDrawImpl *This) -{ - -} - -HRESULT HAL_DirectDrawSet_exclusive_mode(IDirectDrawImpl *This, DWORD dwEnterExcl) -{ - return DDERR_UNSUPPORTED; -} - - -HRESULT HAL_DirectDraw_create_primary(IDirectDrawImpl* This, const DDSURFACEDESC2* pDDSD, LPDIRECTDRAWSURFACE7* ppSurf, - IUnknown* pUnkOuter) - -{ - return DDERR_UNSUPPORTED; - } - -HRESULT HAL_DirectDraw_create_backbuffer(IDirectDrawImpl* This, - const DDSURFACEDESC2* pDDSD, - LPDIRECTDRAWSURFACE7* ppSurf, - IUnknown* pUnkOuter, - IDirectDrawSurfaceImpl* primary) -{ - return DDERR_UNSUPPORTED; - } - -HRESULT HAL_DirectDraw_create_texture(IDirectDrawImpl* This, - const DDSURFACEDESC2* pDDSD, - LPDIRECTDRAWSURFACE7* ppSurf, - LPUNKNOWN pOuter, - DWORD dwMipMapLevel) -{ - return DDERR_UNSUPPORTED; - } - - - - - - -/* basic funtion for the com object */ -HRESULT WINAPI HAL_DirectDraw_QueryInterface(LPDIRECTDRAW7 iface,REFIID refiid,LPVOID *obj) -{ - return DDERR_UNSUPPORTED; - } - -ULONG WINAPI HAL_DirectDraw_AddRef(LPDIRECTDRAW7 iface) -{ - IDirectDrawImpl *This = (IDirectDrawImpl *)iface; - ULONG ref = InterlockedIncrement(&This->ref); - - //TRACE("(%p)->() incrementing from %lu.\n", This, ref -1); - - return ref; -} - -ULONG WINAPI HAL_DirectDraw_Release(LPDIRECTDRAW7 iface) -{ - IDirectDrawImpl *This = (IDirectDrawImpl *)iface; - ULONG ref = InterlockedDecrement(&This->ref); - - if (ref == 0) - { - if (This->final_release != NULL) - This->final_release(This); - - /* We free the private. This is an artifact of the fact that I don't - * have the destructors set up correctly. */ - if (This->private != (This+1)) - HeapFree(GetProcessHeap(), 0, This->private); - - HeapFree(GetProcessHeap(), 0, This); - } - - return ref; -} - -HRESULT WINAPI HAL_DirectDraw_Compact(LPDIRECTDRAW7 iface) -{ - - return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_CreateClipper(LPDIRECTDRAW7 iface, DWORD dwFlags, - LPDIRECTDRAWCLIPPER *ppClipper, IUnknown *pUnkOuter) -{ - return DDERR_UNSUPPORTED; -} -HRESULT WINAPI HAL_DirectDraw_CreatePalette(LPDIRECTDRAW7 iface, DWORD dwFlags, - LPPALETTEENTRY palent,LPDIRECTDRAWPALETTE* ppPalette,LPUNKNOWN pUnknown) -{ - return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_CreateSurface(LPDIRECTDRAW7 iface, LPDDSURFACEDESC2 pDDSD, - LPDIRECTDRAWSURFACE7 *ppSurf,IUnknown *pUnkOuter) -{ - return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_DuplicateSurface(LPDIRECTDRAW7 iface, LPDIRECTDRAWSURFACE7 src, - LPDIRECTDRAWSURFACE7* dst) -{ - return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_EnumDisplayModes(LPDIRECTDRAW7 iface, DWORD dwFlags, - LPDDSURFACEDESC2 pDDSD, LPVOID context, LPDDENUMMODESCALLBACK2 callback) -{ - return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_EnumSurfaces(LPDIRECTDRAW7 iface, DWORD dwFlags, - LPDDSURFACEDESC2 lpDDSD2, LPVOID context, - LPDDENUMSURFACESCALLBACK7 callback) -{ - return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_FlipToGDISurface(LPDIRECTDRAW7 iface) -{ -return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_GetCaps(LPDIRECTDRAW7 iface, LPDDCAPS pDriverCaps, - LPDDCAPS pHELCaps) -{ -return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_GetDisplayMode(LPDIRECTDRAW7 iface, LPDDSURFACEDESC2 pDDSD) -{ - return DDERR_UNSUPPORTED; -} - - -HRESULT WINAPI HAL_DirectDraw_GetFourCCCodes(LPDIRECTDRAW7 iface, LPDWORD pNumCodes, LPDWORD pCodes) -{ - - return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_GetGDISurface(LPDIRECTDRAW7 iface, - LPDIRECTDRAWSURFACE7 *lplpGDIDDSSurface) -{ - - return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_GetMonitorFrequency(LPDIRECTDRAW7 iface,LPDWORD freq) -{ - return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_GetScanLine(LPDIRECTDRAW7 iface, LPDWORD lpdwScanLine) -{ - return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_GetVerticalBlankStatus(LPDIRECTDRAW7 iface, LPBOOL status) -{ - return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_Initialize(LPDIRECTDRAW7 iface, LPGUID lpGuid) -{ - return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_RestoreDisplayMode(LPDIRECTDRAW7 iface) -{ - return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_SetCooperativeLevel(LPDIRECTDRAW7 iface, HWND hwnd, - DWORD cooplevel) -{ - return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_SetDisplayMode(LPDIRECTDRAW7 iface, DWORD dwWidth, - DWORD dwHeight, DWORD dwBPP, DWORD dwRefreshRate, DWORD dwFlags) -{ - - return DDERR_UNSUPPORTED; -} - - -HRESULT WINAPI HAL_DirectDraw_WaitForVerticalBlank(LPDIRECTDRAW7 iface, DWORD dwFlags, - HANDLE h) -{ - - return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_GetAvailableVidMem(LPDIRECTDRAW7 iface, LPDDSCAPS2 ddscaps, - LPDWORD total, LPDWORD free) - -{ - - return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_GetSurfaceFromDC(LPDIRECTDRAW7 iface, HDC hdc, - LPDIRECTDRAWSURFACE7 *lpDDS) -{ - return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_RestoreAllSurfaces(LPDIRECTDRAW7 iface) -{ - return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_TestCooperativeLevel(LPDIRECTDRAW7 iface) -{ - return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_GetDeviceIdentifier(LPDIRECTDRAW7 iface, - LPDDDEVICEIDENTIFIER2 pDDDI, DWORD dwFlags) -{ - return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_StartModeTest(LPDIRECTDRAW7 iface, LPSIZE pModes, - DWORD dwNumModes, DWORD dwFlags) -{ - return DDERR_UNSUPPORTED; -} - -HRESULT WINAPI HAL_DirectDraw_EvaluateMode(LPDIRECTDRAW7 iface,DWORD a,DWORD* b) -{ - return DDERR_UNSUPPORTED; -} - -/* End com interface */ - - - - -HRESULT WINAPI HAL_DirectDraw_Create(const GUID* pGUID, LPDIRECTDRAW7* pIface, - IUnknown* pUnkOuter, BOOL ex) -{ - - HRESULT hr; - IDirectDrawImpl* This; - HDC desktop; - - /* - This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(IDirectDrawImpl) - + sizeof(HAL_DirectDrawImpl)); - */ - This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(IDirectDrawImpl)); - - if (This == NULL) return E_OUTOFMEMORY; - - /* Note that this relation does *not* hold true if the DD object was - * CoCreateInstanced then Initialized. */ - //This->private = (HAL_DirectDrawImpl *)(This+1); - - /* Initialize the DDCAPS structure */ - This->caps.dwSize = sizeof(This->caps); - - hr = HAL_DirectDraw_Construct(This, ex); - if (FAILED(hr)) - HeapFree(GetProcessHeap(), 0, This); - else *pIface = ICOM_INTERFACE(This, IDirectDraw7); - - /* create a scaner that check which driver we should get the HDC from */ - /* for now we always asume it is the active dirver that should be use. */ - - desktop = GetWindowDC(GetDesktopWindow()); - *pIface = OsThunkDdCreateDirectDrawObject(desktop); - if (pIface == NULL) hr == DDERR_NODIRECTDRAWHW; - - return DDERR_UNSUPPORTED; -} - -static IDirectDraw7Vtbl HAL_DirectDraw_VTable = -{ - HAL_DirectDraw_QueryInterface, - HAL_DirectDraw_AddRef, - HAL_DirectDraw_Release, - HAL_DirectDraw_Compact, - HAL_DirectDraw_CreateClipper, - HAL_DirectDraw_CreatePalette, - HAL_DirectDraw_CreateSurface, - HAL_DirectDraw_DuplicateSurface, - HAL_DirectDraw_EnumDisplayModes, - HAL_DirectDraw_EnumSurfaces, - HAL_DirectDraw_FlipToGDISurface, - HAL_DirectDraw_GetCaps, - HAL_DirectDraw_GetDisplayMode, - HAL_DirectDraw_GetFourCCCodes, - HAL_DirectDraw_GetGDISurface, - HAL_DirectDraw_GetMonitorFrequency, - HAL_DirectDraw_GetScanLine, - HAL_DirectDraw_GetVerticalBlankStatus, - HAL_DirectDraw_Initialize, - HAL_DirectDraw_RestoreDisplayMode, - HAL_DirectDraw_SetCooperativeLevel, - HAL_DirectDraw_SetDisplayMode, - HAL_DirectDraw_WaitForVerticalBlank, - HAL_DirectDraw_GetAvailableVidMem, - HAL_DirectDraw_GetSurfaceFromDC, - HAL_DirectDraw_RestoreAllSurfaces, - HAL_DirectDraw_TestCooperativeLevel, - HAL_DirectDraw_GetDeviceIdentifier, - HAL_DirectDraw_StartModeTest, - HAL_DirectDraw_EvaluateMode -}; + + + +#include +#include "ddraw.h" +#include "rosddraw.h" +#include "ddraw_private.h" + +static IDirectDraw7Vtbl HAL_DirectDraw_VTable; + + +HRESULT HAL_DirectDraw_Construct(IDirectDrawImpl *This, BOOL ex) +{ + //This->local.lpGbl = &dd_gbl; + + This->final_release = HAL_DirectDraw_final_release; + This->set_exclusive_mode = HAL_DirectDrawSet_exclusive_mode; + // This->create_palette = HAL_DirectDrawPalette_Create; + + This->create_primary = HAL_DirectDraw_create_primary; + This->create_backbuffer = HAL_DirectDraw_create_backbuffer; + This->create_texture = HAL_DirectDraw_create_texture; + + // ICOM_INIT_INTERFACE(This, IDirectDraw7, HAL_DirectDraw_VTable); + return S_OK; +} + +void HAL_DirectDraw_final_release(IDirectDrawImpl *This) +{ + +} + +HRESULT HAL_DirectDrawSet_exclusive_mode(IDirectDrawImpl *This, DWORD dwEnterExcl) +{ + return DDERR_UNSUPPORTED; +} + + +HRESULT HAL_DirectDraw_create_primary(IDirectDrawImpl* This, const DDSURFACEDESC2* pDDSD, LPDIRECTDRAWSURFACE7* ppSurf, + IUnknown* pUnkOuter) + +{ + return DDERR_UNSUPPORTED; + } + +HRESULT HAL_DirectDraw_create_backbuffer(IDirectDrawImpl* This, + const DDSURFACEDESC2* pDDSD, + LPDIRECTDRAWSURFACE7* ppSurf, + IUnknown* pUnkOuter, + IDirectDrawSurfaceImpl* primary) +{ + return DDERR_UNSUPPORTED; + } + +HRESULT HAL_DirectDraw_create_texture(IDirectDrawImpl* This, + const DDSURFACEDESC2* pDDSD, + LPDIRECTDRAWSURFACE7* ppSurf, + LPUNKNOWN pOuter, + DWORD dwMipMapLevel) +{ + return DDERR_UNSUPPORTED; + } + + + + + + +/* basic funtion for the com object */ +HRESULT WINAPI HAL_DirectDraw_QueryInterface(LPDIRECTDRAW7 iface,REFIID refiid,LPVOID *obj) +{ + return DDERR_UNSUPPORTED; + } + +ULONG WINAPI HAL_DirectDraw_AddRef(LPDIRECTDRAW7 iface) +{ + IDirectDrawImpl *This = (IDirectDrawImpl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + //TRACE("(%p)->() incrementing from %lu.\n", This, ref -1); + + return ref; +} + +ULONG WINAPI HAL_DirectDraw_Release(LPDIRECTDRAW7 iface) +{ + IDirectDrawImpl *This = (IDirectDrawImpl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + if (ref == 0) + { + if (This->final_release != NULL) + This->final_release(This); + + /* We free the private. This is an artifact of the fact that I don't + * have the destructors set up correctly. */ + if (This->private != (This+1)) + HeapFree(GetProcessHeap(), 0, This->private); + + HeapFree(GetProcessHeap(), 0, This); + } + + return ref; +} + +HRESULT WINAPI HAL_DirectDraw_Compact(LPDIRECTDRAW7 iface) +{ + + return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_CreateClipper(LPDIRECTDRAW7 iface, DWORD dwFlags, + LPDIRECTDRAWCLIPPER *ppClipper, IUnknown *pUnkOuter) +{ + return DDERR_UNSUPPORTED; +} +HRESULT WINAPI HAL_DirectDraw_CreatePalette(LPDIRECTDRAW7 iface, DWORD dwFlags, + LPPALETTEENTRY palent,LPDIRECTDRAWPALETTE* ppPalette,LPUNKNOWN pUnknown) +{ + return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_CreateSurface(LPDIRECTDRAW7 iface, LPDDSURFACEDESC2 pDDSD, + LPDIRECTDRAWSURFACE7 *ppSurf,IUnknown *pUnkOuter) +{ + return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_DuplicateSurface(LPDIRECTDRAW7 iface, LPDIRECTDRAWSURFACE7 src, + LPDIRECTDRAWSURFACE7* dst) +{ + return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_EnumDisplayModes(LPDIRECTDRAW7 iface, DWORD dwFlags, + LPDDSURFACEDESC2 pDDSD, LPVOID context, LPDDENUMMODESCALLBACK2 callback) +{ + return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_EnumSurfaces(LPDIRECTDRAW7 iface, DWORD dwFlags, + LPDDSURFACEDESC2 lpDDSD2, LPVOID context, + LPDDENUMSURFACESCALLBACK7 callback) +{ + return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_FlipToGDISurface(LPDIRECTDRAW7 iface) +{ +return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_GetCaps(LPDIRECTDRAW7 iface, LPDDCAPS pDriverCaps, + LPDDCAPS pHELCaps) +{ +return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_GetDisplayMode(LPDIRECTDRAW7 iface, LPDDSURFACEDESC2 pDDSD) +{ + return DDERR_UNSUPPORTED; +} + + +HRESULT WINAPI HAL_DirectDraw_GetFourCCCodes(LPDIRECTDRAW7 iface, LPDWORD pNumCodes, LPDWORD pCodes) +{ + + return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_GetGDISurface(LPDIRECTDRAW7 iface, + LPDIRECTDRAWSURFACE7 *lplpGDIDDSSurface) +{ + + return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_GetMonitorFrequency(LPDIRECTDRAW7 iface,LPDWORD freq) +{ + return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_GetScanLine(LPDIRECTDRAW7 iface, LPDWORD lpdwScanLine) +{ + return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_GetVerticalBlankStatus(LPDIRECTDRAW7 iface, LPBOOL status) +{ + return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_Initialize(LPDIRECTDRAW7 iface, LPGUID lpGuid) +{ + return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_RestoreDisplayMode(LPDIRECTDRAW7 iface) +{ + return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_SetCooperativeLevel(LPDIRECTDRAW7 iface, HWND hwnd, + DWORD cooplevel) +{ + return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_SetDisplayMode(LPDIRECTDRAW7 iface, DWORD dwWidth, + DWORD dwHeight, DWORD dwBPP, DWORD dwRefreshRate, DWORD dwFlags) +{ + + return DDERR_UNSUPPORTED; +} + + +HRESULT WINAPI HAL_DirectDraw_WaitForVerticalBlank(LPDIRECTDRAW7 iface, DWORD dwFlags, + HANDLE h) +{ + + return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_GetAvailableVidMem(LPDIRECTDRAW7 iface, LPDDSCAPS2 ddscaps, + LPDWORD total, LPDWORD free) + +{ + + return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_GetSurfaceFromDC(LPDIRECTDRAW7 iface, HDC hdc, + LPDIRECTDRAWSURFACE7 *lpDDS) +{ + return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_RestoreAllSurfaces(LPDIRECTDRAW7 iface) +{ + return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_TestCooperativeLevel(LPDIRECTDRAW7 iface) +{ + return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_GetDeviceIdentifier(LPDIRECTDRAW7 iface, + LPDDDEVICEIDENTIFIER2 pDDDI, DWORD dwFlags) +{ + return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_StartModeTest(LPDIRECTDRAW7 iface, LPSIZE pModes, + DWORD dwNumModes, DWORD dwFlags) +{ + return DDERR_UNSUPPORTED; +} + +HRESULT WINAPI HAL_DirectDraw_EvaluateMode(LPDIRECTDRAW7 iface,DWORD a,DWORD* b) +{ + return DDERR_UNSUPPORTED; +} + +/* End com interface */ + + + + +HRESULT WINAPI HAL_DirectDraw_Create(const GUID* pGUID, LPDIRECTDRAW7* pIface, + IUnknown* pUnkOuter, BOOL ex) +{ + + HRESULT hr; + IDirectDrawImpl* This; + HDC desktop; + + /* + This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(IDirectDrawImpl) + + sizeof(HAL_DirectDrawImpl)); + */ + This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(IDirectDrawImpl)); + + if (This == NULL) return E_OUTOFMEMORY; + + /* Note that this relation does *not* hold true if the DD object was + * CoCreateInstanced then Initialized. */ + //This->private = (HAL_DirectDrawImpl *)(This+1); + + /* Initialize the DDCAPS structure */ + This->caps.dwSize = sizeof(This->caps); + + hr = HAL_DirectDraw_Construct(This, ex); + if (FAILED(hr)) + HeapFree(GetProcessHeap(), 0, This); + else *pIface = ICOM_INTERFACE(This, IDirectDraw7); + + /* create a scaner that check which driver we should get the HDC from */ + /* for now we always asume it is the active dirver that should be use. */ + + desktop = GetWindowDC(GetDesktopWindow()); + *pIface = OsThunkDdCreateDirectDrawObject(desktop); + if (pIface == NULL) hr == DDERR_NODIRECTDRAWHW; + + return DDERR_UNSUPPORTED; +} + +static IDirectDraw7Vtbl HAL_DirectDraw_VTable = +{ + HAL_DirectDraw_QueryInterface, + HAL_DirectDraw_AddRef, + HAL_DirectDraw_Release, + HAL_DirectDraw_Compact, + HAL_DirectDraw_CreateClipper, + HAL_DirectDraw_CreatePalette, + HAL_DirectDraw_CreateSurface, + HAL_DirectDraw_DuplicateSurface, + HAL_DirectDraw_EnumDisplayModes, + HAL_DirectDraw_EnumSurfaces, + HAL_DirectDraw_FlipToGDISurface, + HAL_DirectDraw_GetCaps, + HAL_DirectDraw_GetDisplayMode, + HAL_DirectDraw_GetFourCCCodes, + HAL_DirectDraw_GetGDISurface, + HAL_DirectDraw_GetMonitorFrequency, + HAL_DirectDraw_GetScanLine, + HAL_DirectDraw_GetVerticalBlankStatus, + HAL_DirectDraw_Initialize, + HAL_DirectDraw_RestoreDisplayMode, + HAL_DirectDraw_SetCooperativeLevel, + HAL_DirectDraw_SetDisplayMode, + HAL_DirectDraw_WaitForVerticalBlank, + HAL_DirectDraw_GetAvailableVidMem, + HAL_DirectDraw_GetSurfaceFromDC, + HAL_DirectDraw_RestoreAllSurfaces, + HAL_DirectDraw_TestCooperativeLevel, + HAL_DirectDraw_GetDeviceIdentifier, + HAL_DirectDraw_StartModeTest, + HAL_DirectDraw_EvaluateMode +}; diff --git a/reactos/lib/ddraw/ddraw_private.h b/reactos/lib/ddraw/ddraw_private.h index 98558e97515..3b92748567a 100644 --- a/reactos/lib/ddraw/ddraw_private.h +++ b/reactos/lib/ddraw/ddraw_private.h @@ -1,482 +1,482 @@ -/* - * Copyright 2000-2001 TransGaming Technologies Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _DDCOMIMPL_H_ -#define _DDCOMIMPL_H_ - -#include - -/* Generates the name for a vtable pointer for a given interface. */ -/* The canonical name for a single interface is "lpVtbl". */ -#define ICOM_VFIELD_MULTI_NAME2(iface) ITF_##iface -#define ICOM_VFIELD_MULTI_NAME(iface) ICOM_VFIELD_MULTI_NAME2(iface) - -/* Declares a vtable pointer field in an implementation. */ -#define ICOM_VFIELD_MULTI(iface) \ - iface ICOM_VFIELD_MULTI_NAME(iface) - -/* Returns the offset of a vtable pointer within an implementation object. */ -#define ICOM_VFIELD_OFFSET(impltype, iface) \ - offsetof(impltype, ICOM_VFIELD_MULTI_NAME(iface)) - -/* Given an interface pointer, returns the implementation pointer. */ -#define ICOM_OBJECT(impltype, ifacename, ifaceptr) \ - (impltype*)((ifaceptr) == NULL ? NULL \ - : (char*)(ifaceptr) - ICOM_VFIELD_OFFSET(impltype,ifacename)) - -#define ICOM_THIS_FROM(impltype, ifacename, ifaceptr) \ - impltype* This = ICOM_OBJECT(impltype, ifacename, ifaceptr) - -/* Given an object and interface name, returns a pointer to that interface. */ -#define ICOM_INTERFACE(implobj, iface) \ - (&((implobj)->ICOM_VFIELD_MULTI_NAME(iface))) - -#define ICOM_INIT_INTERFACE(implobj, ifacename, vtblname) \ - do { \ - (implobj)->ICOM_VFIELD_MULTI_NAME(ifacename).lpVtbl = &(vtblname); \ - } while (0) - -#define COM_INTERFACE_CAST(impltype, ifnamefrom, ifnameto, ifaceptr) \ - ICOM_INTERFACE(ICOM_OBJECT(impltype, ifnamefrom, ifaceptr), ifnameto) - -#endif /* _DDCOMIMPL_H_ */ - -#ifndef __WINE_DLLS_DDRAW_DDRAW_PRIVATE_H -#define __WINE_DLLS_DDRAW_DDRAW_PRIVATE_H - -/* MAY NOT CONTAIN X11 or DGA specific includes/defines/structs! */ - -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "wtypes.h" -#include "wingdi.h" -#include "winuser.h" -#include "ddraw.h" -#include "d3d.h" -#include "ddrawi.h" - -/* XXX Put this somewhere proper. */ -#define DD_STRUCT_INIT(x) \ - do { \ - memset((x), 0, sizeof(*(x))); \ - (x)->dwSize = sizeof(*x); \ - } while (0) - -#define DD_STRUCT_COPY_BYSIZE(to,from) \ - do { \ - DWORD __size = (to)->dwSize; \ - DWORD __copysize = __size; \ - DWORD __resetsize = __size; \ - if (__resetsize > sizeof(*to)) \ - __resetsize = sizeof(*to); \ - memset(to,0,__resetsize); \ - if ((from)->dwSize < __size) \ - __copysize = (from)->dwSize; \ - memcpy(to,from,__copysize); \ - (to)->dwSize = __size;/*restore size*/ \ - } while (0) - -#define MAKE_FOURCC(a,b,c,d) ((a << 0) | (b << 8) | (c << 16) | (d << 24)) - -/***************************************************************************** - * IDirectDraw implementation structure - */ - -typedef struct IDirectDrawImpl IDirectDrawImpl; -typedef struct IDirectDrawPaletteImpl IDirectDrawPaletteImpl; -typedef struct IDirectDrawClipperImpl IDirectDrawClipperImpl; -typedef struct IDirectDrawSurfaceImpl IDirectDrawSurfaceImpl; -typedef struct IDirect3DDeviceImpl IDirect3DDeviceImpl; - -typedef void (*pixel_convert_func)(void *src, void *dst, DWORD width, - DWORD height, LONG pitch, - IDirectDrawPaletteImpl *palette); - -typedef void (*palette_convert_func)(LPPALETTEENTRY palent, - void *screen_palette, DWORD start, - DWORD count); - -struct IDirectDrawImpl -{ - ICOM_VFIELD_MULTI(IDirectDraw7); - ICOM_VFIELD_MULTI(IDirectDraw4); - ICOM_VFIELD_MULTI(IDirectDraw2); - ICOM_VFIELD_MULTI(IDirectDraw); - ICOM_VFIELD_MULTI(IDirect3D7); - ICOM_VFIELD_MULTI(IDirect3D3); - ICOM_VFIELD_MULTI(IDirect3D2); - ICOM_VFIELD_MULTI(IDirect3D); - - DWORD ref; - - /* TRUE if created via DirectDrawCreateEx or CoCreateInstance, - * FALSE if created via DirectDrawCreate. */ - BOOL ex; - - /* Linked list of surfaces, joined by next_ddraw in IDirectSurfaceImpl. */ - IDirectDrawSurfaceImpl* surfaces; - /* Linked list of palettes, joined by next_ddraw. */ - IDirectDrawPaletteImpl* palettes; - /* Linked list of clippers, joined by next_ddraw. */ - IDirectDrawClipperImpl* clippers; - - IDirectDrawSurfaceImpl* primary_surface; - - DDRAWI_DIRECTDRAW_LCL local; - DDCAPS caps; - - HWND window; - DWORD cooperative_level; - WNDPROC original_wndproc; - - DWORD width, height; - LONG pitch; - DDPIXELFORMAT pixelformat; - DWORD cur_scanline; - - /* Should each of these go into some structure? */ - DWORD orig_width, orig_height; - LONG orig_pitch; - DDPIXELFORMAT orig_pixelformat; - - /* Called when the refcount goes to 0. */ - void (*final_release)(IDirectDrawImpl *This); - - HRESULT (*set_exclusive_mode)(IDirectDrawImpl *This, DWORD dwExcl); - - HRESULT (*create_palette)(IDirectDrawImpl* This, DWORD dwFlags, - LPDIRECTDRAWPALETTE* ppPalette, - LPUNKNOWN pUnkOuter); - - /* Surface creation functions. For all of these, pOuter == NULL. */ - - /* Do not create any backbuffers or the flipping chain. */ - HRESULT (*create_primary)(IDirectDrawImpl* This, - const DDSURFACEDESC2* pDDSD, - LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pOuter); - - /* Primary may be NULL if we are creating an unattached backbuffer. */ - HRESULT (*create_backbuffer)(IDirectDrawImpl* This, - const DDSURFACEDESC2* pDDSD, - LPDIRECTDRAWSURFACE7* ppSurf, - LPUNKNOWN pOuter, - IDirectDrawSurfaceImpl* primary); - - /* shiny happy offscreenplain surfaces */ - HRESULT (*create_offscreen)(IDirectDrawImpl* This, - const DDSURFACEDESC2* pDDSD, - LPDIRECTDRAWSURFACE7* ppSurf, - LPUNKNOWN pOuter); - - /* dwMipMapLevel is specified as per OpenGL. (i.e. 0 is base) */ - HRESULT (*create_texture)(IDirectDrawImpl* This, - const DDSURFACEDESC2* pDDSD, - LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pOuter, - DWORD dwMipMapLevel); - - HRESULT (*create_zbuffer)(IDirectDrawImpl* This, - const DDSURFACEDESC2* pDDSD, - LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pOuter); - - LPVOID private; - - /* Everything below here is still questionable. */ - - DDPIXELFORMAT screen_pixelformat; - - int pixmap_depth; - // pixel_convert_func pixel_convert; - // palette_convert_func palette_convert; - - /* Use to fool some too strict games */ - INT32 (*allocate_memory)(IDirectDrawImpl *This, DWORD mem); - void (*free_memory)(IDirectDrawImpl *This, DWORD mem); - DWORD total_vidmem, available_vidmem; - - /* IDirect3D fields */ - LPVOID d3d_private; - - /* Used as a callback function to create a texture */ - HRESULT (*d3d_create_texture)(IDirectDrawImpl *d3d, IDirectDrawSurfaceImpl *tex, BOOLEAN at_creation, IDirectDrawSurfaceImpl *main); - - /* Used as a callback for Devices to tell to the D3D object it's been created */ - HRESULT (*d3d_added_device)(IDirectDrawImpl *d3d, IDirect3DDeviceImpl *device); - HRESULT (*d3d_removed_device)(IDirectDrawImpl *d3d, IDirect3DDeviceImpl *device); - - /* This is needed for delayed texture creation and Z buffer blits */ - IDirect3DDeviceImpl *current_device; - - /* This is for the fake mainWindow */ - ATOM winclass; - PAINTSTRUCT ps; - BOOL paintable; -}; - -/***************************************************************************** - * IDirectDrawPalette implementation structure - */ -struct IDirectDrawPaletteImpl -{ - /* IUnknown fields */ - ICOM_VFIELD_MULTI(IDirectDrawPalette); - DWORD ref; - - DDRAWI_DDRAWPALETTE_LCL local; - DDRAWI_DDRAWPALETTE_GBL global; - - /* IDirectDrawPalette fields */ - HPALETTE hpal; - WORD palVersion, palNumEntries; /* LOGPALETTE */ - PALETTEENTRY palents[256]; - /* This is to store the palette in 'screen format' */ - int screen_palents[256]; - - VOID (*final_release)(IDirectDrawPaletteImpl* This); - - IDirectDrawImpl* ddraw_owner; - IDirectDrawPaletteImpl* prev_ddraw; - IDirectDrawPaletteImpl* next_ddraw; - - LPVOID private; -}; - -/***************************************************************************** - * IDirectDrawClipper implementation structure - */ -struct IDirectDrawClipperImpl -{ - /* IUnknown fields */ - ICOM_VFIELD_MULTI(IDirectDrawClipper); - DWORD ref; - - /* IDirectDrawClipper fields */ - HWND hWnd; - - IDirectDrawImpl* ddraw_owner; - IDirectDrawClipperImpl* prev_ddraw; - IDirectDrawClipperImpl* next_ddraw; -}; - -/***************************************************************************** - * IDirectDrawSurface implementation structure - */ - -struct IDirectDrawSurfaceImpl -{ - /* IUnknown fields */ - ICOM_VFIELD_MULTI(IDirectDrawSurface7); - ICOM_VFIELD_MULTI(IDirectDrawSurface3); - ICOM_VFIELD_MULTI(IDirectDrawGammaControl); - ICOM_VFIELD_MULTI(IDirect3DTexture2); - ICOM_VFIELD_MULTI(IDirect3DTexture); - DWORD ref; - - struct IDirectDrawSurfaceImpl* attached; /* attached surfaces */ - - struct IDirectDrawSurfaceImpl* next_ddraw; /* ddraw surface chain */ - struct IDirectDrawSurfaceImpl* prev_ddraw; - struct IDirectDrawSurfaceImpl* next_attached; /* attached surface chain */ - struct IDirectDrawSurfaceImpl* prev_attached; - - IDirectDrawImpl* ddraw_owner; - IDirectDrawSurfaceImpl* surface_owner; - - IDirectDrawPaletteImpl* palette; /* strong ref */ - IDirectDrawClipperImpl* clipper; /* strong ref */ - - DDRAWI_DDRAWSURFACE_LCL local; - DDRAWI_DDRAWSURFACE_MORE more; - /* FIXME: since Flip should swap the GBL structures, they should - * probably not be embedded into the IDirectDrawSurfaceImpl structure... */ - LPDDRAWI_DDRAWSURFACE_GBL_MORE gmore; - DDRAWI_DDRAWSURFACE_GBL global; - DDRAWI_DDRAWSURFACE_GBL_MORE global_more; - - DDSURFACEDESC2 surface_desc; - - HDC hDC; - RECT lastlockrect; - DWORD lastlocktype; - BOOL dc_in_use; - BOOL locked; - - HRESULT (*duplicate_surface)(IDirectDrawSurfaceImpl* src, - LPDIRECTDRAWSURFACE7* dst); - void (*final_release)(IDirectDrawSurfaceImpl *This); - HRESULT (*late_allocate)(IDirectDrawSurfaceImpl *This); - BOOL (*attach)(IDirectDrawSurfaceImpl *This, IDirectDrawSurfaceImpl *to); - BOOL (*detach)(IDirectDrawSurfaceImpl *This); - void (*lock_update)(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags); - void (*unlock_update)(IDirectDrawSurfaceImpl* This, LPCRECT pRect); - void (*lose_surface)(IDirectDrawSurfaceImpl* This); - BOOL (*flip_data)(IDirectDrawSurfaceImpl* front, - IDirectDrawSurfaceImpl* back, - DWORD dwFlags); - void (*flip_update)(IDirectDrawSurfaceImpl* front, DWORD dwFlags); - HRESULT (*get_dc)(IDirectDrawSurfaceImpl* This, HDC* phDC); - HRESULT (*release_dc)(IDirectDrawSurfaceImpl* This, HDC hDC); - void (*set_palette)(IDirectDrawSurfaceImpl* This, IDirectDrawPaletteImpl* pal); - void (*update_palette)(IDirectDrawSurfaceImpl* This, IDirectDrawPaletteImpl* pal, - DWORD dwStart, DWORD dwCount, LPPALETTEENTRY palent); - HWND (*get_display_window)(IDirectDrawSurfaceImpl *This); - HRESULT (*get_gamma_ramp)(IDirectDrawSurfaceImpl *This, DWORD dwFlags, LPDDGAMMARAMP lpGammaRamp); - HRESULT (*set_gamma_ramp)(IDirectDrawSurfaceImpl *This, DWORD dwFlags, LPDDGAMMARAMP lpGammaRamp); - - struct PrivateData* private_data; - - DWORD max_lod; - DWORD priority; - - BOOL lost; - - DWORD uniqueness_value; - - LPVOID private; - - /* Everything below here is dodgy. */ - /* For Direct3D use */ - LPVOID aux_ctx, aux_data; - void (*aux_release)(LPVOID ctx, LPVOID data); - BOOL (*aux_flip)(LPVOID ctx, LPVOID data); - void (*aux_unlock)(LPVOID ctx, LPVOID data, LPRECT lpRect); - HRESULT (*aux_blt)(struct IDirectDrawSurfaceImpl *This, LPRECT rdst, LPDIRECTDRAWSURFACE7 src, LPRECT rsrc, DWORD dwFlags, LPDDBLTFX lpbltfx); - HRESULT (*aux_bltfast)(struct IDirectDrawSurfaceImpl *This, DWORD dstx, DWORD dsty, LPDIRECTDRAWSURFACE7 src, LPRECT rsrc, DWORD trans); - HRESULT (*aux_setcolorkey_cb)(struct IDirectDrawSurfaceImpl *texture, DWORD dwFlags, LPDDCOLORKEY ckey ); - /* This is to get the D3DDevice object associated to this surface */ - struct IDirect3DDeviceImpl *d3ddevice; - /* This is for texture */ - IDirectDrawSurfaceImpl *mip_main; - int mipmap_level; - LPVOID tex_private; - void (*lock_update_prev)(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags); - void (*unlock_update_prev)(IDirectDrawSurfaceImpl* This, LPCRECT pRect); - BOOLEAN (*get_dirty_status)(IDirectDrawSurfaceImpl* This, LPCRECT pRect); -}; - -/***************************************************************************** - * Driver initialisation functions. - */ -BOOL DDRAW_HAL_Init(HINSTANCE, DWORD, LPVOID); -BOOL DDRAW_User_Init(HINSTANCE, DWORD, LPVOID); - -typedef struct { - const DDDEVICEIDENTIFIER2* info; - int preference; /* how good we are. dga might get 100, xlib 50*/ - HRESULT (*create)(const GUID*, LPDIRECTDRAW7*, LPUNKNOWN, BOOL ex); - - /* For IDirectDraw7::Initialize. */ - HRESULT (*init)(IDirectDrawImpl *, const GUID*); -} ddraw_driver; - -void DDRAW_register_driver(const ddraw_driver*); - -const ddraw_driver* DDRAW_FindDriver(const GUID* guid); - -/****************************************************************************** - * Random utilities - */ - -/* Get DDSCAPS of surface (shortcutmacro) */ -#define SDDSCAPS(iface) ((iface)->s.surface_desc.ddsCaps.dwCaps) -/* Get the number of bytes per pixel for a given surface */ -#define PFGET_BPP(pf) (pf.dwFlags&DDPF_PALETTEINDEXED8?1:((pf.u1.dwRGBBitCount+7)/8)) -#define GET_BPP(desc) PFGET_BPP(desc.u4.ddpfPixelFormat) - -LONG DDRAW_width_bpp_to_pitch(DWORD width, DWORD bpp); - -typedef struct { - unsigned short bpp,depth; - unsigned int rmask,gmask,bmask; -} ConvertMode; - -typedef struct { - void (*pixel_convert)(void *src, void *dst, DWORD width, DWORD height, LONG pitch, IDirectDrawPaletteImpl* palette); - void (*palette_convert)(LPPALETTEENTRY palent, void *screen_palette, DWORD start, DWORD count); -} ConvertFuncs; - -typedef struct { - ConvertMode screen, dest; - ConvertFuncs funcs; -} Convert; - -extern Convert ModeEmulations[8]; -extern int _common_depth_to_pixelformat(DWORD depth,LPDIRECTDRAW ddraw); -extern BOOL opengl_initialized; -extern BOOL s3tc_initialized; - -typedef void (*FUNC_FETCH_2D_TEXEL_RGBA_DXT1)(int srcRowStride, const BYTE *pixdata, int i, int j, void *texel); -typedef void (*FUNC_FETCH_2D_TEXEL_RGBA_DXT3)(int srcRowStride, const BYTE *pixdata, int i, int j, void *texel); -typedef void (*FUNC_FETCH_2D_TEXEL_RGBA_DXT5)(int srcRowStride, const BYTE *pixdata, int i, int j, void *texel); - -extern FUNC_FETCH_2D_TEXEL_RGBA_DXT1 fetch_2d_texel_rgba_dxt1; -extern FUNC_FETCH_2D_TEXEL_RGBA_DXT3 fetch_2d_texel_rgba_dxt3; -extern FUNC_FETCH_2D_TEXEL_RGBA_DXT5 fetch_2d_texel_rgba_dxt5; - -/****************************************************************************** - * Structure conversion (for thunks) - */ -void DDRAW_Convert_DDSCAPS_1_To_2(const DDSCAPS* pIn, DDSCAPS2* pOut); -void DDRAW_Convert_DDDEVICEIDENTIFIER_2_To_1(const DDDEVICEIDENTIFIER2* pIn, - DDDEVICEIDENTIFIER* pOut); - -/****************************************************************************** - * Debugging / Flags output functions - */ -extern void DDRAW_dump_DDBLTFX(DWORD flagmask); -extern void DDRAW_dump_DDBLTFAST(DWORD flagmask); -extern void DDRAW_dump_DDBLT(DWORD flagmask); -extern void DDRAW_dump_DDSCAPS(const DDSCAPS *in); -extern void DDRAW_dump_DDSCAPS2(const DDSCAPS2 *in); -extern void DDRAW_dump_pixelformat_flag(DWORD flagmask); -extern void DDRAW_dump_paletteformat(DWORD dwFlags); -extern void DDRAW_dump_pixelformat(const DDPIXELFORMAT *in); -extern void DDRAW_dump_colorkeyflag(DWORD ck); -extern void DDRAW_dump_surface_desc(const DDSURFACEDESC2 *lpddsd); -extern void DDRAW_dump_cooperativelevel(DWORD cooplevel); -extern void DDRAW_dump_lockflag(DWORD lockflag); -extern void DDRAW_dump_DDCOLORKEY(const DDCOLORKEY *in); -extern void DDRAW_dump_DDCAPS(const DDCAPS *lpcaps); -extern void DDRAW_dump_surface_to_disk(IDirectDrawSurfaceImpl *surface, FILE *f, int scale) ; - -/* Used for generic dumping */ -typedef struct -{ - DWORD val; - const char* name; -} flag_info; - -#define FE(x) { x, #x } - -typedef struct -{ - DWORD val; - const char* name; - void (*func)(const void *); - ptrdiff_t offset; -} member_info; - -#define DDRAW_dump_flags(flags,names,num_names) DDRAW_dump_flags_(flags, names, num_names, 1) -#define ME(x,f,e) { x, #x, (void (*)(const void *))(f), offsetof(STRUCT, e) } - -extern void DDRAW_dump_flags_(DWORD flags, const flag_info* names, size_t num_names, int newline); -extern void DDRAW_dump_members(DWORD flags, const void* data, const member_info* mems, size_t num_mems); - - -#endif /* __WINE_DLLS_DDRAW_DDRAW_PRIVATE_H */ +/* + * Copyright 2000-2001 TransGaming Technologies Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _DDCOMIMPL_H_ +#define _DDCOMIMPL_H_ + +#include + +/* Generates the name for a vtable pointer for a given interface. */ +/* The canonical name for a single interface is "lpVtbl". */ +#define ICOM_VFIELD_MULTI_NAME2(iface) ITF_##iface +#define ICOM_VFIELD_MULTI_NAME(iface) ICOM_VFIELD_MULTI_NAME2(iface) + +/* Declares a vtable pointer field in an implementation. */ +#define ICOM_VFIELD_MULTI(iface) \ + iface ICOM_VFIELD_MULTI_NAME(iface) + +/* Returns the offset of a vtable pointer within an implementation object. */ +#define ICOM_VFIELD_OFFSET(impltype, iface) \ + offsetof(impltype, ICOM_VFIELD_MULTI_NAME(iface)) + +/* Given an interface pointer, returns the implementation pointer. */ +#define ICOM_OBJECT(impltype, ifacename, ifaceptr) \ + (impltype*)((ifaceptr) == NULL ? NULL \ + : (char*)(ifaceptr) - ICOM_VFIELD_OFFSET(impltype,ifacename)) + +#define ICOM_THIS_FROM(impltype, ifacename, ifaceptr) \ + impltype* This = ICOM_OBJECT(impltype, ifacename, ifaceptr) + +/* Given an object and interface name, returns a pointer to that interface. */ +#define ICOM_INTERFACE(implobj, iface) \ + (&((implobj)->ICOM_VFIELD_MULTI_NAME(iface))) + +#define ICOM_INIT_INTERFACE(implobj, ifacename, vtblname) \ + do { \ + (implobj)->ICOM_VFIELD_MULTI_NAME(ifacename).lpVtbl = &(vtblname); \ + } while (0) + +#define COM_INTERFACE_CAST(impltype, ifnamefrom, ifnameto, ifaceptr) \ + ICOM_INTERFACE(ICOM_OBJECT(impltype, ifnamefrom, ifaceptr), ifnameto) + +#endif /* _DDCOMIMPL_H_ */ + +#ifndef __WINE_DLLS_DDRAW_DDRAW_PRIVATE_H +#define __WINE_DLLS_DDRAW_DDRAW_PRIVATE_H + +/* MAY NOT CONTAIN X11 or DGA specific includes/defines/structs! */ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wtypes.h" +#include "wingdi.h" +#include "winuser.h" +#include "ddraw.h" +#include "d3d.h" +#include "ddrawi.h" + +/* XXX Put this somewhere proper. */ +#define DD_STRUCT_INIT(x) \ + do { \ + memset((x), 0, sizeof(*(x))); \ + (x)->dwSize = sizeof(*x); \ + } while (0) + +#define DD_STRUCT_COPY_BYSIZE(to,from) \ + do { \ + DWORD __size = (to)->dwSize; \ + DWORD __copysize = __size; \ + DWORD __resetsize = __size; \ + if (__resetsize > sizeof(*to)) \ + __resetsize = sizeof(*to); \ + memset(to,0,__resetsize); \ + if ((from)->dwSize < __size) \ + __copysize = (from)->dwSize; \ + memcpy(to,from,__copysize); \ + (to)->dwSize = __size;/*restore size*/ \ + } while (0) + +#define MAKE_FOURCC(a,b,c,d) ((a << 0) | (b << 8) | (c << 16) | (d << 24)) + +/***************************************************************************** + * IDirectDraw implementation structure + */ + +typedef struct IDirectDrawImpl IDirectDrawImpl; +typedef struct IDirectDrawPaletteImpl IDirectDrawPaletteImpl; +typedef struct IDirectDrawClipperImpl IDirectDrawClipperImpl; +typedef struct IDirectDrawSurfaceImpl IDirectDrawSurfaceImpl; +typedef struct IDirect3DDeviceImpl IDirect3DDeviceImpl; + +typedef void (*pixel_convert_func)(void *src, void *dst, DWORD width, + DWORD height, LONG pitch, + IDirectDrawPaletteImpl *palette); + +typedef void (*palette_convert_func)(LPPALETTEENTRY palent, + void *screen_palette, DWORD start, + DWORD count); + +struct IDirectDrawImpl +{ + ICOM_VFIELD_MULTI(IDirectDraw7); + ICOM_VFIELD_MULTI(IDirectDraw4); + ICOM_VFIELD_MULTI(IDirectDraw2); + ICOM_VFIELD_MULTI(IDirectDraw); + ICOM_VFIELD_MULTI(IDirect3D7); + ICOM_VFIELD_MULTI(IDirect3D3); + ICOM_VFIELD_MULTI(IDirect3D2); + ICOM_VFIELD_MULTI(IDirect3D); + + DWORD ref; + + /* TRUE if created via DirectDrawCreateEx or CoCreateInstance, + * FALSE if created via DirectDrawCreate. */ + BOOL ex; + + /* Linked list of surfaces, joined by next_ddraw in IDirectSurfaceImpl. */ + IDirectDrawSurfaceImpl* surfaces; + /* Linked list of palettes, joined by next_ddraw. */ + IDirectDrawPaletteImpl* palettes; + /* Linked list of clippers, joined by next_ddraw. */ + IDirectDrawClipperImpl* clippers; + + IDirectDrawSurfaceImpl* primary_surface; + + DDRAWI_DIRECTDRAW_LCL local; + DDCAPS caps; + + HWND window; + DWORD cooperative_level; + WNDPROC original_wndproc; + + DWORD width, height; + LONG pitch; + DDPIXELFORMAT pixelformat; + DWORD cur_scanline; + + /* Should each of these go into some structure? */ + DWORD orig_width, orig_height; + LONG orig_pitch; + DDPIXELFORMAT orig_pixelformat; + + /* Called when the refcount goes to 0. */ + void (*final_release)(IDirectDrawImpl *This); + + HRESULT (*set_exclusive_mode)(IDirectDrawImpl *This, DWORD dwExcl); + + HRESULT (*create_palette)(IDirectDrawImpl* This, DWORD dwFlags, + LPDIRECTDRAWPALETTE* ppPalette, + LPUNKNOWN pUnkOuter); + + /* Surface creation functions. For all of these, pOuter == NULL. */ + + /* Do not create any backbuffers or the flipping chain. */ + HRESULT (*create_primary)(IDirectDrawImpl* This, + const DDSURFACEDESC2* pDDSD, + LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pOuter); + + /* Primary may be NULL if we are creating an unattached backbuffer. */ + HRESULT (*create_backbuffer)(IDirectDrawImpl* This, + const DDSURFACEDESC2* pDDSD, + LPDIRECTDRAWSURFACE7* ppSurf, + LPUNKNOWN pOuter, + IDirectDrawSurfaceImpl* primary); + + /* shiny happy offscreenplain surfaces */ + HRESULT (*create_offscreen)(IDirectDrawImpl* This, + const DDSURFACEDESC2* pDDSD, + LPDIRECTDRAWSURFACE7* ppSurf, + LPUNKNOWN pOuter); + + /* dwMipMapLevel is specified as per OpenGL. (i.e. 0 is base) */ + HRESULT (*create_texture)(IDirectDrawImpl* This, + const DDSURFACEDESC2* pDDSD, + LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pOuter, + DWORD dwMipMapLevel); + + HRESULT (*create_zbuffer)(IDirectDrawImpl* This, + const DDSURFACEDESC2* pDDSD, + LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pOuter); + + LPVOID private; + + /* Everything below here is still questionable. */ + + DDPIXELFORMAT screen_pixelformat; + + int pixmap_depth; + // pixel_convert_func pixel_convert; + // palette_convert_func palette_convert; + + /* Use to fool some too strict games */ + INT32 (*allocate_memory)(IDirectDrawImpl *This, DWORD mem); + void (*free_memory)(IDirectDrawImpl *This, DWORD mem); + DWORD total_vidmem, available_vidmem; + + /* IDirect3D fields */ + LPVOID d3d_private; + + /* Used as a callback function to create a texture */ + HRESULT (*d3d_create_texture)(IDirectDrawImpl *d3d, IDirectDrawSurfaceImpl *tex, BOOLEAN at_creation, IDirectDrawSurfaceImpl *main); + + /* Used as a callback for Devices to tell to the D3D object it's been created */ + HRESULT (*d3d_added_device)(IDirectDrawImpl *d3d, IDirect3DDeviceImpl *device); + HRESULT (*d3d_removed_device)(IDirectDrawImpl *d3d, IDirect3DDeviceImpl *device); + + /* This is needed for delayed texture creation and Z buffer blits */ + IDirect3DDeviceImpl *current_device; + + /* This is for the fake mainWindow */ + ATOM winclass; + PAINTSTRUCT ps; + BOOL paintable; +}; + +/***************************************************************************** + * IDirectDrawPalette implementation structure + */ +struct IDirectDrawPaletteImpl +{ + /* IUnknown fields */ + ICOM_VFIELD_MULTI(IDirectDrawPalette); + DWORD ref; + + DDRAWI_DDRAWPALETTE_LCL local; + DDRAWI_DDRAWPALETTE_GBL global; + + /* IDirectDrawPalette fields */ + HPALETTE hpal; + WORD palVersion, palNumEntries; /* LOGPALETTE */ + PALETTEENTRY palents[256]; + /* This is to store the palette in 'screen format' */ + int screen_palents[256]; + + VOID (*final_release)(IDirectDrawPaletteImpl* This); + + IDirectDrawImpl* ddraw_owner; + IDirectDrawPaletteImpl* prev_ddraw; + IDirectDrawPaletteImpl* next_ddraw; + + LPVOID private; +}; + +/***************************************************************************** + * IDirectDrawClipper implementation structure + */ +struct IDirectDrawClipperImpl +{ + /* IUnknown fields */ + ICOM_VFIELD_MULTI(IDirectDrawClipper); + DWORD ref; + + /* IDirectDrawClipper fields */ + HWND hWnd; + + IDirectDrawImpl* ddraw_owner; + IDirectDrawClipperImpl* prev_ddraw; + IDirectDrawClipperImpl* next_ddraw; +}; + +/***************************************************************************** + * IDirectDrawSurface implementation structure + */ + +struct IDirectDrawSurfaceImpl +{ + /* IUnknown fields */ + ICOM_VFIELD_MULTI(IDirectDrawSurface7); + ICOM_VFIELD_MULTI(IDirectDrawSurface3); + ICOM_VFIELD_MULTI(IDirectDrawGammaControl); + ICOM_VFIELD_MULTI(IDirect3DTexture2); + ICOM_VFIELD_MULTI(IDirect3DTexture); + DWORD ref; + + struct IDirectDrawSurfaceImpl* attached; /* attached surfaces */ + + struct IDirectDrawSurfaceImpl* next_ddraw; /* ddraw surface chain */ + struct IDirectDrawSurfaceImpl* prev_ddraw; + struct IDirectDrawSurfaceImpl* next_attached; /* attached surface chain */ + struct IDirectDrawSurfaceImpl* prev_attached; + + IDirectDrawImpl* ddraw_owner; + IDirectDrawSurfaceImpl* surface_owner; + + IDirectDrawPaletteImpl* palette; /* strong ref */ + IDirectDrawClipperImpl* clipper; /* strong ref */ + + DDRAWI_DDRAWSURFACE_LCL local; + DDRAWI_DDRAWSURFACE_MORE more; + /* FIXME: since Flip should swap the GBL structures, they should + * probably not be embedded into the IDirectDrawSurfaceImpl structure... */ + LPDDRAWI_DDRAWSURFACE_GBL_MORE gmore; + DDRAWI_DDRAWSURFACE_GBL global; + DDRAWI_DDRAWSURFACE_GBL_MORE global_more; + + DDSURFACEDESC2 surface_desc; + + HDC hDC; + RECT lastlockrect; + DWORD lastlocktype; + BOOL dc_in_use; + BOOL locked; + + HRESULT (*duplicate_surface)(IDirectDrawSurfaceImpl* src, + LPDIRECTDRAWSURFACE7* dst); + void (*final_release)(IDirectDrawSurfaceImpl *This); + HRESULT (*late_allocate)(IDirectDrawSurfaceImpl *This); + BOOL (*attach)(IDirectDrawSurfaceImpl *This, IDirectDrawSurfaceImpl *to); + BOOL (*detach)(IDirectDrawSurfaceImpl *This); + void (*lock_update)(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags); + void (*unlock_update)(IDirectDrawSurfaceImpl* This, LPCRECT pRect); + void (*lose_surface)(IDirectDrawSurfaceImpl* This); + BOOL (*flip_data)(IDirectDrawSurfaceImpl* front, + IDirectDrawSurfaceImpl* back, + DWORD dwFlags); + void (*flip_update)(IDirectDrawSurfaceImpl* front, DWORD dwFlags); + HRESULT (*get_dc)(IDirectDrawSurfaceImpl* This, HDC* phDC); + HRESULT (*release_dc)(IDirectDrawSurfaceImpl* This, HDC hDC); + void (*set_palette)(IDirectDrawSurfaceImpl* This, IDirectDrawPaletteImpl* pal); + void (*update_palette)(IDirectDrawSurfaceImpl* This, IDirectDrawPaletteImpl* pal, + DWORD dwStart, DWORD dwCount, LPPALETTEENTRY palent); + HWND (*get_display_window)(IDirectDrawSurfaceImpl *This); + HRESULT (*get_gamma_ramp)(IDirectDrawSurfaceImpl *This, DWORD dwFlags, LPDDGAMMARAMP lpGammaRamp); + HRESULT (*set_gamma_ramp)(IDirectDrawSurfaceImpl *This, DWORD dwFlags, LPDDGAMMARAMP lpGammaRamp); + + struct PrivateData* private_data; + + DWORD max_lod; + DWORD priority; + + BOOL lost; + + DWORD uniqueness_value; + + LPVOID private; + + /* Everything below here is dodgy. */ + /* For Direct3D use */ + LPVOID aux_ctx, aux_data; + void (*aux_release)(LPVOID ctx, LPVOID data); + BOOL (*aux_flip)(LPVOID ctx, LPVOID data); + void (*aux_unlock)(LPVOID ctx, LPVOID data, LPRECT lpRect); + HRESULT (*aux_blt)(struct IDirectDrawSurfaceImpl *This, LPRECT rdst, LPDIRECTDRAWSURFACE7 src, LPRECT rsrc, DWORD dwFlags, LPDDBLTFX lpbltfx); + HRESULT (*aux_bltfast)(struct IDirectDrawSurfaceImpl *This, DWORD dstx, DWORD dsty, LPDIRECTDRAWSURFACE7 src, LPRECT rsrc, DWORD trans); + HRESULT (*aux_setcolorkey_cb)(struct IDirectDrawSurfaceImpl *texture, DWORD dwFlags, LPDDCOLORKEY ckey ); + /* This is to get the D3DDevice object associated to this surface */ + struct IDirect3DDeviceImpl *d3ddevice; + /* This is for texture */ + IDirectDrawSurfaceImpl *mip_main; + int mipmap_level; + LPVOID tex_private; + void (*lock_update_prev)(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags); + void (*unlock_update_prev)(IDirectDrawSurfaceImpl* This, LPCRECT pRect); + BOOLEAN (*get_dirty_status)(IDirectDrawSurfaceImpl* This, LPCRECT pRect); +}; + +/***************************************************************************** + * Driver initialisation functions. + */ +BOOL DDRAW_HAL_Init(HINSTANCE, DWORD, LPVOID); +BOOL DDRAW_User_Init(HINSTANCE, DWORD, LPVOID); + +typedef struct { + const DDDEVICEIDENTIFIER2* info; + int preference; /* how good we are. dga might get 100, xlib 50*/ + HRESULT (*create)(const GUID*, LPDIRECTDRAW7*, LPUNKNOWN, BOOL ex); + + /* For IDirectDraw7::Initialize. */ + HRESULT (*init)(IDirectDrawImpl *, const GUID*); +} ddraw_driver; + +void DDRAW_register_driver(const ddraw_driver*); + +const ddraw_driver* DDRAW_FindDriver(const GUID* guid); + +/****************************************************************************** + * Random utilities + */ + +/* Get DDSCAPS of surface (shortcutmacro) */ +#define SDDSCAPS(iface) ((iface)->s.surface_desc.ddsCaps.dwCaps) +/* Get the number of bytes per pixel for a given surface */ +#define PFGET_BPP(pf) (pf.dwFlags&DDPF_PALETTEINDEXED8?1:((pf.u1.dwRGBBitCount+7)/8)) +#define GET_BPP(desc) PFGET_BPP(desc.u4.ddpfPixelFormat) + +LONG DDRAW_width_bpp_to_pitch(DWORD width, DWORD bpp); + +typedef struct { + unsigned short bpp,depth; + unsigned int rmask,gmask,bmask; +} ConvertMode; + +typedef struct { + void (*pixel_convert)(void *src, void *dst, DWORD width, DWORD height, LONG pitch, IDirectDrawPaletteImpl* palette); + void (*palette_convert)(LPPALETTEENTRY palent, void *screen_palette, DWORD start, DWORD count); +} ConvertFuncs; + +typedef struct { + ConvertMode screen, dest; + ConvertFuncs funcs; +} Convert; + +extern Convert ModeEmulations[8]; +extern int _common_depth_to_pixelformat(DWORD depth,LPDIRECTDRAW ddraw); +extern BOOL opengl_initialized; +extern BOOL s3tc_initialized; + +typedef void (*FUNC_FETCH_2D_TEXEL_RGBA_DXT1)(int srcRowStride, const BYTE *pixdata, int i, int j, void *texel); +typedef void (*FUNC_FETCH_2D_TEXEL_RGBA_DXT3)(int srcRowStride, const BYTE *pixdata, int i, int j, void *texel); +typedef void (*FUNC_FETCH_2D_TEXEL_RGBA_DXT5)(int srcRowStride, const BYTE *pixdata, int i, int j, void *texel); + +extern FUNC_FETCH_2D_TEXEL_RGBA_DXT1 fetch_2d_texel_rgba_dxt1; +extern FUNC_FETCH_2D_TEXEL_RGBA_DXT3 fetch_2d_texel_rgba_dxt3; +extern FUNC_FETCH_2D_TEXEL_RGBA_DXT5 fetch_2d_texel_rgba_dxt5; + +/****************************************************************************** + * Structure conversion (for thunks) + */ +void DDRAW_Convert_DDSCAPS_1_To_2(const DDSCAPS* pIn, DDSCAPS2* pOut); +void DDRAW_Convert_DDDEVICEIDENTIFIER_2_To_1(const DDDEVICEIDENTIFIER2* pIn, + DDDEVICEIDENTIFIER* pOut); + +/****************************************************************************** + * Debugging / Flags output functions + */ +extern void DDRAW_dump_DDBLTFX(DWORD flagmask); +extern void DDRAW_dump_DDBLTFAST(DWORD flagmask); +extern void DDRAW_dump_DDBLT(DWORD flagmask); +extern void DDRAW_dump_DDSCAPS(const DDSCAPS *in); +extern void DDRAW_dump_DDSCAPS2(const DDSCAPS2 *in); +extern void DDRAW_dump_pixelformat_flag(DWORD flagmask); +extern void DDRAW_dump_paletteformat(DWORD dwFlags); +extern void DDRAW_dump_pixelformat(const DDPIXELFORMAT *in); +extern void DDRAW_dump_colorkeyflag(DWORD ck); +extern void DDRAW_dump_surface_desc(const DDSURFACEDESC2 *lpddsd); +extern void DDRAW_dump_cooperativelevel(DWORD cooplevel); +extern void DDRAW_dump_lockflag(DWORD lockflag); +extern void DDRAW_dump_DDCOLORKEY(const DDCOLORKEY *in); +extern void DDRAW_dump_DDCAPS(const DDCAPS *lpcaps); +extern void DDRAW_dump_surface_to_disk(IDirectDrawSurfaceImpl *surface, FILE *f, int scale) ; + +/* Used for generic dumping */ +typedef struct +{ + DWORD val; + const char* name; +} flag_info; + +#define FE(x) { x, #x } + +typedef struct +{ + DWORD val; + const char* name; + void (*func)(const void *); + ptrdiff_t offset; +} member_info; + +#define DDRAW_dump_flags(flags,names,num_names) DDRAW_dump_flags_(flags, names, num_names, 1) +#define ME(x,f,e) { x, #x, (void (*)(const void *))(f), offsetof(STRUCT, e) } + +extern void DDRAW_dump_flags_(DWORD flags, const flag_info* names, size_t num_names, int newline); +extern void DDRAW_dump_members(DWORD flags, const void* data, const member_info* mems, size_t num_mems); + + +#endif /* __WINE_DLLS_DDRAW_DDRAW_PRIVATE_H */ diff --git a/reactos/lib/ddraw/ddraw_user.c b/reactos/lib/ddraw/ddraw_user.c index a956854d708..14bb379cba0 100644 --- a/reactos/lib/ddraw/ddraw_user.c +++ b/reactos/lib/ddraw/ddraw_user.c @@ -19,8 +19,8 @@ -#include -#include "ddraw.h" +#include +#include "ddraw.h" #include "rosddraw.h" #include "ddraw_private.h" diff --git a/reactos/lib/ddraw/rosddraw.h b/reactos/lib/ddraw/rosddraw.h index 670affe569f..d96309f8d4c 100644 --- a/reactos/lib/ddraw/rosddraw.h +++ b/reactos/lib/ddraw/rosddraw.h @@ -1,47 +1,47 @@ -/* - * - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: lib/ddraw/ddraw.c - * PURPOSE: ddraw lib - * PROGRAMMER: Magnus Olsen - * UPDATE HISTORY: - */ -#include "ddraw_private.h" - - - -HANDLE STDCALL OsThunkDdCreateDirectDrawObject(HDC hdc); - - -void HAL_DirectDraw_final_release(IDirectDrawImpl *This); -HRESULT HAL_DirectDrawSet_exclusive_mode(IDirectDrawImpl *This, DWORD dwEnterExcl); - - - - - +/* + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: lib/ddraw/ddraw.c + * PURPOSE: ddraw lib + * PROGRAMMER: Magnus Olsen + * UPDATE HISTORY: + */ +#include "ddraw_private.h" + + + +HANDLE STDCALL OsThunkDdCreateDirectDrawObject(HDC hdc); + + +void HAL_DirectDraw_final_release(IDirectDrawImpl *This); +HRESULT HAL_DirectDrawSet_exclusive_mode(IDirectDrawImpl *This, DWORD dwEnterExcl); + + + + + HRESULT HAL_DirectDraw_create_primary(IDirectDrawImpl* This, const DDSURFACEDESC2* pDDSD, LPDIRECTDRAWSURFACE7* ppSurf, - IUnknown* pUnkOuter); - + IUnknown* pUnkOuter); + HRESULT HAL_DirectDraw_create_backbuffer(IDirectDrawImpl* This, const DDSURFACEDESC2* pDDSD, LPDIRECTDRAWSURFACE7* ppSurf, IUnknown* pUnkOuter, - IDirectDrawSurfaceImpl* primary); - + IDirectDrawSurfaceImpl* primary); + HRESULT HAL_DirectDraw_create_texture(IDirectDrawImpl* This, const DDSURFACEDESC2* pDDSD, LPDIRECTDRAWSURFACE7* ppSurf, LPUNKNOWN pOuter, - DWORD dwMipMapLevel); - -HRESULT DDRAW_Create(LPGUID lpGUID, LPVOID *lplpDD, LPUNKNOWN pUnkOuter, REFIID iid, BOOL ex); - - + DWORD dwMipMapLevel); + +HRESULT DDRAW_Create(LPGUID lpGUID, LPVOID *lplpDD, LPUNKNOWN pUnkOuter, REFIID iid, BOOL ex); + + HRESULT WINAPI HAL7_DirectDraw_CreateClipper(LPDIRECTDRAW7 iface, DWORD dwFlags, - LPDIRECTDRAWCLIPPER *ppClipper, IUnknown *pUnkOuter); - + LPDIRECTDRAWCLIPPER *ppClipper, IUnknown *pUnkOuter); + HRESULT WINAPI HAL7_DirectDraw_QueryInterface(LPDIRECTDRAW7 iface,REFIID refiid,LPVOID *obj) ; ULONG WINAPI HAL7_DirectDraw_AddRef(LPDIRECTDRAW7 iface) ; @@ -122,4 +122,4 @@ HRESULT WINAPI HAL7_DirectDraw_EvaluateMode(LPDIRECTDRAW7 iface,DWORD a,DWORD* b HRESULT WINAPI HAL7_DirectDraw_Create(const GUID* pGUID, LPDIRECTDRAW7* pIface, - IUnknown* pUnkOuter, BOOL ex); + IUnknown* pUnkOuter, BOOL ex); diff --git a/reactos/lib/dinput/data_formats.c b/reactos/lib/dinput/data_formats.c index 7962a67b187..e2c831581ed 100644 --- a/reactos/lib/dinput/data_formats.c +++ b/reactos/lib/dinput/data_formats.c @@ -1,302 +1,302 @@ -/* - * Copyright (c) 2004 Robert Reif - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* TODO: - * add keyboard - */ - -#include - -#include "windef.h" -#include "dinput.h" - -#define numObjects(x) (sizeof(x) / sizeof(x[0])) - -DIOBJECTDATAFORMAT dfDIJoystick[] = { - { &GUID_XAxis,DIJOFS_X,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_YAxis,DIJOFS_Y,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_ZAxis,DIJOFS_Z,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_RxAxis,DIJOFS_RX,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_RyAxis,DIJOFS_RY,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_RzAxis,DIJOFS_RZ,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_Slider,DIJOFS_SLIDER(0),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_Slider,DIJOFS_SLIDER(1),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_POV,DIJOFS_POV(0),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, - { &GUID_POV,DIJOFS_POV(1),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, - { &GUID_POV,DIJOFS_POV(2),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, - { &GUID_POV,DIJOFS_POV(3),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(0),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(1),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(2),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(3),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(4),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(5),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(6),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(7),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(8),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(9),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(10),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(11),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(12),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(13),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(14),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(15),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(16),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(17),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(18),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(19),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(20),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(21),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(22),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(23),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(24),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(25),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(26),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(27),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(28),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(29),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(30),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(31),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, -}; - -const DIDATAFORMAT c_dfDIJoystick = { - sizeof(DIDATAFORMAT), - sizeof(DIOBJECTDATAFORMAT), - DIDF_ABSAXIS, - sizeof(DIJOYSTATE2), - numObjects(dfDIJoystick), - dfDIJoystick -}; - -DIOBJECTDATAFORMAT dfDIJoystick2[] = { - { &GUID_XAxis,DIJOFS_X,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_YAxis,DIJOFS_Y,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_ZAxis,DIJOFS_Z,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_RxAxis,DIJOFS_RX,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_RyAxis,DIJOFS_RY,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_RzAxis,DIJOFS_RZ,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_Slider,DIJOFS_SLIDER(0),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_Slider,DIJOFS_SLIDER(1),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_POV,DIJOFS_POV(0),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, - { &GUID_POV,DIJOFS_POV(1),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, - { &GUID_POV,DIJOFS_POV(2),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, - { &GUID_POV,DIJOFS_POV(3),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(0),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(1),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(2),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(3),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(4),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(5),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(6),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(7),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(8),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(9),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(10),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(11),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(12),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(13),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(14),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(15),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(16),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(17),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(18),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(19),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(20),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(21),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(22),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(23),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(24),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(25),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(26),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(27),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(28),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(29),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(30),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(31),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(32),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(33),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(34),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(35),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(36),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(37),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(38),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(39),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(40),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(41),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(42),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(43),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(44),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(45),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(46),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(47),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(48),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(49),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(50),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(51),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(52),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(53),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(54),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(55),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(56),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(57),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(58),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(59),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(60),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(61),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(62),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(63),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(64),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(65),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(66),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(67),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(68),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(69),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(70),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(71),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(72),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(73),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(74),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(75),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(76),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(77),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(78),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(79),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(80),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(81),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(82),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(83),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(84),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(85),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(86),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(87),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(88),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(89),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(90),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(91),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(92),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(93),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(94),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(95),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(96),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(97),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(98),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(99),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(100),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(101),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(102),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(103),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(104),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(105),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(106),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(107),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(108),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(109),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(110),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(111),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(112),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(113),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(114),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(115),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(116),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(117),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(118),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(119),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(120),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(121),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(122),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(123),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(124),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(125),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(126),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { NULL,DIJOFS_BUTTON(127),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, - { &GUID_XAxis,FIELD_OFFSET(DIJOYSTATE2,lVX),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_YAxis,FIELD_OFFSET(DIJOYSTATE2,lVY),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_ZAxis,FIELD_OFFSET(DIJOYSTATE2,lVZ),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_RxAxis,FIELD_OFFSET(DIJOYSTATE2,lVRx),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_RyAxis,FIELD_OFFSET(DIJOYSTATE2,lVRy),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_RzAxis,FIELD_OFFSET(DIJOYSTATE2,lVRz),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglVSlider[0]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglVSlider[1]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_XAxis,FIELD_OFFSET(DIJOYSTATE2,lAX),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_YAxis,FIELD_OFFSET(DIJOYSTATE2,lAY),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_ZAxis,FIELD_OFFSET(DIJOYSTATE2,lAZ),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_RxAxis,FIELD_OFFSET(DIJOYSTATE2,lARx),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_RyAxis,FIELD_OFFSET(DIJOYSTATE2,lARy),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_RzAxis,FIELD_OFFSET(DIJOYSTATE2,lARz),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglASlider[0]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglASlider[1]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_XAxis,FIELD_OFFSET(DIJOYSTATE2,lFX),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_YAxis,FIELD_OFFSET(DIJOYSTATE2,lFY),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_ZAxis,FIELD_OFFSET(DIJOYSTATE2,lFZ),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_RxAxis,FIELD_OFFSET(DIJOYSTATE2,lFRx),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_RyAxis,FIELD_OFFSET(DIJOYSTATE2,lFRy),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_RzAxis,FIELD_OFFSET(DIJOYSTATE2,lFRz),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglFSlider[0]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, - { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglFSlider[1]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, -}; - -const DIDATAFORMAT c_dfDIJoystick2 = { - sizeof(DIDATAFORMAT), - sizeof(DIOBJECTDATAFORMAT), - DIDF_ABSAXIS, - sizeof(DIJOYSTATE2), - numObjects(dfDIJoystick2), - dfDIJoystick2 -}; - -DIOBJECTDATAFORMAT dfDIMouse[] = { - { &GUID_XAxis, DIMOFS_X, DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, - { &GUID_YAxis, DIMOFS_Y, DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, - { &GUID_ZAxis, DIMOFS_Z, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, - { &GUID_Button, DIMOFS_BUTTON0, DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, - { &GUID_Button, DIMOFS_BUTTON1, DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, - { &GUID_Button, DIMOFS_BUTTON2, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, - { &GUID_Button, DIMOFS_BUTTON3, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 } -}; - -const DIDATAFORMAT c_dfDIMouse = { - sizeof(DIDATAFORMAT), - sizeof(DIOBJECTDATAFORMAT), - DIDF_RELAXIS, - sizeof(DIMOUSESTATE), - numObjects(dfDIMouse), - dfDIMouse -}; - -DIOBJECTDATAFORMAT dfDIMouse2[] = { - { &GUID_XAxis, DIMOFS_X, DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, - { &GUID_YAxis, DIMOFS_Y, DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, - { &GUID_ZAxis, DIMOFS_Z, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, - { &GUID_Button, DIMOFS_BUTTON0, DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, - { &GUID_Button, DIMOFS_BUTTON1, DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, - { &GUID_Button, DIMOFS_BUTTON2, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, - { &GUID_Button, DIMOFS_BUTTON3, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, - { &GUID_Button, DIMOFS_BUTTON4, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, - { &GUID_Button, DIMOFS_BUTTON5, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, - { &GUID_Button, DIMOFS_BUTTON6, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, - { &GUID_Button, DIMOFS_BUTTON7, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 } -}; - -const DIDATAFORMAT c_dfDIMouse2 = { - sizeof(DIDATAFORMAT), - sizeof(DIOBJECTDATAFORMAT), - DIDF_RELAXIS, - sizeof(DIMOUSESTATE2), - numObjects(dfDIMouse2), - dfDIMouse2 -}; +/* + * Copyright (c) 2004 Robert Reif + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* TODO: + * add keyboard + */ + +#include + +#include "windef.h" +#include "dinput.h" + +#define numObjects(x) (sizeof(x) / sizeof(x[0])) + +DIOBJECTDATAFORMAT dfDIJoystick[] = { + { &GUID_XAxis,DIJOFS_X,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_YAxis,DIJOFS_Y,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_ZAxis,DIJOFS_Z,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RxAxis,DIJOFS_RX,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RyAxis,DIJOFS_RY,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RzAxis,DIJOFS_RZ,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_Slider,DIJOFS_SLIDER(0),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_Slider,DIJOFS_SLIDER(1),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_POV,DIJOFS_POV(0),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, + { &GUID_POV,DIJOFS_POV(1),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, + { &GUID_POV,DIJOFS_POV(2),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, + { &GUID_POV,DIJOFS_POV(3),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(0),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(1),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(2),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(3),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(4),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(5),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(6),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(7),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(8),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(9),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(10),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(11),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(12),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(13),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(14),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(15),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(16),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(17),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(18),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(19),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(20),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(21),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(22),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(23),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(24),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(25),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(26),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(27),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(28),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(29),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(30),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(31),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, +}; + +const DIDATAFORMAT c_dfDIJoystick = { + sizeof(DIDATAFORMAT), + sizeof(DIOBJECTDATAFORMAT), + DIDF_ABSAXIS, + sizeof(DIJOYSTATE2), + numObjects(dfDIJoystick), + dfDIJoystick +}; + +DIOBJECTDATAFORMAT dfDIJoystick2[] = { + { &GUID_XAxis,DIJOFS_X,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_YAxis,DIJOFS_Y,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_ZAxis,DIJOFS_Z,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RxAxis,DIJOFS_RX,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RyAxis,DIJOFS_RY,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RzAxis,DIJOFS_RZ,DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_Slider,DIJOFS_SLIDER(0),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_Slider,DIJOFS_SLIDER(1),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_POV,DIJOFS_POV(0),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, + { &GUID_POV,DIJOFS_POV(1),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, + { &GUID_POV,DIJOFS_POV(2),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, + { &GUID_POV,DIJOFS_POV(3),DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(0),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(1),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(2),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(3),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(4),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(5),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(6),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(7),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(8),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(9),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(10),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(11),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(12),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(13),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(14),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(15),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(16),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(17),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(18),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(19),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(20),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(21),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(22),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(23),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(24),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(25),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(26),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(27),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(28),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(29),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(30),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(31),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(32),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(33),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(34),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(35),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(36),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(37),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(38),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(39),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(40),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(41),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(42),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(43),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(44),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(45),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(46),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(47),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(48),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(49),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(50),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(51),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(52),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(53),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(54),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(55),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(56),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(57),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(58),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(59),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(60),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(61),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(62),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(63),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(64),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(65),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(66),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(67),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(68),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(69),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(70),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(71),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(72),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(73),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(74),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(75),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(76),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(77),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(78),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(79),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(80),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(81),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(82),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(83),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(84),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(85),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(86),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(87),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(88),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(89),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(90),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(91),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(92),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(93),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(94),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(95),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(96),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(97),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(98),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(99),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(100),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(101),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(102),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(103),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(104),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(105),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(106),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(107),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(108),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(109),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(110),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(111),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(112),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(113),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(114),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(115),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(116),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(117),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(118),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(119),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(120),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(121),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(122),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(123),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(124),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(125),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(126),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { NULL,DIJOFS_BUTTON(127),DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE,0}, + { &GUID_XAxis,FIELD_OFFSET(DIJOYSTATE2,lVX),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_YAxis,FIELD_OFFSET(DIJOYSTATE2,lVY),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_ZAxis,FIELD_OFFSET(DIJOYSTATE2,lVZ),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RxAxis,FIELD_OFFSET(DIJOYSTATE2,lVRx),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RyAxis,FIELD_OFFSET(DIJOYSTATE2,lVRy),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RzAxis,FIELD_OFFSET(DIJOYSTATE2,lVRz),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglVSlider[0]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglVSlider[1]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_XAxis,FIELD_OFFSET(DIJOYSTATE2,lAX),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_YAxis,FIELD_OFFSET(DIJOYSTATE2,lAY),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_ZAxis,FIELD_OFFSET(DIJOYSTATE2,lAZ),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RxAxis,FIELD_OFFSET(DIJOYSTATE2,lARx),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RyAxis,FIELD_OFFSET(DIJOYSTATE2,lARy),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RzAxis,FIELD_OFFSET(DIJOYSTATE2,lARz),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglASlider[0]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglASlider[1]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_XAxis,FIELD_OFFSET(DIJOYSTATE2,lFX),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_YAxis,FIELD_OFFSET(DIJOYSTATE2,lFY),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_ZAxis,FIELD_OFFSET(DIJOYSTATE2,lFZ),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RxAxis,FIELD_OFFSET(DIJOYSTATE2,lFRx),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RyAxis,FIELD_OFFSET(DIJOYSTATE2,lFRy),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_RzAxis,FIELD_OFFSET(DIJOYSTATE2,lFRz),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglFSlider[0]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, + { &GUID_Slider,FIELD_OFFSET(DIJOYSTATE2,rglFSlider[1]),DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE,0}, +}; + +const DIDATAFORMAT c_dfDIJoystick2 = { + sizeof(DIDATAFORMAT), + sizeof(DIOBJECTDATAFORMAT), + DIDF_ABSAXIS, + sizeof(DIJOYSTATE2), + numObjects(dfDIJoystick2), + dfDIJoystick2 +}; + +DIOBJECTDATAFORMAT dfDIMouse[] = { + { &GUID_XAxis, DIMOFS_X, DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, + { &GUID_YAxis, DIMOFS_Y, DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, + { &GUID_ZAxis, DIMOFS_Z, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, + { &GUID_Button, DIMOFS_BUTTON0, DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, + { &GUID_Button, DIMOFS_BUTTON1, DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, + { &GUID_Button, DIMOFS_BUTTON2, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, + { &GUID_Button, DIMOFS_BUTTON3, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 } +}; + +const DIDATAFORMAT c_dfDIMouse = { + sizeof(DIDATAFORMAT), + sizeof(DIOBJECTDATAFORMAT), + DIDF_RELAXIS, + sizeof(DIMOUSESTATE), + numObjects(dfDIMouse), + dfDIMouse +}; + +DIOBJECTDATAFORMAT dfDIMouse2[] = { + { &GUID_XAxis, DIMOFS_X, DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, + { &GUID_YAxis, DIMOFS_Y, DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, + { &GUID_ZAxis, DIMOFS_Z, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_AXIS, 0 }, + { &GUID_Button, DIMOFS_BUTTON0, DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, + { &GUID_Button, DIMOFS_BUTTON1, DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, + { &GUID_Button, DIMOFS_BUTTON2, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, + { &GUID_Button, DIMOFS_BUTTON3, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, + { &GUID_Button, DIMOFS_BUTTON4, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, + { &GUID_Button, DIMOFS_BUTTON5, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, + { &GUID_Button, DIMOFS_BUTTON6, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 }, + { &GUID_Button, DIMOFS_BUTTON7, DIDFT_OPTIONAL | DIDFT_ANYINSTANCE | DIDFT_BUTTON, 0 } +}; + +const DIDATAFORMAT c_dfDIMouse2 = { + sizeof(DIDATAFORMAT), + sizeof(DIOBJECTDATAFORMAT), + DIDF_RELAXIS, + sizeof(DIMOUSESTATE2), + numObjects(dfDIMouse2), + dfDIMouse2 +}; diff --git a/reactos/lib/dinput/device.c b/reactos/lib/dinput/device.c index 2980c3c00d1..4d5aefafdc9 100644 --- a/reactos/lib/dinput/device.c +++ b/reactos/lib/dinput/device.c @@ -1,884 +1,884 @@ -/* DirectInput Device - * - * Copyright 1998 Marcus Meissner - * Copyright 1998,1999 Lionel Ulmer - * - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* This file contains all the Device specific functions that can be used as stubs - by real device implementations. - - It also contains all the helper functions. -*/ -#include "config.h" - -#include -#include -#include "wine/debug.h" -#include "wine/unicode.h" -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "dinput.h" -#include "device_private.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dinput); - -/****************************************************************************** - * Various debugging tools - */ -void _dump_cooperativelevel_DI(DWORD dwFlags) { - if (TRACE_ON(dinput)) { - unsigned int i; - static const struct { - DWORD mask; - const char *name; - } flags[] = { -#define FE(x) { x, #x} - FE(DISCL_BACKGROUND), - FE(DISCL_EXCLUSIVE), - FE(DISCL_FOREGROUND), - FE(DISCL_NONEXCLUSIVE) -#undef FE - }; - for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) - if (flags[i].mask & dwFlags) - DPRINTF("%s ",flags[i].name); - DPRINTF("\n"); - } -} - -void _dump_EnumObjects_flags(DWORD dwFlags) { - if (TRACE_ON(dinput)) { - unsigned int i; - DWORD type, instance; - static const struct { - DWORD mask; - const char *name; - } flags[] = { -#define FE(x) { x, #x} - FE(DIDFT_RELAXIS), - FE(DIDFT_ABSAXIS), - FE(DIDFT_PSHBUTTON), - FE(DIDFT_TGLBUTTON), - FE(DIDFT_POV), - FE(DIDFT_COLLECTION), - FE(DIDFT_NODATA), - FE(DIDFT_FFACTUATOR), - FE(DIDFT_FFEFFECTTRIGGER), - FE(DIDFT_OUTPUT) -#undef FE - }; - type = (dwFlags & 0xFF0000FF); - instance = ((dwFlags >> 8) & 0xFFFF); - DPRINTF("Type:"); - if (type == DIDFT_ALL) { - DPRINTF(" DIDFT_ALL"); - } else { - for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) { - if (flags[i].mask & type) { - type &= ~flags[i].mask; - DPRINTF(" %s",flags[i].name); - } - } - if (type) { - DPRINTF(" (unhandled: %08lx)", type); - } - } - DPRINTF(" / Instance: "); - if (instance == ((DIDFT_ANYINSTANCE >> 8) & 0xFFFF)) { - DPRINTF("DIDFT_ANYINSTANCE"); - } else { - DPRINTF("%3ld", instance); - } - } -} - -void _dump_DIPROPHEADER(LPCDIPROPHEADER diph) { - if (TRACE_ON(dinput)) { - DPRINTF(" - dwObj = 0x%08lx\n", diph->dwObj); - DPRINTF(" - dwHow = %s\n", - ((diph->dwHow == DIPH_DEVICE) ? "DIPH_DEVICE" : - ((diph->dwHow == DIPH_BYOFFSET) ? "DIPH_BYOFFSET" : - ((diph->dwHow == DIPH_BYID)) ? "DIPH_BYID" : "unknown"))); - } -} - -void _dump_OBJECTINSTANCEA(DIDEVICEOBJECTINSTANCEA *ddoi) { - if (TRACE_ON(dinput)) { - DPRINTF(" - enumerating : %s ('%s') - %2ld - 0x%08lx - %s\n", - debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, ddoi->tszName); - } -} - -void _dump_OBJECTINSTANCEW(DIDEVICEOBJECTINSTANCEW *ddoi) { - if (TRACE_ON(dinput)) { - DPRINTF(" - enumerating : %s ('%s'), - %2ld - 0x%08lx - %s\n", - debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, debugstr_w(ddoi->tszName)); - } -} - -/* This function is a helper to convert a GUID into any possible DInput GUID out there */ -const char *_dump_dinput_GUID(const GUID *guid) { - unsigned int i; - static const struct { - const GUID *guid; - const char *name; - } guids[] = { -#define FE(x) { &x, #x} - FE(GUID_XAxis), - FE(GUID_YAxis), - FE(GUID_ZAxis), - FE(GUID_RxAxis), - FE(GUID_RyAxis), - FE(GUID_RzAxis), - FE(GUID_Slider), - FE(GUID_Button), - FE(GUID_Key), - FE(GUID_POV), - FE(GUID_Unknown), - FE(GUID_SysMouse), - FE(GUID_SysKeyboard), - FE(GUID_Joystick), - FE(GUID_ConstantForce), - FE(GUID_RampForce), - FE(GUID_Square), - FE(GUID_Sine), - FE(GUID_Triangle), - FE(GUID_SawtoothUp), - FE(GUID_SawtoothDown), - FE(GUID_Spring), - FE(GUID_Damper), - FE(GUID_Inertia), - FE(GUID_Friction), - FE(GUID_CustomForce) -#undef FE - }; - if (guid == NULL) - return "null GUID"; - for (i = 0; i < (sizeof(guids) / sizeof(guids[0])); i++) { - if (IsEqualGUID(guids[i].guid, guid)) { - return guids[i].name; - } - } - return "Unknown GUID"; -} - -void _dump_DIDATAFORMAT(const DIDATAFORMAT *df) { - unsigned int i; - - TRACE("Dumping DIDATAFORMAT structure:\n"); - TRACE(" - dwSize: %ld\n", df->dwSize); - if (df->dwSize != sizeof(DIDATAFORMAT)) { - WARN("Non-standard DIDATAFORMAT structure size (%ld instead of %d).\n", df->dwSize, sizeof(DIDATAFORMAT)); - } - TRACE(" - dwObjsize: %ld\n", df->dwObjSize); - if (df->dwObjSize != sizeof(DIOBJECTDATAFORMAT)) { - WARN("Non-standard DIOBJECTDATAFORMAT structure size (%ld instead of %d).\n", df->dwObjSize, sizeof(DIOBJECTDATAFORMAT)); - } - TRACE(" - dwFlags: 0x%08lx (", df->dwFlags); - switch (df->dwFlags) { - case DIDF_ABSAXIS: TRACE("DIDF_ABSAXIS"); break; - case DIDF_RELAXIS: TRACE("DIDF_RELAXIS"); break; - default: TRACE("unknown"); break; - } - TRACE(")\n"); - TRACE(" - dwDataSize: %ld\n", df->dwDataSize); - TRACE(" - dwNumObjs: %ld\n", df->dwNumObjs); - - for (i = 0; i < df->dwNumObjs; i++) { - TRACE(" - Object %d:\n", i); - TRACE(" * GUID: %s ('%s')\n", debugstr_guid(df->rgodf[i].pguid), _dump_dinput_GUID(df->rgodf[i].pguid)); - TRACE(" * dwOfs: %ld\n", df->rgodf[i].dwOfs); - TRACE(" * dwType: 0x%08lx\n", df->rgodf[i].dwType); - TRACE(" "); _dump_EnumObjects_flags(df->rgodf[i].dwType); TRACE("\n"); - TRACE(" * dwFlags: 0x%08lx\n", df->rgodf[i].dwFlags); - } -} - -/* Conversion between internal data buffer and external data buffer */ -void fill_DataFormat(void *out, const void *in, DataFormat *df) { - int i; - char *in_c = (char *) in; - char *out_c = (char *) out; - - if (df->dt == NULL) { - /* This means that the app uses Wine's internal data format */ - memcpy(out, in, df->internal_format_size); - } else { - for (i = 0; i < df->size; i++) { - if (df->dt[i].offset_in >= 0) { - switch (df->dt[i].size) { - case 1: - TRACE("Copying (c) to %d from %d (value %d)\n", - df->dt[i].offset_out, df->dt[i].offset_in, *((char *) (in_c + df->dt[i].offset_in))); - *((char *) (out_c + df->dt[i].offset_out)) = *((char *) (in_c + df->dt[i].offset_in)); - break; - - case 2: - TRACE("Copying (s) to %d from %d (value %d)\n", - df->dt[i].offset_out, df->dt[i].offset_in, *((short *) (in_c + df->dt[i].offset_in))); - *((short *) (out_c + df->dt[i].offset_out)) = *((short *) (in_c + df->dt[i].offset_in)); - break; - - case 4: - TRACE("Copying (i) to %d from %d (value %d)\n", - df->dt[i].offset_out, df->dt[i].offset_in, *((int *) (in_c + df->dt[i].offset_in))); - *((int *) (out_c + df->dt[i].offset_out)) = *((int *) (in_c + df->dt[i].offset_in)); - break; - - default: - memcpy((out_c + df->dt[i].offset_out), (in_c + df->dt[i].offset_in), df->dt[i].size); - break; - } - } else { - switch (df->dt[i].size) { - case 1: - TRACE("Copying (c) to %d default value %d\n", - df->dt[i].offset_out, df->dt[i].value); - *((char *) (out_c + df->dt[i].offset_out)) = (char) df->dt[i].value; - break; - - case 2: - TRACE("Copying (s) to %d default value %d\n", - df->dt[i].offset_out, df->dt[i].value); - *((short *) (out_c + df->dt[i].offset_out)) = (short) df->dt[i].value; - break; - - case 4: - TRACE("Copying (i) to %d default value %d\n", - df->dt[i].offset_out, df->dt[i].value); - *((int *) (out_c + df->dt[i].offset_out)) = (int) df->dt[i].value; - break; - - default: - memset((out_c + df->dt[i].offset_out), df->dt[i].size, 0); - break; - } - } - } - } -} - -void release_DataFormat(DataFormat * format) -{ - TRACE("Deleting DataTransform : \n"); - - HeapFree(GetProcessHeap(), 0, format->dt); -} - -DataFormat *create_DataFormat(const DIDATAFORMAT *wine_format, LPCDIDATAFORMAT asked_format, int *offset) { - DataFormat *ret; - DataTransform *dt; - unsigned int i, j; - int same = 1; - int *done; - int index = 0; - DWORD next = 0; - - ret = (DataFormat *) HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat)); - - done = (int *) HeapAlloc(GetProcessHeap(), 0, sizeof(int) * asked_format->dwNumObjs); - memset(done, 0, sizeof(int) * asked_format->dwNumObjs); - - dt = (DataTransform *) HeapAlloc(GetProcessHeap(), 0, asked_format->dwNumObjs * sizeof(DataTransform)); - - TRACE("Creating DataTransform : \n"); - - for (i = 0; i < wine_format->dwNumObjs; i++) { - offset[i] = -1; - - for (j = 0; j < asked_format->dwNumObjs; j++) { - if (done[j] == 1) - continue; - - if (/* Check if the application either requests any GUID and if not, it if matches - * the GUID of the Wine object. - */ - ((asked_format->rgodf[j].pguid == NULL) || - (IsEqualGUID(wine_format->rgodf[i].pguid, asked_format->rgodf[j].pguid))) - && - (/* Then check if it accepts any instance id, and if not, if it matches Wine's - * instance id. - */ - ((asked_format->rgodf[j].dwType & 0x00FFFF00) == DIDFT_ANYINSTANCE) || - (wine_format->rgodf[i].dwType & asked_format->rgodf[j].dwType))) { - - done[j] = 1; - - TRACE("Matching : \n"); - TRACE(" - Asked (%d) :\n", j); - TRACE(" * GUID: %s ('%s')\n", - debugstr_guid(asked_format->rgodf[j].pguid), - _dump_dinput_GUID(asked_format->rgodf[j].pguid)); - TRACE(" * Offset: %3ld\n", asked_format->rgodf[j].dwOfs); - TRACE(" * dwType: %08lx\n", asked_format->rgodf[j].dwType); - TRACE(" "); _dump_EnumObjects_flags(asked_format->rgodf[j].dwType); TRACE("\n"); - - TRACE(" - Wine (%d) :\n", j); - TRACE(" * GUID: %s ('%s')\n", - debugstr_guid(wine_format->rgodf[j].pguid), - _dump_dinput_GUID(wine_format->rgodf[j].pguid)); - TRACE(" * Offset: %3ld\n", wine_format->rgodf[j].dwOfs); - TRACE(" * dwType: %08lx\n", wine_format->rgodf[j].dwType); - TRACE(" "); _dump_EnumObjects_flags(wine_format->rgodf[j].dwType); TRACE("\n"); - - if (wine_format->rgodf[i].dwType & DIDFT_BUTTON) - dt[index].size = sizeof(BYTE); - else - dt[index].size = sizeof(DWORD); - dt[index].offset_in = wine_format ->rgodf[i].dwOfs; - if (asked_format->rgodf[j].dwOfs < next) { - WARN("bad format: dwOfs=%ld, changing to %ld\n", asked_format->rgodf[j].dwOfs, next); - dt[index].offset_out = next; - offset[i] = next; - } else { - dt[index].offset_out = asked_format->rgodf[j].dwOfs; - offset[i] = asked_format->rgodf[j].dwOfs; - } - dt[index].value = 0; - next = next + dt[index].size; - - if (wine_format->rgodf[i].dwOfs != dt[index].offset_out) - same = 0; - - index++; - break; - } - } - - if (j == asked_format->dwNumObjs) - same = 0; - } - - TRACE("Setting to default value :\n"); - for (j = 0; j < asked_format->dwNumObjs; j++) { - if (done[j] == 0) { - TRACE(" - Asked (%d) :\n", j); - TRACE(" * GUID: %s ('%s')\n", - debugstr_guid(asked_format->rgodf[j].pguid), - _dump_dinput_GUID(asked_format->rgodf[j].pguid)); - TRACE(" * Offset: %3ld\n", asked_format->rgodf[j].dwOfs); - TRACE(" * dwType: %08lx\n", asked_format->rgodf[j].dwType); - TRACE(" "); _dump_EnumObjects_flags(asked_format->rgodf[j].dwType); TRACE("\n"); - - if (asked_format->rgodf[j].dwType & DIDFT_BUTTON) - dt[index].size = sizeof(BYTE); - else - dt[index].size = sizeof(DWORD); - dt[index].offset_in = -1; - dt[index].offset_out = asked_format->rgodf[j].dwOfs; - dt[index].value = 0; - index++; - - same = 0; - } - } - - ret->internal_format_size = wine_format->dwDataSize; - ret->size = index; - if (same) { - ret->dt = NULL; - HeapFree(GetProcessHeap(), 0, dt); - } else { - ret->dt = dt; - } - - HeapFree(GetProcessHeap(), 0, done); - - return ret; -} - -BOOL DIEnumDevicesCallbackAtoW(LPCDIDEVICEOBJECTINSTANCEA lpddi, LPVOID lpvRef) { - DIDEVICEOBJECTINSTANCEW ddtmp; - device_enumobjects_AtoWcb_data* data; - - data = (device_enumobjects_AtoWcb_data*) lpvRef; - - memset(&ddtmp, 0, sizeof(DIDEVICEINSTANCEW)); - - ddtmp.dwSize = sizeof(DIDEVICEINSTANCEW); - ddtmp.guidType = lpddi->guidType; - ddtmp.dwOfs = lpddi->dwOfs; - ddtmp.dwType = lpddi->dwType; - ddtmp.dwFlags = lpddi->dwFlags; - MultiByteToWideChar(CP_ACP, 0, lpddi->tszName, -1, ddtmp.tszName, MAX_PATH); - - if (lpddi->dwSize == sizeof(DIDEVICEINSTANCEA)) { - /** - * if dwSize < sizeof(DIDEVICEINSTANCEA of DInput version >= 5) - * force feedback and other newer datas aren't available - */ - ddtmp.dwFFMaxForce = lpddi->dwFFMaxForce; - ddtmp.dwFFForceResolution = lpddi->dwFFForceResolution; - ddtmp.wCollectionNumber = lpddi->wCollectionNumber; - ddtmp.wDesignatorIndex = lpddi->wDesignatorIndex; - ddtmp.wUsagePage = lpddi->wUsagePage; - ddtmp.wUsage = lpddi->wUsage; - ddtmp.dwDimension = lpddi->dwDimension; - ddtmp.wExponent = lpddi->wExponent; - ddtmp.wReserved = lpddi->wReserved; - } - return data->lpCallBack(&ddtmp, data->lpvRef); -} - -/****************************************************************************** - * IDirectInputDeviceA - */ - -HRESULT WINAPI IDirectInputDevice2AImpl_SetDataFormat( - LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df -) { - IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; - - TRACE("(this=%p,%p)\n",This,df); - - _dump_DIDATAFORMAT(df); - - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice2AImpl_SetCooperativeLevel( - LPDIRECTINPUTDEVICE8A iface,HWND hwnd,DWORD dwflags -) { - IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; - TRACE("(this=%p,0x%08lx,0x%08lx)\n",This,(DWORD)hwnd,dwflags); - if (TRACE_ON(dinput)) { - TRACE(" cooperative level : "); - _dump_cooperativelevel_DI(dwflags); - } - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice2AImpl_SetEventNotification( - LPDIRECTINPUTDEVICE8A iface,HANDLE hnd -) { - IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; - FIXME("(this=%p,0x%08lx): stub\n",This,(DWORD)hnd); - return DI_OK; -} - -ULONG WINAPI IDirectInputDevice2AImpl_Release(LPDIRECTINPUTDEVICE8A iface) -{ - IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; - ULONG ref; - ref = InterlockedDecrement(&(This->ref)); - if (ref == 0) - HeapFree(GetProcessHeap(),0,This); - return ref; -} - -HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface( - LPDIRECTINPUTDEVICE8A iface,REFIID riid,LPVOID *ppobj -) -{ - IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; - - TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); - if (IsEqualGUID(&IID_IUnknown,riid)) { - IDirectInputDevice2_AddRef(iface); - *ppobj = This; - return DI_OK; - } - if (IsEqualGUID(&IID_IDirectInputDeviceA,riid)) { - IDirectInputDevice2_AddRef(iface); - *ppobj = This; - return DI_OK; - } - if (IsEqualGUID(&IID_IDirectInputDevice2A,riid)) { - IDirectInputDevice2_AddRef(iface); - *ppobj = This; - return DI_OK; - } - if (IsEqualGUID(&IID_IDirectInputDevice7A,riid)) { - IDirectInputDevice7_AddRef(iface); - *ppobj = This; - return DI_OK; - } - TRACE("Unsupported interface !\n"); - return E_FAIL; -} - -HRESULT WINAPI IDirectInputDevice2WImpl_QueryInterface( - LPDIRECTINPUTDEVICE8W iface,REFIID riid,LPVOID *ppobj -) -{ - IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; - - TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); - if (IsEqualGUID(&IID_IUnknown,riid)) { - IDirectInputDevice2_AddRef(iface); - *ppobj = This; - return DI_OK; - } - if (IsEqualGUID(&IID_IDirectInputDeviceW,riid)) { - IDirectInputDevice2_AddRef(iface); - *ppobj = This; - return DI_OK; - } - if (IsEqualGUID(&IID_IDirectInputDevice2W,riid)) { - IDirectInputDevice2_AddRef(iface); - *ppobj = This; - return DI_OK; - } - if (IsEqualGUID(&IID_IDirectInputDevice7W,riid)) { - IDirectInputDevice7_AddRef(iface); - *ppobj = This; - return DI_OK; - } - TRACE("Unsupported interface !\n"); - return E_FAIL; -} - -ULONG WINAPI IDirectInputDevice2AImpl_AddRef( - LPDIRECTINPUTDEVICE8A iface) -{ - IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; - return InterlockedIncrement(&(This->ref)); -} - -HRESULT WINAPI IDirectInputDevice2AImpl_EnumObjects( - LPDIRECTINPUTDEVICE8A iface, - LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, - LPVOID lpvRef, - DWORD dwFlags) -{ - FIXME("(this=%p,%p,%p,%08lx): stub!\n", iface, lpCallback, lpvRef, dwFlags); - if (TRACE_ON(dinput)) { - DPRINTF(" - flags = "); - _dump_EnumObjects_flags(dwFlags); - DPRINTF("\n"); - } - - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice2WImpl_EnumObjects( - LPDIRECTINPUTDEVICE8W iface, - LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, - LPVOID lpvRef, - DWORD dwFlags) -{ - FIXME("(this=%p,%p,%p,%08lx): stub!\n", iface, lpCallback, lpvRef, dwFlags); - if (TRACE_ON(dinput)) { - DPRINTF(" - flags = "); - _dump_EnumObjects_flags(dwFlags); - DPRINTF("\n"); - } - - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice2AImpl_GetProperty( - LPDIRECTINPUTDEVICE8A iface, - REFGUID rguid, - LPDIPROPHEADER pdiph) -{ - FIXME("(this=%p,%s,%p): stub!\n", - iface, debugstr_guid(rguid), pdiph); - - if (TRACE_ON(dinput)) - _dump_DIPROPHEADER(pdiph); - - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice2AImpl_GetObjectInfo( - LPDIRECTINPUTDEVICE8A iface, - LPDIDEVICEOBJECTINSTANCEA pdidoi, - DWORD dwObj, - DWORD dwHow) -{ - FIXME("(this=%p,%p,%ld,0x%08lx): stub!\n", - iface, pdidoi, dwObj, dwHow); - - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice2WImpl_GetObjectInfo( - LPDIRECTINPUTDEVICE8W iface, - LPDIDEVICEOBJECTINSTANCEW pdidoi, - DWORD dwObj, - DWORD dwHow) -{ - FIXME("(this=%p,%p,%ld,0x%08lx): stub!\n", - iface, pdidoi, dwObj, dwHow); - - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceInfo( - LPDIRECTINPUTDEVICE8A iface, - LPDIDEVICEINSTANCEA pdidi) -{ - FIXME("(this=%p,%p): stub!\n", - iface, pdidi); - - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice2WImpl_GetDeviceInfo( - LPDIRECTINPUTDEVICE8W iface, - LPDIDEVICEINSTANCEW pdidi) -{ - FIXME("(this=%p,%p): stub!\n", - iface, pdidi); - - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel( - LPDIRECTINPUTDEVICE8A iface, - HWND hwndOwner, - DWORD dwFlags) -{ - FIXME("(this=%p,%p,0x%08lx): stub!\n", - iface, hwndOwner, dwFlags); - - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice2AImpl_Initialize( - LPDIRECTINPUTDEVICE8A iface, - HINSTANCE hinst, - DWORD dwVersion, - REFGUID rguid) -{ - FIXME("(this=%p,%p,%ld,%s): stub!\n", - iface, hinst, dwVersion, debugstr_guid(rguid)); - return DI_OK; -} - -/****************************************************************************** - * IDirectInputDevice2A - */ - -HRESULT WINAPI IDirectInputDevice2AImpl_CreateEffect( - LPDIRECTINPUTDEVICE8A iface, - REFGUID rguid, - LPCDIEFFECT lpeff, - LPDIRECTINPUTEFFECT *ppdef, - LPUNKNOWN pUnkOuter) -{ - FIXME("(this=%p,%s,%p,%p,%p): stub!\n", - iface, debugstr_guid(rguid), lpeff, ppdef, pUnkOuter); - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice2AImpl_EnumEffects( - LPDIRECTINPUTDEVICE8A iface, - LPDIENUMEFFECTSCALLBACKA lpCallback, - LPVOID lpvRef, - DWORD dwFlags) -{ - FIXME("(this=%p,%p,%p,0x%08lx): stub!\n", - iface, lpCallback, lpvRef, dwFlags); - - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice2WImpl_EnumEffects( - LPDIRECTINPUTDEVICE8W iface, - LPDIENUMEFFECTSCALLBACKW lpCallback, - LPVOID lpvRef, - DWORD dwFlags) -{ - FIXME("(this=%p,%p,%p,0x%08lx): stub!\n", - iface, lpCallback, lpvRef, dwFlags); - - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice2AImpl_GetEffectInfo( - LPDIRECTINPUTDEVICE8A iface, - LPDIEFFECTINFOA lpdei, - REFGUID rguid) -{ - FIXME("(this=%p,%p,%s): stub!\n", - iface, lpdei, debugstr_guid(rguid)); - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice2WImpl_GetEffectInfo( - LPDIRECTINPUTDEVICE8W iface, - LPDIEFFECTINFOW lpdei, - REFGUID rguid) -{ - FIXME("(this=%p,%p,%s): stub!\n", - iface, lpdei, debugstr_guid(rguid)); - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice2AImpl_GetForceFeedbackState( - LPDIRECTINPUTDEVICE8A iface, - LPDWORD pdwOut) -{ - FIXME("(this=%p,%p): stub!\n", - iface, pdwOut); - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice2AImpl_SendForceFeedbackCommand( - LPDIRECTINPUTDEVICE8A iface, - DWORD dwFlags) -{ - FIXME("(this=%p,0x%08lx): stub!\n", - iface, dwFlags); - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects( - LPDIRECTINPUTDEVICE8A iface, - LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, - LPVOID lpvRef, - DWORD dwFlags) -{ - FIXME("(this=%p,%p,%p,0x%08lx): stub!\n", - iface, lpCallback, lpvRef, dwFlags); - if (lpCallback) - lpCallback(NULL, lpvRef); - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice2AImpl_Escape( - LPDIRECTINPUTDEVICE8A iface, - LPDIEFFESCAPE lpDIEEsc) -{ - FIXME("(this=%p,%p): stub!\n", - iface, lpDIEEsc); - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice2AImpl_Poll( - LPDIRECTINPUTDEVICE8A iface) -{ - /* Because wine devices do not need to be polled, just return DI_NOEFFECT */ - return DI_NOEFFECT; -} - -HRESULT WINAPI IDirectInputDevice2AImpl_SendDeviceData( - LPDIRECTINPUTDEVICE8A iface, - DWORD cbObjectData, - LPCDIDEVICEOBJECTDATA rgdod, - LPDWORD pdwInOut, - DWORD dwFlags) -{ - FIXME("(this=%p,0x%08lx,%p,%p,0x%08lx): stub!\n", - iface, cbObjectData, rgdod, pdwInOut, dwFlags); - - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice7AImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8A iface, - LPCSTR lpszFileName, - LPDIENUMEFFECTSINFILECALLBACK pec, - LPVOID pvRef, - DWORD dwFlags) -{ - FIXME("(%p)->(%s,%p,%p,%08lx): stub !\n", iface, lpszFileName, pec, pvRef, dwFlags); - - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice7WImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8W iface, - LPCWSTR lpszFileName, - LPDIENUMEFFECTSINFILECALLBACK pec, - LPVOID pvRef, - DWORD dwFlags) -{ - FIXME("(%p)->(%s,%p,%p,%08lx): stub !\n", iface, debugstr_w(lpszFileName), pec, pvRef, dwFlags); - - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice7AImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8A iface, - LPCSTR lpszFileName, - DWORD dwEntries, - LPDIFILEEFFECT rgDiFileEft, - DWORD dwFlags) -{ - FIXME("(%p)->(%s,%08lx,%p,%08lx): stub !\n", iface, lpszFileName, dwEntries, rgDiFileEft, dwFlags); - - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice7WImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8W iface, - LPCWSTR lpszFileName, - DWORD dwEntries, - LPDIFILEEFFECT rgDiFileEft, - DWORD dwFlags) -{ - FIXME("(%p)->(%s,%08lx,%p,%08lx): stub !\n", iface, debugstr_w(lpszFileName), dwEntries, rgDiFileEft, dwFlags); - - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice8AImpl_BuildActionMap(LPDIRECTINPUTDEVICE8A iface, - LPDIACTIONFORMATA lpdiaf, - LPCSTR lpszUserName, - DWORD dwFlags) -{ - FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, lpszUserName, dwFlags); - - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice8WImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface, - LPDIACTIONFORMATW lpdiaf, - LPCWSTR lpszUserName, - DWORD dwFlags) -{ - FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags); - - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice8AImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface, - LPDIACTIONFORMATA lpdiaf, - LPCSTR lpszUserName, - DWORD dwFlags) -{ - FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, lpszUserName, dwFlags); - - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice8WImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface, - LPDIACTIONFORMATW lpdiaf, - LPCWSTR lpszUserName, - DWORD dwFlags) -{ - FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags); - - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice8AImpl_GetImageInfo(LPDIRECTINPUTDEVICE8A iface, - LPDIDEVICEIMAGEINFOHEADERA lpdiDevImageInfoHeader) -{ - FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader); - - return DI_OK; -} - -HRESULT WINAPI IDirectInputDevice8WImpl_GetImageInfo(LPDIRECTINPUTDEVICE8W iface, - LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader) -{ - FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader); - - return DI_OK; -} +/* DirectInput Device + * + * Copyright 1998 Marcus Meissner + * Copyright 1998,1999 Lionel Ulmer + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* This file contains all the Device specific functions that can be used as stubs + by real device implementations. + + It also contains all the helper functions. +*/ +#include "config.h" + +#include +#include +#include "wine/debug.h" +#include "wine/unicode.h" +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "dinput.h" +#include "device_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dinput); + +/****************************************************************************** + * Various debugging tools + */ +void _dump_cooperativelevel_DI(DWORD dwFlags) { + if (TRACE_ON(dinput)) { + unsigned int i; + static const struct { + DWORD mask; + const char *name; + } flags[] = { +#define FE(x) { x, #x} + FE(DISCL_BACKGROUND), + FE(DISCL_EXCLUSIVE), + FE(DISCL_FOREGROUND), + FE(DISCL_NONEXCLUSIVE) +#undef FE + }; + for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) + if (flags[i].mask & dwFlags) + DPRINTF("%s ",flags[i].name); + DPRINTF("\n"); + } +} + +void _dump_EnumObjects_flags(DWORD dwFlags) { + if (TRACE_ON(dinput)) { + unsigned int i; + DWORD type, instance; + static const struct { + DWORD mask; + const char *name; + } flags[] = { +#define FE(x) { x, #x} + FE(DIDFT_RELAXIS), + FE(DIDFT_ABSAXIS), + FE(DIDFT_PSHBUTTON), + FE(DIDFT_TGLBUTTON), + FE(DIDFT_POV), + FE(DIDFT_COLLECTION), + FE(DIDFT_NODATA), + FE(DIDFT_FFACTUATOR), + FE(DIDFT_FFEFFECTTRIGGER), + FE(DIDFT_OUTPUT) +#undef FE + }; + type = (dwFlags & 0xFF0000FF); + instance = ((dwFlags >> 8) & 0xFFFF); + DPRINTF("Type:"); + if (type == DIDFT_ALL) { + DPRINTF(" DIDFT_ALL"); + } else { + for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) { + if (flags[i].mask & type) { + type &= ~flags[i].mask; + DPRINTF(" %s",flags[i].name); + } + } + if (type) { + DPRINTF(" (unhandled: %08lx)", type); + } + } + DPRINTF(" / Instance: "); + if (instance == ((DIDFT_ANYINSTANCE >> 8) & 0xFFFF)) { + DPRINTF("DIDFT_ANYINSTANCE"); + } else { + DPRINTF("%3ld", instance); + } + } +} + +void _dump_DIPROPHEADER(LPCDIPROPHEADER diph) { + if (TRACE_ON(dinput)) { + DPRINTF(" - dwObj = 0x%08lx\n", diph->dwObj); + DPRINTF(" - dwHow = %s\n", + ((diph->dwHow == DIPH_DEVICE) ? "DIPH_DEVICE" : + ((diph->dwHow == DIPH_BYOFFSET) ? "DIPH_BYOFFSET" : + ((diph->dwHow == DIPH_BYID)) ? "DIPH_BYID" : "unknown"))); + } +} + +void _dump_OBJECTINSTANCEA(DIDEVICEOBJECTINSTANCEA *ddoi) { + if (TRACE_ON(dinput)) { + DPRINTF(" - enumerating : %s ('%s') - %2ld - 0x%08lx - %s\n", + debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, ddoi->tszName); + } +} + +void _dump_OBJECTINSTANCEW(DIDEVICEOBJECTINSTANCEW *ddoi) { + if (TRACE_ON(dinput)) { + DPRINTF(" - enumerating : %s ('%s'), - %2ld - 0x%08lx - %s\n", + debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, debugstr_w(ddoi->tszName)); + } +} + +/* This function is a helper to convert a GUID into any possible DInput GUID out there */ +const char *_dump_dinput_GUID(const GUID *guid) { + unsigned int i; + static const struct { + const GUID *guid; + const char *name; + } guids[] = { +#define FE(x) { &x, #x} + FE(GUID_XAxis), + FE(GUID_YAxis), + FE(GUID_ZAxis), + FE(GUID_RxAxis), + FE(GUID_RyAxis), + FE(GUID_RzAxis), + FE(GUID_Slider), + FE(GUID_Button), + FE(GUID_Key), + FE(GUID_POV), + FE(GUID_Unknown), + FE(GUID_SysMouse), + FE(GUID_SysKeyboard), + FE(GUID_Joystick), + FE(GUID_ConstantForce), + FE(GUID_RampForce), + FE(GUID_Square), + FE(GUID_Sine), + FE(GUID_Triangle), + FE(GUID_SawtoothUp), + FE(GUID_SawtoothDown), + FE(GUID_Spring), + FE(GUID_Damper), + FE(GUID_Inertia), + FE(GUID_Friction), + FE(GUID_CustomForce) +#undef FE + }; + if (guid == NULL) + return "null GUID"; + for (i = 0; i < (sizeof(guids) / sizeof(guids[0])); i++) { + if (IsEqualGUID(guids[i].guid, guid)) { + return guids[i].name; + } + } + return "Unknown GUID"; +} + +void _dump_DIDATAFORMAT(const DIDATAFORMAT *df) { + unsigned int i; + + TRACE("Dumping DIDATAFORMAT structure:\n"); + TRACE(" - dwSize: %ld\n", df->dwSize); + if (df->dwSize != sizeof(DIDATAFORMAT)) { + WARN("Non-standard DIDATAFORMAT structure size (%ld instead of %d).\n", df->dwSize, sizeof(DIDATAFORMAT)); + } + TRACE(" - dwObjsize: %ld\n", df->dwObjSize); + if (df->dwObjSize != sizeof(DIOBJECTDATAFORMAT)) { + WARN("Non-standard DIOBJECTDATAFORMAT structure size (%ld instead of %d).\n", df->dwObjSize, sizeof(DIOBJECTDATAFORMAT)); + } + TRACE(" - dwFlags: 0x%08lx (", df->dwFlags); + switch (df->dwFlags) { + case DIDF_ABSAXIS: TRACE("DIDF_ABSAXIS"); break; + case DIDF_RELAXIS: TRACE("DIDF_RELAXIS"); break; + default: TRACE("unknown"); break; + } + TRACE(")\n"); + TRACE(" - dwDataSize: %ld\n", df->dwDataSize); + TRACE(" - dwNumObjs: %ld\n", df->dwNumObjs); + + for (i = 0; i < df->dwNumObjs; i++) { + TRACE(" - Object %d:\n", i); + TRACE(" * GUID: %s ('%s')\n", debugstr_guid(df->rgodf[i].pguid), _dump_dinput_GUID(df->rgodf[i].pguid)); + TRACE(" * dwOfs: %ld\n", df->rgodf[i].dwOfs); + TRACE(" * dwType: 0x%08lx\n", df->rgodf[i].dwType); + TRACE(" "); _dump_EnumObjects_flags(df->rgodf[i].dwType); TRACE("\n"); + TRACE(" * dwFlags: 0x%08lx\n", df->rgodf[i].dwFlags); + } +} + +/* Conversion between internal data buffer and external data buffer */ +void fill_DataFormat(void *out, const void *in, DataFormat *df) { + int i; + char *in_c = (char *) in; + char *out_c = (char *) out; + + if (df->dt == NULL) { + /* This means that the app uses Wine's internal data format */ + memcpy(out, in, df->internal_format_size); + } else { + for (i = 0; i < df->size; i++) { + if (df->dt[i].offset_in >= 0) { + switch (df->dt[i].size) { + case 1: + TRACE("Copying (c) to %d from %d (value %d)\n", + df->dt[i].offset_out, df->dt[i].offset_in, *((char *) (in_c + df->dt[i].offset_in))); + *((char *) (out_c + df->dt[i].offset_out)) = *((char *) (in_c + df->dt[i].offset_in)); + break; + + case 2: + TRACE("Copying (s) to %d from %d (value %d)\n", + df->dt[i].offset_out, df->dt[i].offset_in, *((short *) (in_c + df->dt[i].offset_in))); + *((short *) (out_c + df->dt[i].offset_out)) = *((short *) (in_c + df->dt[i].offset_in)); + break; + + case 4: + TRACE("Copying (i) to %d from %d (value %d)\n", + df->dt[i].offset_out, df->dt[i].offset_in, *((int *) (in_c + df->dt[i].offset_in))); + *((int *) (out_c + df->dt[i].offset_out)) = *((int *) (in_c + df->dt[i].offset_in)); + break; + + default: + memcpy((out_c + df->dt[i].offset_out), (in_c + df->dt[i].offset_in), df->dt[i].size); + break; + } + } else { + switch (df->dt[i].size) { + case 1: + TRACE("Copying (c) to %d default value %d\n", + df->dt[i].offset_out, df->dt[i].value); + *((char *) (out_c + df->dt[i].offset_out)) = (char) df->dt[i].value; + break; + + case 2: + TRACE("Copying (s) to %d default value %d\n", + df->dt[i].offset_out, df->dt[i].value); + *((short *) (out_c + df->dt[i].offset_out)) = (short) df->dt[i].value; + break; + + case 4: + TRACE("Copying (i) to %d default value %d\n", + df->dt[i].offset_out, df->dt[i].value); + *((int *) (out_c + df->dt[i].offset_out)) = (int) df->dt[i].value; + break; + + default: + memset((out_c + df->dt[i].offset_out), df->dt[i].size, 0); + break; + } + } + } + } +} + +void release_DataFormat(DataFormat * format) +{ + TRACE("Deleting DataTransform : \n"); + + HeapFree(GetProcessHeap(), 0, format->dt); +} + +DataFormat *create_DataFormat(const DIDATAFORMAT *wine_format, LPCDIDATAFORMAT asked_format, int *offset) { + DataFormat *ret; + DataTransform *dt; + unsigned int i, j; + int same = 1; + int *done; + int index = 0; + DWORD next = 0; + + ret = (DataFormat *) HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat)); + + done = (int *) HeapAlloc(GetProcessHeap(), 0, sizeof(int) * asked_format->dwNumObjs); + memset(done, 0, sizeof(int) * asked_format->dwNumObjs); + + dt = (DataTransform *) HeapAlloc(GetProcessHeap(), 0, asked_format->dwNumObjs * sizeof(DataTransform)); + + TRACE("Creating DataTransform : \n"); + + for (i = 0; i < wine_format->dwNumObjs; i++) { + offset[i] = -1; + + for (j = 0; j < asked_format->dwNumObjs; j++) { + if (done[j] == 1) + continue; + + if (/* Check if the application either requests any GUID and if not, it if matches + * the GUID of the Wine object. + */ + ((asked_format->rgodf[j].pguid == NULL) || + (IsEqualGUID(wine_format->rgodf[i].pguid, asked_format->rgodf[j].pguid))) + && + (/* Then check if it accepts any instance id, and if not, if it matches Wine's + * instance id. + */ + ((asked_format->rgodf[j].dwType & 0x00FFFF00) == DIDFT_ANYINSTANCE) || + (wine_format->rgodf[i].dwType & asked_format->rgodf[j].dwType))) { + + done[j] = 1; + + TRACE("Matching : \n"); + TRACE(" - Asked (%d) :\n", j); + TRACE(" * GUID: %s ('%s')\n", + debugstr_guid(asked_format->rgodf[j].pguid), + _dump_dinput_GUID(asked_format->rgodf[j].pguid)); + TRACE(" * Offset: %3ld\n", asked_format->rgodf[j].dwOfs); + TRACE(" * dwType: %08lx\n", asked_format->rgodf[j].dwType); + TRACE(" "); _dump_EnumObjects_flags(asked_format->rgodf[j].dwType); TRACE("\n"); + + TRACE(" - Wine (%d) :\n", j); + TRACE(" * GUID: %s ('%s')\n", + debugstr_guid(wine_format->rgodf[j].pguid), + _dump_dinput_GUID(wine_format->rgodf[j].pguid)); + TRACE(" * Offset: %3ld\n", wine_format->rgodf[j].dwOfs); + TRACE(" * dwType: %08lx\n", wine_format->rgodf[j].dwType); + TRACE(" "); _dump_EnumObjects_flags(wine_format->rgodf[j].dwType); TRACE("\n"); + + if (wine_format->rgodf[i].dwType & DIDFT_BUTTON) + dt[index].size = sizeof(BYTE); + else + dt[index].size = sizeof(DWORD); + dt[index].offset_in = wine_format ->rgodf[i].dwOfs; + if (asked_format->rgodf[j].dwOfs < next) { + WARN("bad format: dwOfs=%ld, changing to %ld\n", asked_format->rgodf[j].dwOfs, next); + dt[index].offset_out = next; + offset[i] = next; + } else { + dt[index].offset_out = asked_format->rgodf[j].dwOfs; + offset[i] = asked_format->rgodf[j].dwOfs; + } + dt[index].value = 0; + next = next + dt[index].size; + + if (wine_format->rgodf[i].dwOfs != dt[index].offset_out) + same = 0; + + index++; + break; + } + } + + if (j == asked_format->dwNumObjs) + same = 0; + } + + TRACE("Setting to default value :\n"); + for (j = 0; j < asked_format->dwNumObjs; j++) { + if (done[j] == 0) { + TRACE(" - Asked (%d) :\n", j); + TRACE(" * GUID: %s ('%s')\n", + debugstr_guid(asked_format->rgodf[j].pguid), + _dump_dinput_GUID(asked_format->rgodf[j].pguid)); + TRACE(" * Offset: %3ld\n", asked_format->rgodf[j].dwOfs); + TRACE(" * dwType: %08lx\n", asked_format->rgodf[j].dwType); + TRACE(" "); _dump_EnumObjects_flags(asked_format->rgodf[j].dwType); TRACE("\n"); + + if (asked_format->rgodf[j].dwType & DIDFT_BUTTON) + dt[index].size = sizeof(BYTE); + else + dt[index].size = sizeof(DWORD); + dt[index].offset_in = -1; + dt[index].offset_out = asked_format->rgodf[j].dwOfs; + dt[index].value = 0; + index++; + + same = 0; + } + } + + ret->internal_format_size = wine_format->dwDataSize; + ret->size = index; + if (same) { + ret->dt = NULL; + HeapFree(GetProcessHeap(), 0, dt); + } else { + ret->dt = dt; + } + + HeapFree(GetProcessHeap(), 0, done); + + return ret; +} + +BOOL DIEnumDevicesCallbackAtoW(LPCDIDEVICEOBJECTINSTANCEA lpddi, LPVOID lpvRef) { + DIDEVICEOBJECTINSTANCEW ddtmp; + device_enumobjects_AtoWcb_data* data; + + data = (device_enumobjects_AtoWcb_data*) lpvRef; + + memset(&ddtmp, 0, sizeof(DIDEVICEINSTANCEW)); + + ddtmp.dwSize = sizeof(DIDEVICEINSTANCEW); + ddtmp.guidType = lpddi->guidType; + ddtmp.dwOfs = lpddi->dwOfs; + ddtmp.dwType = lpddi->dwType; + ddtmp.dwFlags = lpddi->dwFlags; + MultiByteToWideChar(CP_ACP, 0, lpddi->tszName, -1, ddtmp.tszName, MAX_PATH); + + if (lpddi->dwSize == sizeof(DIDEVICEINSTANCEA)) { + /** + * if dwSize < sizeof(DIDEVICEINSTANCEA of DInput version >= 5) + * force feedback and other newer datas aren't available + */ + ddtmp.dwFFMaxForce = lpddi->dwFFMaxForce; + ddtmp.dwFFForceResolution = lpddi->dwFFForceResolution; + ddtmp.wCollectionNumber = lpddi->wCollectionNumber; + ddtmp.wDesignatorIndex = lpddi->wDesignatorIndex; + ddtmp.wUsagePage = lpddi->wUsagePage; + ddtmp.wUsage = lpddi->wUsage; + ddtmp.dwDimension = lpddi->dwDimension; + ddtmp.wExponent = lpddi->wExponent; + ddtmp.wReserved = lpddi->wReserved; + } + return data->lpCallBack(&ddtmp, data->lpvRef); +} + +/****************************************************************************** + * IDirectInputDeviceA + */ + +HRESULT WINAPI IDirectInputDevice2AImpl_SetDataFormat( + LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df +) { + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + + TRACE("(this=%p,%p)\n",This,df); + + _dump_DIDATAFORMAT(df); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_SetCooperativeLevel( + LPDIRECTINPUTDEVICE8A iface,HWND hwnd,DWORD dwflags +) { + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + TRACE("(this=%p,0x%08lx,0x%08lx)\n",This,(DWORD)hwnd,dwflags); + if (TRACE_ON(dinput)) { + TRACE(" cooperative level : "); + _dump_cooperativelevel_DI(dwflags); + } + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_SetEventNotification( + LPDIRECTINPUTDEVICE8A iface,HANDLE hnd +) { + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + FIXME("(this=%p,0x%08lx): stub\n",This,(DWORD)hnd); + return DI_OK; +} + +ULONG WINAPI IDirectInputDevice2AImpl_Release(LPDIRECTINPUTDEVICE8A iface) +{ + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + ULONG ref; + ref = InterlockedDecrement(&(This->ref)); + if (ref == 0) + HeapFree(GetProcessHeap(),0,This); + return ref; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface( + LPDIRECTINPUTDEVICE8A iface,REFIID riid,LPVOID *ppobj +) +{ + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + + TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(&IID_IUnknown,riid)) { + IDirectInputDevice2_AddRef(iface); + *ppobj = This; + return DI_OK; + } + if (IsEqualGUID(&IID_IDirectInputDeviceA,riid)) { + IDirectInputDevice2_AddRef(iface); + *ppobj = This; + return DI_OK; + } + if (IsEqualGUID(&IID_IDirectInputDevice2A,riid)) { + IDirectInputDevice2_AddRef(iface); + *ppobj = This; + return DI_OK; + } + if (IsEqualGUID(&IID_IDirectInputDevice7A,riid)) { + IDirectInputDevice7_AddRef(iface); + *ppobj = This; + return DI_OK; + } + TRACE("Unsupported interface !\n"); + return E_FAIL; +} + +HRESULT WINAPI IDirectInputDevice2WImpl_QueryInterface( + LPDIRECTINPUTDEVICE8W iface,REFIID riid,LPVOID *ppobj +) +{ + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + + TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(&IID_IUnknown,riid)) { + IDirectInputDevice2_AddRef(iface); + *ppobj = This; + return DI_OK; + } + if (IsEqualGUID(&IID_IDirectInputDeviceW,riid)) { + IDirectInputDevice2_AddRef(iface); + *ppobj = This; + return DI_OK; + } + if (IsEqualGUID(&IID_IDirectInputDevice2W,riid)) { + IDirectInputDevice2_AddRef(iface); + *ppobj = This; + return DI_OK; + } + if (IsEqualGUID(&IID_IDirectInputDevice7W,riid)) { + IDirectInputDevice7_AddRef(iface); + *ppobj = This; + return DI_OK; + } + TRACE("Unsupported interface !\n"); + return E_FAIL; +} + +ULONG WINAPI IDirectInputDevice2AImpl_AddRef( + LPDIRECTINPUTDEVICE8A iface) +{ + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + return InterlockedIncrement(&(This->ref)); +} + +HRESULT WINAPI IDirectInputDevice2AImpl_EnumObjects( + LPDIRECTINPUTDEVICE8A iface, + LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + FIXME("(this=%p,%p,%p,%08lx): stub!\n", iface, lpCallback, lpvRef, dwFlags); + if (TRACE_ON(dinput)) { + DPRINTF(" - flags = "); + _dump_EnumObjects_flags(dwFlags); + DPRINTF("\n"); + } + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2WImpl_EnumObjects( + LPDIRECTINPUTDEVICE8W iface, + LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + FIXME("(this=%p,%p,%p,%08lx): stub!\n", iface, lpCallback, lpvRef, dwFlags); + if (TRACE_ON(dinput)) { + DPRINTF(" - flags = "); + _dump_EnumObjects_flags(dwFlags); + DPRINTF("\n"); + } + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_GetProperty( + LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, + LPDIPROPHEADER pdiph) +{ + FIXME("(this=%p,%s,%p): stub!\n", + iface, debugstr_guid(rguid), pdiph); + + if (TRACE_ON(dinput)) + _dump_DIPROPHEADER(pdiph); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_GetObjectInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEOBJECTINSTANCEA pdidoi, + DWORD dwObj, + DWORD dwHow) +{ + FIXME("(this=%p,%p,%ld,0x%08lx): stub!\n", + iface, pdidoi, dwObj, dwHow); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2WImpl_GetObjectInfo( + LPDIRECTINPUTDEVICE8W iface, + LPDIDEVICEOBJECTINSTANCEW pdidoi, + DWORD dwObj, + DWORD dwHow) +{ + FIXME("(this=%p,%p,%ld,0x%08lx): stub!\n", + iface, pdidoi, dwObj, dwHow); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEINSTANCEA pdidi) +{ + FIXME("(this=%p,%p): stub!\n", + iface, pdidi); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2WImpl_GetDeviceInfo( + LPDIRECTINPUTDEVICE8W iface, + LPDIDEVICEINSTANCEW pdidi) +{ + FIXME("(this=%p,%p): stub!\n", + iface, pdidi); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel( + LPDIRECTINPUTDEVICE8A iface, + HWND hwndOwner, + DWORD dwFlags) +{ + FIXME("(this=%p,%p,0x%08lx): stub!\n", + iface, hwndOwner, dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_Initialize( + LPDIRECTINPUTDEVICE8A iface, + HINSTANCE hinst, + DWORD dwVersion, + REFGUID rguid) +{ + FIXME("(this=%p,%p,%ld,%s): stub!\n", + iface, hinst, dwVersion, debugstr_guid(rguid)); + return DI_OK; +} + +/****************************************************************************** + * IDirectInputDevice2A + */ + +HRESULT WINAPI IDirectInputDevice2AImpl_CreateEffect( + LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, + LPCDIEFFECT lpeff, + LPDIRECTINPUTEFFECT *ppdef, + LPUNKNOWN pUnkOuter) +{ + FIXME("(this=%p,%s,%p,%p,%p): stub!\n", + iface, debugstr_guid(rguid), lpeff, ppdef, pUnkOuter); + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_EnumEffects( + LPDIRECTINPUTDEVICE8A iface, + LPDIENUMEFFECTSCALLBACKA lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + FIXME("(this=%p,%p,%p,0x%08lx): stub!\n", + iface, lpCallback, lpvRef, dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2WImpl_EnumEffects( + LPDIRECTINPUTDEVICE8W iface, + LPDIENUMEFFECTSCALLBACKW lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + FIXME("(this=%p,%p,%p,0x%08lx): stub!\n", + iface, lpCallback, lpvRef, dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_GetEffectInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIEFFECTINFOA lpdei, + REFGUID rguid) +{ + FIXME("(this=%p,%p,%s): stub!\n", + iface, lpdei, debugstr_guid(rguid)); + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2WImpl_GetEffectInfo( + LPDIRECTINPUTDEVICE8W iface, + LPDIEFFECTINFOW lpdei, + REFGUID rguid) +{ + FIXME("(this=%p,%p,%s): stub!\n", + iface, lpdei, debugstr_guid(rguid)); + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_GetForceFeedbackState( + LPDIRECTINPUTDEVICE8A iface, + LPDWORD pdwOut) +{ + FIXME("(this=%p,%p): stub!\n", + iface, pdwOut); + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_SendForceFeedbackCommand( + LPDIRECTINPUTDEVICE8A iface, + DWORD dwFlags) +{ + FIXME("(this=%p,0x%08lx): stub!\n", + iface, dwFlags); + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects( + LPDIRECTINPUTDEVICE8A iface, + LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + FIXME("(this=%p,%p,%p,0x%08lx): stub!\n", + iface, lpCallback, lpvRef, dwFlags); + if (lpCallback) + lpCallback(NULL, lpvRef); + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_Escape( + LPDIRECTINPUTDEVICE8A iface, + LPDIEFFESCAPE lpDIEEsc) +{ + FIXME("(this=%p,%p): stub!\n", + iface, lpDIEEsc); + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_Poll( + LPDIRECTINPUTDEVICE8A iface) +{ + /* Because wine devices do not need to be polled, just return DI_NOEFFECT */ + return DI_NOEFFECT; +} + +HRESULT WINAPI IDirectInputDevice2AImpl_SendDeviceData( + LPDIRECTINPUTDEVICE8A iface, + DWORD cbObjectData, + LPCDIDEVICEOBJECTDATA rgdod, + LPDWORD pdwInOut, + DWORD dwFlags) +{ + FIXME("(this=%p,0x%08lx,%p,%p,0x%08lx): stub!\n", + iface, cbObjectData, rgdod, pdwInOut, dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice7AImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8A iface, + LPCSTR lpszFileName, + LPDIENUMEFFECTSINFILECALLBACK pec, + LPVOID pvRef, + DWORD dwFlags) +{ + FIXME("(%p)->(%s,%p,%p,%08lx): stub !\n", iface, lpszFileName, pec, pvRef, dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice7WImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8W iface, + LPCWSTR lpszFileName, + LPDIENUMEFFECTSINFILECALLBACK pec, + LPVOID pvRef, + DWORD dwFlags) +{ + FIXME("(%p)->(%s,%p,%p,%08lx): stub !\n", iface, debugstr_w(lpszFileName), pec, pvRef, dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice7AImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8A iface, + LPCSTR lpszFileName, + DWORD dwEntries, + LPDIFILEEFFECT rgDiFileEft, + DWORD dwFlags) +{ + FIXME("(%p)->(%s,%08lx,%p,%08lx): stub !\n", iface, lpszFileName, dwEntries, rgDiFileEft, dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice7WImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8W iface, + LPCWSTR lpszFileName, + DWORD dwEntries, + LPDIFILEEFFECT rgDiFileEft, + DWORD dwFlags) +{ + FIXME("(%p)->(%s,%08lx,%p,%08lx): stub !\n", iface, debugstr_w(lpszFileName), dwEntries, rgDiFileEft, dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice8AImpl_BuildActionMap(LPDIRECTINPUTDEVICE8A iface, + LPDIACTIONFORMATA lpdiaf, + LPCSTR lpszUserName, + DWORD dwFlags) +{ + FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, lpszUserName, dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice8WImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface, + LPDIACTIONFORMATW lpdiaf, + LPCWSTR lpszUserName, + DWORD dwFlags) +{ + FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice8AImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface, + LPDIACTIONFORMATA lpdiaf, + LPCSTR lpszUserName, + DWORD dwFlags) +{ + FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, lpszUserName, dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice8WImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface, + LPDIACTIONFORMATW lpdiaf, + LPCWSTR lpszUserName, + DWORD dwFlags) +{ + FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice8AImpl_GetImageInfo(LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEIMAGEINFOHEADERA lpdiDevImageInfoHeader) +{ + FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader); + + return DI_OK; +} + +HRESULT WINAPI IDirectInputDevice8WImpl_GetImageInfo(LPDIRECTINPUTDEVICE8W iface, + LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader) +{ + FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader); + + return DI_OK; +} diff --git a/reactos/lib/dinput/device_private.h b/reactos/lib/dinput/device_private.h index a044af5ef16..e7a32096efa 100644 --- a/reactos/lib/dinput/device_private.h +++ b/reactos/lib/dinput/device_private.h @@ -1,236 +1,236 @@ -/* - * Copyright 2000 Lionel Ulmer - * Copyright 2000-2001 TransGaming Technologies Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_DLLS_DINPUT_DINPUTDEVICE_PRIVATE_H -#define __WINE_DLLS_DINPUT_DINPUTDEVICE_PRIVATE_H - -#include - -#include "windef.h" -#include "winbase.h" -#include "dinput.h" - -/* Device implementation */ -typedef struct IDirectInputDevice2AImpl IDirectInputDevice2AImpl; -struct IDirectInputDevice2AImpl -{ - IDirectInputDevice2AVtbl *lpVtbl; - DWORD ref; - GUID guid; -}; - -/* Routines to do DataFormat / WineFormat conversions */ -typedef struct { - int size; - int offset_in; - int offset_out; - int value; -} DataTransform; - -typedef struct { - int size; - int internal_format_size; - DataTransform *dt; -} DataFormat; -extern void fill_DataFormat(void *out, const void *in, DataFormat *df) ; -extern DataFormat *create_DataFormat(const DIDATAFORMAT *wine_format, LPCDIDATAFORMAT asked_format, int *offset) ; -extern void release_DataFormat(DataFormat *df) ; - -/* Used to fill events in the queue */ -#define GEN_EVENT(offset,data,xtime,seq) \ -{ \ - /* If queue_len > 0, queuing is requested -> TRACE the event queued */ \ - if (This->queue_len > 0) { \ - int nq; \ - TRACE(" queueing %d at offset %d (queue head %d / size %d)\n", \ - (int) (data), (int) (offset), \ - (int) (This->queue_head), (int) (This->queue_len)); \ - \ - nq = This->queue_head+1; \ - while (nq >= This->queue_len) nq -= This->queue_len; \ - if ((offset >= 0) && (nq != This->queue_tail)) { \ - This->data_queue[This->queue_head].dwOfs = offset; \ - This->data_queue[This->queue_head].dwData = data; \ - This->data_queue[This->queue_head].dwTimeStamp = xtime; \ - This->data_queue[This->queue_head].dwSequence = seq; \ - This->queue_head = nq; \ - } else \ - This->overflow = TRUE; \ - } \ -} - -/** - * Callback Data used by specific callback - * for EnumObject on 'W' interfaces - */ -typedef struct { - LPDIENUMDEVICEOBJECTSCALLBACKW lpCallBack; - LPVOID lpvRef; -} device_enumobjects_AtoWcb_data; - -extern BOOL DIEnumDevicesCallbackAtoW(LPCDIDEVICEOBJECTINSTANCEA, LPVOID); - - -/* Various debug tools */ -extern void _dump_cooperativelevel_DI(DWORD dwFlags) ; -extern void _dump_EnumObjects_flags(DWORD dwFlags) ; -extern void _dump_DIPROPHEADER(LPCDIPROPHEADER diph) ; -extern void _dump_OBJECTINSTANCEA(DIDEVICEOBJECTINSTANCEA *ddoi) ; -extern void _dump_OBJECTINSTANCEW(DIDEVICEOBJECTINSTANCEW *ddoi) ; -extern void _dump_DIDATAFORMAT(const DIDATAFORMAT *df) ; -extern const char *_dump_dinput_GUID(const GUID *guid) ; - -/* And the stubs */ -extern HRESULT WINAPI IDirectInputDevice2AImpl_SetDataFormat( - LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df ) ; -extern HRESULT WINAPI IDirectInputDevice2AImpl_SetCooperativeLevel( - LPDIRECTINPUTDEVICE8A iface,HWND hwnd,DWORD dwflags ) ; -extern HRESULT WINAPI IDirectInputDevice2AImpl_SetEventNotification( - LPDIRECTINPUTDEVICE8A iface,HANDLE hnd ) ; -extern ULONG WINAPI IDirectInputDevice2AImpl_Release(LPDIRECTINPUTDEVICE8A iface) ; -extern HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface(LPDIRECTINPUTDEVICE8A iface,REFIID riid,LPVOID *ppobj); -extern HRESULT WINAPI IDirectInputDevice2WImpl_QueryInterface(LPDIRECTINPUTDEVICE8W iface,REFIID riid,LPVOID *ppobj); -extern ULONG WINAPI IDirectInputDevice2AImpl_AddRef( - LPDIRECTINPUTDEVICE8A iface) ; -extern HRESULT WINAPI IDirectInputDevice2AImpl_EnumObjects( - LPDIRECTINPUTDEVICE8A iface, - LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, - LPVOID lpvRef, - DWORD dwFlags) ; -extern HRESULT WINAPI IDirectInputDevice2WImpl_EnumObjects( - LPDIRECTINPUTDEVICE8W iface, - LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, - LPVOID lpvRef, - DWORD dwFlags) ; -extern HRESULT WINAPI IDirectInputDevice2AImpl_GetProperty( - LPDIRECTINPUTDEVICE8A iface, - REFGUID rguid, - LPDIPROPHEADER pdiph) ; -extern HRESULT WINAPI IDirectInputDevice2AImpl_GetObjectInfo( - LPDIRECTINPUTDEVICE8A iface, - LPDIDEVICEOBJECTINSTANCEA pdidoi, - DWORD dwObj, - DWORD dwHow) ; -extern HRESULT WINAPI IDirectInputDevice2WImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface, - LPDIDEVICEOBJECTINSTANCEW pdidoi, - DWORD dwObj, - DWORD dwHow); -extern HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceInfo( - LPDIRECTINPUTDEVICE8A iface, - LPDIDEVICEINSTANCEA pdidi) ; -extern HRESULT WINAPI IDirectInputDevice2WImpl_GetDeviceInfo( - LPDIRECTINPUTDEVICE8W iface, - LPDIDEVICEINSTANCEW pdidi) ; -extern HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel( - LPDIRECTINPUTDEVICE8A iface, - HWND hwndOwner, - DWORD dwFlags) ; -extern HRESULT WINAPI IDirectInputDevice2AImpl_Initialize( - LPDIRECTINPUTDEVICE8A iface, - HINSTANCE hinst, - DWORD dwVersion, - REFGUID rguid) ; -extern HRESULT WINAPI IDirectInputDevice2AImpl_CreateEffect( - LPDIRECTINPUTDEVICE8A iface, - REFGUID rguid, - LPCDIEFFECT lpeff, - LPDIRECTINPUTEFFECT *ppdef, - LPUNKNOWN pUnkOuter) ; -extern HRESULT WINAPI IDirectInputDevice2AImpl_EnumEffects( - LPDIRECTINPUTDEVICE8A iface, - LPDIENUMEFFECTSCALLBACKA lpCallback, - LPVOID lpvRef, - DWORD dwFlags) ; -extern HRESULT WINAPI IDirectInputDevice2WImpl_EnumEffects( - LPDIRECTINPUTDEVICE8W iface, - LPDIENUMEFFECTSCALLBACKW lpCallback, - LPVOID lpvRef, - DWORD dwFlags) ; -extern HRESULT WINAPI IDirectInputDevice2AImpl_GetEffectInfo( - LPDIRECTINPUTDEVICE8A iface, - LPDIEFFECTINFOA lpdei, - REFGUID rguid) ; -extern HRESULT WINAPI IDirectInputDevice2WImpl_GetEffectInfo( - LPDIRECTINPUTDEVICE8W iface, - LPDIEFFECTINFOW lpdei, - REFGUID rguid) ; -extern HRESULT WINAPI IDirectInputDevice2AImpl_GetForceFeedbackState( - LPDIRECTINPUTDEVICE8A iface, - LPDWORD pdwOut) ; -extern HRESULT WINAPI IDirectInputDevice2AImpl_SendForceFeedbackCommand( - LPDIRECTINPUTDEVICE8A iface, - DWORD dwFlags) ; -extern HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects( - LPDIRECTINPUTDEVICE8A iface, - LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, - LPVOID lpvRef, - DWORD dwFlags) ; -extern HRESULT WINAPI IDirectInputDevice2AImpl_Escape( - LPDIRECTINPUTDEVICE8A iface, - LPDIEFFESCAPE lpDIEEsc) ; -extern HRESULT WINAPI IDirectInputDevice2AImpl_Poll( - LPDIRECTINPUTDEVICE8A iface) ; -extern HRESULT WINAPI IDirectInputDevice2AImpl_SendDeviceData( - LPDIRECTINPUTDEVICE8A iface, - DWORD cbObjectData, - LPCDIDEVICEOBJECTDATA rgdod, - LPDWORD pdwInOut, - DWORD dwFlags) ; -extern HRESULT WINAPI IDirectInputDevice7AImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8A iface, - LPCSTR lpszFileName, - LPDIENUMEFFECTSINFILECALLBACK pec, - LPVOID pvRef, - DWORD dwFlags) ; -extern HRESULT WINAPI IDirectInputDevice7WImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8W iface, - LPCWSTR lpszFileName, - LPDIENUMEFFECTSINFILECALLBACK pec, - LPVOID pvRef, - DWORD dwFlags) ; -extern HRESULT WINAPI IDirectInputDevice7AImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8A iface, - LPCSTR lpszFileName, - DWORD dwEntries, - LPDIFILEEFFECT rgDiFileEft, - DWORD dwFlags) ; -extern HRESULT WINAPI IDirectInputDevice7WImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8W iface, - LPCWSTR lpszFileName, - DWORD dwEntries, - LPDIFILEEFFECT rgDiFileEft, - DWORD dwFlags) ; -extern HRESULT WINAPI IDirectInputDevice8AImpl_BuildActionMap(LPDIRECTINPUTDEVICE8A iface, - LPDIACTIONFORMATA lpdiaf, - LPCSTR lpszUserName, - DWORD dwFlags); -extern HRESULT WINAPI IDirectInputDevice8WImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface, - LPDIACTIONFORMATW lpdiaf, - LPCWSTR lpszUserName, - DWORD dwFlags); -extern HRESULT WINAPI IDirectInputDevice8AImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface, - LPDIACTIONFORMATA lpdiaf, - LPCSTR lpszUserName, - DWORD dwFlags); -extern HRESULT WINAPI IDirectInputDevice8WImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface, - LPDIACTIONFORMATW lpdiaf, - LPCWSTR lpszUserName, - DWORD dwFlags); -extern HRESULT WINAPI IDirectInputDevice8AImpl_GetImageInfo(LPDIRECTINPUTDEVICE8A iface, - LPDIDEVICEIMAGEINFOHEADERA lpdiDevImageInfoHeader); -extern HRESULT WINAPI IDirectInputDevice8WImpl_GetImageInfo(LPDIRECTINPUTDEVICE8W iface, - LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader); - -#endif /* __WINE_DLLS_DINPUT_DINPUTDEVICE_PRIVATE_H */ +/* + * Copyright 2000 Lionel Ulmer + * Copyright 2000-2001 TransGaming Technologies Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_DLLS_DINPUT_DINPUTDEVICE_PRIVATE_H +#define __WINE_DLLS_DINPUT_DINPUTDEVICE_PRIVATE_H + +#include + +#include "windef.h" +#include "winbase.h" +#include "dinput.h" + +/* Device implementation */ +typedef struct IDirectInputDevice2AImpl IDirectInputDevice2AImpl; +struct IDirectInputDevice2AImpl +{ + IDirectInputDevice2AVtbl *lpVtbl; + DWORD ref; + GUID guid; +}; + +/* Routines to do DataFormat / WineFormat conversions */ +typedef struct { + int size; + int offset_in; + int offset_out; + int value; +} DataTransform; + +typedef struct { + int size; + int internal_format_size; + DataTransform *dt; +} DataFormat; +extern void fill_DataFormat(void *out, const void *in, DataFormat *df) ; +extern DataFormat *create_DataFormat(const DIDATAFORMAT *wine_format, LPCDIDATAFORMAT asked_format, int *offset) ; +extern void release_DataFormat(DataFormat *df) ; + +/* Used to fill events in the queue */ +#define GEN_EVENT(offset,data,xtime,seq) \ +{ \ + /* If queue_len > 0, queuing is requested -> TRACE the event queued */ \ + if (This->queue_len > 0) { \ + int nq; \ + TRACE(" queueing %d at offset %d (queue head %d / size %d)\n", \ + (int) (data), (int) (offset), \ + (int) (This->queue_head), (int) (This->queue_len)); \ + \ + nq = This->queue_head+1; \ + while (nq >= This->queue_len) nq -= This->queue_len; \ + if ((offset >= 0) && (nq != This->queue_tail)) { \ + This->data_queue[This->queue_head].dwOfs = offset; \ + This->data_queue[This->queue_head].dwData = data; \ + This->data_queue[This->queue_head].dwTimeStamp = xtime; \ + This->data_queue[This->queue_head].dwSequence = seq; \ + This->queue_head = nq; \ + } else \ + This->overflow = TRUE; \ + } \ +} + +/** + * Callback Data used by specific callback + * for EnumObject on 'W' interfaces + */ +typedef struct { + LPDIENUMDEVICEOBJECTSCALLBACKW lpCallBack; + LPVOID lpvRef; +} device_enumobjects_AtoWcb_data; + +extern BOOL DIEnumDevicesCallbackAtoW(LPCDIDEVICEOBJECTINSTANCEA, LPVOID); + + +/* Various debug tools */ +extern void _dump_cooperativelevel_DI(DWORD dwFlags) ; +extern void _dump_EnumObjects_flags(DWORD dwFlags) ; +extern void _dump_DIPROPHEADER(LPCDIPROPHEADER diph) ; +extern void _dump_OBJECTINSTANCEA(DIDEVICEOBJECTINSTANCEA *ddoi) ; +extern void _dump_OBJECTINSTANCEW(DIDEVICEOBJECTINSTANCEW *ddoi) ; +extern void _dump_DIDATAFORMAT(const DIDATAFORMAT *df) ; +extern const char *_dump_dinput_GUID(const GUID *guid) ; + +/* And the stubs */ +extern HRESULT WINAPI IDirectInputDevice2AImpl_SetDataFormat( + LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df ) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_SetCooperativeLevel( + LPDIRECTINPUTDEVICE8A iface,HWND hwnd,DWORD dwflags ) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_SetEventNotification( + LPDIRECTINPUTDEVICE8A iface,HANDLE hnd ) ; +extern ULONG WINAPI IDirectInputDevice2AImpl_Release(LPDIRECTINPUTDEVICE8A iface) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface(LPDIRECTINPUTDEVICE8A iface,REFIID riid,LPVOID *ppobj); +extern HRESULT WINAPI IDirectInputDevice2WImpl_QueryInterface(LPDIRECTINPUTDEVICE8W iface,REFIID riid,LPVOID *ppobj); +extern ULONG WINAPI IDirectInputDevice2AImpl_AddRef( + LPDIRECTINPUTDEVICE8A iface) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_EnumObjects( + LPDIRECTINPUTDEVICE8A iface, + LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, + LPVOID lpvRef, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice2WImpl_EnumObjects( + LPDIRECTINPUTDEVICE8W iface, + LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, + LPVOID lpvRef, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_GetProperty( + LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, + LPDIPROPHEADER pdiph) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_GetObjectInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEOBJECTINSTANCEA pdidoi, + DWORD dwObj, + DWORD dwHow) ; +extern HRESULT WINAPI IDirectInputDevice2WImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface, + LPDIDEVICEOBJECTINSTANCEW pdidoi, + DWORD dwObj, + DWORD dwHow); +extern HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEINSTANCEA pdidi) ; +extern HRESULT WINAPI IDirectInputDevice2WImpl_GetDeviceInfo( + LPDIRECTINPUTDEVICE8W iface, + LPDIDEVICEINSTANCEW pdidi) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel( + LPDIRECTINPUTDEVICE8A iface, + HWND hwndOwner, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_Initialize( + LPDIRECTINPUTDEVICE8A iface, + HINSTANCE hinst, + DWORD dwVersion, + REFGUID rguid) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_CreateEffect( + LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, + LPCDIEFFECT lpeff, + LPDIRECTINPUTEFFECT *ppdef, + LPUNKNOWN pUnkOuter) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_EnumEffects( + LPDIRECTINPUTDEVICE8A iface, + LPDIENUMEFFECTSCALLBACKA lpCallback, + LPVOID lpvRef, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice2WImpl_EnumEffects( + LPDIRECTINPUTDEVICE8W iface, + LPDIENUMEFFECTSCALLBACKW lpCallback, + LPVOID lpvRef, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_GetEffectInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIEFFECTINFOA lpdei, + REFGUID rguid) ; +extern HRESULT WINAPI IDirectInputDevice2WImpl_GetEffectInfo( + LPDIRECTINPUTDEVICE8W iface, + LPDIEFFECTINFOW lpdei, + REFGUID rguid) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_GetForceFeedbackState( + LPDIRECTINPUTDEVICE8A iface, + LPDWORD pdwOut) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_SendForceFeedbackCommand( + LPDIRECTINPUTDEVICE8A iface, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects( + LPDIRECTINPUTDEVICE8A iface, + LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, + LPVOID lpvRef, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_Escape( + LPDIRECTINPUTDEVICE8A iface, + LPDIEFFESCAPE lpDIEEsc) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_Poll( + LPDIRECTINPUTDEVICE8A iface) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_SendDeviceData( + LPDIRECTINPUTDEVICE8A iface, + DWORD cbObjectData, + LPCDIDEVICEOBJECTDATA rgdod, + LPDWORD pdwInOut, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice7AImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8A iface, + LPCSTR lpszFileName, + LPDIENUMEFFECTSINFILECALLBACK pec, + LPVOID pvRef, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice7WImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8W iface, + LPCWSTR lpszFileName, + LPDIENUMEFFECTSINFILECALLBACK pec, + LPVOID pvRef, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice7AImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8A iface, + LPCSTR lpszFileName, + DWORD dwEntries, + LPDIFILEEFFECT rgDiFileEft, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice7WImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8W iface, + LPCWSTR lpszFileName, + DWORD dwEntries, + LPDIFILEEFFECT rgDiFileEft, + DWORD dwFlags) ; +extern HRESULT WINAPI IDirectInputDevice8AImpl_BuildActionMap(LPDIRECTINPUTDEVICE8A iface, + LPDIACTIONFORMATA lpdiaf, + LPCSTR lpszUserName, + DWORD dwFlags); +extern HRESULT WINAPI IDirectInputDevice8WImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface, + LPDIACTIONFORMATW lpdiaf, + LPCWSTR lpszUserName, + DWORD dwFlags); +extern HRESULT WINAPI IDirectInputDevice8AImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface, + LPDIACTIONFORMATA lpdiaf, + LPCSTR lpszUserName, + DWORD dwFlags); +extern HRESULT WINAPI IDirectInputDevice8WImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface, + LPDIACTIONFORMATW lpdiaf, + LPCWSTR lpszUserName, + DWORD dwFlags); +extern HRESULT WINAPI IDirectInputDevice8AImpl_GetImageInfo(LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEIMAGEINFOHEADERA lpdiDevImageInfoHeader); +extern HRESULT WINAPI IDirectInputDevice8WImpl_GetImageInfo(LPDIRECTINPUTDEVICE8W iface, + LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader); + +#endif /* __WINE_DLLS_DINPUT_DINPUTDEVICE_PRIVATE_H */ diff --git a/reactos/lib/dinput/dinput_main.c b/reactos/lib/dinput/dinput_main.c index bd003d07e6a..1edb9dba96d 100644 --- a/reactos/lib/dinput/dinput_main.c +++ b/reactos/lib/dinput/dinput_main.c @@ -1,756 +1,756 @@ -/* DirectInput - * - * Copyright 1998 Marcus Meissner - * Copyright 1998,1999 Lionel Ulmer - * Copyright 2000-2002 TransGaming Technologies Inc. - * - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -/* Status: - * - * - Tomb Raider 2 Demo: - * Playable using keyboard only. - * - WingCommander Prophecy Demo: - * Doesn't get Input Focus. - * - * - Fallout : works great in X and DGA mode - */ - -#include "config.h" -#include "wine/port.h" - -#include -#include -#include - -#define COBJMACROS - -#include "wine/debug.h" -#include "wine/unicode.h" -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "winerror.h" -#include "dinput_private.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dinput); - -static IDirectInput7AVtbl ddi7avt; -static IDirectInput7WVtbl ddi7wvt; -static IDirectInput8AVtbl ddi8avt; -static IDirectInput8WVtbl ddi8wvt; - -/* This array will be filled a dinput.so loading */ -#define MAX_WINE_DINPUT_DEVICES 4 -static dinput_device * dinput_devices[MAX_WINE_DINPUT_DEVICES]; -static int nrof_dinput_devices = 0; - -HINSTANCE DINPUT_instance = NULL; - -BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserv) -{ - switch(reason) - { - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(inst); - DINPUT_instance = inst; - break; - case DLL_PROCESS_DETACH: - break; - } - return TRUE; -} - -/* register a direct draw driver. We better not use malloc for we are in - * the ELF startup initialisation at this point. - */ -void dinput_register_device(dinput_device *device) { - int i; - - /* insert according to priority */ - for (i=0;ipref <= device->pref) { - memcpy(dinput_devices+i+1,dinput_devices+i,sizeof(dinput_devices[0])*(nrof_dinput_devices-i)); - dinput_devices[i] = device; - break; - } - } - if (i==nrof_dinput_devices) /* not found, or too low priority */ - dinput_devices[nrof_dinput_devices] = device; - - nrof_dinput_devices++; - - /* increase MAX_DDRAW_DRIVERS if the line below triggers */ - assert(nrof_dinput_devices <= MAX_WINE_DINPUT_DEVICES); -} - -/****************************************************************************** - * DirectInputCreateEx (DINPUT.@) - */ -HRESULT WINAPI DirectInputCreateEx( - HINSTANCE hinst, DWORD dwVersion, REFIID riid, LPVOID *ppDI, - LPUNKNOWN punkOuter) -{ - IDirectInputImpl* This; - - TRACE("(0x%08lx,%04lx,%s,%p,%p)\n", (DWORD)hinst,dwVersion,debugstr_guid(riid),ppDI,punkOuter); - - if (IsEqualGUID(&IID_IDirectInputA,riid) || - IsEqualGUID(&IID_IDirectInput2A,riid) || - IsEqualGUID(&IID_IDirectInput7A,riid)) { - This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); - This->lpVtbl = &ddi7avt; - This->ref = 1; - This->version = 1; - *ppDI = This; - - return DI_OK; - } - - if (IsEqualGUID(&IID_IDirectInputW,riid) || - IsEqualGUID(&IID_IDirectInput2W,riid) || - IsEqualGUID(&IID_IDirectInput7W,riid)) { - This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); - This->lpVtbl = &ddi7wvt; - This->ref = 1; - This->version = 1; - *ppDI = This; - - return DI_OK; - } - - if (IsEqualGUID(&IID_IDirectInput8A,riid)) { - This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); - This->lpVtbl = &ddi8avt; - This->ref = 1; - This->version = 8; - *ppDI = This; - - return DI_OK; - } - - if (IsEqualGUID(&IID_IDirectInput8W,riid)) { - This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); - This->lpVtbl = &ddi8wvt; - This->ref = 1; - This->version = 8; - *ppDI = This; - - return DI_OK; - } - - return DIERR_OLDDIRECTINPUTVERSION; -} - -/****************************************************************************** - * DirectInputCreateA (DINPUT.@) - */ -HRESULT WINAPI DirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter) -{ - IDirectInputImpl* This; - TRACE("(0x%08lx,%04lx,%p,%p)\n", (DWORD)hinst,dwVersion,ppDI,punkOuter); - - //trace:dinput:DirectInputCreateA (0x00400000,0500,0x42bafc54,(nil)) - This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); - This->lpVtbl = &ddi7avt; - This->ref = 1; - if (dwVersion > 0x0700) { - This->version = 8; - } else { - /* We do not differientiate between version 1, 2 and 7 */ - This->version = 1; - } - *ppDI = (IDirectInputA*)This; - return 0; - -} - -/****************************************************************************** - * DirectInputCreateW (DINPUT.@) - */ -HRESULT WINAPI DirectInputCreateW(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTW *ppDI, LPUNKNOWN punkOuter) -{ - IDirectInputImpl* This; - TRACE("(0x%08lx,%04lx,%p,%p)\n", (DWORD)hinst,dwVersion,ppDI,punkOuter); - This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); - This->lpVtbl = &ddi7wvt; - This->ref = 1; - if (dwVersion >= 0x0800) { - This->version = 8; - } else { - /* We do not differientiate between version 1, 2 and 7 */ - This->version = 1; - } - *ppDI = (IDirectInputW*)This; - return 0; -} - -static const char *_dump_DIDEVTYPE_value(DWORD dwDevType) { - switch (dwDevType) { - case 0: return "All devices"; - case DIDEVTYPE_MOUSE: return "DIDEVTYPE_MOUSE"; - case DIDEVTYPE_KEYBOARD: return "DIDEVTYPE_KEYBOARD"; - case DIDEVTYPE_JOYSTICK: return "DIDEVTYPE_JOYSTICK"; - case DIDEVTYPE_DEVICE: return "DIDEVTYPE_DEVICE"; - default: return "Unkown"; - } -} - -static void _dump_EnumDevices_dwFlags(DWORD dwFlags) { - if (TRACE_ON(dinput)) { - unsigned int i; - static const struct { - DWORD mask; - const char *name; - } flags[] = { -#define FE(x) { x, #x} - FE(DIEDFL_ALLDEVICES), - FE(DIEDFL_ATTACHEDONLY), - FE(DIEDFL_FORCEFEEDBACK), - FE(DIEDFL_INCLUDEALIASES), - FE(DIEDFL_INCLUDEPHANTOMS) -#undef FE - }; - if (dwFlags == 0) { - DPRINTF("DIEDFL_ALLDEVICES"); - return; - } - for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) - if (flags[i].mask & dwFlags) - DPRINTF("%s ",flags[i].name); - } -} - -/****************************************************************************** - * IDirectInputA_EnumDevices - */ -static HRESULT WINAPI IDirectInputAImpl_EnumDevices( - LPDIRECTINPUT7A iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, - LPVOID pvRef, DWORD dwFlags) -{ - IDirectInputImpl *This = (IDirectInputImpl *)iface; - DIDEVICEINSTANCEA devInstance; - int i, j, r; - - TRACE("(this=%p,0x%04lx '%s',%p,%p,%04lx)\n", - This, dwDevType, _dump_DIDEVTYPE_value(dwDevType), - lpCallback, pvRef, dwFlags); - - if (nrof_dinput_devices==0){ - scan_mouse(); - scan_keyboard(); - } - - TRACE(" flags: "); _dump_EnumDevices_dwFlags(dwFlags); TRACE("\n"); - - - for (i = 0; i < nrof_dinput_devices; i++) { - for (j = 0, r = -1; r != 0; j++) { - devInstance.dwSize = sizeof(devInstance); - TRACE(" - checking device %d ('%s')\n", i, dinput_devices[i]->name); - - - if ((r = dinput_devices[i]->enum_deviceA(dwDevType, dwFlags, &devInstance, This->version, j))) { - if (lpCallback(&devInstance,pvRef) == DIENUM_STOP) - return 0; - } - } - } - - return 0; -} -/****************************************************************************** - * IDirectInputW_EnumDevices - */ -static HRESULT WINAPI IDirectInputWImpl_EnumDevices( - LPDIRECTINPUT7W iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, - LPVOID pvRef, DWORD dwFlags) -{ - IDirectInputImpl *This = (IDirectInputImpl *)iface; - DIDEVICEINSTANCEW devInstance; - int i, j, r; - - if (nrof_dinput_devices==0){ - scan_mouse(); - scan_keyboard(); - } - - TRACE("(this=%p,0x%04lx '%s',%p,%p,%04lx)\n", - This, dwDevType, _dump_DIDEVTYPE_value(dwDevType), - lpCallback, pvRef, dwFlags); - TRACE(" flags: "); _dump_EnumDevices_dwFlags(dwFlags); TRACE("\n"); - - - for (i = 0; i < nrof_dinput_devices; i++) { - for (j = 0, r = -1; r != 0; j++) { - devInstance.dwSize = sizeof(devInstance); - TRACE(" - checking device %d ('%s')\n", i, dinput_devices[i]->name); - if ((r = dinput_devices[i]->enum_deviceW(dwDevType, dwFlags, &devInstance, This->version, j))) { - if (lpCallback(&devInstance,pvRef) == DIENUM_STOP) - return 0; - } - } - } - - return 0; -} - -static ULONG WINAPI IDirectInputAImpl_AddRef(LPDIRECTINPUT7A iface) -{ - IDirectInputImpl *This = (IDirectInputImpl *)iface; - return InterlockedIncrement((&This->ref)); -} - -static ULONG WINAPI IDirectInputAImpl_Release(LPDIRECTINPUT7A iface) -{ - IDirectInputImpl *This = (IDirectInputImpl *)iface; - ULONG ref; - ref = InterlockedDecrement(&(This->ref)); - if (ref == 0) - HeapFree(GetProcessHeap(),0,This); - return ref; -} - -static HRESULT WINAPI IDirectInputAImpl_QueryInterface(LPDIRECTINPUT7A iface, REFIID riid, LPVOID *ppobj) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; - - TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); - if (IsEqualGUID(&IID_IUnknown,riid) || - IsEqualGUID(&IID_IDirectInputA,riid) || - IsEqualGUID(&IID_IDirectInput2A,riid) || - IsEqualGUID(&IID_IDirectInput7A,riid)) { - IDirectInputAImpl_AddRef(iface); - *ppobj = This; - return 0; - } - TRACE("Unsupported interface !\n"); - return E_FAIL; -} - -static HRESULT WINAPI IDirectInputWImpl_QueryInterface(LPDIRECTINPUT7W iface, REFIID riid, LPVOID *ppobj) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; - - TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); - if (IsEqualGUID(&IID_IUnknown,riid) || - IsEqualGUID(&IID_IDirectInputW,riid) || - IsEqualGUID(&IID_IDirectInput2W,riid) || - IsEqualGUID(&IID_IDirectInput7W,riid)) { - IDirectInputAImpl_AddRef((LPDIRECTINPUT7A) iface); - *ppobj = This; - return 0; - } - TRACE("Unsupported interface !\n"); - return E_FAIL; -} - -static HRESULT WINAPI IDirectInputAImpl_CreateDevice( - LPDIRECTINPUT7A iface,REFGUID rguid,LPDIRECTINPUTDEVICEA* pdev, - LPUNKNOWN punk -) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; - HRESULT ret_value = DIERR_DEVICENOTREG; - int i; - - TRACE("(this=%p,%s,%p,%p)\n",This,debugstr_guid(rguid),pdev,punk); - - if (nrof_dinput_devices==0){ - scan_mouse(); - scan_keyboard(); - } - - /* Loop on all the devices to see if anyone matches the given GUID */ - for (i = 0; i < nrof_dinput_devices; i++) { - HRESULT ret; - if ((ret = dinput_devices[i]->create_deviceA(This, rguid, NULL, pdev)) == DI_OK) - return DI_OK; - - if (ret == DIERR_NOINTERFACE) - ret_value = DIERR_NOINTERFACE; - } - - return ret_value; -} - -static HRESULT WINAPI IDirectInputWImpl_CreateDevice(LPDIRECTINPUT7A iface, - REFGUID rguid, LPDIRECTINPUTDEVICEW* pdev, LPUNKNOWN punk) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; - HRESULT ret_value = DIERR_DEVICENOTREG; - int i; - - TRACE("(this=%p,%s,%p,%p)\n",This,debugstr_guid(rguid),pdev,punk); - - if (nrof_dinput_devices==0){ - scan_mouse(); - scan_keyboard(); - } - - /* Loop on all the devices to see if anyone matches the given GUID */ - for (i = 0; i < nrof_dinput_devices; i++) { - HRESULT ret; - if ((ret = dinput_devices[i]->create_deviceW(This, rguid, NULL, pdev)) == DI_OK) - return DI_OK; - - if (ret == DIERR_NOINTERFACE) - ret_value = DIERR_NOINTERFACE; - } - - return ret_value; -} - -static HRESULT WINAPI IDirectInputAImpl_Initialize(LPDIRECTINPUT7A iface, HINSTANCE hinst, DWORD x) { - return DIERR_ALREADYINITIALIZED; -} - -static HRESULT WINAPI IDirectInputAImpl_GetDeviceStatus(LPDIRECTINPUT7A iface, - REFGUID rguid) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; - - FIXME("(%p)->(%s): stub\n",This,debugstr_guid(rguid)); - - return DI_OK; -} - -static HRESULT WINAPI IDirectInputAImpl_RunControlPanel(LPDIRECTINPUT7A iface, - HWND hwndOwner, - DWORD dwFlags) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; - FIXME("(%p)->(%08lx,%08lx): stub\n",This, (DWORD) hwndOwner, dwFlags); - - return DI_OK; -} - -static HRESULT WINAPI IDirectInput2AImpl_FindDevice(LPDIRECTINPUT7A iface, REFGUID rguid, - LPCSTR pszName, LPGUID pguidInstance) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; - FIXME("(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), pszName, pguidInstance); - - return DI_OK; -} - -static HRESULT WINAPI IDirectInput2WImpl_FindDevice(LPDIRECTINPUT7W iface, REFGUID rguid, - LPCWSTR pszName, LPGUID pguidInstance) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; - FIXME("(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), debugstr_w(pszName), pguidInstance); - - return DI_OK; -} - -static HRESULT WINAPI IDirectInput7AImpl_CreateDeviceEx(LPDIRECTINPUT7A iface, REFGUID rguid, - REFIID riid, LPVOID* pvOut, LPUNKNOWN lpUnknownOuter) -{ - IDirectInputImpl *This = (IDirectInputImpl *)iface; - HRESULT ret_value = DIERR_DEVICENOTREG; - int i; - - TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter); - - if (nrof_dinput_devices==0){ - scan_mouse(); - scan_keyboard(); - } - - /* Loop on all the devices to see if anyone matches the given GUID */ - for (i = 0; i < nrof_dinput_devices; i++) { - HRESULT ret; - if ((ret = dinput_devices[i]->create_deviceA(This, rguid, riid, (LPDIRECTINPUTDEVICEA*) pvOut)) == DI_OK) - return DI_OK; - - if (ret == DIERR_NOINTERFACE) - ret_value = DIERR_NOINTERFACE; - } - - return ret_value; -} - -static HRESULT WINAPI IDirectInput7WImpl_CreateDeviceEx(LPDIRECTINPUT7W iface, REFGUID rguid, - REFIID riid, LPVOID* pvOut, LPUNKNOWN lpUnknownOuter) -{ - IDirectInputImpl *This = (IDirectInputImpl *)iface; - HRESULT ret_value = DIERR_DEVICENOTREG; - int i; - - TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter); - - if (nrof_dinput_devices==0){ - scan_mouse(); - scan_keyboard(); - } - - - - /* Loop on all the devices to see if anyone matches the given GUID */ - for (i = 0; i < nrof_dinput_devices; i++) { - HRESULT ret; - if ((ret = dinput_devices[i]->create_deviceW(This, rguid, riid, (LPDIRECTINPUTDEVICEW*) pvOut)) == DI_OK) - return DI_OK; - - if (ret == DIERR_NOINTERFACE) - ret_value = DIERR_NOINTERFACE; - } - - return ret_value; -} - -static HRESULT WINAPI IDirectInput8AImpl_QueryInterface(LPDIRECTINPUT8A iface, REFIID riid, LPVOID *ppobj) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; - - TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); - if (IsEqualGUID(&IID_IUnknown,riid) || - IsEqualGUID(&IID_IDirectInput8A,riid)) { - IDirectInputAImpl_AddRef((LPDIRECTINPUT7A) iface); - *ppobj = This; - return 0; - } - TRACE("Unsupported interface !\n"); - return E_NOINTERFACE; -} - -static HRESULT WINAPI IDirectInput8WImpl_QueryInterface(LPDIRECTINPUT8W iface, REFIID riid, LPVOID *ppobj) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; - - TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); - if (IsEqualGUID(&IID_IUnknown,riid) || - IsEqualGUID(&IID_IDirectInput8W,riid)) { - IDirectInputAImpl_AddRef((LPDIRECTINPUT7A) iface); - *ppobj = This; - return 0; - } - TRACE("Unsupported interface !\n"); - return E_NOINTERFACE; -} - -static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics( - LPDIRECTINPUT8A iface, LPCSTR ptszUserName, LPDIACTIONFORMATA lpdiActionFormat, - LPDIENUMDEVICESBYSEMANTICSCBA lpCallback, - LPVOID pvRef, DWORD dwFlags -) -{ - IDirectInputImpl *This = (IDirectInputImpl *)iface; - - FIXME("(this=%p,%s,%p,%p,%p,%04lx): stub\n", This, ptszUserName, lpdiActionFormat, - lpCallback, pvRef, dwFlags); - return 0; -} - -static HRESULT WINAPI IDirectInput8WImpl_EnumDevicesBySemantics( - LPDIRECTINPUT8W iface, LPCWSTR ptszUserName, LPDIACTIONFORMATW lpdiActionFormat, - LPDIENUMDEVICESBYSEMANTICSCBW lpCallback, - LPVOID pvRef, DWORD dwFlags -) -{ - IDirectInputImpl *This = (IDirectInputImpl *)iface; - - FIXME("(this=%p,%s,%p,%p,%p,%04lx): stub\n", This, debugstr_w(ptszUserName), lpdiActionFormat, - lpCallback, pvRef, dwFlags); - return 0; -} - -static HRESULT WINAPI IDirectInput8AImpl_ConfigureDevices( - LPDIRECTINPUT8A iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback, - LPDICONFIGUREDEVICESPARAMSA lpdiCDParams, DWORD dwFlags, LPVOID pvRefData -) -{ - IDirectInputImpl *This = (IDirectInputImpl *)iface; - - FIXME("(this=%p,%p,%p,%04lx,%p): stub\n", This, lpdiCallback, lpdiCDParams, - dwFlags, pvRefData); - return 0; -} - -static HRESULT WINAPI IDirectInput8WImpl_ConfigureDevices( - LPDIRECTINPUT8W iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback, - LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData -) -{ - IDirectInputImpl *This = (IDirectInputImpl *)iface; - - FIXME("(this=%p,%p,%p,%04lx,%p): stub\n", This, lpdiCallback, lpdiCDParams, - dwFlags, pvRefData); - return 0; -} - -#if !defined(__STRICT_ANSI__) && defined(__GNUC__) -# define XCAST(fun) (typeof(ddi7avt.fun)) -#else -# define XCAST(fun) (void*) -#endif - -static IDirectInput7AVtbl ddi7avt = { - XCAST(QueryInterface)IDirectInputAImpl_QueryInterface, - XCAST(AddRef)IDirectInputAImpl_AddRef, - XCAST(Release)IDirectInputAImpl_Release, - XCAST(CreateDevice)IDirectInputAImpl_CreateDevice, - XCAST(EnumDevices)IDirectInputAImpl_EnumDevices, - XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus, - XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel, - XCAST(Initialize)IDirectInputAImpl_Initialize, - XCAST(FindDevice)IDirectInput2AImpl_FindDevice, - XCAST(CreateDeviceEx)IDirectInput7AImpl_CreateDeviceEx -}; - -#undef XCAST -#if !defined(__STRICT_ANSI__) && defined(__GNUC__) -# define XCAST(fun) (typeof(ddi7wvt.fun)) -#else -# define XCAST(fun) (void*) -#endif - -static IDirectInput7WVtbl ddi7wvt = { - XCAST(QueryInterface)IDirectInputWImpl_QueryInterface, - XCAST(AddRef)IDirectInputAImpl_AddRef, - XCAST(Release)IDirectInputAImpl_Release, - XCAST(CreateDevice)IDirectInputWImpl_CreateDevice, - XCAST(EnumDevices)IDirectInputWImpl_EnumDevices, - XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus, - XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel, - XCAST(Initialize)IDirectInputAImpl_Initialize, - XCAST(FindDevice)IDirectInput2WImpl_FindDevice, - XCAST(CreateDeviceEx)IDirectInput7WImpl_CreateDeviceEx -}; -#undef XCAST - -#if !defined(__STRICT_ANSI__) && defined(__GNUC__) -# define XCAST(fun) (typeof(ddi8avt.fun)) -#else -# define XCAST(fun) (void*) -#endif - -static IDirectInput8AVtbl ddi8avt = { - XCAST(QueryInterface)IDirectInput8AImpl_QueryInterface, - XCAST(AddRef)IDirectInputAImpl_AddRef, - XCAST(Release)IDirectInputAImpl_Release, - XCAST(CreateDevice)IDirectInputAImpl_CreateDevice, - XCAST(EnumDevices)IDirectInputAImpl_EnumDevices, - XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus, - XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel, - XCAST(Initialize)IDirectInputAImpl_Initialize, - XCAST(FindDevice)IDirectInput2AImpl_FindDevice, - XCAST(EnumDevicesBySemantics)IDirectInput8AImpl_EnumDevicesBySemantics, - XCAST(ConfigureDevices)IDirectInput8AImpl_ConfigureDevices -}; -#undef XCAST - -#if !defined(__STRICT_ANSI__) && defined(__GNUC__) -# define XCAST(fun) (typeof(ddi8wvt.fun)) -#else -# define XCAST(fun) (void*) -#endif -static IDirectInput8WVtbl ddi8wvt = { - XCAST(QueryInterface)IDirectInput8WImpl_QueryInterface, - XCAST(AddRef)IDirectInputAImpl_AddRef, - XCAST(Release)IDirectInputAImpl_Release, - XCAST(CreateDevice)IDirectInputWImpl_CreateDevice, - XCAST(EnumDevices)IDirectInputWImpl_EnumDevices, - XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus, - XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel, - XCAST(Initialize)IDirectInputAImpl_Initialize, - XCAST(FindDevice)IDirectInput2WImpl_FindDevice, - XCAST(EnumDevicesBySemantics)IDirectInput8WImpl_EnumDevicesBySemantics, - XCAST(ConfigureDevices)IDirectInput8WImpl_ConfigureDevices -}; -#undef XCAST - -/******************************************************************************* - * DirectInput ClassFactory - */ -typedef struct -{ - /* IUnknown fields */ - IClassFactoryVtbl *lpVtbl; - DWORD ref; -} IClassFactoryImpl; - -static HRESULT WINAPI DICF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - - FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj); - return E_NOINTERFACE; -} - -static ULONG WINAPI DICF_AddRef(LPCLASSFACTORY iface) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - return InterlockedIncrement(&(This->ref)); -} - -static ULONG WINAPI DICF_Release(LPCLASSFACTORY iface) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - /* static class, won't be freed */ - return InterlockedDecrement(&(This->ref)); -} - -static HRESULT WINAPI DICF_CreateInstance( - LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj -) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - - TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj); - if ( IsEqualGUID( &IID_IDirectInputA, riid ) || - IsEqualGUID( &IID_IDirectInputW, riid ) || - IsEqualGUID( &IID_IDirectInput2A, riid ) || - IsEqualGUID( &IID_IDirectInput2W, riid ) || - IsEqualGUID( &IID_IDirectInput7A, riid ) || - IsEqualGUID( &IID_IDirectInput7W, riid ) || - IsEqualGUID( &IID_IDirectInput8A, riid ) || - IsEqualGUID( &IID_IDirectInput8W, riid ) ) { - /* FIXME: reuse already created dinput if present? */ - return DirectInputCreateEx(0,0,riid,ppobj,pOuter); - } - - FIXME("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); - return E_NOINTERFACE; -} - -static HRESULT WINAPI DICF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - FIXME("(%p)->(%d),stub!\n",This,dolock); - return S_OK; -} - -static IClassFactoryVtbl DICF_Vtbl = { - DICF_QueryInterface, - DICF_AddRef, - DICF_Release, - DICF_CreateInstance, - DICF_LockServer -}; -static IClassFactoryImpl DINPUT_CF = {&DICF_Vtbl, 1 }; - -/*********************************************************************** - * DllCanUnloadNow (DINPUT.@) - */ -HRESULT WINAPI DINPUT_DllCanUnloadNow(void) -{ - FIXME("(void): stub\n"); - - return S_FALSE; -} - -/*********************************************************************** - * DllGetClassObject (DINPUT.@) - */ -HRESULT WINAPI DINPUT_DllGetClassObject(REFCLSID rclsid, REFIID riid, - LPVOID *ppv) -{ - TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); - if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) { - *ppv = (LPVOID)&DINPUT_CF; - IClassFactory_AddRef((IClassFactory*)*ppv); - return S_OK; - } - - FIXME("(%s,%s,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); - return CLASS_E_CLASSNOTAVAILABLE; -} +/* DirectInput + * + * Copyright 1998 Marcus Meissner + * Copyright 1998,1999 Lionel Ulmer + * Copyright 2000-2002 TransGaming Technologies Inc. + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* Status: + * + * - Tomb Raider 2 Demo: + * Playable using keyboard only. + * - WingCommander Prophecy Demo: + * Doesn't get Input Focus. + * + * - Fallout : works great in X and DGA mode + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include + +#define COBJMACROS + +#include "wine/debug.h" +#include "wine/unicode.h" +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winerror.h" +#include "dinput_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dinput); + +static IDirectInput7AVtbl ddi7avt; +static IDirectInput7WVtbl ddi7wvt; +static IDirectInput8AVtbl ddi8avt; +static IDirectInput8WVtbl ddi8wvt; + +/* This array will be filled a dinput.so loading */ +#define MAX_WINE_DINPUT_DEVICES 4 +static dinput_device * dinput_devices[MAX_WINE_DINPUT_DEVICES]; +static int nrof_dinput_devices = 0; + +HINSTANCE DINPUT_instance = NULL; + +BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserv) +{ + switch(reason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(inst); + DINPUT_instance = inst; + break; + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + +/* register a direct draw driver. We better not use malloc for we are in + * the ELF startup initialisation at this point. + */ +void dinput_register_device(dinput_device *device) { + int i; + + /* insert according to priority */ + for (i=0;ipref <= device->pref) { + memcpy(dinput_devices+i+1,dinput_devices+i,sizeof(dinput_devices[0])*(nrof_dinput_devices-i)); + dinput_devices[i] = device; + break; + } + } + if (i==nrof_dinput_devices) /* not found, or too low priority */ + dinput_devices[nrof_dinput_devices] = device; + + nrof_dinput_devices++; + + /* increase MAX_DDRAW_DRIVERS if the line below triggers */ + assert(nrof_dinput_devices <= MAX_WINE_DINPUT_DEVICES); +} + +/****************************************************************************** + * DirectInputCreateEx (DINPUT.@) + */ +HRESULT WINAPI DirectInputCreateEx( + HINSTANCE hinst, DWORD dwVersion, REFIID riid, LPVOID *ppDI, + LPUNKNOWN punkOuter) +{ + IDirectInputImpl* This; + + TRACE("(0x%08lx,%04lx,%s,%p,%p)\n", (DWORD)hinst,dwVersion,debugstr_guid(riid),ppDI,punkOuter); + + if (IsEqualGUID(&IID_IDirectInputA,riid) || + IsEqualGUID(&IID_IDirectInput2A,riid) || + IsEqualGUID(&IID_IDirectInput7A,riid)) { + This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); + This->lpVtbl = &ddi7avt; + This->ref = 1; + This->version = 1; + *ppDI = This; + + return DI_OK; + } + + if (IsEqualGUID(&IID_IDirectInputW,riid) || + IsEqualGUID(&IID_IDirectInput2W,riid) || + IsEqualGUID(&IID_IDirectInput7W,riid)) { + This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); + This->lpVtbl = &ddi7wvt; + This->ref = 1; + This->version = 1; + *ppDI = This; + + return DI_OK; + } + + if (IsEqualGUID(&IID_IDirectInput8A,riid)) { + This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); + This->lpVtbl = &ddi8avt; + This->ref = 1; + This->version = 8; + *ppDI = This; + + return DI_OK; + } + + if (IsEqualGUID(&IID_IDirectInput8W,riid)) { + This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); + This->lpVtbl = &ddi8wvt; + This->ref = 1; + This->version = 8; + *ppDI = This; + + return DI_OK; + } + + return DIERR_OLDDIRECTINPUTVERSION; +} + +/****************************************************************************** + * DirectInputCreateA (DINPUT.@) + */ +HRESULT WINAPI DirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter) +{ + IDirectInputImpl* This; + TRACE("(0x%08lx,%04lx,%p,%p)\n", (DWORD)hinst,dwVersion,ppDI,punkOuter); + + //trace:dinput:DirectInputCreateA (0x00400000,0500,0x42bafc54,(nil)) + This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); + This->lpVtbl = &ddi7avt; + This->ref = 1; + if (dwVersion > 0x0700) { + This->version = 8; + } else { + /* We do not differientiate between version 1, 2 and 7 */ + This->version = 1; + } + *ppDI = (IDirectInputA*)This; + return 0; + +} + +/****************************************************************************** + * DirectInputCreateW (DINPUT.@) + */ +HRESULT WINAPI DirectInputCreateW(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTW *ppDI, LPUNKNOWN punkOuter) +{ + IDirectInputImpl* This; + TRACE("(0x%08lx,%04lx,%p,%p)\n", (DWORD)hinst,dwVersion,ppDI,punkOuter); + This = (IDirectInputImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); + This->lpVtbl = &ddi7wvt; + This->ref = 1; + if (dwVersion >= 0x0800) { + This->version = 8; + } else { + /* We do not differientiate between version 1, 2 and 7 */ + This->version = 1; + } + *ppDI = (IDirectInputW*)This; + return 0; +} + +static const char *_dump_DIDEVTYPE_value(DWORD dwDevType) { + switch (dwDevType) { + case 0: return "All devices"; + case DIDEVTYPE_MOUSE: return "DIDEVTYPE_MOUSE"; + case DIDEVTYPE_KEYBOARD: return "DIDEVTYPE_KEYBOARD"; + case DIDEVTYPE_JOYSTICK: return "DIDEVTYPE_JOYSTICK"; + case DIDEVTYPE_DEVICE: return "DIDEVTYPE_DEVICE"; + default: return "Unkown"; + } +} + +static void _dump_EnumDevices_dwFlags(DWORD dwFlags) { + if (TRACE_ON(dinput)) { + unsigned int i; + static const struct { + DWORD mask; + const char *name; + } flags[] = { +#define FE(x) { x, #x} + FE(DIEDFL_ALLDEVICES), + FE(DIEDFL_ATTACHEDONLY), + FE(DIEDFL_FORCEFEEDBACK), + FE(DIEDFL_INCLUDEALIASES), + FE(DIEDFL_INCLUDEPHANTOMS) +#undef FE + }; + if (dwFlags == 0) { + DPRINTF("DIEDFL_ALLDEVICES"); + return; + } + for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) + if (flags[i].mask & dwFlags) + DPRINTF("%s ",flags[i].name); + } +} + +/****************************************************************************** + * IDirectInputA_EnumDevices + */ +static HRESULT WINAPI IDirectInputAImpl_EnumDevices( + LPDIRECTINPUT7A iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, + LPVOID pvRef, DWORD dwFlags) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; + DIDEVICEINSTANCEA devInstance; + int i, j, r; + + TRACE("(this=%p,0x%04lx '%s',%p,%p,%04lx)\n", + This, dwDevType, _dump_DIDEVTYPE_value(dwDevType), + lpCallback, pvRef, dwFlags); + + if (nrof_dinput_devices==0){ + scan_mouse(); + scan_keyboard(); + } + + TRACE(" flags: "); _dump_EnumDevices_dwFlags(dwFlags); TRACE("\n"); + + + for (i = 0; i < nrof_dinput_devices; i++) { + for (j = 0, r = -1; r != 0; j++) { + devInstance.dwSize = sizeof(devInstance); + TRACE(" - checking device %d ('%s')\n", i, dinput_devices[i]->name); + + + if ((r = dinput_devices[i]->enum_deviceA(dwDevType, dwFlags, &devInstance, This->version, j))) { + if (lpCallback(&devInstance,pvRef) == DIENUM_STOP) + return 0; + } + } + } + + return 0; +} +/****************************************************************************** + * IDirectInputW_EnumDevices + */ +static HRESULT WINAPI IDirectInputWImpl_EnumDevices( + LPDIRECTINPUT7W iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, + LPVOID pvRef, DWORD dwFlags) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; + DIDEVICEINSTANCEW devInstance; + int i, j, r; + + if (nrof_dinput_devices==0){ + scan_mouse(); + scan_keyboard(); + } + + TRACE("(this=%p,0x%04lx '%s',%p,%p,%04lx)\n", + This, dwDevType, _dump_DIDEVTYPE_value(dwDevType), + lpCallback, pvRef, dwFlags); + TRACE(" flags: "); _dump_EnumDevices_dwFlags(dwFlags); TRACE("\n"); + + + for (i = 0; i < nrof_dinput_devices; i++) { + for (j = 0, r = -1; r != 0; j++) { + devInstance.dwSize = sizeof(devInstance); + TRACE(" - checking device %d ('%s')\n", i, dinput_devices[i]->name); + if ((r = dinput_devices[i]->enum_deviceW(dwDevType, dwFlags, &devInstance, This->version, j))) { + if (lpCallback(&devInstance,pvRef) == DIENUM_STOP) + return 0; + } + } + } + + return 0; +} + +static ULONG WINAPI IDirectInputAImpl_AddRef(LPDIRECTINPUT7A iface) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; + return InterlockedIncrement((&This->ref)); +} + +static ULONG WINAPI IDirectInputAImpl_Release(LPDIRECTINPUT7A iface) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; + ULONG ref; + ref = InterlockedDecrement(&(This->ref)); + if (ref == 0) + HeapFree(GetProcessHeap(),0,This); + return ref; +} + +static HRESULT WINAPI IDirectInputAImpl_QueryInterface(LPDIRECTINPUT7A iface, REFIID riid, LPVOID *ppobj) { + IDirectInputImpl *This = (IDirectInputImpl *)iface; + + TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(&IID_IUnknown,riid) || + IsEqualGUID(&IID_IDirectInputA,riid) || + IsEqualGUID(&IID_IDirectInput2A,riid) || + IsEqualGUID(&IID_IDirectInput7A,riid)) { + IDirectInputAImpl_AddRef(iface); + *ppobj = This; + return 0; + } + TRACE("Unsupported interface !\n"); + return E_FAIL; +} + +static HRESULT WINAPI IDirectInputWImpl_QueryInterface(LPDIRECTINPUT7W iface, REFIID riid, LPVOID *ppobj) { + IDirectInputImpl *This = (IDirectInputImpl *)iface; + + TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(&IID_IUnknown,riid) || + IsEqualGUID(&IID_IDirectInputW,riid) || + IsEqualGUID(&IID_IDirectInput2W,riid) || + IsEqualGUID(&IID_IDirectInput7W,riid)) { + IDirectInputAImpl_AddRef((LPDIRECTINPUT7A) iface); + *ppobj = This; + return 0; + } + TRACE("Unsupported interface !\n"); + return E_FAIL; +} + +static HRESULT WINAPI IDirectInputAImpl_CreateDevice( + LPDIRECTINPUT7A iface,REFGUID rguid,LPDIRECTINPUTDEVICEA* pdev, + LPUNKNOWN punk +) { + IDirectInputImpl *This = (IDirectInputImpl *)iface; + HRESULT ret_value = DIERR_DEVICENOTREG; + int i; + + TRACE("(this=%p,%s,%p,%p)\n",This,debugstr_guid(rguid),pdev,punk); + + if (nrof_dinput_devices==0){ + scan_mouse(); + scan_keyboard(); + } + + /* Loop on all the devices to see if anyone matches the given GUID */ + for (i = 0; i < nrof_dinput_devices; i++) { + HRESULT ret; + if ((ret = dinput_devices[i]->create_deviceA(This, rguid, NULL, pdev)) == DI_OK) + return DI_OK; + + if (ret == DIERR_NOINTERFACE) + ret_value = DIERR_NOINTERFACE; + } + + return ret_value; +} + +static HRESULT WINAPI IDirectInputWImpl_CreateDevice(LPDIRECTINPUT7A iface, + REFGUID rguid, LPDIRECTINPUTDEVICEW* pdev, LPUNKNOWN punk) { + IDirectInputImpl *This = (IDirectInputImpl *)iface; + HRESULT ret_value = DIERR_DEVICENOTREG; + int i; + + TRACE("(this=%p,%s,%p,%p)\n",This,debugstr_guid(rguid),pdev,punk); + + if (nrof_dinput_devices==0){ + scan_mouse(); + scan_keyboard(); + } + + /* Loop on all the devices to see if anyone matches the given GUID */ + for (i = 0; i < nrof_dinput_devices; i++) { + HRESULT ret; + if ((ret = dinput_devices[i]->create_deviceW(This, rguid, NULL, pdev)) == DI_OK) + return DI_OK; + + if (ret == DIERR_NOINTERFACE) + ret_value = DIERR_NOINTERFACE; + } + + return ret_value; +} + +static HRESULT WINAPI IDirectInputAImpl_Initialize(LPDIRECTINPUT7A iface, HINSTANCE hinst, DWORD x) { + return DIERR_ALREADYINITIALIZED; +} + +static HRESULT WINAPI IDirectInputAImpl_GetDeviceStatus(LPDIRECTINPUT7A iface, + REFGUID rguid) { + IDirectInputImpl *This = (IDirectInputImpl *)iface; + + FIXME("(%p)->(%s): stub\n",This,debugstr_guid(rguid)); + + return DI_OK; +} + +static HRESULT WINAPI IDirectInputAImpl_RunControlPanel(LPDIRECTINPUT7A iface, + HWND hwndOwner, + DWORD dwFlags) { + IDirectInputImpl *This = (IDirectInputImpl *)iface; + FIXME("(%p)->(%08lx,%08lx): stub\n",This, (DWORD) hwndOwner, dwFlags); + + return DI_OK; +} + +static HRESULT WINAPI IDirectInput2AImpl_FindDevice(LPDIRECTINPUT7A iface, REFGUID rguid, + LPCSTR pszName, LPGUID pguidInstance) { + IDirectInputImpl *This = (IDirectInputImpl *)iface; + FIXME("(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), pszName, pguidInstance); + + return DI_OK; +} + +static HRESULT WINAPI IDirectInput2WImpl_FindDevice(LPDIRECTINPUT7W iface, REFGUID rguid, + LPCWSTR pszName, LPGUID pguidInstance) { + IDirectInputImpl *This = (IDirectInputImpl *)iface; + FIXME("(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), debugstr_w(pszName), pguidInstance); + + return DI_OK; +} + +static HRESULT WINAPI IDirectInput7AImpl_CreateDeviceEx(LPDIRECTINPUT7A iface, REFGUID rguid, + REFIID riid, LPVOID* pvOut, LPUNKNOWN lpUnknownOuter) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; + HRESULT ret_value = DIERR_DEVICENOTREG; + int i; + + TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter); + + if (nrof_dinput_devices==0){ + scan_mouse(); + scan_keyboard(); + } + + /* Loop on all the devices to see if anyone matches the given GUID */ + for (i = 0; i < nrof_dinput_devices; i++) { + HRESULT ret; + if ((ret = dinput_devices[i]->create_deviceA(This, rguid, riid, (LPDIRECTINPUTDEVICEA*) pvOut)) == DI_OK) + return DI_OK; + + if (ret == DIERR_NOINTERFACE) + ret_value = DIERR_NOINTERFACE; + } + + return ret_value; +} + +static HRESULT WINAPI IDirectInput7WImpl_CreateDeviceEx(LPDIRECTINPUT7W iface, REFGUID rguid, + REFIID riid, LPVOID* pvOut, LPUNKNOWN lpUnknownOuter) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; + HRESULT ret_value = DIERR_DEVICENOTREG; + int i; + + TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter); + + if (nrof_dinput_devices==0){ + scan_mouse(); + scan_keyboard(); + } + + + + /* Loop on all the devices to see if anyone matches the given GUID */ + for (i = 0; i < nrof_dinput_devices; i++) { + HRESULT ret; + if ((ret = dinput_devices[i]->create_deviceW(This, rguid, riid, (LPDIRECTINPUTDEVICEW*) pvOut)) == DI_OK) + return DI_OK; + + if (ret == DIERR_NOINTERFACE) + ret_value = DIERR_NOINTERFACE; + } + + return ret_value; +} + +static HRESULT WINAPI IDirectInput8AImpl_QueryInterface(LPDIRECTINPUT8A iface, REFIID riid, LPVOID *ppobj) { + IDirectInputImpl *This = (IDirectInputImpl *)iface; + + TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(&IID_IUnknown,riid) || + IsEqualGUID(&IID_IDirectInput8A,riid)) { + IDirectInputAImpl_AddRef((LPDIRECTINPUT7A) iface); + *ppobj = This; + return 0; + } + TRACE("Unsupported interface !\n"); + return E_NOINTERFACE; +} + +static HRESULT WINAPI IDirectInput8WImpl_QueryInterface(LPDIRECTINPUT8W iface, REFIID riid, LPVOID *ppobj) { + IDirectInputImpl *This = (IDirectInputImpl *)iface; + + TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); + if (IsEqualGUID(&IID_IUnknown,riid) || + IsEqualGUID(&IID_IDirectInput8W,riid)) { + IDirectInputAImpl_AddRef((LPDIRECTINPUT7A) iface); + *ppobj = This; + return 0; + } + TRACE("Unsupported interface !\n"); + return E_NOINTERFACE; +} + +static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics( + LPDIRECTINPUT8A iface, LPCSTR ptszUserName, LPDIACTIONFORMATA lpdiActionFormat, + LPDIENUMDEVICESBYSEMANTICSCBA lpCallback, + LPVOID pvRef, DWORD dwFlags +) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; + + FIXME("(this=%p,%s,%p,%p,%p,%04lx): stub\n", This, ptszUserName, lpdiActionFormat, + lpCallback, pvRef, dwFlags); + return 0; +} + +static HRESULT WINAPI IDirectInput8WImpl_EnumDevicesBySemantics( + LPDIRECTINPUT8W iface, LPCWSTR ptszUserName, LPDIACTIONFORMATW lpdiActionFormat, + LPDIENUMDEVICESBYSEMANTICSCBW lpCallback, + LPVOID pvRef, DWORD dwFlags +) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; + + FIXME("(this=%p,%s,%p,%p,%p,%04lx): stub\n", This, debugstr_w(ptszUserName), lpdiActionFormat, + lpCallback, pvRef, dwFlags); + return 0; +} + +static HRESULT WINAPI IDirectInput8AImpl_ConfigureDevices( + LPDIRECTINPUT8A iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback, + LPDICONFIGUREDEVICESPARAMSA lpdiCDParams, DWORD dwFlags, LPVOID pvRefData +) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; + + FIXME("(this=%p,%p,%p,%04lx,%p): stub\n", This, lpdiCallback, lpdiCDParams, + dwFlags, pvRefData); + return 0; +} + +static HRESULT WINAPI IDirectInput8WImpl_ConfigureDevices( + LPDIRECTINPUT8W iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback, + LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData +) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; + + FIXME("(this=%p,%p,%p,%04lx,%p): stub\n", This, lpdiCallback, lpdiCDParams, + dwFlags, pvRefData); + return 0; +} + +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(ddi7avt.fun)) +#else +# define XCAST(fun) (void*) +#endif + +static IDirectInput7AVtbl ddi7avt = { + XCAST(QueryInterface)IDirectInputAImpl_QueryInterface, + XCAST(AddRef)IDirectInputAImpl_AddRef, + XCAST(Release)IDirectInputAImpl_Release, + XCAST(CreateDevice)IDirectInputAImpl_CreateDevice, + XCAST(EnumDevices)IDirectInputAImpl_EnumDevices, + XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus, + XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel, + XCAST(Initialize)IDirectInputAImpl_Initialize, + XCAST(FindDevice)IDirectInput2AImpl_FindDevice, + XCAST(CreateDeviceEx)IDirectInput7AImpl_CreateDeviceEx +}; + +#undef XCAST +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(ddi7wvt.fun)) +#else +# define XCAST(fun) (void*) +#endif + +static IDirectInput7WVtbl ddi7wvt = { + XCAST(QueryInterface)IDirectInputWImpl_QueryInterface, + XCAST(AddRef)IDirectInputAImpl_AddRef, + XCAST(Release)IDirectInputAImpl_Release, + XCAST(CreateDevice)IDirectInputWImpl_CreateDevice, + XCAST(EnumDevices)IDirectInputWImpl_EnumDevices, + XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus, + XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel, + XCAST(Initialize)IDirectInputAImpl_Initialize, + XCAST(FindDevice)IDirectInput2WImpl_FindDevice, + XCAST(CreateDeviceEx)IDirectInput7WImpl_CreateDeviceEx +}; +#undef XCAST + +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(ddi8avt.fun)) +#else +# define XCAST(fun) (void*) +#endif + +static IDirectInput8AVtbl ddi8avt = { + XCAST(QueryInterface)IDirectInput8AImpl_QueryInterface, + XCAST(AddRef)IDirectInputAImpl_AddRef, + XCAST(Release)IDirectInputAImpl_Release, + XCAST(CreateDevice)IDirectInputAImpl_CreateDevice, + XCAST(EnumDevices)IDirectInputAImpl_EnumDevices, + XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus, + XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel, + XCAST(Initialize)IDirectInputAImpl_Initialize, + XCAST(FindDevice)IDirectInput2AImpl_FindDevice, + XCAST(EnumDevicesBySemantics)IDirectInput8AImpl_EnumDevicesBySemantics, + XCAST(ConfigureDevices)IDirectInput8AImpl_ConfigureDevices +}; +#undef XCAST + +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(ddi8wvt.fun)) +#else +# define XCAST(fun) (void*) +#endif +static IDirectInput8WVtbl ddi8wvt = { + XCAST(QueryInterface)IDirectInput8WImpl_QueryInterface, + XCAST(AddRef)IDirectInputAImpl_AddRef, + XCAST(Release)IDirectInputAImpl_Release, + XCAST(CreateDevice)IDirectInputWImpl_CreateDevice, + XCAST(EnumDevices)IDirectInputWImpl_EnumDevices, + XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus, + XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel, + XCAST(Initialize)IDirectInputAImpl_Initialize, + XCAST(FindDevice)IDirectInput2WImpl_FindDevice, + XCAST(EnumDevicesBySemantics)IDirectInput8WImpl_EnumDevicesBySemantics, + XCAST(ConfigureDevices)IDirectInput8WImpl_ConfigureDevices +}; +#undef XCAST + +/******************************************************************************* + * DirectInput ClassFactory + */ +typedef struct +{ + /* IUnknown fields */ + IClassFactoryVtbl *lpVtbl; + DWORD ref; +} IClassFactoryImpl; + +static HRESULT WINAPI DICF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + + FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj); + return E_NOINTERFACE; +} + +static ULONG WINAPI DICF_AddRef(LPCLASSFACTORY iface) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + return InterlockedIncrement(&(This->ref)); +} + +static ULONG WINAPI DICF_Release(LPCLASSFACTORY iface) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + /* static class, won't be freed */ + return InterlockedDecrement(&(This->ref)); +} + +static HRESULT WINAPI DICF_CreateInstance( + LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj +) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + + TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj); + if ( IsEqualGUID( &IID_IDirectInputA, riid ) || + IsEqualGUID( &IID_IDirectInputW, riid ) || + IsEqualGUID( &IID_IDirectInput2A, riid ) || + IsEqualGUID( &IID_IDirectInput2W, riid ) || + IsEqualGUID( &IID_IDirectInput7A, riid ) || + IsEqualGUID( &IID_IDirectInput7W, riid ) || + IsEqualGUID( &IID_IDirectInput8A, riid ) || + IsEqualGUID( &IID_IDirectInput8W, riid ) ) { + /* FIXME: reuse already created dinput if present? */ + return DirectInputCreateEx(0,0,riid,ppobj,pOuter); + } + + FIXME("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); + return E_NOINTERFACE; +} + +static HRESULT WINAPI DICF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + FIXME("(%p)->(%d),stub!\n",This,dolock); + return S_OK; +} + +static IClassFactoryVtbl DICF_Vtbl = { + DICF_QueryInterface, + DICF_AddRef, + DICF_Release, + DICF_CreateInstance, + DICF_LockServer +}; +static IClassFactoryImpl DINPUT_CF = {&DICF_Vtbl, 1 }; + +/*********************************************************************** + * DllCanUnloadNow (DINPUT.@) + */ +HRESULT WINAPI DINPUT_DllCanUnloadNow(void) +{ + FIXME("(void): stub\n"); + + return S_FALSE; +} + +/*********************************************************************** + * DllGetClassObject (DINPUT.@) + */ +HRESULT WINAPI DINPUT_DllGetClassObject(REFCLSID rclsid, REFIID riid, + LPVOID *ppv) +{ + TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); + if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) { + *ppv = (LPVOID)&DINPUT_CF; + IClassFactory_AddRef((IClassFactory*)*ppv); + return S_OK; + } + + FIXME("(%s,%s,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); + return CLASS_E_CLASSNOTAVAILABLE; +} diff --git a/reactos/lib/dinput/dinput_private.h b/reactos/lib/dinput/dinput_private.h index ce7b54a9577..e1e8cd8e92d 100644 --- a/reactos/lib/dinput/dinput_private.h +++ b/reactos/lib/dinput/dinput_private.h @@ -1,58 +1,58 @@ -/* - * Copyright 2000 Lionel Ulmer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_DLLS_DINPUT_DINPUT_PRIVATE_H -#define __WINE_DLLS_DINPUT_DINPUT_PRIVATE_H - -#include - -#include "windef.h" -#include "winbase.h" -#include "dinput.h" - -/* Implementation specification */ -typedef struct IDirectInputImpl IDirectInputImpl; -struct IDirectInputImpl -{ - LPVOID lpVtbl; - DWORD ref; - - /* Used to have an unique sequence number for all the events */ - DWORD evsequence; - - int version; -}; - -/* Function called by all devices that Wine supports */ -typedef struct dinput_device { - INT pref; - const char *name; - BOOL (*enum_deviceA)(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, int version, int id); - BOOL (*enum_deviceW)(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, int version, int id); - HRESULT (*create_deviceA)(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev); - HRESULT (*create_deviceW)(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev); -} dinput_device; - -extern void dinput_register_device(dinput_device *device); - -extern HINSTANCE DINPUT_instance; - -void scan_keyboard(); -void scan_mouse(); - -#endif /* __WINE_DLLS_DINPUT_DINPUT_PRIVATE_H */ +/* + * Copyright 2000 Lionel Ulmer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_DLLS_DINPUT_DINPUT_PRIVATE_H +#define __WINE_DLLS_DINPUT_DINPUT_PRIVATE_H + +#include + +#include "windef.h" +#include "winbase.h" +#include "dinput.h" + +/* Implementation specification */ +typedef struct IDirectInputImpl IDirectInputImpl; +struct IDirectInputImpl +{ + LPVOID lpVtbl; + DWORD ref; + + /* Used to have an unique sequence number for all the events */ + DWORD evsequence; + + int version; +}; + +/* Function called by all devices that Wine supports */ +typedef struct dinput_device { + INT pref; + const char *name; + BOOL (*enum_deviceA)(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, int version, int id); + BOOL (*enum_deviceW)(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, int version, int id); + HRESULT (*create_deviceA)(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev); + HRESULT (*create_deviceW)(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev); +} dinput_device; + +extern void dinput_register_device(dinput_device *device); + +extern HINSTANCE DINPUT_instance; + +void scan_keyboard(); +void scan_mouse(); + +#endif /* __WINE_DLLS_DINPUT_DINPUT_PRIVATE_H */ diff --git a/reactos/lib/dinput/joystick_linux.c b/reactos/lib/dinput/joystick_linux.c index 138ded7caf8..ba26a950a51 100644 --- a/reactos/lib/dinput/joystick_linux.c +++ b/reactos/lib/dinput/joystick_linux.c @@ -1,1700 +1,1700 @@ -/* DirectInput Joystick device - * - * Copyright 1998 Marcus Meissner - * Copyright 1998,1999 Lionel Ulmer - * Copyright 2000-2001 TransGaming Technologies Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * To Do: - * dead zone - * force feedback - */ - -#include "config.h" -#include "wine/port.h" - -#ifdef HAVE_LINUX_22_JOYSTICK_API - -#include -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif -#ifdef HAVE_SYS_TIME_H -# include -#endif -#include -#ifdef HAVE_SYS_IOCTL_H -# include -#endif -#include -#ifdef HAVE_SYS_ERRNO_H -# include -#endif -#ifdef HAVE_LINUX_IOCTL_H -# include -#endif -#ifdef HAVE_LINUX_JOYSTICK_H -# include -#endif -#define JOYDEV "/dev/js" - -#include "wine/debug.h" -#include "wine/unicode.h" -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "winreg.h" -#include "dinput.h" - -#include "dinput_private.h" -#include "device_private.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dinput); - -typedef struct { - LONG lMin; - LONG lMax; - LONG lDeadZone; - LONG lSaturation; -} ObjProps; - -typedef struct { - LONG lX; - LONG lY; -} POV; - -typedef struct JoystickImpl JoystickImpl; -static IDirectInputDevice8AVtbl JoystickAvt; -static IDirectInputDevice8WVtbl JoystickWvt; -struct JoystickImpl -{ - LPVOID lpVtbl; - DWORD ref; - GUID guid; - char dev[32]; - - /* The 'parent' DInput */ - IDirectInputImpl *dinput; - - /* joystick private */ - int joyfd; - DIJOYSTATE2 js; /* wine data */ - LPDIDATAFORMAT user_df; /* user defined format */ - DataFormat *transform; /* wine to user format converter */ - int *offsets; /* object offsets */ - ObjProps *props; - HANDLE hEvent; - LPDIDEVICEOBJECTDATA data_queue; - int queue_head, queue_tail, queue_len; - BOOL acquired; - char *name; - DIDEVCAPS devcaps; - LONG deadzone; - int *axis_map; - int axes; - int buttons; - POV povs[4]; - CRITICAL_SECTION crit; - BOOL overflow; -}; - -static GUID DInput_Wine_Joystick_GUID = { /* 9e573ed9-7734-11d2-8d4a-23903fb6bdf7 */ - 0x9e573ed9, - 0x7734, - 0x11d2, - {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7} -}; - -static void _dump_DIDEVCAPS(LPDIDEVCAPS lpDIDevCaps) -{ - TRACE("dwSize: %ld\n", lpDIDevCaps->dwSize); - TRACE("dwFlags: %08lx\n",lpDIDevCaps->dwFlags); - TRACE("dwDevType: %08lx %s\n", lpDIDevCaps->dwDevType, - lpDIDevCaps->dwDevType == DIDEVTYPE_DEVICE ? "DIDEVTYPE_DEVICE" : - lpDIDevCaps->dwDevType == DIDEVTYPE_DEVICE ? "DIDEVTYPE_DEVICE" : - lpDIDevCaps->dwDevType == DIDEVTYPE_MOUSE ? "DIDEVTYPE_MOUSE" : - lpDIDevCaps->dwDevType == DIDEVTYPE_KEYBOARD ? "DIDEVTYPE_KEYBOARD" : - lpDIDevCaps->dwDevType == DIDEVTYPE_JOYSTICK ? "DIDEVTYPE_JOYSTICK" : - lpDIDevCaps->dwDevType == DIDEVTYPE_HID ? "DIDEVTYPE_HID" : "UNKNOWN"); - TRACE("dwAxes: %ld\n",lpDIDevCaps->dwAxes); - TRACE("dwButtons: %ld\n",lpDIDevCaps->dwButtons); - TRACE("dwPOVs: %ld\n",lpDIDevCaps->dwPOVs); - if (lpDIDevCaps->dwSize > sizeof(DIDEVCAPS_DX3)) { - TRACE("dwFFSamplePeriod: %ld\n",lpDIDevCaps->dwFFSamplePeriod); - TRACE("dwFFMinTimeResolution: %ld\n",lpDIDevCaps->dwFFMinTimeResolution); - TRACE("dwFirmwareRevision: %ld\n",lpDIDevCaps->dwFirmwareRevision); - TRACE("dwHardwareRevision: %ld\n",lpDIDevCaps->dwHardwareRevision); - TRACE("dwFFDriverVersion: %ld\n",lpDIDevCaps->dwFFDriverVersion); - } -} - -static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, int version, int id) -{ - int fd = -1; - char dev[32]; - - if (dwFlags & DIEDFL_FORCEFEEDBACK) { - WARN("force feedback not supported\n"); - return FALSE; - } - - if ((dwDevType == 0) || - ((dwDevType == DIDEVTYPE_JOYSTICK) && (version < 8)) || - (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 8))) { - /* check whether we have a joystick */ - sprintf(dev, "%s%d", JOYDEV, id); - if ((fd = open(dev,O_RDONLY)) < 0) { - WARN("open(%s,O_RDONLY) failed: %s\n", dev, strerror(errno)); - return FALSE; - } - - /* Return joystick */ - lpddi->guidInstance = DInput_Wine_Joystick_GUID; - lpddi->guidInstance.Data3 = id; - lpddi->guidProduct = DInput_Wine_Joystick_GUID; - /* we only support traditional joysticks for now */ - if (version >= 8) - lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); - else - lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); - sprintf(lpddi->tszInstanceName, "Joystick %d", id); -#if defined(JSIOCGNAME) - if (ioctl(fd,JSIOCGNAME(sizeof(lpddi->tszProductName)),lpddi->tszProductName) < 0) { - WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", dev, strerror(errno)); - strcpy(lpddi->tszProductName, "Wine Joystick"); - } -#else - strcpy(lpddi->tszProductName, "Wine Joystick"); -#endif - - lpddi->guidFFDriver = GUID_NULL; - close(fd); - TRACE("Enumerating the linux Joystick device: %s (%s)\n", dev, lpddi->tszProductName); - return TRUE; - } - - return FALSE; -} - -static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, int version, int id) -{ - int fd = -1; - char name[MAX_PATH]; - char dev[32]; - char friendly[32]; - - if (dwFlags & DIEDFL_FORCEFEEDBACK) { - WARN("force feedback not supported\n"); - return FALSE; - } - - if ((dwDevType == 0) || - ((dwDevType == DIDEVTYPE_JOYSTICK) && (version < 8)) || - (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 8))) { - /* check whether we have a joystick */ - sprintf(dev, "%s%d", JOYDEV, id); - if ((fd = open(dev,O_RDONLY)) < 0) { - WARN("open(%s,O_RDONLY) failed: %s\n", dev, strerror(errno)); - return FALSE; - } - - /* Return joystick */ - lpddi->guidInstance = DInput_Wine_Joystick_GUID; - lpddi->guidInstance.Data3 = id; - lpddi->guidProduct = DInput_Wine_Joystick_GUID; - /* we only support traditional joysticks for now */ - if (version >= 8) - lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); - else - lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); - sprintf(friendly, "Joystick %d", id); - MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH); -#if defined(JSIOCGNAME) - if (ioctl(fd,JSIOCGNAME(sizeof(name)),name) < 0) { - WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", dev, strerror(errno)); - strcpy(name, "Wine Joystick"); - } -#else - strcpy(name, "Wine Joystick"); -#endif - MultiByteToWideChar(CP_ACP, 0, name, -1, lpddi->tszProductName, MAX_PATH); - lpddi->guidFFDriver = GUID_NULL; - close(fd); - TRACE("Enumerating the linux Joystick device: %s (%s)\n",dev,name); - return TRUE; - } - - return FALSE; -} - -/* - * Get a config key from either the app-specific or the default config - */ - -inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name, - char *buffer, DWORD size ) -{ - if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, buffer, &size )) - return 0; - - if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, buffer, &size )) - return 0; - - return ERROR_FILE_NOT_FOUND; -} - -/* - * Setup the dinput options. - */ - -static HRESULT setup_dinput_options(JoystickImpl * device) -{ - char buffer[MAX_PATH+1]; - HKEY hkey, appkey = 0; - DWORD len; - - buffer[MAX_PATH]='\0'; - - if (RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\dinput", &hkey)) hkey = 0; - - len = GetModuleFileNameA( 0, buffer, MAX_PATH ); - if (len && len < MAX_PATH) { - HKEY tmpkey; - - if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\AppDefaults", &tmpkey )) { - char appname[MAX_PATH+16]; - char *p = strrchr( buffer, '\\' ); - if (p!=NULL) { - strcpy(appname,p+1); - strcat(appname,"\\dinput"); - TRACE("appname = [%s] \n",appname); - if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0; - } - RegCloseKey( tmpkey ); - } - } - - /* get options */ - - if (!get_config_key( hkey, appkey, "DefaultDeadZone", buffer, MAX_PATH )) { - device->deadzone = atoi(buffer); - TRACE("setting default deadzone to: \"%s\" %ld\n", buffer, device->deadzone); - } - - if (!get_config_key( hkey, appkey, device->name, buffer, MAX_PATH )) { - int tokens = 0; - int axis = 0; - int pov = 0; - const char *delim = ","; - char * ptr; - TRACE("\"%s\" = \"%s\"\n", device->name, buffer); - - device->axis_map = HeapAlloc(GetProcessHeap(), 0, device->axes * sizeof(int)); - if (device->axis_map == 0) - return DIERR_OUTOFMEMORY; - - if ((ptr = strtok(buffer, delim)) != NULL) { - do { - if (strcmp(ptr, "X") == 0) { - device->axis_map[tokens] = 0; - axis++; - } else if (strcmp(ptr, "Y") == 0) { - device->axis_map[tokens] = 1; - axis++; - } else if (strcmp(ptr, "Z") == 0) { - device->axis_map[tokens] = 2; - axis++; - } else if (strcmp(ptr, "Rx") == 0) { - device->axis_map[tokens] = 3; - axis++; - } else if (strcmp(ptr, "Ry") == 0) { - device->axis_map[tokens] = 4; - axis++; - } else if (strcmp(ptr, "Rz") == 0) { - device->axis_map[tokens] = 5; - axis++; - } else if (strcmp(ptr, "Slider1") == 0) { - device->axis_map[tokens] = 6; - axis++; - } else if (strcmp(ptr, "Slider2") == 0) { - device->axis_map[tokens] = 7; - axis++; - } else if (strcmp(ptr, "POV1") == 0) { - device->axis_map[tokens++] = 8; - device->axis_map[tokens] = 8; - pov++; - } else if (strcmp(ptr, "POV2") == 0) { - device->axis_map[tokens++] = 9; - device->axis_map[tokens] = 9; - pov++; - } else if (strcmp(ptr, "POV3") == 0) { - device->axis_map[tokens++] = 10; - device->axis_map[tokens] = 10; - pov++; - } else if (strcmp(ptr, "POV4") == 0) { - device->axis_map[tokens++] = 11; - device->axis_map[tokens] = 11; - pov++; - } else { - ERR("invalid joystick axis type: %s\n", ptr); - device->axis_map[tokens] = tokens; - axis++; - } - - tokens++; - } while ((ptr = strtok(NULL, delim)) != NULL); - - if (tokens != device->devcaps.dwAxes) { - ERR("not all joystick axes mapped: %d axes(%d,%d), %d arguments\n", device->axes, axis, pov,tokens); - while (tokens < device->axes) { - device->axis_map[tokens] = tokens; - tokens++; - } - } - } - - device->devcaps.dwAxes = axis; - device->devcaps.dwPOVs = pov; - } - - if (appkey) - RegCloseKey( appkey ); - - if (hkey) - RegCloseKey( hkey ); - - return DI_OK; -} - -void calculate_ids(JoystickImpl* device) -{ - int i; - int axis = 0; - int button = 0; - int pov = 0; - int axis_base; - int pov_base; - int button_base; - - /* Make two passes over the format. The first counts the number - * for each type and the second sets the id */ - for (i = 0; i < device->user_df->dwNumObjs; i++) { - if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_AXIS) - axis++; - else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_POV) - pov++; - else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_BUTTON) - button++; - } - - axis_base = 0; - pov_base = axis; - button_base = axis + pov; - - axis = 0; - button = 0; - pov = 0; - - for (i = 0; i < device->user_df->dwNumObjs; i++) { - DWORD type = 0; - if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_AXIS) { - axis++; - type = DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) | - DIDFT_MAKEINSTANCE(axis + axis_base); - TRACE("axis type = 0x%08lx\n", type); - } else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_POV) { - pov++; - type = DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) | - DIDFT_MAKEINSTANCE(pov + pov_base); - TRACE("POV type = 0x%08lx\n", type); - } else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_BUTTON) { - button++; - type = DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) | - DIDFT_MAKEINSTANCE(button + button_base); - TRACE("button type = 0x%08lx\n", type); - } - device->user_df->rgodf[i].dwType = type; - } -} - -static HRESULT alloc_device(REFGUID rguid, LPVOID jvt, IDirectInputImpl *dinput, LPDIRECTINPUTDEVICEA* pdev) -{ - DWORD i; - JoystickImpl* newDevice; - char name[MAX_PATH]; - HRESULT hr; - - newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl)); - if (newDevice == 0) { - WARN("out of memory\n"); - *pdev = 0; - return DIERR_OUTOFMEMORY; - } - - sprintf(newDevice->dev, "%s%d", JOYDEV, rguid->Data3); - - if ((newDevice->joyfd = open(newDevice->dev,O_RDONLY)) < 0) { - WARN("open(%s,O_RDONLY) failed: %s\n", newDevice->dev, strerror(errno)); - HeapFree(GetProcessHeap(), 0, newDevice); - return DIERR_DEVICENOTREG; - } - - /* get the device name */ -#if defined(JSIOCGNAME) - if (ioctl(newDevice->joyfd,JSIOCGNAME(MAX_PATH),name) < 0) { - WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", newDevice->dev, strerror(errno)); - strcpy(name, "Wine Joystick"); - } -#else - strcpy(name, "Wine Joystick"); -#endif - - /* copy the device name */ - newDevice->name = HeapAlloc(GetProcessHeap(),0,strlen(name) + 1); - strcpy(newDevice->name, name); - -#ifdef JSIOCGAXES - if (ioctl(newDevice->joyfd,JSIOCGAXES,&newDevice->axes) < 0) { - WARN("ioctl(%s,JSIOCGAXES) failed: %s, defauting to 2\n", newDevice->dev, strerror(errno)); - newDevice->axes = 2; - } -#endif -#ifdef JSIOCGBUTTONS - if (ioctl(newDevice->joyfd,JSIOCGBUTTONS,&newDevice->buttons) < 0) { - WARN("ioctl(%s,JSIOCGBUTTONS) failed: %s, defauting to 2\n", newDevice->dev, strerror(errno)); - newDevice->buttons = 2; - } -#endif - - newDevice->lpVtbl = jvt; - newDevice->ref = 1; - newDevice->dinput = dinput; - newDevice->acquired = FALSE; - newDevice->overflow = FALSE; - CopyMemory(&(newDevice->guid),rguid,sizeof(*rguid)); - - /* setup_dinput_options may change these */ - newDevice->deadzone = 5000; - newDevice->devcaps.dwButtons = newDevice->buttons; - newDevice->devcaps.dwAxes = newDevice->axes; - newDevice->devcaps.dwPOVs = 0; - - /* do any user specified configuration */ - hr = setup_dinput_options(newDevice); - if (hr != DI_OK) - goto FAILED1; - - if (newDevice->axis_map == 0) { - newDevice->axis_map = HeapAlloc(GetProcessHeap(), 0, newDevice->axes * sizeof(int)); - if (newDevice->axis_map == 0) - goto FAILED; - - for (i = 0; i < newDevice->axes; i++) - newDevice->axis_map[i] = i; - } - - /* wine uses DIJOYSTATE2 as it's internal format so copy - * the already defined format c_dfDIJoystick2 */ - newDevice->user_df = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwSize); - if (newDevice->user_df == 0) - goto FAILED; - - CopyMemory(newDevice->user_df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize); - - /* copy default objects */ - newDevice->user_df->rgodf = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwNumObjs*c_dfDIJoystick2.dwObjSize); - if (newDevice->user_df->rgodf == 0) - goto FAILED; - - CopyMemory(newDevice->user_df->rgodf,c_dfDIJoystick2.rgodf,c_dfDIJoystick2.dwNumObjs*c_dfDIJoystick2.dwObjSize); - - /* create default properties */ - newDevice->props = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwNumObjs*sizeof(ObjProps)); - if (newDevice->props == 0) - goto FAILED; - - /* initialize default properties */ - for (i = 0; i < c_dfDIJoystick2.dwNumObjs; i++) { - newDevice->props[i].lMin = 0; - newDevice->props[i].lMax = 0xffff; - newDevice->props[i].lDeadZone = newDevice->deadzone; /* % * 1000 */ - newDevice->props[i].lSaturation = 0; - } - - /* create an offsets array */ - newDevice->offsets = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,c_dfDIJoystick2.dwNumObjs*sizeof(int)); - if (newDevice->offsets == 0) - goto FAILED; - - /* create the default transform filter */ - newDevice->transform = create_DataFormat(&c_dfDIJoystick2, newDevice->user_df, newDevice->offsets); - - calculate_ids(newDevice); - - IDirectInputDevice_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->dinput); - InitializeCriticalSection(&(newDevice->crit)); - newDevice->crit.DebugInfo->Spare[1] = (DWORD)"DINPUT_Mouse"; - - newDevice->devcaps.dwSize = sizeof(newDevice->devcaps); - newDevice->devcaps.dwFlags = DIDC_ATTACHED; - if (newDevice->dinput->version >= 8) - newDevice->devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); - else - newDevice->devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); - newDevice->devcaps.dwFFSamplePeriod = 0; - newDevice->devcaps.dwFFMinTimeResolution = 0; - newDevice->devcaps.dwFirmwareRevision = 0; - newDevice->devcaps.dwHardwareRevision = 0; - newDevice->devcaps.dwFFDriverVersion = 0; - - if (TRACE_ON(dinput)) { - _dump_DIDATAFORMAT(newDevice->user_df); - for (i = 0; i < (newDevice->axes); i++) - TRACE("axis_map[%ld] = %d\n", i, newDevice->axis_map[i]); - _dump_DIDEVCAPS(&newDevice->devcaps); - } - - *pdev = (LPDIRECTINPUTDEVICEA)newDevice; - - return DI_OK; - -FAILED: - hr = DIERR_OUTOFMEMORY; -FAILED1: - HeapFree(GetProcessHeap(),0,newDevice->axis_map); - HeapFree(GetProcessHeap(),0,newDevice->name); - HeapFree(GetProcessHeap(),0,newDevice->props); - HeapFree(GetProcessHeap(),0,newDevice->user_df->rgodf); - HeapFree(GetProcessHeap(),0,newDevice->user_df); - HeapFree(GetProcessHeap(),0,newDevice); - *pdev = 0; - - return hr; -} - -static BOOL IsJoystickGUID(REFGUID guid) -{ - GUID wine_joystick = DInput_Wine_Joystick_GUID; - GUID dev_guid = *guid; - - wine_joystick.Data3 = 0; - dev_guid.Data3 = 0; - - return IsEqualGUID(&wine_joystick, &dev_guid); -} - -static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev) -{ - if ((IsEqualGUID(&GUID_Joystick,rguid)) || - (IsJoystickGUID(rguid))) { - if ((riid == NULL) || - IsEqualGUID(&IID_IDirectInputDeviceA,riid) || - IsEqualGUID(&IID_IDirectInputDevice2A,riid) || - IsEqualGUID(&IID_IDirectInputDevice7A,riid) || - IsEqualGUID(&IID_IDirectInputDevice8A,riid)) { - return alloc_device(rguid, &JoystickAvt, dinput, pdev); - } else { - WARN("no interface\n"); - *pdev = 0; - return DIERR_NOINTERFACE; - } - } - - WARN("invalid device GUID\n"); - *pdev = 0; - return DIERR_DEVICENOTREG; -} - -static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev) -{ - if ((IsEqualGUID(&GUID_Joystick,rguid)) || - (IsJoystickGUID(rguid))) { - if ((riid == NULL) || - IsEqualGUID(&IID_IDirectInputDeviceW,riid) || - IsEqualGUID(&IID_IDirectInputDevice2W,riid) || - IsEqualGUID(&IID_IDirectInputDevice7W,riid) || - IsEqualGUID(&IID_IDirectInputDevice8W,riid)) { - return alloc_device(rguid, &JoystickWvt, dinput, (LPDIRECTINPUTDEVICEA *)pdev); - } else { - WARN("no interface\n"); - *pdev = 0; - return DIERR_NOINTERFACE; - } - } - - WARN("invalid device GUID\n"); - *pdev = 0; - return DIERR_DEVICENOTREG; -} - -static dinput_device joydev = { - 10, - "Wine Linux joystick driver", - joydev_enum_deviceA, - joydev_enum_deviceW, - joydev_create_deviceA, - joydev_create_deviceW -}; - -DECL_GLOBAL_CONSTRUCTOR(joydev_register) { dinput_register_device(&joydev); } - - - -/****************************************************************************** - * Joystick - */ -static ULONG WINAPI JoystickAImpl_Release(LPDIRECTINPUTDEVICE8A iface) -{ - JoystickImpl *This = (JoystickImpl *)iface; - ULONG ref; - - ref = InterlockedDecrement((&This->ref)); - if (ref) - return ref; - - /* Free the device name */ - HeapFree(GetProcessHeap(),0,This->name); - - /* Free the axis map */ - HeapFree(GetProcessHeap(),0,This->axis_map); - - /* Free the data queue */ - HeapFree(GetProcessHeap(),0,This->data_queue); - - /* Free the DataFormat */ - HeapFree(GetProcessHeap(), 0, This->user_df->rgodf); - HeapFree(GetProcessHeap(), 0, This->user_df); - - /* Free the properties */ - HeapFree(GetProcessHeap(), 0, This->props); - - /* Free the offsets array */ - HeapFree(GetProcessHeap(),0,This->offsets); - - /* release the data transform filter */ - release_DataFormat(This->transform); - - This->crit.DebugInfo->Spare[1] = 0; - DeleteCriticalSection(&(This->crit)); - IDirectInputDevice_Release((LPDIRECTINPUTDEVICE8A)This->dinput); - - HeapFree(GetProcessHeap(),0,This); - return 0; -} - -/****************************************************************************** - * SetDataFormat : the application can choose the format of the data - * the device driver sends back with GetDeviceState. - */ -static HRESULT WINAPI JoystickAImpl_SetDataFormat( - LPDIRECTINPUTDEVICE8A iface, - LPCDIDATAFORMAT df) -{ - JoystickImpl *This = (JoystickImpl *)iface; - unsigned int i; - LPDIDATAFORMAT new_df = 0; - LPDIOBJECTDATAFORMAT new_rgodf = 0; - ObjProps * new_props = 0; - - TRACE("(%p,%p)\n",This,df); - - if (This->acquired) { - WARN("acquired\n"); - return DIERR_ACQUIRED; - } - - if (TRACE_ON(dinput)) - _dump_DIDATAFORMAT(df); - - /* Store the new data format */ - new_df = HeapAlloc(GetProcessHeap(),0,df->dwSize); - if (new_df == 0) - goto FAILED; - - new_rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize); - if (new_rgodf == 0) - goto FAILED; - - new_props = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*sizeof(ObjProps)); - if (new_props == 0) - goto FAILED; - - HeapFree(GetProcessHeap(),0,This->user_df); - HeapFree(GetProcessHeap(),0,This->user_df->rgodf); - HeapFree(GetProcessHeap(),0,This->props); - release_DataFormat(This->transform); - - This->user_df = new_df; - CopyMemory(This->user_df, df, df->dwSize); - This->user_df->rgodf = new_rgodf; - CopyMemory(This->user_df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize); - This->props = new_props; - for (i = 0; i < df->dwNumObjs; i++) { - This->props[i].lMin = 0; - This->props[i].lMax = 0xffff; - This->props[i].lDeadZone = 1000; - This->props[i].lSaturation = 0; - } - This->transform = create_DataFormat(&c_dfDIJoystick2, This->user_df, This->offsets); - - calculate_ids(This); - - return DI_OK; - -FAILED: - WARN("out of memory\n"); - HeapFree(GetProcessHeap(),0,new_props); - HeapFree(GetProcessHeap(),0,new_rgodf); - HeapFree(GetProcessHeap(),0,new_df); - return DIERR_OUTOFMEMORY; -} - -/****************************************************************************** - * Acquire : gets exclusive control of the joystick - */ -static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) -{ - JoystickImpl *This = (JoystickImpl *)iface; - - TRACE("(%p)\n",This); - - if (This->acquired) { - WARN("already acquired\n"); - return S_FALSE; - } - - /* open the joystick device */ - if (This->joyfd==-1) { - TRACE("opening joystick device %s\n", This->dev); - - This->joyfd=open(This->dev,O_RDONLY); - if (This->joyfd==-1) { - ERR("open(%s) failed: %s\n", This->dev, strerror(errno)); - return DIERR_NOTFOUND; - } - } - - This->acquired = TRUE; - - return DI_OK; -} - -/****************************************************************************** - * Unacquire : frees the joystick - */ -static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) -{ - JoystickImpl *This = (JoystickImpl *)iface; - - TRACE("(%p)\n",This); - - if (!This->acquired) { - WARN("not acquired\n"); - return DIERR_NOTACQUIRED; - } - - if (This->joyfd!=-1) { - TRACE("closing joystick device\n"); - close(This->joyfd); - This->joyfd = -1; - This->acquired = FALSE; - return DI_OK; - } - - This->acquired = FALSE; - - return DI_NOEFFECT; -} - -LONG map_axis(JoystickImpl * This, short val, short index) -{ - double fval = val; - double fmin = This->props[index].lMin; - double fmax = This->props[index].lMax; - double fret; - - fret = (((fval + 32767.0) * (fmax - fmin)) / (32767.0*2.0)) + fmin; - - if (fret >= 0.0) - fret += 0.5; - else - fret -= 0.5; - - return fret; -} - -/* convert wine format offset to user format object index */ -int offset_to_object(JoystickImpl *This, int offset) -{ - int i; - - for (i = 0; i < This->user_df->dwNumObjs; i++) { - if (This->user_df->rgodf[i].dwOfs == offset) - return i; - } - - return -1; -} - -static LONG calculate_pov(JoystickImpl *This, int index) -{ - if (This->povs[index].lX < 16384) { - if (This->povs[index].lY < 16384) - This->js.rgdwPOV[index] = 31500; - else if (This->povs[index].lY > 49150) - This->js.rgdwPOV[index] = 22500; - else - This->js.rgdwPOV[index] = 27000; - } else if (This->povs[index].lX > 49150) { - if (This->povs[index].lY < 16384) - This->js.rgdwPOV[index] = 4500; - else if (This->povs[index].lY > 49150) - This->js.rgdwPOV[index] = 13500; - else - This->js.rgdwPOV[index] = 9000; - } else { - if (This->povs[index].lY < 16384) - This->js.rgdwPOV[index] = 0; - else if (This->povs[index].lY > 49150) - This->js.rgdwPOV[index] = 18000; - else - This->js.rgdwPOV[index] = -1; - } - - return This->js.rgdwPOV[index]; -} - -static void joy_polldev(JoystickImpl *This) { - struct timeval tv; - fd_set readfds; - struct js_event jse; - TRACE("(%p)\n", This); - - if (This->joyfd==-1) { - WARN("no device\n"); - return; - } - while (1) { - memset(&tv,0,sizeof(tv)); - FD_ZERO(&readfds);FD_SET(This->joyfd,&readfds); - if (1>select(This->joyfd+1,&readfds,NULL,NULL,&tv)) - return; - /* we have one event, so we can read */ - if (sizeof(jse)!=read(This->joyfd,&jse,sizeof(jse))) { - return; - } - TRACE("js_event: type 0x%x, number %d, value %d\n", - jse.type,jse.number,jse.value); - if (jse.type & JS_EVENT_BUTTON) { - int offset = This->offsets[jse.number + 12]; - int value = jse.value?0x80:0x00; - - This->js.rgbButtons[jse.number] = value; - GEN_EVENT(offset,value,jse.time,(This->dinput->evsequence)++); - } else if (jse.type & JS_EVENT_AXIS) { - int number = This->axis_map[jse.number]; /* wine format object index */ - if (number < 12) { - int offset = This->offsets[number]; - int index = offset_to_object(This, offset); - LONG value = map_axis(This, jse.value, index); - - /* FIXME do deadzone and saturation here */ - - TRACE("changing axis %d => %d\n", jse.number, number); - switch (number) { - case 0: - This->js.lX = value; - break; - case 1: - This->js.lY = value; - break; - case 2: - This->js.lZ = value; - break; - case 3: - This->js.lRx = value; - break; - case 4: - This->js.lRy = value; - break; - case 5: - This->js.lRz = value; - break; - case 6: - This->js.rglSlider[0] = value; - break; - case 7: - This->js.rglSlider[1] = value; - break; - case 8: - /* FIXME don't go off array */ - if (This->axis_map[jse.number + 1] == number) - This->povs[0].lX = value; - else if (This->axis_map[jse.number - 1] == number) - This->povs[0].lY = value; - value = calculate_pov(This, 0); - break; - case 9: - if (This->axis_map[jse.number + 1] == number) - This->povs[1].lX = value; - else if (This->axis_map[jse.number - 1] == number) - This->povs[1].lY = value; - value = calculate_pov(This, 1); - break; - case 10: - if (This->axis_map[jse.number + 1] == number) - This->povs[2].lX = value; - else if (This->axis_map[jse.number - 1] == number) - This->povs[2].lY = value; - value = calculate_pov(This, 2); - break; - case 11: - if (This->axis_map[jse.number + 1] == number) - This->povs[3].lX = value; - else if (This->axis_map[jse.number - 1] == number) - This->povs[3].lY = value; - value = calculate_pov(This, 3); - break; - } - - GEN_EVENT(offset,value,jse.time,(This->dinput->evsequence)++); - } else - WARN("axis %d not supported\n", number); - } - } -} - -/****************************************************************************** - * GetDeviceState : returns the "state" of the joystick. - * - */ -static HRESULT WINAPI JoystickAImpl_GetDeviceState( - LPDIRECTINPUTDEVICE8A iface, - DWORD len, - LPVOID ptr) -{ - JoystickImpl *This = (JoystickImpl *)iface; - - TRACE("(%p,0x%08lx,%p)\n",This,len,ptr); - - if (!This->acquired) { - WARN("not acquired\n"); - return DIERR_NOTACQUIRED; - } - - /* update joystick state */ - joy_polldev(This); - - /* convert and copy data to user supplied buffer */ - fill_DataFormat(ptr, &This->js, This->transform); - - return DI_OK; -} - -/****************************************************************************** - * GetDeviceData : gets buffered input data. - */ -static HRESULT WINAPI JoystickAImpl_GetDeviceData( - LPDIRECTINPUTDEVICE8A iface, - DWORD dodsize, - LPDIDEVICEOBJECTDATA dod, - LPDWORD entries, - DWORD flags) -{ - JoystickImpl *This = (JoystickImpl *)iface; - DWORD len; - int nqtail; - HRESULT hr = DI_OK; - - TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags); - - if (!This->acquired) { - WARN("not acquired\n"); - return DIERR_NOTACQUIRED; - } - - EnterCriticalSection(&(This->crit)); - - joy_polldev(This); - - len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0) - + (This->queue_head - This->queue_tail); - if (len > *entries) - len = *entries; - - if (dod == NULL) { - if (len) - TRACE("Application discarding %ld event(s).\n", len); - - *entries = len; - nqtail = This->queue_tail + len; - while (nqtail >= This->queue_len) - nqtail -= This->queue_len; - } else { - if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3)) { - ERR("Wrong structure size !\n"); - LeaveCriticalSection(&(This->crit)); - return DIERR_INVALIDPARAM; - } - - if (len) - TRACE("Application retrieving %ld event(s).\n", len); - - *entries = 0; - nqtail = This->queue_tail; - while (len) { - /* Copy the buffered data into the application queue */ - memcpy((char *)dod + *entries * dodsize, This->data_queue + nqtail, dodsize); - /* Advance position */ - nqtail++; - if (nqtail >= This->queue_len) - nqtail -= This->queue_len; - (*entries)++; - len--; - } - } - - if (This->overflow) { - hr = DI_BUFFEROVERFLOW; - if (!(flags & DIGDD_PEEK)) { - This->overflow = FALSE; - } - } - - if (!(flags & DIGDD_PEEK)) - This->queue_tail = nqtail; - - LeaveCriticalSection(&(This->crit)); - - return hr; -} - -int find_property(JoystickImpl * This, LPCDIPROPHEADER ph) -{ - int i; - if (ph->dwHow == DIPH_BYOFFSET) { - return offset_to_object(This, ph->dwObj); - } else if (ph->dwHow == DIPH_BYID) { - for (i = 0; i < This->user_df->dwNumObjs; i++) { - if ((This->user_df->rgodf[i].dwType & 0x00ffffff) == (ph->dwObj & 0x00ffffff)) { - return i; - } - } - } - - return -1; -} - -/****************************************************************************** - * SetProperty : change input device properties - */ -static HRESULT WINAPI JoystickAImpl_SetProperty( - LPDIRECTINPUTDEVICE8A iface, - REFGUID rguid, - LPCDIPROPHEADER ph) -{ - JoystickImpl *This = (JoystickImpl *)iface; - int i; - - TRACE("(%p,%s,%p)\n",This,debugstr_guid(rguid),ph); - - if (TRACE_ON(dinput)) - _dump_DIPROPHEADER(ph); - - if (!HIWORD(rguid)) { - switch ((DWORD)rguid) { - case (DWORD) DIPROP_BUFFERSIZE: { - LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; - TRACE("buffersize = %ld\n",pd->dwData); - if (This->data_queue) - This->data_queue = HeapReAlloc(GetProcessHeap(),0, This->data_queue, pd->dwData * sizeof(DIDEVICEOBJECTDATA)); - else - This->data_queue = HeapAlloc(GetProcessHeap(),0, pd->dwData * sizeof(DIDEVICEOBJECTDATA)); - This->queue_head = 0; - This->queue_tail = 0; - This->queue_len = pd->dwData; - break; - } - case (DWORD)DIPROP_RANGE: { - LPCDIPROPRANGE pr = (LPCDIPROPRANGE)ph; - if (ph->dwHow == DIPH_DEVICE) { - TRACE("proprange(%ld,%ld) all\n",pr->lMin,pr->lMax); - for (i = 0; i < This->user_df->dwNumObjs; i++) { - This->props[i].lMin = pr->lMin; - This->props[i].lMax = pr->lMax; - } - } else { - int obj = find_property(This, ph); - TRACE("proprange(%ld,%ld) obj=%d\n",pr->lMin,pr->lMax,obj); - if (obj >= 0) { - This->props[obj].lMin = pr->lMin; - This->props[obj].lMax = pr->lMax; - return DI_OK; - } - } - break; - } - case (DWORD)DIPROP_DEADZONE: { - LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; - if (ph->dwHow == DIPH_DEVICE) { - TRACE("deadzone(%ld) all\n",pd->dwData); - for (i = 0; i < This->user_df->dwNumObjs; i++) - This->props[i].lDeadZone = pd->dwData; - } else { - int obj = find_property(This, ph); - TRACE("deadzone(%ld) obj=%d\n",pd->dwData,obj); - if (obj >= 0) { - This->props[obj].lDeadZone = pd->dwData; - return DI_OK; - } - } - break; - } - case (DWORD)DIPROP_SATURATION: { - LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; - if (ph->dwHow == DIPH_DEVICE) { - TRACE("saturation(%ld) all\n",pd->dwData); - for (i = 0; i < This->user_df->dwNumObjs; i++) - This->props[i].lSaturation = pd->dwData; - } else { - int obj = find_property(This, ph); - TRACE("saturation(%ld) obj=%d\n",pd->dwData,obj); - if (obj >= 0) { - This->props[obj].lSaturation = pd->dwData; - return DI_OK; - } - } - break; - } - default: - FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); - break; - } - } - - return DI_OK; -} - -/****************************************************************************** - * SetEventNotification : specifies event to be sent on state change - */ -static HRESULT WINAPI JoystickAImpl_SetEventNotification( - LPDIRECTINPUTDEVICE8A iface, HANDLE hnd -) { - JoystickImpl *This = (JoystickImpl *)iface; - - TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd); - This->hEvent = hnd; - return DI_OK; -} - -static HRESULT WINAPI JoystickAImpl_GetCapabilities( - LPDIRECTINPUTDEVICE8A iface, - LPDIDEVCAPS lpDIDevCaps) -{ - JoystickImpl *This = (JoystickImpl *)iface; - int size; - - TRACE("%p->(%p)\n",iface,lpDIDevCaps); - - if (lpDIDevCaps == NULL) { - WARN("invalid parameter: lpDIDevCaps = NULL\n"); - return DIERR_INVALIDPARAM; - } - - size = lpDIDevCaps->dwSize; - CopyMemory(lpDIDevCaps, &This->devcaps, size); - lpDIDevCaps->dwSize = size; - - if (TRACE_ON(dinput)) - _dump_DIDEVCAPS(lpDIDevCaps); - - return DI_OK; -} - -static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE8A iface) -{ - JoystickImpl *This = (JoystickImpl *)iface; - - TRACE("(%p)\n",This); - - if (!This->acquired) { - WARN("not acquired\n"); - return DIERR_NOTACQUIRED; - } - - joy_polldev(This); - return DI_OK; -} - -/****************************************************************************** - * EnumObjects : enumerate the different buttons and axis... - */ -static HRESULT WINAPI JoystickAImpl_EnumObjects( - LPDIRECTINPUTDEVICE8A iface, - LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, - LPVOID lpvRef, - DWORD dwFlags) -{ - JoystickImpl *This = (JoystickImpl *)iface; - DIDEVICEOBJECTINSTANCEA ddoi; - BYTE i; - int user_offset; - int user_object; - - TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags); - if (TRACE_ON(dinput)) { - TRACE(" - flags = "); - _dump_EnumObjects_flags(dwFlags); - TRACE("\n"); - } - - /* Only the fields till dwFFMaxForce are relevant */ - ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce); - - /* For the joystick, do as is done in the GetCapabilities function */ - if ((dwFlags == DIDFT_ALL) || - (dwFlags & DIDFT_AXIS) || - (dwFlags & DIDFT_POV)) { - int pov[4] = { 0, 0, 0, 0 }; - int axes = 0; - int povs = 0; - - for (i = 0; i < This->axes; i++) { - int wine_obj = This->axis_map[i]; - BOOL skip = FALSE; - - switch (wine_obj) { - case 0: - ddoi.guidType = GUID_XAxis; - break; - case 1: - ddoi.guidType = GUID_YAxis; - break; - case 2: - ddoi.guidType = GUID_ZAxis; - break; - case 3: - ddoi.guidType = GUID_RxAxis; - break; - case 4: - ddoi.guidType = GUID_RyAxis; - break; - case 5: - ddoi.guidType = GUID_RzAxis; - break; - case 6: - ddoi.guidType = GUID_Slider; - break; - case 7: - ddoi.guidType = GUID_Slider; - break; - case 8: - pov[0]++; - ddoi.guidType = GUID_POV; - break; - case 9: - pov[1]++; - ddoi.guidType = GUID_POV; - break; - case 10: - pov[2]++; - ddoi.guidType = GUID_POV; - break; - case 11: - pov[3]++; - ddoi.guidType = GUID_POV; - break; - default: - ddoi.guidType = GUID_Unknown; - } - if (wine_obj < 8) { - user_offset = This->offsets[wine_obj]; /* get user offset from wine index */ - user_object = offset_to_object(This, user_offset); - - ddoi.dwType = This->user_df->rgodf[user_object].dwType & 0x00ffffff; - ddoi.dwOfs = This->user_df->rgodf[user_object].dwOfs; - sprintf(ddoi.tszName, "Axis %d", axes); - axes++; - } else { - if (pov[wine_obj - 8] < 2) { - user_offset = This->offsets[wine_obj]; /* get user offset from wine index */ - user_object = offset_to_object(This, user_offset); - - ddoi.dwType = This->user_df->rgodf[user_object].dwType & 0x00ffffff; - ddoi.dwOfs = This->user_df->rgodf[user_object].dwOfs; - sprintf(ddoi.tszName, "POV %d", povs); - povs++; - } else - skip = TRUE; - } - if (!skip) { - _dump_OBJECTINSTANCEA(&ddoi); - if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) - return DI_OK; - } - } - } - - if ((dwFlags == DIDFT_ALL) || - (dwFlags & DIDFT_BUTTON)) { - - /* The DInput SDK says that GUID_Button is only for mouse buttons but well... */ - ddoi.guidType = GUID_Button; - - for (i = 0; i < This->buttons; i++) { - user_offset = This->offsets[i + 12]; /* get user offset from wine index */ - user_object = offset_to_object(This, user_offset); - ddoi.guidType = GUID_Button; - ddoi.dwType = This->user_df->rgodf[user_object].dwType & 0x00ffffff; - ddoi.dwOfs = This->user_df->rgodf[user_object].dwOfs; - sprintf(ddoi.tszName, "Button %d", i); - _dump_OBJECTINSTANCEA(&ddoi); - if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; - } - } - - return DI_OK; -} - -/****************************************************************************** - * EnumObjects : enumerate the different buttons and axis... - */ -static HRESULT WINAPI JoystickWImpl_EnumObjects( - LPDIRECTINPUTDEVICE8W iface, - LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, - LPVOID lpvRef, - DWORD dwFlags) -{ - JoystickImpl *This = (JoystickImpl *)iface; - - device_enumobjects_AtoWcb_data data; - - data.lpCallBack = lpCallback; - data.lpvRef = lpvRef; - - return JoystickAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags); -} - -/****************************************************************************** - * GetProperty : get input device properties - */ -static HRESULT WINAPI JoystickAImpl_GetProperty( - LPDIRECTINPUTDEVICE8A iface, - REFGUID rguid, - LPDIPROPHEADER pdiph) -{ - JoystickImpl *This = (JoystickImpl *)iface; - - TRACE("(%p,%s,%p)\n", iface, debugstr_guid(rguid), pdiph); - - if (TRACE_ON(dinput)) - _dump_DIPROPHEADER(pdiph); - - if (!HIWORD(rguid)) { - switch ((DWORD)rguid) { - case (DWORD) DIPROP_BUFFERSIZE: { - LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; - TRACE(" return buffersize = %d\n",This->queue_len); - pd->dwData = This->queue_len; - break; - } - case (DWORD) DIPROP_RANGE: { - LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph; - int obj = find_property(This, pdiph); - /* The app is querying the current range of the axis - * return the lMin and lMax values */ - if (obj >= 0) { - pr->lMin = This->props[obj].lMin; - pr->lMax = This->props[obj].lMax; - TRACE("range(%ld, %ld) obj=%d\n", pr->lMin, pr->lMax, obj); - return DI_OK; - } - break; - } - case (DWORD) DIPROP_DEADZONE: { - LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; - int obj = find_property(This, pdiph); - if (obj >= 0) { - pd->dwData = This->props[obj].lDeadZone; - TRACE("deadzone(%ld) obj=%d\n", pd->dwData, obj); - return DI_OK; - } - break; - } - case (DWORD) DIPROP_SATURATION: { - LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; - int obj = find_property(This, pdiph); - if (obj >= 0) { - pd->dwData = This->props[obj].lSaturation; - TRACE("saturation(%ld) obj=%d\n", pd->dwData, obj); - return DI_OK; - } - break; - } - default: - FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); - break; - } - } - - return DI_OK; -} - -/****************************************************************************** - * GetObjectInfo : get object info - */ -HRESULT WINAPI JoystickAImpl_GetObjectInfo( - LPDIRECTINPUTDEVICE8A iface, - LPDIDEVICEOBJECTINSTANCEA pdidoi, - DWORD dwObj, - DWORD dwHow) -{ - JoystickImpl *This = (JoystickImpl *)iface; - DIDEVICEOBJECTINSTANCEA didoiA; - unsigned int i; - - TRACE("(%p,%p,%ld,0x%08lx(%s))\n", - iface, pdidoi, dwObj, dwHow, - dwHow == DIPH_BYOFFSET ? "DIPH_BYOFFSET" : - dwHow == DIPH_BYID ? "DIPH_BYID" : - dwHow == DIPH_BYUSAGE ? "DIPH_BYUSAGE" : - "UNKNOWN"); - - if (pdidoi == NULL) { - WARN("invalid parameter: pdidoi = NULL\n"); - return DIERR_INVALIDPARAM; - } - - if ((pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCEA)) && - (pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCE_DX3A))) { - WARN("invalid parameter: pdidoi->dwSize = %ld != %d or %d\n", - pdidoi->dwSize, sizeof(DIDEVICEOBJECTINSTANCEA), - sizeof(DIDEVICEOBJECTINSTANCE_DX3A)); - return DIERR_INVALIDPARAM; - } - - ZeroMemory(&didoiA, sizeof(didoiA)); - didoiA.dwSize = pdidoi->dwSize; - - switch (dwHow) { - case DIPH_BYOFFSET: { - int axis = 0; - int pov = 0; - int button = 0; - for (i = 0; i < This->user_df->dwNumObjs; i++) { - if (This->user_df->rgodf[i].dwOfs == dwObj) { - if (This->user_df->rgodf[i].pguid) - didoiA.guidType = *This->user_df->rgodf[i].pguid; - else - didoiA.guidType = GUID_NULL; - - didoiA.dwOfs = dwObj; - didoiA.dwType = This->user_df->rgodf[i].dwType; - didoiA.dwFlags = This->user_df->rgodf[i].dwFlags; - - if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_AXIS) - sprintf(didoiA.tszName, "Axis %d", axis); - else if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_POV) - sprintf(didoiA.tszName, "POV %d", pov); - else if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_BUTTON) - sprintf(didoiA.tszName, "Button %d", button); - - CopyMemory(pdidoi, &didoiA, pdidoi->dwSize); - return DI_OK; - } - - if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_AXIS) - axis++; - else if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_POV) - pov++; - else if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_BUTTON) - button++; - } - break; - } - case DIPH_BYID: - FIXME("dwHow = DIPH_BYID not implemented\n"); - break; - case DIPH_BYUSAGE: - FIXME("dwHow = DIPH_BYUSAGE not implemented\n"); - break; - default: - WARN("invalid parameter: dwHow = %08lx\n", dwHow); - return DIERR_INVALIDPARAM; - } - - CopyMemory(pdidoi, &didoiA, pdidoi->dwSize); - - return DI_OK; -} - -/****************************************************************************** - * GetDeviceInfo : get information about a device's identity - */ -HRESULT WINAPI JoystickAImpl_GetDeviceInfo( - LPDIRECTINPUTDEVICE8A iface, - LPDIDEVICEINSTANCEA pdidi) -{ - JoystickImpl *This = (JoystickImpl *)iface; - - TRACE("(%p,%p)\n", iface, pdidi); - - if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3A)) && - (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA))) { - WARN("invalid parameter: pdidi->dwSize = %ld != %d or %d\n", - pdidi->dwSize, sizeof(DIDEVICEINSTANCE_DX3A), - sizeof(DIDEVICEINSTANCEA)); - return DIERR_INVALIDPARAM; - } - - /* Return joystick */ - pdidi->guidInstance = GUID_Joystick; - pdidi->guidProduct = DInput_Wine_Joystick_GUID; - /* we only support traditional joysticks for now */ - pdidi->dwDevType = This->devcaps.dwDevType; - strcpy(pdidi->tszInstanceName, "Joystick"); - strcpy(pdidi->tszProductName, This->name); - if (pdidi->dwSize > sizeof(DIDEVICEINSTANCE_DX3A)) { - pdidi->guidFFDriver = GUID_NULL; - pdidi->wUsagePage = 0; - pdidi->wUsage = 0; - } - - return DI_OK; -} - -/****************************************************************************** - * GetDeviceInfo : get information about a device's identity - */ -HRESULT WINAPI JoystickWImpl_GetDeviceInfo( - LPDIRECTINPUTDEVICE8W iface, - LPDIDEVICEINSTANCEW pdidi) -{ - JoystickImpl *This = (JoystickImpl *)iface; - - TRACE("(%p,%p)\n", iface, pdidi); - - if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3W)) && - (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW))) { - WARN("invalid parameter: pdidi->dwSize = %ld != %d or %d\n", - pdidi->dwSize, sizeof(DIDEVICEINSTANCE_DX3W), - sizeof(DIDEVICEINSTANCEW)); - return DIERR_INVALIDPARAM; - } - - /* Return joystick */ - pdidi->guidInstance = GUID_Joystick; - pdidi->guidProduct = DInput_Wine_Joystick_GUID; - /* we only support traditional joysticks for now */ - pdidi->dwDevType = This->devcaps.dwDevType; - MultiByteToWideChar(CP_ACP, 0, "Joystick", -1, pdidi->tszInstanceName, MAX_PATH); - MultiByteToWideChar(CP_ACP, 0, This->name, -1, pdidi->tszProductName, MAX_PATH); - if (pdidi->dwSize > sizeof(DIDEVICEINSTANCE_DX3W)) { - pdidi->guidFFDriver = GUID_NULL; - pdidi->wUsagePage = 0; - pdidi->wUsage = 0; - } - - return DI_OK; -} - -static IDirectInputDevice8AVtbl JoystickAvt = -{ - IDirectInputDevice2AImpl_QueryInterface, - IDirectInputDevice2AImpl_AddRef, - JoystickAImpl_Release, - JoystickAImpl_GetCapabilities, - JoystickAImpl_EnumObjects, - JoystickAImpl_GetProperty, - JoystickAImpl_SetProperty, - JoystickAImpl_Acquire, - JoystickAImpl_Unacquire, - JoystickAImpl_GetDeviceState, - JoystickAImpl_GetDeviceData, - JoystickAImpl_SetDataFormat, - JoystickAImpl_SetEventNotification, - IDirectInputDevice2AImpl_SetCooperativeLevel, - JoystickAImpl_GetObjectInfo, - JoystickAImpl_GetDeviceInfo, - IDirectInputDevice2AImpl_RunControlPanel, - IDirectInputDevice2AImpl_Initialize, - IDirectInputDevice2AImpl_CreateEffect, - IDirectInputDevice2AImpl_EnumEffects, - IDirectInputDevice2AImpl_GetEffectInfo, - IDirectInputDevice2AImpl_GetForceFeedbackState, - IDirectInputDevice2AImpl_SendForceFeedbackCommand, - IDirectInputDevice2AImpl_EnumCreatedEffectObjects, - IDirectInputDevice2AImpl_Escape, - JoystickAImpl_Poll, - IDirectInputDevice2AImpl_SendDeviceData, - IDirectInputDevice7AImpl_EnumEffectsInFile, - IDirectInputDevice7AImpl_WriteEffectToFile, - IDirectInputDevice8AImpl_BuildActionMap, - IDirectInputDevice8AImpl_SetActionMap, - IDirectInputDevice8AImpl_GetImageInfo -}; - -#if !defined(__STRICT_ANSI__) && defined(__GNUC__) -# define XCAST(fun) (typeof(SysJoystickWvt.fun)) -#else -# define XCAST(fun) (void*) -#endif - -static IDirectInputDevice8WVtbl SysJoystickWvt = -{ - IDirectInputDevice2WImpl_QueryInterface, - XCAST(AddRef)IDirectInputDevice2AImpl_AddRef, - XCAST(Release)JoystickAImpl_Release, - XCAST(GetCapabilities)JoystickAImpl_GetCapabilities, - JoystickWImpl_EnumObjects, - XCAST(GetProperty)JoystickAImpl_GetProperty, - XCAST(SetProperty)JoystickAImpl_SetProperty, - XCAST(Acquire)JoystickAImpl_Acquire, - XCAST(Unacquire)JoystickAImpl_Unacquire, - XCAST(GetDeviceState)JoystickAImpl_GetDeviceState, - XCAST(GetDeviceData)JoystickAImpl_GetDeviceData, - XCAST(SetDataFormat)JoystickAImpl_SetDataFormat, - XCAST(SetEventNotification)JoystickAImpl_SetEventNotification, - XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel, - IDirectInputDevice2WImpl_GetObjectInfo, - JoystickWImpl_GetDeviceInfo, - XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel, - XCAST(Initialize)IDirectInputDevice2AImpl_Initialize, - XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect, - IDirectInputDevice2WImpl_EnumEffects, - IDirectInputDevice2WImpl_GetEffectInfo, - XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState, - XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand, - XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects, - XCAST(Escape)IDirectInputDevice2AImpl_Escape, - XCAST(Poll)JoystickAImpl_Poll, - XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData, - IDirectInputDevice7WImpl_EnumEffectsInFile, - IDirectInputDevice7WImpl_WriteEffectToFile, - IDirectInputDevice8WImpl_BuildActionMap, - IDirectInputDevice8WImpl_SetActionMap, - IDirectInputDevice8WImpl_GetImageInfo -}; -#undef XCAST - -#endif /* HAVE_LINUX_22_JOYSTICK_API */ +/* DirectInput Joystick device + * + * Copyright 1998 Marcus Meissner + * Copyright 1998,1999 Lionel Ulmer + * Copyright 2000-2001 TransGaming Technologies Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * To Do: + * dead zone + * force feedback + */ + +#include "config.h" +#include "wine/port.h" + +#ifdef HAVE_LINUX_22_JOYSTICK_API + +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_SYS_TIME_H +# include +#endif +#include +#ifdef HAVE_SYS_IOCTL_H +# include +#endif +#include +#ifdef HAVE_SYS_ERRNO_H +# include +#endif +#ifdef HAVE_LINUX_IOCTL_H +# include +#endif +#ifdef HAVE_LINUX_JOYSTICK_H +# include +#endif +#define JOYDEV "/dev/js" + +#include "wine/debug.h" +#include "wine/unicode.h" +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" +#include "dinput.h" + +#include "dinput_private.h" +#include "device_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dinput); + +typedef struct { + LONG lMin; + LONG lMax; + LONG lDeadZone; + LONG lSaturation; +} ObjProps; + +typedef struct { + LONG lX; + LONG lY; +} POV; + +typedef struct JoystickImpl JoystickImpl; +static IDirectInputDevice8AVtbl JoystickAvt; +static IDirectInputDevice8WVtbl JoystickWvt; +struct JoystickImpl +{ + LPVOID lpVtbl; + DWORD ref; + GUID guid; + char dev[32]; + + /* The 'parent' DInput */ + IDirectInputImpl *dinput; + + /* joystick private */ + int joyfd; + DIJOYSTATE2 js; /* wine data */ + LPDIDATAFORMAT user_df; /* user defined format */ + DataFormat *transform; /* wine to user format converter */ + int *offsets; /* object offsets */ + ObjProps *props; + HANDLE hEvent; + LPDIDEVICEOBJECTDATA data_queue; + int queue_head, queue_tail, queue_len; + BOOL acquired; + char *name; + DIDEVCAPS devcaps; + LONG deadzone; + int *axis_map; + int axes; + int buttons; + POV povs[4]; + CRITICAL_SECTION crit; + BOOL overflow; +}; + +static GUID DInput_Wine_Joystick_GUID = { /* 9e573ed9-7734-11d2-8d4a-23903fb6bdf7 */ + 0x9e573ed9, + 0x7734, + 0x11d2, + {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7} +}; + +static void _dump_DIDEVCAPS(LPDIDEVCAPS lpDIDevCaps) +{ + TRACE("dwSize: %ld\n", lpDIDevCaps->dwSize); + TRACE("dwFlags: %08lx\n",lpDIDevCaps->dwFlags); + TRACE("dwDevType: %08lx %s\n", lpDIDevCaps->dwDevType, + lpDIDevCaps->dwDevType == DIDEVTYPE_DEVICE ? "DIDEVTYPE_DEVICE" : + lpDIDevCaps->dwDevType == DIDEVTYPE_DEVICE ? "DIDEVTYPE_DEVICE" : + lpDIDevCaps->dwDevType == DIDEVTYPE_MOUSE ? "DIDEVTYPE_MOUSE" : + lpDIDevCaps->dwDevType == DIDEVTYPE_KEYBOARD ? "DIDEVTYPE_KEYBOARD" : + lpDIDevCaps->dwDevType == DIDEVTYPE_JOYSTICK ? "DIDEVTYPE_JOYSTICK" : + lpDIDevCaps->dwDevType == DIDEVTYPE_HID ? "DIDEVTYPE_HID" : "UNKNOWN"); + TRACE("dwAxes: %ld\n",lpDIDevCaps->dwAxes); + TRACE("dwButtons: %ld\n",lpDIDevCaps->dwButtons); + TRACE("dwPOVs: %ld\n",lpDIDevCaps->dwPOVs); + if (lpDIDevCaps->dwSize > sizeof(DIDEVCAPS_DX3)) { + TRACE("dwFFSamplePeriod: %ld\n",lpDIDevCaps->dwFFSamplePeriod); + TRACE("dwFFMinTimeResolution: %ld\n",lpDIDevCaps->dwFFMinTimeResolution); + TRACE("dwFirmwareRevision: %ld\n",lpDIDevCaps->dwFirmwareRevision); + TRACE("dwHardwareRevision: %ld\n",lpDIDevCaps->dwHardwareRevision); + TRACE("dwFFDriverVersion: %ld\n",lpDIDevCaps->dwFFDriverVersion); + } +} + +static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, int version, int id) +{ + int fd = -1; + char dev[32]; + + if (dwFlags & DIEDFL_FORCEFEEDBACK) { + WARN("force feedback not supported\n"); + return FALSE; + } + + if ((dwDevType == 0) || + ((dwDevType == DIDEVTYPE_JOYSTICK) && (version < 8)) || + (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 8))) { + /* check whether we have a joystick */ + sprintf(dev, "%s%d", JOYDEV, id); + if ((fd = open(dev,O_RDONLY)) < 0) { + WARN("open(%s,O_RDONLY) failed: %s\n", dev, strerror(errno)); + return FALSE; + } + + /* Return joystick */ + lpddi->guidInstance = DInput_Wine_Joystick_GUID; + lpddi->guidInstance.Data3 = id; + lpddi->guidProduct = DInput_Wine_Joystick_GUID; + /* we only support traditional joysticks for now */ + if (version >= 8) + lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); + else + lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); + sprintf(lpddi->tszInstanceName, "Joystick %d", id); +#if defined(JSIOCGNAME) + if (ioctl(fd,JSIOCGNAME(sizeof(lpddi->tszProductName)),lpddi->tszProductName) < 0) { + WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", dev, strerror(errno)); + strcpy(lpddi->tszProductName, "Wine Joystick"); + } +#else + strcpy(lpddi->tszProductName, "Wine Joystick"); +#endif + + lpddi->guidFFDriver = GUID_NULL; + close(fd); + TRACE("Enumerating the linux Joystick device: %s (%s)\n", dev, lpddi->tszProductName); + return TRUE; + } + + return FALSE; +} + +static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, int version, int id) +{ + int fd = -1; + char name[MAX_PATH]; + char dev[32]; + char friendly[32]; + + if (dwFlags & DIEDFL_FORCEFEEDBACK) { + WARN("force feedback not supported\n"); + return FALSE; + } + + if ((dwDevType == 0) || + ((dwDevType == DIDEVTYPE_JOYSTICK) && (version < 8)) || + (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 8))) { + /* check whether we have a joystick */ + sprintf(dev, "%s%d", JOYDEV, id); + if ((fd = open(dev,O_RDONLY)) < 0) { + WARN("open(%s,O_RDONLY) failed: %s\n", dev, strerror(errno)); + return FALSE; + } + + /* Return joystick */ + lpddi->guidInstance = DInput_Wine_Joystick_GUID; + lpddi->guidInstance.Data3 = id; + lpddi->guidProduct = DInput_Wine_Joystick_GUID; + /* we only support traditional joysticks for now */ + if (version >= 8) + lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); + else + lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); + sprintf(friendly, "Joystick %d", id); + MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH); +#if defined(JSIOCGNAME) + if (ioctl(fd,JSIOCGNAME(sizeof(name)),name) < 0) { + WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", dev, strerror(errno)); + strcpy(name, "Wine Joystick"); + } +#else + strcpy(name, "Wine Joystick"); +#endif + MultiByteToWideChar(CP_ACP, 0, name, -1, lpddi->tszProductName, MAX_PATH); + lpddi->guidFFDriver = GUID_NULL; + close(fd); + TRACE("Enumerating the linux Joystick device: %s (%s)\n",dev,name); + return TRUE; + } + + return FALSE; +} + +/* + * Get a config key from either the app-specific or the default config + */ + +inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name, + char *buffer, DWORD size ) +{ + if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, buffer, &size )) + return 0; + + if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, buffer, &size )) + return 0; + + return ERROR_FILE_NOT_FOUND; +} + +/* + * Setup the dinput options. + */ + +static HRESULT setup_dinput_options(JoystickImpl * device) +{ + char buffer[MAX_PATH+1]; + HKEY hkey, appkey = 0; + DWORD len; + + buffer[MAX_PATH]='\0'; + + if (RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\dinput", &hkey)) hkey = 0; + + len = GetModuleFileNameA( 0, buffer, MAX_PATH ); + if (len && len < MAX_PATH) { + HKEY tmpkey; + + if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\AppDefaults", &tmpkey )) { + char appname[MAX_PATH+16]; + char *p = strrchr( buffer, '\\' ); + if (p!=NULL) { + strcpy(appname,p+1); + strcat(appname,"\\dinput"); + TRACE("appname = [%s] \n",appname); + if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0; + } + RegCloseKey( tmpkey ); + } + } + + /* get options */ + + if (!get_config_key( hkey, appkey, "DefaultDeadZone", buffer, MAX_PATH )) { + device->deadzone = atoi(buffer); + TRACE("setting default deadzone to: \"%s\" %ld\n", buffer, device->deadzone); + } + + if (!get_config_key( hkey, appkey, device->name, buffer, MAX_PATH )) { + int tokens = 0; + int axis = 0; + int pov = 0; + const char *delim = ","; + char * ptr; + TRACE("\"%s\" = \"%s\"\n", device->name, buffer); + + device->axis_map = HeapAlloc(GetProcessHeap(), 0, device->axes * sizeof(int)); + if (device->axis_map == 0) + return DIERR_OUTOFMEMORY; + + if ((ptr = strtok(buffer, delim)) != NULL) { + do { + if (strcmp(ptr, "X") == 0) { + device->axis_map[tokens] = 0; + axis++; + } else if (strcmp(ptr, "Y") == 0) { + device->axis_map[tokens] = 1; + axis++; + } else if (strcmp(ptr, "Z") == 0) { + device->axis_map[tokens] = 2; + axis++; + } else if (strcmp(ptr, "Rx") == 0) { + device->axis_map[tokens] = 3; + axis++; + } else if (strcmp(ptr, "Ry") == 0) { + device->axis_map[tokens] = 4; + axis++; + } else if (strcmp(ptr, "Rz") == 0) { + device->axis_map[tokens] = 5; + axis++; + } else if (strcmp(ptr, "Slider1") == 0) { + device->axis_map[tokens] = 6; + axis++; + } else if (strcmp(ptr, "Slider2") == 0) { + device->axis_map[tokens] = 7; + axis++; + } else if (strcmp(ptr, "POV1") == 0) { + device->axis_map[tokens++] = 8; + device->axis_map[tokens] = 8; + pov++; + } else if (strcmp(ptr, "POV2") == 0) { + device->axis_map[tokens++] = 9; + device->axis_map[tokens] = 9; + pov++; + } else if (strcmp(ptr, "POV3") == 0) { + device->axis_map[tokens++] = 10; + device->axis_map[tokens] = 10; + pov++; + } else if (strcmp(ptr, "POV4") == 0) { + device->axis_map[tokens++] = 11; + device->axis_map[tokens] = 11; + pov++; + } else { + ERR("invalid joystick axis type: %s\n", ptr); + device->axis_map[tokens] = tokens; + axis++; + } + + tokens++; + } while ((ptr = strtok(NULL, delim)) != NULL); + + if (tokens != device->devcaps.dwAxes) { + ERR("not all joystick axes mapped: %d axes(%d,%d), %d arguments\n", device->axes, axis, pov,tokens); + while (tokens < device->axes) { + device->axis_map[tokens] = tokens; + tokens++; + } + } + } + + device->devcaps.dwAxes = axis; + device->devcaps.dwPOVs = pov; + } + + if (appkey) + RegCloseKey( appkey ); + + if (hkey) + RegCloseKey( hkey ); + + return DI_OK; +} + +void calculate_ids(JoystickImpl* device) +{ + int i; + int axis = 0; + int button = 0; + int pov = 0; + int axis_base; + int pov_base; + int button_base; + + /* Make two passes over the format. The first counts the number + * for each type and the second sets the id */ + for (i = 0; i < device->user_df->dwNumObjs; i++) { + if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_AXIS) + axis++; + else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_POV) + pov++; + else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_BUTTON) + button++; + } + + axis_base = 0; + pov_base = axis; + button_base = axis + pov; + + axis = 0; + button = 0; + pov = 0; + + for (i = 0; i < device->user_df->dwNumObjs; i++) { + DWORD type = 0; + if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_AXIS) { + axis++; + type = DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) | + DIDFT_MAKEINSTANCE(axis + axis_base); + TRACE("axis type = 0x%08lx\n", type); + } else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_POV) { + pov++; + type = DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) | + DIDFT_MAKEINSTANCE(pov + pov_base); + TRACE("POV type = 0x%08lx\n", type); + } else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_BUTTON) { + button++; + type = DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) | + DIDFT_MAKEINSTANCE(button + button_base); + TRACE("button type = 0x%08lx\n", type); + } + device->user_df->rgodf[i].dwType = type; + } +} + +static HRESULT alloc_device(REFGUID rguid, LPVOID jvt, IDirectInputImpl *dinput, LPDIRECTINPUTDEVICEA* pdev) +{ + DWORD i; + JoystickImpl* newDevice; + char name[MAX_PATH]; + HRESULT hr; + + newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl)); + if (newDevice == 0) { + WARN("out of memory\n"); + *pdev = 0; + return DIERR_OUTOFMEMORY; + } + + sprintf(newDevice->dev, "%s%d", JOYDEV, rguid->Data3); + + if ((newDevice->joyfd = open(newDevice->dev,O_RDONLY)) < 0) { + WARN("open(%s,O_RDONLY) failed: %s\n", newDevice->dev, strerror(errno)); + HeapFree(GetProcessHeap(), 0, newDevice); + return DIERR_DEVICENOTREG; + } + + /* get the device name */ +#if defined(JSIOCGNAME) + if (ioctl(newDevice->joyfd,JSIOCGNAME(MAX_PATH),name) < 0) { + WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", newDevice->dev, strerror(errno)); + strcpy(name, "Wine Joystick"); + } +#else + strcpy(name, "Wine Joystick"); +#endif + + /* copy the device name */ + newDevice->name = HeapAlloc(GetProcessHeap(),0,strlen(name) + 1); + strcpy(newDevice->name, name); + +#ifdef JSIOCGAXES + if (ioctl(newDevice->joyfd,JSIOCGAXES,&newDevice->axes) < 0) { + WARN("ioctl(%s,JSIOCGAXES) failed: %s, defauting to 2\n", newDevice->dev, strerror(errno)); + newDevice->axes = 2; + } +#endif +#ifdef JSIOCGBUTTONS + if (ioctl(newDevice->joyfd,JSIOCGBUTTONS,&newDevice->buttons) < 0) { + WARN("ioctl(%s,JSIOCGBUTTONS) failed: %s, defauting to 2\n", newDevice->dev, strerror(errno)); + newDevice->buttons = 2; + } +#endif + + newDevice->lpVtbl = jvt; + newDevice->ref = 1; + newDevice->dinput = dinput; + newDevice->acquired = FALSE; + newDevice->overflow = FALSE; + CopyMemory(&(newDevice->guid),rguid,sizeof(*rguid)); + + /* setup_dinput_options may change these */ + newDevice->deadzone = 5000; + newDevice->devcaps.dwButtons = newDevice->buttons; + newDevice->devcaps.dwAxes = newDevice->axes; + newDevice->devcaps.dwPOVs = 0; + + /* do any user specified configuration */ + hr = setup_dinput_options(newDevice); + if (hr != DI_OK) + goto FAILED1; + + if (newDevice->axis_map == 0) { + newDevice->axis_map = HeapAlloc(GetProcessHeap(), 0, newDevice->axes * sizeof(int)); + if (newDevice->axis_map == 0) + goto FAILED; + + for (i = 0; i < newDevice->axes; i++) + newDevice->axis_map[i] = i; + } + + /* wine uses DIJOYSTATE2 as it's internal format so copy + * the already defined format c_dfDIJoystick2 */ + newDevice->user_df = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwSize); + if (newDevice->user_df == 0) + goto FAILED; + + CopyMemory(newDevice->user_df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize); + + /* copy default objects */ + newDevice->user_df->rgodf = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwNumObjs*c_dfDIJoystick2.dwObjSize); + if (newDevice->user_df->rgodf == 0) + goto FAILED; + + CopyMemory(newDevice->user_df->rgodf,c_dfDIJoystick2.rgodf,c_dfDIJoystick2.dwNumObjs*c_dfDIJoystick2.dwObjSize); + + /* create default properties */ + newDevice->props = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwNumObjs*sizeof(ObjProps)); + if (newDevice->props == 0) + goto FAILED; + + /* initialize default properties */ + for (i = 0; i < c_dfDIJoystick2.dwNumObjs; i++) { + newDevice->props[i].lMin = 0; + newDevice->props[i].lMax = 0xffff; + newDevice->props[i].lDeadZone = newDevice->deadzone; /* % * 1000 */ + newDevice->props[i].lSaturation = 0; + } + + /* create an offsets array */ + newDevice->offsets = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,c_dfDIJoystick2.dwNumObjs*sizeof(int)); + if (newDevice->offsets == 0) + goto FAILED; + + /* create the default transform filter */ + newDevice->transform = create_DataFormat(&c_dfDIJoystick2, newDevice->user_df, newDevice->offsets); + + calculate_ids(newDevice); + + IDirectInputDevice_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->dinput); + InitializeCriticalSection(&(newDevice->crit)); + newDevice->crit.DebugInfo->Spare[1] = (DWORD)"DINPUT_Mouse"; + + newDevice->devcaps.dwSize = sizeof(newDevice->devcaps); + newDevice->devcaps.dwFlags = DIDC_ATTACHED; + if (newDevice->dinput->version >= 8) + newDevice->devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); + else + newDevice->devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); + newDevice->devcaps.dwFFSamplePeriod = 0; + newDevice->devcaps.dwFFMinTimeResolution = 0; + newDevice->devcaps.dwFirmwareRevision = 0; + newDevice->devcaps.dwHardwareRevision = 0; + newDevice->devcaps.dwFFDriverVersion = 0; + + if (TRACE_ON(dinput)) { + _dump_DIDATAFORMAT(newDevice->user_df); + for (i = 0; i < (newDevice->axes); i++) + TRACE("axis_map[%ld] = %d\n", i, newDevice->axis_map[i]); + _dump_DIDEVCAPS(&newDevice->devcaps); + } + + *pdev = (LPDIRECTINPUTDEVICEA)newDevice; + + return DI_OK; + +FAILED: + hr = DIERR_OUTOFMEMORY; +FAILED1: + HeapFree(GetProcessHeap(),0,newDevice->axis_map); + HeapFree(GetProcessHeap(),0,newDevice->name); + HeapFree(GetProcessHeap(),0,newDevice->props); + HeapFree(GetProcessHeap(),0,newDevice->user_df->rgodf); + HeapFree(GetProcessHeap(),0,newDevice->user_df); + HeapFree(GetProcessHeap(),0,newDevice); + *pdev = 0; + + return hr; +} + +static BOOL IsJoystickGUID(REFGUID guid) +{ + GUID wine_joystick = DInput_Wine_Joystick_GUID; + GUID dev_guid = *guid; + + wine_joystick.Data3 = 0; + dev_guid.Data3 = 0; + + return IsEqualGUID(&wine_joystick, &dev_guid); +} + +static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev) +{ + if ((IsEqualGUID(&GUID_Joystick,rguid)) || + (IsJoystickGUID(rguid))) { + if ((riid == NULL) || + IsEqualGUID(&IID_IDirectInputDeviceA,riid) || + IsEqualGUID(&IID_IDirectInputDevice2A,riid) || + IsEqualGUID(&IID_IDirectInputDevice7A,riid) || + IsEqualGUID(&IID_IDirectInputDevice8A,riid)) { + return alloc_device(rguid, &JoystickAvt, dinput, pdev); + } else { + WARN("no interface\n"); + *pdev = 0; + return DIERR_NOINTERFACE; + } + } + + WARN("invalid device GUID\n"); + *pdev = 0; + return DIERR_DEVICENOTREG; +} + +static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev) +{ + if ((IsEqualGUID(&GUID_Joystick,rguid)) || + (IsJoystickGUID(rguid))) { + if ((riid == NULL) || + IsEqualGUID(&IID_IDirectInputDeviceW,riid) || + IsEqualGUID(&IID_IDirectInputDevice2W,riid) || + IsEqualGUID(&IID_IDirectInputDevice7W,riid) || + IsEqualGUID(&IID_IDirectInputDevice8W,riid)) { + return alloc_device(rguid, &JoystickWvt, dinput, (LPDIRECTINPUTDEVICEA *)pdev); + } else { + WARN("no interface\n"); + *pdev = 0; + return DIERR_NOINTERFACE; + } + } + + WARN("invalid device GUID\n"); + *pdev = 0; + return DIERR_DEVICENOTREG; +} + +static dinput_device joydev = { + 10, + "Wine Linux joystick driver", + joydev_enum_deviceA, + joydev_enum_deviceW, + joydev_create_deviceA, + joydev_create_deviceW +}; + +DECL_GLOBAL_CONSTRUCTOR(joydev_register) { dinput_register_device(&joydev); } + + + +/****************************************************************************** + * Joystick + */ +static ULONG WINAPI JoystickAImpl_Release(LPDIRECTINPUTDEVICE8A iface) +{ + JoystickImpl *This = (JoystickImpl *)iface; + ULONG ref; + + ref = InterlockedDecrement((&This->ref)); + if (ref) + return ref; + + /* Free the device name */ + HeapFree(GetProcessHeap(),0,This->name); + + /* Free the axis map */ + HeapFree(GetProcessHeap(),0,This->axis_map); + + /* Free the data queue */ + HeapFree(GetProcessHeap(),0,This->data_queue); + + /* Free the DataFormat */ + HeapFree(GetProcessHeap(), 0, This->user_df->rgodf); + HeapFree(GetProcessHeap(), 0, This->user_df); + + /* Free the properties */ + HeapFree(GetProcessHeap(), 0, This->props); + + /* Free the offsets array */ + HeapFree(GetProcessHeap(),0,This->offsets); + + /* release the data transform filter */ + release_DataFormat(This->transform); + + This->crit.DebugInfo->Spare[1] = 0; + DeleteCriticalSection(&(This->crit)); + IDirectInputDevice_Release((LPDIRECTINPUTDEVICE8A)This->dinput); + + HeapFree(GetProcessHeap(),0,This); + return 0; +} + +/****************************************************************************** + * SetDataFormat : the application can choose the format of the data + * the device driver sends back with GetDeviceState. + */ +static HRESULT WINAPI JoystickAImpl_SetDataFormat( + LPDIRECTINPUTDEVICE8A iface, + LPCDIDATAFORMAT df) +{ + JoystickImpl *This = (JoystickImpl *)iface; + unsigned int i; + LPDIDATAFORMAT new_df = 0; + LPDIOBJECTDATAFORMAT new_rgodf = 0; + ObjProps * new_props = 0; + + TRACE("(%p,%p)\n",This,df); + + if (This->acquired) { + WARN("acquired\n"); + return DIERR_ACQUIRED; + } + + if (TRACE_ON(dinput)) + _dump_DIDATAFORMAT(df); + + /* Store the new data format */ + new_df = HeapAlloc(GetProcessHeap(),0,df->dwSize); + if (new_df == 0) + goto FAILED; + + new_rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize); + if (new_rgodf == 0) + goto FAILED; + + new_props = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*sizeof(ObjProps)); + if (new_props == 0) + goto FAILED; + + HeapFree(GetProcessHeap(),0,This->user_df); + HeapFree(GetProcessHeap(),0,This->user_df->rgodf); + HeapFree(GetProcessHeap(),0,This->props); + release_DataFormat(This->transform); + + This->user_df = new_df; + CopyMemory(This->user_df, df, df->dwSize); + This->user_df->rgodf = new_rgodf; + CopyMemory(This->user_df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize); + This->props = new_props; + for (i = 0; i < df->dwNumObjs; i++) { + This->props[i].lMin = 0; + This->props[i].lMax = 0xffff; + This->props[i].lDeadZone = 1000; + This->props[i].lSaturation = 0; + } + This->transform = create_DataFormat(&c_dfDIJoystick2, This->user_df, This->offsets); + + calculate_ids(This); + + return DI_OK; + +FAILED: + WARN("out of memory\n"); + HeapFree(GetProcessHeap(),0,new_props); + HeapFree(GetProcessHeap(),0,new_rgodf); + HeapFree(GetProcessHeap(),0,new_df); + return DIERR_OUTOFMEMORY; +} + +/****************************************************************************** + * Acquire : gets exclusive control of the joystick + */ +static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(%p)\n",This); + + if (This->acquired) { + WARN("already acquired\n"); + return S_FALSE; + } + + /* open the joystick device */ + if (This->joyfd==-1) { + TRACE("opening joystick device %s\n", This->dev); + + This->joyfd=open(This->dev,O_RDONLY); + if (This->joyfd==-1) { + ERR("open(%s) failed: %s\n", This->dev, strerror(errno)); + return DIERR_NOTFOUND; + } + } + + This->acquired = TRUE; + + return DI_OK; +} + +/****************************************************************************** + * Unacquire : frees the joystick + */ +static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(%p)\n",This); + + if (!This->acquired) { + WARN("not acquired\n"); + return DIERR_NOTACQUIRED; + } + + if (This->joyfd!=-1) { + TRACE("closing joystick device\n"); + close(This->joyfd); + This->joyfd = -1; + This->acquired = FALSE; + return DI_OK; + } + + This->acquired = FALSE; + + return DI_NOEFFECT; +} + +LONG map_axis(JoystickImpl * This, short val, short index) +{ + double fval = val; + double fmin = This->props[index].lMin; + double fmax = This->props[index].lMax; + double fret; + + fret = (((fval + 32767.0) * (fmax - fmin)) / (32767.0*2.0)) + fmin; + + if (fret >= 0.0) + fret += 0.5; + else + fret -= 0.5; + + return fret; +} + +/* convert wine format offset to user format object index */ +int offset_to_object(JoystickImpl *This, int offset) +{ + int i; + + for (i = 0; i < This->user_df->dwNumObjs; i++) { + if (This->user_df->rgodf[i].dwOfs == offset) + return i; + } + + return -1; +} + +static LONG calculate_pov(JoystickImpl *This, int index) +{ + if (This->povs[index].lX < 16384) { + if (This->povs[index].lY < 16384) + This->js.rgdwPOV[index] = 31500; + else if (This->povs[index].lY > 49150) + This->js.rgdwPOV[index] = 22500; + else + This->js.rgdwPOV[index] = 27000; + } else if (This->povs[index].lX > 49150) { + if (This->povs[index].lY < 16384) + This->js.rgdwPOV[index] = 4500; + else if (This->povs[index].lY > 49150) + This->js.rgdwPOV[index] = 13500; + else + This->js.rgdwPOV[index] = 9000; + } else { + if (This->povs[index].lY < 16384) + This->js.rgdwPOV[index] = 0; + else if (This->povs[index].lY > 49150) + This->js.rgdwPOV[index] = 18000; + else + This->js.rgdwPOV[index] = -1; + } + + return This->js.rgdwPOV[index]; +} + +static void joy_polldev(JoystickImpl *This) { + struct timeval tv; + fd_set readfds; + struct js_event jse; + TRACE("(%p)\n", This); + + if (This->joyfd==-1) { + WARN("no device\n"); + return; + } + while (1) { + memset(&tv,0,sizeof(tv)); + FD_ZERO(&readfds);FD_SET(This->joyfd,&readfds); + if (1>select(This->joyfd+1,&readfds,NULL,NULL,&tv)) + return; + /* we have one event, so we can read */ + if (sizeof(jse)!=read(This->joyfd,&jse,sizeof(jse))) { + return; + } + TRACE("js_event: type 0x%x, number %d, value %d\n", + jse.type,jse.number,jse.value); + if (jse.type & JS_EVENT_BUTTON) { + int offset = This->offsets[jse.number + 12]; + int value = jse.value?0x80:0x00; + + This->js.rgbButtons[jse.number] = value; + GEN_EVENT(offset,value,jse.time,(This->dinput->evsequence)++); + } else if (jse.type & JS_EVENT_AXIS) { + int number = This->axis_map[jse.number]; /* wine format object index */ + if (number < 12) { + int offset = This->offsets[number]; + int index = offset_to_object(This, offset); + LONG value = map_axis(This, jse.value, index); + + /* FIXME do deadzone and saturation here */ + + TRACE("changing axis %d => %d\n", jse.number, number); + switch (number) { + case 0: + This->js.lX = value; + break; + case 1: + This->js.lY = value; + break; + case 2: + This->js.lZ = value; + break; + case 3: + This->js.lRx = value; + break; + case 4: + This->js.lRy = value; + break; + case 5: + This->js.lRz = value; + break; + case 6: + This->js.rglSlider[0] = value; + break; + case 7: + This->js.rglSlider[1] = value; + break; + case 8: + /* FIXME don't go off array */ + if (This->axis_map[jse.number + 1] == number) + This->povs[0].lX = value; + else if (This->axis_map[jse.number - 1] == number) + This->povs[0].lY = value; + value = calculate_pov(This, 0); + break; + case 9: + if (This->axis_map[jse.number + 1] == number) + This->povs[1].lX = value; + else if (This->axis_map[jse.number - 1] == number) + This->povs[1].lY = value; + value = calculate_pov(This, 1); + break; + case 10: + if (This->axis_map[jse.number + 1] == number) + This->povs[2].lX = value; + else if (This->axis_map[jse.number - 1] == number) + This->povs[2].lY = value; + value = calculate_pov(This, 2); + break; + case 11: + if (This->axis_map[jse.number + 1] == number) + This->povs[3].lX = value; + else if (This->axis_map[jse.number - 1] == number) + This->povs[3].lY = value; + value = calculate_pov(This, 3); + break; + } + + GEN_EVENT(offset,value,jse.time,(This->dinput->evsequence)++); + } else + WARN("axis %d not supported\n", number); + } + } +} + +/****************************************************************************** + * GetDeviceState : returns the "state" of the joystick. + * + */ +static HRESULT WINAPI JoystickAImpl_GetDeviceState( + LPDIRECTINPUTDEVICE8A iface, + DWORD len, + LPVOID ptr) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(%p,0x%08lx,%p)\n",This,len,ptr); + + if (!This->acquired) { + WARN("not acquired\n"); + return DIERR_NOTACQUIRED; + } + + /* update joystick state */ + joy_polldev(This); + + /* convert and copy data to user supplied buffer */ + fill_DataFormat(ptr, &This->js, This->transform); + + return DI_OK; +} + +/****************************************************************************** + * GetDeviceData : gets buffered input data. + */ +static HRESULT WINAPI JoystickAImpl_GetDeviceData( + LPDIRECTINPUTDEVICE8A iface, + DWORD dodsize, + LPDIDEVICEOBJECTDATA dod, + LPDWORD entries, + DWORD flags) +{ + JoystickImpl *This = (JoystickImpl *)iface; + DWORD len; + int nqtail; + HRESULT hr = DI_OK; + + TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags); + + if (!This->acquired) { + WARN("not acquired\n"); + return DIERR_NOTACQUIRED; + } + + EnterCriticalSection(&(This->crit)); + + joy_polldev(This); + + len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0) + + (This->queue_head - This->queue_tail); + if (len > *entries) + len = *entries; + + if (dod == NULL) { + if (len) + TRACE("Application discarding %ld event(s).\n", len); + + *entries = len; + nqtail = This->queue_tail + len; + while (nqtail >= This->queue_len) + nqtail -= This->queue_len; + } else { + if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3)) { + ERR("Wrong structure size !\n"); + LeaveCriticalSection(&(This->crit)); + return DIERR_INVALIDPARAM; + } + + if (len) + TRACE("Application retrieving %ld event(s).\n", len); + + *entries = 0; + nqtail = This->queue_tail; + while (len) { + /* Copy the buffered data into the application queue */ + memcpy((char *)dod + *entries * dodsize, This->data_queue + nqtail, dodsize); + /* Advance position */ + nqtail++; + if (nqtail >= This->queue_len) + nqtail -= This->queue_len; + (*entries)++; + len--; + } + } + + if (This->overflow) { + hr = DI_BUFFEROVERFLOW; + if (!(flags & DIGDD_PEEK)) { + This->overflow = FALSE; + } + } + + if (!(flags & DIGDD_PEEK)) + This->queue_tail = nqtail; + + LeaveCriticalSection(&(This->crit)); + + return hr; +} + +int find_property(JoystickImpl * This, LPCDIPROPHEADER ph) +{ + int i; + if (ph->dwHow == DIPH_BYOFFSET) { + return offset_to_object(This, ph->dwObj); + } else if (ph->dwHow == DIPH_BYID) { + for (i = 0; i < This->user_df->dwNumObjs; i++) { + if ((This->user_df->rgodf[i].dwType & 0x00ffffff) == (ph->dwObj & 0x00ffffff)) { + return i; + } + } + } + + return -1; +} + +/****************************************************************************** + * SetProperty : change input device properties + */ +static HRESULT WINAPI JoystickAImpl_SetProperty( + LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, + LPCDIPROPHEADER ph) +{ + JoystickImpl *This = (JoystickImpl *)iface; + int i; + + TRACE("(%p,%s,%p)\n",This,debugstr_guid(rguid),ph); + + if (TRACE_ON(dinput)) + _dump_DIPROPHEADER(ph); + + if (!HIWORD(rguid)) { + switch ((DWORD)rguid) { + case (DWORD) DIPROP_BUFFERSIZE: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + TRACE("buffersize = %ld\n",pd->dwData); + if (This->data_queue) + This->data_queue = HeapReAlloc(GetProcessHeap(),0, This->data_queue, pd->dwData * sizeof(DIDEVICEOBJECTDATA)); + else + This->data_queue = HeapAlloc(GetProcessHeap(),0, pd->dwData * sizeof(DIDEVICEOBJECTDATA)); + This->queue_head = 0; + This->queue_tail = 0; + This->queue_len = pd->dwData; + break; + } + case (DWORD)DIPROP_RANGE: { + LPCDIPROPRANGE pr = (LPCDIPROPRANGE)ph; + if (ph->dwHow == DIPH_DEVICE) { + TRACE("proprange(%ld,%ld) all\n",pr->lMin,pr->lMax); + for (i = 0; i < This->user_df->dwNumObjs; i++) { + This->props[i].lMin = pr->lMin; + This->props[i].lMax = pr->lMax; + } + } else { + int obj = find_property(This, ph); + TRACE("proprange(%ld,%ld) obj=%d\n",pr->lMin,pr->lMax,obj); + if (obj >= 0) { + This->props[obj].lMin = pr->lMin; + This->props[obj].lMax = pr->lMax; + return DI_OK; + } + } + break; + } + case (DWORD)DIPROP_DEADZONE: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + if (ph->dwHow == DIPH_DEVICE) { + TRACE("deadzone(%ld) all\n",pd->dwData); + for (i = 0; i < This->user_df->dwNumObjs; i++) + This->props[i].lDeadZone = pd->dwData; + } else { + int obj = find_property(This, ph); + TRACE("deadzone(%ld) obj=%d\n",pd->dwData,obj); + if (obj >= 0) { + This->props[obj].lDeadZone = pd->dwData; + return DI_OK; + } + } + break; + } + case (DWORD)DIPROP_SATURATION: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + if (ph->dwHow == DIPH_DEVICE) { + TRACE("saturation(%ld) all\n",pd->dwData); + for (i = 0; i < This->user_df->dwNumObjs; i++) + This->props[i].lSaturation = pd->dwData; + } else { + int obj = find_property(This, ph); + TRACE("saturation(%ld) obj=%d\n",pd->dwData,obj); + if (obj >= 0) { + This->props[obj].lSaturation = pd->dwData; + return DI_OK; + } + } + break; + } + default: + FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); + break; + } + } + + return DI_OK; +} + +/****************************************************************************** + * SetEventNotification : specifies event to be sent on state change + */ +static HRESULT WINAPI JoystickAImpl_SetEventNotification( + LPDIRECTINPUTDEVICE8A iface, HANDLE hnd +) { + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd); + This->hEvent = hnd; + return DI_OK; +} + +static HRESULT WINAPI JoystickAImpl_GetCapabilities( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVCAPS lpDIDevCaps) +{ + JoystickImpl *This = (JoystickImpl *)iface; + int size; + + TRACE("%p->(%p)\n",iface,lpDIDevCaps); + + if (lpDIDevCaps == NULL) { + WARN("invalid parameter: lpDIDevCaps = NULL\n"); + return DIERR_INVALIDPARAM; + } + + size = lpDIDevCaps->dwSize; + CopyMemory(lpDIDevCaps, &This->devcaps, size); + lpDIDevCaps->dwSize = size; + + if (TRACE_ON(dinput)) + _dump_DIDEVCAPS(lpDIDevCaps); + + return DI_OK; +} + +static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE8A iface) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(%p)\n",This); + + if (!This->acquired) { + WARN("not acquired\n"); + return DIERR_NOTACQUIRED; + } + + joy_polldev(This); + return DI_OK; +} + +/****************************************************************************** + * EnumObjects : enumerate the different buttons and axis... + */ +static HRESULT WINAPI JoystickAImpl_EnumObjects( + LPDIRECTINPUTDEVICE8A iface, + LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + JoystickImpl *This = (JoystickImpl *)iface; + DIDEVICEOBJECTINSTANCEA ddoi; + BYTE i; + int user_offset; + int user_object; + + TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags); + if (TRACE_ON(dinput)) { + TRACE(" - flags = "); + _dump_EnumObjects_flags(dwFlags); + TRACE("\n"); + } + + /* Only the fields till dwFFMaxForce are relevant */ + ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce); + + /* For the joystick, do as is done in the GetCapabilities function */ + if ((dwFlags == DIDFT_ALL) || + (dwFlags & DIDFT_AXIS) || + (dwFlags & DIDFT_POV)) { + int pov[4] = { 0, 0, 0, 0 }; + int axes = 0; + int povs = 0; + + for (i = 0; i < This->axes; i++) { + int wine_obj = This->axis_map[i]; + BOOL skip = FALSE; + + switch (wine_obj) { + case 0: + ddoi.guidType = GUID_XAxis; + break; + case 1: + ddoi.guidType = GUID_YAxis; + break; + case 2: + ddoi.guidType = GUID_ZAxis; + break; + case 3: + ddoi.guidType = GUID_RxAxis; + break; + case 4: + ddoi.guidType = GUID_RyAxis; + break; + case 5: + ddoi.guidType = GUID_RzAxis; + break; + case 6: + ddoi.guidType = GUID_Slider; + break; + case 7: + ddoi.guidType = GUID_Slider; + break; + case 8: + pov[0]++; + ddoi.guidType = GUID_POV; + break; + case 9: + pov[1]++; + ddoi.guidType = GUID_POV; + break; + case 10: + pov[2]++; + ddoi.guidType = GUID_POV; + break; + case 11: + pov[3]++; + ddoi.guidType = GUID_POV; + break; + default: + ddoi.guidType = GUID_Unknown; + } + if (wine_obj < 8) { + user_offset = This->offsets[wine_obj]; /* get user offset from wine index */ + user_object = offset_to_object(This, user_offset); + + ddoi.dwType = This->user_df->rgodf[user_object].dwType & 0x00ffffff; + ddoi.dwOfs = This->user_df->rgodf[user_object].dwOfs; + sprintf(ddoi.tszName, "Axis %d", axes); + axes++; + } else { + if (pov[wine_obj - 8] < 2) { + user_offset = This->offsets[wine_obj]; /* get user offset from wine index */ + user_object = offset_to_object(This, user_offset); + + ddoi.dwType = This->user_df->rgodf[user_object].dwType & 0x00ffffff; + ddoi.dwOfs = This->user_df->rgodf[user_object].dwOfs; + sprintf(ddoi.tszName, "POV %d", povs); + povs++; + } else + skip = TRUE; + } + if (!skip) { + _dump_OBJECTINSTANCEA(&ddoi); + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) + return DI_OK; + } + } + } + + if ((dwFlags == DIDFT_ALL) || + (dwFlags & DIDFT_BUTTON)) { + + /* The DInput SDK says that GUID_Button is only for mouse buttons but well... */ + ddoi.guidType = GUID_Button; + + for (i = 0; i < This->buttons; i++) { + user_offset = This->offsets[i + 12]; /* get user offset from wine index */ + user_object = offset_to_object(This, user_offset); + ddoi.guidType = GUID_Button; + ddoi.dwType = This->user_df->rgodf[user_object].dwType & 0x00ffffff; + ddoi.dwOfs = This->user_df->rgodf[user_object].dwOfs; + sprintf(ddoi.tszName, "Button %d", i); + _dump_OBJECTINSTANCEA(&ddoi); + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; + } + } + + return DI_OK; +} + +/****************************************************************************** + * EnumObjects : enumerate the different buttons and axis... + */ +static HRESULT WINAPI JoystickWImpl_EnumObjects( + LPDIRECTINPUTDEVICE8W iface, + LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + device_enumobjects_AtoWcb_data data; + + data.lpCallBack = lpCallback; + data.lpvRef = lpvRef; + + return JoystickAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags); +} + +/****************************************************************************** + * GetProperty : get input device properties + */ +static HRESULT WINAPI JoystickAImpl_GetProperty( + LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, + LPDIPROPHEADER pdiph) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(%p,%s,%p)\n", iface, debugstr_guid(rguid), pdiph); + + if (TRACE_ON(dinput)) + _dump_DIPROPHEADER(pdiph); + + if (!HIWORD(rguid)) { + switch ((DWORD)rguid) { + case (DWORD) DIPROP_BUFFERSIZE: { + LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; + TRACE(" return buffersize = %d\n",This->queue_len); + pd->dwData = This->queue_len; + break; + } + case (DWORD) DIPROP_RANGE: { + LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph; + int obj = find_property(This, pdiph); + /* The app is querying the current range of the axis + * return the lMin and lMax values */ + if (obj >= 0) { + pr->lMin = This->props[obj].lMin; + pr->lMax = This->props[obj].lMax; + TRACE("range(%ld, %ld) obj=%d\n", pr->lMin, pr->lMax, obj); + return DI_OK; + } + break; + } + case (DWORD) DIPROP_DEADZONE: { + LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; + int obj = find_property(This, pdiph); + if (obj >= 0) { + pd->dwData = This->props[obj].lDeadZone; + TRACE("deadzone(%ld) obj=%d\n", pd->dwData, obj); + return DI_OK; + } + break; + } + case (DWORD) DIPROP_SATURATION: { + LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; + int obj = find_property(This, pdiph); + if (obj >= 0) { + pd->dwData = This->props[obj].lSaturation; + TRACE("saturation(%ld) obj=%d\n", pd->dwData, obj); + return DI_OK; + } + break; + } + default: + FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); + break; + } + } + + return DI_OK; +} + +/****************************************************************************** + * GetObjectInfo : get object info + */ +HRESULT WINAPI JoystickAImpl_GetObjectInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEOBJECTINSTANCEA pdidoi, + DWORD dwObj, + DWORD dwHow) +{ + JoystickImpl *This = (JoystickImpl *)iface; + DIDEVICEOBJECTINSTANCEA didoiA; + unsigned int i; + + TRACE("(%p,%p,%ld,0x%08lx(%s))\n", + iface, pdidoi, dwObj, dwHow, + dwHow == DIPH_BYOFFSET ? "DIPH_BYOFFSET" : + dwHow == DIPH_BYID ? "DIPH_BYID" : + dwHow == DIPH_BYUSAGE ? "DIPH_BYUSAGE" : + "UNKNOWN"); + + if (pdidoi == NULL) { + WARN("invalid parameter: pdidoi = NULL\n"); + return DIERR_INVALIDPARAM; + } + + if ((pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCEA)) && + (pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCE_DX3A))) { + WARN("invalid parameter: pdidoi->dwSize = %ld != %d or %d\n", + pdidoi->dwSize, sizeof(DIDEVICEOBJECTINSTANCEA), + sizeof(DIDEVICEOBJECTINSTANCE_DX3A)); + return DIERR_INVALIDPARAM; + } + + ZeroMemory(&didoiA, sizeof(didoiA)); + didoiA.dwSize = pdidoi->dwSize; + + switch (dwHow) { + case DIPH_BYOFFSET: { + int axis = 0; + int pov = 0; + int button = 0; + for (i = 0; i < This->user_df->dwNumObjs; i++) { + if (This->user_df->rgodf[i].dwOfs == dwObj) { + if (This->user_df->rgodf[i].pguid) + didoiA.guidType = *This->user_df->rgodf[i].pguid; + else + didoiA.guidType = GUID_NULL; + + didoiA.dwOfs = dwObj; + didoiA.dwType = This->user_df->rgodf[i].dwType; + didoiA.dwFlags = This->user_df->rgodf[i].dwFlags; + + if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_AXIS) + sprintf(didoiA.tszName, "Axis %d", axis); + else if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_POV) + sprintf(didoiA.tszName, "POV %d", pov); + else if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_BUTTON) + sprintf(didoiA.tszName, "Button %d", button); + + CopyMemory(pdidoi, &didoiA, pdidoi->dwSize); + return DI_OK; + } + + if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_AXIS) + axis++; + else if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_POV) + pov++; + else if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_BUTTON) + button++; + } + break; + } + case DIPH_BYID: + FIXME("dwHow = DIPH_BYID not implemented\n"); + break; + case DIPH_BYUSAGE: + FIXME("dwHow = DIPH_BYUSAGE not implemented\n"); + break; + default: + WARN("invalid parameter: dwHow = %08lx\n", dwHow); + return DIERR_INVALIDPARAM; + } + + CopyMemory(pdidoi, &didoiA, pdidoi->dwSize); + + return DI_OK; +} + +/****************************************************************************** + * GetDeviceInfo : get information about a device's identity + */ +HRESULT WINAPI JoystickAImpl_GetDeviceInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEINSTANCEA pdidi) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(%p,%p)\n", iface, pdidi); + + if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3A)) && + (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA))) { + WARN("invalid parameter: pdidi->dwSize = %ld != %d or %d\n", + pdidi->dwSize, sizeof(DIDEVICEINSTANCE_DX3A), + sizeof(DIDEVICEINSTANCEA)); + return DIERR_INVALIDPARAM; + } + + /* Return joystick */ + pdidi->guidInstance = GUID_Joystick; + pdidi->guidProduct = DInput_Wine_Joystick_GUID; + /* we only support traditional joysticks for now */ + pdidi->dwDevType = This->devcaps.dwDevType; + strcpy(pdidi->tszInstanceName, "Joystick"); + strcpy(pdidi->tszProductName, This->name); + if (pdidi->dwSize > sizeof(DIDEVICEINSTANCE_DX3A)) { + pdidi->guidFFDriver = GUID_NULL; + pdidi->wUsagePage = 0; + pdidi->wUsage = 0; + } + + return DI_OK; +} + +/****************************************************************************** + * GetDeviceInfo : get information about a device's identity + */ +HRESULT WINAPI JoystickWImpl_GetDeviceInfo( + LPDIRECTINPUTDEVICE8W iface, + LPDIDEVICEINSTANCEW pdidi) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(%p,%p)\n", iface, pdidi); + + if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3W)) && + (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW))) { + WARN("invalid parameter: pdidi->dwSize = %ld != %d or %d\n", + pdidi->dwSize, sizeof(DIDEVICEINSTANCE_DX3W), + sizeof(DIDEVICEINSTANCEW)); + return DIERR_INVALIDPARAM; + } + + /* Return joystick */ + pdidi->guidInstance = GUID_Joystick; + pdidi->guidProduct = DInput_Wine_Joystick_GUID; + /* we only support traditional joysticks for now */ + pdidi->dwDevType = This->devcaps.dwDevType; + MultiByteToWideChar(CP_ACP, 0, "Joystick", -1, pdidi->tszInstanceName, MAX_PATH); + MultiByteToWideChar(CP_ACP, 0, This->name, -1, pdidi->tszProductName, MAX_PATH); + if (pdidi->dwSize > sizeof(DIDEVICEINSTANCE_DX3W)) { + pdidi->guidFFDriver = GUID_NULL; + pdidi->wUsagePage = 0; + pdidi->wUsage = 0; + } + + return DI_OK; +} + +static IDirectInputDevice8AVtbl JoystickAvt = +{ + IDirectInputDevice2AImpl_QueryInterface, + IDirectInputDevice2AImpl_AddRef, + JoystickAImpl_Release, + JoystickAImpl_GetCapabilities, + JoystickAImpl_EnumObjects, + JoystickAImpl_GetProperty, + JoystickAImpl_SetProperty, + JoystickAImpl_Acquire, + JoystickAImpl_Unacquire, + JoystickAImpl_GetDeviceState, + JoystickAImpl_GetDeviceData, + JoystickAImpl_SetDataFormat, + JoystickAImpl_SetEventNotification, + IDirectInputDevice2AImpl_SetCooperativeLevel, + JoystickAImpl_GetObjectInfo, + JoystickAImpl_GetDeviceInfo, + IDirectInputDevice2AImpl_RunControlPanel, + IDirectInputDevice2AImpl_Initialize, + IDirectInputDevice2AImpl_CreateEffect, + IDirectInputDevice2AImpl_EnumEffects, + IDirectInputDevice2AImpl_GetEffectInfo, + IDirectInputDevice2AImpl_GetForceFeedbackState, + IDirectInputDevice2AImpl_SendForceFeedbackCommand, + IDirectInputDevice2AImpl_EnumCreatedEffectObjects, + IDirectInputDevice2AImpl_Escape, + JoystickAImpl_Poll, + IDirectInputDevice2AImpl_SendDeviceData, + IDirectInputDevice7AImpl_EnumEffectsInFile, + IDirectInputDevice7AImpl_WriteEffectToFile, + IDirectInputDevice8AImpl_BuildActionMap, + IDirectInputDevice8AImpl_SetActionMap, + IDirectInputDevice8AImpl_GetImageInfo +}; + +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(SysJoystickWvt.fun)) +#else +# define XCAST(fun) (void*) +#endif + +static IDirectInputDevice8WVtbl SysJoystickWvt = +{ + IDirectInputDevice2WImpl_QueryInterface, + XCAST(AddRef)IDirectInputDevice2AImpl_AddRef, + XCAST(Release)JoystickAImpl_Release, + XCAST(GetCapabilities)JoystickAImpl_GetCapabilities, + JoystickWImpl_EnumObjects, + XCAST(GetProperty)JoystickAImpl_GetProperty, + XCAST(SetProperty)JoystickAImpl_SetProperty, + XCAST(Acquire)JoystickAImpl_Acquire, + XCAST(Unacquire)JoystickAImpl_Unacquire, + XCAST(GetDeviceState)JoystickAImpl_GetDeviceState, + XCAST(GetDeviceData)JoystickAImpl_GetDeviceData, + XCAST(SetDataFormat)JoystickAImpl_SetDataFormat, + XCAST(SetEventNotification)JoystickAImpl_SetEventNotification, + XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel, + IDirectInputDevice2WImpl_GetObjectInfo, + JoystickWImpl_GetDeviceInfo, + XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel, + XCAST(Initialize)IDirectInputDevice2AImpl_Initialize, + XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect, + IDirectInputDevice2WImpl_EnumEffects, + IDirectInputDevice2WImpl_GetEffectInfo, + XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState, + XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand, + XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects, + XCAST(Escape)IDirectInputDevice2AImpl_Escape, + XCAST(Poll)JoystickAImpl_Poll, + XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData, + IDirectInputDevice7WImpl_EnumEffectsInFile, + IDirectInputDevice7WImpl_WriteEffectToFile, + IDirectInputDevice8WImpl_BuildActionMap, + IDirectInputDevice8WImpl_SetActionMap, + IDirectInputDevice8WImpl_GetImageInfo +}; +#undef XCAST + +#endif /* HAVE_LINUX_22_JOYSTICK_API */ diff --git a/reactos/lib/dinput/joystick_linuxinput.c b/reactos/lib/dinput/joystick_linuxinput.c index 673cc3852fc..18f146716a0 100644 --- a/reactos/lib/dinput/joystick_linuxinput.c +++ b/reactos/lib/dinput/joystick_linuxinput.c @@ -1,1099 +1,1099 @@ -/* DirectInput Joystick device - * - * Copyright 1998,2000 Marcus Meissner - * Copyright 1998,1999 Lionel Ulmer - * Copyright 2000-2001 TransGaming Technologies Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" -#include "wine/port.h" - -#ifdef HAVE_LINUX_INPUT_H - -#include -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif -#ifdef HAVE_SYS_TIME_H -# include -#endif -#include -#ifdef HAVE_SYS_IOCTL_H -# include -#endif -#include -#ifdef HAVE_SYS_ERRNO_H -# include -#endif - -#ifdef HAVE_CORRECT_LINUXINPUT_H - -#ifdef HAVE_LINUX_INPUT_H -# include -#endif - - -#define EVDEVPREFIX "/dev/input/event" - -#include "wine/debug.h" -#include "wine/unicode.h" -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "dinput.h" - -#include "dinput_private.h" -#include "device_private.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dinput); - -/* Wine joystick driver object instances */ -#define WINE_JOYSTICK_AXIS_BASE 0 -#define WINE_JOYSTICK_BUTTON_BASE 8 - -typedef struct JoystickImpl JoystickImpl; -static IDirectInputDevice8AVtbl JoystickAvt; -static IDirectInputDevice8WVtbl JoystickWvt; -struct JoystickImpl -{ - LPVOID lpVtbl; - DWORD ref; - GUID guid; - - - /* The 'parent' DInput */ - IDirectInputImpl *dinput; - - /* joystick private */ - /* what range and deadzone the game wants */ - LONG wantmin[ABS_MAX]; - LONG wantmax[ABS_MAX]; - LONG deadz[ABS_MAX]; - - /* autodetecting ranges per axe by following movement */ - LONG havemax[ABS_MAX]; - LONG havemin[ABS_MAX]; - - int joyfd; - - LPDIDATAFORMAT df; - HANDLE hEvent; - LPDIDEVICEOBJECTDATA data_queue; - int queue_head, queue_tail, queue_len; - BOOL overflow; - DIJOYSTATE2 js; - - /* data returned by the EVIOCGABS() ioctl */ - int axes[ABS_MAX+1][5]; - -#define AXE_ABS 0 -#define AXE_ABSMIN 1 -#define AXE_ABSMAX 2 -#define AXE_ABSFUZZ 3 -#define AXE_ABSFLAT 4 - - - /* data returned by EVIOCGBIT for EV_ABS and EV_KEY */ - BYTE absbits[(ABS_MAX+7)/8]; - BYTE keybits[(KEY_MAX+7)/8]; -}; - -/* This GUID is slightly different from the linux joystick one. Take note. */ -static GUID DInput_Wine_Joystick_GUID = { /* 9e573eda-7734-11d2-8d4a-23903fb6bdf7 */ - 0x9e573eda, - 0x7734, - 0x11d2, - {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7} -}; - -static void fake_current_js_state(JoystickImpl *ji); - -#define test_bit(arr,bit) (((BYTE*)arr)[bit>>3]&(1<<(bit&7))) - -static int joydev_have(void) -{ - int i, fd; - int havejoy = 0; - - for (i=0;i<64;i++) { - char buf[200]; - BYTE absbits[(ABS_MAX+7)/8],keybits[(KEY_MAX+7)/8]; - - sprintf(buf,EVDEVPREFIX"%d",i); - if (-1!=(fd=open(buf,O_RDONLY))) { - if (-1==ioctl(fd,EVIOCGBIT(EV_ABS,sizeof(absbits)),absbits)) { - perror("EVIOCGBIT EV_ABS"); - close(fd); - continue; - } - if (-1==ioctl(fd,EVIOCGBIT(EV_KEY,sizeof(keybits)),keybits)) { - perror("EVIOCGBIT EV_KEY"); - close(fd); - continue; - } - /* A true joystick has at least axis X and Y, and at least 1 - * button. copied from linux/drivers/input/joydev.c */ - if (test_bit(absbits,ABS_X) && test_bit(absbits,ABS_Y) && - ( test_bit(keybits,BTN_TRIGGER) || - test_bit(keybits,BTN_A) || - test_bit(keybits,BTN_1) - ) - ) { - FIXME("found a joystick at %s!\n",buf); - havejoy = 1; - } - close(fd); - } - if (havejoy || (errno==ENODEV)) - break; - } - return havejoy; -} - -static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, int version, int id) -{ - int havejoy = 0; - - if (id != 0) - return FALSE; - - if (!((dwDevType == 0) || - ((dwDevType == DIDEVTYPE_JOYSTICK) && (version < 8)) || - (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 8)))) - return FALSE; - - if (dwFlags & DIEDFL_FORCEFEEDBACK) - return FALSE; - - havejoy = joydev_have(); - - if (!havejoy) - return FALSE; - - TRACE("Enumerating the linuxinput Joystick device\n"); - - /* Return joystick */ - lpddi->guidInstance = GUID_Joystick; - lpddi->guidProduct = DInput_Wine_Joystick_GUID; - - lpddi->guidFFDriver = GUID_NULL; - if (version >= 8) - lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); - else - lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); - - strcpy(lpddi->tszInstanceName, "Joystick"); - /* ioctl JSIOCGNAME(len) */ - strcpy(lpddi->tszProductName, "Wine Joystick"); - return TRUE; -} - -static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, int version, int id) -{ - int havejoy = 0; - - if (id != 0) - return FALSE; - - if (!((dwDevType == 0) || - ((dwDevType == DIDEVTYPE_JOYSTICK) && (version < 8)) || - (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 8)))) - return FALSE; - - if (dwFlags & DIEDFL_FORCEFEEDBACK) - return FALSE; - - havejoy = joydev_have(); - - if (!havejoy) - return FALSE; - - TRACE("Enumerating the linuxinput Joystick device\n"); - - /* Return joystick */ - lpddi->guidInstance = GUID_Joystick; - lpddi->guidProduct = DInput_Wine_Joystick_GUID; - - lpddi->guidFFDriver = GUID_NULL; - if (version >= 8) - lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); - else - lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); - - MultiByteToWideChar(CP_ACP, 0, "Joystick", -1, lpddi->tszInstanceName, MAX_PATH); - /* ioctl JSIOCGNAME(len) */ - MultiByteToWideChar(CP_ACP, 0, "Wine Joystick", -1, lpddi->tszProductName, MAX_PATH); - return TRUE; -} - -static JoystickImpl *alloc_device(REFGUID rguid, LPVOID jvt, IDirectInputImpl *dinput) -{ - JoystickImpl* newDevice; - int i; - - newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl)); - newDevice->lpVtbl = jvt; - newDevice->ref = 1; - newDevice->joyfd = -1; - newDevice->dinput = dinput; - memcpy(&(newDevice->guid),rguid,sizeof(*rguid)); - for (i=0;iwantmin[i] = -32768; - newDevice->wantmax[i] = 32767; - /* TODO: - * direct input defines a default for the deadzone somewhere; but as long - * as in map_axis the code for the dead zone is commented out its no - * problem - */ - newDevice->deadz[i] = 0; - } - fake_current_js_state(newDevice); - return newDevice; -} - -static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev) -{ - int havejoy = 0; - - havejoy = joydev_have(); - - if (!havejoy) - return DIERR_DEVICENOTREG; - - if ((IsEqualGUID(&GUID_Joystick,rguid)) || - (IsEqualGUID(&DInput_Wine_Joystick_GUID,rguid))) { - if ((riid == NULL) || - IsEqualGUID(&IID_IDirectInputDeviceA,riid) || - IsEqualGUID(&IID_IDirectInputDevice2A,riid) || - IsEqualGUID(&IID_IDirectInputDevice7A,riid) || - IsEqualGUID(&IID_IDirectInputDevice8A,riid)) { - *pdev = (IDirectInputDeviceA*) alloc_device(rguid, &JoystickAvt, dinput); - TRACE("Creating a Joystick device (%p)\n", *pdev); - return DI_OK; - } else - return DIERR_NOINTERFACE; - } - - return DIERR_DEVICENOTREG; -} - - -static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev) -{ - int havejoy = 0; - - havejoy = joydev_have(); - - if (!havejoy) - return DIERR_DEVICENOTREG; - - if ((IsEqualGUID(&GUID_Joystick,rguid)) || - (IsEqualGUID(&DInput_Wine_Joystick_GUID,rguid))) { - if ((riid == NULL) || - IsEqualGUID(&IID_IDirectInputDeviceW,riid) || - IsEqualGUID(&IID_IDirectInputDevice2W,riid) || - IsEqualGUID(&IID_IDirectInputDevice7W,riid) || - IsEqualGUID(&IID_IDirectInputDevice8W,riid)) { - *pdev = (IDirectInputDeviceW*) alloc_device(rguid, &JoystickWvt, dinput); - TRACE("Creating a Joystick device (%p)\n", *pdev); - return DI_OK; - } else - return DIERR_NOINTERFACE; - } - - return DIERR_DEVICENOTREG; -} - -static dinput_device joydev = { - 20, - "Wine Linux-input joystick driver", - joydev_enum_deviceA, - joydev_enum_deviceW, - joydev_create_deviceA, - joydev_create_deviceW -}; - -DECL_GLOBAL_CONSTRUCTOR(joydev_register) { dinput_register_device(&joydev); } - -/****************************************************************************** - * Joystick - */ -static ULONG WINAPI JoystickAImpl_Release(LPDIRECTINPUTDEVICE8A iface) -{ - JoystickImpl *This = (JoystickImpl *)iface; - ULONG ref; - - ref = InterlockedDecrement(&(This->ref)); - if (ref) - return ref; - - /* Free the data queue */ - HeapFree(GetProcessHeap(),0,This->data_queue); - - /* Free the DataFormat */ - HeapFree(GetProcessHeap(), 0, This->df); - - HeapFree(GetProcessHeap(),0,This); - return 0; -} - -/****************************************************************************** - * SetDataFormat : the application can choose the format of the data - * the device driver sends back with GetDeviceState. - */ -static HRESULT WINAPI JoystickAImpl_SetDataFormat( - LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df -) -{ - JoystickImpl *This = (JoystickImpl *)iface; - - TRACE("(this=%p,%p)\n",This,df); - - _dump_DIDATAFORMAT(df); - - /* Store the new data format */ - This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize); - memcpy(This->df, df, df->dwSize); - This->df->rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize); - memcpy(This->df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize); - - return 0; -} - -/****************************************************************************** - * Acquire : gets exclusive control of the joystick - */ -static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) -{ - int i; - JoystickImpl *This = (JoystickImpl *)iface; - char buf[200]; - - TRACE("(this=%p)\n",This); - if (This->joyfd!=-1) - return 0; - for (i=0;i<64;i++) { - sprintf(buf,EVDEVPREFIX"%d",i); - if (-1==(This->joyfd=open(buf,O_RDONLY))) { - if (errno==ENODEV) - return DIERR_NOTFOUND; - perror(buf); - continue; - } - if ((-1!=ioctl(This->joyfd,EVIOCGBIT(EV_ABS,sizeof(This->absbits)),This->absbits)) && - (-1!=ioctl(This->joyfd,EVIOCGBIT(EV_KEY,sizeof(This->keybits)),This->keybits)) && - (test_bit(This->absbits,ABS_X) && test_bit(This->absbits,ABS_Y) && - (test_bit(This->keybits,BTN_TRIGGER)|| - test_bit(This->keybits,BTN_A) || - test_bit(This->keybits,BTN_1) - ) - ) - ) - break; - close(This->joyfd); - This->joyfd = -1; - } - if (This->joyfd==-1) - return DIERR_NOTFOUND; - - for (i=0;iabsbits,i)) { - if (-1==ioctl(This->joyfd,EVIOCGABS(i),&(This->axes[i]))) - continue; - FIXME("axe %d: cur=%d, min=%d, max=%d, fuzz=%d, flat=%d\n", - i, - This->axes[i][AXE_ABS], - This->axes[i][AXE_ABSMIN], - This->axes[i][AXE_ABSMAX], - This->axes[i][AXE_ABSFUZZ], - This->axes[i][AXE_ABSFLAT] - ); - This->havemin[i] = This->axes[i][AXE_ABSMIN]; - This->havemax[i] = This->axes[i][AXE_ABSMAX]; - } - } - MESSAGE("\n"); - - fake_current_js_state(This); - - return 0; -} - -/****************************************************************************** - * Unacquire : frees the joystick - */ -static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) -{ - JoystickImpl *This = (JoystickImpl *)iface; - - TRACE("(this=%p)\n",This); - if (This->joyfd!=-1) { - close(This->joyfd); - This->joyfd = -1; - return DI_OK; - } - else - return DI_NOEFFECT; -} - -/* - * This maps the read value (from the input event) to a value in the - * 'wanted' range. It also autodetects the possible range of the axe and - * adapts values accordingly. - */ -static int -map_axis(JoystickImpl* This, int axis, int val) { - int xmin = This->axes[axis][AXE_ABSMIN]; - int xmax = This->axes[axis][AXE_ABSMAX]; - int hmax = This->havemax[axis]; - int hmin = This->havemin[axis]; - int wmin = This->wantmin[axis]; - int wmax = This->wantmax[axis]; - int ret; - - if (val > hmax) This->havemax[axis] = hmax = val; - if (val < hmin) This->havemin[axis] = hmin = val; - - if (xmin == xmax) return val; - - /* map the value from the hmin-hmax range into the wmin-wmax range */ - ret = (val * (wmax-wmin)) / (hmax-hmin) + wmin; - -#if 0 - /* deadzone doesn't work comfortably enough right now. needs more testing*/ - if ((ret > -deadz/2 ) && (ret < deadz/2)) { - FIXME("%d in deadzone, return mid.\n",val); - return (wmax-wmin)/2+wmin; - } -#endif - return ret; -} - -/* - * set the current state of the js device as it would be with the middle - * values on the axes - */ -static void fake_current_js_state(JoystickImpl *ji) -{ - ji->js.lX = map_axis(ji, ABS_X, ji->axes[ABS_X ][AXE_ABS]); - ji->js.lY = map_axis(ji, ABS_Y, ji->axes[ABS_Y ][AXE_ABS]); - ji->js.lZ = map_axis(ji, ABS_Z, ji->axes[ABS_Z ][AXE_ABS]); - ji->js.lRx = map_axis(ji, ABS_RX, ji->axes[ABS_RX][AXE_ABS]); - ji->js.lRy = map_axis(ji, ABS_RY, ji->axes[ABS_RY][AXE_ABS]); - ji->js.lRz = map_axis(ji, ABS_RZ, ji->axes[ABS_RZ][AXE_ABS]); -} - -static void joy_polldev(JoystickImpl *This) { - struct timeval tv; - fd_set readfds; - struct input_event ie; - - if (This->joyfd==-1) - return; - - while (1) { - memset(&tv,0,sizeof(tv)); - FD_ZERO(&readfds); - FD_SET(This->joyfd,&readfds); - - if (1>select(This->joyfd+1,&readfds,NULL,NULL,&tv)) - return; - - /* we have one event, so we can read */ - if (sizeof(ie)!=read(This->joyfd,&ie,sizeof(ie))) - return; - - TRACE("input_event: type %d, code %d, value %d\n",ie.type,ie.code,ie.value); - switch (ie.type) { - case EV_KEY: /* button */ - switch (ie.code) { - case BTN_TRIGGER: /* normal flight stick */ - case BTN_A: /* gamepad */ - case BTN_1: /* generic */ - This->js.rgbButtons[0] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(0),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case BTN_THUMB: - case BTN_B: - case BTN_2: - This->js.rgbButtons[1] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(1),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case BTN_THUMB2: - case BTN_C: - case BTN_3: - This->js.rgbButtons[2] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(2),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case BTN_TOP: - case BTN_X: - case BTN_4: - This->js.rgbButtons[3] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(3),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case BTN_TOP2: - case BTN_Y: - case BTN_5: - This->js.rgbButtons[4] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(4),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case BTN_PINKIE: - case BTN_Z: - case BTN_6: - This->js.rgbButtons[5] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(5),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case BTN_BASE: - case BTN_TL: - case BTN_7: - This->js.rgbButtons[6] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(6),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case BTN_BASE2: - case BTN_TR: - case BTN_8: - This->js.rgbButtons[7] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(7),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case BTN_BASE3: - case BTN_TL2: - case BTN_9: - This->js.rgbButtons[8] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(8),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case BTN_BASE4: - case BTN_TR2: - This->js.rgbButtons[9] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(9),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case BTN_BASE5: - case BTN_SELECT: - This->js.rgbButtons[10] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(10),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - default: - FIXME("unhandled joystick button %x, value %d\n",ie.code,ie.value); - break; - } - break; - case EV_ABS: - switch (ie.code) { - case ABS_X: - This->js.lX = map_axis(This,ABS_X,ie.value); - GEN_EVENT(DIJOFS_X,This->js.lX,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case ABS_Y: - This->js.lY = map_axis(This,ABS_Y,ie.value); - GEN_EVENT(DIJOFS_Y,This->js.lY,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case ABS_Z: - This->js.lZ = map_axis(This,ABS_Z,ie.value); - GEN_EVENT(DIJOFS_Z,This->js.lZ,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case ABS_RX: - This->js.lRx = map_axis(This,ABS_RX,ie.value); - GEN_EVENT(DIJOFS_RX,This->js.lRx,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case ABS_RY: - This->js.lRy = map_axis(This,ABS_RY,ie.value); - GEN_EVENT(DIJOFS_RY,This->js.lRy,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case ABS_RZ: - This->js.lRz = map_axis(This,ABS_RZ,ie.value); - GEN_EVENT(DIJOFS_RZ,This->js.lRz,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - default: - FIXME("unhandled joystick axe event (code %d, value %d)\n",ie.code,ie.value); - break; - } - break; - default: - FIXME("joystick cannot handle type %d event (code %d)\n",ie.type,ie.code); - break; - } - } -} - -/****************************************************************************** - * GetDeviceState : returns the "state" of the joystick. - * - */ -static HRESULT WINAPI JoystickAImpl_GetDeviceState( - LPDIRECTINPUTDEVICE8A iface,DWORD len,LPVOID ptr -) { - JoystickImpl *This = (JoystickImpl *)iface; - - joy_polldev(This); - - TRACE("(this=%p,0x%08lx,%p)\n",This,len,ptr); - if ((len != sizeof(DIJOYSTATE)) && (len != sizeof(DIJOYSTATE2))) { - FIXME("len %ld is not sizeof(DIJOYSTATE) or DIJOYSTATE2, unsupported format.\n",len); - return E_FAIL; - } - memcpy(ptr,&(This->js),len); - This->queue_head = 0; - This->queue_tail = 0; - return 0; -} - -/****************************************************************************** - * GetDeviceData : gets buffered input data. - */ -static HRESULT WINAPI JoystickAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface, - DWORD dodsize, - LPDIDEVICEOBJECTDATA dod, - LPDWORD entries, - DWORD flags -) { - JoystickImpl *This = (JoystickImpl *)iface; - - FIXME("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx),STUB!\n",This,dodsize,*entries,flags); - - joy_polldev(This); - if (flags & DIGDD_PEEK) - FIXME("DIGDD_PEEK\n"); - - if (dod == NULL) { - } else { - } - return 0; -} - -/****************************************************************************** - * SetProperty : change input device properties - */ -static HRESULT WINAPI JoystickAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface, - REFGUID rguid, - LPCDIPROPHEADER ph) -{ - JoystickImpl *This = (JoystickImpl *)iface; - - FIXME("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph); - FIXME("ph.dwSize = %ld, ph.dwHeaderSize =%ld, ph.dwObj = %ld, ph.dwHow= %ld\n",ph->dwSize, ph->dwHeaderSize,ph->dwObj,ph->dwHow); - - if (!HIWORD(rguid)) { - switch ((DWORD)rguid) { - case (DWORD) DIPROP_BUFFERSIZE: { - LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; - - FIXME("buffersize = %ld\n",pd->dwData); - break; - } - case (DWORD)DIPROP_RANGE: { - LPCDIPROPRANGE pr = (LPCDIPROPRANGE)ph; - - FIXME("proprange(%ld,%ld)\n",pr->lMin,pr->lMax); - switch (ph->dwObj) { - case 0: /* X */ - case 4: /* Y */ - case 8: /* Z */ - case 12: /* Rx */ - case 16: /* Ry */ - case 20: /* Rz */ - This->wantmin[ph->dwObj/4] = pr->lMin; - This->wantmax[ph->dwObj/4] = pr->lMax; - break; - default: - FIXME("setting proprange %ld - %ld for dwObj %ld\n",pr->lMin,pr->lMax,ph->dwObj); - } - break; - } - case (DWORD)DIPROP_DEADZONE: { - LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; - - FIXME("setting deadzone(%ld)\n",pd->dwData); - This->deadz[ph->dwObj/4] = pd->dwData; - break; - } - default: - FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); - break; - } - } - fake_current_js_state(This); - return 0; -} - -/****************************************************************************** - * SetEventNotification : specifies event to be sent on state change - */ -static HRESULT WINAPI JoystickAImpl_SetEventNotification( - LPDIRECTINPUTDEVICE8A iface, HANDLE hnd -) { - JoystickImpl *This = (JoystickImpl *)iface; - - TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd); - This->hEvent = hnd; - return DI_OK; -} - -static HRESULT WINAPI JoystickAImpl_GetCapabilities( - LPDIRECTINPUTDEVICE8A iface, - LPDIDEVCAPS lpDIDevCaps) -{ - JoystickImpl *This = (JoystickImpl *)iface; - int xfd = This->joyfd; - int i,axes,buttons; - int wasacquired = 1; - - TRACE("%p->(%p)\n",iface,lpDIDevCaps); - if (xfd==-1) { - /* yes, games assume we return something, even if unacquired */ - JoystickAImpl_Acquire(iface); - xfd = This->joyfd; - wasacquired = 0; - } - lpDIDevCaps->dwFlags = DIDC_ATTACHED; - if (This->dinput->version >= 8) - lpDIDevCaps->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); - else - lpDIDevCaps->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); - - axes=0; - for (i=0;iabsbits,i)) axes++; - buttons=0; - for (i=0;ikeybits,i)) buttons++; - - lpDIDevCaps->dwAxes = axes; - lpDIDevCaps->dwButtons = buttons; - - if (!wasacquired) - JoystickAImpl_Unacquire(iface); - - return DI_OK; -} - -static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE8A iface) { - JoystickImpl *This = (JoystickImpl *)iface; - TRACE("(),stub!\n"); - - joy_polldev(This); - return DI_OK; -} - -/****************************************************************************** - * EnumObjects : enumerate the different buttons and axis... - */ -static HRESULT WINAPI JoystickAImpl_EnumObjects( - LPDIRECTINPUTDEVICE8A iface, - LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, - LPVOID lpvRef, - DWORD dwFlags) -{ - JoystickImpl *This = (JoystickImpl *)iface; - DIDEVICEOBJECTINSTANCEA ddoi; - int xfd = This->joyfd; - - - TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags); - if (TRACE_ON(dinput)) { - TRACE(" - flags = "); - _dump_EnumObjects_flags(dwFlags); - TRACE("\n"); - } - - if (xfd == -1) return DIERR_NOTACQUIRED; - - /* Only the fields till dwFFMaxForce are relevant */ - ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce); - - /* For the joystick, do as is done in the GetCapabilities function */ - /* FIXME: needs more items */ - if ((dwFlags == DIDFT_ALL) || - (dwFlags & DIDFT_AXIS)) { - BYTE i; - - for (i = 0; i < ABS_MAX; i++) { - if (!test_bit(This->absbits,i)) continue; - - switch (i) { - case ABS_X: - ddoi.guidType = GUID_XAxis; - ddoi.dwOfs = DIJOFS_X; - break; - case ABS_Y: - ddoi.guidType = GUID_YAxis; - ddoi.dwOfs = DIJOFS_Y; - break; - case ABS_Z: - ddoi.guidType = GUID_ZAxis; - ddoi.dwOfs = DIJOFS_Z; - break; - case ABS_RX: - ddoi.guidType = GUID_RxAxis; - ddoi.dwOfs = DIJOFS_RX; - break; - case ABS_RY: - ddoi.guidType = GUID_RyAxis; - ddoi.dwOfs = DIJOFS_RY; - break; - case ABS_RZ: - ddoi.guidType = GUID_RzAxis; - ddoi.dwOfs = DIJOFS_RZ; - break; - case ABS_THROTTLE: - ddoi.guidType = GUID_Slider; - ddoi.dwOfs = DIJOFS_SLIDER(0); - break; - default: - FIXME("unhandled abs axis %d, ignoring!\n",i); - } - ddoi.dwType = DIDFT_MAKEINSTANCE((1<keybits,i)) continue; - - switch (i) { - case BTN_TRIGGER: - case BTN_A: - case BTN_1: - ddoi.dwOfs = DIJOFS_BUTTON(0); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 0) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - case BTN_THUMB: - case BTN_B: - case BTN_2: - ddoi.dwOfs = DIJOFS_BUTTON(1); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 1) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - case BTN_THUMB2: - case BTN_C: - case BTN_3: - ddoi.dwOfs = DIJOFS_BUTTON(2); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 2) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - case BTN_TOP: - case BTN_X: - case BTN_4: - ddoi.dwOfs = DIJOFS_BUTTON(3); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 3) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - case BTN_TOP2: - case BTN_Y: - case BTN_5: - ddoi.dwOfs = DIJOFS_BUTTON(4); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 4) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - case BTN_PINKIE: - case BTN_Z: - case BTN_6: - ddoi.dwOfs = DIJOFS_BUTTON(5); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 5) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - case BTN_BASE: - case BTN_TL: - case BTN_7: - ddoi.dwOfs = DIJOFS_BUTTON(6); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 6) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - case BTN_BASE2: - case BTN_TR: - case BTN_8: - ddoi.dwOfs = DIJOFS_BUTTON(7); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 7) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - case BTN_BASE3: - case BTN_TL2: - case BTN_9: - ddoi.dwOfs = DIJOFS_BUTTON(8); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 8) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - case BTN_BASE4: - case BTN_TR2: - ddoi.dwOfs = DIJOFS_BUTTON(9); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 9) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - case BTN_BASE5: - case BTN_SELECT: - ddoi.dwOfs = DIJOFS_BUTTON(10); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 10) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - } - sprintf(ddoi.tszName, "%d-Button", i); - _dump_OBJECTINSTANCEA(&ddoi); - if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) - return DI_OK; - } - } - - if (xfd!=This->joyfd) - close(xfd); - - return DI_OK; -} - -static HRESULT WINAPI JoystickWImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface, - LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, - LPVOID lpvRef, - DWORD dwFlags) -{ - JoystickImpl *This = (JoystickImpl *)iface; - - device_enumobjects_AtoWcb_data data; - - data.lpCallBack = lpCallback; - data.lpvRef = lpvRef; - - return JoystickAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags); -} - -/****************************************************************************** - * GetProperty : get input device properties - */ -static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, - REFGUID rguid, - LPDIPROPHEADER pdiph) -{ - JoystickImpl *This = (JoystickImpl *)iface; - - TRACE("(this=%p,%s,%p): stub!\n", - iface, debugstr_guid(rguid), pdiph); - - if (TRACE_ON(dinput)) - _dump_DIPROPHEADER(pdiph); - - if (!HIWORD(rguid)) { - switch ((DWORD)rguid) { - case (DWORD) DIPROP_BUFFERSIZE: { - LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; - - TRACE(" return buffersize = %d\n",This->queue_len); - pd->dwData = This->queue_len; - break; - } - - case (DWORD) DIPROP_RANGE: { - /* LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph; */ - if ((pdiph->dwHow == DIPH_BYID) && - (pdiph->dwObj & DIDFT_ABSAXIS)) { - /* The app is querying the current range of the axis : return the lMin and lMax values */ - FIXME("unimplemented axis range query.\n"); - } - - break; - } - - default: - FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); - break; - } - } - - - return DI_OK; -} - -static IDirectInputDevice8AVtbl JoystickAvt = -{ - IDirectInputDevice2AImpl_QueryInterface, - IDirectInputDevice2AImpl_AddRef, - JoystickAImpl_Release, - JoystickAImpl_GetCapabilities, - JoystickAImpl_EnumObjects, - JoystickAImpl_GetProperty, - JoystickAImpl_SetProperty, - JoystickAImpl_Acquire, - JoystickAImpl_Unacquire, - JoystickAImpl_GetDeviceState, - JoystickAImpl_GetDeviceData, - JoystickAImpl_SetDataFormat, - JoystickAImpl_SetEventNotification, - IDirectInputDevice2AImpl_SetCooperativeLevel, - IDirectInputDevice2AImpl_GetObjectInfo, - IDirectInputDevice2AImpl_GetDeviceInfo, - IDirectInputDevice2AImpl_RunControlPanel, - IDirectInputDevice2AImpl_Initialize, - IDirectInputDevice2AImpl_CreateEffect, - IDirectInputDevice2AImpl_EnumEffects, - IDirectInputDevice2AImpl_GetEffectInfo, - IDirectInputDevice2AImpl_GetForceFeedbackState, - IDirectInputDevice2AImpl_SendForceFeedbackCommand, - IDirectInputDevice2AImpl_EnumCreatedEffectObjects, - IDirectInputDevice2AImpl_Escape, - JoystickAImpl_Poll, - IDirectInputDevice2AImpl_SendDeviceData, - IDirectInputDevice7AImpl_EnumEffectsInFile, - IDirectInputDevice7AImpl_WriteEffectToFile, - IDirectInputDevice8AImpl_BuildActionMap, - IDirectInputDevice8AImpl_SetActionMap, - IDirectInputDevice8AImpl_GetImageInfo -}; - -#if !defined(__STRICT_ANSI__) && defined(__GNUC__) -# define XCAST(fun) (typeof(JoystickWvt.fun)) -#else -# define XCAST(fun) (void*) -#endif - -static IDirectInputDevice8WVtbl JoystickWvt = -{ - IDirectInputDevice2WImpl_QueryInterface, - XCAST(AddRef)IDirectInputDevice2AImpl_AddRef, - XCAST(Release)JoystickAImpl_Release, - XCAST(GetCapabilities)JoystickAImpl_GetCapabilities, - JoystickWImpl_EnumObjects, - XCAST(GetProperty)JoystickAImpl_GetProperty, - XCAST(SetProperty)JoystickAImpl_SetProperty, - XCAST(Acquire)JoystickAImpl_Acquire, - XCAST(Unacquire)JoystickAImpl_Unacquire, - XCAST(GetDeviceState)JoystickAImpl_GetDeviceState, - XCAST(GetDeviceData)JoystickAImpl_GetDeviceData, - XCAST(SetDataFormat)JoystickAImpl_SetDataFormat, - XCAST(SetEventNotification)JoystickAImpl_SetEventNotification, - XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel, - IDirectInputDevice2WImpl_GetObjectInfo, - IDirectInputDevice2WImpl_GetDeviceInfo, - XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel, - XCAST(Initialize)IDirectInputDevice2AImpl_Initialize, - XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect, - IDirectInputDevice2WImpl_EnumEffects, - IDirectInputDevice2WImpl_GetEffectInfo, - XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState, - XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand, - XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects, - XCAST(Escape)IDirectInputDevice2AImpl_Escape, - XCAST(Poll)JoystickAImpl_Poll, - XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData, - IDirectInputDevice7WImpl_EnumEffectsInFile, - IDirectInputDevice7WImpl_WriteEffectToFile, - IDirectInputDevice8WImpl_BuildActionMap, - IDirectInputDevice8WImpl_SetActionMap, - IDirectInputDevice8WImpl_GetImageInfo -}; -#undef XCAST - -#endif /* HAVE_LINUX_INPUT_H */ - -#endif +/* DirectInput Joystick device + * + * Copyright 1998,2000 Marcus Meissner + * Copyright 1998,1999 Lionel Ulmer + * Copyright 2000-2001 TransGaming Technologies Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "wine/port.h" + +#ifdef HAVE_LINUX_INPUT_H + +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#ifdef HAVE_SYS_TIME_H +# include +#endif +#include +#ifdef HAVE_SYS_IOCTL_H +# include +#endif +#include +#ifdef HAVE_SYS_ERRNO_H +# include +#endif + +#ifdef HAVE_CORRECT_LINUXINPUT_H + +#ifdef HAVE_LINUX_INPUT_H +# include +#endif + + +#define EVDEVPREFIX "/dev/input/event" + +#include "wine/debug.h" +#include "wine/unicode.h" +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "dinput.h" + +#include "dinput_private.h" +#include "device_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dinput); + +/* Wine joystick driver object instances */ +#define WINE_JOYSTICK_AXIS_BASE 0 +#define WINE_JOYSTICK_BUTTON_BASE 8 + +typedef struct JoystickImpl JoystickImpl; +static IDirectInputDevice8AVtbl JoystickAvt; +static IDirectInputDevice8WVtbl JoystickWvt; +struct JoystickImpl +{ + LPVOID lpVtbl; + DWORD ref; + GUID guid; + + + /* The 'parent' DInput */ + IDirectInputImpl *dinput; + + /* joystick private */ + /* what range and deadzone the game wants */ + LONG wantmin[ABS_MAX]; + LONG wantmax[ABS_MAX]; + LONG deadz[ABS_MAX]; + + /* autodetecting ranges per axe by following movement */ + LONG havemax[ABS_MAX]; + LONG havemin[ABS_MAX]; + + int joyfd; + + LPDIDATAFORMAT df; + HANDLE hEvent; + LPDIDEVICEOBJECTDATA data_queue; + int queue_head, queue_tail, queue_len; + BOOL overflow; + DIJOYSTATE2 js; + + /* data returned by the EVIOCGABS() ioctl */ + int axes[ABS_MAX+1][5]; + +#define AXE_ABS 0 +#define AXE_ABSMIN 1 +#define AXE_ABSMAX 2 +#define AXE_ABSFUZZ 3 +#define AXE_ABSFLAT 4 + + + /* data returned by EVIOCGBIT for EV_ABS and EV_KEY */ + BYTE absbits[(ABS_MAX+7)/8]; + BYTE keybits[(KEY_MAX+7)/8]; +}; + +/* This GUID is slightly different from the linux joystick one. Take note. */ +static GUID DInput_Wine_Joystick_GUID = { /* 9e573eda-7734-11d2-8d4a-23903fb6bdf7 */ + 0x9e573eda, + 0x7734, + 0x11d2, + {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7} +}; + +static void fake_current_js_state(JoystickImpl *ji); + +#define test_bit(arr,bit) (((BYTE*)arr)[bit>>3]&(1<<(bit&7))) + +static int joydev_have(void) +{ + int i, fd; + int havejoy = 0; + + for (i=0;i<64;i++) { + char buf[200]; + BYTE absbits[(ABS_MAX+7)/8],keybits[(KEY_MAX+7)/8]; + + sprintf(buf,EVDEVPREFIX"%d",i); + if (-1!=(fd=open(buf,O_RDONLY))) { + if (-1==ioctl(fd,EVIOCGBIT(EV_ABS,sizeof(absbits)),absbits)) { + perror("EVIOCGBIT EV_ABS"); + close(fd); + continue; + } + if (-1==ioctl(fd,EVIOCGBIT(EV_KEY,sizeof(keybits)),keybits)) { + perror("EVIOCGBIT EV_KEY"); + close(fd); + continue; + } + /* A true joystick has at least axis X and Y, and at least 1 + * button. copied from linux/drivers/input/joydev.c */ + if (test_bit(absbits,ABS_X) && test_bit(absbits,ABS_Y) && + ( test_bit(keybits,BTN_TRIGGER) || + test_bit(keybits,BTN_A) || + test_bit(keybits,BTN_1) + ) + ) { + FIXME("found a joystick at %s!\n",buf); + havejoy = 1; + } + close(fd); + } + if (havejoy || (errno==ENODEV)) + break; + } + return havejoy; +} + +static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, int version, int id) +{ + int havejoy = 0; + + if (id != 0) + return FALSE; + + if (!((dwDevType == 0) || + ((dwDevType == DIDEVTYPE_JOYSTICK) && (version < 8)) || + (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 8)))) + return FALSE; + + if (dwFlags & DIEDFL_FORCEFEEDBACK) + return FALSE; + + havejoy = joydev_have(); + + if (!havejoy) + return FALSE; + + TRACE("Enumerating the linuxinput Joystick device\n"); + + /* Return joystick */ + lpddi->guidInstance = GUID_Joystick; + lpddi->guidProduct = DInput_Wine_Joystick_GUID; + + lpddi->guidFFDriver = GUID_NULL; + if (version >= 8) + lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); + else + lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); + + strcpy(lpddi->tszInstanceName, "Joystick"); + /* ioctl JSIOCGNAME(len) */ + strcpy(lpddi->tszProductName, "Wine Joystick"); + return TRUE; +} + +static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, int version, int id) +{ + int havejoy = 0; + + if (id != 0) + return FALSE; + + if (!((dwDevType == 0) || + ((dwDevType == DIDEVTYPE_JOYSTICK) && (version < 8)) || + (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 8)))) + return FALSE; + + if (dwFlags & DIEDFL_FORCEFEEDBACK) + return FALSE; + + havejoy = joydev_have(); + + if (!havejoy) + return FALSE; + + TRACE("Enumerating the linuxinput Joystick device\n"); + + /* Return joystick */ + lpddi->guidInstance = GUID_Joystick; + lpddi->guidProduct = DInput_Wine_Joystick_GUID; + + lpddi->guidFFDriver = GUID_NULL; + if (version >= 8) + lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); + else + lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); + + MultiByteToWideChar(CP_ACP, 0, "Joystick", -1, lpddi->tszInstanceName, MAX_PATH); + /* ioctl JSIOCGNAME(len) */ + MultiByteToWideChar(CP_ACP, 0, "Wine Joystick", -1, lpddi->tszProductName, MAX_PATH); + return TRUE; +} + +static JoystickImpl *alloc_device(REFGUID rguid, LPVOID jvt, IDirectInputImpl *dinput) +{ + JoystickImpl* newDevice; + int i; + + newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl)); + newDevice->lpVtbl = jvt; + newDevice->ref = 1; + newDevice->joyfd = -1; + newDevice->dinput = dinput; + memcpy(&(newDevice->guid),rguid,sizeof(*rguid)); + for (i=0;iwantmin[i] = -32768; + newDevice->wantmax[i] = 32767; + /* TODO: + * direct input defines a default for the deadzone somewhere; but as long + * as in map_axis the code for the dead zone is commented out its no + * problem + */ + newDevice->deadz[i] = 0; + } + fake_current_js_state(newDevice); + return newDevice; +} + +static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev) +{ + int havejoy = 0; + + havejoy = joydev_have(); + + if (!havejoy) + return DIERR_DEVICENOTREG; + + if ((IsEqualGUID(&GUID_Joystick,rguid)) || + (IsEqualGUID(&DInput_Wine_Joystick_GUID,rguid))) { + if ((riid == NULL) || + IsEqualGUID(&IID_IDirectInputDeviceA,riid) || + IsEqualGUID(&IID_IDirectInputDevice2A,riid) || + IsEqualGUID(&IID_IDirectInputDevice7A,riid) || + IsEqualGUID(&IID_IDirectInputDevice8A,riid)) { + *pdev = (IDirectInputDeviceA*) alloc_device(rguid, &JoystickAvt, dinput); + TRACE("Creating a Joystick device (%p)\n", *pdev); + return DI_OK; + } else + return DIERR_NOINTERFACE; + } + + return DIERR_DEVICENOTREG; +} + + +static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev) +{ + int havejoy = 0; + + havejoy = joydev_have(); + + if (!havejoy) + return DIERR_DEVICENOTREG; + + if ((IsEqualGUID(&GUID_Joystick,rguid)) || + (IsEqualGUID(&DInput_Wine_Joystick_GUID,rguid))) { + if ((riid == NULL) || + IsEqualGUID(&IID_IDirectInputDeviceW,riid) || + IsEqualGUID(&IID_IDirectInputDevice2W,riid) || + IsEqualGUID(&IID_IDirectInputDevice7W,riid) || + IsEqualGUID(&IID_IDirectInputDevice8W,riid)) { + *pdev = (IDirectInputDeviceW*) alloc_device(rguid, &JoystickWvt, dinput); + TRACE("Creating a Joystick device (%p)\n", *pdev); + return DI_OK; + } else + return DIERR_NOINTERFACE; + } + + return DIERR_DEVICENOTREG; +} + +static dinput_device joydev = { + 20, + "Wine Linux-input joystick driver", + joydev_enum_deviceA, + joydev_enum_deviceW, + joydev_create_deviceA, + joydev_create_deviceW +}; + +DECL_GLOBAL_CONSTRUCTOR(joydev_register) { dinput_register_device(&joydev); } + +/****************************************************************************** + * Joystick + */ +static ULONG WINAPI JoystickAImpl_Release(LPDIRECTINPUTDEVICE8A iface) +{ + JoystickImpl *This = (JoystickImpl *)iface; + ULONG ref; + + ref = InterlockedDecrement(&(This->ref)); + if (ref) + return ref; + + /* Free the data queue */ + HeapFree(GetProcessHeap(),0,This->data_queue); + + /* Free the DataFormat */ + HeapFree(GetProcessHeap(), 0, This->df); + + HeapFree(GetProcessHeap(),0,This); + return 0; +} + +/****************************************************************************** + * SetDataFormat : the application can choose the format of the data + * the device driver sends back with GetDeviceState. + */ +static HRESULT WINAPI JoystickAImpl_SetDataFormat( + LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df +) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(this=%p,%p)\n",This,df); + + _dump_DIDATAFORMAT(df); + + /* Store the new data format */ + This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize); + memcpy(This->df, df, df->dwSize); + This->df->rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize); + memcpy(This->df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize); + + return 0; +} + +/****************************************************************************** + * Acquire : gets exclusive control of the joystick + */ +static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) +{ + int i; + JoystickImpl *This = (JoystickImpl *)iface; + char buf[200]; + + TRACE("(this=%p)\n",This); + if (This->joyfd!=-1) + return 0; + for (i=0;i<64;i++) { + sprintf(buf,EVDEVPREFIX"%d",i); + if (-1==(This->joyfd=open(buf,O_RDONLY))) { + if (errno==ENODEV) + return DIERR_NOTFOUND; + perror(buf); + continue; + } + if ((-1!=ioctl(This->joyfd,EVIOCGBIT(EV_ABS,sizeof(This->absbits)),This->absbits)) && + (-1!=ioctl(This->joyfd,EVIOCGBIT(EV_KEY,sizeof(This->keybits)),This->keybits)) && + (test_bit(This->absbits,ABS_X) && test_bit(This->absbits,ABS_Y) && + (test_bit(This->keybits,BTN_TRIGGER)|| + test_bit(This->keybits,BTN_A) || + test_bit(This->keybits,BTN_1) + ) + ) + ) + break; + close(This->joyfd); + This->joyfd = -1; + } + if (This->joyfd==-1) + return DIERR_NOTFOUND; + + for (i=0;iabsbits,i)) { + if (-1==ioctl(This->joyfd,EVIOCGABS(i),&(This->axes[i]))) + continue; + FIXME("axe %d: cur=%d, min=%d, max=%d, fuzz=%d, flat=%d\n", + i, + This->axes[i][AXE_ABS], + This->axes[i][AXE_ABSMIN], + This->axes[i][AXE_ABSMAX], + This->axes[i][AXE_ABSFUZZ], + This->axes[i][AXE_ABSFLAT] + ); + This->havemin[i] = This->axes[i][AXE_ABSMIN]; + This->havemax[i] = This->axes[i][AXE_ABSMAX]; + } + } + MESSAGE("\n"); + + fake_current_js_state(This); + + return 0; +} + +/****************************************************************************** + * Unacquire : frees the joystick + */ +static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(this=%p)\n",This); + if (This->joyfd!=-1) { + close(This->joyfd); + This->joyfd = -1; + return DI_OK; + } + else + return DI_NOEFFECT; +} + +/* + * This maps the read value (from the input event) to a value in the + * 'wanted' range. It also autodetects the possible range of the axe and + * adapts values accordingly. + */ +static int +map_axis(JoystickImpl* This, int axis, int val) { + int xmin = This->axes[axis][AXE_ABSMIN]; + int xmax = This->axes[axis][AXE_ABSMAX]; + int hmax = This->havemax[axis]; + int hmin = This->havemin[axis]; + int wmin = This->wantmin[axis]; + int wmax = This->wantmax[axis]; + int ret; + + if (val > hmax) This->havemax[axis] = hmax = val; + if (val < hmin) This->havemin[axis] = hmin = val; + + if (xmin == xmax) return val; + + /* map the value from the hmin-hmax range into the wmin-wmax range */ + ret = (val * (wmax-wmin)) / (hmax-hmin) + wmin; + +#if 0 + /* deadzone doesn't work comfortably enough right now. needs more testing*/ + if ((ret > -deadz/2 ) && (ret < deadz/2)) { + FIXME("%d in deadzone, return mid.\n",val); + return (wmax-wmin)/2+wmin; + } +#endif + return ret; +} + +/* + * set the current state of the js device as it would be with the middle + * values on the axes + */ +static void fake_current_js_state(JoystickImpl *ji) +{ + ji->js.lX = map_axis(ji, ABS_X, ji->axes[ABS_X ][AXE_ABS]); + ji->js.lY = map_axis(ji, ABS_Y, ji->axes[ABS_Y ][AXE_ABS]); + ji->js.lZ = map_axis(ji, ABS_Z, ji->axes[ABS_Z ][AXE_ABS]); + ji->js.lRx = map_axis(ji, ABS_RX, ji->axes[ABS_RX][AXE_ABS]); + ji->js.lRy = map_axis(ji, ABS_RY, ji->axes[ABS_RY][AXE_ABS]); + ji->js.lRz = map_axis(ji, ABS_RZ, ji->axes[ABS_RZ][AXE_ABS]); +} + +static void joy_polldev(JoystickImpl *This) { + struct timeval tv; + fd_set readfds; + struct input_event ie; + + if (This->joyfd==-1) + return; + + while (1) { + memset(&tv,0,sizeof(tv)); + FD_ZERO(&readfds); + FD_SET(This->joyfd,&readfds); + + if (1>select(This->joyfd+1,&readfds,NULL,NULL,&tv)) + return; + + /* we have one event, so we can read */ + if (sizeof(ie)!=read(This->joyfd,&ie,sizeof(ie))) + return; + + TRACE("input_event: type %d, code %d, value %d\n",ie.type,ie.code,ie.value); + switch (ie.type) { + case EV_KEY: /* button */ + switch (ie.code) { + case BTN_TRIGGER: /* normal flight stick */ + case BTN_A: /* gamepad */ + case BTN_1: /* generic */ + This->js.rgbButtons[0] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(0),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case BTN_THUMB: + case BTN_B: + case BTN_2: + This->js.rgbButtons[1] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(1),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case BTN_THUMB2: + case BTN_C: + case BTN_3: + This->js.rgbButtons[2] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(2),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case BTN_TOP: + case BTN_X: + case BTN_4: + This->js.rgbButtons[3] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(3),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case BTN_TOP2: + case BTN_Y: + case BTN_5: + This->js.rgbButtons[4] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(4),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case BTN_PINKIE: + case BTN_Z: + case BTN_6: + This->js.rgbButtons[5] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(5),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case BTN_BASE: + case BTN_TL: + case BTN_7: + This->js.rgbButtons[6] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(6),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case BTN_BASE2: + case BTN_TR: + case BTN_8: + This->js.rgbButtons[7] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(7),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case BTN_BASE3: + case BTN_TL2: + case BTN_9: + This->js.rgbButtons[8] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(8),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case BTN_BASE4: + case BTN_TR2: + This->js.rgbButtons[9] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(9),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case BTN_BASE5: + case BTN_SELECT: + This->js.rgbButtons[10] = ie.value?0x80:0x00; + GEN_EVENT(DIJOFS_BUTTON(10),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + default: + FIXME("unhandled joystick button %x, value %d\n",ie.code,ie.value); + break; + } + break; + case EV_ABS: + switch (ie.code) { + case ABS_X: + This->js.lX = map_axis(This,ABS_X,ie.value); + GEN_EVENT(DIJOFS_X,This->js.lX,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case ABS_Y: + This->js.lY = map_axis(This,ABS_Y,ie.value); + GEN_EVENT(DIJOFS_Y,This->js.lY,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case ABS_Z: + This->js.lZ = map_axis(This,ABS_Z,ie.value); + GEN_EVENT(DIJOFS_Z,This->js.lZ,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case ABS_RX: + This->js.lRx = map_axis(This,ABS_RX,ie.value); + GEN_EVENT(DIJOFS_RX,This->js.lRx,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case ABS_RY: + This->js.lRy = map_axis(This,ABS_RY,ie.value); + GEN_EVENT(DIJOFS_RY,This->js.lRy,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + case ABS_RZ: + This->js.lRz = map_axis(This,ABS_RZ,ie.value); + GEN_EVENT(DIJOFS_RZ,This->js.lRz,ie.time.tv_usec,(This->dinput->evsequence)++); + break; + default: + FIXME("unhandled joystick axe event (code %d, value %d)\n",ie.code,ie.value); + break; + } + break; + default: + FIXME("joystick cannot handle type %d event (code %d)\n",ie.type,ie.code); + break; + } + } +} + +/****************************************************************************** + * GetDeviceState : returns the "state" of the joystick. + * + */ +static HRESULT WINAPI JoystickAImpl_GetDeviceState( + LPDIRECTINPUTDEVICE8A iface,DWORD len,LPVOID ptr +) { + JoystickImpl *This = (JoystickImpl *)iface; + + joy_polldev(This); + + TRACE("(this=%p,0x%08lx,%p)\n",This,len,ptr); + if ((len != sizeof(DIJOYSTATE)) && (len != sizeof(DIJOYSTATE2))) { + FIXME("len %ld is not sizeof(DIJOYSTATE) or DIJOYSTATE2, unsupported format.\n",len); + return E_FAIL; + } + memcpy(ptr,&(This->js),len); + This->queue_head = 0; + This->queue_tail = 0; + return 0; +} + +/****************************************************************************** + * GetDeviceData : gets buffered input data. + */ +static HRESULT WINAPI JoystickAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface, + DWORD dodsize, + LPDIDEVICEOBJECTDATA dod, + LPDWORD entries, + DWORD flags +) { + JoystickImpl *This = (JoystickImpl *)iface; + + FIXME("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx),STUB!\n",This,dodsize,*entries,flags); + + joy_polldev(This); + if (flags & DIGDD_PEEK) + FIXME("DIGDD_PEEK\n"); + + if (dod == NULL) { + } else { + } + return 0; +} + +/****************************************************************************** + * SetProperty : change input device properties + */ +static HRESULT WINAPI JoystickAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, + LPCDIPROPHEADER ph) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + FIXME("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph); + FIXME("ph.dwSize = %ld, ph.dwHeaderSize =%ld, ph.dwObj = %ld, ph.dwHow= %ld\n",ph->dwSize, ph->dwHeaderSize,ph->dwObj,ph->dwHow); + + if (!HIWORD(rguid)) { + switch ((DWORD)rguid) { + case (DWORD) DIPROP_BUFFERSIZE: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + + FIXME("buffersize = %ld\n",pd->dwData); + break; + } + case (DWORD)DIPROP_RANGE: { + LPCDIPROPRANGE pr = (LPCDIPROPRANGE)ph; + + FIXME("proprange(%ld,%ld)\n",pr->lMin,pr->lMax); + switch (ph->dwObj) { + case 0: /* X */ + case 4: /* Y */ + case 8: /* Z */ + case 12: /* Rx */ + case 16: /* Ry */ + case 20: /* Rz */ + This->wantmin[ph->dwObj/4] = pr->lMin; + This->wantmax[ph->dwObj/4] = pr->lMax; + break; + default: + FIXME("setting proprange %ld - %ld for dwObj %ld\n",pr->lMin,pr->lMax,ph->dwObj); + } + break; + } + case (DWORD)DIPROP_DEADZONE: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + + FIXME("setting deadzone(%ld)\n",pd->dwData); + This->deadz[ph->dwObj/4] = pd->dwData; + break; + } + default: + FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); + break; + } + } + fake_current_js_state(This); + return 0; +} + +/****************************************************************************** + * SetEventNotification : specifies event to be sent on state change + */ +static HRESULT WINAPI JoystickAImpl_SetEventNotification( + LPDIRECTINPUTDEVICE8A iface, HANDLE hnd +) { + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd); + This->hEvent = hnd; + return DI_OK; +} + +static HRESULT WINAPI JoystickAImpl_GetCapabilities( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVCAPS lpDIDevCaps) +{ + JoystickImpl *This = (JoystickImpl *)iface; + int xfd = This->joyfd; + int i,axes,buttons; + int wasacquired = 1; + + TRACE("%p->(%p)\n",iface,lpDIDevCaps); + if (xfd==-1) { + /* yes, games assume we return something, even if unacquired */ + JoystickAImpl_Acquire(iface); + xfd = This->joyfd; + wasacquired = 0; + } + lpDIDevCaps->dwFlags = DIDC_ATTACHED; + if (This->dinput->version >= 8) + lpDIDevCaps->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); + else + lpDIDevCaps->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); + + axes=0; + for (i=0;iabsbits,i)) axes++; + buttons=0; + for (i=0;ikeybits,i)) buttons++; + + lpDIDevCaps->dwAxes = axes; + lpDIDevCaps->dwButtons = buttons; + + if (!wasacquired) + JoystickAImpl_Unacquire(iface); + + return DI_OK; +} + +static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE8A iface) { + JoystickImpl *This = (JoystickImpl *)iface; + TRACE("(),stub!\n"); + + joy_polldev(This); + return DI_OK; +} + +/****************************************************************************** + * EnumObjects : enumerate the different buttons and axis... + */ +static HRESULT WINAPI JoystickAImpl_EnumObjects( + LPDIRECTINPUTDEVICE8A iface, + LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + JoystickImpl *This = (JoystickImpl *)iface; + DIDEVICEOBJECTINSTANCEA ddoi; + int xfd = This->joyfd; + + + TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags); + if (TRACE_ON(dinput)) { + TRACE(" - flags = "); + _dump_EnumObjects_flags(dwFlags); + TRACE("\n"); + } + + if (xfd == -1) return DIERR_NOTACQUIRED; + + /* Only the fields till dwFFMaxForce are relevant */ + ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce); + + /* For the joystick, do as is done in the GetCapabilities function */ + /* FIXME: needs more items */ + if ((dwFlags == DIDFT_ALL) || + (dwFlags & DIDFT_AXIS)) { + BYTE i; + + for (i = 0; i < ABS_MAX; i++) { + if (!test_bit(This->absbits,i)) continue; + + switch (i) { + case ABS_X: + ddoi.guidType = GUID_XAxis; + ddoi.dwOfs = DIJOFS_X; + break; + case ABS_Y: + ddoi.guidType = GUID_YAxis; + ddoi.dwOfs = DIJOFS_Y; + break; + case ABS_Z: + ddoi.guidType = GUID_ZAxis; + ddoi.dwOfs = DIJOFS_Z; + break; + case ABS_RX: + ddoi.guidType = GUID_RxAxis; + ddoi.dwOfs = DIJOFS_RX; + break; + case ABS_RY: + ddoi.guidType = GUID_RyAxis; + ddoi.dwOfs = DIJOFS_RY; + break; + case ABS_RZ: + ddoi.guidType = GUID_RzAxis; + ddoi.dwOfs = DIJOFS_RZ; + break; + case ABS_THROTTLE: + ddoi.guidType = GUID_Slider; + ddoi.dwOfs = DIJOFS_SLIDER(0); + break; + default: + FIXME("unhandled abs axis %d, ignoring!\n",i); + } + ddoi.dwType = DIDFT_MAKEINSTANCE((1<keybits,i)) continue; + + switch (i) { + case BTN_TRIGGER: + case BTN_A: + case BTN_1: + ddoi.dwOfs = DIJOFS_BUTTON(0); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 0) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + case BTN_THUMB: + case BTN_B: + case BTN_2: + ddoi.dwOfs = DIJOFS_BUTTON(1); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 1) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + case BTN_THUMB2: + case BTN_C: + case BTN_3: + ddoi.dwOfs = DIJOFS_BUTTON(2); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 2) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + case BTN_TOP: + case BTN_X: + case BTN_4: + ddoi.dwOfs = DIJOFS_BUTTON(3); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 3) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + case BTN_TOP2: + case BTN_Y: + case BTN_5: + ddoi.dwOfs = DIJOFS_BUTTON(4); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 4) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + case BTN_PINKIE: + case BTN_Z: + case BTN_6: + ddoi.dwOfs = DIJOFS_BUTTON(5); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 5) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + case BTN_BASE: + case BTN_TL: + case BTN_7: + ddoi.dwOfs = DIJOFS_BUTTON(6); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 6) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + case BTN_BASE2: + case BTN_TR: + case BTN_8: + ddoi.dwOfs = DIJOFS_BUTTON(7); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 7) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + case BTN_BASE3: + case BTN_TL2: + case BTN_9: + ddoi.dwOfs = DIJOFS_BUTTON(8); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 8) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + case BTN_BASE4: + case BTN_TR2: + ddoi.dwOfs = DIJOFS_BUTTON(9); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 9) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + case BTN_BASE5: + case BTN_SELECT: + ddoi.dwOfs = DIJOFS_BUTTON(10); + ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 10) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; + break; + } + sprintf(ddoi.tszName, "%d-Button", i); + _dump_OBJECTINSTANCEA(&ddoi); + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) + return DI_OK; + } + } + + if (xfd!=This->joyfd) + close(xfd); + + return DI_OK; +} + +static HRESULT WINAPI JoystickWImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface, + LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + device_enumobjects_AtoWcb_data data; + + data.lpCallBack = lpCallback; + data.lpvRef = lpvRef; + + return JoystickAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags); +} + +/****************************************************************************** + * GetProperty : get input device properties + */ +static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, + LPDIPROPHEADER pdiph) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(this=%p,%s,%p): stub!\n", + iface, debugstr_guid(rguid), pdiph); + + if (TRACE_ON(dinput)) + _dump_DIPROPHEADER(pdiph); + + if (!HIWORD(rguid)) { + switch ((DWORD)rguid) { + case (DWORD) DIPROP_BUFFERSIZE: { + LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; + + TRACE(" return buffersize = %d\n",This->queue_len); + pd->dwData = This->queue_len; + break; + } + + case (DWORD) DIPROP_RANGE: { + /* LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph; */ + if ((pdiph->dwHow == DIPH_BYID) && + (pdiph->dwObj & DIDFT_ABSAXIS)) { + /* The app is querying the current range of the axis : return the lMin and lMax values */ + FIXME("unimplemented axis range query.\n"); + } + + break; + } + + default: + FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); + break; + } + } + + + return DI_OK; +} + +static IDirectInputDevice8AVtbl JoystickAvt = +{ + IDirectInputDevice2AImpl_QueryInterface, + IDirectInputDevice2AImpl_AddRef, + JoystickAImpl_Release, + JoystickAImpl_GetCapabilities, + JoystickAImpl_EnumObjects, + JoystickAImpl_GetProperty, + JoystickAImpl_SetProperty, + JoystickAImpl_Acquire, + JoystickAImpl_Unacquire, + JoystickAImpl_GetDeviceState, + JoystickAImpl_GetDeviceData, + JoystickAImpl_SetDataFormat, + JoystickAImpl_SetEventNotification, + IDirectInputDevice2AImpl_SetCooperativeLevel, + IDirectInputDevice2AImpl_GetObjectInfo, + IDirectInputDevice2AImpl_GetDeviceInfo, + IDirectInputDevice2AImpl_RunControlPanel, + IDirectInputDevice2AImpl_Initialize, + IDirectInputDevice2AImpl_CreateEffect, + IDirectInputDevice2AImpl_EnumEffects, + IDirectInputDevice2AImpl_GetEffectInfo, + IDirectInputDevice2AImpl_GetForceFeedbackState, + IDirectInputDevice2AImpl_SendForceFeedbackCommand, + IDirectInputDevice2AImpl_EnumCreatedEffectObjects, + IDirectInputDevice2AImpl_Escape, + JoystickAImpl_Poll, + IDirectInputDevice2AImpl_SendDeviceData, + IDirectInputDevice7AImpl_EnumEffectsInFile, + IDirectInputDevice7AImpl_WriteEffectToFile, + IDirectInputDevice8AImpl_BuildActionMap, + IDirectInputDevice8AImpl_SetActionMap, + IDirectInputDevice8AImpl_GetImageInfo +}; + +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(JoystickWvt.fun)) +#else +# define XCAST(fun) (void*) +#endif + +static IDirectInputDevice8WVtbl JoystickWvt = +{ + IDirectInputDevice2WImpl_QueryInterface, + XCAST(AddRef)IDirectInputDevice2AImpl_AddRef, + XCAST(Release)JoystickAImpl_Release, + XCAST(GetCapabilities)JoystickAImpl_GetCapabilities, + JoystickWImpl_EnumObjects, + XCAST(GetProperty)JoystickAImpl_GetProperty, + XCAST(SetProperty)JoystickAImpl_SetProperty, + XCAST(Acquire)JoystickAImpl_Acquire, + XCAST(Unacquire)JoystickAImpl_Unacquire, + XCAST(GetDeviceState)JoystickAImpl_GetDeviceState, + XCAST(GetDeviceData)JoystickAImpl_GetDeviceData, + XCAST(SetDataFormat)JoystickAImpl_SetDataFormat, + XCAST(SetEventNotification)JoystickAImpl_SetEventNotification, + XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel, + IDirectInputDevice2WImpl_GetObjectInfo, + IDirectInputDevice2WImpl_GetDeviceInfo, + XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel, + XCAST(Initialize)IDirectInputDevice2AImpl_Initialize, + XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect, + IDirectInputDevice2WImpl_EnumEffects, + IDirectInputDevice2WImpl_GetEffectInfo, + XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState, + XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand, + XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects, + XCAST(Escape)IDirectInputDevice2AImpl_Escape, + XCAST(Poll)JoystickAImpl_Poll, + XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData, + IDirectInputDevice7WImpl_EnumEffectsInFile, + IDirectInputDevice7WImpl_WriteEffectToFile, + IDirectInputDevice8WImpl_BuildActionMap, + IDirectInputDevice8WImpl_SetActionMap, + IDirectInputDevice8WImpl_GetImageInfo +}; +#undef XCAST + +#endif /* HAVE_LINUX_INPUT_H */ + +#endif diff --git a/reactos/lib/dinput/keyboard.c b/reactos/lib/dinput/keyboard.c index 40b85ca3eac..8607d8d24b1 100644 --- a/reactos/lib/dinput/keyboard.c +++ b/reactos/lib/dinput/keyboard.c @@ -1,858 +1,858 @@ -/* DirectInput Keyboard device - * - * Copyright 1998 Marcus Meissner - * Copyright 1998,1999 Lionel Ulmer - * Copyright 2000-2001 TransGaming Technologies Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" -#include "wine/port.h" - -#include -#include -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "winerror.h" -#include "dinput.h" - -#include "dinput_private.h" -#include "device_private.h" -#include "wine/debug.h" -#include "wine/unicode.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dinput); - -//fast fix misning from mingw headers -#ifdef __REACTOS__ -#define LLKHF_INJECTED 0x00000010 -#endif - -static IDirectInputDevice8AVtbl SysKeyboardAvt; -static IDirectInputDevice8WVtbl SysKeyboardWvt; - -typedef struct SysKeyboardImpl SysKeyboardImpl; -struct SysKeyboardImpl -{ - LPVOID lpVtbl; - DWORD ref; - GUID guid; - - IDirectInputImpl* dinput; - - HANDLE hEvent; - /* SysKeyboardAImpl */ - int acquired; - int buffersize; /* set in 'SetProperty' */ - LPDIDEVICEOBJECTDATA buffer; /* buffer for 'GetDeviceData'. - Alloc at 'Acquire', Free at - 'Unacquire' */ - int count; /* number of objects in use in - 'buffer' */ - int start; /* 'buffer' rotates. This is the - first in use (if count > 0) */ - BOOL overflow; /* return DI_BUFFEROVERFLOW in - 'GetDeviceData' */ - CRITICAL_SECTION crit; -}; - -SysKeyboardImpl *current; /* Today's acquired device -FIXME: currently this can be only one. -Maybe this should be a linked list or st. -I don't know what the rules are for multiple acquired keyboards, -but 'DI_LOSTFOCUS' and 'DI_UNACQUIRED' exist for a reason. -*/ - -static BYTE DInputKeyState[256]; /* array for 'GetDeviceState' */ - -static CRITICAL_SECTION keyboard_crit; -static CRITICAL_SECTION_DEBUG critsect_debug = -{ - 0, 0, &keyboard_crit, - { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, - 0, 0, { 0, (DWORD)(__FILE__ ": keyboard_crit") } -}; -static CRITICAL_SECTION keyboard_crit = { &critsect_debug, -1, 0, 0, 0, 0 }; - -#ifndef __REACTOS__ -static DWORD keyboard_users; -static HHOOK keyboard_hook; -#endif - -#ifdef __REACTOS__ -void reactos_input_keyboard(); - -void reactos_input_keyboard() -{ - int disk_code = -1; - BYTE oldDInputKeyState[256]; - int t; - - memcpy(&oldDInputKeyState,&DInputKeyState,256); - GetKeyboardState(DInputKeyState); - - for( t=0;t<255;t++) - { - if (oldDInputKeyState[t]!=DInputKeyState[t]) disk_code=t; - } - - - if (disk_code!=-1) { - if (current->buffer != NULL) - { - int n; - n = (current->start + current->count) % current->buffersize; - - current->buffer[n].dwOfs = (BYTE) disk_code; - current->buffer[n].dwData = DInputKeyState[disk_code]; - current->buffer[n].dwTimeStamp = 10; - current->buffer[n].dwSequence = current->dinput->evsequence++; - - - if (current->count == current->buffersize) - { - current->start = ++current->start % current->buffersize; - current->overflow = TRUE; - } - else - current->count++; - - } - } - - -} -#endif -#ifndef __REACTOS__ -LRESULT CALLBACK KeyboardCallback( int code, WPARAM wparam, LPARAM lparam ) -{ - TRACE("(%d,%d,%ld)\n", code, wparam, lparam); - - if (code == HC_ACTION) - { - BYTE dik_code; - BOOL down; - DWORD timestamp; - - { - KBDLLHOOKSTRUCT *hook = (KBDLLHOOKSTRUCT *)lparam; - dik_code = hook->scanCode; - if (hook->flags & LLKHF_EXTENDED) dik_code |= 0x80; - down = !(hook->flags & LLKHF_UP); - timestamp = hook->time; - } - - DInputKeyState[dik_code] = (down ? 0x80 : 0); - TRACE(" setting %02X to %02X\n", dik_code, DInputKeyState[dik_code]); - - if (current != NULL) - { - if (current->hEvent) - SetEvent(current->hEvent); - - if (current->buffer != NULL) - { - int n; - - EnterCriticalSection(&(current->crit)); - - n = (current->start + current->count) % current->buffersize; - - current->buffer[n].dwOfs = dik_code; - current->buffer[n].dwData = down ? 0x80 : 0; - current->buffer[n].dwTimeStamp = timestamp; - current->buffer[n].dwSequence = current->dinput->evsequence++; - - TRACE("Adding event at offset %d : %ld - %ld - %ld - %ld\n", n, - current->buffer[n].dwOfs, current->buffer[n].dwData, current->buffer[n].dwTimeStamp, current->buffer[n].dwSequence); - - if (current->count == current->buffersize) - { - current->start = ++current->start % current->buffersize; - current->overflow = TRUE; - } - else - current->count++; - - LeaveCriticalSection(&(current->crit)); - } - } - } - - return CallNextHookEx(keyboard_hook, code, wparam, lparam); -} -#endif - -static GUID DInput_Wine_Keyboard_GUID = { /* 0ab8648a-7735-11d2-8c73-71df54a96441 */ - 0x0ab8648a, - 0x7735, - 0x11d2, - {0x8c, 0x73, 0x71, 0xdf, 0x54, 0xa9, 0x64, 0x41} -}; - -static void fill_keyboard_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, int version) { - DWORD dwSize; - DIDEVICEINSTANCEA ddi; - - dwSize = lpddi->dwSize; - - TRACE("%ld %p\n", dwSize, lpddi); - - memset(lpddi, 0, dwSize); - memset(&ddi, 0, sizeof(ddi)); - - ddi.dwSize = dwSize; - ddi.guidInstance = GUID_SysKeyboard;/* DInput's GUID */ - ddi.guidProduct = DInput_Wine_Keyboard_GUID; /* Vendor's GUID */ - if (version >= 8) - ddi.dwDevType = DI8DEVTYPE_KEYBOARD | (DI8DEVTYPEKEYBOARD_UNKNOWN << 8); - else - ddi.dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_UNKNOWN << 8); - strcpy(ddi.tszInstanceName, "Keyboard"); - strcpy(ddi.tszProductName, "Wine Keyboard"); - - memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi))); -} - -static void fill_keyboard_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, int version) { - DWORD dwSize; - DIDEVICEINSTANCEW ddi; - - dwSize = lpddi->dwSize; - - TRACE("%ld %p\n", dwSize, lpddi); - - memset(lpddi, 0, dwSize); - memset(&ddi, 0, sizeof(ddi)); - - ddi.dwSize = dwSize; - ddi.guidInstance = GUID_SysKeyboard;/* DInput's GUID */ - ddi.guidProduct = DInput_Wine_Keyboard_GUID; /* Vendor's GUID */ - if (version >= 8) - ddi.dwDevType = DI8DEVTYPE_KEYBOARD | (DI8DEVTYPEKEYBOARD_UNKNOWN << 8); - else - ddi.dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_UNKNOWN << 8); - MultiByteToWideChar(CP_ACP, 0, "Keyboard", -1, ddi.tszInstanceName, MAX_PATH); - MultiByteToWideChar(CP_ACP, 0, "Wine Keyboard", -1, ddi.tszProductName, MAX_PATH); - - memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi))); -} - -static BOOL keyboarddev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, int version, int id) -{ - if (id != 0) - return FALSE; - - if ((dwDevType == 0) || - ((dwDevType == DIDEVTYPE_KEYBOARD) && (version < 8)) || - (((dwDevType == DI8DEVCLASS_KEYBOARD) || (dwDevType == DI8DEVTYPE_KEYBOARD)) && (version >= 8))) { - TRACE("Enumerating the Keyboard device\n"); - - fill_keyboard_dideviceinstanceA(lpddi, version); - - return TRUE; - } - - return FALSE; -} - -static BOOL keyboarddev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, int version, int id) -{ - if (id != 0) - return FALSE; - - if ((dwDevType == 0) || - ((dwDevType == DIDEVTYPE_KEYBOARD) && (version < 8)) || - (((dwDevType == DI8DEVCLASS_KEYBOARD) || (dwDevType == DI8DEVTYPE_KEYBOARD)) && (version >= 8))) { - TRACE("Enumerating the Keyboard device\n"); - - fill_keyboard_dideviceinstanceW(lpddi, version); - - return TRUE; - } - - return FALSE; -} - -static SysKeyboardImpl *alloc_device_keyboard(REFGUID rguid, LPVOID kvt, IDirectInputImpl *dinput) -{ - SysKeyboardImpl* newDevice; - newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysKeyboardImpl)); - newDevice->lpVtbl = kvt; - newDevice->ref = 1; - memcpy(&(newDevice->guid),rguid,sizeof(*rguid)); - newDevice->dinput = dinput; - -#ifndef __REACTOS__ - EnterCriticalSection(&keyboard_crit); - - if (!keyboard_users++) - keyboard_hook = SetWindowsHookExW( WH_KEYBOARD_LL, KeyboardCallback, DINPUT_instance, 0 ); - - LeaveCriticalSection(&keyboard_crit); -#endif - return newDevice; -} - - -static HRESULT keyboarddev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev) -{ - if ((IsEqualGUID(&GUID_SysKeyboard,rguid)) || /* Generic Keyboard */ - (IsEqualGUID(&DInput_Wine_Keyboard_GUID,rguid))) { /* Wine Keyboard */ - if ((riid == NULL) || - IsEqualGUID(&IID_IDirectInputDeviceA,riid) || - IsEqualGUID(&IID_IDirectInputDevice2A,riid) || - IsEqualGUID(&IID_IDirectInputDevice7A,riid) || - IsEqualGUID(&IID_IDirectInputDevice8A,riid)) { - *pdev = (IDirectInputDeviceA*) alloc_device_keyboard(rguid, &SysKeyboardAvt, dinput); - TRACE("Creating a Keyboard device (%p)\n", *pdev); - return DI_OK; - } else - return DIERR_NOINTERFACE; - } - return DIERR_DEVICENOTREG; -} - -static HRESULT keyboarddev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev) -{ - if ((IsEqualGUID(&GUID_SysKeyboard,rguid)) || /* Generic Keyboard */ - (IsEqualGUID(&DInput_Wine_Keyboard_GUID,rguid))) { /* Wine Keyboard */ - if ((riid == NULL) || - IsEqualGUID(&IID_IDirectInputDeviceW,riid) || - IsEqualGUID(&IID_IDirectInputDevice2W,riid) || - IsEqualGUID(&IID_IDirectInputDevice7W,riid) || - IsEqualGUID(&IID_IDirectInputDevice8W,riid)) { - *pdev = (IDirectInputDeviceW*) alloc_device_keyboard(rguid, &SysKeyboardWvt, dinput); - TRACE("Creating a Keyboard device (%p)\n", *pdev); - return DI_OK; - } else - return DIERR_NOINTERFACE; - } - return DIERR_DEVICENOTREG; -} - -dinput_device keyboarddev = { - 100, - "Wine keyboard driver", - keyboarddev_enum_deviceA, - keyboarddev_enum_deviceW, - keyboarddev_create_deviceA, - keyboarddev_create_deviceW -}; - -void scan_keyboard() -{ - dinput_register_device(&keyboarddev); -} - -DECL_GLOBAL_CONSTRUCTOR(keyboarddev_register) { dinput_register_device(&keyboarddev); } - -static ULONG WINAPI SysKeyboardAImpl_Release(LPDIRECTINPUTDEVICE8A iface) -{ - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - ULONG ref; - - ref = InterlockedDecrement(&(This->ref)); - if (ref) - return ref; - -#ifndef __REACTOS__ - EnterCriticalSection(&keyboard_crit); - if (!--keyboard_users) { - UnhookWindowsHookEx( keyboard_hook ); - keyboard_hook = 0; - } - LeaveCriticalSection(&keyboard_crit); -#endif - - /* Free the data queue */ - HeapFree(GetProcessHeap(),0,This->buffer); - - DeleteCriticalSection(&(This->crit)); - - HeapFree(GetProcessHeap(),0,This); - return DI_OK; -} - -static HRESULT WINAPI SysKeyboardAImpl_SetProperty( - LPDIRECTINPUTDEVICE8A iface,REFGUID rguid,LPCDIPROPHEADER ph -) -{ - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - - TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph); - TRACE("(size=%ld,headersize=%ld,obj=%ld,how=%ld\n", - ph->dwSize,ph->dwHeaderSize,ph->dwObj,ph->dwHow); - if (!HIWORD(rguid)) { - switch ((DWORD)rguid) { - case (DWORD) DIPROP_BUFFERSIZE: { - LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; - - TRACE("(buffersize=%ld)\n",pd->dwData); - - if (This->acquired) - return DIERR_INVALIDPARAM; - - This->buffersize = pd->dwData; - - break; - } - default: - WARN("Unknown type %ld\n",(DWORD)rguid); - break; - } - } - return DI_OK; -} - - -static HRESULT WINAPI SysKeyboardAImpl_GetDeviceState( - LPDIRECTINPUTDEVICE8A iface,DWORD len,LPVOID ptr -) -{ - TRACE("(%p)->(%ld,%p)\n", iface, len, ptr); - -#ifdef __REACTOS__ - reactos_input_keyboard(); -#endif - - /* Note: device does not need to be acquired */ - if (len != 256) - return DIERR_INVALIDPARAM; - - MsgWaitForMultipleObjectsEx(0, NULL, 0, 0, 0); - - if (TRACE_ON(dinput)) { - int i; - for (i = 0; i < 256; i++) { - if (DInputKeyState[i] != 0x00) { - TRACE(" - %02X: %02x\n", i, DInputKeyState[i]); - } - } - } - - memcpy(ptr, DInputKeyState, 256); - return DI_OK; -} - -static HRESULT WINAPI SysKeyboardAImpl_GetDeviceData( - LPDIRECTINPUTDEVICE8A iface,DWORD dodsize,LPDIDEVICEOBJECTDATA dod, - LPDWORD entries,DWORD flags -) -{ - - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - int ret = DI_OK, i = 0; -#ifdef __REACTOS__ - reactos_input_keyboard(); -#endif - - TRACE("(this=%p,%ld,%p,%p(%ld)),0x%08lx)\n", - This,dodsize,dod,entries,entries?*entries:0,flags); - - if (This->acquired == 0) - return DIERR_NOTACQUIRED; - - if (This->buffer == NULL) - return DIERR_NOTBUFFERED; - - if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3)) - return DIERR_INVALIDPARAM; - - MsgWaitForMultipleObjectsEx(0, NULL, 0, 0, 0); - - EnterCriticalSection(&(This->crit)); - - /* Copy item at a time for the case dodsize > sizeof(buffer[n]) */ - while ((i < *entries || *entries == INFINITE) && i < This->count) - { - if (dod != NULL) - { - int n = (This->start + i) % This->buffersize; - LPDIDEVICEOBJECTDATA pd - = (LPDIDEVICEOBJECTDATA)((BYTE *)dod + dodsize * i); - pd->dwOfs = This->buffer[n].dwOfs; - pd->dwData = This->buffer[n].dwData; - pd->dwTimeStamp = This->buffer[n].dwTimeStamp; - pd->dwSequence = This->buffer[n].dwSequence; - } - i++; - } - - *entries = i; - - if (This->overflow) - ret = DI_BUFFEROVERFLOW; - - if (!(flags & DIGDD_PEEK)) - { - /* Empty buffer */ - This->count -= i; - This->start = (This->start + i) % This->buffersize; - This->overflow = FALSE; - } - - LeaveCriticalSection(&(This->crit)); - - TRACE("Returning %ld events queued\n", *entries); - - return ret; -} - -static HRESULT WINAPI SysKeyboardAImpl_EnumObjects( - LPDIRECTINPUTDEVICE8A iface, - LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, - LPVOID lpvRef, - DWORD dwFlags) -{ - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - DIDEVICEOBJECTINSTANCEA ddoi; - int i; - - TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags); - if (TRACE_ON(dinput)) { - TRACE(" - flags = "); - _dump_EnumObjects_flags(dwFlags); - TRACE("\n"); - } - - /* Only the fields till dwFFMaxForce are relevant */ - memset(&ddoi, 0, sizeof(ddoi)); - ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce); - - for (i = 0; i < 256; i++) { - /* Report 255 keys :-) */ - ddoi.guidType = GUID_Key; - ddoi.dwOfs = i; - ddoi.dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_BUTTON; - GetKeyNameTextA(((i & 0x7f) << 16) | ((i & 0x80) << 17), ddoi.tszName, sizeof(ddoi.tszName)); - _dump_OBJECTINSTANCEA(&ddoi); - if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; - } - - return DI_OK; -} - -static HRESULT WINAPI SysKeyboardWImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface, - LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, - LPVOID lpvRef, - DWORD dwFlags) -{ - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - - device_enumobjects_AtoWcb_data data; - - data.lpCallBack = lpCallback; - data.lpvRef = lpvRef; - - return SysKeyboardAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags); -} - -static HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface); - -static HRESULT WINAPI SysKeyboardAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) -{ - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - - TRACE("(this=%p)\n",This); - - if (This->acquired) - return S_FALSE; - - This->acquired = 1; - - if (current != NULL) - { - FIXME("Not more than one keyboard can be acquired at the same time.\n"); - SysKeyboardAImpl_Unacquire(iface); - } - - current = This; - - if (This->buffersize > 0) - { - This->buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - This->buffersize * sizeof(*(This->buffer))); - This->start = 0; - This->count = 0; - This->overflow = FALSE; - InitializeCriticalSection(&(This->crit)); - } - else - This->buffer = NULL; - - - return DI_OK; -} - -static HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) -{ - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - TRACE("(this=%p)\n",This); - - if (This->acquired == 0) - return DI_NOEFFECT; - - if (current == This) - current = NULL; - else - ERR("this != current\n"); - - This->acquired = 0; - - if (This->buffersize >= 0) - { - HeapFree(GetProcessHeap(), 0, This->buffer); - This->buffer = NULL; - DeleteCriticalSection(&(This->crit)); - } - - return DI_OK; -} - -static HRESULT WINAPI SysKeyboardAImpl_SetEventNotification(LPDIRECTINPUTDEVICE8A iface, - HANDLE hnd) { - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - - TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd); - - This->hEvent = hnd; - return DI_OK; -} - -/****************************************************************************** - * GetCapabilities : get the device capablitites - */ -static HRESULT WINAPI SysKeyboardAImpl_GetCapabilities( - LPDIRECTINPUTDEVICE8A iface, - LPDIDEVCAPS lpDIDevCaps) -{ - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - DIDEVCAPS devcaps; - - TRACE("(this=%p,%p)\n",This,lpDIDevCaps); - - if ((lpDIDevCaps->dwSize != sizeof(DIDEVCAPS)) && (lpDIDevCaps->dwSize != sizeof(DIDEVCAPS_DX3))) { - WARN("invalid parameter\n"); - return DIERR_INVALIDPARAM; - } - - devcaps.dwSize = lpDIDevCaps->dwSize; - devcaps.dwFlags = DIDC_ATTACHED; - if (This->dinput->version >= 8) - devcaps.dwDevType = DI8DEVTYPE_KEYBOARD | (DI8DEVTYPEKEYBOARD_UNKNOWN << 8); - else - devcaps.dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_UNKNOWN << 8); - devcaps.dwAxes = 0; - devcaps.dwButtons = 256; - devcaps.dwPOVs = 0; - devcaps.dwFFSamplePeriod = 0; - devcaps.dwFFMinTimeResolution = 0; - devcaps.dwFirmwareRevision = 100; - devcaps.dwHardwareRevision = 100; - devcaps.dwFFDriverVersion = 0; - - memcpy(lpDIDevCaps, &devcaps, lpDIDevCaps->dwSize); - - return DI_OK; -} - -/****************************************************************************** - * GetObjectInfo : get information about a device object such as a button - * or axis - */ -static HRESULT WINAPI -SysKeyboardAImpl_GetObjectInfo( - LPDIRECTINPUTDEVICE8A iface, - LPDIDEVICEOBJECTINSTANCEA pdidoi, - DWORD dwObj, - DWORD dwHow) -{ - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - DIDEVICEOBJECTINSTANCEA ddoi; - DWORD dwSize = pdidoi->dwSize; - - TRACE("(this=%p,%p,%ld,0x%08lx)\n", This, pdidoi, dwObj, dwHow); - - if (dwHow == DIPH_BYID) { - WARN(" querying by id not supported yet...\n"); - return DI_OK; - } - - memset(pdidoi, 0, dwSize); - memset(&ddoi, 0, sizeof(ddoi)); - - ddoi.dwSize = dwSize; - ddoi.guidType = GUID_Key; - ddoi.dwOfs = dwObj; - ddoi.dwType = DIDFT_MAKEINSTANCE(dwObj) | DIDFT_BUTTON; - GetKeyNameTextA(((dwObj & 0x7f) << 16) | ((dwObj & 0x80) << 17), ddoi.tszName, sizeof(ddoi.tszName)); - - /* And return our just filled device object instance structure */ - memcpy(pdidoi, &ddoi, (dwSize < sizeof(ddoi) ? dwSize : sizeof(ddoi))); - - _dump_OBJECTINSTANCEA(pdidoi); - - return DI_OK; -} - -static HRESULT WINAPI SysKeyboardWImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface, - LPDIDEVICEOBJECTINSTANCEW pdidoi, - DWORD dwObj, - DWORD dwHow) -{ - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - DIDEVICEOBJECTINSTANCEW ddoi; - DWORD dwSize = pdidoi->dwSize; - - TRACE("(this=%p,%p,%ld,0x%08lx)\n", This, pdidoi, dwObj, dwHow); - - if (dwHow == DIPH_BYID) { - WARN(" querying by id not supported yet...\n"); - return DI_OK; - } - - memset(pdidoi, 0, dwSize); - memset(&ddoi, 0, sizeof(ddoi)); - - ddoi.dwSize = dwSize; - ddoi.guidType = GUID_Key; - ddoi.dwOfs = dwObj; - ddoi.dwType = DIDFT_MAKEINSTANCE(dwObj) | DIDFT_BUTTON; - GetKeyNameTextW(((dwObj & 0x7f) << 16) | ((dwObj & 0x80) << 17), ddoi.tszName, sizeof(ddoi.tszName)); - - /* And return our just filled device object instance structure */ - memcpy(pdidoi, &ddoi, (dwSize < sizeof(ddoi) ? dwSize : sizeof(ddoi))); - - _dump_OBJECTINSTANCEW(pdidoi); - - return DI_OK; -} - -/****************************************************************************** - * GetDeviceInfo : get information about a device's identity - */ -static HRESULT WINAPI SysKeyboardAImpl_GetDeviceInfo( - LPDIRECTINPUTDEVICE8A iface, - LPDIDEVICEINSTANCEA pdidi) -{ - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - TRACE("(this=%p,%p)\n", This, pdidi); - - if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA)) { - WARN(" dinput3 not supporte yet...\n"); - return DI_OK; - } - - fill_keyboard_dideviceinstanceA(pdidi, This->dinput->version); - - return DI_OK; -} - -static HRESULT WINAPI SysKeyboardWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, LPDIDEVICEINSTANCEW pdidi) -{ - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - TRACE("(this=%p,%p)\n", This, pdidi); - - if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW)) { - WARN(" dinput3 not supporte yet...\n"); - return DI_OK; - } - - fill_keyboard_dideviceinstanceW(pdidi, This->dinput->version); - - return DI_OK; -} - -static IDirectInputDevice8AVtbl SysKeyboardAvt = -{ - IDirectInputDevice2AImpl_QueryInterface, - IDirectInputDevice2AImpl_AddRef, - SysKeyboardAImpl_Release, - SysKeyboardAImpl_GetCapabilities, - SysKeyboardAImpl_EnumObjects, - IDirectInputDevice2AImpl_GetProperty, - SysKeyboardAImpl_SetProperty, - SysKeyboardAImpl_Acquire, - SysKeyboardAImpl_Unacquire, - SysKeyboardAImpl_GetDeviceState, - SysKeyboardAImpl_GetDeviceData, - IDirectInputDevice2AImpl_SetDataFormat, - SysKeyboardAImpl_SetEventNotification, - IDirectInputDevice2AImpl_SetCooperativeLevel, - SysKeyboardAImpl_GetObjectInfo, - SysKeyboardAImpl_GetDeviceInfo, - IDirectInputDevice2AImpl_RunControlPanel, - IDirectInputDevice2AImpl_Initialize, - IDirectInputDevice2AImpl_CreateEffect, - IDirectInputDevice2AImpl_EnumEffects, - IDirectInputDevice2AImpl_GetEffectInfo, - IDirectInputDevice2AImpl_GetForceFeedbackState, - IDirectInputDevice2AImpl_SendForceFeedbackCommand, - IDirectInputDevice2AImpl_EnumCreatedEffectObjects, - IDirectInputDevice2AImpl_Escape, - IDirectInputDevice2AImpl_Poll, - IDirectInputDevice2AImpl_SendDeviceData, - IDirectInputDevice7AImpl_EnumEffectsInFile, - IDirectInputDevice7AImpl_WriteEffectToFile, - IDirectInputDevice8AImpl_BuildActionMap, - IDirectInputDevice8AImpl_SetActionMap, - IDirectInputDevice8AImpl_GetImageInfo -}; - -#if !defined(__STRICT_ANSI__) && defined(__GNUC__) -# define XCAST(fun) (typeof(SysKeyboardWvt.fun)) -#else -# define XCAST(fun) (void*) -#endif - -static IDirectInputDevice8WVtbl SysKeyboardWvt = -{ - IDirectInputDevice2WImpl_QueryInterface, - XCAST(AddRef)IDirectInputDevice2AImpl_AddRef, - XCAST(Release)SysKeyboardAImpl_Release, - XCAST(GetCapabilities)SysKeyboardAImpl_GetCapabilities, - SysKeyboardWImpl_EnumObjects, - XCAST(GetProperty)IDirectInputDevice2AImpl_GetProperty, - XCAST(SetProperty)SysKeyboardAImpl_SetProperty, - XCAST(Acquire)SysKeyboardAImpl_Acquire, - XCAST(Unacquire)SysKeyboardAImpl_Unacquire, - XCAST(GetDeviceState)SysKeyboardAImpl_GetDeviceState, - XCAST(GetDeviceData)SysKeyboardAImpl_GetDeviceData, - XCAST(SetDataFormat)IDirectInputDevice2AImpl_SetDataFormat, - XCAST(SetEventNotification)SysKeyboardAImpl_SetEventNotification, - XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel, - SysKeyboardWImpl_GetObjectInfo, - SysKeyboardWImpl_GetDeviceInfo, - XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel, - XCAST(Initialize)IDirectInputDevice2AImpl_Initialize, - XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect, - IDirectInputDevice2WImpl_EnumEffects, - IDirectInputDevice2WImpl_GetEffectInfo, - XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState, - XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand, - XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects, - XCAST(Escape)IDirectInputDevice2AImpl_Escape, - XCAST(Poll)IDirectInputDevice2AImpl_Poll, - XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData, - IDirectInputDevice7WImpl_EnumEffectsInFile, - IDirectInputDevice7WImpl_WriteEffectToFile, - IDirectInputDevice8WImpl_BuildActionMap, - IDirectInputDevice8WImpl_SetActionMap, - IDirectInputDevice8WImpl_GetImageInfo -}; -#undef XCAST +/* DirectInput Keyboard device + * + * Copyright 1998 Marcus Meissner + * Copyright 1998,1999 Lionel Ulmer + * Copyright 2000-2001 TransGaming Technologies Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winerror.h" +#include "dinput.h" + +#include "dinput_private.h" +#include "device_private.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dinput); + +//fast fix misning from mingw headers +#ifdef __REACTOS__ +#define LLKHF_INJECTED 0x00000010 +#endif + +static IDirectInputDevice8AVtbl SysKeyboardAvt; +static IDirectInputDevice8WVtbl SysKeyboardWvt; + +typedef struct SysKeyboardImpl SysKeyboardImpl; +struct SysKeyboardImpl +{ + LPVOID lpVtbl; + DWORD ref; + GUID guid; + + IDirectInputImpl* dinput; + + HANDLE hEvent; + /* SysKeyboardAImpl */ + int acquired; + int buffersize; /* set in 'SetProperty' */ + LPDIDEVICEOBJECTDATA buffer; /* buffer for 'GetDeviceData'. + Alloc at 'Acquire', Free at + 'Unacquire' */ + int count; /* number of objects in use in + 'buffer' */ + int start; /* 'buffer' rotates. This is the + first in use (if count > 0) */ + BOOL overflow; /* return DI_BUFFEROVERFLOW in + 'GetDeviceData' */ + CRITICAL_SECTION crit; +}; + +SysKeyboardImpl *current; /* Today's acquired device +FIXME: currently this can be only one. +Maybe this should be a linked list or st. +I don't know what the rules are for multiple acquired keyboards, +but 'DI_LOSTFOCUS' and 'DI_UNACQUIRED' exist for a reason. +*/ + +static BYTE DInputKeyState[256]; /* array for 'GetDeviceState' */ + +static CRITICAL_SECTION keyboard_crit; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &keyboard_crit, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": keyboard_crit") } +}; +static CRITICAL_SECTION keyboard_crit = { &critsect_debug, -1, 0, 0, 0, 0 }; + +#ifndef __REACTOS__ +static DWORD keyboard_users; +static HHOOK keyboard_hook; +#endif + +#ifdef __REACTOS__ +void reactos_input_keyboard(); + +void reactos_input_keyboard() +{ + int disk_code = -1; + BYTE oldDInputKeyState[256]; + int t; + + memcpy(&oldDInputKeyState,&DInputKeyState,256); + GetKeyboardState(DInputKeyState); + + for( t=0;t<255;t++) + { + if (oldDInputKeyState[t]!=DInputKeyState[t]) disk_code=t; + } + + + if (disk_code!=-1) { + if (current->buffer != NULL) + { + int n; + n = (current->start + current->count) % current->buffersize; + + current->buffer[n].dwOfs = (BYTE) disk_code; + current->buffer[n].dwData = DInputKeyState[disk_code]; + current->buffer[n].dwTimeStamp = 10; + current->buffer[n].dwSequence = current->dinput->evsequence++; + + + if (current->count == current->buffersize) + { + current->start = ++current->start % current->buffersize; + current->overflow = TRUE; + } + else + current->count++; + + } + } + + +} +#endif +#ifndef __REACTOS__ +LRESULT CALLBACK KeyboardCallback( int code, WPARAM wparam, LPARAM lparam ) +{ + TRACE("(%d,%d,%ld)\n", code, wparam, lparam); + + if (code == HC_ACTION) + { + BYTE dik_code; + BOOL down; + DWORD timestamp; + + { + KBDLLHOOKSTRUCT *hook = (KBDLLHOOKSTRUCT *)lparam; + dik_code = hook->scanCode; + if (hook->flags & LLKHF_EXTENDED) dik_code |= 0x80; + down = !(hook->flags & LLKHF_UP); + timestamp = hook->time; + } + + DInputKeyState[dik_code] = (down ? 0x80 : 0); + TRACE(" setting %02X to %02X\n", dik_code, DInputKeyState[dik_code]); + + if (current != NULL) + { + if (current->hEvent) + SetEvent(current->hEvent); + + if (current->buffer != NULL) + { + int n; + + EnterCriticalSection(&(current->crit)); + + n = (current->start + current->count) % current->buffersize; + + current->buffer[n].dwOfs = dik_code; + current->buffer[n].dwData = down ? 0x80 : 0; + current->buffer[n].dwTimeStamp = timestamp; + current->buffer[n].dwSequence = current->dinput->evsequence++; + + TRACE("Adding event at offset %d : %ld - %ld - %ld - %ld\n", n, + current->buffer[n].dwOfs, current->buffer[n].dwData, current->buffer[n].dwTimeStamp, current->buffer[n].dwSequence); + + if (current->count == current->buffersize) + { + current->start = ++current->start % current->buffersize; + current->overflow = TRUE; + } + else + current->count++; + + LeaveCriticalSection(&(current->crit)); + } + } + } + + return CallNextHookEx(keyboard_hook, code, wparam, lparam); +} +#endif + +static GUID DInput_Wine_Keyboard_GUID = { /* 0ab8648a-7735-11d2-8c73-71df54a96441 */ + 0x0ab8648a, + 0x7735, + 0x11d2, + {0x8c, 0x73, 0x71, 0xdf, 0x54, 0xa9, 0x64, 0x41} +}; + +static void fill_keyboard_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, int version) { + DWORD dwSize; + DIDEVICEINSTANCEA ddi; + + dwSize = lpddi->dwSize; + + TRACE("%ld %p\n", dwSize, lpddi); + + memset(lpddi, 0, dwSize); + memset(&ddi, 0, sizeof(ddi)); + + ddi.dwSize = dwSize; + ddi.guidInstance = GUID_SysKeyboard;/* DInput's GUID */ + ddi.guidProduct = DInput_Wine_Keyboard_GUID; /* Vendor's GUID */ + if (version >= 8) + ddi.dwDevType = DI8DEVTYPE_KEYBOARD | (DI8DEVTYPEKEYBOARD_UNKNOWN << 8); + else + ddi.dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_UNKNOWN << 8); + strcpy(ddi.tszInstanceName, "Keyboard"); + strcpy(ddi.tszProductName, "Wine Keyboard"); + + memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi))); +} + +static void fill_keyboard_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, int version) { + DWORD dwSize; + DIDEVICEINSTANCEW ddi; + + dwSize = lpddi->dwSize; + + TRACE("%ld %p\n", dwSize, lpddi); + + memset(lpddi, 0, dwSize); + memset(&ddi, 0, sizeof(ddi)); + + ddi.dwSize = dwSize; + ddi.guidInstance = GUID_SysKeyboard;/* DInput's GUID */ + ddi.guidProduct = DInput_Wine_Keyboard_GUID; /* Vendor's GUID */ + if (version >= 8) + ddi.dwDevType = DI8DEVTYPE_KEYBOARD | (DI8DEVTYPEKEYBOARD_UNKNOWN << 8); + else + ddi.dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_UNKNOWN << 8); + MultiByteToWideChar(CP_ACP, 0, "Keyboard", -1, ddi.tszInstanceName, MAX_PATH); + MultiByteToWideChar(CP_ACP, 0, "Wine Keyboard", -1, ddi.tszProductName, MAX_PATH); + + memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi))); +} + +static BOOL keyboarddev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, int version, int id) +{ + if (id != 0) + return FALSE; + + if ((dwDevType == 0) || + ((dwDevType == DIDEVTYPE_KEYBOARD) && (version < 8)) || + (((dwDevType == DI8DEVCLASS_KEYBOARD) || (dwDevType == DI8DEVTYPE_KEYBOARD)) && (version >= 8))) { + TRACE("Enumerating the Keyboard device\n"); + + fill_keyboard_dideviceinstanceA(lpddi, version); + + return TRUE; + } + + return FALSE; +} + +static BOOL keyboarddev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, int version, int id) +{ + if (id != 0) + return FALSE; + + if ((dwDevType == 0) || + ((dwDevType == DIDEVTYPE_KEYBOARD) && (version < 8)) || + (((dwDevType == DI8DEVCLASS_KEYBOARD) || (dwDevType == DI8DEVTYPE_KEYBOARD)) && (version >= 8))) { + TRACE("Enumerating the Keyboard device\n"); + + fill_keyboard_dideviceinstanceW(lpddi, version); + + return TRUE; + } + + return FALSE; +} + +static SysKeyboardImpl *alloc_device_keyboard(REFGUID rguid, LPVOID kvt, IDirectInputImpl *dinput) +{ + SysKeyboardImpl* newDevice; + newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysKeyboardImpl)); + newDevice->lpVtbl = kvt; + newDevice->ref = 1; + memcpy(&(newDevice->guid),rguid,sizeof(*rguid)); + newDevice->dinput = dinput; + +#ifndef __REACTOS__ + EnterCriticalSection(&keyboard_crit); + + if (!keyboard_users++) + keyboard_hook = SetWindowsHookExW( WH_KEYBOARD_LL, KeyboardCallback, DINPUT_instance, 0 ); + + LeaveCriticalSection(&keyboard_crit); +#endif + return newDevice; +} + + +static HRESULT keyboarddev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev) +{ + if ((IsEqualGUID(&GUID_SysKeyboard,rguid)) || /* Generic Keyboard */ + (IsEqualGUID(&DInput_Wine_Keyboard_GUID,rguid))) { /* Wine Keyboard */ + if ((riid == NULL) || + IsEqualGUID(&IID_IDirectInputDeviceA,riid) || + IsEqualGUID(&IID_IDirectInputDevice2A,riid) || + IsEqualGUID(&IID_IDirectInputDevice7A,riid) || + IsEqualGUID(&IID_IDirectInputDevice8A,riid)) { + *pdev = (IDirectInputDeviceA*) alloc_device_keyboard(rguid, &SysKeyboardAvt, dinput); + TRACE("Creating a Keyboard device (%p)\n", *pdev); + return DI_OK; + } else + return DIERR_NOINTERFACE; + } + return DIERR_DEVICENOTREG; +} + +static HRESULT keyboarddev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev) +{ + if ((IsEqualGUID(&GUID_SysKeyboard,rguid)) || /* Generic Keyboard */ + (IsEqualGUID(&DInput_Wine_Keyboard_GUID,rguid))) { /* Wine Keyboard */ + if ((riid == NULL) || + IsEqualGUID(&IID_IDirectInputDeviceW,riid) || + IsEqualGUID(&IID_IDirectInputDevice2W,riid) || + IsEqualGUID(&IID_IDirectInputDevice7W,riid) || + IsEqualGUID(&IID_IDirectInputDevice8W,riid)) { + *pdev = (IDirectInputDeviceW*) alloc_device_keyboard(rguid, &SysKeyboardWvt, dinput); + TRACE("Creating a Keyboard device (%p)\n", *pdev); + return DI_OK; + } else + return DIERR_NOINTERFACE; + } + return DIERR_DEVICENOTREG; +} + +dinput_device keyboarddev = { + 100, + "Wine keyboard driver", + keyboarddev_enum_deviceA, + keyboarddev_enum_deviceW, + keyboarddev_create_deviceA, + keyboarddev_create_deviceW +}; + +void scan_keyboard() +{ + dinput_register_device(&keyboarddev); +} + +DECL_GLOBAL_CONSTRUCTOR(keyboarddev_register) { dinput_register_device(&keyboarddev); } + +static ULONG WINAPI SysKeyboardAImpl_Release(LPDIRECTINPUTDEVICE8A iface) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + ULONG ref; + + ref = InterlockedDecrement(&(This->ref)); + if (ref) + return ref; + +#ifndef __REACTOS__ + EnterCriticalSection(&keyboard_crit); + if (!--keyboard_users) { + UnhookWindowsHookEx( keyboard_hook ); + keyboard_hook = 0; + } + LeaveCriticalSection(&keyboard_crit); +#endif + + /* Free the data queue */ + HeapFree(GetProcessHeap(),0,This->buffer); + + DeleteCriticalSection(&(This->crit)); + + HeapFree(GetProcessHeap(),0,This); + return DI_OK; +} + +static HRESULT WINAPI SysKeyboardAImpl_SetProperty( + LPDIRECTINPUTDEVICE8A iface,REFGUID rguid,LPCDIPROPHEADER ph +) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + + TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph); + TRACE("(size=%ld,headersize=%ld,obj=%ld,how=%ld\n", + ph->dwSize,ph->dwHeaderSize,ph->dwObj,ph->dwHow); + if (!HIWORD(rguid)) { + switch ((DWORD)rguid) { + case (DWORD) DIPROP_BUFFERSIZE: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + + TRACE("(buffersize=%ld)\n",pd->dwData); + + if (This->acquired) + return DIERR_INVALIDPARAM; + + This->buffersize = pd->dwData; + + break; + } + default: + WARN("Unknown type %ld\n",(DWORD)rguid); + break; + } + } + return DI_OK; +} + + +static HRESULT WINAPI SysKeyboardAImpl_GetDeviceState( + LPDIRECTINPUTDEVICE8A iface,DWORD len,LPVOID ptr +) +{ + TRACE("(%p)->(%ld,%p)\n", iface, len, ptr); + +#ifdef __REACTOS__ + reactos_input_keyboard(); +#endif + + /* Note: device does not need to be acquired */ + if (len != 256) + return DIERR_INVALIDPARAM; + + MsgWaitForMultipleObjectsEx(0, NULL, 0, 0, 0); + + if (TRACE_ON(dinput)) { + int i; + for (i = 0; i < 256; i++) { + if (DInputKeyState[i] != 0x00) { + TRACE(" - %02X: %02x\n", i, DInputKeyState[i]); + } + } + } + + memcpy(ptr, DInputKeyState, 256); + return DI_OK; +} + +static HRESULT WINAPI SysKeyboardAImpl_GetDeviceData( + LPDIRECTINPUTDEVICE8A iface,DWORD dodsize,LPDIDEVICEOBJECTDATA dod, + LPDWORD entries,DWORD flags +) +{ + + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + int ret = DI_OK, i = 0; +#ifdef __REACTOS__ + reactos_input_keyboard(); +#endif + + TRACE("(this=%p,%ld,%p,%p(%ld)),0x%08lx)\n", + This,dodsize,dod,entries,entries?*entries:0,flags); + + if (This->acquired == 0) + return DIERR_NOTACQUIRED; + + if (This->buffer == NULL) + return DIERR_NOTBUFFERED; + + if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3)) + return DIERR_INVALIDPARAM; + + MsgWaitForMultipleObjectsEx(0, NULL, 0, 0, 0); + + EnterCriticalSection(&(This->crit)); + + /* Copy item at a time for the case dodsize > sizeof(buffer[n]) */ + while ((i < *entries || *entries == INFINITE) && i < This->count) + { + if (dod != NULL) + { + int n = (This->start + i) % This->buffersize; + LPDIDEVICEOBJECTDATA pd + = (LPDIDEVICEOBJECTDATA)((BYTE *)dod + dodsize * i); + pd->dwOfs = This->buffer[n].dwOfs; + pd->dwData = This->buffer[n].dwData; + pd->dwTimeStamp = This->buffer[n].dwTimeStamp; + pd->dwSequence = This->buffer[n].dwSequence; + } + i++; + } + + *entries = i; + + if (This->overflow) + ret = DI_BUFFEROVERFLOW; + + if (!(flags & DIGDD_PEEK)) + { + /* Empty buffer */ + This->count -= i; + This->start = (This->start + i) % This->buffersize; + This->overflow = FALSE; + } + + LeaveCriticalSection(&(This->crit)); + + TRACE("Returning %ld events queued\n", *entries); + + return ret; +} + +static HRESULT WINAPI SysKeyboardAImpl_EnumObjects( + LPDIRECTINPUTDEVICE8A iface, + LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + DIDEVICEOBJECTINSTANCEA ddoi; + int i; + + TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags); + if (TRACE_ON(dinput)) { + TRACE(" - flags = "); + _dump_EnumObjects_flags(dwFlags); + TRACE("\n"); + } + + /* Only the fields till dwFFMaxForce are relevant */ + memset(&ddoi, 0, sizeof(ddoi)); + ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce); + + for (i = 0; i < 256; i++) { + /* Report 255 keys :-) */ + ddoi.guidType = GUID_Key; + ddoi.dwOfs = i; + ddoi.dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_BUTTON; + GetKeyNameTextA(((i & 0x7f) << 16) | ((i & 0x80) << 17), ddoi.tszName, sizeof(ddoi.tszName)); + _dump_OBJECTINSTANCEA(&ddoi); + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; + } + + return DI_OK; +} + +static HRESULT WINAPI SysKeyboardWImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface, + LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + + device_enumobjects_AtoWcb_data data; + + data.lpCallBack = lpCallback; + data.lpvRef = lpvRef; + + return SysKeyboardAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags); +} + +static HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface); + +static HRESULT WINAPI SysKeyboardAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + + TRACE("(this=%p)\n",This); + + if (This->acquired) + return S_FALSE; + + This->acquired = 1; + + if (current != NULL) + { + FIXME("Not more than one keyboard can be acquired at the same time.\n"); + SysKeyboardAImpl_Unacquire(iface); + } + + current = This; + + if (This->buffersize > 0) + { + This->buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + This->buffersize * sizeof(*(This->buffer))); + This->start = 0; + This->count = 0; + This->overflow = FALSE; + InitializeCriticalSection(&(This->crit)); + } + else + This->buffer = NULL; + + + return DI_OK; +} + +static HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + TRACE("(this=%p)\n",This); + + if (This->acquired == 0) + return DI_NOEFFECT; + + if (current == This) + current = NULL; + else + ERR("this != current\n"); + + This->acquired = 0; + + if (This->buffersize >= 0) + { + HeapFree(GetProcessHeap(), 0, This->buffer); + This->buffer = NULL; + DeleteCriticalSection(&(This->crit)); + } + + return DI_OK; +} + +static HRESULT WINAPI SysKeyboardAImpl_SetEventNotification(LPDIRECTINPUTDEVICE8A iface, + HANDLE hnd) { + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + + TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd); + + This->hEvent = hnd; + return DI_OK; +} + +/****************************************************************************** + * GetCapabilities : get the device capablitites + */ +static HRESULT WINAPI SysKeyboardAImpl_GetCapabilities( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVCAPS lpDIDevCaps) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + DIDEVCAPS devcaps; + + TRACE("(this=%p,%p)\n",This,lpDIDevCaps); + + if ((lpDIDevCaps->dwSize != sizeof(DIDEVCAPS)) && (lpDIDevCaps->dwSize != sizeof(DIDEVCAPS_DX3))) { + WARN("invalid parameter\n"); + return DIERR_INVALIDPARAM; + } + + devcaps.dwSize = lpDIDevCaps->dwSize; + devcaps.dwFlags = DIDC_ATTACHED; + if (This->dinput->version >= 8) + devcaps.dwDevType = DI8DEVTYPE_KEYBOARD | (DI8DEVTYPEKEYBOARD_UNKNOWN << 8); + else + devcaps.dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_UNKNOWN << 8); + devcaps.dwAxes = 0; + devcaps.dwButtons = 256; + devcaps.dwPOVs = 0; + devcaps.dwFFSamplePeriod = 0; + devcaps.dwFFMinTimeResolution = 0; + devcaps.dwFirmwareRevision = 100; + devcaps.dwHardwareRevision = 100; + devcaps.dwFFDriverVersion = 0; + + memcpy(lpDIDevCaps, &devcaps, lpDIDevCaps->dwSize); + + return DI_OK; +} + +/****************************************************************************** + * GetObjectInfo : get information about a device object such as a button + * or axis + */ +static HRESULT WINAPI +SysKeyboardAImpl_GetObjectInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEOBJECTINSTANCEA pdidoi, + DWORD dwObj, + DWORD dwHow) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + DIDEVICEOBJECTINSTANCEA ddoi; + DWORD dwSize = pdidoi->dwSize; + + TRACE("(this=%p,%p,%ld,0x%08lx)\n", This, pdidoi, dwObj, dwHow); + + if (dwHow == DIPH_BYID) { + WARN(" querying by id not supported yet...\n"); + return DI_OK; + } + + memset(pdidoi, 0, dwSize); + memset(&ddoi, 0, sizeof(ddoi)); + + ddoi.dwSize = dwSize; + ddoi.guidType = GUID_Key; + ddoi.dwOfs = dwObj; + ddoi.dwType = DIDFT_MAKEINSTANCE(dwObj) | DIDFT_BUTTON; + GetKeyNameTextA(((dwObj & 0x7f) << 16) | ((dwObj & 0x80) << 17), ddoi.tszName, sizeof(ddoi.tszName)); + + /* And return our just filled device object instance structure */ + memcpy(pdidoi, &ddoi, (dwSize < sizeof(ddoi) ? dwSize : sizeof(ddoi))); + + _dump_OBJECTINSTANCEA(pdidoi); + + return DI_OK; +} + +static HRESULT WINAPI SysKeyboardWImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface, + LPDIDEVICEOBJECTINSTANCEW pdidoi, + DWORD dwObj, + DWORD dwHow) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + DIDEVICEOBJECTINSTANCEW ddoi; + DWORD dwSize = pdidoi->dwSize; + + TRACE("(this=%p,%p,%ld,0x%08lx)\n", This, pdidoi, dwObj, dwHow); + + if (dwHow == DIPH_BYID) { + WARN(" querying by id not supported yet...\n"); + return DI_OK; + } + + memset(pdidoi, 0, dwSize); + memset(&ddoi, 0, sizeof(ddoi)); + + ddoi.dwSize = dwSize; + ddoi.guidType = GUID_Key; + ddoi.dwOfs = dwObj; + ddoi.dwType = DIDFT_MAKEINSTANCE(dwObj) | DIDFT_BUTTON; + GetKeyNameTextW(((dwObj & 0x7f) << 16) | ((dwObj & 0x80) << 17), ddoi.tszName, sizeof(ddoi.tszName)); + + /* And return our just filled device object instance structure */ + memcpy(pdidoi, &ddoi, (dwSize < sizeof(ddoi) ? dwSize : sizeof(ddoi))); + + _dump_OBJECTINSTANCEW(pdidoi); + + return DI_OK; +} + +/****************************************************************************** + * GetDeviceInfo : get information about a device's identity + */ +static HRESULT WINAPI SysKeyboardAImpl_GetDeviceInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEINSTANCEA pdidi) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + TRACE("(this=%p,%p)\n", This, pdidi); + + if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA)) { + WARN(" dinput3 not supporte yet...\n"); + return DI_OK; + } + + fill_keyboard_dideviceinstanceA(pdidi, This->dinput->version); + + return DI_OK; +} + +static HRESULT WINAPI SysKeyboardWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, LPDIDEVICEINSTANCEW pdidi) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + TRACE("(this=%p,%p)\n", This, pdidi); + + if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW)) { + WARN(" dinput3 not supporte yet...\n"); + return DI_OK; + } + + fill_keyboard_dideviceinstanceW(pdidi, This->dinput->version); + + return DI_OK; +} + +static IDirectInputDevice8AVtbl SysKeyboardAvt = +{ + IDirectInputDevice2AImpl_QueryInterface, + IDirectInputDevice2AImpl_AddRef, + SysKeyboardAImpl_Release, + SysKeyboardAImpl_GetCapabilities, + SysKeyboardAImpl_EnumObjects, + IDirectInputDevice2AImpl_GetProperty, + SysKeyboardAImpl_SetProperty, + SysKeyboardAImpl_Acquire, + SysKeyboardAImpl_Unacquire, + SysKeyboardAImpl_GetDeviceState, + SysKeyboardAImpl_GetDeviceData, + IDirectInputDevice2AImpl_SetDataFormat, + SysKeyboardAImpl_SetEventNotification, + IDirectInputDevice2AImpl_SetCooperativeLevel, + SysKeyboardAImpl_GetObjectInfo, + SysKeyboardAImpl_GetDeviceInfo, + IDirectInputDevice2AImpl_RunControlPanel, + IDirectInputDevice2AImpl_Initialize, + IDirectInputDevice2AImpl_CreateEffect, + IDirectInputDevice2AImpl_EnumEffects, + IDirectInputDevice2AImpl_GetEffectInfo, + IDirectInputDevice2AImpl_GetForceFeedbackState, + IDirectInputDevice2AImpl_SendForceFeedbackCommand, + IDirectInputDevice2AImpl_EnumCreatedEffectObjects, + IDirectInputDevice2AImpl_Escape, + IDirectInputDevice2AImpl_Poll, + IDirectInputDevice2AImpl_SendDeviceData, + IDirectInputDevice7AImpl_EnumEffectsInFile, + IDirectInputDevice7AImpl_WriteEffectToFile, + IDirectInputDevice8AImpl_BuildActionMap, + IDirectInputDevice8AImpl_SetActionMap, + IDirectInputDevice8AImpl_GetImageInfo +}; + +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(SysKeyboardWvt.fun)) +#else +# define XCAST(fun) (void*) +#endif + +static IDirectInputDevice8WVtbl SysKeyboardWvt = +{ + IDirectInputDevice2WImpl_QueryInterface, + XCAST(AddRef)IDirectInputDevice2AImpl_AddRef, + XCAST(Release)SysKeyboardAImpl_Release, + XCAST(GetCapabilities)SysKeyboardAImpl_GetCapabilities, + SysKeyboardWImpl_EnumObjects, + XCAST(GetProperty)IDirectInputDevice2AImpl_GetProperty, + XCAST(SetProperty)SysKeyboardAImpl_SetProperty, + XCAST(Acquire)SysKeyboardAImpl_Acquire, + XCAST(Unacquire)SysKeyboardAImpl_Unacquire, + XCAST(GetDeviceState)SysKeyboardAImpl_GetDeviceState, + XCAST(GetDeviceData)SysKeyboardAImpl_GetDeviceData, + XCAST(SetDataFormat)IDirectInputDevice2AImpl_SetDataFormat, + XCAST(SetEventNotification)SysKeyboardAImpl_SetEventNotification, + XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel, + SysKeyboardWImpl_GetObjectInfo, + SysKeyboardWImpl_GetDeviceInfo, + XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel, + XCAST(Initialize)IDirectInputDevice2AImpl_Initialize, + XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect, + IDirectInputDevice2WImpl_EnumEffects, + IDirectInputDevice2WImpl_GetEffectInfo, + XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState, + XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand, + XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects, + XCAST(Escape)IDirectInputDevice2AImpl_Escape, + XCAST(Poll)IDirectInputDevice2AImpl_Poll, + XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData, + IDirectInputDevice7WImpl_EnumEffectsInFile, + IDirectInputDevice7WImpl_WriteEffectToFile, + IDirectInputDevice8WImpl_BuildActionMap, + IDirectInputDevice8WImpl_SetActionMap, + IDirectInputDevice8WImpl_GetImageInfo +}; +#undef XCAST diff --git a/reactos/lib/dinput/mouse.c b/reactos/lib/dinput/mouse.c index c628dbb59d9..d1d11a50f2c 100644 --- a/reactos/lib/dinput/mouse.c +++ b/reactos/lib/dinput/mouse.c @@ -1,1297 +1,1297 @@ -/* DirectInput Mouse device - * - * Copyright 1998 Marcus Meissner - * Copyright 1998,1999 Lionel Ulmer - * Copyright 2000-2001 TransGaming Technologies Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" -#include "wine/port.h" - -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winerror.h" -#include "dinput.h" - -#include "dinput_private.h" -#include "device_private.h" -#include "wine/debug.h" -#include "wine/unicode.h" - -#define MOUSE_HACK - -WINE_DEFAULT_DEBUG_CHANNEL(dinput); - - -/* Wine mouse driver object instances */ -#define WINE_MOUSE_X_AXIS_INSTANCE 0 -#define WINE_MOUSE_Y_AXIS_INSTANCE 1 -#define WINE_MOUSE_Z_AXIS_INSTANCE 2 -#define WINE_MOUSE_L_BUTTON_INSTANCE 0 -#define WINE_MOUSE_R_BUTTON_INSTANCE 1 -#define WINE_MOUSE_M_BUTTON_INSTANCE 2 -#define WINE_MOUSE_D_BUTTON_INSTANCE 3 - -/* ------------------------------- */ -/* Wine mouse internal data format */ -/* ------------------------------- */ - -/* Constants used to access the offset array */ -#define WINE_MOUSE_X_POSITION 0 -#define WINE_MOUSE_Y_POSITION 1 -#define WINE_MOUSE_Z_POSITION 2 -#define WINE_MOUSE_L_POSITION 3 -#define WINE_MOUSE_R_POSITION 4 -#define WINE_MOUSE_M_POSITION 5 - -typedef struct { - LONG lX; - LONG lY; - LONG lZ; - BYTE rgbButtons[4]; -} Wine_InternalMouseData; - -#define WINE_INTERNALMOUSE_NUM_OBJS 6 - -static const DIOBJECTDATAFORMAT Wine_InternalMouseObjectFormat[WINE_INTERNALMOUSE_NUM_OBJS] = { - { &GUID_XAxis, FIELD_OFFSET(Wine_InternalMouseData, lX), - DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 }, - { &GUID_YAxis, FIELD_OFFSET(Wine_InternalMouseData, lY), - DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 }, - { &GUID_ZAxis, FIELD_OFFSET(Wine_InternalMouseData, lZ), - DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 }, - { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 0, - DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 }, - { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 1, - DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 }, - { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 2, - DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 } -}; - -static const DIDATAFORMAT Wine_InternalMouseFormat = { - 0, /* dwSize - unused */ - 0, /* dwObjsize - unused */ - 0, /* dwFlags - unused */ - sizeof(Wine_InternalMouseData), - WINE_INTERNALMOUSE_NUM_OBJS, /* dwNumObjs */ - (LPDIOBJECTDATAFORMAT) Wine_InternalMouseObjectFormat -}; - -static IDirectInputDevice8AVtbl SysMouseAvt; -static IDirectInputDevice8WVtbl SysMouseWvt; - -typedef struct SysMouseImpl SysMouseImpl; - -typedef enum { - WARP_DONE, /* Warping has been done */ - WARP_NEEDED, /* Warping is needed */ - WARP_STARTED /* Warping has been done, waiting for the warp event */ -} WARP_STATUS; - -struct SysMouseImpl -{ - LPVOID lpVtbl; - DWORD ref; - GUID guid; - - IDirectInputImpl *dinput; - - /* The current data format and the conversion between internal - and external data formats */ - DIDATAFORMAT *df; - DataFormat *wine_df; - int offset_array[WINE_INTERNALMOUSE_NUM_OBJS]; - - /* SysMouseAImpl */ - BYTE absolute; - /* Previous position for relative moves */ - LONG prevX, prevY; - /* These are used in case of relative -> absolute transitions */ - POINT org_coords; - HHOOK hook; - HWND win; - DWORD dwCoopLevel; - POINT mapped_center; - DWORD win_centerX, win_centerY; - LPDIDEVICEOBJECTDATA data_queue; - int queue_head, queue_tail, queue_len; - BOOL overflow; - /* warping: whether we need to move mouse back to middle once we - * reach window borders (for e.g. shooters, "surface movement" games) */ - WARP_STATUS need_warp; - int acquired; - HANDLE hEvent; - CRITICAL_SECTION crit; - - /* This is for mouse reporting. */ - Wine_InternalMouseData m_state; -}; - -/* FIXME: This is ugly and not thread safe :/ */ -static IDirectInputDevice8A* current_lock = NULL; - -/* FIXME: This is ugly but needed on Windows */ -static int mouse_set = 0; - -static GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */ - 0x9e573ed8, - 0x7734, - 0x11d2, - {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7} -}; - -static void fill_mouse_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, int version) { - DWORD dwSize; - DIDEVICEINSTANCEA ddi; - - dwSize = lpddi->dwSize; - - TRACE("%ld %p\n", dwSize, lpddi); - - memset(lpddi, 0, dwSize); - memset(&ddi, 0, sizeof(ddi)); - - ddi.dwSize = dwSize; - ddi.guidInstance = GUID_SysMouse;/* DInput's GUID */ - ddi.guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */ - if (version >= 8) - ddi.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8); - else - ddi.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8); - strcpy(ddi.tszInstanceName, "Mouse"); - strcpy(ddi.tszProductName, "Wine Mouse"); - - memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi))); -} - -static void fill_mouse_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, int version) { - DWORD dwSize; - DIDEVICEINSTANCEW ddi; - - dwSize = lpddi->dwSize; - - TRACE("%ld %p\n", dwSize, lpddi); - - memset(lpddi, 0, dwSize); - memset(&ddi, 0, sizeof(ddi)); - - ddi.dwSize = dwSize; - ddi.guidInstance = GUID_SysMouse;/* DInput's GUID */ - ddi.guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */ - if (version >= 8) - ddi.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8); - else - ddi.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8); - MultiByteToWideChar(CP_ACP, 0, "Mouse", -1, ddi.tszInstanceName, MAX_PATH); - MultiByteToWideChar(CP_ACP, 0, "Wine Mouse", -1, ddi.tszProductName, MAX_PATH); - - memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi))); -} - -static BOOL mousedev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, int version, int id) -{ - if (id != 0) - return FALSE; - - if ((dwDevType == 0) || - ((dwDevType == DIDEVTYPE_MOUSE) && (version < 8)) || - (((dwDevType == DI8DEVCLASS_POINTER) || (dwDevType == DI8DEVTYPE_MOUSE)) && (version >= 8))) { - TRACE("Enumerating the mouse device\n"); - - fill_mouse_dideviceinstanceA(lpddi, version); - - return TRUE; - } - - return FALSE; -} - -static BOOL mousedev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, int version, int id) -{ - if (id != 0) - return FALSE; - - if ((dwDevType == 0) || - ((dwDevType == DIDEVTYPE_MOUSE) && (version < 8)) || - (((dwDevType == DI8DEVCLASS_POINTER) || (dwDevType == DI8DEVTYPE_MOUSE)) && (version >= 8))) { - TRACE("Enumerating the mouse device\n"); - - fill_mouse_dideviceinstanceW(lpddi, version); - - return TRUE; - } - - return FALSE; -} - -static SysMouseImpl *alloc_device_mouse(REFGUID rguid, LPVOID mvt, IDirectInputImpl *dinput) -{ - int offset_array[WINE_INTERNALMOUSE_NUM_OBJS] = { - FIELD_OFFSET(Wine_InternalMouseData, lX), - FIELD_OFFSET(Wine_InternalMouseData, lY), - FIELD_OFFSET(Wine_InternalMouseData, lZ), - FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 0, - FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 1, - FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 2 - }; - SysMouseImpl* newDevice; - newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouseImpl)); - newDevice->ref = 1; - newDevice->lpVtbl = mvt; -#ifndef __REACTOS__ - InitializeCriticalSection(&(newDevice->crit)); -#endif - memcpy(&(newDevice->guid),rguid,sizeof(*rguid)); - - /* Per default, Wine uses its internal data format */ - newDevice->df = (DIDATAFORMAT *) &Wine_InternalMouseFormat; - memcpy(newDevice->offset_array, offset_array, WINE_INTERNALMOUSE_NUM_OBJS * sizeof(int)); - newDevice->wine_df = (DataFormat *) HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat)); - newDevice->wine_df->size = 0; - newDevice->wine_df->internal_format_size = Wine_InternalMouseFormat.dwDataSize; - newDevice->wine_df->dt = NULL; - newDevice->dinput = dinput; - - return newDevice; -} - -static HRESULT mousedev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev) -{ - if ((IsEqualGUID(&GUID_SysMouse,rguid)) || /* Generic Mouse */ - (IsEqualGUID(&DInput_Wine_Mouse_GUID,rguid))) { /* Wine Mouse */ - if ((riid == NULL) || - IsEqualGUID(&IID_IDirectInputDeviceA,riid) || - IsEqualGUID(&IID_IDirectInputDevice2A,riid) || - IsEqualGUID(&IID_IDirectInputDevice7A,riid) || - IsEqualGUID(&IID_IDirectInputDevice8A,riid)) { - *pdev = (IDirectInputDeviceA*) alloc_device_mouse(rguid, &SysMouseAvt, dinput); - TRACE("Creating a Mouse device (%p)\n", *pdev); - return DI_OK; - } else - return DIERR_NOINTERFACE; - } - - return DIERR_DEVICENOTREG; -} - -static HRESULT mousedev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev) -{ - if ((IsEqualGUID(&GUID_SysMouse,rguid)) || /* Generic Mouse */ - (IsEqualGUID(&DInput_Wine_Mouse_GUID,rguid))) { /* Wine Mouse */ - if ((riid == NULL) || - IsEqualGUID(&IID_IDirectInputDeviceW,riid) || - IsEqualGUID(&IID_IDirectInputDevice2W,riid) || - IsEqualGUID(&IID_IDirectInputDevice7W,riid) || - IsEqualGUID(&IID_IDirectInputDevice8W,riid)) { - *pdev = (IDirectInputDeviceW*) alloc_device_mouse(rguid, &SysMouseWvt, dinput); - TRACE("Creating a Mouse device (%p)\n", *pdev); - return DI_OK; - } else - return DIERR_NOINTERFACE; - } - - return DIERR_DEVICENOTREG; -} - -static dinput_device mousedev = { - 100, - "Wine mouse driver", - mousedev_enum_deviceA, - mousedev_enum_deviceW, - mousedev_create_deviceA, - mousedev_create_deviceW -}; - -#ifdef __REACTOS__ -void scan_mouse() -{ - dinput_register_device(&mousedev); -} - -DECL_GLOBAL_CONSTRUCTOR(mousedev_register) { dinput_register_device(&mousedev); } -#endif - -/****************************************************************************** - * SysMouseA (DInput Mouse support) - */ - -/****************************************************************************** - * Release : release the mouse buffer. - */ -static ULONG WINAPI SysMouseAImpl_Release(LPDIRECTINPUTDEVICE8A iface) -{ - SysMouseImpl *This = (SysMouseImpl *)iface; - ULONG ref; - - ref = InterlockedDecrement(&(This->ref)); - if (ref) - return ref; - - /* Free the data queue */ - HeapFree(GetProcessHeap(),0,This->data_queue); - - - if (This->hook) { - UnhookWindowsHookEx( This->hook ); - if (This->dwCoopLevel & DISCL_EXCLUSIVE) - ShowCursor(TRUE); /* show cursor */ - } -#ifndef __REACTOS__ - DeleteCriticalSection(&(This->crit)); -#endif - - /* Free the DataFormat */ - if (This->df != &(Wine_InternalMouseFormat)) { - HeapFree(GetProcessHeap(), 0, This->df->rgodf); - HeapFree(GetProcessHeap(), 0, This->df); - } - - HeapFree(GetProcessHeap(),0,This); - return 0; -} - - -/****************************************************************************** - * SetCooperativeLevel : store the window in which we will do our - * grabbing. - */ -static HRESULT WINAPI SysMouseAImpl_SetCooperativeLevel( - LPDIRECTINPUTDEVICE8A iface,HWND hwnd,DWORD dwflags -) -{ - SysMouseImpl *This = (SysMouseImpl *)iface; - - TRACE("(this=%p,0x%08lx,0x%08lx)\n",This,(DWORD)hwnd,dwflags); - - if (TRACE_ON(dinput)) { - TRACE(" cooperative level : "); - _dump_cooperativelevel_DI(dwflags); - } - - /* Store the window which asks for the mouse */ - if (!hwnd) - hwnd = GetDesktopWindow(); - This->win = hwnd; - This->dwCoopLevel = dwflags; - - return DI_OK; -} - - -/****************************************************************************** - * SetDataFormat : the application can choose the format of the data - * the device driver sends back with GetDeviceState. - * - * For the moment, only the "standard" configuration (c_dfDIMouse) is supported - * in absolute and relative mode. - */ -static HRESULT WINAPI SysMouseAImpl_SetDataFormat( - LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df -) -{ - SysMouseImpl *This = (SysMouseImpl *)iface; - - TRACE("(this=%p,%p)\n",This,df); - - _dump_DIDATAFORMAT(df); - - /* Tests under windows show that a call to SetDataFormat always sets the mouse - in relative mode whatever the dwFlags value (DIDF_ABSAXIS/DIDF_RELAXIS). - To switch in absolute mode, SetProperty must be used. */ - This->absolute = 0; - - /* Store the new data format */ - This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize); - memcpy(This->df, df, df->dwSize); - This->df->rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize); - memcpy(This->df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize); - - /* Prepare all the data-conversion filters */ - This->wine_df = create_DataFormat(&(Wine_InternalMouseFormat), df, This->offset_array); - - return DI_OK; -} - -/* low-level mouse hook */ -static LRESULT CALLBACK dinput_mouse_hook( int code, WPARAM wparam, LPARAM lparam ) -{ - LRESULT ret; - MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam; - SysMouseImpl* This = (SysMouseImpl*) current_lock; - DWORD dwCoop; - static long last_event = 0; - int wdata; - - if (code != HC_ACTION) return CallNextHookEx( This->hook, code, wparam, lparam ); - -#ifndef __REACTOS__ - EnterCriticalSection(&(This->crit)); -#endif - - dwCoop = This->dwCoopLevel; - - /* Only allow mouse events every 10 ms. - * This is to allow the cursor to start acceleration before - * the warps happen. But if it involves a mouse button event we - * allow it since we don't want to lose the clicks. - */ - if (((GetCurrentTime() - last_event) < 10) - && wparam == WM_MOUSEMOVE) - goto end; - else last_event = GetCurrentTime(); - - /* Mouse moved -> send event if asked */ - if (This->hEvent) - SetEvent(This->hEvent); - - if (wparam == WM_MOUSEMOVE) { - if (This->absolute) { - if (hook->pt.x != This->prevX) - GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x, hook->time, 0); - if (hook->pt.y != This->prevY) - GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y, hook->time, 0); - } else { - /* Now, warp handling */ - if ((This->need_warp == WARP_STARTED) && - (hook->pt.x == This->mapped_center.x) && (hook->pt.y == This->mapped_center.y)) { - /* Warp has been done... */ - This->need_warp = WARP_DONE; - goto end; - } - - /* Relative mouse input with absolute mouse event : the real fun starts here... */ - if ((This->need_warp == WARP_NEEDED) || - (This->need_warp == WARP_STARTED)) { - if (hook->pt.x != This->prevX) - GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->prevX, - hook->time, (This->dinput->evsequence)++); - if (hook->pt.y != This->prevY) - GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->prevY, - hook->time, (This->dinput->evsequence)++); - } else { - /* This is the first time the event handler has been called after a - GetDeviceData or GetDeviceState. */ - if (hook->pt.x != This->mapped_center.x) { - GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->mapped_center.x, - hook->time, (This->dinput->evsequence)++); - This->need_warp = WARP_NEEDED; - } - - if (hook->pt.y != This->mapped_center.y) { - GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->mapped_center.y, - hook->time, (This->dinput->evsequence)++); - This->need_warp = WARP_NEEDED; - } - } - } - - This->prevX = hook->pt.x; - This->prevY = hook->pt.y; - - if (This->absolute) { - This->m_state.lX = hook->pt.x; - This->m_state.lY = hook->pt.y; - } else { - This->m_state.lX = hook->pt.x - This->mapped_center.x; - This->m_state.lY = hook->pt.y - This->mapped_center.y; - } - } - - TRACE(" msg %x pt %ld %ld (W=%d)\n", - wparam, hook->pt.x, hook->pt.y, (!This->absolute) && This->need_warp ); - - switch(wparam) { - case WM_LBUTTONDOWN: - GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0x80, - hook->time, This->dinput->evsequence++); - This->m_state.rgbButtons[0] = 0x80; - break; - case WM_LBUTTONUP: - GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0x00, - hook->time, This->dinput->evsequence++); - This->m_state.rgbButtons[0] = 0x00; - break; - case WM_RBUTTONDOWN: - GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0x80, - hook->time, This->dinput->evsequence++); - This->m_state.rgbButtons[1] = 0x80; - break; - case WM_RBUTTONUP: - GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0x00, - hook->time, This->dinput->evsequence++); - This->m_state.rgbButtons[1] = 0x00; - break; - case WM_MBUTTONDOWN: - GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0x80, - hook->time, This->dinput->evsequence++); - This->m_state.rgbButtons[2] = 0x80; - break; - case WM_MBUTTONUP: - GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0x00, - hook->time, This->dinput->evsequence++); - This->m_state.rgbButtons[2] = 0x00; - break; - case WM_MOUSEWHEEL: - wdata = (short)HIWORD(hook->mouseData); - GEN_EVENT(This->offset_array[WINE_MOUSE_Z_POSITION], wdata, - hook->time, This->dinput->evsequence++); - This->m_state.lZ += wdata; - break; - } - - TRACE("(X: %ld - Y: %ld L: %02x M: %02x R: %02x)\n", - This->m_state.lX, This->m_state.lY, - This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]); - - end: -#ifndef __REACTOS__ - LeaveCriticalSection(&(This->crit)); -#endif - - if (dwCoop & DISCL_NONEXCLUSIVE) { - /* Pass the events down to previous handlers (e.g. win32 input) */ - ret = CallNextHookEx( This->hook, code, wparam, lparam ); - } else { - /* Ignore message */ - ret = 1; - } - return ret; -} - - -static void dinput_window_check(SysMouseImpl* This) { - RECT rect; - DWORD centerX, centerY; - - /* make sure the window hasn't moved */ - GetWindowRect(This->win, &rect); - centerX = (rect.right - rect.left) / 2; - centerY = (rect.bottom - rect.top ) / 2; - if (This->win_centerX != centerX || This->win_centerY != centerY) { - This->win_centerX = centerX; - This->win_centerY = centerY; - } - This->mapped_center.x = This->win_centerX; - This->mapped_center.y = This->win_centerY; - MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1); -} - - -/****************************************************************************** - * Acquire : gets exclusive control of the mouse - */ -static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) -{ - SysMouseImpl *This = (SysMouseImpl *)iface; - RECT rect; - - TRACE("(this=%p)\n",This); - - - - if (This->acquired == 0) { - POINT point; - - - - /* Store (in a global variable) the current lock */ - current_lock = (IDirectInputDevice8A*)This; - - /* Init the mouse state */ - GetCursorPos( &point ); - if (This->absolute) { - This->m_state.lX = point.x; - This->m_state.lY = point.y; - This->prevX = point.x; - This->prevY = point.y; - } else { - This->m_state.lX = 0; - This->m_state.lY = 0; - This->org_coords = point; - } - This->m_state.lZ = 0; - This->m_state.rgbButtons[0] = ((GetKeyState(VK_LBUTTON) & 0x80) ? 0xFF : 0x00); - This->m_state.rgbButtons[1] = ((GetKeyState(VK_RBUTTON) & 0x80) ? 0xFF : 0x00); - This->m_state.rgbButtons[2] = ((GetKeyState(VK_MBUTTON) & 0x80) ? 0xFF : 0x00); - - /* Install our mouse hook */ - if (This->dwCoopLevel & DISCL_EXCLUSIVE) - ShowCursor(FALSE); /* hide cursor */ - - This->hook = SetWindowsHookExA( WH_MOUSE_LL, dinput_mouse_hook, DINPUT_instance, 0 ); - - /* Get the window dimension and find the center */ - GetWindowRect(This->win, &rect); - This->win_centerX = (rect.right - rect.left) / 2; - This->win_centerY = (rect.bottom - rect.top ) / 2; - - /* Warp the mouse to the center of the window */ - if (This->absolute == 0) { - This->mapped_center.x = This->win_centerX; - This->mapped_center.y = This->win_centerY; - MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1); - TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y); - SetCursorPos( This->mapped_center.x, This->mapped_center.y ); -#ifdef MOUSE_HACK - This->need_warp = WARP_DONE; -#else - This->need_warp = WARP_STARTED; -#endif - } - - This->acquired = 1; - return DI_OK; - } - return S_FALSE; -} - -/****************************************************************************** - * Unacquire : frees the mouse - */ -static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) -{ - SysMouseImpl *This = (SysMouseImpl *)iface; - - TRACE("(this=%p)\n",This); - - if (This->acquired) { - /* Reinstall previous mouse event handler */ - - - if (This->hook) { - UnhookWindowsHookEx( This->hook ); - This->hook = 0; - - if (This->dwCoopLevel & DISCL_EXCLUSIVE) - ShowCursor(TRUE); /* show cursor */ - } - - /* No more locks */ - current_lock = NULL; - - /* Unacquire device */ - This->acquired = 0; - - /* And put the mouse cursor back where it was at acquire time */ - if (This->absolute == 0) { - TRACE(" warping mouse back to (%ld , %ld)\n", This->org_coords.x, This->org_coords.y); - SetCursorPos(This->org_coords.x, This->org_coords.y); - } - } else { - return DI_NOEFFECT; - } - - return DI_OK; -} - -// if you call poll then to getdevicestate -// it did not send back right value in windows -int poll_mouse=0; - -#ifdef __REACTOS__ -void getmousesvalue(LPDIRECTINPUTDEVICE8A iface); -int filp=0; -void getmousesvalue(LPDIRECTINPUTDEVICE8A iface) -{ - POINT point; - SysMouseImpl *This = (SysMouseImpl *)iface; - - This->m_state.rgbButtons[0] = ((GetKeyState(VK_LBUTTON) & 0x80) ? 0xFF : 0x00); - This->m_state.rgbButtons[1] = ((GetKeyState(VK_RBUTTON) & 0x80) ? 0xFF : 0x00); - This->m_state.rgbButtons[2] = ((GetKeyState(VK_MBUTTON) & 0x80) ? 0xFF : 0x00); - This->m_state.rgbButtons[3] = ((GetKeyState(VK_XBUTTON1) & 0x80) ? 0xFF : 0x00); - This->m_state.rgbButtons[4] = ((GetKeyState(VK_XBUTTON2) & 0x80) ? 0xFF : 0x00); - - - - - if (poll_mouse==1) filp=0; - if (filp==2) filp=0; - if (filp==0) { - GetCursorPos( &point ); - - if (This->prevX == point.x) This->m_state.lX = 0; - else { - This->prevX = point.x; - This->m_state.lX = point.x - This->org_coords.x; - } - - if (This->prevY == point.y) This->m_state.lY = 0; - else { - This->prevY = point.y; - This->m_state.lY = point.y - This->org_coords.y; - } - - } - else - { - This->m_state.lX = 0; - This->m_state.lY = 0; - } - filp++; - -// check see if buffer have been set - -} - -#endif - -static HRESULT WINAPI SysMouseAImpl_Poll(LPDIRECTINPUTDEVICE8A iface) -{ - int retValue = DI_OK; - - if (poll_mouse==0) { - retValue=SysMouseAImpl_Acquire(iface); - poll_mouse=1; - if (retValue!=DI_OK) retValue=DIERR_NOTACQUIRED; - else retValue = DI_OK; - } - - return retValue; -} - - -/****************************************************************************** - * GetDeviceState : returns the "state" of the mouse. - * - * For the moment, only the "standard" return structure (DIMOUSESTATE) is - * supported. - */ -static HRESULT WINAPI SysMouseAImpl_GetDeviceState( - LPDIRECTINPUTDEVICE8A iface,DWORD len,LPVOID ptr -) { - SysMouseImpl *This = (SysMouseImpl *)iface; - -#ifndef __REACTOS__ - EnterCriticalSection(&(This->crit)); -#endif - - TRACE("(this=%p,0x%08lx,%p): \n",This,len,ptr); - - /* Copy the current mouse state */ - fill_DataFormat(ptr, &(This->m_state), This->wine_df); - -#ifdef __REACTOS__ - // this fix windows bugs when - // some program calling on mouse poll - if (poll_mouse==1) poll_mouse=0; - else { - if (This->absolute == 0) { - This->m_state.lX = 0; - This->m_state.lY = 0; - This->m_state.lZ = 0; - } - } -#endif - - /* Check if we need to do a mouse warping */ - if (This->need_warp == WARP_NEEDED) { - dinput_window_check(This); - TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y); - if (mouse_set==0){ - SetCursorPos( This->mapped_center.x, This->mapped_center.y ); - mouse_set++; - } - -#ifdef MOUSE_HACK - This->need_warp = WARP_DONE; -#else - This->need_warp = WARP_STARTED; -#endif - } - -#ifndef __REACTOS__ - LeaveCriticalSection(&(This->crit)); -#endif - - TRACE("(X: %ld - Y: %ld - Z: %ld L: %02x M: %02x R: %02x)\n", - This->m_state.lX, This->m_state.lY, This->m_state.lZ, - This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]); - - return DI_OK; -} - -/****************************************************************************** - * GetDeviceState : gets buffered input data. - */ - - -static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface, - DWORD dodsize, - LPDIDEVICEOBJECTDATA dod, - LPDWORD entries, - DWORD flags -) { - SysMouseImpl *This = (SysMouseImpl *)iface; - DWORD len; - int nqtail; - - - TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags); - - - if (This->acquired == 0) { - WARN(" application tries to get data from an unacquired device !\n"); - //return DIERR_NOTACQUIRED; - - // windows does not get any data if - // we do not call manual to mouse Acquire - // this is only need if some apps calling on getdevice data direcly - // in windows GetdeviceData does always update first the data - // then return it. - SysMouseAImpl_Acquire(iface); - } - - - - - - - -#ifndef __REACTOS__ - EnterCriticalSection(&(This->crit)); -#endif - - // FIXME mouse are bit choppy here. - - len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0) - + (This->queue_head - This->queue_tail); - if (len > *entries) len = *entries; - - if (dod == NULL) { - if (len) - TRACE("Application discarding %ld event(s).\n", len); - - *entries = len; - nqtail = This->queue_tail + len; - while (nqtail >= This->queue_len) nqtail -= This->queue_len; - } else { - if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3)) { - ERR("Wrong structure size !\n"); - - LeaveCriticalSection(&(This->crit)); - - return DIERR_INVALIDPARAM; - } - - if (len) - TRACE("Application retrieving %ld event(s).\n", len); - - *entries = 0; - nqtail = This->queue_tail; - while (len) { - /* Copy the buffered data into the application queue */ - memcpy((char *)dod + *entries * dodsize, This->data_queue + nqtail, dodsize); - - /* Advance position */ - nqtail++; - if (nqtail >= This->queue_len) - nqtail -= This->queue_len; - (*entries)++; - len--; - } - } - if (!(flags & DIGDD_PEEK)) - This->queue_tail = nqtail; -#ifndef __REACTOS__ - LeaveCriticalSection(&(This->crit)); -#endif - /* Check if we need to do a mouse warping */ - - - if (This->need_warp == WARP_NEEDED) { - dinput_window_check(This); - TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y); - if (mouse_set==0){ - SetCursorPos( This->mapped_center.x, This->mapped_center.y ); - mouse_set++; - } - -#ifdef MOUSE_HACK - This->need_warp = WARP_DONE; -#else - This->need_warp = WARP_STARTED; -#endif - } - return DI_OK; -} - -/****************************************************************************** - * SetProperty : change input device properties - */ -static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface, - REFGUID rguid, - LPCDIPROPHEADER ph) -{ - SysMouseImpl *This = (SysMouseImpl *)iface; - - TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph); - - if (!HIWORD(rguid)) { - switch ((DWORD)rguid) { - case (DWORD) DIPROP_BUFFERSIZE: { - LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; - - TRACE("buffersize = %ld\n",pd->dwData); - - This->data_queue = (LPDIDEVICEOBJECTDATA)HeapAlloc(GetProcessHeap(),0, - pd->dwData * sizeof(DIDEVICEOBJECTDATA)); - This->queue_head = 0; - This->queue_tail = 0; - This->queue_len = pd->dwData; - break; - } - case (DWORD) DIPROP_AXISMODE: { - LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; - This->absolute = !(pd->dwData); - - TRACE("Using %s coordinates mode now\n", This->absolute ? "absolute" : "relative"); - break; - } - default: - FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); - break; - } - } - - return DI_OK; -} - -/****************************************************************************** - * GetProperty : get input device properties - */ -static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, - REFGUID rguid, - LPDIPROPHEADER pdiph) -{ - SysMouseImpl *This = (SysMouseImpl *)iface; - - TRACE("(this=%p,%s,%p): stub!\n", - iface, debugstr_guid(rguid), pdiph); - - if (TRACE_ON(dinput)) - _dump_DIPROPHEADER(pdiph); - - if (!HIWORD(rguid)) { - switch ((DWORD)rguid) { - case (DWORD) DIPROP_BUFFERSIZE: { - LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; - - TRACE(" return buffersize = %d\n",This->queue_len); - pd->dwData = This->queue_len; - break; - } - - case (DWORD) DIPROP_GRANULARITY: { - LPDIPROPDWORD pr = (LPDIPROPDWORD) pdiph; - - /* We'll just assume that the app asks about the Z axis */ - pr->dwData = WHEEL_DELTA; - - break; - } - - case (DWORD) DIPROP_RANGE: { - LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph; - - if ((pdiph->dwHow == DIPH_BYID) && - ((pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS)) || - (pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS)))) { - /* Querying the range of either the X or the Y axis. As I do - not know the range, do as if the range were - unrestricted...*/ - pr->lMin = DIPROPRANGE_NOMIN; - pr->lMax = DIPROPRANGE_NOMAX; - } - - break; - } - - default: - FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); - break; - } - } - - return DI_OK; -} - - - -/****************************************************************************** - * SetEventNotification : specifies event to be sent on state change - */ -static HRESULT WINAPI SysMouseAImpl_SetEventNotification(LPDIRECTINPUTDEVICE8A iface, - HANDLE hnd) { - SysMouseImpl *This = (SysMouseImpl *)iface; - - TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd); - - This->hEvent = hnd; - - return DI_OK; -} - -/****************************************************************************** - * GetCapabilities : get the device capablitites - */ -static HRESULT WINAPI SysMouseAImpl_GetCapabilities( - LPDIRECTINPUTDEVICE8A iface, - LPDIDEVCAPS lpDIDevCaps) -{ - SysMouseImpl *This = (SysMouseImpl *)iface; - DIDEVCAPS devcaps; - - TRACE("(this=%p,%p)\n",This,lpDIDevCaps); - - if ((lpDIDevCaps->dwSize != sizeof(DIDEVCAPS)) && (lpDIDevCaps->dwSize != sizeof(DIDEVCAPS_DX3))) { - WARN("invalid parameter\n"); - return DIERR_INVALIDPARAM; - } - - devcaps.dwSize = lpDIDevCaps->dwSize; - devcaps.dwFlags = DIDC_ATTACHED; - if (This->dinput->version >= 8) - devcaps.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8); - else - devcaps.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8); - devcaps.dwAxes = 3; - devcaps.dwButtons = 3; - devcaps.dwPOVs = 0; - devcaps.dwFFSamplePeriod = 0; - devcaps.dwFFMinTimeResolution = 0; - devcaps.dwFirmwareRevision = 100; - devcaps.dwHardwareRevision = 100; - devcaps.dwFFDriverVersion = 0; - - memcpy(lpDIDevCaps, &devcaps, lpDIDevCaps->dwSize); - - return DI_OK; -} - - -/****************************************************************************** - * EnumObjects : enumerate the different buttons and axis... - */ -static HRESULT WINAPI SysMouseAImpl_EnumObjects( - LPDIRECTINPUTDEVICE8A iface, - LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, - LPVOID lpvRef, - DWORD dwFlags) -{ - SysMouseImpl *This = (SysMouseImpl *)iface; - DIDEVICEOBJECTINSTANCEA ddoi; - - TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags); - if (TRACE_ON(dinput)) { - TRACE(" - flags = "); - _dump_EnumObjects_flags(dwFlags); - TRACE("\n"); - } - - /* Only the fields till dwFFMaxForce are relevant */ - memset(&ddoi, 0, sizeof(ddoi)); - ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce); - - /* In a mouse, we have : two relative axis and three buttons */ - if ((dwFlags == DIDFT_ALL) || - (dwFlags & DIDFT_AXIS)) { - /* X axis */ - ddoi.guidType = GUID_XAxis; - ddoi.dwOfs = This->offset_array[WINE_MOUSE_X_POSITION]; - ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS; - strcpy(ddoi.tszName, "X-Axis"); - _dump_OBJECTINSTANCEA(&ddoi); - if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; - - /* Y axis */ - ddoi.guidType = GUID_YAxis; - ddoi.dwOfs = This->offset_array[WINE_MOUSE_Y_POSITION]; - ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS; - strcpy(ddoi.tszName, "Y-Axis"); - _dump_OBJECTINSTANCEA(&ddoi); - if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; - - /* Z axis */ - ddoi.guidType = GUID_ZAxis; - ddoi.dwOfs = This->offset_array[WINE_MOUSE_Z_POSITION]; - ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS; - strcpy(ddoi.tszName, "Z-Axis"); - _dump_OBJECTINSTANCEA(&ddoi); - if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; - } - - if ((dwFlags == DIDFT_ALL) || - (dwFlags & DIDFT_BUTTON)) { - ddoi.guidType = GUID_Button; - - /* Left button */ - ddoi.dwOfs = This->offset_array[WINE_MOUSE_L_POSITION]; - ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON; - strcpy(ddoi.tszName, "Left-Button"); - _dump_OBJECTINSTANCEA(&ddoi); - if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; - - /* Right button */ - ddoi.dwOfs = This->offset_array[WINE_MOUSE_R_POSITION]; - ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON; - strcpy(ddoi.tszName, "Right-Button"); - _dump_OBJECTINSTANCEA(&ddoi); - if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; - - /* Middle button */ - ddoi.dwOfs = This->offset_array[WINE_MOUSE_M_POSITION]; - ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON; - strcpy(ddoi.tszName, "Middle-Button"); - _dump_OBJECTINSTANCEA(&ddoi); - if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; - } - - return DI_OK; -} - -static HRESULT WINAPI SysMouseWImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface, LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID lpvRef,DWORD dwFlags) -{ - SysMouseImpl *This = (SysMouseImpl *)iface; - - device_enumobjects_AtoWcb_data data; - - data.lpCallBack = lpCallback; - data.lpvRef = lpvRef; - - return SysMouseAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags); -} - -/****************************************************************************** - * GetDeviceInfo : get information about a device's identity - */ -static HRESULT WINAPI SysMouseAImpl_GetDeviceInfo( - LPDIRECTINPUTDEVICE8A iface, - LPDIDEVICEINSTANCEA pdidi) -{ - SysMouseImpl *This = (SysMouseImpl *)iface; - TRACE("(this=%p,%p)\n", This, pdidi); - - if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA)) { - WARN(" dinput3 not supporte yet...\n"); - return DI_OK; - } - - fill_mouse_dideviceinstanceA(pdidi, This->dinput->version); - - return DI_OK; -} - -static HRESULT WINAPI SysMouseWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, LPDIDEVICEINSTANCEW pdidi) -{ - SysMouseImpl *This = (SysMouseImpl *)iface; - TRACE("(this=%p,%p)\n", This, pdidi); - - if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW)) { - WARN(" dinput3 not supporte yet...\n"); - return DI_OK; - } - - fill_mouse_dideviceinstanceW(pdidi, This->dinput->version); - - return DI_OK; -} - - -static IDirectInputDevice8AVtbl SysMouseAvt = -{ - IDirectInputDevice2AImpl_QueryInterface, - IDirectInputDevice2AImpl_AddRef, - SysMouseAImpl_Release, - SysMouseAImpl_GetCapabilities, - SysMouseAImpl_EnumObjects, - SysMouseAImpl_GetProperty, - SysMouseAImpl_SetProperty, - SysMouseAImpl_Acquire, - SysMouseAImpl_Unacquire, - SysMouseAImpl_GetDeviceState, - SysMouseAImpl_GetDeviceData, - SysMouseAImpl_SetDataFormat, - SysMouseAImpl_SetEventNotification, - SysMouseAImpl_SetCooperativeLevel, - IDirectInputDevice2AImpl_GetObjectInfo, - SysMouseAImpl_GetDeviceInfo, - IDirectInputDevice2AImpl_RunControlPanel, - IDirectInputDevice2AImpl_Initialize, - IDirectInputDevice2AImpl_CreateEffect, - IDirectInputDevice2AImpl_EnumEffects, - IDirectInputDevice2AImpl_GetEffectInfo, - IDirectInputDevice2AImpl_GetForceFeedbackState, - IDirectInputDevice2AImpl_SendForceFeedbackCommand, - IDirectInputDevice2AImpl_EnumCreatedEffectObjects, - IDirectInputDevice2AImpl_Escape, - SysMouseAImpl_Poll, - IDirectInputDevice2AImpl_SendDeviceData, - IDirectInputDevice7AImpl_EnumEffectsInFile, - IDirectInputDevice7AImpl_WriteEffectToFile, - IDirectInputDevice8AImpl_BuildActionMap, - IDirectInputDevice8AImpl_SetActionMap, - IDirectInputDevice8AImpl_GetImageInfo -}; - -#if !defined(__STRICT_ANSI__) && defined(__GNUC__) -# define XCAST(fun) (typeof(SysMouseWvt.fun)) -#else -# define XCAST(fun) (void*) -#endif - -static IDirectInputDevice8WVtbl SysMouseWvt = -{ - IDirectInputDevice2WImpl_QueryInterface, - XCAST(AddRef)IDirectInputDevice2AImpl_AddRef, - XCAST(Release)SysMouseAImpl_Release, - XCAST(GetCapabilities)SysMouseAImpl_GetCapabilities, - SysMouseWImpl_EnumObjects, - XCAST(GetProperty)SysMouseAImpl_GetProperty, - XCAST(SetProperty)SysMouseAImpl_SetProperty, - XCAST(Acquire)SysMouseAImpl_Acquire, - XCAST(Unacquire)SysMouseAImpl_Unacquire, - XCAST(GetDeviceState)SysMouseAImpl_GetDeviceState, - XCAST(GetDeviceData)SysMouseAImpl_GetDeviceData, - XCAST(SetDataFormat)SysMouseAImpl_SetDataFormat, - XCAST(SetEventNotification)SysMouseAImpl_SetEventNotification, - XCAST(SetCooperativeLevel)SysMouseAImpl_SetCooperativeLevel, - IDirectInputDevice2WImpl_GetObjectInfo, - SysMouseWImpl_GetDeviceInfo, - XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel, - XCAST(Initialize)IDirectInputDevice2AImpl_Initialize, - XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect, - IDirectInputDevice2WImpl_EnumEffects, - IDirectInputDevice2WImpl_GetEffectInfo, - XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState, - XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand, - XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects, - XCAST(Escape)IDirectInputDevice2AImpl_Escape, - XCAST(Poll)SysMouseAImpl_Poll, - XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData, - IDirectInputDevice7WImpl_EnumEffectsInFile, - IDirectInputDevice7WImpl_WriteEffectToFile, - IDirectInputDevice8WImpl_BuildActionMap, - IDirectInputDevice8WImpl_SetActionMap, - IDirectInputDevice8WImpl_GetImageInfo -}; -#undef XCAST +/* DirectInput Mouse device + * + * Copyright 1998 Marcus Meissner + * Copyright 1998,1999 Lionel Ulmer + * Copyright 2000-2001 TransGaming Technologies Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winerror.h" +#include "dinput.h" + +#include "dinput_private.h" +#include "device_private.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +#define MOUSE_HACK + +WINE_DEFAULT_DEBUG_CHANNEL(dinput); + + +/* Wine mouse driver object instances */ +#define WINE_MOUSE_X_AXIS_INSTANCE 0 +#define WINE_MOUSE_Y_AXIS_INSTANCE 1 +#define WINE_MOUSE_Z_AXIS_INSTANCE 2 +#define WINE_MOUSE_L_BUTTON_INSTANCE 0 +#define WINE_MOUSE_R_BUTTON_INSTANCE 1 +#define WINE_MOUSE_M_BUTTON_INSTANCE 2 +#define WINE_MOUSE_D_BUTTON_INSTANCE 3 + +/* ------------------------------- */ +/* Wine mouse internal data format */ +/* ------------------------------- */ + +/* Constants used to access the offset array */ +#define WINE_MOUSE_X_POSITION 0 +#define WINE_MOUSE_Y_POSITION 1 +#define WINE_MOUSE_Z_POSITION 2 +#define WINE_MOUSE_L_POSITION 3 +#define WINE_MOUSE_R_POSITION 4 +#define WINE_MOUSE_M_POSITION 5 + +typedef struct { + LONG lX; + LONG lY; + LONG lZ; + BYTE rgbButtons[4]; +} Wine_InternalMouseData; + +#define WINE_INTERNALMOUSE_NUM_OBJS 6 + +static const DIOBJECTDATAFORMAT Wine_InternalMouseObjectFormat[WINE_INTERNALMOUSE_NUM_OBJS] = { + { &GUID_XAxis, FIELD_OFFSET(Wine_InternalMouseData, lX), + DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 }, + { &GUID_YAxis, FIELD_OFFSET(Wine_InternalMouseData, lY), + DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 }, + { &GUID_ZAxis, FIELD_OFFSET(Wine_InternalMouseData, lZ), + DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 }, + { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 0, + DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 }, + { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 1, + DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 }, + { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 2, + DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 } +}; + +static const DIDATAFORMAT Wine_InternalMouseFormat = { + 0, /* dwSize - unused */ + 0, /* dwObjsize - unused */ + 0, /* dwFlags - unused */ + sizeof(Wine_InternalMouseData), + WINE_INTERNALMOUSE_NUM_OBJS, /* dwNumObjs */ + (LPDIOBJECTDATAFORMAT) Wine_InternalMouseObjectFormat +}; + +static IDirectInputDevice8AVtbl SysMouseAvt; +static IDirectInputDevice8WVtbl SysMouseWvt; + +typedef struct SysMouseImpl SysMouseImpl; + +typedef enum { + WARP_DONE, /* Warping has been done */ + WARP_NEEDED, /* Warping is needed */ + WARP_STARTED /* Warping has been done, waiting for the warp event */ +} WARP_STATUS; + +struct SysMouseImpl +{ + LPVOID lpVtbl; + DWORD ref; + GUID guid; + + IDirectInputImpl *dinput; + + /* The current data format and the conversion between internal + and external data formats */ + DIDATAFORMAT *df; + DataFormat *wine_df; + int offset_array[WINE_INTERNALMOUSE_NUM_OBJS]; + + /* SysMouseAImpl */ + BYTE absolute; + /* Previous position for relative moves */ + LONG prevX, prevY; + /* These are used in case of relative -> absolute transitions */ + POINT org_coords; + HHOOK hook; + HWND win; + DWORD dwCoopLevel; + POINT mapped_center; + DWORD win_centerX, win_centerY; + LPDIDEVICEOBJECTDATA data_queue; + int queue_head, queue_tail, queue_len; + BOOL overflow; + /* warping: whether we need to move mouse back to middle once we + * reach window borders (for e.g. shooters, "surface movement" games) */ + WARP_STATUS need_warp; + int acquired; + HANDLE hEvent; + CRITICAL_SECTION crit; + + /* This is for mouse reporting. */ + Wine_InternalMouseData m_state; +}; + +/* FIXME: This is ugly and not thread safe :/ */ +static IDirectInputDevice8A* current_lock = NULL; + +/* FIXME: This is ugly but needed on Windows */ +static int mouse_set = 0; + +static GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */ + 0x9e573ed8, + 0x7734, + 0x11d2, + {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7} +}; + +static void fill_mouse_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, int version) { + DWORD dwSize; + DIDEVICEINSTANCEA ddi; + + dwSize = lpddi->dwSize; + + TRACE("%ld %p\n", dwSize, lpddi); + + memset(lpddi, 0, dwSize); + memset(&ddi, 0, sizeof(ddi)); + + ddi.dwSize = dwSize; + ddi.guidInstance = GUID_SysMouse;/* DInput's GUID */ + ddi.guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */ + if (version >= 8) + ddi.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8); + else + ddi.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8); + strcpy(ddi.tszInstanceName, "Mouse"); + strcpy(ddi.tszProductName, "Wine Mouse"); + + memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi))); +} + +static void fill_mouse_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, int version) { + DWORD dwSize; + DIDEVICEINSTANCEW ddi; + + dwSize = lpddi->dwSize; + + TRACE("%ld %p\n", dwSize, lpddi); + + memset(lpddi, 0, dwSize); + memset(&ddi, 0, sizeof(ddi)); + + ddi.dwSize = dwSize; + ddi.guidInstance = GUID_SysMouse;/* DInput's GUID */ + ddi.guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */ + if (version >= 8) + ddi.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8); + else + ddi.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8); + MultiByteToWideChar(CP_ACP, 0, "Mouse", -1, ddi.tszInstanceName, MAX_PATH); + MultiByteToWideChar(CP_ACP, 0, "Wine Mouse", -1, ddi.tszProductName, MAX_PATH); + + memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi))); +} + +static BOOL mousedev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, int version, int id) +{ + if (id != 0) + return FALSE; + + if ((dwDevType == 0) || + ((dwDevType == DIDEVTYPE_MOUSE) && (version < 8)) || + (((dwDevType == DI8DEVCLASS_POINTER) || (dwDevType == DI8DEVTYPE_MOUSE)) && (version >= 8))) { + TRACE("Enumerating the mouse device\n"); + + fill_mouse_dideviceinstanceA(lpddi, version); + + return TRUE; + } + + return FALSE; +} + +static BOOL mousedev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, int version, int id) +{ + if (id != 0) + return FALSE; + + if ((dwDevType == 0) || + ((dwDevType == DIDEVTYPE_MOUSE) && (version < 8)) || + (((dwDevType == DI8DEVCLASS_POINTER) || (dwDevType == DI8DEVTYPE_MOUSE)) && (version >= 8))) { + TRACE("Enumerating the mouse device\n"); + + fill_mouse_dideviceinstanceW(lpddi, version); + + return TRUE; + } + + return FALSE; +} + +static SysMouseImpl *alloc_device_mouse(REFGUID rguid, LPVOID mvt, IDirectInputImpl *dinput) +{ + int offset_array[WINE_INTERNALMOUSE_NUM_OBJS] = { + FIELD_OFFSET(Wine_InternalMouseData, lX), + FIELD_OFFSET(Wine_InternalMouseData, lY), + FIELD_OFFSET(Wine_InternalMouseData, lZ), + FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 0, + FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 1, + FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 2 + }; + SysMouseImpl* newDevice; + newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouseImpl)); + newDevice->ref = 1; + newDevice->lpVtbl = mvt; +#ifndef __REACTOS__ + InitializeCriticalSection(&(newDevice->crit)); +#endif + memcpy(&(newDevice->guid),rguid,sizeof(*rguid)); + + /* Per default, Wine uses its internal data format */ + newDevice->df = (DIDATAFORMAT *) &Wine_InternalMouseFormat; + memcpy(newDevice->offset_array, offset_array, WINE_INTERNALMOUSE_NUM_OBJS * sizeof(int)); + newDevice->wine_df = (DataFormat *) HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat)); + newDevice->wine_df->size = 0; + newDevice->wine_df->internal_format_size = Wine_InternalMouseFormat.dwDataSize; + newDevice->wine_df->dt = NULL; + newDevice->dinput = dinput; + + return newDevice; +} + +static HRESULT mousedev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev) +{ + if ((IsEqualGUID(&GUID_SysMouse,rguid)) || /* Generic Mouse */ + (IsEqualGUID(&DInput_Wine_Mouse_GUID,rguid))) { /* Wine Mouse */ + if ((riid == NULL) || + IsEqualGUID(&IID_IDirectInputDeviceA,riid) || + IsEqualGUID(&IID_IDirectInputDevice2A,riid) || + IsEqualGUID(&IID_IDirectInputDevice7A,riid) || + IsEqualGUID(&IID_IDirectInputDevice8A,riid)) { + *pdev = (IDirectInputDeviceA*) alloc_device_mouse(rguid, &SysMouseAvt, dinput); + TRACE("Creating a Mouse device (%p)\n", *pdev); + return DI_OK; + } else + return DIERR_NOINTERFACE; + } + + return DIERR_DEVICENOTREG; +} + +static HRESULT mousedev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev) +{ + if ((IsEqualGUID(&GUID_SysMouse,rguid)) || /* Generic Mouse */ + (IsEqualGUID(&DInput_Wine_Mouse_GUID,rguid))) { /* Wine Mouse */ + if ((riid == NULL) || + IsEqualGUID(&IID_IDirectInputDeviceW,riid) || + IsEqualGUID(&IID_IDirectInputDevice2W,riid) || + IsEqualGUID(&IID_IDirectInputDevice7W,riid) || + IsEqualGUID(&IID_IDirectInputDevice8W,riid)) { + *pdev = (IDirectInputDeviceW*) alloc_device_mouse(rguid, &SysMouseWvt, dinput); + TRACE("Creating a Mouse device (%p)\n", *pdev); + return DI_OK; + } else + return DIERR_NOINTERFACE; + } + + return DIERR_DEVICENOTREG; +} + +static dinput_device mousedev = { + 100, + "Wine mouse driver", + mousedev_enum_deviceA, + mousedev_enum_deviceW, + mousedev_create_deviceA, + mousedev_create_deviceW +}; + +#ifdef __REACTOS__ +void scan_mouse() +{ + dinput_register_device(&mousedev); +} + +DECL_GLOBAL_CONSTRUCTOR(mousedev_register) { dinput_register_device(&mousedev); } +#endif + +/****************************************************************************** + * SysMouseA (DInput Mouse support) + */ + +/****************************************************************************** + * Release : release the mouse buffer. + */ +static ULONG WINAPI SysMouseAImpl_Release(LPDIRECTINPUTDEVICE8A iface) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + ULONG ref; + + ref = InterlockedDecrement(&(This->ref)); + if (ref) + return ref; + + /* Free the data queue */ + HeapFree(GetProcessHeap(),0,This->data_queue); + + + if (This->hook) { + UnhookWindowsHookEx( This->hook ); + if (This->dwCoopLevel & DISCL_EXCLUSIVE) + ShowCursor(TRUE); /* show cursor */ + } +#ifndef __REACTOS__ + DeleteCriticalSection(&(This->crit)); +#endif + + /* Free the DataFormat */ + if (This->df != &(Wine_InternalMouseFormat)) { + HeapFree(GetProcessHeap(), 0, This->df->rgodf); + HeapFree(GetProcessHeap(), 0, This->df); + } + + HeapFree(GetProcessHeap(),0,This); + return 0; +} + + +/****************************************************************************** + * SetCooperativeLevel : store the window in which we will do our + * grabbing. + */ +static HRESULT WINAPI SysMouseAImpl_SetCooperativeLevel( + LPDIRECTINPUTDEVICE8A iface,HWND hwnd,DWORD dwflags +) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + + TRACE("(this=%p,0x%08lx,0x%08lx)\n",This,(DWORD)hwnd,dwflags); + + if (TRACE_ON(dinput)) { + TRACE(" cooperative level : "); + _dump_cooperativelevel_DI(dwflags); + } + + /* Store the window which asks for the mouse */ + if (!hwnd) + hwnd = GetDesktopWindow(); + This->win = hwnd; + This->dwCoopLevel = dwflags; + + return DI_OK; +} + + +/****************************************************************************** + * SetDataFormat : the application can choose the format of the data + * the device driver sends back with GetDeviceState. + * + * For the moment, only the "standard" configuration (c_dfDIMouse) is supported + * in absolute and relative mode. + */ +static HRESULT WINAPI SysMouseAImpl_SetDataFormat( + LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df +) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + + TRACE("(this=%p,%p)\n",This,df); + + _dump_DIDATAFORMAT(df); + + /* Tests under windows show that a call to SetDataFormat always sets the mouse + in relative mode whatever the dwFlags value (DIDF_ABSAXIS/DIDF_RELAXIS). + To switch in absolute mode, SetProperty must be used. */ + This->absolute = 0; + + /* Store the new data format */ + This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize); + memcpy(This->df, df, df->dwSize); + This->df->rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize); + memcpy(This->df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize); + + /* Prepare all the data-conversion filters */ + This->wine_df = create_DataFormat(&(Wine_InternalMouseFormat), df, This->offset_array); + + return DI_OK; +} + +/* low-level mouse hook */ +static LRESULT CALLBACK dinput_mouse_hook( int code, WPARAM wparam, LPARAM lparam ) +{ + LRESULT ret; + MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam; + SysMouseImpl* This = (SysMouseImpl*) current_lock; + DWORD dwCoop; + static long last_event = 0; + int wdata; + + if (code != HC_ACTION) return CallNextHookEx( This->hook, code, wparam, lparam ); + +#ifndef __REACTOS__ + EnterCriticalSection(&(This->crit)); +#endif + + dwCoop = This->dwCoopLevel; + + /* Only allow mouse events every 10 ms. + * This is to allow the cursor to start acceleration before + * the warps happen. But if it involves a mouse button event we + * allow it since we don't want to lose the clicks. + */ + if (((GetCurrentTime() - last_event) < 10) + && wparam == WM_MOUSEMOVE) + goto end; + else last_event = GetCurrentTime(); + + /* Mouse moved -> send event if asked */ + if (This->hEvent) + SetEvent(This->hEvent); + + if (wparam == WM_MOUSEMOVE) { + if (This->absolute) { + if (hook->pt.x != This->prevX) + GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x, hook->time, 0); + if (hook->pt.y != This->prevY) + GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y, hook->time, 0); + } else { + /* Now, warp handling */ + if ((This->need_warp == WARP_STARTED) && + (hook->pt.x == This->mapped_center.x) && (hook->pt.y == This->mapped_center.y)) { + /* Warp has been done... */ + This->need_warp = WARP_DONE; + goto end; + } + + /* Relative mouse input with absolute mouse event : the real fun starts here... */ + if ((This->need_warp == WARP_NEEDED) || + (This->need_warp == WARP_STARTED)) { + if (hook->pt.x != This->prevX) + GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->prevX, + hook->time, (This->dinput->evsequence)++); + if (hook->pt.y != This->prevY) + GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->prevY, + hook->time, (This->dinput->evsequence)++); + } else { + /* This is the first time the event handler has been called after a + GetDeviceData or GetDeviceState. */ + if (hook->pt.x != This->mapped_center.x) { + GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->mapped_center.x, + hook->time, (This->dinput->evsequence)++); + This->need_warp = WARP_NEEDED; + } + + if (hook->pt.y != This->mapped_center.y) { + GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->mapped_center.y, + hook->time, (This->dinput->evsequence)++); + This->need_warp = WARP_NEEDED; + } + } + } + + This->prevX = hook->pt.x; + This->prevY = hook->pt.y; + + if (This->absolute) { + This->m_state.lX = hook->pt.x; + This->m_state.lY = hook->pt.y; + } else { + This->m_state.lX = hook->pt.x - This->mapped_center.x; + This->m_state.lY = hook->pt.y - This->mapped_center.y; + } + } + + TRACE(" msg %x pt %ld %ld (W=%d)\n", + wparam, hook->pt.x, hook->pt.y, (!This->absolute) && This->need_warp ); + + switch(wparam) { + case WM_LBUTTONDOWN: + GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0x80, + hook->time, This->dinput->evsequence++); + This->m_state.rgbButtons[0] = 0x80; + break; + case WM_LBUTTONUP: + GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0x00, + hook->time, This->dinput->evsequence++); + This->m_state.rgbButtons[0] = 0x00; + break; + case WM_RBUTTONDOWN: + GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0x80, + hook->time, This->dinput->evsequence++); + This->m_state.rgbButtons[1] = 0x80; + break; + case WM_RBUTTONUP: + GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0x00, + hook->time, This->dinput->evsequence++); + This->m_state.rgbButtons[1] = 0x00; + break; + case WM_MBUTTONDOWN: + GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0x80, + hook->time, This->dinput->evsequence++); + This->m_state.rgbButtons[2] = 0x80; + break; + case WM_MBUTTONUP: + GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0x00, + hook->time, This->dinput->evsequence++); + This->m_state.rgbButtons[2] = 0x00; + break; + case WM_MOUSEWHEEL: + wdata = (short)HIWORD(hook->mouseData); + GEN_EVENT(This->offset_array[WINE_MOUSE_Z_POSITION], wdata, + hook->time, This->dinput->evsequence++); + This->m_state.lZ += wdata; + break; + } + + TRACE("(X: %ld - Y: %ld L: %02x M: %02x R: %02x)\n", + This->m_state.lX, This->m_state.lY, + This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]); + + end: +#ifndef __REACTOS__ + LeaveCriticalSection(&(This->crit)); +#endif + + if (dwCoop & DISCL_NONEXCLUSIVE) { + /* Pass the events down to previous handlers (e.g. win32 input) */ + ret = CallNextHookEx( This->hook, code, wparam, lparam ); + } else { + /* Ignore message */ + ret = 1; + } + return ret; +} + + +static void dinput_window_check(SysMouseImpl* This) { + RECT rect; + DWORD centerX, centerY; + + /* make sure the window hasn't moved */ + GetWindowRect(This->win, &rect); + centerX = (rect.right - rect.left) / 2; + centerY = (rect.bottom - rect.top ) / 2; + if (This->win_centerX != centerX || This->win_centerY != centerY) { + This->win_centerX = centerX; + This->win_centerY = centerY; + } + This->mapped_center.x = This->win_centerX; + This->mapped_center.y = This->win_centerY; + MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1); +} + + +/****************************************************************************** + * Acquire : gets exclusive control of the mouse + */ +static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + RECT rect; + + TRACE("(this=%p)\n",This); + + + + if (This->acquired == 0) { + POINT point; + + + + /* Store (in a global variable) the current lock */ + current_lock = (IDirectInputDevice8A*)This; + + /* Init the mouse state */ + GetCursorPos( &point ); + if (This->absolute) { + This->m_state.lX = point.x; + This->m_state.lY = point.y; + This->prevX = point.x; + This->prevY = point.y; + } else { + This->m_state.lX = 0; + This->m_state.lY = 0; + This->org_coords = point; + } + This->m_state.lZ = 0; + This->m_state.rgbButtons[0] = ((GetKeyState(VK_LBUTTON) & 0x80) ? 0xFF : 0x00); + This->m_state.rgbButtons[1] = ((GetKeyState(VK_RBUTTON) & 0x80) ? 0xFF : 0x00); + This->m_state.rgbButtons[2] = ((GetKeyState(VK_MBUTTON) & 0x80) ? 0xFF : 0x00); + + /* Install our mouse hook */ + if (This->dwCoopLevel & DISCL_EXCLUSIVE) + ShowCursor(FALSE); /* hide cursor */ + + This->hook = SetWindowsHookExA( WH_MOUSE_LL, dinput_mouse_hook, DINPUT_instance, 0 ); + + /* Get the window dimension and find the center */ + GetWindowRect(This->win, &rect); + This->win_centerX = (rect.right - rect.left) / 2; + This->win_centerY = (rect.bottom - rect.top ) / 2; + + /* Warp the mouse to the center of the window */ + if (This->absolute == 0) { + This->mapped_center.x = This->win_centerX; + This->mapped_center.y = This->win_centerY; + MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1); + TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y); + SetCursorPos( This->mapped_center.x, This->mapped_center.y ); +#ifdef MOUSE_HACK + This->need_warp = WARP_DONE; +#else + This->need_warp = WARP_STARTED; +#endif + } + + This->acquired = 1; + return DI_OK; + } + return S_FALSE; +} + +/****************************************************************************** + * Unacquire : frees the mouse + */ +static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + + TRACE("(this=%p)\n",This); + + if (This->acquired) { + /* Reinstall previous mouse event handler */ + + + if (This->hook) { + UnhookWindowsHookEx( This->hook ); + This->hook = 0; + + if (This->dwCoopLevel & DISCL_EXCLUSIVE) + ShowCursor(TRUE); /* show cursor */ + } + + /* No more locks */ + current_lock = NULL; + + /* Unacquire device */ + This->acquired = 0; + + /* And put the mouse cursor back where it was at acquire time */ + if (This->absolute == 0) { + TRACE(" warping mouse back to (%ld , %ld)\n", This->org_coords.x, This->org_coords.y); + SetCursorPos(This->org_coords.x, This->org_coords.y); + } + } else { + return DI_NOEFFECT; + } + + return DI_OK; +} + +// if you call poll then to getdevicestate +// it did not send back right value in windows +int poll_mouse=0; + +#ifdef __REACTOS__ +void getmousesvalue(LPDIRECTINPUTDEVICE8A iface); +int filp=0; +void getmousesvalue(LPDIRECTINPUTDEVICE8A iface) +{ + POINT point; + SysMouseImpl *This = (SysMouseImpl *)iface; + + This->m_state.rgbButtons[0] = ((GetKeyState(VK_LBUTTON) & 0x80) ? 0xFF : 0x00); + This->m_state.rgbButtons[1] = ((GetKeyState(VK_RBUTTON) & 0x80) ? 0xFF : 0x00); + This->m_state.rgbButtons[2] = ((GetKeyState(VK_MBUTTON) & 0x80) ? 0xFF : 0x00); + This->m_state.rgbButtons[3] = ((GetKeyState(VK_XBUTTON1) & 0x80) ? 0xFF : 0x00); + This->m_state.rgbButtons[4] = ((GetKeyState(VK_XBUTTON2) & 0x80) ? 0xFF : 0x00); + + + + + if (poll_mouse==1) filp=0; + if (filp==2) filp=0; + if (filp==0) { + GetCursorPos( &point ); + + if (This->prevX == point.x) This->m_state.lX = 0; + else { + This->prevX = point.x; + This->m_state.lX = point.x - This->org_coords.x; + } + + if (This->prevY == point.y) This->m_state.lY = 0; + else { + This->prevY = point.y; + This->m_state.lY = point.y - This->org_coords.y; + } + + } + else + { + This->m_state.lX = 0; + This->m_state.lY = 0; + } + filp++; + +// check see if buffer have been set + +} + +#endif + +static HRESULT WINAPI SysMouseAImpl_Poll(LPDIRECTINPUTDEVICE8A iface) +{ + int retValue = DI_OK; + + if (poll_mouse==0) { + retValue=SysMouseAImpl_Acquire(iface); + poll_mouse=1; + if (retValue!=DI_OK) retValue=DIERR_NOTACQUIRED; + else retValue = DI_OK; + } + + return retValue; +} + + +/****************************************************************************** + * GetDeviceState : returns the "state" of the mouse. + * + * For the moment, only the "standard" return structure (DIMOUSESTATE) is + * supported. + */ +static HRESULT WINAPI SysMouseAImpl_GetDeviceState( + LPDIRECTINPUTDEVICE8A iface,DWORD len,LPVOID ptr +) { + SysMouseImpl *This = (SysMouseImpl *)iface; + +#ifndef __REACTOS__ + EnterCriticalSection(&(This->crit)); +#endif + + TRACE("(this=%p,0x%08lx,%p): \n",This,len,ptr); + + /* Copy the current mouse state */ + fill_DataFormat(ptr, &(This->m_state), This->wine_df); + +#ifdef __REACTOS__ + // this fix windows bugs when + // some program calling on mouse poll + if (poll_mouse==1) poll_mouse=0; + else { + if (This->absolute == 0) { + This->m_state.lX = 0; + This->m_state.lY = 0; + This->m_state.lZ = 0; + } + } +#endif + + /* Check if we need to do a mouse warping */ + if (This->need_warp == WARP_NEEDED) { + dinput_window_check(This); + TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y); + if (mouse_set==0){ + SetCursorPos( This->mapped_center.x, This->mapped_center.y ); + mouse_set++; + } + +#ifdef MOUSE_HACK + This->need_warp = WARP_DONE; +#else + This->need_warp = WARP_STARTED; +#endif + } + +#ifndef __REACTOS__ + LeaveCriticalSection(&(This->crit)); +#endif + + TRACE("(X: %ld - Y: %ld - Z: %ld L: %02x M: %02x R: %02x)\n", + This->m_state.lX, This->m_state.lY, This->m_state.lZ, + This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]); + + return DI_OK; +} + +/****************************************************************************** + * GetDeviceState : gets buffered input data. + */ + + +static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface, + DWORD dodsize, + LPDIDEVICEOBJECTDATA dod, + LPDWORD entries, + DWORD flags +) { + SysMouseImpl *This = (SysMouseImpl *)iface; + DWORD len; + int nqtail; + + + TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags); + + + if (This->acquired == 0) { + WARN(" application tries to get data from an unacquired device !\n"); + //return DIERR_NOTACQUIRED; + + // windows does not get any data if + // we do not call manual to mouse Acquire + // this is only need if some apps calling on getdevice data direcly + // in windows GetdeviceData does always update first the data + // then return it. + SysMouseAImpl_Acquire(iface); + } + + + + + + + +#ifndef __REACTOS__ + EnterCriticalSection(&(This->crit)); +#endif + + // FIXME mouse are bit choppy here. + + len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0) + + (This->queue_head - This->queue_tail); + if (len > *entries) len = *entries; + + if (dod == NULL) { + if (len) + TRACE("Application discarding %ld event(s).\n", len); + + *entries = len; + nqtail = This->queue_tail + len; + while (nqtail >= This->queue_len) nqtail -= This->queue_len; + } else { + if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3)) { + ERR("Wrong structure size !\n"); + + LeaveCriticalSection(&(This->crit)); + + return DIERR_INVALIDPARAM; + } + + if (len) + TRACE("Application retrieving %ld event(s).\n", len); + + *entries = 0; + nqtail = This->queue_tail; + while (len) { + /* Copy the buffered data into the application queue */ + memcpy((char *)dod + *entries * dodsize, This->data_queue + nqtail, dodsize); + + /* Advance position */ + nqtail++; + if (nqtail >= This->queue_len) + nqtail -= This->queue_len; + (*entries)++; + len--; + } + } + if (!(flags & DIGDD_PEEK)) + This->queue_tail = nqtail; +#ifndef __REACTOS__ + LeaveCriticalSection(&(This->crit)); +#endif + /* Check if we need to do a mouse warping */ + + + if (This->need_warp == WARP_NEEDED) { + dinput_window_check(This); + TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y); + if (mouse_set==0){ + SetCursorPos( This->mapped_center.x, This->mapped_center.y ); + mouse_set++; + } + +#ifdef MOUSE_HACK + This->need_warp = WARP_DONE; +#else + This->need_warp = WARP_STARTED; +#endif + } + return DI_OK; +} + +/****************************************************************************** + * SetProperty : change input device properties + */ +static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, + LPCDIPROPHEADER ph) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + + TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph); + + if (!HIWORD(rguid)) { + switch ((DWORD)rguid) { + case (DWORD) DIPROP_BUFFERSIZE: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + + TRACE("buffersize = %ld\n",pd->dwData); + + This->data_queue = (LPDIDEVICEOBJECTDATA)HeapAlloc(GetProcessHeap(),0, + pd->dwData * sizeof(DIDEVICEOBJECTDATA)); + This->queue_head = 0; + This->queue_tail = 0; + This->queue_len = pd->dwData; + break; + } + case (DWORD) DIPROP_AXISMODE: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + This->absolute = !(pd->dwData); + + TRACE("Using %s coordinates mode now\n", This->absolute ? "absolute" : "relative"); + break; + } + default: + FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); + break; + } + } + + return DI_OK; +} + +/****************************************************************************** + * GetProperty : get input device properties + */ +static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, + LPDIPROPHEADER pdiph) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + + TRACE("(this=%p,%s,%p): stub!\n", + iface, debugstr_guid(rguid), pdiph); + + if (TRACE_ON(dinput)) + _dump_DIPROPHEADER(pdiph); + + if (!HIWORD(rguid)) { + switch ((DWORD)rguid) { + case (DWORD) DIPROP_BUFFERSIZE: { + LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; + + TRACE(" return buffersize = %d\n",This->queue_len); + pd->dwData = This->queue_len; + break; + } + + case (DWORD) DIPROP_GRANULARITY: { + LPDIPROPDWORD pr = (LPDIPROPDWORD) pdiph; + + /* We'll just assume that the app asks about the Z axis */ + pr->dwData = WHEEL_DELTA; + + break; + } + + case (DWORD) DIPROP_RANGE: { + LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph; + + if ((pdiph->dwHow == DIPH_BYID) && + ((pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS)) || + (pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS)))) { + /* Querying the range of either the X or the Y axis. As I do + not know the range, do as if the range were + unrestricted...*/ + pr->lMin = DIPROPRANGE_NOMIN; + pr->lMax = DIPROPRANGE_NOMAX; + } + + break; + } + + default: + FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); + break; + } + } + + return DI_OK; +} + + + +/****************************************************************************** + * SetEventNotification : specifies event to be sent on state change + */ +static HRESULT WINAPI SysMouseAImpl_SetEventNotification(LPDIRECTINPUTDEVICE8A iface, + HANDLE hnd) { + SysMouseImpl *This = (SysMouseImpl *)iface; + + TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd); + + This->hEvent = hnd; + + return DI_OK; +} + +/****************************************************************************** + * GetCapabilities : get the device capablitites + */ +static HRESULT WINAPI SysMouseAImpl_GetCapabilities( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVCAPS lpDIDevCaps) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + DIDEVCAPS devcaps; + + TRACE("(this=%p,%p)\n",This,lpDIDevCaps); + + if ((lpDIDevCaps->dwSize != sizeof(DIDEVCAPS)) && (lpDIDevCaps->dwSize != sizeof(DIDEVCAPS_DX3))) { + WARN("invalid parameter\n"); + return DIERR_INVALIDPARAM; + } + + devcaps.dwSize = lpDIDevCaps->dwSize; + devcaps.dwFlags = DIDC_ATTACHED; + if (This->dinput->version >= 8) + devcaps.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8); + else + devcaps.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8); + devcaps.dwAxes = 3; + devcaps.dwButtons = 3; + devcaps.dwPOVs = 0; + devcaps.dwFFSamplePeriod = 0; + devcaps.dwFFMinTimeResolution = 0; + devcaps.dwFirmwareRevision = 100; + devcaps.dwHardwareRevision = 100; + devcaps.dwFFDriverVersion = 0; + + memcpy(lpDIDevCaps, &devcaps, lpDIDevCaps->dwSize); + + return DI_OK; +} + + +/****************************************************************************** + * EnumObjects : enumerate the different buttons and axis... + */ +static HRESULT WINAPI SysMouseAImpl_EnumObjects( + LPDIRECTINPUTDEVICE8A iface, + LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, + LPVOID lpvRef, + DWORD dwFlags) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + DIDEVICEOBJECTINSTANCEA ddoi; + + TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags); + if (TRACE_ON(dinput)) { + TRACE(" - flags = "); + _dump_EnumObjects_flags(dwFlags); + TRACE("\n"); + } + + /* Only the fields till dwFFMaxForce are relevant */ + memset(&ddoi, 0, sizeof(ddoi)); + ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce); + + /* In a mouse, we have : two relative axis and three buttons */ + if ((dwFlags == DIDFT_ALL) || + (dwFlags & DIDFT_AXIS)) { + /* X axis */ + ddoi.guidType = GUID_XAxis; + ddoi.dwOfs = This->offset_array[WINE_MOUSE_X_POSITION]; + ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS; + strcpy(ddoi.tszName, "X-Axis"); + _dump_OBJECTINSTANCEA(&ddoi); + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; + + /* Y axis */ + ddoi.guidType = GUID_YAxis; + ddoi.dwOfs = This->offset_array[WINE_MOUSE_Y_POSITION]; + ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS; + strcpy(ddoi.tszName, "Y-Axis"); + _dump_OBJECTINSTANCEA(&ddoi); + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; + + /* Z axis */ + ddoi.guidType = GUID_ZAxis; + ddoi.dwOfs = This->offset_array[WINE_MOUSE_Z_POSITION]; + ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS; + strcpy(ddoi.tszName, "Z-Axis"); + _dump_OBJECTINSTANCEA(&ddoi); + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; + } + + if ((dwFlags == DIDFT_ALL) || + (dwFlags & DIDFT_BUTTON)) { + ddoi.guidType = GUID_Button; + + /* Left button */ + ddoi.dwOfs = This->offset_array[WINE_MOUSE_L_POSITION]; + ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON; + strcpy(ddoi.tszName, "Left-Button"); + _dump_OBJECTINSTANCEA(&ddoi); + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; + + /* Right button */ + ddoi.dwOfs = This->offset_array[WINE_MOUSE_R_POSITION]; + ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON; + strcpy(ddoi.tszName, "Right-Button"); + _dump_OBJECTINSTANCEA(&ddoi); + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; + + /* Middle button */ + ddoi.dwOfs = This->offset_array[WINE_MOUSE_M_POSITION]; + ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON; + strcpy(ddoi.tszName, "Middle-Button"); + _dump_OBJECTINSTANCEA(&ddoi); + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; + } + + return DI_OK; +} + +static HRESULT WINAPI SysMouseWImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface, LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID lpvRef,DWORD dwFlags) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + + device_enumobjects_AtoWcb_data data; + + data.lpCallBack = lpCallback; + data.lpvRef = lpvRef; + + return SysMouseAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags); +} + +/****************************************************************************** + * GetDeviceInfo : get information about a device's identity + */ +static HRESULT WINAPI SysMouseAImpl_GetDeviceInfo( + LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEINSTANCEA pdidi) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + TRACE("(this=%p,%p)\n", This, pdidi); + + if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA)) { + WARN(" dinput3 not supporte yet...\n"); + return DI_OK; + } + + fill_mouse_dideviceinstanceA(pdidi, This->dinput->version); + + return DI_OK; +} + +static HRESULT WINAPI SysMouseWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, LPDIDEVICEINSTANCEW pdidi) +{ + SysMouseImpl *This = (SysMouseImpl *)iface; + TRACE("(this=%p,%p)\n", This, pdidi); + + if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW)) { + WARN(" dinput3 not supporte yet...\n"); + return DI_OK; + } + + fill_mouse_dideviceinstanceW(pdidi, This->dinput->version); + + return DI_OK; +} + + +static IDirectInputDevice8AVtbl SysMouseAvt = +{ + IDirectInputDevice2AImpl_QueryInterface, + IDirectInputDevice2AImpl_AddRef, + SysMouseAImpl_Release, + SysMouseAImpl_GetCapabilities, + SysMouseAImpl_EnumObjects, + SysMouseAImpl_GetProperty, + SysMouseAImpl_SetProperty, + SysMouseAImpl_Acquire, + SysMouseAImpl_Unacquire, + SysMouseAImpl_GetDeviceState, + SysMouseAImpl_GetDeviceData, + SysMouseAImpl_SetDataFormat, + SysMouseAImpl_SetEventNotification, + SysMouseAImpl_SetCooperativeLevel, + IDirectInputDevice2AImpl_GetObjectInfo, + SysMouseAImpl_GetDeviceInfo, + IDirectInputDevice2AImpl_RunControlPanel, + IDirectInputDevice2AImpl_Initialize, + IDirectInputDevice2AImpl_CreateEffect, + IDirectInputDevice2AImpl_EnumEffects, + IDirectInputDevice2AImpl_GetEffectInfo, + IDirectInputDevice2AImpl_GetForceFeedbackState, + IDirectInputDevice2AImpl_SendForceFeedbackCommand, + IDirectInputDevice2AImpl_EnumCreatedEffectObjects, + IDirectInputDevice2AImpl_Escape, + SysMouseAImpl_Poll, + IDirectInputDevice2AImpl_SendDeviceData, + IDirectInputDevice7AImpl_EnumEffectsInFile, + IDirectInputDevice7AImpl_WriteEffectToFile, + IDirectInputDevice8AImpl_BuildActionMap, + IDirectInputDevice8AImpl_SetActionMap, + IDirectInputDevice8AImpl_GetImageInfo +}; + +#if !defined(__STRICT_ANSI__) && defined(__GNUC__) +# define XCAST(fun) (typeof(SysMouseWvt.fun)) +#else +# define XCAST(fun) (void*) +#endif + +static IDirectInputDevice8WVtbl SysMouseWvt = +{ + IDirectInputDevice2WImpl_QueryInterface, + XCAST(AddRef)IDirectInputDevice2AImpl_AddRef, + XCAST(Release)SysMouseAImpl_Release, + XCAST(GetCapabilities)SysMouseAImpl_GetCapabilities, + SysMouseWImpl_EnumObjects, + XCAST(GetProperty)SysMouseAImpl_GetProperty, + XCAST(SetProperty)SysMouseAImpl_SetProperty, + XCAST(Acquire)SysMouseAImpl_Acquire, + XCAST(Unacquire)SysMouseAImpl_Unacquire, + XCAST(GetDeviceState)SysMouseAImpl_GetDeviceState, + XCAST(GetDeviceData)SysMouseAImpl_GetDeviceData, + XCAST(SetDataFormat)SysMouseAImpl_SetDataFormat, + XCAST(SetEventNotification)SysMouseAImpl_SetEventNotification, + XCAST(SetCooperativeLevel)SysMouseAImpl_SetCooperativeLevel, + IDirectInputDevice2WImpl_GetObjectInfo, + SysMouseWImpl_GetDeviceInfo, + XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel, + XCAST(Initialize)IDirectInputDevice2AImpl_Initialize, + XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect, + IDirectInputDevice2WImpl_EnumEffects, + IDirectInputDevice2WImpl_GetEffectInfo, + XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState, + XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand, + XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects, + XCAST(Escape)IDirectInputDevice2AImpl_Escape, + XCAST(Poll)SysMouseAImpl_Poll, + XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData, + IDirectInputDevice7WImpl_EnumEffectsInFile, + IDirectInputDevice7WImpl_WriteEffectToFile, + IDirectInputDevice8WImpl_BuildActionMap, + IDirectInputDevice8WImpl_SetActionMap, + IDirectInputDevice8WImpl_GetImageInfo +}; +#undef XCAST diff --git a/reactos/lib/dinput/regsvr.c b/reactos/lib/dinput/regsvr.c index 47c085daf7a..6bdd46a0e3c 100644 --- a/reactos/lib/dinput/regsvr.c +++ b/reactos/lib/dinput/regsvr.c @@ -1,558 +1,558 @@ -/* - * self-registerable dll functions for dinput.dll - * - * Copyright (C) 2003 John K. Hohm - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winreg.h" -#include "winerror.h" - -#include "dinput.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dinput); - -/* - * Near the bottom of this file are the exported DllRegisterServer and - * DllUnregisterServer, which make all this worthwhile. - */ - -/*********************************************************************** - * interface for self-registering - */ -struct regsvr_interface -{ - IID const *iid; /* NULL for end of list */ - LPCSTR name; /* can be NULL to omit */ - IID const *base_iid; /* can be NULL to omit */ - int num_methods; /* can be <0 to omit */ - CLSID const *ps_clsid; /* can be NULL to omit */ - CLSID const *ps_clsid32; /* can be NULL to omit */ -}; - -static HRESULT register_interfaces(struct regsvr_interface const *list); -static HRESULT unregister_interfaces(struct regsvr_interface const *list); - -struct regsvr_coclass -{ - CLSID const *clsid; /* NULL for end of list */ - LPCSTR name; /* can be NULL to omit */ - LPCSTR ips; /* can be NULL to omit */ - LPCSTR ips32; /* can be NULL to omit */ - LPCSTR ips32_tmodel; /* can be NULL to omit */ - LPCSTR progid; /* can be NULL to omit */ - LPCSTR viprogid; /* can be NULL to omit */ - LPCSTR progid_extra; /* can be NULL to omit */ -}; - -static HRESULT register_coclasses(struct regsvr_coclass const *list); -static HRESULT unregister_coclasses(struct regsvr_coclass const *list); - -/*********************************************************************** - * static string constants - */ -static WCHAR const interface_keyname[10] = { - 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 }; -static WCHAR const base_ifa_keyname[14] = { - 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', - 'e', 0 }; -static WCHAR const num_methods_keyname[11] = { - 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 }; -static WCHAR const ps_clsid_keyname[15] = { - 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', - 'i', 'd', 0 }; -static WCHAR const ps_clsid32_keyname[17] = { - 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', - 'i', 'd', '3', '2', 0 }; -static WCHAR const clsid_keyname[6] = { - 'C', 'L', 'S', 'I', 'D', 0 }; -static WCHAR const curver_keyname[7] = { - 'C', 'u', 'r', 'V', 'e', 'r', 0 }; -static WCHAR const ips_keyname[13] = { - 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', - 0 }; -static WCHAR const ips32_keyname[15] = { - 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', - '3', '2', 0 }; -static WCHAR const progid_keyname[7] = { - 'P', 'r', 'o', 'g', 'I', 'D', 0 }; -static WCHAR const viprogid_keyname[25] = { - 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p', - 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D', - 0 }; -static char const tmodel_valuename[] = "ThreadingModel"; - -/*********************************************************************** - * static helper functions - */ -static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid); -static LONG register_key_defvalueW(HKEY base, WCHAR const *name, - WCHAR const *value); -static LONG register_key_defvalueA(HKEY base, WCHAR const *name, - char const *value); -static LONG register_progid(WCHAR const *clsid, - char const *progid, char const *curver_progid, - char const *name, char const *extra); -static LONG recursive_delete_key(HKEY key); -static LONG recursive_delete_keyA(HKEY base, char const *name); -static LONG recursive_delete_keyW(HKEY base, WCHAR const *name); - -/*********************************************************************** - * register_interfaces - */ -static HRESULT register_interfaces(struct regsvr_interface const *list) -{ - LONG res = ERROR_SUCCESS; - HKEY interface_key; - - res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &interface_key, NULL); - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->iid; ++list) { - WCHAR buf[39]; - HKEY iid_key; - - StringFromGUID2(list->iid, buf, 39); - res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &iid_key, NULL); - if (res != ERROR_SUCCESS) goto error_close_interface_key; - - if (list->name) { - res = RegSetValueExA(iid_key, NULL, 0, REG_SZ, - (CONST BYTE*)(list->name), - strlen(list->name) + 1); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (list->base_iid) { - register_key_guid(iid_key, base_ifa_keyname, list->base_iid); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (0 <= list->num_methods) { - static WCHAR const fmt[3] = { '%', 'd', 0 }; - HKEY key; - - res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &key, NULL); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - - wsprintfW(buf, fmt, list->num_methods); - res = RegSetValueExW(key, NULL, 0, REG_SZ, - (CONST BYTE*)buf, - (lstrlenW(buf) + 1) * sizeof(WCHAR)); - RegCloseKey(key); - - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (list->ps_clsid) { - register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (list->ps_clsid32) { - register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - error_close_iid_key: - RegCloseKey(iid_key); - } - -error_close_interface_key: - RegCloseKey(interface_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * unregister_interfaces - */ -static HRESULT unregister_interfaces(struct regsvr_interface const *list) -{ - LONG res = ERROR_SUCCESS; - HKEY interface_key; - - res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, - KEY_READ | KEY_WRITE, &interface_key); - if (res == ERROR_FILE_NOT_FOUND) return S_OK; - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->iid; ++list) { - WCHAR buf[39]; - - StringFromGUID2(list->iid, buf, 39); - res = recursive_delete_keyW(interface_key, buf); - } - - RegCloseKey(interface_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * register_coclasses - */ -static HRESULT register_coclasses(struct regsvr_coclass const *list) -{ - LONG res = ERROR_SUCCESS; - HKEY coclass_key; - - res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL); - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->clsid; ++list) { - WCHAR buf[39]; - HKEY clsid_key; - - StringFromGUID2(list->clsid, buf, 39); - res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL); - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - - if (list->name) { - res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ, - (CONST BYTE*)(list->name), - strlen(list->name) + 1); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->ips) { - res = register_key_defvalueA(clsid_key, ips_keyname, list->ips); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->ips32) { - HKEY ips32_key; - - res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, - &ips32_key, NULL); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - - res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ, - (CONST BYTE*)list->ips32, - lstrlenA(list->ips32) + 1); - if (res == ERROR_SUCCESS && list->ips32_tmodel) - res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ, - (CONST BYTE*)list->ips32_tmodel, - strlen(list->ips32_tmodel) + 1); - RegCloseKey(ips32_key); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->progid) { - res = register_key_defvalueA(clsid_key, progid_keyname, - list->progid); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - - res = register_progid(buf, list->progid, NULL, - list->name, list->progid_extra); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->viprogid) { - res = register_key_defvalueA(clsid_key, viprogid_keyname, - list->viprogid); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - - res = register_progid(buf, list->viprogid, list->progid, - list->name, list->progid_extra); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - error_close_clsid_key: - RegCloseKey(clsid_key); - } - -error_close_coclass_key: - RegCloseKey(coclass_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * unregister_coclasses - */ -static HRESULT unregister_coclasses(struct regsvr_coclass const *list) -{ - LONG res = ERROR_SUCCESS; - HKEY coclass_key; - - res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, - KEY_READ | KEY_WRITE, &coclass_key); - if (res == ERROR_FILE_NOT_FOUND) return S_OK; - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->clsid; ++list) { - WCHAR buf[39]; - - StringFromGUID2(list->clsid, buf, 39); - res = recursive_delete_keyW(coclass_key, buf); - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - - if (list->progid) { - res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid); - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - } - - if (list->viprogid) { - res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid); - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - } - } - -error_close_coclass_key: - RegCloseKey(coclass_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * regsvr_key_guid - */ -static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) -{ - WCHAR buf[39]; - - StringFromGUID2(guid, buf, 39); - return register_key_defvalueW(base, name, buf); -} - -/*********************************************************************** - * regsvr_key_defvalueW - */ -static LONG register_key_defvalueW( - HKEY base, - WCHAR const *name, - WCHAR const *value) -{ - LONG res; - HKEY key; - - res = RegCreateKeyExW(base, name, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &key, NULL); - if (res != ERROR_SUCCESS) return res; - res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value, - (lstrlenW(value) + 1) * sizeof(WCHAR)); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * regsvr_key_defvalueA - */ -static LONG register_key_defvalueA( - HKEY base, - WCHAR const *name, - char const *value) -{ - LONG res; - HKEY key; - - res = RegCreateKeyExW(base, name, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &key, NULL); - if (res != ERROR_SUCCESS) return res; - res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value, - lstrlenA(value) + 1); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * regsvr_progid - */ -static LONG register_progid( - WCHAR const *clsid, - char const *progid, - char const *curver_progid, - char const *name, - char const *extra) -{ - LONG res; - HKEY progid_key; - - res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0, - NULL, 0, KEY_READ | KEY_WRITE, NULL, - &progid_key, NULL); - if (res != ERROR_SUCCESS) return res; - - if (name) { - res = RegSetValueExA(progid_key, NULL, 0, REG_SZ, - (CONST BYTE*)name, strlen(name) + 1); - if (res != ERROR_SUCCESS) goto error_close_progid_key; - } - - if (clsid) { - res = register_key_defvalueW(progid_key, clsid_keyname, clsid); - if (res != ERROR_SUCCESS) goto error_close_progid_key; - } - - if (curver_progid) { - res = register_key_defvalueA(progid_key, curver_keyname, - curver_progid); - if (res != ERROR_SUCCESS) goto error_close_progid_key; - } - - if (extra) { - HKEY extra_key; - - res = RegCreateKeyExA(progid_key, extra, 0, - NULL, 0, KEY_READ | KEY_WRITE, NULL, - &extra_key, NULL); - if (res == ERROR_SUCCESS) - RegCloseKey(extra_key); - } - -error_close_progid_key: - RegCloseKey(progid_key); - return res; -} - -/*********************************************************************** - * recursive_delete_key - */ -static LONG recursive_delete_key(HKEY key) -{ - LONG res; - WCHAR subkey_name[MAX_PATH]; - DWORD cName; - HKEY subkey; - - for (;;) { - cName = sizeof(subkey_name) / sizeof(WCHAR); - res = RegEnumKeyExW(key, 0, subkey_name, &cName, - NULL, NULL, NULL, NULL); - if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) { - res = ERROR_SUCCESS; /* presumably we're done enumerating */ - break; - } - res = RegOpenKeyExW(key, subkey_name, 0, - KEY_READ | KEY_WRITE, &subkey); - if (res == ERROR_FILE_NOT_FOUND) continue; - if (res != ERROR_SUCCESS) break; - - res = recursive_delete_key(subkey); - RegCloseKey(subkey); - if (res != ERROR_SUCCESS) break; - } - - if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0); - return res; -} - -/*********************************************************************** - * recursive_delete_keyA - */ -static LONG recursive_delete_keyA(HKEY base, char const *name) -{ - LONG res; - HKEY key; - - res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key); - if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; - if (res != ERROR_SUCCESS) return res; - res = recursive_delete_key(key); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * recursive_delete_keyW - */ -static LONG recursive_delete_keyW(HKEY base, WCHAR const *name) -{ - LONG res; - HKEY key; - - res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key); - if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; - if (res != ERROR_SUCCESS) return res; - res = recursive_delete_key(key); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * coclass list - */ -static struct regsvr_coclass const coclass_list[] = { - { - &CLSID_DirectInput, - "DirectInput Object", - NULL, - "dinput.dll", - "Both" - }, - { - &CLSID_DirectInputDevice, - "DirectInputDevice Object", - NULL, - "dinput.dll", - "Both" - }, - { NULL } /* list terminator */ -}; - -/*********************************************************************** - * interface list - */ - -static struct regsvr_interface const interface_list[] = { - { NULL } /* list terminator */ -}; - -/*********************************************************************** - * DllRegisterServer (DINPUT.@) - */ -HRESULT WINAPI DINPUT_DllRegisterServer(void) -{ - HRESULT hr; - - TRACE("\n"); - - hr = register_coclasses(coclass_list); - if (SUCCEEDED(hr)) - hr = register_interfaces(interface_list); - return hr; -} - -/*********************************************************************** - * DllUnregisterServer (DINPUT.@) - */ -HRESULT WINAPI DINPUT_DllUnregisterServer(void) -{ - HRESULT hr; - - TRACE("\n"); - - hr = unregister_coclasses(coclass_list); - if (SUCCEEDED(hr)) - hr = unregister_interfaces(interface_list); - return hr; -} +/* + * self-registerable dll functions for dinput.dll + * + * Copyright (C) 2003 John K. Hohm + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winreg.h" +#include "winerror.h" + +#include "dinput.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dinput); + +/* + * Near the bottom of this file are the exported DllRegisterServer and + * DllUnregisterServer, which make all this worthwhile. + */ + +/*********************************************************************** + * interface for self-registering + */ +struct regsvr_interface +{ + IID const *iid; /* NULL for end of list */ + LPCSTR name; /* can be NULL to omit */ + IID const *base_iid; /* can be NULL to omit */ + int num_methods; /* can be <0 to omit */ + CLSID const *ps_clsid; /* can be NULL to omit */ + CLSID const *ps_clsid32; /* can be NULL to omit */ +}; + +static HRESULT register_interfaces(struct regsvr_interface const *list); +static HRESULT unregister_interfaces(struct regsvr_interface const *list); + +struct regsvr_coclass +{ + CLSID const *clsid; /* NULL for end of list */ + LPCSTR name; /* can be NULL to omit */ + LPCSTR ips; /* can be NULL to omit */ + LPCSTR ips32; /* can be NULL to omit */ + LPCSTR ips32_tmodel; /* can be NULL to omit */ + LPCSTR progid; /* can be NULL to omit */ + LPCSTR viprogid; /* can be NULL to omit */ + LPCSTR progid_extra; /* can be NULL to omit */ +}; + +static HRESULT register_coclasses(struct regsvr_coclass const *list); +static HRESULT unregister_coclasses(struct regsvr_coclass const *list); + +/*********************************************************************** + * static string constants + */ +static WCHAR const interface_keyname[10] = { + 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 }; +static WCHAR const base_ifa_keyname[14] = { + 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', + 'e', 0 }; +static WCHAR const num_methods_keyname[11] = { + 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 }; +static WCHAR const ps_clsid_keyname[15] = { + 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', + 'i', 'd', 0 }; +static WCHAR const ps_clsid32_keyname[17] = { + 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', + 'i', 'd', '3', '2', 0 }; +static WCHAR const clsid_keyname[6] = { + 'C', 'L', 'S', 'I', 'D', 0 }; +static WCHAR const curver_keyname[7] = { + 'C', 'u', 'r', 'V', 'e', 'r', 0 }; +static WCHAR const ips_keyname[13] = { + 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', + 0 }; +static WCHAR const ips32_keyname[15] = { + 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', + '3', '2', 0 }; +static WCHAR const progid_keyname[7] = { + 'P', 'r', 'o', 'g', 'I', 'D', 0 }; +static WCHAR const viprogid_keyname[25] = { + 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p', + 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D', + 0 }; +static char const tmodel_valuename[] = "ThreadingModel"; + +/*********************************************************************** + * static helper functions + */ +static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid); +static LONG register_key_defvalueW(HKEY base, WCHAR const *name, + WCHAR const *value); +static LONG register_key_defvalueA(HKEY base, WCHAR const *name, + char const *value); +static LONG register_progid(WCHAR const *clsid, + char const *progid, char const *curver_progid, + char const *name, char const *extra); +static LONG recursive_delete_key(HKEY key); +static LONG recursive_delete_keyA(HKEY base, char const *name); +static LONG recursive_delete_keyW(HKEY base, WCHAR const *name); + +/*********************************************************************** + * register_interfaces + */ +static HRESULT register_interfaces(struct regsvr_interface const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY interface_key; + + res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &interface_key, NULL); + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->iid; ++list) { + WCHAR buf[39]; + HKEY iid_key; + + StringFromGUID2(list->iid, buf, 39); + res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &iid_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_interface_key; + + if (list->name) { + res = RegSetValueExA(iid_key, NULL, 0, REG_SZ, + (CONST BYTE*)(list->name), + strlen(list->name) + 1); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->base_iid) { + register_key_guid(iid_key, base_ifa_keyname, list->base_iid); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (0 <= list->num_methods) { + static WCHAR const fmt[3] = { '%', 'd', 0 }; + HKEY key; + + res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + + wsprintfW(buf, fmt, list->num_methods); + res = RegSetValueExW(key, NULL, 0, REG_SZ, + (CONST BYTE*)buf, + (lstrlenW(buf) + 1) * sizeof(WCHAR)); + RegCloseKey(key); + + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->ps_clsid) { + register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->ps_clsid32) { + register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + error_close_iid_key: + RegCloseKey(iid_key); + } + +error_close_interface_key: + RegCloseKey(interface_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * unregister_interfaces + */ +static HRESULT unregister_interfaces(struct regsvr_interface const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY interface_key; + + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, + KEY_READ | KEY_WRITE, &interface_key); + if (res == ERROR_FILE_NOT_FOUND) return S_OK; + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->iid; ++list) { + WCHAR buf[39]; + + StringFromGUID2(list->iid, buf, 39); + res = recursive_delete_keyW(interface_key, buf); + } + + RegCloseKey(interface_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * register_coclasses + */ +static HRESULT register_coclasses(struct regsvr_coclass const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY coclass_key; + + res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL); + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->clsid; ++list) { + WCHAR buf[39]; + HKEY clsid_key; + + StringFromGUID2(list->clsid, buf, 39); + res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + + if (list->name) { + res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ, + (CONST BYTE*)(list->name), + strlen(list->name) + 1); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->ips) { + res = register_key_defvalueA(clsid_key, ips_keyname, list->ips); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->ips32) { + HKEY ips32_key; + + res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, + &ips32_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ, + (CONST BYTE*)list->ips32, + lstrlenA(list->ips32) + 1); + if (res == ERROR_SUCCESS && list->ips32_tmodel) + res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ, + (CONST BYTE*)list->ips32_tmodel, + strlen(list->ips32_tmodel) + 1); + RegCloseKey(ips32_key); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->progid) { + res = register_key_defvalueA(clsid_key, progid_keyname, + list->progid); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = register_progid(buf, list->progid, NULL, + list->name, list->progid_extra); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->viprogid) { + res = register_key_defvalueA(clsid_key, viprogid_keyname, + list->viprogid); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = register_progid(buf, list->viprogid, list->progid, + list->name, list->progid_extra); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + error_close_clsid_key: + RegCloseKey(clsid_key); + } + +error_close_coclass_key: + RegCloseKey(coclass_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * unregister_coclasses + */ +static HRESULT unregister_coclasses(struct regsvr_coclass const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY coclass_key; + + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, + KEY_READ | KEY_WRITE, &coclass_key); + if (res == ERROR_FILE_NOT_FOUND) return S_OK; + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->clsid; ++list) { + WCHAR buf[39]; + + StringFromGUID2(list->clsid, buf, 39); + res = recursive_delete_keyW(coclass_key, buf); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + + if (list->progid) { + res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + } + + if (list->viprogid) { + res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + } + } + +error_close_coclass_key: + RegCloseKey(coclass_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * regsvr_key_guid + */ +static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) +{ + WCHAR buf[39]; + + StringFromGUID2(guid, buf, 39); + return register_key_defvalueW(base, name, buf); +} + +/*********************************************************************** + * regsvr_key_defvalueW + */ +static LONG register_key_defvalueW( + HKEY base, + WCHAR const *name, + WCHAR const *value) +{ + LONG res; + HKEY key; + + res = RegCreateKeyExW(base, name, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) return res; + res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value, + (lstrlenW(value) + 1) * sizeof(WCHAR)); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * regsvr_key_defvalueA + */ +static LONG register_key_defvalueA( + HKEY base, + WCHAR const *name, + char const *value) +{ + LONG res; + HKEY key; + + res = RegCreateKeyExW(base, name, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) return res; + res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value, + lstrlenA(value) + 1); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * regsvr_progid + */ +static LONG register_progid( + WCHAR const *clsid, + char const *progid, + char const *curver_progid, + char const *name, + char const *extra) +{ + LONG res; + HKEY progid_key; + + res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0, + NULL, 0, KEY_READ | KEY_WRITE, NULL, + &progid_key, NULL); + if (res != ERROR_SUCCESS) return res; + + if (name) { + res = RegSetValueExA(progid_key, NULL, 0, REG_SZ, + (CONST BYTE*)name, strlen(name) + 1); + if (res != ERROR_SUCCESS) goto error_close_progid_key; + } + + if (clsid) { + res = register_key_defvalueW(progid_key, clsid_keyname, clsid); + if (res != ERROR_SUCCESS) goto error_close_progid_key; + } + + if (curver_progid) { + res = register_key_defvalueA(progid_key, curver_keyname, + curver_progid); + if (res != ERROR_SUCCESS) goto error_close_progid_key; + } + + if (extra) { + HKEY extra_key; + + res = RegCreateKeyExA(progid_key, extra, 0, + NULL, 0, KEY_READ | KEY_WRITE, NULL, + &extra_key, NULL); + if (res == ERROR_SUCCESS) + RegCloseKey(extra_key); + } + +error_close_progid_key: + RegCloseKey(progid_key); + return res; +} + +/*********************************************************************** + * recursive_delete_key + */ +static LONG recursive_delete_key(HKEY key) +{ + LONG res; + WCHAR subkey_name[MAX_PATH]; + DWORD cName; + HKEY subkey; + + for (;;) { + cName = sizeof(subkey_name) / sizeof(WCHAR); + res = RegEnumKeyExW(key, 0, subkey_name, &cName, + NULL, NULL, NULL, NULL); + if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) { + res = ERROR_SUCCESS; /* presumably we're done enumerating */ + break; + } + res = RegOpenKeyExW(key, subkey_name, 0, + KEY_READ | KEY_WRITE, &subkey); + if (res == ERROR_FILE_NOT_FOUND) continue; + if (res != ERROR_SUCCESS) break; + + res = recursive_delete_key(subkey); + RegCloseKey(subkey); + if (res != ERROR_SUCCESS) break; + } + + if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0); + return res; +} + +/*********************************************************************** + * recursive_delete_keyA + */ +static LONG recursive_delete_keyA(HKEY base, char const *name) +{ + LONG res; + HKEY key; + + res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key); + if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; + if (res != ERROR_SUCCESS) return res; + res = recursive_delete_key(key); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * recursive_delete_keyW + */ +static LONG recursive_delete_keyW(HKEY base, WCHAR const *name) +{ + LONG res; + HKEY key; + + res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key); + if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; + if (res != ERROR_SUCCESS) return res; + res = recursive_delete_key(key); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * coclass list + */ +static struct regsvr_coclass const coclass_list[] = { + { + &CLSID_DirectInput, + "DirectInput Object", + NULL, + "dinput.dll", + "Both" + }, + { + &CLSID_DirectInputDevice, + "DirectInputDevice Object", + NULL, + "dinput.dll", + "Both" + }, + { NULL } /* list terminator */ +}; + +/*********************************************************************** + * interface list + */ + +static struct regsvr_interface const interface_list[] = { + { NULL } /* list terminator */ +}; + +/*********************************************************************** + * DllRegisterServer (DINPUT.@) + */ +HRESULT WINAPI DINPUT_DllRegisterServer(void) +{ + HRESULT hr; + + TRACE("\n"); + + hr = register_coclasses(coclass_list); + if (SUCCEEDED(hr)) + hr = register_interfaces(interface_list); + return hr; +} + +/*********************************************************************** + * DllUnregisterServer (DINPUT.@) + */ +HRESULT WINAPI DINPUT_DllUnregisterServer(void) +{ + HRESULT hr; + + TRACE("\n"); + + hr = unregister_coclasses(coclass_list); + if (SUCCEEDED(hr)) + hr = unregister_interfaces(interface_list); + return hr; +} diff --git a/reactos/lib/dinput8/dinput8_main.c b/reactos/lib/dinput8/dinput8_main.c index 77ac6d52618..7de9b95079b 100644 --- a/reactos/lib/dinput8/dinput8_main.c +++ b/reactos/lib/dinput8/dinput8_main.c @@ -1,83 +1,83 @@ -/* DirectInput 8 - * - * Copyright 2002 TransGaming Technologies Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" -#include -#include -#include - -#include "wine/debug.h" -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "dinput.h" - -WINE_DEFAULT_DEBUG_CHANNEL(dinput); - -/****************************************************************************** - * DirectInput8Create (DINPUT8.@) - */ -HRESULT WINAPI DirectInput8Create( - HINSTANCE hinst, DWORD dwVersion, REFIID riid, LPVOID *ppDI, - LPUNKNOWN punkOuter -) { - return DirectInputCreateEx(hinst, dwVersion, riid, ppDI, punkOuter); -} - -/*********************************************************************** - * DllCanUnloadNow (DINPUT8.@) - */ -HRESULT WINAPI DINPUT8_DllCanUnloadNow(void) -{ - FIXME("(void): stub\n"); - - return S_FALSE; -} - -/*********************************************************************** - * DllGetClassObject (DINPUT8.@) - */ -HRESULT WINAPI DINPUT8_DllGetClassObject(REFCLSID rclsid, REFIID riid, - LPVOID *ppv) -{ - FIXME("(%p, %p, %p): stub\n", debugstr_guid(rclsid), - debugstr_guid(riid), ppv); - - return CLASS_E_CLASSNOTAVAILABLE; -} - -/*********************************************************************** - * DllRegisterServer (DINPUT8.@) - */ -HRESULT WINAPI DINPUT8_DllRegisterServer(void) -{ - FIXME("(void): stub\n"); - - return S_OK; -} - -/*********************************************************************** - * DllUnregisterServer (DINPUT8.@) - */ -HRESULT WINAPI DINPUT8_DllUnregisterServer(void) -{ - FIXME("(void): stub\n"); - - return S_OK; -} +/* DirectInput 8 + * + * Copyright 2002 TransGaming Technologies Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include +#include +#include + +#include "wine/debug.h" +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "dinput.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dinput); + +/****************************************************************************** + * DirectInput8Create (DINPUT8.@) + */ +HRESULT WINAPI DirectInput8Create( + HINSTANCE hinst, DWORD dwVersion, REFIID riid, LPVOID *ppDI, + LPUNKNOWN punkOuter +) { + return DirectInputCreateEx(hinst, dwVersion, riid, ppDI, punkOuter); +} + +/*********************************************************************** + * DllCanUnloadNow (DINPUT8.@) + */ +HRESULT WINAPI DINPUT8_DllCanUnloadNow(void) +{ + FIXME("(void): stub\n"); + + return S_FALSE; +} + +/*********************************************************************** + * DllGetClassObject (DINPUT8.@) + */ +HRESULT WINAPI DINPUT8_DllGetClassObject(REFCLSID rclsid, REFIID riid, + LPVOID *ppv) +{ + FIXME("(%p, %p, %p): stub\n", debugstr_guid(rclsid), + debugstr_guid(riid), ppv); + + return CLASS_E_CLASSNOTAVAILABLE; +} + +/*********************************************************************** + * DllRegisterServer (DINPUT8.@) + */ +HRESULT WINAPI DINPUT8_DllRegisterServer(void) +{ + FIXME("(void): stub\n"); + + return S_OK; +} + +/*********************************************************************** + * DllUnregisterServer (DINPUT8.@) + */ +HRESULT WINAPI DINPUT8_DllUnregisterServer(void) +{ + FIXME("(void): stub\n"); + + return S_OK; +} diff --git a/reactos/lib/freetype/include/freetype/ftbitmap.h b/reactos/lib/freetype/include/freetype/ftbitmap.h index 2868bb7877b..319dd086944 100644 --- a/reactos/lib/freetype/include/freetype/ftbitmap.h +++ b/reactos/lib/freetype/include/freetype/ftbitmap.h @@ -1,206 +1,206 @@ -/***************************************************************************/ -/* */ -/* ftbitmap.h */ -/* */ -/* FreeType utility functions for converting 1bpp, 2bpp, 4bpp, and 8bpp */ -/* bitmaps into 8bpp format (specification). */ -/* */ -/* Copyright 2004, 2005 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - -#ifndef __FTBITMAP_H__ -#define __FTBITMAP_H__ - - -#include -#include FT_FREETYPE_H - -#ifdef FREETYPE_H -#error "freetype.h of FreeType 1 has been loaded!" -#error "Please fix the directory search order for header files" -#error "so that freetype.h of FreeType 2 is found first." -#endif - - -FT_BEGIN_HEADER - - - /*************************************************************************/ - /* */ - /*
*/ - /* bitmap_handling */ - /* */ - /* */ - /* Bitmap Handling */ - /* */ - /* <Abstract> */ - /* Handling FT_Bitmap objects. */ - /* */ - /* <Description> */ - /* This section contains functions for converting FT_Bitmap objects. */ - /* */ - /*************************************************************************/ - - - /*************************************************************************/ - /* */ - /* <Function> */ - /* FT_Bitmap_New */ - /* */ - /* <Description> */ - /* Initialize a pointer to an FT_Bitmap structure. */ - /* */ - /* <InOut> */ - /* abitmap :: A pointer to the bitmap structure. */ - /* */ - FT_EXPORT( void ) - FT_Bitmap_New( FT_Bitmap *abitmap ); - - - /*************************************************************************/ - /* */ - /* <Function> */ - /* FT_Bitmap_Copy */ - /* */ - /* <Description> */ - /* Copies an bitmap into another one. */ - /* */ - /* <Input> */ - /* library :: A handle to a library object. */ - /* */ - /* source :: A handle to the source bitmap. */ - /* */ - /* <Output> */ - /* target :: A handle to the target bitmap. */ - /* */ - /* <Return> */ - /* FreeType error code. 0 means success. */ - /* */ - FT_EXPORT_DEF( FT_Error ) - FT_Bitmap_Copy( FT_Library library, - const FT_Bitmap *source, - FT_Bitmap *target); - - - /*************************************************************************/ - /* */ - /* <Function> */ - /* FT_Bitmap_Embolden */ - /* */ - /* <Description> */ - /* Embolden a bitmap. The new bitmap will be about `xStrength' */ - /* pixels wider and `yStrength' pixels higher. The left and bottom */ - /* borders are kept unchanged. */ - /* */ - /* <Input> */ - /* library :: A handle to a library object. */ - /* */ - /* xStrength :: How strong the glyph is emboldened horizontally. */ - /* Expressed in 26.6 pixel format. */ - /* */ - /* yStrength :: How strong the glyph is emboldened vertically. */ - /* Expressed in 26.6 pixel format. */ - /* */ - /* <InOut> */ - /* bitmap :: A handle to the target bitmap. */ - /* */ - /* <Return> */ - /* FreeType error code. 0 means success. */ - /* */ - /* <Note> */ - /* The current implementation restricts `xStrength' to be less than */ - /* or equal to 8 if bitmap is of pixel_mode @FT_PIXEL_MODE_MONO. */ - /* */ - /* Don't embolden the bitmap owned by a @FT_GlyphSlot directly! Call */ - /* @FT_Bitmap_Copy to get a copy and work on the copy instead. */ - /* */ - FT_EXPORT_DEF( FT_Error ) - FT_Bitmap_Embolden( FT_Library library, - FT_Bitmap* bitmap, - FT_Pos xStrength, - FT_Pos yStrength ); - - - /*************************************************************************/ - /* */ - /* <Function> */ - /* FT_Bitmap_Convert */ - /* */ - /* <Description> */ - /* Convert a bitmap object with depth 1bpp, 2bpp, 4bpp, or 8bpp to a */ - /* bitmap object with depth 8bpp, making the number of used bytes per */ - /* line (a.k.a. the `pitch') a multiple of `alignment'. */ - /* */ - /* <Input> */ - /* library :: A handle to a library object. */ - /* */ - /* source :: The source bitmap. */ - /* */ - /* alignment :: The pitch of the bitmap is a multiple of this */ - /* parameter. Common values are 1, 2, or 4. */ - /* */ - /* <Output> */ - /* target :: The target bitmap. */ - /* */ - /* <Return> */ - /* FreeType error code. 0 means success. */ - /* */ - /* <Note> */ - /* It is possible to call @FT_Bitmap_Convert multiple times without */ - /* calling @FT_Bitmap_Done (the memory is simply reallocated). */ - /* */ - /* Use @FT_Bitmap_Done to finally remove the bitmap object. */ - /* */ - /* The `library' argument is taken to have access to FreeType's */ - /* memory handling functions. */ - /* */ - FT_EXPORT( FT_Error ) - FT_Bitmap_Convert( FT_Library library, - const FT_Bitmap *source, - FT_Bitmap *target, - FT_Int alignment ); - - - /*************************************************************************/ - /* */ - /* <Function> */ - /* FT_Bitmap_Done */ - /* */ - /* <Description> */ - /* Destroy a bitmap object created with @FT_Bitmap_New. */ - /* */ - /* <Input> */ - /* library :: A handle to a library object. */ - /* */ - /* bitmap :: The bitmap object to be freed. */ - /* */ - /* <Return> */ - /* FreeType error code. 0 means success. */ - /* */ - /* <Note> */ - /* The `library' argument is taken to have access to FreeType's */ - /* memory handling functions. */ - /* */ - FT_EXPORT( FT_Error ) - FT_Bitmap_Done( FT_Library library, - FT_Bitmap *bitmap ); - - - /* */ - - -FT_END_HEADER - -#endif /* __FTBITMAP_H__ */ - - -/* END */ +/***************************************************************************/ +/* */ +/* ftbitmap.h */ +/* */ +/* FreeType utility functions for converting 1bpp, 2bpp, 4bpp, and 8bpp */ +/* bitmaps into 8bpp format (specification). */ +/* */ +/* Copyright 2004, 2005 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTBITMAP_H__ +#define __FTBITMAP_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* bitmap_handling */ + /* */ + /* <Title> */ + /* Bitmap Handling */ + /* */ + /* <Abstract> */ + /* Handling FT_Bitmap objects. */ + /* */ + /* <Description> */ + /* This section contains functions for converting FT_Bitmap objects. */ + /* */ + /*************************************************************************/ + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Bitmap_New */ + /* */ + /* <Description> */ + /* Initialize a pointer to an FT_Bitmap structure. */ + /* */ + /* <InOut> */ + /* abitmap :: A pointer to the bitmap structure. */ + /* */ + FT_EXPORT( void ) + FT_Bitmap_New( FT_Bitmap *abitmap ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Bitmap_Copy */ + /* */ + /* <Description> */ + /* Copies an bitmap into another one. */ + /* */ + /* <Input> */ + /* library :: A handle to a library object. */ + /* */ + /* source :: A handle to the source bitmap. */ + /* */ + /* <Output> */ + /* target :: A handle to the target bitmap. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + FT_EXPORT_DEF( FT_Error ) + FT_Bitmap_Copy( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Bitmap_Embolden */ + /* */ + /* <Description> */ + /* Embolden a bitmap. The new bitmap will be about `xStrength' */ + /* pixels wider and `yStrength' pixels higher. The left and bottom */ + /* borders are kept unchanged. */ + /* */ + /* <Input> */ + /* library :: A handle to a library object. */ + /* */ + /* xStrength :: How strong the glyph is emboldened horizontally. */ + /* Expressed in 26.6 pixel format. */ + /* */ + /* yStrength :: How strong the glyph is emboldened vertically. */ + /* Expressed in 26.6 pixel format. */ + /* */ + /* <InOut> */ + /* bitmap :: A handle to the target bitmap. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The current implementation restricts `xStrength' to be less than */ + /* or equal to 8 if bitmap is of pixel_mode @FT_PIXEL_MODE_MONO. */ + /* */ + /* Don't embolden the bitmap owned by a @FT_GlyphSlot directly! Call */ + /* @FT_Bitmap_Copy to get a copy and work on the copy instead. */ + /* */ + FT_EXPORT_DEF( FT_Error ) + FT_Bitmap_Embolden( FT_Library library, + FT_Bitmap* bitmap, + FT_Pos xStrength, + FT_Pos yStrength ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Bitmap_Convert */ + /* */ + /* <Description> */ + /* Convert a bitmap object with depth 1bpp, 2bpp, 4bpp, or 8bpp to a */ + /* bitmap object with depth 8bpp, making the number of used bytes per */ + /* line (a.k.a. the `pitch') a multiple of `alignment'. */ + /* */ + /* <Input> */ + /* library :: A handle to a library object. */ + /* */ + /* source :: The source bitmap. */ + /* */ + /* alignment :: The pitch of the bitmap is a multiple of this */ + /* parameter. Common values are 1, 2, or 4. */ + /* */ + /* <Output> */ + /* target :: The target bitmap. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* It is possible to call @FT_Bitmap_Convert multiple times without */ + /* calling @FT_Bitmap_Done (the memory is simply reallocated). */ + /* */ + /* Use @FT_Bitmap_Done to finally remove the bitmap object. */ + /* */ + /* The `library' argument is taken to have access to FreeType's */ + /* memory handling functions. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Convert( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target, + FT_Int alignment ); + + + /*************************************************************************/ + /* */ + /* <Function> */ + /* FT_Bitmap_Done */ + /* */ + /* <Description> */ + /* Destroy a bitmap object created with @FT_Bitmap_New. */ + /* */ + /* <Input> */ + /* library :: A handle to a library object. */ + /* */ + /* bitmap :: The bitmap object to be freed. */ + /* */ + /* <Return> */ + /* FreeType error code. 0 means success. */ + /* */ + /* <Note> */ + /* The `library' argument is taken to have access to FreeType's */ + /* memory handling functions. */ + /* */ + FT_EXPORT( FT_Error ) + FT_Bitmap_Done( FT_Library library, + FT_Bitmap *bitmap ); + + + /* */ + + +FT_END_HEADER + +#endif /* __FTBITMAP_H__ */ + + +/* END */ diff --git a/reactos/lib/freetype/include/freetype/ftotval.h b/reactos/lib/freetype/include/freetype/ftotval.h index abde36669ea..a8de58af9d3 100644 --- a/reactos/lib/freetype/include/freetype/ftotval.h +++ b/reactos/lib/freetype/include/freetype/ftotval.h @@ -1,170 +1,170 @@ -/***************************************************************************/ -/* */ -/* ftotval.h */ -/* */ -/* FreeType API for validating OpenType tables (specification). */ -/* */ -/* Copyright 2004, 2005 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - -/***************************************************************************/ -/* */ -/* */ -/* Warning: This module might be moved to a different library in the */ -/* future to avoid a tight dependency between FreeType and the */ -/* OpenType specification. */ -/* */ -/* */ -/***************************************************************************/ - - -#ifndef __FTOTVAL_H__ -#define __FTOTVAL_H__ - -#include <ft2build.h> -#include FT_FREETYPE_H - -#ifdef FREETYPE_H -#error "freetype.h of FreeType 1 has been loaded!" -#error "Please fix the directory search order for header files" -#error "so that freetype.h of FreeType 2 is found first." -#endif - - -FT_BEGIN_HEADER - - - /*************************************************************************/ - /* */ - /* <Section> */ - /* ot_validation */ - /* */ - /* <Title> */ - /* OpenType Validation */ - /* */ - /* <Abstract> */ - /* An API to validate OpenType tables. */ - /* */ - /* <Description> */ - /* This section contains the declaration of functions to validate */ - /* some OpenType tables (BASE, GDEF, GPOS, GSUB, JSTF). */ - /* */ - /*************************************************************************/ - - - /********************************************************************** - * - * @enum: - * FT_VALIDATE_XXX - * - * @description: - * A list of bit-field constants used with @FT_OpenType_Validate to - * indicate which OpenType tables should be validated. - * - * @values: - * FT_VALIDATE_BASE :: - * Validate BASE table. - * - * FT_VALIDATE_GDEF :: - * Validate GDEF table. - * - * FT_VALIDATE_GPOS :: - * Validate GPOS table. - * - * FT_VALIDATE_GSUB :: - * Validate GSUB table. - * - * FT_VALIDATE_JSTF :: - * Validate JSTF table. - * - * FT_VALIDATE_OT :: - * Validate all OpenType tables (BASE, GDEF, GPOS, GSUB, JSTF). - * - */ -#define FT_VALIDATE_BASE 0x0100 -#define FT_VALIDATE_GDEF 0x0200 -#define FT_VALIDATE_GPOS 0x0400 -#define FT_VALIDATE_GSUB 0x0800 -#define FT_VALIDATE_JSTF 0x1000 - -#define FT_VALIDATE_OT FT_VALIDATE_BASE | \ - FT_VALIDATE_GDEF | \ - FT_VALIDATE_GPOS | \ - FT_VALIDATE_GSUB | \ - FT_VALIDATE_JSTF - - /* */ - - /********************************************************************** - * - * @function: - * FT_OpenType_Validate - * - * @description: - * Validate various OpenType tables to assure that all offsets and - * indices are valid. The idea is that a higher-level library which - * actually does the text layout can access those tables without - * error checking (which can be quite time consuming). - * - * @input: - * face :: - * A handle to the input face. - * - * validation_flags :: - * A bit field which specifies the tables to be validated. See - * @FT_VALIDATE_XXX for possible values. - * - * @output: - * BASE_table :: - * A pointer to the BASE table. - * - * GDEF_table :: - * A pointer to the GDEF table. - * - * GPOS_table :: - * A pointer to the GPOS table. - * - * GSUB_table :: - * A pointer to the GSUB table. - * - * JSTF_table :: - * A pointer to the JSTF table. - * - * @return: - * FreeType error code. 0 means success. - * - * @note: - * This function only works with OpenType fonts, returning an error - * otherwise. - * - * After use, the application should deallocate the five tables with - * `free'. A NULL value indicates that the table either doesn't exist - * in the font, or the application hasn't asked for validation. - */ - FT_EXPORT( FT_Error ) - FT_OpenType_Validate( FT_Face face, - FT_UInt validation_flags, - FT_Bytes *BASE_table, - FT_Bytes *GDEF_table, - FT_Bytes *GPOS_table, - FT_Bytes *GSUB_table, - FT_Bytes *JSTF_table ); - - /* */ - - -FT_END_HEADER - -#endif /* __FTOTVAL_H__ */ - - -/* END */ +/***************************************************************************/ +/* */ +/* ftotval.h */ +/* */ +/* FreeType API for validating OpenType tables (specification). */ +/* */ +/* Copyright 2004, 2005 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +/***************************************************************************/ +/* */ +/* */ +/* Warning: This module might be moved to a different library in the */ +/* future to avoid a tight dependency between FreeType and the */ +/* OpenType specification. */ +/* */ +/* */ +/***************************************************************************/ + + +#ifndef __FTOTVAL_H__ +#define __FTOTVAL_H__ + +#include <ft2build.h> +#include FT_FREETYPE_H + +#ifdef FREETYPE_H +#error "freetype.h of FreeType 1 has been loaded!" +#error "Please fix the directory search order for header files" +#error "so that freetype.h of FreeType 2 is found first." +#endif + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /* */ + /* <Section> */ + /* ot_validation */ + /* */ + /* <Title> */ + /* OpenType Validation */ + /* */ + /* <Abstract> */ + /* An API to validate OpenType tables. */ + /* */ + /* <Description> */ + /* This section contains the declaration of functions to validate */ + /* some OpenType tables (BASE, GDEF, GPOS, GSUB, JSTF). */ + /* */ + /*************************************************************************/ + + + /********************************************************************** + * + * @enum: + * FT_VALIDATE_XXX + * + * @description: + * A list of bit-field constants used with @FT_OpenType_Validate to + * indicate which OpenType tables should be validated. + * + * @values: + * FT_VALIDATE_BASE :: + * Validate BASE table. + * + * FT_VALIDATE_GDEF :: + * Validate GDEF table. + * + * FT_VALIDATE_GPOS :: + * Validate GPOS table. + * + * FT_VALIDATE_GSUB :: + * Validate GSUB table. + * + * FT_VALIDATE_JSTF :: + * Validate JSTF table. + * + * FT_VALIDATE_OT :: + * Validate all OpenType tables (BASE, GDEF, GPOS, GSUB, JSTF). + * + */ +#define FT_VALIDATE_BASE 0x0100 +#define FT_VALIDATE_GDEF 0x0200 +#define FT_VALIDATE_GPOS 0x0400 +#define FT_VALIDATE_GSUB 0x0800 +#define FT_VALIDATE_JSTF 0x1000 + +#define FT_VALIDATE_OT FT_VALIDATE_BASE | \ + FT_VALIDATE_GDEF | \ + FT_VALIDATE_GPOS | \ + FT_VALIDATE_GSUB | \ + FT_VALIDATE_JSTF + + /* */ + + /********************************************************************** + * + * @function: + * FT_OpenType_Validate + * + * @description: + * Validate various OpenType tables to assure that all offsets and + * indices are valid. The idea is that a higher-level library which + * actually does the text layout can access those tables without + * error checking (which can be quite time consuming). + * + * @input: + * face :: + * A handle to the input face. + * + * validation_flags :: + * A bit field which specifies the tables to be validated. See + * @FT_VALIDATE_XXX for possible values. + * + * @output: + * BASE_table :: + * A pointer to the BASE table. + * + * GDEF_table :: + * A pointer to the GDEF table. + * + * GPOS_table :: + * A pointer to the GPOS table. + * + * GSUB_table :: + * A pointer to the GSUB table. + * + * JSTF_table :: + * A pointer to the JSTF table. + * + * @return: + * FreeType error code. 0 means success. + * + * @note: + * This function only works with OpenType fonts, returning an error + * otherwise. + * + * After use, the application should deallocate the five tables with + * `free'. A NULL value indicates that the table either doesn't exist + * in the font, or the application hasn't asked for validation. + */ + FT_EXPORT( FT_Error ) + FT_OpenType_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *BASE_table, + FT_Bytes *GDEF_table, + FT_Bytes *GPOS_table, + FT_Bytes *GSUB_table, + FT_Bytes *JSTF_table ); + + /* */ + + +FT_END_HEADER + +#endif /* __FTOTVAL_H__ */ + + +/* END */ diff --git a/reactos/lib/freetype/include/freetype/internal/ftvalid.h b/reactos/lib/freetype/include/freetype/internal/ftvalid.h index 3f318493d2c..d52ff2f3b29 100644 --- a/reactos/lib/freetype/include/freetype/internal/ftvalid.h +++ b/reactos/lib/freetype/include/freetype/internal/ftvalid.h @@ -1,148 +1,148 @@ -/***************************************************************************/ -/* */ -/* ftvalid.h */ -/* */ -/* FreeType validation support (specification). */ -/* */ -/* Copyright 2004 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - -#ifndef __FTVALID_H__ -#define __FTVALID_H__ - -#include <ft2build.h> -#include FT_CONFIG_STANDARD_LIBRARY_H /* for ft_setjmp and ft_longjmp */ - - -FT_BEGIN_HEADER - - - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - /**** ****/ - /**** ****/ - /**** V A L I D A T I O N ****/ - /**** ****/ - /**** ****/ - /*************************************************************************/ - /*************************************************************************/ - /*************************************************************************/ - - /* handle to a validation object */ - typedef struct FT_ValidatorRec_* FT_Validator; - - - /*************************************************************************/ - /* */ - /* There are three distinct validation levels defined here: */ - /* */ - /* FT_VALIDATE_DEFAULT :: */ - /* A table that passes this validation level can be used reliably by */ - /* FreeType. It generally means that all offsets have been checked to */ - /* prevent out-of-bound reads, that array counts are correct, etc. */ - /* */ - /* FT_VALIDATE_TIGHT :: */ - /* A table that passes this validation level can be used reliably and */ - /* doesn't contain invalid data. For example, a charmap table that */ - /* returns invalid glyph indices will not pass, even though it can */ - /* be used with FreeType in default mode (the library will simply */ - /* return an error later when trying to load the glyph). */ - /* */ - /* It also checks that fields which must be a multiple of 2, 4, or 8, */ - /* don't have incorrect values, etc. */ - /* */ - /* FT_VALIDATE_PARANOID :: */ - /* Only for font debugging. Checks that a table follows the */ - /* specification by 100%. Very few fonts will be able to pass this */ - /* level anyway but it can be useful for certain tools like font */ - /* editors/converters. */ - /* */ - typedef enum FT_ValidationLevel_ - { - FT_VALIDATE_DEFAULT = 0, - FT_VALIDATE_TIGHT, - FT_VALIDATE_PARANOID - - } FT_ValidationLevel; - - - /* validator structure */ - typedef struct FT_ValidatorRec_ - { - const FT_Byte* base; /* address of table in memory */ - const FT_Byte* limit; /* `base' + sizeof(table) in memory */ - FT_ValidationLevel level; /* validation level */ - FT_Error error; /* error returned. 0 means success */ - - ft_jmp_buf jump_buffer; /* used for exception handling */ - - } FT_ValidatorRec; - - -#define FT_VALIDATOR( x ) ((FT_Validator)( x )) - - - FT_BASE( void ) - ft_validator_init( FT_Validator valid, - const FT_Byte* base, - const FT_Byte* limit, - FT_ValidationLevel level ); - - FT_BASE( FT_Int ) - ft_validator_run( FT_Validator valid ); - - /* Sets the error field in a validator, then calls `longjmp' to return */ - /* to high-level caller. Using `setjmp/longjmp' avoids many stupid */ - /* error checks within the validation routines. */ - /* */ - FT_BASE( void ) - ft_validator_error( FT_Validator valid, - FT_Error error ); - - - /* Calls ft_validate_error. Assumes that the `valid' local variable */ - /* holds a pointer to the current validator object. */ - /* */ - /* Use preprocessor prescan to pass FT_ERR_PREFIX. */ - /* */ -#define FT_INVALID( _prefix, _error ) FT_INVALID_( _prefix, _error ) -#define FT_INVALID_( _prefix, _error ) \ - ft_validator_error( valid, _prefix ## _error ) - - /* called when a broken table is detected */ -#define FT_INVALID_TOO_SHORT \ - FT_INVALID( FT_ERR_PREFIX, Invalid_Table ) - - /* called when an invalid offset is detected */ -#define FT_INVALID_OFFSET \ - FT_INVALID( FT_ERR_PREFIX, Invalid_Offset ) - - /* called when an invalid format/value is detected */ -#define FT_INVALID_FORMAT \ - FT_INVALID( FT_ERR_PREFIX, Invalid_Table ) - - /* called when an invalid glyph index is detected */ -#define FT_INVALID_GLYPH_ID \ - FT_INVALID( FT_ERR_PREFIX, Invalid_Glyph_Index ) - - /* called when an invalid field value is detected */ -#define FT_INVALID_DATA \ - FT_INVALID( FT_ERR_PREFIX, Invalid_Table ) - - -FT_END_HEADER - -#endif /* __FTVALID_H__ */ - - -/* END */ +/***************************************************************************/ +/* */ +/* ftvalid.h */ +/* */ +/* FreeType validation support (specification). */ +/* */ +/* Copyright 2004 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __FTVALID_H__ +#define __FTVALID_H__ + +#include <ft2build.h> +#include FT_CONFIG_STANDARD_LIBRARY_H /* for ft_setjmp and ft_longjmp */ + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + /**** ****/ + /**** ****/ + /**** V A L I D A T I O N ****/ + /**** ****/ + /**** ****/ + /*************************************************************************/ + /*************************************************************************/ + /*************************************************************************/ + + /* handle to a validation object */ + typedef struct FT_ValidatorRec_* FT_Validator; + + + /*************************************************************************/ + /* */ + /* There are three distinct validation levels defined here: */ + /* */ + /* FT_VALIDATE_DEFAULT :: */ + /* A table that passes this validation level can be used reliably by */ + /* FreeType. It generally means that all offsets have been checked to */ + /* prevent out-of-bound reads, that array counts are correct, etc. */ + /* */ + /* FT_VALIDATE_TIGHT :: */ + /* A table that passes this validation level can be used reliably and */ + /* doesn't contain invalid data. For example, a charmap table that */ + /* returns invalid glyph indices will not pass, even though it can */ + /* be used with FreeType in default mode (the library will simply */ + /* return an error later when trying to load the glyph). */ + /* */ + /* It also checks that fields which must be a multiple of 2, 4, or 8, */ + /* don't have incorrect values, etc. */ + /* */ + /* FT_VALIDATE_PARANOID :: */ + /* Only for font debugging. Checks that a table follows the */ + /* specification by 100%. Very few fonts will be able to pass this */ + /* level anyway but it can be useful for certain tools like font */ + /* editors/converters. */ + /* */ + typedef enum FT_ValidationLevel_ + { + FT_VALIDATE_DEFAULT = 0, + FT_VALIDATE_TIGHT, + FT_VALIDATE_PARANOID + + } FT_ValidationLevel; + + + /* validator structure */ + typedef struct FT_ValidatorRec_ + { + const FT_Byte* base; /* address of table in memory */ + const FT_Byte* limit; /* `base' + sizeof(table) in memory */ + FT_ValidationLevel level; /* validation level */ + FT_Error error; /* error returned. 0 means success */ + + ft_jmp_buf jump_buffer; /* used for exception handling */ + + } FT_ValidatorRec; + + +#define FT_VALIDATOR( x ) ((FT_Validator)( x )) + + + FT_BASE( void ) + ft_validator_init( FT_Validator valid, + const FT_Byte* base, + const FT_Byte* limit, + FT_ValidationLevel level ); + + FT_BASE( FT_Int ) + ft_validator_run( FT_Validator valid ); + + /* Sets the error field in a validator, then calls `longjmp' to return */ + /* to high-level caller. Using `setjmp/longjmp' avoids many stupid */ + /* error checks within the validation routines. */ + /* */ + FT_BASE( void ) + ft_validator_error( FT_Validator valid, + FT_Error error ); + + + /* Calls ft_validate_error. Assumes that the `valid' local variable */ + /* holds a pointer to the current validator object. */ + /* */ + /* Use preprocessor prescan to pass FT_ERR_PREFIX. */ + /* */ +#define FT_INVALID( _prefix, _error ) FT_INVALID_( _prefix, _error ) +#define FT_INVALID_( _prefix, _error ) \ + ft_validator_error( valid, _prefix ## _error ) + + /* called when a broken table is detected */ +#define FT_INVALID_TOO_SHORT \ + FT_INVALID( FT_ERR_PREFIX, Invalid_Table ) + + /* called when an invalid offset is detected */ +#define FT_INVALID_OFFSET \ + FT_INVALID( FT_ERR_PREFIX, Invalid_Offset ) + + /* called when an invalid format/value is detected */ +#define FT_INVALID_FORMAT \ + FT_INVALID( FT_ERR_PREFIX, Invalid_Table ) + + /* called when an invalid glyph index is detected */ +#define FT_INVALID_GLYPH_ID \ + FT_INVALID( FT_ERR_PREFIX, Invalid_Glyph_Index ) + + /* called when an invalid field value is detected */ +#define FT_INVALID_DATA \ + FT_INVALID( FT_ERR_PREFIX, Invalid_Table ) + + +FT_END_HEADER + +#endif /* __FTVALID_H__ */ + + +/* END */ diff --git a/reactos/lib/freetype/include/freetype/internal/services/svotval.h b/reactos/lib/freetype/include/freetype/internal/services/svotval.h index 44c2a20dc40..fbe45d0ddfe 100644 --- a/reactos/lib/freetype/include/freetype/internal/services/svotval.h +++ b/reactos/lib/freetype/include/freetype/internal/services/svotval.h @@ -1,53 +1,53 @@ -/***************************************************************************/ -/* */ -/* svotval.h */ -/* */ -/* The FreeType OpenType validation service (specification). */ -/* */ -/* Copyright 2004 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - -#ifndef __SVOTVAL_H__ -#define __SVOTVAL_H__ - - -FT_BEGIN_HEADER - - -#define FT_SERVICE_ID_OPENTYPE_VALIDATE "opentype-validate" - - - typedef FT_Error - (*otv_validate_func)( FT_Face face, - FT_UInt ot_flags, - FT_Bytes *base, - FT_Bytes *gdef, - FT_Bytes *gpos, - FT_Bytes *gsub, - FT_Bytes *jstf ); - - - FT_DEFINE_SERVICE( OTvalidate ) - { - otv_validate_func validate; - }; - - /* */ - - -FT_END_HEADER - - -#endif /* __SVOTVAL_H__ */ - - -/* END */ +/***************************************************************************/ +/* */ +/* svotval.h */ +/* */ +/* The FreeType OpenType validation service (specification). */ +/* */ +/* Copyright 2004 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __SVOTVAL_H__ +#define __SVOTVAL_H__ + + +FT_BEGIN_HEADER + + +#define FT_SERVICE_ID_OPENTYPE_VALIDATE "opentype-validate" + + + typedef FT_Error + (*otv_validate_func)( FT_Face face, + FT_UInt ot_flags, + FT_Bytes *base, + FT_Bytes *gdef, + FT_Bytes *gpos, + FT_Bytes *gsub, + FT_Bytes *jstf ); + + + FT_DEFINE_SERVICE( OTvalidate ) + { + otv_validate_func validate; + }; + + /* */ + + +FT_END_HEADER + + +#endif /* __SVOTVAL_H__ */ + + +/* END */ diff --git a/reactos/lib/freetype/src/autofit/afangles.h b/reactos/lib/freetype/src/autofit/afangles.h index 59f42d8d85d..f33f9e108e3 100644 --- a/reactos/lib/freetype/src/autofit/afangles.h +++ b/reactos/lib/freetype/src/autofit/afangles.h @@ -1,7 +1,7 @@ -/* - * afangles.h - * - * This is a dummy file, used to please the build system. It is never - * included by the auto-fitter sources. - * - */ +/* + * afangles.h + * + * This is a dummy file, used to please the build system. It is never + * included by the auto-fitter sources. + * + */ diff --git a/reactos/lib/freetype/src/autofit/aferrors.h b/reactos/lib/freetype/src/autofit/aferrors.h index a2e2a00adf9..c2ed5fe2abe 100644 --- a/reactos/lib/freetype/src/autofit/aferrors.h +++ b/reactos/lib/freetype/src/autofit/aferrors.h @@ -1,40 +1,40 @@ -/***************************************************************************/ -/* */ -/* aferrors.h */ -/* */ -/* Autofitter error codes (specification only). */ -/* */ -/* Copyright 2005 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - - /*************************************************************************/ - /* */ - /* This file is used to define the Autofitter error enumeration */ - /* constants. */ - /* */ - /*************************************************************************/ - -#ifndef __AFERRORS_H__ -#define __AFERRORS_H__ - -#include FT_MODULE_ERRORS_H - -#undef __FTERRORS_H__ - -#define FT_ERR_PREFIX AF_Err_ -#define FT_ERR_BASE FT_Mod_Err_Autofit - -#include FT_ERRORS_H - -#endif /* __AFERRORS_H__ */ - -/* END */ +/***************************************************************************/ +/* */ +/* aferrors.h */ +/* */ +/* Autofitter error codes (specification only). */ +/* */ +/* Copyright 2005 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file is used to define the Autofitter error enumeration */ + /* constants. */ + /* */ + /*************************************************************************/ + +#ifndef __AFERRORS_H__ +#define __AFERRORS_H__ + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX AF_Err_ +#define FT_ERR_BASE FT_Mod_Err_Autofit + +#include FT_ERRORS_H + +#endif /* __AFERRORS_H__ */ + +/* END */ diff --git a/reactos/lib/freetype/src/base/ftbitmap.c b/reactos/lib/freetype/src/base/ftbitmap.c index 6de4aac75f6..7c95af7fa9e 100644 --- a/reactos/lib/freetype/src/base/ftbitmap.c +++ b/reactos/lib/freetype/src/base/ftbitmap.c @@ -1,616 +1,616 @@ -/***************************************************************************/ -/* */ -/* ftbitmap.c */ -/* */ -/* FreeType utility functions for converting 1bpp, 2bpp, 4bpp, and 8bpp */ -/* bitmaps into 8bpp format (body). */ -/* */ -/* Copyright 2004, 2005 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - -#include <ft2build.h> -#include FT_BITMAP_H -#include FT_INTERNAL_OBJECTS_H - - - static - const FT_Bitmap null_bitmap = { 0, 0, 0, 0, 0, 0, 0, 0 }; - - - /* documentation is in ftbitmap.h */ - - FT_EXPORT_DEF( void ) - FT_Bitmap_New( FT_Bitmap *abitmap ) - { - *abitmap = null_bitmap; - } - - - /* documentation is in ftbitmap.h */ - - FT_EXPORT_DEF( FT_Error ) - FT_Bitmap_Copy( FT_Library library, - const FT_Bitmap *source, - FT_Bitmap *target) - { - FT_Memory memory = library->memory; - FT_Error error = FT_Err_Ok; - FT_Int pitch = source->pitch; - FT_ULong size; - - - if ( source == target ) - return FT_Err_Ok; - - if ( source->buffer == NULL ) - { - *target = *source; - - return FT_Err_Ok; - } - - if ( pitch < 0 ) - pitch = -pitch; - size = (FT_ULong)( pitch * source->rows ); - - if ( target->buffer ) - { - FT_Int target_pitch = target->pitch; - FT_ULong target_size; - - - if ( target_pitch < 0 ) - target_pitch = -target_pitch; - target_size = (FT_ULong)( target_pitch * target->rows ); - - if ( target_size != size ) - FT_QREALLOC( target->buffer, target_size, size ); - } - else - FT_QALLOC( target->buffer, size ); - - if ( !error ) - { - unsigned char *p; - - - p = target->buffer; - *target = *source; - target->buffer = p; - - FT_MEM_COPY( target->buffer, source->buffer, size ); - } - - return error; - } - - - static FT_Error - ft_bitmap_assure_buffer( FT_Memory memory, - FT_Bitmap* bitmap, - FT_UInt xpixels, - FT_UInt ypixels ) - { - FT_Error error; - int pitch; - int new_pitch; - FT_UInt ppb; - FT_Int i; - unsigned char* buffer; - - - pitch = bitmap->pitch; - if ( pitch < 0 ) - pitch = -pitch; - - switch ( bitmap->pixel_mode ) - { - case FT_PIXEL_MODE_MONO: - ppb = 8; - break; - case FT_PIXEL_MODE_GRAY2: - ppb = 4; - break; - case FT_PIXEL_MODE_GRAY4: - ppb = 2; - break; - case FT_PIXEL_MODE_GRAY: - case FT_PIXEL_MODE_LCD: - case FT_PIXEL_MODE_LCD_V: - ppb = 1; - break; - default: - return FT_Err_Invalid_Glyph_Format; - } - - /* if no need to allocate memory */ - if ( ypixels == 0 && pitch * ppb >= bitmap->width + xpixels ) - { - /* zero the padding */ - for ( i = 0; i < bitmap->rows; i++ ) - { - unsigned char* last_byte; - int bits = xpixels * ( 8 / ppb ); - int mask = 0; - - - last_byte = bitmap->buffer + i * pitch + ( bitmap->width - 1 ) / ppb; - - if ( bits >= 8 ) - { - FT_MEM_ZERO( last_byte + 1, bits / 8 ); - bits %= 8; - } - - if ( bits > 0 ) - { - while ( bits-- > 0 ) - mask |= 1 << bits; - - *last_byte &= ~mask; - } - } - - return FT_Err_Ok; - } - - new_pitch = ( bitmap->width + xpixels + ppb - 1 ) / ppb; - - if ( FT_ALLOC( buffer, new_pitch * ( bitmap->rows + ypixels ) ) ) - return error; - - if ( bitmap->pitch > 0 ) - { - for ( i = 0; i < bitmap->rows; i++ ) - FT_MEM_COPY( buffer + new_pitch * ( ypixels + i ), - bitmap->buffer + pitch * i, pitch ); - } - else - { - for ( i = 0; i < bitmap->rows; i++ ) - FT_MEM_COPY( buffer + new_pitch * i, - bitmap->buffer + pitch * i, pitch ); - } - - FT_FREE( bitmap->buffer ); - bitmap->buffer = buffer; - - if ( bitmap->pitch < 0 ) - new_pitch = -new_pitch; - - /* set pitch only */ - bitmap->pitch = new_pitch; - - return FT_Err_Ok; - } - - - /* documentation is in ftbitmap.h */ - - FT_EXPORT_DEF( FT_Error ) - FT_Bitmap_Embolden( FT_Library library, - FT_Bitmap* bitmap, - FT_Pos xStrength, - FT_Pos yStrength ) - { - FT_Error error; - unsigned char* p; - FT_Int i, x, y, pitch; - FT_Int xstr, ystr; - - - if ( !library ) - return FT_Err_Invalid_Library_Handle; - - if ( !bitmap || !bitmap->buffer ) - return FT_Err_Invalid_Argument; - - xstr = FT_PIX_ROUND( xStrength ) >> 6; - ystr = FT_PIX_ROUND( yStrength ) >> 6; - - if ( xstr == 0 && ystr == 0 ) - return FT_Err_Ok; - else if ( xstr < 0 || ystr < 0 ) - return FT_Err_Invalid_Argument; - - switch ( bitmap->pixel_mode ) - { - case FT_PIXEL_MODE_GRAY2: - case FT_PIXEL_MODE_GRAY4: - { - FT_Bitmap tmp; - FT_Int align; - - - if ( bitmap->pixel_mode == FT_PIXEL_MODE_GRAY2 ) - align = ( bitmap->width + xstr + 3 ) / 4; - else - align = ( bitmap->width + xstr + 1 ) / 2; - - FT_Bitmap_New( &tmp ); - error = FT_Bitmap_Convert( library, bitmap, &tmp, align ); - - if ( error ) - return error; - - FT_Bitmap_Done( library, bitmap ); - *bitmap = tmp; - } - break; - - case FT_PIXEL_MODE_MONO: - if ( xstr > 8 ) - xstr = 8; - break; - - case FT_PIXEL_MODE_LCD: - xstr *= 3; - break; - - case FT_PIXEL_MODE_LCD_V: - ystr *= 3; - break; - } - - error = ft_bitmap_assure_buffer( library->memory, bitmap, xstr, ystr ); - if ( error ) - return error; - - pitch = bitmap->pitch; - if ( pitch > 0 ) - p = bitmap->buffer + pitch * ystr; - else - { - pitch = -pitch; - p = bitmap->buffer + pitch * ( bitmap->rows - 1 ); - } - - /* for each row */ - for ( y = 0; y < bitmap->rows ; y++ ) - { - /* - * Horizontally: - * - * From the last pixel on, make each pixel or'ed with the - * `xstr' pixels before it. - */ - for ( x = pitch - 1; x >= 0; x-- ) - { - unsigned char tmp; - - - tmp = p[x]; - for ( i = 1; i <= xstr; i++ ) - { - if ( bitmap->pixel_mode == FT_PIXEL_MODE_MONO ) - { - p[x] |= tmp >> i; - - /* the maximum value of 8 for `xstr' comes from here */ - if ( x > 0 ) - p[x] |= p[x - 1] << ( 8 - i ); - -#if 0 - if ( p[x] == 0xff ) - break; -#endif - } - else - { - if ( x - i >= 0 ) - { - if ( p[x] + p[x - i] > bitmap->num_grays - 1 ) - { - p[x] = bitmap->num_grays - 1; - break; - } - else - { - p[x] += p[x - i]; - if ( p[x] == bitmap->num_grays - 1 ) - break; - } - } - else - break; - } - } - } - - /* - * Vertically: - * - * Make the above `ystr' rows or'ed with it. - */ - for ( x = 1; x <= ystr; x++ ) - { - unsigned char* q; - - - q = p - bitmap->pitch * x; - for ( i = 0; i < pitch; i++ ) - q[i] |= p[i]; - } - - p += bitmap->pitch; - } - - bitmap->width += xstr; - bitmap->rows += ystr; - - return FT_Err_Ok; - } - - - /* documentation is in ftbitmap.h */ - - FT_EXPORT_DEF( FT_Error ) - FT_Bitmap_Convert( FT_Library library, - const FT_Bitmap *source, - FT_Bitmap *target, - FT_Int alignment ) - { - FT_Error error = FT_Err_Ok; - FT_Memory memory; - - - if ( !library ) - return FT_Err_Invalid_Library_Handle; - - memory = library->memory; - - switch ( source->pixel_mode ) - { - case FT_PIXEL_MODE_MONO: - case FT_PIXEL_MODE_GRAY: - case FT_PIXEL_MODE_GRAY2: - case FT_PIXEL_MODE_GRAY4: - { - FT_Int pad; - FT_Long old_size; - - - old_size = target->rows * target->pitch; - if ( old_size < 0 ) - old_size = -old_size; - - target->pixel_mode = FT_PIXEL_MODE_GRAY; - target->rows = source->rows; - target->width = source->width; - - pad = 0; - if ( alignment > 0 ) - { - pad = source->width % alignment; - if ( pad != 0 ) - pad = alignment - pad; - } - - target->pitch = source->width + pad; - - if ( target->rows * target->pitch > old_size && - FT_QREALLOC( target->buffer, - old_size, target->rows * target->pitch ) ) - return error; - } - break; - - default: - error = FT_Err_Invalid_Argument; - } - - switch ( source->pixel_mode ) - { - case FT_PIXEL_MODE_MONO: - { - FT_Byte* s = source->buffer; - FT_Byte* t = target->buffer; - FT_Int i; - - - target->num_grays = 2; - - for ( i = source->rows; i > 0; i-- ) - { - FT_Byte* ss = s; - FT_Byte* tt = t; - FT_Int j; - - - /* get the full bytes */ - for ( j = source->width >> 3; j > 0; j-- ) - { - FT_Int val = ss[0]; /* avoid a byte->int cast on each line */ - - - tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7 ); - tt[1] = (FT_Byte)( ( val & 0x40 ) >> 6 ); - tt[2] = (FT_Byte)( ( val & 0x20 ) >> 5 ); - tt[3] = (FT_Byte)( ( val & 0x10 ) >> 4 ); - tt[4] = (FT_Byte)( ( val & 0x08 ) >> 3 ); - tt[5] = (FT_Byte)( ( val & 0x04 ) >> 2 ); - tt[6] = (FT_Byte)( ( val & 0x02 ) >> 1 ); - tt[7] = (FT_Byte)( val & 0x01 ); - - tt += 8; - ss += 1; - } - - /* get remaining pixels (if any) */ - j = source->width & 7; - if ( j > 0 ) - { - FT_Int val = *ss; - - - for ( ; j > 0; j-- ) - { - tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7); - val <<= 1; - tt += 1; - } - } - - s += source->pitch; - t += target->pitch; - } - } - break; - - - case FT_PIXEL_MODE_GRAY: - { - FT_Int width = source->width; - FT_Byte* s = source->buffer; - FT_Byte* t = target->buffer; - FT_Int s_pitch = source->pitch; - FT_Int t_pitch = target->pitch; - FT_Int i; - - - target->num_grays = 256; - - for ( i = source->rows; i > 0; i-- ) - { - FT_ARRAY_COPY( t, s, width ); - - s += s_pitch; - t += t_pitch; - } - } - break; - - - case FT_PIXEL_MODE_GRAY2: - { - FT_Byte* s = source->buffer; - FT_Byte* t = target->buffer; - FT_Int i; - - - target->num_grays = 4; - - for ( i = source->rows; i > 0; i-- ) - { - FT_Byte* ss = s; - FT_Byte* tt = t; - FT_Int j; - - - /* get the full bytes */ - for ( j = source->width >> 2; j > 0; j-- ) - { - FT_Int val = ss[0]; - - - tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 ); - tt[1] = (FT_Byte)( ( val & 0x30 ) >> 4 ); - tt[2] = (FT_Byte)( ( val & 0x0C ) >> 2 ); - tt[3] = (FT_Byte)( ( val & 0x03 ) ); - - ss += 1; - tt += 4; - } - - j = source->width & 3; - if ( j > 0 ) - { - FT_Int val = ss[0]; - - - for ( ; j > 0; j-- ) - { - tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 ); - val <<= 2; - tt += 1; - } - } - - s += source->pitch; - t += target->pitch; - } - } - break; - - - case FT_PIXEL_MODE_GRAY4: - { - FT_Byte* s = source->buffer; - FT_Byte* t = target->buffer; - FT_Int i; - - - target->num_grays = 16; - - for ( i = source->rows; i > 0; i-- ) - { - FT_Byte* ss = s; - FT_Byte* tt = t; - FT_Int j; - - - /* get the full bytes */ - for ( j = source->width >> 1; j > 0; j-- ) - { - FT_Int val = ss[0]; - - - tt[0] = (FT_Byte)( ( val & 0xF0 ) >> 4 ); - tt[1] = (FT_Byte)( ( val & 0x0F ) ); - - ss += 1; - tt += 2; - } - - if ( source->width & 1 ) - tt[0] = (FT_Byte)( ( ss[0] & 0xF0 ) >> 4 ); - - s += source->pitch; - t += target->pitch; - } - } - break; - - - default: - ; - } - - return error; - } - - - /* documentation is in ftbitmap.h */ - - FT_EXPORT_DEF( FT_Error ) - FT_Bitmap_Done( FT_Library library, - FT_Bitmap *bitmap ) - { - FT_Memory memory; - - - if ( !library ) - return FT_Err_Invalid_Library_Handle; - - if ( !bitmap ) - return FT_Err_Invalid_Argument; - - memory = library->memory; - - FT_FREE( bitmap->buffer ); - *bitmap = null_bitmap; - - return FT_Err_Ok; - } - - -/* END */ +/***************************************************************************/ +/* */ +/* ftbitmap.c */ +/* */ +/* FreeType utility functions for converting 1bpp, 2bpp, 4bpp, and 8bpp */ +/* bitmaps into 8bpp format (body). */ +/* */ +/* Copyright 2004, 2005 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_BITMAP_H +#include FT_INTERNAL_OBJECTS_H + + + static + const FT_Bitmap null_bitmap = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + + /* documentation is in ftbitmap.h */ + + FT_EXPORT_DEF( void ) + FT_Bitmap_New( FT_Bitmap *abitmap ) + { + *abitmap = null_bitmap; + } + + + /* documentation is in ftbitmap.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Bitmap_Copy( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target) + { + FT_Memory memory = library->memory; + FT_Error error = FT_Err_Ok; + FT_Int pitch = source->pitch; + FT_ULong size; + + + if ( source == target ) + return FT_Err_Ok; + + if ( source->buffer == NULL ) + { + *target = *source; + + return FT_Err_Ok; + } + + if ( pitch < 0 ) + pitch = -pitch; + size = (FT_ULong)( pitch * source->rows ); + + if ( target->buffer ) + { + FT_Int target_pitch = target->pitch; + FT_ULong target_size; + + + if ( target_pitch < 0 ) + target_pitch = -target_pitch; + target_size = (FT_ULong)( target_pitch * target->rows ); + + if ( target_size != size ) + FT_QREALLOC( target->buffer, target_size, size ); + } + else + FT_QALLOC( target->buffer, size ); + + if ( !error ) + { + unsigned char *p; + + + p = target->buffer; + *target = *source; + target->buffer = p; + + FT_MEM_COPY( target->buffer, source->buffer, size ); + } + + return error; + } + + + static FT_Error + ft_bitmap_assure_buffer( FT_Memory memory, + FT_Bitmap* bitmap, + FT_UInt xpixels, + FT_UInt ypixels ) + { + FT_Error error; + int pitch; + int new_pitch; + FT_UInt ppb; + FT_Int i; + unsigned char* buffer; + + + pitch = bitmap->pitch; + if ( pitch < 0 ) + pitch = -pitch; + + switch ( bitmap->pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + ppb = 8; + break; + case FT_PIXEL_MODE_GRAY2: + ppb = 4; + break; + case FT_PIXEL_MODE_GRAY4: + ppb = 2; + break; + case FT_PIXEL_MODE_GRAY: + case FT_PIXEL_MODE_LCD: + case FT_PIXEL_MODE_LCD_V: + ppb = 1; + break; + default: + return FT_Err_Invalid_Glyph_Format; + } + + /* if no need to allocate memory */ + if ( ypixels == 0 && pitch * ppb >= bitmap->width + xpixels ) + { + /* zero the padding */ + for ( i = 0; i < bitmap->rows; i++ ) + { + unsigned char* last_byte; + int bits = xpixels * ( 8 / ppb ); + int mask = 0; + + + last_byte = bitmap->buffer + i * pitch + ( bitmap->width - 1 ) / ppb; + + if ( bits >= 8 ) + { + FT_MEM_ZERO( last_byte + 1, bits / 8 ); + bits %= 8; + } + + if ( bits > 0 ) + { + while ( bits-- > 0 ) + mask |= 1 << bits; + + *last_byte &= ~mask; + } + } + + return FT_Err_Ok; + } + + new_pitch = ( bitmap->width + xpixels + ppb - 1 ) / ppb; + + if ( FT_ALLOC( buffer, new_pitch * ( bitmap->rows + ypixels ) ) ) + return error; + + if ( bitmap->pitch > 0 ) + { + for ( i = 0; i < bitmap->rows; i++ ) + FT_MEM_COPY( buffer + new_pitch * ( ypixels + i ), + bitmap->buffer + pitch * i, pitch ); + } + else + { + for ( i = 0; i < bitmap->rows; i++ ) + FT_MEM_COPY( buffer + new_pitch * i, + bitmap->buffer + pitch * i, pitch ); + } + + FT_FREE( bitmap->buffer ); + bitmap->buffer = buffer; + + if ( bitmap->pitch < 0 ) + new_pitch = -new_pitch; + + /* set pitch only */ + bitmap->pitch = new_pitch; + + return FT_Err_Ok; + } + + + /* documentation is in ftbitmap.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Bitmap_Embolden( FT_Library library, + FT_Bitmap* bitmap, + FT_Pos xStrength, + FT_Pos yStrength ) + { + FT_Error error; + unsigned char* p; + FT_Int i, x, y, pitch; + FT_Int xstr, ystr; + + + if ( !library ) + return FT_Err_Invalid_Library_Handle; + + if ( !bitmap || !bitmap->buffer ) + return FT_Err_Invalid_Argument; + + xstr = FT_PIX_ROUND( xStrength ) >> 6; + ystr = FT_PIX_ROUND( yStrength ) >> 6; + + if ( xstr == 0 && ystr == 0 ) + return FT_Err_Ok; + else if ( xstr < 0 || ystr < 0 ) + return FT_Err_Invalid_Argument; + + switch ( bitmap->pixel_mode ) + { + case FT_PIXEL_MODE_GRAY2: + case FT_PIXEL_MODE_GRAY4: + { + FT_Bitmap tmp; + FT_Int align; + + + if ( bitmap->pixel_mode == FT_PIXEL_MODE_GRAY2 ) + align = ( bitmap->width + xstr + 3 ) / 4; + else + align = ( bitmap->width + xstr + 1 ) / 2; + + FT_Bitmap_New( &tmp ); + error = FT_Bitmap_Convert( library, bitmap, &tmp, align ); + + if ( error ) + return error; + + FT_Bitmap_Done( library, bitmap ); + *bitmap = tmp; + } + break; + + case FT_PIXEL_MODE_MONO: + if ( xstr > 8 ) + xstr = 8; + break; + + case FT_PIXEL_MODE_LCD: + xstr *= 3; + break; + + case FT_PIXEL_MODE_LCD_V: + ystr *= 3; + break; + } + + error = ft_bitmap_assure_buffer( library->memory, bitmap, xstr, ystr ); + if ( error ) + return error; + + pitch = bitmap->pitch; + if ( pitch > 0 ) + p = bitmap->buffer + pitch * ystr; + else + { + pitch = -pitch; + p = bitmap->buffer + pitch * ( bitmap->rows - 1 ); + } + + /* for each row */ + for ( y = 0; y < bitmap->rows ; y++ ) + { + /* + * Horizontally: + * + * From the last pixel on, make each pixel or'ed with the + * `xstr' pixels before it. + */ + for ( x = pitch - 1; x >= 0; x-- ) + { + unsigned char tmp; + + + tmp = p[x]; + for ( i = 1; i <= xstr; i++ ) + { + if ( bitmap->pixel_mode == FT_PIXEL_MODE_MONO ) + { + p[x] |= tmp >> i; + + /* the maximum value of 8 for `xstr' comes from here */ + if ( x > 0 ) + p[x] |= p[x - 1] << ( 8 - i ); + +#if 0 + if ( p[x] == 0xff ) + break; +#endif + } + else + { + if ( x - i >= 0 ) + { + if ( p[x] + p[x - i] > bitmap->num_grays - 1 ) + { + p[x] = bitmap->num_grays - 1; + break; + } + else + { + p[x] += p[x - i]; + if ( p[x] == bitmap->num_grays - 1 ) + break; + } + } + else + break; + } + } + } + + /* + * Vertically: + * + * Make the above `ystr' rows or'ed with it. + */ + for ( x = 1; x <= ystr; x++ ) + { + unsigned char* q; + + + q = p - bitmap->pitch * x; + for ( i = 0; i < pitch; i++ ) + q[i] |= p[i]; + } + + p += bitmap->pitch; + } + + bitmap->width += xstr; + bitmap->rows += ystr; + + return FT_Err_Ok; + } + + + /* documentation is in ftbitmap.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Bitmap_Convert( FT_Library library, + const FT_Bitmap *source, + FT_Bitmap *target, + FT_Int alignment ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory; + + + if ( !library ) + return FT_Err_Invalid_Library_Handle; + + memory = library->memory; + + switch ( source->pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + case FT_PIXEL_MODE_GRAY: + case FT_PIXEL_MODE_GRAY2: + case FT_PIXEL_MODE_GRAY4: + { + FT_Int pad; + FT_Long old_size; + + + old_size = target->rows * target->pitch; + if ( old_size < 0 ) + old_size = -old_size; + + target->pixel_mode = FT_PIXEL_MODE_GRAY; + target->rows = source->rows; + target->width = source->width; + + pad = 0; + if ( alignment > 0 ) + { + pad = source->width % alignment; + if ( pad != 0 ) + pad = alignment - pad; + } + + target->pitch = source->width + pad; + + if ( target->rows * target->pitch > old_size && + FT_QREALLOC( target->buffer, + old_size, target->rows * target->pitch ) ) + return error; + } + break; + + default: + error = FT_Err_Invalid_Argument; + } + + switch ( source->pixel_mode ) + { + case FT_PIXEL_MODE_MONO: + { + FT_Byte* s = source->buffer; + FT_Byte* t = target->buffer; + FT_Int i; + + + target->num_grays = 2; + + for ( i = source->rows; i > 0; i-- ) + { + FT_Byte* ss = s; + FT_Byte* tt = t; + FT_Int j; + + + /* get the full bytes */ + for ( j = source->width >> 3; j > 0; j-- ) + { + FT_Int val = ss[0]; /* avoid a byte->int cast on each line */ + + + tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7 ); + tt[1] = (FT_Byte)( ( val & 0x40 ) >> 6 ); + tt[2] = (FT_Byte)( ( val & 0x20 ) >> 5 ); + tt[3] = (FT_Byte)( ( val & 0x10 ) >> 4 ); + tt[4] = (FT_Byte)( ( val & 0x08 ) >> 3 ); + tt[5] = (FT_Byte)( ( val & 0x04 ) >> 2 ); + tt[6] = (FT_Byte)( ( val & 0x02 ) >> 1 ); + tt[7] = (FT_Byte)( val & 0x01 ); + + tt += 8; + ss += 1; + } + + /* get remaining pixels (if any) */ + j = source->width & 7; + if ( j > 0 ) + { + FT_Int val = *ss; + + + for ( ; j > 0; j-- ) + { + tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7); + val <<= 1; + tt += 1; + } + } + + s += source->pitch; + t += target->pitch; + } + } + break; + + + case FT_PIXEL_MODE_GRAY: + { + FT_Int width = source->width; + FT_Byte* s = source->buffer; + FT_Byte* t = target->buffer; + FT_Int s_pitch = source->pitch; + FT_Int t_pitch = target->pitch; + FT_Int i; + + + target->num_grays = 256; + + for ( i = source->rows; i > 0; i-- ) + { + FT_ARRAY_COPY( t, s, width ); + + s += s_pitch; + t += t_pitch; + } + } + break; + + + case FT_PIXEL_MODE_GRAY2: + { + FT_Byte* s = source->buffer; + FT_Byte* t = target->buffer; + FT_Int i; + + + target->num_grays = 4; + + for ( i = source->rows; i > 0; i-- ) + { + FT_Byte* ss = s; + FT_Byte* tt = t; + FT_Int j; + + + /* get the full bytes */ + for ( j = source->width >> 2; j > 0; j-- ) + { + FT_Int val = ss[0]; + + + tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 ); + tt[1] = (FT_Byte)( ( val & 0x30 ) >> 4 ); + tt[2] = (FT_Byte)( ( val & 0x0C ) >> 2 ); + tt[3] = (FT_Byte)( ( val & 0x03 ) ); + + ss += 1; + tt += 4; + } + + j = source->width & 3; + if ( j > 0 ) + { + FT_Int val = ss[0]; + + + for ( ; j > 0; j-- ) + { + tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 ); + val <<= 2; + tt += 1; + } + } + + s += source->pitch; + t += target->pitch; + } + } + break; + + + case FT_PIXEL_MODE_GRAY4: + { + FT_Byte* s = source->buffer; + FT_Byte* t = target->buffer; + FT_Int i; + + + target->num_grays = 16; + + for ( i = source->rows; i > 0; i-- ) + { + FT_Byte* ss = s; + FT_Byte* tt = t; + FT_Int j; + + + /* get the full bytes */ + for ( j = source->width >> 1; j > 0; j-- ) + { + FT_Int val = ss[0]; + + + tt[0] = (FT_Byte)( ( val & 0xF0 ) >> 4 ); + tt[1] = (FT_Byte)( ( val & 0x0F ) ); + + ss += 1; + tt += 2; + } + + if ( source->width & 1 ) + tt[0] = (FT_Byte)( ( ss[0] & 0xF0 ) >> 4 ); + + s += source->pitch; + t += target->pitch; + } + } + break; + + + default: + ; + } + + return error; + } + + + /* documentation is in ftbitmap.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_Bitmap_Done( FT_Library library, + FT_Bitmap *bitmap ) + { + FT_Memory memory; + + + if ( !library ) + return FT_Err_Invalid_Library_Handle; + + if ( !bitmap ) + return FT_Err_Invalid_Argument; + + memory = library->memory; + + FT_FREE( bitmap->buffer ); + *bitmap = null_bitmap; + + return FT_Err_Ok; + } + + +/* END */ diff --git a/reactos/lib/freetype/src/base/ftotval.c b/reactos/lib/freetype/src/base/ftotval.c index eb6be68d2f3..1364d754ec2 100644 --- a/reactos/lib/freetype/src/base/ftotval.c +++ b/reactos/lib/freetype/src/base/ftotval.c @@ -1,72 +1,72 @@ -/***************************************************************************/ -/* */ -/* ftotval.c */ -/* */ -/* FreeType API for validating OpenType tables (body). */ -/* */ -/* Copyright 2004 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - -#include <ft2build.h> -#include FT_INTERNAL_OBJECTS_H -#include FT_SERVICE_OPENTYPE_VALIDATE_H - - - /* documentation is in ftotval.h */ - - FT_EXPORT_DEF( FT_Error ) - FT_OpenType_Validate( FT_Face face, - FT_UInt validation_flags, - FT_Bytes *BASE_table, - FT_Bytes *GDEF_table, - FT_Bytes *GPOS_table, - FT_Bytes *GSUB_table, - FT_Bytes *JSTF_table ) - { - FT_Service_OTvalidate service; - FT_Error error; - - - if ( !face ) - { - error = FT_Err_Invalid_Face_Handle; - goto Exit; - } - - if ( !( BASE_table && - GDEF_table && - GPOS_table && - GSUB_table && - JSTF_table ) ) - { - error = FT_Err_Invalid_Argument; - goto Exit; - } - - FT_FACE_FIND_GLOBAL_SERVICE( face, service, OPENTYPE_VALIDATE ); - - if ( service ) - error = service->validate( face, - validation_flags, - BASE_table, - GDEF_table, - GPOS_table, - GSUB_table, - JSTF_table ); - else - error = FT_Err_Invalid_Argument; - - Exit: - return error; - } - - -/* END */ +/***************************************************************************/ +/* */ +/* ftotval.c */ +/* */ +/* FreeType API for validating OpenType tables (body). */ +/* */ +/* Copyright 2004 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +#include <ft2build.h> +#include FT_INTERNAL_OBJECTS_H +#include FT_SERVICE_OPENTYPE_VALIDATE_H + + + /* documentation is in ftotval.h */ + + FT_EXPORT_DEF( FT_Error ) + FT_OpenType_Validate( FT_Face face, + FT_UInt validation_flags, + FT_Bytes *BASE_table, + FT_Bytes *GDEF_table, + FT_Bytes *GPOS_table, + FT_Bytes *GSUB_table, + FT_Bytes *JSTF_table ) + { + FT_Service_OTvalidate service; + FT_Error error; + + + if ( !face ) + { + error = FT_Err_Invalid_Face_Handle; + goto Exit; + } + + if ( !( BASE_table && + GDEF_table && + GPOS_table && + GSUB_table && + JSTF_table ) ) + { + error = FT_Err_Invalid_Argument; + goto Exit; + } + + FT_FACE_FIND_GLOBAL_SERVICE( face, service, OPENTYPE_VALIDATE ); + + if ( service ) + error = service->validate( face, + validation_flags, + BASE_table, + GDEF_table, + GPOS_table, + GSUB_table, + JSTF_table ); + else + error = FT_Err_Invalid_Argument; + + Exit: + return error; + } + + +/* END */ diff --git a/reactos/lib/freetype/src/otvalid/otvalid.c b/reactos/lib/freetype/src/otvalid/otvalid.c index 121142eebe1..2f85f601b66 100644 --- a/reactos/lib/freetype/src/otvalid/otvalid.c +++ b/reactos/lib/freetype/src/otvalid/otvalid.c @@ -1,30 +1,30 @@ -/***************************************************************************/ -/* */ -/* otvalid.c */ -/* */ -/* FreeType validator for OpenType tables (body only). */ -/* */ -/* Copyright 2004 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - -#define FT_MAKE_OPTION_SINGLE_OBJECT - -#include <ft2build.h> - -#include "otvbase.c" -#include "otvcommn.c" -#include "otvgdef.c" -#include "otvgpos.c" -#include "otvgsub.c" -#include "otvjstf.c" -#include "otvmod.c" - -/* END */ +/***************************************************************************/ +/* */ +/* otvalid.c */ +/* */ +/* FreeType validator for OpenType tables (body only). */ +/* */ +/* Copyright 2004 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + +#define FT_MAKE_OPTION_SINGLE_OBJECT + +#include <ft2build.h> + +#include "otvbase.c" +#include "otvcommn.c" +#include "otvgdef.c" +#include "otvgpos.c" +#include "otvgsub.c" +#include "otvjstf.c" +#include "otvmod.c" + +/* END */ diff --git a/reactos/lib/freetype/src/otvalid/otvalid.h b/reactos/lib/freetype/src/otvalid/otvalid.h index 826ea098d11..38f030f3935 100644 --- a/reactos/lib/freetype/src/otvalid/otvalid.h +++ b/reactos/lib/freetype/src/otvalid/otvalid.h @@ -1,72 +1,72 @@ -/***************************************************************************/ -/* */ -/* otvalid.h */ -/* */ -/* OpenType table validation (specification only). */ -/* */ -/* Copyright 2004 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - -#ifndef __OTVALID_H__ -#define __OTVALID_H__ - - -#include <ft2build.h> -#include FT_FREETYPE_H - -#include "otverror.h" /* must come before FT_INTERNAL_VALIDATE_H */ - -#include FT_INTERNAL_VALIDATE_H -#include FT_INTERNAL_STREAM_H - - -FT_BEGIN_HEADER - - - FT_LOCAL( void ) - otv_BASE_validate( FT_Bytes table, - FT_Validator valid ); - - /* GSUB and GPOS tables should already be validated; */ - /* if missing, set corresponding argument to 0 */ - FT_LOCAL( void ) - otv_GDEF_validate( FT_Bytes table, - FT_Bytes gsub, - FT_Bytes gpos, - FT_Validator valid ); - - FT_LOCAL( void ) - otv_GPOS_validate( FT_Bytes table, - FT_UInt glyph_count, - FT_Validator valid ); - - FT_LOCAL( void ) - otv_GSUB_validate( FT_Bytes table, - FT_UInt glyph_count, - FT_Validator valid ); - - /* GSUB and GPOS tables should already be validated; */ - /* if missing, set corresponding argument to 0 */ - FT_LOCAL( void ) - otv_JSTF_validate( FT_Bytes table, - FT_Bytes gsub, - FT_Bytes gpos, - FT_UInt glyph_count, - FT_Validator valid ); - - -FT_END_HEADER - -#endif /* __OTVALID_H__ */ - - -/* END */ +/***************************************************************************/ +/* */ +/* otvalid.h */ +/* */ +/* OpenType table validation (specification only). */ +/* */ +/* Copyright 2004 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __OTVALID_H__ +#define __OTVALID_H__ + + +#include <ft2build.h> +#include FT_FREETYPE_H + +#include "otverror.h" /* must come before FT_INTERNAL_VALIDATE_H */ + +#include FT_INTERNAL_VALIDATE_H +#include FT_INTERNAL_STREAM_H + + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + otv_BASE_validate( FT_Bytes table, + FT_Validator valid ); + + /* GSUB and GPOS tables should already be validated; */ + /* if missing, set corresponding argument to 0 */ + FT_LOCAL( void ) + otv_GDEF_validate( FT_Bytes table, + FT_Bytes gsub, + FT_Bytes gpos, + FT_Validator valid ); + + FT_LOCAL( void ) + otv_GPOS_validate( FT_Bytes table, + FT_UInt glyph_count, + FT_Validator valid ); + + FT_LOCAL( void ) + otv_GSUB_validate( FT_Bytes table, + FT_UInt glyph_count, + FT_Validator valid ); + + /* GSUB and GPOS tables should already be validated; */ + /* if missing, set corresponding argument to 0 */ + FT_LOCAL( void ) + otv_JSTF_validate( FT_Bytes table, + FT_Bytes gsub, + FT_Bytes gpos, + FT_UInt glyph_count, + FT_Validator valid ); + + +FT_END_HEADER + +#endif /* __OTVALID_H__ */ + + +/* END */ diff --git a/reactos/lib/freetype/src/otvalid/otvbase.c b/reactos/lib/freetype/src/otvalid/otvbase.c index 4f04b518ed8..8ad2238d6d6 100644 --- a/reactos/lib/freetype/src/otvalid/otvbase.c +++ b/reactos/lib/freetype/src/otvalid/otvbase.c @@ -1,318 +1,318 @@ -/***************************************************************************/ -/* */ -/* otvbase.c */ -/* */ -/* OpenType BASE table validation (body). */ -/* */ -/* Copyright 2004 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - -#include "otvalid.h" -#include "otvcommn.h" - - - /*************************************************************************/ - /* */ - /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ - /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ - /* messages during execution. */ - /* */ -#undef FT_COMPONENT -#define FT_COMPONENT trace_otvbase - - - static void - otv_BaseCoord_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt BaseCoordFormat; - - - OTV_NAME_ENTER( "BaseCoord" ); - - OTV_LIMIT_CHECK( 4 ); - BaseCoordFormat = FT_NEXT_USHORT( p ); - p += 2; /* skip Coordinate */ - - OTV_TRACE(( " (format %d)\n", BaseCoordFormat )); - - switch ( BaseCoordFormat ) - { - case 1: /* BaseCoordFormat1 */ - break; - - case 2: /* BaseCoordFormat2 */ - OTV_LIMIT_CHECK( 4 ); /* ReferenceGlyph, BaseCoordPoint */ - break; - - case 3: /* BaseCoordFormat3 */ - OTV_LIMIT_CHECK( 2 ); - /* DeviceTable */ - otv_Device_validate( table + FT_NEXT_USHORT( p ), valid ); - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - static void - otv_BaseTagList_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt BaseTagCount; - - - OTV_NAME_ENTER( "BaseTagList" ); - - OTV_LIMIT_CHECK( 2 ); - - BaseTagCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (BaseTagCount = %d)\n", BaseTagCount )); - - OTV_LIMIT_CHECK( BaseTagCount * 4 ); /* BaselineTag */ - - OTV_EXIT; - } - - - static void - otv_BaseValues_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt BaseCoordCount; - - - OTV_NAME_ENTER( "BaseValues" ); - - OTV_LIMIT_CHECK( 4 ); - - p += 2; /* skip DefaultIndex */ - BaseCoordCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (BaseCoordCount = %d)\n", BaseCoordCount )); - - OTV_LIMIT_CHECK( BaseCoordCount * 2 ); - - /* BaseCoord */ - for ( ; BaseCoordCount > 0; BaseCoordCount-- ) - otv_BaseCoord_validate( table + FT_NEXT_USHORT( p ), valid ); - - OTV_EXIT; - } - - - static void - otv_MinMax_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt table_size; - FT_UInt FeatMinMaxCount; - - OTV_OPTIONAL_TABLE( MinCoord ); - OTV_OPTIONAL_TABLE( MaxCoord ); - - - OTV_NAME_ENTER( "MinMax" ); - - OTV_LIMIT_CHECK( 6 ); - - OTV_OPTIONAL_OFFSET( MinCoord ); - OTV_OPTIONAL_OFFSET( MaxCoord ); - FeatMinMaxCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (FeatMinMaxCount = %d)\n", FeatMinMaxCount )); - - table_size = FeatMinMaxCount * 8 + 6; - - OTV_SIZE_CHECK( MinCoord ); - if ( MinCoord ) - otv_BaseCoord_validate( table + MinCoord, valid ); - - OTV_SIZE_CHECK( MaxCoord ); - if ( MaxCoord ) - otv_BaseCoord_validate( table + MaxCoord, valid ); - - OTV_LIMIT_CHECK( FeatMinMaxCount * 8 ); - - /* FeatMinMaxRecord */ - for ( ; FeatMinMaxCount > 0; FeatMinMaxCount-- ) - { - p += 4; /* skip FeatureTableTag */ - - OTV_OPTIONAL_OFFSET( MinCoord ); - OTV_OPTIONAL_OFFSET( MaxCoord ); - - OTV_SIZE_CHECK( MinCoord ); - if ( MinCoord ) - otv_BaseCoord_validate( table + MinCoord, valid ); - - OTV_SIZE_CHECK( MaxCoord ); - if ( MaxCoord ) - otv_BaseCoord_validate( table + MaxCoord, valid ); - } - - OTV_EXIT; - } - - - static void - otv_BaseScript_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt table_size; - FT_UInt BaseLangSysCount; - - OTV_OPTIONAL_TABLE( BaseValues ); - OTV_OPTIONAL_TABLE( DefaultMinMax ); - - - OTV_NAME_ENTER( "BaseScript" ); - - OTV_LIMIT_CHECK( 6 ); - OTV_OPTIONAL_OFFSET( BaseValues ); - OTV_OPTIONAL_OFFSET( DefaultMinMax ); - BaseLangSysCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (BaseLangSysCount = %d)\n", BaseLangSysCount )); - - table_size = BaseLangSysCount * 6 + 6; - - OTV_SIZE_CHECK( BaseValues ); - if ( BaseValues ) - otv_BaseValues_validate( table + BaseValues, valid ); - - OTV_SIZE_CHECK( DefaultMinMax ); - if ( DefaultMinMax ) - otv_MinMax_validate( table + DefaultMinMax, valid ); - - OTV_LIMIT_CHECK( BaseLangSysCount * 6 ); - - /* BaseLangSysRecord */ - for ( ; BaseLangSysCount > 0; BaseLangSysCount-- ) - { - p += 4; /* skip BaseLangSysTag */ - - otv_MinMax_validate( table + FT_NEXT_USHORT( p ), valid ); - } - - OTV_EXIT; - } - - - static void - otv_BaseScriptList_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt BaseScriptCount; - - - OTV_NAME_ENTER( "BaseScriptList" ); - - OTV_LIMIT_CHECK( 2 ); - BaseScriptCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (BaseScriptCount = %d)\n", BaseScriptCount )); - - OTV_LIMIT_CHECK( BaseScriptCount * 6 ); - - /* BaseScriptRecord */ - for ( ; BaseScriptCount > 0; BaseScriptCount-- ) - { - p += 4; /* skip BaseScriptTag */ - - /* BaseScript */ - otv_BaseScript_validate( table + FT_NEXT_USHORT( p ), valid ); - } - - OTV_EXIT; - } - - - static void - otv_Axis_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt table_size; - - OTV_OPTIONAL_TABLE( BaseTagList ); - - - OTV_NAME_ENTER( "Axis" ); - - OTV_LIMIT_CHECK( 4 ); - OTV_OPTIONAL_OFFSET( BaseTagList ); - - table_size = 4; - - OTV_SIZE_CHECK( BaseTagList ); - if ( BaseTagList ) - otv_BaseTagList_validate( table + BaseTagList, valid ); - - /* BaseScriptList */ - otv_BaseScriptList_validate( table + FT_NEXT_USHORT( p ), valid ); - - OTV_EXIT; - } - - - FT_LOCAL_DEF( void ) - otv_BASE_validate( FT_Bytes table, - FT_Validator ftvalid ) - { - OTV_ValidatorRec validrec; - OTV_Validator valid = &validrec; - FT_Bytes p = table; - FT_UInt table_size; - - OTV_OPTIONAL_TABLE( HorizAxis ); - OTV_OPTIONAL_TABLE( VertAxis ); - - - valid->root = ftvalid; - - FT_TRACE3(( "validating BASE table\n" )); - OTV_INIT; - - OTV_LIMIT_CHECK( 6 ); - - if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ - FT_INVALID_DATA; - - table_size = 6; - - OTV_OPTIONAL_OFFSET( HorizAxis ); - OTV_SIZE_CHECK( HorizAxis ); - if ( HorizAxis ) - otv_Axis_validate( table + HorizAxis, valid ); - - OTV_OPTIONAL_OFFSET( VertAxis ); - OTV_SIZE_CHECK( VertAxis ); - if ( VertAxis ) - otv_Axis_validate( table + VertAxis, valid ); - - FT_TRACE4(( "\n" )); - } - - -/* END */ +/***************************************************************************/ +/* */ +/* otvbase.c */ +/* */ +/* OpenType BASE table validation (body). */ +/* */ +/* Copyright 2004 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include "otvalid.h" +#include "otvcommn.h" + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_otvbase + + + static void + otv_BaseCoord_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt BaseCoordFormat; + + + OTV_NAME_ENTER( "BaseCoord" ); + + OTV_LIMIT_CHECK( 4 ); + BaseCoordFormat = FT_NEXT_USHORT( p ); + p += 2; /* skip Coordinate */ + + OTV_TRACE(( " (format %d)\n", BaseCoordFormat )); + + switch ( BaseCoordFormat ) + { + case 1: /* BaseCoordFormat1 */ + break; + + case 2: /* BaseCoordFormat2 */ + OTV_LIMIT_CHECK( 4 ); /* ReferenceGlyph, BaseCoordPoint */ + break; + + case 3: /* BaseCoordFormat3 */ + OTV_LIMIT_CHECK( 2 ); + /* DeviceTable */ + otv_Device_validate( table + FT_NEXT_USHORT( p ), valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + static void + otv_BaseTagList_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt BaseTagCount; + + + OTV_NAME_ENTER( "BaseTagList" ); + + OTV_LIMIT_CHECK( 2 ); + + BaseTagCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BaseTagCount = %d)\n", BaseTagCount )); + + OTV_LIMIT_CHECK( BaseTagCount * 4 ); /* BaselineTag */ + + OTV_EXIT; + } + + + static void + otv_BaseValues_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt BaseCoordCount; + + + OTV_NAME_ENTER( "BaseValues" ); + + OTV_LIMIT_CHECK( 4 ); + + p += 2; /* skip DefaultIndex */ + BaseCoordCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BaseCoordCount = %d)\n", BaseCoordCount )); + + OTV_LIMIT_CHECK( BaseCoordCount * 2 ); + + /* BaseCoord */ + for ( ; BaseCoordCount > 0; BaseCoordCount-- ) + otv_BaseCoord_validate( table + FT_NEXT_USHORT( p ), valid ); + + OTV_EXIT; + } + + + static void + otv_MinMax_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt table_size; + FT_UInt FeatMinMaxCount; + + OTV_OPTIONAL_TABLE( MinCoord ); + OTV_OPTIONAL_TABLE( MaxCoord ); + + + OTV_NAME_ENTER( "MinMax" ); + + OTV_LIMIT_CHECK( 6 ); + + OTV_OPTIONAL_OFFSET( MinCoord ); + OTV_OPTIONAL_OFFSET( MaxCoord ); + FeatMinMaxCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (FeatMinMaxCount = %d)\n", FeatMinMaxCount )); + + table_size = FeatMinMaxCount * 8 + 6; + + OTV_SIZE_CHECK( MinCoord ); + if ( MinCoord ) + otv_BaseCoord_validate( table + MinCoord, valid ); + + OTV_SIZE_CHECK( MaxCoord ); + if ( MaxCoord ) + otv_BaseCoord_validate( table + MaxCoord, valid ); + + OTV_LIMIT_CHECK( FeatMinMaxCount * 8 ); + + /* FeatMinMaxRecord */ + for ( ; FeatMinMaxCount > 0; FeatMinMaxCount-- ) + { + p += 4; /* skip FeatureTableTag */ + + OTV_OPTIONAL_OFFSET( MinCoord ); + OTV_OPTIONAL_OFFSET( MaxCoord ); + + OTV_SIZE_CHECK( MinCoord ); + if ( MinCoord ) + otv_BaseCoord_validate( table + MinCoord, valid ); + + OTV_SIZE_CHECK( MaxCoord ); + if ( MaxCoord ) + otv_BaseCoord_validate( table + MaxCoord, valid ); + } + + OTV_EXIT; + } + + + static void + otv_BaseScript_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt table_size; + FT_UInt BaseLangSysCount; + + OTV_OPTIONAL_TABLE( BaseValues ); + OTV_OPTIONAL_TABLE( DefaultMinMax ); + + + OTV_NAME_ENTER( "BaseScript" ); + + OTV_LIMIT_CHECK( 6 ); + OTV_OPTIONAL_OFFSET( BaseValues ); + OTV_OPTIONAL_OFFSET( DefaultMinMax ); + BaseLangSysCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BaseLangSysCount = %d)\n", BaseLangSysCount )); + + table_size = BaseLangSysCount * 6 + 6; + + OTV_SIZE_CHECK( BaseValues ); + if ( BaseValues ) + otv_BaseValues_validate( table + BaseValues, valid ); + + OTV_SIZE_CHECK( DefaultMinMax ); + if ( DefaultMinMax ) + otv_MinMax_validate( table + DefaultMinMax, valid ); + + OTV_LIMIT_CHECK( BaseLangSysCount * 6 ); + + /* BaseLangSysRecord */ + for ( ; BaseLangSysCount > 0; BaseLangSysCount-- ) + { + p += 4; /* skip BaseLangSysTag */ + + otv_MinMax_validate( table + FT_NEXT_USHORT( p ), valid ); + } + + OTV_EXIT; + } + + + static void + otv_BaseScriptList_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt BaseScriptCount; + + + OTV_NAME_ENTER( "BaseScriptList" ); + + OTV_LIMIT_CHECK( 2 ); + BaseScriptCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BaseScriptCount = %d)\n", BaseScriptCount )); + + OTV_LIMIT_CHECK( BaseScriptCount * 6 ); + + /* BaseScriptRecord */ + for ( ; BaseScriptCount > 0; BaseScriptCount-- ) + { + p += 4; /* skip BaseScriptTag */ + + /* BaseScript */ + otv_BaseScript_validate( table + FT_NEXT_USHORT( p ), valid ); + } + + OTV_EXIT; + } + + + static void + otv_Axis_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt table_size; + + OTV_OPTIONAL_TABLE( BaseTagList ); + + + OTV_NAME_ENTER( "Axis" ); + + OTV_LIMIT_CHECK( 4 ); + OTV_OPTIONAL_OFFSET( BaseTagList ); + + table_size = 4; + + OTV_SIZE_CHECK( BaseTagList ); + if ( BaseTagList ) + otv_BaseTagList_validate( table + BaseTagList, valid ); + + /* BaseScriptList */ + otv_BaseScriptList_validate( table + FT_NEXT_USHORT( p ), valid ); + + OTV_EXIT; + } + + + FT_LOCAL_DEF( void ) + otv_BASE_validate( FT_Bytes table, + FT_Validator ftvalid ) + { + OTV_ValidatorRec validrec; + OTV_Validator valid = &validrec; + FT_Bytes p = table; + FT_UInt table_size; + + OTV_OPTIONAL_TABLE( HorizAxis ); + OTV_OPTIONAL_TABLE( VertAxis ); + + + valid->root = ftvalid; + + FT_TRACE3(( "validating BASE table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 6 ); + + if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ + FT_INVALID_DATA; + + table_size = 6; + + OTV_OPTIONAL_OFFSET( HorizAxis ); + OTV_SIZE_CHECK( HorizAxis ); + if ( HorizAxis ) + otv_Axis_validate( table + HorizAxis, valid ); + + OTV_OPTIONAL_OFFSET( VertAxis ); + OTV_SIZE_CHECK( VertAxis ); + if ( VertAxis ) + otv_Axis_validate( table + VertAxis, valid ); + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/reactos/lib/freetype/src/otvalid/otvcommn.c b/reactos/lib/freetype/src/otvalid/otvcommn.c index fdb5ff3e9da..1b9d77c425f 100644 --- a/reactos/lib/freetype/src/otvalid/otvcommn.c +++ b/reactos/lib/freetype/src/otvalid/otvcommn.c @@ -1,1055 +1,1055 @@ -/***************************************************************************/ -/* */ -/* otvcommn.c */ -/* */ -/* OpenType common tables validation (body). */ -/* */ -/* Copyright 2004, 2005 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - -#include "otvcommn.h" - - - /*************************************************************************/ - /* */ - /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ - /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ - /* messages during execution. */ - /* */ -#undef FT_COMPONENT -#define FT_COMPONENT trace_otvcommon - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** COVERAGE TABLE *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - FT_LOCAL_DEF( void ) - otv_Coverage_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt CoverageFormat; - - - OTV_NAME_ENTER( "Coverage" ); - - OTV_LIMIT_CHECK( 4 ); - CoverageFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", CoverageFormat )); - - switch ( CoverageFormat ) - { - case 1: /* CoverageFormat1 */ - { - FT_UInt GlyphCount; - - - GlyphCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); - - OTV_LIMIT_CHECK( GlyphCount * 2 ); /* GlyphArray */ - } - break; - - case 2: /* CoverageFormat2 */ - { - FT_UInt n, RangeCount; - FT_UInt Start, End, StartCoverageIndex, total = 0, last = 0; - - - RangeCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (RangeCount = %d)\n", RangeCount )); - - OTV_LIMIT_CHECK( RangeCount * 6 ); - - /* RangeRecord */ - for ( n = 0; n < RangeCount; n++ ) - { - Start = FT_NEXT_USHORT( p ); - End = FT_NEXT_USHORT( p ); - StartCoverageIndex = FT_NEXT_USHORT( p ); - - if ( Start > End || StartCoverageIndex != total ) - FT_INVALID_DATA; - - if ( n > 0 && Start <= last ) - FT_INVALID_DATA; - - total += End - Start + 1; - last = End; - } - } - break; - - default: - FT_INVALID_FORMAT; - } - - /* no need to check glyph indices used as input to coverage tables */ - /* since even invalid glyph indices return a meaningful result */ - - OTV_EXIT; - } - - - FT_LOCAL_DEF( FT_UInt ) - otv_Coverage_get_first( FT_Bytes table ) - { - FT_Bytes p = table; - - - p += 4; /* skip CoverageFormat and Glyph/RangeCount */ - - return FT_NEXT_USHORT( p ); - } - - - FT_LOCAL_DEF( FT_UInt ) - otv_Coverage_get_last( FT_Bytes table ) - { - FT_Bytes p = table; - FT_UInt CoverageFormat = FT_NEXT_USHORT( p ); - FT_UInt count = FT_NEXT_USHORT( p ); /* Glyph/RangeCount */ - FT_UInt result = 0; - - - switch ( CoverageFormat ) - { - case 1: - p += ( count - 1 ) * 2; - result = FT_NEXT_USHORT( p ); - break; - - case 2: - p += ( count - 1 ) * 6 + 2; - result = FT_NEXT_USHORT( p ); - break; - - default: - ; - } - - return result; - } - - - FT_LOCAL_DEF( FT_UInt ) - otv_Coverage_get_count( FT_Bytes table ) - { - FT_Bytes p = table; - FT_UInt CoverageFormat = FT_NEXT_USHORT( p ); - FT_UInt count = FT_NEXT_USHORT( p ); /* Glyph/RangeCount */ - FT_UInt result = 0; - - - switch ( CoverageFormat ) - { - case 1: - return count; - - case 2: - { - FT_UInt Start, End; - - - for ( ; count > 0; count-- ) - { - Start = FT_NEXT_USHORT( p ); - End = FT_NEXT_USHORT( p ); - p += 2; /* skip StartCoverageIndex */ - - result += End - Start + 1; - } - } - break; - - default: - ; - } - - return result; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** CLASS DEFINITION TABLE *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - FT_LOCAL_DEF( void ) - otv_ClassDef_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt ClassFormat; - - - OTV_NAME_ENTER( "ClassDef" ); - - OTV_LIMIT_CHECK( 4 ); - ClassFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", ClassFormat )); - - switch ( ClassFormat ) - { - case 1: /* ClassDefFormat1 */ - { - FT_UInt GlyphCount; - - - p += 2; /* skip StartGlyph */ - - OTV_LIMIT_CHECK( 2 ); - - OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); - - GlyphCount = FT_NEXT_USHORT( p ); - - OTV_LIMIT_CHECK( GlyphCount * 2 ); /* ClassValueArray */ - } - break; - - case 2: /* ClassDefFormat2 */ - { - FT_UInt n, ClassRangeCount; - FT_UInt Start, End, last = 0; - - - ClassRangeCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (ClassRangeCount = %d)\n", ClassRangeCount )); - - OTV_LIMIT_CHECK( ClassRangeCount * 6 ); - - /* ClassRangeRecord */ - for ( n = 0; n < ClassRangeCount; n++ ) - { - Start = FT_NEXT_USHORT( p ); - End = FT_NEXT_USHORT( p ); - p += 2; /* skip Class */ - - if ( Start > End || ( n > 0 && Start <= last ) ) - FT_INVALID_DATA; - - last = End; - } - } - break; - - default: - FT_INVALID_FORMAT; - } - - /* no need to check glyph indices used as input to class definition */ - /* tables since even invalid glyph indices return a meaningful result */ - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** DEVICE TABLE *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - FT_LOCAL_DEF( void ) - otv_Device_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt StartSize, EndSize, DeltaFormat, count; - - - OTV_NAME_ENTER( "Device" ); - - OTV_LIMIT_CHECK( 8 ); - StartSize = FT_NEXT_USHORT( p ); - EndSize = FT_NEXT_USHORT( p ); - DeltaFormat = FT_NEXT_USHORT( p ); - - if ( DeltaFormat < 1 || DeltaFormat > 3 || EndSize < StartSize ) - FT_INVALID_DATA; - - count = EndSize - StartSize + 1; - OTV_LIMIT_CHECK( ( 1 << DeltaFormat ) * count / 8 ); /* DeltaValue */ - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** LOOKUPS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* uses valid->type_count */ - /* uses valid->type_funcs */ - - FT_LOCAL_DEF( void ) - otv_Lookup_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt LookupType, SubTableCount; - OTV_Validate_Func validate; - - - OTV_NAME_ENTER( "Lookup" ); - - OTV_LIMIT_CHECK( 6 ); - LookupType = FT_NEXT_USHORT( p ); - p += 2; /* skip LookupFlag */ - SubTableCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (type %d)\n", LookupType )); - - if ( LookupType == 0 || LookupType >= valid->type_count ) - FT_INVALID_DATA; - - validate = valid->type_funcs[LookupType - 1]; - - OTV_TRACE(( " (SubTableCount = %d)\n", SubTableCount )); - - OTV_LIMIT_CHECK( SubTableCount * 2 ); - - /* SubTable */ - for ( ; SubTableCount > 0; SubTableCount-- ) - validate( table + FT_NEXT_USHORT( p ), valid ); - - OTV_EXIT; - } - - - /* uses valid->lookup_count */ - - FT_LOCAL_DEF( void ) - otv_LookupList_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt LookupCount; - - - OTV_NAME_ENTER( "LookupList" ); - - OTV_LIMIT_CHECK( 2 ); - LookupCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (LookupCount = %d)\n", LookupCount )); - - OTV_LIMIT_CHECK( LookupCount * 2 ); - - valid->lookup_count = LookupCount; - - /* Lookup */ - for ( ; LookupCount > 0; LookupCount-- ) - otv_Lookup_validate( table + FT_NEXT_USHORT( p ), valid ); - - OTV_EXIT; - } - - - static FT_UInt - otv_LookupList_get_count( FT_Bytes table ) - { - return FT_NEXT_USHORT( table ); - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** FEATURES *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* uses valid->lookup_count */ - - FT_LOCAL_DEF( void ) - otv_Feature_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt LookupCount; - - - OTV_NAME_ENTER( "Feature" ); - - OTV_LIMIT_CHECK( 4 ); - p += 2; /* skip FeatureParams (unused) */ - LookupCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (LookupCount = %d)\n", LookupCount )); - - OTV_LIMIT_CHECK( LookupCount * 2 ); - - /* LookupListIndex */ - for ( ; LookupCount > 0; LookupCount-- ) - if ( FT_NEXT_USHORT( p ) >= valid->lookup_count ) - FT_INVALID_DATA; - - OTV_EXIT; - } - - - static FT_UInt - otv_Feature_get_count( FT_Bytes table ) - { - return FT_NEXT_USHORT( table ); - } - - - /* sets valid->lookup_count */ - - FT_LOCAL_DEF( void ) - otv_FeatureList_validate( FT_Bytes table, - FT_Bytes lookups, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt FeatureCount; - - - OTV_NAME_ENTER( "FeatureList" ); - - OTV_LIMIT_CHECK( 2 ); - FeatureCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (FeatureCount = %d)\n", FeatureCount )); - - OTV_LIMIT_CHECK( FeatureCount * 2 ); - - valid->lookup_count = otv_LookupList_get_count( lookups ); - - /* FeatureRecord */ - for ( ; FeatureCount > 0; FeatureCount-- ) - { - p += 4; /* skip FeatureTag */ - - /* Feature */ - otv_Feature_validate( table + FT_NEXT_USHORT( p ), valid ); - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** LANGUAGE SYSTEM *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - - /* uses valid->extra1 (number of features) */ - - FT_LOCAL_DEF( void ) - otv_LangSys_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt ReqFeatureIndex; - FT_UInt FeatureCount; - - - OTV_NAME_ENTER( "LangSys" ); - - OTV_LIMIT_CHECK( 6 ); - p += 2; /* skip LookupOrder (unused) */ - ReqFeatureIndex = FT_NEXT_USHORT( p ); - FeatureCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (ReqFeatureIndex = %d)\n", ReqFeatureIndex )); - OTV_TRACE(( " (FeatureCount = %d)\n", FeatureCount )); - - if ( ReqFeatureIndex != 0xFFFFU && ReqFeatureIndex >= valid->extra1 ) - FT_INVALID_DATA; - - OTV_LIMIT_CHECK( FeatureCount * 2 ); - - /* FeatureIndex */ - for ( ; FeatureCount > 0; FeatureCount-- ) - if ( FT_NEXT_USHORT( p ) >= valid->extra1 ) - FT_INVALID_DATA; - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** SCRIPTS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - FT_LOCAL_DEF( void ) - otv_Script_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_UInt DefaultLangSys, LangSysCount; - FT_Bytes p = table; - - - OTV_NAME_ENTER( "Script" ); - - OTV_LIMIT_CHECK( 4 ); - DefaultLangSys = FT_NEXT_USHORT( p ); - LangSysCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (LangSysCount = %d)\n", LangSysCount )); - - if ( DefaultLangSys != 0 ) - otv_LangSys_validate( table + DefaultLangSys, valid ); - - OTV_LIMIT_CHECK( LangSysCount * 6 ); - - /* LangSysRecord */ - for ( ; LangSysCount > 0; LangSysCount-- ) - { - p += 4; /* skip LangSysTag */ - - /* LangSys */ - otv_LangSys_validate( table + FT_NEXT_USHORT( p ), valid ); - } - - OTV_EXIT; - } - - - /* sets valid->extra1 (number of features) */ - - FT_LOCAL_DEF( void ) - otv_ScriptList_validate( FT_Bytes table, - FT_Bytes features, - OTV_Validator valid ) - { - FT_UInt ScriptCount; - FT_Bytes p = table; - - - OTV_NAME_ENTER( "ScriptList" ); - - OTV_LIMIT_CHECK( 2 ); - ScriptCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (ScriptCount = %d)\n", ScriptCount )); - - OTV_LIMIT_CHECK( ScriptCount * 6 ); - - valid->extra1 = otv_Feature_get_count( features ); - - /* ScriptRecord */ - for ( ; ScriptCount > 0; ScriptCount-- ) - { - p += 4; /* skip ScriptTag */ - - otv_Script_validate( table + FT_NEXT_USHORT( p ), valid ); /* Script */ - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** UTILITY FUNCTIONS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* - u: uint16 - ux: unit16 [x] - - s: struct - sx: struct [x] - sxy: struct [x], using external y count - - x: uint16 x - - C: Coverage - - O: Offset - On: Offset (NULL) - Ox: Offset [x] - Onx: Offset (NULL) [x] - */ - - FT_LOCAL_DEF( void ) - otv_x_Ox( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt Count; - OTV_Validate_Func func; - - - OTV_ENTER; - - OTV_LIMIT_CHECK( 2 ); - Count = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (Count = %d)\n", Count )); - - OTV_LIMIT_CHECK( Count * 2 ); - - valid->nesting_level++; - func = valid->func[valid->nesting_level]; - - for ( ; Count > 0; Count-- ) - func( table + FT_NEXT_USHORT( p ), valid ); - - valid->nesting_level--; - - OTV_EXIT; - } - - - FT_LOCAL_DEF( void ) - otv_u_C_x_Ox( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt Count, Coverage; - OTV_Validate_Func func; - - - OTV_ENTER; - - p += 2; /* skip Format */ - - OTV_LIMIT_CHECK( 4 ); - Coverage = FT_NEXT_USHORT( p ); - Count = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (Count = %d)\n", Count )); - - otv_Coverage_validate( table + Coverage, valid ); - - OTV_LIMIT_CHECK( Count * 2 ); - - valid->nesting_level++; - func = valid->func[valid->nesting_level]; - - for ( ; Count > 0; Count-- ) - func( table + FT_NEXT_USHORT( p ), valid ); - - valid->nesting_level--; - - OTV_EXIT; - } - - - /* uses valid->extra1 (if > 0: array value limit) */ - - FT_LOCAL_DEF( void ) - otv_x_ux( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt Count; - - - OTV_ENTER; - - OTV_LIMIT_CHECK( 2 ); - Count = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (Count = %d)\n", Count )); - - OTV_LIMIT_CHECK( Count * 2 ); - - if ( valid->extra1 ) - { - for ( ; Count > 0; Count-- ) - if ( FT_NEXT_USHORT( p ) >= valid->extra1 ) - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /* `ux' in the function's name is not really correct since only x-1 */ - /* elements are tested */ - - /* uses valid->extra1 (array value limit) */ - - FT_LOCAL_DEF( void ) - otv_x_y_ux_sy( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt Count1, Count2; - - - OTV_ENTER; - - OTV_LIMIT_CHECK( 4 ); - Count1 = FT_NEXT_USHORT( p ); - Count2 = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (Count1 = %d)\n", Count1 )); - OTV_TRACE(( " (Count2 = %d)\n", Count2 )); - - if ( Count1 == 0 ) - FT_INVALID_DATA; - - OTV_LIMIT_CHECK( ( Count1 - 1 ) * 2 + Count2 * 4 ); - - for ( ; Count2 > 0; Count2-- ) - { - if ( FT_NEXT_USHORT( p ) >= Count1 ) - FT_INVALID_DATA; - - if ( FT_NEXT_USHORT( p ) >= valid->extra1 ) - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /* `uy' in the function's name is not really correct since only y-1 */ - /* elements are tested */ - - /* uses valid->extra1 (array value limit) */ - - FT_LOCAL_DEF( void ) - otv_x_ux_y_uy_z_uz_p_sp( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt BacktrackCount, InputCount, LookaheadCount; - FT_UInt Count; - - - OTV_ENTER; - - OTV_LIMIT_CHECK( 2 ); - BacktrackCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (BacktrackCount = %d)\n", BacktrackCount )); - - OTV_LIMIT_CHECK( BacktrackCount * 2 + 2 ); - p += BacktrackCount * 2; - - InputCount = FT_NEXT_USHORT( p ); - if ( InputCount == 0 ) - FT_INVALID_DATA; - - OTV_TRACE(( " (InputCount = %d)\n", InputCount )); - - OTV_LIMIT_CHECK( InputCount * 2 ); - p += ( InputCount - 1 ) * 2; - - LookaheadCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (LookaheadCount = %d)\n", LookaheadCount )); - - OTV_LIMIT_CHECK( LookaheadCount * 2 + 2 ); - p += LookaheadCount * 2; - - Count = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (Count = %d)\n", Count )); - - OTV_LIMIT_CHECK( Count * 4 ); - - for ( ; Count > 0; Count-- ) - { - if ( FT_NEXT_USHORT( p ) >= InputCount ) - FT_INVALID_DATA; - - if ( FT_NEXT_USHORT( p ) >= valid->extra1 ) - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /* sets valid->extra1 (valid->lookup_count) */ - - FT_LOCAL_DEF( void ) - otv_u_O_O_x_Onx( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt Coverage, ClassDef, ClassSetCount; - OTV_Validate_Func func; - - - OTV_ENTER; - - p += 2; /* skip Format */ - - OTV_LIMIT_CHECK( 6 ); - Coverage = FT_NEXT_USHORT( p ); - ClassDef = FT_NEXT_USHORT( p ); - ClassSetCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (ClassSetCount = %d)\n", ClassSetCount )); - - otv_Coverage_validate( table + Coverage, valid ); - otv_ClassDef_validate( table + ClassDef, valid ); - - OTV_LIMIT_CHECK( ClassSetCount * 2 ); - - valid->nesting_level++; - func = valid->func[valid->nesting_level]; - valid->extra1 = valid->lookup_count; - - for ( ; ClassSetCount > 0; ClassSetCount-- ) - { - FT_UInt offset = FT_NEXT_USHORT( p ); - - - if ( offset ) - func( table + offset, valid ); - } - - valid->nesting_level--; - - OTV_EXIT; - } - - - /* uses valid->lookup_count */ - - FT_LOCAL_DEF( void ) - otv_u_x_y_Ox_sy( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt GlyphCount, Count, count1; - - - OTV_ENTER; - - p += 2; /* skip Format */ - - OTV_LIMIT_CHECK( 4 ); - GlyphCount = FT_NEXT_USHORT( p ); - Count = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); - OTV_TRACE(( " (Count = %d)\n", Count )); - - OTV_LIMIT_CHECK( GlyphCount * 2 + Count * 4 ); - - for ( count1 = GlyphCount; count1 > 0; count1-- ) - otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid ); - - for ( ; Count > 0; Count-- ) - { - if ( FT_NEXT_USHORT( p ) >= GlyphCount ) - FT_INVALID_DATA; - - if ( FT_NEXT_USHORT( p ) >= valid->lookup_count ) - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /* sets valid->extra1 (valid->lookup_count) */ - - FT_LOCAL_DEF( void ) - otv_u_O_O_O_O_x_Onx( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt Coverage; - FT_UInt BacktrackClassDef, InputClassDef, LookaheadClassDef; - FT_UInt ChainClassSetCount; - OTV_Validate_Func func; - - - OTV_ENTER; - - p += 2; /* skip Format */ - - OTV_LIMIT_CHECK( 10 ); - Coverage = FT_NEXT_USHORT( p ); - BacktrackClassDef = FT_NEXT_USHORT( p ); - InputClassDef = FT_NEXT_USHORT( p ); - LookaheadClassDef = FT_NEXT_USHORT( p ); - ChainClassSetCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (ChainClassSetCount = %d)\n", ChainClassSetCount )); - - otv_Coverage_validate( table + Coverage, valid ); - - otv_ClassDef_validate( table + BacktrackClassDef, valid ); - otv_ClassDef_validate( table + InputClassDef, valid ); - otv_ClassDef_validate( table + LookaheadClassDef, valid ); - - OTV_LIMIT_CHECK( ChainClassSetCount * 2 ); - - valid->nesting_level++; - func = valid->func[valid->nesting_level]; - valid->extra1 = valid->lookup_count; - - for ( ; ChainClassSetCount > 0; ChainClassSetCount-- ) - { - FT_UInt offset = FT_NEXT_USHORT( p ); - - - if ( offset ) - func( table + offset, valid ); - } - - valid->nesting_level--; - - OTV_EXIT; - } - - - /* uses valid->lookup_count */ - - FT_LOCAL_DEF( void ) - otv_u_x_Ox_y_Oy_z_Oz_p_sp( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt BacktrackGlyphCount, InputGlyphCount, LookaheadGlyphCount; - FT_UInt count1, count2; - - - OTV_ENTER; - - p += 2; /* skip Format */ - - OTV_LIMIT_CHECK( 2 ); - BacktrackGlyphCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (BacktrackGlyphCount = %d)\n", BacktrackGlyphCount )); - - OTV_LIMIT_CHECK( BacktrackGlyphCount * 2 + 2 ); - - for ( ; BacktrackGlyphCount > 0; BacktrackGlyphCount-- ) - otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid ); - - InputGlyphCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (InputGlyphCount = %d)\n", InputGlyphCount )); - - OTV_LIMIT_CHECK( InputGlyphCount * 2 + 2 ); - - for ( count1 = InputGlyphCount; count1 > 0; count1-- ) - otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid ); - - LookaheadGlyphCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (LookaheadGlyphCount = %d)\n", LookaheadGlyphCount )); - - OTV_LIMIT_CHECK( LookaheadGlyphCount * 2 + 2 ); - - for ( ; LookaheadGlyphCount > 0; LookaheadGlyphCount-- ) - otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid ); - - count2 = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (Count = %d)\n", count2 )); - - OTV_LIMIT_CHECK( count2 * 4 ); - - for ( ; count2 > 0; count2-- ) - { - if ( FT_NEXT_USHORT( p ) >= InputGlyphCount ) - FT_INVALID_DATA; - - if ( FT_NEXT_USHORT( p ) >= valid->lookup_count ) - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - FT_LOCAL_DEF( FT_UInt ) - otv_GSUBGPOS_get_Lookup_count( FT_Bytes table ) - { - FT_Bytes p = table + 8; - - - return otv_LookupList_get_count( table + FT_NEXT_USHORT( p ) ); - } - - - FT_LOCAL_DEF( FT_UInt ) - otv_GSUBGPOS_have_MarkAttachmentType_flag( FT_Bytes table ) - { - FT_Bytes p, lookup; - FT_UInt count; - - - if ( !table ) - return 0; - - /* LookupList */ - p = table + 8; - table += FT_NEXT_USHORT( p ); - - /* LookupCount */ - p = table; - count = FT_NEXT_USHORT( p ); - - for ( ; count > 0; count-- ) - { - FT_Bytes oldp; - - - /* Lookup */ - lookup = table + FT_NEXT_USHORT( p ); - - oldp = p; - - /* LookupFlag */ - p = lookup + 2; - if ( FT_NEXT_USHORT( p ) & 0xFF00U ) - return 1; - - p = oldp; - } - - return 0; - } - - -/* END */ +/***************************************************************************/ +/* */ +/* otvcommn.c */ +/* */ +/* OpenType common tables validation (body). */ +/* */ +/* Copyright 2004, 2005 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include "otvcommn.h" + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_otvcommon + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** COVERAGE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + otv_Coverage_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt CoverageFormat; + + + OTV_NAME_ENTER( "Coverage" ); + + OTV_LIMIT_CHECK( 4 ); + CoverageFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", CoverageFormat )); + + switch ( CoverageFormat ) + { + case 1: /* CoverageFormat1 */ + { + FT_UInt GlyphCount; + + + GlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + + OTV_LIMIT_CHECK( GlyphCount * 2 ); /* GlyphArray */ + } + break; + + case 2: /* CoverageFormat2 */ + { + FT_UInt n, RangeCount; + FT_UInt Start, End, StartCoverageIndex, total = 0, last = 0; + + + RangeCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (RangeCount = %d)\n", RangeCount )); + + OTV_LIMIT_CHECK( RangeCount * 6 ); + + /* RangeRecord */ + for ( n = 0; n < RangeCount; n++ ) + { + Start = FT_NEXT_USHORT( p ); + End = FT_NEXT_USHORT( p ); + StartCoverageIndex = FT_NEXT_USHORT( p ); + + if ( Start > End || StartCoverageIndex != total ) + FT_INVALID_DATA; + + if ( n > 0 && Start <= last ) + FT_INVALID_DATA; + + total += End - Start + 1; + last = End; + } + } + break; + + default: + FT_INVALID_FORMAT; + } + + /* no need to check glyph indices used as input to coverage tables */ + /* since even invalid glyph indices return a meaningful result */ + + OTV_EXIT; + } + + + FT_LOCAL_DEF( FT_UInt ) + otv_Coverage_get_first( FT_Bytes table ) + { + FT_Bytes p = table; + + + p += 4; /* skip CoverageFormat and Glyph/RangeCount */ + + return FT_NEXT_USHORT( p ); + } + + + FT_LOCAL_DEF( FT_UInt ) + otv_Coverage_get_last( FT_Bytes table ) + { + FT_Bytes p = table; + FT_UInt CoverageFormat = FT_NEXT_USHORT( p ); + FT_UInt count = FT_NEXT_USHORT( p ); /* Glyph/RangeCount */ + FT_UInt result = 0; + + + switch ( CoverageFormat ) + { + case 1: + p += ( count - 1 ) * 2; + result = FT_NEXT_USHORT( p ); + break; + + case 2: + p += ( count - 1 ) * 6 + 2; + result = FT_NEXT_USHORT( p ); + break; + + default: + ; + } + + return result; + } + + + FT_LOCAL_DEF( FT_UInt ) + otv_Coverage_get_count( FT_Bytes table ) + { + FT_Bytes p = table; + FT_UInt CoverageFormat = FT_NEXT_USHORT( p ); + FT_UInt count = FT_NEXT_USHORT( p ); /* Glyph/RangeCount */ + FT_UInt result = 0; + + + switch ( CoverageFormat ) + { + case 1: + return count; + + case 2: + { + FT_UInt Start, End; + + + for ( ; count > 0; count-- ) + { + Start = FT_NEXT_USHORT( p ); + End = FT_NEXT_USHORT( p ); + p += 2; /* skip StartCoverageIndex */ + + result += End - Start + 1; + } + } + break; + + default: + ; + } + + return result; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CLASS DEFINITION TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + otv_ClassDef_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt ClassFormat; + + + OTV_NAME_ENTER( "ClassDef" ); + + OTV_LIMIT_CHECK( 4 ); + ClassFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", ClassFormat )); + + switch ( ClassFormat ) + { + case 1: /* ClassDefFormat1 */ + { + FT_UInt GlyphCount; + + + p += 2; /* skip StartGlyph */ + + OTV_LIMIT_CHECK( 2 ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + + GlyphCount = FT_NEXT_USHORT( p ); + + OTV_LIMIT_CHECK( GlyphCount * 2 ); /* ClassValueArray */ + } + break; + + case 2: /* ClassDefFormat2 */ + { + FT_UInt n, ClassRangeCount; + FT_UInt Start, End, last = 0; + + + ClassRangeCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ClassRangeCount = %d)\n", ClassRangeCount )); + + OTV_LIMIT_CHECK( ClassRangeCount * 6 ); + + /* ClassRangeRecord */ + for ( n = 0; n < ClassRangeCount; n++ ) + { + Start = FT_NEXT_USHORT( p ); + End = FT_NEXT_USHORT( p ); + p += 2; /* skip Class */ + + if ( Start > End || ( n > 0 && Start <= last ) ) + FT_INVALID_DATA; + + last = End; + } + } + break; + + default: + FT_INVALID_FORMAT; + } + + /* no need to check glyph indices used as input to class definition */ + /* tables since even invalid glyph indices return a meaningful result */ + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** DEVICE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + otv_Device_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt StartSize, EndSize, DeltaFormat, count; + + + OTV_NAME_ENTER( "Device" ); + + OTV_LIMIT_CHECK( 8 ); + StartSize = FT_NEXT_USHORT( p ); + EndSize = FT_NEXT_USHORT( p ); + DeltaFormat = FT_NEXT_USHORT( p ); + + if ( DeltaFormat < 1 || DeltaFormat > 3 || EndSize < StartSize ) + FT_INVALID_DATA; + + count = EndSize - StartSize + 1; + OTV_LIMIT_CHECK( ( 1 << DeltaFormat ) * count / 8 ); /* DeltaValue */ + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LOOKUPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses valid->type_count */ + /* uses valid->type_funcs */ + + FT_LOCAL_DEF( void ) + otv_Lookup_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt LookupType, SubTableCount; + OTV_Validate_Func validate; + + + OTV_NAME_ENTER( "Lookup" ); + + OTV_LIMIT_CHECK( 6 ); + LookupType = FT_NEXT_USHORT( p ); + p += 2; /* skip LookupFlag */ + SubTableCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (type %d)\n", LookupType )); + + if ( LookupType == 0 || LookupType >= valid->type_count ) + FT_INVALID_DATA; + + validate = valid->type_funcs[LookupType - 1]; + + OTV_TRACE(( " (SubTableCount = %d)\n", SubTableCount )); + + OTV_LIMIT_CHECK( SubTableCount * 2 ); + + /* SubTable */ + for ( ; SubTableCount > 0; SubTableCount-- ) + validate( table + FT_NEXT_USHORT( p ), valid ); + + OTV_EXIT; + } + + + /* uses valid->lookup_count */ + + FT_LOCAL_DEF( void ) + otv_LookupList_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt LookupCount; + + + OTV_NAME_ENTER( "LookupList" ); + + OTV_LIMIT_CHECK( 2 ); + LookupCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LookupCount = %d)\n", LookupCount )); + + OTV_LIMIT_CHECK( LookupCount * 2 ); + + valid->lookup_count = LookupCount; + + /* Lookup */ + for ( ; LookupCount > 0; LookupCount-- ) + otv_Lookup_validate( table + FT_NEXT_USHORT( p ), valid ); + + OTV_EXIT; + } + + + static FT_UInt + otv_LookupList_get_count( FT_Bytes table ) + { + return FT_NEXT_USHORT( table ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FEATURES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses valid->lookup_count */ + + FT_LOCAL_DEF( void ) + otv_Feature_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt LookupCount; + + + OTV_NAME_ENTER( "Feature" ); + + OTV_LIMIT_CHECK( 4 ); + p += 2; /* skip FeatureParams (unused) */ + LookupCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LookupCount = %d)\n", LookupCount )); + + OTV_LIMIT_CHECK( LookupCount * 2 ); + + /* LookupListIndex */ + for ( ; LookupCount > 0; LookupCount-- ) + if ( FT_NEXT_USHORT( p ) >= valid->lookup_count ) + FT_INVALID_DATA; + + OTV_EXIT; + } + + + static FT_UInt + otv_Feature_get_count( FT_Bytes table ) + { + return FT_NEXT_USHORT( table ); + } + + + /* sets valid->lookup_count */ + + FT_LOCAL_DEF( void ) + otv_FeatureList_validate( FT_Bytes table, + FT_Bytes lookups, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt FeatureCount; + + + OTV_NAME_ENTER( "FeatureList" ); + + OTV_LIMIT_CHECK( 2 ); + FeatureCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (FeatureCount = %d)\n", FeatureCount )); + + OTV_LIMIT_CHECK( FeatureCount * 2 ); + + valid->lookup_count = otv_LookupList_get_count( lookups ); + + /* FeatureRecord */ + for ( ; FeatureCount > 0; FeatureCount-- ) + { + p += 4; /* skip FeatureTag */ + + /* Feature */ + otv_Feature_validate( table + FT_NEXT_USHORT( p ), valid ); + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LANGUAGE SYSTEM *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + + /* uses valid->extra1 (number of features) */ + + FT_LOCAL_DEF( void ) + otv_LangSys_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt ReqFeatureIndex; + FT_UInt FeatureCount; + + + OTV_NAME_ENTER( "LangSys" ); + + OTV_LIMIT_CHECK( 6 ); + p += 2; /* skip LookupOrder (unused) */ + ReqFeatureIndex = FT_NEXT_USHORT( p ); + FeatureCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ReqFeatureIndex = %d)\n", ReqFeatureIndex )); + OTV_TRACE(( " (FeatureCount = %d)\n", FeatureCount )); + + if ( ReqFeatureIndex != 0xFFFFU && ReqFeatureIndex >= valid->extra1 ) + FT_INVALID_DATA; + + OTV_LIMIT_CHECK( FeatureCount * 2 ); + + /* FeatureIndex */ + for ( ; FeatureCount > 0; FeatureCount-- ) + if ( FT_NEXT_USHORT( p ) >= valid->extra1 ) + FT_INVALID_DATA; + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SCRIPTS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + otv_Script_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_UInt DefaultLangSys, LangSysCount; + FT_Bytes p = table; + + + OTV_NAME_ENTER( "Script" ); + + OTV_LIMIT_CHECK( 4 ); + DefaultLangSys = FT_NEXT_USHORT( p ); + LangSysCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LangSysCount = %d)\n", LangSysCount )); + + if ( DefaultLangSys != 0 ) + otv_LangSys_validate( table + DefaultLangSys, valid ); + + OTV_LIMIT_CHECK( LangSysCount * 6 ); + + /* LangSysRecord */ + for ( ; LangSysCount > 0; LangSysCount-- ) + { + p += 4; /* skip LangSysTag */ + + /* LangSys */ + otv_LangSys_validate( table + FT_NEXT_USHORT( p ), valid ); + } + + OTV_EXIT; + } + + + /* sets valid->extra1 (number of features) */ + + FT_LOCAL_DEF( void ) + otv_ScriptList_validate( FT_Bytes table, + FT_Bytes features, + OTV_Validator valid ) + { + FT_UInt ScriptCount; + FT_Bytes p = table; + + + OTV_NAME_ENTER( "ScriptList" ); + + OTV_LIMIT_CHECK( 2 ); + ScriptCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ScriptCount = %d)\n", ScriptCount )); + + OTV_LIMIT_CHECK( ScriptCount * 6 ); + + valid->extra1 = otv_Feature_get_count( features ); + + /* ScriptRecord */ + for ( ; ScriptCount > 0; ScriptCount-- ) + { + p += 4; /* skip ScriptTag */ + + otv_Script_validate( table + FT_NEXT_USHORT( p ), valid ); /* Script */ + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* + u: uint16 + ux: unit16 [x] + + s: struct + sx: struct [x] + sxy: struct [x], using external y count + + x: uint16 x + + C: Coverage + + O: Offset + On: Offset (NULL) + Ox: Offset [x] + Onx: Offset (NULL) [x] + */ + + FT_LOCAL_DEF( void ) + otv_x_Ox( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt Count; + OTV_Validate_Func func; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 2 ); + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", Count )); + + OTV_LIMIT_CHECK( Count * 2 ); + + valid->nesting_level++; + func = valid->func[valid->nesting_level]; + + for ( ; Count > 0; Count-- ) + func( table + FT_NEXT_USHORT( p ), valid ); + + valid->nesting_level--; + + OTV_EXIT; + } + + + FT_LOCAL_DEF( void ) + otv_u_C_x_Ox( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt Count, Coverage; + OTV_Validate_Func func; + + + OTV_ENTER; + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 4 ); + Coverage = FT_NEXT_USHORT( p ); + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", Count )); + + otv_Coverage_validate( table + Coverage, valid ); + + OTV_LIMIT_CHECK( Count * 2 ); + + valid->nesting_level++; + func = valid->func[valid->nesting_level]; + + for ( ; Count > 0; Count-- ) + func( table + FT_NEXT_USHORT( p ), valid ); + + valid->nesting_level--; + + OTV_EXIT; + } + + + /* uses valid->extra1 (if > 0: array value limit) */ + + FT_LOCAL_DEF( void ) + otv_x_ux( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt Count; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 2 ); + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", Count )); + + OTV_LIMIT_CHECK( Count * 2 ); + + if ( valid->extra1 ) + { + for ( ; Count > 0; Count-- ) + if ( FT_NEXT_USHORT( p ) >= valid->extra1 ) + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /* `ux' in the function's name is not really correct since only x-1 */ + /* elements are tested */ + + /* uses valid->extra1 (array value limit) */ + + FT_LOCAL_DEF( void ) + otv_x_y_ux_sy( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt Count1, Count2; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 4 ); + Count1 = FT_NEXT_USHORT( p ); + Count2 = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count1 = %d)\n", Count1 )); + OTV_TRACE(( " (Count2 = %d)\n", Count2 )); + + if ( Count1 == 0 ) + FT_INVALID_DATA; + + OTV_LIMIT_CHECK( ( Count1 - 1 ) * 2 + Count2 * 4 ); + + for ( ; Count2 > 0; Count2-- ) + { + if ( FT_NEXT_USHORT( p ) >= Count1 ) + FT_INVALID_DATA; + + if ( FT_NEXT_USHORT( p ) >= valid->extra1 ) + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /* `uy' in the function's name is not really correct since only y-1 */ + /* elements are tested */ + + /* uses valid->extra1 (array value limit) */ + + FT_LOCAL_DEF( void ) + otv_x_ux_y_uy_z_uz_p_sp( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt BacktrackCount, InputCount, LookaheadCount; + FT_UInt Count; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 2 ); + BacktrackCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BacktrackCount = %d)\n", BacktrackCount )); + + OTV_LIMIT_CHECK( BacktrackCount * 2 + 2 ); + p += BacktrackCount * 2; + + InputCount = FT_NEXT_USHORT( p ); + if ( InputCount == 0 ) + FT_INVALID_DATA; + + OTV_TRACE(( " (InputCount = %d)\n", InputCount )); + + OTV_LIMIT_CHECK( InputCount * 2 ); + p += ( InputCount - 1 ) * 2; + + LookaheadCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LookaheadCount = %d)\n", LookaheadCount )); + + OTV_LIMIT_CHECK( LookaheadCount * 2 + 2 ); + p += LookaheadCount * 2; + + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", Count )); + + OTV_LIMIT_CHECK( Count * 4 ); + + for ( ; Count > 0; Count-- ) + { + if ( FT_NEXT_USHORT( p ) >= InputCount ) + FT_INVALID_DATA; + + if ( FT_NEXT_USHORT( p ) >= valid->extra1 ) + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /* sets valid->extra1 (valid->lookup_count) */ + + FT_LOCAL_DEF( void ) + otv_u_O_O_x_Onx( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt Coverage, ClassDef, ClassSetCount; + OTV_Validate_Func func; + + + OTV_ENTER; + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 6 ); + Coverage = FT_NEXT_USHORT( p ); + ClassDef = FT_NEXT_USHORT( p ); + ClassSetCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ClassSetCount = %d)\n", ClassSetCount )); + + otv_Coverage_validate( table + Coverage, valid ); + otv_ClassDef_validate( table + ClassDef, valid ); + + OTV_LIMIT_CHECK( ClassSetCount * 2 ); + + valid->nesting_level++; + func = valid->func[valid->nesting_level]; + valid->extra1 = valid->lookup_count; + + for ( ; ClassSetCount > 0; ClassSetCount-- ) + { + FT_UInt offset = FT_NEXT_USHORT( p ); + + + if ( offset ) + func( table + offset, valid ); + } + + valid->nesting_level--; + + OTV_EXIT; + } + + + /* uses valid->lookup_count */ + + FT_LOCAL_DEF( void ) + otv_u_x_y_Ox_sy( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt GlyphCount, Count, count1; + + + OTV_ENTER; + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 4 ); + GlyphCount = FT_NEXT_USHORT( p ); + Count = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + OTV_TRACE(( " (Count = %d)\n", Count )); + + OTV_LIMIT_CHECK( GlyphCount * 2 + Count * 4 ); + + for ( count1 = GlyphCount; count1 > 0; count1-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid ); + + for ( ; Count > 0; Count-- ) + { + if ( FT_NEXT_USHORT( p ) >= GlyphCount ) + FT_INVALID_DATA; + + if ( FT_NEXT_USHORT( p ) >= valid->lookup_count ) + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /* sets valid->extra1 (valid->lookup_count) */ + + FT_LOCAL_DEF( void ) + otv_u_O_O_O_O_x_Onx( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt Coverage; + FT_UInt BacktrackClassDef, InputClassDef, LookaheadClassDef; + FT_UInt ChainClassSetCount; + OTV_Validate_Func func; + + + OTV_ENTER; + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 10 ); + Coverage = FT_NEXT_USHORT( p ); + BacktrackClassDef = FT_NEXT_USHORT( p ); + InputClassDef = FT_NEXT_USHORT( p ); + LookaheadClassDef = FT_NEXT_USHORT( p ); + ChainClassSetCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ChainClassSetCount = %d)\n", ChainClassSetCount )); + + otv_Coverage_validate( table + Coverage, valid ); + + otv_ClassDef_validate( table + BacktrackClassDef, valid ); + otv_ClassDef_validate( table + InputClassDef, valid ); + otv_ClassDef_validate( table + LookaheadClassDef, valid ); + + OTV_LIMIT_CHECK( ChainClassSetCount * 2 ); + + valid->nesting_level++; + func = valid->func[valid->nesting_level]; + valid->extra1 = valid->lookup_count; + + for ( ; ChainClassSetCount > 0; ChainClassSetCount-- ) + { + FT_UInt offset = FT_NEXT_USHORT( p ); + + + if ( offset ) + func( table + offset, valid ); + } + + valid->nesting_level--; + + OTV_EXIT; + } + + + /* uses valid->lookup_count */ + + FT_LOCAL_DEF( void ) + otv_u_x_Ox_y_Oy_z_Oz_p_sp( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt BacktrackGlyphCount, InputGlyphCount, LookaheadGlyphCount; + FT_UInt count1, count2; + + + OTV_ENTER; + + p += 2; /* skip Format */ + + OTV_LIMIT_CHECK( 2 ); + BacktrackGlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BacktrackGlyphCount = %d)\n", BacktrackGlyphCount )); + + OTV_LIMIT_CHECK( BacktrackGlyphCount * 2 + 2 ); + + for ( ; BacktrackGlyphCount > 0; BacktrackGlyphCount-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid ); + + InputGlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (InputGlyphCount = %d)\n", InputGlyphCount )); + + OTV_LIMIT_CHECK( InputGlyphCount * 2 + 2 ); + + for ( count1 = InputGlyphCount; count1 > 0; count1-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid ); + + LookaheadGlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LookaheadGlyphCount = %d)\n", LookaheadGlyphCount )); + + OTV_LIMIT_CHECK( LookaheadGlyphCount * 2 + 2 ); + + for ( ; LookaheadGlyphCount > 0; LookaheadGlyphCount-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid ); + + count2 = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (Count = %d)\n", count2 )); + + OTV_LIMIT_CHECK( count2 * 4 ); + + for ( ; count2 > 0; count2-- ) + { + if ( FT_NEXT_USHORT( p ) >= InputGlyphCount ) + FT_INVALID_DATA; + + if ( FT_NEXT_USHORT( p ) >= valid->lookup_count ) + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + FT_LOCAL_DEF( FT_UInt ) + otv_GSUBGPOS_get_Lookup_count( FT_Bytes table ) + { + FT_Bytes p = table + 8; + + + return otv_LookupList_get_count( table + FT_NEXT_USHORT( p ) ); + } + + + FT_LOCAL_DEF( FT_UInt ) + otv_GSUBGPOS_have_MarkAttachmentType_flag( FT_Bytes table ) + { + FT_Bytes p, lookup; + FT_UInt count; + + + if ( !table ) + return 0; + + /* LookupList */ + p = table + 8; + table += FT_NEXT_USHORT( p ); + + /* LookupCount */ + p = table; + count = FT_NEXT_USHORT( p ); + + for ( ; count > 0; count-- ) + { + FT_Bytes oldp; + + + /* Lookup */ + lookup = table + FT_NEXT_USHORT( p ); + + oldp = p; + + /* LookupFlag */ + p = lookup + 2; + if ( FT_NEXT_USHORT( p ) & 0xFF00U ) + return 1; + + p = oldp; + } + + return 0; + } + + +/* END */ diff --git a/reactos/lib/freetype/src/otvalid/otvcommn.h b/reactos/lib/freetype/src/otvalid/otvcommn.h index 3efcb4a8cad..9f84910d518 100644 --- a/reactos/lib/freetype/src/otvalid/otvcommn.h +++ b/reactos/lib/freetype/src/otvalid/otvcommn.h @@ -1,442 +1,442 @@ -/***************************************************************************/ -/* */ -/* otvcommn.h */ -/* */ -/* OpenType common tables validation (specification). */ -/* */ -/* Copyright 2004 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - -#ifndef __OTVCOMMN_H__ -#define __OTVCOMMN_H__ - - -#include <ft2build.h> -#include "otvalid.h" -#include FT_INTERNAL_DEBUG_H - - -FT_BEGIN_HEADER - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** VALIDATION *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - typedef struct OTV_ValidatorRec_* OTV_Validator; - - typedef void (*OTV_Validate_Func)( FT_Bytes table, - OTV_Validator valid ); - - typedef struct OTV_ValidatorRec_ - { - FT_Validator root; - FT_UInt type_count; - OTV_Validate_Func* type_funcs; - - FT_UInt lookup_count; - FT_UInt glyph_count; - - FT_UInt nesting_level; - - OTV_Validate_Func func[3]; - - FT_UInt extra1; /* for passing parameters */ - FT_UInt extra2; - FT_Bytes extra3; - -#ifdef FT_DEBUG_LEVEL_TRACE - FT_UInt debug_indent; - const FT_String* debug_function_name[3]; -#endif - - } OTV_ValidatorRec; - - -#undef FT_INVALID_ -#define FT_INVALID_( _prefix, _error ) \ - ft_validator_error( valid->root, _prefix ## _error ) - -#define OTV_OPTIONAL_TABLE( _table ) FT_UInt _table; \ - FT_Bytes _table ## _p - -#define OTV_OPTIONAL_OFFSET( _offset ) \ - FT_BEGIN_STMNT \ - _offset ## _p = p; \ - _offset = FT_NEXT_USHORT( p ); \ - FT_END_STMNT - -#define OTV_LIMIT_CHECK( _count ) \ - FT_BEGIN_STMNT \ - if ( p + (_count) > valid->root->limit ) \ - FT_INVALID_TOO_SHORT; \ - FT_END_STMNT - -#define OTV_SIZE_CHECK( _size ) \ - FT_BEGIN_STMNT \ - if ( _size > 0 && _size < table_size ) \ - { \ - if ( valid->root->level == FT_VALIDATE_PARANOID ) \ - FT_INVALID_OFFSET; \ - else \ - { \ - /* strip off `const' */ \ - FT_Byte* pp = (FT_Byte*)_size ## _p; \ - \ - \ - FT_TRACE3(( "\n" \ - "Invalid offset to optional table `%s'!\n" \ - "Set to zero.\n" \ - "\n", #_size )); \ - \ - /* always assume 16bit entities */ \ - _size = pp[0] = pp[1] = 0; \ - } \ - } \ - FT_END_STMNT - - -#ifdef FT_DEBUG_LEVEL_TRACE - - /* use preprocessor's argument prescan to expand one argument into two */ -#define OTV_NEST1( x ) OTV_NEST1_( x ) -#define OTV_NEST1_( func0, name0 ) \ - FT_BEGIN_STMNT \ - valid->nesting_level = 0; \ - valid->func[0] = func0; \ - valid->debug_function_name[0] = name0; \ - FT_END_STMNT - - /* use preprocessor's argument prescan to expand two arguments into four */ -#define OTV_NEST2( x, y ) OTV_NEST2_( x, y ) -#define OTV_NEST2_( func0, name0, func1, name1 ) \ - FT_BEGIN_STMNT \ - valid->nesting_level = 0; \ - valid->func[0] = func0; \ - valid->func[1] = func1; \ - valid->debug_function_name[0] = name0; \ - valid->debug_function_name[1] = name1; \ - FT_END_STMNT - - /* use preprocessor's argument prescan to expand three arguments into six */ -#define OTV_NEST3( x, y, z ) OTV_NEST3_( x, y, z ) -#define OTV_NEST3_( func0, name0, func1, name1, func2, name2 ) \ - FT_BEGIN_STMNT \ - valid->nesting_level = 0; \ - valid->func[0] = func0; \ - valid->func[1] = func1; \ - valid->func[2] = func2; \ - valid->debug_function_name[0] = name0; \ - valid->debug_function_name[1] = name1; \ - valid->debug_function_name[2] = name2; \ - FT_END_STMNT - -#define OTV_INIT valid->debug_indent = 0 - -#define OTV_ENTER \ - FT_BEGIN_STMNT \ - valid->debug_indent += 2; \ - FT_TRACE4(( "%*.s", valid->debug_indent, 0 )); \ - FT_TRACE4(( "%s table\n", \ - valid->debug_function_name[valid->nesting_level] )); \ - FT_END_STMNT - -#define OTV_NAME_ENTER( name ) \ - FT_BEGIN_STMNT \ - valid->debug_indent += 2; \ - FT_TRACE4(( "%*.s", valid->debug_indent, 0 )); \ - FT_TRACE4(( "%s table\n", name )); \ - FT_END_STMNT - -#define OTV_EXIT valid->debug_indent -= 2 - -#define OTV_TRACE( s ) \ - FT_BEGIN_STMNT \ - FT_TRACE4(( "%*.s", valid->debug_indent, 0 )); \ - FT_TRACE4( s ); \ - FT_END_STMNT - -#else /* !FT_DEBUG_LEVEL_TRACE */ - - /* use preprocessor's argument prescan to expand one argument into two */ -#define OTV_NEST1( x ) OTV_NEST1_( x ) -#define OTV_NEST1_( func0, name0 ) \ - FT_BEGIN_STMNT \ - valid->nesting_level = 0; \ - valid->func[0] = func0; \ - FT_END_STMNT - - /* use preprocessor's argument prescan to expand two arguments into four */ -#define OTV_NEST2( x, y ) OTV_NEST2_( x, y ) -#define OTV_NEST2_( func0, name0, func1, name1 ) \ - FT_BEGIN_STMNT \ - valid->nesting_level = 0; \ - valid->func[0] = func0; \ - valid->func[1] = func1; \ - FT_END_STMNT - - /* use preprocessor's argument prescan to expand three arguments into six */ -#define OTV_NEST3( x, y, z ) OTV_NEST3_( x, y, z ) -#define OTV_NEST3_( func0, name0, func1, name1, func2, name2 ) \ - FT_BEGIN_STMNT \ - valid->nesting_level = 0; \ - valid->func[0] = func0; \ - valid->func[1] = func1; \ - valid->func[2] = func2; \ - FT_END_STMNT - -#define OTV_INIT do ; while ( 0 ) -#define OTV_ENTER do ; while ( 0 ) -#define OTV_NAME_ENTER( name ) do ; while ( 0 ) -#define OTV_EXIT do ; while ( 0 ) - -#define OTV_TRACE( s ) do ; while ( 0 ) - -#endif /* !FT_DEBUG_LEVEL_TRACE */ - - -#define OTV_RUN valid->func[0] - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** COVERAGE TABLE *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - FT_LOCAL( void ) - otv_Coverage_validate( FT_Bytes table, - OTV_Validator valid ); - - /* return first covered glyph */ - FT_LOCAL( FT_UInt ) - otv_Coverage_get_first( FT_Bytes table ); - - /* return last covered glyph */ - FT_LOCAL( FT_UInt ) - otv_Coverage_get_last( FT_Bytes table ); - - /* return number of covered glyphs */ - FT_LOCAL( FT_UInt ) - otv_Coverage_get_count( FT_Bytes table ); - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** CLASS DEFINITION TABLE *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - FT_LOCAL( void ) - otv_ClassDef_validate( FT_Bytes table, - OTV_Validator valid ); - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** DEVICE TABLE *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - FT_LOCAL( void ) - otv_Device_validate( FT_Bytes table, - OTV_Validator valid ); - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** LOOKUPS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - FT_LOCAL( void ) - otv_Lookup_validate( FT_Bytes table, - OTV_Validator valid ); - - FT_LOCAL( void ) - otv_LookupList_validate( FT_Bytes table, - OTV_Validator valid ); - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** FEATURES *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - FT_LOCAL( void ) - otv_Feature_validate( FT_Bytes table, - OTV_Validator valid ); - - /* lookups must already be validated */ - FT_LOCAL( void ) - otv_FeatureList_validate( FT_Bytes table, - FT_Bytes lookups, - OTV_Validator valid ); - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** LANGUAGE SYSTEM *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - FT_LOCAL( void ) - otv_LangSys_validate( FT_Bytes table, - OTV_Validator valid ); - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** SCRIPTS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - FT_LOCAL( void ) - otv_Script_validate( FT_Bytes table, - OTV_Validator valid ); - - /* features must already be validated */ - FT_LOCAL( void ) - otv_ScriptList_validate( FT_Bytes table, - FT_Bytes features, - OTV_Validator valid ); - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** UTILITY FUNCTIONS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - -#define ChainPosClassSet otv_x_Ox, "ChainPosClassSet" -#define ChainPosRuleSet otv_x_Ox, "ChainPosRuleSet" -#define ChainSubClassSet otv_x_Ox, "ChainSubClassSet" -#define ChainSubRuleSet otv_x_Ox, "ChainSubRuleSet" -#define JstfLangSys otv_x_Ox, "JstfLangSys" -#define JstfMax otv_x_Ox, "JstfMax" -#define LigGlyph otv_x_Ox, "LigGlyph" -#define LigatureArray otv_x_Ox, "LigatureArray" -#define LigatureSet otv_x_Ox, "LigatureSet" -#define PosClassSet otv_x_Ox, "PosClassSet" -#define PosRuleSet otv_x_Ox, "PosRuleSet" -#define SubClassSet otv_x_Ox, "SubClassSet" -#define SubRuleSet otv_x_Ox, "SubRuleSet" - - FT_LOCAL( void ) - otv_x_Ox ( FT_Bytes table, - OTV_Validator valid ); - -#define AlternateSubstFormat1 otv_u_C_x_Ox, "AlternateSubstFormat1" -#define ChainContextPosFormat1 otv_u_C_x_Ox, "ChainContextPosFormat1" -#define ChainContextSubstFormat1 otv_u_C_x_Ox, "ChainContextSubstFormat1" -#define ContextPosFormat1 otv_u_C_x_Ox, "ContextPosFormat1" -#define ContextSubstFormat1 otv_u_C_x_Ox, "ContextSubstFormat1" -#define LigatureSubstFormat1 otv_u_C_x_Ox, "LigatureSubstFormat1" -#define MultipleSubstFormat1 otv_u_C_x_Ox, "MultipleSubstFormat1" - - FT_LOCAL( void ) - otv_u_C_x_Ox( FT_Bytes table, - OTV_Validator valid ); - -#define AlternateSet otv_x_ux, "AlternateSet" -#define AttachPoint otv_x_ux, "AttachPoint" -#define ExtenderGlyph otv_x_ux, "ExtenderGlyph" -#define JstfGPOSModList otv_x_ux, "JstfGPOSModList" -#define JstfGSUBModList otv_x_ux, "JstfGSUBModList" -#define Sequence otv_x_ux, "Sequence" - - FT_LOCAL( void ) - otv_x_ux( FT_Bytes table, - OTV_Validator valid ); - -#define PosClassRule otv_x_y_ux_sy, "PosClassRule" -#define PosRule otv_x_y_ux_sy, "PosRule" -#define SubClassRule otv_x_y_ux_sy, "SubClassRule" -#define SubRule otv_x_y_ux_sy, "SubRule" - - FT_LOCAL( void ) - otv_x_y_ux_sy( FT_Bytes table, - OTV_Validator valid ); - -#define ChainPosClassRule otv_x_ux_y_uy_z_uz_p_sp, "ChainPosClassRule" -#define ChainPosRule otv_x_ux_y_uy_z_uz_p_sp, "ChainPosRule" -#define ChainSubClassRule otv_x_ux_y_uy_z_uz_p_sp, "ChainSubClassRule" -#define ChainSubRule otv_x_ux_y_uy_z_uz_p_sp, "ChainSubRule" - - FT_LOCAL( void ) - otv_x_ux_y_uy_z_uz_p_sp( FT_Bytes table, - OTV_Validator valid ); - -#define ContextPosFormat2 otv_u_O_O_x_Onx, "ContextPosFormat2" -#define ContextSubstFormat2 otv_u_O_O_x_Onx, "ContextSubstFormat2" - - FT_LOCAL( void ) - otv_u_O_O_x_Onx( FT_Bytes table, - OTV_Validator valid ); - -#define ContextPosFormat3 otv_u_x_y_Ox_sy, "ContextPosFormat3" -#define ContextSubstFormat3 otv_u_x_y_Ox_sy, "ContextSubstFormat3" - - FT_LOCAL( void ) - otv_u_x_y_Ox_sy( FT_Bytes table, - OTV_Validator valid ); - -#define ChainContextPosFormat2 otv_u_O_O_O_O_x_Onx, "ChainContextPosFormat2" -#define ChainContextSubstFormat2 otv_u_O_O_O_O_x_Onx, "ChainContextSubstFormat2" - - FT_LOCAL( void ) - otv_u_O_O_O_O_x_Onx( FT_Bytes table, - OTV_Validator valid ); - -#define ChainContextPosFormat3 otv_u_x_Ox_y_Oy_z_Oz_p_sp, "ChainContextPosFormat3" -#define ChainContextSubstFormat3 otv_u_x_Ox_y_Oy_z_Oz_p_sp, "ChainContextSubstFormat3" - - FT_LOCAL( void ) - otv_u_x_Ox_y_Oy_z_Oz_p_sp( FT_Bytes table, - OTV_Validator valid ); - - - FT_LOCAL( FT_UInt ) - otv_GSUBGPOS_get_Lookup_count( FT_Bytes table ); - - FT_LOCAL( FT_UInt ) - otv_GSUBGPOS_have_MarkAttachmentType_flag( FT_Bytes table ); - - /* */ - -FT_END_HEADER - -#endif /* __OTVCOMMN_H__ */ - - -/* END */ +/***************************************************************************/ +/* */ +/* otvcommn.h */ +/* */ +/* OpenType common tables validation (specification). */ +/* */ +/* Copyright 2004 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __OTVCOMMN_H__ +#define __OTVCOMMN_H__ + + +#include <ft2build.h> +#include "otvalid.h" +#include FT_INTERNAL_DEBUG_H + + +FT_BEGIN_HEADER + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** VALIDATION *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + typedef struct OTV_ValidatorRec_* OTV_Validator; + + typedef void (*OTV_Validate_Func)( FT_Bytes table, + OTV_Validator valid ); + + typedef struct OTV_ValidatorRec_ + { + FT_Validator root; + FT_UInt type_count; + OTV_Validate_Func* type_funcs; + + FT_UInt lookup_count; + FT_UInt glyph_count; + + FT_UInt nesting_level; + + OTV_Validate_Func func[3]; + + FT_UInt extra1; /* for passing parameters */ + FT_UInt extra2; + FT_Bytes extra3; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_UInt debug_indent; + const FT_String* debug_function_name[3]; +#endif + + } OTV_ValidatorRec; + + +#undef FT_INVALID_ +#define FT_INVALID_( _prefix, _error ) \ + ft_validator_error( valid->root, _prefix ## _error ) + +#define OTV_OPTIONAL_TABLE( _table ) FT_UInt _table; \ + FT_Bytes _table ## _p + +#define OTV_OPTIONAL_OFFSET( _offset ) \ + FT_BEGIN_STMNT \ + _offset ## _p = p; \ + _offset = FT_NEXT_USHORT( p ); \ + FT_END_STMNT + +#define OTV_LIMIT_CHECK( _count ) \ + FT_BEGIN_STMNT \ + if ( p + (_count) > valid->root->limit ) \ + FT_INVALID_TOO_SHORT; \ + FT_END_STMNT + +#define OTV_SIZE_CHECK( _size ) \ + FT_BEGIN_STMNT \ + if ( _size > 0 && _size < table_size ) \ + { \ + if ( valid->root->level == FT_VALIDATE_PARANOID ) \ + FT_INVALID_OFFSET; \ + else \ + { \ + /* strip off `const' */ \ + FT_Byte* pp = (FT_Byte*)_size ## _p; \ + \ + \ + FT_TRACE3(( "\n" \ + "Invalid offset to optional table `%s'!\n" \ + "Set to zero.\n" \ + "\n", #_size )); \ + \ + /* always assume 16bit entities */ \ + _size = pp[0] = pp[1] = 0; \ + } \ + } \ + FT_END_STMNT + + +#ifdef FT_DEBUG_LEVEL_TRACE + + /* use preprocessor's argument prescan to expand one argument into two */ +#define OTV_NEST1( x ) OTV_NEST1_( x ) +#define OTV_NEST1_( func0, name0 ) \ + FT_BEGIN_STMNT \ + valid->nesting_level = 0; \ + valid->func[0] = func0; \ + valid->debug_function_name[0] = name0; \ + FT_END_STMNT + + /* use preprocessor's argument prescan to expand two arguments into four */ +#define OTV_NEST2( x, y ) OTV_NEST2_( x, y ) +#define OTV_NEST2_( func0, name0, func1, name1 ) \ + FT_BEGIN_STMNT \ + valid->nesting_level = 0; \ + valid->func[0] = func0; \ + valid->func[1] = func1; \ + valid->debug_function_name[0] = name0; \ + valid->debug_function_name[1] = name1; \ + FT_END_STMNT + + /* use preprocessor's argument prescan to expand three arguments into six */ +#define OTV_NEST3( x, y, z ) OTV_NEST3_( x, y, z ) +#define OTV_NEST3_( func0, name0, func1, name1, func2, name2 ) \ + FT_BEGIN_STMNT \ + valid->nesting_level = 0; \ + valid->func[0] = func0; \ + valid->func[1] = func1; \ + valid->func[2] = func2; \ + valid->debug_function_name[0] = name0; \ + valid->debug_function_name[1] = name1; \ + valid->debug_function_name[2] = name2; \ + FT_END_STMNT + +#define OTV_INIT valid->debug_indent = 0 + +#define OTV_ENTER \ + FT_BEGIN_STMNT \ + valid->debug_indent += 2; \ + FT_TRACE4(( "%*.s", valid->debug_indent, 0 )); \ + FT_TRACE4(( "%s table\n", \ + valid->debug_function_name[valid->nesting_level] )); \ + FT_END_STMNT + +#define OTV_NAME_ENTER( name ) \ + FT_BEGIN_STMNT \ + valid->debug_indent += 2; \ + FT_TRACE4(( "%*.s", valid->debug_indent, 0 )); \ + FT_TRACE4(( "%s table\n", name )); \ + FT_END_STMNT + +#define OTV_EXIT valid->debug_indent -= 2 + +#define OTV_TRACE( s ) \ + FT_BEGIN_STMNT \ + FT_TRACE4(( "%*.s", valid->debug_indent, 0 )); \ + FT_TRACE4( s ); \ + FT_END_STMNT + +#else /* !FT_DEBUG_LEVEL_TRACE */ + + /* use preprocessor's argument prescan to expand one argument into two */ +#define OTV_NEST1( x ) OTV_NEST1_( x ) +#define OTV_NEST1_( func0, name0 ) \ + FT_BEGIN_STMNT \ + valid->nesting_level = 0; \ + valid->func[0] = func0; \ + FT_END_STMNT + + /* use preprocessor's argument prescan to expand two arguments into four */ +#define OTV_NEST2( x, y ) OTV_NEST2_( x, y ) +#define OTV_NEST2_( func0, name0, func1, name1 ) \ + FT_BEGIN_STMNT \ + valid->nesting_level = 0; \ + valid->func[0] = func0; \ + valid->func[1] = func1; \ + FT_END_STMNT + + /* use preprocessor's argument prescan to expand three arguments into six */ +#define OTV_NEST3( x, y, z ) OTV_NEST3_( x, y, z ) +#define OTV_NEST3_( func0, name0, func1, name1, func2, name2 ) \ + FT_BEGIN_STMNT \ + valid->nesting_level = 0; \ + valid->func[0] = func0; \ + valid->func[1] = func1; \ + valid->func[2] = func2; \ + FT_END_STMNT + +#define OTV_INIT do ; while ( 0 ) +#define OTV_ENTER do ; while ( 0 ) +#define OTV_NAME_ENTER( name ) do ; while ( 0 ) +#define OTV_EXIT do ; while ( 0 ) + +#define OTV_TRACE( s ) do ; while ( 0 ) + +#endif /* !FT_DEBUG_LEVEL_TRACE */ + + +#define OTV_RUN valid->func[0] + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** COVERAGE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_Coverage_validate( FT_Bytes table, + OTV_Validator valid ); + + /* return first covered glyph */ + FT_LOCAL( FT_UInt ) + otv_Coverage_get_first( FT_Bytes table ); + + /* return last covered glyph */ + FT_LOCAL( FT_UInt ) + otv_Coverage_get_last( FT_Bytes table ); + + /* return number of covered glyphs */ + FT_LOCAL( FT_UInt ) + otv_Coverage_get_count( FT_Bytes table ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** CLASS DEFINITION TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_ClassDef_validate( FT_Bytes table, + OTV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** DEVICE TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_Device_validate( FT_Bytes table, + OTV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LOOKUPS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_Lookup_validate( FT_Bytes table, + OTV_Validator valid ); + + FT_LOCAL( void ) + otv_LookupList_validate( FT_Bytes table, + OTV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FEATURES *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_Feature_validate( FT_Bytes table, + OTV_Validator valid ); + + /* lookups must already be validated */ + FT_LOCAL( void ) + otv_FeatureList_validate( FT_Bytes table, + FT_Bytes lookups, + OTV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LANGUAGE SYSTEM *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_LangSys_validate( FT_Bytes table, + OTV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** SCRIPTS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL( void ) + otv_Script_validate( FT_Bytes table, + OTV_Validator valid ); + + /* features must already be validated */ + FT_LOCAL( void ) + otv_ScriptList_validate( FT_Bytes table, + FT_Bytes features, + OTV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define ChainPosClassSet otv_x_Ox, "ChainPosClassSet" +#define ChainPosRuleSet otv_x_Ox, "ChainPosRuleSet" +#define ChainSubClassSet otv_x_Ox, "ChainSubClassSet" +#define ChainSubRuleSet otv_x_Ox, "ChainSubRuleSet" +#define JstfLangSys otv_x_Ox, "JstfLangSys" +#define JstfMax otv_x_Ox, "JstfMax" +#define LigGlyph otv_x_Ox, "LigGlyph" +#define LigatureArray otv_x_Ox, "LigatureArray" +#define LigatureSet otv_x_Ox, "LigatureSet" +#define PosClassSet otv_x_Ox, "PosClassSet" +#define PosRuleSet otv_x_Ox, "PosRuleSet" +#define SubClassSet otv_x_Ox, "SubClassSet" +#define SubRuleSet otv_x_Ox, "SubRuleSet" + + FT_LOCAL( void ) + otv_x_Ox ( FT_Bytes table, + OTV_Validator valid ); + +#define AlternateSubstFormat1 otv_u_C_x_Ox, "AlternateSubstFormat1" +#define ChainContextPosFormat1 otv_u_C_x_Ox, "ChainContextPosFormat1" +#define ChainContextSubstFormat1 otv_u_C_x_Ox, "ChainContextSubstFormat1" +#define ContextPosFormat1 otv_u_C_x_Ox, "ContextPosFormat1" +#define ContextSubstFormat1 otv_u_C_x_Ox, "ContextSubstFormat1" +#define LigatureSubstFormat1 otv_u_C_x_Ox, "LigatureSubstFormat1" +#define MultipleSubstFormat1 otv_u_C_x_Ox, "MultipleSubstFormat1" + + FT_LOCAL( void ) + otv_u_C_x_Ox( FT_Bytes table, + OTV_Validator valid ); + +#define AlternateSet otv_x_ux, "AlternateSet" +#define AttachPoint otv_x_ux, "AttachPoint" +#define ExtenderGlyph otv_x_ux, "ExtenderGlyph" +#define JstfGPOSModList otv_x_ux, "JstfGPOSModList" +#define JstfGSUBModList otv_x_ux, "JstfGSUBModList" +#define Sequence otv_x_ux, "Sequence" + + FT_LOCAL( void ) + otv_x_ux( FT_Bytes table, + OTV_Validator valid ); + +#define PosClassRule otv_x_y_ux_sy, "PosClassRule" +#define PosRule otv_x_y_ux_sy, "PosRule" +#define SubClassRule otv_x_y_ux_sy, "SubClassRule" +#define SubRule otv_x_y_ux_sy, "SubRule" + + FT_LOCAL( void ) + otv_x_y_ux_sy( FT_Bytes table, + OTV_Validator valid ); + +#define ChainPosClassRule otv_x_ux_y_uy_z_uz_p_sp, "ChainPosClassRule" +#define ChainPosRule otv_x_ux_y_uy_z_uz_p_sp, "ChainPosRule" +#define ChainSubClassRule otv_x_ux_y_uy_z_uz_p_sp, "ChainSubClassRule" +#define ChainSubRule otv_x_ux_y_uy_z_uz_p_sp, "ChainSubRule" + + FT_LOCAL( void ) + otv_x_ux_y_uy_z_uz_p_sp( FT_Bytes table, + OTV_Validator valid ); + +#define ContextPosFormat2 otv_u_O_O_x_Onx, "ContextPosFormat2" +#define ContextSubstFormat2 otv_u_O_O_x_Onx, "ContextSubstFormat2" + + FT_LOCAL( void ) + otv_u_O_O_x_Onx( FT_Bytes table, + OTV_Validator valid ); + +#define ContextPosFormat3 otv_u_x_y_Ox_sy, "ContextPosFormat3" +#define ContextSubstFormat3 otv_u_x_y_Ox_sy, "ContextSubstFormat3" + + FT_LOCAL( void ) + otv_u_x_y_Ox_sy( FT_Bytes table, + OTV_Validator valid ); + +#define ChainContextPosFormat2 otv_u_O_O_O_O_x_Onx, "ChainContextPosFormat2" +#define ChainContextSubstFormat2 otv_u_O_O_O_O_x_Onx, "ChainContextSubstFormat2" + + FT_LOCAL( void ) + otv_u_O_O_O_O_x_Onx( FT_Bytes table, + OTV_Validator valid ); + +#define ChainContextPosFormat3 otv_u_x_Ox_y_Oy_z_Oz_p_sp, "ChainContextPosFormat3" +#define ChainContextSubstFormat3 otv_u_x_Ox_y_Oy_z_Oz_p_sp, "ChainContextSubstFormat3" + + FT_LOCAL( void ) + otv_u_x_Ox_y_Oy_z_Oz_p_sp( FT_Bytes table, + OTV_Validator valid ); + + + FT_LOCAL( FT_UInt ) + otv_GSUBGPOS_get_Lookup_count( FT_Bytes table ); + + FT_LOCAL( FT_UInt ) + otv_GSUBGPOS_have_MarkAttachmentType_flag( FT_Bytes table ); + + /* */ + +FT_END_HEADER + +#endif /* __OTVCOMMN_H__ */ + + +/* END */ diff --git a/reactos/lib/freetype/src/otvalid/otverror.h b/reactos/lib/freetype/src/otvalid/otverror.h index cbf5ae12469..041b538368c 100644 --- a/reactos/lib/freetype/src/otvalid/otverror.h +++ b/reactos/lib/freetype/src/otvalid/otverror.h @@ -1,43 +1,43 @@ -/***************************************************************************/ -/* */ -/* otverror.h */ -/* */ -/* OpenType validation module error codes (specification only). */ -/* */ -/* Copyright 2004, 2005 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - - /*************************************************************************/ - /* */ - /* This file is used to define the OpenType validation module error */ - /* enumeration constants. */ - /* */ - /*************************************************************************/ - -#ifndef __OTVERROR_H__ -#define __OTVERROR_H__ - -#include FT_MODULE_ERRORS_H - -#undef __FTERRORS_H__ - -#define FT_ERR_PREFIX OTV_Err_ -#define FT_ERR_BASE FT_Mod_Err_OTvalid - -#define FT_KEEP_ERR_PREFIX - -#include FT_ERRORS_H - -#endif /* __OTVERROR_H__ */ - - -/* END */ +/***************************************************************************/ +/* */ +/* otverror.h */ +/* */ +/* OpenType validation module error codes (specification only). */ +/* */ +/* Copyright 2004, 2005 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /*************************************************************************/ + /* */ + /* This file is used to define the OpenType validation module error */ + /* enumeration constants. */ + /* */ + /*************************************************************************/ + +#ifndef __OTVERROR_H__ +#define __OTVERROR_H__ + +#include FT_MODULE_ERRORS_H + +#undef __FTERRORS_H__ + +#define FT_ERR_PREFIX OTV_Err_ +#define FT_ERR_BASE FT_Mod_Err_OTvalid + +#define FT_KEEP_ERR_PREFIX + +#include FT_ERRORS_H + +#endif /* __OTVERROR_H__ */ + + +/* END */ diff --git a/reactos/lib/freetype/src/otvalid/otvgdef.c b/reactos/lib/freetype/src/otvalid/otvgdef.c index 15966a31de0..e408c709add 100644 --- a/reactos/lib/freetype/src/otvalid/otvgdef.c +++ b/reactos/lib/freetype/src/otvalid/otvgdef.c @@ -1,219 +1,219 @@ -/***************************************************************************/ -/* */ -/* otvgdef.c */ -/* */ -/* OpenType GDEF table validation (body). */ -/* */ -/* Copyright 2004, 2005 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - -#include "otvalid.h" -#include "otvcommn.h" - - - /*************************************************************************/ - /* */ - /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ - /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ - /* messages during execution. */ - /* */ -#undef FT_COMPONENT -#define FT_COMPONENT trace_otvgdef - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** UTILITY FUNCTIONS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - -#define AttachList otv_O_x_Ox, "AttachList" -#define LigCaretList otv_O_x_Ox, "LigCaretList" - - /* sets valid->extra1 (0) */ - - static void - otv_O_x_Ox( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_Bytes Coverage; - FT_UInt GlyphCount; - OTV_Validate_Func func; - - - OTV_ENTER; - - OTV_LIMIT_CHECK( 4 ); - Coverage = table + FT_NEXT_USHORT( p ); - GlyphCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); - - otv_Coverage_validate( Coverage, valid ); - if ( GlyphCount != otv_Coverage_get_count( Coverage ) ) - FT_INVALID_DATA; - - OTV_LIMIT_CHECK( GlyphCount * 2 ); - - valid->nesting_level++; - func = valid->func[valid->nesting_level]; - valid->extra1 = 0; - - for ( ; GlyphCount > 0; GlyphCount-- ) - func( table + FT_NEXT_USHORT( p ), valid ); - - valid->nesting_level--; - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** LIGATURE CARETS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - -#define CaretValue otv_CaretValue_validate, "CaretValue" - - static void - otv_CaretValue_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt CaretValueFormat; - - - OTV_ENTER; - - OTV_LIMIT_CHECK( 4 ); - - CaretValueFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format = %d)\n", CaretValueFormat )); - - switch ( CaretValueFormat ) - { - case 1: /* CaretValueFormat1 */ - /* skip Coordinate, no test */ - break; - - case 2: /* CaretValueFormat2 */ - /* skip CaretValuePoint, no test */ - break; - - case 3: /* CaretValueFormat3 */ - p += 2; /* skip Coordinate */ - - OTV_LIMIT_CHECK( 2 ); - - /* DeviceTable */ - otv_Device_validate( table + FT_NEXT_USHORT( p ), valid ); - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GDEF TABLE *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - FT_LOCAL_DEF( void ) - otv_GDEF_validate( FT_Bytes table, - FT_Bytes gsub, - FT_Bytes gpos, - FT_Validator ftvalid ) - { - OTV_ValidatorRec validrec; - OTV_Validator valid = &validrec; - FT_Bytes p = table; - FT_UInt table_size; - FT_Bool need_MarkAttachClassDef; - - OTV_OPTIONAL_TABLE( GlyphClassDef ); - OTV_OPTIONAL_TABLE( AttachListOffset ); - OTV_OPTIONAL_TABLE( LigCaretListOffset ); - OTV_OPTIONAL_TABLE( MarkAttachClassDef ); - - - valid->root = ftvalid; - - FT_TRACE3(( "validating GDEF table\n" )); - OTV_INIT; - - OTV_LIMIT_CHECK( 12 ); - - if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ - FT_INVALID_FORMAT; - - /* MarkAttachClassDef has been added to the OpenType */ - /* specification without increasing GDEF's version, */ - /* so we use this ugly hack to find out whether the */ - /* table is needed actually. */ - - need_MarkAttachClassDef = FT_BOOL( - otv_GSUBGPOS_have_MarkAttachmentType_flag( gsub ) || - otv_GSUBGPOS_have_MarkAttachmentType_flag( gpos ) ); - - if ( need_MarkAttachClassDef ) - table_size = 12; /* OpenType >= 1.2 */ - else - table_size = 10; /* OpenType < 1.2 */ - - OTV_OPTIONAL_OFFSET( GlyphClassDef ); - OTV_SIZE_CHECK( GlyphClassDef ); - if ( GlyphClassDef ) - otv_ClassDef_validate( table + GlyphClassDef, valid ); - - OTV_OPTIONAL_OFFSET( AttachListOffset ); - OTV_SIZE_CHECK( AttachListOffset ); - if ( AttachListOffset ) - { - OTV_NEST2( AttachList, AttachPoint ); - OTV_RUN( table + AttachListOffset, valid ); - } - - OTV_OPTIONAL_OFFSET( LigCaretListOffset ); - OTV_SIZE_CHECK( LigCaretListOffset ); - if ( LigCaretListOffset ) - { - OTV_NEST3( LigCaretList, LigGlyph, CaretValue ); - OTV_RUN( table + LigCaretListOffset, valid ); - } - - if ( need_MarkAttachClassDef ) - { - OTV_OPTIONAL_OFFSET( MarkAttachClassDef ); - OTV_SIZE_CHECK( MarkAttachClassDef ); - if ( MarkAttachClassDef ) - otv_ClassDef_validate( table + MarkAttachClassDef, valid ); - } - - FT_TRACE4(( "\n" )); - } - - -/* END */ +/***************************************************************************/ +/* */ +/* otvgdef.c */ +/* */ +/* OpenType GDEF table validation (body). */ +/* */ +/* Copyright 2004, 2005 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include "otvalid.h" +#include "otvcommn.h" + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_otvgdef + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define AttachList otv_O_x_Ox, "AttachList" +#define LigCaretList otv_O_x_Ox, "LigCaretList" + + /* sets valid->extra1 (0) */ + + static void + otv_O_x_Ox( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_Bytes Coverage; + FT_UInt GlyphCount; + OTV_Validate_Func func; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 4 ); + Coverage = table + FT_NEXT_USHORT( p ); + GlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + + otv_Coverage_validate( Coverage, valid ); + if ( GlyphCount != otv_Coverage_get_count( Coverage ) ) + FT_INVALID_DATA; + + OTV_LIMIT_CHECK( GlyphCount * 2 ); + + valid->nesting_level++; + func = valid->func[valid->nesting_level]; + valid->extra1 = 0; + + for ( ; GlyphCount > 0; GlyphCount-- ) + func( table + FT_NEXT_USHORT( p ), valid ); + + valid->nesting_level--; + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** LIGATURE CARETS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define CaretValue otv_CaretValue_validate, "CaretValue" + + static void + otv_CaretValue_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt CaretValueFormat; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 4 ); + + CaretValueFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format = %d)\n", CaretValueFormat )); + + switch ( CaretValueFormat ) + { + case 1: /* CaretValueFormat1 */ + /* skip Coordinate, no test */ + break; + + case 2: /* CaretValueFormat2 */ + /* skip CaretValuePoint, no test */ + break; + + case 3: /* CaretValueFormat3 */ + p += 2; /* skip Coordinate */ + + OTV_LIMIT_CHECK( 2 ); + + /* DeviceTable */ + otv_Device_validate( table + FT_NEXT_USHORT( p ), valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GDEF TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + FT_LOCAL_DEF( void ) + otv_GDEF_validate( FT_Bytes table, + FT_Bytes gsub, + FT_Bytes gpos, + FT_Validator ftvalid ) + { + OTV_ValidatorRec validrec; + OTV_Validator valid = &validrec; + FT_Bytes p = table; + FT_UInt table_size; + FT_Bool need_MarkAttachClassDef; + + OTV_OPTIONAL_TABLE( GlyphClassDef ); + OTV_OPTIONAL_TABLE( AttachListOffset ); + OTV_OPTIONAL_TABLE( LigCaretListOffset ); + OTV_OPTIONAL_TABLE( MarkAttachClassDef ); + + + valid->root = ftvalid; + + FT_TRACE3(( "validating GDEF table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 12 ); + + if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ + FT_INVALID_FORMAT; + + /* MarkAttachClassDef has been added to the OpenType */ + /* specification without increasing GDEF's version, */ + /* so we use this ugly hack to find out whether the */ + /* table is needed actually. */ + + need_MarkAttachClassDef = FT_BOOL( + otv_GSUBGPOS_have_MarkAttachmentType_flag( gsub ) || + otv_GSUBGPOS_have_MarkAttachmentType_flag( gpos ) ); + + if ( need_MarkAttachClassDef ) + table_size = 12; /* OpenType >= 1.2 */ + else + table_size = 10; /* OpenType < 1.2 */ + + OTV_OPTIONAL_OFFSET( GlyphClassDef ); + OTV_SIZE_CHECK( GlyphClassDef ); + if ( GlyphClassDef ) + otv_ClassDef_validate( table + GlyphClassDef, valid ); + + OTV_OPTIONAL_OFFSET( AttachListOffset ); + OTV_SIZE_CHECK( AttachListOffset ); + if ( AttachListOffset ) + { + OTV_NEST2( AttachList, AttachPoint ); + OTV_RUN( table + AttachListOffset, valid ); + } + + OTV_OPTIONAL_OFFSET( LigCaretListOffset ); + OTV_SIZE_CHECK( LigCaretListOffset ); + if ( LigCaretListOffset ) + { + OTV_NEST3( LigCaretList, LigGlyph, CaretValue ); + OTV_RUN( table + LigCaretListOffset, valid ); + } + + if ( need_MarkAttachClassDef ) + { + OTV_OPTIONAL_OFFSET( MarkAttachClassDef ); + OTV_SIZE_CHECK( MarkAttachClassDef ); + if ( MarkAttachClassDef ) + otv_ClassDef_validate( table + MarkAttachClassDef, valid ); + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/reactos/lib/freetype/src/otvalid/otvgpos.c b/reactos/lib/freetype/src/otvalid/otvgpos.c index ed869b0dad2..ceffd2f8ef5 100644 --- a/reactos/lib/freetype/src/otvalid/otvgpos.c +++ b/reactos/lib/freetype/src/otvalid/otvgpos.c @@ -1,1013 +1,1013 @@ -/***************************************************************************/ -/* */ -/* otvgpos.c */ -/* */ -/* OpenType GPOS table validation (body). */ -/* */ -/* Copyright 2002, 2004, 2005 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - -#include "otvalid.h" -#include "otvcommn.h" -#include "otvgpos.h" - - - /*************************************************************************/ - /* */ - /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ - /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ - /* messages during execution. */ - /* */ -#undef FT_COMPONENT -#define FT_COMPONENT trace_otvgpos - - - static void - otv_Anchor_validate( FT_Bytes table, - OTV_Validator valid ); - - static void - otv_MarkArray_validate( FT_Bytes table, - OTV_Validator valid ); - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** UTILITY FUNCTIONS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - -#define BaseArray otv_x_sxy, "BaseArray" -#define LigatureAttach otv_x_sxy, "LigatureAttach" -#define Mark2Array otv_x_sxy, "Mark2Array" - - /* uses valid->extra1 (counter) */ - /* uses valid->extra2 (boolean to handle NULL anchor field) */ - - static void - otv_x_sxy( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt Count, count1, table_size; - - - OTV_ENTER; - - OTV_LIMIT_CHECK( 2 ); - - OTV_TRACE(( " (Count = %d)\n", Count )); - - Count = FT_NEXT_USHORT( p ); - - OTV_LIMIT_CHECK( Count * valid->extra1 * 2 ); - - table_size = Count * valid->extra1 * 2 + 2; - - for ( ; Count > 0; Count-- ) - for ( count1 = valid->extra1; count1 > 0; count1-- ) - { - OTV_OPTIONAL_TABLE( anchor_offset ); - - - OTV_OPTIONAL_OFFSET( anchor_offset ); - - if ( valid->extra2 ) - { - OTV_SIZE_CHECK( anchor_offset ); - if ( anchor_offset ) - otv_Anchor_validate( table + anchor_offset, valid ); - } - else - otv_Anchor_validate( table + anchor_offset, valid ); - } - - OTV_EXIT; - } - - -#define MarkBasePosFormat1 otv_u_O_O_u_O_O, "MarkBasePosFormat1" -#define MarkLigPosFormat1 otv_u_O_O_u_O_O, "MarkLigPosFormat1" -#define MarkMarkPosFormat1 otv_u_O_O_u_O_O, "MarkMarkPosFormat1" - - /* sets valid->extra1 (class count) */ - - static void - otv_u_O_O_u_O_O( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt Coverage1, Coverage2, ClassCount; - FT_UInt Array1, Array2; - OTV_Validate_Func func; - - - OTV_ENTER; - - p += 2; /* skip PosFormat */ - - OTV_LIMIT_CHECK( 10 ); - Coverage1 = FT_NEXT_USHORT( p ); - Coverage2 = FT_NEXT_USHORT( p ); - ClassCount = FT_NEXT_USHORT( p ); - Array1 = FT_NEXT_USHORT( p ); - Array2 = FT_NEXT_USHORT( p ); - - otv_Coverage_validate( table + Coverage1, valid ); - otv_Coverage_validate( table + Coverage2, valid ); - - otv_MarkArray_validate( table + Array1, valid ); - - valid->nesting_level++; - func = valid->func[valid->nesting_level]; - valid->extra1 = ClassCount; - - func( table + Array2, valid ); - - valid->nesting_level--; - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** VALUE RECORDS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - static FT_UInt - otv_value_length( FT_UInt format ) - { - FT_UInt count; - - - count = ( ( format & 0xAA ) >> 1 ) + ( format & 0x55 ); - count = ( ( count & 0xCC ) >> 2 ) + ( count & 0x33 ); - count = ( ( count & 0xF0 ) >> 4 ) + ( count & 0x0F ); - - return count * 2; - } - - - /* uses valid->extra3 (pointer to base table) */ - - static void - otv_ValueRecord_validate( FT_Bytes table, - FT_UInt format, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt count; - -#ifdef FT_DEBUG_LEVEL_TRACE - FT_Int loop; - FT_ULong res = 0; - - - OTV_NAME_ENTER( "ValueRecord" ); - - /* display `format' in dual representation */ - for ( loop = 7; loop >= 0; loop-- ) - { - res <<= 4; - res += ( format >> loop ) & 1; - } - - OTV_TRACE(( " (format 0b%08lx)\n", res )); -#endif - - if ( format >= 0x100 ) - FT_INVALID_DATA; - - for ( count = 4; count > 0; count-- ) - { - if ( format & 1 ) - { - /* XPlacement, YPlacement, XAdvance, YAdvance */ - OTV_LIMIT_CHECK( 2 ); - p += 2; - } - - format >>= 1; - } - - for ( count = 4; count > 0; count-- ) - { - if ( format & 1 ) - { - FT_UInt table_size; - - OTV_OPTIONAL_TABLE( device ); - - - /* XPlaDevice, YPlaDevice, XAdvDevice, YAdvDevice */ - OTV_LIMIT_CHECK( 2 ); - OTV_OPTIONAL_OFFSET( device ); - - /* XXX: this value is usually too small, especially if the current */ - /* ValueRecord is part of an array -- getting the correct table */ - /* size is probably not worth the trouble */ - - table_size = p - valid->extra3; - - OTV_SIZE_CHECK( device ); - if ( device ) - otv_Device_validate( valid->extra3 + device, valid ); - } - format >>= 1; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** ANCHORS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - static void - otv_Anchor_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt AnchorFormat; - - - OTV_NAME_ENTER( "Anchor"); - - OTV_LIMIT_CHECK( 6 ); - AnchorFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", AnchorFormat )); - - p += 4; /* skip XCoordinate and YCoordinate */ - - switch ( AnchorFormat ) - { - case 1: - break; - - case 2: - OTV_LIMIT_CHECK( 2 ); /* AnchorPoint */ - break; - - case 3: - { - FT_UInt table_size; - - OTV_OPTIONAL_TABLE( XDeviceTable ); - OTV_OPTIONAL_TABLE( YDeviceTable ); - - - OTV_LIMIT_CHECK( 4 ); - OTV_OPTIONAL_OFFSET( XDeviceTable ); - OTV_OPTIONAL_OFFSET( YDeviceTable ); - - table_size = 6 + 4; - - OTV_SIZE_CHECK( XDeviceTable ); - if ( XDeviceTable ) - otv_Device_validate( table + XDeviceTable, valid ); - - OTV_SIZE_CHECK( YDeviceTable ); - if ( YDeviceTable ) - otv_Device_validate( table + YDeviceTable, valid ); - } - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** MARK ARRAYS *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - static void - otv_MarkArray_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt MarkCount; - - - OTV_NAME_ENTER( "MarkArray" ); - - OTV_LIMIT_CHECK( 2 ); - MarkCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (MarkCount = %d)\n", MarkCount )); - - OTV_LIMIT_CHECK( MarkCount * 4 ); - - /* MarkRecord */ - for ( ; MarkCount > 0; MarkCount-- ) - { - p += 2; /* skip Class */ - /* MarkAnchor */ - otv_Anchor_validate( table + FT_NEXT_USHORT( p ), valid ); - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GPOS LOOKUP TYPE 1 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* sets valid->extra3 (pointer to base table) */ - - static void - otv_SinglePos_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt PosFormat; - - - OTV_NAME_ENTER( "SinglePos" ); - - OTV_LIMIT_CHECK( 2 ); - PosFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", PosFormat )); - - valid->extra3 = table; - - switch ( PosFormat ) - { - case 1: /* SinglePosFormat1 */ - { - FT_UInt Coverage, ValueFormat; - - - OTV_LIMIT_CHECK( 4 ); - Coverage = FT_NEXT_USHORT( p ); - ValueFormat = FT_NEXT_USHORT( p ); - - otv_Coverage_validate( table + Coverage, valid ); - otv_ValueRecord_validate( p, ValueFormat, valid ); /* Value */ - } - break; - - case 2: /* SinglePosFormat2 */ - { - FT_UInt Coverage, ValueFormat, ValueCount, len_value; - - - OTV_LIMIT_CHECK( 6 ); - Coverage = FT_NEXT_USHORT( p ); - ValueFormat = FT_NEXT_USHORT( p ); - ValueCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (ValueCount = %d)\n", ValueCount )); - - len_value = otv_value_length( ValueFormat ); - - otv_Coverage_validate( table + Coverage, valid ); - - OTV_LIMIT_CHECK( ValueCount * len_value ); - - /* Value */ - for ( ; ValueCount > 0; ValueCount-- ) - { - otv_ValueRecord_validate( p, ValueFormat, valid ); - p += len_value; - } - } - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GPOS LOOKUP TYPE 2 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - static void - otv_PairSet_validate( FT_Bytes table, - FT_UInt format1, - FT_UInt format2, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt value_len1, value_len2, PairValueCount; - - - OTV_NAME_ENTER( "PairSet" ); - - OTV_LIMIT_CHECK( 2 ); - PairValueCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (PairValueCount = %d)\n", PairValueCount )); - - value_len1 = otv_value_length( format1 ); - value_len2 = otv_value_length( format2 ); - - OTV_LIMIT_CHECK( PairValueCount * ( value_len1 + value_len2 + 2 ) ); - - /* PairValueRecord */ - for ( ; PairValueCount > 0; PairValueCount-- ) - { - p += 2; /* skip SecondGlyph */ - - if ( format1 ) - otv_ValueRecord_validate( p, format1, valid ); /* Value1 */ - p += value_len1; - - if ( format2 ) - otv_ValueRecord_validate( p, format2, valid ); /* Value2 */ - p += value_len2; - } - - OTV_EXIT; - } - - - /* sets valid->extra3 (pointer to base table) */ - - static void - otv_PairPos_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt PosFormat; - - - OTV_NAME_ENTER( "PairPos" ); - - OTV_LIMIT_CHECK( 2 ); - PosFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", PosFormat )); - - valid->extra3 = table; - - switch ( PosFormat ) - { - case 1: /* PairPosFormat1 */ - { - FT_UInt Coverage, ValueFormat1, ValueFormat2, PairSetCount; - - - OTV_LIMIT_CHECK( 8 ); - Coverage = FT_NEXT_USHORT( p ); - ValueFormat1 = FT_NEXT_USHORT( p ); - ValueFormat2 = FT_NEXT_USHORT( p ); - PairSetCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (PairSetCount = %d)\n", PairSetCount )); - - otv_Coverage_validate( table + Coverage, valid ); - - OTV_LIMIT_CHECK( PairSetCount * 2 ); - - /* PairSetOffset */ - for ( ; PairSetCount > 0; PairSetCount-- ) - otv_PairSet_validate( table + FT_NEXT_USHORT( p ), - ValueFormat1, ValueFormat2, valid ); - } - break; - - case 2: /* PairPosFormat2 */ - { - FT_UInt Coverage, ValueFormat1, ValueFormat2, ClassDef1, ClassDef2; - FT_UInt ClassCount1, ClassCount2, len_value1, len_value2, count; - - - OTV_LIMIT_CHECK( 14 ); - Coverage = FT_NEXT_USHORT( p ); - ValueFormat1 = FT_NEXT_USHORT( p ); - ValueFormat2 = FT_NEXT_USHORT( p ); - ClassDef1 = FT_NEXT_USHORT( p ); - ClassDef2 = FT_NEXT_USHORT( p ); - ClassCount1 = FT_NEXT_USHORT( p ); - ClassCount2 = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (ClassCount1 = %d)\n", ClassCount1 )); - OTV_TRACE(( " (ClassCount2 = %d)\n", ClassCount2 )); - - len_value1 = otv_value_length( ValueFormat1 ); - len_value2 = otv_value_length( ValueFormat2 ); - - otv_Coverage_validate( table + Coverage, valid ); - otv_ClassDef_validate( table + ClassDef1, valid ); - otv_ClassDef_validate( table + ClassDef2, valid ); - - OTV_LIMIT_CHECK( ClassCount1 * ClassCount2 * - ( len_value1 + len_value2 ) ); - - /* Class1Record */ - for ( ; ClassCount1 > 0; ClassCount1-- ) - { - /* Class2Record */ - for ( count = ClassCount2; count > 0; count-- ) - { - if ( ValueFormat1 ) - /* Value1 */ - otv_ValueRecord_validate( p, ValueFormat1, valid ); - p += len_value1; - - if ( ValueFormat2 ) - /* Value2 */ - otv_ValueRecord_validate( p, ValueFormat2, valid ); - p += len_value2; - } - } - } - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GPOS LOOKUP TYPE 3 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - static void - otv_CursivePos_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt PosFormat; - - - OTV_NAME_ENTER( "CursivePos" ); - - OTV_LIMIT_CHECK( 2 ); - PosFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", PosFormat )); - - switch ( PosFormat ) - { - case 1: /* CursivePosFormat1 */ - { - FT_UInt table_size; - FT_UInt Coverage, EntryExitCount; - - OTV_OPTIONAL_TABLE( EntryAnchor ); - OTV_OPTIONAL_TABLE( ExitAnchor ); - - - OTV_LIMIT_CHECK( 4 ); - Coverage = FT_NEXT_USHORT( p ); - EntryExitCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (EntryExitCount = %d)\n", EntryExitCount )); - - otv_Coverage_validate( table + Coverage, valid ); - - OTV_LIMIT_CHECK( EntryExitCount * 4 ); - - table_size = EntryExitCount * 4 + 4; - - /* EntryExitRecord */ - for ( ; EntryExitCount > 0; EntryExitCount-- ) - { - OTV_OPTIONAL_OFFSET( EntryAnchor ); - OTV_OPTIONAL_OFFSET( ExitAnchor ); - - OTV_SIZE_CHECK( EntryAnchor ); - if ( EntryAnchor ) - otv_Anchor_validate( table + EntryAnchor, valid ); - - OTV_SIZE_CHECK( ExitAnchor ); - if ( ExitAnchor ) - otv_Anchor_validate( table + ExitAnchor, valid ); - } - } - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GPOS LOOKUP TYPE 4 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* sets valid->extra2 (0) */ - - static void - otv_MarkBasePos_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt PosFormat; - - - OTV_NAME_ENTER( "MarkBasePos" ); - - OTV_LIMIT_CHECK( 2 ); - PosFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", PosFormat )); - - switch ( PosFormat ) - { - case 1: - valid->extra2 = 0; - OTV_NEST2( MarkBasePosFormat1, BaseArray ); - OTV_RUN( table, valid ); - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GPOS LOOKUP TYPE 5 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* sets valid->extra2 (1) */ - - static void - otv_MarkLigPos_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt PosFormat; - - - OTV_NAME_ENTER( "MarkLigPos" ); - - OTV_LIMIT_CHECK( 2 ); - PosFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", PosFormat )); - - switch ( PosFormat ) - { - case 1: - valid->extra2 = 1; - OTV_NEST3( MarkLigPosFormat1, LigatureArray, LigatureAttach ); - OTV_RUN( table, valid ); - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GPOS LOOKUP TYPE 6 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* sets valid->extra2 (0) */ - - static void - otv_MarkMarkPos_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt PosFormat; - - - OTV_NAME_ENTER( "MarkMarkPos" ); - - OTV_LIMIT_CHECK( 2 ); - PosFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", PosFormat )); - - switch ( PosFormat ) - { - case 1: - valid->extra2 = 0; - OTV_NEST2( MarkMarkPosFormat1, Mark2Array ); - OTV_RUN( table, valid ); - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GPOS LOOKUP TYPE 7 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* sets valid->extra1 (lookup count) */ - - static void - otv_ContextPos_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt PosFormat; - - - OTV_NAME_ENTER( "ContextPos" ); - - OTV_LIMIT_CHECK( 2 ); - PosFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", PosFormat )); - - switch ( PosFormat ) - { - case 1: - /* no need to check glyph indices/classes used as input for these */ - /* context rules since even invalid glyph indices/classes return */ - /* meaningful results */ - - valid->extra1 = valid->lookup_count; - OTV_NEST3( ContextPosFormat1, PosRuleSet, PosRule ); - OTV_RUN( table, valid ); - break; - - case 2: - /* no need to check glyph indices/classes used as input for these */ - /* context rules since even invalid glyph indices/classes return */ - /* meaningful results */ - - OTV_NEST3( ContextPosFormat2, PosClassSet, PosClassRule ); - OTV_RUN( table, valid ); - break; - - case 3: - OTV_NEST1( ContextPosFormat3 ); - OTV_RUN( table, valid ); - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GPOS LOOKUP TYPE 8 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* sets valid->extra1 (lookup count) */ - - static void - otv_ChainContextPos_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt PosFormat; - - - OTV_NAME_ENTER( "ChainContextPos" ); - - OTV_LIMIT_CHECK( 2 ); - PosFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", PosFormat )); - - switch ( PosFormat ) - { - case 1: - /* no need to check glyph indices/classes used as input for these */ - /* context rules since even invalid glyph indices/classes return */ - /* meaningful results */ - - valid->extra1 = valid->lookup_count; - OTV_NEST3( ChainContextPosFormat1, - ChainPosRuleSet, ChainPosRule ); - OTV_RUN( table, valid ); - break; - - case 2: - /* no need to check glyph indices/classes used as input for these */ - /* context rules since even invalid glyph indices/classes return */ - /* meaningful results */ - - OTV_NEST3( ChainContextPosFormat2, - ChainPosClassSet, ChainPosClassRule ); - OTV_RUN( table, valid ); - break; - - case 3: - OTV_NEST1( ChainContextPosFormat3 ); - OTV_RUN( table, valid ); - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GPOS LOOKUP TYPE 9 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* uses valid->type_funcs */ - - static void - otv_ExtensionPos_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt PosFormat; - - - OTV_NAME_ENTER( "ExtensionPos" ); - - OTV_LIMIT_CHECK( 2 ); - PosFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", PosFormat )); - - switch ( PosFormat ) - { - case 1: /* ExtensionPosFormat1 */ - { - FT_UInt ExtensionLookupType, ExtensionOffset; - OTV_Validate_Func validate; - - - OTV_LIMIT_CHECK( 6 ); - ExtensionLookupType = FT_NEXT_USHORT( p ); - ExtensionOffset = FT_NEXT_ULONG( p ); - - if ( ExtensionLookupType == 0 || ExtensionLookupType >= 9 ) - FT_INVALID_DATA; - - validate = valid->type_funcs[ExtensionLookupType - 1]; - validate( table + ExtensionOffset, valid ); - } - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - static const OTV_Validate_Func otv_gpos_validate_funcs[9] = - { - otv_SinglePos_validate, - otv_PairPos_validate, - otv_CursivePos_validate, - otv_MarkBasePos_validate, - otv_MarkLigPos_validate, - otv_MarkMarkPos_validate, - otv_ContextPos_validate, - otv_ChainContextPos_validate, - otv_ExtensionPos_validate - }; - - - /* sets valid->type_count */ - /* sets valid->type_funcs */ - - FT_LOCAL_DEF( void ) - otv_GPOS_subtable_validate( FT_Bytes table, - OTV_Validator valid ) - { - valid->type_count = 9; - valid->type_funcs = (OTV_Validate_Func*)otv_gpos_validate_funcs; - - otv_Lookup_validate( table, valid ); - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GPOS TABLE *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* sets valid->glyph_count */ - - FT_LOCAL_DEF( void ) - otv_GPOS_validate( FT_Bytes table, - FT_UInt glyph_count, - FT_Validator ftvalid ) - { - OTV_ValidatorRec validrec; - OTV_Validator valid = &validrec; - FT_Bytes p = table; - FT_UInt ScriptList, FeatureList, LookupList; - - - valid->root = ftvalid; - - FT_TRACE3(( "validating GPOS table\n" )); - OTV_INIT; - - OTV_LIMIT_CHECK( 10 ); - - if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ - FT_INVALID_DATA; - - ScriptList = FT_NEXT_USHORT( p ); - FeatureList = FT_NEXT_USHORT( p ); - LookupList = FT_NEXT_USHORT( p ); - - valid->type_count = 9; - valid->type_funcs = (OTV_Validate_Func*)otv_gpos_validate_funcs; - valid->glyph_count = glyph_count; - - otv_LookupList_validate( table + LookupList, - valid ); - otv_FeatureList_validate( table + FeatureList, table + LookupList, - valid ); - otv_ScriptList_validate( table + ScriptList, table + FeatureList, - valid ); - - FT_TRACE4(( "\n" )); - } - - -/* END */ +/***************************************************************************/ +/* */ +/* otvgpos.c */ +/* */ +/* OpenType GPOS table validation (body). */ +/* */ +/* Copyright 2002, 2004, 2005 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include "otvalid.h" +#include "otvcommn.h" +#include "otvgpos.h" + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_otvgpos + + + static void + otv_Anchor_validate( FT_Bytes table, + OTV_Validator valid ); + + static void + otv_MarkArray_validate( FT_Bytes table, + OTV_Validator valid ); + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** UTILITY FUNCTIONS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define BaseArray otv_x_sxy, "BaseArray" +#define LigatureAttach otv_x_sxy, "LigatureAttach" +#define Mark2Array otv_x_sxy, "Mark2Array" + + /* uses valid->extra1 (counter) */ + /* uses valid->extra2 (boolean to handle NULL anchor field) */ + + static void + otv_x_sxy( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt Count, count1, table_size; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 2 ); + + OTV_TRACE(( " (Count = %d)\n", Count )); + + Count = FT_NEXT_USHORT( p ); + + OTV_LIMIT_CHECK( Count * valid->extra1 * 2 ); + + table_size = Count * valid->extra1 * 2 + 2; + + for ( ; Count > 0; Count-- ) + for ( count1 = valid->extra1; count1 > 0; count1-- ) + { + OTV_OPTIONAL_TABLE( anchor_offset ); + + + OTV_OPTIONAL_OFFSET( anchor_offset ); + + if ( valid->extra2 ) + { + OTV_SIZE_CHECK( anchor_offset ); + if ( anchor_offset ) + otv_Anchor_validate( table + anchor_offset, valid ); + } + else + otv_Anchor_validate( table + anchor_offset, valid ); + } + + OTV_EXIT; + } + + +#define MarkBasePosFormat1 otv_u_O_O_u_O_O, "MarkBasePosFormat1" +#define MarkLigPosFormat1 otv_u_O_O_u_O_O, "MarkLigPosFormat1" +#define MarkMarkPosFormat1 otv_u_O_O_u_O_O, "MarkMarkPosFormat1" + + /* sets valid->extra1 (class count) */ + + static void + otv_u_O_O_u_O_O( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt Coverage1, Coverage2, ClassCount; + FT_UInt Array1, Array2; + OTV_Validate_Func func; + + + OTV_ENTER; + + p += 2; /* skip PosFormat */ + + OTV_LIMIT_CHECK( 10 ); + Coverage1 = FT_NEXT_USHORT( p ); + Coverage2 = FT_NEXT_USHORT( p ); + ClassCount = FT_NEXT_USHORT( p ); + Array1 = FT_NEXT_USHORT( p ); + Array2 = FT_NEXT_USHORT( p ); + + otv_Coverage_validate( table + Coverage1, valid ); + otv_Coverage_validate( table + Coverage2, valid ); + + otv_MarkArray_validate( table + Array1, valid ); + + valid->nesting_level++; + func = valid->func[valid->nesting_level]; + valid->extra1 = ClassCount; + + func( table + Array2, valid ); + + valid->nesting_level--; + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** VALUE RECORDS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static FT_UInt + otv_value_length( FT_UInt format ) + { + FT_UInt count; + + + count = ( ( format & 0xAA ) >> 1 ) + ( format & 0x55 ); + count = ( ( count & 0xCC ) >> 2 ) + ( count & 0x33 ); + count = ( ( count & 0xF0 ) >> 4 ) + ( count & 0x0F ); + + return count * 2; + } + + + /* uses valid->extra3 (pointer to base table) */ + + static void + otv_ValueRecord_validate( FT_Bytes table, + FT_UInt format, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt count; + +#ifdef FT_DEBUG_LEVEL_TRACE + FT_Int loop; + FT_ULong res = 0; + + + OTV_NAME_ENTER( "ValueRecord" ); + + /* display `format' in dual representation */ + for ( loop = 7; loop >= 0; loop-- ) + { + res <<= 4; + res += ( format >> loop ) & 1; + } + + OTV_TRACE(( " (format 0b%08lx)\n", res )); +#endif + + if ( format >= 0x100 ) + FT_INVALID_DATA; + + for ( count = 4; count > 0; count-- ) + { + if ( format & 1 ) + { + /* XPlacement, YPlacement, XAdvance, YAdvance */ + OTV_LIMIT_CHECK( 2 ); + p += 2; + } + + format >>= 1; + } + + for ( count = 4; count > 0; count-- ) + { + if ( format & 1 ) + { + FT_UInt table_size; + + OTV_OPTIONAL_TABLE( device ); + + + /* XPlaDevice, YPlaDevice, XAdvDevice, YAdvDevice */ + OTV_LIMIT_CHECK( 2 ); + OTV_OPTIONAL_OFFSET( device ); + + /* XXX: this value is usually too small, especially if the current */ + /* ValueRecord is part of an array -- getting the correct table */ + /* size is probably not worth the trouble */ + + table_size = p - valid->extra3; + + OTV_SIZE_CHECK( device ); + if ( device ) + otv_Device_validate( valid->extra3 + device, valid ); + } + format >>= 1; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** ANCHORS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_Anchor_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt AnchorFormat; + + + OTV_NAME_ENTER( "Anchor"); + + OTV_LIMIT_CHECK( 6 ); + AnchorFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", AnchorFormat )); + + p += 4; /* skip XCoordinate and YCoordinate */ + + switch ( AnchorFormat ) + { + case 1: + break; + + case 2: + OTV_LIMIT_CHECK( 2 ); /* AnchorPoint */ + break; + + case 3: + { + FT_UInt table_size; + + OTV_OPTIONAL_TABLE( XDeviceTable ); + OTV_OPTIONAL_TABLE( YDeviceTable ); + + + OTV_LIMIT_CHECK( 4 ); + OTV_OPTIONAL_OFFSET( XDeviceTable ); + OTV_OPTIONAL_OFFSET( YDeviceTable ); + + table_size = 6 + 4; + + OTV_SIZE_CHECK( XDeviceTable ); + if ( XDeviceTable ) + otv_Device_validate( table + XDeviceTable, valid ); + + OTV_SIZE_CHECK( YDeviceTable ); + if ( YDeviceTable ) + otv_Device_validate( table + YDeviceTable, valid ); + } + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** MARK ARRAYS *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_MarkArray_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt MarkCount; + + + OTV_NAME_ENTER( "MarkArray" ); + + OTV_LIMIT_CHECK( 2 ); + MarkCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (MarkCount = %d)\n", MarkCount )); + + OTV_LIMIT_CHECK( MarkCount * 4 ); + + /* MarkRecord */ + for ( ; MarkCount > 0; MarkCount-- ) + { + p += 2; /* skip Class */ + /* MarkAnchor */ + otv_Anchor_validate( table + FT_NEXT_USHORT( p ), valid ); + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 1 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra3 (pointer to base table) */ + + static void + otv_SinglePos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "SinglePos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + valid->extra3 = table; + + switch ( PosFormat ) + { + case 1: /* SinglePosFormat1 */ + { + FT_UInt Coverage, ValueFormat; + + + OTV_LIMIT_CHECK( 4 ); + Coverage = FT_NEXT_USHORT( p ); + ValueFormat = FT_NEXT_USHORT( p ); + + otv_Coverage_validate( table + Coverage, valid ); + otv_ValueRecord_validate( p, ValueFormat, valid ); /* Value */ + } + break; + + case 2: /* SinglePosFormat2 */ + { + FT_UInt Coverage, ValueFormat, ValueCount, len_value; + + + OTV_LIMIT_CHECK( 6 ); + Coverage = FT_NEXT_USHORT( p ); + ValueFormat = FT_NEXT_USHORT( p ); + ValueCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ValueCount = %d)\n", ValueCount )); + + len_value = otv_value_length( ValueFormat ); + + otv_Coverage_validate( table + Coverage, valid ); + + OTV_LIMIT_CHECK( ValueCount * len_value ); + + /* Value */ + for ( ; ValueCount > 0; ValueCount-- ) + { + otv_ValueRecord_validate( p, ValueFormat, valid ); + p += len_value; + } + } + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 2 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_PairSet_validate( FT_Bytes table, + FT_UInt format1, + FT_UInt format2, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt value_len1, value_len2, PairValueCount; + + + OTV_NAME_ENTER( "PairSet" ); + + OTV_LIMIT_CHECK( 2 ); + PairValueCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (PairValueCount = %d)\n", PairValueCount )); + + value_len1 = otv_value_length( format1 ); + value_len2 = otv_value_length( format2 ); + + OTV_LIMIT_CHECK( PairValueCount * ( value_len1 + value_len2 + 2 ) ); + + /* PairValueRecord */ + for ( ; PairValueCount > 0; PairValueCount-- ) + { + p += 2; /* skip SecondGlyph */ + + if ( format1 ) + otv_ValueRecord_validate( p, format1, valid ); /* Value1 */ + p += value_len1; + + if ( format2 ) + otv_ValueRecord_validate( p, format2, valid ); /* Value2 */ + p += value_len2; + } + + OTV_EXIT; + } + + + /* sets valid->extra3 (pointer to base table) */ + + static void + otv_PairPos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "PairPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + valid->extra3 = table; + + switch ( PosFormat ) + { + case 1: /* PairPosFormat1 */ + { + FT_UInt Coverage, ValueFormat1, ValueFormat2, PairSetCount; + + + OTV_LIMIT_CHECK( 8 ); + Coverage = FT_NEXT_USHORT( p ); + ValueFormat1 = FT_NEXT_USHORT( p ); + ValueFormat2 = FT_NEXT_USHORT( p ); + PairSetCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (PairSetCount = %d)\n", PairSetCount )); + + otv_Coverage_validate( table + Coverage, valid ); + + OTV_LIMIT_CHECK( PairSetCount * 2 ); + + /* PairSetOffset */ + for ( ; PairSetCount > 0; PairSetCount-- ) + otv_PairSet_validate( table + FT_NEXT_USHORT( p ), + ValueFormat1, ValueFormat2, valid ); + } + break; + + case 2: /* PairPosFormat2 */ + { + FT_UInt Coverage, ValueFormat1, ValueFormat2, ClassDef1, ClassDef2; + FT_UInt ClassCount1, ClassCount2, len_value1, len_value2, count; + + + OTV_LIMIT_CHECK( 14 ); + Coverage = FT_NEXT_USHORT( p ); + ValueFormat1 = FT_NEXT_USHORT( p ); + ValueFormat2 = FT_NEXT_USHORT( p ); + ClassDef1 = FT_NEXT_USHORT( p ); + ClassDef2 = FT_NEXT_USHORT( p ); + ClassCount1 = FT_NEXT_USHORT( p ); + ClassCount2 = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (ClassCount1 = %d)\n", ClassCount1 )); + OTV_TRACE(( " (ClassCount2 = %d)\n", ClassCount2 )); + + len_value1 = otv_value_length( ValueFormat1 ); + len_value2 = otv_value_length( ValueFormat2 ); + + otv_Coverage_validate( table + Coverage, valid ); + otv_ClassDef_validate( table + ClassDef1, valid ); + otv_ClassDef_validate( table + ClassDef2, valid ); + + OTV_LIMIT_CHECK( ClassCount1 * ClassCount2 * + ( len_value1 + len_value2 ) ); + + /* Class1Record */ + for ( ; ClassCount1 > 0; ClassCount1-- ) + { + /* Class2Record */ + for ( count = ClassCount2; count > 0; count-- ) + { + if ( ValueFormat1 ) + /* Value1 */ + otv_ValueRecord_validate( p, ValueFormat1, valid ); + p += len_value1; + + if ( ValueFormat2 ) + /* Value2 */ + otv_ValueRecord_validate( p, ValueFormat2, valid ); + p += len_value2; + } + } + } + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 3 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + static void + otv_CursivePos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "CursivePos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: /* CursivePosFormat1 */ + { + FT_UInt table_size; + FT_UInt Coverage, EntryExitCount; + + OTV_OPTIONAL_TABLE( EntryAnchor ); + OTV_OPTIONAL_TABLE( ExitAnchor ); + + + OTV_LIMIT_CHECK( 4 ); + Coverage = FT_NEXT_USHORT( p ); + EntryExitCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (EntryExitCount = %d)\n", EntryExitCount )); + + otv_Coverage_validate( table + Coverage, valid ); + + OTV_LIMIT_CHECK( EntryExitCount * 4 ); + + table_size = EntryExitCount * 4 + 4; + + /* EntryExitRecord */ + for ( ; EntryExitCount > 0; EntryExitCount-- ) + { + OTV_OPTIONAL_OFFSET( EntryAnchor ); + OTV_OPTIONAL_OFFSET( ExitAnchor ); + + OTV_SIZE_CHECK( EntryAnchor ); + if ( EntryAnchor ) + otv_Anchor_validate( table + EntryAnchor, valid ); + + OTV_SIZE_CHECK( ExitAnchor ); + if ( ExitAnchor ) + otv_Anchor_validate( table + ExitAnchor, valid ); + } + } + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 4 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra2 (0) */ + + static void + otv_MarkBasePos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "MarkBasePos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + valid->extra2 = 0; + OTV_NEST2( MarkBasePosFormat1, BaseArray ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 5 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra2 (1) */ + + static void + otv_MarkLigPos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "MarkLigPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + valid->extra2 = 1; + OTV_NEST3( MarkLigPosFormat1, LigatureArray, LigatureAttach ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 6 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra2 (0) */ + + static void + otv_MarkMarkPos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "MarkMarkPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + valid->extra2 = 0; + OTV_NEST2( MarkMarkPosFormat1, Mark2Array ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 7 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra1 (lookup count) */ + + static void + otv_ContextPos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "ContextPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + valid->extra1 = valid->lookup_count; + OTV_NEST3( ContextPosFormat1, PosRuleSet, PosRule ); + OTV_RUN( table, valid ); + break; + + case 2: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + OTV_NEST3( ContextPosFormat2, PosClassSet, PosClassRule ); + OTV_RUN( table, valid ); + break; + + case 3: + OTV_NEST1( ContextPosFormat3 ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 8 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra1 (lookup count) */ + + static void + otv_ChainContextPos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "ChainContextPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + valid->extra1 = valid->lookup_count; + OTV_NEST3( ChainContextPosFormat1, + ChainPosRuleSet, ChainPosRule ); + OTV_RUN( table, valid ); + break; + + case 2: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + OTV_NEST3( ChainContextPosFormat2, + ChainPosClassSet, ChainPosClassRule ); + OTV_RUN( table, valid ); + break; + + case 3: + OTV_NEST1( ChainContextPosFormat3 ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS LOOKUP TYPE 9 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses valid->type_funcs */ + + static void + otv_ExtensionPos_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt PosFormat; + + + OTV_NAME_ENTER( "ExtensionPos" ); + + OTV_LIMIT_CHECK( 2 ); + PosFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", PosFormat )); + + switch ( PosFormat ) + { + case 1: /* ExtensionPosFormat1 */ + { + FT_UInt ExtensionLookupType, ExtensionOffset; + OTV_Validate_Func validate; + + + OTV_LIMIT_CHECK( 6 ); + ExtensionLookupType = FT_NEXT_USHORT( p ); + ExtensionOffset = FT_NEXT_ULONG( p ); + + if ( ExtensionLookupType == 0 || ExtensionLookupType >= 9 ) + FT_INVALID_DATA; + + validate = valid->type_funcs[ExtensionLookupType - 1]; + validate( table + ExtensionOffset, valid ); + } + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + static const OTV_Validate_Func otv_gpos_validate_funcs[9] = + { + otv_SinglePos_validate, + otv_PairPos_validate, + otv_CursivePos_validate, + otv_MarkBasePos_validate, + otv_MarkLigPos_validate, + otv_MarkMarkPos_validate, + otv_ContextPos_validate, + otv_ChainContextPos_validate, + otv_ExtensionPos_validate + }; + + + /* sets valid->type_count */ + /* sets valid->type_funcs */ + + FT_LOCAL_DEF( void ) + otv_GPOS_subtable_validate( FT_Bytes table, + OTV_Validator valid ) + { + valid->type_count = 9; + valid->type_funcs = (OTV_Validate_Func*)otv_gpos_validate_funcs; + + otv_Lookup_validate( table, valid ); + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GPOS TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->glyph_count */ + + FT_LOCAL_DEF( void ) + otv_GPOS_validate( FT_Bytes table, + FT_UInt glyph_count, + FT_Validator ftvalid ) + { + OTV_ValidatorRec validrec; + OTV_Validator valid = &validrec; + FT_Bytes p = table; + FT_UInt ScriptList, FeatureList, LookupList; + + + valid->root = ftvalid; + + FT_TRACE3(( "validating GPOS table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 10 ); + + if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ + FT_INVALID_DATA; + + ScriptList = FT_NEXT_USHORT( p ); + FeatureList = FT_NEXT_USHORT( p ); + LookupList = FT_NEXT_USHORT( p ); + + valid->type_count = 9; + valid->type_funcs = (OTV_Validate_Func*)otv_gpos_validate_funcs; + valid->glyph_count = glyph_count; + + otv_LookupList_validate( table + LookupList, + valid ); + otv_FeatureList_validate( table + FeatureList, table + LookupList, + valid ); + otv_ScriptList_validate( table + ScriptList, table + FeatureList, + valid ); + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/reactos/lib/freetype/src/otvalid/otvgpos.h b/reactos/lib/freetype/src/otvalid/otvgpos.h index a2a1b99042e..14ca408261d 100644 --- a/reactos/lib/freetype/src/otvalid/otvgpos.h +++ b/reactos/lib/freetype/src/otvalid/otvgpos.h @@ -1,36 +1,36 @@ -/***************************************************************************/ -/* */ -/* otvgpos.h */ -/* */ -/* OpenType GPOS table validator (specification). */ -/* */ -/* Copyright 2004 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - -#ifndef __OTVGPOS_H__ -#define __OTVGPOS_H__ - - -FT_BEGIN_HEADER - - - FT_LOCAL( void ) - otv_GPOS_subtable_validate( FT_Bytes table, - OTV_Validator valid ); - - -FT_END_HEADER - -#endif /* __OTVGPOS_H__ */ - - -/* END */ +/***************************************************************************/ +/* */ +/* otvgpos.h */ +/* */ +/* OpenType GPOS table validator (specification). */ +/* */ +/* Copyright 2004 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __OTVGPOS_H__ +#define __OTVGPOS_H__ + + +FT_BEGIN_HEADER + + + FT_LOCAL( void ) + otv_GPOS_subtable_validate( FT_Bytes table, + OTV_Validator valid ); + + +FT_END_HEADER + +#endif /* __OTVGPOS_H__ */ + + +/* END */ diff --git a/reactos/lib/freetype/src/otvalid/otvgsub.c b/reactos/lib/freetype/src/otvalid/otvgsub.c index 01aa0ba6677..022fa46f6d4 100644 --- a/reactos/lib/freetype/src/otvalid/otvgsub.c +++ b/reactos/lib/freetype/src/otvalid/otvgsub.c @@ -1,584 +1,584 @@ -/***************************************************************************/ -/* */ -/* otvgsub.c */ -/* */ -/* OpenType GSUB table validation (body). */ -/* */ -/* Copyright 2004, 2005 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - -#include "otvalid.h" -#include "otvcommn.h" - - - /*************************************************************************/ - /* */ - /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ - /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ - /* messages during execution. */ - /* */ -#undef FT_COMPONENT -#define FT_COMPONENT trace_otvgsub - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GSUB LOOKUP TYPE 1 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* uses valid->glyph_count */ - - static void - otv_SingleSubst_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt SubstFormat; - - - OTV_NAME_ENTER( "SingleSubst" ); - - OTV_LIMIT_CHECK( 2 ); - SubstFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", SubstFormat )); - - switch ( SubstFormat ) - { - case 1: /* SingleSubstFormat1 */ - { - FT_Bytes Coverage; - FT_Int DeltaGlyphID; - FT_Long idx; - - - OTV_LIMIT_CHECK( 4 ); - Coverage = table + FT_NEXT_USHORT( p ); - DeltaGlyphID = FT_NEXT_SHORT( p ); - - otv_Coverage_validate( Coverage, valid ); - - idx = otv_Coverage_get_first( Coverage ) + DeltaGlyphID; - if ( idx < 0 ) - FT_INVALID_DATA; - - idx = otv_Coverage_get_last( Coverage ) + DeltaGlyphID; - if ( (FT_UInt)idx >= valid->glyph_count ) - FT_INVALID_DATA; - } - break; - - case 2: /* SingleSubstFormat2 */ - { - FT_UInt Coverage, GlyphCount; - - - OTV_LIMIT_CHECK( 4 ); - Coverage = FT_NEXT_USHORT( p ); - GlyphCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); - - otv_Coverage_validate( table + Coverage, valid ); - - OTV_LIMIT_CHECK( GlyphCount * 2 ); - - /* Substitute */ - for ( ; GlyphCount > 0; GlyphCount-- ) - if ( FT_NEXT_USHORT( p ) >= valid->glyph_count ) - FT_INVALID_DATA; - } - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GSUB LOOKUP TYPE 2 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* sets valid->extra1 (glyph count) */ - - static void - otv_MultipleSubst_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt SubstFormat; - - - OTV_NAME_ENTER( "MultipleSubst" ); - - OTV_LIMIT_CHECK( 2 ); - SubstFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", SubstFormat )); - - switch ( SubstFormat ) - { - case 1: - valid->extra1 = valid->glyph_count; - OTV_NEST2( MultipleSubstFormat1, Sequence ); - OTV_RUN( table, valid ); - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GSUB LOOKUP TYPE 3 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* sets valid->extra1 (glyph count) */ - - static void - otv_AlternateSubst_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt SubstFormat; - - - OTV_NAME_ENTER( "AlternateSubst" ); - - OTV_LIMIT_CHECK( 2 ); - SubstFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", SubstFormat )); - - switch ( SubstFormat ) - { - case 1: - valid->extra1 = valid->glyph_count; - OTV_NEST2( AlternateSubstFormat1, AlternateSet ); - OTV_RUN( table, valid ); - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GSUB LOOKUP TYPE 4 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - -#define Ligature otv_Ligature_validate, "Ligature" - - /* uses valid->glyph_count */ - - static void - otv_Ligature_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt LigatureGlyph, CompCount; - - - OTV_ENTER; - - OTV_LIMIT_CHECK( 4 ); - LigatureGlyph = FT_NEXT_USHORT( p ); - if ( LigatureGlyph >= valid->glyph_count ) - FT_INVALID_DATA; - - CompCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (CompCount = %d)\n", CompCount )); - - if ( CompCount == 0 ) - FT_INVALID_DATA; - - CompCount--; - - OTV_LIMIT_CHECK( CompCount * 2 ); /* Component */ - - /* no need to check the Component glyph indices */ - - OTV_EXIT; - } - - - static void - otv_LigatureSubst_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt SubstFormat; - - - OTV_NAME_ENTER( "LigatureSubst" ); - - OTV_LIMIT_CHECK( 2 ); - SubstFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", SubstFormat )); - - switch ( SubstFormat ) - { - case 1: - OTV_NEST3( LigatureSubstFormat1, LigatureSet, Ligature ); - OTV_RUN( table, valid ); - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GSUB LOOKUP TYPE 5 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* sets valid->extra1 (lookup count) */ - - static void - otv_ContextSubst_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt SubstFormat; - - - OTV_NAME_ENTER( "ContextSubst" ); - - OTV_LIMIT_CHECK( 2 ); - SubstFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", SubstFormat )); - - switch ( SubstFormat ) - { - case 1: - /* no need to check glyph indices/classes used as input for these */ - /* context rules since even invalid glyph indices/classes return */ - /* meaningful results */ - - valid->extra1 = valid->lookup_count; - OTV_NEST3( ContextSubstFormat1, SubRuleSet, SubRule ); - OTV_RUN( table, valid ); - break; - - case 2: - /* no need to check glyph indices/classes used as input for these */ - /* context rules since even invalid glyph indices/classes return */ - /* meaningful results */ - - OTV_NEST3( ContextSubstFormat2, SubClassSet, SubClassRule ); - OTV_RUN( table, valid ); - break; - - case 3: - OTV_NEST1( ContextSubstFormat3 ); - OTV_RUN( table, valid ); - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GSUB LOOKUP TYPE 6 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* sets valid->extra1 (lookup count) */ - - static void - otv_ChainContextSubst_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt SubstFormat; - - - OTV_NAME_ENTER( "ChainContextSubst" ); - - OTV_LIMIT_CHECK( 2 ); - SubstFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", SubstFormat )); - - switch ( SubstFormat ) - { - case 1: - /* no need to check glyph indices/classes used as input for these */ - /* context rules since even invalid glyph indices/classes return */ - /* meaningful results */ - - valid->extra1 = valid->lookup_count; - OTV_NEST3( ChainContextSubstFormat1, - ChainSubRuleSet, ChainSubRule ); - OTV_RUN( table, valid ); - break; - - case 2: - /* no need to check glyph indices/classes used as input for these */ - /* context rules since even invalid glyph indices/classes return */ - /* meaningful results */ - - OTV_NEST3( ChainContextSubstFormat2, - ChainSubClassSet, ChainSubClassRule ); - OTV_RUN( table, valid ); - break; - - case 3: - OTV_NEST1( ChainContextSubstFormat3 ); - OTV_RUN( table, valid ); - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GSUB LOOKUP TYPE 7 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* uses valid->type_funcs */ - - static void - otv_ExtensionSubst_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt SubstFormat; - - - OTV_NAME_ENTER( "ExtensionSubst" ); - - OTV_LIMIT_CHECK( 2 ); - SubstFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", SubstFormat )); - - switch ( SubstFormat ) - { - case 1: /* ExtensionSubstFormat1 */ - { - FT_UInt ExtensionLookupType, ExtensionOffset; - OTV_Validate_Func validate; - - - OTV_LIMIT_CHECK( 6 ); - ExtensionLookupType = FT_NEXT_USHORT( p ); - ExtensionOffset = FT_NEXT_ULONG( p ); - - if ( ExtensionLookupType == 0 || - ExtensionLookupType == 7 || - ExtensionLookupType > 8 ) - FT_INVALID_DATA; - - validate = valid->type_funcs[ExtensionLookupType - 1]; - validate( table + ExtensionOffset, valid ); - } - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GSUB LOOKUP TYPE 8 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* uses valid->glyph_count */ - - static void - otv_ReverseChainSingleSubst_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table, Coverage; - FT_UInt SubstFormat; - FT_UInt BacktrackGlyphCount, LookaheadGlyphCount, GlyphCount; - - - OTV_NAME_ENTER( "ReverseChainSingleSubst" ); - - OTV_LIMIT_CHECK( 2 ); - SubstFormat = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (format %d)\n", SubstFormat )); - - switch ( SubstFormat ) - { - case 1: /* ReverseChainSingleSubstFormat1 */ - OTV_LIMIT_CHECK( 4 ); - Coverage = table + FT_NEXT_USHORT( p ); - BacktrackGlyphCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (BacktrackGlyphCount = %d)\n", BacktrackGlyphCount )); - - otv_Coverage_validate( Coverage, valid ); - - OTV_LIMIT_CHECK( BacktrackGlyphCount * 2 + 2 ); - - for ( ; BacktrackGlyphCount > 0; BacktrackGlyphCount-- ) - otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid ); - - LookaheadGlyphCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (LookaheadGlyphCount = %d)\n", LookaheadGlyphCount )); - - OTV_LIMIT_CHECK( LookaheadGlyphCount * 2 + 2 ); - - for ( ; LookaheadGlyphCount > 0; LookaheadGlyphCount-- ) - otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid ); - - GlyphCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); - - if ( GlyphCount != otv_Coverage_get_count( Coverage ) ) - FT_INVALID_DATA; - - OTV_LIMIT_CHECK( GlyphCount * 2 ); - - /* Substitute */ - for ( ; GlyphCount > 0; GlyphCount-- ) - if ( FT_NEXT_USHORT( p ) >= valid->glyph_count ) - FT_INVALID_DATA; - - break; - - default: - FT_INVALID_DATA; - } - - OTV_EXIT; - } - - - static const OTV_Validate_Func otv_gsub_validate_funcs[8] = - { - otv_SingleSubst_validate, - otv_MultipleSubst_validate, - otv_AlternateSubst_validate, - otv_LigatureSubst_validate, - otv_ContextSubst_validate, - otv_ChainContextSubst_validate, - otv_ExtensionSubst_validate, - otv_ReverseChainSingleSubst_validate - }; - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** GSUB TABLE *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /* sets valid->type_count */ - /* sets valid->type_funcs */ - /* sets valid->glyph_count */ - - FT_LOCAL_DEF( void ) - otv_GSUB_validate( FT_Bytes table, - FT_UInt glyph_count, - FT_Validator ftvalid ) - { - OTV_ValidatorRec validrec; - OTV_Validator valid = &validrec; - FT_Bytes p = table; - FT_UInt ScriptList, FeatureList, LookupList; - - - valid->root = ftvalid; - - FT_TRACE3(( "validating GSUB table\n" )); - OTV_INIT; - - OTV_LIMIT_CHECK( 10 ); - - if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ - FT_INVALID_DATA; - - ScriptList = FT_NEXT_USHORT( p ); - FeatureList = FT_NEXT_USHORT( p ); - LookupList = FT_NEXT_USHORT( p ); - - valid->type_count = 8; - valid->type_funcs = (OTV_Validate_Func*)otv_gsub_validate_funcs; - valid->glyph_count = glyph_count; - - otv_LookupList_validate( table + LookupList, - valid ); - otv_FeatureList_validate( table + FeatureList, table + LookupList, - valid ); - otv_ScriptList_validate( table + ScriptList, table + FeatureList, - valid ); - - FT_TRACE4(( "\n" )); - } - - -/* END */ +/***************************************************************************/ +/* */ +/* otvgsub.c */ +/* */ +/* OpenType GSUB table validation (body). */ +/* */ +/* Copyright 2004, 2005 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include "otvalid.h" +#include "otvcommn.h" + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_otvgsub + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 1 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses valid->glyph_count */ + + static void + otv_SingleSubst_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "SingleSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: /* SingleSubstFormat1 */ + { + FT_Bytes Coverage; + FT_Int DeltaGlyphID; + FT_Long idx; + + + OTV_LIMIT_CHECK( 4 ); + Coverage = table + FT_NEXT_USHORT( p ); + DeltaGlyphID = FT_NEXT_SHORT( p ); + + otv_Coverage_validate( Coverage, valid ); + + idx = otv_Coverage_get_first( Coverage ) + DeltaGlyphID; + if ( idx < 0 ) + FT_INVALID_DATA; + + idx = otv_Coverage_get_last( Coverage ) + DeltaGlyphID; + if ( (FT_UInt)idx >= valid->glyph_count ) + FT_INVALID_DATA; + } + break; + + case 2: /* SingleSubstFormat2 */ + { + FT_UInt Coverage, GlyphCount; + + + OTV_LIMIT_CHECK( 4 ); + Coverage = FT_NEXT_USHORT( p ); + GlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + + otv_Coverage_validate( table + Coverage, valid ); + + OTV_LIMIT_CHECK( GlyphCount * 2 ); + + /* Substitute */ + for ( ; GlyphCount > 0; GlyphCount-- ) + if ( FT_NEXT_USHORT( p ) >= valid->glyph_count ) + FT_INVALID_DATA; + } + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 2 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra1 (glyph count) */ + + static void + otv_MultipleSubst_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "MultipleSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: + valid->extra1 = valid->glyph_count; + OTV_NEST2( MultipleSubstFormat1, Sequence ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 3 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra1 (glyph count) */ + + static void + otv_AlternateSubst_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "AlternateSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: + valid->extra1 = valid->glyph_count; + OTV_NEST2( AlternateSubstFormat1, AlternateSet ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 4 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + +#define Ligature otv_Ligature_validate, "Ligature" + + /* uses valid->glyph_count */ + + static void + otv_Ligature_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt LigatureGlyph, CompCount; + + + OTV_ENTER; + + OTV_LIMIT_CHECK( 4 ); + LigatureGlyph = FT_NEXT_USHORT( p ); + if ( LigatureGlyph >= valid->glyph_count ) + FT_INVALID_DATA; + + CompCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (CompCount = %d)\n", CompCount )); + + if ( CompCount == 0 ) + FT_INVALID_DATA; + + CompCount--; + + OTV_LIMIT_CHECK( CompCount * 2 ); /* Component */ + + /* no need to check the Component glyph indices */ + + OTV_EXIT; + } + + + static void + otv_LigatureSubst_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "LigatureSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: + OTV_NEST3( LigatureSubstFormat1, LigatureSet, Ligature ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 5 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra1 (lookup count) */ + + static void + otv_ContextSubst_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "ContextSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + valid->extra1 = valid->lookup_count; + OTV_NEST3( ContextSubstFormat1, SubRuleSet, SubRule ); + OTV_RUN( table, valid ); + break; + + case 2: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + OTV_NEST3( ContextSubstFormat2, SubClassSet, SubClassRule ); + OTV_RUN( table, valid ); + break; + + case 3: + OTV_NEST1( ContextSubstFormat3 ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 6 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->extra1 (lookup count) */ + + static void + otv_ChainContextSubst_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "ChainContextSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + valid->extra1 = valid->lookup_count; + OTV_NEST3( ChainContextSubstFormat1, + ChainSubRuleSet, ChainSubRule ); + OTV_RUN( table, valid ); + break; + + case 2: + /* no need to check glyph indices/classes used as input for these */ + /* context rules since even invalid glyph indices/classes return */ + /* meaningful results */ + + OTV_NEST3( ChainContextSubstFormat2, + ChainSubClassSet, ChainSubClassRule ); + OTV_RUN( table, valid ); + break; + + case 3: + OTV_NEST1( ChainContextSubstFormat3 ); + OTV_RUN( table, valid ); + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 7 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses valid->type_funcs */ + + static void + otv_ExtensionSubst_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt SubstFormat; + + + OTV_NAME_ENTER( "ExtensionSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: /* ExtensionSubstFormat1 */ + { + FT_UInt ExtensionLookupType, ExtensionOffset; + OTV_Validate_Func validate; + + + OTV_LIMIT_CHECK( 6 ); + ExtensionLookupType = FT_NEXT_USHORT( p ); + ExtensionOffset = FT_NEXT_ULONG( p ); + + if ( ExtensionLookupType == 0 || + ExtensionLookupType == 7 || + ExtensionLookupType > 8 ) + FT_INVALID_DATA; + + validate = valid->type_funcs[ExtensionLookupType - 1]; + validate( table + ExtensionOffset, valid ); + } + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB LOOKUP TYPE 8 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* uses valid->glyph_count */ + + static void + otv_ReverseChainSingleSubst_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table, Coverage; + FT_UInt SubstFormat; + FT_UInt BacktrackGlyphCount, LookaheadGlyphCount, GlyphCount; + + + OTV_NAME_ENTER( "ReverseChainSingleSubst" ); + + OTV_LIMIT_CHECK( 2 ); + SubstFormat = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (format %d)\n", SubstFormat )); + + switch ( SubstFormat ) + { + case 1: /* ReverseChainSingleSubstFormat1 */ + OTV_LIMIT_CHECK( 4 ); + Coverage = table + FT_NEXT_USHORT( p ); + BacktrackGlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (BacktrackGlyphCount = %d)\n", BacktrackGlyphCount )); + + otv_Coverage_validate( Coverage, valid ); + + OTV_LIMIT_CHECK( BacktrackGlyphCount * 2 + 2 ); + + for ( ; BacktrackGlyphCount > 0; BacktrackGlyphCount-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid ); + + LookaheadGlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (LookaheadGlyphCount = %d)\n", LookaheadGlyphCount )); + + OTV_LIMIT_CHECK( LookaheadGlyphCount * 2 + 2 ); + + for ( ; LookaheadGlyphCount > 0; LookaheadGlyphCount-- ) + otv_Coverage_validate( table + FT_NEXT_USHORT( p ), valid ); + + GlyphCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (GlyphCount = %d)\n", GlyphCount )); + + if ( GlyphCount != otv_Coverage_get_count( Coverage ) ) + FT_INVALID_DATA; + + OTV_LIMIT_CHECK( GlyphCount * 2 ); + + /* Substitute */ + for ( ; GlyphCount > 0; GlyphCount-- ) + if ( FT_NEXT_USHORT( p ) >= valid->glyph_count ) + FT_INVALID_DATA; + + break; + + default: + FT_INVALID_DATA; + } + + OTV_EXIT; + } + + + static const OTV_Validate_Func otv_gsub_validate_funcs[8] = + { + otv_SingleSubst_validate, + otv_MultipleSubst_validate, + otv_AlternateSubst_validate, + otv_LigatureSubst_validate, + otv_ContextSubst_validate, + otv_ChainContextSubst_validate, + otv_ExtensionSubst_validate, + otv_ReverseChainSingleSubst_validate + }; + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** GSUB TABLE *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /* sets valid->type_count */ + /* sets valid->type_funcs */ + /* sets valid->glyph_count */ + + FT_LOCAL_DEF( void ) + otv_GSUB_validate( FT_Bytes table, + FT_UInt glyph_count, + FT_Validator ftvalid ) + { + OTV_ValidatorRec validrec; + OTV_Validator valid = &validrec; + FT_Bytes p = table; + FT_UInt ScriptList, FeatureList, LookupList; + + + valid->root = ftvalid; + + FT_TRACE3(( "validating GSUB table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 10 ); + + if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ + FT_INVALID_DATA; + + ScriptList = FT_NEXT_USHORT( p ); + FeatureList = FT_NEXT_USHORT( p ); + LookupList = FT_NEXT_USHORT( p ); + + valid->type_count = 8; + valid->type_funcs = (OTV_Validate_Func*)otv_gsub_validate_funcs; + valid->glyph_count = glyph_count; + + otv_LookupList_validate( table + LookupList, + valid ); + otv_FeatureList_validate( table + FeatureList, table + LookupList, + valid ); + otv_ScriptList_validate( table + ScriptList, table + FeatureList, + valid ); + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/reactos/lib/freetype/src/otvalid/otvjstf.c b/reactos/lib/freetype/src/otvalid/otvjstf.c index b45f0279968..a230b36fbc0 100644 --- a/reactos/lib/freetype/src/otvalid/otvjstf.c +++ b/reactos/lib/freetype/src/otvalid/otvjstf.c @@ -1,258 +1,258 @@ -/***************************************************************************/ -/* */ -/* otvjstf.c */ -/* */ -/* OpenType JSTF table validation (body). */ -/* */ -/* Copyright 2004 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - -#include "otvalid.h" -#include "otvcommn.h" -#include "otvgpos.h" - - - /*************************************************************************/ - /* */ - /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ - /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ - /* messages during execution. */ - /* */ -#undef FT_COMPONENT -#define FT_COMPONENT trace_otvjstf - - -#define JstfPriority otv_JstfPriority_validate, "JstfPriority" -#define JstfLookup otv_GPOS_subtable_validate, "" - - /* uses valid->extra1 (GSUB lookup count) */ - /* uses valid->extra2 (GPOS lookup count) */ - /* sets valid->extra1 (counter) */ - - static void - otv_JstfPriority_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt table_size; - FT_UInt gsub_lookup_count, gpos_lookup_count; - - OTV_OPTIONAL_TABLE( ShrinkageEnableGSUB ); - OTV_OPTIONAL_TABLE( ShrinkageDisableGSUB ); - OTV_OPTIONAL_TABLE( ShrinkageEnableGPOS ); - OTV_OPTIONAL_TABLE( ShrinkageDisableGPOS ); - OTV_OPTIONAL_TABLE( ExtensionEnableGSUB ); - OTV_OPTIONAL_TABLE( ExtensionDisableGSUB ); - OTV_OPTIONAL_TABLE( ExtensionEnableGPOS ); - OTV_OPTIONAL_TABLE( ExtensionDisableGPOS ); - OTV_OPTIONAL_TABLE( ShrinkageJstfMax ); - OTV_OPTIONAL_TABLE( ExtensionJstfMax ); - - - OTV_ENTER; - OTV_TRACE(( "JstfPriority table\n" )); - - OTV_LIMIT_CHECK( 20 ); - - gsub_lookup_count = valid->extra1; - gpos_lookup_count = valid->extra2; - - table_size = 20; - - valid->extra1 = gsub_lookup_count; - - OTV_OPTIONAL_OFFSET( ShrinkageEnableGSUB ); - OTV_SIZE_CHECK( ShrinkageEnableGSUB ); - if ( ShrinkageEnableGSUB ) - otv_x_ux( table + ShrinkageEnableGSUB, valid ); - - OTV_OPTIONAL_OFFSET( ShrinkageDisableGSUB ); - OTV_SIZE_CHECK( ShrinkageDisableGSUB ); - if ( ShrinkageDisableGSUB ) - otv_x_ux( table + ShrinkageDisableGSUB, valid ); - - valid->extra1 = gpos_lookup_count; - - OTV_OPTIONAL_OFFSET( ShrinkageEnableGPOS ); - OTV_SIZE_CHECK( ShrinkageEnableGPOS ); - if ( ShrinkageEnableGPOS ) - otv_x_ux( table + ShrinkageEnableGPOS, valid ); - - OTV_OPTIONAL_OFFSET( ShrinkageDisableGPOS ); - OTV_SIZE_CHECK( ShrinkageDisableGPOS ); - if ( ShrinkageDisableGPOS ) - otv_x_ux( table + ShrinkageDisableGPOS, valid ); - - OTV_OPTIONAL_OFFSET( ShrinkageJstfMax ); - OTV_SIZE_CHECK( ShrinkageJstfMax ); - if ( ShrinkageJstfMax ) - { - /* XXX: check lookup types? */ - OTV_NEST2( JstfMax, JstfLookup ); - OTV_RUN( table + ShrinkageJstfMax, valid ); - } - - valid->extra1 = gsub_lookup_count; - - OTV_OPTIONAL_OFFSET( ExtensionEnableGSUB ); - OTV_SIZE_CHECK( ExtensionEnableGSUB ); - if ( ExtensionEnableGSUB ) - otv_x_ux( table + ExtensionEnableGSUB, valid ); - - OTV_OPTIONAL_OFFSET( ExtensionDisableGSUB ); - OTV_SIZE_CHECK( ExtensionDisableGSUB ); - if ( ExtensionDisableGSUB ) - otv_x_ux( table + ExtensionDisableGSUB, valid ); - - valid->extra1 = gpos_lookup_count; - - OTV_OPTIONAL_OFFSET( ExtensionEnableGPOS ); - OTV_SIZE_CHECK( ExtensionEnableGPOS ); - if ( ExtensionEnableGPOS ) - otv_x_ux( table + ExtensionEnableGPOS, valid ); - - OTV_OPTIONAL_OFFSET( ExtensionDisableGPOS ); - OTV_SIZE_CHECK( ExtensionDisableGPOS ); - if ( ExtensionDisableGPOS ) - otv_x_ux( table + ExtensionDisableGPOS, valid ); - - OTV_OPTIONAL_OFFSET( ExtensionJstfMax ); - OTV_SIZE_CHECK( ExtensionJstfMax ); - if ( ExtensionJstfMax ) - { - /* XXX: check lookup types? */ - OTV_NEST2( JstfMax, JstfLookup ); - OTV_RUN( table + ExtensionJstfMax, valid ); - } - - valid->extra1 = gsub_lookup_count; - valid->extra2 = gpos_lookup_count; - - OTV_EXIT; - } - - - /* sets valid->extra (glyph count) */ - /* sets valid->func1 (otv_JstfPriority_validate) */ - - static void - otv_JstfScript_validate( FT_Bytes table, - OTV_Validator valid ) - { - FT_Bytes p = table; - FT_UInt table_size; - FT_UInt JstfLangSysCount; - - OTV_OPTIONAL_TABLE( ExtGlyph ); - OTV_OPTIONAL_TABLE( DefJstfLangSys ); - - - OTV_NAME_ENTER( "JstfScript" ); - - OTV_LIMIT_CHECK( 6 ); - OTV_OPTIONAL_OFFSET( ExtGlyph ); - OTV_OPTIONAL_OFFSET( DefJstfLangSys ); - JstfLangSysCount = FT_NEXT_USHORT( p ); - - OTV_TRACE(( " (JstfLangSysCount = %d)\n", JstfLangSysCount )); - - table_size = JstfLangSysCount * 6 + 6; - - OTV_SIZE_CHECK( ExtGlyph ); - if ( ExtGlyph ) - { - valid->extra1 = valid->glyph_count; - OTV_NEST1( ExtenderGlyph ); - OTV_RUN( table + ExtGlyph, valid ); - } - - OTV_SIZE_CHECK( DefJstfLangSys ); - if ( DefJstfLangSys ) - { - OTV_NEST2( JstfLangSys, JstfPriority ); - OTV_RUN( table + DefJstfLangSys, valid ); - } - - OTV_LIMIT_CHECK( 6 * JstfLangSysCount ); - - /* JstfLangSysRecord */ - OTV_NEST2( JstfLangSys, JstfPriority ); - for ( ; JstfLangSysCount > 0; JstfLangSysCount-- ) - { - p += 4; /* skip JstfLangSysTag */ - - OTV_RUN( table + FT_NEXT_USHORT( p ), valid ); - } - - OTV_EXIT; - } - - - /* sets valid->extra1 (GSUB lookup count) */ - /* sets valid->extra2 (GPOS lookup count) */ - /* sets valid->glyph_count */ - - FT_LOCAL_DEF( void ) - otv_JSTF_validate( FT_Bytes table, - FT_Bytes gsub, - FT_Bytes gpos, - FT_UInt glyph_count, - FT_Validator ftvalid ) - { - OTV_ValidatorRec validrec; - OTV_Validator valid = &validrec; - FT_Bytes p = table; - FT_UInt JstfScriptCount; - - - valid->root = ftvalid; - - FT_TRACE3(( "validating JSTF table\n" )); - OTV_INIT; - - OTV_LIMIT_CHECK( 6 ); - - if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ - FT_INVALID_DATA; - - JstfScriptCount = FT_NEXT_USHORT( p ); - - FT_TRACE3(( " (JstfScriptCount = %d)\n", JstfScriptCount )); - - OTV_LIMIT_CHECK( JstfScriptCount * 6 ); - - if ( gsub ) - valid->extra1 = otv_GSUBGPOS_get_Lookup_count( gsub ); - else - valid->extra1 = 0; - - if ( gpos ) - valid->extra2 = otv_GSUBGPOS_get_Lookup_count( gpos ); - else - valid->extra2 = 0; - - valid->glyph_count = glyph_count; - - /* JstfScriptRecord */ - for ( ; JstfScriptCount > 0; JstfScriptCount-- ) - { - p += 4; /* skip JstfScriptTag */ - - /* JstfScript */ - otv_JstfScript_validate( table + FT_NEXT_USHORT( p ), valid ); - } - - FT_TRACE4(( "\n" )); - } - - -/* END */ +/***************************************************************************/ +/* */ +/* otvjstf.c */ +/* */ +/* OpenType JSTF table validation (body). */ +/* */ +/* Copyright 2004 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include "otvalid.h" +#include "otvcommn.h" +#include "otvgpos.h" + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_otvjstf + + +#define JstfPriority otv_JstfPriority_validate, "JstfPriority" +#define JstfLookup otv_GPOS_subtable_validate, "" + + /* uses valid->extra1 (GSUB lookup count) */ + /* uses valid->extra2 (GPOS lookup count) */ + /* sets valid->extra1 (counter) */ + + static void + otv_JstfPriority_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt table_size; + FT_UInt gsub_lookup_count, gpos_lookup_count; + + OTV_OPTIONAL_TABLE( ShrinkageEnableGSUB ); + OTV_OPTIONAL_TABLE( ShrinkageDisableGSUB ); + OTV_OPTIONAL_TABLE( ShrinkageEnableGPOS ); + OTV_OPTIONAL_TABLE( ShrinkageDisableGPOS ); + OTV_OPTIONAL_TABLE( ExtensionEnableGSUB ); + OTV_OPTIONAL_TABLE( ExtensionDisableGSUB ); + OTV_OPTIONAL_TABLE( ExtensionEnableGPOS ); + OTV_OPTIONAL_TABLE( ExtensionDisableGPOS ); + OTV_OPTIONAL_TABLE( ShrinkageJstfMax ); + OTV_OPTIONAL_TABLE( ExtensionJstfMax ); + + + OTV_ENTER; + OTV_TRACE(( "JstfPriority table\n" )); + + OTV_LIMIT_CHECK( 20 ); + + gsub_lookup_count = valid->extra1; + gpos_lookup_count = valid->extra2; + + table_size = 20; + + valid->extra1 = gsub_lookup_count; + + OTV_OPTIONAL_OFFSET( ShrinkageEnableGSUB ); + OTV_SIZE_CHECK( ShrinkageEnableGSUB ); + if ( ShrinkageEnableGSUB ) + otv_x_ux( table + ShrinkageEnableGSUB, valid ); + + OTV_OPTIONAL_OFFSET( ShrinkageDisableGSUB ); + OTV_SIZE_CHECK( ShrinkageDisableGSUB ); + if ( ShrinkageDisableGSUB ) + otv_x_ux( table + ShrinkageDisableGSUB, valid ); + + valid->extra1 = gpos_lookup_count; + + OTV_OPTIONAL_OFFSET( ShrinkageEnableGPOS ); + OTV_SIZE_CHECK( ShrinkageEnableGPOS ); + if ( ShrinkageEnableGPOS ) + otv_x_ux( table + ShrinkageEnableGPOS, valid ); + + OTV_OPTIONAL_OFFSET( ShrinkageDisableGPOS ); + OTV_SIZE_CHECK( ShrinkageDisableGPOS ); + if ( ShrinkageDisableGPOS ) + otv_x_ux( table + ShrinkageDisableGPOS, valid ); + + OTV_OPTIONAL_OFFSET( ShrinkageJstfMax ); + OTV_SIZE_CHECK( ShrinkageJstfMax ); + if ( ShrinkageJstfMax ) + { + /* XXX: check lookup types? */ + OTV_NEST2( JstfMax, JstfLookup ); + OTV_RUN( table + ShrinkageJstfMax, valid ); + } + + valid->extra1 = gsub_lookup_count; + + OTV_OPTIONAL_OFFSET( ExtensionEnableGSUB ); + OTV_SIZE_CHECK( ExtensionEnableGSUB ); + if ( ExtensionEnableGSUB ) + otv_x_ux( table + ExtensionEnableGSUB, valid ); + + OTV_OPTIONAL_OFFSET( ExtensionDisableGSUB ); + OTV_SIZE_CHECK( ExtensionDisableGSUB ); + if ( ExtensionDisableGSUB ) + otv_x_ux( table + ExtensionDisableGSUB, valid ); + + valid->extra1 = gpos_lookup_count; + + OTV_OPTIONAL_OFFSET( ExtensionEnableGPOS ); + OTV_SIZE_CHECK( ExtensionEnableGPOS ); + if ( ExtensionEnableGPOS ) + otv_x_ux( table + ExtensionEnableGPOS, valid ); + + OTV_OPTIONAL_OFFSET( ExtensionDisableGPOS ); + OTV_SIZE_CHECK( ExtensionDisableGPOS ); + if ( ExtensionDisableGPOS ) + otv_x_ux( table + ExtensionDisableGPOS, valid ); + + OTV_OPTIONAL_OFFSET( ExtensionJstfMax ); + OTV_SIZE_CHECK( ExtensionJstfMax ); + if ( ExtensionJstfMax ) + { + /* XXX: check lookup types? */ + OTV_NEST2( JstfMax, JstfLookup ); + OTV_RUN( table + ExtensionJstfMax, valid ); + } + + valid->extra1 = gsub_lookup_count; + valid->extra2 = gpos_lookup_count; + + OTV_EXIT; + } + + + /* sets valid->extra (glyph count) */ + /* sets valid->func1 (otv_JstfPriority_validate) */ + + static void + otv_JstfScript_validate( FT_Bytes table, + OTV_Validator valid ) + { + FT_Bytes p = table; + FT_UInt table_size; + FT_UInt JstfLangSysCount; + + OTV_OPTIONAL_TABLE( ExtGlyph ); + OTV_OPTIONAL_TABLE( DefJstfLangSys ); + + + OTV_NAME_ENTER( "JstfScript" ); + + OTV_LIMIT_CHECK( 6 ); + OTV_OPTIONAL_OFFSET( ExtGlyph ); + OTV_OPTIONAL_OFFSET( DefJstfLangSys ); + JstfLangSysCount = FT_NEXT_USHORT( p ); + + OTV_TRACE(( " (JstfLangSysCount = %d)\n", JstfLangSysCount )); + + table_size = JstfLangSysCount * 6 + 6; + + OTV_SIZE_CHECK( ExtGlyph ); + if ( ExtGlyph ) + { + valid->extra1 = valid->glyph_count; + OTV_NEST1( ExtenderGlyph ); + OTV_RUN( table + ExtGlyph, valid ); + } + + OTV_SIZE_CHECK( DefJstfLangSys ); + if ( DefJstfLangSys ) + { + OTV_NEST2( JstfLangSys, JstfPriority ); + OTV_RUN( table + DefJstfLangSys, valid ); + } + + OTV_LIMIT_CHECK( 6 * JstfLangSysCount ); + + /* JstfLangSysRecord */ + OTV_NEST2( JstfLangSys, JstfPriority ); + for ( ; JstfLangSysCount > 0; JstfLangSysCount-- ) + { + p += 4; /* skip JstfLangSysTag */ + + OTV_RUN( table + FT_NEXT_USHORT( p ), valid ); + } + + OTV_EXIT; + } + + + /* sets valid->extra1 (GSUB lookup count) */ + /* sets valid->extra2 (GPOS lookup count) */ + /* sets valid->glyph_count */ + + FT_LOCAL_DEF( void ) + otv_JSTF_validate( FT_Bytes table, + FT_Bytes gsub, + FT_Bytes gpos, + FT_UInt glyph_count, + FT_Validator ftvalid ) + { + OTV_ValidatorRec validrec; + OTV_Validator valid = &validrec; + FT_Bytes p = table; + FT_UInt JstfScriptCount; + + + valid->root = ftvalid; + + FT_TRACE3(( "validating JSTF table\n" )); + OTV_INIT; + + OTV_LIMIT_CHECK( 6 ); + + if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ + FT_INVALID_DATA; + + JstfScriptCount = FT_NEXT_USHORT( p ); + + FT_TRACE3(( " (JstfScriptCount = %d)\n", JstfScriptCount )); + + OTV_LIMIT_CHECK( JstfScriptCount * 6 ); + + if ( gsub ) + valid->extra1 = otv_GSUBGPOS_get_Lookup_count( gsub ); + else + valid->extra1 = 0; + + if ( gpos ) + valid->extra2 = otv_GSUBGPOS_get_Lookup_count( gpos ); + else + valid->extra2 = 0; + + valid->glyph_count = glyph_count; + + /* JstfScriptRecord */ + for ( ; JstfScriptCount > 0; JstfScriptCount-- ) + { + p += 4; /* skip JstfScriptTag */ + + /* JstfScript */ + otv_JstfScript_validate( table + FT_NEXT_USHORT( p ), valid ); + } + + FT_TRACE4(( "\n" )); + } + + +/* END */ diff --git a/reactos/lib/freetype/src/otvalid/otvmod.c b/reactos/lib/freetype/src/otvalid/otvmod.c index 0467ae8bb49..3572a3dd8f8 100644 --- a/reactos/lib/freetype/src/otvalid/otvmod.c +++ b/reactos/lib/freetype/src/otvalid/otvmod.c @@ -1,238 +1,238 @@ -/***************************************************************************/ -/* */ -/* otvmod.c */ -/* */ -/* FreeType's OpenType validation module implementation (body). */ -/* */ -/* Copyright 2004, 2005 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - -#include <ft2build.h> -#include FT_TRUETYPE_TABLES_H -#include FT_TRUETYPE_TAGS_H -#include FT_OPENTYPE_VALIDATE_H -#include FT_INTERNAL_OBJECTS_H -#include FT_SERVICE_OPENTYPE_VALIDATE_H - -#include "otvmod.h" -#include "otvalid.h" -#include "otvcommn.h" - - - /*************************************************************************/ - /* */ - /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ - /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ - /* messages during execution. */ - /* */ -#undef FT_COMPONENT -#define FT_COMPONENT trace_otvmodule - - - static FT_Error - otv_load_table( FT_Face face, - FT_Tag tag, - FT_Byte* *table, - FT_ULong *table_len ) - { - FT_Error error; - FT_Memory memory = FT_FACE_MEMORY( face ); - - - error = FT_Load_Sfnt_Table( face, tag, 0, NULL, table_len ); - if ( error == OTV_Err_Table_Missing ) - return OTV_Err_Ok; - if ( error ) - goto Exit; - - if ( FT_ALLOC( *table, *table_len ) ) - goto Exit; - - error = FT_Load_Sfnt_Table( face, tag, 0, *table, table_len ); - - Exit: - return error; - } - - - static FT_Error - otv_validate( FT_Face face, - FT_UInt ot_flags, - FT_Bytes *ot_base, - FT_Bytes *ot_gdef, - FT_Bytes *ot_gpos, - FT_Bytes *ot_gsub, - FT_Bytes *ot_jstf ) - { - FT_Error error = OTV_Err_Ok; - FT_Byte *base, *gdef, *gpos, *gsub, *jstf; - FT_ULong len_base, len_gdef, len_gpos, len_gsub, len_jstf; - FT_ValidatorRec valid; - - - base = gdef = gpos = gsub = jstf = NULL; - len_base = len_gdef = len_gpos = len_gsub = len_jstf = 0; - - /* load tables */ - - if ( ot_flags & FT_VALIDATE_BASE ) - { - error = otv_load_table( face, TTAG_BASE, &base, &len_base ); - if ( error ) - goto Exit; - } - - if ( ot_flags & FT_VALIDATE_GDEF ) - { - error = otv_load_table( face, TTAG_GDEF, &gdef, &len_gdef ); - if ( error ) - goto Exit; - } - - if ( ot_flags & FT_VALIDATE_GPOS ) - { - error = otv_load_table( face, TTAG_GPOS, &gpos, &len_gpos ); - if ( error ) - goto Exit; - } - - if ( ot_flags & FT_VALIDATE_GSUB ) - { - error = otv_load_table( face, TTAG_GSUB, &gsub, &len_gsub ); - if ( error ) - goto Exit; - } - - if ( ot_flags & FT_VALIDATE_JSTF ) - { - error = otv_load_table( face, TTAG_JSTF, &jstf, &len_jstf ); - if ( error ) - goto Exit; - } - - /* validate tables */ - - if ( base ) - { - ft_validator_init( &valid, base, base + len_base, FT_VALIDATE_DEFAULT ); - if ( ft_setjmp( valid.jump_buffer ) == 0 ) - otv_BASE_validate( base, &valid ); - error = valid.error; - if ( error ) - goto Exit; - } - - if ( gpos ) - { - ft_validator_init( &valid, gpos, gpos + len_gpos, FT_VALIDATE_DEFAULT ); - if (ft_setjmp( valid.jump_buffer ) == 0 ) - otv_GPOS_validate( gpos, face->num_glyphs, &valid ); - error = valid.error; - if ( error ) - goto Exit; - } - - if ( gsub ) - { - ft_validator_init( &valid, gsub, gsub + len_gsub, FT_VALIDATE_DEFAULT ); - if ( ft_setjmp( valid.jump_buffer ) == 0 ) - otv_GSUB_validate( gsub, face->num_glyphs, &valid ); - error = valid.error; - if ( error ) - goto Exit; - } - - if ( gdef ) - { - ft_validator_init( &valid, gdef, gdef + len_gdef, FT_VALIDATE_DEFAULT ); - if ( ft_setjmp( valid.jump_buffer ) == 0 ) - otv_GDEF_validate( gdef, gsub, gpos, &valid ); - error = valid.error; - if ( error ) - goto Exit; - } - - if ( jstf ) - { - ft_validator_init( &valid, jstf, jstf + len_jstf, FT_VALIDATE_DEFAULT ); - if ( ft_setjmp( valid.jump_buffer ) == 0 ) - otv_JSTF_validate( jstf, gsub, gpos, face->num_glyphs, &valid ); - error = valid.error; - if ( error ) - goto Exit; - } - - *ot_base = (FT_Bytes)base; - *ot_gdef = (FT_Bytes)gdef; - *ot_gpos = (FT_Bytes)gpos; - *ot_gsub = (FT_Bytes)gsub; - *ot_jstf = (FT_Bytes)jstf; - - Exit: - if ( error ) { - FT_Memory memory = FT_FACE_MEMORY( face ); - - - FT_FREE( base ); - FT_FREE( gdef ); - FT_FREE( gpos ); - FT_FREE( gsub ); - FT_FREE( jstf ); - } - - return error; - } - - - static - const FT_Service_OTvalidateRec otvalid_interface = - { - otv_validate - }; - - - static - const FT_ServiceDescRec otvalid_services[] = - { - { FT_SERVICE_ID_OPENTYPE_VALIDATE, &otvalid_interface }, - { NULL, NULL } - }; - - - static FT_Pointer - otvalid_get_service( FT_Module module, - const char* service_id ) - { - FT_UNUSED( module ); - - return ft_service_list_lookup( otvalid_services, service_id ); - } - - - FT_CALLBACK_TABLE_DEF - const FT_Module_Class otv_module_class = - { - 0, - sizeof( FT_ModuleRec ), - "otvalid", - 0x10000L, - 0x20000L, - - 0, /* module-specific interface */ - - (FT_Module_Constructor)0, - (FT_Module_Destructor) 0, - (FT_Module_Requester) otvalid_get_service - }; - - -/* END */ +/***************************************************************************/ +/* */ +/* otvmod.c */ +/* */ +/* FreeType's OpenType validation module implementation (body). */ +/* */ +/* Copyright 2004, 2005 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_TRUETYPE_TABLES_H +#include FT_TRUETYPE_TAGS_H +#include FT_OPENTYPE_VALIDATE_H +#include FT_INTERNAL_OBJECTS_H +#include FT_SERVICE_OPENTYPE_VALIDATE_H + +#include "otvmod.h" +#include "otvalid.h" +#include "otvcommn.h" + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_otvmodule + + + static FT_Error + otv_load_table( FT_Face face, + FT_Tag tag, + FT_Byte* *table, + FT_ULong *table_len ) + { + FT_Error error; + FT_Memory memory = FT_FACE_MEMORY( face ); + + + error = FT_Load_Sfnt_Table( face, tag, 0, NULL, table_len ); + if ( error == OTV_Err_Table_Missing ) + return OTV_Err_Ok; + if ( error ) + goto Exit; + + if ( FT_ALLOC( *table, *table_len ) ) + goto Exit; + + error = FT_Load_Sfnt_Table( face, tag, 0, *table, table_len ); + + Exit: + return error; + } + + + static FT_Error + otv_validate( FT_Face face, + FT_UInt ot_flags, + FT_Bytes *ot_base, + FT_Bytes *ot_gdef, + FT_Bytes *ot_gpos, + FT_Bytes *ot_gsub, + FT_Bytes *ot_jstf ) + { + FT_Error error = OTV_Err_Ok; + FT_Byte *base, *gdef, *gpos, *gsub, *jstf; + FT_ULong len_base, len_gdef, len_gpos, len_gsub, len_jstf; + FT_ValidatorRec valid; + + + base = gdef = gpos = gsub = jstf = NULL; + len_base = len_gdef = len_gpos = len_gsub = len_jstf = 0; + + /* load tables */ + + if ( ot_flags & FT_VALIDATE_BASE ) + { + error = otv_load_table( face, TTAG_BASE, &base, &len_base ); + if ( error ) + goto Exit; + } + + if ( ot_flags & FT_VALIDATE_GDEF ) + { + error = otv_load_table( face, TTAG_GDEF, &gdef, &len_gdef ); + if ( error ) + goto Exit; + } + + if ( ot_flags & FT_VALIDATE_GPOS ) + { + error = otv_load_table( face, TTAG_GPOS, &gpos, &len_gpos ); + if ( error ) + goto Exit; + } + + if ( ot_flags & FT_VALIDATE_GSUB ) + { + error = otv_load_table( face, TTAG_GSUB, &gsub, &len_gsub ); + if ( error ) + goto Exit; + } + + if ( ot_flags & FT_VALIDATE_JSTF ) + { + error = otv_load_table( face, TTAG_JSTF, &jstf, &len_jstf ); + if ( error ) + goto Exit; + } + + /* validate tables */ + + if ( base ) + { + ft_validator_init( &valid, base, base + len_base, FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + otv_BASE_validate( base, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + if ( gpos ) + { + ft_validator_init( &valid, gpos, gpos + len_gpos, FT_VALIDATE_DEFAULT ); + if (ft_setjmp( valid.jump_buffer ) == 0 ) + otv_GPOS_validate( gpos, face->num_glyphs, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + if ( gsub ) + { + ft_validator_init( &valid, gsub, gsub + len_gsub, FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + otv_GSUB_validate( gsub, face->num_glyphs, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + if ( gdef ) + { + ft_validator_init( &valid, gdef, gdef + len_gdef, FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + otv_GDEF_validate( gdef, gsub, gpos, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + if ( jstf ) + { + ft_validator_init( &valid, jstf, jstf + len_jstf, FT_VALIDATE_DEFAULT ); + if ( ft_setjmp( valid.jump_buffer ) == 0 ) + otv_JSTF_validate( jstf, gsub, gpos, face->num_glyphs, &valid ); + error = valid.error; + if ( error ) + goto Exit; + } + + *ot_base = (FT_Bytes)base; + *ot_gdef = (FT_Bytes)gdef; + *ot_gpos = (FT_Bytes)gpos; + *ot_gsub = (FT_Bytes)gsub; + *ot_jstf = (FT_Bytes)jstf; + + Exit: + if ( error ) { + FT_Memory memory = FT_FACE_MEMORY( face ); + + + FT_FREE( base ); + FT_FREE( gdef ); + FT_FREE( gpos ); + FT_FREE( gsub ); + FT_FREE( jstf ); + } + + return error; + } + + + static + const FT_Service_OTvalidateRec otvalid_interface = + { + otv_validate + }; + + + static + const FT_ServiceDescRec otvalid_services[] = + { + { FT_SERVICE_ID_OPENTYPE_VALIDATE, &otvalid_interface }, + { NULL, NULL } + }; + + + static FT_Pointer + otvalid_get_service( FT_Module module, + const char* service_id ) + { + FT_UNUSED( module ); + + return ft_service_list_lookup( otvalid_services, service_id ); + } + + + FT_CALLBACK_TABLE_DEF + const FT_Module_Class otv_module_class = + { + 0, + sizeof( FT_ModuleRec ), + "otvalid", + 0x10000L, + 0x20000L, + + 0, /* module-specific interface */ + + (FT_Module_Constructor)0, + (FT_Module_Destructor) 0, + (FT_Module_Requester) otvalid_get_service + }; + + +/* END */ diff --git a/reactos/lib/freetype/src/otvalid/otvmod.h b/reactos/lib/freetype/src/otvalid/otvmod.h index 303655933fa..1bfc1899fe3 100644 --- a/reactos/lib/freetype/src/otvalid/otvmod.h +++ b/reactos/lib/freetype/src/otvalid/otvmod.h @@ -1,39 +1,39 @@ -/***************************************************************************/ -/* */ -/* otvmod.h */ -/* */ -/* FreeType's OpenType validation module implementation */ -/* (specification). */ -/* */ -/* Copyright 2004 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - -#ifndef __OTVMOD_H__ -#define __OTVMOD_H__ - - -#include <ft2build.h> -#include FT_MODULE_H - - -FT_BEGIN_HEADER - - - FT_EXPORT_VAR( const FT_Module_Class ) otv_module_class; - - -FT_END_HEADER - -#endif /* __OTVMOD_H__ */ - - -/* END */ +/***************************************************************************/ +/* */ +/* otvmod.h */ +/* */ +/* FreeType's OpenType validation module implementation */ +/* (specification). */ +/* */ +/* Copyright 2004 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __OTVMOD_H__ +#define __OTVMOD_H__ + + +#include <ft2build.h> +#include FT_MODULE_H + + +FT_BEGIN_HEADER + + + FT_EXPORT_VAR( const FT_Module_Class ) otv_module_class; + + +FT_END_HEADER + +#endif /* __OTVMOD_H__ */ + + +/* END */ diff --git a/reactos/lib/freetype/src/raster/ftmisc.h b/reactos/lib/freetype/src/raster/ftmisc.h index 927ac4ce952..c5dbd50d003 100644 --- a/reactos/lib/freetype/src/raster/ftmisc.h +++ b/reactos/lib/freetype/src/raster/ftmisc.h @@ -1,83 +1,83 @@ -/***************************************************************************/ -/* */ -/* ftmisc.h */ -/* */ -/* Miscellaneous macros for stand-alone rasterizer (specification */ -/* only). */ -/* */ -/* Copyright 2005 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used */ -/* modified and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - - /***************************************************/ - /* */ - /* This file is *not* portable! You have to adapt */ - /* its definitions to your platform. */ - /* */ - /***************************************************/ - -#ifndef __FTMISC_H__ -#define __FTMISC_H__ - -#include <string.h> /* memset */ - -#define FT_BEGIN_HEADER -#define FT_END_HEADER - -#define FT_LOCAL_DEF( x ) static x - - /* from include/freetype2/fttypes.h */ - - typedef unsigned char FT_Byte; - typedef signed int FT_Int; - typedef unsigned int FT_UInt; - typedef signed long FT_Long; - typedef unsigned long FT_ULong; - typedef signed long FT_F26Dot6; - typedef int FT_Error; - -#define FT_MAKE_TAG( _x1, _x2, _x3, _x4 ) \ - ( ( (FT_ULong)_x1 << 24 ) | \ - ( (FT_ULong)_x2 << 16 ) | \ - ( (FT_ULong)_x3 << 8 ) | \ - (FT_ULong)_x4 ) - - - /* from src/ftcalc.c */ - -#include <inttypes.h> - - typedef int64_t FT_Int64; - - static FT_Long - FT_MulDiv( FT_Long a, - FT_Long b, - FT_Long c ) - { - FT_Int s; - FT_Long d; - - - s = 1; - if ( a < 0 ) { a = -a; s = -1; } - if ( b < 0 ) { b = -b; s = -s; } - if ( c < 0 ) { c = -c; s = -s; } - - d = (FT_Long)( c > 0 ? ( (FT_Int64)a * b + ( c >> 1 ) ) / c - : 0x7FFFFFFFL ); - - return ( s > 0 ) ? d : -d; - } - -#endif /* __FTMISC_H__ */ - - -/* END */ +/***************************************************************************/ +/* */ +/* ftmisc.h */ +/* */ +/* Miscellaneous macros for stand-alone rasterizer (specification */ +/* only). */ +/* */ +/* Copyright 2005 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used */ +/* modified and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + + /***************************************************/ + /* */ + /* This file is *not* portable! You have to adapt */ + /* its definitions to your platform. */ + /* */ + /***************************************************/ + +#ifndef __FTMISC_H__ +#define __FTMISC_H__ + +#include <string.h> /* memset */ + +#define FT_BEGIN_HEADER +#define FT_END_HEADER + +#define FT_LOCAL_DEF( x ) static x + + /* from include/freetype2/fttypes.h */ + + typedef unsigned char FT_Byte; + typedef signed int FT_Int; + typedef unsigned int FT_UInt; + typedef signed long FT_Long; + typedef unsigned long FT_ULong; + typedef signed long FT_F26Dot6; + typedef int FT_Error; + +#define FT_MAKE_TAG( _x1, _x2, _x3, _x4 ) \ + ( ( (FT_ULong)_x1 << 24 ) | \ + ( (FT_ULong)_x2 << 16 ) | \ + ( (FT_ULong)_x3 << 8 ) | \ + (FT_ULong)_x4 ) + + + /* from src/ftcalc.c */ + +#include <inttypes.h> + + typedef int64_t FT_Int64; + + static FT_Long + FT_MulDiv( FT_Long a, + FT_Long b, + FT_Long c ) + { + FT_Int s; + FT_Long d; + + + s = 1; + if ( a < 0 ) { a = -a; s = -1; } + if ( b < 0 ) { b = -b; s = -s; } + if ( c < 0 ) { c = -c; s = -s; } + + d = (FT_Long)( c > 0 ? ( (FT_Int64)a * b + ( c >> 1 ) ) / c + : 0x7FFFFFFFL ); + + return ( s > 0 ) ? d : -d; + } + +#endif /* __FTMISC_H__ */ + + +/* END */ diff --git a/reactos/lib/freetype/src/sfnt/ttcmap.c b/reactos/lib/freetype/src/sfnt/ttcmap.c index e095ab4bbf6..0f3a3241ce5 100644 --- a/reactos/lib/freetype/src/sfnt/ttcmap.c +++ b/reactos/lib/freetype/src/sfnt/ttcmap.c @@ -1,2214 +1,2214 @@ -/***************************************************************************/ -/* */ -/* ttcmap.c */ -/* */ -/* TrueType character mapping table (cmap) support (body). */ -/* */ -/* Copyright 2002, 2003, 2004, 2005 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - -#include <ft2build.h> -#include FT_INTERNAL_DEBUG_H - -#include "sferrors.h" /* must come before FT_INTERNAL_VALIDATE_H */ - -#include FT_INTERNAL_VALIDATE_H -#include FT_INTERNAL_STREAM_H -#include "ttload.h" -#include "ttcmap.h" - - - /*************************************************************************/ - /* */ - /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ - /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ - /* messages during execution. */ - /* */ -#undef FT_COMPONENT -#define FT_COMPONENT trace_ttcmap - - -#define TT_PEEK_SHORT FT_PEEK_SHORT -#define TT_PEEK_USHORT FT_PEEK_USHORT -#define TT_PEEK_LONG FT_PEEK_LONG -#define TT_PEEK_ULONG FT_PEEK_ULONG - -#define TT_NEXT_SHORT FT_NEXT_SHORT -#define TT_NEXT_USHORT FT_NEXT_USHORT -#define TT_NEXT_LONG FT_NEXT_LONG -#define TT_NEXT_ULONG FT_NEXT_ULONG - - - FT_CALLBACK_DEF( FT_Error ) - tt_cmap_init( TT_CMap cmap, - FT_Byte* table ) - { - cmap->data = table; - return SFNT_Err_Ok; - } - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** FORMAT 0 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /*************************************************************************/ - /* */ - /* TABLE OVERVIEW */ - /* -------------- */ - /* */ - /* NAME OFFSET TYPE DESCRIPTION */ - /* */ - /* format 0 USHORT must be 0 */ - /* length 2 USHORT table length in bytes */ - /* language 4 USHORT Mac language code */ - /* glyph_ids 6 BYTE[256] array of glyph indices */ - /* 262 */ - /* */ - -#ifdef TT_CONFIG_CMAP_FORMAT_0 - - FT_CALLBACK_DEF( FT_Error ) - tt_cmap0_validate( FT_Byte* table, - FT_Validator valid ) - { - FT_Byte* p = table + 2; - FT_UInt length = TT_NEXT_USHORT( p ); - - - if ( table + length > valid->limit || length < 262 ) - FT_INVALID_TOO_SHORT; - - /* check glyph indices whenever necessary */ - if ( valid->level >= FT_VALIDATE_TIGHT ) - { - FT_UInt n, idx; - - - p = table + 6; - for ( n = 0; n < 256; n++ ) - { - idx = *p++; - if ( idx >= TT_VALID_GLYPH_COUNT( valid ) ) - FT_INVALID_GLYPH_ID; - } - } - - return SFNT_Err_Ok; - } - - - FT_CALLBACK_DEF( FT_UInt ) - tt_cmap0_char_index( TT_CMap cmap, - FT_UInt32 char_code ) - { - FT_Byte* table = cmap->data; - - - return char_code < 256 ? table[6 + char_code] : 0; - } - - - FT_CALLBACK_DEF( FT_UInt ) - tt_cmap0_char_next( TT_CMap cmap, - FT_UInt32 *pchar_code ) - { - FT_Byte* table = cmap->data; - FT_UInt32 charcode = *pchar_code; - FT_UInt32 result = 0; - FT_UInt gindex = 0; - - - table += 6; /* go to glyph ids */ - while ( ++charcode < 256 ) - { - gindex = table[charcode]; - if ( gindex != 0 ) - { - result = charcode; - break; - } - } - - *pchar_code = result; - return gindex; - } - - - FT_CALLBACK_DEF( FT_Error ) - tt_cmap0_get_info( TT_CMap cmap, - TT_CMapInfo *cmap_info ) - { - FT_Byte* p = cmap->data + 4; - - - cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); - - return SFNT_Err_Ok; - } - - - FT_CALLBACK_TABLE_DEF - const TT_CMap_ClassRec tt_cmap0_class_rec = - { - { - sizeof ( TT_CMapRec ), - - (FT_CMap_InitFunc) tt_cmap_init, - (FT_CMap_DoneFunc) NULL, - (FT_CMap_CharIndexFunc)tt_cmap0_char_index, - (FT_CMap_CharNextFunc) tt_cmap0_char_next - }, - 0, - (TT_CMap_ValidateFunc) tt_cmap0_validate, - (TT_CMap_Info_GetFunc) tt_cmap0_get_info - }; - -#endif /* TT_CONFIG_CMAP_FORMAT_0 */ - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** FORMAT 2 *****/ - /***** *****/ - /***** This is used for certain CJK encodings that encode text in a *****/ - /***** mixed 8/16 bits encoding along the following lines: *****/ - /***** *****/ - /***** * Certain byte values correspond to an 8-bit character code *****/ - /***** (typically in the range 0..127 for ASCII compatibility). *****/ - /***** *****/ - /***** * Certain byte values signal the first byte of a 2-byte *****/ - /***** character code (but these values are also valid as the *****/ - /***** second byte of a 2-byte character). *****/ - /***** *****/ - /***** The following charmap lookup and iteration functions all *****/ - /***** assume that the value "charcode" correspond to following: *****/ - /***** *****/ - /***** - For one byte characters, "charcode" is simply the *****/ - /***** character code. *****/ - /***** *****/ - /***** - For two byte characters, "charcode" is the 2-byte *****/ - /***** character code in big endian format. More exactly: *****/ - /***** *****/ - /***** (charcode >> 8) is the first byte value *****/ - /***** (charcode & 0xFF) is the second byte value *****/ - /***** *****/ - /***** Note that not all values of "charcode" are valid according *****/ - /***** to these rules, and the function moderately check the *****/ - /***** arguments. *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /*************************************************************************/ - /* */ - /* TABLE OVERVIEW */ - /* -------------- */ - /* */ - /* NAME OFFSET TYPE DESCRIPTION */ - /* */ - /* format 0 USHORT must be 2 */ - /* length 2 USHORT table length in bytes */ - /* language 4 USHORT Mac language code */ - /* keys 6 USHORT[256] sub-header keys */ - /* subs 518 SUBHEAD[NSUBS] sub-headers array */ - /* glyph_ids 518+NSUB*8 USHORT[] glyph id array */ - /* */ - /* The `keys' table is used to map charcode high-bytes to sub-headers. */ - /* The value of `NSUBS' is the number of sub-headers defined in the */ - /* table and is computed by finding the maximum of the `keys' table. */ - /* */ - /* Note that for any n, `keys[n]' is a byte offset within the `subs' */ - /* table, i.e., it is the corresponding sub-header index multiplied */ - /* by 8. */ - /* */ - /* Each sub-header has the following format: */ - /* */ - /* NAME OFFSET TYPE DESCRIPTION */ - /* */ - /* first 0 USHORT first valid low-byte */ - /* count 2 USHORT number of valid low-bytes */ - /* delta 4 SHORT see below */ - /* offset 6 USHORT see below */ - /* */ - /* A sub-header defines, for each high-byte, the range of valid */ - /* low-bytes within the charmap. Note that the range defined by `first' */ - /* and `count' must be completely included in the interval [0..255] */ - /* according to the specification. */ - /* */ - /* If a character code is contained within a given sub-header, then */ - /* mapping it to a glyph index is done as follows: */ - /* */ - /* * The value of `offset' is read. This is a _byte_ distance from the */ - /* location of the `offset' field itself into a slice of the */ - /* `glyph_ids' table. Let's call it `slice' (it's a USHORT[] too). */ - /* */ - /* * The value `slice[char.lo - first]' is read. If it is 0, there is */ - /* no glyph for the charcode. Otherwise, the value of `delta' is */ - /* added to it (modulo 65536) to form a new glyph index. */ - /* */ - /* It is up to the validation routine to check that all offsets fall */ - /* within the glyph ids table (and not within the `subs' table itself or */ - /* outside of the CMap). */ - /* */ - -#ifdef TT_CONFIG_CMAP_FORMAT_2 - - FT_CALLBACK_DEF( FT_Error ) - tt_cmap2_validate( FT_Byte* table, - FT_Validator valid ) - { - FT_Byte* p = table + 2; /* skip format */ - FT_UInt length = TT_PEEK_USHORT( p ); - FT_UInt n, max_subs; - FT_Byte* keys; /* keys table */ - FT_Byte* subs; /* sub-headers */ - FT_Byte* glyph_ids; /* glyph id array */ - - - if ( table + length > valid->limit || length < 6 + 512 ) - FT_INVALID_TOO_SHORT; - - keys = table + 6; - - /* parse keys to compute sub-headers count */ - p = keys; - max_subs = 0; - for ( n = 0; n < 256; n++ ) - { - FT_UInt idx = TT_NEXT_USHORT( p ); - - - /* value must be multiple of 8 */ - if ( valid->level >= FT_VALIDATE_PARANOID && ( idx & 7 ) != 0 ) - FT_INVALID_DATA; - - idx >>= 3; - - if ( idx > max_subs ) - max_subs = idx; - } - - FT_ASSERT( p == table + 518 ); - - subs = p; - glyph_ids = subs + (max_subs + 1) * 8; - if ( glyph_ids > valid->limit ) - FT_INVALID_TOO_SHORT; - - /* parse sub-headers */ - for ( n = 0; n <= max_subs; n++ ) - { - FT_UInt first_code, code_count, offset; - FT_Int delta; - FT_Byte* ids; - - - first_code = TT_NEXT_USHORT( p ); - code_count = TT_NEXT_USHORT( p ); - delta = TT_NEXT_SHORT( p ); - offset = TT_NEXT_USHORT( p ); - - /* check range within 0..255 */ - if ( valid->level >= FT_VALIDATE_PARANOID ) - { - if ( first_code >= 256 || first_code + code_count > 256 ) - FT_INVALID_DATA; - } - - /* check offset */ - if ( offset != 0 ) - { - ids = p - 2 + offset; - if ( ids < glyph_ids || ids + code_count*2 > table + length ) - FT_INVALID_OFFSET; - - /* check glyph ids */ - if ( valid->level >= FT_VALIDATE_TIGHT ) - { - FT_Byte* limit = p + code_count * 2; - FT_UInt idx; - - - for ( ; p < limit; ) - { - idx = TT_NEXT_USHORT( p ); - if ( idx != 0 ) - { - idx = ( idx + delta ) & 0xFFFFU; - if ( idx >= TT_VALID_GLYPH_COUNT( valid ) ) - FT_INVALID_GLYPH_ID; - } - } - } - } - } - - return SFNT_Err_Ok; - } - - - /* return sub header corresponding to a given character code */ - /* NULL on invalid charcode */ - static FT_Byte* - tt_cmap2_get_subheader( FT_Byte* table, - FT_UInt32 char_code ) - { - FT_Byte* result = NULL; - - - if ( char_code < 0x10000UL ) - { - FT_UInt char_lo = (FT_UInt)( char_code & 0xFF ); - FT_UInt char_hi = (FT_UInt)( char_code >> 8 ); - FT_Byte* p = table + 6; /* keys table */ - FT_Byte* subs = table + 518; /* subheaders table */ - FT_Byte* sub; - - - if ( char_hi == 0 ) - { - /* an 8-bit character code -- we use subHeader 0 in this case */ - /* to test whether the character code is in the charmap */ - /* */ - sub = subs; /* jump to first sub-header */ - - /* check that the sub-header for this byte is 0, which */ - /* indicates that it's really a valid one-byte value */ - /* Otherwise, return 0 */ - /* */ - p += char_lo * 2; - if ( TT_PEEK_USHORT( p ) != 0 ) - goto Exit; - } - else - { - /* a 16-bit character code */ - - /* jump to key entry */ - p += char_hi * 2; - /* jump to sub-header */ - sub = subs + ( FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 8 ) ); - - /* check that the high byte isn't a valid one-byte value */ - if ( sub == subs ) - goto Exit; - } - result = sub; - } - Exit: - return result; - } - - - FT_CALLBACK_DEF( FT_UInt ) - tt_cmap2_char_index( TT_CMap cmap, - FT_UInt32 char_code ) - { - FT_Byte* table = cmap->data; - FT_UInt result = 0; - FT_Byte* subheader; - - - subheader = tt_cmap2_get_subheader( table, char_code ); - if ( subheader ) - { - FT_Byte* p = subheader; - FT_UInt idx = (FT_UInt)(char_code & 0xFF); - FT_UInt start, count; - FT_Int delta; - FT_UInt offset; - - - start = TT_NEXT_USHORT( p ); - count = TT_NEXT_USHORT( p ); - delta = TT_NEXT_SHORT ( p ); - offset = TT_PEEK_USHORT( p ); - - idx -= start; - if ( idx < count && offset != 0 ) - { - p += offset + 2 * idx; - idx = TT_PEEK_USHORT( p ); - - if ( idx != 0 ) - result = (FT_UInt)( idx + delta ) & 0xFFFFU; - } - } - return result; - } - - - FT_CALLBACK_DEF( FT_UInt ) - tt_cmap2_char_next( TT_CMap cmap, - FT_UInt32 *pcharcode ) - { - FT_Byte* table = cmap->data; - FT_UInt gindex = 0; - FT_UInt32 result = 0; - FT_UInt32 charcode = *pcharcode + 1; - FT_Byte* subheader; - - - while ( charcode < 0x10000UL ) - { - subheader = tt_cmap2_get_subheader( table, charcode ); - if ( subheader ) - { - FT_Byte* p = subheader; - FT_UInt start = TT_NEXT_USHORT( p ); - FT_UInt count = TT_NEXT_USHORT( p ); - FT_Int delta = TT_NEXT_SHORT ( p ); - FT_UInt offset = TT_PEEK_USHORT( p ); - FT_UInt char_lo = (FT_UInt)( charcode & 0xFF ); - FT_UInt pos, idx; - - - if ( offset == 0 ) - goto Next_SubHeader; - - if ( char_lo < start ) - { - char_lo = start; - pos = 0; - } - else - pos = (FT_UInt)( char_lo - start ); - - p += offset + pos * 2; - charcode = FT_PAD_FLOOR( charcode, 256 ) + char_lo; - - for ( ; pos < count; pos++, charcode++ ) - { - idx = TT_NEXT_USHORT( p ); - - if ( idx != 0 ) - { - gindex = ( idx + delta ) & 0xFFFFU; - if ( gindex != 0 ) - { - result = charcode; - goto Exit; - } - } - } - } - - /* jump to next sub-header, i.e. higher byte value */ - Next_SubHeader: - charcode = FT_PAD_FLOOR( charcode, 256 ) + 256; - } - - Exit: - *pcharcode = result; - - return gindex; - } - - - FT_CALLBACK_DEF( FT_Error ) - tt_cmap2_get_info( TT_CMap cmap, - TT_CMapInfo *cmap_info ) - { - FT_Byte* p = cmap->data + 4; - - - cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); - - return SFNT_Err_Ok; - } - - - FT_CALLBACK_TABLE_DEF - const TT_CMap_ClassRec tt_cmap2_class_rec = - { - { - sizeof ( TT_CMapRec ), - - (FT_CMap_InitFunc) tt_cmap_init, - (FT_CMap_DoneFunc) NULL, - (FT_CMap_CharIndexFunc)tt_cmap2_char_index, - (FT_CMap_CharNextFunc) tt_cmap2_char_next - }, - 2, - (TT_CMap_ValidateFunc) tt_cmap2_validate, - (TT_CMap_Info_GetFunc) tt_cmap2_get_info - }; - -#endif /* TT_CONFIG_CMAP_FORMAT_2 */ - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** FORMAT 4 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /*************************************************************************/ - /* */ - /* TABLE OVERVIEW */ - /* -------------- */ - /* */ - /* NAME OFFSET TYPE DESCRIPTION */ - /* */ - /* format 0 USHORT must be 4 */ - /* length 2 USHORT table length */ - /* in bytes */ - /* language 4 USHORT Mac language code */ - /* */ - /* segCountX2 6 USHORT 2*NUM_SEGS */ - /* searchRange 8 USHORT 2*(1 << LOG_SEGS) */ - /* entrySelector 10 USHORT LOG_SEGS */ - /* rangeShift 12 USHORT segCountX2 - */ - /* searchRange */ - /* */ - /* endCount 14 USHORT[NUM_SEGS] end charcode for */ - /* each segment; last */ - /* is 0xFFFF */ - /* */ - /* pad 14+NUM_SEGS*2 USHORT padding */ - /* */ - /* startCount 16+NUM_SEGS*2 USHORT[NUM_SEGS] first charcode for */ - /* each segment */ - /* */ - /* idDelta 16+NUM_SEGS*4 SHORT[NUM_SEGS] delta for each */ - /* segment */ - /* idOffset 16+NUM_SEGS*6 SHORT[NUM_SEGS] range offset for */ - /* each segment; can be */ - /* zero */ - /* */ - /* glyphIds 16+NUM_SEGS*8 USHORT[] array of glyph id */ - /* ranges */ - /* */ - /* Character codes are modelled by a series of ordered (increasing) */ - /* intervals called segments. Each segment has start and end codes, */ - /* provided by the `startCount' and `endCount' arrays. Segments must */ - /* not be overlapping and the last segment should always contain the */ - /* `0xFFFF' endCount. */ - /* */ - /* The fields `searchRange', `entrySelector' and `rangeShift' are better */ - /* ignored (they are traces of over-engineering in the TrueType */ - /* specification). */ - /* */ - /* Each segment also has a signed `delta', as well as an optional offset */ - /* within the `glyphIds' table. */ - /* */ - /* If a segment's idOffset is 0, the glyph index corresponding to any */ - /* charcode within the segment is obtained by adding the value of */ - /* `idDelta' directly to the charcode, modulo 65536. */ - /* */ - /* Otherwise, a glyph index is taken from the glyph ids sub-array for */ - /* the segment, and the value of `idDelta' is added to it. */ - /* */ - /* */ - /* Finally, note that certain fonts contain invalid charmaps that */ - /* contain end=0xFFFF, start=0xFFFF, delta=0x0001, offset=0xFFFF at the */ - /* of their charmaps (e.g. opens___.ttf which comes with OpenOffice.org) */ - /* we need special code to deal with them correctly... */ - /* */ - -#ifdef TT_CONFIG_CMAP_FORMAT_4 - -#define OPT_CMAP4 - -#ifdef OPT_CMAP4 - - typedef struct TT_CMap4Rec_ - { - TT_CMapRec cmap; - FT_UInt32 old_charcode; /* old charcode */ - FT_UInt32 cur_charcode; /* current charcode */ - FT_UInt cur_gindex; /* current glyph index */ - - FT_UInt table_length; - FT_UInt num_ranges; - FT_UInt cur_range; - FT_UInt cur_start; - FT_UInt cur_end; - FT_Int cur_delta; - FT_Byte* cur_values; - - } TT_CMap4Rec, *TT_CMap4; - - - FT_CALLBACK_DEF( FT_Error ) - tt_cmap4_init( TT_CMap4 cmap, - FT_Byte* table ) - { - FT_Byte* p; - - - cmap->cmap.data = table; - - p = table + 2; - cmap->table_length = FT_PEEK_USHORT( p ); - - p = table + 6; - cmap->num_ranges = FT_PEEK_USHORT( p ) >> 1; - cmap->cur_range = cmap->num_ranges; - cmap->old_charcode = 0xFFFFFFFFUL; - cmap->cur_charcode = 0; - cmap->cur_gindex = 0; - - return SFNT_Err_Ok; - } - - - static FT_Int - tt_cmap4_set_range( TT_CMap4 cmap, - FT_UInt range_index ) - { - FT_Byte* table = cmap->cmap.data; - FT_Byte* p; - FT_UInt num_ranges = cmap->num_ranges; - - - while ( range_index < num_ranges ) - { - FT_UInt offset; - - - p = table + 14 + range_index * 2; - cmap->cur_end = FT_PEEK_USHORT( p ); - - p += 2 + num_ranges * 2; - cmap->cur_start = FT_PEEK_USHORT( p ); - - p += num_ranges * 2; - cmap->cur_delta = FT_PEEK_SHORT( p ); - - p += num_ranges * 2; - offset = FT_PEEK_USHORT( p ); - - if ( offset != 0xFFFFU ) - { - cmap->cur_values = offset ? p + offset : NULL; - cmap->cur_range = range_index; - return 0; - } - - /* we skip empty segments */ - range_index++; - } - - cmap->old_charcode = 0xFFFFFFFFUL; - cmap->cur_charcode = 0; - cmap->cur_gindex = 0; - cmap->cur_range = num_ranges; - return -1; - } - - - static void - tt_cmap4_next( TT_CMap4 cmap ) - { - FT_UInt charcode = cmap->cur_charcode + 1; - - - cmap->old_charcode = cmap->cur_charcode; - - for ( ;; ) - { - FT_Byte* values = cmap->cur_values; - FT_UInt end = cmap->cur_end; - FT_Int delta = cmap->cur_delta; - - - if ( charcode <= end ) - { - if ( values ) - { - FT_Byte* p = values + 2 * ( charcode - cmap->cur_start ); - - - do - { - FT_UInt gindex = FT_NEXT_USHORT( p ); - - - if ( gindex != 0 ) - { - gindex = (FT_UInt)( ( gindex + delta ) & 0xFFFFU ); - if ( gindex != 0 ) - { - cmap->cur_charcode = charcode; - cmap->cur_gindex = gindex; - return; - } - } - } while ( ++charcode <= end ); - } - else - { - do - { - FT_UInt gindex = (FT_UInt)( ( charcode + delta ) & 0xFFFFU ); - - - if ( gindex != 0 ) - { - cmap->cur_charcode = charcode; - cmap->cur_gindex = gindex; - return; - } - } while ( ++charcode <= end ); - } - } - - /* we need to find another range */ - if ( tt_cmap4_set_range( cmap, cmap->cur_range + 1 ) < 0 ) - break; - - charcode = cmap->cur_start; - } - } - - - static void - tt_cmap4_reset( TT_CMap4 cmap, - FT_UInt code, - FT_UInt range_index ) - { - if ( tt_cmap4_set_range( cmap, range_index ) >= 0 ) - { - cmap->cur_charcode = code; - tt_cmap4_next( cmap ); - } - } - -#endif /* OPT_CMAP4 */ - - - - FT_CALLBACK_DEF( FT_Error ) - tt_cmap4_validate( FT_Byte* table, - FT_Validator valid ) - { - FT_Byte* p = table + 2; /* skip format */ - FT_UInt length = TT_NEXT_USHORT( p ); - FT_Byte *ends, *starts, *offsets, *deltas, *glyph_ids; - FT_UInt num_segs; - FT_Error error = SFNT_Err_Ok; - - - /* in certain fonts, the `length' field is invalid and goes */ - /* out of bound. We try to correct this here... */ - if ( length < 16 ) - FT_INVALID_TOO_SHORT; - - if ( table + length > valid->limit ) - { - if ( valid->level >= FT_VALIDATE_TIGHT ) - FT_INVALID_TOO_SHORT; - - length = (FT_UInt)( valid->limit - table ); - } - - p = table + 6; - num_segs = TT_NEXT_USHORT( p ); /* read segCountX2 */ - - if ( valid->level >= FT_VALIDATE_PARANOID ) - { - /* check that we have an even value here */ - if ( num_segs & 1 ) - FT_INVALID_DATA; - } - - num_segs /= 2; - - /* check the search parameters - even though we never use them */ - /* */ - if ( valid->level >= FT_VALIDATE_PARANOID ) - { - /* check the values of 'searchRange', 'entrySelector', 'rangeShift' */ - FT_UInt search_range = TT_NEXT_USHORT( p ); - FT_UInt entry_selector = TT_NEXT_USHORT( p ); - FT_UInt range_shift = TT_NEXT_USHORT( p ); - - - if ( ( search_range | range_shift ) & 1 ) /* must be even values */ - FT_INVALID_DATA; - - search_range /= 2; - range_shift /= 2; - - /* `search range' is the greatest power of 2 that is <= num_segs */ - - if ( search_range > num_segs || - search_range * 2 < num_segs || - search_range + range_shift != num_segs || - search_range != ( 1U << entry_selector ) ) - FT_INVALID_DATA; - } - - ends = table + 14; - starts = table + 16 + num_segs * 2; - deltas = starts + num_segs * 2; - offsets = deltas + num_segs * 2; - glyph_ids = offsets + num_segs * 2; - - if ( glyph_ids > table + length ) - FT_INVALID_TOO_SHORT; - - /* check last segment, its end count must be FFFF */ - if ( valid->level >= FT_VALIDATE_PARANOID ) - { - p = ends + ( num_segs - 1 ) * 2; - if ( TT_PEEK_USHORT( p ) != 0xFFFFU ) - FT_INVALID_DATA; - } - - /* check that segments are sorted in increasing order and do not */ - /* overlap; check also the offsets */ - { - FT_UInt start, end, last = 0, offset, n; - FT_Int delta; - - - for ( n = 0; n < num_segs; n++ ) - { - p = starts + n * 2; - start = TT_PEEK_USHORT( p ); - p = ends + n * 2; - end = TT_PEEK_USHORT( p ); - p = deltas + n * 2; - delta = TT_PEEK_SHORT( p ); - p = offsets + n * 2; - offset = TT_PEEK_USHORT( p ); - - if ( start > end ) - FT_INVALID_DATA; - - /* this test should be performed at default validation level; */ - /* unfortunately, some popular Asian fonts present overlapping */ - /* ranges in their charmaps */ - /* */ - if ( n > 0 && start <= last ) - { - if ( valid->level >= FT_VALIDATE_TIGHT ) - FT_INVALID_DATA; - else - error = SFNT_Err_Invalid_CharMap_Format; - } - - if ( offset && offset != 0xFFFFU ) - { - p += offset; /* start of glyph id array */ - - /* check that we point within the glyph ids table only */ - if ( valid->level >= FT_VALIDATE_TIGHT ) - { - if ( p < glyph_ids || - p + ( end - start + 1 ) * 2 > table + length ) - FT_INVALID_DATA; - } - else - { - if ( p < glyph_ids || - p + ( end - start + 1 ) * 2 > valid->limit ) - FT_INVALID_DATA; - } - - /* check glyph indices within the segment range */ - if ( valid->level >= FT_VALIDATE_TIGHT ) - { - FT_UInt i, idx; - - - for ( i = start; i < end; i++ ) - { - idx = FT_NEXT_USHORT( p ); - if ( idx != 0 ) - { - idx = (FT_UInt)( idx + delta ) & 0xFFFFU; - - if ( idx >= TT_VALID_GLYPH_COUNT( valid ) ) - FT_INVALID_GLYPH_ID; - } - } - } - } - else if ( offset == 0xFFFFU ) - { - /* Some fonts (erroneously?) use a range offset of 0xFFFF */ - /* to mean missing glyph in cmap table */ - /* */ - if ( valid->level >= FT_VALIDATE_PARANOID || - n != num_segs - 1 || - !( start == 0xFFFFU && end == 0xFFFFU && delta == 0x1U ) ) - FT_INVALID_DATA; - } - - last = end; - } - } - - return error; - } - - - FT_CALLBACK_DEF( FT_UInt ) - tt_cmap4_char_index( TT_CMap cmap, - FT_UInt32 char_code ) - { - FT_Byte* table = cmap->data; - FT_UInt result = 0; - - - if ( char_code < 0x10000UL ) - { - FT_UInt idx, num_segs2; - FT_Int delta; - FT_UInt code = (FT_UInt)char_code; - FT_Byte* p; - - p = table + 6; - num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 ); /* be paranoid! */ - - if ( !cmap->unsorted ) - { - /* Some fonts have more than 170 segments in their charmaps! */ - /* We changed this function to use a more efficient binary */ - /* search for improving performance */ - FT_UInt min = 0; - FT_UInt max = num_segs2 >> 1; - FT_UInt mid, start, end, offset; - - - while ( min < max ) - { - mid = ( min + max ) >> 1; - p = table + 14 + mid * 2; - end = TT_NEXT_USHORT( p ); - p += num_segs2; - start = TT_PEEK_USHORT( p); - - if ( code < start ) - max = mid; - else if ( code > end ) - min = mid + 1; - else - { - /* we found the segment */ - idx = code; - - p += num_segs2; - delta = TT_PEEK_SHORT( p ); - - p += num_segs2; - offset = TT_PEEK_USHORT( p ); - - if ( offset == 0xFFFFU ) - goto Exit; - - if ( offset != 0 ) - { - p += offset + 2 * ( idx - start ); - idx = TT_PEEK_USHORT( p ); - } - - if ( idx != 0 ) - result = (FT_UInt)( idx + delta ) & 0xFFFFU; - - goto Exit; - } - } - } - else - { - FT_UInt n; - FT_Byte* q; - - - p = table + 14; /* ends table */ - q = table + 16 + num_segs2; /* starts table */ - - - for ( n = 0; n < num_segs2; n += 2 ) - { - FT_UInt end = TT_NEXT_USHORT( p ); - FT_UInt start = TT_NEXT_USHORT( q ); - FT_UInt offset; - - - if ( code < start ) - break; - - if ( code <= end ) - { - idx = code; - - p = q + num_segs2 - 2; - delta = TT_PEEK_SHORT( p ); - p += num_segs2; - offset = TT_PEEK_USHORT( p ); - - if ( offset == 0xFFFFU ) - goto Exit; - - if ( offset != 0 ) - { - p += offset + 2 * ( idx - start ); - idx = TT_PEEK_USHORT( p ); - } - - if ( idx != 0 ) - result = (FT_UInt)( idx + delta ) & 0xFFFFU; - } - } - } - } - - Exit: - return result; - } - - - FT_CALLBACK_DEF( FT_UInt ) - tt_cmap4_char_next( TT_CMap cmap, - FT_UInt32 *pchar_code ) - { - FT_Byte* table = cmap->data; - FT_UInt32 result = 0; - FT_UInt gindex = 0; - FT_UInt32 char_code = *pchar_code; - FT_Byte* p; - FT_UInt code, num_segs2; - - - if ( char_code >= 0xFFFFUL ) - goto Exit; - -#ifdef OPT_CMAP4 - { - TT_CMap4 cmap4 = (TT_CMap4)cmap; - - - if ( char_code == cmap4->old_charcode ) - { - result = cmap4->cur_charcode; - gindex = cmap4->cur_gindex; - if ( result != 0 ) - { - tt_cmap4_next( cmap4 ); - goto Exit; - } - } - } -#endif /* OPT_CMAP4 */ - - code = (FT_UInt)char_code + 1; - p = table + 6; - num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 ); /* ensure even-ness */ - - if ( !cmap->unsorted ) - { - for (;;) - { - /* Some fonts have more than 170 segments in their charmaps! */ - /* We changed this function to use a more efficient binary */ - /* search */ - FT_UInt offset; - FT_Int delta; - FT_UInt min = 0; - FT_UInt max = num_segs2 >> 1; - FT_UInt mid, start, end; - FT_UInt hi; - - - /* we begin by finding the segment which end is - closer to our code point */ - hi = max + 1; - while ( min < max ) - { - mid = ( min + max ) >> 1; - p = table + 14 + mid * 2; - end = TT_PEEK_USHORT( p ); - - if ( end < code ) - min = mid + 1; - else - { - hi = mid; - max = mid; - } - } - - if ( hi > max ) - { - /* the point is behind the last segment; - we will exit right now */ - goto Exit; - } - - p = table + 14 + hi * 2; - end = TT_PEEK_USHORT( p ); - - p += 2 + num_segs2; - start = TT_PEEK_USHORT( p ); - - if ( code < start ) - code = start; - - p += num_segs2; - delta = TT_PEEK_USHORT( p ); - - p += num_segs2; - offset = TT_PEEK_USHORT( p ); - - if ( offset != 0 && offset != 0xFFFFU ) - { - /* parse the glyph ids array for non-zero index */ - p += offset + ( code - start ) * 2; - while ( code <= end ) - { - gindex = TT_NEXT_USHORT( p ); - if ( gindex != 0 ) - { - gindex = (FT_UInt)( gindex + delta ) & 0xFFFFU; - if ( gindex != 0 ) - { - result = code; -#ifdef OPT_CMAP4 - tt_cmap4_reset( (TT_CMap4)cmap, code, hi ); -#endif - goto Exit; - } - } - code++; - } - } - else if ( offset == 0xFFFFU ) - { - /* an offset of 0xFFFF means an empty segment in certain fonts! */ - code = end + 1; - } - else /* offset == 0 */ - { - gindex = (FT_UInt)( code + delta ) & 0xFFFFU; - if ( gindex != 0 ) - { - result = code; -#ifdef OPT_CMAP4 - tt_cmap4_reset( (TT_CMap4)cmap, code, hi ); -#endif - goto Exit; - } - code++; - } - } - } - else - { - for ( ;; ) - { - FT_UInt offset, n; - FT_Int delta; - FT_Byte* q; - - - p = table + 14; /* ends table */ - q = table + 16 + num_segs2; /* starts table */ - - for ( n = 0; n < num_segs2; n += 2 ) - { - FT_UInt end = TT_NEXT_USHORT( p ); - FT_UInt start = TT_NEXT_USHORT( q ); - - - if ( code < start ) - code = start; - - if ( code <= end ) - { - p = q + num_segs2 - 2; - delta = TT_PEEK_SHORT( p ); - p += num_segs2; - offset = TT_PEEK_USHORT( p ); - - if ( offset != 0 && offset != 0xFFFFU ) - { - /* parse the glyph ids array for non-0 index */ - p += offset + ( code - start ) * 2; - while ( code <= end ) - { - gindex = TT_NEXT_USHORT( p ); - if ( gindex != 0 ) - { - gindex = (FT_UInt)( gindex + delta ) & 0xFFFFU; - if ( gindex != 0 ) - break; - } - code++; - } - } - else if ( offset == 0xFFFFU ) - { - /* an offset of 0xFFFF means an empty glyph in certain fonts! */ - code = end; - break; - } - else - gindex = (FT_UInt)( code + delta ) & 0xFFFFU; - - if ( gindex == 0 ) - break; - - result = code; - goto Exit; - } - } - /* loop to next trial charcode */ - if ( code >= 0xFFFFU ) - break; - - code++; - } - } - - Exit: - *pchar_code = result; - return gindex; - } - - - FT_CALLBACK_DEF( FT_Error ) - tt_cmap4_get_info( TT_CMap cmap, - TT_CMapInfo *cmap_info ) - { - FT_Byte* p = cmap->data + 4; - - - cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); - - return SFNT_Err_Ok; - } - - - FT_CALLBACK_TABLE_DEF - const TT_CMap_ClassRec tt_cmap4_class_rec = - { - { -#ifdef OPT_CMAP4 - sizeof ( TT_CMap4Rec ), - (FT_CMap_InitFunc) tt_cmap4_init, -#else - sizeof ( TT_CMapRec ), - (FT_CMap_InitFunc) tt_cmap_init, -#endif - (FT_CMap_DoneFunc) NULL, - (FT_CMap_CharIndexFunc)tt_cmap4_char_index, - (FT_CMap_CharNextFunc) tt_cmap4_char_next - }, - 4, - (TT_CMap_ValidateFunc) tt_cmap4_validate, - (TT_CMap_Info_GetFunc) tt_cmap4_get_info - }; - -#endif /* TT_CONFIG_CMAP_FORMAT_4 */ - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** FORMAT 6 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /*************************************************************************/ - /* */ - /* TABLE OVERVIEW */ - /* -------------- */ - /* */ - /* NAME OFFSET TYPE DESCRIPTION */ - /* */ - /* format 0 USHORT must be 4 */ - /* length 2 USHORT table length in bytes */ - /* language 4 USHORT Mac language code */ - /* */ - /* first 6 USHORT first segment code */ - /* count 8 USHORT segment size in chars */ - /* glyphIds 10 USHORT[count] glyph ids */ - /* */ - /* A very simplified segment mapping. */ - /* */ - -#ifdef TT_CONFIG_CMAP_FORMAT_6 - - FT_CALLBACK_DEF( FT_Error ) - tt_cmap6_validate( FT_Byte* table, - FT_Validator valid ) - { - FT_Byte* p; - FT_UInt length, count; - - - if ( table + 10 > valid->limit ) - FT_INVALID_TOO_SHORT; - - p = table + 2; - length = TT_NEXT_USHORT( p ); - - p = table + 8; /* skip language and start index */ - count = TT_NEXT_USHORT( p ); - - if ( table + length > valid->limit || length < 10 + count * 2 ) - FT_INVALID_TOO_SHORT; - - /* check glyph indices */ - if ( valid->level >= FT_VALIDATE_TIGHT ) - { - FT_UInt gindex; - - - for ( ; count > 0; count-- ) - { - gindex = TT_NEXT_USHORT( p ); - if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) ) - FT_INVALID_GLYPH_ID; - } - } - - return SFNT_Err_Ok; - } - - - FT_CALLBACK_DEF( FT_UInt ) - tt_cmap6_char_index( TT_CMap cmap, - FT_UInt32 char_code ) - { - FT_Byte* table = cmap->data; - FT_UInt result = 0; - FT_Byte* p = table + 6; - FT_UInt start = TT_NEXT_USHORT( p ); - FT_UInt count = TT_NEXT_USHORT( p ); - FT_UInt idx = (FT_UInt)( char_code - start ); - - - if ( idx < count ) - { - p += 2 * idx; - result = TT_PEEK_USHORT( p ); - } - return result; - } - - - FT_CALLBACK_DEF( FT_UInt ) - tt_cmap6_char_next( TT_CMap cmap, - FT_UInt32 *pchar_code ) - { - FT_Byte* table = cmap->data; - FT_UInt32 result = 0; - FT_UInt32 char_code = *pchar_code + 1; - FT_UInt gindex = 0; - - FT_Byte* p = table + 6; - FT_UInt start = TT_NEXT_USHORT( p ); - FT_UInt count = TT_NEXT_USHORT( p ); - FT_UInt idx; - - - if ( char_code >= 0x10000UL ) - goto Exit; - - if ( char_code < start ) - char_code = start; - - idx = (FT_UInt)( char_code - start ); - p += 2 * idx; - - for ( ; idx < count; idx++ ) - { - gindex = TT_NEXT_USHORT( p ); - if ( gindex != 0 ) - { - result = char_code; - break; - } - char_code++; - } - - Exit: - *pchar_code = result; - return gindex; - } - - - FT_CALLBACK_DEF( FT_Error ) - tt_cmap6_get_info( TT_CMap cmap, - TT_CMapInfo *cmap_info ) - { - FT_Byte* p = cmap->data + 4; - - - cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); - - return SFNT_Err_Ok; - } - - - FT_CALLBACK_TABLE_DEF - const TT_CMap_ClassRec tt_cmap6_class_rec = - { - { - sizeof ( TT_CMapRec ), - - (FT_CMap_InitFunc) tt_cmap_init, - (FT_CMap_DoneFunc) NULL, - (FT_CMap_CharIndexFunc)tt_cmap6_char_index, - (FT_CMap_CharNextFunc) tt_cmap6_char_next - }, - 6, - (TT_CMap_ValidateFunc) tt_cmap6_validate, - (TT_CMap_Info_GetFunc) tt_cmap6_get_info - }; - -#endif /* TT_CONFIG_CMAP_FORMAT_6 */ - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** FORMAT 8 *****/ - /***** *****/ - /***** It's hard to completely understand what the OpenType spec *****/ - /***** says about this format, but here is my conclusion. *****/ - /***** *****/ - /***** The purpose of this format is to easily map UTF-16 text to *****/ - /***** glyph indices. Basically, the `char_code' must be in one of *****/ - /***** the following formats: *****/ - /***** *****/ - /***** - A 16-bit value that isn't part of the Unicode Surrogates *****/ - /***** Area (i.e. U+D800-U+DFFF). *****/ - /***** *****/ - /***** - A 32-bit value, made of two surrogate values, i.e.. if *****/ - /***** `char_code = (char_hi << 16) | char_lo', then both *****/ - /***** `char_hi' and `char_lo' must be in the Surrogates Area. *****/ - /***** Area. *****/ - /***** *****/ - /***** The 'is32' table embedded in the charmap indicates whether a *****/ - /***** given 16-bit value is in the surrogates area or not. *****/ - /***** *****/ - /***** So, for any given `char_code', we can assert the following: *****/ - /***** *****/ - /***** If `char_hi == 0' then we must have `is32[char_lo] == 0'. *****/ - /***** *****/ - /***** If `char_hi != 0' then we must have both *****/ - /***** `is32[char_hi] != 0' and `is32[char_lo] != 0'. *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /*************************************************************************/ - /* */ - /* TABLE OVERVIEW */ - /* -------------- */ - /* */ - /* NAME OFFSET TYPE DESCRIPTION */ - /* */ - /* format 0 USHORT must be 8 */ - /* reseved 2 USHORT reserved */ - /* length 4 ULONG length in bytes */ - /* language 8 ULONG Mac language code */ - /* is32 12 BYTE[8192] 32-bitness bitmap */ - /* count 8204 ULONG number of groups */ - /* */ - /* This header is followed by 'count' groups of the following format: */ - /* */ - /* start 0 ULONG first charcode */ - /* end 4 ULONG last charcode */ - /* startId 8 ULONG start glyph id for the group */ - /* */ - -#ifdef TT_CONFIG_CMAP_FORMAT_8 - - FT_CALLBACK_DEF( FT_Error ) - tt_cmap8_validate( FT_Byte* table, - FT_Validator valid ) - { - FT_Byte* p = table + 4; - FT_Byte* is32; - FT_UInt32 length; - FT_UInt32 num_groups; - - - if ( table + 16 + 8192 > valid->limit ) - FT_INVALID_TOO_SHORT; - - length = TT_NEXT_ULONG( p ); - if ( table + length > valid->limit || length < 8208 ) - FT_INVALID_TOO_SHORT; - - is32 = table + 12; - p = is32 + 8192; /* skip `is32' array */ - num_groups = TT_NEXT_ULONG( p ); - - if ( p + num_groups * 12 > valid->limit ) - FT_INVALID_TOO_SHORT; - - /* check groups, they must be in increasing order */ - { - FT_UInt32 n, start, end, start_id, count, last = 0; - - - for ( n = 0; n < num_groups; n++ ) - { - FT_UInt hi, lo; - - - start = TT_NEXT_ULONG( p ); - end = TT_NEXT_ULONG( p ); - start_id = TT_NEXT_ULONG( p ); - - if ( start > end ) - FT_INVALID_DATA; - - if ( n > 0 && start <= last ) - FT_INVALID_DATA; - - if ( valid->level >= FT_VALIDATE_TIGHT ) - { - if ( start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) ) - FT_INVALID_GLYPH_ID; - - count = (FT_UInt32)( end - start + 1 ); - - if ( start & ~0xFFFFU ) - { - /* start_hi != 0; check that is32[i] is 1 for each i in */ - /* the `hi' and `lo' of the range [start..end] */ - for ( ; count > 0; count--, start++ ) - { - hi = (FT_UInt)( start >> 16 ); - lo = (FT_UInt)( start & 0xFFFFU ); - - if ( (is32[hi >> 3] & ( 0x80 >> ( hi & 7 ) ) ) == 0 ) - FT_INVALID_DATA; - - if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) == 0 ) - FT_INVALID_DATA; - } - } - else - { - /* start_hi == 0; check that is32[i] is 0 for each i in */ - /* the range [start..end] */ - - /* end_hi cannot be != 0! */ - if ( end & ~0xFFFFU ) - FT_INVALID_DATA; - - for ( ; count > 0; count--, start++ ) - { - lo = (FT_UInt)( start & 0xFFFFU ); - - if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) != 0 ) - FT_INVALID_DATA; - } - } - } - - last = end; - } - } - - return SFNT_Err_Ok; - } - - - FT_CALLBACK_DEF( FT_UInt ) - tt_cmap8_char_index( TT_CMap cmap, - FT_UInt32 char_code ) - { - FT_Byte* table = cmap->data; - FT_UInt result = 0; - FT_Byte* p = table + 8204; - FT_UInt32 num_groups = TT_NEXT_ULONG( p ); - FT_UInt32 start, end, start_id; - - - for ( ; num_groups > 0; num_groups-- ) - { - start = TT_NEXT_ULONG( p ); - end = TT_NEXT_ULONG( p ); - start_id = TT_NEXT_ULONG( p ); - - if ( char_code < start ) - break; - - if ( char_code <= end ) - { - result = (FT_UInt)( start_id + char_code - start ); - break; - } - } - return result; - } - - - FT_CALLBACK_DEF( FT_UInt ) - tt_cmap8_char_next( TT_CMap cmap, - FT_UInt32 *pchar_code ) - { - FT_UInt32 result = 0; - FT_UInt32 char_code = *pchar_code + 1; - FT_UInt gindex = 0; - FT_Byte* table = cmap->data; - FT_Byte* p = table + 8204; - FT_UInt32 num_groups = TT_NEXT_ULONG( p ); - FT_UInt32 start, end, start_id; - - - p = table + 8208; - - for ( ; num_groups > 0; num_groups-- ) - { - start = TT_NEXT_ULONG( p ); - end = TT_NEXT_ULONG( p ); - start_id = TT_NEXT_ULONG( p ); - - if ( char_code < start ) - char_code = start; - - if ( char_code <= end ) - { - gindex = (FT_UInt)( char_code - start + start_id ); - if ( gindex != 0 ) - { - result = char_code; - goto Exit; - } - } - } - - Exit: - *pchar_code = result; - return gindex; - } - - - FT_CALLBACK_DEF( FT_Error ) - tt_cmap8_get_info( TT_CMap cmap, - TT_CMapInfo *cmap_info ) - { - FT_Byte* p = cmap->data + 8; - - - cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); - - return SFNT_Err_Ok; - } - - - FT_CALLBACK_TABLE_DEF - const TT_CMap_ClassRec tt_cmap8_class_rec = - { - { - sizeof ( TT_CMapRec ), - - (FT_CMap_InitFunc) tt_cmap_init, - (FT_CMap_DoneFunc) NULL, - (FT_CMap_CharIndexFunc)tt_cmap8_char_index, - (FT_CMap_CharNextFunc) tt_cmap8_char_next - }, - 8, - (TT_CMap_ValidateFunc) tt_cmap8_validate, - (TT_CMap_Info_GetFunc) tt_cmap8_get_info - }; - -#endif /* TT_CONFIG_CMAP_FORMAT_8 */ - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** FORMAT 10 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /*************************************************************************/ - /* */ - /* TABLE OVERVIEW */ - /* -------------- */ - /* */ - /* NAME OFFSET TYPE DESCRIPTION */ - /* */ - /* format 0 USHORT must be 10 */ - /* reserved 2 USHORT reserved */ - /* length 4 ULONG length in bytes */ - /* language 8 ULONG Mac language code */ - /* */ - /* start 12 ULONG first char in range */ - /* count 16 ULONG number of chars in range */ - /* glyphIds 20 USHORT[count] glyph indices covered */ - /* */ - -#ifdef TT_CONFIG_CMAP_FORMAT_10 - - FT_CALLBACK_DEF( FT_Error ) - tt_cmap10_validate( FT_Byte* table, - FT_Validator valid ) - { - FT_Byte* p = table + 4; - FT_ULong length, count; - - - if ( table + 20 > valid->limit ) - FT_INVALID_TOO_SHORT; - - length = TT_NEXT_ULONG( p ); - p = table + 16; - count = TT_NEXT_ULONG( p ); - - if ( table + length > valid->limit || length < 20 + count * 2 ) - FT_INVALID_TOO_SHORT; - - /* check glyph indices */ - if ( valid->level >= FT_VALIDATE_TIGHT ) - { - FT_UInt gindex; - - - for ( ; count > 0; count-- ) - { - gindex = TT_NEXT_USHORT( p ); - if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) ) - FT_INVALID_GLYPH_ID; - } - } - - return SFNT_Err_Ok; - } - - - FT_CALLBACK_DEF( FT_UInt ) - tt_cmap10_char_index( TT_CMap cmap, - FT_UInt32 char_code ) - { - FT_Byte* table = cmap->data; - FT_UInt result = 0; - FT_Byte* p = table + 12; - FT_UInt32 start = TT_NEXT_ULONG( p ); - FT_UInt32 count = TT_NEXT_ULONG( p ); - FT_UInt32 idx = (FT_ULong)( char_code - start ); - - - if ( idx < count ) - { - p += 2 * idx; - result = TT_PEEK_USHORT( p ); - } - return result; - } - - - FT_CALLBACK_DEF( FT_UInt ) - tt_cmap10_char_next( TT_CMap cmap, - FT_UInt32 *pchar_code ) - { - FT_Byte* table = cmap->data; - FT_UInt32 char_code = *pchar_code + 1; - FT_UInt gindex = 0; - FT_Byte* p = table + 12; - FT_UInt32 start = TT_NEXT_ULONG( p ); - FT_UInt32 count = TT_NEXT_ULONG( p ); - FT_UInt32 idx; - - - if ( char_code < start ) - char_code = start; - - idx = (FT_UInt32)( char_code - start ); - p += 2 * idx; - - for ( ; idx < count; idx++ ) - { - gindex = TT_NEXT_USHORT( p ); - if ( gindex != 0 ) - break; - char_code++; - } - - *pchar_code = char_code; - return gindex; - } - - - FT_CALLBACK_DEF( FT_Error ) - tt_cmap10_get_info( TT_CMap cmap, - TT_CMapInfo *cmap_info ) - { - FT_Byte* p = cmap->data + 8; - - - cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); - - return SFNT_Err_Ok; - } - - - FT_CALLBACK_TABLE_DEF - const TT_CMap_ClassRec tt_cmap10_class_rec = - { - { - sizeof ( TT_CMapRec ), - - (FT_CMap_InitFunc) tt_cmap_init, - (FT_CMap_DoneFunc) NULL, - (FT_CMap_CharIndexFunc)tt_cmap10_char_index, - (FT_CMap_CharNextFunc) tt_cmap10_char_next - }, - 10, - (TT_CMap_ValidateFunc) tt_cmap10_validate, - (TT_CMap_Info_GetFunc) tt_cmap10_get_info - }; - -#endif /* TT_CONFIG_CMAP_FORMAT_10 */ - - - /*************************************************************************/ - /*************************************************************************/ - /***** *****/ - /***** FORMAT 12 *****/ - /***** *****/ - /*************************************************************************/ - /*************************************************************************/ - - /*************************************************************************/ - /* */ - /* TABLE OVERVIEW */ - /* -------------- */ - /* */ - /* NAME OFFSET TYPE DESCRIPTION */ - /* */ - /* format 0 USHORT must be 12 */ - /* reserved 2 USHORT reserved */ - /* length 4 ULONG length in bytes */ - /* language 8 ULONG Mac language code */ - /* count 12 ULONG number of groups */ - /* 16 */ - /* */ - /* This header is followed by `count' groups of the following format: */ - /* */ - /* start 0 ULONG first charcode */ - /* end 4 ULONG last charcode */ - /* startId 8 ULONG start glyph id for the group */ - /* */ - -#ifdef TT_CONFIG_CMAP_FORMAT_12 - - FT_CALLBACK_DEF( FT_Error ) - tt_cmap12_validate( FT_Byte* table, - FT_Validator valid ) - { - FT_Byte* p; - FT_ULong length; - FT_ULong num_groups; - - - if ( table + 16 > valid->limit ) - FT_INVALID_TOO_SHORT; - - p = table + 4; - length = TT_NEXT_ULONG( p ); - - p = table + 12; - num_groups = TT_NEXT_ULONG( p ); - - if ( table + length > valid->limit || length < 16 + 12 * num_groups ) - FT_INVALID_TOO_SHORT; - - /* check groups, they must be in increasing order */ - { - FT_ULong n, start, end, start_id, last = 0; - - - for ( n = 0; n < num_groups; n++ ) - { - start = TT_NEXT_ULONG( p ); - end = TT_NEXT_ULONG( p ); - start_id = TT_NEXT_ULONG( p ); - - if ( start > end ) - FT_INVALID_DATA; - - if ( n > 0 && start <= last ) - FT_INVALID_DATA; - - if ( valid->level >= FT_VALIDATE_TIGHT ) - { - if ( start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) ) - FT_INVALID_GLYPH_ID; - } - - last = end; - } - } - - return SFNT_Err_Ok; - } - - - FT_CALLBACK_DEF( FT_UInt ) - tt_cmap12_char_index( TT_CMap cmap, - FT_UInt32 char_code ) - { - FT_UInt result = 0; - FT_Byte* table = cmap->data; - FT_Byte* p = table + 12; - FT_UInt32 num_groups = TT_NEXT_ULONG( p ); - FT_UInt32 start, end, start_id; - - - for ( ; num_groups > 0; num_groups-- ) - { - start = TT_NEXT_ULONG( p ); - end = TT_NEXT_ULONG( p ); - start_id = TT_NEXT_ULONG( p ); - - if ( char_code < start ) - break; - - if ( char_code <= end ) - { - result = (FT_UInt)( start_id + char_code - start ); - break; - } - } - return result; - } - - - FT_CALLBACK_DEF( FT_UInt ) - tt_cmap12_char_next( TT_CMap cmap, - FT_UInt32 *pchar_code ) - { - FT_Byte* table = cmap->data; - FT_UInt32 result = 0; - FT_UInt32 char_code = *pchar_code + 1; - FT_UInt gindex = 0; - FT_Byte* p = table + 12; - FT_UInt32 num_groups = TT_NEXT_ULONG( p ); - FT_UInt32 start, end, start_id; - - - p = table + 16; - - for ( ; num_groups > 0; num_groups-- ) - { - start = TT_NEXT_ULONG( p ); - end = TT_NEXT_ULONG( p ); - start_id = TT_NEXT_ULONG( p ); - - if ( char_code < start ) - char_code = start; - - if ( char_code <= end ) - { - gindex = (FT_UInt)(char_code - start + start_id); - if ( gindex != 0 ) - { - result = char_code; - goto Exit; - } - } - } - - Exit: - *pchar_code = result; - return gindex; - } - - - FT_CALLBACK_DEF( FT_Error ) - tt_cmap12_get_info( TT_CMap cmap, - TT_CMapInfo *cmap_info ) - { - FT_Byte* p = cmap->data + 8; - - - cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); - - return SFNT_Err_Ok; - } - - - FT_CALLBACK_TABLE_DEF - const TT_CMap_ClassRec tt_cmap12_class_rec = - { - { - sizeof ( TT_CMapRec ), - - (FT_CMap_InitFunc) tt_cmap_init, - (FT_CMap_DoneFunc) NULL, - (FT_CMap_CharIndexFunc)tt_cmap12_char_index, - (FT_CMap_CharNextFunc) tt_cmap12_char_next - }, - 12, - (TT_CMap_ValidateFunc) tt_cmap12_validate, - (TT_CMap_Info_GetFunc) tt_cmap12_get_info - }; - - -#endif /* TT_CONFIG_CMAP_FORMAT_12 */ - - - static const TT_CMap_Class tt_cmap_classes[] = - { -#ifdef TT_CONFIG_CMAP_FORMAT_0 - &tt_cmap0_class_rec, -#endif - -#ifdef TT_CONFIG_CMAP_FORMAT_2 - &tt_cmap2_class_rec, -#endif - -#ifdef TT_CONFIG_CMAP_FORMAT_4 - &tt_cmap4_class_rec, -#endif - -#ifdef TT_CONFIG_CMAP_FORMAT_6 - &tt_cmap6_class_rec, -#endif - -#ifdef TT_CONFIG_CMAP_FORMAT_8 - &tt_cmap8_class_rec, -#endif - -#ifdef TT_CONFIG_CMAP_FORMAT_10 - &tt_cmap10_class_rec, -#endif - -#ifdef TT_CONFIG_CMAP_FORMAT_12 - &tt_cmap12_class_rec, -#endif - - NULL, - }; - - - /* parse the `cmap' table and build the corresponding TT_CMap objects */ - /* in the current face */ - /* */ - FT_LOCAL_DEF( FT_Error ) - tt_face_build_cmaps( TT_Face face ) - { - FT_Byte* table = face->cmap_table; - FT_Byte* limit = table + face->cmap_size; - FT_UInt volatile num_cmaps; - FT_Byte* volatile p = table; - - - if ( p + 4 > limit ) - return SFNT_Err_Invalid_Table; - - /* only recognize format 0 */ - if ( TT_NEXT_USHORT( p ) != 0 ) - { - p -= 2; - FT_ERROR(( "tt_face_build_cmaps: unsupported `cmap' table format = %d\n", - TT_PEEK_USHORT( p ) )); - return SFNT_Err_Invalid_Table; - } - - num_cmaps = TT_NEXT_USHORT( p ); - - for ( ; num_cmaps > 0 && p + 8 <= limit; num_cmaps-- ) - { - FT_CharMapRec charmap; - FT_UInt32 offset; - - - charmap.platform_id = TT_NEXT_USHORT( p ); - charmap.encoding_id = TT_NEXT_USHORT( p ); - charmap.face = FT_FACE( face ); - charmap.encoding = FT_ENCODING_NONE; /* will be filled later */ - offset = TT_NEXT_ULONG( p ); - - if ( offset && - table + offset + 2 < limit && - table + offset >= table ) - { - FT_Byte* cmap = table + offset; - volatile FT_UInt format = TT_PEEK_USHORT( cmap ); - const TT_CMap_Class* volatile pclazz = tt_cmap_classes; - TT_CMap_Class clazz; - - - for ( ; *pclazz; pclazz++ ) - { - clazz = *pclazz; - if ( clazz->format == format ) - { - volatile TT_ValidatorRec valid; - FT_Error error = SFNT_Err_Ok; - - - ft_validator_init( FT_VALIDATOR( &valid ), cmap, limit, - FT_VALIDATE_DEFAULT ); - - valid.num_glyphs = (FT_UInt)face->root.num_glyphs; - - if ( ft_setjmp( FT_VALIDATOR( &valid )->jump_buffer ) == 0 ) - { - /* validate this cmap sub-table */ - error = clazz->validate( cmap, FT_VALIDATOR( &valid ) ); - } - - if ( valid.validator.error == 0 ) - { - (void)FT_CMap_New( (FT_CMap_Class)clazz, cmap, &charmap, NULL ); - - /* it is simpler to directly set the `unsorted' flag instead */ - /* of adding a parameter to FT_CMap_New */ - ((TT_CMap)(face->root.charmaps - [face->root.num_charmaps - 1]))->unsorted = - FT_BOOL( error ); - } - else - { - FT_ERROR(( "tt_face_build_cmaps:" )); - FT_ERROR(( " broken cmap sub-table ignored!\n" )); - } - break; - } - } - } - } - - return SFNT_Err_Ok; - } - - - FT_LOCAL( FT_Error ) - tt_get_cmap_info( FT_CharMap charmap, - TT_CMapInfo *cmap_info ) - { - FT_CMap cmap = (FT_CMap)charmap; - TT_CMap_Class clazz = (TT_CMap_Class)cmap->clazz; - - - return clazz->get_cmap_info( charmap, cmap_info ); - } - - -/* END */ +/***************************************************************************/ +/* */ +/* ttcmap.c */ +/* */ +/* TrueType character mapping table (cmap) support (body). */ +/* */ +/* Copyright 2002, 2003, 2004, 2005 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_DEBUG_H + +#include "sferrors.h" /* must come before FT_INTERNAL_VALIDATE_H */ + +#include FT_INTERNAL_VALIDATE_H +#include FT_INTERNAL_STREAM_H +#include "ttload.h" +#include "ttcmap.h" + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_ttcmap + + +#define TT_PEEK_SHORT FT_PEEK_SHORT +#define TT_PEEK_USHORT FT_PEEK_USHORT +#define TT_PEEK_LONG FT_PEEK_LONG +#define TT_PEEK_ULONG FT_PEEK_ULONG + +#define TT_NEXT_SHORT FT_NEXT_SHORT +#define TT_NEXT_USHORT FT_NEXT_USHORT +#define TT_NEXT_LONG FT_NEXT_LONG +#define TT_NEXT_ULONG FT_NEXT_ULONG + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap_init( TT_CMap cmap, + FT_Byte* table ) + { + cmap->data = table; + return SFNT_Err_Ok; + } + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 0 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* TABLE OVERVIEW */ + /* -------------- */ + /* */ + /* NAME OFFSET TYPE DESCRIPTION */ + /* */ + /* format 0 USHORT must be 0 */ + /* length 2 USHORT table length in bytes */ + /* language 4 USHORT Mac language code */ + /* glyph_ids 6 BYTE[256] array of glyph indices */ + /* 262 */ + /* */ + +#ifdef TT_CONFIG_CMAP_FORMAT_0 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap0_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p = table + 2; + FT_UInt length = TT_NEXT_USHORT( p ); + + + if ( table + length > valid->limit || length < 262 ) + FT_INVALID_TOO_SHORT; + + /* check glyph indices whenever necessary */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt n, idx; + + + p = table + 6; + for ( n = 0; n < 256; n++ ) + { + idx = *p++; + if ( idx >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap0_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + FT_Byte* table = cmap->data; + + + return char_code < 256 ? table[6 + char_code] : 0; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap0_char_next( TT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_Byte* table = cmap->data; + FT_UInt32 charcode = *pchar_code; + FT_UInt32 result = 0; + FT_UInt gindex = 0; + + + table += 6; /* go to glyph ids */ + while ( ++charcode < 256 ) + { + gindex = table[charcode]; + if ( gindex != 0 ) + { + result = charcode; + break; + } + } + + *pchar_code = result; + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap0_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 4; + + + cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_TABLE_DEF + const TT_CMap_ClassRec tt_cmap0_class_rec = + { + { + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) tt_cmap_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap0_char_index, + (FT_CMap_CharNextFunc) tt_cmap0_char_next + }, + 0, + (TT_CMap_ValidateFunc) tt_cmap0_validate, + (TT_CMap_Info_GetFunc) tt_cmap0_get_info + }; + +#endif /* TT_CONFIG_CMAP_FORMAT_0 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 2 *****/ + /***** *****/ + /***** This is used for certain CJK encodings that encode text in a *****/ + /***** mixed 8/16 bits encoding along the following lines: *****/ + /***** *****/ + /***** * Certain byte values correspond to an 8-bit character code *****/ + /***** (typically in the range 0..127 for ASCII compatibility). *****/ + /***** *****/ + /***** * Certain byte values signal the first byte of a 2-byte *****/ + /***** character code (but these values are also valid as the *****/ + /***** second byte of a 2-byte character). *****/ + /***** *****/ + /***** The following charmap lookup and iteration functions all *****/ + /***** assume that the value "charcode" correspond to following: *****/ + /***** *****/ + /***** - For one byte characters, "charcode" is simply the *****/ + /***** character code. *****/ + /***** *****/ + /***** - For two byte characters, "charcode" is the 2-byte *****/ + /***** character code in big endian format. More exactly: *****/ + /***** *****/ + /***** (charcode >> 8) is the first byte value *****/ + /***** (charcode & 0xFF) is the second byte value *****/ + /***** *****/ + /***** Note that not all values of "charcode" are valid according *****/ + /***** to these rules, and the function moderately check the *****/ + /***** arguments. *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* TABLE OVERVIEW */ + /* -------------- */ + /* */ + /* NAME OFFSET TYPE DESCRIPTION */ + /* */ + /* format 0 USHORT must be 2 */ + /* length 2 USHORT table length in bytes */ + /* language 4 USHORT Mac language code */ + /* keys 6 USHORT[256] sub-header keys */ + /* subs 518 SUBHEAD[NSUBS] sub-headers array */ + /* glyph_ids 518+NSUB*8 USHORT[] glyph id array */ + /* */ + /* The `keys' table is used to map charcode high-bytes to sub-headers. */ + /* The value of `NSUBS' is the number of sub-headers defined in the */ + /* table and is computed by finding the maximum of the `keys' table. */ + /* */ + /* Note that for any n, `keys[n]' is a byte offset within the `subs' */ + /* table, i.e., it is the corresponding sub-header index multiplied */ + /* by 8. */ + /* */ + /* Each sub-header has the following format: */ + /* */ + /* NAME OFFSET TYPE DESCRIPTION */ + /* */ + /* first 0 USHORT first valid low-byte */ + /* count 2 USHORT number of valid low-bytes */ + /* delta 4 SHORT see below */ + /* offset 6 USHORT see below */ + /* */ + /* A sub-header defines, for each high-byte, the range of valid */ + /* low-bytes within the charmap. Note that the range defined by `first' */ + /* and `count' must be completely included in the interval [0..255] */ + /* according to the specification. */ + /* */ + /* If a character code is contained within a given sub-header, then */ + /* mapping it to a glyph index is done as follows: */ + /* */ + /* * The value of `offset' is read. This is a _byte_ distance from the */ + /* location of the `offset' field itself into a slice of the */ + /* `glyph_ids' table. Let's call it `slice' (it's a USHORT[] too). */ + /* */ + /* * The value `slice[char.lo - first]' is read. If it is 0, there is */ + /* no glyph for the charcode. Otherwise, the value of `delta' is */ + /* added to it (modulo 65536) to form a new glyph index. */ + /* */ + /* It is up to the validation routine to check that all offsets fall */ + /* within the glyph ids table (and not within the `subs' table itself or */ + /* outside of the CMap). */ + /* */ + +#ifdef TT_CONFIG_CMAP_FORMAT_2 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap2_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p = table + 2; /* skip format */ + FT_UInt length = TT_PEEK_USHORT( p ); + FT_UInt n, max_subs; + FT_Byte* keys; /* keys table */ + FT_Byte* subs; /* sub-headers */ + FT_Byte* glyph_ids; /* glyph id array */ + + + if ( table + length > valid->limit || length < 6 + 512 ) + FT_INVALID_TOO_SHORT; + + keys = table + 6; + + /* parse keys to compute sub-headers count */ + p = keys; + max_subs = 0; + for ( n = 0; n < 256; n++ ) + { + FT_UInt idx = TT_NEXT_USHORT( p ); + + + /* value must be multiple of 8 */ + if ( valid->level >= FT_VALIDATE_PARANOID && ( idx & 7 ) != 0 ) + FT_INVALID_DATA; + + idx >>= 3; + + if ( idx > max_subs ) + max_subs = idx; + } + + FT_ASSERT( p == table + 518 ); + + subs = p; + glyph_ids = subs + (max_subs + 1) * 8; + if ( glyph_ids > valid->limit ) + FT_INVALID_TOO_SHORT; + + /* parse sub-headers */ + for ( n = 0; n <= max_subs; n++ ) + { + FT_UInt first_code, code_count, offset; + FT_Int delta; + FT_Byte* ids; + + + first_code = TT_NEXT_USHORT( p ); + code_count = TT_NEXT_USHORT( p ); + delta = TT_NEXT_SHORT( p ); + offset = TT_NEXT_USHORT( p ); + + /* check range within 0..255 */ + if ( valid->level >= FT_VALIDATE_PARANOID ) + { + if ( first_code >= 256 || first_code + code_count > 256 ) + FT_INVALID_DATA; + } + + /* check offset */ + if ( offset != 0 ) + { + ids = p - 2 + offset; + if ( ids < glyph_ids || ids + code_count*2 > table + length ) + FT_INVALID_OFFSET; + + /* check glyph ids */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_Byte* limit = p + code_count * 2; + FT_UInt idx; + + + for ( ; p < limit; ) + { + idx = TT_NEXT_USHORT( p ); + if ( idx != 0 ) + { + idx = ( idx + delta ) & 0xFFFFU; + if ( idx >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + } + } + } + + return SFNT_Err_Ok; + } + + + /* return sub header corresponding to a given character code */ + /* NULL on invalid charcode */ + static FT_Byte* + tt_cmap2_get_subheader( FT_Byte* table, + FT_UInt32 char_code ) + { + FT_Byte* result = NULL; + + + if ( char_code < 0x10000UL ) + { + FT_UInt char_lo = (FT_UInt)( char_code & 0xFF ); + FT_UInt char_hi = (FT_UInt)( char_code >> 8 ); + FT_Byte* p = table + 6; /* keys table */ + FT_Byte* subs = table + 518; /* subheaders table */ + FT_Byte* sub; + + + if ( char_hi == 0 ) + { + /* an 8-bit character code -- we use subHeader 0 in this case */ + /* to test whether the character code is in the charmap */ + /* */ + sub = subs; /* jump to first sub-header */ + + /* check that the sub-header for this byte is 0, which */ + /* indicates that it's really a valid one-byte value */ + /* Otherwise, return 0 */ + /* */ + p += char_lo * 2; + if ( TT_PEEK_USHORT( p ) != 0 ) + goto Exit; + } + else + { + /* a 16-bit character code */ + + /* jump to key entry */ + p += char_hi * 2; + /* jump to sub-header */ + sub = subs + ( FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 8 ) ); + + /* check that the high byte isn't a valid one-byte value */ + if ( sub == subs ) + goto Exit; + } + result = sub; + } + Exit: + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap2_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + FT_Byte* table = cmap->data; + FT_UInt result = 0; + FT_Byte* subheader; + + + subheader = tt_cmap2_get_subheader( table, char_code ); + if ( subheader ) + { + FT_Byte* p = subheader; + FT_UInt idx = (FT_UInt)(char_code & 0xFF); + FT_UInt start, count; + FT_Int delta; + FT_UInt offset; + + + start = TT_NEXT_USHORT( p ); + count = TT_NEXT_USHORT( p ); + delta = TT_NEXT_SHORT ( p ); + offset = TT_PEEK_USHORT( p ); + + idx -= start; + if ( idx < count && offset != 0 ) + { + p += offset + 2 * idx; + idx = TT_PEEK_USHORT( p ); + + if ( idx != 0 ) + result = (FT_UInt)( idx + delta ) & 0xFFFFU; + } + } + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap2_char_next( TT_CMap cmap, + FT_UInt32 *pcharcode ) + { + FT_Byte* table = cmap->data; + FT_UInt gindex = 0; + FT_UInt32 result = 0; + FT_UInt32 charcode = *pcharcode + 1; + FT_Byte* subheader; + + + while ( charcode < 0x10000UL ) + { + subheader = tt_cmap2_get_subheader( table, charcode ); + if ( subheader ) + { + FT_Byte* p = subheader; + FT_UInt start = TT_NEXT_USHORT( p ); + FT_UInt count = TT_NEXT_USHORT( p ); + FT_Int delta = TT_NEXT_SHORT ( p ); + FT_UInt offset = TT_PEEK_USHORT( p ); + FT_UInt char_lo = (FT_UInt)( charcode & 0xFF ); + FT_UInt pos, idx; + + + if ( offset == 0 ) + goto Next_SubHeader; + + if ( char_lo < start ) + { + char_lo = start; + pos = 0; + } + else + pos = (FT_UInt)( char_lo - start ); + + p += offset + pos * 2; + charcode = FT_PAD_FLOOR( charcode, 256 ) + char_lo; + + for ( ; pos < count; pos++, charcode++ ) + { + idx = TT_NEXT_USHORT( p ); + + if ( idx != 0 ) + { + gindex = ( idx + delta ) & 0xFFFFU; + if ( gindex != 0 ) + { + result = charcode; + goto Exit; + } + } + } + } + + /* jump to next sub-header, i.e. higher byte value */ + Next_SubHeader: + charcode = FT_PAD_FLOOR( charcode, 256 ) + 256; + } + + Exit: + *pcharcode = result; + + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap2_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 4; + + + cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_TABLE_DEF + const TT_CMap_ClassRec tt_cmap2_class_rec = + { + { + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) tt_cmap_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap2_char_index, + (FT_CMap_CharNextFunc) tt_cmap2_char_next + }, + 2, + (TT_CMap_ValidateFunc) tt_cmap2_validate, + (TT_CMap_Info_GetFunc) tt_cmap2_get_info + }; + +#endif /* TT_CONFIG_CMAP_FORMAT_2 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 4 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* TABLE OVERVIEW */ + /* -------------- */ + /* */ + /* NAME OFFSET TYPE DESCRIPTION */ + /* */ + /* format 0 USHORT must be 4 */ + /* length 2 USHORT table length */ + /* in bytes */ + /* language 4 USHORT Mac language code */ + /* */ + /* segCountX2 6 USHORT 2*NUM_SEGS */ + /* searchRange 8 USHORT 2*(1 << LOG_SEGS) */ + /* entrySelector 10 USHORT LOG_SEGS */ + /* rangeShift 12 USHORT segCountX2 - */ + /* searchRange */ + /* */ + /* endCount 14 USHORT[NUM_SEGS] end charcode for */ + /* each segment; last */ + /* is 0xFFFF */ + /* */ + /* pad 14+NUM_SEGS*2 USHORT padding */ + /* */ + /* startCount 16+NUM_SEGS*2 USHORT[NUM_SEGS] first charcode for */ + /* each segment */ + /* */ + /* idDelta 16+NUM_SEGS*4 SHORT[NUM_SEGS] delta for each */ + /* segment */ + /* idOffset 16+NUM_SEGS*6 SHORT[NUM_SEGS] range offset for */ + /* each segment; can be */ + /* zero */ + /* */ + /* glyphIds 16+NUM_SEGS*8 USHORT[] array of glyph id */ + /* ranges */ + /* */ + /* Character codes are modelled by a series of ordered (increasing) */ + /* intervals called segments. Each segment has start and end codes, */ + /* provided by the `startCount' and `endCount' arrays. Segments must */ + /* not be overlapping and the last segment should always contain the */ + /* `0xFFFF' endCount. */ + /* */ + /* The fields `searchRange', `entrySelector' and `rangeShift' are better */ + /* ignored (they are traces of over-engineering in the TrueType */ + /* specification). */ + /* */ + /* Each segment also has a signed `delta', as well as an optional offset */ + /* within the `glyphIds' table. */ + /* */ + /* If a segment's idOffset is 0, the glyph index corresponding to any */ + /* charcode within the segment is obtained by adding the value of */ + /* `idDelta' directly to the charcode, modulo 65536. */ + /* */ + /* Otherwise, a glyph index is taken from the glyph ids sub-array for */ + /* the segment, and the value of `idDelta' is added to it. */ + /* */ + /* */ + /* Finally, note that certain fonts contain invalid charmaps that */ + /* contain end=0xFFFF, start=0xFFFF, delta=0x0001, offset=0xFFFF at the */ + /* of their charmaps (e.g. opens___.ttf which comes with OpenOffice.org) */ + /* we need special code to deal with them correctly... */ + /* */ + +#ifdef TT_CONFIG_CMAP_FORMAT_4 + +#define OPT_CMAP4 + +#ifdef OPT_CMAP4 + + typedef struct TT_CMap4Rec_ + { + TT_CMapRec cmap; + FT_UInt32 old_charcode; /* old charcode */ + FT_UInt32 cur_charcode; /* current charcode */ + FT_UInt cur_gindex; /* current glyph index */ + + FT_UInt table_length; + FT_UInt num_ranges; + FT_UInt cur_range; + FT_UInt cur_start; + FT_UInt cur_end; + FT_Int cur_delta; + FT_Byte* cur_values; + + } TT_CMap4Rec, *TT_CMap4; + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap4_init( TT_CMap4 cmap, + FT_Byte* table ) + { + FT_Byte* p; + + + cmap->cmap.data = table; + + p = table + 2; + cmap->table_length = FT_PEEK_USHORT( p ); + + p = table + 6; + cmap->num_ranges = FT_PEEK_USHORT( p ) >> 1; + cmap->cur_range = cmap->num_ranges; + cmap->old_charcode = 0xFFFFFFFFUL; + cmap->cur_charcode = 0; + cmap->cur_gindex = 0; + + return SFNT_Err_Ok; + } + + + static FT_Int + tt_cmap4_set_range( TT_CMap4 cmap, + FT_UInt range_index ) + { + FT_Byte* table = cmap->cmap.data; + FT_Byte* p; + FT_UInt num_ranges = cmap->num_ranges; + + + while ( range_index < num_ranges ) + { + FT_UInt offset; + + + p = table + 14 + range_index * 2; + cmap->cur_end = FT_PEEK_USHORT( p ); + + p += 2 + num_ranges * 2; + cmap->cur_start = FT_PEEK_USHORT( p ); + + p += num_ranges * 2; + cmap->cur_delta = FT_PEEK_SHORT( p ); + + p += num_ranges * 2; + offset = FT_PEEK_USHORT( p ); + + if ( offset != 0xFFFFU ) + { + cmap->cur_values = offset ? p + offset : NULL; + cmap->cur_range = range_index; + return 0; + } + + /* we skip empty segments */ + range_index++; + } + + cmap->old_charcode = 0xFFFFFFFFUL; + cmap->cur_charcode = 0; + cmap->cur_gindex = 0; + cmap->cur_range = num_ranges; + return -1; + } + + + static void + tt_cmap4_next( TT_CMap4 cmap ) + { + FT_UInt charcode = cmap->cur_charcode + 1; + + + cmap->old_charcode = cmap->cur_charcode; + + for ( ;; ) + { + FT_Byte* values = cmap->cur_values; + FT_UInt end = cmap->cur_end; + FT_Int delta = cmap->cur_delta; + + + if ( charcode <= end ) + { + if ( values ) + { + FT_Byte* p = values + 2 * ( charcode - cmap->cur_start ); + + + do + { + FT_UInt gindex = FT_NEXT_USHORT( p ); + + + if ( gindex != 0 ) + { + gindex = (FT_UInt)( ( gindex + delta ) & 0xFFFFU ); + if ( gindex != 0 ) + { + cmap->cur_charcode = charcode; + cmap->cur_gindex = gindex; + return; + } + } + } while ( ++charcode <= end ); + } + else + { + do + { + FT_UInt gindex = (FT_UInt)( ( charcode + delta ) & 0xFFFFU ); + + + if ( gindex != 0 ) + { + cmap->cur_charcode = charcode; + cmap->cur_gindex = gindex; + return; + } + } while ( ++charcode <= end ); + } + } + + /* we need to find another range */ + if ( tt_cmap4_set_range( cmap, cmap->cur_range + 1 ) < 0 ) + break; + + charcode = cmap->cur_start; + } + } + + + static void + tt_cmap4_reset( TT_CMap4 cmap, + FT_UInt code, + FT_UInt range_index ) + { + if ( tt_cmap4_set_range( cmap, range_index ) >= 0 ) + { + cmap->cur_charcode = code; + tt_cmap4_next( cmap ); + } + } + +#endif /* OPT_CMAP4 */ + + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap4_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p = table + 2; /* skip format */ + FT_UInt length = TT_NEXT_USHORT( p ); + FT_Byte *ends, *starts, *offsets, *deltas, *glyph_ids; + FT_UInt num_segs; + FT_Error error = SFNT_Err_Ok; + + + /* in certain fonts, the `length' field is invalid and goes */ + /* out of bound. We try to correct this here... */ + if ( length < 16 ) + FT_INVALID_TOO_SHORT; + + if ( table + length > valid->limit ) + { + if ( valid->level >= FT_VALIDATE_TIGHT ) + FT_INVALID_TOO_SHORT; + + length = (FT_UInt)( valid->limit - table ); + } + + p = table + 6; + num_segs = TT_NEXT_USHORT( p ); /* read segCountX2 */ + + if ( valid->level >= FT_VALIDATE_PARANOID ) + { + /* check that we have an even value here */ + if ( num_segs & 1 ) + FT_INVALID_DATA; + } + + num_segs /= 2; + + /* check the search parameters - even though we never use them */ + /* */ + if ( valid->level >= FT_VALIDATE_PARANOID ) + { + /* check the values of 'searchRange', 'entrySelector', 'rangeShift' */ + FT_UInt search_range = TT_NEXT_USHORT( p ); + FT_UInt entry_selector = TT_NEXT_USHORT( p ); + FT_UInt range_shift = TT_NEXT_USHORT( p ); + + + if ( ( search_range | range_shift ) & 1 ) /* must be even values */ + FT_INVALID_DATA; + + search_range /= 2; + range_shift /= 2; + + /* `search range' is the greatest power of 2 that is <= num_segs */ + + if ( search_range > num_segs || + search_range * 2 < num_segs || + search_range + range_shift != num_segs || + search_range != ( 1U << entry_selector ) ) + FT_INVALID_DATA; + } + + ends = table + 14; + starts = table + 16 + num_segs * 2; + deltas = starts + num_segs * 2; + offsets = deltas + num_segs * 2; + glyph_ids = offsets + num_segs * 2; + + if ( glyph_ids > table + length ) + FT_INVALID_TOO_SHORT; + + /* check last segment, its end count must be FFFF */ + if ( valid->level >= FT_VALIDATE_PARANOID ) + { + p = ends + ( num_segs - 1 ) * 2; + if ( TT_PEEK_USHORT( p ) != 0xFFFFU ) + FT_INVALID_DATA; + } + + /* check that segments are sorted in increasing order and do not */ + /* overlap; check also the offsets */ + { + FT_UInt start, end, last = 0, offset, n; + FT_Int delta; + + + for ( n = 0; n < num_segs; n++ ) + { + p = starts + n * 2; + start = TT_PEEK_USHORT( p ); + p = ends + n * 2; + end = TT_PEEK_USHORT( p ); + p = deltas + n * 2; + delta = TT_PEEK_SHORT( p ); + p = offsets + n * 2; + offset = TT_PEEK_USHORT( p ); + + if ( start > end ) + FT_INVALID_DATA; + + /* this test should be performed at default validation level; */ + /* unfortunately, some popular Asian fonts present overlapping */ + /* ranges in their charmaps */ + /* */ + if ( n > 0 && start <= last ) + { + if ( valid->level >= FT_VALIDATE_TIGHT ) + FT_INVALID_DATA; + else + error = SFNT_Err_Invalid_CharMap_Format; + } + + if ( offset && offset != 0xFFFFU ) + { + p += offset; /* start of glyph id array */ + + /* check that we point within the glyph ids table only */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + if ( p < glyph_ids || + p + ( end - start + 1 ) * 2 > table + length ) + FT_INVALID_DATA; + } + else + { + if ( p < glyph_ids || + p + ( end - start + 1 ) * 2 > valid->limit ) + FT_INVALID_DATA; + } + + /* check glyph indices within the segment range */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt i, idx; + + + for ( i = start; i < end; i++ ) + { + idx = FT_NEXT_USHORT( p ); + if ( idx != 0 ) + { + idx = (FT_UInt)( idx + delta ) & 0xFFFFU; + + if ( idx >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + } + } + else if ( offset == 0xFFFFU ) + { + /* Some fonts (erroneously?) use a range offset of 0xFFFF */ + /* to mean missing glyph in cmap table */ + /* */ + if ( valid->level >= FT_VALIDATE_PARANOID || + n != num_segs - 1 || + !( start == 0xFFFFU && end == 0xFFFFU && delta == 0x1U ) ) + FT_INVALID_DATA; + } + + last = end; + } + } + + return error; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap4_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + FT_Byte* table = cmap->data; + FT_UInt result = 0; + + + if ( char_code < 0x10000UL ) + { + FT_UInt idx, num_segs2; + FT_Int delta; + FT_UInt code = (FT_UInt)char_code; + FT_Byte* p; + + p = table + 6; + num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 ); /* be paranoid! */ + + if ( !cmap->unsorted ) + { + /* Some fonts have more than 170 segments in their charmaps! */ + /* We changed this function to use a more efficient binary */ + /* search for improving performance */ + FT_UInt min = 0; + FT_UInt max = num_segs2 >> 1; + FT_UInt mid, start, end, offset; + + + while ( min < max ) + { + mid = ( min + max ) >> 1; + p = table + 14 + mid * 2; + end = TT_NEXT_USHORT( p ); + p += num_segs2; + start = TT_PEEK_USHORT( p); + + if ( code < start ) + max = mid; + else if ( code > end ) + min = mid + 1; + else + { + /* we found the segment */ + idx = code; + + p += num_segs2; + delta = TT_PEEK_SHORT( p ); + + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + + if ( offset == 0xFFFFU ) + goto Exit; + + if ( offset != 0 ) + { + p += offset + 2 * ( idx - start ); + idx = TT_PEEK_USHORT( p ); + } + + if ( idx != 0 ) + result = (FT_UInt)( idx + delta ) & 0xFFFFU; + + goto Exit; + } + } + } + else + { + FT_UInt n; + FT_Byte* q; + + + p = table + 14; /* ends table */ + q = table + 16 + num_segs2; /* starts table */ + + + for ( n = 0; n < num_segs2; n += 2 ) + { + FT_UInt end = TT_NEXT_USHORT( p ); + FT_UInt start = TT_NEXT_USHORT( q ); + FT_UInt offset; + + + if ( code < start ) + break; + + if ( code <= end ) + { + idx = code; + + p = q + num_segs2 - 2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + + if ( offset == 0xFFFFU ) + goto Exit; + + if ( offset != 0 ) + { + p += offset + 2 * ( idx - start ); + idx = TT_PEEK_USHORT( p ); + } + + if ( idx != 0 ) + result = (FT_UInt)( idx + delta ) & 0xFFFFU; + } + } + } + } + + Exit: + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap4_char_next( TT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_Byte* table = cmap->data; + FT_UInt32 result = 0; + FT_UInt gindex = 0; + FT_UInt32 char_code = *pchar_code; + FT_Byte* p; + FT_UInt code, num_segs2; + + + if ( char_code >= 0xFFFFUL ) + goto Exit; + +#ifdef OPT_CMAP4 + { + TT_CMap4 cmap4 = (TT_CMap4)cmap; + + + if ( char_code == cmap4->old_charcode ) + { + result = cmap4->cur_charcode; + gindex = cmap4->cur_gindex; + if ( result != 0 ) + { + tt_cmap4_next( cmap4 ); + goto Exit; + } + } + } +#endif /* OPT_CMAP4 */ + + code = (FT_UInt)char_code + 1; + p = table + 6; + num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 ); /* ensure even-ness */ + + if ( !cmap->unsorted ) + { + for (;;) + { + /* Some fonts have more than 170 segments in their charmaps! */ + /* We changed this function to use a more efficient binary */ + /* search */ + FT_UInt offset; + FT_Int delta; + FT_UInt min = 0; + FT_UInt max = num_segs2 >> 1; + FT_UInt mid, start, end; + FT_UInt hi; + + + /* we begin by finding the segment which end is + closer to our code point */ + hi = max + 1; + while ( min < max ) + { + mid = ( min + max ) >> 1; + p = table + 14 + mid * 2; + end = TT_PEEK_USHORT( p ); + + if ( end < code ) + min = mid + 1; + else + { + hi = mid; + max = mid; + } + } + + if ( hi > max ) + { + /* the point is behind the last segment; + we will exit right now */ + goto Exit; + } + + p = table + 14 + hi * 2; + end = TT_PEEK_USHORT( p ); + + p += 2 + num_segs2; + start = TT_PEEK_USHORT( p ); + + if ( code < start ) + code = start; + + p += num_segs2; + delta = TT_PEEK_USHORT( p ); + + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + + if ( offset != 0 && offset != 0xFFFFU ) + { + /* parse the glyph ids array for non-zero index */ + p += offset + ( code - start ) * 2; + while ( code <= end ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex != 0 ) + { + gindex = (FT_UInt)( gindex + delta ) & 0xFFFFU; + if ( gindex != 0 ) + { + result = code; +#ifdef OPT_CMAP4 + tt_cmap4_reset( (TT_CMap4)cmap, code, hi ); +#endif + goto Exit; + } + } + code++; + } + } + else if ( offset == 0xFFFFU ) + { + /* an offset of 0xFFFF means an empty segment in certain fonts! */ + code = end + 1; + } + else /* offset == 0 */ + { + gindex = (FT_UInt)( code + delta ) & 0xFFFFU; + if ( gindex != 0 ) + { + result = code; +#ifdef OPT_CMAP4 + tt_cmap4_reset( (TT_CMap4)cmap, code, hi ); +#endif + goto Exit; + } + code++; + } + } + } + else + { + for ( ;; ) + { + FT_UInt offset, n; + FT_Int delta; + FT_Byte* q; + + + p = table + 14; /* ends table */ + q = table + 16 + num_segs2; /* starts table */ + + for ( n = 0; n < num_segs2; n += 2 ) + { + FT_UInt end = TT_NEXT_USHORT( p ); + FT_UInt start = TT_NEXT_USHORT( q ); + + + if ( code < start ) + code = start; + + if ( code <= end ) + { + p = q + num_segs2 - 2; + delta = TT_PEEK_SHORT( p ); + p += num_segs2; + offset = TT_PEEK_USHORT( p ); + + if ( offset != 0 && offset != 0xFFFFU ) + { + /* parse the glyph ids array for non-0 index */ + p += offset + ( code - start ) * 2; + while ( code <= end ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex != 0 ) + { + gindex = (FT_UInt)( gindex + delta ) & 0xFFFFU; + if ( gindex != 0 ) + break; + } + code++; + } + } + else if ( offset == 0xFFFFU ) + { + /* an offset of 0xFFFF means an empty glyph in certain fonts! */ + code = end; + break; + } + else + gindex = (FT_UInt)( code + delta ) & 0xFFFFU; + + if ( gindex == 0 ) + break; + + result = code; + goto Exit; + } + } + /* loop to next trial charcode */ + if ( code >= 0xFFFFU ) + break; + + code++; + } + } + + Exit: + *pchar_code = result; + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap4_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 4; + + + cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_TABLE_DEF + const TT_CMap_ClassRec tt_cmap4_class_rec = + { + { +#ifdef OPT_CMAP4 + sizeof ( TT_CMap4Rec ), + (FT_CMap_InitFunc) tt_cmap4_init, +#else + sizeof ( TT_CMapRec ), + (FT_CMap_InitFunc) tt_cmap_init, +#endif + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap4_char_index, + (FT_CMap_CharNextFunc) tt_cmap4_char_next + }, + 4, + (TT_CMap_ValidateFunc) tt_cmap4_validate, + (TT_CMap_Info_GetFunc) tt_cmap4_get_info + }; + +#endif /* TT_CONFIG_CMAP_FORMAT_4 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 6 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* TABLE OVERVIEW */ + /* -------------- */ + /* */ + /* NAME OFFSET TYPE DESCRIPTION */ + /* */ + /* format 0 USHORT must be 4 */ + /* length 2 USHORT table length in bytes */ + /* language 4 USHORT Mac language code */ + /* */ + /* first 6 USHORT first segment code */ + /* count 8 USHORT segment size in chars */ + /* glyphIds 10 USHORT[count] glyph ids */ + /* */ + /* A very simplified segment mapping. */ + /* */ + +#ifdef TT_CONFIG_CMAP_FORMAT_6 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap6_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p; + FT_UInt length, count; + + + if ( table + 10 > valid->limit ) + FT_INVALID_TOO_SHORT; + + p = table + 2; + length = TT_NEXT_USHORT( p ); + + p = table + 8; /* skip language and start index */ + count = TT_NEXT_USHORT( p ); + + if ( table + length > valid->limit || length < 10 + count * 2 ) + FT_INVALID_TOO_SHORT; + + /* check glyph indices */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt gindex; + + + for ( ; count > 0; count-- ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap6_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + FT_Byte* table = cmap->data; + FT_UInt result = 0; + FT_Byte* p = table + 6; + FT_UInt start = TT_NEXT_USHORT( p ); + FT_UInt count = TT_NEXT_USHORT( p ); + FT_UInt idx = (FT_UInt)( char_code - start ); + + + if ( idx < count ) + { + p += 2 * idx; + result = TT_PEEK_USHORT( p ); + } + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap6_char_next( TT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_Byte* table = cmap->data; + FT_UInt32 result = 0; + FT_UInt32 char_code = *pchar_code + 1; + FT_UInt gindex = 0; + + FT_Byte* p = table + 6; + FT_UInt start = TT_NEXT_USHORT( p ); + FT_UInt count = TT_NEXT_USHORT( p ); + FT_UInt idx; + + + if ( char_code >= 0x10000UL ) + goto Exit; + + if ( char_code < start ) + char_code = start; + + idx = (FT_UInt)( char_code - start ); + p += 2 * idx; + + for ( ; idx < count; idx++ ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex != 0 ) + { + result = char_code; + break; + } + char_code++; + } + + Exit: + *pchar_code = result; + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap6_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 4; + + + cmap_info->language = (FT_ULong)TT_PEEK_USHORT( p ); + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_TABLE_DEF + const TT_CMap_ClassRec tt_cmap6_class_rec = + { + { + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) tt_cmap_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap6_char_index, + (FT_CMap_CharNextFunc) tt_cmap6_char_next + }, + 6, + (TT_CMap_ValidateFunc) tt_cmap6_validate, + (TT_CMap_Info_GetFunc) tt_cmap6_get_info + }; + +#endif /* TT_CONFIG_CMAP_FORMAT_6 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 8 *****/ + /***** *****/ + /***** It's hard to completely understand what the OpenType spec *****/ + /***** says about this format, but here is my conclusion. *****/ + /***** *****/ + /***** The purpose of this format is to easily map UTF-16 text to *****/ + /***** glyph indices. Basically, the `char_code' must be in one of *****/ + /***** the following formats: *****/ + /***** *****/ + /***** - A 16-bit value that isn't part of the Unicode Surrogates *****/ + /***** Area (i.e. U+D800-U+DFFF). *****/ + /***** *****/ + /***** - A 32-bit value, made of two surrogate values, i.e.. if *****/ + /***** `char_code = (char_hi << 16) | char_lo', then both *****/ + /***** `char_hi' and `char_lo' must be in the Surrogates Area. *****/ + /***** Area. *****/ + /***** *****/ + /***** The 'is32' table embedded in the charmap indicates whether a *****/ + /***** given 16-bit value is in the surrogates area or not. *****/ + /***** *****/ + /***** So, for any given `char_code', we can assert the following: *****/ + /***** *****/ + /***** If `char_hi == 0' then we must have `is32[char_lo] == 0'. *****/ + /***** *****/ + /***** If `char_hi != 0' then we must have both *****/ + /***** `is32[char_hi] != 0' and `is32[char_lo] != 0'. *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* TABLE OVERVIEW */ + /* -------------- */ + /* */ + /* NAME OFFSET TYPE DESCRIPTION */ + /* */ + /* format 0 USHORT must be 8 */ + /* reseved 2 USHORT reserved */ + /* length 4 ULONG length in bytes */ + /* language 8 ULONG Mac language code */ + /* is32 12 BYTE[8192] 32-bitness bitmap */ + /* count 8204 ULONG number of groups */ + /* */ + /* This header is followed by 'count' groups of the following format: */ + /* */ + /* start 0 ULONG first charcode */ + /* end 4 ULONG last charcode */ + /* startId 8 ULONG start glyph id for the group */ + /* */ + +#ifdef TT_CONFIG_CMAP_FORMAT_8 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap8_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p = table + 4; + FT_Byte* is32; + FT_UInt32 length; + FT_UInt32 num_groups; + + + if ( table + 16 + 8192 > valid->limit ) + FT_INVALID_TOO_SHORT; + + length = TT_NEXT_ULONG( p ); + if ( table + length > valid->limit || length < 8208 ) + FT_INVALID_TOO_SHORT; + + is32 = table + 12; + p = is32 + 8192; /* skip `is32' array */ + num_groups = TT_NEXT_ULONG( p ); + + if ( p + num_groups * 12 > valid->limit ) + FT_INVALID_TOO_SHORT; + + /* check groups, they must be in increasing order */ + { + FT_UInt32 n, start, end, start_id, count, last = 0; + + + for ( n = 0; n < num_groups; n++ ) + { + FT_UInt hi, lo; + + + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + + if ( start > end ) + FT_INVALID_DATA; + + if ( n > 0 && start <= last ) + FT_INVALID_DATA; + + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + if ( start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + + count = (FT_UInt32)( end - start + 1 ); + + if ( start & ~0xFFFFU ) + { + /* start_hi != 0; check that is32[i] is 1 for each i in */ + /* the `hi' and `lo' of the range [start..end] */ + for ( ; count > 0; count--, start++ ) + { + hi = (FT_UInt)( start >> 16 ); + lo = (FT_UInt)( start & 0xFFFFU ); + + if ( (is32[hi >> 3] & ( 0x80 >> ( hi & 7 ) ) ) == 0 ) + FT_INVALID_DATA; + + if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) == 0 ) + FT_INVALID_DATA; + } + } + else + { + /* start_hi == 0; check that is32[i] is 0 for each i in */ + /* the range [start..end] */ + + /* end_hi cannot be != 0! */ + if ( end & ~0xFFFFU ) + FT_INVALID_DATA; + + for ( ; count > 0; count--, start++ ) + { + lo = (FT_UInt)( start & 0xFFFFU ); + + if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) != 0 ) + FT_INVALID_DATA; + } + } + } + + last = end; + } + } + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap8_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + FT_Byte* table = cmap->data; + FT_UInt result = 0; + FT_Byte* p = table + 8204; + FT_UInt32 num_groups = TT_NEXT_ULONG( p ); + FT_UInt32 start, end, start_id; + + + for ( ; num_groups > 0; num_groups-- ) + { + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + + if ( char_code < start ) + break; + + if ( char_code <= end ) + { + result = (FT_UInt)( start_id + char_code - start ); + break; + } + } + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap8_char_next( TT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_UInt32 result = 0; + FT_UInt32 char_code = *pchar_code + 1; + FT_UInt gindex = 0; + FT_Byte* table = cmap->data; + FT_Byte* p = table + 8204; + FT_UInt32 num_groups = TT_NEXT_ULONG( p ); + FT_UInt32 start, end, start_id; + + + p = table + 8208; + + for ( ; num_groups > 0; num_groups-- ) + { + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + + if ( char_code < start ) + char_code = start; + + if ( char_code <= end ) + { + gindex = (FT_UInt)( char_code - start + start_id ); + if ( gindex != 0 ) + { + result = char_code; + goto Exit; + } + } + } + + Exit: + *pchar_code = result; + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap8_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 8; + + + cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_TABLE_DEF + const TT_CMap_ClassRec tt_cmap8_class_rec = + { + { + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) tt_cmap_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap8_char_index, + (FT_CMap_CharNextFunc) tt_cmap8_char_next + }, + 8, + (TT_CMap_ValidateFunc) tt_cmap8_validate, + (TT_CMap_Info_GetFunc) tt_cmap8_get_info + }; + +#endif /* TT_CONFIG_CMAP_FORMAT_8 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 10 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* TABLE OVERVIEW */ + /* -------------- */ + /* */ + /* NAME OFFSET TYPE DESCRIPTION */ + /* */ + /* format 0 USHORT must be 10 */ + /* reserved 2 USHORT reserved */ + /* length 4 ULONG length in bytes */ + /* language 8 ULONG Mac language code */ + /* */ + /* start 12 ULONG first char in range */ + /* count 16 ULONG number of chars in range */ + /* glyphIds 20 USHORT[count] glyph indices covered */ + /* */ + +#ifdef TT_CONFIG_CMAP_FORMAT_10 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap10_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p = table + 4; + FT_ULong length, count; + + + if ( table + 20 > valid->limit ) + FT_INVALID_TOO_SHORT; + + length = TT_NEXT_ULONG( p ); + p = table + 16; + count = TT_NEXT_ULONG( p ); + + if ( table + length > valid->limit || length < 20 + count * 2 ) + FT_INVALID_TOO_SHORT; + + /* check glyph indices */ + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + FT_UInt gindex; + + + for ( ; count > 0; count-- ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + } + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap10_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + FT_Byte* table = cmap->data; + FT_UInt result = 0; + FT_Byte* p = table + 12; + FT_UInt32 start = TT_NEXT_ULONG( p ); + FT_UInt32 count = TT_NEXT_ULONG( p ); + FT_UInt32 idx = (FT_ULong)( char_code - start ); + + + if ( idx < count ) + { + p += 2 * idx; + result = TT_PEEK_USHORT( p ); + } + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap10_char_next( TT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_Byte* table = cmap->data; + FT_UInt32 char_code = *pchar_code + 1; + FT_UInt gindex = 0; + FT_Byte* p = table + 12; + FT_UInt32 start = TT_NEXT_ULONG( p ); + FT_UInt32 count = TT_NEXT_ULONG( p ); + FT_UInt32 idx; + + + if ( char_code < start ) + char_code = start; + + idx = (FT_UInt32)( char_code - start ); + p += 2 * idx; + + for ( ; idx < count; idx++ ) + { + gindex = TT_NEXT_USHORT( p ); + if ( gindex != 0 ) + break; + char_code++; + } + + *pchar_code = char_code; + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap10_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 8; + + + cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_TABLE_DEF + const TT_CMap_ClassRec tt_cmap10_class_rec = + { + { + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) tt_cmap_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap10_char_index, + (FT_CMap_CharNextFunc) tt_cmap10_char_next + }, + 10, + (TT_CMap_ValidateFunc) tt_cmap10_validate, + (TT_CMap_Info_GetFunc) tt_cmap10_get_info + }; + +#endif /* TT_CONFIG_CMAP_FORMAT_10 */ + + + /*************************************************************************/ + /*************************************************************************/ + /***** *****/ + /***** FORMAT 12 *****/ + /***** *****/ + /*************************************************************************/ + /*************************************************************************/ + + /*************************************************************************/ + /* */ + /* TABLE OVERVIEW */ + /* -------------- */ + /* */ + /* NAME OFFSET TYPE DESCRIPTION */ + /* */ + /* format 0 USHORT must be 12 */ + /* reserved 2 USHORT reserved */ + /* length 4 ULONG length in bytes */ + /* language 8 ULONG Mac language code */ + /* count 12 ULONG number of groups */ + /* 16 */ + /* */ + /* This header is followed by `count' groups of the following format: */ + /* */ + /* start 0 ULONG first charcode */ + /* end 4 ULONG last charcode */ + /* startId 8 ULONG start glyph id for the group */ + /* */ + +#ifdef TT_CONFIG_CMAP_FORMAT_12 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap12_validate( FT_Byte* table, + FT_Validator valid ) + { + FT_Byte* p; + FT_ULong length; + FT_ULong num_groups; + + + if ( table + 16 > valid->limit ) + FT_INVALID_TOO_SHORT; + + p = table + 4; + length = TT_NEXT_ULONG( p ); + + p = table + 12; + num_groups = TT_NEXT_ULONG( p ); + + if ( table + length > valid->limit || length < 16 + 12 * num_groups ) + FT_INVALID_TOO_SHORT; + + /* check groups, they must be in increasing order */ + { + FT_ULong n, start, end, start_id, last = 0; + + + for ( n = 0; n < num_groups; n++ ) + { + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + + if ( start > end ) + FT_INVALID_DATA; + + if ( n > 0 && start <= last ) + FT_INVALID_DATA; + + if ( valid->level >= FT_VALIDATE_TIGHT ) + { + if ( start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) ) + FT_INVALID_GLYPH_ID; + } + + last = end; + } + } + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap12_char_index( TT_CMap cmap, + FT_UInt32 char_code ) + { + FT_UInt result = 0; + FT_Byte* table = cmap->data; + FT_Byte* p = table + 12; + FT_UInt32 num_groups = TT_NEXT_ULONG( p ); + FT_UInt32 start, end, start_id; + + + for ( ; num_groups > 0; num_groups-- ) + { + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + + if ( char_code < start ) + break; + + if ( char_code <= end ) + { + result = (FT_UInt)( start_id + char_code - start ); + break; + } + } + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap12_char_next( TT_CMap cmap, + FT_UInt32 *pchar_code ) + { + FT_Byte* table = cmap->data; + FT_UInt32 result = 0; + FT_UInt32 char_code = *pchar_code + 1; + FT_UInt gindex = 0; + FT_Byte* p = table + 12; + FT_UInt32 num_groups = TT_NEXT_ULONG( p ); + FT_UInt32 start, end, start_id; + + + p = table + 16; + + for ( ; num_groups > 0; num_groups-- ) + { + start = TT_NEXT_ULONG( p ); + end = TT_NEXT_ULONG( p ); + start_id = TT_NEXT_ULONG( p ); + + if ( char_code < start ) + char_code = start; + + if ( char_code <= end ) + { + gindex = (FT_UInt)(char_code - start + start_id); + if ( gindex != 0 ) + { + result = char_code; + goto Exit; + } + } + } + + Exit: + *pchar_code = result; + return gindex; + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap12_get_info( TT_CMap cmap, + TT_CMapInfo *cmap_info ) + { + FT_Byte* p = cmap->data + 8; + + + cmap_info->language = (FT_ULong)TT_PEEK_ULONG( p ); + + return SFNT_Err_Ok; + } + + + FT_CALLBACK_TABLE_DEF + const TT_CMap_ClassRec tt_cmap12_class_rec = + { + { + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) tt_cmap_init, + (FT_CMap_DoneFunc) NULL, + (FT_CMap_CharIndexFunc)tt_cmap12_char_index, + (FT_CMap_CharNextFunc) tt_cmap12_char_next + }, + 12, + (TT_CMap_ValidateFunc) tt_cmap12_validate, + (TT_CMap_Info_GetFunc) tt_cmap12_get_info + }; + + +#endif /* TT_CONFIG_CMAP_FORMAT_12 */ + + + static const TT_CMap_Class tt_cmap_classes[] = + { +#ifdef TT_CONFIG_CMAP_FORMAT_0 + &tt_cmap0_class_rec, +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_2 + &tt_cmap2_class_rec, +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_4 + &tt_cmap4_class_rec, +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_6 + &tt_cmap6_class_rec, +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_8 + &tt_cmap8_class_rec, +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_10 + &tt_cmap10_class_rec, +#endif + +#ifdef TT_CONFIG_CMAP_FORMAT_12 + &tt_cmap12_class_rec, +#endif + + NULL, + }; + + + /* parse the `cmap' table and build the corresponding TT_CMap objects */ + /* in the current face */ + /* */ + FT_LOCAL_DEF( FT_Error ) + tt_face_build_cmaps( TT_Face face ) + { + FT_Byte* table = face->cmap_table; + FT_Byte* limit = table + face->cmap_size; + FT_UInt volatile num_cmaps; + FT_Byte* volatile p = table; + + + if ( p + 4 > limit ) + return SFNT_Err_Invalid_Table; + + /* only recognize format 0 */ + if ( TT_NEXT_USHORT( p ) != 0 ) + { + p -= 2; + FT_ERROR(( "tt_face_build_cmaps: unsupported `cmap' table format = %d\n", + TT_PEEK_USHORT( p ) )); + return SFNT_Err_Invalid_Table; + } + + num_cmaps = TT_NEXT_USHORT( p ); + + for ( ; num_cmaps > 0 && p + 8 <= limit; num_cmaps-- ) + { + FT_CharMapRec charmap; + FT_UInt32 offset; + + + charmap.platform_id = TT_NEXT_USHORT( p ); + charmap.encoding_id = TT_NEXT_USHORT( p ); + charmap.face = FT_FACE( face ); + charmap.encoding = FT_ENCODING_NONE; /* will be filled later */ + offset = TT_NEXT_ULONG( p ); + + if ( offset && + table + offset + 2 < limit && + table + offset >= table ) + { + FT_Byte* cmap = table + offset; + volatile FT_UInt format = TT_PEEK_USHORT( cmap ); + const TT_CMap_Class* volatile pclazz = tt_cmap_classes; + TT_CMap_Class clazz; + + + for ( ; *pclazz; pclazz++ ) + { + clazz = *pclazz; + if ( clazz->format == format ) + { + volatile TT_ValidatorRec valid; + FT_Error error = SFNT_Err_Ok; + + + ft_validator_init( FT_VALIDATOR( &valid ), cmap, limit, + FT_VALIDATE_DEFAULT ); + + valid.num_glyphs = (FT_UInt)face->root.num_glyphs; + + if ( ft_setjmp( FT_VALIDATOR( &valid )->jump_buffer ) == 0 ) + { + /* validate this cmap sub-table */ + error = clazz->validate( cmap, FT_VALIDATOR( &valid ) ); + } + + if ( valid.validator.error == 0 ) + { + (void)FT_CMap_New( (FT_CMap_Class)clazz, cmap, &charmap, NULL ); + + /* it is simpler to directly set the `unsorted' flag instead */ + /* of adding a parameter to FT_CMap_New */ + ((TT_CMap)(face->root.charmaps + [face->root.num_charmaps - 1]))->unsorted = + FT_BOOL( error ); + } + else + { + FT_ERROR(( "tt_face_build_cmaps:" )); + FT_ERROR(( " broken cmap sub-table ignored!\n" )); + } + break; + } + } + } + } + + return SFNT_Err_Ok; + } + + + FT_LOCAL( FT_Error ) + tt_get_cmap_info( FT_CharMap charmap, + TT_CMapInfo *cmap_info ) + { + FT_CMap cmap = (FT_CMap)charmap; + TT_CMap_Class clazz = (TT_CMap_Class)cmap->clazz; + + + return clazz->get_cmap_info( charmap, cmap_info ); + } + + +/* END */ diff --git a/reactos/lib/freetype/src/sfnt/ttcmap.h b/reactos/lib/freetype/src/sfnt/ttcmap.h index 6db691eee94..5f758a46d22 100644 --- a/reactos/lib/freetype/src/sfnt/ttcmap.h +++ b/reactos/lib/freetype/src/sfnt/ttcmap.h @@ -1,81 +1,81 @@ -/***************************************************************************/ -/* */ -/* ttcmap.h */ -/* */ -/* TrueType character mapping table (cmap) support (specification). */ -/* */ -/* Copyright 2002, 2003, 2004, 2005 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - -#ifndef __TTCMAP_H__ -#define __TTCMAP_H__ - - -#include <ft2build.h> -#include FT_INTERNAL_TRUETYPE_TYPES_H -#include FT_INTERNAL_VALIDATE_H -#include FT_SERVICE_TT_CMAP_H - -FT_BEGIN_HEADER - - typedef struct TT_CMapRec_ - { - FT_CMapRec cmap; - FT_Byte* data; /* pointer to in-memory cmap table */ - FT_Bool unsorted; /* for format 4 only */ - - } TT_CMapRec, *TT_CMap; - - typedef const struct TT_CMap_ClassRec_* TT_CMap_Class; - - - typedef FT_Error - (*TT_CMap_ValidateFunc)( FT_Byte* data, - FT_Validator valid ); - - typedef struct TT_CMap_ClassRec_ - { - FT_CMap_ClassRec clazz; - FT_UInt format; - TT_CMap_ValidateFunc validate; - TT_CMap_Info_GetFunc get_cmap_info; - - } TT_CMap_ClassRec; - - - typedef struct TT_ValidatorRec_ - { - FT_ValidatorRec validator; - FT_UInt num_glyphs; - - } TT_ValidatorRec, *TT_Validator; - - -#define TT_VALIDATOR( x ) ((TT_Validator)( x )) -#define TT_VALID_GLYPH_COUNT( x ) TT_VALIDATOR( x )->num_glyphs - - - FT_LOCAL( FT_Error ) - tt_face_build_cmaps( TT_Face face ); - - /* used in tt-cmaps service */ - FT_LOCAL( FT_Error ) - tt_get_cmap_info( FT_CharMap charmap, - TT_CMapInfo *cmap_info ); - - -FT_END_HEADER - -#endif /* __TTCMAP_H__ */ - - -/* END */ +/***************************************************************************/ +/* */ +/* ttcmap.h */ +/* */ +/* TrueType character mapping table (cmap) support (specification). */ +/* */ +/* Copyright 2002, 2003, 2004, 2005 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __TTCMAP_H__ +#define __TTCMAP_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_TRUETYPE_TYPES_H +#include FT_INTERNAL_VALIDATE_H +#include FT_SERVICE_TT_CMAP_H + +FT_BEGIN_HEADER + + typedef struct TT_CMapRec_ + { + FT_CMapRec cmap; + FT_Byte* data; /* pointer to in-memory cmap table */ + FT_Bool unsorted; /* for format 4 only */ + + } TT_CMapRec, *TT_CMap; + + typedef const struct TT_CMap_ClassRec_* TT_CMap_Class; + + + typedef FT_Error + (*TT_CMap_ValidateFunc)( FT_Byte* data, + FT_Validator valid ); + + typedef struct TT_CMap_ClassRec_ + { + FT_CMap_ClassRec clazz; + FT_UInt format; + TT_CMap_ValidateFunc validate; + TT_CMap_Info_GetFunc get_cmap_info; + + } TT_CMap_ClassRec; + + + typedef struct TT_ValidatorRec_ + { + FT_ValidatorRec validator; + FT_UInt num_glyphs; + + } TT_ValidatorRec, *TT_Validator; + + +#define TT_VALIDATOR( x ) ((TT_Validator)( x )) +#define TT_VALID_GLYPH_COUNT( x ) TT_VALIDATOR( x )->num_glyphs + + + FT_LOCAL( FT_Error ) + tt_face_build_cmaps( TT_Face face ); + + /* used in tt-cmaps service */ + FT_LOCAL( FT_Error ) + tt_get_cmap_info( FT_CharMap charmap, + TT_CMapInfo *cmap_info ); + + +FT_END_HEADER + +#endif /* __TTCMAP_H__ */ + + +/* END */ diff --git a/reactos/lib/freetype/src/sfnt/ttkern.c b/reactos/lib/freetype/src/sfnt/ttkern.c index e32d703b668..805efa5c3b5 100644 --- a/reactos/lib/freetype/src/sfnt/ttkern.c +++ b/reactos/lib/freetype/src/sfnt/ttkern.c @@ -1,491 +1,491 @@ -/***************************************************************************/ -/* */ -/* ttkern.c */ -/* */ -/* Load the basic TrueType kerning table. This doesn't handle */ -/* kerning data within the GPOS table at the moment. */ -/* */ -/* Copyright 1996-2001, 2002, 2003, 2004, 2005 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - -#include <ft2build.h> -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_TRUETYPE_TAGS_H -#include "ttkern.h" -#include "ttload.h" - -#include "sferrors.h" - - - /*************************************************************************/ - /* */ - /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ - /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ - /* messages during execution. */ - /* */ -#undef FT_COMPONENT -#define FT_COMPONENT trace_ttkern - - -#undef TT_KERN_INDEX -#define TT_KERN_INDEX( g1, g2 ) ( ( (FT_ULong)(g1) << 16 ) | (g2) ) - - -#ifdef FT_OPTIMIZE_MEMORY - - FT_LOCAL_DEF( FT_Error ) - tt_face_load_kern( TT_Face face, - FT_Stream stream ) - { - FT_Error error; - FT_ULong table_size; - FT_Byte* p; - FT_Byte* p_limit; - FT_UInt nn, num_tables; - FT_UInt32 avail = 0, ordered = 0; - - - /* the kern table is optional; exit silently if it is missing */ - error = face->goto_table( face, TTAG_kern, stream, &table_size ); - if ( error ) - goto Exit; - - if ( table_size < 4 ) /* the case of a malformed table */ - { - FT_ERROR(( "kerning table is too small - ignored\n" )); - error = SFNT_Err_Table_Missing; - goto Exit; - } - - if ( FT_FRAME_EXTRACT( table_size, face->kern_table ) ) - { - FT_ERROR(( "could not extract kerning table\n" )); - goto Exit; - } - - face->kern_table_size = table_size; - - p = face->kern_table; - p_limit = p + table_size; - - p += 2; /* skip version */ - num_tables = FT_NEXT_USHORT( p ); - - if ( num_tables > 32 ) /* we only support up to 32 sub-tables */ - num_tables = 32; - - for ( nn = 0; nn < num_tables; nn++ ) - { - FT_UInt num_pairs, version, length, coverage; - FT_Byte* p_next; - FT_UInt32 mask = 1UL << nn; - - - if ( p + 6 > p_limit ) - break; - - p_next = p; - - version = FT_NEXT_USHORT( p ); - length = FT_NEXT_USHORT( p ); - coverage = FT_NEXT_USHORT( p ); - - if ( length <= 6 ) - break; - - p_next += length; - - /* only use horizontal kerning tables */ - if ( ( coverage & ~8 ) != 0x0001 || - p + 8 > p_limit ) - goto NextTable; - - num_pairs = FT_NEXT_USHORT( p ); - p += 6; - - if ( p + 6 * num_pairs > p_limit ) - goto NextTable; - - avail |= mask; - - /* - * Now check whether the pairs in this table are ordered. - * We then can use binary search. - */ - if ( num_pairs > 0 ) - { - FT_UInt count; - FT_UInt old_pair; - - - old_pair = FT_NEXT_ULONG( p ); - p += 2; - - for ( count = num_pairs - 1; count > 0; count-- ) - { - FT_UInt32 cur_pair; - - - cur_pair = FT_NEXT_ULONG( p ); - if ( cur_pair <= old_pair ) - break; - - p += 2; - old_pair = cur_pair; - } - - if ( count == 0 ) - ordered |= mask; - } - - NextTable: - p = p_next; - } - - face->num_kern_tables = nn; - face->kern_avail_bits = avail; - face->kern_order_bits = ordered; - - Exit: - return error; - } - - - FT_LOCAL_DEF( void ) - tt_face_done_kern( TT_Face face ) - { - FT_Stream stream = face->root.stream; - - - FT_FRAME_RELEASE( face->kern_table ); - face->kern_table_size = 0; - face->num_kern_tables = 0; - face->kern_avail_bits = 0; - face->kern_order_bits = 0; - } - - - FT_LOCAL_DEF( FT_Int ) - tt_face_get_kerning( TT_Face face, - FT_UInt left_glyph, - FT_UInt right_glyph ) - { - FT_Int result = 0; - FT_UInt count, mask = 1; - FT_Byte* p = face->kern_table; - - - p += 4; - mask = 0x0001; - - for ( count = face->num_kern_tables; count > 0; count--, mask <<= 1 ) - { - FT_Byte* base = p; - FT_Byte* next = base; - FT_UInt version = FT_NEXT_USHORT( p ); - FT_UInt length = FT_NEXT_USHORT( p ); - FT_UInt coverage = FT_NEXT_USHORT( p ); - FT_Int value = 0; - - FT_UNUSED( version ); - - - next = base + length; - - if ( ( face->kern_avail_bits & mask ) == 0 ) - goto NextTable; - - if ( p + 8 > next ) - goto NextTable; - - switch ( coverage >> 8 ) - { - case 0: - { - FT_UInt num_pairs = FT_NEXT_USHORT( p ); - FT_ULong key0 = TT_KERN_INDEX( left_glyph, right_glyph ); - - - p += 6; - - if ( face->kern_order_bits & mask ) /* binary search */ - { - FT_UInt min = 0; - FT_UInt max = num_pairs; - - - while ( min < max ) - { - FT_UInt mid = ( min + max ) >> 1; - FT_Byte* q = p + 6 * mid; - FT_ULong key; - - - key = FT_NEXT_ULONG( q ); - - if ( key == key0 ) - { - value = FT_PEEK_SHORT( q ); - goto Found; - } - if ( key < key0 ) - min = mid + 1; - else - max = mid; - } - } - else /* linear search */ - { - for ( count = num_pairs; count > 0; count-- ) - { - FT_ULong key = FT_NEXT_ULONG( p ); - - - if ( key == key0 ) - { - value = FT_PEEK_SHORT( p ); - goto Found; - } - p += 2; - } - } - } - break; - - /* - * We don't support format 2 because we've never seen a single font - * using it in real life... - */ - - default: - ; - } - - goto NextTable; - - Found: - if ( coverage & 8 ) /* overide or add */ - result = value; - else - result += value; - - NextTable: - p = next; - } - - return result; - } - -#else /* !OPTIMIZE_MEMORY */ - - FT_CALLBACK_DEF( int ) - tt_kern_pair_compare( const void* a, - const void* b ); - - - FT_LOCAL_DEF( FT_Error ) - tt_face_load_kern( TT_Face face, - FT_Stream stream ) - { - FT_Error error; - FT_Memory memory = stream->memory; - - FT_UInt n, num_tables; - - - /* the kern table is optional; exit silently if it is missing */ - error = face->goto_table( face, TTAG_kern, stream, 0 ); - if ( error ) - return SFNT_Err_Ok; - - if ( FT_FRAME_ENTER( 4L ) ) - goto Exit; - - (void)FT_GET_USHORT(); /* version */ - num_tables = FT_GET_USHORT(); - - FT_FRAME_EXIT(); - - for ( n = 0; n < num_tables; n++ ) - { - FT_UInt coverage; - FT_UInt length; - - - if ( FT_FRAME_ENTER( 6L ) ) - goto Exit; - - (void)FT_GET_USHORT(); /* version */ - length = FT_GET_USHORT() - 6; /* substract header length */ - coverage = FT_GET_USHORT(); - - FT_FRAME_EXIT(); - - if ( coverage == 0x0001 ) - { - FT_UInt num_pairs; - TT_Kern0_Pair pair; - TT_Kern0_Pair limit; - - - /* found a horizontal format 0 kerning table! */ - if ( FT_FRAME_ENTER( 8L ) ) - goto Exit; - - num_pairs = FT_GET_USHORT(); - - /* skip the rest */ - - FT_FRAME_EXIT(); - - /* allocate array of kerning pairs */ - if ( FT_QNEW_ARRAY( face->kern_pairs, num_pairs ) || - FT_FRAME_ENTER( 6L * num_pairs ) ) - goto Exit; - - pair = face->kern_pairs; - limit = pair + num_pairs; - for ( ; pair < limit; pair++ ) - { - pair->left = FT_GET_USHORT(); - pair->right = FT_GET_USHORT(); - pair->value = FT_GET_USHORT(); - } - - FT_FRAME_EXIT(); - - face->num_kern_pairs = num_pairs; - face->kern_table_index = n; - - /* ensure that the kerning pair table is sorted (yes, some */ - /* fonts have unsorted tables!) */ - - if ( num_pairs > 0 ) - { - TT_Kern0_Pair pair0 = face->kern_pairs; - FT_ULong prev = TT_KERN_INDEX( pair0->left, pair0->right ); - - - for ( pair0++; pair0 < limit; pair0++ ) - { - FT_ULong next = TT_KERN_INDEX( pair0->left, pair0->right ); - - - if ( next < prev ) - goto SortIt; - - prev = next; - } - goto Exit; - - SortIt: - ft_qsort( (void*)face->kern_pairs, (int)num_pairs, - sizeof ( TT_Kern0_PairRec ), tt_kern_pair_compare ); - } - - goto Exit; - } - - if ( FT_STREAM_SKIP( length ) ) - goto Exit; - } - - /* no kern table found -- doesn't matter */ - face->kern_table_index = -1; - face->num_kern_pairs = 0; - face->kern_pairs = NULL; - - Exit: - return error; - } - - - FT_CALLBACK_DEF( int ) - tt_kern_pair_compare( const void* a, - const void* b ) - { - TT_Kern0_Pair pair1 = (TT_Kern0_Pair)a; - TT_Kern0_Pair pair2 = (TT_Kern0_Pair)b; - - FT_ULong index1 = TT_KERN_INDEX( pair1->left, pair1->right ); - FT_ULong index2 = TT_KERN_INDEX( pair2->left, pair2->right ); - - return index1 < index2 ? -1 - : ( index1 > index2 ? 1 - : 0 ); - } - - - FT_LOCAL_DEF( void ) - tt_face_done_kern( TT_Face face ) - { - FT_Memory memory = face->root.stream->memory; - - - FT_FREE( face->kern_pairs ); - face->num_kern_pairs = 0; - } - - - FT_LOCAL_DEF( FT_Int ) - tt_face_get_kerning( TT_Face face, - FT_UInt left_glyph, - FT_UInt right_glyph ) - { - FT_Int result = 0; - TT_Kern0_Pair pair; - - - if ( face && face->kern_pairs ) - { - /* there are some kerning pairs in this font file! */ - FT_ULong search_tag = TT_KERN_INDEX( left_glyph, right_glyph ); - FT_Long left, right; - - - left = 0; - right = face->num_kern_pairs - 1; - - while ( left <= right ) - { - FT_Long middle = left + ( ( right - left ) >> 1 ); - FT_ULong cur_pair; - - - pair = face->kern_pairs + middle; - cur_pair = TT_KERN_INDEX( pair->left, pair->right ); - - if ( cur_pair == search_tag ) - goto Found; - - if ( cur_pair < search_tag ) - left = middle + 1; - else - right = middle - 1; - } - } - - Exit: - return result; - - Found: - result = pair->value; - goto Exit; - } - -#endif /* !OPTIMIZE_MEMORY */ - - -#undef TT_KERN_INDEX - -/* END */ +/***************************************************************************/ +/* */ +/* ttkern.c */ +/* */ +/* Load the basic TrueType kerning table. This doesn't handle */ +/* kerning data within the GPOS table at the moment. */ +/* */ +/* Copyright 1996-2001, 2002, 2003, 2004, 2005 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_TRUETYPE_TAGS_H +#include "ttkern.h" +#include "ttload.h" + +#include "sferrors.h" + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_ttkern + + +#undef TT_KERN_INDEX +#define TT_KERN_INDEX( g1, g2 ) ( ( (FT_ULong)(g1) << 16 ) | (g2) ) + + +#ifdef FT_OPTIMIZE_MEMORY + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_kern( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_ULong table_size; + FT_Byte* p; + FT_Byte* p_limit; + FT_UInt nn, num_tables; + FT_UInt32 avail = 0, ordered = 0; + + + /* the kern table is optional; exit silently if it is missing */ + error = face->goto_table( face, TTAG_kern, stream, &table_size ); + if ( error ) + goto Exit; + + if ( table_size < 4 ) /* the case of a malformed table */ + { + FT_ERROR(( "kerning table is too small - ignored\n" )); + error = SFNT_Err_Table_Missing; + goto Exit; + } + + if ( FT_FRAME_EXTRACT( table_size, face->kern_table ) ) + { + FT_ERROR(( "could not extract kerning table\n" )); + goto Exit; + } + + face->kern_table_size = table_size; + + p = face->kern_table; + p_limit = p + table_size; + + p += 2; /* skip version */ + num_tables = FT_NEXT_USHORT( p ); + + if ( num_tables > 32 ) /* we only support up to 32 sub-tables */ + num_tables = 32; + + for ( nn = 0; nn < num_tables; nn++ ) + { + FT_UInt num_pairs, version, length, coverage; + FT_Byte* p_next; + FT_UInt32 mask = 1UL << nn; + + + if ( p + 6 > p_limit ) + break; + + p_next = p; + + version = FT_NEXT_USHORT( p ); + length = FT_NEXT_USHORT( p ); + coverage = FT_NEXT_USHORT( p ); + + if ( length <= 6 ) + break; + + p_next += length; + + /* only use horizontal kerning tables */ + if ( ( coverage & ~8 ) != 0x0001 || + p + 8 > p_limit ) + goto NextTable; + + num_pairs = FT_NEXT_USHORT( p ); + p += 6; + + if ( p + 6 * num_pairs > p_limit ) + goto NextTable; + + avail |= mask; + + /* + * Now check whether the pairs in this table are ordered. + * We then can use binary search. + */ + if ( num_pairs > 0 ) + { + FT_UInt count; + FT_UInt old_pair; + + + old_pair = FT_NEXT_ULONG( p ); + p += 2; + + for ( count = num_pairs - 1; count > 0; count-- ) + { + FT_UInt32 cur_pair; + + + cur_pair = FT_NEXT_ULONG( p ); + if ( cur_pair <= old_pair ) + break; + + p += 2; + old_pair = cur_pair; + } + + if ( count == 0 ) + ordered |= mask; + } + + NextTable: + p = p_next; + } + + face->num_kern_tables = nn; + face->kern_avail_bits = avail; + face->kern_order_bits = ordered; + + Exit: + return error; + } + + + FT_LOCAL_DEF( void ) + tt_face_done_kern( TT_Face face ) + { + FT_Stream stream = face->root.stream; + + + FT_FRAME_RELEASE( face->kern_table ); + face->kern_table_size = 0; + face->num_kern_tables = 0; + face->kern_avail_bits = 0; + face->kern_order_bits = 0; + } + + + FT_LOCAL_DEF( FT_Int ) + tt_face_get_kerning( TT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph ) + { + FT_Int result = 0; + FT_UInt count, mask = 1; + FT_Byte* p = face->kern_table; + + + p += 4; + mask = 0x0001; + + for ( count = face->num_kern_tables; count > 0; count--, mask <<= 1 ) + { + FT_Byte* base = p; + FT_Byte* next = base; + FT_UInt version = FT_NEXT_USHORT( p ); + FT_UInt length = FT_NEXT_USHORT( p ); + FT_UInt coverage = FT_NEXT_USHORT( p ); + FT_Int value = 0; + + FT_UNUSED( version ); + + + next = base + length; + + if ( ( face->kern_avail_bits & mask ) == 0 ) + goto NextTable; + + if ( p + 8 > next ) + goto NextTable; + + switch ( coverage >> 8 ) + { + case 0: + { + FT_UInt num_pairs = FT_NEXT_USHORT( p ); + FT_ULong key0 = TT_KERN_INDEX( left_glyph, right_glyph ); + + + p += 6; + + if ( face->kern_order_bits & mask ) /* binary search */ + { + FT_UInt min = 0; + FT_UInt max = num_pairs; + + + while ( min < max ) + { + FT_UInt mid = ( min + max ) >> 1; + FT_Byte* q = p + 6 * mid; + FT_ULong key; + + + key = FT_NEXT_ULONG( q ); + + if ( key == key0 ) + { + value = FT_PEEK_SHORT( q ); + goto Found; + } + if ( key < key0 ) + min = mid + 1; + else + max = mid; + } + } + else /* linear search */ + { + for ( count = num_pairs; count > 0; count-- ) + { + FT_ULong key = FT_NEXT_ULONG( p ); + + + if ( key == key0 ) + { + value = FT_PEEK_SHORT( p ); + goto Found; + } + p += 2; + } + } + } + break; + + /* + * We don't support format 2 because we've never seen a single font + * using it in real life... + */ + + default: + ; + } + + goto NextTable; + + Found: + if ( coverage & 8 ) /* overide or add */ + result = value; + else + result += value; + + NextTable: + p = next; + } + + return result; + } + +#else /* !OPTIMIZE_MEMORY */ + + FT_CALLBACK_DEF( int ) + tt_kern_pair_compare( const void* a, + const void* b ); + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_kern( TT_Face face, + FT_Stream stream ) + { + FT_Error error; + FT_Memory memory = stream->memory; + + FT_UInt n, num_tables; + + + /* the kern table is optional; exit silently if it is missing */ + error = face->goto_table( face, TTAG_kern, stream, 0 ); + if ( error ) + return SFNT_Err_Ok; + + if ( FT_FRAME_ENTER( 4L ) ) + goto Exit; + + (void)FT_GET_USHORT(); /* version */ + num_tables = FT_GET_USHORT(); + + FT_FRAME_EXIT(); + + for ( n = 0; n < num_tables; n++ ) + { + FT_UInt coverage; + FT_UInt length; + + + if ( FT_FRAME_ENTER( 6L ) ) + goto Exit; + + (void)FT_GET_USHORT(); /* version */ + length = FT_GET_USHORT() - 6; /* substract header length */ + coverage = FT_GET_USHORT(); + + FT_FRAME_EXIT(); + + if ( coverage == 0x0001 ) + { + FT_UInt num_pairs; + TT_Kern0_Pair pair; + TT_Kern0_Pair limit; + + + /* found a horizontal format 0 kerning table! */ + if ( FT_FRAME_ENTER( 8L ) ) + goto Exit; + + num_pairs = FT_GET_USHORT(); + + /* skip the rest */ + + FT_FRAME_EXIT(); + + /* allocate array of kerning pairs */ + if ( FT_QNEW_ARRAY( face->kern_pairs, num_pairs ) || + FT_FRAME_ENTER( 6L * num_pairs ) ) + goto Exit; + + pair = face->kern_pairs; + limit = pair + num_pairs; + for ( ; pair < limit; pair++ ) + { + pair->left = FT_GET_USHORT(); + pair->right = FT_GET_USHORT(); + pair->value = FT_GET_USHORT(); + } + + FT_FRAME_EXIT(); + + face->num_kern_pairs = num_pairs; + face->kern_table_index = n; + + /* ensure that the kerning pair table is sorted (yes, some */ + /* fonts have unsorted tables!) */ + + if ( num_pairs > 0 ) + { + TT_Kern0_Pair pair0 = face->kern_pairs; + FT_ULong prev = TT_KERN_INDEX( pair0->left, pair0->right ); + + + for ( pair0++; pair0 < limit; pair0++ ) + { + FT_ULong next = TT_KERN_INDEX( pair0->left, pair0->right ); + + + if ( next < prev ) + goto SortIt; + + prev = next; + } + goto Exit; + + SortIt: + ft_qsort( (void*)face->kern_pairs, (int)num_pairs, + sizeof ( TT_Kern0_PairRec ), tt_kern_pair_compare ); + } + + goto Exit; + } + + if ( FT_STREAM_SKIP( length ) ) + goto Exit; + } + + /* no kern table found -- doesn't matter */ + face->kern_table_index = -1; + face->num_kern_pairs = 0; + face->kern_pairs = NULL; + + Exit: + return error; + } + + + FT_CALLBACK_DEF( int ) + tt_kern_pair_compare( const void* a, + const void* b ) + { + TT_Kern0_Pair pair1 = (TT_Kern0_Pair)a; + TT_Kern0_Pair pair2 = (TT_Kern0_Pair)b; + + FT_ULong index1 = TT_KERN_INDEX( pair1->left, pair1->right ); + FT_ULong index2 = TT_KERN_INDEX( pair2->left, pair2->right ); + + return index1 < index2 ? -1 + : ( index1 > index2 ? 1 + : 0 ); + } + + + FT_LOCAL_DEF( void ) + tt_face_done_kern( TT_Face face ) + { + FT_Memory memory = face->root.stream->memory; + + + FT_FREE( face->kern_pairs ); + face->num_kern_pairs = 0; + } + + + FT_LOCAL_DEF( FT_Int ) + tt_face_get_kerning( TT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph ) + { + FT_Int result = 0; + TT_Kern0_Pair pair; + + + if ( face && face->kern_pairs ) + { + /* there are some kerning pairs in this font file! */ + FT_ULong search_tag = TT_KERN_INDEX( left_glyph, right_glyph ); + FT_Long left, right; + + + left = 0; + right = face->num_kern_pairs - 1; + + while ( left <= right ) + { + FT_Long middle = left + ( ( right - left ) >> 1 ); + FT_ULong cur_pair; + + + pair = face->kern_pairs + middle; + cur_pair = TT_KERN_INDEX( pair->left, pair->right ); + + if ( cur_pair == search_tag ) + goto Found; + + if ( cur_pair < search_tag ) + left = middle + 1; + else + right = middle - 1; + } + } + + Exit: + return result; + + Found: + result = pair->value; + goto Exit; + } + +#endif /* !OPTIMIZE_MEMORY */ + + +#undef TT_KERN_INDEX + +/* END */ diff --git a/reactos/lib/freetype/src/sfnt/ttkern.h b/reactos/lib/freetype/src/sfnt/ttkern.h index 40134afe10b..18b1381b4e3 100644 --- a/reactos/lib/freetype/src/sfnt/ttkern.h +++ b/reactos/lib/freetype/src/sfnt/ttkern.h @@ -1,56 +1,56 @@ -/***************************************************************************/ -/* */ -/* ttkern.h */ -/* */ -/* Load the basic TrueType kerning table. This doesn't handle */ -/* kerning data within the GPOS table at the moment. */ -/* */ -/* Copyright 1996-2001, 2002, 2005 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - -#ifndef __TTKERN_H__ -#define __TTKERN_H__ - - -#include <ft2build.h> -#include FT_INTERNAL_STREAM_H -#include FT_INTERNAL_TRUETYPE_TYPES_H - - -FT_BEGIN_HEADER - - - FT_LOCAL( FT_Error ) - tt_face_load_kern( TT_Face face, - FT_Stream stream ); - - FT_LOCAL( void ) - tt_face_done_kern( TT_Face face ); - - FT_LOCAL( FT_Int ) - tt_face_get_kerning( TT_Face face, - FT_UInt left_glyph, - FT_UInt right_glyph ); - -#ifdef FT_OPTIMIZE_MEMORY -# define TT_FACE_HAS_KERNING( face ) ( (face)->kern_avail_bits != 0 ) -#else -# define TT_FACE_HAS_KERNING( face ) ( (face)->kern_pairs != NULL ) -#endif - - -FT_END_HEADER - -#endif /* __TTKERN_H__ */ - - -/* END */ +/***************************************************************************/ +/* */ +/* ttkern.h */ +/* */ +/* Load the basic TrueType kerning table. This doesn't handle */ +/* kerning data within the GPOS table at the moment. */ +/* */ +/* Copyright 1996-2001, 2002, 2005 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#ifndef __TTKERN_H__ +#define __TTKERN_H__ + + +#include <ft2build.h> +#include FT_INTERNAL_STREAM_H +#include FT_INTERNAL_TRUETYPE_TYPES_H + + +FT_BEGIN_HEADER + + + FT_LOCAL( FT_Error ) + tt_face_load_kern( TT_Face face, + FT_Stream stream ); + + FT_LOCAL( void ) + tt_face_done_kern( TT_Face face ); + + FT_LOCAL( FT_Int ) + tt_face_get_kerning( TT_Face face, + FT_UInt left_glyph, + FT_UInt right_glyph ); + +#ifdef FT_OPTIMIZE_MEMORY +# define TT_FACE_HAS_KERNING( face ) ( (face)->kern_avail_bits != 0 ) +#else +# define TT_FACE_HAS_KERNING( face ) ( (face)->kern_pairs != NULL ) +#endif + + +FT_END_HEADER + +#endif /* __TTKERN_H__ */ + + +/* END */ diff --git a/reactos/lib/freetype/src/sfnt/ttsbit0.c b/reactos/lib/freetype/src/sfnt/ttsbit0.c index c9ae530c2c8..31c77856f39 100644 --- a/reactos/lib/freetype/src/sfnt/ttsbit0.c +++ b/reactos/lib/freetype/src/sfnt/ttsbit0.c @@ -1,967 +1,967 @@ -/***************************************************************************/ -/* */ -/* ttsbit0.c */ -/* */ -/* TrueType and OpenType embedded bitmap support (body). */ -/* This is a heap-optimized version. */ -/* */ -/* Copyright 2005 by */ -/* David Turner, Robert Wilhelm, and Werner Lemberg. */ -/* */ -/* This file is part of the FreeType project, and may only be used, */ -/* modified, and distributed under the terms of the FreeType project */ -/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ -/* this file you indicate that you have read the license and */ -/* understand and accept it fully. */ -/* */ -/***************************************************************************/ - - -#include <ft2build.h> -#include FT_INTERNAL_DEBUG_H -#include FT_INTERNAL_STREAM_H -#include FT_TRUETYPE_TAGS_H -#include "ttsbit.h" - -#include "sferrors.h" - - - /*************************************************************************/ - /* */ - /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ - /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ - /* messages during execution. */ - /* */ -#undef FT_COMPONENT -#define FT_COMPONENT trace_ttsbit - - - static const FT_Frame_Field tt_sbit_line_metrics_fields[] = - { -#undef FT_STRUCTURE -#define FT_STRUCTURE TT_SBit_LineMetricsRec - - /* no FT_FRAME_START */ - FT_FRAME_CHAR( ascender ), - FT_FRAME_CHAR( descender ), - FT_FRAME_BYTE( max_width ), - - FT_FRAME_CHAR( caret_slope_numerator ), - FT_FRAME_CHAR( caret_slope_denominator ), - FT_FRAME_CHAR( caret_offset ), - - FT_FRAME_CHAR( min_origin_SB ), - FT_FRAME_CHAR( min_advance_SB ), - FT_FRAME_CHAR( max_before_BL ), - FT_FRAME_CHAR( min_after_BL ), - FT_FRAME_CHAR( pads[0] ), - FT_FRAME_CHAR( pads[1] ), - FT_FRAME_END - }; - - static const FT_Frame_Field tt_strike_start_fields[] = - { -#undef FT_STRUCTURE -#define FT_STRUCTURE TT_SBit_StrikeRec - - /* no FT_FRAME_START */ - FT_FRAME_ULONG( ranges_offset ), - FT_FRAME_SKIP_LONG, - FT_FRAME_ULONG( num_ranges ), - FT_FRAME_ULONG( color_ref ), - FT_FRAME_END - }; - - static const FT_Frame_Field tt_strike_end_fields[] = - { - /* no FT_FRAME_START */ - FT_FRAME_USHORT( start_glyph ), - FT_FRAME_USHORT( end_glyph ), - FT_FRAME_BYTE ( x_ppem ), - FT_FRAME_BYTE ( y_ppem ), - FT_FRAME_BYTE ( bit_depth ), - FT_FRAME_CHAR ( flags ), - FT_FRAME_END - }; - - - FT_LOCAL_DEF( FT_Error ) - tt_face_load_sbit_strikes( TT_Face face, - FT_Stream stream ) - { - FT_Error error = SFNT_Err_Ok; - FT_Fixed version; - FT_ULong num_strikes, table_size; - FT_Byte* p; - FT_Byte* p_limit; - FT_UInt nn, count; - - - face->sbit_num_strikes = 0; - - /* this table is optional */ - error = face->goto_table( face, TTAG_EBLC, stream, &table_size ); - if ( error ) - error = face->goto_table( face, TTAG_bloc, stream, &table_size ); - if ( error ) - goto Exit; - - if ( table_size < 8 ) - { - FT_ERROR(( "%s: table too short!\n", "tt_face_load_sbit_strikes" )); - error = SFNT_Err_Invalid_File_Format; - goto Exit; - } - - if ( FT_FRAME_EXTRACT( table_size, face->sbit_table ) ) - goto Exit; - - face->sbit_table_size = table_size; - - p = face->sbit_table; - p_limit = p + table_size; - - version = FT_NEXT_ULONG( p ); - num_strikes = FT_NEXT_ULONG( p ); - - if ( version != 0x00020000UL || num_strikes >= 0x10000UL ) - { - FT_ERROR(( "%s: invalid table version!\n", - "tt_face_load_sbit_strikes" )); - error = SFNT_Err_Invalid_File_Format; - goto Fail; - } - - /* - * Count the number of strikes available in the table. We are a bit - * paranoid there and don't trust the data. - */ - count = (FT_UInt)num_strikes; - if ( 8 +48UL * count > table_size ) - count = (FT_UInt)( ( p_limit - p ) / 48 ); - - face->sbit_num_strikes = count; - - /* - * Now allocate the root array of FT_Bitmap_Size records and - * populate them. Unfortunately, it isn't possible to indicate bit - * depths in the FT_Bitmap_Size record. This is a design error. - */ - { - FT_Memory memory = face->root.stream->memory; - FT_UInt em_size = (FT_UInt) face->header.Units_Per_EM; - FT_Short height = (FT_Short)( face->horizontal.Ascender - - face->horizontal.Descender + - face->horizontal.Line_Gap ); - - FT_Short avgwidth = face->os2.xAvgCharWidth; - - - if ( FT_NEW_ARRAY( face->root.available_sizes, count ) ) - goto Fail; - - for ( nn = 0; nn < count; nn++ ) - { - FT_Bitmap_Size* bsize = face->root.available_sizes + nn; - FT_UInt x_ppem, y_ppem; - - - x_ppem = p[44]; - y_ppem = p[45]; - - bsize->x_ppem = (FT_Pos)(x_ppem << 6); - bsize->y_ppem = (FT_Pos)(y_ppem << 6); - - bsize->height = (FT_Short)( height*y_ppem + em_size / 2 ) / em_size; - bsize->width = (FT_Short)( avgwidth*y_ppem + em_size / 2 ) / em_size; - bsize->size = bsize->y_ppem; - - p += 48; - } - - face->root.face_flags |= FT_FACE_FLAG_FIXED_SIZES; - face->root.num_fixed_sizes = count; - } - - Exit: - return error; - - Fail: - FT_FRAME_RELEASE( face->sbit_table ); - face->sbit_table_size = 0; - goto Exit; - } - - - FT_LOCAL_DEF( void ) - tt_face_free_sbit_strikes( TT_Face face ) - { - FT_Stream stream = face->root.stream; - - - FT_FRAME_RELEASE( face->sbit_table ); - face->sbit_table_size = 0; - face->sbit_num_strikes = 0; - } - - - FT_LOCAL_DEF( FT_Error ) - tt_face_set_sbit_strike( TT_Face face, - FT_UInt x_ppem, - FT_UInt y_ppem, - FT_ULong *astrike_index ) - { - FT_UInt nn, count; - FT_Byte* p; - FT_Byte* p_limit; - - - if ( x_ppem > 255 || - y_ppem < 1 || y_ppem > 255 ) - return SFNT_Err_Invalid_PPem; - - p = face->sbit_table + 8; - p_limit = p + face->sbit_table_size; - count = face->sbit_num_strikes; - - for ( nn = 0; nn < count; nn++ ) - { - if ( x_ppem == (FT_UInt)p[44] && y_ppem == (FT_UInt)p[45] ) - { - *astrike_index = (FT_ULong)nn; - return SFNT_Err_Ok; - } - p += 48; - } - - return SFNT_Err_Invalid_PPem; - } - - - typedef struct - { - TT_Face face; - FT_Stream stream; - FT_Bitmap* bitmap; - TT_SBit_Metrics metrics; - FT_Bool metrics_loaded; - FT_Bool bitmap_allocated; - FT_Byte bit_depth; - - FT_ULong ebdt_start; - FT_ULong ebdt_size; - - FT_ULong strike_index_array; - FT_ULong strike_index_count; - FT_Byte* eblc_base; - FT_Byte* eblc_limit; - - } TT_SBitDecoderRec, *TT_SBitDecoder; - - - static FT_Error - tt_sbit_decoder_init( TT_SBitDecoder decoder, - TT_Face face, - FT_ULong strike_index, - TT_SBit_MetricsRec* metrics ) - { - FT_Error error; - FT_Stream stream = face->root.stream; - FT_ULong ebdt_size; - - - error = face->goto_table( face, TTAG_EBDT, stream, &ebdt_size ); - if ( error ) - error = face->goto_table( face, TTAG_bdat, stream, &ebdt_size ); - if ( error ) - goto Exit; - - decoder->face = face; - decoder->stream = stream; - decoder->bitmap = &face->root.glyph->bitmap; - decoder->metrics = metrics; - - decoder->metrics_loaded = 0; - decoder->bitmap_allocated = 0; - - decoder->ebdt_start = FT_STREAM_POS(); - decoder->ebdt_size = ebdt_size; - - decoder->eblc_base = face->sbit_table; - decoder->eblc_limit = face->sbit_table + face->sbit_table_size; - - /* now find the strike corresponding to the index */ - { - FT_Byte* p = decoder->eblc_base + 8 + 48 * strike_index; - - - decoder->strike_index_array = FT_NEXT_ULONG( p ); - p += 4; - decoder->strike_index_count = FT_NEXT_ULONG( p ); - p += 34; - decoder->bit_depth = *p; - } - - Exit: - return error; - } - - - static void - tt_sbit_decoder_done( TT_SBitDecoder decoder ) - { - FT_UNUSED( decoder ); - } - - - static FT_Error - tt_sbit_decoder_alloc_bitmap( TT_SBitDecoder decoder ) - { - FT_Error error = SFNT_Err_Ok; - FT_UInt width, height; - FT_Bitmap* map = decoder->bitmap; - FT_Long size; - - - if ( !decoder->metrics_loaded ) - { - error = SFNT_Err_Invalid_Argument; - goto Exit; - } - - width = decoder->metrics->width; - height = decoder->metrics->height; - - map->width = (int)width; - map->rows = (int)height; - - switch ( decoder->bit_depth ) - { - case 1: - map->pixel_mode = FT_PIXEL_MODE_MONO; - map->pitch = ( map->width + 7 ) >> 3; - break; - - case 2: - map->pixel_mode = FT_PIXEL_MODE_GRAY2; - map->pitch = ( map->width + 3 ) >> 2; - break; - - case 4: - map->pixel_mode = FT_PIXEL_MODE_GRAY4; - map->pitch = ( map->width + 1 ) >> 1; - break; - - case 8: - map->pixel_mode = FT_PIXEL_MODE_GRAY; - map->pitch = map->width; - break; - - default: - error = SFNT_Err_Invalid_File_Format; - goto Exit; - } - - size = map->rows * map->pitch; - - /* check that there is no empty image */ - if ( size == 0 ) - goto Exit; /* exit successfully! */ - - error = ft_glyphslot_alloc_bitmap( decoder->face->root.glyph, size ); - if ( error ) - goto Exit; - - decoder->bitmap_allocated = 1; - - Exit: - return error; - } - - - static FT_Error - tt_sbit_decoder_load_metrics( TT_SBitDecoder decoder, - FT_Byte* *pp, - FT_Byte* limit, - FT_Bool big ) - { - FT_Byte* p = *pp; - TT_SBit_Metrics metrics = decoder->metrics; - - - if ( p + 5 > limit ) - goto Fail; - - if ( !decoder->metrics_loaded ) - { - metrics->height = p[0]; - metrics->width = p[1]; - metrics->horiBearingX = (FT_Char)p[2]; - metrics->horiBearingY = (FT_Char)p[3]; - metrics->horiAdvance = p[4]; - } - - p += 5; - if ( big ) - { - if ( p + 3 > limit ) - goto Fail; - - if ( !decoder->metrics_loaded ) - { - metrics->vertBearingX = (FT_Char)p[0]; - metrics->vertBearingY = (FT_Char)p[1]; - metrics->vertAdvance = p[2]; - } - - p += 3; - } - - decoder->metrics_loaded = 1; - *pp = p; - return 0; - - Fail: - return SFNT_Err_Invalid_Argument; - } - - - /* forward declaration */ - static FT_Error - tt_sbit_decoder_load_image( TT_SBitDecoder decoder, - FT_UInt glyph_index, - FT_Int x_pos, - FT_Int y_pos ); - - typedef FT_Error (*TT_SBitDecoder_LoadFunc)( TT_SBitDecoder decoder, - FT_Byte* p, - FT_Byte* plimit, - FT_Int x_pos, - FT_Int y_pos ); - - - static FT_Error - tt_sbit_decoder_load_byte_aligned( TT_SBitDecoder decoder, - FT_Byte* p, - FT_Byte* limit, - FT_Int x_pos, - FT_Int y_pos ) - { - FT_Error error = SFNT_Err_Ok; - FT_Byte* line; - FT_Int bit_height, bit_width, pitch, width, height, h; - FT_Bitmap* bitmap; - - - if ( !decoder->bitmap_allocated ) - { - error = tt_sbit_decoder_alloc_bitmap( decoder ); - if ( error ) - goto Exit; - } - - /* check that we can write the glyph into the bitmap */ - bitmap = decoder->bitmap; - bit_width = bitmap->width; - bit_height = bitmap->rows; - pitch = bitmap->pitch; - line = bitmap->buffer; - - width = decoder->metrics->width; - height = decoder->metrics->height; - - if ( x_pos < 0 || x_pos + width > bit_width || - y_pos < 0 || y_pos + height > bit_height ) - { - error = SFNT_Err_Invalid_File_Format; - goto Exit; - } - - if ( p + ( ( width + 7 ) >> 3 ) * height > limit ) - { - error = SFNT_Err_Invalid_File_Format; - goto Exit; - } - - /* now do the blit */ - line += y_pos * pitch + ( x_pos >> 3 ); - x_pos &= 7; - - if ( x_pos == 0 ) /* the easy one */ - { - for ( h = height; h > 0; h--, line += pitch ) - { - FT_Byte* write = line; - FT_Int w; - - - for ( w = width; w >= 8; w -= 8 ) - { - write[0] = (FT_Byte)( write[0] | *p++ ); - write += 1; - } - - if ( w > 0 ) - write[0] = (FT_Byte)( write[0] | ( *p++ & ( 0xFF00U >> w ) ) ); - } - } - else /* x_pos > 0 */ - { - for ( h = height; h > 0; h--, line += pitch ) - { - FT_Byte* write = line; - FT_Int w; - FT_UInt wval = 0; - - - for ( w = width; w >= 8; w -= 8 ) - { - wval = (FT_UInt)( wval | *p++ ); - write[0] = (FT_Byte)( write[0] | ( wval >> x_pos ) ); - write += 1; - wval <<= 8; - } - - if ( w > 0 ) - wval = (FT_UInt)(wval | ( *p++ & ( 0xFF00U >> w ) ) ); - - write[0] = (FT_Byte)( write[0] | ( wval >> x_pos ) ); - } - } - - Exit: - return error; - } - - - static FT_Error - tt_sbit_decoder_load_bit_aligned( TT_SBitDecoder decoder, - FT_Byte* p, - FT_Byte* limit, - FT_Int x_pos, - FT_Int y_pos ) - { - FT_Error error = SFNT_Err_Ok; - FT_Byte* line; - FT_Int bit_height, bit_width, pitch, width, height, h; - FT_Bitmap* bitmap; - FT_UInt32 rval; - - - if ( !decoder->bitmap_allocated ) - { - error = tt_sbit_decoder_alloc_bitmap( decoder ); - if ( error ) - goto Exit; - } - - /* check that we can write the glyph into the bitmap */ - bitmap = decoder->bitmap; - bit_width = bitmap->width; - bit_height = bitmap->rows; - pitch = bitmap->pitch; - line = bitmap->buffer; - - width = decoder->metrics->width; - height = decoder->metrics->height; - - if ( x_pos < 0 || x_pos + width > bit_width || - y_pos < 0 || y_pos + height > bit_height ) - { - error = SFNT_Err_Invalid_File_Format; - goto Exit; - } - - if ( p + ( ( width + 7 ) >> 3 ) * height > limit ) - { - error = SFNT_Err_Invalid_File_Format; - goto Exit; - } - - /* now do the blit */ - line += y_pos * pitch + ( x_pos >> 3 ); - x_pos &= 7; - rval = 0x10000UL; - - for ( h = height; h > 0; h--, line += pitch ) - { - FT_Byte* write = line; - FT_UInt32 wval = 0x100 << x_pos; - FT_Int w; - - - for ( w = width; w >= 8; w -= 8 ) - { - if ( rval & 0x10000UL ) - rval = 0x100 | *p++; - - wval |= rval & 0x80; - - wval <<= 1; - rval <<= 1; - - if ( wval & 0x10000UL ) - { - write[0] = (FT_Byte)( write[0] | ( wval >> 8 ) ); - write += 1; - wval = 0x100; - } - } - - if ( wval != 0x100 ) - { - while ( wval > 0x1FF ) - wval >>= 1; - - write[0] = (FT_Byte)( write[0] | wval ); - } - } - - Exit: - return error; - } - - - static FT_Error - tt_sbit_decoder_load_compound( TT_SBitDecoder decoder, - FT_Byte* p, - FT_Byte* limit, - FT_Int x_pos, - FT_Int y_pos ) - { - FT_Error error = SFNT_Err_Ok; - FT_UInt num_components, nn; - - - if ( p + 2 > limit ) - goto Fail; - - num_components = FT_NEXT_USHORT( p ); - if ( p + 4 * num_components > limit ) - goto Fail; - - for ( nn = 0; nn < num_components; nn++ ) - { - FT_UInt gindex = FT_NEXT_USHORT( p ); - FT_Byte dx = FT_NEXT_BYTE( p ); - FT_Byte dy = FT_NEXT_BYTE( p ); - - - /* NB: a recursive call */ - error = tt_sbit_decoder_load_image( decoder, gindex, - x_pos + dx, y_pos + dy ); - if ( error ) - break; - } - - Exit: - return error; - - Fail: - error = SFNT_Err_Invalid_File_Format; - goto Exit; - } - - - static FT_Error - tt_sbit_decoder_load_bitmap( TT_SBitDecoder decoder, - FT_UInt glyph_format, - FT_ULong glyph_start, - FT_ULong glyph_size, - FT_Int x_pos, - FT_Int y_pos ) - { - FT_Error error; - FT_Stream stream = decoder->stream; - FT_Byte* p; - FT_Byte* p_limit; - FT_Byte* data; - - - /* seek into the EBDT table now */ - if ( glyph_start + glyph_size > decoder->ebdt_size ) - { - error = SFNT_Err_Invalid_Argument; - goto Exit; - } - - if ( FT_STREAM_SEEK( decoder->ebdt_start + glyph_start ) || - FT_FRAME_EXTRACT( glyph_size, data ) ) - goto Exit; - - p = data; - p_limit = p + glyph_size; - - /* read the data, depending on the glyph format */ - switch ( glyph_format ) - { - case 1: - case 2: - case 8: - error = tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 0 ); - break; - - case 6: - case 7: - case 9: - error = tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ); - break; - - default: - error = SFNT_Err_Ok; - } - - if ( error ) - goto Fail; - - { - TT_SBitDecoder_LoadFunc loader; - - - switch ( glyph_format ) - { - case 1: - case 6: - loader = tt_sbit_decoder_load_byte_aligned; - break; - - case 2: - case 5: - case 7: - loader = tt_sbit_decoder_load_bit_aligned; - break; - - case 8: - if ( p + 1 > p_limit ) - goto Fail; - - p += 1; /* skip padding */ - /* fall-through */ - - case 9: - loader = tt_sbit_decoder_load_compound; - break; - - default: - goto Fail; - } - - error = loader( decoder, p, p_limit, x_pos, y_pos ); - } - - Fail: - FT_FRAME_RELEASE( data ); - - Exit: - return error; - } - - - static FT_Error - tt_sbit_decoder_load_image( TT_SBitDecoder decoder, - FT_UInt glyph_index, - FT_Int x_pos, - FT_Int y_pos ) - { - /* - * First, we find the correct strike range that applies to this - * glyph index. - */ - - FT_Byte* p = decoder->eblc_base + decoder->strike_index_array; - FT_Byte* p_limit = decoder->eblc_limit; - FT_ULong num_ranges = decoder->strike_index_count; - FT_UInt start, end, index_format, image_format; - FT_ULong image_start = 0, image_end = 0, image_offset; - - - if ( p + 8 * num_ranges > p_limit ) - goto NoBitmap; - - for ( ; num_ranges > 0; num_ranges-- ) - { - start = FT_NEXT_USHORT( p ); - end = FT_NEXT_USHORT( p ); - - if ( glyph_index >= start && glyph_index <= end ) - goto FoundRange; - - p += 4; /* ignore index offset */ - } - goto NoBitmap; - - FoundRange: - image_offset = FT_NEXT_ULONG( p ); - p = decoder->eblc_base + decoder->strike_index_array + image_offset; - if ( p + 8 > p_limit ) - goto NoBitmap; - - /* now find the glyph's location and extend within the ebdt table */ - index_format = FT_NEXT_USHORT( p ); - image_format = FT_NEXT_USHORT( p ); - image_offset = FT_NEXT_ULONG ( p ); - - switch ( index_format ) - { - case 1: /* 4-byte offsets relative to `image_offset' */ - { - p += 4 * ( glyph_index - start ); - if ( p + 8 > p_limit ) - goto NoBitmap; - - image_start = FT_NEXT_ULONG( p ); - image_end = FT_NEXT_ULONG( p ); - - if ( image_start == image_end ) /* missing glyph */ - goto NoBitmap; - } - break; - - case 2: /* big metrics, constant image size */ - { - FT_ULong image_size; - - - if ( p + 12 > p_limit ) - goto NoBitmap; - - image_size = FT_NEXT_ULONG( p ); - - if ( tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ) ) - goto NoBitmap; - - image_start = image_offset + image_size * ( glyph_index - start ); - image_end = image_start + image_size; - } - break; - - case 3: /* 2-byte offsets relative to 'image_offset' */ - { - p += 2 * ( glyph_index - start ); - if ( p + 4 > p_limit ) - goto NoBitmap; - - image_start = FT_NEXT_USHORT( p ); - image_end = FT_NEXT_USHORT( p ); - - if ( image_start == image_end ) /* missing glyph */ - goto NoBitmap; - } - break; - - case 4: /* sparse glyph array with (glyph,offset) pairs */ - { - FT_ULong mm, num_glyphs; - - - if ( p + 4 > p_limit ) - goto NoBitmap; - - num_glyphs = FT_NEXT_ULONG( p ); - if ( p + ( num_glyphs + 1 ) * 4 > p_limit ) - goto NoBitmap; - - for ( mm = 0; mm < num_glyphs; mm++ ) - { - FT_UInt gindex = FT_NEXT_USHORT( p ); - - - if ( gindex == glyph_index ) - { - image_start = FT_NEXT_USHORT( p ); - p += 2; - image_end = FT_PEEK_USHORT( p ); - break; - } - p += 2; - } - - if ( mm >= num_glyphs ) - goto NoBitmap; - } - break; - - case 5: /* constant metrics with sparse glyph codes */ - { - FT_ULong image_size, mm, num_glyphs; - - - if ( p + 16 > p_limit ) - goto NoBitmap; - - image_size = FT_NEXT_ULONG( p ); - - if ( tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ) ) - goto NoBitmap; - - num_glyphs = FT_NEXT_ULONG( p ); - if ( p + 2 * num_glyphs > p_limit ) - goto NoBitmap; - - for ( mm = 0; mm < num_glyphs; mm++ ) - { - FT_UInt gindex = FT_NEXT_USHORT( p ); - - - if ( gindex == glyph_index ) - break; - } - - if ( mm >= num_glyphs ) - goto NoBitmap; - - image_start = image_offset + image_size*mm; - image_end = image_start + image_size; - } - break; - - default: - goto NoBitmap; - } - - if ( image_start > image_end ) - goto NoBitmap; - - image_end -= image_start; - image_start = image_offset + image_start; - - return tt_sbit_decoder_load_bitmap( decoder, - image_format, - image_start, - image_end, - x_pos, - y_pos ); - - NoBitmap: - return SFNT_Err_Invalid_Argument; - } - - - FT_LOCAL( FT_Error ) - tt_face_load_sbit_image( TT_Face face, - FT_ULong strike_index, - FT_UInt glyph_index, - FT_UInt load_flags, - FT_Stream stream, - FT_Bitmap *map, - TT_SBit_MetricsRec *metrics ) - { - TT_SBitDecoderRec decoder[1]; - FT_Error error; - - FT_UNUSED( load_flags ); - FT_UNUSED( stream ); - FT_UNUSED( map ); - - - error = tt_sbit_decoder_init( decoder, face, strike_index, metrics ); - if ( !error ) - { - error = tt_sbit_decoder_load_image( decoder, glyph_index, 0, 0 ); - tt_sbit_decoder_done( decoder ); - } - - return error; - } - -/* EOF */ +/***************************************************************************/ +/* */ +/* ttsbit0.c */ +/* */ +/* TrueType and OpenType embedded bitmap support (body). */ +/* This is a heap-optimized version. */ +/* */ +/* Copyright 2005 by */ +/* David Turner, Robert Wilhelm, and Werner Lemberg. */ +/* */ +/* This file is part of the FreeType project, and may only be used, */ +/* modified, and distributed under the terms of the FreeType project */ +/* license, LICENSE.TXT. By continuing to use, modify, or distribute */ +/* this file you indicate that you have read the license and */ +/* understand and accept it fully. */ +/* */ +/***************************************************************************/ + + +#include <ft2build.h> +#include FT_INTERNAL_DEBUG_H +#include FT_INTERNAL_STREAM_H +#include FT_TRUETYPE_TAGS_H +#include "ttsbit.h" + +#include "sferrors.h" + + + /*************************************************************************/ + /* */ + /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ + /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ + /* messages during execution. */ + /* */ +#undef FT_COMPONENT +#define FT_COMPONENT trace_ttsbit + + + static const FT_Frame_Field tt_sbit_line_metrics_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_SBit_LineMetricsRec + + /* no FT_FRAME_START */ + FT_FRAME_CHAR( ascender ), + FT_FRAME_CHAR( descender ), + FT_FRAME_BYTE( max_width ), + + FT_FRAME_CHAR( caret_slope_numerator ), + FT_FRAME_CHAR( caret_slope_denominator ), + FT_FRAME_CHAR( caret_offset ), + + FT_FRAME_CHAR( min_origin_SB ), + FT_FRAME_CHAR( min_advance_SB ), + FT_FRAME_CHAR( max_before_BL ), + FT_FRAME_CHAR( min_after_BL ), + FT_FRAME_CHAR( pads[0] ), + FT_FRAME_CHAR( pads[1] ), + FT_FRAME_END + }; + + static const FT_Frame_Field tt_strike_start_fields[] = + { +#undef FT_STRUCTURE +#define FT_STRUCTURE TT_SBit_StrikeRec + + /* no FT_FRAME_START */ + FT_FRAME_ULONG( ranges_offset ), + FT_FRAME_SKIP_LONG, + FT_FRAME_ULONG( num_ranges ), + FT_FRAME_ULONG( color_ref ), + FT_FRAME_END + }; + + static const FT_Frame_Field tt_strike_end_fields[] = + { + /* no FT_FRAME_START */ + FT_FRAME_USHORT( start_glyph ), + FT_FRAME_USHORT( end_glyph ), + FT_FRAME_BYTE ( x_ppem ), + FT_FRAME_BYTE ( y_ppem ), + FT_FRAME_BYTE ( bit_depth ), + FT_FRAME_CHAR ( flags ), + FT_FRAME_END + }; + + + FT_LOCAL_DEF( FT_Error ) + tt_face_load_sbit_strikes( TT_Face face, + FT_Stream stream ) + { + FT_Error error = SFNT_Err_Ok; + FT_Fixed version; + FT_ULong num_strikes, table_size; + FT_Byte* p; + FT_Byte* p_limit; + FT_UInt nn, count; + + + face->sbit_num_strikes = 0; + + /* this table is optional */ + error = face->goto_table( face, TTAG_EBLC, stream, &table_size ); + if ( error ) + error = face->goto_table( face, TTAG_bloc, stream, &table_size ); + if ( error ) + goto Exit; + + if ( table_size < 8 ) + { + FT_ERROR(( "%s: table too short!\n", "tt_face_load_sbit_strikes" )); + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + + if ( FT_FRAME_EXTRACT( table_size, face->sbit_table ) ) + goto Exit; + + face->sbit_table_size = table_size; + + p = face->sbit_table; + p_limit = p + table_size; + + version = FT_NEXT_ULONG( p ); + num_strikes = FT_NEXT_ULONG( p ); + + if ( version != 0x00020000UL || num_strikes >= 0x10000UL ) + { + FT_ERROR(( "%s: invalid table version!\n", + "tt_face_load_sbit_strikes" )); + error = SFNT_Err_Invalid_File_Format; + goto Fail; + } + + /* + * Count the number of strikes available in the table. We are a bit + * paranoid there and don't trust the data. + */ + count = (FT_UInt)num_strikes; + if ( 8 +48UL * count > table_size ) + count = (FT_UInt)( ( p_limit - p ) / 48 ); + + face->sbit_num_strikes = count; + + /* + * Now allocate the root array of FT_Bitmap_Size records and + * populate them. Unfortunately, it isn't possible to indicate bit + * depths in the FT_Bitmap_Size record. This is a design error. + */ + { + FT_Memory memory = face->root.stream->memory; + FT_UInt em_size = (FT_UInt) face->header.Units_Per_EM; + FT_Short height = (FT_Short)( face->horizontal.Ascender - + face->horizontal.Descender + + face->horizontal.Line_Gap ); + + FT_Short avgwidth = face->os2.xAvgCharWidth; + + + if ( FT_NEW_ARRAY( face->root.available_sizes, count ) ) + goto Fail; + + for ( nn = 0; nn < count; nn++ ) + { + FT_Bitmap_Size* bsize = face->root.available_sizes + nn; + FT_UInt x_ppem, y_ppem; + + + x_ppem = p[44]; + y_ppem = p[45]; + + bsize->x_ppem = (FT_Pos)(x_ppem << 6); + bsize->y_ppem = (FT_Pos)(y_ppem << 6); + + bsize->height = (FT_Short)( height*y_ppem + em_size / 2 ) / em_size; + bsize->width = (FT_Short)( avgwidth*y_ppem + em_size / 2 ) / em_size; + bsize->size = bsize->y_ppem; + + p += 48; + } + + face->root.face_flags |= FT_FACE_FLAG_FIXED_SIZES; + face->root.num_fixed_sizes = count; + } + + Exit: + return error; + + Fail: + FT_FRAME_RELEASE( face->sbit_table ); + face->sbit_table_size = 0; + goto Exit; + } + + + FT_LOCAL_DEF( void ) + tt_face_free_sbit_strikes( TT_Face face ) + { + FT_Stream stream = face->root.stream; + + + FT_FRAME_RELEASE( face->sbit_table ); + face->sbit_table_size = 0; + face->sbit_num_strikes = 0; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_set_sbit_strike( TT_Face face, + FT_UInt x_ppem, + FT_UInt y_ppem, + FT_ULong *astrike_index ) + { + FT_UInt nn, count; + FT_Byte* p; + FT_Byte* p_limit; + + + if ( x_ppem > 255 || + y_ppem < 1 || y_ppem > 255 ) + return SFNT_Err_Invalid_PPem; + + p = face->sbit_table + 8; + p_limit = p + face->sbit_table_size; + count = face->sbit_num_strikes; + + for ( nn = 0; nn < count; nn++ ) + { + if ( x_ppem == (FT_UInt)p[44] && y_ppem == (FT_UInt)p[45] ) + { + *astrike_index = (FT_ULong)nn; + return SFNT_Err_Ok; + } + p += 48; + } + + return SFNT_Err_Invalid_PPem; + } + + + typedef struct + { + TT_Face face; + FT_Stream stream; + FT_Bitmap* bitmap; + TT_SBit_Metrics metrics; + FT_Bool metrics_loaded; + FT_Bool bitmap_allocated; + FT_Byte bit_depth; + + FT_ULong ebdt_start; + FT_ULong ebdt_size; + + FT_ULong strike_index_array; + FT_ULong strike_index_count; + FT_Byte* eblc_base; + FT_Byte* eblc_limit; + + } TT_SBitDecoderRec, *TT_SBitDecoder; + + + static FT_Error + tt_sbit_decoder_init( TT_SBitDecoder decoder, + TT_Face face, + FT_ULong strike_index, + TT_SBit_MetricsRec* metrics ) + { + FT_Error error; + FT_Stream stream = face->root.stream; + FT_ULong ebdt_size; + + + error = face->goto_table( face, TTAG_EBDT, stream, &ebdt_size ); + if ( error ) + error = face->goto_table( face, TTAG_bdat, stream, &ebdt_size ); + if ( error ) + goto Exit; + + decoder->face = face; + decoder->stream = stream; + decoder->bitmap = &face->root.glyph->bitmap; + decoder->metrics = metrics; + + decoder->metrics_loaded = 0; + decoder->bitmap_allocated = 0; + + decoder->ebdt_start = FT_STREAM_POS(); + decoder->ebdt_size = ebdt_size; + + decoder->eblc_base = face->sbit_table; + decoder->eblc_limit = face->sbit_table + face->sbit_table_size; + + /* now find the strike corresponding to the index */ + { + FT_Byte* p = decoder->eblc_base + 8 + 48 * strike_index; + + + decoder->strike_index_array = FT_NEXT_ULONG( p ); + p += 4; + decoder->strike_index_count = FT_NEXT_ULONG( p ); + p += 34; + decoder->bit_depth = *p; + } + + Exit: + return error; + } + + + static void + tt_sbit_decoder_done( TT_SBitDecoder decoder ) + { + FT_UNUSED( decoder ); + } + + + static FT_Error + tt_sbit_decoder_alloc_bitmap( TT_SBitDecoder decoder ) + { + FT_Error error = SFNT_Err_Ok; + FT_UInt width, height; + FT_Bitmap* map = decoder->bitmap; + FT_Long size; + + + if ( !decoder->metrics_loaded ) + { + error = SFNT_Err_Invalid_Argument; + goto Exit; + } + + width = decoder->metrics->width; + height = decoder->metrics->height; + + map->width = (int)width; + map->rows = (int)height; + + switch ( decoder->bit_depth ) + { + case 1: + map->pixel_mode = FT_PIXEL_MODE_MONO; + map->pitch = ( map->width + 7 ) >> 3; + break; + + case 2: + map->pixel_mode = FT_PIXEL_MODE_GRAY2; + map->pitch = ( map->width + 3 ) >> 2; + break; + + case 4: + map->pixel_mode = FT_PIXEL_MODE_GRAY4; + map->pitch = ( map->width + 1 ) >> 1; + break; + + case 8: + map->pixel_mode = FT_PIXEL_MODE_GRAY; + map->pitch = map->width; + break; + + default: + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + + size = map->rows * map->pitch; + + /* check that there is no empty image */ + if ( size == 0 ) + goto Exit; /* exit successfully! */ + + error = ft_glyphslot_alloc_bitmap( decoder->face->root.glyph, size ); + if ( error ) + goto Exit; + + decoder->bitmap_allocated = 1; + + Exit: + return error; + } + + + static FT_Error + tt_sbit_decoder_load_metrics( TT_SBitDecoder decoder, + FT_Byte* *pp, + FT_Byte* limit, + FT_Bool big ) + { + FT_Byte* p = *pp; + TT_SBit_Metrics metrics = decoder->metrics; + + + if ( p + 5 > limit ) + goto Fail; + + if ( !decoder->metrics_loaded ) + { + metrics->height = p[0]; + metrics->width = p[1]; + metrics->horiBearingX = (FT_Char)p[2]; + metrics->horiBearingY = (FT_Char)p[3]; + metrics->horiAdvance = p[4]; + } + + p += 5; + if ( big ) + { + if ( p + 3 > limit ) + goto Fail; + + if ( !decoder->metrics_loaded ) + { + metrics->vertBearingX = (FT_Char)p[0]; + metrics->vertBearingY = (FT_Char)p[1]; + metrics->vertAdvance = p[2]; + } + + p += 3; + } + + decoder->metrics_loaded = 1; + *pp = p; + return 0; + + Fail: + return SFNT_Err_Invalid_Argument; + } + + + /* forward declaration */ + static FT_Error + tt_sbit_decoder_load_image( TT_SBitDecoder decoder, + FT_UInt glyph_index, + FT_Int x_pos, + FT_Int y_pos ); + + typedef FT_Error (*TT_SBitDecoder_LoadFunc)( TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* plimit, + FT_Int x_pos, + FT_Int y_pos ); + + + static FT_Error + tt_sbit_decoder_load_byte_aligned( TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* limit, + FT_Int x_pos, + FT_Int y_pos ) + { + FT_Error error = SFNT_Err_Ok; + FT_Byte* line; + FT_Int bit_height, bit_width, pitch, width, height, h; + FT_Bitmap* bitmap; + + + if ( !decoder->bitmap_allocated ) + { + error = tt_sbit_decoder_alloc_bitmap( decoder ); + if ( error ) + goto Exit; + } + + /* check that we can write the glyph into the bitmap */ + bitmap = decoder->bitmap; + bit_width = bitmap->width; + bit_height = bitmap->rows; + pitch = bitmap->pitch; + line = bitmap->buffer; + + width = decoder->metrics->width; + height = decoder->metrics->height; + + if ( x_pos < 0 || x_pos + width > bit_width || + y_pos < 0 || y_pos + height > bit_height ) + { + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + + if ( p + ( ( width + 7 ) >> 3 ) * height > limit ) + { + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + + /* now do the blit */ + line += y_pos * pitch + ( x_pos >> 3 ); + x_pos &= 7; + + if ( x_pos == 0 ) /* the easy one */ + { + for ( h = height; h > 0; h--, line += pitch ) + { + FT_Byte* write = line; + FT_Int w; + + + for ( w = width; w >= 8; w -= 8 ) + { + write[0] = (FT_Byte)( write[0] | *p++ ); + write += 1; + } + + if ( w > 0 ) + write[0] = (FT_Byte)( write[0] | ( *p++ & ( 0xFF00U >> w ) ) ); + } + } + else /* x_pos > 0 */ + { + for ( h = height; h > 0; h--, line += pitch ) + { + FT_Byte* write = line; + FT_Int w; + FT_UInt wval = 0; + + + for ( w = width; w >= 8; w -= 8 ) + { + wval = (FT_UInt)( wval | *p++ ); + write[0] = (FT_Byte)( write[0] | ( wval >> x_pos ) ); + write += 1; + wval <<= 8; + } + + if ( w > 0 ) + wval = (FT_UInt)(wval | ( *p++ & ( 0xFF00U >> w ) ) ); + + write[0] = (FT_Byte)( write[0] | ( wval >> x_pos ) ); + } + } + + Exit: + return error; + } + + + static FT_Error + tt_sbit_decoder_load_bit_aligned( TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* limit, + FT_Int x_pos, + FT_Int y_pos ) + { + FT_Error error = SFNT_Err_Ok; + FT_Byte* line; + FT_Int bit_height, bit_width, pitch, width, height, h; + FT_Bitmap* bitmap; + FT_UInt32 rval; + + + if ( !decoder->bitmap_allocated ) + { + error = tt_sbit_decoder_alloc_bitmap( decoder ); + if ( error ) + goto Exit; + } + + /* check that we can write the glyph into the bitmap */ + bitmap = decoder->bitmap; + bit_width = bitmap->width; + bit_height = bitmap->rows; + pitch = bitmap->pitch; + line = bitmap->buffer; + + width = decoder->metrics->width; + height = decoder->metrics->height; + + if ( x_pos < 0 || x_pos + width > bit_width || + y_pos < 0 || y_pos + height > bit_height ) + { + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + + if ( p + ( ( width + 7 ) >> 3 ) * height > limit ) + { + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + + /* now do the blit */ + line += y_pos * pitch + ( x_pos >> 3 ); + x_pos &= 7; + rval = 0x10000UL; + + for ( h = height; h > 0; h--, line += pitch ) + { + FT_Byte* write = line; + FT_UInt32 wval = 0x100 << x_pos; + FT_Int w; + + + for ( w = width; w >= 8; w -= 8 ) + { + if ( rval & 0x10000UL ) + rval = 0x100 | *p++; + + wval |= rval & 0x80; + + wval <<= 1; + rval <<= 1; + + if ( wval & 0x10000UL ) + { + write[0] = (FT_Byte)( write[0] | ( wval >> 8 ) ); + write += 1; + wval = 0x100; + } + } + + if ( wval != 0x100 ) + { + while ( wval > 0x1FF ) + wval >>= 1; + + write[0] = (FT_Byte)( write[0] | wval ); + } + } + + Exit: + return error; + } + + + static FT_Error + tt_sbit_decoder_load_compound( TT_SBitDecoder decoder, + FT_Byte* p, + FT_Byte* limit, + FT_Int x_pos, + FT_Int y_pos ) + { + FT_Error error = SFNT_Err_Ok; + FT_UInt num_components, nn; + + + if ( p + 2 > limit ) + goto Fail; + + num_components = FT_NEXT_USHORT( p ); + if ( p + 4 * num_components > limit ) + goto Fail; + + for ( nn = 0; nn < num_components; nn++ ) + { + FT_UInt gindex = FT_NEXT_USHORT( p ); + FT_Byte dx = FT_NEXT_BYTE( p ); + FT_Byte dy = FT_NEXT_BYTE( p ); + + + /* NB: a recursive call */ + error = tt_sbit_decoder_load_image( decoder, gindex, + x_pos + dx, y_pos + dy ); + if ( error ) + break; + } + + Exit: + return error; + + Fail: + error = SFNT_Err_Invalid_File_Format; + goto Exit; + } + + + static FT_Error + tt_sbit_decoder_load_bitmap( TT_SBitDecoder decoder, + FT_UInt glyph_format, + FT_ULong glyph_start, + FT_ULong glyph_size, + FT_Int x_pos, + FT_Int y_pos ) + { + FT_Error error; + FT_Stream stream = decoder->stream; + FT_Byte* p; + FT_Byte* p_limit; + FT_Byte* data; + + + /* seek into the EBDT table now */ + if ( glyph_start + glyph_size > decoder->ebdt_size ) + { + error = SFNT_Err_Invalid_Argument; + goto Exit; + } + + if ( FT_STREAM_SEEK( decoder->ebdt_start + glyph_start ) || + FT_FRAME_EXTRACT( glyph_size, data ) ) + goto Exit; + + p = data; + p_limit = p + glyph_size; + + /* read the data, depending on the glyph format */ + switch ( glyph_format ) + { + case 1: + case 2: + case 8: + error = tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 0 ); + break; + + case 6: + case 7: + case 9: + error = tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ); + break; + + default: + error = SFNT_Err_Ok; + } + + if ( error ) + goto Fail; + + { + TT_SBitDecoder_LoadFunc loader; + + + switch ( glyph_format ) + { + case 1: + case 6: + loader = tt_sbit_decoder_load_byte_aligned; + break; + + case 2: + case 5: + case 7: + loader = tt_sbit_decoder_load_bit_aligned; + break; + + case 8: + if ( p + 1 > p_limit ) + goto Fail; + + p += 1; /* skip padding */ + /* fall-through */ + + case 9: + loader = tt_sbit_decoder_load_compound; + break; + + default: + goto Fail; + } + + error = loader( decoder, p, p_limit, x_pos, y_pos ); + } + + Fail: + FT_FRAME_RELEASE( data ); + + Exit: + return error; + } + + + static FT_Error + tt_sbit_decoder_load_image( TT_SBitDecoder decoder, + FT_UInt glyph_index, + FT_Int x_pos, + FT_Int y_pos ) + { + /* + * First, we find the correct strike range that applies to this + * glyph index. + */ + + FT_Byte* p = decoder->eblc_base + decoder->strike_index_array; + FT_Byte* p_limit = decoder->eblc_limit; + FT_ULong num_ranges = decoder->strike_index_count; + FT_UInt start, end, index_format, image_format; + FT_ULong image_start = 0, image_end = 0, image_offset; + + + if ( p + 8 * num_ranges > p_limit ) + goto NoBitmap; + + for ( ; num_ranges > 0; num_ranges-- ) + { + start = FT_NEXT_USHORT( p ); + end = FT_NEXT_USHORT( p ); + + if ( glyph_index >= start && glyph_index <= end ) + goto FoundRange; + + p += 4; /* ignore index offset */ + } + goto NoBitmap; + + FoundRange: + image_offset = FT_NEXT_ULONG( p ); + p = decoder->eblc_base + decoder->strike_index_array + image_offset; + if ( p + 8 > p_limit ) + goto NoBitmap; + + /* now find the glyph's location and extend within the ebdt table */ + index_format = FT_NEXT_USHORT( p ); + image_format = FT_NEXT_USHORT( p ); + image_offset = FT_NEXT_ULONG ( p ); + + switch ( index_format ) + { + case 1: /* 4-byte offsets relative to `image_offset' */ + { + p += 4 * ( glyph_index - start ); + if ( p + 8 > p_limit ) + goto NoBitmap; + + image_start = FT_NEXT_ULONG( p ); + image_end = FT_NEXT_ULONG( p ); + + if ( image_start == image_end ) /* missing glyph */ + goto NoBitmap; + } + break; + + case 2: /* big metrics, constant image size */ + { + FT_ULong image_size; + + + if ( p + 12 > p_limit ) + goto NoBitmap; + + image_size = FT_NEXT_ULONG( p ); + + if ( tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ) ) + goto NoBitmap; + + image_start = image_offset + image_size * ( glyph_index - start ); + image_end = image_start + image_size; + } + break; + + case 3: /* 2-byte offsets relative to 'image_offset' */ + { + p += 2 * ( glyph_index - start ); + if ( p + 4 > p_limit ) + goto NoBitmap; + + image_start = FT_NEXT_USHORT( p ); + image_end = FT_NEXT_USHORT( p ); + + if ( image_start == image_end ) /* missing glyph */ + goto NoBitmap; + } + break; + + case 4: /* sparse glyph array with (glyph,offset) pairs */ + { + FT_ULong mm, num_glyphs; + + + if ( p + 4 > p_limit ) + goto NoBitmap; + + num_glyphs = FT_NEXT_ULONG( p ); + if ( p + ( num_glyphs + 1 ) * 4 > p_limit ) + goto NoBitmap; + + for ( mm = 0; mm < num_glyphs; mm++ ) + { + FT_UInt gindex = FT_NEXT_USHORT( p ); + + + if ( gindex == glyph_index ) + { + image_start = FT_NEXT_USHORT( p ); + p += 2; + image_end = FT_PEEK_USHORT( p ); + break; + } + p += 2; + } + + if ( mm >= num_glyphs ) + goto NoBitmap; + } + break; + + case 5: /* constant metrics with sparse glyph codes */ + { + FT_ULong image_size, mm, num_glyphs; + + + if ( p + 16 > p_limit ) + goto NoBitmap; + + image_size = FT_NEXT_ULONG( p ); + + if ( tt_sbit_decoder_load_metrics( decoder, &p, p_limit, 1 ) ) + goto NoBitmap; + + num_glyphs = FT_NEXT_ULONG( p ); + if ( p + 2 * num_glyphs > p_limit ) + goto NoBitmap; + + for ( mm = 0; mm < num_glyphs; mm++ ) + { + FT_UInt gindex = FT_NEXT_USHORT( p ); + + + if ( gindex == glyph_index ) + break; + } + + if ( mm >= num_glyphs ) + goto NoBitmap; + + image_start = image_offset + image_size*mm; + image_end = image_start + image_size; + } + break; + + default: + goto NoBitmap; + } + + if ( image_start > image_end ) + goto NoBitmap; + + image_end -= image_start; + image_start = image_offset + image_start; + + return tt_sbit_decoder_load_bitmap( decoder, + image_format, + image_start, + image_end, + x_pos, + y_pos ); + + NoBitmap: + return SFNT_Err_Invalid_Argument; + } + + + FT_LOCAL( FT_Error ) + tt_face_load_sbit_image( TT_Face face, + FT_ULong strike_index, + FT_UInt glyph_index, + FT_UInt load_flags, + FT_Stream stream, + FT_Bitmap *map, + TT_SBit_MetricsRec *metrics ) + { + TT_SBitDecoderRec decoder[1]; + FT_Error error; + + FT_UNUSED( load_flags ); + FT_UNUSED( stream ); + FT_UNUSED( map ); + + + error = tt_sbit_decoder_init( decoder, face, strike_index, metrics ); + if ( !error ) + { + error = tt_sbit_decoder_load_image( decoder, glyph_index, 0, 0 ); + tt_sbit_decoder_done( decoder ); + } + + return error; + } + +/* EOF */ diff --git a/reactos/lib/freetype/src/sfnt/ttsbit0.h b/reactos/lib/freetype/src/sfnt/ttsbit0.h index 647db5f1c4f..396ddc555e5 100644 --- a/reactos/lib/freetype/src/sfnt/ttsbit0.h +++ b/reactos/lib/freetype/src/sfnt/ttsbit0.h @@ -1,7 +1,7 @@ -/* - * ttsbit0.h - * - * This is a dummy file, used to please the build system. It is never - * included by the sfnt sources. - * - */ +/* + * ttsbit0.h + * + * This is a dummy file, used to please the build system. It is never + * included by the sfnt sources. + * + */ diff --git a/reactos/lib/fslib/vfatxlib/fatx.c b/reactos/lib/fslib/vfatxlib/fatx.c index 84eb9feb79c..aba3027d43b 100644 --- a/reactos/lib/fslib/vfatxlib/fatx.c +++ b/reactos/lib/fslib/vfatxlib/fatx.c @@ -1,427 +1,427 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS VFATX filesystem library - * FILE: fatx.c - * PURPOSE: Fatx support - * PROGRAMMERS: Hartmut Birr - * REVISIONS: - */ -#include "vfatxlib.h" - -#define NDEBUG -#include <debug.h> - -static ULONG -GetShiftCount(ULONG Value) -{ - ULONG i = 1; - while (Value > 0) - { - i++; - Value /= 2; - } - return i - 2; -} - - -static ULONG -CalcVolumeSerialNumber(VOID) -{ - LARGE_INTEGER SystemTime; - TIME_FIELDS TimeFields; - ULONG Serial; - PUCHAR Buffer; - - NtQuerySystemTime (&SystemTime); - RtlTimeToTimeFields (&SystemTime, &TimeFields); - - Buffer = (PUCHAR)&Serial; - Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF); - Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF); - Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF); - Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF); - - return Serial; -} - - -static NTSTATUS -FatxWriteBootSector (IN HANDLE FileHandle, - IN PFATX_BOOT_SECTOR BootSector, - IN OUT PFORMAT_CONTEXT Context) -{ - IO_STATUS_BLOCK IoStatusBlock; - NTSTATUS Status; - PUCHAR NewBootSector; - LARGE_INTEGER FileOffset; - - /* Allocate buffer for new bootsector */ - NewBootSector = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(), - 0, - sizeof(FATX_BOOT_SECTOR)); - if (NewBootSector == NULL) - return(STATUS_INSUFFICIENT_RESOURCES); - - /* Zero the new bootsector */ - memset(NewBootSector, 0, sizeof(FATX_BOOT_SECTOR)); - - /* Copy FAT16 BPB to new bootsector */ - memcpy(NewBootSector, BootSector, 18); /* FAT16 BPB length (up to (not including) Res2) */ - - /* Write sector 0 */ - FileOffset.QuadPart = 0ULL; - Status = NtWriteFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - NewBootSector, - sizeof(FATX_BOOT_SECTOR), - &FileOffset, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT("NtWriteFile() failed (Status %lx)\n", Status); - RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector); - return Status; - } - - VfatxUpdateProgress (Context, 1); - - /* Free the new boot sector */ - RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector); - - return Status; -} - - -static NTSTATUS -Fatx16WriteFAT (IN HANDLE FileHandle, - IN ULONG SectorOffset, - IN ULONG FATSectors, - IN OUT PFORMAT_CONTEXT Context) -{ - IO_STATUS_BLOCK IoStatusBlock; - NTSTATUS Status; - PUCHAR Buffer; - LARGE_INTEGER FileOffset; - ULONG i; - ULONG Sectors; - - /* Allocate buffer */ - Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(), - 0, - 32 * 1024); - if (Buffer == NULL) - return(STATUS_INSUFFICIENT_RESOURCES); - - /* Zero the buffer */ - memset(Buffer, 0, 32 * 1024); - - /* FAT cluster 0 */ - Buffer[0] = 0xf8; /* Media type */ - Buffer[1] = 0xff; - - /* FAT cluster 1 */ - Buffer[2] = 0xff; /* Clean shutdown, no disk read/write errors, end-of-cluster (EOC) mark */ - Buffer[3] = 0xff; - - /* Write first sector of the FAT */ - FileOffset.QuadPart = (SectorOffset * 512) + sizeof(FATX_BOOT_SECTOR); - Status = NtWriteFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - Buffer, - 512, - &FileOffset, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT("NtWriteFile() failed (Status %lx)\n", Status); - RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); - return(Status); - } - - VfatxUpdateProgress (Context, 1); - - /* Zero the begin of the buffer */ - memset(Buffer, 0, 4); - - /* Zero the rest of the FAT */ - Sectors = 32 * 1024 / 512; - for (i = 1; i < FATSectors; i += Sectors) - { - /* Zero some sectors of the FAT */ - FileOffset.QuadPart = (SectorOffset + i) * 512 + sizeof(FATX_BOOT_SECTOR) ; - if ((FATSectors - i) <= Sectors) - { - Sectors = FATSectors - i; - } - - Status = NtWriteFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - Buffer, - Sectors * 512, - &FileOffset, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT("NtWriteFile() failed (Status %lx)\n", Status); - RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); - return(Status); - } - - VfatxUpdateProgress (Context, Sectors); - } - - /* Free the buffer */ - RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); - - return(Status); -} - -static NTSTATUS -Fatx32WriteFAT (IN HANDLE FileHandle, - IN ULONG SectorOffset, - IN ULONG FATSectors, - IN OUT PFORMAT_CONTEXT Context) -{ - IO_STATUS_BLOCK IoStatusBlock; - NTSTATUS Status; - PUCHAR Buffer; - LARGE_INTEGER FileOffset; - ULONG i; - ULONG Sectors; - - /* Allocate buffer */ - Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(), - 0, - 64 * 1024); - if (Buffer == NULL) - return(STATUS_INSUFFICIENT_RESOURCES); - - /* Zero the buffer */ - memset(Buffer, 0, 64 * 1024); - - /* FAT cluster 0 */ - Buffer[0] = 0xf8; /* Media type */ - Buffer[1] = 0xff; - Buffer[2] = 0xff; - Buffer[3] = 0x0f; - /* FAT cluster 1 */ - Buffer[4] = 0xff; /* Clean shutdown, no disk read/write errors, end-of-cluster (EOC) mark */ - Buffer[5] = 0xff; - Buffer[6] = 0xff; - Buffer[7] = 0x0f; - - /* Write first sector of the FAT */ - FileOffset.QuadPart = (SectorOffset * 512) + sizeof(FATX_BOOT_SECTOR); - Status = NtWriteFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - Buffer, - 512, - &FileOffset, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT("NtWriteFile() failed (Status %lx)\n", Status); - RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); - return(Status); - } - - VfatxUpdateProgress (Context, 1); - - /* Zero the begin of the buffer */ - memset(Buffer, 0, 8); - - /* Zero the rest of the FAT */ - Sectors = 64 * 1024 / 512; - for (i = 1; i < FATSectors; i += Sectors) - { - /* Zero some sectors of the FAT */ - FileOffset.QuadPart = (SectorOffset + i) * 512 + sizeof(FATX_BOOT_SECTOR); - - if ((FATSectors - i) <= Sectors) - { - Sectors = FATSectors - i; - } - - Status = NtWriteFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - Buffer, - Sectors * 512, - &FileOffset, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT("NtWriteFile() failed (Status %lx)\n", Status); - RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); - return(Status); - } - - VfatxUpdateProgress (Context, Sectors); - } - - /* Free the buffer */ - RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); - - return(Status); -} - -static NTSTATUS -FatxWriteRootDirectory (IN HANDLE FileHandle, - IN ULONG FATSectors, - IN OUT PFORMAT_CONTEXT Context) -{ - IO_STATUS_BLOCK IoStatusBlock; - NTSTATUS Status = STATUS_SUCCESS; - PUCHAR Buffer; - LARGE_INTEGER FileOffset; - ULONG FirstRootDirSector; - ULONG RootDirSectors; - - /* Write cluster */ - RootDirSectors = 256 * 64 / 512; - FirstRootDirSector = sizeof(FATX_BOOT_SECTOR) / 512 + FATSectors; - - DPRINT("RootDirSectors = %lu\n", RootDirSectors); - DPRINT("FirstRootDirSector = %lu\n", FirstRootDirSector); - - /* Allocate buffer for the cluster */ - Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(), - 0, - RootDirSectors * 512); - if (Buffer == NULL) - return(STATUS_INSUFFICIENT_RESOURCES); - - /* Zero the buffer */ - memset(Buffer, 0xff, RootDirSectors * 512); - - /* Zero some sectors of the root directory */ - FileOffset.QuadPart = FirstRootDirSector * 512; - - Status = NtWriteFile(FileHandle, - NULL, - NULL, - NULL, - &IoStatusBlock, - Buffer, - RootDirSectors * 512, - &FileOffset, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT("NtWriteFile() failed (Status %lx)\n", Status); - } - - /* Free the buffer */ - RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); - - return(Status); -} - - -NTSTATUS -FatxFormat (HANDLE FileHandle, - PPARTITION_INFORMATION PartitionInfo, - PDISK_GEOMETRY DiskGeometry, - BOOLEAN QuickFormat, - PFORMAT_CONTEXT Context) -{ - FATX_BOOT_SECTOR BootSector; - ULONGLONG SectorCount; - ULONG ClusterCount; - ULONG RootDirSectors; - ULONG FATSectors; - - NTSTATUS Status; - - SectorCount = PartitionInfo->PartitionLength.QuadPart >> GetShiftCount(512); /* Use shifting to avoid 64-bit division */ - - memset(&BootSector, 0, sizeof(FATX_BOOT_SECTOR)); - memcpy(&BootSector.SysType[0], "FATX", 4); - BootSector.SectorsPerCluster = 32; - BootSector.FATCount = 1; - BootSector.VolumeID = CalcVolumeSerialNumber(); - RootDirSectors = 256 * 64 / 512; - - /* Calculate number of FAT sectors */ - ClusterCount = SectorCount >> GetShiftCount(32); - - if (ClusterCount > 65525) - { - FATSectors = (((ClusterCount * 4) + 4095) & ~4095) >> GetShiftCount(512); - } - else - { - FATSectors = (((ClusterCount * 2) + 4095) & ~4095) >> GetShiftCount(512); - } - DPRINT("FATSectors = %hu\n", FATSectors); - - /* Init context data */ - if (QuickFormat) - { - Context->TotalSectorCount = - 1 + FATSectors + RootDirSectors; - } - else - { - Context->TotalSectorCount = SectorCount; - } - - Status = FatxWriteBootSector (FileHandle, - &BootSector, - Context); - if (!NT_SUCCESS(Status)) - { - DPRINT("FatxWriteBootSector() failed with status 0x%.08x\n", Status); - return Status; - } - - /* Write first FAT copy */ - if (ClusterCount > 65525) - { - Status = Fatx32WriteFAT (FileHandle, - 0, - FATSectors, - Context); - } - else - { - Status = Fatx16WriteFAT (FileHandle, - 0, - FATSectors, - Context); - } - if (!NT_SUCCESS(Status)) - { - DPRINT("FatxWriteFAT() failed with status 0x%.08x\n", Status); - return Status; - } - - Status = FatxWriteRootDirectory (FileHandle, - FATSectors, - Context); - if (!NT_SUCCESS(Status)) - { - DPRINT("FatxWriteRootDirectory() failed with status 0x%.08x\n", Status); - } - - if (!QuickFormat) - { - /* FIXME: Fill remaining sectors */ - } - - return Status; -} +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS VFATX filesystem library + * FILE: fatx.c + * PURPOSE: Fatx support + * PROGRAMMERS: Hartmut Birr + * REVISIONS: + */ +#include "vfatxlib.h" + +#define NDEBUG +#include <debug.h> + +static ULONG +GetShiftCount(ULONG Value) +{ + ULONG i = 1; + while (Value > 0) + { + i++; + Value /= 2; + } + return i - 2; +} + + +static ULONG +CalcVolumeSerialNumber(VOID) +{ + LARGE_INTEGER SystemTime; + TIME_FIELDS TimeFields; + ULONG Serial; + PUCHAR Buffer; + + NtQuerySystemTime (&SystemTime); + RtlTimeToTimeFields (&SystemTime, &TimeFields); + + Buffer = (PUCHAR)&Serial; + Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF); + Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF); + Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF); + Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF); + + return Serial; +} + + +static NTSTATUS +FatxWriteBootSector (IN HANDLE FileHandle, + IN PFATX_BOOT_SECTOR BootSector, + IN OUT PFORMAT_CONTEXT Context) +{ + IO_STATUS_BLOCK IoStatusBlock; + NTSTATUS Status; + PUCHAR NewBootSector; + LARGE_INTEGER FileOffset; + + /* Allocate buffer for new bootsector */ + NewBootSector = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(), + 0, + sizeof(FATX_BOOT_SECTOR)); + if (NewBootSector == NULL) + return(STATUS_INSUFFICIENT_RESOURCES); + + /* Zero the new bootsector */ + memset(NewBootSector, 0, sizeof(FATX_BOOT_SECTOR)); + + /* Copy FAT16 BPB to new bootsector */ + memcpy(NewBootSector, BootSector, 18); /* FAT16 BPB length (up to (not including) Res2) */ + + /* Write sector 0 */ + FileOffset.QuadPart = 0ULL; + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + NewBootSector, + sizeof(FATX_BOOT_SECTOR), + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT("NtWriteFile() failed (Status %lx)\n", Status); + RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector); + return Status; + } + + VfatxUpdateProgress (Context, 1); + + /* Free the new boot sector */ + RtlFreeHeap(RtlGetProcessHeap(), 0, NewBootSector); + + return Status; +} + + +static NTSTATUS +Fatx16WriteFAT (IN HANDLE FileHandle, + IN ULONG SectorOffset, + IN ULONG FATSectors, + IN OUT PFORMAT_CONTEXT Context) +{ + IO_STATUS_BLOCK IoStatusBlock; + NTSTATUS Status; + PUCHAR Buffer; + LARGE_INTEGER FileOffset; + ULONG i; + ULONG Sectors; + + /* Allocate buffer */ + Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(), + 0, + 32 * 1024); + if (Buffer == NULL) + return(STATUS_INSUFFICIENT_RESOURCES); + + /* Zero the buffer */ + memset(Buffer, 0, 32 * 1024); + + /* FAT cluster 0 */ + Buffer[0] = 0xf8; /* Media type */ + Buffer[1] = 0xff; + + /* FAT cluster 1 */ + Buffer[2] = 0xff; /* Clean shutdown, no disk read/write errors, end-of-cluster (EOC) mark */ + Buffer[3] = 0xff; + + /* Write first sector of the FAT */ + FileOffset.QuadPart = (SectorOffset * 512) + sizeof(FATX_BOOT_SECTOR); + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + Buffer, + 512, + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT("NtWriteFile() failed (Status %lx)\n", Status); + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); + return(Status); + } + + VfatxUpdateProgress (Context, 1); + + /* Zero the begin of the buffer */ + memset(Buffer, 0, 4); + + /* Zero the rest of the FAT */ + Sectors = 32 * 1024 / 512; + for (i = 1; i < FATSectors; i += Sectors) + { + /* Zero some sectors of the FAT */ + FileOffset.QuadPart = (SectorOffset + i) * 512 + sizeof(FATX_BOOT_SECTOR) ; + if ((FATSectors - i) <= Sectors) + { + Sectors = FATSectors - i; + } + + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + Buffer, + Sectors * 512, + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT("NtWriteFile() failed (Status %lx)\n", Status); + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); + return(Status); + } + + VfatxUpdateProgress (Context, Sectors); + } + + /* Free the buffer */ + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); + + return(Status); +} + +static NTSTATUS +Fatx32WriteFAT (IN HANDLE FileHandle, + IN ULONG SectorOffset, + IN ULONG FATSectors, + IN OUT PFORMAT_CONTEXT Context) +{ + IO_STATUS_BLOCK IoStatusBlock; + NTSTATUS Status; + PUCHAR Buffer; + LARGE_INTEGER FileOffset; + ULONG i; + ULONG Sectors; + + /* Allocate buffer */ + Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(), + 0, + 64 * 1024); + if (Buffer == NULL) + return(STATUS_INSUFFICIENT_RESOURCES); + + /* Zero the buffer */ + memset(Buffer, 0, 64 * 1024); + + /* FAT cluster 0 */ + Buffer[0] = 0xf8; /* Media type */ + Buffer[1] = 0xff; + Buffer[2] = 0xff; + Buffer[3] = 0x0f; + /* FAT cluster 1 */ + Buffer[4] = 0xff; /* Clean shutdown, no disk read/write errors, end-of-cluster (EOC) mark */ + Buffer[5] = 0xff; + Buffer[6] = 0xff; + Buffer[7] = 0x0f; + + /* Write first sector of the FAT */ + FileOffset.QuadPart = (SectorOffset * 512) + sizeof(FATX_BOOT_SECTOR); + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + Buffer, + 512, + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT("NtWriteFile() failed (Status %lx)\n", Status); + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); + return(Status); + } + + VfatxUpdateProgress (Context, 1); + + /* Zero the begin of the buffer */ + memset(Buffer, 0, 8); + + /* Zero the rest of the FAT */ + Sectors = 64 * 1024 / 512; + for (i = 1; i < FATSectors; i += Sectors) + { + /* Zero some sectors of the FAT */ + FileOffset.QuadPart = (SectorOffset + i) * 512 + sizeof(FATX_BOOT_SECTOR); + + if ((FATSectors - i) <= Sectors) + { + Sectors = FATSectors - i; + } + + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + Buffer, + Sectors * 512, + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT("NtWriteFile() failed (Status %lx)\n", Status); + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); + return(Status); + } + + VfatxUpdateProgress (Context, Sectors); + } + + /* Free the buffer */ + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); + + return(Status); +} + +static NTSTATUS +FatxWriteRootDirectory (IN HANDLE FileHandle, + IN ULONG FATSectors, + IN OUT PFORMAT_CONTEXT Context) +{ + IO_STATUS_BLOCK IoStatusBlock; + NTSTATUS Status = STATUS_SUCCESS; + PUCHAR Buffer; + LARGE_INTEGER FileOffset; + ULONG FirstRootDirSector; + ULONG RootDirSectors; + + /* Write cluster */ + RootDirSectors = 256 * 64 / 512; + FirstRootDirSector = sizeof(FATX_BOOT_SECTOR) / 512 + FATSectors; + + DPRINT("RootDirSectors = %lu\n", RootDirSectors); + DPRINT("FirstRootDirSector = %lu\n", FirstRootDirSector); + + /* Allocate buffer for the cluster */ + Buffer = (PUCHAR)RtlAllocateHeap(RtlGetProcessHeap(), + 0, + RootDirSectors * 512); + if (Buffer == NULL) + return(STATUS_INSUFFICIENT_RESOURCES); + + /* Zero the buffer */ + memset(Buffer, 0xff, RootDirSectors * 512); + + /* Zero some sectors of the root directory */ + FileOffset.QuadPart = FirstRootDirSector * 512; + + Status = NtWriteFile(FileHandle, + NULL, + NULL, + NULL, + &IoStatusBlock, + Buffer, + RootDirSectors * 512, + &FileOffset, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT("NtWriteFile() failed (Status %lx)\n", Status); + } + + /* Free the buffer */ + RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); + + return(Status); +} + + +NTSTATUS +FatxFormat (HANDLE FileHandle, + PPARTITION_INFORMATION PartitionInfo, + PDISK_GEOMETRY DiskGeometry, + BOOLEAN QuickFormat, + PFORMAT_CONTEXT Context) +{ + FATX_BOOT_SECTOR BootSector; + ULONGLONG SectorCount; + ULONG ClusterCount; + ULONG RootDirSectors; + ULONG FATSectors; + + NTSTATUS Status; + + SectorCount = PartitionInfo->PartitionLength.QuadPart >> GetShiftCount(512); /* Use shifting to avoid 64-bit division */ + + memset(&BootSector, 0, sizeof(FATX_BOOT_SECTOR)); + memcpy(&BootSector.SysType[0], "FATX", 4); + BootSector.SectorsPerCluster = 32; + BootSector.FATCount = 1; + BootSector.VolumeID = CalcVolumeSerialNumber(); + RootDirSectors = 256 * 64 / 512; + + /* Calculate number of FAT sectors */ + ClusterCount = SectorCount >> GetShiftCount(32); + + if (ClusterCount > 65525) + { + FATSectors = (((ClusterCount * 4) + 4095) & ~4095) >> GetShiftCount(512); + } + else + { + FATSectors = (((ClusterCount * 2) + 4095) & ~4095) >> GetShiftCount(512); + } + DPRINT("FATSectors = %hu\n", FATSectors); + + /* Init context data */ + if (QuickFormat) + { + Context->TotalSectorCount = + 1 + FATSectors + RootDirSectors; + } + else + { + Context->TotalSectorCount = SectorCount; + } + + Status = FatxWriteBootSector (FileHandle, + &BootSector, + Context); + if (!NT_SUCCESS(Status)) + { + DPRINT("FatxWriteBootSector() failed with status 0x%.08x\n", Status); + return Status; + } + + /* Write first FAT copy */ + if (ClusterCount > 65525) + { + Status = Fatx32WriteFAT (FileHandle, + 0, + FATSectors, + Context); + } + else + { + Status = Fatx16WriteFAT (FileHandle, + 0, + FATSectors, + Context); + } + if (!NT_SUCCESS(Status)) + { + DPRINT("FatxWriteFAT() failed with status 0x%.08x\n", Status); + return Status; + } + + Status = FatxWriteRootDirectory (FileHandle, + FATSectors, + Context); + if (!NT_SUCCESS(Status)) + { + DPRINT("FatxWriteRootDirectory() failed with status 0x%.08x\n", Status); + } + + if (!QuickFormat) + { + /* FIXME: Fill remaining sectors */ + } + + return Status; +} diff --git a/reactos/lib/fslib/vfatxlib/vfatxlib.c b/reactos/lib/fslib/vfatxlib/vfatxlib.c index 48a5c8bbe17..3fd6e096c0c 100644 --- a/reactos/lib/fslib/vfatxlib/vfatxlib.c +++ b/reactos/lib/fslib/vfatxlib/vfatxlib.c @@ -1,193 +1,193 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS VFATx filesystem library - * FILE: vfatxlib.c - * PURPOSE: Main API - * PROGRAMMERS: Hartmut Birr - * REVISIONS: - * CSH 05/04-2003 Created - */ -#include "vfatxlib.h" - -#define NDEBUG -#include <debug.h> - -NTSTATUS -VfatxInitialize(VOID) -{ - DPRINT("VfatxInitialize()\n"); - - return STATUS_SUCCESS; -} - - -NTSTATUS -VfatxFormat (PUNICODE_STRING DriveRoot, - ULONG MediaFlag, - BOOLEAN QuickFormat, - PFMIFSCALLBACK Callback) -{ - OBJECT_ATTRIBUTES ObjectAttributes; - DISK_GEOMETRY DiskGeometry; - IO_STATUS_BLOCK Iosb; - HANDLE FileHandle; - PARTITION_INFORMATION PartitionInfo; - FORMAT_CONTEXT Context; - NTSTATUS Status; - - DPRINT("VfatxFormat(DriveRoot '%wZ')\n", DriveRoot); - - Context.TotalSectorCount = 0; - Context.CurrentSectorCount = 0; - Context.Callback = Callback; - Context.Success = FALSE; - Context.Percent = 0; - - InitializeObjectAttributes(&ObjectAttributes, - DriveRoot, - 0, - NULL, - NULL); - - Status = NtOpenFile(&FileHandle, - FILE_GENERIC_READ | FILE_GENERIC_WRITE, - &ObjectAttributes, - &Iosb, - FILE_SHARE_READ, - FILE_SYNCHRONOUS_IO_ALERT); - if (!NT_SUCCESS(Status)) - { - DPRINT("NtOpenFile() failed with status 0x%.08x\n", Status); - return Status; - } - - Status = NtDeviceIoControlFile(FileHandle, - NULL, - NULL, - NULL, - &Iosb, - IOCTL_DISK_GET_DRIVE_GEOMETRY, - NULL, - 0, - &DiskGeometry, - sizeof(DISK_GEOMETRY)); - if (!NT_SUCCESS(Status)) - { - DPRINT("IOCTL_DISK_GET_DRIVE_GEOMETRY failed with status 0x%.08x\n", Status); - NtClose(FileHandle); - return Status; - } - - if (DiskGeometry.MediaType == FixedMedia) - { - DPRINT("Cylinders %I64d\n", DiskGeometry.Cylinders.QuadPart); - DPRINT("TracksPerCylinder %ld\n", DiskGeometry.TracksPerCylinder); - DPRINT("SectorsPerTrack %ld\n", DiskGeometry.SectorsPerTrack); - DPRINT("BytesPerSector %ld\n", DiskGeometry.BytesPerSector); - DPRINT("DiskSize %I64d\n", - DiskGeometry.Cylinders.QuadPart * - (ULONGLONG)DiskGeometry.TracksPerCylinder * - (ULONGLONG)DiskGeometry.SectorsPerTrack * - (ULONGLONG)DiskGeometry.BytesPerSector); - - Status = NtDeviceIoControlFile(FileHandle, - NULL, - NULL, - NULL, - &Iosb, - IOCTL_DISK_GET_PARTITION_INFO, - NULL, - 0, - &PartitionInfo, - sizeof(PARTITION_INFORMATION)); - if (!NT_SUCCESS(Status)) - { - DPRINT("IOCTL_DISK_GET_PARTITION_INFO failed with status 0x%.08x\n", Status); - NtClose(FileHandle); - return Status; - } - - /* - * FIXME: This is a hack! - * Partitioning software MUST set the correct number of hidden sectors! - */ - PartitionInfo.HiddenSectors = DiskGeometry.SectorsPerTrack; - } - else - { - PartitionInfo.PartitionType = 0; - PartitionInfo.StartingOffset.QuadPart = 0ULL; - PartitionInfo.PartitionLength.QuadPart = - DiskGeometry.Cylinders.QuadPart * - (ULONGLONG)DiskGeometry.TracksPerCylinder * - (ULONGLONG)DiskGeometry.SectorsPerTrack * - (ULONGLONG)DiskGeometry.BytesPerSector; - PartitionInfo.HiddenSectors = 0; - PartitionInfo.PartitionNumber = 0; - PartitionInfo.BootIndicator = FALSE; - PartitionInfo.RewritePartition = FALSE; - PartitionInfo.RecognizedPartition = FALSE; - } - - DPRINT("PartitionType 0x%x\n", PartitionInfo.PartitionType); - DPRINT("StartingOffset %I64d\n", PartitionInfo.StartingOffset.QuadPart); - DPRINT("PartitionLength %I64d\n", PartitionInfo.PartitionLength.QuadPart); - DPRINT("HiddenSectors %lu\n", PartitionInfo.HiddenSectors); - DPRINT("PartitionNumber %d\n", PartitionInfo.PartitionNumber); - DPRINT("BootIndicator 0x%x\n", PartitionInfo.BootIndicator); - DPRINT("RewritePartition %d\n", PartitionInfo.RewritePartition); - DPRINT("RecognizedPartition %d\n", PartitionInfo.RecognizedPartition); - - if (Callback != NULL) - { - Context.Percent = 0; - Callback (PROGRESS, 0, (PVOID)&Context.Percent); - } - - Status = FatxFormat (FileHandle, - &PartitionInfo, - &DiskGeometry, - QuickFormat, - &Context); - NtClose(FileHandle); - - if (Callback != NULL) - { - Context.Success = (BOOLEAN)(NT_SUCCESS(Status)); - Callback (DONE, 0, (PVOID)&Context.Success); - } - - DPRINT("VfatxFormat() done. Status 0x%.08x\n", Status); - - return Status; -} - - -NTSTATUS -VfatxCleanup(VOID) -{ - DPRINT("VfatxCleanup()\n"); - - return STATUS_SUCCESS; -} - - -VOID -VfatxUpdateProgress (PFORMAT_CONTEXT Context, - ULONG Increment) -{ - ULONG NewPercent; - - Context->CurrentSectorCount += (ULONGLONG)Increment; - - - NewPercent = (Context->CurrentSectorCount * 100ULL) / Context->TotalSectorCount; - - if (NewPercent > Context->Percent) - { - Context->Percent = NewPercent; - Context->Callback (PROGRESS, 0, &Context->Percent); - } -} - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS VFATx filesystem library + * FILE: vfatxlib.c + * PURPOSE: Main API + * PROGRAMMERS: Hartmut Birr + * REVISIONS: + * CSH 05/04-2003 Created + */ +#include "vfatxlib.h" + +#define NDEBUG +#include <debug.h> + +NTSTATUS +VfatxInitialize(VOID) +{ + DPRINT("VfatxInitialize()\n"); + + return STATUS_SUCCESS; +} + + +NTSTATUS +VfatxFormat (PUNICODE_STRING DriveRoot, + ULONG MediaFlag, + BOOLEAN QuickFormat, + PFMIFSCALLBACK Callback) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + DISK_GEOMETRY DiskGeometry; + IO_STATUS_BLOCK Iosb; + HANDLE FileHandle; + PARTITION_INFORMATION PartitionInfo; + FORMAT_CONTEXT Context; + NTSTATUS Status; + + DPRINT("VfatxFormat(DriveRoot '%wZ')\n", DriveRoot); + + Context.TotalSectorCount = 0; + Context.CurrentSectorCount = 0; + Context.Callback = Callback; + Context.Success = FALSE; + Context.Percent = 0; + + InitializeObjectAttributes(&ObjectAttributes, + DriveRoot, + 0, + NULL, + NULL); + + Status = NtOpenFile(&FileHandle, + FILE_GENERIC_READ | FILE_GENERIC_WRITE, + &ObjectAttributes, + &Iosb, + FILE_SHARE_READ, + FILE_SYNCHRONOUS_IO_ALERT); + if (!NT_SUCCESS(Status)) + { + DPRINT("NtOpenFile() failed with status 0x%.08x\n", Status); + return Status; + } + + Status = NtDeviceIoControlFile(FileHandle, + NULL, + NULL, + NULL, + &Iosb, + IOCTL_DISK_GET_DRIVE_GEOMETRY, + NULL, + 0, + &DiskGeometry, + sizeof(DISK_GEOMETRY)); + if (!NT_SUCCESS(Status)) + { + DPRINT("IOCTL_DISK_GET_DRIVE_GEOMETRY failed with status 0x%.08x\n", Status); + NtClose(FileHandle); + return Status; + } + + if (DiskGeometry.MediaType == FixedMedia) + { + DPRINT("Cylinders %I64d\n", DiskGeometry.Cylinders.QuadPart); + DPRINT("TracksPerCylinder %ld\n", DiskGeometry.TracksPerCylinder); + DPRINT("SectorsPerTrack %ld\n", DiskGeometry.SectorsPerTrack); + DPRINT("BytesPerSector %ld\n", DiskGeometry.BytesPerSector); + DPRINT("DiskSize %I64d\n", + DiskGeometry.Cylinders.QuadPart * + (ULONGLONG)DiskGeometry.TracksPerCylinder * + (ULONGLONG)DiskGeometry.SectorsPerTrack * + (ULONGLONG)DiskGeometry.BytesPerSector); + + Status = NtDeviceIoControlFile(FileHandle, + NULL, + NULL, + NULL, + &Iosb, + IOCTL_DISK_GET_PARTITION_INFO, + NULL, + 0, + &PartitionInfo, + sizeof(PARTITION_INFORMATION)); + if (!NT_SUCCESS(Status)) + { + DPRINT("IOCTL_DISK_GET_PARTITION_INFO failed with status 0x%.08x\n", Status); + NtClose(FileHandle); + return Status; + } + + /* + * FIXME: This is a hack! + * Partitioning software MUST set the correct number of hidden sectors! + */ + PartitionInfo.HiddenSectors = DiskGeometry.SectorsPerTrack; + } + else + { + PartitionInfo.PartitionType = 0; + PartitionInfo.StartingOffset.QuadPart = 0ULL; + PartitionInfo.PartitionLength.QuadPart = + DiskGeometry.Cylinders.QuadPart * + (ULONGLONG)DiskGeometry.TracksPerCylinder * + (ULONGLONG)DiskGeometry.SectorsPerTrack * + (ULONGLONG)DiskGeometry.BytesPerSector; + PartitionInfo.HiddenSectors = 0; + PartitionInfo.PartitionNumber = 0; + PartitionInfo.BootIndicator = FALSE; + PartitionInfo.RewritePartition = FALSE; + PartitionInfo.RecognizedPartition = FALSE; + } + + DPRINT("PartitionType 0x%x\n", PartitionInfo.PartitionType); + DPRINT("StartingOffset %I64d\n", PartitionInfo.StartingOffset.QuadPart); + DPRINT("PartitionLength %I64d\n", PartitionInfo.PartitionLength.QuadPart); + DPRINT("HiddenSectors %lu\n", PartitionInfo.HiddenSectors); + DPRINT("PartitionNumber %d\n", PartitionInfo.PartitionNumber); + DPRINT("BootIndicator 0x%x\n", PartitionInfo.BootIndicator); + DPRINT("RewritePartition %d\n", PartitionInfo.RewritePartition); + DPRINT("RecognizedPartition %d\n", PartitionInfo.RecognizedPartition); + + if (Callback != NULL) + { + Context.Percent = 0; + Callback (PROGRESS, 0, (PVOID)&Context.Percent); + } + + Status = FatxFormat (FileHandle, + &PartitionInfo, + &DiskGeometry, + QuickFormat, + &Context); + NtClose(FileHandle); + + if (Callback != NULL) + { + Context.Success = (BOOLEAN)(NT_SUCCESS(Status)); + Callback (DONE, 0, (PVOID)&Context.Success); + } + + DPRINT("VfatxFormat() done. Status 0x%.08x\n", Status); + + return Status; +} + + +NTSTATUS +VfatxCleanup(VOID) +{ + DPRINT("VfatxCleanup()\n"); + + return STATUS_SUCCESS; +} + + +VOID +VfatxUpdateProgress (PFORMAT_CONTEXT Context, + ULONG Increment) +{ + ULONG NewPercent; + + Context->CurrentSectorCount += (ULONGLONG)Increment; + + + NewPercent = (Context->CurrentSectorCount * 100ULL) / Context->TotalSectorCount; + + if (NewPercent > Context->Percent) + { + Context->Percent = NewPercent; + Context->Callback (PROGRESS, 0, &Context->Percent); + } +} + +/* EOF */ diff --git a/reactos/lib/fslib/vfatxlib/vfatxlib.h b/reactos/lib/fslib/vfatxlib/vfatxlib.h index e5dd8566dcd..4ebdb2ae6d3 100644 --- a/reactos/lib/fslib/vfatxlib/vfatxlib.h +++ b/reactos/lib/fslib/vfatxlib/vfatxlib.h @@ -1,44 +1,44 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS VFAT filesystem library - * FILE: vfatxlib.h - */ -#include <windows.h> -#include <fmifs/fmifs.h> -#define NTOS_MODE_USER -#include <ndk/ntndk.h> - -typedef struct _FATX_BOOT_SECTOR -{ - unsigned char SysType[4]; // 0 - unsigned long VolumeID; // 4 - unsigned long SectorsPerCluster; // 8 - unsigned short FATCount; // 12 - unsigned long Unknown; // 14 - unsigned char Unused[4078]; // 18 -} __attribute__((packed)) FATX_BOOT_SECTOR, *PFATX_BOOT_SECTOR; - - -typedef struct _FORMAT_CONTEXT -{ - PFMIFSCALLBACK Callback; - ULONG TotalSectorCount; - ULONG CurrentSectorCount; - BOOLEAN Success; - ULONG Percent; -} FORMAT_CONTEXT, *PFORMAT_CONTEXT; - - - -NTSTATUS -FatxFormat (HANDLE FileHandle, - PPARTITION_INFORMATION PartitionInfo, - PDISK_GEOMETRY DiskGeometry, - BOOLEAN QuickFormat, - PFORMAT_CONTEXT Context); - -VOID -VfatxUpdateProgress (PFORMAT_CONTEXT Context, - ULONG Increment); - -/* EOF */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS VFAT filesystem library + * FILE: vfatxlib.h + */ +#include <windows.h> +#include <fmifs/fmifs.h> +#define NTOS_MODE_USER +#include <ndk/ntndk.h> + +typedef struct _FATX_BOOT_SECTOR +{ + unsigned char SysType[4]; // 0 + unsigned long VolumeID; // 4 + unsigned long SectorsPerCluster; // 8 + unsigned short FATCount; // 12 + unsigned long Unknown; // 14 + unsigned char Unused[4078]; // 18 +} __attribute__((packed)) FATX_BOOT_SECTOR, *PFATX_BOOT_SECTOR; + + +typedef struct _FORMAT_CONTEXT +{ + PFMIFSCALLBACK Callback; + ULONG TotalSectorCount; + ULONG CurrentSectorCount; + BOOLEAN Success; + ULONG Percent; +} FORMAT_CONTEXT, *PFORMAT_CONTEXT; + + + +NTSTATUS +FatxFormat (HANDLE FileHandle, + PPARTITION_INFORMATION PartitionInfo, + PDISK_GEOMETRY DiskGeometry, + BOOLEAN QuickFormat, + PFORMAT_CONTEXT Context); + +VOID +VfatxUpdateProgress (PFORMAT_CONTEXT Context, + ULONG Increment); + +/* EOF */ diff --git a/reactos/lib/gdi32/objects/bitmap.c b/reactos/lib/gdi32/objects/bitmap.c index 40d37a84f93..c4f62480c5b 100644 --- a/reactos/lib/gdi32/objects/bitmap.c +++ b/reactos/lib/gdi32/objects/bitmap.c @@ -1,59 +1,59 @@ -#include "precomp.h" - -/* - * @implemented - */ -HBITMAP STDCALL -CreateDIBSection( - HDC hDC, - CONST BITMAPINFO *BitmapInfo, - UINT Usage, - VOID **Bits, - HANDLE hSection, - DWORD dwOffset) -{ - PBITMAPINFO pConvertedInfo; - UINT ConvertedInfoSize; - HBITMAP hBitmap = NULL; - - pConvertedInfo = ConvertBitmapInfo(BitmapInfo, Usage, - &ConvertedInfoSize, FALSE); - if (pConvertedInfo) - { - hBitmap = NtGdiCreateDIBSection(hDC, pConvertedInfo, Usage, Bits, - hSection, dwOffset); - if (BitmapInfo != pConvertedInfo) - RtlFreeHeap(RtlGetProcessHeap(), 0, pConvertedInfo); - } - - return hBitmap; -} - -/* - * @implemented - */ -BOOL STDCALL -StretchBlt( - HDC hdcDest, /* handle to destination DC */ - int nXOriginDest, /* x-coord of destination upper-left corner */ - int nYOriginDest, /* y-coord of destination upper-left corner */ - int nWidthDest, /* width of destination rectangle */ - int nHeightDest, /* height of destination rectangle */ - HDC hdcSrc, /* handle to source DC */ - int nXOriginSrc, /* x-coord of source upper-left corner */ - int nYOriginSrc, /* y-coord of source upper-left corner */ - int nWidthSrc, /* width of source rectangle */ - int nHeightSrc, /* height of source rectangle */ - DWORD dwRop) /* raster operation code */ - -{ - if ((nWidthDest != nWidthSrc) || (nHeightDest != nHeightSrc)) - { - return NtGdiStretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, - nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, - nWidthSrc, nHeightSrc, dwRop); - } - - return NtGdiBitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, - nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, dwRop); -} +#include "precomp.h" + +/* + * @implemented + */ +HBITMAP STDCALL +CreateDIBSection( + HDC hDC, + CONST BITMAPINFO *BitmapInfo, + UINT Usage, + VOID **Bits, + HANDLE hSection, + DWORD dwOffset) +{ + PBITMAPINFO pConvertedInfo; + UINT ConvertedInfoSize; + HBITMAP hBitmap = NULL; + + pConvertedInfo = ConvertBitmapInfo(BitmapInfo, Usage, + &ConvertedInfoSize, FALSE); + if (pConvertedInfo) + { + hBitmap = NtGdiCreateDIBSection(hDC, pConvertedInfo, Usage, Bits, + hSection, dwOffset); + if (BitmapInfo != pConvertedInfo) + RtlFreeHeap(RtlGetProcessHeap(), 0, pConvertedInfo); + } + + return hBitmap; +} + +/* + * @implemented + */ +BOOL STDCALL +StretchBlt( + HDC hdcDest, /* handle to destination DC */ + int nXOriginDest, /* x-coord of destination upper-left corner */ + int nYOriginDest, /* y-coord of destination upper-left corner */ + int nWidthDest, /* width of destination rectangle */ + int nHeightDest, /* height of destination rectangle */ + HDC hdcSrc, /* handle to source DC */ + int nXOriginSrc, /* x-coord of source upper-left corner */ + int nYOriginSrc, /* y-coord of source upper-left corner */ + int nWidthSrc, /* width of source rectangle */ + int nHeightSrc, /* height of source rectangle */ + DWORD dwRop) /* raster operation code */ + +{ + if ((nWidthDest != nWidthSrc) || (nHeightDest != nHeightSrc)) + { + return NtGdiStretchBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, + nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, + nWidthSrc, nHeightSrc, dwRop); + } + + return NtGdiBitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, + nHeightDest, hdcSrc, nXOriginSrc, nYOriginSrc, dwRop); +} diff --git a/reactos/lib/gdi32/objects/brush.c b/reactos/lib/gdi32/objects/brush.c index 6978962b489..ebf0174e4c3 100644 --- a/reactos/lib/gdi32/objects/brush.c +++ b/reactos/lib/gdi32/objects/brush.c @@ -1,127 +1,127 @@ -#include "precomp.h" - -#define NDEBUG -#include <debug.h> - -/* - * @implemented - */ -BOOL -STDCALL -FixBrushOrgEx( - HDC hDC, - INT nXOrg, - INT nYOrg, - LPPOINT lpPoint) -{ - return FALSE; -} - -/* - * @implemented - */ -HBRUSH STDCALL -CreateDIBPatternBrush( - HGLOBAL hglbDIBPacked, - UINT fuColorSpec) -{ - PVOID lpPackedDIB; - HBRUSH hBrush = NULL; - PBITMAPINFO pConvertedInfo; - UINT ConvertedInfoSize; - - lpPackedDIB = GlobalLock(hglbDIBPacked); - if (lpPackedDIB == NULL) - return 0; - - pConvertedInfo = ConvertBitmapInfo((PBITMAPINFO)lpPackedDIB, fuColorSpec, - &ConvertedInfoSize, TRUE); - if (pConvertedInfo) - { - hBrush = NtGdiCreateDIBBrush(pConvertedInfo, fuColorSpec, - ConvertedInfoSize, lpPackedDIB); - if ((PBITMAPINFO)lpPackedDIB != pConvertedInfo) - RtlFreeHeap(RtlGetProcessHeap(), 0, pConvertedInfo); - } - - GlobalUnlock(hglbDIBPacked); - - return hBrush; -} - -/* - * @implemented - */ -HBRUSH STDCALL -CreateDIBPatternBrushPt( - CONST VOID *lpPackedDIB, - UINT fuColorSpec) -{ - HBRUSH hBrush = NULL; - PBITMAPINFO pConvertedInfo; - UINT ConvertedInfoSize; - - if (lpPackedDIB == NULL) - return 0; - - pConvertedInfo = ConvertBitmapInfo((PBITMAPINFO)lpPackedDIB, fuColorSpec, - &ConvertedInfoSize, TRUE); - if (pConvertedInfo) - { - hBrush = NtGdiCreateDIBBrush(pConvertedInfo, fuColorSpec, - ConvertedInfoSize, lpPackedDIB); - if ((PBITMAPINFO)lpPackedDIB != pConvertedInfo) - RtlFreeHeap(RtlGetProcessHeap(), 0, pConvertedInfo); - } - - return hBrush; -} - -/* - * @implemented - */ -HBRUSH STDCALL -CreateBrushIndirect( - CONST LOGBRUSH *LogBrush) -{ - HBRUSH hBrush; - - switch (LogBrush->lbStyle) - { - case BS_DIBPATTERN8X8: - case BS_DIBPATTERN: - hBrush = CreateDIBPatternBrush((HGLOBAL)LogBrush->lbHatch, - LogBrush->lbColor); - break; - - case BS_DIBPATTERNPT: - hBrush = CreateDIBPatternBrushPt((PVOID)LogBrush->lbHatch, - LogBrush->lbColor); - break; - - case BS_PATTERN: - case BS_PATTERN8X8: - hBrush = NtGdiCreatePatternBrush((HBITMAP)LogBrush->lbHatch); - break; - - case BS_SOLID: - hBrush = NtGdiCreateSolidBrush(LogBrush->lbColor); - break; - - case BS_HATCHED: - hBrush = NtGdiCreateHatchBrush(LogBrush->lbHatch, LogBrush->lbColor); - break; - - case BS_NULL: - hBrush = NtGdiGetStockObject(NULL_BRUSH); - break; - - default: - SetLastError(ERROR_INVALID_PARAMETER); - hBrush = NULL; - break; - } - - return hBrush; -} - +#include "precomp.h" + +#define NDEBUG +#include <debug.h> + +/* + * @implemented + */ +BOOL +STDCALL +FixBrushOrgEx( + HDC hDC, + INT nXOrg, + INT nYOrg, + LPPOINT lpPoint) +{ + return FALSE; +} + +/* + * @implemented + */ +HBRUSH STDCALL +CreateDIBPatternBrush( + HGLOBAL hglbDIBPacked, + UINT fuColorSpec) +{ + PVOID lpPackedDIB; + HBRUSH hBrush = NULL; + PBITMAPINFO pConvertedInfo; + UINT ConvertedInfoSize; + + lpPackedDIB = GlobalLock(hglbDIBPacked); + if (lpPackedDIB == NULL) + return 0; + + pConvertedInfo = ConvertBitmapInfo((PBITMAPINFO)lpPackedDIB, fuColorSpec, + &ConvertedInfoSize, TRUE); + if (pConvertedInfo) + { + hBrush = NtGdiCreateDIBBrush(pConvertedInfo, fuColorSpec, + ConvertedInfoSize, lpPackedDIB); + if ((PBITMAPINFO)lpPackedDIB != pConvertedInfo) + RtlFreeHeap(RtlGetProcessHeap(), 0, pConvertedInfo); + } + + GlobalUnlock(hglbDIBPacked); + + return hBrush; +} + +/* + * @implemented + */ +HBRUSH STDCALL +CreateDIBPatternBrushPt( + CONST VOID *lpPackedDIB, + UINT fuColorSpec) +{ + HBRUSH hBrush = NULL; + PBITMAPINFO pConvertedInfo; + UINT ConvertedInfoSize; + + if (lpPackedDIB == NULL) + return 0; + + pConvertedInfo = ConvertBitmapInfo((PBITMAPINFO)lpPackedDIB, fuColorSpec, + &ConvertedInfoSize, TRUE); + if (pConvertedInfo) + { + hBrush = NtGdiCreateDIBBrush(pConvertedInfo, fuColorSpec, + ConvertedInfoSize, lpPackedDIB); + if ((PBITMAPINFO)lpPackedDIB != pConvertedInfo) + RtlFreeHeap(RtlGetProcessHeap(), 0, pConvertedInfo); + } + + return hBrush; +} + +/* + * @implemented + */ +HBRUSH STDCALL +CreateBrushIndirect( + CONST LOGBRUSH *LogBrush) +{ + HBRUSH hBrush; + + switch (LogBrush->lbStyle) + { + case BS_DIBPATTERN8X8: + case BS_DIBPATTERN: + hBrush = CreateDIBPatternBrush((HGLOBAL)LogBrush->lbHatch, + LogBrush->lbColor); + break; + + case BS_DIBPATTERNPT: + hBrush = CreateDIBPatternBrushPt((PVOID)LogBrush->lbHatch, + LogBrush->lbColor); + break; + + case BS_PATTERN: + case BS_PATTERN8X8: + hBrush = NtGdiCreatePatternBrush((HBITMAP)LogBrush->lbHatch); + break; + + case BS_SOLID: + hBrush = NtGdiCreateSolidBrush(LogBrush->lbColor); + break; + + case BS_HATCHED: + hBrush = NtGdiCreateHatchBrush(LogBrush->lbHatch, LogBrush->lbColor); + break; + + case BS_NULL: + hBrush = NtGdiGetStockObject(NULL_BRUSH); + break; + + default: + SetLastError(ERROR_INVALID_PARAMETER); + hBrush = NULL; + break; + } + + return hBrush; +} + diff --git a/reactos/lib/gdi32/objects/utils.c b/reactos/lib/gdi32/objects/utils.c index 142ce8a341e..3f9bcd3cc01 100644 --- a/reactos/lib/gdi32/objects/utils.c +++ b/reactos/lib/gdi32/objects/utils.c @@ -1,385 +1,385 @@ -#include "precomp.h" - -/** - * @name CalculateColorTableSize - * - * Internal routine to calculate the number of color table entries. - * - * @param BitmapInfoHeader - * Input bitmap information header, can be any version of - * BITMAPINFOHEADER or BITMAPCOREHEADER. - * - * @param ColorSpec - * Pointer to variable which specifiing the color mode (DIB_RGB_COLORS - * or DIB_RGB_COLORS). On successful return this value is normalized - * according to the bitmap info. - * - * @param ColorTableSize - * On successful return this variable is filled with number of - * entries in color table for the image with specified parameters. - * - * @return - * TRUE if the input values together form a valid image, FALSE otherwise. - */ - -BOOL STDCALL -CalculateColorTableSize( - CONST BITMAPINFOHEADER *BitmapInfoHeader, - UINT *ColorSpec, - UINT *ColorTableSize) -{ - WORD BitCount; - DWORD ClrUsed; - DWORD Compression; - - /* - * At first get some basic parameters from the passed BitmapInfoHeader - * structure. It can have one of the following formats: - * - BITMAPCOREHEADER (the oldest one with totally different layout - * from the others) - * - BITMAPINFOHEADER (the standard and most common header) - * - BITMAPV4HEADER (extension of BITMAPINFOHEADER) - * - BITMAPV5HEADER (extension of BITMAPV4HEADER) - */ - - if (BitmapInfoHeader->biSize == sizeof(BITMAPCOREHEADER)) - { - BitCount = ((LPBITMAPCOREHEADER)BitmapInfoHeader)->bcBitCount; - ClrUsed = 0; - Compression = BI_RGB; - } - else - { - BitCount = BitmapInfoHeader->biBitCount; - ClrUsed = BitmapInfoHeader->biClrUsed; - Compression = BitmapInfoHeader->biCompression; - } - - switch (Compression) - { - case BI_BITFIELDS: - if (*ColorSpec == DIB_PAL_COLORS) - *ColorSpec = DIB_RGB_COLORS; - - if (BitCount != 16 && BitCount != 32) - return FALSE; - - /* - * For BITMAPV4HEADER/BITMAPV5HEADER the masks are included in - * the structure itself (bV4RedMask, bV4GreenMask, and bV4BlueMask). - * For BITMAPINFOHEADER the color masks are stored in the palette. - */ - - if (BitmapInfoHeader->biSize > sizeof(BITMAPINFOHEADER)) - *ColorTableSize = 0; - else - *ColorTableSize = 3; - - return TRUE; - - case BI_RGB: - switch (BitCount) - { - case 1: - *ColorTableSize = ClrUsed ? min(ClrUsed, 2) : 2; - return TRUE; - - case 4: - *ColorTableSize = ClrUsed ? min(ClrUsed, 16) : 16; - return TRUE; - - case 8: - *ColorTableSize = ClrUsed ? min(ClrUsed, 256) : 256; - return TRUE; - - default: - if (*ColorSpec == DIB_PAL_COLORS) - *ColorSpec = DIB_RGB_COLORS; - if (BitCount != 16 && BitCount != 24 && BitCount != 32) - return FALSE; - *ColorTableSize = ClrUsed; - return TRUE; - } - - case BI_RLE4: - if (BitCount == 4) - { - *ColorTableSize = ClrUsed ? min(ClrUsed, 16) : 16; - return TRUE; - } - return FALSE; - - case BI_RLE8: - if (BitCount == 8) - { - *ColorTableSize = ClrUsed ? min(ClrUsed, 256) : 256; - return TRUE; - } - return FALSE; - - case BI_JPEG: - case BI_PNG: - *ColorTableSize = ClrUsed; - return TRUE; - - default: - return FALSE; - } -} - -/** - * @name ConvertBitmapInfo - * - * Internal routine to convert a user-passed BITMAPINFO structure into - * unified BITMAPINFO structure. - * - * @param BitmapInfo - * Input bitmap info, can be any version of BITMAPINFO or - * BITMAPCOREINFO. - * @param ColorSpec - * Specifies whether the bmiColors member of the BITMAPINFO structure - * contains a valid color table and, if so, whether the entries in - * this color table contain explicit red, green, blue (DIB_RGB_COLORS) - * values or palette indexes (DIB_PAL_COLORS). - * @param BitmapInfoSize - * On successful return contains the size of the returned BITMAPINFO - * structure. If FollowedByData is TRUE the size includes the number - * of bytes occupied by the image data. - * @param FollowedByData - * Specifies if the BITMAPINFO header is immediately followed - * by the actual bitmap data (eg. as passed to CreateDIBPatternBrush). - * - * @return - * Either the original BitmapInfo or newly allocated structure is - * returned. For the later case the caller is responsible for freeing the - * memory using RtlFreeHeap with the current process heap. - * - * @example - * PBITMAPINFO NewBitmapInfo; - * UINT NewBitmapInfoSize; - * - * NewBitmapInfo = ConvertBitmapInfo(OldBitmapInfo, DIB_RGB_COLORS, - * &NewBitmapInfoSize, FALSE); - * if (NewBitmapInfo) - * { - * <do something with the bitmap info> - * if (NewBitmapInfo != OldBitmapInfo) - * RtlFreeHeap(RtlGetProcessHeap(), 0, NewBitmapInfo); - * } - */ - -LPBITMAPINFO STDCALL -ConvertBitmapInfo( - CONST BITMAPINFO *BitmapInfo, - UINT ColorSpec, - UINT *BitmapInfoSize, - BOOL FollowedByData) -{ - LPBITMAPINFO NewBitmapInfo = (LPBITMAPINFO)BitmapInfo; - LPBITMAPCOREINFO CoreBitmapInfo = (LPBITMAPCOREINFO)BitmapInfo; - DWORD Size = 0; - ULONG DataSize = 0; - UINT PaletteEntryCount = 0; - - /* - * At first check if the passed BitmapInfo structure has valid size. It - * can have one of these headers: BITMAPCOREHEADER, BITMAPINFOHEADER, - * BITMAPV4HEADER or BITMAPV5HEADER (see CalculateColorTableSize for - * description). - */ - - if (BitmapInfo->bmiHeader.biSize != sizeof(BITMAPCOREHEADER) && - (BitmapInfo->bmiHeader.biSize < sizeof(BITMAPINFOHEADER) || - BitmapInfo->bmiHeader.biSize > sizeof(BITMAPV5HEADER))) - { - return NULL; - } - - /* - * Now calculate the color table size. Also if the bitmap info contains - * invalid color information it's rejected here. - */ - - if (!CalculateColorTableSize(&BitmapInfo->bmiHeader, &ColorSpec, - &PaletteEntryCount)) - { - return NULL; - } - - /* - * Calculate the size of image data if applicable. We must be careful - * to do proper aligning on line ends. - */ - - if (FollowedByData) - { - if (BitmapInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) - { - DataSize = - CoreBitmapInfo->bmciHeader.bcHeight * - CoreBitmapInfo->bmciHeader.bcWidth * - CoreBitmapInfo->bmciHeader.bcBitCount; - DataSize = ((DataSize + 31) & ~31) / 8; - DataSize *= CoreBitmapInfo->bmciHeader.bcPlanes; - } - else - { - if (BitmapInfo->bmiHeader.biCompression == BI_RGB || - BitmapInfo->bmiHeader.biCompression == BI_BITFIELDS) - { - DataSize = - abs(BitmapInfo->bmiHeader.biHeight) * - BitmapInfo->bmiHeader.biWidth * - BitmapInfo->bmiHeader.biBitCount; - DataSize = ((DataSize + 31) & ~31) / 8; - DataSize *= BitmapInfo->bmiHeader.biPlanes; - } - else - { - DataSize = BitmapInfo->bmiHeader.biSizeImage; - } - } - } - - /* - * If BitmapInfo was originally BITMAPCOREINFO then we need to convert - * it to the standard BITMAPINFO layout. - */ - - if (BitmapInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) - { - Size = sizeof(BITMAPINFOHEADER); - if (ColorSpec == DIB_RGB_COLORS) - Size += PaletteEntryCount * sizeof(RGBQUAD); - else - Size += PaletteEntryCount * sizeof(USHORT); - Size += DataSize; - - NewBitmapInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size); - if (NewBitmapInfo == NULL) - { - return NULL; - } - - NewBitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - NewBitmapInfo->bmiHeader.biWidth = CoreBitmapInfo->bmciHeader.bcWidth; - NewBitmapInfo->bmiHeader.biHeight = CoreBitmapInfo->bmciHeader.bcHeight; - NewBitmapInfo->bmiHeader.biPlanes = CoreBitmapInfo->bmciHeader.bcPlanes; - NewBitmapInfo->bmiHeader.biBitCount = CoreBitmapInfo->bmciHeader.bcBitCount; - NewBitmapInfo->bmiHeader.biCompression = BI_RGB; - NewBitmapInfo->bmiHeader.biSizeImage = 0; - NewBitmapInfo->bmiHeader.biXPelsPerMeter = 0; - NewBitmapInfo->bmiHeader.biYPelsPerMeter = 0; - NewBitmapInfo->bmiHeader.biClrUsed = 0; - NewBitmapInfo->bmiHeader.biClrImportant = 0; - - if (PaletteEntryCount != 0) - { - if (ColorSpec == DIB_RGB_COLORS) - { - ULONG Index; - - for (Index = 0; Index < PaletteEntryCount; Index++) - { - NewBitmapInfo->bmiColors[Index].rgbRed = - CoreBitmapInfo->bmciColors[Index].rgbtRed; - NewBitmapInfo->bmiColors[Index].rgbGreen = - CoreBitmapInfo->bmciColors[Index].rgbtGreen; - NewBitmapInfo->bmiColors[Index].rgbBlue = - CoreBitmapInfo->bmciColors[Index].rgbtBlue; - NewBitmapInfo->bmiColors[Index].rgbReserved = 0; - } - } - else - { - RtlCopyMemory(NewBitmapInfo->bmiColors, - CoreBitmapInfo->bmciColors, - PaletteEntryCount * sizeof(USHORT)); - } - } - - if (FollowedByData) - { - ULONG_PTR NewDataPtr, OldDataPtr; - - if (ColorSpec == DIB_RGB_COLORS) - { - NewDataPtr = (ULONG_PTR)(NewBitmapInfo->bmiColors + - PaletteEntryCount); - OldDataPtr = (ULONG_PTR)(CoreBitmapInfo->bmciColors + - PaletteEntryCount); - } - else - { - NewDataPtr = (ULONG_PTR)(NewBitmapInfo->bmiColors) + - PaletteEntryCount * sizeof(USHORT); - OldDataPtr = (ULONG_PTR)(CoreBitmapInfo->bmciColors) + - PaletteEntryCount * sizeof(USHORT); - } - - RtlCopyMemory((PVOID)NewDataPtr, (PVOID)OldDataPtr, DataSize); - } - } - - Size = NewBitmapInfo->bmiHeader.biSize; - if (ColorSpec == DIB_RGB_COLORS) - Size += PaletteEntryCount * sizeof(RGBQUAD); - else - Size += PaletteEntryCount * sizeof(USHORT); - Size += DataSize; - *BitmapInfoSize = Size; - - return NewBitmapInfo; -} - -VOID -STDCALL -LogFontA2W(LPLOGFONTW pW, CONST LOGFONTA *pA) -{ -#define COPYS(f,len) MultiByteToWideChar ( CP_THREAD_ACP, 0, pA->f, len, pW->f, len ) -#define COPYN(f) pW->f = pA->f - - COPYN(lfHeight); - COPYN(lfWidth); - COPYN(lfEscapement); - COPYN(lfOrientation); - COPYN(lfWeight); - COPYN(lfItalic); - COPYN(lfUnderline); - COPYN(lfStrikeOut); - COPYN(lfCharSet); - COPYN(lfOutPrecision); - COPYN(lfClipPrecision); - COPYN(lfQuality); - COPYN(lfPitchAndFamily); - COPYS(lfFaceName,LF_FACESIZE); - -#undef COPYN -#undef COPYS -} - -VOID -STDCALL -LogFontW2A(LPLOGFONTA pA, CONST LOGFONTW *pW) -{ -#define COPYS(f,len) WideCharToMultiByte ( CP_THREAD_ACP, 0, pW->f, len, pA->f, len, NULL, NULL ) -#define COPYN(f) pA->f = pW->f - - COPYN(lfHeight); - COPYN(lfWidth); - COPYN(lfEscapement); - COPYN(lfOrientation); - COPYN(lfWeight); - COPYN(lfItalic); - COPYN(lfUnderline); - COPYN(lfStrikeOut); - COPYN(lfCharSet); - COPYN(lfOutPrecision); - COPYN(lfClipPrecision); - COPYN(lfQuality); - COPYN(lfPitchAndFamily); - COPYS(lfFaceName,LF_FACESIZE); - -#undef COPYN -#undef COPYS -} +#include "precomp.h" + +/** + * @name CalculateColorTableSize + * + * Internal routine to calculate the number of color table entries. + * + * @param BitmapInfoHeader + * Input bitmap information header, can be any version of + * BITMAPINFOHEADER or BITMAPCOREHEADER. + * + * @param ColorSpec + * Pointer to variable which specifiing the color mode (DIB_RGB_COLORS + * or DIB_RGB_COLORS). On successful return this value is normalized + * according to the bitmap info. + * + * @param ColorTableSize + * On successful return this variable is filled with number of + * entries in color table for the image with specified parameters. + * + * @return + * TRUE if the input values together form a valid image, FALSE otherwise. + */ + +BOOL STDCALL +CalculateColorTableSize( + CONST BITMAPINFOHEADER *BitmapInfoHeader, + UINT *ColorSpec, + UINT *ColorTableSize) +{ + WORD BitCount; + DWORD ClrUsed; + DWORD Compression; + + /* + * At first get some basic parameters from the passed BitmapInfoHeader + * structure. It can have one of the following formats: + * - BITMAPCOREHEADER (the oldest one with totally different layout + * from the others) + * - BITMAPINFOHEADER (the standard and most common header) + * - BITMAPV4HEADER (extension of BITMAPINFOHEADER) + * - BITMAPV5HEADER (extension of BITMAPV4HEADER) + */ + + if (BitmapInfoHeader->biSize == sizeof(BITMAPCOREHEADER)) + { + BitCount = ((LPBITMAPCOREHEADER)BitmapInfoHeader)->bcBitCount; + ClrUsed = 0; + Compression = BI_RGB; + } + else + { + BitCount = BitmapInfoHeader->biBitCount; + ClrUsed = BitmapInfoHeader->biClrUsed; + Compression = BitmapInfoHeader->biCompression; + } + + switch (Compression) + { + case BI_BITFIELDS: + if (*ColorSpec == DIB_PAL_COLORS) + *ColorSpec = DIB_RGB_COLORS; + + if (BitCount != 16 && BitCount != 32) + return FALSE; + + /* + * For BITMAPV4HEADER/BITMAPV5HEADER the masks are included in + * the structure itself (bV4RedMask, bV4GreenMask, and bV4BlueMask). + * For BITMAPINFOHEADER the color masks are stored in the palette. + */ + + if (BitmapInfoHeader->biSize > sizeof(BITMAPINFOHEADER)) + *ColorTableSize = 0; + else + *ColorTableSize = 3; + + return TRUE; + + case BI_RGB: + switch (BitCount) + { + case 1: + *ColorTableSize = ClrUsed ? min(ClrUsed, 2) : 2; + return TRUE; + + case 4: + *ColorTableSize = ClrUsed ? min(ClrUsed, 16) : 16; + return TRUE; + + case 8: + *ColorTableSize = ClrUsed ? min(ClrUsed, 256) : 256; + return TRUE; + + default: + if (*ColorSpec == DIB_PAL_COLORS) + *ColorSpec = DIB_RGB_COLORS; + if (BitCount != 16 && BitCount != 24 && BitCount != 32) + return FALSE; + *ColorTableSize = ClrUsed; + return TRUE; + } + + case BI_RLE4: + if (BitCount == 4) + { + *ColorTableSize = ClrUsed ? min(ClrUsed, 16) : 16; + return TRUE; + } + return FALSE; + + case BI_RLE8: + if (BitCount == 8) + { + *ColorTableSize = ClrUsed ? min(ClrUsed, 256) : 256; + return TRUE; + } + return FALSE; + + case BI_JPEG: + case BI_PNG: + *ColorTableSize = ClrUsed; + return TRUE; + + default: + return FALSE; + } +} + +/** + * @name ConvertBitmapInfo + * + * Internal routine to convert a user-passed BITMAPINFO structure into + * unified BITMAPINFO structure. + * + * @param BitmapInfo + * Input bitmap info, can be any version of BITMAPINFO or + * BITMAPCOREINFO. + * @param ColorSpec + * Specifies whether the bmiColors member of the BITMAPINFO structure + * contains a valid color table and, if so, whether the entries in + * this color table contain explicit red, green, blue (DIB_RGB_COLORS) + * values or palette indexes (DIB_PAL_COLORS). + * @param BitmapInfoSize + * On successful return contains the size of the returned BITMAPINFO + * structure. If FollowedByData is TRUE the size includes the number + * of bytes occupied by the image data. + * @param FollowedByData + * Specifies if the BITMAPINFO header is immediately followed + * by the actual bitmap data (eg. as passed to CreateDIBPatternBrush). + * + * @return + * Either the original BitmapInfo or newly allocated structure is + * returned. For the later case the caller is responsible for freeing the + * memory using RtlFreeHeap with the current process heap. + * + * @example + * PBITMAPINFO NewBitmapInfo; + * UINT NewBitmapInfoSize; + * + * NewBitmapInfo = ConvertBitmapInfo(OldBitmapInfo, DIB_RGB_COLORS, + * &NewBitmapInfoSize, FALSE); + * if (NewBitmapInfo) + * { + * <do something with the bitmap info> + * if (NewBitmapInfo != OldBitmapInfo) + * RtlFreeHeap(RtlGetProcessHeap(), 0, NewBitmapInfo); + * } + */ + +LPBITMAPINFO STDCALL +ConvertBitmapInfo( + CONST BITMAPINFO *BitmapInfo, + UINT ColorSpec, + UINT *BitmapInfoSize, + BOOL FollowedByData) +{ + LPBITMAPINFO NewBitmapInfo = (LPBITMAPINFO)BitmapInfo; + LPBITMAPCOREINFO CoreBitmapInfo = (LPBITMAPCOREINFO)BitmapInfo; + DWORD Size = 0; + ULONG DataSize = 0; + UINT PaletteEntryCount = 0; + + /* + * At first check if the passed BitmapInfo structure has valid size. It + * can have one of these headers: BITMAPCOREHEADER, BITMAPINFOHEADER, + * BITMAPV4HEADER or BITMAPV5HEADER (see CalculateColorTableSize for + * description). + */ + + if (BitmapInfo->bmiHeader.biSize != sizeof(BITMAPCOREHEADER) && + (BitmapInfo->bmiHeader.biSize < sizeof(BITMAPINFOHEADER) || + BitmapInfo->bmiHeader.biSize > sizeof(BITMAPV5HEADER))) + { + return NULL; + } + + /* + * Now calculate the color table size. Also if the bitmap info contains + * invalid color information it's rejected here. + */ + + if (!CalculateColorTableSize(&BitmapInfo->bmiHeader, &ColorSpec, + &PaletteEntryCount)) + { + return NULL; + } + + /* + * Calculate the size of image data if applicable. We must be careful + * to do proper aligning on line ends. + */ + + if (FollowedByData) + { + if (BitmapInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) + { + DataSize = + CoreBitmapInfo->bmciHeader.bcHeight * + CoreBitmapInfo->bmciHeader.bcWidth * + CoreBitmapInfo->bmciHeader.bcBitCount; + DataSize = ((DataSize + 31) & ~31) / 8; + DataSize *= CoreBitmapInfo->bmciHeader.bcPlanes; + } + else + { + if (BitmapInfo->bmiHeader.biCompression == BI_RGB || + BitmapInfo->bmiHeader.biCompression == BI_BITFIELDS) + { + DataSize = + abs(BitmapInfo->bmiHeader.biHeight) * + BitmapInfo->bmiHeader.biWidth * + BitmapInfo->bmiHeader.biBitCount; + DataSize = ((DataSize + 31) & ~31) / 8; + DataSize *= BitmapInfo->bmiHeader.biPlanes; + } + else + { + DataSize = BitmapInfo->bmiHeader.biSizeImage; + } + } + } + + /* + * If BitmapInfo was originally BITMAPCOREINFO then we need to convert + * it to the standard BITMAPINFO layout. + */ + + if (BitmapInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)) + { + Size = sizeof(BITMAPINFOHEADER); + if (ColorSpec == DIB_RGB_COLORS) + Size += PaletteEntryCount * sizeof(RGBQUAD); + else + Size += PaletteEntryCount * sizeof(USHORT); + Size += DataSize; + + NewBitmapInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size); + if (NewBitmapInfo == NULL) + { + return NULL; + } + + NewBitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + NewBitmapInfo->bmiHeader.biWidth = CoreBitmapInfo->bmciHeader.bcWidth; + NewBitmapInfo->bmiHeader.biHeight = CoreBitmapInfo->bmciHeader.bcHeight; + NewBitmapInfo->bmiHeader.biPlanes = CoreBitmapInfo->bmciHeader.bcPlanes; + NewBitmapInfo->bmiHeader.biBitCount = CoreBitmapInfo->bmciHeader.bcBitCount; + NewBitmapInfo->bmiHeader.biCompression = BI_RGB; + NewBitmapInfo->bmiHeader.biSizeImage = 0; + NewBitmapInfo->bmiHeader.biXPelsPerMeter = 0; + NewBitmapInfo->bmiHeader.biYPelsPerMeter = 0; + NewBitmapInfo->bmiHeader.biClrUsed = 0; + NewBitmapInfo->bmiHeader.biClrImportant = 0; + + if (PaletteEntryCount != 0) + { + if (ColorSpec == DIB_RGB_COLORS) + { + ULONG Index; + + for (Index = 0; Index < PaletteEntryCount; Index++) + { + NewBitmapInfo->bmiColors[Index].rgbRed = + CoreBitmapInfo->bmciColors[Index].rgbtRed; + NewBitmapInfo->bmiColors[Index].rgbGreen = + CoreBitmapInfo->bmciColors[Index].rgbtGreen; + NewBitmapInfo->bmiColors[Index].rgbBlue = + CoreBitmapInfo->bmciColors[Index].rgbtBlue; + NewBitmapInfo->bmiColors[Index].rgbReserved = 0; + } + } + else + { + RtlCopyMemory(NewBitmapInfo->bmiColors, + CoreBitmapInfo->bmciColors, + PaletteEntryCount * sizeof(USHORT)); + } + } + + if (FollowedByData) + { + ULONG_PTR NewDataPtr, OldDataPtr; + + if (ColorSpec == DIB_RGB_COLORS) + { + NewDataPtr = (ULONG_PTR)(NewBitmapInfo->bmiColors + + PaletteEntryCount); + OldDataPtr = (ULONG_PTR)(CoreBitmapInfo->bmciColors + + PaletteEntryCount); + } + else + { + NewDataPtr = (ULONG_PTR)(NewBitmapInfo->bmiColors) + + PaletteEntryCount * sizeof(USHORT); + OldDataPtr = (ULONG_PTR)(CoreBitmapInfo->bmciColors) + + PaletteEntryCount * sizeof(USHORT); + } + + RtlCopyMemory((PVOID)NewDataPtr, (PVOID)OldDataPtr, DataSize); + } + } + + Size = NewBitmapInfo->bmiHeader.biSize; + if (ColorSpec == DIB_RGB_COLORS) + Size += PaletteEntryCount * sizeof(RGBQUAD); + else + Size += PaletteEntryCount * sizeof(USHORT); + Size += DataSize; + *BitmapInfoSize = Size; + + return NewBitmapInfo; +} + +VOID +STDCALL +LogFontA2W(LPLOGFONTW pW, CONST LOGFONTA *pA) +{ +#define COPYS(f,len) MultiByteToWideChar ( CP_THREAD_ACP, 0, pA->f, len, pW->f, len ) +#define COPYN(f) pW->f = pA->f + + COPYN(lfHeight); + COPYN(lfWidth); + COPYN(lfEscapement); + COPYN(lfOrientation); + COPYN(lfWeight); + COPYN(lfItalic); + COPYN(lfUnderline); + COPYN(lfStrikeOut); + COPYN(lfCharSet); + COPYN(lfOutPrecision); + COPYN(lfClipPrecision); + COPYN(lfQuality); + COPYN(lfPitchAndFamily); + COPYS(lfFaceName,LF_FACESIZE); + +#undef COPYN +#undef COPYS +} + +VOID +STDCALL +LogFontW2A(LPLOGFONTA pA, CONST LOGFONTW *pW) +{ +#define COPYS(f,len) WideCharToMultiByte ( CP_THREAD_ACP, 0, pW->f, len, pA->f, len, NULL, NULL ) +#define COPYN(f) pA->f = pW->f + + COPYN(lfHeight); + COPYN(lfWidth); + COPYN(lfEscapement); + COPYN(lfOrientation); + COPYN(lfWeight); + COPYN(lfItalic); + COPYN(lfUnderline); + COPYN(lfStrikeOut); + COPYN(lfCharSet); + COPYN(lfOutPrecision); + COPYN(lfClipPrecision); + COPYN(lfQuality); + COPYN(lfPitchAndFamily); + COPYS(lfFaceName,LF_FACESIZE); + +#undef COPYN +#undef COPYS +} diff --git a/reactos/lib/icmp/icmp_main.c b/reactos/lib/icmp/icmp_main.c index 4f68446f24a..370fe84c1c5 100644 --- a/reactos/lib/icmp/icmp_main.c +++ b/reactos/lib/icmp/icmp_main.c @@ -1,514 +1,514 @@ -/* - * ICMP - * - * Francois Gouget, 1999, based on the work of - * RW Hall, 1999, based on public domain code PING.C by Mike Muus (1983) - * and later works (c) 1989 Regents of Univ. of California - see copyright - * notice at end of source-code. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* Future work: - * - Systems like FreeBSD don't seem to support the IP_TTL option and maybe others. - * But using IP_HDRINCL and building the IP header by hand might work. - * - Not all IP options are supported. - * - Are ICMP handles real handles, i.e. inheritable and all? There might be some - * more work to do here, including server side stuff with synchronization. - * - Is it correct to use malloc for the internal buffer, for allocating the - * handle's structure? - * - This API should probably be thread safe. Is it really? - * - Using the winsock functions has not been tested. - */ - -#include "config.h" - -#include <sys/types.h> -#ifdef HAVE_SYS_SOCKET_H -# include <sys/socket.h> -#endif -#ifdef HAVE_NETDB_H -# include <netdb.h> -#endif -#ifdef HAVE_NETINET_IN_SYSTM_H -# include <netinet/in_systm.h> -#endif -#ifdef HAVE_NETINET_IN_H -# include <netinet/in.h> -#endif - -#ifdef HAVE_SYS_TIME_H -# include <sys/time.h> -#endif -#include <stdarg.h> -#include <string.h> -#include <errno.h> -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#endif -#ifdef HAVE_ARPA_INET_H -# include <arpa/inet.h> -#endif - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "ipexport.h" -#include "icmpapi.h" -#include "wine/debug.h" - -/* Set up endiannes macros for the ip and ip_icmp BSD headers */ -#ifndef BIG_ENDIAN -#define BIG_ENDIAN 4321 -#endif -#ifndef LITTLE_ENDIAN -#define LITTLE_ENDIAN 1234 -#endif -#ifndef BYTE_ORDER -#ifdef WORDS_BIGENDIAN -#define BYTE_ORDER BIG_ENDIAN -#else -#define BYTE_ORDER LITTLE_ENDIAN -#endif -#endif /* BYTE_ORDER */ - -#define u_int16_t WORD -#define u_int32_t DWORD - -/* These are BSD headers. We use these here because they are needed on - * libc5 Linux systems. On other platforms they are usually simply more - * complete than the native stuff, and cause less portability problems - * so we use them anyway. - */ -#include "ip.h" -#include "ip_icmp.h" - - -WINE_DEFAULT_DEBUG_CHANNEL(icmp); - - -typedef struct { - int sid; - IP_OPTION_INFORMATION default_opts; -} icmp_t; - -#define IP_OPTS_UNKNOWN 0 -#define IP_OPTS_DEFAULT 1 -#define IP_OPTS_CUSTOM 2 - -/* The sequence number is unique process wide, so that all threads - * have a distinct sequence number. - */ -static LONG icmp_sequence=0; - -static int in_cksum(u_short *addr, int len) -{ - int nleft=len; - u_short *w = addr; - int sum = 0; - u_short answer = 0; - - while (nleft > 1) { - sum += *w++; - nleft -= 2; - } - - if (nleft == 1) { - *(u_char *)(&answer) = *(u_char *)w; - sum += answer; - } - - sum = (sum >> 16) + (sum & 0xffff); - sum += (sum >> 16); - answer = ~sum; - return(answer); -} - - - -/* - * Exported Routines. - */ - -/*********************************************************************** - * IcmpCreateFile (ICMP.@) - */ -HANDLE WINAPI IcmpCreateFile(VOID) -{ - icmp_t* icp; - - int sid=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP); - if (sid < 0) { - MESSAGE("WARNING: Trying to use ICMP (network ping) will fail unless running as root\n"); - SetLastError(ERROR_ACCESS_DENIED); - return INVALID_HANDLE_VALUE; - } - - icp=HeapAlloc(GetProcessHeap(), 0, sizeof(*icp)); - if (icp==NULL) { - SetLastError(IP_NO_RESOURCES); - return INVALID_HANDLE_VALUE; - } - icp->sid=sid; - icp->default_opts.OptionsSize=IP_OPTS_UNKNOWN; - return (HANDLE)icp; -} - - -/*********************************************************************** - * IcmpCloseHandle (ICMP.@) - */ -BOOL WINAPI IcmpCloseHandle(HANDLE IcmpHandle) -{ - icmp_t* icp=(icmp_t*)IcmpHandle; - if (IcmpHandle==INVALID_HANDLE_VALUE) { - /* FIXME: in fact win98 seems to ignore the handle value !!! */ - SetLastError(ERROR_INVALID_HANDLE); - return FALSE; - } - - shutdown(icp->sid,2); - HeapFree(GetProcessHeap (), 0, icp); - return TRUE; -} - - -/*********************************************************************** - * IcmpSendEcho (ICMP.@) - */ -DWORD WINAPI IcmpSendEcho( - HANDLE IcmpHandle, - IPAddr DestinationAddress, - LPVOID RequestData, - WORD RequestSize, - PIP_OPTION_INFORMATION RequestOptions, - LPVOID ReplyBuffer, - DWORD ReplySize, - DWORD Timeout - ) -{ - icmp_t* icp=(icmp_t*)IcmpHandle; - unsigned char* reqbuf; - int reqsize; - - struct icmp_echo_reply* ier; - struct ip* ip_header; - struct icmp* icmp_header; - char* endbuf; - int ip_header_len; - int maxlen; - fd_set fdr; - struct timeval timeout; - DWORD send_time,recv_time; - struct sockaddr_in addr; - int addrlen; - unsigned short id,seq,cksum; - int res; - - if (IcmpHandle==INVALID_HANDLE_VALUE) { - /* FIXME: in fact win98 seems to ignore the handle value !!! */ - SetLastError(ERROR_INVALID_HANDLE); - return 0; - } - - if (ReplySize<sizeof(ICMP_ECHO_REPLY)+ICMP_MINLEN) { - SetLastError(IP_BUF_TOO_SMALL); - return 0; - } - /* check the request size against SO_MAX_MSG_SIZE using getsockopt */ - - /* Prepare the request */ - id=getpid() & 0xFFFF; - seq=InterlockedIncrement(&icmp_sequence) & 0xFFFF; - - reqsize=ICMP_MINLEN+RequestSize; - reqbuf=HeapAlloc(GetProcessHeap(), 0, reqsize); - if (reqbuf==NULL) { - SetLastError(ERROR_OUTOFMEMORY); - return 0; - } - - icmp_header=(struct icmp*)reqbuf; - icmp_header->icmp_type=ICMP_ECHO; - icmp_header->icmp_code=0; - icmp_header->icmp_cksum=0; - icmp_header->icmp_id=id; - icmp_header->icmp_seq=seq; - memcpy(reqbuf+ICMP_MINLEN, RequestData, RequestSize); - icmp_header->icmp_cksum=cksum=in_cksum((u_short*)reqbuf,reqsize); - - addr.sin_family=AF_INET; - addr.sin_addr.s_addr=DestinationAddress; - addr.sin_port=0; - - if (RequestOptions!=NULL) { - int val; - if (icp->default_opts.OptionsSize==IP_OPTS_UNKNOWN) { - int len; - /* Before we mess with the options, get the default values */ - len=sizeof(val); - getsockopt(icp->sid,IPPROTO_IP,IP_TTL,(char *)&val,&len); - icp->default_opts.Ttl=val; - - len=sizeof(val); - getsockopt(icp->sid,IPPROTO_IP,IP_TOS,(char *)&val,&len); - icp->default_opts.Tos=val; - /* FIXME: missing: handling of IP 'flags', and all the other options */ - } - - val=RequestOptions->Ttl; - setsockopt(icp->sid,IPPROTO_IP,IP_TTL,(char *)&val,sizeof(val)); - val=RequestOptions->Tos; - setsockopt(icp->sid,IPPROTO_IP,IP_TOS,(char *)&val,sizeof(val)); - /* FIXME: missing: handling of IP 'flags', and all the other options */ - - icp->default_opts.OptionsSize=IP_OPTS_CUSTOM; - } else if (icp->default_opts.OptionsSize==IP_OPTS_CUSTOM) { - int val; - - /* Restore the default options */ - val=icp->default_opts.Ttl; - setsockopt(icp->sid,IPPROTO_IP,IP_TTL,(char *)&val,sizeof(val)); - val=icp->default_opts.Tos; - setsockopt(icp->sid,IPPROTO_IP,IP_TOS,(char *)&val,sizeof(val)); - /* FIXME: missing: handling of IP 'flags', and all the other options */ - - icp->default_opts.OptionsSize=IP_OPTS_DEFAULT; - } - - /* Get ready for receiving the reply - * Do it before we send the request to minimize the risk of introducing delays - */ - FD_ZERO(&fdr); - FD_SET(icp->sid,&fdr); - timeout.tv_sec=Timeout/1000; - timeout.tv_usec=(Timeout % 1000)*1000; - addrlen=sizeof(addr); - ier=ReplyBuffer; - ip_header=(struct ip *) ((char *) ReplyBuffer+sizeof(ICMP_ECHO_REPLY)); - endbuf=(char *) ReplyBuffer+ReplySize; - maxlen=ReplySize-sizeof(ICMP_ECHO_REPLY); - - /* Send the packet */ - TRACE("Sending %d bytes (RequestSize=%d) to %s\n", reqsize, RequestSize, inet_ntoa(addr.sin_addr)); -#if 0 - if (TRACE_ON(icmp)){ - unsigned char* buf=(unsigned char*)reqbuf; - int i; - printf("Output buffer:\n"); - for (i=0;i<reqsize;i++) - printf("%2x,", buf[i]); - printf("\n"); - } -#endif - - send_time = GetTickCount(); - res=sendto(icp->sid, reqbuf, reqsize, 0, (struct sockaddr*)&addr, sizeof(addr)); - HeapFree(GetProcessHeap (), 0, reqbuf); - if (res<0) { - if (errno==EMSGSIZE) - SetLastError(IP_PACKET_TOO_BIG); - else { - switch (errno) { - case ENETUNREACH: - SetLastError(IP_DEST_NET_UNREACHABLE); - break; - case EHOSTUNREACH: - SetLastError(IP_DEST_HOST_UNREACHABLE); - break; - default: - TRACE("unknown error: errno=%d\n",errno); - SetLastError(IP_GENERAL_FAILURE); - } - } - return 0; - } - - /* Get the reply */ - ip_header_len=0; /* because gcc was complaining */ - while ((res=select(icp->sid+1,&fdr,NULL,NULL,&timeout))>0) { - recv_time = GetTickCount(); - res=recvfrom(icp->sid, (char*)ip_header, maxlen, 0, (struct sockaddr*)&addr,&addrlen); - TRACE("received %d bytes from %s\n",res, inet_ntoa(addr.sin_addr)); - ier->Status=IP_REQ_TIMED_OUT; - - /* Check whether we should ignore this packet */ - if ((ip_header->ip_p==IPPROTO_ICMP) && (res>=sizeof(struct ip)+ICMP_MINLEN)) { - ip_header_len=ip_header->ip_hl << 2; - icmp_header=(struct icmp*)(((char*)ip_header)+ip_header_len); - TRACE("received an ICMP packet of type,code=%d,%d\n",icmp_header->icmp_type,icmp_header->icmp_code); - if (icmp_header->icmp_type==ICMP_ECHOREPLY) { - if ((icmp_header->icmp_id==id) && (icmp_header->icmp_seq==seq)) - ier->Status=IP_SUCCESS; - } else { - switch (icmp_header->icmp_type) { - case ICMP_UNREACH: - switch (icmp_header->icmp_code) { - case ICMP_UNREACH_HOST: -#ifdef ICMP_UNREACH_HOST_UNKNOWN - case ICMP_UNREACH_HOST_UNKNOWN: -#endif -#ifdef ICMP_UNREACH_ISOLATED - case ICMP_UNREACH_ISOLATED: -#endif -#ifdef ICMP_UNREACH_HOST_PROHIB - case ICMP_UNREACH_HOST_PROHIB: -#endif -#ifdef ICMP_UNREACH_TOSHOST - case ICMP_UNREACH_TOSHOST: -#endif - ier->Status=IP_DEST_HOST_UNREACHABLE; - break; - case ICMP_UNREACH_PORT: - ier->Status=IP_DEST_PORT_UNREACHABLE; - break; - case ICMP_UNREACH_PROTOCOL: - ier->Status=IP_DEST_PROT_UNREACHABLE; - break; - case ICMP_UNREACH_SRCFAIL: - ier->Status=IP_BAD_ROUTE; - break; - default: - ier->Status=IP_DEST_NET_UNREACHABLE; - } - break; - case ICMP_TIMXCEED: - if (icmp_header->icmp_code==ICMP_TIMXCEED_REASS) - ier->Status=IP_TTL_EXPIRED_REASSEM; - else - ier->Status=IP_TTL_EXPIRED_TRANSIT; - break; - case ICMP_PARAMPROB: - ier->Status=IP_PARAM_PROBLEM; - break; - case ICMP_SOURCEQUENCH: - ier->Status=IP_SOURCE_QUENCH; - break; - } - if (ier->Status!=IP_REQ_TIMED_OUT) { - struct ip* rep_ip_header; - struct icmp* rep_icmp_header; - /* The ICMP header size of all the packets we accept is the same */ - rep_ip_header=(struct ip*)(((char*)icmp_header)+ICMP_MINLEN); - rep_icmp_header=(struct icmp*)(((char*)rep_ip_header)+(rep_ip_header->ip_hl << 2)); - - /* Make sure that this is really a reply to our packet */ - if (ip_header_len+ICMP_MINLEN+(rep_ip_header->ip_hl << 2)+ICMP_MINLEN>ip_header->ip_len) { - ier->Status=IP_REQ_TIMED_OUT; - } else if ((rep_icmp_header->icmp_type!=ICMP_ECHO) || - (rep_icmp_header->icmp_code!=0) || - (rep_icmp_header->icmp_id!=id) || - /* windows doesn't check this checksum, else tracert */ - /* behind a Linux 2.2 masquerading firewall would fail*/ - /* (rep_icmp_header->icmp_cksum!=cksum) || */ - (rep_icmp_header->icmp_seq!=seq)) { - /* This was not a reply to one of our packets after all */ - TRACE("skipping type,code=%d,%d id,seq=%d,%d cksum=%d\n", - rep_icmp_header->icmp_type,rep_icmp_header->icmp_code, - rep_icmp_header->icmp_id,rep_icmp_header->icmp_seq, - rep_icmp_header->icmp_cksum); - TRACE("expected type,code=8,0 id,seq=%d,%d cksum=%d\n", - id,seq, - cksum); - ier->Status=IP_REQ_TIMED_OUT; - } - } - } - } - - if (ier->Status==IP_REQ_TIMED_OUT) { - /* This packet was not for us. - * Decrease the timeout so that we don't enter an endless loop even - * if we get flooded with ICMP packets that are not for us. - */ - int t = Timeout - (recv_time - send_time); - if (t < 0) t = 0; - timeout.tv_sec = t / 1000; - timeout.tv_usec = (t % 1000) * 1000; - continue; - } else { - /* This is a reply to our packet */ - memcpy(&ier->Address,&ip_header->ip_src,sizeof(IPAddr)); - /* Status is already set */ - ier->RoundTripTime= recv_time - send_time; - ier->DataSize=res-ip_header_len-ICMP_MINLEN; - ier->Reserved=0; - ier->Data=endbuf-ier->DataSize; - memmove(ier->Data,((char*)ip_header)+ip_header_len+ICMP_MINLEN,ier->DataSize); - ier->Options.Ttl=ip_header->ip_ttl; - ier->Options.Tos=ip_header->ip_tos; - ier->Options.Flags=ip_header->ip_off >> 13; - ier->Options.OptionsSize=ip_header_len-sizeof(struct ip); - if (ier->Options.OptionsSize!=0) { - ier->Options.OptionsData=(unsigned char *) ier->Data-ier->Options.OptionsSize; - /* FIXME: We are supposed to rearrange the option's 'source route' data */ - memmove(ier->Options.OptionsData,((char*)ip_header)+ip_header_len,ier->Options.OptionsSize); - endbuf=ier->Options.OptionsData; - } else { - ier->Options.OptionsData=NULL; - endbuf=ier->Data; - } - - /* Prepare for the next packet */ - ier++; - ip_header=(struct ip*)(((char*)ip_header)+sizeof(ICMP_ECHO_REPLY)); - maxlen=endbuf-(char*)ip_header; - - /* Check out whether there is more but don't wait this time */ - timeout.tv_sec=0; - timeout.tv_usec=0; - } - FD_ZERO(&fdr); - FD_SET(icp->sid,&fdr); - } - res=ier-(ICMP_ECHO_REPLY*)ReplyBuffer; - if (res==0) - SetLastError(IP_REQ_TIMED_OUT); - TRACE("received %d replies\n",res); - return res; -} - -/* - * Copyright (c) 1989 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Mike Muuss. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - */ +/* + * ICMP + * + * Francois Gouget, 1999, based on the work of + * RW Hall, 1999, based on public domain code PING.C by Mike Muus (1983) + * and later works (c) 1989 Regents of Univ. of California - see copyright + * notice at end of source-code. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Future work: + * - Systems like FreeBSD don't seem to support the IP_TTL option and maybe others. + * But using IP_HDRINCL and building the IP header by hand might work. + * - Not all IP options are supported. + * - Are ICMP handles real handles, i.e. inheritable and all? There might be some + * more work to do here, including server side stuff with synchronization. + * - Is it correct to use malloc for the internal buffer, for allocating the + * handle's structure? + * - This API should probably be thread safe. Is it really? + * - Using the winsock functions has not been tested. + */ + +#include "config.h" + +#include <sys/types.h> +#ifdef HAVE_SYS_SOCKET_H +# include <sys/socket.h> +#endif +#ifdef HAVE_NETDB_H +# include <netdb.h> +#endif +#ifdef HAVE_NETINET_IN_SYSTM_H +# include <netinet/in_systm.h> +#endif +#ifdef HAVE_NETINET_IN_H +# include <netinet/in.h> +#endif + +#ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +#endif +#include <stdarg.h> +#include <string.h> +#include <errno.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#ifdef HAVE_ARPA_INET_H +# include <arpa/inet.h> +#endif + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "ipexport.h" +#include "icmpapi.h" +#include "wine/debug.h" + +/* Set up endiannes macros for the ip and ip_icmp BSD headers */ +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 4321 +#endif +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#endif +#ifndef BYTE_ORDER +#ifdef WORDS_BIGENDIAN +#define BYTE_ORDER BIG_ENDIAN +#else +#define BYTE_ORDER LITTLE_ENDIAN +#endif +#endif /* BYTE_ORDER */ + +#define u_int16_t WORD +#define u_int32_t DWORD + +/* These are BSD headers. We use these here because they are needed on + * libc5 Linux systems. On other platforms they are usually simply more + * complete than the native stuff, and cause less portability problems + * so we use them anyway. + */ +#include "ip.h" +#include "ip_icmp.h" + + +WINE_DEFAULT_DEBUG_CHANNEL(icmp); + + +typedef struct { + int sid; + IP_OPTION_INFORMATION default_opts; +} icmp_t; + +#define IP_OPTS_UNKNOWN 0 +#define IP_OPTS_DEFAULT 1 +#define IP_OPTS_CUSTOM 2 + +/* The sequence number is unique process wide, so that all threads + * have a distinct sequence number. + */ +static LONG icmp_sequence=0; + +static int in_cksum(u_short *addr, int len) +{ + int nleft=len; + u_short *w = addr; + int sum = 0; + u_short answer = 0; + + while (nleft > 1) { + sum += *w++; + nleft -= 2; + } + + if (nleft == 1) { + *(u_char *)(&answer) = *(u_char *)w; + sum += answer; + } + + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + answer = ~sum; + return(answer); +} + + + +/* + * Exported Routines. + */ + +/*********************************************************************** + * IcmpCreateFile (ICMP.@) + */ +HANDLE WINAPI IcmpCreateFile(VOID) +{ + icmp_t* icp; + + int sid=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP); + if (sid < 0) { + MESSAGE("WARNING: Trying to use ICMP (network ping) will fail unless running as root\n"); + SetLastError(ERROR_ACCESS_DENIED); + return INVALID_HANDLE_VALUE; + } + + icp=HeapAlloc(GetProcessHeap(), 0, sizeof(*icp)); + if (icp==NULL) { + SetLastError(IP_NO_RESOURCES); + return INVALID_HANDLE_VALUE; + } + icp->sid=sid; + icp->default_opts.OptionsSize=IP_OPTS_UNKNOWN; + return (HANDLE)icp; +} + + +/*********************************************************************** + * IcmpCloseHandle (ICMP.@) + */ +BOOL WINAPI IcmpCloseHandle(HANDLE IcmpHandle) +{ + icmp_t* icp=(icmp_t*)IcmpHandle; + if (IcmpHandle==INVALID_HANDLE_VALUE) { + /* FIXME: in fact win98 seems to ignore the handle value !!! */ + SetLastError(ERROR_INVALID_HANDLE); + return FALSE; + } + + shutdown(icp->sid,2); + HeapFree(GetProcessHeap (), 0, icp); + return TRUE; +} + + +/*********************************************************************** + * IcmpSendEcho (ICMP.@) + */ +DWORD WINAPI IcmpSendEcho( + HANDLE IcmpHandle, + IPAddr DestinationAddress, + LPVOID RequestData, + WORD RequestSize, + PIP_OPTION_INFORMATION RequestOptions, + LPVOID ReplyBuffer, + DWORD ReplySize, + DWORD Timeout + ) +{ + icmp_t* icp=(icmp_t*)IcmpHandle; + unsigned char* reqbuf; + int reqsize; + + struct icmp_echo_reply* ier; + struct ip* ip_header; + struct icmp* icmp_header; + char* endbuf; + int ip_header_len; + int maxlen; + fd_set fdr; + struct timeval timeout; + DWORD send_time,recv_time; + struct sockaddr_in addr; + int addrlen; + unsigned short id,seq,cksum; + int res; + + if (IcmpHandle==INVALID_HANDLE_VALUE) { + /* FIXME: in fact win98 seems to ignore the handle value !!! */ + SetLastError(ERROR_INVALID_HANDLE); + return 0; + } + + if (ReplySize<sizeof(ICMP_ECHO_REPLY)+ICMP_MINLEN) { + SetLastError(IP_BUF_TOO_SMALL); + return 0; + } + /* check the request size against SO_MAX_MSG_SIZE using getsockopt */ + + /* Prepare the request */ + id=getpid() & 0xFFFF; + seq=InterlockedIncrement(&icmp_sequence) & 0xFFFF; + + reqsize=ICMP_MINLEN+RequestSize; + reqbuf=HeapAlloc(GetProcessHeap(), 0, reqsize); + if (reqbuf==NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return 0; + } + + icmp_header=(struct icmp*)reqbuf; + icmp_header->icmp_type=ICMP_ECHO; + icmp_header->icmp_code=0; + icmp_header->icmp_cksum=0; + icmp_header->icmp_id=id; + icmp_header->icmp_seq=seq; + memcpy(reqbuf+ICMP_MINLEN, RequestData, RequestSize); + icmp_header->icmp_cksum=cksum=in_cksum((u_short*)reqbuf,reqsize); + + addr.sin_family=AF_INET; + addr.sin_addr.s_addr=DestinationAddress; + addr.sin_port=0; + + if (RequestOptions!=NULL) { + int val; + if (icp->default_opts.OptionsSize==IP_OPTS_UNKNOWN) { + int len; + /* Before we mess with the options, get the default values */ + len=sizeof(val); + getsockopt(icp->sid,IPPROTO_IP,IP_TTL,(char *)&val,&len); + icp->default_opts.Ttl=val; + + len=sizeof(val); + getsockopt(icp->sid,IPPROTO_IP,IP_TOS,(char *)&val,&len); + icp->default_opts.Tos=val; + /* FIXME: missing: handling of IP 'flags', and all the other options */ + } + + val=RequestOptions->Ttl; + setsockopt(icp->sid,IPPROTO_IP,IP_TTL,(char *)&val,sizeof(val)); + val=RequestOptions->Tos; + setsockopt(icp->sid,IPPROTO_IP,IP_TOS,(char *)&val,sizeof(val)); + /* FIXME: missing: handling of IP 'flags', and all the other options */ + + icp->default_opts.OptionsSize=IP_OPTS_CUSTOM; + } else if (icp->default_opts.OptionsSize==IP_OPTS_CUSTOM) { + int val; + + /* Restore the default options */ + val=icp->default_opts.Ttl; + setsockopt(icp->sid,IPPROTO_IP,IP_TTL,(char *)&val,sizeof(val)); + val=icp->default_opts.Tos; + setsockopt(icp->sid,IPPROTO_IP,IP_TOS,(char *)&val,sizeof(val)); + /* FIXME: missing: handling of IP 'flags', and all the other options */ + + icp->default_opts.OptionsSize=IP_OPTS_DEFAULT; + } + + /* Get ready for receiving the reply + * Do it before we send the request to minimize the risk of introducing delays + */ + FD_ZERO(&fdr); + FD_SET(icp->sid,&fdr); + timeout.tv_sec=Timeout/1000; + timeout.tv_usec=(Timeout % 1000)*1000; + addrlen=sizeof(addr); + ier=ReplyBuffer; + ip_header=(struct ip *) ((char *) ReplyBuffer+sizeof(ICMP_ECHO_REPLY)); + endbuf=(char *) ReplyBuffer+ReplySize; + maxlen=ReplySize-sizeof(ICMP_ECHO_REPLY); + + /* Send the packet */ + TRACE("Sending %d bytes (RequestSize=%d) to %s\n", reqsize, RequestSize, inet_ntoa(addr.sin_addr)); +#if 0 + if (TRACE_ON(icmp)){ + unsigned char* buf=(unsigned char*)reqbuf; + int i; + printf("Output buffer:\n"); + for (i=0;i<reqsize;i++) + printf("%2x,", buf[i]); + printf("\n"); + } +#endif + + send_time = GetTickCount(); + res=sendto(icp->sid, reqbuf, reqsize, 0, (struct sockaddr*)&addr, sizeof(addr)); + HeapFree(GetProcessHeap (), 0, reqbuf); + if (res<0) { + if (errno==EMSGSIZE) + SetLastError(IP_PACKET_TOO_BIG); + else { + switch (errno) { + case ENETUNREACH: + SetLastError(IP_DEST_NET_UNREACHABLE); + break; + case EHOSTUNREACH: + SetLastError(IP_DEST_HOST_UNREACHABLE); + break; + default: + TRACE("unknown error: errno=%d\n",errno); + SetLastError(IP_GENERAL_FAILURE); + } + } + return 0; + } + + /* Get the reply */ + ip_header_len=0; /* because gcc was complaining */ + while ((res=select(icp->sid+1,&fdr,NULL,NULL,&timeout))>0) { + recv_time = GetTickCount(); + res=recvfrom(icp->sid, (char*)ip_header, maxlen, 0, (struct sockaddr*)&addr,&addrlen); + TRACE("received %d bytes from %s\n",res, inet_ntoa(addr.sin_addr)); + ier->Status=IP_REQ_TIMED_OUT; + + /* Check whether we should ignore this packet */ + if ((ip_header->ip_p==IPPROTO_ICMP) && (res>=sizeof(struct ip)+ICMP_MINLEN)) { + ip_header_len=ip_header->ip_hl << 2; + icmp_header=(struct icmp*)(((char*)ip_header)+ip_header_len); + TRACE("received an ICMP packet of type,code=%d,%d\n",icmp_header->icmp_type,icmp_header->icmp_code); + if (icmp_header->icmp_type==ICMP_ECHOREPLY) { + if ((icmp_header->icmp_id==id) && (icmp_header->icmp_seq==seq)) + ier->Status=IP_SUCCESS; + } else { + switch (icmp_header->icmp_type) { + case ICMP_UNREACH: + switch (icmp_header->icmp_code) { + case ICMP_UNREACH_HOST: +#ifdef ICMP_UNREACH_HOST_UNKNOWN + case ICMP_UNREACH_HOST_UNKNOWN: +#endif +#ifdef ICMP_UNREACH_ISOLATED + case ICMP_UNREACH_ISOLATED: +#endif +#ifdef ICMP_UNREACH_HOST_PROHIB + case ICMP_UNREACH_HOST_PROHIB: +#endif +#ifdef ICMP_UNREACH_TOSHOST + case ICMP_UNREACH_TOSHOST: +#endif + ier->Status=IP_DEST_HOST_UNREACHABLE; + break; + case ICMP_UNREACH_PORT: + ier->Status=IP_DEST_PORT_UNREACHABLE; + break; + case ICMP_UNREACH_PROTOCOL: + ier->Status=IP_DEST_PROT_UNREACHABLE; + break; + case ICMP_UNREACH_SRCFAIL: + ier->Status=IP_BAD_ROUTE; + break; + default: + ier->Status=IP_DEST_NET_UNREACHABLE; + } + break; + case ICMP_TIMXCEED: + if (icmp_header->icmp_code==ICMP_TIMXCEED_REASS) + ier->Status=IP_TTL_EXPIRED_REASSEM; + else + ier->Status=IP_TTL_EXPIRED_TRANSIT; + break; + case ICMP_PARAMPROB: + ier->Status=IP_PARAM_PROBLEM; + break; + case ICMP_SOURCEQUENCH: + ier->Status=IP_SOURCE_QUENCH; + break; + } + if (ier->Status!=IP_REQ_TIMED_OUT) { + struct ip* rep_ip_header; + struct icmp* rep_icmp_header; + /* The ICMP header size of all the packets we accept is the same */ + rep_ip_header=(struct ip*)(((char*)icmp_header)+ICMP_MINLEN); + rep_icmp_header=(struct icmp*)(((char*)rep_ip_header)+(rep_ip_header->ip_hl << 2)); + + /* Make sure that this is really a reply to our packet */ + if (ip_header_len+ICMP_MINLEN+(rep_ip_header->ip_hl << 2)+ICMP_MINLEN>ip_header->ip_len) { + ier->Status=IP_REQ_TIMED_OUT; + } else if ((rep_icmp_header->icmp_type!=ICMP_ECHO) || + (rep_icmp_header->icmp_code!=0) || + (rep_icmp_header->icmp_id!=id) || + /* windows doesn't check this checksum, else tracert */ + /* behind a Linux 2.2 masquerading firewall would fail*/ + /* (rep_icmp_header->icmp_cksum!=cksum) || */ + (rep_icmp_header->icmp_seq!=seq)) { + /* This was not a reply to one of our packets after all */ + TRACE("skipping type,code=%d,%d id,seq=%d,%d cksum=%d\n", + rep_icmp_header->icmp_type,rep_icmp_header->icmp_code, + rep_icmp_header->icmp_id,rep_icmp_header->icmp_seq, + rep_icmp_header->icmp_cksum); + TRACE("expected type,code=8,0 id,seq=%d,%d cksum=%d\n", + id,seq, + cksum); + ier->Status=IP_REQ_TIMED_OUT; + } + } + } + } + + if (ier->Status==IP_REQ_TIMED_OUT) { + /* This packet was not for us. + * Decrease the timeout so that we don't enter an endless loop even + * if we get flooded with ICMP packets that are not for us. + */ + int t = Timeout - (recv_time - send_time); + if (t < 0) t = 0; + timeout.tv_sec = t / 1000; + timeout.tv_usec = (t % 1000) * 1000; + continue; + } else { + /* This is a reply to our packet */ + memcpy(&ier->Address,&ip_header->ip_src,sizeof(IPAddr)); + /* Status is already set */ + ier->RoundTripTime= recv_time - send_time; + ier->DataSize=res-ip_header_len-ICMP_MINLEN; + ier->Reserved=0; + ier->Data=endbuf-ier->DataSize; + memmove(ier->Data,((char*)ip_header)+ip_header_len+ICMP_MINLEN,ier->DataSize); + ier->Options.Ttl=ip_header->ip_ttl; + ier->Options.Tos=ip_header->ip_tos; + ier->Options.Flags=ip_header->ip_off >> 13; + ier->Options.OptionsSize=ip_header_len-sizeof(struct ip); + if (ier->Options.OptionsSize!=0) { + ier->Options.OptionsData=(unsigned char *) ier->Data-ier->Options.OptionsSize; + /* FIXME: We are supposed to rearrange the option's 'source route' data */ + memmove(ier->Options.OptionsData,((char*)ip_header)+ip_header_len,ier->Options.OptionsSize); + endbuf=ier->Options.OptionsData; + } else { + ier->Options.OptionsData=NULL; + endbuf=ier->Data; + } + + /* Prepare for the next packet */ + ier++; + ip_header=(struct ip*)(((char*)ip_header)+sizeof(ICMP_ECHO_REPLY)); + maxlen=endbuf-(char*)ip_header; + + /* Check out whether there is more but don't wait this time */ + timeout.tv_sec=0; + timeout.tv_usec=0; + } + FD_ZERO(&fdr); + FD_SET(icp->sid,&fdr); + } + res=ier-(ICMP_ECHO_REPLY*)ReplyBuffer; + if (res==0) + SetLastError(IP_REQ_TIMED_OUT); + TRACE("received %d replies\n",res); + return res; +} + +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Mike Muuss. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ diff --git a/reactos/lib/icmp/ip.h b/reactos/lib/icmp/ip.h index 6463b72dcc4..823ac6ab1ae 100644 --- a/reactos/lib/icmp/ip.h +++ b/reactos/lib/icmp/ip.h @@ -1,195 +1,195 @@ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)ip.h 8.2 (Berkeley) 6/1/94 - * $FreeBSD: src/sys/netinet/ip.h,v 1.16 1999/08/28 00:49:19 peter Exp $ - */ - -#ifndef _NETINET_IP_H_ -#define _NETINET_IP_H_ - -/* - * Definitions for internet protocol version 4. - * Per RFC 791, September 1981. - */ -#define IPVERSION 4 - -/* A little magic to make the Windows build happy. */ -#if defined(_MSC_VER) || defined(__MINGW32__) -#include <winsock2.h> -#include <ws2tcpip.h> -#include <time.h> - -typedef u_short n_short; -typedef u_int n_long; -typedef u_int n_time; - -#define EMSGSIZE WSAEMSGSIZE -#define ENETUNREACH WSAENETUNREACH -#define EHOSTUNREACH WSAEHOSTUNREACH -#endif - -/* - * Structure of an internet header, naked of options. - */ -struct ip { -#ifdef _IP_VHL - u_char ip_vhl; /* version << 4 | header length >> 2 */ -#else -#if BYTE_ORDER == LITTLE_ENDIAN - u_int ip_hl:4, /* header length */ - ip_v:4; /* version */ -#endif -#if BYTE_ORDER == BIG_ENDIAN - u_int ip_v:4, /* version */ - ip_hl:4; /* header length */ -#endif -#endif /* not _IP_VHL */ - u_char ip_tos; /* type of service */ - u_short ip_len; /* total length */ - u_short ip_id; /* identification */ - u_short ip_off; /* fragment offset field */ -#define IP_RF 0x8000 /* reserved fragment flag */ -#define IP_DF 0x4000 /* don't fragment flag */ -#define IP_MF 0x2000 /* more fragments flag */ -#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ - u_char ip_ttl; /* time to live */ - u_char ip_p; /* protocol */ - u_short ip_sum; /* checksum */ - struct in_addr ip_src,ip_dst; /* source and dest address */ -}; - -#ifdef _IP_VHL -#define IP_MAKE_VHL(v, hl) ((v) << 4 | (hl)) -#define IP_VHL_HL(vhl) ((vhl) & 0x0f) -#define IP_VHL_V(vhl) ((vhl) >> 4) -#define IP_VHL_BORING 0x45 -#endif - -#define IP_MAXPACKET 65535 /* maximum packet size */ - -/* - * Definitions for IP type of service (ip_tos) - */ -#define IPTOS_LOWDELAY 0x10 -#define IPTOS_THROUGHPUT 0x08 -#define IPTOS_RELIABILITY 0x04 -#define IPTOS_MINCOST 0x02 - -/* - * Definitions for IP precedence (also in ip_tos) (hopefully unused) - */ -#define IPTOS_PREC_NETCONTROL 0xe0 -#define IPTOS_PREC_INTERNETCONTROL 0xc0 -#define IPTOS_PREC_CRITIC_ECP 0xa0 -#define IPTOS_PREC_FLASHOVERRIDE 0x80 -#define IPTOS_PREC_FLASH 0x60 -#define IPTOS_PREC_IMMEDIATE 0x40 -#define IPTOS_PREC_PRIORITY 0x20 -#define IPTOS_PREC_ROUTINE 0x00 - -/* - * Definitions for options. - */ -#define IPOPT_COPIED(o) ((o)&0x80) -#define IPOPT_CLASS(o) ((o)&0x60) -#define IPOPT_NUMBER(o) ((o)&0x1f) - -#define IPOPT_CONTROL 0x00 -#define IPOPT_RESERVED1 0x20 -#define IPOPT_DEBMEAS 0x40 -#define IPOPT_RESERVED2 0x60 - -#define IPOPT_EOL 0 /* end of option list */ -#define IPOPT_NOP 1 /* no operation */ - -#define IPOPT_RR 7 /* record packet route */ -#define IPOPT_TS 68 /* timestamp */ -#define IPOPT_SECURITY 130 /* provide s,c,h,tcc */ -#define IPOPT_LSRR 131 /* loose source route */ -#define IPOPT_SATID 136 /* satnet id */ -#define IPOPT_SSRR 137 /* strict source route */ -#define IPOPT_RA 148 /* router alert */ - -/* - * Offsets to fields in options other than EOL and NOP. - */ -#define IPOPT_OPTVAL 0 /* option ID */ -#define IPOPT_OLEN 1 /* option length */ -#define IPOPT_OFFSET 2 /* offset within option */ -#define IPOPT_MINOFF 4 /* min value of above */ - -/* - * Time stamp option structure. - */ -struct ip_timestamp { - u_char ipt_code; /* IPOPT_TS */ - u_char ipt_len; /* size of structure (variable) */ - u_char ipt_ptr; /* index of current entry */ -#if BYTE_ORDER == LITTLE_ENDIAN - u_int ipt_flg:4, /* flags, see below */ - ipt_oflw:4; /* overflow counter */ -#endif -#if BYTE_ORDER == BIG_ENDIAN - u_int ipt_oflw:4, /* overflow counter */ - ipt_flg:4; /* flags, see below */ -#endif - union ipt_timestamp { - n_long ipt_time[1]; - struct ipt_ta { - struct in_addr ipt_addr; - n_long ipt_time; - } ipt_ta[1]; - } ipt_timestamp; -}; - -/* flag bits for ipt_flg */ -#define IPOPT_TS_TSONLY 0 /* timestamps only */ -#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ -#define IPOPT_TS_PRESPEC 3 /* specified modules only */ - -/* bits for security (not byte swapped) */ -#define IPOPT_SECUR_UNCLASS 0x0000 -#define IPOPT_SECUR_CONFID 0xf135 -#define IPOPT_SECUR_EFTO 0x789a -#define IPOPT_SECUR_MMMM 0xbc4d -#define IPOPT_SECUR_RESTR 0xaf13 -#define IPOPT_SECUR_SECRET 0xd788 -#define IPOPT_SECUR_TOPSECRET 0x6bc5 - -/* - * Internet implementation parameters. - */ -#define MAXTTL 255 /* maximum time to live (seconds) */ -#define IPDEFTTL 64 /* default ttl, from RFC 1340 */ -#define IPFRAGTTL 60 /* time to live for frags, slowhz */ -#define IPTTLDEC 1 /* subtracted when forwarding */ - -#define IP_MSS 576 /* default maximum segment size */ - -#endif +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ip.h 8.2 (Berkeley) 6/1/94 + * $FreeBSD: src/sys/netinet/ip.h,v 1.16 1999/08/28 00:49:19 peter Exp $ + */ + +#ifndef _NETINET_IP_H_ +#define _NETINET_IP_H_ + +/* + * Definitions for internet protocol version 4. + * Per RFC 791, September 1981. + */ +#define IPVERSION 4 + +/* A little magic to make the Windows build happy. */ +#if defined(_MSC_VER) || defined(__MINGW32__) +#include <winsock2.h> +#include <ws2tcpip.h> +#include <time.h> + +typedef u_short n_short; +typedef u_int n_long; +typedef u_int n_time; + +#define EMSGSIZE WSAEMSGSIZE +#define ENETUNREACH WSAENETUNREACH +#define EHOSTUNREACH WSAEHOSTUNREACH +#endif + +/* + * Structure of an internet header, naked of options. + */ +struct ip { +#ifdef _IP_VHL + u_char ip_vhl; /* version << 4 | header length >> 2 */ +#else +#if BYTE_ORDER == LITTLE_ENDIAN + u_int ip_hl:4, /* header length */ + ip_v:4; /* version */ +#endif +#if BYTE_ORDER == BIG_ENDIAN + u_int ip_v:4, /* version */ + ip_hl:4; /* header length */ +#endif +#endif /* not _IP_VHL */ + u_char ip_tos; /* type of service */ + u_short ip_len; /* total length */ + u_short ip_id; /* identification */ + u_short ip_off; /* fragment offset field */ +#define IP_RF 0x8000 /* reserved fragment flag */ +#define IP_DF 0x4000 /* don't fragment flag */ +#define IP_MF 0x2000 /* more fragments flag */ +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + u_char ip_ttl; /* time to live */ + u_char ip_p; /* protocol */ + u_short ip_sum; /* checksum */ + struct in_addr ip_src,ip_dst; /* source and dest address */ +}; + +#ifdef _IP_VHL +#define IP_MAKE_VHL(v, hl) ((v) << 4 | (hl)) +#define IP_VHL_HL(vhl) ((vhl) & 0x0f) +#define IP_VHL_V(vhl) ((vhl) >> 4) +#define IP_VHL_BORING 0x45 +#endif + +#define IP_MAXPACKET 65535 /* maximum packet size */ + +/* + * Definitions for IP type of service (ip_tos) + */ +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 +#define IPTOS_MINCOST 0x02 + +/* + * Definitions for IP precedence (also in ip_tos) (hopefully unused) + */ +#define IPTOS_PREC_NETCONTROL 0xe0 +#define IPTOS_PREC_INTERNETCONTROL 0xc0 +#define IPTOS_PREC_CRITIC_ECP 0xa0 +#define IPTOS_PREC_FLASHOVERRIDE 0x80 +#define IPTOS_PREC_FLASH 0x60 +#define IPTOS_PREC_IMMEDIATE 0x40 +#define IPTOS_PREC_PRIORITY 0x20 +#define IPTOS_PREC_ROUTINE 0x00 + +/* + * Definitions for options. + */ +#define IPOPT_COPIED(o) ((o)&0x80) +#define IPOPT_CLASS(o) ((o)&0x60) +#define IPOPT_NUMBER(o) ((o)&0x1f) + +#define IPOPT_CONTROL 0x00 +#define IPOPT_RESERVED1 0x20 +#define IPOPT_DEBMEAS 0x40 +#define IPOPT_RESERVED2 0x60 + +#define IPOPT_EOL 0 /* end of option list */ +#define IPOPT_NOP 1 /* no operation */ + +#define IPOPT_RR 7 /* record packet route */ +#define IPOPT_TS 68 /* timestamp */ +#define IPOPT_SECURITY 130 /* provide s,c,h,tcc */ +#define IPOPT_LSRR 131 /* loose source route */ +#define IPOPT_SATID 136 /* satnet id */ +#define IPOPT_SSRR 137 /* strict source route */ +#define IPOPT_RA 148 /* router alert */ + +/* + * Offsets to fields in options other than EOL and NOP. + */ +#define IPOPT_OPTVAL 0 /* option ID */ +#define IPOPT_OLEN 1 /* option length */ +#define IPOPT_OFFSET 2 /* offset within option */ +#define IPOPT_MINOFF 4 /* min value of above */ + +/* + * Time stamp option structure. + */ +struct ip_timestamp { + u_char ipt_code; /* IPOPT_TS */ + u_char ipt_len; /* size of structure (variable) */ + u_char ipt_ptr; /* index of current entry */ +#if BYTE_ORDER == LITTLE_ENDIAN + u_int ipt_flg:4, /* flags, see below */ + ipt_oflw:4; /* overflow counter */ +#endif +#if BYTE_ORDER == BIG_ENDIAN + u_int ipt_oflw:4, /* overflow counter */ + ipt_flg:4; /* flags, see below */ +#endif + union ipt_timestamp { + n_long ipt_time[1]; + struct ipt_ta { + struct in_addr ipt_addr; + n_long ipt_time; + } ipt_ta[1]; + } ipt_timestamp; +}; + +/* flag bits for ipt_flg */ +#define IPOPT_TS_TSONLY 0 /* timestamps only */ +#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ +#define IPOPT_TS_PRESPEC 3 /* specified modules only */ + +/* bits for security (not byte swapped) */ +#define IPOPT_SECUR_UNCLASS 0x0000 +#define IPOPT_SECUR_CONFID 0xf135 +#define IPOPT_SECUR_EFTO 0x789a +#define IPOPT_SECUR_MMMM 0xbc4d +#define IPOPT_SECUR_RESTR 0xaf13 +#define IPOPT_SECUR_SECRET 0xd788 +#define IPOPT_SECUR_TOPSECRET 0x6bc5 + +/* + * Internet implementation parameters. + */ +#define MAXTTL 255 /* maximum time to live (seconds) */ +#define IPDEFTTL 64 /* default ttl, from RFC 1340 */ +#define IPFRAGTTL 60 /* time to live for frags, slowhz */ +#define IPTTLDEC 1 /* subtracted when forwarding */ + +#define IP_MSS 576 /* default maximum segment size */ + +#endif diff --git a/reactos/lib/icmp/ip_icmp.h b/reactos/lib/icmp/ip_icmp.h index 2b3ee2eb280..ce5449526d2 100644 --- a/reactos/lib/icmp/ip_icmp.h +++ b/reactos/lib/icmp/ip_icmp.h @@ -1,186 +1,186 @@ -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93 - * $FreeBSD: src/sys/netinet/ip_icmp.h,v 1.13 1999/08/28 00:49:24 peter Exp $ - */ - -#ifndef _NETINET_IP_ICMP_H_ -#define _NETINET_IP_ICMP_H_ - -/* - * Interface Control Message Protocol Definitions. - * Per RFC 792, September 1981. - */ - -/* - * Internal of an ICMP Router Advertisement - */ -struct icmp_ra_addr { - u_int32_t ira_addr; - u_int32_t ira_preference; -}; - -/* - * Structure of an icmp header. - */ -struct icmp { - u_char icmp_type; /* type of message, see below */ - u_char icmp_code; /* type sub code */ - u_short icmp_cksum; /* ones complement cksum of struct */ - union { - u_char ih_pptr; /* ICMP_PARAMPROB */ - struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ - struct ih_idseq { - n_short icd_id; - n_short icd_seq; - } ih_idseq; - int ih_void; - - /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ - struct ih_pmtu { - n_short ipm_void; - n_short ipm_nextmtu; - } ih_pmtu; - - struct ih_rtradv { - u_char irt_num_addrs; - u_char irt_wpa; - u_int16_t irt_lifetime; - } ih_rtradv; - } icmp_hun; -#define icmp_pptr icmp_hun.ih_pptr -#define icmp_gwaddr icmp_hun.ih_gwaddr -#define icmp_id icmp_hun.ih_idseq.icd_id -#define icmp_seq icmp_hun.ih_idseq.icd_seq -#define icmp_void icmp_hun.ih_void -#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void -#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu -#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs -#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa -#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime - union { - struct id_ts { - n_time its_otime; - n_time its_rtime; - n_time its_ttime; - } id_ts; - struct id_ip { - struct ip idi_ip; - /* options and then 64 bits of data */ - } id_ip; - struct icmp_ra_addr id_radv; - u_int32_t id_mask; - char id_data[1]; - } icmp_dun; -#define icmp_otime icmp_dun.id_ts.its_otime -#define icmp_rtime icmp_dun.id_ts.its_rtime -#define icmp_ttime icmp_dun.id_ts.its_ttime -#define icmp_ip icmp_dun.id_ip.idi_ip -#define icmp_radv icmp_dun.id_radv -#define icmp_mask icmp_dun.id_mask -#define icmp_data icmp_dun.id_data -}; - -/* - * Lower bounds on packet lengths for various types. - * For the error advice packets must first insure that the - * packet is large enough to contain the returned ip header. - * Only then can we do the check to see if 64 bits of packet - * data have been returned, since we need to check the returned - * ip header length. - */ -#define ICMP_MINLEN 8 /* abs minimum */ -#define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */ -#define ICMP_MASKLEN 12 /* address mask */ -#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ -#ifndef _IP_VHL -#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) - /* N.B.: must separately check that ip_hl >= 5 */ -#else -#define ICMP_ADVLEN(p) (8 + (IP_VHL_HL((p)->icmp_ip.ip_vhl) << 2) + 8) - /* N.B.: must separately check that header length >= 5 */ -#endif - -/* - * Definition of type and code field values. - */ -#define ICMP_ECHOREPLY 0 /* echo reply */ -#define ICMP_UNREACH 3 /* dest unreachable, codes: */ -#define ICMP_UNREACH_NET 0 /* bad net */ -#define ICMP_UNREACH_HOST 1 /* bad host */ -#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ -#define ICMP_UNREACH_PORT 3 /* bad port */ -#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ -#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ -#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ -#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ -#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ -#define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */ -#define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */ -#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ -#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ -#define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohib */ -#define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host prec vio. */ -#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* prec cutoff */ -#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ -#define ICMP_REDIRECT 5 /* shorter route, codes: */ -#define ICMP_REDIRECT_NET 0 /* for network */ -#define ICMP_REDIRECT_HOST 1 /* for host */ -#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ -#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ -#define ICMP_ECHO 8 /* echo service */ -#define ICMP_ROUTERADVERT 9 /* router advertisement */ -#define ICMP_ROUTERSOLICIT 10 /* router solicitation */ -#define ICMP_TIMXCEED 11 /* time exceeded, code: */ -#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ -#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ -#define ICMP_PARAMPROB 12 /* ip header bad */ -#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ -#define ICMP_TSTAMP 13 /* timestamp request */ -#define ICMP_TSTAMPREPLY 14 /* timestamp reply */ -#define ICMP_IREQ 15 /* information request */ -#define ICMP_IREQREPLY 16 /* information reply */ -#define ICMP_MASKREQ 17 /* address mask request */ -#define ICMP_MASKREPLY 18 /* address mask reply */ - -#define ICMP_MAXTYPE 18 - -#define ICMP_INFOTYPE(type) \ - ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ - (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \ - (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ - (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ - (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) - -#ifdef KERNEL -void icmp_error __P((struct mbuf *, int, int, n_long, struct ifnet *)); -void icmp_input __P((struct mbuf *, int)); -#endif - -#endif +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/netinet/ip_icmp.h,v 1.13 1999/08/28 00:49:24 peter Exp $ + */ + +#ifndef _NETINET_IP_ICMP_H_ +#define _NETINET_IP_ICMP_H_ + +/* + * Interface Control Message Protocol Definitions. + * Per RFC 792, September 1981. + */ + +/* + * Internal of an ICMP Router Advertisement + */ +struct icmp_ra_addr { + u_int32_t ira_addr; + u_int32_t ira_preference; +}; + +/* + * Structure of an icmp header. + */ +struct icmp { + u_char icmp_type; /* type of message, see below */ + u_char icmp_code; /* type sub code */ + u_short icmp_cksum; /* ones complement cksum of struct */ + union { + u_char ih_pptr; /* ICMP_PARAMPROB */ + struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ + struct ih_idseq { + n_short icd_id; + n_short icd_seq; + } ih_idseq; + int ih_void; + + /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ + struct ih_pmtu { + n_short ipm_void; + n_short ipm_nextmtu; + } ih_pmtu; + + struct ih_rtradv { + u_char irt_num_addrs; + u_char irt_wpa; + u_int16_t irt_lifetime; + } ih_rtradv; + } icmp_hun; +#define icmp_pptr icmp_hun.ih_pptr +#define icmp_gwaddr icmp_hun.ih_gwaddr +#define icmp_id icmp_hun.ih_idseq.icd_id +#define icmp_seq icmp_hun.ih_idseq.icd_seq +#define icmp_void icmp_hun.ih_void +#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void +#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu +#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs +#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa +#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime + union { + struct id_ts { + n_time its_otime; + n_time its_rtime; + n_time its_ttime; + } id_ts; + struct id_ip { + struct ip idi_ip; + /* options and then 64 bits of data */ + } id_ip; + struct icmp_ra_addr id_radv; + u_int32_t id_mask; + char id_data[1]; + } icmp_dun; +#define icmp_otime icmp_dun.id_ts.its_otime +#define icmp_rtime icmp_dun.id_ts.its_rtime +#define icmp_ttime icmp_dun.id_ts.its_ttime +#define icmp_ip icmp_dun.id_ip.idi_ip +#define icmp_radv icmp_dun.id_radv +#define icmp_mask icmp_dun.id_mask +#define icmp_data icmp_dun.id_data +}; + +/* + * Lower bounds on packet lengths for various types. + * For the error advice packets must first insure that the + * packet is large enough to contain the returned ip header. + * Only then can we do the check to see if 64 bits of packet + * data have been returned, since we need to check the returned + * ip header length. + */ +#define ICMP_MINLEN 8 /* abs minimum */ +#define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */ +#define ICMP_MASKLEN 12 /* address mask */ +#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ +#ifndef _IP_VHL +#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) + /* N.B.: must separately check that ip_hl >= 5 */ +#else +#define ICMP_ADVLEN(p) (8 + (IP_VHL_HL((p)->icmp_ip.ip_vhl) << 2) + 8) + /* N.B.: must separately check that header length >= 5 */ +#endif + +/* + * Definition of type and code field values. + */ +#define ICMP_ECHOREPLY 0 /* echo reply */ +#define ICMP_UNREACH 3 /* dest unreachable, codes: */ +#define ICMP_UNREACH_NET 0 /* bad net */ +#define ICMP_UNREACH_HOST 1 /* bad host */ +#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ +#define ICMP_UNREACH_PORT 3 /* bad port */ +#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ +#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ +#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ +#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ +#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ +#define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */ +#define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */ +#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ +#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ +#define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohib */ +#define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host prec vio. */ +#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* prec cutoff */ +#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ +#define ICMP_REDIRECT 5 /* shorter route, codes: */ +#define ICMP_REDIRECT_NET 0 /* for network */ +#define ICMP_REDIRECT_HOST 1 /* for host */ +#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ +#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ +#define ICMP_ECHO 8 /* echo service */ +#define ICMP_ROUTERADVERT 9 /* router advertisement */ +#define ICMP_ROUTERSOLICIT 10 /* router solicitation */ +#define ICMP_TIMXCEED 11 /* time exceeded, code: */ +#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ +#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ +#define ICMP_PARAMPROB 12 /* ip header bad */ +#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ +#define ICMP_TSTAMP 13 /* timestamp request */ +#define ICMP_TSTAMPREPLY 14 /* timestamp reply */ +#define ICMP_IREQ 15 /* information request */ +#define ICMP_IREQREPLY 16 /* information reply */ +#define ICMP_MASKREQ 17 /* address mask request */ +#define ICMP_MASKREPLY 18 /* address mask reply */ + +#define ICMP_MAXTYPE 18 + +#define ICMP_INFOTYPE(type) \ + ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ + (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \ + (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ + (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ + (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) + +#ifdef KERNEL +void icmp_error __P((struct mbuf *, int, int, n_long, struct ifnet *)); +void icmp_input __P((struct mbuf *, int)); +#endif + +#endif diff --git a/reactos/lib/intrlck/intrlck.c b/reactos/lib/intrlck/intrlck.c index 31f38bd1890..c33b2eedc83 100644 --- a/reactos/lib/intrlck/intrlck.c +++ b/reactos/lib/intrlck/intrlck.c @@ -1,209 +1,209 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS system libraries - * FILE: lib/ntdll/rtl/intrlck.c - * PURPOSE: Inter lock increments - * UPDATE HISTORY: - * Created 30/09/99 - */ - -/* - * Win32 kernel functions - * - * Copyright 1995 Martin von Loewis - * Copyright 1997 Onno Hovers - * Copied from kernel32 - */ - -/* PowerPC Functions from gatomic.c in glib - * - * GLIB - Library of useful routines for C programming - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * - * g_atomic_*: atomic operations. - * Copyright (C) 2003 Sebastian Wilhelmi - * - * 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 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/************************************************************************ -* InterlockedIncrement * -* * -* InterlockedIncrement adds 1 to a long variable and returns * -* the resulting incremented value. * -* * -************************************************************************/ - -#include <windows.h> - -LONG -STDCALL -InterlockedIncrement(PLONG Addend) -{ - long ret; -#ifdef _M_IX86 - __asm__ - ( - "\tlock\n" /* for SMP systems */ - "\txaddl %0, (%1)\n" - "\tincl %0\n" - :"=r" (ret) - :"r" (Addend), "0" (1) - : "memory" - ); -#elif defined(_M_PPC) - ret = *Addend; - ret = InterlockedExchangeAdd( Addend, ret + 1 ); -#else -#error Unknown compiler for inline assembler -#endif - return ret; -} - -/************************************************************************ -* InterlockedDecrement * -* * -* InterlockedDecrement adds -1 to a long variable and returns * -* the resulting decremented value. * -* * -************************************************************************/ - -LONG -STDCALL -InterlockedDecrement(LPLONG lpAddend) -{ - long ret; -#ifdef _M_IX86 - __asm__ - ( - "\tlock\n" /* for SMP systems */ - "\txaddl %0, (%1)\n" - "\tdecl %0\n" - :"=r" (ret) - :"r" (lpAddend), "0" (-1) - : "memory" - ); -#elif defined(_M_PPC) - ret = *lpAddend; - ret = InterlockedExchangeAdd( lpAddend, ret - 1 ); -#else -#error Unknown compiler for inline assembler -#endif - return ret; - - -} - -/************************************************************************ - * InterlockedExchange - * - * Atomically exchanges a pair of values. - * - * RETURNS - * Prior value of value pointed to by Target - */ - -LONG -STDCALL -InterlockedExchange(LPLONG target, LONG value ) -{ - long ret; -#ifdef _M_IX86 - __asm__ ( /* lock for SMP systems */ - "lock\n\txchgl %0,(%1)" - :"=r" (ret):"r" (target), "0" (value):"memory" ); -#elif defined(_M_PPC) - do { - ret = *(volatile LONG *)target; - } while( InterlockedCompareExchange( target, value, ret ) != ret ); -#else -#error Unknown compiler for inline assembler -#endif - return ret; -} - -/************************************************************************ - * InterlockedCompareExchange - * - * Atomically compares Destination and Comperand, and if found equal exchanges - * the value of Destination with Exchange - * - * RETURNS - * Prior value of value pointed to by Destination - */ -LONG -STDCALL -InterlockedCompareExchange( - LPLONG Destination, - LONG Exchange, - LONG Comperand ) -{ - LONG ret; -#ifdef _M_IX86 - __asm__ __volatile__( "lock; cmpxchgl %2,(%1)" - : "=a" (ret) : "r" (Destination), "r" (Exchange), "0" (Comperand) : "memory" ); -#elif defined(_M_PPC) - __asm__ __volatile__ ("sync\n" - "1: lwarx %0,0,%1\n" - " subf. %0,%2,%0\n" - " bne 2f\n" - " stwcx. %3,0,%1\n" - " bne- 1b\n" - "2: isync" - : "=&r" (ret) - : "b" (Destination), "r" (Comperand), "r" (Exchange) - : "cr0", "memory"); -#else -#error Unknown compiler for inline assembler -#endif - return ret; -} - -/************************************************************************ - * InterlockedExchangeAdd - * - * Atomically adds Increment to Addend and returns the previous value of - * Addend - * - * RETURNS - * Prior value of value pointed to by Addend - */ -LONG -STDCALL -InterlockedExchangeAdd( - PLONG Addend, - LONG Increment -) -{ - LONG ret; -#ifdef _M_IX86 - __asm__ ( /* lock for SMP systems */ - "lock\n\t" - "xaddl %0,(%1)" - :"=r" (ret) - :"r" (Addend), "0" (Increment) - :"memory" ); -#elif defined(_M_PPC) - LONG newval; - do { - ret = *(volatile LONG *)Addend; - newval = ret + Increment; - } while (InterlockedCompareExchange(Addend, ret, newval) != ret); -#else -#error Unknown compiler for inline assembler -#endif - return ret; -} +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS system libraries + * FILE: lib/ntdll/rtl/intrlck.c + * PURPOSE: Inter lock increments + * UPDATE HISTORY: + * Created 30/09/99 + */ + +/* + * Win32 kernel functions + * + * Copyright 1995 Martin von Loewis + * Copyright 1997 Onno Hovers + * Copied from kernel32 + */ + +/* PowerPC Functions from gatomic.c in glib + * + * GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * g_atomic_*: atomic operations. + * Copyright (C) 2003 Sebastian Wilhelmi + * + * 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 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/************************************************************************ +* InterlockedIncrement * +* * +* InterlockedIncrement adds 1 to a long variable and returns * +* the resulting incremented value. * +* * +************************************************************************/ + +#include <windows.h> + +LONG +STDCALL +InterlockedIncrement(PLONG Addend) +{ + long ret; +#ifdef _M_IX86 + __asm__ + ( + "\tlock\n" /* for SMP systems */ + "\txaddl %0, (%1)\n" + "\tincl %0\n" + :"=r" (ret) + :"r" (Addend), "0" (1) + : "memory" + ); +#elif defined(_M_PPC) + ret = *Addend; + ret = InterlockedExchangeAdd( Addend, ret + 1 ); +#else +#error Unknown compiler for inline assembler +#endif + return ret; +} + +/************************************************************************ +* InterlockedDecrement * +* * +* InterlockedDecrement adds -1 to a long variable and returns * +* the resulting decremented value. * +* * +************************************************************************/ + +LONG +STDCALL +InterlockedDecrement(LPLONG lpAddend) +{ + long ret; +#ifdef _M_IX86 + __asm__ + ( + "\tlock\n" /* for SMP systems */ + "\txaddl %0, (%1)\n" + "\tdecl %0\n" + :"=r" (ret) + :"r" (lpAddend), "0" (-1) + : "memory" + ); +#elif defined(_M_PPC) + ret = *lpAddend; + ret = InterlockedExchangeAdd( lpAddend, ret - 1 ); +#else +#error Unknown compiler for inline assembler +#endif + return ret; + + +} + +/************************************************************************ + * InterlockedExchange + * + * Atomically exchanges a pair of values. + * + * RETURNS + * Prior value of value pointed to by Target + */ + +LONG +STDCALL +InterlockedExchange(LPLONG target, LONG value ) +{ + long ret; +#ifdef _M_IX86 + __asm__ ( /* lock for SMP systems */ + "lock\n\txchgl %0,(%1)" + :"=r" (ret):"r" (target), "0" (value):"memory" ); +#elif defined(_M_PPC) + do { + ret = *(volatile LONG *)target; + } while( InterlockedCompareExchange( target, value, ret ) != ret ); +#else +#error Unknown compiler for inline assembler +#endif + return ret; +} + +/************************************************************************ + * InterlockedCompareExchange + * + * Atomically compares Destination and Comperand, and if found equal exchanges + * the value of Destination with Exchange + * + * RETURNS + * Prior value of value pointed to by Destination + */ +LONG +STDCALL +InterlockedCompareExchange( + LPLONG Destination, + LONG Exchange, + LONG Comperand ) +{ + LONG ret; +#ifdef _M_IX86 + __asm__ __volatile__( "lock; cmpxchgl %2,(%1)" + : "=a" (ret) : "r" (Destination), "r" (Exchange), "0" (Comperand) : "memory" ); +#elif defined(_M_PPC) + __asm__ __volatile__ ("sync\n" + "1: lwarx %0,0,%1\n" + " subf. %0,%2,%0\n" + " bne 2f\n" + " stwcx. %3,0,%1\n" + " bne- 1b\n" + "2: isync" + : "=&r" (ret) + : "b" (Destination), "r" (Comperand), "r" (Exchange) + : "cr0", "memory"); +#else +#error Unknown compiler for inline assembler +#endif + return ret; +} + +/************************************************************************ + * InterlockedExchangeAdd + * + * Atomically adds Increment to Addend and returns the previous value of + * Addend + * + * RETURNS + * Prior value of value pointed to by Addend + */ +LONG +STDCALL +InterlockedExchangeAdd( + PLONG Addend, + LONG Increment +) +{ + LONG ret; +#ifdef _M_IX86 + __asm__ ( /* lock for SMP systems */ + "lock\n\t" + "xaddl %0,(%1)" + :"=r" (ret) + :"r" (Addend), "0" (Increment) + :"memory" ); +#elif defined(_M_PPC) + LONG newval; + do { + ret = *(volatile LONG *)Addend; + newval = ret + Increment; + } while (InterlockedCompareExchange(Addend, ret, newval) != ret); +#else +#error Unknown compiler for inline assembler +#endif + return ret; +} diff --git a/reactos/lib/kbdes/kbdes.c b/reactos/lib/kbdes/kbdes.c index 18ad873a8f8..7849f417e60 100644 --- a/reactos/lib/kbdes/kbdes.c +++ b/reactos/lib/kbdes/kbdes.c @@ -1,539 +1,539 @@ -/* - * ReactOS ESASCII Keyboard layout - * Copyright (C) 2003 ReactOS - * License: LGPL, see: LGPL.txt - * Created by HUMA2000 from kbdus, kbdgr, kbdda and kbdfr - * huma2000@terra.es - * Thanks to arty for the kbtest utility and help - * Thanks to carraca from reactos.com forum for his fixes - * Thanks Elrond for help - * - * Thanks to: http://www.barcodeman.com/altek/mule/scandoc.php - * and http://win.tue.nl/~aeb/linux/kbd/scancodes-1.html - */ - - -#include <windows.h> -#include <internal/kbd.h> - -#ifdef _M_IA64 -#define ROSDATA static __declspec(allocate(".data")) -#else -#ifdef _MSC_VER -#pragma data_seg(".data") -#define ROSDATA static -#else -#define ROSDATA static __attribute__((section(".data"))) -#endif -#endif - - -#define VK_EMPTY 0xff /* The non-existent VK */ -#define KSHIFT 0x001 /* Shift modifier */ -#define KCTRL 0x002 /* Ctrl modifier */ -#define KALT 0x004 /* Alt modifier */ -#define KEXT 0x100 /* Extended key code */ -#define KMULTI 0x200 /* Multi-key */ -#define KSPEC 0x400 /* Special key */ -#define KNUMP 0x800 /* Number-pad */ -#define KNUMS 0xc00 /* Special + number pad */ -#define KMEXT 0x300 /* Multi + ext */ - -#define SHFT_INVALID 0x0F - -ROSDATA USHORT scancode_to_vk[] = { -/* 00 */ VK_EMPTY, -/* 01 */ VK_ESCAPE, -/* 02 */ '1', -/* 03 */ '2', -/* 04 */ '3', -/* 05 */ '4', -/* 06 */ '5', -/* 07 */ '6', -/* 08 */ '7', -/* 09 */ '8', -/* 0a */ '9', -/* 0b */ '0', -/* 0c */ VK_OEM_4, -/* 0d */ VK_OEM_6, -/* 0e */ VK_BACK, -/* 0f */ VK_TAB, -/* 10 */ 'Q', -/* 11 */ 'W', -/* 12 */ 'E', -/* 13 */ 'R', -/* 14 */ 'T', -/* 15 */ 'Y', -/* 16 */ 'U', -/* 17 */ 'I', -/* 18 */ 'O', -/* 19 */ 'P', -/* 1a */ VK_OEM_1, -/* 1b */ VK_OEM_PLUS, -/* 1c */ VK_RETURN, -/* 1d */ VK_LCONTROL, -/* 1e */ 'A', -/* 1f */ 'S', -/* 20 */ 'D', -/* 21 */ 'F', -/* 22 */ 'G', -/* 23 */ 'H', -/* 24 */ 'J', -/* 25 */ 'K', -/* 26 */ 'L', -/* 27 */ VK_OEM_3, -/* 28 */ VK_OEM_7, -/* 29 */ VK_OEM_5, -/* 2a */ VK_LSHIFT, -/* 2b */ VK_OEM_2, -/* 2c */ 'Z', -/* 2d */ 'X', -/* 2e */ 'C', -/* 2f */ 'V', -/* 30 */ 'B', -/* 31 */ 'N', -/* 32 */ 'M', -/* 33 */ VK_OEM_COMMA, -/* 34 */ VK_OEM_PERIOD, -/* 35 */ VK_OEM_MINUS, -/* 36 */ VK_RSHIFT, -/* 37 */ VK_MULTIPLY, -/* 38 */ VK_LMENU, -/* 39 */ VK_SPACE, -/* 3a */ VK_CAPITAL, -/* 3b */ VK_F1, -/* 3c */ VK_F2, -/* 3d */ VK_F3, -/* 3e */ VK_F4, -/* 3f */ VK_F5, -/* 40 */ VK_F6, -/* 41 */ VK_F7, -/* 42 */ VK_F8, -/* 43 */ VK_F9, -/* 44 */ VK_F10, -/* 45 */ VK_NUMLOCK | KMEXT, -/* 46 */ VK_SCROLL | KMULTI, -/* 47 */ VK_HOME | KNUMS, -/* 48 */ VK_UP | KNUMS, -/* 49 */ VK_PRIOR | KNUMS, -/* 4a */ VK_SUBTRACT, -/* 4b */ VK_LEFT | KNUMS, -/* 4c */ VK_CLEAR | KNUMS, -/* 4d */ VK_RIGHT | KNUMS, -/* 4e */ VK_ADD, -/* 4f */ VK_END | KNUMS, -/* 50 */ VK_DOWN | KNUMS, -/* 51 */ VK_NEXT | KNUMS, -/* 52 */ VK_INSERT | KNUMS, -/* 53 */ VK_DELETE | KNUMS, -/* 54 */ VK_SNAPSHOT, -/* 55 */ VK_EMPTY, -/* 56 */ VK_OEM_102, -/* 57 */ VK_F11, -/* 58 */ VK_F12, -/* 59 */ VK_EMPTY, -/* 5a */ VK_CLEAR, -/* 5b */ VK_EMPTY, -/* 5c */ VK_EMPTY, -/* 5d */ VK_EMPTY, -/* 5e */ VK_EMPTY, /* EREOF */ -/* 5f */ VK_EMPTY, -/* 60 */ VK_EMPTY, -/* 61 */ VK_EMPTY, -/* 62 */ VK_EMPTY, -/* 63 */ VK_EMPTY, /* ZOOM */ -/* 64 */ VK_HELP, -/* 65 */ VK_F13, -/* 66 */ VK_F14, -/* 67 */ VK_F15, -/* 68 */ VK_F16, -/* 69 */ VK_F17, -/* 6a */ VK_F18, -/* 6b */ VK_F19, -/* 6c */ VK_F20, -/* 6d */ VK_F21, -/* 6e */ VK_F22, -/* 6f */ VK_F23, -/* 70 */ VK_EMPTY, -/* 71 */ VK_EMPTY, -/* 72 */ VK_EMPTY, -/* 73 */ VK_EMPTY, -/* 74 */ VK_EMPTY, -/* 75 */ VK_EMPTY, -/* 76 */ VK_EMPTY, -/* 77 */ VK_F24, -/* 78 */ VK_EMPTY, -/* 79 */ VK_EMPTY, -/* 7a */ VK_EMPTY, -/* 7b */ VK_EMPTY, -/* 7c */ VK_EMPTY, -/* 7d */ VK_EMPTY, -/* 7e */ VK_EMPTY, -/* 7f */ VK_EMPTY, -/* 80 */ VK_EMPTY, -/* 00 */ 0 -}; - -ROSDATA VSC_VK extcode0_to_vk[] = { - { 0x10, VK_MEDIA_PREV_TRACK | KEXT }, // Pista anterior, no puedo probarlo hasta que no se implemente el sonido - { 0x19, VK_MEDIA_NEXT_TRACK | KEXT }, // Pista siguiente, - { 0x1D, VK_RCONTROL | KEXT }, // Tecla control - { 0x20, VK_VOLUME_MUTE | KEXT }, // Silenciar volumen - { 0x21, VK_LAUNCH_APP2 | KEXT }, // Tecla calculadora - { 0x22, VK_MEDIA_PLAY_PAUSE | KEXT }, // Play/pause - { 0x24, VK_MEDIA_STOP | KEXT }, // Stop - { 0x2E, VK_VOLUME_DOWN | KEXT }, // Bajar volumen - { 0x30, VK_VOLUME_UP | KEXT }, // Subir volumen - { 0x32, VK_BROWSER_HOME | KEXT }, // Pagina de inicio del navegador de internet o abrirlo si no esta activolo - { 0x35, VK_DIVIDE | KEXT }, // Tecla - { 0x37, VK_SNAPSHOT | KEXT }, // La tecla de imprimir pantalla - { 0x38, VK_RMENU | KEXT }, // Tecla alt - { 0x47, VK_HOME | KEXT }, // Tecla inicio - { 0x48, VK_UP | KEXT }, // Cursor arriba - { 0x49, VK_PRIOR | KEXT }, // Tecla Re pag - { 0x4B, VK_LEFT | KEXT }, // Cursor izquierda - { 0x4D, VK_RIGHT | KEXT }, // Cursor derecha - { 0x4F, VK_END | KEXT }, // Tecla Fin - { 0x50, VK_DOWN | KEXT }, // Cursor abajo - { 0x51, VK_NEXT | KEXT }, // Tecla Av pag - { 0x52, VK_INSERT | KEXT }, // Tecla insertar - { 0x53, VK_DELETE | KEXT }, // Tecla deletear - { 0x5B, VK_LWIN | KEXT }, // Tecla windows izquierda - { 0x5C, VK_RWIN | KEXT }, // Tecla windows derecha - { 0x5D, VK_APPS | KEXT }, // Tecla menu aplicacion derecha - { 0x5F, VK_SLEEP | KEXT }, // Tecla Sleep - { 0x65, VK_BROWSER_SEARCH | KEXT }, // Pagina de búsqueda en el navegador de internet - { 0x66, VK_BROWSER_FAVORITES | KEXT }, // Favoritos, tengo que esperar a que el tcp/ip - { 0x67, VK_BROWSER_REFRESH | KEXT }, // Refrescar el navegador de internet - { 0x68, VK_BROWSER_STOP | KEXT }, // Stop en el navegador de internet - { 0x69, VK_BROWSER_FORWARD | KEXT }, // Adelante en el navegador de internet - { 0x6A, VK_BROWSER_BACK | KEXT }, // Atrás en el navegador de internet - { 0x6B, VK_LAUNCH_APP1 | KEXT }, // Tecla Mi pc - { 0x6C, VK_LAUNCH_MAIL | KEXT }, // Abrir programa de e-mail - { 0x6D, VK_LAUNCH_MEDIA_SELECT | KEXT }, // Abrir reproductor multimedia - { 0x1C, VK_RETURN | KEXT }, // La tecla de intro - { 0x46, VK_CANCEL | KEXT }, // Tecla escape - { 0, 0 }, -}; - - -ROSDATA VSC_VK extcode1_to_vk[] = { - { 0, 0 }, -}; - -ROSDATA VK_TO_BIT modifier_keys[] = { - { VK_SHIFT, KSHIFT }, - { VK_CONTROL, KCTRL }, - { VK_MENU, KALT }, - { 0, 0 } -}; - -ROSDATA MODIFIERS modifier_bits = { - modifier_keys, - 6, - { 0, 1, 2, 4, SHFT_INVALID, SHFT_INVALID, 3 } -/* NONE, SHIFT, CTRL, CTRL+SHIFT, ALT */ -}; - -#define NOCAPS 0 -#define CAPS KSHIFT /* Caps -> shift */ - -ROSDATA VK_TO_WCHARS2 key_to_chars_2mod[] = { - /* Normal vs Shifted */ - /* The numbers */ - //Del 1 al 5 tienen tres estados - { '4', NOCAPS, {'4', '$'} }, - { '5', NOCAPS, {'5', '%'} }, - //El 6 tiene 3 estados - { '7', NOCAPS, {'7', '/'} }, - { '8', NOCAPS, {'8', '('} }, - { '9', NOCAPS, {'9', ')'} }, - { '0', NOCAPS, {'0', '='} }, - /* First letter row */ - { 'Q', CAPS, {'q', 'Q'} }, - { 'W', CAPS, {'w', 'W'} }, - //La E tiene 3 estados - { 'R', CAPS, {'r', 'R'} }, - { 'T', CAPS, {'t', 'T'} }, - { 'Y', CAPS, {'y', 'Y'} }, - { 'U', CAPS, {'u', 'U'} }, - { 'I', CAPS, {'i', 'I'} }, - { 'O', CAPS, {'o', 'O'} }, - { 'P', CAPS, {'p', 'P'} }, - /* Second letter row */ - { 'A', CAPS, {'a', 'A'} }, - { 'S', CAPS, {'s', 'S'} }, - { 'D', CAPS, {'d', 'D'} }, - { 'F', CAPS, {'f', 'F'} }, - { 'G', CAPS, {'g', 'G'} }, - { 'H', CAPS, {'h', 'H'} }, - { 'J', CAPS, {'j', 'J'} }, - { 'K', CAPS, {'k', 'K'} }, - { 'L', CAPS, {'l', 'L'} }, - { VK_OEM_3, CAPS, {0x00F1, 0x00D1} }, // ñÑ - /* Third letter row */ - { 'Z', CAPS, {'z', 'Z'} }, - { 'X', CAPS, {'x', 'X'} }, - { 'C', CAPS, {'c', 'C'} }, - { 'V', CAPS, {'v', 'V'} }, - { 'B', CAPS, {'b', 'B'} }, - { 'N', CAPS, {'n', 'N'} }, - { 'M', CAPS, {'m', 'M'} }, - - /* Specials */ - /* Ctrl-_ generates ES */ - { VK_OEM_6 ,NOCAPS, {0x00a1, 0x00bf} }, // ¡¿ - { VK_OEM_4 ,NOCAPS, {0x0027, '?'} }, //'? - { VK_OEM_COMMA ,NOCAPS, {',', ';'} }, - { VK_OEM_PERIOD ,NOCAPS, {'.', ':'} }, - { VK_OEM_MINUS ,NOCAPS, {'-', '_'} }, - { VK_OEM_102 ,NOCAPS, {'<', '>'} }, - - /* Keys that do not have shift states */ - { VK_TAB, NOCAPS, {'\t', '\t'} }, - { VK_ADD, NOCAPS, {'+', '+'} }, - { VK_SUBTRACT, NOCAPS, {'-', '-'} }, - { VK_MULTIPLY, NOCAPS, {'*', '*'} }, - { VK_DIVIDE, NOCAPS, {'/', '/'} }, - { VK_ESCAPE, NOCAPS, {'\x1b','\x1b'} }, - { VK_SPACE, NOCAPS, {' ', ' '} }, - { 0, 0 } -}; - - -ROSDATA VK_TO_WCHARS3 key_to_chars_3mod[] = { - /* Normal, Shifted, Ctrl */ - /* Legacy (telnet-style) ascii escapes */ - { VK_RETURN, NOCAPS, {'\r', '\r', '\n'} }, - { 0,0 } -}; - - -ROSDATA VK_TO_WCHARS4 key_to_chars_4mod[] = { -/* Normal, shifted, control, Alt+Gr */ - { '1', NOCAPS, {'1', '!', WCH_NONE, 0x00a6} }, // 1!| - { '2', NOCAPS, {'2', '"', WCH_NONE, '@'} }, // 2"@ - { '3', NOCAPS, {'3', 0x00B7, WCH_NONE, '#'} }, // 3·# - { '6', NOCAPS, {'6', '&', WCH_NONE, 0x00AC} }, // 6&¬ - { 'E', CAPS, {'e', 'E', WCH_NONE, 0x20AC} }, // eE€ - { VK_OEM_PLUS, NOCAPS, {'+', '*', WCH_NONE, 0x005d} }, // +*] - { VK_OEM_2, NOCAPS, {0x00e7, 0x00c7, WCH_NONE, '}'} }, // çÇ} - - { VK_OEM_7, NOCAPS, {WCH_DEAD, WCH_DEAD, WCH_NONE, '{'} }, // ´¨{ - { VK_EMPTY, NOCAPS, {0xB4, 0xA8, WCH_NONE, WCH_NONE} }, // ´¨{ - - { VK_OEM_1, NOCAPS, {WCH_DEAD, WCH_DEAD, WCH_NONE, 0x5B} }, // `^[ - { VK_EMPTY, NOCAPS, {0x60, 0x5e, WCH_NONE, WCH_NONE} }, // `^[ - - { VK_OEM_5, NOCAPS, {0x00BA, 0x00AA, WCH_NONE, 0x005c} }, // çÇ} - { 0, 0 } -}; - - - -ROSDATA VK_TO_WCHARS1 keypad_numbers[] = { - { VK_NUMPAD0, 0, {'0'} }, - { VK_NUMPAD1, 0, {'1'} }, - { VK_NUMPAD2, 0, {'2'} }, - { VK_NUMPAD3, 0, {'3'} }, - { VK_NUMPAD4, 0, {'4'} }, - { VK_NUMPAD5, 0, {'5'} }, - { VK_NUMPAD6, 0, {'6'} }, - { VK_NUMPAD7, 0, {'7'} }, - { VK_NUMPAD8, 0, {'8'} }, - { VK_NUMPAD9, 0, {'9'} }, - { VK_DECIMAL, 0, {'.'} }, - { VK_BACK, 0, {'\010'} }, - { 0,0 } -}; - - -#define vk_master(n,x) { (PVK_TO_WCHARS1)x, n, sizeof(x[0]) } - - -ROSDATA VK_TO_WCHAR_TABLE vk_to_wchar_master_table[] = { - vk_master(1,keypad_numbers), - vk_master(2,key_to_chars_2mod), - vk_master(3,key_to_chars_3mod), - vk_master(4,key_to_chars_4mod), - { 0,0,0 } -}; - -#define DEADTRANS(ch, accent, comp, flags) MAKELONG(ch, accent), comp, flags //no funciona -ROSDATA DEADKEY deadkey[] = -{ - //*´* - { DEADTRANS(L'a', 0xb4, 0xE1, 0x00) }, // letra a con ´ - { DEADTRANS(L'A', 0xb4, 0xC1, 0x00) }, // letra A con ´ - { DEADTRANS(L'e', 0xb4, 0xE9, 0x00) }, // letra e con ´ - { DEADTRANS(L'E', 0xb4, 0xC9, 0x00) }, // letra E con ´ - { DEADTRANS(L'i', 0xb4, 0xED, 0x00) }, // letra i con ´ - { DEADTRANS(L'I', 0xb4, 0xCD, 0x00) }, // letra I con ´ - { DEADTRANS(L'o', 0xb4, 0xF3, 0x00) }, // letra o con ´ - { DEADTRANS(L'O', 0xb4, 0xD3, 0x00) }, // letra O con ´ - { DEADTRANS(L'u', 0xb4, 0xFA, 0x00) }, // letra u con ´ - { DEADTRANS(L'U', 0xb4, 0xDA, 0x00) }, // letra U con ´ - //*`* - { DEADTRANS(L'a', 0x60, 0xE0, 0x00) }, // letra a con ` - { DEADTRANS(L'A', 0x60, 0xC0, 0x00) }, // letra A con ` - { DEADTRANS(L'e', 0x60, 0xE8, 0x00) }, // letra e con ` - { DEADTRANS(L'E', 0x60, 0xC8, 0x00) }, // letra E con ` - { DEADTRANS(L'i', 0x60, 0xEC, 0x00) }, // letra i con ` - { DEADTRANS(L'I', 0x60, 0xCC, 0x00) }, // letra I con ` - { DEADTRANS(L'o', 0x60, 0xF2, 0x00) }, // letra o con ` - { DEADTRANS(L'O', 0x60, 0xD2, 0x00) }, // letra O con ` - { DEADTRANS(L'u', 0x60, 0xF9, 0x00) }, // letra u con ` - { DEADTRANS(L'U', 0x60, 0xD9, 0x00) }, // letra U con ` - //*^* - { DEADTRANS(L'a', 0x5E, 0xE2, 0x00) }, // letra a con ^ - { DEADTRANS(L'A', 0x5E, 0xC2, 0x00) }, // letra A con ^ - { DEADTRANS(L'e', 0x5E, 0xEA, 0x00) }, // letra e con ^ - { DEADTRANS(L'E', 0x5E, 0xCA, 0x00) }, // letra E con ^ - { DEADTRANS(L'i', 0x5E, 0xEE, 0x00) }, // letra i con ^ - { DEADTRANS(L'I', 0x5E, 0xCE, 0x00) }, // letra I con ^ - { DEADTRANS(L'o', 0x5E, 0xF4, 0x00) }, // letra o con ^ - { DEADTRANS(L'O', 0x5E, 0xD4, 0x00) }, // letra O con ^ - { DEADTRANS(L'u', 0x5E, 0xFB, 0x00) }, // letra u con ^ - { DEADTRANS(L'U', 0x5E, 0xDB, 0x00) }, // letra U con ^ - //*¨* - { DEADTRANS(L'a', 0xA8, 0xE4, 0x00) }, // letra a con ¨ - { DEADTRANS(L'A', 0xA8, 0xC4, 0x00) }, // letra A con ¨ - { DEADTRANS(L'e', 0xA8, 0xEB, 0x00) }, // letra e con ¨ - { DEADTRANS(L'E', 0xA8, 0xCB, 0x00) }, // letra E con ¨ - { DEADTRANS(L'i', 0xA8, 0xEF, 0x00) }, // letra i con ¨ - { DEADTRANS(L'I', 0xA8, 0xCF, 0x00) }, // letra I con ¨ - { DEADTRANS(L'o', 0xA8, 0xF6, 0x00) }, // letra o con ¨ - { DEADTRANS(L'O', 0xA8, 0xD6, 0x00) }, // letra O con ¨ - { DEADTRANS(L'u', 0xA8, 0xFC, 0x00) }, // letra u con ¨ - { DEADTRANS(L'U', 0xA8, 0xDC, 0x00) }, // letra U con ¨ - { 0, 0, 0} -}; - -ROSDATA VSC_LPWSTR key_names[] = { - { 0x00, L"" }, - { 0x01, L"Escape" }, - { 0x0e, L"Borrar" }, - { 0x0f, L"Tabulador" }, - { 0x1c, L"Intro" }, - { 0x1d, L"Ctrl" }, - { 0x2a, L"Shift" }, - { 0x36, L"Shift derecho" }, - { 0x37, L"* numerico" }, - { 0x38, L"Alt" }, - { 0x39, L"Espacio" }, - { 0x3a, L"Bloqueo mayusculas" }, - { 0x3b, L"F1" }, - { 0x3c, L"F2" }, - { 0x3d, L"F3" }, - { 0x3e, L"F4" }, - { 0x3f, L"F5" }, - { 0x40, L"F6" }, - { 0x41, L"F7" }, - { 0x42, L"F8" }, - { 0x43, L"F9" }, - { 0x44, L"F10" }, - { 0x45, L"Pausa" }, - { 0x46, L"Bloqueo de scroll" }, - { 0x47, L"Num 7" }, - { 0x48, L"Num 8" }, - { 0x49, L"Num 9" }, - { 0x4a, L"Num -" }, - { 0x4b, L"Num 4" }, - { 0x4c, L"Num 5" }, - { 0x4d, L"Num 6" }, - { 0x4e, L"Num +" }, - { 0x4f, L"Num 1" }, - { 0x50, L"Num 2" }, - { 0x51, L"Num 3" }, - { 0x52, L"Num 0" }, - { 0x53, L"Borrardo numerico" }, - { 0x54, L"Peticion de sistema" }, - { 0x57, L"F11" }, - { 0x58, L"F12" }, - { 0x7c, L"F13" }, - { 0x7d, L"F14" }, - { 0x7e, L"F15" }, - { 0x7f, L"F16" }, - { 0x80, L"F17" }, - { 0x81, L"F18" }, - { 0x82, L"F19" }, - { 0x83, L"F20" }, - { 0x84, L"F21" }, - { 0x85, L"F22" }, - { 0x86, L"F23" }, - { 0x87, L"F24" }, - { 0, NULL }, -}; - -ROSDATA VSC_LPWSTR extended_key_names[] = { - { 0x1c, L"Intro numerico" }, - { 0x1d, L"Ctrl derecho" }, - { 0x35, L"/ numerica" }, - { 0x37, L"Imprimir pantalla" }, - { 0x38, L"Alt derecho" }, - { 0x45, L"Bloqueo numerico" }, - { 0x46, L"Interrumpir" }, - { 0x47, L"Inicio" }, - { 0x48, L"Arriba" }, - { 0x49, L"Subir pagina" }, - { 0x4b, L"Izquierda" }, - { 0x4c, L"Centrar" }, - { 0x4d, L"Derecha" }, - { 0x4f, L"Fin" }, - { 0x50, L"Abajo" }, - { 0x51, L"Bajar pagina" }, - { 0x52, L"Insertar" }, - { 0x53, L"Borrar" }, - { 0x54, L"<ReactOS>" }, - { 0x55, L"Ayuda" }, - { 0x5b, L"Windows izquierda" }, - { 0x5c, L"Windows derecha" }, - { 0, NULL }, -}; - -ROSDATA DEADKEY_LPWSTR dead_key_names[] = { - L"\x00b4" L"Agudo", - L"\x0060" L"Grave", - L"\x005e" L"Circunflejo", - L"\x00A8" L"Dieresis", - NULL -}; - - -/* Finally, the master table */ -ROSDATA KBDTABLES keyboard_layout_table = { - - /* modifier assignments */ - &modifier_bits, - - /* character from vk tables */ - vk_to_wchar_master_table, - - /* diacritical marks -- currently implemented by wine code */ - /* Spanish have severals */ - deadkey, - - /* Key names */ - (VSC_LPWSTR *)key_names, - (VSC_LPWSTR *)extended_key_names, - dead_key_names, - /* Dead key names */ - - /* scan code to virtual key maps */ - scancode_to_vk, - sizeof(scancode_to_vk) / sizeof(scancode_to_vk[0]), - extcode0_to_vk, - extcode1_to_vk, - - MAKELONG(0,1), /* Version 1.0 */ - - /* Ligatures -- Spanish doesn't have any */ - 0, - 0, - NULL -}; - - -PKBDTABLES STDCALL KbdLayerDescriptor() { - return &keyboard_layout_table; -} +/* + * ReactOS ESASCII Keyboard layout + * Copyright (C) 2003 ReactOS + * License: LGPL, see: LGPL.txt + * Created by HUMA2000 from kbdus, kbdgr, kbdda and kbdfr + * huma2000@terra.es + * Thanks to arty for the kbtest utility and help + * Thanks to carraca from reactos.com forum for his fixes + * Thanks Elrond for help + * + * Thanks to: http://www.barcodeman.com/altek/mule/scandoc.php + * and http://win.tue.nl/~aeb/linux/kbd/scancodes-1.html + */ + + +#include <windows.h> +#include <internal/kbd.h> + +#ifdef _M_IA64 +#define ROSDATA static __declspec(allocate(".data")) +#else +#ifdef _MSC_VER +#pragma data_seg(".data") +#define ROSDATA static +#else +#define ROSDATA static __attribute__((section(".data"))) +#endif +#endif + + +#define VK_EMPTY 0xff /* The non-existent VK */ +#define KSHIFT 0x001 /* Shift modifier */ +#define KCTRL 0x002 /* Ctrl modifier */ +#define KALT 0x004 /* Alt modifier */ +#define KEXT 0x100 /* Extended key code */ +#define KMULTI 0x200 /* Multi-key */ +#define KSPEC 0x400 /* Special key */ +#define KNUMP 0x800 /* Number-pad */ +#define KNUMS 0xc00 /* Special + number pad */ +#define KMEXT 0x300 /* Multi + ext */ + +#define SHFT_INVALID 0x0F + +ROSDATA USHORT scancode_to_vk[] = { +/* 00 */ VK_EMPTY, +/* 01 */ VK_ESCAPE, +/* 02 */ '1', +/* 03 */ '2', +/* 04 */ '3', +/* 05 */ '4', +/* 06 */ '5', +/* 07 */ '6', +/* 08 */ '7', +/* 09 */ '8', +/* 0a */ '9', +/* 0b */ '0', +/* 0c */ VK_OEM_4, +/* 0d */ VK_OEM_6, +/* 0e */ VK_BACK, +/* 0f */ VK_TAB, +/* 10 */ 'Q', +/* 11 */ 'W', +/* 12 */ 'E', +/* 13 */ 'R', +/* 14 */ 'T', +/* 15 */ 'Y', +/* 16 */ 'U', +/* 17 */ 'I', +/* 18 */ 'O', +/* 19 */ 'P', +/* 1a */ VK_OEM_1, +/* 1b */ VK_OEM_PLUS, +/* 1c */ VK_RETURN, +/* 1d */ VK_LCONTROL, +/* 1e */ 'A', +/* 1f */ 'S', +/* 20 */ 'D', +/* 21 */ 'F', +/* 22 */ 'G', +/* 23 */ 'H', +/* 24 */ 'J', +/* 25 */ 'K', +/* 26 */ 'L', +/* 27 */ VK_OEM_3, +/* 28 */ VK_OEM_7, +/* 29 */ VK_OEM_5, +/* 2a */ VK_LSHIFT, +/* 2b */ VK_OEM_2, +/* 2c */ 'Z', +/* 2d */ 'X', +/* 2e */ 'C', +/* 2f */ 'V', +/* 30 */ 'B', +/* 31 */ 'N', +/* 32 */ 'M', +/* 33 */ VK_OEM_COMMA, +/* 34 */ VK_OEM_PERIOD, +/* 35 */ VK_OEM_MINUS, +/* 36 */ VK_RSHIFT, +/* 37 */ VK_MULTIPLY, +/* 38 */ VK_LMENU, +/* 39 */ VK_SPACE, +/* 3a */ VK_CAPITAL, +/* 3b */ VK_F1, +/* 3c */ VK_F2, +/* 3d */ VK_F3, +/* 3e */ VK_F4, +/* 3f */ VK_F5, +/* 40 */ VK_F6, +/* 41 */ VK_F7, +/* 42 */ VK_F8, +/* 43 */ VK_F9, +/* 44 */ VK_F10, +/* 45 */ VK_NUMLOCK | KMEXT, +/* 46 */ VK_SCROLL | KMULTI, +/* 47 */ VK_HOME | KNUMS, +/* 48 */ VK_UP | KNUMS, +/* 49 */ VK_PRIOR | KNUMS, +/* 4a */ VK_SUBTRACT, +/* 4b */ VK_LEFT | KNUMS, +/* 4c */ VK_CLEAR | KNUMS, +/* 4d */ VK_RIGHT | KNUMS, +/* 4e */ VK_ADD, +/* 4f */ VK_END | KNUMS, +/* 50 */ VK_DOWN | KNUMS, +/* 51 */ VK_NEXT | KNUMS, +/* 52 */ VK_INSERT | KNUMS, +/* 53 */ VK_DELETE | KNUMS, +/* 54 */ VK_SNAPSHOT, +/* 55 */ VK_EMPTY, +/* 56 */ VK_OEM_102, +/* 57 */ VK_F11, +/* 58 */ VK_F12, +/* 59 */ VK_EMPTY, +/* 5a */ VK_CLEAR, +/* 5b */ VK_EMPTY, +/* 5c */ VK_EMPTY, +/* 5d */ VK_EMPTY, +/* 5e */ VK_EMPTY, /* EREOF */ +/* 5f */ VK_EMPTY, +/* 60 */ VK_EMPTY, +/* 61 */ VK_EMPTY, +/* 62 */ VK_EMPTY, +/* 63 */ VK_EMPTY, /* ZOOM */ +/* 64 */ VK_HELP, +/* 65 */ VK_F13, +/* 66 */ VK_F14, +/* 67 */ VK_F15, +/* 68 */ VK_F16, +/* 69 */ VK_F17, +/* 6a */ VK_F18, +/* 6b */ VK_F19, +/* 6c */ VK_F20, +/* 6d */ VK_F21, +/* 6e */ VK_F22, +/* 6f */ VK_F23, +/* 70 */ VK_EMPTY, +/* 71 */ VK_EMPTY, +/* 72 */ VK_EMPTY, +/* 73 */ VK_EMPTY, +/* 74 */ VK_EMPTY, +/* 75 */ VK_EMPTY, +/* 76 */ VK_EMPTY, +/* 77 */ VK_F24, +/* 78 */ VK_EMPTY, +/* 79 */ VK_EMPTY, +/* 7a */ VK_EMPTY, +/* 7b */ VK_EMPTY, +/* 7c */ VK_EMPTY, +/* 7d */ VK_EMPTY, +/* 7e */ VK_EMPTY, +/* 7f */ VK_EMPTY, +/* 80 */ VK_EMPTY, +/* 00 */ 0 +}; + +ROSDATA VSC_VK extcode0_to_vk[] = { + { 0x10, VK_MEDIA_PREV_TRACK | KEXT }, // Pista anterior, no puedo probarlo hasta que no se implemente el sonido + { 0x19, VK_MEDIA_NEXT_TRACK | KEXT }, // Pista siguiente, + { 0x1D, VK_RCONTROL | KEXT }, // Tecla control + { 0x20, VK_VOLUME_MUTE | KEXT }, // Silenciar volumen + { 0x21, VK_LAUNCH_APP2 | KEXT }, // Tecla calculadora + { 0x22, VK_MEDIA_PLAY_PAUSE | KEXT }, // Play/pause + { 0x24, VK_MEDIA_STOP | KEXT }, // Stop + { 0x2E, VK_VOLUME_DOWN | KEXT }, // Bajar volumen + { 0x30, VK_VOLUME_UP | KEXT }, // Subir volumen + { 0x32, VK_BROWSER_HOME | KEXT }, // Pagina de inicio del navegador de internet o abrirlo si no esta activolo + { 0x35, VK_DIVIDE | KEXT }, // Tecla + { 0x37, VK_SNAPSHOT | KEXT }, // La tecla de imprimir pantalla + { 0x38, VK_RMENU | KEXT }, // Tecla alt + { 0x47, VK_HOME | KEXT }, // Tecla inicio + { 0x48, VK_UP | KEXT }, // Cursor arriba + { 0x49, VK_PRIOR | KEXT }, // Tecla Re pag + { 0x4B, VK_LEFT | KEXT }, // Cursor izquierda + { 0x4D, VK_RIGHT | KEXT }, // Cursor derecha + { 0x4F, VK_END | KEXT }, // Tecla Fin + { 0x50, VK_DOWN | KEXT }, // Cursor abajo + { 0x51, VK_NEXT | KEXT }, // Tecla Av pag + { 0x52, VK_INSERT | KEXT }, // Tecla insertar + { 0x53, VK_DELETE | KEXT }, // Tecla deletear + { 0x5B, VK_LWIN | KEXT }, // Tecla windows izquierda + { 0x5C, VK_RWIN | KEXT }, // Tecla windows derecha + { 0x5D, VK_APPS | KEXT }, // Tecla menu aplicacion derecha + { 0x5F, VK_SLEEP | KEXT }, // Tecla Sleep + { 0x65, VK_BROWSER_SEARCH | KEXT }, // Pagina de búsqueda en el navegador de internet + { 0x66, VK_BROWSER_FAVORITES | KEXT }, // Favoritos, tengo que esperar a que el tcp/ip + { 0x67, VK_BROWSER_REFRESH | KEXT }, // Refrescar el navegador de internet + { 0x68, VK_BROWSER_STOP | KEXT }, // Stop en el navegador de internet + { 0x69, VK_BROWSER_FORWARD | KEXT }, // Adelante en el navegador de internet + { 0x6A, VK_BROWSER_BACK | KEXT }, // Atrás en el navegador de internet + { 0x6B, VK_LAUNCH_APP1 | KEXT }, // Tecla Mi pc + { 0x6C, VK_LAUNCH_MAIL | KEXT }, // Abrir programa de e-mail + { 0x6D, VK_LAUNCH_MEDIA_SELECT | KEXT }, // Abrir reproductor multimedia + { 0x1C, VK_RETURN | KEXT }, // La tecla de intro + { 0x46, VK_CANCEL | KEXT }, // Tecla escape + { 0, 0 }, +}; + + +ROSDATA VSC_VK extcode1_to_vk[] = { + { 0, 0 }, +}; + +ROSDATA VK_TO_BIT modifier_keys[] = { + { VK_SHIFT, KSHIFT }, + { VK_CONTROL, KCTRL }, + { VK_MENU, KALT }, + { 0, 0 } +}; + +ROSDATA MODIFIERS modifier_bits = { + modifier_keys, + 6, + { 0, 1, 2, 4, SHFT_INVALID, SHFT_INVALID, 3 } +/* NONE, SHIFT, CTRL, CTRL+SHIFT, ALT */ +}; + +#define NOCAPS 0 +#define CAPS KSHIFT /* Caps -> shift */ + +ROSDATA VK_TO_WCHARS2 key_to_chars_2mod[] = { + /* Normal vs Shifted */ + /* The numbers */ + //Del 1 al 5 tienen tres estados + { '4', NOCAPS, {'4', '$'} }, + { '5', NOCAPS, {'5', '%'} }, + //El 6 tiene 3 estados + { '7', NOCAPS, {'7', '/'} }, + { '8', NOCAPS, {'8', '('} }, + { '9', NOCAPS, {'9', ')'} }, + { '0', NOCAPS, {'0', '='} }, + /* First letter row */ + { 'Q', CAPS, {'q', 'Q'} }, + { 'W', CAPS, {'w', 'W'} }, + //La E tiene 3 estados + { 'R', CAPS, {'r', 'R'} }, + { 'T', CAPS, {'t', 'T'} }, + { 'Y', CAPS, {'y', 'Y'} }, + { 'U', CAPS, {'u', 'U'} }, + { 'I', CAPS, {'i', 'I'} }, + { 'O', CAPS, {'o', 'O'} }, + { 'P', CAPS, {'p', 'P'} }, + /* Second letter row */ + { 'A', CAPS, {'a', 'A'} }, + { 'S', CAPS, {'s', 'S'} }, + { 'D', CAPS, {'d', 'D'} }, + { 'F', CAPS, {'f', 'F'} }, + { 'G', CAPS, {'g', 'G'} }, + { 'H', CAPS, {'h', 'H'} }, + { 'J', CAPS, {'j', 'J'} }, + { 'K', CAPS, {'k', 'K'} }, + { 'L', CAPS, {'l', 'L'} }, + { VK_OEM_3, CAPS, {0x00F1, 0x00D1} }, // ñÑ + /* Third letter row */ + { 'Z', CAPS, {'z', 'Z'} }, + { 'X', CAPS, {'x', 'X'} }, + { 'C', CAPS, {'c', 'C'} }, + { 'V', CAPS, {'v', 'V'} }, + { 'B', CAPS, {'b', 'B'} }, + { 'N', CAPS, {'n', 'N'} }, + { 'M', CAPS, {'m', 'M'} }, + + /* Specials */ + /* Ctrl-_ generates ES */ + { VK_OEM_6 ,NOCAPS, {0x00a1, 0x00bf} }, // ¡¿ + { VK_OEM_4 ,NOCAPS, {0x0027, '?'} }, //'? + { VK_OEM_COMMA ,NOCAPS, {',', ';'} }, + { VK_OEM_PERIOD ,NOCAPS, {'.', ':'} }, + { VK_OEM_MINUS ,NOCAPS, {'-', '_'} }, + { VK_OEM_102 ,NOCAPS, {'<', '>'} }, + + /* Keys that do not have shift states */ + { VK_TAB, NOCAPS, {'\t', '\t'} }, + { VK_ADD, NOCAPS, {'+', '+'} }, + { VK_SUBTRACT, NOCAPS, {'-', '-'} }, + { VK_MULTIPLY, NOCAPS, {'*', '*'} }, + { VK_DIVIDE, NOCAPS, {'/', '/'} }, + { VK_ESCAPE, NOCAPS, {'\x1b','\x1b'} }, + { VK_SPACE, NOCAPS, {' ', ' '} }, + { 0, 0 } +}; + + +ROSDATA VK_TO_WCHARS3 key_to_chars_3mod[] = { + /* Normal, Shifted, Ctrl */ + /* Legacy (telnet-style) ascii escapes */ + { VK_RETURN, NOCAPS, {'\r', '\r', '\n'} }, + { 0,0 } +}; + + +ROSDATA VK_TO_WCHARS4 key_to_chars_4mod[] = { +/* Normal, shifted, control, Alt+Gr */ + { '1', NOCAPS, {'1', '!', WCH_NONE, 0x00a6} }, // 1!| + { '2', NOCAPS, {'2', '"', WCH_NONE, '@'} }, // 2"@ + { '3', NOCAPS, {'3', 0x00B7, WCH_NONE, '#'} }, // 3·# + { '6', NOCAPS, {'6', '&', WCH_NONE, 0x00AC} }, // 6&¬ + { 'E', CAPS, {'e', 'E', WCH_NONE, 0x20AC} }, // eE€ + { VK_OEM_PLUS, NOCAPS, {'+', '*', WCH_NONE, 0x005d} }, // +*] + { VK_OEM_2, NOCAPS, {0x00e7, 0x00c7, WCH_NONE, '}'} }, // çÇ} + + { VK_OEM_7, NOCAPS, {WCH_DEAD, WCH_DEAD, WCH_NONE, '{'} }, // ´¨{ + { VK_EMPTY, NOCAPS, {0xB4, 0xA8, WCH_NONE, WCH_NONE} }, // ´¨{ + + { VK_OEM_1, NOCAPS, {WCH_DEAD, WCH_DEAD, WCH_NONE, 0x5B} }, // `^[ + { VK_EMPTY, NOCAPS, {0x60, 0x5e, WCH_NONE, WCH_NONE} }, // `^[ + + { VK_OEM_5, NOCAPS, {0x00BA, 0x00AA, WCH_NONE, 0x005c} }, // çÇ} + { 0, 0 } +}; + + + +ROSDATA VK_TO_WCHARS1 keypad_numbers[] = { + { VK_NUMPAD0, 0, {'0'} }, + { VK_NUMPAD1, 0, {'1'} }, + { VK_NUMPAD2, 0, {'2'} }, + { VK_NUMPAD3, 0, {'3'} }, + { VK_NUMPAD4, 0, {'4'} }, + { VK_NUMPAD5, 0, {'5'} }, + { VK_NUMPAD6, 0, {'6'} }, + { VK_NUMPAD7, 0, {'7'} }, + { VK_NUMPAD8, 0, {'8'} }, + { VK_NUMPAD9, 0, {'9'} }, + { VK_DECIMAL, 0, {'.'} }, + { VK_BACK, 0, {'\010'} }, + { 0,0 } +}; + + +#define vk_master(n,x) { (PVK_TO_WCHARS1)x, n, sizeof(x[0]) } + + +ROSDATA VK_TO_WCHAR_TABLE vk_to_wchar_master_table[] = { + vk_master(1,keypad_numbers), + vk_master(2,key_to_chars_2mod), + vk_master(3,key_to_chars_3mod), + vk_master(4,key_to_chars_4mod), + { 0,0,0 } +}; + +#define DEADTRANS(ch, accent, comp, flags) MAKELONG(ch, accent), comp, flags //no funciona +ROSDATA DEADKEY deadkey[] = +{ + //*´* + { DEADTRANS(L'a', 0xb4, 0xE1, 0x00) }, // letra a con ´ + { DEADTRANS(L'A', 0xb4, 0xC1, 0x00) }, // letra A con ´ + { DEADTRANS(L'e', 0xb4, 0xE9, 0x00) }, // letra e con ´ + { DEADTRANS(L'E', 0xb4, 0xC9, 0x00) }, // letra E con ´ + { DEADTRANS(L'i', 0xb4, 0xED, 0x00) }, // letra i con ´ + { DEADTRANS(L'I', 0xb4, 0xCD, 0x00) }, // letra I con ´ + { DEADTRANS(L'o', 0xb4, 0xF3, 0x00) }, // letra o con ´ + { DEADTRANS(L'O', 0xb4, 0xD3, 0x00) }, // letra O con ´ + { DEADTRANS(L'u', 0xb4, 0xFA, 0x00) }, // letra u con ´ + { DEADTRANS(L'U', 0xb4, 0xDA, 0x00) }, // letra U con ´ + //*`* + { DEADTRANS(L'a', 0x60, 0xE0, 0x00) }, // letra a con ` + { DEADTRANS(L'A', 0x60, 0xC0, 0x00) }, // letra A con ` + { DEADTRANS(L'e', 0x60, 0xE8, 0x00) }, // letra e con ` + { DEADTRANS(L'E', 0x60, 0xC8, 0x00) }, // letra E con ` + { DEADTRANS(L'i', 0x60, 0xEC, 0x00) }, // letra i con ` + { DEADTRANS(L'I', 0x60, 0xCC, 0x00) }, // letra I con ` + { DEADTRANS(L'o', 0x60, 0xF2, 0x00) }, // letra o con ` + { DEADTRANS(L'O', 0x60, 0xD2, 0x00) }, // letra O con ` + { DEADTRANS(L'u', 0x60, 0xF9, 0x00) }, // letra u con ` + { DEADTRANS(L'U', 0x60, 0xD9, 0x00) }, // letra U con ` + //*^* + { DEADTRANS(L'a', 0x5E, 0xE2, 0x00) }, // letra a con ^ + { DEADTRANS(L'A', 0x5E, 0xC2, 0x00) }, // letra A con ^ + { DEADTRANS(L'e', 0x5E, 0xEA, 0x00) }, // letra e con ^ + { DEADTRANS(L'E', 0x5E, 0xCA, 0x00) }, // letra E con ^ + { DEADTRANS(L'i', 0x5E, 0xEE, 0x00) }, // letra i con ^ + { DEADTRANS(L'I', 0x5E, 0xCE, 0x00) }, // letra I con ^ + { DEADTRANS(L'o', 0x5E, 0xF4, 0x00) }, // letra o con ^ + { DEADTRANS(L'O', 0x5E, 0xD4, 0x00) }, // letra O con ^ + { DEADTRANS(L'u', 0x5E, 0xFB, 0x00) }, // letra u con ^ + { DEADTRANS(L'U', 0x5E, 0xDB, 0x00) }, // letra U con ^ + //*¨* + { DEADTRANS(L'a', 0xA8, 0xE4, 0x00) }, // letra a con ¨ + { DEADTRANS(L'A', 0xA8, 0xC4, 0x00) }, // letra A con ¨ + { DEADTRANS(L'e', 0xA8, 0xEB, 0x00) }, // letra e con ¨ + { DEADTRANS(L'E', 0xA8, 0xCB, 0x00) }, // letra E con ¨ + { DEADTRANS(L'i', 0xA8, 0xEF, 0x00) }, // letra i con ¨ + { DEADTRANS(L'I', 0xA8, 0xCF, 0x00) }, // letra I con ¨ + { DEADTRANS(L'o', 0xA8, 0xF6, 0x00) }, // letra o con ¨ + { DEADTRANS(L'O', 0xA8, 0xD6, 0x00) }, // letra O con ¨ + { DEADTRANS(L'u', 0xA8, 0xFC, 0x00) }, // letra u con ¨ + { DEADTRANS(L'U', 0xA8, 0xDC, 0x00) }, // letra U con ¨ + { 0, 0, 0} +}; + +ROSDATA VSC_LPWSTR key_names[] = { + { 0x00, L"" }, + { 0x01, L"Escape" }, + { 0x0e, L"Borrar" }, + { 0x0f, L"Tabulador" }, + { 0x1c, L"Intro" }, + { 0x1d, L"Ctrl" }, + { 0x2a, L"Shift" }, + { 0x36, L"Shift derecho" }, + { 0x37, L"* numerico" }, + { 0x38, L"Alt" }, + { 0x39, L"Espacio" }, + { 0x3a, L"Bloqueo mayusculas" }, + { 0x3b, L"F1" }, + { 0x3c, L"F2" }, + { 0x3d, L"F3" }, + { 0x3e, L"F4" }, + { 0x3f, L"F5" }, + { 0x40, L"F6" }, + { 0x41, L"F7" }, + { 0x42, L"F8" }, + { 0x43, L"F9" }, + { 0x44, L"F10" }, + { 0x45, L"Pausa" }, + { 0x46, L"Bloqueo de scroll" }, + { 0x47, L"Num 7" }, + { 0x48, L"Num 8" }, + { 0x49, L"Num 9" }, + { 0x4a, L"Num -" }, + { 0x4b, L"Num 4" }, + { 0x4c, L"Num 5" }, + { 0x4d, L"Num 6" }, + { 0x4e, L"Num +" }, + { 0x4f, L"Num 1" }, + { 0x50, L"Num 2" }, + { 0x51, L"Num 3" }, + { 0x52, L"Num 0" }, + { 0x53, L"Borrardo numerico" }, + { 0x54, L"Peticion de sistema" }, + { 0x57, L"F11" }, + { 0x58, L"F12" }, + { 0x7c, L"F13" }, + { 0x7d, L"F14" }, + { 0x7e, L"F15" }, + { 0x7f, L"F16" }, + { 0x80, L"F17" }, + { 0x81, L"F18" }, + { 0x82, L"F19" }, + { 0x83, L"F20" }, + { 0x84, L"F21" }, + { 0x85, L"F22" }, + { 0x86, L"F23" }, + { 0x87, L"F24" }, + { 0, NULL }, +}; + +ROSDATA VSC_LPWSTR extended_key_names[] = { + { 0x1c, L"Intro numerico" }, + { 0x1d, L"Ctrl derecho" }, + { 0x35, L"/ numerica" }, + { 0x37, L"Imprimir pantalla" }, + { 0x38, L"Alt derecho" }, + { 0x45, L"Bloqueo numerico" }, + { 0x46, L"Interrumpir" }, + { 0x47, L"Inicio" }, + { 0x48, L"Arriba" }, + { 0x49, L"Subir pagina" }, + { 0x4b, L"Izquierda" }, + { 0x4c, L"Centrar" }, + { 0x4d, L"Derecha" }, + { 0x4f, L"Fin" }, + { 0x50, L"Abajo" }, + { 0x51, L"Bajar pagina" }, + { 0x52, L"Insertar" }, + { 0x53, L"Borrar" }, + { 0x54, L"<ReactOS>" }, + { 0x55, L"Ayuda" }, + { 0x5b, L"Windows izquierda" }, + { 0x5c, L"Windows derecha" }, + { 0, NULL }, +}; + +ROSDATA DEADKEY_LPWSTR dead_key_names[] = { + L"\x00b4" L"Agudo", + L"\x0060" L"Grave", + L"\x005e" L"Circunflejo", + L"\x00A8" L"Dieresis", + NULL +}; + + +/* Finally, the master table */ +ROSDATA KBDTABLES keyboard_layout_table = { + + /* modifier assignments */ + &modifier_bits, + + /* character from vk tables */ + vk_to_wchar_master_table, + + /* diacritical marks -- currently implemented by wine code */ + /* Spanish have severals */ + deadkey, + + /* Key names */ + (VSC_LPWSTR *)key_names, + (VSC_LPWSTR *)extended_key_names, + dead_key_names, + /* Dead key names */ + + /* scan code to virtual key maps */ + scancode_to_vk, + sizeof(scancode_to_vk) / sizeof(scancode_to_vk[0]), + extcode0_to_vk, + extcode1_to_vk, + + MAKELONG(0,1), /* Version 1.0 */ + + /* Ligatures -- Spanish doesn't have any */ + 0, + 0, + NULL +}; + + +PKBDTABLES STDCALL KbdLayerDescriptor() { + return &keyboard_layout_table; +} diff --git a/reactos/lib/kbdru/kbdru.c b/reactos/lib/kbdru/kbdru.c index 49bc74486d5..8b295db0560 100644 --- a/reactos/lib/kbdru/kbdru.c +++ b/reactos/lib/kbdru/kbdru.c @@ -1,406 +1,406 @@ -/* - * ReactOS Russian ASCII Keyboard layout - * Copyright (C) 2005 ReactOS - * Author: Aleksey Bragin - * License: LGPL, see: LGPL.txt - * - * Thanks to: http://www.barcodeman.com/altek/mule/scandoc.php - * and http://win.tue.nl/~aeb/linux/kbd/scancodes-1.html - */ - -#include <windows.h> -#include <internal/kbd.h> - -#ifdef _M_IA64 -#define ROSDATA static __declspec(allocate(".data")) -#else -#ifdef _MSC_VER -#pragma data_seg(".data") -#define ROSDATA static -#else -#define ROSDATA static __attribute__((section(".data"))) -#endif -#endif - -#define VK_EMPTY 0xff /* The non-existent VK */ -#define KSHIFT 0x001 /* Shift modifier */ -#define KCTRL 0x002 /* Ctrl modifier */ -#define KALT 0x004 /* Alt modifier */ -#define KEXT 0x100 /* Extended key code */ -#define KMULTI 0x200 /* Multi-key */ -#define KSPEC 0x400 /* Special key */ -#define KNUMP 0x800 /* Number-pad */ -#define KNUMS 0xc00 /* Special + number pad */ -#define KMEXT 0x300 /* Multi + ext */ - -#define SHFT_INVALID 0x0F - -ROSDATA USHORT scancode_to_vk[] = { - /* Numbers Row */ - /* - 00 - */ - /* 1 ... 2 ... 3 ... 4 ... */ - VK_EMPTY, VK_ESCAPE, '1', '2', - '3', '4', '5', '6', - '7', '8', '9', '0', - VK_OEM_MINUS, VK_OEM_PLUS, VK_BACK, - /* - 0f - */ - /* First Letters Row */ - VK_TAB, 'Q', 'W', 'E', - 'R', 'T', 'Y', 'U', - 'I', 'O', 'P', - VK_OEM_4, VK_OEM_6, VK_RETURN, - /* - 1d - */ - /* Second Letters Row */ - VK_LCONTROL, - 'A', 'S', 'D', 'F', - 'G', 'H', 'J', 'K', - 'L', VK_OEM_1, VK_OEM_7, VK_OEM_3, - VK_LSHIFT, VK_OEM_5, - /* - 2c - */ - /* Third letters row */ - 'Z', 'X', 'C', 'V', - 'B', 'N', 'M', VK_OEM_COMMA, - VK_OEM_PERIOD,VK_OEM_2, VK_RSHIFT | KEXT, - /* - 37 - */ - /* Bottom Row */ - 0x26a, VK_LMENU, VK_SPACE, VK_CAPITAL, - - /* - 3b - */ - /* F-Keys */ - VK_F1, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, - VK_F7, VK_F8, VK_F9, VK_F10, - /* - 45 - */ - /* Locks */ - VK_NUMLOCK | KMEXT, - VK_SCROLL | KMULTI, - /* - 47 - */ - /* Number-Pad */ - VK_HOME | KNUMS, VK_UP | KNUMS, VK_PRIOR | KNUMS, VK_SUBTRACT, - VK_LEFT | KNUMS, VK_CLEAR | KNUMS, VK_RIGHT | KNUMS, VK_ADD, - VK_END | KNUMS, VK_DOWN | KNUMS, VK_NEXT | KNUMS, - VK_INSERT | KNUMS, VK_DELETE | KNUMS, - /* - 54 - */ - /* Presumably PrtSc */ - VK_SNAPSHOT, - /* - 55 - */ - /* Oddities, and the remaining standard F-Keys */ - VK_EMPTY, VK_OEM_102, VK_F11, VK_F12, - /* - 59 - */ - VK_CLEAR, VK_OEM_WSCTRL,VK_OEM_FINISH,VK_OEM_JUMP, VK_EREOF, /* EREOF */ - VK_OEM_BACKTAB, VK_OEM_AUTO, VK_EMPTY, VK_ZOOM, /* ZOOM */ - VK_HELP, - /* - 64 - */ - /* Even more F-Keys (for example, NCR keyboards from the early 90's) */ - VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, VK_F19, VK_F20, - VK_F21, VK_F22, VK_F23, - /* - 6f - */ - /* Not sure who uses these codes */ - VK_OEM_PA3, VK_EMPTY, VK_OEM_RESET, - /* - 72 - */ - VK_EMPTY, 0xc1, VK_EMPTY, VK_EMPTY, - /* - 76 - */ - /* One more f-key */ - VK_F24, - /* - 77 - */ - VK_EMPTY, VK_EMPTY, VK_EMPTY, VK_EMPTY, - VK_OEM_PA1, VK_TAB, 0xc2, 0, /* PA1 */ - 0, - /* - 80 - */ - 0 -}; - -ROSDATA VSC_VK extcode0_to_vk[] = { - { 0x10, VK_MEDIA_PREV_TRACK | KEXT }, - { 0x19, VK_MEDIA_NEXT_TRACK | KEXT }, - { 0x1D, VK_RCONTROL | KEXT }, - { 0x20, VK_VOLUME_MUTE | KEXT }, - { 0x21, VK_LAUNCH_APP2 | KEXT }, - { 0x22, VK_MEDIA_PLAY_PAUSE | KEXT }, - { 0x24, VK_MEDIA_STOP | KEXT }, - { 0x2E, VK_VOLUME_DOWN | KEXT }, - { 0x30, VK_VOLUME_UP | KEXT }, - { 0x32, VK_BROWSER_HOME | KEXT }, - { 0x35, VK_DIVIDE | KEXT }, - { 0x37, VK_SNAPSHOT | KEXT }, - { 0x38, VK_RMENU | KEXT }, - { 0x47, VK_HOME | KEXT }, - { 0x48, VK_UP | KEXT }, - { 0x49, VK_PRIOR | KEXT }, - { 0x4B, VK_LEFT | KEXT }, - { 0x4D, VK_RIGHT | KEXT }, - { 0x4F, VK_END | KEXT }, - { 0x50, VK_DOWN | KEXT }, - { 0x51, VK_NEXT | KEXT }, - { 0x52, VK_INSERT | KEXT }, - { 0x53, VK_DELETE | KEXT }, - { 0x5B, VK_LWIN | KEXT }, - { 0x5C, VK_RWIN | KEXT }, - { 0x5D, VK_APPS | KEXT }, - { 0x5F, VK_SLEEP | KEXT }, - { 0x65, VK_BROWSER_SEARCH | KEXT }, - { 0x66, VK_BROWSER_FAVORITES | KEXT }, - { 0x67, VK_BROWSER_REFRESH | KEXT }, - { 0x68, VK_BROWSER_STOP | KEXT }, - { 0x69, VK_BROWSER_FORWARD | KEXT }, - { 0x6A, VK_BROWSER_BACK | KEXT }, - { 0x6B, VK_LAUNCH_APP1 | KEXT }, - { 0x6C, VK_LAUNCH_MAIL | KEXT }, - { 0x6D, VK_LAUNCH_MEDIA_SELECT | KEXT }, - { 0x1C, VK_RETURN | KEXT }, - { 0x46, VK_CANCEL | KEXT }, - { 0, 0 }, -}; - -ROSDATA VSC_VK extcode1_to_vk[] = { - { 0x1d, VK_PAUSE}, - { 0, 0 }, -}; - -ROSDATA VK_TO_BIT modifier_keys[] = { - { VK_SHIFT, KSHIFT }, - { VK_CONTROL, KCTRL }, - { VK_MENU, KALT }, - { 0, 0 } -}; - -ROSDATA MODIFIERS modifier_bits = { - modifier_keys, - 3, - { 0, 1, 2, 3, 0, 0, 0xC0 } /* Modifier bit order, NONE, SHIFT, CTRL, ALT, MENU, SHIFT + MENU, CTRL + MENU */ -}; - -#define NOCAPS 0 -#define CAPS KSHIFT /* Caps -> shift */ - -ROSDATA VK_TO_WCHARS2 key_to_chars_2mod[] = { - {VK_OEM_3, CAPS, {0x451, 0x401} }, - { '1', NOCAPS, {'1', '!'} }, - { '3', NOCAPS, {'3', 0x2116} }, - { '4', NOCAPS, {'4', ';'} }, - { '5', NOCAPS, {'5', '%'} }, - { '7', NOCAPS, {'7', '?'} }, - { '8', NOCAPS, {'8', '*'} }, - { '9', NOCAPS, {'9', '('} }, - { '0', NOCAPS, {'0', ')'} }, - { VK_OEM_PLUS, NOCAPS, {'=', '+'} }, - - /* First letter row */ - { 'Q', CAPS, {0x439, 0x419} }, - { 'W', CAPS, {0x446, 0x426} }, - { 'E', CAPS, {0x443, 0x423} }, - { 'R', CAPS, {0x43a, 0x41a} }, - { 'T', CAPS, {0x435, 0x415} }, - { 'Y', CAPS, {0x43d, 0x41d} }, - { 'U', CAPS, {0x433, 0x413} }, - { 'I', CAPS, {0x448, 0x428} }, - { 'O', CAPS, {0x449, 0x429} }, - { 'P', CAPS, {0x437, 0x417} }, - { VK_OEM_4, CAPS, {0x445, 0x425} }, - { VK_OEM_6, CAPS, {0x44a, 0x42a} }, - - /* Second letter row */ - { 'A', CAPS, {0x444, 0x424} }, - { 'S', CAPS, {0x44b, 0x42b} }, - { 'D', CAPS, {0x432, 0x412} }, - { 'F', CAPS, {0x430, 0x410} }, - { 'G', CAPS, {0x43f, 0x41f} }, - { 'H', CAPS, {0x440, 0x420} }, - { 'J', CAPS, {0x43e, 0x41e} }, - { 'K', CAPS, {0x43b, 0x41b} }, - { 'L', CAPS, {0x434, 0x414} }, - { VK_OEM_1, CAPS, {0x436, 0x416} }, - { VK_OEM_7, CAPS, {0x44d, 0x42d} }, - - /* Third letter row */ - { 'Z', CAPS, {0x44f, 0x42f} }, - { 'X', CAPS, {0x447, 0x427} }, - { 'C', CAPS, {0x441, 0x421} }, - { 'V', CAPS, {0x43c, 0x41c} }, - { 'B', CAPS, {0x438, 0x418} }, - { 'N', CAPS, {0x442, 0x422} }, - { 'M', CAPS, {0x44c, 0x42c} }, - { VK_OEM_COMMA,CAPS, {0x431, 0x411} }, - { VK_OEM_PERIOD,CAPS, {0x44e, 0x42e} }, - { VK_OEM_2, NOCAPS, {'.', ','} }, - - /* Specials */ - { 0x6e, NOCAPS, {',', ','} }, - { VK_TAB, NOCAPS, {9, 9} }, - { VK_ADD, NOCAPS, {'+', '+'} }, - { VK_DIVIDE, NOCAPS, {'/', '/'} }, - { VK_MULTIPLY, NOCAPS, {'*', '*'} }, - { VK_SUBTRACT, NOCAPS, {'-', '-'} }, - { 0, 0 } -}; - -ROSDATA VK_TO_WCHARS3 key_to_chars_3mod[] = { - /* Normal, Shifted, Ctrl */ - /* Legacy (telnet-style) ascii escapes */ - { VK_OEM_5, NOCAPS, {0x5c, 0x2f, 0x1c} }, - { VK_OEM_102, NOCAPS, {0x5c, 0x2f, 0x1c} }, - { VK_BACK, NOCAPS, {0x8, 0x8, 0x7f} }, - { VK_ESCAPE, NOCAPS, {0x1b, 0x1b, 0x1b} }, - { VK_RETURN, NOCAPS, {'\r', '\r', '\n'} }, - { VK_SPACE, NOCAPS, {' ', ' ', ' '} }, - { VK_CANCEL, NOCAPS, {0x03, 0x03, 0x03} }, - { 0,0 } -}; - -ROSDATA VK_TO_WCHARS4 key_to_chars_4mod[] = { - /* Normal, Shifted, Ctrl, Ctrl-Alt */ - /* Legacy Ascii generators */ - { '2', NOCAPS, {'2', '\"', WCH_NONE, 0} }, - { '6', NOCAPS, {'6', ':', WCH_NONE, 0x001e} }, - { VK_OEM_MINUS, NOCAPS, {0x2d, '_', WCH_NONE, 0x001f} }, // different '-' - { 0, 0 } -}; - -ROSDATA VK_TO_WCHARS1 keypad_numbers[] = { - { VK_NUMPAD0, 0, {'0'} }, - { VK_NUMPAD1, 0, {'1'} }, - { VK_NUMPAD2, 0, {'2'} }, - { VK_NUMPAD3, 0, {'3'} }, - { VK_NUMPAD4, 0, {'4'} }, - { VK_NUMPAD5, 0, {'5'} }, - { VK_NUMPAD6, 0, {'6'} }, - { VK_NUMPAD7, 0, {'7'} }, - { VK_NUMPAD8, 0, {'8'} }, - { VK_NUMPAD9, 0, {'9'} }, - { 0,0 } -}; - -#define vk_master(n,x) { (PVK_TO_WCHARS1)x, n, sizeof(x[0]) } - -ROSDATA VK_TO_WCHAR_TABLE vk_to_wchar_master_table[] = { - vk_master(3,key_to_chars_3mod), - vk_master(4,key_to_chars_4mod), - vk_master(2,key_to_chars_2mod), - vk_master(1,keypad_numbers), - { 0,0,0 } -}; - -ROSDATA VSC_LPWSTR key_names[] = { - { 0x01, L"Esc" }, - { 0x0e, L"Backspace" }, - { 0x0f, L"Tab" }, - { 0x1c, L"Enter" }, - { 0x1d, L"Ctrl" }, - { 0x2a, L"Shift" }, - { 0x36, L"Right Shift" }, - { 0x37, L"Num *" }, - { 0x38, L"Alt" }, - { 0x39, L"Space" }, - { 0x3a, L"Caps Lock" }, - { 0x3b, L"F1" }, - { 0x3c, L"F2" }, - { 0x3d, L"F3" }, - { 0x3e, L"F4" }, - { 0x3f, L"F5" }, - { 0x40, L"F6" }, - { 0x41, L"F7" }, - { 0x42, L"F8" }, - { 0x43, L"F9" }, - { 0x44, L"F10" }, - { 0x45, L"Pause" }, - { 0x46, L"Scroll Lock" }, - { 0x47, L"Num 7" }, - { 0x48, L"Num 8" }, - { 0x49, L"Num 9" }, - { 0x4a, L"Num -" }, - { 0x4b, L"Num 4" }, - { 0x4c, L"Num 5" }, - { 0x4d, L"Num 6" }, - { 0x4e, L"Num +" }, - { 0x4f, L"Num 1" }, - { 0x50, L"Num 2" }, - { 0x51, L"Num 3" }, - { 0x52, L"Num 0" }, - { 0x53, L"Num Del" }, - { 0x54, L"Sys Req" }, - { 0x57, L"F11" }, - { 0x58, L"F12" }, - { 0x7c, L"F13" }, - { 0x7d, L"F14" }, - { 0x7e, L"F15" }, - { 0x7f, L"F16" }, - { 0x80, L"F17" }, - { 0x81, L"F18" }, - { 0x82, L"F19" }, - { 0x83, L"F20" }, - { 0x84, L"F21" }, - { 0x85, L"F22" }, - { 0x86, L"F23" }, - { 0x87, L"F24" }, - { 0, NULL } -}; - -ROSDATA VSC_LPWSTR extended_key_names[] = { - { 0x1c, L"Num Enter" }, - { 0x1d, L"Right Control" }, - { 0x35, L"Num /" }, - { 0x37, L"Prnt Scrn" }, - { 0x38, L"Right Alt" }, - { 0x45, L"Num Lock" }, - { 0x46, L"Break" }, - { 0x47, L"Home" }, - { 0x48, L"Up" }, - { 0x49, L"Page Up" }, - { 0x4b, L"Left" }, -//{ 0x4c, L"Center" }, - { 0x4d, L"Right" }, - { 0x4f, L"End" }, - { 0x50, L"Down" }, - { 0x51, L"Page Down" }, - { 0x52, L"Insert" }, - { 0x53, L"Delete" }, - { 0x54, L"<ReactOS>" }, - { 0x56, L"Help" }, - { 0x5b, L"Left <ReactOS>" }, - { 0x5c, L"Right <ReactOS>" }, - { 0x5d, L"Application" }, - { 0, NULL } -}; - -/* Finally, the master table */ -ROSDATA KBDTABLES keyboard_layout_table = { - /* modifier assignments */ - &modifier_bits, - - /* character from vk tables */ - vk_to_wchar_master_table, - - /* diacritical marks */ - NULL, - - /* Key names */ - (VSC_LPWSTR *)key_names, - (VSC_LPWSTR *)extended_key_names, - NULL, /* Dead key names */ - - /* scan code to virtual key maps */ - scancode_to_vk, - sizeof(scancode_to_vk) / sizeof(scancode_to_vk[0]), - extcode0_to_vk, - extcode1_to_vk, - - MAKELONG(0,1), /* Version 1.0 */ - - /* Ligatures -- Russian doesn't have any */ - 0, - 0, - NULL -}; - -PKBDTABLES STDCALL KbdLayerDescriptor() { - return &keyboard_layout_table; -} - -INT STDCALL -DllMain( - PVOID hinstDll, - ULONG dwReason, - PVOID reserved) -{ - return 1; -} - +/* + * ReactOS Russian ASCII Keyboard layout + * Copyright (C) 2005 ReactOS + * Author: Aleksey Bragin + * License: LGPL, see: LGPL.txt + * + * Thanks to: http://www.barcodeman.com/altek/mule/scandoc.php + * and http://win.tue.nl/~aeb/linux/kbd/scancodes-1.html + */ + +#include <windows.h> +#include <internal/kbd.h> + +#ifdef _M_IA64 +#define ROSDATA static __declspec(allocate(".data")) +#else +#ifdef _MSC_VER +#pragma data_seg(".data") +#define ROSDATA static +#else +#define ROSDATA static __attribute__((section(".data"))) +#endif +#endif + +#define VK_EMPTY 0xff /* The non-existent VK */ +#define KSHIFT 0x001 /* Shift modifier */ +#define KCTRL 0x002 /* Ctrl modifier */ +#define KALT 0x004 /* Alt modifier */ +#define KEXT 0x100 /* Extended key code */ +#define KMULTI 0x200 /* Multi-key */ +#define KSPEC 0x400 /* Special key */ +#define KNUMP 0x800 /* Number-pad */ +#define KNUMS 0xc00 /* Special + number pad */ +#define KMEXT 0x300 /* Multi + ext */ + +#define SHFT_INVALID 0x0F + +ROSDATA USHORT scancode_to_vk[] = { + /* Numbers Row */ + /* - 00 - */ + /* 1 ... 2 ... 3 ... 4 ... */ + VK_EMPTY, VK_ESCAPE, '1', '2', + '3', '4', '5', '6', + '7', '8', '9', '0', + VK_OEM_MINUS, VK_OEM_PLUS, VK_BACK, + /* - 0f - */ + /* First Letters Row */ + VK_TAB, 'Q', 'W', 'E', + 'R', 'T', 'Y', 'U', + 'I', 'O', 'P', + VK_OEM_4, VK_OEM_6, VK_RETURN, + /* - 1d - */ + /* Second Letters Row */ + VK_LCONTROL, + 'A', 'S', 'D', 'F', + 'G', 'H', 'J', 'K', + 'L', VK_OEM_1, VK_OEM_7, VK_OEM_3, + VK_LSHIFT, VK_OEM_5, + /* - 2c - */ + /* Third letters row */ + 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', VK_OEM_COMMA, + VK_OEM_PERIOD,VK_OEM_2, VK_RSHIFT | KEXT, + /* - 37 - */ + /* Bottom Row */ + 0x26a, VK_LMENU, VK_SPACE, VK_CAPITAL, + + /* - 3b - */ + /* F-Keys */ + VK_F1, VK_F2, VK_F3, VK_F4, VK_F5, VK_F6, + VK_F7, VK_F8, VK_F9, VK_F10, + /* - 45 - */ + /* Locks */ + VK_NUMLOCK | KMEXT, + VK_SCROLL | KMULTI, + /* - 47 - */ + /* Number-Pad */ + VK_HOME | KNUMS, VK_UP | KNUMS, VK_PRIOR | KNUMS, VK_SUBTRACT, + VK_LEFT | KNUMS, VK_CLEAR | KNUMS, VK_RIGHT | KNUMS, VK_ADD, + VK_END | KNUMS, VK_DOWN | KNUMS, VK_NEXT | KNUMS, + VK_INSERT | KNUMS, VK_DELETE | KNUMS, + /* - 54 - */ + /* Presumably PrtSc */ + VK_SNAPSHOT, + /* - 55 - */ + /* Oddities, and the remaining standard F-Keys */ + VK_EMPTY, VK_OEM_102, VK_F11, VK_F12, + /* - 59 - */ + VK_CLEAR, VK_OEM_WSCTRL,VK_OEM_FINISH,VK_OEM_JUMP, VK_EREOF, /* EREOF */ + VK_OEM_BACKTAB, VK_OEM_AUTO, VK_EMPTY, VK_ZOOM, /* ZOOM */ + VK_HELP, + /* - 64 - */ + /* Even more F-Keys (for example, NCR keyboards from the early 90's) */ + VK_F13, VK_F14, VK_F15, VK_F16, VK_F17, VK_F18, VK_F19, VK_F20, + VK_F21, VK_F22, VK_F23, + /* - 6f - */ + /* Not sure who uses these codes */ + VK_OEM_PA3, VK_EMPTY, VK_OEM_RESET, + /* - 72 - */ + VK_EMPTY, 0xc1, VK_EMPTY, VK_EMPTY, + /* - 76 - */ + /* One more f-key */ + VK_F24, + /* - 77 - */ + VK_EMPTY, VK_EMPTY, VK_EMPTY, VK_EMPTY, + VK_OEM_PA1, VK_TAB, 0xc2, 0, /* PA1 */ + 0, + /* - 80 - */ + 0 +}; + +ROSDATA VSC_VK extcode0_to_vk[] = { + { 0x10, VK_MEDIA_PREV_TRACK | KEXT }, + { 0x19, VK_MEDIA_NEXT_TRACK | KEXT }, + { 0x1D, VK_RCONTROL | KEXT }, + { 0x20, VK_VOLUME_MUTE | KEXT }, + { 0x21, VK_LAUNCH_APP2 | KEXT }, + { 0x22, VK_MEDIA_PLAY_PAUSE | KEXT }, + { 0x24, VK_MEDIA_STOP | KEXT }, + { 0x2E, VK_VOLUME_DOWN | KEXT }, + { 0x30, VK_VOLUME_UP | KEXT }, + { 0x32, VK_BROWSER_HOME | KEXT }, + { 0x35, VK_DIVIDE | KEXT }, + { 0x37, VK_SNAPSHOT | KEXT }, + { 0x38, VK_RMENU | KEXT }, + { 0x47, VK_HOME | KEXT }, + { 0x48, VK_UP | KEXT }, + { 0x49, VK_PRIOR | KEXT }, + { 0x4B, VK_LEFT | KEXT }, + { 0x4D, VK_RIGHT | KEXT }, + { 0x4F, VK_END | KEXT }, + { 0x50, VK_DOWN | KEXT }, + { 0x51, VK_NEXT | KEXT }, + { 0x52, VK_INSERT | KEXT }, + { 0x53, VK_DELETE | KEXT }, + { 0x5B, VK_LWIN | KEXT }, + { 0x5C, VK_RWIN | KEXT }, + { 0x5D, VK_APPS | KEXT }, + { 0x5F, VK_SLEEP | KEXT }, + { 0x65, VK_BROWSER_SEARCH | KEXT }, + { 0x66, VK_BROWSER_FAVORITES | KEXT }, + { 0x67, VK_BROWSER_REFRESH | KEXT }, + { 0x68, VK_BROWSER_STOP | KEXT }, + { 0x69, VK_BROWSER_FORWARD | KEXT }, + { 0x6A, VK_BROWSER_BACK | KEXT }, + { 0x6B, VK_LAUNCH_APP1 | KEXT }, + { 0x6C, VK_LAUNCH_MAIL | KEXT }, + { 0x6D, VK_LAUNCH_MEDIA_SELECT | KEXT }, + { 0x1C, VK_RETURN | KEXT }, + { 0x46, VK_CANCEL | KEXT }, + { 0, 0 }, +}; + +ROSDATA VSC_VK extcode1_to_vk[] = { + { 0x1d, VK_PAUSE}, + { 0, 0 }, +}; + +ROSDATA VK_TO_BIT modifier_keys[] = { + { VK_SHIFT, KSHIFT }, + { VK_CONTROL, KCTRL }, + { VK_MENU, KALT }, + { 0, 0 } +}; + +ROSDATA MODIFIERS modifier_bits = { + modifier_keys, + 3, + { 0, 1, 2, 3, 0, 0, 0xC0 } /* Modifier bit order, NONE, SHIFT, CTRL, ALT, MENU, SHIFT + MENU, CTRL + MENU */ +}; + +#define NOCAPS 0 +#define CAPS KSHIFT /* Caps -> shift */ + +ROSDATA VK_TO_WCHARS2 key_to_chars_2mod[] = { + {VK_OEM_3, CAPS, {0x451, 0x401} }, + { '1', NOCAPS, {'1', '!'} }, + { '3', NOCAPS, {'3', 0x2116} }, + { '4', NOCAPS, {'4', ';'} }, + { '5', NOCAPS, {'5', '%'} }, + { '7', NOCAPS, {'7', '?'} }, + { '8', NOCAPS, {'8', '*'} }, + { '9', NOCAPS, {'9', '('} }, + { '0', NOCAPS, {'0', ')'} }, + { VK_OEM_PLUS, NOCAPS, {'=', '+'} }, + + /* First letter row */ + { 'Q', CAPS, {0x439, 0x419} }, + { 'W', CAPS, {0x446, 0x426} }, + { 'E', CAPS, {0x443, 0x423} }, + { 'R', CAPS, {0x43a, 0x41a} }, + { 'T', CAPS, {0x435, 0x415} }, + { 'Y', CAPS, {0x43d, 0x41d} }, + { 'U', CAPS, {0x433, 0x413} }, + { 'I', CAPS, {0x448, 0x428} }, + { 'O', CAPS, {0x449, 0x429} }, + { 'P', CAPS, {0x437, 0x417} }, + { VK_OEM_4, CAPS, {0x445, 0x425} }, + { VK_OEM_6, CAPS, {0x44a, 0x42a} }, + + /* Second letter row */ + { 'A', CAPS, {0x444, 0x424} }, + { 'S', CAPS, {0x44b, 0x42b} }, + { 'D', CAPS, {0x432, 0x412} }, + { 'F', CAPS, {0x430, 0x410} }, + { 'G', CAPS, {0x43f, 0x41f} }, + { 'H', CAPS, {0x440, 0x420} }, + { 'J', CAPS, {0x43e, 0x41e} }, + { 'K', CAPS, {0x43b, 0x41b} }, + { 'L', CAPS, {0x434, 0x414} }, + { VK_OEM_1, CAPS, {0x436, 0x416} }, + { VK_OEM_7, CAPS, {0x44d, 0x42d} }, + + /* Third letter row */ + { 'Z', CAPS, {0x44f, 0x42f} }, + { 'X', CAPS, {0x447, 0x427} }, + { 'C', CAPS, {0x441, 0x421} }, + { 'V', CAPS, {0x43c, 0x41c} }, + { 'B', CAPS, {0x438, 0x418} }, + { 'N', CAPS, {0x442, 0x422} }, + { 'M', CAPS, {0x44c, 0x42c} }, + { VK_OEM_COMMA,CAPS, {0x431, 0x411} }, + { VK_OEM_PERIOD,CAPS, {0x44e, 0x42e} }, + { VK_OEM_2, NOCAPS, {'.', ','} }, + + /* Specials */ + { 0x6e, NOCAPS, {',', ','} }, + { VK_TAB, NOCAPS, {9, 9} }, + { VK_ADD, NOCAPS, {'+', '+'} }, + { VK_DIVIDE, NOCAPS, {'/', '/'} }, + { VK_MULTIPLY, NOCAPS, {'*', '*'} }, + { VK_SUBTRACT, NOCAPS, {'-', '-'} }, + { 0, 0 } +}; + +ROSDATA VK_TO_WCHARS3 key_to_chars_3mod[] = { + /* Normal, Shifted, Ctrl */ + /* Legacy (telnet-style) ascii escapes */ + { VK_OEM_5, NOCAPS, {0x5c, 0x2f, 0x1c} }, + { VK_OEM_102, NOCAPS, {0x5c, 0x2f, 0x1c} }, + { VK_BACK, NOCAPS, {0x8, 0x8, 0x7f} }, + { VK_ESCAPE, NOCAPS, {0x1b, 0x1b, 0x1b} }, + { VK_RETURN, NOCAPS, {'\r', '\r', '\n'} }, + { VK_SPACE, NOCAPS, {' ', ' ', ' '} }, + { VK_CANCEL, NOCAPS, {0x03, 0x03, 0x03} }, + { 0,0 } +}; + +ROSDATA VK_TO_WCHARS4 key_to_chars_4mod[] = { + /* Normal, Shifted, Ctrl, Ctrl-Alt */ + /* Legacy Ascii generators */ + { '2', NOCAPS, {'2', '\"', WCH_NONE, 0} }, + { '6', NOCAPS, {'6', ':', WCH_NONE, 0x001e} }, + { VK_OEM_MINUS, NOCAPS, {0x2d, '_', WCH_NONE, 0x001f} }, // different '-' + { 0, 0 } +}; + +ROSDATA VK_TO_WCHARS1 keypad_numbers[] = { + { VK_NUMPAD0, 0, {'0'} }, + { VK_NUMPAD1, 0, {'1'} }, + { VK_NUMPAD2, 0, {'2'} }, + { VK_NUMPAD3, 0, {'3'} }, + { VK_NUMPAD4, 0, {'4'} }, + { VK_NUMPAD5, 0, {'5'} }, + { VK_NUMPAD6, 0, {'6'} }, + { VK_NUMPAD7, 0, {'7'} }, + { VK_NUMPAD8, 0, {'8'} }, + { VK_NUMPAD9, 0, {'9'} }, + { 0,0 } +}; + +#define vk_master(n,x) { (PVK_TO_WCHARS1)x, n, sizeof(x[0]) } + +ROSDATA VK_TO_WCHAR_TABLE vk_to_wchar_master_table[] = { + vk_master(3,key_to_chars_3mod), + vk_master(4,key_to_chars_4mod), + vk_master(2,key_to_chars_2mod), + vk_master(1,keypad_numbers), + { 0,0,0 } +}; + +ROSDATA VSC_LPWSTR key_names[] = { + { 0x01, L"Esc" }, + { 0x0e, L"Backspace" }, + { 0x0f, L"Tab" }, + { 0x1c, L"Enter" }, + { 0x1d, L"Ctrl" }, + { 0x2a, L"Shift" }, + { 0x36, L"Right Shift" }, + { 0x37, L"Num *" }, + { 0x38, L"Alt" }, + { 0x39, L"Space" }, + { 0x3a, L"Caps Lock" }, + { 0x3b, L"F1" }, + { 0x3c, L"F2" }, + { 0x3d, L"F3" }, + { 0x3e, L"F4" }, + { 0x3f, L"F5" }, + { 0x40, L"F6" }, + { 0x41, L"F7" }, + { 0x42, L"F8" }, + { 0x43, L"F9" }, + { 0x44, L"F10" }, + { 0x45, L"Pause" }, + { 0x46, L"Scroll Lock" }, + { 0x47, L"Num 7" }, + { 0x48, L"Num 8" }, + { 0x49, L"Num 9" }, + { 0x4a, L"Num -" }, + { 0x4b, L"Num 4" }, + { 0x4c, L"Num 5" }, + { 0x4d, L"Num 6" }, + { 0x4e, L"Num +" }, + { 0x4f, L"Num 1" }, + { 0x50, L"Num 2" }, + { 0x51, L"Num 3" }, + { 0x52, L"Num 0" }, + { 0x53, L"Num Del" }, + { 0x54, L"Sys Req" }, + { 0x57, L"F11" }, + { 0x58, L"F12" }, + { 0x7c, L"F13" }, + { 0x7d, L"F14" }, + { 0x7e, L"F15" }, + { 0x7f, L"F16" }, + { 0x80, L"F17" }, + { 0x81, L"F18" }, + { 0x82, L"F19" }, + { 0x83, L"F20" }, + { 0x84, L"F21" }, + { 0x85, L"F22" }, + { 0x86, L"F23" }, + { 0x87, L"F24" }, + { 0, NULL } +}; + +ROSDATA VSC_LPWSTR extended_key_names[] = { + { 0x1c, L"Num Enter" }, + { 0x1d, L"Right Control" }, + { 0x35, L"Num /" }, + { 0x37, L"Prnt Scrn" }, + { 0x38, L"Right Alt" }, + { 0x45, L"Num Lock" }, + { 0x46, L"Break" }, + { 0x47, L"Home" }, + { 0x48, L"Up" }, + { 0x49, L"Page Up" }, + { 0x4b, L"Left" }, +//{ 0x4c, L"Center" }, + { 0x4d, L"Right" }, + { 0x4f, L"End" }, + { 0x50, L"Down" }, + { 0x51, L"Page Down" }, + { 0x52, L"Insert" }, + { 0x53, L"Delete" }, + { 0x54, L"<ReactOS>" }, + { 0x56, L"Help" }, + { 0x5b, L"Left <ReactOS>" }, + { 0x5c, L"Right <ReactOS>" }, + { 0x5d, L"Application" }, + { 0, NULL } +}; + +/* Finally, the master table */ +ROSDATA KBDTABLES keyboard_layout_table = { + /* modifier assignments */ + &modifier_bits, + + /* character from vk tables */ + vk_to_wchar_master_table, + + /* diacritical marks */ + NULL, + + /* Key names */ + (VSC_LPWSTR *)key_names, + (VSC_LPWSTR *)extended_key_names, + NULL, /* Dead key names */ + + /* scan code to virtual key maps */ + scancode_to_vk, + sizeof(scancode_to_vk) / sizeof(scancode_to_vk[0]), + extcode0_to_vk, + extcode1_to_vk, + + MAKELONG(0,1), /* Version 1.0 */ + + /* Ligatures -- Russian doesn't have any */ + 0, + 0, + NULL +}; + +PKBDTABLES STDCALL KbdLayerDescriptor() { + return &keyboard_layout_table; +} + +INT STDCALL +DllMain( + PVOID hinstDll, + ULONG dwReason, + PVOID reserved) +{ + return 1; +} + diff --git a/reactos/lib/lsasrv/lsaport.c b/reactos/lib/lsasrv/lsaport.c index 0dc6ec75e05..86cb20cbc93 100644 --- a/reactos/lib/lsasrv/lsaport.c +++ b/reactos/lib/lsasrv/lsaport.c @@ -1,178 +1,178 @@ -/* - */ - -#include <windows.h> -#define NTOS_MODE_USER -#include <ndk/ntndk.h> - -//#define NDEBUG -#include <debug.h> - - -HANDLE PortThreadHandle = NULL; -HANDLE ConnectPortHandle = NULL; -HANDLE MessagePortHandle = NULL; - - -static NTSTATUS -InitializeLsaPort(VOID) -{ - OBJECT_ATTRIBUTES ObjectAttributes; - UNICODE_STRING PortName; - LPC_MAX_MESSAGE Request; - NTSTATUS Status; - - ConnectPortHandle = NULL; - MessagePortHandle = NULL; - - RtlInitUnicodeString(&PortName, - L"\\SeLsaCommandPort"); - - InitializeObjectAttributes(&ObjectAttributes, - &PortName, - 0, - NULL, - NULL); - - Status = NtCreatePort(&ConnectPortHandle, - &ObjectAttributes, - 0, - 0x100, - 0x2000); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtCreatePort() failed (Status %lx)\n", Status); - goto ByeBye; - } - - Status = NtListenPort(ConnectPortHandle, - &Request.Header); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtListenPort() failed (Status %lx)\n", Status); - goto ByeBye; - } - - Status = NtAcceptConnectPort(&MessagePortHandle, - ConnectPortHandle, - NULL, - TRUE, - NULL, - NULL); - if (!NT_SUCCESS (Status)) - { - DPRINT1("NtAcceptConnectPort() failed (Status %lx)\n", Status); - goto ByeBye; - } - - Status = NtCompleteConnectPort (MessagePortHandle); - if (!NT_SUCCESS (Status)) - { - DPRINT1("NtCompleteConnectPort() failed (Status %lx)\n", Status); - goto ByeBye; - } - -ByeBye: - if (!NT_SUCCESS (Status)) - { - if (ConnectPortHandle != NULL) - NtClose (ConnectPortHandle); - - if (MessagePortHandle != NULL) - NtClose (MessagePortHandle); - } - - return Status; -} - - -static NTSTATUS -ProcessPortMessage(VOID) -{ - LPC_MAX_MESSAGE Request; -// LPC_MAX_MESSAGE Reply; - NTSTATUS Status; - - - DPRINT1("ProcessPortMessage() called\n"); - - Status = STATUS_SUCCESS; - - for (;;) - { - Status = NtReplyWaitReceivePort(MessagePortHandle, - 0, - NULL, - &Request.Header); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtReplyWaitReceivePort() failed (Status %lx)\n", Status); - break; - } - - DPRINT("Received message\n"); - - if (Request.Header.MessageType == LPC_PORT_CLOSED) - { - DPRINT("Port closed\n"); - -// return STATUS_UNSUCCESSFUL; - } - if (Request.Header.MessageType == LPC_REQUEST) - { - DPRINT("Received request\n"); - - } - else if (Request.Header.MessageType == LPC_DATAGRAM) - { - DPRINT("Received datagram\n"); - -// Message = (PIO_ERROR_LOG_MESSAGE)&Request.Data; - - } - } - - return Status; -} - - -static NTSTATUS STDCALL -PortThreadRoutine(PVOID Param) -{ - NTSTATUS Status = STATUS_SUCCESS; - - Status = InitializeLsaPort(); - if (!NT_SUCCESS(Status)) - return Status; - - while (NT_SUCCESS(Status)) - { - Status = ProcessPortMessage(); - } - - if (ConnectPortHandle != NULL) - NtClose (ConnectPortHandle); - - if (MessagePortHandle != NULL) - NtClose (MessagePortHandle); - - return Status; -} - - -BOOLEAN -StartLsaPortThread(VOID) -{ - DWORD ThreadId; - - PortThreadHandle = CreateThread(NULL, - 0x1000, - (LPTHREAD_START_ROUTINE)PortThreadRoutine, - NULL, - 0, - &ThreadId); - - return (PortThreadHandle != NULL); -} - -/* EOF */ +/* + */ + +#include <windows.h> +#define NTOS_MODE_USER +#include <ndk/ntndk.h> + +//#define NDEBUG +#include <debug.h> + + +HANDLE PortThreadHandle = NULL; +HANDLE ConnectPortHandle = NULL; +HANDLE MessagePortHandle = NULL; + + +static NTSTATUS +InitializeLsaPort(VOID) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING PortName; + LPC_MAX_MESSAGE Request; + NTSTATUS Status; + + ConnectPortHandle = NULL; + MessagePortHandle = NULL; + + RtlInitUnicodeString(&PortName, + L"\\SeLsaCommandPort"); + + InitializeObjectAttributes(&ObjectAttributes, + &PortName, + 0, + NULL, + NULL); + + Status = NtCreatePort(&ConnectPortHandle, + &ObjectAttributes, + 0, + 0x100, + 0x2000); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtCreatePort() failed (Status %lx)\n", Status); + goto ByeBye; + } + + Status = NtListenPort(ConnectPortHandle, + &Request.Header); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtListenPort() failed (Status %lx)\n", Status); + goto ByeBye; + } + + Status = NtAcceptConnectPort(&MessagePortHandle, + ConnectPortHandle, + NULL, + TRUE, + NULL, + NULL); + if (!NT_SUCCESS (Status)) + { + DPRINT1("NtAcceptConnectPort() failed (Status %lx)\n", Status); + goto ByeBye; + } + + Status = NtCompleteConnectPort (MessagePortHandle); + if (!NT_SUCCESS (Status)) + { + DPRINT1("NtCompleteConnectPort() failed (Status %lx)\n", Status); + goto ByeBye; + } + +ByeBye: + if (!NT_SUCCESS (Status)) + { + if (ConnectPortHandle != NULL) + NtClose (ConnectPortHandle); + + if (MessagePortHandle != NULL) + NtClose (MessagePortHandle); + } + + return Status; +} + + +static NTSTATUS +ProcessPortMessage(VOID) +{ + LPC_MAX_MESSAGE Request; +// LPC_MAX_MESSAGE Reply; + NTSTATUS Status; + + + DPRINT1("ProcessPortMessage() called\n"); + + Status = STATUS_SUCCESS; + + for (;;) + { + Status = NtReplyWaitReceivePort(MessagePortHandle, + 0, + NULL, + &Request.Header); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtReplyWaitReceivePort() failed (Status %lx)\n", Status); + break; + } + + DPRINT("Received message\n"); + + if (Request.Header.MessageType == LPC_PORT_CLOSED) + { + DPRINT("Port closed\n"); + +// return STATUS_UNSUCCESSFUL; + } + if (Request.Header.MessageType == LPC_REQUEST) + { + DPRINT("Received request\n"); + + } + else if (Request.Header.MessageType == LPC_DATAGRAM) + { + DPRINT("Received datagram\n"); + +// Message = (PIO_ERROR_LOG_MESSAGE)&Request.Data; + + } + } + + return Status; +} + + +static NTSTATUS STDCALL +PortThreadRoutine(PVOID Param) +{ + NTSTATUS Status = STATUS_SUCCESS; + + Status = InitializeLsaPort(); + if (!NT_SUCCESS(Status)) + return Status; + + while (NT_SUCCESS(Status)) + { + Status = ProcessPortMessage(); + } + + if (ConnectPortHandle != NULL) + NtClose (ConnectPortHandle); + + if (MessagePortHandle != NULL) + NtClose (MessagePortHandle); + + return Status; +} + + +BOOLEAN +StartLsaPortThread(VOID) +{ + DWORD ThreadId; + + PortThreadHandle = CreateThread(NULL, + 0x1000, + (LPTHREAD_START_ROUTINE)PortThreadRoutine, + NULL, + 0, + &ThreadId); + + return (PortThreadHandle != NULL); +} + +/* EOF */ diff --git a/reactos/lib/lsasrv/lsasrv.c b/reactos/lib/lsasrv/lsasrv.c index d967568b836..2431f0541ea 100644 --- a/reactos/lib/lsasrv/lsasrv.c +++ b/reactos/lib/lsasrv/lsasrv.c @@ -1,24 +1,24 @@ - -#include <windows.h> -#define NTOS_MODE_USER -#include <ndk/ntndk.h> - -#include <lsass/lsasrv.h> - -#define NDEBUG -#include <debug.h> - -VOID StartLsaPortThread(VOID); - - -NTSTATUS STDCALL -LsapInitLsa(VOID) -{ - DPRINT1("LsapInitLsa() called\n"); - - StartLsaPortThread(); - - return STATUS_SUCCESS; -} - -/* EOF */ + +#include <windows.h> +#define NTOS_MODE_USER +#include <ndk/ntndk.h> + +#include <lsass/lsasrv.h> + +#define NDEBUG +#include <debug.h> + +VOID StartLsaPortThread(VOID); + + +NTSTATUS STDCALL +LsapInitLsa(VOID) +{ + DPRINT1("LsapInitLsa() called\n"); + + StartLsaPortThread(); + + return STATUS_SUCCESS; +} + +/* EOF */ diff --git a/reactos/lib/mpr/auth.c b/reactos/lib/mpr/auth.c index f18751032f9..531ca8a60fe 100644 --- a/reactos/lib/mpr/auth.c +++ b/reactos/lib/mpr/auth.c @@ -1,95 +1,95 @@ -/* - * MPR Authentication and Logon functions - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winnetwk.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mpr); - - -/***************************************************************** - * WNetLogoffA [MPR.@] - */ -DWORD WINAPI WNetLogoffA( LPCSTR lpProvider, HWND hwndOwner ) -{ - FIXME( "(%s, %p): stub\n", debugstr_a(lpProvider), hwndOwner ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/***************************************************************** - * WNetLogoffW [MPR.@] - */ -DWORD WINAPI WNetLogoffW( LPCWSTR lpProvider, HWND hwndOwner ) -{ - FIXME( "(%s, %p): stub\n", debugstr_w(lpProvider), hwndOwner ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/***************************************************************** - * WNetLogonA [MPR.@] - */ -DWORD WINAPI WNetLogonA( LPCSTR lpProvider, HWND hwndOwner ) -{ - FIXME( "(%s, %p): stub\n", debugstr_a(lpProvider), hwndOwner ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/***************************************************************** - * WNetLogonW [MPR.@] - */ -DWORD WINAPI WNetLogonW( LPCWSTR lpProvider, HWND hwndOwner ) -{ - FIXME( "(%s, %p): stub\n", debugstr_w(lpProvider), hwndOwner ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/***************************************************************** - * WNetVerifyPasswordA [MPR.@] - */ -DWORD WINAPI WNetVerifyPasswordA( LPCSTR lpszPassword, BOOL *pfMatch ) -{ - FIXME( "(%p, %p): stub\n", lpszPassword, pfMatch ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/***************************************************************** - * WNetVerifyPasswordW [MPR.@] - */ -DWORD WINAPI WNetVerifyPasswordW( LPCWSTR lpszPassword, BOOL *pfMatch ) -{ - FIXME( "(%p, %p): stub\n", lpszPassword, pfMatch ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} +/* + * MPR Authentication and Logon functions + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winnetwk.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mpr); + + +/***************************************************************** + * WNetLogoffA [MPR.@] + */ +DWORD WINAPI WNetLogoffA( LPCSTR lpProvider, HWND hwndOwner ) +{ + FIXME( "(%s, %p): stub\n", debugstr_a(lpProvider), hwndOwner ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/***************************************************************** + * WNetLogoffW [MPR.@] + */ +DWORD WINAPI WNetLogoffW( LPCWSTR lpProvider, HWND hwndOwner ) +{ + FIXME( "(%s, %p): stub\n", debugstr_w(lpProvider), hwndOwner ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/***************************************************************** + * WNetLogonA [MPR.@] + */ +DWORD WINAPI WNetLogonA( LPCSTR lpProvider, HWND hwndOwner ) +{ + FIXME( "(%s, %p): stub\n", debugstr_a(lpProvider), hwndOwner ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/***************************************************************** + * WNetLogonW [MPR.@] + */ +DWORD WINAPI WNetLogonW( LPCWSTR lpProvider, HWND hwndOwner ) +{ + FIXME( "(%s, %p): stub\n", debugstr_w(lpProvider), hwndOwner ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/***************************************************************** + * WNetVerifyPasswordA [MPR.@] + */ +DWORD WINAPI WNetVerifyPasswordA( LPCSTR lpszPassword, BOOL *pfMatch ) +{ + FIXME( "(%p, %p): stub\n", lpszPassword, pfMatch ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/***************************************************************** + * WNetVerifyPasswordW [MPR.@] + */ +DWORD WINAPI WNetVerifyPasswordW( LPCWSTR lpszPassword, BOOL *pfMatch ) +{ + FIXME( "(%p, %p): stub\n", lpszPassword, pfMatch ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} diff --git a/reactos/lib/mpr/mpr_main.c b/reactos/lib/mpr/mpr_main.c index a1a9ec4e928..2c8eee76640 100644 --- a/reactos/lib/mpr/mpr_main.c +++ b/reactos/lib/mpr/mpr_main.c @@ -1,100 +1,100 @@ -/* - * MPR undocumented functions - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winnetwk.h" -#include "wine/debug.h" -#include "wnetpriv.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mpr); - - /* - * FIXME: The following routines should use a private heap ... - */ - -/***************************************************************** - * @ [MPR.22] - */ -LPVOID WINAPI MPR_Alloc( DWORD dwSize ) -{ - return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize ); -} - -/***************************************************************** - * @ [MPR.23] - */ -LPVOID WINAPI MPR_ReAlloc( LPVOID lpSrc, DWORD dwSize ) -{ - if ( lpSrc ) - return HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, lpSrc, dwSize ); - else - return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize ); -} - -/***************************************************************** - * @ [MPR.24] - */ -BOOL WINAPI MPR_Free( LPVOID lpMem ) -{ - if ( lpMem ) - return HeapFree( GetProcessHeap(), 0, lpMem ); - else - return FALSE; -} - -/***************************************************************** - * @ [MPR.25] - */ -BOOL WINAPI _MPR_25( LPBYTE lpMem, INT len ) -{ - FIXME( "(%p, %d): stub\n", lpMem, len ); - - return FALSE; -} - -/***************************************************************** - * DllCanUnloadNow [MPR.@] - */ -DWORD WINAPI MPR_DllCanUnloadNow(void) -{ - FIXME("Stub\n"); - return S_OK; -} - -/***************************************************************** - * DllMain [MPR.init] - */ -BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - switch (fdwReason) { - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls( hinstDLL ); - wnetInit(hinstDLL); - break; - - case DLL_PROCESS_DETACH: - wnetFree(); - break; - } - return TRUE; -} +/* + * MPR undocumented functions + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winnetwk.h" +#include "wine/debug.h" +#include "wnetpriv.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mpr); + + /* + * FIXME: The following routines should use a private heap ... + */ + +/***************************************************************** + * @ [MPR.22] + */ +LPVOID WINAPI MPR_Alloc( DWORD dwSize ) +{ + return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize ); +} + +/***************************************************************** + * @ [MPR.23] + */ +LPVOID WINAPI MPR_ReAlloc( LPVOID lpSrc, DWORD dwSize ) +{ + if ( lpSrc ) + return HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, lpSrc, dwSize ); + else + return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize ); +} + +/***************************************************************** + * @ [MPR.24] + */ +BOOL WINAPI MPR_Free( LPVOID lpMem ) +{ + if ( lpMem ) + return HeapFree( GetProcessHeap(), 0, lpMem ); + else + return FALSE; +} + +/***************************************************************** + * @ [MPR.25] + */ +BOOL WINAPI _MPR_25( LPBYTE lpMem, INT len ) +{ + FIXME( "(%p, %d): stub\n", lpMem, len ); + + return FALSE; +} + +/***************************************************************** + * DllCanUnloadNow [MPR.@] + */ +DWORD WINAPI MPR_DllCanUnloadNow(void) +{ + FIXME("Stub\n"); + return S_OK; +} + +/***************************************************************** + * DllMain [MPR.init] + */ +BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls( hinstDLL ); + wnetInit(hinstDLL); + break; + + case DLL_PROCESS_DETACH: + wnetFree(); + break; + } + return TRUE; +} diff --git a/reactos/lib/mpr/mprres.h b/reactos/lib/mpr/mprres.h index bfaa59a242c..fa9cf8be7d6 100644 --- a/reactos/lib/mpr/mprres.h +++ b/reactos/lib/mpr/mprres.h @@ -1,32 +1,32 @@ -/* - * Copyright (C) 2004 Juan Lang - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __WINE_MPRRES_H__ -#define __WINE_MPRRES_H__ - -#define IDS_ENTIRENETWORK 1 - -#define IDD_PROXYDLG 0x400 - -#define IDC_PROXY 0x401 -#define IDC_REALM 0x402 -#define IDC_USERNAME 0x403 -#define IDC_PASSWORD 0x404 -#define IDC_SAVEPASSWORD 0x405 -#define IDC_EXPLAIN 0x406 - -#endif /* ndef __WINE_MPRRES_H__ */ +/* + * Copyright (C) 2004 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __WINE_MPRRES_H__ +#define __WINE_MPRRES_H__ + +#define IDS_ENTIRENETWORK 1 + +#define IDD_PROXYDLG 0x400 + +#define IDC_PROXY 0x401 +#define IDC_REALM 0x402 +#define IDC_USERNAME 0x403 +#define IDC_PASSWORD 0x404 +#define IDC_SAVEPASSWORD 0x405 +#define IDC_EXPLAIN 0x406 + +#endif /* ndef __WINE_MPRRES_H__ */ diff --git a/reactos/lib/mpr/multinet.c b/reactos/lib/mpr/multinet.c index 3c41367b625..aa8cfb8908b 100644 --- a/reactos/lib/mpr/multinet.c +++ b/reactos/lib/mpr/multinet.c @@ -1,81 +1,81 @@ -/* - * MPR Multinet functions - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winnetwk.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mpr); - - -/***************************************************************** - * MultinetGetConnectionPerformanceA [MPR.@] - * - * RETURNS - * Success: NO_ERROR - * Failure: ERROR_NOT_SUPPORTED, ERROR_NOT_CONNECTED, - * ERROR_NO_NET_OR_BAD_PATH, ERROR_BAD_DEVICE, - * ERROR_BAD_NET_NAME, ERROR_INVALID_PARAMETER, - * ERROR_NO_NETWORK, ERROR_EXTENDED_ERROR - */ -DWORD WINAPI MultinetGetConnectionPerformanceA( - LPNETRESOURCEA lpNetResource, - LPNETCONNECTINFOSTRUCT lpNetConnectInfoStruct ) -{ - FIXME( "(%p, %p): stub\n", lpNetResource, lpNetConnectInfoStruct ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/***************************************************************** - * MultinetGetConnectionPerformanceW [MPR.@] - */ -DWORD WINAPI MultinetGetConnectionPerformanceW( - LPNETRESOURCEW lpNetResource, - LPNETCONNECTINFOSTRUCT lpNetConnectInfoStruct ) -{ - FIXME( "(%p, %p): stub\n", lpNetResource, lpNetConnectInfoStruct ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/***************************************************************** - * MultinetGetErrorTextA [MPR.@] - */ -DWORD WINAPI MultinetGetErrorTextA( DWORD x, DWORD y, DWORD z ) -{ - FIXME( "(%lx, %lx, %lx): stub\n", x, y, z ); - return 0; -} - -/***************************************************************** - * MultinetGetErrorTextW [MPR.@] - */ -DWORD WINAPI MultinetGetErrorTextW( DWORD x, DWORD y, DWORD z ) -{ - FIXME( "(%lx, %lx, %lx ): stub\n", x, y, z ); - return 0; -} - +/* + * MPR Multinet functions + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winnetwk.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mpr); + + +/***************************************************************** + * MultinetGetConnectionPerformanceA [MPR.@] + * + * RETURNS + * Success: NO_ERROR + * Failure: ERROR_NOT_SUPPORTED, ERROR_NOT_CONNECTED, + * ERROR_NO_NET_OR_BAD_PATH, ERROR_BAD_DEVICE, + * ERROR_BAD_NET_NAME, ERROR_INVALID_PARAMETER, + * ERROR_NO_NETWORK, ERROR_EXTENDED_ERROR + */ +DWORD WINAPI MultinetGetConnectionPerformanceA( + LPNETRESOURCEA lpNetResource, + LPNETCONNECTINFOSTRUCT lpNetConnectInfoStruct ) +{ + FIXME( "(%p, %p): stub\n", lpNetResource, lpNetConnectInfoStruct ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/***************************************************************** + * MultinetGetConnectionPerformanceW [MPR.@] + */ +DWORD WINAPI MultinetGetConnectionPerformanceW( + LPNETRESOURCEW lpNetResource, + LPNETCONNECTINFOSTRUCT lpNetConnectInfoStruct ) +{ + FIXME( "(%p, %p): stub\n", lpNetResource, lpNetConnectInfoStruct ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/***************************************************************** + * MultinetGetErrorTextA [MPR.@] + */ +DWORD WINAPI MultinetGetErrorTextA( DWORD x, DWORD y, DWORD z ) +{ + FIXME( "(%lx, %lx, %lx): stub\n", x, y, z ); + return 0; +} + +/***************************************************************** + * MultinetGetErrorTextW [MPR.@] + */ +DWORD WINAPI MultinetGetErrorTextW( DWORD x, DWORD y, DWORD z ) +{ + FIXME( "(%lx, %lx, %lx ): stub\n", x, y, z ); + return 0; +} + diff --git a/reactos/lib/mpr/nps.c b/reactos/lib/mpr/nps.c index 980c58a67a6..7fe15565b89 100644 --- a/reactos/lib/mpr/nps.c +++ b/reactos/lib/mpr/nps.c @@ -1,213 +1,213 @@ -/* - * MPR Network Provider Services functions - * - * Copyright 1999 Ulrich Weigand - * Copyright 2004 Mike McCormack for CodeWeavers Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "netspi.h" -#include "wine/debug.h" -#include "winerror.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mpr); - -#include "wine/unicode.h" - -#include "mprres.h" - -/*********************************************************************** - * NPS_ProxyPasswordDialog - */ -static INT_PTR WINAPI NPS_ProxyPasswordDialog( - HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) -{ - HWND hitem; - LPAUTHDLGSTRUCTA lpAuthDlgStruct; - - if( uMsg == WM_INITDIALOG ) - { - TRACE("WM_INITDIALOG (%08lx)\n", lParam); - - /* save the parameter list */ - lpAuthDlgStruct = (LPAUTHDLGSTRUCTA) lParam; - SetWindowLongPtrW( hdlg, GWLP_USERDATA, lParam ); - - if( lpAuthDlgStruct->lpExplainText ) - { - hitem = GetDlgItem( hdlg, IDC_EXPLAIN ); - SetWindowTextA( hitem, lpAuthDlgStruct->lpExplainText ); - } - - /* extract the Realm from the proxy response and show it */ - if( lpAuthDlgStruct->lpResource ) - { - hitem = GetDlgItem( hdlg, IDC_REALM ); - SetWindowTextA( hitem, lpAuthDlgStruct->lpResource ); - } - - return TRUE; - } - - lpAuthDlgStruct = (LPAUTHDLGSTRUCTA) GetWindowLongPtrW( hdlg, GWLP_USERDATA ); - - switch( uMsg ) - { - case WM_COMMAND: - if( wParam == IDOK ) - { - WCHAR username[0x20], password[0x20]; - - username[0] = 0; - hitem = GetDlgItem( hdlg, IDC_USERNAME ); - if( hitem ) - GetWindowTextA( hitem, lpAuthDlgStruct->lpUsername, lpAuthDlgStruct->cbUsername ); - - password[0] = 0; - hitem = GetDlgItem( hdlg, IDC_PASSWORD ); - if( hitem ) - GetWindowTextA( hitem, lpAuthDlgStruct->lpPassword, lpAuthDlgStruct->cbPassword ); - - EndDialog( hdlg, WN_SUCCESS ); - return TRUE; - } - if( wParam == IDCANCEL ) - { - EndDialog( hdlg, WN_CANCEL ); - return TRUE; - } - break; - } - return FALSE; -} - -/***************************************************************** - * NPSAuthenticationDialogA [MPR.@] - */ -DWORD WINAPI NPSAuthenticationDialogA( LPAUTHDLGSTRUCTA lpAuthDlgStruct ) -{ - HMODULE hwininet = GetModuleHandleA( "mpr.dll" ); - - TRACE("%p\n", lpAuthDlgStruct); - - if( !lpAuthDlgStruct ) - return WN_BAD_POINTER; - if( lpAuthDlgStruct->cbStructure < sizeof *lpAuthDlgStruct ) - return WN_BAD_POINTER; - - TRACE("%s %s %s\n",lpAuthDlgStruct->lpResource, - lpAuthDlgStruct->lpOUTitle, lpAuthDlgStruct->lpExplainText); - - return DialogBoxParamW( hwininet, MAKEINTRESOURCEW( IDD_PROXYDLG ), - lpAuthDlgStruct->hwndOwner, NPS_ProxyPasswordDialog, - (LPARAM) lpAuthDlgStruct ); -} - -/***************************************************************** - * NPSGetProviderHandleA [MPR.@] - */ -DWORD WINAPI NPSGetProviderHandleA( PHPROVIDER phProvider ) -{ - FIXME( "(%p): stub\n", phProvider ); - return WN_NOT_SUPPORTED; -} - -/***************************************************************** - * NPSGetProviderNameA [MPR.@] - */ -DWORD WINAPI NPSGetProviderNameA( HPROVIDER hProvider, LPCSTR *lpszProviderName ) -{ - FIXME( "(%p, %p): stub\n", hProvider, lpszProviderName ); - return WN_NOT_SUPPORTED; -} - -/***************************************************************** - * NPSGetSectionNameA [MPR.@] - */ -DWORD WINAPI NPSGetSectionNameA( HPROVIDER hProvider, LPCSTR *lpszSectionName ) -{ - FIXME( "(%p, %p): stub\n", hProvider, lpszSectionName ); - return WN_NOT_SUPPORTED; -} - -/***************************************************************** - * NPSSetExtendedErrorA [MPR.@] - */ -DWORD WINAPI NPSSetExtendedErrorA( DWORD NetSpecificError, LPSTR lpExtendedErrorText ) -{ - FIXME( "(%08lx, %s): stub\n", NetSpecificError, debugstr_a(lpExtendedErrorText) ); - return WN_NOT_SUPPORTED; -} - -/***************************************************************** - * NPSSetCustomTextA [MPR.@] - */ -VOID WINAPI NPSSetCustomTextA( LPSTR lpCustomErrorText ) -{ - FIXME( "(%s): stub\n", debugstr_a(lpCustomErrorText) ); -} - -/***************************************************************** - * NPSCopyStringA [MPR.@] - */ -DWORD WINAPI NPSCopyStringA( LPCSTR lpString, LPVOID lpBuffer, LPDWORD lpdwBufferSize ) -{ - FIXME( "(%s, %p, %p): stub\n", debugstr_a(lpString), lpBuffer, lpdwBufferSize ); - return WN_NOT_SUPPORTED; -} - -/***************************************************************** - * NPSDeviceGetNumberA [MPR.@] - */ -DWORD WINAPI NPSDeviceGetNumberA( LPSTR lpLocalName, LPDWORD lpdwNumber, LPDWORD lpdwType ) -{ - FIXME( "(%s, %p, %p): stub\n", debugstr_a(lpLocalName), lpdwNumber, lpdwType ); - return WN_NOT_SUPPORTED; -} - -/***************************************************************** - * NPSDeviceGetStringA [MPR.@] - */ -DWORD WINAPI NPSDeviceGetStringA( DWORD dwNumber, DWORD dwType, LPSTR lpLocalName, LPDWORD lpdwBufferSize ) -{ - FIXME( "(%ld, %ld, %p, %p): stub\n", dwNumber, dwType, lpLocalName, lpdwBufferSize ); - return WN_NOT_SUPPORTED; -} - -/***************************************************************** - * NPSNotifyRegisterA [MPR.@] - */ -DWORD WINAPI NPSNotifyRegisterA( enum NOTIFYTYPE NotifyType, NOTIFYCALLBACK pfNotifyCallBack ) -{ - FIXME( "(%d, %p): stub\n", NotifyType, pfNotifyCallBack ); - return WN_NOT_SUPPORTED; -} - -/***************************************************************** - * NPSNotifyGetContextA [MPR.@] - */ -LPVOID WINAPI NPSNotifyGetContextA( NOTIFYCALLBACK pfNotifyCallBack ) -{ - FIXME( "(%p): stub\n", pfNotifyCallBack ); - return NULL; -} +/* + * MPR Network Provider Services functions + * + * Copyright 1999 Ulrich Weigand + * Copyright 2004 Mike McCormack for CodeWeavers Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "netspi.h" +#include "wine/debug.h" +#include "winerror.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mpr); + +#include "wine/unicode.h" + +#include "mprres.h" + +/*********************************************************************** + * NPS_ProxyPasswordDialog + */ +static INT_PTR WINAPI NPS_ProxyPasswordDialog( + HWND hdlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + HWND hitem; + LPAUTHDLGSTRUCTA lpAuthDlgStruct; + + if( uMsg == WM_INITDIALOG ) + { + TRACE("WM_INITDIALOG (%08lx)\n", lParam); + + /* save the parameter list */ + lpAuthDlgStruct = (LPAUTHDLGSTRUCTA) lParam; + SetWindowLongPtrW( hdlg, GWLP_USERDATA, lParam ); + + if( lpAuthDlgStruct->lpExplainText ) + { + hitem = GetDlgItem( hdlg, IDC_EXPLAIN ); + SetWindowTextA( hitem, lpAuthDlgStruct->lpExplainText ); + } + + /* extract the Realm from the proxy response and show it */ + if( lpAuthDlgStruct->lpResource ) + { + hitem = GetDlgItem( hdlg, IDC_REALM ); + SetWindowTextA( hitem, lpAuthDlgStruct->lpResource ); + } + + return TRUE; + } + + lpAuthDlgStruct = (LPAUTHDLGSTRUCTA) GetWindowLongPtrW( hdlg, GWLP_USERDATA ); + + switch( uMsg ) + { + case WM_COMMAND: + if( wParam == IDOK ) + { + WCHAR username[0x20], password[0x20]; + + username[0] = 0; + hitem = GetDlgItem( hdlg, IDC_USERNAME ); + if( hitem ) + GetWindowTextA( hitem, lpAuthDlgStruct->lpUsername, lpAuthDlgStruct->cbUsername ); + + password[0] = 0; + hitem = GetDlgItem( hdlg, IDC_PASSWORD ); + if( hitem ) + GetWindowTextA( hitem, lpAuthDlgStruct->lpPassword, lpAuthDlgStruct->cbPassword ); + + EndDialog( hdlg, WN_SUCCESS ); + return TRUE; + } + if( wParam == IDCANCEL ) + { + EndDialog( hdlg, WN_CANCEL ); + return TRUE; + } + break; + } + return FALSE; +} + +/***************************************************************** + * NPSAuthenticationDialogA [MPR.@] + */ +DWORD WINAPI NPSAuthenticationDialogA( LPAUTHDLGSTRUCTA lpAuthDlgStruct ) +{ + HMODULE hwininet = GetModuleHandleA( "mpr.dll" ); + + TRACE("%p\n", lpAuthDlgStruct); + + if( !lpAuthDlgStruct ) + return WN_BAD_POINTER; + if( lpAuthDlgStruct->cbStructure < sizeof *lpAuthDlgStruct ) + return WN_BAD_POINTER; + + TRACE("%s %s %s\n",lpAuthDlgStruct->lpResource, + lpAuthDlgStruct->lpOUTitle, lpAuthDlgStruct->lpExplainText); + + return DialogBoxParamW( hwininet, MAKEINTRESOURCEW( IDD_PROXYDLG ), + lpAuthDlgStruct->hwndOwner, NPS_ProxyPasswordDialog, + (LPARAM) lpAuthDlgStruct ); +} + +/***************************************************************** + * NPSGetProviderHandleA [MPR.@] + */ +DWORD WINAPI NPSGetProviderHandleA( PHPROVIDER phProvider ) +{ + FIXME( "(%p): stub\n", phProvider ); + return WN_NOT_SUPPORTED; +} + +/***************************************************************** + * NPSGetProviderNameA [MPR.@] + */ +DWORD WINAPI NPSGetProviderNameA( HPROVIDER hProvider, LPCSTR *lpszProviderName ) +{ + FIXME( "(%p, %p): stub\n", hProvider, lpszProviderName ); + return WN_NOT_SUPPORTED; +} + +/***************************************************************** + * NPSGetSectionNameA [MPR.@] + */ +DWORD WINAPI NPSGetSectionNameA( HPROVIDER hProvider, LPCSTR *lpszSectionName ) +{ + FIXME( "(%p, %p): stub\n", hProvider, lpszSectionName ); + return WN_NOT_SUPPORTED; +} + +/***************************************************************** + * NPSSetExtendedErrorA [MPR.@] + */ +DWORD WINAPI NPSSetExtendedErrorA( DWORD NetSpecificError, LPSTR lpExtendedErrorText ) +{ + FIXME( "(%08lx, %s): stub\n", NetSpecificError, debugstr_a(lpExtendedErrorText) ); + return WN_NOT_SUPPORTED; +} + +/***************************************************************** + * NPSSetCustomTextA [MPR.@] + */ +VOID WINAPI NPSSetCustomTextA( LPSTR lpCustomErrorText ) +{ + FIXME( "(%s): stub\n", debugstr_a(lpCustomErrorText) ); +} + +/***************************************************************** + * NPSCopyStringA [MPR.@] + */ +DWORD WINAPI NPSCopyStringA( LPCSTR lpString, LPVOID lpBuffer, LPDWORD lpdwBufferSize ) +{ + FIXME( "(%s, %p, %p): stub\n", debugstr_a(lpString), lpBuffer, lpdwBufferSize ); + return WN_NOT_SUPPORTED; +} + +/***************************************************************** + * NPSDeviceGetNumberA [MPR.@] + */ +DWORD WINAPI NPSDeviceGetNumberA( LPSTR lpLocalName, LPDWORD lpdwNumber, LPDWORD lpdwType ) +{ + FIXME( "(%s, %p, %p): stub\n", debugstr_a(lpLocalName), lpdwNumber, lpdwType ); + return WN_NOT_SUPPORTED; +} + +/***************************************************************** + * NPSDeviceGetStringA [MPR.@] + */ +DWORD WINAPI NPSDeviceGetStringA( DWORD dwNumber, DWORD dwType, LPSTR lpLocalName, LPDWORD lpdwBufferSize ) +{ + FIXME( "(%ld, %ld, %p, %p): stub\n", dwNumber, dwType, lpLocalName, lpdwBufferSize ); + return WN_NOT_SUPPORTED; +} + +/***************************************************************** + * NPSNotifyRegisterA [MPR.@] + */ +DWORD WINAPI NPSNotifyRegisterA( enum NOTIFYTYPE NotifyType, NOTIFYCALLBACK pfNotifyCallBack ) +{ + FIXME( "(%d, %p): stub\n", NotifyType, pfNotifyCallBack ); + return WN_NOT_SUPPORTED; +} + +/***************************************************************** + * NPSNotifyGetContextA [MPR.@] + */ +LPVOID WINAPI NPSNotifyGetContextA( NOTIFYCALLBACK pfNotifyCallBack ) +{ + FIXME( "(%p): stub\n", pfNotifyCallBack ); + return NULL; +} diff --git a/reactos/lib/mpr/pwcache.c b/reactos/lib/mpr/pwcache.c index 7f24cf467c1..24b3fcd1bdf 100644 --- a/reactos/lib/mpr/pwcache.c +++ b/reactos/lib/mpr/pwcache.c @@ -1,319 +1,319 @@ -/* - * MPR Password Cache functions - * - * Copyright 1999 Ulrich Weigand - * Copyright 2003,2004 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> -#include <stdio.h> - -#include "windef.h" -#include "winbase.h" -#include "winnetwk.h" -#include "winreg.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mpr); - -static const char mpr_key[] = "Software\\Wine\\Wine\\Mpr\\"; - -static inline BYTE hex( BYTE x ) -{ - if( x <= 9 ) - return x + '0'; - return x + 'A' - 10; -} - -static inline CHAR ctox( CHAR x ) -{ - if( ( x >= '0' ) && ( x <= '9' ) ) - return x - '0'; - if( ( x >= 'A' ) && ( x <= 'F' ) ) - return x - 'A' + 10; - if( ( x >= 'a' ) && ( x <= 'a' ) ) - return x - 'a' + 10; - return -1; -} - -static LPSTR MPR_GetValueName( LPSTR pbResource, WORD cbResource, BYTE nType ) -{ - LPSTR name; - DWORD i; - - name = HeapAlloc( GetProcessHeap(), 0, 6+cbResource*2 ); - if( name ) - sprintf( name, "X-%02X-", nType ); - for(i=0; i<cbResource; i++) - { - name[5+i*2]=hex((pbResource[i]&0xf0)>>4); - name[6+i*2]=hex(pbResource[i]&0x0f); - } - name[5+i*2]=0; - TRACE( "Value is %s\n", name ); - return name; -} - - -/************************************************************************** - * WNetCachePassword [MPR.@] Saves password in cache - * - * NOTES - * only the parameter count is verifyed - * - * ---- everything below this line might be wrong (js) ----- - * RETURNS - * Success: WN_SUCCESS - * Failure: WN_ACCESS_DENIED, WN_BAD_PASSWORD, WN_BADVALUE, WN_NET_ERROR, - * WN_NOT_SUPPORTED, WN_OUT_OF_MEMORY - */ -DWORD WINAPI WNetCachePassword( - LPSTR pbResource, /* [in] Name of workgroup, computer, or resource */ - WORD cbResource, /* [in] Size of name */ - LPSTR pbPassword, /* [in] Buffer containing password */ - WORD cbPassword, /* [in] Size of password */ - BYTE nType, /* [in] Type of password to cache */ - WORD x) - -{ - HKEY hkey; - DWORD r; - LPSTR valname; - - WARN( "(%p(%s), %d, %p(%s), %d, %d, 0x%08x): totally insecure\n", - pbResource, debugstr_a(pbResource), cbResource, - pbPassword, debugstr_a(pbPassword), cbPassword, - nType, x ); - - /* @@ Wine registry key: HKCU\Software\Wine\Wine\Mpr */ - r = RegCreateKeyA( HKEY_CURRENT_USER, mpr_key, &hkey ); - if( r ) - return WN_ACCESS_DENIED; - - valname = MPR_GetValueName( pbResource, cbResource, nType ); - if( valname ) - { - r = RegSetValueExA( hkey, valname, 0, REG_BINARY, - pbPassword, cbPassword ); - if( r ) - r = WN_CANCEL; - else - r = WN_SUCCESS; - HeapFree( GetProcessHeap(), 0, valname ); - } - else - r = WN_OUT_OF_MEMORY; - - RegCloseKey( hkey ); - - return r; -} - -/***************************************************************** - * WNetRemoveCachedPassword [MPR.@] - */ -UINT WINAPI WNetRemoveCachedPassword( - LPSTR pbResource, /* [in] resource ID to delete */ - WORD cbResource, /* [in] number of bytes in the resource ID */ - BYTE nType ) /* [in] Type of the resource to delete */ -{ - HKEY hkey; - DWORD r; - LPSTR valname; - - WARN( "(%p(%s), %d, %d): totally insecure\n", - pbResource, debugstr_a(pbResource), cbResource, nType ); - - /* @@ Wine registry key: HKCU\Software\Wine\Wine\Mpr */ - r = RegCreateKeyA( HKEY_CURRENT_USER, mpr_key, &hkey ); - if( r ) - return WN_ACCESS_DENIED; - - valname = MPR_GetValueName( pbResource, cbResource, nType ); - if( valname ) - { - r = RegDeleteValueA( hkey, valname ); - if( r ) - r = WN_ACCESS_DENIED; - else - r = WN_SUCCESS; - HeapFree( GetProcessHeap(), 0, valname ); - } - else - r = WN_OUT_OF_MEMORY; - - return r; -} - -/***************************************************************** - * WNetGetCachedPassword [MPR.@] Retrieves password from cache - * - * NOTES - * the stub seems to be wrong: - * arg1: ptr 0x40xxxxxx -> (no string) - * arg2: len 36 - * arg3: ptr 0x40xxxxxx -> (no string) - * arg4: ptr 0x40xxxxxx -> 0xc8 - * arg5: type? 4 - * - * ---- everything below this line might be wrong (js) ----- - * RETURNS - * Success: WN_SUCCESS - * Failure: WN_ACCESS_DENIED, WN_BAD_PASSWORD, WN_BAD_VALUE, - * WN_NET_ERROR, WN_NOT_SUPPORTED, WN_OUT_OF_MEMORY - */ -DWORD WINAPI WNetGetCachedPassword( - LPSTR pbResource, /* [in] Name of workgroup, computer, or resource */ - WORD cbResource, /* [in] Size of name */ - LPSTR pbPassword, /* [out] Buffer to receive password */ - LPWORD pcbPassword, /* [out] Receives size of password */ - BYTE nType) /* [in] Type of password to retrieve */ -{ - HKEY hkey; - DWORD r, type = 0, sz; - LPSTR valname; - - WARN( "(%p(%s), %d, %p, %p, %d): totally insecure\n", - pbResource, debugstr_a(pbResource), cbResource, - pbPassword, pcbPassword, nType ); - - memset( pbPassword, 0, *pcbPassword); - - /* @@ Wine registry key: HKCU\Software\Wine\Wine\Mpr */ - r = RegCreateKeyA( HKEY_CURRENT_USER, mpr_key, &hkey ); - if( r ) - return WN_ACCESS_DENIED; - - valname = MPR_GetValueName( pbResource, cbResource, nType ); - if( valname ) - { - sz = *pcbPassword; - r = RegQueryValueExA( hkey, valname, 0, &type, pbPassword, &sz ); - *pcbPassword = sz; - if( r ) - r = WN_CANCEL; - else - r = WN_SUCCESS; - HeapFree( GetProcessHeap(), 0, valname ); - } - else - r = WN_OUT_OF_MEMORY; - - return r; -} - -/******************************************************************* - * WNetEnumCachedPasswords [MPR.@] - * - * NOTES - * the parameter count is verifyed - * - * This function is a huge security risk, as virii and such can use - * it to grab all the passwords in the cache. It's bad enough to - * store the passwords (insecurely). - * - * bpPrefix and cbPrefix are used to filter the returned passwords - * the first cbPrefix bytes of the password resource identifier - * should match the same number of bytes in bpPrefix - * - * RETURNS - * Success: WN_SUCCESS (even if no entries were enumerated) - * Failure: WN_ACCESS_DENIED, WN_BAD_PASSWORD, WN_BAD_VALUE, - * WN_NET_ERROR, WN_NOT_SUPPORTED, WN_OUT_OF_MEMORY - */ - -UINT WINAPI WNetEnumCachedPasswords( - LPSTR pbPrefix, /* [in] prefix to filter cache entries */ - WORD cbPrefix, /* [in] number of bytes in Prefix substring */ - BYTE nType, /* [in] match the Type ID of the entry */ - ENUMPASSWORDPROC enumPasswordProc, /* [in] callback function */ - DWORD param) /* [in] parameter passed to enum function */ -{ - HKEY hkey; - DWORD r, type, val_sz, data_sz, i, j, size; - PASSWORD_CACHE_ENTRY *entry; - CHAR val[256], prefix[6]; - - WARN( "(%s, %d, %d, %p, 0x%08lx) totally insecure\n", - debugstr_an(pbPrefix,cbPrefix), cbPrefix, - nType, enumPasswordProc, param ); - - /* @@ Wine registry key: HKCU\Software\Wine\Wine\Mpr */ - r = RegCreateKeyA( HKEY_CURRENT_USER, mpr_key, &hkey ); - if( r ) - return WN_ACCESS_DENIED; - - sprintf(prefix, "X-%02X-", nType ); - - i = 0; - for( i=0; ; i++ ) - { - val_sz = sizeof val; - data_sz = 0; - type = 0; - val[0] = 0; - r = RegEnumValueA( hkey, i, val, &val_sz, NULL, &type, NULL, &data_sz ); - if( r != ERROR_SUCCESS ) - break; - if( type != REG_BINARY ) - continue; - - /* check the value is in the format we expect */ - if( val_sz < sizeof prefix ) - continue; - if( memcmp( prefix, val, 5 ) ) - continue; - - /* decode the value */ - for(j=5; j<val_sz; j+=2 ) - { - CHAR hi = ctox( val[j] ), lo = ctox( val[j+1] ); - if( ( hi < 0 ) || ( lo < 0 ) ) - break; - val[(j-5)/2] = (hi<<4) | lo; - } - - /* find the decoded length */ - val_sz = (j - 5)/2; - val[val_sz]=0; - if( val_sz < cbPrefix ) - continue; - - /* check the prefix matches */ - if( memcmp(val, pbPrefix, cbPrefix) ) - continue; - - /* read the value data */ - size = sizeof *entry - sizeof entry->abResource[0] + val_sz + data_sz; - entry = HeapAlloc( GetProcessHeap(), 0, sizeof *entry + val_sz + data_sz ); - memcpy( entry->abResource, val, val_sz ); - entry->cbEntry = size; - entry->cbResource = val_sz; - entry->cbPassword = data_sz; - entry->iEntry = i; - entry->nType = nType; - r = RegEnumValueA( hkey, i, NULL, &val_sz, NULL, &type, - &entry->abResource[val_sz], &data_sz ); - if( r == ERROR_SUCCESS ) - enumPasswordProc( entry, param ); - HeapFree( GetProcessHeap(), 0, entry ); - } - - RegCloseKey( hkey ); - - return WN_SUCCESS; -} +/* + * MPR Password Cache functions + * + * Copyright 1999 Ulrich Weigand + * Copyright 2003,2004 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> +#include <stdio.h> + +#include "windef.h" +#include "winbase.h" +#include "winnetwk.h" +#include "winreg.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mpr); + +static const char mpr_key[] = "Software\\Wine\\Wine\\Mpr\\"; + +static inline BYTE hex( BYTE x ) +{ + if( x <= 9 ) + return x + '0'; + return x + 'A' - 10; +} + +static inline CHAR ctox( CHAR x ) +{ + if( ( x >= '0' ) && ( x <= '9' ) ) + return x - '0'; + if( ( x >= 'A' ) && ( x <= 'F' ) ) + return x - 'A' + 10; + if( ( x >= 'a' ) && ( x <= 'a' ) ) + return x - 'a' + 10; + return -1; +} + +static LPSTR MPR_GetValueName( LPSTR pbResource, WORD cbResource, BYTE nType ) +{ + LPSTR name; + DWORD i; + + name = HeapAlloc( GetProcessHeap(), 0, 6+cbResource*2 ); + if( name ) + sprintf( name, "X-%02X-", nType ); + for(i=0; i<cbResource; i++) + { + name[5+i*2]=hex((pbResource[i]&0xf0)>>4); + name[6+i*2]=hex(pbResource[i]&0x0f); + } + name[5+i*2]=0; + TRACE( "Value is %s\n", name ); + return name; +} + + +/************************************************************************** + * WNetCachePassword [MPR.@] Saves password in cache + * + * NOTES + * only the parameter count is verifyed + * + * ---- everything below this line might be wrong (js) ----- + * RETURNS + * Success: WN_SUCCESS + * Failure: WN_ACCESS_DENIED, WN_BAD_PASSWORD, WN_BADVALUE, WN_NET_ERROR, + * WN_NOT_SUPPORTED, WN_OUT_OF_MEMORY + */ +DWORD WINAPI WNetCachePassword( + LPSTR pbResource, /* [in] Name of workgroup, computer, or resource */ + WORD cbResource, /* [in] Size of name */ + LPSTR pbPassword, /* [in] Buffer containing password */ + WORD cbPassword, /* [in] Size of password */ + BYTE nType, /* [in] Type of password to cache */ + WORD x) + +{ + HKEY hkey; + DWORD r; + LPSTR valname; + + WARN( "(%p(%s), %d, %p(%s), %d, %d, 0x%08x): totally insecure\n", + pbResource, debugstr_a(pbResource), cbResource, + pbPassword, debugstr_a(pbPassword), cbPassword, + nType, x ); + + /* @@ Wine registry key: HKCU\Software\Wine\Wine\Mpr */ + r = RegCreateKeyA( HKEY_CURRENT_USER, mpr_key, &hkey ); + if( r ) + return WN_ACCESS_DENIED; + + valname = MPR_GetValueName( pbResource, cbResource, nType ); + if( valname ) + { + r = RegSetValueExA( hkey, valname, 0, REG_BINARY, + pbPassword, cbPassword ); + if( r ) + r = WN_CANCEL; + else + r = WN_SUCCESS; + HeapFree( GetProcessHeap(), 0, valname ); + } + else + r = WN_OUT_OF_MEMORY; + + RegCloseKey( hkey ); + + return r; +} + +/***************************************************************** + * WNetRemoveCachedPassword [MPR.@] + */ +UINT WINAPI WNetRemoveCachedPassword( + LPSTR pbResource, /* [in] resource ID to delete */ + WORD cbResource, /* [in] number of bytes in the resource ID */ + BYTE nType ) /* [in] Type of the resource to delete */ +{ + HKEY hkey; + DWORD r; + LPSTR valname; + + WARN( "(%p(%s), %d, %d): totally insecure\n", + pbResource, debugstr_a(pbResource), cbResource, nType ); + + /* @@ Wine registry key: HKCU\Software\Wine\Wine\Mpr */ + r = RegCreateKeyA( HKEY_CURRENT_USER, mpr_key, &hkey ); + if( r ) + return WN_ACCESS_DENIED; + + valname = MPR_GetValueName( pbResource, cbResource, nType ); + if( valname ) + { + r = RegDeleteValueA( hkey, valname ); + if( r ) + r = WN_ACCESS_DENIED; + else + r = WN_SUCCESS; + HeapFree( GetProcessHeap(), 0, valname ); + } + else + r = WN_OUT_OF_MEMORY; + + return r; +} + +/***************************************************************** + * WNetGetCachedPassword [MPR.@] Retrieves password from cache + * + * NOTES + * the stub seems to be wrong: + * arg1: ptr 0x40xxxxxx -> (no string) + * arg2: len 36 + * arg3: ptr 0x40xxxxxx -> (no string) + * arg4: ptr 0x40xxxxxx -> 0xc8 + * arg5: type? 4 + * + * ---- everything below this line might be wrong (js) ----- + * RETURNS + * Success: WN_SUCCESS + * Failure: WN_ACCESS_DENIED, WN_BAD_PASSWORD, WN_BAD_VALUE, + * WN_NET_ERROR, WN_NOT_SUPPORTED, WN_OUT_OF_MEMORY + */ +DWORD WINAPI WNetGetCachedPassword( + LPSTR pbResource, /* [in] Name of workgroup, computer, or resource */ + WORD cbResource, /* [in] Size of name */ + LPSTR pbPassword, /* [out] Buffer to receive password */ + LPWORD pcbPassword, /* [out] Receives size of password */ + BYTE nType) /* [in] Type of password to retrieve */ +{ + HKEY hkey; + DWORD r, type = 0, sz; + LPSTR valname; + + WARN( "(%p(%s), %d, %p, %p, %d): totally insecure\n", + pbResource, debugstr_a(pbResource), cbResource, + pbPassword, pcbPassword, nType ); + + memset( pbPassword, 0, *pcbPassword); + + /* @@ Wine registry key: HKCU\Software\Wine\Wine\Mpr */ + r = RegCreateKeyA( HKEY_CURRENT_USER, mpr_key, &hkey ); + if( r ) + return WN_ACCESS_DENIED; + + valname = MPR_GetValueName( pbResource, cbResource, nType ); + if( valname ) + { + sz = *pcbPassword; + r = RegQueryValueExA( hkey, valname, 0, &type, pbPassword, &sz ); + *pcbPassword = sz; + if( r ) + r = WN_CANCEL; + else + r = WN_SUCCESS; + HeapFree( GetProcessHeap(), 0, valname ); + } + else + r = WN_OUT_OF_MEMORY; + + return r; +} + +/******************************************************************* + * WNetEnumCachedPasswords [MPR.@] + * + * NOTES + * the parameter count is verifyed + * + * This function is a huge security risk, as virii and such can use + * it to grab all the passwords in the cache. It's bad enough to + * store the passwords (insecurely). + * + * bpPrefix and cbPrefix are used to filter the returned passwords + * the first cbPrefix bytes of the password resource identifier + * should match the same number of bytes in bpPrefix + * + * RETURNS + * Success: WN_SUCCESS (even if no entries were enumerated) + * Failure: WN_ACCESS_DENIED, WN_BAD_PASSWORD, WN_BAD_VALUE, + * WN_NET_ERROR, WN_NOT_SUPPORTED, WN_OUT_OF_MEMORY + */ + +UINT WINAPI WNetEnumCachedPasswords( + LPSTR pbPrefix, /* [in] prefix to filter cache entries */ + WORD cbPrefix, /* [in] number of bytes in Prefix substring */ + BYTE nType, /* [in] match the Type ID of the entry */ + ENUMPASSWORDPROC enumPasswordProc, /* [in] callback function */ + DWORD param) /* [in] parameter passed to enum function */ +{ + HKEY hkey; + DWORD r, type, val_sz, data_sz, i, j, size; + PASSWORD_CACHE_ENTRY *entry; + CHAR val[256], prefix[6]; + + WARN( "(%s, %d, %d, %p, 0x%08lx) totally insecure\n", + debugstr_an(pbPrefix,cbPrefix), cbPrefix, + nType, enumPasswordProc, param ); + + /* @@ Wine registry key: HKCU\Software\Wine\Wine\Mpr */ + r = RegCreateKeyA( HKEY_CURRENT_USER, mpr_key, &hkey ); + if( r ) + return WN_ACCESS_DENIED; + + sprintf(prefix, "X-%02X-", nType ); + + i = 0; + for( i=0; ; i++ ) + { + val_sz = sizeof val; + data_sz = 0; + type = 0; + val[0] = 0; + r = RegEnumValueA( hkey, i, val, &val_sz, NULL, &type, NULL, &data_sz ); + if( r != ERROR_SUCCESS ) + break; + if( type != REG_BINARY ) + continue; + + /* check the value is in the format we expect */ + if( val_sz < sizeof prefix ) + continue; + if( memcmp( prefix, val, 5 ) ) + continue; + + /* decode the value */ + for(j=5; j<val_sz; j+=2 ) + { + CHAR hi = ctox( val[j] ), lo = ctox( val[j+1] ); + if( ( hi < 0 ) || ( lo < 0 ) ) + break; + val[(j-5)/2] = (hi<<4) | lo; + } + + /* find the decoded length */ + val_sz = (j - 5)/2; + val[val_sz]=0; + if( val_sz < cbPrefix ) + continue; + + /* check the prefix matches */ + if( memcmp(val, pbPrefix, cbPrefix) ) + continue; + + /* read the value data */ + size = sizeof *entry - sizeof entry->abResource[0] + val_sz + data_sz; + entry = HeapAlloc( GetProcessHeap(), 0, sizeof *entry + val_sz + data_sz ); + memcpy( entry->abResource, val, val_sz ); + entry->cbEntry = size; + entry->cbResource = val_sz; + entry->cbPassword = data_sz; + entry->iEntry = i; + entry->nType = nType; + r = RegEnumValueA( hkey, i, NULL, &val_sz, NULL, &type, + &entry->abResource[val_sz], &data_sz ); + if( r == ERROR_SUCCESS ) + enumPasswordProc( entry, param ); + HeapFree( GetProcessHeap(), 0, entry ); + } + + RegCloseKey( hkey ); + + return WN_SUCCESS; +} diff --git a/reactos/lib/mpr/wnet.c b/reactos/lib/mpr/wnet.c index a5ee8473828..3b585c07b13 100644 --- a/reactos/lib/mpr/wnet.c +++ b/reactos/lib/mpr/wnet.c @@ -1,2038 +1,2038 @@ -/* - * MPR WNet functions - * - * Copyright 1999 Ulrich Weigand - * Copyright 2004 Juan Lang - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "winnls.h" -#include "winnetwk.h" -#include "npapi.h" -#include "winreg.h" -#include "winuser.h" -#include "wine/debug.h" -#include "wine/unicode.h" -#include "mprres.h" -#include "wnetpriv.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mpr); - -/* Data structures representing network service providers. Assumes only one - * thread creates them, and that they are constant for the life of the process - * (and therefore doesn't synchronize access). - * FIXME: only basic provider data and enumeration-related data are implemented - * so far, need to implement the rest too. - */ -typedef struct _WNetProvider -{ - HMODULE hLib; - PWSTR name; - PF_NPGetCaps getCaps; - DWORD dwSpecVersion; - DWORD dwNetType; - DWORD dwEnumScopes; - PF_NPOpenEnum openEnum; - PF_NPEnumResource enumResource; - PF_NPCloseEnum closeEnum; -} WNetProvider, *PWNetProvider; - -typedef struct _WNetProviderTable -{ - LPWSTR entireNetwork; - DWORD numAllocated; - DWORD numProviders; - WNetProvider table[1]; -} WNetProviderTable, *PWNetProviderTable; - -#define WNET_ENUMERATOR_TYPE_NULL 0 -#define WNET_ENUMERATOR_TYPE_GLOBAL 1 -#define WNET_ENUMERATOR_TYPE_PROVIDER 2 -#define WNET_ENUMERATOR_TYPE_CONTEXT 3 - -/* An WNet enumerator. Note that the type doesn't correspond to the scope of - * the enumeration; it represents one of the following types: - * - a 'null' enumeration, one that contains no members - * - a global enumeration, one that's executed across all providers - * - a provider-specific enumeration, one that's only executed by a single - * provider - * - a context enumeration. I know this contradicts what I just said about - * there being no correspondence between the scope and the type, but it's - * necessary for the special case that a "Entire Network" entry needs to - * be enumerated in an enumeration of the context scope. Thus an enumeration - * of the context scope results in a context type enumerator, which morphs - * into a global enumeration (so the enumeration continues across all - * providers). - */ -typedef struct _WNetEnumerator -{ - DWORD enumType; - DWORD providerIndex; - HANDLE handle; - BOOL providerDone; - DWORD dwScope; - DWORD dwType; - DWORD dwUsage; - LPNETRESOURCEW lpNet; -} WNetEnumerator, *PWNetEnumerator; - -#define BAD_PROVIDER_INDEX (DWORD)0xffffffff - -/* Returns an index (into the global WNetProviderTable) of the provider with - * the given name, or BAD_PROVIDER_INDEX if not found. - */ -static DWORD _findProviderIndexW(LPCWSTR lpProvider); - -PWNetProviderTable providerTable; - -/* - * Global provider table functions - */ - -static void _tryLoadProvider(PCWSTR provider) -{ - static const WCHAR servicePrefix[] = { 'S','y','s','t','e','m','\\', - 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', - 'S','e','r','v','i','c','e','s','\\',0 }; - static const WCHAR serviceFmt[] = { '%','s','%','s','\\', - 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 }; - WCHAR serviceName[MAX_PATH]; - HKEY hKey; - - TRACE("%s\n", debugstr_w(provider)); - snprintfW(serviceName, sizeof(serviceName) / sizeof(WCHAR), serviceFmt, - servicePrefix, provider); - serviceName[sizeof(serviceName) / sizeof(WCHAR) - 1] = '\0'; - if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, serviceName, 0, KEY_READ, &hKey) == - ERROR_SUCCESS) - { - static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r', - 'P','a','t','h',0 }; - WCHAR providerPath[MAX_PATH]; - DWORD type, size = sizeof(providerPath); - - if (RegQueryValueExW(hKey, szProviderPath, NULL, &type, - (LPBYTE)providerPath, &size) == ERROR_SUCCESS && type == REG_SZ) - { - static const WCHAR szProviderName[] = { 'N','a','m','e',0 }; - PWSTR name = NULL; - - size = 0; - RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &size); - if (size) - { - name = HeapAlloc(GetProcessHeap(), 0, size); - if (RegQueryValueExW(hKey, szProviderName, NULL, &type, - (LPBYTE)name, &size) != ERROR_SUCCESS || type != REG_SZ) - { - HeapFree(GetProcessHeap(), 0, name); - name = NULL; - } - } - if (name) - { - HMODULE hLib = LoadLibraryW(providerPath); - - if (hLib) - { - PF_NPGetCaps getCaps = (PF_NPGetCaps)GetProcAddress(hLib, - "NPGetCaps"); - - TRACE("loaded lib %p\n", hLib); - if (getCaps) - { - PWNetProvider provider = - &providerTable->table[providerTable->numProviders]; - - provider->hLib = hLib; - provider->name = name; - TRACE("name is %s\n", debugstr_w(name)); - provider->getCaps = getCaps; - provider->dwSpecVersion = getCaps(WNNC_SPEC_VERSION); - provider->dwNetType = getCaps(WNNC_NET_TYPE); - TRACE("net type is 0x%08lx\n", provider->dwNetType); - provider->dwEnumScopes = getCaps(WNNC_ENUMERATION); - if (provider->dwEnumScopes) - { - TRACE("supports enumeration\n"); - provider->openEnum = (PF_NPOpenEnum) - GetProcAddress(hLib, "NPOpenEnum"); - TRACE("openEnum is %p\n", provider->openEnum); - provider->enumResource = (PF_NPEnumResource) - GetProcAddress(hLib, "NPEnumResource"); - TRACE("enumResource is %p\n", - provider->enumResource); - provider->closeEnum = (PF_NPCloseEnum) - GetProcAddress(hLib, "NPCloseEnum"); - TRACE("closeEnum is %p\n", provider->closeEnum); - if (!provider->openEnum || !provider->enumResource - || !provider->closeEnum) - { - provider->openEnum = NULL; - provider->enumResource = NULL; - provider->closeEnum = NULL; - provider->dwEnumScopes = 0; - WARN("Couldn't load enumeration functions\n"); - } - } - providerTable->numProviders++; - } - else - { - WARN("Provider %s didn't export NPGetCaps\n", - debugstr_w(provider)); - HeapFree(GetProcessHeap(), 0, name); - FreeLibrary(hLib); - } - } - else - { - WARN("Couldn't load library %s for provider %s\n", - debugstr_w(providerPath), debugstr_w(provider)); - HeapFree(GetProcessHeap(), 0, name); - } - } - else - { - WARN("Couldn't get provider name for provider %s\n", - debugstr_w(provider)); - } - } - else - WARN("Couldn't open value %s\n", debugstr_w(szProviderPath)); - RegCloseKey(hKey); - } - else - WARN("Couldn't open service key for provider %s\n", - debugstr_w(provider)); -} - -void wnetInit(HINSTANCE hInstDll) -{ - static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\', - 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', - 'C','o','n','t','r','o','l','\\', - 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\', - 'O','r','d','e','r',0 }; - static const WCHAR providerOrder[] = { 'P','r','o','v','i','d','e','r', - 'O','r','d','e','r',0 }; - HKEY hKey; - - if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey) - == ERROR_SUCCESS) - { - DWORD size = 0; - - RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size); - if (size) - { - PWSTR providers = HeapAlloc(GetProcessHeap(), 0, size); - - if (providers) - { - DWORD type; - - if (RegQueryValueExW(hKey, providerOrder, NULL, &type, - (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ) - { - PWSTR ptr; - DWORD numToAllocate; - - TRACE("provider order is %s\n", debugstr_w(providers)); - /* first count commas as a heuristic for how many to - * allocate space for */ - for (ptr = providers, numToAllocate = 1; ptr; ) - { - ptr = strchrW(ptr, ','); - if (ptr) - numToAllocate++; - } - providerTable = - HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(WNetProviderTable) - + (numToAllocate - 1) * sizeof(WNetProvider)); - if (providerTable) - { - PWSTR ptrPrev; - int entireNetworkLen; - - entireNetworkLen = LoadStringW(hInstDll, - IDS_ENTIRENETWORK, NULL, 0); - providerTable->entireNetwork = HeapAlloc( - GetProcessHeap(), 0, (entireNetworkLen + 1) * - sizeof(WCHAR)); - if (providerTable->entireNetwork) - LoadStringW(hInstDll, IDS_ENTIRENETWORK, - providerTable->entireNetwork, - entireNetworkLen + 1); - providerTable->numAllocated = numToAllocate; - for (ptr = providers; ptr; ) - { - ptrPrev = ptr; - ptr = strchrW(ptr, ','); - if (ptr) - *ptr = '\0'; - _tryLoadProvider(ptrPrev); - } - } - } - HeapFree(GetProcessHeap(), 0, providers); - } - } - RegCloseKey(hKey); - } -} - -void wnetFree(void) -{ - if (providerTable) - { - DWORD i; - - for (i = 0; i < providerTable->numProviders; i++) - { - HeapFree(GetProcessHeap(), 0, providerTable->table[i].name); - FreeModule(providerTable->table[i].hLib); - } - HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork); - HeapFree(GetProcessHeap(), 0, providerTable); - providerTable = NULL; - } -} - -static DWORD _findProviderIndexW(LPCWSTR lpProvider) -{ - DWORD ret = BAD_PROVIDER_INDEX; - - if (providerTable && providerTable->numProviders) - { - DWORD i; - - for (i = 0; i < providerTable->numProviders && - ret == BAD_PROVIDER_INDEX; i++) - if (!strcmpW(lpProvider, providerTable->table[i].name)) - ret = i; - } - return ret; -} - -/* - * Browsing Functions - */ - -static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet) -{ - LPNETRESOURCEW ret; - - if (lpNet) - { - ret = HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW)); - if (ret) - { - size_t len; - - memcpy(ret, lpNet, sizeof(ret)); - ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL; - if (lpNet->lpRemoteName) - { - len = strlenW(lpNet->lpRemoteName) + 1; - ret->lpRemoteName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); - if (ret->lpRemoteName) - strcpyW(ret->lpRemoteName, lpNet->lpRemoteName); - } - } - } - else - ret = NULL; - return ret; -} - -static void _freeEnumNetResource(LPNETRESOURCEW lpNet) -{ - if (lpNet) - { - HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName); - HeapFree(GetProcessHeap(), 0, lpNet); - } -} - -static PWNetEnumerator _createNullEnumerator(void) -{ - PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, sizeof(WNetEnumerator)); - - if (ret) - ret->enumType = WNET_ENUMERATOR_TYPE_NULL; - return ret; -} - -static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType, - DWORD dwUsage, LPNETRESOURCEW lpNet) -{ - PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, sizeof(WNetEnumerator)); - - if (ret) - { - ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL; - ret->dwScope = dwScope; - ret->dwType = dwType; - ret->dwUsage = dwUsage; - ret->lpNet = _copyNetResourceForEnumW(lpNet); - } - return ret; -} - -static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType, - DWORD dwUsage, DWORD index, HANDLE handle) -{ - PWNetEnumerator ret; - - if (!providerTable || index >= providerTable->numProviders) - ret = NULL; - else - { - ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator)); - if (ret) - { - ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER; - ret->providerIndex = index; - ret->dwScope = dwScope; - ret->dwType = dwType; - ret->dwUsage = dwUsage; - ret->handle = handle; - } - } - return ret; -} - -static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType, - DWORD dwUsage) -{ - PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, sizeof(WNetEnumerator)); - - if (ret) - { - ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT; - ret->dwScope = dwScope; - ret->dwType = dwType; - ret->dwUsage = dwUsage; - } - return ret; -} - -/* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer - * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries - * to start. On return, *lpcCount reflects the number thunked into lpBuffer. - * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA - * if not all members of the array could be thunked, and something else on - * failure. - */ -static DWORD _thunkNetResourceArrayWToA(const LPNETRESOURCEW lpNetArrayIn, - LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) -{ - DWORD i, numToThunk, totalBytes, ret; - LPSTR strNext; - - if (!lpNetArrayIn) - return WN_BAD_POINTER; - if (!lpcCount) - return WN_BAD_POINTER; - if (*lpcCount == -1) - return WN_BAD_VALUE; - if (!lpBuffer) - return WN_BAD_POINTER; - if (!lpBufferSize) - return WN_BAD_POINTER; - - for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++) - { - LPNETRESOURCEW lpNet = lpNetArrayIn + i; - - totalBytes += sizeof(NETRESOURCEA); - if (lpNet->lpLocalName) - totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName, - -1, NULL, 0, NULL, NULL); - if (lpNet->lpRemoteName) - totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName, - -1, NULL, 0, NULL, NULL); - if (lpNet->lpComment) - totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment, - -1, NULL, 0, NULL, NULL); - if (lpNet->lpProvider) - totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider, - -1, NULL, 0, NULL, NULL); - if (totalBytes < *lpBufferSize) - numToThunk = i + 1; - } - strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA)); - for (i = 0; i < numToThunk; i++) - { - LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i; - LPNETRESOURCEW lpNetIn = lpNetArrayIn + i; - - memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA)); - /* lie about string lengths, we already verified how many - * we have space for above - */ - if (lpNetIn->lpLocalName) - { - lpNetOut->lpLocalName = strNext; - strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1, - lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL); - } - if (lpNetIn->lpRemoteName) - { - lpNetOut->lpRemoteName = strNext; - strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1, - lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL); - } - if (lpNetIn->lpComment) - { - lpNetOut->lpComment = strNext; - strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1, - lpNetOut->lpComment, *lpBufferSize, NULL, NULL); - } - if (lpNetIn->lpProvider) - { - lpNetOut->lpProvider = strNext; - strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1, - lpNetOut->lpProvider, *lpBufferSize, NULL, NULL); - } - } - ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS; - TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk, - *lpcCount, ret); - return ret; -} - -/* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer - * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries - * to start. On return, *lpcCount reflects the number thunked into lpBuffer. - * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA - * if not all members of the array could be thunked, and something else on - * failure. - */ -static DWORD _thunkNetResourceArrayAToW(const LPNETRESOURCEA lpNetArrayIn, - LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) -{ - DWORD i, numToThunk, totalBytes, ret; - LPWSTR strNext; - - if (!lpNetArrayIn) - return WN_BAD_POINTER; - if (!lpcCount) - return WN_BAD_POINTER; - if (*lpcCount == -1) - return WN_BAD_VALUE; - if (!lpBuffer) - return WN_BAD_POINTER; - if (!lpBufferSize) - return WN_BAD_POINTER; - - for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++) - { - LPNETRESOURCEA lpNet = lpNetArrayIn + i; - - totalBytes += sizeof(NETRESOURCEW); - if (lpNet->lpLocalName) - totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName, - -1, NULL, 0) * sizeof(WCHAR); - if (lpNet->lpRemoteName) - totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName, - -1, NULL, 0) * sizeof(WCHAR); - if (lpNet->lpComment) - totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment, - -1, NULL, 0) * sizeof(WCHAR); - if (lpNet->lpProvider) - totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider, - -1, NULL, 0) * sizeof(WCHAR); - if (totalBytes < *lpBufferSize) - numToThunk = i + 1; - } - strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW)); - for (i = 0; i < numToThunk; i++) - { - LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i; - LPNETRESOURCEA lpNetIn = lpNetArrayIn + i; - - memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW)); - /* lie about string lengths, we already verified how many - * we have space for above - */ - if (lpNetIn->lpLocalName) - { - lpNetOut->lpLocalName = strNext; - strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName, - -1, lpNetOut->lpLocalName, *lpBufferSize); - } - if (lpNetIn->lpRemoteName) - { - lpNetOut->lpRemoteName = strNext; - strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName, - -1, lpNetOut->lpRemoteName, *lpBufferSize); - } - if (lpNetIn->lpComment) - { - lpNetOut->lpComment = strNext; - strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment, - -1, lpNetOut->lpComment, *lpBufferSize); - } - if (lpNetIn->lpProvider) - { - lpNetOut->lpProvider = strNext; - strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider, - -1, lpNetOut->lpProvider, *lpBufferSize); - } - } - ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS; - TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk, - *lpcCount, ret); - return ret; -} - -/********************************************************************* - * WNetOpenEnumA [MPR.@] - * - * See comments for WNetOpenEnumW. - */ -DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage, - LPNETRESOURCEA lpNet, LPHANDLE lphEnum ) -{ - DWORD ret; - - TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n", - dwScope, dwType, dwUsage, lpNet, lphEnum ); - - if (!lphEnum) - ret = WN_BAD_POINTER; - else if (!providerTable || providerTable->numProviders == 0) - ret = WN_NO_NETWORK; - else - { - if (lpNet) - { - LPNETRESOURCEW lpNetWide = NULL; - BYTE buf[1024]; - DWORD size = sizeof(buf), count = 1; - BOOL allocated = FALSE; - - ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size); - if (ret == WN_MORE_DATA) - { - lpNetWide = HeapAlloc(GetProcessHeap(), 0, - size); - if (lpNetWide) - { - ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide, - &size); - allocated = TRUE; - } - else - ret = WN_OUT_OF_MEMORY; - } - else if (ret == WN_SUCCESS) - lpNetWide = (LPNETRESOURCEW)buf; - if (ret == WN_SUCCESS) - ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide, - lphEnum); - if (allocated && lpNetWide) - HeapFree(GetProcessHeap(), 0, lpNetWide); - } - else - ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum); - } - if (ret) - SetLastError(ret); - TRACE("Returning %ld\n", ret); - return ret; -} - -/********************************************************************* - * WNetOpenEnumW [MPR.@] - * - * Network enumeration has way too many parameters, so I'm not positive I got - * them right. What I've got so far: - * - * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed, - * all the network providers should be enumerated. - * - * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and - * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's - * lpProvider is set, all the network providers should be enumerated. - * (This means the enumeration is a list of network providers, not that the - * enumeration is passed on to the providers.) - * - * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the - * resource matches the "Entire Network" resource (no remote name, no - * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET - * enumeration is done on every network provider. - * - * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and - * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through - * only to the given network provider. - * - * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and - * no lpProvider is set, enumeration will be tried on every network provider, - * in the order in which they're loaded. - * - * - The LPNETRESOURCE should be disregarded for scopes besides - * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not - * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL. - * - * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net - * resource in the enumerated list, as well as any machines in your - * workgroup. The machines in your workgroup come from doing a - * RESOURCE_CONTEXT enumeration of every Network Provider. - */ -DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage, - LPNETRESOURCEW lpNet, LPHANDLE lphEnum ) -{ - DWORD ret; - - TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n", - dwScope, dwType, dwUsage, lpNet, lphEnum ); - - if (!lphEnum) - ret = WN_BAD_POINTER; - else if (!providerTable || providerTable->numProviders == 0) - ret = WN_NO_NETWORK; - else - { - switch (dwScope) - { - case RESOURCE_GLOBALNET: - if (lpNet) - { - if (lpNet->lpProvider) - { - DWORD index = _findProviderIndexW(lpNet->lpProvider); - - if (index != BAD_PROVIDER_INDEX) - { - if (providerTable->table[index].openEnum && - providerTable->table[index].dwEnumScopes & dwScope) - { - HANDLE handle; - - ret = providerTable->table[index].openEnum( - dwScope, dwType, dwUsage, lpNet, &handle); - if (ret == WN_SUCCESS) - { - *lphEnum = - (HANDLE)_createProviderEnumerator( - dwScope, dwType, dwUsage, index, handle); - ret = *lphEnum ? WN_SUCCESS : - WN_OUT_OF_MEMORY; - } - } - else - ret = WN_NOT_SUPPORTED; - } - else - ret = WN_BAD_PROVIDER; - } - else if (lpNet->lpRemoteName) - { - *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope, - dwType, dwUsage, lpNet); - ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; - } - else - { - if (lpNet->lpComment && !strcmpW(lpNet->lpComment, - providerTable->entireNetwork)) - { - /* comment matches the "Entire Network", enumerate - * global scope of every provider - */ - *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope, - dwType, dwUsage, lpNet); - } - else - { - /* this is the same as not having passed lpNet */ - *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope, - dwType, dwUsage, NULL); - } - ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; - } - } - else - { - *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope, dwType, - dwUsage, lpNet); - ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; - } - break; - case RESOURCE_CONTEXT: - *lphEnum = (HANDLE)_createContextEnumerator(dwScope, dwType, - dwUsage); - ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; - break; - case RESOURCE_REMEMBERED: - case RESOURCE_CONNECTED: - *lphEnum = (HANDLE)_createNullEnumerator(); - ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; - break; - default: - WARN("unknown scope 0x%08lx\n", dwScope); - ret = WN_BAD_VALUE; - } - } - if (ret) - SetLastError(ret); - TRACE("Returning %ld\n", ret); - return ret; -} - -/********************************************************************* - * WNetEnumResourceA [MPR.@] - */ -DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount, - LPVOID lpBuffer, LPDWORD lpBufferSize ) -{ - DWORD ret; - - TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize ); - - if (!hEnum) - ret = WN_BAD_POINTER; - else if (!lpcCount) - ret = WN_BAD_POINTER; - if (!lpBuffer) - ret = WN_BAD_POINTER; - else if (!lpBufferSize) - ret = WN_BAD_POINTER; - else if (*lpBufferSize < sizeof(NETRESOURCEA)) - { - *lpBufferSize = sizeof(NETRESOURCEA); - ret = WN_MORE_DATA; - } - else - { - DWORD localCount = *lpcCount, localSize = *lpBufferSize; - LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize); - - if (localBuffer) - { - ret = WNetEnumResourceW(hEnum, &localCount, localBuffer, - &localSize); - if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1)) - { - /* FIXME: this isn't necessarily going to work in the case of - * WN_MORE_DATA, because our enumerator may have moved on to - * the next provider. MSDN states that a large (16KB) buffer - * size is the appropriate usage of this function, so - * hopefully it won't be an issue. - */ - ret = _thunkNetResourceArrayWToA((LPNETRESOURCEW)localBuffer, - &localCount, lpBuffer, lpBufferSize); - *lpcCount = localCount; - } - HeapFree(GetProcessHeap(), 0, localBuffer); - } - else - ret = WN_OUT_OF_MEMORY; - } - if (ret) - SetLastError(ret); - TRACE("Returning %ld\n", ret); - return ret; -} - -static DWORD _countProviderBytesW(PWNetProvider provider) -{ - DWORD ret; - - if (provider) - { - ret = sizeof(NETRESOURCEW); - ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR); - } - else - ret = 0; - return ret; -} - -static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount, - LPVOID lpBuffer, LPDWORD lpBufferSize) -{ - DWORD ret; - - if (!enumerator) - return WN_BAD_POINTER; - if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL) - return WN_BAD_VALUE; - if (!lpcCount) - return WN_BAD_POINTER; - if (!lpBuffer) - return WN_BAD_POINTER; - if (!lpBufferSize) - return WN_BAD_POINTER; - if (*lpBufferSize < sizeof(NETRESOURCEA)) - return WN_MORE_DATA; - - if (!providerTable || enumerator->providerIndex >= - providerTable->numProviders) - ret = WN_NO_MORE_ENTRIES; - else - { - DWORD bytes = 0, count = 0, countLimit, i; - LPNETRESOURCEW resource; - LPWSTR strNext; - - countLimit = *lpcCount == -1 ? - providerTable->numProviders - enumerator->providerIndex : *lpcCount; - while (count < countLimit && bytes < *lpBufferSize) - { - DWORD bytesNext = _countProviderBytesW( - &providerTable->table[count + enumerator->providerIndex]); - - if (bytes + bytesNext < *lpBufferSize) - { - bytes += bytesNext; - count++; - } - } - strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW)); - for (i = 0, resource = (LPNETRESOURCEW)lpBuffer; i < count; - i++, resource++) - { - resource->dwScope = RESOURCE_GLOBALNET; - resource->dwType = RESOURCETYPE_ANY; - resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK; - resource->dwUsage = RESOURCEUSAGE_CONTAINER | - RESOURCEUSAGE_RESERVED; - resource->lpLocalName = NULL; - resource->lpRemoteName = strNext; - strcpyW(resource->lpRemoteName, - providerTable->table[i + enumerator->providerIndex].name); - strNext += strlenW(resource->lpRemoteName) + 1; - resource->lpComment = NULL; - resource->lpProvider = strNext; - strcpyW(resource->lpProvider, - providerTable->table[i + enumerator->providerIndex].name); - strNext += strlenW(resource->lpProvider) + 1; - } - enumerator->providerIndex += count; - *lpcCount = count; - ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA; - } - TRACE("Returning %ld\n", ret); - return ret; -} - -/* Advances the enumerator (assumed to be a global enumerator) to the next - * provider that supports the enumeration scope passed to WNetOpenEnum. Does - * not open a handle with the next provider. - * If the existing handle is NULL, may leave the enumerator unchanged, since - * the current provider may support the desired scope. - * If the existing handle is not NULL, closes it before moving on. - * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available - * provider, and another error on failure. - */ -static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator) -{ - if (!enumerator) - return WN_BAD_POINTER; - if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL) - return WN_BAD_VALUE; - if (!providerTable || enumerator->providerIndex >= - providerTable->numProviders) - return WN_NO_MORE_ENTRIES; - - if (enumerator->providerDone) - { - enumerator->providerDone = FALSE; - if (enumerator->handle) - { - providerTable->table[enumerator->providerIndex].closeEnum( - enumerator->handle); - enumerator->handle = NULL; - enumerator->providerIndex++; - } - for (; enumerator->providerIndex < providerTable->numProviders && - !(enumerator->dwScope & providerTable->table - [enumerator->providerIndex].dwEnumScopes); - enumerator->providerIndex++) - ; - } - return enumerator->providerIndex < providerTable->numProviders ? - WN_SUCCESS : WN_NO_MORE_ENTRIES; -} - -/* "Passes through" call to the next provider that supports the enumeration - * type. - * FIXME: if one call to a provider's enumerator succeeds while there's still - * space in lpBuffer, I don't call to the next provider. The caller may not - * expect that it should call EnumResourceW again with a return value of - * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings - * may have to be moved around a bit, ick. - */ -static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator, - LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) -{ - DWORD ret; - - if (!enumerator) - return WN_BAD_POINTER; - if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL) - return WN_BAD_VALUE; - if (!lpcCount) - return WN_BAD_POINTER; - if (!lpBuffer) - return WN_BAD_POINTER; - if (!lpBufferSize) - return WN_BAD_POINTER; - if (*lpBufferSize < sizeof(NETRESOURCEW)) - return WN_MORE_DATA; - - ret = _globalEnumeratorAdvance(enumerator); - if (ret == WN_SUCCESS) - { - ret = providerTable->table[enumerator->providerIndex]. - openEnum(enumerator->dwScope, enumerator->dwType, - enumerator->dwUsage, enumerator->lpNet, - &enumerator->handle); - if (ret == WN_SUCCESS) - { - ret = providerTable->table[enumerator->providerIndex]. - enumResource(enumerator->handle, lpcCount, lpBuffer, - lpBufferSize); - if (ret != WN_MORE_DATA) - enumerator->providerDone = TRUE; - } - } - TRACE("Returning %ld\n", ret); - return ret; -} - -static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount, - LPVOID lpBuffer, LPDWORD lpBufferSize) -{ - DWORD ret; - - if (!enumerator) - return WN_BAD_POINTER; - if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL) - return WN_BAD_VALUE; - if (!lpcCount) - return WN_BAD_POINTER; - if (!lpBuffer) - return WN_BAD_POINTER; - if (!lpBufferSize) - return WN_BAD_POINTER; - if (*lpBufferSize < sizeof(NETRESOURCEW)) - return WN_MORE_DATA; - if (!providerTable) - return WN_NO_NETWORK; - - switch (enumerator->dwScope) - { - case RESOURCE_GLOBALNET: - if (enumerator->lpNet) - ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, - lpBuffer, lpBufferSize); - else - ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer, - lpBufferSize); - break; - case RESOURCE_CONTEXT: - ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer, - lpBufferSize); - break; - default: - WARN("unexpected scope 0x%08lx\n", enumerator->dwScope); - ret = WN_NO_MORE_ENTRIES; - } - TRACE("Returning %ld\n", ret); - return ret; -} - -static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount, - LPVOID lpBuffer, LPDWORD lpBufferSize) -{ - if (!enumerator) - return WN_BAD_POINTER; - if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER) - return WN_BAD_VALUE; - if (!enumerator->handle) - return WN_BAD_VALUE; - if (!lpcCount) - return WN_BAD_POINTER; - if (!lpBuffer) - return WN_BAD_POINTER; - if (!lpBufferSize) - return WN_BAD_POINTER; - if (!providerTable) - return WN_NO_NETWORK; - if (enumerator->providerIndex >= providerTable->numProviders) - return WN_NO_MORE_ENTRIES; - if (!providerTable->table[enumerator->providerIndex].enumResource) - return WN_BAD_VALUE; - return providerTable->table[enumerator->providerIndex].enumResource( - enumerator->handle, lpcCount, lpBuffer, lpBufferSize); -} - -static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount, - LPVOID lpBuffer, LPDWORD lpBufferSize) -{ - DWORD ret; - size_t cchEntireNetworkLen, bytesNeeded; - - if (!enumerator) - return WN_BAD_POINTER; - if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT) - return WN_BAD_VALUE; - if (!lpcCount) - return WN_BAD_POINTER; - if (!lpBuffer) - return WN_BAD_POINTER; - if (!lpBufferSize) - return WN_BAD_POINTER; - if (!providerTable) - return WN_NO_NETWORK; - - cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1; - bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR); - if (*lpBufferSize < bytesNeeded) - { - *lpBufferSize = bytesNeeded; - ret = WN_MORE_DATA; - } - else - { - LPNETRESOURCEW lpNet = (LPNETRESOURCEW)lpBuffer; - - lpNet->dwScope = RESOURCE_GLOBALNET; - lpNet->dwType = enumerator->dwType; - lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT; - lpNet->dwUsage = RESOURCEUSAGE_CONTAINER; - lpNet->lpLocalName = NULL; - lpNet->lpRemoteName = NULL; - lpNet->lpProvider = NULL; - /* odd, but correct: put comment at end of buffer, so it won't get - * overwritten by subsequent calls to a provider's enumResource - */ - lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize - - (cchEntireNetworkLen * sizeof(WCHAR))); - strcpyW(lpNet->lpComment, providerTable->entireNetwork); - ret = WN_SUCCESS; - } - if (ret == WN_SUCCESS) - { - DWORD bufferSize = *lpBufferSize - bytesNeeded; - - /* "Entire Network" entry enumerated--morph this into a global - * enumerator. enumerator->lpNet continues to be NULL, since it has - * no meaning when the scope isn't RESOURCE_GLOBALNET. - */ - enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL; - ret = _enumerateGlobalW(enumerator, lpcCount, - (LPBYTE)lpBuffer + bytesNeeded, &bufferSize); - if (ret == WN_SUCCESS) - { - /* reflect the fact that we already enumerated "Entire Network" */ - lpcCount++; - *lpBufferSize = bufferSize + bytesNeeded; - } - else - { - /* the provider enumeration failed, but we already succeeded in - * enumerating "Entire Network"--leave type as global to allow a - * retry, but indicate success with a count of one. - */ - ret = WN_SUCCESS; - *lpcCount = 1; - *lpBufferSize = bytesNeeded; - } - } - TRACE("Returning %ld\n", ret); - return ret; -} - -/********************************************************************* - * WNetEnumResourceW [MPR.@] - */ -DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount, - LPVOID lpBuffer, LPDWORD lpBufferSize ) -{ - DWORD ret; - - TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize ); - - if (!hEnum) - ret = WN_BAD_POINTER; - else if (!lpcCount) - ret = WN_BAD_POINTER; - else if (!lpBuffer) - ret = WN_BAD_POINTER; - else if (!lpBufferSize) - ret = WN_BAD_POINTER; - else if (*lpBufferSize < sizeof(NETRESOURCEW)) - { - *lpBufferSize = sizeof(NETRESOURCEW); - ret = WN_MORE_DATA; - } - else - { - PWNetEnumerator enumerator = (PWNetEnumerator)hEnum; - - switch (enumerator->enumType) - { - case WNET_ENUMERATOR_TYPE_NULL: - ret = WN_NO_MORE_ENTRIES; - break; - case WNET_ENUMERATOR_TYPE_GLOBAL: - ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer, - lpBufferSize); - break; - case WNET_ENUMERATOR_TYPE_PROVIDER: - ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer, - lpBufferSize); - break; - case WNET_ENUMERATOR_TYPE_CONTEXT: - ret = _enumerateContextW(enumerator, lpcCount, lpBuffer, - lpBufferSize); - break; - default: - WARN("bogus enumerator type!\n"); - ret = WN_NO_NETWORK; - } - } - if (ret) - SetLastError(ret); - TRACE("Returning %ld\n", ret); - return ret; -} - -/********************************************************************* - * WNetCloseEnum [MPR.@] - */ -DWORD WINAPI WNetCloseEnum( HANDLE hEnum ) -{ - DWORD ret; - - TRACE( "(%p)\n", hEnum ); - - if (hEnum) - { - PWNetEnumerator enumerator = (PWNetEnumerator)hEnum; - - switch (enumerator->enumType) - { - case WNET_ENUMERATOR_TYPE_NULL: - ret = WN_SUCCESS; - break; - case WNET_ENUMERATOR_TYPE_GLOBAL: - if (enumerator->lpNet) - _freeEnumNetResource(enumerator->lpNet); - if (enumerator->handle) - providerTable->table[enumerator->providerIndex]. - closeEnum(enumerator->handle); - ret = WN_SUCCESS; - break; - case WNET_ENUMERATOR_TYPE_PROVIDER: - if (enumerator->handle) - providerTable->table[enumerator->providerIndex]. - closeEnum(enumerator->handle); - ret = WN_SUCCESS; - break; - default: - WARN("bogus enumerator type!\n"); - ret = WN_BAD_HANDLE; - } - HeapFree(GetProcessHeap(), 0, hEnum); - } - else - ret = WN_BAD_HANDLE; - if (ret) - SetLastError(ret); - TRACE("Returning %ld\n", ret); - return ret; -} - -/********************************************************************* - * WNetGetResourceInformationA [MPR.@] - */ -DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource, - LPVOID lpBuffer, LPDWORD cbBuffer, - LPSTR *lplpSystem ) -{ - FIXME( "(%p, %p, %p, %p): stub\n", - lpNetResource, lpBuffer, cbBuffer, lplpSystem ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/********************************************************************* - * WNetGetResourceInformationW [MPR.@] - */ -DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource, - LPVOID lpBuffer, LPDWORD cbBuffer, - LPWSTR *lplpSystem ) -{ - FIXME( "(%p, %p, %p, %p): stub\n", - lpNetResource, lpBuffer, cbBuffer, lplpSystem ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/********************************************************************* - * WNetGetResourceParentA [MPR.@] - */ -DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource, - LPVOID lpBuffer, LPDWORD lpBufferSize ) -{ - FIXME( "(%p, %p, %p): stub\n", - lpNetResource, lpBuffer, lpBufferSize ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/********************************************************************* - * WNetGetResourceParentW [MPR.@] - */ -DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource, - LPVOID lpBuffer, LPDWORD lpBufferSize ) -{ - FIXME( "(%p, %p, %p): stub\n", - lpNetResource, lpBuffer, lpBufferSize ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - - - -/* - * Connection Functions - */ - -/********************************************************************* - * WNetAddConnectionA [MPR.@] - */ -DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword, - LPCSTR lpLocalName ) -{ - FIXME( "(%s, %p, %s): stub\n", - debugstr_a(lpRemoteName), lpPassword, debugstr_a(lpLocalName) ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/********************************************************************* - * WNetAddConnectionW [MPR.@] - */ -DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword, - LPCWSTR lpLocalName ) -{ - FIXME( "(%s, %p, %s): stub\n", - debugstr_w(lpRemoteName), lpPassword, debugstr_w(lpLocalName) ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/********************************************************************* - * WNetAddConnection2A [MPR.@] - */ -DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource, - LPCSTR lpPassword, LPCSTR lpUserID, - DWORD dwFlags ) -{ - FIXME( "(%p, %p, %s, 0x%08lX): stub\n", - lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/********************************************************************* - * WNetAddConnection2W [MPR.@] - */ -DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource, - LPCWSTR lpPassword, LPCWSTR lpUserID, - DWORD dwFlags ) -{ - FIXME( "(%p, %p, %s, 0x%08lX): stub\n", - lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/********************************************************************* - * WNetAddConnection3A [MPR.@] - */ -DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource, - LPCSTR lpPassword, LPCSTR lpUserID, - DWORD dwFlags ) -{ - FIXME( "(%p, %p, %p, %s, 0x%08lX), stub\n", - hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/********************************************************************* - * WNetAddConnection3W [MPR.@] - */ -DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource, - LPCWSTR lpPassword, LPCWSTR lpUserID, - DWORD dwFlags ) -{ - FIXME( "(%p, %p, %p, %s, 0x%08lX), stub\n", - hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/***************************************************************** - * WNetUseConnectionA [MPR.@] - */ -DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, LPNETRESOURCEA lpNetResource, - LPCSTR lpPassword, LPCSTR lpUserID, DWORD dwFlags, - LPSTR lpAccessName, LPDWORD lpBufferSize, - LPDWORD lpResult ) -{ - FIXME( "(%p, %p, %p, %s, 0x%08lX, %s, %p, %p), stub\n", - hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags, - debugstr_a(lpAccessName), lpBufferSize, lpResult ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/***************************************************************** - * WNetUseConnectionW [MPR.@] - */ -DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, LPNETRESOURCEW lpNetResource, - LPCWSTR lpPassword, LPCWSTR lpUserID, DWORD dwFlags, - LPWSTR lpAccessName, LPDWORD lpBufferSize, - LPDWORD lpResult ) -{ - FIXME( "(%p, %p, %p, %s, 0x%08lX, %s, %p, %p), stub\n", - hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags, - debugstr_w(lpAccessName), lpBufferSize, lpResult ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/********************************************************************* - * WNetCancelConnectionA [MPR.@] - */ -DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce ) -{ - FIXME( "(%s, %d), stub\n", debugstr_a(lpName), fForce ); - - return WN_SUCCESS; -} - -/********************************************************************* - * WNetCancelConnectionW [MPR.@] - */ -DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce ) -{ - FIXME( "(%s, %d), stub\n", debugstr_w(lpName), fForce ); - - return WN_SUCCESS; -} - -/********************************************************************* - * WNetCancelConnection2A [MPR.@] - */ -DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce ) -{ - FIXME( "(%s, %08lX, %d), stub\n", debugstr_a(lpName), dwFlags, fForce ); - - return WN_SUCCESS; -} - -/********************************************************************* - * WNetCancelConnection2W [MPR.@] - */ -DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce ) -{ - FIXME( "(%s, %08lX, %d), stub\n", debugstr_w(lpName), dwFlags, fForce ); - - return WN_SUCCESS; -} - -/***************************************************************** - * WNetRestoreConnectionA [MPR.@] - */ -DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPSTR lpszDevice ) -{ - FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/***************************************************************** - * WNetRestoreConnectionW [MPR.@] - */ -DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPWSTR lpszDevice ) -{ - FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/************************************************************************** - * WNetGetConnectionA [MPR.@] - * - * RETURNS - * - WN_BAD_LOCALNAME lpLocalName makes no sense - * - WN_NOT_CONNECTED drive is a local drive - * - WN_MORE_DATA buffer isn't big enough - * - WN_SUCCESS success (net path in buffer) - * - * FIXME: need to test return values under different errors - */ -DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName, - LPSTR lpRemoteName, LPDWORD lpBufferSize ) -{ - DWORD ret; - - if (!lpLocalName) - ret = WN_BAD_POINTER; - else if (!lpRemoteName) - ret = WN_BAD_POINTER; - else if (!lpBufferSize) - ret = WN_BAD_POINTER; - else - { - int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0); - - if (len) - { - PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); - - if (wideLocalName) - { - WCHAR wideRemoteStatic[MAX_PATH]; - DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR); - - MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len); - - /* try once without memory allocation */ - ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic, - &wideRemoteSize); - if (ret == WN_SUCCESS) - { - int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, - -1, NULL, 0, NULL, NULL); - - if (len <= *lpBufferSize) - { - WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1, - lpRemoteName, *lpBufferSize, NULL, NULL); - ret = WN_SUCCESS; - } - else - { - *lpBufferSize = len; - ret = WN_MORE_DATA; - } - } - else if (ret == WN_MORE_DATA) - { - PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0, - wideRemoteSize * sizeof(WCHAR)); - - if (wideRemote) - { - ret = WNetGetConnectionW(wideLocalName, wideRemote, - &wideRemoteSize); - if (ret == WN_SUCCESS) - { - if (len <= *lpBufferSize) - { - WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, - -1, lpRemoteName, *lpBufferSize, NULL, NULL); - ret = WN_SUCCESS; - } - else - { - *lpBufferSize = len; - ret = WN_MORE_DATA; - } - } - HeapFree(GetProcessHeap(), 0, wideRemote); - } - else - ret = WN_OUT_OF_MEMORY; - } - HeapFree(GetProcessHeap(), 0, wideLocalName); - } - else - ret = WN_OUT_OF_MEMORY; - } - else - ret = WN_BAD_LOCALNAME; - } - if (ret) - SetLastError(ret); - TRACE("Returning %ld\n", ret); - return ret; -} - -/************************************************************************** - * WNetGetConnectionW [MPR.@] - * - * FIXME: need to test return values under different errors - */ -DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName, - LPWSTR lpRemoteName, LPDWORD lpBufferSize ) -{ - DWORD ret; - - TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName, - lpBufferSize); - - if (!lpLocalName) - ret = WN_BAD_POINTER; - else if (!lpRemoteName) - ret = WN_BAD_POINTER; - else if (!lpBufferSize) - ret = WN_BAD_POINTER; - else if (!lpLocalName[0]) - ret = WN_BAD_LOCALNAME; - else - { - if (lpLocalName[1] == ':') - { - switch(GetDriveTypeW(lpLocalName)) - { - case DRIVE_REMOTE: - { - WCHAR remote[MAX_PATH]; - if (!QueryDosDeviceW( lpLocalName, remote, MAX_PATH )) remote[0] = 0; - if (strlenW(remote) + 1 > *lpBufferSize) - { - *lpBufferSize = strlenW(remote) + 1; - ret = WN_MORE_DATA; - } - else - { - strcpyW( lpRemoteName, remote ); - *lpBufferSize = strlenW(lpRemoteName) + 1; - ret = WN_SUCCESS; - } - break; - } - case DRIVE_REMOVABLE: - case DRIVE_FIXED: - case DRIVE_CDROM: - TRACE("file is local\n"); - ret = WN_NOT_CONNECTED; - break; - default: - ret = WN_BAD_LOCALNAME; - } - } - else - ret = WN_BAD_LOCALNAME; - } - if (ret) - SetLastError(ret); - TRACE("Returning %ld\n", ret); - return ret; -} - -/************************************************************************** - * WNetSetConnectionA [MPR.@] - */ -DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty, - LPVOID pvValue ) -{ - FIXME( "(%s, %08lX, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/************************************************************************** - * WNetSetConnectionW [MPR.@] - */ -DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty, - LPVOID pvValue ) -{ - FIXME( "(%s, %08lX, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/***************************************************************** - * WNetGetUniversalNameA [MPR.@] - */ -DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel, - LPVOID lpBuffer, LPDWORD lpBufferSize ) -{ - FIXME( "(%s, 0x%08lX, %p, %p): stub\n", - debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/***************************************************************** - * WNetGetUniversalNameW [MPR.@] - */ -DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel, - LPVOID lpBuffer, LPDWORD lpBufferSize ) -{ - FIXME( "(%s, 0x%08lX, %p, %p): stub\n", - debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - - - -/* - * Other Functions - */ - -/************************************************************************** - * WNetGetUserA [MPR.@] - * - * FIXME: we should not return ourselves, but the owner of the drive lpName - */ -DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize ) -{ - if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS; - return GetLastError(); -} - -/***************************************************************** - * WNetGetUserW [MPR.@] - * - * FIXME: we should not return ourselves, but the owner of the drive lpName - */ -DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize ) -{ - if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS; - return GetLastError(); -} - -/********************************************************************* - * WNetConnectionDialog [MPR.@] - */ -DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType ) -{ - FIXME( "(%p, %08lX): stub\n", hwnd, dwType ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/********************************************************************* - * WNetConnectionDialog1A [MPR.@] - */ -DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct ) -{ - FIXME( "(%p): stub\n", lpConnDlgStruct ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/********************************************************************* - * WNetConnectionDialog1W [MPR.@] - */ -DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct ) -{ - FIXME( "(%p): stub\n", lpConnDlgStruct ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/********************************************************************* - * WNetDisconnectDialog [MPR.@] - */ -DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType ) -{ - FIXME( "(%p, %08lX): stub\n", hwnd, dwType ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/********************************************************************* - * WNetDisconnectDialog1A [MPR.@] - */ -DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct ) -{ - FIXME( "(%p): stub\n", lpConnDlgStruct ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/********************************************************************* - * WNetDisconnectDialog1W [MPR.@] - */ -DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct ) -{ - FIXME( "(%p): stub\n", lpConnDlgStruct ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/********************************************************************* - * WNetGetLastErrorA [MPR.@] - */ -DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError, - LPSTR lpErrorBuf, DWORD nErrorBufSize, - LPSTR lpNameBuf, DWORD nNameBufSize ) -{ - FIXME( "(%p, %p, %ld, %p, %ld): stub\n", - lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/********************************************************************* - * WNetGetLastErrorW [MPR.@] - */ -DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError, - LPWSTR lpErrorBuf, DWORD nErrorBufSize, - LPWSTR lpNameBuf, DWORD nNameBufSize ) -{ - FIXME( "(%p, %p, %ld, %p, %ld): stub\n", - lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize ); - - SetLastError(WN_NO_NETWORK); - return WN_NO_NETWORK; -} - -/********************************************************************* - * WNetGetNetworkInformationA [MPR.@] - */ -DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider, - LPNETINFOSTRUCT lpNetInfoStruct ) -{ - DWORD ret; - - TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct ); - - if (!lpProvider) - ret = WN_BAD_POINTER; - else - { - int len; - - len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0); - if (len) - { - LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); - - if (wideProvider) - { - MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider, - len); - ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct); - HeapFree(GetProcessHeap(), 0, wideProvider); - } - else - ret = WN_OUT_OF_MEMORY; - } - else - ret = GetLastError(); - } - if (ret) - SetLastError(ret); - TRACE("Returning %ld\n", ret); - return ret; -} - -/********************************************************************* - * WNetGetNetworkInformationW [MPR.@] - */ -DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider, - LPNETINFOSTRUCT lpNetInfoStruct ) -{ - DWORD ret; - - TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct ); - - if (!lpProvider) - ret = WN_BAD_POINTER; - else if (!lpNetInfoStruct) - ret = WN_BAD_POINTER; - else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT)) - ret = WN_BAD_VALUE; - else - { - if (providerTable && providerTable->numProviders) - { - DWORD providerIndex = _findProviderIndexW(lpProvider); - - if (providerIndex != BAD_PROVIDER_INDEX) - { - lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT); - lpNetInfoStruct->dwProviderVersion = - providerTable->table[providerIndex].dwSpecVersion; - lpNetInfoStruct->dwStatus = NO_ERROR; - lpNetInfoStruct->dwCharacteristics = 0; - lpNetInfoStruct->dwHandle = (ULONG_PTR)NULL; - lpNetInfoStruct->wNetType = - HIWORD(providerTable->table[providerIndex].dwNetType); - lpNetInfoStruct->dwPrinters = -1; - lpNetInfoStruct->dwDrives = -1; - ret = WN_SUCCESS; - } - else - ret = WN_BAD_PROVIDER; - } - else - ret = WN_NO_NETWORK; - } - if (ret) - SetLastError(ret); - TRACE("Returning %ld\n", ret); - return ret; -} - -/***************************************************************** - * WNetGetProviderNameA [MPR.@] - */ -DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType, - LPSTR lpProvider, LPDWORD lpBufferSize ) -{ - DWORD ret; - - TRACE("(0x%08lx, %s, %p)\n", dwNetType, debugstr_a(lpProvider), - lpBufferSize); - - if (!lpProvider) - ret = WN_BAD_POINTER; - else if (!lpBufferSize) - ret = WN_BAD_POINTER; - else - { - if (providerTable) - { - DWORD i; - - ret = WN_NO_NETWORK; - for (i = 0; i < providerTable->numProviders && - HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType); - i++) - ; - if (i < providerTable->numProviders) - { - DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0, - providerTable->table[i].name, -1, NULL, 0, NULL, NULL); - - if (*lpBufferSize < sizeNeeded) - { - *lpBufferSize = sizeNeeded; - ret = WN_MORE_DATA; - } - else - { - WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name, - -1, lpProvider, *lpBufferSize, NULL, NULL); - ret = WN_SUCCESS; - /* FIXME: is *lpBufferSize set to the number of characters - * copied? */ - } - } - } - else - ret = WN_NO_NETWORK; - } - if (ret) - SetLastError(ret); - TRACE("Returning %ld\n", ret); - return ret; -} - -/***************************************************************** - * WNetGetProviderNameW [MPR.@] - */ -DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType, - LPWSTR lpProvider, LPDWORD lpBufferSize ) -{ - DWORD ret; - - TRACE("(0x%08lx, %s, %p)\n", dwNetType, debugstr_w(lpProvider), - lpBufferSize); - - if (!lpProvider) - ret = WN_BAD_POINTER; - else if (!lpBufferSize) - ret = WN_BAD_POINTER; - else - { - if (providerTable) - { - DWORD i; - - ret = WN_NO_NETWORK; - for (i = 0; i < providerTable->numProviders && - HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType); - i++) - ; - if (i < providerTable->numProviders) - { - DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1; - - if (*lpBufferSize < sizeNeeded) - { - *lpBufferSize = sizeNeeded; - ret = WN_MORE_DATA; - } - else - { - strcpyW(lpProvider, providerTable->table[i].name); - ret = WN_SUCCESS; - /* FIXME: is *lpBufferSize set to the number of characters - * copied? */ - } - } - } - else - ret = WN_NO_NETWORK; - } - if (ret) - SetLastError(ret); - TRACE("Returning %ld\n", ret); - return ret; -} +/* + * MPR WNet functions + * + * Copyright 1999 Ulrich Weigand + * Copyright 2004 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winnls.h" +#include "winnetwk.h" +#include "npapi.h" +#include "winreg.h" +#include "winuser.h" +#include "wine/debug.h" +#include "wine/unicode.h" +#include "mprres.h" +#include "wnetpriv.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mpr); + +/* Data structures representing network service providers. Assumes only one + * thread creates them, and that they are constant for the life of the process + * (and therefore doesn't synchronize access). + * FIXME: only basic provider data and enumeration-related data are implemented + * so far, need to implement the rest too. + */ +typedef struct _WNetProvider +{ + HMODULE hLib; + PWSTR name; + PF_NPGetCaps getCaps; + DWORD dwSpecVersion; + DWORD dwNetType; + DWORD dwEnumScopes; + PF_NPOpenEnum openEnum; + PF_NPEnumResource enumResource; + PF_NPCloseEnum closeEnum; +} WNetProvider, *PWNetProvider; + +typedef struct _WNetProviderTable +{ + LPWSTR entireNetwork; + DWORD numAllocated; + DWORD numProviders; + WNetProvider table[1]; +} WNetProviderTable, *PWNetProviderTable; + +#define WNET_ENUMERATOR_TYPE_NULL 0 +#define WNET_ENUMERATOR_TYPE_GLOBAL 1 +#define WNET_ENUMERATOR_TYPE_PROVIDER 2 +#define WNET_ENUMERATOR_TYPE_CONTEXT 3 + +/* An WNet enumerator. Note that the type doesn't correspond to the scope of + * the enumeration; it represents one of the following types: + * - a 'null' enumeration, one that contains no members + * - a global enumeration, one that's executed across all providers + * - a provider-specific enumeration, one that's only executed by a single + * provider + * - a context enumeration. I know this contradicts what I just said about + * there being no correspondence between the scope and the type, but it's + * necessary for the special case that a "Entire Network" entry needs to + * be enumerated in an enumeration of the context scope. Thus an enumeration + * of the context scope results in a context type enumerator, which morphs + * into a global enumeration (so the enumeration continues across all + * providers). + */ +typedef struct _WNetEnumerator +{ + DWORD enumType; + DWORD providerIndex; + HANDLE handle; + BOOL providerDone; + DWORD dwScope; + DWORD dwType; + DWORD dwUsage; + LPNETRESOURCEW lpNet; +} WNetEnumerator, *PWNetEnumerator; + +#define BAD_PROVIDER_INDEX (DWORD)0xffffffff + +/* Returns an index (into the global WNetProviderTable) of the provider with + * the given name, or BAD_PROVIDER_INDEX if not found. + */ +static DWORD _findProviderIndexW(LPCWSTR lpProvider); + +PWNetProviderTable providerTable; + +/* + * Global provider table functions + */ + +static void _tryLoadProvider(PCWSTR provider) +{ + static const WCHAR servicePrefix[] = { 'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'S','e','r','v','i','c','e','s','\\',0 }; + static const WCHAR serviceFmt[] = { '%','s','%','s','\\', + 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r',0 }; + WCHAR serviceName[MAX_PATH]; + HKEY hKey; + + TRACE("%s\n", debugstr_w(provider)); + snprintfW(serviceName, sizeof(serviceName) / sizeof(WCHAR), serviceFmt, + servicePrefix, provider); + serviceName[sizeof(serviceName) / sizeof(WCHAR) - 1] = '\0'; + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, serviceName, 0, KEY_READ, &hKey) == + ERROR_SUCCESS) + { + static const WCHAR szProviderPath[] = { 'P','r','o','v','i','d','e','r', + 'P','a','t','h',0 }; + WCHAR providerPath[MAX_PATH]; + DWORD type, size = sizeof(providerPath); + + if (RegQueryValueExW(hKey, szProviderPath, NULL, &type, + (LPBYTE)providerPath, &size) == ERROR_SUCCESS && type == REG_SZ) + { + static const WCHAR szProviderName[] = { 'N','a','m','e',0 }; + PWSTR name = NULL; + + size = 0; + RegQueryValueExW(hKey, szProviderName, NULL, NULL, NULL, &size); + if (size) + { + name = HeapAlloc(GetProcessHeap(), 0, size); + if (RegQueryValueExW(hKey, szProviderName, NULL, &type, + (LPBYTE)name, &size) != ERROR_SUCCESS || type != REG_SZ) + { + HeapFree(GetProcessHeap(), 0, name); + name = NULL; + } + } + if (name) + { + HMODULE hLib = LoadLibraryW(providerPath); + + if (hLib) + { + PF_NPGetCaps getCaps = (PF_NPGetCaps)GetProcAddress(hLib, + "NPGetCaps"); + + TRACE("loaded lib %p\n", hLib); + if (getCaps) + { + PWNetProvider provider = + &providerTable->table[providerTable->numProviders]; + + provider->hLib = hLib; + provider->name = name; + TRACE("name is %s\n", debugstr_w(name)); + provider->getCaps = getCaps; + provider->dwSpecVersion = getCaps(WNNC_SPEC_VERSION); + provider->dwNetType = getCaps(WNNC_NET_TYPE); + TRACE("net type is 0x%08lx\n", provider->dwNetType); + provider->dwEnumScopes = getCaps(WNNC_ENUMERATION); + if (provider->dwEnumScopes) + { + TRACE("supports enumeration\n"); + provider->openEnum = (PF_NPOpenEnum) + GetProcAddress(hLib, "NPOpenEnum"); + TRACE("openEnum is %p\n", provider->openEnum); + provider->enumResource = (PF_NPEnumResource) + GetProcAddress(hLib, "NPEnumResource"); + TRACE("enumResource is %p\n", + provider->enumResource); + provider->closeEnum = (PF_NPCloseEnum) + GetProcAddress(hLib, "NPCloseEnum"); + TRACE("closeEnum is %p\n", provider->closeEnum); + if (!provider->openEnum || !provider->enumResource + || !provider->closeEnum) + { + provider->openEnum = NULL; + provider->enumResource = NULL; + provider->closeEnum = NULL; + provider->dwEnumScopes = 0; + WARN("Couldn't load enumeration functions\n"); + } + } + providerTable->numProviders++; + } + else + { + WARN("Provider %s didn't export NPGetCaps\n", + debugstr_w(provider)); + HeapFree(GetProcessHeap(), 0, name); + FreeLibrary(hLib); + } + } + else + { + WARN("Couldn't load library %s for provider %s\n", + debugstr_w(providerPath), debugstr_w(provider)); + HeapFree(GetProcessHeap(), 0, name); + } + } + else + { + WARN("Couldn't get provider name for provider %s\n", + debugstr_w(provider)); + } + } + else + WARN("Couldn't open value %s\n", debugstr_w(szProviderPath)); + RegCloseKey(hKey); + } + else + WARN("Couldn't open service key for provider %s\n", + debugstr_w(provider)); +} + +void wnetInit(HINSTANCE hInstDll) +{ + static const WCHAR providerOrderKey[] = { 'S','y','s','t','e','m','\\', + 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', + 'C','o','n','t','r','o','l','\\', + 'N','e','t','w','o','r','k','P','r','o','v','i','d','e','r','\\', + 'O','r','d','e','r',0 }; + static const WCHAR providerOrder[] = { 'P','r','o','v','i','d','e','r', + 'O','r','d','e','r',0 }; + HKEY hKey; + + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, providerOrderKey, 0, KEY_READ, &hKey) + == ERROR_SUCCESS) + { + DWORD size = 0; + + RegQueryValueExW(hKey, providerOrder, NULL, NULL, NULL, &size); + if (size) + { + PWSTR providers = HeapAlloc(GetProcessHeap(), 0, size); + + if (providers) + { + DWORD type; + + if (RegQueryValueExW(hKey, providerOrder, NULL, &type, + (LPBYTE)providers, &size) == ERROR_SUCCESS && type == REG_SZ) + { + PWSTR ptr; + DWORD numToAllocate; + + TRACE("provider order is %s\n", debugstr_w(providers)); + /* first count commas as a heuristic for how many to + * allocate space for */ + for (ptr = providers, numToAllocate = 1; ptr; ) + { + ptr = strchrW(ptr, ','); + if (ptr) + numToAllocate++; + } + providerTable = + HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(WNetProviderTable) + + (numToAllocate - 1) * sizeof(WNetProvider)); + if (providerTable) + { + PWSTR ptrPrev; + int entireNetworkLen; + + entireNetworkLen = LoadStringW(hInstDll, + IDS_ENTIRENETWORK, NULL, 0); + providerTable->entireNetwork = HeapAlloc( + GetProcessHeap(), 0, (entireNetworkLen + 1) * + sizeof(WCHAR)); + if (providerTable->entireNetwork) + LoadStringW(hInstDll, IDS_ENTIRENETWORK, + providerTable->entireNetwork, + entireNetworkLen + 1); + providerTable->numAllocated = numToAllocate; + for (ptr = providers; ptr; ) + { + ptrPrev = ptr; + ptr = strchrW(ptr, ','); + if (ptr) + *ptr = '\0'; + _tryLoadProvider(ptrPrev); + } + } + } + HeapFree(GetProcessHeap(), 0, providers); + } + } + RegCloseKey(hKey); + } +} + +void wnetFree(void) +{ + if (providerTable) + { + DWORD i; + + for (i = 0; i < providerTable->numProviders; i++) + { + HeapFree(GetProcessHeap(), 0, providerTable->table[i].name); + FreeModule(providerTable->table[i].hLib); + } + HeapFree(GetProcessHeap(), 0, providerTable->entireNetwork); + HeapFree(GetProcessHeap(), 0, providerTable); + providerTable = NULL; + } +} + +static DWORD _findProviderIndexW(LPCWSTR lpProvider) +{ + DWORD ret = BAD_PROVIDER_INDEX; + + if (providerTable && providerTable->numProviders) + { + DWORD i; + + for (i = 0; i < providerTable->numProviders && + ret == BAD_PROVIDER_INDEX; i++) + if (!strcmpW(lpProvider, providerTable->table[i].name)) + ret = i; + } + return ret; +} + +/* + * Browsing Functions + */ + +static LPNETRESOURCEW _copyNetResourceForEnumW(LPNETRESOURCEW lpNet) +{ + LPNETRESOURCEW ret; + + if (lpNet) + { + ret = HeapAlloc(GetProcessHeap(), 0, sizeof(NETRESOURCEW)); + if (ret) + { + size_t len; + + memcpy(ret, lpNet, sizeof(ret)); + ret->lpLocalName = ret->lpComment = ret->lpProvider = NULL; + if (lpNet->lpRemoteName) + { + len = strlenW(lpNet->lpRemoteName) + 1; + ret->lpRemoteName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (ret->lpRemoteName) + strcpyW(ret->lpRemoteName, lpNet->lpRemoteName); + } + } + } + else + ret = NULL; + return ret; +} + +static void _freeEnumNetResource(LPNETRESOURCEW lpNet) +{ + if (lpNet) + { + HeapFree(GetProcessHeap(), 0, lpNet->lpRemoteName); + HeapFree(GetProcessHeap(), 0, lpNet); + } +} + +static PWNetEnumerator _createNullEnumerator(void) +{ + PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, sizeof(WNetEnumerator)); + + if (ret) + ret->enumType = WNET_ENUMERATOR_TYPE_NULL; + return ret; +} + +static PWNetEnumerator _createGlobalEnumeratorW(DWORD dwScope, DWORD dwType, + DWORD dwUsage, LPNETRESOURCEW lpNet) +{ + PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, sizeof(WNetEnumerator)); + + if (ret) + { + ret->enumType = WNET_ENUMERATOR_TYPE_GLOBAL; + ret->dwScope = dwScope; + ret->dwType = dwType; + ret->dwUsage = dwUsage; + ret->lpNet = _copyNetResourceForEnumW(lpNet); + } + return ret; +} + +static PWNetEnumerator _createProviderEnumerator(DWORD dwScope, DWORD dwType, + DWORD dwUsage, DWORD index, HANDLE handle) +{ + PWNetEnumerator ret; + + if (!providerTable || index >= providerTable->numProviders) + ret = NULL; + else + { + ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WNetEnumerator)); + if (ret) + { + ret->enumType = WNET_ENUMERATOR_TYPE_PROVIDER; + ret->providerIndex = index; + ret->dwScope = dwScope; + ret->dwType = dwType; + ret->dwUsage = dwUsage; + ret->handle = handle; + } + } + return ret; +} + +static PWNetEnumerator _createContextEnumerator(DWORD dwScope, DWORD dwType, + DWORD dwUsage) +{ + PWNetEnumerator ret = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, sizeof(WNetEnumerator)); + + if (ret) + { + ret->enumType = WNET_ENUMERATOR_TYPE_CONTEXT; + ret->dwScope = dwScope; + ret->dwType = dwType; + ret->dwUsage = dwUsage; + } + return ret; +} + +/* Thunks the array of wide-string LPNETRESOURCEs lpNetArrayIn into buffer + * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries + * to start. On return, *lpcCount reflects the number thunked into lpBuffer. + * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA + * if not all members of the array could be thunked, and something else on + * failure. + */ +static DWORD _thunkNetResourceArrayWToA(const LPNETRESOURCEW lpNetArrayIn, + LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) +{ + DWORD i, numToThunk, totalBytes, ret; + LPSTR strNext; + + if (!lpNetArrayIn) + return WN_BAD_POINTER; + if (!lpcCount) + return WN_BAD_POINTER; + if (*lpcCount == -1) + return WN_BAD_VALUE; + if (!lpBuffer) + return WN_BAD_POINTER; + if (!lpBufferSize) + return WN_BAD_POINTER; + + for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++) + { + LPNETRESOURCEW lpNet = lpNetArrayIn + i; + + totalBytes += sizeof(NETRESOURCEA); + if (lpNet->lpLocalName) + totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpLocalName, + -1, NULL, 0, NULL, NULL); + if (lpNet->lpRemoteName) + totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpRemoteName, + -1, NULL, 0, NULL, NULL); + if (lpNet->lpComment) + totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpComment, + -1, NULL, 0, NULL, NULL); + if (lpNet->lpProvider) + totalBytes += WideCharToMultiByte(CP_ACP, 0, lpNet->lpProvider, + -1, NULL, 0, NULL, NULL); + if (totalBytes < *lpBufferSize) + numToThunk = i + 1; + } + strNext = (LPSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEA)); + for (i = 0; i < numToThunk; i++) + { + LPNETRESOURCEA lpNetOut = (LPNETRESOURCEA)lpBuffer + i; + LPNETRESOURCEW lpNetIn = lpNetArrayIn + i; + + memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEA)); + /* lie about string lengths, we already verified how many + * we have space for above + */ + if (lpNetIn->lpLocalName) + { + lpNetOut->lpLocalName = strNext; + strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpLocalName, -1, + lpNetOut->lpLocalName, *lpBufferSize, NULL, NULL); + } + if (lpNetIn->lpRemoteName) + { + lpNetOut->lpRemoteName = strNext; + strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpRemoteName, -1, + lpNetOut->lpRemoteName, *lpBufferSize, NULL, NULL); + } + if (lpNetIn->lpComment) + { + lpNetOut->lpComment = strNext; + strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpComment, -1, + lpNetOut->lpComment, *lpBufferSize, NULL, NULL); + } + if (lpNetIn->lpProvider) + { + lpNetOut->lpProvider = strNext; + strNext += WideCharToMultiByte(CP_ACP, 0, lpNetIn->lpProvider, -1, + lpNetOut->lpProvider, *lpBufferSize, NULL, NULL); + } + } + ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS; + TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk, + *lpcCount, ret); + return ret; +} + +/* Thunks the array of multibyte-string LPNETRESOURCEs lpNetArrayIn into buffer + * lpBuffer, with size *lpBufferSize. lpNetArrayIn contains *lpcCount entries + * to start. On return, *lpcCount reflects the number thunked into lpBuffer. + * Returns WN_SUCCESS on success (all of lpNetArrayIn thunked), WN_MORE_DATA + * if not all members of the array could be thunked, and something else on + * failure. + */ +static DWORD _thunkNetResourceArrayAToW(const LPNETRESOURCEA lpNetArrayIn, + LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) +{ + DWORD i, numToThunk, totalBytes, ret; + LPWSTR strNext; + + if (!lpNetArrayIn) + return WN_BAD_POINTER; + if (!lpcCount) + return WN_BAD_POINTER; + if (*lpcCount == -1) + return WN_BAD_VALUE; + if (!lpBuffer) + return WN_BAD_POINTER; + if (!lpBufferSize) + return WN_BAD_POINTER; + + for (i = 0, numToThunk = 0, totalBytes = 0; i < *lpcCount; i++) + { + LPNETRESOURCEA lpNet = lpNetArrayIn + i; + + totalBytes += sizeof(NETRESOURCEW); + if (lpNet->lpLocalName) + totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpLocalName, + -1, NULL, 0) * sizeof(WCHAR); + if (lpNet->lpRemoteName) + totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpRemoteName, + -1, NULL, 0) * sizeof(WCHAR); + if (lpNet->lpComment) + totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpComment, + -1, NULL, 0) * sizeof(WCHAR); + if (lpNet->lpProvider) + totalBytes += MultiByteToWideChar(CP_ACP, 0, lpNet->lpProvider, + -1, NULL, 0) * sizeof(WCHAR); + if (totalBytes < *lpBufferSize) + numToThunk = i + 1; + } + strNext = (LPWSTR)((LPBYTE)lpBuffer + numToThunk * sizeof(NETRESOURCEW)); + for (i = 0; i < numToThunk; i++) + { + LPNETRESOURCEW lpNetOut = (LPNETRESOURCEW)lpBuffer + i; + LPNETRESOURCEA lpNetIn = lpNetArrayIn + i; + + memcpy(lpNetOut, lpNetIn, sizeof(NETRESOURCEW)); + /* lie about string lengths, we already verified how many + * we have space for above + */ + if (lpNetIn->lpLocalName) + { + lpNetOut->lpLocalName = strNext; + strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpLocalName, + -1, lpNetOut->lpLocalName, *lpBufferSize); + } + if (lpNetIn->lpRemoteName) + { + lpNetOut->lpRemoteName = strNext; + strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpRemoteName, + -1, lpNetOut->lpRemoteName, *lpBufferSize); + } + if (lpNetIn->lpComment) + { + lpNetOut->lpComment = strNext; + strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpComment, + -1, lpNetOut->lpComment, *lpBufferSize); + } + if (lpNetIn->lpProvider) + { + lpNetOut->lpProvider = strNext; + strNext += MultiByteToWideChar(CP_ACP, 0, lpNetIn->lpProvider, + -1, lpNetOut->lpProvider, *lpBufferSize); + } + } + ret = numToThunk < *lpcCount ? WN_MORE_DATA : WN_SUCCESS; + TRACE("numToThunk is %ld, *lpcCount is %ld, returning %ld\n", numToThunk, + *lpcCount, ret); + return ret; +} + +/********************************************************************* + * WNetOpenEnumA [MPR.@] + * + * See comments for WNetOpenEnumW. + */ +DWORD WINAPI WNetOpenEnumA( DWORD dwScope, DWORD dwType, DWORD dwUsage, + LPNETRESOURCEA lpNet, LPHANDLE lphEnum ) +{ + DWORD ret; + + TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n", + dwScope, dwType, dwUsage, lpNet, lphEnum ); + + if (!lphEnum) + ret = WN_BAD_POINTER; + else if (!providerTable || providerTable->numProviders == 0) + ret = WN_NO_NETWORK; + else + { + if (lpNet) + { + LPNETRESOURCEW lpNetWide = NULL; + BYTE buf[1024]; + DWORD size = sizeof(buf), count = 1; + BOOL allocated = FALSE; + + ret = _thunkNetResourceArrayAToW(lpNet, &count, buf, &size); + if (ret == WN_MORE_DATA) + { + lpNetWide = HeapAlloc(GetProcessHeap(), 0, + size); + if (lpNetWide) + { + ret = _thunkNetResourceArrayAToW(lpNet, &count, lpNetWide, + &size); + allocated = TRUE; + } + else + ret = WN_OUT_OF_MEMORY; + } + else if (ret == WN_SUCCESS) + lpNetWide = (LPNETRESOURCEW)buf; + if (ret == WN_SUCCESS) + ret = WNetOpenEnumW(dwScope, dwType, dwUsage, lpNetWide, + lphEnum); + if (allocated && lpNetWide) + HeapFree(GetProcessHeap(), 0, lpNetWide); + } + else + ret = WNetOpenEnumW(dwScope, dwType, dwUsage, NULL, lphEnum); + } + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); + return ret; +} + +/********************************************************************* + * WNetOpenEnumW [MPR.@] + * + * Network enumeration has way too many parameters, so I'm not positive I got + * them right. What I've got so far: + * + * - If the scope is RESOURCE_GLOBALNET, and no LPNETRESOURCE is passed, + * all the network providers should be enumerated. + * + * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and + * and neither the LPNETRESOURCE's lpRemoteName nor the LPNETRESOURCE's + * lpProvider is set, all the network providers should be enumerated. + * (This means the enumeration is a list of network providers, not that the + * enumeration is passed on to the providers.) + * + * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and the + * resource matches the "Entire Network" resource (no remote name, no + * provider, comment is the "Entire Network" string), a RESOURCE_GLOBALNET + * enumeration is done on every network provider. + * + * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and + * the LPNETRESOURCE's lpProvider is set, enumeration will be passed through + * only to the given network provider. + * + * - If the scope is RESOURCE_GLOBALNET, and LPNETRESOURCE is passed, and + * no lpProvider is set, enumeration will be tried on every network provider, + * in the order in which they're loaded. + * + * - The LPNETRESOURCE should be disregarded for scopes besides + * RESOURCE_GLOBALNET. MSDN states that lpNet must be NULL if dwScope is not + * RESOURCE_GLOBALNET, but Windows doesn't return an error if it isn't NULL. + * + * - If the scope is RESOURCE_CONTEXT, MS includes an "Entire Network" net + * resource in the enumerated list, as well as any machines in your + * workgroup. The machines in your workgroup come from doing a + * RESOURCE_CONTEXT enumeration of every Network Provider. + */ +DWORD WINAPI WNetOpenEnumW( DWORD dwScope, DWORD dwType, DWORD dwUsage, + LPNETRESOURCEW lpNet, LPHANDLE lphEnum ) +{ + DWORD ret; + + TRACE( "(%08lX, %08lX, %08lX, %p, %p)\n", + dwScope, dwType, dwUsage, lpNet, lphEnum ); + + if (!lphEnum) + ret = WN_BAD_POINTER; + else if (!providerTable || providerTable->numProviders == 0) + ret = WN_NO_NETWORK; + else + { + switch (dwScope) + { + case RESOURCE_GLOBALNET: + if (lpNet) + { + if (lpNet->lpProvider) + { + DWORD index = _findProviderIndexW(lpNet->lpProvider); + + if (index != BAD_PROVIDER_INDEX) + { + if (providerTable->table[index].openEnum && + providerTable->table[index].dwEnumScopes & dwScope) + { + HANDLE handle; + + ret = providerTable->table[index].openEnum( + dwScope, dwType, dwUsage, lpNet, &handle); + if (ret == WN_SUCCESS) + { + *lphEnum = + (HANDLE)_createProviderEnumerator( + dwScope, dwType, dwUsage, index, handle); + ret = *lphEnum ? WN_SUCCESS : + WN_OUT_OF_MEMORY; + } + } + else + ret = WN_NOT_SUPPORTED; + } + else + ret = WN_BAD_PROVIDER; + } + else if (lpNet->lpRemoteName) + { + *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope, + dwType, dwUsage, lpNet); + ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; + } + else + { + if (lpNet->lpComment && !strcmpW(lpNet->lpComment, + providerTable->entireNetwork)) + { + /* comment matches the "Entire Network", enumerate + * global scope of every provider + */ + *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope, + dwType, dwUsage, lpNet); + } + else + { + /* this is the same as not having passed lpNet */ + *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope, + dwType, dwUsage, NULL); + } + ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; + } + } + else + { + *lphEnum = (HANDLE)_createGlobalEnumeratorW(dwScope, dwType, + dwUsage, lpNet); + ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; + } + break; + case RESOURCE_CONTEXT: + *lphEnum = (HANDLE)_createContextEnumerator(dwScope, dwType, + dwUsage); + ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; + break; + case RESOURCE_REMEMBERED: + case RESOURCE_CONNECTED: + *lphEnum = (HANDLE)_createNullEnumerator(); + ret = *lphEnum ? WN_SUCCESS : WN_OUT_OF_MEMORY; + break; + default: + WARN("unknown scope 0x%08lx\n", dwScope); + ret = WN_BAD_VALUE; + } + } + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); + return ret; +} + +/********************************************************************* + * WNetEnumResourceA [MPR.@] + */ +DWORD WINAPI WNetEnumResourceA( HANDLE hEnum, LPDWORD lpcCount, + LPVOID lpBuffer, LPDWORD lpBufferSize ) +{ + DWORD ret; + + TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize ); + + if (!hEnum) + ret = WN_BAD_POINTER; + else if (!lpcCount) + ret = WN_BAD_POINTER; + if (!lpBuffer) + ret = WN_BAD_POINTER; + else if (!lpBufferSize) + ret = WN_BAD_POINTER; + else if (*lpBufferSize < sizeof(NETRESOURCEA)) + { + *lpBufferSize = sizeof(NETRESOURCEA); + ret = WN_MORE_DATA; + } + else + { + DWORD localCount = *lpcCount, localSize = *lpBufferSize; + LPVOID localBuffer = HeapAlloc(GetProcessHeap(), 0, localSize); + + if (localBuffer) + { + ret = WNetEnumResourceW(hEnum, &localCount, localBuffer, + &localSize); + if (ret == WN_SUCCESS || (ret == WN_MORE_DATA && localCount != -1)) + { + /* FIXME: this isn't necessarily going to work in the case of + * WN_MORE_DATA, because our enumerator may have moved on to + * the next provider. MSDN states that a large (16KB) buffer + * size is the appropriate usage of this function, so + * hopefully it won't be an issue. + */ + ret = _thunkNetResourceArrayWToA((LPNETRESOURCEW)localBuffer, + &localCount, lpBuffer, lpBufferSize); + *lpcCount = localCount; + } + HeapFree(GetProcessHeap(), 0, localBuffer); + } + else + ret = WN_OUT_OF_MEMORY; + } + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); + return ret; +} + +static DWORD _countProviderBytesW(PWNetProvider provider) +{ + DWORD ret; + + if (provider) + { + ret = sizeof(NETRESOURCEW); + ret += 2 * (strlenW(provider->name) + 1) * sizeof(WCHAR); + } + else + ret = 0; + return ret; +} + +static DWORD _enumerateProvidersW(PWNetEnumerator enumerator, LPDWORD lpcCount, + LPVOID lpBuffer, LPDWORD lpBufferSize) +{ + DWORD ret; + + if (!enumerator) + return WN_BAD_POINTER; + if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL) + return WN_BAD_VALUE; + if (!lpcCount) + return WN_BAD_POINTER; + if (!lpBuffer) + return WN_BAD_POINTER; + if (!lpBufferSize) + return WN_BAD_POINTER; + if (*lpBufferSize < sizeof(NETRESOURCEA)) + return WN_MORE_DATA; + + if (!providerTable || enumerator->providerIndex >= + providerTable->numProviders) + ret = WN_NO_MORE_ENTRIES; + else + { + DWORD bytes = 0, count = 0, countLimit, i; + LPNETRESOURCEW resource; + LPWSTR strNext; + + countLimit = *lpcCount == -1 ? + providerTable->numProviders - enumerator->providerIndex : *lpcCount; + while (count < countLimit && bytes < *lpBufferSize) + { + DWORD bytesNext = _countProviderBytesW( + &providerTable->table[count + enumerator->providerIndex]); + + if (bytes + bytesNext < *lpBufferSize) + { + bytes += bytesNext; + count++; + } + } + strNext = (LPWSTR)((LPBYTE)lpBuffer + count * sizeof(NETRESOURCEW)); + for (i = 0, resource = (LPNETRESOURCEW)lpBuffer; i < count; + i++, resource++) + { + resource->dwScope = RESOURCE_GLOBALNET; + resource->dwType = RESOURCETYPE_ANY; + resource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK; + resource->dwUsage = RESOURCEUSAGE_CONTAINER | + RESOURCEUSAGE_RESERVED; + resource->lpLocalName = NULL; + resource->lpRemoteName = strNext; + strcpyW(resource->lpRemoteName, + providerTable->table[i + enumerator->providerIndex].name); + strNext += strlenW(resource->lpRemoteName) + 1; + resource->lpComment = NULL; + resource->lpProvider = strNext; + strcpyW(resource->lpProvider, + providerTable->table[i + enumerator->providerIndex].name); + strNext += strlenW(resource->lpProvider) + 1; + } + enumerator->providerIndex += count; + *lpcCount = count; + ret = count > 0 ? WN_SUCCESS : WN_MORE_DATA; + } + TRACE("Returning %ld\n", ret); + return ret; +} + +/* Advances the enumerator (assumed to be a global enumerator) to the next + * provider that supports the enumeration scope passed to WNetOpenEnum. Does + * not open a handle with the next provider. + * If the existing handle is NULL, may leave the enumerator unchanged, since + * the current provider may support the desired scope. + * If the existing handle is not NULL, closes it before moving on. + * Returns WN_SUCCESS on success, WN_NO_MORE_ENTRIES if there is no available + * provider, and another error on failure. + */ +static DWORD _globalEnumeratorAdvance(PWNetEnumerator enumerator) +{ + if (!enumerator) + return WN_BAD_POINTER; + if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL) + return WN_BAD_VALUE; + if (!providerTable || enumerator->providerIndex >= + providerTable->numProviders) + return WN_NO_MORE_ENTRIES; + + if (enumerator->providerDone) + { + enumerator->providerDone = FALSE; + if (enumerator->handle) + { + providerTable->table[enumerator->providerIndex].closeEnum( + enumerator->handle); + enumerator->handle = NULL; + enumerator->providerIndex++; + } + for (; enumerator->providerIndex < providerTable->numProviders && + !(enumerator->dwScope & providerTable->table + [enumerator->providerIndex].dwEnumScopes); + enumerator->providerIndex++) + ; + } + return enumerator->providerIndex < providerTable->numProviders ? + WN_SUCCESS : WN_NO_MORE_ENTRIES; +} + +/* "Passes through" call to the next provider that supports the enumeration + * type. + * FIXME: if one call to a provider's enumerator succeeds while there's still + * space in lpBuffer, I don't call to the next provider. The caller may not + * expect that it should call EnumResourceW again with a return value of + * WN_SUCCESS (depending what *lpcCount was to begin with). That means strings + * may have to be moved around a bit, ick. + */ +static DWORD _enumerateGlobalPassthroughW(PWNetEnumerator enumerator, + LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize) +{ + DWORD ret; + + if (!enumerator) + return WN_BAD_POINTER; + if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL) + return WN_BAD_VALUE; + if (!lpcCount) + return WN_BAD_POINTER; + if (!lpBuffer) + return WN_BAD_POINTER; + if (!lpBufferSize) + return WN_BAD_POINTER; + if (*lpBufferSize < sizeof(NETRESOURCEW)) + return WN_MORE_DATA; + + ret = _globalEnumeratorAdvance(enumerator); + if (ret == WN_SUCCESS) + { + ret = providerTable->table[enumerator->providerIndex]. + openEnum(enumerator->dwScope, enumerator->dwType, + enumerator->dwUsage, enumerator->lpNet, + &enumerator->handle); + if (ret == WN_SUCCESS) + { + ret = providerTable->table[enumerator->providerIndex]. + enumResource(enumerator->handle, lpcCount, lpBuffer, + lpBufferSize); + if (ret != WN_MORE_DATA) + enumerator->providerDone = TRUE; + } + } + TRACE("Returning %ld\n", ret); + return ret; +} + +static DWORD _enumerateGlobalW(PWNetEnumerator enumerator, LPDWORD lpcCount, + LPVOID lpBuffer, LPDWORD lpBufferSize) +{ + DWORD ret; + + if (!enumerator) + return WN_BAD_POINTER; + if (enumerator->enumType != WNET_ENUMERATOR_TYPE_GLOBAL) + return WN_BAD_VALUE; + if (!lpcCount) + return WN_BAD_POINTER; + if (!lpBuffer) + return WN_BAD_POINTER; + if (!lpBufferSize) + return WN_BAD_POINTER; + if (*lpBufferSize < sizeof(NETRESOURCEW)) + return WN_MORE_DATA; + if (!providerTable) + return WN_NO_NETWORK; + + switch (enumerator->dwScope) + { + case RESOURCE_GLOBALNET: + if (enumerator->lpNet) + ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, + lpBuffer, lpBufferSize); + else + ret = _enumerateProvidersW(enumerator, lpcCount, lpBuffer, + lpBufferSize); + break; + case RESOURCE_CONTEXT: + ret = _enumerateGlobalPassthroughW(enumerator, lpcCount, lpBuffer, + lpBufferSize); + break; + default: + WARN("unexpected scope 0x%08lx\n", enumerator->dwScope); + ret = WN_NO_MORE_ENTRIES; + } + TRACE("Returning %ld\n", ret); + return ret; +} + +static DWORD _enumerateProviderW(PWNetEnumerator enumerator, LPDWORD lpcCount, + LPVOID lpBuffer, LPDWORD lpBufferSize) +{ + if (!enumerator) + return WN_BAD_POINTER; + if (enumerator->enumType != WNET_ENUMERATOR_TYPE_PROVIDER) + return WN_BAD_VALUE; + if (!enumerator->handle) + return WN_BAD_VALUE; + if (!lpcCount) + return WN_BAD_POINTER; + if (!lpBuffer) + return WN_BAD_POINTER; + if (!lpBufferSize) + return WN_BAD_POINTER; + if (!providerTable) + return WN_NO_NETWORK; + if (enumerator->providerIndex >= providerTable->numProviders) + return WN_NO_MORE_ENTRIES; + if (!providerTable->table[enumerator->providerIndex].enumResource) + return WN_BAD_VALUE; + return providerTable->table[enumerator->providerIndex].enumResource( + enumerator->handle, lpcCount, lpBuffer, lpBufferSize); +} + +static DWORD _enumerateContextW(PWNetEnumerator enumerator, LPDWORD lpcCount, + LPVOID lpBuffer, LPDWORD lpBufferSize) +{ + DWORD ret; + size_t cchEntireNetworkLen, bytesNeeded; + + if (!enumerator) + return WN_BAD_POINTER; + if (enumerator->enumType != WNET_ENUMERATOR_TYPE_CONTEXT) + return WN_BAD_VALUE; + if (!lpcCount) + return WN_BAD_POINTER; + if (!lpBuffer) + return WN_BAD_POINTER; + if (!lpBufferSize) + return WN_BAD_POINTER; + if (!providerTable) + return WN_NO_NETWORK; + + cchEntireNetworkLen = strlenW(providerTable->entireNetwork) + 1; + bytesNeeded = sizeof(NETRESOURCEW) + cchEntireNetworkLen * sizeof(WCHAR); + if (*lpBufferSize < bytesNeeded) + { + *lpBufferSize = bytesNeeded; + ret = WN_MORE_DATA; + } + else + { + LPNETRESOURCEW lpNet = (LPNETRESOURCEW)lpBuffer; + + lpNet->dwScope = RESOURCE_GLOBALNET; + lpNet->dwType = enumerator->dwType; + lpNet->dwDisplayType = RESOURCEDISPLAYTYPE_ROOT; + lpNet->dwUsage = RESOURCEUSAGE_CONTAINER; + lpNet->lpLocalName = NULL; + lpNet->lpRemoteName = NULL; + lpNet->lpProvider = NULL; + /* odd, but correct: put comment at end of buffer, so it won't get + * overwritten by subsequent calls to a provider's enumResource + */ + lpNet->lpComment = (LPWSTR)((LPBYTE)lpBuffer + *lpBufferSize - + (cchEntireNetworkLen * sizeof(WCHAR))); + strcpyW(lpNet->lpComment, providerTable->entireNetwork); + ret = WN_SUCCESS; + } + if (ret == WN_SUCCESS) + { + DWORD bufferSize = *lpBufferSize - bytesNeeded; + + /* "Entire Network" entry enumerated--morph this into a global + * enumerator. enumerator->lpNet continues to be NULL, since it has + * no meaning when the scope isn't RESOURCE_GLOBALNET. + */ + enumerator->enumType = WNET_ENUMERATOR_TYPE_GLOBAL; + ret = _enumerateGlobalW(enumerator, lpcCount, + (LPBYTE)lpBuffer + bytesNeeded, &bufferSize); + if (ret == WN_SUCCESS) + { + /* reflect the fact that we already enumerated "Entire Network" */ + lpcCount++; + *lpBufferSize = bufferSize + bytesNeeded; + } + else + { + /* the provider enumeration failed, but we already succeeded in + * enumerating "Entire Network"--leave type as global to allow a + * retry, but indicate success with a count of one. + */ + ret = WN_SUCCESS; + *lpcCount = 1; + *lpBufferSize = bytesNeeded; + } + } + TRACE("Returning %ld\n", ret); + return ret; +} + +/********************************************************************* + * WNetEnumResourceW [MPR.@] + */ +DWORD WINAPI WNetEnumResourceW( HANDLE hEnum, LPDWORD lpcCount, + LPVOID lpBuffer, LPDWORD lpBufferSize ) +{ + DWORD ret; + + TRACE( "(%p, %p, %p, %p)\n", hEnum, lpcCount, lpBuffer, lpBufferSize ); + + if (!hEnum) + ret = WN_BAD_POINTER; + else if (!lpcCount) + ret = WN_BAD_POINTER; + else if (!lpBuffer) + ret = WN_BAD_POINTER; + else if (!lpBufferSize) + ret = WN_BAD_POINTER; + else if (*lpBufferSize < sizeof(NETRESOURCEW)) + { + *lpBufferSize = sizeof(NETRESOURCEW); + ret = WN_MORE_DATA; + } + else + { + PWNetEnumerator enumerator = (PWNetEnumerator)hEnum; + + switch (enumerator->enumType) + { + case WNET_ENUMERATOR_TYPE_NULL: + ret = WN_NO_MORE_ENTRIES; + break; + case WNET_ENUMERATOR_TYPE_GLOBAL: + ret = _enumerateGlobalW(enumerator, lpcCount, lpBuffer, + lpBufferSize); + break; + case WNET_ENUMERATOR_TYPE_PROVIDER: + ret = _enumerateProviderW(enumerator, lpcCount, lpBuffer, + lpBufferSize); + break; + case WNET_ENUMERATOR_TYPE_CONTEXT: + ret = _enumerateContextW(enumerator, lpcCount, lpBuffer, + lpBufferSize); + break; + default: + WARN("bogus enumerator type!\n"); + ret = WN_NO_NETWORK; + } + } + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); + return ret; +} + +/********************************************************************* + * WNetCloseEnum [MPR.@] + */ +DWORD WINAPI WNetCloseEnum( HANDLE hEnum ) +{ + DWORD ret; + + TRACE( "(%p)\n", hEnum ); + + if (hEnum) + { + PWNetEnumerator enumerator = (PWNetEnumerator)hEnum; + + switch (enumerator->enumType) + { + case WNET_ENUMERATOR_TYPE_NULL: + ret = WN_SUCCESS; + break; + case WNET_ENUMERATOR_TYPE_GLOBAL: + if (enumerator->lpNet) + _freeEnumNetResource(enumerator->lpNet); + if (enumerator->handle) + providerTable->table[enumerator->providerIndex]. + closeEnum(enumerator->handle); + ret = WN_SUCCESS; + break; + case WNET_ENUMERATOR_TYPE_PROVIDER: + if (enumerator->handle) + providerTable->table[enumerator->providerIndex]. + closeEnum(enumerator->handle); + ret = WN_SUCCESS; + break; + default: + WARN("bogus enumerator type!\n"); + ret = WN_BAD_HANDLE; + } + HeapFree(GetProcessHeap(), 0, hEnum); + } + else + ret = WN_BAD_HANDLE; + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); + return ret; +} + +/********************************************************************* + * WNetGetResourceInformationA [MPR.@] + */ +DWORD WINAPI WNetGetResourceInformationA( LPNETRESOURCEA lpNetResource, + LPVOID lpBuffer, LPDWORD cbBuffer, + LPSTR *lplpSystem ) +{ + FIXME( "(%p, %p, %p, %p): stub\n", + lpNetResource, lpBuffer, cbBuffer, lplpSystem ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/********************************************************************* + * WNetGetResourceInformationW [MPR.@] + */ +DWORD WINAPI WNetGetResourceInformationW( LPNETRESOURCEW lpNetResource, + LPVOID lpBuffer, LPDWORD cbBuffer, + LPWSTR *lplpSystem ) +{ + FIXME( "(%p, %p, %p, %p): stub\n", + lpNetResource, lpBuffer, cbBuffer, lplpSystem ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/********************************************************************* + * WNetGetResourceParentA [MPR.@] + */ +DWORD WINAPI WNetGetResourceParentA( LPNETRESOURCEA lpNetResource, + LPVOID lpBuffer, LPDWORD lpBufferSize ) +{ + FIXME( "(%p, %p, %p): stub\n", + lpNetResource, lpBuffer, lpBufferSize ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/********************************************************************* + * WNetGetResourceParentW [MPR.@] + */ +DWORD WINAPI WNetGetResourceParentW( LPNETRESOURCEW lpNetResource, + LPVOID lpBuffer, LPDWORD lpBufferSize ) +{ + FIXME( "(%p, %p, %p): stub\n", + lpNetResource, lpBuffer, lpBufferSize ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + + + +/* + * Connection Functions + */ + +/********************************************************************* + * WNetAddConnectionA [MPR.@] + */ +DWORD WINAPI WNetAddConnectionA( LPCSTR lpRemoteName, LPCSTR lpPassword, + LPCSTR lpLocalName ) +{ + FIXME( "(%s, %p, %s): stub\n", + debugstr_a(lpRemoteName), lpPassword, debugstr_a(lpLocalName) ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/********************************************************************* + * WNetAddConnectionW [MPR.@] + */ +DWORD WINAPI WNetAddConnectionW( LPCWSTR lpRemoteName, LPCWSTR lpPassword, + LPCWSTR lpLocalName ) +{ + FIXME( "(%s, %p, %s): stub\n", + debugstr_w(lpRemoteName), lpPassword, debugstr_w(lpLocalName) ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/********************************************************************* + * WNetAddConnection2A [MPR.@] + */ +DWORD WINAPI WNetAddConnection2A( LPNETRESOURCEA lpNetResource, + LPCSTR lpPassword, LPCSTR lpUserID, + DWORD dwFlags ) +{ + FIXME( "(%p, %p, %s, 0x%08lX): stub\n", + lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/********************************************************************* + * WNetAddConnection2W [MPR.@] + */ +DWORD WINAPI WNetAddConnection2W( LPNETRESOURCEW lpNetResource, + LPCWSTR lpPassword, LPCWSTR lpUserID, + DWORD dwFlags ) +{ + FIXME( "(%p, %p, %s, 0x%08lX): stub\n", + lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/********************************************************************* + * WNetAddConnection3A [MPR.@] + */ +DWORD WINAPI WNetAddConnection3A( HWND hwndOwner, LPNETRESOURCEA lpNetResource, + LPCSTR lpPassword, LPCSTR lpUserID, + DWORD dwFlags ) +{ + FIXME( "(%p, %p, %p, %s, 0x%08lX), stub\n", + hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/********************************************************************* + * WNetAddConnection3W [MPR.@] + */ +DWORD WINAPI WNetAddConnection3W( HWND hwndOwner, LPNETRESOURCEW lpNetResource, + LPCWSTR lpPassword, LPCWSTR lpUserID, + DWORD dwFlags ) +{ + FIXME( "(%p, %p, %p, %s, 0x%08lX), stub\n", + hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/***************************************************************** + * WNetUseConnectionA [MPR.@] + */ +DWORD WINAPI WNetUseConnectionA( HWND hwndOwner, LPNETRESOURCEA lpNetResource, + LPCSTR lpPassword, LPCSTR lpUserID, DWORD dwFlags, + LPSTR lpAccessName, LPDWORD lpBufferSize, + LPDWORD lpResult ) +{ + FIXME( "(%p, %p, %p, %s, 0x%08lX, %s, %p, %p), stub\n", + hwndOwner, lpNetResource, lpPassword, debugstr_a(lpUserID), dwFlags, + debugstr_a(lpAccessName), lpBufferSize, lpResult ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/***************************************************************** + * WNetUseConnectionW [MPR.@] + */ +DWORD WINAPI WNetUseConnectionW( HWND hwndOwner, LPNETRESOURCEW lpNetResource, + LPCWSTR lpPassword, LPCWSTR lpUserID, DWORD dwFlags, + LPWSTR lpAccessName, LPDWORD lpBufferSize, + LPDWORD lpResult ) +{ + FIXME( "(%p, %p, %p, %s, 0x%08lX, %s, %p, %p), stub\n", + hwndOwner, lpNetResource, lpPassword, debugstr_w(lpUserID), dwFlags, + debugstr_w(lpAccessName), lpBufferSize, lpResult ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/********************************************************************* + * WNetCancelConnectionA [MPR.@] + */ +DWORD WINAPI WNetCancelConnectionA( LPCSTR lpName, BOOL fForce ) +{ + FIXME( "(%s, %d), stub\n", debugstr_a(lpName), fForce ); + + return WN_SUCCESS; +} + +/********************************************************************* + * WNetCancelConnectionW [MPR.@] + */ +DWORD WINAPI WNetCancelConnectionW( LPCWSTR lpName, BOOL fForce ) +{ + FIXME( "(%s, %d), stub\n", debugstr_w(lpName), fForce ); + + return WN_SUCCESS; +} + +/********************************************************************* + * WNetCancelConnection2A [MPR.@] + */ +DWORD WINAPI WNetCancelConnection2A( LPCSTR lpName, DWORD dwFlags, BOOL fForce ) +{ + FIXME( "(%s, %08lX, %d), stub\n", debugstr_a(lpName), dwFlags, fForce ); + + return WN_SUCCESS; +} + +/********************************************************************* + * WNetCancelConnection2W [MPR.@] + */ +DWORD WINAPI WNetCancelConnection2W( LPCWSTR lpName, DWORD dwFlags, BOOL fForce ) +{ + FIXME( "(%s, %08lX, %d), stub\n", debugstr_w(lpName), dwFlags, fForce ); + + return WN_SUCCESS; +} + +/***************************************************************** + * WNetRestoreConnectionA [MPR.@] + */ +DWORD WINAPI WNetRestoreConnectionA( HWND hwndOwner, LPSTR lpszDevice ) +{ + FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_a(lpszDevice) ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/***************************************************************** + * WNetRestoreConnectionW [MPR.@] + */ +DWORD WINAPI WNetRestoreConnectionW( HWND hwndOwner, LPWSTR lpszDevice ) +{ + FIXME( "(%p, %s), stub\n", hwndOwner, debugstr_w(lpszDevice) ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/************************************************************************** + * WNetGetConnectionA [MPR.@] + * + * RETURNS + * - WN_BAD_LOCALNAME lpLocalName makes no sense + * - WN_NOT_CONNECTED drive is a local drive + * - WN_MORE_DATA buffer isn't big enough + * - WN_SUCCESS success (net path in buffer) + * + * FIXME: need to test return values under different errors + */ +DWORD WINAPI WNetGetConnectionA( LPCSTR lpLocalName, + LPSTR lpRemoteName, LPDWORD lpBufferSize ) +{ + DWORD ret; + + if (!lpLocalName) + ret = WN_BAD_POINTER; + else if (!lpRemoteName) + ret = WN_BAD_POINTER; + else if (!lpBufferSize) + ret = WN_BAD_POINTER; + else + { + int len = MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, NULL, 0); + + if (len) + { + PWSTR wideLocalName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + + if (wideLocalName) + { + WCHAR wideRemoteStatic[MAX_PATH]; + DWORD wideRemoteSize = sizeof(wideRemoteStatic) / sizeof(WCHAR); + + MultiByteToWideChar(CP_ACP, 0, lpLocalName, -1, wideLocalName, len); + + /* try once without memory allocation */ + ret = WNetGetConnectionW(wideLocalName, wideRemoteStatic, + &wideRemoteSize); + if (ret == WN_SUCCESS) + { + int len = WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, + -1, NULL, 0, NULL, NULL); + + if (len <= *lpBufferSize) + { + WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, -1, + lpRemoteName, *lpBufferSize, NULL, NULL); + ret = WN_SUCCESS; + } + else + { + *lpBufferSize = len; + ret = WN_MORE_DATA; + } + } + else if (ret == WN_MORE_DATA) + { + PWSTR wideRemote = HeapAlloc(GetProcessHeap(), 0, + wideRemoteSize * sizeof(WCHAR)); + + if (wideRemote) + { + ret = WNetGetConnectionW(wideLocalName, wideRemote, + &wideRemoteSize); + if (ret == WN_SUCCESS) + { + if (len <= *lpBufferSize) + { + WideCharToMultiByte(CP_ACP, 0, wideRemoteStatic, + -1, lpRemoteName, *lpBufferSize, NULL, NULL); + ret = WN_SUCCESS; + } + else + { + *lpBufferSize = len; + ret = WN_MORE_DATA; + } + } + HeapFree(GetProcessHeap(), 0, wideRemote); + } + else + ret = WN_OUT_OF_MEMORY; + } + HeapFree(GetProcessHeap(), 0, wideLocalName); + } + else + ret = WN_OUT_OF_MEMORY; + } + else + ret = WN_BAD_LOCALNAME; + } + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); + return ret; +} + +/************************************************************************** + * WNetGetConnectionW [MPR.@] + * + * FIXME: need to test return values under different errors + */ +DWORD WINAPI WNetGetConnectionW( LPCWSTR lpLocalName, + LPWSTR lpRemoteName, LPDWORD lpBufferSize ) +{ + DWORD ret; + + TRACE("(%s, %p, %p)\n", debugstr_w(lpLocalName), lpRemoteName, + lpBufferSize); + + if (!lpLocalName) + ret = WN_BAD_POINTER; + else if (!lpRemoteName) + ret = WN_BAD_POINTER; + else if (!lpBufferSize) + ret = WN_BAD_POINTER; + else if (!lpLocalName[0]) + ret = WN_BAD_LOCALNAME; + else + { + if (lpLocalName[1] == ':') + { + switch(GetDriveTypeW(lpLocalName)) + { + case DRIVE_REMOTE: + { + WCHAR remote[MAX_PATH]; + if (!QueryDosDeviceW( lpLocalName, remote, MAX_PATH )) remote[0] = 0; + if (strlenW(remote) + 1 > *lpBufferSize) + { + *lpBufferSize = strlenW(remote) + 1; + ret = WN_MORE_DATA; + } + else + { + strcpyW( lpRemoteName, remote ); + *lpBufferSize = strlenW(lpRemoteName) + 1; + ret = WN_SUCCESS; + } + break; + } + case DRIVE_REMOVABLE: + case DRIVE_FIXED: + case DRIVE_CDROM: + TRACE("file is local\n"); + ret = WN_NOT_CONNECTED; + break; + default: + ret = WN_BAD_LOCALNAME; + } + } + else + ret = WN_BAD_LOCALNAME; + } + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); + return ret; +} + +/************************************************************************** + * WNetSetConnectionA [MPR.@] + */ +DWORD WINAPI WNetSetConnectionA( LPCSTR lpName, DWORD dwProperty, + LPVOID pvValue ) +{ + FIXME( "(%s, %08lX, %p): stub\n", debugstr_a(lpName), dwProperty, pvValue ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/************************************************************************** + * WNetSetConnectionW [MPR.@] + */ +DWORD WINAPI WNetSetConnectionW( LPCWSTR lpName, DWORD dwProperty, + LPVOID pvValue ) +{ + FIXME( "(%s, %08lX, %p): stub\n", debugstr_w(lpName), dwProperty, pvValue ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/***************************************************************** + * WNetGetUniversalNameA [MPR.@] + */ +DWORD WINAPI WNetGetUniversalNameA ( LPCSTR lpLocalPath, DWORD dwInfoLevel, + LPVOID lpBuffer, LPDWORD lpBufferSize ) +{ + FIXME( "(%s, 0x%08lX, %p, %p): stub\n", + debugstr_a(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/***************************************************************** + * WNetGetUniversalNameW [MPR.@] + */ +DWORD WINAPI WNetGetUniversalNameW ( LPCWSTR lpLocalPath, DWORD dwInfoLevel, + LPVOID lpBuffer, LPDWORD lpBufferSize ) +{ + FIXME( "(%s, 0x%08lX, %p, %p): stub\n", + debugstr_w(lpLocalPath), dwInfoLevel, lpBuffer, lpBufferSize); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + + + +/* + * Other Functions + */ + +/************************************************************************** + * WNetGetUserA [MPR.@] + * + * FIXME: we should not return ourselves, but the owner of the drive lpName + */ +DWORD WINAPI WNetGetUserA( LPCSTR lpName, LPSTR lpUserID, LPDWORD lpBufferSize ) +{ + if (GetUserNameA( lpUserID, lpBufferSize )) return WN_SUCCESS; + return GetLastError(); +} + +/***************************************************************** + * WNetGetUserW [MPR.@] + * + * FIXME: we should not return ourselves, but the owner of the drive lpName + */ +DWORD WINAPI WNetGetUserW( LPCWSTR lpName, LPWSTR lpUserID, LPDWORD lpBufferSize ) +{ + if (GetUserNameW( lpUserID, lpBufferSize )) return WN_SUCCESS; + return GetLastError(); +} + +/********************************************************************* + * WNetConnectionDialog [MPR.@] + */ +DWORD WINAPI WNetConnectionDialog( HWND hwnd, DWORD dwType ) +{ + FIXME( "(%p, %08lX): stub\n", hwnd, dwType ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/********************************************************************* + * WNetConnectionDialog1A [MPR.@] + */ +DWORD WINAPI WNetConnectionDialog1A( LPCONNECTDLGSTRUCTA lpConnDlgStruct ) +{ + FIXME( "(%p): stub\n", lpConnDlgStruct ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/********************************************************************* + * WNetConnectionDialog1W [MPR.@] + */ +DWORD WINAPI WNetConnectionDialog1W( LPCONNECTDLGSTRUCTW lpConnDlgStruct ) +{ + FIXME( "(%p): stub\n", lpConnDlgStruct ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/********************************************************************* + * WNetDisconnectDialog [MPR.@] + */ +DWORD WINAPI WNetDisconnectDialog( HWND hwnd, DWORD dwType ) +{ + FIXME( "(%p, %08lX): stub\n", hwnd, dwType ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/********************************************************************* + * WNetDisconnectDialog1A [MPR.@] + */ +DWORD WINAPI WNetDisconnectDialog1A( LPDISCDLGSTRUCTA lpConnDlgStruct ) +{ + FIXME( "(%p): stub\n", lpConnDlgStruct ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/********************************************************************* + * WNetDisconnectDialog1W [MPR.@] + */ +DWORD WINAPI WNetDisconnectDialog1W( LPDISCDLGSTRUCTW lpConnDlgStruct ) +{ + FIXME( "(%p): stub\n", lpConnDlgStruct ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/********************************************************************* + * WNetGetLastErrorA [MPR.@] + */ +DWORD WINAPI WNetGetLastErrorA( LPDWORD lpError, + LPSTR lpErrorBuf, DWORD nErrorBufSize, + LPSTR lpNameBuf, DWORD nNameBufSize ) +{ + FIXME( "(%p, %p, %ld, %p, %ld): stub\n", + lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/********************************************************************* + * WNetGetLastErrorW [MPR.@] + */ +DWORD WINAPI WNetGetLastErrorW( LPDWORD lpError, + LPWSTR lpErrorBuf, DWORD nErrorBufSize, + LPWSTR lpNameBuf, DWORD nNameBufSize ) +{ + FIXME( "(%p, %p, %ld, %p, %ld): stub\n", + lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize ); + + SetLastError(WN_NO_NETWORK); + return WN_NO_NETWORK; +} + +/********************************************************************* + * WNetGetNetworkInformationA [MPR.@] + */ +DWORD WINAPI WNetGetNetworkInformationA( LPCSTR lpProvider, + LPNETINFOSTRUCT lpNetInfoStruct ) +{ + DWORD ret; + + TRACE( "(%s, %p)\n", debugstr_a(lpProvider), lpNetInfoStruct ); + + if (!lpProvider) + ret = WN_BAD_POINTER; + else + { + int len; + + len = MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, NULL, 0); + if (len) + { + LPWSTR wideProvider = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + + if (wideProvider) + { + MultiByteToWideChar(CP_ACP, 0, lpProvider, -1, wideProvider, + len); + ret = WNetGetNetworkInformationW(wideProvider, lpNetInfoStruct); + HeapFree(GetProcessHeap(), 0, wideProvider); + } + else + ret = WN_OUT_OF_MEMORY; + } + else + ret = GetLastError(); + } + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); + return ret; +} + +/********************************************************************* + * WNetGetNetworkInformationW [MPR.@] + */ +DWORD WINAPI WNetGetNetworkInformationW( LPCWSTR lpProvider, + LPNETINFOSTRUCT lpNetInfoStruct ) +{ + DWORD ret; + + TRACE( "(%s, %p)\n", debugstr_w(lpProvider), lpNetInfoStruct ); + + if (!lpProvider) + ret = WN_BAD_POINTER; + else if (!lpNetInfoStruct) + ret = WN_BAD_POINTER; + else if (lpNetInfoStruct->cbStructure < sizeof(NETINFOSTRUCT)) + ret = WN_BAD_VALUE; + else + { + if (providerTable && providerTable->numProviders) + { + DWORD providerIndex = _findProviderIndexW(lpProvider); + + if (providerIndex != BAD_PROVIDER_INDEX) + { + lpNetInfoStruct->cbStructure = sizeof(NETINFOSTRUCT); + lpNetInfoStruct->dwProviderVersion = + providerTable->table[providerIndex].dwSpecVersion; + lpNetInfoStruct->dwStatus = NO_ERROR; + lpNetInfoStruct->dwCharacteristics = 0; + lpNetInfoStruct->dwHandle = (ULONG_PTR)NULL; + lpNetInfoStruct->wNetType = + HIWORD(providerTable->table[providerIndex].dwNetType); + lpNetInfoStruct->dwPrinters = -1; + lpNetInfoStruct->dwDrives = -1; + ret = WN_SUCCESS; + } + else + ret = WN_BAD_PROVIDER; + } + else + ret = WN_NO_NETWORK; + } + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); + return ret; +} + +/***************************************************************** + * WNetGetProviderNameA [MPR.@] + */ +DWORD WINAPI WNetGetProviderNameA( DWORD dwNetType, + LPSTR lpProvider, LPDWORD lpBufferSize ) +{ + DWORD ret; + + TRACE("(0x%08lx, %s, %p)\n", dwNetType, debugstr_a(lpProvider), + lpBufferSize); + + if (!lpProvider) + ret = WN_BAD_POINTER; + else if (!lpBufferSize) + ret = WN_BAD_POINTER; + else + { + if (providerTable) + { + DWORD i; + + ret = WN_NO_NETWORK; + for (i = 0; i < providerTable->numProviders && + HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType); + i++) + ; + if (i < providerTable->numProviders) + { + DWORD sizeNeeded = WideCharToMultiByte(CP_ACP, 0, + providerTable->table[i].name, -1, NULL, 0, NULL, NULL); + + if (*lpBufferSize < sizeNeeded) + { + *lpBufferSize = sizeNeeded; + ret = WN_MORE_DATA; + } + else + { + WideCharToMultiByte(CP_ACP, 0, providerTable->table[i].name, + -1, lpProvider, *lpBufferSize, NULL, NULL); + ret = WN_SUCCESS; + /* FIXME: is *lpBufferSize set to the number of characters + * copied? */ + } + } + } + else + ret = WN_NO_NETWORK; + } + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); + return ret; +} + +/***************************************************************** + * WNetGetProviderNameW [MPR.@] + */ +DWORD WINAPI WNetGetProviderNameW( DWORD dwNetType, + LPWSTR lpProvider, LPDWORD lpBufferSize ) +{ + DWORD ret; + + TRACE("(0x%08lx, %s, %p)\n", dwNetType, debugstr_w(lpProvider), + lpBufferSize); + + if (!lpProvider) + ret = WN_BAD_POINTER; + else if (!lpBufferSize) + ret = WN_BAD_POINTER; + else + { + if (providerTable) + { + DWORD i; + + ret = WN_NO_NETWORK; + for (i = 0; i < providerTable->numProviders && + HIWORD(providerTable->table[i].dwNetType) != HIWORD(dwNetType); + i++) + ; + if (i < providerTable->numProviders) + { + DWORD sizeNeeded = strlenW(providerTable->table[i].name) + 1; + + if (*lpBufferSize < sizeNeeded) + { + *lpBufferSize = sizeNeeded; + ret = WN_MORE_DATA; + } + else + { + strcpyW(lpProvider, providerTable->table[i].name); + ret = WN_SUCCESS; + /* FIXME: is *lpBufferSize set to the number of characters + * copied? */ + } + } + } + else + ret = WN_NO_NETWORK; + } + if (ret) + SetLastError(ret); + TRACE("Returning %ld\n", ret); + return ret; +} diff --git a/reactos/lib/mpr/wnetpriv.h b/reactos/lib/mpr/wnetpriv.h index 5b0116404bc..7a275de1445 100644 --- a/reactos/lib/mpr/wnetpriv.h +++ b/reactos/lib/mpr/wnetpriv.h @@ -1,27 +1,27 @@ -/* - * WNet private definitions - * - * Copyright (C) 2004 Juan Lang - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WNET_PRIV_H__ -#define __WNET_PRIV_H__ - -void wnetInit(HINSTANCE hInstDll); -void wnetFree(void); - -#endif /* ndef __WNET_PRIV_H__ */ +/* + * WNet private definitions + * + * Copyright (C) 2004 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WNET_PRIV_H__ +#define __WNET_PRIV_H__ + +void wnetInit(HINSTANCE hInstDll); +void wnetFree(void); + +#endif /* ndef __WNET_PRIV_H__ */ diff --git a/reactos/lib/msi/cond.tab.c b/reactos/lib/msi/cond.tab.c index 72fe698b431..d025c24df54 100644 --- a/reactos/lib/msi/cond.tab.c +++ b/reactos/lib/msi/cond.tab.c @@ -1,2031 +1,2031 @@ -/* A Bison parser, made from ./cond.y - by GNU bison 1.35. */ - -#define YYBISON 1 /* Identify Bison output. */ - -#define yyparse COND_parse -#define yylex COND_lex -#define yyerror COND_error -#define yylval COND_lval -#define yychar COND_char -#define yydebug COND_debug -#define yynerrs COND_nerrs -# define COND_SPACE 257 -# define COND_EOF 258 -# define COND_OR 259 -# define COND_AND 260 -# define COND_NOT 261 -# define COND_LT 262 -# define COND_GT 263 -# define COND_EQ 264 -# define COND_LPAR 265 -# define COND_RPAR 266 -# define COND_TILDA 267 -# define COND_PERCENT 268 -# define COND_DOLLARS 269 -# define COND_QUESTION 270 -# define COND_AMPER 271 -# define COND_EXCLAM 272 -# define COND_IDENT 273 -# define COND_NUMBER 274 -# define COND_LITER 275 -# define COND_ERROR 276 - -#line 1 "./cond.y" - - -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2003 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> - -#include "windef.h" -#include "winbase.h" -#include "wine/debug.h" -#include "wine/unicode.h" - -#include "msi.h" -#include "msiquery.h" -#include "msipriv.h" - -#define YYLEX_PARAM info -#define YYPARSE_PARAM info - -static int COND_error(char *str); - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -typedef struct tag_yyinput -{ - MSIPACKAGE *package; - LPCWSTR str; - INT n; - MSICONDITION result; -} COND_input; - -struct cond_str { - LPCWSTR data; - INT len; -}; - -static LPWSTR COND_GetString( struct cond_str *str ); -static LPWSTR COND_GetLiteral( struct cond_str *str ); -static int COND_lex( void *COND_lval, COND_input *info); - -typedef INT (*comp_int)(INT a, INT b); -typedef INT (*comp_str)(LPWSTR a, LPWSTR b, BOOL caseless); -typedef INT (*comp_m1)(LPWSTR a,int b); -typedef INT (*comp_m2)(int a,LPWSTR b); - -static INT comp_lt_i(INT a, INT b); -static INT comp_gt_i(INT a, INT b); -static INT comp_le_i(INT a, INT b); -static INT comp_ge_i(INT a, INT b); -static INT comp_eq_i(INT a, INT b); -static INT comp_ne_i(INT a, INT b); -static INT comp_bitand(INT a, INT b); -static INT comp_highcomp(INT a, INT b); -static INT comp_lowcomp(INT a, INT b); - -static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless); - -static INT comp_eq_m1(LPWSTR a, INT b); -static INT comp_ne_m1(LPWSTR a, INT b); -static INT comp_lt_m1(LPWSTR a, INT b); -static INT comp_gt_m1(LPWSTR a, INT b); -static INT comp_le_m1(LPWSTR a, INT b); -static INT comp_ge_m1(LPWSTR a, INT b); - -static INT comp_eq_m2(INT a, LPWSTR b); -static INT comp_ne_m2(INT a, LPWSTR b); -static INT comp_lt_m2(INT a, LPWSTR b); -static INT comp_gt_m2(INT a, LPWSTR b); -static INT comp_le_m2(INT a, LPWSTR b); -static INT comp_ge_m2(INT a, LPWSTR b); - - -#line 105 "./cond.y" -#ifndef YYSTYPE -typedef union -{ - struct cond_str str; - LPWSTR string; - INT value; - comp_int fn_comp_int; - comp_str fn_comp_str; - comp_m1 fn_comp_m1; - comp_m2 fn_comp_m2; -} yystype; -# define YYSTYPE yystype -# define YYSTYPE_IS_TRIVIAL 1 -#endif -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif - - - -#define YYFINAL 74 -#define YYFLAG -32768 -#define YYNTBASE 23 - -/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */ -#define YYTRANSLATE(x) ((unsigned)(x) <= 276 ? yytranslate[x] : 39) - -/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */ -static const char yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 3, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22 -}; - -#if YYDEBUG -static const short yyprhs[] = -{ - 0, 0, 2, 4, 8, 10, 14, 16, 19, 21, - 23, 27, 31, 36, 40, 44, 48, 50, 53, 55, - 57, 60, 63, 66, 69, 72, 74, 77, 79, 81, - 84, 87, 90, 93, 96, 98, 101, 103, 105, 108, - 111, 114, 117, 120, 122, 125, 127, 129, 132, 135, - 138, 141, 144, 146, 148, 150, 152, 154, 157, 160, - 163, 166, 168, 171, 173 -}; -static const short yyrhs[] = -{ - 24, 0, 25, 0, 25, 5, 24, 0, 26, 0, - 25, 6, 26, 0, 27, 0, 7, 27, 0, 32, - 0, 33, 0, 32, 28, 32, 0, 33, 29, 33, - 0, 33, 13, 29, 33, 0, 33, 30, 32, 0, - 32, 31, 33, 0, 11, 24, 12, 0, 10, 0, - 8, 9, 0, 8, 0, 9, 0, 8, 10, 0, - 9, 10, 0, 9, 8, 0, 8, 8, 0, 9, - 9, 0, 10, 0, 8, 9, 0, 8, 0, 9, - 0, 8, 10, 0, 9, 10, 0, 9, 8, 0, - 8, 8, 0, 9, 9, 0, 10, 0, 8, 9, - 0, 8, 0, 9, 0, 8, 10, 0, 9, 10, - 0, 9, 8, 0, 8, 8, 0, 9, 9, 0, - 10, 0, 8, 9, 0, 8, 0, 9, 0, 8, - 10, 0, 9, 10, 0, 9, 8, 0, 8, 8, - 0, 9, 9, 0, 35, 0, 38, 0, 36, 0, - 34, 0, 21, 0, 15, 37, 0, 16, 37, 0, - 17, 37, 0, 18, 37, 0, 37, 0, 14, 37, - 0, 19, 0, 20, 0 -}; - -#endif - -#if YYDEBUG -/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ -static const short yyrline[] = -{ - 0, 135, 143, 148, 154, 159, 165, 170, 177, 182, - 186, 190, 194, 198, 202, 206, 212, 218, 222, 226, - 230, 234, 239, 243, 247, 253, 259, 263, 267, 271, - 275, 280, 284, 288, 294, 300, 304, 308, 312, 316, - 321, 325, 329, 335, 341, 345, 349, 353, 357, 362, - 366, 370, 376, 381, 387, 392, 398, 407, 417, 426, - 435, 446, 470, 483, 492 -}; -#endif - - -#if (YYDEBUG) || defined YYERROR_VERBOSE - -/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */ -static const char *const yytname[] = -{ - "$", "error", "$undefined.", "COND_SPACE", "COND_EOF", "COND_OR", - "COND_AND", "COND_NOT", "COND_LT", "COND_GT", "COND_EQ", "COND_LPAR", - "COND_RPAR", "COND_TILDA", "COND_PERCENT", "COND_DOLLARS", - "COND_QUESTION", "COND_AMPER", "COND_EXCLAM", "COND_IDENT", - "COND_NUMBER", "COND_LITER", "COND_ERROR", "condition", "expression", - "boolean_term", "boolean_factor", "term", "comp_op_i", "comp_op_s", - "comp_op_m1", "comp_op_m2", "value_i", "value_s", "literal", "symbol_i", - "symbol_s", "identifier", "integer", 0 -}; -#endif - -/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const short yyr1[] = -{ - 0, 23, 24, 24, 25, 25, 26, 26, 27, 27, - 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 32, 32, 33, 33, 34, 35, 35, 35, - 35, 36, 36, 37, 38 -}; - -/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ -static const short yyr2[] = -{ - 0, 1, 1, 3, 1, 3, 1, 2, 1, 1, - 3, 3, 4, 3, 3, 3, 1, 2, 1, 1, - 2, 2, 2, 2, 2, 1, 2, 1, 1, 2, - 2, 2, 2, 2, 1, 2, 1, 1, 2, 2, - 2, 2, 2, 1, 2, 1, 1, 2, 2, 2, - 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, - 2, 1, 2, 1, 1 -}; - -/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE - doesn't specify something else to do. Zero means the default is an - error. */ -static const short yydefact[] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, - 56, 1, 2, 4, 6, 8, 9, 55, 52, 54, - 61, 53, 7, 0, 62, 57, 58, 59, 60, 0, - 0, 18, 19, 16, 0, 0, 36, 37, 34, 0, - 0, 0, 15, 3, 5, 23, 17, 20, 22, 24, - 21, 10, 14, 41, 35, 38, 40, 42, 39, 27, - 28, 25, 0, 11, 13, 32, 26, 29, 31, 33, - 30, 12, 0, 0, 0 -}; - -static const short yydefgoto[] = -{ - 72, 11, 12, 13, 14, 34, 40, 41, 35, 15, - 16, 17, 18, 19, 20, 21 -}; - -static const short yypact[] = -{ - -5, 50, -5, -12, -12, -12, -12, -12,-32768,-32768, - -32768,-32768, -2,-32768,-32768, 48, 123,-32768,-32768,-32768, - -32768,-32768,-32768, -4,-32768,-32768,-32768,-32768,-32768, -5, - -5, 10, 24, 33, 110, 58, 27, 41, 59, 135, - 58, 110,-32768,-32768,-32768, 62, 68, 71, 72, 80, - 81,-32768,-32768, 84, 90, 93, 94, 102, 103, 138, - 141,-32768, 58,-32768,-32768,-32768,-32768,-32768,-32768,-32768, - -32768,-32768, 17, 21,-32768 -}; - -static const short yypgoto[] = -{ - -32768, -1,-32768, -8, 25,-32768, -14,-32768,-32768, -11, - -35,-32768,-32768,-32768, 134,-32768 -}; - - -#define YYLAST 151 - - -static const short yytable[] = -{ - 52, 23, 1, 29, 30, 63, 2, 8, 42, 3, - 4, 5, 6, 7, 8, 9, 10, 73, 45, 46, - 47, 74, 44, 51, -45, 62, 22, 71, 43, -45, - 64, -45, 48, 49, 50, 53, 54, 55, -46, 0, - 0, -27, 0, -46, 0, -46, -27, -43, -27, 56, - 57, 58, -43, 0, -43, -28, 31, 32, 33, 0, - -28, 2, -28, 0, 3, 4, 5, 6, 7, 8, - 9, 10, 3, -25, 0, 0, -50, 8, -25, 10, - -25, -50, -44, -50, 0, -47, -49, -44, 0, -44, - -47, -49, -47, -49, -51, -48, 0, 0, -32, -51, - -48, -51, -48, -32, -26, -32, 0, -29, -31, -26, - 0, -26, -29, -31, -29, -31, -33, -30, 0, 0, - 0, -33, -30, -33, -30, 4, 5, 6, 7, 0, - 9, 36, 37, 38, 0, 0, 39, 24, 25, 26, - 27, 28, 0, 59, 60, 61, 65, 66, 67, 68, - 69, 70 -}; - -static const short yycheck[] = -{ - 35, 2, 7, 5, 6, 40, 11, 19, 12, 14, - 15, 16, 17, 18, 19, 20, 21, 0, 8, 9, - 10, 0, 30, 34, 14, 39, 1, 62, 29, 19, - 41, 21, 8, 9, 10, 8, 9, 10, 14, -1, - -1, 14, -1, 19, -1, 21, 19, 14, 21, 8, - 9, 10, 19, -1, 21, 14, 8, 9, 10, -1, - 19, 11, 21, -1, 14, 15, 16, 17, 18, 19, - 20, 21, 14, 14, -1, -1, 14, 19, 19, 21, - 21, 19, 14, 21, -1, 14, 14, 19, -1, 21, - 19, 19, 21, 21, 14, 14, -1, -1, 14, 19, - 19, 21, 21, 19, 14, 21, -1, 14, 14, 19, - -1, 21, 19, 19, 21, 21, 14, 14, -1, -1, - -1, 19, 19, 21, 21, 15, 16, 17, 18, -1, - 20, 8, 9, 10, -1, -1, 13, 3, 4, 5, - 6, 7, -1, 8, 9, 10, 8, 9, 10, 8, - 9, 10 -}; -#define YYPURE 1 - -/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ -#line 3 "/usr/share/bison/bison.simple" - -/* Skeleton output parser for bison, - - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software - Foundation, Inc. - - 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, 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., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -/* As a special exception, when this file is copied by Bison into a - Bison output file, you may use that output file without restriction. - This special exception was added by the Free Software Foundation - in version 1.24 of Bison. */ - -/* This is the parser code that is written into each bison parser when - the %semantic_parser declaration is not specified in the grammar. - It was written by Richard Stallman by simplifying the hairy parser - used when %semantic_parser is specified. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -#if ! defined (yyoverflow) || defined (YYERROR_VERBOSE) - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# if YYSTACK_USE_ALLOCA -# define YYSTACK_ALLOC alloca -# else -# ifndef YYSTACK_USE_ALLOCA -# if defined (alloca) || defined (_ALLOCA_H) -# define YYSTACK_ALLOC alloca -# else -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# endif -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's `empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) -# else -# if defined (__STDC__) || defined (__cplusplus) -# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# endif -# define YYSTACK_ALLOC malloc -# define YYSTACK_FREE free -# endif -#endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */ - - -#if (! defined (yyoverflow) \ - && (! defined (__cplusplus) \ - || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - short yyss; - YYSTYPE yyvs; -# if YYLSP_NEEDED - YYLTYPE yyls; -# endif -}; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# if YYLSP_NEEDED -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ - + 2 * YYSTACK_GAP_MAX) -# else -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ - + YYSTACK_GAP_MAX) -# endif - -/* Copy COUNT objects from FROM to TO. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) -# else -# define YYCOPY(To, From, Count) \ - do \ - { \ - register YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ - while (0) -# endif -# endif - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack, Stack, yysize); \ - Stack = &yyptr->Stack; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAX; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (0) - -#endif - - -#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) -# define YYSIZE_T __SIZE_TYPE__ -#endif -#if ! defined (YYSIZE_T) && defined (size_t) -# define YYSIZE_T size_t -#endif -#if ! defined (YYSIZE_T) -# if defined (__STDC__) || defined (__cplusplus) -# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# endif -#endif -#if ! defined (YYSIZE_T) -# define YYSIZE_T unsigned int -#endif - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY -2 -#define YYEOF 0 -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrlab1 -/* Like YYERROR except do call yyerror. This remains here temporarily - to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. */ -#define YYFAIL goto yyerrlab -#define YYRECOVERING() (!!yyerrstatus) -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - yychar1 = YYTRANSLATE (yychar); \ - YYPOPSTACK; \ - goto yybackup; \ - } \ - else \ - { \ - yyerror ("syntax error: cannot back up"); \ - YYERROR; \ - } \ -while (0) - -#define YYTERROR 1 -#define YYERRCODE 256 - - -/* YYLLOC_DEFAULT -- Compute the default location (before the actions - are run). - - When YYLLOC_DEFAULT is run, CURRENT is set the location of the - first token. By default, to implement support for ranges, extend - its range to the last symbol. */ - -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - Current.last_line = Rhs[N].last_line; \ - Current.last_column = Rhs[N].last_column; -#endif - - -/* YYLEX -- calling `yylex' with the right arguments. */ - -#if YYPURE -# if YYLSP_NEEDED -# ifdef YYLEX_PARAM -# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) -# else -# define YYLEX yylex (&yylval, &yylloc) -# endif -# else /* !YYLSP_NEEDED */ -# ifdef YYLEX_PARAM -# define YYLEX yylex (&yylval, YYLEX_PARAM) -# else -# define YYLEX yylex (&yylval) -# endif -# endif /* !YYLSP_NEEDED */ -#else /* !YYPURE */ -# define YYLEX yylex () -#endif /* !YYPURE */ - - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (0) -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -#endif /* !YYDEBUG */ - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#if YYMAXDEPTH == 0 -# undef YYMAXDEPTH -#endif - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - -#ifdef YYERROR_VERBOSE - -# ifndef yystrlen -# if defined (__GLIBC__) && defined (_STRING_H) -# define yystrlen strlen -# else -/* Return the length of YYSTR. */ -static YYSIZE_T -# if defined (__STDC__) || defined (__cplusplus) -yystrlen (const char *yystr) -# else -yystrlen (yystr) - const char *yystr; -# endif -{ - register const char *yys = yystr; - - while (*yys++ != '\0') - continue; - - return yys - yystr - 1; -} -# endif -# endif - -# ifndef yystpcpy -# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) -# define yystpcpy stpcpy -# else -/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in - YYDEST. */ -static char * -# if defined (__STDC__) || defined (__cplusplus) -yystpcpy (char *yydest, const char *yysrc) -# else -yystpcpy (yydest, yysrc) - char *yydest; - const char *yysrc; -# endif -{ - register char *yyd = yydest; - register const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif -#endif - -#line 315 "/usr/share/bison/bison.simple" - - -/* The user can define YYPARSE_PARAM as the name of an argument to be passed - into yyparse. The argument should have type void *. - It should actually point to an object. - Grammar actions can access the variable by casting it - to the proper pointer type. */ - -#ifdef YYPARSE_PARAM -# if defined (__STDC__) || defined (__cplusplus) -# define YYPARSE_PARAM_ARG void *YYPARSE_PARAM -# define YYPARSE_PARAM_DECL -# else -# define YYPARSE_PARAM_ARG YYPARSE_PARAM -# define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; -# endif -#else /* !YYPARSE_PARAM */ -# define YYPARSE_PARAM_ARG -# define YYPARSE_PARAM_DECL -#endif /* !YYPARSE_PARAM */ - -/* Prevent warning if -Wstrict-prototypes. */ -#ifdef __GNUC__ -# ifdef YYPARSE_PARAM -int yyparse (void *); -# else -int yyparse (void); -# endif -#endif - -/* YY_DECL_VARIABLES -- depending whether we use a pure parser, - variables are global, or local to YYPARSE. */ - -#define YY_DECL_NON_LSP_VARIABLES \ -/* The lookahead symbol. */ \ -int yychar; \ - \ -/* The semantic value of the lookahead symbol. */ \ -YYSTYPE yylval; \ - \ -/* Number of parse errors so far. */ \ -int yynerrs; - -#if YYLSP_NEEDED -# define YY_DECL_VARIABLES \ -YY_DECL_NON_LSP_VARIABLES \ - \ -/* Location data for the lookahead symbol. */ \ -YYLTYPE yylloc; -#else -# define YY_DECL_VARIABLES \ -YY_DECL_NON_LSP_VARIABLES -#endif - - -/* If nonreentrant, generate the variables here. */ - -#if !YYPURE -YY_DECL_VARIABLES -#endif /* !YYPURE */ - -int -yyparse (YYPARSE_PARAM_ARG) - YYPARSE_PARAM_DECL -{ - /* If reentrant, generate the variables here. */ -#if YYPURE - YY_DECL_VARIABLES -#endif /* !YYPURE */ - - register int yystate; - register int yyn; - int yyresult; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - /* Lookahead token as an internal (translated) token number. */ - int yychar1 = 0; - - /* Three stacks and their tools: - `yyss': related to states, - `yyvs': related to semantic values, - `yyls': related to locations. - - Refer to the stacks thru separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - short yyssa[YYINITDEPTH]; - short *yyss = yyssa; - register short *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs = yyvsa; - register YYSTYPE *yyvsp; - -#if YYLSP_NEEDED - /* The location stack. */ - YYLTYPE yylsa[YYINITDEPTH]; - YYLTYPE *yyls = yylsa; - YYLTYPE *yylsp; -#endif - -#if YYLSP_NEEDED -# define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) -#else -# define YYPOPSTACK (yyvsp--, yyssp--) -#endif - - YYSIZE_T yystacksize = YYINITDEPTH; - - - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; -#if YYLSP_NEEDED - YYLTYPE yyloc; -#endif - - /* When reducing, the number of symbols on the RHS of the reduced - rule. */ - int yylen; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - - yyssp = yyss; - yyvsp = yyvs; -#if YYLSP_NEEDED - yylsp = yyls; -#endif - goto yysetstate; - -/*------------------------------------------------------------. -| yynewstate -- Push a new state, which is found in yystate. | -`------------------------------------------------------------*/ - yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. so pushing a state here evens the stacks. - */ - yyssp++; - - yysetstate: - *yyssp = yystate; - - if (yyssp >= yyss + yystacksize - 1) - { - /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; - -#ifdef yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - short *yyss1 = yyss; - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. */ -# if YYLSP_NEEDED - YYLTYPE *yyls1 = yyls; - /* This used to be a conditional around just the two extra args, - but that might be undefined if yyoverflow is a macro. */ - yyoverflow ("parser stack overflow", - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - &yyls1, yysize * sizeof (*yylsp), - &yystacksize); - yyls = yyls1; -# else - yyoverflow ("parser stack overflow", - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - &yystacksize); -# endif - yyss = yyss1; - yyvs = yyvs1; - } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyoverflowlab; -# else - /* Extend the stack our own way. */ - if (yystacksize >= YYMAXDEPTH) - goto yyoverflowlab; - yystacksize *= 2; - if (yystacksize > YYMAXDEPTH) - yystacksize = YYMAXDEPTH; - - { - short *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyoverflowlab; - YYSTACK_RELOCATE (yyss); - YYSTACK_RELOCATE (yyvs); -# if YYLSP_NEEDED - YYSTACK_RELOCATE (yyls); -# endif -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif -#endif /* no yyoverflow */ - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; -#if YYLSP_NEEDED - yylsp = yyls + yysize - 1; -#endif - - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); - - if (yyssp >= yyss + yystacksize - 1) - YYABORT; - } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - - goto yybackup; - - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - -/* Do appropriate processing given the current state. */ -/* Read a lookahead token if we need one and don't already have one. */ -/* yyresume: */ - - /* First try to decide what to do without reference to lookahead token. */ - - yyn = yypact[yystate]; - if (yyn == YYFLAG) - goto yydefault; - - /* Not known => get a lookahead token if don't already have one. */ - - /* yychar is either YYEMPTY or YYEOF - or a valid token in external form. */ - - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = YYLEX; - } - - /* Convert token to internal form (in yychar1) for indexing tables with */ - - if (yychar <= 0) /* This means end of input. */ - { - yychar1 = 0; - yychar = YYEOF; /* Don't call YYLEX any more */ - - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yychar1 = YYTRANSLATE (yychar); - -#if YYDEBUG - /* We have to keep this `#if YYDEBUG', since we use variables - which are defined only if `YYDEBUG' is set. */ - if (yydebug) - { - YYFPRINTF (stderr, "Next token is %d (%s", - yychar, yytname[yychar1]); - /* Give the individual parser a way to print the precise - meaning of a token, for further debugging info. */ -# ifdef YYPRINT - YYPRINT (stderr, yychar, yylval); -# endif - YYFPRINTF (stderr, ")\n"); - } -#endif - } - - yyn += yychar1; - if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) - goto yydefault; - - yyn = yytable[yyn]; - - /* yyn is what to do for this token type in this state. - Negative => reduce, -yyn is rule number. - Positive => shift, yyn is new state. - New state is final state => don't bother to shift, - just return success. - 0, or most negative number => error. */ - - if (yyn < 0) - { - if (yyn == YYFLAG) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - else if (yyn == 0) - goto yyerrlab; - - if (yyn == YYFINAL) - YYACCEPT; - - /* Shift the lookahead token. */ - YYDPRINTF ((stderr, "Shifting token %d (%s), ", - yychar, yytname[yychar1])); - - /* Discard the token being shifted unless it is eof. */ - if (yychar != YYEOF) - yychar = YYEMPTY; - - *++yyvsp = yylval; -#if YYLSP_NEEDED - *++yylsp = yylloc; -#endif - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - yystate = yyn; - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- Do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - `$$ = $1'. - - Otherwise, the following line sets YYVAL to the semantic value of - the lookahead token. This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - -#if YYLSP_NEEDED - /* Similarly for the default location. Let the user run additional - commands if for instance locations are ranges. */ - yyloc = yylsp[1-yylen]; - YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); -#endif - -#if YYDEBUG - /* We have to keep this `#if YYDEBUG', since we use variables which - are defined only if `YYDEBUG' is set. */ - if (yydebug) - { - int yyi; - - YYFPRINTF (stderr, "Reducing via rule %d (line %d), ", - yyn, yyrline[yyn]); - - /* Print the symbols being reduced, and their result. */ - for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++) - YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]); - YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]); - } -#endif - - switch (yyn) { - -case 1: -#line 137 "./cond.y" -{ - COND_input* cond = (COND_input*) info; - cond->result = yyvsp[0].value; - ; - break;} -case 2: -#line 145 "./cond.y" -{ - yyval.value = yyvsp[0].value; - ; - break;} -case 3: -#line 149 "./cond.y" -{ - yyval.value = yyvsp[-2].value || yyvsp[0].value; - ; - break;} -case 4: -#line 156 "./cond.y" -{ - yyval.value = yyvsp[0].value; - ; - break;} -case 5: -#line 160 "./cond.y" -{ - yyval.value = yyvsp[-2].value && yyvsp[0].value; - ; - break;} -case 6: -#line 167 "./cond.y" -{ - yyval.value = yyvsp[0].value; - ; - break;} -case 7: -#line 171 "./cond.y" -{ - yyval.value = ! yyvsp[0].value; - ; - break;} -case 8: -#line 179 "./cond.y" -{ - yyval.value = yyvsp[0].value; - ; - break;} -case 9: -#line 183 "./cond.y" -{ - yyval.value = (yyvsp[0].string && yyvsp[0].string[0]) ? MSICONDITION_TRUE : MSICONDITION_FALSE; - ; - break;} -case 10: -#line 187 "./cond.y" -{ - yyval.value = yyvsp[-1].fn_comp_int( yyvsp[-2].value, yyvsp[0].value ); - ; - break;} -case 11: -#line 191 "./cond.y" -{ - yyval.value = yyvsp[-1].fn_comp_str( yyvsp[-2].string, yyvsp[0].string, FALSE ); - ; - break;} -case 12: -#line 195 "./cond.y" -{ - yyval.value = yyvsp[-1].fn_comp_str( yyvsp[-3].string, yyvsp[0].string, TRUE ); - ; - break;} -case 13: -#line 199 "./cond.y" -{ - yyval.value = yyvsp[-1].fn_comp_m1( yyvsp[-2].string, yyvsp[0].value ); - ; - break;} -case 14: -#line 203 "./cond.y" -{ - yyval.value = yyvsp[-1].fn_comp_m2( yyvsp[-2].value, yyvsp[0].string ); - ; - break;} -case 15: -#line 207 "./cond.y" -{ - yyval.value = yyvsp[-1].value; - ; - break;} -case 16: -#line 215 "./cond.y" -{ - yyval.fn_comp_int = comp_eq_i; - ; - break;} -case 17: -#line 219 "./cond.y" -{ - yyval.fn_comp_int = comp_ne_i; - ; - break;} -case 18: -#line 223 "./cond.y" -{ - yyval.fn_comp_int = comp_lt_i; - ; - break;} -case 19: -#line 227 "./cond.y" -{ - yyval.fn_comp_int = comp_gt_i; - ; - break;} -case 20: -#line 231 "./cond.y" -{ - yyval.fn_comp_int = comp_le_i; - ; - break;} -case 21: -#line 235 "./cond.y" -{ - yyval.fn_comp_int = comp_ge_i; - ; - break;} -case 22: -#line 240 "./cond.y" -{ - yyval.fn_comp_int = comp_bitand; - ; - break;} -case 23: -#line 244 "./cond.y" -{ - yyval.fn_comp_int = comp_highcomp; - ; - break;} -case 24: -#line 248 "./cond.y" -{ - yyval.fn_comp_int = comp_lowcomp; - ; - break;} -case 25: -#line 256 "./cond.y" -{ - yyval.fn_comp_str = comp_eq_s; - ; - break;} -case 26: -#line 260 "./cond.y" -{ - yyval.fn_comp_str = comp_ne_s; - ; - break;} -case 27: -#line 264 "./cond.y" -{ - yyval.fn_comp_str = comp_lt_s; - ; - break;} -case 28: -#line 268 "./cond.y" -{ - yyval.fn_comp_str = comp_gt_s; - ; - break;} -case 29: -#line 272 "./cond.y" -{ - yyval.fn_comp_str = comp_le_s; - ; - break;} -case 30: -#line 276 "./cond.y" -{ - yyval.fn_comp_str = comp_ge_s; - ; - break;} -case 31: -#line 281 "./cond.y" -{ - yyval.fn_comp_str = comp_substring; - ; - break;} -case 32: -#line 285 "./cond.y" -{ - yyval.fn_comp_str = comp_start; - ; - break;} -case 33: -#line 289 "./cond.y" -{ - yyval.fn_comp_str = comp_end; - ; - break;} -case 34: -#line 297 "./cond.y" -{ - yyval.fn_comp_m1 = comp_eq_m1; - ; - break;} -case 35: -#line 301 "./cond.y" -{ - yyval.fn_comp_m1 = comp_ne_m1; - ; - break;} -case 36: -#line 305 "./cond.y" -{ - yyval.fn_comp_m1 = comp_lt_m1; - ; - break;} -case 37: -#line 309 "./cond.y" -{ - yyval.fn_comp_m1 = comp_gt_m1; - ; - break;} -case 38: -#line 313 "./cond.y" -{ - yyval.fn_comp_m1 = comp_le_m1; - ; - break;} -case 39: -#line 317 "./cond.y" -{ - yyval.fn_comp_m1 = comp_ge_m1; - ; - break;} -case 40: -#line 322 "./cond.y" -{ - yyval.fn_comp_m1 = 0; - ; - break;} -case 41: -#line 326 "./cond.y" -{ - yyval.fn_comp_m1 = 0; - ; - break;} -case 42: -#line 330 "./cond.y" -{ - yyval.fn_comp_m1 = 0; - ; - break;} -case 43: -#line 338 "./cond.y" -{ - yyval.fn_comp_m2 = comp_eq_m2; - ; - break;} -case 44: -#line 342 "./cond.y" -{ - yyval.fn_comp_m2 = comp_ne_m2; - ; - break;} -case 45: -#line 346 "./cond.y" -{ - yyval.fn_comp_m2 = comp_lt_m2; - ; - break;} -case 46: -#line 350 "./cond.y" -{ - yyval.fn_comp_m2 = comp_gt_m2; - ; - break;} -case 47: -#line 354 "./cond.y" -{ - yyval.fn_comp_m2 = comp_le_m2; - ; - break;} -case 48: -#line 358 "./cond.y" -{ - yyval.fn_comp_m2 = comp_ge_m2; - ; - break;} -case 49: -#line 363 "./cond.y" -{ - yyval.fn_comp_m2 = 0; - ; - break;} -case 50: -#line 367 "./cond.y" -{ - yyval.fn_comp_m2 = 0; - ; - break;} -case 51: -#line 371 "./cond.y" -{ - yyval.fn_comp_m2 = 0; - ; - break;} -case 52: -#line 378 "./cond.y" -{ - yyval.value = yyvsp[0].value; - ; - break;} -case 53: -#line 382 "./cond.y" -{ - yyval.value = yyvsp[0].value; - ; - break;} -case 54: -#line 389 "./cond.y" -{ - yyval.string = yyvsp[0].string; - ; - break;} -case 55: -#line 393 "./cond.y" -{ - yyval.string = yyvsp[0].string; - ; - break;} -case 56: -#line 400 "./cond.y" -{ - yyval.string = COND_GetLiteral(&yyvsp[0].str); - if( !yyval.string ) - YYABORT; - ; - break;} -case 57: -#line 409 "./cond.y" -{ - COND_input* cond = (COND_input*) info; - INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; - - MSI_GetComponentStateW(cond->package, yyvsp[0].string, &install, &action ); - yyval.value = action; - HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); - ; - break;} -case 58: -#line 418 "./cond.y" -{ - COND_input* cond = (COND_input*) info; - INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; - - MSI_GetComponentStateW(cond->package, yyvsp[0].string, &install, &action ); - yyval.value = install; - HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); - ; - break;} -case 59: -#line 427 "./cond.y" -{ - COND_input* cond = (COND_input*) info; - INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; - - MSI_GetFeatureStateW(cond->package, yyvsp[0].string, &install, &action ); - yyval.value = action; - HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); - ; - break;} -case 60: -#line 436 "./cond.y" -{ - COND_input* cond = (COND_input*) info; - INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; - - MSI_GetFeatureStateW(cond->package, yyvsp[0].string, &install, &action ); - yyval.value = install; - HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); - ; - break;} -case 61: -#line 448 "./cond.y" -{ - DWORD sz; - COND_input* cond = (COND_input*) info; - - sz = 0; - MSI_GetPropertyW(cond->package, yyvsp[0].string, NULL, &sz); - if (sz == 0) - { - yyval.string = HeapAlloc( GetProcessHeap(), 0 ,sizeof(WCHAR)); - yyval.string[0] = 0; - } - else - { - sz ++; - yyval.string = HeapAlloc( GetProcessHeap(), 0, sz*sizeof (WCHAR) ); - - /* Lookup the identifier */ - - MSI_GetPropertyW(cond->package,yyvsp[0].string,yyval.string,&sz); - } - HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); - ; - break;} -case 62: -#line 471 "./cond.y" -{ - UINT len = GetEnvironmentVariableW( yyvsp[0].string, NULL, 0 ); - if( len++ ) - { - yyval.string = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) ); - if( yyval.string ) - GetEnvironmentVariableW( yyvsp[0].string, yyval.string, len ); - } - HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); - ; - break;} -case 63: -#line 485 "./cond.y" -{ - yyval.string = COND_GetString(&yyvsp[0].str); - if( !yyval.string ) - YYABORT; - ; - break;} -case 64: -#line 494 "./cond.y" -{ - LPWSTR szNum = COND_GetString(&yyvsp[0].str); - if( !szNum ) - YYABORT; - yyval.value = atoiW( szNum ); - HeapFree( GetProcessHeap(), 0, szNum ); - ; - break;} -} - -#line 705 "/usr/share/bison/bison.simple" - - - yyvsp -= yylen; - yyssp -= yylen; -#if YYLSP_NEEDED - yylsp -= yylen; -#endif - -#if YYDEBUG - if (yydebug) - { - short *yyssp1 = yyss - 1; - YYFPRINTF (stderr, "state stack now"); - while (yyssp1 != yyssp) - YYFPRINTF (stderr, " %d", *++yyssp1); - YYFPRINTF (stderr, "\n"); - } -#endif - - *++yyvsp = yyval; -#if YYLSP_NEEDED - *++yylsp = yyloc; -#endif - - /* Now `shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTBASE] + *yyssp; - if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTBASE]; - - goto yynewstate; - - -/*------------------------------------. -| yyerrlab -- here on detecting error | -`------------------------------------*/ -yyerrlab: - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; - -#ifdef YYERROR_VERBOSE - yyn = yypact[yystate]; - - if (yyn > YYFLAG && yyn < YYLAST) - { - YYSIZE_T yysize = 0; - char *yymsg; - int yyx, yycount; - - yycount = 0; - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. */ - for (yyx = yyn < 0 ? -yyn : 0; - yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) - if (yycheck[yyx + yyn] == yyx) - yysize += yystrlen (yytname[yyx]) + 15, yycount++; - yysize += yystrlen ("parse error, unexpected ") + 1; - yysize += yystrlen (yytname[YYTRANSLATE (yychar)]); - yymsg = (char *) YYSTACK_ALLOC (yysize); - if (yymsg != 0) - { - char *yyp = yystpcpy (yymsg, "parse error, unexpected "); - yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]); - - if (yycount < 5) - { - yycount = 0; - for (yyx = yyn < 0 ? -yyn : 0; - yyx < (int) (sizeof (yytname) / sizeof (char *)); - yyx++) - if (yycheck[yyx + yyn] == yyx) - { - const char *yyq = ! yycount ? ", expecting " : " or "; - yyp = yystpcpy (yyp, yyq); - yyp = yystpcpy (yyp, yytname[yyx]); - yycount++; - } - } - yyerror (yymsg); - YYSTACK_FREE (yymsg); - } - else - yyerror ("parse error; also virtual memory exhausted"); - } - else -#endif /* defined (YYERROR_VERBOSE) */ - yyerror ("parse error"); - } - goto yyerrlab1; - - -/*--------------------------------------------------. -| yyerrlab1 -- error raised explicitly by an action | -`--------------------------------------------------*/ -yyerrlab1: - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse lookahead token after an - error, discard it. */ - - /* return failure if at end of input */ - if (yychar == YYEOF) - YYABORT; - YYDPRINTF ((stderr, "Discarding token %d (%s).\n", - yychar, yytname[yychar1])); - yychar = YYEMPTY; - } - - /* Else will try to reuse lookahead token after shifting the error - token. */ - - yyerrstatus = 3; /* Each real token shifted decrements this */ - - goto yyerrhandle; - - -/*-------------------------------------------------------------------. -| yyerrdefault -- current state does not do anything special for the | -| error token. | -`-------------------------------------------------------------------*/ -yyerrdefault: -#if 0 - /* This is wrong; only states that explicitly want error tokens - should shift them. */ - - /* If its default is to accept any token, ok. Otherwise pop it. */ - yyn = yydefact[yystate]; - if (yyn) - goto yydefault; -#endif - - -/*---------------------------------------------------------------. -| yyerrpop -- pop the current state because it cannot handle the | -| error token | -`---------------------------------------------------------------*/ -yyerrpop: - if (yyssp == yyss) - YYABORT; - yyvsp--; - yystate = *--yyssp; -#if YYLSP_NEEDED - yylsp--; -#endif - -#if YYDEBUG - if (yydebug) - { - short *yyssp1 = yyss - 1; - YYFPRINTF (stderr, "Error: state stack now"); - while (yyssp1 != yyssp) - YYFPRINTF (stderr, " %d", *++yyssp1); - YYFPRINTF (stderr, "\n"); - } -#endif - -/*--------------. -| yyerrhandle. | -`--------------*/ -yyerrhandle: - yyn = yypact[yystate]; - if (yyn == YYFLAG) - goto yyerrdefault; - - yyn += YYTERROR; - if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) - goto yyerrdefault; - - yyn = yytable[yyn]; - if (yyn < 0) - { - if (yyn == YYFLAG) - goto yyerrpop; - yyn = -yyn; - goto yyreduce; - } - else if (yyn == 0) - goto yyerrpop; - - if (yyn == YYFINAL) - YYACCEPT; - - YYDPRINTF ((stderr, "Shifting error token, ")); - - *++yyvsp = yylval; -#if YYLSP_NEEDED - *++yylsp = yylloc; -#endif - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - -/*---------------------------------------------. -| yyoverflowab -- parser overflow comes here. | -`---------------------------------------------*/ -yyoverflowlab: - yyerror ("parser stack overflow"); - yyresult = 2; - /* Fall through. */ - -yyreturn: -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif - return yyresult; -} -#line 503 "./cond.y" - - - -static int COND_IsAlpha( WCHAR x ) -{ - return( ( ( x >= 'A' ) && ( x <= 'Z' ) ) || - ( ( x >= 'a' ) && ( x <= 'z' ) ) || - ( ( x == '_' ) ) ); -} - -static int COND_IsNumber( WCHAR x ) -{ - return( (( x >= '0' ) && ( x <= '9' )) || (x =='-') || (x =='.') ); -} - - -/* the mess of comparison functions */ - -static INT comp_lt_i(INT a, INT b) -{ return (a < b); } -static INT comp_gt_i(INT a, INT b) -{ return (a > b); } -static INT comp_le_i(INT a, INT b) -{ return (a <= b); } -static INT comp_ge_i(INT a, INT b) -{ return (a >= b); } -static INT comp_eq_i(INT a, INT b) -{ return (a == b); } -static INT comp_ne_i(INT a, INT b) -{ return (a != b); } -static INT comp_bitand(INT a, INT b) -{ return a & b;} -static INT comp_highcomp(INT a, INT b) -{ return HIWORD(a)==b; } -static INT comp_lowcomp(INT a, INT b) -{ return LOWORD(a)==b; } - -static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return !strcmpiW(a,b); else return !strcmpW(a,b);} -static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b); else return strcmpW(a,b);} -static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b)<0; else return strcmpW(a,b)<0;} -static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b)>0; else return strcmpW(a,b)>0;} -static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b)<=0; else return strcmpW(a,b)<=0;} -static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b)>=0; else return strcmpW(a,b)>=0;} -static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless) -/* ERROR NOT WORKING REWRITE */ -{ if (casless) return strstrW(a,b)!=NULL; else return strstrW(a,b)!=NULL;} -static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strncmpiW(a,b,strlenW(b))==0; - else return strncmpW(a,b,strlenW(b))==0;} -static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless) -{ - int i = strlenW(a); - int j = strlenW(b); - if (j>i) - return 0; - if (casless) return (!strcmpiW(&a[i-j-1],b)); - else return (!strcmpW(&a[i-j-1],b)); -} - - -static INT comp_eq_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)==b; else return 0;} -static INT comp_ne_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)!=b; else return 1;} -static INT comp_lt_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)<b; else return 0;} -static INT comp_gt_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)>b; else return 0;} -static INT comp_le_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)<=b; else return 0;} -static INT comp_ge_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)>=b; else return 0;} - -static INT comp_eq_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a == atoiW(b); else return 0;} -static INT comp_ne_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a != atoiW(b); else return 1;} -static INT comp_lt_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a < atoiW(b); else return 0;} -static INT comp_gt_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a > atoiW(b); else return 0;} -static INT comp_le_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a <= atoiW(b); else return 0;} -static INT comp_ge_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a >= atoiW(b); else return 0;} - - - -static int COND_IsIdent( WCHAR x ) -{ - return( COND_IsAlpha( x ) || COND_IsNumber( x ) || ( x == '_' ) - || ( x == '#' ) || (x == '.') ); -} - -static int COND_GetOne( struct cond_str *str, COND_input *cond ) -{ - static const WCHAR szNot[] = {'N','O','T',0}; - static const WCHAR szAnd[] = {'A','N','D',0}; - static const WCHAR szOr[] = {'O','R',0}; - WCHAR ch; - int rc, len = 1; - - str->data = &cond->str[cond->n]; - - ch = str->data[0]; - switch( ch ) - { - case 0: return 0; - case '(': rc = COND_LPAR; break; - case ')': rc = COND_RPAR; break; - case '&': rc = COND_AMPER; break; - case '!': rc = COND_EXCLAM; break; - case '$': rc = COND_DOLLARS; break; - case '?': rc = COND_QUESTION; break; - case '%': rc = COND_PERCENT; break; - case ' ': rc = COND_SPACE; break; - case '=': rc = COND_EQ; break; - case '~': rc = COND_TILDA; break; - case '<': rc = COND_LT; break; - case '>': rc = COND_GT; break; - case '"': - { - const WCHAR *ch2 = str->data + 1; - - - while ( *ch2 && *ch2 != '"' ) - ++ch2; - if (*ch2 == '"') - { - len = ch2 - str->data + 1; - rc = COND_LITER; - break; - } - } - ERR("Unterminated string\n"); - rc = COND_ERROR; - break; - default: - if( COND_IsAlpha( ch ) ) - { - while( COND_IsIdent( str->data[len] ) ) - len++; - rc = COND_IDENT; - break; - } - - if( COND_IsNumber( ch ) ) - { - while( COND_IsNumber( str->data[len] ) ) - len++; - rc = COND_NUMBER; - break; - } - - ERR("Got unknown character %c(%x)\n",ch,ch); - rc = COND_ERROR; - break; - } - - /* keyword identifiers */ - if( rc == COND_IDENT ) - { - if( (len==3) && (strncmpiW(str->data,szNot,len)==0) ) - rc = COND_NOT; - else if( (len==3) && (strncmpiW(str->data,szAnd,len)==0) ) - rc = COND_AND; - else if( (len==2) && (strncmpiW(str->data,szOr,len)==0) ) - rc = COND_OR; - } - - cond->n += len; - str->len = len; - - return rc; -} - -static int COND_lex( void *COND_lval, COND_input *cond ) -{ - int rc; - struct cond_str *str = COND_lval; - - do { - rc = COND_GetOne( str, cond ); - } while (rc == COND_SPACE); - - return rc; -} - -static LPWSTR COND_GetString( struct cond_str *str ) -{ - LPWSTR ret; - - ret = HeapAlloc( GetProcessHeap(), 0, (str->len+1) * sizeof (WCHAR) ); - if( ret ) - { - memcpy( ret, str->data, str->len * sizeof(WCHAR)); - ret[str->len]=0; - } - TRACE("Got identifier %s\n",debugstr_w(ret)); - return ret; -} - -static LPWSTR COND_GetLiteral( struct cond_str *str ) -{ - LPWSTR ret; - - ret = HeapAlloc( GetProcessHeap(), 0, (str->len-1) * sizeof (WCHAR) ); - if( ret ) - { - memcpy( ret, str->data+1, (str->len-2) * sizeof(WCHAR) ); - ret[str->len - 2]=0; - } - TRACE("Got literal %s\n",debugstr_w(ret)); - return ret; -} - -static int COND_error(char *str) -{ - return 0; -} - -MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition ) -{ - COND_input cond; - MSICONDITION r; - - cond.package = package; - cond.str = szCondition; - cond.n = 0; - cond.result = -1; - - TRACE("Evaluating %s\n",debugstr_w(szCondition)); - - if ( szCondition == NULL || szCondition[0] == 0) - r = MSICONDITION_NONE; - else if ( !COND_parse( &cond ) ) - r = cond.result; - else - r = MSICONDITION_ERROR; - - TRACE("Evaluates to %i\n",r); - return r; -} - -MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szCondition ) -{ - MSIPACKAGE *package; - UINT ret; - - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); - if( !package) - return ERROR_INVALID_HANDLE; - ret = MSI_EvaluateConditionW( package, szCondition ); - msiobj_release( &package->hdr ); - return ret; -} - -MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szCondition ) -{ - LPWSTR szwCond = NULL; - MSICONDITION r; - - if( szCondition ) - { - UINT len = MultiByteToWideChar( CP_ACP, 0, szCondition, -1, NULL, 0 ); - szwCond = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, szCondition, -1, szwCond, len ); - } - - r = MsiEvaluateConditionW( hInstall, szwCond ); - - HeapFree( GetProcessHeap(), 0, szwCond ); - - return r; -} +/* A Bison parser, made from ./cond.y + by GNU bison 1.35. */ + +#define YYBISON 1 /* Identify Bison output. */ + +#define yyparse COND_parse +#define yylex COND_lex +#define yyerror COND_error +#define yylval COND_lval +#define yychar COND_char +#define yydebug COND_debug +#define yynerrs COND_nerrs +# define COND_SPACE 257 +# define COND_EOF 258 +# define COND_OR 259 +# define COND_AND 260 +# define COND_NOT 261 +# define COND_LT 262 +# define COND_GT 263 +# define COND_EQ 264 +# define COND_LPAR 265 +# define COND_RPAR 266 +# define COND_TILDA 267 +# define COND_PERCENT 268 +# define COND_DOLLARS 269 +# define COND_QUESTION 270 +# define COND_AMPER 271 +# define COND_EXCLAM 272 +# define COND_IDENT 273 +# define COND_NUMBER 274 +# define COND_LITER 275 +# define COND_ERROR 276 + +#line 1 "./cond.y" + + +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2003 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> + +#include "windef.h" +#include "winbase.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +#include "msi.h" +#include "msiquery.h" +#include "msipriv.h" + +#define YYLEX_PARAM info +#define YYPARSE_PARAM info + +static int COND_error(char *str); + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +typedef struct tag_yyinput +{ + MSIPACKAGE *package; + LPCWSTR str; + INT n; + MSICONDITION result; +} COND_input; + +struct cond_str { + LPCWSTR data; + INT len; +}; + +static LPWSTR COND_GetString( struct cond_str *str ); +static LPWSTR COND_GetLiteral( struct cond_str *str ); +static int COND_lex( void *COND_lval, COND_input *info); + +typedef INT (*comp_int)(INT a, INT b); +typedef INT (*comp_str)(LPWSTR a, LPWSTR b, BOOL caseless); +typedef INT (*comp_m1)(LPWSTR a,int b); +typedef INT (*comp_m2)(int a,LPWSTR b); + +static INT comp_lt_i(INT a, INT b); +static INT comp_gt_i(INT a, INT b); +static INT comp_le_i(INT a, INT b); +static INT comp_ge_i(INT a, INT b); +static INT comp_eq_i(INT a, INT b); +static INT comp_ne_i(INT a, INT b); +static INT comp_bitand(INT a, INT b); +static INT comp_highcomp(INT a, INT b); +static INT comp_lowcomp(INT a, INT b); + +static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless); +static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless); + +static INT comp_eq_m1(LPWSTR a, INT b); +static INT comp_ne_m1(LPWSTR a, INT b); +static INT comp_lt_m1(LPWSTR a, INT b); +static INT comp_gt_m1(LPWSTR a, INT b); +static INT comp_le_m1(LPWSTR a, INT b); +static INT comp_ge_m1(LPWSTR a, INT b); + +static INT comp_eq_m2(INT a, LPWSTR b); +static INT comp_ne_m2(INT a, LPWSTR b); +static INT comp_lt_m2(INT a, LPWSTR b); +static INT comp_gt_m2(INT a, LPWSTR b); +static INT comp_le_m2(INT a, LPWSTR b); +static INT comp_ge_m2(INT a, LPWSTR b); + + +#line 105 "./cond.y" +#ifndef YYSTYPE +typedef union +{ + struct cond_str str; + LPWSTR string; + INT value; + comp_int fn_comp_int; + comp_str fn_comp_str; + comp_m1 fn_comp_m1; + comp_m2 fn_comp_m2; +} yystype; +# define YYSTYPE yystype +# define YYSTYPE_IS_TRIVIAL 1 +#endif +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + + + +#define YYFINAL 74 +#define YYFLAG -32768 +#define YYNTBASE 23 + +/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */ +#define YYTRANSLATE(x) ((unsigned)(x) <= 276 ? yytranslate[x] : 39) + +/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */ +static const char yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22 +}; + +#if YYDEBUG +static const short yyprhs[] = +{ + 0, 0, 2, 4, 8, 10, 14, 16, 19, 21, + 23, 27, 31, 36, 40, 44, 48, 50, 53, 55, + 57, 60, 63, 66, 69, 72, 74, 77, 79, 81, + 84, 87, 90, 93, 96, 98, 101, 103, 105, 108, + 111, 114, 117, 120, 122, 125, 127, 129, 132, 135, + 138, 141, 144, 146, 148, 150, 152, 154, 157, 160, + 163, 166, 168, 171, 173 +}; +static const short yyrhs[] = +{ + 24, 0, 25, 0, 25, 5, 24, 0, 26, 0, + 25, 6, 26, 0, 27, 0, 7, 27, 0, 32, + 0, 33, 0, 32, 28, 32, 0, 33, 29, 33, + 0, 33, 13, 29, 33, 0, 33, 30, 32, 0, + 32, 31, 33, 0, 11, 24, 12, 0, 10, 0, + 8, 9, 0, 8, 0, 9, 0, 8, 10, 0, + 9, 10, 0, 9, 8, 0, 8, 8, 0, 9, + 9, 0, 10, 0, 8, 9, 0, 8, 0, 9, + 0, 8, 10, 0, 9, 10, 0, 9, 8, 0, + 8, 8, 0, 9, 9, 0, 10, 0, 8, 9, + 0, 8, 0, 9, 0, 8, 10, 0, 9, 10, + 0, 9, 8, 0, 8, 8, 0, 9, 9, 0, + 10, 0, 8, 9, 0, 8, 0, 9, 0, 8, + 10, 0, 9, 10, 0, 9, 8, 0, 8, 8, + 0, 9, 9, 0, 35, 0, 38, 0, 36, 0, + 34, 0, 21, 0, 15, 37, 0, 16, 37, 0, + 17, 37, 0, 18, 37, 0, 37, 0, 14, 37, + 0, 19, 0, 20, 0 +}; + +#endif + +#if YYDEBUG +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const short yyrline[] = +{ + 0, 135, 143, 148, 154, 159, 165, 170, 177, 182, + 186, 190, 194, 198, 202, 206, 212, 218, 222, 226, + 230, 234, 239, 243, 247, 253, 259, 263, 267, 271, + 275, 280, 284, 288, 294, 300, 304, 308, 312, 316, + 321, 325, 329, 335, 341, 345, 349, 353, 357, 362, + 366, 370, 376, 381, 387, 392, 398, 407, 417, 426, + 435, 446, 470, 483, 492 +}; +#endif + + +#if (YYDEBUG) || defined YYERROR_VERBOSE + +/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */ +static const char *const yytname[] = +{ + "$", "error", "$undefined.", "COND_SPACE", "COND_EOF", "COND_OR", + "COND_AND", "COND_NOT", "COND_LT", "COND_GT", "COND_EQ", "COND_LPAR", + "COND_RPAR", "COND_TILDA", "COND_PERCENT", "COND_DOLLARS", + "COND_QUESTION", "COND_AMPER", "COND_EXCLAM", "COND_IDENT", + "COND_NUMBER", "COND_LITER", "COND_ERROR", "condition", "expression", + "boolean_term", "boolean_factor", "term", "comp_op_i", "comp_op_s", + "comp_op_m1", "comp_op_m2", "value_i", "value_s", "literal", "symbol_i", + "symbol_s", "identifier", "integer", 0 +}; +#endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const short yyr1[] = +{ + 0, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 32, 32, 33, 33, 34, 35, 35, 35, + 35, 36, 36, 37, 38 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const short yyr2[] = +{ + 0, 1, 1, 3, 1, 3, 1, 2, 1, 1, + 3, 3, 4, 3, 3, 3, 1, 2, 1, 1, + 2, 2, 2, 2, 2, 1, 2, 1, 1, 2, + 2, 2, 2, 2, 1, 2, 1, 1, 2, 2, + 2, 2, 2, 1, 2, 1, 1, 2, 2, 2, + 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, + 2, 1, 2, 1, 1 +}; + +/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE + doesn't specify something else to do. Zero means the default is an + error. */ +static const short yydefact[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, + 56, 1, 2, 4, 6, 8, 9, 55, 52, 54, + 61, 53, 7, 0, 62, 57, 58, 59, 60, 0, + 0, 18, 19, 16, 0, 0, 36, 37, 34, 0, + 0, 0, 15, 3, 5, 23, 17, 20, 22, 24, + 21, 10, 14, 41, 35, 38, 40, 42, 39, 27, + 28, 25, 0, 11, 13, 32, 26, 29, 31, 33, + 30, 12, 0, 0, 0 +}; + +static const short yydefgoto[] = +{ + 72, 11, 12, 13, 14, 34, 40, 41, 35, 15, + 16, 17, 18, 19, 20, 21 +}; + +static const short yypact[] = +{ + -5, 50, -5, -12, -12, -12, -12, -12,-32768,-32768, + -32768,-32768, -2,-32768,-32768, 48, 123,-32768,-32768,-32768, + -32768,-32768,-32768, -4,-32768,-32768,-32768,-32768,-32768, -5, + -5, 10, 24, 33, 110, 58, 27, 41, 59, 135, + 58, 110,-32768,-32768,-32768, 62, 68, 71, 72, 80, + 81,-32768,-32768, 84, 90, 93, 94, 102, 103, 138, + 141,-32768, 58,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + -32768,-32768, 17, 21,-32768 +}; + +static const short yypgoto[] = +{ + -32768, -1,-32768, -8, 25,-32768, -14,-32768,-32768, -11, + -35,-32768,-32768,-32768, 134,-32768 +}; + + +#define YYLAST 151 + + +static const short yytable[] = +{ + 52, 23, 1, 29, 30, 63, 2, 8, 42, 3, + 4, 5, 6, 7, 8, 9, 10, 73, 45, 46, + 47, 74, 44, 51, -45, 62, 22, 71, 43, -45, + 64, -45, 48, 49, 50, 53, 54, 55, -46, 0, + 0, -27, 0, -46, 0, -46, -27, -43, -27, 56, + 57, 58, -43, 0, -43, -28, 31, 32, 33, 0, + -28, 2, -28, 0, 3, 4, 5, 6, 7, 8, + 9, 10, 3, -25, 0, 0, -50, 8, -25, 10, + -25, -50, -44, -50, 0, -47, -49, -44, 0, -44, + -47, -49, -47, -49, -51, -48, 0, 0, -32, -51, + -48, -51, -48, -32, -26, -32, 0, -29, -31, -26, + 0, -26, -29, -31, -29, -31, -33, -30, 0, 0, + 0, -33, -30, -33, -30, 4, 5, 6, 7, 0, + 9, 36, 37, 38, 0, 0, 39, 24, 25, 26, + 27, 28, 0, 59, 60, 61, 65, 66, 67, 68, + 69, 70 +}; + +static const short yycheck[] = +{ + 35, 2, 7, 5, 6, 40, 11, 19, 12, 14, + 15, 16, 17, 18, 19, 20, 21, 0, 8, 9, + 10, 0, 30, 34, 14, 39, 1, 62, 29, 19, + 41, 21, 8, 9, 10, 8, 9, 10, 14, -1, + -1, 14, -1, 19, -1, 21, 19, 14, 21, 8, + 9, 10, 19, -1, 21, 14, 8, 9, 10, -1, + 19, 11, 21, -1, 14, 15, 16, 17, 18, 19, + 20, 21, 14, 14, -1, -1, 14, 19, 19, 21, + 21, 19, 14, 21, -1, 14, 14, 19, -1, 21, + 19, 19, 21, 21, 14, 14, -1, -1, 14, 19, + 19, 21, 21, 19, 14, 21, -1, 14, 14, 19, + -1, 21, 19, 19, 21, 21, 14, 14, -1, -1, + -1, 19, 19, 21, 21, 15, 16, 17, 18, -1, + 20, 8, 9, 10, -1, -1, 13, 3, 4, 5, + 6, 7, -1, 8, 9, 10, 8, 9, 10, 8, + 9, 10 +}; +#define YYPURE 1 + +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/usr/share/bison/bison.simple" + +/* Skeleton output parser for bison, + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software + Foundation, Inc. + + 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, 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* This is the parser code that is written into each bison parser when + the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +#if ! defined (yyoverflow) || defined (YYERROR_VERBOSE) + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# if YYSTACK_USE_ALLOCA +# define YYSTACK_ALLOC alloca +# else +# ifndef YYSTACK_USE_ALLOCA +# if defined (alloca) || defined (_ALLOCA_H) +# define YYSTACK_ALLOC alloca +# else +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# else +# if defined (__STDC__) || defined (__cplusplus) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +# define YYSTACK_ALLOC malloc +# define YYSTACK_FREE free +# endif +#endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */ + + +#if (! defined (yyoverflow) \ + && (! defined (__cplusplus) \ + || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + short yyss; + YYSTYPE yyvs; +# if YYLSP_NEEDED + YYLTYPE yyls; +# endif +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# if YYLSP_NEEDED +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAX) +# else +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAX) +# endif + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + register YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (0) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAX; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + + +#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) +# define YYSIZE_T __SIZE_TYPE__ +#endif +#if ! defined (YYSIZE_T) && defined (size_t) +# define YYSIZE_T size_t +#endif +#if ! defined (YYSIZE_T) +# if defined (__STDC__) || defined (__cplusplus) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +#endif +#if ! defined (YYSIZE_T) +# define YYSIZE_T unsigned int +#endif + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrlab1 +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto yyerrlab +#define YYRECOVERING() (!!yyerrstatus) +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror ("syntax error: cannot back up"); \ + YYERROR; \ + } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Compute the default location (before the actions + are run). + + When YYLLOC_DEFAULT is run, CURRENT is set the location of the + first token. By default, to implement support for ranges, extend + its range to the last symbol. */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + Current.last_line = Rhs[N].last_line; \ + Current.last_column = Rhs[N].last_column; +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#if YYPURE +# if YYLSP_NEEDED +# ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) +# else +# define YYLEX yylex (&yylval, &yylloc) +# endif +# else /* !YYLSP_NEEDED */ +# ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, YYLEX_PARAM) +# else +# define YYLEX yylex (&yylval) +# endif +# endif /* !YYLSP_NEEDED */ +#else /* !YYPURE */ +# define YYLEX yylex () +#endif /* !YYPURE */ + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +#endif /* !YYDEBUG */ + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#if YYMAXDEPTH == 0 +# undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + +#ifdef YYERROR_VERBOSE + +# ifndef yystrlen +# if defined (__GLIBC__) && defined (_STRING_H) +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +# if defined (__STDC__) || defined (__cplusplus) +yystrlen (const char *yystr) +# else +yystrlen (yystr) + const char *yystr; +# endif +{ + register const char *yys = yystr; + + while (*yys++ != '\0') + continue; + + return yys - yystr - 1; +} +# endif +# endif + +# ifndef yystpcpy +# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +# if defined (__STDC__) || defined (__cplusplus) +yystpcpy (char *yydest, const char *yysrc) +# else +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +# endif +{ + register char *yyd = yydest; + register const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif +#endif + +#line 315 "/usr/share/bison/bison.simple" + + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +# define YYPARSE_PARAM_ARG void *YYPARSE_PARAM +# define YYPARSE_PARAM_DECL +# else +# define YYPARSE_PARAM_ARG YYPARSE_PARAM +# define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +# endif +#else /* !YYPARSE_PARAM */ +# define YYPARSE_PARAM_ARG +# define YYPARSE_PARAM_DECL +#endif /* !YYPARSE_PARAM */ + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +# ifdef YYPARSE_PARAM +int yyparse (void *); +# else +int yyparse (void); +# endif +#endif + +/* YY_DECL_VARIABLES -- depending whether we use a pure parser, + variables are global, or local to YYPARSE. */ + +#define YY_DECL_NON_LSP_VARIABLES \ +/* The lookahead symbol. */ \ +int yychar; \ + \ +/* The semantic value of the lookahead symbol. */ \ +YYSTYPE yylval; \ + \ +/* Number of parse errors so far. */ \ +int yynerrs; + +#if YYLSP_NEEDED +# define YY_DECL_VARIABLES \ +YY_DECL_NON_LSP_VARIABLES \ + \ +/* Location data for the lookahead symbol. */ \ +YYLTYPE yylloc; +#else +# define YY_DECL_VARIABLES \ +YY_DECL_NON_LSP_VARIABLES +#endif + + +/* If nonreentrant, generate the variables here. */ + +#if !YYPURE +YY_DECL_VARIABLES +#endif /* !YYPURE */ + +int +yyparse (YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + /* If reentrant, generate the variables here. */ +#if YYPURE + YY_DECL_VARIABLES +#endif /* !YYPURE */ + + register int yystate; + register int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Lookahead token as an internal (translated) token number. */ + int yychar1 = 0; + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + short yyssa[YYINITDEPTH]; + short *yyss = yyssa; + register short *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + register YYSTYPE *yyvsp; + +#if YYLSP_NEEDED + /* The location stack. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; +#endif + +#if YYLSP_NEEDED +# define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +# define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + YYSIZE_T yystacksize = YYINITDEPTH; + + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; +#if YYLSP_NEEDED + YYLTYPE yyloc; +#endif + + /* When reducing, the number of symbols on the RHS of the reduced + rule. */ + int yylen; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; +#if YYLSP_NEEDED + yylsp = yyls; +#endif + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. + */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. */ +# if YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yyls1, yysize * sizeof (*yylsp), + &yystacksize); + yyls = yyls1; +# else + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); +# endif + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyoverflowlab; +# else + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + goto yyoverflowlab; + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; + + { + short *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyoverflowlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); +# if YYLSP_NEEDED + YYSTACK_RELOCATE (yyls); +# endif +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; +#if YYLSP_NEEDED + yylsp = yyls + yysize - 1; +#endif + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yychar1 = YYTRANSLATE (yychar); + +#if YYDEBUG + /* We have to keep this `#if YYDEBUG', since we use variables + which are defined only if `YYDEBUG' is set. */ + if (yydebug) + { + YYFPRINTF (stderr, "Next token is %d (%s", + yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise + meaning of a token, for further debugging info. */ +# ifdef YYPRINT + YYPRINT (stderr, yychar, yylval); +# endif + YYFPRINTF (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + YYDPRINTF ((stderr, "Shifting token %d (%s), ", + yychar, yytname[yychar1])); + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#if YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + yystate = yyn; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to the semantic value of + the lookahead token. This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + +#if YYLSP_NEEDED + /* Similarly for the default location. Let the user run additional + commands if for instance locations are ranges. */ + yyloc = yylsp[1-yylen]; + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); +#endif + +#if YYDEBUG + /* We have to keep this `#if YYDEBUG', since we use variables which + are defined only if `YYDEBUG' is set. */ + if (yydebug) + { + int yyi; + + YYFPRINTF (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++) + YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]); + YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + switch (yyn) { + +case 1: +#line 137 "./cond.y" +{ + COND_input* cond = (COND_input*) info; + cond->result = yyvsp[0].value; + ; + break;} +case 2: +#line 145 "./cond.y" +{ + yyval.value = yyvsp[0].value; + ; + break;} +case 3: +#line 149 "./cond.y" +{ + yyval.value = yyvsp[-2].value || yyvsp[0].value; + ; + break;} +case 4: +#line 156 "./cond.y" +{ + yyval.value = yyvsp[0].value; + ; + break;} +case 5: +#line 160 "./cond.y" +{ + yyval.value = yyvsp[-2].value && yyvsp[0].value; + ; + break;} +case 6: +#line 167 "./cond.y" +{ + yyval.value = yyvsp[0].value; + ; + break;} +case 7: +#line 171 "./cond.y" +{ + yyval.value = ! yyvsp[0].value; + ; + break;} +case 8: +#line 179 "./cond.y" +{ + yyval.value = yyvsp[0].value; + ; + break;} +case 9: +#line 183 "./cond.y" +{ + yyval.value = (yyvsp[0].string && yyvsp[0].string[0]) ? MSICONDITION_TRUE : MSICONDITION_FALSE; + ; + break;} +case 10: +#line 187 "./cond.y" +{ + yyval.value = yyvsp[-1].fn_comp_int( yyvsp[-2].value, yyvsp[0].value ); + ; + break;} +case 11: +#line 191 "./cond.y" +{ + yyval.value = yyvsp[-1].fn_comp_str( yyvsp[-2].string, yyvsp[0].string, FALSE ); + ; + break;} +case 12: +#line 195 "./cond.y" +{ + yyval.value = yyvsp[-1].fn_comp_str( yyvsp[-3].string, yyvsp[0].string, TRUE ); + ; + break;} +case 13: +#line 199 "./cond.y" +{ + yyval.value = yyvsp[-1].fn_comp_m1( yyvsp[-2].string, yyvsp[0].value ); + ; + break;} +case 14: +#line 203 "./cond.y" +{ + yyval.value = yyvsp[-1].fn_comp_m2( yyvsp[-2].value, yyvsp[0].string ); + ; + break;} +case 15: +#line 207 "./cond.y" +{ + yyval.value = yyvsp[-1].value; + ; + break;} +case 16: +#line 215 "./cond.y" +{ + yyval.fn_comp_int = comp_eq_i; + ; + break;} +case 17: +#line 219 "./cond.y" +{ + yyval.fn_comp_int = comp_ne_i; + ; + break;} +case 18: +#line 223 "./cond.y" +{ + yyval.fn_comp_int = comp_lt_i; + ; + break;} +case 19: +#line 227 "./cond.y" +{ + yyval.fn_comp_int = comp_gt_i; + ; + break;} +case 20: +#line 231 "./cond.y" +{ + yyval.fn_comp_int = comp_le_i; + ; + break;} +case 21: +#line 235 "./cond.y" +{ + yyval.fn_comp_int = comp_ge_i; + ; + break;} +case 22: +#line 240 "./cond.y" +{ + yyval.fn_comp_int = comp_bitand; + ; + break;} +case 23: +#line 244 "./cond.y" +{ + yyval.fn_comp_int = comp_highcomp; + ; + break;} +case 24: +#line 248 "./cond.y" +{ + yyval.fn_comp_int = comp_lowcomp; + ; + break;} +case 25: +#line 256 "./cond.y" +{ + yyval.fn_comp_str = comp_eq_s; + ; + break;} +case 26: +#line 260 "./cond.y" +{ + yyval.fn_comp_str = comp_ne_s; + ; + break;} +case 27: +#line 264 "./cond.y" +{ + yyval.fn_comp_str = comp_lt_s; + ; + break;} +case 28: +#line 268 "./cond.y" +{ + yyval.fn_comp_str = comp_gt_s; + ; + break;} +case 29: +#line 272 "./cond.y" +{ + yyval.fn_comp_str = comp_le_s; + ; + break;} +case 30: +#line 276 "./cond.y" +{ + yyval.fn_comp_str = comp_ge_s; + ; + break;} +case 31: +#line 281 "./cond.y" +{ + yyval.fn_comp_str = comp_substring; + ; + break;} +case 32: +#line 285 "./cond.y" +{ + yyval.fn_comp_str = comp_start; + ; + break;} +case 33: +#line 289 "./cond.y" +{ + yyval.fn_comp_str = comp_end; + ; + break;} +case 34: +#line 297 "./cond.y" +{ + yyval.fn_comp_m1 = comp_eq_m1; + ; + break;} +case 35: +#line 301 "./cond.y" +{ + yyval.fn_comp_m1 = comp_ne_m1; + ; + break;} +case 36: +#line 305 "./cond.y" +{ + yyval.fn_comp_m1 = comp_lt_m1; + ; + break;} +case 37: +#line 309 "./cond.y" +{ + yyval.fn_comp_m1 = comp_gt_m1; + ; + break;} +case 38: +#line 313 "./cond.y" +{ + yyval.fn_comp_m1 = comp_le_m1; + ; + break;} +case 39: +#line 317 "./cond.y" +{ + yyval.fn_comp_m1 = comp_ge_m1; + ; + break;} +case 40: +#line 322 "./cond.y" +{ + yyval.fn_comp_m1 = 0; + ; + break;} +case 41: +#line 326 "./cond.y" +{ + yyval.fn_comp_m1 = 0; + ; + break;} +case 42: +#line 330 "./cond.y" +{ + yyval.fn_comp_m1 = 0; + ; + break;} +case 43: +#line 338 "./cond.y" +{ + yyval.fn_comp_m2 = comp_eq_m2; + ; + break;} +case 44: +#line 342 "./cond.y" +{ + yyval.fn_comp_m2 = comp_ne_m2; + ; + break;} +case 45: +#line 346 "./cond.y" +{ + yyval.fn_comp_m2 = comp_lt_m2; + ; + break;} +case 46: +#line 350 "./cond.y" +{ + yyval.fn_comp_m2 = comp_gt_m2; + ; + break;} +case 47: +#line 354 "./cond.y" +{ + yyval.fn_comp_m2 = comp_le_m2; + ; + break;} +case 48: +#line 358 "./cond.y" +{ + yyval.fn_comp_m2 = comp_ge_m2; + ; + break;} +case 49: +#line 363 "./cond.y" +{ + yyval.fn_comp_m2 = 0; + ; + break;} +case 50: +#line 367 "./cond.y" +{ + yyval.fn_comp_m2 = 0; + ; + break;} +case 51: +#line 371 "./cond.y" +{ + yyval.fn_comp_m2 = 0; + ; + break;} +case 52: +#line 378 "./cond.y" +{ + yyval.value = yyvsp[0].value; + ; + break;} +case 53: +#line 382 "./cond.y" +{ + yyval.value = yyvsp[0].value; + ; + break;} +case 54: +#line 389 "./cond.y" +{ + yyval.string = yyvsp[0].string; + ; + break;} +case 55: +#line 393 "./cond.y" +{ + yyval.string = yyvsp[0].string; + ; + break;} +case 56: +#line 400 "./cond.y" +{ + yyval.string = COND_GetLiteral(&yyvsp[0].str); + if( !yyval.string ) + YYABORT; + ; + break;} +case 57: +#line 409 "./cond.y" +{ + COND_input* cond = (COND_input*) info; + INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; + + MSI_GetComponentStateW(cond->package, yyvsp[0].string, &install, &action ); + yyval.value = action; + HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); + ; + break;} +case 58: +#line 418 "./cond.y" +{ + COND_input* cond = (COND_input*) info; + INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; + + MSI_GetComponentStateW(cond->package, yyvsp[0].string, &install, &action ); + yyval.value = install; + HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); + ; + break;} +case 59: +#line 427 "./cond.y" +{ + COND_input* cond = (COND_input*) info; + INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; + + MSI_GetFeatureStateW(cond->package, yyvsp[0].string, &install, &action ); + yyval.value = action; + HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); + ; + break;} +case 60: +#line 436 "./cond.y" +{ + COND_input* cond = (COND_input*) info; + INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; + + MSI_GetFeatureStateW(cond->package, yyvsp[0].string, &install, &action ); + yyval.value = install; + HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); + ; + break;} +case 61: +#line 448 "./cond.y" +{ + DWORD sz; + COND_input* cond = (COND_input*) info; + + sz = 0; + MSI_GetPropertyW(cond->package, yyvsp[0].string, NULL, &sz); + if (sz == 0) + { + yyval.string = HeapAlloc( GetProcessHeap(), 0 ,sizeof(WCHAR)); + yyval.string[0] = 0; + } + else + { + sz ++; + yyval.string = HeapAlloc( GetProcessHeap(), 0, sz*sizeof (WCHAR) ); + + /* Lookup the identifier */ + + MSI_GetPropertyW(cond->package,yyvsp[0].string,yyval.string,&sz); + } + HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); + ; + break;} +case 62: +#line 471 "./cond.y" +{ + UINT len = GetEnvironmentVariableW( yyvsp[0].string, NULL, 0 ); + if( len++ ) + { + yyval.string = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) ); + if( yyval.string ) + GetEnvironmentVariableW( yyvsp[0].string, yyval.string, len ); + } + HeapFree( GetProcessHeap(), 0, yyvsp[0].string ); + ; + break;} +case 63: +#line 485 "./cond.y" +{ + yyval.string = COND_GetString(&yyvsp[0].str); + if( !yyval.string ) + YYABORT; + ; + break;} +case 64: +#line 494 "./cond.y" +{ + LPWSTR szNum = COND_GetString(&yyvsp[0].str); + if( !szNum ) + YYABORT; + yyval.value = atoiW( szNum ); + HeapFree( GetProcessHeap(), 0, szNum ); + ; + break;} +} + +#line 705 "/usr/share/bison/bison.simple" + + + yyvsp -= yylen; + yyssp -= yylen; +#if YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG + if (yydebug) + { + short *yyssp1 = yyss - 1; + YYFPRINTF (stderr, "state stack now"); + while (yyssp1 != yyssp) + YYFPRINTF (stderr, " %d", *++yyssp1); + YYFPRINTF (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; +#if YYLSP_NEEDED + *++yylsp = yyloc; +#endif + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + YYSIZE_T yysize = 0; + char *yymsg; + int yyx, yycount; + + yycount = 0; + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) + if (yycheck[yyx + yyn] == yyx) + yysize += yystrlen (yytname[yyx]) + 15, yycount++; + yysize += yystrlen ("parse error, unexpected ") + 1; + yysize += yystrlen (yytname[YYTRANSLATE (yychar)]); + yymsg = (char *) YYSTACK_ALLOC (yysize); + if (yymsg != 0) + { + char *yyp = yystpcpy (yymsg, "parse error, unexpected "); + yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]); + + if (yycount < 5) + { + yycount = 0; + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); + yyx++) + if (yycheck[yyx + yyn] == yyx) + { + const char *yyq = ! yycount ? ", expecting " : " or "; + yyp = yystpcpy (yyp, yyq); + yyp = yystpcpy (yyp, yytname[yyx]); + yycount++; + } + } + yyerror (yymsg); + YYSTACK_FREE (yymsg); + } + else + yyerror ("parse error; also virtual memory exhausted"); + } + else +#endif /* defined (YYERROR_VERBOSE) */ + yyerror ("parse error"); + } + goto yyerrlab1; + + +/*--------------------------------------------------. +| yyerrlab1 -- error raised explicitly by an action | +`--------------------------------------------------*/ +yyerrlab1: + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + YYDPRINTF ((stderr, "Discarding token %d (%s).\n", + yychar, yytname[yychar1])); + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + + +/*-------------------------------------------------------------------. +| yyerrdefault -- current state does not do anything special for the | +| error token. | +`-------------------------------------------------------------------*/ +yyerrdefault: +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + + /* If its default is to accept any token, ok. Otherwise pop it. */ + yyn = yydefact[yystate]; + if (yyn) + goto yydefault; +#endif + + +/*---------------------------------------------------------------. +| yyerrpop -- pop the current state because it cannot handle the | +| error token | +`---------------------------------------------------------------*/ +yyerrpop: + if (yyssp == yyss) + YYABORT; + yyvsp--; + yystate = *--yyssp; +#if YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG + if (yydebug) + { + short *yyssp1 = yyss - 1; + YYFPRINTF (stderr, "Error: state stack now"); + while (yyssp1 != yyssp) + YYFPRINTF (stderr, " %d", *++yyssp1); + YYFPRINTF (stderr, "\n"); + } +#endif + +/*--------------. +| yyerrhandle. | +`--------------*/ +yyerrhandle: + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + + YYDPRINTF ((stderr, "Shifting error token, ")); + + *++yyvsp = yylval; +#if YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +/*---------------------------------------------. +| yyoverflowab -- parser overflow comes here. | +`---------------------------------------------*/ +yyoverflowlab: + yyerror ("parser stack overflow"); + yyresult = 2; + /* Fall through. */ + +yyreturn: +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + return yyresult; +} +#line 503 "./cond.y" + + + +static int COND_IsAlpha( WCHAR x ) +{ + return( ( ( x >= 'A' ) && ( x <= 'Z' ) ) || + ( ( x >= 'a' ) && ( x <= 'z' ) ) || + ( ( x == '_' ) ) ); +} + +static int COND_IsNumber( WCHAR x ) +{ + return( (( x >= '0' ) && ( x <= '9' )) || (x =='-') || (x =='.') ); +} + + +/* the mess of comparison functions */ + +static INT comp_lt_i(INT a, INT b) +{ return (a < b); } +static INT comp_gt_i(INT a, INT b) +{ return (a > b); } +static INT comp_le_i(INT a, INT b) +{ return (a <= b); } +static INT comp_ge_i(INT a, INT b) +{ return (a >= b); } +static INT comp_eq_i(INT a, INT b) +{ return (a == b); } +static INT comp_ne_i(INT a, INT b) +{ return (a != b); } +static INT comp_bitand(INT a, INT b) +{ return a & b;} +static INT comp_highcomp(INT a, INT b) +{ return HIWORD(a)==b; } +static INT comp_lowcomp(INT a, INT b) +{ return LOWORD(a)==b; } + +static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless) +{ if (casless) return !strcmpiW(a,b); else return !strcmpW(a,b);} +static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless) +{ if (casless) return strcmpiW(a,b); else return strcmpW(a,b);} +static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless) +{ if (casless) return strcmpiW(a,b)<0; else return strcmpW(a,b)<0;} +static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless) +{ if (casless) return strcmpiW(a,b)>0; else return strcmpW(a,b)>0;} +static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless) +{ if (casless) return strcmpiW(a,b)<=0; else return strcmpW(a,b)<=0;} +static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless) +{ if (casless) return strcmpiW(a,b)>=0; else return strcmpW(a,b)>=0;} +static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless) +/* ERROR NOT WORKING REWRITE */ +{ if (casless) return strstrW(a,b)!=NULL; else return strstrW(a,b)!=NULL;} +static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless) +{ if (casless) return strncmpiW(a,b,strlenW(b))==0; + else return strncmpW(a,b,strlenW(b))==0;} +static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless) +{ + int i = strlenW(a); + int j = strlenW(b); + if (j>i) + return 0; + if (casless) return (!strcmpiW(&a[i-j-1],b)); + else return (!strcmpW(&a[i-j-1],b)); +} + + +static INT comp_eq_m1(LPWSTR a, INT b) +{ if (COND_IsNumber(a[0])) return atoiW(a)==b; else return 0;} +static INT comp_ne_m1(LPWSTR a, INT b) +{ if (COND_IsNumber(a[0])) return atoiW(a)!=b; else return 1;} +static INT comp_lt_m1(LPWSTR a, INT b) +{ if (COND_IsNumber(a[0])) return atoiW(a)<b; else return 0;} +static INT comp_gt_m1(LPWSTR a, INT b) +{ if (COND_IsNumber(a[0])) return atoiW(a)>b; else return 0;} +static INT comp_le_m1(LPWSTR a, INT b) +{ if (COND_IsNumber(a[0])) return atoiW(a)<=b; else return 0;} +static INT comp_ge_m1(LPWSTR a, INT b) +{ if (COND_IsNumber(a[0])) return atoiW(a)>=b; else return 0;} + +static INT comp_eq_m2(INT a, LPWSTR b) +{ if (COND_IsNumber(b[0])) return a == atoiW(b); else return 0;} +static INT comp_ne_m2(INT a, LPWSTR b) +{ if (COND_IsNumber(b[0])) return a != atoiW(b); else return 1;} +static INT comp_lt_m2(INT a, LPWSTR b) +{ if (COND_IsNumber(b[0])) return a < atoiW(b); else return 0;} +static INT comp_gt_m2(INT a, LPWSTR b) +{ if (COND_IsNumber(b[0])) return a > atoiW(b); else return 0;} +static INT comp_le_m2(INT a, LPWSTR b) +{ if (COND_IsNumber(b[0])) return a <= atoiW(b); else return 0;} +static INT comp_ge_m2(INT a, LPWSTR b) +{ if (COND_IsNumber(b[0])) return a >= atoiW(b); else return 0;} + + + +static int COND_IsIdent( WCHAR x ) +{ + return( COND_IsAlpha( x ) || COND_IsNumber( x ) || ( x == '_' ) + || ( x == '#' ) || (x == '.') ); +} + +static int COND_GetOne( struct cond_str *str, COND_input *cond ) +{ + static const WCHAR szNot[] = {'N','O','T',0}; + static const WCHAR szAnd[] = {'A','N','D',0}; + static const WCHAR szOr[] = {'O','R',0}; + WCHAR ch; + int rc, len = 1; + + str->data = &cond->str[cond->n]; + + ch = str->data[0]; + switch( ch ) + { + case 0: return 0; + case '(': rc = COND_LPAR; break; + case ')': rc = COND_RPAR; break; + case '&': rc = COND_AMPER; break; + case '!': rc = COND_EXCLAM; break; + case '$': rc = COND_DOLLARS; break; + case '?': rc = COND_QUESTION; break; + case '%': rc = COND_PERCENT; break; + case ' ': rc = COND_SPACE; break; + case '=': rc = COND_EQ; break; + case '~': rc = COND_TILDA; break; + case '<': rc = COND_LT; break; + case '>': rc = COND_GT; break; + case '"': + { + const WCHAR *ch2 = str->data + 1; + + + while ( *ch2 && *ch2 != '"' ) + ++ch2; + if (*ch2 == '"') + { + len = ch2 - str->data + 1; + rc = COND_LITER; + break; + } + } + ERR("Unterminated string\n"); + rc = COND_ERROR; + break; + default: + if( COND_IsAlpha( ch ) ) + { + while( COND_IsIdent( str->data[len] ) ) + len++; + rc = COND_IDENT; + break; + } + + if( COND_IsNumber( ch ) ) + { + while( COND_IsNumber( str->data[len] ) ) + len++; + rc = COND_NUMBER; + break; + } + + ERR("Got unknown character %c(%x)\n",ch,ch); + rc = COND_ERROR; + break; + } + + /* keyword identifiers */ + if( rc == COND_IDENT ) + { + if( (len==3) && (strncmpiW(str->data,szNot,len)==0) ) + rc = COND_NOT; + else if( (len==3) && (strncmpiW(str->data,szAnd,len)==0) ) + rc = COND_AND; + else if( (len==2) && (strncmpiW(str->data,szOr,len)==0) ) + rc = COND_OR; + } + + cond->n += len; + str->len = len; + + return rc; +} + +static int COND_lex( void *COND_lval, COND_input *cond ) +{ + int rc; + struct cond_str *str = COND_lval; + + do { + rc = COND_GetOne( str, cond ); + } while (rc == COND_SPACE); + + return rc; +} + +static LPWSTR COND_GetString( struct cond_str *str ) +{ + LPWSTR ret; + + ret = HeapAlloc( GetProcessHeap(), 0, (str->len+1) * sizeof (WCHAR) ); + if( ret ) + { + memcpy( ret, str->data, str->len * sizeof(WCHAR)); + ret[str->len]=0; + } + TRACE("Got identifier %s\n",debugstr_w(ret)); + return ret; +} + +static LPWSTR COND_GetLiteral( struct cond_str *str ) +{ + LPWSTR ret; + + ret = HeapAlloc( GetProcessHeap(), 0, (str->len-1) * sizeof (WCHAR) ); + if( ret ) + { + memcpy( ret, str->data+1, (str->len-2) * sizeof(WCHAR) ); + ret[str->len - 2]=0; + } + TRACE("Got literal %s\n",debugstr_w(ret)); + return ret; +} + +static int COND_error(char *str) +{ + return 0; +} + +MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition ) +{ + COND_input cond; + MSICONDITION r; + + cond.package = package; + cond.str = szCondition; + cond.n = 0; + cond.result = -1; + + TRACE("Evaluating %s\n",debugstr_w(szCondition)); + + if ( szCondition == NULL || szCondition[0] == 0) + r = MSICONDITION_NONE; + else if ( !COND_parse( &cond ) ) + r = cond.result; + else + r = MSICONDITION_ERROR; + + TRACE("Evaluates to %i\n",r); + return r; +} + +MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szCondition ) +{ + MSIPACKAGE *package; + UINT ret; + + package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); + if( !package) + return ERROR_INVALID_HANDLE; + ret = MSI_EvaluateConditionW( package, szCondition ); + msiobj_release( &package->hdr ); + return ret; +} + +MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szCondition ) +{ + LPWSTR szwCond = NULL; + MSICONDITION r; + + if( szCondition ) + { + UINT len = MultiByteToWideChar( CP_ACP, 0, szCondition, -1, NULL, 0 ); + szwCond = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, szCondition, -1, szwCond, len ); + } + + r = MsiEvaluateConditionW( hInstall, szwCond ); + + HeapFree( GetProcessHeap(), 0, szwCond ); + + return r; +} diff --git a/reactos/lib/msi/create.c b/reactos/lib/msi/create.c index bbf90425dca..51d316e6b50 100644 --- a/reactos/lib/msi/create.c +++ b/reactos/lib/msi/create.c @@ -1,249 +1,249 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2002-2004 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "wine/debug.h" -#include "msi.h" -#include "msiquery.h" -#include "objbase.h" -#include "objidl.h" -#include "msipriv.h" -#include "winnls.h" - -#include "query.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - - -/* below is the query interface to a table */ - -typedef struct tagMSICREATEVIEW -{ - MSIVIEW view; - MSIDATABASE *db; - LPWSTR name; - BOOL bIsTemp; - create_col_info *col_info; -} MSICREATEVIEW; - -static UINT CREATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) -{ - MSICREATEVIEW *cv = (MSICREATEVIEW*)view; - - TRACE("%p %d %d %p\n", cv, row, col, val ); - - return ERROR_FUNCTION_FAILED; -} - -static UINT CREATE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) -{ - MSICREATEVIEW *cv = (MSICREATEVIEW*)view; - create_col_info *col; - UINT r, nField, row, table_val, column_val; - static const WCHAR szTables[] = { '_','T','a','b','l','e','s',0 }; - static const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 }; - MSIVIEW *tv = NULL; - - TRACE("%p Table %s (%s)\n", cv, debugstr_w(cv->name), - cv->bIsTemp?"temporary":"permanent"); - - /* only add tables that don't exist already */ - if( TABLE_Exists(cv->db, cv->name ) ) - return ERROR_BAD_QUERY_SYNTAX; - - /* add the name to the _Tables table */ - table_val = msi_addstringW( cv->db->strings, 0, cv->name, -1, 1 ); - TRACE("New string %s -> %d\n", debugstr_w( cv->name ), table_val ); - if( table_val < 0 ) - return ERROR_FUNCTION_FAILED; - - r = TABLE_CreateView( cv->db, szTables, &tv ); - TRACE("CreateView returned %x\n", r); - if( r ) - return r; - - r = tv->ops->execute( tv, 0 ); - TRACE("tv execute returned %x\n", r); - if( r ) - return r; - - row = -1; - r = tv->ops->insert_row( tv, &row ); - TRACE("insert_row returned %x\n", r); - if( r ) - goto err; - - r = tv->ops->set_int( tv, row, 1, table_val ); - if( r ) - goto err; - tv->ops->delete( tv ); - tv = NULL; - - /* add each column to the _Columns table */ - r = TABLE_CreateView( cv->db, szColumns, &tv ); - if( r ) - return r; - - r = tv->ops->execute( tv, 0 ); - TRACE("tv execute returned %x\n", r); - if( r ) - return r; - - /* - * need to set the table, column number, col name and type - * for each column we enter in the table - */ - nField = 1; - for( col = cv->col_info; col; col = col->next ) - { - row = -1; - r = tv->ops->insert_row( tv, &row ); - if( r ) - goto err; - - column_val = msi_addstringW( cv->db->strings, 0, col->colname, -1, 1 ); - TRACE("New string %s -> %d\n", debugstr_w( col->colname ), column_val ); - if( column_val < 0 ) - break; - - /* add the string again here so we increase the reference count */ - table_val = msi_addstringW( cv->db->strings, 0, cv->name, -1, 1 ); - if( table_val < 0 ) - break; - - r = tv->ops->set_int( tv, row, 1, table_val ); - if( r ) - break; - - r = tv->ops->set_int( tv, row, 2, 0x8000|nField ); - if( r ) - break; - - r = tv->ops->set_int( tv, row, 3, column_val ); - if( r ) - break; - - r = tv->ops->set_int( tv, row, 4, 0x8000|col->type ); - if( r ) - break; - - nField++; - } - if( !col ) - r = ERROR_SUCCESS; - -err: - /* FIXME: remove values from the string table on error */ - if( tv ) - tv->ops->delete( tv ); - return r; -} - -static UINT CREATE_close( struct tagMSIVIEW *view ) -{ - MSICREATEVIEW *cv = (MSICREATEVIEW*)view; - - TRACE("%p\n", cv); - - return ERROR_SUCCESS; -} - -static UINT CREATE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols ) -{ - MSICREATEVIEW *cv = (MSICREATEVIEW*)view; - - TRACE("%p %p %p\n", cv, rows, cols ); - - return ERROR_FUNCTION_FAILED; -} - -static UINT CREATE_get_column_info( struct tagMSIVIEW *view, - UINT n, LPWSTR *name, UINT *type ) -{ - MSICREATEVIEW *cv = (MSICREATEVIEW*)view; - - TRACE("%p %d %p %p\n", cv, n, name, type ); - - return ERROR_FUNCTION_FAILED; -} - -static UINT CREATE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, - MSIRECORD *rec) -{ - MSICREATEVIEW *cv = (MSICREATEVIEW*)view; - - TRACE("%p %d %p\n", cv, eModifyMode, rec ); - - return ERROR_FUNCTION_FAILED; -} - -static UINT CREATE_delete( struct tagMSIVIEW *view ) -{ - MSICREATEVIEW *cv = (MSICREATEVIEW*)view; - - TRACE("%p\n", cv ); - - msiobj_release( &cv->db->hdr ); - HeapFree( GetProcessHeap(), 0, cv ); - - return ERROR_SUCCESS; -} - - -MSIVIEWOPS create_ops = -{ - CREATE_fetch_int, - NULL, - NULL, - NULL, - CREATE_execute, - CREATE_close, - CREATE_get_dimensions, - CREATE_get_column_info, - CREATE_modify, - CREATE_delete -}; - -UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, - create_col_info *col_info, BOOL temp ) -{ - MSICREATEVIEW *cv = NULL; - - TRACE("%p\n", cv ); - - cv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *cv ); - if( !cv ) - return ERROR_FUNCTION_FAILED; - - /* fill the structure */ - cv->view.ops = &create_ops; - msiobj_addref( &db->hdr ); - cv->db = db; - cv->name = table; - cv->col_info = col_info; - cv->bIsTemp = temp; - *view = (MSIVIEW*) cv; - - return ERROR_SUCCESS; -} +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2002-2004 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/debug.h" +#include "msi.h" +#include "msiquery.h" +#include "objbase.h" +#include "objidl.h" +#include "msipriv.h" +#include "winnls.h" + +#include "query.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + + +/* below is the query interface to a table */ + +typedef struct tagMSICREATEVIEW +{ + MSIVIEW view; + MSIDATABASE *db; + LPWSTR name; + BOOL bIsTemp; + create_col_info *col_info; +} MSICREATEVIEW; + +static UINT CREATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) +{ + MSICREATEVIEW *cv = (MSICREATEVIEW*)view; + + TRACE("%p %d %d %p\n", cv, row, col, val ); + + return ERROR_FUNCTION_FAILED; +} + +static UINT CREATE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) +{ + MSICREATEVIEW *cv = (MSICREATEVIEW*)view; + create_col_info *col; + UINT r, nField, row, table_val, column_val; + static const WCHAR szTables[] = { '_','T','a','b','l','e','s',0 }; + static const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 }; + MSIVIEW *tv = NULL; + + TRACE("%p Table %s (%s)\n", cv, debugstr_w(cv->name), + cv->bIsTemp?"temporary":"permanent"); + + /* only add tables that don't exist already */ + if( TABLE_Exists(cv->db, cv->name ) ) + return ERROR_BAD_QUERY_SYNTAX; + + /* add the name to the _Tables table */ + table_val = msi_addstringW( cv->db->strings, 0, cv->name, -1, 1 ); + TRACE("New string %s -> %d\n", debugstr_w( cv->name ), table_val ); + if( table_val < 0 ) + return ERROR_FUNCTION_FAILED; + + r = TABLE_CreateView( cv->db, szTables, &tv ); + TRACE("CreateView returned %x\n", r); + if( r ) + return r; + + r = tv->ops->execute( tv, 0 ); + TRACE("tv execute returned %x\n", r); + if( r ) + return r; + + row = -1; + r = tv->ops->insert_row( tv, &row ); + TRACE("insert_row returned %x\n", r); + if( r ) + goto err; + + r = tv->ops->set_int( tv, row, 1, table_val ); + if( r ) + goto err; + tv->ops->delete( tv ); + tv = NULL; + + /* add each column to the _Columns table */ + r = TABLE_CreateView( cv->db, szColumns, &tv ); + if( r ) + return r; + + r = tv->ops->execute( tv, 0 ); + TRACE("tv execute returned %x\n", r); + if( r ) + return r; + + /* + * need to set the table, column number, col name and type + * for each column we enter in the table + */ + nField = 1; + for( col = cv->col_info; col; col = col->next ) + { + row = -1; + r = tv->ops->insert_row( tv, &row ); + if( r ) + goto err; + + column_val = msi_addstringW( cv->db->strings, 0, col->colname, -1, 1 ); + TRACE("New string %s -> %d\n", debugstr_w( col->colname ), column_val ); + if( column_val < 0 ) + break; + + /* add the string again here so we increase the reference count */ + table_val = msi_addstringW( cv->db->strings, 0, cv->name, -1, 1 ); + if( table_val < 0 ) + break; + + r = tv->ops->set_int( tv, row, 1, table_val ); + if( r ) + break; + + r = tv->ops->set_int( tv, row, 2, 0x8000|nField ); + if( r ) + break; + + r = tv->ops->set_int( tv, row, 3, column_val ); + if( r ) + break; + + r = tv->ops->set_int( tv, row, 4, 0x8000|col->type ); + if( r ) + break; + + nField++; + } + if( !col ) + r = ERROR_SUCCESS; + +err: + /* FIXME: remove values from the string table on error */ + if( tv ) + tv->ops->delete( tv ); + return r; +} + +static UINT CREATE_close( struct tagMSIVIEW *view ) +{ + MSICREATEVIEW *cv = (MSICREATEVIEW*)view; + + TRACE("%p\n", cv); + + return ERROR_SUCCESS; +} + +static UINT CREATE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols ) +{ + MSICREATEVIEW *cv = (MSICREATEVIEW*)view; + + TRACE("%p %p %p\n", cv, rows, cols ); + + return ERROR_FUNCTION_FAILED; +} + +static UINT CREATE_get_column_info( struct tagMSIVIEW *view, + UINT n, LPWSTR *name, UINT *type ) +{ + MSICREATEVIEW *cv = (MSICREATEVIEW*)view; + + TRACE("%p %d %p %p\n", cv, n, name, type ); + + return ERROR_FUNCTION_FAILED; +} + +static UINT CREATE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, + MSIRECORD *rec) +{ + MSICREATEVIEW *cv = (MSICREATEVIEW*)view; + + TRACE("%p %d %p\n", cv, eModifyMode, rec ); + + return ERROR_FUNCTION_FAILED; +} + +static UINT CREATE_delete( struct tagMSIVIEW *view ) +{ + MSICREATEVIEW *cv = (MSICREATEVIEW*)view; + + TRACE("%p\n", cv ); + + msiobj_release( &cv->db->hdr ); + HeapFree( GetProcessHeap(), 0, cv ); + + return ERROR_SUCCESS; +} + + +MSIVIEWOPS create_ops = +{ + CREATE_fetch_int, + NULL, + NULL, + NULL, + CREATE_execute, + CREATE_close, + CREATE_get_dimensions, + CREATE_get_column_info, + CREATE_modify, + CREATE_delete +}; + +UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, + create_col_info *col_info, BOOL temp ) +{ + MSICREATEVIEW *cv = NULL; + + TRACE("%p\n", cv ); + + cv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *cv ); + if( !cv ) + return ERROR_FUNCTION_FAILED; + + /* fill the structure */ + cv->view.ops = &create_ops; + msiobj_addref( &db->hdr ); + cv->db = db; + cv->name = table; + cv->col_info = col_info; + cv->bIsTemp = temp; + *view = (MSIVIEW*) cv; + + return ERROR_SUCCESS; +} diff --git a/reactos/lib/msi/distinct.c b/reactos/lib/msi/distinct.c index c74759ca8f4..64fa5ef9755 100644 --- a/reactos/lib/msi/distinct.c +++ b/reactos/lib/msi/distinct.c @@ -1,292 +1,292 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2002 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "wine/debug.h" -#include "msi.h" -#include "msiquery.h" -#include "objbase.h" -#include "objidl.h" -#include "msipriv.h" -#include "winnls.h" - -#include "query.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -typedef struct tagDISTINCTSET -{ - UINT val; - UINT count; - UINT row; - struct tagDISTINCTSET *nextrow; - struct tagDISTINCTSET *nextcol; -} DISTINCTSET; - -typedef struct tagMSIDISTINCTVIEW -{ - MSIVIEW view; - MSIDATABASE *db; - MSIVIEW *table; - UINT row_count; - UINT *translation; -} MSIDISTINCTVIEW; - -static DISTINCTSET ** distinct_insert( DISTINCTSET **x, UINT val, UINT row ) -{ - /* horrible O(n) find */ - while( *x ) - { - if( (*x)->val == val ) - { - (*x)->count++; - return x; - } - x = &(*x)->nextrow; - } - - /* nothing found, so add one */ - *x = HeapAlloc( GetProcessHeap(), 0, sizeof (DISTINCTSET) ); - if( *x ) - { - (*x)->val = val; - (*x)->count = 1; - (*x)->row = row; - (*x)->nextrow = NULL; - (*x)->nextcol = NULL; - } - return x; -} - -static void distinct_free( DISTINCTSET *x ) -{ - while( x ) - { - DISTINCTSET *next = x->nextrow; - distinct_free( x->nextcol ); - HeapFree( GetProcessHeap(), 0, x ); - x = next; - } -} - -static UINT DISTINCT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) -{ - MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view; - - TRACE("%p %d %d %p\n", dv, row, col, val ); - - if( !dv->table ) - return ERROR_FUNCTION_FAILED; - - if( row >= dv->row_count ) - return ERROR_INVALID_PARAMETER; - - row = dv->translation[ row ]; - - return dv->table->ops->fetch_int( dv->table, row, col, val ); -} - -static UINT DISTINCT_execute( struct tagMSIVIEW *view, MSIRECORD *record ) -{ - MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view; - UINT r, i, j, r_count, c_count; - DISTINCTSET *rowset = NULL; - - TRACE("%p %p\n", dv, record); - - if( !dv->table ) - return ERROR_FUNCTION_FAILED; - - r = dv->table->ops->execute( dv->table, record ); - if( r != ERROR_SUCCESS ) - return r; - - r = dv->table->ops->get_dimensions( dv->table, &r_count, &c_count ); - if( r != ERROR_SUCCESS ) - return r; - - dv->translation = HeapAlloc( GetProcessHeap(), 0, r_count*sizeof(UINT) ); - if( !dv->translation ) - return ERROR_FUNCTION_FAILED; - - /* build it */ - for( i=0; i<r_count; i++ ) - { - DISTINCTSET **x = &rowset; - - for( j=1; j<=c_count; j++ ) - { - UINT val = 0; - r = dv->table->ops->fetch_int( dv->table, i, j, &val ); - if( r != ERROR_SUCCESS ) - { - ERR("Failed to fetch int at %d %d\n", i, j ); - distinct_free( rowset ); - return r; - } - x = distinct_insert( x, val, i ); - if( !*x ) - { - ERR("Failed to insert at %d %d\n", i, j ); - distinct_free( rowset ); - return ERROR_FUNCTION_FAILED; - } - if( j != c_count ) - x = &(*x)->nextcol; - } - - /* check if it was distinct and if so, include it */ - if( (*x)->row == i ) - { - TRACE("Row %d -> %d\n", dv->row_count, i); - dv->translation[dv->row_count++] = i; - } - } - - distinct_free( rowset ); - - return ERROR_SUCCESS; -} - -static UINT DISTINCT_close( struct tagMSIVIEW *view ) -{ - MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view; - - TRACE("%p\n", dv ); - - if( !dv->table ) - return ERROR_FUNCTION_FAILED; - - HeapFree( GetProcessHeap(), 0, dv->translation ); - dv->translation = NULL; - dv->row_count = 0; - - return dv->table->ops->close( dv->table ); -} - -static UINT DISTINCT_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols ) -{ - MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view; - - TRACE("%p %p %p\n", dv, rows, cols ); - - if( !dv->table ) - return ERROR_FUNCTION_FAILED; - - if( rows ) - { - if( !dv->translation ) - return ERROR_FUNCTION_FAILED; - *rows = dv->row_count; - } - - return dv->table->ops->get_dimensions( dv->table, NULL, cols ); -} - -static UINT DISTINCT_get_column_info( struct tagMSIVIEW *view, - UINT n, LPWSTR *name, UINT *type ) -{ - MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view; - - TRACE("%p %d %p %p\n", dv, n, name, type ); - - if( !dv->table ) - return ERROR_FUNCTION_FAILED; - - return dv->table->ops->get_column_info( dv->table, n, name, type ); -} - -static UINT DISTINCT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, - MSIRECORD *rec ) -{ - MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view; - - TRACE("%p %d %p\n", dv, eModifyMode, rec ); - - if( !dv->table ) - return ERROR_FUNCTION_FAILED; - - return dv->table->ops->modify( dv->table, eModifyMode, rec ); -} - -static UINT DISTINCT_delete( struct tagMSIVIEW *view ) -{ - MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view; - - TRACE("%p\n", dv ); - - if( dv->table ) - dv->table->ops->delete( dv->table ); - - HeapFree( GetProcessHeap(), 0, dv->translation ); - msiobj_release( &dv->db->hdr ); - HeapFree( GetProcessHeap(), 0, dv ); - - return ERROR_SUCCESS; -} - - -MSIVIEWOPS distinct_ops = -{ - DISTINCT_fetch_int, - NULL, - NULL, - NULL, - DISTINCT_execute, - DISTINCT_close, - DISTINCT_get_dimensions, - DISTINCT_get_column_info, - DISTINCT_modify, - DISTINCT_delete -}; - -UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table ) -{ - MSIDISTINCTVIEW *dv = NULL; - UINT count = 0, r; - - TRACE("%p\n", dv ); - - r = table->ops->get_dimensions( table, NULL, &count ); - if( r != ERROR_SUCCESS ) - { - ERR("can't get table dimensions\n"); - return r; - } - - dv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *dv ); - if( !dv ) - return ERROR_FUNCTION_FAILED; - - /* fill the structure */ - dv->view.ops = &distinct_ops; - msiobj_addref( &db->hdr ); - dv->db = db; - dv->table = table; - dv->translation = NULL; - dv->row_count = 0; - *view = (MSIVIEW*) dv; - - return ERROR_SUCCESS; -} +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2002 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/debug.h" +#include "msi.h" +#include "msiquery.h" +#include "objbase.h" +#include "objidl.h" +#include "msipriv.h" +#include "winnls.h" + +#include "query.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +typedef struct tagDISTINCTSET +{ + UINT val; + UINT count; + UINT row; + struct tagDISTINCTSET *nextrow; + struct tagDISTINCTSET *nextcol; +} DISTINCTSET; + +typedef struct tagMSIDISTINCTVIEW +{ + MSIVIEW view; + MSIDATABASE *db; + MSIVIEW *table; + UINT row_count; + UINT *translation; +} MSIDISTINCTVIEW; + +static DISTINCTSET ** distinct_insert( DISTINCTSET **x, UINT val, UINT row ) +{ + /* horrible O(n) find */ + while( *x ) + { + if( (*x)->val == val ) + { + (*x)->count++; + return x; + } + x = &(*x)->nextrow; + } + + /* nothing found, so add one */ + *x = HeapAlloc( GetProcessHeap(), 0, sizeof (DISTINCTSET) ); + if( *x ) + { + (*x)->val = val; + (*x)->count = 1; + (*x)->row = row; + (*x)->nextrow = NULL; + (*x)->nextcol = NULL; + } + return x; +} + +static void distinct_free( DISTINCTSET *x ) +{ + while( x ) + { + DISTINCTSET *next = x->nextrow; + distinct_free( x->nextcol ); + HeapFree( GetProcessHeap(), 0, x ); + x = next; + } +} + +static UINT DISTINCT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) +{ + MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view; + + TRACE("%p %d %d %p\n", dv, row, col, val ); + + if( !dv->table ) + return ERROR_FUNCTION_FAILED; + + if( row >= dv->row_count ) + return ERROR_INVALID_PARAMETER; + + row = dv->translation[ row ]; + + return dv->table->ops->fetch_int( dv->table, row, col, val ); +} + +static UINT DISTINCT_execute( struct tagMSIVIEW *view, MSIRECORD *record ) +{ + MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view; + UINT r, i, j, r_count, c_count; + DISTINCTSET *rowset = NULL; + + TRACE("%p %p\n", dv, record); + + if( !dv->table ) + return ERROR_FUNCTION_FAILED; + + r = dv->table->ops->execute( dv->table, record ); + if( r != ERROR_SUCCESS ) + return r; + + r = dv->table->ops->get_dimensions( dv->table, &r_count, &c_count ); + if( r != ERROR_SUCCESS ) + return r; + + dv->translation = HeapAlloc( GetProcessHeap(), 0, r_count*sizeof(UINT) ); + if( !dv->translation ) + return ERROR_FUNCTION_FAILED; + + /* build it */ + for( i=0; i<r_count; i++ ) + { + DISTINCTSET **x = &rowset; + + for( j=1; j<=c_count; j++ ) + { + UINT val = 0; + r = dv->table->ops->fetch_int( dv->table, i, j, &val ); + if( r != ERROR_SUCCESS ) + { + ERR("Failed to fetch int at %d %d\n", i, j ); + distinct_free( rowset ); + return r; + } + x = distinct_insert( x, val, i ); + if( !*x ) + { + ERR("Failed to insert at %d %d\n", i, j ); + distinct_free( rowset ); + return ERROR_FUNCTION_FAILED; + } + if( j != c_count ) + x = &(*x)->nextcol; + } + + /* check if it was distinct and if so, include it */ + if( (*x)->row == i ) + { + TRACE("Row %d -> %d\n", dv->row_count, i); + dv->translation[dv->row_count++] = i; + } + } + + distinct_free( rowset ); + + return ERROR_SUCCESS; +} + +static UINT DISTINCT_close( struct tagMSIVIEW *view ) +{ + MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view; + + TRACE("%p\n", dv ); + + if( !dv->table ) + return ERROR_FUNCTION_FAILED; + + HeapFree( GetProcessHeap(), 0, dv->translation ); + dv->translation = NULL; + dv->row_count = 0; + + return dv->table->ops->close( dv->table ); +} + +static UINT DISTINCT_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols ) +{ + MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view; + + TRACE("%p %p %p\n", dv, rows, cols ); + + if( !dv->table ) + return ERROR_FUNCTION_FAILED; + + if( rows ) + { + if( !dv->translation ) + return ERROR_FUNCTION_FAILED; + *rows = dv->row_count; + } + + return dv->table->ops->get_dimensions( dv->table, NULL, cols ); +} + +static UINT DISTINCT_get_column_info( struct tagMSIVIEW *view, + UINT n, LPWSTR *name, UINT *type ) +{ + MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view; + + TRACE("%p %d %p %p\n", dv, n, name, type ); + + if( !dv->table ) + return ERROR_FUNCTION_FAILED; + + return dv->table->ops->get_column_info( dv->table, n, name, type ); +} + +static UINT DISTINCT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, + MSIRECORD *rec ) +{ + MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view; + + TRACE("%p %d %p\n", dv, eModifyMode, rec ); + + if( !dv->table ) + return ERROR_FUNCTION_FAILED; + + return dv->table->ops->modify( dv->table, eModifyMode, rec ); +} + +static UINT DISTINCT_delete( struct tagMSIVIEW *view ) +{ + MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view; + + TRACE("%p\n", dv ); + + if( dv->table ) + dv->table->ops->delete( dv->table ); + + HeapFree( GetProcessHeap(), 0, dv->translation ); + msiobj_release( &dv->db->hdr ); + HeapFree( GetProcessHeap(), 0, dv ); + + return ERROR_SUCCESS; +} + + +MSIVIEWOPS distinct_ops = +{ + DISTINCT_fetch_int, + NULL, + NULL, + NULL, + DISTINCT_execute, + DISTINCT_close, + DISTINCT_get_dimensions, + DISTINCT_get_column_info, + DISTINCT_modify, + DISTINCT_delete +}; + +UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table ) +{ + MSIDISTINCTVIEW *dv = NULL; + UINT count = 0, r; + + TRACE("%p\n", dv ); + + r = table->ops->get_dimensions( table, NULL, &count ); + if( r != ERROR_SUCCESS ) + { + ERR("can't get table dimensions\n"); + return r; + } + + dv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *dv ); + if( !dv ) + return ERROR_FUNCTION_FAILED; + + /* fill the structure */ + dv->view.ops = &distinct_ops; + msiobj_addref( &db->hdr ); + dv->db = db; + dv->table = table; + dv->translation = NULL; + dv->row_count = 0; + *view = (MSIVIEW*) dv; + + return ERROR_SUCCESS; +} diff --git a/reactos/lib/msi/handle.c b/reactos/lib/msi/handle.c index 281a16c0325..9ecfd053870 100644 --- a/reactos/lib/msi/handle.c +++ b/reactos/lib/msi/handle.c @@ -1,259 +1,259 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2002-2004 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "shlwapi.h" -#include "wine/debug.h" -#include "msi.h" -#include "msiquery.h" -#include "msipriv.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -static CRITICAL_SECTION MSI_handle_cs; -static CRITICAL_SECTION_DEBUG MSI_handle_cs_debug = -{ - 0, 0, &MSI_handle_cs, - { &MSI_handle_cs_debug.ProcessLocksList, - &MSI_handle_cs_debug.ProcessLocksList }, - 0, 0, { 0, (DWORD)(__FILE__ ": MSI_handle_cs") } -}; -static CRITICAL_SECTION MSI_handle_cs = { &MSI_handle_cs_debug, -1, 0, 0, 0, 0 }; - -static CRITICAL_SECTION MSI_object_cs; -static CRITICAL_SECTION_DEBUG MSI_object_cs_debug = -{ - 0, 0, &MSI_object_cs, - { &MSI_object_cs_debug.ProcessLocksList, - &MSI_object_cs_debug.ProcessLocksList }, - 0, 0, { 0, (DWORD)(__FILE__ ": MSI_object_cs") } -}; -static CRITICAL_SECTION MSI_object_cs = { &MSI_object_cs_debug, -1, 0, 0, 0, 0 }; - -typedef struct msi_handle_info_t -{ - MSIOBJECTHDR *obj; - DWORD dwThreadId; -} msi_handle_info; - -static msi_handle_info msihandletable[MSIMAXHANDLES]; - -MSIHANDLE alloc_msihandle( MSIOBJECTHDR *obj ) -{ - MSIHANDLE ret = 0; - UINT i; - - EnterCriticalSection( &MSI_handle_cs ); - - /* find a slot */ - for(i=0; i<MSIMAXHANDLES; i++) - if( !msihandletable[i].obj ) - break; - if( (i>=MSIMAXHANDLES) || msihandletable[i].obj ) - goto out; - - msiobj_addref( obj ); - msihandletable[i].obj = obj; - msihandletable[i].dwThreadId = GetCurrentThreadId(); - ret = (MSIHANDLE) (i+1); -out: - TRACE("%p -> %ld\n", obj, ret ); - - LeaveCriticalSection( &MSI_handle_cs ); - return ret; -} - -void *msihandle2msiinfo(MSIHANDLE handle, UINT type) -{ - MSIOBJECTHDR *ret = NULL; - - EnterCriticalSection( &MSI_handle_cs ); - handle--; - if( handle<0 ) - goto out; - if( handle>=MSIMAXHANDLES ) - goto out; - if( !msihandletable[handle].obj ) - goto out; - if( msihandletable[handle].obj->magic != MSIHANDLE_MAGIC ) - goto out; - if( type && (msihandletable[handle].obj->type != type) ) - goto out; - ret = msihandletable[handle].obj; - msiobj_addref( ret ); - -out: - LeaveCriticalSection( &MSI_handle_cs ); - - return (void*) ret; -} - -MSIHANDLE msiobj_findhandle( MSIOBJECTHDR *hdr ) -{ - MSIHANDLE ret = 0; - UINT i; - - TRACE("%p\n", hdr); - - EnterCriticalSection( &MSI_handle_cs ); - for(i=0; (i<MSIMAXHANDLES) && !ret; i++) - if( msihandletable[i].obj == hdr ) - ret = i+1; - LeaveCriticalSection( &MSI_handle_cs ); - - TRACE("%p -> %ld\n", hdr, ret); - - msiobj_addref( hdr ); - return ret; -} - -void *alloc_msiobject(UINT type, UINT size, msihandledestructor destroy ) -{ - MSIOBJECTHDR *info; - - info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ); - if( info ) - { - info->magic = MSIHANDLE_MAGIC; - info->type = type; - info->refcount = 1; - info->destructor = destroy; - } - - return info; -} - -void msiobj_addref( MSIOBJECTHDR *info ) -{ - TRACE("%p\n", info); - - if( !info ) - return; - - if( info->magic != MSIHANDLE_MAGIC ) - { - ERR("Invalid handle!\n"); - return; - } - - InterlockedIncrement(&info->refcount); -} - -void msiobj_lock( MSIOBJECTHDR *info ) -{ - EnterCriticalSection( &MSI_object_cs ); -} - -void msiobj_unlock( MSIOBJECTHDR *info ) -{ - LeaveCriticalSection( &MSI_object_cs ); -} - -int msiobj_release( MSIOBJECTHDR *info ) -{ - int ret; - - TRACE("%p\n",info); - - if( !info ) - return -1; - - if( info->magic != MSIHANDLE_MAGIC ) - { - ERR("Invalid handle!\n"); - return -1; - } - - ret = InterlockedDecrement( &info->refcount ); - if( ret==0 ) - { - if( info->destructor ) - info->destructor( info ); - HeapFree( GetProcessHeap(), 0, info ); - TRACE("object %p destroyed\n", info); - } - - return ret; -} - -/*********************************************************** - * MsiCloseHandle [MSI.@] - */ -UINT WINAPI MsiCloseHandle(MSIHANDLE handle) -{ - MSIOBJECTHDR *info; - UINT ret = ERROR_INVALID_HANDLE; - - TRACE("%lx\n",handle); - - EnterCriticalSection( &MSI_handle_cs ); - - info = msihandle2msiinfo(handle, 0); - if( !info ) - goto out; - - if( info->magic != MSIHANDLE_MAGIC ) - { - ERR("Invalid handle!\n"); - goto out; - } - - msiobj_release( info ); - msihandletable[handle-1].obj = NULL; - ret = ERROR_SUCCESS; - - TRACE("handle %lx Destroyed\n", handle); -out: - LeaveCriticalSection( &MSI_handle_cs ); - if( info ) - msiobj_release( info ); - - return ret; -} - -/*********************************************************** - * MsiCloseAllHandles [MSI.@] - * - * Closes all handles owned by the current thread - * - * RETURNS: - * The number of handles closed - */ -UINT WINAPI MsiCloseAllHandles(void) -{ - UINT i, n=0; - - TRACE("\n"); - - for(i=0; i<MSIMAXHANDLES; i++) - { - if(msihandletable[i].dwThreadId == GetCurrentThreadId()) - { - MsiCloseHandle( i+1 ); - n++; - } - } - - return n; -} +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2002-2004 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "shlwapi.h" +#include "wine/debug.h" +#include "msi.h" +#include "msiquery.h" +#include "msipriv.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +static CRITICAL_SECTION MSI_handle_cs; +static CRITICAL_SECTION_DEBUG MSI_handle_cs_debug = +{ + 0, 0, &MSI_handle_cs, + { &MSI_handle_cs_debug.ProcessLocksList, + &MSI_handle_cs_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": MSI_handle_cs") } +}; +static CRITICAL_SECTION MSI_handle_cs = { &MSI_handle_cs_debug, -1, 0, 0, 0, 0 }; + +static CRITICAL_SECTION MSI_object_cs; +static CRITICAL_SECTION_DEBUG MSI_object_cs_debug = +{ + 0, 0, &MSI_object_cs, + { &MSI_object_cs_debug.ProcessLocksList, + &MSI_object_cs_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": MSI_object_cs") } +}; +static CRITICAL_SECTION MSI_object_cs = { &MSI_object_cs_debug, -1, 0, 0, 0, 0 }; + +typedef struct msi_handle_info_t +{ + MSIOBJECTHDR *obj; + DWORD dwThreadId; +} msi_handle_info; + +static msi_handle_info msihandletable[MSIMAXHANDLES]; + +MSIHANDLE alloc_msihandle( MSIOBJECTHDR *obj ) +{ + MSIHANDLE ret = 0; + UINT i; + + EnterCriticalSection( &MSI_handle_cs ); + + /* find a slot */ + for(i=0; i<MSIMAXHANDLES; i++) + if( !msihandletable[i].obj ) + break; + if( (i>=MSIMAXHANDLES) || msihandletable[i].obj ) + goto out; + + msiobj_addref( obj ); + msihandletable[i].obj = obj; + msihandletable[i].dwThreadId = GetCurrentThreadId(); + ret = (MSIHANDLE) (i+1); +out: + TRACE("%p -> %ld\n", obj, ret ); + + LeaveCriticalSection( &MSI_handle_cs ); + return ret; +} + +void *msihandle2msiinfo(MSIHANDLE handle, UINT type) +{ + MSIOBJECTHDR *ret = NULL; + + EnterCriticalSection( &MSI_handle_cs ); + handle--; + if( handle<0 ) + goto out; + if( handle>=MSIMAXHANDLES ) + goto out; + if( !msihandletable[handle].obj ) + goto out; + if( msihandletable[handle].obj->magic != MSIHANDLE_MAGIC ) + goto out; + if( type && (msihandletable[handle].obj->type != type) ) + goto out; + ret = msihandletable[handle].obj; + msiobj_addref( ret ); + +out: + LeaveCriticalSection( &MSI_handle_cs ); + + return (void*) ret; +} + +MSIHANDLE msiobj_findhandle( MSIOBJECTHDR *hdr ) +{ + MSIHANDLE ret = 0; + UINT i; + + TRACE("%p\n", hdr); + + EnterCriticalSection( &MSI_handle_cs ); + for(i=0; (i<MSIMAXHANDLES) && !ret; i++) + if( msihandletable[i].obj == hdr ) + ret = i+1; + LeaveCriticalSection( &MSI_handle_cs ); + + TRACE("%p -> %ld\n", hdr, ret); + + msiobj_addref( hdr ); + return ret; +} + +void *alloc_msiobject(UINT type, UINT size, msihandledestructor destroy ) +{ + MSIOBJECTHDR *info; + + info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ); + if( info ) + { + info->magic = MSIHANDLE_MAGIC; + info->type = type; + info->refcount = 1; + info->destructor = destroy; + } + + return info; +} + +void msiobj_addref( MSIOBJECTHDR *info ) +{ + TRACE("%p\n", info); + + if( !info ) + return; + + if( info->magic != MSIHANDLE_MAGIC ) + { + ERR("Invalid handle!\n"); + return; + } + + InterlockedIncrement(&info->refcount); +} + +void msiobj_lock( MSIOBJECTHDR *info ) +{ + EnterCriticalSection( &MSI_object_cs ); +} + +void msiobj_unlock( MSIOBJECTHDR *info ) +{ + LeaveCriticalSection( &MSI_object_cs ); +} + +int msiobj_release( MSIOBJECTHDR *info ) +{ + int ret; + + TRACE("%p\n",info); + + if( !info ) + return -1; + + if( info->magic != MSIHANDLE_MAGIC ) + { + ERR("Invalid handle!\n"); + return -1; + } + + ret = InterlockedDecrement( &info->refcount ); + if( ret==0 ) + { + if( info->destructor ) + info->destructor( info ); + HeapFree( GetProcessHeap(), 0, info ); + TRACE("object %p destroyed\n", info); + } + + return ret; +} + +/*********************************************************** + * MsiCloseHandle [MSI.@] + */ +UINT WINAPI MsiCloseHandle(MSIHANDLE handle) +{ + MSIOBJECTHDR *info; + UINT ret = ERROR_INVALID_HANDLE; + + TRACE("%lx\n",handle); + + EnterCriticalSection( &MSI_handle_cs ); + + info = msihandle2msiinfo(handle, 0); + if( !info ) + goto out; + + if( info->magic != MSIHANDLE_MAGIC ) + { + ERR("Invalid handle!\n"); + goto out; + } + + msiobj_release( info ); + msihandletable[handle-1].obj = NULL; + ret = ERROR_SUCCESS; + + TRACE("handle %lx Destroyed\n", handle); +out: + LeaveCriticalSection( &MSI_handle_cs ); + if( info ) + msiobj_release( info ); + + return ret; +} + +/*********************************************************** + * MsiCloseAllHandles [MSI.@] + * + * Closes all handles owned by the current thread + * + * RETURNS: + * The number of handles closed + */ +UINT WINAPI MsiCloseAllHandles(void) +{ + UINT i, n=0; + + TRACE("\n"); + + for(i=0; i<MSIMAXHANDLES; i++) + { + if(msihandletable[i].dwThreadId == GetCurrentThreadId()) + { + MsiCloseHandle( i+1 ); + n++; + } + } + + return n; +} diff --git a/reactos/lib/msi/insert.c b/reactos/lib/msi/insert.c index b8e69980943..1ec84bf3523 100644 --- a/reactos/lib/msi/insert.c +++ b/reactos/lib/msi/insert.c @@ -1,292 +1,292 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2004 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "wine/debug.h" -#include "msi.h" -#include "msiquery.h" -#include "objbase.h" -#include "objidl.h" -#include "msipriv.h" -#include "winnls.h" - -#include "query.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - - -/* below is the query interface to a table */ - -typedef struct tagMSIINSERTVIEW -{ - MSIVIEW view; - MSIDATABASE *db; - BOOL bIsTemp; - MSIVIEW *sv; - value_list *vals; -} MSIINSERTVIEW; - -static UINT INSERT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) -{ - MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; - - TRACE("%p %d %d %p\n", iv, row, col, val ); - - return ERROR_FUNCTION_FAILED; -} - -/* - * INSERT_merge_record - * - * Merge a value_list and a record to create a second record. - * Replace wildcard entries in the valuelist with values from the record - */ -static MSIRECORD *INSERT_merge_record( UINT fields, value_list *vl, MSIRECORD *rec ) -{ - MSIRECORD *merged; - DWORD wildcard_count = 1, i; - const WCHAR *str; - - merged = MSI_CreateRecord( fields ); - for( i=1; i <= fields; i++ ) - { - if( !vl ) - { - TRACE("Not enough elements in the list to insert\n"); - goto err; - } - switch( vl->val->type ) - { - case EXPR_SVAL: - TRACE("field %ld -> %s\n", i, debugstr_w(vl->val->u.sval)); - MSI_RecordSetStringW( merged, i, vl->val->u.sval ); - break; - case EXPR_IVAL: - MSI_RecordSetInteger( merged, i, vl->val->u.ival ); - break; - case EXPR_WILDCARD: - if( !rec ) - goto err; - if( MSI_RecordIsNull( rec, wildcard_count ) ) - goto err; - str = MSI_RecordGetString( rec, wildcard_count ); - MSI_RecordSetStringW( merged, i, str ); - wildcard_count++; - break; - default: - ERR("Unknown expression type %d\n", vl->val->type); - } - vl = vl->next; - } - - return merged; -err: - msiobj_release( &merged->hdr ); - return NULL; -} - -static UINT INSERT_execute( struct tagMSIVIEW *view, MSIRECORD *record ) -{ - MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; - UINT n, type, val, r, row, col_count = 0; - MSIVIEW *sv; - MSIRECORD *values = NULL; - - TRACE("%p %p\n", iv, record ); - - sv = iv->sv; - if( !sv ) - return ERROR_FUNCTION_FAILED; - - r = sv->ops->execute( sv, 0 ); - TRACE("tv execute returned %x\n", r); - if( r ) - return r; - - r = sv->ops->get_dimensions( sv, NULL, &col_count ); - if( r ) - goto err; - - /* - * Merge the wildcard values into the list of values provided - * in the query, and create a record containing both. - */ - values = INSERT_merge_record( col_count, iv->vals, record ); - if( !values ) - goto err; - - row = -1; - r = sv->ops->insert_row( sv, &row ); - TRACE("insert_row returned %x\n", r); - if( r ) - goto err; - - for( n = 1; n <= col_count; n++ ) - { - r = sv->ops->get_column_info( sv, n, NULL, &type ); - if( r ) - break; - - if( type & MSITYPE_STRING ) - { - const WCHAR *str = MSI_RecordGetString( values, n ); - val = msi_addstringW( iv->db->strings, 0, str, -1, 1 ); - } - else - { - val = MSI_RecordGetInteger( values, n ); - val |= 0x8000; - } - r = sv->ops->set_int( sv, row, n, val ); - if( r ) - break; - } - -err: - if( values ) - msiobj_release( &values->hdr ); - - return ERROR_SUCCESS; -} - - -static UINT INSERT_close( struct tagMSIVIEW *view ) -{ - MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; - MSIVIEW *sv; - - TRACE("%p\n", iv); - - sv = iv->sv; - if( !sv ) - return ERROR_FUNCTION_FAILED; - - return sv->ops->close( sv ); -} - -static UINT INSERT_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols ) -{ - MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; - MSIVIEW *sv; - - TRACE("%p %p %p\n", iv, rows, cols ); - - sv = iv->sv; - if( !sv ) - return ERROR_FUNCTION_FAILED; - - return sv->ops->get_dimensions( sv, rows, cols ); -} - -static UINT INSERT_get_column_info( struct tagMSIVIEW *view, - UINT n, LPWSTR *name, UINT *type ) -{ - MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; - MSIVIEW *sv; - - TRACE("%p %d %p %p\n", iv, n, name, type ); - - sv = iv->sv; - if( !sv ) - return ERROR_FUNCTION_FAILED; - - return sv->ops->get_column_info( sv, n, name, type ); -} - -static UINT INSERT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIRECORD *rec) -{ - MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; - - TRACE("%p %d %p\n", iv, eModifyMode, rec ); - - return ERROR_FUNCTION_FAILED; -} - -static UINT INSERT_delete( struct tagMSIVIEW *view ) -{ - MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; - MSIVIEW *sv; - - TRACE("%p\n", iv ); - - sv = iv->sv; - if( sv ) - sv->ops->delete( sv ); - msiobj_release( &iv->db->hdr ); - HeapFree( GetProcessHeap(), 0, iv ); - - return ERROR_SUCCESS; -} - - -MSIVIEWOPS insert_ops = -{ - INSERT_fetch_int, - NULL, - NULL, - NULL, - INSERT_execute, - INSERT_close, - INSERT_get_dimensions, - INSERT_get_column_info, - INSERT_modify, - INSERT_delete -}; - -UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, - string_list *columns, value_list *values, BOOL temp ) -{ - MSIINSERTVIEW *iv = NULL; - UINT r; - MSIVIEW *tv = NULL, *sv = NULL; - - TRACE("%p\n", iv ); - - r = TABLE_CreateView( db, table, &tv ); - if( r != ERROR_SUCCESS ) - return r; - - r = SELECT_CreateView( db, &sv, tv, columns ); - if( r != ERROR_SUCCESS ) - { - if( tv ) - tv->ops->delete( tv ); - return r; - } - - iv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *iv ); - if( !iv ) - return ERROR_FUNCTION_FAILED; - - /* fill the structure */ - iv->view.ops = &insert_ops; - msiobj_addref( &db->hdr ); - iv->db = db; - iv->vals = values; - iv->bIsTemp = temp; - iv->sv = sv; - *view = (MSIVIEW*) iv; - - return ERROR_SUCCESS; -} +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2004 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/debug.h" +#include "msi.h" +#include "msiquery.h" +#include "objbase.h" +#include "objidl.h" +#include "msipriv.h" +#include "winnls.h" + +#include "query.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + + +/* below is the query interface to a table */ + +typedef struct tagMSIINSERTVIEW +{ + MSIVIEW view; + MSIDATABASE *db; + BOOL bIsTemp; + MSIVIEW *sv; + value_list *vals; +} MSIINSERTVIEW; + +static UINT INSERT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) +{ + MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; + + TRACE("%p %d %d %p\n", iv, row, col, val ); + + return ERROR_FUNCTION_FAILED; +} + +/* + * INSERT_merge_record + * + * Merge a value_list and a record to create a second record. + * Replace wildcard entries in the valuelist with values from the record + */ +static MSIRECORD *INSERT_merge_record( UINT fields, value_list *vl, MSIRECORD *rec ) +{ + MSIRECORD *merged; + DWORD wildcard_count = 1, i; + const WCHAR *str; + + merged = MSI_CreateRecord( fields ); + for( i=1; i <= fields; i++ ) + { + if( !vl ) + { + TRACE("Not enough elements in the list to insert\n"); + goto err; + } + switch( vl->val->type ) + { + case EXPR_SVAL: + TRACE("field %ld -> %s\n", i, debugstr_w(vl->val->u.sval)); + MSI_RecordSetStringW( merged, i, vl->val->u.sval ); + break; + case EXPR_IVAL: + MSI_RecordSetInteger( merged, i, vl->val->u.ival ); + break; + case EXPR_WILDCARD: + if( !rec ) + goto err; + if( MSI_RecordIsNull( rec, wildcard_count ) ) + goto err; + str = MSI_RecordGetString( rec, wildcard_count ); + MSI_RecordSetStringW( merged, i, str ); + wildcard_count++; + break; + default: + ERR("Unknown expression type %d\n", vl->val->type); + } + vl = vl->next; + } + + return merged; +err: + msiobj_release( &merged->hdr ); + return NULL; +} + +static UINT INSERT_execute( struct tagMSIVIEW *view, MSIRECORD *record ) +{ + MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; + UINT n, type, val, r, row, col_count = 0; + MSIVIEW *sv; + MSIRECORD *values = NULL; + + TRACE("%p %p\n", iv, record ); + + sv = iv->sv; + if( !sv ) + return ERROR_FUNCTION_FAILED; + + r = sv->ops->execute( sv, 0 ); + TRACE("tv execute returned %x\n", r); + if( r ) + return r; + + r = sv->ops->get_dimensions( sv, NULL, &col_count ); + if( r ) + goto err; + + /* + * Merge the wildcard values into the list of values provided + * in the query, and create a record containing both. + */ + values = INSERT_merge_record( col_count, iv->vals, record ); + if( !values ) + goto err; + + row = -1; + r = sv->ops->insert_row( sv, &row ); + TRACE("insert_row returned %x\n", r); + if( r ) + goto err; + + for( n = 1; n <= col_count; n++ ) + { + r = sv->ops->get_column_info( sv, n, NULL, &type ); + if( r ) + break; + + if( type & MSITYPE_STRING ) + { + const WCHAR *str = MSI_RecordGetString( values, n ); + val = msi_addstringW( iv->db->strings, 0, str, -1, 1 ); + } + else + { + val = MSI_RecordGetInteger( values, n ); + val |= 0x8000; + } + r = sv->ops->set_int( sv, row, n, val ); + if( r ) + break; + } + +err: + if( values ) + msiobj_release( &values->hdr ); + + return ERROR_SUCCESS; +} + + +static UINT INSERT_close( struct tagMSIVIEW *view ) +{ + MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; + MSIVIEW *sv; + + TRACE("%p\n", iv); + + sv = iv->sv; + if( !sv ) + return ERROR_FUNCTION_FAILED; + + return sv->ops->close( sv ); +} + +static UINT INSERT_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols ) +{ + MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; + MSIVIEW *sv; + + TRACE("%p %p %p\n", iv, rows, cols ); + + sv = iv->sv; + if( !sv ) + return ERROR_FUNCTION_FAILED; + + return sv->ops->get_dimensions( sv, rows, cols ); +} + +static UINT INSERT_get_column_info( struct tagMSIVIEW *view, + UINT n, LPWSTR *name, UINT *type ) +{ + MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; + MSIVIEW *sv; + + TRACE("%p %d %p %p\n", iv, n, name, type ); + + sv = iv->sv; + if( !sv ) + return ERROR_FUNCTION_FAILED; + + return sv->ops->get_column_info( sv, n, name, type ); +} + +static UINT INSERT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIRECORD *rec) +{ + MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; + + TRACE("%p %d %p\n", iv, eModifyMode, rec ); + + return ERROR_FUNCTION_FAILED; +} + +static UINT INSERT_delete( struct tagMSIVIEW *view ) +{ + MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view; + MSIVIEW *sv; + + TRACE("%p\n", iv ); + + sv = iv->sv; + if( sv ) + sv->ops->delete( sv ); + msiobj_release( &iv->db->hdr ); + HeapFree( GetProcessHeap(), 0, iv ); + + return ERROR_SUCCESS; +} + + +MSIVIEWOPS insert_ops = +{ + INSERT_fetch_int, + NULL, + NULL, + NULL, + INSERT_execute, + INSERT_close, + INSERT_get_dimensions, + INSERT_get_column_info, + INSERT_modify, + INSERT_delete +}; + +UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, + string_list *columns, value_list *values, BOOL temp ) +{ + MSIINSERTVIEW *iv = NULL; + UINT r; + MSIVIEW *tv = NULL, *sv = NULL; + + TRACE("%p\n", iv ); + + r = TABLE_CreateView( db, table, &tv ); + if( r != ERROR_SUCCESS ) + return r; + + r = SELECT_CreateView( db, &sv, tv, columns ); + if( r != ERROR_SUCCESS ) + { + if( tv ) + tv->ops->delete( tv ); + return r; + } + + iv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *iv ); + if( !iv ) + return ERROR_FUNCTION_FAILED; + + /* fill the structure */ + iv->view.ops = &insert_ops; + msiobj_addref( &db->hdr ); + iv->db = db; + iv->vals = values; + iv->bIsTemp = temp; + iv->sv = sv; + *view = (MSIVIEW*) iv; + + return ERROR_SUCCESS; +} diff --git a/reactos/lib/msi/msi.c b/reactos/lib/msi/msi.c index 8bc930bca81..e7d1fa1a094 100644 --- a/reactos/lib/msi/msi.c +++ b/reactos/lib/msi/msi.c @@ -1,1722 +1,1722 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2002,2003,2004,2005 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> - -#define COBJMACROS -#define NONAMELESSUNION - -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "winnls.h" -#include "shlwapi.h" -#include "wine/debug.h" -#include "msi.h" -#include "msiquery.h" -#include "msipriv.h" -#include "wincrypt.h" -#include "winver.h" -#include "winuser.h" -#include "wine/unicode.h" -#include "action.h" - -UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf); - - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -/* - * The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR, - * which is a problem because LPCTSTR isn't defined when compiling wine. - * To work around this problem, we need to define LPCTSTR as LPCWSTR here, - * and make sure to only use it in W functions. - */ -#define LPCTSTR LPCWSTR - -/* the UI level */ -INSTALLUILEVEL gUILevel = INSTALLUILEVEL_BASIC; -HWND gUIhwnd = 0; -INSTALLUI_HANDLERA gUIHandlerA = NULL; -INSTALLUI_HANDLERW gUIHandlerW = NULL; -DWORD gUIFilter = 0; -LPVOID gUIContext = NULL; -WCHAR gszLogFile[MAX_PATH]; -HINSTANCE msi_hInstance; - -static const WCHAR installerW[] = {'\\','I','n','s','t','a','l','l','e','r',0}; - -UINT WINAPI MsiOpenProductA(LPCSTR szProduct, MSIHANDLE *phProduct) -{ - UINT r; - LPWSTR szwProd = NULL; - - TRACE("%s %p\n",debugstr_a(szProduct), phProduct); - - if( szProduct ) - { - szwProd = strdupAtoW( szProduct ); - if( !szwProd ) - return ERROR_OUTOFMEMORY; - } - - r = MsiOpenProductW( szwProd, phProduct ); - - HeapFree( GetProcessHeap(), 0, szwProd ); - - return r; -} - -UINT WINAPI MsiOpenProductW(LPCWSTR szProduct, MSIHANDLE *phProduct) -{ - static const WCHAR szLocalPackage[] = { - 'L','o','c','a','l','P','a','c','k','a','g','e', 0 - }; - LPWSTR path = NULL; - UINT r; - HKEY hKeyProduct = NULL; - DWORD count, type; - - TRACE("%s %p\n",debugstr_w(szProduct), phProduct); - - r = MSIREG_OpenUninstallKey(szProduct,&hKeyProduct,FALSE); - if( r != ERROR_SUCCESS ) - { - r = ERROR_UNKNOWN_PRODUCT; - goto end; - } - - /* find the size of the path */ - type = count = 0; - r = RegQueryValueExW( hKeyProduct, szLocalPackage, - NULL, &type, NULL, &count ); - if( r != ERROR_SUCCESS ) - { - r = ERROR_UNKNOWN_PRODUCT; - goto end; - } - - /* now alloc and fetch the path of the database to open */ - path = HeapAlloc( GetProcessHeap(), 0, count ); - if( !path ) - goto end; - - r = RegQueryValueExW( hKeyProduct, szLocalPackage, - NULL, &type, (LPBYTE) path, &count ); - if( r != ERROR_SUCCESS ) - { - r = ERROR_UNKNOWN_PRODUCT; - goto end; - } - - r = MsiOpenPackageW( path, phProduct ); - -end: - HeapFree( GetProcessHeap(), 0, path ); - if( hKeyProduct ) - RegCloseKey( hKeyProduct ); - - return r; -} - -UINT WINAPI MsiAdvertiseProductA(LPCSTR szPackagePath, LPCSTR szScriptfilePath, - LPCSTR szTransforms, LANGID lgidLanguage) -{ - FIXME("%s %s %s %08x\n",debugstr_a(szPackagePath), - debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiAdvertiseProductW(LPCWSTR szPackagePath, LPCWSTR szScriptfilePath, - LPCWSTR szTransforms, LANGID lgidLanguage) -{ - FIXME("%s %s %s %08x\n",debugstr_w(szPackagePath), - debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiAdvertiseProductExA(LPCSTR szPackagePath, LPCSTR szScriptfilePath, - LPCSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions) -{ - FIXME("%s %s %s %08x %08lx %08lx\n", debugstr_a(szPackagePath), - debugstr_a(szScriptfilePath), debugstr_a(szTransforms), - lgidLanguage, dwPlatform, dwOptions); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiAdvertiseProductExW( LPCWSTR szPackagePath, LPCWSTR szScriptfilePath, - LPCWSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions) -{ - FIXME("%s %s %s %08x %08lx %08lx\n", debugstr_w(szPackagePath), - debugstr_w(szScriptfilePath), debugstr_w(szTransforms), - lgidLanguage, dwPlatform, dwOptions); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiInstallProductA(LPCSTR szPackagePath, LPCSTR szCommandLine) -{ - LPWSTR szwPath = NULL, szwCommand = NULL; - UINT r = ERROR_OUTOFMEMORY; - - TRACE("%s %s\n",debugstr_a(szPackagePath), debugstr_a(szCommandLine)); - - if( szPackagePath ) - { - szwPath = strdupAtoW( szPackagePath ); - if( !szwPath ) - goto end; - } - - if( szCommandLine ) - { - szwCommand = strdupAtoW( szCommandLine ); - if( !szwCommand ) - goto end; - } - - r = MsiInstallProductW( szwPath, szwCommand ); - -end: - HeapFree( GetProcessHeap(), 0, szwPath ); - HeapFree( GetProcessHeap(), 0, szwCommand ); - - return r; -} - -UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine) -{ - MSIPACKAGE *package = NULL; - UINT r; - MSIHANDLE handle; - - FIXME("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine)); - - r = MsiVerifyPackageW(szPackagePath); - if (r != ERROR_SUCCESS) - return r; - - r = MSI_OpenPackageW(szPackagePath,&package); - if (r != ERROR_SUCCESS) - return r; - - handle = alloc_msihandle( &package->hdr ); - - r = ACTION_DoTopLevelINSTALL(package, szPackagePath, szCommandLine); - - MsiCloseHandle(handle); - msiobj_release( &package->hdr ); - return r; -} - -UINT WINAPI MsiReinstallProductA(LPCSTR szProduct, DWORD dwReinstallMode) -{ - FIXME("%s %08lx\n", debugstr_a(szProduct), dwReinstallMode); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiReinstallProductW(LPCWSTR szProduct, DWORD dwReinstallMode) -{ - FIXME("%s %08lx\n", debugstr_w(szProduct), dwReinstallMode); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiApplyPatchA(LPCSTR szPatchPackage, LPCSTR szInstallPackage, - INSTALLTYPE eInstallType, LPCSTR szCommandLine) -{ - FIXME("%s %s %d %s\n", debugstr_a(szPatchPackage), debugstr_a(szInstallPackage), - eInstallType, debugstr_a(szCommandLine)); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szInstallPackage, - INSTALLTYPE eInstallType, LPCWSTR szCommandLine) -{ - FIXME("%s %s %d %s\n", debugstr_w(szPatchPackage), debugstr_w(szInstallPackage), - eInstallType, debugstr_w(szCommandLine)); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel, - INSTALLSTATE eInstallState, LPCWSTR szCommandLine) -{ - MSIHANDLE handle = -1; - MSIPACKAGE* package; - UINT rc; - HKEY hkey=0,hkey1=0; - DWORD sz; - static const WCHAR szSouceList[] = { - 'S','o','u','r','c','e','L','i','s','t',0}; - static const WCHAR szLUS[] = { - 'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0}; - WCHAR sourcepath[0x200]; - static const WCHAR szInstalled[] = { - ' ','I','n','s','t','a','l','l','e','d','=','1',0}; - LPWSTR commandline; - - FIXME("%s %d %d %s\n",debugstr_w(szProduct), iInstallLevel, eInstallState, - debugstr_w(szCommandLine)); - - if (eInstallState != INSTALLSTATE_LOCAL && - eInstallState != INSTALLSTATE_DEFAULT) - { - FIXME("Not implemented for anything other than local installs\n"); - return ERROR_CALL_NOT_IMPLEMENTED; - } - - rc = MSIREG_OpenUserProductsKey(szProduct,&hkey,FALSE); - if (rc != ERROR_SUCCESS) - goto end; - - rc = RegOpenKeyW(hkey,szSouceList,&hkey1); - if (rc != ERROR_SUCCESS) - goto end; - - sz = sizeof(sourcepath); - rc = RegQueryValueExW(hkey1, szLUS, NULL, NULL,(LPBYTE)sourcepath, &sz); - if (rc != ERROR_SUCCESS) - goto end; - - RegCloseKey(hkey1); - /* - * ok 1, we need to find the msi file for this product. - * 2, find the source dir for the files - * 3, do the configure/install. - * 4, cleanupany runonce entry. - */ - - rc = MsiOpenProductW(szProduct,&handle); - if (rc != ERROR_SUCCESS) - goto end; - - package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE); - if (!package) - { - rc = ERROR_INVALID_HANDLE; - goto end; - } - - sz = lstrlenW(szInstalled); - - if (szCommandLine) - sz += lstrlenW(szCommandLine); - - commandline = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR)); - - if (szCommandLine) - lstrcpyW(commandline,szCommandLine); - else - commandline[0] = 0; - - if (MsiQueryProductStateW(szProduct) != INSTALLSTATE_UNKNOWN) - lstrcatW(commandline,szInstalled); - - rc = ACTION_DoTopLevelINSTALL(package, sourcepath, commandline); - - msiobj_release( &package->hdr ); - - HeapFree(GetProcessHeap(),0,commandline); -end: - RegCloseKey(hkey); - if (handle != -1) - MsiCloseHandle(handle); - - return rc; -} - -UINT WINAPI MsiConfigureProductExA(LPCSTR szProduct, int iInstallLevel, - INSTALLSTATE eInstallState, LPCSTR szCommandLine) -{ - LPWSTR szwProduct = NULL; - LPWSTR szwCommandLine = NULL; - UINT r = ERROR_OUTOFMEMORY; - - if( szProduct ) - { - szwProduct = strdupAtoW( szProduct ); - if( !szwProduct ) - goto end; - } - - if( szCommandLine) - { - szwCommandLine = strdupAtoW( szCommandLine ); - if( !szwCommandLine) - goto end; - } - - r = MsiConfigureProductExW( szwProduct, iInstallLevel, eInstallState, - szwCommandLine ); -end: - HeapFree( GetProcessHeap(), 0, szwProduct ); - HeapFree( GetProcessHeap(), 0, szwCommandLine); - - return r; -} - -UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel, - INSTALLSTATE eInstallState) -{ - LPWSTR szwProduct = NULL; - UINT r; - - TRACE("%s %d %d\n",debugstr_a(szProduct), iInstallLevel, eInstallState); - - if( szProduct ) - { - szwProduct = strdupAtoW( szProduct ); - if( !szwProduct ) - return ERROR_OUTOFMEMORY; - } - - r = MsiConfigureProductW( szwProduct, iInstallLevel, eInstallState ); - HeapFree( GetProcessHeap(), 0, szwProduct ); - - return r; -} - -UINT WINAPI MsiConfigureProductW(LPCWSTR szProduct, int iInstallLevel, - INSTALLSTATE eInstallState) -{ - FIXME("%s %d %d\n", debugstr_w(szProduct), iInstallLevel, eInstallState); - - return MsiConfigureProductExW(szProduct, iInstallLevel, eInstallState, NULL); -} - -UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer) -{ - LPWSTR szwComponent = NULL; - UINT r; - WCHAR szwBuffer[GUID_SIZE]; - - TRACE("%s %s\n",debugstr_a(szComponent), debugstr_a(szBuffer)); - - if( szComponent ) - { - szwComponent = strdupAtoW( szComponent ); - if( !szwComponent ) - return ERROR_OUTOFMEMORY; - } - - r = MsiGetProductCodeW( szwComponent, szwBuffer ); - - if( ERROR_SUCCESS == r ) - WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, GUID_SIZE, NULL, NULL); - - HeapFree( GetProcessHeap(), 0, szwComponent ); - - return r; -} - -UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer) -{ - UINT rc; - HKEY hkey; - WCHAR szSquished[GUID_SIZE]; - DWORD sz = GUID_SIZE; - static const WCHAR szPermKey[] = - { '0','0','0','0','0','0','0','0','0','0','0','0', - '0','0','0','0','0','0','0', '0','0','0','0','0', - '0','0','0','0','0','0','0','0',0}; - - TRACE("%s %p\n",debugstr_w(szComponent), szBuffer); - - if (NULL == szComponent) - return ERROR_INVALID_PARAMETER; - - rc = MSIREG_OpenComponentsKey( szComponent, &hkey, FALSE); - if (rc != ERROR_SUCCESS) - return ERROR_UNKNOWN_COMPONENT; - - rc = RegEnumValueW(hkey, 0, szSquished, &sz, NULL, NULL, NULL, NULL); - if (rc == ERROR_SUCCESS && strcmpW(szSquished,szPermKey)==0) - { - sz = GUID_SIZE; - rc = RegEnumValueW(hkey, 1, szSquished, &sz, NULL, NULL, NULL, NULL); - } - - RegCloseKey(hkey); - - if (rc != ERROR_SUCCESS) - return ERROR_INSTALL_FAILURE; - - unsquash_guid(szSquished, szBuffer); - return ERROR_SUCCESS; -} - -UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute, - LPSTR szBuffer, DWORD *pcchValueBuf) -{ - LPWSTR szwProduct = NULL, szwAttribute = NULL, szwBuffer = NULL; - UINT r = ERROR_OUTOFMEMORY; - - TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szAttribute), - szBuffer, pcchValueBuf); - - if( szProduct ) - { - szwProduct = strdupAtoW( szProduct ); - if( !szwProduct ) - goto end; - } - - if( szAttribute ) - { - szwAttribute = strdupAtoW( szAttribute ); - if( !szwAttribute ) - goto end; - } - - if( szBuffer ) - { - szwBuffer = HeapAlloc( GetProcessHeap(), 0, (*pcchValueBuf) * sizeof(WCHAR) ); - if( !szwBuffer ) - goto end; - } - - r = MsiGetProductInfoW( szwProduct, szwAttribute, szwBuffer, pcchValueBuf ); - - if( ERROR_SUCCESS == r ) - WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, *pcchValueBuf, NULL, NULL); - -end: - HeapFree( GetProcessHeap(), 0, szwProduct ); - HeapFree( GetProcessHeap(), 0, szwAttribute ); - HeapFree( GetProcessHeap(), 0, szwBuffer ); - - return r; -} - -UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, - LPWSTR szBuffer, DWORD *pcchValueBuf) -{ - MSIHANDLE hProduct; - UINT r; - static const WCHAR szPackageCode[] = - {'P','a','c','k','a','g','e','C','o','d','e',0}; - static const WCHAR szVersionString[] = - {'V','e','r','s','i','o','n','S','t','r','i','n','g',0}; - static const WCHAR szProductVersion[] = - {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0}; - static const WCHAR szAssignmentType[] = - {'A','s','s','i','g','n','m','e','n','t','T','y','p','e',0}; - - FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szAttribute), - szBuffer, pcchValueBuf); - - if (NULL != szBuffer && NULL == pcchValueBuf) - return ERROR_INVALID_PARAMETER; - if (NULL == szProduct || NULL == szAttribute) - return ERROR_INVALID_PARAMETER; - - /* check for special properties */ - if (strcmpW(szAttribute, szPackageCode)==0) - { - HKEY hkey; - WCHAR squished[GUID_SIZE]; - WCHAR package[200]; - DWORD sz = sizeof(squished); - - r = MSIREG_OpenUserProductsKey(szProduct, &hkey, FALSE); - if (r != ERROR_SUCCESS) - return ERROR_UNKNOWN_PRODUCT; - - r = RegQueryValueExW(hkey, szPackageCode, NULL, NULL, - (LPBYTE)squished, &sz); - if (r != ERROR_SUCCESS) - { - RegCloseKey(hkey); - return ERROR_UNKNOWN_PRODUCT; - } - - unsquash_guid(squished, package); - *pcchValueBuf = strlenW(package); - if (strlenW(package) > *pcchValueBuf) - { - RegCloseKey(hkey); - return ERROR_MORE_DATA; - } - else - strcpyW(szBuffer, package); - - RegCloseKey(hkey); - r = ERROR_SUCCESS; - } - else if (strcmpW(szAttribute, szVersionString)==0) - { - r = MsiOpenProductW(szProduct, &hProduct); - if (ERROR_SUCCESS != r) - return r; - - r = MsiGetPropertyW(hProduct, szProductVersion, szBuffer, pcchValueBuf); - MsiCloseHandle(hProduct); - } - else if (strcmpW(szAttribute, szAssignmentType)==0) - { - FIXME("0 (zero) if advertised, 1(one) if per machine.\n"); - if (szBuffer) - szBuffer[0] = 1; - r = ERROR_SUCCESS; - } - else - { - r = MsiOpenProductW(szProduct, &hProduct); - if (ERROR_SUCCESS != r) - return r; - - r = MsiGetPropertyW(hProduct, szAttribute, szBuffer, pcchValueBuf); - MsiCloseHandle(hProduct); - } - - return r; -} - -UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes) -{ - LPWSTR szwLogFile = NULL; - UINT r; - - TRACE("%08lx %s %08lx\n", dwLogMode, debugstr_a(szLogFile), attributes); - - if( szLogFile ) - { - szwLogFile = strdupAtoW( szLogFile ); - if( !szwLogFile ) - return ERROR_OUTOFMEMORY; - } - r = MsiEnableLogW( dwLogMode, szwLogFile, attributes ); - HeapFree( GetProcessHeap(), 0, szwLogFile ); - return r; -} - -UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes) -{ - HANDLE file = INVALID_HANDLE_VALUE; - - TRACE("%08lx %s %08lx\n", dwLogMode, debugstr_w(szLogFile), attributes); - - lstrcpyW(gszLogFile,szLogFile); - if (!(attributes & INSTALLLOGATTRIBUTES_APPEND)) - DeleteFileW(szLogFile); - file = CreateFileW(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL); - if (file != INVALID_HANDLE_VALUE) - CloseHandle(file); - else - ERR("Unable to enable log %s\n",debugstr_w(szLogFile)); - - return ERROR_SUCCESS; -} - -INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct) -{ - LPWSTR szwProduct = NULL; - INSTALLSTATE r; - - if( szProduct ) - { - szwProduct = strdupAtoW( szProduct ); - if( !szwProduct ) - return ERROR_OUTOFMEMORY; - } - r = MsiQueryProductStateW( szwProduct ); - HeapFree( GetProcessHeap(), 0, szwProduct ); - return r; -} - -INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct) -{ - UINT rc; - INSTALLSTATE rrc = INSTALLSTATE_UNKNOWN; - HKEY hkey = 0; - static const WCHAR szWindowsInstaller[] = { - 'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0 }; - DWORD sz; - - TRACE("%s\n", debugstr_w(szProduct)); - - rc = MSIREG_OpenUserProductsKey(szProduct,&hkey,FALSE); - if (rc != ERROR_SUCCESS) - goto end; - - RegCloseKey(hkey); - - rc = MSIREG_OpenUninstallKey(szProduct,&hkey,FALSE); - if (rc != ERROR_SUCCESS) - goto end; - - sz = sizeof(rrc); - rc = RegQueryValueExW(hkey,szWindowsInstaller,NULL,NULL,(LPVOID)&rrc, &sz); - if (rc != ERROR_SUCCESS) - goto end; - - switch (rrc) - { - case 1: - /* default */ - rrc = INSTALLSTATE_DEFAULT; - break; - default: - FIXME("Unknown install state read from registry (%i)\n",rrc); - rrc = INSTALLSTATE_UNKNOWN; - break; - } -end: - RegCloseKey(hkey); - return rrc; -} - -INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd) -{ - INSTALLUILEVEL old = gUILevel; - HWND oldwnd = gUIhwnd; - - TRACE("%08x %p\n", dwUILevel, phWnd); - - gUILevel = dwUILevel; - if (phWnd) - { - gUIhwnd = *phWnd; - *phWnd = oldwnd; - } - return old; -} - -INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler, - DWORD dwMessageFilter, LPVOID pvContext) -{ - INSTALLUI_HANDLERA prev = gUIHandlerA; - - TRACE("%p %lx %p\n",puiHandler, dwMessageFilter,pvContext); - gUIHandlerA = puiHandler; - gUIFilter = dwMessageFilter; - gUIContext = pvContext; - - return prev; -} - -INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler, - DWORD dwMessageFilter, LPVOID pvContext) -{ - INSTALLUI_HANDLERW prev = gUIHandlerW; - - TRACE("%p %lx %p\n",puiHandler,dwMessageFilter,pvContext); - gUIHandlerW = puiHandler; - gUIFilter = dwMessageFilter; - gUIContext = pvContext; - - return prev; -} - -/****************************************************************** - * MsiLoadStringW [MSI.@] - * - * Loads a string from MSI's string resources. - * - * PARAMS - * - * handle [I] only -1 is handled currently - * id [I] id of the string to be loaded - * lpBuffer [O] buffer for the string to be written to - * nBufferMax [I] maximum size of the buffer in characters - * lang [I] the preferred language for the string - * - * RETURNS - * - * If successful, this function returns the language id of the string loaded - * If the function fails, the function returns zero. - * - * NOTES - * - * The type of the first parameter is unknown. LoadString's prototype - * suggests that it might be a module handle. I have made it an MSI handle - * for starters, as -1 is an invalid MSI handle, but not an invalid module - * handle. Maybe strings can be stored in an MSI database somehow. - */ -LANGID WINAPI MsiLoadStringW( MSIHANDLE handle, UINT id, LPWSTR lpBuffer, - int nBufferMax, LANGID lang ) -{ - HRSRC hres; - HGLOBAL hResData; - LPWSTR p; - DWORD i, len; - - TRACE("%ld %u %p %d %d\n", handle, id, lpBuffer, nBufferMax, lang); - - if( handle != -1 ) - FIXME("don't know how to deal with handle = %08lx\n", handle); - - if( !lang ) - lang = GetUserDefaultLangID(); - - hres = FindResourceExW( msi_hInstance, (LPCWSTR) RT_STRING, - (LPWSTR)1, lang ); - if( !hres ) - return 0; - hResData = LoadResource( msi_hInstance, hres ); - if( !hResData ) - return 0; - p = LockResource( hResData ); - if( !p ) - return 0; - - for (i = 0; i < (id&0xf); i++) - p += *p + 1; - len = *p; - - if( nBufferMax <= len ) - return 0; - - memcpy( lpBuffer, p+1, len * sizeof(WCHAR)); - lpBuffer[ len ] = 0; - - TRACE("found -> %s\n", debugstr_w(lpBuffer)); - - return lang; -} - -LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer, - int nBufferMax, LANGID lang ) -{ - LPWSTR bufW; - LANGID r; - DWORD len; - - bufW = HeapAlloc(GetProcessHeap(), 0, nBufferMax*sizeof(WCHAR)); - r = MsiLoadStringW(handle, id, bufW, nBufferMax, lang); - if( r ) - { - len = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL ); - if( len <= nBufferMax ) - WideCharToMultiByte( CP_ACP, 0, bufW, -1, - lpBuffer, nBufferMax, NULL, NULL ); - else - r = 0; - } - HeapFree(GetProcessHeap(), 0, bufW); - return r; -} - -INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf, - DWORD *pcchBuf) -{ - FIXME("%s %p %08lx\n", debugstr_a(szComponent), lpPathBuf, *pcchBuf); - return INSTALLSTATE_UNKNOWN; -} - -INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPSTR lpPathBuf, - DWORD *pcchBuf) -{ - FIXME("%s %p %08lx\n", debugstr_w(szComponent), lpPathBuf, *pcchBuf); - return INSTALLSTATE_UNKNOWN; -} - -UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType, - WORD wLanguageId, DWORD f) -{ - FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_a(lpText),debugstr_a(lpCaption), - uType,wLanguageId,f); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType, - WORD wLanguageId, DWORD f) -{ - FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_w(lpText),debugstr_w(lpCaption), - uType,wLanguageId,f); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext, - DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf, - DWORD* pcchPathBuf ) -{ - FIXME("%s %s %08lx %08lx %p %p\n", debugstr_a(szAssemblyName), - debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf, - pcchPathBuf); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext, - DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf, - DWORD* pcchPathBuf ) -{ - FIXME("%s %s %08lx %08lx %p %p\n", debugstr_w(szAssemblyName), - debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf, - pcchPathBuf); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor, - LPSTR szPath, DWORD *pcchPath, DWORD *pcchArgs ) -{ - FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs ); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor, - LPWSTR szPath, DWORD *pcchPath, DWORD *pcchArgs ) -{ - FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs ); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR szSignedObjectPath, - DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData, - DWORD* pcbHashData) -{ - FIXME("%s %08lx %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags, - ppcCertContext, pbHashData, pcbHashData); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR szSignedObjectPath, - DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData, - DWORD* pcbHashData) -{ - FIXME("%s %08lx %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags, - ppcCertContext, pbHashData, pcbHashData); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiGetProductPropertyA( MSIHANDLE hProduct, LPCSTR szProperty, - LPSTR szValue, DWORD *pccbValue ) -{ - FIXME("%ld %s %p %p\n", hProduct, debugstr_a(szProperty), szValue, pccbValue); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiGetProductPropertyW( MSIHANDLE hProduct, LPCWSTR szProperty, - LPWSTR szValue, DWORD *pccbValue ) -{ - FIXME("%ld %s %p %p\n", hProduct, debugstr_w(szProperty), szValue, pccbValue); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage ) -{ - UINT r; - LPWSTR szPack = NULL; - - TRACE("%s\n", debugstr_a(szPackage) ); - - if( szPackage ) - { - szPack = strdupAtoW( szPackage ); - if( !szPack ) - return ERROR_OUTOFMEMORY; - } - - r = MsiVerifyPackageW( szPack ); - - HeapFree( GetProcessHeap(), 0, szPack ); - - return r; -} - -UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage ) -{ - MSIHANDLE handle; - UINT r; - - TRACE("%s\n", debugstr_w(szPackage) ); - - r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle ); - MsiCloseHandle( handle ); - - return r; -} - -INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent, - LPSTR lpPathBuf, DWORD* pcchBuf) -{ - LPWSTR szwProduct = NULL, szwComponent = NULL, lpwPathBuf= NULL; - INSTALLSTATE rc; - UINT incoming_len; - - if( szProduct ) - { - szwProduct = strdupAtoW( szProduct ); - if( !szwProduct) - return ERROR_OUTOFMEMORY; - } - - if( szComponent ) - { - szwComponent = strdupAtoW( szComponent ); - if( !szwComponent ) - { - HeapFree( GetProcessHeap(), 0, szwProduct); - return ERROR_OUTOFMEMORY; - } - } - - if( pcchBuf && *pcchBuf > 0 ) - lpwPathBuf = HeapAlloc( GetProcessHeap(), 0, *pcchBuf * sizeof(WCHAR)); - else - lpwPathBuf = NULL; - - incoming_len = *pcchBuf; - rc = MsiGetComponentPathW(szwProduct, szwComponent, lpwPathBuf, pcchBuf); - - HeapFree( GetProcessHeap(), 0, szwProduct); - HeapFree( GetProcessHeap(), 0, szwComponent); - if (lpwPathBuf) - { - if (rc != INSTALLSTATE_UNKNOWN) - WideCharToMultiByte(CP_ACP, 0, lpwPathBuf, incoming_len, - lpPathBuf, incoming_len, NULL, NULL); - HeapFree( GetProcessHeap(), 0, lpwPathBuf); - } - - return rc; -} - -INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent, - LPWSTR lpPathBuf, DWORD* pcchBuf) -{ - WCHAR squished_pc[GUID_SIZE]; - UINT rc; - INSTALLSTATE rrc = INSTALLSTATE_UNKNOWN; - HKEY hkey = 0; - LPWSTR path = NULL; - DWORD sz, type; - - TRACE("%s %s %p %p\n", debugstr_w(szProduct), - debugstr_w(szComponent), lpPathBuf, pcchBuf); - - if( lpPathBuf && !pcchBuf ) - return INSTALLSTATE_INVALIDARG; - - squash_guid(szProduct,squished_pc); - - rc = MSIREG_OpenProductsKey( szProduct, &hkey, FALSE); - if( rc != ERROR_SUCCESS ) - goto end; - - RegCloseKey(hkey); - - rc = MSIREG_OpenComponentsKey( szComponent, &hkey, FALSE); - if( rc != ERROR_SUCCESS ) - goto end; - - sz = 0; - type = 0; - rc = RegQueryValueExW( hkey, squished_pc, NULL, &type, NULL, &sz ); - if( rc != ERROR_SUCCESS ) - goto end; - if( type != REG_SZ ) - goto end; - - sz += sizeof(WCHAR); - path = HeapAlloc( GetProcessHeap(), 0, sz ); - if( !path ) - goto end; - - rc = RegQueryValueExW( hkey, squished_pc, NULL, NULL, (LPVOID) path, &sz ); - if( rc != ERROR_SUCCESS ) - goto end; - - TRACE("found path of (%s:%s)(%s)\n", debugstr_w(szComponent), - debugstr_w(szProduct), debugstr_w(path)); - - if (path[0]=='0') - { - FIXME("Registry entry.. check entry\n"); - rrc = INSTALLSTATE_LOCAL; - } - else - { - /* PROBABLY a file */ - if ( GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES ) - rrc = INSTALLSTATE_LOCAL; - else - rrc = INSTALLSTATE_ABSENT; - } - - if( pcchBuf ) - { - sz = sz / sizeof(WCHAR); - if( *pcchBuf >= sz ) - lstrcpyW( lpPathBuf, path ); - *pcchBuf = sz; - } - -end: - HeapFree(GetProcessHeap(), 0, path ); - RegCloseKey(hkey); - return rrc; -} - -/****************************************************************** - * MsiQueryFeatureStateA [MSI.@] - */ -INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature) -{ - INSTALLSTATE rc; - LPWSTR szwProduct= NULL; - LPWSTR szwFeature= NULL; - - if( szProduct ) - { - szwProduct = strdupAtoW( szProduct ); - if( !szwProduct) - return ERROR_OUTOFMEMORY; - } - - if( szFeature ) - { - szwFeature = strdupAtoW( szFeature ); - if( !szwFeature) - { - HeapFree( GetProcessHeap(), 0, szwProduct); - return ERROR_OUTOFMEMORY; - } - } - - rc = MsiQueryFeatureStateW(szwProduct, szwFeature); - - HeapFree( GetProcessHeap(), 0, szwProduct); - HeapFree( GetProcessHeap(), 0, szwFeature); - - return rc; -} - -/****************************************************************** - * MsiQueryFeatureStateW [MSI.@] - * - * This does not verify that the Feature is functional. So i am only going to - * check the existence of the key in the registry. This should tell me if it is - * installed. - */ -INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature) -{ - UINT rc; - DWORD sz = 0; - HKEY hkey; - - TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature)); - - rc = MSIREG_OpenFeaturesKey(szProduct, &hkey, FALSE); - if (rc != ERROR_SUCCESS) - return INSTALLSTATE_UNKNOWN; - - rc = RegQueryValueExW( hkey, szFeature, NULL, NULL, NULL, &sz); - RegCloseKey(hkey); - - if (rc == ERROR_SUCCESS) - return INSTALLSTATE_LOCAL; - else - return INSTALLSTATE_ABSENT; -} - -/****************************************************************** - * MsiGetFileVersionA [MSI.@] - */ -UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf, - DWORD* pcchVersionBuf, LPSTR lpLangBuf, DWORD* pcchLangBuf) -{ - LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL; - UINT ret = ERROR_OUTOFMEMORY; - - if( szFilePath ) - { - szwFilePath = strdupAtoW( szFilePath ); - if( !szwFilePath ) - goto end; - } - - if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf ) - { - lpwVersionBuff = HeapAlloc(GetProcessHeap(), 0, *pcchVersionBuf*sizeof(WCHAR)); - if( !lpwVersionBuff ) - goto end; - } - - if( lpLangBuf && pcchLangBuf && *pcchLangBuf ) - { - lpwLangBuff = HeapAlloc(GetProcessHeap(), 0, *pcchVersionBuf*sizeof(WCHAR)); - if( !lpwLangBuff ) - goto end; - } - - ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf, - lpwLangBuff, pcchLangBuf); - - if( lpwVersionBuff ) - WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1, - lpVersionBuf, *pcchVersionBuf, NULL, NULL); - if( lpwLangBuff ) - WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1, - lpLangBuf, *pcchLangBuf, NULL, NULL); - -end: - HeapFree(GetProcessHeap(), 0, szwFilePath); - HeapFree(GetProcessHeap(), 0, lpwVersionBuff); - HeapFree(GetProcessHeap(), 0, lpwLangBuff); - - return ret; -} - -/****************************************************************** - * MsiGetFileVersionW [MSI.@] - */ -UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, - DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf) -{ - static const WCHAR szVersionResource[] = {'\\',0}; - static const WCHAR szVersionFormat[] = { - '%','d','.','%','d','.','%','d','.','%','d',0}; - static const WCHAR szLangFormat[] = {'%','d',0}; - UINT ret = 0; - DWORD dwVerLen; - LPVOID lpVer = NULL; - VS_FIXEDFILEINFO *ffi; - UINT puLen; - WCHAR tmp[32]; - - TRACE("%s %p %ld %p %ld\n", debugstr_w(szFilePath), - lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0, - lpLangBuf, pcchLangBuf?*pcchLangBuf:0); - - dwVerLen = GetFileVersionInfoSizeW((LPWSTR)szFilePath, NULL); - if( !dwVerLen ) - return GetLastError(); - - lpVer = HeapAlloc(GetProcessHeap(), 0, dwVerLen); - if( !lpVer ) - { - ret = ERROR_OUTOFMEMORY; - goto end; - } - - if( !GetFileVersionInfoW((LPWSTR)szFilePath, 0, dwVerLen, lpVer) ) - { - ret = GetLastError(); - goto end; - } - if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf ) - { - if( VerQueryValueW(lpVer, (LPWSTR)szVersionResource, (LPVOID*)&ffi, &puLen) && - (puLen > 0) ) - { - wsprintfW(tmp, szVersionFormat, - HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS), - HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS)); - lstrcpynW(lpVersionBuf, tmp, *pcchVersionBuf); - *pcchVersionBuf = lstrlenW(lpVersionBuf); - } - else - { - *lpVersionBuf = 0; - *pcchVersionBuf = 0; - } - } - - if( lpLangBuf && pcchLangBuf && *pcchLangBuf ) - { - DWORD lang = GetUserDefaultLangID(); - - FIXME("Retrieve language from file\n"); - wsprintfW(tmp, szLangFormat, lang); - lstrcpynW(lpLangBuf, tmp, *pcchLangBuf); - *pcchLangBuf = lstrlenW(lpLangBuf); - } - -end: - HeapFree(GetProcessHeap(), 0, lpVer); - return ret; -} - - -/****************************************************************** - * DllMain - */ -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - switch(fdwReason) - { - case DLL_PROCESS_ATTACH: - msi_hInstance = hinstDLL; - DisableThreadLibraryCalls(hinstDLL); - msi_dialog_register_class(); - break; - case DLL_PROCESS_DETACH: - msi_dialog_unregister_class(); - /* FIXME: Cleanup */ - break; - } - return TRUE; -} - -typedef struct tagIClassFactoryImpl -{ - IClassFactoryVtbl *lpVtbl; -} IClassFactoryImpl; - -static HRESULT WINAPI MsiCF_QueryInterface(LPCLASSFACTORY iface, - REFIID riid,LPVOID *ppobj) -{ - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - FIXME("%p %s %p\n",This,debugstr_guid(riid),ppobj); - return E_NOINTERFACE; -} - -static ULONG WINAPI MsiCF_AddRef(LPCLASSFACTORY iface) -{ - return 2; -} - -static ULONG WINAPI MsiCF_Release(LPCLASSFACTORY iface) -{ - return 1; -} - -static HRESULT WINAPI MsiCF_CreateInstance(LPCLASSFACTORY iface, - LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj) -{ - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - - FIXME("%p %p %s %p\n", This, pOuter, debugstr_guid(riid), ppobj); - return E_FAIL; -} - -static HRESULT WINAPI MsiCF_LockServer(LPCLASSFACTORY iface, BOOL dolock) -{ - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - - FIXME("%p %d\n", This, dolock); - return S_OK; -} - -static IClassFactoryVtbl MsiCF_Vtbl = -{ - MsiCF_QueryInterface, - MsiCF_AddRef, - MsiCF_Release, - MsiCF_CreateInstance, - MsiCF_LockServer -}; - -static IClassFactoryImpl Msi_CF = { &MsiCF_Vtbl }; - -/****************************************************************** - * DllGetClassObject [MSI.@] - */ -HRESULT WINAPI MSI_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) -{ - TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); - - if( IsEqualCLSID (rclsid, &CLSID_IMsiServer) || - IsEqualCLSID (rclsid, &CLSID_IMsiServerMessage) || - IsEqualCLSID (rclsid, &CLSID_IMsiServerX1) || - IsEqualCLSID (rclsid, &CLSID_IMsiServerX2) || - IsEqualCLSID (rclsid, &CLSID_IMsiServerX3) ) - { - *ppv = (LPVOID) &Msi_CF; - return S_OK; - } - return CLASS_E_CLASSNOTAVAILABLE; -} - -/****************************************************************** - * DllGetVersion [MSI.@] - */ -HRESULT WINAPI MSI_DllGetVersion(DLLVERSIONINFO *pdvi) -{ - TRACE("%p\n",pdvi); - - if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) - return E_INVALIDARG; - - pdvi->dwMajorVersion = MSI_MAJORVERSION; - pdvi->dwMinorVersion = MSI_MINORVERSION; - pdvi->dwBuildNumber = MSI_BUILDNUMBER; - pdvi->dwPlatformID = 1; - - return S_OK; -} - -/****************************************************************** - * DllCanUnloadNow [MSI.@] - */ -BOOL WINAPI MSI_DllCanUnloadNow(void) -{ - return S_FALSE; -} - -UINT WINAPI MsiGetFeatureUsageW(LPCWSTR szProduct, LPCWSTR szFeature, - DWORD* pdwUseCount, WORD* pwDateUsed) -{ - FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature), - pdwUseCount, pwDateUsed); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiGetFeatureUsageA(LPCSTR szProduct, LPCSTR szFeature, - DWORD* pdwUseCount, WORD* pwDateUsed) -{ - FIXME("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature), - pdwUseCount, pwDateUsed); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -INSTALLSTATE WINAPI MsiUseFeatureExW(LPCWSTR szProduct, LPCWSTR szFeature, - DWORD dwInstallMode, DWORD dwReserved) -{ - FIXME("%s %s %li %li\n", debugstr_w(szProduct), debugstr_w(szFeature), - dwInstallMode, dwReserved); - - /* - * Polls all the components of the feature to find install state and then - * writes: - * Software\\Microsoft\\Windows\\CurrentVersion\\ - * Installer\\Products\\<squishguid>\\<feature> - * "Usage"=dword:........ - */ - - return INSTALLSTATE_LOCAL; -} - -/*********************************************************************** - * MsiUseFeatureExA [MSI.@] - */ -INSTALLSTATE WINAPI MsiUseFeatureExA(LPCSTR szProduct, LPCSTR szFeature, - DWORD dwInstallMode, DWORD dwReserved) -{ - FIXME("%s %s %li %li\n", debugstr_a(szProduct), debugstr_a(szFeature), - dwInstallMode, dwReserved); - - return INSTALLSTATE_LOCAL; -} - -INSTALLSTATE WINAPI MsiUseFeatureW(LPCWSTR szProduct, LPCWSTR szFeature) -{ - FIXME("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature)); - - return INSTALLSTATE_LOCAL; -} - -INSTALLSTATE WINAPI MsiUseFeatureA(LPCSTR szProduct, LPCSTR szFeature) -{ - FIXME("%s %s\n", debugstr_a(szProduct), debugstr_a(szFeature)); - - return INSTALLSTATE_LOCAL; -} - -UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent, - LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR szProduct, - DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf, - DWORD* pcchPathBuf) -{ - HKEY hkey; - UINT rc; - LPWSTR info; - DWORD sz; - LPWSTR product = NULL; - LPWSTR component = NULL; - LPWSTR ptr; - GUID clsid; - - TRACE("%s %s %li %s %li %li %p %p\n", debugstr_w(szComponent), - debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct), - Unused1, Unused2, lpPathBuf, pcchPathBuf); - - rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE); - if (rc != ERROR_SUCCESS) - return ERROR_INDEX_ABSENT; - - sz = 0; - rc = RegQueryValueExW( hkey, szQualifier, NULL, NULL, NULL, &sz); - if (sz <= 0) - { - RegCloseKey(hkey); - return ERROR_INDEX_ABSENT; - } - - info = HeapAlloc(GetProcessHeap(),0,sz); - rc = RegQueryValueExW( hkey, szQualifier, NULL, NULL, (LPBYTE)info, &sz); - if (rc != ERROR_SUCCESS) - { - RegCloseKey(hkey); - HeapFree(GetProcessHeap(),0,info); - return ERROR_INDEX_ABSENT; - } - - /* find the component */ - ptr = strchrW(&info[20],'>'); - if (ptr) - ptr++; - else - { - RegCloseKey(hkey); - HeapFree(GetProcessHeap(),0,info); - return ERROR_INDEX_ABSENT; - } - - if (!szProduct) - { - decode_base85_guid(info,&clsid); - StringFromCLSID(&clsid, &product); - } - decode_base85_guid(ptr,&clsid); - StringFromCLSID(&clsid, &component); - - if (!szProduct) - rc = MsiGetComponentPathW(product, component, lpPathBuf, pcchPathBuf); - else - rc = MsiGetComponentPathW(szProduct, component, lpPathBuf, pcchPathBuf); - - RegCloseKey(hkey); - HeapFree(GetProcessHeap(),0,info); - HeapFree(GetProcessHeap(),0,product); - HeapFree(GetProcessHeap(),0,component); - - if (rc == INSTALLSTATE_LOCAL) - return ERROR_SUCCESS; - else - return ERROR_FILE_NOT_FOUND; -} - -/*********************************************************************** - * MsiProvideQualifiedComponentW [MSI.@] - */ -UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent, - LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf, - DWORD* pcchPathBuf) -{ - return MsiProvideQualifiedComponentExW(szComponent, szQualifier, - dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf); -} - -/*********************************************************************** - * MsiProvideQualifiedComponentA [MSI.@] - */ -UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent, - LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf, - DWORD* pcchPathBuf) -{ - LPWSTR szwComponent, szwQualifier, lpwPathBuf; - DWORD pcchwPathBuf; - UINT rc; - - TRACE("%s %s %li %p %p\n",szComponent, szQualifier, - dwInstallMode, lpPathBuf, pcchPathBuf); - - szwComponent= strdupAtoW( szComponent); - szwQualifier= strdupAtoW( szQualifier); - - lpwPathBuf = HeapAlloc(GetProcessHeap(),0,*pcchPathBuf * sizeof(WCHAR)); - - pcchwPathBuf = *pcchPathBuf; - - rc = MsiProvideQualifiedComponentW(szwComponent, szwQualifier, - dwInstallMode, lpwPathBuf, &pcchwPathBuf); - - HeapFree(GetProcessHeap(),0,szwComponent); - HeapFree(GetProcessHeap(),0,szwQualifier); - *pcchPathBuf = WideCharToMultiByte(CP_ACP, 0, lpwPathBuf, pcchwPathBuf, - lpPathBuf, *pcchPathBuf, NULL, NULL); - - HeapFree(GetProcessHeap(),0,lpwPathBuf); - return rc; -} - -USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct, LPWSTR lpUserNameBuf, - DWORD* pcchUserNameBuf, LPWSTR lpOrgNameBuf, - DWORD* pcchOrgNameBuf, LPWSTR lpSerialBuf, DWORD* pcchSerialBuf) -{ - HKEY hkey; - DWORD sz; - UINT rc = ERROR_SUCCESS,rc2 = ERROR_SUCCESS; - static const WCHAR szOwner[] = {'R','e','g','O','w','n','e','r',0}; - static const WCHAR szCompany[] = {'R','e','g','C','o','m','p','a','n','y',0}; - static const WCHAR szSerial[] = {'P','r','o','d','u','c','t','I','D',0}; - - TRACE("%s %p %p %p %p %p %p\n",debugstr_w(szProduct), lpUserNameBuf, - pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf, - pcchSerialBuf); - - rc = MSIREG_OpenUninstallKey(szProduct, &hkey, FALSE); - if (rc != ERROR_SUCCESS) - return USERINFOSTATE_UNKNOWN; - - if (lpUserNameBuf) - { - sz = *lpUserNameBuf * sizeof(WCHAR); - rc = RegQueryValueExW( hkey, szOwner, NULL, NULL, (LPBYTE)lpUserNameBuf, - &sz); - } - if (!lpUserNameBuf && pcchUserNameBuf) - { - sz = 0; - rc = RegQueryValueExW( hkey, szOwner, NULL, NULL, NULL, &sz); - } - - if (pcchUserNameBuf) - *pcchUserNameBuf = sz / sizeof(WCHAR); - - if (lpOrgNameBuf) - { - sz = *pcchOrgNameBuf * sizeof(WCHAR); - rc2 = RegQueryValueExW( hkey, szCompany, NULL, NULL, - (LPBYTE)lpOrgNameBuf, &sz); - } - if (!lpOrgNameBuf && pcchOrgNameBuf) - { - sz = 0; - rc2 = RegQueryValueExW( hkey, szCompany, NULL, NULL, NULL, &sz); - } - - if (pcchOrgNameBuf) - *pcchOrgNameBuf = sz / sizeof(WCHAR); - - if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA && - rc2 != ERROR_SUCCESS && rc2 != ERROR_MORE_DATA) - { - RegCloseKey(hkey); - return USERINFOSTATE_ABSENT; - } - - if (lpSerialBuf) - { - sz = *pcchSerialBuf * sizeof(WCHAR); - RegQueryValueExW( hkey, szSerial, NULL, NULL, (LPBYTE)lpSerialBuf, - &sz); - } - if (!lpSerialBuf && pcchSerialBuf) - { - sz = 0; - rc = RegQueryValueExW( hkey, szSerial, NULL, NULL, NULL, &sz); - } - if (pcchSerialBuf) - *pcchSerialBuf = sz / sizeof(WCHAR); - - RegCloseKey(hkey); - return USERINFOSTATE_PRESENT; -} - -USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct, LPSTR lpUserNameBuf, - DWORD* pcchUserNameBuf, LPSTR lpOrgNameBuf, - DWORD* pcchOrgNameBuf, LPSTR lpSerialBuf, DWORD* pcchSerialBuf) -{ - FIXME("%s %p %p %p %p %p %p\n",debugstr_a(szProduct), lpUserNameBuf, - pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf, - pcchSerialBuf); - - return USERINFOSTATE_UNKNOWN; -} - -UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct) -{ - MSIHANDLE handle; - UINT rc; - MSIPACKAGE *package; - static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0}; - - TRACE("(%s)\n",debugstr_w(szProduct)); - - rc = MsiOpenProductW(szProduct,&handle); - if (rc != ERROR_SUCCESS) - return ERROR_INVALID_PARAMETER; - - package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE); - rc = ACTION_PerformUIAction(package, szFirstRun); - msiobj_release( &package->hdr ); - - MsiCloseHandle(handle); - - return rc; -} - -UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct) -{ - MSIHANDLE handle; - UINT rc; - MSIPACKAGE *package; - static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0}; - - TRACE("(%s)\n",debugstr_a(szProduct)); - - rc = MsiOpenProductA(szProduct,&handle); - if (rc != ERROR_SUCCESS) - return ERROR_INVALID_PARAMETER; - - package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE); - rc = ACTION_PerformUIAction(package, szFirstRun); - msiobj_release( &package->hdr ); - - MsiCloseHandle(handle); - - return rc; -} - -UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved) -{ - WCHAR path[MAX_PATH]; - - if(dwReserved) { - FIXME("Don't know how to handle argument %ld\n", dwReserved); - return ERROR_CALL_NOT_IMPLEMENTED; - } - - if(!GetWindowsDirectoryW(path, MAX_PATH)) { - FIXME("GetWindowsDirectory failed unexpected! Error %ld\n", - GetLastError()); - return ERROR_CALL_NOT_IMPLEMENTED; - } - - strcatW(path, installerW); - - CreateDirectoryW(path, NULL); - - return 0; -} - -UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget, - LPSTR szProductCode, LPSTR szFeatureId, - LPSTR szComponentCode ) -{ - FIXME("\n"); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget, - LPWSTR szProductCode, LPWSTR szFeatureId, - LPWSTR szComponentCode ) -{ - FIXME("\n"); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature, - DWORD dwReinstallMode ) -{ - FIXME("%s %s %li\n", debugstr_w(szProduct), debugstr_w(szFeature), - dwReinstallMode); - return ERROR_SUCCESS; -} - -UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature, - DWORD dwReinstallMode ) -{ - FIXME("%s %s %li\n", debugstr_a(szProduct), debugstr_a(szFeature), - dwReinstallMode); - return ERROR_SUCCESS; -} +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2002,2003,2004,2005 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> + +#define COBJMACROS +#define NONAMELESSUNION + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winnls.h" +#include "shlwapi.h" +#include "wine/debug.h" +#include "msi.h" +#include "msiquery.h" +#include "msipriv.h" +#include "wincrypt.h" +#include "winver.h" +#include "winuser.h" +#include "wine/unicode.h" +#include "action.h" + +UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf); + + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +/* + * The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR, + * which is a problem because LPCTSTR isn't defined when compiling wine. + * To work around this problem, we need to define LPCTSTR as LPCWSTR here, + * and make sure to only use it in W functions. + */ +#define LPCTSTR LPCWSTR + +/* the UI level */ +INSTALLUILEVEL gUILevel = INSTALLUILEVEL_BASIC; +HWND gUIhwnd = 0; +INSTALLUI_HANDLERA gUIHandlerA = NULL; +INSTALLUI_HANDLERW gUIHandlerW = NULL; +DWORD gUIFilter = 0; +LPVOID gUIContext = NULL; +WCHAR gszLogFile[MAX_PATH]; +HINSTANCE msi_hInstance; + +static const WCHAR installerW[] = {'\\','I','n','s','t','a','l','l','e','r',0}; + +UINT WINAPI MsiOpenProductA(LPCSTR szProduct, MSIHANDLE *phProduct) +{ + UINT r; + LPWSTR szwProd = NULL; + + TRACE("%s %p\n",debugstr_a(szProduct), phProduct); + + if( szProduct ) + { + szwProd = strdupAtoW( szProduct ); + if( !szwProd ) + return ERROR_OUTOFMEMORY; + } + + r = MsiOpenProductW( szwProd, phProduct ); + + HeapFree( GetProcessHeap(), 0, szwProd ); + + return r; +} + +UINT WINAPI MsiOpenProductW(LPCWSTR szProduct, MSIHANDLE *phProduct) +{ + static const WCHAR szLocalPackage[] = { + 'L','o','c','a','l','P','a','c','k','a','g','e', 0 + }; + LPWSTR path = NULL; + UINT r; + HKEY hKeyProduct = NULL; + DWORD count, type; + + TRACE("%s %p\n",debugstr_w(szProduct), phProduct); + + r = MSIREG_OpenUninstallKey(szProduct,&hKeyProduct,FALSE); + if( r != ERROR_SUCCESS ) + { + r = ERROR_UNKNOWN_PRODUCT; + goto end; + } + + /* find the size of the path */ + type = count = 0; + r = RegQueryValueExW( hKeyProduct, szLocalPackage, + NULL, &type, NULL, &count ); + if( r != ERROR_SUCCESS ) + { + r = ERROR_UNKNOWN_PRODUCT; + goto end; + } + + /* now alloc and fetch the path of the database to open */ + path = HeapAlloc( GetProcessHeap(), 0, count ); + if( !path ) + goto end; + + r = RegQueryValueExW( hKeyProduct, szLocalPackage, + NULL, &type, (LPBYTE) path, &count ); + if( r != ERROR_SUCCESS ) + { + r = ERROR_UNKNOWN_PRODUCT; + goto end; + } + + r = MsiOpenPackageW( path, phProduct ); + +end: + HeapFree( GetProcessHeap(), 0, path ); + if( hKeyProduct ) + RegCloseKey( hKeyProduct ); + + return r; +} + +UINT WINAPI MsiAdvertiseProductA(LPCSTR szPackagePath, LPCSTR szScriptfilePath, + LPCSTR szTransforms, LANGID lgidLanguage) +{ + FIXME("%s %s %s %08x\n",debugstr_a(szPackagePath), + debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiAdvertiseProductW(LPCWSTR szPackagePath, LPCWSTR szScriptfilePath, + LPCWSTR szTransforms, LANGID lgidLanguage) +{ + FIXME("%s %s %s %08x\n",debugstr_w(szPackagePath), + debugstr_w(szScriptfilePath), debugstr_w(szTransforms), lgidLanguage); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiAdvertiseProductExA(LPCSTR szPackagePath, LPCSTR szScriptfilePath, + LPCSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions) +{ + FIXME("%s %s %s %08x %08lx %08lx\n", debugstr_a(szPackagePath), + debugstr_a(szScriptfilePath), debugstr_a(szTransforms), + lgidLanguage, dwPlatform, dwOptions); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiAdvertiseProductExW( LPCWSTR szPackagePath, LPCWSTR szScriptfilePath, + LPCWSTR szTransforms, LANGID lgidLanguage, DWORD dwPlatform, DWORD dwOptions) +{ + FIXME("%s %s %s %08x %08lx %08lx\n", debugstr_w(szPackagePath), + debugstr_w(szScriptfilePath), debugstr_w(szTransforms), + lgidLanguage, dwPlatform, dwOptions); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiInstallProductA(LPCSTR szPackagePath, LPCSTR szCommandLine) +{ + LPWSTR szwPath = NULL, szwCommand = NULL; + UINT r = ERROR_OUTOFMEMORY; + + TRACE("%s %s\n",debugstr_a(szPackagePath), debugstr_a(szCommandLine)); + + if( szPackagePath ) + { + szwPath = strdupAtoW( szPackagePath ); + if( !szwPath ) + goto end; + } + + if( szCommandLine ) + { + szwCommand = strdupAtoW( szCommandLine ); + if( !szwCommand ) + goto end; + } + + r = MsiInstallProductW( szwPath, szwCommand ); + +end: + HeapFree( GetProcessHeap(), 0, szwPath ); + HeapFree( GetProcessHeap(), 0, szwCommand ); + + return r; +} + +UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine) +{ + MSIPACKAGE *package = NULL; + UINT r; + MSIHANDLE handle; + + FIXME("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine)); + + r = MsiVerifyPackageW(szPackagePath); + if (r != ERROR_SUCCESS) + return r; + + r = MSI_OpenPackageW(szPackagePath,&package); + if (r != ERROR_SUCCESS) + return r; + + handle = alloc_msihandle( &package->hdr ); + + r = ACTION_DoTopLevelINSTALL(package, szPackagePath, szCommandLine); + + MsiCloseHandle(handle); + msiobj_release( &package->hdr ); + return r; +} + +UINT WINAPI MsiReinstallProductA(LPCSTR szProduct, DWORD dwReinstallMode) +{ + FIXME("%s %08lx\n", debugstr_a(szProduct), dwReinstallMode); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiReinstallProductW(LPCWSTR szProduct, DWORD dwReinstallMode) +{ + FIXME("%s %08lx\n", debugstr_w(szProduct), dwReinstallMode); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiApplyPatchA(LPCSTR szPatchPackage, LPCSTR szInstallPackage, + INSTALLTYPE eInstallType, LPCSTR szCommandLine) +{ + FIXME("%s %s %d %s\n", debugstr_a(szPatchPackage), debugstr_a(szInstallPackage), + eInstallType, debugstr_a(szCommandLine)); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiApplyPatchW(LPCWSTR szPatchPackage, LPCWSTR szInstallPackage, + INSTALLTYPE eInstallType, LPCWSTR szCommandLine) +{ + FIXME("%s %s %d %s\n", debugstr_w(szPatchPackage), debugstr_w(szInstallPackage), + eInstallType, debugstr_w(szCommandLine)); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiConfigureProductExW(LPCWSTR szProduct, int iInstallLevel, + INSTALLSTATE eInstallState, LPCWSTR szCommandLine) +{ + MSIHANDLE handle = -1; + MSIPACKAGE* package; + UINT rc; + HKEY hkey=0,hkey1=0; + DWORD sz; + static const WCHAR szSouceList[] = { + 'S','o','u','r','c','e','L','i','s','t',0}; + static const WCHAR szLUS[] = { + 'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0}; + WCHAR sourcepath[0x200]; + static const WCHAR szInstalled[] = { + ' ','I','n','s','t','a','l','l','e','d','=','1',0}; + LPWSTR commandline; + + FIXME("%s %d %d %s\n",debugstr_w(szProduct), iInstallLevel, eInstallState, + debugstr_w(szCommandLine)); + + if (eInstallState != INSTALLSTATE_LOCAL && + eInstallState != INSTALLSTATE_DEFAULT) + { + FIXME("Not implemented for anything other than local installs\n"); + return ERROR_CALL_NOT_IMPLEMENTED; + } + + rc = MSIREG_OpenUserProductsKey(szProduct,&hkey,FALSE); + if (rc != ERROR_SUCCESS) + goto end; + + rc = RegOpenKeyW(hkey,szSouceList,&hkey1); + if (rc != ERROR_SUCCESS) + goto end; + + sz = sizeof(sourcepath); + rc = RegQueryValueExW(hkey1, szLUS, NULL, NULL,(LPBYTE)sourcepath, &sz); + if (rc != ERROR_SUCCESS) + goto end; + + RegCloseKey(hkey1); + /* + * ok 1, we need to find the msi file for this product. + * 2, find the source dir for the files + * 3, do the configure/install. + * 4, cleanupany runonce entry. + */ + + rc = MsiOpenProductW(szProduct,&handle); + if (rc != ERROR_SUCCESS) + goto end; + + package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE); + if (!package) + { + rc = ERROR_INVALID_HANDLE; + goto end; + } + + sz = lstrlenW(szInstalled); + + if (szCommandLine) + sz += lstrlenW(szCommandLine); + + commandline = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR)); + + if (szCommandLine) + lstrcpyW(commandline,szCommandLine); + else + commandline[0] = 0; + + if (MsiQueryProductStateW(szProduct) != INSTALLSTATE_UNKNOWN) + lstrcatW(commandline,szInstalled); + + rc = ACTION_DoTopLevelINSTALL(package, sourcepath, commandline); + + msiobj_release( &package->hdr ); + + HeapFree(GetProcessHeap(),0,commandline); +end: + RegCloseKey(hkey); + if (handle != -1) + MsiCloseHandle(handle); + + return rc; +} + +UINT WINAPI MsiConfigureProductExA(LPCSTR szProduct, int iInstallLevel, + INSTALLSTATE eInstallState, LPCSTR szCommandLine) +{ + LPWSTR szwProduct = NULL; + LPWSTR szwCommandLine = NULL; + UINT r = ERROR_OUTOFMEMORY; + + if( szProduct ) + { + szwProduct = strdupAtoW( szProduct ); + if( !szwProduct ) + goto end; + } + + if( szCommandLine) + { + szwCommandLine = strdupAtoW( szCommandLine ); + if( !szwCommandLine) + goto end; + } + + r = MsiConfigureProductExW( szwProduct, iInstallLevel, eInstallState, + szwCommandLine ); +end: + HeapFree( GetProcessHeap(), 0, szwProduct ); + HeapFree( GetProcessHeap(), 0, szwCommandLine); + + return r; +} + +UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel, + INSTALLSTATE eInstallState) +{ + LPWSTR szwProduct = NULL; + UINT r; + + TRACE("%s %d %d\n",debugstr_a(szProduct), iInstallLevel, eInstallState); + + if( szProduct ) + { + szwProduct = strdupAtoW( szProduct ); + if( !szwProduct ) + return ERROR_OUTOFMEMORY; + } + + r = MsiConfigureProductW( szwProduct, iInstallLevel, eInstallState ); + HeapFree( GetProcessHeap(), 0, szwProduct ); + + return r; +} + +UINT WINAPI MsiConfigureProductW(LPCWSTR szProduct, int iInstallLevel, + INSTALLSTATE eInstallState) +{ + FIXME("%s %d %d\n", debugstr_w(szProduct), iInstallLevel, eInstallState); + + return MsiConfigureProductExW(szProduct, iInstallLevel, eInstallState, NULL); +} + +UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer) +{ + LPWSTR szwComponent = NULL; + UINT r; + WCHAR szwBuffer[GUID_SIZE]; + + TRACE("%s %s\n",debugstr_a(szComponent), debugstr_a(szBuffer)); + + if( szComponent ) + { + szwComponent = strdupAtoW( szComponent ); + if( !szwComponent ) + return ERROR_OUTOFMEMORY; + } + + r = MsiGetProductCodeW( szwComponent, szwBuffer ); + + if( ERROR_SUCCESS == r ) + WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, GUID_SIZE, NULL, NULL); + + HeapFree( GetProcessHeap(), 0, szwComponent ); + + return r; +} + +UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer) +{ + UINT rc; + HKEY hkey; + WCHAR szSquished[GUID_SIZE]; + DWORD sz = GUID_SIZE; + static const WCHAR szPermKey[] = + { '0','0','0','0','0','0','0','0','0','0','0','0', + '0','0','0','0','0','0','0', '0','0','0','0','0', + '0','0','0','0','0','0','0','0',0}; + + TRACE("%s %p\n",debugstr_w(szComponent), szBuffer); + + if (NULL == szComponent) + return ERROR_INVALID_PARAMETER; + + rc = MSIREG_OpenComponentsKey( szComponent, &hkey, FALSE); + if (rc != ERROR_SUCCESS) + return ERROR_UNKNOWN_COMPONENT; + + rc = RegEnumValueW(hkey, 0, szSquished, &sz, NULL, NULL, NULL, NULL); + if (rc == ERROR_SUCCESS && strcmpW(szSquished,szPermKey)==0) + { + sz = GUID_SIZE; + rc = RegEnumValueW(hkey, 1, szSquished, &sz, NULL, NULL, NULL, NULL); + } + + RegCloseKey(hkey); + + if (rc != ERROR_SUCCESS) + return ERROR_INSTALL_FAILURE; + + unsquash_guid(szSquished, szBuffer); + return ERROR_SUCCESS; +} + +UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute, + LPSTR szBuffer, DWORD *pcchValueBuf) +{ + LPWSTR szwProduct = NULL, szwAttribute = NULL, szwBuffer = NULL; + UINT r = ERROR_OUTOFMEMORY; + + TRACE("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szAttribute), + szBuffer, pcchValueBuf); + + if( szProduct ) + { + szwProduct = strdupAtoW( szProduct ); + if( !szwProduct ) + goto end; + } + + if( szAttribute ) + { + szwAttribute = strdupAtoW( szAttribute ); + if( !szwAttribute ) + goto end; + } + + if( szBuffer ) + { + szwBuffer = HeapAlloc( GetProcessHeap(), 0, (*pcchValueBuf) * sizeof(WCHAR) ); + if( !szwBuffer ) + goto end; + } + + r = MsiGetProductInfoW( szwProduct, szwAttribute, szwBuffer, pcchValueBuf ); + + if( ERROR_SUCCESS == r ) + WideCharToMultiByte(CP_ACP, 0, szwBuffer, -1, szBuffer, *pcchValueBuf, NULL, NULL); + +end: + HeapFree( GetProcessHeap(), 0, szwProduct ); + HeapFree( GetProcessHeap(), 0, szwAttribute ); + HeapFree( GetProcessHeap(), 0, szwBuffer ); + + return r; +} + +UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, + LPWSTR szBuffer, DWORD *pcchValueBuf) +{ + MSIHANDLE hProduct; + UINT r; + static const WCHAR szPackageCode[] = + {'P','a','c','k','a','g','e','C','o','d','e',0}; + static const WCHAR szVersionString[] = + {'V','e','r','s','i','o','n','S','t','r','i','n','g',0}; + static const WCHAR szProductVersion[] = + {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0}; + static const WCHAR szAssignmentType[] = + {'A','s','s','i','g','n','m','e','n','t','T','y','p','e',0}; + + FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szAttribute), + szBuffer, pcchValueBuf); + + if (NULL != szBuffer && NULL == pcchValueBuf) + return ERROR_INVALID_PARAMETER; + if (NULL == szProduct || NULL == szAttribute) + return ERROR_INVALID_PARAMETER; + + /* check for special properties */ + if (strcmpW(szAttribute, szPackageCode)==0) + { + HKEY hkey; + WCHAR squished[GUID_SIZE]; + WCHAR package[200]; + DWORD sz = sizeof(squished); + + r = MSIREG_OpenUserProductsKey(szProduct, &hkey, FALSE); + if (r != ERROR_SUCCESS) + return ERROR_UNKNOWN_PRODUCT; + + r = RegQueryValueExW(hkey, szPackageCode, NULL, NULL, + (LPBYTE)squished, &sz); + if (r != ERROR_SUCCESS) + { + RegCloseKey(hkey); + return ERROR_UNKNOWN_PRODUCT; + } + + unsquash_guid(squished, package); + *pcchValueBuf = strlenW(package); + if (strlenW(package) > *pcchValueBuf) + { + RegCloseKey(hkey); + return ERROR_MORE_DATA; + } + else + strcpyW(szBuffer, package); + + RegCloseKey(hkey); + r = ERROR_SUCCESS; + } + else if (strcmpW(szAttribute, szVersionString)==0) + { + r = MsiOpenProductW(szProduct, &hProduct); + if (ERROR_SUCCESS != r) + return r; + + r = MsiGetPropertyW(hProduct, szProductVersion, szBuffer, pcchValueBuf); + MsiCloseHandle(hProduct); + } + else if (strcmpW(szAttribute, szAssignmentType)==0) + { + FIXME("0 (zero) if advertised, 1(one) if per machine.\n"); + if (szBuffer) + szBuffer[0] = 1; + r = ERROR_SUCCESS; + } + else + { + r = MsiOpenProductW(szProduct, &hProduct); + if (ERROR_SUCCESS != r) + return r; + + r = MsiGetPropertyW(hProduct, szAttribute, szBuffer, pcchValueBuf); + MsiCloseHandle(hProduct); + } + + return r; +} + +UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, DWORD attributes) +{ + LPWSTR szwLogFile = NULL; + UINT r; + + TRACE("%08lx %s %08lx\n", dwLogMode, debugstr_a(szLogFile), attributes); + + if( szLogFile ) + { + szwLogFile = strdupAtoW( szLogFile ); + if( !szwLogFile ) + return ERROR_OUTOFMEMORY; + } + r = MsiEnableLogW( dwLogMode, szwLogFile, attributes ); + HeapFree( GetProcessHeap(), 0, szwLogFile ); + return r; +} + +UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, DWORD attributes) +{ + HANDLE file = INVALID_HANDLE_VALUE; + + TRACE("%08lx %s %08lx\n", dwLogMode, debugstr_w(szLogFile), attributes); + + lstrcpyW(gszLogFile,szLogFile); + if (!(attributes & INSTALLLOGATTRIBUTES_APPEND)) + DeleteFileW(szLogFile); + file = CreateFileW(szLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + if (file != INVALID_HANDLE_VALUE) + CloseHandle(file); + else + ERR("Unable to enable log %s\n",debugstr_w(szLogFile)); + + return ERROR_SUCCESS; +} + +INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct) +{ + LPWSTR szwProduct = NULL; + INSTALLSTATE r; + + if( szProduct ) + { + szwProduct = strdupAtoW( szProduct ); + if( !szwProduct ) + return ERROR_OUTOFMEMORY; + } + r = MsiQueryProductStateW( szwProduct ); + HeapFree( GetProcessHeap(), 0, szwProduct ); + return r; +} + +INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct) +{ + UINT rc; + INSTALLSTATE rrc = INSTALLSTATE_UNKNOWN; + HKEY hkey = 0; + static const WCHAR szWindowsInstaller[] = { + 'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0 }; + DWORD sz; + + TRACE("%s\n", debugstr_w(szProduct)); + + rc = MSIREG_OpenUserProductsKey(szProduct,&hkey,FALSE); + if (rc != ERROR_SUCCESS) + goto end; + + RegCloseKey(hkey); + + rc = MSIREG_OpenUninstallKey(szProduct,&hkey,FALSE); + if (rc != ERROR_SUCCESS) + goto end; + + sz = sizeof(rrc); + rc = RegQueryValueExW(hkey,szWindowsInstaller,NULL,NULL,(LPVOID)&rrc, &sz); + if (rc != ERROR_SUCCESS) + goto end; + + switch (rrc) + { + case 1: + /* default */ + rrc = INSTALLSTATE_DEFAULT; + break; + default: + FIXME("Unknown install state read from registry (%i)\n",rrc); + rrc = INSTALLSTATE_UNKNOWN; + break; + } +end: + RegCloseKey(hkey); + return rrc; +} + +INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd) +{ + INSTALLUILEVEL old = gUILevel; + HWND oldwnd = gUIhwnd; + + TRACE("%08x %p\n", dwUILevel, phWnd); + + gUILevel = dwUILevel; + if (phWnd) + { + gUIhwnd = *phWnd; + *phWnd = oldwnd; + } + return old; +} + +INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler, + DWORD dwMessageFilter, LPVOID pvContext) +{ + INSTALLUI_HANDLERA prev = gUIHandlerA; + + TRACE("%p %lx %p\n",puiHandler, dwMessageFilter,pvContext); + gUIHandlerA = puiHandler; + gUIFilter = dwMessageFilter; + gUIContext = pvContext; + + return prev; +} + +INSTALLUI_HANDLERW WINAPI MsiSetExternalUIW(INSTALLUI_HANDLERW puiHandler, + DWORD dwMessageFilter, LPVOID pvContext) +{ + INSTALLUI_HANDLERW prev = gUIHandlerW; + + TRACE("%p %lx %p\n",puiHandler,dwMessageFilter,pvContext); + gUIHandlerW = puiHandler; + gUIFilter = dwMessageFilter; + gUIContext = pvContext; + + return prev; +} + +/****************************************************************** + * MsiLoadStringW [MSI.@] + * + * Loads a string from MSI's string resources. + * + * PARAMS + * + * handle [I] only -1 is handled currently + * id [I] id of the string to be loaded + * lpBuffer [O] buffer for the string to be written to + * nBufferMax [I] maximum size of the buffer in characters + * lang [I] the preferred language for the string + * + * RETURNS + * + * If successful, this function returns the language id of the string loaded + * If the function fails, the function returns zero. + * + * NOTES + * + * The type of the first parameter is unknown. LoadString's prototype + * suggests that it might be a module handle. I have made it an MSI handle + * for starters, as -1 is an invalid MSI handle, but not an invalid module + * handle. Maybe strings can be stored in an MSI database somehow. + */ +LANGID WINAPI MsiLoadStringW( MSIHANDLE handle, UINT id, LPWSTR lpBuffer, + int nBufferMax, LANGID lang ) +{ + HRSRC hres; + HGLOBAL hResData; + LPWSTR p; + DWORD i, len; + + TRACE("%ld %u %p %d %d\n", handle, id, lpBuffer, nBufferMax, lang); + + if( handle != -1 ) + FIXME("don't know how to deal with handle = %08lx\n", handle); + + if( !lang ) + lang = GetUserDefaultLangID(); + + hres = FindResourceExW( msi_hInstance, (LPCWSTR) RT_STRING, + (LPWSTR)1, lang ); + if( !hres ) + return 0; + hResData = LoadResource( msi_hInstance, hres ); + if( !hResData ) + return 0; + p = LockResource( hResData ); + if( !p ) + return 0; + + for (i = 0; i < (id&0xf); i++) + p += *p + 1; + len = *p; + + if( nBufferMax <= len ) + return 0; + + memcpy( lpBuffer, p+1, len * sizeof(WCHAR)); + lpBuffer[ len ] = 0; + + TRACE("found -> %s\n", debugstr_w(lpBuffer)); + + return lang; +} + +LANGID WINAPI MsiLoadStringA( MSIHANDLE handle, UINT id, LPSTR lpBuffer, + int nBufferMax, LANGID lang ) +{ + LPWSTR bufW; + LANGID r; + DWORD len; + + bufW = HeapAlloc(GetProcessHeap(), 0, nBufferMax*sizeof(WCHAR)); + r = MsiLoadStringW(handle, id, bufW, nBufferMax, lang); + if( r ) + { + len = WideCharToMultiByte(CP_ACP, 0, bufW, -1, NULL, 0, NULL, NULL ); + if( len <= nBufferMax ) + WideCharToMultiByte( CP_ACP, 0, bufW, -1, + lpBuffer, nBufferMax, NULL, NULL ); + else + r = 0; + } + HeapFree(GetProcessHeap(), 0, bufW); + return r; +} + +INSTALLSTATE WINAPI MsiLocateComponentA(LPCSTR szComponent, LPSTR lpPathBuf, + DWORD *pcchBuf) +{ + FIXME("%s %p %08lx\n", debugstr_a(szComponent), lpPathBuf, *pcchBuf); + return INSTALLSTATE_UNKNOWN; +} + +INSTALLSTATE WINAPI MsiLocateComponentW(LPCWSTR szComponent, LPSTR lpPathBuf, + DWORD *pcchBuf) +{ + FIXME("%s %p %08lx\n", debugstr_w(szComponent), lpPathBuf, *pcchBuf); + return INSTALLSTATE_UNKNOWN; +} + +UINT WINAPI MsiMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType, + WORD wLanguageId, DWORD f) +{ + FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_a(lpText),debugstr_a(lpCaption), + uType,wLanguageId,f); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiMessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType, + WORD wLanguageId, DWORD f) +{ + FIXME("%p %s %s %u %08x %08lx\n",hWnd,debugstr_w(lpText),debugstr_w(lpCaption), + uType,wLanguageId,f); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiProvideAssemblyA( LPCSTR szAssemblyName, LPCSTR szAppContext, + DWORD dwInstallMode, DWORD dwAssemblyInfo, LPSTR lpPathBuf, + DWORD* pcchPathBuf ) +{ + FIXME("%s %s %08lx %08lx %p %p\n", debugstr_a(szAssemblyName), + debugstr_a(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf, + pcchPathBuf); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiProvideAssemblyW( LPCWSTR szAssemblyName, LPCWSTR szAppContext, + DWORD dwInstallMode, DWORD dwAssemblyInfo, LPWSTR lpPathBuf, + DWORD* pcchPathBuf ) +{ + FIXME("%s %s %08lx %08lx %p %p\n", debugstr_w(szAssemblyName), + debugstr_w(szAppContext), dwInstallMode, dwAssemblyInfo, lpPathBuf, + pcchPathBuf); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor, + LPSTR szPath, DWORD *pcchPath, DWORD *pcchArgs ) +{ + FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs ); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor, + LPWSTR szPath, DWORD *pcchPath, DWORD *pcchArgs ) +{ + FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs ); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +HRESULT WINAPI MsiGetFileSignatureInformationA( LPCSTR szSignedObjectPath, + DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData, + DWORD* pcbHashData) +{ + FIXME("%s %08lx %p %p %p\n", debugstr_a(szSignedObjectPath), dwFlags, + ppcCertContext, pbHashData, pcbHashData); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +HRESULT WINAPI MsiGetFileSignatureInformationW( LPCWSTR szSignedObjectPath, + DWORD dwFlags, PCCERT_CONTEXT* ppcCertContext, BYTE* pbHashData, + DWORD* pcbHashData) +{ + FIXME("%s %08lx %p %p %p\n", debugstr_w(szSignedObjectPath), dwFlags, + ppcCertContext, pbHashData, pcbHashData); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiGetProductPropertyA( MSIHANDLE hProduct, LPCSTR szProperty, + LPSTR szValue, DWORD *pccbValue ) +{ + FIXME("%ld %s %p %p\n", hProduct, debugstr_a(szProperty), szValue, pccbValue); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiGetProductPropertyW( MSIHANDLE hProduct, LPCWSTR szProperty, + LPWSTR szValue, DWORD *pccbValue ) +{ + FIXME("%ld %s %p %p\n", hProduct, debugstr_w(szProperty), szValue, pccbValue); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiVerifyPackageA( LPCSTR szPackage ) +{ + UINT r; + LPWSTR szPack = NULL; + + TRACE("%s\n", debugstr_a(szPackage) ); + + if( szPackage ) + { + szPack = strdupAtoW( szPackage ); + if( !szPack ) + return ERROR_OUTOFMEMORY; + } + + r = MsiVerifyPackageW( szPack ); + + HeapFree( GetProcessHeap(), 0, szPack ); + + return r; +} + +UINT WINAPI MsiVerifyPackageW( LPCWSTR szPackage ) +{ + MSIHANDLE handle; + UINT r; + + TRACE("%s\n", debugstr_w(szPackage) ); + + r = MsiOpenDatabaseW( szPackage, MSIDBOPEN_READONLY, &handle ); + MsiCloseHandle( handle ); + + return r; +} + +INSTALLSTATE WINAPI MsiGetComponentPathA(LPCSTR szProduct, LPCSTR szComponent, + LPSTR lpPathBuf, DWORD* pcchBuf) +{ + LPWSTR szwProduct = NULL, szwComponent = NULL, lpwPathBuf= NULL; + INSTALLSTATE rc; + UINT incoming_len; + + if( szProduct ) + { + szwProduct = strdupAtoW( szProduct ); + if( !szwProduct) + return ERROR_OUTOFMEMORY; + } + + if( szComponent ) + { + szwComponent = strdupAtoW( szComponent ); + if( !szwComponent ) + { + HeapFree( GetProcessHeap(), 0, szwProduct); + return ERROR_OUTOFMEMORY; + } + } + + if( pcchBuf && *pcchBuf > 0 ) + lpwPathBuf = HeapAlloc( GetProcessHeap(), 0, *pcchBuf * sizeof(WCHAR)); + else + lpwPathBuf = NULL; + + incoming_len = *pcchBuf; + rc = MsiGetComponentPathW(szwProduct, szwComponent, lpwPathBuf, pcchBuf); + + HeapFree( GetProcessHeap(), 0, szwProduct); + HeapFree( GetProcessHeap(), 0, szwComponent); + if (lpwPathBuf) + { + if (rc != INSTALLSTATE_UNKNOWN) + WideCharToMultiByte(CP_ACP, 0, lpwPathBuf, incoming_len, + lpPathBuf, incoming_len, NULL, NULL); + HeapFree( GetProcessHeap(), 0, lpwPathBuf); + } + + return rc; +} + +INSTALLSTATE WINAPI MsiGetComponentPathW(LPCWSTR szProduct, LPCWSTR szComponent, + LPWSTR lpPathBuf, DWORD* pcchBuf) +{ + WCHAR squished_pc[GUID_SIZE]; + UINT rc; + INSTALLSTATE rrc = INSTALLSTATE_UNKNOWN; + HKEY hkey = 0; + LPWSTR path = NULL; + DWORD sz, type; + + TRACE("%s %s %p %p\n", debugstr_w(szProduct), + debugstr_w(szComponent), lpPathBuf, pcchBuf); + + if( lpPathBuf && !pcchBuf ) + return INSTALLSTATE_INVALIDARG; + + squash_guid(szProduct,squished_pc); + + rc = MSIREG_OpenProductsKey( szProduct, &hkey, FALSE); + if( rc != ERROR_SUCCESS ) + goto end; + + RegCloseKey(hkey); + + rc = MSIREG_OpenComponentsKey( szComponent, &hkey, FALSE); + if( rc != ERROR_SUCCESS ) + goto end; + + sz = 0; + type = 0; + rc = RegQueryValueExW( hkey, squished_pc, NULL, &type, NULL, &sz ); + if( rc != ERROR_SUCCESS ) + goto end; + if( type != REG_SZ ) + goto end; + + sz += sizeof(WCHAR); + path = HeapAlloc( GetProcessHeap(), 0, sz ); + if( !path ) + goto end; + + rc = RegQueryValueExW( hkey, squished_pc, NULL, NULL, (LPVOID) path, &sz ); + if( rc != ERROR_SUCCESS ) + goto end; + + TRACE("found path of (%s:%s)(%s)\n", debugstr_w(szComponent), + debugstr_w(szProduct), debugstr_w(path)); + + if (path[0]=='0') + { + FIXME("Registry entry.. check entry\n"); + rrc = INSTALLSTATE_LOCAL; + } + else + { + /* PROBABLY a file */ + if ( GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES ) + rrc = INSTALLSTATE_LOCAL; + else + rrc = INSTALLSTATE_ABSENT; + } + + if( pcchBuf ) + { + sz = sz / sizeof(WCHAR); + if( *pcchBuf >= sz ) + lstrcpyW( lpPathBuf, path ); + *pcchBuf = sz; + } + +end: + HeapFree(GetProcessHeap(), 0, path ); + RegCloseKey(hkey); + return rrc; +} + +/****************************************************************** + * MsiQueryFeatureStateA [MSI.@] + */ +INSTALLSTATE WINAPI MsiQueryFeatureStateA(LPCSTR szProduct, LPCSTR szFeature) +{ + INSTALLSTATE rc; + LPWSTR szwProduct= NULL; + LPWSTR szwFeature= NULL; + + if( szProduct ) + { + szwProduct = strdupAtoW( szProduct ); + if( !szwProduct) + return ERROR_OUTOFMEMORY; + } + + if( szFeature ) + { + szwFeature = strdupAtoW( szFeature ); + if( !szwFeature) + { + HeapFree( GetProcessHeap(), 0, szwProduct); + return ERROR_OUTOFMEMORY; + } + } + + rc = MsiQueryFeatureStateW(szwProduct, szwFeature); + + HeapFree( GetProcessHeap(), 0, szwProduct); + HeapFree( GetProcessHeap(), 0, szwFeature); + + return rc; +} + +/****************************************************************** + * MsiQueryFeatureStateW [MSI.@] + * + * This does not verify that the Feature is functional. So i am only going to + * check the existence of the key in the registry. This should tell me if it is + * installed. + */ +INSTALLSTATE WINAPI MsiQueryFeatureStateW(LPCWSTR szProduct, LPCWSTR szFeature) +{ + UINT rc; + DWORD sz = 0; + HKEY hkey; + + TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature)); + + rc = MSIREG_OpenFeaturesKey(szProduct, &hkey, FALSE); + if (rc != ERROR_SUCCESS) + return INSTALLSTATE_UNKNOWN; + + rc = RegQueryValueExW( hkey, szFeature, NULL, NULL, NULL, &sz); + RegCloseKey(hkey); + + if (rc == ERROR_SUCCESS) + return INSTALLSTATE_LOCAL; + else + return INSTALLSTATE_ABSENT; +} + +/****************************************************************** + * MsiGetFileVersionA [MSI.@] + */ +UINT WINAPI MsiGetFileVersionA(LPCSTR szFilePath, LPSTR lpVersionBuf, + DWORD* pcchVersionBuf, LPSTR lpLangBuf, DWORD* pcchLangBuf) +{ + LPWSTR szwFilePath = NULL, lpwVersionBuff = NULL, lpwLangBuff = NULL; + UINT ret = ERROR_OUTOFMEMORY; + + if( szFilePath ) + { + szwFilePath = strdupAtoW( szFilePath ); + if( !szwFilePath ) + goto end; + } + + if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf ) + { + lpwVersionBuff = HeapAlloc(GetProcessHeap(), 0, *pcchVersionBuf*sizeof(WCHAR)); + if( !lpwVersionBuff ) + goto end; + } + + if( lpLangBuf && pcchLangBuf && *pcchLangBuf ) + { + lpwLangBuff = HeapAlloc(GetProcessHeap(), 0, *pcchVersionBuf*sizeof(WCHAR)); + if( !lpwLangBuff ) + goto end; + } + + ret = MsiGetFileVersionW(szwFilePath, lpwVersionBuff, pcchVersionBuf, + lpwLangBuff, pcchLangBuf); + + if( lpwVersionBuff ) + WideCharToMultiByte(CP_ACP, 0, lpwVersionBuff, -1, + lpVersionBuf, *pcchVersionBuf, NULL, NULL); + if( lpwLangBuff ) + WideCharToMultiByte(CP_ACP, 0, lpwLangBuff, -1, + lpLangBuf, *pcchLangBuf, NULL, NULL); + +end: + HeapFree(GetProcessHeap(), 0, szwFilePath); + HeapFree(GetProcessHeap(), 0, lpwVersionBuff); + HeapFree(GetProcessHeap(), 0, lpwLangBuff); + + return ret; +} + +/****************************************************************** + * MsiGetFileVersionW [MSI.@] + */ +UINT WINAPI MsiGetFileVersionW(LPCWSTR szFilePath, LPWSTR lpVersionBuf, + DWORD* pcchVersionBuf, LPWSTR lpLangBuf, DWORD* pcchLangBuf) +{ + static const WCHAR szVersionResource[] = {'\\',0}; + static const WCHAR szVersionFormat[] = { + '%','d','.','%','d','.','%','d','.','%','d',0}; + static const WCHAR szLangFormat[] = {'%','d',0}; + UINT ret = 0; + DWORD dwVerLen; + LPVOID lpVer = NULL; + VS_FIXEDFILEINFO *ffi; + UINT puLen; + WCHAR tmp[32]; + + TRACE("%s %p %ld %p %ld\n", debugstr_w(szFilePath), + lpVersionBuf, pcchVersionBuf?*pcchVersionBuf:0, + lpLangBuf, pcchLangBuf?*pcchLangBuf:0); + + dwVerLen = GetFileVersionInfoSizeW((LPWSTR)szFilePath, NULL); + if( !dwVerLen ) + return GetLastError(); + + lpVer = HeapAlloc(GetProcessHeap(), 0, dwVerLen); + if( !lpVer ) + { + ret = ERROR_OUTOFMEMORY; + goto end; + } + + if( !GetFileVersionInfoW((LPWSTR)szFilePath, 0, dwVerLen, lpVer) ) + { + ret = GetLastError(); + goto end; + } + if( lpVersionBuf && pcchVersionBuf && *pcchVersionBuf ) + { + if( VerQueryValueW(lpVer, (LPWSTR)szVersionResource, (LPVOID*)&ffi, &puLen) && + (puLen > 0) ) + { + wsprintfW(tmp, szVersionFormat, + HIWORD(ffi->dwFileVersionMS), LOWORD(ffi->dwFileVersionMS), + HIWORD(ffi->dwFileVersionLS), LOWORD(ffi->dwFileVersionLS)); + lstrcpynW(lpVersionBuf, tmp, *pcchVersionBuf); + *pcchVersionBuf = lstrlenW(lpVersionBuf); + } + else + { + *lpVersionBuf = 0; + *pcchVersionBuf = 0; + } + } + + if( lpLangBuf && pcchLangBuf && *pcchLangBuf ) + { + DWORD lang = GetUserDefaultLangID(); + + FIXME("Retrieve language from file\n"); + wsprintfW(tmp, szLangFormat, lang); + lstrcpynW(lpLangBuf, tmp, *pcchLangBuf); + *pcchLangBuf = lstrlenW(lpLangBuf); + } + +end: + HeapFree(GetProcessHeap(), 0, lpVer); + return ret; +} + + +/****************************************************************** + * DllMain + */ +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + switch(fdwReason) + { + case DLL_PROCESS_ATTACH: + msi_hInstance = hinstDLL; + DisableThreadLibraryCalls(hinstDLL); + msi_dialog_register_class(); + break; + case DLL_PROCESS_DETACH: + msi_dialog_unregister_class(); + /* FIXME: Cleanup */ + break; + } + return TRUE; +} + +typedef struct tagIClassFactoryImpl +{ + IClassFactoryVtbl *lpVtbl; +} IClassFactoryImpl; + +static HRESULT WINAPI MsiCF_QueryInterface(LPCLASSFACTORY iface, + REFIID riid,LPVOID *ppobj) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + FIXME("%p %s %p\n",This,debugstr_guid(riid),ppobj); + return E_NOINTERFACE; +} + +static ULONG WINAPI MsiCF_AddRef(LPCLASSFACTORY iface) +{ + return 2; +} + +static ULONG WINAPI MsiCF_Release(LPCLASSFACTORY iface) +{ + return 1; +} + +static HRESULT WINAPI MsiCF_CreateInstance(LPCLASSFACTORY iface, + LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + + FIXME("%p %p %s %p\n", This, pOuter, debugstr_guid(riid), ppobj); + return E_FAIL; +} + +static HRESULT WINAPI MsiCF_LockServer(LPCLASSFACTORY iface, BOOL dolock) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + + FIXME("%p %d\n", This, dolock); + return S_OK; +} + +static IClassFactoryVtbl MsiCF_Vtbl = +{ + MsiCF_QueryInterface, + MsiCF_AddRef, + MsiCF_Release, + MsiCF_CreateInstance, + MsiCF_LockServer +}; + +static IClassFactoryImpl Msi_CF = { &MsiCF_Vtbl }; + +/****************************************************************** + * DllGetClassObject [MSI.@] + */ +HRESULT WINAPI MSI_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) +{ + TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); + + if( IsEqualCLSID (rclsid, &CLSID_IMsiServer) || + IsEqualCLSID (rclsid, &CLSID_IMsiServerMessage) || + IsEqualCLSID (rclsid, &CLSID_IMsiServerX1) || + IsEqualCLSID (rclsid, &CLSID_IMsiServerX2) || + IsEqualCLSID (rclsid, &CLSID_IMsiServerX3) ) + { + *ppv = (LPVOID) &Msi_CF; + return S_OK; + } + return CLASS_E_CLASSNOTAVAILABLE; +} + +/****************************************************************** + * DllGetVersion [MSI.@] + */ +HRESULT WINAPI MSI_DllGetVersion(DLLVERSIONINFO *pdvi) +{ + TRACE("%p\n",pdvi); + + if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) + return E_INVALIDARG; + + pdvi->dwMajorVersion = MSI_MAJORVERSION; + pdvi->dwMinorVersion = MSI_MINORVERSION; + pdvi->dwBuildNumber = MSI_BUILDNUMBER; + pdvi->dwPlatformID = 1; + + return S_OK; +} + +/****************************************************************** + * DllCanUnloadNow [MSI.@] + */ +BOOL WINAPI MSI_DllCanUnloadNow(void) +{ + return S_FALSE; +} + +UINT WINAPI MsiGetFeatureUsageW(LPCWSTR szProduct, LPCWSTR szFeature, + DWORD* pdwUseCount, WORD* pwDateUsed) +{ + FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szFeature), + pdwUseCount, pwDateUsed); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiGetFeatureUsageA(LPCSTR szProduct, LPCSTR szFeature, + DWORD* pdwUseCount, WORD* pwDateUsed) +{ + FIXME("%s %s %p %p\n", debugstr_a(szProduct), debugstr_a(szFeature), + pdwUseCount, pwDateUsed); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +INSTALLSTATE WINAPI MsiUseFeatureExW(LPCWSTR szProduct, LPCWSTR szFeature, + DWORD dwInstallMode, DWORD dwReserved) +{ + FIXME("%s %s %li %li\n", debugstr_w(szProduct), debugstr_w(szFeature), + dwInstallMode, dwReserved); + + /* + * Polls all the components of the feature to find install state and then + * writes: + * Software\\Microsoft\\Windows\\CurrentVersion\\ + * Installer\\Products\\<squishguid>\\<feature> + * "Usage"=dword:........ + */ + + return INSTALLSTATE_LOCAL; +} + +/*********************************************************************** + * MsiUseFeatureExA [MSI.@] + */ +INSTALLSTATE WINAPI MsiUseFeatureExA(LPCSTR szProduct, LPCSTR szFeature, + DWORD dwInstallMode, DWORD dwReserved) +{ + FIXME("%s %s %li %li\n", debugstr_a(szProduct), debugstr_a(szFeature), + dwInstallMode, dwReserved); + + return INSTALLSTATE_LOCAL; +} + +INSTALLSTATE WINAPI MsiUseFeatureW(LPCWSTR szProduct, LPCWSTR szFeature) +{ + FIXME("%s %s\n", debugstr_w(szProduct), debugstr_w(szFeature)); + + return INSTALLSTATE_LOCAL; +} + +INSTALLSTATE WINAPI MsiUseFeatureA(LPCSTR szProduct, LPCSTR szFeature) +{ + FIXME("%s %s\n", debugstr_a(szProduct), debugstr_a(szFeature)); + + return INSTALLSTATE_LOCAL; +} + +UINT WINAPI MsiProvideQualifiedComponentExW(LPCWSTR szComponent, + LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR szProduct, + DWORD Unused1, DWORD Unused2, LPWSTR lpPathBuf, + DWORD* pcchPathBuf) +{ + HKEY hkey; + UINT rc; + LPWSTR info; + DWORD sz; + LPWSTR product = NULL; + LPWSTR component = NULL; + LPWSTR ptr; + GUID clsid; + + TRACE("%s %s %li %s %li %li %p %p\n", debugstr_w(szComponent), + debugstr_w(szQualifier), dwInstallMode, debugstr_w(szProduct), + Unused1, Unused2, lpPathBuf, pcchPathBuf); + + rc = MSIREG_OpenUserComponentsKey(szComponent, &hkey, FALSE); + if (rc != ERROR_SUCCESS) + return ERROR_INDEX_ABSENT; + + sz = 0; + rc = RegQueryValueExW( hkey, szQualifier, NULL, NULL, NULL, &sz); + if (sz <= 0) + { + RegCloseKey(hkey); + return ERROR_INDEX_ABSENT; + } + + info = HeapAlloc(GetProcessHeap(),0,sz); + rc = RegQueryValueExW( hkey, szQualifier, NULL, NULL, (LPBYTE)info, &sz); + if (rc != ERROR_SUCCESS) + { + RegCloseKey(hkey); + HeapFree(GetProcessHeap(),0,info); + return ERROR_INDEX_ABSENT; + } + + /* find the component */ + ptr = strchrW(&info[20],'>'); + if (ptr) + ptr++; + else + { + RegCloseKey(hkey); + HeapFree(GetProcessHeap(),0,info); + return ERROR_INDEX_ABSENT; + } + + if (!szProduct) + { + decode_base85_guid(info,&clsid); + StringFromCLSID(&clsid, &product); + } + decode_base85_guid(ptr,&clsid); + StringFromCLSID(&clsid, &component); + + if (!szProduct) + rc = MsiGetComponentPathW(product, component, lpPathBuf, pcchPathBuf); + else + rc = MsiGetComponentPathW(szProduct, component, lpPathBuf, pcchPathBuf); + + RegCloseKey(hkey); + HeapFree(GetProcessHeap(),0,info); + HeapFree(GetProcessHeap(),0,product); + HeapFree(GetProcessHeap(),0,component); + + if (rc == INSTALLSTATE_LOCAL) + return ERROR_SUCCESS; + else + return ERROR_FILE_NOT_FOUND; +} + +/*********************************************************************** + * MsiProvideQualifiedComponentW [MSI.@] + */ +UINT WINAPI MsiProvideQualifiedComponentW( LPCWSTR szComponent, + LPCWSTR szQualifier, DWORD dwInstallMode, LPWSTR lpPathBuf, + DWORD* pcchPathBuf) +{ + return MsiProvideQualifiedComponentExW(szComponent, szQualifier, + dwInstallMode, NULL, 0, 0, lpPathBuf, pcchPathBuf); +} + +/*********************************************************************** + * MsiProvideQualifiedComponentA [MSI.@] + */ +UINT WINAPI MsiProvideQualifiedComponentA( LPCSTR szComponent, + LPCSTR szQualifier, DWORD dwInstallMode, LPSTR lpPathBuf, + DWORD* pcchPathBuf) +{ + LPWSTR szwComponent, szwQualifier, lpwPathBuf; + DWORD pcchwPathBuf; + UINT rc; + + TRACE("%s %s %li %p %p\n",szComponent, szQualifier, + dwInstallMode, lpPathBuf, pcchPathBuf); + + szwComponent= strdupAtoW( szComponent); + szwQualifier= strdupAtoW( szQualifier); + + lpwPathBuf = HeapAlloc(GetProcessHeap(),0,*pcchPathBuf * sizeof(WCHAR)); + + pcchwPathBuf = *pcchPathBuf; + + rc = MsiProvideQualifiedComponentW(szwComponent, szwQualifier, + dwInstallMode, lpwPathBuf, &pcchwPathBuf); + + HeapFree(GetProcessHeap(),0,szwComponent); + HeapFree(GetProcessHeap(),0,szwQualifier); + *pcchPathBuf = WideCharToMultiByte(CP_ACP, 0, lpwPathBuf, pcchwPathBuf, + lpPathBuf, *pcchPathBuf, NULL, NULL); + + HeapFree(GetProcessHeap(),0,lpwPathBuf); + return rc; +} + +USERINFOSTATE WINAPI MsiGetUserInfoW(LPCWSTR szProduct, LPWSTR lpUserNameBuf, + DWORD* pcchUserNameBuf, LPWSTR lpOrgNameBuf, + DWORD* pcchOrgNameBuf, LPWSTR lpSerialBuf, DWORD* pcchSerialBuf) +{ + HKEY hkey; + DWORD sz; + UINT rc = ERROR_SUCCESS,rc2 = ERROR_SUCCESS; + static const WCHAR szOwner[] = {'R','e','g','O','w','n','e','r',0}; + static const WCHAR szCompany[] = {'R','e','g','C','o','m','p','a','n','y',0}; + static const WCHAR szSerial[] = {'P','r','o','d','u','c','t','I','D',0}; + + TRACE("%s %p %p %p %p %p %p\n",debugstr_w(szProduct), lpUserNameBuf, + pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf, + pcchSerialBuf); + + rc = MSIREG_OpenUninstallKey(szProduct, &hkey, FALSE); + if (rc != ERROR_SUCCESS) + return USERINFOSTATE_UNKNOWN; + + if (lpUserNameBuf) + { + sz = *lpUserNameBuf * sizeof(WCHAR); + rc = RegQueryValueExW( hkey, szOwner, NULL, NULL, (LPBYTE)lpUserNameBuf, + &sz); + } + if (!lpUserNameBuf && pcchUserNameBuf) + { + sz = 0; + rc = RegQueryValueExW( hkey, szOwner, NULL, NULL, NULL, &sz); + } + + if (pcchUserNameBuf) + *pcchUserNameBuf = sz / sizeof(WCHAR); + + if (lpOrgNameBuf) + { + sz = *pcchOrgNameBuf * sizeof(WCHAR); + rc2 = RegQueryValueExW( hkey, szCompany, NULL, NULL, + (LPBYTE)lpOrgNameBuf, &sz); + } + if (!lpOrgNameBuf && pcchOrgNameBuf) + { + sz = 0; + rc2 = RegQueryValueExW( hkey, szCompany, NULL, NULL, NULL, &sz); + } + + if (pcchOrgNameBuf) + *pcchOrgNameBuf = sz / sizeof(WCHAR); + + if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA && + rc2 != ERROR_SUCCESS && rc2 != ERROR_MORE_DATA) + { + RegCloseKey(hkey); + return USERINFOSTATE_ABSENT; + } + + if (lpSerialBuf) + { + sz = *pcchSerialBuf * sizeof(WCHAR); + RegQueryValueExW( hkey, szSerial, NULL, NULL, (LPBYTE)lpSerialBuf, + &sz); + } + if (!lpSerialBuf && pcchSerialBuf) + { + sz = 0; + rc = RegQueryValueExW( hkey, szSerial, NULL, NULL, NULL, &sz); + } + if (pcchSerialBuf) + *pcchSerialBuf = sz / sizeof(WCHAR); + + RegCloseKey(hkey); + return USERINFOSTATE_PRESENT; +} + +USERINFOSTATE WINAPI MsiGetUserInfoA(LPCSTR szProduct, LPSTR lpUserNameBuf, + DWORD* pcchUserNameBuf, LPSTR lpOrgNameBuf, + DWORD* pcchOrgNameBuf, LPSTR lpSerialBuf, DWORD* pcchSerialBuf) +{ + FIXME("%s %p %p %p %p %p %p\n",debugstr_a(szProduct), lpUserNameBuf, + pcchUserNameBuf, lpOrgNameBuf, pcchOrgNameBuf, lpSerialBuf, + pcchSerialBuf); + + return USERINFOSTATE_UNKNOWN; +} + +UINT WINAPI MsiCollectUserInfoW(LPCWSTR szProduct) +{ + MSIHANDLE handle; + UINT rc; + MSIPACKAGE *package; + static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0}; + + TRACE("(%s)\n",debugstr_w(szProduct)); + + rc = MsiOpenProductW(szProduct,&handle); + if (rc != ERROR_SUCCESS) + return ERROR_INVALID_PARAMETER; + + package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE); + rc = ACTION_PerformUIAction(package, szFirstRun); + msiobj_release( &package->hdr ); + + MsiCloseHandle(handle); + + return rc; +} + +UINT WINAPI MsiCollectUserInfoA(LPCSTR szProduct) +{ + MSIHANDLE handle; + UINT rc; + MSIPACKAGE *package; + static const WCHAR szFirstRun[] = {'F','i','r','s','t','R','u','n',0}; + + TRACE("(%s)\n",debugstr_a(szProduct)); + + rc = MsiOpenProductA(szProduct,&handle); + if (rc != ERROR_SUCCESS) + return ERROR_INVALID_PARAMETER; + + package = msihandle2msiinfo(handle, MSIHANDLETYPE_PACKAGE); + rc = ACTION_PerformUIAction(package, szFirstRun); + msiobj_release( &package->hdr ); + + MsiCloseHandle(handle); + + return rc; +} + +UINT WINAPI MsiCreateAndVerifyInstallerDirectory(DWORD dwReserved) +{ + WCHAR path[MAX_PATH]; + + if(dwReserved) { + FIXME("Don't know how to handle argument %ld\n", dwReserved); + return ERROR_CALL_NOT_IMPLEMENTED; + } + + if(!GetWindowsDirectoryW(path, MAX_PATH)) { + FIXME("GetWindowsDirectory failed unexpected! Error %ld\n", + GetLastError()); + return ERROR_CALL_NOT_IMPLEMENTED; + } + + strcatW(path, installerW); + + CreateDirectoryW(path, NULL); + + return 0; +} + +UINT WINAPI MsiGetShortcutTargetA( LPCSTR szShortcutTarget, + LPSTR szProductCode, LPSTR szFeatureId, + LPSTR szComponentCode ) +{ + FIXME("\n"); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiGetShortcutTargetW( LPCWSTR szShortcutTarget, + LPWSTR szProductCode, LPWSTR szFeatureId, + LPWSTR szComponentCode ) +{ + FIXME("\n"); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiReinstallFeatureW( LPCWSTR szProduct, LPCWSTR szFeature, + DWORD dwReinstallMode ) +{ + FIXME("%s %s %li\n", debugstr_w(szProduct), debugstr_w(szFeature), + dwReinstallMode); + return ERROR_SUCCESS; +} + +UINT WINAPI MsiReinstallFeatureA( LPCSTR szProduct, LPCSTR szFeature, + DWORD dwReinstallMode ) +{ + FIXME("%s %s %li\n", debugstr_a(szProduct), debugstr_a(szFeature), + dwReinstallMode); + return ERROR_SUCCESS; +} diff --git a/reactos/lib/msi/msipriv.h b/reactos/lib/msi/msipriv.h index 2aad08a9d82..8aa931a198b 100644 --- a/reactos/lib/msi/msipriv.h +++ b/reactos/lib/msi/msipriv.h @@ -1,423 +1,423 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2002-2005 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_MSI_PRIVATE__ -#define __WINE_MSI_PRIVATE__ - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "msi.h" -#include "msiquery.h" -#include "objbase.h" -#include "objidl.h" -#include "wine/unicode.h" -#include "wine/list.h" - -#define MSI_DATASIZEMASK 0x00ff -#define MSITYPE_VALID 0x0100 -#define MSITYPE_STRING 0x0800 -#define MSITYPE_NULLABLE 0x1000 -#define MSITYPE_KEY 0x2000 - -#define MSITYPE_BINARY 0x8900 - -struct tagMSITABLE; -typedef struct tagMSITABLE MSITABLE; - -struct string_table; -typedef struct string_table string_table; - -struct tagMSIOBJECTHDR; -typedef struct tagMSIOBJECTHDR MSIOBJECTHDR; - -typedef VOID (*msihandledestructor)( MSIOBJECTHDR * ); - -struct tagMSIOBJECTHDR -{ - UINT magic; - UINT type; - DWORD refcount; - msihandledestructor destructor; - struct tagMSIOBJECTHDR *next; - struct tagMSIOBJECTHDR *prev; -}; - -typedef struct tagMSIDATABASE -{ - MSIOBJECTHDR hdr; - IStorage *storage; - string_table *strings; - LPWSTR mode; - MSITABLE *first_table, *last_table; -} MSIDATABASE; - -typedef struct tagMSIVIEW MSIVIEW; - -typedef struct tagMSIQUERY -{ - MSIOBJECTHDR hdr; - MSIVIEW *view; - UINT row; - MSIDATABASE *db; - struct list mem; -} MSIQUERY; - -/* maybe we can use a Variant instead of doing it ourselves? */ -typedef struct tagMSIFIELD -{ - UINT type; - union - { - INT iVal; - LPWSTR szwVal; - IStream *stream; - } u; -} MSIFIELD; - -typedef struct tagMSIRECORD -{ - MSIOBJECTHDR hdr; - UINT count; /* as passed to MsiCreateRecord */ - MSIFIELD fields[1]; /* nb. array size is count+1 */ -} MSIRECORD; - -typedef struct tagMSIVIEWOPS -{ - /* - * fetch_int - reads one integer from {row,col} in the table - * - * This function should be called after the execute method. - * Data returned by the function should not change until - * close or delete is called. - * To get a string value, query the database's string table with - * the integer value returned from this function. - */ - UINT (*fetch_int)( struct tagMSIVIEW *, UINT row, UINT col, UINT *val ); - - /* - * fetch_int - reads one integer from {row,col} in the table - * - * This function is similar to fetch_int, except fetches a - * stream instead of an integer. - */ - UINT (*fetch_stream)( struct tagMSIVIEW *, UINT row, UINT col, IStream **stm ); - - /* - * get_int - sets one integer at {row,col} in the table - * - * Similar semantics to fetch_int - */ - UINT (*set_int)( struct tagMSIVIEW *, UINT row, UINT col, UINT val ); - - /* - * Inserts a new, blank row into the database - * *row receives the number of the new row - */ - UINT (*insert_row)( struct tagMSIVIEW *, UINT *row ); - - /* - * execute - loads the underlying data into memory so it can be read - */ - UINT (*execute)( struct tagMSIVIEW *, MSIRECORD * ); - - /* - * close - clears the data read by execute from memory - */ - UINT (*close)( struct tagMSIVIEW * ); - - /* - * get_dimensions - returns the number of rows or columns in a table. - * - * The number of rows can only be queried after the execute method - * is called. The number of columns can be queried at any time. - */ - UINT (*get_dimensions)( struct tagMSIVIEW *, UINT *rows, UINT *cols ); - - /* - * get_column_info - returns the name and type of a specific column - * - * The name is HeapAlloc'ed by this function and should be freed by - * the caller. - * The column information can be queried at any time. - */ - UINT (*get_column_info)( struct tagMSIVIEW *, UINT n, LPWSTR *name, UINT *type ); - - /* - * modify - not yet implemented properly - */ - UINT (*modify)( struct tagMSIVIEW *, MSIMODIFY, MSIRECORD * ); - - /* - * delete - destroys the structure completely - */ - UINT (*delete)( struct tagMSIVIEW * ); - -} MSIVIEWOPS; - -struct tagMSIVIEW -{ - MSIOBJECTHDR hdr; - MSIVIEWOPS *ops; -}; - -struct msi_dialog_tag; -typedef struct msi_dialog_tag msi_dialog; - -typedef struct tagMSIPACKAGE -{ - MSIOBJECTHDR hdr; - MSIDATABASE *db; - struct tagMSIFEATURE *features; - UINT loaded_features; - struct tagMSIFOLDER *folders; - UINT loaded_folders; - struct tagMSICOMPONENT *components; - UINT loaded_components; - struct tagMSIFILE *files; - UINT loaded_files; - LPWSTR ActionFormat; - LPWSTR LastAction; - - LPWSTR *DeferredAction; - UINT DeferredActionCount; - - LPWSTR *CommitAction; - UINT CommitActionCount; - - struct tagMSIRUNNINGACTION *RunningAction; - UINT RunningActionCount; - - LPWSTR PackagePath; - - UINT CurrentInstallState; - msi_dialog *dialog; - LPWSTR next_dialog; - - BOOL ExecuteSequenceRun; -} MSIPACKAGE; - -typedef struct tagMSIPREVIEW -{ - MSIOBJECTHDR hdr; - MSIPACKAGE *package; - msi_dialog *dialog; -} MSIPREVIEW; - -#define MSIHANDLETYPE_ANY 0 -#define MSIHANDLETYPE_DATABASE 1 -#define MSIHANDLETYPE_SUMMARYINFO 2 -#define MSIHANDLETYPE_VIEW 3 -#define MSIHANDLETYPE_RECORD 4 -#define MSIHANDLETYPE_PACKAGE 5 -#define MSIHANDLETYPE_PREVIEW 6 - -#define MSI_MAJORVERSION 2 -#define MSI_MINORVERSION 0 -#define MSI_BUILDNUMBER 2600 - -#define GUID_SIZE 39 - -#define MSIHANDLE_MAGIC 0x4d434923 -#define MSIMAXHANDLES 0xf0 - -#define MSISUMINFO_OFFSET 0x30LL - -DEFINE_GUID(CLSID_IMsiServer, 0x000C101C,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); -DEFINE_GUID(CLSID_IMsiServerX1, 0x000C103E,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); -DEFINE_GUID(CLSID_IMsiServerX2, 0x000C1090,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); -DEFINE_GUID(CLSID_IMsiServerX3, 0x000C1094,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); - -DEFINE_GUID(CLSID_IMsiServerMessage, 0x000C101D,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); - - -/* handle functions */ -extern void *msihandle2msiinfo(MSIHANDLE handle, UINT type); -extern MSIHANDLE alloc_msihandle( MSIOBJECTHDR * ); -extern void *alloc_msiobject(UINT type, UINT size, msihandledestructor destroy ); -extern void msiobj_addref(MSIOBJECTHDR *); -extern int msiobj_release(MSIOBJECTHDR *); -extern void msiobj_lock(MSIOBJECTHDR *); -extern void msiobj_unlock(MSIOBJECTHDR *); -extern MSIHANDLE msiobj_findhandle( MSIOBJECTHDR *hdr ); - -/* add this table to the list of cached tables in the database */ -extern void add_table(MSIDATABASE *db, MSITABLE *table); -extern void remove_table( MSIDATABASE *db, MSITABLE *table ); -extern void free_table( MSIDATABASE *db, MSITABLE *table ); -extern void free_cached_tables( MSIDATABASE *db ); -extern UINT find_cached_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **table); -extern UINT get_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **table); -extern UINT load_string_table( MSIDATABASE *db ); -extern UINT MSI_CommitTables( MSIDATABASE *db ); -extern HRESULT init_string_table( IStorage *stg ); - - -/* string table functions */ -extern BOOL msi_addstring( string_table *st, int string_no, const CHAR *data, int len, UINT refcount ); -extern BOOL msi_addstringW( string_table *st, int string_no, const WCHAR *data, int len, UINT refcount ); -extern UINT msi_id2stringW( string_table *st, UINT string_no, LPWSTR buffer, UINT *sz ); -extern UINT msi_id2stringA( string_table *st, UINT string_no, LPSTR buffer, UINT *sz ); - -extern LPWSTR MSI_makestring( MSIDATABASE *db, UINT stringid); -extern UINT msi_string2idW( string_table *st, LPCWSTR buffer, UINT *id ); -extern UINT msi_string2idA( string_table *st, LPCSTR str, UINT *id ); -extern string_table *msi_init_stringtable( int entries, UINT codepage ); -extern VOID msi_destroy_stringtable( string_table *st ); -extern UINT msi_string_count( string_table *st ); -extern UINT msi_id_refcount( string_table *st, UINT i ); -extern UINT msi_string_totalsize( string_table *st, UINT *last ); -extern UINT msi_strcmp( string_table *st, UINT lval, UINT rval, UINT *res ); -extern const WCHAR *msi_string_lookup_id( string_table *st, UINT id ); -extern UINT msi_string_get_codepage( string_table *st ); - - -extern UINT VIEW_find_column( MSIVIEW *view, LPCWSTR name, UINT *n ); - -extern BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name ); - -extern UINT read_raw_stream_data( MSIDATABASE*, LPCWSTR stname, - USHORT **pdata, UINT *psz ); - -/* action internals */ -extern UINT ACTION_DoTopLevelINSTALL( MSIPACKAGE *, LPCWSTR, LPCWSTR ); -extern void ACTION_free_package_structures( MSIPACKAGE* ); -extern UINT ACTION_DialogBox( MSIPACKAGE*, LPCWSTR); - -/* record internals */ -extern UINT MSI_RecordSetIStream( MSIRECORD *, unsigned int, IStream *); -extern UINT MSI_RecordGetIStream( MSIRECORD *, unsigned int, IStream **); -extern const WCHAR *MSI_RecordGetString( MSIRECORD *, unsigned int ); -extern MSIRECORD *MSI_CreateRecord( unsigned int ); -extern UINT MSI_RecordSetInteger( MSIRECORD *, unsigned int, int ); -extern UINT MSI_RecordSetStringW( MSIRECORD *, unsigned int, LPCWSTR ); -extern BOOL MSI_RecordIsNull( MSIRECORD *, unsigned int ); -extern UINT MSI_RecordGetStringW( MSIRECORD * , unsigned int, LPWSTR, DWORD *); -extern UINT MSI_RecordGetStringA( MSIRECORD *, unsigned int, LPSTR, DWORD *); -extern int MSI_RecordGetInteger( MSIRECORD *, unsigned int ); -extern UINT MSI_RecordReadStream( MSIRECORD *, unsigned int, char *, DWORD *); -extern unsigned int MSI_RecordGetFieldCount( MSIRECORD *rec ); - -/* stream internals */ -extern UINT get_raw_stream( MSIHANDLE hdb, LPCWSTR stname, IStream **stm ); -extern UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm ); -extern void enum_stream_names( IStorage *stg ); - -/* database internals */ -extern UINT MSI_OpenDatabaseW( LPCWSTR, LPCWSTR, MSIDATABASE ** ); -extern UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY ** ); -extern UINT MSI_OpenQuery( MSIDATABASE *, MSIQUERY **, LPCWSTR, ... ); -typedef UINT (*record_func)( MSIRECORD *rec, LPVOID param ); -extern UINT MSI_IterateRecords( MSIQUERY *, DWORD *, record_func, LPVOID ); - -/* view internals */ -extern UINT MSI_ViewExecute( MSIQUERY*, MSIRECORD * ); -extern UINT MSI_ViewFetch( MSIQUERY*, MSIRECORD ** ); -extern UINT MSI_ViewClose( MSIQUERY* ); - -/* package internals */ -extern MSIPACKAGE *MSI_CreatePackage( MSIDATABASE * ); -extern UINT MSI_OpenPackageW( LPCWSTR szPackage, MSIPACKAGE ** ); -extern UINT MSI_SetTargetPathW( MSIPACKAGE *, LPCWSTR, LPCWSTR ); -extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR ); -extern INT MSI_ProcessMessage( MSIPACKAGE *, INSTALLMESSAGE, MSIRECORD * ); -extern UINT MSI_GetPropertyW( MSIPACKAGE *, LPCWSTR, LPWSTR, DWORD * ); -extern MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *, LPCWSTR ); -extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR ); -extern UINT MSI_GetComponentStateW( MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE * ); -extern UINT MSI_GetFeatureStateW( MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE * ); -extern UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE*, LPCWSTR, INSTALLSTATE ); - -/* for deformating */ -extern UINT MSI_FormatRecordW(MSIPACKAGE* package, MSIRECORD* record, - LPWSTR buffer, DWORD *size); - -/* registry data encoding/decoding functions */ -extern BOOL unsquash_guid(LPCWSTR in, LPWSTR out); -extern BOOL squash_guid(LPCWSTR in, LPWSTR out); -extern BOOL encode_base85_guid(GUID *,LPWSTR); -extern BOOL decode_base85_guid(LPCWSTR,GUID*); -extern UINT MSIREG_OpenUninstallKey(LPCWSTR szProduct, HKEY* key, BOOL create); -extern UINT MSIREG_OpenUserProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create); -extern UINT MSIREG_OpenFeatures(HKEY* key); -extern UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create); -extern UINT MSIREG_OpenComponents(HKEY* key); -extern UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create); -extern UINT MSIREG_OpenComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create); -extern UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create); -extern UINT MSIREG_OpenUserFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create); -extern UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szProduct, HKEY* key, BOOL create); - -/* msi dialog interface */ -typedef VOID (*msi_dialog_event_handler)( MSIPACKAGE*, LPCWSTR, LPCWSTR, msi_dialog* ); -extern msi_dialog *msi_dialog_create( MSIPACKAGE*, LPCWSTR, msi_dialog_event_handler ); -extern UINT msi_dialog_run_message_loop( msi_dialog* ); -extern void msi_dialog_end_dialog( msi_dialog* ); -extern void msi_dialog_check_messages( HANDLE ); -extern void msi_dialog_do_preview( msi_dialog* ); -extern void msi_dialog_destroy( msi_dialog* ); -extern BOOL msi_dialog_register_class( void ); -extern void msi_dialog_unregister_class( void ); - -/* UI globals */ -extern INSTALLUILEVEL gUILevel; -extern HWND gUIhwnd; -extern INSTALLUI_HANDLERA gUIHandlerA; -extern INSTALLUI_HANDLERW gUIHandlerW; -extern DWORD gUIFilter; -extern LPVOID gUIContext; -extern WCHAR gszLogFile[MAX_PATH]; - -inline static char *strdupWtoA( LPCWSTR str ) -{ - LPSTR ret = NULL; - if (str) - { - DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL -); - if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) - WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL ); - } - return ret; -} - -inline static LPWSTR strdupAtoW( LPCSTR str ) -{ - LPWSTR ret = NULL; - if (str) - { - DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 ); - if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) - MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len ); - } - return ret; -} - -inline static LPWSTR strdupW( LPCWSTR src ) -{ - LPWSTR dest; - if (!src) return NULL; - dest = HeapAlloc(GetProcessHeap(), 0, (strlenW(src)+1)*sizeof(WCHAR)); - strcpyW(dest, src); - return dest; -} - -#endif /* __WINE_MSI_PRIVATE__ */ +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2002-2005 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_MSI_PRIVATE__ +#define __WINE_MSI_PRIVATE__ + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "msi.h" +#include "msiquery.h" +#include "objbase.h" +#include "objidl.h" +#include "wine/unicode.h" +#include "wine/list.h" + +#define MSI_DATASIZEMASK 0x00ff +#define MSITYPE_VALID 0x0100 +#define MSITYPE_STRING 0x0800 +#define MSITYPE_NULLABLE 0x1000 +#define MSITYPE_KEY 0x2000 + +#define MSITYPE_BINARY 0x8900 + +struct tagMSITABLE; +typedef struct tagMSITABLE MSITABLE; + +struct string_table; +typedef struct string_table string_table; + +struct tagMSIOBJECTHDR; +typedef struct tagMSIOBJECTHDR MSIOBJECTHDR; + +typedef VOID (*msihandledestructor)( MSIOBJECTHDR * ); + +struct tagMSIOBJECTHDR +{ + UINT magic; + UINT type; + DWORD refcount; + msihandledestructor destructor; + struct tagMSIOBJECTHDR *next; + struct tagMSIOBJECTHDR *prev; +}; + +typedef struct tagMSIDATABASE +{ + MSIOBJECTHDR hdr; + IStorage *storage; + string_table *strings; + LPWSTR mode; + MSITABLE *first_table, *last_table; +} MSIDATABASE; + +typedef struct tagMSIVIEW MSIVIEW; + +typedef struct tagMSIQUERY +{ + MSIOBJECTHDR hdr; + MSIVIEW *view; + UINT row; + MSIDATABASE *db; + struct list mem; +} MSIQUERY; + +/* maybe we can use a Variant instead of doing it ourselves? */ +typedef struct tagMSIFIELD +{ + UINT type; + union + { + INT iVal; + LPWSTR szwVal; + IStream *stream; + } u; +} MSIFIELD; + +typedef struct tagMSIRECORD +{ + MSIOBJECTHDR hdr; + UINT count; /* as passed to MsiCreateRecord */ + MSIFIELD fields[1]; /* nb. array size is count+1 */ +} MSIRECORD; + +typedef struct tagMSIVIEWOPS +{ + /* + * fetch_int - reads one integer from {row,col} in the table + * + * This function should be called after the execute method. + * Data returned by the function should not change until + * close or delete is called. + * To get a string value, query the database's string table with + * the integer value returned from this function. + */ + UINT (*fetch_int)( struct tagMSIVIEW *, UINT row, UINT col, UINT *val ); + + /* + * fetch_int - reads one integer from {row,col} in the table + * + * This function is similar to fetch_int, except fetches a + * stream instead of an integer. + */ + UINT (*fetch_stream)( struct tagMSIVIEW *, UINT row, UINT col, IStream **stm ); + + /* + * get_int - sets one integer at {row,col} in the table + * + * Similar semantics to fetch_int + */ + UINT (*set_int)( struct tagMSIVIEW *, UINT row, UINT col, UINT val ); + + /* + * Inserts a new, blank row into the database + * *row receives the number of the new row + */ + UINT (*insert_row)( struct tagMSIVIEW *, UINT *row ); + + /* + * execute - loads the underlying data into memory so it can be read + */ + UINT (*execute)( struct tagMSIVIEW *, MSIRECORD * ); + + /* + * close - clears the data read by execute from memory + */ + UINT (*close)( struct tagMSIVIEW * ); + + /* + * get_dimensions - returns the number of rows or columns in a table. + * + * The number of rows can only be queried after the execute method + * is called. The number of columns can be queried at any time. + */ + UINT (*get_dimensions)( struct tagMSIVIEW *, UINT *rows, UINT *cols ); + + /* + * get_column_info - returns the name and type of a specific column + * + * The name is HeapAlloc'ed by this function and should be freed by + * the caller. + * The column information can be queried at any time. + */ + UINT (*get_column_info)( struct tagMSIVIEW *, UINT n, LPWSTR *name, UINT *type ); + + /* + * modify - not yet implemented properly + */ + UINT (*modify)( struct tagMSIVIEW *, MSIMODIFY, MSIRECORD * ); + + /* + * delete - destroys the structure completely + */ + UINT (*delete)( struct tagMSIVIEW * ); + +} MSIVIEWOPS; + +struct tagMSIVIEW +{ + MSIOBJECTHDR hdr; + MSIVIEWOPS *ops; +}; + +struct msi_dialog_tag; +typedef struct msi_dialog_tag msi_dialog; + +typedef struct tagMSIPACKAGE +{ + MSIOBJECTHDR hdr; + MSIDATABASE *db; + struct tagMSIFEATURE *features; + UINT loaded_features; + struct tagMSIFOLDER *folders; + UINT loaded_folders; + struct tagMSICOMPONENT *components; + UINT loaded_components; + struct tagMSIFILE *files; + UINT loaded_files; + LPWSTR ActionFormat; + LPWSTR LastAction; + + LPWSTR *DeferredAction; + UINT DeferredActionCount; + + LPWSTR *CommitAction; + UINT CommitActionCount; + + struct tagMSIRUNNINGACTION *RunningAction; + UINT RunningActionCount; + + LPWSTR PackagePath; + + UINT CurrentInstallState; + msi_dialog *dialog; + LPWSTR next_dialog; + + BOOL ExecuteSequenceRun; +} MSIPACKAGE; + +typedef struct tagMSIPREVIEW +{ + MSIOBJECTHDR hdr; + MSIPACKAGE *package; + msi_dialog *dialog; +} MSIPREVIEW; + +#define MSIHANDLETYPE_ANY 0 +#define MSIHANDLETYPE_DATABASE 1 +#define MSIHANDLETYPE_SUMMARYINFO 2 +#define MSIHANDLETYPE_VIEW 3 +#define MSIHANDLETYPE_RECORD 4 +#define MSIHANDLETYPE_PACKAGE 5 +#define MSIHANDLETYPE_PREVIEW 6 + +#define MSI_MAJORVERSION 2 +#define MSI_MINORVERSION 0 +#define MSI_BUILDNUMBER 2600 + +#define GUID_SIZE 39 + +#define MSIHANDLE_MAGIC 0x4d434923 +#define MSIMAXHANDLES 0xf0 + +#define MSISUMINFO_OFFSET 0x30LL + +DEFINE_GUID(CLSID_IMsiServer, 0x000C101C,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); +DEFINE_GUID(CLSID_IMsiServerX1, 0x000C103E,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); +DEFINE_GUID(CLSID_IMsiServerX2, 0x000C1090,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); +DEFINE_GUID(CLSID_IMsiServerX3, 0x000C1094,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); + +DEFINE_GUID(CLSID_IMsiServerMessage, 0x000C101D,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); + + +/* handle functions */ +extern void *msihandle2msiinfo(MSIHANDLE handle, UINT type); +extern MSIHANDLE alloc_msihandle( MSIOBJECTHDR * ); +extern void *alloc_msiobject(UINT type, UINT size, msihandledestructor destroy ); +extern void msiobj_addref(MSIOBJECTHDR *); +extern int msiobj_release(MSIOBJECTHDR *); +extern void msiobj_lock(MSIOBJECTHDR *); +extern void msiobj_unlock(MSIOBJECTHDR *); +extern MSIHANDLE msiobj_findhandle( MSIOBJECTHDR *hdr ); + +/* add this table to the list of cached tables in the database */ +extern void add_table(MSIDATABASE *db, MSITABLE *table); +extern void remove_table( MSIDATABASE *db, MSITABLE *table ); +extern void free_table( MSIDATABASE *db, MSITABLE *table ); +extern void free_cached_tables( MSIDATABASE *db ); +extern UINT find_cached_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **table); +extern UINT get_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **table); +extern UINT load_string_table( MSIDATABASE *db ); +extern UINT MSI_CommitTables( MSIDATABASE *db ); +extern HRESULT init_string_table( IStorage *stg ); + + +/* string table functions */ +extern BOOL msi_addstring( string_table *st, int string_no, const CHAR *data, int len, UINT refcount ); +extern BOOL msi_addstringW( string_table *st, int string_no, const WCHAR *data, int len, UINT refcount ); +extern UINT msi_id2stringW( string_table *st, UINT string_no, LPWSTR buffer, UINT *sz ); +extern UINT msi_id2stringA( string_table *st, UINT string_no, LPSTR buffer, UINT *sz ); + +extern LPWSTR MSI_makestring( MSIDATABASE *db, UINT stringid); +extern UINT msi_string2idW( string_table *st, LPCWSTR buffer, UINT *id ); +extern UINT msi_string2idA( string_table *st, LPCSTR str, UINT *id ); +extern string_table *msi_init_stringtable( int entries, UINT codepage ); +extern VOID msi_destroy_stringtable( string_table *st ); +extern UINT msi_string_count( string_table *st ); +extern UINT msi_id_refcount( string_table *st, UINT i ); +extern UINT msi_string_totalsize( string_table *st, UINT *last ); +extern UINT msi_strcmp( string_table *st, UINT lval, UINT rval, UINT *res ); +extern const WCHAR *msi_string_lookup_id( string_table *st, UINT id ); +extern UINT msi_string_get_codepage( string_table *st ); + + +extern UINT VIEW_find_column( MSIVIEW *view, LPCWSTR name, UINT *n ); + +extern BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name ); + +extern UINT read_raw_stream_data( MSIDATABASE*, LPCWSTR stname, + USHORT **pdata, UINT *psz ); + +/* action internals */ +extern UINT ACTION_DoTopLevelINSTALL( MSIPACKAGE *, LPCWSTR, LPCWSTR ); +extern void ACTION_free_package_structures( MSIPACKAGE* ); +extern UINT ACTION_DialogBox( MSIPACKAGE*, LPCWSTR); + +/* record internals */ +extern UINT MSI_RecordSetIStream( MSIRECORD *, unsigned int, IStream *); +extern UINT MSI_RecordGetIStream( MSIRECORD *, unsigned int, IStream **); +extern const WCHAR *MSI_RecordGetString( MSIRECORD *, unsigned int ); +extern MSIRECORD *MSI_CreateRecord( unsigned int ); +extern UINT MSI_RecordSetInteger( MSIRECORD *, unsigned int, int ); +extern UINT MSI_RecordSetStringW( MSIRECORD *, unsigned int, LPCWSTR ); +extern BOOL MSI_RecordIsNull( MSIRECORD *, unsigned int ); +extern UINT MSI_RecordGetStringW( MSIRECORD * , unsigned int, LPWSTR, DWORD *); +extern UINT MSI_RecordGetStringA( MSIRECORD *, unsigned int, LPSTR, DWORD *); +extern int MSI_RecordGetInteger( MSIRECORD *, unsigned int ); +extern UINT MSI_RecordReadStream( MSIRECORD *, unsigned int, char *, DWORD *); +extern unsigned int MSI_RecordGetFieldCount( MSIRECORD *rec ); + +/* stream internals */ +extern UINT get_raw_stream( MSIHANDLE hdb, LPCWSTR stname, IStream **stm ); +extern UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm ); +extern void enum_stream_names( IStorage *stg ); + +/* database internals */ +extern UINT MSI_OpenDatabaseW( LPCWSTR, LPCWSTR, MSIDATABASE ** ); +extern UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY ** ); +extern UINT MSI_OpenQuery( MSIDATABASE *, MSIQUERY **, LPCWSTR, ... ); +typedef UINT (*record_func)( MSIRECORD *rec, LPVOID param ); +extern UINT MSI_IterateRecords( MSIQUERY *, DWORD *, record_func, LPVOID ); + +/* view internals */ +extern UINT MSI_ViewExecute( MSIQUERY*, MSIRECORD * ); +extern UINT MSI_ViewFetch( MSIQUERY*, MSIRECORD ** ); +extern UINT MSI_ViewClose( MSIQUERY* ); + +/* package internals */ +extern MSIPACKAGE *MSI_CreatePackage( MSIDATABASE * ); +extern UINT MSI_OpenPackageW( LPCWSTR szPackage, MSIPACKAGE ** ); +extern UINT MSI_SetTargetPathW( MSIPACKAGE *, LPCWSTR, LPCWSTR ); +extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR ); +extern INT MSI_ProcessMessage( MSIPACKAGE *, INSTALLMESSAGE, MSIRECORD * ); +extern UINT MSI_GetPropertyW( MSIPACKAGE *, LPCWSTR, LPWSTR, DWORD * ); +extern MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *, LPCWSTR ); +extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR ); +extern UINT MSI_GetComponentStateW( MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE * ); +extern UINT MSI_GetFeatureStateW( MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE * ); +extern UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE*, LPCWSTR, INSTALLSTATE ); + +/* for deformating */ +extern UINT MSI_FormatRecordW(MSIPACKAGE* package, MSIRECORD* record, + LPWSTR buffer, DWORD *size); + +/* registry data encoding/decoding functions */ +extern BOOL unsquash_guid(LPCWSTR in, LPWSTR out); +extern BOOL squash_guid(LPCWSTR in, LPWSTR out); +extern BOOL encode_base85_guid(GUID *,LPWSTR); +extern BOOL decode_base85_guid(LPCWSTR,GUID*); +extern UINT MSIREG_OpenUninstallKey(LPCWSTR szProduct, HKEY* key, BOOL create); +extern UINT MSIREG_OpenUserProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create); +extern UINT MSIREG_OpenFeatures(HKEY* key); +extern UINT MSIREG_OpenFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create); +extern UINT MSIREG_OpenComponents(HKEY* key); +extern UINT MSIREG_OpenUserComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create); +extern UINT MSIREG_OpenComponentsKey(LPCWSTR szComponent, HKEY* key, BOOL create); +extern UINT MSIREG_OpenProductsKey(LPCWSTR szProduct, HKEY* key, BOOL create); +extern UINT MSIREG_OpenUserFeaturesKey(LPCWSTR szProduct, HKEY* key, BOOL create); +extern UINT MSIREG_OpenUpgradeCodesKey(LPCWSTR szProduct, HKEY* key, BOOL create); + +/* msi dialog interface */ +typedef VOID (*msi_dialog_event_handler)( MSIPACKAGE*, LPCWSTR, LPCWSTR, msi_dialog* ); +extern msi_dialog *msi_dialog_create( MSIPACKAGE*, LPCWSTR, msi_dialog_event_handler ); +extern UINT msi_dialog_run_message_loop( msi_dialog* ); +extern void msi_dialog_end_dialog( msi_dialog* ); +extern void msi_dialog_check_messages( HANDLE ); +extern void msi_dialog_do_preview( msi_dialog* ); +extern void msi_dialog_destroy( msi_dialog* ); +extern BOOL msi_dialog_register_class( void ); +extern void msi_dialog_unregister_class( void ); + +/* UI globals */ +extern INSTALLUILEVEL gUILevel; +extern HWND gUIhwnd; +extern INSTALLUI_HANDLERA gUIHandlerA; +extern INSTALLUI_HANDLERW gUIHandlerW; +extern DWORD gUIFilter; +extern LPVOID gUIContext; +extern WCHAR gszLogFile[MAX_PATH]; + +inline static char *strdupWtoA( LPCWSTR str ) +{ + LPSTR ret = NULL; + if (str) + { + DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL +); + if ((ret = HeapAlloc( GetProcessHeap(), 0, len ))) + WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL ); + } + return ret; +} + +inline static LPWSTR strdupAtoW( LPCSTR str ) +{ + LPWSTR ret = NULL; + if (str) + { + DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 ); + if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) + MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len ); + } + return ret; +} + +inline static LPWSTR strdupW( LPCWSTR src ) +{ + LPWSTR dest; + if (!src) return NULL; + dest = HeapAlloc(GetProcessHeap(), 0, (strlenW(src)+1)*sizeof(WCHAR)); + strcpyW(dest, src); + return dest; +} + +#endif /* __WINE_MSI_PRIVATE__ */ diff --git a/reactos/lib/msi/msiquery.c b/reactos/lib/msi/msiquery.c index cdd4457e612..f833847c840 100644 --- a/reactos/lib/msi/msiquery.c +++ b/reactos/lib/msi/msiquery.c @@ -1,708 +1,708 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2002-2005 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "wine/debug.h" -#include "wine/unicode.h" -#include "msi.h" -#include "msiquery.h" -#include "objbase.h" -#include "objidl.h" -#include "msipriv.h" -#include "winnls.h" - -#include "query.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -void MSI_CloseView( MSIOBJECTHDR *arg ) -{ - MSIQUERY *query = (MSIQUERY*) arg; - struct list *ptr, *t; - - if( query->view && query->view->ops->delete ) - query->view->ops->delete( query->view ); - msiobj_release( &query->db->hdr ); - - LIST_FOR_EACH_SAFE( ptr, t, &query->mem ) - { - HeapFree( GetProcessHeap(), 0, ptr ); - } -} - -UINT VIEW_find_column( MSIVIEW *table, LPCWSTR name, UINT *n ) -{ - LPWSTR col_name; - UINT i, count, r; - - r = table->ops->get_dimensions( table, NULL, &count ); - if( r != ERROR_SUCCESS ) - return r; - - for( i=1; i<=count; i++ ) - { - INT x; - - col_name = NULL; - r = table->ops->get_column_info( table, i, &col_name, NULL ); - if( r != ERROR_SUCCESS ) - return r; - x = lstrcmpW( name, col_name ); - HeapFree( GetProcessHeap(), 0, col_name ); - if( !x ) - { - *n = i; - return ERROR_SUCCESS; - } - } - - return ERROR_INVALID_PARAMETER; -} - -UINT WINAPI MsiDatabaseOpenViewA(MSIHANDLE hdb, - LPCSTR szQuery, MSIHANDLE *phView) -{ - UINT r; - LPWSTR szwQuery; - - TRACE("%ld %s %p\n", hdb, debugstr_a(szQuery), phView); - - if( szQuery ) - { - szwQuery = strdupAtoW( szQuery ); - if( !szwQuery ) - return ERROR_FUNCTION_FAILED; - } - else - szwQuery = NULL; - - r = MsiDatabaseOpenViewW( hdb, szwQuery, phView); - - HeapFree( GetProcessHeap(), 0, szwQuery ); - return r; -} - -UINT MSI_DatabaseOpenViewW(MSIDATABASE *db, - LPCWSTR szQuery, MSIQUERY **pView) -{ - MSIQUERY *query; - UINT r; - - TRACE("%s %p\n", debugstr_w(szQuery), pView); - - if( !szQuery) - return ERROR_INVALID_PARAMETER; - - /* pre allocate a handle to hold a pointer to the view */ - query = alloc_msiobject( MSIHANDLETYPE_VIEW, sizeof (MSIQUERY), - MSI_CloseView ); - if( !query ) - return ERROR_FUNCTION_FAILED; - - msiobj_addref( &db->hdr ); - query->row = 0; - query->db = db; - query->view = NULL; - list_init( &query->mem ); - - r = MSI_ParseSQL( db, szQuery, &query->view, &query->mem ); - if( r == ERROR_SUCCESS ) - { - msiobj_addref( &query->hdr ); - *pView = query; - } - - msiobj_release( &query->hdr ); - return r; -} - -UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... ) -{ - LPWSTR szQuery; - LPCWSTR p; - UINT sz, rc; - va_list va; - - /* figure out how much space we need to allocate */ - va_start(va, fmt); - sz = lstrlenW(fmt) + 1; - p = fmt; - while (*p) - { - p = strchrW(p, '%'); - if (!p) - break; - p++; - switch (*p) - { - case 's': /* a string */ - sz += lstrlenW(va_arg(va,LPCWSTR)); - break; - case 'd': - case 'i': /* an integer -2147483648 seems to be longest */ - sz += 3*sizeof(int); - (void)va_arg(va,int); - break; - case '%': /* a single % - leave it alone */ - break; - default: - FIXME("Unhandled character type %c\n",*p); - } - p++; - } - va_end(va); - - /* construct the string */ - szQuery = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR)); - va_start(va, fmt); - vsnprintfW(szQuery, sz, fmt, va); - va_end(va); - - /* perform the query */ - rc = MSI_DatabaseOpenViewW(db, szQuery, view); - HeapFree(GetProcessHeap(), 0, szQuery); - return rc; -} - -UINT MSI_IterateRecords( MSIQUERY *view, DWORD *count, - record_func func, LPVOID param ) -{ - MSIRECORD *rec = NULL; - UINT r, n = 0, max = 0; - - r = MSI_ViewExecute( view, NULL ); - if( r != ERROR_SUCCESS ) - return r; - - if( count ) - max = *count; - - /* iterate a query */ - for( n = 0; (max == 0) || (n < max); n++ ) - { - r = MSI_ViewFetch( view, &rec ); - if( r != ERROR_SUCCESS ) - break; - r = func( rec, param ); - msiobj_release( &rec->hdr ); - if( r != ERROR_SUCCESS ) - break; - } - - MSI_ViewClose( view ); - - if( count ) - *count = n; - - if( r == ERROR_NO_MORE_ITEMS ) - r = ERROR_SUCCESS; - - return r; -} - -UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb, - LPCWSTR szQuery, MSIHANDLE *phView) -{ - MSIDATABASE *db; - MSIQUERY *query = NULL; - UINT ret; - - TRACE("%s %p\n", debugstr_w(szQuery), phView); - - db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE ); - if( !db ) - return ERROR_INVALID_HANDLE; - - ret = MSI_DatabaseOpenViewW( db, szQuery, &query ); - if( ret == ERROR_SUCCESS ) - { - *phView = alloc_msihandle( &query->hdr ); - msiobj_release( &query->hdr ); - } - msiobj_release( &db->hdr ); - - return ret; -} - -UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec) -{ - MSIVIEW *view; - MSIRECORD *rec; - UINT row_count = 0, col_count = 0, i, ival, ret, type; - - TRACE("%p %p\n", query, prec ); - - view = query->view; - if( !view ) - return ERROR_FUNCTION_FAILED; - - ret = view->ops->get_dimensions( view, &row_count, &col_count ); - if( ret ) - return ret; - if( !col_count ) - return ERROR_INVALID_PARAMETER; - - if( query->row >= row_count ) - return ERROR_NO_MORE_ITEMS; - - rec = MSI_CreateRecord( col_count ); - if( !rec ) - return ERROR_FUNCTION_FAILED; - - for( i=1; i<=col_count; i++ ) - { - ret = view->ops->get_column_info( view, i, NULL, &type ); - if( ret ) - { - ERR("Error getting column type for %d\n", i ); - continue; - } - if (( type != MSITYPE_BINARY) && (type != (MSITYPE_BINARY | - MSITYPE_NULLABLE))) - { - ret = view->ops->fetch_int( view, query->row, i, &ival ); - if( ret ) - { - ERR("Error fetching data for %d\n", i ); - continue; - } - if( ! (type & MSITYPE_VALID ) ) - ERR("Invalid type!\n"); - - /* check if it's nul (0) - if so, don't set anything */ - if( !ival ) - continue; - - if( type & MSITYPE_STRING ) - { - LPWSTR sval; - - sval = MSI_makestring( query->db, ival ); - MSI_RecordSetStringW( rec, i, sval ); - HeapFree( GetProcessHeap(), 0, sval ); - } - else - { - if( (type & MSI_DATASIZEMASK) == 2 ) - MSI_RecordSetInteger( rec, i, ival - (1<<15) ); - else - MSI_RecordSetInteger( rec, i, ival - (1<<31) ); - } - } - else - { - IStream *stm = NULL; - - ret = view->ops->fetch_stream( view, query->row, i, &stm ); - if( ( ret == ERROR_SUCCESS ) && stm ) - { - MSI_RecordSetIStream( rec, i, stm ); - IStream_Release( stm ); - } - else - ERR("failed to get stream\n"); - } - } - query->row ++; - - *prec = rec; - - return ERROR_SUCCESS; -} - -UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record) -{ - MSIQUERY *query; - MSIRECORD *rec = NULL; - UINT ret; - - TRACE("%ld %p\n", hView, record); - - query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); - if( !query ) - return ERROR_INVALID_HANDLE; - ret = MSI_ViewFetch( query, &rec ); - if( ret == ERROR_SUCCESS ) - { - *record = alloc_msihandle( &rec->hdr ); - msiobj_release( &rec->hdr ); - } - msiobj_release( &query->hdr ); - return ret; -} - -UINT MSI_ViewClose(MSIQUERY *query) -{ - MSIVIEW *view; - - TRACE("%p\n", query ); - - view = query->view; - if( !view ) - return ERROR_FUNCTION_FAILED; - if( !view->ops->close ) - return ERROR_FUNCTION_FAILED; - - return view->ops->close( view ); -} - -UINT WINAPI MsiViewClose(MSIHANDLE hView) -{ - MSIQUERY *query; - UINT ret; - - TRACE("%ld\n", hView ); - - query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); - if( !query ) - return ERROR_INVALID_HANDLE; - - ret = MSI_ViewClose( query ); - msiobj_release( &query->hdr ); - return ret; -} - -UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec ) -{ - MSIVIEW *view; - - TRACE("%p %p\n", query, rec); - - view = query->view; - if( !view ) - return ERROR_FUNCTION_FAILED; - if( !view->ops->execute ) - return ERROR_FUNCTION_FAILED; - query->row = 0; - - return view->ops->execute( view, rec ); -} - -UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec) -{ - MSIQUERY *query; - MSIRECORD *rec = NULL; - UINT ret; - - TRACE("%ld %ld\n", hView, hRec); - - query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); - if( !query ) - return ERROR_INVALID_HANDLE; - - if( hRec ) - { - rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD ); - if( !rec ) - { - ret = ERROR_INVALID_HANDLE; - goto out; - } - } - - msiobj_lock( &rec->hdr ); - ret = MSI_ViewExecute( query, rec ); - msiobj_unlock( &rec->hdr ); - -out: - msiobj_release( &query->hdr ); - if( rec ) - msiobj_release( &rec->hdr ); - - return ret; -} - -UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec) -{ - MSIVIEW *view = NULL; - MSIQUERY *query = NULL; - MSIRECORD *rec = NULL; - UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type; - LPWSTR name; - - TRACE("%ld %d %p\n", hView, info, hRec); - - query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); - if( !query ) - return ERROR_INVALID_HANDLE; - - view = query->view; - if( !view ) - goto out; - - if( !view->ops->get_dimensions ) - goto out; - - r = view->ops->get_dimensions( view, NULL, &count ); - if( r ) - goto out; - if( !count ) - { - r = ERROR_INVALID_PARAMETER; - goto out; - } - - rec = MSI_CreateRecord( count ); - if( !rec ) - { - r = ERROR_FUNCTION_FAILED; - goto out; - } - - for( i=0; i<count; i++ ) - { - name = NULL; - r = view->ops->get_column_info( view, i+1, &name, &type ); - if( r != ERROR_SUCCESS ) - continue; - MSI_RecordSetStringW( rec, i+1, name ); - HeapFree( GetProcessHeap(), 0, name ); - } - - *hRec = alloc_msihandle( &rec->hdr ); - -out: - msiobj_release( &query->hdr ); - if( rec ) - msiobj_release( &rec->hdr ); - - return r; -} - -UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode, - MSIHANDLE hRecord) -{ - MSIVIEW *view = NULL; - MSIQUERY *query = NULL; - MSIRECORD *rec = NULL; - UINT r = ERROR_FUNCTION_FAILED; - - TRACE("%ld %x %ld\n", hView, eModifyMode, hRecord); - - query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); - if( !query ) - return ERROR_INVALID_HANDLE; - - view = query->view; - if( !view ) - goto out; - - if( !view->ops->modify ) - goto out; - - rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD ); - if( !rec ) - { - r = ERROR_INVALID_HANDLE; - goto out; - } - - r = view->ops->modify( view, eModifyMode, rec ); - -out: - msiobj_release( &query->hdr ); - if( rec ) - msiobj_release( &rec->hdr ); - - return r; -} - -UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb, - LPCSTR szTransformFile, int iErrorCond) -{ - FIXME("%ld %s %d\n", hdb, debugstr_a(szTransformFile), iErrorCond); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb, - LPCWSTR szTransformFile, int iErrorCond) -{ - FIXME("%ld %s %d\n", hdb, debugstr_w(szTransformFile), iErrorCond); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref, - LPCSTR szTransformFile, int iReserved1, int iReserved2 ) -{ - FIXME("%ld %ld %s %d %d\n", hdb, hdbref, - debugstr_a(szTransformFile), iReserved1, iReserved2); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref, - LPCWSTR szTransformFile, int iReserved1, int iReserved2 ) -{ - FIXME("%ld %ld %s %d %d\n", hdb, hdbref, - debugstr_w(szTransformFile), iReserved1, iReserved2); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb ) -{ - MSIDATABASE *db; - UINT r; - - TRACE("%ld\n", hdb); - - db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE ); - if( !db ) - return ERROR_INVALID_HANDLE; - - /* FIXME: lock the database */ - - r = MSI_CommitTables( db ); - - /* FIXME: unlock the database */ - - msiobj_release( &db->hdr ); - - return r; -} - -struct msi_primary_key_record_info -{ - DWORD n; - MSIRECORD *rec; -}; - -static UINT msi_primary_key_iterator( MSIRECORD *rec, LPVOID param ) -{ - struct msi_primary_key_record_info *info = param; - LPCWSTR name; - DWORD type; - - type = MSI_RecordGetInteger( rec, 4 ); - if( type & MSITYPE_KEY ) - { - info->n++; - if( info->rec ) - { - name = MSI_RecordGetString( rec, 3 ); - MSI_RecordSetStringW( info->rec, info->n, name ); - } - } - - return ERROR_SUCCESS; -} - -UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db, - LPCWSTR table, MSIRECORD **prec ) -{ - static const WCHAR sql[] = { - 's','e','l','e','c','t',' ','*',' ', - 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ', - 'w','h','e','r','e',' ', - '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 }; - struct msi_primary_key_record_info info; - MSIQUERY *query = NULL; - MSIVIEW *view; - UINT r; - - r = MSI_OpenQuery( db, &query, sql, table ); - if( r != ERROR_SUCCESS ) - return r; - - view = query->view; - - /* count the number of primary key records */ - info.n = 0; - info.rec = 0; - r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info ); - if( r == ERROR_SUCCESS ) - { - TRACE("Found %ld primary keys\n", info.n ); - - /* allocate a record and fill in the names of the tables */ - info.rec = MSI_CreateRecord( info.n ); - info.n = 0; - r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info ); - if( r == ERROR_SUCCESS ) - *prec = info.rec; - else - msiobj_release( &info.rec->hdr ); - } - msiobj_release( &query->hdr ); - - return r; -} - -UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb, - LPCWSTR table, MSIHANDLE* phRec ) -{ - MSIRECORD *rec = NULL; - MSIDATABASE *db; - UINT r; - - TRACE("%ld %s %p\n", hdb, debugstr_w(table), phRec); - - db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE ); - if( !db ) - return ERROR_INVALID_HANDLE; - - r = MSI_DatabaseGetPrimaryKeys( db, table, &rec ); - if( r == ERROR_SUCCESS ) - { - *phRec = alloc_msihandle( &rec->hdr ); - msiobj_release( &rec->hdr ); - } - msiobj_release( &db->hdr ); - - return r; -} - -UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb, - LPCSTR table, MSIHANDLE* phRec) -{ - LPWSTR szwTable = NULL; - UINT r; - - TRACE("%ld %s %p\n", hdb, debugstr_a(table), phRec); - - if( table ) - { - szwTable = strdupAtoW( table ); - if( !szwTable ) - return ERROR_OUTOFMEMORY; - } - r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec ); - HeapFree( GetProcessHeap(), 0, szwTable ); - - return r; -} - -UINT WINAPI MsiDatabaseIsTablePersistentA( - MSIHANDLE hDatabase, LPSTR szTableName) -{ - FIXME("%lx %s\n", hDatabase, debugstr_a(szTableName)); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -UINT WINAPI MsiDatabaseIsTablePersistentW( - MSIHANDLE hDatabase, LPWSTR szTableName) -{ - FIXME("%lx %s\n", hDatabase, debugstr_w(szTableName)); - return ERROR_CALL_NOT_IMPLEMENTED; -} +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2002-2005 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/debug.h" +#include "wine/unicode.h" +#include "msi.h" +#include "msiquery.h" +#include "objbase.h" +#include "objidl.h" +#include "msipriv.h" +#include "winnls.h" + +#include "query.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +void MSI_CloseView( MSIOBJECTHDR *arg ) +{ + MSIQUERY *query = (MSIQUERY*) arg; + struct list *ptr, *t; + + if( query->view && query->view->ops->delete ) + query->view->ops->delete( query->view ); + msiobj_release( &query->db->hdr ); + + LIST_FOR_EACH_SAFE( ptr, t, &query->mem ) + { + HeapFree( GetProcessHeap(), 0, ptr ); + } +} + +UINT VIEW_find_column( MSIVIEW *table, LPCWSTR name, UINT *n ) +{ + LPWSTR col_name; + UINT i, count, r; + + r = table->ops->get_dimensions( table, NULL, &count ); + if( r != ERROR_SUCCESS ) + return r; + + for( i=1; i<=count; i++ ) + { + INT x; + + col_name = NULL; + r = table->ops->get_column_info( table, i, &col_name, NULL ); + if( r != ERROR_SUCCESS ) + return r; + x = lstrcmpW( name, col_name ); + HeapFree( GetProcessHeap(), 0, col_name ); + if( !x ) + { + *n = i; + return ERROR_SUCCESS; + } + } + + return ERROR_INVALID_PARAMETER; +} + +UINT WINAPI MsiDatabaseOpenViewA(MSIHANDLE hdb, + LPCSTR szQuery, MSIHANDLE *phView) +{ + UINT r; + LPWSTR szwQuery; + + TRACE("%ld %s %p\n", hdb, debugstr_a(szQuery), phView); + + if( szQuery ) + { + szwQuery = strdupAtoW( szQuery ); + if( !szwQuery ) + return ERROR_FUNCTION_FAILED; + } + else + szwQuery = NULL; + + r = MsiDatabaseOpenViewW( hdb, szwQuery, phView); + + HeapFree( GetProcessHeap(), 0, szwQuery ); + return r; +} + +UINT MSI_DatabaseOpenViewW(MSIDATABASE *db, + LPCWSTR szQuery, MSIQUERY **pView) +{ + MSIQUERY *query; + UINT r; + + TRACE("%s %p\n", debugstr_w(szQuery), pView); + + if( !szQuery) + return ERROR_INVALID_PARAMETER; + + /* pre allocate a handle to hold a pointer to the view */ + query = alloc_msiobject( MSIHANDLETYPE_VIEW, sizeof (MSIQUERY), + MSI_CloseView ); + if( !query ) + return ERROR_FUNCTION_FAILED; + + msiobj_addref( &db->hdr ); + query->row = 0; + query->db = db; + query->view = NULL; + list_init( &query->mem ); + + r = MSI_ParseSQL( db, szQuery, &query->view, &query->mem ); + if( r == ERROR_SUCCESS ) + { + msiobj_addref( &query->hdr ); + *pView = query; + } + + msiobj_release( &query->hdr ); + return r; +} + +UINT MSI_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... ) +{ + LPWSTR szQuery; + LPCWSTR p; + UINT sz, rc; + va_list va; + + /* figure out how much space we need to allocate */ + va_start(va, fmt); + sz = lstrlenW(fmt) + 1; + p = fmt; + while (*p) + { + p = strchrW(p, '%'); + if (!p) + break; + p++; + switch (*p) + { + case 's': /* a string */ + sz += lstrlenW(va_arg(va,LPCWSTR)); + break; + case 'd': + case 'i': /* an integer -2147483648 seems to be longest */ + sz += 3*sizeof(int); + (void)va_arg(va,int); + break; + case '%': /* a single % - leave it alone */ + break; + default: + FIXME("Unhandled character type %c\n",*p); + } + p++; + } + va_end(va); + + /* construct the string */ + szQuery = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR)); + va_start(va, fmt); + vsnprintfW(szQuery, sz, fmt, va); + va_end(va); + + /* perform the query */ + rc = MSI_DatabaseOpenViewW(db, szQuery, view); + HeapFree(GetProcessHeap(), 0, szQuery); + return rc; +} + +UINT MSI_IterateRecords( MSIQUERY *view, DWORD *count, + record_func func, LPVOID param ) +{ + MSIRECORD *rec = NULL; + UINT r, n = 0, max = 0; + + r = MSI_ViewExecute( view, NULL ); + if( r != ERROR_SUCCESS ) + return r; + + if( count ) + max = *count; + + /* iterate a query */ + for( n = 0; (max == 0) || (n < max); n++ ) + { + r = MSI_ViewFetch( view, &rec ); + if( r != ERROR_SUCCESS ) + break; + r = func( rec, param ); + msiobj_release( &rec->hdr ); + if( r != ERROR_SUCCESS ) + break; + } + + MSI_ViewClose( view ); + + if( count ) + *count = n; + + if( r == ERROR_NO_MORE_ITEMS ) + r = ERROR_SUCCESS; + + return r; +} + +UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb, + LPCWSTR szQuery, MSIHANDLE *phView) +{ + MSIDATABASE *db; + MSIQUERY *query = NULL; + UINT ret; + + TRACE("%s %p\n", debugstr_w(szQuery), phView); + + db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE ); + if( !db ) + return ERROR_INVALID_HANDLE; + + ret = MSI_DatabaseOpenViewW( db, szQuery, &query ); + if( ret == ERROR_SUCCESS ) + { + *phView = alloc_msihandle( &query->hdr ); + msiobj_release( &query->hdr ); + } + msiobj_release( &db->hdr ); + + return ret; +} + +UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec) +{ + MSIVIEW *view; + MSIRECORD *rec; + UINT row_count = 0, col_count = 0, i, ival, ret, type; + + TRACE("%p %p\n", query, prec ); + + view = query->view; + if( !view ) + return ERROR_FUNCTION_FAILED; + + ret = view->ops->get_dimensions( view, &row_count, &col_count ); + if( ret ) + return ret; + if( !col_count ) + return ERROR_INVALID_PARAMETER; + + if( query->row >= row_count ) + return ERROR_NO_MORE_ITEMS; + + rec = MSI_CreateRecord( col_count ); + if( !rec ) + return ERROR_FUNCTION_FAILED; + + for( i=1; i<=col_count; i++ ) + { + ret = view->ops->get_column_info( view, i, NULL, &type ); + if( ret ) + { + ERR("Error getting column type for %d\n", i ); + continue; + } + if (( type != MSITYPE_BINARY) && (type != (MSITYPE_BINARY | + MSITYPE_NULLABLE))) + { + ret = view->ops->fetch_int( view, query->row, i, &ival ); + if( ret ) + { + ERR("Error fetching data for %d\n", i ); + continue; + } + if( ! (type & MSITYPE_VALID ) ) + ERR("Invalid type!\n"); + + /* check if it's nul (0) - if so, don't set anything */ + if( !ival ) + continue; + + if( type & MSITYPE_STRING ) + { + LPWSTR sval; + + sval = MSI_makestring( query->db, ival ); + MSI_RecordSetStringW( rec, i, sval ); + HeapFree( GetProcessHeap(), 0, sval ); + } + else + { + if( (type & MSI_DATASIZEMASK) == 2 ) + MSI_RecordSetInteger( rec, i, ival - (1<<15) ); + else + MSI_RecordSetInteger( rec, i, ival - (1<<31) ); + } + } + else + { + IStream *stm = NULL; + + ret = view->ops->fetch_stream( view, query->row, i, &stm ); + if( ( ret == ERROR_SUCCESS ) && stm ) + { + MSI_RecordSetIStream( rec, i, stm ); + IStream_Release( stm ); + } + else + ERR("failed to get stream\n"); + } + } + query->row ++; + + *prec = rec; + + return ERROR_SUCCESS; +} + +UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record) +{ + MSIQUERY *query; + MSIRECORD *rec = NULL; + UINT ret; + + TRACE("%ld %p\n", hView, record); + + query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); + if( !query ) + return ERROR_INVALID_HANDLE; + ret = MSI_ViewFetch( query, &rec ); + if( ret == ERROR_SUCCESS ) + { + *record = alloc_msihandle( &rec->hdr ); + msiobj_release( &rec->hdr ); + } + msiobj_release( &query->hdr ); + return ret; +} + +UINT MSI_ViewClose(MSIQUERY *query) +{ + MSIVIEW *view; + + TRACE("%p\n", query ); + + view = query->view; + if( !view ) + return ERROR_FUNCTION_FAILED; + if( !view->ops->close ) + return ERROR_FUNCTION_FAILED; + + return view->ops->close( view ); +} + +UINT WINAPI MsiViewClose(MSIHANDLE hView) +{ + MSIQUERY *query; + UINT ret; + + TRACE("%ld\n", hView ); + + query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); + if( !query ) + return ERROR_INVALID_HANDLE; + + ret = MSI_ViewClose( query ); + msiobj_release( &query->hdr ); + return ret; +} + +UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec ) +{ + MSIVIEW *view; + + TRACE("%p %p\n", query, rec); + + view = query->view; + if( !view ) + return ERROR_FUNCTION_FAILED; + if( !view->ops->execute ) + return ERROR_FUNCTION_FAILED; + query->row = 0; + + return view->ops->execute( view, rec ); +} + +UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec) +{ + MSIQUERY *query; + MSIRECORD *rec = NULL; + UINT ret; + + TRACE("%ld %ld\n", hView, hRec); + + query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); + if( !query ) + return ERROR_INVALID_HANDLE; + + if( hRec ) + { + rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD ); + if( !rec ) + { + ret = ERROR_INVALID_HANDLE; + goto out; + } + } + + msiobj_lock( &rec->hdr ); + ret = MSI_ViewExecute( query, rec ); + msiobj_unlock( &rec->hdr ); + +out: + msiobj_release( &query->hdr ); + if( rec ) + msiobj_release( &rec->hdr ); + + return ret; +} + +UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec) +{ + MSIVIEW *view = NULL; + MSIQUERY *query = NULL; + MSIRECORD *rec = NULL; + UINT r = ERROR_FUNCTION_FAILED, i, count = 0, type; + LPWSTR name; + + TRACE("%ld %d %p\n", hView, info, hRec); + + query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); + if( !query ) + return ERROR_INVALID_HANDLE; + + view = query->view; + if( !view ) + goto out; + + if( !view->ops->get_dimensions ) + goto out; + + r = view->ops->get_dimensions( view, NULL, &count ); + if( r ) + goto out; + if( !count ) + { + r = ERROR_INVALID_PARAMETER; + goto out; + } + + rec = MSI_CreateRecord( count ); + if( !rec ) + { + r = ERROR_FUNCTION_FAILED; + goto out; + } + + for( i=0; i<count; i++ ) + { + name = NULL; + r = view->ops->get_column_info( view, i+1, &name, &type ); + if( r != ERROR_SUCCESS ) + continue; + MSI_RecordSetStringW( rec, i+1, name ); + HeapFree( GetProcessHeap(), 0, name ); + } + + *hRec = alloc_msihandle( &rec->hdr ); + +out: + msiobj_release( &query->hdr ); + if( rec ) + msiobj_release( &rec->hdr ); + + return r; +} + +UINT WINAPI MsiViewModify( MSIHANDLE hView, MSIMODIFY eModifyMode, + MSIHANDLE hRecord) +{ + MSIVIEW *view = NULL; + MSIQUERY *query = NULL; + MSIRECORD *rec = NULL; + UINT r = ERROR_FUNCTION_FAILED; + + TRACE("%ld %x %ld\n", hView, eModifyMode, hRecord); + + query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW ); + if( !query ) + return ERROR_INVALID_HANDLE; + + view = query->view; + if( !view ) + goto out; + + if( !view->ops->modify ) + goto out; + + rec = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD ); + if( !rec ) + { + r = ERROR_INVALID_HANDLE; + goto out; + } + + r = view->ops->modify( view, eModifyMode, rec ); + +out: + msiobj_release( &query->hdr ); + if( rec ) + msiobj_release( &rec->hdr ); + + return r; +} + +UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb, + LPCSTR szTransformFile, int iErrorCond) +{ + FIXME("%ld %s %d\n", hdb, debugstr_a(szTransformFile), iErrorCond); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb, + LPCWSTR szTransformFile, int iErrorCond) +{ + FIXME("%ld %s %d\n", hdb, debugstr_w(szTransformFile), iErrorCond); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref, + LPCSTR szTransformFile, int iReserved1, int iReserved2 ) +{ + FIXME("%ld %ld %s %d %d\n", hdb, hdbref, + debugstr_a(szTransformFile), iReserved1, iReserved2); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref, + LPCWSTR szTransformFile, int iReserved1, int iReserved2 ) +{ + FIXME("%ld %ld %s %d %d\n", hdb, hdbref, + debugstr_w(szTransformFile), iReserved1, iReserved2); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb ) +{ + MSIDATABASE *db; + UINT r; + + TRACE("%ld\n", hdb); + + db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE ); + if( !db ) + return ERROR_INVALID_HANDLE; + + /* FIXME: lock the database */ + + r = MSI_CommitTables( db ); + + /* FIXME: unlock the database */ + + msiobj_release( &db->hdr ); + + return r; +} + +struct msi_primary_key_record_info +{ + DWORD n; + MSIRECORD *rec; +}; + +static UINT msi_primary_key_iterator( MSIRECORD *rec, LPVOID param ) +{ + struct msi_primary_key_record_info *info = param; + LPCWSTR name; + DWORD type; + + type = MSI_RecordGetInteger( rec, 4 ); + if( type & MSITYPE_KEY ) + { + info->n++; + if( info->rec ) + { + name = MSI_RecordGetString( rec, 3 ); + MSI_RecordSetStringW( info->rec, info->n, name ); + } + } + + return ERROR_SUCCESS; +} + +UINT MSI_DatabaseGetPrimaryKeys( MSIDATABASE *db, + LPCWSTR table, MSIRECORD **prec ) +{ + static const WCHAR sql[] = { + 's','e','l','e','c','t',' ','*',' ', + 'f','r','o','m',' ','`','_','C','o','l','u','m','n','s','`',' ', + 'w','h','e','r','e',' ', + '`','T','a','b','l','e','`',' ','=',' ','\'','%','s','\'',0 }; + struct msi_primary_key_record_info info; + MSIQUERY *query = NULL; + MSIVIEW *view; + UINT r; + + r = MSI_OpenQuery( db, &query, sql, table ); + if( r != ERROR_SUCCESS ) + return r; + + view = query->view; + + /* count the number of primary key records */ + info.n = 0; + info.rec = 0; + r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info ); + if( r == ERROR_SUCCESS ) + { + TRACE("Found %ld primary keys\n", info.n ); + + /* allocate a record and fill in the names of the tables */ + info.rec = MSI_CreateRecord( info.n ); + info.n = 0; + r = MSI_IterateRecords( query, 0, msi_primary_key_iterator, &info ); + if( r == ERROR_SUCCESS ) + *prec = info.rec; + else + msiobj_release( &info.rec->hdr ); + } + msiobj_release( &query->hdr ); + + return r; +} + +UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb, + LPCWSTR table, MSIHANDLE* phRec ) +{ + MSIRECORD *rec = NULL; + MSIDATABASE *db; + UINT r; + + TRACE("%ld %s %p\n", hdb, debugstr_w(table), phRec); + + db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE ); + if( !db ) + return ERROR_INVALID_HANDLE; + + r = MSI_DatabaseGetPrimaryKeys( db, table, &rec ); + if( r == ERROR_SUCCESS ) + { + *phRec = alloc_msihandle( &rec->hdr ); + msiobj_release( &rec->hdr ); + } + msiobj_release( &db->hdr ); + + return r; +} + +UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb, + LPCSTR table, MSIHANDLE* phRec) +{ + LPWSTR szwTable = NULL; + UINT r; + + TRACE("%ld %s %p\n", hdb, debugstr_a(table), phRec); + + if( table ) + { + szwTable = strdupAtoW( table ); + if( !szwTable ) + return ERROR_OUTOFMEMORY; + } + r = MsiDatabaseGetPrimaryKeysW( hdb, szwTable, phRec ); + HeapFree( GetProcessHeap(), 0, szwTable ); + + return r; +} + +UINT WINAPI MsiDatabaseIsTablePersistentA( + MSIHANDLE hDatabase, LPSTR szTableName) +{ + FIXME("%lx %s\n", hDatabase, debugstr_a(szTableName)); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +UINT WINAPI MsiDatabaseIsTablePersistentW( + MSIHANDLE hDatabase, LPWSTR szTableName) +{ + FIXME("%lx %s\n", hDatabase, debugstr_w(szTableName)); + return ERROR_CALL_NOT_IMPLEMENTED; +} diff --git a/reactos/lib/msi/order.c b/reactos/lib/msi/order.c index 33947a0620f..0e3b98fa84e 100644 --- a/reactos/lib/msi/order.c +++ b/reactos/lib/msi/order.c @@ -1,338 +1,338 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2002 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "wine/debug.h" -#include "msi.h" -#include "msiquery.h" -#include "objbase.h" -#include "objidl.h" -#include "msipriv.h" -#include "winnls.h" - -#include "query.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - - -/* below is the query interface to a table */ - -typedef struct tagMSIORDERVIEW -{ - MSIVIEW view; - MSIDATABASE *db; - MSIVIEW *table; - UINT *reorder; - UINT num_cols; - UINT cols[1]; -} MSIORDERVIEW; - -static UINT ORDER_compare( MSIORDERVIEW *ov, UINT a, UINT b, UINT *swap ) -{ - UINT r, i, a_val = 0, b_val = 0; - - *swap = 0; - for( i=0; i<ov->num_cols; i++ ) - { - r = ov->table->ops->fetch_int( ov->table, a, ov->cols[i], &a_val ); - if( r != ERROR_SUCCESS ) - return r; - - r = ov->table->ops->fetch_int( ov->table, b, ov->cols[i], &b_val ); - if( r != ERROR_SUCCESS ) - return r; - - if( a_val != b_val ) - { - if( a_val > b_val ) - *swap = 1; - break; - } - } - - return ERROR_SUCCESS; -} - -static UINT ORDER_mergesort( MSIORDERVIEW *ov, UINT left, UINT right ) -{ - UINT r, centre = (left + right)/2, temp, swap = 0, i, j; - UINT *array = ov->reorder; - - if( left == right ) - return ERROR_SUCCESS; - - /* sort the left half */ - r = ORDER_mergesort( ov, left, centre ); - if( r != ERROR_SUCCESS ) - return r; - - /* sort the right half */ - r = ORDER_mergesort( ov, centre+1, right ); - if( r != ERROR_SUCCESS ) - return r; - - for( i=left, j=centre+1; (i<=centre) && (j<=right); i++ ) - { - r = ORDER_compare( ov, array[i], array[j], &swap ); - if( r != ERROR_SUCCESS ) - return r; - if( swap ) - { - temp = array[j]; - memmove( &array[i+1], &array[i], (j-i)*sizeof (UINT) ); - array[i] = temp; - j++; - centre++; - } - } - - return ERROR_SUCCESS; -} - -static UINT ORDER_verify( MSIORDERVIEW *ov, UINT num_rows ) -{ - UINT i, swap, r; - - for( i=1; i<num_rows; i++ ) - { - r = ORDER_compare( ov, ov->reorder[i-1], ov->reorder[i], &swap ); - if( r != ERROR_SUCCESS ) - return r; - if( !swap ) - continue; - ERR("Bad order! %d\n", i); - return ERROR_FUNCTION_FAILED; - } - - return ERROR_SUCCESS; -} - -static UINT ORDER_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) -{ - MSIORDERVIEW *ov = (MSIORDERVIEW*)view; - - TRACE("%p %d %d %p\n", ov, row, col, val ); - - if( !ov->table ) - return ERROR_FUNCTION_FAILED; - - row = ov->reorder[ row ]; - - return ov->table->ops->fetch_int( ov->table, row, col, val ); -} - -static UINT ORDER_execute( struct tagMSIVIEW *view, MSIRECORD *record ) -{ - MSIORDERVIEW *ov = (MSIORDERVIEW*)view; - UINT r, num_rows = 0, i; - - TRACE("%p %p\n", ov, record); - - if( !ov->table ) - return ERROR_FUNCTION_FAILED; - - r = ov->table->ops->execute( ov->table, record ); - if( r != ERROR_SUCCESS ) - return r; - - r = ov->table->ops->get_dimensions( ov->table, &num_rows, NULL ); - if( r != ERROR_SUCCESS ) - return r; - - ov->reorder = HeapAlloc( GetProcessHeap(), 0, num_rows*sizeof(UINT) ); - if( !ov->reorder ) - return ERROR_FUNCTION_FAILED; - - for( i=0; i<num_rows; i++ ) - ov->reorder[i] = i; - - r = ORDER_mergesort( ov, 0, num_rows - 1 ); - if( r != ERROR_SUCCESS ) - return r; - - r = ORDER_verify( ov, num_rows ); - if( r != ERROR_SUCCESS ) - return r; - - return ERROR_SUCCESS; -} - -static UINT ORDER_close( struct tagMSIVIEW *view ) -{ - MSIORDERVIEW *ov = (MSIORDERVIEW*)view; - - TRACE("%p\n", ov ); - - if( !ov->table ) - return ERROR_FUNCTION_FAILED; - - HeapFree( GetProcessHeap(), 0, ov->reorder ); - ov->reorder = NULL; - - return ov->table->ops->close( ov->table ); -} - -static UINT ORDER_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols ) -{ - MSIORDERVIEW *ov = (MSIORDERVIEW*)view; - - TRACE("%p %p %p\n", ov, rows, cols ); - - if( !ov->table ) - return ERROR_FUNCTION_FAILED; - - return ov->table->ops->get_dimensions( ov->table, rows, cols ); -} - -static UINT ORDER_get_column_info( struct tagMSIVIEW *view, - UINT n, LPWSTR *name, UINT *type ) -{ - MSIORDERVIEW *ov = (MSIORDERVIEW*)view; - - TRACE("%p %d %p %p\n", ov, n, name, type ); - - if( !ov->table ) - return ERROR_FUNCTION_FAILED; - - return ov->table->ops->get_column_info( ov->table, n, name, type ); -} - -static UINT ORDER_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, - MSIRECORD *rec ) -{ - MSIORDERVIEW *ov = (MSIORDERVIEW*)view; - - TRACE("%p %d %p\n", ov, eModifyMode, rec ); - - if( !ov->table ) - return ERROR_FUNCTION_FAILED; - - return ov->table->ops->modify( ov->table, eModifyMode, rec ); -} - -static UINT ORDER_delete( struct tagMSIVIEW *view ) -{ - MSIORDERVIEW *ov = (MSIORDERVIEW*)view; - - TRACE("%p\n", ov ); - - if( ov->table ) - ov->table->ops->delete( ov->table ); - - HeapFree( GetProcessHeap(), 0, ov->reorder ); - ov->reorder = NULL; - - msiobj_release( &ov->db->hdr ); - HeapFree( GetProcessHeap(), 0, ov ); - - return ERROR_SUCCESS; -} - - -MSIVIEWOPS order_ops = -{ - ORDER_fetch_int, - NULL, - NULL, - NULL, - ORDER_execute, - ORDER_close, - ORDER_get_dimensions, - ORDER_get_column_info, - ORDER_modify, - ORDER_delete -}; - -static UINT ORDER_AddColumn( MSIORDERVIEW *ov, LPCWSTR name ) -{ - UINT n, count, r; - MSIVIEW *table; - - TRACE("%p adding %s\n", ov, debugstr_w( name ) ); - - if( ov->view.ops != &order_ops ) - return ERROR_FUNCTION_FAILED; - - table = ov->table; - if( !table ) - return ERROR_FUNCTION_FAILED; - if( !table->ops->get_dimensions ) - return ERROR_FUNCTION_FAILED; - if( !table->ops->get_column_info ) - return ERROR_FUNCTION_FAILED; - - r = table->ops->get_dimensions( table, NULL, &count ); - if( r != ERROR_SUCCESS ) - return r; - - if( ov->num_cols >= count ) - return ERROR_FUNCTION_FAILED; - - r = VIEW_find_column( table, name, &n ); - if( r != ERROR_SUCCESS ) - return r; - - ov->cols[ov->num_cols] = n; - TRACE("Ordering by column %s (%d)\n", debugstr_w( name ), n); - - ov->num_cols++; - - return ERROR_SUCCESS; -} - -UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, - string_list *columns ) -{ - MSIORDERVIEW *ov = NULL; - UINT count = 0, r; - string_list *x; - - TRACE("%p\n", ov ); - - r = table->ops->get_dimensions( table, NULL, &count ); - if( r != ERROR_SUCCESS ) - { - ERR("can't get table dimensions\n"); - return r; - } - - ov = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof *ov + sizeof (UINT) * count ); - if( !ov ) - return ERROR_FUNCTION_FAILED; - - /* fill the structure */ - ov->view.ops = &order_ops; - msiobj_addref( &db->hdr ); - ov->db = db; - ov->table = table; - ov->reorder = NULL; - ov->num_cols = 0; - *view = (MSIVIEW*) ov; - - for( x = columns; x ; x = x->next ) - ORDER_AddColumn( ov, x->string ); - - return ERROR_SUCCESS; -} +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2002 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/debug.h" +#include "msi.h" +#include "msiquery.h" +#include "objbase.h" +#include "objidl.h" +#include "msipriv.h" +#include "winnls.h" + +#include "query.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + + +/* below is the query interface to a table */ + +typedef struct tagMSIORDERVIEW +{ + MSIVIEW view; + MSIDATABASE *db; + MSIVIEW *table; + UINT *reorder; + UINT num_cols; + UINT cols[1]; +} MSIORDERVIEW; + +static UINT ORDER_compare( MSIORDERVIEW *ov, UINT a, UINT b, UINT *swap ) +{ + UINT r, i, a_val = 0, b_val = 0; + + *swap = 0; + for( i=0; i<ov->num_cols; i++ ) + { + r = ov->table->ops->fetch_int( ov->table, a, ov->cols[i], &a_val ); + if( r != ERROR_SUCCESS ) + return r; + + r = ov->table->ops->fetch_int( ov->table, b, ov->cols[i], &b_val ); + if( r != ERROR_SUCCESS ) + return r; + + if( a_val != b_val ) + { + if( a_val > b_val ) + *swap = 1; + break; + } + } + + return ERROR_SUCCESS; +} + +static UINT ORDER_mergesort( MSIORDERVIEW *ov, UINT left, UINT right ) +{ + UINT r, centre = (left + right)/2, temp, swap = 0, i, j; + UINT *array = ov->reorder; + + if( left == right ) + return ERROR_SUCCESS; + + /* sort the left half */ + r = ORDER_mergesort( ov, left, centre ); + if( r != ERROR_SUCCESS ) + return r; + + /* sort the right half */ + r = ORDER_mergesort( ov, centre+1, right ); + if( r != ERROR_SUCCESS ) + return r; + + for( i=left, j=centre+1; (i<=centre) && (j<=right); i++ ) + { + r = ORDER_compare( ov, array[i], array[j], &swap ); + if( r != ERROR_SUCCESS ) + return r; + if( swap ) + { + temp = array[j]; + memmove( &array[i+1], &array[i], (j-i)*sizeof (UINT) ); + array[i] = temp; + j++; + centre++; + } + } + + return ERROR_SUCCESS; +} + +static UINT ORDER_verify( MSIORDERVIEW *ov, UINT num_rows ) +{ + UINT i, swap, r; + + for( i=1; i<num_rows; i++ ) + { + r = ORDER_compare( ov, ov->reorder[i-1], ov->reorder[i], &swap ); + if( r != ERROR_SUCCESS ) + return r; + if( !swap ) + continue; + ERR("Bad order! %d\n", i); + return ERROR_FUNCTION_FAILED; + } + + return ERROR_SUCCESS; +} + +static UINT ORDER_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) +{ + MSIORDERVIEW *ov = (MSIORDERVIEW*)view; + + TRACE("%p %d %d %p\n", ov, row, col, val ); + + if( !ov->table ) + return ERROR_FUNCTION_FAILED; + + row = ov->reorder[ row ]; + + return ov->table->ops->fetch_int( ov->table, row, col, val ); +} + +static UINT ORDER_execute( struct tagMSIVIEW *view, MSIRECORD *record ) +{ + MSIORDERVIEW *ov = (MSIORDERVIEW*)view; + UINT r, num_rows = 0, i; + + TRACE("%p %p\n", ov, record); + + if( !ov->table ) + return ERROR_FUNCTION_FAILED; + + r = ov->table->ops->execute( ov->table, record ); + if( r != ERROR_SUCCESS ) + return r; + + r = ov->table->ops->get_dimensions( ov->table, &num_rows, NULL ); + if( r != ERROR_SUCCESS ) + return r; + + ov->reorder = HeapAlloc( GetProcessHeap(), 0, num_rows*sizeof(UINT) ); + if( !ov->reorder ) + return ERROR_FUNCTION_FAILED; + + for( i=0; i<num_rows; i++ ) + ov->reorder[i] = i; + + r = ORDER_mergesort( ov, 0, num_rows - 1 ); + if( r != ERROR_SUCCESS ) + return r; + + r = ORDER_verify( ov, num_rows ); + if( r != ERROR_SUCCESS ) + return r; + + return ERROR_SUCCESS; +} + +static UINT ORDER_close( struct tagMSIVIEW *view ) +{ + MSIORDERVIEW *ov = (MSIORDERVIEW*)view; + + TRACE("%p\n", ov ); + + if( !ov->table ) + return ERROR_FUNCTION_FAILED; + + HeapFree( GetProcessHeap(), 0, ov->reorder ); + ov->reorder = NULL; + + return ov->table->ops->close( ov->table ); +} + +static UINT ORDER_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols ) +{ + MSIORDERVIEW *ov = (MSIORDERVIEW*)view; + + TRACE("%p %p %p\n", ov, rows, cols ); + + if( !ov->table ) + return ERROR_FUNCTION_FAILED; + + return ov->table->ops->get_dimensions( ov->table, rows, cols ); +} + +static UINT ORDER_get_column_info( struct tagMSIVIEW *view, + UINT n, LPWSTR *name, UINT *type ) +{ + MSIORDERVIEW *ov = (MSIORDERVIEW*)view; + + TRACE("%p %d %p %p\n", ov, n, name, type ); + + if( !ov->table ) + return ERROR_FUNCTION_FAILED; + + return ov->table->ops->get_column_info( ov->table, n, name, type ); +} + +static UINT ORDER_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, + MSIRECORD *rec ) +{ + MSIORDERVIEW *ov = (MSIORDERVIEW*)view; + + TRACE("%p %d %p\n", ov, eModifyMode, rec ); + + if( !ov->table ) + return ERROR_FUNCTION_FAILED; + + return ov->table->ops->modify( ov->table, eModifyMode, rec ); +} + +static UINT ORDER_delete( struct tagMSIVIEW *view ) +{ + MSIORDERVIEW *ov = (MSIORDERVIEW*)view; + + TRACE("%p\n", ov ); + + if( ov->table ) + ov->table->ops->delete( ov->table ); + + HeapFree( GetProcessHeap(), 0, ov->reorder ); + ov->reorder = NULL; + + msiobj_release( &ov->db->hdr ); + HeapFree( GetProcessHeap(), 0, ov ); + + return ERROR_SUCCESS; +} + + +MSIVIEWOPS order_ops = +{ + ORDER_fetch_int, + NULL, + NULL, + NULL, + ORDER_execute, + ORDER_close, + ORDER_get_dimensions, + ORDER_get_column_info, + ORDER_modify, + ORDER_delete +}; + +static UINT ORDER_AddColumn( MSIORDERVIEW *ov, LPCWSTR name ) +{ + UINT n, count, r; + MSIVIEW *table; + + TRACE("%p adding %s\n", ov, debugstr_w( name ) ); + + if( ov->view.ops != &order_ops ) + return ERROR_FUNCTION_FAILED; + + table = ov->table; + if( !table ) + return ERROR_FUNCTION_FAILED; + if( !table->ops->get_dimensions ) + return ERROR_FUNCTION_FAILED; + if( !table->ops->get_column_info ) + return ERROR_FUNCTION_FAILED; + + r = table->ops->get_dimensions( table, NULL, &count ); + if( r != ERROR_SUCCESS ) + return r; + + if( ov->num_cols >= count ) + return ERROR_FUNCTION_FAILED; + + r = VIEW_find_column( table, name, &n ); + if( r != ERROR_SUCCESS ) + return r; + + ov->cols[ov->num_cols] = n; + TRACE("Ordering by column %s (%d)\n", debugstr_w( name ), n); + + ov->num_cols++; + + return ERROR_SUCCESS; +} + +UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, + string_list *columns ) +{ + MSIORDERVIEW *ov = NULL; + UINT count = 0, r; + string_list *x; + + TRACE("%p\n", ov ); + + r = table->ops->get_dimensions( table, NULL, &count ); + if( r != ERROR_SUCCESS ) + { + ERR("can't get table dimensions\n"); + return r; + } + + ov = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof *ov + sizeof (UINT) * count ); + if( !ov ) + return ERROR_FUNCTION_FAILED; + + /* fill the structure */ + ov->view.ops = &order_ops; + msiobj_addref( &db->hdr ); + ov->db = db; + ov->table = table; + ov->reorder = NULL; + ov->num_cols = 0; + *view = (MSIVIEW*) ov; + + for( x = columns; x ; x = x->next ) + ORDER_AddColumn( ov, x->string ); + + return ERROR_SUCCESS; +} diff --git a/reactos/lib/msi/package.c b/reactos/lib/msi/package.c index be257e1d9d0..53808ab0679 100644 --- a/reactos/lib/msi/package.c +++ b/reactos/lib/msi/package.c @@ -1,902 +1,902 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2004 Aric Stewart for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define NONAMELESSUNION - -#include <stdarg.h> -#include <stdio.h> -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "winnls.h" -#include "shlwapi.h" -#include "wingdi.h" -#include "wine/debug.h" -#include "msi.h" -#include "msiquery.h" -#include "msipriv.h" -#include "objidl.h" -#include "wincrypt.h" -#include "winuser.h" -#include "shlobj.h" -#include "wine/unicode.h" -#include "objbase.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -/* - * The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR, - * which is a problem because LPCTSTR isn't defined when compiling wine. - * To work around this problem, we need to define LPCTSTR as LPCWSTR here, - * and make sure to only use it in W functions. - */ -#define LPCTSTR LPCWSTR - -void MSI_FreePackage( MSIOBJECTHDR *arg) -{ - MSIPACKAGE *package= (MSIPACKAGE*) arg; - - if( package->dialog ) - msi_dialog_destroy( package->dialog ); - ACTION_free_package_structures(package); - - msiobj_release( &package->db->hdr ); -} - -static UINT clone_properties(MSIDATABASE *db) -{ - MSIQUERY * view = NULL; - UINT rc; - static const WCHAR CreateSql[] = { - 'C','R','E','A','T','E',' ','T','A','B','L','E',' ','`','_','P','r','o', - 'p','e','r','t','y','`',' ','(',' ','`','_','P','r','o','p','e','r','t', - 'y','`',' ','C','H','A','R','(','5','6',')',' ','N','O','T',' ','N','U', - 'L','L',',',' ','`','V','a','l','u','e','`',' ','C','H','A','R','(','9', - '8',')',' ','N','O','T',' ','N','U','L','L',' ','P','R','I','M','A','R', - 'Y',' ','K','E','Y',' ','`','_','P','r','o','p','e','r','t','y','`',')',0}; - static const WCHAR Query[] = { - 'S','E','L','E','C','T',' ','*',' ', - 'F','R','O','M',' ','`','P','r','o','p','e','r','t','y','`',0}; - static const WCHAR Insert[] = { - 'I','N','S','E','R','T',' ','i','n','t','o',' ', - '`','_','P','r','o','p','e','r','t','y','`',' ', - '(','`','_','P','r','o','p','e','r','t','y','`',',', - '`','V','a','l','u','e','`',')',' ', - 'V','A','L','U','E','S',' ','(','?',',','?',')',0}; - - /* create the temporary properties table */ - rc = MSI_DatabaseOpenViewW(db, CreateSql, &view); - if (rc != ERROR_SUCCESS) - return rc; - rc = MSI_ViewExecute(view,0); - MSI_ViewClose(view); - msiobj_release(&view->hdr); - if (rc != ERROR_SUCCESS) - return rc; - - /* clone the existing properties */ - rc = MSI_DatabaseOpenViewW(db, Query, &view); - if (rc != ERROR_SUCCESS) - return rc; - - rc = MSI_ViewExecute(view, 0); - if (rc != ERROR_SUCCESS) - { - MSI_ViewClose(view); - msiobj_release(&view->hdr); - return rc; - } - while (1) - { - MSIRECORD * row; - MSIQUERY * view2; - - rc = MSI_ViewFetch(view,&row); - if (rc != ERROR_SUCCESS) - break; - - rc = MSI_DatabaseOpenViewW(db,Insert,&view2); - if (rc!= ERROR_SUCCESS) - continue; - rc = MSI_ViewExecute(view2,row); - MSI_ViewClose(view2); - msiobj_release(&view2->hdr); - - if (rc == ERROR_SUCCESS) - msiobj_release(&row->hdr); - } - MSI_ViewClose(view); - msiobj_release(&view->hdr); - - return rc; -} - -/* - * There are a whole slew of these we need to set - * - * -http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/properties.asp - */ -static VOID set_installer_properties(MSIPACKAGE *package) -{ - WCHAR pth[MAX_PATH]; - WCHAR *ptr; - OSVERSIONINFOA OSVersion; - MEMORYSTATUSEX msex; - DWORD verval; - WCHAR verstr[10], bufstr[20]; - HDC dc; - - static const WCHAR cszbs[]={'\\',0}; - static const WCHAR CFF[] = -{'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0}; - static const WCHAR PFF[] = -{'P','r','o','g','r','a','m','F','i','l','e','s','F','o','l','d','e','r',0}; - static const WCHAR CADF[] = -{'C','o','m','m','o','n','A','p','p','D','a','t','a','F','o','l','d','e','r',0}; - static const WCHAR FaF[] = -{'F','a','v','o','r','i','t','e','s','F','o','l','d','e','r',0}; - static const WCHAR FoF[] = -{'F','o','n','t','s','F','o','l','d','e','r',0}; - static const WCHAR SendTF[] = -{'S','e','n','d','T','o','F','o','l','d','e','r',0}; - static const WCHAR SMF[] = -{'S','t','a','r','t','M','e','n','u','F','o','l','d','e','r',0}; - static const WCHAR StF[] = -{'S','t','a','r','t','u','p','F','o','l','d','e','r',0}; - static const WCHAR TemplF[] = -{'T','e','m','p','l','a','t','e','F','o','l','d','e','r',0}; - static const WCHAR DF[] = -{'D','e','s','k','t','o','p','F','o','l','d','e','r',0}; - static const WCHAR PMF[] = -{'P','r','o','g','r','a','m','M','e','n','u','F','o','l','d','e','r',0}; - static const WCHAR ATF[] = -{'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0}; - static const WCHAR ADF[] = -{'A','p','p','D','a','t','a','F','o','l','d','e','r',0}; - static const WCHAR SF[] = -{'S','y','s','t','e','m','F','o','l','d','e','r',0}; - static const WCHAR SF16[] = -{'S','y','s','t','e','m','1','6','F','o','l','d','e','r',0}; - static const WCHAR LADF[] = -{'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0}; - static const WCHAR MPF[] = -{'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0}; - static const WCHAR PF[] = -{'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0}; - static const WCHAR WF[] = -{'W','i','n','d','o','w','s','F','o','l','d','e','r',0}; - static const WCHAR WV[] = -{'W','i','n','d','o','w','s','V','o','l','u','m','e',0}; - static const WCHAR TF[]= -{'T','e','m','p','F','o','l','d','e','r',0}; - static const WCHAR szAdminUser[] = -{'A','d','m','i','n','U','s','e','r',0}; - static const WCHAR szPriv[] = -{'P','r','i','v','i','l','e','g','e','d',0}; - static const WCHAR szOne[] = -{'1',0}; - static const WCHAR v9x[] = { 'V','e','r','s','i','o','n','9','X',0 }; - static const WCHAR vNT[] = { 'V','e','r','s','i','o','n','N','T',0 }; - static const WCHAR szFormat[] = {'%','l','i',0}; - static const WCHAR szWinBuild[] = -{'W','i','n','d','o','w','s','B','u','i','l','d', 0 }; - static const WCHAR szSPL[] = -{'S','e','r','v','i','c','e','P','a','c','k','L','e','v','e','l',0 }; - static const WCHAR szSix[] = {'6',0 }; - - static const WCHAR szVersionMsi[] = { 'V','e','r','s','i','o','n','M','s','i',0 }; - static const WCHAR szPhysicalMemory[] = { 'P','h','y','s','i','c','a','l','M','e','m','o','r','y',0 }; - static const WCHAR szFormat2[] = {'%','l','i','.','%','l','i',0}; -/* Screen properties */ - static const WCHAR szScreenX[] = {'S','c','r','e','e','n','X',0}; - static const WCHAR szScreenY[] = {'S','c','r','e','e','n','Y',0}; - static const WCHAR szColorBits[] = {'C','o','l','o','r','B','i','t','s',0}; - static const WCHAR szScreenFormat[] = {'%','d',0}; - -/* - * Other things I notice set - * -SystemLanguageID -ComputerName -UserLanguageID -LogonUser -VirtualMemory -Intel -ShellAdvSupport -DefaultUIFont -VersionDatabase -PackagecodeChanging -ProductState -CaptionHeight -BorderTop -BorderSide -TextHeight -RedirectedDllSupport -Time -Date -Privileged -*/ - - SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth); - strcatW(pth,cszbs); - MSI_SetPropertyW(package, CFF, pth); - - SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES,NULL,0,pth); - strcatW(pth,cszbs); - MSI_SetPropertyW(package, PFF, pth); - - SHGetFolderPathW(NULL,CSIDL_COMMON_APPDATA,NULL,0,pth); - strcatW(pth,cszbs); - MSI_SetPropertyW(package, CADF, pth); - - SHGetFolderPathW(NULL,CSIDL_FAVORITES,NULL,0,pth); - strcatW(pth,cszbs); - MSI_SetPropertyW(package, FaF, pth); - - SHGetFolderPathW(NULL,CSIDL_FONTS,NULL,0,pth); - strcatW(pth,cszbs); - MSI_SetPropertyW(package, FoF, pth); - - SHGetFolderPathW(NULL,CSIDL_SENDTO,NULL,0,pth); - strcatW(pth,cszbs); - MSI_SetPropertyW(package, SendTF, pth); - - SHGetFolderPathW(NULL,CSIDL_STARTMENU,NULL,0,pth); - strcatW(pth,cszbs); - MSI_SetPropertyW(package, SMF, pth); - - SHGetFolderPathW(NULL,CSIDL_STARTUP,NULL,0,pth); - strcatW(pth,cszbs); - MSI_SetPropertyW(package, StF, pth); - - SHGetFolderPathW(NULL,CSIDL_TEMPLATES,NULL,0,pth); - strcatW(pth,cszbs); - MSI_SetPropertyW(package, TemplF, pth); - - SHGetFolderPathW(NULL,CSIDL_DESKTOP,NULL,0,pth); - strcatW(pth,cszbs); - MSI_SetPropertyW(package, DF, pth); - - SHGetFolderPathW(NULL,CSIDL_PROGRAMS,NULL,0,pth); - strcatW(pth,cszbs); - MSI_SetPropertyW(package, PMF, pth); - - SHGetFolderPathW(NULL,CSIDL_ADMINTOOLS,NULL,0,pth); - strcatW(pth,cszbs); - MSI_SetPropertyW(package, ATF, pth); - - SHGetFolderPathW(NULL,CSIDL_APPDATA,NULL,0,pth); - strcatW(pth,cszbs); - MSI_SetPropertyW(package, ADF, pth); - - SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth); - strcatW(pth,cszbs); - MSI_SetPropertyW(package, SF, pth); - MSI_SetPropertyW(package, SF16, pth); - - SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth); - strcatW(pth,cszbs); - MSI_SetPropertyW(package, LADF, pth); - - SHGetFolderPathW(NULL,CSIDL_MYPICTURES,NULL,0,pth); - strcatW(pth,cszbs); - MSI_SetPropertyW(package, MPF, pth); - - SHGetFolderPathW(NULL,CSIDL_PERSONAL,NULL,0,pth); - strcatW(pth,cszbs); - MSI_SetPropertyW(package, PF, pth); - - SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth); - strcatW(pth,cszbs); - MSI_SetPropertyW(package, WF, pth); - - /* Physical Memory is specified in MB. Using total amount. */ - msex.dwLength = sizeof(msex); - GlobalMemoryStatusEx( &msex ); - sprintfW( bufstr, szScreenFormat, (int)(msex.ullTotalPhys/1024/1024)); - MSI_SetPropertyW(package, szPhysicalMemory, bufstr); - - SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth); - ptr = strchrW(pth,'\\'); - if (ptr) - *(ptr+1) = 0; - MSI_SetPropertyW(package, WV, pth); - - GetTempPathW(MAX_PATH,pth); - MSI_SetPropertyW(package, TF, pth); - - - /* in a wine environment the user is always admin and privileged */ - MSI_SetPropertyW(package,szAdminUser,szOne); - MSI_SetPropertyW(package,szPriv,szOne); - - /* set the os things */ - OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); - GetVersionExA(&OSVersion); - verval = OSVersion.dwMinorVersion+OSVersion.dwMajorVersion*100; - sprintfW(verstr,szFormat,verval); - switch (OSVersion.dwPlatformId) - { - case VER_PLATFORM_WIN32_WINDOWS: - MSI_SetPropertyW(package,v9x,verstr); - break; - case VER_PLATFORM_WIN32_NT: - MSI_SetPropertyW(package,vNT,verstr); - break; - } - sprintfW(verstr,szFormat,OSVersion.dwBuildNumber); - MSI_SetPropertyW(package,szWinBuild,verstr); - /* just fudge this */ - MSI_SetPropertyW(package,szSPL,szSix); - - sprintfW( bufstr, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION); - MSI_SetPropertyW( package, szVersionMsi, bufstr ); - - /* Screen properties. */ - dc = GetDC(0); - sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, HORZRES ) ); - MSI_SetPropertyW( package, szScreenX, bufstr ); - sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, VERTRES )); - MSI_SetPropertyW( package, szScreenY, bufstr ); - sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, BITSPIXEL )); - MSI_SetPropertyW( package, szColorBits, bufstr ); - ReleaseDC(0, dc); -} - -MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db ) -{ - static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 }; - static const WCHAR szpi[] = {'%','i',0}; - MSIPACKAGE *package = NULL; - WCHAR uilevel[10]; - - TRACE("%p\n", db); - - package = alloc_msiobject( MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE), - MSI_FreePackage ); - if( package ) - { - msiobj_addref( &db->hdr ); - - package->db = db; - package->features = NULL; - package->folders = NULL; - package->components = NULL; - package->files = NULL; - package->loaded_features = 0; - package->loaded_folders = 0; - package->loaded_components= 0; - package->loaded_files = 0; - package->ActionFormat = NULL; - package->LastAction = NULL; - package->dialog = NULL; - package->next_dialog = NULL; - - /* OK, here is where we do a slew of things to the database to - * prep for all that is to come as a package */ - - clone_properties(db); - set_installer_properties(package); - sprintfW(uilevel,szpi,gUILevel); - MSI_SetPropertyW(package, szLevel, uilevel); - } - - return package; -} - -UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) -{ - MSIDATABASE *db = NULL; - MSIPACKAGE *package; - MSIHANDLE handle; - - TRACE("%s %p\n", debugstr_w(szPackage), pPackage); - - if( szPackage[0] == '#' ) - { - handle = atoiW(&szPackage[1]); - db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE ); - if( !db ) - return ERROR_INVALID_HANDLE; - } - else - { - UINT r = MSI_OpenDatabaseW(szPackage, MSIDBOPEN_READONLY, &db); - if( r != ERROR_SUCCESS ) - return r; - } - - package = MSI_CreatePackage( db ); - msiobj_release( &db->hdr ); - if( !package ) - return ERROR_FUNCTION_FAILED; - - /* - * FIXME: I don't think this is right. Maybe we should be storing the - * name of the database in the MSIDATABASE structure and fetching this - * info from there, or maybe this is only relevant to cached databases. - */ - if( szPackage[0] != '#' ) - { - static const WCHAR OriginalDatabase[] = - {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0}; - static const WCHAR Database[] = {'D','A','T','A','B','A','S','E',0}; - - MSI_SetPropertyW( package, OriginalDatabase, szPackage ); - MSI_SetPropertyW( package, Database, szPackage ); - } - - *pPackage = package; - - return ERROR_SUCCESS; -} - -UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage) -{ - MSIPACKAGE *package = NULL; - UINT ret; - - TRACE("%s %08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage); - - if( dwOptions ) - FIXME("dwOptions %08lx not supported\n", dwOptions); - - ret = MSI_OpenPackageW( szPackage, &package); - if( ret == ERROR_SUCCESS ) - { - *phPackage = alloc_msihandle( &package->hdr ); - msiobj_release( &package->hdr ); - } - return ret; -} - -UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage) -{ - return MsiOpenPackageExW( szPackage, 0, phPackage ); -} - -UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage) -{ - LPWSTR szwPack = NULL; - UINT ret; - - if( szPackage ) - { - szwPack = strdupAtoW( szPackage ); - if( !szwPack ) - return ERROR_OUTOFMEMORY; - } - - ret = MsiOpenPackageExW( szwPack, dwOptions, phPackage ); - - HeapFree( GetProcessHeap(), 0, szwPack ); - - return ret; -} - -UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage) -{ - return MsiOpenPackageExA( szPackage, 0, phPackage ); -} - -MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall) -{ - MSIPACKAGE *package; - MSIHANDLE handle = 0; - - TRACE("(%ld)\n",hInstall); - - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); - if( package) - { - handle = alloc_msihandle( &package->db->hdr ); - msiobj_release( &package->hdr ); - } - - return handle; -} - -INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType, - MSIRECORD *record) -{ - DWORD log_type = 0; - LPWSTR message; - DWORD sz; - DWORD total_size = 0; - INT msg_field=1; - INT i; - INT rc; - char *msg; - int len; - - TRACE("%x \n",eMessageType); - rc = 0; - - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR) - log_type |= INSTALLLOGMODE_ERROR; - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_WARNING) - log_type |= INSTALLLOGMODE_WARNING; - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_USER) - log_type |= INSTALLLOGMODE_USER; - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INFO) - log_type |= INSTALLLOGMODE_INFO; - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA) - log_type |= INSTALLLOGMODE_COMMONDATA; - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART) - log_type |= INSTALLLOGMODE_ACTIONSTART; - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA) - log_type |= INSTALLLOGMODE_ACTIONDATA; - /* just a guess */ - if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS) - log_type |= 0x800; - - message = HeapAlloc(GetProcessHeap(),0,1*sizeof (WCHAR)); - message[0]=0; - msg_field = MSI_RecordGetFieldCount(record); - for (i = 1; i <= msg_field; i++) - { - LPWSTR tmp; - WCHAR number[3]; - const static WCHAR format[] = { '%','i',':',' ',0}; - const static WCHAR space[] = { ' ',0}; - sz = 0; - MSI_RecordGetStringW(record,i,NULL,&sz); - sz+=4; - total_size+=sz*sizeof(WCHAR); - tmp = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR)); - message = HeapReAlloc(GetProcessHeap(),0,message,total_size*sizeof (WCHAR)); - - MSI_RecordGetStringW(record,i,tmp,&sz); - - if (msg_field > 1) - { - sprintfW(number,format,i); - strcatW(message,number); - } - strcatW(message,tmp); - if (msg_field > 1) - strcatW(message,space); - - HeapFree(GetProcessHeap(),0,tmp); - } - - TRACE("(%p %lx %lx %s)\n",gUIHandlerA, gUIFilter, log_type, - debugstr_w(message)); - - /* convert it to ASCII */ - len = WideCharToMultiByte( CP_ACP, 0, message, -1, - NULL, 0, NULL, NULL ); - msg = HeapAlloc( GetProcessHeap(), 0, len ); - WideCharToMultiByte( CP_ACP, 0, message, -1, - msg, len, NULL, NULL ); - - if (gUIHandlerA && (gUIFilter & log_type)) - { - rc = gUIHandlerA(gUIContext,eMessageType,msg); - } - - if ((!rc) && (gszLogFile[0]) && !((eMessageType & 0xff000000) == - INSTALLMESSAGE_PROGRESS)) - { - DWORD write; - HANDLE log_file = CreateFileW(gszLogFile,GENERIC_WRITE, 0, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - - if (log_file != INVALID_HANDLE_VALUE) - { - SetFilePointer(log_file,0, NULL, FILE_END); - WriteFile(log_file,msg,strlen(msg),&write,NULL); - WriteFile(log_file,"\n",1,&write,NULL); - CloseHandle(log_file); - } - } - HeapFree( GetProcessHeap(), 0, msg ); - - HeapFree(GetProcessHeap(),0,message); - return ERROR_SUCCESS; -} - -INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType, - MSIHANDLE hRecord) -{ - UINT ret = ERROR_INVALID_HANDLE; - MSIPACKAGE *package = NULL; - MSIRECORD *record = NULL; - - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE ); - if( !package ) - return ERROR_INVALID_HANDLE; - - record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD ); - if( !record ) - goto out; - - ret = MSI_ProcessMessage( package, eMessageType, record ); - -out: - msiobj_release( &package->hdr ); - if( record ) - msiobj_release( &record->hdr ); - - return ret; -} - -/* property code */ -UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue) -{ - LPWSTR szwName = NULL, szwValue = NULL; - UINT hr = ERROR_INSTALL_FAILURE; - - if( szName ) - { - szwName = strdupAtoW( szName ); - if( !szwName ) - goto end; - } - - if( szValue ) - { - szwValue = strdupAtoW( szValue ); - if( !szwValue) - goto end; - } - - hr = MsiSetPropertyW( hInstall, szwName, szwValue); - -end: - HeapFree( GetProcessHeap(), 0, szwName ); - HeapFree( GetProcessHeap(), 0, szwValue ); - - return hr; -} - -UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue) -{ - MSIQUERY *view; - MSIRECORD *row; - UINT rc; - DWORD sz = 0; - static const WCHAR Insert[]= - {'I','N','S','E','R','T',' ','i','n','t','o',' ','`','_','P','r','o','p' -,'e','r','t','y','`',' ','(','`','_','P','r','o','p','e','r','t','y','`' -,',','`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S' -,' ','(','?',',','?',')',0}; - static const WCHAR Update[]= - {'U','P','D','A','T','E',' ','_','P','r','o','p','e' -,'r','t','y',' ','s','e','t',' ','`','V','a','l','u','e','`',' ','=' -,' ','?',' ','w','h','e','r','e',' ','`','_','P','r','o','p' -,'e','r','t','y','`',' ','=',' ','\'','%','s','\'',0}; - WCHAR Query[1024]; - - TRACE("Setting property (%s %s)\n",debugstr_w(szName), - debugstr_w(szValue)); - - rc = MSI_GetPropertyW(package,szName,0,&sz); - if (rc==ERROR_MORE_DATA || rc == ERROR_SUCCESS) - { - sprintfW(Query,Update,szName); - - row = MSI_CreateRecord(1); - MSI_RecordSetStringW(row,1,szValue); - - } - else - { - strcpyW(Query,Insert); - - row = MSI_CreateRecord(2); - MSI_RecordSetStringW(row,1,szName); - MSI_RecordSetStringW(row,2,szValue); - } - - - rc = MSI_DatabaseOpenViewW(package->db,Query,&view); - if (rc!= ERROR_SUCCESS) - { - msiobj_release(&row->hdr); - return rc; - } - - rc = MSI_ViewExecute(view,row); - - msiobj_release(&row->hdr); - MSI_ViewClose(view); - msiobj_release(&view->hdr); - - return rc; -} - -UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue) -{ - MSIPACKAGE *package; - UINT ret; - - if (NULL == szName) - return ERROR_INVALID_PARAMETER; - if (NULL == szValue) - return ERROR_INVALID_PARAMETER; - - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); - if( !package ) - return ERROR_INVALID_HANDLE; - ret = MSI_SetPropertyW( package, szName, szValue); - msiobj_release( &package->hdr ); - return ret; -} - -static UINT MSI_GetPropertyRow(MSIPACKAGE *package, LPCWSTR szName, MSIRECORD **row) -{ - MSIQUERY *view; - UINT rc, sz; - static const WCHAR select[]= - {'S','E','L','E','C','T',' ','`','V','a','l','u','e','`',' ', - 'F','R','O','M',' ' ,'`','_','P','r','o','p','e','r','t','y','`', - ' ','W','H','E','R','E',' ' ,'`','_','P','r','o','p','e','r','t','y','`', - '=','\'','%','s','\'',0}; - LPWSTR query; - - if (!szName) - return ERROR_INVALID_PARAMETER; - - sz = sizeof select + strlenW(szName)*sizeof(WCHAR); - query = HeapAlloc(GetProcessHeap(), 0, sz); - sprintfW(query,select,szName); - - rc = MSI_DatabaseOpenViewW(package->db, query, &view); - HeapFree(GetProcessHeap(), 0, query); - if (rc == ERROR_SUCCESS) - { - rc = MSI_ViewExecute(view, 0); - if (rc == ERROR_SUCCESS) - rc = MSI_ViewFetch(view,row); - - MSI_ViewClose(view); - msiobj_release(&view->hdr); - } - - return rc; -} - -UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName, - LPWSTR szValueBuf, DWORD* pchValueBuf) -{ - MSIRECORD *row; - UINT rc; - - rc = MSI_GetPropertyRow(package, szName, &row); - - if (*pchValueBuf > 0) - szValueBuf[0] = 0; - - if (rc == ERROR_SUCCESS) - { - rc = MSI_RecordGetStringW(row,1,szValueBuf,pchValueBuf); - msiobj_release(&row->hdr); - } - - if (rc == ERROR_SUCCESS) - TRACE("returning %s for property %s\n", debugstr_w(szValueBuf), - debugstr_w(szName)); - else if (rc == ERROR_MORE_DATA) - TRACE("need %li sized buffer for %s\n", *pchValueBuf, - debugstr_w(szName)); - else - { - *pchValueBuf = 0; - TRACE("property %s not found\n", debugstr_w(szName)); - } - - return rc; -} - -UINT MSI_GetPropertyA(MSIPACKAGE *package, LPCSTR szName, - LPSTR szValueBuf, DWORD* pchValueBuf) -{ - MSIRECORD *row; - UINT rc; - LPWSTR szwName = NULL; - - if (*pchValueBuf > 0) - szValueBuf[0] = 0; - - if( szName ) - { - szwName = strdupAtoW( szName ); - if (!szwName) - return ERROR_NOT_ENOUGH_MEMORY; - } - - rc = MSI_GetPropertyRow(package, szwName, &row); - if (rc == ERROR_SUCCESS) - { - rc = MSI_RecordGetStringA(row,1,szValueBuf,pchValueBuf); - msiobj_release(&row->hdr); - } - - if (rc == ERROR_SUCCESS) - TRACE("returning %s for property %s\n", debugstr_a(szValueBuf), - debugstr_a(szName)); - else if (rc == ERROR_MORE_DATA) - TRACE("need %ld sized buffer for %s\n", *pchValueBuf, - debugstr_a(szName)); - else - { - *pchValueBuf = 0; - TRACE("property not found\n"); - } - HeapFree( GetProcessHeap(), 0, szwName ); - - return rc; -} - -UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf) -{ - MSIPACKAGE *package; - UINT ret; - - TRACE("%lu %s %lu\n", hInstall, debugstr_a(szName), *pchValueBuf); - - if (0 == hInstall) - return ERROR_INVALID_HANDLE; - if (NULL == szName) - return ERROR_INVALID_PARAMETER; - if (NULL != szValueBuf && NULL == pchValueBuf) - return ERROR_INVALID_PARAMETER; - - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); - if (!package) - return ERROR_INVALID_HANDLE; - ret = MSI_GetPropertyA(package, szName, szValueBuf, pchValueBuf ); - msiobj_release( &package->hdr ); - - /* MsiGetProperty does not return error codes on missing properties */ - if (ret!= ERROR_MORE_DATA) - return ERROR_SUCCESS; - else - return ret; -} - - -UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, - LPWSTR szValueBuf, DWORD* pchValueBuf) -{ - MSIPACKAGE *package; - UINT ret; - - if (0 == hInstall) - return ERROR_INVALID_HANDLE; - if (NULL == szName) - return ERROR_INVALID_PARAMETER; - if (NULL != szValueBuf && NULL == pchValueBuf) - return ERROR_INVALID_PARAMETER; - - package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); - if (!package) - return ERROR_INVALID_HANDLE; - ret = MSI_GetPropertyW(package, szName, szValueBuf, pchValueBuf ); - msiobj_release( &package->hdr ); - - /* MsiGetProperty does not return error codes on missing properties */ - if (ret!= ERROR_MORE_DATA) - return ERROR_SUCCESS; - else - return ret; -} +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2004 Aric Stewart for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define NONAMELESSUNION + +#include <stdarg.h> +#include <stdio.h> +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winnls.h" +#include "shlwapi.h" +#include "wingdi.h" +#include "wine/debug.h" +#include "msi.h" +#include "msiquery.h" +#include "msipriv.h" +#include "objidl.h" +#include "wincrypt.h" +#include "winuser.h" +#include "shlobj.h" +#include "wine/unicode.h" +#include "objbase.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +/* + * The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR, + * which is a problem because LPCTSTR isn't defined when compiling wine. + * To work around this problem, we need to define LPCTSTR as LPCWSTR here, + * and make sure to only use it in W functions. + */ +#define LPCTSTR LPCWSTR + +void MSI_FreePackage( MSIOBJECTHDR *arg) +{ + MSIPACKAGE *package= (MSIPACKAGE*) arg; + + if( package->dialog ) + msi_dialog_destroy( package->dialog ); + ACTION_free_package_structures(package); + + msiobj_release( &package->db->hdr ); +} + +static UINT clone_properties(MSIDATABASE *db) +{ + MSIQUERY * view = NULL; + UINT rc; + static const WCHAR CreateSql[] = { + 'C','R','E','A','T','E',' ','T','A','B','L','E',' ','`','_','P','r','o', + 'p','e','r','t','y','`',' ','(',' ','`','_','P','r','o','p','e','r','t', + 'y','`',' ','C','H','A','R','(','5','6',')',' ','N','O','T',' ','N','U', + 'L','L',',',' ','`','V','a','l','u','e','`',' ','C','H','A','R','(','9', + '8',')',' ','N','O','T',' ','N','U','L','L',' ','P','R','I','M','A','R', + 'Y',' ','K','E','Y',' ','`','_','P','r','o','p','e','r','t','y','`',')',0}; + static const WCHAR Query[] = { + 'S','E','L','E','C','T',' ','*',' ', + 'F','R','O','M',' ','`','P','r','o','p','e','r','t','y','`',0}; + static const WCHAR Insert[] = { + 'I','N','S','E','R','T',' ','i','n','t','o',' ', + '`','_','P','r','o','p','e','r','t','y','`',' ', + '(','`','_','P','r','o','p','e','r','t','y','`',',', + '`','V','a','l','u','e','`',')',' ', + 'V','A','L','U','E','S',' ','(','?',',','?',')',0}; + + /* create the temporary properties table */ + rc = MSI_DatabaseOpenViewW(db, CreateSql, &view); + if (rc != ERROR_SUCCESS) + return rc; + rc = MSI_ViewExecute(view,0); + MSI_ViewClose(view); + msiobj_release(&view->hdr); + if (rc != ERROR_SUCCESS) + return rc; + + /* clone the existing properties */ + rc = MSI_DatabaseOpenViewW(db, Query, &view); + if (rc != ERROR_SUCCESS) + return rc; + + rc = MSI_ViewExecute(view, 0); + if (rc != ERROR_SUCCESS) + { + MSI_ViewClose(view); + msiobj_release(&view->hdr); + return rc; + } + while (1) + { + MSIRECORD * row; + MSIQUERY * view2; + + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + break; + + rc = MSI_DatabaseOpenViewW(db,Insert,&view2); + if (rc!= ERROR_SUCCESS) + continue; + rc = MSI_ViewExecute(view2,row); + MSI_ViewClose(view2); + msiobj_release(&view2->hdr); + + if (rc == ERROR_SUCCESS) + msiobj_release(&row->hdr); + } + MSI_ViewClose(view); + msiobj_release(&view->hdr); + + return rc; +} + +/* + * There are a whole slew of these we need to set + * + * +http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/properties.asp + */ +static VOID set_installer_properties(MSIPACKAGE *package) +{ + WCHAR pth[MAX_PATH]; + WCHAR *ptr; + OSVERSIONINFOA OSVersion; + MEMORYSTATUSEX msex; + DWORD verval; + WCHAR verstr[10], bufstr[20]; + HDC dc; + + static const WCHAR cszbs[]={'\\',0}; + static const WCHAR CFF[] = +{'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0}; + static const WCHAR PFF[] = +{'P','r','o','g','r','a','m','F','i','l','e','s','F','o','l','d','e','r',0}; + static const WCHAR CADF[] = +{'C','o','m','m','o','n','A','p','p','D','a','t','a','F','o','l','d','e','r',0}; + static const WCHAR FaF[] = +{'F','a','v','o','r','i','t','e','s','F','o','l','d','e','r',0}; + static const WCHAR FoF[] = +{'F','o','n','t','s','F','o','l','d','e','r',0}; + static const WCHAR SendTF[] = +{'S','e','n','d','T','o','F','o','l','d','e','r',0}; + static const WCHAR SMF[] = +{'S','t','a','r','t','M','e','n','u','F','o','l','d','e','r',0}; + static const WCHAR StF[] = +{'S','t','a','r','t','u','p','F','o','l','d','e','r',0}; + static const WCHAR TemplF[] = +{'T','e','m','p','l','a','t','e','F','o','l','d','e','r',0}; + static const WCHAR DF[] = +{'D','e','s','k','t','o','p','F','o','l','d','e','r',0}; + static const WCHAR PMF[] = +{'P','r','o','g','r','a','m','M','e','n','u','F','o','l','d','e','r',0}; + static const WCHAR ATF[] = +{'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0}; + static const WCHAR ADF[] = +{'A','p','p','D','a','t','a','F','o','l','d','e','r',0}; + static const WCHAR SF[] = +{'S','y','s','t','e','m','F','o','l','d','e','r',0}; + static const WCHAR SF16[] = +{'S','y','s','t','e','m','1','6','F','o','l','d','e','r',0}; + static const WCHAR LADF[] = +{'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0}; + static const WCHAR MPF[] = +{'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0}; + static const WCHAR PF[] = +{'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0}; + static const WCHAR WF[] = +{'W','i','n','d','o','w','s','F','o','l','d','e','r',0}; + static const WCHAR WV[] = +{'W','i','n','d','o','w','s','V','o','l','u','m','e',0}; + static const WCHAR TF[]= +{'T','e','m','p','F','o','l','d','e','r',0}; + static const WCHAR szAdminUser[] = +{'A','d','m','i','n','U','s','e','r',0}; + static const WCHAR szPriv[] = +{'P','r','i','v','i','l','e','g','e','d',0}; + static const WCHAR szOne[] = +{'1',0}; + static const WCHAR v9x[] = { 'V','e','r','s','i','o','n','9','X',0 }; + static const WCHAR vNT[] = { 'V','e','r','s','i','o','n','N','T',0 }; + static const WCHAR szFormat[] = {'%','l','i',0}; + static const WCHAR szWinBuild[] = +{'W','i','n','d','o','w','s','B','u','i','l','d', 0 }; + static const WCHAR szSPL[] = +{'S','e','r','v','i','c','e','P','a','c','k','L','e','v','e','l',0 }; + static const WCHAR szSix[] = {'6',0 }; + + static const WCHAR szVersionMsi[] = { 'V','e','r','s','i','o','n','M','s','i',0 }; + static const WCHAR szPhysicalMemory[] = { 'P','h','y','s','i','c','a','l','M','e','m','o','r','y',0 }; + static const WCHAR szFormat2[] = {'%','l','i','.','%','l','i',0}; +/* Screen properties */ + static const WCHAR szScreenX[] = {'S','c','r','e','e','n','X',0}; + static const WCHAR szScreenY[] = {'S','c','r','e','e','n','Y',0}; + static const WCHAR szColorBits[] = {'C','o','l','o','r','B','i','t','s',0}; + static const WCHAR szScreenFormat[] = {'%','d',0}; + +/* + * Other things I notice set + * +SystemLanguageID +ComputerName +UserLanguageID +LogonUser +VirtualMemory +Intel +ShellAdvSupport +DefaultUIFont +VersionDatabase +PackagecodeChanging +ProductState +CaptionHeight +BorderTop +BorderSide +TextHeight +RedirectedDllSupport +Time +Date +Privileged +*/ + + SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth); + strcatW(pth,cszbs); + MSI_SetPropertyW(package, CFF, pth); + + SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES,NULL,0,pth); + strcatW(pth,cszbs); + MSI_SetPropertyW(package, PFF, pth); + + SHGetFolderPathW(NULL,CSIDL_COMMON_APPDATA,NULL,0,pth); + strcatW(pth,cszbs); + MSI_SetPropertyW(package, CADF, pth); + + SHGetFolderPathW(NULL,CSIDL_FAVORITES,NULL,0,pth); + strcatW(pth,cszbs); + MSI_SetPropertyW(package, FaF, pth); + + SHGetFolderPathW(NULL,CSIDL_FONTS,NULL,0,pth); + strcatW(pth,cszbs); + MSI_SetPropertyW(package, FoF, pth); + + SHGetFolderPathW(NULL,CSIDL_SENDTO,NULL,0,pth); + strcatW(pth,cszbs); + MSI_SetPropertyW(package, SendTF, pth); + + SHGetFolderPathW(NULL,CSIDL_STARTMENU,NULL,0,pth); + strcatW(pth,cszbs); + MSI_SetPropertyW(package, SMF, pth); + + SHGetFolderPathW(NULL,CSIDL_STARTUP,NULL,0,pth); + strcatW(pth,cszbs); + MSI_SetPropertyW(package, StF, pth); + + SHGetFolderPathW(NULL,CSIDL_TEMPLATES,NULL,0,pth); + strcatW(pth,cszbs); + MSI_SetPropertyW(package, TemplF, pth); + + SHGetFolderPathW(NULL,CSIDL_DESKTOP,NULL,0,pth); + strcatW(pth,cszbs); + MSI_SetPropertyW(package, DF, pth); + + SHGetFolderPathW(NULL,CSIDL_PROGRAMS,NULL,0,pth); + strcatW(pth,cszbs); + MSI_SetPropertyW(package, PMF, pth); + + SHGetFolderPathW(NULL,CSIDL_ADMINTOOLS,NULL,0,pth); + strcatW(pth,cszbs); + MSI_SetPropertyW(package, ATF, pth); + + SHGetFolderPathW(NULL,CSIDL_APPDATA,NULL,0,pth); + strcatW(pth,cszbs); + MSI_SetPropertyW(package, ADF, pth); + + SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth); + strcatW(pth,cszbs); + MSI_SetPropertyW(package, SF, pth); + MSI_SetPropertyW(package, SF16, pth); + + SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth); + strcatW(pth,cszbs); + MSI_SetPropertyW(package, LADF, pth); + + SHGetFolderPathW(NULL,CSIDL_MYPICTURES,NULL,0,pth); + strcatW(pth,cszbs); + MSI_SetPropertyW(package, MPF, pth); + + SHGetFolderPathW(NULL,CSIDL_PERSONAL,NULL,0,pth); + strcatW(pth,cszbs); + MSI_SetPropertyW(package, PF, pth); + + SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth); + strcatW(pth,cszbs); + MSI_SetPropertyW(package, WF, pth); + + /* Physical Memory is specified in MB. Using total amount. */ + msex.dwLength = sizeof(msex); + GlobalMemoryStatusEx( &msex ); + sprintfW( bufstr, szScreenFormat, (int)(msex.ullTotalPhys/1024/1024)); + MSI_SetPropertyW(package, szPhysicalMemory, bufstr); + + SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth); + ptr = strchrW(pth,'\\'); + if (ptr) + *(ptr+1) = 0; + MSI_SetPropertyW(package, WV, pth); + + GetTempPathW(MAX_PATH,pth); + MSI_SetPropertyW(package, TF, pth); + + + /* in a wine environment the user is always admin and privileged */ + MSI_SetPropertyW(package,szAdminUser,szOne); + MSI_SetPropertyW(package,szPriv,szOne); + + /* set the os things */ + OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); + GetVersionExA(&OSVersion); + verval = OSVersion.dwMinorVersion+OSVersion.dwMajorVersion*100; + sprintfW(verstr,szFormat,verval); + switch (OSVersion.dwPlatformId) + { + case VER_PLATFORM_WIN32_WINDOWS: + MSI_SetPropertyW(package,v9x,verstr); + break; + case VER_PLATFORM_WIN32_NT: + MSI_SetPropertyW(package,vNT,verstr); + break; + } + sprintfW(verstr,szFormat,OSVersion.dwBuildNumber); + MSI_SetPropertyW(package,szWinBuild,verstr); + /* just fudge this */ + MSI_SetPropertyW(package,szSPL,szSix); + + sprintfW( bufstr, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION); + MSI_SetPropertyW( package, szVersionMsi, bufstr ); + + /* Screen properties. */ + dc = GetDC(0); + sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, HORZRES ) ); + MSI_SetPropertyW( package, szScreenX, bufstr ); + sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, VERTRES )); + MSI_SetPropertyW( package, szScreenY, bufstr ); + sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, BITSPIXEL )); + MSI_SetPropertyW( package, szColorBits, bufstr ); + ReleaseDC(0, dc); +} + +MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db ) +{ + static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 }; + static const WCHAR szpi[] = {'%','i',0}; + MSIPACKAGE *package = NULL; + WCHAR uilevel[10]; + + TRACE("%p\n", db); + + package = alloc_msiobject( MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE), + MSI_FreePackage ); + if( package ) + { + msiobj_addref( &db->hdr ); + + package->db = db; + package->features = NULL; + package->folders = NULL; + package->components = NULL; + package->files = NULL; + package->loaded_features = 0; + package->loaded_folders = 0; + package->loaded_components= 0; + package->loaded_files = 0; + package->ActionFormat = NULL; + package->LastAction = NULL; + package->dialog = NULL; + package->next_dialog = NULL; + + /* OK, here is where we do a slew of things to the database to + * prep for all that is to come as a package */ + + clone_properties(db); + set_installer_properties(package); + sprintfW(uilevel,szpi,gUILevel); + MSI_SetPropertyW(package, szLevel, uilevel); + } + + return package; +} + +UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage) +{ + MSIDATABASE *db = NULL; + MSIPACKAGE *package; + MSIHANDLE handle; + + TRACE("%s %p\n", debugstr_w(szPackage), pPackage); + + if( szPackage[0] == '#' ) + { + handle = atoiW(&szPackage[1]); + db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE ); + if( !db ) + return ERROR_INVALID_HANDLE; + } + else + { + UINT r = MSI_OpenDatabaseW(szPackage, MSIDBOPEN_READONLY, &db); + if( r != ERROR_SUCCESS ) + return r; + } + + package = MSI_CreatePackage( db ); + msiobj_release( &db->hdr ); + if( !package ) + return ERROR_FUNCTION_FAILED; + + /* + * FIXME: I don't think this is right. Maybe we should be storing the + * name of the database in the MSIDATABASE structure and fetching this + * info from there, or maybe this is only relevant to cached databases. + */ + if( szPackage[0] != '#' ) + { + static const WCHAR OriginalDatabase[] = + {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0}; + static const WCHAR Database[] = {'D','A','T','A','B','A','S','E',0}; + + MSI_SetPropertyW( package, OriginalDatabase, szPackage ); + MSI_SetPropertyW( package, Database, szPackage ); + } + + *pPackage = package; + + return ERROR_SUCCESS; +} + +UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage) +{ + MSIPACKAGE *package = NULL; + UINT ret; + + TRACE("%s %08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage); + + if( dwOptions ) + FIXME("dwOptions %08lx not supported\n", dwOptions); + + ret = MSI_OpenPackageW( szPackage, &package); + if( ret == ERROR_SUCCESS ) + { + *phPackage = alloc_msihandle( &package->hdr ); + msiobj_release( &package->hdr ); + } + return ret; +} + +UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage) +{ + return MsiOpenPackageExW( szPackage, 0, phPackage ); +} + +UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage) +{ + LPWSTR szwPack = NULL; + UINT ret; + + if( szPackage ) + { + szwPack = strdupAtoW( szPackage ); + if( !szwPack ) + return ERROR_OUTOFMEMORY; + } + + ret = MsiOpenPackageExW( szwPack, dwOptions, phPackage ); + + HeapFree( GetProcessHeap(), 0, szwPack ); + + return ret; +} + +UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage) +{ + return MsiOpenPackageExA( szPackage, 0, phPackage ); +} + +MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall) +{ + MSIPACKAGE *package; + MSIHANDLE handle = 0; + + TRACE("(%ld)\n",hInstall); + + package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); + if( package) + { + handle = alloc_msihandle( &package->db->hdr ); + msiobj_release( &package->hdr ); + } + + return handle; +} + +INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType, + MSIRECORD *record) +{ + DWORD log_type = 0; + LPWSTR message; + DWORD sz; + DWORD total_size = 0; + INT msg_field=1; + INT i; + INT rc; + char *msg; + int len; + + TRACE("%x \n",eMessageType); + rc = 0; + + if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR) + log_type |= INSTALLLOGMODE_ERROR; + if ((eMessageType & 0xff000000) == INSTALLMESSAGE_WARNING) + log_type |= INSTALLLOGMODE_WARNING; + if ((eMessageType & 0xff000000) == INSTALLMESSAGE_USER) + log_type |= INSTALLLOGMODE_USER; + if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INFO) + log_type |= INSTALLLOGMODE_INFO; + if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA) + log_type |= INSTALLLOGMODE_COMMONDATA; + if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART) + log_type |= INSTALLLOGMODE_ACTIONSTART; + if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA) + log_type |= INSTALLLOGMODE_ACTIONDATA; + /* just a guess */ + if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS) + log_type |= 0x800; + + message = HeapAlloc(GetProcessHeap(),0,1*sizeof (WCHAR)); + message[0]=0; + msg_field = MSI_RecordGetFieldCount(record); + for (i = 1; i <= msg_field; i++) + { + LPWSTR tmp; + WCHAR number[3]; + const static WCHAR format[] = { '%','i',':',' ',0}; + const static WCHAR space[] = { ' ',0}; + sz = 0; + MSI_RecordGetStringW(record,i,NULL,&sz); + sz+=4; + total_size+=sz*sizeof(WCHAR); + tmp = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR)); + message = HeapReAlloc(GetProcessHeap(),0,message,total_size*sizeof (WCHAR)); + + MSI_RecordGetStringW(record,i,tmp,&sz); + + if (msg_field > 1) + { + sprintfW(number,format,i); + strcatW(message,number); + } + strcatW(message,tmp); + if (msg_field > 1) + strcatW(message,space); + + HeapFree(GetProcessHeap(),0,tmp); + } + + TRACE("(%p %lx %lx %s)\n",gUIHandlerA, gUIFilter, log_type, + debugstr_w(message)); + + /* convert it to ASCII */ + len = WideCharToMultiByte( CP_ACP, 0, message, -1, + NULL, 0, NULL, NULL ); + msg = HeapAlloc( GetProcessHeap(), 0, len ); + WideCharToMultiByte( CP_ACP, 0, message, -1, + msg, len, NULL, NULL ); + + if (gUIHandlerA && (gUIFilter & log_type)) + { + rc = gUIHandlerA(gUIContext,eMessageType,msg); + } + + if ((!rc) && (gszLogFile[0]) && !((eMessageType & 0xff000000) == + INSTALLMESSAGE_PROGRESS)) + { + DWORD write; + HANDLE log_file = CreateFileW(gszLogFile,GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (log_file != INVALID_HANDLE_VALUE) + { + SetFilePointer(log_file,0, NULL, FILE_END); + WriteFile(log_file,msg,strlen(msg),&write,NULL); + WriteFile(log_file,"\n",1,&write,NULL); + CloseHandle(log_file); + } + } + HeapFree( GetProcessHeap(), 0, msg ); + + HeapFree(GetProcessHeap(),0,message); + return ERROR_SUCCESS; +} + +INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType, + MSIHANDLE hRecord) +{ + UINT ret = ERROR_INVALID_HANDLE; + MSIPACKAGE *package = NULL; + MSIRECORD *record = NULL; + + package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE ); + if( !package ) + return ERROR_INVALID_HANDLE; + + record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD ); + if( !record ) + goto out; + + ret = MSI_ProcessMessage( package, eMessageType, record ); + +out: + msiobj_release( &package->hdr ); + if( record ) + msiobj_release( &record->hdr ); + + return ret; +} + +/* property code */ +UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue) +{ + LPWSTR szwName = NULL, szwValue = NULL; + UINT hr = ERROR_INSTALL_FAILURE; + + if( szName ) + { + szwName = strdupAtoW( szName ); + if( !szwName ) + goto end; + } + + if( szValue ) + { + szwValue = strdupAtoW( szValue ); + if( !szwValue) + goto end; + } + + hr = MsiSetPropertyW( hInstall, szwName, szwValue); + +end: + HeapFree( GetProcessHeap(), 0, szwName ); + HeapFree( GetProcessHeap(), 0, szwValue ); + + return hr; +} + +UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue) +{ + MSIQUERY *view; + MSIRECORD *row; + UINT rc; + DWORD sz = 0; + static const WCHAR Insert[]= + {'I','N','S','E','R','T',' ','i','n','t','o',' ','`','_','P','r','o','p' +,'e','r','t','y','`',' ','(','`','_','P','r','o','p','e','r','t','y','`' +,',','`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S' +,' ','(','?',',','?',')',0}; + static const WCHAR Update[]= + {'U','P','D','A','T','E',' ','_','P','r','o','p','e' +,'r','t','y',' ','s','e','t',' ','`','V','a','l','u','e','`',' ','=' +,' ','?',' ','w','h','e','r','e',' ','`','_','P','r','o','p' +,'e','r','t','y','`',' ','=',' ','\'','%','s','\'',0}; + WCHAR Query[1024]; + + TRACE("Setting property (%s %s)\n",debugstr_w(szName), + debugstr_w(szValue)); + + rc = MSI_GetPropertyW(package,szName,0,&sz); + if (rc==ERROR_MORE_DATA || rc == ERROR_SUCCESS) + { + sprintfW(Query,Update,szName); + + row = MSI_CreateRecord(1); + MSI_RecordSetStringW(row,1,szValue); + + } + else + { + strcpyW(Query,Insert); + + row = MSI_CreateRecord(2); + MSI_RecordSetStringW(row,1,szName); + MSI_RecordSetStringW(row,2,szValue); + } + + + rc = MSI_DatabaseOpenViewW(package->db,Query,&view); + if (rc!= ERROR_SUCCESS) + { + msiobj_release(&row->hdr); + return rc; + } + + rc = MSI_ViewExecute(view,row); + + msiobj_release(&row->hdr); + MSI_ViewClose(view); + msiobj_release(&view->hdr); + + return rc; +} + +UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue) +{ + MSIPACKAGE *package; + UINT ret; + + if (NULL == szName) + return ERROR_INVALID_PARAMETER; + if (NULL == szValue) + return ERROR_INVALID_PARAMETER; + + package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); + if( !package ) + return ERROR_INVALID_HANDLE; + ret = MSI_SetPropertyW( package, szName, szValue); + msiobj_release( &package->hdr ); + return ret; +} + +static UINT MSI_GetPropertyRow(MSIPACKAGE *package, LPCWSTR szName, MSIRECORD **row) +{ + MSIQUERY *view; + UINT rc, sz; + static const WCHAR select[]= + {'S','E','L','E','C','T',' ','`','V','a','l','u','e','`',' ', + 'F','R','O','M',' ' ,'`','_','P','r','o','p','e','r','t','y','`', + ' ','W','H','E','R','E',' ' ,'`','_','P','r','o','p','e','r','t','y','`', + '=','\'','%','s','\'',0}; + LPWSTR query; + + if (!szName) + return ERROR_INVALID_PARAMETER; + + sz = sizeof select + strlenW(szName)*sizeof(WCHAR); + query = HeapAlloc(GetProcessHeap(), 0, sz); + sprintfW(query,select,szName); + + rc = MSI_DatabaseOpenViewW(package->db, query, &view); + HeapFree(GetProcessHeap(), 0, query); + if (rc == ERROR_SUCCESS) + { + rc = MSI_ViewExecute(view, 0); + if (rc == ERROR_SUCCESS) + rc = MSI_ViewFetch(view,row); + + MSI_ViewClose(view); + msiobj_release(&view->hdr); + } + + return rc; +} + +UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName, + LPWSTR szValueBuf, DWORD* pchValueBuf) +{ + MSIRECORD *row; + UINT rc; + + rc = MSI_GetPropertyRow(package, szName, &row); + + if (*pchValueBuf > 0) + szValueBuf[0] = 0; + + if (rc == ERROR_SUCCESS) + { + rc = MSI_RecordGetStringW(row,1,szValueBuf,pchValueBuf); + msiobj_release(&row->hdr); + } + + if (rc == ERROR_SUCCESS) + TRACE("returning %s for property %s\n", debugstr_w(szValueBuf), + debugstr_w(szName)); + else if (rc == ERROR_MORE_DATA) + TRACE("need %li sized buffer for %s\n", *pchValueBuf, + debugstr_w(szName)); + else + { + *pchValueBuf = 0; + TRACE("property %s not found\n", debugstr_w(szName)); + } + + return rc; +} + +UINT MSI_GetPropertyA(MSIPACKAGE *package, LPCSTR szName, + LPSTR szValueBuf, DWORD* pchValueBuf) +{ + MSIRECORD *row; + UINT rc; + LPWSTR szwName = NULL; + + if (*pchValueBuf > 0) + szValueBuf[0] = 0; + + if( szName ) + { + szwName = strdupAtoW( szName ); + if (!szwName) + return ERROR_NOT_ENOUGH_MEMORY; + } + + rc = MSI_GetPropertyRow(package, szwName, &row); + if (rc == ERROR_SUCCESS) + { + rc = MSI_RecordGetStringA(row,1,szValueBuf,pchValueBuf); + msiobj_release(&row->hdr); + } + + if (rc == ERROR_SUCCESS) + TRACE("returning %s for property %s\n", debugstr_a(szValueBuf), + debugstr_a(szName)); + else if (rc == ERROR_MORE_DATA) + TRACE("need %ld sized buffer for %s\n", *pchValueBuf, + debugstr_a(szName)); + else + { + *pchValueBuf = 0; + TRACE("property not found\n"); + } + HeapFree( GetProcessHeap(), 0, szwName ); + + return rc; +} + +UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf) +{ + MSIPACKAGE *package; + UINT ret; + + TRACE("%lu %s %lu\n", hInstall, debugstr_a(szName), *pchValueBuf); + + if (0 == hInstall) + return ERROR_INVALID_HANDLE; + if (NULL == szName) + return ERROR_INVALID_PARAMETER; + if (NULL != szValueBuf && NULL == pchValueBuf) + return ERROR_INVALID_PARAMETER; + + package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); + if (!package) + return ERROR_INVALID_HANDLE; + ret = MSI_GetPropertyA(package, szName, szValueBuf, pchValueBuf ); + msiobj_release( &package->hdr ); + + /* MsiGetProperty does not return error codes on missing properties */ + if (ret!= ERROR_MORE_DATA) + return ERROR_SUCCESS; + else + return ret; +} + + +UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, + LPWSTR szValueBuf, DWORD* pchValueBuf) +{ + MSIPACKAGE *package; + UINT ret; + + if (0 == hInstall) + return ERROR_INVALID_HANDLE; + if (NULL == szName) + return ERROR_INVALID_PARAMETER; + if (NULL != szValueBuf && NULL == pchValueBuf) + return ERROR_INVALID_PARAMETER; + + package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); + if (!package) + return ERROR_INVALID_HANDLE; + ret = MSI_GetPropertyW(package, szName, szValueBuf, pchValueBuf ); + msiobj_release( &package->hdr ); + + /* MsiGetProperty does not return error codes on missing properties */ + if (ret!= ERROR_MORE_DATA) + return ERROR_SUCCESS; + else + return ret; +} diff --git a/reactos/lib/msi/query.h b/reactos/lib/msi/query.h index 7227129405d..28f74b515e4 100644 --- a/reactos/lib/msi/query.h +++ b/reactos/lib/msi/query.h @@ -1,138 +1,138 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2002 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_MSI_QUERY_H -#define __WINE_MSI_QUERY_H - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "objbase.h" -#include "objidl.h" -#include "msi.h" -#include "msiquery.h" -#include "msipriv.h" -#include "wine/list.h" - - -#define OP_EQ 1 -#define OP_AND 2 -#define OP_OR 3 -#define OP_GT 4 -#define OP_LT 5 -#define OP_LE 6 -#define OP_GE 7 -#define OP_NE 8 -#define OP_ISNULL 9 -#define OP_NOTNULL 10 - -#define EXPR_COMPLEX 1 -#define EXPR_COLUMN 2 -#define EXPR_COL_NUMBER 3 -#define EXPR_IVAL 4 -#define EXPR_SVAL 5 -#define EXPR_UVAL 6 -#define EXPR_STRCMP 7 -#define EXPR_WILDCARD 9 -#define EXPR_COL_NUMBER_STRING 10 - -struct sql_str { - LPCWSTR data; - INT len; -}; - -typedef struct _string_list -{ - LPWSTR string; - struct _string_list *next; -} string_list; - -struct complex_expr -{ - UINT op; - struct expr *left; - struct expr *right; -}; - -struct expr -{ - int type; - union - { - struct complex_expr expr; - INT ival; - UINT uval; - LPWSTR sval; - LPWSTR column; - UINT col_number; - } u; -}; - -typedef struct _create_col_info -{ - LPWSTR colname; - UINT type; - struct _create_col_info *next; -} create_col_info; - -typedef struct _value_list -{ - struct expr *val; - struct _value_list *next; -} value_list; - -typedef struct _column_assignment -{ - string_list *col_list; - value_list *val_list; -} column_assignment; - - -UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview, - struct list *mem ); - -UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view ); - -UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, - string_list *columns ); - -UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table ); - -UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, - string_list *columns ); - -UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, - struct expr *cond ); - -UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, - create_col_info *col_info, BOOL temp ); - -UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, - string_list *columns, value_list *values, BOOL temp ); - -UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **, LPWSTR table, - column_assignment *list, struct expr *expr ); - -UINT DELETE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table ); - -int sqliteGetToken(const WCHAR *z, int *tokenType); - -#endif /* __WINE_MSI_QUERY_H */ +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2002 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_MSI_QUERY_H +#define __WINE_MSI_QUERY_H + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" +#include "objidl.h" +#include "msi.h" +#include "msiquery.h" +#include "msipriv.h" +#include "wine/list.h" + + +#define OP_EQ 1 +#define OP_AND 2 +#define OP_OR 3 +#define OP_GT 4 +#define OP_LT 5 +#define OP_LE 6 +#define OP_GE 7 +#define OP_NE 8 +#define OP_ISNULL 9 +#define OP_NOTNULL 10 + +#define EXPR_COMPLEX 1 +#define EXPR_COLUMN 2 +#define EXPR_COL_NUMBER 3 +#define EXPR_IVAL 4 +#define EXPR_SVAL 5 +#define EXPR_UVAL 6 +#define EXPR_STRCMP 7 +#define EXPR_WILDCARD 9 +#define EXPR_COL_NUMBER_STRING 10 + +struct sql_str { + LPCWSTR data; + INT len; +}; + +typedef struct _string_list +{ + LPWSTR string; + struct _string_list *next; +} string_list; + +struct complex_expr +{ + UINT op; + struct expr *left; + struct expr *right; +}; + +struct expr +{ + int type; + union + { + struct complex_expr expr; + INT ival; + UINT uval; + LPWSTR sval; + LPWSTR column; + UINT col_number; + } u; +}; + +typedef struct _create_col_info +{ + LPWSTR colname; + UINT type; + struct _create_col_info *next; +} create_col_info; + +typedef struct _value_list +{ + struct expr *val; + struct _value_list *next; +} value_list; + +typedef struct _column_assignment +{ + string_list *col_list; + value_list *val_list; +} column_assignment; + + +UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview, + struct list *mem ); + +UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view ); + +UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, + string_list *columns ); + +UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table ); + +UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, + string_list *columns ); + +UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, + struct expr *cond ); + +UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, + create_col_info *col_info, BOOL temp ); + +UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, + string_list *columns, value_list *values, BOOL temp ); + +UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **, LPWSTR table, + column_assignment *list, struct expr *expr ); + +UINT DELETE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table ); + +int sqliteGetToken(const WCHAR *z, int *tokenType); + +#endif /* __WINE_MSI_QUERY_H */ diff --git a/reactos/lib/msi/record.c b/reactos/lib/msi/record.c index 2b0469040c2..57a1d71279a 100644 --- a/reactos/lib/msi/record.c +++ b/reactos/lib/msi/record.c @@ -1,763 +1,763 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2002-2004 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "winerror.h" -#include "wine/debug.h" -#include "msi.h" -#include "msiquery.h" -#include "msipriv.h" -#include "objidl.h" -#include "winnls.h" -#include "ole2.h" - -#include "query.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -#define MSIFIELD_NULL 0 -#define MSIFIELD_INT 1 -#define MSIFIELD_STR 2 -#define MSIFIELD_WSTR 3 -#define MSIFIELD_STREAM 4 - -void MSI_FreeField( MSIFIELD *field ) -{ - switch( field->type ) - { - case MSIFIELD_NULL: - case MSIFIELD_INT: - break; - case MSIFIELD_WSTR: - HeapFree( GetProcessHeap(), 0, field->u.szwVal); - break; - case MSIFIELD_STREAM: - IStream_Release( field->u.stream ); - break; - default: - ERR("Invalid field type %d\n", field->type); - } -} - -void MSI_CloseRecord( MSIOBJECTHDR *arg ) -{ - MSIRECORD *rec = (MSIRECORD *) arg; - UINT i; - - for( i=0; i<=rec->count; i++ ) - MSI_FreeField( &rec->fields[i] ); -} - -MSIRECORD *MSI_CreateRecord( unsigned int cParams ) -{ - MSIRECORD *rec; - UINT len; - - TRACE("%d\n", cParams); - - if( cParams>65535 ) - return NULL; - - len = sizeof (MSIRECORD) + sizeof (MSIFIELD)*cParams; - rec = alloc_msiobject( MSIHANDLETYPE_RECORD, len, MSI_CloseRecord ); - if( rec ) - rec->count = cParams; - return rec; -} - -MSIHANDLE WINAPI MsiCreateRecord( unsigned int cParams ) -{ - MSIRECORD *rec; - MSIHANDLE ret = 0; - - TRACE("%d\n", cParams); - - rec = MSI_CreateRecord( cParams ); - if( rec ) - ret = alloc_msihandle( &rec->hdr ); - msiobj_release( &rec->hdr ); - return ret; -} - -unsigned int MSI_RecordGetFieldCount( MSIRECORD *rec ) -{ - return rec->count; -} - -unsigned int WINAPI MsiRecordGetFieldCount( MSIHANDLE handle ) -{ - MSIRECORD *rec; - UINT ret; - - TRACE("%ld\n", handle ); - - rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); - if( !rec ) - return -1; - - msiobj_lock( &rec->hdr ); - ret = MSI_RecordGetFieldCount( rec ); - msiobj_unlock( &rec->hdr ); - msiobj_release( &rec->hdr ); - - return ret; -} - -static BOOL string2intW( LPCWSTR str, int *out ) -{ - int x = 0; - LPCWSTR p = str; - - if( *p == '-' ) /* skip the minus sign */ - p++; - while ( *p ) - { - if( (*p < '0') || (*p > '9') ) - return FALSE; - x *= 10; - x += (*p - '0'); - p++; - } - - if( str[0] == '-' ) /* check if it's negative */ - x = -x; - *out = x; - - return TRUE; -} - -int MSI_RecordGetInteger( MSIRECORD *rec, unsigned int iField) -{ - int ret = 0; - - TRACE("%p %d\n", rec, iField ); - - if( iField > rec->count ) - return MSI_NULL_INTEGER; - - switch( rec->fields[iField].type ) - { - case MSIFIELD_INT: - return rec->fields[iField].u.iVal; - case MSIFIELD_WSTR: - if( string2intW( rec->fields[iField].u.szwVal, &ret ) ) - return ret; - return MSI_NULL_INTEGER; - default: - break; - } - - return MSI_NULL_INTEGER; -} - -int WINAPI MsiRecordGetInteger( MSIHANDLE handle, unsigned int iField) -{ - MSIRECORD *rec; - UINT ret; - - TRACE("%ld %d\n", handle, iField ); - - rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); - if( !rec ) - return MSI_NULL_INTEGER; - - msiobj_lock( &rec->hdr ); - ret = MSI_RecordGetInteger( rec, iField ); - msiobj_unlock( &rec->hdr ); - msiobj_release( &rec->hdr ); - - return ret; -} - -UINT WINAPI MsiRecordClearData( MSIHANDLE handle ) -{ - MSIRECORD *rec; - UINT i; - - TRACE("%ld\n", handle ); - - rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); - if( !rec ) - return ERROR_INVALID_HANDLE; - - msiobj_lock( &rec->hdr ); - for( i=0; i<=rec->count; i++) - { - MSI_FreeField( &rec->fields[i] ); - rec->fields[i].type = MSIFIELD_NULL; - rec->fields[i].u.iVal = 0; - } - msiobj_unlock( &rec->hdr ); - msiobj_release( &rec->hdr ); - - return ERROR_SUCCESS; -} - -UINT MSI_RecordSetInteger( MSIRECORD *rec, unsigned int iField, int iVal ) -{ - TRACE("%p %u %d\n", rec, iField, iVal); - - if( iField > rec->count ) - return ERROR_INVALID_PARAMETER; - - MSI_FreeField( &rec->fields[iField] ); - rec->fields[iField].type = MSIFIELD_INT; - rec->fields[iField].u.iVal = iVal; - - return ERROR_SUCCESS; -} - -UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, unsigned int iField, int iVal ) -{ - MSIRECORD *rec; - UINT ret; - - TRACE("%ld %u %d\n", handle, iField, iVal); - - rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); - if( !rec ) - return ERROR_INVALID_HANDLE; - - msiobj_lock( &rec->hdr ); - ret = MSI_RecordSetInteger( rec, iField, iVal ); - msiobj_unlock( &rec->hdr ); - msiobj_release( &rec->hdr ); - return ret; -} - -BOOL MSI_RecordIsNull( MSIRECORD *rec, unsigned int iField ) -{ - BOOL r = TRUE; - - TRACE("%p %d\n", rec, iField ); - - r = ( iField > rec->count ) || - ( rec->fields[iField].type == MSIFIELD_NULL ); - - return r; -} - -BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, unsigned int iField ) -{ - MSIRECORD *rec; - UINT ret; - - TRACE("%ld %d\n", handle, iField ); - - rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); - if( !rec ) - return 0; - msiobj_lock( &rec->hdr ); - ret = MSI_RecordIsNull( rec, iField ); - msiobj_unlock( &rec->hdr ); - msiobj_release( &rec->hdr ); - return ret; - -} - -UINT MSI_RecordGetStringA(MSIRECORD *rec, unsigned int iField, - LPSTR szValue, DWORD *pcchValue) -{ - UINT len=0, ret; - CHAR buffer[16]; - - TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue); - - if( iField > rec->count ) - return ERROR_INVALID_PARAMETER; - - ret = ERROR_SUCCESS; - switch( rec->fields[iField].type ) - { - case MSIFIELD_INT: - wsprintfA(buffer, "%d", rec->fields[iField].u.iVal); - len = lstrlenA( buffer ); - lstrcpynA(szValue, buffer, *pcchValue); - break; - case MSIFIELD_WSTR: - len = WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1, - NULL, 0 , NULL, NULL); - WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1, - szValue, *pcchValue, NULL, NULL); - if( *pcchValue && len>*pcchValue ) - szValue[*pcchValue-1] = 0; - if( len ) - len--; - break; - case MSIFIELD_NULL: - if( *pcchValue > 0 ) - szValue[0] = 0; - break; - default: - ret = ERROR_INVALID_PARAMETER; - break; - } - - if( *pcchValue < len ) - ret = ERROR_MORE_DATA; - *pcchValue = len; - - return ret; -} - -UINT WINAPI MsiRecordGetStringA(MSIHANDLE handle, unsigned int iField, - LPSTR szValue, DWORD *pcchValue) -{ - MSIRECORD *rec; - UINT ret; - - TRACE("%ld %d %p %p\n", handle, iField, szValue, pcchValue); - - rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); - if( !rec ) - return ERROR_INVALID_HANDLE; - msiobj_lock( &rec->hdr ); - ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue); - msiobj_unlock( &rec->hdr ); - msiobj_release( &rec->hdr ); - return ret; -} - -const WCHAR *MSI_RecordGetString( MSIRECORD *rec, unsigned int iField ) -{ - if( iField > rec->count ) - return NULL; - - if( rec->fields[iField].type != MSIFIELD_WSTR ) - return NULL; - - return rec->fields[iField].u.szwVal; -} - -UINT MSI_RecordGetStringW(MSIRECORD *rec, unsigned int iField, - LPWSTR szValue, DWORD *pcchValue) -{ - UINT len=0, ret; - WCHAR buffer[16]; - static const WCHAR szFormat[] = { '%','d',0 }; - - TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue); - - if( iField > rec->count ) - return ERROR_INVALID_PARAMETER; - - ret = ERROR_SUCCESS; - switch( rec->fields[iField].type ) - { - case MSIFIELD_INT: - wsprintfW(buffer, szFormat, rec->fields[iField].u.iVal); - len = lstrlenW( buffer ); - lstrcpynW(szValue, buffer, *pcchValue); - break; - case MSIFIELD_WSTR: - len = lstrlenW( rec->fields[iField].u.szwVal ); - lstrcpynW(szValue, rec->fields[iField].u.szwVal, *pcchValue); - break; - case MSIFIELD_NULL: - len = 1; - if( *pcchValue > 0 ) - szValue[0] = 0; - default: - break; - } - - if( *pcchValue < len ) - ret = ERROR_MORE_DATA; - *pcchValue = len; - - return ret; -} - -UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, unsigned int iField, - LPWSTR szValue, DWORD *pcchValue) -{ - MSIRECORD *rec; - UINT ret; - - TRACE("%ld %d %p %p\n", handle, iField, szValue, pcchValue); - - rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); - if( !rec ) - return ERROR_INVALID_HANDLE; - - msiobj_lock( &rec->hdr ); - ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue ); - msiobj_unlock( &rec->hdr ); - msiobj_release( &rec->hdr ); - return ret; -} - -UINT MSI_RecordDataSize(MSIRECORD *rec, unsigned int iField) -{ - TRACE("%p %d\n", rec, iField); - - if( iField > rec->count ) - return 0; - - switch( rec->fields[iField].type ) - { - case MSIFIELD_INT: - return sizeof (INT); - case MSIFIELD_WSTR: - return lstrlenW( rec->fields[iField].u.szwVal ); - case MSIFIELD_NULL: - break; - } - return 0; -} - -UINT WINAPI MsiRecordDataSize(MSIHANDLE handle, unsigned int iField) -{ - MSIRECORD *rec; - UINT ret; - - TRACE("%ld %d\n", handle, iField); - - rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); - if( !rec ) - return 0; - msiobj_lock( &rec->hdr ); - ret = MSI_RecordDataSize( rec, iField); - msiobj_unlock( &rec->hdr ); - msiobj_release( &rec->hdr ); - return ret; -} - -UINT MSI_RecordSetStringA( MSIRECORD *rec, unsigned int iField, LPCSTR szValue ) -{ - LPWSTR str; - - TRACE("%p %d %s\n", rec, iField, debugstr_a(szValue)); - - if( iField > rec->count ) - return ERROR_INVALID_FIELD; - - MSI_FreeField( &rec->fields[iField] ); - if( szValue && szValue[0] ) - { - str = strdupAtoW( szValue ); - rec->fields[iField].type = MSIFIELD_WSTR; - rec->fields[iField].u.szwVal = str; - } - else - { - rec->fields[iField].type = MSIFIELD_NULL; - rec->fields[iField].u.szwVal = NULL; - } - - return 0; -} - -UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, unsigned int iField, LPCSTR szValue ) -{ - MSIRECORD *rec; - UINT ret; - - TRACE("%ld %d %s\n", handle, iField, debugstr_a(szValue)); - - rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); - if( !rec ) - return ERROR_INVALID_HANDLE; - msiobj_lock( &rec->hdr ); - ret = MSI_RecordSetStringA( rec, iField, szValue ); - msiobj_unlock( &rec->hdr ); - msiobj_release( &rec->hdr ); - return ret; -} - -UINT MSI_RecordSetStringW( MSIRECORD *rec, unsigned int iField, LPCWSTR szValue ) -{ - LPWSTR str; - - TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue)); - - if( iField > rec->count ) - return ERROR_INVALID_FIELD; - - MSI_FreeField( &rec->fields[iField] ); - - if( szValue && szValue[0] ) - { - str = strdupW( szValue ); - rec->fields[iField].type = MSIFIELD_WSTR; - rec->fields[iField].u.szwVal = str; - } - else - { - rec->fields[iField].type = MSIFIELD_NULL; - rec->fields[iField].u.szwVal = NULL; - } - - return 0; -} - -UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, unsigned int iField, LPCWSTR szValue ) -{ - MSIRECORD *rec; - UINT ret; - - TRACE("%ld %d %s\n", handle, iField, debugstr_w(szValue)); - - rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); - if( !rec ) - return ERROR_INVALID_HANDLE; - - msiobj_lock( &rec->hdr ); - ret = MSI_RecordSetStringW( rec, iField, szValue ); - msiobj_unlock( &rec->hdr ); - msiobj_release( &rec->hdr ); - return ret; -} - -/* read the data in a file into an IStream */ -UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm) -{ - DWORD sz, szHighWord = 0, read; - HANDLE handle; - HGLOBAL hGlob = 0; - HRESULT hr; - ULARGE_INTEGER ulSize; - - TRACE("reading %s\n", debugstr_w(szFile)); - - /* read the file into memory */ - handle = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - if( handle == INVALID_HANDLE_VALUE ) - return GetLastError(); - sz = GetFileSize(handle, &szHighWord); - if( sz != INVALID_FILE_SIZE && szHighWord == 0 ) - { - hGlob = GlobalAlloc(GMEM_FIXED, sz); - if( hGlob ) - { - BOOL r = ReadFile(handle, hGlob, sz, &read, NULL); - if( !r ) - { - GlobalFree(hGlob); - hGlob = 0; - } - } - } - CloseHandle(handle); - if( !hGlob ) - return ERROR_FUNCTION_FAILED; - - /* make a stream out of it, and set the correct file size */ - hr = CreateStreamOnHGlobal(hGlob, TRUE, pstm); - if( FAILED( hr ) ) - { - GlobalFree(hGlob); - return ERROR_FUNCTION_FAILED; - } - - /* set the correct size - CreateStreamOnHGlobal screws it up */ - ulSize.QuadPart = sz; - IStream_SetSize(*pstm, ulSize); - - TRACE("read %s, %ld bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm); - - return ERROR_SUCCESS; -} - -UINT MSI_RecordSetStreamW(MSIRECORD *rec, unsigned int iField, LPCWSTR szFilename) -{ - IStream *stm = NULL; - HRESULT r; - - if( (iField == 0) || (iField > rec->count) ) - return ERROR_INVALID_PARAMETER; - - /* no filename means we should seek back to the start of the stream */ - if( !szFilename ) - { - LARGE_INTEGER ofs; - ULARGE_INTEGER cur; - - if( rec->fields[iField].type != MSIFIELD_STREAM ) - return ERROR_INVALID_FIELD; - - stm = rec->fields[iField].u.stream; - if( !stm ) - return ERROR_INVALID_FIELD; - - ofs.QuadPart = 0; - r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur ); - if( FAILED( r ) ) - return ERROR_FUNCTION_FAILED; - } - else - { - /* read the file into a stream and save the stream in the record */ - r = RECORD_StreamFromFile(szFilename, &stm); - if( r != ERROR_SUCCESS ) - return r; - - /* if all's good, store it in the record */ - MSI_FreeField( &rec->fields[iField] ); - rec->fields[iField].type = MSIFIELD_STREAM; - rec->fields[iField].u.stream = stm; - } - - return ERROR_SUCCESS; -} - -UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, unsigned int iField, LPCSTR szFilename) -{ - LPWSTR wstr = NULL; - UINT ret; - - TRACE("%ld %d %s\n", hRecord, iField, debugstr_a(szFilename)); - - if( szFilename ) - { - wstr = strdupAtoW( szFilename ); - if( !wstr ) - return ERROR_OUTOFMEMORY; - } - ret = MsiRecordSetStreamW(hRecord, iField, wstr); - HeapFree(GetProcessHeap(),0,wstr); - - return ret; -} - -UINT WINAPI MsiRecordSetStreamW(MSIHANDLE handle, unsigned int iField, LPCWSTR szFilename) -{ - MSIRECORD *rec; - UINT ret; - - TRACE("%ld %d %s\n", handle, iField, debugstr_w(szFilename)); - - rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); - if( !rec ) - return ERROR_INVALID_HANDLE; - - msiobj_lock( &rec->hdr ); - ret = MSI_RecordSetStreamW( rec, iField, szFilename ); - msiobj_unlock( &rec->hdr ); - msiobj_release( &rec->hdr ); - return ret; -} - -UINT MSI_RecordReadStream(MSIRECORD *rec, unsigned int iField, char *buf, DWORD *sz) -{ - ULONG count; - HRESULT r; - IStream *stm; - - TRACE("%p %d %p %p\n", rec, iField, buf, sz); - - if( !sz ) - return ERROR_INVALID_PARAMETER; - - if( iField > rec->count) - return ERROR_INVALID_PARAMETER; - - if( rec->fields[iField].type != MSIFIELD_STREAM ) - return ERROR_INVALID_DATATYPE; - - stm = rec->fields[iField].u.stream; - if( !stm ) - return ERROR_INVALID_PARAMETER; - - /* if there's no buffer pointer, calculate the length to the end */ - if( !buf ) - { - LARGE_INTEGER ofs; - ULARGE_INTEGER end, cur; - - ofs.QuadPart = cur.QuadPart = 0; - end.QuadPart = 0; - r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur ); - IStream_Seek( stm, ofs, STREAM_SEEK_END, &end ); - ofs.QuadPart = cur.QuadPart; - IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur ); - *sz = end.QuadPart - cur.QuadPart; - - return ERROR_SUCCESS; - } - - /* read the data */ - count = 0; - r = IStream_Read( stm, buf, *sz, &count ); - if( FAILED( r ) ) - { - *sz = 0; - return ERROR_FUNCTION_FAILED; - } - - *sz = count; - - return ERROR_SUCCESS; -} - -UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, unsigned int iField, char *buf, DWORD *sz) -{ - MSIRECORD *rec; - UINT ret; - - TRACE("%ld %d %p %p\n", handle, iField, buf, sz); - - rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); - if( !rec ) - return ERROR_INVALID_HANDLE; - msiobj_lock( &rec->hdr ); - ret = MSI_RecordReadStream( rec, iField, buf, sz ); - msiobj_unlock( &rec->hdr ); - msiobj_release( &rec->hdr ); - return ret; -} - -UINT MSI_RecordSetIStream( MSIRECORD *rec, unsigned int iField, IStream *stm ) -{ - TRACE("%p %d %p\n", rec, iField, stm); - - if( iField > rec->count ) - return ERROR_INVALID_FIELD; - - MSI_FreeField( &rec->fields[iField] ); - - rec->fields[iField].type = MSIFIELD_STREAM; - rec->fields[iField].u.stream = stm; - IStream_AddRef( stm ); - - return ERROR_SUCCESS; -} - -UINT MSI_RecordGetIStream( MSIRECORD *rec, unsigned int iField, IStream **pstm) -{ - TRACE("%p %d %p\n", rec, iField, pstm); - - if( iField > rec->count ) - return ERROR_INVALID_FIELD; - - if( rec->fields[iField].type != MSIFIELD_STREAM ) - return ERROR_INVALID_FIELD; - - *pstm = rec->fields[iField].u.stream; - IStream_AddRef( *pstm ); - - return ERROR_SUCCESS; -} +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2002-2004 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winerror.h" +#include "wine/debug.h" +#include "msi.h" +#include "msiquery.h" +#include "msipriv.h" +#include "objidl.h" +#include "winnls.h" +#include "ole2.h" + +#include "query.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +#define MSIFIELD_NULL 0 +#define MSIFIELD_INT 1 +#define MSIFIELD_STR 2 +#define MSIFIELD_WSTR 3 +#define MSIFIELD_STREAM 4 + +void MSI_FreeField( MSIFIELD *field ) +{ + switch( field->type ) + { + case MSIFIELD_NULL: + case MSIFIELD_INT: + break; + case MSIFIELD_WSTR: + HeapFree( GetProcessHeap(), 0, field->u.szwVal); + break; + case MSIFIELD_STREAM: + IStream_Release( field->u.stream ); + break; + default: + ERR("Invalid field type %d\n", field->type); + } +} + +void MSI_CloseRecord( MSIOBJECTHDR *arg ) +{ + MSIRECORD *rec = (MSIRECORD *) arg; + UINT i; + + for( i=0; i<=rec->count; i++ ) + MSI_FreeField( &rec->fields[i] ); +} + +MSIRECORD *MSI_CreateRecord( unsigned int cParams ) +{ + MSIRECORD *rec; + UINT len; + + TRACE("%d\n", cParams); + + if( cParams>65535 ) + return NULL; + + len = sizeof (MSIRECORD) + sizeof (MSIFIELD)*cParams; + rec = alloc_msiobject( MSIHANDLETYPE_RECORD, len, MSI_CloseRecord ); + if( rec ) + rec->count = cParams; + return rec; +} + +MSIHANDLE WINAPI MsiCreateRecord( unsigned int cParams ) +{ + MSIRECORD *rec; + MSIHANDLE ret = 0; + + TRACE("%d\n", cParams); + + rec = MSI_CreateRecord( cParams ); + if( rec ) + ret = alloc_msihandle( &rec->hdr ); + msiobj_release( &rec->hdr ); + return ret; +} + +unsigned int MSI_RecordGetFieldCount( MSIRECORD *rec ) +{ + return rec->count; +} + +unsigned int WINAPI MsiRecordGetFieldCount( MSIHANDLE handle ) +{ + MSIRECORD *rec; + UINT ret; + + TRACE("%ld\n", handle ); + + rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); + if( !rec ) + return -1; + + msiobj_lock( &rec->hdr ); + ret = MSI_RecordGetFieldCount( rec ); + msiobj_unlock( &rec->hdr ); + msiobj_release( &rec->hdr ); + + return ret; +} + +static BOOL string2intW( LPCWSTR str, int *out ) +{ + int x = 0; + LPCWSTR p = str; + + if( *p == '-' ) /* skip the minus sign */ + p++; + while ( *p ) + { + if( (*p < '0') || (*p > '9') ) + return FALSE; + x *= 10; + x += (*p - '0'); + p++; + } + + if( str[0] == '-' ) /* check if it's negative */ + x = -x; + *out = x; + + return TRUE; +} + +int MSI_RecordGetInteger( MSIRECORD *rec, unsigned int iField) +{ + int ret = 0; + + TRACE("%p %d\n", rec, iField ); + + if( iField > rec->count ) + return MSI_NULL_INTEGER; + + switch( rec->fields[iField].type ) + { + case MSIFIELD_INT: + return rec->fields[iField].u.iVal; + case MSIFIELD_WSTR: + if( string2intW( rec->fields[iField].u.szwVal, &ret ) ) + return ret; + return MSI_NULL_INTEGER; + default: + break; + } + + return MSI_NULL_INTEGER; +} + +int WINAPI MsiRecordGetInteger( MSIHANDLE handle, unsigned int iField) +{ + MSIRECORD *rec; + UINT ret; + + TRACE("%ld %d\n", handle, iField ); + + rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); + if( !rec ) + return MSI_NULL_INTEGER; + + msiobj_lock( &rec->hdr ); + ret = MSI_RecordGetInteger( rec, iField ); + msiobj_unlock( &rec->hdr ); + msiobj_release( &rec->hdr ); + + return ret; +} + +UINT WINAPI MsiRecordClearData( MSIHANDLE handle ) +{ + MSIRECORD *rec; + UINT i; + + TRACE("%ld\n", handle ); + + rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); + if( !rec ) + return ERROR_INVALID_HANDLE; + + msiobj_lock( &rec->hdr ); + for( i=0; i<=rec->count; i++) + { + MSI_FreeField( &rec->fields[i] ); + rec->fields[i].type = MSIFIELD_NULL; + rec->fields[i].u.iVal = 0; + } + msiobj_unlock( &rec->hdr ); + msiobj_release( &rec->hdr ); + + return ERROR_SUCCESS; +} + +UINT MSI_RecordSetInteger( MSIRECORD *rec, unsigned int iField, int iVal ) +{ + TRACE("%p %u %d\n", rec, iField, iVal); + + if( iField > rec->count ) + return ERROR_INVALID_PARAMETER; + + MSI_FreeField( &rec->fields[iField] ); + rec->fields[iField].type = MSIFIELD_INT; + rec->fields[iField].u.iVal = iVal; + + return ERROR_SUCCESS; +} + +UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, unsigned int iField, int iVal ) +{ + MSIRECORD *rec; + UINT ret; + + TRACE("%ld %u %d\n", handle, iField, iVal); + + rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); + if( !rec ) + return ERROR_INVALID_HANDLE; + + msiobj_lock( &rec->hdr ); + ret = MSI_RecordSetInteger( rec, iField, iVal ); + msiobj_unlock( &rec->hdr ); + msiobj_release( &rec->hdr ); + return ret; +} + +BOOL MSI_RecordIsNull( MSIRECORD *rec, unsigned int iField ) +{ + BOOL r = TRUE; + + TRACE("%p %d\n", rec, iField ); + + r = ( iField > rec->count ) || + ( rec->fields[iField].type == MSIFIELD_NULL ); + + return r; +} + +BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, unsigned int iField ) +{ + MSIRECORD *rec; + UINT ret; + + TRACE("%ld %d\n", handle, iField ); + + rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); + if( !rec ) + return 0; + msiobj_lock( &rec->hdr ); + ret = MSI_RecordIsNull( rec, iField ); + msiobj_unlock( &rec->hdr ); + msiobj_release( &rec->hdr ); + return ret; + +} + +UINT MSI_RecordGetStringA(MSIRECORD *rec, unsigned int iField, + LPSTR szValue, DWORD *pcchValue) +{ + UINT len=0, ret; + CHAR buffer[16]; + + TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue); + + if( iField > rec->count ) + return ERROR_INVALID_PARAMETER; + + ret = ERROR_SUCCESS; + switch( rec->fields[iField].type ) + { + case MSIFIELD_INT: + wsprintfA(buffer, "%d", rec->fields[iField].u.iVal); + len = lstrlenA( buffer ); + lstrcpynA(szValue, buffer, *pcchValue); + break; + case MSIFIELD_WSTR: + len = WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1, + NULL, 0 , NULL, NULL); + WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1, + szValue, *pcchValue, NULL, NULL); + if( *pcchValue && len>*pcchValue ) + szValue[*pcchValue-1] = 0; + if( len ) + len--; + break; + case MSIFIELD_NULL: + if( *pcchValue > 0 ) + szValue[0] = 0; + break; + default: + ret = ERROR_INVALID_PARAMETER; + break; + } + + if( *pcchValue < len ) + ret = ERROR_MORE_DATA; + *pcchValue = len; + + return ret; +} + +UINT WINAPI MsiRecordGetStringA(MSIHANDLE handle, unsigned int iField, + LPSTR szValue, DWORD *pcchValue) +{ + MSIRECORD *rec; + UINT ret; + + TRACE("%ld %d %p %p\n", handle, iField, szValue, pcchValue); + + rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); + if( !rec ) + return ERROR_INVALID_HANDLE; + msiobj_lock( &rec->hdr ); + ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue); + msiobj_unlock( &rec->hdr ); + msiobj_release( &rec->hdr ); + return ret; +} + +const WCHAR *MSI_RecordGetString( MSIRECORD *rec, unsigned int iField ) +{ + if( iField > rec->count ) + return NULL; + + if( rec->fields[iField].type != MSIFIELD_WSTR ) + return NULL; + + return rec->fields[iField].u.szwVal; +} + +UINT MSI_RecordGetStringW(MSIRECORD *rec, unsigned int iField, + LPWSTR szValue, DWORD *pcchValue) +{ + UINT len=0, ret; + WCHAR buffer[16]; + static const WCHAR szFormat[] = { '%','d',0 }; + + TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue); + + if( iField > rec->count ) + return ERROR_INVALID_PARAMETER; + + ret = ERROR_SUCCESS; + switch( rec->fields[iField].type ) + { + case MSIFIELD_INT: + wsprintfW(buffer, szFormat, rec->fields[iField].u.iVal); + len = lstrlenW( buffer ); + lstrcpynW(szValue, buffer, *pcchValue); + break; + case MSIFIELD_WSTR: + len = lstrlenW( rec->fields[iField].u.szwVal ); + lstrcpynW(szValue, rec->fields[iField].u.szwVal, *pcchValue); + break; + case MSIFIELD_NULL: + len = 1; + if( *pcchValue > 0 ) + szValue[0] = 0; + default: + break; + } + + if( *pcchValue < len ) + ret = ERROR_MORE_DATA; + *pcchValue = len; + + return ret; +} + +UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, unsigned int iField, + LPWSTR szValue, DWORD *pcchValue) +{ + MSIRECORD *rec; + UINT ret; + + TRACE("%ld %d %p %p\n", handle, iField, szValue, pcchValue); + + rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); + if( !rec ) + return ERROR_INVALID_HANDLE; + + msiobj_lock( &rec->hdr ); + ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue ); + msiobj_unlock( &rec->hdr ); + msiobj_release( &rec->hdr ); + return ret; +} + +UINT MSI_RecordDataSize(MSIRECORD *rec, unsigned int iField) +{ + TRACE("%p %d\n", rec, iField); + + if( iField > rec->count ) + return 0; + + switch( rec->fields[iField].type ) + { + case MSIFIELD_INT: + return sizeof (INT); + case MSIFIELD_WSTR: + return lstrlenW( rec->fields[iField].u.szwVal ); + case MSIFIELD_NULL: + break; + } + return 0; +} + +UINT WINAPI MsiRecordDataSize(MSIHANDLE handle, unsigned int iField) +{ + MSIRECORD *rec; + UINT ret; + + TRACE("%ld %d\n", handle, iField); + + rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); + if( !rec ) + return 0; + msiobj_lock( &rec->hdr ); + ret = MSI_RecordDataSize( rec, iField); + msiobj_unlock( &rec->hdr ); + msiobj_release( &rec->hdr ); + return ret; +} + +UINT MSI_RecordSetStringA( MSIRECORD *rec, unsigned int iField, LPCSTR szValue ) +{ + LPWSTR str; + + TRACE("%p %d %s\n", rec, iField, debugstr_a(szValue)); + + if( iField > rec->count ) + return ERROR_INVALID_FIELD; + + MSI_FreeField( &rec->fields[iField] ); + if( szValue && szValue[0] ) + { + str = strdupAtoW( szValue ); + rec->fields[iField].type = MSIFIELD_WSTR; + rec->fields[iField].u.szwVal = str; + } + else + { + rec->fields[iField].type = MSIFIELD_NULL; + rec->fields[iField].u.szwVal = NULL; + } + + return 0; +} + +UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, unsigned int iField, LPCSTR szValue ) +{ + MSIRECORD *rec; + UINT ret; + + TRACE("%ld %d %s\n", handle, iField, debugstr_a(szValue)); + + rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); + if( !rec ) + return ERROR_INVALID_HANDLE; + msiobj_lock( &rec->hdr ); + ret = MSI_RecordSetStringA( rec, iField, szValue ); + msiobj_unlock( &rec->hdr ); + msiobj_release( &rec->hdr ); + return ret; +} + +UINT MSI_RecordSetStringW( MSIRECORD *rec, unsigned int iField, LPCWSTR szValue ) +{ + LPWSTR str; + + TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue)); + + if( iField > rec->count ) + return ERROR_INVALID_FIELD; + + MSI_FreeField( &rec->fields[iField] ); + + if( szValue && szValue[0] ) + { + str = strdupW( szValue ); + rec->fields[iField].type = MSIFIELD_WSTR; + rec->fields[iField].u.szwVal = str; + } + else + { + rec->fields[iField].type = MSIFIELD_NULL; + rec->fields[iField].u.szwVal = NULL; + } + + return 0; +} + +UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, unsigned int iField, LPCWSTR szValue ) +{ + MSIRECORD *rec; + UINT ret; + + TRACE("%ld %d %s\n", handle, iField, debugstr_w(szValue)); + + rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); + if( !rec ) + return ERROR_INVALID_HANDLE; + + msiobj_lock( &rec->hdr ); + ret = MSI_RecordSetStringW( rec, iField, szValue ); + msiobj_unlock( &rec->hdr ); + msiobj_release( &rec->hdr ); + return ret; +} + +/* read the data in a file into an IStream */ +UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm) +{ + DWORD sz, szHighWord = 0, read; + HANDLE handle; + HGLOBAL hGlob = 0; + HRESULT hr; + ULARGE_INTEGER ulSize; + + TRACE("reading %s\n", debugstr_w(szFile)); + + /* read the file into memory */ + handle = CreateFileW(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if( handle == INVALID_HANDLE_VALUE ) + return GetLastError(); + sz = GetFileSize(handle, &szHighWord); + if( sz != INVALID_FILE_SIZE && szHighWord == 0 ) + { + hGlob = GlobalAlloc(GMEM_FIXED, sz); + if( hGlob ) + { + BOOL r = ReadFile(handle, hGlob, sz, &read, NULL); + if( !r ) + { + GlobalFree(hGlob); + hGlob = 0; + } + } + } + CloseHandle(handle); + if( !hGlob ) + return ERROR_FUNCTION_FAILED; + + /* make a stream out of it, and set the correct file size */ + hr = CreateStreamOnHGlobal(hGlob, TRUE, pstm); + if( FAILED( hr ) ) + { + GlobalFree(hGlob); + return ERROR_FUNCTION_FAILED; + } + + /* set the correct size - CreateStreamOnHGlobal screws it up */ + ulSize.QuadPart = sz; + IStream_SetSize(*pstm, ulSize); + + TRACE("read %s, %ld bytes into IStream %p\n", debugstr_w(szFile), sz, *pstm); + + return ERROR_SUCCESS; +} + +UINT MSI_RecordSetStreamW(MSIRECORD *rec, unsigned int iField, LPCWSTR szFilename) +{ + IStream *stm = NULL; + HRESULT r; + + if( (iField == 0) || (iField > rec->count) ) + return ERROR_INVALID_PARAMETER; + + /* no filename means we should seek back to the start of the stream */ + if( !szFilename ) + { + LARGE_INTEGER ofs; + ULARGE_INTEGER cur; + + if( rec->fields[iField].type != MSIFIELD_STREAM ) + return ERROR_INVALID_FIELD; + + stm = rec->fields[iField].u.stream; + if( !stm ) + return ERROR_INVALID_FIELD; + + ofs.QuadPart = 0; + r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur ); + if( FAILED( r ) ) + return ERROR_FUNCTION_FAILED; + } + else + { + /* read the file into a stream and save the stream in the record */ + r = RECORD_StreamFromFile(szFilename, &stm); + if( r != ERROR_SUCCESS ) + return r; + + /* if all's good, store it in the record */ + MSI_FreeField( &rec->fields[iField] ); + rec->fields[iField].type = MSIFIELD_STREAM; + rec->fields[iField].u.stream = stm; + } + + return ERROR_SUCCESS; +} + +UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, unsigned int iField, LPCSTR szFilename) +{ + LPWSTR wstr = NULL; + UINT ret; + + TRACE("%ld %d %s\n", hRecord, iField, debugstr_a(szFilename)); + + if( szFilename ) + { + wstr = strdupAtoW( szFilename ); + if( !wstr ) + return ERROR_OUTOFMEMORY; + } + ret = MsiRecordSetStreamW(hRecord, iField, wstr); + HeapFree(GetProcessHeap(),0,wstr); + + return ret; +} + +UINT WINAPI MsiRecordSetStreamW(MSIHANDLE handle, unsigned int iField, LPCWSTR szFilename) +{ + MSIRECORD *rec; + UINT ret; + + TRACE("%ld %d %s\n", handle, iField, debugstr_w(szFilename)); + + rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); + if( !rec ) + return ERROR_INVALID_HANDLE; + + msiobj_lock( &rec->hdr ); + ret = MSI_RecordSetStreamW( rec, iField, szFilename ); + msiobj_unlock( &rec->hdr ); + msiobj_release( &rec->hdr ); + return ret; +} + +UINT MSI_RecordReadStream(MSIRECORD *rec, unsigned int iField, char *buf, DWORD *sz) +{ + ULONG count; + HRESULT r; + IStream *stm; + + TRACE("%p %d %p %p\n", rec, iField, buf, sz); + + if( !sz ) + return ERROR_INVALID_PARAMETER; + + if( iField > rec->count) + return ERROR_INVALID_PARAMETER; + + if( rec->fields[iField].type != MSIFIELD_STREAM ) + return ERROR_INVALID_DATATYPE; + + stm = rec->fields[iField].u.stream; + if( !stm ) + return ERROR_INVALID_PARAMETER; + + /* if there's no buffer pointer, calculate the length to the end */ + if( !buf ) + { + LARGE_INTEGER ofs; + ULARGE_INTEGER end, cur; + + ofs.QuadPart = cur.QuadPart = 0; + end.QuadPart = 0; + r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur ); + IStream_Seek( stm, ofs, STREAM_SEEK_END, &end ); + ofs.QuadPart = cur.QuadPart; + IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur ); + *sz = end.QuadPart - cur.QuadPart; + + return ERROR_SUCCESS; + } + + /* read the data */ + count = 0; + r = IStream_Read( stm, buf, *sz, &count ); + if( FAILED( r ) ) + { + *sz = 0; + return ERROR_FUNCTION_FAILED; + } + + *sz = count; + + return ERROR_SUCCESS; +} + +UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, unsigned int iField, char *buf, DWORD *sz) +{ + MSIRECORD *rec; + UINT ret; + + TRACE("%ld %d %p %p\n", handle, iField, buf, sz); + + rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD ); + if( !rec ) + return ERROR_INVALID_HANDLE; + msiobj_lock( &rec->hdr ); + ret = MSI_RecordReadStream( rec, iField, buf, sz ); + msiobj_unlock( &rec->hdr ); + msiobj_release( &rec->hdr ); + return ret; +} + +UINT MSI_RecordSetIStream( MSIRECORD *rec, unsigned int iField, IStream *stm ) +{ + TRACE("%p %d %p\n", rec, iField, stm); + + if( iField > rec->count ) + return ERROR_INVALID_FIELD; + + MSI_FreeField( &rec->fields[iField] ); + + rec->fields[iField].type = MSIFIELD_STREAM; + rec->fields[iField].u.stream = stm; + IStream_AddRef( stm ); + + return ERROR_SUCCESS; +} + +UINT MSI_RecordGetIStream( MSIRECORD *rec, unsigned int iField, IStream **pstm) +{ + TRACE("%p %d %p\n", rec, iField, pstm); + + if( iField > rec->count ) + return ERROR_INVALID_FIELD; + + if( rec->fields[iField].type != MSIFIELD_STREAM ) + return ERROR_INVALID_FIELD; + + *pstm = rec->fields[iField].u.stream; + IStream_AddRef( *pstm ); + + return ERROR_SUCCESS; +} diff --git a/reactos/lib/msi/regsvr.c b/reactos/lib/msi/regsvr.c index 64df6dd6552..fa3cf503a1c 100644 --- a/reactos/lib/msi/regsvr.c +++ b/reactos/lib/msi/regsvr.c @@ -1,624 +1,624 @@ -/* - * self-registerable dll functions for msi.dll - * - * Copyright (C) 2004 Raphael Junqueira - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <stdarg.h> -#include <string.h> - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "winreg.h" -#include "winerror.h" - -#include "ole2.h" -#include "olectl.h" - -#include "wine/debug.h" - -#include "msi.h" -#include "initguid.h" -#include "msipriv.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -/* - * Near the bottom of this file are the exported DllRegisterServer and - * DllUnregisterServer, which make all this worthwhile. - */ - -/*********************************************************************** - * interface for self-registering - */ -struct regsvr_interface { - IID const *iid; /* NULL for end of list */ - LPCSTR name; /* can be NULL to omit */ - IID const *base_iid; /* can be NULL to omit */ - int num_methods; /* can be <0 to omit */ - CLSID const *ps_clsid; /* can be NULL to omit */ - CLSID const *ps_clsid32; /* can be NULL to omit */ -}; - -static HRESULT register_interfaces(struct regsvr_interface const *list); -static HRESULT unregister_interfaces(struct regsvr_interface const *list); - -/** - * @todo: maybe adding typelibs support here - * [Software\\Classes\\CLSID\\{000C1090-0000-0000-C000-000000000046}\\TypeLib] 1080380217 - * @="{000C1092-0000-0000-C000-000000000046}" - */ -struct regsvr_coclass { - CLSID const *clsid; /* NULL for end of list */ - LPCSTR name; /* can be NULL to omit */ - LPCSTR iph32; /* can be NULL to omit */ - LPCSTR ips; /* can be NULL to omit */ - LPCSTR ips32; /* can be NULL to omit */ - LPCSTR ips32_tmodel; /* can be NULL to omit, if apartment, iph32 must be set */ - LPCSTR progid; /* can be NULL to omit */ - LPCSTR viprogid; /* can be NULL to omit */ - LPCSTR progid_extra; /* can be NULL to omit */ -}; - -static HRESULT register_coclasses(struct regsvr_coclass const *list); -static HRESULT unregister_coclasses(struct regsvr_coclass const *list); - -/*********************************************************************** - * static string constants - */ -static WCHAR const interface_keyname[10] = { - 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 }; -static WCHAR const base_ifa_keyname[14] = { - 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', - 'e', 0 }; -static WCHAR const num_methods_keyname[11] = { - 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 }; -static WCHAR const ps_clsid_keyname[15] = { - 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', - 'i', 'd', 0 }; -static WCHAR const ps_clsid32_keyname[17] = { - 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', - 'i', 'd', '3', '2', 0 }; -static WCHAR const clsid_keyname[6] = { - 'C', 'L', 'S', 'I', 'D', 0 }; -static WCHAR const curver_keyname[7] = { - 'C', 'u', 'r', 'V', 'e', 'r', 0 }; -static WCHAR const iph32_keyname[] = { - 'I', 'n', 'P', 'r', 'o', 'c', 'H', 'a', 'n', 'd', 'l', 'e', 'r', - '3', '2', 0 }; -static WCHAR const ips_keyname[13] = { - 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', - 0 }; -static WCHAR const ips32_keyname[15] = { - 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', - '3', '2', 0 }; -static WCHAR const progid_keyname[7] = { - 'P', 'r', 'o', 'g', 'I', 'D', 0 }; -static WCHAR const viprogid_keyname[25] = { - 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p', - 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D', - 0 }; -static char const tmodel_valuename[] = "ThreadingModel"; - -/*********************************************************************** - * static helper functions - */ -static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid); -static LONG register_key_defvalueW(HKEY base, WCHAR const *name, - WCHAR const *value); -static LONG register_key_defvalueA(HKEY base, WCHAR const *name, - char const *value); -static LONG register_progid(WCHAR const *clsid, - char const *progid, char const *curver_progid, - char const *name, char const *extra); -static LONG recursive_delete_key(HKEY key); -static LONG recursive_delete_keyA(HKEY base, char const *name); -static LONG recursive_delete_keyW(HKEY base, WCHAR const *name); - -/*********************************************************************** - * register_interfaces - */ -static HRESULT register_interfaces(struct regsvr_interface const *list) { - LONG res = ERROR_SUCCESS; - HKEY interface_key; - - res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &interface_key, NULL); - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->iid; ++list) { - WCHAR buf[39]; - HKEY iid_key; - - StringFromGUID2(list->iid, buf, 39); - res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &iid_key, NULL); - if (res != ERROR_SUCCESS) goto error_close_interface_key; - - if (list->name) { - res = RegSetValueExA(iid_key, NULL, 0, REG_SZ, - (CONST BYTE*)(list->name), - strlen(list->name) + 1); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (list->base_iid) { - register_key_guid(iid_key, base_ifa_keyname, list->base_iid); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (0 <= list->num_methods) { - static WCHAR const fmt[3] = { '%', 'd', 0 }; - HKEY key; - - res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &key, NULL); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - - wsprintfW(buf, fmt, list->num_methods); - res = RegSetValueExW(key, NULL, 0, REG_SZ, - (CONST BYTE*)buf, - (lstrlenW(buf) + 1) * sizeof(WCHAR)); - RegCloseKey(key); - - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (list->ps_clsid) { - register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (list->ps_clsid32) { - register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - error_close_iid_key: - RegCloseKey(iid_key); - } - -error_close_interface_key: - RegCloseKey(interface_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * unregister_interfaces - */ -static HRESULT unregister_interfaces(struct regsvr_interface const *list) { - LONG res = ERROR_SUCCESS; - HKEY interface_key; - - res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, - KEY_READ | KEY_WRITE, &interface_key); - if (res == ERROR_FILE_NOT_FOUND) return S_OK; - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->iid; ++list) { - WCHAR buf[39]; - - StringFromGUID2(list->iid, buf, 39); - res = recursive_delete_keyW(interface_key, buf); - } - - RegCloseKey(interface_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * register_coclasses - */ -static HRESULT register_coclasses(struct regsvr_coclass const *list) { - LONG res = ERROR_SUCCESS; - HKEY coclass_key; - - res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL); - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->clsid; ++list) { - WCHAR buf[39]; - HKEY clsid_key; - - StringFromGUID2(list->clsid, buf, 39); - res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL); - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - - if (list->name) { - res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ, - (CONST BYTE*)(list->name), - strlen(list->name) + 1); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->iph32) { - HKEY iph32_key; - - res = RegCreateKeyExW(clsid_key, iph32_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, - &iph32_key, NULL); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - - res = RegSetValueExA(iph32_key, NULL, 0, REG_SZ, - (CONST BYTE*)list->iph32, - lstrlenA(list->iph32) + 1); - RegCloseKey(iph32_key); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->ips) { - res = register_key_defvalueA(clsid_key, ips_keyname, list->ips); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->ips32) { - HKEY ips32_key; - - res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, - &ips32_key, NULL); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - - res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ, - (CONST BYTE*)list->ips32, - lstrlenA(list->ips32) + 1); - if (res == ERROR_SUCCESS && list->ips32_tmodel) - res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ, - (CONST BYTE*)list->ips32_tmodel, - strlen(list->ips32_tmodel) + 1); - RegCloseKey(ips32_key); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->progid) { - res = register_key_defvalueA(clsid_key, progid_keyname, - list->progid); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - - res = register_progid(buf, list->progid, NULL, - list->name, list->progid_extra); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->viprogid) { - res = register_key_defvalueA(clsid_key, viprogid_keyname, - list->viprogid); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - - res = register_progid(buf, list->viprogid, list->progid, - list->name, list->progid_extra); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - error_close_clsid_key: - RegCloseKey(clsid_key); - } - -error_close_coclass_key: - RegCloseKey(coclass_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * unregister_coclasses - */ -static HRESULT unregister_coclasses(struct regsvr_coclass const *list) { - LONG res = ERROR_SUCCESS; - HKEY coclass_key; - - res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, - KEY_READ | KEY_WRITE, &coclass_key); - if (res == ERROR_FILE_NOT_FOUND) return S_OK; - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->clsid; ++list) { - WCHAR buf[39]; - - StringFromGUID2(list->clsid, buf, 39); - res = recursive_delete_keyW(coclass_key, buf); - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - - if (list->progid) { - res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid); - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - } - - if (list->viprogid) { - res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid); - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - } - } - -error_close_coclass_key: - RegCloseKey(coclass_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * regsvr_key_guid - */ -static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) { - WCHAR buf[39]; - - StringFromGUID2(guid, buf, 39); - return register_key_defvalueW(base, name, buf); -} - -/*********************************************************************** - * regsvr_key_defvalueW - */ -static LONG register_key_defvalueW( - HKEY base, - WCHAR const *name, - WCHAR const *value) { - LONG res; - HKEY key; - - res = RegCreateKeyExW(base, name, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &key, NULL); - if (res != ERROR_SUCCESS) return res; - res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value, - (lstrlenW(value) + 1) * sizeof(WCHAR)); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * regsvr_key_defvalueA - */ -static LONG register_key_defvalueA( - HKEY base, - WCHAR const *name, - char const *value) { - LONG res; - HKEY key; - - res = RegCreateKeyExW(base, name, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &key, NULL); - if (res != ERROR_SUCCESS) return res; - res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value, - lstrlenA(value) + 1); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * regsvr_progid - */ -static LONG register_progid( - WCHAR const *clsid, - char const *progid, - char const *curver_progid, - char const *name, - char const *extra) { - LONG res; - HKEY progid_key; - - res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0, - NULL, 0, KEY_READ | KEY_WRITE, NULL, - &progid_key, NULL); - if (res != ERROR_SUCCESS) return res; - - if (name) { - res = RegSetValueExA(progid_key, NULL, 0, REG_SZ, - (CONST BYTE*)name, strlen(name) + 1); - if (res != ERROR_SUCCESS) goto error_close_progid_key; - } - - if (clsid) { - res = register_key_defvalueW(progid_key, clsid_keyname, clsid); - if (res != ERROR_SUCCESS) goto error_close_progid_key; - } - - if (curver_progid) { - res = register_key_defvalueA(progid_key, curver_keyname, - curver_progid); - if (res != ERROR_SUCCESS) goto error_close_progid_key; - } - - if (extra) { - HKEY extra_key; - - res = RegCreateKeyExA(progid_key, extra, 0, - NULL, 0, KEY_READ | KEY_WRITE, NULL, - &extra_key, NULL); - if (res == ERROR_SUCCESS) - RegCloseKey(extra_key); - } - -error_close_progid_key: - RegCloseKey(progid_key); - return res; -} - -/*********************************************************************** - * recursive_delete_key - */ -static LONG recursive_delete_key(HKEY key) { - LONG res; - WCHAR subkey_name[MAX_PATH]; - DWORD cName; - HKEY subkey; - - for (;;) { - cName = sizeof(subkey_name) / sizeof(WCHAR); - res = RegEnumKeyExW(key, 0, subkey_name, &cName, - NULL, NULL, NULL, NULL); - if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) { - res = ERROR_SUCCESS; /* presumably we're done enumerating */ - break; - } - res = RegOpenKeyExW(key, subkey_name, 0, - KEY_READ | KEY_WRITE, &subkey); - if (res == ERROR_FILE_NOT_FOUND) continue; - if (res != ERROR_SUCCESS) break; - - res = recursive_delete_key(subkey); - RegCloseKey(subkey); - if (res != ERROR_SUCCESS) break; - } - - if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0); - return res; -} - -/*********************************************************************** - * recursive_delete_keyA - */ -static LONG recursive_delete_keyA(HKEY base, char const *name) { - LONG res; - HKEY key; - - res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key); - if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; - if (res != ERROR_SUCCESS) return res; - res = recursive_delete_key(key); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * recursive_delete_keyW - */ -static LONG recursive_delete_keyW(HKEY base, WCHAR const *name) { - LONG res; - HKEY key; - - res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key); - if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; - if (res != ERROR_SUCCESS) return res; - res = recursive_delete_key(key); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * coclass list - */ -static struct regsvr_coclass const coclass_list[] = { - { - &CLSID_IMsiServer, - "Msi install server", - "ole32.dll", - NULL, - "msi.dll", - "Apartment", - "WindowsInstaller.Installer", - NULL - }, - { - &CLSID_IMsiServerMessage, - "Wine Installer Message RPC", - NULL, - NULL, - "msi.dll", - NULL, - "WindowsInstaller.Message", - NULL - }, - { - &CLSID_IMsiServerX1, - "Msi install server", - "ole32.dll", - NULL, - "msi.dll", - "Apartment", - "WindowsInstaller.Installer", - NULL - }, - { - &CLSID_IMsiServerX2, - "Msi install server", - "ole32.dll", - NULL, - "msi.dll", - "Apartment", - "WindowsInstaller.Installer", - NULL - }, - { - &CLSID_IMsiServerX3, - "Msi install server", - "ole32.dll", - NULL, - "msi.dll", - "Apartment", - "WindowsInstaller.Installer", - NULL - }, - { NULL } /* list terminator */ -}; - -/*********************************************************************** - * interface list - */ -/* - * we should declare: (@see ole32/regsvr.c for examples) - [-HKEY_CLASSES_ROOT\Interface\{000C101C-0000-0000-C000-000000000046}] - [-HKEY_CLASSES_ROOT\Interface\{000C101D-0000-0000-C000-000000000046}] - [-HKEY_CLASSES_ROOT\Interface\{000C1025-0000-0000-C000-000000000046}] - [-HKEY_CLASSES_ROOT\Interface\{000C1033-0000-0000-C000-000000000046}] - [-HKEY_CLASSES_ROOT\Interface\{000C1090-0000-0000-C000-000000000046}] - [-HKEY_CLASSES_ROOT\Interface\{000C1093-0000-0000-C000-000000000046}] - [-HKEY_CLASSES_ROOT\Interface\{000C1095-0000-0000-C000-000000000046}] - [-HKEY_CLASSES_ROOT\Interface\{000C109A-0000-0000-C000-000000000046}] - [-HKEY_CLASSES_ROOT\Interface\{000C109B-0000-0000-C000-000000000046}] - [-HKEY_CLASSES_ROOT\Interface\{000C109C-0000-0000-C000-000000000046}] - [-HKEY_CLASSES_ROOT\Interface\{000C109D-0000-0000-C000-000000000046}] - [-HKEY_CLASSES_ROOT\Interface\{000C109E-0000-0000-C000-000000000046}] - [-HKEY_CLASSES_ROOT\Interface\{000C109F-0000-0000-C000-000000000046}] -*/ -static struct regsvr_interface const interface_list[] = { - { NULL } /* list terminator */ -}; - -/*********************************************************************** - * DllRegisterServer - */ -HRESULT WINAPI MSI_DllRegisterServer(void) { - HRESULT hr; - - TRACE("\n"); - - hr = register_coclasses(coclass_list); - if (SUCCEEDED(hr)) - hr = register_interfaces(interface_list); - return hr; -} - -/*********************************************************************** - * DllUnregisterServer - */ -HRESULT WINAPI MSI_DllUnregisterServer(void) { - HRESULT hr; - - TRACE("\n"); - - hr = unregister_coclasses(coclass_list); - if (SUCCEEDED(hr)) - hr = unregister_interfaces(interface_list); - return hr; -} +/* + * self-registerable dll functions for msi.dll + * + * Copyright (C) 2004 Raphael Junqueira + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <stdarg.h> +#include <string.h> + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "winerror.h" + +#include "ole2.h" +#include "olectl.h" + +#include "wine/debug.h" + +#include "msi.h" +#include "initguid.h" +#include "msipriv.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +/* + * Near the bottom of this file are the exported DllRegisterServer and + * DllUnregisterServer, which make all this worthwhile. + */ + +/*********************************************************************** + * interface for self-registering + */ +struct regsvr_interface { + IID const *iid; /* NULL for end of list */ + LPCSTR name; /* can be NULL to omit */ + IID const *base_iid; /* can be NULL to omit */ + int num_methods; /* can be <0 to omit */ + CLSID const *ps_clsid; /* can be NULL to omit */ + CLSID const *ps_clsid32; /* can be NULL to omit */ +}; + +static HRESULT register_interfaces(struct regsvr_interface const *list); +static HRESULT unregister_interfaces(struct regsvr_interface const *list); + +/** + * @todo: maybe adding typelibs support here + * [Software\\Classes\\CLSID\\{000C1090-0000-0000-C000-000000000046}\\TypeLib] 1080380217 + * @="{000C1092-0000-0000-C000-000000000046}" + */ +struct regsvr_coclass { + CLSID const *clsid; /* NULL for end of list */ + LPCSTR name; /* can be NULL to omit */ + LPCSTR iph32; /* can be NULL to omit */ + LPCSTR ips; /* can be NULL to omit */ + LPCSTR ips32; /* can be NULL to omit */ + LPCSTR ips32_tmodel; /* can be NULL to omit, if apartment, iph32 must be set */ + LPCSTR progid; /* can be NULL to omit */ + LPCSTR viprogid; /* can be NULL to omit */ + LPCSTR progid_extra; /* can be NULL to omit */ +}; + +static HRESULT register_coclasses(struct regsvr_coclass const *list); +static HRESULT unregister_coclasses(struct regsvr_coclass const *list); + +/*********************************************************************** + * static string constants + */ +static WCHAR const interface_keyname[10] = { + 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 }; +static WCHAR const base_ifa_keyname[14] = { + 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', + 'e', 0 }; +static WCHAR const num_methods_keyname[11] = { + 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 }; +static WCHAR const ps_clsid_keyname[15] = { + 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', + 'i', 'd', 0 }; +static WCHAR const ps_clsid32_keyname[17] = { + 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', + 'i', 'd', '3', '2', 0 }; +static WCHAR const clsid_keyname[6] = { + 'C', 'L', 'S', 'I', 'D', 0 }; +static WCHAR const curver_keyname[7] = { + 'C', 'u', 'r', 'V', 'e', 'r', 0 }; +static WCHAR const iph32_keyname[] = { + 'I', 'n', 'P', 'r', 'o', 'c', 'H', 'a', 'n', 'd', 'l', 'e', 'r', + '3', '2', 0 }; +static WCHAR const ips_keyname[13] = { + 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', + 0 }; +static WCHAR const ips32_keyname[15] = { + 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', + '3', '2', 0 }; +static WCHAR const progid_keyname[7] = { + 'P', 'r', 'o', 'g', 'I', 'D', 0 }; +static WCHAR const viprogid_keyname[25] = { + 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p', + 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D', + 0 }; +static char const tmodel_valuename[] = "ThreadingModel"; + +/*********************************************************************** + * static helper functions + */ +static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid); +static LONG register_key_defvalueW(HKEY base, WCHAR const *name, + WCHAR const *value); +static LONG register_key_defvalueA(HKEY base, WCHAR const *name, + char const *value); +static LONG register_progid(WCHAR const *clsid, + char const *progid, char const *curver_progid, + char const *name, char const *extra); +static LONG recursive_delete_key(HKEY key); +static LONG recursive_delete_keyA(HKEY base, char const *name); +static LONG recursive_delete_keyW(HKEY base, WCHAR const *name); + +/*********************************************************************** + * register_interfaces + */ +static HRESULT register_interfaces(struct regsvr_interface const *list) { + LONG res = ERROR_SUCCESS; + HKEY interface_key; + + res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &interface_key, NULL); + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->iid; ++list) { + WCHAR buf[39]; + HKEY iid_key; + + StringFromGUID2(list->iid, buf, 39); + res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &iid_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_interface_key; + + if (list->name) { + res = RegSetValueExA(iid_key, NULL, 0, REG_SZ, + (CONST BYTE*)(list->name), + strlen(list->name) + 1); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->base_iid) { + register_key_guid(iid_key, base_ifa_keyname, list->base_iid); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (0 <= list->num_methods) { + static WCHAR const fmt[3] = { '%', 'd', 0 }; + HKEY key; + + res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + + wsprintfW(buf, fmt, list->num_methods); + res = RegSetValueExW(key, NULL, 0, REG_SZ, + (CONST BYTE*)buf, + (lstrlenW(buf) + 1) * sizeof(WCHAR)); + RegCloseKey(key); + + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->ps_clsid) { + register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->ps_clsid32) { + register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + error_close_iid_key: + RegCloseKey(iid_key); + } + +error_close_interface_key: + RegCloseKey(interface_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * unregister_interfaces + */ +static HRESULT unregister_interfaces(struct regsvr_interface const *list) { + LONG res = ERROR_SUCCESS; + HKEY interface_key; + + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, + KEY_READ | KEY_WRITE, &interface_key); + if (res == ERROR_FILE_NOT_FOUND) return S_OK; + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->iid; ++list) { + WCHAR buf[39]; + + StringFromGUID2(list->iid, buf, 39); + res = recursive_delete_keyW(interface_key, buf); + } + + RegCloseKey(interface_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * register_coclasses + */ +static HRESULT register_coclasses(struct regsvr_coclass const *list) { + LONG res = ERROR_SUCCESS; + HKEY coclass_key; + + res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL); + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->clsid; ++list) { + WCHAR buf[39]; + HKEY clsid_key; + + StringFromGUID2(list->clsid, buf, 39); + res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + + if (list->name) { + res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ, + (CONST BYTE*)(list->name), + strlen(list->name) + 1); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->iph32) { + HKEY iph32_key; + + res = RegCreateKeyExW(clsid_key, iph32_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, + &iph32_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = RegSetValueExA(iph32_key, NULL, 0, REG_SZ, + (CONST BYTE*)list->iph32, + lstrlenA(list->iph32) + 1); + RegCloseKey(iph32_key); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->ips) { + res = register_key_defvalueA(clsid_key, ips_keyname, list->ips); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->ips32) { + HKEY ips32_key; + + res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, + &ips32_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ, + (CONST BYTE*)list->ips32, + lstrlenA(list->ips32) + 1); + if (res == ERROR_SUCCESS && list->ips32_tmodel) + res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ, + (CONST BYTE*)list->ips32_tmodel, + strlen(list->ips32_tmodel) + 1); + RegCloseKey(ips32_key); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->progid) { + res = register_key_defvalueA(clsid_key, progid_keyname, + list->progid); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = register_progid(buf, list->progid, NULL, + list->name, list->progid_extra); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->viprogid) { + res = register_key_defvalueA(clsid_key, viprogid_keyname, + list->viprogid); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = register_progid(buf, list->viprogid, list->progid, + list->name, list->progid_extra); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + error_close_clsid_key: + RegCloseKey(clsid_key); + } + +error_close_coclass_key: + RegCloseKey(coclass_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * unregister_coclasses + */ +static HRESULT unregister_coclasses(struct regsvr_coclass const *list) { + LONG res = ERROR_SUCCESS; + HKEY coclass_key; + + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, + KEY_READ | KEY_WRITE, &coclass_key); + if (res == ERROR_FILE_NOT_FOUND) return S_OK; + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->clsid; ++list) { + WCHAR buf[39]; + + StringFromGUID2(list->clsid, buf, 39); + res = recursive_delete_keyW(coclass_key, buf); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + + if (list->progid) { + res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + } + + if (list->viprogid) { + res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + } + } + +error_close_coclass_key: + RegCloseKey(coclass_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * regsvr_key_guid + */ +static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) { + WCHAR buf[39]; + + StringFromGUID2(guid, buf, 39); + return register_key_defvalueW(base, name, buf); +} + +/*********************************************************************** + * regsvr_key_defvalueW + */ +static LONG register_key_defvalueW( + HKEY base, + WCHAR const *name, + WCHAR const *value) { + LONG res; + HKEY key; + + res = RegCreateKeyExW(base, name, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) return res; + res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value, + (lstrlenW(value) + 1) * sizeof(WCHAR)); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * regsvr_key_defvalueA + */ +static LONG register_key_defvalueA( + HKEY base, + WCHAR const *name, + char const *value) { + LONG res; + HKEY key; + + res = RegCreateKeyExW(base, name, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) return res; + res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value, + lstrlenA(value) + 1); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * regsvr_progid + */ +static LONG register_progid( + WCHAR const *clsid, + char const *progid, + char const *curver_progid, + char const *name, + char const *extra) { + LONG res; + HKEY progid_key; + + res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0, + NULL, 0, KEY_READ | KEY_WRITE, NULL, + &progid_key, NULL); + if (res != ERROR_SUCCESS) return res; + + if (name) { + res = RegSetValueExA(progid_key, NULL, 0, REG_SZ, + (CONST BYTE*)name, strlen(name) + 1); + if (res != ERROR_SUCCESS) goto error_close_progid_key; + } + + if (clsid) { + res = register_key_defvalueW(progid_key, clsid_keyname, clsid); + if (res != ERROR_SUCCESS) goto error_close_progid_key; + } + + if (curver_progid) { + res = register_key_defvalueA(progid_key, curver_keyname, + curver_progid); + if (res != ERROR_SUCCESS) goto error_close_progid_key; + } + + if (extra) { + HKEY extra_key; + + res = RegCreateKeyExA(progid_key, extra, 0, + NULL, 0, KEY_READ | KEY_WRITE, NULL, + &extra_key, NULL); + if (res == ERROR_SUCCESS) + RegCloseKey(extra_key); + } + +error_close_progid_key: + RegCloseKey(progid_key); + return res; +} + +/*********************************************************************** + * recursive_delete_key + */ +static LONG recursive_delete_key(HKEY key) { + LONG res; + WCHAR subkey_name[MAX_PATH]; + DWORD cName; + HKEY subkey; + + for (;;) { + cName = sizeof(subkey_name) / sizeof(WCHAR); + res = RegEnumKeyExW(key, 0, subkey_name, &cName, + NULL, NULL, NULL, NULL); + if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) { + res = ERROR_SUCCESS; /* presumably we're done enumerating */ + break; + } + res = RegOpenKeyExW(key, subkey_name, 0, + KEY_READ | KEY_WRITE, &subkey); + if (res == ERROR_FILE_NOT_FOUND) continue; + if (res != ERROR_SUCCESS) break; + + res = recursive_delete_key(subkey); + RegCloseKey(subkey); + if (res != ERROR_SUCCESS) break; + } + + if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0); + return res; +} + +/*********************************************************************** + * recursive_delete_keyA + */ +static LONG recursive_delete_keyA(HKEY base, char const *name) { + LONG res; + HKEY key; + + res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key); + if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; + if (res != ERROR_SUCCESS) return res; + res = recursive_delete_key(key); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * recursive_delete_keyW + */ +static LONG recursive_delete_keyW(HKEY base, WCHAR const *name) { + LONG res; + HKEY key; + + res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key); + if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; + if (res != ERROR_SUCCESS) return res; + res = recursive_delete_key(key); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * coclass list + */ +static struct regsvr_coclass const coclass_list[] = { + { + &CLSID_IMsiServer, + "Msi install server", + "ole32.dll", + NULL, + "msi.dll", + "Apartment", + "WindowsInstaller.Installer", + NULL + }, + { + &CLSID_IMsiServerMessage, + "Wine Installer Message RPC", + NULL, + NULL, + "msi.dll", + NULL, + "WindowsInstaller.Message", + NULL + }, + { + &CLSID_IMsiServerX1, + "Msi install server", + "ole32.dll", + NULL, + "msi.dll", + "Apartment", + "WindowsInstaller.Installer", + NULL + }, + { + &CLSID_IMsiServerX2, + "Msi install server", + "ole32.dll", + NULL, + "msi.dll", + "Apartment", + "WindowsInstaller.Installer", + NULL + }, + { + &CLSID_IMsiServerX3, + "Msi install server", + "ole32.dll", + NULL, + "msi.dll", + "Apartment", + "WindowsInstaller.Installer", + NULL + }, + { NULL } /* list terminator */ +}; + +/*********************************************************************** + * interface list + */ +/* + * we should declare: (@see ole32/regsvr.c for examples) + [-HKEY_CLASSES_ROOT\Interface\{000C101C-0000-0000-C000-000000000046}] + [-HKEY_CLASSES_ROOT\Interface\{000C101D-0000-0000-C000-000000000046}] + [-HKEY_CLASSES_ROOT\Interface\{000C1025-0000-0000-C000-000000000046}] + [-HKEY_CLASSES_ROOT\Interface\{000C1033-0000-0000-C000-000000000046}] + [-HKEY_CLASSES_ROOT\Interface\{000C1090-0000-0000-C000-000000000046}] + [-HKEY_CLASSES_ROOT\Interface\{000C1093-0000-0000-C000-000000000046}] + [-HKEY_CLASSES_ROOT\Interface\{000C1095-0000-0000-C000-000000000046}] + [-HKEY_CLASSES_ROOT\Interface\{000C109A-0000-0000-C000-000000000046}] + [-HKEY_CLASSES_ROOT\Interface\{000C109B-0000-0000-C000-000000000046}] + [-HKEY_CLASSES_ROOT\Interface\{000C109C-0000-0000-C000-000000000046}] + [-HKEY_CLASSES_ROOT\Interface\{000C109D-0000-0000-C000-000000000046}] + [-HKEY_CLASSES_ROOT\Interface\{000C109E-0000-0000-C000-000000000046}] + [-HKEY_CLASSES_ROOT\Interface\{000C109F-0000-0000-C000-000000000046}] +*/ +static struct regsvr_interface const interface_list[] = { + { NULL } /* list terminator */ +}; + +/*********************************************************************** + * DllRegisterServer + */ +HRESULT WINAPI MSI_DllRegisterServer(void) { + HRESULT hr; + + TRACE("\n"); + + hr = register_coclasses(coclass_list); + if (SUCCEEDED(hr)) + hr = register_interfaces(interface_list); + return hr; +} + +/*********************************************************************** + * DllUnregisterServer + */ +HRESULT WINAPI MSI_DllUnregisterServer(void) { + HRESULT hr; + + TRACE("\n"); + + hr = unregister_coclasses(coclass_list); + if (SUCCEEDED(hr)) + hr = unregister_interfaces(interface_list); + return hr; +} diff --git a/reactos/lib/msi/select.c b/reactos/lib/msi/select.c index 69ec7c6b772..6118966d072 100644 --- a/reactos/lib/msi/select.c +++ b/reactos/lib/msi/select.c @@ -1,291 +1,291 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2002-2004 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "wine/debug.h" -#include "msi.h" -#include "msiquery.h" -#include "objbase.h" -#include "objidl.h" -#include "msipriv.h" -#include "winnls.h" - -#include "query.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - - -/* below is the query interface to a table */ - -typedef struct tagMSISELECTVIEW -{ - MSIVIEW view; - MSIDATABASE *db; - MSIVIEW *table; - UINT num_cols; - UINT max_cols; - UINT cols[1]; -} MSISELECTVIEW; - -static UINT SELECT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) -{ - MSISELECTVIEW *sv = (MSISELECTVIEW*)view; - - TRACE("%p %d %d %p\n", sv, row, col, val ); - - if( !sv->table ) - return ERROR_FUNCTION_FAILED; - - if( (col==0) || (col>sv->num_cols) ) - return ERROR_FUNCTION_FAILED; - - col = sv->cols[ col - 1 ]; - - return sv->table->ops->fetch_int( sv->table, row, col, val ); -} - -static UINT SELECT_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm) -{ - MSISELECTVIEW *sv = (MSISELECTVIEW*)view; - - TRACE("%p %d %d %p\n", sv, row, col, stm ); - - if( !sv->table ) - return ERROR_FUNCTION_FAILED; - - if( (col==0) || (col>sv->num_cols) ) - return ERROR_FUNCTION_FAILED; - - col = sv->cols[ col - 1 ]; - - return sv->table->ops->fetch_stream( sv->table, row, col, stm ); -} - -static UINT SELECT_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val ) -{ - MSISELECTVIEW *sv = (MSISELECTVIEW*)view; - - TRACE("%p %d %d %04x\n", sv, row, col, val ); - - if( !sv->table ) - return ERROR_FUNCTION_FAILED; - - if( (col==0) || (col>sv->num_cols) ) - return ERROR_FUNCTION_FAILED; - - col = sv->cols[ col - 1 ]; - - return sv->table->ops->set_int( sv->table, row, col, val ); -} - -static UINT SELECT_insert_row( struct tagMSIVIEW *view, UINT *num ) -{ - MSISELECTVIEW *sv = (MSISELECTVIEW*)view; - - TRACE("%p %p\n", sv, num ); - - if( !sv->table ) - return ERROR_FUNCTION_FAILED; - - return sv->table->ops->insert_row( sv->table, num ); -} - -static UINT SELECT_execute( struct tagMSIVIEW *view, MSIRECORD *record ) -{ - MSISELECTVIEW *sv = (MSISELECTVIEW*)view; - - TRACE("%p %p\n", sv, record); - - if( !sv->table ) - return ERROR_FUNCTION_FAILED; - - return sv->table->ops->execute( sv->table, record ); -} - -static UINT SELECT_close( struct tagMSIVIEW *view ) -{ - MSISELECTVIEW *sv = (MSISELECTVIEW*)view; - - TRACE("%p\n", sv ); - - if( !sv->table ) - return ERROR_FUNCTION_FAILED; - - return sv->table->ops->close( sv->table ); -} - -static UINT SELECT_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols ) -{ - MSISELECTVIEW *sv = (MSISELECTVIEW*)view; - - TRACE("%p %p %p\n", sv, rows, cols ); - - if( !sv->table ) - return ERROR_FUNCTION_FAILED; - - if( cols ) - *cols = sv->num_cols; - - return sv->table->ops->get_dimensions( sv->table, rows, NULL ); -} - -static UINT SELECT_get_column_info( struct tagMSIVIEW *view, - UINT n, LPWSTR *name, UINT *type ) -{ - MSISELECTVIEW *sv = (MSISELECTVIEW*)view; - - TRACE("%p %d %p %p\n", sv, n, name, type ); - - if( !sv->table ) - return ERROR_FUNCTION_FAILED; - - if( (n==0) || (n>sv->num_cols) ) - return ERROR_FUNCTION_FAILED; - - n = sv->cols[ n - 1 ]; - - return sv->table->ops->get_column_info( sv->table, n, name, type ); -} - -static UINT SELECT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, - MSIRECORD *rec ) -{ - MSISELECTVIEW *sv = (MSISELECTVIEW*)view; - - TRACE("%p %d %p\n", sv, eModifyMode, rec ); - - if( !sv->table ) - return ERROR_FUNCTION_FAILED; - - return sv->table->ops->modify( sv->table, eModifyMode, rec ); -} - -static UINT SELECT_delete( struct tagMSIVIEW *view ) -{ - MSISELECTVIEW *sv = (MSISELECTVIEW*)view; - - TRACE("%p\n", sv ); - - if( sv->table ) - sv->table->ops->delete( sv->table ); - - HeapFree( GetProcessHeap(), 0, sv ); - - return ERROR_SUCCESS; -} - - -MSIVIEWOPS select_ops = -{ - SELECT_fetch_int, - SELECT_fetch_stream, - SELECT_set_int, - SELECT_insert_row, - SELECT_execute, - SELECT_close, - SELECT_get_dimensions, - SELECT_get_column_info, - SELECT_modify, - SELECT_delete -}; - -static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPWSTR name ) -{ - UINT r, n=0; - MSIVIEW *table; - - TRACE("%p adding %s\n", sv, debugstr_w( name ) ); - - if( sv->view.ops != &select_ops ) - return ERROR_FUNCTION_FAILED; - - table = sv->table; - if( !table ) - return ERROR_FUNCTION_FAILED; - if( !table->ops->get_dimensions ) - return ERROR_FUNCTION_FAILED; - if( !table->ops->get_column_info ) - return ERROR_FUNCTION_FAILED; - - if( sv->num_cols >= sv->max_cols ) - return ERROR_FUNCTION_FAILED; - - r = VIEW_find_column( table, name, &n ); - if( r != ERROR_SUCCESS ) - return r; - - sv->cols[sv->num_cols] = n; - TRACE("Translating column %s from %d -> %d\n", - debugstr_w( name ), sv->num_cols, n); - - sv->num_cols++; - - return ERROR_SUCCESS; -} - -UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, - string_list *columns ) -{ - MSISELECTVIEW *sv = NULL; - UINT count = 0, r; - - TRACE("%p\n", sv ); - - r = table->ops->get_dimensions( table, NULL, &count ); - if( r != ERROR_SUCCESS ) - { - ERR("can't get table dimensions\n"); - return r; - } - - sv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof *sv + count*sizeof (UINT) ); - if( !sv ) - return ERROR_FUNCTION_FAILED; - - /* fill the structure */ - sv->view.ops = &select_ops; - sv->db = db; - sv->table = table; - sv->num_cols = 0; - sv->max_cols = count; - - while( columns ) - { - r = SELECT_AddColumn( sv, columns->string ); - if( r ) - break; - columns = columns->next; - } - - if( r != ERROR_SUCCESS ) - { - sv->view.ops->delete( &sv->view ); - sv = NULL; - } - - *view = &sv->view; - - return r; -} +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2002-2004 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/debug.h" +#include "msi.h" +#include "msiquery.h" +#include "objbase.h" +#include "objidl.h" +#include "msipriv.h" +#include "winnls.h" + +#include "query.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + + +/* below is the query interface to a table */ + +typedef struct tagMSISELECTVIEW +{ + MSIVIEW view; + MSIDATABASE *db; + MSIVIEW *table; + UINT num_cols; + UINT max_cols; + UINT cols[1]; +} MSISELECTVIEW; + +static UINT SELECT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) +{ + MSISELECTVIEW *sv = (MSISELECTVIEW*)view; + + TRACE("%p %d %d %p\n", sv, row, col, val ); + + if( !sv->table ) + return ERROR_FUNCTION_FAILED; + + if( (col==0) || (col>sv->num_cols) ) + return ERROR_FUNCTION_FAILED; + + col = sv->cols[ col - 1 ]; + + return sv->table->ops->fetch_int( sv->table, row, col, val ); +} + +static UINT SELECT_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm) +{ + MSISELECTVIEW *sv = (MSISELECTVIEW*)view; + + TRACE("%p %d %d %p\n", sv, row, col, stm ); + + if( !sv->table ) + return ERROR_FUNCTION_FAILED; + + if( (col==0) || (col>sv->num_cols) ) + return ERROR_FUNCTION_FAILED; + + col = sv->cols[ col - 1 ]; + + return sv->table->ops->fetch_stream( sv->table, row, col, stm ); +} + +static UINT SELECT_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val ) +{ + MSISELECTVIEW *sv = (MSISELECTVIEW*)view; + + TRACE("%p %d %d %04x\n", sv, row, col, val ); + + if( !sv->table ) + return ERROR_FUNCTION_FAILED; + + if( (col==0) || (col>sv->num_cols) ) + return ERROR_FUNCTION_FAILED; + + col = sv->cols[ col - 1 ]; + + return sv->table->ops->set_int( sv->table, row, col, val ); +} + +static UINT SELECT_insert_row( struct tagMSIVIEW *view, UINT *num ) +{ + MSISELECTVIEW *sv = (MSISELECTVIEW*)view; + + TRACE("%p %p\n", sv, num ); + + if( !sv->table ) + return ERROR_FUNCTION_FAILED; + + return sv->table->ops->insert_row( sv->table, num ); +} + +static UINT SELECT_execute( struct tagMSIVIEW *view, MSIRECORD *record ) +{ + MSISELECTVIEW *sv = (MSISELECTVIEW*)view; + + TRACE("%p %p\n", sv, record); + + if( !sv->table ) + return ERROR_FUNCTION_FAILED; + + return sv->table->ops->execute( sv->table, record ); +} + +static UINT SELECT_close( struct tagMSIVIEW *view ) +{ + MSISELECTVIEW *sv = (MSISELECTVIEW*)view; + + TRACE("%p\n", sv ); + + if( !sv->table ) + return ERROR_FUNCTION_FAILED; + + return sv->table->ops->close( sv->table ); +} + +static UINT SELECT_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols ) +{ + MSISELECTVIEW *sv = (MSISELECTVIEW*)view; + + TRACE("%p %p %p\n", sv, rows, cols ); + + if( !sv->table ) + return ERROR_FUNCTION_FAILED; + + if( cols ) + *cols = sv->num_cols; + + return sv->table->ops->get_dimensions( sv->table, rows, NULL ); +} + +static UINT SELECT_get_column_info( struct tagMSIVIEW *view, + UINT n, LPWSTR *name, UINT *type ) +{ + MSISELECTVIEW *sv = (MSISELECTVIEW*)view; + + TRACE("%p %d %p %p\n", sv, n, name, type ); + + if( !sv->table ) + return ERROR_FUNCTION_FAILED; + + if( (n==0) || (n>sv->num_cols) ) + return ERROR_FUNCTION_FAILED; + + n = sv->cols[ n - 1 ]; + + return sv->table->ops->get_column_info( sv->table, n, name, type ); +} + +static UINT SELECT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, + MSIRECORD *rec ) +{ + MSISELECTVIEW *sv = (MSISELECTVIEW*)view; + + TRACE("%p %d %p\n", sv, eModifyMode, rec ); + + if( !sv->table ) + return ERROR_FUNCTION_FAILED; + + return sv->table->ops->modify( sv->table, eModifyMode, rec ); +} + +static UINT SELECT_delete( struct tagMSIVIEW *view ) +{ + MSISELECTVIEW *sv = (MSISELECTVIEW*)view; + + TRACE("%p\n", sv ); + + if( sv->table ) + sv->table->ops->delete( sv->table ); + + HeapFree( GetProcessHeap(), 0, sv ); + + return ERROR_SUCCESS; +} + + +MSIVIEWOPS select_ops = +{ + SELECT_fetch_int, + SELECT_fetch_stream, + SELECT_set_int, + SELECT_insert_row, + SELECT_execute, + SELECT_close, + SELECT_get_dimensions, + SELECT_get_column_info, + SELECT_modify, + SELECT_delete +}; + +static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPWSTR name ) +{ + UINT r, n=0; + MSIVIEW *table; + + TRACE("%p adding %s\n", sv, debugstr_w( name ) ); + + if( sv->view.ops != &select_ops ) + return ERROR_FUNCTION_FAILED; + + table = sv->table; + if( !table ) + return ERROR_FUNCTION_FAILED; + if( !table->ops->get_dimensions ) + return ERROR_FUNCTION_FAILED; + if( !table->ops->get_column_info ) + return ERROR_FUNCTION_FAILED; + + if( sv->num_cols >= sv->max_cols ) + return ERROR_FUNCTION_FAILED; + + r = VIEW_find_column( table, name, &n ); + if( r != ERROR_SUCCESS ) + return r; + + sv->cols[sv->num_cols] = n; + TRACE("Translating column %s from %d -> %d\n", + debugstr_w( name ), sv->num_cols, n); + + sv->num_cols++; + + return ERROR_SUCCESS; +} + +UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, + string_list *columns ) +{ + MSISELECTVIEW *sv = NULL; + UINT count = 0, r; + + TRACE("%p\n", sv ); + + r = table->ops->get_dimensions( table, NULL, &count ); + if( r != ERROR_SUCCESS ) + { + ERR("can't get table dimensions\n"); + return r; + } + + sv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof *sv + count*sizeof (UINT) ); + if( !sv ) + return ERROR_FUNCTION_FAILED; + + /* fill the structure */ + sv->view.ops = &select_ops; + sv->db = db; + sv->table = table; + sv->num_cols = 0; + sv->max_cols = count; + + while( columns ) + { + r = SELECT_AddColumn( sv, columns->string ); + if( r ) + break; + columns = columns->next; + } + + if( r != ERROR_SUCCESS ) + { + sv->view.ops->delete( &sv->view ); + sv = NULL; + } + + *view = &sv->view; + + return r; +} diff --git a/reactos/lib/msi/sql.tab.c b/reactos/lib/msi/sql.tab.c index 524ddda0788..6ead0d2e7c0 100644 --- a/reactos/lib/msi/sql.tab.c +++ b/reactos/lib/msi/sql.tab.c @@ -1,2148 +1,2148 @@ -/* A Bison parser, made from ./sql.y - by GNU bison 1.35. */ - -#define YYBISON 1 /* Identify Bison output. */ - -#define yyparse SQL_parse -#define yylex SQL_lex -#define yyerror SQL_error -#define yylval SQL_lval -#define yychar SQL_char -#define yydebug SQL_debug -#define yynerrs SQL_nerrs -# define TK_ABORT 257 -# define TK_AFTER 258 -# define TK_AGG_FUNCTION 259 -# define TK_ALL 260 -# define TK_AND 261 -# define TK_AS 262 -# define TK_ASC 263 -# define TK_BEFORE 264 -# define TK_BEGIN 265 -# define TK_BETWEEN 266 -# define TK_BITAND 267 -# define TK_BITNOT 268 -# define TK_BITOR 269 -# define TK_BY 270 -# define TK_CASCADE 271 -# define TK_CASE 272 -# define TK_CHAR 273 -# define TK_CHECK 274 -# define TK_CLUSTER 275 -# define TK_COLLATE 276 -# define TK_COLUMN 277 -# define TK_COMMA 278 -# define TK_COMMENT 279 -# define TK_COMMIT 280 -# define TK_CONCAT 281 -# define TK_CONFLICT 282 -# define TK_CONSTRAINT 283 -# define TK_COPY 284 -# define TK_CREATE 285 -# define TK_DEFAULT 286 -# define TK_DEFERRABLE 287 -# define TK_DEFERRED 288 -# define TK_DELETE 289 -# define TK_DELIMITERS 290 -# define TK_DESC 291 -# define TK_DISTINCT 292 -# define TK_DOT 293 -# define TK_DROP 294 -# define TK_EACH 295 -# define TK_ELSE 296 -# define TK_END 297 -# define TK_END_OF_FILE 298 -# define TK_EQ 299 -# define TK_EXCEPT 300 -# define TK_EXPLAIN 301 -# define TK_FAIL 302 -# define TK_FLOAT 303 -# define TK_FOR 304 -# define TK_FOREIGN 305 -# define TK_FROM 306 -# define TK_FUNCTION 307 -# define TK_GE 308 -# define TK_GLOB 309 -# define TK_GROUP 310 -# define TK_GT 311 -# define TK_HAVING 312 -# define TK_HOLD 313 -# define TK_IGNORE 314 -# define TK_ILLEGAL 315 -# define TK_IMMEDIATE 316 -# define TK_IN 317 -# define TK_INDEX 318 -# define TK_INITIALLY 319 -# define TK_ID 320 -# define TK_INSERT 321 -# define TK_INSTEAD 322 -# define TK_INT 323 -# define TK_INTEGER 324 -# define TK_INTERSECT 325 -# define TK_INTO 326 -# define TK_IS 327 -# define TK_ISNULL 328 -# define TK_JOIN 329 -# define TK_JOIN_KW 330 -# define TK_KEY 331 -# define TK_LE 332 -# define TK_LIKE 333 -# define TK_LIMIT 334 -# define TK_LONG 335 -# define TK_LONGCHAR 336 -# define TK_LP 337 -# define TK_LSHIFT 338 -# define TK_LT 339 -# define TK_LOCALIZABLE 340 -# define TK_MATCH 341 -# define TK_MINUS 342 -# define TK_NE 343 -# define TK_NOT 344 -# define TK_NOTNULL 345 -# define TK_NULL 346 -# define TK_OBJECT 347 -# define TK_OF 348 -# define TK_OFFSET 349 -# define TK_ON 350 -# define TK_OR 351 -# define TK_ORACLE_OUTER_JOIN 352 -# define TK_ORDER 353 -# define TK_PLUS 354 -# define TK_PRAGMA 355 -# define TK_PRIMARY 356 -# define TK_RAISE 357 -# define TK_REFERENCES 358 -# define TK_REM 359 -# define TK_REPLACE 360 -# define TK_RESTRICT 361 -# define TK_ROLLBACK 362 -# define TK_ROW 363 -# define TK_RP 364 -# define TK_RSHIFT 365 -# define TK_SELECT 366 -# define TK_SEMI 367 -# define TK_SET 368 -# define TK_SHORT 369 -# define TK_SLASH 370 -# define TK_SPACE 371 -# define TK_STAR 372 -# define TK_STATEMENT 373 -# define TK_STRING 374 -# define TK_TABLE 375 -# define TK_TEMP 376 -# define TK_THEN 377 -# define TK_TRANSACTION 378 -# define TK_TRIGGER 379 -# define TK_UMINUS 380 -# define TK_UNCLOSED_STRING 381 -# define TK_UNION 382 -# define TK_UNIQUE 383 -# define TK_UPDATE 384 -# define TK_UPLUS 385 -# define TK_USING 386 -# define TK_VACUUM 387 -# define TK_VALUES 388 -# define TK_VIEW 389 -# define TK_WHEN 390 -# define TK_WHERE 391 -# define TK_WILDCARD 392 -# define END_OF_FILE 393 -# define ILLEGAL 394 -# define SPACE 395 -# define UNCLOSED_STRING 396 -# define COMMENT 397 -# define FUNCTION 398 -# define COLUMN 399 - -#line 1 "./sql.y" - - -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2002-2004 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include "config.h" - -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> - -#include "windef.h" -#include "winbase.h" -#include "query.h" -#include "wine/list.h" -#include "wine/debug.h" -#include "wine/unicode.h" - -#define YYLEX_PARAM info -#define YYPARSE_PARAM info - -extern int SQL_error(const char *str); - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -typedef struct tag_SQL_input -{ - MSIDATABASE *db; - LPCWSTR command; - DWORD n, len; - MSIVIEW **view; /* view structure for the resulting query */ - struct list *mem; -} SQL_input; - -static LPWSTR SQL_getstring( void *info, struct sql_str *str ); -static INT SQL_getint( void *info ); -static int SQL_lex( void *SQL_lval, SQL_input *info ); - -static void *parser_alloc( void *info, unsigned int sz ); - -static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys); - -static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r ); -static struct expr * EXPR_column( void *info, LPWSTR column ); -static struct expr * EXPR_ival( void *info, struct sql_str *, int sign ); -static struct expr * EXPR_sval( void *info, struct sql_str * ); -static struct expr * EXPR_wildcard( void *info ); - - -#line 71 "./sql.y" -#ifndef YYSTYPE -typedef union -{ - struct sql_str str; - LPWSTR string; - string_list *column_list; - value_list *val_list; - MSIVIEW *query; - struct expr *expr; - USHORT column_type; - create_col_info *column_info; - column_assignment update_col_info; -} yystype; -# define YYSTYPE yystype -# define YYSTYPE_IS_TRIVIAL 1 -#endif -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif - - - -#define YYFINAL 126 -#define YYFLAG -32768 -#define YYNTBASE 147 - -/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */ -#define YYTRANSLATE(x) ((unsigned)(x) <= 400 ? yytranslate[x] : 175) - -/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */ -static const short yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 3, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, - 146 -}; - -#if YYDEBUG -static const short yyprhs[] = -{ - 0, 0, 2, 4, 6, 8, 10, 12, 23, 35, - 42, 50, 57, 60, 65, 70, 73, 75, 78, 80, - 84, 86, 91, 93, 95, 97, 99, 101, 103, 108, - 110, 113, 117, 120, 122, 126, 128, 130, 134, 137, - 141, 145, 149, 153, 157, 161, 165, 169, 173, 177, - 181, 186, 188, 190, 192, 196, 198, 202, 206, 208, - 211, 213, 215, 217, 221, 223, 225 -}; -static const short yyrhs[] = -{ - 148, 0, 159, 0, 150, 0, 149, 0, 151, 0, - 152, 0, 67, 72, 173, 83, 162, 110, 134, 83, - 167, 110, 0, 67, 72, 173, 83, 162, 110, 134, - 83, 167, 110, 122, 0, 31, 121, 173, 83, 153, - 110, 0, 31, 121, 173, 83, 153, 110, 59, 0, - 130, 173, 114, 168, 137, 165, 0, 35, 163, 0, - 154, 102, 77, 162, 0, 154, 24, 172, 155, 0, - 172, 155, 0, 156, 0, 156, 86, 0, 157, 0, - 157, 90, 92, 0, 19, 0, 19, 83, 158, 110, - 0, 82, 0, 115, 0, 69, 0, 81, 0, 93, - 0, 70, 0, 160, 99, 16, 162, 0, 160, 0, - 112, 161, 0, 112, 38, 161, 0, 162, 163, 0, - 172, 0, 172, 24, 162, 0, 118, 0, 164, 0, - 164, 137, 165, 0, 52, 173, 0, 83, 165, 110, - 0, 171, 45, 171, 0, 165, 7, 165, 0, 165, - 97, 165, 0, 171, 45, 166, 0, 171, 57, 166, - 0, 171, 85, 166, 0, 171, 78, 166, 0, 171, - 54, 166, 0, 171, 89, 166, 0, 171, 73, 92, - 0, 171, 73, 90, 92, 0, 171, 0, 170, 0, - 170, 0, 170, 24, 167, 0, 169, 0, 169, 24, - 168, 0, 172, 45, 170, 0, 70, 0, 88, 70, - 0, 120, 0, 138, 0, 172, 0, 173, 39, 174, - 0, 174, 0, 174, 0, 66, 0 -}; - -#endif - -#if YYDEBUG -/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ -static const short yyrline[] = -{ - 0, 140, 148, 150, 151, 152, 153, 156, 168, 180, - 193, 207, 220, 233, 243, 263, 274, 279, 286, 291, - 297, 302, 306, 310, 314, 318, 322, 328, 339, 352, - 355, 360, 371, 387, 401, 414, 420, 422, 434, 447, - 454, 460, 466, 472, 478, 484, 490, 496, 502, 508, - 514, 522, 524, 527, 539, 552, 554, 562, 578, 585, - 591, 597, 605, 614, 619, 625, 632 -}; -#endif - - -#if (YYDEBUG) || defined YYERROR_VERBOSE - -/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */ -static const char *const yytname[] = -{ - "$", "error", "$undefined.", "TK_ABORT", "TK_AFTER", "TK_AGG_FUNCTION", - "TK_ALL", "TK_AND", "TK_AS", "TK_ASC", "TK_BEFORE", "TK_BEGIN", - "TK_BETWEEN", "TK_BITAND", "TK_BITNOT", "TK_BITOR", "TK_BY", - "TK_CASCADE", "TK_CASE", "TK_CHAR", "TK_CHECK", "TK_CLUSTER", - "TK_COLLATE", "TK_COLUMN", "TK_COMMA", "TK_COMMENT", "TK_COMMIT", - "TK_CONCAT", "TK_CONFLICT", "TK_CONSTRAINT", "TK_COPY", "TK_CREATE", - "TK_DEFAULT", "TK_DEFERRABLE", "TK_DEFERRED", "TK_DELETE", - "TK_DELIMITERS", "TK_DESC", "TK_DISTINCT", "TK_DOT", "TK_DROP", - "TK_EACH", "TK_ELSE", "TK_END", "TK_END_OF_FILE", "TK_EQ", "TK_EXCEPT", - "TK_EXPLAIN", "TK_FAIL", "TK_FLOAT", "TK_FOR", "TK_FOREIGN", "TK_FROM", - "TK_FUNCTION", "TK_GE", "TK_GLOB", "TK_GROUP", "TK_GT", "TK_HAVING", - "TK_HOLD", "TK_IGNORE", "TK_ILLEGAL", "TK_IMMEDIATE", "TK_IN", - "TK_INDEX", "TK_INITIALLY", "TK_ID", "TK_INSERT", "TK_INSTEAD", - "TK_INT", "TK_INTEGER", "TK_INTERSECT", "TK_INTO", "TK_IS", "TK_ISNULL", - "TK_JOIN", "TK_JOIN_KW", "TK_KEY", "TK_LE", "TK_LIKE", "TK_LIMIT", - "TK_LONG", "TK_LONGCHAR", "TK_LP", "TK_LSHIFT", "TK_LT", - "TK_LOCALIZABLE", "TK_MATCH", "TK_MINUS", "TK_NE", "TK_NOT", - "TK_NOTNULL", "TK_NULL", "TK_OBJECT", "TK_OF", "TK_OFFSET", "TK_ON", - "TK_OR", "TK_ORACLE_OUTER_JOIN", "TK_ORDER", "TK_PLUS", "TK_PRAGMA", - "TK_PRIMARY", "TK_RAISE", "TK_REFERENCES", "TK_REM", "TK_REPLACE", - "TK_RESTRICT", "TK_ROLLBACK", "TK_ROW", "TK_RP", "TK_RSHIFT", - "TK_SELECT", "TK_SEMI", "TK_SET", "TK_SHORT", "TK_SLASH", "TK_SPACE", - "TK_STAR", "TK_STATEMENT", "TK_STRING", "TK_TABLE", "TK_TEMP", - "TK_THEN", "TK_TRANSACTION", "TK_TRIGGER", "TK_UMINUS", - "TK_UNCLOSED_STRING", "TK_UNION", "TK_UNIQUE", "TK_UPDATE", "TK_UPLUS", - "TK_USING", "TK_VACUUM", "TK_VALUES", "TK_VIEW", "TK_WHEN", "TK_WHERE", - "TK_WILDCARD", "END_OF_FILE", "ILLEGAL", "SPACE", "UNCLOSED_STRING", - "COMMENT", "FUNCTION", "COLUMN", "AGG_FUNCTION.", "query", "onequery", - "oneinsert", "onecreate", "oneupdate", "onedelete", "table_def", - "column_def", "column_type", "data_type_l", "data_type", "data_count", - "oneselect", "unorderedsel", "selectfrom", "selcollist", "from", - "fromtable", "expr", "val", "constlist", "update_assign_list", - "column_assignment", "const_val", "column_val", "column", "table", "id", 0 -}; -#endif - -/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const short yyr1[] = -{ - 0, 147, 148, 148, 148, 148, 148, 149, 149, 150, - 150, 151, 152, 153, 154, 154, 155, 155, 156, 156, - 157, 157, 157, 157, 157, 157, 157, 158, 159, 159, - 160, 160, 161, 162, 162, 162, 163, 163, 164, 165, - 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, - 165, 166, 166, 167, 167, 168, 168, 169, 170, 170, - 170, 170, 171, 172, 172, 173, 174 -}; - -/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ -static const short yyr2[] = -{ - 0, 1, 1, 1, 1, 1, 1, 10, 11, 6, - 7, 6, 2, 4, 4, 2, 1, 2, 1, 3, - 1, 4, 1, 1, 1, 1, 1, 1, 4, 1, - 2, 3, 2, 1, 3, 1, 1, 3, 2, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 1, 1, 1, 3, 1, 3, 3, 1, 2, - 1, 1, 1, 3, 1, 1, 1 -}; - -/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE - doesn't specify something else to do. Zero means the default is an - error. */ -static const short yydefact[] = -{ - 0, 0, 0, 0, 0, 0, 1, 4, 3, 5, - 6, 2, 29, 0, 0, 12, 36, 0, 0, 66, - 35, 30, 0, 33, 0, 64, 0, 65, 0, 0, - 38, 0, 0, 31, 32, 0, 0, 0, 0, 0, - 0, 37, 0, 62, 0, 34, 63, 0, 55, 0, - 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, - 0, 20, 24, 25, 22, 26, 23, 15, 16, 18, - 39, 41, 42, 58, 0, 60, 61, 43, 52, 40, - 47, 51, 44, 0, 49, 46, 45, 48, 0, 11, - 56, 57, 10, 0, 0, 0, 17, 0, 59, 50, - 0, 14, 13, 27, 0, 19, 0, 21, 0, 53, - 7, 0, 8, 54, 0, 0, 0 -}; - -static const short yydefgoto[] = -{ - 124, 6, 7, 8, 9, 10, 51, 52, 77, 78, - 79, 114, 11, 12, 21, 22, 15, 16, 41, 87, - 118, 47, 48, 88, 42, 43, 24, 25 -}; - -static const short yypact[] = -{ - -28, -102, -32, -48, -29, -39,-32768,-32768,-32768,-32768, - -32768,-32768, -61, -39, -39,-32768, -97, -39, -50,-32768, - -32768,-32768, -32, 19, 6, 9, -65,-32768, 34, -30, - -32768, -37, -26,-32768,-32768, -50, -39, -39, -50, -39, - -37, -2, -31,-32768, -50,-32768,-32768, -86, 32, 10, - -32768, -51, -20, -17, -7, -37, -37, -60, -60, -60, - -59, -60, -60, -60, -36, -37, -39, -58, 16, -39, - 2, 0,-32768,-32768,-32768,-32768,-32768,-32768, -5, 1, - -32768, -2, -2,-32768, 15,-32768,-32768,-32768,-32768,-32768, - -32768,-32768,-32768, -4,-32768,-32768,-32768,-32768, -42, -2, - -32768,-32768,-32768, -17, -50, 23,-32768, 5,-32768,-32768, - 11,-32768,-32768,-32768, -11,-32768, -58,-32768, -10, 83, - -9, -58,-32768,-32768, 117, 118,-32768 -}; - -static const short yypgoto[] = -{ - -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 17,-32768, - -32768,-32768,-32768,-32768, 101, -27, 99,-32768, 31, 53, - 3, 57,-32768, -49, 47, -3, 56, 8 -}; - - -#define YYLAST 124 - - -static const short yytable[] = -{ - 55, 23, 71, 1, 69, 55, 19, 2, 45, 18, - 83, 50, 83, 27, 57, 23, 19, 64, 101, 13, - 14, 27, 27, 58, 17, 27, 59, 19, 84, 19, - 84, 93, 23, 94, 49, 23, 53, 19, 28, 3, - 31, 23, 60, 35, 46, 36, 40, 61, -65, 37, - 38, 65, 72, 39, 62, 67, 66, 44, 63, 68, - 85, 26, 85, 49, 73, 74, 103, 119, 20, 29, - 30, 54, 119, 32, 98, 102, 75, 112, 86, 104, - 86, 106, 70, 105, 4, 108, 81, 82, 109, 20, - 56, 107, 110, 113, 116, 56, 99, 115, 76, 117, - 120, 23, 5, 80, 89, 91, 91, 121, 91, 91, - 91, 90, 92, 122, 95, 96, 97, 125, 126, 33, - 111, 34, 0, 100, 123 -}; - -static const short yycheck[] = -{ - 7, 4, 19, 31, 24, 7, 66, 35, 35, 38, - 70, 38, 70, 5, 45, 18, 66, 44, 67, 121, - 52, 13, 14, 54, 72, 17, 57, 66, 88, 66, - 88, 90, 35, 92, 37, 38, 39, 66, 99, 67, - 137, 44, 73, 24, 36, 39, 83, 78, 39, 114, - 16, 137, 69, 83, 85, 45, 24, 83, 89, 110, - 120, 5, 120, 66, 81, 82, 69, 116, 118, 13, - 14, 40, 121, 17, 110, 59, 93, 104, 138, 77, - 138, 86, 102, 83, 112, 70, 55, 56, 92, 118, - 97, 90, 134, 70, 83, 97, 65, 92, 115, 110, - 110, 104, 130, 110, 57, 58, 59, 24, 61, 62, - 63, 58, 59, 122, 61, 62, 63, 0, 0, 18, - 103, 22, -1, 66, 121 -}; -#define YYPURE 1 - -/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ -#line 3 "/usr/share/bison/bison.simple" - -/* Skeleton output parser for bison, - - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software - Foundation, Inc. - - 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, 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., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -/* As a special exception, when this file is copied by Bison into a - Bison output file, you may use that output file without restriction. - This special exception was added by the Free Software Foundation - in version 1.24 of Bison. */ - -/* This is the parser code that is written into each bison parser when - the %semantic_parser declaration is not specified in the grammar. - It was written by Richard Stallman by simplifying the hairy parser - used when %semantic_parser is specified. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -#if ! defined (yyoverflow) || defined (YYERROR_VERBOSE) - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# if YYSTACK_USE_ALLOCA -# define YYSTACK_ALLOC alloca -# else -# ifndef YYSTACK_USE_ALLOCA -# if defined (alloca) || defined (_ALLOCA_H) -# define YYSTACK_ALLOC alloca -# else -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# endif -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's `empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) -# else -# if defined (__STDC__) || defined (__cplusplus) -# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# endif -# define YYSTACK_ALLOC malloc -# define YYSTACK_FREE free -# endif -#endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */ - - -#if (! defined (yyoverflow) \ - && (! defined (__cplusplus) \ - || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - short yyss; - YYSTYPE yyvs; -# if YYLSP_NEEDED - YYLTYPE yyls; -# endif -}; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# if YYLSP_NEEDED -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ - + 2 * YYSTACK_GAP_MAX) -# else -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ - + YYSTACK_GAP_MAX) -# endif - -/* Copy COUNT objects from FROM to TO. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) -# else -# define YYCOPY(To, From, Count) \ - do \ - { \ - register YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ - while (0) -# endif -# endif - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack, Stack, yysize); \ - Stack = &yyptr->Stack; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAX; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (0) - -#endif - - -#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) -# define YYSIZE_T __SIZE_TYPE__ -#endif -#if ! defined (YYSIZE_T) && defined (size_t) -# define YYSIZE_T size_t -#endif -#if ! defined (YYSIZE_T) -# if defined (__STDC__) || defined (__cplusplus) -# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# endif -#endif -#if ! defined (YYSIZE_T) -# define YYSIZE_T unsigned int -#endif - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY -2 -#define YYEOF 0 -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrlab1 -/* Like YYERROR except do call yyerror. This remains here temporarily - to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. */ -#define YYFAIL goto yyerrlab -#define YYRECOVERING() (!!yyerrstatus) -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - yychar1 = YYTRANSLATE (yychar); \ - YYPOPSTACK; \ - goto yybackup; \ - } \ - else \ - { \ - yyerror ("syntax error: cannot back up"); \ - YYERROR; \ - } \ -while (0) - -#define YYTERROR 1 -#define YYERRCODE 256 - - -/* YYLLOC_DEFAULT -- Compute the default location (before the actions - are run). - - When YYLLOC_DEFAULT is run, CURRENT is set the location of the - first token. By default, to implement support for ranges, extend - its range to the last symbol. */ - -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - Current.last_line = Rhs[N].last_line; \ - Current.last_column = Rhs[N].last_column; -#endif - - -/* YYLEX -- calling `yylex' with the right arguments. */ - -#if YYPURE -# if YYLSP_NEEDED -# ifdef YYLEX_PARAM -# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) -# else -# define YYLEX yylex (&yylval, &yylloc) -# endif -# else /* !YYLSP_NEEDED */ -# ifdef YYLEX_PARAM -# define YYLEX yylex (&yylval, YYLEX_PARAM) -# else -# define YYLEX yylex (&yylval) -# endif -# endif /* !YYLSP_NEEDED */ -#else /* !YYPURE */ -# define YYLEX yylex () -#endif /* !YYPURE */ - - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (0) -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -#endif /* !YYDEBUG */ - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#if YYMAXDEPTH == 0 -# undef YYMAXDEPTH -#endif - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - -#ifdef YYERROR_VERBOSE - -# ifndef yystrlen -# if defined (__GLIBC__) && defined (_STRING_H) -# define yystrlen strlen -# else -/* Return the length of YYSTR. */ -static YYSIZE_T -# if defined (__STDC__) || defined (__cplusplus) -yystrlen (const char *yystr) -# else -yystrlen (yystr) - const char *yystr; -# endif -{ - register const char *yys = yystr; - - while (*yys++ != '\0') - continue; - - return yys - yystr - 1; -} -# endif -# endif - -# ifndef yystpcpy -# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) -# define yystpcpy stpcpy -# else -/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in - YYDEST. */ -static char * -# if defined (__STDC__) || defined (__cplusplus) -yystpcpy (char *yydest, const char *yysrc) -# else -yystpcpy (yydest, yysrc) - char *yydest; - const char *yysrc; -# endif -{ - register char *yyd = yydest; - register const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif -#endif - -#line 315 "/usr/share/bison/bison.simple" - - -/* The user can define YYPARSE_PARAM as the name of an argument to be passed - into yyparse. The argument should have type void *. - It should actually point to an object. - Grammar actions can access the variable by casting it - to the proper pointer type. */ - -#ifdef YYPARSE_PARAM -# if defined (__STDC__) || defined (__cplusplus) -# define YYPARSE_PARAM_ARG void *YYPARSE_PARAM -# define YYPARSE_PARAM_DECL -# else -# define YYPARSE_PARAM_ARG YYPARSE_PARAM -# define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; -# endif -#else /* !YYPARSE_PARAM */ -# define YYPARSE_PARAM_ARG -# define YYPARSE_PARAM_DECL -#endif /* !YYPARSE_PARAM */ - -/* Prevent warning if -Wstrict-prototypes. */ -#ifdef __GNUC__ -# ifdef YYPARSE_PARAM -int yyparse (void *); -# else -int yyparse (void); -# endif -#endif - -/* YY_DECL_VARIABLES -- depending whether we use a pure parser, - variables are global, or local to YYPARSE. */ - -#define YY_DECL_NON_LSP_VARIABLES \ -/* The lookahead symbol. */ \ -int yychar; \ - \ -/* The semantic value of the lookahead symbol. */ \ -YYSTYPE yylval; \ - \ -/* Number of parse errors so far. */ \ -int yynerrs; - -#if YYLSP_NEEDED -# define YY_DECL_VARIABLES \ -YY_DECL_NON_LSP_VARIABLES \ - \ -/* Location data for the lookahead symbol. */ \ -YYLTYPE yylloc; -#else -# define YY_DECL_VARIABLES \ -YY_DECL_NON_LSP_VARIABLES -#endif - - -/* If nonreentrant, generate the variables here. */ - -#if !YYPURE -YY_DECL_VARIABLES -#endif /* !YYPURE */ - -int -yyparse (YYPARSE_PARAM_ARG) - YYPARSE_PARAM_DECL -{ - /* If reentrant, generate the variables here. */ -#if YYPURE - YY_DECL_VARIABLES -#endif /* !YYPURE */ - - register int yystate; - register int yyn; - int yyresult; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - /* Lookahead token as an internal (translated) token number. */ - int yychar1 = 0; - - /* Three stacks and their tools: - `yyss': related to states, - `yyvs': related to semantic values, - `yyls': related to locations. - - Refer to the stacks thru separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - short yyssa[YYINITDEPTH]; - short *yyss = yyssa; - register short *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs = yyvsa; - register YYSTYPE *yyvsp; - -#if YYLSP_NEEDED - /* The location stack. */ - YYLTYPE yylsa[YYINITDEPTH]; - YYLTYPE *yyls = yylsa; - YYLTYPE *yylsp; -#endif - -#if YYLSP_NEEDED -# define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) -#else -# define YYPOPSTACK (yyvsp--, yyssp--) -#endif - - YYSIZE_T yystacksize = YYINITDEPTH; - - - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; -#if YYLSP_NEEDED - YYLTYPE yyloc; -#endif - - /* When reducing, the number of symbols on the RHS of the reduced - rule. */ - int yylen; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - - yyssp = yyss; - yyvsp = yyvs; -#if YYLSP_NEEDED - yylsp = yyls; -#endif - goto yysetstate; - -/*------------------------------------------------------------. -| yynewstate -- Push a new state, which is found in yystate. | -`------------------------------------------------------------*/ - yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. so pushing a state here evens the stacks. - */ - yyssp++; - - yysetstate: - *yyssp = yystate; - - if (yyssp >= yyss + yystacksize - 1) - { - /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; - -#ifdef yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - short *yyss1 = yyss; - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. */ -# if YYLSP_NEEDED - YYLTYPE *yyls1 = yyls; - /* This used to be a conditional around just the two extra args, - but that might be undefined if yyoverflow is a macro. */ - yyoverflow ("parser stack overflow", - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - &yyls1, yysize * sizeof (*yylsp), - &yystacksize); - yyls = yyls1; -# else - yyoverflow ("parser stack overflow", - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - &yystacksize); -# endif - yyss = yyss1; - yyvs = yyvs1; - } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyoverflowlab; -# else - /* Extend the stack our own way. */ - if (yystacksize >= YYMAXDEPTH) - goto yyoverflowlab; - yystacksize *= 2; - if (yystacksize > YYMAXDEPTH) - yystacksize = YYMAXDEPTH; - - { - short *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyoverflowlab; - YYSTACK_RELOCATE (yyss); - YYSTACK_RELOCATE (yyvs); -# if YYLSP_NEEDED - YYSTACK_RELOCATE (yyls); -# endif -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif -#endif /* no yyoverflow */ - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; -#if YYLSP_NEEDED - yylsp = yyls + yysize - 1; -#endif - - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); - - if (yyssp >= yyss + yystacksize - 1) - YYABORT; - } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - - goto yybackup; - - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - -/* Do appropriate processing given the current state. */ -/* Read a lookahead token if we need one and don't already have one. */ -/* yyresume: */ - - /* First try to decide what to do without reference to lookahead token. */ - - yyn = yypact[yystate]; - if (yyn == YYFLAG) - goto yydefault; - - /* Not known => get a lookahead token if don't already have one. */ - - /* yychar is either YYEMPTY or YYEOF - or a valid token in external form. */ - - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = YYLEX; - } - - /* Convert token to internal form (in yychar1) for indexing tables with */ - - if (yychar <= 0) /* This means end of input. */ - { - yychar1 = 0; - yychar = YYEOF; /* Don't call YYLEX any more */ - - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yychar1 = YYTRANSLATE (yychar); - -#if YYDEBUG - /* We have to keep this `#if YYDEBUG', since we use variables - which are defined only if `YYDEBUG' is set. */ - if (yydebug) - { - YYFPRINTF (stderr, "Next token is %d (%s", - yychar, yytname[yychar1]); - /* Give the individual parser a way to print the precise - meaning of a token, for further debugging info. */ -# ifdef YYPRINT - YYPRINT (stderr, yychar, yylval); -# endif - YYFPRINTF (stderr, ")\n"); - } -#endif - } - - yyn += yychar1; - if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) - goto yydefault; - - yyn = yytable[yyn]; - - /* yyn is what to do for this token type in this state. - Negative => reduce, -yyn is rule number. - Positive => shift, yyn is new state. - New state is final state => don't bother to shift, - just return success. - 0, or most negative number => error. */ - - if (yyn < 0) - { - if (yyn == YYFLAG) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - else if (yyn == 0) - goto yyerrlab; - - if (yyn == YYFINAL) - YYACCEPT; - - /* Shift the lookahead token. */ - YYDPRINTF ((stderr, "Shifting token %d (%s), ", - yychar, yytname[yychar1])); - - /* Discard the token being shifted unless it is eof. */ - if (yychar != YYEOF) - yychar = YYEMPTY; - - *++yyvsp = yylval; -#if YYLSP_NEEDED - *++yylsp = yylloc; -#endif - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - yystate = yyn; - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- Do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - `$$ = $1'. - - Otherwise, the following line sets YYVAL to the semantic value of - the lookahead token. This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - -#if YYLSP_NEEDED - /* Similarly for the default location. Let the user run additional - commands if for instance locations are ranges. */ - yyloc = yylsp[1-yylen]; - YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); -#endif - -#if YYDEBUG - /* We have to keep this `#if YYDEBUG', since we use variables which - are defined only if `YYDEBUG' is set. */ - if (yydebug) - { - int yyi; - - YYFPRINTF (stderr, "Reducing via rule %d (line %d), ", - yyn, yyrline[yyn]); - - /* Print the symbols being reduced, and their result. */ - for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++) - YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]); - YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]); - } -#endif - - switch (yyn) { - -case 1: -#line 142 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - *sql->view = yyvsp[0].query; - ; - break;} -case 7: -#line 158 "./sql.y" -{ - SQL_input *sql = (SQL_input*) info; - MSIVIEW *insert = NULL; - UINT r; - - r = INSERT_CreateView( sql->db, &insert, yyvsp[-7].string, yyvsp[-5].column_list, yyvsp[-1].val_list, FALSE ); - if( !insert ) - YYABORT; - yyval.query = insert; - ; - break;} -case 8: -#line 169 "./sql.y" -{ - SQL_input *sql = (SQL_input*) info; - MSIVIEW *insert = NULL; - - INSERT_CreateView( sql->db, &insert, yyvsp[-8].string, yyvsp[-6].column_list, yyvsp[-2].val_list, TRUE ); - if( !insert ) - YYABORT; - yyval.query = insert; - ; - break;} -case 9: -#line 182 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - MSIVIEW *create = NULL; - - if( !yyvsp[-1].column_info ) - YYABORT; - CREATE_CreateView( sql->db, &create, yyvsp[-3].string, yyvsp[-1].column_info, FALSE ); - if( !create ) - YYABORT; - yyval.query = create; - ; - break;} -case 10: -#line 194 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - MSIVIEW *create = NULL; - - if( !yyvsp[-2].column_info ) - YYABORT; - CREATE_CreateView( sql->db, &create, yyvsp[-4].string, yyvsp[-2].column_info, TRUE ); - if( !create ) - YYABORT; - yyval.query = create; - ; - break;} -case 11: -#line 209 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - MSIVIEW *update = NULL; - - UPDATE_CreateView( sql->db, &update, yyvsp[-4].string, &yyvsp[-2].update_col_info, yyvsp[0].expr ); - if( !update ) - YYABORT; - yyval.query = update; - ; - break;} -case 12: -#line 222 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - MSIVIEW *delete = NULL; - - DELETE_CreateView( sql->db, &delete, yyvsp[0].query ); - if( !delete ) - YYABORT; - yyval.query = delete; - ; - break;} -case 13: -#line 235 "./sql.y" -{ - if( SQL_MarkPrimaryKeys( yyvsp[-3].column_info, yyvsp[0].column_list ) ) - yyval.column_info = yyvsp[-3].column_info; - else - yyval.column_info = NULL; - ; - break;} -case 14: -#line 245 "./sql.y" -{ - create_col_info *ci; - - for( ci = yyvsp[-3].column_info; ci->next; ci = ci->next ) - ; - - ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info ); - if( !ci->next ) - { - /* FIXME: free $1 */ - YYABORT; - } - ci->next->colname = yyvsp[-1].string; - ci->next->type = yyvsp[0].column_type; - ci->next->next = NULL; - - yyval.column_info = yyvsp[-3].column_info; - ; - break;} -case 15: -#line 264 "./sql.y" -{ - yyval.column_info = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info ); - if( ! yyval.column_info ) - YYABORT; - yyval.column_info->colname = yyvsp[-1].string; - yyval.column_info->type = yyvsp[0].column_type; - yyval.column_info->next = NULL; - ; - break;} -case 16: -#line 276 "./sql.y" -{ - yyval.column_type = yyvsp[0].column_type | MSITYPE_VALID; - ; - break;} -case 17: -#line 280 "./sql.y" -{ - FIXME("LOCALIZABLE ignored\n"); - yyval.column_type = yyvsp[-1].column_type | MSITYPE_VALID; - ; - break;} -case 18: -#line 288 "./sql.y" -{ - yyval.column_type |= MSITYPE_NULLABLE; - ; - break;} -case 19: -#line 292 "./sql.y" -{ - yyval.column_type = yyvsp[-2].column_type; - ; - break;} -case 20: -#line 299 "./sql.y" -{ - yyval.column_type = MSITYPE_STRING | 1; - ; - break;} -case 21: -#line 303 "./sql.y" -{ - yyval.column_type = MSITYPE_STRING | 0x400 | yyvsp[-1].column_type; - ; - break;} -case 22: -#line 307 "./sql.y" -{ - yyval.column_type = 2; - ; - break;} -case 23: -#line 311 "./sql.y" -{ - yyval.column_type = 2; - ; - break;} -case 24: -#line 315 "./sql.y" -{ - yyval.column_type = 2; - ; - break;} -case 25: -#line 319 "./sql.y" -{ - yyval.column_type = 4; - ; - break;} -case 26: -#line 323 "./sql.y" -{ - yyval.column_type = 0; - ; - break;} -case 27: -#line 330 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - int val = SQL_getint(sql); - if( ( val > 255 ) || ( val < 0 ) ) - YYABORT; - yyval.column_type = val; - ; - break;} -case 28: -#line 341 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - - yyval.query = NULL; - if( yyvsp[0].column_list ) - ORDER_CreateView( sql->db, &yyval.query, yyvsp[-3].query, yyvsp[0].column_list ); - else - yyval.query = yyvsp[-3].query; - if( !yyval.query ) - YYABORT; - ; - break;} -case 30: -#line 357 "./sql.y" -{ - yyval.query = yyvsp[0].query; - ; - break;} -case 31: -#line 361 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - - yyval.query = NULL; - DISTINCT_CreateView( sql->db, &yyval.query, yyvsp[0].query ); - if( !yyval.query ) - YYABORT; - ; - break;} -case 32: -#line 373 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - - yyval.query = NULL; - if( yyvsp[-1].column_list ) - SELECT_CreateView( sql->db, &yyval.query, yyvsp[0].query, yyvsp[-1].column_list ); - else - yyval.query = yyvsp[0].query; - - if( !yyval.query ) - YYABORT; - ; - break;} -case 33: -#line 389 "./sql.y" -{ - string_list *list; - - list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); - if( !list ) - YYABORT; - list->string = yyvsp[0].string; - list->next = NULL; - - yyval.column_list = list; - TRACE("Collist %s\n",debugstr_w(yyval.column_list->string)); - ; - break;} -case 34: -#line 402 "./sql.y" -{ - string_list *list; - - list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); - if( !list ) - YYABORT; - list->string = yyvsp[-2].string; - list->next = yyvsp[0].column_list; - - yyval.column_list = list; - TRACE("From table: %s\n",debugstr_w(yyval.column_list->string)); - ; - break;} -case 35: -#line 415 "./sql.y" -{ - yyval.column_list = NULL; - ; - break;} -case 37: -#line 423 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - UINT r; - - yyval.query = NULL; - r = WHERE_CreateView( sql->db, &yyval.query, yyvsp[-2].query, yyvsp[0].expr ); - if( r != ERROR_SUCCESS || !yyval.query ) - YYABORT; - ; - break;} -case 38: -#line 436 "./sql.y" -{ - SQL_input* sql = (SQL_input*) info; - UINT r; - - yyval.query = NULL; - r = TABLE_CreateView( sql->db, yyvsp[0].string, &yyval.query ); - if( r != ERROR_SUCCESS || !yyval.query ) - YYABORT; - ; - break;} -case 39: -#line 449 "./sql.y" -{ - yyval.expr = yyvsp[-1].expr; - if( !yyval.expr ) - YYABORT; - ; - break;} -case 40: -#line 455 "./sql.y" -{ - yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_EQ, yyvsp[0].expr ); - if( !yyval.expr ) - YYABORT; - ; - break;} -case 41: -#line 461 "./sql.y" -{ - yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_AND, yyvsp[0].expr ); - if( !yyval.expr ) - YYABORT; - ; - break;} -case 42: -#line 467 "./sql.y" -{ - yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_OR, yyvsp[0].expr ); - if( !yyval.expr ) - YYABORT; - ; - break;} -case 43: -#line 473 "./sql.y" -{ - yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_EQ, yyvsp[0].expr ); - if( !yyval.expr ) - YYABORT; - ; - break;} -case 44: -#line 479 "./sql.y" -{ - yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_GT, yyvsp[0].expr ); - if( !yyval.expr ) - YYABORT; - ; - break;} -case 45: -#line 485 "./sql.y" -{ - yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_LT, yyvsp[0].expr ); - if( !yyval.expr ) - YYABORT; - ; - break;} -case 46: -#line 491 "./sql.y" -{ - yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_LE, yyvsp[0].expr ); - if( !yyval.expr ) - YYABORT; - ; - break;} -case 47: -#line 497 "./sql.y" -{ - yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_GE, yyvsp[0].expr ); - if( !yyval.expr ) - YYABORT; - ; - break;} -case 48: -#line 503 "./sql.y" -{ - yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_NE, yyvsp[0].expr ); - if( !yyval.expr ) - YYABORT; - ; - break;} -case 49: -#line 509 "./sql.y" -{ - yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_ISNULL, NULL ); - if( !yyval.expr ) - YYABORT; - ; - break;} -case 50: -#line 515 "./sql.y" -{ - yyval.expr = EXPR_complex( info, yyvsp[-3].expr, OP_NOTNULL, NULL ); - if( !yyval.expr ) - YYABORT; - ; - break;} -case 53: -#line 529 "./sql.y" -{ - value_list *vals; - - vals = parser_alloc( info, sizeof *vals ); - if( !vals ) - YYABORT; - vals->val = yyvsp[0].expr; - vals->next = NULL; - yyval.val_list = vals; - ; - break;} -case 54: -#line 540 "./sql.y" -{ - value_list *vals; - - vals = parser_alloc( info, sizeof *vals ); - if( !vals ) - YYABORT; - vals->val = yyvsp[-2].expr; - vals->next = yyvsp[0].val_list; - yyval.val_list = vals; - ; - break;} -case 56: -#line 555 "./sql.y" -{ - yyvsp[-2].update_col_info.col_list->next = yyvsp[0].update_col_info.col_list; - yyvsp[-2].update_col_info.val_list->next = yyvsp[0].update_col_info.val_list; - yyval.update_col_info = yyvsp[-2].update_col_info; - ; - break;} -case 57: -#line 564 "./sql.y" -{ - yyval.update_col_info.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.col_list ); - if( !yyval.update_col_info.col_list ) - YYABORT; - yyval.update_col_info.col_list->string = yyvsp[-2].string; - yyval.update_col_info.col_list->next = NULL; - yyval.update_col_info.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.val_list ); - if( !yyval.update_col_info.val_list ) - YYABORT; - yyval.update_col_info.val_list->val = yyvsp[0].expr; - yyval.update_col_info.val_list->next = 0; - ; - break;} -case 58: -#line 580 "./sql.y" -{ - yyval.expr = EXPR_ival( info, &yyvsp[0].str, 1 ); - if( !yyval.expr ) - YYABORT; - ; - break;} -case 59: -#line 586 "./sql.y" -{ - yyval.expr = EXPR_ival( info, &yyvsp[0].str, -1 ); - if( !yyval.expr ) - YYABORT; - ; - break;} -case 60: -#line 592 "./sql.y" -{ - yyval.expr = EXPR_sval( info, &yyvsp[0].str ); - if( !yyval.expr ) - YYABORT; - ; - break;} -case 61: -#line 598 "./sql.y" -{ - yyval.expr = EXPR_wildcard( info ); - if( !yyval.expr ) - YYABORT; - ; - break;} -case 62: -#line 607 "./sql.y" -{ - yyval.expr = EXPR_column( info, yyvsp[0].string ); - if( !yyval.expr ) - YYABORT; - ; - break;} -case 63: -#line 616 "./sql.y" -{ - yyval.string = yyvsp[0].string; /* FIXME */ - ; - break;} -case 64: -#line 620 "./sql.y" -{ - yyval.string = yyvsp[0].string; - ; - break;} -case 65: -#line 627 "./sql.y" -{ - yyval.string = yyvsp[0].string; - ; - break;} -case 66: -#line 634 "./sql.y" -{ - yyval.string = SQL_getstring( info, &yyvsp[0].str ); - if( !yyval.string ) - YYABORT; - ; - break;} -} - -#line 705 "/usr/share/bison/bison.simple" - - - yyvsp -= yylen; - yyssp -= yylen; -#if YYLSP_NEEDED - yylsp -= yylen; -#endif - -#if YYDEBUG - if (yydebug) - { - short *yyssp1 = yyss - 1; - YYFPRINTF (stderr, "state stack now"); - while (yyssp1 != yyssp) - YYFPRINTF (stderr, " %d", *++yyssp1); - YYFPRINTF (stderr, "\n"); - } -#endif - - *++yyvsp = yyval; -#if YYLSP_NEEDED - *++yylsp = yyloc; -#endif - - /* Now `shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTBASE] + *yyssp; - if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTBASE]; - - goto yynewstate; - - -/*------------------------------------. -| yyerrlab -- here on detecting error | -`------------------------------------*/ -yyerrlab: - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; - -#ifdef YYERROR_VERBOSE - yyn = yypact[yystate]; - - if (yyn > YYFLAG && yyn < YYLAST) - { - YYSIZE_T yysize = 0; - char *yymsg; - int yyx, yycount; - - yycount = 0; - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. */ - for (yyx = yyn < 0 ? -yyn : 0; - yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) - if (yycheck[yyx + yyn] == yyx) - yysize += yystrlen (yytname[yyx]) + 15, yycount++; - yysize += yystrlen ("parse error, unexpected ") + 1; - yysize += yystrlen (yytname[YYTRANSLATE (yychar)]); - yymsg = (char *) YYSTACK_ALLOC (yysize); - if (yymsg != 0) - { - char *yyp = yystpcpy (yymsg, "parse error, unexpected "); - yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]); - - if (yycount < 5) - { - yycount = 0; - for (yyx = yyn < 0 ? -yyn : 0; - yyx < (int) (sizeof (yytname) / sizeof (char *)); - yyx++) - if (yycheck[yyx + yyn] == yyx) - { - const char *yyq = ! yycount ? ", expecting " : " or "; - yyp = yystpcpy (yyp, yyq); - yyp = yystpcpy (yyp, yytname[yyx]); - yycount++; - } - } - yyerror (yymsg); - YYSTACK_FREE (yymsg); - } - else - yyerror ("parse error; also virtual memory exhausted"); - } - else -#endif /* defined (YYERROR_VERBOSE) */ - yyerror ("parse error"); - } - goto yyerrlab1; - - -/*--------------------------------------------------. -| yyerrlab1 -- error raised explicitly by an action | -`--------------------------------------------------*/ -yyerrlab1: - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse lookahead token after an - error, discard it. */ - - /* return failure if at end of input */ - if (yychar == YYEOF) - YYABORT; - YYDPRINTF ((stderr, "Discarding token %d (%s).\n", - yychar, yytname[yychar1])); - yychar = YYEMPTY; - } - - /* Else will try to reuse lookahead token after shifting the error - token. */ - - yyerrstatus = 3; /* Each real token shifted decrements this */ - - goto yyerrhandle; - - -/*-------------------------------------------------------------------. -| yyerrdefault -- current state does not do anything special for the | -| error token. | -`-------------------------------------------------------------------*/ -yyerrdefault: -#if 0 - /* This is wrong; only states that explicitly want error tokens - should shift them. */ - - /* If its default is to accept any token, ok. Otherwise pop it. */ - yyn = yydefact[yystate]; - if (yyn) - goto yydefault; -#endif - - -/*---------------------------------------------------------------. -| yyerrpop -- pop the current state because it cannot handle the | -| error token | -`---------------------------------------------------------------*/ -yyerrpop: - if (yyssp == yyss) - YYABORT; - yyvsp--; - yystate = *--yyssp; -#if YYLSP_NEEDED - yylsp--; -#endif - -#if YYDEBUG - if (yydebug) - { - short *yyssp1 = yyss - 1; - YYFPRINTF (stderr, "Error: state stack now"); - while (yyssp1 != yyssp) - YYFPRINTF (stderr, " %d", *++yyssp1); - YYFPRINTF (stderr, "\n"); - } -#endif - -/*--------------. -| yyerrhandle. | -`--------------*/ -yyerrhandle: - yyn = yypact[yystate]; - if (yyn == YYFLAG) - goto yyerrdefault; - - yyn += YYTERROR; - if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) - goto yyerrdefault; - - yyn = yytable[yyn]; - if (yyn < 0) - { - if (yyn == YYFLAG) - goto yyerrpop; - yyn = -yyn; - goto yyreduce; - } - else if (yyn == 0) - goto yyerrpop; - - if (yyn == YYFINAL) - YYACCEPT; - - YYDPRINTF ((stderr, "Shifting error token, ")); - - *++yyvsp = yylval; -#if YYLSP_NEEDED - *++yylsp = yylloc; -#endif - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - -/*---------------------------------------------. -| yyoverflowab -- parser overflow comes here. | -`---------------------------------------------*/ -yyoverflowlab: - yyerror ("parser stack overflow"); - yyresult = 2; - /* Fall through. */ - -yyreturn: -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif - return yyresult; -} -#line 641 "./sql.y" - - -static void *parser_alloc( void *info, unsigned int sz ) -{ - SQL_input* sql = (SQL_input*) info; - struct list *mem; - - mem = HeapAlloc( GetProcessHeap(), 0, sizeof (struct list) + sz ); - list_add_tail( sql->mem, mem ); - return &mem[1]; -} - -int SQL_lex( void *SQL_lval, SQL_input *sql ) -{ - int token; - struct sql_str * str = SQL_lval; - - do - { - sql->n += sql->len; - if( ! sql->command[sql->n] ) - return 0; /* end of input */ - - TRACE("string : %s\n", debugstr_w(&sql->command[sql->n])); - sql->len = sqliteGetToken( &sql->command[sql->n], &token ); - if( sql->len==0 ) - break; - str->data = &sql->command[sql->n]; - str->len = sql->len; - } - while( token == TK_SPACE ); - - TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len)); - - return token; -} - -LPWSTR SQL_getstring( void *info, struct sql_str *strdata ) -{ - LPCWSTR p = strdata->data; - UINT len = strdata->len; - LPWSTR str; - - /* if there's quotes, remove them */ - if( ( (p[0]=='`') && (p[len-1]=='`') ) || - ( (p[0]=='\'') && (p[len-1]=='\'') ) ) - { - p++; - len -= 2; - } - str = parser_alloc( info, (len + 1)*sizeof(WCHAR) ); - if( !str ) - return str; - memcpy( str, p, len*sizeof(WCHAR) ); - str[len]=0; - - return str; -} - -INT SQL_getint( void *info ) -{ - SQL_input* sql = (SQL_input*) info; - LPCWSTR p = &sql->command[sql->n]; - - return atoiW( p ); -} - -int SQL_error( const char *str ) -{ - return 0; -} - -static struct expr * EXPR_wildcard( void *info ) -{ - struct expr *e = parser_alloc( info, sizeof *e ); - if( e ) - { - e->type = EXPR_WILDCARD; - } - return e; -} - -static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r ) -{ - struct expr *e = parser_alloc( info, sizeof *e ); - if( e ) - { - e->type = EXPR_COMPLEX; - e->u.expr.left = l; - e->u.expr.op = op; - e->u.expr.right = r; - } - return e; -} - -static struct expr * EXPR_column( void *info, LPWSTR column ) -{ - struct expr *e = parser_alloc( info, sizeof *e ); - if( e ) - { - e->type = EXPR_COLUMN; - e->u.sval = column; - } - return e; -} - -static struct expr * EXPR_ival( void *info, struct sql_str *str, int sign ) -{ - struct expr *e = parser_alloc( info, sizeof *e ); - if( e ) - { - e->type = EXPR_IVAL; - e->u.ival = atoiW( str->data ) * sign; - } - return e; -} - -static struct expr * EXPR_sval( void *info, struct sql_str *str ) -{ - struct expr *e = parser_alloc( info, sizeof *e ); - if( e ) - { - e->type = EXPR_SVAL; - e->u.sval = SQL_getstring( info, str ); - } - return e; -} - -static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys) -{ - string_list *k; - BOOL found = TRUE; - - for( k = keys; k && found; k = k->next ) - { - create_col_info *c; - - found = FALSE; - for( c = cols; c && !found; c = c->next ) - { - if( lstrcmpW( k->string, c->colname ) ) - continue; - c->type |= MSITYPE_KEY; - found = TRUE; - } - } - - return found; -} - -UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview, - struct list *mem ) -{ - SQL_input sql; - int r; - - *phview = NULL; - - sql.db = db; - sql.command = command; - sql.n = 0; - sql.len = 0; - sql.view = phview; - sql.mem = mem; - - r = SQL_parse(&sql); - - TRACE("Parse returned %d\n", r); - if( r ) - { - if( *sql.view ) - (*sql.view)->ops->delete( *sql.view ); - *sql.view = NULL; - return ERROR_BAD_QUERY_SYNTAX; - } - - return ERROR_SUCCESS; -} +/* A Bison parser, made from ./sql.y + by GNU bison 1.35. */ + +#define YYBISON 1 /* Identify Bison output. */ + +#define yyparse SQL_parse +#define yylex SQL_lex +#define yyerror SQL_error +#define yylval SQL_lval +#define yychar SQL_char +#define yydebug SQL_debug +#define yynerrs SQL_nerrs +# define TK_ABORT 257 +# define TK_AFTER 258 +# define TK_AGG_FUNCTION 259 +# define TK_ALL 260 +# define TK_AND 261 +# define TK_AS 262 +# define TK_ASC 263 +# define TK_BEFORE 264 +# define TK_BEGIN 265 +# define TK_BETWEEN 266 +# define TK_BITAND 267 +# define TK_BITNOT 268 +# define TK_BITOR 269 +# define TK_BY 270 +# define TK_CASCADE 271 +# define TK_CASE 272 +# define TK_CHAR 273 +# define TK_CHECK 274 +# define TK_CLUSTER 275 +# define TK_COLLATE 276 +# define TK_COLUMN 277 +# define TK_COMMA 278 +# define TK_COMMENT 279 +# define TK_COMMIT 280 +# define TK_CONCAT 281 +# define TK_CONFLICT 282 +# define TK_CONSTRAINT 283 +# define TK_COPY 284 +# define TK_CREATE 285 +# define TK_DEFAULT 286 +# define TK_DEFERRABLE 287 +# define TK_DEFERRED 288 +# define TK_DELETE 289 +# define TK_DELIMITERS 290 +# define TK_DESC 291 +# define TK_DISTINCT 292 +# define TK_DOT 293 +# define TK_DROP 294 +# define TK_EACH 295 +# define TK_ELSE 296 +# define TK_END 297 +# define TK_END_OF_FILE 298 +# define TK_EQ 299 +# define TK_EXCEPT 300 +# define TK_EXPLAIN 301 +# define TK_FAIL 302 +# define TK_FLOAT 303 +# define TK_FOR 304 +# define TK_FOREIGN 305 +# define TK_FROM 306 +# define TK_FUNCTION 307 +# define TK_GE 308 +# define TK_GLOB 309 +# define TK_GROUP 310 +# define TK_GT 311 +# define TK_HAVING 312 +# define TK_HOLD 313 +# define TK_IGNORE 314 +# define TK_ILLEGAL 315 +# define TK_IMMEDIATE 316 +# define TK_IN 317 +# define TK_INDEX 318 +# define TK_INITIALLY 319 +# define TK_ID 320 +# define TK_INSERT 321 +# define TK_INSTEAD 322 +# define TK_INT 323 +# define TK_INTEGER 324 +# define TK_INTERSECT 325 +# define TK_INTO 326 +# define TK_IS 327 +# define TK_ISNULL 328 +# define TK_JOIN 329 +# define TK_JOIN_KW 330 +# define TK_KEY 331 +# define TK_LE 332 +# define TK_LIKE 333 +# define TK_LIMIT 334 +# define TK_LONG 335 +# define TK_LONGCHAR 336 +# define TK_LP 337 +# define TK_LSHIFT 338 +# define TK_LT 339 +# define TK_LOCALIZABLE 340 +# define TK_MATCH 341 +# define TK_MINUS 342 +# define TK_NE 343 +# define TK_NOT 344 +# define TK_NOTNULL 345 +# define TK_NULL 346 +# define TK_OBJECT 347 +# define TK_OF 348 +# define TK_OFFSET 349 +# define TK_ON 350 +# define TK_OR 351 +# define TK_ORACLE_OUTER_JOIN 352 +# define TK_ORDER 353 +# define TK_PLUS 354 +# define TK_PRAGMA 355 +# define TK_PRIMARY 356 +# define TK_RAISE 357 +# define TK_REFERENCES 358 +# define TK_REM 359 +# define TK_REPLACE 360 +# define TK_RESTRICT 361 +# define TK_ROLLBACK 362 +# define TK_ROW 363 +# define TK_RP 364 +# define TK_RSHIFT 365 +# define TK_SELECT 366 +# define TK_SEMI 367 +# define TK_SET 368 +# define TK_SHORT 369 +# define TK_SLASH 370 +# define TK_SPACE 371 +# define TK_STAR 372 +# define TK_STATEMENT 373 +# define TK_STRING 374 +# define TK_TABLE 375 +# define TK_TEMP 376 +# define TK_THEN 377 +# define TK_TRANSACTION 378 +# define TK_TRIGGER 379 +# define TK_UMINUS 380 +# define TK_UNCLOSED_STRING 381 +# define TK_UNION 382 +# define TK_UNIQUE 383 +# define TK_UPDATE 384 +# define TK_UPLUS 385 +# define TK_USING 386 +# define TK_VACUUM 387 +# define TK_VALUES 388 +# define TK_VIEW 389 +# define TK_WHEN 390 +# define TK_WHERE 391 +# define TK_WILDCARD 392 +# define END_OF_FILE 393 +# define ILLEGAL 394 +# define SPACE 395 +# define UNCLOSED_STRING 396 +# define COMMENT 397 +# define FUNCTION 398 +# define COLUMN 399 + +#line 1 "./sql.y" + + +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2002-2004 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "config.h" + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> + +#include "windef.h" +#include "winbase.h" +#include "query.h" +#include "wine/list.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +#define YYLEX_PARAM info +#define YYPARSE_PARAM info + +extern int SQL_error(const char *str); + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +typedef struct tag_SQL_input +{ + MSIDATABASE *db; + LPCWSTR command; + DWORD n, len; + MSIVIEW **view; /* view structure for the resulting query */ + struct list *mem; +} SQL_input; + +static LPWSTR SQL_getstring( void *info, struct sql_str *str ); +static INT SQL_getint( void *info ); +static int SQL_lex( void *SQL_lval, SQL_input *info ); + +static void *parser_alloc( void *info, unsigned int sz ); + +static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys); + +static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r ); +static struct expr * EXPR_column( void *info, LPWSTR column ); +static struct expr * EXPR_ival( void *info, struct sql_str *, int sign ); +static struct expr * EXPR_sval( void *info, struct sql_str * ); +static struct expr * EXPR_wildcard( void *info ); + + +#line 71 "./sql.y" +#ifndef YYSTYPE +typedef union +{ + struct sql_str str; + LPWSTR string; + string_list *column_list; + value_list *val_list; + MSIVIEW *query; + struct expr *expr; + USHORT column_type; + create_col_info *column_info; + column_assignment update_col_info; +} yystype; +# define YYSTYPE yystype +# define YYSTYPE_IS_TRIVIAL 1 +#endif +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + + + +#define YYFINAL 126 +#define YYFLAG -32768 +#define YYNTBASE 147 + +/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */ +#define YYTRANSLATE(x) ((unsigned)(x) <= 400 ? yytranslate[x] : 175) + +/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */ +static const short yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, + 146 +}; + +#if YYDEBUG +static const short yyprhs[] = +{ + 0, 0, 2, 4, 6, 8, 10, 12, 23, 35, + 42, 50, 57, 60, 65, 70, 73, 75, 78, 80, + 84, 86, 91, 93, 95, 97, 99, 101, 103, 108, + 110, 113, 117, 120, 122, 126, 128, 130, 134, 137, + 141, 145, 149, 153, 157, 161, 165, 169, 173, 177, + 181, 186, 188, 190, 192, 196, 198, 202, 206, 208, + 211, 213, 215, 217, 221, 223, 225 +}; +static const short yyrhs[] = +{ + 148, 0, 159, 0, 150, 0, 149, 0, 151, 0, + 152, 0, 67, 72, 173, 83, 162, 110, 134, 83, + 167, 110, 0, 67, 72, 173, 83, 162, 110, 134, + 83, 167, 110, 122, 0, 31, 121, 173, 83, 153, + 110, 0, 31, 121, 173, 83, 153, 110, 59, 0, + 130, 173, 114, 168, 137, 165, 0, 35, 163, 0, + 154, 102, 77, 162, 0, 154, 24, 172, 155, 0, + 172, 155, 0, 156, 0, 156, 86, 0, 157, 0, + 157, 90, 92, 0, 19, 0, 19, 83, 158, 110, + 0, 82, 0, 115, 0, 69, 0, 81, 0, 93, + 0, 70, 0, 160, 99, 16, 162, 0, 160, 0, + 112, 161, 0, 112, 38, 161, 0, 162, 163, 0, + 172, 0, 172, 24, 162, 0, 118, 0, 164, 0, + 164, 137, 165, 0, 52, 173, 0, 83, 165, 110, + 0, 171, 45, 171, 0, 165, 7, 165, 0, 165, + 97, 165, 0, 171, 45, 166, 0, 171, 57, 166, + 0, 171, 85, 166, 0, 171, 78, 166, 0, 171, + 54, 166, 0, 171, 89, 166, 0, 171, 73, 92, + 0, 171, 73, 90, 92, 0, 171, 0, 170, 0, + 170, 0, 170, 24, 167, 0, 169, 0, 169, 24, + 168, 0, 172, 45, 170, 0, 70, 0, 88, 70, + 0, 120, 0, 138, 0, 172, 0, 173, 39, 174, + 0, 174, 0, 174, 0, 66, 0 +}; + +#endif + +#if YYDEBUG +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const short yyrline[] = +{ + 0, 140, 148, 150, 151, 152, 153, 156, 168, 180, + 193, 207, 220, 233, 243, 263, 274, 279, 286, 291, + 297, 302, 306, 310, 314, 318, 322, 328, 339, 352, + 355, 360, 371, 387, 401, 414, 420, 422, 434, 447, + 454, 460, 466, 472, 478, 484, 490, 496, 502, 508, + 514, 522, 524, 527, 539, 552, 554, 562, 578, 585, + 591, 597, 605, 614, 619, 625, 632 +}; +#endif + + +#if (YYDEBUG) || defined YYERROR_VERBOSE + +/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */ +static const char *const yytname[] = +{ + "$", "error", "$undefined.", "TK_ABORT", "TK_AFTER", "TK_AGG_FUNCTION", + "TK_ALL", "TK_AND", "TK_AS", "TK_ASC", "TK_BEFORE", "TK_BEGIN", + "TK_BETWEEN", "TK_BITAND", "TK_BITNOT", "TK_BITOR", "TK_BY", + "TK_CASCADE", "TK_CASE", "TK_CHAR", "TK_CHECK", "TK_CLUSTER", + "TK_COLLATE", "TK_COLUMN", "TK_COMMA", "TK_COMMENT", "TK_COMMIT", + "TK_CONCAT", "TK_CONFLICT", "TK_CONSTRAINT", "TK_COPY", "TK_CREATE", + "TK_DEFAULT", "TK_DEFERRABLE", "TK_DEFERRED", "TK_DELETE", + "TK_DELIMITERS", "TK_DESC", "TK_DISTINCT", "TK_DOT", "TK_DROP", + "TK_EACH", "TK_ELSE", "TK_END", "TK_END_OF_FILE", "TK_EQ", "TK_EXCEPT", + "TK_EXPLAIN", "TK_FAIL", "TK_FLOAT", "TK_FOR", "TK_FOREIGN", "TK_FROM", + "TK_FUNCTION", "TK_GE", "TK_GLOB", "TK_GROUP", "TK_GT", "TK_HAVING", + "TK_HOLD", "TK_IGNORE", "TK_ILLEGAL", "TK_IMMEDIATE", "TK_IN", + "TK_INDEX", "TK_INITIALLY", "TK_ID", "TK_INSERT", "TK_INSTEAD", + "TK_INT", "TK_INTEGER", "TK_INTERSECT", "TK_INTO", "TK_IS", "TK_ISNULL", + "TK_JOIN", "TK_JOIN_KW", "TK_KEY", "TK_LE", "TK_LIKE", "TK_LIMIT", + "TK_LONG", "TK_LONGCHAR", "TK_LP", "TK_LSHIFT", "TK_LT", + "TK_LOCALIZABLE", "TK_MATCH", "TK_MINUS", "TK_NE", "TK_NOT", + "TK_NOTNULL", "TK_NULL", "TK_OBJECT", "TK_OF", "TK_OFFSET", "TK_ON", + "TK_OR", "TK_ORACLE_OUTER_JOIN", "TK_ORDER", "TK_PLUS", "TK_PRAGMA", + "TK_PRIMARY", "TK_RAISE", "TK_REFERENCES", "TK_REM", "TK_REPLACE", + "TK_RESTRICT", "TK_ROLLBACK", "TK_ROW", "TK_RP", "TK_RSHIFT", + "TK_SELECT", "TK_SEMI", "TK_SET", "TK_SHORT", "TK_SLASH", "TK_SPACE", + "TK_STAR", "TK_STATEMENT", "TK_STRING", "TK_TABLE", "TK_TEMP", + "TK_THEN", "TK_TRANSACTION", "TK_TRIGGER", "TK_UMINUS", + "TK_UNCLOSED_STRING", "TK_UNION", "TK_UNIQUE", "TK_UPDATE", "TK_UPLUS", + "TK_USING", "TK_VACUUM", "TK_VALUES", "TK_VIEW", "TK_WHEN", "TK_WHERE", + "TK_WILDCARD", "END_OF_FILE", "ILLEGAL", "SPACE", "UNCLOSED_STRING", + "COMMENT", "FUNCTION", "COLUMN", "AGG_FUNCTION.", "query", "onequery", + "oneinsert", "onecreate", "oneupdate", "onedelete", "table_def", + "column_def", "column_type", "data_type_l", "data_type", "data_count", + "oneselect", "unorderedsel", "selectfrom", "selcollist", "from", + "fromtable", "expr", "val", "constlist", "update_assign_list", + "column_assignment", "const_val", "column_val", "column", "table", "id", 0 +}; +#endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const short yyr1[] = +{ + 0, 147, 148, 148, 148, 148, 148, 149, 149, 150, + 150, 151, 152, 153, 154, 154, 155, 155, 156, 156, + 157, 157, 157, 157, 157, 157, 157, 158, 159, 159, + 160, 160, 161, 162, 162, 162, 163, 163, 164, 165, + 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, + 165, 166, 166, 167, 167, 168, 168, 169, 170, 170, + 170, 170, 171, 172, 172, 173, 174 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const short yyr2[] = +{ + 0, 1, 1, 1, 1, 1, 1, 10, 11, 6, + 7, 6, 2, 4, 4, 2, 1, 2, 1, 3, + 1, 4, 1, 1, 1, 1, 1, 1, 4, 1, + 2, 3, 2, 1, 3, 1, 1, 3, 2, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 1, 1, 1, 3, 1, 3, 3, 1, 2, + 1, 1, 1, 3, 1, 1, 1 +}; + +/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE + doesn't specify something else to do. Zero means the default is an + error. */ +static const short yydefact[] = +{ + 0, 0, 0, 0, 0, 0, 1, 4, 3, 5, + 6, 2, 29, 0, 0, 12, 36, 0, 0, 66, + 35, 30, 0, 33, 0, 64, 0, 65, 0, 0, + 38, 0, 0, 31, 32, 0, 0, 0, 0, 0, + 0, 37, 0, 62, 0, 34, 63, 0, 55, 0, + 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, + 0, 20, 24, 25, 22, 26, 23, 15, 16, 18, + 39, 41, 42, 58, 0, 60, 61, 43, 52, 40, + 47, 51, 44, 0, 49, 46, 45, 48, 0, 11, + 56, 57, 10, 0, 0, 0, 17, 0, 59, 50, + 0, 14, 13, 27, 0, 19, 0, 21, 0, 53, + 7, 0, 8, 54, 0, 0, 0 +}; + +static const short yydefgoto[] = +{ + 124, 6, 7, 8, 9, 10, 51, 52, 77, 78, + 79, 114, 11, 12, 21, 22, 15, 16, 41, 87, + 118, 47, 48, 88, 42, 43, 24, 25 +}; + +static const short yypact[] = +{ + -28, -102, -32, -48, -29, -39,-32768,-32768,-32768,-32768, + -32768,-32768, -61, -39, -39,-32768, -97, -39, -50,-32768, + -32768,-32768, -32, 19, 6, 9, -65,-32768, 34, -30, + -32768, -37, -26,-32768,-32768, -50, -39, -39, -50, -39, + -37, -2, -31,-32768, -50,-32768,-32768, -86, 32, 10, + -32768, -51, -20, -17, -7, -37, -37, -60, -60, -60, + -59, -60, -60, -60, -36, -37, -39, -58, 16, -39, + 2, 0,-32768,-32768,-32768,-32768,-32768,-32768, -5, 1, + -32768, -2, -2,-32768, 15,-32768,-32768,-32768,-32768,-32768, + -32768,-32768,-32768, -4,-32768,-32768,-32768,-32768, -42, -2, + -32768,-32768,-32768, -17, -50, 23,-32768, 5,-32768,-32768, + 11,-32768,-32768,-32768, -11,-32768, -58,-32768, -10, 83, + -9, -58,-32768,-32768, 117, 118,-32768 +}; + +static const short yypgoto[] = +{ + -32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 17,-32768, + -32768,-32768,-32768,-32768, 101, -27, 99,-32768, 31, 53, + 3, 57,-32768, -49, 47, -3, 56, 8 +}; + + +#define YYLAST 124 + + +static const short yytable[] = +{ + 55, 23, 71, 1, 69, 55, 19, 2, 45, 18, + 83, 50, 83, 27, 57, 23, 19, 64, 101, 13, + 14, 27, 27, 58, 17, 27, 59, 19, 84, 19, + 84, 93, 23, 94, 49, 23, 53, 19, 28, 3, + 31, 23, 60, 35, 46, 36, 40, 61, -65, 37, + 38, 65, 72, 39, 62, 67, 66, 44, 63, 68, + 85, 26, 85, 49, 73, 74, 103, 119, 20, 29, + 30, 54, 119, 32, 98, 102, 75, 112, 86, 104, + 86, 106, 70, 105, 4, 108, 81, 82, 109, 20, + 56, 107, 110, 113, 116, 56, 99, 115, 76, 117, + 120, 23, 5, 80, 89, 91, 91, 121, 91, 91, + 91, 90, 92, 122, 95, 96, 97, 125, 126, 33, + 111, 34, 0, 100, 123 +}; + +static const short yycheck[] = +{ + 7, 4, 19, 31, 24, 7, 66, 35, 35, 38, + 70, 38, 70, 5, 45, 18, 66, 44, 67, 121, + 52, 13, 14, 54, 72, 17, 57, 66, 88, 66, + 88, 90, 35, 92, 37, 38, 39, 66, 99, 67, + 137, 44, 73, 24, 36, 39, 83, 78, 39, 114, + 16, 137, 69, 83, 85, 45, 24, 83, 89, 110, + 120, 5, 120, 66, 81, 82, 69, 116, 118, 13, + 14, 40, 121, 17, 110, 59, 93, 104, 138, 77, + 138, 86, 102, 83, 112, 70, 55, 56, 92, 118, + 97, 90, 134, 70, 83, 97, 65, 92, 115, 110, + 110, 104, 130, 110, 57, 58, 59, 24, 61, 62, + 63, 58, 59, 122, 61, 62, 63, 0, 0, 18, + 103, 22, -1, 66, 121 +}; +#define YYPURE 1 + +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/usr/share/bison/bison.simple" + +/* Skeleton output parser for bison, + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software + Foundation, Inc. + + 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, 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* This is the parser code that is written into each bison parser when + the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +#if ! defined (yyoverflow) || defined (YYERROR_VERBOSE) + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# if YYSTACK_USE_ALLOCA +# define YYSTACK_ALLOC alloca +# else +# ifndef YYSTACK_USE_ALLOCA +# if defined (alloca) || defined (_ALLOCA_H) +# define YYSTACK_ALLOC alloca +# else +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# else +# if defined (__STDC__) || defined (__cplusplus) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +# define YYSTACK_ALLOC malloc +# define YYSTACK_FREE free +# endif +#endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */ + + +#if (! defined (yyoverflow) \ + && (! defined (__cplusplus) \ + || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + short yyss; + YYSTYPE yyvs; +# if YYLSP_NEEDED + YYLTYPE yyls; +# endif +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# if YYLSP_NEEDED +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAX) +# else +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAX) +# endif + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + register YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (0) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAX; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + + +#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) +# define YYSIZE_T __SIZE_TYPE__ +#endif +#if ! defined (YYSIZE_T) && defined (size_t) +# define YYSIZE_T size_t +#endif +#if ! defined (YYSIZE_T) +# if defined (__STDC__) || defined (__cplusplus) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +#endif +#if ! defined (YYSIZE_T) +# define YYSIZE_T unsigned int +#endif + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrlab1 +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto yyerrlab +#define YYRECOVERING() (!!yyerrstatus) +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror ("syntax error: cannot back up"); \ + YYERROR; \ + } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Compute the default location (before the actions + are run). + + When YYLLOC_DEFAULT is run, CURRENT is set the location of the + first token. By default, to implement support for ranges, extend + its range to the last symbol. */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + Current.last_line = Rhs[N].last_line; \ + Current.last_column = Rhs[N].last_column; +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#if YYPURE +# if YYLSP_NEEDED +# ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) +# else +# define YYLEX yylex (&yylval, &yylloc) +# endif +# else /* !YYLSP_NEEDED */ +# ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, YYLEX_PARAM) +# else +# define YYLEX yylex (&yylval) +# endif +# endif /* !YYLSP_NEEDED */ +#else /* !YYPURE */ +# define YYLEX yylex () +#endif /* !YYPURE */ + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +#endif /* !YYDEBUG */ + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#if YYMAXDEPTH == 0 +# undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + +#ifdef YYERROR_VERBOSE + +# ifndef yystrlen +# if defined (__GLIBC__) && defined (_STRING_H) +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +# if defined (__STDC__) || defined (__cplusplus) +yystrlen (const char *yystr) +# else +yystrlen (yystr) + const char *yystr; +# endif +{ + register const char *yys = yystr; + + while (*yys++ != '\0') + continue; + + return yys - yystr - 1; +} +# endif +# endif + +# ifndef yystpcpy +# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +# if defined (__STDC__) || defined (__cplusplus) +yystpcpy (char *yydest, const char *yysrc) +# else +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +# endif +{ + register char *yyd = yydest; + register const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif +#endif + +#line 315 "/usr/share/bison/bison.simple" + + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +# define YYPARSE_PARAM_ARG void *YYPARSE_PARAM +# define YYPARSE_PARAM_DECL +# else +# define YYPARSE_PARAM_ARG YYPARSE_PARAM +# define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +# endif +#else /* !YYPARSE_PARAM */ +# define YYPARSE_PARAM_ARG +# define YYPARSE_PARAM_DECL +#endif /* !YYPARSE_PARAM */ + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +# ifdef YYPARSE_PARAM +int yyparse (void *); +# else +int yyparse (void); +# endif +#endif + +/* YY_DECL_VARIABLES -- depending whether we use a pure parser, + variables are global, or local to YYPARSE. */ + +#define YY_DECL_NON_LSP_VARIABLES \ +/* The lookahead symbol. */ \ +int yychar; \ + \ +/* The semantic value of the lookahead symbol. */ \ +YYSTYPE yylval; \ + \ +/* Number of parse errors so far. */ \ +int yynerrs; + +#if YYLSP_NEEDED +# define YY_DECL_VARIABLES \ +YY_DECL_NON_LSP_VARIABLES \ + \ +/* Location data for the lookahead symbol. */ \ +YYLTYPE yylloc; +#else +# define YY_DECL_VARIABLES \ +YY_DECL_NON_LSP_VARIABLES +#endif + + +/* If nonreentrant, generate the variables here. */ + +#if !YYPURE +YY_DECL_VARIABLES +#endif /* !YYPURE */ + +int +yyparse (YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + /* If reentrant, generate the variables here. */ +#if YYPURE + YY_DECL_VARIABLES +#endif /* !YYPURE */ + + register int yystate; + register int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Lookahead token as an internal (translated) token number. */ + int yychar1 = 0; + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + short yyssa[YYINITDEPTH]; + short *yyss = yyssa; + register short *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + register YYSTYPE *yyvsp; + +#if YYLSP_NEEDED + /* The location stack. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; +#endif + +#if YYLSP_NEEDED +# define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +# define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + YYSIZE_T yystacksize = YYINITDEPTH; + + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; +#if YYLSP_NEEDED + YYLTYPE yyloc; +#endif + + /* When reducing, the number of symbols on the RHS of the reduced + rule. */ + int yylen; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; +#if YYLSP_NEEDED + yylsp = yyls; +#endif + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. + */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. */ +# if YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yyls1, yysize * sizeof (*yylsp), + &yystacksize); + yyls = yyls1; +# else + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); +# endif + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyoverflowlab; +# else + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + goto yyoverflowlab; + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; + + { + short *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyoverflowlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); +# if YYLSP_NEEDED + YYSTACK_RELOCATE (yyls); +# endif +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; +#if YYLSP_NEEDED + yylsp = yyls + yysize - 1; +#endif + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yychar1 = YYTRANSLATE (yychar); + +#if YYDEBUG + /* We have to keep this `#if YYDEBUG', since we use variables + which are defined only if `YYDEBUG' is set. */ + if (yydebug) + { + YYFPRINTF (stderr, "Next token is %d (%s", + yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise + meaning of a token, for further debugging info. */ +# ifdef YYPRINT + YYPRINT (stderr, yychar, yylval); +# endif + YYFPRINTF (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + YYDPRINTF ((stderr, "Shifting token %d (%s), ", + yychar, yytname[yychar1])); + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#if YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + yystate = yyn; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to the semantic value of + the lookahead token. This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + +#if YYLSP_NEEDED + /* Similarly for the default location. Let the user run additional + commands if for instance locations are ranges. */ + yyloc = yylsp[1-yylen]; + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); +#endif + +#if YYDEBUG + /* We have to keep this `#if YYDEBUG', since we use variables which + are defined only if `YYDEBUG' is set. */ + if (yydebug) + { + int yyi; + + YYFPRINTF (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++) + YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]); + YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + switch (yyn) { + +case 1: +#line 142 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + *sql->view = yyvsp[0].query; + ; + break;} +case 7: +#line 158 "./sql.y" +{ + SQL_input *sql = (SQL_input*) info; + MSIVIEW *insert = NULL; + UINT r; + + r = INSERT_CreateView( sql->db, &insert, yyvsp[-7].string, yyvsp[-5].column_list, yyvsp[-1].val_list, FALSE ); + if( !insert ) + YYABORT; + yyval.query = insert; + ; + break;} +case 8: +#line 169 "./sql.y" +{ + SQL_input *sql = (SQL_input*) info; + MSIVIEW *insert = NULL; + + INSERT_CreateView( sql->db, &insert, yyvsp[-8].string, yyvsp[-6].column_list, yyvsp[-2].val_list, TRUE ); + if( !insert ) + YYABORT; + yyval.query = insert; + ; + break;} +case 9: +#line 182 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + MSIVIEW *create = NULL; + + if( !yyvsp[-1].column_info ) + YYABORT; + CREATE_CreateView( sql->db, &create, yyvsp[-3].string, yyvsp[-1].column_info, FALSE ); + if( !create ) + YYABORT; + yyval.query = create; + ; + break;} +case 10: +#line 194 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + MSIVIEW *create = NULL; + + if( !yyvsp[-2].column_info ) + YYABORT; + CREATE_CreateView( sql->db, &create, yyvsp[-4].string, yyvsp[-2].column_info, TRUE ); + if( !create ) + YYABORT; + yyval.query = create; + ; + break;} +case 11: +#line 209 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + MSIVIEW *update = NULL; + + UPDATE_CreateView( sql->db, &update, yyvsp[-4].string, &yyvsp[-2].update_col_info, yyvsp[0].expr ); + if( !update ) + YYABORT; + yyval.query = update; + ; + break;} +case 12: +#line 222 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + MSIVIEW *delete = NULL; + + DELETE_CreateView( sql->db, &delete, yyvsp[0].query ); + if( !delete ) + YYABORT; + yyval.query = delete; + ; + break;} +case 13: +#line 235 "./sql.y" +{ + if( SQL_MarkPrimaryKeys( yyvsp[-3].column_info, yyvsp[0].column_list ) ) + yyval.column_info = yyvsp[-3].column_info; + else + yyval.column_info = NULL; + ; + break;} +case 14: +#line 245 "./sql.y" +{ + create_col_info *ci; + + for( ci = yyvsp[-3].column_info; ci->next; ci = ci->next ) + ; + + ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info ); + if( !ci->next ) + { + /* FIXME: free $1 */ + YYABORT; + } + ci->next->colname = yyvsp[-1].string; + ci->next->type = yyvsp[0].column_type; + ci->next->next = NULL; + + yyval.column_info = yyvsp[-3].column_info; + ; + break;} +case 15: +#line 264 "./sql.y" +{ + yyval.column_info = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.column_info ); + if( ! yyval.column_info ) + YYABORT; + yyval.column_info->colname = yyvsp[-1].string; + yyval.column_info->type = yyvsp[0].column_type; + yyval.column_info->next = NULL; + ; + break;} +case 16: +#line 276 "./sql.y" +{ + yyval.column_type = yyvsp[0].column_type | MSITYPE_VALID; + ; + break;} +case 17: +#line 280 "./sql.y" +{ + FIXME("LOCALIZABLE ignored\n"); + yyval.column_type = yyvsp[-1].column_type | MSITYPE_VALID; + ; + break;} +case 18: +#line 288 "./sql.y" +{ + yyval.column_type |= MSITYPE_NULLABLE; + ; + break;} +case 19: +#line 292 "./sql.y" +{ + yyval.column_type = yyvsp[-2].column_type; + ; + break;} +case 20: +#line 299 "./sql.y" +{ + yyval.column_type = MSITYPE_STRING | 1; + ; + break;} +case 21: +#line 303 "./sql.y" +{ + yyval.column_type = MSITYPE_STRING | 0x400 | yyvsp[-1].column_type; + ; + break;} +case 22: +#line 307 "./sql.y" +{ + yyval.column_type = 2; + ; + break;} +case 23: +#line 311 "./sql.y" +{ + yyval.column_type = 2; + ; + break;} +case 24: +#line 315 "./sql.y" +{ + yyval.column_type = 2; + ; + break;} +case 25: +#line 319 "./sql.y" +{ + yyval.column_type = 4; + ; + break;} +case 26: +#line 323 "./sql.y" +{ + yyval.column_type = 0; + ; + break;} +case 27: +#line 330 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + int val = SQL_getint(sql); + if( ( val > 255 ) || ( val < 0 ) ) + YYABORT; + yyval.column_type = val; + ; + break;} +case 28: +#line 341 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + + yyval.query = NULL; + if( yyvsp[0].column_list ) + ORDER_CreateView( sql->db, &yyval.query, yyvsp[-3].query, yyvsp[0].column_list ); + else + yyval.query = yyvsp[-3].query; + if( !yyval.query ) + YYABORT; + ; + break;} +case 30: +#line 357 "./sql.y" +{ + yyval.query = yyvsp[0].query; + ; + break;} +case 31: +#line 361 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + + yyval.query = NULL; + DISTINCT_CreateView( sql->db, &yyval.query, yyvsp[0].query ); + if( !yyval.query ) + YYABORT; + ; + break;} +case 32: +#line 373 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + + yyval.query = NULL; + if( yyvsp[-1].column_list ) + SELECT_CreateView( sql->db, &yyval.query, yyvsp[0].query, yyvsp[-1].column_list ); + else + yyval.query = yyvsp[0].query; + + if( !yyval.query ) + YYABORT; + ; + break;} +case 33: +#line 389 "./sql.y" +{ + string_list *list; + + list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); + if( !list ) + YYABORT; + list->string = yyvsp[0].string; + list->next = NULL; + + yyval.column_list = list; + TRACE("Collist %s\n",debugstr_w(yyval.column_list->string)); + ; + break;} +case 34: +#line 402 "./sql.y" +{ + string_list *list; + + list = HeapAlloc( GetProcessHeap(), 0, sizeof *list ); + if( !list ) + YYABORT; + list->string = yyvsp[-2].string; + list->next = yyvsp[0].column_list; + + yyval.column_list = list; + TRACE("From table: %s\n",debugstr_w(yyval.column_list->string)); + ; + break;} +case 35: +#line 415 "./sql.y" +{ + yyval.column_list = NULL; + ; + break;} +case 37: +#line 423 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + UINT r; + + yyval.query = NULL; + r = WHERE_CreateView( sql->db, &yyval.query, yyvsp[-2].query, yyvsp[0].expr ); + if( r != ERROR_SUCCESS || !yyval.query ) + YYABORT; + ; + break;} +case 38: +#line 436 "./sql.y" +{ + SQL_input* sql = (SQL_input*) info; + UINT r; + + yyval.query = NULL; + r = TABLE_CreateView( sql->db, yyvsp[0].string, &yyval.query ); + if( r != ERROR_SUCCESS || !yyval.query ) + YYABORT; + ; + break;} +case 39: +#line 449 "./sql.y" +{ + yyval.expr = yyvsp[-1].expr; + if( !yyval.expr ) + YYABORT; + ; + break;} +case 40: +#line 455 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_EQ, yyvsp[0].expr ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 41: +#line 461 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_AND, yyvsp[0].expr ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 42: +#line 467 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_OR, yyvsp[0].expr ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 43: +#line 473 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_EQ, yyvsp[0].expr ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 44: +#line 479 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_GT, yyvsp[0].expr ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 45: +#line 485 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_LT, yyvsp[0].expr ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 46: +#line 491 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_LE, yyvsp[0].expr ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 47: +#line 497 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_GE, yyvsp[0].expr ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 48: +#line 503 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_NE, yyvsp[0].expr ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 49: +#line 509 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-2].expr, OP_ISNULL, NULL ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 50: +#line 515 "./sql.y" +{ + yyval.expr = EXPR_complex( info, yyvsp[-3].expr, OP_NOTNULL, NULL ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 53: +#line 529 "./sql.y" +{ + value_list *vals; + + vals = parser_alloc( info, sizeof *vals ); + if( !vals ) + YYABORT; + vals->val = yyvsp[0].expr; + vals->next = NULL; + yyval.val_list = vals; + ; + break;} +case 54: +#line 540 "./sql.y" +{ + value_list *vals; + + vals = parser_alloc( info, sizeof *vals ); + if( !vals ) + YYABORT; + vals->val = yyvsp[-2].expr; + vals->next = yyvsp[0].val_list; + yyval.val_list = vals; + ; + break;} +case 56: +#line 555 "./sql.y" +{ + yyvsp[-2].update_col_info.col_list->next = yyvsp[0].update_col_info.col_list; + yyvsp[-2].update_col_info.val_list->next = yyvsp[0].update_col_info.val_list; + yyval.update_col_info = yyvsp[-2].update_col_info; + ; + break;} +case 57: +#line 564 "./sql.y" +{ + yyval.update_col_info.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.col_list ); + if( !yyval.update_col_info.col_list ) + YYABORT; + yyval.update_col_info.col_list->string = yyvsp[-2].string; + yyval.update_col_info.col_list->next = NULL; + yyval.update_col_info.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *yyval.update_col_info.val_list ); + if( !yyval.update_col_info.val_list ) + YYABORT; + yyval.update_col_info.val_list->val = yyvsp[0].expr; + yyval.update_col_info.val_list->next = 0; + ; + break;} +case 58: +#line 580 "./sql.y" +{ + yyval.expr = EXPR_ival( info, &yyvsp[0].str, 1 ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 59: +#line 586 "./sql.y" +{ + yyval.expr = EXPR_ival( info, &yyvsp[0].str, -1 ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 60: +#line 592 "./sql.y" +{ + yyval.expr = EXPR_sval( info, &yyvsp[0].str ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 61: +#line 598 "./sql.y" +{ + yyval.expr = EXPR_wildcard( info ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 62: +#line 607 "./sql.y" +{ + yyval.expr = EXPR_column( info, yyvsp[0].string ); + if( !yyval.expr ) + YYABORT; + ; + break;} +case 63: +#line 616 "./sql.y" +{ + yyval.string = yyvsp[0].string; /* FIXME */ + ; + break;} +case 64: +#line 620 "./sql.y" +{ + yyval.string = yyvsp[0].string; + ; + break;} +case 65: +#line 627 "./sql.y" +{ + yyval.string = yyvsp[0].string; + ; + break;} +case 66: +#line 634 "./sql.y" +{ + yyval.string = SQL_getstring( info, &yyvsp[0].str ); + if( !yyval.string ) + YYABORT; + ; + break;} +} + +#line 705 "/usr/share/bison/bison.simple" + + + yyvsp -= yylen; + yyssp -= yylen; +#if YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG + if (yydebug) + { + short *yyssp1 = yyss - 1; + YYFPRINTF (stderr, "state stack now"); + while (yyssp1 != yyssp) + YYFPRINTF (stderr, " %d", *++yyssp1); + YYFPRINTF (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; +#if YYLSP_NEEDED + *++yylsp = yyloc; +#endif + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + YYSIZE_T yysize = 0; + char *yymsg; + int yyx, yycount; + + yycount = 0; + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) + if (yycheck[yyx + yyn] == yyx) + yysize += yystrlen (yytname[yyx]) + 15, yycount++; + yysize += yystrlen ("parse error, unexpected ") + 1; + yysize += yystrlen (yytname[YYTRANSLATE (yychar)]); + yymsg = (char *) YYSTACK_ALLOC (yysize); + if (yymsg != 0) + { + char *yyp = yystpcpy (yymsg, "parse error, unexpected "); + yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]); + + if (yycount < 5) + { + yycount = 0; + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); + yyx++) + if (yycheck[yyx + yyn] == yyx) + { + const char *yyq = ! yycount ? ", expecting " : " or "; + yyp = yystpcpy (yyp, yyq); + yyp = yystpcpy (yyp, yytname[yyx]); + yycount++; + } + } + yyerror (yymsg); + YYSTACK_FREE (yymsg); + } + else + yyerror ("parse error; also virtual memory exhausted"); + } + else +#endif /* defined (YYERROR_VERBOSE) */ + yyerror ("parse error"); + } + goto yyerrlab1; + + +/*--------------------------------------------------. +| yyerrlab1 -- error raised explicitly by an action | +`--------------------------------------------------*/ +yyerrlab1: + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + YYDPRINTF ((stderr, "Discarding token %d (%s).\n", + yychar, yytname[yychar1])); + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + + +/*-------------------------------------------------------------------. +| yyerrdefault -- current state does not do anything special for the | +| error token. | +`-------------------------------------------------------------------*/ +yyerrdefault: +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + + /* If its default is to accept any token, ok. Otherwise pop it. */ + yyn = yydefact[yystate]; + if (yyn) + goto yydefault; +#endif + + +/*---------------------------------------------------------------. +| yyerrpop -- pop the current state because it cannot handle the | +| error token | +`---------------------------------------------------------------*/ +yyerrpop: + if (yyssp == yyss) + YYABORT; + yyvsp--; + yystate = *--yyssp; +#if YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG + if (yydebug) + { + short *yyssp1 = yyss - 1; + YYFPRINTF (stderr, "Error: state stack now"); + while (yyssp1 != yyssp) + YYFPRINTF (stderr, " %d", *++yyssp1); + YYFPRINTF (stderr, "\n"); + } +#endif + +/*--------------. +| yyerrhandle. | +`--------------*/ +yyerrhandle: + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + + YYDPRINTF ((stderr, "Shifting error token, ")); + + *++yyvsp = yylval; +#if YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +/*---------------------------------------------. +| yyoverflowab -- parser overflow comes here. | +`---------------------------------------------*/ +yyoverflowlab: + yyerror ("parser stack overflow"); + yyresult = 2; + /* Fall through. */ + +yyreturn: +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + return yyresult; +} +#line 641 "./sql.y" + + +static void *parser_alloc( void *info, unsigned int sz ) +{ + SQL_input* sql = (SQL_input*) info; + struct list *mem; + + mem = HeapAlloc( GetProcessHeap(), 0, sizeof (struct list) + sz ); + list_add_tail( sql->mem, mem ); + return &mem[1]; +} + +int SQL_lex( void *SQL_lval, SQL_input *sql ) +{ + int token; + struct sql_str * str = SQL_lval; + + do + { + sql->n += sql->len; + if( ! sql->command[sql->n] ) + return 0; /* end of input */ + + TRACE("string : %s\n", debugstr_w(&sql->command[sql->n])); + sql->len = sqliteGetToken( &sql->command[sql->n], &token ); + if( sql->len==0 ) + break; + str->data = &sql->command[sql->n]; + str->len = sql->len; + } + while( token == TK_SPACE ); + + TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len)); + + return token; +} + +LPWSTR SQL_getstring( void *info, struct sql_str *strdata ) +{ + LPCWSTR p = strdata->data; + UINT len = strdata->len; + LPWSTR str; + + /* if there's quotes, remove them */ + if( ( (p[0]=='`') && (p[len-1]=='`') ) || + ( (p[0]=='\'') && (p[len-1]=='\'') ) ) + { + p++; + len -= 2; + } + str = parser_alloc( info, (len + 1)*sizeof(WCHAR) ); + if( !str ) + return str; + memcpy( str, p, len*sizeof(WCHAR) ); + str[len]=0; + + return str; +} + +INT SQL_getint( void *info ) +{ + SQL_input* sql = (SQL_input*) info; + LPCWSTR p = &sql->command[sql->n]; + + return atoiW( p ); +} + +int SQL_error( const char *str ) +{ + return 0; +} + +static struct expr * EXPR_wildcard( void *info ) +{ + struct expr *e = parser_alloc( info, sizeof *e ); + if( e ) + { + e->type = EXPR_WILDCARD; + } + return e; +} + +static struct expr * EXPR_complex( void *info, struct expr *l, UINT op, struct expr *r ) +{ + struct expr *e = parser_alloc( info, sizeof *e ); + if( e ) + { + e->type = EXPR_COMPLEX; + e->u.expr.left = l; + e->u.expr.op = op; + e->u.expr.right = r; + } + return e; +} + +static struct expr * EXPR_column( void *info, LPWSTR column ) +{ + struct expr *e = parser_alloc( info, sizeof *e ); + if( e ) + { + e->type = EXPR_COLUMN; + e->u.sval = column; + } + return e; +} + +static struct expr * EXPR_ival( void *info, struct sql_str *str, int sign ) +{ + struct expr *e = parser_alloc( info, sizeof *e ); + if( e ) + { + e->type = EXPR_IVAL; + e->u.ival = atoiW( str->data ) * sign; + } + return e; +} + +static struct expr * EXPR_sval( void *info, struct sql_str *str ) +{ + struct expr *e = parser_alloc( info, sizeof *e ); + if( e ) + { + e->type = EXPR_SVAL; + e->u.sval = SQL_getstring( info, str ); + } + return e; +} + +static BOOL SQL_MarkPrimaryKeys( create_col_info *cols, string_list *keys) +{ + string_list *k; + BOOL found = TRUE; + + for( k = keys; k && found; k = k->next ) + { + create_col_info *c; + + found = FALSE; + for( c = cols; c && !found; c = c->next ) + { + if( lstrcmpW( k->string, c->colname ) ) + continue; + c->type |= MSITYPE_KEY; + found = TRUE; + } + } + + return found; +} + +UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview, + struct list *mem ) +{ + SQL_input sql; + int r; + + *phview = NULL; + + sql.db = db; + sql.command = command; + sql.n = 0; + sql.len = 0; + sql.view = phview; + sql.mem = mem; + + r = SQL_parse(&sql); + + TRACE("Parse returned %d\n", r); + if( r ) + { + if( *sql.view ) + (*sql.view)->ops->delete( *sql.view ); + *sql.view = NULL; + return ERROR_BAD_QUERY_SYNTAX; + } + + return ERROR_SUCCESS; +} diff --git a/reactos/lib/msi/string.c b/reactos/lib/msi/string.c index cf59b04b028..4222894c58a 100644 --- a/reactos/lib/msi/string.c +++ b/reactos/lib/msi/string.c @@ -1,458 +1,458 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2002-2004, Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> -#include <assert.h> - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "wine/debug.h" -#include "wine/unicode.h" -#include "msi.h" -#include "msiquery.h" -#include "objbase.h" -#include "objidl.h" -#include "msipriv.h" -#include "winnls.h" - -#include "query.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -typedef struct _msistring -{ - UINT hash; - UINT refcount; - LPWSTR str; -} msistring; - -struct string_table -{ - UINT maxcount; /* the number of strings */ - UINT freeslot; - UINT codepage; - msistring *strings; /* an array of strings (in the tree) */ -}; - -static UINT msistring_makehash( const WCHAR *str ) -{ - UINT hash = 0; - - if (str==NULL) - return hash; - - while( *str ) - { - hash ^= *str++; - hash *= 53; - hash = (hash<<5) | (hash>>27); - } - return hash; -} - -string_table *msi_init_stringtable( int entries, UINT codepage ) -{ - string_table *st; - - st = HeapAlloc( GetProcessHeap(), 0, sizeof (string_table) ); - if( !st ) - return NULL; - st->strings = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof (msistring) * entries ); - if( !st ) - { - HeapFree( GetProcessHeap(), 0, st ); - return NULL; - } - if( entries < 1 ) - entries = 1; - st->maxcount = entries; - st->freeslot = 1; - st->codepage = codepage; - - return st; -} - -VOID msi_destroy_stringtable( string_table *st ) -{ - UINT i; - - for( i=0; i<st->maxcount; i++ ) - { - if( st->strings[i].refcount ) - HeapFree( GetProcessHeap(), 0, st->strings[i].str ); - } - HeapFree( GetProcessHeap(), 0, st->strings ); - HeapFree( GetProcessHeap(), 0, st ); -} - -static int st_find_free_entry( string_table *st ) -{ - UINT i, sz; - msistring *p; - - TRACE("%p\n", st); - - if( st->freeslot ) - { - for( i = st->freeslot; i < st->maxcount; i++ ) - if( !st->strings[i].refcount ) - return i; - } - for( i = 1; i < st->maxcount; i++ ) - if( !st->strings[i].refcount ) - return i; - - /* dynamically resize */ - sz = st->maxcount + 1 + st->maxcount/2; - p = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - st->strings, sz*sizeof(msistring) ); - if( !p ) - return -1; - st->strings = p; - st->freeslot = st->maxcount; - st->maxcount = sz; - if( st->strings[st->freeslot].refcount ) - ERR("oops. expected freeslot to be free...\n"); - return st->freeslot; -} - -static void st_mark_entry_used( string_table *st, UINT n ) -{ - if( n >= st->maxcount ) - return; - st->freeslot = n + 1; -} - -int msi_addstring( string_table *st, int n, const CHAR *data, int len, UINT refcount ) -{ - int sz; - - if( !data ) - return 0; - if( !data[0] ) - return 0; - if( n > 0 ) - { - if( st->strings[n].refcount ) - return -1; - } - else - { - if( ERROR_SUCCESS == msi_string2idA( st, data, &n ) ) - { - st->strings[n].refcount++; - return n; - } - n = st_find_free_entry( st ); - if( n < 0 ) - return -1; - } - - if( n < 1 ) - { - ERR("invalid index adding %s (%d)\n", debugstr_a( data ), n ); - return -1; - } - - /* allocate a new string */ - if( len < 0 ) - len = strlen(data); - sz = MultiByteToWideChar( st->codepage, 0, data, len, NULL, 0 ); - st->strings[n].str = HeapAlloc( GetProcessHeap(), 0, (sz+1)*sizeof(WCHAR) ); - if( !st->strings[n].str ) - return -1; - MultiByteToWideChar( st->codepage, 0, data, len, st->strings[n].str, sz ); - st->strings[n].str[sz] = 0; - st->strings[n].refcount = 1; - st->strings[n].hash = msistring_makehash( st->strings[n].str ); - - st_mark_entry_used( st, n ); - - return n; -} - -int msi_addstringW( string_table *st, int n, const WCHAR *data, int len, UINT refcount ) -{ - /* TRACE("[%2d] = %s\n", string_no, debugstr_an(data,len) ); */ - - if( !data ) - return 0; - if( !data[0] ) - return 0; - if( n > 0 ) - { - if( st->strings[n].refcount ) - return -1; - } - else - { - if( ERROR_SUCCESS == msi_string2idW( st, data, &n ) ) - { - st->strings[n].refcount++; - return n; - } - n = st_find_free_entry( st ); - if( n < 0 ) - return -1; - } - - if( n < 1 ) - { - ERR("invalid index adding %s (%d)\n", debugstr_w( data ), n ); - return -1; - } - - /* allocate a new string */ - if(len<0) - len = strlenW(data); - TRACE("%s, n = %d len = %d\n", debugstr_w(data), n, len ); - - st->strings[n].str = HeapAlloc( GetProcessHeap(), 0, (len+1)*sizeof(WCHAR) ); - if( !st->strings[n].str ) - return -1; - TRACE("%d\n",__LINE__); - memcpy( st->strings[n].str, data, len*sizeof(WCHAR) ); - st->strings[n].str[len] = 0; - st->strings[n].refcount = 1; - st->strings[n].hash = msistring_makehash( st->strings[n].str ); - - st_mark_entry_used( st, n ); - - return n; -} - -/* find the string identified by an id - return null if there's none */ -const WCHAR *msi_string_lookup_id( string_table *st, UINT id ) -{ - static const WCHAR zero[] = { 0 }; - if( id == 0 ) - return zero; - - if( id >= st->maxcount ) - return NULL; - - if( id && !st->strings[id].refcount ) - return NULL; - - return st->strings[id].str; -} - -/* - * msi_id2stringW - * - * [in] st - pointer to the string table - * [in] id - id of the string to retrieve - * [out] buffer - destination of the string - * [in/out] sz - number of bytes available in the buffer on input - * number of bytes used on output - * - * The size includes the terminating nul character. Short buffers - * will be filled, but not nul terminated. - */ -UINT msi_id2stringW( string_table *st, UINT id, LPWSTR buffer, UINT *sz ) -{ - UINT len; - const WCHAR *str; - - TRACE("Finding string %d of %d\n", id, st->maxcount); - - str = msi_string_lookup_id( st, id ); - if( !str ) - return ERROR_FUNCTION_FAILED; - - len = strlenW( str ) + 1; - - if( !buffer ) - { - *sz = len; - return ERROR_SUCCESS; - } - - if( *sz < len ) - *sz = len; - memcpy( buffer, str, (*sz)*sizeof(WCHAR) ); - *sz = len; - - return ERROR_SUCCESS; -} - -/* - * msi_id2stringA - * - * [in] st - pointer to the string table - * [in] id - id of the string to retrieve - * [out] buffer - destination of the UTF8 string - * [in/out] sz - number of bytes available in the buffer on input - * number of bytes used on output - * - * The size includes the terminating nul character. Short buffers - * will be filled, but not nul terminated. - */ -UINT msi_id2stringA( string_table *st, UINT id, LPSTR buffer, UINT *sz ) -{ - UINT len; - const WCHAR *str; - int n; - - TRACE("Finding string %d of %d\n", id, st->maxcount); - - str = msi_string_lookup_id( st, id ); - if( !str ) - return ERROR_FUNCTION_FAILED; - - len = WideCharToMultiByte( st->codepage, 0, str, -1, NULL, 0, NULL, NULL ); - - if( !buffer ) - { - *sz = len; - return ERROR_SUCCESS; - } - - if( len > *sz ) - { - n = strlenW( str ) + 1; - while( n && (len > *sz) ) - len = WideCharToMultiByte( st->codepage, 0, - str, --n, NULL, 0, NULL, NULL ); - } - else - n = -1; - - *sz = WideCharToMultiByte( st->codepage, 0, str, n, buffer, len, NULL, NULL ); - - return ERROR_SUCCESS; -} - -/* - * msi_string2idW - * - * [in] st - pointer to the string table - * [in] str - string to find in the string table - * [out] id - id of the string, if found - */ -UINT msi_string2idW( string_table *st, LPCWSTR str, UINT *id ) -{ - UINT hash; - UINT i, r = ERROR_INVALID_PARAMETER; - - hash = msistring_makehash( str ); - for( i=0; i<st->maxcount; i++ ) - { - if ( (str == NULL && st->strings[i].str == NULL) || - ( ( st->strings[i].hash == hash ) && - !strcmpW( st->strings[i].str, str ) )) - { - r = ERROR_SUCCESS; - *id = i; - break; - } - } - - return r; -} - -UINT msi_string2idA( string_table *st, LPCSTR buffer, UINT *id ) -{ - DWORD sz; - UINT r = ERROR_INVALID_PARAMETER; - LPWSTR str; - - TRACE("Finding string %s in string table\n", debugstr_a(buffer) ); - - if( buffer[0] == 0 ) - { - *id = 0; - return ERROR_SUCCESS; - } - - sz = MultiByteToWideChar( st->codepage, 0, buffer, -1, NULL, 0 ); - if( sz <= 0 ) - return r; - str = HeapAlloc( GetProcessHeap(), 0, sz*sizeof(WCHAR) ); - if( !str ) - return ERROR_NOT_ENOUGH_MEMORY; - MultiByteToWideChar( st->codepage, 0, buffer, -1, str, sz ); - - r = msi_string2idW( st, str, id ); - HeapFree( GetProcessHeap(), 0, str ); - - return r; -} - -UINT msi_strcmp( string_table *st, UINT lval, UINT rval, UINT *res ) -{ - const WCHAR *l_str, *r_str; - - l_str = msi_string_lookup_id( st, lval ); - if( !l_str ) - return ERROR_INVALID_PARAMETER; - - r_str = msi_string_lookup_id( st, rval ); - if( !r_str ) - return ERROR_INVALID_PARAMETER; - - /* does this do the right thing for all UTF-8 strings? */ - *res = strcmpW( l_str, r_str ); - - return ERROR_SUCCESS; -} - -UINT msi_string_count( string_table *st ) -{ - return st->maxcount; -} - -UINT msi_id_refcount( string_table *st, UINT i ) -{ - if( i >= st->maxcount ) - return 0; - return st->strings[i].refcount; -} - -UINT msi_string_totalsize( string_table *st, UINT *total ) -{ - UINT size = 0, i, len; - - if( st->strings[0].str || st->strings[0].refcount ) - ERR("oops. element 0 has a string\n"); - *total = 0; - for( i=1; i<st->maxcount; i++ ) - { - if( st->strings[i].str ) - { - TRACE("[%u] = %s\n", i, debugstr_w(st->strings[i].str)); - len = WideCharToMultiByte( st->codepage, 0, - st->strings[i].str, -1, NULL, 0, NULL, NULL); - if( len ) - len--; - size += len; - *total = (i+1); - } - } - TRACE("%u/%u strings %u bytes codepage %x\n", *total, st->maxcount, size, st->codepage ); - return size; -} - -UINT msi_string_get_codepage( string_table *st ) -{ - return st->codepage; -} +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2002-2004, Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> +#include <assert.h> + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/debug.h" +#include "wine/unicode.h" +#include "msi.h" +#include "msiquery.h" +#include "objbase.h" +#include "objidl.h" +#include "msipriv.h" +#include "winnls.h" + +#include "query.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +typedef struct _msistring +{ + UINT hash; + UINT refcount; + LPWSTR str; +} msistring; + +struct string_table +{ + UINT maxcount; /* the number of strings */ + UINT freeslot; + UINT codepage; + msistring *strings; /* an array of strings (in the tree) */ +}; + +static UINT msistring_makehash( const WCHAR *str ) +{ + UINT hash = 0; + + if (str==NULL) + return hash; + + while( *str ) + { + hash ^= *str++; + hash *= 53; + hash = (hash<<5) | (hash>>27); + } + return hash; +} + +string_table *msi_init_stringtable( int entries, UINT codepage ) +{ + string_table *st; + + st = HeapAlloc( GetProcessHeap(), 0, sizeof (string_table) ); + if( !st ) + return NULL; + st->strings = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof (msistring) * entries ); + if( !st ) + { + HeapFree( GetProcessHeap(), 0, st ); + return NULL; + } + if( entries < 1 ) + entries = 1; + st->maxcount = entries; + st->freeslot = 1; + st->codepage = codepage; + + return st; +} + +VOID msi_destroy_stringtable( string_table *st ) +{ + UINT i; + + for( i=0; i<st->maxcount; i++ ) + { + if( st->strings[i].refcount ) + HeapFree( GetProcessHeap(), 0, st->strings[i].str ); + } + HeapFree( GetProcessHeap(), 0, st->strings ); + HeapFree( GetProcessHeap(), 0, st ); +} + +static int st_find_free_entry( string_table *st ) +{ + UINT i, sz; + msistring *p; + + TRACE("%p\n", st); + + if( st->freeslot ) + { + for( i = st->freeslot; i < st->maxcount; i++ ) + if( !st->strings[i].refcount ) + return i; + } + for( i = 1; i < st->maxcount; i++ ) + if( !st->strings[i].refcount ) + return i; + + /* dynamically resize */ + sz = st->maxcount + 1 + st->maxcount/2; + p = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + st->strings, sz*sizeof(msistring) ); + if( !p ) + return -1; + st->strings = p; + st->freeslot = st->maxcount; + st->maxcount = sz; + if( st->strings[st->freeslot].refcount ) + ERR("oops. expected freeslot to be free...\n"); + return st->freeslot; +} + +static void st_mark_entry_used( string_table *st, UINT n ) +{ + if( n >= st->maxcount ) + return; + st->freeslot = n + 1; +} + +int msi_addstring( string_table *st, int n, const CHAR *data, int len, UINT refcount ) +{ + int sz; + + if( !data ) + return 0; + if( !data[0] ) + return 0; + if( n > 0 ) + { + if( st->strings[n].refcount ) + return -1; + } + else + { + if( ERROR_SUCCESS == msi_string2idA( st, data, &n ) ) + { + st->strings[n].refcount++; + return n; + } + n = st_find_free_entry( st ); + if( n < 0 ) + return -1; + } + + if( n < 1 ) + { + ERR("invalid index adding %s (%d)\n", debugstr_a( data ), n ); + return -1; + } + + /* allocate a new string */ + if( len < 0 ) + len = strlen(data); + sz = MultiByteToWideChar( st->codepage, 0, data, len, NULL, 0 ); + st->strings[n].str = HeapAlloc( GetProcessHeap(), 0, (sz+1)*sizeof(WCHAR) ); + if( !st->strings[n].str ) + return -1; + MultiByteToWideChar( st->codepage, 0, data, len, st->strings[n].str, sz ); + st->strings[n].str[sz] = 0; + st->strings[n].refcount = 1; + st->strings[n].hash = msistring_makehash( st->strings[n].str ); + + st_mark_entry_used( st, n ); + + return n; +} + +int msi_addstringW( string_table *st, int n, const WCHAR *data, int len, UINT refcount ) +{ + /* TRACE("[%2d] = %s\n", string_no, debugstr_an(data,len) ); */ + + if( !data ) + return 0; + if( !data[0] ) + return 0; + if( n > 0 ) + { + if( st->strings[n].refcount ) + return -1; + } + else + { + if( ERROR_SUCCESS == msi_string2idW( st, data, &n ) ) + { + st->strings[n].refcount++; + return n; + } + n = st_find_free_entry( st ); + if( n < 0 ) + return -1; + } + + if( n < 1 ) + { + ERR("invalid index adding %s (%d)\n", debugstr_w( data ), n ); + return -1; + } + + /* allocate a new string */ + if(len<0) + len = strlenW(data); + TRACE("%s, n = %d len = %d\n", debugstr_w(data), n, len ); + + st->strings[n].str = HeapAlloc( GetProcessHeap(), 0, (len+1)*sizeof(WCHAR) ); + if( !st->strings[n].str ) + return -1; + TRACE("%d\n",__LINE__); + memcpy( st->strings[n].str, data, len*sizeof(WCHAR) ); + st->strings[n].str[len] = 0; + st->strings[n].refcount = 1; + st->strings[n].hash = msistring_makehash( st->strings[n].str ); + + st_mark_entry_used( st, n ); + + return n; +} + +/* find the string identified by an id - return null if there's none */ +const WCHAR *msi_string_lookup_id( string_table *st, UINT id ) +{ + static const WCHAR zero[] = { 0 }; + if( id == 0 ) + return zero; + + if( id >= st->maxcount ) + return NULL; + + if( id && !st->strings[id].refcount ) + return NULL; + + return st->strings[id].str; +} + +/* + * msi_id2stringW + * + * [in] st - pointer to the string table + * [in] id - id of the string to retrieve + * [out] buffer - destination of the string + * [in/out] sz - number of bytes available in the buffer on input + * number of bytes used on output + * + * The size includes the terminating nul character. Short buffers + * will be filled, but not nul terminated. + */ +UINT msi_id2stringW( string_table *st, UINT id, LPWSTR buffer, UINT *sz ) +{ + UINT len; + const WCHAR *str; + + TRACE("Finding string %d of %d\n", id, st->maxcount); + + str = msi_string_lookup_id( st, id ); + if( !str ) + return ERROR_FUNCTION_FAILED; + + len = strlenW( str ) + 1; + + if( !buffer ) + { + *sz = len; + return ERROR_SUCCESS; + } + + if( *sz < len ) + *sz = len; + memcpy( buffer, str, (*sz)*sizeof(WCHAR) ); + *sz = len; + + return ERROR_SUCCESS; +} + +/* + * msi_id2stringA + * + * [in] st - pointer to the string table + * [in] id - id of the string to retrieve + * [out] buffer - destination of the UTF8 string + * [in/out] sz - number of bytes available in the buffer on input + * number of bytes used on output + * + * The size includes the terminating nul character. Short buffers + * will be filled, but not nul terminated. + */ +UINT msi_id2stringA( string_table *st, UINT id, LPSTR buffer, UINT *sz ) +{ + UINT len; + const WCHAR *str; + int n; + + TRACE("Finding string %d of %d\n", id, st->maxcount); + + str = msi_string_lookup_id( st, id ); + if( !str ) + return ERROR_FUNCTION_FAILED; + + len = WideCharToMultiByte( st->codepage, 0, str, -1, NULL, 0, NULL, NULL ); + + if( !buffer ) + { + *sz = len; + return ERROR_SUCCESS; + } + + if( len > *sz ) + { + n = strlenW( str ) + 1; + while( n && (len > *sz) ) + len = WideCharToMultiByte( st->codepage, 0, + str, --n, NULL, 0, NULL, NULL ); + } + else + n = -1; + + *sz = WideCharToMultiByte( st->codepage, 0, str, n, buffer, len, NULL, NULL ); + + return ERROR_SUCCESS; +} + +/* + * msi_string2idW + * + * [in] st - pointer to the string table + * [in] str - string to find in the string table + * [out] id - id of the string, if found + */ +UINT msi_string2idW( string_table *st, LPCWSTR str, UINT *id ) +{ + UINT hash; + UINT i, r = ERROR_INVALID_PARAMETER; + + hash = msistring_makehash( str ); + for( i=0; i<st->maxcount; i++ ) + { + if ( (str == NULL && st->strings[i].str == NULL) || + ( ( st->strings[i].hash == hash ) && + !strcmpW( st->strings[i].str, str ) )) + { + r = ERROR_SUCCESS; + *id = i; + break; + } + } + + return r; +} + +UINT msi_string2idA( string_table *st, LPCSTR buffer, UINT *id ) +{ + DWORD sz; + UINT r = ERROR_INVALID_PARAMETER; + LPWSTR str; + + TRACE("Finding string %s in string table\n", debugstr_a(buffer) ); + + if( buffer[0] == 0 ) + { + *id = 0; + return ERROR_SUCCESS; + } + + sz = MultiByteToWideChar( st->codepage, 0, buffer, -1, NULL, 0 ); + if( sz <= 0 ) + return r; + str = HeapAlloc( GetProcessHeap(), 0, sz*sizeof(WCHAR) ); + if( !str ) + return ERROR_NOT_ENOUGH_MEMORY; + MultiByteToWideChar( st->codepage, 0, buffer, -1, str, sz ); + + r = msi_string2idW( st, str, id ); + HeapFree( GetProcessHeap(), 0, str ); + + return r; +} + +UINT msi_strcmp( string_table *st, UINT lval, UINT rval, UINT *res ) +{ + const WCHAR *l_str, *r_str; + + l_str = msi_string_lookup_id( st, lval ); + if( !l_str ) + return ERROR_INVALID_PARAMETER; + + r_str = msi_string_lookup_id( st, rval ); + if( !r_str ) + return ERROR_INVALID_PARAMETER; + + /* does this do the right thing for all UTF-8 strings? */ + *res = strcmpW( l_str, r_str ); + + return ERROR_SUCCESS; +} + +UINT msi_string_count( string_table *st ) +{ + return st->maxcount; +} + +UINT msi_id_refcount( string_table *st, UINT i ) +{ + if( i >= st->maxcount ) + return 0; + return st->strings[i].refcount; +} + +UINT msi_string_totalsize( string_table *st, UINT *total ) +{ + UINT size = 0, i, len; + + if( st->strings[0].str || st->strings[0].refcount ) + ERR("oops. element 0 has a string\n"); + *total = 0; + for( i=1; i<st->maxcount; i++ ) + { + if( st->strings[i].str ) + { + TRACE("[%u] = %s\n", i, debugstr_w(st->strings[i].str)); + len = WideCharToMultiByte( st->codepage, 0, + st->strings[i].str, -1, NULL, 0, NULL, NULL); + if( len ) + len--; + size += len; + *total = (i+1); + } + } + TRACE("%u/%u strings %u bytes codepage %x\n", *total, st->maxcount, size, st->codepage ); + return size; +} + +UINT msi_string_get_codepage( string_table *st ) +{ + return st->codepage; +} diff --git a/reactos/lib/msi/suminfo.c b/reactos/lib/msi/suminfo.c index 997dacc3698..744898d3379 100644 --- a/reactos/lib/msi/suminfo.c +++ b/reactos/lib/msi/suminfo.c @@ -1,753 +1,753 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2002, 2005 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> - -#define COBJMACROS -#define NONAMELESSUNION - -#define PRSPEC_PROPID (1) - -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "winnls.h" -#include "shlwapi.h" -#include "wine/debug.h" -#include "msi.h" -#include "msiquery.h" -#include "msidefs.h" -#include "msipriv.h" -#include "objidl.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -#define MSI_MAX_PROPS 20 - -#include "pshpack1.h" - -typedef struct { - WORD wByteOrder; - WORD wFormat; - DWORD dwOSVer; - CLSID clsID; - DWORD reserved; -} PROPERTYSETHEADER; - -typedef struct { - FMTID fmtid; - DWORD dwOffset; -} FORMATIDOFFSET; - -typedef struct { - DWORD cbSection; - DWORD cProperties; -} PROPERTYSECTIONHEADER; - -typedef struct { - DWORD propid; - DWORD dwOffset; -} PROPERTYIDOFFSET; - -typedef struct { - DWORD type; - union { - INT i4; - SHORT i2; - FILETIME ft; - struct { - DWORD len; - BYTE str[1]; - } str; - } u; -} PROPERTY_DATA; - -#include "poppack.h" - -#define SECT_HDR_SIZE (sizeof(PROPERTYSECTIONHEADER)) - -typedef struct { - BOOL unicode; - union { - LPSTR a; - LPWSTR w; - } str; -} awstring; - -typedef struct tagMSISUMMARYINFO -{ - MSIOBJECTHDR hdr; - MSIDATABASE *db; - DWORD update_count; - PROPVARIANT property[MSI_MAX_PROPS]; -} MSISUMMARYINFO; - -static const WCHAR szSumInfo[] = { 5 ,'S','u','m','m','a','r','y', - 'I','n','f','o','r','m','a','t','i','o','n',0 }; - -static void free_prop( PROPVARIANT *prop ) -{ - if (prop->vt == VT_LPSTR ) - HeapFree( GetProcessHeap(), 0, prop->u.pszVal ); - prop->vt = VT_EMPTY; -} - -static void MSI_CloseSummaryInfo( MSIOBJECTHDR *arg ) -{ - MSISUMMARYINFO *si = (MSISUMMARYINFO *) arg; - DWORD i; - - for( i = 0; i < MSI_MAX_PROPS; i++ ) - free_prop( &si->property[i] ); - msiobj_release( &si->db->hdr ); -} - -static UINT get_type( UINT uiProperty ) -{ - switch( uiProperty ) - { - case PID_CODEPAGE: - return VT_I2; - - case PID_SUBJECT: - case PID_AUTHOR: - case PID_KEYWORDS: - case PID_COMMENTS: - case PID_TEMPLATE: - case PID_LASTAUTHOR: - case PID_REVNUMBER: - case PID_APPNAME: - case PID_TITLE: - return VT_LPSTR; - - case PID_LASTPRINTED: - case PID_CREATE_DTM: - case PID_LASTSAVE_DTM: - return VT_FILETIME; - - case PID_WORDCOUNT: - case PID_CHARCOUNT: - case PID_SECURITY: - case PID_PAGECOUNT: - return VT_I4; - } - return VT_EMPTY; -} - -static UINT get_property_count( PROPVARIANT *property ) -{ - UINT i, n = 0; - - if( !property ) - return n; - for( i = 0; i < MSI_MAX_PROPS; i++ ) - if( property[i].vt != VT_EMPTY ) - n++; - return n; -} - -/* FIXME: doesn't deal with endian conversion */ -static void read_properties_from_data( PROPVARIANT *prop, LPBYTE data, DWORD sz ) -{ - UINT type; - DWORD i; - int size; - PROPERTY_DATA *propdata; - PROPVARIANT *property; - PROPERTYIDOFFSET *idofs; - PROPERTYSECTIONHEADER *section_hdr; - - section_hdr = (PROPERTYSECTIONHEADER*) &data[0]; - idofs = (PROPERTYIDOFFSET*) &data[SECT_HDR_SIZE]; - - /* now set all the properties */ - for( i = 0; i < section_hdr->cProperties; i++ ) - { - type = get_type( idofs[i].propid ); - if( type == VT_EMPTY ) - { - ERR("propid %ld has unknown type\n", idofs[i].propid); - break; - } - - propdata = (PROPERTY_DATA*) &data[ idofs[i].dwOffset ]; - - /* check the type is the same as we expect */ - if( type != propdata->type ) - { - ERR("wrong type %d != %ld\n", type, propdata->type); - break; - } - - /* check we don't run off the end of the data */ - size = sz - idofs[i].dwOffset - sizeof(DWORD); - if( sizeof(DWORD) > size || - ( type == VT_FILETIME && sizeof(FILETIME) > size ) || - ( type == VT_LPSTR && (propdata->u.str.len + sizeof(DWORD)) > size ) ) - { - ERR("not enough data\n"); - break; - } - - if( idofs[i].propid >= MSI_MAX_PROPS ) - { - ERR("Unknown property ID %ld\n", idofs[i].propid ); - break; - } - - property = &prop[ idofs[i].propid ]; - property->vt = type; - - if( type == VT_LPSTR ) - { - LPSTR str = HeapAlloc( GetProcessHeap(), 0, propdata->u.str.len ); - memcpy( str, propdata->u.str.str, propdata->u.str.len ); - str[ propdata->u.str.len - 1 ] = 0; - property->u.pszVal = str; - } - else if( type == VT_FILETIME ) - property->u.filetime = propdata->u.ft; - else if( type == VT_I2 ) - property->u.iVal = propdata->u.i2; - else if( type == VT_I4 ) - property->u.lVal = propdata->u.i4; - } -} - -static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm ) -{ - UINT ret = ERROR_FUNCTION_FAILED; - PROPERTYSETHEADER set_hdr; - FORMATIDOFFSET format_hdr; - PROPERTYSECTIONHEADER section_hdr; - LPBYTE data = NULL; - LARGE_INTEGER ofs; - ULONG count, sz; - HRESULT r; - - TRACE("%p %p\n", si, stm); - - /* read the header */ - sz = sizeof set_hdr; - r = IStream_Read( stm, &set_hdr, sz, &count ); - if( FAILED(r) || count != sz ) - return ret; - - if( set_hdr.wByteOrder != 0xfffe ) - { - ERR("property set not big-endian %04X\n", set_hdr.wByteOrder); - return ret; - } - - sz = sizeof format_hdr; - r = IStream_Read( stm, &format_hdr, sz, &count ); - if( FAILED(r) || count != sz ) - return ret; - - /* check the format id is correct */ - if( !IsEqualGUID( &FMTID_SummaryInformation, &format_hdr.fmtid ) ) - return ret; - - /* seek to the location of the section */ - ofs.QuadPart = format_hdr.dwOffset; - r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, NULL ); - if( FAILED(r) ) - return ret; - - /* read the section itself */ - sz = SECT_HDR_SIZE; - r = IStream_Read( stm, §ion_hdr, sz, &count ); - if( FAILED(r) || count != sz ) - return ret; - - if( section_hdr.cProperties > MSI_MAX_PROPS ) - { - ERR("too many properties %ld\n", section_hdr.cProperties); - return ret; - } - - data = HeapAlloc( GetProcessHeap(), 0, section_hdr.cbSection); - if( !data ) - return ret; - - memcpy( data, §ion_hdr, SECT_HDR_SIZE ); - - /* read all the data in one go */ - sz = section_hdr.cbSection - SECT_HDR_SIZE; - r = IStream_Read( stm, &data[ SECT_HDR_SIZE ], sz, &count ); - if( SUCCEEDED(r) && count == sz ) - read_properties_from_data( si->property, data, sz + SECT_HDR_SIZE ); - else - ERR("failed to read properties %ld %ld\n", count, sz); - - HeapFree( GetProcessHeap(), 0, data ); - return ret; -} - -static DWORD write_dword( LPBYTE data, DWORD ofs, DWORD val ) -{ - if( data ) - { - data[ofs++] = val&0xff; - data[ofs++] = (val>>8)&0xff; - data[ofs++] = (val>>16)&0xff; - data[ofs++] = (val>>24)&0xff; - } - return 4; -} - -static DWORD write_filetime( LPBYTE data, DWORD ofs, LPFILETIME ft ) -{ - write_dword( data, ofs, ft->dwLowDateTime ); - write_dword( data, ofs + 4, ft->dwHighDateTime ); - return 8; -} - -static DWORD write_string( LPBYTE data, DWORD ofs, LPCSTR str ) -{ - DWORD len = lstrlenA( str ) + 1; - write_dword( data, ofs, len ); - if( data ) - lstrcpyA( &data[ofs + 4], str ); - return (7 + len) & ~3; -} - -static UINT write_property_to_data( PROPVARIANT *prop, LPBYTE data ) -{ - DWORD sz = 0; - - if( prop->vt == VT_EMPTY ) - return sz; - - /* add the type */ - sz += write_dword( data, sz, prop->vt ); - switch( prop->vt ) - { - case VT_I2: - sz += write_dword( data, sz, prop->u.iVal ); - break; - case VT_I4: - sz += write_dword( data, sz, prop->u.lVal ); - break; - case VT_FILETIME: - sz += write_filetime( data, sz, &prop->u.filetime ); - break; - case VT_LPSTR: - sz += write_string( data, sz, prop->u.pszVal ); - break; - } - return sz; -} - -static UINT save_summary_info( MSISUMMARYINFO * si, IStream *stm ) -{ - UINT ret = ERROR_FUNCTION_FAILED; - PROPERTYSETHEADER set_hdr; - FORMATIDOFFSET format_hdr; - PROPERTYSECTIONHEADER section_hdr; - PROPERTYIDOFFSET idofs[MSI_MAX_PROPS]; - LPBYTE data = NULL; - ULONG count, sz; - HRESULT r; - int i, n; - - /* write the header */ - sz = sizeof set_hdr; - memset( &set_hdr, 0, sz ); - set_hdr.wByteOrder = 0xfffe; - set_hdr.wFormat = 0; - set_hdr.dwOSVer = 0x00020005; /* build 5, platform id 2 */ - /* set_hdr.clsID is {00000000-0000-0000-0000-000000000000} */ - set_hdr.reserved = 1; - r = IStream_Write( stm, &set_hdr, sz, &count ); - if( FAILED(r) || count != sz ) - return ret; - - /* write the format header */ - sz = sizeof format_hdr; - memcpy( &format_hdr.fmtid, &FMTID_SummaryInformation, sizeof (FMTID) ); - format_hdr.dwOffset = sizeof format_hdr + sizeof set_hdr; - r = IStream_Write( stm, &format_hdr, sz, &count ); - if( FAILED(r) || count != sz ) - return ret; - - /* add up how much space the data will take and calculate the offsets */ - section_hdr.cbSection = sizeof section_hdr; - section_hdr.cbSection += (get_property_count( si->property ) * sizeof idofs[0]); - section_hdr.cProperties = 0; - n = 0; - for( i = 0; i < MSI_MAX_PROPS; i++ ) - { - sz = write_property_to_data( &si->property[i], NULL ); - if( !sz ) - continue; - idofs[ section_hdr.cProperties ].propid = i; - idofs[ section_hdr.cProperties ].dwOffset = section_hdr.cbSection; - section_hdr.cProperties++; - section_hdr.cbSection += sz; - } - - data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, section_hdr.cbSection ); - - sz = 0; - memcpy( &data[sz], §ion_hdr, sizeof section_hdr ); - sz += sizeof section_hdr; - - memcpy( &data[sz], idofs, section_hdr.cProperties * sizeof idofs[0] ); - sz += section_hdr.cProperties * sizeof idofs[0]; - - /* write out the data */ - for( i = 0; i < MSI_MAX_PROPS; i++ ) - sz += write_property_to_data( &si->property[i], &data[sz] ); - - r = IStream_Write( stm, data, sz, &count ); - HeapFree( GetProcessHeap(), 0, data ); - if( FAILED(r) || count != sz ) - return ret; - - return ERROR_SUCCESS; -} - -UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase, - LPCWSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle ) -{ - UINT ret = ERROR_SUCCESS; - IStream *stm = NULL; - MSISUMMARYINFO *si; - MSIHANDLE handle; - MSIDATABASE *db; - DWORD grfMode; - HRESULT r; - - TRACE("%ld %s %d %p\n", hDatabase, debugstr_w(szDatabase), - uiUpdateCount, pHandle); - - if( !pHandle ) - return ERROR_INVALID_PARAMETER; - - if( szDatabase ) - { - UINT res; - - res = MSI_OpenDatabaseW(szDatabase, NULL, &db); - if( res != ERROR_SUCCESS ) - return res; - } - else - { - db = msihandle2msiinfo(hDatabase, MSIHANDLETYPE_DATABASE); - if( !db ) - return ERROR_INVALID_PARAMETER; - } - - si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO, - sizeof (MSISUMMARYINFO), MSI_CloseSummaryInfo ); - if( !si ) - { - ret = ERROR_FUNCTION_FAILED; - goto end; - } - - msiobj_addref( &db->hdr ); - si->db = db; - memset( &si->property, 0, sizeof si->property ); - si->update_count = uiUpdateCount; - - /* read the stream... if we fail, we'll start with an empty property set */ - grfMode = STGM_READ | STGM_SHARE_EXCLUSIVE; - r = IStorage_OpenStream( si->db->storage, szSumInfo, 0, grfMode, 0, &stm ); - if( SUCCEEDED(r) ) - { - load_summary_info( si, stm ); - IStream_Release( stm ); - } - - handle = alloc_msihandle( &si->hdr ); - if( handle ) - *pHandle = handle; - else - ret = ERROR_FUNCTION_FAILED; - msiobj_release( &si->hdr ); - -end: - if( db ) - msiobj_release( &db->hdr ); - - return ret; -} - -UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE hDatabase, - LPCSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle) -{ - LPWSTR szwDatabase = NULL; - UINT ret; - - TRACE("%ld %s %d %p\n", hDatabase, debugstr_a(szDatabase), - uiUpdateCount, pHandle); - - if( szDatabase ) - { - szwDatabase = strdupAtoW( szDatabase ); - if( !szwDatabase ) - return ERROR_FUNCTION_FAILED; - } - - ret = MsiGetSummaryInformationW(hDatabase, szwDatabase, uiUpdateCount, pHandle); - - HeapFree( GetProcessHeap(), 0, szwDatabase ); - - return ret; -} - -UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo, UINT *pCount) -{ - MSISUMMARYINFO *si; - - TRACE("%ld %p\n",hSummaryInfo, pCount); - - si = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO ); - if( !si ) - return ERROR_INVALID_HANDLE; - - if( pCount ) - *pCount = get_property_count( si->property ); - msiobj_release( &si->hdr ); - - return ERROR_SUCCESS; -} - -static UINT get_prop( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, - INT *piValue, FILETIME *pftValue, awstring *str, DWORD *pcchValueBuf) -{ - MSISUMMARYINFO *si; - PROPVARIANT *prop; - - TRACE("%ld %d %p %p %p %p %p\n", handle, uiProperty, puiDataType, - piValue, pftValue, str, pcchValueBuf); - - si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ); - if( !si ) - return ERROR_INVALID_HANDLE; - - prop = &si->property[uiProperty]; - - if( puiDataType ) - *puiDataType = prop->vt; - - switch( prop->vt ) - { - case VT_I2: - if( piValue ) - *piValue = prop->u.iVal; - break; - case VT_I4: - if( piValue ) - *piValue = prop->u.lVal; - break; - case VT_LPSTR: - if( pcchValueBuf ) - { - DWORD len = 0; - - if( str->unicode ) - { - len = MultiByteToWideChar( CP_ACP, 0, prop->u.pszVal, -1, - str->str.w, *pcchValueBuf ); - } - else - { - len = lstrlenA( prop->u.pszVal ); - if( str->str.a ) - lstrcpynA(str->str.a, prop->u.pszVal, *pcchValueBuf ); - } - *pcchValueBuf = len; - } - break; - case VT_FILETIME: - if( pftValue ) - memcpy(pftValue, &prop->u.filetime, sizeof (FILETIME) ); - break; - case VT_EMPTY: - break; - default: - FIXME("Unknown property variant type\n"); - break; - } - msiobj_release( &si->hdr ); - return ERROR_SUCCESS; -} - -UINT WINAPI MsiSummaryInfoGetPropertyA( - MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, INT *piValue, - FILETIME *pftValue, LPSTR szValueBuf, DWORD *pcchValueBuf) -{ - awstring str; - - TRACE("%ld %d %p %p %p %p %p\n", handle, uiProperty, puiDataType, - piValue, pftValue, szValueBuf, pcchValueBuf ); - - str.unicode = FALSE; - str.str.a = szValueBuf; - - return get_prop( handle, uiProperty, puiDataType, piValue, - pftValue, &str, pcchValueBuf ); -} - -UINT WINAPI MsiSummaryInfoGetPropertyW( - MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, INT *piValue, - FILETIME *pftValue, LPWSTR szValueBuf, DWORD *pcchValueBuf) -{ - awstring str; - - TRACE("%ld %d %p %p %p %p %p\n", handle, uiProperty, puiDataType, - piValue, pftValue, szValueBuf, pcchValueBuf ); - - str.unicode = TRUE; - str.str.w = szValueBuf; - - return get_prop( handle, uiProperty, puiDataType, piValue, - pftValue, &str, pcchValueBuf ); -} - -static UINT set_prop( MSIHANDLE handle, UINT uiProperty, UINT uiDataType, - INT iValue, FILETIME* pftValue, awstring *str ) -{ - MSISUMMARYINFO *si; - PROPVARIANT *prop; - UINT type, len, ret = ERROR_SUCCESS; - - TRACE("%ld %u %u %i %p %p\n", handle, uiProperty, uiDataType, - iValue, pftValue, str ); - - type = get_type( uiProperty ); - if( type == VT_EMPTY || type != uiDataType ) - return ERROR_DATATYPE_MISMATCH; - - if( uiDataType == VT_LPSTR && !str->str.w ) - return ERROR_INVALID_PARAMETER; - - if( uiDataType == VT_FILETIME && !pftValue ) - return ERROR_INVALID_PARAMETER; - - si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ); - if( !si ) - return ERROR_INVALID_HANDLE; - - prop = &si->property[uiProperty]; - - if( prop->vt == VT_EMPTY ) - { - if( !si->update_count ) - { - ret = ERROR_FUNCTION_FAILED; - goto end; - } - si->update_count--; - } - else if( prop->vt != type ) - goto end; - - free_prop( prop ); - prop->vt = type; - switch( type ) - { - case VT_I4: - prop->u.lVal = iValue; - break; - case VT_I2: - prop->u.iVal = iValue; - break; - case VT_FILETIME: - memcpy( &prop->u.filetime, pftValue, sizeof prop->u.filetime ); - break; - case VT_LPSTR: - if( str->unicode ) - { - len = WideCharToMultiByte( CP_ACP, 0, str->str.w, -1, - NULL, 0, NULL, NULL ); - prop->u.pszVal = HeapAlloc( GetProcessHeap(), 0, len ); - WideCharToMultiByte( CP_ACP, 0, str->str.w, -1, - prop->u.pszVal, len, NULL, NULL ); - } - else - { - len = lstrlenA( str->str.a ) + 1; - prop->u.pszVal = HeapAlloc( GetProcessHeap(), 0, len ); - lstrcpyA( prop->u.pszVal, str->str.a ); - } - break; - } - -end: - msiobj_release( &si->hdr ); - return ret; -} - -UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty, - UINT uiDataType, INT iValue, FILETIME* pftValue, LPWSTR szValue ) -{ - awstring str; - - TRACE("%ld %u %u %i %p %s\n", handle, uiProperty, uiDataType, - iValue, pftValue, debugstr_w(szValue) ); - - str.unicode = TRUE; - str.str.w = szValue; - return set_prop( handle, uiProperty, uiDataType, iValue, pftValue, &str ); -} - -UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty, - UINT uiDataType, INT iValue, FILETIME* pftValue, LPSTR szValue ) -{ - awstring str; - - TRACE("%ld %u %u %i %p %s\n", handle, uiProperty, uiDataType, - iValue, pftValue, debugstr_a(szValue) ); - - str.unicode = FALSE; - str.str.a = szValue; - return set_prop( handle, uiProperty, uiDataType, iValue, pftValue, &str ); -} - -UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE handle ) -{ - IStream *stm = NULL; - MSISUMMARYINFO *si; - DWORD grfMode; - HRESULT r; - UINT ret = ERROR_FUNCTION_FAILED; - - TRACE("%ld\n", handle ); - - si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ); - if( !si ) - return ERROR_INVALID_HANDLE; - - grfMode = STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE; - r = IStorage_CreateStream( si->db->storage, szSumInfo, grfMode, 0, 0, &stm ); - if( SUCCEEDED(r) ) - { - ret = save_summary_info( si, stm ); - IStream_Release( stm ); - } - msiobj_release( &si->hdr ); - - return ret; -} +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2002, 2005 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> + +#define COBJMACROS +#define NONAMELESSUNION + +#define PRSPEC_PROPID (1) + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winnls.h" +#include "shlwapi.h" +#include "wine/debug.h" +#include "msi.h" +#include "msiquery.h" +#include "msidefs.h" +#include "msipriv.h" +#include "objidl.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +#define MSI_MAX_PROPS 20 + +#include "pshpack1.h" + +typedef struct { + WORD wByteOrder; + WORD wFormat; + DWORD dwOSVer; + CLSID clsID; + DWORD reserved; +} PROPERTYSETHEADER; + +typedef struct { + FMTID fmtid; + DWORD dwOffset; +} FORMATIDOFFSET; + +typedef struct { + DWORD cbSection; + DWORD cProperties; +} PROPERTYSECTIONHEADER; + +typedef struct { + DWORD propid; + DWORD dwOffset; +} PROPERTYIDOFFSET; + +typedef struct { + DWORD type; + union { + INT i4; + SHORT i2; + FILETIME ft; + struct { + DWORD len; + BYTE str[1]; + } str; + } u; +} PROPERTY_DATA; + +#include "poppack.h" + +#define SECT_HDR_SIZE (sizeof(PROPERTYSECTIONHEADER)) + +typedef struct { + BOOL unicode; + union { + LPSTR a; + LPWSTR w; + } str; +} awstring; + +typedef struct tagMSISUMMARYINFO +{ + MSIOBJECTHDR hdr; + MSIDATABASE *db; + DWORD update_count; + PROPVARIANT property[MSI_MAX_PROPS]; +} MSISUMMARYINFO; + +static const WCHAR szSumInfo[] = { 5 ,'S','u','m','m','a','r','y', + 'I','n','f','o','r','m','a','t','i','o','n',0 }; + +static void free_prop( PROPVARIANT *prop ) +{ + if (prop->vt == VT_LPSTR ) + HeapFree( GetProcessHeap(), 0, prop->u.pszVal ); + prop->vt = VT_EMPTY; +} + +static void MSI_CloseSummaryInfo( MSIOBJECTHDR *arg ) +{ + MSISUMMARYINFO *si = (MSISUMMARYINFO *) arg; + DWORD i; + + for( i = 0; i < MSI_MAX_PROPS; i++ ) + free_prop( &si->property[i] ); + msiobj_release( &si->db->hdr ); +} + +static UINT get_type( UINT uiProperty ) +{ + switch( uiProperty ) + { + case PID_CODEPAGE: + return VT_I2; + + case PID_SUBJECT: + case PID_AUTHOR: + case PID_KEYWORDS: + case PID_COMMENTS: + case PID_TEMPLATE: + case PID_LASTAUTHOR: + case PID_REVNUMBER: + case PID_APPNAME: + case PID_TITLE: + return VT_LPSTR; + + case PID_LASTPRINTED: + case PID_CREATE_DTM: + case PID_LASTSAVE_DTM: + return VT_FILETIME; + + case PID_WORDCOUNT: + case PID_CHARCOUNT: + case PID_SECURITY: + case PID_PAGECOUNT: + return VT_I4; + } + return VT_EMPTY; +} + +static UINT get_property_count( PROPVARIANT *property ) +{ + UINT i, n = 0; + + if( !property ) + return n; + for( i = 0; i < MSI_MAX_PROPS; i++ ) + if( property[i].vt != VT_EMPTY ) + n++; + return n; +} + +/* FIXME: doesn't deal with endian conversion */ +static void read_properties_from_data( PROPVARIANT *prop, LPBYTE data, DWORD sz ) +{ + UINT type; + DWORD i; + int size; + PROPERTY_DATA *propdata; + PROPVARIANT *property; + PROPERTYIDOFFSET *idofs; + PROPERTYSECTIONHEADER *section_hdr; + + section_hdr = (PROPERTYSECTIONHEADER*) &data[0]; + idofs = (PROPERTYIDOFFSET*) &data[SECT_HDR_SIZE]; + + /* now set all the properties */ + for( i = 0; i < section_hdr->cProperties; i++ ) + { + type = get_type( idofs[i].propid ); + if( type == VT_EMPTY ) + { + ERR("propid %ld has unknown type\n", idofs[i].propid); + break; + } + + propdata = (PROPERTY_DATA*) &data[ idofs[i].dwOffset ]; + + /* check the type is the same as we expect */ + if( type != propdata->type ) + { + ERR("wrong type %d != %ld\n", type, propdata->type); + break; + } + + /* check we don't run off the end of the data */ + size = sz - idofs[i].dwOffset - sizeof(DWORD); + if( sizeof(DWORD) > size || + ( type == VT_FILETIME && sizeof(FILETIME) > size ) || + ( type == VT_LPSTR && (propdata->u.str.len + sizeof(DWORD)) > size ) ) + { + ERR("not enough data\n"); + break; + } + + if( idofs[i].propid >= MSI_MAX_PROPS ) + { + ERR("Unknown property ID %ld\n", idofs[i].propid ); + break; + } + + property = &prop[ idofs[i].propid ]; + property->vt = type; + + if( type == VT_LPSTR ) + { + LPSTR str = HeapAlloc( GetProcessHeap(), 0, propdata->u.str.len ); + memcpy( str, propdata->u.str.str, propdata->u.str.len ); + str[ propdata->u.str.len - 1 ] = 0; + property->u.pszVal = str; + } + else if( type == VT_FILETIME ) + property->u.filetime = propdata->u.ft; + else if( type == VT_I2 ) + property->u.iVal = propdata->u.i2; + else if( type == VT_I4 ) + property->u.lVal = propdata->u.i4; + } +} + +static UINT load_summary_info( MSISUMMARYINFO *si, IStream *stm ) +{ + UINT ret = ERROR_FUNCTION_FAILED; + PROPERTYSETHEADER set_hdr; + FORMATIDOFFSET format_hdr; + PROPERTYSECTIONHEADER section_hdr; + LPBYTE data = NULL; + LARGE_INTEGER ofs; + ULONG count, sz; + HRESULT r; + + TRACE("%p %p\n", si, stm); + + /* read the header */ + sz = sizeof set_hdr; + r = IStream_Read( stm, &set_hdr, sz, &count ); + if( FAILED(r) || count != sz ) + return ret; + + if( set_hdr.wByteOrder != 0xfffe ) + { + ERR("property set not big-endian %04X\n", set_hdr.wByteOrder); + return ret; + } + + sz = sizeof format_hdr; + r = IStream_Read( stm, &format_hdr, sz, &count ); + if( FAILED(r) || count != sz ) + return ret; + + /* check the format id is correct */ + if( !IsEqualGUID( &FMTID_SummaryInformation, &format_hdr.fmtid ) ) + return ret; + + /* seek to the location of the section */ + ofs.QuadPart = format_hdr.dwOffset; + r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, NULL ); + if( FAILED(r) ) + return ret; + + /* read the section itself */ + sz = SECT_HDR_SIZE; + r = IStream_Read( stm, §ion_hdr, sz, &count ); + if( FAILED(r) || count != sz ) + return ret; + + if( section_hdr.cProperties > MSI_MAX_PROPS ) + { + ERR("too many properties %ld\n", section_hdr.cProperties); + return ret; + } + + data = HeapAlloc( GetProcessHeap(), 0, section_hdr.cbSection); + if( !data ) + return ret; + + memcpy( data, §ion_hdr, SECT_HDR_SIZE ); + + /* read all the data in one go */ + sz = section_hdr.cbSection - SECT_HDR_SIZE; + r = IStream_Read( stm, &data[ SECT_HDR_SIZE ], sz, &count ); + if( SUCCEEDED(r) && count == sz ) + read_properties_from_data( si->property, data, sz + SECT_HDR_SIZE ); + else + ERR("failed to read properties %ld %ld\n", count, sz); + + HeapFree( GetProcessHeap(), 0, data ); + return ret; +} + +static DWORD write_dword( LPBYTE data, DWORD ofs, DWORD val ) +{ + if( data ) + { + data[ofs++] = val&0xff; + data[ofs++] = (val>>8)&0xff; + data[ofs++] = (val>>16)&0xff; + data[ofs++] = (val>>24)&0xff; + } + return 4; +} + +static DWORD write_filetime( LPBYTE data, DWORD ofs, LPFILETIME ft ) +{ + write_dword( data, ofs, ft->dwLowDateTime ); + write_dword( data, ofs + 4, ft->dwHighDateTime ); + return 8; +} + +static DWORD write_string( LPBYTE data, DWORD ofs, LPCSTR str ) +{ + DWORD len = lstrlenA( str ) + 1; + write_dword( data, ofs, len ); + if( data ) + lstrcpyA( &data[ofs + 4], str ); + return (7 + len) & ~3; +} + +static UINT write_property_to_data( PROPVARIANT *prop, LPBYTE data ) +{ + DWORD sz = 0; + + if( prop->vt == VT_EMPTY ) + return sz; + + /* add the type */ + sz += write_dword( data, sz, prop->vt ); + switch( prop->vt ) + { + case VT_I2: + sz += write_dword( data, sz, prop->u.iVal ); + break; + case VT_I4: + sz += write_dword( data, sz, prop->u.lVal ); + break; + case VT_FILETIME: + sz += write_filetime( data, sz, &prop->u.filetime ); + break; + case VT_LPSTR: + sz += write_string( data, sz, prop->u.pszVal ); + break; + } + return sz; +} + +static UINT save_summary_info( MSISUMMARYINFO * si, IStream *stm ) +{ + UINT ret = ERROR_FUNCTION_FAILED; + PROPERTYSETHEADER set_hdr; + FORMATIDOFFSET format_hdr; + PROPERTYSECTIONHEADER section_hdr; + PROPERTYIDOFFSET idofs[MSI_MAX_PROPS]; + LPBYTE data = NULL; + ULONG count, sz; + HRESULT r; + int i, n; + + /* write the header */ + sz = sizeof set_hdr; + memset( &set_hdr, 0, sz ); + set_hdr.wByteOrder = 0xfffe; + set_hdr.wFormat = 0; + set_hdr.dwOSVer = 0x00020005; /* build 5, platform id 2 */ + /* set_hdr.clsID is {00000000-0000-0000-0000-000000000000} */ + set_hdr.reserved = 1; + r = IStream_Write( stm, &set_hdr, sz, &count ); + if( FAILED(r) || count != sz ) + return ret; + + /* write the format header */ + sz = sizeof format_hdr; + memcpy( &format_hdr.fmtid, &FMTID_SummaryInformation, sizeof (FMTID) ); + format_hdr.dwOffset = sizeof format_hdr + sizeof set_hdr; + r = IStream_Write( stm, &format_hdr, sz, &count ); + if( FAILED(r) || count != sz ) + return ret; + + /* add up how much space the data will take and calculate the offsets */ + section_hdr.cbSection = sizeof section_hdr; + section_hdr.cbSection += (get_property_count( si->property ) * sizeof idofs[0]); + section_hdr.cProperties = 0; + n = 0; + for( i = 0; i < MSI_MAX_PROPS; i++ ) + { + sz = write_property_to_data( &si->property[i], NULL ); + if( !sz ) + continue; + idofs[ section_hdr.cProperties ].propid = i; + idofs[ section_hdr.cProperties ].dwOffset = section_hdr.cbSection; + section_hdr.cProperties++; + section_hdr.cbSection += sz; + } + + data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, section_hdr.cbSection ); + + sz = 0; + memcpy( &data[sz], §ion_hdr, sizeof section_hdr ); + sz += sizeof section_hdr; + + memcpy( &data[sz], idofs, section_hdr.cProperties * sizeof idofs[0] ); + sz += section_hdr.cProperties * sizeof idofs[0]; + + /* write out the data */ + for( i = 0; i < MSI_MAX_PROPS; i++ ) + sz += write_property_to_data( &si->property[i], &data[sz] ); + + r = IStream_Write( stm, data, sz, &count ); + HeapFree( GetProcessHeap(), 0, data ); + if( FAILED(r) || count != sz ) + return ret; + + return ERROR_SUCCESS; +} + +UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase, + LPCWSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle ) +{ + UINT ret = ERROR_SUCCESS; + IStream *stm = NULL; + MSISUMMARYINFO *si; + MSIHANDLE handle; + MSIDATABASE *db; + DWORD grfMode; + HRESULT r; + + TRACE("%ld %s %d %p\n", hDatabase, debugstr_w(szDatabase), + uiUpdateCount, pHandle); + + if( !pHandle ) + return ERROR_INVALID_PARAMETER; + + if( szDatabase ) + { + UINT res; + + res = MSI_OpenDatabaseW(szDatabase, NULL, &db); + if( res != ERROR_SUCCESS ) + return res; + } + else + { + db = msihandle2msiinfo(hDatabase, MSIHANDLETYPE_DATABASE); + if( !db ) + return ERROR_INVALID_PARAMETER; + } + + si = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO, + sizeof (MSISUMMARYINFO), MSI_CloseSummaryInfo ); + if( !si ) + { + ret = ERROR_FUNCTION_FAILED; + goto end; + } + + msiobj_addref( &db->hdr ); + si->db = db; + memset( &si->property, 0, sizeof si->property ); + si->update_count = uiUpdateCount; + + /* read the stream... if we fail, we'll start with an empty property set */ + grfMode = STGM_READ | STGM_SHARE_EXCLUSIVE; + r = IStorage_OpenStream( si->db->storage, szSumInfo, 0, grfMode, 0, &stm ); + if( SUCCEEDED(r) ) + { + load_summary_info( si, stm ); + IStream_Release( stm ); + } + + handle = alloc_msihandle( &si->hdr ); + if( handle ) + *pHandle = handle; + else + ret = ERROR_FUNCTION_FAILED; + msiobj_release( &si->hdr ); + +end: + if( db ) + msiobj_release( &db->hdr ); + + return ret; +} + +UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE hDatabase, + LPCSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *pHandle) +{ + LPWSTR szwDatabase = NULL; + UINT ret; + + TRACE("%ld %s %d %p\n", hDatabase, debugstr_a(szDatabase), + uiUpdateCount, pHandle); + + if( szDatabase ) + { + szwDatabase = strdupAtoW( szDatabase ); + if( !szwDatabase ) + return ERROR_FUNCTION_FAILED; + } + + ret = MsiGetSummaryInformationW(hDatabase, szwDatabase, uiUpdateCount, pHandle); + + HeapFree( GetProcessHeap(), 0, szwDatabase ); + + return ret; +} + +UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo, UINT *pCount) +{ + MSISUMMARYINFO *si; + + TRACE("%ld %p\n",hSummaryInfo, pCount); + + si = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO ); + if( !si ) + return ERROR_INVALID_HANDLE; + + if( pCount ) + *pCount = get_property_count( si->property ); + msiobj_release( &si->hdr ); + + return ERROR_SUCCESS; +} + +static UINT get_prop( MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, + INT *piValue, FILETIME *pftValue, awstring *str, DWORD *pcchValueBuf) +{ + MSISUMMARYINFO *si; + PROPVARIANT *prop; + + TRACE("%ld %d %p %p %p %p %p\n", handle, uiProperty, puiDataType, + piValue, pftValue, str, pcchValueBuf); + + si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ); + if( !si ) + return ERROR_INVALID_HANDLE; + + prop = &si->property[uiProperty]; + + if( puiDataType ) + *puiDataType = prop->vt; + + switch( prop->vt ) + { + case VT_I2: + if( piValue ) + *piValue = prop->u.iVal; + break; + case VT_I4: + if( piValue ) + *piValue = prop->u.lVal; + break; + case VT_LPSTR: + if( pcchValueBuf ) + { + DWORD len = 0; + + if( str->unicode ) + { + len = MultiByteToWideChar( CP_ACP, 0, prop->u.pszVal, -1, + str->str.w, *pcchValueBuf ); + } + else + { + len = lstrlenA( prop->u.pszVal ); + if( str->str.a ) + lstrcpynA(str->str.a, prop->u.pszVal, *pcchValueBuf ); + } + *pcchValueBuf = len; + } + break; + case VT_FILETIME: + if( pftValue ) + memcpy(pftValue, &prop->u.filetime, sizeof (FILETIME) ); + break; + case VT_EMPTY: + break; + default: + FIXME("Unknown property variant type\n"); + break; + } + msiobj_release( &si->hdr ); + return ERROR_SUCCESS; +} + +UINT WINAPI MsiSummaryInfoGetPropertyA( + MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, INT *piValue, + FILETIME *pftValue, LPSTR szValueBuf, DWORD *pcchValueBuf) +{ + awstring str; + + TRACE("%ld %d %p %p %p %p %p\n", handle, uiProperty, puiDataType, + piValue, pftValue, szValueBuf, pcchValueBuf ); + + str.unicode = FALSE; + str.str.a = szValueBuf; + + return get_prop( handle, uiProperty, puiDataType, piValue, + pftValue, &str, pcchValueBuf ); +} + +UINT WINAPI MsiSummaryInfoGetPropertyW( + MSIHANDLE handle, UINT uiProperty, UINT *puiDataType, INT *piValue, + FILETIME *pftValue, LPWSTR szValueBuf, DWORD *pcchValueBuf) +{ + awstring str; + + TRACE("%ld %d %p %p %p %p %p\n", handle, uiProperty, puiDataType, + piValue, pftValue, szValueBuf, pcchValueBuf ); + + str.unicode = TRUE; + str.str.w = szValueBuf; + + return get_prop( handle, uiProperty, puiDataType, piValue, + pftValue, &str, pcchValueBuf ); +} + +static UINT set_prop( MSIHANDLE handle, UINT uiProperty, UINT uiDataType, + INT iValue, FILETIME* pftValue, awstring *str ) +{ + MSISUMMARYINFO *si; + PROPVARIANT *prop; + UINT type, len, ret = ERROR_SUCCESS; + + TRACE("%ld %u %u %i %p %p\n", handle, uiProperty, uiDataType, + iValue, pftValue, str ); + + type = get_type( uiProperty ); + if( type == VT_EMPTY || type != uiDataType ) + return ERROR_DATATYPE_MISMATCH; + + if( uiDataType == VT_LPSTR && !str->str.w ) + return ERROR_INVALID_PARAMETER; + + if( uiDataType == VT_FILETIME && !pftValue ) + return ERROR_INVALID_PARAMETER; + + si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ); + if( !si ) + return ERROR_INVALID_HANDLE; + + prop = &si->property[uiProperty]; + + if( prop->vt == VT_EMPTY ) + { + if( !si->update_count ) + { + ret = ERROR_FUNCTION_FAILED; + goto end; + } + si->update_count--; + } + else if( prop->vt != type ) + goto end; + + free_prop( prop ); + prop->vt = type; + switch( type ) + { + case VT_I4: + prop->u.lVal = iValue; + break; + case VT_I2: + prop->u.iVal = iValue; + break; + case VT_FILETIME: + memcpy( &prop->u.filetime, pftValue, sizeof prop->u.filetime ); + break; + case VT_LPSTR: + if( str->unicode ) + { + len = WideCharToMultiByte( CP_ACP, 0, str->str.w, -1, + NULL, 0, NULL, NULL ); + prop->u.pszVal = HeapAlloc( GetProcessHeap(), 0, len ); + WideCharToMultiByte( CP_ACP, 0, str->str.w, -1, + prop->u.pszVal, len, NULL, NULL ); + } + else + { + len = lstrlenA( str->str.a ) + 1; + prop->u.pszVal = HeapAlloc( GetProcessHeap(), 0, len ); + lstrcpyA( prop->u.pszVal, str->str.a ); + } + break; + } + +end: + msiobj_release( &si->hdr ); + return ret; +} + +UINT WINAPI MsiSummaryInfoSetPropertyW( MSIHANDLE handle, UINT uiProperty, + UINT uiDataType, INT iValue, FILETIME* pftValue, LPWSTR szValue ) +{ + awstring str; + + TRACE("%ld %u %u %i %p %s\n", handle, uiProperty, uiDataType, + iValue, pftValue, debugstr_w(szValue) ); + + str.unicode = TRUE; + str.str.w = szValue; + return set_prop( handle, uiProperty, uiDataType, iValue, pftValue, &str ); +} + +UINT WINAPI MsiSummaryInfoSetPropertyA( MSIHANDLE handle, UINT uiProperty, + UINT uiDataType, INT iValue, FILETIME* pftValue, LPSTR szValue ) +{ + awstring str; + + TRACE("%ld %u %u %i %p %s\n", handle, uiProperty, uiDataType, + iValue, pftValue, debugstr_a(szValue) ); + + str.unicode = FALSE; + str.str.a = szValue; + return set_prop( handle, uiProperty, uiDataType, iValue, pftValue, &str ); +} + +UINT WINAPI MsiSummaryInfoPersist( MSIHANDLE handle ) +{ + IStream *stm = NULL; + MSISUMMARYINFO *si; + DWORD grfMode; + HRESULT r; + UINT ret = ERROR_FUNCTION_FAILED; + + TRACE("%ld\n", handle ); + + si = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO ); + if( !si ) + return ERROR_INVALID_HANDLE; + + grfMode = STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE; + r = IStorage_CreateStream( si->db->storage, szSumInfo, grfMode, 0, 0, &stm ); + if( SUCCEEDED(r) ) + { + ret = save_summary_info( si, stm ); + IStream_Release( stm ); + } + msiobj_release( &si->hdr ); + + return ret; +} diff --git a/reactos/lib/msi/table.c b/reactos/lib/msi/table.c index b0fe75b69c3..29f19117a66 100644 --- a/reactos/lib/msi/table.c +++ b/reactos/lib/msi/table.c @@ -1,1417 +1,1417 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2002-2004 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "wine/debug.h" -#include "msi.h" -#include "msiquery.h" -#include "objbase.h" -#include "objidl.h" -#include "msipriv.h" -#include "winnls.h" - -#include "query.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -typedef struct tagMSICOLUMNINFO -{ - LPWSTR tablename; - UINT number; - LPWSTR colname; - UINT type; - UINT offset; -} MSICOLUMNINFO; - -struct tagMSITABLE -{ - USHORT **data; - UINT ref_count; - UINT row_count; - struct tagMSITABLE *next; - struct tagMSITABLE *prev; - WCHAR name[1]; -}; - -#define MAX_STREAM_NAME 0x1f - -static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name, - MSICOLUMNINFO **pcols, UINT *pcount ); -static UINT get_tablecolumns( MSIDATABASE *db, - LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz); - -static inline UINT bytes_per_column( MSICOLUMNINFO *col ) -{ - if( col->type & MSITYPE_STRING ) - return 2; - if( (col->type & 0xff) > 4 ) - ERR("Invalid column size!\n"); - return col->type & 0xff; -} - -static int utf2mime(int x) -{ - if( (x>='0') && (x<='9') ) - return x-'0'; - if( (x>='A') && (x<='Z') ) - return x-'A'+10; - if( (x>='a') && (x<='z') ) - return x-'a'+10+26; - if( x=='.' ) - return 10+26+26; - if( x=='_' ) - return 10+26+26+1; - return -1; -} - -static LPWSTR encode_streamname(BOOL bTable, LPCWSTR in) -{ - DWORD count = MAX_STREAM_NAME; - DWORD ch, next; - LPWSTR out, p; - - if( !bTable ) - count = lstrlenW( in )+2; - out = HeapAlloc( GetProcessHeap(), 0, count*sizeof(WCHAR) ); - p = out; - - if( bTable ) - { - *p++ = 0x4840; - count --; - } - while( count -- ) - { - ch = *in++; - if( !ch ) - { - *p = ch; - return out; - } - if( ( ch < 0x80 ) && ( utf2mime(ch) >= 0 ) ) - { - ch = utf2mime(ch) + 0x4800; - next = *in; - if( next && (next<0x80) ) - { - next = utf2mime(next); - if( next >= 0 ) - { - next += 0x3ffffc0; - ch += (next<<6); - in++; - } - } - } - *p++ = ch; - } - ERR("Failed to encode stream name (%s)\n",debugstr_w(in)); - HeapFree( GetProcessHeap(), 0, out ); - return NULL; -} - -static int mime2utf(int x) -{ - if( x<10 ) - return x + '0'; - if( x<(10+26)) - return x - 10 + 'A'; - if( x<(10+26+26)) - return x - 10 - 26 + 'a'; - if( x == (10+26+26) ) - return '.'; - return '_'; -} - -static BOOL decode_streamname(LPWSTR in, LPWSTR out) -{ - WCHAR ch; - DWORD count = 0; - - while ( (ch = *in++) ) - { - if( (ch >= 0x3800 ) && (ch < 0x4840 ) ) - { - if( ch >= 0x4800 ) - ch = mime2utf(ch-0x4800); - else - { - ch -= 0x3800; - *out++ = mime2utf(ch&0x3f); - count++; - ch = mime2utf((ch>>6)&0x3f); - } - } - *out++ = ch; - count++; - } - *out = 0; - return count; -} - -void enum_stream_names( IStorage *stg ) -{ - IEnumSTATSTG *stgenum = NULL; - HRESULT r; - STATSTG stat; - ULONG n, count; - WCHAR name[0x40]; - - r = IStorage_EnumElements( stg, 0, NULL, 0, &stgenum ); - if( FAILED( r ) ) - return; - - n = 0; - while( 1 ) - { - count = 0; - r = IEnumSTATSTG_Next( stgenum, 1, &stat, &count ); - if( FAILED( r ) || !count ) - break; - decode_streamname( stat.pwcsName, name ); - TRACE("stream %2ld -> %s %s\n", n, - debugstr_w(stat.pwcsName), debugstr_w(name) ); - n++; - } - - IEnumSTATSTG_Release( stgenum ); -} - -static UINT read_stream_data( IStorage *stg, LPCWSTR stname, - USHORT **pdata, UINT *psz ) -{ - HRESULT r; - UINT ret = ERROR_FUNCTION_FAILED; - VOID *data; - ULONG sz, count; - IStream *stm = NULL; - STATSTG stat; - LPWSTR encname; - - encname = encode_streamname(TRUE, stname); - - TRACE("%s -> %s\n",debugstr_w(stname),debugstr_w(encname)); - - r = IStorage_OpenStream(stg, encname, NULL, - STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm); - HeapFree( GetProcessHeap(), 0, encname ); - if( FAILED( r ) ) - { - WARN("open stream failed r = %08lx - empty table?\n",r); - return ret; - } - - r = IStream_Stat(stm, &stat, STATFLAG_NONAME ); - if( FAILED( r ) ) - { - WARN("open stream failed r = %08lx!\n",r); - goto end; - } - - if( stat.cbSize.QuadPart >> 32 ) - { - WARN("Too big!\n"); - goto end; - } - - sz = stat.cbSize.QuadPart; - data = HeapAlloc( GetProcessHeap(), 0, sz ); - if( !data ) - { - WARN("couldn't allocate memory r=%08lx!\n",r); - ret = ERROR_NOT_ENOUGH_MEMORY; - goto end; - } - - r = IStream_Read(stm, data, sz, &count ); - if( FAILED( r ) || ( count != sz ) ) - { - HeapFree( GetProcessHeap(), 0, data ); - WARN("read stream failed r = %08lx!\n",r); - goto end; - } - - *pdata = data; - *psz = sz; - ret = ERROR_SUCCESS; - -end: - IStream_Release( stm ); - - return ret; -} - -UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm ) -{ - LPWSTR encname; - HRESULT r; - - encname = encode_streamname(FALSE, stname); - - TRACE("%s -> %s\n",debugstr_w(stname),debugstr_w(encname)); - - r = IStorage_OpenStream(db->storage, encname, NULL, - STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm); - HeapFree( GetProcessHeap(), 0, encname ); - if( FAILED( r ) ) - { - WARN("open stream failed r = %08lx - empty table?\n",r); - return ERROR_FUNCTION_FAILED; - } - - return ERROR_SUCCESS; -} - -UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname, - USHORT **pdata, UINT *psz ) -{ - HRESULT r; - UINT ret = ERROR_FUNCTION_FAILED; - VOID *data; - ULONG sz, count; - IStream *stm = NULL; - STATSTG stat; - - r = db_get_raw_stream( db, stname, &stm ); - if( r != ERROR_SUCCESS) - return ret; - r = IStream_Stat(stm, &stat, STATFLAG_NONAME ); - if( FAILED( r ) ) - { - WARN("open stream failed r = %08lx!\n",r); - goto end; - } - - if( stat.cbSize.QuadPart >> 32 ) - { - WARN("Too big!\n"); - goto end; - } - - sz = stat.cbSize.QuadPart; - data = HeapAlloc( GetProcessHeap(), 0, sz ); - if( !data ) - { - WARN("couldn't allocate memory r=%08lx!\n",r); - ret = ERROR_NOT_ENOUGH_MEMORY; - goto end; - } - - r = IStream_Read(stm, data, sz, &count ); - if( FAILED( r ) || ( count != sz ) ) - { - HeapFree( GetProcessHeap(), 0, data ); - WARN("read stream failed r = %08lx!\n",r); - goto end; - } - - *pdata = data; - *psz = sz; - ret = ERROR_SUCCESS; - -end: - IStream_Release( stm ); - - return ret; -} - -static UINT write_stream_data( IStorage *stg, LPCWSTR stname, - LPVOID data, UINT sz ) -{ - HRESULT r; - UINT ret = ERROR_FUNCTION_FAILED; - ULONG count; - IStream *stm = NULL; - ULARGE_INTEGER size; - LARGE_INTEGER pos; - LPWSTR encname; - - encname = encode_streamname(TRUE, stname ); - r = IStorage_OpenStream( stg, encname, NULL, - STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &stm); - if( FAILED(r) ) - { - r = IStorage_CreateStream( stg, encname, - STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm); - } - HeapFree( GetProcessHeap(), 0, encname ); - if( FAILED( r ) ) - { - WARN("open stream failed r = %08lx\n",r); - return ret; - } - - size.QuadPart = sz; - r = IStream_SetSize( stm, size ); - if( FAILED( r ) ) - { - WARN("Failed to SetSize\n"); - goto end; - } - - pos.QuadPart = 0; - r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL ); - if( FAILED( r ) ) - { - WARN("Failed to Seek\n"); - goto end; - } - - r = IStream_Write(stm, data, sz, &count ); - if( FAILED( r ) || ( count != sz ) ) - { - WARN("Failed to Write\n"); - goto end; - } - - ret = ERROR_SUCCESS; - -end: - IStream_Release( stm ); - - return ret; -} - -UINT read_table_from_storage( MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable) -{ - MSITABLE *t; - USHORT *rawdata = NULL; - UINT rawsize = 0, r, i, j, row_size = 0, num_cols = 0; - MSICOLUMNINFO *cols, *last_col; - - TRACE("%s\n",debugstr_w(name)); - - /* nonexistent tables should be interpreted as empty tables */ - t = HeapAlloc( GetProcessHeap(), 0, - sizeof (MSITABLE) + lstrlenW(name)*sizeof (WCHAR) ); - if( !t ) - return ERROR_NOT_ENOUGH_MEMORY; - - r = table_get_column_info( db, name, &cols, &num_cols ); - if( r != ERROR_SUCCESS ) - { - HeapFree( GetProcessHeap(), 0, t ); - return r; - } - last_col = &cols[num_cols-1]; - row_size = last_col->offset + bytes_per_column( last_col ); - - t->row_count = 0; - t->data = NULL; - lstrcpyW( t->name, name ); - t->ref_count = 1; - *ptable = t; - - /* if we can't read the table, just assume that it's empty */ - read_stream_data( db->storage, name, &rawdata, &rawsize ); - if( !rawdata ) - return ERROR_SUCCESS; - - TRACE("Read %d bytes\n", rawsize ); - - if( rawsize % row_size ) - { - WARN("Table size is invalid %d/%d\n", rawsize, row_size ); - return ERROR_FUNCTION_FAILED; - } - - t->row_count = rawsize / row_size; - t->data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - t->row_count * sizeof (USHORT*) ); - if( !t->data ) - return ERROR_NOT_ENOUGH_MEMORY; /* FIXME: memory leak */ - - /* transpose all the data */ - TRACE("Transposing data from %d columns\n", t->row_count ); - for( i=0; i<t->row_count; i++ ) - { - t->data[i] = HeapAlloc( GetProcessHeap(), 0, row_size ); - if( !t->data[i] ) - return ERROR_NOT_ENOUGH_MEMORY; /* FIXME: memory leak */ - for( j=0; j<num_cols; j++ ) - { - UINT ofs = cols[j].offset/2; - UINT n = bytes_per_column( &cols[j] ); - - switch( n ) - { - case 2: - t->data[i][ofs] = rawdata[ofs*t->row_count + i ]; - break; - case 4: - t->data[i][ofs] = rawdata[ofs*t->row_count + i*2 ]; - t->data[i][ofs+1] = rawdata[ofs*t->row_count + i*2 + 1]; - break; - default: - ERR("oops - unknown column width %d\n", n); - return ERROR_FUNCTION_FAILED; - } - } - } - - HeapFree( GetProcessHeap(), 0, cols ); - HeapFree( GetProcessHeap(), 0, rawdata ); - - return ERROR_SUCCESS; -} - -/* add this table to the list of cached tables in the database */ -void add_table(MSIDATABASE *db, MSITABLE *table) -{ - table->next = db->first_table; - table->prev = NULL; - if( db->first_table ) - db->first_table->prev = table; - else - db->last_table = table; - db->first_table = table; -} - -/* remove from the list of cached tables */ -void remove_table( MSIDATABASE *db, MSITABLE *table ) -{ - if( table->next ) - table->next->prev = table->prev; - else - db->last_table = table->prev; - if( table->prev ) - table->prev->next = table->next; - else - db->first_table = table->next; - table->next = NULL; - table->prev = NULL; -} - -void release_table( MSIDATABASE *db, MSITABLE *table ) -{ - if( !table->ref_count ) - ERR("Trying to destroy table with refcount 0\n"); - table->ref_count --; - if( !table->ref_count ) - { - remove_table( db, table ); - HeapFree( GetProcessHeap(), 0, table->data ); - HeapFree( GetProcessHeap(), 0, table ); - TRACE("Destroyed table %s\n", debugstr_w(table->name)); - } -} - -void free_cached_tables( MSIDATABASE *db ) -{ - while( db->first_table ) - { - MSITABLE *t = db->first_table; - - if ( --t->ref_count ) - ERR("table ref count not zero for %s\n", debugstr_w(t->name)); - remove_table( db, t ); - HeapFree( GetProcessHeap(), 0, t->data ); - HeapFree( GetProcessHeap(), 0, t ); - } -} - -UINT find_cached_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable) -{ - MSITABLE *t; - - for( t = db->first_table; t; t=t->next ) - { - if( !lstrcmpW( name, t->name ) ) - { - *ptable = t; - return ERROR_SUCCESS; - } - } - - return ERROR_FUNCTION_FAILED; -} - -static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO **pcols, UINT *pcount ) -{ - UINT r, column_count; - MSICOLUMNINFO *columns; - - /* get the number of columns in this table */ - column_count = 0; - r = get_tablecolumns( db, name, NULL, &column_count ); - if( r != ERROR_SUCCESS ) - return r; - - /* if there's no columns, there's no table */ - if( column_count == 0 ) - return ERROR_INVALID_PARAMETER; - - TRACE("Table %s found\n", debugstr_w(name) ); - - columns = HeapAlloc( GetProcessHeap(), 0, column_count*sizeof (MSICOLUMNINFO)); - if( !columns ) - return ERROR_FUNCTION_FAILED; - - r = get_tablecolumns( db, name, columns, &column_count ); - if( r != ERROR_SUCCESS ) - { - HeapFree( GetProcessHeap(), 0, columns ); - return ERROR_FUNCTION_FAILED; - } - - *pcols = columns; - *pcount = column_count; - - return r; -} - -UINT get_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable) -{ - UINT r; - - *ptable = NULL; - - /* first, see if the table is cached */ - r = find_cached_table( db, name, ptable ); - if( r == ERROR_SUCCESS ) - { - (*ptable)->ref_count++; - return r; - } - - r = read_table_from_storage( db, name, ptable ); - if( r != ERROR_SUCCESS ) - return r; - - /* add the table to the list */ - add_table( db, *ptable ); - (*ptable)->ref_count++; - - return ERROR_SUCCESS; -} - -UINT save_table( MSIDATABASE *db, MSITABLE *t ) -{ - USHORT *rawdata = NULL, *p; - UINT rawsize, r, i, j, row_size, num_cols = 0; - MSICOLUMNINFO *cols, *last_col; - - TRACE("Saving %s\n", debugstr_w( t->name ) ); - - r = table_get_column_info( db, t->name, &cols, &num_cols ); - if( r != ERROR_SUCCESS ) - return r; - - last_col = &cols[num_cols-1]; - row_size = last_col->offset + bytes_per_column( last_col ); - - rawsize = t->row_count * row_size; - rawdata = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, rawsize ); - if( !rawdata ) - return ERROR_NOT_ENOUGH_MEMORY; - - p = rawdata; - for( i=0; i<num_cols; i++ ) - { - for( j=0; j<t->row_count; j++ ) - { - UINT offset = cols[i].offset; - - *p++ = t->data[j][offset/2]; - if( 4 == bytes_per_column( &cols[i] ) ) - *p++ = t->data[j][offset/2+1]; - } - } - - TRACE("writing %d bytes\n", rawsize); - r = write_stream_data( db->storage, t->name, rawdata, rawsize ); - - HeapFree( GetProcessHeap(), 0, rawdata ); - - return r; -} - -HRESULT init_string_table( IStorage *stg ) -{ - HRESULT r; - static const WCHAR szStringData[] = { - '_','S','t','r','i','n','g','D','a','t','a',0 }; - static const WCHAR szStringPool[] = { - '_','S','t','r','i','n','g','P','o','o','l',0 }; - USHORT zero[2] = { 0, 0 }; - ULONG count = 0; - IStream *stm = NULL; - LPWSTR encname; - - encname = encode_streamname(TRUE, szStringPool ); - - /* create the StringPool stream... add the zero string to it*/ - r = IStorage_CreateStream( stg, encname, - STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm); - HeapFree( GetProcessHeap(), 0, encname ); - if( r ) - { - TRACE("Failed\n"); - return r; - } - - r = IStream_Write(stm, zero, sizeof zero, &count ); - IStream_Release( stm ); - - if( FAILED( r ) || ( count != sizeof zero ) ) - { - TRACE("Failed\n"); - return E_FAIL; - } - - /* create the StringData stream... make it zero length */ - encname = encode_streamname(TRUE, szStringData ); - r = IStorage_CreateStream( stg, encname, - STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm); - HeapFree( GetProcessHeap(), 0, encname ); - if( r ) - { - TRACE("Failed\n"); - return E_FAIL; - } - IStream_Release( stm ); - - return r; -} - -UINT load_string_table( MSIDATABASE *db ) -{ - CHAR *data; - USHORT *pool; - UINT r, ret = ERROR_FUNCTION_FAILED, datasize = 0, poolsize = 0, codepage; - DWORD i, count, offset, len, n; - static const WCHAR szStringData[] = { - '_','S','t','r','i','n','g','D','a','t','a',0 }; - static const WCHAR szStringPool[] = { - '_','S','t','r','i','n','g','P','o','o','l',0 }; - - if( db->strings ) - { - msi_destroy_stringtable( db->strings ); - db->strings = NULL; - } - - r = read_stream_data( db->storage, szStringPool, &pool, &poolsize ); - if( r != ERROR_SUCCESS) - goto end; - r = read_stream_data( db->storage, szStringData, (USHORT**)&data, &datasize ); - if( r != ERROR_SUCCESS) - goto end; - - count = poolsize/4; - if( poolsize > 4 ) - codepage = pool[0] | ( pool[1] << 16 ); - else - codepage = CP_ACP; - db->strings = msi_init_stringtable( count, codepage ); - - offset = 0; - for( i=1; i<count; i++ ) - { - len = pool[i*2]; - n = msi_addstring( db->strings, i, data+offset, len, pool[i*2+1] ); - if( n != i ) - ERR("Failed to add string %ld\n", i ); - offset += len; - } - - TRACE("Loaded %ld strings\n", count); - - ret = ERROR_SUCCESS; - -end: - HeapFree( GetProcessHeap(), 0, pool ); - HeapFree( GetProcessHeap(), 0, data ); - - return ret; -} - -UINT save_string_table( MSIDATABASE *db ) -{ - UINT i, count, datasize, poolsize, sz, used, r, codepage; - UINT ret = ERROR_FUNCTION_FAILED; - static const WCHAR szStringData[] = { - '_','S','t','r','i','n','g','D','a','t','a',0 }; - static const WCHAR szStringPool[] = { - '_','S','t','r','i','n','g','P','o','o','l',0 }; - CHAR *data = NULL; - USHORT *pool = NULL; - - TRACE("\n"); - - /* construct the new table in memory first */ - datasize = msi_string_totalsize( db->strings, &count ); - poolsize = count*2*sizeof(USHORT); - - pool = HeapAlloc( GetProcessHeap(), 0, poolsize ); - if( ! pool ) - { - WARN("Failed to alloc pool %d bytes\n", poolsize ); - goto err; - } - data = HeapAlloc( GetProcessHeap(), 0, datasize ); - if( ! data ) - { - WARN("Failed to alloc data %d bytes\n", poolsize ); - goto err; - } - - used = 0; - codepage = msi_string_get_codepage( db->strings ); - pool[0]=codepage&0xffff; - pool[1]=(codepage>>16); - for( i=1; i<count; i++ ) - { - sz = datasize - used; - r = msi_id2stringA( db->strings, i, data+used, &sz ); - if( r != ERROR_SUCCESS ) - { - ERR("failed to fetch string\n"); - sz = 0; - } - if( sz && (sz < (datasize - used ) ) ) - sz--; - TRACE("adding %u bytes %s\n", sz, data+used ); - pool[ i*2 ] = sz; - pool[ i*2 + 1 ] = msi_id_refcount( db->strings, i ); - used += sz; - if( used > datasize ) - { - ERR("oops overran %d >= %d\n", used, datasize); - goto err; - } - } - - if( used != datasize ) - { - ERR("oops used %d != datasize %d\n", used, datasize); - goto err; - } - - /* write the streams */ - r = write_stream_data( db->storage, szStringData, data, datasize ); - TRACE("Wrote StringData r=%08x\n", r); - if( r ) - goto err; - r = write_stream_data( db->storage, szStringPool, pool, poolsize ); - TRACE("Wrote StringPool r=%08x\n", r); - if( r ) - goto err; - - ret = ERROR_SUCCESS; - -err: - HeapFree( GetProcessHeap(), 0, data ); - HeapFree( GetProcessHeap(), 0, pool ); - - return ret; -} - -/* information for default tables */ -static const WCHAR szTables[] = { '_','T','a','b','l','e','s',0 }; -static const WCHAR szTable[] = { 'T','a','b','l','e',0 }; -static const WCHAR szName[] = { 'N','a','m','e',0 }; -static const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 }; -static const WCHAR szColumn[] = { 'C','o','l','u','m','n',0 }; -static const WCHAR szNumber[] = { 'N','u','m','b','e','r',0 }; -static const WCHAR szType[] = { 'T','y','p','e',0 }; - -struct standard_table { - LPCWSTR tablename; - LPCWSTR columnname; - UINT number; - UINT type; -} MSI_standard_tables[] = -{ - { szTables, szName, 1, MSITYPE_VALID | MSITYPE_STRING | 32}, - { szColumns, szTable, 1, MSITYPE_VALID | MSITYPE_STRING | 32}, - { szColumns, szNumber, 2, MSITYPE_VALID | 2}, - { szColumns, szName, 3, MSITYPE_VALID | MSITYPE_STRING | 32}, - { szColumns, szType, 4, MSITYPE_VALID | 2}, -}; - -#define STANDARD_TABLE_COUNT \ - (sizeof(MSI_standard_tables)/sizeof(struct standard_table)) - -UINT get_defaulttablecolumns( LPCWSTR szTable, MSICOLUMNINFO *colinfo, UINT *sz) -{ - DWORD i, n=0; - - for(i=0; i<STANDARD_TABLE_COUNT; i++) - { - if( lstrcmpW( szTable, MSI_standard_tables[i].tablename ) ) - continue; - if(colinfo && (n < *sz) ) - { - colinfo[n].tablename = strdupW(MSI_standard_tables[i].tablename); - colinfo[n].colname = strdupW(MSI_standard_tables[i].columnname); - colinfo[n].number = MSI_standard_tables[i].number; - colinfo[n].type = MSI_standard_tables[i].type; - /* ERR("Table %s has column %s\n",debugstr_w(colinfo[n].tablename), - debugstr_w(colinfo[n].colname)); */ - if( n ) - colinfo[n].offset = colinfo[n-1].offset - + bytes_per_column( &colinfo[n-1] ); - else - colinfo[n].offset = 0; - } - n++; - if( colinfo && (n >= *sz) ) - break; - } - *sz = n; - return ERROR_SUCCESS; -} - -LPWSTR MSI_makestring( MSIDATABASE *db, UINT stringid) -{ - UINT sz=0, r; - LPWSTR str; - - r = msi_id2stringW( db->strings, stringid, NULL, &sz ); - if( r != ERROR_SUCCESS ) - return NULL; - str = HeapAlloc( GetProcessHeap(), 0, sz*sizeof (WCHAR)); - if( !str ) - return str; - r = msi_id2stringW( db->strings, stringid, str, &sz ); - if( r == ERROR_SUCCESS ) - return str; - HeapFree( GetProcessHeap(), 0, str ); - return NULL; -} - -static UINT get_tablecolumns( MSIDATABASE *db, - LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz) -{ - UINT r, i, n=0, table_id, count, maxcount = *sz; - MSITABLE *table = NULL; - static const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 }; - - /* first check if there is a default table with that name */ - r = get_defaulttablecolumns( szTableName, colinfo, sz ); - if( ( r == ERROR_SUCCESS ) && *sz ) - return r; - - r = get_table( db, szColumns, &table); - if( r != ERROR_SUCCESS ) - { - WARN("table %s not available\n", debugstr_w(szColumns)); - return r; - } - - /* convert table and column names to IDs from the string table */ - r = msi_string2idW( db->strings, szTableName, &table_id ); - if( r != ERROR_SUCCESS ) - { - release_table( db, table ); - WARN("Couldn't find id for %s\n", debugstr_w(szTableName)); - return r; - } - - TRACE("Table id is %d\n", table_id); - - count = table->row_count; - for( i=0; i<count; i++ ) - { - if( table->data[ i ][ 0 ] != table_id ) - continue; - if( colinfo ) - { - UINT id = table->data[ i ] [ 2 ]; - colinfo[n].tablename = MSI_makestring( db, table_id ); - colinfo[n].number = table->data[ i ][ 1 ] - (1<<15); - colinfo[n].colname = MSI_makestring( db, id ); - colinfo[n].type = table->data[ i ] [ 3 ]; - /* this assumes that columns are in order in the table */ - if( n ) - colinfo[n].offset = colinfo[n-1].offset - + bytes_per_column( &colinfo[n-1] ); - else - colinfo[n].offset = 0; - TRACE("table %s column %d is [%s] (%d) with type %08x " - "offset %d at row %d\n", debugstr_w(szTableName), - colinfo[n].number, debugstr_w(colinfo[n].colname), - id, colinfo[n].type, colinfo[n].offset, i); - if( n != (colinfo[n].number-1) ) - { - ERR("oops. data in the _Columns table isn't in the right " - "order for table %s\n", debugstr_w(szTableName)); - return ERROR_FUNCTION_FAILED; - } - } - n++; - if( colinfo && ( n >= maxcount ) ) - break; - } - *sz = n; - - release_table( db, table ); - - return ERROR_SUCCESS; -} - -/* try to find the table name in the _Tables table */ -BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name ) -{ - static const WCHAR szTables[] = { '_','T','a','b','l','e','s',0 }; - static const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 }; - UINT r, table_id = 0, i, count; - MSITABLE *table = NULL; - - if( !lstrcmpW( name, szTables ) ) - return TRUE; - if( !lstrcmpW( name, szColumns ) ) - return TRUE; - - r = msi_string2idW( db->strings, name, &table_id ); - if( r != ERROR_SUCCESS ) - { - TRACE("Couldn't find id for %s\n", debugstr_w(name)); - return FALSE; - } - - r = get_table( db, szTables, &table); - if( r != ERROR_SUCCESS ) - { - TRACE("table %s not available\n", debugstr_w(szTables)); - return FALSE; - } - - /* count = table->size/2; */ - count = table->row_count; - for( i=0; i<count; i++ ) - if( table->data[ i ][ 0 ] == table_id ) - break; - - release_table( db, table ); - - if (i!=count) - return TRUE; - - TRACE("Searched %d tables, but %d was not found\n", count, table_id ); - - return FALSE; -} - -/* below is the query interface to a table */ - -typedef struct tagMSITABLEVIEW -{ - MSIVIEW view; - MSIDATABASE *db; - MSITABLE *table; - MSICOLUMNINFO *columns; - UINT num_cols; - UINT row_size; - WCHAR name[1]; -} MSITABLEVIEW; - -static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) -{ - MSITABLEVIEW *tv = (MSITABLEVIEW*)view; - UINT offset, num_rows, n; - - if( !tv->table ) - return ERROR_INVALID_PARAMETER; - - if( (col==0) || (col>tv->num_cols) ) - return ERROR_INVALID_PARAMETER; - - /* how many rows are there ? */ - num_rows = tv->table->row_count; - if( row >= num_rows ) - return ERROR_NO_MORE_ITEMS; - - if( tv->columns[col-1].offset >= tv->row_size ) - { - ERR("Stuffed up %d >= %d\n", tv->columns[col-1].offset, tv->row_size ); - ERR("%p %p\n", tv, tv->columns ); - return ERROR_FUNCTION_FAILED; - } - - offset = row + (tv->columns[col-1].offset/2) * num_rows; - n = bytes_per_column( &tv->columns[col-1] ); - switch( n ) - { - case 4: - offset = tv->columns[col-1].offset/2; - *val = tv->table->data[row][offset] + - (tv->table->data[row][offset + 1] << 16); - break; - case 2: - offset = tv->columns[col-1].offset/2; - *val = tv->table->data[row][offset]; - break; - default: - ERR("oops! what is %d bytes per column?\n", n ); - return ERROR_FUNCTION_FAILED; - } - - /* TRACE("Data [%d][%d] = %d \n", row, col, *val ); */ - - return ERROR_SUCCESS; -} - -/* - * We need a special case for streams, as we need to reference column with - * the name of the stream in the same table, and the table name - * which may not be available at higher levels of the query - */ -static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm ) -{ - MSITABLEVIEW *tv = (MSITABLEVIEW*)view; - UINT ival = 0, refcol = 0, r; - LPWSTR sval; - LPWSTR full_name; - DWORD len; - static const WCHAR szDot[] = { '.', 0 }; - - if( !view->ops->fetch_int ) - return ERROR_INVALID_PARAMETER; - - /* - * The column marked with the type stream data seems to have a single number - * which references the column containing the name of the stream data - * - * Fetch the column to reference first. - */ - r = view->ops->fetch_int( view, row, col, &ival ); - if( r != ERROR_SUCCESS ) - return r; - - /* now get the column with the name of the stream */ - r = view->ops->fetch_int( view, row, ival, &refcol ); - if( r != ERROR_SUCCESS ) - return r; - - /* lookup the string value from the string table */ - sval = MSI_makestring( tv->db, refcol ); - if( !sval ) - return ERROR_INVALID_PARAMETER; - - len = lstrlenW( tv->name ) + 2 + lstrlenW( sval ); - full_name = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); - lstrcpyW( full_name, tv->name ); - lstrcatW( full_name, szDot ); - lstrcatW( full_name, sval ); - - r = db_get_raw_stream( tv->db, full_name, stm ); - if( r ) - ERR("fetching stream %s, error = %d\n",debugstr_w(full_name), r); - HeapFree( GetProcessHeap(), 0, full_name ); - HeapFree( GetProcessHeap(), 0, sval ); - - return r; -} - -static UINT TABLE_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val ) -{ - MSITABLEVIEW *tv = (MSITABLEVIEW*)view; - UINT offset, n; - - if( !tv->table ) - return ERROR_INVALID_PARAMETER; - - if( (col==0) || (col>tv->num_cols) ) - return ERROR_INVALID_PARAMETER; - - if( tv->columns[col-1].offset >= tv->row_size ) - { - ERR("Stuffed up %d >= %d\n", tv->columns[col-1].offset, tv->row_size ); - ERR("%p %p\n", tv, tv->columns ); - return ERROR_FUNCTION_FAILED; - } - - n = bytes_per_column( &tv->columns[col-1] ); - switch( n ) - { - case 4: - offset = tv->columns[col-1].offset/2; - tv->table->data[row][offset] = val & 0xffff; - tv->table->data[row][offset + 1] = (val>>16)&0xffff; - break; - case 2: - offset = tv->columns[col-1].offset/2; - tv->table->data[row][offset] = val; - break; - default: - ERR("oops! what is %d bytes per column?\n", n ); - return ERROR_FUNCTION_FAILED; - } - return ERROR_SUCCESS; -} - -UINT TABLE_insert_row( struct tagMSIVIEW *view, UINT *num ) -{ - MSITABLEVIEW *tv = (MSITABLEVIEW*)view; - USHORT **p, *row; - UINT sz; - - TRACE("%p\n", view); - - if( !tv->table ) - return ERROR_INVALID_PARAMETER; - - row = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, tv->row_size ); - if( !row ) - return ERROR_NOT_ENOUGH_MEMORY; - - sz = (tv->table->row_count + 1) * sizeof (UINT*); - if( tv->table->data ) - p = HeapReAlloc( GetProcessHeap(), 0, tv->table->data, sz ); - else - p = HeapAlloc( GetProcessHeap(), 0, sz ); - if( !p ) - { - HeapFree( GetProcessHeap(), 0, row ); - return ERROR_NOT_ENOUGH_MEMORY; - } - - tv->table->data = p; - tv->table->data[tv->table->row_count] = row; - *num = tv->table->row_count; - tv->table->row_count++; - - return ERROR_SUCCESS; -} - -static UINT TABLE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) -{ - MSITABLEVIEW *tv = (MSITABLEVIEW*)view; - UINT r; - - TRACE("%p %p\n", tv, record); - - if( tv->table ) - { - release_table( tv->db, tv->table ); - tv->table = NULL; - } - - r = get_table( tv->db, tv->name, &tv->table ); - if( r != ERROR_SUCCESS ) - return r; - - return ERROR_SUCCESS; -} - -static UINT TABLE_close( struct tagMSIVIEW *view ) -{ - MSITABLEVIEW *tv = (MSITABLEVIEW*)view; - - TRACE("%p\n", view ); - - if( !tv->table ) - return ERROR_FUNCTION_FAILED; - - release_table( tv->db, tv->table ); - tv->table = NULL; - - return ERROR_SUCCESS; -} - -static UINT TABLE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols) -{ - MSITABLEVIEW *tv = (MSITABLEVIEW*)view; - - TRACE("%p %p %p\n", view, rows, cols ); - - if( cols ) - *cols = tv->num_cols; - if( rows ) - { - if( !tv->table ) - return ERROR_INVALID_PARAMETER; - *rows = tv->table->row_count; - } - - return ERROR_SUCCESS; -} - -static UINT TABLE_get_column_info( struct tagMSIVIEW *view, - UINT n, LPWSTR *name, UINT *type ) -{ - MSITABLEVIEW *tv = (MSITABLEVIEW*)view; - - TRACE("%p %d %p %p\n", tv, n, name, type ); - - if( ( n == 0 ) || ( n > tv->num_cols ) ) - return ERROR_INVALID_PARAMETER; - - if( name ) - { - *name = strdupW( tv->columns[n-1].colname ); - if( !*name ) - return ERROR_FUNCTION_FAILED; - } - if( type ) - *type = tv->columns[n-1].type; - - return ERROR_SUCCESS; -} - -static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, - MSIRECORD *rec) -{ - FIXME("%p %d %p\n", view, eModifyMode, rec ); - return ERROR_CALL_NOT_IMPLEMENTED; -} - -static UINT TABLE_delete( struct tagMSIVIEW *view ) -{ - MSITABLEVIEW *tv = (MSITABLEVIEW*)view; - - TRACE("%p\n", view ); - - if( tv->table ) - release_table( tv->db, tv->table ); - tv->table = NULL; - - if( tv->columns ) - { - UINT i; - for( i=0; i<tv->num_cols; i++) - { - HeapFree( GetProcessHeap(), 0, tv->columns[i].colname ); - HeapFree( GetProcessHeap(), 0, tv->columns[i].tablename ); - } - HeapFree( GetProcessHeap(), 0, tv->columns ); - } - tv->columns = NULL; - - HeapFree( GetProcessHeap(), 0, tv ); - - return ERROR_SUCCESS; -} - - -MSIVIEWOPS table_ops = -{ - TABLE_fetch_int, - TABLE_fetch_stream, - TABLE_set_int, - TABLE_insert_row, - TABLE_execute, - TABLE_close, - TABLE_get_dimensions, - TABLE_get_column_info, - TABLE_modify, - TABLE_delete -}; - -UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view ) -{ - MSITABLEVIEW *tv ; - UINT r, sz, column_count; - MSICOLUMNINFO *columns, *last_col; - - TRACE("%p %s %p\n", db, debugstr_w(name), view ); - - /* get the number of columns in this table */ - column_count = 0; - r = get_tablecolumns( db, name, NULL, &column_count ); - if( r != ERROR_SUCCESS ) - return r; - - /* if there's no columns, there's no table */ - if( column_count == 0 ) - return ERROR_INVALID_PARAMETER; - - TRACE("Table found\n"); - - sz = sizeof *tv + lstrlenW(name)*sizeof name[0] ; - tv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sz ); - if( !tv ) - return ERROR_FUNCTION_FAILED; - - columns = HeapAlloc( GetProcessHeap(), 0, column_count*sizeof (MSICOLUMNINFO)); - if( !columns ) - { - HeapFree( GetProcessHeap(), 0, tv ); - return ERROR_FUNCTION_FAILED; - } - - r = get_tablecolumns( db, name, columns, &column_count ); - if( r != ERROR_SUCCESS ) - { - HeapFree( GetProcessHeap(), 0, columns ); - HeapFree( GetProcessHeap(), 0, tv ); - return ERROR_FUNCTION_FAILED; - } - - TRACE("Table has %d columns\n", column_count); - - last_col = &columns[column_count-1]; - - /* fill the structure */ - tv->view.ops = &table_ops; - tv->db = db; - tv->columns = columns; - tv->num_cols = column_count; - tv->table = NULL; - tv->row_size = last_col->offset + bytes_per_column( last_col ); - - TRACE("one row is %d bytes\n", tv->row_size ); - - *view = (MSIVIEW*) tv; - lstrcpyW( tv->name, name ); - - return ERROR_SUCCESS; -} - -UINT MSI_CommitTables( MSIDATABASE *db ) -{ - UINT r; - MSITABLE *table = NULL; - - TRACE("%p\n",db); - - r = save_string_table( db ); - if( r != ERROR_SUCCESS ) - { - WARN("failed to save string table r=%08x\n",r); - return r; - } - - for( table = db->first_table; table; table = table->next ) - { - r = save_table( db, table ); - if( r != ERROR_SUCCESS ) - { - WARN("failed to save table %s (r=%08x)\n", - debugstr_w(table->name), r); - return r; - } - } - - /* force everything to reload next time */ - free_cached_tables( db ); - - return ERROR_SUCCESS; -} +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2002-2004 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/debug.h" +#include "msi.h" +#include "msiquery.h" +#include "objbase.h" +#include "objidl.h" +#include "msipriv.h" +#include "winnls.h" + +#include "query.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +typedef struct tagMSICOLUMNINFO +{ + LPWSTR tablename; + UINT number; + LPWSTR colname; + UINT type; + UINT offset; +} MSICOLUMNINFO; + +struct tagMSITABLE +{ + USHORT **data; + UINT ref_count; + UINT row_count; + struct tagMSITABLE *next; + struct tagMSITABLE *prev; + WCHAR name[1]; +}; + +#define MAX_STREAM_NAME 0x1f + +static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name, + MSICOLUMNINFO **pcols, UINT *pcount ); +static UINT get_tablecolumns( MSIDATABASE *db, + LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz); + +static inline UINT bytes_per_column( MSICOLUMNINFO *col ) +{ + if( col->type & MSITYPE_STRING ) + return 2; + if( (col->type & 0xff) > 4 ) + ERR("Invalid column size!\n"); + return col->type & 0xff; +} + +static int utf2mime(int x) +{ + if( (x>='0') && (x<='9') ) + return x-'0'; + if( (x>='A') && (x<='Z') ) + return x-'A'+10; + if( (x>='a') && (x<='z') ) + return x-'a'+10+26; + if( x=='.' ) + return 10+26+26; + if( x=='_' ) + return 10+26+26+1; + return -1; +} + +static LPWSTR encode_streamname(BOOL bTable, LPCWSTR in) +{ + DWORD count = MAX_STREAM_NAME; + DWORD ch, next; + LPWSTR out, p; + + if( !bTable ) + count = lstrlenW( in )+2; + out = HeapAlloc( GetProcessHeap(), 0, count*sizeof(WCHAR) ); + p = out; + + if( bTable ) + { + *p++ = 0x4840; + count --; + } + while( count -- ) + { + ch = *in++; + if( !ch ) + { + *p = ch; + return out; + } + if( ( ch < 0x80 ) && ( utf2mime(ch) >= 0 ) ) + { + ch = utf2mime(ch) + 0x4800; + next = *in; + if( next && (next<0x80) ) + { + next = utf2mime(next); + if( next >= 0 ) + { + next += 0x3ffffc0; + ch += (next<<6); + in++; + } + } + } + *p++ = ch; + } + ERR("Failed to encode stream name (%s)\n",debugstr_w(in)); + HeapFree( GetProcessHeap(), 0, out ); + return NULL; +} + +static int mime2utf(int x) +{ + if( x<10 ) + return x + '0'; + if( x<(10+26)) + return x - 10 + 'A'; + if( x<(10+26+26)) + return x - 10 - 26 + 'a'; + if( x == (10+26+26) ) + return '.'; + return '_'; +} + +static BOOL decode_streamname(LPWSTR in, LPWSTR out) +{ + WCHAR ch; + DWORD count = 0; + + while ( (ch = *in++) ) + { + if( (ch >= 0x3800 ) && (ch < 0x4840 ) ) + { + if( ch >= 0x4800 ) + ch = mime2utf(ch-0x4800); + else + { + ch -= 0x3800; + *out++ = mime2utf(ch&0x3f); + count++; + ch = mime2utf((ch>>6)&0x3f); + } + } + *out++ = ch; + count++; + } + *out = 0; + return count; +} + +void enum_stream_names( IStorage *stg ) +{ + IEnumSTATSTG *stgenum = NULL; + HRESULT r; + STATSTG stat; + ULONG n, count; + WCHAR name[0x40]; + + r = IStorage_EnumElements( stg, 0, NULL, 0, &stgenum ); + if( FAILED( r ) ) + return; + + n = 0; + while( 1 ) + { + count = 0; + r = IEnumSTATSTG_Next( stgenum, 1, &stat, &count ); + if( FAILED( r ) || !count ) + break; + decode_streamname( stat.pwcsName, name ); + TRACE("stream %2ld -> %s %s\n", n, + debugstr_w(stat.pwcsName), debugstr_w(name) ); + n++; + } + + IEnumSTATSTG_Release( stgenum ); +} + +static UINT read_stream_data( IStorage *stg, LPCWSTR stname, + USHORT **pdata, UINT *psz ) +{ + HRESULT r; + UINT ret = ERROR_FUNCTION_FAILED; + VOID *data; + ULONG sz, count; + IStream *stm = NULL; + STATSTG stat; + LPWSTR encname; + + encname = encode_streamname(TRUE, stname); + + TRACE("%s -> %s\n",debugstr_w(stname),debugstr_w(encname)); + + r = IStorage_OpenStream(stg, encname, NULL, + STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm); + HeapFree( GetProcessHeap(), 0, encname ); + if( FAILED( r ) ) + { + WARN("open stream failed r = %08lx - empty table?\n",r); + return ret; + } + + r = IStream_Stat(stm, &stat, STATFLAG_NONAME ); + if( FAILED( r ) ) + { + WARN("open stream failed r = %08lx!\n",r); + goto end; + } + + if( stat.cbSize.QuadPart >> 32 ) + { + WARN("Too big!\n"); + goto end; + } + + sz = stat.cbSize.QuadPart; + data = HeapAlloc( GetProcessHeap(), 0, sz ); + if( !data ) + { + WARN("couldn't allocate memory r=%08lx!\n",r); + ret = ERROR_NOT_ENOUGH_MEMORY; + goto end; + } + + r = IStream_Read(stm, data, sz, &count ); + if( FAILED( r ) || ( count != sz ) ) + { + HeapFree( GetProcessHeap(), 0, data ); + WARN("read stream failed r = %08lx!\n",r); + goto end; + } + + *pdata = data; + *psz = sz; + ret = ERROR_SUCCESS; + +end: + IStream_Release( stm ); + + return ret; +} + +UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm ) +{ + LPWSTR encname; + HRESULT r; + + encname = encode_streamname(FALSE, stname); + + TRACE("%s -> %s\n",debugstr_w(stname),debugstr_w(encname)); + + r = IStorage_OpenStream(db->storage, encname, NULL, + STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm); + HeapFree( GetProcessHeap(), 0, encname ); + if( FAILED( r ) ) + { + WARN("open stream failed r = %08lx - empty table?\n",r); + return ERROR_FUNCTION_FAILED; + } + + return ERROR_SUCCESS; +} + +UINT read_raw_stream_data( MSIDATABASE *db, LPCWSTR stname, + USHORT **pdata, UINT *psz ) +{ + HRESULT r; + UINT ret = ERROR_FUNCTION_FAILED; + VOID *data; + ULONG sz, count; + IStream *stm = NULL; + STATSTG stat; + + r = db_get_raw_stream( db, stname, &stm ); + if( r != ERROR_SUCCESS) + return ret; + r = IStream_Stat(stm, &stat, STATFLAG_NONAME ); + if( FAILED( r ) ) + { + WARN("open stream failed r = %08lx!\n",r); + goto end; + } + + if( stat.cbSize.QuadPart >> 32 ) + { + WARN("Too big!\n"); + goto end; + } + + sz = stat.cbSize.QuadPart; + data = HeapAlloc( GetProcessHeap(), 0, sz ); + if( !data ) + { + WARN("couldn't allocate memory r=%08lx!\n",r); + ret = ERROR_NOT_ENOUGH_MEMORY; + goto end; + } + + r = IStream_Read(stm, data, sz, &count ); + if( FAILED( r ) || ( count != sz ) ) + { + HeapFree( GetProcessHeap(), 0, data ); + WARN("read stream failed r = %08lx!\n",r); + goto end; + } + + *pdata = data; + *psz = sz; + ret = ERROR_SUCCESS; + +end: + IStream_Release( stm ); + + return ret; +} + +static UINT write_stream_data( IStorage *stg, LPCWSTR stname, + LPVOID data, UINT sz ) +{ + HRESULT r; + UINT ret = ERROR_FUNCTION_FAILED; + ULONG count; + IStream *stm = NULL; + ULARGE_INTEGER size; + LARGE_INTEGER pos; + LPWSTR encname; + + encname = encode_streamname(TRUE, stname ); + r = IStorage_OpenStream( stg, encname, NULL, + STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &stm); + if( FAILED(r) ) + { + r = IStorage_CreateStream( stg, encname, + STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm); + } + HeapFree( GetProcessHeap(), 0, encname ); + if( FAILED( r ) ) + { + WARN("open stream failed r = %08lx\n",r); + return ret; + } + + size.QuadPart = sz; + r = IStream_SetSize( stm, size ); + if( FAILED( r ) ) + { + WARN("Failed to SetSize\n"); + goto end; + } + + pos.QuadPart = 0; + r = IStream_Seek( stm, pos, STREAM_SEEK_SET, NULL ); + if( FAILED( r ) ) + { + WARN("Failed to Seek\n"); + goto end; + } + + r = IStream_Write(stm, data, sz, &count ); + if( FAILED( r ) || ( count != sz ) ) + { + WARN("Failed to Write\n"); + goto end; + } + + ret = ERROR_SUCCESS; + +end: + IStream_Release( stm ); + + return ret; +} + +UINT read_table_from_storage( MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable) +{ + MSITABLE *t; + USHORT *rawdata = NULL; + UINT rawsize = 0, r, i, j, row_size = 0, num_cols = 0; + MSICOLUMNINFO *cols, *last_col; + + TRACE("%s\n",debugstr_w(name)); + + /* nonexistent tables should be interpreted as empty tables */ + t = HeapAlloc( GetProcessHeap(), 0, + sizeof (MSITABLE) + lstrlenW(name)*sizeof (WCHAR) ); + if( !t ) + return ERROR_NOT_ENOUGH_MEMORY; + + r = table_get_column_info( db, name, &cols, &num_cols ); + if( r != ERROR_SUCCESS ) + { + HeapFree( GetProcessHeap(), 0, t ); + return r; + } + last_col = &cols[num_cols-1]; + row_size = last_col->offset + bytes_per_column( last_col ); + + t->row_count = 0; + t->data = NULL; + lstrcpyW( t->name, name ); + t->ref_count = 1; + *ptable = t; + + /* if we can't read the table, just assume that it's empty */ + read_stream_data( db->storage, name, &rawdata, &rawsize ); + if( !rawdata ) + return ERROR_SUCCESS; + + TRACE("Read %d bytes\n", rawsize ); + + if( rawsize % row_size ) + { + WARN("Table size is invalid %d/%d\n", rawsize, row_size ); + return ERROR_FUNCTION_FAILED; + } + + t->row_count = rawsize / row_size; + t->data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, + t->row_count * sizeof (USHORT*) ); + if( !t->data ) + return ERROR_NOT_ENOUGH_MEMORY; /* FIXME: memory leak */ + + /* transpose all the data */ + TRACE("Transposing data from %d columns\n", t->row_count ); + for( i=0; i<t->row_count; i++ ) + { + t->data[i] = HeapAlloc( GetProcessHeap(), 0, row_size ); + if( !t->data[i] ) + return ERROR_NOT_ENOUGH_MEMORY; /* FIXME: memory leak */ + for( j=0; j<num_cols; j++ ) + { + UINT ofs = cols[j].offset/2; + UINT n = bytes_per_column( &cols[j] ); + + switch( n ) + { + case 2: + t->data[i][ofs] = rawdata[ofs*t->row_count + i ]; + break; + case 4: + t->data[i][ofs] = rawdata[ofs*t->row_count + i*2 ]; + t->data[i][ofs+1] = rawdata[ofs*t->row_count + i*2 + 1]; + break; + default: + ERR("oops - unknown column width %d\n", n); + return ERROR_FUNCTION_FAILED; + } + } + } + + HeapFree( GetProcessHeap(), 0, cols ); + HeapFree( GetProcessHeap(), 0, rawdata ); + + return ERROR_SUCCESS; +} + +/* add this table to the list of cached tables in the database */ +void add_table(MSIDATABASE *db, MSITABLE *table) +{ + table->next = db->first_table; + table->prev = NULL; + if( db->first_table ) + db->first_table->prev = table; + else + db->last_table = table; + db->first_table = table; +} + +/* remove from the list of cached tables */ +void remove_table( MSIDATABASE *db, MSITABLE *table ) +{ + if( table->next ) + table->next->prev = table->prev; + else + db->last_table = table->prev; + if( table->prev ) + table->prev->next = table->next; + else + db->first_table = table->next; + table->next = NULL; + table->prev = NULL; +} + +void release_table( MSIDATABASE *db, MSITABLE *table ) +{ + if( !table->ref_count ) + ERR("Trying to destroy table with refcount 0\n"); + table->ref_count --; + if( !table->ref_count ) + { + remove_table( db, table ); + HeapFree( GetProcessHeap(), 0, table->data ); + HeapFree( GetProcessHeap(), 0, table ); + TRACE("Destroyed table %s\n", debugstr_w(table->name)); + } +} + +void free_cached_tables( MSIDATABASE *db ) +{ + while( db->first_table ) + { + MSITABLE *t = db->first_table; + + if ( --t->ref_count ) + ERR("table ref count not zero for %s\n", debugstr_w(t->name)); + remove_table( db, t ); + HeapFree( GetProcessHeap(), 0, t->data ); + HeapFree( GetProcessHeap(), 0, t ); + } +} + +UINT find_cached_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable) +{ + MSITABLE *t; + + for( t = db->first_table; t; t=t->next ) + { + if( !lstrcmpW( name, t->name ) ) + { + *ptable = t; + return ERROR_SUCCESS; + } + } + + return ERROR_FUNCTION_FAILED; +} + +static UINT table_get_column_info( MSIDATABASE *db, LPCWSTR name, MSICOLUMNINFO **pcols, UINT *pcount ) +{ + UINT r, column_count; + MSICOLUMNINFO *columns; + + /* get the number of columns in this table */ + column_count = 0; + r = get_tablecolumns( db, name, NULL, &column_count ); + if( r != ERROR_SUCCESS ) + return r; + + /* if there's no columns, there's no table */ + if( column_count == 0 ) + return ERROR_INVALID_PARAMETER; + + TRACE("Table %s found\n", debugstr_w(name) ); + + columns = HeapAlloc( GetProcessHeap(), 0, column_count*sizeof (MSICOLUMNINFO)); + if( !columns ) + return ERROR_FUNCTION_FAILED; + + r = get_tablecolumns( db, name, columns, &column_count ); + if( r != ERROR_SUCCESS ) + { + HeapFree( GetProcessHeap(), 0, columns ); + return ERROR_FUNCTION_FAILED; + } + + *pcols = columns; + *pcount = column_count; + + return r; +} + +UINT get_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable) +{ + UINT r; + + *ptable = NULL; + + /* first, see if the table is cached */ + r = find_cached_table( db, name, ptable ); + if( r == ERROR_SUCCESS ) + { + (*ptable)->ref_count++; + return r; + } + + r = read_table_from_storage( db, name, ptable ); + if( r != ERROR_SUCCESS ) + return r; + + /* add the table to the list */ + add_table( db, *ptable ); + (*ptable)->ref_count++; + + return ERROR_SUCCESS; +} + +UINT save_table( MSIDATABASE *db, MSITABLE *t ) +{ + USHORT *rawdata = NULL, *p; + UINT rawsize, r, i, j, row_size, num_cols = 0; + MSICOLUMNINFO *cols, *last_col; + + TRACE("Saving %s\n", debugstr_w( t->name ) ); + + r = table_get_column_info( db, t->name, &cols, &num_cols ); + if( r != ERROR_SUCCESS ) + return r; + + last_col = &cols[num_cols-1]; + row_size = last_col->offset + bytes_per_column( last_col ); + + rawsize = t->row_count * row_size; + rawdata = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, rawsize ); + if( !rawdata ) + return ERROR_NOT_ENOUGH_MEMORY; + + p = rawdata; + for( i=0; i<num_cols; i++ ) + { + for( j=0; j<t->row_count; j++ ) + { + UINT offset = cols[i].offset; + + *p++ = t->data[j][offset/2]; + if( 4 == bytes_per_column( &cols[i] ) ) + *p++ = t->data[j][offset/2+1]; + } + } + + TRACE("writing %d bytes\n", rawsize); + r = write_stream_data( db->storage, t->name, rawdata, rawsize ); + + HeapFree( GetProcessHeap(), 0, rawdata ); + + return r; +} + +HRESULT init_string_table( IStorage *stg ) +{ + HRESULT r; + static const WCHAR szStringData[] = { + '_','S','t','r','i','n','g','D','a','t','a',0 }; + static const WCHAR szStringPool[] = { + '_','S','t','r','i','n','g','P','o','o','l',0 }; + USHORT zero[2] = { 0, 0 }; + ULONG count = 0; + IStream *stm = NULL; + LPWSTR encname; + + encname = encode_streamname(TRUE, szStringPool ); + + /* create the StringPool stream... add the zero string to it*/ + r = IStorage_CreateStream( stg, encname, + STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm); + HeapFree( GetProcessHeap(), 0, encname ); + if( r ) + { + TRACE("Failed\n"); + return r; + } + + r = IStream_Write(stm, zero, sizeof zero, &count ); + IStream_Release( stm ); + + if( FAILED( r ) || ( count != sizeof zero ) ) + { + TRACE("Failed\n"); + return E_FAIL; + } + + /* create the StringData stream... make it zero length */ + encname = encode_streamname(TRUE, szStringData ); + r = IStorage_CreateStream( stg, encname, + STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm); + HeapFree( GetProcessHeap(), 0, encname ); + if( r ) + { + TRACE("Failed\n"); + return E_FAIL; + } + IStream_Release( stm ); + + return r; +} + +UINT load_string_table( MSIDATABASE *db ) +{ + CHAR *data; + USHORT *pool; + UINT r, ret = ERROR_FUNCTION_FAILED, datasize = 0, poolsize = 0, codepage; + DWORD i, count, offset, len, n; + static const WCHAR szStringData[] = { + '_','S','t','r','i','n','g','D','a','t','a',0 }; + static const WCHAR szStringPool[] = { + '_','S','t','r','i','n','g','P','o','o','l',0 }; + + if( db->strings ) + { + msi_destroy_stringtable( db->strings ); + db->strings = NULL; + } + + r = read_stream_data( db->storage, szStringPool, &pool, &poolsize ); + if( r != ERROR_SUCCESS) + goto end; + r = read_stream_data( db->storage, szStringData, (USHORT**)&data, &datasize ); + if( r != ERROR_SUCCESS) + goto end; + + count = poolsize/4; + if( poolsize > 4 ) + codepage = pool[0] | ( pool[1] << 16 ); + else + codepage = CP_ACP; + db->strings = msi_init_stringtable( count, codepage ); + + offset = 0; + for( i=1; i<count; i++ ) + { + len = pool[i*2]; + n = msi_addstring( db->strings, i, data+offset, len, pool[i*2+1] ); + if( n != i ) + ERR("Failed to add string %ld\n", i ); + offset += len; + } + + TRACE("Loaded %ld strings\n", count); + + ret = ERROR_SUCCESS; + +end: + HeapFree( GetProcessHeap(), 0, pool ); + HeapFree( GetProcessHeap(), 0, data ); + + return ret; +} + +UINT save_string_table( MSIDATABASE *db ) +{ + UINT i, count, datasize, poolsize, sz, used, r, codepage; + UINT ret = ERROR_FUNCTION_FAILED; + static const WCHAR szStringData[] = { + '_','S','t','r','i','n','g','D','a','t','a',0 }; + static const WCHAR szStringPool[] = { + '_','S','t','r','i','n','g','P','o','o','l',0 }; + CHAR *data = NULL; + USHORT *pool = NULL; + + TRACE("\n"); + + /* construct the new table in memory first */ + datasize = msi_string_totalsize( db->strings, &count ); + poolsize = count*2*sizeof(USHORT); + + pool = HeapAlloc( GetProcessHeap(), 0, poolsize ); + if( ! pool ) + { + WARN("Failed to alloc pool %d bytes\n", poolsize ); + goto err; + } + data = HeapAlloc( GetProcessHeap(), 0, datasize ); + if( ! data ) + { + WARN("Failed to alloc data %d bytes\n", poolsize ); + goto err; + } + + used = 0; + codepage = msi_string_get_codepage( db->strings ); + pool[0]=codepage&0xffff; + pool[1]=(codepage>>16); + for( i=1; i<count; i++ ) + { + sz = datasize - used; + r = msi_id2stringA( db->strings, i, data+used, &sz ); + if( r != ERROR_SUCCESS ) + { + ERR("failed to fetch string\n"); + sz = 0; + } + if( sz && (sz < (datasize - used ) ) ) + sz--; + TRACE("adding %u bytes %s\n", sz, data+used ); + pool[ i*2 ] = sz; + pool[ i*2 + 1 ] = msi_id_refcount( db->strings, i ); + used += sz; + if( used > datasize ) + { + ERR("oops overran %d >= %d\n", used, datasize); + goto err; + } + } + + if( used != datasize ) + { + ERR("oops used %d != datasize %d\n", used, datasize); + goto err; + } + + /* write the streams */ + r = write_stream_data( db->storage, szStringData, data, datasize ); + TRACE("Wrote StringData r=%08x\n", r); + if( r ) + goto err; + r = write_stream_data( db->storage, szStringPool, pool, poolsize ); + TRACE("Wrote StringPool r=%08x\n", r); + if( r ) + goto err; + + ret = ERROR_SUCCESS; + +err: + HeapFree( GetProcessHeap(), 0, data ); + HeapFree( GetProcessHeap(), 0, pool ); + + return ret; +} + +/* information for default tables */ +static const WCHAR szTables[] = { '_','T','a','b','l','e','s',0 }; +static const WCHAR szTable[] = { 'T','a','b','l','e',0 }; +static const WCHAR szName[] = { 'N','a','m','e',0 }; +static const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 }; +static const WCHAR szColumn[] = { 'C','o','l','u','m','n',0 }; +static const WCHAR szNumber[] = { 'N','u','m','b','e','r',0 }; +static const WCHAR szType[] = { 'T','y','p','e',0 }; + +struct standard_table { + LPCWSTR tablename; + LPCWSTR columnname; + UINT number; + UINT type; +} MSI_standard_tables[] = +{ + { szTables, szName, 1, MSITYPE_VALID | MSITYPE_STRING | 32}, + { szColumns, szTable, 1, MSITYPE_VALID | MSITYPE_STRING | 32}, + { szColumns, szNumber, 2, MSITYPE_VALID | 2}, + { szColumns, szName, 3, MSITYPE_VALID | MSITYPE_STRING | 32}, + { szColumns, szType, 4, MSITYPE_VALID | 2}, +}; + +#define STANDARD_TABLE_COUNT \ + (sizeof(MSI_standard_tables)/sizeof(struct standard_table)) + +UINT get_defaulttablecolumns( LPCWSTR szTable, MSICOLUMNINFO *colinfo, UINT *sz) +{ + DWORD i, n=0; + + for(i=0; i<STANDARD_TABLE_COUNT; i++) + { + if( lstrcmpW( szTable, MSI_standard_tables[i].tablename ) ) + continue; + if(colinfo && (n < *sz) ) + { + colinfo[n].tablename = strdupW(MSI_standard_tables[i].tablename); + colinfo[n].colname = strdupW(MSI_standard_tables[i].columnname); + colinfo[n].number = MSI_standard_tables[i].number; + colinfo[n].type = MSI_standard_tables[i].type; + /* ERR("Table %s has column %s\n",debugstr_w(colinfo[n].tablename), + debugstr_w(colinfo[n].colname)); */ + if( n ) + colinfo[n].offset = colinfo[n-1].offset + + bytes_per_column( &colinfo[n-1] ); + else + colinfo[n].offset = 0; + } + n++; + if( colinfo && (n >= *sz) ) + break; + } + *sz = n; + return ERROR_SUCCESS; +} + +LPWSTR MSI_makestring( MSIDATABASE *db, UINT stringid) +{ + UINT sz=0, r; + LPWSTR str; + + r = msi_id2stringW( db->strings, stringid, NULL, &sz ); + if( r != ERROR_SUCCESS ) + return NULL; + str = HeapAlloc( GetProcessHeap(), 0, sz*sizeof (WCHAR)); + if( !str ) + return str; + r = msi_id2stringW( db->strings, stringid, str, &sz ); + if( r == ERROR_SUCCESS ) + return str; + HeapFree( GetProcessHeap(), 0, str ); + return NULL; +} + +static UINT get_tablecolumns( MSIDATABASE *db, + LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz) +{ + UINT r, i, n=0, table_id, count, maxcount = *sz; + MSITABLE *table = NULL; + static const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 }; + + /* first check if there is a default table with that name */ + r = get_defaulttablecolumns( szTableName, colinfo, sz ); + if( ( r == ERROR_SUCCESS ) && *sz ) + return r; + + r = get_table( db, szColumns, &table); + if( r != ERROR_SUCCESS ) + { + WARN("table %s not available\n", debugstr_w(szColumns)); + return r; + } + + /* convert table and column names to IDs from the string table */ + r = msi_string2idW( db->strings, szTableName, &table_id ); + if( r != ERROR_SUCCESS ) + { + release_table( db, table ); + WARN("Couldn't find id for %s\n", debugstr_w(szTableName)); + return r; + } + + TRACE("Table id is %d\n", table_id); + + count = table->row_count; + for( i=0; i<count; i++ ) + { + if( table->data[ i ][ 0 ] != table_id ) + continue; + if( colinfo ) + { + UINT id = table->data[ i ] [ 2 ]; + colinfo[n].tablename = MSI_makestring( db, table_id ); + colinfo[n].number = table->data[ i ][ 1 ] - (1<<15); + colinfo[n].colname = MSI_makestring( db, id ); + colinfo[n].type = table->data[ i ] [ 3 ]; + /* this assumes that columns are in order in the table */ + if( n ) + colinfo[n].offset = colinfo[n-1].offset + + bytes_per_column( &colinfo[n-1] ); + else + colinfo[n].offset = 0; + TRACE("table %s column %d is [%s] (%d) with type %08x " + "offset %d at row %d\n", debugstr_w(szTableName), + colinfo[n].number, debugstr_w(colinfo[n].colname), + id, colinfo[n].type, colinfo[n].offset, i); + if( n != (colinfo[n].number-1) ) + { + ERR("oops. data in the _Columns table isn't in the right " + "order for table %s\n", debugstr_w(szTableName)); + return ERROR_FUNCTION_FAILED; + } + } + n++; + if( colinfo && ( n >= maxcount ) ) + break; + } + *sz = n; + + release_table( db, table ); + + return ERROR_SUCCESS; +} + +/* try to find the table name in the _Tables table */ +BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name ) +{ + static const WCHAR szTables[] = { '_','T','a','b','l','e','s',0 }; + static const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 }; + UINT r, table_id = 0, i, count; + MSITABLE *table = NULL; + + if( !lstrcmpW( name, szTables ) ) + return TRUE; + if( !lstrcmpW( name, szColumns ) ) + return TRUE; + + r = msi_string2idW( db->strings, name, &table_id ); + if( r != ERROR_SUCCESS ) + { + TRACE("Couldn't find id for %s\n", debugstr_w(name)); + return FALSE; + } + + r = get_table( db, szTables, &table); + if( r != ERROR_SUCCESS ) + { + TRACE("table %s not available\n", debugstr_w(szTables)); + return FALSE; + } + + /* count = table->size/2; */ + count = table->row_count; + for( i=0; i<count; i++ ) + if( table->data[ i ][ 0 ] == table_id ) + break; + + release_table( db, table ); + + if (i!=count) + return TRUE; + + TRACE("Searched %d tables, but %d was not found\n", count, table_id ); + + return FALSE; +} + +/* below is the query interface to a table */ + +typedef struct tagMSITABLEVIEW +{ + MSIVIEW view; + MSIDATABASE *db; + MSITABLE *table; + MSICOLUMNINFO *columns; + UINT num_cols; + UINT row_size; + WCHAR name[1]; +} MSITABLEVIEW; + +static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) +{ + MSITABLEVIEW *tv = (MSITABLEVIEW*)view; + UINT offset, num_rows, n; + + if( !tv->table ) + return ERROR_INVALID_PARAMETER; + + if( (col==0) || (col>tv->num_cols) ) + return ERROR_INVALID_PARAMETER; + + /* how many rows are there ? */ + num_rows = tv->table->row_count; + if( row >= num_rows ) + return ERROR_NO_MORE_ITEMS; + + if( tv->columns[col-1].offset >= tv->row_size ) + { + ERR("Stuffed up %d >= %d\n", tv->columns[col-1].offset, tv->row_size ); + ERR("%p %p\n", tv, tv->columns ); + return ERROR_FUNCTION_FAILED; + } + + offset = row + (tv->columns[col-1].offset/2) * num_rows; + n = bytes_per_column( &tv->columns[col-1] ); + switch( n ) + { + case 4: + offset = tv->columns[col-1].offset/2; + *val = tv->table->data[row][offset] + + (tv->table->data[row][offset + 1] << 16); + break; + case 2: + offset = tv->columns[col-1].offset/2; + *val = tv->table->data[row][offset]; + break; + default: + ERR("oops! what is %d bytes per column?\n", n ); + return ERROR_FUNCTION_FAILED; + } + + /* TRACE("Data [%d][%d] = %d \n", row, col, *val ); */ + + return ERROR_SUCCESS; +} + +/* + * We need a special case for streams, as we need to reference column with + * the name of the stream in the same table, and the table name + * which may not be available at higher levels of the query + */ +static UINT TABLE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm ) +{ + MSITABLEVIEW *tv = (MSITABLEVIEW*)view; + UINT ival = 0, refcol = 0, r; + LPWSTR sval; + LPWSTR full_name; + DWORD len; + static const WCHAR szDot[] = { '.', 0 }; + + if( !view->ops->fetch_int ) + return ERROR_INVALID_PARAMETER; + + /* + * The column marked with the type stream data seems to have a single number + * which references the column containing the name of the stream data + * + * Fetch the column to reference first. + */ + r = view->ops->fetch_int( view, row, col, &ival ); + if( r != ERROR_SUCCESS ) + return r; + + /* now get the column with the name of the stream */ + r = view->ops->fetch_int( view, row, ival, &refcol ); + if( r != ERROR_SUCCESS ) + return r; + + /* lookup the string value from the string table */ + sval = MSI_makestring( tv->db, refcol ); + if( !sval ) + return ERROR_INVALID_PARAMETER; + + len = lstrlenW( tv->name ) + 2 + lstrlenW( sval ); + full_name = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); + lstrcpyW( full_name, tv->name ); + lstrcatW( full_name, szDot ); + lstrcatW( full_name, sval ); + + r = db_get_raw_stream( tv->db, full_name, stm ); + if( r ) + ERR("fetching stream %s, error = %d\n",debugstr_w(full_name), r); + HeapFree( GetProcessHeap(), 0, full_name ); + HeapFree( GetProcessHeap(), 0, sval ); + + return r; +} + +static UINT TABLE_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val ) +{ + MSITABLEVIEW *tv = (MSITABLEVIEW*)view; + UINT offset, n; + + if( !tv->table ) + return ERROR_INVALID_PARAMETER; + + if( (col==0) || (col>tv->num_cols) ) + return ERROR_INVALID_PARAMETER; + + if( tv->columns[col-1].offset >= tv->row_size ) + { + ERR("Stuffed up %d >= %d\n", tv->columns[col-1].offset, tv->row_size ); + ERR("%p %p\n", tv, tv->columns ); + return ERROR_FUNCTION_FAILED; + } + + n = bytes_per_column( &tv->columns[col-1] ); + switch( n ) + { + case 4: + offset = tv->columns[col-1].offset/2; + tv->table->data[row][offset] = val & 0xffff; + tv->table->data[row][offset + 1] = (val>>16)&0xffff; + break; + case 2: + offset = tv->columns[col-1].offset/2; + tv->table->data[row][offset] = val; + break; + default: + ERR("oops! what is %d bytes per column?\n", n ); + return ERROR_FUNCTION_FAILED; + } + return ERROR_SUCCESS; +} + +UINT TABLE_insert_row( struct tagMSIVIEW *view, UINT *num ) +{ + MSITABLEVIEW *tv = (MSITABLEVIEW*)view; + USHORT **p, *row; + UINT sz; + + TRACE("%p\n", view); + + if( !tv->table ) + return ERROR_INVALID_PARAMETER; + + row = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, tv->row_size ); + if( !row ) + return ERROR_NOT_ENOUGH_MEMORY; + + sz = (tv->table->row_count + 1) * sizeof (UINT*); + if( tv->table->data ) + p = HeapReAlloc( GetProcessHeap(), 0, tv->table->data, sz ); + else + p = HeapAlloc( GetProcessHeap(), 0, sz ); + if( !p ) + { + HeapFree( GetProcessHeap(), 0, row ); + return ERROR_NOT_ENOUGH_MEMORY; + } + + tv->table->data = p; + tv->table->data[tv->table->row_count] = row; + *num = tv->table->row_count; + tv->table->row_count++; + + return ERROR_SUCCESS; +} + +static UINT TABLE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) +{ + MSITABLEVIEW *tv = (MSITABLEVIEW*)view; + UINT r; + + TRACE("%p %p\n", tv, record); + + if( tv->table ) + { + release_table( tv->db, tv->table ); + tv->table = NULL; + } + + r = get_table( tv->db, tv->name, &tv->table ); + if( r != ERROR_SUCCESS ) + return r; + + return ERROR_SUCCESS; +} + +static UINT TABLE_close( struct tagMSIVIEW *view ) +{ + MSITABLEVIEW *tv = (MSITABLEVIEW*)view; + + TRACE("%p\n", view ); + + if( !tv->table ) + return ERROR_FUNCTION_FAILED; + + release_table( tv->db, tv->table ); + tv->table = NULL; + + return ERROR_SUCCESS; +} + +static UINT TABLE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols) +{ + MSITABLEVIEW *tv = (MSITABLEVIEW*)view; + + TRACE("%p %p %p\n", view, rows, cols ); + + if( cols ) + *cols = tv->num_cols; + if( rows ) + { + if( !tv->table ) + return ERROR_INVALID_PARAMETER; + *rows = tv->table->row_count; + } + + return ERROR_SUCCESS; +} + +static UINT TABLE_get_column_info( struct tagMSIVIEW *view, + UINT n, LPWSTR *name, UINT *type ) +{ + MSITABLEVIEW *tv = (MSITABLEVIEW*)view; + + TRACE("%p %d %p %p\n", tv, n, name, type ); + + if( ( n == 0 ) || ( n > tv->num_cols ) ) + return ERROR_INVALID_PARAMETER; + + if( name ) + { + *name = strdupW( tv->columns[n-1].colname ); + if( !*name ) + return ERROR_FUNCTION_FAILED; + } + if( type ) + *type = tv->columns[n-1].type; + + return ERROR_SUCCESS; +} + +static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, + MSIRECORD *rec) +{ + FIXME("%p %d %p\n", view, eModifyMode, rec ); + return ERROR_CALL_NOT_IMPLEMENTED; +} + +static UINT TABLE_delete( struct tagMSIVIEW *view ) +{ + MSITABLEVIEW *tv = (MSITABLEVIEW*)view; + + TRACE("%p\n", view ); + + if( tv->table ) + release_table( tv->db, tv->table ); + tv->table = NULL; + + if( tv->columns ) + { + UINT i; + for( i=0; i<tv->num_cols; i++) + { + HeapFree( GetProcessHeap(), 0, tv->columns[i].colname ); + HeapFree( GetProcessHeap(), 0, tv->columns[i].tablename ); + } + HeapFree( GetProcessHeap(), 0, tv->columns ); + } + tv->columns = NULL; + + HeapFree( GetProcessHeap(), 0, tv ); + + return ERROR_SUCCESS; +} + + +MSIVIEWOPS table_ops = +{ + TABLE_fetch_int, + TABLE_fetch_stream, + TABLE_set_int, + TABLE_insert_row, + TABLE_execute, + TABLE_close, + TABLE_get_dimensions, + TABLE_get_column_info, + TABLE_modify, + TABLE_delete +}; + +UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view ) +{ + MSITABLEVIEW *tv ; + UINT r, sz, column_count; + MSICOLUMNINFO *columns, *last_col; + + TRACE("%p %s %p\n", db, debugstr_w(name), view ); + + /* get the number of columns in this table */ + column_count = 0; + r = get_tablecolumns( db, name, NULL, &column_count ); + if( r != ERROR_SUCCESS ) + return r; + + /* if there's no columns, there's no table */ + if( column_count == 0 ) + return ERROR_INVALID_PARAMETER; + + TRACE("Table found\n"); + + sz = sizeof *tv + lstrlenW(name)*sizeof name[0] ; + tv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sz ); + if( !tv ) + return ERROR_FUNCTION_FAILED; + + columns = HeapAlloc( GetProcessHeap(), 0, column_count*sizeof (MSICOLUMNINFO)); + if( !columns ) + { + HeapFree( GetProcessHeap(), 0, tv ); + return ERROR_FUNCTION_FAILED; + } + + r = get_tablecolumns( db, name, columns, &column_count ); + if( r != ERROR_SUCCESS ) + { + HeapFree( GetProcessHeap(), 0, columns ); + HeapFree( GetProcessHeap(), 0, tv ); + return ERROR_FUNCTION_FAILED; + } + + TRACE("Table has %d columns\n", column_count); + + last_col = &columns[column_count-1]; + + /* fill the structure */ + tv->view.ops = &table_ops; + tv->db = db; + tv->columns = columns; + tv->num_cols = column_count; + tv->table = NULL; + tv->row_size = last_col->offset + bytes_per_column( last_col ); + + TRACE("one row is %d bytes\n", tv->row_size ); + + *view = (MSIVIEW*) tv; + lstrcpyW( tv->name, name ); + + return ERROR_SUCCESS; +} + +UINT MSI_CommitTables( MSIDATABASE *db ) +{ + UINT r; + MSITABLE *table = NULL; + + TRACE("%p\n",db); + + r = save_string_table( db ); + if( r != ERROR_SUCCESS ) + { + WARN("failed to save string table r=%08x\n",r); + return r; + } + + for( table = db->first_table; table; table = table->next ) + { + r = save_table( db, table ); + if( r != ERROR_SUCCESS ) + { + WARN("failed to save table %s (r=%08x)\n", + debugstr_w(table->name), r); + return r; + } + } + + /* force everything to reload next time */ + free_cached_tables( db ); + + return ERROR_SUCCESS; +} diff --git a/reactos/lib/msi/tokenize.c b/reactos/lib/msi/tokenize.c index 223414eb47b..315bac9a670 100644 --- a/reactos/lib/msi/tokenize.c +++ b/reactos/lib/msi/tokenize.c @@ -1,400 +1,400 @@ -/* -** 2001 September 15 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** An tokenizer for SQL -** -** This file contains C code that splits an SQL input string up into -** individual tokens and sends those tokens one-by-one over to the -** parser for analysis. -*/ - -#include <ctype.h> -#include <stdarg.h> -#include <stdlib.h> - -#include "windef.h" -#include "winbase.h" -#include "wine/debug.h" -#include "winnls.h" -#include "query.h" -#include "sql.tab.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - -/* -** All the keywords of the SQL language are stored as in a hash -** table composed of instances of the following structure. -*/ -typedef struct Keyword Keyword; -struct Keyword { - const char *zName; /* The keyword name */ - int tokenType; /* The token value for this keyword */ -}; - -/* -** These are the keywords -*/ -static const Keyword aKeywordTable[] = { - { "ABORT", TK_ABORT }, - { "AFTER", TK_AFTER }, - { "ALL", TK_ALL }, - { "AND", TK_AND }, - { "AS", TK_AS }, - { "ASC", TK_ASC }, - { "BEFORE", TK_BEFORE }, - { "BEGIN", TK_BEGIN }, - { "BETWEEN", TK_BETWEEN }, - { "BY", TK_BY }, - { "CASCADE", TK_CASCADE }, - { "CASE", TK_CASE }, - { "CHAR", TK_CHAR }, - { "CHARACTER", TK_CHAR }, - { "CHECK", TK_CHECK }, - { "CLUSTER", TK_CLUSTER }, - { "COLLATE", TK_COLLATE }, - { "COMMIT", TK_COMMIT }, - { "CONFLICT", TK_CONFLICT }, - { "CONSTRAINT", TK_CONSTRAINT }, - { "COPY", TK_COPY }, - { "CREATE", TK_CREATE }, - { "CROSS", TK_JOIN_KW }, - { "DEFAULT", TK_DEFAULT }, - { "DEFERRED", TK_DEFERRED }, - { "DEFERRABLE", TK_DEFERRABLE }, - { "DELETE", TK_DELETE }, - { "DELIMITERS", TK_DELIMITERS }, - { "DESC", TK_DESC }, - { "DISTINCT", TK_DISTINCT }, - { "DROP", TK_DROP }, - { "END", TK_END }, - { "EACH", TK_EACH }, - { "ELSE", TK_ELSE }, - { "EXCEPT", TK_EXCEPT }, - { "EXPLAIN", TK_EXPLAIN }, - { "FAIL", TK_FAIL }, - { "FOR", TK_FOR }, - { "FOREIGN", TK_FOREIGN }, - { "FROM", TK_FROM }, - { "FULL", TK_JOIN_KW }, - { "GLOB", TK_GLOB }, - { "GROUP", TK_GROUP }, - { "HAVING", TK_HAVING }, - { "HOLD", TK_HOLD }, - { "IGNORE", TK_IGNORE }, - { "IMMEDIATE", TK_IMMEDIATE }, - { "IN", TK_IN }, - { "INDEX", TK_INDEX }, - { "INITIALLY", TK_INITIALLY }, - { "INNER", TK_JOIN_KW }, - { "INSERT", TK_INSERT }, - { "INSTEAD", TK_INSTEAD }, - { "INT", TK_INT }, - { "INTERSECT", TK_INTERSECT }, - { "INTO", TK_INTO }, - { "IS", TK_IS }, - { "ISNULL", TK_ISNULL }, - { "JOIN", TK_JOIN }, - { "KEY", TK_KEY }, - { "LEFT", TK_JOIN_KW }, - { "LIKE", TK_LIKE }, - { "LIMIT", TK_LIMIT }, - { "LOCALIZABLE", TK_LOCALIZABLE }, - { "LONG", TK_LONG }, - { "LONGCHAR", TK_LONGCHAR }, - { "MATCH", TK_MATCH }, - { "NATURAL", TK_JOIN_KW }, - { "NOT", TK_NOT }, - { "NOTNULL", TK_NOTNULL }, - { "NULL", TK_NULL }, - { "OBJECT", TK_OBJECT }, - { "OF", TK_OF }, - { "OFFSET", TK_OFFSET }, - { "ON", TK_ON }, - { "OR", TK_OR }, - { "ORDER", TK_ORDER }, - { "OUTER", TK_JOIN_KW }, - { "PRAGMA", TK_PRAGMA }, - { "PRIMARY", TK_PRIMARY }, - { "RAISE", TK_RAISE }, - { "REFERENCES", TK_REFERENCES }, - { "REPLACE", TK_REPLACE }, - { "RESTRICT", TK_RESTRICT }, - { "RIGHT", TK_JOIN_KW }, - { "ROLLBACK", TK_ROLLBACK }, - { "ROW", TK_ROW }, - { "SELECT", TK_SELECT }, - { "SET", TK_SET }, - { "SHORT", TK_SHORT }, - { "STATEMENT", TK_STATEMENT }, - { "TABLE", TK_TABLE }, - { "TEMP", TK_TEMP }, - { "TEMPORARY", TK_TEMP }, - { "THEN", TK_THEN }, - { "TRANSACTION", TK_TRANSACTION }, - { "TRIGGER", TK_TRIGGER }, - { "UNION", TK_UNION }, - { "UNIQUE", TK_UNIQUE }, - { "UPDATE", TK_UPDATE }, - { "USING", TK_USING }, - { "VACUUM", TK_VACUUM }, - { "VALUES", TK_VALUES }, - { "VIEW", TK_VIEW }, - { "WHEN", TK_WHEN }, - { "WHERE", TK_WHERE }, -}; - -#define KEYWORD_COUNT ( sizeof aKeywordTable/sizeof (Keyword) ) - -/* -** This function looks up an identifier to determine if it is a -** keyword. If it is a keyword, the token code of that keyword is -** returned. If the input is not a keyword, TK_ID is returned. -*/ -int sqliteKeywordCode(const WCHAR *z, int n){ - UINT i, len; - char buffer[0x10]; - - len = WideCharToMultiByte( CP_ACP, 0, z, n, buffer, sizeof buffer, NULL, NULL ); - for(i=0; i<len; i++) - buffer[i] = toupper(buffer[i]); - for(i=0; i<KEYWORD_COUNT; i++) - { - if(memcmp(buffer, aKeywordTable[i].zName, len)) - continue; - if(strlen(aKeywordTable[i].zName) == len ) - return aKeywordTable[i].tokenType; - } - return TK_ID; -} - - -/* -** If X is a character that can be used in an identifier then -** isIdChar[X] will be 1. Otherwise isIdChar[X] will be 0. -** -** In this implementation, an identifier can be a string of -** alphabetic characters, digits, and "_" plus any character -** with the high-order bit set. The latter rule means that -** any sequence of UTF-8 characters or characters taken from -** an extended ISO8859 character set can form an identifier. -*/ -static const char isIdChar[] = { -/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */ - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8x */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9x */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Ax */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Bx */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Cx */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Dx */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Ex */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Fx */ -}; - - -/* -** Return the length of the token that begins at z[0]. Return -** -1 if the token is (or might be) incomplete. Store the token -** type in *tokenType before returning. -*/ -int sqliteGetToken(const WCHAR *z, int *tokenType){ - int i; - switch( *z ){ - case ' ': case '\t': case '\n': case '\f': case '\r': { - for(i=1; isspace(z[i]); i++){} - *tokenType = TK_SPACE; - return i; - } - case '-': { - if( z[1]==0 ) return -1; - if( z[1]=='-' ){ - for(i=2; z[i] && z[i]!='\n'; i++){} - *tokenType = TK_COMMENT; - return i; - } - *tokenType = TK_MINUS; - return 1; - } - case '(': { - if( z[1]=='+' && z[2]==')' ){ - *tokenType = TK_ORACLE_OUTER_JOIN; - return 3; - }else{ - *tokenType = TK_LP; - return 1; - } - } - case ')': { - *tokenType = TK_RP; - return 1; - } - case ';': { - *tokenType = TK_SEMI; - return 1; - } - case '+': { - *tokenType = TK_PLUS; - return 1; - } - case '*': { - *tokenType = TK_STAR; - return 1; - } - case '/': { - if( z[1]!='*' || z[2]==0 ){ - *tokenType = TK_SLASH; - return 1; - } - for(i=3; z[i] && (z[i]!='/' || z[i-1]!='*'); i++){} - if( z[i] ) i++; - *tokenType = TK_COMMENT; - return i; - } - case '%': { - *tokenType = TK_REM; - return 1; - } - case '=': { - *tokenType = TK_EQ; - return 1 + (z[1]=='='); - } - case '<': { - if( z[1]=='=' ){ - *tokenType = TK_LE; - return 2; - }else if( z[1]=='>' ){ - *tokenType = TK_NE; - return 2; - }else if( z[1]=='<' ){ - *tokenType = TK_LSHIFT; - return 2; - }else{ - *tokenType = TK_LT; - return 1; - } - } - case '>': { - if( z[1]=='=' ){ - *tokenType = TK_GE; - return 2; - }else if( z[1]=='>' ){ - *tokenType = TK_RSHIFT; - return 2; - }else{ - *tokenType = TK_GT; - return 1; - } - } - case '!': { - if( z[1]!='=' ){ - *tokenType = TK_ILLEGAL; - return 2; - }else{ - *tokenType = TK_NE; - return 2; - } - } - case '|': { - if( z[1]!='|' ){ - *tokenType = TK_BITOR; - return 1; - }else{ - *tokenType = TK_CONCAT; - return 2; - } - } - case '?': { - *tokenType = TK_WILDCARD; - return 1; - } - case ',': { - *tokenType = TK_COMMA; - return 1; - } - case '&': { - *tokenType = TK_BITAND; - return 1; - } - case '~': { - *tokenType = TK_BITNOT; - return 1; - } - case '`': case '\'': case '"': { - int delim = z[0]; - for(i=1; z[i]; i++){ - if( z[i]==delim ){ - if( z[i+1]==delim ){ - i++; - }else{ - break; - } - } - } - if( z[i] ) i++; - if( delim == '`' ) - *tokenType = TK_ID; - else - *tokenType = TK_STRING; - return i; - } - case '.': { - if( !isdigit(z[1]) ){ - *tokenType = TK_DOT; - return 1; - } - /* Fall thru into the next case */ - } - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': { - *tokenType = TK_INTEGER; - for(i=1; isdigit(z[i]); i++){} - if( z[i]=='.' ){ - i++; - while( isdigit(z[i]) ){ i++; } - *tokenType = TK_FLOAT; - } - if( (z[i]=='e' || z[i]=='E') && - ( isdigit(z[i+1]) - || ((z[i+1]=='+' || z[i+1]=='-') && isdigit(z[i+2])) - ) - ){ - i += 2; - while( isdigit(z[i]) ){ i++; } - *tokenType = TK_FLOAT; - }else if( z[0]=='.' ){ - *tokenType = TK_FLOAT; - } - return i; - } - case '[': { - for(i=1; z[i] && z[i-1]!=']'; i++){} - *tokenType = TK_ID; - return i; - } - default: { - if( !isIdChar[*z] ){ - break; - } - for(i=1; isIdChar[z[i]]; i++){} - *tokenType = sqliteKeywordCode(z, i); - return i; - } - } - *tokenType = TK_ILLEGAL; - return 1; -} +/* +** 2001 September 15 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** An tokenizer for SQL +** +** This file contains C code that splits an SQL input string up into +** individual tokens and sends those tokens one-by-one over to the +** parser for analysis. +*/ + +#include <ctype.h> +#include <stdarg.h> +#include <stdlib.h> + +#include "windef.h" +#include "winbase.h" +#include "wine/debug.h" +#include "winnls.h" +#include "query.h" +#include "sql.tab.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + +/* +** All the keywords of the SQL language are stored as in a hash +** table composed of instances of the following structure. +*/ +typedef struct Keyword Keyword; +struct Keyword { + const char *zName; /* The keyword name */ + int tokenType; /* The token value for this keyword */ +}; + +/* +** These are the keywords +*/ +static const Keyword aKeywordTable[] = { + { "ABORT", TK_ABORT }, + { "AFTER", TK_AFTER }, + { "ALL", TK_ALL }, + { "AND", TK_AND }, + { "AS", TK_AS }, + { "ASC", TK_ASC }, + { "BEFORE", TK_BEFORE }, + { "BEGIN", TK_BEGIN }, + { "BETWEEN", TK_BETWEEN }, + { "BY", TK_BY }, + { "CASCADE", TK_CASCADE }, + { "CASE", TK_CASE }, + { "CHAR", TK_CHAR }, + { "CHARACTER", TK_CHAR }, + { "CHECK", TK_CHECK }, + { "CLUSTER", TK_CLUSTER }, + { "COLLATE", TK_COLLATE }, + { "COMMIT", TK_COMMIT }, + { "CONFLICT", TK_CONFLICT }, + { "CONSTRAINT", TK_CONSTRAINT }, + { "COPY", TK_COPY }, + { "CREATE", TK_CREATE }, + { "CROSS", TK_JOIN_KW }, + { "DEFAULT", TK_DEFAULT }, + { "DEFERRED", TK_DEFERRED }, + { "DEFERRABLE", TK_DEFERRABLE }, + { "DELETE", TK_DELETE }, + { "DELIMITERS", TK_DELIMITERS }, + { "DESC", TK_DESC }, + { "DISTINCT", TK_DISTINCT }, + { "DROP", TK_DROP }, + { "END", TK_END }, + { "EACH", TK_EACH }, + { "ELSE", TK_ELSE }, + { "EXCEPT", TK_EXCEPT }, + { "EXPLAIN", TK_EXPLAIN }, + { "FAIL", TK_FAIL }, + { "FOR", TK_FOR }, + { "FOREIGN", TK_FOREIGN }, + { "FROM", TK_FROM }, + { "FULL", TK_JOIN_KW }, + { "GLOB", TK_GLOB }, + { "GROUP", TK_GROUP }, + { "HAVING", TK_HAVING }, + { "HOLD", TK_HOLD }, + { "IGNORE", TK_IGNORE }, + { "IMMEDIATE", TK_IMMEDIATE }, + { "IN", TK_IN }, + { "INDEX", TK_INDEX }, + { "INITIALLY", TK_INITIALLY }, + { "INNER", TK_JOIN_KW }, + { "INSERT", TK_INSERT }, + { "INSTEAD", TK_INSTEAD }, + { "INT", TK_INT }, + { "INTERSECT", TK_INTERSECT }, + { "INTO", TK_INTO }, + { "IS", TK_IS }, + { "ISNULL", TK_ISNULL }, + { "JOIN", TK_JOIN }, + { "KEY", TK_KEY }, + { "LEFT", TK_JOIN_KW }, + { "LIKE", TK_LIKE }, + { "LIMIT", TK_LIMIT }, + { "LOCALIZABLE", TK_LOCALIZABLE }, + { "LONG", TK_LONG }, + { "LONGCHAR", TK_LONGCHAR }, + { "MATCH", TK_MATCH }, + { "NATURAL", TK_JOIN_KW }, + { "NOT", TK_NOT }, + { "NOTNULL", TK_NOTNULL }, + { "NULL", TK_NULL }, + { "OBJECT", TK_OBJECT }, + { "OF", TK_OF }, + { "OFFSET", TK_OFFSET }, + { "ON", TK_ON }, + { "OR", TK_OR }, + { "ORDER", TK_ORDER }, + { "OUTER", TK_JOIN_KW }, + { "PRAGMA", TK_PRAGMA }, + { "PRIMARY", TK_PRIMARY }, + { "RAISE", TK_RAISE }, + { "REFERENCES", TK_REFERENCES }, + { "REPLACE", TK_REPLACE }, + { "RESTRICT", TK_RESTRICT }, + { "RIGHT", TK_JOIN_KW }, + { "ROLLBACK", TK_ROLLBACK }, + { "ROW", TK_ROW }, + { "SELECT", TK_SELECT }, + { "SET", TK_SET }, + { "SHORT", TK_SHORT }, + { "STATEMENT", TK_STATEMENT }, + { "TABLE", TK_TABLE }, + { "TEMP", TK_TEMP }, + { "TEMPORARY", TK_TEMP }, + { "THEN", TK_THEN }, + { "TRANSACTION", TK_TRANSACTION }, + { "TRIGGER", TK_TRIGGER }, + { "UNION", TK_UNION }, + { "UNIQUE", TK_UNIQUE }, + { "UPDATE", TK_UPDATE }, + { "USING", TK_USING }, + { "VACUUM", TK_VACUUM }, + { "VALUES", TK_VALUES }, + { "VIEW", TK_VIEW }, + { "WHEN", TK_WHEN }, + { "WHERE", TK_WHERE }, +}; + +#define KEYWORD_COUNT ( sizeof aKeywordTable/sizeof (Keyword) ) + +/* +** This function looks up an identifier to determine if it is a +** keyword. If it is a keyword, the token code of that keyword is +** returned. If the input is not a keyword, TK_ID is returned. +*/ +int sqliteKeywordCode(const WCHAR *z, int n){ + UINT i, len; + char buffer[0x10]; + + len = WideCharToMultiByte( CP_ACP, 0, z, n, buffer, sizeof buffer, NULL, NULL ); + for(i=0; i<len; i++) + buffer[i] = toupper(buffer[i]); + for(i=0; i<KEYWORD_COUNT; i++) + { + if(memcmp(buffer, aKeywordTable[i].zName, len)) + continue; + if(strlen(aKeywordTable[i].zName) == len ) + return aKeywordTable[i].tokenType; + } + return TK_ID; +} + + +/* +** If X is a character that can be used in an identifier then +** isIdChar[X] will be 1. Otherwise isIdChar[X] will be 0. +** +** In this implementation, an identifier can be a string of +** alphabetic characters, digits, and "_" plus any character +** with the high-order bit set. The latter rule means that +** any sequence of UTF-8 characters or characters taken from +** an extended ISO8859 character set can form an identifier. +*/ +static const char isIdChar[] = { +/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9x */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Ax */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Bx */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Cx */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Dx */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Ex */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Fx */ +}; + + +/* +** Return the length of the token that begins at z[0]. Return +** -1 if the token is (or might be) incomplete. Store the token +** type in *tokenType before returning. +*/ +int sqliteGetToken(const WCHAR *z, int *tokenType){ + int i; + switch( *z ){ + case ' ': case '\t': case '\n': case '\f': case '\r': { + for(i=1; isspace(z[i]); i++){} + *tokenType = TK_SPACE; + return i; + } + case '-': { + if( z[1]==0 ) return -1; + if( z[1]=='-' ){ + for(i=2; z[i] && z[i]!='\n'; i++){} + *tokenType = TK_COMMENT; + return i; + } + *tokenType = TK_MINUS; + return 1; + } + case '(': { + if( z[1]=='+' && z[2]==')' ){ + *tokenType = TK_ORACLE_OUTER_JOIN; + return 3; + }else{ + *tokenType = TK_LP; + return 1; + } + } + case ')': { + *tokenType = TK_RP; + return 1; + } + case ';': { + *tokenType = TK_SEMI; + return 1; + } + case '+': { + *tokenType = TK_PLUS; + return 1; + } + case '*': { + *tokenType = TK_STAR; + return 1; + } + case '/': { + if( z[1]!='*' || z[2]==0 ){ + *tokenType = TK_SLASH; + return 1; + } + for(i=3; z[i] && (z[i]!='/' || z[i-1]!='*'); i++){} + if( z[i] ) i++; + *tokenType = TK_COMMENT; + return i; + } + case '%': { + *tokenType = TK_REM; + return 1; + } + case '=': { + *tokenType = TK_EQ; + return 1 + (z[1]=='='); + } + case '<': { + if( z[1]=='=' ){ + *tokenType = TK_LE; + return 2; + }else if( z[1]=='>' ){ + *tokenType = TK_NE; + return 2; + }else if( z[1]=='<' ){ + *tokenType = TK_LSHIFT; + return 2; + }else{ + *tokenType = TK_LT; + return 1; + } + } + case '>': { + if( z[1]=='=' ){ + *tokenType = TK_GE; + return 2; + }else if( z[1]=='>' ){ + *tokenType = TK_RSHIFT; + return 2; + }else{ + *tokenType = TK_GT; + return 1; + } + } + case '!': { + if( z[1]!='=' ){ + *tokenType = TK_ILLEGAL; + return 2; + }else{ + *tokenType = TK_NE; + return 2; + } + } + case '|': { + if( z[1]!='|' ){ + *tokenType = TK_BITOR; + return 1; + }else{ + *tokenType = TK_CONCAT; + return 2; + } + } + case '?': { + *tokenType = TK_WILDCARD; + return 1; + } + case ',': { + *tokenType = TK_COMMA; + return 1; + } + case '&': { + *tokenType = TK_BITAND; + return 1; + } + case '~': { + *tokenType = TK_BITNOT; + return 1; + } + case '`': case '\'': case '"': { + int delim = z[0]; + for(i=1; z[i]; i++){ + if( z[i]==delim ){ + if( z[i+1]==delim ){ + i++; + }else{ + break; + } + } + } + if( z[i] ) i++; + if( delim == '`' ) + *tokenType = TK_ID; + else + *tokenType = TK_STRING; + return i; + } + case '.': { + if( !isdigit(z[1]) ){ + *tokenType = TK_DOT; + return 1; + } + /* Fall thru into the next case */ + } + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + *tokenType = TK_INTEGER; + for(i=1; isdigit(z[i]); i++){} + if( z[i]=='.' ){ + i++; + while( isdigit(z[i]) ){ i++; } + *tokenType = TK_FLOAT; + } + if( (z[i]=='e' || z[i]=='E') && + ( isdigit(z[i+1]) + || ((z[i+1]=='+' || z[i+1]=='-') && isdigit(z[i+2])) + ) + ){ + i += 2; + while( isdigit(z[i]) ){ i++; } + *tokenType = TK_FLOAT; + }else if( z[0]=='.' ){ + *tokenType = TK_FLOAT; + } + return i; + } + case '[': { + for(i=1; z[i] && z[i-1]!=']'; i++){} + *tokenType = TK_ID; + return i; + } + default: { + if( !isIdChar[*z] ){ + break; + } + for(i=1; isIdChar[z[i]]; i++){} + *tokenType = sqliteKeywordCode(z, i); + return i; + } + } + *tokenType = TK_ILLEGAL; + return 1; +} diff --git a/reactos/lib/msi/update.c b/reactos/lib/msi/update.c index 88644bd3005..3ab38603a10 100644 --- a/reactos/lib/msi/update.c +++ b/reactos/lib/msi/update.c @@ -1,239 +1,239 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2004 Mike McCormack for CodeWeavers - * - * 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 receuved a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "wine/debug.h" -#include "msi.h" -#include "msiquery.h" -#include "objbase.h" -#include "objidl.h" -#include "msipriv.h" -#include "winnls.h" - -#include "query.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - - -/* below is the query interface to a table */ - -typedef struct tagMSIUPDATEVIEW -{ - MSIVIEW view; - MSIDATABASE *db; - MSIVIEW *wv; - value_list *vals; -} MSIUPDATEVIEW; - -static UINT UPDATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) -{ - MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view; - - TRACE("%p %d %d %p\n", uv, row, col, val ); - - return ERROR_FUNCTION_FAILED; -} - -static UINT UPDATE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) -{ - MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view; - UINT n, type, val, r, row, col_count = 0, row_count = 0; - MSIVIEW *wv; - - TRACE("%p %p\n", uv, record ); - - if( !record ) - return ERROR_FUNCTION_FAILED; - - wv = uv->wv; - if( !wv ) - return ERROR_FUNCTION_FAILED; - - r = wv->ops->execute( wv, 0 ); - TRACE("tv execute returned %x\n", r); - if( r ) - return r; - - r = wv->ops->get_dimensions( wv, &row_count, &col_count ); - if( r ) - goto err; - - for( row = 0; row < row_count; row++ ) - { - for( n = 1; n <= col_count; n++ ) - { - r = wv->ops->get_column_info( wv, n, NULL, &type ); - if( r ) - break; - - if( type & MSITYPE_STRING ) - { - const WCHAR *str = MSI_RecordGetString( record, n ); - val = msi_addstringW( uv->db->strings, 0, str, -1, 1 ); - } - else - { - val = MSI_RecordGetInteger( record, n ); - val |= 0x8000; - } - r = wv->ops->set_int( wv, row, n, val ); - if( r ) - break; - } - } - -err: - return ERROR_SUCCESS; -} - - -static UINT UPDATE_close( struct tagMSIVIEW *view ) -{ - MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view; - MSIVIEW *wv; - - TRACE("%p\n", uv); - - wv = uv->wv; - if( !wv ) - return ERROR_FUNCTION_FAILED; - - return wv->ops->close( wv ); -} - -static UINT UPDATE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols ) -{ - MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view; - MSIVIEW *wv; - - TRACE("%p %p %p\n", uv, rows, cols ); - - wv = uv->wv; - if( !wv ) - return ERROR_FUNCTION_FAILED; - - return wv->ops->get_dimensions( wv, rows, cols ); -} - -static UINT UPDATE_get_column_info( struct tagMSIVIEW *view, - UINT n, LPWSTR *name, UINT *type ) -{ - MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view; - MSIVIEW *wv; - - TRACE("%p %d %p %p\n", uv, n, name, type ); - - wv = uv->wv; - if( !wv ) - return ERROR_FUNCTION_FAILED; - - return wv->ops->get_column_info( wv, n, name, type ); -} - -static UINT UPDATE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, - MSIRECORD *rec ) -{ - MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view; - - TRACE("%p %d %p\n", uv, eModifyMode, rec ); - - return ERROR_FUNCTION_FAILED; -} - -static UINT UPDATE_delete( struct tagMSIVIEW *view ) -{ - MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view; - MSIVIEW *wv; - - TRACE("%p\n", uv ); - - wv = uv->wv; - if( wv ) - wv->ops->delete( wv ); - msiobj_release( &uv->db->hdr ); - HeapFree( GetProcessHeap(), 0, uv ); - - return ERROR_SUCCESS; -} - - -static MSIVIEWOPS update_ops = -{ - UPDATE_fetch_int, - NULL, - NULL, - NULL, - UPDATE_execute, - UPDATE_close, - UPDATE_get_dimensions, - UPDATE_get_column_info, - UPDATE_modify, - UPDATE_delete -}; - -UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, - column_assignment *list, struct expr *expr ) -{ - MSIUPDATEVIEW *uv = NULL; - UINT r; - MSIVIEW *tv = NULL, *sv = NULL, *wv = NULL; - - TRACE("%p\n", uv ); - - r = TABLE_CreateView( db, table, &tv ); - if( r != ERROR_SUCCESS ) - return r; - - /* add conditions first */ - r = WHERE_CreateView( db, &wv, tv, expr ); - if( r != ERROR_SUCCESS ) - { - if( sv ) - sv->ops->delete( tv ); - return r; - } - - /* then select the columns we want */ - r = SELECT_CreateView( db, &sv, wv, list->col_list ); - if( r != ERROR_SUCCESS ) - { - if( tv ) - tv->ops->delete( sv ); - return r; - } - - uv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *uv ); - if( !uv ) - return ERROR_FUNCTION_FAILED; - - /* fill the structure */ - uv->view.ops = &update_ops; - msiobj_addref( &db->hdr ); - uv->db = db; - uv->vals = list->val_list; - uv->wv = sv; - *view = (MSIVIEW*) uv; - - return ERROR_SUCCESS; -} +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2004 Mike McCormack for CodeWeavers + * + * 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 receuved a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/debug.h" +#include "msi.h" +#include "msiquery.h" +#include "objbase.h" +#include "objidl.h" +#include "msipriv.h" +#include "winnls.h" + +#include "query.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + + +/* below is the query interface to a table */ + +typedef struct tagMSIUPDATEVIEW +{ + MSIVIEW view; + MSIDATABASE *db; + MSIVIEW *wv; + value_list *vals; +} MSIUPDATEVIEW; + +static UINT UPDATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) +{ + MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view; + + TRACE("%p %d %d %p\n", uv, row, col, val ); + + return ERROR_FUNCTION_FAILED; +} + +static UINT UPDATE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) +{ + MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view; + UINT n, type, val, r, row, col_count = 0, row_count = 0; + MSIVIEW *wv; + + TRACE("%p %p\n", uv, record ); + + if( !record ) + return ERROR_FUNCTION_FAILED; + + wv = uv->wv; + if( !wv ) + return ERROR_FUNCTION_FAILED; + + r = wv->ops->execute( wv, 0 ); + TRACE("tv execute returned %x\n", r); + if( r ) + return r; + + r = wv->ops->get_dimensions( wv, &row_count, &col_count ); + if( r ) + goto err; + + for( row = 0; row < row_count; row++ ) + { + for( n = 1; n <= col_count; n++ ) + { + r = wv->ops->get_column_info( wv, n, NULL, &type ); + if( r ) + break; + + if( type & MSITYPE_STRING ) + { + const WCHAR *str = MSI_RecordGetString( record, n ); + val = msi_addstringW( uv->db->strings, 0, str, -1, 1 ); + } + else + { + val = MSI_RecordGetInteger( record, n ); + val |= 0x8000; + } + r = wv->ops->set_int( wv, row, n, val ); + if( r ) + break; + } + } + +err: + return ERROR_SUCCESS; +} + + +static UINT UPDATE_close( struct tagMSIVIEW *view ) +{ + MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view; + MSIVIEW *wv; + + TRACE("%p\n", uv); + + wv = uv->wv; + if( !wv ) + return ERROR_FUNCTION_FAILED; + + return wv->ops->close( wv ); +} + +static UINT UPDATE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols ) +{ + MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view; + MSIVIEW *wv; + + TRACE("%p %p %p\n", uv, rows, cols ); + + wv = uv->wv; + if( !wv ) + return ERROR_FUNCTION_FAILED; + + return wv->ops->get_dimensions( wv, rows, cols ); +} + +static UINT UPDATE_get_column_info( struct tagMSIVIEW *view, + UINT n, LPWSTR *name, UINT *type ) +{ + MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view; + MSIVIEW *wv; + + TRACE("%p %d %p %p\n", uv, n, name, type ); + + wv = uv->wv; + if( !wv ) + return ERROR_FUNCTION_FAILED; + + return wv->ops->get_column_info( wv, n, name, type ); +} + +static UINT UPDATE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, + MSIRECORD *rec ) +{ + MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view; + + TRACE("%p %d %p\n", uv, eModifyMode, rec ); + + return ERROR_FUNCTION_FAILED; +} + +static UINT UPDATE_delete( struct tagMSIVIEW *view ) +{ + MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view; + MSIVIEW *wv; + + TRACE("%p\n", uv ); + + wv = uv->wv; + if( wv ) + wv->ops->delete( wv ); + msiobj_release( &uv->db->hdr ); + HeapFree( GetProcessHeap(), 0, uv ); + + return ERROR_SUCCESS; +} + + +static MSIVIEWOPS update_ops = +{ + UPDATE_fetch_int, + NULL, + NULL, + NULL, + UPDATE_execute, + UPDATE_close, + UPDATE_get_dimensions, + UPDATE_get_column_info, + UPDATE_modify, + UPDATE_delete +}; + +UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table, + column_assignment *list, struct expr *expr ) +{ + MSIUPDATEVIEW *uv = NULL; + UINT r; + MSIVIEW *tv = NULL, *sv = NULL, *wv = NULL; + + TRACE("%p\n", uv ); + + r = TABLE_CreateView( db, table, &tv ); + if( r != ERROR_SUCCESS ) + return r; + + /* add conditions first */ + r = WHERE_CreateView( db, &wv, tv, expr ); + if( r != ERROR_SUCCESS ) + { + if( sv ) + sv->ops->delete( tv ); + return r; + } + + /* then select the columns we want */ + r = SELECT_CreateView( db, &sv, wv, list->col_list ); + if( r != ERROR_SUCCESS ) + { + if( tv ) + tv->ops->delete( sv ); + return r; + } + + uv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *uv ); + if( !uv ) + return ERROR_FUNCTION_FAILED; + + /* fill the structure */ + uv->view.ops = &update_ops; + msiobj_addref( &db->hdr ); + uv->db = db; + uv->vals = list->val_list; + uv->wv = sv; + *view = (MSIVIEW*) uv; + + return ERROR_SUCCESS; +} diff --git a/reactos/lib/msi/where.c b/reactos/lib/msi/where.c index 9a78074ea1b..e43e3c48984 100644 --- a/reactos/lib/msi/where.c +++ b/reactos/lib/msi/where.c @@ -1,481 +1,481 @@ -/* - * Implementation of the Microsoft Installer (msi.dll) - * - * Copyright 2002 Mike McCormack for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "wine/debug.h" -#include "wine/unicode.h" -#include "msi.h" -#include "msiquery.h" -#include "objbase.h" -#include "objidl.h" -#include "msipriv.h" -#include "winnls.h" - -#include "query.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msi); - - -/* below is the query interface to a table */ - -typedef struct tagMSIWHEREVIEW -{ - MSIVIEW view; - MSIDATABASE *db; - MSIVIEW *table; - UINT row_count; - UINT *reorder; - struct expr *cond; -} MSIWHEREVIEW; - -static UINT WHERE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) -{ - MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; - - TRACE("%p %d %d %p\n", wv, row, col, val ); - - if( !wv->table ) - return ERROR_FUNCTION_FAILED; - - if( row > wv->row_count ) - return ERROR_NO_MORE_ITEMS; - - row = wv->reorder[ row ]; - - return wv->table->ops->fetch_int( wv->table, row, col, val ); -} - -static UINT WHERE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm ) -{ - MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; - - TRACE("%p %d %d %p\n", wv, row, col, stm ); - - if( !wv->table ) - return ERROR_FUNCTION_FAILED; - - if( row > wv->row_count ) - return ERROR_NO_MORE_ITEMS; - - row = wv->reorder[ row ]; - - return wv->table->ops->fetch_stream( wv->table, row, col, stm ); -} - -static UINT WHERE_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val ) -{ - MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; - - TRACE("%p %d %d %04x\n", wv, row, col, val ); - - if( !wv->table ) - return ERROR_FUNCTION_FAILED; - - if( row > wv->row_count ) - return ERROR_NO_MORE_ITEMS; - - row = wv->reorder[ row ]; - - return wv->table->ops->set_int( wv->table, row, col, val ); -} - -static UINT INT_evaluate( UINT lval, UINT op, UINT rval ) -{ - switch( op ) - { - case OP_EQ: - return ( lval == rval ); - case OP_AND: - return ( lval && rval ); - case OP_OR: - return ( lval || rval ); - case OP_GT: - return ( lval > rval ); - case OP_LT: - return ( lval < rval ); - case OP_LE: - return ( lval <= rval ); - case OP_GE: - return ( lval >= rval ); - case OP_NE: - return ( lval != rval ); - case OP_ISNULL: - return ( !lval ); - case OP_NOTNULL: - return ( lval ); - default: - ERR("Unknown operator %d\n", op ); - } - return 0; -} - -static const WCHAR *STRING_evaluate( string_table *st, - MSIVIEW *table, UINT row, struct expr *expr, MSIRECORD *record ) -{ - UINT val = 0, r; - - switch( expr->type ) - { - case EXPR_COL_NUMBER_STRING: - r = table->ops->fetch_int( table, row, expr->u.col_number, &val ); - if( r != ERROR_SUCCESS ) - return NULL; - return msi_string_lookup_id( st, val ); - - case EXPR_SVAL: - return expr->u.sval; - - case EXPR_WILDCARD: - return MSI_RecordGetString( record, 1 ); - - default: - ERR("Invalid expression type\n"); - break; - } - return NULL; -} - -static UINT STRCMP_Evaluate( string_table *st, MSIVIEW *table, UINT row, - struct expr *cond, UINT *val, MSIRECORD *record ) -{ - int sr; - const WCHAR *l_str, *r_str; - - l_str = STRING_evaluate( st, table, row, cond->u.expr.left, record ); - r_str = STRING_evaluate( st, table, row, cond->u.expr.right, record ); - if( l_str == r_str ) - sr = 0; - else if( l_str && ! r_str ) - sr = 1; - else if( r_str && ! l_str ) - sr = -1; - else - sr = strcmpW( l_str, r_str ); - - *val = ( cond->u.expr.op == OP_EQ && ( sr == 0 ) ) || - ( cond->u.expr.op == OP_LT && ( sr < 0 ) ) || - ( cond->u.expr.op == OP_GT && ( sr > 0 ) ); - - return ERROR_SUCCESS; -} - -static UINT WHERE_evaluate( MSIDATABASE *db, MSIVIEW *table, UINT row, - struct expr *cond, UINT *val, MSIRECORD *record ) -{ - UINT r, lval, rval; - - if( !cond ) - return ERROR_SUCCESS; - - switch( cond->type ) - { - case EXPR_COL_NUMBER_STRING: - case EXPR_COL_NUMBER: - return table->ops->fetch_int( table, row, cond->u.col_number, val ); - - case EXPR_UVAL: - *val = cond->u.uval; - return ERROR_SUCCESS; - - case EXPR_COMPLEX: - r = WHERE_evaluate( db, table, row, cond->u.expr.left, &lval, record ); - if( r != ERROR_SUCCESS ) - return r; - r = WHERE_evaluate( db, table, row, cond->u.expr.right, &rval, record ); - if( r != ERROR_SUCCESS ) - return r; - *val = INT_evaluate( lval, cond->u.expr.op, rval ); - return ERROR_SUCCESS; - - case EXPR_STRCMP: - return STRCMP_Evaluate( db->strings, table, row, cond, val, record ); - - case EXPR_WILDCARD: - *val = MSI_RecordGetInteger( record, 1 ); - return ERROR_SUCCESS; - - default: - ERR("Invalid expression type\n"); - break; - } - - return ERROR_SUCCESS; - -} - -static UINT WHERE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) -{ - MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; - UINT count = 0, r, val, i; - MSIVIEW *table = wv->table; - - TRACE("%p %p\n", wv, record); - - if( !table ) - return ERROR_FUNCTION_FAILED; - - r = table->ops->execute( table, record ); - if( r != ERROR_SUCCESS ) - return r; - - r = table->ops->get_dimensions( table, &count, NULL ); - if( r != ERROR_SUCCESS ) - return r; - - wv->reorder = HeapAlloc( GetProcessHeap(), 0, count*sizeof(UINT) ); - if( !wv->reorder ) - return ERROR_FUNCTION_FAILED; - - wv->row_count = 0; - for( i=0; i<count; i++ ) - { - val = 0; - r = WHERE_evaluate( wv->db, table, i, wv->cond, &val, record ); - if( r != ERROR_SUCCESS ) - return r; - if( val ) - wv->reorder[ wv->row_count ++ ] = i; - } - - return ERROR_SUCCESS; -} - -static UINT WHERE_close( struct tagMSIVIEW *view ) -{ - MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; - - TRACE("%p\n", wv ); - - if( !wv->table ) - return ERROR_FUNCTION_FAILED; - - HeapFree( GetProcessHeap(), 0, wv->reorder ); - wv->reorder = NULL; - - return wv->table->ops->close( wv->table ); -} - -static UINT WHERE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols ) -{ - MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; - - TRACE("%p %p %p\n", wv, rows, cols ); - - if( !wv->table ) - return ERROR_FUNCTION_FAILED; - - if( rows ) - { - if( !wv->reorder ) - return ERROR_FUNCTION_FAILED; - *rows = wv->row_count; - } - - return wv->table->ops->get_dimensions( wv->table, NULL, cols ); -} - -static UINT WHERE_get_column_info( struct tagMSIVIEW *view, - UINT n, LPWSTR *name, UINT *type ) -{ - MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; - - TRACE("%p %d %p %p\n", wv, n, name, type ); - - if( !wv->table ) - return ERROR_FUNCTION_FAILED; - - return wv->table->ops->get_column_info( wv->table, n, name, type ); -} - -static UINT WHERE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, - MSIRECORD *rec ) -{ - MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; - - TRACE("%p %d %p\n", wv, eModifyMode, rec ); - - if( !wv->table ) - return ERROR_FUNCTION_FAILED; - - return wv->table->ops->modify( wv->table, eModifyMode, rec ); -} - -static UINT WHERE_delete( struct tagMSIVIEW *view ) -{ - MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; - - TRACE("%p\n", wv ); - - if( wv->table ) - wv->table->ops->delete( wv->table ); - - HeapFree( GetProcessHeap(), 0, wv->reorder ); - wv->reorder = NULL; - wv->row_count = 0; - - msiobj_release( &wv->db->hdr ); - HeapFree( GetProcessHeap(), 0, wv ); - - return ERROR_SUCCESS; -} - - -MSIVIEWOPS where_ops = -{ - WHERE_fetch_int, - WHERE_fetch_stream, - WHERE_set_int, - NULL, - WHERE_execute, - WHERE_close, - WHERE_get_dimensions, - WHERE_get_column_info, - WHERE_modify, - WHERE_delete -}; - -static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr *cond, - UINT *valid ) -{ - UINT r, val = 0; - - switch( cond->type ) - { - case EXPR_COLUMN: - r = VIEW_find_column( table, cond->u.column, &val ); - if( r == ERROR_SUCCESS ) - { - UINT type = 0; - r = table->ops->get_column_info( table, val, NULL, &type ); - if( r == ERROR_SUCCESS ) - { - if (type&MSITYPE_STRING) - cond->type = EXPR_COL_NUMBER_STRING; - else - cond->type = EXPR_COL_NUMBER; - cond->u.col_number = val; - *valid = 1; - } - else - *valid = 0; - } - else - { - *valid = 0; - ERR("Couldn't find column %s\n", debugstr_w( cond->u.column ) ); - } - break; - case EXPR_COMPLEX: - r = WHERE_VerifyCondition( db, table, cond->u.expr.left, valid ); - if( r != ERROR_SUCCESS ) - return r; - if( !*valid ) - return ERROR_SUCCESS; - r = WHERE_VerifyCondition( db, table, cond->u.expr.right, valid ); - if( r != ERROR_SUCCESS ) - return r; - - /* check the type of the comparison */ - if( ( cond->u.expr.left->type == EXPR_SVAL ) || - ( cond->u.expr.left->type == EXPR_COL_NUMBER_STRING ) || - ( cond->u.expr.right->type == EXPR_SVAL ) || - ( cond->u.expr.right->type == EXPR_COL_NUMBER_STRING ) ) - { - switch( cond->u.expr.op ) - { - case OP_EQ: - case OP_GT: - case OP_LT: - break; - default: - *valid = FALSE; - return ERROR_INVALID_PARAMETER; - } - - /* FIXME: check we're comparing a string to a column */ - - cond->type = EXPR_STRCMP; - } - - break; - case EXPR_IVAL: - *valid = 1; - cond->type = EXPR_UVAL; - cond->u.uval = cond->u.ival + (1<<15); - break; - case EXPR_WILDCARD: - *valid = 1; - break; - case EXPR_SVAL: - *valid = 1; - break; - default: - ERR("Invalid expression type\n"); - *valid = 0; - break; - } - - return ERROR_SUCCESS; -} - -UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, - struct expr *cond ) -{ - MSIWHEREVIEW *wv = NULL; - UINT count = 0, r, valid = 0; - - TRACE("%p\n", wv ); - - r = table->ops->get_dimensions( table, NULL, &count ); - if( r != ERROR_SUCCESS ) - { - ERR("can't get table dimensions\n"); - return r; - } - - if( cond ) - { - r = WHERE_VerifyCondition( db, table, cond, &valid ); - if( r != ERROR_SUCCESS ) - return r; - if( !valid ) - return ERROR_FUNCTION_FAILED; - } - - wv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *wv ); - if( !wv ) - return ERROR_FUNCTION_FAILED; - - /* fill the structure */ - wv->view.ops = &where_ops; - msiobj_addref( &db->hdr ); - wv->db = db; - wv->table = table; - wv->row_count = 0; - wv->reorder = NULL; - wv->cond = cond; - *view = (MSIVIEW*) wv; - - return ERROR_SUCCESS; -} +/* + * Implementation of the Microsoft Installer (msi.dll) + * + * Copyright 2002 Mike McCormack for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/debug.h" +#include "wine/unicode.h" +#include "msi.h" +#include "msiquery.h" +#include "objbase.h" +#include "objidl.h" +#include "msipriv.h" +#include "winnls.h" + +#include "query.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msi); + + +/* below is the query interface to a table */ + +typedef struct tagMSIWHEREVIEW +{ + MSIVIEW view; + MSIDATABASE *db; + MSIVIEW *table; + UINT row_count; + UINT *reorder; + struct expr *cond; +} MSIWHEREVIEW; + +static UINT WHERE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val ) +{ + MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; + + TRACE("%p %d %d %p\n", wv, row, col, val ); + + if( !wv->table ) + return ERROR_FUNCTION_FAILED; + + if( row > wv->row_count ) + return ERROR_NO_MORE_ITEMS; + + row = wv->reorder[ row ]; + + return wv->table->ops->fetch_int( wv->table, row, col, val ); +} + +static UINT WHERE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm ) +{ + MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; + + TRACE("%p %d %d %p\n", wv, row, col, stm ); + + if( !wv->table ) + return ERROR_FUNCTION_FAILED; + + if( row > wv->row_count ) + return ERROR_NO_MORE_ITEMS; + + row = wv->reorder[ row ]; + + return wv->table->ops->fetch_stream( wv->table, row, col, stm ); +} + +static UINT WHERE_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val ) +{ + MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; + + TRACE("%p %d %d %04x\n", wv, row, col, val ); + + if( !wv->table ) + return ERROR_FUNCTION_FAILED; + + if( row > wv->row_count ) + return ERROR_NO_MORE_ITEMS; + + row = wv->reorder[ row ]; + + return wv->table->ops->set_int( wv->table, row, col, val ); +} + +static UINT INT_evaluate( UINT lval, UINT op, UINT rval ) +{ + switch( op ) + { + case OP_EQ: + return ( lval == rval ); + case OP_AND: + return ( lval && rval ); + case OP_OR: + return ( lval || rval ); + case OP_GT: + return ( lval > rval ); + case OP_LT: + return ( lval < rval ); + case OP_LE: + return ( lval <= rval ); + case OP_GE: + return ( lval >= rval ); + case OP_NE: + return ( lval != rval ); + case OP_ISNULL: + return ( !lval ); + case OP_NOTNULL: + return ( lval ); + default: + ERR("Unknown operator %d\n", op ); + } + return 0; +} + +static const WCHAR *STRING_evaluate( string_table *st, + MSIVIEW *table, UINT row, struct expr *expr, MSIRECORD *record ) +{ + UINT val = 0, r; + + switch( expr->type ) + { + case EXPR_COL_NUMBER_STRING: + r = table->ops->fetch_int( table, row, expr->u.col_number, &val ); + if( r != ERROR_SUCCESS ) + return NULL; + return msi_string_lookup_id( st, val ); + + case EXPR_SVAL: + return expr->u.sval; + + case EXPR_WILDCARD: + return MSI_RecordGetString( record, 1 ); + + default: + ERR("Invalid expression type\n"); + break; + } + return NULL; +} + +static UINT STRCMP_Evaluate( string_table *st, MSIVIEW *table, UINT row, + struct expr *cond, UINT *val, MSIRECORD *record ) +{ + int sr; + const WCHAR *l_str, *r_str; + + l_str = STRING_evaluate( st, table, row, cond->u.expr.left, record ); + r_str = STRING_evaluate( st, table, row, cond->u.expr.right, record ); + if( l_str == r_str ) + sr = 0; + else if( l_str && ! r_str ) + sr = 1; + else if( r_str && ! l_str ) + sr = -1; + else + sr = strcmpW( l_str, r_str ); + + *val = ( cond->u.expr.op == OP_EQ && ( sr == 0 ) ) || + ( cond->u.expr.op == OP_LT && ( sr < 0 ) ) || + ( cond->u.expr.op == OP_GT && ( sr > 0 ) ); + + return ERROR_SUCCESS; +} + +static UINT WHERE_evaluate( MSIDATABASE *db, MSIVIEW *table, UINT row, + struct expr *cond, UINT *val, MSIRECORD *record ) +{ + UINT r, lval, rval; + + if( !cond ) + return ERROR_SUCCESS; + + switch( cond->type ) + { + case EXPR_COL_NUMBER_STRING: + case EXPR_COL_NUMBER: + return table->ops->fetch_int( table, row, cond->u.col_number, val ); + + case EXPR_UVAL: + *val = cond->u.uval; + return ERROR_SUCCESS; + + case EXPR_COMPLEX: + r = WHERE_evaluate( db, table, row, cond->u.expr.left, &lval, record ); + if( r != ERROR_SUCCESS ) + return r; + r = WHERE_evaluate( db, table, row, cond->u.expr.right, &rval, record ); + if( r != ERROR_SUCCESS ) + return r; + *val = INT_evaluate( lval, cond->u.expr.op, rval ); + return ERROR_SUCCESS; + + case EXPR_STRCMP: + return STRCMP_Evaluate( db->strings, table, row, cond, val, record ); + + case EXPR_WILDCARD: + *val = MSI_RecordGetInteger( record, 1 ); + return ERROR_SUCCESS; + + default: + ERR("Invalid expression type\n"); + break; + } + + return ERROR_SUCCESS; + +} + +static UINT WHERE_execute( struct tagMSIVIEW *view, MSIRECORD *record ) +{ + MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; + UINT count = 0, r, val, i; + MSIVIEW *table = wv->table; + + TRACE("%p %p\n", wv, record); + + if( !table ) + return ERROR_FUNCTION_FAILED; + + r = table->ops->execute( table, record ); + if( r != ERROR_SUCCESS ) + return r; + + r = table->ops->get_dimensions( table, &count, NULL ); + if( r != ERROR_SUCCESS ) + return r; + + wv->reorder = HeapAlloc( GetProcessHeap(), 0, count*sizeof(UINT) ); + if( !wv->reorder ) + return ERROR_FUNCTION_FAILED; + + wv->row_count = 0; + for( i=0; i<count; i++ ) + { + val = 0; + r = WHERE_evaluate( wv->db, table, i, wv->cond, &val, record ); + if( r != ERROR_SUCCESS ) + return r; + if( val ) + wv->reorder[ wv->row_count ++ ] = i; + } + + return ERROR_SUCCESS; +} + +static UINT WHERE_close( struct tagMSIVIEW *view ) +{ + MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; + + TRACE("%p\n", wv ); + + if( !wv->table ) + return ERROR_FUNCTION_FAILED; + + HeapFree( GetProcessHeap(), 0, wv->reorder ); + wv->reorder = NULL; + + return wv->table->ops->close( wv->table ); +} + +static UINT WHERE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols ) +{ + MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; + + TRACE("%p %p %p\n", wv, rows, cols ); + + if( !wv->table ) + return ERROR_FUNCTION_FAILED; + + if( rows ) + { + if( !wv->reorder ) + return ERROR_FUNCTION_FAILED; + *rows = wv->row_count; + } + + return wv->table->ops->get_dimensions( wv->table, NULL, cols ); +} + +static UINT WHERE_get_column_info( struct tagMSIVIEW *view, + UINT n, LPWSTR *name, UINT *type ) +{ + MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; + + TRACE("%p %d %p %p\n", wv, n, name, type ); + + if( !wv->table ) + return ERROR_FUNCTION_FAILED; + + return wv->table->ops->get_column_info( wv->table, n, name, type ); +} + +static UINT WHERE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, + MSIRECORD *rec ) +{ + MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; + + TRACE("%p %d %p\n", wv, eModifyMode, rec ); + + if( !wv->table ) + return ERROR_FUNCTION_FAILED; + + return wv->table->ops->modify( wv->table, eModifyMode, rec ); +} + +static UINT WHERE_delete( struct tagMSIVIEW *view ) +{ + MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view; + + TRACE("%p\n", wv ); + + if( wv->table ) + wv->table->ops->delete( wv->table ); + + HeapFree( GetProcessHeap(), 0, wv->reorder ); + wv->reorder = NULL; + wv->row_count = 0; + + msiobj_release( &wv->db->hdr ); + HeapFree( GetProcessHeap(), 0, wv ); + + return ERROR_SUCCESS; +} + + +MSIVIEWOPS where_ops = +{ + WHERE_fetch_int, + WHERE_fetch_stream, + WHERE_set_int, + NULL, + WHERE_execute, + WHERE_close, + WHERE_get_dimensions, + WHERE_get_column_info, + WHERE_modify, + WHERE_delete +}; + +static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr *cond, + UINT *valid ) +{ + UINT r, val = 0; + + switch( cond->type ) + { + case EXPR_COLUMN: + r = VIEW_find_column( table, cond->u.column, &val ); + if( r == ERROR_SUCCESS ) + { + UINT type = 0; + r = table->ops->get_column_info( table, val, NULL, &type ); + if( r == ERROR_SUCCESS ) + { + if (type&MSITYPE_STRING) + cond->type = EXPR_COL_NUMBER_STRING; + else + cond->type = EXPR_COL_NUMBER; + cond->u.col_number = val; + *valid = 1; + } + else + *valid = 0; + } + else + { + *valid = 0; + ERR("Couldn't find column %s\n", debugstr_w( cond->u.column ) ); + } + break; + case EXPR_COMPLEX: + r = WHERE_VerifyCondition( db, table, cond->u.expr.left, valid ); + if( r != ERROR_SUCCESS ) + return r; + if( !*valid ) + return ERROR_SUCCESS; + r = WHERE_VerifyCondition( db, table, cond->u.expr.right, valid ); + if( r != ERROR_SUCCESS ) + return r; + + /* check the type of the comparison */ + if( ( cond->u.expr.left->type == EXPR_SVAL ) || + ( cond->u.expr.left->type == EXPR_COL_NUMBER_STRING ) || + ( cond->u.expr.right->type == EXPR_SVAL ) || + ( cond->u.expr.right->type == EXPR_COL_NUMBER_STRING ) ) + { + switch( cond->u.expr.op ) + { + case OP_EQ: + case OP_GT: + case OP_LT: + break; + default: + *valid = FALSE; + return ERROR_INVALID_PARAMETER; + } + + /* FIXME: check we're comparing a string to a column */ + + cond->type = EXPR_STRCMP; + } + + break; + case EXPR_IVAL: + *valid = 1; + cond->type = EXPR_UVAL; + cond->u.uval = cond->u.ival + (1<<15); + break; + case EXPR_WILDCARD: + *valid = 1; + break; + case EXPR_SVAL: + *valid = 1; + break; + default: + ERR("Invalid expression type\n"); + *valid = 0; + break; + } + + return ERROR_SUCCESS; +} + +UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table, + struct expr *cond ) +{ + MSIWHEREVIEW *wv = NULL; + UINT count = 0, r, valid = 0; + + TRACE("%p\n", wv ); + + r = table->ops->get_dimensions( table, NULL, &count ); + if( r != ERROR_SUCCESS ) + { + ERR("can't get table dimensions\n"); + return r; + } + + if( cond ) + { + r = WHERE_VerifyCondition( db, table, cond, &valid ); + if( r != ERROR_SUCCESS ) + return r; + if( !valid ) + return ERROR_FUNCTION_FAILED; + } + + wv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *wv ); + if( !wv ) + return ERROR_FUNCTION_FAILED; + + /* fill the structure */ + wv->view.ops = &where_ops; + msiobj_addref( &db->hdr ); + wv->db = db; + wv->table = table; + wv->row_count = 0; + wv->reorder = NULL; + wv->cond = cond; + *view = (MSIVIEW*) wv; + + return ERROR_SUCCESS; +} diff --git a/reactos/lib/ntdll/rtl/secobj.c b/reactos/lib/ntdll/rtl/secobj.c index 6cc513ba28e..0caded262eb 100644 --- a/reactos/lib/ntdll/rtl/secobj.c +++ b/reactos/lib/ntdll/rtl/secobj.c @@ -1,97 +1,97 @@ -/* - * ReactOS kernel - * Copyright (C) 2005 Eric Kohl - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS system libraries - * PURPOSE: Security object implementation - * FILE: lib/ntdll/rtl/secobj.c - */ - -/* INCLUDES ****************************************************************/ - -#include <ntdll.h> -#define NDEBUG -#include <debug.h> - -/* - * @implemented - */ -NTSTATUS -STDCALL -RtlDeleteSecurityObject(IN PSECURITY_DESCRIPTOR *ObjectDescriptor) -{ - DPRINT("RtlDeleteSecurityObject(%p)\n", ObjectDescriptor); - - RtlFreeHeap(RtlGetProcessHeap(), - 0, - *ObjectDescriptor); - - return STATUS_SUCCESS; -} - - -/* - * @unimplemented - */ -NTSTATUS -STDCALL -RtlNewSecurityObject(IN PSECURITY_DESCRIPTOR ParentDescriptor, - IN PSECURITY_DESCRIPTOR CreatorDescriptor, - OUT PSECURITY_DESCRIPTOR *NewDescriptor, - IN BOOLEAN IsDirectoryObject, - IN HANDLE Token, - IN PGENERIC_MAPPING GenericMapping) -{ - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; -} - - -/* - * @unimplemented - */ -NTSTATUS -STDCALL -RtlQuerySecurityObject(IN PSECURITY_DESCRIPTOR ObjectDescriptor, - IN SECURITY_INFORMATION SecurityInformation, - OUT PSECURITY_DESCRIPTOR ResultantDescriptor, - IN ULONG DescriptorLength, - OUT PULONG ReturnLength) -{ - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; -} - - -/* - * @unimplemented - */ -NTSTATUS -STDCALL -RtlSetSecurityObject(IN SECURITY_INFORMATION SecurityInformation, - IN PSECURITY_DESCRIPTOR ModificationDescriptor, - OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor, - IN PGENERIC_MAPPING GenericMapping, - IN HANDLE Token) -{ - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; -} - -/* EOF */ +/* + * ReactOS kernel + * Copyright (C) 2005 Eric Kohl + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS system libraries + * PURPOSE: Security object implementation + * FILE: lib/ntdll/rtl/secobj.c + */ + +/* INCLUDES ****************************************************************/ + +#include <ntdll.h> +#define NDEBUG +#include <debug.h> + +/* + * @implemented + */ +NTSTATUS +STDCALL +RtlDeleteSecurityObject(IN PSECURITY_DESCRIPTOR *ObjectDescriptor) +{ + DPRINT("RtlDeleteSecurityObject(%p)\n", ObjectDescriptor); + + RtlFreeHeap(RtlGetProcessHeap(), + 0, + *ObjectDescriptor); + + return STATUS_SUCCESS; +} + + +/* + * @unimplemented + */ +NTSTATUS +STDCALL +RtlNewSecurityObject(IN PSECURITY_DESCRIPTOR ParentDescriptor, + IN PSECURITY_DESCRIPTOR CreatorDescriptor, + OUT PSECURITY_DESCRIPTOR *NewDescriptor, + IN BOOLEAN IsDirectoryObject, + IN HANDLE Token, + IN PGENERIC_MAPPING GenericMapping) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + + +/* + * @unimplemented + */ +NTSTATUS +STDCALL +RtlQuerySecurityObject(IN PSECURITY_DESCRIPTOR ObjectDescriptor, + IN SECURITY_INFORMATION SecurityInformation, + OUT PSECURITY_DESCRIPTOR ResultantDescriptor, + IN ULONG DescriptorLength, + OUT PULONG ReturnLength) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + + +/* + * @unimplemented + */ +NTSTATUS +STDCALL +RtlSetSecurityObject(IN SECURITY_INFORMATION SecurityInformation, + IN PSECURITY_DESCRIPTOR ModificationDescriptor, + OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor, + IN PGENERIC_MAPPING GenericMapping, + IN HANDLE Token) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +/* EOF */ diff --git a/reactos/lib/ntdll/stdio/scanf.h b/reactos/lib/ntdll/stdio/scanf.h index 22ee5139370..dd2fc9f3d60 100644 --- a/reactos/lib/ntdll/stdio/scanf.h +++ b/reactos/lib/ntdll/stdio/scanf.h @@ -1,560 +1,560 @@ -/* - * general implementation of scanf used by scanf, sscanf, fscanf, - * _cscanf, wscanf, swscanf and fwscanf - * - * Copyright 1996,1998 Marcus Meissner - * Copyright 1996 Jukka Iivonen - * Copyright 1997,2000, 2003 Uwe Bonnes - * Copyright 2000 Jon Griffiths - * Copyright 2002 Daniel Gudbjartsson - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef WIDE_SCANF -#define _CHAR_ wchar_t -#define _EOF_ WEOF -#define _EOF_RET WEOF -#define _ISSPACE_(c) iswspace(c) -#define _ISDIGIT_(c) iswdigit(c) -#define _WIDE2SUPPORTED_(c) c /* No conversion needed (wide to wide) */ -#define _CHAR2SUPPORTED_(c) c /* FIXME: convert char to wide char */ -#define _CHAR2DIGIT_(c, base) wchar2digit((c), (base)) -#define _BITMAPSIZE_ 256*256 -#else /* WIDE_SCANF */ -#define _CHAR_ char -#define _EOF_ EOF -#define _EOF_RET EOF -#define _ISSPACE_(c) isspace(c) -#define _ISDIGIT_(c) isdigit(c) -#define _WIDE2SUPPORTED_(c) c /* FIXME: convert wide char to char */ -#define _CHAR2SUPPORTED_(c) c /* No conversion needed (char to char) */ -#define _CHAR2DIGIT_(c, base) char2digit((c), (base)) -#define _BITMAPSIZE_ 256 -#endif /* WIDE_SCANF */ - -#ifdef CONSOLE -#define _GETC_(file) (consumed++, _getch()) -#define _UNGETC_(nch, file) do { _ungetch(nch); consumed--; } while(0) -#define _FUNCTION_ int vcscanf(const char *format, va_list ap) -#else -#ifdef STRING -#undef _EOF_ -#define _EOF_ 0 -#define _GETC_(file) (consumed++, *file++) -#define _UNGETC_(nch, file) do { file--; consumed--; } while(0) -#ifdef WIDE_SCANF -#define _FUNCTION_ int vswscanf(const wchar_t *file, const wchar_t *format, va_list ap) -#else /* WIDE_SCANF */ -#define _FUNCTION_ int vsscanf(const char *file, const char *format, va_list ap) -#endif /* WIDE_SCANF */ -#else /* STRING */ -#ifdef WIDE_SCANF -#define _GETC_(file) (consumed++, fgetwc(file)) -#define _UNGETC_(nch, file) do { ungetwc(nch, file); consumed--; } while(0) -#define _FUNCTION_ int vfwscanf(FILE* file, const wchar_t *format, va_list ap) -#else /* WIDE_SCANF */ -#define _GETC_(file) (consumed++, fgetc(file)) -#define _UNGETC_(nch, file) do { ungetc(nch, file); consumed--; } while(0) -#define _FUNCTION_ int vfscanf(FILE* file, const char *format, va_list ap) -#endif /* WIDE_SCANF */ -#endif /* STRING */ -#endif /* CONSOLE */ - -/********************************************************************* - * Implemented based on - * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_crt_format_specification_fields_.2d_.scanf_and_wscanf_functions.asp - * Extended by C. Scott Ananian <cananian@alumni.princeton.edu> to handle - * more types of format spec. - */ -_FUNCTION_ { - int rd = 0, consumed = 0; - int nch; - if (!*format) return 0; -#ifndef WIDE_SCANF -#ifdef CONSOLE - TRACE("(%s): \n", debugstr_a(format)); -#else /* CONSOLE */ -#ifdef STRING - TRACE("%s (%s)\n", file, debugstr_a(format)); -#else /* STRING */ - TRACE("%p (%s)\n", file, debugstr_a(format)); -#endif /* STRING */ -#endif /* CONSOLE */ -#endif /* WIDE_SCANF */ - nch = _GETC_(file); - if (nch == _EOF_) return _EOF_RET; - - while (*format) { - /* a whitespace character in the format string causes scanf to read, - * but not store, all consecutive white-space characters in the input - * up to the next non-white-space character. One white space character - * in the input matches any number (including zero) and combination of - * white-space characters in the input. */ - if (_ISSPACE_(*format)) { - /* skip whitespace */ - while ((nch!=_EOF_) && _ISSPACE_(nch)) - nch = _GETC_(file); - } - /* a format specification causes scanf to read and convert characters - * in the input into values of a specified type. The value is assigned - * to an argument in the argument list. Format specifications have - * the form %[*][width][{h | l | I64 | L}]type */ - else if (*format == '%') { - int st = 0; int suppress = 0; int width = 0; - int base, number_signed; - int h_prefix = 0; - int l_prefix = 0; - int L_prefix = 0; - int w_prefix = 0; - int prefix_finished = 0; - int I64_prefix = 0; - format++; - /* look for leading asterisk, which means 'suppress assignment of - * this field'. */ - if (*format=='*') { - format++; - suppress=1; - } - /* look for width specification */ - while (_ISDIGIT_(*format)) { - width*=10; - width+=*format++ - '0'; - } - if (width==0) width=-1; /* no width spec seen */ - /* read prefix (if any) */ - while (!prefix_finished) { - switch(*format) { - case 'h': h_prefix = 1; break; - case 'l': l_prefix = 1; break; - case 'w': w_prefix = 1; break; - case 'L': L_prefix = 1; break; - case 'I': - if (*(format + 1) == '6' && - *(format + 2) == '4') { - I64_prefix = 1; - format += 2; - } - break; - default: - prefix_finished = 1; - } - if (!prefix_finished) format++; - } - /* read type */ - switch(*format) { - case 'x': - case 'X': /* hexadecimal integer. */ - base = 16; number_signed = 0; - goto number; - case 'o': /* octal integer */ - base = 8; number_signed = 0; - goto number; - case 'u': /* unsigned decimal integer */ - base = 10; number_signed = 0; - goto number; - case 'd': /* signed decimal integer */ - base = 10; number_signed = 1; - goto number; - case 'i': /* generic integer */ - base = 10; number_signed = 1; - number: { - /* read an integer */ - ULONGLONG cur = 0; - int negative = 0; - int seendigit=0; - /* skip initial whitespace */ - while ((nch!=_EOF_) && _ISSPACE_(nch)) - nch = _GETC_(file); - /* get sign */ - if (number_signed && (nch == '-' || - nch == '+')) { - negative = (nch=='-'); - nch = _GETC_(file); - if (width>0) width--; - } - /* look for leading indication of base */ - if (width!=0 && nch == '0') { - nch = _GETC_(file); - if (width>0) width--; - seendigit=1; - if (width!=0 && (nch=='x' || nch=='X')) { - if (base==0) - base=16; - if (base==16) { - nch = _GETC_(file); - if (width>0) width--; - seendigit=0; - } - } else if (base==0) - base = 8; - } - /* throw away leading zeros */ - while (width!=0 && nch=='0') { - nch = _GETC_(file); - if (width>0) width--; - seendigit=1; - } - if (width!=0 && _CHAR2DIGIT_(nch, base)!=-1) { - cur = _CHAR2DIGIT_(nch, base); - nch = _GETC_(file); - if (width>0) width--; - seendigit=1; - } - /* read until no more digits */ - while (width!=0 && (nch!=_EOF_) && _CHAR2DIGIT_(nch, base)!=-1) { - cur = cur*base + _CHAR2DIGIT_(nch, base); - nch = _GETC_(file); - if (width>0) width--; - seendigit=1; - } - /* okay, done! */ - if (!seendigit) break; /* not a valid number */ - st = 1; - if (!suppress) { -#define _SET_NUMBER_(type) *va_arg(ap, type*) = negative ? -cur : cur - if (number_signed) { - if (I64_prefix) _SET_NUMBER_(LONGLONG); - else if (l_prefix) _SET_NUMBER_(long int); - else if (h_prefix) _SET_NUMBER_(short int); - else _SET_NUMBER_(int); - } else { - if (negative) { - WARN("Dropping sign in reading a negative number into an unsigned value"); - negative = 0; - } - if (I64_prefix) _SET_NUMBER_(ULONGLONG); - else if (l_prefix) _SET_NUMBER_(unsigned long int); - else if (h_prefix) - _SET_NUMBER_(unsigned short int); - else _SET_NUMBER_(unsigned int); - } - } - } - break; - case 'e': - case 'E': - case 'f': - case 'g': - case 'G': { /* read a float */ - long double cur = 0; - int negative = 0; - /* skip initial whitespace */ - while ((nch!=_EOF_) && _ISSPACE_(nch)) - nch = _GETC_(file); - /* get sign. */ - if (nch == '-' || nch == '+') { - negative = (nch=='-'); - if (width>0) width--; - if (width==0) break; - nch = _GETC_(file); - } - /* get first digit. */ - if ('.' != nch) { - if (!_ISDIGIT_(nch)) break; - cur = (nch - '0'); - nch = _GETC_(file); - if (width>0) width--; - /* read until no more digits */ - while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { - cur = cur*10 + (nch - '0'); - nch = _GETC_(file); - if (width>0) width--; - } - } else { - cur = 0; /* MaxPayneDemo Fix: .8 -> 0.8 */ - } - /* handle decimals */ - if (width!=0 && nch == '.') { - float dec = 1; - nch = _GETC_(file); - if (width>0) width--; - while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { - dec /= 10; - cur += dec * (nch - '0'); - nch = _GETC_(file); - if (width>0) width--; - } - } - /* handle exponent */ - if (width!=0 && (nch == 'e' || nch == 'E')) { - int exponent = 0, negexp = 0; - float expcnt; - nch = _GETC_(file); - if (width>0) width--; - /* possible sign on the exponent */ - if (width!=0 && (nch=='+' || nch=='-')) { - negexp = (nch=='-'); - nch = _GETC_(file); - if (width>0) width--; - } - /* exponent digits */ - while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { - exponent *= 10; - exponent += (nch - '0'); - nch = _GETC_(file); - if (width>0) width--; - } - /* update 'cur' with this exponent. */ - expcnt = negexp ? .1 : 10; - while (exponent!=0) { - if (exponent&1) - cur*=expcnt; - exponent/=2; - expcnt=expcnt*expcnt; - } - } - st = 1; - if (!suppress) { - if (L_prefix) _SET_NUMBER_(long double); - else if (l_prefix) _SET_NUMBER_(double); - else _SET_NUMBER_(float); - } - } - break; - /* According to - * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt_scanf_type_field_characters.asp - * 's' reads a character string in a call to fscanf - * and 'S' a wide character string and vice versa in a - * call to fwscanf. The 'h', 'w' and 'l' prefixes override - * this behaviour. 'h' forces reading char * but 'l' and 'w' - * force reading WCHAR. */ - case 's': - if (w_prefix || l_prefix) goto widecharstring; - else if (h_prefix) goto charstring; -#ifdef WIDE_SCANF - else goto widecharstring; -#else /* WIDE_SCANF */ - else goto charstring; -#endif /* WIDE_SCANF */ - case 'S': - if (w_prefix || l_prefix) goto widecharstring; - else if (h_prefix) goto charstring; -#ifdef WIDE_SCANF - else goto charstring; -#else /* WIDE_SCANF */ - else goto widecharstring; -#endif /* WIDE_SCANF */ - charstring: { /* read a word into a char */ - char*str = suppress ? NULL : va_arg(ap, char*); - char*sptr = str; - /* skip initial whitespace */ - while ((nch!=_EOF_) && _ISSPACE_(nch)) - nch = _GETC_(file); - /* read until whitespace */ - while (width!=0 && (nch!=_EOF_) && !_ISSPACE_(nch)) { - if (!suppress) *sptr++ = _CHAR2SUPPORTED_(nch); - st++; - nch = _GETC_(file); - if (width>0) width--; - } - /* terminate */ - if (!suppress) *sptr = 0; - } - break; - widecharstring: { /* read a word into a wchar_t* */ - wchar_t*str = - suppress ? NULL : va_arg(ap, wchar_t*); - wchar_t*sptr = str; - /* skip initial whitespace */ - while ((nch!=_EOF_) && _ISSPACE_(nch)) - nch = _GETC_(file); - /* read until whitespace */ - while (width!=0 && (nch!=_EOF_) && !_ISSPACE_(nch)) { - if (!suppress) *sptr++ = _WIDE2SUPPORTED_(nch); - st++; - nch = _GETC_(file); - if (width>0) width--; - } - /* terminate */ - if (!suppress) *sptr = 0; - } - break; - /* 'c' and 'C work analogously to 's' and 'S' as described - * above */ - case 'c': - if (w_prefix || l_prefix) goto widecharacter; - else if (h_prefix) goto character; -#ifdef WIDE_SCANF - else goto widecharacter; -#else /* WIDE_SCANF */ - else goto character; -#endif /* WIDE_SCANF */ - case 'C': - if (w_prefix || l_prefix) goto widecharacter; - else if (h_prefix) goto character; -#ifdef WIDE_SCANF - else goto character; -#else /* WIDE_SCANF */ - else goto widecharacter; -#endif /* WIDE_SCANF */ - character: { /* read single character into char */ - if (nch!=_EOF_) { - if (!suppress) { - char*c = va_arg(ap, char*); - *c = _CHAR2SUPPORTED_(nch); - } - st = 1; - nch = _GETC_(file); - } - } - break; - widecharacter: { /* read single character into a wchar_t */ - if (nch!=_EOF_) { - if (!suppress) { - wchar_t*c = va_arg(ap, wchar_t*); - *c = _WIDE2SUPPORTED_(nch); - } - nch = _GETC_(file); - st = 1; - } - } - break; - case 'n': { - if (!suppress) { - int*n = va_arg(ap, int*); - - /* - *n = consumed - (nch!=_EOF_); - - FIXME: The above is the Wine version and it doesnt work in ros - when %n is at end of input string (return one too many). - But does it fail in Wine too?? If so wine also needs fixin. - -Gunnar - */ - - *n = consumed - 1; - } - /* This is an odd one: according to the standard, - * "Execution of a %n directive does not increment the - * assignment count returned at the completion of - * execution" even if it wasn't suppressed with the - * '*' flag. The Corrigendum to the standard seems - * to contradict this (comment out the assignment to - * suppress below if you want to implement these - * alternate semantics) but the windows program I'm - * looking at expects the behavior I've coded here - * (which happens to be what glibc does as well). - */ - suppress = 1; - st = 1; - } - break; - case '[': { - _CHAR_ *str = suppress ? NULL : va_arg(ap, _CHAR_*); - _CHAR_ *sptr = str; - RTL_BITMAP bitMask; - ULONG *Mask; - int invert = 0; /* Set if we are NOT to find the chars */ - - /* Init our bitmap */ - Mask = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, _BITMAPSIZE_/8); - RtlInitializeBitMap(&bitMask, Mask, _BITMAPSIZE_); - - /* Read the format */ - format++; - if(*format == '^') { - invert = 1; - format++; - } - if(*format == ']') { - RtlSetBits(&bitMask, ']', 1); - format++; - } - while(*format && (*format != ']')) { - /* According to: - * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_crt_scanf_width_specification.asp - * "Note that %[a-z] and %[z-a] are interpreted as equivalent to %[abcde...z]." */ - if((*format == '-') && (*(format + 1) != ']')) { - if ((*(format - 1)) < *(format + 1)) - RtlSetBits(&bitMask, *(format - 1) +1 , *(format + 1) - *(format - 1)); - else - RtlSetBits(&bitMask, *(format + 1) , *(format - 1) - *(format + 1)); - format++; - } else - RtlSetBits(&bitMask, *format, 1); - format++; - } - /* read until char is not suitable */ - while ((width != 0) && (nch != _EOF_)) { - if(!invert) { - if(RtlAreBitsSet(&bitMask, nch, 1)) { - if (!suppress) *sptr++ = _CHAR2SUPPORTED_(nch); - } else - break; - } else { - if(RtlAreBitsClear(&bitMask, nch, 1)) { - if (!suppress) *sptr++ = _CHAR2SUPPORTED_(nch); - } else - break; - } - st++; - nch = _GETC_(file); - if (width>0) width--; - } - /* terminate */ - if (!suppress) *sptr = 0; - RtlFreeHeap(RtlGetProcessHeap(), 0, Mask); - } - break; - default: - /* From spec: "if a percent sign is followed by a character - * that has no meaning as a format-control character, that - * character and the following characters are treated as - * an ordinary sequence of characters, that is, a sequence - * of characters that must match the input. For example, - * to specify that a percent-sign character is to be input, - * use %%." */ - while ((nch!=_EOF_) && _ISSPACE_(nch)) - nch = _GETC_(file); - if (nch==*format) { - suppress = 1; /* whoops no field to be read */ - st = 1; /* but we got what we expected */ - nch = _GETC_(file); - } - break; - } - if (st && !suppress) rd++; - else if (!st) break; - } - /* a non-white-space character causes scanf to read, but not store, - * a matching non-white-space character. */ - else { - /* check for character match */ - if (nch == *format) { - nch = _GETC_(file); - } else break; - } - format++; - } - if (nch!=_EOF_) { - _UNGETC_(nch, file); - } - TRACE("returning %d\n", rd); - return rd; -} - -#undef _CHAR_ -#undef _EOF_ -#undef _EOF_RET -#undef _ISSPACE_ -#undef _ISDIGIT_ -#undef _CHAR2SUPPORTED_ -#undef _WIDE2SUPPORTED_ -#undef _CHAR2DIGIT_ -#undef _GETC_ -#undef _UNGETC_ -#undef _FUNCTION_ -#undef _BITMAPSIZE_ +/* + * general implementation of scanf used by scanf, sscanf, fscanf, + * _cscanf, wscanf, swscanf and fwscanf + * + * Copyright 1996,1998 Marcus Meissner + * Copyright 1996 Jukka Iivonen + * Copyright 1997,2000, 2003 Uwe Bonnes + * Copyright 2000 Jon Griffiths + * Copyright 2002 Daniel Gudbjartsson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef WIDE_SCANF +#define _CHAR_ wchar_t +#define _EOF_ WEOF +#define _EOF_RET WEOF +#define _ISSPACE_(c) iswspace(c) +#define _ISDIGIT_(c) iswdigit(c) +#define _WIDE2SUPPORTED_(c) c /* No conversion needed (wide to wide) */ +#define _CHAR2SUPPORTED_(c) c /* FIXME: convert char to wide char */ +#define _CHAR2DIGIT_(c, base) wchar2digit((c), (base)) +#define _BITMAPSIZE_ 256*256 +#else /* WIDE_SCANF */ +#define _CHAR_ char +#define _EOF_ EOF +#define _EOF_RET EOF +#define _ISSPACE_(c) isspace(c) +#define _ISDIGIT_(c) isdigit(c) +#define _WIDE2SUPPORTED_(c) c /* FIXME: convert wide char to char */ +#define _CHAR2SUPPORTED_(c) c /* No conversion needed (char to char) */ +#define _CHAR2DIGIT_(c, base) char2digit((c), (base)) +#define _BITMAPSIZE_ 256 +#endif /* WIDE_SCANF */ + +#ifdef CONSOLE +#define _GETC_(file) (consumed++, _getch()) +#define _UNGETC_(nch, file) do { _ungetch(nch); consumed--; } while(0) +#define _FUNCTION_ int vcscanf(const char *format, va_list ap) +#else +#ifdef STRING +#undef _EOF_ +#define _EOF_ 0 +#define _GETC_(file) (consumed++, *file++) +#define _UNGETC_(nch, file) do { file--; consumed--; } while(0) +#ifdef WIDE_SCANF +#define _FUNCTION_ int vswscanf(const wchar_t *file, const wchar_t *format, va_list ap) +#else /* WIDE_SCANF */ +#define _FUNCTION_ int vsscanf(const char *file, const char *format, va_list ap) +#endif /* WIDE_SCANF */ +#else /* STRING */ +#ifdef WIDE_SCANF +#define _GETC_(file) (consumed++, fgetwc(file)) +#define _UNGETC_(nch, file) do { ungetwc(nch, file); consumed--; } while(0) +#define _FUNCTION_ int vfwscanf(FILE* file, const wchar_t *format, va_list ap) +#else /* WIDE_SCANF */ +#define _GETC_(file) (consumed++, fgetc(file)) +#define _UNGETC_(nch, file) do { ungetc(nch, file); consumed--; } while(0) +#define _FUNCTION_ int vfscanf(FILE* file, const char *format, va_list ap) +#endif /* WIDE_SCANF */ +#endif /* STRING */ +#endif /* CONSOLE */ + +/********************************************************************* + * Implemented based on + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_crt_format_specification_fields_.2d_.scanf_and_wscanf_functions.asp + * Extended by C. Scott Ananian <cananian@alumni.princeton.edu> to handle + * more types of format spec. + */ +_FUNCTION_ { + int rd = 0, consumed = 0; + int nch; + if (!*format) return 0; +#ifndef WIDE_SCANF +#ifdef CONSOLE + TRACE("(%s): \n", debugstr_a(format)); +#else /* CONSOLE */ +#ifdef STRING + TRACE("%s (%s)\n", file, debugstr_a(format)); +#else /* STRING */ + TRACE("%p (%s)\n", file, debugstr_a(format)); +#endif /* STRING */ +#endif /* CONSOLE */ +#endif /* WIDE_SCANF */ + nch = _GETC_(file); + if (nch == _EOF_) return _EOF_RET; + + while (*format) { + /* a whitespace character in the format string causes scanf to read, + * but not store, all consecutive white-space characters in the input + * up to the next non-white-space character. One white space character + * in the input matches any number (including zero) and combination of + * white-space characters in the input. */ + if (_ISSPACE_(*format)) { + /* skip whitespace */ + while ((nch!=_EOF_) && _ISSPACE_(nch)) + nch = _GETC_(file); + } + /* a format specification causes scanf to read and convert characters + * in the input into values of a specified type. The value is assigned + * to an argument in the argument list. Format specifications have + * the form %[*][width][{h | l | I64 | L}]type */ + else if (*format == '%') { + int st = 0; int suppress = 0; int width = 0; + int base, number_signed; + int h_prefix = 0; + int l_prefix = 0; + int L_prefix = 0; + int w_prefix = 0; + int prefix_finished = 0; + int I64_prefix = 0; + format++; + /* look for leading asterisk, which means 'suppress assignment of + * this field'. */ + if (*format=='*') { + format++; + suppress=1; + } + /* look for width specification */ + while (_ISDIGIT_(*format)) { + width*=10; + width+=*format++ - '0'; + } + if (width==0) width=-1; /* no width spec seen */ + /* read prefix (if any) */ + while (!prefix_finished) { + switch(*format) { + case 'h': h_prefix = 1; break; + case 'l': l_prefix = 1; break; + case 'w': w_prefix = 1; break; + case 'L': L_prefix = 1; break; + case 'I': + if (*(format + 1) == '6' && + *(format + 2) == '4') { + I64_prefix = 1; + format += 2; + } + break; + default: + prefix_finished = 1; + } + if (!prefix_finished) format++; + } + /* read type */ + switch(*format) { + case 'x': + case 'X': /* hexadecimal integer. */ + base = 16; number_signed = 0; + goto number; + case 'o': /* octal integer */ + base = 8; number_signed = 0; + goto number; + case 'u': /* unsigned decimal integer */ + base = 10; number_signed = 0; + goto number; + case 'd': /* signed decimal integer */ + base = 10; number_signed = 1; + goto number; + case 'i': /* generic integer */ + base = 10; number_signed = 1; + number: { + /* read an integer */ + ULONGLONG cur = 0; + int negative = 0; + int seendigit=0; + /* skip initial whitespace */ + while ((nch!=_EOF_) && _ISSPACE_(nch)) + nch = _GETC_(file); + /* get sign */ + if (number_signed && (nch == '-' || + nch == '+')) { + negative = (nch=='-'); + nch = _GETC_(file); + if (width>0) width--; + } + /* look for leading indication of base */ + if (width!=0 && nch == '0') { + nch = _GETC_(file); + if (width>0) width--; + seendigit=1; + if (width!=0 && (nch=='x' || nch=='X')) { + if (base==0) + base=16; + if (base==16) { + nch = _GETC_(file); + if (width>0) width--; + seendigit=0; + } + } else if (base==0) + base = 8; + } + /* throw away leading zeros */ + while (width!=0 && nch=='0') { + nch = _GETC_(file); + if (width>0) width--; + seendigit=1; + } + if (width!=0 && _CHAR2DIGIT_(nch, base)!=-1) { + cur = _CHAR2DIGIT_(nch, base); + nch = _GETC_(file); + if (width>0) width--; + seendigit=1; + } + /* read until no more digits */ + while (width!=0 && (nch!=_EOF_) && _CHAR2DIGIT_(nch, base)!=-1) { + cur = cur*base + _CHAR2DIGIT_(nch, base); + nch = _GETC_(file); + if (width>0) width--; + seendigit=1; + } + /* okay, done! */ + if (!seendigit) break; /* not a valid number */ + st = 1; + if (!suppress) { +#define _SET_NUMBER_(type) *va_arg(ap, type*) = negative ? -cur : cur + if (number_signed) { + if (I64_prefix) _SET_NUMBER_(LONGLONG); + else if (l_prefix) _SET_NUMBER_(long int); + else if (h_prefix) _SET_NUMBER_(short int); + else _SET_NUMBER_(int); + } else { + if (negative) { + WARN("Dropping sign in reading a negative number into an unsigned value"); + negative = 0; + } + if (I64_prefix) _SET_NUMBER_(ULONGLONG); + else if (l_prefix) _SET_NUMBER_(unsigned long int); + else if (h_prefix) + _SET_NUMBER_(unsigned short int); + else _SET_NUMBER_(unsigned int); + } + } + } + break; + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': { /* read a float */ + long double cur = 0; + int negative = 0; + /* skip initial whitespace */ + while ((nch!=_EOF_) && _ISSPACE_(nch)) + nch = _GETC_(file); + /* get sign. */ + if (nch == '-' || nch == '+') { + negative = (nch=='-'); + if (width>0) width--; + if (width==0) break; + nch = _GETC_(file); + } + /* get first digit. */ + if ('.' != nch) { + if (!_ISDIGIT_(nch)) break; + cur = (nch - '0'); + nch = _GETC_(file); + if (width>0) width--; + /* read until no more digits */ + while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { + cur = cur*10 + (nch - '0'); + nch = _GETC_(file); + if (width>0) width--; + } + } else { + cur = 0; /* MaxPayneDemo Fix: .8 -> 0.8 */ + } + /* handle decimals */ + if (width!=0 && nch == '.') { + float dec = 1; + nch = _GETC_(file); + if (width>0) width--; + while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { + dec /= 10; + cur += dec * (nch - '0'); + nch = _GETC_(file); + if (width>0) width--; + } + } + /* handle exponent */ + if (width!=0 && (nch == 'e' || nch == 'E')) { + int exponent = 0, negexp = 0; + float expcnt; + nch = _GETC_(file); + if (width>0) width--; + /* possible sign on the exponent */ + if (width!=0 && (nch=='+' || nch=='-')) { + negexp = (nch=='-'); + nch = _GETC_(file); + if (width>0) width--; + } + /* exponent digits */ + while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { + exponent *= 10; + exponent += (nch - '0'); + nch = _GETC_(file); + if (width>0) width--; + } + /* update 'cur' with this exponent. */ + expcnt = negexp ? .1 : 10; + while (exponent!=0) { + if (exponent&1) + cur*=expcnt; + exponent/=2; + expcnt=expcnt*expcnt; + } + } + st = 1; + if (!suppress) { + if (L_prefix) _SET_NUMBER_(long double); + else if (l_prefix) _SET_NUMBER_(double); + else _SET_NUMBER_(float); + } + } + break; + /* According to + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt_scanf_type_field_characters.asp + * 's' reads a character string in a call to fscanf + * and 'S' a wide character string and vice versa in a + * call to fwscanf. The 'h', 'w' and 'l' prefixes override + * this behaviour. 'h' forces reading char * but 'l' and 'w' + * force reading WCHAR. */ + case 's': + if (w_prefix || l_prefix) goto widecharstring; + else if (h_prefix) goto charstring; +#ifdef WIDE_SCANF + else goto widecharstring; +#else /* WIDE_SCANF */ + else goto charstring; +#endif /* WIDE_SCANF */ + case 'S': + if (w_prefix || l_prefix) goto widecharstring; + else if (h_prefix) goto charstring; +#ifdef WIDE_SCANF + else goto charstring; +#else /* WIDE_SCANF */ + else goto widecharstring; +#endif /* WIDE_SCANF */ + charstring: { /* read a word into a char */ + char*str = suppress ? NULL : va_arg(ap, char*); + char*sptr = str; + /* skip initial whitespace */ + while ((nch!=_EOF_) && _ISSPACE_(nch)) + nch = _GETC_(file); + /* read until whitespace */ + while (width!=0 && (nch!=_EOF_) && !_ISSPACE_(nch)) { + if (!suppress) *sptr++ = _CHAR2SUPPORTED_(nch); + st++; + nch = _GETC_(file); + if (width>0) width--; + } + /* terminate */ + if (!suppress) *sptr = 0; + } + break; + widecharstring: { /* read a word into a wchar_t* */ + wchar_t*str = + suppress ? NULL : va_arg(ap, wchar_t*); + wchar_t*sptr = str; + /* skip initial whitespace */ + while ((nch!=_EOF_) && _ISSPACE_(nch)) + nch = _GETC_(file); + /* read until whitespace */ + while (width!=0 && (nch!=_EOF_) && !_ISSPACE_(nch)) { + if (!suppress) *sptr++ = _WIDE2SUPPORTED_(nch); + st++; + nch = _GETC_(file); + if (width>0) width--; + } + /* terminate */ + if (!suppress) *sptr = 0; + } + break; + /* 'c' and 'C work analogously to 's' and 'S' as described + * above */ + case 'c': + if (w_prefix || l_prefix) goto widecharacter; + else if (h_prefix) goto character; +#ifdef WIDE_SCANF + else goto widecharacter; +#else /* WIDE_SCANF */ + else goto character; +#endif /* WIDE_SCANF */ + case 'C': + if (w_prefix || l_prefix) goto widecharacter; + else if (h_prefix) goto character; +#ifdef WIDE_SCANF + else goto character; +#else /* WIDE_SCANF */ + else goto widecharacter; +#endif /* WIDE_SCANF */ + character: { /* read single character into char */ + if (nch!=_EOF_) { + if (!suppress) { + char*c = va_arg(ap, char*); + *c = _CHAR2SUPPORTED_(nch); + } + st = 1; + nch = _GETC_(file); + } + } + break; + widecharacter: { /* read single character into a wchar_t */ + if (nch!=_EOF_) { + if (!suppress) { + wchar_t*c = va_arg(ap, wchar_t*); + *c = _WIDE2SUPPORTED_(nch); + } + nch = _GETC_(file); + st = 1; + } + } + break; + case 'n': { + if (!suppress) { + int*n = va_arg(ap, int*); + + /* + *n = consumed - (nch!=_EOF_); + + FIXME: The above is the Wine version and it doesnt work in ros + when %n is at end of input string (return one too many). + But does it fail in Wine too?? If so wine also needs fixin. + -Gunnar + */ + + *n = consumed - 1; + } + /* This is an odd one: according to the standard, + * "Execution of a %n directive does not increment the + * assignment count returned at the completion of + * execution" even if it wasn't suppressed with the + * '*' flag. The Corrigendum to the standard seems + * to contradict this (comment out the assignment to + * suppress below if you want to implement these + * alternate semantics) but the windows program I'm + * looking at expects the behavior I've coded here + * (which happens to be what glibc does as well). + */ + suppress = 1; + st = 1; + } + break; + case '[': { + _CHAR_ *str = suppress ? NULL : va_arg(ap, _CHAR_*); + _CHAR_ *sptr = str; + RTL_BITMAP bitMask; + ULONG *Mask; + int invert = 0; /* Set if we are NOT to find the chars */ + + /* Init our bitmap */ + Mask = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, _BITMAPSIZE_/8); + RtlInitializeBitMap(&bitMask, Mask, _BITMAPSIZE_); + + /* Read the format */ + format++; + if(*format == '^') { + invert = 1; + format++; + } + if(*format == ']') { + RtlSetBits(&bitMask, ']', 1); + format++; + } + while(*format && (*format != ']')) { + /* According to: + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore98/html/_crt_scanf_width_specification.asp + * "Note that %[a-z] and %[z-a] are interpreted as equivalent to %[abcde...z]." */ + if((*format == '-') && (*(format + 1) != ']')) { + if ((*(format - 1)) < *(format + 1)) + RtlSetBits(&bitMask, *(format - 1) +1 , *(format + 1) - *(format - 1)); + else + RtlSetBits(&bitMask, *(format + 1) , *(format - 1) - *(format + 1)); + format++; + } else + RtlSetBits(&bitMask, *format, 1); + format++; + } + /* read until char is not suitable */ + while ((width != 0) && (nch != _EOF_)) { + if(!invert) { + if(RtlAreBitsSet(&bitMask, nch, 1)) { + if (!suppress) *sptr++ = _CHAR2SUPPORTED_(nch); + } else + break; + } else { + if(RtlAreBitsClear(&bitMask, nch, 1)) { + if (!suppress) *sptr++ = _CHAR2SUPPORTED_(nch); + } else + break; + } + st++; + nch = _GETC_(file); + if (width>0) width--; + } + /* terminate */ + if (!suppress) *sptr = 0; + RtlFreeHeap(RtlGetProcessHeap(), 0, Mask); + } + break; + default: + /* From spec: "if a percent sign is followed by a character + * that has no meaning as a format-control character, that + * character and the following characters are treated as + * an ordinary sequence of characters, that is, a sequence + * of characters that must match the input. For example, + * to specify that a percent-sign character is to be input, + * use %%." */ + while ((nch!=_EOF_) && _ISSPACE_(nch)) + nch = _GETC_(file); + if (nch==*format) { + suppress = 1; /* whoops no field to be read */ + st = 1; /* but we got what we expected */ + nch = _GETC_(file); + } + break; + } + if (st && !suppress) rd++; + else if (!st) break; + } + /* a non-white-space character causes scanf to read, but not store, + * a matching non-white-space character. */ + else { + /* check for character match */ + if (nch == *format) { + nch = _GETC_(file); + } else break; + } + format++; + } + if (nch!=_EOF_) { + _UNGETC_(nch, file); + } + TRACE("returning %d\n", rd); + return rd; +} + +#undef _CHAR_ +#undef _EOF_ +#undef _EOF_RET +#undef _ISSPACE_ +#undef _ISDIGIT_ +#undef _CHAR2SUPPORTED_ +#undef _WIDE2SUPPORTED_ +#undef _CHAR2DIGIT_ +#undef _GETC_ +#undef _UNGETC_ +#undef _FUNCTION_ +#undef _BITMAPSIZE_ diff --git a/reactos/lib/ole32/antimoniker.c b/reactos/lib/ole32/antimoniker.c index d0edf8c2197..f08f7aa1908 100644 --- a/reactos/lib/ole32/antimoniker.c +++ b/reactos/lib/ole32/antimoniker.c @@ -1,612 +1,612 @@ -/*************************************************************************************** - * AntiMonikers implementation - * - * Copyright 1999 Noomen Hamza - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - ***************************************************************************************/ - -#include <assert.h> -#include <stdarg.h> -#include <string.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "objbase.h" -#include "wine/debug.h" -#include "moniker.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -const CLSID CLSID_AntiMoniker = { - 0x305, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46} -}; - -/* AntiMoniker data structure */ -typedef struct AntiMonikerImpl{ - - IMonikerVtbl* lpvtbl1; /* VTable relative to the IMoniker interface.*/ - - /* The ROT (RunningObjectTable implementation) uses the IROTData interface to test whether - * two monikers are equal. That's whay IROTData interface is implemented by monikers. - */ - IROTDataVtbl* lpvtbl2; /* VTable relative to the IROTData interface.*/ - - ULONG ref; /* reference counter for this object */ - -} AntiMonikerImpl; - - -/******************************************************************************* - * AntiMoniker_QueryInterface - *******************************************************************************/ -static HRESULT WINAPI -AntiMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject) -{ - AntiMonikerImpl *This = (AntiMonikerImpl *)iface; - - TRACE("(%p,%p,%p)\n",This,riid,ppvObject); - - /* Perform a sanity check on the parameters.*/ - if ( (This==0) || (ppvObject==0) ) - return E_INVALIDARG; - - /* Initialize the return parameter */ - *ppvObject = 0; - - /* Compare the riid with the interface IDs implemented by this object.*/ - if (IsEqualIID(&IID_IUnknown, riid) || - IsEqualIID(&IID_IPersist, riid) || - IsEqualIID(&IID_IPersistStream, riid) || - IsEqualIID(&IID_IMoniker, riid)) - *ppvObject = iface; - else if (IsEqualIID(&IID_IROTData, riid)) - *ppvObject = (IROTData*)&(This->lpvtbl2); - - /* Check that we obtained an interface.*/ - if ((*ppvObject)==0) - return E_NOINTERFACE; - - /* always increase the reference count by one when it is successful */ - IMoniker_AddRef(iface); - - return S_OK; -} - -/****************************************************************************** - * AntiMoniker_AddRef - ******************************************************************************/ -static ULONG WINAPI -AntiMonikerImpl_AddRef(IMoniker* iface) -{ - AntiMonikerImpl *This = (AntiMonikerImpl *)iface; - - TRACE("(%p)\n",This); - - return InterlockedIncrement(&This->ref); -} - -/****************************************************************************** - * AntiMoniker_Release - ******************************************************************************/ -static ULONG WINAPI -AntiMonikerImpl_Release(IMoniker* iface) -{ - AntiMonikerImpl *This = (AntiMonikerImpl *)iface; - ULONG ref; - - TRACE("(%p)\n",This); - - ref = InterlockedDecrement(&This->ref); - - /* destroy the object if there's no more reference on it */ - if (ref == 0) HeapFree(GetProcessHeap(),0,This); - - return ref; -} - -/****************************************************************************** - * AntiMoniker_GetClassID - ******************************************************************************/ -static HRESULT WINAPI -AntiMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID) -{ - TRACE("(%p,%p),stub!\n",iface,pClassID); - - if (pClassID==NULL) - return E_POINTER; - - *pClassID = CLSID_AntiMoniker; - - return S_OK; -} - -/****************************************************************************** - * AntiMoniker_IsDirty - ******************************************************************************/ -static HRESULT WINAPI -AntiMonikerImpl_IsDirty(IMoniker* iface) -{ - /* Note that the OLE-provided implementations of the IPersistStream::IsDirty - method in the OLE-provided moniker interfaces always return S_FALSE because - their internal state never changes. */ - - TRACE("(%p)\n",iface); - - return S_FALSE; -} - -/****************************************************************************** - * AntiMoniker_Load - ******************************************************************************/ -static HRESULT WINAPI -AntiMonikerImpl_Load(IMoniker* iface,IStream* pStm) -{ - DWORD constant=1,dwbuffer; - HRESULT res; - - /* data read by this function is only a DWORD constant (must be 1) ! */ - res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),NULL); - - if (SUCCEEDED(res)&& dwbuffer!=constant) - return E_FAIL; - - return res; -} - -/****************************************************************************** - * AntiMoniker_Save - ******************************************************************************/ -static HRESULT WINAPI -AntiMonikerImpl_Save(IMoniker* iface,IStream* pStm,BOOL fClearDirty) -{ - DWORD constant=1; - HRESULT res; - - /* data written by this function is only a DWORD constant set to 1 ! */ - res=IStream_Write(pStm,&constant,sizeof(constant),NULL); - - return res; -} - -/****************************************************************************** - * AntiMoniker_GetSizeMax - * - * PARAMS - * pcbSize [out] Pointer to size of stream needed to save object - ******************************************************************************/ -static HRESULT WINAPI -AntiMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize) -{ - TRACE("(%p,%p)\n",iface,pcbSize); - - if (pcbSize!=NULL) - return E_POINTER; - - /* for more details see AntiMonikerImpl_Save coments */ - - /* - * Normally the sizemax must be sizeof DWORD, but - * I tested this function it usually return 16 bytes - * more than the number of bytes used by AntiMoniker::Save function - */ - pcbSize->u.LowPart = sizeof(DWORD)+16; - - pcbSize->u.HighPart=0; - - return S_OK; -} - -/****************************************************************************** - * AntiMoniker_BindToObject - ******************************************************************************/ -static HRESULT WINAPI -AntiMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, - REFIID riid, VOID** ppvResult) -{ - TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult); - return E_NOTIMPL; -} - -/****************************************************************************** - * AntiMoniker_BindToStorage - ******************************************************************************/ -static HRESULT WINAPI -AntiMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, - REFIID riid, VOID** ppvResult) -{ - TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult); - return E_NOTIMPL; -} - -/****************************************************************************** - * AntiMoniker_Reduce - ******************************************************************************/ -static HRESULT WINAPI -AntiMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar, - IMoniker** ppmkToLeft, IMoniker** ppmkReduced) -{ - TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); - - if (ppmkReduced==NULL) - return E_POINTER; - - AntiMonikerImpl_AddRef(iface); - - *ppmkReduced=iface; - - return MK_S_REDUCED_TO_SELF; -} -/****************************************************************************** - * AntiMoniker_ComposeWith - ******************************************************************************/ -static HRESULT WINAPI -AntiMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight, - BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite) -{ - - TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite); - - if ((ppmkComposite==NULL)||(pmkRight==NULL)) - return E_POINTER; - - *ppmkComposite=0; - - if (fOnlyIfNotGeneric) - return MK_E_NEEDGENERIC; - else - return CreateGenericComposite(iface,pmkRight,ppmkComposite); -} - -/****************************************************************************** - * AntiMoniker_Enum - ******************************************************************************/ -static HRESULT WINAPI -AntiMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker) -{ - TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker); - - if (ppenumMoniker == NULL) - return E_POINTER; - - *ppenumMoniker = NULL; - - return S_OK; -} - -/****************************************************************************** - * AntiMoniker_IsEqual - ******************************************************************************/ -static HRESULT WINAPI -AntiMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker) -{ - DWORD mkSys; - - TRACE("(%p,%p)\n",iface,pmkOtherMoniker); - - if (pmkOtherMoniker==NULL) - return S_FALSE; - - IMoniker_IsSystemMoniker(pmkOtherMoniker,&mkSys); - - if (mkSys==MKSYS_ANTIMONIKER) - return S_OK; - else - return S_FALSE; -} - -/****************************************************************************** - * AntiMoniker_Hash - ******************************************************************************/ -static HRESULT WINAPI AntiMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash) -{ - if (pdwHash==NULL) - return E_POINTER; - - *pdwHash=0; - - return S_OK; -} - -/****************************************************************************** - * AntiMoniker_IsRunning - ******************************************************************************/ -static HRESULT WINAPI -AntiMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, - IMoniker* pmkNewlyRunning) -{ - IRunningObjectTable* rot; - HRESULT res; - - TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning); - - if (pbc==NULL) - return E_INVALIDARG; - - res=IBindCtx_GetRunningObjectTable(pbc,&rot); - - if (FAILED(res)) - return res; - - res = IRunningObjectTable_IsRunning(rot,iface); - - IRunningObjectTable_Release(rot); - - return res; -} - -/****************************************************************************** - * AntiMoniker_GetTimeOfLastChange - ******************************************************************************/ -static HRESULT WINAPI AntiMonikerImpl_GetTimeOfLastChange(IMoniker* iface, - IBindCtx* pbc, - IMoniker* pmkToLeft, - FILETIME* pAntiTime) -{ - TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pAntiTime); - return E_NOTIMPL; -} - -/****************************************************************************** - * AntiMoniker_Inverse - ******************************************************************************/ -static HRESULT WINAPI -AntiMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk) -{ - TRACE("(%p,%p)\n",iface,ppmk); - - if (ppmk==NULL) - return E_POINTER; - - *ppmk=0; - - return MK_E_NOINVERSE; -} - -/****************************************************************************** - * AntiMoniker_CommonPrefixWith - ******************************************************************************/ -static HRESULT WINAPI -AntiMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix) -{ - DWORD mkSys; - - IMoniker_IsSystemMoniker(pmkOther,&mkSys); - - if(mkSys==MKSYS_ITEMMONIKER){ - - IMoniker_AddRef(iface); - - *ppmkPrefix=iface; - - IMoniker_AddRef(iface); - - return MK_S_US; - } - else - return MonikerCommonPrefixWith(iface,pmkOther,ppmkPrefix); -} - -/****************************************************************************** - * AntiMoniker_RelativePathTo - ******************************************************************************/ -static HRESULT WINAPI -AntiMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath) -{ - TRACE("(%p,%p,%p)\n",iface,pmOther,ppmkRelPath); - - if (ppmkRelPath==NULL) - return E_POINTER; - - IMoniker_AddRef(pmOther); - - *ppmkRelPath=pmOther; - - return MK_S_HIM; -} - -/****************************************************************************** - * AntiMoniker_GetDisplayName - ******************************************************************************/ -static HRESULT WINAPI -AntiMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc, - IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName) -{ - static const WCHAR back[]={'\\','.','.',0}; - - TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName); - - if (ppszDisplayName==NULL) - return E_POINTER; - - if (pmkToLeft!=NULL){ - FIXME("() pmkToLeft!=NULL not implemented \n"); - return E_NOTIMPL; - } - - *ppszDisplayName=CoTaskMemAlloc(sizeof(back)); - - if (*ppszDisplayName==NULL) - return E_OUTOFMEMORY; - - lstrcpyW(*ppszDisplayName,back); - - return S_OK; -} - -/****************************************************************************** - * AntiMoniker_ParseDisplayName - ******************************************************************************/ -static HRESULT WINAPI -AntiMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc, - IMoniker* pmkToLeft, LPOLESTR pszDisplayName, - ULONG* pchEaten, IMoniker** ppmkOut) -{ - TRACE("(%p,%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut); - return E_NOTIMPL; -} - -/****************************************************************************** - * AntiMoniker_IsSystemMoniker - ******************************************************************************/ -static HRESULT WINAPI -AntiMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys) -{ - TRACE("(%p,%p)\n",iface,pwdMksys); - - if (!pwdMksys) - return E_POINTER; - - (*pwdMksys)=MKSYS_ANTIMONIKER; - - return S_OK; -} - -/******************************************************************************* - * AntiMonikerIROTData_QueryInterface - *******************************************************************************/ -static HRESULT WINAPI -AntiMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject) -{ - ICOM_THIS_From_IROTData(IMoniker, iface); - - TRACE("(%p,%p,%p)\n",iface,riid,ppvObject); - - return AntiMonikerImpl_QueryInterface(This, riid, ppvObject); -} - -/*********************************************************************** - * AntiMonikerIROTData_AddRef - */ -static ULONG WINAPI AntiMonikerROTDataImpl_AddRef(IROTData *iface) -{ - ICOM_THIS_From_IROTData(IMoniker, iface); - - TRACE("(%p)\n",iface); - - return AntiMonikerImpl_AddRef(This); -} - -/*********************************************************************** - * AntiMonikerIROTData_Release - */ -static ULONG WINAPI AntiMonikerROTDataImpl_Release(IROTData* iface) -{ - ICOM_THIS_From_IROTData(IMoniker, iface); - - TRACE("(%p)\n",iface); - - return AntiMonikerImpl_Release(This); -} - -/****************************************************************************** - * AntiMonikerIROTData_GetComparaisonData - ******************************************************************************/ -static HRESULT WINAPI -AntiMonikerROTDataImpl_GetComparaisonData(IROTData* iface, BYTE* pbData, - ULONG cbMax, ULONG* pcbData) -{ - FIXME("(),stub!\n"); - return E_NOTIMPL; -} - -/********************************************************************************/ -/* Virtual function table for the AntiMonikerImpl class which include IPersist,*/ -/* IPersistStream and IMoniker functions. */ -static IMonikerVtbl VT_AntiMonikerImpl = -{ - AntiMonikerImpl_QueryInterface, - AntiMonikerImpl_AddRef, - AntiMonikerImpl_Release, - AntiMonikerImpl_GetClassID, - AntiMonikerImpl_IsDirty, - AntiMonikerImpl_Load, - AntiMonikerImpl_Save, - AntiMonikerImpl_GetSizeMax, - AntiMonikerImpl_BindToObject, - AntiMonikerImpl_BindToStorage, - AntiMonikerImpl_Reduce, - AntiMonikerImpl_ComposeWith, - AntiMonikerImpl_Enum, - AntiMonikerImpl_IsEqual, - AntiMonikerImpl_Hash, - AntiMonikerImpl_IsRunning, - AntiMonikerImpl_GetTimeOfLastChange, - AntiMonikerImpl_Inverse, - AntiMonikerImpl_CommonPrefixWith, - AntiMonikerImpl_RelativePathTo, - AntiMonikerImpl_GetDisplayName, - AntiMonikerImpl_ParseDisplayName, - AntiMonikerImpl_IsSystemMoniker -}; - -/********************************************************************************/ -/* Virtual function table for the IROTData class. */ -static IROTDataVtbl VT_ROTDataImpl = -{ - AntiMonikerROTDataImpl_QueryInterface, - AntiMonikerROTDataImpl_AddRef, - AntiMonikerROTDataImpl_Release, - AntiMonikerROTDataImpl_GetComparaisonData -}; - -/****************************************************************************** - * AntiMoniker_Construct (local function) - *******************************************************************************/ -static HRESULT AntiMonikerImpl_Construct(AntiMonikerImpl* This) -{ - - TRACE("(%p)\n",This); - - /* Initialize the virtual fgunction table. */ - This->lpvtbl1 = &VT_AntiMonikerImpl; - This->lpvtbl2 = &VT_ROTDataImpl; - This->ref = 0; - - return S_OK; -} - -/****************************************************************************** - * CreateAntiMoniker [OLE32.@] - ******************************************************************************/ -HRESULT WINAPI CreateAntiMoniker(LPMONIKER * ppmk) -{ - AntiMonikerImpl* newAntiMoniker = 0; - HRESULT hr = S_OK; - IID riid=IID_IMoniker; - - TRACE("(%p)\n",ppmk); - - newAntiMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(AntiMonikerImpl)); - - if (newAntiMoniker == 0) - return STG_E_INSUFFICIENTMEMORY; - - hr = AntiMonikerImpl_Construct(newAntiMoniker); - if (FAILED(hr)) - { - HeapFree(GetProcessHeap(),0,newAntiMoniker); - return hr; - } - - hr = AntiMonikerImpl_QueryInterface((IMoniker*)newAntiMoniker,&riid,(void**)ppmk); - - return hr; -} +/*************************************************************************************** + * AntiMonikers implementation + * + * Copyright 1999 Noomen Hamza + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + ***************************************************************************************/ + +#include <assert.h> +#include <stdarg.h> +#include <string.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "objbase.h" +#include "wine/debug.h" +#include "moniker.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +const CLSID CLSID_AntiMoniker = { + 0x305, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46} +}; + +/* AntiMoniker data structure */ +typedef struct AntiMonikerImpl{ + + IMonikerVtbl* lpvtbl1; /* VTable relative to the IMoniker interface.*/ + + /* The ROT (RunningObjectTable implementation) uses the IROTData interface to test whether + * two monikers are equal. That's whay IROTData interface is implemented by monikers. + */ + IROTDataVtbl* lpvtbl2; /* VTable relative to the IROTData interface.*/ + + ULONG ref; /* reference counter for this object */ + +} AntiMonikerImpl; + + +/******************************************************************************* + * AntiMoniker_QueryInterface + *******************************************************************************/ +static HRESULT WINAPI +AntiMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject) +{ + AntiMonikerImpl *This = (AntiMonikerImpl *)iface; + + TRACE("(%p,%p,%p)\n",This,riid,ppvObject); + + /* Perform a sanity check on the parameters.*/ + if ( (This==0) || (ppvObject==0) ) + return E_INVALIDARG; + + /* Initialize the return parameter */ + *ppvObject = 0; + + /* Compare the riid with the interface IDs implemented by this object.*/ + if (IsEqualIID(&IID_IUnknown, riid) || + IsEqualIID(&IID_IPersist, riid) || + IsEqualIID(&IID_IPersistStream, riid) || + IsEqualIID(&IID_IMoniker, riid)) + *ppvObject = iface; + else if (IsEqualIID(&IID_IROTData, riid)) + *ppvObject = (IROTData*)&(This->lpvtbl2); + + /* Check that we obtained an interface.*/ + if ((*ppvObject)==0) + return E_NOINTERFACE; + + /* always increase the reference count by one when it is successful */ + IMoniker_AddRef(iface); + + return S_OK; +} + +/****************************************************************************** + * AntiMoniker_AddRef + ******************************************************************************/ +static ULONG WINAPI +AntiMonikerImpl_AddRef(IMoniker* iface) +{ + AntiMonikerImpl *This = (AntiMonikerImpl *)iface; + + TRACE("(%p)\n",This); + + return InterlockedIncrement(&This->ref); +} + +/****************************************************************************** + * AntiMoniker_Release + ******************************************************************************/ +static ULONG WINAPI +AntiMonikerImpl_Release(IMoniker* iface) +{ + AntiMonikerImpl *This = (AntiMonikerImpl *)iface; + ULONG ref; + + TRACE("(%p)\n",This); + + ref = InterlockedDecrement(&This->ref); + + /* destroy the object if there's no more reference on it */ + if (ref == 0) HeapFree(GetProcessHeap(),0,This); + + return ref; +} + +/****************************************************************************** + * AntiMoniker_GetClassID + ******************************************************************************/ +static HRESULT WINAPI +AntiMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID) +{ + TRACE("(%p,%p),stub!\n",iface,pClassID); + + if (pClassID==NULL) + return E_POINTER; + + *pClassID = CLSID_AntiMoniker; + + return S_OK; +} + +/****************************************************************************** + * AntiMoniker_IsDirty + ******************************************************************************/ +static HRESULT WINAPI +AntiMonikerImpl_IsDirty(IMoniker* iface) +{ + /* Note that the OLE-provided implementations of the IPersistStream::IsDirty + method in the OLE-provided moniker interfaces always return S_FALSE because + their internal state never changes. */ + + TRACE("(%p)\n",iface); + + return S_FALSE; +} + +/****************************************************************************** + * AntiMoniker_Load + ******************************************************************************/ +static HRESULT WINAPI +AntiMonikerImpl_Load(IMoniker* iface,IStream* pStm) +{ + DWORD constant=1,dwbuffer; + HRESULT res; + + /* data read by this function is only a DWORD constant (must be 1) ! */ + res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),NULL); + + if (SUCCEEDED(res)&& dwbuffer!=constant) + return E_FAIL; + + return res; +} + +/****************************************************************************** + * AntiMoniker_Save + ******************************************************************************/ +static HRESULT WINAPI +AntiMonikerImpl_Save(IMoniker* iface,IStream* pStm,BOOL fClearDirty) +{ + DWORD constant=1; + HRESULT res; + + /* data written by this function is only a DWORD constant set to 1 ! */ + res=IStream_Write(pStm,&constant,sizeof(constant),NULL); + + return res; +} + +/****************************************************************************** + * AntiMoniker_GetSizeMax + * + * PARAMS + * pcbSize [out] Pointer to size of stream needed to save object + ******************************************************************************/ +static HRESULT WINAPI +AntiMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize) +{ + TRACE("(%p,%p)\n",iface,pcbSize); + + if (pcbSize!=NULL) + return E_POINTER; + + /* for more details see AntiMonikerImpl_Save coments */ + + /* + * Normally the sizemax must be sizeof DWORD, but + * I tested this function it usually return 16 bytes + * more than the number of bytes used by AntiMoniker::Save function + */ + pcbSize->u.LowPart = sizeof(DWORD)+16; + + pcbSize->u.HighPart=0; + + return S_OK; +} + +/****************************************************************************** + * AntiMoniker_BindToObject + ******************************************************************************/ +static HRESULT WINAPI +AntiMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, + REFIID riid, VOID** ppvResult) +{ + TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult); + return E_NOTIMPL; +} + +/****************************************************************************** + * AntiMoniker_BindToStorage + ******************************************************************************/ +static HRESULT WINAPI +AntiMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, + REFIID riid, VOID** ppvResult) +{ + TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult); + return E_NOTIMPL; +} + +/****************************************************************************** + * AntiMoniker_Reduce + ******************************************************************************/ +static HRESULT WINAPI +AntiMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar, + IMoniker** ppmkToLeft, IMoniker** ppmkReduced) +{ + TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); + + if (ppmkReduced==NULL) + return E_POINTER; + + AntiMonikerImpl_AddRef(iface); + + *ppmkReduced=iface; + + return MK_S_REDUCED_TO_SELF; +} +/****************************************************************************** + * AntiMoniker_ComposeWith + ******************************************************************************/ +static HRESULT WINAPI +AntiMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight, + BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite) +{ + + TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite); + + if ((ppmkComposite==NULL)||(pmkRight==NULL)) + return E_POINTER; + + *ppmkComposite=0; + + if (fOnlyIfNotGeneric) + return MK_E_NEEDGENERIC; + else + return CreateGenericComposite(iface,pmkRight,ppmkComposite); +} + +/****************************************************************************** + * AntiMoniker_Enum + ******************************************************************************/ +static HRESULT WINAPI +AntiMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker) +{ + TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker); + + if (ppenumMoniker == NULL) + return E_POINTER; + + *ppenumMoniker = NULL; + + return S_OK; +} + +/****************************************************************************** + * AntiMoniker_IsEqual + ******************************************************************************/ +static HRESULT WINAPI +AntiMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker) +{ + DWORD mkSys; + + TRACE("(%p,%p)\n",iface,pmkOtherMoniker); + + if (pmkOtherMoniker==NULL) + return S_FALSE; + + IMoniker_IsSystemMoniker(pmkOtherMoniker,&mkSys); + + if (mkSys==MKSYS_ANTIMONIKER) + return S_OK; + else + return S_FALSE; +} + +/****************************************************************************** + * AntiMoniker_Hash + ******************************************************************************/ +static HRESULT WINAPI AntiMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash) +{ + if (pdwHash==NULL) + return E_POINTER; + + *pdwHash=0; + + return S_OK; +} + +/****************************************************************************** + * AntiMoniker_IsRunning + ******************************************************************************/ +static HRESULT WINAPI +AntiMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, + IMoniker* pmkNewlyRunning) +{ + IRunningObjectTable* rot; + HRESULT res; + + TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning); + + if (pbc==NULL) + return E_INVALIDARG; + + res=IBindCtx_GetRunningObjectTable(pbc,&rot); + + if (FAILED(res)) + return res; + + res = IRunningObjectTable_IsRunning(rot,iface); + + IRunningObjectTable_Release(rot); + + return res; +} + +/****************************************************************************** + * AntiMoniker_GetTimeOfLastChange + ******************************************************************************/ +static HRESULT WINAPI AntiMonikerImpl_GetTimeOfLastChange(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + FILETIME* pAntiTime) +{ + TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pAntiTime); + return E_NOTIMPL; +} + +/****************************************************************************** + * AntiMoniker_Inverse + ******************************************************************************/ +static HRESULT WINAPI +AntiMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk) +{ + TRACE("(%p,%p)\n",iface,ppmk); + + if (ppmk==NULL) + return E_POINTER; + + *ppmk=0; + + return MK_E_NOINVERSE; +} + +/****************************************************************************** + * AntiMoniker_CommonPrefixWith + ******************************************************************************/ +static HRESULT WINAPI +AntiMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix) +{ + DWORD mkSys; + + IMoniker_IsSystemMoniker(pmkOther,&mkSys); + + if(mkSys==MKSYS_ITEMMONIKER){ + + IMoniker_AddRef(iface); + + *ppmkPrefix=iface; + + IMoniker_AddRef(iface); + + return MK_S_US; + } + else + return MonikerCommonPrefixWith(iface,pmkOther,ppmkPrefix); +} + +/****************************************************************************** + * AntiMoniker_RelativePathTo + ******************************************************************************/ +static HRESULT WINAPI +AntiMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath) +{ + TRACE("(%p,%p,%p)\n",iface,pmOther,ppmkRelPath); + + if (ppmkRelPath==NULL) + return E_POINTER; + + IMoniker_AddRef(pmOther); + + *ppmkRelPath=pmOther; + + return MK_S_HIM; +} + +/****************************************************************************** + * AntiMoniker_GetDisplayName + ******************************************************************************/ +static HRESULT WINAPI +AntiMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc, + IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName) +{ + static const WCHAR back[]={'\\','.','.',0}; + + TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName); + + if (ppszDisplayName==NULL) + return E_POINTER; + + if (pmkToLeft!=NULL){ + FIXME("() pmkToLeft!=NULL not implemented \n"); + return E_NOTIMPL; + } + + *ppszDisplayName=CoTaskMemAlloc(sizeof(back)); + + if (*ppszDisplayName==NULL) + return E_OUTOFMEMORY; + + lstrcpyW(*ppszDisplayName,back); + + return S_OK; +} + +/****************************************************************************** + * AntiMoniker_ParseDisplayName + ******************************************************************************/ +static HRESULT WINAPI +AntiMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc, + IMoniker* pmkToLeft, LPOLESTR pszDisplayName, + ULONG* pchEaten, IMoniker** ppmkOut) +{ + TRACE("(%p,%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut); + return E_NOTIMPL; +} + +/****************************************************************************** + * AntiMoniker_IsSystemMoniker + ******************************************************************************/ +static HRESULT WINAPI +AntiMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys) +{ + TRACE("(%p,%p)\n",iface,pwdMksys); + + if (!pwdMksys) + return E_POINTER; + + (*pwdMksys)=MKSYS_ANTIMONIKER; + + return S_OK; +} + +/******************************************************************************* + * AntiMonikerIROTData_QueryInterface + *******************************************************************************/ +static HRESULT WINAPI +AntiMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject) +{ + ICOM_THIS_From_IROTData(IMoniker, iface); + + TRACE("(%p,%p,%p)\n",iface,riid,ppvObject); + + return AntiMonikerImpl_QueryInterface(This, riid, ppvObject); +} + +/*********************************************************************** + * AntiMonikerIROTData_AddRef + */ +static ULONG WINAPI AntiMonikerROTDataImpl_AddRef(IROTData *iface) +{ + ICOM_THIS_From_IROTData(IMoniker, iface); + + TRACE("(%p)\n",iface); + + return AntiMonikerImpl_AddRef(This); +} + +/*********************************************************************** + * AntiMonikerIROTData_Release + */ +static ULONG WINAPI AntiMonikerROTDataImpl_Release(IROTData* iface) +{ + ICOM_THIS_From_IROTData(IMoniker, iface); + + TRACE("(%p)\n",iface); + + return AntiMonikerImpl_Release(This); +} + +/****************************************************************************** + * AntiMonikerIROTData_GetComparaisonData + ******************************************************************************/ +static HRESULT WINAPI +AntiMonikerROTDataImpl_GetComparaisonData(IROTData* iface, BYTE* pbData, + ULONG cbMax, ULONG* pcbData) +{ + FIXME("(),stub!\n"); + return E_NOTIMPL; +} + +/********************************************************************************/ +/* Virtual function table for the AntiMonikerImpl class which include IPersist,*/ +/* IPersistStream and IMoniker functions. */ +static IMonikerVtbl VT_AntiMonikerImpl = +{ + AntiMonikerImpl_QueryInterface, + AntiMonikerImpl_AddRef, + AntiMonikerImpl_Release, + AntiMonikerImpl_GetClassID, + AntiMonikerImpl_IsDirty, + AntiMonikerImpl_Load, + AntiMonikerImpl_Save, + AntiMonikerImpl_GetSizeMax, + AntiMonikerImpl_BindToObject, + AntiMonikerImpl_BindToStorage, + AntiMonikerImpl_Reduce, + AntiMonikerImpl_ComposeWith, + AntiMonikerImpl_Enum, + AntiMonikerImpl_IsEqual, + AntiMonikerImpl_Hash, + AntiMonikerImpl_IsRunning, + AntiMonikerImpl_GetTimeOfLastChange, + AntiMonikerImpl_Inverse, + AntiMonikerImpl_CommonPrefixWith, + AntiMonikerImpl_RelativePathTo, + AntiMonikerImpl_GetDisplayName, + AntiMonikerImpl_ParseDisplayName, + AntiMonikerImpl_IsSystemMoniker +}; + +/********************************************************************************/ +/* Virtual function table for the IROTData class. */ +static IROTDataVtbl VT_ROTDataImpl = +{ + AntiMonikerROTDataImpl_QueryInterface, + AntiMonikerROTDataImpl_AddRef, + AntiMonikerROTDataImpl_Release, + AntiMonikerROTDataImpl_GetComparaisonData +}; + +/****************************************************************************** + * AntiMoniker_Construct (local function) + *******************************************************************************/ +static HRESULT AntiMonikerImpl_Construct(AntiMonikerImpl* This) +{ + + TRACE("(%p)\n",This); + + /* Initialize the virtual fgunction table. */ + This->lpvtbl1 = &VT_AntiMonikerImpl; + This->lpvtbl2 = &VT_ROTDataImpl; + This->ref = 0; + + return S_OK; +} + +/****************************************************************************** + * CreateAntiMoniker [OLE32.@] + ******************************************************************************/ +HRESULT WINAPI CreateAntiMoniker(LPMONIKER * ppmk) +{ + AntiMonikerImpl* newAntiMoniker = 0; + HRESULT hr = S_OK; + IID riid=IID_IMoniker; + + TRACE("(%p)\n",ppmk); + + newAntiMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(AntiMonikerImpl)); + + if (newAntiMoniker == 0) + return STG_E_INSUFFICIENTMEMORY; + + hr = AntiMonikerImpl_Construct(newAntiMoniker); + if (FAILED(hr)) + { + HeapFree(GetProcessHeap(),0,newAntiMoniker); + return hr; + } + + hr = AntiMonikerImpl_QueryInterface((IMoniker*)newAntiMoniker,&riid,(void**)ppmk); + + return hr; +} diff --git a/reactos/lib/ole32/bindctx.c b/reactos/lib/ole32/bindctx.c index 30f67b54b2f..1992e62edb2 100644 --- a/reactos/lib/ole32/bindctx.c +++ b/reactos/lib/ole32/bindctx.c @@ -1,575 +1,575 @@ -/*************************************************************************************** - * BindCtx implementation - * - * Copyright 1999 Noomen Hamza - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - ***************************************************************************************/ - -#include <stdarg.h> -#include <string.h> -#include <assert.h> - -#define COBJMACROS - -#include "winerror.h" -#include "windef.h" -#include "winbase.h" -#include "objbase.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/* represent the first size table and it's increment block size */ -#define BLOCK_TAB_SIZE 10 -#define MAX_TAB_SIZE 0xFFFFFFFF - -/* data structure of the BindCtx table elements */ -typedef struct BindCtxObject{ - - IUnknown* pObj; /* point on a bound object */ - - LPOLESTR pkeyObj; /* key associated to this bound object */ - - BYTE regType; /* registration type: 1 if RegisterObjectParam and 0 if RegisterObjectBound */ - -} BindCtxObject; - -/* BindCtx data strucrture */ -typedef struct BindCtxImpl{ - - IBindCtxVtbl *lpVtbl; /* VTable relative to the IBindCtx interface.*/ - - ULONG ref; /* reference counter for this object */ - - BindCtxObject* bindCtxTable; /* this is a table in which all bounded objects are stored*/ - DWORD bindCtxTableLastIndex; /* first free index in the table */ - DWORD bindCtxTableSize; /* size table */ - - BIND_OPTS2 bindOption2; /* a structure which contains the bind options*/ - -} BindCtxImpl; - -/* IBindCtx prototype functions : */ -static HRESULT WINAPI BindCtxImpl_ReleaseBoundObjects(IBindCtx*); -static HRESULT BindCtxImpl_GetObjectIndex(BindCtxImpl*, IUnknown*, LPOLESTR, DWORD *); - -/******************************************************************************* - * BindCtx_QueryInterface - *******************************************************************************/ -static HRESULT WINAPI -BindCtxImpl_QueryInterface(IBindCtx* iface,REFIID riid,void** ppvObject) -{ - BindCtxImpl *This = (BindCtxImpl *)iface; - - TRACE("(%p,%p,%p)\n",This,riid,ppvObject); - - /* Perform a sanity check on the parameters.*/ - if ( (This==0) || (ppvObject==0) ) - return E_INVALIDARG; - - /* Initialize the return parameter.*/ - *ppvObject = 0; - - /* Compare the riid with the interface IDs implemented by this object.*/ - if (IsEqualIID(&IID_IUnknown, riid) || - IsEqualIID(&IID_IBindCtx, riid)) - { - *ppvObject = (IBindCtx*)This; - IBindCtx_AddRef(iface); - return S_OK; - } - - return E_NOINTERFACE; -} - -/****************************************************************************** - * BindCtx_AddRef - ******************************************************************************/ -static ULONG WINAPI BindCtxImpl_AddRef(IBindCtx* iface) -{ - BindCtxImpl *This = (BindCtxImpl *)iface; - - TRACE("(%p)\n",This); - - return InterlockedIncrement(&This->ref); -} - -/****************************************************************************** - * BindCtx_Destroy (local function) - *******************************************************************************/ -static HRESULT BindCtxImpl_Destroy(BindCtxImpl* This) -{ - TRACE("(%p)\n",This); - - /* free the table space memory */ - HeapFree(GetProcessHeap(),0,This->bindCtxTable); - - /* free the bindctx structure */ - HeapFree(GetProcessHeap(),0,This); - - return S_OK; -} - -/****************************************************************************** - * BindCtx_Release - ******************************************************************************/ -static ULONG WINAPI BindCtxImpl_Release(IBindCtx* iface) -{ - BindCtxImpl *This = (BindCtxImpl *)iface; - ULONG ref; - - TRACE("(%p)\n",This); - - ref = InterlockedDecrement(&This->ref); - if (ref == 0) - { - /* release all registered objects */ - BindCtxImpl_ReleaseBoundObjects((IBindCtx*)This); - - BindCtxImpl_Destroy(This); - } - return ref; -} - - -/****************************************************************************** - * BindCtx_RegisterObjectBound - ******************************************************************************/ -static HRESULT WINAPI -BindCtxImpl_RegisterObjectBound(IBindCtx* iface,IUnknown* punk) -{ - BindCtxImpl *This = (BindCtxImpl *)iface; - DWORD lastIndex=This->bindCtxTableLastIndex; - - TRACE("(%p,%p)\n",This,punk); - - if (punk==NULL) - return E_POINTER; - - IUnknown_AddRef(punk); - - /* put the object in the first free element in the table */ - This->bindCtxTable[lastIndex].pObj = punk; - This->bindCtxTable[lastIndex].pkeyObj = NULL; - This->bindCtxTable[lastIndex].regType = 0; - lastIndex= ++This->bindCtxTableLastIndex; - - if (lastIndex == This->bindCtxTableSize){ /* the table is full so it must be resized */ - - if (This->bindCtxTableSize > (MAX_TAB_SIZE-BLOCK_TAB_SIZE)){ - FIXME("This->bindCtxTableSize: %ld is out of data limite \n",This->bindCtxTableSize); - return E_FAIL; - } - - This->bindCtxTableSize+=BLOCK_TAB_SIZE; /* new table size */ - - This->bindCtxTable = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->bindCtxTable, - This->bindCtxTableSize * sizeof(BindCtxObject)); - if (!This->bindCtxTable) - return E_OUTOFMEMORY; - } - return S_OK; -} - -/****************************************************************************** - * BindCtx_RevokeObjectBound - ******************************************************************************/ -static HRESULT WINAPI -BindCtxImpl_RevokeObjectBound(IBindCtx* iface, IUnknown* punk) -{ - DWORD index,j; - - BindCtxImpl *This = (BindCtxImpl *)iface; - - TRACE("(%p,%p)\n",This,punk); - - /* check if the object was registered or not */ - if (BindCtxImpl_GetObjectIndex(This,punk,NULL,&index)==S_FALSE) - return MK_E_NOTBOUND; - - if(This->bindCtxTable[index].pObj) - IUnknown_Release(This->bindCtxTable[index].pObj); - HeapFree(GetProcessHeap(),0,This->bindCtxTable[index].pkeyObj); - - /* left-shift all elements in the right side of the current revoked object */ - for(j=index; j<This->bindCtxTableLastIndex-1; j++) - This->bindCtxTable[j]= This->bindCtxTable[j+1]; - - This->bindCtxTableLastIndex--; - - return S_OK; -} - -/****************************************************************************** - * BindCtx_ReleaseBoundObjects - ******************************************************************************/ -static HRESULT WINAPI -BindCtxImpl_ReleaseBoundObjects(IBindCtx* iface) -{ - DWORD i; - - BindCtxImpl *This = (BindCtxImpl *)iface; - - TRACE("(%p)\n",This); - - for(i=0;i<This->bindCtxTableLastIndex;i++) - { - if(This->bindCtxTable[i].pObj) - IUnknown_Release(This->bindCtxTable[i].pObj); - HeapFree(GetProcessHeap(),0,This->bindCtxTable[i].pkeyObj); - } - - This->bindCtxTableLastIndex = 0; - - return S_OK; -} - -/****************************************************************************** - * BindCtx_SetBindOptions - ******************************************************************************/ -static HRESULT WINAPI -BindCtxImpl_SetBindOptions(IBindCtx* iface,BIND_OPTS *pbindopts) -{ - BindCtxImpl *This = (BindCtxImpl *)iface; - - TRACE("(%p,%p)\n",This,pbindopts); - - if (pbindopts==NULL) - return E_POINTER; - - if (pbindopts->cbStruct > sizeof(BIND_OPTS2)) - { - WARN("invalid size\n"); - return E_INVALIDARG; /* FIXME : not verified */ - } - memcpy(&This->bindOption2, pbindopts, pbindopts->cbStruct); - return S_OK; -} - -/****************************************************************************** - * BindCtx_GetBindOptions - ******************************************************************************/ -static HRESULT WINAPI -BindCtxImpl_GetBindOptions(IBindCtx* iface,BIND_OPTS *pbindopts) -{ - BindCtxImpl *This = (BindCtxImpl *)iface; - - TRACE("(%p,%p)\n",This,pbindopts); - - if (pbindopts==NULL) - return E_POINTER; - - if (pbindopts->cbStruct > sizeof(BIND_OPTS2)) - { - WARN("invalid size\n"); - return E_INVALIDARG; /* FIXME : not verified */ - } - memcpy(pbindopts, &This->bindOption2, pbindopts->cbStruct); - return S_OK; -} - -/****************************************************************************** - * BindCtx_GetRunningObjectTable - ******************************************************************************/ -static HRESULT WINAPI -BindCtxImpl_GetRunningObjectTable(IBindCtx* iface,IRunningObjectTable** pprot) -{ - HRESULT res; - - BindCtxImpl *This = (BindCtxImpl *)iface; - - TRACE("(%p,%p)\n",This,pprot); - - if (pprot==NULL) - return E_POINTER; - - res=GetRunningObjectTable(0, pprot); - - return res; -} - -/****************************************************************************** - * BindCtx_RegisterObjectParam - ******************************************************************************/ -static HRESULT WINAPI -BindCtxImpl_RegisterObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown* punk) -{ - DWORD index=0; - BindCtxImpl *This = (BindCtxImpl *)iface; - - TRACE("(%p,%s,%p)\n",This,debugstr_w(pszkey),punk); - - if (punk==NULL) - return E_INVALIDARG; - - if (pszkey!=NULL && BindCtxImpl_GetObjectIndex(This,NULL,pszkey,&index)==S_OK) - { - TRACE("Overwriting existing key\n"); - if(This->bindCtxTable[index].pObj!=NULL) - IUnknown_Release(This->bindCtxTable[index].pObj); - This->bindCtxTable[index].pObj=punk; - IUnknown_AddRef(punk); - return S_OK; - } - This->bindCtxTable[This->bindCtxTableLastIndex].pObj = punk; - This->bindCtxTable[This->bindCtxTableLastIndex].regType = 1; - - if (pszkey==NULL) - - This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj=NULL; - - else - { - - This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj= - HeapAlloc(GetProcessHeap(),0,(sizeof(WCHAR)*(1+lstrlenW(pszkey)))); - - if (This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj==NULL) - return E_OUTOFMEMORY; - lstrcpyW(This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj,pszkey); - } - - This->bindCtxTableLastIndex++; - - if (This->bindCtxTableLastIndex == This->bindCtxTableSize) - { - /* table is full ! must be resized */ - - This->bindCtxTableSize+=BLOCK_TAB_SIZE; /* new table size */ - if (This->bindCtxTableSize > (MAX_TAB_SIZE-BLOCK_TAB_SIZE)) - { - FIXME("This->bindCtxTableSize: %ld is out of data limite \n",This->bindCtxTableSize); - return E_FAIL; - } - This->bindCtxTable = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->bindCtxTable, - This->bindCtxTableSize * sizeof(BindCtxObject)); - if (!This->bindCtxTable) - return E_OUTOFMEMORY; - } - IUnknown_AddRef(punk); - return S_OK; -} - -/****************************************************************************** - * BindCtx_GetObjectParam - ******************************************************************************/ -static HRESULT WINAPI -BindCtxImpl_GetObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown** punk) -{ - DWORD index; - BindCtxImpl *This = (BindCtxImpl *)iface; - - TRACE("(%p,%s,%p)\n",This,debugstr_w(pszkey),punk); - - if (punk==NULL) - return E_POINTER; - - *punk=0; - - if (BindCtxImpl_GetObjectIndex(This,NULL,pszkey,&index)==S_FALSE) - return E_FAIL; - - IUnknown_AddRef(This->bindCtxTable[index].pObj); - - *punk = This->bindCtxTable[index].pObj; - - return S_OK; -} - -/****************************************************************************** - * BindCtx_RevokeObjectParam - ******************************************************************************/ -static HRESULT WINAPI -BindCtxImpl_RevokeObjectParam(IBindCtx* iface,LPOLESTR ppenum) -{ - DWORD index,j; - - BindCtxImpl *This = (BindCtxImpl *)iface; - - TRACE("(%p,%s)\n",This,debugstr_w(ppenum)); - - if (BindCtxImpl_GetObjectIndex(This,NULL,ppenum,&index)==S_FALSE) - return E_FAIL; - - /* release the object if it's found */ - if(This->bindCtxTable[index].pObj) - IUnknown_Release(This->bindCtxTable[index].pObj); - HeapFree(GetProcessHeap(),0,This->bindCtxTable[index].pkeyObj); - - /* remove the object from the table with a left-shifting of all objects in the right side */ - for(j=index; j<This->bindCtxTableLastIndex-1; j++) - This->bindCtxTable[j]= This->bindCtxTable[j+1]; - - This->bindCtxTableLastIndex--; - - return S_OK; -} - -/****************************************************************************** - * BindCtx_EnumObjectParam - ******************************************************************************/ -static HRESULT WINAPI -BindCtxImpl_EnumObjectParam(IBindCtx* iface,IEnumString** pszkey) -{ - FIXME("(%p,%p),stub!\n",iface,pszkey); - return E_NOTIMPL; -} - -/******************************************************************************** - * GetObjectIndex (local function) - ********************************************************************************/ -static HRESULT BindCtxImpl_GetObjectIndex(BindCtxImpl* This, - IUnknown* punk, - LPOLESTR pszkey, - DWORD *index) -{ - - DWORD i; - BYTE found=0; - - TRACE("(%p,%p,%p,%p)\n",This,punk,pszkey,index); - - if (punk==NULL) - /* search object identified by a register key */ - for(i=0; ( (i<This->bindCtxTableLastIndex) && (!found));i++) - { - if(This->bindCtxTable[i].regType==1){ - - if ( ( (This->bindCtxTable[i].pkeyObj==NULL) && (pszkey==NULL) ) || - ( (This->bindCtxTable[i].pkeyObj!=NULL) && - (pszkey!=NULL) && - (lstrcmpW(This->bindCtxTable[i].pkeyObj,pszkey)==0) - ) - ) - - found=1; - } - } - else - /* search object identified by a moniker*/ - for(i=0; ( (i<This->bindCtxTableLastIndex) && (!found));i++) - if(This->bindCtxTable[i].pObj==punk) - found=1; - - if (index != NULL) - *index=i-1; - - if (found) - return S_OK; - TRACE("key not found\n"); - return S_FALSE; -} - -/* Virtual function table for the BindCtx class. */ -static IBindCtxVtbl VT_BindCtxImpl = -{ - BindCtxImpl_QueryInterface, - BindCtxImpl_AddRef, - BindCtxImpl_Release, - BindCtxImpl_RegisterObjectBound, - BindCtxImpl_RevokeObjectBound, - BindCtxImpl_ReleaseBoundObjects, - BindCtxImpl_SetBindOptions, - BindCtxImpl_GetBindOptions, - BindCtxImpl_GetRunningObjectTable, - BindCtxImpl_RegisterObjectParam, - BindCtxImpl_GetObjectParam, - BindCtxImpl_EnumObjectParam, - BindCtxImpl_RevokeObjectParam -}; - -/****************************************************************************** - * BindCtx_Construct (local function) - *******************************************************************************/ -static HRESULT BindCtxImpl_Construct(BindCtxImpl* This) -{ - TRACE("(%p)\n",This); - - /* Initialize the virtual function table.*/ - This->lpVtbl = &VT_BindCtxImpl; - This->ref = 0; - - /* Initialize the BIND_OPTS2 structure */ - This->bindOption2.cbStruct = sizeof(BIND_OPTS2); - This->bindOption2.grfFlags = 0; - This->bindOption2.grfMode = STGM_READWRITE; - This->bindOption2.dwTickCountDeadline = 0; - - This->bindOption2.dwTrackFlags = 0; - This->bindOption2.dwClassContext = CLSCTX_SERVER; - This->bindOption2.locale = 1033; - This->bindOption2.pServerInfo = 0; - - /* Initialize the bindctx table */ - This->bindCtxTableSize=BLOCK_TAB_SIZE; - This->bindCtxTableLastIndex=0; - This->bindCtxTable = HeapAlloc(GetProcessHeap(), 0, - This->bindCtxTableSize*sizeof(BindCtxObject)); - - if (This->bindCtxTable==NULL) - return E_OUTOFMEMORY; - - return S_OK; -} - -/****************************************************************************** - * CreateBindCtx16 - ******************************************************************************/ -HRESULT WINAPI CreateBindCtx16(DWORD reserved, LPBC * ppbc) -{ - FIXME("(%ld,%p),stub!\n",reserved,ppbc); - return E_NOTIMPL; -} - -/****************************************************************************** - * CreateBindCtx (OLE32.@) - ******************************************************************************/ -HRESULT WINAPI CreateBindCtx(DWORD reserved, LPBC * ppbc) -{ - BindCtxImpl* newBindCtx = 0; - HRESULT hr; - IID riid=IID_IBindCtx; - - TRACE("(%ld,%p)\n",reserved,ppbc); - - newBindCtx = HeapAlloc(GetProcessHeap(), 0, sizeof(BindCtxImpl)); - if (newBindCtx == 0) - return E_OUTOFMEMORY; - - hr = BindCtxImpl_Construct(newBindCtx); - if (FAILED(hr)) - { - HeapFree(GetProcessHeap(),0,newBindCtx); - return hr; - } - - hr = BindCtxImpl_QueryInterface((IBindCtx*)newBindCtx,&riid,(void**)ppbc); - - return hr; -} - -HRESULT WINAPI BindMoniker(LPMONIKER pmk, DWORD grfOpt, REFIID riid, LPVOID * ppvResult) -{ - HRESULT res; - IBindCtx * pbc; - - TRACE("(%p, %lx, %s, %p)\n", pmk, grfOpt, debugstr_guid(riid), ppvResult); - - res = CreateBindCtx(grfOpt, &pbc); - if (SUCCEEDED(res)) - res = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppvResult); - return res; -} +/*************************************************************************************** + * BindCtx implementation + * + * Copyright 1999 Noomen Hamza + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + ***************************************************************************************/ + +#include <stdarg.h> +#include <string.h> +#include <assert.h> + +#define COBJMACROS + +#include "winerror.h" +#include "windef.h" +#include "winbase.h" +#include "objbase.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/* represent the first size table and it's increment block size */ +#define BLOCK_TAB_SIZE 10 +#define MAX_TAB_SIZE 0xFFFFFFFF + +/* data structure of the BindCtx table elements */ +typedef struct BindCtxObject{ + + IUnknown* pObj; /* point on a bound object */ + + LPOLESTR pkeyObj; /* key associated to this bound object */ + + BYTE regType; /* registration type: 1 if RegisterObjectParam and 0 if RegisterObjectBound */ + +} BindCtxObject; + +/* BindCtx data strucrture */ +typedef struct BindCtxImpl{ + + IBindCtxVtbl *lpVtbl; /* VTable relative to the IBindCtx interface.*/ + + ULONG ref; /* reference counter for this object */ + + BindCtxObject* bindCtxTable; /* this is a table in which all bounded objects are stored*/ + DWORD bindCtxTableLastIndex; /* first free index in the table */ + DWORD bindCtxTableSize; /* size table */ + + BIND_OPTS2 bindOption2; /* a structure which contains the bind options*/ + +} BindCtxImpl; + +/* IBindCtx prototype functions : */ +static HRESULT WINAPI BindCtxImpl_ReleaseBoundObjects(IBindCtx*); +static HRESULT BindCtxImpl_GetObjectIndex(BindCtxImpl*, IUnknown*, LPOLESTR, DWORD *); + +/******************************************************************************* + * BindCtx_QueryInterface + *******************************************************************************/ +static HRESULT WINAPI +BindCtxImpl_QueryInterface(IBindCtx* iface,REFIID riid,void** ppvObject) +{ + BindCtxImpl *This = (BindCtxImpl *)iface; + + TRACE("(%p,%p,%p)\n",This,riid,ppvObject); + + /* Perform a sanity check on the parameters.*/ + if ( (This==0) || (ppvObject==0) ) + return E_INVALIDARG; + + /* Initialize the return parameter.*/ + *ppvObject = 0; + + /* Compare the riid with the interface IDs implemented by this object.*/ + if (IsEqualIID(&IID_IUnknown, riid) || + IsEqualIID(&IID_IBindCtx, riid)) + { + *ppvObject = (IBindCtx*)This; + IBindCtx_AddRef(iface); + return S_OK; + } + + return E_NOINTERFACE; +} + +/****************************************************************************** + * BindCtx_AddRef + ******************************************************************************/ +static ULONG WINAPI BindCtxImpl_AddRef(IBindCtx* iface) +{ + BindCtxImpl *This = (BindCtxImpl *)iface; + + TRACE("(%p)\n",This); + + return InterlockedIncrement(&This->ref); +} + +/****************************************************************************** + * BindCtx_Destroy (local function) + *******************************************************************************/ +static HRESULT BindCtxImpl_Destroy(BindCtxImpl* This) +{ + TRACE("(%p)\n",This); + + /* free the table space memory */ + HeapFree(GetProcessHeap(),0,This->bindCtxTable); + + /* free the bindctx structure */ + HeapFree(GetProcessHeap(),0,This); + + return S_OK; +} + +/****************************************************************************** + * BindCtx_Release + ******************************************************************************/ +static ULONG WINAPI BindCtxImpl_Release(IBindCtx* iface) +{ + BindCtxImpl *This = (BindCtxImpl *)iface; + ULONG ref; + + TRACE("(%p)\n",This); + + ref = InterlockedDecrement(&This->ref); + if (ref == 0) + { + /* release all registered objects */ + BindCtxImpl_ReleaseBoundObjects((IBindCtx*)This); + + BindCtxImpl_Destroy(This); + } + return ref; +} + + +/****************************************************************************** + * BindCtx_RegisterObjectBound + ******************************************************************************/ +static HRESULT WINAPI +BindCtxImpl_RegisterObjectBound(IBindCtx* iface,IUnknown* punk) +{ + BindCtxImpl *This = (BindCtxImpl *)iface; + DWORD lastIndex=This->bindCtxTableLastIndex; + + TRACE("(%p,%p)\n",This,punk); + + if (punk==NULL) + return E_POINTER; + + IUnknown_AddRef(punk); + + /* put the object in the first free element in the table */ + This->bindCtxTable[lastIndex].pObj = punk; + This->bindCtxTable[lastIndex].pkeyObj = NULL; + This->bindCtxTable[lastIndex].regType = 0; + lastIndex= ++This->bindCtxTableLastIndex; + + if (lastIndex == This->bindCtxTableSize){ /* the table is full so it must be resized */ + + if (This->bindCtxTableSize > (MAX_TAB_SIZE-BLOCK_TAB_SIZE)){ + FIXME("This->bindCtxTableSize: %ld is out of data limite \n",This->bindCtxTableSize); + return E_FAIL; + } + + This->bindCtxTableSize+=BLOCK_TAB_SIZE; /* new table size */ + + This->bindCtxTable = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->bindCtxTable, + This->bindCtxTableSize * sizeof(BindCtxObject)); + if (!This->bindCtxTable) + return E_OUTOFMEMORY; + } + return S_OK; +} + +/****************************************************************************** + * BindCtx_RevokeObjectBound + ******************************************************************************/ +static HRESULT WINAPI +BindCtxImpl_RevokeObjectBound(IBindCtx* iface, IUnknown* punk) +{ + DWORD index,j; + + BindCtxImpl *This = (BindCtxImpl *)iface; + + TRACE("(%p,%p)\n",This,punk); + + /* check if the object was registered or not */ + if (BindCtxImpl_GetObjectIndex(This,punk,NULL,&index)==S_FALSE) + return MK_E_NOTBOUND; + + if(This->bindCtxTable[index].pObj) + IUnknown_Release(This->bindCtxTable[index].pObj); + HeapFree(GetProcessHeap(),0,This->bindCtxTable[index].pkeyObj); + + /* left-shift all elements in the right side of the current revoked object */ + for(j=index; j<This->bindCtxTableLastIndex-1; j++) + This->bindCtxTable[j]= This->bindCtxTable[j+1]; + + This->bindCtxTableLastIndex--; + + return S_OK; +} + +/****************************************************************************** + * BindCtx_ReleaseBoundObjects + ******************************************************************************/ +static HRESULT WINAPI +BindCtxImpl_ReleaseBoundObjects(IBindCtx* iface) +{ + DWORD i; + + BindCtxImpl *This = (BindCtxImpl *)iface; + + TRACE("(%p)\n",This); + + for(i=0;i<This->bindCtxTableLastIndex;i++) + { + if(This->bindCtxTable[i].pObj) + IUnknown_Release(This->bindCtxTable[i].pObj); + HeapFree(GetProcessHeap(),0,This->bindCtxTable[i].pkeyObj); + } + + This->bindCtxTableLastIndex = 0; + + return S_OK; +} + +/****************************************************************************** + * BindCtx_SetBindOptions + ******************************************************************************/ +static HRESULT WINAPI +BindCtxImpl_SetBindOptions(IBindCtx* iface,BIND_OPTS *pbindopts) +{ + BindCtxImpl *This = (BindCtxImpl *)iface; + + TRACE("(%p,%p)\n",This,pbindopts); + + if (pbindopts==NULL) + return E_POINTER; + + if (pbindopts->cbStruct > sizeof(BIND_OPTS2)) + { + WARN("invalid size\n"); + return E_INVALIDARG; /* FIXME : not verified */ + } + memcpy(&This->bindOption2, pbindopts, pbindopts->cbStruct); + return S_OK; +} + +/****************************************************************************** + * BindCtx_GetBindOptions + ******************************************************************************/ +static HRESULT WINAPI +BindCtxImpl_GetBindOptions(IBindCtx* iface,BIND_OPTS *pbindopts) +{ + BindCtxImpl *This = (BindCtxImpl *)iface; + + TRACE("(%p,%p)\n",This,pbindopts); + + if (pbindopts==NULL) + return E_POINTER; + + if (pbindopts->cbStruct > sizeof(BIND_OPTS2)) + { + WARN("invalid size\n"); + return E_INVALIDARG; /* FIXME : not verified */ + } + memcpy(pbindopts, &This->bindOption2, pbindopts->cbStruct); + return S_OK; +} + +/****************************************************************************** + * BindCtx_GetRunningObjectTable + ******************************************************************************/ +static HRESULT WINAPI +BindCtxImpl_GetRunningObjectTable(IBindCtx* iface,IRunningObjectTable** pprot) +{ + HRESULT res; + + BindCtxImpl *This = (BindCtxImpl *)iface; + + TRACE("(%p,%p)\n",This,pprot); + + if (pprot==NULL) + return E_POINTER; + + res=GetRunningObjectTable(0, pprot); + + return res; +} + +/****************************************************************************** + * BindCtx_RegisterObjectParam + ******************************************************************************/ +static HRESULT WINAPI +BindCtxImpl_RegisterObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown* punk) +{ + DWORD index=0; + BindCtxImpl *This = (BindCtxImpl *)iface; + + TRACE("(%p,%s,%p)\n",This,debugstr_w(pszkey),punk); + + if (punk==NULL) + return E_INVALIDARG; + + if (pszkey!=NULL && BindCtxImpl_GetObjectIndex(This,NULL,pszkey,&index)==S_OK) + { + TRACE("Overwriting existing key\n"); + if(This->bindCtxTable[index].pObj!=NULL) + IUnknown_Release(This->bindCtxTable[index].pObj); + This->bindCtxTable[index].pObj=punk; + IUnknown_AddRef(punk); + return S_OK; + } + This->bindCtxTable[This->bindCtxTableLastIndex].pObj = punk; + This->bindCtxTable[This->bindCtxTableLastIndex].regType = 1; + + if (pszkey==NULL) + + This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj=NULL; + + else + { + + This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj= + HeapAlloc(GetProcessHeap(),0,(sizeof(WCHAR)*(1+lstrlenW(pszkey)))); + + if (This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj==NULL) + return E_OUTOFMEMORY; + lstrcpyW(This->bindCtxTable[This->bindCtxTableLastIndex].pkeyObj,pszkey); + } + + This->bindCtxTableLastIndex++; + + if (This->bindCtxTableLastIndex == This->bindCtxTableSize) + { + /* table is full ! must be resized */ + + This->bindCtxTableSize+=BLOCK_TAB_SIZE; /* new table size */ + if (This->bindCtxTableSize > (MAX_TAB_SIZE-BLOCK_TAB_SIZE)) + { + FIXME("This->bindCtxTableSize: %ld is out of data limite \n",This->bindCtxTableSize); + return E_FAIL; + } + This->bindCtxTable = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,This->bindCtxTable, + This->bindCtxTableSize * sizeof(BindCtxObject)); + if (!This->bindCtxTable) + return E_OUTOFMEMORY; + } + IUnknown_AddRef(punk); + return S_OK; +} + +/****************************************************************************** + * BindCtx_GetObjectParam + ******************************************************************************/ +static HRESULT WINAPI +BindCtxImpl_GetObjectParam(IBindCtx* iface,LPOLESTR pszkey, IUnknown** punk) +{ + DWORD index; + BindCtxImpl *This = (BindCtxImpl *)iface; + + TRACE("(%p,%s,%p)\n",This,debugstr_w(pszkey),punk); + + if (punk==NULL) + return E_POINTER; + + *punk=0; + + if (BindCtxImpl_GetObjectIndex(This,NULL,pszkey,&index)==S_FALSE) + return E_FAIL; + + IUnknown_AddRef(This->bindCtxTable[index].pObj); + + *punk = This->bindCtxTable[index].pObj; + + return S_OK; +} + +/****************************************************************************** + * BindCtx_RevokeObjectParam + ******************************************************************************/ +static HRESULT WINAPI +BindCtxImpl_RevokeObjectParam(IBindCtx* iface,LPOLESTR ppenum) +{ + DWORD index,j; + + BindCtxImpl *This = (BindCtxImpl *)iface; + + TRACE("(%p,%s)\n",This,debugstr_w(ppenum)); + + if (BindCtxImpl_GetObjectIndex(This,NULL,ppenum,&index)==S_FALSE) + return E_FAIL; + + /* release the object if it's found */ + if(This->bindCtxTable[index].pObj) + IUnknown_Release(This->bindCtxTable[index].pObj); + HeapFree(GetProcessHeap(),0,This->bindCtxTable[index].pkeyObj); + + /* remove the object from the table with a left-shifting of all objects in the right side */ + for(j=index; j<This->bindCtxTableLastIndex-1; j++) + This->bindCtxTable[j]= This->bindCtxTable[j+1]; + + This->bindCtxTableLastIndex--; + + return S_OK; +} + +/****************************************************************************** + * BindCtx_EnumObjectParam + ******************************************************************************/ +static HRESULT WINAPI +BindCtxImpl_EnumObjectParam(IBindCtx* iface,IEnumString** pszkey) +{ + FIXME("(%p,%p),stub!\n",iface,pszkey); + return E_NOTIMPL; +} + +/******************************************************************************** + * GetObjectIndex (local function) + ********************************************************************************/ +static HRESULT BindCtxImpl_GetObjectIndex(BindCtxImpl* This, + IUnknown* punk, + LPOLESTR pszkey, + DWORD *index) +{ + + DWORD i; + BYTE found=0; + + TRACE("(%p,%p,%p,%p)\n",This,punk,pszkey,index); + + if (punk==NULL) + /* search object identified by a register key */ + for(i=0; ( (i<This->bindCtxTableLastIndex) && (!found));i++) + { + if(This->bindCtxTable[i].regType==1){ + + if ( ( (This->bindCtxTable[i].pkeyObj==NULL) && (pszkey==NULL) ) || + ( (This->bindCtxTable[i].pkeyObj!=NULL) && + (pszkey!=NULL) && + (lstrcmpW(This->bindCtxTable[i].pkeyObj,pszkey)==0) + ) + ) + + found=1; + } + } + else + /* search object identified by a moniker*/ + for(i=0; ( (i<This->bindCtxTableLastIndex) && (!found));i++) + if(This->bindCtxTable[i].pObj==punk) + found=1; + + if (index != NULL) + *index=i-1; + + if (found) + return S_OK; + TRACE("key not found\n"); + return S_FALSE; +} + +/* Virtual function table for the BindCtx class. */ +static IBindCtxVtbl VT_BindCtxImpl = +{ + BindCtxImpl_QueryInterface, + BindCtxImpl_AddRef, + BindCtxImpl_Release, + BindCtxImpl_RegisterObjectBound, + BindCtxImpl_RevokeObjectBound, + BindCtxImpl_ReleaseBoundObjects, + BindCtxImpl_SetBindOptions, + BindCtxImpl_GetBindOptions, + BindCtxImpl_GetRunningObjectTable, + BindCtxImpl_RegisterObjectParam, + BindCtxImpl_GetObjectParam, + BindCtxImpl_EnumObjectParam, + BindCtxImpl_RevokeObjectParam +}; + +/****************************************************************************** + * BindCtx_Construct (local function) + *******************************************************************************/ +static HRESULT BindCtxImpl_Construct(BindCtxImpl* This) +{ + TRACE("(%p)\n",This); + + /* Initialize the virtual function table.*/ + This->lpVtbl = &VT_BindCtxImpl; + This->ref = 0; + + /* Initialize the BIND_OPTS2 structure */ + This->bindOption2.cbStruct = sizeof(BIND_OPTS2); + This->bindOption2.grfFlags = 0; + This->bindOption2.grfMode = STGM_READWRITE; + This->bindOption2.dwTickCountDeadline = 0; + + This->bindOption2.dwTrackFlags = 0; + This->bindOption2.dwClassContext = CLSCTX_SERVER; + This->bindOption2.locale = 1033; + This->bindOption2.pServerInfo = 0; + + /* Initialize the bindctx table */ + This->bindCtxTableSize=BLOCK_TAB_SIZE; + This->bindCtxTableLastIndex=0; + This->bindCtxTable = HeapAlloc(GetProcessHeap(), 0, + This->bindCtxTableSize*sizeof(BindCtxObject)); + + if (This->bindCtxTable==NULL) + return E_OUTOFMEMORY; + + return S_OK; +} + +/****************************************************************************** + * CreateBindCtx16 + ******************************************************************************/ +HRESULT WINAPI CreateBindCtx16(DWORD reserved, LPBC * ppbc) +{ + FIXME("(%ld,%p),stub!\n",reserved,ppbc); + return E_NOTIMPL; +} + +/****************************************************************************** + * CreateBindCtx (OLE32.@) + ******************************************************************************/ +HRESULT WINAPI CreateBindCtx(DWORD reserved, LPBC * ppbc) +{ + BindCtxImpl* newBindCtx = 0; + HRESULT hr; + IID riid=IID_IBindCtx; + + TRACE("(%ld,%p)\n",reserved,ppbc); + + newBindCtx = HeapAlloc(GetProcessHeap(), 0, sizeof(BindCtxImpl)); + if (newBindCtx == 0) + return E_OUTOFMEMORY; + + hr = BindCtxImpl_Construct(newBindCtx); + if (FAILED(hr)) + { + HeapFree(GetProcessHeap(),0,newBindCtx); + return hr; + } + + hr = BindCtxImpl_QueryInterface((IBindCtx*)newBindCtx,&riid,(void**)ppbc); + + return hr; +} + +HRESULT WINAPI BindMoniker(LPMONIKER pmk, DWORD grfOpt, REFIID riid, LPVOID * ppvResult) +{ + HRESULT res; + IBindCtx * pbc; + + TRACE("(%p, %lx, %s, %p)\n", pmk, grfOpt, debugstr_guid(riid), ppvResult); + + res = CreateBindCtx(grfOpt, &pbc); + if (SUCCEEDED(res)) + res = IMoniker_BindToObject(pmk, pbc, NULL, riid, ppvResult); + return res; +} diff --git a/reactos/lib/ole32/clipboard.c b/reactos/lib/ole32/clipboard.c index 3d50057399d..236416e15c8 100644 --- a/reactos/lib/ole32/clipboard.c +++ b/reactos/lib/ole32/clipboard.c @@ -1,1790 +1,1790 @@ -/* - * OLE 2 clipboard support - * - * Copyright 1999 Noel Borthwick <noel@macadamian.com> - * Copyright 2000 Abey George <abey@macadamian.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTES: - * This file contains the implementation for the OLE Clipboard and its - * internal interfaces. The OLE clipboard interacts with an IDataObject - * interface via the OleSetClipboard, OleGetClipboard and - * OleIsCurrentClipboard API's. An internal IDataObject delegates - * to a client supplied IDataObject or the WIN32 clipboard API depending - * on whether OleSetClipboard has been invoked. - * Here are some operating scenarios: - * - * 1. OleSetClipboard called: In this case the internal IDataObject - * delegates to the client supplied IDataObject. Additionally OLE takes - * ownership of the Windows clipboard and any HGLOCBAL IDataObject - * items are placed on the Windows clipboard. This allows non OLE aware - * applications to access these. A local WinProc fields WM_RENDERFORMAT - * and WM_RENDERALLFORMATS messages in this case. - * - * 2. OleGetClipboard called without previous OleSetClipboard. Here the internal - * IDataObject functionality wraps around the WIN32 clipboard API. - * - * 3. OleGetClipboard called after previous OleSetClipboard. Here the internal - * IDataObject delegates to the source IDataObjects functionality directly, - * thereby bypassing the Windows clipboard. - * - * Implementation references : Inside OLE 2'nd edition by Kraig Brockschmidt - * - * TODO: - * - Support for pasting between different processes. OLE clipboard support - * currently works only for in process copy and paste. Since we internally - * store a pointer to the source's IDataObject and delegate to that, this - * will fail if the IDataObject client belongs to a different process. - * - IDataObject::GetDataHere is not implemented - * - OleFlushClipboard needs to additionally handle TYMED_IStorage media - * by copying the storage into global memory. Subsequently the default - * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL - * back to TYMED_IStorage. - * - OLE1 compatibility formats to be synthesized from OLE2 formats and put on - * clipboard in OleSetClipboard. - * - */ - -#include <assert.h> -#include <stdarg.h> -#include <string.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winerror.h" -#include "winnls.h" -#include "ole2.h" -#include "wine/debug.h" -#include "olestd.h" - -#include "storage32.h" - -#define HANDLE_ERROR(err) { hr = err; TRACE("(HRESULT=%lx)\n", (HRESULT)err); goto CLEANUP; } - -/* For CoGetMalloc (MEMCTX_TASK is currently ignored) */ -#ifndef MEMCTX_TASK -# define MEMCTX_TASK -1 -#endif - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/**************************************************************************** - * OLEClipbrd - * DO NOT add any members before the VTables declaration! - */ -struct OLEClipbrd -{ - /* - * List all interface VTables here - */ - IDataObjectVtbl* lpvtbl1; /* IDataObject VTable */ - - /* - * The hidden OLE clipboard window. This window is used as the bridge between the - * the OLE and windows clipboard API. (Windows creates one such window per process) - */ - HWND hWndClipboard; - - /* - * Pointer to the source data object (via OleSetClipboard) - */ - IDataObject* pIDataObjectSrc; - - /* - * The registered DataObject clipboard format - */ - UINT cfDataObj; - - /* - * The handle to ourself - */ - HGLOBAL hSelf; - - /* - * Reference count of this object - */ - ULONG ref; -}; - -typedef struct OLEClipbrd OLEClipbrd; - - -/**************************************************************************** -* IEnumFORMATETC implementation -* DO NOT add any members before the VTables declaration! -*/ -typedef struct -{ - /* IEnumFORMATETC VTable */ - IEnumFORMATETCVtbl *lpVtbl; - - /* IEnumFORMATETC fields */ - UINT posFmt; /* current enumerator position */ - UINT countFmt; /* number of EnumFORMATETC's in array */ - LPFORMATETC pFmt; /* array of EnumFORMATETC's */ - - /* - * Reference count of this object - */ - DWORD ref; - - /* - * IUnknown implementation of the parent data object. - */ - IUnknown* pUnkDataObj; - -} IEnumFORMATETCImpl; - -typedef struct PresentationDataHeader -{ - BYTE unknown1[28]; - DWORD dwObjectExtentX; - DWORD dwObjectExtentY; - DWORD dwSize; -} PresentationDataHeader; - -/* - * The one and only OLEClipbrd object which is created by OLEClipbrd_Initialize() - */ -static HGLOBAL hTheOleClipboard = 0; -static OLEClipbrd* theOleClipboard = NULL; - - -/* - * Prototypes for the methods of the OLEClipboard class. - */ -void OLEClipbrd_Initialize(void); -void OLEClipbrd_UnInitialize(void); -static OLEClipbrd* OLEClipbrd_Construct(void); -static void OLEClipbrd_Destroy(OLEClipbrd* ptrToDestroy); -static HWND OLEClipbrd_CreateWindow(void); -static void OLEClipbrd_DestroyWindow(HWND hwnd); -LRESULT CALLBACK OLEClipbrd_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); -static HRESULT OLEClipbrd_RenderFormat( IDataObject *pIDataObject, LPFORMATETC pFormatetc ); -static HGLOBAL OLEClipbrd_GlobalDupMem( HGLOBAL hGlobalSrc ); - -/* - * Prototypes for the methods of the OLEClipboard class - * that implement IDataObject methods. - */ -static HRESULT WINAPI OLEClipbrd_IDataObject_QueryInterface( - IDataObject* iface, - REFIID riid, - void** ppvObject); -static ULONG WINAPI OLEClipbrd_IDataObject_AddRef( - IDataObject* iface); -static ULONG WINAPI OLEClipbrd_IDataObject_Release( - IDataObject* iface); -static HRESULT WINAPI OLEClipbrd_IDataObject_GetData( - IDataObject* iface, - LPFORMATETC pformatetcIn, - STGMEDIUM* pmedium); -static HRESULT WINAPI OLEClipbrd_IDataObject_GetDataHere( - IDataObject* iface, - LPFORMATETC pformatetc, - STGMEDIUM* pmedium); -static HRESULT WINAPI OLEClipbrd_IDataObject_QueryGetData( - IDataObject* iface, - LPFORMATETC pformatetc); -static HRESULT WINAPI OLEClipbrd_IDataObject_GetCanonicalFormatEtc( - IDataObject* iface, - LPFORMATETC pformatectIn, - LPFORMATETC pformatetcOut); -static HRESULT WINAPI OLEClipbrd_IDataObject_SetData( - IDataObject* iface, - LPFORMATETC pformatetc, - STGMEDIUM* pmedium, - BOOL fRelease); -static HRESULT WINAPI OLEClipbrd_IDataObject_EnumFormatEtc( - IDataObject* iface, - DWORD dwDirection, - IEnumFORMATETC** ppenumFormatEtc); -static HRESULT WINAPI OLEClipbrd_IDataObject_DAdvise( - IDataObject* iface, - FORMATETC* pformatetc, - DWORD advf, - IAdviseSink* pAdvSink, - DWORD* pdwConnection); -static HRESULT WINAPI OLEClipbrd_IDataObject_DUnadvise( - IDataObject* iface, - DWORD dwConnection); -static HRESULT WINAPI OLEClipbrd_IDataObject_EnumDAdvise( - IDataObject* iface, - IEnumSTATDATA** ppenumAdvise); - -/* - * Prototypes for the IEnumFORMATETC methods. - */ -static LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[], - LPUNKNOWN pUnkDataObj); -static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface(LPENUMFORMATETC iface, REFIID riid, - LPVOID* ppvObj); -static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface); -static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface); -static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next(LPENUMFORMATETC iface, ULONG celt, - FORMATETC* rgelt, ULONG* pceltFethed); -static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt); -static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface); -static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone(LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum); - - -/* - * Virtual function table for the OLEClipbrd's exposed IDataObject interface - */ -static IDataObjectVtbl OLEClipbrd_IDataObject_VTable = -{ - OLEClipbrd_IDataObject_QueryInterface, - OLEClipbrd_IDataObject_AddRef, - OLEClipbrd_IDataObject_Release, - OLEClipbrd_IDataObject_GetData, - OLEClipbrd_IDataObject_GetDataHere, - OLEClipbrd_IDataObject_QueryGetData, - OLEClipbrd_IDataObject_GetCanonicalFormatEtc, - OLEClipbrd_IDataObject_SetData, - OLEClipbrd_IDataObject_EnumFormatEtc, - OLEClipbrd_IDataObject_DAdvise, - OLEClipbrd_IDataObject_DUnadvise, - OLEClipbrd_IDataObject_EnumDAdvise -}; - -/* - * Virtual function table for IEnumFORMATETC interface - */ -static struct IEnumFORMATETCVtbl efvt = -{ - OLEClipbrd_IEnumFORMATETC_QueryInterface, - OLEClipbrd_IEnumFORMATETC_AddRef, - OLEClipbrd_IEnumFORMATETC_Release, - OLEClipbrd_IEnumFORMATETC_Next, - OLEClipbrd_IEnumFORMATETC_Skip, - OLEClipbrd_IEnumFORMATETC_Reset, - OLEClipbrd_IEnumFORMATETC_Clone -}; - -/* - * Name of our registered OLE clipboard window class - */ -CHAR OLEClipbrd_WNDCLASS[] = "CLIPBRDWNDCLASS"; - -/* - * If we need to store state info we can store it here. - * For now we don't need this functionality. - * -typedef struct tagClipboardWindowInfo -{ -} ClipboardWindowInfo; - */ - -/*---------------------------------------------------------------------* - * Win32 OLE clipboard API - *---------------------------------------------------------------------*/ - -/*********************************************************************** - * OleSetClipboard [OLE32.@] - * Places a pointer to the specified data object onto the clipboard, - * making the data object accessible to the OleGetClipboard function. - * - * RETURNS: - * - * S_OK IDataObject pointer placed on the clipboard - * CLIPBRD_E_CANT_OPEN OpenClipboard failed - * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed - * CLIPBRD_E_CANT_CLOSE CloseClipboard failed - * CLIPBRD_E_CANT_SET SetClipboard failed - */ - -HRESULT WINAPI OleSetClipboard(IDataObject* pDataObj) -{ - HRESULT hr = S_OK; - IEnumFORMATETC* penumFormatetc = NULL; - FORMATETC rgelt; - BOOL bClipboardOpen = FALSE; -/* - HGLOBAL hDataObject = 0; - OLEClipbrd **ppDataObject; -*/ - - TRACE("(%p)\n", pDataObj); - - /* - * Make sure we have a clipboard object - */ - OLEClipbrd_Initialize(); - - /* - * If the Ole clipboard window hasn't been created yet, create it now. - */ - if ( !theOleClipboard->hWndClipboard ) - theOleClipboard->hWndClipboard = OLEClipbrd_CreateWindow(); - - if ( !theOleClipboard->hWndClipboard ) /* sanity check */ - HANDLE_ERROR( E_FAIL ); - - /* - * Open the Windows clipboard, associating it with our hidden window - */ - if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) ) - HANDLE_ERROR( CLIPBRD_E_CANT_OPEN ); - - /* - * Empty the current clipboard and make our window the clipboard owner - * NOTE: This will trigger a WM_DESTROYCLIPBOARD message - */ - if ( !EmptyClipboard() ) - HANDLE_ERROR( CLIPBRD_E_CANT_EMPTY ); - - /* - * If we are already holding on to an IDataObject first release that. - */ - if ( theOleClipboard->pIDataObjectSrc ) - { - IDataObject_Release(theOleClipboard->pIDataObjectSrc); - theOleClipboard->pIDataObjectSrc = NULL; - } - - /* - * AddRef the data object passed in and save its pointer. - * A NULL value indicates that the clipboard should be emptied. - */ - theOleClipboard->pIDataObjectSrc = pDataObj; - if ( pDataObj ) - { - IDataObject_AddRef(theOleClipboard->pIDataObjectSrc); - } - - /* - * Enumerate all HGLOBAL formats supported by the source and make - * those formats available using delayed rendering using SetClipboardData. - * Only global memory based data items may be made available to non-OLE - * applications via the standard Windows clipboard API. Data based on other - * mediums(non TYMED_HGLOBAL) can only be accessed via the Ole Clipboard API. - * - * TODO: Do we need to additionally handle TYMED_IStorage media by copying - * the storage into global memory? - */ - if ( pDataObj ) - { - if ( FAILED(hr = IDataObject_EnumFormatEtc( pDataObj, - DATADIR_GET, - &penumFormatetc ))) - { - HANDLE_ERROR( hr ); - } - - while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) ) - { - if ( rgelt.tymed == TYMED_HGLOBAL ) - { - CHAR szFmtName[80]; - TRACE("(cfFormat=%d:%s)\n", rgelt.cfFormat, - GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1) - ? szFmtName : ""); - - SetClipboardData( rgelt.cfFormat, NULL); - } - } - IEnumFORMATETC_Release(penumFormatetc); - } - - /* - * Windows additionally creates a new "DataObject" clipboard format - * and stores in on the clipboard. We could possibly store a pointer - * to our internal IDataObject interface on the clipboard. I'm not - * sure what the use of this is though. - * Enable the code below for this functionality. - */ -/* - theOleClipboard->cfDataObj = RegisterClipboardFormatA("DataObject"); - hDataObject = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, - sizeof(OLEClipbrd *)); - if (hDataObject==0) - HANDLE_ERROR( E_OUTOFMEMORY ); - - ppDataObject = (OLEClipbrd**)GlobalLock(hDataObject); - *ppDataObject = theOleClipboard; - GlobalUnlock(hDataObject); - - if ( !SetClipboardData( theOleClipboard->cfDataObj, hDataObject ) ) - HANDLE_ERROR( CLIPBRD_E_CANT_SET ); -*/ - - hr = S_OK; - -CLEANUP: - - /* - * Close Windows clipboard (It remains associated with our window) - */ - if ( bClipboardOpen && !CloseClipboard() ) - hr = CLIPBRD_E_CANT_CLOSE; - - /* - * Release the source IDataObject if something failed - */ - if ( FAILED(hr) ) - { - if (theOleClipboard->pIDataObjectSrc) - { - IDataObject_Release(theOleClipboard->pIDataObjectSrc); - theOleClipboard->pIDataObjectSrc = NULL; - } - } - - return hr; -} - - -/*********************************************************************** - * OleGetClipboard [OLE32.@] - * Returns a pointer to our internal IDataObject which represents the conceptual - * state of the Windows clipboard. If the current clipboard already contains - * an IDataObject, our internal IDataObject will delegate to this object. - */ -HRESULT WINAPI OleGetClipboard(IDataObject** ppDataObj) -{ - HRESULT hr = S_OK; - TRACE("()\n"); - - /* - * Make sure we have a clipboard object - */ - OLEClipbrd_Initialize(); - - if (!theOleClipboard) - return E_OUTOFMEMORY; - - /* Return a reference counted IDataObject */ - hr = IDataObject_QueryInterface( (IDataObject*)&(theOleClipboard->lpvtbl1), - &IID_IDataObject, (void**)ppDataObj); - return hr; -} - -/*********************************************************************** - * OleFlushClipboard [OLE2.76] - */ - -HRESULT WINAPI OleFlushClipboard16(void) -{ - return OleFlushClipboard(); -} - - -/****************************************************************************** - * OleFlushClipboard [OLE32.@] - * Renders the data from the source IDataObject into the windows clipboard - * - * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media - * by copying the storage into global memory. Subsequently the default - * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL - * back to TYMED_IStorage. - */ -HRESULT WINAPI OleFlushClipboard() -{ - IEnumFORMATETC* penumFormatetc = NULL; - FORMATETC rgelt; - HRESULT hr = S_OK; - BOOL bClipboardOpen = FALSE; - IDataObject* pIDataObjectSrc = NULL; - - TRACE("()\n"); - - /* - * Make sure we have a clipboard object - */ - OLEClipbrd_Initialize(); - - /* - * Already flushed or no source DataObject? Nothing to do. - */ - if (!theOleClipboard->pIDataObjectSrc) - return S_OK; - - /* - * Addref and save the source data object we are holding on to temporarily, - * since it will be released when we empty the clipboard. - */ - pIDataObjectSrc = theOleClipboard->pIDataObjectSrc; - IDataObject_AddRef(pIDataObjectSrc); - - /* - * Open the Windows clipboard - */ - if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) ) - HANDLE_ERROR( CLIPBRD_E_CANT_OPEN ); - - /* - * Empty the current clipboard - */ - if ( !EmptyClipboard() ) - HANDLE_ERROR( CLIPBRD_E_CANT_EMPTY ); - - /* - * Render all HGLOBAL formats supported by the source into - * the windows clipboard. - */ - if ( FAILED( hr = IDataObject_EnumFormatEtc( pIDataObjectSrc, - DATADIR_GET, - &penumFormatetc) )) - { - HANDLE_ERROR( hr ); - } - - while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) ) - { - if ( rgelt.tymed == TYMED_HGLOBAL ) - { - CHAR szFmtName[80]; - TRACE("(cfFormat=%d:%s)\n", rgelt.cfFormat, - GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1) - ? szFmtName : ""); - - /* - * Render the clipboard data - */ - if ( FAILED(OLEClipbrd_RenderFormat( pIDataObjectSrc, &rgelt )) ) - continue; - } - } - - IEnumFORMATETC_Release(penumFormatetc); - - /* - * Release the source data object we are holding on to - */ - IDataObject_Release(pIDataObjectSrc); - -CLEANUP: - - /* - * Close Windows clipboard (It remains associated with our window) - */ - if ( bClipboardOpen && !CloseClipboard() ) - hr = CLIPBRD_E_CANT_CLOSE; - - return hr; -} - - -/*********************************************************************** - * OleIsCurrentClipboard [OLE32.@] - */ -HRESULT WINAPI OleIsCurrentClipboard ( IDataObject *pDataObject) -{ - TRACE("()\n"); - /* - * Make sure we have a clipboard object - */ - OLEClipbrd_Initialize(); - - if (!theOleClipboard) - return E_OUTOFMEMORY; - - return (pDataObject == theOleClipboard->pIDataObjectSrc) ? S_OK : S_FALSE; -} - - -/*---------------------------------------------------------------------* - * Internal implementation methods for the OLE clipboard - *---------------------------------------------------------------------*/ - -/*********************************************************************** - * OLEClipbrd_Initialize() - * Initializes the OLE clipboard. - */ -void OLEClipbrd_Initialize(void) -{ - /* - * Create the clipboard if necessary - */ - if ( !theOleClipboard ) - { - TRACE("()\n"); - theOleClipboard = OLEClipbrd_Construct(); - } -} - - -/*********************************************************************** - * OLEClipbrd_UnInitialize() - * Un-Initializes the OLE clipboard - */ -void OLEClipbrd_UnInitialize(void) -{ - TRACE("()\n"); - /* - * Destroy the clipboard if no one holds a reference to us. - * Note that the clipboard was created with a reference count of 1. - */ - if ( theOleClipboard && (theOleClipboard->ref <= 1) ) - { - OLEClipbrd_Destroy( theOleClipboard ); - } - else - { - WARN( "() : OLEClipbrd_UnInitialize called while client holds an IDataObject reference!\n"); - } -} - - -/********************************************************* - * Construct the OLEClipbrd class. - */ -static OLEClipbrd* OLEClipbrd_Construct() -{ - OLEClipbrd* newObject = NULL; - HGLOBAL hNewObject = 0; - - /* - * Allocate space for the object. We use GlobalAlloc since we need - * an HGLOBAL to expose our DataObject as a registered clipboard type. - */ - hNewObject = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, - sizeof(OLEClipbrd)); - if (hNewObject==0) - return NULL; - - /* - * Lock the handle for the entire lifetime of the clipboard. - */ - newObject = GlobalLock(hNewObject); - - /* - * Initialize the virtual function table. - */ - newObject->lpvtbl1 = &OLEClipbrd_IDataObject_VTable; - - /* - * Start with one reference count. The caller of this function - * must release the interface pointer when it is done. - */ - newObject->ref = 1; - - newObject->hSelf = hNewObject; - - /* - * The Ole clipboard is a singleton - save the global handle and pointer - */ - theOleClipboard = newObject; - hTheOleClipboard = hNewObject; - - return theOleClipboard; -} - -static void OLEClipbrd_Destroy(OLEClipbrd* ptrToDestroy) -{ - TRACE("()\n"); - - if ( !ptrToDestroy ) - return; - - /* - * Destroy the Ole clipboard window - */ - if ( ptrToDestroy->hWndClipboard ) - OLEClipbrd_DestroyWindow(ptrToDestroy->hWndClipboard); - - /* - * Free the actual OLE Clipboard structure. - */ - TRACE("() - Destroying clipboard data object.\n"); - GlobalUnlock(ptrToDestroy->hSelf); - GlobalFree(ptrToDestroy->hSelf); - - /* - * The Ole clipboard is a singleton (ptrToDestroy == theOleClipboard) - */ - theOleClipboard = NULL; - hTheOleClipboard = 0; -} - - -/*********************************************************************** - * OLEClipbrd_CreateWindow() - * Create the clipboard window - */ -static HWND OLEClipbrd_CreateWindow() -{ - HWND hwnd = 0; - WNDCLASSEXA wcex; - - /* - * Register the clipboard window class if necessary - */ - ZeroMemory( &wcex, sizeof(WNDCLASSEXA)); - - wcex.cbSize = sizeof(WNDCLASSEXA); - /* Windows creates this class with a style mask of 0 - * We don't bother doing this since the FindClassByAtom code - * would have to be changed to deal with this idiosyncrasy. */ - wcex.style = CS_GLOBALCLASS; - wcex.lpfnWndProc = OLEClipbrd_WndProc; - wcex.hInstance = 0; - wcex.lpszClassName = OLEClipbrd_WNDCLASS; - - RegisterClassExA(&wcex); - - /* - * Create a hidden window to receive OLE clipboard messages - */ - -/* - * If we need to store state info we can store it here. - * For now we don't need this functionality. - * ClipboardWindowInfo clipboardInfo; - * ZeroMemory( &trackerInfo, sizeof(ClipboardWindowInfo)); - */ - - hwnd = CreateWindowA(OLEClipbrd_WNDCLASS, - "ClipboardWindow", - WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - 0, - 0, - 0, - 0 /*(LPVOID)&clipboardInfo */); - - return hwnd; -} - -/*********************************************************************** - * OLEClipbrd_DestroyWindow(HWND) - * Destroy the clipboard window and unregister its class - */ -static void OLEClipbrd_DestroyWindow(HWND hwnd) -{ - /* - * Destroy clipboard window and unregister its WNDCLASS - */ - DestroyWindow(hwnd); - UnregisterClassA( OLEClipbrd_WNDCLASS, 0 ); -} - -/*********************************************************************** - * OLEClipbrd_WndProc(HWND, unsigned, WORD, LONG) - * Processes messages sent to the OLE clipboard window. - * Note that we will intercept messages in our WndProc only when data - * has been placed in the clipboard via OleSetClipboard(). - * i.e. Only when OLE owns the windows clipboard. - */ -LRESULT CALLBACK OLEClipbrd_WndProc - (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) - { - /* - * WM_RENDERFORMAT - * We receive this message to allow us to handle delayed rendering of - * a specific clipboard format when an application requests data in - * that format by calling GetClipboardData. - * (Recall that in OleSetClipboard, we used SetClipboardData to - * make all HGLOBAL formats supported by the source IDataObject - * available using delayed rendering) - * On receiving this message we must actually render the data in the - * specified format and place it on the clipboard by calling the - * SetClipboardData function. - */ - case WM_RENDERFORMAT: - { - FORMATETC rgelt; - - ZeroMemory( &rgelt, sizeof(FORMATETC)); - - /* - * Initialize FORMATETC to a Windows clipboard friendly format - */ - rgelt.cfFormat = (UINT) wParam; - rgelt.dwAspect = DVASPECT_CONTENT; - rgelt.lindex = -1; - rgelt.tymed = TYMED_HGLOBAL; - - TRACE("(): WM_RENDERFORMAT(cfFormat=%d)\n", rgelt.cfFormat); - - /* - * Render the clipboard data. - * (We must have a source data object or we wouldn't be in this WndProc) - */ - OLEClipbrd_RenderFormat( (IDataObject*)&(theOleClipboard->lpvtbl1), &rgelt ); - - break; - } - - /* - * WM_RENDERALLFORMATS - * Sent before the clipboard owner window is destroyed. - * We should receive this message only when OleUninitialize is called - * while we have an IDataObject in the clipboard. - * For the content of the clipboard to remain available to other - * applications, we must render data in all the formats the source IDataObject - * is capable of generating, and place the data on the clipboard by calling - * SetClipboardData. - */ - case WM_RENDERALLFORMATS: - { - IEnumFORMATETC* penumFormatetc = NULL; - FORMATETC rgelt; - - TRACE("(): WM_RENDERALLFORMATS\n"); - - /* - * Render all HGLOBAL formats supported by the source into - * the windows clipboard. - */ - if ( FAILED( IDataObject_EnumFormatEtc( (IDataObject*)&(theOleClipboard->lpvtbl1), - DATADIR_GET, &penumFormatetc) ) ) - { - WARN("(): WM_RENDERALLFORMATS failed to retrieve EnumFormatEtc!\n"); - return 0; - } - - while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) ) - { - if ( rgelt.tymed == TYMED_HGLOBAL ) - { - /* - * Render the clipboard data. - */ - if ( FAILED(OLEClipbrd_RenderFormat( (IDataObject*)&(theOleClipboard->lpvtbl1), &rgelt )) ) - continue; - - TRACE("(): WM_RENDERALLFORMATS(cfFormat=%d)\n", rgelt.cfFormat); - } - } - - IEnumFORMATETC_Release(penumFormatetc); - - break; - } - - /* - * WM_DESTROYCLIPBOARD - * This is sent by EmptyClipboard before the clipboard is emptied. - * We should release any IDataObject we are holding onto when we receive - * this message, since it indicates that the OLE clipboard should be empty - * from this point on. - */ - case WM_DESTROYCLIPBOARD: - { - TRACE("(): WM_DESTROYCLIPBOARD\n"); - /* - * Release the data object we are holding on to - */ - if ( theOleClipboard->pIDataObjectSrc ) - { - IDataObject_Release(theOleClipboard->pIDataObjectSrc); - theOleClipboard->pIDataObjectSrc = NULL; - } - break; - } - -/* - case WM_ASKCBFORMATNAME: - case WM_CHANGECBCHAIN: - case WM_DRAWCLIPBOARD: - case WM_SIZECLIPBOARD: - case WM_HSCROLLCLIPBOARD: - case WM_VSCROLLCLIPBOARD: - case WM_PAINTCLIPBOARD: -*/ - default: - return DefWindowProcA(hWnd, message, wParam, lParam); - } - - return 0; -} - -#define MAX_CLIPFORMAT_NAME 80 - -/*********************************************************************** - * OLEClipbrd_RenderFormat(LPFORMATETC) - * Render the clipboard data. Note that this call will delegate to the - * source data object. - * Note: This function assumes it is passed an HGLOBAL format to render. - */ -static HRESULT OLEClipbrd_RenderFormat(IDataObject *pIDataObject, LPFORMATETC pFormatetc) -{ - STGMEDIUM std; - HGLOBAL hDup; - HRESULT hr = S_OK; - char szFmtName[MAX_CLIPFORMAT_NAME]; - ILockBytes *ptrILockBytes = 0; - HGLOBAL hStorage = 0; - - GetClipboardFormatNameA(pFormatetc->cfFormat, szFmtName, MAX_CLIPFORMAT_NAME); - - /* If embed source */ - if (!strcmp(szFmtName, CF_EMBEDSOURCE)) - { - memset(&std, 0, sizeof(STGMEDIUM)); - std.tymed = pFormatetc->tymed = TYMED_ISTORAGE; - - hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0); - if (hStorage == NULL) - HANDLE_ERROR( E_OUTOFMEMORY ); - hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes); - hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg); - - if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->pIDataObjectSrc, pFormatetc, &std))) - { - WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%lx)\n", hr); - GlobalFree(hStorage); - return hr; - } - - if (1) /* check whether the presentation data is already -not- present */ - { - FORMATETC fmt2; - STGMEDIUM std2; - METAFILEPICT *mfp = 0; - - fmt2.cfFormat = CF_METAFILEPICT; - fmt2.ptd = 0; - fmt2.dwAspect = DVASPECT_CONTENT; - fmt2.lindex = -1; - fmt2.tymed = TYMED_MFPICT; - - memset(&std2, 0, sizeof(STGMEDIUM)); - std2.tymed = TYMED_MFPICT; - - /* Get the metafile picture out of it */ - - if (!FAILED(hr = IDataObject_GetData(theOleClipboard->pIDataObjectSrc, &fmt2, &std2))) - { - mfp = (METAFILEPICT *)GlobalLock(std2.u.hGlobal); - } - - if (mfp) - { - OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0}; - IStream *pStream = 0; - void *mfBits; - PresentationDataHeader pdh; - INT nSize; - CLSID clsID; - LPOLESTR strProgID; - CHAR strOleTypeName[51]; - BYTE OlePresStreamHeader [] = - { - 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 - }; - - nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL); - - memset(&pdh, 0, sizeof(PresentationDataHeader)); - memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader)); - - pdh.dwObjectExtentX = mfp->xExt; - pdh.dwObjectExtentY = mfp->yExt; - pdh.dwSize = nSize; - - hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream); - - hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL); - - mfBits = HeapAlloc(GetProcessHeap(), 0, nSize); - nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits); - - hr = IStream_Write(pStream, mfBits, nSize, NULL); - - IStream_Release(pStream); - - HeapFree(GetProcessHeap(), 0, mfBits); - - GlobalUnlock(std2.u.hGlobal); - - ReadClassStg(std.u.pstg, &clsID); - ProgIDFromCLSID(&clsID, &strProgID); - - WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL ); - OLECONVERT_CreateOleStream(std.u.pstg); - OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName); - } - } - } - else - { - if (FAILED(hr = IDataObject_GetData(pIDataObject, pFormatetc, &std))) - { - WARN("() : IDataObject_GetData failed to render clipboard data! (%lx)\n", hr); - GlobalFree(hStorage); - return hr; - } - - /* To put a copy back on the clipboard */ - - hStorage = std.u.hGlobal; - } - - /* - * Put a copy of the rendered data back on the clipboard - */ - - if ( !(hDup = OLEClipbrd_GlobalDupMem(hStorage)) ) - HANDLE_ERROR( E_OUTOFMEMORY ); - - if ( !SetClipboardData( pFormatetc->cfFormat, hDup ) ) - { - GlobalFree(hDup); - WARN("() : Failed to set rendered clipboard data into clipboard!\n"); - } - -CLEANUP: - - ReleaseStgMedium(&std); - - return hr; -} - - -/*********************************************************************** - * OLEClipbrd_GlobalDupMem( HGLOBAL ) - * Helper method to duplicate an HGLOBAL chunk of memory - */ -static HGLOBAL OLEClipbrd_GlobalDupMem( HGLOBAL hGlobalSrc ) -{ - HGLOBAL hGlobalDest; - PVOID pGlobalSrc, pGlobalDest; - DWORD cBytes; - - if ( !hGlobalSrc ) - return 0; - - cBytes = GlobalSize(hGlobalSrc); - if ( 0 == cBytes ) - return 0; - - hGlobalDest = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, - cBytes ); - if ( !hGlobalDest ) - return 0; - - pGlobalSrc = GlobalLock(hGlobalSrc); - pGlobalDest = GlobalLock(hGlobalDest); - if ( !pGlobalSrc || !pGlobalDest ) - { - GlobalFree(hGlobalDest); - return 0; - } - - memcpy(pGlobalDest, pGlobalSrc, cBytes); - - GlobalUnlock(hGlobalSrc); - GlobalUnlock(hGlobalDest); - - return hGlobalDest; -} - - -/*---------------------------------------------------------------------* - * Implementation of the internal IDataObject interface exposed by - * the OLE clipboard. - *---------------------------------------------------------------------*/ - - -/************************************************************************ - * OLEClipbrd_IDataObject_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static HRESULT WINAPI OLEClipbrd_IDataObject_QueryInterface( - IDataObject* iface, - REFIID riid, - void** ppvObject) -{ - /* - * Declare "This" pointer - */ - OLEClipbrd *This = (OLEClipbrd *)iface; - TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObject); - - /* - * Perform a sanity check on the parameters. - */ - if ( (This==0) || (ppvObject==0) ) - return E_INVALIDARG; - - /* - * Initialize the return parameter. - */ - *ppvObject = 0; - - /* - * Compare the riid with the interface IDs implemented by this object. - */ - if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) - { - *ppvObject = iface; - } - else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0) - { - *ppvObject = (IDataObject*)&(This->lpvtbl1); - } - else /* We only support IUnknown and IDataObject */ - { - WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; - } - - /* - * Query Interface always increases the reference count by one when it is - * successful. - */ - IUnknown_AddRef((IUnknown*)*ppvObject); - - return S_OK; -} - -/************************************************************************ - * OLEClipbrd_IDataObject_AddRef (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI OLEClipbrd_IDataObject_AddRef( - IDataObject* iface) -{ - /* - * Declare "This" pointer - */ - OLEClipbrd *This = (OLEClipbrd *)iface; - - TRACE("(%p)->(count=%lu)\n",This, This->ref); - - return InterlockedIncrement(&This->ref); - -} - -/************************************************************************ - * OLEClipbrd_IDataObject_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI OLEClipbrd_IDataObject_Release( - IDataObject* iface) -{ - /* - * Declare "This" pointer - */ - OLEClipbrd *This = (OLEClipbrd *)iface; - ULONG ref; - - TRACE("(%p)->(count=%lu)\n",This, This->ref); - - /* - * Decrease the reference count on this object. - */ - ref = InterlockedDecrement(&This->ref); - - /* - * If the reference count goes down to 0, perform suicide. - */ - if (ref == 0) - { - OLEClipbrd_Destroy(This); - } - - return ref; -} - - -/************************************************************************ - * OLEClipbrd_IDataObject_GetData (IDataObject) - * - * The OLE Clipboard's implementation of this method delegates to - * a data source if there is one or wraps around the windows clipboard - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI OLEClipbrd_IDataObject_GetData( - IDataObject* iface, - LPFORMATETC pformatetcIn, - STGMEDIUM* pmedium) -{ - HANDLE hData = 0; - BOOL bClipboardOpen = FALSE; - HRESULT hr = S_OK; - LPVOID src; - - /* - * Declare "This" pointer - */ - OLEClipbrd *This = (OLEClipbrd *)iface; - - TRACE("(%p,%p,%p)\n", iface, pformatetcIn, pmedium); - - if ( !pformatetcIn || !pmedium ) - return E_INVALIDARG; - - /* - * If we have a data source placed on the clipboard (via OleSetClipboard) - * simply delegate to the source object's QueryGetData - * NOTE: This code assumes that the IDataObject is in the same address space! - * We will need to add marshalling support when Wine handles multiple processes. - */ - if ( This->pIDataObjectSrc ) - { - return IDataObject_GetData(This->pIDataObjectSrc, pformatetcIn, pmedium); - } - - if ( pformatetcIn->lindex != -1 ) - return DV_E_LINDEX; - if ( (pformatetcIn->tymed & TYMED_HGLOBAL) != TYMED_HGLOBAL ) - return DV_E_TYMED; -/* - if ( pformatetcIn->dwAspect != DVASPECT_CONTENT ) - return DV_E_DVASPECT; -*/ - - /* - * Otherwise, get the data from the windows clipboard using GetClipboardData - */ - if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) ) - HANDLE_ERROR( CLIPBRD_E_CANT_OPEN ); - - hData = GetClipboardData(pformatetcIn->cfFormat); - - /* Must make a copy of global handle returned by GetClipboardData; it - * is not valid after we call CloseClipboard - * Application is responsible for freeing the memory (Forte Agent does this) - */ - src = GlobalLock(hData); - if(src) { - LPVOID dest; - ULONG size; - HANDLE hDest; - - size = GlobalSize(hData); - hDest = GlobalAlloc(GHND, size); - dest = GlobalLock(hDest); - memcpy(dest, src, size); - GlobalUnlock(hDest); - GlobalUnlock(hData); - hData = hDest; - } - - /* - * Return the clipboard data in the storage medium structure - */ - pmedium->tymed = (hData == 0) ? TYMED_NULL : TYMED_HGLOBAL; - pmedium->u.hGlobal = (HGLOBAL)hData; - pmedium->pUnkForRelease = NULL; - - hr = S_OK; - -CLEANUP: - /* - * Close Windows clipboard - */ - if ( bClipboardOpen && !CloseClipboard() ) - hr = CLIPBRD_E_CANT_CLOSE; - - if ( FAILED(hr) ) - return hr; - return (hData == 0) ? DV_E_FORMATETC : S_OK; -} - -static HRESULT WINAPI OLEClipbrd_IDataObject_GetDataHere( - IDataObject* iface, - LPFORMATETC pformatetc, - STGMEDIUM* pmedium) -{ - FIXME(": Stub\n"); - return E_NOTIMPL; -} - -/************************************************************************ - * OLEClipbrd_IDataObject_QueryGetData (IDataObject) - * - * The OLE Clipboard's implementation of this method delegates to - * a data source if there is one or wraps around the windows clipboard - * function IsClipboardFormatAvailable() otherwise. - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI OLEClipbrd_IDataObject_QueryGetData( - IDataObject* iface, - LPFORMATETC pformatetc) -{ - /* - * Declare "This" pointer - */ - OLEClipbrd *This = (OLEClipbrd *)iface; - - TRACE("(%p, %p)\n", iface, pformatetc); - - /* - * If we have a data source placed on the clipboard (via OleSetClipboard) - * simply delegate to the source object's QueryGetData - */ - if ( This->pIDataObjectSrc ) - { - return IDataObject_QueryGetData(This->pIDataObjectSrc, pformatetc); - } - - if (!pformatetc) - return E_INVALIDARG; -/* - if ( pformatetc->dwAspect != DVASPECT_CONTENT ) - return DV_E_DVASPECT; -*/ - if ( pformatetc->lindex != -1 ) - return DV_E_LINDEX; - - /* TODO: Handle TYMED_IStorage media which were put on the clipboard - * by copying the storage into global memory. We must convert this - * TYMED_HGLOBAL back to TYMED_IStorage. - */ - if ( pformatetc->tymed != TYMED_HGLOBAL ) - return DV_E_TYMED; - - /* - * Delegate to the Windows clipboard function IsClipboardFormatAvailable - */ - return (IsClipboardFormatAvailable(pformatetc->cfFormat)) ? S_OK : DV_E_FORMATETC; -} - -/************************************************************************ - * OLEClipbrd_IDataObject_GetCanonicalFormatEtc (IDataObject) - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI OLEClipbrd_IDataObject_GetCanonicalFormatEtc( - IDataObject* iface, - LPFORMATETC pformatectIn, - LPFORMATETC pformatetcOut) -{ - TRACE("(%p, %p, %p)\n", iface, pformatectIn, pformatetcOut); - - if ( !pformatectIn || !pformatetcOut ) - return E_INVALIDARG; - - memcpy(pformatetcOut, pformatectIn, sizeof(FORMATETC)); - return DATA_S_SAMEFORMATETC; -} - -/************************************************************************ - * OLEClipbrd_IDataObject_SetData (IDataObject) - * - * The OLE Clipboard's does not implement this method - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI OLEClipbrd_IDataObject_SetData( - IDataObject* iface, - LPFORMATETC pformatetc, - STGMEDIUM* pmedium, - BOOL fRelease) -{ - TRACE("\n"); - return E_NOTIMPL; -} - -/************************************************************************ - * OLEClipbrd_IDataObject_EnumFormatEtc (IDataObject) - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI OLEClipbrd_IDataObject_EnumFormatEtc( - IDataObject* iface, - DWORD dwDirection, - IEnumFORMATETC** ppenumFormatEtc) -{ - HRESULT hr = S_OK; - FORMATETC *afmt = NULL; - int cfmt, i; - UINT format; - BOOL bClipboardOpen; - - /* - * Declare "This" pointer - */ - OLEClipbrd *This = (OLEClipbrd *)iface; - - TRACE("(%p, %lx, %p)\n", iface, dwDirection, ppenumFormatEtc); - - /* - * If we have a data source placed on the clipboard (via OleSetClipboard) - * simply delegate to the source object's EnumFormatEtc - */ - if ( This->pIDataObjectSrc ) - { - return IDataObject_EnumFormatEtc(This->pIDataObjectSrc, - dwDirection, ppenumFormatEtc); - } - - /* - * Otherwise we must provide our own enumerator which wraps around the - * Windows clipboard function EnumClipboardFormats - */ - if ( !ppenumFormatEtc ) - return E_INVALIDARG; - - if ( dwDirection != DATADIR_GET ) /* IDataObject_SetData not implemented */ - return E_NOTIMPL; - - /* - * Store all current clipboard formats in an array of FORMATETC's, - * and create an IEnumFORMATETC enumerator from this list. - */ - cfmt = CountClipboardFormats(); - afmt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(FORMATETC) * cfmt); - /* - * Open the Windows clipboard, associating it with our hidden window - */ - if ( !(bClipboardOpen = OpenClipboard(This->hWndClipboard)) ) - HANDLE_ERROR( CLIPBRD_E_CANT_OPEN ); - - /* - * Store all current clipboard formats in an array of FORMATETC's - * TODO: Handle TYMED_IStorage media which were put on the clipboard - * by copying the storage into global memory. We must convert this - * TYMED_HGLOBAL back to TYMED_IStorage. - */ - for (i = 0, format = 0; i < cfmt; i++) - { - format = EnumClipboardFormats(format); - if (!format) /* Failed! */ - { - ERR("EnumClipboardFormats failed to return format!\n"); - HANDLE_ERROR( E_FAIL ); - } - - /* Init the FORMATETC struct */ - afmt[i].cfFormat = format; - afmt[i].ptd = NULL; - afmt[i].dwAspect = DVASPECT_CONTENT; - afmt[i].lindex = -1; - afmt[i].tymed = TYMED_HGLOBAL; - } - - /* - * Create an EnumFORMATETC enumerator and return an - * EnumFORMATETC after bumping up its ref count - */ - *ppenumFormatEtc = OLEClipbrd_IEnumFORMATETC_Construct( cfmt, afmt, (LPUNKNOWN)iface); - if (!(*ppenumFormatEtc)) - HANDLE_ERROR( E_OUTOFMEMORY ); - - if (FAILED( hr = IEnumFORMATETC_AddRef(*ppenumFormatEtc))) - HANDLE_ERROR( hr ); - - hr = S_OK; - -CLEANUP: - /* - * Free the array of FORMATETC's - */ - HeapFree(GetProcessHeap(), 0, afmt); - - /* - * Close Windows clipboard - */ - if ( bClipboardOpen && !CloseClipboard() ) - hr = CLIPBRD_E_CANT_CLOSE; - - return hr; -} - -/************************************************************************ - * OLEClipbrd_IDataObject_DAdvise (IDataObject) - * - * The OLE Clipboard's does not implement this method - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI OLEClipbrd_IDataObject_DAdvise( - IDataObject* iface, - FORMATETC* pformatetc, - DWORD advf, - IAdviseSink* pAdvSink, - DWORD* pdwConnection) -{ - TRACE("\n"); - return E_NOTIMPL; -} - -/************************************************************************ - * OLEClipbrd_IDataObject_DUnadvise (IDataObject) - * - * The OLE Clipboard's does not implement this method - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI OLEClipbrd_IDataObject_DUnadvise( - IDataObject* iface, - DWORD dwConnection) -{ - TRACE("\n"); - return E_NOTIMPL; -} - -/************************************************************************ - * OLEClipbrd_IDataObject_EnumDAdvise (IDataObject) - * - * The OLE Clipboard does not implement this method - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI OLEClipbrd_IDataObject_EnumDAdvise( - IDataObject* iface, - IEnumSTATDATA** ppenumAdvise) -{ - TRACE("\n"); - return E_NOTIMPL; -} - - -/*---------------------------------------------------------------------* - * Implementation of the internal IEnumFORMATETC interface returned by - * the OLE clipboard's IDataObject. - *---------------------------------------------------------------------*/ - -/************************************************************************ - * OLEClipbrd_IEnumFORMATETC_Construct (UINT, const FORMATETC, LPUNKNOWN) - * - * Creates an IEnumFORMATETC enumerator from an array of FORMATETC - * Structures. pUnkOuter is the outer unknown for reference counting only. - * NOTE: this does not AddRef the interface. - */ - -LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[], - LPUNKNOWN pUnkDataObj) -{ - IEnumFORMATETCImpl* ef; - DWORD size=cfmt * sizeof(FORMATETC); - LPMALLOC pIMalloc; - - ef = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumFORMATETCImpl)); - if (!ef) - return NULL; - - ef->ref = 0; - ef->lpVtbl = &efvt; - ef->pUnkDataObj = pUnkDataObj; - - ef->posFmt = 0; - ef->countFmt = cfmt; - if (FAILED(CoGetMalloc(MEMCTX_TASK, &pIMalloc))) { - HeapFree(GetProcessHeap(), 0, ef); - return NULL; - } - ef->pFmt = (LPFORMATETC)IMalloc_Alloc(pIMalloc, size); - IMalloc_Release(pIMalloc); - - if (ef->pFmt) - memcpy(ef->pFmt, afmt, size); - - TRACE("(%p)->()\n",ef); - return (LPENUMFORMATETC)ef; -} - - -/************************************************************************ - * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface - (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj) -{ - IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; - - TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj); - - /* - * Since enumerators are separate objects from the parent data object - * we only need to support the IUnknown and IEnumFORMATETC interfaces - */ - - *ppvObj = NULL; - - if(IsEqualIID(riid, &IID_IUnknown)) - { - *ppvObj = This; - } - else if(IsEqualIID(riid, &IID_IEnumFORMATETC)) - { - *ppvObj = (IDataObject*)This; - } - - if(*ppvObj) - { - IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj); - TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj); - return S_OK; - } - - TRACE("-- Interface: E_NOINTERFACE\n"); - return E_NOINTERFACE; -} - -/************************************************************************ - * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown) - * - * Since enumerating formats only makes sense when our data object is around, - * we insure that it stays as long as we stay by calling our parents IUnknown - * for AddRef and Release. But since we are not controlled by the lifetime of - * the outer object, we still keep our own reference count in order to - * free ourselves. - */ -static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface) -{ - IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; - TRACE("(%p)->(count=%lu)\n",This, This->ref); - - if (This->pUnkDataObj) - IUnknown_AddRef(This->pUnkDataObj); - - return InterlockedIncrement(&This->ref); -} - -/************************************************************************ - * OLEClipbrd_IEnumFORMATETC_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface) -{ - IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; - LPMALLOC pIMalloc; - ULONG ref; - - TRACE("(%p)->(count=%lu)\n",This, This->ref); - - if (This->pUnkDataObj) - IUnknown_Release(This->pUnkDataObj); /* Release parent data object */ - - ref = InterlockedDecrement(&This->ref); - if (!ref) - { - TRACE("() - destroying IEnumFORMATETC(%p)\n",This); - if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pIMalloc))) - { - IMalloc_Free(pIMalloc, This->pFmt); - IMalloc_Release(pIMalloc); - } - - HeapFree(GetProcessHeap(),0,This); - } - return ref; -} - -/************************************************************************ - * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC) - * - * Standard enumerator members for IEnumFORMATETC - */ -static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next - (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed) -{ - IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; - UINT cfetch; - HRESULT hres = S_FALSE; - - TRACE("(%p)->(pos=%u)\n", This, This->posFmt); - - if (This->posFmt < This->countFmt) - { - cfetch = This->countFmt - This->posFmt; - if (cfetch >= celt) - { - cfetch = celt; - hres = S_OK; - } - - memcpy(rgelt, &This->pFmt[This->posFmt], cfetch * sizeof(FORMATETC)); - This->posFmt += cfetch; - } - else - { - cfetch = 0; - } - - if (pceltFethed) - { - *pceltFethed = cfetch; - } - - return hres; -} - -/************************************************************************ - * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC) - * - * Standard enumerator members for IEnumFORMATETC - */ -static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt) -{ - IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; - TRACE("(%p)->(num=%lu)\n", This, celt); - - This->posFmt += celt; - if (This->posFmt > This->countFmt) - { - This->posFmt = This->countFmt; - return S_FALSE; - } - return S_OK; -} - -/************************************************************************ - * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC) - * - * Standard enumerator members for IEnumFORMATETC - */ -static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface) -{ - IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; - TRACE("(%p)->()\n", This); - - This->posFmt = 0; - return S_OK; -} - -/************************************************************************ - * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC) - * - * Standard enumerator members for IEnumFORMATETC - */ -static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone - (LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum) -{ - IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; - HRESULT hr = S_OK; - - TRACE("(%p)->(ppenum=%p)\n", This, ppenum); - - if ( !ppenum ) - return E_INVALIDARG; - - *ppenum = OLEClipbrd_IEnumFORMATETC_Construct(This->countFmt, - This->pFmt, - This->pUnkDataObj); - - if (FAILED( hr = IEnumFORMATETC_AddRef(*ppenum))) - return ( hr ); - - return (*ppenum) ? S_OK : E_OUTOFMEMORY; -} +/* + * OLE 2 clipboard support + * + * Copyright 1999 Noel Borthwick <noel@macadamian.com> + * Copyright 2000 Abey George <abey@macadamian.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES: + * This file contains the implementation for the OLE Clipboard and its + * internal interfaces. The OLE clipboard interacts with an IDataObject + * interface via the OleSetClipboard, OleGetClipboard and + * OleIsCurrentClipboard API's. An internal IDataObject delegates + * to a client supplied IDataObject or the WIN32 clipboard API depending + * on whether OleSetClipboard has been invoked. + * Here are some operating scenarios: + * + * 1. OleSetClipboard called: In this case the internal IDataObject + * delegates to the client supplied IDataObject. Additionally OLE takes + * ownership of the Windows clipboard and any HGLOCBAL IDataObject + * items are placed on the Windows clipboard. This allows non OLE aware + * applications to access these. A local WinProc fields WM_RENDERFORMAT + * and WM_RENDERALLFORMATS messages in this case. + * + * 2. OleGetClipboard called without previous OleSetClipboard. Here the internal + * IDataObject functionality wraps around the WIN32 clipboard API. + * + * 3. OleGetClipboard called after previous OleSetClipboard. Here the internal + * IDataObject delegates to the source IDataObjects functionality directly, + * thereby bypassing the Windows clipboard. + * + * Implementation references : Inside OLE 2'nd edition by Kraig Brockschmidt + * + * TODO: + * - Support for pasting between different processes. OLE clipboard support + * currently works only for in process copy and paste. Since we internally + * store a pointer to the source's IDataObject and delegate to that, this + * will fail if the IDataObject client belongs to a different process. + * - IDataObject::GetDataHere is not implemented + * - OleFlushClipboard needs to additionally handle TYMED_IStorage media + * by copying the storage into global memory. Subsequently the default + * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL + * back to TYMED_IStorage. + * - OLE1 compatibility formats to be synthesized from OLE2 formats and put on + * clipboard in OleSetClipboard. + * + */ + +#include <assert.h> +#include <stdarg.h> +#include <string.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winerror.h" +#include "winnls.h" +#include "ole2.h" +#include "wine/debug.h" +#include "olestd.h" + +#include "storage32.h" + +#define HANDLE_ERROR(err) { hr = err; TRACE("(HRESULT=%lx)\n", (HRESULT)err); goto CLEANUP; } + +/* For CoGetMalloc (MEMCTX_TASK is currently ignored) */ +#ifndef MEMCTX_TASK +# define MEMCTX_TASK -1 +#endif + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/**************************************************************************** + * OLEClipbrd + * DO NOT add any members before the VTables declaration! + */ +struct OLEClipbrd +{ + /* + * List all interface VTables here + */ + IDataObjectVtbl* lpvtbl1; /* IDataObject VTable */ + + /* + * The hidden OLE clipboard window. This window is used as the bridge between the + * the OLE and windows clipboard API. (Windows creates one such window per process) + */ + HWND hWndClipboard; + + /* + * Pointer to the source data object (via OleSetClipboard) + */ + IDataObject* pIDataObjectSrc; + + /* + * The registered DataObject clipboard format + */ + UINT cfDataObj; + + /* + * The handle to ourself + */ + HGLOBAL hSelf; + + /* + * Reference count of this object + */ + ULONG ref; +}; + +typedef struct OLEClipbrd OLEClipbrd; + + +/**************************************************************************** +* IEnumFORMATETC implementation +* DO NOT add any members before the VTables declaration! +*/ +typedef struct +{ + /* IEnumFORMATETC VTable */ + IEnumFORMATETCVtbl *lpVtbl; + + /* IEnumFORMATETC fields */ + UINT posFmt; /* current enumerator position */ + UINT countFmt; /* number of EnumFORMATETC's in array */ + LPFORMATETC pFmt; /* array of EnumFORMATETC's */ + + /* + * Reference count of this object + */ + DWORD ref; + + /* + * IUnknown implementation of the parent data object. + */ + IUnknown* pUnkDataObj; + +} IEnumFORMATETCImpl; + +typedef struct PresentationDataHeader +{ + BYTE unknown1[28]; + DWORD dwObjectExtentX; + DWORD dwObjectExtentY; + DWORD dwSize; +} PresentationDataHeader; + +/* + * The one and only OLEClipbrd object which is created by OLEClipbrd_Initialize() + */ +static HGLOBAL hTheOleClipboard = 0; +static OLEClipbrd* theOleClipboard = NULL; + + +/* + * Prototypes for the methods of the OLEClipboard class. + */ +void OLEClipbrd_Initialize(void); +void OLEClipbrd_UnInitialize(void); +static OLEClipbrd* OLEClipbrd_Construct(void); +static void OLEClipbrd_Destroy(OLEClipbrd* ptrToDestroy); +static HWND OLEClipbrd_CreateWindow(void); +static void OLEClipbrd_DestroyWindow(HWND hwnd); +LRESULT CALLBACK OLEClipbrd_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); +static HRESULT OLEClipbrd_RenderFormat( IDataObject *pIDataObject, LPFORMATETC pFormatetc ); +static HGLOBAL OLEClipbrd_GlobalDupMem( HGLOBAL hGlobalSrc ); + +/* + * Prototypes for the methods of the OLEClipboard class + * that implement IDataObject methods. + */ +static HRESULT WINAPI OLEClipbrd_IDataObject_QueryInterface( + IDataObject* iface, + REFIID riid, + void** ppvObject); +static ULONG WINAPI OLEClipbrd_IDataObject_AddRef( + IDataObject* iface); +static ULONG WINAPI OLEClipbrd_IDataObject_Release( + IDataObject* iface); +static HRESULT WINAPI OLEClipbrd_IDataObject_GetData( + IDataObject* iface, + LPFORMATETC pformatetcIn, + STGMEDIUM* pmedium); +static HRESULT WINAPI OLEClipbrd_IDataObject_GetDataHere( + IDataObject* iface, + LPFORMATETC pformatetc, + STGMEDIUM* pmedium); +static HRESULT WINAPI OLEClipbrd_IDataObject_QueryGetData( + IDataObject* iface, + LPFORMATETC pformatetc); +static HRESULT WINAPI OLEClipbrd_IDataObject_GetCanonicalFormatEtc( + IDataObject* iface, + LPFORMATETC pformatectIn, + LPFORMATETC pformatetcOut); +static HRESULT WINAPI OLEClipbrd_IDataObject_SetData( + IDataObject* iface, + LPFORMATETC pformatetc, + STGMEDIUM* pmedium, + BOOL fRelease); +static HRESULT WINAPI OLEClipbrd_IDataObject_EnumFormatEtc( + IDataObject* iface, + DWORD dwDirection, + IEnumFORMATETC** ppenumFormatEtc); +static HRESULT WINAPI OLEClipbrd_IDataObject_DAdvise( + IDataObject* iface, + FORMATETC* pformatetc, + DWORD advf, + IAdviseSink* pAdvSink, + DWORD* pdwConnection); +static HRESULT WINAPI OLEClipbrd_IDataObject_DUnadvise( + IDataObject* iface, + DWORD dwConnection); +static HRESULT WINAPI OLEClipbrd_IDataObject_EnumDAdvise( + IDataObject* iface, + IEnumSTATDATA** ppenumAdvise); + +/* + * Prototypes for the IEnumFORMATETC methods. + */ +static LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[], + LPUNKNOWN pUnkDataObj); +static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface(LPENUMFORMATETC iface, REFIID riid, + LPVOID* ppvObj); +static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface); +static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface); +static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next(LPENUMFORMATETC iface, ULONG celt, + FORMATETC* rgelt, ULONG* pceltFethed); +static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt); +static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface); +static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone(LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum); + + +/* + * Virtual function table for the OLEClipbrd's exposed IDataObject interface + */ +static IDataObjectVtbl OLEClipbrd_IDataObject_VTable = +{ + OLEClipbrd_IDataObject_QueryInterface, + OLEClipbrd_IDataObject_AddRef, + OLEClipbrd_IDataObject_Release, + OLEClipbrd_IDataObject_GetData, + OLEClipbrd_IDataObject_GetDataHere, + OLEClipbrd_IDataObject_QueryGetData, + OLEClipbrd_IDataObject_GetCanonicalFormatEtc, + OLEClipbrd_IDataObject_SetData, + OLEClipbrd_IDataObject_EnumFormatEtc, + OLEClipbrd_IDataObject_DAdvise, + OLEClipbrd_IDataObject_DUnadvise, + OLEClipbrd_IDataObject_EnumDAdvise +}; + +/* + * Virtual function table for IEnumFORMATETC interface + */ +static struct IEnumFORMATETCVtbl efvt = +{ + OLEClipbrd_IEnumFORMATETC_QueryInterface, + OLEClipbrd_IEnumFORMATETC_AddRef, + OLEClipbrd_IEnumFORMATETC_Release, + OLEClipbrd_IEnumFORMATETC_Next, + OLEClipbrd_IEnumFORMATETC_Skip, + OLEClipbrd_IEnumFORMATETC_Reset, + OLEClipbrd_IEnumFORMATETC_Clone +}; + +/* + * Name of our registered OLE clipboard window class + */ +CHAR OLEClipbrd_WNDCLASS[] = "CLIPBRDWNDCLASS"; + +/* + * If we need to store state info we can store it here. + * For now we don't need this functionality. + * +typedef struct tagClipboardWindowInfo +{ +} ClipboardWindowInfo; + */ + +/*---------------------------------------------------------------------* + * Win32 OLE clipboard API + *---------------------------------------------------------------------*/ + +/*********************************************************************** + * OleSetClipboard [OLE32.@] + * Places a pointer to the specified data object onto the clipboard, + * making the data object accessible to the OleGetClipboard function. + * + * RETURNS: + * + * S_OK IDataObject pointer placed on the clipboard + * CLIPBRD_E_CANT_OPEN OpenClipboard failed + * CLIPBRD_E_CANT_EMPTY EmptyClipboard failed + * CLIPBRD_E_CANT_CLOSE CloseClipboard failed + * CLIPBRD_E_CANT_SET SetClipboard failed + */ + +HRESULT WINAPI OleSetClipboard(IDataObject* pDataObj) +{ + HRESULT hr = S_OK; + IEnumFORMATETC* penumFormatetc = NULL; + FORMATETC rgelt; + BOOL bClipboardOpen = FALSE; +/* + HGLOBAL hDataObject = 0; + OLEClipbrd **ppDataObject; +*/ + + TRACE("(%p)\n", pDataObj); + + /* + * Make sure we have a clipboard object + */ + OLEClipbrd_Initialize(); + + /* + * If the Ole clipboard window hasn't been created yet, create it now. + */ + if ( !theOleClipboard->hWndClipboard ) + theOleClipboard->hWndClipboard = OLEClipbrd_CreateWindow(); + + if ( !theOleClipboard->hWndClipboard ) /* sanity check */ + HANDLE_ERROR( E_FAIL ); + + /* + * Open the Windows clipboard, associating it with our hidden window + */ + if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) ) + HANDLE_ERROR( CLIPBRD_E_CANT_OPEN ); + + /* + * Empty the current clipboard and make our window the clipboard owner + * NOTE: This will trigger a WM_DESTROYCLIPBOARD message + */ + if ( !EmptyClipboard() ) + HANDLE_ERROR( CLIPBRD_E_CANT_EMPTY ); + + /* + * If we are already holding on to an IDataObject first release that. + */ + if ( theOleClipboard->pIDataObjectSrc ) + { + IDataObject_Release(theOleClipboard->pIDataObjectSrc); + theOleClipboard->pIDataObjectSrc = NULL; + } + + /* + * AddRef the data object passed in and save its pointer. + * A NULL value indicates that the clipboard should be emptied. + */ + theOleClipboard->pIDataObjectSrc = pDataObj; + if ( pDataObj ) + { + IDataObject_AddRef(theOleClipboard->pIDataObjectSrc); + } + + /* + * Enumerate all HGLOBAL formats supported by the source and make + * those formats available using delayed rendering using SetClipboardData. + * Only global memory based data items may be made available to non-OLE + * applications via the standard Windows clipboard API. Data based on other + * mediums(non TYMED_HGLOBAL) can only be accessed via the Ole Clipboard API. + * + * TODO: Do we need to additionally handle TYMED_IStorage media by copying + * the storage into global memory? + */ + if ( pDataObj ) + { + if ( FAILED(hr = IDataObject_EnumFormatEtc( pDataObj, + DATADIR_GET, + &penumFormatetc ))) + { + HANDLE_ERROR( hr ); + } + + while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) ) + { + if ( rgelt.tymed == TYMED_HGLOBAL ) + { + CHAR szFmtName[80]; + TRACE("(cfFormat=%d:%s)\n", rgelt.cfFormat, + GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1) + ? szFmtName : ""); + + SetClipboardData( rgelt.cfFormat, NULL); + } + } + IEnumFORMATETC_Release(penumFormatetc); + } + + /* + * Windows additionally creates a new "DataObject" clipboard format + * and stores in on the clipboard. We could possibly store a pointer + * to our internal IDataObject interface on the clipboard. I'm not + * sure what the use of this is though. + * Enable the code below for this functionality. + */ +/* + theOleClipboard->cfDataObj = RegisterClipboardFormatA("DataObject"); + hDataObject = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, + sizeof(OLEClipbrd *)); + if (hDataObject==0) + HANDLE_ERROR( E_OUTOFMEMORY ); + + ppDataObject = (OLEClipbrd**)GlobalLock(hDataObject); + *ppDataObject = theOleClipboard; + GlobalUnlock(hDataObject); + + if ( !SetClipboardData( theOleClipboard->cfDataObj, hDataObject ) ) + HANDLE_ERROR( CLIPBRD_E_CANT_SET ); +*/ + + hr = S_OK; + +CLEANUP: + + /* + * Close Windows clipboard (It remains associated with our window) + */ + if ( bClipboardOpen && !CloseClipboard() ) + hr = CLIPBRD_E_CANT_CLOSE; + + /* + * Release the source IDataObject if something failed + */ + if ( FAILED(hr) ) + { + if (theOleClipboard->pIDataObjectSrc) + { + IDataObject_Release(theOleClipboard->pIDataObjectSrc); + theOleClipboard->pIDataObjectSrc = NULL; + } + } + + return hr; +} + + +/*********************************************************************** + * OleGetClipboard [OLE32.@] + * Returns a pointer to our internal IDataObject which represents the conceptual + * state of the Windows clipboard. If the current clipboard already contains + * an IDataObject, our internal IDataObject will delegate to this object. + */ +HRESULT WINAPI OleGetClipboard(IDataObject** ppDataObj) +{ + HRESULT hr = S_OK; + TRACE("()\n"); + + /* + * Make sure we have a clipboard object + */ + OLEClipbrd_Initialize(); + + if (!theOleClipboard) + return E_OUTOFMEMORY; + + /* Return a reference counted IDataObject */ + hr = IDataObject_QueryInterface( (IDataObject*)&(theOleClipboard->lpvtbl1), + &IID_IDataObject, (void**)ppDataObj); + return hr; +} + +/*********************************************************************** + * OleFlushClipboard [OLE2.76] + */ + +HRESULT WINAPI OleFlushClipboard16(void) +{ + return OleFlushClipboard(); +} + + +/****************************************************************************** + * OleFlushClipboard [OLE32.@] + * Renders the data from the source IDataObject into the windows clipboard + * + * TODO: OleFlushClipboard needs to additionally handle TYMED_IStorage media + * by copying the storage into global memory. Subsequently the default + * data object exposed through OleGetClipboard must convert this TYMED_HGLOBAL + * back to TYMED_IStorage. + */ +HRESULT WINAPI OleFlushClipboard() +{ + IEnumFORMATETC* penumFormatetc = NULL; + FORMATETC rgelt; + HRESULT hr = S_OK; + BOOL bClipboardOpen = FALSE; + IDataObject* pIDataObjectSrc = NULL; + + TRACE("()\n"); + + /* + * Make sure we have a clipboard object + */ + OLEClipbrd_Initialize(); + + /* + * Already flushed or no source DataObject? Nothing to do. + */ + if (!theOleClipboard->pIDataObjectSrc) + return S_OK; + + /* + * Addref and save the source data object we are holding on to temporarily, + * since it will be released when we empty the clipboard. + */ + pIDataObjectSrc = theOleClipboard->pIDataObjectSrc; + IDataObject_AddRef(pIDataObjectSrc); + + /* + * Open the Windows clipboard + */ + if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) ) + HANDLE_ERROR( CLIPBRD_E_CANT_OPEN ); + + /* + * Empty the current clipboard + */ + if ( !EmptyClipboard() ) + HANDLE_ERROR( CLIPBRD_E_CANT_EMPTY ); + + /* + * Render all HGLOBAL formats supported by the source into + * the windows clipboard. + */ + if ( FAILED( hr = IDataObject_EnumFormatEtc( pIDataObjectSrc, + DATADIR_GET, + &penumFormatetc) )) + { + HANDLE_ERROR( hr ); + } + + while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) ) + { + if ( rgelt.tymed == TYMED_HGLOBAL ) + { + CHAR szFmtName[80]; + TRACE("(cfFormat=%d:%s)\n", rgelt.cfFormat, + GetClipboardFormatNameA(rgelt.cfFormat, szFmtName, sizeof(szFmtName)-1) + ? szFmtName : ""); + + /* + * Render the clipboard data + */ + if ( FAILED(OLEClipbrd_RenderFormat( pIDataObjectSrc, &rgelt )) ) + continue; + } + } + + IEnumFORMATETC_Release(penumFormatetc); + + /* + * Release the source data object we are holding on to + */ + IDataObject_Release(pIDataObjectSrc); + +CLEANUP: + + /* + * Close Windows clipboard (It remains associated with our window) + */ + if ( bClipboardOpen && !CloseClipboard() ) + hr = CLIPBRD_E_CANT_CLOSE; + + return hr; +} + + +/*********************************************************************** + * OleIsCurrentClipboard [OLE32.@] + */ +HRESULT WINAPI OleIsCurrentClipboard ( IDataObject *pDataObject) +{ + TRACE("()\n"); + /* + * Make sure we have a clipboard object + */ + OLEClipbrd_Initialize(); + + if (!theOleClipboard) + return E_OUTOFMEMORY; + + return (pDataObject == theOleClipboard->pIDataObjectSrc) ? S_OK : S_FALSE; +} + + +/*---------------------------------------------------------------------* + * Internal implementation methods for the OLE clipboard + *---------------------------------------------------------------------*/ + +/*********************************************************************** + * OLEClipbrd_Initialize() + * Initializes the OLE clipboard. + */ +void OLEClipbrd_Initialize(void) +{ + /* + * Create the clipboard if necessary + */ + if ( !theOleClipboard ) + { + TRACE("()\n"); + theOleClipboard = OLEClipbrd_Construct(); + } +} + + +/*********************************************************************** + * OLEClipbrd_UnInitialize() + * Un-Initializes the OLE clipboard + */ +void OLEClipbrd_UnInitialize(void) +{ + TRACE("()\n"); + /* + * Destroy the clipboard if no one holds a reference to us. + * Note that the clipboard was created with a reference count of 1. + */ + if ( theOleClipboard && (theOleClipboard->ref <= 1) ) + { + OLEClipbrd_Destroy( theOleClipboard ); + } + else + { + WARN( "() : OLEClipbrd_UnInitialize called while client holds an IDataObject reference!\n"); + } +} + + +/********************************************************* + * Construct the OLEClipbrd class. + */ +static OLEClipbrd* OLEClipbrd_Construct() +{ + OLEClipbrd* newObject = NULL; + HGLOBAL hNewObject = 0; + + /* + * Allocate space for the object. We use GlobalAlloc since we need + * an HGLOBAL to expose our DataObject as a registered clipboard type. + */ + hNewObject = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE|GMEM_ZEROINIT, + sizeof(OLEClipbrd)); + if (hNewObject==0) + return NULL; + + /* + * Lock the handle for the entire lifetime of the clipboard. + */ + newObject = GlobalLock(hNewObject); + + /* + * Initialize the virtual function table. + */ + newObject->lpvtbl1 = &OLEClipbrd_IDataObject_VTable; + + /* + * Start with one reference count. The caller of this function + * must release the interface pointer when it is done. + */ + newObject->ref = 1; + + newObject->hSelf = hNewObject; + + /* + * The Ole clipboard is a singleton - save the global handle and pointer + */ + theOleClipboard = newObject; + hTheOleClipboard = hNewObject; + + return theOleClipboard; +} + +static void OLEClipbrd_Destroy(OLEClipbrd* ptrToDestroy) +{ + TRACE("()\n"); + + if ( !ptrToDestroy ) + return; + + /* + * Destroy the Ole clipboard window + */ + if ( ptrToDestroy->hWndClipboard ) + OLEClipbrd_DestroyWindow(ptrToDestroy->hWndClipboard); + + /* + * Free the actual OLE Clipboard structure. + */ + TRACE("() - Destroying clipboard data object.\n"); + GlobalUnlock(ptrToDestroy->hSelf); + GlobalFree(ptrToDestroy->hSelf); + + /* + * The Ole clipboard is a singleton (ptrToDestroy == theOleClipboard) + */ + theOleClipboard = NULL; + hTheOleClipboard = 0; +} + + +/*********************************************************************** + * OLEClipbrd_CreateWindow() + * Create the clipboard window + */ +static HWND OLEClipbrd_CreateWindow() +{ + HWND hwnd = 0; + WNDCLASSEXA wcex; + + /* + * Register the clipboard window class if necessary + */ + ZeroMemory( &wcex, sizeof(WNDCLASSEXA)); + + wcex.cbSize = sizeof(WNDCLASSEXA); + /* Windows creates this class with a style mask of 0 + * We don't bother doing this since the FindClassByAtom code + * would have to be changed to deal with this idiosyncrasy. */ + wcex.style = CS_GLOBALCLASS; + wcex.lpfnWndProc = OLEClipbrd_WndProc; + wcex.hInstance = 0; + wcex.lpszClassName = OLEClipbrd_WNDCLASS; + + RegisterClassExA(&wcex); + + /* + * Create a hidden window to receive OLE clipboard messages + */ + +/* + * If we need to store state info we can store it here. + * For now we don't need this functionality. + * ClipboardWindowInfo clipboardInfo; + * ZeroMemory( &trackerInfo, sizeof(ClipboardWindowInfo)); + */ + + hwnd = CreateWindowA(OLEClipbrd_WNDCLASS, + "ClipboardWindow", + WS_POPUP | WS_CLIPSIBLINGS | WS_OVERLAPPED, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + 0, + 0, + 0, + 0 /*(LPVOID)&clipboardInfo */); + + return hwnd; +} + +/*********************************************************************** + * OLEClipbrd_DestroyWindow(HWND) + * Destroy the clipboard window and unregister its class + */ +static void OLEClipbrd_DestroyWindow(HWND hwnd) +{ + /* + * Destroy clipboard window and unregister its WNDCLASS + */ + DestroyWindow(hwnd); + UnregisterClassA( OLEClipbrd_WNDCLASS, 0 ); +} + +/*********************************************************************** + * OLEClipbrd_WndProc(HWND, unsigned, WORD, LONG) + * Processes messages sent to the OLE clipboard window. + * Note that we will intercept messages in our WndProc only when data + * has been placed in the clipboard via OleSetClipboard(). + * i.e. Only when OLE owns the windows clipboard. + */ +LRESULT CALLBACK OLEClipbrd_WndProc + (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + /* + * WM_RENDERFORMAT + * We receive this message to allow us to handle delayed rendering of + * a specific clipboard format when an application requests data in + * that format by calling GetClipboardData. + * (Recall that in OleSetClipboard, we used SetClipboardData to + * make all HGLOBAL formats supported by the source IDataObject + * available using delayed rendering) + * On receiving this message we must actually render the data in the + * specified format and place it on the clipboard by calling the + * SetClipboardData function. + */ + case WM_RENDERFORMAT: + { + FORMATETC rgelt; + + ZeroMemory( &rgelt, sizeof(FORMATETC)); + + /* + * Initialize FORMATETC to a Windows clipboard friendly format + */ + rgelt.cfFormat = (UINT) wParam; + rgelt.dwAspect = DVASPECT_CONTENT; + rgelt.lindex = -1; + rgelt.tymed = TYMED_HGLOBAL; + + TRACE("(): WM_RENDERFORMAT(cfFormat=%d)\n", rgelt.cfFormat); + + /* + * Render the clipboard data. + * (We must have a source data object or we wouldn't be in this WndProc) + */ + OLEClipbrd_RenderFormat( (IDataObject*)&(theOleClipboard->lpvtbl1), &rgelt ); + + break; + } + + /* + * WM_RENDERALLFORMATS + * Sent before the clipboard owner window is destroyed. + * We should receive this message only when OleUninitialize is called + * while we have an IDataObject in the clipboard. + * For the content of the clipboard to remain available to other + * applications, we must render data in all the formats the source IDataObject + * is capable of generating, and place the data on the clipboard by calling + * SetClipboardData. + */ + case WM_RENDERALLFORMATS: + { + IEnumFORMATETC* penumFormatetc = NULL; + FORMATETC rgelt; + + TRACE("(): WM_RENDERALLFORMATS\n"); + + /* + * Render all HGLOBAL formats supported by the source into + * the windows clipboard. + */ + if ( FAILED( IDataObject_EnumFormatEtc( (IDataObject*)&(theOleClipboard->lpvtbl1), + DATADIR_GET, &penumFormatetc) ) ) + { + WARN("(): WM_RENDERALLFORMATS failed to retrieve EnumFormatEtc!\n"); + return 0; + } + + while ( S_OK == IEnumFORMATETC_Next(penumFormatetc, 1, &rgelt, NULL) ) + { + if ( rgelt.tymed == TYMED_HGLOBAL ) + { + /* + * Render the clipboard data. + */ + if ( FAILED(OLEClipbrd_RenderFormat( (IDataObject*)&(theOleClipboard->lpvtbl1), &rgelt )) ) + continue; + + TRACE("(): WM_RENDERALLFORMATS(cfFormat=%d)\n", rgelt.cfFormat); + } + } + + IEnumFORMATETC_Release(penumFormatetc); + + break; + } + + /* + * WM_DESTROYCLIPBOARD + * This is sent by EmptyClipboard before the clipboard is emptied. + * We should release any IDataObject we are holding onto when we receive + * this message, since it indicates that the OLE clipboard should be empty + * from this point on. + */ + case WM_DESTROYCLIPBOARD: + { + TRACE("(): WM_DESTROYCLIPBOARD\n"); + /* + * Release the data object we are holding on to + */ + if ( theOleClipboard->pIDataObjectSrc ) + { + IDataObject_Release(theOleClipboard->pIDataObjectSrc); + theOleClipboard->pIDataObjectSrc = NULL; + } + break; + } + +/* + case WM_ASKCBFORMATNAME: + case WM_CHANGECBCHAIN: + case WM_DRAWCLIPBOARD: + case WM_SIZECLIPBOARD: + case WM_HSCROLLCLIPBOARD: + case WM_VSCROLLCLIPBOARD: + case WM_PAINTCLIPBOARD: +*/ + default: + return DefWindowProcA(hWnd, message, wParam, lParam); + } + + return 0; +} + +#define MAX_CLIPFORMAT_NAME 80 + +/*********************************************************************** + * OLEClipbrd_RenderFormat(LPFORMATETC) + * Render the clipboard data. Note that this call will delegate to the + * source data object. + * Note: This function assumes it is passed an HGLOBAL format to render. + */ +static HRESULT OLEClipbrd_RenderFormat(IDataObject *pIDataObject, LPFORMATETC pFormatetc) +{ + STGMEDIUM std; + HGLOBAL hDup; + HRESULT hr = S_OK; + char szFmtName[MAX_CLIPFORMAT_NAME]; + ILockBytes *ptrILockBytes = 0; + HGLOBAL hStorage = 0; + + GetClipboardFormatNameA(pFormatetc->cfFormat, szFmtName, MAX_CLIPFORMAT_NAME); + + /* If embed source */ + if (!strcmp(szFmtName, CF_EMBEDSOURCE)) + { + memset(&std, 0, sizeof(STGMEDIUM)); + std.tymed = pFormatetc->tymed = TYMED_ISTORAGE; + + hStorage = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, 0); + if (hStorage == NULL) + HANDLE_ERROR( E_OUTOFMEMORY ); + hr = CreateILockBytesOnHGlobal(hStorage, FALSE, &ptrILockBytes); + hr = StgCreateDocfileOnILockBytes(ptrILockBytes, STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &std.u.pstg); + + if (FAILED(hr = IDataObject_GetDataHere(theOleClipboard->pIDataObjectSrc, pFormatetc, &std))) + { + WARN("() : IDataObject_GetDataHere failed to render clipboard data! (%lx)\n", hr); + GlobalFree(hStorage); + return hr; + } + + if (1) /* check whether the presentation data is already -not- present */ + { + FORMATETC fmt2; + STGMEDIUM std2; + METAFILEPICT *mfp = 0; + + fmt2.cfFormat = CF_METAFILEPICT; + fmt2.ptd = 0; + fmt2.dwAspect = DVASPECT_CONTENT; + fmt2.lindex = -1; + fmt2.tymed = TYMED_MFPICT; + + memset(&std2, 0, sizeof(STGMEDIUM)); + std2.tymed = TYMED_MFPICT; + + /* Get the metafile picture out of it */ + + if (!FAILED(hr = IDataObject_GetData(theOleClipboard->pIDataObjectSrc, &fmt2, &std2))) + { + mfp = (METAFILEPICT *)GlobalLock(std2.u.hGlobal); + } + + if (mfp) + { + OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0}; + IStream *pStream = 0; + void *mfBits; + PresentationDataHeader pdh; + INT nSize; + CLSID clsID; + LPOLESTR strProgID; + CHAR strOleTypeName[51]; + BYTE OlePresStreamHeader [] = + { + 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + + nSize = GetMetaFileBitsEx(mfp->hMF, 0, NULL); + + memset(&pdh, 0, sizeof(PresentationDataHeader)); + memcpy(&pdh, OlePresStreamHeader, sizeof(OlePresStreamHeader)); + + pdh.dwObjectExtentX = mfp->xExt; + pdh.dwObjectExtentY = mfp->yExt; + pdh.dwSize = nSize; + + hr = IStorage_CreateStream(std.u.pstg, name, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, 0, &pStream); + + hr = IStream_Write(pStream, &pdh, sizeof(PresentationDataHeader), NULL); + + mfBits = HeapAlloc(GetProcessHeap(), 0, nSize); + nSize = GetMetaFileBitsEx(mfp->hMF, nSize, mfBits); + + hr = IStream_Write(pStream, mfBits, nSize, NULL); + + IStream_Release(pStream); + + HeapFree(GetProcessHeap(), 0, mfBits); + + GlobalUnlock(std2.u.hGlobal); + + ReadClassStg(std.u.pstg, &clsID); + ProgIDFromCLSID(&clsID, &strProgID); + + WideCharToMultiByte( CP_ACP, 0, strProgID, -1, strOleTypeName, sizeof(strOleTypeName), NULL, NULL ); + OLECONVERT_CreateOleStream(std.u.pstg); + OLECONVERT_CreateCompObjStream(std.u.pstg, strOleTypeName); + } + } + } + else + { + if (FAILED(hr = IDataObject_GetData(pIDataObject, pFormatetc, &std))) + { + WARN("() : IDataObject_GetData failed to render clipboard data! (%lx)\n", hr); + GlobalFree(hStorage); + return hr; + } + + /* To put a copy back on the clipboard */ + + hStorage = std.u.hGlobal; + } + + /* + * Put a copy of the rendered data back on the clipboard + */ + + if ( !(hDup = OLEClipbrd_GlobalDupMem(hStorage)) ) + HANDLE_ERROR( E_OUTOFMEMORY ); + + if ( !SetClipboardData( pFormatetc->cfFormat, hDup ) ) + { + GlobalFree(hDup); + WARN("() : Failed to set rendered clipboard data into clipboard!\n"); + } + +CLEANUP: + + ReleaseStgMedium(&std); + + return hr; +} + + +/*********************************************************************** + * OLEClipbrd_GlobalDupMem( HGLOBAL ) + * Helper method to duplicate an HGLOBAL chunk of memory + */ +static HGLOBAL OLEClipbrd_GlobalDupMem( HGLOBAL hGlobalSrc ) +{ + HGLOBAL hGlobalDest; + PVOID pGlobalSrc, pGlobalDest; + DWORD cBytes; + + if ( !hGlobalSrc ) + return 0; + + cBytes = GlobalSize(hGlobalSrc); + if ( 0 == cBytes ) + return 0; + + hGlobalDest = GlobalAlloc( GMEM_DDESHARE|GMEM_MOVEABLE, + cBytes ); + if ( !hGlobalDest ) + return 0; + + pGlobalSrc = GlobalLock(hGlobalSrc); + pGlobalDest = GlobalLock(hGlobalDest); + if ( !pGlobalSrc || !pGlobalDest ) + { + GlobalFree(hGlobalDest); + return 0; + } + + memcpy(pGlobalDest, pGlobalSrc, cBytes); + + GlobalUnlock(hGlobalSrc); + GlobalUnlock(hGlobalDest); + + return hGlobalDest; +} + + +/*---------------------------------------------------------------------* + * Implementation of the internal IDataObject interface exposed by + * the OLE clipboard. + *---------------------------------------------------------------------*/ + + +/************************************************************************ + * OLEClipbrd_IDataObject_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static HRESULT WINAPI OLEClipbrd_IDataObject_QueryInterface( + IDataObject* iface, + REFIID riid, + void** ppvObject) +{ + /* + * Declare "This" pointer + */ + OLEClipbrd *This = (OLEClipbrd *)iface; + TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObject); + + /* + * Perform a sanity check on the parameters. + */ + if ( (This==0) || (ppvObject==0) ) + return E_INVALIDARG; + + /* + * Initialize the return parameter. + */ + *ppvObject = 0; + + /* + * Compare the riid with the interface IDs implemented by this object. + */ + if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) + { + *ppvObject = iface; + } + else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0) + { + *ppvObject = (IDataObject*)&(This->lpvtbl1); + } + else /* We only support IUnknown and IDataObject */ + { + WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; + } + + /* + * Query Interface always increases the reference count by one when it is + * successful. + */ + IUnknown_AddRef((IUnknown*)*ppvObject); + + return S_OK; +} + +/************************************************************************ + * OLEClipbrd_IDataObject_AddRef (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI OLEClipbrd_IDataObject_AddRef( + IDataObject* iface) +{ + /* + * Declare "This" pointer + */ + OLEClipbrd *This = (OLEClipbrd *)iface; + + TRACE("(%p)->(count=%lu)\n",This, This->ref); + + return InterlockedIncrement(&This->ref); + +} + +/************************************************************************ + * OLEClipbrd_IDataObject_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI OLEClipbrd_IDataObject_Release( + IDataObject* iface) +{ + /* + * Declare "This" pointer + */ + OLEClipbrd *This = (OLEClipbrd *)iface; + ULONG ref; + + TRACE("(%p)->(count=%lu)\n",This, This->ref); + + /* + * Decrease the reference count on this object. + */ + ref = InterlockedDecrement(&This->ref); + + /* + * If the reference count goes down to 0, perform suicide. + */ + if (ref == 0) + { + OLEClipbrd_Destroy(This); + } + + return ref; +} + + +/************************************************************************ + * OLEClipbrd_IDataObject_GetData (IDataObject) + * + * The OLE Clipboard's implementation of this method delegates to + * a data source if there is one or wraps around the windows clipboard + * + * See Windows documentation for more details on IDataObject methods. + */ +static HRESULT WINAPI OLEClipbrd_IDataObject_GetData( + IDataObject* iface, + LPFORMATETC pformatetcIn, + STGMEDIUM* pmedium) +{ + HANDLE hData = 0; + BOOL bClipboardOpen = FALSE; + HRESULT hr = S_OK; + LPVOID src; + + /* + * Declare "This" pointer + */ + OLEClipbrd *This = (OLEClipbrd *)iface; + + TRACE("(%p,%p,%p)\n", iface, pformatetcIn, pmedium); + + if ( !pformatetcIn || !pmedium ) + return E_INVALIDARG; + + /* + * If we have a data source placed on the clipboard (via OleSetClipboard) + * simply delegate to the source object's QueryGetData + * NOTE: This code assumes that the IDataObject is in the same address space! + * We will need to add marshalling support when Wine handles multiple processes. + */ + if ( This->pIDataObjectSrc ) + { + return IDataObject_GetData(This->pIDataObjectSrc, pformatetcIn, pmedium); + } + + if ( pformatetcIn->lindex != -1 ) + return DV_E_LINDEX; + if ( (pformatetcIn->tymed & TYMED_HGLOBAL) != TYMED_HGLOBAL ) + return DV_E_TYMED; +/* + if ( pformatetcIn->dwAspect != DVASPECT_CONTENT ) + return DV_E_DVASPECT; +*/ + + /* + * Otherwise, get the data from the windows clipboard using GetClipboardData + */ + if ( !(bClipboardOpen = OpenClipboard(theOleClipboard->hWndClipboard)) ) + HANDLE_ERROR( CLIPBRD_E_CANT_OPEN ); + + hData = GetClipboardData(pformatetcIn->cfFormat); + + /* Must make a copy of global handle returned by GetClipboardData; it + * is not valid after we call CloseClipboard + * Application is responsible for freeing the memory (Forte Agent does this) + */ + src = GlobalLock(hData); + if(src) { + LPVOID dest; + ULONG size; + HANDLE hDest; + + size = GlobalSize(hData); + hDest = GlobalAlloc(GHND, size); + dest = GlobalLock(hDest); + memcpy(dest, src, size); + GlobalUnlock(hDest); + GlobalUnlock(hData); + hData = hDest; + } + + /* + * Return the clipboard data in the storage medium structure + */ + pmedium->tymed = (hData == 0) ? TYMED_NULL : TYMED_HGLOBAL; + pmedium->u.hGlobal = (HGLOBAL)hData; + pmedium->pUnkForRelease = NULL; + + hr = S_OK; + +CLEANUP: + /* + * Close Windows clipboard + */ + if ( bClipboardOpen && !CloseClipboard() ) + hr = CLIPBRD_E_CANT_CLOSE; + + if ( FAILED(hr) ) + return hr; + return (hData == 0) ? DV_E_FORMATETC : S_OK; +} + +static HRESULT WINAPI OLEClipbrd_IDataObject_GetDataHere( + IDataObject* iface, + LPFORMATETC pformatetc, + STGMEDIUM* pmedium) +{ + FIXME(": Stub\n"); + return E_NOTIMPL; +} + +/************************************************************************ + * OLEClipbrd_IDataObject_QueryGetData (IDataObject) + * + * The OLE Clipboard's implementation of this method delegates to + * a data source if there is one or wraps around the windows clipboard + * function IsClipboardFormatAvailable() otherwise. + * + * See Windows documentation for more details on IDataObject methods. + */ +static HRESULT WINAPI OLEClipbrd_IDataObject_QueryGetData( + IDataObject* iface, + LPFORMATETC pformatetc) +{ + /* + * Declare "This" pointer + */ + OLEClipbrd *This = (OLEClipbrd *)iface; + + TRACE("(%p, %p)\n", iface, pformatetc); + + /* + * If we have a data source placed on the clipboard (via OleSetClipboard) + * simply delegate to the source object's QueryGetData + */ + if ( This->pIDataObjectSrc ) + { + return IDataObject_QueryGetData(This->pIDataObjectSrc, pformatetc); + } + + if (!pformatetc) + return E_INVALIDARG; +/* + if ( pformatetc->dwAspect != DVASPECT_CONTENT ) + return DV_E_DVASPECT; +*/ + if ( pformatetc->lindex != -1 ) + return DV_E_LINDEX; + + /* TODO: Handle TYMED_IStorage media which were put on the clipboard + * by copying the storage into global memory. We must convert this + * TYMED_HGLOBAL back to TYMED_IStorage. + */ + if ( pformatetc->tymed != TYMED_HGLOBAL ) + return DV_E_TYMED; + + /* + * Delegate to the Windows clipboard function IsClipboardFormatAvailable + */ + return (IsClipboardFormatAvailable(pformatetc->cfFormat)) ? S_OK : DV_E_FORMATETC; +} + +/************************************************************************ + * OLEClipbrd_IDataObject_GetCanonicalFormatEtc (IDataObject) + * + * See Windows documentation for more details on IDataObject methods. + */ +static HRESULT WINAPI OLEClipbrd_IDataObject_GetCanonicalFormatEtc( + IDataObject* iface, + LPFORMATETC pformatectIn, + LPFORMATETC pformatetcOut) +{ + TRACE("(%p, %p, %p)\n", iface, pformatectIn, pformatetcOut); + + if ( !pformatectIn || !pformatetcOut ) + return E_INVALIDARG; + + memcpy(pformatetcOut, pformatectIn, sizeof(FORMATETC)); + return DATA_S_SAMEFORMATETC; +} + +/************************************************************************ + * OLEClipbrd_IDataObject_SetData (IDataObject) + * + * The OLE Clipboard's does not implement this method + * + * See Windows documentation for more details on IDataObject methods. + */ +static HRESULT WINAPI OLEClipbrd_IDataObject_SetData( + IDataObject* iface, + LPFORMATETC pformatetc, + STGMEDIUM* pmedium, + BOOL fRelease) +{ + TRACE("\n"); + return E_NOTIMPL; +} + +/************************************************************************ + * OLEClipbrd_IDataObject_EnumFormatEtc (IDataObject) + * + * See Windows documentation for more details on IDataObject methods. + */ +static HRESULT WINAPI OLEClipbrd_IDataObject_EnumFormatEtc( + IDataObject* iface, + DWORD dwDirection, + IEnumFORMATETC** ppenumFormatEtc) +{ + HRESULT hr = S_OK; + FORMATETC *afmt = NULL; + int cfmt, i; + UINT format; + BOOL bClipboardOpen; + + /* + * Declare "This" pointer + */ + OLEClipbrd *This = (OLEClipbrd *)iface; + + TRACE("(%p, %lx, %p)\n", iface, dwDirection, ppenumFormatEtc); + + /* + * If we have a data source placed on the clipboard (via OleSetClipboard) + * simply delegate to the source object's EnumFormatEtc + */ + if ( This->pIDataObjectSrc ) + { + return IDataObject_EnumFormatEtc(This->pIDataObjectSrc, + dwDirection, ppenumFormatEtc); + } + + /* + * Otherwise we must provide our own enumerator which wraps around the + * Windows clipboard function EnumClipboardFormats + */ + if ( !ppenumFormatEtc ) + return E_INVALIDARG; + + if ( dwDirection != DATADIR_GET ) /* IDataObject_SetData not implemented */ + return E_NOTIMPL; + + /* + * Store all current clipboard formats in an array of FORMATETC's, + * and create an IEnumFORMATETC enumerator from this list. + */ + cfmt = CountClipboardFormats(); + afmt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(FORMATETC) * cfmt); + /* + * Open the Windows clipboard, associating it with our hidden window + */ + if ( !(bClipboardOpen = OpenClipboard(This->hWndClipboard)) ) + HANDLE_ERROR( CLIPBRD_E_CANT_OPEN ); + + /* + * Store all current clipboard formats in an array of FORMATETC's + * TODO: Handle TYMED_IStorage media which were put on the clipboard + * by copying the storage into global memory. We must convert this + * TYMED_HGLOBAL back to TYMED_IStorage. + */ + for (i = 0, format = 0; i < cfmt; i++) + { + format = EnumClipboardFormats(format); + if (!format) /* Failed! */ + { + ERR("EnumClipboardFormats failed to return format!\n"); + HANDLE_ERROR( E_FAIL ); + } + + /* Init the FORMATETC struct */ + afmt[i].cfFormat = format; + afmt[i].ptd = NULL; + afmt[i].dwAspect = DVASPECT_CONTENT; + afmt[i].lindex = -1; + afmt[i].tymed = TYMED_HGLOBAL; + } + + /* + * Create an EnumFORMATETC enumerator and return an + * EnumFORMATETC after bumping up its ref count + */ + *ppenumFormatEtc = OLEClipbrd_IEnumFORMATETC_Construct( cfmt, afmt, (LPUNKNOWN)iface); + if (!(*ppenumFormatEtc)) + HANDLE_ERROR( E_OUTOFMEMORY ); + + if (FAILED( hr = IEnumFORMATETC_AddRef(*ppenumFormatEtc))) + HANDLE_ERROR( hr ); + + hr = S_OK; + +CLEANUP: + /* + * Free the array of FORMATETC's + */ + HeapFree(GetProcessHeap(), 0, afmt); + + /* + * Close Windows clipboard + */ + if ( bClipboardOpen && !CloseClipboard() ) + hr = CLIPBRD_E_CANT_CLOSE; + + return hr; +} + +/************************************************************************ + * OLEClipbrd_IDataObject_DAdvise (IDataObject) + * + * The OLE Clipboard's does not implement this method + * + * See Windows documentation for more details on IDataObject methods. + */ +static HRESULT WINAPI OLEClipbrd_IDataObject_DAdvise( + IDataObject* iface, + FORMATETC* pformatetc, + DWORD advf, + IAdviseSink* pAdvSink, + DWORD* pdwConnection) +{ + TRACE("\n"); + return E_NOTIMPL; +} + +/************************************************************************ + * OLEClipbrd_IDataObject_DUnadvise (IDataObject) + * + * The OLE Clipboard's does not implement this method + * + * See Windows documentation for more details on IDataObject methods. + */ +static HRESULT WINAPI OLEClipbrd_IDataObject_DUnadvise( + IDataObject* iface, + DWORD dwConnection) +{ + TRACE("\n"); + return E_NOTIMPL; +} + +/************************************************************************ + * OLEClipbrd_IDataObject_EnumDAdvise (IDataObject) + * + * The OLE Clipboard does not implement this method + * + * See Windows documentation for more details on IDataObject methods. + */ +static HRESULT WINAPI OLEClipbrd_IDataObject_EnumDAdvise( + IDataObject* iface, + IEnumSTATDATA** ppenumAdvise) +{ + TRACE("\n"); + return E_NOTIMPL; +} + + +/*---------------------------------------------------------------------* + * Implementation of the internal IEnumFORMATETC interface returned by + * the OLE clipboard's IDataObject. + *---------------------------------------------------------------------*/ + +/************************************************************************ + * OLEClipbrd_IEnumFORMATETC_Construct (UINT, const FORMATETC, LPUNKNOWN) + * + * Creates an IEnumFORMATETC enumerator from an array of FORMATETC + * Structures. pUnkOuter is the outer unknown for reference counting only. + * NOTE: this does not AddRef the interface. + */ + +LPENUMFORMATETC OLEClipbrd_IEnumFORMATETC_Construct(UINT cfmt, const FORMATETC afmt[], + LPUNKNOWN pUnkDataObj) +{ + IEnumFORMATETCImpl* ef; + DWORD size=cfmt * sizeof(FORMATETC); + LPMALLOC pIMalloc; + + ef = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumFORMATETCImpl)); + if (!ef) + return NULL; + + ef->ref = 0; + ef->lpVtbl = &efvt; + ef->pUnkDataObj = pUnkDataObj; + + ef->posFmt = 0; + ef->countFmt = cfmt; + if (FAILED(CoGetMalloc(MEMCTX_TASK, &pIMalloc))) { + HeapFree(GetProcessHeap(), 0, ef); + return NULL; + } + ef->pFmt = (LPFORMATETC)IMalloc_Alloc(pIMalloc, size); + IMalloc_Release(pIMalloc); + + if (ef->pFmt) + memcpy(ef->pFmt, afmt, size); + + TRACE("(%p)->()\n",ef); + return (LPENUMFORMATETC)ef; +} + + +/************************************************************************ + * OLEClipbrd_IEnumFORMATETC_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_QueryInterface + (LPENUMFORMATETC iface, REFIID riid, LPVOID* ppvObj) +{ + IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; + + TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj); + + /* + * Since enumerators are separate objects from the parent data object + * we only need to support the IUnknown and IEnumFORMATETC interfaces + */ + + *ppvObj = NULL; + + if(IsEqualIID(riid, &IID_IUnknown)) + { + *ppvObj = This; + } + else if(IsEqualIID(riid, &IID_IEnumFORMATETC)) + { + *ppvObj = (IDataObject*)This; + } + + if(*ppvObj) + { + IEnumFORMATETC_AddRef((IEnumFORMATETC*)*ppvObj); + TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj); + return S_OK; + } + + TRACE("-- Interface: E_NOINTERFACE\n"); + return E_NOINTERFACE; +} + +/************************************************************************ + * OLEClipbrd_IEnumFORMATETC_AddRef (IUnknown) + * + * Since enumerating formats only makes sense when our data object is around, + * we insure that it stays as long as we stay by calling our parents IUnknown + * for AddRef and Release. But since we are not controlled by the lifetime of + * the outer object, we still keep our own reference count in order to + * free ourselves. + */ +static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_AddRef(LPENUMFORMATETC iface) +{ + IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; + TRACE("(%p)->(count=%lu)\n",This, This->ref); + + if (This->pUnkDataObj) + IUnknown_AddRef(This->pUnkDataObj); + + return InterlockedIncrement(&This->ref); +} + +/************************************************************************ + * OLEClipbrd_IEnumFORMATETC_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI OLEClipbrd_IEnumFORMATETC_Release(LPENUMFORMATETC iface) +{ + IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; + LPMALLOC pIMalloc; + ULONG ref; + + TRACE("(%p)->(count=%lu)\n",This, This->ref); + + if (This->pUnkDataObj) + IUnknown_Release(This->pUnkDataObj); /* Release parent data object */ + + ref = InterlockedDecrement(&This->ref); + if (!ref) + { + TRACE("() - destroying IEnumFORMATETC(%p)\n",This); + if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pIMalloc))) + { + IMalloc_Free(pIMalloc, This->pFmt); + IMalloc_Release(pIMalloc); + } + + HeapFree(GetProcessHeap(),0,This); + } + return ref; +} + +/************************************************************************ + * OLEClipbrd_IEnumFORMATETC_Next (IEnumFORMATETC) + * + * Standard enumerator members for IEnumFORMATETC + */ +static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Next + (LPENUMFORMATETC iface, ULONG celt, FORMATETC *rgelt, ULONG *pceltFethed) +{ + IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; + UINT cfetch; + HRESULT hres = S_FALSE; + + TRACE("(%p)->(pos=%u)\n", This, This->posFmt); + + if (This->posFmt < This->countFmt) + { + cfetch = This->countFmt - This->posFmt; + if (cfetch >= celt) + { + cfetch = celt; + hres = S_OK; + } + + memcpy(rgelt, &This->pFmt[This->posFmt], cfetch * sizeof(FORMATETC)); + This->posFmt += cfetch; + } + else + { + cfetch = 0; + } + + if (pceltFethed) + { + *pceltFethed = cfetch; + } + + return hres; +} + +/************************************************************************ + * OLEClipbrd_IEnumFORMATETC_Skip (IEnumFORMATETC) + * + * Standard enumerator members for IEnumFORMATETC + */ +static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Skip(LPENUMFORMATETC iface, ULONG celt) +{ + IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; + TRACE("(%p)->(num=%lu)\n", This, celt); + + This->posFmt += celt; + if (This->posFmt > This->countFmt) + { + This->posFmt = This->countFmt; + return S_FALSE; + } + return S_OK; +} + +/************************************************************************ + * OLEClipbrd_IEnumFORMATETC_Reset (IEnumFORMATETC) + * + * Standard enumerator members for IEnumFORMATETC + */ +static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Reset(LPENUMFORMATETC iface) +{ + IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; + TRACE("(%p)->()\n", This); + + This->posFmt = 0; + return S_OK; +} + +/************************************************************************ + * OLEClipbrd_IEnumFORMATETC_Clone (IEnumFORMATETC) + * + * Standard enumerator members for IEnumFORMATETC + */ +static HRESULT WINAPI OLEClipbrd_IEnumFORMATETC_Clone + (LPENUMFORMATETC iface, LPENUMFORMATETC* ppenum) +{ + IEnumFORMATETCImpl *This = (IEnumFORMATETCImpl *)iface; + HRESULT hr = S_OK; + + TRACE("(%p)->(ppenum=%p)\n", This, ppenum); + + if ( !ppenum ) + return E_INVALIDARG; + + *ppenum = OLEClipbrd_IEnumFORMATETC_Construct(This->countFmt, + This->pFmt, + This->pUnkDataObj); + + if (FAILED( hr = IEnumFORMATETC_AddRef(*ppenum))) + return ( hr ); + + return (*ppenum) ? S_OK : E_OUTOFMEMORY; +} diff --git a/reactos/lib/ole32/compobj.c b/reactos/lib/ole32/compobj.c index 92bd513c2ac..01201228f15 100644 --- a/reactos/lib/ole32/compobj.c +++ b/reactos/lib/ole32/compobj.c @@ -1,2687 +1,2687 @@ -/* - * COMPOBJ library - * - * Copyright 1995 Martin von Loewis - * Copyright 1998 Justin Bradford - * Copyright 1999 Francis Beaudet - * Copyright 1999 Sylvain St-Germain - * Copyright 2002 Marcus Meissner - * Copyright 2004 Mike Hearn - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Note - * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED - * Therefore do not test against COINIT_MULTITHREADED - * - * TODO list: (items bunched together depend on each other) - * - * - Implement the service control manager (in rpcss) to keep track - * of registered class objects: ISCM::ServerRegisterClsid et al - * - Implement the OXID resolver so we don't need magic endpoint names for - * clients and servers to meet up - * - * - Pump the message loop during RPC calls. - * - Call IMessageFilter functions. - * - * - Make all ole interface marshaling use NDR to be wire compatible with - * native DCOM - * - Use & interpret ORPCTHIS & ORPCTHAT. - * - */ - -#include "config.h" - -#include <stdlib.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> -#include <assert.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "objbase.h" -#include "ole2.h" -#include "ole2ver.h" -#include "rpc.h" -#include "winerror.h" -#include "winreg.h" -#include "wownt32.h" -#include "wine/unicode.h" -#include "objbase.h" -#include "compobj_private.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -typedef LPCSTR LPCOLESTR16; - -HINSTANCE OLE32_hInstance = 0; /* FIXME: make static ... */ - -/**************************************************************************** - * This section defines variables internal to the COM module. - * - * TODO: Most of these things will have to be made thread-safe. - */ - -static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk); -static void COM_RevokeAllClasses(void); - -const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} }; - -APARTMENT *MTA; /* protected by csApartment */ -static struct list apts = LIST_INIT( apts ); /* protected by csApartment */ - -static CRITICAL_SECTION csApartment; -static CRITICAL_SECTION_DEBUG critsect_debug = -{ - 0, 0, &csApartment, - { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, - 0, 0, { 0, (DWORD)(__FILE__ ": csApartment") } -}; -static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 }; - -/* - * This lock count counts the number of times CoInitialize is called. It is - * decreased every time CoUninitialize is called. When it hits 0, the COM - * libraries are freed - */ -static LONG s_COMLockCount = 0; - -/* - * This linked list contains the list of registered class objects. These - * are mostly used to register the factories for out-of-proc servers of OLE - * objects. - * - * TODO: Make this data structure aware of inter-process communication. This - * means that parts of this will be exported to the Wine Server. - */ -typedef struct tagRegisteredClass -{ - CLSID classIdentifier; - LPUNKNOWN classObject; - DWORD runContext; - DWORD connectFlags; - DWORD dwCookie; - LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */ - struct tagRegisteredClass* nextClass; -} RegisteredClass; - -static RegisteredClass* firstRegisteredClass = NULL; - -static CRITICAL_SECTION csRegisteredClassList; -static CRITICAL_SECTION_DEBUG class_cs_debug = -{ - 0, 0, &csRegisteredClassList, - { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList }, - 0, 0, { 0, (DWORD)(__FILE__ ": csRegisteredClassList") } -}; -static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 }; - -/***************************************************************************** - * This section contains OpenDllList definitions - * - * The OpenDllList contains only handles of dll loaded by CoGetClassObject or - * other functions that do LoadLibrary _without_ giving back a HMODULE. - * Without this list these handles would never be freed. - * - * FIXME: a DLL that says OK when asked for unloading is unloaded in the - * next unload-call but not before 600 sec. - */ - -typedef struct tagOpenDll { - HINSTANCE hLibrary; - struct tagOpenDll *next; -} OpenDll; - -static OpenDll *openDllList = NULL; /* linked list of open dlls */ - -static CRITICAL_SECTION csOpenDllList; -static CRITICAL_SECTION_DEBUG dll_cs_debug = -{ - 0, 0, &csOpenDllList, - { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList }, - 0, 0, { 0, (DWORD)(__FILE__ ": csOpenDllList") } -}; -static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 }; - -static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',' ', - '0','x','#','#','#','#','#','#','#','#',' ',0}; -static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - -static void COMPOBJ_DLLList_Add(HANDLE hLibrary); -static void COMPOBJ_DllList_FreeUnused(int Timeout); - -static void COMPOBJ_InitProcess( void ) -{ - WNDCLASSW wclass; - - /* Dispatching to the correct thread in an apartment is done through - * window messages rather than RPC transports. When an interface is - * marshalled into another apartment in the same process, a window of the - * following class is created. The *caller* of CoMarshalInterface (ie the - * application) is responsible for pumping the message loop in that thread. - * The WM_USER messages which point to the RPCs are then dispatched to - * COM_AptWndProc by the user's code from the apartment in which the interface - * was unmarshalled. - */ - memset(&wclass, 0, sizeof(wclass)); - wclass.lpfnWndProc = apartment_wndproc; - wclass.hInstance = OLE32_hInstance; - wclass.lpszClassName = wszAptWinClass; - RegisterClassW(&wclass); -} - -static void COMPOBJ_UninitProcess( void ) -{ - UnregisterClassW(wszAptWinClass, OLE32_hInstance); -} - -static void COM_TlsDestroy() -{ - struct oletls *info = NtCurrentTeb()->ReservedForOle; - if (info) - { - if (info->apt) apartment_release(info->apt); - if (info->errorinfo) IErrorInfo_Release(info->errorinfo); - if (info->state) IUnknown_Release(info->state); - HeapFree(GetProcessHeap(), 0, info); - NtCurrentTeb()->ReservedForOle = NULL; - } -} - -/****************************************************************************** - * Manage apartments. - */ - -/* allocates memory and fills in the necessary fields for a new apartment - * object */ -static APARTMENT *apartment_construct(DWORD model) -{ - APARTMENT *apt; - - TRACE("creating new apartment, model=%ld\n", model); - - apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt)); - apt->tid = GetCurrentThreadId(); - DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), - GetCurrentProcess(), &apt->thread, - THREAD_ALL_ACCESS, FALSE, 0); - - list_init(&apt->proxies); - list_init(&apt->stubmgrs); - apt->ipidc = 0; - apt->refs = 1; - apt->remunk_exported = FALSE; - apt->oidc = 1; - InitializeCriticalSection(&apt->cs); - DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment"); - - apt->model = model; - - if (model & COINIT_APARTMENTTHREADED) - { - /* FIXME: should be randomly generated by in an RPC call to rpcss */ - apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId(); - apt->win = CreateWindowW(wszAptWinClass, NULL, 0, - 0, 0, 0, 0, - 0, 0, OLE32_hInstance, NULL); - } - else - { - /* FIXME: should be randomly generated by in an RPC call to rpcss */ - apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe; - } - - TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid)); - - /* the locking here is not currently needed for the MTA case, but it - * doesn't hurt and makes the code simpler */ - EnterCriticalSection(&csApartment); - list_add_head(&apts, &apt->entry); - LeaveCriticalSection(&csApartment); - - return apt; -} - -/* gets and existing apartment if one exists or otherwise creates an apartment - * structure which stores OLE apartment-local information and stores a pointer - * to it in the thread-local storage */ -static APARTMENT *apartment_get_or_create(DWORD model) -{ - APARTMENT *apt = COM_CurrentApt(); - - if (!apt) - { - if (model & COINIT_APARTMENTTHREADED) - { - apt = apartment_construct(model); - COM_CurrentInfo()->apt = apt; - } - else - { - EnterCriticalSection(&csApartment); - - /* The multi-threaded apartment (MTA) contains zero or more threads interacting - * with free threaded (ie thread safe) COM objects. There is only ever one MTA - * in a process */ - if (MTA) - { - TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid)); - apartment_addref(MTA); - } - else - MTA = apartment_construct(model); - - apt = MTA; - COM_CurrentInfo()->apt = apt; - - LeaveCriticalSection(&csApartment); - } - } - - return apt; -} - -DWORD apartment_addref(struct apartment *apt) -{ - DWORD refs = InterlockedIncrement(&apt->refs); - TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1); - return refs; -} - -DWORD apartment_release(struct apartment *apt) -{ - DWORD ret; - - EnterCriticalSection(&csApartment); - - ret = InterlockedDecrement(&apt->refs); - TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret); - /* destruction stuff that needs to happen under csApartment CS */ - if (ret == 0) - { - if (apt == MTA) MTA = NULL; - list_remove(&apt->entry); - } - - LeaveCriticalSection(&csApartment); - - if (ret == 0) - { - struct list *cursor, *cursor2; - - TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid)); - - /* no locking is needed for this apartment, because no other thread - * can access it at this point */ - - apartment_disconnectproxies(apt); - - if (apt->win) DestroyWindow(apt->win); - - LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs) - { - struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry); - /* release the implicit reference given by the fact that the - * stub has external references (it must do since it is in the - * stub manager list in the apartment and all non-apartment users - * must have a ref on the apartment and so it cannot be destroyed). - */ - stub_manager_int_release(stubmgr); - } - - /* if this assert fires, then another thread took a reference to a - * stub manager without taking a reference to the containing - * apartment, which it must do. */ - assert(list_empty(&apt->stubmgrs)); - - if (apt->filter) IUnknown_Release(apt->filter); - - DEBUG_CLEAR_CRITSEC_NAME(&apt->cs); - DeleteCriticalSection(&apt->cs); - CloseHandle(apt->thread); - - HeapFree(GetProcessHeap(), 0, apt); - } - - return ret; -} - -/* The given OXID must be local to this process: - * - * The ref parameter is here mostly to ensure people remember that - * they get one, you should normally take a ref for thread safety. - */ -APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref) -{ - APARTMENT *result = NULL; - struct list *cursor; - - EnterCriticalSection(&csApartment); - LIST_FOR_EACH( cursor, &apts ) - { - struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry ); - if (apt->oxid == oxid) - { - result = apt; - if (ref) apartment_addref(result); - break; - } - } - LeaveCriticalSection(&csApartment); - - return result; -} - -/* gets the apartment which has a given creator thread ID. The caller must - * release the reference from the apartment as soon as the apartment pointer - * is no longer required. */ -APARTMENT *apartment_findfromtid(DWORD tid) -{ - APARTMENT *result = NULL; - struct list *cursor; - - EnterCriticalSection(&csApartment); - LIST_FOR_EACH( cursor, &apts ) - { - struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry ); - if (apt->tid == tid) - { - result = apt; - apartment_addref(result); - break; - } - } - LeaveCriticalSection(&csApartment); - - return result; -} - -static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) - { - case DM_EXECUTERPC: - return RPC_ExecuteCall((struct dispatch_params *)lParam); - default: - return DefWindowProcW(hWnd, msg, wParam, lParam); - } -} - -/***************************************************************************** - * This section contains OpenDllList implemantation - */ - -static void COMPOBJ_DLLList_Add(HANDLE hLibrary) -{ - OpenDll *ptr; - OpenDll *tmp; - - TRACE("\n"); - - EnterCriticalSection( &csOpenDllList ); - - if (openDllList == NULL) { - /* empty list -- add first node */ - openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll)); - openDllList->hLibrary=hLibrary; - openDllList->next = NULL; - } else { - /* search for this dll */ - int found = FALSE; - for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) { - if (ptr->hLibrary == hLibrary) { - found = TRUE; - break; - } - } - if (!found) { - /* dll not found, add it */ - tmp = openDllList; - openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll)); - openDllList->hLibrary = hLibrary; - openDllList->next = tmp; - } - } - - LeaveCriticalSection( &csOpenDllList ); -} - -static void COMPOBJ_DllList_FreeUnused(int Timeout) -{ - OpenDll *curr, *next, *prev = NULL; - typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void); - DllCanUnloadNowFunc DllCanUnloadNow; - - TRACE("\n"); - - EnterCriticalSection( &csOpenDllList ); - - for (curr = openDllList; curr != NULL; ) { - DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow"); - - if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) { - next = curr->next; - - TRACE("freeing %p\n", curr->hLibrary); - FreeLibrary(curr->hLibrary); - - HeapFree(GetProcessHeap(), 0, curr); - if (curr == openDllList) { - openDllList = next; - } else { - prev->next = next; - } - - curr = next; - } else { - prev = curr; - curr = curr->next; - } - } - - LeaveCriticalSection( &csOpenDllList ); -} - -/****************************************************************************** - * CoBuildVersion [OLE32.@] - * CoBuildVersion [COMPOBJ.1] - * - * Gets the build version of the DLL. - * - * PARAMS - * - * RETURNS - * Current build version, hiword is majornumber, loword is minornumber - */ -DWORD WINAPI CoBuildVersion(void) -{ - TRACE("Returning version %d, build %d.\n", rmm, rup); - return (rmm<<16)+rup; -} - -/****************************************************************************** - * CoInitialize [OLE32.@] - * - * Initializes the COM libraries by calling CoInitializeEx with - * COINIT_APARTMENTTHREADED, ie it enters a STA thread. - * - * PARAMS - * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL). - * - * RETURNS - * Success: S_OK if not already initialized, S_FALSE otherwise. - * Failure: HRESULT code. - * - * SEE ALSO - * CoInitializeEx - */ -HRESULT WINAPI CoInitialize(LPVOID lpReserved) -{ - /* - * Just delegate to the newer method. - */ - return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED); -} - -/****************************************************************************** - * CoInitializeEx [OLE32.@] - * - * Initializes the COM libraries. - * - * PARAMS - * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL). - * dwCoInit [I] One or more flags from the COINIT enumeration. See notes. - * - * RETURNS - * S_OK if successful, - * S_FALSE if this function was called already. - * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another - * threading model. - * - * NOTES - * - * The behavior used to set the IMalloc used for memory management is - * obsolete. - * The dwCoInit parameter must specify of of the following apartment - * threading models: - *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA). - *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA). - * The parameter may also specify zero or more of the following flags: - *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support. - *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed. - * - * SEE ALSO - * CoUninitialize - */ -HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit) -{ - HRESULT hr = S_OK; - APARTMENT *apt; - - TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit); - - if (lpReserved!=NULL) - { - ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved); - } - - /* - * Check the lock count. If this is the first time going through the initialize - * process, we have to initialize the libraries. - * - * And crank-up that lock count. - */ - if (InterlockedExchangeAdd(&s_COMLockCount,1)==0) - { - /* - * Initialize the various COM libraries and data structures. - */ - TRACE("() - Initializing the COM libraries\n"); - - /* we may need to defer this until after apartment initialisation */ - RunningObjectTableImpl_Initialize(); - } - - if (!(apt = COM_CurrentInfo()->apt)) - { - apt = apartment_get_or_create(dwCoInit); - if (!apt) return E_OUTOFMEMORY; - } - else if (dwCoInit != apt->model) - { - /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine - code then we are probably using the wrong threading model to implement that API. */ - ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit); - return RPC_E_CHANGED_MODE; - } - else - hr = S_FALSE; - - COM_CurrentInfo()->inits++; - - return hr; -} - -/* On COM finalization for a STA thread, the message queue is flushed to ensure no - pending RPCs are ignored. Non-COM messages are discarded at this point. - */ -static void COM_FlushMessageQueue(void) -{ - MSG message; - APARTMENT *apt = COM_CurrentApt(); - - if (!apt || !apt->win) return; - - TRACE("Flushing STA message queue\n"); - - while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE)) - { - if (message.hwnd != apt->win) - { - WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd); - continue; - } - - TranslateMessage(&message); - DispatchMessageA(&message); - } -} - -/*********************************************************************** - * CoUninitialize [OLE32.@] - * - * This method will decrement the refcount on the current apartment, freeing - * the resources associated with it if it is the last thread in the apartment. - * If the last apartment is freed, the function will additionally release - * any COM resources associated with the process. - * - * PARAMS - * - * RETURNS - * Nothing. - * - * SEE ALSO - * CoInitializeEx - */ -void WINAPI CoUninitialize(void) -{ - struct oletls * info = COM_CurrentInfo(); - LONG lCOMRefCnt; - - TRACE("()\n"); - - /* will only happen on OOM */ - if (!info) return; - - /* sanity check */ - if (!info->inits) - { - ERR("Mismatched CoUninitialize\n"); - return; - } - - if (!--info->inits) - { - apartment_release(info->apt); - info->apt = NULL; - } - - /* - * Decrease the reference count. - * If we are back to 0 locks on the COM library, make sure we free - * all the associated data structures. - */ - lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1); - if (lCOMRefCnt==1) - { - TRACE("() - Releasing the COM libraries\n"); - - RunningObjectTableImpl_UnInitialize(); - - /* Release the references to the registered class objects */ - COM_RevokeAllClasses(); - - /* This will free the loaded COM Dlls */ - CoFreeAllLibraries(); - - /* This ensures we deal with any pending RPCs */ - COM_FlushMessageQueue(); - } - else if (lCOMRefCnt<1) { - ERR( "CoUninitialize() - not CoInitialized.\n" ); - InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */ - } -} - -/****************************************************************************** - * CoDisconnectObject [OLE32.@] - * CoDisconnectObject [COMPOBJ.15] - * - * Disconnects all connections to this object from remote processes. Dispatches - * pending RPCs while blocking new RPCs from occurring, and then calls - * IMarshal::DisconnectObject on the given object. - * - * Typically called when the object server is forced to shut down, for instance by - * the user. - * - * PARAMS - * lpUnk [I] The object whose stub should be disconnected. - * reserved [I] Reserved. Should be set to 0. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - * - * SEE ALSO - * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal - */ -HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved ) -{ - HRESULT hr; - IMarshal *marshal; - APARTMENT *apt; - - TRACE("(%p, 0x%08lx)\n", lpUnk, reserved); - - hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal); - if (hr == S_OK) - { - hr = IMarshal_DisconnectObject(marshal, reserved); - IMarshal_Release(marshal); - return hr; - } - - apt = COM_CurrentApt(); - if (!apt) - return CO_E_NOTINITIALIZED; - - apartment_disconnectobject(apt, lpUnk); - - /* Note: native is pretty broken here because it just silently - * fails, without returning an appropriate error code if the object was - * not found, making apps think that the object was disconnected, when - * it actually wasn't */ - - return S_OK; -} - -/****************************************************************************** - * CoCreateGuid [OLE32.@] - * - * Simply forwards to UuidCreate in RPCRT4. - * - * PARAMS - * pguid [O] Points to the GUID to initialize. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - * - * SEE ALSO - * UuidCreate - */ -HRESULT WINAPI CoCreateGuid(GUID *pguid) -{ - return UuidCreate(pguid); -} - -/****************************************************************************** - * CLSIDFromString [OLE32.@] - * IIDFromString [OLE32.@] - * - * Converts a unique identifier from its string representation into - * the GUID struct. - * - * PARAMS - * idstr [I] The string representation of the GUID. - * id [O] GUID converted from the string. - * - * RETURNS - * S_OK on success - * CO_E_CLASSSTRING if idstr is not a valid CLSID - * - * BUGS - * - * In Windows, if idstr is not a valid CLSID string then it gets - * treated as a ProgID. Wine currently doesn't do this. If idstr is - * NULL it's treated as an all-zero GUID. - * - * SEE ALSO - * StringFromCLSID - */ -HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id) -{ - const BYTE *s = (const BYTE *) idstr; - int i; - BYTE table[256]; - - if (!s) - s = "{00000000-0000-0000-0000-000000000000}"; - else { /* validate the CLSID string */ - - if (strlen(s) != 38) - return CO_E_CLASSSTRING; - - if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}')) - return CO_E_CLASSSTRING; - - 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')))) - return CO_E_CLASSSTRING; - } - } - - 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; -} - -/*****************************************************************************/ - -HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id ) -{ - char xid[40]; - HRESULT ret; - - if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL )) - return CO_E_CLASSSTRING; - - - ret = __CLSIDFromStringA(xid,id); - if(ret != S_OK) { /* It appears a ProgID is also valid */ - ret = CLSIDFromProgID(idstr, id); - } - return ret; -} - -/* Converts a GUID into the respective string representation. */ -HRESULT WINE_StringFromCLSID( - const CLSID *id, /* [in] GUID to be converted */ - LPSTR idstr /* [out] pointer to buffer to contain converted guid */ -) { - static const char *hex = "0123456789ABCDEF"; - char *s; - int i; - - if (!id) - { ERR("called with id=Null\n"); - *idstr = 0x00; - return E_FAIL; - } - - sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-", - id->Data1, id->Data2, id->Data3, - id->Data4[0], id->Data4[1]); - s = &idstr[25]; - - /* 6 hex bytes */ - for (i = 2; i < 8; i++) { - *s++ = hex[id->Data4[i]>>4]; - *s++ = hex[id->Data4[i] & 0xf]; - } - - *s++ = '}'; - *s++ = '\0'; - - TRACE("%p->%s\n", id, idstr); - - return S_OK; -} - - -/****************************************************************************** - * StringFromCLSID [OLE32.@] - * StringFromIID [OLE32.@] - * - * Converts a GUID into the respective string representation. - * The target string is allocated using the OLE IMalloc. - * - * PARAMS - * id [I] the GUID to be converted. - * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string. - * - * RETURNS - * S_OK - * E_FAIL - * - * SEE ALSO - * StringFromGUID2, CLSIDFromString - */ -HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr) -{ - char buf[80]; - HRESULT ret; - LPMALLOC mllc; - - if ((ret = CoGetMalloc(0,&mllc))) - return ret; - - ret=WINE_StringFromCLSID(id,buf); - if (!ret) { - DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 ); - *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len ); - } - return ret; -} - -/****************************************************************************** - * StringFromGUID2 [OLE32.@] - * StringFromGUID2 [COMPOBJ.76] - * - * Modified version of StringFromCLSID that allows you to specify max - * buffer size. - * - * PARAMS - * id [I] GUID to convert to string. - * str [O] Buffer where the result will be stored. - * cmax [I] Size of the buffer in characters. - * - * RETURNS - * Success: The length of the resulting string in characters. - * Failure: 0. - */ -INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax) -{ - char xguid[80]; - - if (WINE_StringFromCLSID(id,xguid)) - return 0; - return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax ); -} - -/****************************************************************************** - * ProgIDFromCLSID [OLE32.@] - * - * Converts a class id into the respective program ID. - * - * PARAMS - * clsid [I] Class ID, as found in registry. - * lplpszProgID [O] Associated ProgID. - * - * RETURNS - * S_OK - * E_OUTOFMEMORY - * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID - */ -HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID) -{ - char strCLSID[50], *buf, *buf2; - DWORD buf2len; - HKEY xhkey; - LPMALLOC mllc; - HRESULT ret = S_OK; - - WINE_StringFromCLSID(clsid, strCLSID); - - buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14); - sprintf(buf,"CLSID\\%s\\ProgID", strCLSID); - if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey)) - ret = REGDB_E_CLASSNOTREG; - - HeapFree(GetProcessHeap(), 0, buf); - - if (ret == S_OK) - { - buf2 = HeapAlloc(GetProcessHeap(), 0, 255); - buf2len = 255; - if (RegQueryValueA(xhkey, NULL, buf2, &buf2len)) - ret = REGDB_E_CLASSNOTREG; - - if (ret == S_OK) - { - if (CoGetMalloc(0,&mllc)) - ret = E_OUTOFMEMORY; - else - { - DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 ); - *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len ); - } - } - HeapFree(GetProcessHeap(), 0, buf2); - RegCloseKey(xhkey); - } - - return ret; -} - -/****************************************************************************** - * 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]; - DWORD buf2len; - HRESULT err; - HKEY xhkey; - - buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8); - sprintf(buf,"%s\\CLSID",progid); - if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) { - HeapFree(GetProcessHeap(),0,buf); - return CO_E_CLASSSTRING; - } - HeapFree(GetProcessHeap(),0,buf); - buf2len = sizeof(buf2); - if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) { - RegCloseKey(xhkey); - return CO_E_CLASSSTRING; - } - RegCloseKey(xhkey); - return __CLSIDFromStringA(buf2,riid); -} - -/****************************************************************************** - * CLSIDFromProgID [OLE32.@] - * - * Converts a program id into the respective GUID. - * - * PARAMS - * progid [I] Unicode 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 CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid) -{ - static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 }; - char buf2[80]; - DWORD buf2len = sizeof(buf2); - HKEY xhkey; - - WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) ); - strcpyW( buf, progid ); - strcatW( buf, clsidW ); - if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey)) - { - HeapFree(GetProcessHeap(),0,buf); - return CO_E_CLASSSTRING; - } - HeapFree(GetProcessHeap(),0,buf); - - if (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) - { - RegCloseKey(xhkey); - return CO_E_CLASSSTRING; - } - RegCloseKey(xhkey); - return __CLSIDFromStringA(buf2,riid); -} - - - -/***************************************************************************** - * CoGetPSClsid [OLE32.@] - * - * Retrieves the CLSID of the proxy/stub factory that implements - * IPSFactoryBuffer for the specified interface. - * - * PARAMS - * riid [I] Interface whose proxy/stub CLSID is to be returned. - * pclsid [O] Where to store returned proxy/stub CLSID. - * - * RETURNS - * S_OK - * E_OUTOFMEMORY - * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed - * - * NOTES - * - * The standard marshaller activates the object with the CLSID - * returned and uses the CreateProxy and CreateStub methods on its - * IPSFactoryBuffer interface to construct the proxies and stubs for a - * given object. - * - * CoGetPSClsid determines this CLSID by searching the - * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32 - * in the registry and any interface id registered by - * CoRegisterPSClsid within the current process. - * - * BUGS - * - * We only search the registry, not ids registered with - * CoRegisterPSClsid. - * Also, native returns S_OK for interfaces with a key in HKCR\Interface, but - * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be - * considered a bug in native unless an application depends on this (unlikely). - */ -HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid) -{ - char *buf, buf2[40]; - DWORD buf2len; - HKEY xhkey; - - TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid); - - /* Get the input iid as a string */ - WINE_StringFromCLSID(riid, buf2); - /* Allocate memory for the registry key we will construct. - (length of iid string plus constant length of static text */ - buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27); - if (buf == NULL) - return E_OUTOFMEMORY; - - /* Construct the registry key we want */ - sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2); - - /* Open the key.. */ - if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey)) - { - WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid)); - HeapFree(GetProcessHeap(),0,buf); - return REGDB_E_IIDNOTREG; - } - HeapFree(GetProcessHeap(),0,buf); - - /* ... Once we have the key, query the registry to get the - value of CLSID as a string, and convert it into a - proper CLSID structure to be passed back to the app */ - buf2len = sizeof(buf2); - if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) ) - { - RegCloseKey(xhkey); - return REGDB_E_IIDNOTREG; - } - RegCloseKey(xhkey); - - /* We have the CLSid we want back from the registry as a string, so - lets convert it into a CLSID structure */ - if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR) - return REGDB_E_IIDNOTREG; - - TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid)); - return S_OK; -} - - - -/*********************************************************************** - * WriteClassStm (OLE32.@) - * - * Writes a CLSID to a stream. - * - * PARAMS - * pStm [I] Stream to write to. - * rclsid [I] CLSID to write. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - */ -HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid) -{ - TRACE("(%p,%p)\n",pStm,rclsid); - - if (rclsid==NULL) - return E_INVALIDARG; - - return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL); -} - -/*********************************************************************** - * ReadClassStm (OLE32.@) - * - * Reads a CLSID from a stream. - * - * PARAMS - * pStm [I] Stream to read from. - * rclsid [O] CLSID to read. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - */ -HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid) -{ - ULONG nbByte; - HRESULT res; - - TRACE("(%p,%p)\n",pStm,pclsid); - - if (pclsid==NULL) - return E_INVALIDARG; - - res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte); - - if (FAILED(res)) - return res; - - if (nbByte != sizeof(CLSID)) - return S_FALSE; - else - return S_OK; -} - - -/*** - * COM_GetRegisteredClassObject - * - * This internal method is used to scan the registered class list to - * find a class object. - * - * Params: - * rclsid Class ID of the class to find. - * dwClsContext Class context to match. - * ppv [out] returns a pointer to the class object. Complying - * to normal COM usage, this method will increase the - * reference count on this object. - */ -static HRESULT COM_GetRegisteredClassObject( - REFCLSID rclsid, - DWORD dwClsContext, - LPUNKNOWN* ppUnk) -{ - HRESULT hr = S_FALSE; - RegisteredClass* curClass; - - EnterCriticalSection( &csRegisteredClassList ); - - /* - * Sanity check - */ - assert(ppUnk!=0); - - /* - * Iterate through the whole list and try to match the class ID. - */ - curClass = firstRegisteredClass; - - while (curClass != 0) - { - /* - * Check if we have a match on the class ID. - */ - if (IsEqualGUID(&(curClass->classIdentifier), rclsid)) - { - /* - * Since we don't do out-of process or DCOM just right away, let's ignore the - * class context. - */ - - /* - * We have a match, return the pointer to the class object. - */ - *ppUnk = curClass->classObject; - - IUnknown_AddRef(curClass->classObject); - - hr = S_OK; - goto end; - } - - /* - * Step to the next class in the list. - */ - curClass = curClass->nextClass; - } - -end: - LeaveCriticalSection( &csRegisteredClassList ); - /* - * If we get to here, we haven't found our class. - */ - return hr; -} - -/****************************************************************************** - * CoRegisterClassObject [OLE32.@] - * - * Registers the class object for a given class ID. Servers housed in EXE - * files use this method instead of exporting DllGetClassObject to allow - * other code to connect to their objects. - * - * PARAMS - * rclsid [I] CLSID of the object to register. - * pUnk [I] IUnknown of the object. - * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable. - * flags [I] REGCLS flags indicating how connections are made. - * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject. - * - * RETURNS - * S_OK on success, - * E_INVALIDARG if lpdwRegister or pUnk are NULL, - * CO_E_OBJISREG if the object is already registered. We should not return this. - * - * SEE ALSO - * CoRevokeClassObject, CoGetClassObject - * - * BUGS - * MSDN claims that multiple interface registrations are legal, but we - * can't do that with our current implementation. - */ -HRESULT WINAPI CoRegisterClassObject( - REFCLSID rclsid, - LPUNKNOWN pUnk, - DWORD dwClsContext, - DWORD flags, - LPDWORD lpdwRegister) -{ - RegisteredClass* newClass; - LPUNKNOWN foundObject; - HRESULT hr; - - TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n", - debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister); - - if ( (lpdwRegister==0) || (pUnk==0) ) - return E_INVALIDARG; - - if (!COM_CurrentApt()) - { - ERR("COM was not initialized\n"); - return CO_E_NOTINITIALIZED; - } - - *lpdwRegister = 0; - - /* - * First, check if the class is already registered. - * If it is, this should cause an error. - */ - hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject); - if (hr == S_OK) { - IUnknown_Release(foundObject); - return CO_E_OBJISREG; - } - - newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass)); - if ( newClass == NULL ) - return E_OUTOFMEMORY; - - EnterCriticalSection( &csRegisteredClassList ); - - newClass->classIdentifier = *rclsid; - newClass->runContext = dwClsContext; - newClass->connectFlags = flags; - /* - * Use the address of the chain node as the cookie since we are sure it's - * unique. FIXME: not on 64-bit platforms. - */ - newClass->dwCookie = (DWORD)newClass; - newClass->nextClass = firstRegisteredClass; - - /* - * Since we're making a copy of the object pointer, we have to increase its - * reference count. - */ - newClass->classObject = pUnk; - IUnknown_AddRef(newClass->classObject); - - firstRegisteredClass = newClass; - LeaveCriticalSection( &csRegisteredClassList ); - - *lpdwRegister = newClass->dwCookie; - - if (dwClsContext & CLSCTX_LOCAL_SERVER) { - IClassFactory *classfac; - - hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory, - (LPVOID*)&classfac); - if (hr) return hr; - - hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData); - if (hr) { - FIXME("Failed to create stream on hglobal, %lx\n", hr); - IUnknown_Release(classfac); - return hr; - } - hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory, - (LPVOID)classfac, MSHCTX_LOCAL, NULL, - MSHLFLAGS_TABLESTRONG); - if (hr) { - FIXME("CoMarshalInterface failed, %lx!\n",hr); - IUnknown_Release(classfac); - return hr; - } - - IUnknown_Release(classfac); - - RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData); - } - return S_OK; -} - -/*********************************************************************** - * CoRevokeClassObject [OLE32.@] - * - * Removes a class object from the class registry. - * - * PARAMS - * dwRegister [I] Cookie returned from CoRegisterClassObject(). - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - * - * SEE ALSO - * CoRegisterClassObject - */ -HRESULT WINAPI CoRevokeClassObject( - DWORD dwRegister) -{ - HRESULT hr = E_INVALIDARG; - RegisteredClass** prevClassLink; - RegisteredClass* curClass; - - TRACE("(%08lx)\n",dwRegister); - - EnterCriticalSection( &csRegisteredClassList ); - - /* - * Iterate through the whole list and try to match the cookie. - */ - curClass = firstRegisteredClass; - prevClassLink = &firstRegisteredClass; - - while (curClass != 0) - { - /* - * Check if we have a match on the cookie. - */ - if (curClass->dwCookie == dwRegister) - { - /* - * Remove the class from the chain. - */ - *prevClassLink = curClass->nextClass; - - /* - * Release the reference to the class object. - */ - IUnknown_Release(curClass->classObject); - - if (curClass->pMarshaledData) - { - LARGE_INTEGER zero; - memset(&zero, 0, sizeof(zero)); - /* FIXME: stop local server thread */ - IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL); - CoReleaseMarshalData(curClass->pMarshaledData); - } - - /* - * Free the memory used by the chain node. - */ - HeapFree(GetProcessHeap(), 0, curClass); - - hr = S_OK; - goto end; - } - - /* - * Step to the next class in the list. - */ - prevClassLink = &(curClass->nextClass); - curClass = curClass->nextClass; - } - -end: - LeaveCriticalSection( &csRegisteredClassList ); - /* - * If we get to here, we haven't found our class. - */ - return hr; -} - -/*********************************************************************** - * compobj_RegReadPath [internal] - * - * Reads a registry value and expands it when necessary - */ -static HRESULT -compobj_RegReadPath(char * keyname, char * valuename, char * dst, DWORD dstlen) -{ - HRESULT hres; - HKEY key; - DWORD keytype; - char src[MAX_PATH]; - DWORD dwLength = dstlen; - - if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) { - if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) { - if (keytype == REG_EXPAND_SZ) { - if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA; - } else { - lstrcpynA(dst, src, dstlen); - } - } - RegCloseKey (key); - } - return hres; -} - -/*********************************************************************** - * CoGetClassObject [COMPOBJ.7] - * CoGetClassObject [OLE32.@] - * - * FIXME. If request allows of several options and there is a failure - * with one (other than not being registered) do we try the - * others or return failure? (E.g. inprocess is registered but - * the DLL is not found but the server version works) - */ -HRESULT WINAPI CoGetClassObject( - REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo, - REFIID iid, LPVOID *ppv -) { - LPUNKNOWN regClassObject; - HRESULT hres = E_UNEXPECTED; - char xclsid[80]; - HINSTANCE hLibrary; - typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv); - DllGetClassObjectFunc DllGetClassObject; - - WINE_StringFromCLSID((LPCLSID)rclsid,xclsid); - - TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid)); - - if (pServerInfo) { - FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName)); - FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo); - } - - /* - * First, try and see if we can't match the class ID with one of the - * registered classes. - */ - if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject)) - { - /* - * Get the required interface from the retrieved pointer. - */ - hres = IUnknown_QueryInterface(regClassObject, iid, ppv); - - /* - * Since QI got another reference on the pointer, we want to release the - * one we already have. If QI was unsuccessful, this will release the object. This - * is good since we are not returning it in the "out" parameter. - */ - IUnknown_Release(regClassObject); - - return hres; - } - - /* first try: in-process */ - if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) { - char keyname[MAX_PATH]; - char dllpath[MAX_PATH+1]; - - sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid); - - if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) { - /* failure: CLSID is not found in registry */ - WARN("class %s not registered inproc\n", xclsid); - hres = REGDB_E_CLASSNOTREG; - } else { - if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) { - /* failure: DLL could not be loaded */ - ERR("couldn't load InprocServer32 dll %s\n", dllpath); - hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */ - } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) { - /* failure: the dll did not export DllGetClassObject */ - ERR("couldn't find function DllGetClassObject in %s\n", dllpath); - FreeLibrary( hLibrary ); - hres = CO_E_DLLNOTFOUND; - } else { - /* OK: get the ClassObject */ - COMPOBJ_DLLList_Add( hLibrary ); - return DllGetClassObject(rclsid, iid, ppv); - } - } - } - - /* Next try out of process */ - if (CLSCTX_LOCAL_SERVER & dwClsContext) - { - return RPC_GetLocalClassObject(rclsid,iid,ppv); - } - - /* Finally try remote: this requires networked DCOM (a lot of work) */ - if (CLSCTX_REMOTE_SERVER & dwClsContext) - { - FIXME ("CLSCTX_REMOTE_SERVER not supported\n"); - hres = E_NOINTERFACE; - } - - return hres; -} -/*********************************************************************** - * CoResumeClassObjects (OLE32.@) - * - * Resumes all class objects registered with REGCLS_SUSPENDED. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - */ -HRESULT WINAPI CoResumeClassObjects(void) -{ - FIXME("stub\n"); - return S_OK; -} - -/*********************************************************************** - * GetClassFile (OLE32.@) - * - * This function supplies the CLSID associated with the given filename. - */ -HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid) -{ - IStorage *pstg=0; - HRESULT res; - int nbElm, length, i; - LONG sizeProgId; - LPOLESTR *pathDec=0,absFile=0,progId=0; - LPWSTR extension; - static const WCHAR bkslashW[] = {'\\',0}; - static const WCHAR dotW[] = {'.',0}; - - TRACE("%s, %p\n", debugstr_w(filePathName), pclsid); - - /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/ - if((StgIsStorageFile(filePathName))==S_OK){ - - res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg); - - if (SUCCEEDED(res)) - res=ReadClassStg(pstg,pclsid); - - IStorage_Release(pstg); - - return res; - } - /* if the file is not a storage object then attemps to match various bits in the file against a - pattern in the registry. this case is not frequently used ! so I present only the psodocode for - this case - - for(i=0;i<nFileTypes;i++) - - for(i=0;j<nPatternsForType;j++){ - - PATTERN pat; - HANDLE hFile; - - pat=ReadPatternFromRegistry(i,j); - hFile=CreateFileW(filePathName,,,,,,hFile); - SetFilePosition(hFile,pat.offset); - ReadFile(hFile,buf,pat.size,&r,NULL); - if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){ - - *pclsid=ReadCLSIDFromRegistry(i); - return S_OK; - } - } - */ - - /* if the above strategies fail then search for the extension key in the registry */ - - /* get the last element (absolute file) in the path name */ - nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec); - absFile=pathDec[nbElm-1]; - - /* failed if the path represente a directory and not an absolute file name*/ - if (!lstrcmpW(absFile, bkslashW)) - return MK_E_INVALIDEXTENSION; - - /* get the extension of the file */ - extension = NULL; - length=lstrlenW(absFile); - for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--) - /* nothing */; - - if (!extension || !lstrcmpW(extension, dotW)) - return MK_E_INVALIDEXTENSION; - - res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId); - - /* get the progId associated to the extension */ - progId = CoTaskMemAlloc(sizeProgId); - res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId); - - if (res==ERROR_SUCCESS) - /* return the clsid associated to the progId */ - res= CLSIDFromProgID(progId,pclsid); - - for(i=0; pathDec[i]!=NULL;i++) - CoTaskMemFree(pathDec[i]); - CoTaskMemFree(pathDec); - - CoTaskMemFree(progId); - - if (res==ERROR_SUCCESS) - return res; - - return MK_E_INVALIDEXTENSION; -} -/*********************************************************************** - * CoCreateInstance [COMPOBJ.13] - * CoCreateInstance [OLE32.@] - */ -HRESULT WINAPI CoCreateInstance( - REFCLSID rclsid, - LPUNKNOWN pUnkOuter, - DWORD dwClsContext, - REFIID iid, - LPVOID *ppv) -{ - HRESULT hres; - LPCLASSFACTORY lpclf = 0; - - if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED; - - /* - * Sanity check - */ - if (ppv==0) - return E_POINTER; - - /* - * Initialize the "out" parameter - */ - *ppv = 0; - - /* - * The Standard Global Interface Table (GIT) object is a process-wide singleton. - * Rather than create a class factory, we can just check for it here - */ - if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) { - if (StdGlobalInterfaceTableInstance == NULL) - StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct(); - hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv); - if (hres) return hres; - - TRACE("Retrieved GIT (%p)\n", *ppv); - return S_OK; - } - - /* - * Get a class factory to construct the object we want. - */ - hres = CoGetClassObject(rclsid, - dwClsContext, - NULL, - &IID_IClassFactory, - (LPVOID)&lpclf); - - if (FAILED(hres)) { - FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n", - debugstr_guid(rclsid),hres); - return hres; - } - - /* - * Create the object and don't forget to release the factory - */ - hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv); - IClassFactory_Release(lpclf); - if(FAILED(hres)) - FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n", - debugstr_guid(iid), debugstr_guid(rclsid),hres); - - return hres; -} - -/*********************************************************************** - * CoCreateInstanceEx [OLE32.@] - */ -HRESULT WINAPI CoCreateInstanceEx( - REFCLSID rclsid, - LPUNKNOWN pUnkOuter, - DWORD dwClsContext, - COSERVERINFO* pServerInfo, - ULONG cmq, - MULTI_QI* pResults) -{ - IUnknown* pUnk = NULL; - HRESULT hr; - ULONG index; - ULONG successCount = 0; - - /* - * Sanity check - */ - if ( (cmq==0) || (pResults==NULL)) - return E_INVALIDARG; - - if (pServerInfo!=NULL) - FIXME("() non-NULL pServerInfo not supported!\n"); - - /* - * Initialize all the "out" parameters. - */ - for (index = 0; index < cmq; index++) - { - pResults[index].pItf = NULL; - pResults[index].hr = E_NOINTERFACE; - } - - /* - * Get the object and get its IUnknown pointer. - */ - hr = CoCreateInstance(rclsid, - pUnkOuter, - dwClsContext, - &IID_IUnknown, - (VOID**)&pUnk); - - if (hr) - return hr; - - /* - * Then, query for all the interfaces requested. - */ - for (index = 0; index < cmq; index++) - { - pResults[index].hr = IUnknown_QueryInterface(pUnk, - pResults[index].pIID, - (VOID**)&(pResults[index].pItf)); - - if (pResults[index].hr == S_OK) - successCount++; - } - - /* - * Release our temporary unknown pointer. - */ - IUnknown_Release(pUnk); - - if (successCount == 0) - return E_NOINTERFACE; - - if (successCount!=cmq) - return CO_S_NOTALLINTERFACES; - - return S_OK; -} - -/*********************************************************************** - * CoLoadLibrary (OLE32.@) - * - * Loads a library. - * - * PARAMS - * lpszLibName [I] Path to library. - * bAutoFree [I] Whether the library should automatically be freed. - * - * RETURNS - * Success: Handle to loaded library. - * Failure: NULL. - * - * SEE ALSO - * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries - */ -HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree) -{ - TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree); - - return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH); -} - -/*********************************************************************** - * CoFreeLibrary [OLE32.@] - * - * Unloads a library from memory. - * - * PARAMS - * hLibrary [I] Handle to library to unload. - * - * RETURNS - * Nothing - * - * SEE ALSO - * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries - */ -void WINAPI CoFreeLibrary(HINSTANCE hLibrary) -{ - FreeLibrary(hLibrary); -} - - -/*********************************************************************** - * CoFreeAllLibraries [OLE32.@] - * - * Function for backwards compatibility only. Does nothing. - * - * RETURNS - * Nothing. - * - * SEE ALSO - * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries - */ -void WINAPI CoFreeAllLibraries(void) -{ - /* NOP */ -} - - -/*********************************************************************** - * CoFreeUnusedLibraries [OLE32.@] - * CoFreeUnusedLibraries [COMPOBJ.17] - * - * Frees any unused libraries. Unused are identified as those that return - * S_OK from their DllCanUnloadNow function. - * - * RETURNS - * Nothing. - * - * SEE ALSO - * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary - */ -void WINAPI CoFreeUnusedLibraries(void) -{ - /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route - * through the main apartment's thread to call DllCanUnloadNow */ - COMPOBJ_DllList_FreeUnused(0); -} - -/*********************************************************************** - * CoFileTimeNow [OLE32.@] - * CoFileTimeNow [COMPOBJ.82] - * - * Retrieves the current time in FILETIME format. - * - * PARAMS - * lpFileTime [O] The current time. - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime ) -{ - GetSystemTimeAsFileTime( lpFileTime ); - return S_OK; -} - -static void COM_RevokeAllClasses() -{ - EnterCriticalSection( &csRegisteredClassList ); - - while (firstRegisteredClass!=0) - { - CoRevokeClassObject(firstRegisteredClass->dwCookie); - } - - LeaveCriticalSection( &csRegisteredClassList ); -} - -/****************************************************************************** - * CoLockObjectExternal [OLE32.@] - * - * Increments or decrements the external reference count of a stub object. - * - * PARAMS - * pUnk [I] Stub object. - * fLock [I] If TRUE then increments the external ref-count, - * otherwise decrements. - * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of - * calling CoDisconnectObject. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - */ -HRESULT WINAPI CoLockObjectExternal( - LPUNKNOWN pUnk, - BOOL fLock, - BOOL fLastUnlockReleases) -{ - struct stub_manager *stubmgr; - struct apartment *apt; - - TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n", - pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE"); - - apt = COM_CurrentApt(); - if (!apt) return CO_E_NOTINITIALIZED; - - stubmgr = get_stub_manager_from_object(apt, pUnk); - - if (stubmgr) - { - if (fLock) - stub_manager_ext_addref(stubmgr, 1); - else - stub_manager_ext_release(stubmgr, 1); - - stub_manager_int_release(stubmgr); - - return S_OK; - } - else - { - WARN("stub object not found %p\n", pUnk); - /* Note: native is pretty broken here because it just silently - * fails, without returning an appropriate error code, making apps - * think that the object was disconnected, when it actually wasn't */ - return S_OK; - } -} - -/*********************************************************************** - * CoInitializeWOW (OLE32.@) - * - * WOW equivalent of CoInitialize? - * - * PARAMS - * x [I] Unknown. - * y [I] Unknown. - * - * RETURNS - * Unknown. - */ -HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) -{ - FIXME("(0x%08lx,0x%08lx),stub!\n",x,y); - return 0; -} - -/*********************************************************************** - * CoGetState [OLE32.@] - * - * Retrieves the thread state object previously stored by CoSetState(). - * - * PARAMS - * ppv [I] Address where pointer to object will be stored. - * - * RETURNS - * Success: S_OK. - * Failure: E_OUTOFMEMORY. - * - * NOTES - * Crashes on all invalid ppv addresses, including NULL. - * If the function returns a non-NULL object then the caller must release its - * reference on the object when the object is no longer required. - * - * SEE ALSO - * CoSetState(). - */ -HRESULT WINAPI CoGetState(IUnknown ** ppv) -{ - struct oletls *info = COM_CurrentInfo(); - if (!info) return E_OUTOFMEMORY; - - *ppv = NULL; - - if (info->state) - { - IUnknown_AddRef(info->state); - *ppv = info->state; - TRACE("apt->state=%p\n", info->state); - } - - return S_OK; -} - -/*********************************************************************** - * CoSetState [OLE32.@] - * - * Sets the thread state object. - * - * PARAMS - * pv [I] Pointer to state object to be stored. - * - * NOTES - * The system keeps a reference on the object while the object stored. - * - * RETURNS - * Success: S_OK. - * Failure: E_OUTOFMEMORY. - */ -HRESULT WINAPI CoSetState(IUnknown * pv) -{ - struct oletls *info = COM_CurrentInfo(); - if (!info) return E_OUTOFMEMORY; - - if (pv) IUnknown_AddRef(pv); - - if (info->state) - { - TRACE("-- release %p now\n", info->state); - IUnknown_Release(info->state); - } - - info->state = pv; - - return S_OK; -} - - -/****************************************************************************** - * OleGetAutoConvert [OLE32.@] - */ -HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew) -{ - HKEY hkey = 0; - char buf[200]; - WCHAR wbuf[200]; - DWORD len; - HRESULT res = S_OK; - - sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]); - if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey)) - { - res = REGDB_E_CLASSNOTREG; - goto done; - } - len = 200; - /* we can just query for the default value of AutoConvertTo key like that, - without opening the AutoConvertTo key and querying for NULL (default) */ - if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len)) - { - res = REGDB_E_KEYMISSING; - goto done; - } - MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) ); - CLSIDFromString(wbuf,pClsidNew); -done: - if (hkey) RegCloseKey(hkey); - return res; -} - -/****************************************************************************** - * CoTreatAsClass [OLE32.@] - * - * Sets the TreatAs value of a class. - * - * PARAMS - * clsidOld [I] Class to set TreatAs value on. - * clsidNew [I] The class the clsidOld should be treated as. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - * - * SEE ALSO - * CoGetTreatAsClass - */ -HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew) -{ - HKEY hkey = 0; - char buf[47]; - char szClsidNew[39]; - HRESULT res = S_OK; - char auto_treat_as[39]; - LONG auto_treat_as_size = sizeof(auto_treat_as); - CLSID id; - - sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]); - WINE_StringFromCLSID(clsidNew, szClsidNew); - if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey)) - { - res = REGDB_E_CLASSNOTREG; - goto done; - } - if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) )) - { - if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) && - !__CLSIDFromStringA(auto_treat_as, &id)) - { - if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1)) - { - res = REGDB_E_WRITEREGDB; - goto done; - } - } - else - { - RegDeleteKeyA(hkey, "TreatAs"); - goto done; - } - } - else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1)) - { - res = REGDB_E_WRITEREGDB; - goto done; - } - -done: - if (hkey) RegCloseKey(hkey); - return res; -} - -/****************************************************************************** - * CoGetTreatAsClass [OLE32.@] - * - * Gets the TreatAs value of a class. - * - * PARAMS - * clsidOld [I] Class to get the TreatAs value of. - * clsidNew [I] The class the clsidOld should be treated as. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - * - * SEE ALSO - * CoSetTreatAsClass - */ -HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew) -{ - HKEY hkey = 0; - char buf[200], szClsidNew[200]; - HRESULT res = S_OK; - LONG len = sizeof(szClsidNew); - - FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew); - sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]); - memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */ - - if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey)) - { - res = REGDB_E_CLASSNOTREG; - goto done; - } - if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len)) - { - res = S_FALSE; - goto done; - } - res = __CLSIDFromStringA(szClsidNew,clsidNew); - if (FAILED(res)) - FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res); -done: - if (hkey) RegCloseKey(hkey); - return res; - -} - -/****************************************************************************** - * CoGetCurrentProcess [OLE32.@] - * CoGetCurrentProcess [COMPOBJ.34] - * - * Gets the current process ID. - * - * RETURNS - * The current process ID. - * - * NOTES - * Is DWORD really the correct return type for this function? - */ -DWORD WINAPI CoGetCurrentProcess(void) -{ - return GetCurrentProcessId(); -} - -/****************************************************************************** - * CoRegisterMessageFilter [OLE32.@] - * - * Registers a message filter. - * - * PARAMS - * lpMessageFilter [I] Pointer to interface. - * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - */ -HRESULT WINAPI CoRegisterMessageFilter( - LPMESSAGEFILTER lpMessageFilter, - LPMESSAGEFILTER *lplpMessageFilter) -{ - FIXME("stub\n"); - if (lplpMessageFilter) { - *lplpMessageFilter = NULL; - } - return S_OK; -} - -/*********************************************************************** - * CoIsOle1Class [OLE32.@] - * - * Determines whether the specified class an OLE v1 class. - * - * PARAMS - * clsid [I] Class to test. - * - * RETURNS - * TRUE if the class is an OLE v1 class, or FALSE otherwise. - */ -BOOL WINAPI CoIsOle1Class(REFCLSID clsid) -{ - FIXME("%s\n", debugstr_guid(clsid)); - return FALSE; -} - -/*********************************************************************** - * IsEqualGUID [OLE32.@] - * - * Compares two Unique Identifiers. - * - * PARAMS - * rguid1 [I] The first GUID to compare. - * rguid2 [I] The other GUID to compare. - * - * RETURNS - * TRUE if equal - */ -#undef IsEqualGUID -BOOL WINAPI IsEqualGUID( - REFGUID rguid1, - REFGUID rguid2) -{ - return !memcmp(rguid1,rguid2,sizeof(GUID)); -} - -/*********************************************************************** - * CoInitializeSecurity [OLE32.@] - */ -HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc, - SOLE_AUTHENTICATION_SERVICE* asAuthSvc, - void* pReserved1, DWORD dwAuthnLevel, - DWORD dwImpLevel, void* pReserved2, - DWORD dwCapabilities, void* pReserved3) -{ - FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc, - asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2, - dwCapabilities, pReserved3); - return S_OK; -} - -/*********************************************************************** - * CoSuspendClassObjects [OLE32.@] - * - * Suspends all registered class objects to prevent further requests coming in - * for those objects. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - */ -HRESULT WINAPI CoSuspendClassObjects(void) -{ - FIXME("\n"); - return S_OK; -} - -/*********************************************************************** - * CoAddRefServerProcess [OLE32.@] - * - * Helper function for incrementing the reference count of a local-server - * process. - * - * RETURNS - * New reference count. - */ -ULONG WINAPI CoAddRefServerProcess(void) -{ - FIXME("\n"); - return 2; -} - -/*********************************************************************** - * CoReleaseServerProcess [OLE32.@] - * - * Helper function for decrementing the reference count of a local-server - * process. - * - * RETURNS - * New reference count. - */ -ULONG WINAPI CoReleaseServerProcess(void) -{ - FIXME("\n"); - return 1; -} - -/*********************************************************************** - * CoIsHandlerConnected [OLE32.@] - * - * Determines whether a proxy is connected to a remote stub. - * - * PARAMS - * pUnk [I] Pointer to object that may or may not be connected. - * - * RETURNS - * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or - * FALSE otherwise. - */ -BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk) -{ - FIXME("%p\n", pUnk); - - return TRUE; -} - -/*********************************************************************** - * CoQueryProxyBlanket [OLE32.@] - * - * Retrieves the security settings being used by a proxy. - * - * PARAMS - * pProxy [I] Pointer to the proxy object. - * pAuthnSvc [O] The type of authentication service. - * pAuthzSvc [O] The type of authorization service. - * ppServerPrincName [O] Optional. The server prinicple name. - * pAuthnLevel [O] The authentication level. - * pImpLevel [O] The impersonation level. - * ppAuthInfo [O] Information specific to the authorization/authentication service. - * pCapabilities [O] Flags affecting the security behaviour. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - * - * SEE ALSO - * CoCopyProxy, CoSetProxyBlanket. - */ -HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc, - DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel, - DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities) -{ - IClientSecurity *pCliSec; - HRESULT hr; - - TRACE("%p\n", pProxy); - - hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec); - if (SUCCEEDED(hr)) - { - hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc, - pAuthzSvc, ppServerPrincName, - pAuthnLevel, pImpLevel, ppAuthInfo, - pCapabilities); - IClientSecurity_Release(pCliSec); - } - - if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr); - return hr; -} - -/*********************************************************************** - * CoSetProxyBlanket [OLE32.@] - * - * Sets the security settings for a proxy. - * - * PARAMS - * pProxy [I] Pointer to the proxy object. - * AuthnSvc [I] The type of authentication service. - * AuthzSvc [I] The type of authorization service. - * pServerPrincName [I] The server prinicple name. - * AuthnLevel [I] The authentication level. - * ImpLevel [I] The impersonation level. - * pAuthInfo [I] Information specific to the authorization/authentication service. - * Capabilities [I] Flags affecting the security behaviour. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - * - * SEE ALSO - * CoQueryProxyBlanket, CoCopyProxy. - */ -HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc, - DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel, - DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities) -{ - IClientSecurity *pCliSec; - HRESULT hr; - - TRACE("%p\n", pProxy); - - hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec); - if (SUCCEEDED(hr)) - { - hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc, - AuthzSvc, pServerPrincName, - AuthnLevel, ImpLevel, pAuthInfo, - Capabilities); - IClientSecurity_Release(pCliSec); - } - - if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr); - return hr; -} - -/*********************************************************************** - * CoCopyProxy [OLE32.@] - * - * Copies a proxy. - * - * PARAMS - * pProxy [I] Pointer to the proxy object. - * ppCopy [O] Copy of the proxy. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - * - * SEE ALSO - * CoQueryProxyBlanket, CoSetProxyBlanket. - */ -HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy) -{ - IClientSecurity *pCliSec; - HRESULT hr; - - TRACE("%p\n", pProxy); - - hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec); - if (SUCCEEDED(hr)) - { - hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy); - IClientSecurity_Release(pCliSec); - } - - if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr); - return hr; -} - - -/*********************************************************************** - * CoWaitForMultipleHandles [OLE32.@] - * - * Waits for one or more handles to become signaled. - * - * PARAMS - * dwFlags [I] Flags. See notes. - * dwTimeout [I] Timeout in milliseconds. - * cHandles [I] Number of handles pointed to by pHandles. - * pHandles [I] Handles to wait for. - * lpdwindex [O] Index of handle that was signaled. - * - * RETURNS - * Success: S_OK. - * Failure: RPC_S_CALLPENDING on timeout. - * - * NOTES - * - * The dwFlags parameter can be zero or more of the following: - *| COWAIT_WAITALL - Wait for all of the handles to become signaled. - *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait. - * - * SEE ALSO - * MsgWaitForMultipleObjects, WaitForMultipleObjects. - */ -HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout, - ULONG cHandles, const HANDLE* pHandles, LPDWORD lpdwindex) -{ - HRESULT hr = S_OK; - DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 | - (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0; - DWORD start_time = GetTickCount(); - - TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags, dwTimeout, cHandles, - pHandles, lpdwindex); - - while (TRUE) - { - DWORD now = GetTickCount(); - DWORD res; - - if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now)) - { - hr = RPC_S_CALLPENDING; - break; - } - - TRACE("waiting for rpc completion or window message\n"); - - res = MsgWaitForMultipleObjectsEx(cHandles, pHandles, - (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now, - QS_ALLINPUT, wait_flags); - - if (res == WAIT_OBJECT_0 + cHandles) /* messages available */ - { - MSG msg; - while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) - { - /* FIXME: filter the messages here */ - TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message); - TranslateMessage(&msg); - DispatchMessageW(&msg); - } - } - else if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles)) - { - /* handle signaled, store index */ - *lpdwindex = (res - WAIT_OBJECT_0); - break; - } - else if (res == WAIT_TIMEOUT) - { - hr = RPC_S_CALLPENDING; - break; - } - else - { - ERR("Unexpected wait termination: %ld, %ld\n", res, GetLastError()); - hr = E_UNEXPECTED; - break; - } - } - TRACE("-- 0x%08lx\n", hr); - return hr; -} - -/*********************************************************************** - * DllMain (OLE32.@) - */ -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad) -{ - TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad); - - switch(fdwReason) { - case DLL_PROCESS_ATTACH: - OLE32_hInstance = hinstDLL; - COMPOBJ_InitProcess(); - if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1); - break; - - case DLL_PROCESS_DETACH: - if (TRACE_ON(ole)) CoRevokeMallocSpy(); - COMPOBJ_UninitProcess(); - OLE32_hInstance = 0; - break; - - case DLL_THREAD_DETACH: - COM_TlsDestroy(); - break; - } - return TRUE; -} - -/* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */ +/* + * COMPOBJ library + * + * Copyright 1995 Martin von Loewis + * Copyright 1998 Justin Bradford + * Copyright 1999 Francis Beaudet + * Copyright 1999 Sylvain St-Germain + * Copyright 2002 Marcus Meissner + * Copyright 2004 Mike Hearn + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Note + * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED + * Therefore do not test against COINIT_MULTITHREADED + * + * TODO list: (items bunched together depend on each other) + * + * - Implement the service control manager (in rpcss) to keep track + * of registered class objects: ISCM::ServerRegisterClsid et al + * - Implement the OXID resolver so we don't need magic endpoint names for + * clients and servers to meet up + * + * - Pump the message loop during RPC calls. + * - Call IMessageFilter functions. + * + * - Make all ole interface marshaling use NDR to be wire compatible with + * native DCOM + * - Use & interpret ORPCTHIS & ORPCTHAT. + * + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "objbase.h" +#include "ole2.h" +#include "ole2ver.h" +#include "rpc.h" +#include "winerror.h" +#include "winreg.h" +#include "wownt32.h" +#include "wine/unicode.h" +#include "objbase.h" +#include "compobj_private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +typedef LPCSTR LPCOLESTR16; + +HINSTANCE OLE32_hInstance = 0; /* FIXME: make static ... */ + +/**************************************************************************** + * This section defines variables internal to the COM module. + * + * TODO: Most of these things will have to be made thread-safe. + */ + +static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk); +static void COM_RevokeAllClasses(void); + +const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} }; + +APARTMENT *MTA; /* protected by csApartment */ +static struct list apts = LIST_INIT( apts ); /* protected by csApartment */ + +static CRITICAL_SECTION csApartment; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &csApartment, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": csApartment") } +}; +static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 }; + +/* + * This lock count counts the number of times CoInitialize is called. It is + * decreased every time CoUninitialize is called. When it hits 0, the COM + * libraries are freed + */ +static LONG s_COMLockCount = 0; + +/* + * This linked list contains the list of registered class objects. These + * are mostly used to register the factories for out-of-proc servers of OLE + * objects. + * + * TODO: Make this data structure aware of inter-process communication. This + * means that parts of this will be exported to the Wine Server. + */ +typedef struct tagRegisteredClass +{ + CLSID classIdentifier; + LPUNKNOWN classObject; + DWORD runContext; + DWORD connectFlags; + DWORD dwCookie; + LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */ + struct tagRegisteredClass* nextClass; +} RegisteredClass; + +static RegisteredClass* firstRegisteredClass = NULL; + +static CRITICAL_SECTION csRegisteredClassList; +static CRITICAL_SECTION_DEBUG class_cs_debug = +{ + 0, 0, &csRegisteredClassList, + { &class_cs_debug.ProcessLocksList, &class_cs_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": csRegisteredClassList") } +}; +static CRITICAL_SECTION csRegisteredClassList = { &class_cs_debug, -1, 0, 0, 0, 0 }; + +/***************************************************************************** + * This section contains OpenDllList definitions + * + * The OpenDllList contains only handles of dll loaded by CoGetClassObject or + * other functions that do LoadLibrary _without_ giving back a HMODULE. + * Without this list these handles would never be freed. + * + * FIXME: a DLL that says OK when asked for unloading is unloaded in the + * next unload-call but not before 600 sec. + */ + +typedef struct tagOpenDll { + HINSTANCE hLibrary; + struct tagOpenDll *next; +} OpenDll; + +static OpenDll *openDllList = NULL; /* linked list of open dlls */ + +static CRITICAL_SECTION csOpenDllList; +static CRITICAL_SECTION_DEBUG dll_cs_debug = +{ + 0, 0, &csOpenDllList, + { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": csOpenDllList") } +}; +static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 }; + +static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',' ', + '0','x','#','#','#','#','#','#','#','#',' ',0}; +static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +static void COMPOBJ_DLLList_Add(HANDLE hLibrary); +static void COMPOBJ_DllList_FreeUnused(int Timeout); + +static void COMPOBJ_InitProcess( void ) +{ + WNDCLASSW wclass; + + /* Dispatching to the correct thread in an apartment is done through + * window messages rather than RPC transports. When an interface is + * marshalled into another apartment in the same process, a window of the + * following class is created. The *caller* of CoMarshalInterface (ie the + * application) is responsible for pumping the message loop in that thread. + * The WM_USER messages which point to the RPCs are then dispatched to + * COM_AptWndProc by the user's code from the apartment in which the interface + * was unmarshalled. + */ + memset(&wclass, 0, sizeof(wclass)); + wclass.lpfnWndProc = apartment_wndproc; + wclass.hInstance = OLE32_hInstance; + wclass.lpszClassName = wszAptWinClass; + RegisterClassW(&wclass); +} + +static void COMPOBJ_UninitProcess( void ) +{ + UnregisterClassW(wszAptWinClass, OLE32_hInstance); +} + +static void COM_TlsDestroy() +{ + struct oletls *info = NtCurrentTeb()->ReservedForOle; + if (info) + { + if (info->apt) apartment_release(info->apt); + if (info->errorinfo) IErrorInfo_Release(info->errorinfo); + if (info->state) IUnknown_Release(info->state); + HeapFree(GetProcessHeap(), 0, info); + NtCurrentTeb()->ReservedForOle = NULL; + } +} + +/****************************************************************************** + * Manage apartments. + */ + +/* allocates memory and fills in the necessary fields for a new apartment + * object */ +static APARTMENT *apartment_construct(DWORD model) +{ + APARTMENT *apt; + + TRACE("creating new apartment, model=%ld\n", model); + + apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt)); + apt->tid = GetCurrentThreadId(); + DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), + GetCurrentProcess(), &apt->thread, + THREAD_ALL_ACCESS, FALSE, 0); + + list_init(&apt->proxies); + list_init(&apt->stubmgrs); + apt->ipidc = 0; + apt->refs = 1; + apt->remunk_exported = FALSE; + apt->oidc = 1; + InitializeCriticalSection(&apt->cs); + DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment"); + + apt->model = model; + + if (model & COINIT_APARTMENTTHREADED) + { + /* FIXME: should be randomly generated by in an RPC call to rpcss */ + apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId(); + apt->win = CreateWindowW(wszAptWinClass, NULL, 0, + 0, 0, 0, 0, + 0, 0, OLE32_hInstance, NULL); + } + else + { + /* FIXME: should be randomly generated by in an RPC call to rpcss */ + apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe; + } + + TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid)); + + /* the locking here is not currently needed for the MTA case, but it + * doesn't hurt and makes the code simpler */ + EnterCriticalSection(&csApartment); + list_add_head(&apts, &apt->entry); + LeaveCriticalSection(&csApartment); + + return apt; +} + +/* gets and existing apartment if one exists or otherwise creates an apartment + * structure which stores OLE apartment-local information and stores a pointer + * to it in the thread-local storage */ +static APARTMENT *apartment_get_or_create(DWORD model) +{ + APARTMENT *apt = COM_CurrentApt(); + + if (!apt) + { + if (model & COINIT_APARTMENTTHREADED) + { + apt = apartment_construct(model); + COM_CurrentInfo()->apt = apt; + } + else + { + EnterCriticalSection(&csApartment); + + /* The multi-threaded apartment (MTA) contains zero or more threads interacting + * with free threaded (ie thread safe) COM objects. There is only ever one MTA + * in a process */ + if (MTA) + { + TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid)); + apartment_addref(MTA); + } + else + MTA = apartment_construct(model); + + apt = MTA; + COM_CurrentInfo()->apt = apt; + + LeaveCriticalSection(&csApartment); + } + } + + return apt; +} + +DWORD apartment_addref(struct apartment *apt) +{ + DWORD refs = InterlockedIncrement(&apt->refs); + TRACE("%s: before = %ld\n", wine_dbgstr_longlong(apt->oxid), refs - 1); + return refs; +} + +DWORD apartment_release(struct apartment *apt) +{ + DWORD ret; + + EnterCriticalSection(&csApartment); + + ret = InterlockedDecrement(&apt->refs); + TRACE("%s: after = %ld\n", wine_dbgstr_longlong(apt->oxid), ret); + /* destruction stuff that needs to happen under csApartment CS */ + if (ret == 0) + { + if (apt == MTA) MTA = NULL; + list_remove(&apt->entry); + } + + LeaveCriticalSection(&csApartment); + + if (ret == 0) + { + struct list *cursor, *cursor2; + + TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid)); + + /* no locking is needed for this apartment, because no other thread + * can access it at this point */ + + apartment_disconnectproxies(apt); + + if (apt->win) DestroyWindow(apt->win); + + LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs) + { + struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry); + /* release the implicit reference given by the fact that the + * stub has external references (it must do since it is in the + * stub manager list in the apartment and all non-apartment users + * must have a ref on the apartment and so it cannot be destroyed). + */ + stub_manager_int_release(stubmgr); + } + + /* if this assert fires, then another thread took a reference to a + * stub manager without taking a reference to the containing + * apartment, which it must do. */ + assert(list_empty(&apt->stubmgrs)); + + if (apt->filter) IUnknown_Release(apt->filter); + + DEBUG_CLEAR_CRITSEC_NAME(&apt->cs); + DeleteCriticalSection(&apt->cs); + CloseHandle(apt->thread); + + HeapFree(GetProcessHeap(), 0, apt); + } + + return ret; +} + +/* The given OXID must be local to this process: + * + * The ref parameter is here mostly to ensure people remember that + * they get one, you should normally take a ref for thread safety. + */ +APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref) +{ + APARTMENT *result = NULL; + struct list *cursor; + + EnterCriticalSection(&csApartment); + LIST_FOR_EACH( cursor, &apts ) + { + struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry ); + if (apt->oxid == oxid) + { + result = apt; + if (ref) apartment_addref(result); + break; + } + } + LeaveCriticalSection(&csApartment); + + return result; +} + +/* gets the apartment which has a given creator thread ID. The caller must + * release the reference from the apartment as soon as the apartment pointer + * is no longer required. */ +APARTMENT *apartment_findfromtid(DWORD tid) +{ + APARTMENT *result = NULL; + struct list *cursor; + + EnterCriticalSection(&csApartment); + LIST_FOR_EACH( cursor, &apts ) + { + struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry ); + if (apt->tid == tid) + { + result = apt; + apartment_addref(result); + break; + } + } + LeaveCriticalSection(&csApartment); + + return result; +} + +static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case DM_EXECUTERPC: + return RPC_ExecuteCall((struct dispatch_params *)lParam); + default: + return DefWindowProcW(hWnd, msg, wParam, lParam); + } +} + +/***************************************************************************** + * This section contains OpenDllList implemantation + */ + +static void COMPOBJ_DLLList_Add(HANDLE hLibrary) +{ + OpenDll *ptr; + OpenDll *tmp; + + TRACE("\n"); + + EnterCriticalSection( &csOpenDllList ); + + if (openDllList == NULL) { + /* empty list -- add first node */ + openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll)); + openDllList->hLibrary=hLibrary; + openDllList->next = NULL; + } else { + /* search for this dll */ + int found = FALSE; + for (ptr = openDllList; ptr->next != NULL; ptr=ptr->next) { + if (ptr->hLibrary == hLibrary) { + found = TRUE; + break; + } + } + if (!found) { + /* dll not found, add it */ + tmp = openDllList; + openDllList = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll)); + openDllList->hLibrary = hLibrary; + openDllList->next = tmp; + } + } + + LeaveCriticalSection( &csOpenDllList ); +} + +static void COMPOBJ_DllList_FreeUnused(int Timeout) +{ + OpenDll *curr, *next, *prev = NULL; + typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void); + DllCanUnloadNowFunc DllCanUnloadNow; + + TRACE("\n"); + + EnterCriticalSection( &csOpenDllList ); + + for (curr = openDllList; curr != NULL; ) { + DllCanUnloadNow = (DllCanUnloadNowFunc) GetProcAddress(curr->hLibrary, "DllCanUnloadNow"); + + if ( (DllCanUnloadNow != NULL) && (DllCanUnloadNow() == S_OK) ) { + next = curr->next; + + TRACE("freeing %p\n", curr->hLibrary); + FreeLibrary(curr->hLibrary); + + HeapFree(GetProcessHeap(), 0, curr); + if (curr == openDllList) { + openDllList = next; + } else { + prev->next = next; + } + + curr = next; + } else { + prev = curr; + curr = curr->next; + } + } + + LeaveCriticalSection( &csOpenDllList ); +} + +/****************************************************************************** + * CoBuildVersion [OLE32.@] + * CoBuildVersion [COMPOBJ.1] + * + * Gets the build version of the DLL. + * + * PARAMS + * + * RETURNS + * Current build version, hiword is majornumber, loword is minornumber + */ +DWORD WINAPI CoBuildVersion(void) +{ + TRACE("Returning version %d, build %d.\n", rmm, rup); + return (rmm<<16)+rup; +} + +/****************************************************************************** + * CoInitialize [OLE32.@] + * + * Initializes the COM libraries by calling CoInitializeEx with + * COINIT_APARTMENTTHREADED, ie it enters a STA thread. + * + * PARAMS + * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL). + * + * RETURNS + * Success: S_OK if not already initialized, S_FALSE otherwise. + * Failure: HRESULT code. + * + * SEE ALSO + * CoInitializeEx + */ +HRESULT WINAPI CoInitialize(LPVOID lpReserved) +{ + /* + * Just delegate to the newer method. + */ + return CoInitializeEx(lpReserved, COINIT_APARTMENTTHREADED); +} + +/****************************************************************************** + * CoInitializeEx [OLE32.@] + * + * Initializes the COM libraries. + * + * PARAMS + * lpReserved [I] Pointer to IMalloc interface (obsolete, should be NULL). + * dwCoInit [I] One or more flags from the COINIT enumeration. See notes. + * + * RETURNS + * S_OK if successful, + * S_FALSE if this function was called already. + * RPC_E_CHANGED_MODE if a previous call to CoInitializeEx specified another + * threading model. + * + * NOTES + * + * The behavior used to set the IMalloc used for memory management is + * obsolete. + * The dwCoInit parameter must specify of of the following apartment + * threading models: + *| COINIT_APARTMENTTHREADED - A single-threaded apartment (STA). + *| COINIT_MULTITHREADED - A multi-threaded apartment (MTA). + * The parameter may also specify zero or more of the following flags: + *| COINIT_DISABLE_OLE1DDE - Don't use DDE for OLE1 support. + *| COINIT_SPEED_OVER_MEMORY - Trade memory for speed. + * + * SEE ALSO + * CoUninitialize + */ +HRESULT WINAPI CoInitializeEx(LPVOID lpReserved, DWORD dwCoInit) +{ + HRESULT hr = S_OK; + APARTMENT *apt; + + TRACE("(%p, %x)\n", lpReserved, (int)dwCoInit); + + if (lpReserved!=NULL) + { + ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved); + } + + /* + * Check the lock count. If this is the first time going through the initialize + * process, we have to initialize the libraries. + * + * And crank-up that lock count. + */ + if (InterlockedExchangeAdd(&s_COMLockCount,1)==0) + { + /* + * Initialize the various COM libraries and data structures. + */ + TRACE("() - Initializing the COM libraries\n"); + + /* we may need to defer this until after apartment initialisation */ + RunningObjectTableImpl_Initialize(); + } + + if (!(apt = COM_CurrentInfo()->apt)) + { + apt = apartment_get_or_create(dwCoInit); + if (!apt) return E_OUTOFMEMORY; + } + else if (dwCoInit != apt->model) + { + /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine + code then we are probably using the wrong threading model to implement that API. */ + ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit); + return RPC_E_CHANGED_MODE; + } + else + hr = S_FALSE; + + COM_CurrentInfo()->inits++; + + return hr; +} + +/* On COM finalization for a STA thread, the message queue is flushed to ensure no + pending RPCs are ignored. Non-COM messages are discarded at this point. + */ +static void COM_FlushMessageQueue(void) +{ + MSG message; + APARTMENT *apt = COM_CurrentApt(); + + if (!apt || !apt->win) return; + + TRACE("Flushing STA message queue\n"); + + while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE)) + { + if (message.hwnd != apt->win) + { + WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd); + continue; + } + + TranslateMessage(&message); + DispatchMessageA(&message); + } +} + +/*********************************************************************** + * CoUninitialize [OLE32.@] + * + * This method will decrement the refcount on the current apartment, freeing + * the resources associated with it if it is the last thread in the apartment. + * If the last apartment is freed, the function will additionally release + * any COM resources associated with the process. + * + * PARAMS + * + * RETURNS + * Nothing. + * + * SEE ALSO + * CoInitializeEx + */ +void WINAPI CoUninitialize(void) +{ + struct oletls * info = COM_CurrentInfo(); + LONG lCOMRefCnt; + + TRACE("()\n"); + + /* will only happen on OOM */ + if (!info) return; + + /* sanity check */ + if (!info->inits) + { + ERR("Mismatched CoUninitialize\n"); + return; + } + + if (!--info->inits) + { + apartment_release(info->apt); + info->apt = NULL; + } + + /* + * Decrease the reference count. + * If we are back to 0 locks on the COM library, make sure we free + * all the associated data structures. + */ + lCOMRefCnt = InterlockedExchangeAdd(&s_COMLockCount,-1); + if (lCOMRefCnt==1) + { + TRACE("() - Releasing the COM libraries\n"); + + RunningObjectTableImpl_UnInitialize(); + + /* Release the references to the registered class objects */ + COM_RevokeAllClasses(); + + /* This will free the loaded COM Dlls */ + CoFreeAllLibraries(); + + /* This ensures we deal with any pending RPCs */ + COM_FlushMessageQueue(); + } + else if (lCOMRefCnt<1) { + ERR( "CoUninitialize() - not CoInitialized.\n" ); + InterlockedExchangeAdd(&s_COMLockCount,1); /* restore the lock count. */ + } +} + +/****************************************************************************** + * CoDisconnectObject [OLE32.@] + * CoDisconnectObject [COMPOBJ.15] + * + * Disconnects all connections to this object from remote processes. Dispatches + * pending RPCs while blocking new RPCs from occurring, and then calls + * IMarshal::DisconnectObject on the given object. + * + * Typically called when the object server is forced to shut down, for instance by + * the user. + * + * PARAMS + * lpUnk [I] The object whose stub should be disconnected. + * reserved [I] Reserved. Should be set to 0. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * SEE ALSO + * CoMarshalInterface, CoReleaseMarshalData, CoLockObjectExternal + */ +HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved ) +{ + HRESULT hr; + IMarshal *marshal; + APARTMENT *apt; + + TRACE("(%p, 0x%08lx)\n", lpUnk, reserved); + + hr = IUnknown_QueryInterface(lpUnk, &IID_IMarshal, (void **)&marshal); + if (hr == S_OK) + { + hr = IMarshal_DisconnectObject(marshal, reserved); + IMarshal_Release(marshal); + return hr; + } + + apt = COM_CurrentApt(); + if (!apt) + return CO_E_NOTINITIALIZED; + + apartment_disconnectobject(apt, lpUnk); + + /* Note: native is pretty broken here because it just silently + * fails, without returning an appropriate error code if the object was + * not found, making apps think that the object was disconnected, when + * it actually wasn't */ + + return S_OK; +} + +/****************************************************************************** + * CoCreateGuid [OLE32.@] + * + * Simply forwards to UuidCreate in RPCRT4. + * + * PARAMS + * pguid [O] Points to the GUID to initialize. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * SEE ALSO + * UuidCreate + */ +HRESULT WINAPI CoCreateGuid(GUID *pguid) +{ + return UuidCreate(pguid); +} + +/****************************************************************************** + * CLSIDFromString [OLE32.@] + * IIDFromString [OLE32.@] + * + * Converts a unique identifier from its string representation into + * the GUID struct. + * + * PARAMS + * idstr [I] The string representation of the GUID. + * id [O] GUID converted from the string. + * + * RETURNS + * S_OK on success + * CO_E_CLASSSTRING if idstr is not a valid CLSID + * + * BUGS + * + * In Windows, if idstr is not a valid CLSID string then it gets + * treated as a ProgID. Wine currently doesn't do this. If idstr is + * NULL it's treated as an all-zero GUID. + * + * SEE ALSO + * StringFromCLSID + */ +HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id) +{ + const BYTE *s = (const BYTE *) idstr; + int i; + BYTE table[256]; + + if (!s) + s = "{00000000-0000-0000-0000-000000000000}"; + else { /* validate the CLSID string */ + + if (strlen(s) != 38) + return CO_E_CLASSSTRING; + + if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') || (s[24]!='-') || (s[37]!='}')) + return CO_E_CLASSSTRING; + + 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')))) + return CO_E_CLASSSTRING; + } + } + + 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; +} + +/*****************************************************************************/ + +HRESULT WINAPI CLSIDFromString(LPOLESTR idstr, CLSID *id ) +{ + char xid[40]; + HRESULT ret; + + if (!WideCharToMultiByte( CP_ACP, 0, idstr, -1, xid, sizeof(xid), NULL, NULL )) + return CO_E_CLASSSTRING; + + + ret = __CLSIDFromStringA(xid,id); + if(ret != S_OK) { /* It appears a ProgID is also valid */ + ret = CLSIDFromProgID(idstr, id); + } + return ret; +} + +/* Converts a GUID into the respective string representation. */ +HRESULT WINE_StringFromCLSID( + const CLSID *id, /* [in] GUID to be converted */ + LPSTR idstr /* [out] pointer to buffer to contain converted guid */ +) { + static const char *hex = "0123456789ABCDEF"; + char *s; + int i; + + if (!id) + { ERR("called with id=Null\n"); + *idstr = 0x00; + return E_FAIL; + } + + sprintf(idstr, "{%08lX-%04X-%04X-%02X%02X-", + id->Data1, id->Data2, id->Data3, + id->Data4[0], id->Data4[1]); + s = &idstr[25]; + + /* 6 hex bytes */ + for (i = 2; i < 8; i++) { + *s++ = hex[id->Data4[i]>>4]; + *s++ = hex[id->Data4[i] & 0xf]; + } + + *s++ = '}'; + *s++ = '\0'; + + TRACE("%p->%s\n", id, idstr); + + return S_OK; +} + + +/****************************************************************************** + * StringFromCLSID [OLE32.@] + * StringFromIID [OLE32.@] + * + * Converts a GUID into the respective string representation. + * The target string is allocated using the OLE IMalloc. + * + * PARAMS + * id [I] the GUID to be converted. + * idstr [O] A pointer to a to-be-allocated pointer pointing to the resulting string. + * + * RETURNS + * S_OK + * E_FAIL + * + * SEE ALSO + * StringFromGUID2, CLSIDFromString + */ +HRESULT WINAPI StringFromCLSID(REFCLSID id, LPOLESTR *idstr) +{ + char buf[80]; + HRESULT ret; + LPMALLOC mllc; + + if ((ret = CoGetMalloc(0,&mllc))) + return ret; + + ret=WINE_StringFromCLSID(id,buf); + if (!ret) { + DWORD len = MultiByteToWideChar( CP_ACP, 0, buf, -1, NULL, 0 ); + *idstr = IMalloc_Alloc( mllc, len * sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, buf, -1, *idstr, len ); + } + return ret; +} + +/****************************************************************************** + * StringFromGUID2 [OLE32.@] + * StringFromGUID2 [COMPOBJ.76] + * + * Modified version of StringFromCLSID that allows you to specify max + * buffer size. + * + * PARAMS + * id [I] GUID to convert to string. + * str [O] Buffer where the result will be stored. + * cmax [I] Size of the buffer in characters. + * + * RETURNS + * Success: The length of the resulting string in characters. + * Failure: 0. + */ +INT WINAPI StringFromGUID2(REFGUID id, LPOLESTR str, INT cmax) +{ + char xguid[80]; + + if (WINE_StringFromCLSID(id,xguid)) + return 0; + return MultiByteToWideChar( CP_ACP, 0, xguid, -1, str, cmax ); +} + +/****************************************************************************** + * ProgIDFromCLSID [OLE32.@] + * + * Converts a class id into the respective program ID. + * + * PARAMS + * clsid [I] Class ID, as found in registry. + * lplpszProgID [O] Associated ProgID. + * + * RETURNS + * S_OK + * E_OUTOFMEMORY + * REGDB_E_CLASSNOTREG if the given clsid has no associated ProgID + */ +HRESULT WINAPI ProgIDFromCLSID(REFCLSID clsid, LPOLESTR *lplpszProgID) +{ + char strCLSID[50], *buf, *buf2; + DWORD buf2len; + HKEY xhkey; + LPMALLOC mllc; + HRESULT ret = S_OK; + + WINE_StringFromCLSID(clsid, strCLSID); + + buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14); + sprintf(buf,"CLSID\\%s\\ProgID", strCLSID); + if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey)) + ret = REGDB_E_CLASSNOTREG; + + HeapFree(GetProcessHeap(), 0, buf); + + if (ret == S_OK) + { + buf2 = HeapAlloc(GetProcessHeap(), 0, 255); + buf2len = 255; + if (RegQueryValueA(xhkey, NULL, buf2, &buf2len)) + ret = REGDB_E_CLASSNOTREG; + + if (ret == S_OK) + { + if (CoGetMalloc(0,&mllc)) + ret = E_OUTOFMEMORY; + else + { + DWORD len = MultiByteToWideChar( CP_ACP, 0, buf2, -1, NULL, 0 ); + *lplpszProgID = IMalloc_Alloc(mllc, len * sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, buf2, -1, *lplpszProgID, len ); + } + } + HeapFree(GetProcessHeap(), 0, buf2); + RegCloseKey(xhkey); + } + + return ret; +} + +/****************************************************************************** + * 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]; + DWORD buf2len; + HRESULT err; + HKEY xhkey; + + buf = HeapAlloc(GetProcessHeap(),0,strlen(progid)+8); + sprintf(buf,"%s\\CLSID",progid); + if ((err=RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&xhkey))) { + HeapFree(GetProcessHeap(),0,buf); + return CO_E_CLASSSTRING; + } + HeapFree(GetProcessHeap(),0,buf); + buf2len = sizeof(buf2); + if ((err=RegQueryValueA(xhkey,NULL,buf2,&buf2len))) { + RegCloseKey(xhkey); + return CO_E_CLASSSTRING; + } + RegCloseKey(xhkey); + return __CLSIDFromStringA(buf2,riid); +} + +/****************************************************************************** + * CLSIDFromProgID [OLE32.@] + * + * Converts a program id into the respective GUID. + * + * PARAMS + * progid [I] Unicode 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 CLSIDFromProgID(LPCOLESTR progid, LPCLSID riid) +{ + static const WCHAR clsidW[] = { '\\','C','L','S','I','D',0 }; + char buf2[80]; + DWORD buf2len = sizeof(buf2); + HKEY xhkey; + + WCHAR *buf = HeapAlloc( GetProcessHeap(),0,(strlenW(progid)+8) * sizeof(WCHAR) ); + strcpyW( buf, progid ); + strcatW( buf, clsidW ); + if (RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&xhkey)) + { + HeapFree(GetProcessHeap(),0,buf); + return CO_E_CLASSSTRING; + } + HeapFree(GetProcessHeap(),0,buf); + + if (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) + { + RegCloseKey(xhkey); + return CO_E_CLASSSTRING; + } + RegCloseKey(xhkey); + return __CLSIDFromStringA(buf2,riid); +} + + + +/***************************************************************************** + * CoGetPSClsid [OLE32.@] + * + * Retrieves the CLSID of the proxy/stub factory that implements + * IPSFactoryBuffer for the specified interface. + * + * PARAMS + * riid [I] Interface whose proxy/stub CLSID is to be returned. + * pclsid [O] Where to store returned proxy/stub CLSID. + * + * RETURNS + * S_OK + * E_OUTOFMEMORY + * REGDB_E_IIDNOTREG if no PSFactoryBuffer is associated with the IID, or it could not be parsed + * + * NOTES + * + * The standard marshaller activates the object with the CLSID + * returned and uses the CreateProxy and CreateStub methods on its + * IPSFactoryBuffer interface to construct the proxies and stubs for a + * given object. + * + * CoGetPSClsid determines this CLSID by searching the + * HKEY_CLASSES_ROOT\Interface\{string form of riid}\ProxyStubClsid32 + * in the registry and any interface id registered by + * CoRegisterPSClsid within the current process. + * + * BUGS + * + * We only search the registry, not ids registered with + * CoRegisterPSClsid. + * Also, native returns S_OK for interfaces with a key in HKCR\Interface, but + * without a ProxyStubClsid32 key and leaves garbage in pclsid. This should be + * considered a bug in native unless an application depends on this (unlikely). + */ +HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid) +{ + char *buf, buf2[40]; + DWORD buf2len; + HKEY xhkey; + + TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid); + + /* Get the input iid as a string */ + WINE_StringFromCLSID(riid, buf2); + /* Allocate memory for the registry key we will construct. + (length of iid string plus constant length of static text */ + buf = HeapAlloc(GetProcessHeap(), 0, strlen(buf2)+27); + if (buf == NULL) + return E_OUTOFMEMORY; + + /* Construct the registry key we want */ + sprintf(buf,"Interface\\%s\\ProxyStubClsid32", buf2); + + /* Open the key.. */ + if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey)) + { + WARN("No PSFactoryBuffer object is registered for IID %s\n", debugstr_guid(riid)); + HeapFree(GetProcessHeap(),0,buf); + return REGDB_E_IIDNOTREG; + } + HeapFree(GetProcessHeap(),0,buf); + + /* ... Once we have the key, query the registry to get the + value of CLSID as a string, and convert it into a + proper CLSID structure to be passed back to the app */ + buf2len = sizeof(buf2); + if ( (RegQueryValueA(xhkey,NULL,buf2,&buf2len)) ) + { + RegCloseKey(xhkey); + return REGDB_E_IIDNOTREG; + } + RegCloseKey(xhkey); + + /* We have the CLSid we want back from the registry as a string, so + lets convert it into a CLSID structure */ + if ( (__CLSIDFromStringA(buf2,pclsid)) != NOERROR) + return REGDB_E_IIDNOTREG; + + TRACE ("() Returning CLSID=%s\n", debugstr_guid(pclsid)); + return S_OK; +} + + + +/*********************************************************************** + * WriteClassStm (OLE32.@) + * + * Writes a CLSID to a stream. + * + * PARAMS + * pStm [I] Stream to write to. + * rclsid [I] CLSID to write. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + */ +HRESULT WINAPI WriteClassStm(IStream *pStm,REFCLSID rclsid) +{ + TRACE("(%p,%p)\n",pStm,rclsid); + + if (rclsid==NULL) + return E_INVALIDARG; + + return IStream_Write(pStm,rclsid,sizeof(CLSID),NULL); +} + +/*********************************************************************** + * ReadClassStm (OLE32.@) + * + * Reads a CLSID from a stream. + * + * PARAMS + * pStm [I] Stream to read from. + * rclsid [O] CLSID to read. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + */ +HRESULT WINAPI ReadClassStm(IStream *pStm,CLSID *pclsid) +{ + ULONG nbByte; + HRESULT res; + + TRACE("(%p,%p)\n",pStm,pclsid); + + if (pclsid==NULL) + return E_INVALIDARG; + + res = IStream_Read(pStm,(void*)pclsid,sizeof(CLSID),&nbByte); + + if (FAILED(res)) + return res; + + if (nbByte != sizeof(CLSID)) + return S_FALSE; + else + return S_OK; +} + + +/*** + * COM_GetRegisteredClassObject + * + * This internal method is used to scan the registered class list to + * find a class object. + * + * Params: + * rclsid Class ID of the class to find. + * dwClsContext Class context to match. + * ppv [out] returns a pointer to the class object. Complying + * to normal COM usage, this method will increase the + * reference count on this object. + */ +static HRESULT COM_GetRegisteredClassObject( + REFCLSID rclsid, + DWORD dwClsContext, + LPUNKNOWN* ppUnk) +{ + HRESULT hr = S_FALSE; + RegisteredClass* curClass; + + EnterCriticalSection( &csRegisteredClassList ); + + /* + * Sanity check + */ + assert(ppUnk!=0); + + /* + * Iterate through the whole list and try to match the class ID. + */ + curClass = firstRegisteredClass; + + while (curClass != 0) + { + /* + * Check if we have a match on the class ID. + */ + if (IsEqualGUID(&(curClass->classIdentifier), rclsid)) + { + /* + * Since we don't do out-of process or DCOM just right away, let's ignore the + * class context. + */ + + /* + * We have a match, return the pointer to the class object. + */ + *ppUnk = curClass->classObject; + + IUnknown_AddRef(curClass->classObject); + + hr = S_OK; + goto end; + } + + /* + * Step to the next class in the list. + */ + curClass = curClass->nextClass; + } + +end: + LeaveCriticalSection( &csRegisteredClassList ); + /* + * If we get to here, we haven't found our class. + */ + return hr; +} + +/****************************************************************************** + * CoRegisterClassObject [OLE32.@] + * + * Registers the class object for a given class ID. Servers housed in EXE + * files use this method instead of exporting DllGetClassObject to allow + * other code to connect to their objects. + * + * PARAMS + * rclsid [I] CLSID of the object to register. + * pUnk [I] IUnknown of the object. + * dwClsContext [I] CLSCTX flags indicating the context in which to run the executable. + * flags [I] REGCLS flags indicating how connections are made. + * lpdwRegister [I] A unique cookie that can be passed to CoRevokeClassObject. + * + * RETURNS + * S_OK on success, + * E_INVALIDARG if lpdwRegister or pUnk are NULL, + * CO_E_OBJISREG if the object is already registered. We should not return this. + * + * SEE ALSO + * CoRevokeClassObject, CoGetClassObject + * + * BUGS + * MSDN claims that multiple interface registrations are legal, but we + * can't do that with our current implementation. + */ +HRESULT WINAPI CoRegisterClassObject( + REFCLSID rclsid, + LPUNKNOWN pUnk, + DWORD dwClsContext, + DWORD flags, + LPDWORD lpdwRegister) +{ + RegisteredClass* newClass; + LPUNKNOWN foundObject; + HRESULT hr; + + TRACE("(%s,%p,0x%08lx,0x%08lx,%p)\n", + debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister); + + if ( (lpdwRegister==0) || (pUnk==0) ) + return E_INVALIDARG; + + if (!COM_CurrentApt()) + { + ERR("COM was not initialized\n"); + return CO_E_NOTINITIALIZED; + } + + *lpdwRegister = 0; + + /* + * First, check if the class is already registered. + * If it is, this should cause an error. + */ + hr = COM_GetRegisteredClassObject(rclsid, dwClsContext, &foundObject); + if (hr == S_OK) { + IUnknown_Release(foundObject); + return CO_E_OBJISREG; + } + + newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass)); + if ( newClass == NULL ) + return E_OUTOFMEMORY; + + EnterCriticalSection( &csRegisteredClassList ); + + newClass->classIdentifier = *rclsid; + newClass->runContext = dwClsContext; + newClass->connectFlags = flags; + /* + * Use the address of the chain node as the cookie since we are sure it's + * unique. FIXME: not on 64-bit platforms. + */ + newClass->dwCookie = (DWORD)newClass; + newClass->nextClass = firstRegisteredClass; + + /* + * Since we're making a copy of the object pointer, we have to increase its + * reference count. + */ + newClass->classObject = pUnk; + IUnknown_AddRef(newClass->classObject); + + firstRegisteredClass = newClass; + LeaveCriticalSection( &csRegisteredClassList ); + + *lpdwRegister = newClass->dwCookie; + + if (dwClsContext & CLSCTX_LOCAL_SERVER) { + IClassFactory *classfac; + + hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory, + (LPVOID*)&classfac); + if (hr) return hr; + + hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData); + if (hr) { + FIXME("Failed to create stream on hglobal, %lx\n", hr); + IUnknown_Release(classfac); + return hr; + } + hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory, + (LPVOID)classfac, MSHCTX_LOCAL, NULL, + MSHLFLAGS_TABLESTRONG); + if (hr) { + FIXME("CoMarshalInterface failed, %lx!\n",hr); + IUnknown_Release(classfac); + return hr; + } + + IUnknown_Release(classfac); + + RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData); + } + return S_OK; +} + +/*********************************************************************** + * CoRevokeClassObject [OLE32.@] + * + * Removes a class object from the class registry. + * + * PARAMS + * dwRegister [I] Cookie returned from CoRegisterClassObject(). + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * SEE ALSO + * CoRegisterClassObject + */ +HRESULT WINAPI CoRevokeClassObject( + DWORD dwRegister) +{ + HRESULT hr = E_INVALIDARG; + RegisteredClass** prevClassLink; + RegisteredClass* curClass; + + TRACE("(%08lx)\n",dwRegister); + + EnterCriticalSection( &csRegisteredClassList ); + + /* + * Iterate through the whole list and try to match the cookie. + */ + curClass = firstRegisteredClass; + prevClassLink = &firstRegisteredClass; + + while (curClass != 0) + { + /* + * Check if we have a match on the cookie. + */ + if (curClass->dwCookie == dwRegister) + { + /* + * Remove the class from the chain. + */ + *prevClassLink = curClass->nextClass; + + /* + * Release the reference to the class object. + */ + IUnknown_Release(curClass->classObject); + + if (curClass->pMarshaledData) + { + LARGE_INTEGER zero; + memset(&zero, 0, sizeof(zero)); + /* FIXME: stop local server thread */ + IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL); + CoReleaseMarshalData(curClass->pMarshaledData); + } + + /* + * Free the memory used by the chain node. + */ + HeapFree(GetProcessHeap(), 0, curClass); + + hr = S_OK; + goto end; + } + + /* + * Step to the next class in the list. + */ + prevClassLink = &(curClass->nextClass); + curClass = curClass->nextClass; + } + +end: + LeaveCriticalSection( &csRegisteredClassList ); + /* + * If we get to here, we haven't found our class. + */ + return hr; +} + +/*********************************************************************** + * compobj_RegReadPath [internal] + * + * Reads a registry value and expands it when necessary + */ +static HRESULT +compobj_RegReadPath(char * keyname, char * valuename, char * dst, DWORD dstlen) +{ + HRESULT hres; + HKEY key; + DWORD keytype; + char src[MAX_PATH]; + DWORD dwLength = dstlen; + + if((hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key)) == ERROR_SUCCESS) { + if( (hres = RegQueryValueExA(key, NULL, NULL, &keytype, (LPBYTE)src, &dwLength)) == ERROR_SUCCESS ) { + if (keytype == REG_EXPAND_SZ) { + if (dstlen <= ExpandEnvironmentStringsA(src, dst, dstlen)) hres = ERROR_MORE_DATA; + } else { + lstrcpynA(dst, src, dstlen); + } + } + RegCloseKey (key); + } + return hres; +} + +/*********************************************************************** + * CoGetClassObject [COMPOBJ.7] + * CoGetClassObject [OLE32.@] + * + * FIXME. If request allows of several options and there is a failure + * with one (other than not being registered) do we try the + * others or return failure? (E.g. inprocess is registered but + * the DLL is not found but the server version works) + */ +HRESULT WINAPI CoGetClassObject( + REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo, + REFIID iid, LPVOID *ppv +) { + LPUNKNOWN regClassObject; + HRESULT hres = E_UNEXPECTED; + char xclsid[80]; + HINSTANCE hLibrary; + typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv); + DllGetClassObjectFunc DllGetClassObject; + + WINE_StringFromCLSID((LPCLSID)rclsid,xclsid); + + TRACE("\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid)); + + if (pServerInfo) { + FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName)); + FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo); + } + + /* + * First, try and see if we can't match the class ID with one of the + * registered classes. + */ + if (S_OK == COM_GetRegisteredClassObject(rclsid, dwClsContext, ®ClassObject)) + { + /* + * Get the required interface from the retrieved pointer. + */ + hres = IUnknown_QueryInterface(regClassObject, iid, ppv); + + /* + * Since QI got another reference on the pointer, we want to release the + * one we already have. If QI was unsuccessful, this will release the object. This + * is good since we are not returning it in the "out" parameter. + */ + IUnknown_Release(regClassObject); + + return hres; + } + + /* first try: in-process */ + if ((CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER) & dwClsContext) { + char keyname[MAX_PATH]; + char dllpath[MAX_PATH+1]; + + sprintf(keyname,"CLSID\\%s\\InprocServer32",xclsid); + + if ( compobj_RegReadPath(keyname, NULL, dllpath, sizeof(dllpath)) != ERROR_SUCCESS) { + /* failure: CLSID is not found in registry */ + WARN("class %s not registered inproc\n", xclsid); + hres = REGDB_E_CLASSNOTREG; + } else { + if ((hLibrary = LoadLibraryExA(dllpath, 0, LOAD_WITH_ALTERED_SEARCH_PATH)) == 0) { + /* failure: DLL could not be loaded */ + ERR("couldn't load InprocServer32 dll %s\n", dllpath); + hres = E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */ + } else if (!(DllGetClassObject = (DllGetClassObjectFunc)GetProcAddress(hLibrary, "DllGetClassObject"))) { + /* failure: the dll did not export DllGetClassObject */ + ERR("couldn't find function DllGetClassObject in %s\n", dllpath); + FreeLibrary( hLibrary ); + hres = CO_E_DLLNOTFOUND; + } else { + /* OK: get the ClassObject */ + COMPOBJ_DLLList_Add( hLibrary ); + return DllGetClassObject(rclsid, iid, ppv); + } + } + } + + /* Next try out of process */ + if (CLSCTX_LOCAL_SERVER & dwClsContext) + { + return RPC_GetLocalClassObject(rclsid,iid,ppv); + } + + /* Finally try remote: this requires networked DCOM (a lot of work) */ + if (CLSCTX_REMOTE_SERVER & dwClsContext) + { + FIXME ("CLSCTX_REMOTE_SERVER not supported\n"); + hres = E_NOINTERFACE; + } + + return hres; +} +/*********************************************************************** + * CoResumeClassObjects (OLE32.@) + * + * Resumes all class objects registered with REGCLS_SUSPENDED. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + */ +HRESULT WINAPI CoResumeClassObjects(void) +{ + FIXME("stub\n"); + return S_OK; +} + +/*********************************************************************** + * GetClassFile (OLE32.@) + * + * This function supplies the CLSID associated with the given filename. + */ +HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid) +{ + IStorage *pstg=0; + HRESULT res; + int nbElm, length, i; + LONG sizeProgId; + LPOLESTR *pathDec=0,absFile=0,progId=0; + LPWSTR extension; + static const WCHAR bkslashW[] = {'\\',0}; + static const WCHAR dotW[] = {'.',0}; + + TRACE("%s, %p\n", debugstr_w(filePathName), pclsid); + + /* if the file contain a storage object the return the CLSID written by IStorage_SetClass method*/ + if((StgIsStorageFile(filePathName))==S_OK){ + + res=StgOpenStorage(filePathName,NULL,STGM_READ | STGM_SHARE_DENY_WRITE,NULL,0,&pstg); + + if (SUCCEEDED(res)) + res=ReadClassStg(pstg,pclsid); + + IStorage_Release(pstg); + + return res; + } + /* if the file is not a storage object then attemps to match various bits in the file against a + pattern in the registry. this case is not frequently used ! so I present only the psodocode for + this case + + for(i=0;i<nFileTypes;i++) + + for(i=0;j<nPatternsForType;j++){ + + PATTERN pat; + HANDLE hFile; + + pat=ReadPatternFromRegistry(i,j); + hFile=CreateFileW(filePathName,,,,,,hFile); + SetFilePosition(hFile,pat.offset); + ReadFile(hFile,buf,pat.size,&r,NULL); + if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){ + + *pclsid=ReadCLSIDFromRegistry(i); + return S_OK; + } + } + */ + + /* if the above strategies fail then search for the extension key in the registry */ + + /* get the last element (absolute file) in the path name */ + nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec); + absFile=pathDec[nbElm-1]; + + /* failed if the path represente a directory and not an absolute file name*/ + if (!lstrcmpW(absFile, bkslashW)) + return MK_E_INVALIDEXTENSION; + + /* get the extension of the file */ + extension = NULL; + length=lstrlenW(absFile); + for(i = length-1; (i >= 0) && *(extension = &absFile[i]) != '.'; i--) + /* nothing */; + + if (!extension || !lstrcmpW(extension, dotW)) + return MK_E_INVALIDEXTENSION; + + res=RegQueryValueW(HKEY_CLASSES_ROOT, extension, NULL, &sizeProgId); + + /* get the progId associated to the extension */ + progId = CoTaskMemAlloc(sizeProgId); + res = RegQueryValueW(HKEY_CLASSES_ROOT, extension, progId, &sizeProgId); + + if (res==ERROR_SUCCESS) + /* return the clsid associated to the progId */ + res= CLSIDFromProgID(progId,pclsid); + + for(i=0; pathDec[i]!=NULL;i++) + CoTaskMemFree(pathDec[i]); + CoTaskMemFree(pathDec); + + CoTaskMemFree(progId); + + if (res==ERROR_SUCCESS) + return res; + + return MK_E_INVALIDEXTENSION; +} +/*********************************************************************** + * CoCreateInstance [COMPOBJ.13] + * CoCreateInstance [OLE32.@] + */ +HRESULT WINAPI CoCreateInstance( + REFCLSID rclsid, + LPUNKNOWN pUnkOuter, + DWORD dwClsContext, + REFIID iid, + LPVOID *ppv) +{ + HRESULT hres; + LPCLASSFACTORY lpclf = 0; + + if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED; + + /* + * Sanity check + */ + if (ppv==0) + return E_POINTER; + + /* + * Initialize the "out" parameter + */ + *ppv = 0; + + /* + * The Standard Global Interface Table (GIT) object is a process-wide singleton. + * Rather than create a class factory, we can just check for it here + */ + if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) { + if (StdGlobalInterfaceTableInstance == NULL) + StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct(); + hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv); + if (hres) return hres; + + TRACE("Retrieved GIT (%p)\n", *ppv); + return S_OK; + } + + /* + * Get a class factory to construct the object we want. + */ + hres = CoGetClassObject(rclsid, + dwClsContext, + NULL, + &IID_IClassFactory, + (LPVOID)&lpclf); + + if (FAILED(hres)) { + FIXME("no classfactory created for CLSID %s, hres is 0x%08lx\n", + debugstr_guid(rclsid),hres); + return hres; + } + + /* + * Create the object and don't forget to release the factory + */ + hres = IClassFactory_CreateInstance(lpclf, pUnkOuter, iid, ppv); + IClassFactory_Release(lpclf); + if(FAILED(hres)) + FIXME("no instance created for interface %s of class %s, hres is 0x%08lx\n", + debugstr_guid(iid), debugstr_guid(rclsid),hres); + + return hres; +} + +/*********************************************************************** + * CoCreateInstanceEx [OLE32.@] + */ +HRESULT WINAPI CoCreateInstanceEx( + REFCLSID rclsid, + LPUNKNOWN pUnkOuter, + DWORD dwClsContext, + COSERVERINFO* pServerInfo, + ULONG cmq, + MULTI_QI* pResults) +{ + IUnknown* pUnk = NULL; + HRESULT hr; + ULONG index; + ULONG successCount = 0; + + /* + * Sanity check + */ + if ( (cmq==0) || (pResults==NULL)) + return E_INVALIDARG; + + if (pServerInfo!=NULL) + FIXME("() non-NULL pServerInfo not supported!\n"); + + /* + * Initialize all the "out" parameters. + */ + for (index = 0; index < cmq; index++) + { + pResults[index].pItf = NULL; + pResults[index].hr = E_NOINTERFACE; + } + + /* + * Get the object and get its IUnknown pointer. + */ + hr = CoCreateInstance(rclsid, + pUnkOuter, + dwClsContext, + &IID_IUnknown, + (VOID**)&pUnk); + + if (hr) + return hr; + + /* + * Then, query for all the interfaces requested. + */ + for (index = 0; index < cmq; index++) + { + pResults[index].hr = IUnknown_QueryInterface(pUnk, + pResults[index].pIID, + (VOID**)&(pResults[index].pItf)); + + if (pResults[index].hr == S_OK) + successCount++; + } + + /* + * Release our temporary unknown pointer. + */ + IUnknown_Release(pUnk); + + if (successCount == 0) + return E_NOINTERFACE; + + if (successCount!=cmq) + return CO_S_NOTALLINTERFACES; + + return S_OK; +} + +/*********************************************************************** + * CoLoadLibrary (OLE32.@) + * + * Loads a library. + * + * PARAMS + * lpszLibName [I] Path to library. + * bAutoFree [I] Whether the library should automatically be freed. + * + * RETURNS + * Success: Handle to loaded library. + * Failure: NULL. + * + * SEE ALSO + * CoFreeLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries + */ +HINSTANCE WINAPI CoLoadLibrary(LPOLESTR lpszLibName, BOOL bAutoFree) +{ + TRACE("(%s, %d)\n", debugstr_w(lpszLibName), bAutoFree); + + return LoadLibraryExW(lpszLibName, 0, LOAD_WITH_ALTERED_SEARCH_PATH); +} + +/*********************************************************************** + * CoFreeLibrary [OLE32.@] + * + * Unloads a library from memory. + * + * PARAMS + * hLibrary [I] Handle to library to unload. + * + * RETURNS + * Nothing + * + * SEE ALSO + * CoLoadLibrary, CoFreeAllLibraries, CoFreeUnusedLibraries + */ +void WINAPI CoFreeLibrary(HINSTANCE hLibrary) +{ + FreeLibrary(hLibrary); +} + + +/*********************************************************************** + * CoFreeAllLibraries [OLE32.@] + * + * Function for backwards compatibility only. Does nothing. + * + * RETURNS + * Nothing. + * + * SEE ALSO + * CoLoadLibrary, CoFreeLibrary, CoFreeUnusedLibraries + */ +void WINAPI CoFreeAllLibraries(void) +{ + /* NOP */ +} + + +/*********************************************************************** + * CoFreeUnusedLibraries [OLE32.@] + * CoFreeUnusedLibraries [COMPOBJ.17] + * + * Frees any unused libraries. Unused are identified as those that return + * S_OK from their DllCanUnloadNow function. + * + * RETURNS + * Nothing. + * + * SEE ALSO + * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary + */ +void WINAPI CoFreeUnusedLibraries(void) +{ + /* FIXME: Calls to CoFreeUnusedLibraries from any thread always route + * through the main apartment's thread to call DllCanUnloadNow */ + COMPOBJ_DllList_FreeUnused(0); +} + +/*********************************************************************** + * CoFileTimeNow [OLE32.@] + * CoFileTimeNow [COMPOBJ.82] + * + * Retrieves the current time in FILETIME format. + * + * PARAMS + * lpFileTime [O] The current time. + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI CoFileTimeNow( FILETIME *lpFileTime ) +{ + GetSystemTimeAsFileTime( lpFileTime ); + return S_OK; +} + +static void COM_RevokeAllClasses() +{ + EnterCriticalSection( &csRegisteredClassList ); + + while (firstRegisteredClass!=0) + { + CoRevokeClassObject(firstRegisteredClass->dwCookie); + } + + LeaveCriticalSection( &csRegisteredClassList ); +} + +/****************************************************************************** + * CoLockObjectExternal [OLE32.@] + * + * Increments or decrements the external reference count of a stub object. + * + * PARAMS + * pUnk [I] Stub object. + * fLock [I] If TRUE then increments the external ref-count, + * otherwise decrements. + * fLastUnlockReleases [I] If TRUE then the last unlock has the effect of + * calling CoDisconnectObject. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + */ +HRESULT WINAPI CoLockObjectExternal( + LPUNKNOWN pUnk, + BOOL fLock, + BOOL fLastUnlockReleases) +{ + struct stub_manager *stubmgr; + struct apartment *apt; + + TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n", + pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE"); + + apt = COM_CurrentApt(); + if (!apt) return CO_E_NOTINITIALIZED; + + stubmgr = get_stub_manager_from_object(apt, pUnk); + + if (stubmgr) + { + if (fLock) + stub_manager_ext_addref(stubmgr, 1); + else + stub_manager_ext_release(stubmgr, 1); + + stub_manager_int_release(stubmgr); + + return S_OK; + } + else + { + WARN("stub object not found %p\n", pUnk); + /* Note: native is pretty broken here because it just silently + * fails, without returning an appropriate error code, making apps + * think that the object was disconnected, when it actually wasn't */ + return S_OK; + } +} + +/*********************************************************************** + * CoInitializeWOW (OLE32.@) + * + * WOW equivalent of CoInitialize? + * + * PARAMS + * x [I] Unknown. + * y [I] Unknown. + * + * RETURNS + * Unknown. + */ +HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) +{ + FIXME("(0x%08lx,0x%08lx),stub!\n",x,y); + return 0; +} + +/*********************************************************************** + * CoGetState [OLE32.@] + * + * Retrieves the thread state object previously stored by CoSetState(). + * + * PARAMS + * ppv [I] Address where pointer to object will be stored. + * + * RETURNS + * Success: S_OK. + * Failure: E_OUTOFMEMORY. + * + * NOTES + * Crashes on all invalid ppv addresses, including NULL. + * If the function returns a non-NULL object then the caller must release its + * reference on the object when the object is no longer required. + * + * SEE ALSO + * CoSetState(). + */ +HRESULT WINAPI CoGetState(IUnknown ** ppv) +{ + struct oletls *info = COM_CurrentInfo(); + if (!info) return E_OUTOFMEMORY; + + *ppv = NULL; + + if (info->state) + { + IUnknown_AddRef(info->state); + *ppv = info->state; + TRACE("apt->state=%p\n", info->state); + } + + return S_OK; +} + +/*********************************************************************** + * CoSetState [OLE32.@] + * + * Sets the thread state object. + * + * PARAMS + * pv [I] Pointer to state object to be stored. + * + * NOTES + * The system keeps a reference on the object while the object stored. + * + * RETURNS + * Success: S_OK. + * Failure: E_OUTOFMEMORY. + */ +HRESULT WINAPI CoSetState(IUnknown * pv) +{ + struct oletls *info = COM_CurrentInfo(); + if (!info) return E_OUTOFMEMORY; + + if (pv) IUnknown_AddRef(pv); + + if (info->state) + { + TRACE("-- release %p now\n", info->state); + IUnknown_Release(info->state); + } + + info->state = pv; + + return S_OK; +} + + +/****************************************************************************** + * OleGetAutoConvert [OLE32.@] + */ +HRESULT WINAPI OleGetAutoConvert(REFCLSID clsidOld, LPCLSID pClsidNew) +{ + HKEY hkey = 0; + char buf[200]; + WCHAR wbuf[200]; + DWORD len; + HRESULT res = S_OK; + + sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]); + if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey)) + { + res = REGDB_E_CLASSNOTREG; + goto done; + } + len = 200; + /* we can just query for the default value of AutoConvertTo key like that, + without opening the AutoConvertTo key and querying for NULL (default) */ + if (RegQueryValueA(hkey,"AutoConvertTo",buf,&len)) + { + res = REGDB_E_KEYMISSING; + goto done; + } + MultiByteToWideChar( CP_ACP, 0, buf, -1, wbuf, sizeof(wbuf)/sizeof(WCHAR) ); + CLSIDFromString(wbuf,pClsidNew); +done: + if (hkey) RegCloseKey(hkey); + return res; +} + +/****************************************************************************** + * CoTreatAsClass [OLE32.@] + * + * Sets the TreatAs value of a class. + * + * PARAMS + * clsidOld [I] Class to set TreatAs value on. + * clsidNew [I] The class the clsidOld should be treated as. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * SEE ALSO + * CoGetTreatAsClass + */ +HRESULT WINAPI CoTreatAsClass(REFCLSID clsidOld, REFCLSID clsidNew) +{ + HKEY hkey = 0; + char buf[47]; + char szClsidNew[39]; + HRESULT res = S_OK; + char auto_treat_as[39]; + LONG auto_treat_as_size = sizeof(auto_treat_as); + CLSID id; + + sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]); + WINE_StringFromCLSID(clsidNew, szClsidNew); + if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey)) + { + res = REGDB_E_CLASSNOTREG; + goto done; + } + if (!memcmp( clsidOld, clsidNew, sizeof(*clsidOld) )) + { + if (!RegQueryValueA(hkey, "AutoTreatAs", auto_treat_as, &auto_treat_as_size) && + !__CLSIDFromStringA(auto_treat_as, &id)) + { + if (RegSetValueA(hkey, "TreatAs", REG_SZ, auto_treat_as, strlen(auto_treat_as)+1)) + { + res = REGDB_E_WRITEREGDB; + goto done; + } + } + else + { + RegDeleteKeyA(hkey, "TreatAs"); + goto done; + } + } + else if (RegSetValueA(hkey, "TreatAs", REG_SZ, szClsidNew, strlen(szClsidNew)+1)) + { + res = REGDB_E_WRITEREGDB; + goto done; + } + +done: + if (hkey) RegCloseKey(hkey); + return res; +} + +/****************************************************************************** + * CoGetTreatAsClass [OLE32.@] + * + * Gets the TreatAs value of a class. + * + * PARAMS + * clsidOld [I] Class to get the TreatAs value of. + * clsidNew [I] The class the clsidOld should be treated as. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * SEE ALSO + * CoSetTreatAsClass + */ +HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew) +{ + HKEY hkey = 0; + char buf[200], szClsidNew[200]; + HRESULT res = S_OK; + LONG len = sizeof(szClsidNew); + + FIXME("(%s,%p)\n", debugstr_guid(clsidOld), clsidNew); + sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]); + memcpy(clsidNew,clsidOld,sizeof(CLSID)); /* copy over old value */ + + if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey)) + { + res = REGDB_E_CLASSNOTREG; + goto done; + } + if (RegQueryValueA(hkey, "TreatAs", szClsidNew, &len)) + { + res = S_FALSE; + goto done; + } + res = __CLSIDFromStringA(szClsidNew,clsidNew); + if (FAILED(res)) + FIXME("Failed CLSIDFromStringA(%s), hres %lx?\n",szClsidNew,res); +done: + if (hkey) RegCloseKey(hkey); + return res; + +} + +/****************************************************************************** + * CoGetCurrentProcess [OLE32.@] + * CoGetCurrentProcess [COMPOBJ.34] + * + * Gets the current process ID. + * + * RETURNS + * The current process ID. + * + * NOTES + * Is DWORD really the correct return type for this function? + */ +DWORD WINAPI CoGetCurrentProcess(void) +{ + return GetCurrentProcessId(); +} + +/****************************************************************************** + * CoRegisterMessageFilter [OLE32.@] + * + * Registers a message filter. + * + * PARAMS + * lpMessageFilter [I] Pointer to interface. + * lplpMessageFilter [O] Indirect pointer to prior instance if non-NULL. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + */ +HRESULT WINAPI CoRegisterMessageFilter( + LPMESSAGEFILTER lpMessageFilter, + LPMESSAGEFILTER *lplpMessageFilter) +{ + FIXME("stub\n"); + if (lplpMessageFilter) { + *lplpMessageFilter = NULL; + } + return S_OK; +} + +/*********************************************************************** + * CoIsOle1Class [OLE32.@] + * + * Determines whether the specified class an OLE v1 class. + * + * PARAMS + * clsid [I] Class to test. + * + * RETURNS + * TRUE if the class is an OLE v1 class, or FALSE otherwise. + */ +BOOL WINAPI CoIsOle1Class(REFCLSID clsid) +{ + FIXME("%s\n", debugstr_guid(clsid)); + return FALSE; +} + +/*********************************************************************** + * IsEqualGUID [OLE32.@] + * + * Compares two Unique Identifiers. + * + * PARAMS + * rguid1 [I] The first GUID to compare. + * rguid2 [I] The other GUID to compare. + * + * RETURNS + * TRUE if equal + */ +#undef IsEqualGUID +BOOL WINAPI IsEqualGUID( + REFGUID rguid1, + REFGUID rguid2) +{ + return !memcmp(rguid1,rguid2,sizeof(GUID)); +} + +/*********************************************************************** + * CoInitializeSecurity [OLE32.@] + */ +HRESULT WINAPI CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc, + SOLE_AUTHENTICATION_SERVICE* asAuthSvc, + void* pReserved1, DWORD dwAuthnLevel, + DWORD dwImpLevel, void* pReserved2, + DWORD dwCapabilities, void* pReserved3) +{ + FIXME("(%p,%ld,%p,%p,%ld,%ld,%p,%ld,%p) - stub!\n", pSecDesc, cAuthSvc, + asAuthSvc, pReserved1, dwAuthnLevel, dwImpLevel, pReserved2, + dwCapabilities, pReserved3); + return S_OK; +} + +/*********************************************************************** + * CoSuspendClassObjects [OLE32.@] + * + * Suspends all registered class objects to prevent further requests coming in + * for those objects. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + */ +HRESULT WINAPI CoSuspendClassObjects(void) +{ + FIXME("\n"); + return S_OK; +} + +/*********************************************************************** + * CoAddRefServerProcess [OLE32.@] + * + * Helper function for incrementing the reference count of a local-server + * process. + * + * RETURNS + * New reference count. + */ +ULONG WINAPI CoAddRefServerProcess(void) +{ + FIXME("\n"); + return 2; +} + +/*********************************************************************** + * CoReleaseServerProcess [OLE32.@] + * + * Helper function for decrementing the reference count of a local-server + * process. + * + * RETURNS + * New reference count. + */ +ULONG WINAPI CoReleaseServerProcess(void) +{ + FIXME("\n"); + return 1; +} + +/*********************************************************************** + * CoIsHandlerConnected [OLE32.@] + * + * Determines whether a proxy is connected to a remote stub. + * + * PARAMS + * pUnk [I] Pointer to object that may or may not be connected. + * + * RETURNS + * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or + * FALSE otherwise. + */ +BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk) +{ + FIXME("%p\n", pUnk); + + return TRUE; +} + +/*********************************************************************** + * CoQueryProxyBlanket [OLE32.@] + * + * Retrieves the security settings being used by a proxy. + * + * PARAMS + * pProxy [I] Pointer to the proxy object. + * pAuthnSvc [O] The type of authentication service. + * pAuthzSvc [O] The type of authorization service. + * ppServerPrincName [O] Optional. The server prinicple name. + * pAuthnLevel [O] The authentication level. + * pImpLevel [O] The impersonation level. + * ppAuthInfo [O] Information specific to the authorization/authentication service. + * pCapabilities [O] Flags affecting the security behaviour. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * SEE ALSO + * CoCopyProxy, CoSetProxyBlanket. + */ +HRESULT WINAPI CoQueryProxyBlanket(IUnknown *pProxy, DWORD *pAuthnSvc, + DWORD *pAuthzSvc, OLECHAR **ppServerPrincName, DWORD *pAuthnLevel, + DWORD *pImpLevel, void **ppAuthInfo, DWORD *pCapabilities) +{ + IClientSecurity *pCliSec; + HRESULT hr; + + TRACE("%p\n", pProxy); + + hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec); + if (SUCCEEDED(hr)) + { + hr = IClientSecurity_QueryBlanket(pCliSec, pProxy, pAuthnSvc, + pAuthzSvc, ppServerPrincName, + pAuthnLevel, pImpLevel, ppAuthInfo, + pCapabilities); + IClientSecurity_Release(pCliSec); + } + + if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr); + return hr; +} + +/*********************************************************************** + * CoSetProxyBlanket [OLE32.@] + * + * Sets the security settings for a proxy. + * + * PARAMS + * pProxy [I] Pointer to the proxy object. + * AuthnSvc [I] The type of authentication service. + * AuthzSvc [I] The type of authorization service. + * pServerPrincName [I] The server prinicple name. + * AuthnLevel [I] The authentication level. + * ImpLevel [I] The impersonation level. + * pAuthInfo [I] Information specific to the authorization/authentication service. + * Capabilities [I] Flags affecting the security behaviour. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * SEE ALSO + * CoQueryProxyBlanket, CoCopyProxy. + */ +HRESULT WINAPI CoSetProxyBlanket(IUnknown *pProxy, DWORD AuthnSvc, + DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel, + DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities) +{ + IClientSecurity *pCliSec; + HRESULT hr; + + TRACE("%p\n", pProxy); + + hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec); + if (SUCCEEDED(hr)) + { + hr = IClientSecurity_SetBlanket(pCliSec, pProxy, AuthnSvc, + AuthzSvc, pServerPrincName, + AuthnLevel, ImpLevel, pAuthInfo, + Capabilities); + IClientSecurity_Release(pCliSec); + } + + if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr); + return hr; +} + +/*********************************************************************** + * CoCopyProxy [OLE32.@] + * + * Copies a proxy. + * + * PARAMS + * pProxy [I] Pointer to the proxy object. + * ppCopy [O] Copy of the proxy. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * SEE ALSO + * CoQueryProxyBlanket, CoSetProxyBlanket. + */ +HRESULT WINAPI CoCopyProxy(IUnknown *pProxy, IUnknown **ppCopy) +{ + IClientSecurity *pCliSec; + HRESULT hr; + + TRACE("%p\n", pProxy); + + hr = IUnknown_QueryInterface(pProxy, &IID_IClientSecurity, (void **)&pCliSec); + if (SUCCEEDED(hr)) + { + hr = IClientSecurity_CopyProxy(pCliSec, pProxy, ppCopy); + IClientSecurity_Release(pCliSec); + } + + if (FAILED(hr)) ERR("-- failed with 0x%08lx\n", hr); + return hr; +} + + +/*********************************************************************** + * CoWaitForMultipleHandles [OLE32.@] + * + * Waits for one or more handles to become signaled. + * + * PARAMS + * dwFlags [I] Flags. See notes. + * dwTimeout [I] Timeout in milliseconds. + * cHandles [I] Number of handles pointed to by pHandles. + * pHandles [I] Handles to wait for. + * lpdwindex [O] Index of handle that was signaled. + * + * RETURNS + * Success: S_OK. + * Failure: RPC_S_CALLPENDING on timeout. + * + * NOTES + * + * The dwFlags parameter can be zero or more of the following: + *| COWAIT_WAITALL - Wait for all of the handles to become signaled. + *| COWAIT_ALERTABLE - Allows a queued APC to run during the wait. + * + * SEE ALSO + * MsgWaitForMultipleObjects, WaitForMultipleObjects. + */ +HRESULT WINAPI CoWaitForMultipleHandles(DWORD dwFlags, DWORD dwTimeout, + ULONG cHandles, const HANDLE* pHandles, LPDWORD lpdwindex) +{ + HRESULT hr = S_OK; + DWORD wait_flags = (dwFlags & COWAIT_WAITALL) ? MWMO_WAITALL : 0 | + (dwFlags & COWAIT_ALERTABLE ) ? MWMO_ALERTABLE : 0; + DWORD start_time = GetTickCount(); + + TRACE("(0x%08lx, 0x%08lx, %ld, %p, %p)\n", dwFlags, dwTimeout, cHandles, + pHandles, lpdwindex); + + while (TRUE) + { + DWORD now = GetTickCount(); + DWORD res; + + if ((dwTimeout != INFINITE) && (start_time + dwTimeout >= now)) + { + hr = RPC_S_CALLPENDING; + break; + } + + TRACE("waiting for rpc completion or window message\n"); + + res = MsgWaitForMultipleObjectsEx(cHandles, pHandles, + (dwTimeout == INFINITE) ? INFINITE : start_time + dwTimeout - now, + QS_ALLINPUT, wait_flags); + + if (res == WAIT_OBJECT_0 + cHandles) /* messages available */ + { + MSG msg; + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) + { + /* FIXME: filter the messages here */ + TRACE("received message whilst waiting for RPC: 0x%04x\n", msg.message); + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + else if ((res >= WAIT_OBJECT_0) && (res < WAIT_OBJECT_0 + cHandles)) + { + /* handle signaled, store index */ + *lpdwindex = (res - WAIT_OBJECT_0); + break; + } + else if (res == WAIT_TIMEOUT) + { + hr = RPC_S_CALLPENDING; + break; + } + else + { + ERR("Unexpected wait termination: %ld, %ld\n", res, GetLastError()); + hr = E_UNEXPECTED; + break; + } + } + TRACE("-- 0x%08lx\n", hr); + return hr; +} + +/*********************************************************************** + * DllMain (OLE32.@) + */ +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad) +{ + TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad); + + switch(fdwReason) { + case DLL_PROCESS_ATTACH: + OLE32_hInstance = hinstDLL; + COMPOBJ_InitProcess(); + if (TRACE_ON(ole)) CoRegisterMallocSpy((LPVOID)-1); + break; + + case DLL_PROCESS_DETACH: + if (TRACE_ON(ole)) CoRevokeMallocSpy(); + COMPOBJ_UninitProcess(); + OLE32_hInstance = 0; + break; + + case DLL_THREAD_DETACH: + COM_TlsDestroy(); + break; + } + return TRUE; +} + +/* NOTE: DllRegisterServer and DllUnregisterServer are in regsvr.c */ diff --git a/reactos/lib/ole32/compobj_private.h b/reactos/lib/ole32/compobj_private.h index 816e07ac110..7e5ddbb64ca 100644 --- a/reactos/lib/ole32/compobj_private.h +++ b/reactos/lib/ole32/compobj_private.h @@ -1,259 +1,259 @@ -/* - * Copyright 1995 Martin von Loewis - * Copyright 1998 Justin Bradford - * Copyright 1999 Francis Beaudet - * Copyright 1999 Sylvain St-Germain - * Copyright 2002 Marcus Meissner - * Copyright 2003 Ove KÃ¥ven, TransGaming Technologies - * Copyright 2004 Mike Hearn, Rob Shearman, CodeWeavers Inc - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_OLE_COMPOBJ_H -#define __WINE_OLE_COMPOBJ_H - -/* All private prototype functions used by OLE will be added to this header file */ - -#include <stdarg.h> - -#include "wine/list.h" - -#include "windef.h" -#include "winbase.h" -#include "wtypes.h" -#include "dcom.h" -#include "winreg.h" -#include "winternl.h" - -struct apartment; -typedef struct apartment APARTMENT; - -/* Thread-safety Annotation Legend: - * - * RO - The value is read only. It never changes after creation, so no - * locking is required. - * LOCK - The value is written to only using Interlocked* functions. - * CS - The value is read or written to inside a critical section. - * The identifier following "CS" is the specific critical setion that - * must be used. - * MUTEX - The value is read or written to with a mutex held. - * The identifier following "MUTEX" is the specific mutex that - * must be used. - */ - -typedef enum ifstub_state -{ - STUBSTATE_NORMAL_MARSHALED, - STUBSTATE_NORMAL_UNMARSHALED, - STUBSTATE_TABLE_WEAK_MARSHALED, - STUBSTATE_TABLE_WEAK_UNMARSHALED, - STUBSTATE_TABLE_STRONG, -} STUB_STATE; - -/* an interface stub */ -struct ifstub -{ - struct list entry; /* entry in stub_manager->ifstubs list (CS stub_manager->lock) */ - IRpcStubBuffer *stubbuffer; /* RO */ - IID iid; /* RO */ - IPID ipid; /* RO */ - IUnknown *iface; /* RO */ -}; - - -/* stub managers hold refs on the object and each interface stub */ -struct stub_manager -{ - struct list entry; /* entry in apartment stubmgr list (CS apt->cs) */ - struct list ifstubs; /* list of active ifstubs for the object (CS lock) */ - CRITICAL_SECTION lock; - APARTMENT *apt; /* owning apt (RO) */ - - ULONG extrefs; /* number of 'external' references (CS lock) */ - ULONG refs; /* internal reference count (CS apt->cs) */ - OID oid; /* apartment-scoped unique identifier (RO) */ - IUnknown *object; /* the object we are managing the stub for (RO) */ - ULONG next_ipid; /* currently unused (LOCK) */ - STUB_STATE state; /* state machine (CS lock) */ -}; - -/* imported interface proxy */ -struct ifproxy -{ - struct list entry; /* entry in proxy_manager list (CS parent->cs) */ - struct proxy_manager *parent; /* owning proxy_manager (RO) */ - LPVOID iface; /* interface pointer (RO) */ - IID iid; /* interface ID (RO) */ - IPID ipid; /* imported interface ID (RO) */ - LPRPCPROXYBUFFER proxy; /* interface proxy (RO) */ - DWORD refs; /* imported (public) references (MUTEX parent->remoting_mutex) */ - IRpcChannelBuffer *chan; /* channel to object (CS parent->cs) */ -}; - -/* imported object / proxy manager */ -struct proxy_manager -{ - const IMultiQIVtbl *lpVtbl; - struct apartment *parent; /* owning apartment (RO) */ - struct list entry; /* entry in apartment (CS parent->cs) */ - OXID oxid; /* object exported ID (RO) */ - OID oid; /* object ID (RO) */ - struct list interfaces; /* imported interfaces (CS cs) */ - DWORD refs; /* proxy reference count (LOCK) */ - CRITICAL_SECTION cs; /* thread safety for this object and children */ - ULONG sorflags; /* STDOBJREF flags (RO) */ - IRemUnknown *remunk; /* proxy to IRemUnknown used for lifecycle management (CS cs) */ - HANDLE remoting_mutex; /* mutex used for synchronizing access to IRemUnknown */ -}; - -/* this needs to become a COM object that implements IRemUnknown */ -struct apartment -{ - struct list entry; - - DWORD refs; /* refcount of the apartment (LOCK) */ - DWORD model; /* threading model (RO) */ - DWORD tid; /* thread id (RO) */ - HANDLE thread; /* thread handle (RO) */ - OXID oxid; /* object exporter ID (RO) */ - DWORD ipidc; /* interface pointer ID counter, starts at 1 (LOCK) */ - HWND win; /* message window (RO) */ - CRITICAL_SECTION cs; /* thread safety */ - LPMESSAGEFILTER filter; /* message filter (CS cs) */ - struct list proxies; /* imported objects (CS cs) */ - struct list stubmgrs; /* stub managers for exported objects (CS cs) */ - BOOL remunk_exported; /* has the IRemUnknown interface for this apartment been created yet? (CS cs) */ - LONG remoting_started; /* has the RPC system been started for this apartment? (LOCK) */ - - /* FIXME: OID's should be given out by RPCSS */ - OID oidc; /* object ID counter, starts at 1, zero is invalid OID (CS cs) */ -}; - -/* this is what is stored in TEB->ReservedForOle */ -struct oletls -{ - struct apartment *apt; - IErrorInfo *errorinfo; /* see errorinfo.c */ - IUnknown *state; /* see CoSetState */ - DWORD inits; /* number of times CoInitializeEx called */ -}; - - -/* Global Interface Table Functions */ - -extern void* StdGlobalInterfaceTable_Construct(void); -extern void StdGlobalInterfaceTable_Destroy(void* self); -extern HRESULT StdGlobalInterfaceTable_GetFactory(LPVOID *ppv); -extern void* StdGlobalInterfaceTableInstance; - -/* FIXME: these shouldn't be needed, except for 16-bit functions */ -extern HRESULT WINE_StringFromCLSID(const CLSID *id,LPSTR idstr); -HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id); - -HRESULT MARSHAL_GetStandardMarshalCF(LPVOID *ppv); - -/* Stub Manager */ - -ULONG stub_manager_int_addref(struct stub_manager *This); -ULONG stub_manager_int_release(struct stub_manager *This); -struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object, MSHLFLAGS mshlflags); -ULONG stub_manager_ext_addref(struct stub_manager *m, ULONG refs); -ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs); -struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *sb, IUnknown *iptr, REFIID iid); -struct stub_manager *get_stub_manager(APARTMENT *apt, OID oid); -struct stub_manager *get_stub_manager_from_object(APARTMENT *apt, void *object); -BOOL stub_manager_notify_unmarshal(struct stub_manager *m); -BOOL stub_manager_is_table_marshaled(struct stub_manager *m); -void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs); -HRESULT ipid_to_stub_manager(const IPID *ipid, APARTMENT **stub_apt, struct stub_manager **stubmgr_ret); -IRpcStubBuffer *ipid_to_apt_and_stubbuffer(const IPID *ipid, APARTMENT **stub_apt); -HRESULT start_apartment_remote_unknown(void); - -HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *obj, MSHLFLAGS mshlflags); - -/* RPC Backend */ - -struct dispatch_params; - -void RPC_StartRemoting(struct apartment *apt); -HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, IRpcChannelBuffer **pipebuf); -HRESULT RPC_ExecuteCall(struct dispatch_params *params); -HRESULT RPC_RegisterInterface(REFIID riid); -void RPC_UnregisterInterface(REFIID riid); -void RPC_StartLocalServer(REFCLSID clsid, IStream *stream); -HRESULT RPC_GetLocalClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv); - -/* This function initialize the Running Object Table */ -HRESULT WINAPI RunningObjectTableImpl_Initialize(void); - -/* This function uninitialize the Running Object Table */ -HRESULT WINAPI RunningObjectTableImpl_UnInitialize(void); - -/* This function decomposes a String path to a String Table containing all the elements ("\" or "subDirectory" or "Directory" or "FileName") of the path */ -int FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable); - - -/* Apartment Functions */ - -APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref); -APARTMENT *apartment_findfromtid(DWORD tid); -DWORD apartment_addref(struct apartment *apt); -DWORD apartment_release(struct apartment *apt); -HRESULT apartment_disconnectproxies(struct apartment *apt); -void apartment_disconnectobject(struct apartment *apt, void *object); -static inline HRESULT apartment_getoxid(struct apartment *apt, OXID *oxid) -{ - *oxid = apt->oxid; - return S_OK; -} - - -/* DCOM messages used by the apartment window (not compatible with native) */ -#define DM_EXECUTERPC (WM_USER + 0) /* WPARAM = 0, LPARAM = (struct dispatch_params *) */ - -/* - * Per-thread values are stored in the TEB on offset 0xF80, - * see http://www.microsoft.com/msj/1099/bugslayer/bugslayer1099.htm - */ - -/* will create if necessary */ -static inline struct oletls *COM_CurrentInfo(void) -{ - if (!NtCurrentTeb()->ReservedForOle) - NtCurrentTeb()->ReservedForOle = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct oletls)); - - return NtCurrentTeb()->ReservedForOle; -} - -static inline APARTMENT* COM_CurrentApt(void) -{ - return COM_CurrentInfo()->apt; -} - -#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) - -/* helpers for debugging */ -#ifdef __i386__ -# define DEBUG_SET_CRITSEC_NAME(cs, name) (cs)->DebugInfo->Spare[1] = (DWORD)(__FILE__ ": " name) -# define DEBUG_CLEAR_CRITSEC_NAME(cs) (cs)->DebugInfo->Spare[1] = 0 -#else -# define DEBUG_SET_CRITSEC_NAME(cs, name) -# define DEBUG_CLEAR_CRITSEC_NAME(cs) -#endif - -extern HINSTANCE OLE32_hInstance; /* FIXME: make static */ - -#endif /* __WINE_OLE_COMPOBJ_H */ +/* + * Copyright 1995 Martin von Loewis + * Copyright 1998 Justin Bradford + * Copyright 1999 Francis Beaudet + * Copyright 1999 Sylvain St-Germain + * Copyright 2002 Marcus Meissner + * Copyright 2003 Ove KÃ¥ven, TransGaming Technologies + * Copyright 2004 Mike Hearn, Rob Shearman, CodeWeavers Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_OLE_COMPOBJ_H +#define __WINE_OLE_COMPOBJ_H + +/* All private prototype functions used by OLE will be added to this header file */ + +#include <stdarg.h> + +#include "wine/list.h" + +#include "windef.h" +#include "winbase.h" +#include "wtypes.h" +#include "dcom.h" +#include "winreg.h" +#include "winternl.h" + +struct apartment; +typedef struct apartment APARTMENT; + +/* Thread-safety Annotation Legend: + * + * RO - The value is read only. It never changes after creation, so no + * locking is required. + * LOCK - The value is written to only using Interlocked* functions. + * CS - The value is read or written to inside a critical section. + * The identifier following "CS" is the specific critical setion that + * must be used. + * MUTEX - The value is read or written to with a mutex held. + * The identifier following "MUTEX" is the specific mutex that + * must be used. + */ + +typedef enum ifstub_state +{ + STUBSTATE_NORMAL_MARSHALED, + STUBSTATE_NORMAL_UNMARSHALED, + STUBSTATE_TABLE_WEAK_MARSHALED, + STUBSTATE_TABLE_WEAK_UNMARSHALED, + STUBSTATE_TABLE_STRONG, +} STUB_STATE; + +/* an interface stub */ +struct ifstub +{ + struct list entry; /* entry in stub_manager->ifstubs list (CS stub_manager->lock) */ + IRpcStubBuffer *stubbuffer; /* RO */ + IID iid; /* RO */ + IPID ipid; /* RO */ + IUnknown *iface; /* RO */ +}; + + +/* stub managers hold refs on the object and each interface stub */ +struct stub_manager +{ + struct list entry; /* entry in apartment stubmgr list (CS apt->cs) */ + struct list ifstubs; /* list of active ifstubs for the object (CS lock) */ + CRITICAL_SECTION lock; + APARTMENT *apt; /* owning apt (RO) */ + + ULONG extrefs; /* number of 'external' references (CS lock) */ + ULONG refs; /* internal reference count (CS apt->cs) */ + OID oid; /* apartment-scoped unique identifier (RO) */ + IUnknown *object; /* the object we are managing the stub for (RO) */ + ULONG next_ipid; /* currently unused (LOCK) */ + STUB_STATE state; /* state machine (CS lock) */ +}; + +/* imported interface proxy */ +struct ifproxy +{ + struct list entry; /* entry in proxy_manager list (CS parent->cs) */ + struct proxy_manager *parent; /* owning proxy_manager (RO) */ + LPVOID iface; /* interface pointer (RO) */ + IID iid; /* interface ID (RO) */ + IPID ipid; /* imported interface ID (RO) */ + LPRPCPROXYBUFFER proxy; /* interface proxy (RO) */ + DWORD refs; /* imported (public) references (MUTEX parent->remoting_mutex) */ + IRpcChannelBuffer *chan; /* channel to object (CS parent->cs) */ +}; + +/* imported object / proxy manager */ +struct proxy_manager +{ + const IMultiQIVtbl *lpVtbl; + struct apartment *parent; /* owning apartment (RO) */ + struct list entry; /* entry in apartment (CS parent->cs) */ + OXID oxid; /* object exported ID (RO) */ + OID oid; /* object ID (RO) */ + struct list interfaces; /* imported interfaces (CS cs) */ + DWORD refs; /* proxy reference count (LOCK) */ + CRITICAL_SECTION cs; /* thread safety for this object and children */ + ULONG sorflags; /* STDOBJREF flags (RO) */ + IRemUnknown *remunk; /* proxy to IRemUnknown used for lifecycle management (CS cs) */ + HANDLE remoting_mutex; /* mutex used for synchronizing access to IRemUnknown */ +}; + +/* this needs to become a COM object that implements IRemUnknown */ +struct apartment +{ + struct list entry; + + DWORD refs; /* refcount of the apartment (LOCK) */ + DWORD model; /* threading model (RO) */ + DWORD tid; /* thread id (RO) */ + HANDLE thread; /* thread handle (RO) */ + OXID oxid; /* object exporter ID (RO) */ + DWORD ipidc; /* interface pointer ID counter, starts at 1 (LOCK) */ + HWND win; /* message window (RO) */ + CRITICAL_SECTION cs; /* thread safety */ + LPMESSAGEFILTER filter; /* message filter (CS cs) */ + struct list proxies; /* imported objects (CS cs) */ + struct list stubmgrs; /* stub managers for exported objects (CS cs) */ + BOOL remunk_exported; /* has the IRemUnknown interface for this apartment been created yet? (CS cs) */ + LONG remoting_started; /* has the RPC system been started for this apartment? (LOCK) */ + + /* FIXME: OID's should be given out by RPCSS */ + OID oidc; /* object ID counter, starts at 1, zero is invalid OID (CS cs) */ +}; + +/* this is what is stored in TEB->ReservedForOle */ +struct oletls +{ + struct apartment *apt; + IErrorInfo *errorinfo; /* see errorinfo.c */ + IUnknown *state; /* see CoSetState */ + DWORD inits; /* number of times CoInitializeEx called */ +}; + + +/* Global Interface Table Functions */ + +extern void* StdGlobalInterfaceTable_Construct(void); +extern void StdGlobalInterfaceTable_Destroy(void* self); +extern HRESULT StdGlobalInterfaceTable_GetFactory(LPVOID *ppv); +extern void* StdGlobalInterfaceTableInstance; + +/* FIXME: these shouldn't be needed, except for 16-bit functions */ +extern HRESULT WINE_StringFromCLSID(const CLSID *id,LPSTR idstr); +HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id); + +HRESULT MARSHAL_GetStandardMarshalCF(LPVOID *ppv); + +/* Stub Manager */ + +ULONG stub_manager_int_addref(struct stub_manager *This); +ULONG stub_manager_int_release(struct stub_manager *This); +struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object, MSHLFLAGS mshlflags); +ULONG stub_manager_ext_addref(struct stub_manager *m, ULONG refs); +ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs); +struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *sb, IUnknown *iptr, REFIID iid); +struct stub_manager *get_stub_manager(APARTMENT *apt, OID oid); +struct stub_manager *get_stub_manager_from_object(APARTMENT *apt, void *object); +BOOL stub_manager_notify_unmarshal(struct stub_manager *m); +BOOL stub_manager_is_table_marshaled(struct stub_manager *m); +void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs); +HRESULT ipid_to_stub_manager(const IPID *ipid, APARTMENT **stub_apt, struct stub_manager **stubmgr_ret); +IRpcStubBuffer *ipid_to_apt_and_stubbuffer(const IPID *ipid, APARTMENT **stub_apt); +HRESULT start_apartment_remote_unknown(void); + +HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *obj, MSHLFLAGS mshlflags); + +/* RPC Backend */ + +struct dispatch_params; + +void RPC_StartRemoting(struct apartment *apt); +HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, IRpcChannelBuffer **pipebuf); +HRESULT RPC_ExecuteCall(struct dispatch_params *params); +HRESULT RPC_RegisterInterface(REFIID riid); +void RPC_UnregisterInterface(REFIID riid); +void RPC_StartLocalServer(REFCLSID clsid, IStream *stream); +HRESULT RPC_GetLocalClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv); + +/* This function initialize the Running Object Table */ +HRESULT WINAPI RunningObjectTableImpl_Initialize(void); + +/* This function uninitialize the Running Object Table */ +HRESULT WINAPI RunningObjectTableImpl_UnInitialize(void); + +/* This function decomposes a String path to a String Table containing all the elements ("\" or "subDirectory" or "Directory" or "FileName") of the path */ +int FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable); + + +/* Apartment Functions */ + +APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref); +APARTMENT *apartment_findfromtid(DWORD tid); +DWORD apartment_addref(struct apartment *apt); +DWORD apartment_release(struct apartment *apt); +HRESULT apartment_disconnectproxies(struct apartment *apt); +void apartment_disconnectobject(struct apartment *apt, void *object); +static inline HRESULT apartment_getoxid(struct apartment *apt, OXID *oxid) +{ + *oxid = apt->oxid; + return S_OK; +} + + +/* DCOM messages used by the apartment window (not compatible with native) */ +#define DM_EXECUTERPC (WM_USER + 0) /* WPARAM = 0, LPARAM = (struct dispatch_params *) */ + +/* + * Per-thread values are stored in the TEB on offset 0xF80, + * see http://www.microsoft.com/msj/1099/bugslayer/bugslayer1099.htm + */ + +/* will create if necessary */ +static inline struct oletls *COM_CurrentInfo(void) +{ + if (!NtCurrentTeb()->ReservedForOle) + NtCurrentTeb()->ReservedForOle = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct oletls)); + + return NtCurrentTeb()->ReservedForOle; +} + +static inline APARTMENT* COM_CurrentApt(void) +{ + return COM_CurrentInfo()->apt; +} + +#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) + +/* helpers for debugging */ +#ifdef __i386__ +# define DEBUG_SET_CRITSEC_NAME(cs, name) (cs)->DebugInfo->Spare[1] = (DWORD)(__FILE__ ": " name) +# define DEBUG_CLEAR_CRITSEC_NAME(cs) (cs)->DebugInfo->Spare[1] = 0 +#else +# define DEBUG_SET_CRITSEC_NAME(cs, name) +# define DEBUG_CLEAR_CRITSEC_NAME(cs) +#endif + +extern HINSTANCE OLE32_hInstance; /* FIXME: make static */ + +#endif /* __WINE_OLE_COMPOBJ_H */ diff --git a/reactos/lib/ole32/compositemoniker.c b/reactos/lib/ole32/compositemoniker.c index 9ab1d0c2494..cb3015cd50a 100644 --- a/reactos/lib/ole32/compositemoniker.c +++ b/reactos/lib/ole32/compositemoniker.c @@ -1,1698 +1,1698 @@ -/* - * CompositeMonikers implementation - * - * Copyright 1999 Noomen Hamza - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <assert.h> -#include <stdarg.h> -#include <string.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "winerror.h" -#include "wine/debug.h" -#include "wine/unicode.h" -#include "ole2.h" -#include "moniker.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -const CLSID CLSID_CompositeMoniker = { - 0x309, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46} -}; - -#define BLOCK_TAB_SIZE 5 /* represent the first size table and it's increment block size */ - -/* CompositeMoniker data structure */ -typedef struct CompositeMonikerImpl{ - - IMonikerVtbl* lpvtbl1; /* VTable relative to the IMoniker interface.*/ - - /* The ROT (RunningObjectTable implementation) uses the IROTData - * interface to test whether two monikers are equal. That's why IROTData - * interface is implemented by monikers. - */ - IROTDataVtbl* lpvtbl2; /* VTable relative to the IROTData interface.*/ - - ULONG ref; /* reference counter for this object */ - - IMoniker** tabMoniker; /* dynamaic table containing all components (monikers) of this composite moniker */ - - ULONG tabSize; /* size of tabMoniker */ - - ULONG tabLastIndex; /* first free index in tabMoniker */ - -} CompositeMonikerImpl; - - -/* EnumMoniker data structure */ -typedef struct EnumMonikerImpl{ - - IEnumMonikerVtbl *lpVtbl; /* VTable relative to the IEnumMoniker interface.*/ - - ULONG ref; /* reference counter for this object */ - - IMoniker** tabMoniker; /* dynamic table containing the enumerated monikers */ - - ULONG tabSize; /* size of tabMoniker */ - - ULONG currentPos; /* index pointer on the current moniker */ - -} EnumMonikerImpl; - - -static HRESULT EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker,ULONG tabSize,ULONG currentPos,BOOL leftToRigth,IEnumMoniker ** ppmk); - -/******************************************************************************* - * CompositeMoniker_QueryInterface - *******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject) -{ - CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface; - - TRACE("(%p,%p,%p)\n",This,riid,ppvObject); - - /* Perform a sanity check on the parameters.*/ - if ( (This==0) || (ppvObject==0) ) - return E_INVALIDARG; - - /* Initialize the return parameter */ - *ppvObject = 0; - - /* Compare the riid with the interface IDs implemented by this object.*/ - if (IsEqualIID(&IID_IUnknown, riid) || - IsEqualIID(&IID_IPersist, riid) || - IsEqualIID(&IID_IPersistStream, riid) || - IsEqualIID(&IID_IMoniker, riid) - ) - *ppvObject = iface; - else if (IsEqualIID(&IID_IROTData, riid)) - *ppvObject = (IROTData*)&(This->lpvtbl2); - - /* Check that we obtained an interface.*/ - if ((*ppvObject)==0) - return E_NOINTERFACE; - - /* Query Interface always increases the reference count by one when it is successful */ - IMoniker_AddRef(iface); - - return S_OK; -} - -/****************************************************************************** - * CompositeMoniker_AddRef - ******************************************************************************/ -static ULONG WINAPI -CompositeMonikerImpl_AddRef(IMoniker* iface) -{ - CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface; - - TRACE("(%p)\n",This); - - return InterlockedIncrement(&This->ref); -} - -/****************************************************************************** - * CompositeMoniker_Release - ******************************************************************************/ -static ULONG WINAPI -CompositeMonikerImpl_Release(IMoniker* iface) -{ - CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface; - ULONG i; - ULONG ref; - - TRACE("(%p)\n",This); - - ref = InterlockedDecrement(&This->ref); - - /* destroy the object if there's no more reference on it */ - if (ref == 0){ - - /* release all the components before destroying this object */ - for (i=0;i<This->tabLastIndex;i++) - IMoniker_Release(This->tabMoniker[i]); - - HeapFree(GetProcessHeap(),0,This->tabMoniker); - HeapFree(GetProcessHeap(),0,This); - } - return ref; -} - -/****************************************************************************** - * CompositeMoniker_GetClassID - ******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID) -{ - TRACE("(%p,%p),stub!\n",iface,pClassID); - - if (pClassID==NULL) - return E_POINTER; - - *pClassID = CLSID_CompositeMoniker; - - return S_OK; -} - -/****************************************************************************** - * CompositeMoniker_IsDirty - ******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerImpl_IsDirty(IMoniker* iface) -{ - /* Note that the OLE-provided implementations of the IPersistStream::IsDirty - method in the OLE-provided moniker interfaces always return S_FALSE because - their internal state never changes. */ - - TRACE("(%p)\n",iface); - - return S_FALSE; -} - -/****************************************************************************** - * CompositeMoniker_Load - ******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerImpl_Load(IMoniker* iface,IStream* pStm) -{ - HRESULT res; - DWORD constant; - CLSID clsid; - WCHAR string[1]={0}; - - CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface; - - TRACE("(%p,%p)\n",iface,pStm); - - /* this function call OleLoadFromStream function for each moniker within this object */ - - /* read the a constant written by CompositeMonikerImpl_Save (see CompositeMonikerImpl_Save for more details)*/ - res=IStream_Read(pStm,&constant,sizeof(DWORD),NULL); - - if (SUCCEEDED(res)&& constant!=3) - return E_FAIL; - - while(1){ -#if 0 - res=OleLoadFromStream(pStm,&IID_IMoniker,(void**)&This->tabMoniker[This->tabLastIndex]); -#endif - res=ReadClassStm(pStm,&clsid); - DPRINTF("res=%ld",res); - if (FAILED(res)) - break; - - if (IsEqualIID(&clsid,&CLSID_FileMoniker)){ - res=CreateFileMoniker(string,&This->tabMoniker[This->tabLastIndex]); - if (FAILED(res)) - break; - res=IMoniker_Load(This->tabMoniker[This->tabLastIndex],pStm); - if (FAILED(res)) - break; - } - else if (IsEqualIID(&clsid,&CLSID_ItemMoniker)){ - CreateItemMoniker(string,string,&This->tabMoniker[This->tabLastIndex]); - if (res!=S_OK) - break; - IMoniker_Load(This->tabMoniker[This->tabLastIndex],pStm); - if (FAILED(res)) - break; - } - else if (IsEqualIID(&clsid,&CLSID_AntiMoniker)){ - CreateAntiMoniker(&This->tabMoniker[This->tabLastIndex]); - if (FAILED(res)) - break; - IMoniker_Load(This->tabMoniker[This->tabLastIndex],pStm); - if (FAILED(res)) - break; - } - else if (IsEqualIID(&clsid,&CLSID_CompositeMoniker)) - return E_FAIL; - - else - { - FIXME("()\n"); - /* FIXME: To whoever wrote this code: It's either return or break. it cannot be both! */ - break; - return E_NOTIMPL; - } - - /* resize the table if needed */ - if (++This->tabLastIndex==This->tabSize){ - - This->tabSize+=BLOCK_TAB_SIZE; - This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker)); - - if (This->tabMoniker==NULL) - return E_OUTOFMEMORY; - } - } - - return res; -} - -/****************************************************************************** - * CompositeMoniker_Save - ******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerImpl_Save(IMoniker* iface,IStream* pStm,BOOL fClearDirty) -{ - HRESULT res; - IEnumMoniker *enumMk; - IMoniker *pmk; - DWORD constant=3; - - TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty); - - /* This function calls OleSaveToStream function for each moniker within - * this object. - * When I tested this function in windows, I usually found this constant - * at the beginning of the stream. I don't known why (there's no - * indication in the specification) ! - */ - res=IStream_Write(pStm,&constant,sizeof(constant),NULL); - - IMoniker_Enum(iface,TRUE,&enumMk); - - while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){ - - res=OleSaveToStream((IPersistStream*)pmk,pStm); - - IMoniker_Release(pmk); - - if (FAILED(res)){ - - IEnumMoniker_Release(pmk); - return res; - } - } - - IEnumMoniker_Release(enumMk); - - return S_OK; -} - -/****************************************************************************** - * CompositeMoniker_GetSizeMax - ******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerImpl_GetSizeMax(IMoniker* iface,ULARGE_INTEGER* pcbSize) -{ - IEnumMoniker *enumMk; - IMoniker *pmk; - ULARGE_INTEGER ptmpSize; - - /* The sizeMax of this object is calculated by calling GetSizeMax on - * each moniker within this object then summing all returned values - */ - - TRACE("(%p,%p)\n",iface,pcbSize); - - if (pcbSize!=NULL) - return E_POINTER; - - pcbSize->u.LowPart =0; - pcbSize->u.HighPart=0; - - IMoniker_Enum(iface,TRUE,&enumMk); - - while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)){ - - IMoniker_GetSizeMax(pmk,&ptmpSize); - - IMoniker_Release(pmk); - - pcbSize->u.LowPart +=ptmpSize.u.LowPart; - pcbSize->u.HighPart+=ptmpSize.u.HighPart; - } - - IEnumMoniker_Release(enumMk); - - return S_OK; -} - -/****************************************************************************** - * CompositeMoniker_BindToObject - ******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc, - IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult) -{ - HRESULT res; - IRunningObjectTable *prot; - IMoniker *tempMk,*antiMk,*mostRigthMk; - IEnumMoniker *enumMoniker; - - TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult); - - if (ppvResult==NULL) - return E_POINTER; - - *ppvResult=0; - /* If pmkToLeft is NULL, this method looks for the moniker in the ROT, and if found, queries the retrieved */ - /* object for the requested interface pointer. */ - if(pmkToLeft==NULL){ - - res=IBindCtx_GetRunningObjectTable(pbc,&prot); - - if (SUCCEEDED(res)){ - - /* if the requested class was loaded before ! we don't need to reload it */ - res = IRunningObjectTable_GetObject(prot,iface,(IUnknown**)ppvResult); - - if (res==S_OK) - return res; - } - } - else{ - /* If pmkToLeft is not NULL, the method recursively calls IMoniker::BindToObject on the rightmost */ - /* component of the composite, passing the rest of the composite as the pmkToLeft parameter for that call */ - - IMoniker_Enum(iface,FALSE,&enumMoniker); - IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); - IEnumMoniker_Release(enumMoniker); - - res=CreateAntiMoniker(&antiMk); - res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); - IMoniker_Release(antiMk); - - res=CompositeMonikerImpl_BindToObject(mostRigthMk,pbc,tempMk,riid,ppvResult); - - IMoniker_Release(tempMk); - IMoniker_Release(mostRigthMk); - } - - return res; -} - -/****************************************************************************** - * CompositeMoniker_BindToStorage - ******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc, - IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult) -{ - HRESULT res; - IMoniker *tempMk,*antiMk,*mostRigthMk; - IEnumMoniker *enumMoniker; - - TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult); - - *ppvResult=0; - - /* This method recursively calls BindToStorage on the rightmost component of the composite, */ - /* passing the rest of the composite as the pmkToLeft parameter for that call. */ - - if (pmkToLeft!=NULL){ - - IMoniker_Enum(iface,FALSE,&enumMoniker); - IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); - IEnumMoniker_Release(enumMoniker); - - res=CreateAntiMoniker(&antiMk); - res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); - IMoniker_Release(antiMk); - - res=CompositeMonikerImpl_BindToStorage(mostRigthMk,pbc,tempMk,riid,ppvResult); - - IMoniker_Release(tempMk); - - IMoniker_Release(mostRigthMk); - - return res; - } - else - return IMoniker_BindToStorage(iface,pbc,NULL,riid,ppvResult); -} - -/****************************************************************************** - * CompositeMoniker_Reduce - ******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar, - IMoniker** ppmkToLeft, IMoniker** ppmkReduced) -{ - HRESULT res; - IMoniker *tempMk,*antiMk,*mostRigthMk,*leftReducedComposedMk,*mostRigthReducedMk; - IEnumMoniker *enumMoniker; - - TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); - - if (ppmkReduced==NULL) - return E_POINTER; - - /* This method recursively calls Reduce for each of its component monikers. */ - - if (ppmkToLeft==NULL){ - - IMoniker_Enum(iface,FALSE,&enumMoniker); - IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); - IEnumMoniker_Release(enumMoniker); - - res=CreateAntiMoniker(&antiMk); - res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); - IMoniker_Release(antiMk); - - return CompositeMonikerImpl_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk, ppmkReduced); - } - else if (*ppmkToLeft==NULL) - - return IMoniker_Reduce(iface,pbc,dwReduceHowFar,NULL,ppmkReduced); - - else{ - - /* separate the composite moniker in to left and right moniker */ - IMoniker_Enum(iface,FALSE,&enumMoniker); - IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); - IEnumMoniker_Release(enumMoniker); - - res=CreateAntiMoniker(&antiMk); - res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); - IMoniker_Release(antiMk); - - /* If any of the components reduces itself, the method returns S_OK and passes back a composite */ - /* of the reduced components */ - if (IMoniker_Reduce(mostRigthMk,pbc,dwReduceHowFar,NULL,&mostRigthReducedMk) && - CompositeMonikerImpl_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk,&leftReducedComposedMk) - ) - - return CreateGenericComposite(leftReducedComposedMk,mostRigthReducedMk,ppmkReduced); - - else{ - /* If no reduction occurred, the method passes back the same moniker and returns MK_S_REDUCED_TO_SELF.*/ - - IMoniker_AddRef(iface); - - *ppmkReduced=iface; - - return MK_S_REDUCED_TO_SELF; - } - } -} - -/****************************************************************************** - * CompositeMoniker_ComposeWith - ******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight, - BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite) -{ - TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite); - - if ((ppmkComposite==NULL)||(pmkRight==NULL)) - return E_POINTER; - - *ppmkComposite=0; - - /* If fOnlyIfNotGeneric is TRUE, this method sets *pmkComposite to NULL and returns MK_E_NEEDGENERIC; */ - /* otherwise, the method returns the result of combining the two monikers by calling the */ - /* CreateGenericComposite function */ - - if (fOnlyIfNotGeneric) - return MK_E_NEEDGENERIC; - - return CreateGenericComposite(iface,pmkRight,ppmkComposite); -} - -/****************************************************************************** - * CompositeMoniker_Enum - ******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker) -{ - CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface; - - TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker); - - if (ppenumMoniker == NULL) - return E_POINTER; - - return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabLastIndex,0,fForward,ppenumMoniker); -} - -/****************************************************************************** - * CompositeMoniker_IsEqual - ******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker) -{ - IEnumMoniker *enumMoniker1,*enumMoniker2; - IMoniker *tempMk1,*tempMk2; - HRESULT res1,res2,res; - - TRACE("(%p,%p)\n",iface,pmkOtherMoniker); - - if (pmkOtherMoniker==NULL) - return S_FALSE; - - /* This method returns S_OK if the components of both monikers are equal when compared in the */ - /* left-to-right order.*/ - IMoniker_Enum(pmkOtherMoniker,TRUE,&enumMoniker1); - - if (enumMoniker1==NULL) - return S_FALSE; - - IMoniker_Enum(iface,TRUE,&enumMoniker2); - - while(1){ - - res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL); - res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL); - - if((res1==S_OK)&&(res2==S_OK)){ - - if(IMoniker_IsEqual(tempMk1,tempMk2)==S_FALSE){ - res= S_FALSE; - break; - } - else - continue; - } - else if ( (res1==S_FALSE) && (res2==S_FALSE) ){ - res = S_OK; - break; - } - else{ - res = S_FALSE; - break; - } - - if (res1==S_OK) - IMoniker_Release(tempMk1); - - if (res2==S_OK) - IMoniker_Release(tempMk2); - } - - IEnumMoniker_Release(enumMoniker1); - IEnumMoniker_Release(enumMoniker2); - - return res; -} -/****************************************************************************** - * CompositeMoniker_Hash - ******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash) -{ - IEnumMoniker *enumMoniker; - IMoniker *tempMk; - HRESULT res; - DWORD tempHash; - - TRACE("(%p,%p)\n",iface,pdwHash); - - if (pdwHash==NULL) - return E_POINTER; - - res = IMoniker_Enum(iface,TRUE,&enumMoniker); - if(FAILED(res)) - return res; - - while(1){ - res=IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL); - if(FAILED(res)) - break; - - res = IMoniker_Hash(tempMk, &tempHash); - if(FAILED(res)) - break; - *pdwHash = (*pdwHash * 37) + tempHash; - - IMoniker_Release(tempMk); - } - - IEnumMoniker_Release(enumMoniker); - - return res; -} - -/****************************************************************************** - * CompositeMoniker_IsRunning - ******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc, - IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning) -{ - IRunningObjectTable* rot; - HRESULT res; - IMoniker *tempMk,*antiMk,*mostRigthMk; - IEnumMoniker *enumMoniker; - - TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning); - - /* If pmkToLeft is non-NULL, this method composes pmkToLeft with this moniker and calls IsRunning on the result.*/ - if (pmkToLeft!=NULL){ - - CreateGenericComposite(pmkToLeft,iface,&tempMk); - - res = IMoniker_IsRunning(tempMk,pbc,NULL,pmkNewlyRunning); - - IMoniker_Release(tempMk); - - return res; - } - else - /* If pmkToLeft is NULL, this method returns S_OK if pmkNewlyRunning is non-NULL and is equal */ - /* to this moniker */ - - if (pmkNewlyRunning!=NULL) - - if (IMoniker_IsEqual(iface,pmkNewlyRunning)==S_OK) - return S_OK; - - else - return S_FALSE; - - else{ - - if (pbc==NULL) - return E_POINTER; - - /* If pmkToLeft and pmkNewlyRunning are both NULL, this method checks the ROT to see whether */ - /* the moniker is running. If so, the method returns S_OK; otherwise, it recursively calls */ - /* IMoniker::IsRunning on the rightmost component of the composite, passing the remainder of */ - /* the composite as the pmkToLeft parameter for that call. */ - - res=IBindCtx_GetRunningObjectTable(pbc,&rot); - - if (FAILED(res)) - return res; - - res = IRunningObjectTable_IsRunning(rot,iface); - IRunningObjectTable_Release(rot); - - if(res==S_OK) - return S_OK; - - else{ - - IMoniker_Enum(iface,FALSE,&enumMoniker); - IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); - IEnumMoniker_Release(enumMoniker); - - res=CreateAntiMoniker(&antiMk); - res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); - IMoniker_Release(antiMk); - - res=IMoniker_IsRunning(mostRigthMk,pbc,tempMk,pmkNewlyRunning); - - IMoniker_Release(tempMk); - IMoniker_Release(mostRigthMk); - - return res; - } - } -} - -/****************************************************************************** - * CompositeMoniker_GetTimeOfLastChange - ******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc, - IMoniker* pmkToLeft, FILETIME* pCompositeTime) -{ - IRunningObjectTable* rot; - HRESULT res; - IMoniker *tempMk,*antiMk,*mostRigthMk; - IEnumMoniker *enumMoniker; - - TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pCompositeTime); - - if (pCompositeTime==NULL) - return E_INVALIDARG; - - /* This method creates a composite of pmkToLeft (if non-NULL) and this moniker and uses the ROT to */ - /* retrieve the time of last change. If the object is not in the ROT, the method recursively calls */ - /* IMoniker::GetTimeOfLastChange on the rightmost component of the composite, passing the remainder */ - /* of the composite as the pmkToLeft parameter for that call. */ - if (pmkToLeft!=NULL){ - - res=CreateGenericComposite(pmkToLeft,iface,&tempMk); - - res=IBindCtx_GetRunningObjectTable(pbc,&rot); - - if (FAILED(res)) - return res; - - if (IRunningObjectTable_GetTimeOfLastChange(rot,tempMk,pCompositeTime)==S_OK) - return res; - else - - IMoniker_Enum(iface,FALSE,&enumMoniker); - IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); - IEnumMoniker_Release(enumMoniker); - - res=CreateAntiMoniker(&antiMk); - res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); - IMoniker_Release(antiMk); - - res=CompositeMonikerImpl_GetTimeOfLastChange(mostRigthMk,pbc,tempMk,pCompositeTime); - - IMoniker_Release(tempMk); - IMoniker_Release(mostRigthMk); - - return res; - } - else - return IMoniker_GetTimeOfLastChange(iface,pbc,NULL,pCompositeTime); -} - -/****************************************************************************** - * CompositeMoniker_Inverse - ******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk) -{ - HRESULT res; - IMoniker *tempMk,*antiMk,*mostRigthMk,*tempInvMk,*mostRigthInvMk; - IEnumMoniker *enumMoniker; - - TRACE("(%p,%p)\n",iface,ppmk); - - if (ppmk==NULL) - return E_POINTER; - - /* This method returns a composite moniker that consists of the inverses of each of the components */ - /* of the original composite, stored in reverse order */ - - res=CreateAntiMoniker(&antiMk); - res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); - IMoniker_Release(antiMk); - - if (tempMk==NULL) - - return IMoniker_Inverse(iface,ppmk); - - else{ - - IMoniker_Enum(iface,FALSE,&enumMoniker); - IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); - IEnumMoniker_Release(enumMoniker); - - IMoniker_Inverse(mostRigthMk,&mostRigthInvMk); - CompositeMonikerImpl_Inverse(tempMk,&tempInvMk); - - res=CreateGenericComposite(mostRigthInvMk,tempInvMk,ppmk); - - IMoniker_Release(tempMk); - IMoniker_Release(mostRigthMk); - IMoniker_Release(tempInvMk); - IMoniker_Release(mostRigthInvMk); - - return res; - } -} - -/****************************************************************************** - * CompositeMoniker_CommonPrefixWith - ******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerImpl_CommonPrefixWith(IMoniker* iface, IMoniker* pmkOther, - IMoniker** ppmkPrefix) -{ - DWORD mkSys; - HRESULT res1,res2; - IMoniker *tempMk1,*tempMk2,*mostLeftMk1,*mostLeftMk2; - IEnumMoniker *enumMoniker1,*enumMoniker2; - ULONG i,nbCommonMk=0; - - /* If the other moniker is a composite, this method compares the components of each composite from left */ - /* to right. The returned common prefix moniker might also be a composite moniker, depending on how many */ - /* of the leftmost components were common to both monikers. */ - - if (ppmkPrefix==NULL) - return E_POINTER; - - *ppmkPrefix=0; - - if (pmkOther==NULL) - return MK_E_NOPREFIX; - - IMoniker_IsSystemMoniker(pmkOther,&mkSys); - - if((mkSys==MKSYS_GENERICCOMPOSITE)){ - - IMoniker_Enum(iface,TRUE,&enumMoniker1); - IMoniker_Enum(pmkOther,TRUE,&enumMoniker2); - - while(1){ - - res1=IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL); - res2=IEnumMoniker_Next(enumMoniker2,1,&mostLeftMk2,NULL); - - if ((res1==S_FALSE) && (res2==S_FALSE)){ - - /* If the monikers are equal, the method returns MK_S_US and sets ppmkPrefix to this moniker.*/ - *ppmkPrefix=iface; - IMoniker_AddRef(iface); - return MK_S_US; - } - else if ((res1==S_OK) && (res2==S_OK)){ - - if (IMoniker_IsEqual(mostLeftMk1,mostLeftMk2)==S_OK) - - nbCommonMk++; - - else - break; - - } - else if (res1==S_OK){ - - /* If the other moniker is a prefix of this moniker, the method returns MK_S_HIM and sets */ - /* ppmkPrefix to the other moniker. */ - *ppmkPrefix=pmkOther; - return MK_S_HIM; - } - else{ - /* If this moniker is a prefix of the other, this method returns MK_S_ME and sets ppmkPrefix */ - /* to this moniker. */ - *ppmkPrefix=iface; - return MK_S_ME; - } - } - - IEnumMoniker_Release(enumMoniker1); - IEnumMoniker_Release(enumMoniker2); - - /* If there is no common prefix, this method returns MK_E_NOPREFIX and sets ppmkPrefix to NULL. */ - if (nbCommonMk==0) - return MK_E_NOPREFIX; - - IEnumMoniker_Reset(enumMoniker1); - - IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL); - - /* if we have more than one commun moniker the result will be a composite moniker */ - if (nbCommonMk>1){ - - /* initialize the common prefix moniker with the composite of two first moniker (from the left)*/ - IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL); - CreateGenericComposite(tempMk1,tempMk2,ppmkPrefix); - IMoniker_Release(tempMk1); - IMoniker_Release(tempMk2); - - /* compose all common monikers in a composite moniker */ - for(i=0;i<nbCommonMk;i++){ - - IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL); - - CreateGenericComposite(*ppmkPrefix,tempMk1,&tempMk2); - - IMoniker_Release(*ppmkPrefix); - - IMoniker_Release(tempMk1); - - *ppmkPrefix=tempMk2; - } - return S_OK; - } - else{ - /* if we have only one commun moniker the result will be a simple moniker which is the most-left one*/ - *ppmkPrefix=tempMk1; - - return S_OK; - } - } - else{ - /* If the other moniker is not a composite, the method simply compares it to the leftmost component - of this moniker.*/ - - IMoniker_Enum(iface,TRUE,&enumMoniker1); - - IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL); - - if (IMoniker_IsEqual(pmkOther,mostLeftMk1)==S_OK){ - - *ppmkPrefix=pmkOther; - - return MK_S_HIM; - } - else - return MK_E_NOPREFIX; - } -} - -/*************************************************************************************************** - * GetAfterCommonPrefix (local function) - * This function returns a moniker that consist of the remainder when the common prefix is removed - ***************************************************************************************************/ -static VOID GetAfterCommonPrefix(IMoniker* pGenMk,IMoniker* commonMk,IMoniker** restMk) -{ - IMoniker *tempMk,*tempMk1,*tempMk2; - IEnumMoniker *enumMoniker1,*enumMoniker2,*enumMoniker3; - ULONG nbRestMk=0; - DWORD mkSys; - HRESULT res1,res2; - - *restMk=0; - - /* to create an enumerator for pGenMk with current position pointed on the first element after common */ - /* prefix: enum the two monikers (left-right) then compare these enumerations (left-right) and stop */ - /* on the first difference. */ - IMoniker_Enum(pGenMk,TRUE,&enumMoniker1); - - IMoniker_IsSystemMoniker(commonMk,&mkSys); - - if (mkSys==MKSYS_GENERICCOMPOSITE){ - - IMoniker_Enum(commonMk,TRUE,&enumMoniker2); - while(1){ - - res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL); - res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL); - - if ((res1==S_FALSE)||(res2==S_FALSE)){ - - if (res1==S_OK) - - nbRestMk++; - - IMoniker_Release(tempMk1); - IMoniker_Release(tempMk1); - - break; - } - IMoniker_Release(tempMk1); - IMoniker_Release(tempMk1); - } - } - else{ - IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL); - IMoniker_Release(tempMk1); - } - - /* count the number of elements in the enumerator after the common prefix */ - IEnumMoniker_Clone(enumMoniker1,&enumMoniker3); - - for(;IEnumMoniker_Next(enumMoniker3,1,&tempMk,NULL)==S_OK;nbRestMk++) - - IMoniker_Release(tempMk); - - if (nbRestMk==0) - return; - - /* create a generic composite moniker with monikers located after the common prefix */ - IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL); - - if (nbRestMk==1){ - - *restMk= tempMk1; - return; - } - else { - - IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL); - - CreateGenericComposite(tempMk1,tempMk2,restMk); - - IMoniker_Release(tempMk1); - - IMoniker_Release(tempMk2); - - while(IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL)==S_OK){ - - CreateGenericComposite(*restMk,tempMk1,&tempMk2); - - IMoniker_Release(tempMk1); - - IMoniker_Release(*restMk); - - *restMk=tempMk2; - } - } -} - -/****************************************************************************** - * CompositeMoniker_RelativePathTo - ******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmkOther, - IMoniker** ppmkRelPath) -{ - HRESULT res; - IMoniker *restOtherMk=0,*restThisMk=0,*invRestThisMk=0,*commonMk=0; - - TRACE("(%p,%p,%p)\n",iface,pmkOther,ppmkRelPath); - - if (ppmkRelPath==NULL) - return E_POINTER; - - *ppmkRelPath=0; - - /* This method finds the common prefix of the two monikers and creates two monikers that consist */ - /* of the remainder when the common prefix is removed. Then it creates the inverse for the remainder */ - /* of this moniker and composes the remainder of the other moniker on the right of it. */ - - /* finds the common prefix of the two monikers */ - res=IMoniker_CommonPrefixWith(iface,pmkOther,&commonMk); - - /* if there's no common prefix or the two moniker are equal the relative is the other moniker */ - if ((res== MK_E_NOPREFIX)||(res==MK_S_US)){ - - *ppmkRelPath=pmkOther; - IMoniker_AddRef(pmkOther); - return MK_S_HIM; - } - - GetAfterCommonPrefix(iface,commonMk,&restThisMk); - GetAfterCommonPrefix(pmkOther,commonMk,&restOtherMk); - - /* if other is a prefix of this moniker the relative path is the inverse of the remainder path of this */ - /* moniker when the common prefix is removed */ - if (res==MK_S_HIM){ - - IMoniker_Inverse(restThisMk,ppmkRelPath); - IMoniker_Release(restThisMk); - } - /* if this moniker is a prefix of other moniker the relative path is the remainder path of other moniker */ - /* when the common prefix is removed */ - else if (res==MK_S_ME){ - - *ppmkRelPath=restOtherMk; - IMoniker_AddRef(restOtherMk); - } - /* the relative path is the inverse for the remainder of this moniker and the remainder of the other */ - /* moniker on the right of it. */ - else if (res==S_OK){ - - IMoniker_Inverse(restThisMk,&invRestThisMk); - IMoniker_Release(restThisMk); - CreateGenericComposite(invRestThisMk,restOtherMk,ppmkRelPath); - IMoniker_Release(invRestThisMk); - IMoniker_Release(restOtherMk); - } - return S_OK; -} - -/****************************************************************************** - * CompositeMoniker_GetDisplayName - ******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc, - IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName) -{ - ULONG lengthStr=1; - IEnumMoniker *enumMoniker; - IMoniker* tempMk; - LPOLESTR tempStr; - - TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName); - - if (ppszDisplayName==NULL) - return E_POINTER; - - *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR)); - - if (*ppszDisplayName==NULL) - return E_OUTOFMEMORY; - - /* This method returns the concatenation of the display names returned by each component moniker of */ - /* the composite */ - - **ppszDisplayName=0; - - IMoniker_Enum(iface,TRUE,&enumMoniker); - - while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){ - - IMoniker_GetDisplayName(tempMk,pbc,NULL,&tempStr); - - lengthStr+=lstrlenW(tempStr); - - *ppszDisplayName=CoTaskMemRealloc(*ppszDisplayName,lengthStr * sizeof(WCHAR)); - - if (*ppszDisplayName==NULL) - return E_OUTOFMEMORY; - - strcatW(*ppszDisplayName,tempStr); - - CoTaskMemFree(tempStr); - IMoniker_Release(tempMk); - } - - IEnumMoniker_Release(enumMoniker); - - return S_OK; -} - -/****************************************************************************** - * CompositeMoniker_ParseDisplayName - ******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc, - IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten, - IMoniker** ppmkOut) -{ - IEnumMoniker *enumMoniker; - IMoniker *tempMk,*mostRigthMk,*antiMk; - /* This method recursively calls IMoniker::ParseDisplayName on the rightmost component of the composite,*/ - /* passing everything else as the pmkToLeft parameter for that call. */ - - /* get the most right moniker */ - IMoniker_Enum(iface,FALSE,&enumMoniker); - IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); - IEnumMoniker_Release(enumMoniker); - - /* get the left moniker */ - CreateAntiMoniker(&antiMk); - IMoniker_ComposeWith(iface,antiMk,0,&tempMk); - IMoniker_Release(antiMk); - - return IMoniker_ParseDisplayName(mostRigthMk,pbc,tempMk,pszDisplayName,pchEaten,ppmkOut); -} - -/****************************************************************************** - * CompositeMoniker_IsSystemMoniker - ******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys) -{ - TRACE("(%p,%p)\n",iface,pwdMksys); - - if (!pwdMksys) - return E_POINTER; - - (*pwdMksys)=MKSYS_GENERICCOMPOSITE; - - return S_OK; -} - -/******************************************************************************* - * CompositeMonikerIROTData_QueryInterface - *******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid, - VOID** ppvObject) -{ - - ICOM_THIS_From_IROTData(IMoniker, iface); - - TRACE("(%p,%p,%p)\n",iface,riid,ppvObject); - - return CompositeMonikerImpl_QueryInterface(This, riid, ppvObject); -} - -/*********************************************************************** - * CompositeMonikerIROTData_AddRef - */ -static ULONG WINAPI -CompositeMonikerROTDataImpl_AddRef(IROTData *iface) -{ - ICOM_THIS_From_IROTData(IMoniker, iface); - - TRACE("(%p)\n",iface); - - return IMoniker_AddRef(This); -} - -/*********************************************************************** - * CompositeMonikerIROTData_Release - */ -static ULONG WINAPI CompositeMonikerROTDataImpl_Release(IROTData* iface) -{ - ICOM_THIS_From_IROTData(IMoniker, iface); - - TRACE("(%p)\n",iface); - - return IMoniker_Release(This); -} - -/****************************************************************************** - * CompositeMonikerIROTData_GetComparaisonData - ******************************************************************************/ -static HRESULT WINAPI -CompositeMonikerROTDataImpl_GetComparaisonData(IROTData* iface, - BYTE* pbData, ULONG cbMax, ULONG* pcbData) -{ - FIXME("(),stub!\n"); - return E_NOTIMPL; -} - -/****************************************************************************** - * EnumMonikerImpl_QueryInterface - ******************************************************************************/ -static HRESULT WINAPI -EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject) -{ - EnumMonikerImpl *This = (EnumMonikerImpl *)iface; - - TRACE("(%p,%p,%p)\n",This,riid,ppvObject); - - /* Perform a sanity check on the parameters.*/ - if ( (This==0) || (ppvObject==0) ) - return E_INVALIDARG; - - /* Initialize the return parameter */ - *ppvObject = 0; - - /* Compare the riid with the interface IDs implemented by this object.*/ - if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IEnumMoniker, riid)) - *ppvObject = iface; - - /* Check that we obtained an interface.*/ - if ((*ppvObject)==0) - return E_NOINTERFACE; - - /* Query Interface always increases the reference count by one when it is successful */ - IEnumMoniker_AddRef(iface); - - return S_OK; -} - -/****************************************************************************** - * EnumMonikerImpl_AddRef - ******************************************************************************/ -static ULONG WINAPI -EnumMonikerImpl_AddRef(IEnumMoniker* iface) -{ - EnumMonikerImpl *This = (EnumMonikerImpl *)iface; - - TRACE("(%p)\n",This); - - return InterlockedIncrement(&This->ref); - -} - -/****************************************************************************** - * EnumMonikerImpl_Release - ******************************************************************************/ -static ULONG WINAPI -EnumMonikerImpl_Release(IEnumMoniker* iface) -{ - EnumMonikerImpl *This = (EnumMonikerImpl *)iface; - ULONG i; - ULONG ref; - TRACE("(%p)\n",This); - - ref = InterlockedDecrement(&This->ref); - - /* destroy the object if there's no more reference on it */ - if (ref == 0) { - - for(i=0;i<This->tabSize;i++) - IMoniker_Release(This->tabMoniker[i]); - - HeapFree(GetProcessHeap(),0,This->tabMoniker); - HeapFree(GetProcessHeap(),0,This); - } - return ref; -} - -/****************************************************************************** - * EnumMonikerImpl_Next - ******************************************************************************/ -static HRESULT WINAPI -EnumMonikerImpl_Next(IEnumMoniker* iface,ULONG celt, IMoniker** rgelt, - ULONG* pceltFethed) -{ - EnumMonikerImpl *This = (EnumMonikerImpl *)iface; - ULONG i; - - /* retrieve the requested number of moniker from the current position */ - for(i=0;((This->currentPos < This->tabSize) && (i < celt));i++) - - rgelt[i]=This->tabMoniker[This->currentPos++]; - - if (pceltFethed!=NULL) - *pceltFethed= i; - - if (i==celt) - return S_OK; - else - return S_FALSE; -} - -/****************************************************************************** - * EnumMonikerImpl_Skip - ******************************************************************************/ -static HRESULT WINAPI -EnumMonikerImpl_Skip(IEnumMoniker* iface,ULONG celt) -{ - EnumMonikerImpl *This = (EnumMonikerImpl *)iface; - - if ((This->currentPos+celt) >= This->tabSize) - return S_FALSE; - - This->currentPos+=celt; - - return S_OK; -} - -/****************************************************************************** - * EnumMonikerImpl_Reset - ******************************************************************************/ -static HRESULT WINAPI -EnumMonikerImpl_Reset(IEnumMoniker* iface) -{ - - EnumMonikerImpl *This = (EnumMonikerImpl *)iface; - - This->currentPos=0; - - return S_OK; -} - -/****************************************************************************** - * EnumMonikerImpl_Clone - ******************************************************************************/ -static HRESULT WINAPI -EnumMonikerImpl_Clone(IEnumMoniker* iface,IEnumMoniker** ppenum) -{ - EnumMonikerImpl *This = (EnumMonikerImpl *)iface; - - return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabSize,This->currentPos,TRUE,ppenum); -} - -/********************************************************************************/ -/* Virtual function table for the IROTData class */ -static IEnumMonikerVtbl VT_EnumMonikerImpl = -{ - EnumMonikerImpl_QueryInterface, - EnumMonikerImpl_AddRef, - EnumMonikerImpl_Release, - EnumMonikerImpl_Next, - EnumMonikerImpl_Skip, - EnumMonikerImpl_Reset, - EnumMonikerImpl_Clone -}; - -/****************************************************************************** - * EnumMonikerImpl_CreateEnumMoniker - ******************************************************************************/ -static HRESULT -EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker, ULONG tabSize, - ULONG currentPos, BOOL leftToRigth, IEnumMoniker ** ppmk) -{ - EnumMonikerImpl* newEnumMoniker; - int i; - - if (currentPos > tabSize) - return E_INVALIDARG; - - newEnumMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumMonikerImpl)); - - if (newEnumMoniker == 0) - return STG_E_INSUFFICIENTMEMORY; - - /* Initialize the virtual function table. */ - newEnumMoniker->lpVtbl = &VT_EnumMonikerImpl; - newEnumMoniker->ref = 0; - - newEnumMoniker->tabSize=tabSize; - newEnumMoniker->currentPos=currentPos; - - newEnumMoniker->tabMoniker=HeapAlloc(GetProcessHeap(),0,tabSize*sizeof(IMoniker)); - - if (newEnumMoniker->tabMoniker==NULL) { - HeapFree(GetProcessHeap(), 0, newEnumMoniker); - return E_OUTOFMEMORY; - } - - if (leftToRigth) - for (i=0;i<tabSize;i++){ - - newEnumMoniker->tabMoniker[i]=tabMoniker[i]; - IMoniker_AddRef(tabMoniker[i]); - } - else - for (i=tabSize-1;i>=0;i--){ - - newEnumMoniker->tabMoniker[tabSize-i-1]=tabMoniker[i]; - IMoniker_AddRef(tabMoniker[i]); - } - - *ppmk=(IEnumMoniker*)newEnumMoniker; - - return S_OK; -} - -/********************************************************************************/ -/* Virtual function table for the CompositeMonikerImpl class which includes */ -/* IPersist, IPersistStream and IMoniker functions. */ - -static IMonikerVtbl VT_CompositeMonikerImpl = -{ - CompositeMonikerImpl_QueryInterface, - CompositeMonikerImpl_AddRef, - CompositeMonikerImpl_Release, - CompositeMonikerImpl_GetClassID, - CompositeMonikerImpl_IsDirty, - CompositeMonikerImpl_Load, - CompositeMonikerImpl_Save, - CompositeMonikerImpl_GetSizeMax, - CompositeMonikerImpl_BindToObject, - CompositeMonikerImpl_BindToStorage, - CompositeMonikerImpl_Reduce, - CompositeMonikerImpl_ComposeWith, - CompositeMonikerImpl_Enum, - CompositeMonikerImpl_IsEqual, - CompositeMonikerImpl_Hash, - CompositeMonikerImpl_IsRunning, - CompositeMonikerImpl_GetTimeOfLastChange, - CompositeMonikerImpl_Inverse, - CompositeMonikerImpl_CommonPrefixWith, - CompositeMonikerImpl_RelativePathTo, - CompositeMonikerImpl_GetDisplayName, - CompositeMonikerImpl_ParseDisplayName, - CompositeMonikerImpl_IsSystemMoniker -}; - -/********************************************************************************/ -/* Virtual function table for the IROTData class. */ -static IROTDataVtbl VT_ROTDataImpl = -{ - CompositeMonikerROTDataImpl_QueryInterface, - CompositeMonikerROTDataImpl_AddRef, - CompositeMonikerROTDataImpl_Release, - CompositeMonikerROTDataImpl_GetComparaisonData -}; - -/****************************************************************************** - * Composite-Moniker_Construct (local function) - *******************************************************************************/ -static HRESULT -CompositeMonikerImpl_Construct(CompositeMonikerImpl* This, - LPMONIKER pmkFirst, LPMONIKER pmkRest) -{ - DWORD mkSys; - IEnumMoniker *enumMoniker; - IMoniker *tempMk; - HRESULT res; - - TRACE("(%p,%p,%p)\n",This,pmkFirst,pmkRest); - - /* Initialize the virtual function table. */ - This->lpvtbl1 = &VT_CompositeMonikerImpl; - This->lpvtbl2 = &VT_ROTDataImpl; - This->ref = 0; - - This->tabSize=BLOCK_TAB_SIZE; - This->tabLastIndex=0; - - This->tabMoniker=HeapAlloc(GetProcessHeap(),0,This->tabSize*sizeof(IMoniker)); - if (This->tabMoniker==NULL) - return E_OUTOFMEMORY; - - IMoniker_IsSystemMoniker(pmkFirst,&mkSys); - - /* put the first moniker contents in the beginning of the table */ - if (mkSys!=MKSYS_GENERICCOMPOSITE){ - - This->tabMoniker[(This->tabLastIndex)++]=pmkFirst; - IMoniker_AddRef(pmkFirst); - } - else{ - - IMoniker_Enum(pmkFirst,TRUE,&enumMoniker); - - while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){ - - - if (++This->tabLastIndex==This->tabSize){ - - This->tabSize+=BLOCK_TAB_SIZE; - This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker)); - - if (This->tabMoniker==NULL) - return E_OUTOFMEMORY; - } - } - - IEnumMoniker_Release(enumMoniker); - } - - /* put the rest moniker contents after the first one and make simplification if needed */ - - IMoniker_IsSystemMoniker(pmkRest,&mkSys); - - if (mkSys!=MKSYS_GENERICCOMPOSITE){ - - /* add a simple moniker to the moniker table */ - - res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],pmkRest,TRUE,&tempMk); - - if (res==MK_E_NEEDGENERIC){ - - /* there's no simplification in this case */ - This->tabMoniker[This->tabLastIndex]=pmkRest; - - This->tabLastIndex++; - - IMoniker_AddRef(pmkRest); - } - else if (tempMk==NULL){ - - /* we have an antimoniker after a simple moniker so we can make a simplification in this case */ - IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]); - - This->tabLastIndex--; - } - else if (SUCCEEDED(res)){ - - /* the non-generic composition was successful so we can make a simplification in this case */ - IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]); - - This->tabMoniker[This->tabLastIndex-1]=tempMk; - } else - return res; - - /* resize tabMoniker if needed */ - if (This->tabLastIndex==This->tabSize){ - - This->tabSize+=BLOCK_TAB_SIZE; - - This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker)); - - if (This->tabMoniker==NULL) - return E_OUTOFMEMORY; - } - } - else{ - - /* add a composite moniker to the moniker table (do the same thing - * for each moniker within the composite moniker as a simple moniker - * (see above for how to add a simple moniker case) ) - */ - IMoniker_Enum(pmkRest,TRUE,&enumMoniker); - - while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){ - - res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],This->tabMoniker[This->tabLastIndex],TRUE,&tempMk); - - if (res==MK_E_NEEDGENERIC){ - - This->tabLastIndex++; - } - else if (tempMk==NULL){ - - IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]); - IMoniker_Release(This->tabMoniker[This->tabLastIndex]); - This->tabLastIndex--; - } - else{ - - IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]); - - This->tabMoniker[This->tabLastIndex-1]=tempMk; - } - - if (This->tabLastIndex==This->tabSize){ - - This->tabSize+=BLOCK_TAB_SIZE; - - This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker)); - - if (This->tabMoniker==NULL) - return E_OUTOFMEMORY; - } - } - - IEnumMoniker_Release(enumMoniker); - } - - return S_OK; -} - -/****************************************************************************** - * CreateGenericComposite [OLE32.@] - ******************************************************************************/ -HRESULT WINAPI -CreateGenericComposite(LPMONIKER pmkFirst, LPMONIKER pmkRest, - LPMONIKER* ppmkComposite) -{ - CompositeMonikerImpl* newCompositeMoniker = 0; - HRESULT hr = S_OK; - - TRACE("(%p,%p,%p)\n",pmkFirst,pmkRest,ppmkComposite); - - if (ppmkComposite==NULL) - return E_POINTER; - - *ppmkComposite=0; - - if (pmkFirst==NULL && pmkRest!=NULL){ - - *ppmkComposite=pmkRest; - return S_OK; - } - else if (pmkFirst!=NULL && pmkRest==NULL){ - *ppmkComposite=pmkFirst; - return S_OK; - } - else if (pmkFirst==NULL && pmkRest==NULL) - return S_OK; - - newCompositeMoniker = HeapAlloc(GetProcessHeap(), 0,sizeof(CompositeMonikerImpl)); - - if (newCompositeMoniker == 0) - return STG_E_INSUFFICIENTMEMORY; - - hr = CompositeMonikerImpl_Construct(newCompositeMoniker,pmkFirst,pmkRest); - - if (FAILED(hr)){ - - HeapFree(GetProcessHeap(),0,newCompositeMoniker); - return hr; - } - if (newCompositeMoniker->tabLastIndex==1) - - hr = IMoniker_QueryInterface(newCompositeMoniker->tabMoniker[0],&IID_IMoniker,(void**)ppmkComposite); - else - - hr = IMoniker_QueryInterface((IMoniker*)newCompositeMoniker,&IID_IMoniker,(void**)ppmkComposite); - - return hr; -} - -/****************************************************************************** - * MonikerCommonPrefixWith [OLE32.@] - ******************************************************************************/ -HRESULT WINAPI -MonikerCommonPrefixWith(IMoniker* pmkThis,IMoniker* pmkOther,IMoniker** ppmkCommon) -{ - FIXME("(),stub!\n"); - return E_NOTIMPL; -} +/* + * CompositeMonikers implementation + * + * Copyright 1999 Noomen Hamza + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <assert.h> +#include <stdarg.h> +#include <string.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winerror.h" +#include "wine/debug.h" +#include "wine/unicode.h" +#include "ole2.h" +#include "moniker.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +const CLSID CLSID_CompositeMoniker = { + 0x309, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46} +}; + +#define BLOCK_TAB_SIZE 5 /* represent the first size table and it's increment block size */ + +/* CompositeMoniker data structure */ +typedef struct CompositeMonikerImpl{ + + IMonikerVtbl* lpvtbl1; /* VTable relative to the IMoniker interface.*/ + + /* The ROT (RunningObjectTable implementation) uses the IROTData + * interface to test whether two monikers are equal. That's why IROTData + * interface is implemented by monikers. + */ + IROTDataVtbl* lpvtbl2; /* VTable relative to the IROTData interface.*/ + + ULONG ref; /* reference counter for this object */ + + IMoniker** tabMoniker; /* dynamaic table containing all components (monikers) of this composite moniker */ + + ULONG tabSize; /* size of tabMoniker */ + + ULONG tabLastIndex; /* first free index in tabMoniker */ + +} CompositeMonikerImpl; + + +/* EnumMoniker data structure */ +typedef struct EnumMonikerImpl{ + + IEnumMonikerVtbl *lpVtbl; /* VTable relative to the IEnumMoniker interface.*/ + + ULONG ref; /* reference counter for this object */ + + IMoniker** tabMoniker; /* dynamic table containing the enumerated monikers */ + + ULONG tabSize; /* size of tabMoniker */ + + ULONG currentPos; /* index pointer on the current moniker */ + +} EnumMonikerImpl; + + +static HRESULT EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker,ULONG tabSize,ULONG currentPos,BOOL leftToRigth,IEnumMoniker ** ppmk); + +/******************************************************************************* + * CompositeMoniker_QueryInterface + *******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject) +{ + CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface; + + TRACE("(%p,%p,%p)\n",This,riid,ppvObject); + + /* Perform a sanity check on the parameters.*/ + if ( (This==0) || (ppvObject==0) ) + return E_INVALIDARG; + + /* Initialize the return parameter */ + *ppvObject = 0; + + /* Compare the riid with the interface IDs implemented by this object.*/ + if (IsEqualIID(&IID_IUnknown, riid) || + IsEqualIID(&IID_IPersist, riid) || + IsEqualIID(&IID_IPersistStream, riid) || + IsEqualIID(&IID_IMoniker, riid) + ) + *ppvObject = iface; + else if (IsEqualIID(&IID_IROTData, riid)) + *ppvObject = (IROTData*)&(This->lpvtbl2); + + /* Check that we obtained an interface.*/ + if ((*ppvObject)==0) + return E_NOINTERFACE; + + /* Query Interface always increases the reference count by one when it is successful */ + IMoniker_AddRef(iface); + + return S_OK; +} + +/****************************************************************************** + * CompositeMoniker_AddRef + ******************************************************************************/ +static ULONG WINAPI +CompositeMonikerImpl_AddRef(IMoniker* iface) +{ + CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface; + + TRACE("(%p)\n",This); + + return InterlockedIncrement(&This->ref); +} + +/****************************************************************************** + * CompositeMoniker_Release + ******************************************************************************/ +static ULONG WINAPI +CompositeMonikerImpl_Release(IMoniker* iface) +{ + CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface; + ULONG i; + ULONG ref; + + TRACE("(%p)\n",This); + + ref = InterlockedDecrement(&This->ref); + + /* destroy the object if there's no more reference on it */ + if (ref == 0){ + + /* release all the components before destroying this object */ + for (i=0;i<This->tabLastIndex;i++) + IMoniker_Release(This->tabMoniker[i]); + + HeapFree(GetProcessHeap(),0,This->tabMoniker); + HeapFree(GetProcessHeap(),0,This); + } + return ref; +} + +/****************************************************************************** + * CompositeMoniker_GetClassID + ******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID) +{ + TRACE("(%p,%p),stub!\n",iface,pClassID); + + if (pClassID==NULL) + return E_POINTER; + + *pClassID = CLSID_CompositeMoniker; + + return S_OK; +} + +/****************************************************************************** + * CompositeMoniker_IsDirty + ******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerImpl_IsDirty(IMoniker* iface) +{ + /* Note that the OLE-provided implementations of the IPersistStream::IsDirty + method in the OLE-provided moniker interfaces always return S_FALSE because + their internal state never changes. */ + + TRACE("(%p)\n",iface); + + return S_FALSE; +} + +/****************************************************************************** + * CompositeMoniker_Load + ******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerImpl_Load(IMoniker* iface,IStream* pStm) +{ + HRESULT res; + DWORD constant; + CLSID clsid; + WCHAR string[1]={0}; + + CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface; + + TRACE("(%p,%p)\n",iface,pStm); + + /* this function call OleLoadFromStream function for each moniker within this object */ + + /* read the a constant written by CompositeMonikerImpl_Save (see CompositeMonikerImpl_Save for more details)*/ + res=IStream_Read(pStm,&constant,sizeof(DWORD),NULL); + + if (SUCCEEDED(res)&& constant!=3) + return E_FAIL; + + while(1){ +#if 0 + res=OleLoadFromStream(pStm,&IID_IMoniker,(void**)&This->tabMoniker[This->tabLastIndex]); +#endif + res=ReadClassStm(pStm,&clsid); + DPRINTF("res=%ld",res); + if (FAILED(res)) + break; + + if (IsEqualIID(&clsid,&CLSID_FileMoniker)){ + res=CreateFileMoniker(string,&This->tabMoniker[This->tabLastIndex]); + if (FAILED(res)) + break; + res=IMoniker_Load(This->tabMoniker[This->tabLastIndex],pStm); + if (FAILED(res)) + break; + } + else if (IsEqualIID(&clsid,&CLSID_ItemMoniker)){ + CreateItemMoniker(string,string,&This->tabMoniker[This->tabLastIndex]); + if (res!=S_OK) + break; + IMoniker_Load(This->tabMoniker[This->tabLastIndex],pStm); + if (FAILED(res)) + break; + } + else if (IsEqualIID(&clsid,&CLSID_AntiMoniker)){ + CreateAntiMoniker(&This->tabMoniker[This->tabLastIndex]); + if (FAILED(res)) + break; + IMoniker_Load(This->tabMoniker[This->tabLastIndex],pStm); + if (FAILED(res)) + break; + } + else if (IsEqualIID(&clsid,&CLSID_CompositeMoniker)) + return E_FAIL; + + else + { + FIXME("()\n"); + /* FIXME: To whoever wrote this code: It's either return or break. it cannot be both! */ + break; + return E_NOTIMPL; + } + + /* resize the table if needed */ + if (++This->tabLastIndex==This->tabSize){ + + This->tabSize+=BLOCK_TAB_SIZE; + This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker)); + + if (This->tabMoniker==NULL) + return E_OUTOFMEMORY; + } + } + + return res; +} + +/****************************************************************************** + * CompositeMoniker_Save + ******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerImpl_Save(IMoniker* iface,IStream* pStm,BOOL fClearDirty) +{ + HRESULT res; + IEnumMoniker *enumMk; + IMoniker *pmk; + DWORD constant=3; + + TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty); + + /* This function calls OleSaveToStream function for each moniker within + * this object. + * When I tested this function in windows, I usually found this constant + * at the beginning of the stream. I don't known why (there's no + * indication in the specification) ! + */ + res=IStream_Write(pStm,&constant,sizeof(constant),NULL); + + IMoniker_Enum(iface,TRUE,&enumMk); + + while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==S_OK){ + + res=OleSaveToStream((IPersistStream*)pmk,pStm); + + IMoniker_Release(pmk); + + if (FAILED(res)){ + + IEnumMoniker_Release(pmk); + return res; + } + } + + IEnumMoniker_Release(enumMk); + + return S_OK; +} + +/****************************************************************************** + * CompositeMoniker_GetSizeMax + ******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerImpl_GetSizeMax(IMoniker* iface,ULARGE_INTEGER* pcbSize) +{ + IEnumMoniker *enumMk; + IMoniker *pmk; + ULARGE_INTEGER ptmpSize; + + /* The sizeMax of this object is calculated by calling GetSizeMax on + * each moniker within this object then summing all returned values + */ + + TRACE("(%p,%p)\n",iface,pcbSize); + + if (pcbSize!=NULL) + return E_POINTER; + + pcbSize->u.LowPart =0; + pcbSize->u.HighPart=0; + + IMoniker_Enum(iface,TRUE,&enumMk); + + while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)){ + + IMoniker_GetSizeMax(pmk,&ptmpSize); + + IMoniker_Release(pmk); + + pcbSize->u.LowPart +=ptmpSize.u.LowPart; + pcbSize->u.HighPart+=ptmpSize.u.HighPart; + } + + IEnumMoniker_Release(enumMk); + + return S_OK; +} + +/****************************************************************************** + * CompositeMoniker_BindToObject + ******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc, + IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult) +{ + HRESULT res; + IRunningObjectTable *prot; + IMoniker *tempMk,*antiMk,*mostRigthMk; + IEnumMoniker *enumMoniker; + + TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult); + + if (ppvResult==NULL) + return E_POINTER; + + *ppvResult=0; + /* If pmkToLeft is NULL, this method looks for the moniker in the ROT, and if found, queries the retrieved */ + /* object for the requested interface pointer. */ + if(pmkToLeft==NULL){ + + res=IBindCtx_GetRunningObjectTable(pbc,&prot); + + if (SUCCEEDED(res)){ + + /* if the requested class was loaded before ! we don't need to reload it */ + res = IRunningObjectTable_GetObject(prot,iface,(IUnknown**)ppvResult); + + if (res==S_OK) + return res; + } + } + else{ + /* If pmkToLeft is not NULL, the method recursively calls IMoniker::BindToObject on the rightmost */ + /* component of the composite, passing the rest of the composite as the pmkToLeft parameter for that call */ + + IMoniker_Enum(iface,FALSE,&enumMoniker); + IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); + IEnumMoniker_Release(enumMoniker); + + res=CreateAntiMoniker(&antiMk); + res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); + IMoniker_Release(antiMk); + + res=CompositeMonikerImpl_BindToObject(mostRigthMk,pbc,tempMk,riid,ppvResult); + + IMoniker_Release(tempMk); + IMoniker_Release(mostRigthMk); + } + + return res; +} + +/****************************************************************************** + * CompositeMoniker_BindToStorage + ******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc, + IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult) +{ + HRESULT res; + IMoniker *tempMk,*antiMk,*mostRigthMk; + IEnumMoniker *enumMoniker; + + TRACE("(%p,%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,riid,ppvResult); + + *ppvResult=0; + + /* This method recursively calls BindToStorage on the rightmost component of the composite, */ + /* passing the rest of the composite as the pmkToLeft parameter for that call. */ + + if (pmkToLeft!=NULL){ + + IMoniker_Enum(iface,FALSE,&enumMoniker); + IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); + IEnumMoniker_Release(enumMoniker); + + res=CreateAntiMoniker(&antiMk); + res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); + IMoniker_Release(antiMk); + + res=CompositeMonikerImpl_BindToStorage(mostRigthMk,pbc,tempMk,riid,ppvResult); + + IMoniker_Release(tempMk); + + IMoniker_Release(mostRigthMk); + + return res; + } + else + return IMoniker_BindToStorage(iface,pbc,NULL,riid,ppvResult); +} + +/****************************************************************************** + * CompositeMoniker_Reduce + ******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar, + IMoniker** ppmkToLeft, IMoniker** ppmkReduced) +{ + HRESULT res; + IMoniker *tempMk,*antiMk,*mostRigthMk,*leftReducedComposedMk,*mostRigthReducedMk; + IEnumMoniker *enumMoniker; + + TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); + + if (ppmkReduced==NULL) + return E_POINTER; + + /* This method recursively calls Reduce for each of its component monikers. */ + + if (ppmkToLeft==NULL){ + + IMoniker_Enum(iface,FALSE,&enumMoniker); + IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); + IEnumMoniker_Release(enumMoniker); + + res=CreateAntiMoniker(&antiMk); + res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); + IMoniker_Release(antiMk); + + return CompositeMonikerImpl_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk, ppmkReduced); + } + else if (*ppmkToLeft==NULL) + + return IMoniker_Reduce(iface,pbc,dwReduceHowFar,NULL,ppmkReduced); + + else{ + + /* separate the composite moniker in to left and right moniker */ + IMoniker_Enum(iface,FALSE,&enumMoniker); + IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); + IEnumMoniker_Release(enumMoniker); + + res=CreateAntiMoniker(&antiMk); + res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); + IMoniker_Release(antiMk); + + /* If any of the components reduces itself, the method returns S_OK and passes back a composite */ + /* of the reduced components */ + if (IMoniker_Reduce(mostRigthMk,pbc,dwReduceHowFar,NULL,&mostRigthReducedMk) && + CompositeMonikerImpl_Reduce(mostRigthMk,pbc,dwReduceHowFar,&tempMk,&leftReducedComposedMk) + ) + + return CreateGenericComposite(leftReducedComposedMk,mostRigthReducedMk,ppmkReduced); + + else{ + /* If no reduction occurred, the method passes back the same moniker and returns MK_S_REDUCED_TO_SELF.*/ + + IMoniker_AddRef(iface); + + *ppmkReduced=iface; + + return MK_S_REDUCED_TO_SELF; + } + } +} + +/****************************************************************************** + * CompositeMoniker_ComposeWith + ******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight, + BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite) +{ + TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite); + + if ((ppmkComposite==NULL)||(pmkRight==NULL)) + return E_POINTER; + + *ppmkComposite=0; + + /* If fOnlyIfNotGeneric is TRUE, this method sets *pmkComposite to NULL and returns MK_E_NEEDGENERIC; */ + /* otherwise, the method returns the result of combining the two monikers by calling the */ + /* CreateGenericComposite function */ + + if (fOnlyIfNotGeneric) + return MK_E_NEEDGENERIC; + + return CreateGenericComposite(iface,pmkRight,ppmkComposite); +} + +/****************************************************************************** + * CompositeMoniker_Enum + ******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker) +{ + CompositeMonikerImpl *This = (CompositeMonikerImpl *)iface; + + TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker); + + if (ppenumMoniker == NULL) + return E_POINTER; + + return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabLastIndex,0,fForward,ppenumMoniker); +} + +/****************************************************************************** + * CompositeMoniker_IsEqual + ******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker) +{ + IEnumMoniker *enumMoniker1,*enumMoniker2; + IMoniker *tempMk1,*tempMk2; + HRESULT res1,res2,res; + + TRACE("(%p,%p)\n",iface,pmkOtherMoniker); + + if (pmkOtherMoniker==NULL) + return S_FALSE; + + /* This method returns S_OK if the components of both monikers are equal when compared in the */ + /* left-to-right order.*/ + IMoniker_Enum(pmkOtherMoniker,TRUE,&enumMoniker1); + + if (enumMoniker1==NULL) + return S_FALSE; + + IMoniker_Enum(iface,TRUE,&enumMoniker2); + + while(1){ + + res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL); + res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL); + + if((res1==S_OK)&&(res2==S_OK)){ + + if(IMoniker_IsEqual(tempMk1,tempMk2)==S_FALSE){ + res= S_FALSE; + break; + } + else + continue; + } + else if ( (res1==S_FALSE) && (res2==S_FALSE) ){ + res = S_OK; + break; + } + else{ + res = S_FALSE; + break; + } + + if (res1==S_OK) + IMoniker_Release(tempMk1); + + if (res2==S_OK) + IMoniker_Release(tempMk2); + } + + IEnumMoniker_Release(enumMoniker1); + IEnumMoniker_Release(enumMoniker2); + + return res; +} +/****************************************************************************** + * CompositeMoniker_Hash + ******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash) +{ + IEnumMoniker *enumMoniker; + IMoniker *tempMk; + HRESULT res; + DWORD tempHash; + + TRACE("(%p,%p)\n",iface,pdwHash); + + if (pdwHash==NULL) + return E_POINTER; + + res = IMoniker_Enum(iface,TRUE,&enumMoniker); + if(FAILED(res)) + return res; + + while(1){ + res=IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL); + if(FAILED(res)) + break; + + res = IMoniker_Hash(tempMk, &tempHash); + if(FAILED(res)) + break; + *pdwHash = (*pdwHash * 37) + tempHash; + + IMoniker_Release(tempMk); + } + + IEnumMoniker_Release(enumMoniker); + + return res; +} + +/****************************************************************************** + * CompositeMoniker_IsRunning + ******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc, + IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning) +{ + IRunningObjectTable* rot; + HRESULT res; + IMoniker *tempMk,*antiMk,*mostRigthMk; + IEnumMoniker *enumMoniker; + + TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning); + + /* If pmkToLeft is non-NULL, this method composes pmkToLeft with this moniker and calls IsRunning on the result.*/ + if (pmkToLeft!=NULL){ + + CreateGenericComposite(pmkToLeft,iface,&tempMk); + + res = IMoniker_IsRunning(tempMk,pbc,NULL,pmkNewlyRunning); + + IMoniker_Release(tempMk); + + return res; + } + else + /* If pmkToLeft is NULL, this method returns S_OK if pmkNewlyRunning is non-NULL and is equal */ + /* to this moniker */ + + if (pmkNewlyRunning!=NULL) + + if (IMoniker_IsEqual(iface,pmkNewlyRunning)==S_OK) + return S_OK; + + else + return S_FALSE; + + else{ + + if (pbc==NULL) + return E_POINTER; + + /* If pmkToLeft and pmkNewlyRunning are both NULL, this method checks the ROT to see whether */ + /* the moniker is running. If so, the method returns S_OK; otherwise, it recursively calls */ + /* IMoniker::IsRunning on the rightmost component of the composite, passing the remainder of */ + /* the composite as the pmkToLeft parameter for that call. */ + + res=IBindCtx_GetRunningObjectTable(pbc,&rot); + + if (FAILED(res)) + return res; + + res = IRunningObjectTable_IsRunning(rot,iface); + IRunningObjectTable_Release(rot); + + if(res==S_OK) + return S_OK; + + else{ + + IMoniker_Enum(iface,FALSE,&enumMoniker); + IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); + IEnumMoniker_Release(enumMoniker); + + res=CreateAntiMoniker(&antiMk); + res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); + IMoniker_Release(antiMk); + + res=IMoniker_IsRunning(mostRigthMk,pbc,tempMk,pmkNewlyRunning); + + IMoniker_Release(tempMk); + IMoniker_Release(mostRigthMk); + + return res; + } + } +} + +/****************************************************************************** + * CompositeMoniker_GetTimeOfLastChange + ******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc, + IMoniker* pmkToLeft, FILETIME* pCompositeTime) +{ + IRunningObjectTable* rot; + HRESULT res; + IMoniker *tempMk,*antiMk,*mostRigthMk; + IEnumMoniker *enumMoniker; + + TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pCompositeTime); + + if (pCompositeTime==NULL) + return E_INVALIDARG; + + /* This method creates a composite of pmkToLeft (if non-NULL) and this moniker and uses the ROT to */ + /* retrieve the time of last change. If the object is not in the ROT, the method recursively calls */ + /* IMoniker::GetTimeOfLastChange on the rightmost component of the composite, passing the remainder */ + /* of the composite as the pmkToLeft parameter for that call. */ + if (pmkToLeft!=NULL){ + + res=CreateGenericComposite(pmkToLeft,iface,&tempMk); + + res=IBindCtx_GetRunningObjectTable(pbc,&rot); + + if (FAILED(res)) + return res; + + if (IRunningObjectTable_GetTimeOfLastChange(rot,tempMk,pCompositeTime)==S_OK) + return res; + else + + IMoniker_Enum(iface,FALSE,&enumMoniker); + IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); + IEnumMoniker_Release(enumMoniker); + + res=CreateAntiMoniker(&antiMk); + res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); + IMoniker_Release(antiMk); + + res=CompositeMonikerImpl_GetTimeOfLastChange(mostRigthMk,pbc,tempMk,pCompositeTime); + + IMoniker_Release(tempMk); + IMoniker_Release(mostRigthMk); + + return res; + } + else + return IMoniker_GetTimeOfLastChange(iface,pbc,NULL,pCompositeTime); +} + +/****************************************************************************** + * CompositeMoniker_Inverse + ******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk) +{ + HRESULT res; + IMoniker *tempMk,*antiMk,*mostRigthMk,*tempInvMk,*mostRigthInvMk; + IEnumMoniker *enumMoniker; + + TRACE("(%p,%p)\n",iface,ppmk); + + if (ppmk==NULL) + return E_POINTER; + + /* This method returns a composite moniker that consists of the inverses of each of the components */ + /* of the original composite, stored in reverse order */ + + res=CreateAntiMoniker(&antiMk); + res=IMoniker_ComposeWith(iface,antiMk,0,&tempMk); + IMoniker_Release(antiMk); + + if (tempMk==NULL) + + return IMoniker_Inverse(iface,ppmk); + + else{ + + IMoniker_Enum(iface,FALSE,&enumMoniker); + IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); + IEnumMoniker_Release(enumMoniker); + + IMoniker_Inverse(mostRigthMk,&mostRigthInvMk); + CompositeMonikerImpl_Inverse(tempMk,&tempInvMk); + + res=CreateGenericComposite(mostRigthInvMk,tempInvMk,ppmk); + + IMoniker_Release(tempMk); + IMoniker_Release(mostRigthMk); + IMoniker_Release(tempInvMk); + IMoniker_Release(mostRigthInvMk); + + return res; + } +} + +/****************************************************************************** + * CompositeMoniker_CommonPrefixWith + ******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerImpl_CommonPrefixWith(IMoniker* iface, IMoniker* pmkOther, + IMoniker** ppmkPrefix) +{ + DWORD mkSys; + HRESULT res1,res2; + IMoniker *tempMk1,*tempMk2,*mostLeftMk1,*mostLeftMk2; + IEnumMoniker *enumMoniker1,*enumMoniker2; + ULONG i,nbCommonMk=0; + + /* If the other moniker is a composite, this method compares the components of each composite from left */ + /* to right. The returned common prefix moniker might also be a composite moniker, depending on how many */ + /* of the leftmost components were common to both monikers. */ + + if (ppmkPrefix==NULL) + return E_POINTER; + + *ppmkPrefix=0; + + if (pmkOther==NULL) + return MK_E_NOPREFIX; + + IMoniker_IsSystemMoniker(pmkOther,&mkSys); + + if((mkSys==MKSYS_GENERICCOMPOSITE)){ + + IMoniker_Enum(iface,TRUE,&enumMoniker1); + IMoniker_Enum(pmkOther,TRUE,&enumMoniker2); + + while(1){ + + res1=IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL); + res2=IEnumMoniker_Next(enumMoniker2,1,&mostLeftMk2,NULL); + + if ((res1==S_FALSE) && (res2==S_FALSE)){ + + /* If the monikers are equal, the method returns MK_S_US and sets ppmkPrefix to this moniker.*/ + *ppmkPrefix=iface; + IMoniker_AddRef(iface); + return MK_S_US; + } + else if ((res1==S_OK) && (res2==S_OK)){ + + if (IMoniker_IsEqual(mostLeftMk1,mostLeftMk2)==S_OK) + + nbCommonMk++; + + else + break; + + } + else if (res1==S_OK){ + + /* If the other moniker is a prefix of this moniker, the method returns MK_S_HIM and sets */ + /* ppmkPrefix to the other moniker. */ + *ppmkPrefix=pmkOther; + return MK_S_HIM; + } + else{ + /* If this moniker is a prefix of the other, this method returns MK_S_ME and sets ppmkPrefix */ + /* to this moniker. */ + *ppmkPrefix=iface; + return MK_S_ME; + } + } + + IEnumMoniker_Release(enumMoniker1); + IEnumMoniker_Release(enumMoniker2); + + /* If there is no common prefix, this method returns MK_E_NOPREFIX and sets ppmkPrefix to NULL. */ + if (nbCommonMk==0) + return MK_E_NOPREFIX; + + IEnumMoniker_Reset(enumMoniker1); + + IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL); + + /* if we have more than one commun moniker the result will be a composite moniker */ + if (nbCommonMk>1){ + + /* initialize the common prefix moniker with the composite of two first moniker (from the left)*/ + IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL); + CreateGenericComposite(tempMk1,tempMk2,ppmkPrefix); + IMoniker_Release(tempMk1); + IMoniker_Release(tempMk2); + + /* compose all common monikers in a composite moniker */ + for(i=0;i<nbCommonMk;i++){ + + IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL); + + CreateGenericComposite(*ppmkPrefix,tempMk1,&tempMk2); + + IMoniker_Release(*ppmkPrefix); + + IMoniker_Release(tempMk1); + + *ppmkPrefix=tempMk2; + } + return S_OK; + } + else{ + /* if we have only one commun moniker the result will be a simple moniker which is the most-left one*/ + *ppmkPrefix=tempMk1; + + return S_OK; + } + } + else{ + /* If the other moniker is not a composite, the method simply compares it to the leftmost component + of this moniker.*/ + + IMoniker_Enum(iface,TRUE,&enumMoniker1); + + IEnumMoniker_Next(enumMoniker1,1,&mostLeftMk1,NULL); + + if (IMoniker_IsEqual(pmkOther,mostLeftMk1)==S_OK){ + + *ppmkPrefix=pmkOther; + + return MK_S_HIM; + } + else + return MK_E_NOPREFIX; + } +} + +/*************************************************************************************************** + * GetAfterCommonPrefix (local function) + * This function returns a moniker that consist of the remainder when the common prefix is removed + ***************************************************************************************************/ +static VOID GetAfterCommonPrefix(IMoniker* pGenMk,IMoniker* commonMk,IMoniker** restMk) +{ + IMoniker *tempMk,*tempMk1,*tempMk2; + IEnumMoniker *enumMoniker1,*enumMoniker2,*enumMoniker3; + ULONG nbRestMk=0; + DWORD mkSys; + HRESULT res1,res2; + + *restMk=0; + + /* to create an enumerator for pGenMk with current position pointed on the first element after common */ + /* prefix: enum the two monikers (left-right) then compare these enumerations (left-right) and stop */ + /* on the first difference. */ + IMoniker_Enum(pGenMk,TRUE,&enumMoniker1); + + IMoniker_IsSystemMoniker(commonMk,&mkSys); + + if (mkSys==MKSYS_GENERICCOMPOSITE){ + + IMoniker_Enum(commonMk,TRUE,&enumMoniker2); + while(1){ + + res1=IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL); + res2=IEnumMoniker_Next(enumMoniker2,1,&tempMk2,NULL); + + if ((res1==S_FALSE)||(res2==S_FALSE)){ + + if (res1==S_OK) + + nbRestMk++; + + IMoniker_Release(tempMk1); + IMoniker_Release(tempMk1); + + break; + } + IMoniker_Release(tempMk1); + IMoniker_Release(tempMk1); + } + } + else{ + IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL); + IMoniker_Release(tempMk1); + } + + /* count the number of elements in the enumerator after the common prefix */ + IEnumMoniker_Clone(enumMoniker1,&enumMoniker3); + + for(;IEnumMoniker_Next(enumMoniker3,1,&tempMk,NULL)==S_OK;nbRestMk++) + + IMoniker_Release(tempMk); + + if (nbRestMk==0) + return; + + /* create a generic composite moniker with monikers located after the common prefix */ + IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL); + + if (nbRestMk==1){ + + *restMk= tempMk1; + return; + } + else { + + IEnumMoniker_Next(enumMoniker1,1,&tempMk2,NULL); + + CreateGenericComposite(tempMk1,tempMk2,restMk); + + IMoniker_Release(tempMk1); + + IMoniker_Release(tempMk2); + + while(IEnumMoniker_Next(enumMoniker1,1,&tempMk1,NULL)==S_OK){ + + CreateGenericComposite(*restMk,tempMk1,&tempMk2); + + IMoniker_Release(tempMk1); + + IMoniker_Release(*restMk); + + *restMk=tempMk2; + } + } +} + +/****************************************************************************** + * CompositeMoniker_RelativePathTo + ******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmkOther, + IMoniker** ppmkRelPath) +{ + HRESULT res; + IMoniker *restOtherMk=0,*restThisMk=0,*invRestThisMk=0,*commonMk=0; + + TRACE("(%p,%p,%p)\n",iface,pmkOther,ppmkRelPath); + + if (ppmkRelPath==NULL) + return E_POINTER; + + *ppmkRelPath=0; + + /* This method finds the common prefix of the two monikers and creates two monikers that consist */ + /* of the remainder when the common prefix is removed. Then it creates the inverse for the remainder */ + /* of this moniker and composes the remainder of the other moniker on the right of it. */ + + /* finds the common prefix of the two monikers */ + res=IMoniker_CommonPrefixWith(iface,pmkOther,&commonMk); + + /* if there's no common prefix or the two moniker are equal the relative is the other moniker */ + if ((res== MK_E_NOPREFIX)||(res==MK_S_US)){ + + *ppmkRelPath=pmkOther; + IMoniker_AddRef(pmkOther); + return MK_S_HIM; + } + + GetAfterCommonPrefix(iface,commonMk,&restThisMk); + GetAfterCommonPrefix(pmkOther,commonMk,&restOtherMk); + + /* if other is a prefix of this moniker the relative path is the inverse of the remainder path of this */ + /* moniker when the common prefix is removed */ + if (res==MK_S_HIM){ + + IMoniker_Inverse(restThisMk,ppmkRelPath); + IMoniker_Release(restThisMk); + } + /* if this moniker is a prefix of other moniker the relative path is the remainder path of other moniker */ + /* when the common prefix is removed */ + else if (res==MK_S_ME){ + + *ppmkRelPath=restOtherMk; + IMoniker_AddRef(restOtherMk); + } + /* the relative path is the inverse for the remainder of this moniker and the remainder of the other */ + /* moniker on the right of it. */ + else if (res==S_OK){ + + IMoniker_Inverse(restThisMk,&invRestThisMk); + IMoniker_Release(restThisMk); + CreateGenericComposite(invRestThisMk,restOtherMk,ppmkRelPath); + IMoniker_Release(invRestThisMk); + IMoniker_Release(restOtherMk); + } + return S_OK; +} + +/****************************************************************************** + * CompositeMoniker_GetDisplayName + ******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc, + IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName) +{ + ULONG lengthStr=1; + IEnumMoniker *enumMoniker; + IMoniker* tempMk; + LPOLESTR tempStr; + + TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName); + + if (ppszDisplayName==NULL) + return E_POINTER; + + *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR)); + + if (*ppszDisplayName==NULL) + return E_OUTOFMEMORY; + + /* This method returns the concatenation of the display names returned by each component moniker of */ + /* the composite */ + + **ppszDisplayName=0; + + IMoniker_Enum(iface,TRUE,&enumMoniker); + + while(IEnumMoniker_Next(enumMoniker,1,&tempMk,NULL)==S_OK){ + + IMoniker_GetDisplayName(tempMk,pbc,NULL,&tempStr); + + lengthStr+=lstrlenW(tempStr); + + *ppszDisplayName=CoTaskMemRealloc(*ppszDisplayName,lengthStr * sizeof(WCHAR)); + + if (*ppszDisplayName==NULL) + return E_OUTOFMEMORY; + + strcatW(*ppszDisplayName,tempStr); + + CoTaskMemFree(tempStr); + IMoniker_Release(tempMk); + } + + IEnumMoniker_Release(enumMoniker); + + return S_OK; +} + +/****************************************************************************** + * CompositeMoniker_ParseDisplayName + ******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc, + IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten, + IMoniker** ppmkOut) +{ + IEnumMoniker *enumMoniker; + IMoniker *tempMk,*mostRigthMk,*antiMk; + /* This method recursively calls IMoniker::ParseDisplayName on the rightmost component of the composite,*/ + /* passing everything else as the pmkToLeft parameter for that call. */ + + /* get the most right moniker */ + IMoniker_Enum(iface,FALSE,&enumMoniker); + IEnumMoniker_Next(enumMoniker,1,&mostRigthMk,NULL); + IEnumMoniker_Release(enumMoniker); + + /* get the left moniker */ + CreateAntiMoniker(&antiMk); + IMoniker_ComposeWith(iface,antiMk,0,&tempMk); + IMoniker_Release(antiMk); + + return IMoniker_ParseDisplayName(mostRigthMk,pbc,tempMk,pszDisplayName,pchEaten,ppmkOut); +} + +/****************************************************************************** + * CompositeMoniker_IsSystemMoniker + ******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys) +{ + TRACE("(%p,%p)\n",iface,pwdMksys); + + if (!pwdMksys) + return E_POINTER; + + (*pwdMksys)=MKSYS_GENERICCOMPOSITE; + + return S_OK; +} + +/******************************************************************************* + * CompositeMonikerIROTData_QueryInterface + *******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid, + VOID** ppvObject) +{ + + ICOM_THIS_From_IROTData(IMoniker, iface); + + TRACE("(%p,%p,%p)\n",iface,riid,ppvObject); + + return CompositeMonikerImpl_QueryInterface(This, riid, ppvObject); +} + +/*********************************************************************** + * CompositeMonikerIROTData_AddRef + */ +static ULONG WINAPI +CompositeMonikerROTDataImpl_AddRef(IROTData *iface) +{ + ICOM_THIS_From_IROTData(IMoniker, iface); + + TRACE("(%p)\n",iface); + + return IMoniker_AddRef(This); +} + +/*********************************************************************** + * CompositeMonikerIROTData_Release + */ +static ULONG WINAPI CompositeMonikerROTDataImpl_Release(IROTData* iface) +{ + ICOM_THIS_From_IROTData(IMoniker, iface); + + TRACE("(%p)\n",iface); + + return IMoniker_Release(This); +} + +/****************************************************************************** + * CompositeMonikerIROTData_GetComparaisonData + ******************************************************************************/ +static HRESULT WINAPI +CompositeMonikerROTDataImpl_GetComparaisonData(IROTData* iface, + BYTE* pbData, ULONG cbMax, ULONG* pcbData) +{ + FIXME("(),stub!\n"); + return E_NOTIMPL; +} + +/****************************************************************************** + * EnumMonikerImpl_QueryInterface + ******************************************************************************/ +static HRESULT WINAPI +EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject) +{ + EnumMonikerImpl *This = (EnumMonikerImpl *)iface; + + TRACE("(%p,%p,%p)\n",This,riid,ppvObject); + + /* Perform a sanity check on the parameters.*/ + if ( (This==0) || (ppvObject==0) ) + return E_INVALIDARG; + + /* Initialize the return parameter */ + *ppvObject = 0; + + /* Compare the riid with the interface IDs implemented by this object.*/ + if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IEnumMoniker, riid)) + *ppvObject = iface; + + /* Check that we obtained an interface.*/ + if ((*ppvObject)==0) + return E_NOINTERFACE; + + /* Query Interface always increases the reference count by one when it is successful */ + IEnumMoniker_AddRef(iface); + + return S_OK; +} + +/****************************************************************************** + * EnumMonikerImpl_AddRef + ******************************************************************************/ +static ULONG WINAPI +EnumMonikerImpl_AddRef(IEnumMoniker* iface) +{ + EnumMonikerImpl *This = (EnumMonikerImpl *)iface; + + TRACE("(%p)\n",This); + + return InterlockedIncrement(&This->ref); + +} + +/****************************************************************************** + * EnumMonikerImpl_Release + ******************************************************************************/ +static ULONG WINAPI +EnumMonikerImpl_Release(IEnumMoniker* iface) +{ + EnumMonikerImpl *This = (EnumMonikerImpl *)iface; + ULONG i; + ULONG ref; + TRACE("(%p)\n",This); + + ref = InterlockedDecrement(&This->ref); + + /* destroy the object if there's no more reference on it */ + if (ref == 0) { + + for(i=0;i<This->tabSize;i++) + IMoniker_Release(This->tabMoniker[i]); + + HeapFree(GetProcessHeap(),0,This->tabMoniker); + HeapFree(GetProcessHeap(),0,This); + } + return ref; +} + +/****************************************************************************** + * EnumMonikerImpl_Next + ******************************************************************************/ +static HRESULT WINAPI +EnumMonikerImpl_Next(IEnumMoniker* iface,ULONG celt, IMoniker** rgelt, + ULONG* pceltFethed) +{ + EnumMonikerImpl *This = (EnumMonikerImpl *)iface; + ULONG i; + + /* retrieve the requested number of moniker from the current position */ + for(i=0;((This->currentPos < This->tabSize) && (i < celt));i++) + + rgelt[i]=This->tabMoniker[This->currentPos++]; + + if (pceltFethed!=NULL) + *pceltFethed= i; + + if (i==celt) + return S_OK; + else + return S_FALSE; +} + +/****************************************************************************** + * EnumMonikerImpl_Skip + ******************************************************************************/ +static HRESULT WINAPI +EnumMonikerImpl_Skip(IEnumMoniker* iface,ULONG celt) +{ + EnumMonikerImpl *This = (EnumMonikerImpl *)iface; + + if ((This->currentPos+celt) >= This->tabSize) + return S_FALSE; + + This->currentPos+=celt; + + return S_OK; +} + +/****************************************************************************** + * EnumMonikerImpl_Reset + ******************************************************************************/ +static HRESULT WINAPI +EnumMonikerImpl_Reset(IEnumMoniker* iface) +{ + + EnumMonikerImpl *This = (EnumMonikerImpl *)iface; + + This->currentPos=0; + + return S_OK; +} + +/****************************************************************************** + * EnumMonikerImpl_Clone + ******************************************************************************/ +static HRESULT WINAPI +EnumMonikerImpl_Clone(IEnumMoniker* iface,IEnumMoniker** ppenum) +{ + EnumMonikerImpl *This = (EnumMonikerImpl *)iface; + + return EnumMonikerImpl_CreateEnumMoniker(This->tabMoniker,This->tabSize,This->currentPos,TRUE,ppenum); +} + +/********************************************************************************/ +/* Virtual function table for the IROTData class */ +static IEnumMonikerVtbl VT_EnumMonikerImpl = +{ + EnumMonikerImpl_QueryInterface, + EnumMonikerImpl_AddRef, + EnumMonikerImpl_Release, + EnumMonikerImpl_Next, + EnumMonikerImpl_Skip, + EnumMonikerImpl_Reset, + EnumMonikerImpl_Clone +}; + +/****************************************************************************** + * EnumMonikerImpl_CreateEnumMoniker + ******************************************************************************/ +static HRESULT +EnumMonikerImpl_CreateEnumMoniker(IMoniker** tabMoniker, ULONG tabSize, + ULONG currentPos, BOOL leftToRigth, IEnumMoniker ** ppmk) +{ + EnumMonikerImpl* newEnumMoniker; + int i; + + if (currentPos > tabSize) + return E_INVALIDARG; + + newEnumMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumMonikerImpl)); + + if (newEnumMoniker == 0) + return STG_E_INSUFFICIENTMEMORY; + + /* Initialize the virtual function table. */ + newEnumMoniker->lpVtbl = &VT_EnumMonikerImpl; + newEnumMoniker->ref = 0; + + newEnumMoniker->tabSize=tabSize; + newEnumMoniker->currentPos=currentPos; + + newEnumMoniker->tabMoniker=HeapAlloc(GetProcessHeap(),0,tabSize*sizeof(IMoniker)); + + if (newEnumMoniker->tabMoniker==NULL) { + HeapFree(GetProcessHeap(), 0, newEnumMoniker); + return E_OUTOFMEMORY; + } + + if (leftToRigth) + for (i=0;i<tabSize;i++){ + + newEnumMoniker->tabMoniker[i]=tabMoniker[i]; + IMoniker_AddRef(tabMoniker[i]); + } + else + for (i=tabSize-1;i>=0;i--){ + + newEnumMoniker->tabMoniker[tabSize-i-1]=tabMoniker[i]; + IMoniker_AddRef(tabMoniker[i]); + } + + *ppmk=(IEnumMoniker*)newEnumMoniker; + + return S_OK; +} + +/********************************************************************************/ +/* Virtual function table for the CompositeMonikerImpl class which includes */ +/* IPersist, IPersistStream and IMoniker functions. */ + +static IMonikerVtbl VT_CompositeMonikerImpl = +{ + CompositeMonikerImpl_QueryInterface, + CompositeMonikerImpl_AddRef, + CompositeMonikerImpl_Release, + CompositeMonikerImpl_GetClassID, + CompositeMonikerImpl_IsDirty, + CompositeMonikerImpl_Load, + CompositeMonikerImpl_Save, + CompositeMonikerImpl_GetSizeMax, + CompositeMonikerImpl_BindToObject, + CompositeMonikerImpl_BindToStorage, + CompositeMonikerImpl_Reduce, + CompositeMonikerImpl_ComposeWith, + CompositeMonikerImpl_Enum, + CompositeMonikerImpl_IsEqual, + CompositeMonikerImpl_Hash, + CompositeMonikerImpl_IsRunning, + CompositeMonikerImpl_GetTimeOfLastChange, + CompositeMonikerImpl_Inverse, + CompositeMonikerImpl_CommonPrefixWith, + CompositeMonikerImpl_RelativePathTo, + CompositeMonikerImpl_GetDisplayName, + CompositeMonikerImpl_ParseDisplayName, + CompositeMonikerImpl_IsSystemMoniker +}; + +/********************************************************************************/ +/* Virtual function table for the IROTData class. */ +static IROTDataVtbl VT_ROTDataImpl = +{ + CompositeMonikerROTDataImpl_QueryInterface, + CompositeMonikerROTDataImpl_AddRef, + CompositeMonikerROTDataImpl_Release, + CompositeMonikerROTDataImpl_GetComparaisonData +}; + +/****************************************************************************** + * Composite-Moniker_Construct (local function) + *******************************************************************************/ +static HRESULT +CompositeMonikerImpl_Construct(CompositeMonikerImpl* This, + LPMONIKER pmkFirst, LPMONIKER pmkRest) +{ + DWORD mkSys; + IEnumMoniker *enumMoniker; + IMoniker *tempMk; + HRESULT res; + + TRACE("(%p,%p,%p)\n",This,pmkFirst,pmkRest); + + /* Initialize the virtual function table. */ + This->lpvtbl1 = &VT_CompositeMonikerImpl; + This->lpvtbl2 = &VT_ROTDataImpl; + This->ref = 0; + + This->tabSize=BLOCK_TAB_SIZE; + This->tabLastIndex=0; + + This->tabMoniker=HeapAlloc(GetProcessHeap(),0,This->tabSize*sizeof(IMoniker)); + if (This->tabMoniker==NULL) + return E_OUTOFMEMORY; + + IMoniker_IsSystemMoniker(pmkFirst,&mkSys); + + /* put the first moniker contents in the beginning of the table */ + if (mkSys!=MKSYS_GENERICCOMPOSITE){ + + This->tabMoniker[(This->tabLastIndex)++]=pmkFirst; + IMoniker_AddRef(pmkFirst); + } + else{ + + IMoniker_Enum(pmkFirst,TRUE,&enumMoniker); + + while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){ + + + if (++This->tabLastIndex==This->tabSize){ + + This->tabSize+=BLOCK_TAB_SIZE; + This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker)); + + if (This->tabMoniker==NULL) + return E_OUTOFMEMORY; + } + } + + IEnumMoniker_Release(enumMoniker); + } + + /* put the rest moniker contents after the first one and make simplification if needed */ + + IMoniker_IsSystemMoniker(pmkRest,&mkSys); + + if (mkSys!=MKSYS_GENERICCOMPOSITE){ + + /* add a simple moniker to the moniker table */ + + res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],pmkRest,TRUE,&tempMk); + + if (res==MK_E_NEEDGENERIC){ + + /* there's no simplification in this case */ + This->tabMoniker[This->tabLastIndex]=pmkRest; + + This->tabLastIndex++; + + IMoniker_AddRef(pmkRest); + } + else if (tempMk==NULL){ + + /* we have an antimoniker after a simple moniker so we can make a simplification in this case */ + IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]); + + This->tabLastIndex--; + } + else if (SUCCEEDED(res)){ + + /* the non-generic composition was successful so we can make a simplification in this case */ + IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]); + + This->tabMoniker[This->tabLastIndex-1]=tempMk; + } else + return res; + + /* resize tabMoniker if needed */ + if (This->tabLastIndex==This->tabSize){ + + This->tabSize+=BLOCK_TAB_SIZE; + + This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker)); + + if (This->tabMoniker==NULL) + return E_OUTOFMEMORY; + } + } + else{ + + /* add a composite moniker to the moniker table (do the same thing + * for each moniker within the composite moniker as a simple moniker + * (see above for how to add a simple moniker case) ) + */ + IMoniker_Enum(pmkRest,TRUE,&enumMoniker); + + while(IEnumMoniker_Next(enumMoniker,1,&This->tabMoniker[This->tabLastIndex],NULL)==S_OK){ + + res=IMoniker_ComposeWith(This->tabMoniker[This->tabLastIndex-1],This->tabMoniker[This->tabLastIndex],TRUE,&tempMk); + + if (res==MK_E_NEEDGENERIC){ + + This->tabLastIndex++; + } + else if (tempMk==NULL){ + + IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]); + IMoniker_Release(This->tabMoniker[This->tabLastIndex]); + This->tabLastIndex--; + } + else{ + + IMoniker_Release(This->tabMoniker[This->tabLastIndex-1]); + + This->tabMoniker[This->tabLastIndex-1]=tempMk; + } + + if (This->tabLastIndex==This->tabSize){ + + This->tabSize+=BLOCK_TAB_SIZE; + + This->tabMoniker=HeapReAlloc(GetProcessHeap(),0,This->tabMoniker,This->tabSize*sizeof(IMoniker)); + + if (This->tabMoniker==NULL) + return E_OUTOFMEMORY; + } + } + + IEnumMoniker_Release(enumMoniker); + } + + return S_OK; +} + +/****************************************************************************** + * CreateGenericComposite [OLE32.@] + ******************************************************************************/ +HRESULT WINAPI +CreateGenericComposite(LPMONIKER pmkFirst, LPMONIKER pmkRest, + LPMONIKER* ppmkComposite) +{ + CompositeMonikerImpl* newCompositeMoniker = 0; + HRESULT hr = S_OK; + + TRACE("(%p,%p,%p)\n",pmkFirst,pmkRest,ppmkComposite); + + if (ppmkComposite==NULL) + return E_POINTER; + + *ppmkComposite=0; + + if (pmkFirst==NULL && pmkRest!=NULL){ + + *ppmkComposite=pmkRest; + return S_OK; + } + else if (pmkFirst!=NULL && pmkRest==NULL){ + *ppmkComposite=pmkFirst; + return S_OK; + } + else if (pmkFirst==NULL && pmkRest==NULL) + return S_OK; + + newCompositeMoniker = HeapAlloc(GetProcessHeap(), 0,sizeof(CompositeMonikerImpl)); + + if (newCompositeMoniker == 0) + return STG_E_INSUFFICIENTMEMORY; + + hr = CompositeMonikerImpl_Construct(newCompositeMoniker,pmkFirst,pmkRest); + + if (FAILED(hr)){ + + HeapFree(GetProcessHeap(),0,newCompositeMoniker); + return hr; + } + if (newCompositeMoniker->tabLastIndex==1) + + hr = IMoniker_QueryInterface(newCompositeMoniker->tabMoniker[0],&IID_IMoniker,(void**)ppmkComposite); + else + + hr = IMoniker_QueryInterface((IMoniker*)newCompositeMoniker,&IID_IMoniker,(void**)ppmkComposite); + + return hr; +} + +/****************************************************************************** + * MonikerCommonPrefixWith [OLE32.@] + ******************************************************************************/ +HRESULT WINAPI +MonikerCommonPrefixWith(IMoniker* pmkThis,IMoniker* pmkOther,IMoniker** ppmkCommon) +{ + FIXME("(),stub!\n"); + return E_NOTIMPL; +} diff --git a/reactos/lib/ole32/datacache.c b/reactos/lib/ole32/datacache.c index 2da3f115fbe..298defbf89b 100644 --- a/reactos/lib/ole32/datacache.c +++ b/reactos/lib/ole32/datacache.c @@ -1,1802 +1,1802 @@ -/* - * OLE 2 Data cache - * - * Copyright 1999 Francis Beaudet - * Copyright 2000 Abey George - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTES: - * The OLE2 data cache supports a whole whack of - * interfaces including: - * IDataObject, IPersistStorage, IViewObject2, - * IOleCache2 and IOleCacheControl. - * - * Most of the implementation details are taken from: Inside OLE - * second edition by Kraig Brockschmidt, - * - * NOTES - * - This implementation of the datacache will let your application - * load documents that have embedded OLE objects in them and it will - * also retrieve the metafile representation of those objects. - * - This implementation of the datacache will also allow your - * application to save new documents with OLE objects in them. - * - The main thing that it doesn't do is allow you to activate - * or modify the OLE objects in any way. - * - I haven't found any good documentation on the real usage of - * the streams created by the data cache. In particular, How to - * determine what the XXX stands for in the stream name - * "\002OlePresXXX". It appears to just be a counter. - * - Also, I don't know the real content of the presentation stream - * header. I was able to figure-out where the extent of the object - * was stored and the aspect, but that's about it. - */ -#include <assert.h> -#include <stdarg.h> -#include <string.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winerror.h" -#include "wine/unicode.h" -#include "ole2.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/**************************************************************************** - * PresentationDataHeader - * - * This structure represents the header of the \002OlePresXXX stream in - * the OLE object strorage. - * - * Most fields are still unknown. - */ -typedef struct PresentationDataHeader -{ - DWORD unknown1; /* -1 */ - DWORD unknown2; /* 3, possibly CF_METAFILEPICT */ - DWORD unknown3; /* 4, possibly TYMED_ISTREAM */ - DVASPECT dvAspect; - DWORD unknown5; /* -1 */ - - DWORD unknown6; - DWORD unknown7; /* 0 */ - DWORD dwObjectExtentX; - DWORD dwObjectExtentY; - DWORD dwSize; -} PresentationDataHeader; - -/**************************************************************************** - * DataCache - */ -struct DataCache -{ - /* - * List all interface VTables here - */ - IDataObjectVtbl* lpvtbl1; - IUnknownVtbl* lpvtbl2; - IPersistStorageVtbl* lpvtbl3; - IViewObject2Vtbl* lpvtbl4; - IOleCache2Vtbl* lpvtbl5; - IOleCacheControlVtbl* lpvtbl6; - - /* - * Reference count of this object - */ - ULONG ref; - - /* - * IUnknown implementation of the outer object. - */ - IUnknown* outerUnknown; - - /* - * This storage pointer is set through a call to - * IPersistStorage_Load. This is where the visual - * representation of the object is stored. - */ - IStorage* presentationStorage; - - /* - * The user of this object can setup ONE advise sink - * connection with the object. These parameters describe - * that connection. - */ - DWORD sinkAspects; - DWORD sinkAdviseFlag; - IAdviseSink* sinkInterface; - -}; - -typedef struct DataCache DataCache; - -/* - * Here, I define utility macros to help with the casting of the - * "this" parameter. - * There is a version to accommodate all of the VTables implemented - * by this object. - */ -#define _ICOM_THIS_From_IDataObject(class,name) class* this = (class*)name -#define _ICOM_THIS_From_NDIUnknown(class, name) class* this = (class*)(((char*)name)-sizeof(void*)) -#define _ICOM_THIS_From_IPersistStorage(class, name) class* this = (class*)(((char*)name)-2*sizeof(void*)) -#define _ICOM_THIS_From_IViewObject2(class, name) class* this = (class*)(((char*)name)-3*sizeof(void*)) -#define _ICOM_THIS_From_IOleCache2(class, name) class* this = (class*)(((char*)name)-4*sizeof(void*)) -#define _ICOM_THIS_From_IOleCacheControl(class, name) class* this = (class*)(((char*)name)-5*sizeof(void*)) - -/* - * Prototypes for the methods of the DataCache class. - */ -static DataCache* DataCache_Construct(REFCLSID clsid, - LPUNKNOWN pUnkOuter); -static HRESULT DataCache_OpenPresStream(DataCache *this, - DWORD drawAspect, - IStream **pStm); - -static void DataCache_Destroy( - DataCache* ptrToDestroy) -{ - TRACE("()\n"); - - if (ptrToDestroy->sinkInterface != NULL) - { - IAdviseSink_Release(ptrToDestroy->sinkInterface); - ptrToDestroy->sinkInterface = NULL; - } - - if (ptrToDestroy->presentationStorage != NULL) - { - IStorage_Release(ptrToDestroy->presentationStorage); - ptrToDestroy->presentationStorage = NULL; - } - - /* - * Free the datacache pointer. - */ - HeapFree(GetProcessHeap(), 0, ptrToDestroy); -} - -/************************************************************************ - * DataCache_ReadPresentationData - * - * This method will read information for the requested presentation - * into the given structure. - * - * Param: - * this - Pointer to the DataCache object - * drawAspect - The aspect of the object that we wish to draw. - * header - The structure containing information about this - * aspect of the object. - */ -static HRESULT DataCache_ReadPresentationData( - DataCache* this, - DWORD drawAspect, - PresentationDataHeader* header) -{ - IStream* presStream = NULL; - HRESULT hres; - - /* - * Open the presentation stream. - */ - hres = DataCache_OpenPresStream( - this, - drawAspect, - &presStream); - - if (FAILED(hres)) - return hres; - - /* - * Read the header. - */ - - hres = IStream_Read( - presStream, - header, - sizeof(PresentationDataHeader), - NULL); - - /* - * Cleanup. - */ - IStream_Release(presStream); - - /* - * We don't want to propagate any other error - * code than a failure. - */ - if (hres!=S_OK) - hres = E_FAIL; - - return hres; -} - -/************************************************************************ - * DataCache_FireOnViewChange - * - * This method will fire an OnViewChange notification to the advise - * sink registered with the datacache. - * - * See IAdviseSink::OnViewChange for more details. - */ -static void DataCache_FireOnViewChange( - DataCache* this, - DWORD aspect, - LONG lindex) -{ - TRACE("(%p, %lx, %ld)\n", this, aspect, lindex); - - /* - * The sink supplies a filter when it registers - * we make sure we only send the notifications when that - * filter matches. - */ - if ((this->sinkAspects & aspect) != 0) - { - if (this->sinkInterface != NULL) - { - IAdviseSink_OnViewChange(this->sinkInterface, - aspect, - lindex); - - /* - * Some sinks want to be unregistered automatically when - * the first notification goes out. - */ - if ( (this->sinkAdviseFlag & ADVF_ONLYONCE) != 0) - { - IAdviseSink_Release(this->sinkInterface); - - this->sinkInterface = NULL; - this->sinkAspects = 0; - this->sinkAdviseFlag = 0; - } - } - } -} - -/* Helper for DataCache_OpenPresStream */ -static BOOL DataCache_IsPresentationStream(const STATSTG *elem) -{ - /* The presentation streams have names of the form "\002OlePresXXX", - * where XXX goes from 000 to 999. */ - static const WCHAR OlePres[] = { 2,'O','l','e','P','r','e','s' }; - - LPCWSTR name = elem->pwcsName; - - return (elem->type == STGTY_STREAM) - && (elem->cbSize.u.LowPart >= sizeof(PresentationDataHeader)) - && (strlenW(name) == 11) - && (strncmpW(name, OlePres, 8) == 0) - && (name[8] >= '0') && (name[8] <= '9') - && (name[9] >= '0') && (name[9] <= '9') - && (name[10] >= '0') && (name[10] <= '9'); -} - -/************************************************************************ - * DataCache_OpenPresStream - * - * This method will find the stream for the given presentation. It makes - * no attempt at fallback. - * - * Param: - * this - Pointer to the DataCache object - * drawAspect - The aspect of the object that we wish to draw. - * pStm - A returned stream. It points to the beginning of the - * - presentation data, including the header. - * - * Errors: - * S_OK The requested stream has been opened. - * OLE_E_BLANK The requested stream could not be found. - * Quite a few others I'm too lazy to map correctly. - * - * Notes: - * Algorithm: Scan the elements of the presentation storage, looking - * for presentation streams. For each presentation stream, - * load the header and check to see if the aspect maches. - * - * If a fallback is desired, just opening the first presentation stream - * is a possibility. - */ -static HRESULT DataCache_OpenPresStream( - DataCache *this, - DWORD drawAspect, - IStream **ppStm) -{ - STATSTG elem; - IEnumSTATSTG *pEnum; - HRESULT hr; - - if (!ppStm) return E_POINTER; - - hr = IStorage_EnumElements(this->presentationStorage, 0, NULL, 0, &pEnum); - if (FAILED(hr)) return hr; - - while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK) - { - if (DataCache_IsPresentationStream(&elem)) - { - IStream *pStm; - - hr = IStorage_OpenStream(this->presentationStorage, elem.pwcsName, - NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, - &pStm); - if (SUCCEEDED(hr)) - { - PresentationDataHeader header; - ULONG actual_read; - - hr = IStream_Read(pStm, &header, sizeof(header), &actual_read); - - /* can't use SUCCEEDED(hr): S_FALSE counts as an error */ - if (hr == S_OK && actual_read == sizeof(header) - && header.dvAspect == drawAspect) - { - /* Rewind the stream before returning it. */ - LARGE_INTEGER offset; - offset.u.LowPart = 0; - offset.u.HighPart = 0; - IStream_Seek(pStm, offset, STREAM_SEEK_SET, NULL); - - *ppStm = pStm; - - CoTaskMemFree(elem.pwcsName); - IEnumSTATSTG_Release(pEnum); - - return S_OK; - } - - IStream_Release(pStm); - } - } - - CoTaskMemFree(elem.pwcsName); - } - - IEnumSTATSTG_Release(pEnum); - - return (hr == S_FALSE ? OLE_E_BLANK : hr); -} - -/************************************************************************ - * DataCache_ReadPresentationData - * - * This method will read information for the requested presentation - * into the given structure. - * - * Param: - * this - Pointer to the DataCache object - * drawAspect - The aspect of the object that we wish to draw. - * - * Returns: - * This method returns a metafile handle if it is successful. - * it will return 0 if not. - */ -static HMETAFILE DataCache_ReadPresMetafile( - DataCache* this, - DWORD drawAspect) -{ - LARGE_INTEGER offset; - IStream* presStream = NULL; - HRESULT hres; - void* metafileBits; - STATSTG streamInfo; - HMETAFILE newMetafile = 0; - - /* - * Open the presentation stream. - */ - hres = DataCache_OpenPresStream( - this, - drawAspect, - &presStream); - - if (FAILED(hres)) - return (HMETAFILE)hres; - - /* - * Get the size of the stream. - */ - hres = IStream_Stat(presStream, - &streamInfo, - STATFLAG_NONAME); - - /* - * Skip the header - */ - offset.u.HighPart = 0; - offset.u.LowPart = sizeof(PresentationDataHeader); - - hres = IStream_Seek( - presStream, - offset, - STREAM_SEEK_SET, - NULL); - - streamInfo.cbSize.u.LowPart -= offset.u.LowPart; - - /* - * Allocate a buffer for the metafile bits. - */ - metafileBits = HeapAlloc(GetProcessHeap(), - 0, - streamInfo.cbSize.u.LowPart); - - /* - * Read the metafile bits. - */ - hres = IStream_Read( - presStream, - metafileBits, - streamInfo.cbSize.u.LowPart, - NULL); - - /* - * Create a metafile with those bits. - */ - if (SUCCEEDED(hres)) - { - newMetafile = SetMetaFileBitsEx(streamInfo.cbSize.u.LowPart, metafileBits); - } - - /* - * Cleanup. - */ - HeapFree(GetProcessHeap(), 0, metafileBits); - IStream_Release(presStream); - - if (newMetafile==0) - hres = E_FAIL; - - return newMetafile; -} - -/********************************************************* - * Method implementation for the non delegating IUnknown - * part of the DataCache class. - */ - -/************************************************************************ - * DataCache_NDIUnknown_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - * - * This version of QueryInterface will not delegate it's implementation - * to the outer unknown. - */ -static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface( - IUnknown* iface, - REFIID riid, - void** ppvObject) -{ - _ICOM_THIS_From_NDIUnknown(DataCache, iface); - - /* - * Perform a sanity check on the parameters. - */ - if ( (this==0) || (ppvObject==0) ) - return E_INVALIDARG; - - /* - * Initialize the return parameter. - */ - *ppvObject = 0; - - /* - * Compare the riid with the interface IDs implemented by this object. - */ - if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) - { - *ppvObject = iface; - } - else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0) - { - *ppvObject = (IDataObject*)&(this->lpvtbl1); - } - else if ( (memcmp(&IID_IPersistStorage, riid, sizeof(IID_IPersistStorage)) == 0) || - (memcmp(&IID_IPersist, riid, sizeof(IID_IPersist)) == 0) ) - { - *ppvObject = (IPersistStorage*)&(this->lpvtbl3); - } - else if ( (memcmp(&IID_IViewObject, riid, sizeof(IID_IViewObject)) == 0) || - (memcmp(&IID_IViewObject2, riid, sizeof(IID_IViewObject2)) == 0) ) - { - *ppvObject = (IViewObject2*)&(this->lpvtbl4); - } - else if ( (memcmp(&IID_IOleCache, riid, sizeof(IID_IOleCache)) == 0) || - (memcmp(&IID_IOleCache2, riid, sizeof(IID_IOleCache2)) == 0) ) - { - *ppvObject = (IOleCache2*)&(this->lpvtbl5); - } - else if (memcmp(&IID_IOleCacheControl, riid, sizeof(IID_IOleCacheControl)) == 0) - { - *ppvObject = (IOleCacheControl*)&(this->lpvtbl6); - } - - /* - * Check that we obtained an interface. - */ - if ((*ppvObject)==0) - { - WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; - } - - /* - * Query Interface always increases the reference count by one when it is - * successful. - */ - IUnknown_AddRef((IUnknown*)*ppvObject); - - return S_OK; -} - -/************************************************************************ - * DataCache_NDIUnknown_AddRef (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - * - * This version of QueryInterface will not delegate it's implementation - * to the outer unknown. - */ -static ULONG WINAPI DataCache_NDIUnknown_AddRef( - IUnknown* iface) -{ - _ICOM_THIS_From_NDIUnknown(DataCache, iface); - return InterlockedIncrement(&this->ref); -} - -/************************************************************************ - * DataCache_NDIUnknown_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - * - * This version of QueryInterface will not delegate it's implementation - * to the outer unknown. - */ -static ULONG WINAPI DataCache_NDIUnknown_Release( - IUnknown* iface) -{ - _ICOM_THIS_From_NDIUnknown(DataCache, iface); - ULONG ref; - - /* - * Decrease the reference count on this object. - */ - ref = InterlockedDecrement(&this->ref); - - /* - * If the reference count goes down to 0, perform suicide. - */ - if (ref == 0) DataCache_Destroy(this); - - return ref; -} - -/********************************************************* - * Method implementation for the IDataObject - * part of the DataCache class. - */ - -/************************************************************************ - * DataCache_IDataObject_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static HRESULT WINAPI DataCache_IDataObject_QueryInterface( - IDataObject* iface, - REFIID riid, - void** ppvObject) -{ - _ICOM_THIS_From_IDataObject(DataCache, iface); - - return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject); -} - -/************************************************************************ - * DataCache_IDataObject_AddRef (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI DataCache_IDataObject_AddRef( - IDataObject* iface) -{ - _ICOM_THIS_From_IDataObject(DataCache, iface); - - return IUnknown_AddRef(this->outerUnknown); -} - -/************************************************************************ - * DataCache_IDataObject_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI DataCache_IDataObject_Release( - IDataObject* iface) -{ - _ICOM_THIS_From_IDataObject(DataCache, iface); - - return IUnknown_Release(this->outerUnknown); -} - -/************************************************************************ - * DataCache_GetData - * - * Get Data from a source dataobject using format pformatetcIn->cfFormat - * See Windows documentation for more details on GetData. - * TODO: Currently only CF_METAFILEPICT is implemented - */ -static HRESULT WINAPI DataCache_GetData( - IDataObject* iface, - LPFORMATETC pformatetcIn, - STGMEDIUM* pmedium) -{ - HRESULT hr = 0; - HRESULT hrRet = E_UNEXPECTED; - IPersistStorage *pPersistStorage = 0; - IStorage *pStorage = 0; - IStream *pStream = 0; - OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0}; - HGLOBAL hGlobalMF = 0; - void *mfBits = 0; - PresentationDataHeader pdh; - METAFILEPICT *mfPict; - HMETAFILE hMetaFile = 0; - - if (pformatetcIn->cfFormat == CF_METAFILEPICT) - { - /* Get the Persist Storage */ - - hr = IDataObject_QueryInterface(iface, &IID_IPersistStorage, (void**)&pPersistStorage); - - if (hr != S_OK) - goto cleanup; - - /* Create a doc file to copy the doc to a storage */ - - hr = StgCreateDocfile(NULL, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pStorage); - - if (hr != S_OK) - goto cleanup; - - /* Save it to storage */ - - hr = OleSave(pPersistStorage, pStorage, FALSE); - - if (hr != S_OK) - goto cleanup; - - /* Open the Presentation data srteam */ - - hr = IStorage_OpenStream(pStorage, name, 0, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &pStream); - - if (hr != S_OK) - goto cleanup; - - /* Read the presentation header */ - - hr = IStream_Read(pStream, &pdh, sizeof(PresentationDataHeader), NULL); - - if (hr != S_OK) - goto cleanup; - - mfBits = HeapAlloc(GetProcessHeap(), 0, pdh.dwSize); - - /* Read the Metafile bits */ - - hr = IStream_Read(pStream, mfBits, pdh.dwSize, NULL); - - if (hr != S_OK) - goto cleanup; - - /* Create the metafile and place it in the STGMEDIUM structure */ - - hMetaFile = SetMetaFileBitsEx(pdh.dwSize, mfBits); - - hGlobalMF = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, sizeof(METAFILEPICT)); - mfPict = (METAFILEPICT *)GlobalLock(hGlobalMF); - mfPict->hMF = hMetaFile; - - GlobalUnlock(hGlobalMF); - - pmedium->u.hGlobal = hGlobalMF; - pmedium->tymed = TYMED_MFPICT; - hrRet = S_OK; - -cleanup: - - HeapFree(GetProcessHeap(), 0, mfBits); - - if (pStream) - IStream_Release(pStream); - - if (pStorage) - IStorage_Release(pStorage); - - if (pPersistStorage) - IPersistStorage_Release(pPersistStorage); - - return hrRet; - } - - /* TODO: Other formats are not implemented */ - - return E_NOTIMPL; -} - -static HRESULT WINAPI DataCache_GetDataHere( - IDataObject* iface, - LPFORMATETC pformatetc, - STGMEDIUM* pmedium) -{ - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI DataCache_QueryGetData( - IDataObject* iface, - LPFORMATETC pformatetc) -{ - FIXME("stub\n"); - return E_NOTIMPL; -} - -/************************************************************************ - * DataCache_EnumFormatEtc (IDataObject) - * - * The data cache doesn't implement this method. - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI DataCache_GetCanonicalFormatEtc( - IDataObject* iface, - LPFORMATETC pformatectIn, - LPFORMATETC pformatetcOut) -{ - TRACE("()\n"); - return E_NOTIMPL; -} - -/************************************************************************ - * DataCache_IDataObject_SetData (IDataObject) - * - * This method is delegated to the IOleCache2 implementation. - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI DataCache_IDataObject_SetData( - IDataObject* iface, - LPFORMATETC pformatetc, - STGMEDIUM* pmedium, - BOOL fRelease) -{ - IOleCache2* oleCache = NULL; - HRESULT hres; - - TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease); - - hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache); - - if (FAILED(hres)) - return E_UNEXPECTED; - - hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease); - - IOleCache2_Release(oleCache); - - return hres; -} - -/************************************************************************ - * DataCache_EnumFormatEtc (IDataObject) - * - * The data cache doesn't implement this method. - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI DataCache_EnumFormatEtc( - IDataObject* iface, - DWORD dwDirection, - IEnumFORMATETC** ppenumFormatEtc) -{ - TRACE("()\n"); - return E_NOTIMPL; -} - -/************************************************************************ - * DataCache_DAdvise (IDataObject) - * - * The data cache doesn't support connections. - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI DataCache_DAdvise( - IDataObject* iface, - FORMATETC* pformatetc, - DWORD advf, - IAdviseSink* pAdvSink, - DWORD* pdwConnection) -{ - TRACE("()\n"); - return OLE_E_ADVISENOTSUPPORTED; -} - -/************************************************************************ - * DataCache_DUnadvise (IDataObject) - * - * The data cache doesn't support connections. - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI DataCache_DUnadvise( - IDataObject* iface, - DWORD dwConnection) -{ - TRACE("()\n"); - return OLE_E_NOCONNECTION; -} - -/************************************************************************ - * DataCache_EnumDAdvise (IDataObject) - * - * The data cache doesn't support connections. - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI DataCache_EnumDAdvise( - IDataObject* iface, - IEnumSTATDATA** ppenumAdvise) -{ - TRACE("()\n"); - return OLE_E_ADVISENOTSUPPORTED; -} - -/********************************************************* - * Method implementation for the IDataObject - * part of the DataCache class. - */ - -/************************************************************************ - * DataCache_IPersistStorage_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface( - IPersistStorage* iface, - REFIID riid, - void** ppvObject) -{ - _ICOM_THIS_From_IPersistStorage(DataCache, iface); - - return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject); -} - -/************************************************************************ - * DataCache_IPersistStorage_AddRef (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI DataCache_IPersistStorage_AddRef( - IPersistStorage* iface) -{ - _ICOM_THIS_From_IPersistStorage(DataCache, iface); - - return IUnknown_AddRef(this->outerUnknown); -} - -/************************************************************************ - * DataCache_IPersistStorage_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI DataCache_IPersistStorage_Release( - IPersistStorage* iface) -{ - _ICOM_THIS_From_IPersistStorage(DataCache, iface); - - return IUnknown_Release(this->outerUnknown); -} - -/************************************************************************ - * DataCache_GetClassID (IPersistStorage) - * - * The data cache doesn't implement this method. - * - * See Windows documentation for more details on IPersistStorage methods. - */ -static HRESULT WINAPI DataCache_GetClassID( - IPersistStorage* iface, - CLSID* pClassID) -{ - TRACE("(%p, %p)\n", iface, pClassID); - return E_NOTIMPL; -} - -/************************************************************************ - * DataCache_IsDirty (IPersistStorage) - * - * Until we actully connect to a running object and retrieve new - * information to it, we never get dirty. - * - * See Windows documentation for more details on IPersistStorage methods. - */ -static HRESULT WINAPI DataCache_IsDirty( - IPersistStorage* iface) -{ - TRACE("(%p)\n", iface); - - return S_FALSE; -} - -/************************************************************************ - * DataCache_InitNew (IPersistStorage) - * - * The data cache implementation of IPersistStorage_InitNew simply stores - * the storage pointer. - * - * See Windows documentation for more details on IPersistStorage methods. - */ -static HRESULT WINAPI DataCache_InitNew( - IPersistStorage* iface, - IStorage* pStg) -{ - TRACE("(%p, %p)\n", iface, pStg); - - return IPersistStorage_Load(iface, pStg); -} - -/************************************************************************ - * DataCache_Load (IPersistStorage) - * - * The data cache implementation of IPersistStorage_Load doesn't - * actually load anything. Instead, it holds on to the storage pointer - * and it will load the presentation information when the - * IDataObject_GetData or IViewObject2_Draw methods are called. - * - * See Windows documentation for more details on IPersistStorage methods. - */ -static HRESULT WINAPI DataCache_Load( - IPersistStorage* iface, - IStorage* pStg) -{ - _ICOM_THIS_From_IPersistStorage(DataCache, iface); - - TRACE("(%p, %p)\n", iface, pStg); - - if (this->presentationStorage != NULL) - { - IStorage_Release(this->presentationStorage); - } - - this->presentationStorage = pStg; - - if (this->presentationStorage != NULL) - { - IStorage_AddRef(this->presentationStorage); - } - return S_OK; -} - -/************************************************************************ - * DataCache_Save (IPersistStorage) - * - * Until we actully connect to a running object and retrieve new - * information to it, we never have to save anything. However, it is - * our responsability to copy the information when saving to a new - * storage. - * - * See Windows documentation for more details on IPersistStorage methods. - */ -static HRESULT WINAPI DataCache_Save( - IPersistStorage* iface, - IStorage* pStg, - BOOL fSameAsLoad) -{ - _ICOM_THIS_From_IPersistStorage(DataCache, iface); - - TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad); - - if ( (!fSameAsLoad) && - (this->presentationStorage!=NULL) ) - { - return IStorage_CopyTo(this->presentationStorage, - 0, - NULL, - NULL, - pStg); - } - - return S_OK; -} - -/************************************************************************ - * DataCache_SaveCompleted (IPersistStorage) - * - * This method is called to tell the cache to release the storage - * pointer it's currentlu holding. - * - * See Windows documentation for more details on IPersistStorage methods. - */ -static HRESULT WINAPI DataCache_SaveCompleted( - IPersistStorage* iface, - IStorage* pStgNew) -{ - TRACE("(%p, %p)\n", iface, pStgNew); - - if (pStgNew) - { - /* - * First, make sure we get our hands off any storage we have. - */ - - IPersistStorage_HandsOffStorage(iface); - - /* - * Then, attach to the new storage. - */ - - DataCache_Load(iface, pStgNew); - } - - return S_OK; -} - -/************************************************************************ - * DataCache_HandsOffStorage (IPersistStorage) - * - * This method is called to tell the cache to release the storage - * pointer it's currentlu holding. - * - * See Windows documentation for more details on IPersistStorage methods. - */ -static HRESULT WINAPI DataCache_HandsOffStorage( - IPersistStorage* iface) -{ - _ICOM_THIS_From_IPersistStorage(DataCache, iface); - - TRACE("(%p)\n", iface); - - if (this->presentationStorage != NULL) - { - IStorage_Release(this->presentationStorage); - this->presentationStorage = NULL; - } - - return S_OK; -} - -/********************************************************* - * Method implementation for the IViewObject2 - * part of the DataCache class. - */ - -/************************************************************************ - * DataCache_IViewObject2_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static HRESULT WINAPI DataCache_IViewObject2_QueryInterface( - IViewObject2* iface, - REFIID riid, - void** ppvObject) -{ - _ICOM_THIS_From_IViewObject2(DataCache, iface); - - return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject); -} - -/************************************************************************ - * DataCache_IViewObject2_AddRef (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI DataCache_IViewObject2_AddRef( - IViewObject2* iface) -{ - _ICOM_THIS_From_IViewObject2(DataCache, iface); - - return IUnknown_AddRef(this->outerUnknown); -} - -/************************************************************************ - * DataCache_IViewObject2_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI DataCache_IViewObject2_Release( - IViewObject2* iface) -{ - _ICOM_THIS_From_IViewObject2(DataCache, iface); - - return IUnknown_Release(this->outerUnknown); -} - -/************************************************************************ - * DataCache_Draw (IViewObject2) - * - * This method will draw the cached representation of the object - * to the given device context. - * - * See Windows documentation for more details on IViewObject2 methods. - */ -static HRESULT WINAPI DataCache_Draw( - IViewObject2* iface, - DWORD dwDrawAspect, - LONG lindex, - void* pvAspect, - DVTARGETDEVICE* ptd, - HDC hdcTargetDev, - HDC hdcDraw, - LPCRECTL lprcBounds, - LPCRECTL lprcWBounds, - BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue), - ULONG_PTR dwContinue) -{ - PresentationDataHeader presData; - HMETAFILE presMetafile = 0; - HRESULT hres; - - _ICOM_THIS_From_IViewObject2(DataCache, iface); - - TRACE("(%p, %lx, %ld, %p, %p, %p, %p, %p, %p, %lx)\n", - iface, - dwDrawAspect, - lindex, - pvAspect, - hdcTargetDev, - hdcDraw, - lprcBounds, - lprcWBounds, - pfnContinue, - dwContinue); - - /* - * Sanity check - */ - if (lprcBounds==NULL) - return E_INVALIDARG; - - /* - * First, we need to retrieve the dimensions of the - * image in the metafile. - */ - hres = DataCache_ReadPresentationData(this, - dwDrawAspect, - &presData); - - if (FAILED(hres)) - return hres; - - /* - * Then, we can extract the metafile itself from the cached - * data. - * - * FIXME Unless it isn't a metafile. I think it could be any CF_XXX type, - * particularly CF_DIB. - */ - presMetafile = DataCache_ReadPresMetafile(this, - dwDrawAspect); - - /* - * If we have a metafile, just draw baby... - * We have to be careful not to modify the state of the - * DC. - */ - if (presMetafile!=0) - { - INT prevMapMode = SetMapMode(hdcDraw, MM_ANISOTROPIC); - SIZE oldWindowExt; - SIZE oldViewportExt; - POINT oldViewportOrg; - - SetWindowExtEx(hdcDraw, - presData.dwObjectExtentX, - presData.dwObjectExtentY, - &oldWindowExt); - - SetViewportExtEx(hdcDraw, - lprcBounds->right - lprcBounds->left, - lprcBounds->bottom - lprcBounds->top, - &oldViewportExt); - - SetViewportOrgEx(hdcDraw, - lprcBounds->left, - lprcBounds->top, - &oldViewportOrg); - - PlayMetaFile(hdcDraw, presMetafile); - - SetWindowExtEx(hdcDraw, - oldWindowExt.cx, - oldWindowExt.cy, - NULL); - - SetViewportExtEx(hdcDraw, - oldViewportExt.cx, - oldViewportExt.cy, - NULL); - - SetViewportOrgEx(hdcDraw, - oldViewportOrg.x, - oldViewportOrg.y, - NULL); - - SetMapMode(hdcDraw, prevMapMode); - - DeleteMetaFile(presMetafile); - } - - return S_OK; -} - -static HRESULT WINAPI DataCache_GetColorSet( - IViewObject2* iface, - DWORD dwDrawAspect, - LONG lindex, - void* pvAspect, - DVTARGETDEVICE* ptd, - HDC hicTargetDevice, - LOGPALETTE** ppColorSet) -{ - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI DataCache_Freeze( - IViewObject2* iface, - DWORD dwDrawAspect, - LONG lindex, - void* pvAspect, - DWORD* pdwFreeze) -{ - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI DataCache_Unfreeze( - IViewObject2* iface, - DWORD dwFreeze) -{ - FIXME("stub\n"); - return E_NOTIMPL; -} - -/************************************************************************ - * DataCache_SetAdvise (IViewObject2) - * - * This sets-up an advisory sink with the data cache. When the object's - * view changes, this sink is called. - * - * See Windows documentation for more details on IViewObject2 methods. - */ -static HRESULT WINAPI DataCache_SetAdvise( - IViewObject2* iface, - DWORD aspects, - DWORD advf, - IAdviseSink* pAdvSink) -{ - _ICOM_THIS_From_IViewObject2(DataCache, iface); - - TRACE("(%p, %lx, %lx, %p)\n", iface, aspects, advf, pAdvSink); - - /* - * A call to this function removes the previous sink - */ - if (this->sinkInterface != NULL) - { - IAdviseSink_Release(this->sinkInterface); - this->sinkInterface = NULL; - this->sinkAspects = 0; - this->sinkAdviseFlag = 0; - } - - /* - * Now, setup the new one. - */ - if (pAdvSink!=NULL) - { - this->sinkInterface = pAdvSink; - this->sinkAspects = aspects; - this->sinkAdviseFlag = advf; - - IAdviseSink_AddRef(this->sinkInterface); - } - - /* - * When the ADVF_PRIMEFIRST flag is set, we have to advise the - * sink immediately. - */ - if (advf & ADVF_PRIMEFIRST) - { - DataCache_FireOnViewChange(this, - DVASPECT_CONTENT, - -1); - } - - return S_OK; -} - -/************************************************************************ - * DataCache_GetAdvise (IViewObject2) - * - * This method queries the current state of the advise sink - * installed on the data cache. - * - * See Windows documentation for more details on IViewObject2 methods. - */ -static HRESULT WINAPI DataCache_GetAdvise( - IViewObject2* iface, - DWORD* pAspects, - DWORD* pAdvf, - IAdviseSink** ppAdvSink) -{ - _ICOM_THIS_From_IViewObject2(DataCache, iface); - - TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink); - - /* - * Just copy all the requested values. - */ - if (pAspects!=NULL) - *pAspects = this->sinkAspects; - - if (pAdvf!=NULL) - *pAdvf = this->sinkAdviseFlag; - - if (ppAdvSink!=NULL) - { - IAdviseSink_QueryInterface(this->sinkInterface, - &IID_IAdviseSink, - (void**)ppAdvSink); - } - - return S_OK; -} - -/************************************************************************ - * DataCache_GetExtent (IViewObject2) - * - * This method retrieves the "natural" size of this cached object. - * - * See Windows documentation for more details on IViewObject2 methods. - */ -static HRESULT WINAPI DataCache_GetExtent( - IViewObject2* iface, - DWORD dwDrawAspect, - LONG lindex, - DVTARGETDEVICE* ptd, - LPSIZEL lpsizel) -{ - PresentationDataHeader presData; - HRESULT hres = E_FAIL; - - _ICOM_THIS_From_IViewObject2(DataCache, iface); - - TRACE("(%p, %lx, %ld, %p, %p)\n", - iface, dwDrawAspect, lindex, ptd, lpsizel); - - /* - * Sanity check - */ - if (lpsizel==NULL) - return E_POINTER; - - /* - * Initialize the out parameter. - */ - lpsizel->cx = 0; - lpsizel->cy = 0; - - /* - * This flag should be set to -1. - */ - if (lindex!=-1) - FIXME("Unimplemented flag lindex = %ld\n", lindex); - - /* - * Right now, we support only the callback from - * the default handler. - */ - if (ptd!=NULL) - FIXME("Unimplemented ptd = %p\n", ptd); - - /* - * Get the presentation information from the - * cache. - */ - hres = DataCache_ReadPresentationData(this, - dwDrawAspect, - &presData); - - if (SUCCEEDED(hres)) - { - lpsizel->cx = presData.dwObjectExtentX; - lpsizel->cy = presData.dwObjectExtentY; - } - - /* - * This method returns OLE_E_BLANK when it fails. - */ - if (FAILED(hres)) - hres = OLE_E_BLANK; - - return hres; -} - - -/********************************************************* - * Method implementation for the IOleCache2 - * part of the DataCache class. - */ - -/************************************************************************ - * DataCache_IOleCache2_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static HRESULT WINAPI DataCache_IOleCache2_QueryInterface( - IOleCache2* iface, - REFIID riid, - void** ppvObject) -{ - _ICOM_THIS_From_IOleCache2(DataCache, iface); - - return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject); -} - -/************************************************************************ - * DataCache_IOleCache2_AddRef (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI DataCache_IOleCache2_AddRef( - IOleCache2* iface) -{ - _ICOM_THIS_From_IOleCache2(DataCache, iface); - - return IUnknown_AddRef(this->outerUnknown); -} - -/************************************************************************ - * DataCache_IOleCache2_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI DataCache_IOleCache2_Release( - IOleCache2* iface) -{ - _ICOM_THIS_From_IOleCache2(DataCache, iface); - - return IUnknown_Release(this->outerUnknown); -} - -static HRESULT WINAPI DataCache_Cache( - IOleCache2* iface, - FORMATETC* pformatetc, - DWORD advf, - DWORD* pdwConnection) -{ - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI DataCache_Uncache( - IOleCache2* iface, - DWORD dwConnection) -{ - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI DataCache_EnumCache( - IOleCache2* iface, - IEnumSTATDATA** ppenumSTATDATA) -{ - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI DataCache_InitCache( - IOleCache2* iface, - IDataObject* pDataObject) -{ - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI DataCache_IOleCache2_SetData( - IOleCache2* iface, - FORMATETC* pformatetc, - STGMEDIUM* pmedium, - BOOL fRelease) -{ - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI DataCache_UpdateCache( - IOleCache2* iface, - LPDATAOBJECT pDataObject, - DWORD grfUpdf, - LPVOID pReserved) -{ - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI DataCache_DiscardCache( - IOleCache2* iface, - DWORD dwDiscardOptions) -{ - FIXME("stub\n"); - return E_NOTIMPL; -} - - -/********************************************************* - * Method implementation for the IOleCacheControl - * part of the DataCache class. - */ - -/************************************************************************ - * DataCache_IOleCacheControl_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface( - IOleCacheControl* iface, - REFIID riid, - void** ppvObject) -{ - _ICOM_THIS_From_IOleCacheControl(DataCache, iface); - - return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject); -} - -/************************************************************************ - * DataCache_IOleCacheControl_AddRef (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI DataCache_IOleCacheControl_AddRef( - IOleCacheControl* iface) -{ - _ICOM_THIS_From_IOleCacheControl(DataCache, iface); - - return IUnknown_AddRef(this->outerUnknown); -} - -/************************************************************************ - * DataCache_IOleCacheControl_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI DataCache_IOleCacheControl_Release( - IOleCacheControl* iface) -{ - _ICOM_THIS_From_IOleCacheControl(DataCache, iface); - - return IUnknown_Release(this->outerUnknown); -} - -static HRESULT WINAPI DataCache_OnRun( - IOleCacheControl* iface, - LPDATAOBJECT pDataObject) -{ - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI DataCache_OnStop( - IOleCacheControl* iface) -{ - FIXME("stub\n"); - return E_NOTIMPL; -} - -/* - * Virtual function tables for the DataCache class. - */ -static IUnknownVtbl DataCache_NDIUnknown_VTable = -{ - DataCache_NDIUnknown_QueryInterface, - DataCache_NDIUnknown_AddRef, - DataCache_NDIUnknown_Release -}; - -static IDataObjectVtbl DataCache_IDataObject_VTable = -{ - DataCache_IDataObject_QueryInterface, - DataCache_IDataObject_AddRef, - DataCache_IDataObject_Release, - DataCache_GetData, - DataCache_GetDataHere, - DataCache_QueryGetData, - DataCache_GetCanonicalFormatEtc, - DataCache_IDataObject_SetData, - DataCache_EnumFormatEtc, - DataCache_DAdvise, - DataCache_DUnadvise, - DataCache_EnumDAdvise -}; - -static IPersistStorageVtbl DataCache_IPersistStorage_VTable = -{ - DataCache_IPersistStorage_QueryInterface, - DataCache_IPersistStorage_AddRef, - DataCache_IPersistStorage_Release, - DataCache_GetClassID, - DataCache_IsDirty, - DataCache_InitNew, - DataCache_Load, - DataCache_Save, - DataCache_SaveCompleted, - DataCache_HandsOffStorage -}; - -static IViewObject2Vtbl DataCache_IViewObject2_VTable = -{ - DataCache_IViewObject2_QueryInterface, - DataCache_IViewObject2_AddRef, - DataCache_IViewObject2_Release, - DataCache_Draw, - DataCache_GetColorSet, - DataCache_Freeze, - DataCache_Unfreeze, - DataCache_SetAdvise, - DataCache_GetAdvise, - DataCache_GetExtent -}; - -static IOleCache2Vtbl DataCache_IOleCache2_VTable = -{ - DataCache_IOleCache2_QueryInterface, - DataCache_IOleCache2_AddRef, - DataCache_IOleCache2_Release, - DataCache_Cache, - DataCache_Uncache, - DataCache_EnumCache, - DataCache_InitCache, - DataCache_IOleCache2_SetData, - DataCache_UpdateCache, - DataCache_DiscardCache -}; - -static IOleCacheControlVtbl DataCache_IOleCacheControl_VTable = -{ - DataCache_IOleCacheControl_QueryInterface, - DataCache_IOleCacheControl_AddRef, - DataCache_IOleCacheControl_Release, - DataCache_OnRun, - DataCache_OnStop -}; - -/****************************************************************************** - * CreateDataCache [OLE32.@] - */ -HRESULT WINAPI CreateDataCache( - LPUNKNOWN pUnkOuter, - REFCLSID rclsid, - REFIID riid, - LPVOID* ppvObj) -{ - DataCache* newCache = NULL; - HRESULT hr = S_OK; - - TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj); - - /* - * Sanity check - */ - if (ppvObj==0) - return E_POINTER; - - *ppvObj = 0; - - /* - * If this cache is constructed for aggregation, make sure - * the caller is requesting the IUnknown interface. - * This is necessary because it's the only time the non-delegating - * IUnknown pointer can be returned to the outside. - */ - if ( (pUnkOuter!=NULL) && - (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) != 0) ) - return CLASS_E_NOAGGREGATION; - - /* - * Try to construct a new instance of the class. - */ - newCache = DataCache_Construct(rclsid, - pUnkOuter); - - if (newCache == 0) - return E_OUTOFMEMORY; - - /* - * Make sure it supports the interface required by the caller. - */ - hr = IUnknown_QueryInterface((IUnknown*)&(newCache->lpvtbl2), riid, ppvObj); - - /* - * Release the reference obtained in the constructor. If - * the QueryInterface was unsuccessful, it will free the class. - */ - IUnknown_Release((IUnknown*)&(newCache->lpvtbl2)); - - return hr; -} - -/********************************************************* - * Method implementation for DataCache class. - */ -static DataCache* DataCache_Construct( - REFCLSID clsid, - LPUNKNOWN pUnkOuter) -{ - DataCache* newObject = 0; - - /* - * Allocate space for the object. - */ - newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache)); - - if (newObject==0) - return newObject; - - /* - * Initialize the virtual function table. - */ - newObject->lpvtbl1 = &DataCache_IDataObject_VTable; - newObject->lpvtbl2 = &DataCache_NDIUnknown_VTable; - newObject->lpvtbl3 = &DataCache_IPersistStorage_VTable; - newObject->lpvtbl4 = &DataCache_IViewObject2_VTable; - newObject->lpvtbl5 = &DataCache_IOleCache2_VTable; - newObject->lpvtbl6 = &DataCache_IOleCacheControl_VTable; - - /* - * Start with one reference count. The caller of this function - * must release the interface pointer when it is done. - */ - newObject->ref = 1; - - /* - * Initialize the outer unknown - * We don't keep a reference on the outer unknown since, the way - * aggregation works, our lifetime is at least as large as it's - * lifetime. - */ - if (pUnkOuter==NULL) - pUnkOuter = (IUnknown*)&(newObject->lpvtbl2); - - newObject->outerUnknown = pUnkOuter; - - /* - * Initialize the other members of the structure. - */ - newObject->presentationStorage = NULL; - newObject->sinkAspects = 0; - newObject->sinkAdviseFlag = 0; - newObject->sinkInterface = 0; - - return newObject; -} +/* + * OLE 2 Data cache + * + * Copyright 1999 Francis Beaudet + * Copyright 2000 Abey George + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES: + * The OLE2 data cache supports a whole whack of + * interfaces including: + * IDataObject, IPersistStorage, IViewObject2, + * IOleCache2 and IOleCacheControl. + * + * Most of the implementation details are taken from: Inside OLE + * second edition by Kraig Brockschmidt, + * + * NOTES + * - This implementation of the datacache will let your application + * load documents that have embedded OLE objects in them and it will + * also retrieve the metafile representation of those objects. + * - This implementation of the datacache will also allow your + * application to save new documents with OLE objects in them. + * - The main thing that it doesn't do is allow you to activate + * or modify the OLE objects in any way. + * - I haven't found any good documentation on the real usage of + * the streams created by the data cache. In particular, How to + * determine what the XXX stands for in the stream name + * "\002OlePresXXX". It appears to just be a counter. + * - Also, I don't know the real content of the presentation stream + * header. I was able to figure-out where the extent of the object + * was stored and the aspect, but that's about it. + */ +#include <assert.h> +#include <stdarg.h> +#include <string.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winerror.h" +#include "wine/unicode.h" +#include "ole2.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/**************************************************************************** + * PresentationDataHeader + * + * This structure represents the header of the \002OlePresXXX stream in + * the OLE object strorage. + * + * Most fields are still unknown. + */ +typedef struct PresentationDataHeader +{ + DWORD unknown1; /* -1 */ + DWORD unknown2; /* 3, possibly CF_METAFILEPICT */ + DWORD unknown3; /* 4, possibly TYMED_ISTREAM */ + DVASPECT dvAspect; + DWORD unknown5; /* -1 */ + + DWORD unknown6; + DWORD unknown7; /* 0 */ + DWORD dwObjectExtentX; + DWORD dwObjectExtentY; + DWORD dwSize; +} PresentationDataHeader; + +/**************************************************************************** + * DataCache + */ +struct DataCache +{ + /* + * List all interface VTables here + */ + IDataObjectVtbl* lpvtbl1; + IUnknownVtbl* lpvtbl2; + IPersistStorageVtbl* lpvtbl3; + IViewObject2Vtbl* lpvtbl4; + IOleCache2Vtbl* lpvtbl5; + IOleCacheControlVtbl* lpvtbl6; + + /* + * Reference count of this object + */ + ULONG ref; + + /* + * IUnknown implementation of the outer object. + */ + IUnknown* outerUnknown; + + /* + * This storage pointer is set through a call to + * IPersistStorage_Load. This is where the visual + * representation of the object is stored. + */ + IStorage* presentationStorage; + + /* + * The user of this object can setup ONE advise sink + * connection with the object. These parameters describe + * that connection. + */ + DWORD sinkAspects; + DWORD sinkAdviseFlag; + IAdviseSink* sinkInterface; + +}; + +typedef struct DataCache DataCache; + +/* + * Here, I define utility macros to help with the casting of the + * "this" parameter. + * There is a version to accommodate all of the VTables implemented + * by this object. + */ +#define _ICOM_THIS_From_IDataObject(class,name) class* this = (class*)name +#define _ICOM_THIS_From_NDIUnknown(class, name) class* this = (class*)(((char*)name)-sizeof(void*)) +#define _ICOM_THIS_From_IPersistStorage(class, name) class* this = (class*)(((char*)name)-2*sizeof(void*)) +#define _ICOM_THIS_From_IViewObject2(class, name) class* this = (class*)(((char*)name)-3*sizeof(void*)) +#define _ICOM_THIS_From_IOleCache2(class, name) class* this = (class*)(((char*)name)-4*sizeof(void*)) +#define _ICOM_THIS_From_IOleCacheControl(class, name) class* this = (class*)(((char*)name)-5*sizeof(void*)) + +/* + * Prototypes for the methods of the DataCache class. + */ +static DataCache* DataCache_Construct(REFCLSID clsid, + LPUNKNOWN pUnkOuter); +static HRESULT DataCache_OpenPresStream(DataCache *this, + DWORD drawAspect, + IStream **pStm); + +static void DataCache_Destroy( + DataCache* ptrToDestroy) +{ + TRACE("()\n"); + + if (ptrToDestroy->sinkInterface != NULL) + { + IAdviseSink_Release(ptrToDestroy->sinkInterface); + ptrToDestroy->sinkInterface = NULL; + } + + if (ptrToDestroy->presentationStorage != NULL) + { + IStorage_Release(ptrToDestroy->presentationStorage); + ptrToDestroy->presentationStorage = NULL; + } + + /* + * Free the datacache pointer. + */ + HeapFree(GetProcessHeap(), 0, ptrToDestroy); +} + +/************************************************************************ + * DataCache_ReadPresentationData + * + * This method will read information for the requested presentation + * into the given structure. + * + * Param: + * this - Pointer to the DataCache object + * drawAspect - The aspect of the object that we wish to draw. + * header - The structure containing information about this + * aspect of the object. + */ +static HRESULT DataCache_ReadPresentationData( + DataCache* this, + DWORD drawAspect, + PresentationDataHeader* header) +{ + IStream* presStream = NULL; + HRESULT hres; + + /* + * Open the presentation stream. + */ + hres = DataCache_OpenPresStream( + this, + drawAspect, + &presStream); + + if (FAILED(hres)) + return hres; + + /* + * Read the header. + */ + + hres = IStream_Read( + presStream, + header, + sizeof(PresentationDataHeader), + NULL); + + /* + * Cleanup. + */ + IStream_Release(presStream); + + /* + * We don't want to propagate any other error + * code than a failure. + */ + if (hres!=S_OK) + hres = E_FAIL; + + return hres; +} + +/************************************************************************ + * DataCache_FireOnViewChange + * + * This method will fire an OnViewChange notification to the advise + * sink registered with the datacache. + * + * See IAdviseSink::OnViewChange for more details. + */ +static void DataCache_FireOnViewChange( + DataCache* this, + DWORD aspect, + LONG lindex) +{ + TRACE("(%p, %lx, %ld)\n", this, aspect, lindex); + + /* + * The sink supplies a filter when it registers + * we make sure we only send the notifications when that + * filter matches. + */ + if ((this->sinkAspects & aspect) != 0) + { + if (this->sinkInterface != NULL) + { + IAdviseSink_OnViewChange(this->sinkInterface, + aspect, + lindex); + + /* + * Some sinks want to be unregistered automatically when + * the first notification goes out. + */ + if ( (this->sinkAdviseFlag & ADVF_ONLYONCE) != 0) + { + IAdviseSink_Release(this->sinkInterface); + + this->sinkInterface = NULL; + this->sinkAspects = 0; + this->sinkAdviseFlag = 0; + } + } + } +} + +/* Helper for DataCache_OpenPresStream */ +static BOOL DataCache_IsPresentationStream(const STATSTG *elem) +{ + /* The presentation streams have names of the form "\002OlePresXXX", + * where XXX goes from 000 to 999. */ + static const WCHAR OlePres[] = { 2,'O','l','e','P','r','e','s' }; + + LPCWSTR name = elem->pwcsName; + + return (elem->type == STGTY_STREAM) + && (elem->cbSize.u.LowPart >= sizeof(PresentationDataHeader)) + && (strlenW(name) == 11) + && (strncmpW(name, OlePres, 8) == 0) + && (name[8] >= '0') && (name[8] <= '9') + && (name[9] >= '0') && (name[9] <= '9') + && (name[10] >= '0') && (name[10] <= '9'); +} + +/************************************************************************ + * DataCache_OpenPresStream + * + * This method will find the stream for the given presentation. It makes + * no attempt at fallback. + * + * Param: + * this - Pointer to the DataCache object + * drawAspect - The aspect of the object that we wish to draw. + * pStm - A returned stream. It points to the beginning of the + * - presentation data, including the header. + * + * Errors: + * S_OK The requested stream has been opened. + * OLE_E_BLANK The requested stream could not be found. + * Quite a few others I'm too lazy to map correctly. + * + * Notes: + * Algorithm: Scan the elements of the presentation storage, looking + * for presentation streams. For each presentation stream, + * load the header and check to see if the aspect maches. + * + * If a fallback is desired, just opening the first presentation stream + * is a possibility. + */ +static HRESULT DataCache_OpenPresStream( + DataCache *this, + DWORD drawAspect, + IStream **ppStm) +{ + STATSTG elem; + IEnumSTATSTG *pEnum; + HRESULT hr; + + if (!ppStm) return E_POINTER; + + hr = IStorage_EnumElements(this->presentationStorage, 0, NULL, 0, &pEnum); + if (FAILED(hr)) return hr; + + while ((hr = IEnumSTATSTG_Next(pEnum, 1, &elem, NULL)) == S_OK) + { + if (DataCache_IsPresentationStream(&elem)) + { + IStream *pStm; + + hr = IStorage_OpenStream(this->presentationStorage, elem.pwcsName, + NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, + &pStm); + if (SUCCEEDED(hr)) + { + PresentationDataHeader header; + ULONG actual_read; + + hr = IStream_Read(pStm, &header, sizeof(header), &actual_read); + + /* can't use SUCCEEDED(hr): S_FALSE counts as an error */ + if (hr == S_OK && actual_read == sizeof(header) + && header.dvAspect == drawAspect) + { + /* Rewind the stream before returning it. */ + LARGE_INTEGER offset; + offset.u.LowPart = 0; + offset.u.HighPart = 0; + IStream_Seek(pStm, offset, STREAM_SEEK_SET, NULL); + + *ppStm = pStm; + + CoTaskMemFree(elem.pwcsName); + IEnumSTATSTG_Release(pEnum); + + return S_OK; + } + + IStream_Release(pStm); + } + } + + CoTaskMemFree(elem.pwcsName); + } + + IEnumSTATSTG_Release(pEnum); + + return (hr == S_FALSE ? OLE_E_BLANK : hr); +} + +/************************************************************************ + * DataCache_ReadPresentationData + * + * This method will read information for the requested presentation + * into the given structure. + * + * Param: + * this - Pointer to the DataCache object + * drawAspect - The aspect of the object that we wish to draw. + * + * Returns: + * This method returns a metafile handle if it is successful. + * it will return 0 if not. + */ +static HMETAFILE DataCache_ReadPresMetafile( + DataCache* this, + DWORD drawAspect) +{ + LARGE_INTEGER offset; + IStream* presStream = NULL; + HRESULT hres; + void* metafileBits; + STATSTG streamInfo; + HMETAFILE newMetafile = 0; + + /* + * Open the presentation stream. + */ + hres = DataCache_OpenPresStream( + this, + drawAspect, + &presStream); + + if (FAILED(hres)) + return (HMETAFILE)hres; + + /* + * Get the size of the stream. + */ + hres = IStream_Stat(presStream, + &streamInfo, + STATFLAG_NONAME); + + /* + * Skip the header + */ + offset.u.HighPart = 0; + offset.u.LowPart = sizeof(PresentationDataHeader); + + hres = IStream_Seek( + presStream, + offset, + STREAM_SEEK_SET, + NULL); + + streamInfo.cbSize.u.LowPart -= offset.u.LowPart; + + /* + * Allocate a buffer for the metafile bits. + */ + metafileBits = HeapAlloc(GetProcessHeap(), + 0, + streamInfo.cbSize.u.LowPart); + + /* + * Read the metafile bits. + */ + hres = IStream_Read( + presStream, + metafileBits, + streamInfo.cbSize.u.LowPart, + NULL); + + /* + * Create a metafile with those bits. + */ + if (SUCCEEDED(hres)) + { + newMetafile = SetMetaFileBitsEx(streamInfo.cbSize.u.LowPart, metafileBits); + } + + /* + * Cleanup. + */ + HeapFree(GetProcessHeap(), 0, metafileBits); + IStream_Release(presStream); + + if (newMetafile==0) + hres = E_FAIL; + + return newMetafile; +} + +/********************************************************* + * Method implementation for the non delegating IUnknown + * part of the DataCache class. + */ + +/************************************************************************ + * DataCache_NDIUnknown_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + * + * This version of QueryInterface will not delegate it's implementation + * to the outer unknown. + */ +static HRESULT WINAPI DataCache_NDIUnknown_QueryInterface( + IUnknown* iface, + REFIID riid, + void** ppvObject) +{ + _ICOM_THIS_From_NDIUnknown(DataCache, iface); + + /* + * Perform a sanity check on the parameters. + */ + if ( (this==0) || (ppvObject==0) ) + return E_INVALIDARG; + + /* + * Initialize the return parameter. + */ + *ppvObject = 0; + + /* + * Compare the riid with the interface IDs implemented by this object. + */ + if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) + { + *ppvObject = iface; + } + else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0) + { + *ppvObject = (IDataObject*)&(this->lpvtbl1); + } + else if ( (memcmp(&IID_IPersistStorage, riid, sizeof(IID_IPersistStorage)) == 0) || + (memcmp(&IID_IPersist, riid, sizeof(IID_IPersist)) == 0) ) + { + *ppvObject = (IPersistStorage*)&(this->lpvtbl3); + } + else if ( (memcmp(&IID_IViewObject, riid, sizeof(IID_IViewObject)) == 0) || + (memcmp(&IID_IViewObject2, riid, sizeof(IID_IViewObject2)) == 0) ) + { + *ppvObject = (IViewObject2*)&(this->lpvtbl4); + } + else if ( (memcmp(&IID_IOleCache, riid, sizeof(IID_IOleCache)) == 0) || + (memcmp(&IID_IOleCache2, riid, sizeof(IID_IOleCache2)) == 0) ) + { + *ppvObject = (IOleCache2*)&(this->lpvtbl5); + } + else if (memcmp(&IID_IOleCacheControl, riid, sizeof(IID_IOleCacheControl)) == 0) + { + *ppvObject = (IOleCacheControl*)&(this->lpvtbl6); + } + + /* + * Check that we obtained an interface. + */ + if ((*ppvObject)==0) + { + WARN( "() : asking for unsupported interface %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; + } + + /* + * Query Interface always increases the reference count by one when it is + * successful. + */ + IUnknown_AddRef((IUnknown*)*ppvObject); + + return S_OK; +} + +/************************************************************************ + * DataCache_NDIUnknown_AddRef (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + * + * This version of QueryInterface will not delegate it's implementation + * to the outer unknown. + */ +static ULONG WINAPI DataCache_NDIUnknown_AddRef( + IUnknown* iface) +{ + _ICOM_THIS_From_NDIUnknown(DataCache, iface); + return InterlockedIncrement(&this->ref); +} + +/************************************************************************ + * DataCache_NDIUnknown_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + * + * This version of QueryInterface will not delegate it's implementation + * to the outer unknown. + */ +static ULONG WINAPI DataCache_NDIUnknown_Release( + IUnknown* iface) +{ + _ICOM_THIS_From_NDIUnknown(DataCache, iface); + ULONG ref; + + /* + * Decrease the reference count on this object. + */ + ref = InterlockedDecrement(&this->ref); + + /* + * If the reference count goes down to 0, perform suicide. + */ + if (ref == 0) DataCache_Destroy(this); + + return ref; +} + +/********************************************************* + * Method implementation for the IDataObject + * part of the DataCache class. + */ + +/************************************************************************ + * DataCache_IDataObject_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static HRESULT WINAPI DataCache_IDataObject_QueryInterface( + IDataObject* iface, + REFIID riid, + void** ppvObject) +{ + _ICOM_THIS_From_IDataObject(DataCache, iface); + + return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject); +} + +/************************************************************************ + * DataCache_IDataObject_AddRef (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI DataCache_IDataObject_AddRef( + IDataObject* iface) +{ + _ICOM_THIS_From_IDataObject(DataCache, iface); + + return IUnknown_AddRef(this->outerUnknown); +} + +/************************************************************************ + * DataCache_IDataObject_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI DataCache_IDataObject_Release( + IDataObject* iface) +{ + _ICOM_THIS_From_IDataObject(DataCache, iface); + + return IUnknown_Release(this->outerUnknown); +} + +/************************************************************************ + * DataCache_GetData + * + * Get Data from a source dataobject using format pformatetcIn->cfFormat + * See Windows documentation for more details on GetData. + * TODO: Currently only CF_METAFILEPICT is implemented + */ +static HRESULT WINAPI DataCache_GetData( + IDataObject* iface, + LPFORMATETC pformatetcIn, + STGMEDIUM* pmedium) +{ + HRESULT hr = 0; + HRESULT hrRet = E_UNEXPECTED; + IPersistStorage *pPersistStorage = 0; + IStorage *pStorage = 0; + IStream *pStream = 0; + OLECHAR name[]={ 2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0}; + HGLOBAL hGlobalMF = 0; + void *mfBits = 0; + PresentationDataHeader pdh; + METAFILEPICT *mfPict; + HMETAFILE hMetaFile = 0; + + if (pformatetcIn->cfFormat == CF_METAFILEPICT) + { + /* Get the Persist Storage */ + + hr = IDataObject_QueryInterface(iface, &IID_IPersistStorage, (void**)&pPersistStorage); + + if (hr != S_OK) + goto cleanup; + + /* Create a doc file to copy the doc to a storage */ + + hr = StgCreateDocfile(NULL, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pStorage); + + if (hr != S_OK) + goto cleanup; + + /* Save it to storage */ + + hr = OleSave(pPersistStorage, pStorage, FALSE); + + if (hr != S_OK) + goto cleanup; + + /* Open the Presentation data srteam */ + + hr = IStorage_OpenStream(pStorage, name, 0, STGM_CREATE|STGM_SHARE_EXCLUSIVE|STGM_READWRITE, 0, &pStream); + + if (hr != S_OK) + goto cleanup; + + /* Read the presentation header */ + + hr = IStream_Read(pStream, &pdh, sizeof(PresentationDataHeader), NULL); + + if (hr != S_OK) + goto cleanup; + + mfBits = HeapAlloc(GetProcessHeap(), 0, pdh.dwSize); + + /* Read the Metafile bits */ + + hr = IStream_Read(pStream, mfBits, pdh.dwSize, NULL); + + if (hr != S_OK) + goto cleanup; + + /* Create the metafile and place it in the STGMEDIUM structure */ + + hMetaFile = SetMetaFileBitsEx(pdh.dwSize, mfBits); + + hGlobalMF = GlobalAlloc(GMEM_SHARE|GMEM_MOVEABLE, sizeof(METAFILEPICT)); + mfPict = (METAFILEPICT *)GlobalLock(hGlobalMF); + mfPict->hMF = hMetaFile; + + GlobalUnlock(hGlobalMF); + + pmedium->u.hGlobal = hGlobalMF; + pmedium->tymed = TYMED_MFPICT; + hrRet = S_OK; + +cleanup: + + HeapFree(GetProcessHeap(), 0, mfBits); + + if (pStream) + IStream_Release(pStream); + + if (pStorage) + IStorage_Release(pStorage); + + if (pPersistStorage) + IPersistStorage_Release(pPersistStorage); + + return hrRet; + } + + /* TODO: Other formats are not implemented */ + + return E_NOTIMPL; +} + +static HRESULT WINAPI DataCache_GetDataHere( + IDataObject* iface, + LPFORMATETC pformatetc, + STGMEDIUM* pmedium) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DataCache_QueryGetData( + IDataObject* iface, + LPFORMATETC pformatetc) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + +/************************************************************************ + * DataCache_EnumFormatEtc (IDataObject) + * + * The data cache doesn't implement this method. + * + * See Windows documentation for more details on IDataObject methods. + */ +static HRESULT WINAPI DataCache_GetCanonicalFormatEtc( + IDataObject* iface, + LPFORMATETC pformatectIn, + LPFORMATETC pformatetcOut) +{ + TRACE("()\n"); + return E_NOTIMPL; +} + +/************************************************************************ + * DataCache_IDataObject_SetData (IDataObject) + * + * This method is delegated to the IOleCache2 implementation. + * + * See Windows documentation for more details on IDataObject methods. + */ +static HRESULT WINAPI DataCache_IDataObject_SetData( + IDataObject* iface, + LPFORMATETC pformatetc, + STGMEDIUM* pmedium, + BOOL fRelease) +{ + IOleCache2* oleCache = NULL; + HRESULT hres; + + TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease); + + hres = IDataObject_QueryInterface(iface, &IID_IOleCache2, (void**)&oleCache); + + if (FAILED(hres)) + return E_UNEXPECTED; + + hres = IOleCache2_SetData(oleCache, pformatetc, pmedium, fRelease); + + IOleCache2_Release(oleCache); + + return hres; +} + +/************************************************************************ + * DataCache_EnumFormatEtc (IDataObject) + * + * The data cache doesn't implement this method. + * + * See Windows documentation for more details on IDataObject methods. + */ +static HRESULT WINAPI DataCache_EnumFormatEtc( + IDataObject* iface, + DWORD dwDirection, + IEnumFORMATETC** ppenumFormatEtc) +{ + TRACE("()\n"); + return E_NOTIMPL; +} + +/************************************************************************ + * DataCache_DAdvise (IDataObject) + * + * The data cache doesn't support connections. + * + * See Windows documentation for more details on IDataObject methods. + */ +static HRESULT WINAPI DataCache_DAdvise( + IDataObject* iface, + FORMATETC* pformatetc, + DWORD advf, + IAdviseSink* pAdvSink, + DWORD* pdwConnection) +{ + TRACE("()\n"); + return OLE_E_ADVISENOTSUPPORTED; +} + +/************************************************************************ + * DataCache_DUnadvise (IDataObject) + * + * The data cache doesn't support connections. + * + * See Windows documentation for more details on IDataObject methods. + */ +static HRESULT WINAPI DataCache_DUnadvise( + IDataObject* iface, + DWORD dwConnection) +{ + TRACE("()\n"); + return OLE_E_NOCONNECTION; +} + +/************************************************************************ + * DataCache_EnumDAdvise (IDataObject) + * + * The data cache doesn't support connections. + * + * See Windows documentation for more details on IDataObject methods. + */ +static HRESULT WINAPI DataCache_EnumDAdvise( + IDataObject* iface, + IEnumSTATDATA** ppenumAdvise) +{ + TRACE("()\n"); + return OLE_E_ADVISENOTSUPPORTED; +} + +/********************************************************* + * Method implementation for the IDataObject + * part of the DataCache class. + */ + +/************************************************************************ + * DataCache_IPersistStorage_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static HRESULT WINAPI DataCache_IPersistStorage_QueryInterface( + IPersistStorage* iface, + REFIID riid, + void** ppvObject) +{ + _ICOM_THIS_From_IPersistStorage(DataCache, iface); + + return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject); +} + +/************************************************************************ + * DataCache_IPersistStorage_AddRef (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI DataCache_IPersistStorage_AddRef( + IPersistStorage* iface) +{ + _ICOM_THIS_From_IPersistStorage(DataCache, iface); + + return IUnknown_AddRef(this->outerUnknown); +} + +/************************************************************************ + * DataCache_IPersistStorage_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI DataCache_IPersistStorage_Release( + IPersistStorage* iface) +{ + _ICOM_THIS_From_IPersistStorage(DataCache, iface); + + return IUnknown_Release(this->outerUnknown); +} + +/************************************************************************ + * DataCache_GetClassID (IPersistStorage) + * + * The data cache doesn't implement this method. + * + * See Windows documentation for more details on IPersistStorage methods. + */ +static HRESULT WINAPI DataCache_GetClassID( + IPersistStorage* iface, + CLSID* pClassID) +{ + TRACE("(%p, %p)\n", iface, pClassID); + return E_NOTIMPL; +} + +/************************************************************************ + * DataCache_IsDirty (IPersistStorage) + * + * Until we actully connect to a running object and retrieve new + * information to it, we never get dirty. + * + * See Windows documentation for more details on IPersistStorage methods. + */ +static HRESULT WINAPI DataCache_IsDirty( + IPersistStorage* iface) +{ + TRACE("(%p)\n", iface); + + return S_FALSE; +} + +/************************************************************************ + * DataCache_InitNew (IPersistStorage) + * + * The data cache implementation of IPersistStorage_InitNew simply stores + * the storage pointer. + * + * See Windows documentation for more details on IPersistStorage methods. + */ +static HRESULT WINAPI DataCache_InitNew( + IPersistStorage* iface, + IStorage* pStg) +{ + TRACE("(%p, %p)\n", iface, pStg); + + return IPersistStorage_Load(iface, pStg); +} + +/************************************************************************ + * DataCache_Load (IPersistStorage) + * + * The data cache implementation of IPersistStorage_Load doesn't + * actually load anything. Instead, it holds on to the storage pointer + * and it will load the presentation information when the + * IDataObject_GetData or IViewObject2_Draw methods are called. + * + * See Windows documentation for more details on IPersistStorage methods. + */ +static HRESULT WINAPI DataCache_Load( + IPersistStorage* iface, + IStorage* pStg) +{ + _ICOM_THIS_From_IPersistStorage(DataCache, iface); + + TRACE("(%p, %p)\n", iface, pStg); + + if (this->presentationStorage != NULL) + { + IStorage_Release(this->presentationStorage); + } + + this->presentationStorage = pStg; + + if (this->presentationStorage != NULL) + { + IStorage_AddRef(this->presentationStorage); + } + return S_OK; +} + +/************************************************************************ + * DataCache_Save (IPersistStorage) + * + * Until we actully connect to a running object and retrieve new + * information to it, we never have to save anything. However, it is + * our responsability to copy the information when saving to a new + * storage. + * + * See Windows documentation for more details on IPersistStorage methods. + */ +static HRESULT WINAPI DataCache_Save( + IPersistStorage* iface, + IStorage* pStg, + BOOL fSameAsLoad) +{ + _ICOM_THIS_From_IPersistStorage(DataCache, iface); + + TRACE("(%p, %p, %d)\n", iface, pStg, fSameAsLoad); + + if ( (!fSameAsLoad) && + (this->presentationStorage!=NULL) ) + { + return IStorage_CopyTo(this->presentationStorage, + 0, + NULL, + NULL, + pStg); + } + + return S_OK; +} + +/************************************************************************ + * DataCache_SaveCompleted (IPersistStorage) + * + * This method is called to tell the cache to release the storage + * pointer it's currentlu holding. + * + * See Windows documentation for more details on IPersistStorage methods. + */ +static HRESULT WINAPI DataCache_SaveCompleted( + IPersistStorage* iface, + IStorage* pStgNew) +{ + TRACE("(%p, %p)\n", iface, pStgNew); + + if (pStgNew) + { + /* + * First, make sure we get our hands off any storage we have. + */ + + IPersistStorage_HandsOffStorage(iface); + + /* + * Then, attach to the new storage. + */ + + DataCache_Load(iface, pStgNew); + } + + return S_OK; +} + +/************************************************************************ + * DataCache_HandsOffStorage (IPersistStorage) + * + * This method is called to tell the cache to release the storage + * pointer it's currentlu holding. + * + * See Windows documentation for more details on IPersistStorage methods. + */ +static HRESULT WINAPI DataCache_HandsOffStorage( + IPersistStorage* iface) +{ + _ICOM_THIS_From_IPersistStorage(DataCache, iface); + + TRACE("(%p)\n", iface); + + if (this->presentationStorage != NULL) + { + IStorage_Release(this->presentationStorage); + this->presentationStorage = NULL; + } + + return S_OK; +} + +/********************************************************* + * Method implementation for the IViewObject2 + * part of the DataCache class. + */ + +/************************************************************************ + * DataCache_IViewObject2_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static HRESULT WINAPI DataCache_IViewObject2_QueryInterface( + IViewObject2* iface, + REFIID riid, + void** ppvObject) +{ + _ICOM_THIS_From_IViewObject2(DataCache, iface); + + return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject); +} + +/************************************************************************ + * DataCache_IViewObject2_AddRef (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI DataCache_IViewObject2_AddRef( + IViewObject2* iface) +{ + _ICOM_THIS_From_IViewObject2(DataCache, iface); + + return IUnknown_AddRef(this->outerUnknown); +} + +/************************************************************************ + * DataCache_IViewObject2_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI DataCache_IViewObject2_Release( + IViewObject2* iface) +{ + _ICOM_THIS_From_IViewObject2(DataCache, iface); + + return IUnknown_Release(this->outerUnknown); +} + +/************************************************************************ + * DataCache_Draw (IViewObject2) + * + * This method will draw the cached representation of the object + * to the given device context. + * + * See Windows documentation for more details on IViewObject2 methods. + */ +static HRESULT WINAPI DataCache_Draw( + IViewObject2* iface, + DWORD dwDrawAspect, + LONG lindex, + void* pvAspect, + DVTARGETDEVICE* ptd, + HDC hdcTargetDev, + HDC hdcDraw, + LPCRECTL lprcBounds, + LPCRECTL lprcWBounds, + BOOL (CALLBACK *pfnContinue)(ULONG_PTR dwContinue), + ULONG_PTR dwContinue) +{ + PresentationDataHeader presData; + HMETAFILE presMetafile = 0; + HRESULT hres; + + _ICOM_THIS_From_IViewObject2(DataCache, iface); + + TRACE("(%p, %lx, %ld, %p, %p, %p, %p, %p, %p, %lx)\n", + iface, + dwDrawAspect, + lindex, + pvAspect, + hdcTargetDev, + hdcDraw, + lprcBounds, + lprcWBounds, + pfnContinue, + dwContinue); + + /* + * Sanity check + */ + if (lprcBounds==NULL) + return E_INVALIDARG; + + /* + * First, we need to retrieve the dimensions of the + * image in the metafile. + */ + hres = DataCache_ReadPresentationData(this, + dwDrawAspect, + &presData); + + if (FAILED(hres)) + return hres; + + /* + * Then, we can extract the metafile itself from the cached + * data. + * + * FIXME Unless it isn't a metafile. I think it could be any CF_XXX type, + * particularly CF_DIB. + */ + presMetafile = DataCache_ReadPresMetafile(this, + dwDrawAspect); + + /* + * If we have a metafile, just draw baby... + * We have to be careful not to modify the state of the + * DC. + */ + if (presMetafile!=0) + { + INT prevMapMode = SetMapMode(hdcDraw, MM_ANISOTROPIC); + SIZE oldWindowExt; + SIZE oldViewportExt; + POINT oldViewportOrg; + + SetWindowExtEx(hdcDraw, + presData.dwObjectExtentX, + presData.dwObjectExtentY, + &oldWindowExt); + + SetViewportExtEx(hdcDraw, + lprcBounds->right - lprcBounds->left, + lprcBounds->bottom - lprcBounds->top, + &oldViewportExt); + + SetViewportOrgEx(hdcDraw, + lprcBounds->left, + lprcBounds->top, + &oldViewportOrg); + + PlayMetaFile(hdcDraw, presMetafile); + + SetWindowExtEx(hdcDraw, + oldWindowExt.cx, + oldWindowExt.cy, + NULL); + + SetViewportExtEx(hdcDraw, + oldViewportExt.cx, + oldViewportExt.cy, + NULL); + + SetViewportOrgEx(hdcDraw, + oldViewportOrg.x, + oldViewportOrg.y, + NULL); + + SetMapMode(hdcDraw, prevMapMode); + + DeleteMetaFile(presMetafile); + } + + return S_OK; +} + +static HRESULT WINAPI DataCache_GetColorSet( + IViewObject2* iface, + DWORD dwDrawAspect, + LONG lindex, + void* pvAspect, + DVTARGETDEVICE* ptd, + HDC hicTargetDevice, + LOGPALETTE** ppColorSet) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DataCache_Freeze( + IViewObject2* iface, + DWORD dwDrawAspect, + LONG lindex, + void* pvAspect, + DWORD* pdwFreeze) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DataCache_Unfreeze( + IViewObject2* iface, + DWORD dwFreeze) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + +/************************************************************************ + * DataCache_SetAdvise (IViewObject2) + * + * This sets-up an advisory sink with the data cache. When the object's + * view changes, this sink is called. + * + * See Windows documentation for more details on IViewObject2 methods. + */ +static HRESULT WINAPI DataCache_SetAdvise( + IViewObject2* iface, + DWORD aspects, + DWORD advf, + IAdviseSink* pAdvSink) +{ + _ICOM_THIS_From_IViewObject2(DataCache, iface); + + TRACE("(%p, %lx, %lx, %p)\n", iface, aspects, advf, pAdvSink); + + /* + * A call to this function removes the previous sink + */ + if (this->sinkInterface != NULL) + { + IAdviseSink_Release(this->sinkInterface); + this->sinkInterface = NULL; + this->sinkAspects = 0; + this->sinkAdviseFlag = 0; + } + + /* + * Now, setup the new one. + */ + if (pAdvSink!=NULL) + { + this->sinkInterface = pAdvSink; + this->sinkAspects = aspects; + this->sinkAdviseFlag = advf; + + IAdviseSink_AddRef(this->sinkInterface); + } + + /* + * When the ADVF_PRIMEFIRST flag is set, we have to advise the + * sink immediately. + */ + if (advf & ADVF_PRIMEFIRST) + { + DataCache_FireOnViewChange(this, + DVASPECT_CONTENT, + -1); + } + + return S_OK; +} + +/************************************************************************ + * DataCache_GetAdvise (IViewObject2) + * + * This method queries the current state of the advise sink + * installed on the data cache. + * + * See Windows documentation for more details on IViewObject2 methods. + */ +static HRESULT WINAPI DataCache_GetAdvise( + IViewObject2* iface, + DWORD* pAspects, + DWORD* pAdvf, + IAdviseSink** ppAdvSink) +{ + _ICOM_THIS_From_IViewObject2(DataCache, iface); + + TRACE("(%p, %p, %p, %p)\n", iface, pAspects, pAdvf, ppAdvSink); + + /* + * Just copy all the requested values. + */ + if (pAspects!=NULL) + *pAspects = this->sinkAspects; + + if (pAdvf!=NULL) + *pAdvf = this->sinkAdviseFlag; + + if (ppAdvSink!=NULL) + { + IAdviseSink_QueryInterface(this->sinkInterface, + &IID_IAdviseSink, + (void**)ppAdvSink); + } + + return S_OK; +} + +/************************************************************************ + * DataCache_GetExtent (IViewObject2) + * + * This method retrieves the "natural" size of this cached object. + * + * See Windows documentation for more details on IViewObject2 methods. + */ +static HRESULT WINAPI DataCache_GetExtent( + IViewObject2* iface, + DWORD dwDrawAspect, + LONG lindex, + DVTARGETDEVICE* ptd, + LPSIZEL lpsizel) +{ + PresentationDataHeader presData; + HRESULT hres = E_FAIL; + + _ICOM_THIS_From_IViewObject2(DataCache, iface); + + TRACE("(%p, %lx, %ld, %p, %p)\n", + iface, dwDrawAspect, lindex, ptd, lpsizel); + + /* + * Sanity check + */ + if (lpsizel==NULL) + return E_POINTER; + + /* + * Initialize the out parameter. + */ + lpsizel->cx = 0; + lpsizel->cy = 0; + + /* + * This flag should be set to -1. + */ + if (lindex!=-1) + FIXME("Unimplemented flag lindex = %ld\n", lindex); + + /* + * Right now, we support only the callback from + * the default handler. + */ + if (ptd!=NULL) + FIXME("Unimplemented ptd = %p\n", ptd); + + /* + * Get the presentation information from the + * cache. + */ + hres = DataCache_ReadPresentationData(this, + dwDrawAspect, + &presData); + + if (SUCCEEDED(hres)) + { + lpsizel->cx = presData.dwObjectExtentX; + lpsizel->cy = presData.dwObjectExtentY; + } + + /* + * This method returns OLE_E_BLANK when it fails. + */ + if (FAILED(hres)) + hres = OLE_E_BLANK; + + return hres; +} + + +/********************************************************* + * Method implementation for the IOleCache2 + * part of the DataCache class. + */ + +/************************************************************************ + * DataCache_IOleCache2_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static HRESULT WINAPI DataCache_IOleCache2_QueryInterface( + IOleCache2* iface, + REFIID riid, + void** ppvObject) +{ + _ICOM_THIS_From_IOleCache2(DataCache, iface); + + return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject); +} + +/************************************************************************ + * DataCache_IOleCache2_AddRef (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI DataCache_IOleCache2_AddRef( + IOleCache2* iface) +{ + _ICOM_THIS_From_IOleCache2(DataCache, iface); + + return IUnknown_AddRef(this->outerUnknown); +} + +/************************************************************************ + * DataCache_IOleCache2_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI DataCache_IOleCache2_Release( + IOleCache2* iface) +{ + _ICOM_THIS_From_IOleCache2(DataCache, iface); + + return IUnknown_Release(this->outerUnknown); +} + +static HRESULT WINAPI DataCache_Cache( + IOleCache2* iface, + FORMATETC* pformatetc, + DWORD advf, + DWORD* pdwConnection) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DataCache_Uncache( + IOleCache2* iface, + DWORD dwConnection) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DataCache_EnumCache( + IOleCache2* iface, + IEnumSTATDATA** ppenumSTATDATA) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DataCache_InitCache( + IOleCache2* iface, + IDataObject* pDataObject) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DataCache_IOleCache2_SetData( + IOleCache2* iface, + FORMATETC* pformatetc, + STGMEDIUM* pmedium, + BOOL fRelease) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DataCache_UpdateCache( + IOleCache2* iface, + LPDATAOBJECT pDataObject, + DWORD grfUpdf, + LPVOID pReserved) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DataCache_DiscardCache( + IOleCache2* iface, + DWORD dwDiscardOptions) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + + +/********************************************************* + * Method implementation for the IOleCacheControl + * part of the DataCache class. + */ + +/************************************************************************ + * DataCache_IOleCacheControl_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static HRESULT WINAPI DataCache_IOleCacheControl_QueryInterface( + IOleCacheControl* iface, + REFIID riid, + void** ppvObject) +{ + _ICOM_THIS_From_IOleCacheControl(DataCache, iface); + + return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject); +} + +/************************************************************************ + * DataCache_IOleCacheControl_AddRef (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI DataCache_IOleCacheControl_AddRef( + IOleCacheControl* iface) +{ + _ICOM_THIS_From_IOleCacheControl(DataCache, iface); + + return IUnknown_AddRef(this->outerUnknown); +} + +/************************************************************************ + * DataCache_IOleCacheControl_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI DataCache_IOleCacheControl_Release( + IOleCacheControl* iface) +{ + _ICOM_THIS_From_IOleCacheControl(DataCache, iface); + + return IUnknown_Release(this->outerUnknown); +} + +static HRESULT WINAPI DataCache_OnRun( + IOleCacheControl* iface, + LPDATAOBJECT pDataObject) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI DataCache_OnStop( + IOleCacheControl* iface) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + +/* + * Virtual function tables for the DataCache class. + */ +static IUnknownVtbl DataCache_NDIUnknown_VTable = +{ + DataCache_NDIUnknown_QueryInterface, + DataCache_NDIUnknown_AddRef, + DataCache_NDIUnknown_Release +}; + +static IDataObjectVtbl DataCache_IDataObject_VTable = +{ + DataCache_IDataObject_QueryInterface, + DataCache_IDataObject_AddRef, + DataCache_IDataObject_Release, + DataCache_GetData, + DataCache_GetDataHere, + DataCache_QueryGetData, + DataCache_GetCanonicalFormatEtc, + DataCache_IDataObject_SetData, + DataCache_EnumFormatEtc, + DataCache_DAdvise, + DataCache_DUnadvise, + DataCache_EnumDAdvise +}; + +static IPersistStorageVtbl DataCache_IPersistStorage_VTable = +{ + DataCache_IPersistStorage_QueryInterface, + DataCache_IPersistStorage_AddRef, + DataCache_IPersistStorage_Release, + DataCache_GetClassID, + DataCache_IsDirty, + DataCache_InitNew, + DataCache_Load, + DataCache_Save, + DataCache_SaveCompleted, + DataCache_HandsOffStorage +}; + +static IViewObject2Vtbl DataCache_IViewObject2_VTable = +{ + DataCache_IViewObject2_QueryInterface, + DataCache_IViewObject2_AddRef, + DataCache_IViewObject2_Release, + DataCache_Draw, + DataCache_GetColorSet, + DataCache_Freeze, + DataCache_Unfreeze, + DataCache_SetAdvise, + DataCache_GetAdvise, + DataCache_GetExtent +}; + +static IOleCache2Vtbl DataCache_IOleCache2_VTable = +{ + DataCache_IOleCache2_QueryInterface, + DataCache_IOleCache2_AddRef, + DataCache_IOleCache2_Release, + DataCache_Cache, + DataCache_Uncache, + DataCache_EnumCache, + DataCache_InitCache, + DataCache_IOleCache2_SetData, + DataCache_UpdateCache, + DataCache_DiscardCache +}; + +static IOleCacheControlVtbl DataCache_IOleCacheControl_VTable = +{ + DataCache_IOleCacheControl_QueryInterface, + DataCache_IOleCacheControl_AddRef, + DataCache_IOleCacheControl_Release, + DataCache_OnRun, + DataCache_OnStop +}; + +/****************************************************************************** + * CreateDataCache [OLE32.@] + */ +HRESULT WINAPI CreateDataCache( + LPUNKNOWN pUnkOuter, + REFCLSID rclsid, + REFIID riid, + LPVOID* ppvObj) +{ + DataCache* newCache = NULL; + HRESULT hr = S_OK; + + TRACE("(%s, %p, %s, %p)\n", debugstr_guid(rclsid), pUnkOuter, debugstr_guid(riid), ppvObj); + + /* + * Sanity check + */ + if (ppvObj==0) + return E_POINTER; + + *ppvObj = 0; + + /* + * If this cache is constructed for aggregation, make sure + * the caller is requesting the IUnknown interface. + * This is necessary because it's the only time the non-delegating + * IUnknown pointer can be returned to the outside. + */ + if ( (pUnkOuter!=NULL) && + (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) != 0) ) + return CLASS_E_NOAGGREGATION; + + /* + * Try to construct a new instance of the class. + */ + newCache = DataCache_Construct(rclsid, + pUnkOuter); + + if (newCache == 0) + return E_OUTOFMEMORY; + + /* + * Make sure it supports the interface required by the caller. + */ + hr = IUnknown_QueryInterface((IUnknown*)&(newCache->lpvtbl2), riid, ppvObj); + + /* + * Release the reference obtained in the constructor. If + * the QueryInterface was unsuccessful, it will free the class. + */ + IUnknown_Release((IUnknown*)&(newCache->lpvtbl2)); + + return hr; +} + +/********************************************************* + * Method implementation for DataCache class. + */ +static DataCache* DataCache_Construct( + REFCLSID clsid, + LPUNKNOWN pUnkOuter) +{ + DataCache* newObject = 0; + + /* + * Allocate space for the object. + */ + newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DataCache)); + + if (newObject==0) + return newObject; + + /* + * Initialize the virtual function table. + */ + newObject->lpvtbl1 = &DataCache_IDataObject_VTable; + newObject->lpvtbl2 = &DataCache_NDIUnknown_VTable; + newObject->lpvtbl3 = &DataCache_IPersistStorage_VTable; + newObject->lpvtbl4 = &DataCache_IViewObject2_VTable; + newObject->lpvtbl5 = &DataCache_IOleCache2_VTable; + newObject->lpvtbl6 = &DataCache_IOleCacheControl_VTable; + + /* + * Start with one reference count. The caller of this function + * must release the interface pointer when it is done. + */ + newObject->ref = 1; + + /* + * Initialize the outer unknown + * We don't keep a reference on the outer unknown since, the way + * aggregation works, our lifetime is at least as large as it's + * lifetime. + */ + if (pUnkOuter==NULL) + pUnkOuter = (IUnknown*)&(newObject->lpvtbl2); + + newObject->outerUnknown = pUnkOuter; + + /* + * Initialize the other members of the structure. + */ + newObject->presentationStorage = NULL; + newObject->sinkAspects = 0; + newObject->sinkAdviseFlag = 0; + newObject->sinkInterface = 0; + + return newObject; +} diff --git a/reactos/lib/ole32/dcom.h b/reactos/lib/ole32/dcom.h index 812402b5501..3ea35faaf13 100644 --- a/reactos/lib/ole32/dcom.h +++ b/reactos/lib/ole32/dcom.h @@ -1,515 +1,515 @@ -/*** Autogenerated by WIDL 0.1 from dcom.idl - Do not edit ***/ -#include <rpc.h> -#include <rpcndr.h> - -#ifndef __WIDL_DCOM_H -#define __WIDL_DCOM_H -#ifdef __cplusplus -extern "C" { -#endif -#include <unknwn.h> -typedef MIDL_uhyper ID; - -typedef ID MID; - -typedef ID OXID; - -typedef ID OID; - -typedef ID SETID; - -typedef GUID IPID; - -typedef GUID CID; - -typedef REFGUID REFIPID; - -#define COM_MINOR_VERSION_1 (1) - -#define COM_MINOR_VERSION_2 (2) - -#define COM_MAJOR_VERSION (5) - -#define COM_MINOR_VERSION (3) - -typedef struct tagCOMVERSION { - unsigned short MajorVersion; - unsigned short MinorVersion; -} COMVERSION; - -#define ORPCF_NULL (0) - -#define ORPCF_LOCAL (1) - -#define ORPCF_RESERVED1 (2) - -#define ORPCF_RESERVED2 (4) - -#define ORPCF_RESERVED3 (8) - -#define ORPCF_RESERVED4 (16) - -typedef struct tagORPC_EXTENT { - GUID id; - unsigned long size; - byte data[1]; -} ORPC_EXTENT; - -typedef struct tagORPC_EXTENT_ARRAY { - unsigned long size; - unsigned long reserved; - ORPC_EXTENT **extent; -} ORPC_EXTENT_ARRAY; - -typedef struct tagORPCTHIS { - COMVERSION version; - unsigned long flags; - unsigned long reserved1; - CID cid; - ORPC_EXTENT_ARRAY *extensions; -} ORPCTHIS; - -typedef struct tagORPCTHAT { - unsigned long flags; - ORPC_EXTENT_ARRAY *extensions; -} ORPCTHAT; - -#define NCADG_IP_UDP (0x8) - -#define NCACN_IP_TCP (0x7) - -#define NCADG_IPX (0xe) - -#define NCACN_SPX (0xc) - -#define NCACN_NB_NB (0x12) - -#define NCACN_NB_IPX (0xd) - -#define NCACN_DNET_NSP (0x4) - -#define NCACN_HTTP (0x1f) - -typedef struct tagSTRINGBINDING { - unsigned short wTowerId; - unsigned short aNetworkAddr[1]; -} STRINGBINDING; - -#define COM_C_AUTHZ_NONE (0xffff) - -typedef struct tagSECURITYBINDING { - unsigned short wAuthnSvc; - unsigned short wAuthzSvc; - unsigned short aPrincName[1]; -} SECURITYBINDING; - -typedef struct tagDUALSTRINGARRAY { - unsigned short wNumEntries; - unsigned short wSecurityOffset; - unsigned short aStringArray[1]; -} DUALSTRINGARRAY; - -#define OBJREF_SIGNATURE (0x574f454d) - -#define OBJREF_STANDARD (0x1) - -#define OBJREF_HANDLER (0x2) - -#define OBJREF_CUSTOM (0x4) - -#define SORF_OXRES1 (0x1) - -#define SORF_OXRES2 (0x20) - -#define SORF_OXRES3 (0x40) - -#define SORF_OXRES4 (0x80) - -#define SORF_OXRES5 (0x100) - -#define SORF_OXRES6 (0x200) - -#define SORF_OXRES7 (0x400) - -#define SORF_OXRES8 (0x800) - -#define SORF_NULL (0x0) - -#define SORF_NOPING (0x1000) - -typedef struct tagSTDOBJREF { - unsigned long flags; - unsigned long cPublicRefs; - OXID oxid; - OID oid; - IPID ipid; -} STDOBJREF; - -typedef struct tagOBJREF { - unsigned long signature; - unsigned long flags; - GUID iid; - union { - struct OR_STANDARD { - STDOBJREF std; - DUALSTRINGARRAY saResAddr; - } u_standard; - struct OR_HANDLER { - STDOBJREF std; - CLSID clsid; - DUALSTRINGARRAY saResAddr; - } u_handler; - struct OR_CUSTOM { - CLSID clsid; - unsigned long cbExtension; - unsigned long size; - byte *pData; - } u_custom; - } u_objref; -} OBJREF; - -typedef struct tagMInterfacePointer { - ULONG ulCntData; - BYTE abData[1]; -} MInterfacePointer; - -typedef MInterfacePointer *PMInterfacePointer; - -#ifndef __IRemUnknown_FWD_DEFINED__ -#define __IRemUnknown_FWD_DEFINED__ -typedef struct IRemUnknown IRemUnknown; -#endif - -typedef IRemUnknown *LPREMUNKNOWN; - -typedef struct tagREMQIRESULT { - HRESULT hResult; - STDOBJREF std; -} REMQIRESULT; - -typedef struct tagREMINTERFACEREF { - IPID ipid; - unsigned long cPublicRefs; - unsigned long cPrivateRefs; -} REMINTERFACEREF; - -/***************************************************************************** - * IRemUnknown interface - */ -#ifndef __IRemUnknown_INTERFACE_DEFINED__ -#define __IRemUnknown_INTERFACE_DEFINED__ - -DEFINE_GUID(IID_IRemUnknown, 0x00000131, 0x0000, 0x0000, 0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46); -#if defined(__cplusplus) && !defined(CINTERFACE) -struct IRemUnknown : public IUnknown -{ - virtual HRESULT STDMETHODCALLTYPE RemQueryInterface( - REFIPID ripid, - unsigned long cRefs, - unsigned short cIids, - IID* iids, - REMQIRESULT** ppQIResults) = 0; - - virtual HRESULT STDMETHODCALLTYPE RemAddRef( - unsigned short cInterfaceRefs, - REMINTERFACEREF* InterfaceRefs, - HRESULT* pResults) = 0; - - virtual HRESULT STDMETHODCALLTYPE RemRelease( - unsigned short cInterfaceRefs, - REMINTERFACEREF* InterfaceRefs) = 0; - -}; -#else -typedef struct IRemUnknownVtbl IRemUnknownVtbl; -struct IRemUnknown { - const IRemUnknownVtbl* lpVtbl; -}; -struct IRemUnknownVtbl { - BEGIN_INTERFACE - - /*** IUnknown methods ***/ - HRESULT (STDMETHODCALLTYPE *QueryInterface)( - IRemUnknown* This, - REFIID riid, - void** ppvObject); - - ULONG (STDMETHODCALLTYPE *AddRef)( - IRemUnknown* This); - - ULONG (STDMETHODCALLTYPE *Release)( - IRemUnknown* This); - - /*** IRemUnknown methods ***/ - HRESULT (STDMETHODCALLTYPE *RemQueryInterface)( - IRemUnknown* This, - REFIPID ripid, - unsigned long cRefs, - unsigned short cIids, - IID* iids, - REMQIRESULT** ppQIResults); - - HRESULT (STDMETHODCALLTYPE *RemAddRef)( - IRemUnknown* This, - unsigned short cInterfaceRefs, - REMINTERFACEREF* InterfaceRefs, - HRESULT* pResults); - - HRESULT (STDMETHODCALLTYPE *RemRelease)( - IRemUnknown* This, - unsigned short cInterfaceRefs, - REMINTERFACEREF* InterfaceRefs); - - END_INTERFACE -}; - -#ifdef COBJMACROS -/*** IUnknown methods ***/ -#define IRemUnknown_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) -#define IRemUnknown_AddRef(p) (p)->lpVtbl->AddRef(p) -#define IRemUnknown_Release(p) (p)->lpVtbl->Release(p) -/*** IRemUnknown methods ***/ -#define IRemUnknown_RemQueryInterface(p,a,b,c,d,e) (p)->lpVtbl->RemQueryInterface(p,a,b,c,d,e) -#define IRemUnknown_RemAddRef(p,a,b,c) (p)->lpVtbl->RemAddRef(p,a,b,c) -#define IRemUnknown_RemRelease(p,a,b) (p)->lpVtbl->RemRelease(p,a,b) -#endif - -#endif - -#define IRemUnknown_METHODS \ - /*** IUnknown methods ***/ \ - STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; \ - STDMETHOD_(ULONG,AddRef)(THIS) PURE; \ - STDMETHOD_(ULONG,Release)(THIS) PURE; \ - /*** IRemUnknown methods ***/ \ - STDMETHOD_(HRESULT,RemQueryInterface)(THIS_ REFIPID ripid, unsigned long cRefs, unsigned short cIids, IID* iids, REMQIRESULT** ppQIResults) PURE; \ - STDMETHOD_(HRESULT,RemAddRef)(THIS_ unsigned short cInterfaceRefs, REMINTERFACEREF* InterfaceRefs, HRESULT* pResults) PURE; \ - STDMETHOD_(HRESULT,RemRelease)(THIS_ unsigned short cInterfaceRefs, REMINTERFACEREF* InterfaceRefs) PURE; - -HRESULT CALLBACK IRemUnknown_RemQueryInterface_Proxy( - IRemUnknown* This, - REFIPID ripid, - unsigned long cRefs, - unsigned short cIids, - IID* iids, - REMQIRESULT** ppQIResults); -void __RPC_STUB IRemUnknown_RemQueryInterface_Stub( - struct IRpcStubBuffer* This, - struct IRpcChannelBuffer* pRpcChannelBuffer, - PRPC_MESSAGE pRpcMessage, - DWORD* pdwStubPhase); -HRESULT CALLBACK IRemUnknown_RemAddRef_Proxy( - IRemUnknown* This, - unsigned short cInterfaceRefs, - REMINTERFACEREF* InterfaceRefs, - HRESULT* pResults); -void __RPC_STUB IRemUnknown_RemAddRef_Stub( - struct IRpcStubBuffer* This, - struct IRpcChannelBuffer* pRpcChannelBuffer, - PRPC_MESSAGE pRpcMessage, - DWORD* pdwStubPhase); -HRESULT CALLBACK IRemUnknown_RemRelease_Proxy( - IRemUnknown* This, - unsigned short cInterfaceRefs, - REMINTERFACEREF* InterfaceRefs); -void __RPC_STUB IRemUnknown_RemRelease_Stub( - struct IRpcStubBuffer* This, - struct IRpcChannelBuffer* pRpcChannelBuffer, - PRPC_MESSAGE pRpcMessage, - DWORD* pdwStubPhase); - -#endif /* __IRemUnknown_INTERFACE_DEFINED__ */ - -#ifndef __IRemUnknown2_FWD_DEFINED__ -#define __IRemUnknown2_FWD_DEFINED__ -typedef struct IRemUnknown2 IRemUnknown2; -#endif - -typedef IRemUnknown2 *LPREMUNKNOWN2; - -/***************************************************************************** - * IRemUnknown2 interface - */ -#ifndef __IRemUnknown2_INTERFACE_DEFINED__ -#define __IRemUnknown2_INTERFACE_DEFINED__ - -DEFINE_GUID(IID_IRemUnknown2, 0x00000142, 0x0000, 0x0000, 0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46); -#if defined(__cplusplus) && !defined(CINTERFACE) -struct IRemUnknown2 : public IRemUnknown -{ - virtual HRESULT STDMETHODCALLTYPE RemQueryInterface2( - REFIPID ripid, - unsigned short cIids, - IID* iids, - HRESULT* phr, - MInterfacePointer** ppMIF) = 0; - -}; -#else -typedef struct IRemUnknown2Vtbl IRemUnknown2Vtbl; -struct IRemUnknown2 { - const IRemUnknown2Vtbl* lpVtbl; -}; -struct IRemUnknown2Vtbl { - BEGIN_INTERFACE - - /*** IUnknown methods ***/ - HRESULT (STDMETHODCALLTYPE *QueryInterface)( - IRemUnknown2* This, - REFIID riid, - void** ppvObject); - - ULONG (STDMETHODCALLTYPE *AddRef)( - IRemUnknown2* This); - - ULONG (STDMETHODCALLTYPE *Release)( - IRemUnknown2* This); - - /*** IRemUnknown methods ***/ - HRESULT (STDMETHODCALLTYPE *RemQueryInterface)( - IRemUnknown2* This, - REFIPID ripid, - unsigned long cRefs, - unsigned short cIids, - IID* iids, - REMQIRESULT** ppQIResults); - - HRESULT (STDMETHODCALLTYPE *RemAddRef)( - IRemUnknown2* This, - unsigned short cInterfaceRefs, - REMINTERFACEREF* InterfaceRefs, - HRESULT* pResults); - - HRESULT (STDMETHODCALLTYPE *RemRelease)( - IRemUnknown2* This, - unsigned short cInterfaceRefs, - REMINTERFACEREF* InterfaceRefs); - - /*** IRemUnknown2 methods ***/ - HRESULT (STDMETHODCALLTYPE *RemQueryInterface2)( - IRemUnknown2* This, - REFIPID ripid, - unsigned short cIids, - IID* iids, - HRESULT* phr, - MInterfacePointer** ppMIF); - - END_INTERFACE -}; - -#ifdef COBJMACROS -/*** IUnknown methods ***/ -#define IRemUnknown2_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) -#define IRemUnknown2_AddRef(p) (p)->lpVtbl->AddRef(p) -#define IRemUnknown2_Release(p) (p)->lpVtbl->Release(p) -/*** IRemUnknown methods ***/ -#define IRemUnknown2_RemQueryInterface(p,a,b,c,d,e) (p)->lpVtbl->RemQueryInterface(p,a,b,c,d,e) -#define IRemUnknown2_RemAddRef(p,a,b,c) (p)->lpVtbl->RemAddRef(p,a,b,c) -#define IRemUnknown2_RemRelease(p,a,b) (p)->lpVtbl->RemRelease(p,a,b) -/*** IRemUnknown2 methods ***/ -#define IRemUnknown2_RemQueryInterface2(p,a,b,c,d,e) (p)->lpVtbl->RemQueryInterface2(p,a,b,c,d,e) -#endif - -#endif - -#define IRemUnknown2_METHODS \ - /*** IUnknown methods ***/ \ - STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; \ - STDMETHOD_(ULONG,AddRef)(THIS) PURE; \ - STDMETHOD_(ULONG,Release)(THIS) PURE; \ - /*** IRemUnknown methods ***/ \ - STDMETHOD_(HRESULT,RemQueryInterface)(THIS_ REFIPID ripid, unsigned long cRefs, unsigned short cIids, IID* iids, REMQIRESULT** ppQIResults) PURE; \ - STDMETHOD_(HRESULT,RemAddRef)(THIS_ unsigned short cInterfaceRefs, REMINTERFACEREF* InterfaceRefs, HRESULT* pResults) PURE; \ - STDMETHOD_(HRESULT,RemRelease)(THIS_ unsigned short cInterfaceRefs, REMINTERFACEREF* InterfaceRefs) PURE; \ - /*** IRemUnknown2 methods ***/ \ - STDMETHOD_(HRESULT,RemQueryInterface2)(THIS_ REFIPID ripid, unsigned short cIids, IID* iids, HRESULT* phr, MInterfacePointer** ppMIF) PURE; - -HRESULT CALLBACK IRemUnknown2_RemQueryInterface2_Proxy( - IRemUnknown2* This, - REFIPID ripid, - unsigned short cIids, - IID* iids, - HRESULT* phr, - MInterfacePointer** ppMIF); -void __RPC_STUB IRemUnknown2_RemQueryInterface2_Stub( - struct IRpcStubBuffer* This, - struct IRpcChannelBuffer* pRpcChannelBuffer, - PRPC_MESSAGE pRpcMessage, - DWORD* pdwStubPhase); - -#endif /* __IRemUnknown2_INTERFACE_DEFINED__ */ - -#if 0 -/***************************************************************************** - * IOXIDResolver interface (v0.0) - */ -DEFINE_GUID(IID_IOXIDResolver, 0x99fcfec4, 0x5260, 0x101b, 0xbb,0xcb, 0x00,0xaa,0x00,0x21,0x34,0x7a); -extern RPC_IF_HANDLE IOXIDResolver_v0_0_c_ifspec; -extern RPC_IF_HANDLE IOXIDResolver_v0_0_s_ifspec; -error_status_t ResolveOxid( - handle_t hRpc, - OXID* pOxid, - unsigned short cRequestedProtseqs, - unsigned short arRequestedProtseqs[], - DUALSTRINGARRAY** ppdsaOxidBindings, - IPID* pipidRemUnknown, - DWORD* pAuthnHint); -error_status_t SimplePing( - handle_t hRpc, - SETID* pSetId); -error_status_t ComplexPing( - handle_t hRpc, - SETID* pSetId, - unsigned short SequenceNum, - unsigned short cAddToSet, - unsigned short cDelFromSet, - OID AddToSet[], - OID DelFromSet[], - unsigned short* pPingBackoffFactor); -error_status_t ServerAlive( - handle_t hRpc); -error_status_t ResolveOxid2( - handle_t hRpc, - OXID* pOxid, - unsigned short cRequestedProtseqs, - unsigned short arRequestedProtseqs[], - DUALSTRINGARRAY** ppdsaOxidBindings, - IPID* pipidRemUnknown, - DWORD* pAuthnHint, - COMVERSION* pComVersion); - -#define MODE_GET_CLASS_OBJECT (0xffffffff) - -/***************************************************************************** - * IRemoteActivation interface (v0.0) - */ -DEFINE_GUID(IID_IRemoteActivation, 0x4d9f4ab8, 0x7d1c, 0x11cf, 0x86,0x1e, 0x00,0x20,0xaf,0x6e,0x7c,0x57); -extern RPC_IF_HANDLE IRemoteActivation_v0_0_c_ifspec; -extern RPC_IF_HANDLE IRemoteActivation_v0_0_s_ifspec; -HRESULT RemoteActivation( - handle_t hRpc, - ORPCTHIS* ORPCthis, - ORPCTHAT* ORPCthat, - GUID* Clsid, - WCHAR* pwszObjectName, - MInterfacePointer* pObjectStorage, - DWORD ClientImpLevel, - DWORD Mode, - DWORD Interfaces, - IID* pIIDs, - unsigned short cRequestedProtseqs, - unsigned short RequestedProtseqs[], - OXID* pOxid, - DUALSTRINGARRAY** ppdsaOxidBindings, - IPID* pipidRemUnknown, - DWORD* pAuthnHint, - COMVERSION* pServerVersion, - HRESULT* phr, - MInterfacePointer** ppInterfaceData, - HRESULT* pResults); - -#endif -#ifdef __cplusplus -} -#endif -#endif /* __WIDL_DCOM_H */ +/*** Autogenerated by WIDL 0.1 from dcom.idl - Do not edit ***/ +#include <rpc.h> +#include <rpcndr.h> + +#ifndef __WIDL_DCOM_H +#define __WIDL_DCOM_H +#ifdef __cplusplus +extern "C" { +#endif +#include <unknwn.h> +typedef MIDL_uhyper ID; + +typedef ID MID; + +typedef ID OXID; + +typedef ID OID; + +typedef ID SETID; + +typedef GUID IPID; + +typedef GUID CID; + +typedef REFGUID REFIPID; + +#define COM_MINOR_VERSION_1 (1) + +#define COM_MINOR_VERSION_2 (2) + +#define COM_MAJOR_VERSION (5) + +#define COM_MINOR_VERSION (3) + +typedef struct tagCOMVERSION { + unsigned short MajorVersion; + unsigned short MinorVersion; +} COMVERSION; + +#define ORPCF_NULL (0) + +#define ORPCF_LOCAL (1) + +#define ORPCF_RESERVED1 (2) + +#define ORPCF_RESERVED2 (4) + +#define ORPCF_RESERVED3 (8) + +#define ORPCF_RESERVED4 (16) + +typedef struct tagORPC_EXTENT { + GUID id; + unsigned long size; + byte data[1]; +} ORPC_EXTENT; + +typedef struct tagORPC_EXTENT_ARRAY { + unsigned long size; + unsigned long reserved; + ORPC_EXTENT **extent; +} ORPC_EXTENT_ARRAY; + +typedef struct tagORPCTHIS { + COMVERSION version; + unsigned long flags; + unsigned long reserved1; + CID cid; + ORPC_EXTENT_ARRAY *extensions; +} ORPCTHIS; + +typedef struct tagORPCTHAT { + unsigned long flags; + ORPC_EXTENT_ARRAY *extensions; +} ORPCTHAT; + +#define NCADG_IP_UDP (0x8) + +#define NCACN_IP_TCP (0x7) + +#define NCADG_IPX (0xe) + +#define NCACN_SPX (0xc) + +#define NCACN_NB_NB (0x12) + +#define NCACN_NB_IPX (0xd) + +#define NCACN_DNET_NSP (0x4) + +#define NCACN_HTTP (0x1f) + +typedef struct tagSTRINGBINDING { + unsigned short wTowerId; + unsigned short aNetworkAddr[1]; +} STRINGBINDING; + +#define COM_C_AUTHZ_NONE (0xffff) + +typedef struct tagSECURITYBINDING { + unsigned short wAuthnSvc; + unsigned short wAuthzSvc; + unsigned short aPrincName[1]; +} SECURITYBINDING; + +typedef struct tagDUALSTRINGARRAY { + unsigned short wNumEntries; + unsigned short wSecurityOffset; + unsigned short aStringArray[1]; +} DUALSTRINGARRAY; + +#define OBJREF_SIGNATURE (0x574f454d) + +#define OBJREF_STANDARD (0x1) + +#define OBJREF_HANDLER (0x2) + +#define OBJREF_CUSTOM (0x4) + +#define SORF_OXRES1 (0x1) + +#define SORF_OXRES2 (0x20) + +#define SORF_OXRES3 (0x40) + +#define SORF_OXRES4 (0x80) + +#define SORF_OXRES5 (0x100) + +#define SORF_OXRES6 (0x200) + +#define SORF_OXRES7 (0x400) + +#define SORF_OXRES8 (0x800) + +#define SORF_NULL (0x0) + +#define SORF_NOPING (0x1000) + +typedef struct tagSTDOBJREF { + unsigned long flags; + unsigned long cPublicRefs; + OXID oxid; + OID oid; + IPID ipid; +} STDOBJREF; + +typedef struct tagOBJREF { + unsigned long signature; + unsigned long flags; + GUID iid; + union { + struct OR_STANDARD { + STDOBJREF std; + DUALSTRINGARRAY saResAddr; + } u_standard; + struct OR_HANDLER { + STDOBJREF std; + CLSID clsid; + DUALSTRINGARRAY saResAddr; + } u_handler; + struct OR_CUSTOM { + CLSID clsid; + unsigned long cbExtension; + unsigned long size; + byte *pData; + } u_custom; + } u_objref; +} OBJREF; + +typedef struct tagMInterfacePointer { + ULONG ulCntData; + BYTE abData[1]; +} MInterfacePointer; + +typedef MInterfacePointer *PMInterfacePointer; + +#ifndef __IRemUnknown_FWD_DEFINED__ +#define __IRemUnknown_FWD_DEFINED__ +typedef struct IRemUnknown IRemUnknown; +#endif + +typedef IRemUnknown *LPREMUNKNOWN; + +typedef struct tagREMQIRESULT { + HRESULT hResult; + STDOBJREF std; +} REMQIRESULT; + +typedef struct tagREMINTERFACEREF { + IPID ipid; + unsigned long cPublicRefs; + unsigned long cPrivateRefs; +} REMINTERFACEREF; + +/***************************************************************************** + * IRemUnknown interface + */ +#ifndef __IRemUnknown_INTERFACE_DEFINED__ +#define __IRemUnknown_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IRemUnknown, 0x00000131, 0x0000, 0x0000, 0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46); +#if defined(__cplusplus) && !defined(CINTERFACE) +struct IRemUnknown : public IUnknown +{ + virtual HRESULT STDMETHODCALLTYPE RemQueryInterface( + REFIPID ripid, + unsigned long cRefs, + unsigned short cIids, + IID* iids, + REMQIRESULT** ppQIResults) = 0; + + virtual HRESULT STDMETHODCALLTYPE RemAddRef( + unsigned short cInterfaceRefs, + REMINTERFACEREF* InterfaceRefs, + HRESULT* pResults) = 0; + + virtual HRESULT STDMETHODCALLTYPE RemRelease( + unsigned short cInterfaceRefs, + REMINTERFACEREF* InterfaceRefs) = 0; + +}; +#else +typedef struct IRemUnknownVtbl IRemUnknownVtbl; +struct IRemUnknown { + const IRemUnknownVtbl* lpVtbl; +}; +struct IRemUnknownVtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IRemUnknown* This, + REFIID riid, + void** ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IRemUnknown* This); + + ULONG (STDMETHODCALLTYPE *Release)( + IRemUnknown* This); + + /*** IRemUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *RemQueryInterface)( + IRemUnknown* This, + REFIPID ripid, + unsigned long cRefs, + unsigned short cIids, + IID* iids, + REMQIRESULT** ppQIResults); + + HRESULT (STDMETHODCALLTYPE *RemAddRef)( + IRemUnknown* This, + unsigned short cInterfaceRefs, + REMINTERFACEREF* InterfaceRefs, + HRESULT* pResults); + + HRESULT (STDMETHODCALLTYPE *RemRelease)( + IRemUnknown* This, + unsigned short cInterfaceRefs, + REMINTERFACEREF* InterfaceRefs); + + END_INTERFACE +}; + +#ifdef COBJMACROS +/*** IUnknown methods ***/ +#define IRemUnknown_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IRemUnknown_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IRemUnknown_Release(p) (p)->lpVtbl->Release(p) +/*** IRemUnknown methods ***/ +#define IRemUnknown_RemQueryInterface(p,a,b,c,d,e) (p)->lpVtbl->RemQueryInterface(p,a,b,c,d,e) +#define IRemUnknown_RemAddRef(p,a,b,c) (p)->lpVtbl->RemAddRef(p,a,b,c) +#define IRemUnknown_RemRelease(p,a,b) (p)->lpVtbl->RemRelease(p,a,b) +#endif + +#endif + +#define IRemUnknown_METHODS \ + /*** IUnknown methods ***/ \ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; \ + STDMETHOD_(ULONG,AddRef)(THIS) PURE; \ + STDMETHOD_(ULONG,Release)(THIS) PURE; \ + /*** IRemUnknown methods ***/ \ + STDMETHOD_(HRESULT,RemQueryInterface)(THIS_ REFIPID ripid, unsigned long cRefs, unsigned short cIids, IID* iids, REMQIRESULT** ppQIResults) PURE; \ + STDMETHOD_(HRESULT,RemAddRef)(THIS_ unsigned short cInterfaceRefs, REMINTERFACEREF* InterfaceRefs, HRESULT* pResults) PURE; \ + STDMETHOD_(HRESULT,RemRelease)(THIS_ unsigned short cInterfaceRefs, REMINTERFACEREF* InterfaceRefs) PURE; + +HRESULT CALLBACK IRemUnknown_RemQueryInterface_Proxy( + IRemUnknown* This, + REFIPID ripid, + unsigned long cRefs, + unsigned short cIids, + IID* iids, + REMQIRESULT** ppQIResults); +void __RPC_STUB IRemUnknown_RemQueryInterface_Stub( + struct IRpcStubBuffer* This, + struct IRpcChannelBuffer* pRpcChannelBuffer, + PRPC_MESSAGE pRpcMessage, + DWORD* pdwStubPhase); +HRESULT CALLBACK IRemUnknown_RemAddRef_Proxy( + IRemUnknown* This, + unsigned short cInterfaceRefs, + REMINTERFACEREF* InterfaceRefs, + HRESULT* pResults); +void __RPC_STUB IRemUnknown_RemAddRef_Stub( + struct IRpcStubBuffer* This, + struct IRpcChannelBuffer* pRpcChannelBuffer, + PRPC_MESSAGE pRpcMessage, + DWORD* pdwStubPhase); +HRESULT CALLBACK IRemUnknown_RemRelease_Proxy( + IRemUnknown* This, + unsigned short cInterfaceRefs, + REMINTERFACEREF* InterfaceRefs); +void __RPC_STUB IRemUnknown_RemRelease_Stub( + struct IRpcStubBuffer* This, + struct IRpcChannelBuffer* pRpcChannelBuffer, + PRPC_MESSAGE pRpcMessage, + DWORD* pdwStubPhase); + +#endif /* __IRemUnknown_INTERFACE_DEFINED__ */ + +#ifndef __IRemUnknown2_FWD_DEFINED__ +#define __IRemUnknown2_FWD_DEFINED__ +typedef struct IRemUnknown2 IRemUnknown2; +#endif + +typedef IRemUnknown2 *LPREMUNKNOWN2; + +/***************************************************************************** + * IRemUnknown2 interface + */ +#ifndef __IRemUnknown2_INTERFACE_DEFINED__ +#define __IRemUnknown2_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IRemUnknown2, 0x00000142, 0x0000, 0x0000, 0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46); +#if defined(__cplusplus) && !defined(CINTERFACE) +struct IRemUnknown2 : public IRemUnknown +{ + virtual HRESULT STDMETHODCALLTYPE RemQueryInterface2( + REFIPID ripid, + unsigned short cIids, + IID* iids, + HRESULT* phr, + MInterfacePointer** ppMIF) = 0; + +}; +#else +typedef struct IRemUnknown2Vtbl IRemUnknown2Vtbl; +struct IRemUnknown2 { + const IRemUnknown2Vtbl* lpVtbl; +}; +struct IRemUnknown2Vtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IRemUnknown2* This, + REFIID riid, + void** ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IRemUnknown2* This); + + ULONG (STDMETHODCALLTYPE *Release)( + IRemUnknown2* This); + + /*** IRemUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *RemQueryInterface)( + IRemUnknown2* This, + REFIPID ripid, + unsigned long cRefs, + unsigned short cIids, + IID* iids, + REMQIRESULT** ppQIResults); + + HRESULT (STDMETHODCALLTYPE *RemAddRef)( + IRemUnknown2* This, + unsigned short cInterfaceRefs, + REMINTERFACEREF* InterfaceRefs, + HRESULT* pResults); + + HRESULT (STDMETHODCALLTYPE *RemRelease)( + IRemUnknown2* This, + unsigned short cInterfaceRefs, + REMINTERFACEREF* InterfaceRefs); + + /*** IRemUnknown2 methods ***/ + HRESULT (STDMETHODCALLTYPE *RemQueryInterface2)( + IRemUnknown2* This, + REFIPID ripid, + unsigned short cIids, + IID* iids, + HRESULT* phr, + MInterfacePointer** ppMIF); + + END_INTERFACE +}; + +#ifdef COBJMACROS +/*** IUnknown methods ***/ +#define IRemUnknown2_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IRemUnknown2_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IRemUnknown2_Release(p) (p)->lpVtbl->Release(p) +/*** IRemUnknown methods ***/ +#define IRemUnknown2_RemQueryInterface(p,a,b,c,d,e) (p)->lpVtbl->RemQueryInterface(p,a,b,c,d,e) +#define IRemUnknown2_RemAddRef(p,a,b,c) (p)->lpVtbl->RemAddRef(p,a,b,c) +#define IRemUnknown2_RemRelease(p,a,b) (p)->lpVtbl->RemRelease(p,a,b) +/*** IRemUnknown2 methods ***/ +#define IRemUnknown2_RemQueryInterface2(p,a,b,c,d,e) (p)->lpVtbl->RemQueryInterface2(p,a,b,c,d,e) +#endif + +#endif + +#define IRemUnknown2_METHODS \ + /*** IUnknown methods ***/ \ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; \ + STDMETHOD_(ULONG,AddRef)(THIS) PURE; \ + STDMETHOD_(ULONG,Release)(THIS) PURE; \ + /*** IRemUnknown methods ***/ \ + STDMETHOD_(HRESULT,RemQueryInterface)(THIS_ REFIPID ripid, unsigned long cRefs, unsigned short cIids, IID* iids, REMQIRESULT** ppQIResults) PURE; \ + STDMETHOD_(HRESULT,RemAddRef)(THIS_ unsigned short cInterfaceRefs, REMINTERFACEREF* InterfaceRefs, HRESULT* pResults) PURE; \ + STDMETHOD_(HRESULT,RemRelease)(THIS_ unsigned short cInterfaceRefs, REMINTERFACEREF* InterfaceRefs) PURE; \ + /*** IRemUnknown2 methods ***/ \ + STDMETHOD_(HRESULT,RemQueryInterface2)(THIS_ REFIPID ripid, unsigned short cIids, IID* iids, HRESULT* phr, MInterfacePointer** ppMIF) PURE; + +HRESULT CALLBACK IRemUnknown2_RemQueryInterface2_Proxy( + IRemUnknown2* This, + REFIPID ripid, + unsigned short cIids, + IID* iids, + HRESULT* phr, + MInterfacePointer** ppMIF); +void __RPC_STUB IRemUnknown2_RemQueryInterface2_Stub( + struct IRpcStubBuffer* This, + struct IRpcChannelBuffer* pRpcChannelBuffer, + PRPC_MESSAGE pRpcMessage, + DWORD* pdwStubPhase); + +#endif /* __IRemUnknown2_INTERFACE_DEFINED__ */ + +#if 0 +/***************************************************************************** + * IOXIDResolver interface (v0.0) + */ +DEFINE_GUID(IID_IOXIDResolver, 0x99fcfec4, 0x5260, 0x101b, 0xbb,0xcb, 0x00,0xaa,0x00,0x21,0x34,0x7a); +extern RPC_IF_HANDLE IOXIDResolver_v0_0_c_ifspec; +extern RPC_IF_HANDLE IOXIDResolver_v0_0_s_ifspec; +error_status_t ResolveOxid( + handle_t hRpc, + OXID* pOxid, + unsigned short cRequestedProtseqs, + unsigned short arRequestedProtseqs[], + DUALSTRINGARRAY** ppdsaOxidBindings, + IPID* pipidRemUnknown, + DWORD* pAuthnHint); +error_status_t SimplePing( + handle_t hRpc, + SETID* pSetId); +error_status_t ComplexPing( + handle_t hRpc, + SETID* pSetId, + unsigned short SequenceNum, + unsigned short cAddToSet, + unsigned short cDelFromSet, + OID AddToSet[], + OID DelFromSet[], + unsigned short* pPingBackoffFactor); +error_status_t ServerAlive( + handle_t hRpc); +error_status_t ResolveOxid2( + handle_t hRpc, + OXID* pOxid, + unsigned short cRequestedProtseqs, + unsigned short arRequestedProtseqs[], + DUALSTRINGARRAY** ppdsaOxidBindings, + IPID* pipidRemUnknown, + DWORD* pAuthnHint, + COMVERSION* pComVersion); + +#define MODE_GET_CLASS_OBJECT (0xffffffff) + +/***************************************************************************** + * IRemoteActivation interface (v0.0) + */ +DEFINE_GUID(IID_IRemoteActivation, 0x4d9f4ab8, 0x7d1c, 0x11cf, 0x86,0x1e, 0x00,0x20,0xaf,0x6e,0x7c,0x57); +extern RPC_IF_HANDLE IRemoteActivation_v0_0_c_ifspec; +extern RPC_IF_HANDLE IRemoteActivation_v0_0_s_ifspec; +HRESULT RemoteActivation( + handle_t hRpc, + ORPCTHIS* ORPCthis, + ORPCTHAT* ORPCthat, + GUID* Clsid, + WCHAR* pwszObjectName, + MInterfacePointer* pObjectStorage, + DWORD ClientImpLevel, + DWORD Mode, + DWORD Interfaces, + IID* pIIDs, + unsigned short cRequestedProtseqs, + unsigned short RequestedProtseqs[], + OXID* pOxid, + DUALSTRINGARRAY** ppdsaOxidBindings, + IPID* pipidRemUnknown, + DWORD* pAuthnHint, + COMVERSION* pServerVersion, + HRESULT* phr, + MInterfacePointer** ppInterfaceData, + HRESULT* pResults); + +#endif +#ifdef __cplusplus +} +#endif +#endif /* __WIDL_DCOM_H */ diff --git a/reactos/lib/ole32/defaulthandler.c b/reactos/lib/ole32/defaulthandler.c index 14a06121d80..205000d3ed7 100644 --- a/reactos/lib/ole32/defaulthandler.c +++ b/reactos/lib/ole32/defaulthandler.c @@ -1,1682 +1,1682 @@ -/* - * OLE 2 default object handler - * - * Copyright 1999 Francis Beaudet - * Copyright 2000 Abey George - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTES: - * The OLE2 default object handler supports a whole whack of - * interfaces including: - * IOleObject, IDataObject, IPersistStorage, IViewObject2, - * IRunnableObject, IOleCache2, IOleCacheControl and much more. - * - * All the implementation details are taken from: Inside OLE - * second edition by Kraig Brockschmidt, - * - * TODO - * - This implementation of the default handler does not launch the - * server in the DoVerb, Update, GetData, GetDataHere and Run - * methods. When it is fixed to do so, all the methods will have - * to be revisited to allow delegating to the running object - * - * - All methods in the class that use the class ID should be - * aware that it is possible for a class to be treated as - * another one and go into emulation mode. Nothing has been - * done in this area. - * - * - Some functions still return E_NOTIMPL they have to be - * implemented. Most of those are related to the running of the - * actual server. - * - * - All the methods related to notification and advise sinks are - * in place but no notifications are sent to the sinks yet. - */ -#include <assert.h> -#include <stdarg.h> -#include <string.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "winerror.h" -#include "wine/unicode.h" -#include "ole2.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/**************************************************************************** - * DefaultHandler - * - */ -struct DefaultHandler -{ - /* - * List all interface VTables here - */ - IOleObjectVtbl* lpvtbl1; - IUnknownVtbl* lpvtbl2; - IDataObjectVtbl* lpvtbl3; - IRunnableObjectVtbl* lpvtbl4; - - /* - * Reference count of this object - */ - ULONG ref; - - /* - * IUnknown implementation of the outer object. - */ - IUnknown* outerUnknown; - - /* - * Class Id that this handler object represents. - */ - CLSID clsid; - - /* - * IUnknown implementation of the datacache. - */ - IUnknown* dataCache; - - /* - * Client site for the embedded object. - */ - IOleClientSite* clientSite; - - /* - * The IOleAdviseHolder maintains the connections - * on behalf of the default handler. - */ - IOleAdviseHolder* oleAdviseHolder; - - /* - * The IDataAdviseHolder maintains the data - * connections on behalf of the default handler. - */ - IDataAdviseHolder* dataAdviseHolder; - - /* - * Name of the container and object contained - */ - LPWSTR containerApp; - LPWSTR containerObj; - -}; - -typedef struct DefaultHandler DefaultHandler; - -/* - * Here, I define utility macros to help with the casting of the - * "this" parameter. - * There is a version to accommodate all of the VTables implemented - * by this object. - */ -#define _ICOM_THIS_From_IOleObject(class,name) class* this = (class*)name -#define _ICOM_THIS_From_NDIUnknown(class, name) class* this = (class*)(((char*)name)-sizeof(void*)) -#define _ICOM_THIS_From_IDataObject(class, name) class* this = (class*)(((char*)name)-2*sizeof(void*)) -#define _ICOM_THIS_From_IRunnableObject(class, name) class* this = (class*)(((char*)name)-3*sizeof(void*)) - -/* - * Prototypes for the methods of the DefaultHandler class. - */ -static DefaultHandler* DefaultHandler_Construct(REFCLSID clsid, - LPUNKNOWN pUnkOuter); -static void DefaultHandler_Destroy(DefaultHandler* ptrToDestroy); - -/* - * Prototypes for the methods of the DefaultHandler class - * that implement non delegating IUnknown methods. - */ -static HRESULT WINAPI DefaultHandler_NDIUnknown_QueryInterface( - IUnknown* iface, - REFIID riid, - void** ppvObject); -static ULONG WINAPI DefaultHandler_NDIUnknown_AddRef( - IUnknown* iface); -static ULONG WINAPI DefaultHandler_NDIUnknown_Release( - IUnknown* iface); - -/* - * Prototypes for the methods of the DefaultHandler class - * that implement IOleObject methods. - */ -static HRESULT WINAPI DefaultHandler_QueryInterface( - IOleObject* iface, - REFIID riid, - void** ppvObject); -static ULONG WINAPI DefaultHandler_AddRef( - IOleObject* iface); -static ULONG WINAPI DefaultHandler_Release( - IOleObject* iface); -static HRESULT WINAPI DefaultHandler_SetClientSite( - IOleObject* iface, - IOleClientSite* pClientSite); -static HRESULT WINAPI DefaultHandler_GetClientSite( - IOleObject* iface, - IOleClientSite** ppClientSite); -static HRESULT WINAPI DefaultHandler_SetHostNames( - IOleObject* iface, - LPCOLESTR szContainerApp, - LPCOLESTR szContainerObj); -static HRESULT WINAPI DefaultHandler_Close( - IOleObject* iface, - DWORD dwSaveOption); -static HRESULT WINAPI DefaultHandler_SetMoniker( - IOleObject* iface, - DWORD dwWhichMoniker, - IMoniker* pmk); -static HRESULT WINAPI DefaultHandler_GetMoniker( - IOleObject* iface, - DWORD dwAssign, - DWORD dwWhichMoniker, - IMoniker** ppmk); -static HRESULT WINAPI DefaultHandler_InitFromData( - IOleObject* iface, - IDataObject* pDataObject, - BOOL fCreation, - DWORD dwReserved); -static HRESULT WINAPI DefaultHandler_GetClipboardData( - IOleObject* iface, - DWORD dwReserved, - IDataObject** ppDataObject); -static HRESULT WINAPI DefaultHandler_DoVerb( - IOleObject* iface, - LONG iVerb, - struct tagMSG* lpmsg, - IOleClientSite* pActiveSite, - LONG lindex, - HWND hwndParent, - LPCRECT lprcPosRect); -static HRESULT WINAPI DefaultHandler_EnumVerbs( - IOleObject* iface, - IEnumOLEVERB** ppEnumOleVerb); -static HRESULT WINAPI DefaultHandler_Update( - IOleObject* iface); -static HRESULT WINAPI DefaultHandler_IsUpToDate( - IOleObject* iface); -static HRESULT WINAPI DefaultHandler_GetUserClassID( - IOleObject* iface, - CLSID* pClsid); -static HRESULT WINAPI DefaultHandler_GetUserType( - IOleObject* iface, - DWORD dwFormOfType, - LPOLESTR* pszUserType); -static HRESULT WINAPI DefaultHandler_SetExtent( - IOleObject* iface, - DWORD dwDrawAspect, - SIZEL* psizel); -static HRESULT WINAPI DefaultHandler_GetExtent( - IOleObject* iface, - DWORD dwDrawAspect, - SIZEL* psizel); -static HRESULT WINAPI DefaultHandler_Advise( - IOleObject* iface, - IAdviseSink* pAdvSink, - DWORD* pdwConnection); -static HRESULT WINAPI DefaultHandler_Unadvise( - IOleObject* iface, - DWORD dwConnection); -static HRESULT WINAPI DefaultHandler_EnumAdvise( - IOleObject* iface, - IEnumSTATDATA** ppenumAdvise); -static HRESULT WINAPI DefaultHandler_GetMiscStatus( - IOleObject* iface, - DWORD dwAspect, - DWORD* pdwStatus); -static HRESULT WINAPI DefaultHandler_SetColorScheme( - IOleObject* iface, - struct tagLOGPALETTE* pLogpal); - -/* - * Prototypes for the methods of the DefaultHandler class - * that implement IDataObject methods. - */ -static HRESULT WINAPI DefaultHandler_IDataObject_QueryInterface( - IDataObject* iface, - REFIID riid, - void** ppvObject); -static ULONG WINAPI DefaultHandler_IDataObject_AddRef( - IDataObject* iface); -static ULONG WINAPI DefaultHandler_IDataObject_Release( - IDataObject* iface); -static HRESULT WINAPI DefaultHandler_GetData( - IDataObject* iface, - LPFORMATETC pformatetcIn, - STGMEDIUM* pmedium); -static HRESULT WINAPI DefaultHandler_GetDataHere( - IDataObject* iface, - LPFORMATETC pformatetc, - STGMEDIUM* pmedium); -static HRESULT WINAPI DefaultHandler_QueryGetData( - IDataObject* iface, - LPFORMATETC pformatetc); -static HRESULT WINAPI DefaultHandler_GetCanonicalFormatEtc( - IDataObject* iface, - LPFORMATETC pformatectIn, - LPFORMATETC pformatetcOut); -static HRESULT WINAPI DefaultHandler_SetData( - IDataObject* iface, - LPFORMATETC pformatetc, - STGMEDIUM* pmedium, - BOOL fRelease); -static HRESULT WINAPI DefaultHandler_EnumFormatEtc( - IDataObject* iface, - DWORD dwDirection, - IEnumFORMATETC** ppenumFormatEtc); -static HRESULT WINAPI DefaultHandler_DAdvise( - IDataObject* iface, - FORMATETC* pformatetc, - DWORD advf, - IAdviseSink* pAdvSink, - DWORD* pdwConnection); -static HRESULT WINAPI DefaultHandler_DUnadvise( - IDataObject* iface, - DWORD dwConnection); -static HRESULT WINAPI DefaultHandler_EnumDAdvise( - IDataObject* iface, - IEnumSTATDATA** ppenumAdvise); - -/* - * Prototypes for the methods of the DefaultHandler class - * that implement IRunnableObject methods. - */ -static HRESULT WINAPI DefaultHandler_IRunnableObject_QueryInterface( - IRunnableObject* iface, - REFIID riid, - void** ppvObject); -static ULONG WINAPI DefaultHandler_IRunnableObject_AddRef( - IRunnableObject* iface); -static ULONG WINAPI DefaultHandler_IRunnableObject_Release( - IRunnableObject* iface); -static HRESULT WINAPI DefaultHandler_GetRunningClass( - IRunnableObject* iface, - LPCLSID lpClsid); -static HRESULT WINAPI DefaultHandler_Run( - IRunnableObject* iface, - IBindCtx* pbc); -static BOOL WINAPI DefaultHandler_IsRunning( - IRunnableObject* iface); -static HRESULT WINAPI DefaultHandler_LockRunning( - IRunnableObject* iface, - BOOL fLock, - BOOL fLastUnlockCloses); -static HRESULT WINAPI DefaultHandler_SetContainedObject( - IRunnableObject* iface, - BOOL fContained); - - -/* - * Virtual function tables for the DefaultHandler class. - */ -static IOleObjectVtbl DefaultHandler_IOleObject_VTable = -{ - DefaultHandler_QueryInterface, - DefaultHandler_AddRef, - DefaultHandler_Release, - DefaultHandler_SetClientSite, - DefaultHandler_GetClientSite, - DefaultHandler_SetHostNames, - DefaultHandler_Close, - DefaultHandler_SetMoniker, - DefaultHandler_GetMoniker, - DefaultHandler_InitFromData, - DefaultHandler_GetClipboardData, - DefaultHandler_DoVerb, - DefaultHandler_EnumVerbs, - DefaultHandler_Update, - DefaultHandler_IsUpToDate, - DefaultHandler_GetUserClassID, - DefaultHandler_GetUserType, - DefaultHandler_SetExtent, - DefaultHandler_GetExtent, - DefaultHandler_Advise, - DefaultHandler_Unadvise, - DefaultHandler_EnumAdvise, - DefaultHandler_GetMiscStatus, - DefaultHandler_SetColorScheme -}; - -static IUnknownVtbl DefaultHandler_NDIUnknown_VTable = -{ - DefaultHandler_NDIUnknown_QueryInterface, - DefaultHandler_NDIUnknown_AddRef, - DefaultHandler_NDIUnknown_Release, -}; - -static IDataObjectVtbl DefaultHandler_IDataObject_VTable = -{ - DefaultHandler_IDataObject_QueryInterface, - DefaultHandler_IDataObject_AddRef, - DefaultHandler_IDataObject_Release, - DefaultHandler_GetData, - DefaultHandler_GetDataHere, - DefaultHandler_QueryGetData, - DefaultHandler_GetCanonicalFormatEtc, - DefaultHandler_SetData, - DefaultHandler_EnumFormatEtc, - DefaultHandler_DAdvise, - DefaultHandler_DUnadvise, - DefaultHandler_EnumDAdvise -}; - -static IRunnableObjectVtbl DefaultHandler_IRunnableObject_VTable = -{ - DefaultHandler_IRunnableObject_QueryInterface, - DefaultHandler_IRunnableObject_AddRef, - DefaultHandler_IRunnableObject_Release, - DefaultHandler_GetRunningClass, - DefaultHandler_Run, - DefaultHandler_IsRunning, - DefaultHandler_LockRunning, - DefaultHandler_SetContainedObject -}; - -/****************************************************************************** - * OleCreateDefaultHandler [OLE32.@] - */ -HRESULT WINAPI OleCreateDefaultHandler( - REFCLSID clsid, - LPUNKNOWN pUnkOuter, - REFIID riid, - LPVOID* ppvObj) -{ - DefaultHandler* newHandler = NULL; - HRESULT hr = S_OK; - - TRACE("(%s, %p, %s, %p)\n", debugstr_guid(clsid), pUnkOuter, debugstr_guid(riid), ppvObj); - - /* - * Sanity check - */ - if (ppvObj==0) - return E_POINTER; - - *ppvObj = 0; - - /* - * If this handler is constructed for aggregation, make sure - * the caller is requesting the IUnknown interface. - * This is necessary because it's the only time the non-delegating - * IUnknown pointer can be returned to the outside. - */ - if ( (pUnkOuter!=NULL) && - (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) != 0) ) - return CLASS_E_NOAGGREGATION; - - /* - * Try to construct a new instance of the class. - */ - newHandler = DefaultHandler_Construct(clsid, - pUnkOuter); - - if (newHandler == 0) - return E_OUTOFMEMORY; - - /* - * Make sure it supports the interface required by the caller. - */ - hr = IUnknown_QueryInterface((IUnknown*)&(newHandler->lpvtbl2), riid, ppvObj); - - /* - * Release the reference obtained in the constructor. If - * the QueryInterface was unsuccessful, it will free the class. - */ - IUnknown_Release((IUnknown*)&(newHandler->lpvtbl2)); - - return hr; -} - -/********************************************************* - * Methods implementation for the DefaultHandler class. - */ -static DefaultHandler* DefaultHandler_Construct( - REFCLSID clsid, - LPUNKNOWN pUnkOuter) -{ - DefaultHandler* newObject = 0; - - /* - * Allocate space for the object. - */ - newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DefaultHandler)); - - if (newObject==0) - return newObject; - - /* - * Initialize the virtual function table. - */ - newObject->lpvtbl1 = &DefaultHandler_IOleObject_VTable; - newObject->lpvtbl2 = &DefaultHandler_NDIUnknown_VTable; - newObject->lpvtbl3 = &DefaultHandler_IDataObject_VTable; - newObject->lpvtbl4 = &DefaultHandler_IRunnableObject_VTable; - - /* - * Start with one reference count. The caller of this function - * must release the interface pointer when it is done. - */ - newObject->ref = 1; - - /* - * Initialize the outer unknown - * We don't keep a reference on the outer unknown since, the way - * aggregation works, our lifetime is at least as large as it's - * lifetime. - */ - if (pUnkOuter==NULL) - pUnkOuter = (IUnknown*)&(newObject->lpvtbl2); - - newObject->outerUnknown = pUnkOuter; - - /* - * Create a datacache object. - * We aggregate with the datacache. Make sure we pass our outer - * unknown as the datacache's outer unknown. - */ - CreateDataCache(newObject->outerUnknown, - clsid, - &IID_IUnknown, - (void**)&newObject->dataCache); - - /* - * Initialize the other data members of the class. - */ - memcpy(&(newObject->clsid), clsid, sizeof(CLSID)); - newObject->clientSite = NULL; - newObject->oleAdviseHolder = NULL; - newObject->dataAdviseHolder = NULL; - newObject->containerApp = NULL; - newObject->containerObj = NULL; - - return newObject; -} - -static void DefaultHandler_Destroy( - DefaultHandler* ptrToDestroy) -{ - /* - * Free the strings idenfitying the object - */ - HeapFree( GetProcessHeap(), 0, ptrToDestroy->containerApp ); - ptrToDestroy->containerApp = NULL; - HeapFree( GetProcessHeap(), 0, ptrToDestroy->containerObj ); - ptrToDestroy->containerObj = NULL; - - /* - * Release our reference to the data cache. - */ - if (ptrToDestroy->dataCache!=NULL) - { - IUnknown_Release(ptrToDestroy->dataCache); - ptrToDestroy->dataCache = NULL; - } - - /* - * Same thing for the client site. - */ - if (ptrToDestroy->clientSite!=NULL) - { - IOleClientSite_Release(ptrToDestroy->clientSite); - ptrToDestroy->clientSite = NULL; - } - - /* - * And the advise holder. - */ - if (ptrToDestroy->oleAdviseHolder!=NULL) - { - IOleAdviseHolder_Release(ptrToDestroy->oleAdviseHolder); - ptrToDestroy->oleAdviseHolder = NULL; - } - - /* - * And the data advise holder. - */ - if (ptrToDestroy->dataAdviseHolder!=NULL) - { - IDataAdviseHolder_Release(ptrToDestroy->dataAdviseHolder); - ptrToDestroy->dataAdviseHolder = NULL; - } - - - /* - * Free the actual default handler structure. - */ - HeapFree(GetProcessHeap(), 0, ptrToDestroy); -} - -/********************************************************* - * Method implementation for the non delegating IUnknown - * part of the DefaultHandler class. - */ - -/************************************************************************ - * DefaultHandler_NDIUnknown_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - * - * This version of QueryInterface will not delegate it's implementation - * to the outer unknown. - */ -static HRESULT WINAPI DefaultHandler_NDIUnknown_QueryInterface( - IUnknown* iface, - REFIID riid, - void** ppvObject) -{ - _ICOM_THIS_From_NDIUnknown(DefaultHandler, iface); - - /* - * Perform a sanity check on the parameters. - */ - if ( (this==0) || (ppvObject==0) ) - return E_INVALIDARG; - - /* - * Initialize the return parameter. - */ - *ppvObject = 0; - - /* - * Compare the riid with the interface IDs implemented by this object. - */ - if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) - { - *ppvObject = iface; - } - else if (memcmp(&IID_IOleObject, riid, sizeof(IID_IOleObject)) == 0) - { - *ppvObject = (IOleObject*)&(this->lpvtbl1); - } - else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0) - { - *ppvObject = (IDataObject*)&(this->lpvtbl3); - } - else if (memcmp(&IID_IRunnableObject, riid, sizeof(IID_IRunnableObject)) == 0) - { - *ppvObject = (IRunnableObject*)&(this->lpvtbl4); - } - else - { - /* - * Blind aggregate the data cache to "inherit" it's interfaces. - */ - if (IUnknown_QueryInterface(this->dataCache, riid, ppvObject) == S_OK) - return S_OK; - } - - /* - * Check that we obtained an interface. - */ - if ((*ppvObject)==0) - { - WARN( "() : asking for un supported interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; - } - - /* - * Query Interface always increases the reference count by one when it is - * successful. - */ - IUnknown_AddRef((IUnknown*)*ppvObject); - - return S_OK; -} - -/************************************************************************ - * DefaultHandler_NDIUnknown_AddRef (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - * - * This version of QueryInterface will not delegate it's implementation - * to the outer unknown. - */ -static ULONG WINAPI DefaultHandler_NDIUnknown_AddRef( - IUnknown* iface) -{ - _ICOM_THIS_From_NDIUnknown(DefaultHandler, iface); - return InterlockedIncrement(&this->ref); -} - -/************************************************************************ - * DefaultHandler_NDIUnknown_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - * - * This version of QueryInterface will not delegate it's implementation - * to the outer unknown. - */ -static ULONG WINAPI DefaultHandler_NDIUnknown_Release( - IUnknown* iface) -{ - _ICOM_THIS_From_NDIUnknown(DefaultHandler, iface); - ULONG ref; - - /* - * Decrease the reference count on this object. - */ - ref = InterlockedDecrement(&this->ref); - - /* - * If the reference count goes down to 0, perform suicide. - */ - if (ref == 0) DefaultHandler_Destroy(this); - - return ref; -} - -/********************************************************* - * Methods implementation for the IOleObject part of - * the DefaultHandler class. - */ - -/************************************************************************ - * DefaultHandler_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static HRESULT WINAPI DefaultHandler_QueryInterface( - IOleObject* iface, - REFIID riid, - void** ppvObject) -{ - _ICOM_THIS_From_IOleObject(DefaultHandler, iface); - - return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject); -} - -/************************************************************************ - * DefaultHandler_AddRef (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI DefaultHandler_AddRef( - IOleObject* iface) -{ - _ICOM_THIS_From_IOleObject(DefaultHandler, iface); - - return IUnknown_AddRef(this->outerUnknown); -} - -/************************************************************************ - * DefaultHandler_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI DefaultHandler_Release( - IOleObject* iface) -{ - _ICOM_THIS_From_IOleObject(DefaultHandler, iface); - - return IUnknown_Release(this->outerUnknown); -} - -/************************************************************************ - * DefaultHandler_SetClientSite (IOleObject) - * - * The default handler's implementation of this method only keeps the - * client site pointer for future reference. - * - * See Windows documentation for more details on IOleObject methods. - */ -static HRESULT WINAPI DefaultHandler_SetClientSite( - IOleObject* iface, - IOleClientSite* pClientSite) -{ - _ICOM_THIS_From_IOleObject(DefaultHandler, iface); - - TRACE("(%p, %p)\n", iface, pClientSite); - - /* - * Make sure we release the previous client site if there - * was one. - */ - if (this->clientSite!=NULL) - { - IOleClientSite_Release(this->clientSite); - } - - this->clientSite = pClientSite; - - if (this->clientSite!=NULL) - { - IOleClientSite_AddRef(this->clientSite); - } - - return S_OK; -} - -/************************************************************************ - * DefaultHandler_GetClientSite (IOleObject) - * - * The default handler's implementation of this method returns the - * last pointer set in IOleObject_SetClientSite. - * - * See Windows documentation for more details on IOleObject methods. - */ -static HRESULT WINAPI DefaultHandler_GetClientSite( - IOleObject* iface, - IOleClientSite** ppClientSite) -{ - _ICOM_THIS_From_IOleObject(DefaultHandler, iface); - - /* - * Sanity check. - */ - if (ppClientSite == NULL) - return E_POINTER; - - *ppClientSite = this->clientSite; - - if (this->clientSite != NULL) - { - IOleClientSite_AddRef(this->clientSite); - } - - return S_OK; -} - -/************************************************************************ - * DefaultHandler_SetHostNames (IOleObject) - * - * The default handler's implementation of this method just stores - * the strings and returns S_OK. - * - * See Windows documentation for more details on IOleObject methods. - */ -static HRESULT WINAPI DefaultHandler_SetHostNames( - IOleObject* iface, - LPCOLESTR szContainerApp, - LPCOLESTR szContainerObj) -{ - _ICOM_THIS_From_IOleObject(DefaultHandler, iface); - - TRACE("(%p, %s, %s)\n", - iface, - debugstr_w(szContainerApp), - debugstr_w(szContainerObj)); - - /* - * Be sure to cleanup before re-assinging the strings. - */ - HeapFree( GetProcessHeap(), 0, this->containerApp ); - this->containerApp = NULL; - HeapFree( GetProcessHeap(), 0, this->containerObj ); - this->containerObj = NULL; - - /* - * Copy the string supplied. - */ - if (szContainerApp != NULL) - { - if ((this->containerApp = HeapAlloc( GetProcessHeap(), 0, - (lstrlenW(szContainerApp) + 1) * sizeof(WCHAR) ))) - strcpyW( this->containerApp, szContainerApp ); - } - - if (szContainerObj != NULL) - { - if ((this->containerObj = HeapAlloc( GetProcessHeap(), 0, - (lstrlenW(szContainerObj) + 1) * sizeof(WCHAR) ))) - strcpyW( this->containerObj, szContainerObj ); - } - return S_OK; -} - -/************************************************************************ - * DefaultHandler_Close (IOleObject) - * - * The default handler's implementation of this method is meaningless - * without a running server so it does nothing. - * - * See Windows documentation for more details on IOleObject methods. - */ -static HRESULT WINAPI DefaultHandler_Close( - IOleObject* iface, - DWORD dwSaveOption) -{ - TRACE("()\n"); - return S_OK; -} - -/************************************************************************ - * DefaultHandler_SetMoniker (IOleObject) - * - * The default handler's implementation of this method does nothing. - * - * See Windows documentation for more details on IOleObject methods. - */ -static HRESULT WINAPI DefaultHandler_SetMoniker( - IOleObject* iface, - DWORD dwWhichMoniker, - IMoniker* pmk) -{ - TRACE("(%p, %ld, %p)\n", - iface, - dwWhichMoniker, - pmk); - - return S_OK; -} - -/************************************************************************ - * DefaultHandler_GetMoniker (IOleObject) - * - * Delegate this request to the client site if we have one. - * - * See Windows documentation for more details on IOleObject methods. - */ -static HRESULT WINAPI DefaultHandler_GetMoniker( - IOleObject* iface, - DWORD dwAssign, - DWORD dwWhichMoniker, - IMoniker** ppmk) -{ - _ICOM_THIS_From_IOleObject(DefaultHandler, iface); - - TRACE("(%p, %ld, %ld, %p)\n", - iface, dwAssign, dwWhichMoniker, ppmk); - - if (this->clientSite) - { - return IOleClientSite_GetMoniker(this->clientSite, - dwAssign, - dwWhichMoniker, - ppmk); - - } - - return E_FAIL; -} - -/************************************************************************ - * DefaultHandler_InitFromData (IOleObject) - * - * This method is meaningless if the server is not running - * - * See Windows documentation for more details on IOleObject methods. - */ -static HRESULT WINAPI DefaultHandler_InitFromData( - IOleObject* iface, - IDataObject* pDataObject, - BOOL fCreation, - DWORD dwReserved) -{ - TRACE("(%p, %p, %d, %ld)\n", - iface, pDataObject, fCreation, dwReserved); - - return OLE_E_NOTRUNNING; -} - -/************************************************************************ - * DefaultHandler_GetClipboardData (IOleObject) - * - * This method is meaningless if the server is not running - * - * See Windows documentation for more details on IOleObject methods. - */ -static HRESULT WINAPI DefaultHandler_GetClipboardData( - IOleObject* iface, - DWORD dwReserved, - IDataObject** ppDataObject) -{ - TRACE("(%p, %ld, %p)\n", - iface, dwReserved, ppDataObject); - - return OLE_E_NOTRUNNING; -} - -static HRESULT WINAPI DefaultHandler_DoVerb( - IOleObject* iface, - LONG iVerb, - struct tagMSG* lpmsg, - IOleClientSite* pActiveSite, - LONG lindex, - HWND hwndParent, - LPCRECT lprcPosRect) -{ - FIXME(": Stub\n"); - return E_NOTIMPL; -} - -/************************************************************************ - * DefaultHandler_EnumVerbs (IOleObject) - * - * The default handler implementation of this method simply delegates - * to OleRegEnumVerbs - * - * See Windows documentation for more details on IOleObject methods. - */ -static HRESULT WINAPI DefaultHandler_EnumVerbs( - IOleObject* iface, - IEnumOLEVERB** ppEnumOleVerb) -{ - _ICOM_THIS_From_IOleObject(DefaultHandler, iface); - - TRACE("(%p, %p)\n", iface, ppEnumOleVerb); - - return OleRegEnumVerbs(&this->clsid, ppEnumOleVerb); -} - -static HRESULT WINAPI DefaultHandler_Update( - IOleObject* iface) -{ - FIXME(": Stub\n"); - return E_NOTIMPL; -} - -/************************************************************************ - * DefaultHandler_IsUpToDate (IOleObject) - * - * This method is meaningless if the server is not running - * - * See Windows documentation for more details on IOleObject methods. - */ -static HRESULT WINAPI DefaultHandler_IsUpToDate( - IOleObject* iface) -{ - TRACE("(%p)\n", iface); - - return OLE_E_NOTRUNNING; -} - -/************************************************************************ - * DefaultHandler_GetUserClassID (IOleObject) - * - * TODO: Map to a new class ID if emulation is active. - * - * See Windows documentation for more details on IOleObject methods. - */ -static HRESULT WINAPI DefaultHandler_GetUserClassID( - IOleObject* iface, - CLSID* pClsid) -{ - _ICOM_THIS_From_IOleObject(DefaultHandler, iface); - - TRACE("(%p, %p)\n", iface, pClsid); - - /* - * Sanity check. - */ - if (pClsid==NULL) - return E_POINTER; - - memcpy(pClsid, &this->clsid, sizeof(CLSID)); - - return S_OK; -} - -/************************************************************************ - * DefaultHandler_GetUserType (IOleObject) - * - * The default handler implementation of this method simply delegates - * to OleRegGetUserType - * - * See Windows documentation for more details on IOleObject methods. - */ -static HRESULT WINAPI DefaultHandler_GetUserType( - IOleObject* iface, - DWORD dwFormOfType, - LPOLESTR* pszUserType) -{ - _ICOM_THIS_From_IOleObject(DefaultHandler, iface); - - TRACE("(%p, %ld, %p)\n", iface, dwFormOfType, pszUserType); - - return OleRegGetUserType(&this->clsid, dwFormOfType, pszUserType); -} - -/************************************************************************ - * DefaultHandler_SetExtent (IOleObject) - * - * This method is meaningless if the server is not running - * - * See Windows documentation for more details on IOleObject methods. - */ -static HRESULT WINAPI DefaultHandler_SetExtent( - IOleObject* iface, - DWORD dwDrawAspect, - SIZEL* psizel) -{ - TRACE("(%p, %lx, (%ld x %ld))\n", iface, - dwDrawAspect, psizel->cx, psizel->cy); - return OLE_E_NOTRUNNING; -} - -/************************************************************************ - * DefaultHandler_GetExtent (IOleObject) - * - * The default handler's implementation of this method returns uses - * the cache to locate the aspect and extract the extent from it. - * - * See Windows documentation for more details on IOleObject methods. - */ -static HRESULT WINAPI DefaultHandler_GetExtent( - IOleObject* iface, - DWORD dwDrawAspect, - SIZEL* psizel) -{ - DVTARGETDEVICE* targetDevice; - IViewObject2* cacheView = NULL; - HRESULT hres; - - _ICOM_THIS_From_IOleObject(DefaultHandler, iface); - - TRACE("(%p, %lx, %p)\n", iface, dwDrawAspect, psizel); - - hres = IUnknown_QueryInterface(this->dataCache, &IID_IViewObject2, (void**)&cacheView); - - if (FAILED(hres)) - return E_UNEXPECTED; - - /* - * Prepare the call to the cache's GetExtent method. - * - * Here we would build a valid DVTARGETDEVICE structure - * but, since we are calling into the data cache, we - * know it's implementation and we'll skip this - * extra work until later. - */ - targetDevice = NULL; - - hres = IViewObject2_GetExtent(cacheView, - dwDrawAspect, - -1, - targetDevice, - psizel); - - /* - * Cleanup - */ - IViewObject2_Release(cacheView); - - return hres; -} - -/************************************************************************ - * DefaultHandler_Advise (IOleObject) - * - * The default handler's implementation of this method simply - * delegates to the OleAdviseHolder. - * - * See Windows documentation for more details on IOleObject methods. - */ -static HRESULT WINAPI DefaultHandler_Advise( - IOleObject* iface, - IAdviseSink* pAdvSink, - DWORD* pdwConnection) -{ - HRESULT hres = S_OK; - _ICOM_THIS_From_IOleObject(DefaultHandler, iface); - - TRACE("(%p, %p, %p)\n", iface, pAdvSink, pdwConnection); - - /* - * Make sure we have an advise holder before we start. - */ - if (this->oleAdviseHolder==NULL) - { - hres = CreateOleAdviseHolder(&this->oleAdviseHolder); - } - - if (SUCCEEDED(hres)) - { - hres = IOleAdviseHolder_Advise(this->oleAdviseHolder, - pAdvSink, - pdwConnection); - } - - return hres; -} - -/************************************************************************ - * DefaultHandler_Unadvise (IOleObject) - * - * The default handler's implementation of this method simply - * delegates to the OleAdviseHolder. - * - * See Windows documentation for more details on IOleObject methods. - */ -static HRESULT WINAPI DefaultHandler_Unadvise( - IOleObject* iface, - DWORD dwConnection) -{ - _ICOM_THIS_From_IOleObject(DefaultHandler, iface); - - TRACE("(%p, %ld)\n", iface, dwConnection); - - /* - * If we don't have an advise holder yet, it means we don't have - * a connection. - */ - if (this->oleAdviseHolder==NULL) - return OLE_E_NOCONNECTION; - - return IOleAdviseHolder_Unadvise(this->oleAdviseHolder, - dwConnection); -} - -/************************************************************************ - * DefaultHandler_EnumAdvise (IOleObject) - * - * The default handler's implementation of this method simply - * delegates to the OleAdviseHolder. - * - * See Windows documentation for more details on IOleObject methods. - */ -static HRESULT WINAPI DefaultHandler_EnumAdvise( - IOleObject* iface, - IEnumSTATDATA** ppenumAdvise) -{ - _ICOM_THIS_From_IOleObject(DefaultHandler, iface); - - TRACE("(%p, %p)\n", iface, ppenumAdvise); - - /* - * Sanity check - */ - if (ppenumAdvise==NULL) - return E_POINTER; - - /* - * Initialize the out parameter. - */ - *ppenumAdvise = NULL; - - if (this->oleAdviseHolder==NULL) - return IOleAdviseHolder_EnumAdvise(this->oleAdviseHolder, - ppenumAdvise); - - return S_OK; -} - -/************************************************************************ - * DefaultHandler_GetMiscStatus (IOleObject) - * - * The default handler's implementation of this method simply delegates - * to OleRegGetMiscStatus. - * - * See Windows documentation for more details on IOleObject methods. - */ -static HRESULT WINAPI DefaultHandler_GetMiscStatus( - IOleObject* iface, - DWORD dwAspect, - DWORD* pdwStatus) -{ - HRESULT hres; - _ICOM_THIS_From_IOleObject(DefaultHandler, iface); - - TRACE("(%p, %lx, %p)\n", iface, dwAspect, pdwStatus); - - hres = OleRegGetMiscStatus(&(this->clsid), dwAspect, pdwStatus); - - if (FAILED(hres)) - *pdwStatus = 0; - - return S_OK; -} - -/************************************************************************ - * DefaultHandler_SetExtent (IOleObject) - * - * This method is meaningless if the server is not running - * - * See Windows documentation for more details on IOleObject methods. - */ -static HRESULT WINAPI DefaultHandler_SetColorScheme( - IOleObject* iface, - struct tagLOGPALETTE* pLogpal) -{ - TRACE("(%p, %p))\n", iface, pLogpal); - return OLE_E_NOTRUNNING; -} - -/********************************************************* - * Methods implementation for the IDataObject part of - * the DefaultHandler class. - */ - -/************************************************************************ - * DefaultHandler_IDataObject_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static HRESULT WINAPI DefaultHandler_IDataObject_QueryInterface( - IDataObject* iface, - REFIID riid, - void** ppvObject) -{ - _ICOM_THIS_From_IDataObject(DefaultHandler, iface); - - return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject); -} - -/************************************************************************ - * DefaultHandler_IDataObject_AddRef (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI DefaultHandler_IDataObject_AddRef( - IDataObject* iface) -{ - _ICOM_THIS_From_IDataObject(DefaultHandler, iface); - - return IUnknown_AddRef(this->outerUnknown); -} - -/************************************************************************ - * DefaultHandler_IDataObject_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI DefaultHandler_IDataObject_Release( - IDataObject* iface) -{ - _ICOM_THIS_From_IDataObject(DefaultHandler, iface); - - return IUnknown_Release(this->outerUnknown); -} - -/************************************************************************ - * DefaultHandler_GetData - * - * Get Data from a source dataobject using format pformatetcIn->cfFormat - * See Windows documentation for more details on GetData. - * Default handler's implementation of this method delegates to the cache. - */ -static HRESULT WINAPI DefaultHandler_GetData( - IDataObject* iface, - LPFORMATETC pformatetcIn, - STGMEDIUM* pmedium) -{ - IDataObject* cacheDataObject = NULL; - HRESULT hres; - - _ICOM_THIS_From_IDataObject(DefaultHandler, iface); - - TRACE("(%p, %p, %p)\n", iface, pformatetcIn, pmedium); - - hres = IUnknown_QueryInterface(this->dataCache, - &IID_IDataObject, - (void**)&cacheDataObject); - - if (FAILED(hres)) - return E_UNEXPECTED; - - hres = IDataObject_GetData(cacheDataObject, - pformatetcIn, - pmedium); - - IDataObject_Release(cacheDataObject); - - return hres; -} - -static HRESULT WINAPI DefaultHandler_GetDataHere( - IDataObject* iface, - LPFORMATETC pformatetc, - STGMEDIUM* pmedium) -{ - FIXME(": Stub\n"); - return E_NOTIMPL; -} - -/************************************************************************ - * DefaultHandler_QueryGetData (IDataObject) - * - * The default handler's implementation of this method delegates to - * the cache. - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI DefaultHandler_QueryGetData( - IDataObject* iface, - LPFORMATETC pformatetc) -{ - IDataObject* cacheDataObject = NULL; - HRESULT hres; - - _ICOM_THIS_From_IDataObject(DefaultHandler, iface); - - TRACE("(%p, %p)\n", iface, pformatetc); - - hres = IUnknown_QueryInterface(this->dataCache, - &IID_IDataObject, - (void**)&cacheDataObject); - - if (FAILED(hres)) - return E_UNEXPECTED; - - hres = IDataObject_QueryGetData(cacheDataObject, - pformatetc); - - IDataObject_Release(cacheDataObject); - - return hres; -} - -/************************************************************************ - * DefaultHandler_GetCanonicalFormatEtc (IDataObject) - * - * This method is meaningless if the server is not running - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI DefaultHandler_GetCanonicalFormatEtc( - IDataObject* iface, - LPFORMATETC pformatectIn, - LPFORMATETC pformatetcOut) -{ - FIXME("(%p, %p, %p)\n", iface, pformatectIn, pformatetcOut); - - return OLE_E_NOTRUNNING; -} - -/************************************************************************ - * DefaultHandler_SetData (IDataObject) - * - * The default handler's implementation of this method delegates to - * the cache. - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI DefaultHandler_SetData( - IDataObject* iface, - LPFORMATETC pformatetc, - STGMEDIUM* pmedium, - BOOL fRelease) -{ - IDataObject* cacheDataObject = NULL; - HRESULT hres; - - _ICOM_THIS_From_IDataObject(DefaultHandler, iface); - - TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease); - - hres = IUnknown_QueryInterface(this->dataCache, - &IID_IDataObject, - (void**)&cacheDataObject); - - if (FAILED(hres)) - return E_UNEXPECTED; - - hres = IDataObject_SetData(cacheDataObject, - pformatetc, - pmedium, - fRelease); - - IDataObject_Release(cacheDataObject); - - return hres; -} - -/************************************************************************ - * DefaultHandler_EnumFormatEtc (IDataObject) - * - * The default handler's implementation of this method simply delegates - * to OleRegEnumFormatEtc. - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI DefaultHandler_EnumFormatEtc( - IDataObject* iface, - DWORD dwDirection, - IEnumFORMATETC** ppenumFormatEtc) -{ - HRESULT hres; - _ICOM_THIS_From_IDataObject(DefaultHandler, iface); - - TRACE("(%p, %lx, %p)\n", iface, dwDirection, ppenumFormatEtc); - - hres = OleRegEnumFormatEtc(&(this->clsid), dwDirection, ppenumFormatEtc); - - return hres; -} - -/************************************************************************ - * DefaultHandler_DAdvise (IDataObject) - * - * The default handler's implementation of this method simply - * delegates to the DataAdviseHolder. - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI DefaultHandler_DAdvise( - IDataObject* iface, - FORMATETC* pformatetc, - DWORD advf, - IAdviseSink* pAdvSink, - DWORD* pdwConnection) -{ - HRESULT hres = S_OK; - _ICOM_THIS_From_IDataObject(DefaultHandler, iface); - - TRACE("(%p, %p, %ld, %p, %p)\n", - iface, pformatetc, advf, pAdvSink, pdwConnection); - - /* - * Make sure we have a data advise holder before we start. - */ - if (this->dataAdviseHolder==NULL) - { - hres = CreateDataAdviseHolder(&this->dataAdviseHolder); - } - - if (SUCCEEDED(hres)) - { - hres = IDataAdviseHolder_Advise(this->dataAdviseHolder, - iface, - pformatetc, - advf, - pAdvSink, - pdwConnection); - } - - return hres; -} - -/************************************************************************ - * DefaultHandler_DUnadvise (IDataObject) - * - * The default handler's implementation of this method simply - * delegates to the DataAdviseHolder. - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI DefaultHandler_DUnadvise( - IDataObject* iface, - DWORD dwConnection) -{ - _ICOM_THIS_From_IDataObject(DefaultHandler, iface); - - TRACE("(%p, %ld)\n", iface, dwConnection); - - /* - * If we don't have a data advise holder yet, it means that - * we don't have any connections.. - */ - if (this->dataAdviseHolder==NULL) - { - return OLE_E_NOCONNECTION; - } - - return IDataAdviseHolder_Unadvise(this->dataAdviseHolder, - dwConnection); -} - -/************************************************************************ - * DefaultHandler_EnumDAdvise (IDataObject) - * - * The default handler's implementation of this method simply - * delegates to the DataAdviseHolder. - * - * See Windows documentation for more details on IDataObject methods. - */ -static HRESULT WINAPI DefaultHandler_EnumDAdvise( - IDataObject* iface, - IEnumSTATDATA** ppenumAdvise) -{ - _ICOM_THIS_From_IDataObject(DefaultHandler, iface); - - TRACE("(%p, %p)\n", iface, ppenumAdvise); - - /* - * Sanity check - */ - if (ppenumAdvise == NULL) - return E_POINTER; - - /* - * Initialize the out parameter. - */ - *ppenumAdvise = NULL; - - /* - * If we have a data advise holder object, delegate. - */ - if (this->dataAdviseHolder!=NULL) - { - return IDataAdviseHolder_EnumAdvise(this->dataAdviseHolder, - ppenumAdvise); - } - - return S_OK; -} - -/********************************************************* - * Methods implementation for the IRunnableObject part - * of the DefaultHandler class. - */ - -/************************************************************************ - * DefaultHandler_IRunnableObject_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static HRESULT WINAPI DefaultHandler_IRunnableObject_QueryInterface( - IRunnableObject* iface, - REFIID riid, - void** ppvObject) -{ - _ICOM_THIS_From_IRunnableObject(DefaultHandler, iface); - - return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject); -} - -/************************************************************************ - * DefaultHandler_IRunnableObject_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI DefaultHandler_IRunnableObject_AddRef( - IRunnableObject* iface) -{ - _ICOM_THIS_From_IRunnableObject(DefaultHandler, iface); - - return IUnknown_AddRef(this->outerUnknown); -} - -/************************************************************************ - * DefaultHandler_IRunnableObject_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI DefaultHandler_IRunnableObject_Release( - IRunnableObject* iface) -{ - _ICOM_THIS_From_IRunnableObject(DefaultHandler, iface); - - return IUnknown_Release(this->outerUnknown); -} - -/************************************************************************ - * DefaultHandler_GetRunningClass (IRunnableObject) - * - * According to Brockscmidt, Chapter 19, the default handler's - * implementation of IRunnableobject does nothing until the object - * is actually running. - * - * See Windows documentation for more details on IRunnableObject methods. - */ -static HRESULT WINAPI DefaultHandler_GetRunningClass( - IRunnableObject* iface, - LPCLSID lpClsid) -{ - TRACE("()\n"); - return S_OK; -} - -static HRESULT WINAPI DefaultHandler_Run( - IRunnableObject* iface, - IBindCtx* pbc) -{ - FIXME(": Stub\n"); - return E_NOTIMPL; -} - -/************************************************************************ - * DefaultHandler_IsRunning (IRunnableObject) - * - * According to Brockscmidt, Chapter 19, the default handler's - * implementation of IRunnableobject does nothing until the object - * is actually running. - * - * See Windows documentation for more details on IRunnableObject methods. - */ -static BOOL WINAPI DefaultHandler_IsRunning( - IRunnableObject* iface) -{ - TRACE("()\n"); - return S_FALSE; -} - -/************************************************************************ - * DefaultHandler_LockRunning (IRunnableObject) - * - * According to Brockscmidt, Chapter 19, the default handler's - * implementation of IRunnableobject does nothing until the object - * is actually running. - * - * See Windows documentation for more details on IRunnableObject methods. - */ -static HRESULT WINAPI DefaultHandler_LockRunning( - IRunnableObject* iface, - BOOL fLock, - BOOL fLastUnlockCloses) -{ - TRACE("()\n"); - return S_OK; -} - -/************************************************************************ - * DefaultHandler_SetContainedObject (IRunnableObject) - * - * According to Brockscmidt, Chapter 19, the default handler's - * implementation of IRunnableobject does nothing until the object - * is actually running. - * - * See Windows documentation for more details on IRunnableObject methods. - */ -static HRESULT WINAPI DefaultHandler_SetContainedObject( - IRunnableObject* iface, - BOOL fContained) -{ - TRACE("()\n"); - return S_OK; -} +/* + * OLE 2 default object handler + * + * Copyright 1999 Francis Beaudet + * Copyright 2000 Abey George + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES: + * The OLE2 default object handler supports a whole whack of + * interfaces including: + * IOleObject, IDataObject, IPersistStorage, IViewObject2, + * IRunnableObject, IOleCache2, IOleCacheControl and much more. + * + * All the implementation details are taken from: Inside OLE + * second edition by Kraig Brockschmidt, + * + * TODO + * - This implementation of the default handler does not launch the + * server in the DoVerb, Update, GetData, GetDataHere and Run + * methods. When it is fixed to do so, all the methods will have + * to be revisited to allow delegating to the running object + * + * - All methods in the class that use the class ID should be + * aware that it is possible for a class to be treated as + * another one and go into emulation mode. Nothing has been + * done in this area. + * + * - Some functions still return E_NOTIMPL they have to be + * implemented. Most of those are related to the running of the + * actual server. + * + * - All the methods related to notification and advise sinks are + * in place but no notifications are sent to the sinks yet. + */ +#include <assert.h> +#include <stdarg.h> +#include <string.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winerror.h" +#include "wine/unicode.h" +#include "ole2.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/**************************************************************************** + * DefaultHandler + * + */ +struct DefaultHandler +{ + /* + * List all interface VTables here + */ + IOleObjectVtbl* lpvtbl1; + IUnknownVtbl* lpvtbl2; + IDataObjectVtbl* lpvtbl3; + IRunnableObjectVtbl* lpvtbl4; + + /* + * Reference count of this object + */ + ULONG ref; + + /* + * IUnknown implementation of the outer object. + */ + IUnknown* outerUnknown; + + /* + * Class Id that this handler object represents. + */ + CLSID clsid; + + /* + * IUnknown implementation of the datacache. + */ + IUnknown* dataCache; + + /* + * Client site for the embedded object. + */ + IOleClientSite* clientSite; + + /* + * The IOleAdviseHolder maintains the connections + * on behalf of the default handler. + */ + IOleAdviseHolder* oleAdviseHolder; + + /* + * The IDataAdviseHolder maintains the data + * connections on behalf of the default handler. + */ + IDataAdviseHolder* dataAdviseHolder; + + /* + * Name of the container and object contained + */ + LPWSTR containerApp; + LPWSTR containerObj; + +}; + +typedef struct DefaultHandler DefaultHandler; + +/* + * Here, I define utility macros to help with the casting of the + * "this" parameter. + * There is a version to accommodate all of the VTables implemented + * by this object. + */ +#define _ICOM_THIS_From_IOleObject(class,name) class* this = (class*)name +#define _ICOM_THIS_From_NDIUnknown(class, name) class* this = (class*)(((char*)name)-sizeof(void*)) +#define _ICOM_THIS_From_IDataObject(class, name) class* this = (class*)(((char*)name)-2*sizeof(void*)) +#define _ICOM_THIS_From_IRunnableObject(class, name) class* this = (class*)(((char*)name)-3*sizeof(void*)) + +/* + * Prototypes for the methods of the DefaultHandler class. + */ +static DefaultHandler* DefaultHandler_Construct(REFCLSID clsid, + LPUNKNOWN pUnkOuter); +static void DefaultHandler_Destroy(DefaultHandler* ptrToDestroy); + +/* + * Prototypes for the methods of the DefaultHandler class + * that implement non delegating IUnknown methods. + */ +static HRESULT WINAPI DefaultHandler_NDIUnknown_QueryInterface( + IUnknown* iface, + REFIID riid, + void** ppvObject); +static ULONG WINAPI DefaultHandler_NDIUnknown_AddRef( + IUnknown* iface); +static ULONG WINAPI DefaultHandler_NDIUnknown_Release( + IUnknown* iface); + +/* + * Prototypes for the methods of the DefaultHandler class + * that implement IOleObject methods. + */ +static HRESULT WINAPI DefaultHandler_QueryInterface( + IOleObject* iface, + REFIID riid, + void** ppvObject); +static ULONG WINAPI DefaultHandler_AddRef( + IOleObject* iface); +static ULONG WINAPI DefaultHandler_Release( + IOleObject* iface); +static HRESULT WINAPI DefaultHandler_SetClientSite( + IOleObject* iface, + IOleClientSite* pClientSite); +static HRESULT WINAPI DefaultHandler_GetClientSite( + IOleObject* iface, + IOleClientSite** ppClientSite); +static HRESULT WINAPI DefaultHandler_SetHostNames( + IOleObject* iface, + LPCOLESTR szContainerApp, + LPCOLESTR szContainerObj); +static HRESULT WINAPI DefaultHandler_Close( + IOleObject* iface, + DWORD dwSaveOption); +static HRESULT WINAPI DefaultHandler_SetMoniker( + IOleObject* iface, + DWORD dwWhichMoniker, + IMoniker* pmk); +static HRESULT WINAPI DefaultHandler_GetMoniker( + IOleObject* iface, + DWORD dwAssign, + DWORD dwWhichMoniker, + IMoniker** ppmk); +static HRESULT WINAPI DefaultHandler_InitFromData( + IOleObject* iface, + IDataObject* pDataObject, + BOOL fCreation, + DWORD dwReserved); +static HRESULT WINAPI DefaultHandler_GetClipboardData( + IOleObject* iface, + DWORD dwReserved, + IDataObject** ppDataObject); +static HRESULT WINAPI DefaultHandler_DoVerb( + IOleObject* iface, + LONG iVerb, + struct tagMSG* lpmsg, + IOleClientSite* pActiveSite, + LONG lindex, + HWND hwndParent, + LPCRECT lprcPosRect); +static HRESULT WINAPI DefaultHandler_EnumVerbs( + IOleObject* iface, + IEnumOLEVERB** ppEnumOleVerb); +static HRESULT WINAPI DefaultHandler_Update( + IOleObject* iface); +static HRESULT WINAPI DefaultHandler_IsUpToDate( + IOleObject* iface); +static HRESULT WINAPI DefaultHandler_GetUserClassID( + IOleObject* iface, + CLSID* pClsid); +static HRESULT WINAPI DefaultHandler_GetUserType( + IOleObject* iface, + DWORD dwFormOfType, + LPOLESTR* pszUserType); +static HRESULT WINAPI DefaultHandler_SetExtent( + IOleObject* iface, + DWORD dwDrawAspect, + SIZEL* psizel); +static HRESULT WINAPI DefaultHandler_GetExtent( + IOleObject* iface, + DWORD dwDrawAspect, + SIZEL* psizel); +static HRESULT WINAPI DefaultHandler_Advise( + IOleObject* iface, + IAdviseSink* pAdvSink, + DWORD* pdwConnection); +static HRESULT WINAPI DefaultHandler_Unadvise( + IOleObject* iface, + DWORD dwConnection); +static HRESULT WINAPI DefaultHandler_EnumAdvise( + IOleObject* iface, + IEnumSTATDATA** ppenumAdvise); +static HRESULT WINAPI DefaultHandler_GetMiscStatus( + IOleObject* iface, + DWORD dwAspect, + DWORD* pdwStatus); +static HRESULT WINAPI DefaultHandler_SetColorScheme( + IOleObject* iface, + struct tagLOGPALETTE* pLogpal); + +/* + * Prototypes for the methods of the DefaultHandler class + * that implement IDataObject methods. + */ +static HRESULT WINAPI DefaultHandler_IDataObject_QueryInterface( + IDataObject* iface, + REFIID riid, + void** ppvObject); +static ULONG WINAPI DefaultHandler_IDataObject_AddRef( + IDataObject* iface); +static ULONG WINAPI DefaultHandler_IDataObject_Release( + IDataObject* iface); +static HRESULT WINAPI DefaultHandler_GetData( + IDataObject* iface, + LPFORMATETC pformatetcIn, + STGMEDIUM* pmedium); +static HRESULT WINAPI DefaultHandler_GetDataHere( + IDataObject* iface, + LPFORMATETC pformatetc, + STGMEDIUM* pmedium); +static HRESULT WINAPI DefaultHandler_QueryGetData( + IDataObject* iface, + LPFORMATETC pformatetc); +static HRESULT WINAPI DefaultHandler_GetCanonicalFormatEtc( + IDataObject* iface, + LPFORMATETC pformatectIn, + LPFORMATETC pformatetcOut); +static HRESULT WINAPI DefaultHandler_SetData( + IDataObject* iface, + LPFORMATETC pformatetc, + STGMEDIUM* pmedium, + BOOL fRelease); +static HRESULT WINAPI DefaultHandler_EnumFormatEtc( + IDataObject* iface, + DWORD dwDirection, + IEnumFORMATETC** ppenumFormatEtc); +static HRESULT WINAPI DefaultHandler_DAdvise( + IDataObject* iface, + FORMATETC* pformatetc, + DWORD advf, + IAdviseSink* pAdvSink, + DWORD* pdwConnection); +static HRESULT WINAPI DefaultHandler_DUnadvise( + IDataObject* iface, + DWORD dwConnection); +static HRESULT WINAPI DefaultHandler_EnumDAdvise( + IDataObject* iface, + IEnumSTATDATA** ppenumAdvise); + +/* + * Prototypes for the methods of the DefaultHandler class + * that implement IRunnableObject methods. + */ +static HRESULT WINAPI DefaultHandler_IRunnableObject_QueryInterface( + IRunnableObject* iface, + REFIID riid, + void** ppvObject); +static ULONG WINAPI DefaultHandler_IRunnableObject_AddRef( + IRunnableObject* iface); +static ULONG WINAPI DefaultHandler_IRunnableObject_Release( + IRunnableObject* iface); +static HRESULT WINAPI DefaultHandler_GetRunningClass( + IRunnableObject* iface, + LPCLSID lpClsid); +static HRESULT WINAPI DefaultHandler_Run( + IRunnableObject* iface, + IBindCtx* pbc); +static BOOL WINAPI DefaultHandler_IsRunning( + IRunnableObject* iface); +static HRESULT WINAPI DefaultHandler_LockRunning( + IRunnableObject* iface, + BOOL fLock, + BOOL fLastUnlockCloses); +static HRESULT WINAPI DefaultHandler_SetContainedObject( + IRunnableObject* iface, + BOOL fContained); + + +/* + * Virtual function tables for the DefaultHandler class. + */ +static IOleObjectVtbl DefaultHandler_IOleObject_VTable = +{ + DefaultHandler_QueryInterface, + DefaultHandler_AddRef, + DefaultHandler_Release, + DefaultHandler_SetClientSite, + DefaultHandler_GetClientSite, + DefaultHandler_SetHostNames, + DefaultHandler_Close, + DefaultHandler_SetMoniker, + DefaultHandler_GetMoniker, + DefaultHandler_InitFromData, + DefaultHandler_GetClipboardData, + DefaultHandler_DoVerb, + DefaultHandler_EnumVerbs, + DefaultHandler_Update, + DefaultHandler_IsUpToDate, + DefaultHandler_GetUserClassID, + DefaultHandler_GetUserType, + DefaultHandler_SetExtent, + DefaultHandler_GetExtent, + DefaultHandler_Advise, + DefaultHandler_Unadvise, + DefaultHandler_EnumAdvise, + DefaultHandler_GetMiscStatus, + DefaultHandler_SetColorScheme +}; + +static IUnknownVtbl DefaultHandler_NDIUnknown_VTable = +{ + DefaultHandler_NDIUnknown_QueryInterface, + DefaultHandler_NDIUnknown_AddRef, + DefaultHandler_NDIUnknown_Release, +}; + +static IDataObjectVtbl DefaultHandler_IDataObject_VTable = +{ + DefaultHandler_IDataObject_QueryInterface, + DefaultHandler_IDataObject_AddRef, + DefaultHandler_IDataObject_Release, + DefaultHandler_GetData, + DefaultHandler_GetDataHere, + DefaultHandler_QueryGetData, + DefaultHandler_GetCanonicalFormatEtc, + DefaultHandler_SetData, + DefaultHandler_EnumFormatEtc, + DefaultHandler_DAdvise, + DefaultHandler_DUnadvise, + DefaultHandler_EnumDAdvise +}; + +static IRunnableObjectVtbl DefaultHandler_IRunnableObject_VTable = +{ + DefaultHandler_IRunnableObject_QueryInterface, + DefaultHandler_IRunnableObject_AddRef, + DefaultHandler_IRunnableObject_Release, + DefaultHandler_GetRunningClass, + DefaultHandler_Run, + DefaultHandler_IsRunning, + DefaultHandler_LockRunning, + DefaultHandler_SetContainedObject +}; + +/****************************************************************************** + * OleCreateDefaultHandler [OLE32.@] + */ +HRESULT WINAPI OleCreateDefaultHandler( + REFCLSID clsid, + LPUNKNOWN pUnkOuter, + REFIID riid, + LPVOID* ppvObj) +{ + DefaultHandler* newHandler = NULL; + HRESULT hr = S_OK; + + TRACE("(%s, %p, %s, %p)\n", debugstr_guid(clsid), pUnkOuter, debugstr_guid(riid), ppvObj); + + /* + * Sanity check + */ + if (ppvObj==0) + return E_POINTER; + + *ppvObj = 0; + + /* + * If this handler is constructed for aggregation, make sure + * the caller is requesting the IUnknown interface. + * This is necessary because it's the only time the non-delegating + * IUnknown pointer can be returned to the outside. + */ + if ( (pUnkOuter!=NULL) && + (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) != 0) ) + return CLASS_E_NOAGGREGATION; + + /* + * Try to construct a new instance of the class. + */ + newHandler = DefaultHandler_Construct(clsid, + pUnkOuter); + + if (newHandler == 0) + return E_OUTOFMEMORY; + + /* + * Make sure it supports the interface required by the caller. + */ + hr = IUnknown_QueryInterface((IUnknown*)&(newHandler->lpvtbl2), riid, ppvObj); + + /* + * Release the reference obtained in the constructor. If + * the QueryInterface was unsuccessful, it will free the class. + */ + IUnknown_Release((IUnknown*)&(newHandler->lpvtbl2)); + + return hr; +} + +/********************************************************* + * Methods implementation for the DefaultHandler class. + */ +static DefaultHandler* DefaultHandler_Construct( + REFCLSID clsid, + LPUNKNOWN pUnkOuter) +{ + DefaultHandler* newObject = 0; + + /* + * Allocate space for the object. + */ + newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(DefaultHandler)); + + if (newObject==0) + return newObject; + + /* + * Initialize the virtual function table. + */ + newObject->lpvtbl1 = &DefaultHandler_IOleObject_VTable; + newObject->lpvtbl2 = &DefaultHandler_NDIUnknown_VTable; + newObject->lpvtbl3 = &DefaultHandler_IDataObject_VTable; + newObject->lpvtbl4 = &DefaultHandler_IRunnableObject_VTable; + + /* + * Start with one reference count. The caller of this function + * must release the interface pointer when it is done. + */ + newObject->ref = 1; + + /* + * Initialize the outer unknown + * We don't keep a reference on the outer unknown since, the way + * aggregation works, our lifetime is at least as large as it's + * lifetime. + */ + if (pUnkOuter==NULL) + pUnkOuter = (IUnknown*)&(newObject->lpvtbl2); + + newObject->outerUnknown = pUnkOuter; + + /* + * Create a datacache object. + * We aggregate with the datacache. Make sure we pass our outer + * unknown as the datacache's outer unknown. + */ + CreateDataCache(newObject->outerUnknown, + clsid, + &IID_IUnknown, + (void**)&newObject->dataCache); + + /* + * Initialize the other data members of the class. + */ + memcpy(&(newObject->clsid), clsid, sizeof(CLSID)); + newObject->clientSite = NULL; + newObject->oleAdviseHolder = NULL; + newObject->dataAdviseHolder = NULL; + newObject->containerApp = NULL; + newObject->containerObj = NULL; + + return newObject; +} + +static void DefaultHandler_Destroy( + DefaultHandler* ptrToDestroy) +{ + /* + * Free the strings idenfitying the object + */ + HeapFree( GetProcessHeap(), 0, ptrToDestroy->containerApp ); + ptrToDestroy->containerApp = NULL; + HeapFree( GetProcessHeap(), 0, ptrToDestroy->containerObj ); + ptrToDestroy->containerObj = NULL; + + /* + * Release our reference to the data cache. + */ + if (ptrToDestroy->dataCache!=NULL) + { + IUnknown_Release(ptrToDestroy->dataCache); + ptrToDestroy->dataCache = NULL; + } + + /* + * Same thing for the client site. + */ + if (ptrToDestroy->clientSite!=NULL) + { + IOleClientSite_Release(ptrToDestroy->clientSite); + ptrToDestroy->clientSite = NULL; + } + + /* + * And the advise holder. + */ + if (ptrToDestroy->oleAdviseHolder!=NULL) + { + IOleAdviseHolder_Release(ptrToDestroy->oleAdviseHolder); + ptrToDestroy->oleAdviseHolder = NULL; + } + + /* + * And the data advise holder. + */ + if (ptrToDestroy->dataAdviseHolder!=NULL) + { + IDataAdviseHolder_Release(ptrToDestroy->dataAdviseHolder); + ptrToDestroy->dataAdviseHolder = NULL; + } + + + /* + * Free the actual default handler structure. + */ + HeapFree(GetProcessHeap(), 0, ptrToDestroy); +} + +/********************************************************* + * Method implementation for the non delegating IUnknown + * part of the DefaultHandler class. + */ + +/************************************************************************ + * DefaultHandler_NDIUnknown_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + * + * This version of QueryInterface will not delegate it's implementation + * to the outer unknown. + */ +static HRESULT WINAPI DefaultHandler_NDIUnknown_QueryInterface( + IUnknown* iface, + REFIID riid, + void** ppvObject) +{ + _ICOM_THIS_From_NDIUnknown(DefaultHandler, iface); + + /* + * Perform a sanity check on the parameters. + */ + if ( (this==0) || (ppvObject==0) ) + return E_INVALIDARG; + + /* + * Initialize the return parameter. + */ + *ppvObject = 0; + + /* + * Compare the riid with the interface IDs implemented by this object. + */ + if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) + { + *ppvObject = iface; + } + else if (memcmp(&IID_IOleObject, riid, sizeof(IID_IOleObject)) == 0) + { + *ppvObject = (IOleObject*)&(this->lpvtbl1); + } + else if (memcmp(&IID_IDataObject, riid, sizeof(IID_IDataObject)) == 0) + { + *ppvObject = (IDataObject*)&(this->lpvtbl3); + } + else if (memcmp(&IID_IRunnableObject, riid, sizeof(IID_IRunnableObject)) == 0) + { + *ppvObject = (IRunnableObject*)&(this->lpvtbl4); + } + else + { + /* + * Blind aggregate the data cache to "inherit" it's interfaces. + */ + if (IUnknown_QueryInterface(this->dataCache, riid, ppvObject) == S_OK) + return S_OK; + } + + /* + * Check that we obtained an interface. + */ + if ((*ppvObject)==0) + { + WARN( "() : asking for un supported interface %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; + } + + /* + * Query Interface always increases the reference count by one when it is + * successful. + */ + IUnknown_AddRef((IUnknown*)*ppvObject); + + return S_OK; +} + +/************************************************************************ + * DefaultHandler_NDIUnknown_AddRef (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + * + * This version of QueryInterface will not delegate it's implementation + * to the outer unknown. + */ +static ULONG WINAPI DefaultHandler_NDIUnknown_AddRef( + IUnknown* iface) +{ + _ICOM_THIS_From_NDIUnknown(DefaultHandler, iface); + return InterlockedIncrement(&this->ref); +} + +/************************************************************************ + * DefaultHandler_NDIUnknown_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + * + * This version of QueryInterface will not delegate it's implementation + * to the outer unknown. + */ +static ULONG WINAPI DefaultHandler_NDIUnknown_Release( + IUnknown* iface) +{ + _ICOM_THIS_From_NDIUnknown(DefaultHandler, iface); + ULONG ref; + + /* + * Decrease the reference count on this object. + */ + ref = InterlockedDecrement(&this->ref); + + /* + * If the reference count goes down to 0, perform suicide. + */ + if (ref == 0) DefaultHandler_Destroy(this); + + return ref; +} + +/********************************************************* + * Methods implementation for the IOleObject part of + * the DefaultHandler class. + */ + +/************************************************************************ + * DefaultHandler_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static HRESULT WINAPI DefaultHandler_QueryInterface( + IOleObject* iface, + REFIID riid, + void** ppvObject) +{ + _ICOM_THIS_From_IOleObject(DefaultHandler, iface); + + return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject); +} + +/************************************************************************ + * DefaultHandler_AddRef (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI DefaultHandler_AddRef( + IOleObject* iface) +{ + _ICOM_THIS_From_IOleObject(DefaultHandler, iface); + + return IUnknown_AddRef(this->outerUnknown); +} + +/************************************************************************ + * DefaultHandler_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI DefaultHandler_Release( + IOleObject* iface) +{ + _ICOM_THIS_From_IOleObject(DefaultHandler, iface); + + return IUnknown_Release(this->outerUnknown); +} + +/************************************************************************ + * DefaultHandler_SetClientSite (IOleObject) + * + * The default handler's implementation of this method only keeps the + * client site pointer for future reference. + * + * See Windows documentation for more details on IOleObject methods. + */ +static HRESULT WINAPI DefaultHandler_SetClientSite( + IOleObject* iface, + IOleClientSite* pClientSite) +{ + _ICOM_THIS_From_IOleObject(DefaultHandler, iface); + + TRACE("(%p, %p)\n", iface, pClientSite); + + /* + * Make sure we release the previous client site if there + * was one. + */ + if (this->clientSite!=NULL) + { + IOleClientSite_Release(this->clientSite); + } + + this->clientSite = pClientSite; + + if (this->clientSite!=NULL) + { + IOleClientSite_AddRef(this->clientSite); + } + + return S_OK; +} + +/************************************************************************ + * DefaultHandler_GetClientSite (IOleObject) + * + * The default handler's implementation of this method returns the + * last pointer set in IOleObject_SetClientSite. + * + * See Windows documentation for more details on IOleObject methods. + */ +static HRESULT WINAPI DefaultHandler_GetClientSite( + IOleObject* iface, + IOleClientSite** ppClientSite) +{ + _ICOM_THIS_From_IOleObject(DefaultHandler, iface); + + /* + * Sanity check. + */ + if (ppClientSite == NULL) + return E_POINTER; + + *ppClientSite = this->clientSite; + + if (this->clientSite != NULL) + { + IOleClientSite_AddRef(this->clientSite); + } + + return S_OK; +} + +/************************************************************************ + * DefaultHandler_SetHostNames (IOleObject) + * + * The default handler's implementation of this method just stores + * the strings and returns S_OK. + * + * See Windows documentation for more details on IOleObject methods. + */ +static HRESULT WINAPI DefaultHandler_SetHostNames( + IOleObject* iface, + LPCOLESTR szContainerApp, + LPCOLESTR szContainerObj) +{ + _ICOM_THIS_From_IOleObject(DefaultHandler, iface); + + TRACE("(%p, %s, %s)\n", + iface, + debugstr_w(szContainerApp), + debugstr_w(szContainerObj)); + + /* + * Be sure to cleanup before re-assinging the strings. + */ + HeapFree( GetProcessHeap(), 0, this->containerApp ); + this->containerApp = NULL; + HeapFree( GetProcessHeap(), 0, this->containerObj ); + this->containerObj = NULL; + + /* + * Copy the string supplied. + */ + if (szContainerApp != NULL) + { + if ((this->containerApp = HeapAlloc( GetProcessHeap(), 0, + (lstrlenW(szContainerApp) + 1) * sizeof(WCHAR) ))) + strcpyW( this->containerApp, szContainerApp ); + } + + if (szContainerObj != NULL) + { + if ((this->containerObj = HeapAlloc( GetProcessHeap(), 0, + (lstrlenW(szContainerObj) + 1) * sizeof(WCHAR) ))) + strcpyW( this->containerObj, szContainerObj ); + } + return S_OK; +} + +/************************************************************************ + * DefaultHandler_Close (IOleObject) + * + * The default handler's implementation of this method is meaningless + * without a running server so it does nothing. + * + * See Windows documentation for more details on IOleObject methods. + */ +static HRESULT WINAPI DefaultHandler_Close( + IOleObject* iface, + DWORD dwSaveOption) +{ + TRACE("()\n"); + return S_OK; +} + +/************************************************************************ + * DefaultHandler_SetMoniker (IOleObject) + * + * The default handler's implementation of this method does nothing. + * + * See Windows documentation for more details on IOleObject methods. + */ +static HRESULT WINAPI DefaultHandler_SetMoniker( + IOleObject* iface, + DWORD dwWhichMoniker, + IMoniker* pmk) +{ + TRACE("(%p, %ld, %p)\n", + iface, + dwWhichMoniker, + pmk); + + return S_OK; +} + +/************************************************************************ + * DefaultHandler_GetMoniker (IOleObject) + * + * Delegate this request to the client site if we have one. + * + * See Windows documentation for more details on IOleObject methods. + */ +static HRESULT WINAPI DefaultHandler_GetMoniker( + IOleObject* iface, + DWORD dwAssign, + DWORD dwWhichMoniker, + IMoniker** ppmk) +{ + _ICOM_THIS_From_IOleObject(DefaultHandler, iface); + + TRACE("(%p, %ld, %ld, %p)\n", + iface, dwAssign, dwWhichMoniker, ppmk); + + if (this->clientSite) + { + return IOleClientSite_GetMoniker(this->clientSite, + dwAssign, + dwWhichMoniker, + ppmk); + + } + + return E_FAIL; +} + +/************************************************************************ + * DefaultHandler_InitFromData (IOleObject) + * + * This method is meaningless if the server is not running + * + * See Windows documentation for more details on IOleObject methods. + */ +static HRESULT WINAPI DefaultHandler_InitFromData( + IOleObject* iface, + IDataObject* pDataObject, + BOOL fCreation, + DWORD dwReserved) +{ + TRACE("(%p, %p, %d, %ld)\n", + iface, pDataObject, fCreation, dwReserved); + + return OLE_E_NOTRUNNING; +} + +/************************************************************************ + * DefaultHandler_GetClipboardData (IOleObject) + * + * This method is meaningless if the server is not running + * + * See Windows documentation for more details on IOleObject methods. + */ +static HRESULT WINAPI DefaultHandler_GetClipboardData( + IOleObject* iface, + DWORD dwReserved, + IDataObject** ppDataObject) +{ + TRACE("(%p, %ld, %p)\n", + iface, dwReserved, ppDataObject); + + return OLE_E_NOTRUNNING; +} + +static HRESULT WINAPI DefaultHandler_DoVerb( + IOleObject* iface, + LONG iVerb, + struct tagMSG* lpmsg, + IOleClientSite* pActiveSite, + LONG lindex, + HWND hwndParent, + LPCRECT lprcPosRect) +{ + FIXME(": Stub\n"); + return E_NOTIMPL; +} + +/************************************************************************ + * DefaultHandler_EnumVerbs (IOleObject) + * + * The default handler implementation of this method simply delegates + * to OleRegEnumVerbs + * + * See Windows documentation for more details on IOleObject methods. + */ +static HRESULT WINAPI DefaultHandler_EnumVerbs( + IOleObject* iface, + IEnumOLEVERB** ppEnumOleVerb) +{ + _ICOM_THIS_From_IOleObject(DefaultHandler, iface); + + TRACE("(%p, %p)\n", iface, ppEnumOleVerb); + + return OleRegEnumVerbs(&this->clsid, ppEnumOleVerb); +} + +static HRESULT WINAPI DefaultHandler_Update( + IOleObject* iface) +{ + FIXME(": Stub\n"); + return E_NOTIMPL; +} + +/************************************************************************ + * DefaultHandler_IsUpToDate (IOleObject) + * + * This method is meaningless if the server is not running + * + * See Windows documentation for more details on IOleObject methods. + */ +static HRESULT WINAPI DefaultHandler_IsUpToDate( + IOleObject* iface) +{ + TRACE("(%p)\n", iface); + + return OLE_E_NOTRUNNING; +} + +/************************************************************************ + * DefaultHandler_GetUserClassID (IOleObject) + * + * TODO: Map to a new class ID if emulation is active. + * + * See Windows documentation for more details on IOleObject methods. + */ +static HRESULT WINAPI DefaultHandler_GetUserClassID( + IOleObject* iface, + CLSID* pClsid) +{ + _ICOM_THIS_From_IOleObject(DefaultHandler, iface); + + TRACE("(%p, %p)\n", iface, pClsid); + + /* + * Sanity check. + */ + if (pClsid==NULL) + return E_POINTER; + + memcpy(pClsid, &this->clsid, sizeof(CLSID)); + + return S_OK; +} + +/************************************************************************ + * DefaultHandler_GetUserType (IOleObject) + * + * The default handler implementation of this method simply delegates + * to OleRegGetUserType + * + * See Windows documentation for more details on IOleObject methods. + */ +static HRESULT WINAPI DefaultHandler_GetUserType( + IOleObject* iface, + DWORD dwFormOfType, + LPOLESTR* pszUserType) +{ + _ICOM_THIS_From_IOleObject(DefaultHandler, iface); + + TRACE("(%p, %ld, %p)\n", iface, dwFormOfType, pszUserType); + + return OleRegGetUserType(&this->clsid, dwFormOfType, pszUserType); +} + +/************************************************************************ + * DefaultHandler_SetExtent (IOleObject) + * + * This method is meaningless if the server is not running + * + * See Windows documentation for more details on IOleObject methods. + */ +static HRESULT WINAPI DefaultHandler_SetExtent( + IOleObject* iface, + DWORD dwDrawAspect, + SIZEL* psizel) +{ + TRACE("(%p, %lx, (%ld x %ld))\n", iface, + dwDrawAspect, psizel->cx, psizel->cy); + return OLE_E_NOTRUNNING; +} + +/************************************************************************ + * DefaultHandler_GetExtent (IOleObject) + * + * The default handler's implementation of this method returns uses + * the cache to locate the aspect and extract the extent from it. + * + * See Windows documentation for more details on IOleObject methods. + */ +static HRESULT WINAPI DefaultHandler_GetExtent( + IOleObject* iface, + DWORD dwDrawAspect, + SIZEL* psizel) +{ + DVTARGETDEVICE* targetDevice; + IViewObject2* cacheView = NULL; + HRESULT hres; + + _ICOM_THIS_From_IOleObject(DefaultHandler, iface); + + TRACE("(%p, %lx, %p)\n", iface, dwDrawAspect, psizel); + + hres = IUnknown_QueryInterface(this->dataCache, &IID_IViewObject2, (void**)&cacheView); + + if (FAILED(hres)) + return E_UNEXPECTED; + + /* + * Prepare the call to the cache's GetExtent method. + * + * Here we would build a valid DVTARGETDEVICE structure + * but, since we are calling into the data cache, we + * know it's implementation and we'll skip this + * extra work until later. + */ + targetDevice = NULL; + + hres = IViewObject2_GetExtent(cacheView, + dwDrawAspect, + -1, + targetDevice, + psizel); + + /* + * Cleanup + */ + IViewObject2_Release(cacheView); + + return hres; +} + +/************************************************************************ + * DefaultHandler_Advise (IOleObject) + * + * The default handler's implementation of this method simply + * delegates to the OleAdviseHolder. + * + * See Windows documentation for more details on IOleObject methods. + */ +static HRESULT WINAPI DefaultHandler_Advise( + IOleObject* iface, + IAdviseSink* pAdvSink, + DWORD* pdwConnection) +{ + HRESULT hres = S_OK; + _ICOM_THIS_From_IOleObject(DefaultHandler, iface); + + TRACE("(%p, %p, %p)\n", iface, pAdvSink, pdwConnection); + + /* + * Make sure we have an advise holder before we start. + */ + if (this->oleAdviseHolder==NULL) + { + hres = CreateOleAdviseHolder(&this->oleAdviseHolder); + } + + if (SUCCEEDED(hres)) + { + hres = IOleAdviseHolder_Advise(this->oleAdviseHolder, + pAdvSink, + pdwConnection); + } + + return hres; +} + +/************************************************************************ + * DefaultHandler_Unadvise (IOleObject) + * + * The default handler's implementation of this method simply + * delegates to the OleAdviseHolder. + * + * See Windows documentation for more details on IOleObject methods. + */ +static HRESULT WINAPI DefaultHandler_Unadvise( + IOleObject* iface, + DWORD dwConnection) +{ + _ICOM_THIS_From_IOleObject(DefaultHandler, iface); + + TRACE("(%p, %ld)\n", iface, dwConnection); + + /* + * If we don't have an advise holder yet, it means we don't have + * a connection. + */ + if (this->oleAdviseHolder==NULL) + return OLE_E_NOCONNECTION; + + return IOleAdviseHolder_Unadvise(this->oleAdviseHolder, + dwConnection); +} + +/************************************************************************ + * DefaultHandler_EnumAdvise (IOleObject) + * + * The default handler's implementation of this method simply + * delegates to the OleAdviseHolder. + * + * See Windows documentation for more details on IOleObject methods. + */ +static HRESULT WINAPI DefaultHandler_EnumAdvise( + IOleObject* iface, + IEnumSTATDATA** ppenumAdvise) +{ + _ICOM_THIS_From_IOleObject(DefaultHandler, iface); + + TRACE("(%p, %p)\n", iface, ppenumAdvise); + + /* + * Sanity check + */ + if (ppenumAdvise==NULL) + return E_POINTER; + + /* + * Initialize the out parameter. + */ + *ppenumAdvise = NULL; + + if (this->oleAdviseHolder==NULL) + return IOleAdviseHolder_EnumAdvise(this->oleAdviseHolder, + ppenumAdvise); + + return S_OK; +} + +/************************************************************************ + * DefaultHandler_GetMiscStatus (IOleObject) + * + * The default handler's implementation of this method simply delegates + * to OleRegGetMiscStatus. + * + * See Windows documentation for more details on IOleObject methods. + */ +static HRESULT WINAPI DefaultHandler_GetMiscStatus( + IOleObject* iface, + DWORD dwAspect, + DWORD* pdwStatus) +{ + HRESULT hres; + _ICOM_THIS_From_IOleObject(DefaultHandler, iface); + + TRACE("(%p, %lx, %p)\n", iface, dwAspect, pdwStatus); + + hres = OleRegGetMiscStatus(&(this->clsid), dwAspect, pdwStatus); + + if (FAILED(hres)) + *pdwStatus = 0; + + return S_OK; +} + +/************************************************************************ + * DefaultHandler_SetExtent (IOleObject) + * + * This method is meaningless if the server is not running + * + * See Windows documentation for more details on IOleObject methods. + */ +static HRESULT WINAPI DefaultHandler_SetColorScheme( + IOleObject* iface, + struct tagLOGPALETTE* pLogpal) +{ + TRACE("(%p, %p))\n", iface, pLogpal); + return OLE_E_NOTRUNNING; +} + +/********************************************************* + * Methods implementation for the IDataObject part of + * the DefaultHandler class. + */ + +/************************************************************************ + * DefaultHandler_IDataObject_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static HRESULT WINAPI DefaultHandler_IDataObject_QueryInterface( + IDataObject* iface, + REFIID riid, + void** ppvObject) +{ + _ICOM_THIS_From_IDataObject(DefaultHandler, iface); + + return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject); +} + +/************************************************************************ + * DefaultHandler_IDataObject_AddRef (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI DefaultHandler_IDataObject_AddRef( + IDataObject* iface) +{ + _ICOM_THIS_From_IDataObject(DefaultHandler, iface); + + return IUnknown_AddRef(this->outerUnknown); +} + +/************************************************************************ + * DefaultHandler_IDataObject_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI DefaultHandler_IDataObject_Release( + IDataObject* iface) +{ + _ICOM_THIS_From_IDataObject(DefaultHandler, iface); + + return IUnknown_Release(this->outerUnknown); +} + +/************************************************************************ + * DefaultHandler_GetData + * + * Get Data from a source dataobject using format pformatetcIn->cfFormat + * See Windows documentation for more details on GetData. + * Default handler's implementation of this method delegates to the cache. + */ +static HRESULT WINAPI DefaultHandler_GetData( + IDataObject* iface, + LPFORMATETC pformatetcIn, + STGMEDIUM* pmedium) +{ + IDataObject* cacheDataObject = NULL; + HRESULT hres; + + _ICOM_THIS_From_IDataObject(DefaultHandler, iface); + + TRACE("(%p, %p, %p)\n", iface, pformatetcIn, pmedium); + + hres = IUnknown_QueryInterface(this->dataCache, + &IID_IDataObject, + (void**)&cacheDataObject); + + if (FAILED(hres)) + return E_UNEXPECTED; + + hres = IDataObject_GetData(cacheDataObject, + pformatetcIn, + pmedium); + + IDataObject_Release(cacheDataObject); + + return hres; +} + +static HRESULT WINAPI DefaultHandler_GetDataHere( + IDataObject* iface, + LPFORMATETC pformatetc, + STGMEDIUM* pmedium) +{ + FIXME(": Stub\n"); + return E_NOTIMPL; +} + +/************************************************************************ + * DefaultHandler_QueryGetData (IDataObject) + * + * The default handler's implementation of this method delegates to + * the cache. + * + * See Windows documentation for more details on IDataObject methods. + */ +static HRESULT WINAPI DefaultHandler_QueryGetData( + IDataObject* iface, + LPFORMATETC pformatetc) +{ + IDataObject* cacheDataObject = NULL; + HRESULT hres; + + _ICOM_THIS_From_IDataObject(DefaultHandler, iface); + + TRACE("(%p, %p)\n", iface, pformatetc); + + hres = IUnknown_QueryInterface(this->dataCache, + &IID_IDataObject, + (void**)&cacheDataObject); + + if (FAILED(hres)) + return E_UNEXPECTED; + + hres = IDataObject_QueryGetData(cacheDataObject, + pformatetc); + + IDataObject_Release(cacheDataObject); + + return hres; +} + +/************************************************************************ + * DefaultHandler_GetCanonicalFormatEtc (IDataObject) + * + * This method is meaningless if the server is not running + * + * See Windows documentation for more details on IDataObject methods. + */ +static HRESULT WINAPI DefaultHandler_GetCanonicalFormatEtc( + IDataObject* iface, + LPFORMATETC pformatectIn, + LPFORMATETC pformatetcOut) +{ + FIXME("(%p, %p, %p)\n", iface, pformatectIn, pformatetcOut); + + return OLE_E_NOTRUNNING; +} + +/************************************************************************ + * DefaultHandler_SetData (IDataObject) + * + * The default handler's implementation of this method delegates to + * the cache. + * + * See Windows documentation for more details on IDataObject methods. + */ +static HRESULT WINAPI DefaultHandler_SetData( + IDataObject* iface, + LPFORMATETC pformatetc, + STGMEDIUM* pmedium, + BOOL fRelease) +{ + IDataObject* cacheDataObject = NULL; + HRESULT hres; + + _ICOM_THIS_From_IDataObject(DefaultHandler, iface); + + TRACE("(%p, %p, %p, %d)\n", iface, pformatetc, pmedium, fRelease); + + hres = IUnknown_QueryInterface(this->dataCache, + &IID_IDataObject, + (void**)&cacheDataObject); + + if (FAILED(hres)) + return E_UNEXPECTED; + + hres = IDataObject_SetData(cacheDataObject, + pformatetc, + pmedium, + fRelease); + + IDataObject_Release(cacheDataObject); + + return hres; +} + +/************************************************************************ + * DefaultHandler_EnumFormatEtc (IDataObject) + * + * The default handler's implementation of this method simply delegates + * to OleRegEnumFormatEtc. + * + * See Windows documentation for more details on IDataObject methods. + */ +static HRESULT WINAPI DefaultHandler_EnumFormatEtc( + IDataObject* iface, + DWORD dwDirection, + IEnumFORMATETC** ppenumFormatEtc) +{ + HRESULT hres; + _ICOM_THIS_From_IDataObject(DefaultHandler, iface); + + TRACE("(%p, %lx, %p)\n", iface, dwDirection, ppenumFormatEtc); + + hres = OleRegEnumFormatEtc(&(this->clsid), dwDirection, ppenumFormatEtc); + + return hres; +} + +/************************************************************************ + * DefaultHandler_DAdvise (IDataObject) + * + * The default handler's implementation of this method simply + * delegates to the DataAdviseHolder. + * + * See Windows documentation for more details on IDataObject methods. + */ +static HRESULT WINAPI DefaultHandler_DAdvise( + IDataObject* iface, + FORMATETC* pformatetc, + DWORD advf, + IAdviseSink* pAdvSink, + DWORD* pdwConnection) +{ + HRESULT hres = S_OK; + _ICOM_THIS_From_IDataObject(DefaultHandler, iface); + + TRACE("(%p, %p, %ld, %p, %p)\n", + iface, pformatetc, advf, pAdvSink, pdwConnection); + + /* + * Make sure we have a data advise holder before we start. + */ + if (this->dataAdviseHolder==NULL) + { + hres = CreateDataAdviseHolder(&this->dataAdviseHolder); + } + + if (SUCCEEDED(hres)) + { + hres = IDataAdviseHolder_Advise(this->dataAdviseHolder, + iface, + pformatetc, + advf, + pAdvSink, + pdwConnection); + } + + return hres; +} + +/************************************************************************ + * DefaultHandler_DUnadvise (IDataObject) + * + * The default handler's implementation of this method simply + * delegates to the DataAdviseHolder. + * + * See Windows documentation for more details on IDataObject methods. + */ +static HRESULT WINAPI DefaultHandler_DUnadvise( + IDataObject* iface, + DWORD dwConnection) +{ + _ICOM_THIS_From_IDataObject(DefaultHandler, iface); + + TRACE("(%p, %ld)\n", iface, dwConnection); + + /* + * If we don't have a data advise holder yet, it means that + * we don't have any connections.. + */ + if (this->dataAdviseHolder==NULL) + { + return OLE_E_NOCONNECTION; + } + + return IDataAdviseHolder_Unadvise(this->dataAdviseHolder, + dwConnection); +} + +/************************************************************************ + * DefaultHandler_EnumDAdvise (IDataObject) + * + * The default handler's implementation of this method simply + * delegates to the DataAdviseHolder. + * + * See Windows documentation for more details on IDataObject methods. + */ +static HRESULT WINAPI DefaultHandler_EnumDAdvise( + IDataObject* iface, + IEnumSTATDATA** ppenumAdvise) +{ + _ICOM_THIS_From_IDataObject(DefaultHandler, iface); + + TRACE("(%p, %p)\n", iface, ppenumAdvise); + + /* + * Sanity check + */ + if (ppenumAdvise == NULL) + return E_POINTER; + + /* + * Initialize the out parameter. + */ + *ppenumAdvise = NULL; + + /* + * If we have a data advise holder object, delegate. + */ + if (this->dataAdviseHolder!=NULL) + { + return IDataAdviseHolder_EnumAdvise(this->dataAdviseHolder, + ppenumAdvise); + } + + return S_OK; +} + +/********************************************************* + * Methods implementation for the IRunnableObject part + * of the DefaultHandler class. + */ + +/************************************************************************ + * DefaultHandler_IRunnableObject_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static HRESULT WINAPI DefaultHandler_IRunnableObject_QueryInterface( + IRunnableObject* iface, + REFIID riid, + void** ppvObject) +{ + _ICOM_THIS_From_IRunnableObject(DefaultHandler, iface); + + return IUnknown_QueryInterface(this->outerUnknown, riid, ppvObject); +} + +/************************************************************************ + * DefaultHandler_IRunnableObject_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI DefaultHandler_IRunnableObject_AddRef( + IRunnableObject* iface) +{ + _ICOM_THIS_From_IRunnableObject(DefaultHandler, iface); + + return IUnknown_AddRef(this->outerUnknown); +} + +/************************************************************************ + * DefaultHandler_IRunnableObject_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI DefaultHandler_IRunnableObject_Release( + IRunnableObject* iface) +{ + _ICOM_THIS_From_IRunnableObject(DefaultHandler, iface); + + return IUnknown_Release(this->outerUnknown); +} + +/************************************************************************ + * DefaultHandler_GetRunningClass (IRunnableObject) + * + * According to Brockscmidt, Chapter 19, the default handler's + * implementation of IRunnableobject does nothing until the object + * is actually running. + * + * See Windows documentation for more details on IRunnableObject methods. + */ +static HRESULT WINAPI DefaultHandler_GetRunningClass( + IRunnableObject* iface, + LPCLSID lpClsid) +{ + TRACE("()\n"); + return S_OK; +} + +static HRESULT WINAPI DefaultHandler_Run( + IRunnableObject* iface, + IBindCtx* pbc) +{ + FIXME(": Stub\n"); + return E_NOTIMPL; +} + +/************************************************************************ + * DefaultHandler_IsRunning (IRunnableObject) + * + * According to Brockscmidt, Chapter 19, the default handler's + * implementation of IRunnableobject does nothing until the object + * is actually running. + * + * See Windows documentation for more details on IRunnableObject methods. + */ +static BOOL WINAPI DefaultHandler_IsRunning( + IRunnableObject* iface) +{ + TRACE("()\n"); + return S_FALSE; +} + +/************************************************************************ + * DefaultHandler_LockRunning (IRunnableObject) + * + * According to Brockscmidt, Chapter 19, the default handler's + * implementation of IRunnableobject does nothing until the object + * is actually running. + * + * See Windows documentation for more details on IRunnableObject methods. + */ +static HRESULT WINAPI DefaultHandler_LockRunning( + IRunnableObject* iface, + BOOL fLock, + BOOL fLastUnlockCloses) +{ + TRACE("()\n"); + return S_OK; +} + +/************************************************************************ + * DefaultHandler_SetContainedObject (IRunnableObject) + * + * According to Brockscmidt, Chapter 19, the default handler's + * implementation of IRunnableobject does nothing until the object + * is actually running. + * + * See Windows documentation for more details on IRunnableObject methods. + */ +static HRESULT WINAPI DefaultHandler_SetContainedObject( + IRunnableObject* iface, + BOOL fContained) +{ + TRACE("()\n"); + return S_OK; +} diff --git a/reactos/lib/ole32/errorinfo.c b/reactos/lib/ole32/errorinfo.c index fb8dca77b9d..f06f9052ea1 100644 --- a/reactos/lib/ole32/errorinfo.c +++ b/reactos/lib/ole32/errorinfo.c @@ -1,520 +1,520 @@ -/* - * ErrorInfo API - * - * Copyright 2000 Patrik Stridvall, Juergen Schmied - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTES: - * - * The errorinfo is a per-thread object. The reference is stored in the - * TEB at offset 0xf80. - */ - -#include <stdarg.h> -#include <string.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "objbase.h" -#include "oleauto.h" -#include "winerror.h" - -#include "wine/unicode.h" -#include "compobj_private.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/* this code is from SysAllocStringLen (ole2disp.c in oleaut32) */ -static BSTR WINAPI ERRORINFO_SysAllocString(const OLECHAR* in) -{ - DWORD bufferSize; - DWORD* newBuffer; - WCHAR* stringBuffer; - DWORD len; - - if (in == NULL) - return NULL; - /* - * Find the lenth of the buffer passed-in in bytes. - */ - len = strlenW(in); - bufferSize = len * sizeof (WCHAR); - - /* - * Allocate a new buffer to hold the string. - * don't forget to keep an empty spot at the beginning of the - * buffer for the character count and an extra character at the - * end for the '\0'. - */ - newBuffer = HeapAlloc(GetProcessHeap(), 0, - bufferSize + sizeof(WCHAR) + sizeof(DWORD)); - - /* - * If the memory allocation failed, return a null pointer. - */ - if (newBuffer==0) - return 0; - - /* - * Copy the length of the string in the placeholder. - */ - *newBuffer = bufferSize; - - /* - * Skip the byte count. - */ - newBuffer++; - - /* - * Copy the information in the buffer. - * Since it is valid to pass a NULL pointer here, we'll initialize the - * buffer to nul if it is the case. - */ - if (in != 0) - memcpy(newBuffer, in, bufferSize); - else - memset(newBuffer, 0, bufferSize); - - /* - * Make sure that there is a nul character at the end of the - * string. - */ - stringBuffer = (WCHAR*)newBuffer; - stringBuffer[len] = 0; - - return (LPWSTR)stringBuffer; -} - -/* this code is from SysFreeString (ole2disp.c in oleaut32)*/ -static VOID WINAPI ERRORINFO_SysFreeString(BSTR in) -{ - DWORD* bufferPointer; - - /* NULL is a valid parameter */ - if(!in) return; - - /* - * We have to be careful when we free a BSTR pointer, it points to - * the beginning of the string but it skips the byte count contained - * before the string. - */ - bufferPointer = (DWORD*)in; - - bufferPointer--; - - /* - * Free the memory from it's "real" origin. - */ - HeapFree(GetProcessHeap(), 0, bufferPointer); -} - - -typedef struct ErrorInfoImpl -{ - IErrorInfoVtbl *lpvtei; - ICreateErrorInfoVtbl *lpvtcei; - ISupportErrorInfoVtbl *lpvtsei; - DWORD ref; - - GUID m_Guid; - BSTR bstrSource; - BSTR bstrDescription; - BSTR bstrHelpFile; - DWORD m_dwHelpContext; -} ErrorInfoImpl; - -static IErrorInfoVtbl IErrorInfoImpl_VTable; -static ICreateErrorInfoVtbl ICreateErrorInfoImpl_VTable; -static ISupportErrorInfoVtbl ISupportErrorInfoImpl_VTable; - -/* - converts an object pointer to This - */ -#define _IErrorInfo_Offset ((int)(&(((ErrorInfoImpl*)0)->lpvtei))) -#define _ICOM_THIS_From_IErrorInfo(class, name) class* This = (class*)(((char*)name)-_IErrorInfo_Offset) - -#define _ICreateErrorInfo_Offset ((int)(&(((ErrorInfoImpl*)0)->lpvtcei))) -#define _ICOM_THIS_From_ICreateErrorInfo(class, name) class* This = (class*)(((char*)name)-_ICreateErrorInfo_Offset) - -#define _ISupportErrorInfo_Offset ((int)(&(((ErrorInfoImpl*)0)->lpvtsei))) -#define _ICOM_THIS_From_ISupportErrorInfo(class, name) class* This = (class*)(((char*)name)-_ISupportErrorInfo_Offset) - -/* - converts This to an object pointer - */ -#define _IErrorInfo_(This) (IErrorInfo*)&(This->lpvtei) -#define _ICreateErrorInfo_(This) (ICreateErrorInfo*)&(This->lpvtcei) -#define _ISupportErrorInfo_(This) (ISupportErrorInfo*)&(This->lpvtsei) - -IErrorInfo * IErrorInfoImpl_Constructor() -{ - ErrorInfoImpl * ei = HeapAlloc(GetProcessHeap(), 0, sizeof(ErrorInfoImpl)); - if (ei) - { - ei->lpvtei = &IErrorInfoImpl_VTable; - ei->lpvtcei = &ICreateErrorInfoImpl_VTable; - ei->lpvtsei = &ISupportErrorInfoImpl_VTable; - ei->ref = 1; - ei->bstrSource = NULL; - ei->bstrDescription = NULL; - ei->bstrHelpFile = NULL; - ei->m_dwHelpContext = 0; - } - return (IErrorInfo *)ei; -} - - -static HRESULT WINAPI IErrorInfoImpl_QueryInterface( - IErrorInfo* iface, - REFIID riid, - VOID** ppvoid) -{ - _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); - TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvoid); - - *ppvoid = NULL; - - if(IsEqualIID(riid, &IID_IErrorInfo)) - { - *ppvoid = _IErrorInfo_(This); - } - else if(IsEqualIID(riid, &IID_ICreateErrorInfo)) - { - *ppvoid = _ICreateErrorInfo_(This); - } - else if(IsEqualIID(riid, &IID_ISupportErrorInfo)) - { - *ppvoid = _ISupportErrorInfo_(This); - } - - if(*ppvoid) - { - IUnknown_AddRef( (IUnknown*)*ppvoid ); - TRACE("-- Interface: (%p)->(%p)\n",ppvoid,*ppvoid); - return S_OK; - } - TRACE("-- Interface: E_NOINTERFACE\n"); - return E_NOINTERFACE; -} - -static ULONG WINAPI IErrorInfoImpl_AddRef( - IErrorInfo* iface) -{ - _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); - TRACE("(%p)->(count=%lu)\n",This,This->ref); - return InterlockedIncrement(&This->ref); -} - -static ULONG WINAPI IErrorInfoImpl_Release( - IErrorInfo* iface) -{ - _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); - ULONG ref = InterlockedDecrement(&This->ref); - - TRACE("(%p)->(count=%lu)\n",This,ref+1); - - if (!ref) - { - TRACE("-- destroying IErrorInfo(%p)\n",This); - HeapFree(GetProcessHeap(),0,This); - return 0; - } - return ref; -} - -static HRESULT WINAPI IErrorInfoImpl_GetGUID( - IErrorInfo* iface, - GUID * pGUID) -{ - _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); - TRACE("(%p)->(count=%lu)\n",This,This->ref); - if(!pGUID )return E_INVALIDARG; - memcpy(pGUID, &This->m_Guid, sizeof(GUID)); - return S_OK; -} - -static HRESULT WINAPI IErrorInfoImpl_GetSource( - IErrorInfo* iface, - BSTR *pBstrSource) -{ - _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); - TRACE("(%p)->(pBstrSource=%p)\n",This,pBstrSource); - if (pBstrSource == NULL) - return E_INVALIDARG; - *pBstrSource = ERRORINFO_SysAllocString(This->bstrSource); - return S_OK; -} - -static HRESULT WINAPI IErrorInfoImpl_GetDescription( - IErrorInfo* iface, - BSTR *pBstrDescription) -{ - _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); - - TRACE("(%p)->(pBstrDescription=%p)\n",This,pBstrDescription); - if (pBstrDescription == NULL) - return E_INVALIDARG; - *pBstrDescription = ERRORINFO_SysAllocString(This->bstrDescription); - - return S_OK; -} - -static HRESULT WINAPI IErrorInfoImpl_GetHelpFile( - IErrorInfo* iface, - BSTR *pBstrHelpFile) -{ - _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); - - TRACE("(%p)->(pBstrHelpFile=%p)\n",This, pBstrHelpFile); - if (pBstrHelpFile == NULL) - return E_INVALIDARG; - *pBstrHelpFile = ERRORINFO_SysAllocString(This->bstrHelpFile); - - return S_OK; -} - -static HRESULT WINAPI IErrorInfoImpl_GetHelpContext( - IErrorInfo* iface, - DWORD *pdwHelpContext) -{ - _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); - TRACE("(%p)->(pdwHelpContext=%p)\n",This, pdwHelpContext); - if (pdwHelpContext == NULL) - return E_INVALIDARG; - *pdwHelpContext = This->m_dwHelpContext; - - return S_OK; -} - -static IErrorInfoVtbl IErrorInfoImpl_VTable = -{ - IErrorInfoImpl_QueryInterface, - IErrorInfoImpl_AddRef, - IErrorInfoImpl_Release, - - IErrorInfoImpl_GetGUID, - IErrorInfoImpl_GetSource, - IErrorInfoImpl_GetDescription, - IErrorInfoImpl_GetHelpFile, - IErrorInfoImpl_GetHelpContext -}; - - -static HRESULT WINAPI ICreateErrorInfoImpl_QueryInterface( - ICreateErrorInfo* iface, - REFIID riid, - VOID** ppvoid) -{ - _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); - TRACE("(%p)\n", This); - return IErrorInfo_QueryInterface(_IErrorInfo_(This), riid, ppvoid); -} - -static ULONG WINAPI ICreateErrorInfoImpl_AddRef( - ICreateErrorInfo* iface) -{ - _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); - TRACE("(%p)\n", This); - return IErrorInfo_AddRef(_IErrorInfo_(This)); -} - -static ULONG WINAPI ICreateErrorInfoImpl_Release( - ICreateErrorInfo* iface) -{ - _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); - TRACE("(%p)\n", This); - return IErrorInfo_Release(_IErrorInfo_(This)); -} - - -static HRESULT WINAPI ICreateErrorInfoImpl_SetGUID( - ICreateErrorInfo* iface, - REFGUID rguid) -{ - _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); - TRACE("(%p)->(%s)\n", This, debugstr_guid(rguid)); - memcpy(&This->m_Guid, rguid, sizeof(GUID)); - return S_OK; -} - -static HRESULT WINAPI ICreateErrorInfoImpl_SetSource( - ICreateErrorInfo* iface, - LPOLESTR szSource) -{ - _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); - TRACE("(%p): %s\n",This, debugstr_w(szSource)); - if (This->bstrSource != NULL) - ERRORINFO_SysFreeString(This->bstrSource); - This->bstrSource = ERRORINFO_SysAllocString(szSource); - - return S_OK; -} - -static HRESULT WINAPI ICreateErrorInfoImpl_SetDescription( - ICreateErrorInfo* iface, - LPOLESTR szDescription) -{ - _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); - TRACE("(%p): %s\n",This, debugstr_w(szDescription)); - if (This->bstrDescription != NULL) - ERRORINFO_SysFreeString(This->bstrDescription); - This->bstrDescription = ERRORINFO_SysAllocString(szDescription); - - return S_OK; -} - -static HRESULT WINAPI ICreateErrorInfoImpl_SetHelpFile( - ICreateErrorInfo* iface, - LPOLESTR szHelpFile) -{ - _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); - TRACE("(%p,%s)\n",This,debugstr_w(szHelpFile)); - if (This->bstrHelpFile != NULL) - ERRORINFO_SysFreeString(This->bstrHelpFile); - This->bstrHelpFile = ERRORINFO_SysAllocString(szHelpFile); - return S_OK; -} - -static HRESULT WINAPI ICreateErrorInfoImpl_SetHelpContext( - ICreateErrorInfo* iface, - DWORD dwHelpContext) -{ - _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); - TRACE("(%p,%ld)\n",This,dwHelpContext); - This->m_dwHelpContext = dwHelpContext; - return S_OK; -} - -static ICreateErrorInfoVtbl ICreateErrorInfoImpl_VTable = -{ - ICreateErrorInfoImpl_QueryInterface, - ICreateErrorInfoImpl_AddRef, - ICreateErrorInfoImpl_Release, - - ICreateErrorInfoImpl_SetGUID, - ICreateErrorInfoImpl_SetSource, - ICreateErrorInfoImpl_SetDescription, - ICreateErrorInfoImpl_SetHelpFile, - ICreateErrorInfoImpl_SetHelpContext -}; - -static HRESULT WINAPI ISupportErrorInfoImpl_QueryInterface( - ISupportErrorInfo* iface, - REFIID riid, - VOID** ppvoid) -{ - _ICOM_THIS_From_ISupportErrorInfo(ErrorInfoImpl, iface); - TRACE("(%p)\n", This); - - return IErrorInfo_QueryInterface(_IErrorInfo_(This), riid, ppvoid); -} - -static ULONG WINAPI ISupportErrorInfoImpl_AddRef( - ISupportErrorInfo* iface) -{ - _ICOM_THIS_From_ISupportErrorInfo(ErrorInfoImpl, iface); - TRACE("(%p)\n", This); - return IErrorInfo_AddRef(_IErrorInfo_(This)); -} - -static ULONG WINAPI ISupportErrorInfoImpl_Release( - ISupportErrorInfo* iface) -{ - _ICOM_THIS_From_ISupportErrorInfo(ErrorInfoImpl, iface); - TRACE("(%p)\n", This); - return IErrorInfo_Release(_IErrorInfo_(This)); -} - - -static HRESULT WINAPI ISupportErrorInfoImpl_InterfaceSupportsErrorInfo( - ISupportErrorInfo* iface, - REFIID riid) -{ - _ICOM_THIS_From_ISupportErrorInfo(ErrorInfoImpl, iface); - TRACE("(%p)->(%s)\n", This, debugstr_guid(riid)); - return (IsEqualIID(riid, &This->m_Guid)) ? S_OK : S_FALSE; -} - -static ISupportErrorInfoVtbl ISupportErrorInfoImpl_VTable = -{ - ISupportErrorInfoImpl_QueryInterface, - ISupportErrorInfoImpl_AddRef, - ISupportErrorInfoImpl_Release, - - - ISupportErrorInfoImpl_InterfaceSupportsErrorInfo -}; -/*********************************************************************** - * CreateErrorInfo (OLE32.@) - */ -HRESULT WINAPI CreateErrorInfo(ICreateErrorInfo **pperrinfo) -{ - IErrorInfo * pei; - HRESULT res; - TRACE("(%p): stub:\n", pperrinfo); - if(! pperrinfo ) return E_INVALIDARG; - if(!(pei=IErrorInfoImpl_Constructor()))return E_OUTOFMEMORY; - - res = IErrorInfo_QueryInterface(pei, &IID_ICreateErrorInfo, (LPVOID*)pperrinfo); - IErrorInfo_Release(pei); - return res; -} - -/*********************************************************************** - * GetErrorInfo (OLE32.@) - */ -HRESULT WINAPI GetErrorInfo(ULONG dwReserved, IErrorInfo **pperrinfo) -{ - TRACE("(%ld, %p, %p)\n", dwReserved, pperrinfo, COM_CurrentInfo()->errorinfo); - - if(!pperrinfo) return E_INVALIDARG; - - if (!COM_CurrentInfo()->errorinfo) - { - *pperrinfo = NULL; - return S_FALSE; - } - - *pperrinfo = COM_CurrentInfo()->errorinfo; - - /* clear thread error state */ - COM_CurrentInfo()->errorinfo = NULL; - return S_OK; -} - -/*********************************************************************** - * SetErrorInfo (OLE32.@) - */ -HRESULT WINAPI SetErrorInfo(ULONG dwReserved, IErrorInfo *perrinfo) -{ - IErrorInfo * pei; - - TRACE("(%ld, %p)\n", dwReserved, perrinfo); - - /* release old errorinfo */ - pei = COM_CurrentInfo()->errorinfo; - if (pei) IErrorInfo_Release(pei); - - /* set to new value */ - COM_CurrentInfo()->errorinfo = perrinfo; - if (perrinfo) IErrorInfo_AddRef(perrinfo); - - return S_OK; -} +/* + * ErrorInfo API + * + * Copyright 2000 Patrik Stridvall, Juergen Schmied + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES: + * + * The errorinfo is a per-thread object. The reference is stored in the + * TEB at offset 0xf80. + */ + +#include <stdarg.h> +#include <string.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" +#include "oleauto.h" +#include "winerror.h" + +#include "wine/unicode.h" +#include "compobj_private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/* this code is from SysAllocStringLen (ole2disp.c in oleaut32) */ +static BSTR WINAPI ERRORINFO_SysAllocString(const OLECHAR* in) +{ + DWORD bufferSize; + DWORD* newBuffer; + WCHAR* stringBuffer; + DWORD len; + + if (in == NULL) + return NULL; + /* + * Find the lenth of the buffer passed-in in bytes. + */ + len = strlenW(in); + bufferSize = len * sizeof (WCHAR); + + /* + * Allocate a new buffer to hold the string. + * don't forget to keep an empty spot at the beginning of the + * buffer for the character count and an extra character at the + * end for the '\0'. + */ + newBuffer = HeapAlloc(GetProcessHeap(), 0, + bufferSize + sizeof(WCHAR) + sizeof(DWORD)); + + /* + * If the memory allocation failed, return a null pointer. + */ + if (newBuffer==0) + return 0; + + /* + * Copy the length of the string in the placeholder. + */ + *newBuffer = bufferSize; + + /* + * Skip the byte count. + */ + newBuffer++; + + /* + * Copy the information in the buffer. + * Since it is valid to pass a NULL pointer here, we'll initialize the + * buffer to nul if it is the case. + */ + if (in != 0) + memcpy(newBuffer, in, bufferSize); + else + memset(newBuffer, 0, bufferSize); + + /* + * Make sure that there is a nul character at the end of the + * string. + */ + stringBuffer = (WCHAR*)newBuffer; + stringBuffer[len] = 0; + + return (LPWSTR)stringBuffer; +} + +/* this code is from SysFreeString (ole2disp.c in oleaut32)*/ +static VOID WINAPI ERRORINFO_SysFreeString(BSTR in) +{ + DWORD* bufferPointer; + + /* NULL is a valid parameter */ + if(!in) return; + + /* + * We have to be careful when we free a BSTR pointer, it points to + * the beginning of the string but it skips the byte count contained + * before the string. + */ + bufferPointer = (DWORD*)in; + + bufferPointer--; + + /* + * Free the memory from it's "real" origin. + */ + HeapFree(GetProcessHeap(), 0, bufferPointer); +} + + +typedef struct ErrorInfoImpl +{ + IErrorInfoVtbl *lpvtei; + ICreateErrorInfoVtbl *lpvtcei; + ISupportErrorInfoVtbl *lpvtsei; + DWORD ref; + + GUID m_Guid; + BSTR bstrSource; + BSTR bstrDescription; + BSTR bstrHelpFile; + DWORD m_dwHelpContext; +} ErrorInfoImpl; + +static IErrorInfoVtbl IErrorInfoImpl_VTable; +static ICreateErrorInfoVtbl ICreateErrorInfoImpl_VTable; +static ISupportErrorInfoVtbl ISupportErrorInfoImpl_VTable; + +/* + converts an object pointer to This + */ +#define _IErrorInfo_Offset ((int)(&(((ErrorInfoImpl*)0)->lpvtei))) +#define _ICOM_THIS_From_IErrorInfo(class, name) class* This = (class*)(((char*)name)-_IErrorInfo_Offset) + +#define _ICreateErrorInfo_Offset ((int)(&(((ErrorInfoImpl*)0)->lpvtcei))) +#define _ICOM_THIS_From_ICreateErrorInfo(class, name) class* This = (class*)(((char*)name)-_ICreateErrorInfo_Offset) + +#define _ISupportErrorInfo_Offset ((int)(&(((ErrorInfoImpl*)0)->lpvtsei))) +#define _ICOM_THIS_From_ISupportErrorInfo(class, name) class* This = (class*)(((char*)name)-_ISupportErrorInfo_Offset) + +/* + converts This to an object pointer + */ +#define _IErrorInfo_(This) (IErrorInfo*)&(This->lpvtei) +#define _ICreateErrorInfo_(This) (ICreateErrorInfo*)&(This->lpvtcei) +#define _ISupportErrorInfo_(This) (ISupportErrorInfo*)&(This->lpvtsei) + +IErrorInfo * IErrorInfoImpl_Constructor() +{ + ErrorInfoImpl * ei = HeapAlloc(GetProcessHeap(), 0, sizeof(ErrorInfoImpl)); + if (ei) + { + ei->lpvtei = &IErrorInfoImpl_VTable; + ei->lpvtcei = &ICreateErrorInfoImpl_VTable; + ei->lpvtsei = &ISupportErrorInfoImpl_VTable; + ei->ref = 1; + ei->bstrSource = NULL; + ei->bstrDescription = NULL; + ei->bstrHelpFile = NULL; + ei->m_dwHelpContext = 0; + } + return (IErrorInfo *)ei; +} + + +static HRESULT WINAPI IErrorInfoImpl_QueryInterface( + IErrorInfo* iface, + REFIID riid, + VOID** ppvoid) +{ + _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); + TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvoid); + + *ppvoid = NULL; + + if(IsEqualIID(riid, &IID_IErrorInfo)) + { + *ppvoid = _IErrorInfo_(This); + } + else if(IsEqualIID(riid, &IID_ICreateErrorInfo)) + { + *ppvoid = _ICreateErrorInfo_(This); + } + else if(IsEqualIID(riid, &IID_ISupportErrorInfo)) + { + *ppvoid = _ISupportErrorInfo_(This); + } + + if(*ppvoid) + { + IUnknown_AddRef( (IUnknown*)*ppvoid ); + TRACE("-- Interface: (%p)->(%p)\n",ppvoid,*ppvoid); + return S_OK; + } + TRACE("-- Interface: E_NOINTERFACE\n"); + return E_NOINTERFACE; +} + +static ULONG WINAPI IErrorInfoImpl_AddRef( + IErrorInfo* iface) +{ + _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); + TRACE("(%p)->(count=%lu)\n",This,This->ref); + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI IErrorInfoImpl_Release( + IErrorInfo* iface) +{ + _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(count=%lu)\n",This,ref+1); + + if (!ref) + { + TRACE("-- destroying IErrorInfo(%p)\n",This); + HeapFree(GetProcessHeap(),0,This); + return 0; + } + return ref; +} + +static HRESULT WINAPI IErrorInfoImpl_GetGUID( + IErrorInfo* iface, + GUID * pGUID) +{ + _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); + TRACE("(%p)->(count=%lu)\n",This,This->ref); + if(!pGUID )return E_INVALIDARG; + memcpy(pGUID, &This->m_Guid, sizeof(GUID)); + return S_OK; +} + +static HRESULT WINAPI IErrorInfoImpl_GetSource( + IErrorInfo* iface, + BSTR *pBstrSource) +{ + _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); + TRACE("(%p)->(pBstrSource=%p)\n",This,pBstrSource); + if (pBstrSource == NULL) + return E_INVALIDARG; + *pBstrSource = ERRORINFO_SysAllocString(This->bstrSource); + return S_OK; +} + +static HRESULT WINAPI IErrorInfoImpl_GetDescription( + IErrorInfo* iface, + BSTR *pBstrDescription) +{ + _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); + + TRACE("(%p)->(pBstrDescription=%p)\n",This,pBstrDescription); + if (pBstrDescription == NULL) + return E_INVALIDARG; + *pBstrDescription = ERRORINFO_SysAllocString(This->bstrDescription); + + return S_OK; +} + +static HRESULT WINAPI IErrorInfoImpl_GetHelpFile( + IErrorInfo* iface, + BSTR *pBstrHelpFile) +{ + _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); + + TRACE("(%p)->(pBstrHelpFile=%p)\n",This, pBstrHelpFile); + if (pBstrHelpFile == NULL) + return E_INVALIDARG; + *pBstrHelpFile = ERRORINFO_SysAllocString(This->bstrHelpFile); + + return S_OK; +} + +static HRESULT WINAPI IErrorInfoImpl_GetHelpContext( + IErrorInfo* iface, + DWORD *pdwHelpContext) +{ + _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); + TRACE("(%p)->(pdwHelpContext=%p)\n",This, pdwHelpContext); + if (pdwHelpContext == NULL) + return E_INVALIDARG; + *pdwHelpContext = This->m_dwHelpContext; + + return S_OK; +} + +static IErrorInfoVtbl IErrorInfoImpl_VTable = +{ + IErrorInfoImpl_QueryInterface, + IErrorInfoImpl_AddRef, + IErrorInfoImpl_Release, + + IErrorInfoImpl_GetGUID, + IErrorInfoImpl_GetSource, + IErrorInfoImpl_GetDescription, + IErrorInfoImpl_GetHelpFile, + IErrorInfoImpl_GetHelpContext +}; + + +static HRESULT WINAPI ICreateErrorInfoImpl_QueryInterface( + ICreateErrorInfo* iface, + REFIID riid, + VOID** ppvoid) +{ + _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); + TRACE("(%p)\n", This); + return IErrorInfo_QueryInterface(_IErrorInfo_(This), riid, ppvoid); +} + +static ULONG WINAPI ICreateErrorInfoImpl_AddRef( + ICreateErrorInfo* iface) +{ + _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); + TRACE("(%p)\n", This); + return IErrorInfo_AddRef(_IErrorInfo_(This)); +} + +static ULONG WINAPI ICreateErrorInfoImpl_Release( + ICreateErrorInfo* iface) +{ + _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); + TRACE("(%p)\n", This); + return IErrorInfo_Release(_IErrorInfo_(This)); +} + + +static HRESULT WINAPI ICreateErrorInfoImpl_SetGUID( + ICreateErrorInfo* iface, + REFGUID rguid) +{ + _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); + TRACE("(%p)->(%s)\n", This, debugstr_guid(rguid)); + memcpy(&This->m_Guid, rguid, sizeof(GUID)); + return S_OK; +} + +static HRESULT WINAPI ICreateErrorInfoImpl_SetSource( + ICreateErrorInfo* iface, + LPOLESTR szSource) +{ + _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); + TRACE("(%p): %s\n",This, debugstr_w(szSource)); + if (This->bstrSource != NULL) + ERRORINFO_SysFreeString(This->bstrSource); + This->bstrSource = ERRORINFO_SysAllocString(szSource); + + return S_OK; +} + +static HRESULT WINAPI ICreateErrorInfoImpl_SetDescription( + ICreateErrorInfo* iface, + LPOLESTR szDescription) +{ + _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); + TRACE("(%p): %s\n",This, debugstr_w(szDescription)); + if (This->bstrDescription != NULL) + ERRORINFO_SysFreeString(This->bstrDescription); + This->bstrDescription = ERRORINFO_SysAllocString(szDescription); + + return S_OK; +} + +static HRESULT WINAPI ICreateErrorInfoImpl_SetHelpFile( + ICreateErrorInfo* iface, + LPOLESTR szHelpFile) +{ + _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); + TRACE("(%p,%s)\n",This,debugstr_w(szHelpFile)); + if (This->bstrHelpFile != NULL) + ERRORINFO_SysFreeString(This->bstrHelpFile); + This->bstrHelpFile = ERRORINFO_SysAllocString(szHelpFile); + return S_OK; +} + +static HRESULT WINAPI ICreateErrorInfoImpl_SetHelpContext( + ICreateErrorInfo* iface, + DWORD dwHelpContext) +{ + _ICOM_THIS_From_ICreateErrorInfo(ErrorInfoImpl, iface); + TRACE("(%p,%ld)\n",This,dwHelpContext); + This->m_dwHelpContext = dwHelpContext; + return S_OK; +} + +static ICreateErrorInfoVtbl ICreateErrorInfoImpl_VTable = +{ + ICreateErrorInfoImpl_QueryInterface, + ICreateErrorInfoImpl_AddRef, + ICreateErrorInfoImpl_Release, + + ICreateErrorInfoImpl_SetGUID, + ICreateErrorInfoImpl_SetSource, + ICreateErrorInfoImpl_SetDescription, + ICreateErrorInfoImpl_SetHelpFile, + ICreateErrorInfoImpl_SetHelpContext +}; + +static HRESULT WINAPI ISupportErrorInfoImpl_QueryInterface( + ISupportErrorInfo* iface, + REFIID riid, + VOID** ppvoid) +{ + _ICOM_THIS_From_ISupportErrorInfo(ErrorInfoImpl, iface); + TRACE("(%p)\n", This); + + return IErrorInfo_QueryInterface(_IErrorInfo_(This), riid, ppvoid); +} + +static ULONG WINAPI ISupportErrorInfoImpl_AddRef( + ISupportErrorInfo* iface) +{ + _ICOM_THIS_From_ISupportErrorInfo(ErrorInfoImpl, iface); + TRACE("(%p)\n", This); + return IErrorInfo_AddRef(_IErrorInfo_(This)); +} + +static ULONG WINAPI ISupportErrorInfoImpl_Release( + ISupportErrorInfo* iface) +{ + _ICOM_THIS_From_ISupportErrorInfo(ErrorInfoImpl, iface); + TRACE("(%p)\n", This); + return IErrorInfo_Release(_IErrorInfo_(This)); +} + + +static HRESULT WINAPI ISupportErrorInfoImpl_InterfaceSupportsErrorInfo( + ISupportErrorInfo* iface, + REFIID riid) +{ + _ICOM_THIS_From_ISupportErrorInfo(ErrorInfoImpl, iface); + TRACE("(%p)->(%s)\n", This, debugstr_guid(riid)); + return (IsEqualIID(riid, &This->m_Guid)) ? S_OK : S_FALSE; +} + +static ISupportErrorInfoVtbl ISupportErrorInfoImpl_VTable = +{ + ISupportErrorInfoImpl_QueryInterface, + ISupportErrorInfoImpl_AddRef, + ISupportErrorInfoImpl_Release, + + + ISupportErrorInfoImpl_InterfaceSupportsErrorInfo +}; +/*********************************************************************** + * CreateErrorInfo (OLE32.@) + */ +HRESULT WINAPI CreateErrorInfo(ICreateErrorInfo **pperrinfo) +{ + IErrorInfo * pei; + HRESULT res; + TRACE("(%p): stub:\n", pperrinfo); + if(! pperrinfo ) return E_INVALIDARG; + if(!(pei=IErrorInfoImpl_Constructor()))return E_OUTOFMEMORY; + + res = IErrorInfo_QueryInterface(pei, &IID_ICreateErrorInfo, (LPVOID*)pperrinfo); + IErrorInfo_Release(pei); + return res; +} + +/*********************************************************************** + * GetErrorInfo (OLE32.@) + */ +HRESULT WINAPI GetErrorInfo(ULONG dwReserved, IErrorInfo **pperrinfo) +{ + TRACE("(%ld, %p, %p)\n", dwReserved, pperrinfo, COM_CurrentInfo()->errorinfo); + + if(!pperrinfo) return E_INVALIDARG; + + if (!COM_CurrentInfo()->errorinfo) + { + *pperrinfo = NULL; + return S_FALSE; + } + + *pperrinfo = COM_CurrentInfo()->errorinfo; + + /* clear thread error state */ + COM_CurrentInfo()->errorinfo = NULL; + return S_OK; +} + +/*********************************************************************** + * SetErrorInfo (OLE32.@) + */ +HRESULT WINAPI SetErrorInfo(ULONG dwReserved, IErrorInfo *perrinfo) +{ + IErrorInfo * pei; + + TRACE("(%ld, %p)\n", dwReserved, perrinfo); + + /* release old errorinfo */ + pei = COM_CurrentInfo()->errorinfo; + if (pei) IErrorInfo_Release(pei); + + /* set to new value */ + COM_CurrentInfo()->errorinfo = perrinfo; + if (perrinfo) IErrorInfo_AddRef(perrinfo); + + return S_OK; +} diff --git a/reactos/lib/ole32/filemoniker.c b/reactos/lib/ole32/filemoniker.c index 1f4ee2565d6..9b8cdb1c7db 100644 --- a/reactos/lib/ole32/filemoniker.c +++ b/reactos/lib/ole32/filemoniker.c @@ -1,1430 +1,1430 @@ -/* - * FileMonikers implementation - * - * Copyright 1999 Noomen Hamza - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <assert.h> -#include <stdarg.h> -#include <string.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "winnls.h" -#include "wine/unicode.h" -#include "wine/debug.h" -#include "objbase.h" -#include "moniker.h" - -#include "compobj_private.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -const CLSID CLSID_FileMoniker = { - 0x303, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46} -}; - -/* filemoniker data structure */ -typedef struct FileMonikerImpl{ - - IMonikerVtbl* lpvtbl1; /* VTable relative to the IMoniker interface.*/ - - /* The ROT (RunningObjectTable implementation) uses the IROTData interface to test whether - * two monikers are equal. That's whay IROTData interface is implemented by monikers. - */ - IROTDataVtbl* lpvtbl2; /* VTable relative to the IROTData interface.*/ - - ULONG ref; /* reference counter for this object */ - - LPOLESTR filePathName; /* path string identified by this filemoniker */ - - IUnknown *pMarshal; /* custom marshaler */ -} FileMonikerImpl; - -/* Local function used by filemoniker implementation */ -static HRESULT WINAPI FileMonikerImpl_Construct(FileMonikerImpl* iface, LPCOLESTR lpszPathName); -static HRESULT WINAPI FileMonikerImpl_Destroy(FileMonikerImpl* iface); - -/******************************************************************************* - * FileMoniker_QueryInterface - */ -static HRESULT WINAPI -FileMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject) -{ - FileMonikerImpl *This = (FileMonikerImpl *)iface; - - TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject); - - /* Perform a sanity check on the parameters.*/ - if ( (This==0) || (ppvObject==0) ) - return E_INVALIDARG; - - /* Initialize the return parameter */ - *ppvObject = 0; - - /* Compare the riid with the interface IDs implemented by this object.*/ - if (IsEqualIID(&IID_IUnknown, riid) || - IsEqualIID(&IID_IPersist, riid) || - IsEqualIID(&IID_IPersistStream,riid) || - IsEqualIID(&IID_IMoniker, riid) - ) - *ppvObject = iface; - - else if (IsEqualIID(&IID_IROTData, riid)) - *ppvObject = (IROTData*)&(This->lpvtbl2); - else if (IsEqualIID(&IID_IMarshal, riid)) - { - HRESULT hr = S_OK; - if (!This->pMarshal) - hr = MonikerMarshal_Create(iface, &This->pMarshal); - if (hr != S_OK) - return hr; - return IUnknown_QueryInterface(This->pMarshal, riid, ppvObject); - } - - /* Check that we obtained an interface.*/ - if ((*ppvObject)==0) - return E_NOINTERFACE; - - /* Query Interface always increases the reference count by one when it is successful */ - IMoniker_AddRef(iface); - - return S_OK; -} - -/****************************************************************************** - * FileMoniker_AddRef - */ -static ULONG WINAPI -FileMonikerImpl_AddRef(IMoniker* iface) -{ - FileMonikerImpl *This = (FileMonikerImpl *)iface; - - TRACE("(%p)\n",iface); - - return InterlockedIncrement(&This->ref); -} - -/****************************************************************************** - * FileMoniker_Release - */ -static ULONG WINAPI -FileMonikerImpl_Release(IMoniker* iface) -{ - FileMonikerImpl *This = (FileMonikerImpl *)iface; - ULONG ref; - - TRACE("(%p)\n",iface); - - ref = InterlockedDecrement(&This->ref); - - /* destroy the object if there's no more reference on it */ - if (ref == 0) FileMonikerImpl_Destroy(This); - - return ref; -} - -/****************************************************************************** - * FileMoniker_GetClassID - */ -static HRESULT WINAPI -FileMonikerImpl_GetClassID(IMoniker* iface, CLSID *pClassID) -{ - TRACE("(%p,%p)\n",iface,pClassID); - - if (pClassID==NULL) - return E_POINTER; - - *pClassID = CLSID_FileMoniker; - - return S_OK; -} - -/****************************************************************************** - * FileMoniker_IsDirty - * - * Note that the OLE-provided implementations of the IPersistStream::IsDirty - * method in the OLE-provided moniker interfaces always return S_FALSE because - * their internal state never changes. - */ -static HRESULT WINAPI -FileMonikerImpl_IsDirty(IMoniker* iface) -{ - - TRACE("(%p)\n",iface); - - return S_FALSE; -} - -/****************************************************************************** - * FileMoniker_Load - * - * this function locates and reads from the stream the filePath string - * written by FileMonikerImpl_Save - */ -static HRESULT WINAPI -FileMonikerImpl_Load(IMoniker* iface,IStream* pStm) -{ - HRESULT res; - CHAR* filePathA; - WCHAR* filePathW; - ULONG bread; - WORD wbuffer; - DWORD dwbuffer,length,i,doubleLenHex,doubleLenDec; - - FileMonikerImpl *This = (FileMonikerImpl *)iface; - - TRACE("(%p,%p)\n",iface,pStm); - - /* first WORD is non significative */ - res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread); - if (bread!=sizeof(WORD) || wbuffer!=0) - { - ERR("Couldn't read 0 word\n"); - return E_FAIL; - } - - /* read filePath string length (plus one) */ - res=IStream_Read(pStm,&length,sizeof(DWORD),&bread); - if (bread != sizeof(DWORD)) - { - ERR("Couldn't read file string length\n"); - return E_FAIL; - } - - /* read filePath string */ - filePathA=HeapAlloc(GetProcessHeap(),0,length); - res=IStream_Read(pStm,filePathA,length,&bread); - HeapFree(GetProcessHeap(),0,filePathA); - if (bread != length) - { - ERR("Couldn't read file path string\n"); - return E_FAIL; - } - - /* read the first constant */ - IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread); - if (bread != sizeof(DWORD) || dwbuffer != 0xDEADFFFF) - { - ERR("Couldn't read 0xDEADFFFF constant\n"); - return E_FAIL; - } - - length--; - - for(i=0;i<10;i++){ - res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread); - if (bread!=sizeof(WORD) || wbuffer!=0) - { - ERR("Couldn't read 0 padding\n"); - return E_FAIL; - } - } - - if (length>8) - length=0; - - doubleLenHex=doubleLenDec=2*length; - if (length > 5) - doubleLenDec+=6; - - res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread); - if (bread!=sizeof(DWORD) || dwbuffer!=doubleLenDec) - return E_FAIL; - - if (length==0) - return res; - - res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread); - if (bread!=sizeof(DWORD) || dwbuffer!=doubleLenHex) - return E_FAIL; - - res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread); - if (bread!=sizeof(WORD) || wbuffer!=0x3) - return E_FAIL; - - filePathW=HeapAlloc(GetProcessHeap(),0,(length+1)*sizeof(WCHAR)); - filePathW[length]=0; - res=IStream_Read(pStm,filePathW,doubleLenHex,&bread); - if (bread!=doubleLenHex) { - HeapFree(GetProcessHeap(), 0, filePathW); - return E_FAIL; - } - - HeapFree(GetProcessHeap(),0,This->filePathName); - - This->filePathName=filePathW; - - return res; -} - -/****************************************************************************** - * FileMoniker_Save - * - * This function saves data of this object. In the beginning I thougth - * that I have just to write the filePath string on Stream. But, when I - * tested this function whith windows programs samples, I noticed that it - * was not the case. So I analysed data written by this function on - * Windows and what this did function exactly ! But I have no idea about - * its logic ! - * I guessed data which must be written on stream is: - * 1) WORD constant:zero - * 2) length of the path string ("\0" included) - * 3) path string type A - * 4) DWORD constant : 0xDEADFFFF - * 5) ten WORD constant: zero - * 6) DWORD: double-length of the the path string type W ("\0" not - * included) - * 7) WORD constant: 0x3 - * 8) filePath unicode string. - * if the length(filePath) > 8 or length(filePath) == 8 stop at step 5) - */ -static HRESULT WINAPI -FileMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty) -{ - FileMonikerImpl *This = (FileMonikerImpl *)iface; - - HRESULT res; - LPOLESTR filePathW=This->filePathName; - CHAR* filePathA; - DWORD len; - - DWORD constant1 = 0xDEADFFFF; /* these constants are detected after analysing the data structure written by */ - WORD constant2 = 0x3; /* FileMoniker_Save function in a windows program system */ - - WORD zero=0; - DWORD doubleLenHex; - DWORD doubleLenDec; - int i=0; - - TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty); - - if (pStm==NULL) - return E_POINTER; - - /* write a DWORD set to 0 : constant */ - res=IStream_Write(pStm,&zero,sizeof(WORD),NULL); - - /* write length of filePath string ( "\0" included )*/ - len = WideCharToMultiByte( CP_ACP, 0, filePathW, -1, NULL, 0, NULL, NULL ); - res=IStream_Write(pStm,&len,sizeof(DWORD),NULL); - - /* write filePath string type A */ - filePathA=HeapAlloc(GetProcessHeap(),0,len); - WideCharToMultiByte( CP_ACP, 0, filePathW, -1, filePathA, len, NULL, NULL ); - res=IStream_Write(pStm,filePathA,len,NULL); - HeapFree(GetProcessHeap(),0,filePathA); - - /* write a DWORD set to 0xDEADFFFF: constant */ - res=IStream_Write(pStm,&constant1,sizeof(DWORD),NULL); - - len--; - /* write 10 times a DWORD set to 0 : constants */ - for(i=0;i<10;i++) - res=IStream_Write(pStm,&zero,sizeof(WORD),NULL); - - if (len>8) - len=0; - - doubleLenHex=doubleLenDec=2*len; - if (len > 5) - doubleLenDec+=6; - - /* write double-length of the path string ( "\0" included )*/ - res=IStream_Write(pStm,&doubleLenDec,sizeof(DWORD),NULL); - - if (len==0) - return res; - - /* write double-length (hexa representation) of the path string ( "\0" included ) */ - res=IStream_Write(pStm,&doubleLenHex,sizeof(DWORD),NULL); - - /* write a WORD set to 0x3: constant */ - res=IStream_Write(pStm,&constant2,sizeof(WORD),NULL); - - /* write path unicode string */ - res=IStream_Write(pStm,filePathW,doubleLenHex,NULL); - - return res; -} - -/****************************************************************************** - * FileMoniker_GetSizeMax - */ -static HRESULT WINAPI -FileMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize) -{ - FileMonikerImpl *This = (FileMonikerImpl *)iface; - DWORD len=lstrlenW(This->filePathName); - DWORD sizeMAx; - - TRACE("(%p,%p)\n",iface,pcbSize); - - if (!pcbSize) - return E_POINTER; - - /* for more details see FileMonikerImpl_Save coments */ - - sizeMAx = sizeof(WORD) + /* first WORD is 0 */ - sizeof(DWORD)+ /* length of filePath including "\0" in the end of the string */ - (len+1)+ /* filePath string */ - sizeof(DWORD)+ /* constant : 0xDEADFFFF */ - 10*sizeof(WORD)+ /* 10 zero WORD */ - sizeof(DWORD); /* size of the unicode filePath: "\0" not included */ - - if (len==0 || len > 8) - return S_OK; - - sizeMAx += sizeof(DWORD)+ /* size of the unicode filePath: "\0" not included */ - sizeof(WORD)+ /* constant : 0x3 */ - len*sizeof(WCHAR); /* unicde filePath string */ - - pcbSize->u.LowPart=sizeMAx; - pcbSize->u.HighPart=0; - - return S_OK; -} - -/****************************************************************************** - * FileMoniker_Destroy (local function) - *******************************************************************************/ -HRESULT WINAPI FileMonikerImpl_Destroy(FileMonikerImpl* This) -{ - TRACE("(%p)\n",This); - - if (This->pMarshal) IUnknown_Release(This->pMarshal); - HeapFree(GetProcessHeap(),0,This->filePathName); - HeapFree(GetProcessHeap(),0,This); - - return S_OK; -} - -/****************************************************************************** - * FileMoniker_BindToObject - */ -static HRESULT WINAPI -FileMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, - REFIID riid, VOID** ppvResult) -{ - HRESULT res=E_FAIL; - CLSID clsID; - IUnknown* pObj=0; - IRunningObjectTable *prot=0; - IPersistFile *ppf=0; - IClassFactory *pcf=0; - IClassActivator *pca=0; - - FileMonikerImpl *This = (FileMonikerImpl *)iface; - - *ppvResult=0; - - TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvResult); - - if(pmkToLeft==NULL){ - - res=IBindCtx_GetRunningObjectTable(pbc,&prot); - - if (SUCCEEDED(res)){ - /* if the requested class was loaded before ! we don't need to reload it */ - res = IRunningObjectTable_GetObject(prot,iface,&pObj); - - if (res==S_FALSE){ - /* first activation of this class */ - res=GetClassFile(This->filePathName,&clsID); - if (SUCCEEDED(res)){ - - res=CoCreateInstance(&clsID,NULL,CLSCTX_ALL,&IID_IPersistFile,(void**)&ppf); - if (SUCCEEDED(res)){ - - res=IPersistFile_Load(ppf,This->filePathName,STGM_READ); - if (SUCCEEDED(res)){ - - pObj=(IUnknown*)ppf; - IUnknown_AddRef(pObj); - } - } - } - } - } - } - else{ - res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IClassFactory,(void**)&pcf); - - if (res==E_NOINTERFACE){ - - res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IClassActivator,(void**)&pca); - - if (res==E_NOINTERFACE) - return MK_E_INTERMEDIATEINTERFACENOTSUPPORTED; - } - if (pcf!=NULL){ - - IClassFactory_CreateInstance(pcf,NULL,&IID_IPersistFile,(void**)ppf); - - res=IPersistFile_Load(ppf,This->filePathName,STGM_READ); - - if (SUCCEEDED(res)){ - - pObj=(IUnknown*)ppf; - IUnknown_AddRef(pObj); - } - } - if (pca!=NULL){ - - FIXME("()\n"); - - /*res=GetClassFile(This->filePathName,&clsID); - - if (SUCCEEDED(res)){ - - res=IClassActivator_GetClassObject(pca,&clsID,CLSCTX_ALL,0,&IID_IPersistFile,(void**)&ppf); - - if (SUCCEEDED(res)){ - - pObj=(IUnknown*)ppf; - IUnknown_AddRef(pObj); - } - }*/ - } - } - - if (pObj!=NULL){ - /* get the requested interface from the loaded class */ - res= IUnknown_QueryInterface(pObj,riid,ppvResult); - - IBindCtx_RegisterObjectBound(pbc,(IUnknown*)*ppvResult); - - IUnknown_Release(pObj); - } - - if (prot!=NULL) - IRunningObjectTable_Release(prot); - - if (ppf!=NULL) - IPersistFile_Release(ppf); - - if (pca!=NULL) - IClassActivator_Release(pca); - - if (pcf!=NULL) - IClassFactory_Release(pcf); - - return res; -} - -/****************************************************************************** - * FileMoniker_BindToStorage - */ -static HRESULT WINAPI -FileMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, - REFIID riid, VOID** ppvObject) -{ - LPOLESTR filePath=0; - IStorage *pstg=0; - HRESULT res; - - TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvObject); - - if (pmkToLeft==NULL){ - - if (IsEqualIID(&IID_IStorage, riid)){ - - /* get the file name */ - IMoniker_GetDisplayName(iface,pbc,pmkToLeft,&filePath); - - /* verifie if the file contains a storage object */ - res=StgIsStorageFile(filePath); - - if(res==S_OK){ - - res=StgOpenStorage(filePath,NULL,STGM_READWRITE|STGM_SHARE_DENY_WRITE,NULL,0,&pstg); - - if (SUCCEEDED(res)){ - - *ppvObject=pstg; - - IStorage_AddRef(pstg); - - return res; - } - } - CoTaskMemFree(filePath); - } - else - if ( (IsEqualIID(&IID_IStream, riid)) || (IsEqualIID(&IID_ILockBytes, riid)) ) - return E_FAIL; - else - return E_NOINTERFACE; - } - else { - - FIXME("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvObject); - - return E_NOTIMPL; - } - return res; -} - -/****************************************************************************** - * FileMoniker_Reduce - ******************************************************************************/ -static HRESULT WINAPI -FileMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar, - IMoniker** ppmkToLeft, IMoniker** ppmkReduced) -{ - TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); - - if (ppmkReduced==NULL) - return E_POINTER; - - IMoniker_AddRef(iface); - - *ppmkReduced=iface; - - return MK_S_REDUCED_TO_SELF; -} - -/****************************************************************************** - * FileMoniker_ComposeWith - */ -static HRESULT WINAPI -FileMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight, - BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite) -{ - HRESULT res; - LPOLESTR str1=0,str2=0,*strDec1=0,*strDec2=0,newStr=0; - static const WCHAR twoPoint[]={'.','.',0}; - static const WCHAR bkSlash[]={'\\',0}; - IBindCtx *bind=0; - int i=0,j=0,lastIdx1=0,lastIdx2=0; - DWORD mkSys; - - TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite); - - if (ppmkComposite==NULL) - return E_POINTER; - - if (pmkRight==NULL) - return E_INVALIDARG; - - *ppmkComposite=0; - - IMoniker_IsSystemMoniker(pmkRight,&mkSys); - - /* check if we have two filemonikers to compose or not */ - if(mkSys==MKSYS_FILEMONIKER){ - - CreateBindCtx(0,&bind); - - IMoniker_GetDisplayName(iface,bind,NULL,&str1); - IMoniker_GetDisplayName(pmkRight,bind,NULL,&str2); - - /* decompose pathnames of the two monikers : (to prepare the path merge operation ) */ - lastIdx1=FileMonikerImpl_DecomposePath(str1,&strDec1)-1; - lastIdx2=FileMonikerImpl_DecomposePath(str2,&strDec2)-1; - - if ((lastIdx1==-1 && lastIdx2>-1)||(lastIdx1==1 && lstrcmpW(strDec1[0],twoPoint)==0)) - return MK_E_SYNTAX; - - if(lstrcmpW(strDec1[lastIdx1],bkSlash)==0) - lastIdx1--; - - /* for etch "..\" in the left of str2 remove the right element from str1 */ - for(i=0; ( (lastIdx1>=0) && (strDec2[i]!=NULL) && (lstrcmpW(strDec2[i],twoPoint)==0) ) ;i+=2){ - - lastIdx1-=2; - } - - /* the length of the composed path string is raised by the sum of the two paths lengths */ - newStr=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(lstrlenW(str1)+lstrlenW(str2)+1)); - - if (newStr==NULL) - return E_OUTOFMEMORY; - - /* new path is the concatenation of the rest of str1 and str2 */ - for(*newStr=0,j=0;j<=lastIdx1;j++) - strcatW(newStr,strDec1[j]); - - if ((strDec2[i]==NULL && lastIdx1>-1 && lastIdx2>-1) || lstrcmpW(strDec2[i],bkSlash)!=0) - strcatW(newStr,bkSlash); - - for(j=i;j<=lastIdx2;j++) - strcatW(newStr,strDec2[j]); - - /* create a new moniker with the new string */ - res=CreateFileMoniker(newStr,ppmkComposite); - - /* free all strings space memory used by this function */ - HeapFree(GetProcessHeap(),0,newStr); - - for(i=0; strDec1[i]!=NULL;i++) - CoTaskMemFree(strDec1[i]); - for(i=0; strDec2[i]!=NULL;i++) - CoTaskMemFree(strDec2[i]); - CoTaskMemFree(strDec1); - CoTaskMemFree(strDec2); - - CoTaskMemFree(str1); - CoTaskMemFree(str2); - - return res; - } - else if(mkSys==MKSYS_ANTIMONIKER){ - - *ppmkComposite=NULL; - return S_OK; - } - else if (fOnlyIfNotGeneric){ - - *ppmkComposite=NULL; - return MK_E_NEEDGENERIC; - } - else - - return CreateGenericComposite(iface,pmkRight,ppmkComposite); -} - -/****************************************************************************** - * FileMoniker_Enum - */ -static HRESULT WINAPI -FileMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker) -{ - TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker); - - if (ppenumMoniker == NULL) - return E_POINTER; - - *ppenumMoniker = NULL; - - return S_OK; -} - -/****************************************************************************** - * FileMoniker_IsEqual - */ -static HRESULT WINAPI -FileMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker) -{ - FileMonikerImpl *This = (FileMonikerImpl *)iface; - CLSID clsid; - LPOLESTR filePath; - IBindCtx* bind; - HRESULT res; - - TRACE("(%p,%p)\n",iface,pmkOtherMoniker); - - if (pmkOtherMoniker==NULL) - return S_FALSE; - - IMoniker_GetClassID(pmkOtherMoniker,&clsid); - - if (!IsEqualCLSID(&clsid,&CLSID_FileMoniker)) - return S_FALSE; - - res = CreateBindCtx(0,&bind); - if (FAILED(res)) return res; - - if (SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&filePath))) { - int result = lstrcmpiW(filePath, This->filePathName); - CoTaskMemFree(filePath); - if ( result == 0 ) return S_OK; - } - return S_FALSE; - -} - -/****************************************************************************** - * FileMoniker_Hash - */ -static HRESULT WINAPI -FileMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash) -{ - FileMonikerImpl *This = (FileMonikerImpl *)iface; - - int h = 0,i,skip,len; - int off = 0; - LPOLESTR val; - - if (pdwHash==NULL) - return E_POINTER; - - val = This->filePathName; - len = lstrlenW(val); - - if (len < 16) { - for (i = len ; i > 0; i--) { - h = (h * 37) + val[off++]; - } - } else { - /* only sample some characters */ - skip = len / 8; - for (i = len ; i > 0; i -= skip, off += skip) { - h = (h * 39) + val[off]; - } - } - - *pdwHash=h; - - return S_OK; -} - -/****************************************************************************** - * FileMoniker_IsRunning - */ -static HRESULT WINAPI -FileMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, - IMoniker* pmkNewlyRunning) -{ - IRunningObjectTable* rot; - HRESULT res; - - TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning); - - if ( (pmkNewlyRunning!=NULL) && (IMoniker_IsEqual(pmkNewlyRunning,iface)==S_OK) ) - return S_OK; - - if (pbc==NULL) - return E_POINTER; - - res=IBindCtx_GetRunningObjectTable(pbc,&rot); - - if (FAILED(res)) - return res; - - res = IRunningObjectTable_IsRunning(rot,iface); - - IRunningObjectTable_Release(rot); - - return res; -} - -/****************************************************************************** - * FileMoniker_GetTimeOfLastChange - ******************************************************************************/ -static HRESULT WINAPI -FileMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc, - IMoniker* pmkToLeft, FILETIME* pFileTime) -{ - FileMonikerImpl *This = (FileMonikerImpl *)iface; - IRunningObjectTable* rot; - HRESULT res; - WIN32_FILE_ATTRIBUTE_DATA info; - - TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pFileTime); - - if (pFileTime==NULL) - return E_POINTER; - - if (pmkToLeft!=NULL) - return E_INVALIDARG; - - res=IBindCtx_GetRunningObjectTable(pbc,&rot); - - if (FAILED(res)) - return res; - - res= IRunningObjectTable_GetTimeOfLastChange(rot,iface,pFileTime); - - if (FAILED(res)){ /* the moniker is not registered */ - - if (!GetFileAttributesExW(This->filePathName,GetFileExInfoStandard,&info)) - return MK_E_NOOBJECT; - - *pFileTime=info.ftLastWriteTime; - } - - return S_OK; -} - -/****************************************************************************** - * FileMoniker_Inverse - */ -static HRESULT WINAPI -FileMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk) -{ - TRACE("(%p,%p)\n",iface,ppmk); - - return CreateAntiMoniker(ppmk); -} - -/****************************************************************************** - * FileMoniker_CommonPrefixWith - */ -static HRESULT WINAPI -FileMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix) -{ - - LPOLESTR pathThis,pathOther,*stringTable1,*stringTable2,commonPath; - IBindCtx *pbind; - DWORD mkSys; - ULONG nb1,nb2,i,sameIdx; - BOOL machimeNameCase=FALSE; - - if (ppmkPrefix==NULL) - return E_POINTER; - - if (pmkOther==NULL) - return E_INVALIDARG; - - *ppmkPrefix=0; - - /* check if we have the same type of moniker */ - IMoniker_IsSystemMoniker(pmkOther,&mkSys); - - if(mkSys==MKSYS_FILEMONIKER){ - HRESULT ret; - - CreateBindCtx(0,&pbind); - - /* create a string based on common part of the two paths */ - - IMoniker_GetDisplayName(iface,pbind,NULL,&pathThis); - IMoniker_GetDisplayName(pmkOther,pbind,NULL,&pathOther); - - nb1=FileMonikerImpl_DecomposePath(pathThis,&stringTable1); - nb2=FileMonikerImpl_DecomposePath(pathOther,&stringTable2); - - if (nb1==0 || nb2==0) - return MK_E_NOPREFIX; - - commonPath=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(min(lstrlenW(pathThis),lstrlenW(pathOther))+1)); - - *commonPath=0; - - for(sameIdx=0; ( (stringTable1[sameIdx]!=NULL) && - (stringTable2[sameIdx]!=NULL) && - (lstrcmpiW(stringTable1[sameIdx],stringTable2[sameIdx])==0)); sameIdx++); - - if (sameIdx > 1 && *stringTable1[0]=='\\' && *stringTable2[1]=='\\'){ - - machimeNameCase=TRUE; - - for(i=2;i<sameIdx;i++) - - if( (*stringTable1[i]=='\\') && (i+1 < sameIdx) && (*stringTable1[i+1]=='\\') ){ - machimeNameCase=FALSE; - break; - } - } - - if (machimeNameCase && *stringTable1[sameIdx-1]=='\\') - sameIdx--; - - if (machimeNameCase && (sameIdx<=3) && (nb1 > 3 || nb2 > 3) ) - ret = MK_E_NOPREFIX; - else - { - for(i=0;i<sameIdx;i++) - strcatW(commonPath,stringTable1[i]); - - for(i=0;i<nb1;i++) - CoTaskMemFree(stringTable1[i]); - - CoTaskMemFree(stringTable1); - - for(i=0;i<nb2;i++) - CoTaskMemFree(stringTable2[i]); - - CoTaskMemFree(stringTable2); - - ret = CreateFileMoniker(commonPath,ppmkPrefix); - } - HeapFree(GetProcessHeap(),0,commonPath); - return ret; - } - else - return MonikerCommonPrefixWith(iface,pmkOther,ppmkPrefix); -} - -/****************************************************************************** - * DecomposePath (local function) - */ -int FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable) -{ - static const WCHAR bSlash[] = {'\\',0}; - WCHAR word[MAX_PATH]; - int i=0,j,tabIndex=0; - LPOLESTR *strgtable ; - - int len=lstrlenW(str); - - TRACE("%s, %p\n", debugstr_w(str), *stringTable); - - strgtable =CoTaskMemAlloc(len*sizeof(LPOLESTR)); - - if (strgtable==NULL) - return E_OUTOFMEMORY; - - while(str[i]!=0){ - - if(str[i]==bSlash[0]){ - - strgtable[tabIndex]=CoTaskMemAlloc(2*sizeof(WCHAR)); - - if (strgtable[tabIndex]==NULL) - return E_OUTOFMEMORY; - - strcpyW(strgtable[tabIndex++],bSlash); - - i++; - - } - else { - - for(j=0; str[i]!=0 && str[i]!=bSlash[0] ; i++,j++) - word[j]=str[i]; - - word[j]=0; - - strgtable[tabIndex]=CoTaskMemAlloc(sizeof(WCHAR)*(j+1)); - - if (strgtable[tabIndex]==NULL) - return E_OUTOFMEMORY; - - strcpyW(strgtable[tabIndex++],word); - } - } - strgtable[tabIndex]=NULL; - - *stringTable=strgtable; - - return tabIndex; -} - -/****************************************************************************** - * FileMoniker_RelativePathTo - */ -static HRESULT WINAPI -FileMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath) -{ - IBindCtx *bind; - HRESULT res; - LPOLESTR str1=0,str2=0,*tabStr1=0,*tabStr2=0,relPath=0; - DWORD len1=0,len2=0,sameIdx=0,j=0; - static const WCHAR back[] ={'.','.','\\',0}; - - TRACE("(%p,%p,%p)\n",iface,pmOther,ppmkRelPath); - - if (ppmkRelPath==NULL) - return E_POINTER; - - if (pmOther==NULL) - return E_INVALIDARG; - - res=CreateBindCtx(0,&bind); - if (FAILED(res)) - return res; - - res=IMoniker_GetDisplayName(iface,bind,NULL,&str1); - if (FAILED(res)) - return res; - res=IMoniker_GetDisplayName(pmOther,bind,NULL,&str2); - if (FAILED(res)) - return res; - - len1=FileMonikerImpl_DecomposePath(str1,&tabStr1); - len2=FileMonikerImpl_DecomposePath(str2,&tabStr2); - - if (FAILED(len1) || FAILED(len2)) - return E_OUTOFMEMORY; - - /* count the number of similar items from the begin of the two paths */ - for(sameIdx=0; ( (tabStr1[sameIdx]!=NULL) && - (tabStr2[sameIdx]!=NULL) && - (lstrcmpiW(tabStr1[sameIdx],tabStr2[sameIdx])==0)); sameIdx++); - - /* begin the construction of relativePath */ - /* if the two paths have a consecutive similar item from the begin ! the relativePath will be composed */ - /* by "..\\" in the begin */ - relPath=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(1+lstrlenW(str1)+lstrlenW(str2))); - - *relPath=0; - - if (len2>0 && !(len1==1 && len2==1 && sameIdx==0)) - for(j=sameIdx;(tabStr1[j] != NULL); j++) - if (*tabStr1[j]!='\\') - strcatW(relPath,back); - - /* add items of the second path (similar items with the first path are not included) to the relativePath */ - for(j=sameIdx;tabStr2[j]!=NULL;j++) - strcatW(relPath,tabStr2[j]); - - res=CreateFileMoniker(relPath,ppmkRelPath); - - for(j=0; tabStr1[j]!=NULL;j++) - CoTaskMemFree(tabStr1[j]); - for(j=0; tabStr2[j]!=NULL;j++) - CoTaskMemFree(tabStr2[j]); - CoTaskMemFree(tabStr1); - CoTaskMemFree(tabStr2); - CoTaskMemFree(str1); - CoTaskMemFree(str2); - HeapFree(GetProcessHeap(),0,relPath); - - if (len1==0 || len2==0 || (len1==1 && len2==1 && sameIdx==0)) - return MK_S_HIM; - - return res; -} - -/****************************************************************************** - * FileMoniker_GetDisplayName - */ -static HRESULT WINAPI -FileMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc, - IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName) -{ - FileMonikerImpl *This = (FileMonikerImpl *)iface; - - int len=lstrlenW(This->filePathName); - - TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName); - - if (ppszDisplayName==NULL) - return E_POINTER; - - if (pmkToLeft!=NULL) - return E_INVALIDARG; - - *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR)*(len+1)); - if (*ppszDisplayName==NULL) - return E_OUTOFMEMORY; - - strcpyW(*ppszDisplayName,This->filePathName); - - TRACE("-- %s\n", debugstr_w(*ppszDisplayName)); - - return S_OK; -} - -/****************************************************************************** - * FileMoniker_ParseDisplayName - */ -static HRESULT WINAPI -FileMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, - LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut) -{ - FIXME("(%p,%p,%p,%p,%p,%p),stub!\n",iface,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut); - return E_NOTIMPL; -} - -/****************************************************************************** - * FileMoniker_IsSystemMoniker - */ -static HRESULT WINAPI -FileMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys) -{ - TRACE("(%p,%p)\n",iface,pwdMksys); - - if (!pwdMksys) - return E_POINTER; - - (*pwdMksys)=MKSYS_FILEMONIKER; - - return S_OK; -} - -/******************************************************************************* - * FileMonikerIROTData_QueryInterface - */ -static HRESULT WINAPI -FileMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject) -{ - - ICOM_THIS_From_IROTData(IMoniker, iface); - - TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject); - - return FileMonikerImpl_QueryInterface(This, riid, ppvObject); -} - -/*********************************************************************** - * FileMonikerIROTData_AddRef - */ -static ULONG WINAPI -FileMonikerROTDataImpl_AddRef(IROTData *iface) -{ - ICOM_THIS_From_IROTData(IMoniker, iface); - - TRACE("(%p)\n",This); - - return IMoniker_AddRef(This); -} - -/*********************************************************************** - * FileMonikerIROTData_Release - */ -static ULONG WINAPI -FileMonikerROTDataImpl_Release(IROTData* iface) -{ - ICOM_THIS_From_IROTData(IMoniker, iface); - - TRACE("(%p)\n",This); - - return FileMonikerImpl_Release(This); -} - -/****************************************************************************** - * FileMonikerIROTData_GetComparaisonData - */ -static HRESULT WINAPI -FileMonikerROTDataImpl_GetComparisonData(IROTData* iface, BYTE* pbData, - ULONG cbMax, ULONG* pcbData) -{ - ICOM_THIS_From_IROTData(IMoniker, iface); - FileMonikerImpl *This1 = (FileMonikerImpl *)This; - int len = (strlenW(This1->filePathName)+1); - int i; - LPWSTR pszFileName; - - TRACE("(%p, %lu, %p)\n", pbData, cbMax, pcbData); - - *pcbData = sizeof(CLSID) + len * sizeof(WCHAR); - if (cbMax < *pcbData) - return E_OUTOFMEMORY; - - memcpy(pbData, &CLSID_FileMoniker, sizeof(CLSID)); - pszFileName = (LPWSTR)(pbData+sizeof(CLSID)); - for (i = 0; i < len; i++) - pszFileName[i] = toupperW(This1->filePathName[i]); - - return S_OK; -} - -/* - * Virtual function table for the FileMonikerImpl class which include IPersist, - * IPersistStream and IMoniker functions. - */ -static IMonikerVtbl VT_FileMonikerImpl = -{ - FileMonikerImpl_QueryInterface, - FileMonikerImpl_AddRef, - FileMonikerImpl_Release, - FileMonikerImpl_GetClassID, - FileMonikerImpl_IsDirty, - FileMonikerImpl_Load, - FileMonikerImpl_Save, - FileMonikerImpl_GetSizeMax, - FileMonikerImpl_BindToObject, - FileMonikerImpl_BindToStorage, - FileMonikerImpl_Reduce, - FileMonikerImpl_ComposeWith, - FileMonikerImpl_Enum, - FileMonikerImpl_IsEqual, - FileMonikerImpl_Hash, - FileMonikerImpl_IsRunning, - FileMonikerImpl_GetTimeOfLastChange, - FileMonikerImpl_Inverse, - FileMonikerImpl_CommonPrefixWith, - FileMonikerImpl_RelativePathTo, - FileMonikerImpl_GetDisplayName, - FileMonikerImpl_ParseDisplayName, - FileMonikerImpl_IsSystemMoniker -}; - -/* Virtual function table for the IROTData class. */ -static IROTDataVtbl VT_ROTDataImpl = -{ - FileMonikerROTDataImpl_QueryInterface, - FileMonikerROTDataImpl_AddRef, - FileMonikerROTDataImpl_Release, - FileMonikerROTDataImpl_GetComparisonData -}; - -/****************************************************************************** - * FileMoniker_Construct (local function) - */ -static HRESULT WINAPI -FileMonikerImpl_Construct(FileMonikerImpl* This, LPCOLESTR lpszPathName) -{ - int nb=0,i; - int sizeStr=lstrlenW(lpszPathName); - LPOLESTR *tabStr=0; - static const WCHAR twoPoint[]={'.','.',0}; - static const WCHAR bkSlash[]={'\\',0}; - BYTE addBkSlash; - - TRACE("(%p,%s)\n",This,debugstr_w(lpszPathName)); - - /* Initialize the virtual fgunction table. */ - This->lpvtbl1 = &VT_FileMonikerImpl; - This->lpvtbl2 = &VT_ROTDataImpl; - This->ref = 0; - This->pMarshal = NULL; - - This->filePathName=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr+1)); - - if (This->filePathName==NULL) - return E_OUTOFMEMORY; - - strcpyW(This->filePathName,lpszPathName); - - nb=FileMonikerImpl_DecomposePath(This->filePathName,&tabStr); - - if (nb > 0 ){ - - addBkSlash=1; - if (lstrcmpW(tabStr[0],twoPoint)!=0) - addBkSlash=0; - else - for(i=0;i<nb;i++){ - - if ( (lstrcmpW(tabStr[i],twoPoint)!=0) && (lstrcmpW(tabStr[i],bkSlash)!=0) ){ - addBkSlash=0; - break; - } - else - - if (lstrcmpW(tabStr[i],bkSlash)==0 && i<nb-1 && lstrcmpW(tabStr[i+1],bkSlash)==0){ - *tabStr[i]=0; - sizeStr--; - addBkSlash=0; - break; - } - } - - if (lstrcmpW(tabStr[nb-1],bkSlash)==0) - addBkSlash=0; - - This->filePathName=HeapReAlloc(GetProcessHeap(),0,This->filePathName,(sizeStr+1)*sizeof(WCHAR)); - - *This->filePathName=0; - - for(i=0;tabStr[i]!=NULL;i++) - strcatW(This->filePathName,tabStr[i]); - - if (addBkSlash) - strcatW(This->filePathName,bkSlash); - } - - for(i=0; tabStr[i]!=NULL;i++) - CoTaskMemFree(tabStr[i]); - CoTaskMemFree(tabStr); - - return S_OK; -} - -/****************************************************************************** - * CreateFileMoniker (OLE32.@) - ******************************************************************************/ -HRESULT WINAPI CreateFileMoniker(LPCOLESTR lpszPathName, LPMONIKER * ppmk) -{ - FileMonikerImpl* newFileMoniker; - HRESULT hr; - - TRACE("(%s,%p)\n",debugstr_w(lpszPathName),ppmk); - - if (!ppmk) - return E_POINTER; - - if(!lpszPathName) - return MK_E_SYNTAX; - - *ppmk=NULL; - - newFileMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(FileMonikerImpl)); - - if (!newFileMoniker) - return E_OUTOFMEMORY; - - hr = FileMonikerImpl_Construct(newFileMoniker,lpszPathName); - - if (SUCCEEDED(hr)) - hr = FileMonikerImpl_QueryInterface((IMoniker*)newFileMoniker,&IID_IMoniker,(void**)ppmk); - else - HeapFree(GetProcessHeap(),0,newFileMoniker); - - return hr; -} - -static HRESULT WINAPI FileMonikerCF_QueryInterface(LPCLASSFACTORY iface, - REFIID riid, LPVOID *ppv) -{ - *ppv = NULL; - if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) - { - *ppv = iface; - IUnknown_AddRef(iface); - return S_OK; - } - return E_NOINTERFACE; -} - -static ULONG WINAPI FileMonikerCF_AddRef(LPCLASSFACTORY iface) -{ - return 2; /* non-heap based object */ -} - -static ULONG WINAPI FileMonikerCF_Release(LPCLASSFACTORY iface) -{ - return 1; /* non-heap based object */ -} - -static HRESULT WINAPI FileMonikerCF_CreateInstance(LPCLASSFACTORY iface, - LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv) -{ - FileMonikerImpl* newFileMoniker; - HRESULT hr; - static const WCHAR wszEmpty[] = { 0 }; - - TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv); - - *ppv = NULL; - - if (pUnk) - return CLASS_E_NOAGGREGATION; - - newFileMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(FileMonikerImpl)); - if (!newFileMoniker) - return E_OUTOFMEMORY; - - hr = FileMonikerImpl_Construct(newFileMoniker, wszEmpty); - - if (SUCCEEDED(hr)) - hr = FileMonikerImpl_QueryInterface((IMoniker*)newFileMoniker, riid, ppv); - if (FAILED(hr)) - HeapFree(GetProcessHeap(),0,newFileMoniker); - - return hr; -} - -static HRESULT WINAPI FileMonikerCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) -{ - FIXME("(%d), stub!\n",fLock); - return S_OK; -} - -static const IClassFactoryVtbl FileMonikerCFVtbl = -{ - FileMonikerCF_QueryInterface, - FileMonikerCF_AddRef, - FileMonikerCF_Release, - FileMonikerCF_CreateInstance, - FileMonikerCF_LockServer -}; -static const IClassFactoryVtbl *FileMonikerCF = &FileMonikerCFVtbl; - -HRESULT FileMonikerCF_Create(REFIID riid, LPVOID *ppv) -{ - return IClassFactory_QueryInterface((IClassFactory *)&FileMonikerCF, riid, ppv); -} +/* + * FileMonikers implementation + * + * Copyright 1999 Noomen Hamza + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <assert.h> +#include <stdarg.h> +#include <string.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winnls.h" +#include "wine/unicode.h" +#include "wine/debug.h" +#include "objbase.h" +#include "moniker.h" + +#include "compobj_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +const CLSID CLSID_FileMoniker = { + 0x303, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46} +}; + +/* filemoniker data structure */ +typedef struct FileMonikerImpl{ + + IMonikerVtbl* lpvtbl1; /* VTable relative to the IMoniker interface.*/ + + /* The ROT (RunningObjectTable implementation) uses the IROTData interface to test whether + * two monikers are equal. That's whay IROTData interface is implemented by monikers. + */ + IROTDataVtbl* lpvtbl2; /* VTable relative to the IROTData interface.*/ + + ULONG ref; /* reference counter for this object */ + + LPOLESTR filePathName; /* path string identified by this filemoniker */ + + IUnknown *pMarshal; /* custom marshaler */ +} FileMonikerImpl; + +/* Local function used by filemoniker implementation */ +static HRESULT WINAPI FileMonikerImpl_Construct(FileMonikerImpl* iface, LPCOLESTR lpszPathName); +static HRESULT WINAPI FileMonikerImpl_Destroy(FileMonikerImpl* iface); + +/******************************************************************************* + * FileMoniker_QueryInterface + */ +static HRESULT WINAPI +FileMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject) +{ + FileMonikerImpl *This = (FileMonikerImpl *)iface; + + TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject); + + /* Perform a sanity check on the parameters.*/ + if ( (This==0) || (ppvObject==0) ) + return E_INVALIDARG; + + /* Initialize the return parameter */ + *ppvObject = 0; + + /* Compare the riid with the interface IDs implemented by this object.*/ + if (IsEqualIID(&IID_IUnknown, riid) || + IsEqualIID(&IID_IPersist, riid) || + IsEqualIID(&IID_IPersistStream,riid) || + IsEqualIID(&IID_IMoniker, riid) + ) + *ppvObject = iface; + + else if (IsEqualIID(&IID_IROTData, riid)) + *ppvObject = (IROTData*)&(This->lpvtbl2); + else if (IsEqualIID(&IID_IMarshal, riid)) + { + HRESULT hr = S_OK; + if (!This->pMarshal) + hr = MonikerMarshal_Create(iface, &This->pMarshal); + if (hr != S_OK) + return hr; + return IUnknown_QueryInterface(This->pMarshal, riid, ppvObject); + } + + /* Check that we obtained an interface.*/ + if ((*ppvObject)==0) + return E_NOINTERFACE; + + /* Query Interface always increases the reference count by one when it is successful */ + IMoniker_AddRef(iface); + + return S_OK; +} + +/****************************************************************************** + * FileMoniker_AddRef + */ +static ULONG WINAPI +FileMonikerImpl_AddRef(IMoniker* iface) +{ + FileMonikerImpl *This = (FileMonikerImpl *)iface; + + TRACE("(%p)\n",iface); + + return InterlockedIncrement(&This->ref); +} + +/****************************************************************************** + * FileMoniker_Release + */ +static ULONG WINAPI +FileMonikerImpl_Release(IMoniker* iface) +{ + FileMonikerImpl *This = (FileMonikerImpl *)iface; + ULONG ref; + + TRACE("(%p)\n",iface); + + ref = InterlockedDecrement(&This->ref); + + /* destroy the object if there's no more reference on it */ + if (ref == 0) FileMonikerImpl_Destroy(This); + + return ref; +} + +/****************************************************************************** + * FileMoniker_GetClassID + */ +static HRESULT WINAPI +FileMonikerImpl_GetClassID(IMoniker* iface, CLSID *pClassID) +{ + TRACE("(%p,%p)\n",iface,pClassID); + + if (pClassID==NULL) + return E_POINTER; + + *pClassID = CLSID_FileMoniker; + + return S_OK; +} + +/****************************************************************************** + * FileMoniker_IsDirty + * + * Note that the OLE-provided implementations of the IPersistStream::IsDirty + * method in the OLE-provided moniker interfaces always return S_FALSE because + * their internal state never changes. + */ +static HRESULT WINAPI +FileMonikerImpl_IsDirty(IMoniker* iface) +{ + + TRACE("(%p)\n",iface); + + return S_FALSE; +} + +/****************************************************************************** + * FileMoniker_Load + * + * this function locates and reads from the stream the filePath string + * written by FileMonikerImpl_Save + */ +static HRESULT WINAPI +FileMonikerImpl_Load(IMoniker* iface,IStream* pStm) +{ + HRESULT res; + CHAR* filePathA; + WCHAR* filePathW; + ULONG bread; + WORD wbuffer; + DWORD dwbuffer,length,i,doubleLenHex,doubleLenDec; + + FileMonikerImpl *This = (FileMonikerImpl *)iface; + + TRACE("(%p,%p)\n",iface,pStm); + + /* first WORD is non significative */ + res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread); + if (bread!=sizeof(WORD) || wbuffer!=0) + { + ERR("Couldn't read 0 word\n"); + return E_FAIL; + } + + /* read filePath string length (plus one) */ + res=IStream_Read(pStm,&length,sizeof(DWORD),&bread); + if (bread != sizeof(DWORD)) + { + ERR("Couldn't read file string length\n"); + return E_FAIL; + } + + /* read filePath string */ + filePathA=HeapAlloc(GetProcessHeap(),0,length); + res=IStream_Read(pStm,filePathA,length,&bread); + HeapFree(GetProcessHeap(),0,filePathA); + if (bread != length) + { + ERR("Couldn't read file path string\n"); + return E_FAIL; + } + + /* read the first constant */ + IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread); + if (bread != sizeof(DWORD) || dwbuffer != 0xDEADFFFF) + { + ERR("Couldn't read 0xDEADFFFF constant\n"); + return E_FAIL; + } + + length--; + + for(i=0;i<10;i++){ + res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread); + if (bread!=sizeof(WORD) || wbuffer!=0) + { + ERR("Couldn't read 0 padding\n"); + return E_FAIL; + } + } + + if (length>8) + length=0; + + doubleLenHex=doubleLenDec=2*length; + if (length > 5) + doubleLenDec+=6; + + res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread); + if (bread!=sizeof(DWORD) || dwbuffer!=doubleLenDec) + return E_FAIL; + + if (length==0) + return res; + + res=IStream_Read(pStm,&dwbuffer,sizeof(DWORD),&bread); + if (bread!=sizeof(DWORD) || dwbuffer!=doubleLenHex) + return E_FAIL; + + res=IStream_Read(pStm,&wbuffer,sizeof(WORD),&bread); + if (bread!=sizeof(WORD) || wbuffer!=0x3) + return E_FAIL; + + filePathW=HeapAlloc(GetProcessHeap(),0,(length+1)*sizeof(WCHAR)); + filePathW[length]=0; + res=IStream_Read(pStm,filePathW,doubleLenHex,&bread); + if (bread!=doubleLenHex) { + HeapFree(GetProcessHeap(), 0, filePathW); + return E_FAIL; + } + + HeapFree(GetProcessHeap(),0,This->filePathName); + + This->filePathName=filePathW; + + return res; +} + +/****************************************************************************** + * FileMoniker_Save + * + * This function saves data of this object. In the beginning I thougth + * that I have just to write the filePath string on Stream. But, when I + * tested this function whith windows programs samples, I noticed that it + * was not the case. So I analysed data written by this function on + * Windows and what this did function exactly ! But I have no idea about + * its logic ! + * I guessed data which must be written on stream is: + * 1) WORD constant:zero + * 2) length of the path string ("\0" included) + * 3) path string type A + * 4) DWORD constant : 0xDEADFFFF + * 5) ten WORD constant: zero + * 6) DWORD: double-length of the the path string type W ("\0" not + * included) + * 7) WORD constant: 0x3 + * 8) filePath unicode string. + * if the length(filePath) > 8 or length(filePath) == 8 stop at step 5) + */ +static HRESULT WINAPI +FileMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty) +{ + FileMonikerImpl *This = (FileMonikerImpl *)iface; + + HRESULT res; + LPOLESTR filePathW=This->filePathName; + CHAR* filePathA; + DWORD len; + + DWORD constant1 = 0xDEADFFFF; /* these constants are detected after analysing the data structure written by */ + WORD constant2 = 0x3; /* FileMoniker_Save function in a windows program system */ + + WORD zero=0; + DWORD doubleLenHex; + DWORD doubleLenDec; + int i=0; + + TRACE("(%p,%p,%d)\n",iface,pStm,fClearDirty); + + if (pStm==NULL) + return E_POINTER; + + /* write a DWORD set to 0 : constant */ + res=IStream_Write(pStm,&zero,sizeof(WORD),NULL); + + /* write length of filePath string ( "\0" included )*/ + len = WideCharToMultiByte( CP_ACP, 0, filePathW, -1, NULL, 0, NULL, NULL ); + res=IStream_Write(pStm,&len,sizeof(DWORD),NULL); + + /* write filePath string type A */ + filePathA=HeapAlloc(GetProcessHeap(),0,len); + WideCharToMultiByte( CP_ACP, 0, filePathW, -1, filePathA, len, NULL, NULL ); + res=IStream_Write(pStm,filePathA,len,NULL); + HeapFree(GetProcessHeap(),0,filePathA); + + /* write a DWORD set to 0xDEADFFFF: constant */ + res=IStream_Write(pStm,&constant1,sizeof(DWORD),NULL); + + len--; + /* write 10 times a DWORD set to 0 : constants */ + for(i=0;i<10;i++) + res=IStream_Write(pStm,&zero,sizeof(WORD),NULL); + + if (len>8) + len=0; + + doubleLenHex=doubleLenDec=2*len; + if (len > 5) + doubleLenDec+=6; + + /* write double-length of the path string ( "\0" included )*/ + res=IStream_Write(pStm,&doubleLenDec,sizeof(DWORD),NULL); + + if (len==0) + return res; + + /* write double-length (hexa representation) of the path string ( "\0" included ) */ + res=IStream_Write(pStm,&doubleLenHex,sizeof(DWORD),NULL); + + /* write a WORD set to 0x3: constant */ + res=IStream_Write(pStm,&constant2,sizeof(WORD),NULL); + + /* write path unicode string */ + res=IStream_Write(pStm,filePathW,doubleLenHex,NULL); + + return res; +} + +/****************************************************************************** + * FileMoniker_GetSizeMax + */ +static HRESULT WINAPI +FileMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize) +{ + FileMonikerImpl *This = (FileMonikerImpl *)iface; + DWORD len=lstrlenW(This->filePathName); + DWORD sizeMAx; + + TRACE("(%p,%p)\n",iface,pcbSize); + + if (!pcbSize) + return E_POINTER; + + /* for more details see FileMonikerImpl_Save coments */ + + sizeMAx = sizeof(WORD) + /* first WORD is 0 */ + sizeof(DWORD)+ /* length of filePath including "\0" in the end of the string */ + (len+1)+ /* filePath string */ + sizeof(DWORD)+ /* constant : 0xDEADFFFF */ + 10*sizeof(WORD)+ /* 10 zero WORD */ + sizeof(DWORD); /* size of the unicode filePath: "\0" not included */ + + if (len==0 || len > 8) + return S_OK; + + sizeMAx += sizeof(DWORD)+ /* size of the unicode filePath: "\0" not included */ + sizeof(WORD)+ /* constant : 0x3 */ + len*sizeof(WCHAR); /* unicde filePath string */ + + pcbSize->u.LowPart=sizeMAx; + pcbSize->u.HighPart=0; + + return S_OK; +} + +/****************************************************************************** + * FileMoniker_Destroy (local function) + *******************************************************************************/ +HRESULT WINAPI FileMonikerImpl_Destroy(FileMonikerImpl* This) +{ + TRACE("(%p)\n",This); + + if (This->pMarshal) IUnknown_Release(This->pMarshal); + HeapFree(GetProcessHeap(),0,This->filePathName); + HeapFree(GetProcessHeap(),0,This); + + return S_OK; +} + +/****************************************************************************** + * FileMoniker_BindToObject + */ +static HRESULT WINAPI +FileMonikerImpl_BindToObject(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, + REFIID riid, VOID** ppvResult) +{ + HRESULT res=E_FAIL; + CLSID clsID; + IUnknown* pObj=0; + IRunningObjectTable *prot=0; + IPersistFile *ppf=0; + IClassFactory *pcf=0; + IClassActivator *pca=0; + + FileMonikerImpl *This = (FileMonikerImpl *)iface; + + *ppvResult=0; + + TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvResult); + + if(pmkToLeft==NULL){ + + res=IBindCtx_GetRunningObjectTable(pbc,&prot); + + if (SUCCEEDED(res)){ + /* if the requested class was loaded before ! we don't need to reload it */ + res = IRunningObjectTable_GetObject(prot,iface,&pObj); + + if (res==S_FALSE){ + /* first activation of this class */ + res=GetClassFile(This->filePathName,&clsID); + if (SUCCEEDED(res)){ + + res=CoCreateInstance(&clsID,NULL,CLSCTX_ALL,&IID_IPersistFile,(void**)&ppf); + if (SUCCEEDED(res)){ + + res=IPersistFile_Load(ppf,This->filePathName,STGM_READ); + if (SUCCEEDED(res)){ + + pObj=(IUnknown*)ppf; + IUnknown_AddRef(pObj); + } + } + } + } + } + } + else{ + res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IClassFactory,(void**)&pcf); + + if (res==E_NOINTERFACE){ + + res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IClassActivator,(void**)&pca); + + if (res==E_NOINTERFACE) + return MK_E_INTERMEDIATEINTERFACENOTSUPPORTED; + } + if (pcf!=NULL){ + + IClassFactory_CreateInstance(pcf,NULL,&IID_IPersistFile,(void**)ppf); + + res=IPersistFile_Load(ppf,This->filePathName,STGM_READ); + + if (SUCCEEDED(res)){ + + pObj=(IUnknown*)ppf; + IUnknown_AddRef(pObj); + } + } + if (pca!=NULL){ + + FIXME("()\n"); + + /*res=GetClassFile(This->filePathName,&clsID); + + if (SUCCEEDED(res)){ + + res=IClassActivator_GetClassObject(pca,&clsID,CLSCTX_ALL,0,&IID_IPersistFile,(void**)&ppf); + + if (SUCCEEDED(res)){ + + pObj=(IUnknown*)ppf; + IUnknown_AddRef(pObj); + } + }*/ + } + } + + if (pObj!=NULL){ + /* get the requested interface from the loaded class */ + res= IUnknown_QueryInterface(pObj,riid,ppvResult); + + IBindCtx_RegisterObjectBound(pbc,(IUnknown*)*ppvResult); + + IUnknown_Release(pObj); + } + + if (prot!=NULL) + IRunningObjectTable_Release(prot); + + if (ppf!=NULL) + IPersistFile_Release(ppf); + + if (pca!=NULL) + IClassActivator_Release(pca); + + if (pcf!=NULL) + IClassFactory_Release(pcf); + + return res; +} + +/****************************************************************************** + * FileMoniker_BindToStorage + */ +static HRESULT WINAPI +FileMonikerImpl_BindToStorage(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, + REFIID riid, VOID** ppvObject) +{ + LPOLESTR filePath=0; + IStorage *pstg=0; + HRESULT res; + + TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvObject); + + if (pmkToLeft==NULL){ + + if (IsEqualIID(&IID_IStorage, riid)){ + + /* get the file name */ + IMoniker_GetDisplayName(iface,pbc,pmkToLeft,&filePath); + + /* verifie if the file contains a storage object */ + res=StgIsStorageFile(filePath); + + if(res==S_OK){ + + res=StgOpenStorage(filePath,NULL,STGM_READWRITE|STGM_SHARE_DENY_WRITE,NULL,0,&pstg); + + if (SUCCEEDED(res)){ + + *ppvObject=pstg; + + IStorage_AddRef(pstg); + + return res; + } + } + CoTaskMemFree(filePath); + } + else + if ( (IsEqualIID(&IID_IStream, riid)) || (IsEqualIID(&IID_ILockBytes, riid)) ) + return E_FAIL; + else + return E_NOINTERFACE; + } + else { + + FIXME("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvObject); + + return E_NOTIMPL; + } + return res; +} + +/****************************************************************************** + * FileMoniker_Reduce + ******************************************************************************/ +static HRESULT WINAPI +FileMonikerImpl_Reduce(IMoniker* iface, IBindCtx* pbc, DWORD dwReduceHowFar, + IMoniker** ppmkToLeft, IMoniker** ppmkReduced) +{ + TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); + + if (ppmkReduced==NULL) + return E_POINTER; + + IMoniker_AddRef(iface); + + *ppmkReduced=iface; + + return MK_S_REDUCED_TO_SELF; +} + +/****************************************************************************** + * FileMoniker_ComposeWith + */ +static HRESULT WINAPI +FileMonikerImpl_ComposeWith(IMoniker* iface, IMoniker* pmkRight, + BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite) +{ + HRESULT res; + LPOLESTR str1=0,str2=0,*strDec1=0,*strDec2=0,newStr=0; + static const WCHAR twoPoint[]={'.','.',0}; + static const WCHAR bkSlash[]={'\\',0}; + IBindCtx *bind=0; + int i=0,j=0,lastIdx1=0,lastIdx2=0; + DWORD mkSys; + + TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite); + + if (ppmkComposite==NULL) + return E_POINTER; + + if (pmkRight==NULL) + return E_INVALIDARG; + + *ppmkComposite=0; + + IMoniker_IsSystemMoniker(pmkRight,&mkSys); + + /* check if we have two filemonikers to compose or not */ + if(mkSys==MKSYS_FILEMONIKER){ + + CreateBindCtx(0,&bind); + + IMoniker_GetDisplayName(iface,bind,NULL,&str1); + IMoniker_GetDisplayName(pmkRight,bind,NULL,&str2); + + /* decompose pathnames of the two monikers : (to prepare the path merge operation ) */ + lastIdx1=FileMonikerImpl_DecomposePath(str1,&strDec1)-1; + lastIdx2=FileMonikerImpl_DecomposePath(str2,&strDec2)-1; + + if ((lastIdx1==-1 && lastIdx2>-1)||(lastIdx1==1 && lstrcmpW(strDec1[0],twoPoint)==0)) + return MK_E_SYNTAX; + + if(lstrcmpW(strDec1[lastIdx1],bkSlash)==0) + lastIdx1--; + + /* for etch "..\" in the left of str2 remove the right element from str1 */ + for(i=0; ( (lastIdx1>=0) && (strDec2[i]!=NULL) && (lstrcmpW(strDec2[i],twoPoint)==0) ) ;i+=2){ + + lastIdx1-=2; + } + + /* the length of the composed path string is raised by the sum of the two paths lengths */ + newStr=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(lstrlenW(str1)+lstrlenW(str2)+1)); + + if (newStr==NULL) + return E_OUTOFMEMORY; + + /* new path is the concatenation of the rest of str1 and str2 */ + for(*newStr=0,j=0;j<=lastIdx1;j++) + strcatW(newStr,strDec1[j]); + + if ((strDec2[i]==NULL && lastIdx1>-1 && lastIdx2>-1) || lstrcmpW(strDec2[i],bkSlash)!=0) + strcatW(newStr,bkSlash); + + for(j=i;j<=lastIdx2;j++) + strcatW(newStr,strDec2[j]); + + /* create a new moniker with the new string */ + res=CreateFileMoniker(newStr,ppmkComposite); + + /* free all strings space memory used by this function */ + HeapFree(GetProcessHeap(),0,newStr); + + for(i=0; strDec1[i]!=NULL;i++) + CoTaskMemFree(strDec1[i]); + for(i=0; strDec2[i]!=NULL;i++) + CoTaskMemFree(strDec2[i]); + CoTaskMemFree(strDec1); + CoTaskMemFree(strDec2); + + CoTaskMemFree(str1); + CoTaskMemFree(str2); + + return res; + } + else if(mkSys==MKSYS_ANTIMONIKER){ + + *ppmkComposite=NULL; + return S_OK; + } + else if (fOnlyIfNotGeneric){ + + *ppmkComposite=NULL; + return MK_E_NEEDGENERIC; + } + else + + return CreateGenericComposite(iface,pmkRight,ppmkComposite); +} + +/****************************************************************************** + * FileMoniker_Enum + */ +static HRESULT WINAPI +FileMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker) +{ + TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker); + + if (ppenumMoniker == NULL) + return E_POINTER; + + *ppenumMoniker = NULL; + + return S_OK; +} + +/****************************************************************************** + * FileMoniker_IsEqual + */ +static HRESULT WINAPI +FileMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker) +{ + FileMonikerImpl *This = (FileMonikerImpl *)iface; + CLSID clsid; + LPOLESTR filePath; + IBindCtx* bind; + HRESULT res; + + TRACE("(%p,%p)\n",iface,pmkOtherMoniker); + + if (pmkOtherMoniker==NULL) + return S_FALSE; + + IMoniker_GetClassID(pmkOtherMoniker,&clsid); + + if (!IsEqualCLSID(&clsid,&CLSID_FileMoniker)) + return S_FALSE; + + res = CreateBindCtx(0,&bind); + if (FAILED(res)) return res; + + if (SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&filePath))) { + int result = lstrcmpiW(filePath, This->filePathName); + CoTaskMemFree(filePath); + if ( result == 0 ) return S_OK; + } + return S_FALSE; + +} + +/****************************************************************************** + * FileMoniker_Hash + */ +static HRESULT WINAPI +FileMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash) +{ + FileMonikerImpl *This = (FileMonikerImpl *)iface; + + int h = 0,i,skip,len; + int off = 0; + LPOLESTR val; + + if (pdwHash==NULL) + return E_POINTER; + + val = This->filePathName; + len = lstrlenW(val); + + if (len < 16) { + for (i = len ; i > 0; i--) { + h = (h * 37) + val[off++]; + } + } else { + /* only sample some characters */ + skip = len / 8; + for (i = len ; i > 0; i -= skip, off += skip) { + h = (h * 39) + val[off]; + } + } + + *pdwHash=h; + + return S_OK; +} + +/****************************************************************************** + * FileMoniker_IsRunning + */ +static HRESULT WINAPI +FileMonikerImpl_IsRunning(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, + IMoniker* pmkNewlyRunning) +{ + IRunningObjectTable* rot; + HRESULT res; + + TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning); + + if ( (pmkNewlyRunning!=NULL) && (IMoniker_IsEqual(pmkNewlyRunning,iface)==S_OK) ) + return S_OK; + + if (pbc==NULL) + return E_POINTER; + + res=IBindCtx_GetRunningObjectTable(pbc,&rot); + + if (FAILED(res)) + return res; + + res = IRunningObjectTable_IsRunning(rot,iface); + + IRunningObjectTable_Release(rot); + + return res; +} + +/****************************************************************************** + * FileMoniker_GetTimeOfLastChange + ******************************************************************************/ +static HRESULT WINAPI +FileMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc, + IMoniker* pmkToLeft, FILETIME* pFileTime) +{ + FileMonikerImpl *This = (FileMonikerImpl *)iface; + IRunningObjectTable* rot; + HRESULT res; + WIN32_FILE_ATTRIBUTE_DATA info; + + TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pFileTime); + + if (pFileTime==NULL) + return E_POINTER; + + if (pmkToLeft!=NULL) + return E_INVALIDARG; + + res=IBindCtx_GetRunningObjectTable(pbc,&rot); + + if (FAILED(res)) + return res; + + res= IRunningObjectTable_GetTimeOfLastChange(rot,iface,pFileTime); + + if (FAILED(res)){ /* the moniker is not registered */ + + if (!GetFileAttributesExW(This->filePathName,GetFileExInfoStandard,&info)) + return MK_E_NOOBJECT; + + *pFileTime=info.ftLastWriteTime; + } + + return S_OK; +} + +/****************************************************************************** + * FileMoniker_Inverse + */ +static HRESULT WINAPI +FileMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk) +{ + TRACE("(%p,%p)\n",iface,ppmk); + + return CreateAntiMoniker(ppmk); +} + +/****************************************************************************** + * FileMoniker_CommonPrefixWith + */ +static HRESULT WINAPI +FileMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix) +{ + + LPOLESTR pathThis,pathOther,*stringTable1,*stringTable2,commonPath; + IBindCtx *pbind; + DWORD mkSys; + ULONG nb1,nb2,i,sameIdx; + BOOL machimeNameCase=FALSE; + + if (ppmkPrefix==NULL) + return E_POINTER; + + if (pmkOther==NULL) + return E_INVALIDARG; + + *ppmkPrefix=0; + + /* check if we have the same type of moniker */ + IMoniker_IsSystemMoniker(pmkOther,&mkSys); + + if(mkSys==MKSYS_FILEMONIKER){ + HRESULT ret; + + CreateBindCtx(0,&pbind); + + /* create a string based on common part of the two paths */ + + IMoniker_GetDisplayName(iface,pbind,NULL,&pathThis); + IMoniker_GetDisplayName(pmkOther,pbind,NULL,&pathOther); + + nb1=FileMonikerImpl_DecomposePath(pathThis,&stringTable1); + nb2=FileMonikerImpl_DecomposePath(pathOther,&stringTable2); + + if (nb1==0 || nb2==0) + return MK_E_NOPREFIX; + + commonPath=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(min(lstrlenW(pathThis),lstrlenW(pathOther))+1)); + + *commonPath=0; + + for(sameIdx=0; ( (stringTable1[sameIdx]!=NULL) && + (stringTable2[sameIdx]!=NULL) && + (lstrcmpiW(stringTable1[sameIdx],stringTable2[sameIdx])==0)); sameIdx++); + + if (sameIdx > 1 && *stringTable1[0]=='\\' && *stringTable2[1]=='\\'){ + + machimeNameCase=TRUE; + + for(i=2;i<sameIdx;i++) + + if( (*stringTable1[i]=='\\') && (i+1 < sameIdx) && (*stringTable1[i+1]=='\\') ){ + machimeNameCase=FALSE; + break; + } + } + + if (machimeNameCase && *stringTable1[sameIdx-1]=='\\') + sameIdx--; + + if (machimeNameCase && (sameIdx<=3) && (nb1 > 3 || nb2 > 3) ) + ret = MK_E_NOPREFIX; + else + { + for(i=0;i<sameIdx;i++) + strcatW(commonPath,stringTable1[i]); + + for(i=0;i<nb1;i++) + CoTaskMemFree(stringTable1[i]); + + CoTaskMemFree(stringTable1); + + for(i=0;i<nb2;i++) + CoTaskMemFree(stringTable2[i]); + + CoTaskMemFree(stringTable2); + + ret = CreateFileMoniker(commonPath,ppmkPrefix); + } + HeapFree(GetProcessHeap(),0,commonPath); + return ret; + } + else + return MonikerCommonPrefixWith(iface,pmkOther,ppmkPrefix); +} + +/****************************************************************************** + * DecomposePath (local function) + */ +int FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable) +{ + static const WCHAR bSlash[] = {'\\',0}; + WCHAR word[MAX_PATH]; + int i=0,j,tabIndex=0; + LPOLESTR *strgtable ; + + int len=lstrlenW(str); + + TRACE("%s, %p\n", debugstr_w(str), *stringTable); + + strgtable =CoTaskMemAlloc(len*sizeof(LPOLESTR)); + + if (strgtable==NULL) + return E_OUTOFMEMORY; + + while(str[i]!=0){ + + if(str[i]==bSlash[0]){ + + strgtable[tabIndex]=CoTaskMemAlloc(2*sizeof(WCHAR)); + + if (strgtable[tabIndex]==NULL) + return E_OUTOFMEMORY; + + strcpyW(strgtable[tabIndex++],bSlash); + + i++; + + } + else { + + for(j=0; str[i]!=0 && str[i]!=bSlash[0] ; i++,j++) + word[j]=str[i]; + + word[j]=0; + + strgtable[tabIndex]=CoTaskMemAlloc(sizeof(WCHAR)*(j+1)); + + if (strgtable[tabIndex]==NULL) + return E_OUTOFMEMORY; + + strcpyW(strgtable[tabIndex++],word); + } + } + strgtable[tabIndex]=NULL; + + *stringTable=strgtable; + + return tabIndex; +} + +/****************************************************************************** + * FileMoniker_RelativePathTo + */ +static HRESULT WINAPI +FileMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath) +{ + IBindCtx *bind; + HRESULT res; + LPOLESTR str1=0,str2=0,*tabStr1=0,*tabStr2=0,relPath=0; + DWORD len1=0,len2=0,sameIdx=0,j=0; + static const WCHAR back[] ={'.','.','\\',0}; + + TRACE("(%p,%p,%p)\n",iface,pmOther,ppmkRelPath); + + if (ppmkRelPath==NULL) + return E_POINTER; + + if (pmOther==NULL) + return E_INVALIDARG; + + res=CreateBindCtx(0,&bind); + if (FAILED(res)) + return res; + + res=IMoniker_GetDisplayName(iface,bind,NULL,&str1); + if (FAILED(res)) + return res; + res=IMoniker_GetDisplayName(pmOther,bind,NULL,&str2); + if (FAILED(res)) + return res; + + len1=FileMonikerImpl_DecomposePath(str1,&tabStr1); + len2=FileMonikerImpl_DecomposePath(str2,&tabStr2); + + if (FAILED(len1) || FAILED(len2)) + return E_OUTOFMEMORY; + + /* count the number of similar items from the begin of the two paths */ + for(sameIdx=0; ( (tabStr1[sameIdx]!=NULL) && + (tabStr2[sameIdx]!=NULL) && + (lstrcmpiW(tabStr1[sameIdx],tabStr2[sameIdx])==0)); sameIdx++); + + /* begin the construction of relativePath */ + /* if the two paths have a consecutive similar item from the begin ! the relativePath will be composed */ + /* by "..\\" in the begin */ + relPath=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(1+lstrlenW(str1)+lstrlenW(str2))); + + *relPath=0; + + if (len2>0 && !(len1==1 && len2==1 && sameIdx==0)) + for(j=sameIdx;(tabStr1[j] != NULL); j++) + if (*tabStr1[j]!='\\') + strcatW(relPath,back); + + /* add items of the second path (similar items with the first path are not included) to the relativePath */ + for(j=sameIdx;tabStr2[j]!=NULL;j++) + strcatW(relPath,tabStr2[j]); + + res=CreateFileMoniker(relPath,ppmkRelPath); + + for(j=0; tabStr1[j]!=NULL;j++) + CoTaskMemFree(tabStr1[j]); + for(j=0; tabStr2[j]!=NULL;j++) + CoTaskMemFree(tabStr2[j]); + CoTaskMemFree(tabStr1); + CoTaskMemFree(tabStr2); + CoTaskMemFree(str1); + CoTaskMemFree(str2); + HeapFree(GetProcessHeap(),0,relPath); + + if (len1==0 || len2==0 || (len1==1 && len2==1 && sameIdx==0)) + return MK_S_HIM; + + return res; +} + +/****************************************************************************** + * FileMoniker_GetDisplayName + */ +static HRESULT WINAPI +FileMonikerImpl_GetDisplayName(IMoniker* iface, IBindCtx* pbc, + IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName) +{ + FileMonikerImpl *This = (FileMonikerImpl *)iface; + + int len=lstrlenW(This->filePathName); + + TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName); + + if (ppszDisplayName==NULL) + return E_POINTER; + + if (pmkToLeft!=NULL) + return E_INVALIDARG; + + *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR)*(len+1)); + if (*ppszDisplayName==NULL) + return E_OUTOFMEMORY; + + strcpyW(*ppszDisplayName,This->filePathName); + + TRACE("-- %s\n", debugstr_w(*ppszDisplayName)); + + return S_OK; +} + +/****************************************************************************** + * FileMoniker_ParseDisplayName + */ +static HRESULT WINAPI +FileMonikerImpl_ParseDisplayName(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, + LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut) +{ + FIXME("(%p,%p,%p,%p,%p,%p),stub!\n",iface,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut); + return E_NOTIMPL; +} + +/****************************************************************************** + * FileMoniker_IsSystemMoniker + */ +static HRESULT WINAPI +FileMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys) +{ + TRACE("(%p,%p)\n",iface,pwdMksys); + + if (!pwdMksys) + return E_POINTER; + + (*pwdMksys)=MKSYS_FILEMONIKER; + + return S_OK; +} + +/******************************************************************************* + * FileMonikerIROTData_QueryInterface + */ +static HRESULT WINAPI +FileMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject) +{ + + ICOM_THIS_From_IROTData(IMoniker, iface); + + TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject); + + return FileMonikerImpl_QueryInterface(This, riid, ppvObject); +} + +/*********************************************************************** + * FileMonikerIROTData_AddRef + */ +static ULONG WINAPI +FileMonikerROTDataImpl_AddRef(IROTData *iface) +{ + ICOM_THIS_From_IROTData(IMoniker, iface); + + TRACE("(%p)\n",This); + + return IMoniker_AddRef(This); +} + +/*********************************************************************** + * FileMonikerIROTData_Release + */ +static ULONG WINAPI +FileMonikerROTDataImpl_Release(IROTData* iface) +{ + ICOM_THIS_From_IROTData(IMoniker, iface); + + TRACE("(%p)\n",This); + + return FileMonikerImpl_Release(This); +} + +/****************************************************************************** + * FileMonikerIROTData_GetComparaisonData + */ +static HRESULT WINAPI +FileMonikerROTDataImpl_GetComparisonData(IROTData* iface, BYTE* pbData, + ULONG cbMax, ULONG* pcbData) +{ + ICOM_THIS_From_IROTData(IMoniker, iface); + FileMonikerImpl *This1 = (FileMonikerImpl *)This; + int len = (strlenW(This1->filePathName)+1); + int i; + LPWSTR pszFileName; + + TRACE("(%p, %lu, %p)\n", pbData, cbMax, pcbData); + + *pcbData = sizeof(CLSID) + len * sizeof(WCHAR); + if (cbMax < *pcbData) + return E_OUTOFMEMORY; + + memcpy(pbData, &CLSID_FileMoniker, sizeof(CLSID)); + pszFileName = (LPWSTR)(pbData+sizeof(CLSID)); + for (i = 0; i < len; i++) + pszFileName[i] = toupperW(This1->filePathName[i]); + + return S_OK; +} + +/* + * Virtual function table for the FileMonikerImpl class which include IPersist, + * IPersistStream and IMoniker functions. + */ +static IMonikerVtbl VT_FileMonikerImpl = +{ + FileMonikerImpl_QueryInterface, + FileMonikerImpl_AddRef, + FileMonikerImpl_Release, + FileMonikerImpl_GetClassID, + FileMonikerImpl_IsDirty, + FileMonikerImpl_Load, + FileMonikerImpl_Save, + FileMonikerImpl_GetSizeMax, + FileMonikerImpl_BindToObject, + FileMonikerImpl_BindToStorage, + FileMonikerImpl_Reduce, + FileMonikerImpl_ComposeWith, + FileMonikerImpl_Enum, + FileMonikerImpl_IsEqual, + FileMonikerImpl_Hash, + FileMonikerImpl_IsRunning, + FileMonikerImpl_GetTimeOfLastChange, + FileMonikerImpl_Inverse, + FileMonikerImpl_CommonPrefixWith, + FileMonikerImpl_RelativePathTo, + FileMonikerImpl_GetDisplayName, + FileMonikerImpl_ParseDisplayName, + FileMonikerImpl_IsSystemMoniker +}; + +/* Virtual function table for the IROTData class. */ +static IROTDataVtbl VT_ROTDataImpl = +{ + FileMonikerROTDataImpl_QueryInterface, + FileMonikerROTDataImpl_AddRef, + FileMonikerROTDataImpl_Release, + FileMonikerROTDataImpl_GetComparisonData +}; + +/****************************************************************************** + * FileMoniker_Construct (local function) + */ +static HRESULT WINAPI +FileMonikerImpl_Construct(FileMonikerImpl* This, LPCOLESTR lpszPathName) +{ + int nb=0,i; + int sizeStr=lstrlenW(lpszPathName); + LPOLESTR *tabStr=0; + static const WCHAR twoPoint[]={'.','.',0}; + static const WCHAR bkSlash[]={'\\',0}; + BYTE addBkSlash; + + TRACE("(%p,%s)\n",This,debugstr_w(lpszPathName)); + + /* Initialize the virtual fgunction table. */ + This->lpvtbl1 = &VT_FileMonikerImpl; + This->lpvtbl2 = &VT_ROTDataImpl; + This->ref = 0; + This->pMarshal = NULL; + + This->filePathName=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr+1)); + + if (This->filePathName==NULL) + return E_OUTOFMEMORY; + + strcpyW(This->filePathName,lpszPathName); + + nb=FileMonikerImpl_DecomposePath(This->filePathName,&tabStr); + + if (nb > 0 ){ + + addBkSlash=1; + if (lstrcmpW(tabStr[0],twoPoint)!=0) + addBkSlash=0; + else + for(i=0;i<nb;i++){ + + if ( (lstrcmpW(tabStr[i],twoPoint)!=0) && (lstrcmpW(tabStr[i],bkSlash)!=0) ){ + addBkSlash=0; + break; + } + else + + if (lstrcmpW(tabStr[i],bkSlash)==0 && i<nb-1 && lstrcmpW(tabStr[i+1],bkSlash)==0){ + *tabStr[i]=0; + sizeStr--; + addBkSlash=0; + break; + } + } + + if (lstrcmpW(tabStr[nb-1],bkSlash)==0) + addBkSlash=0; + + This->filePathName=HeapReAlloc(GetProcessHeap(),0,This->filePathName,(sizeStr+1)*sizeof(WCHAR)); + + *This->filePathName=0; + + for(i=0;tabStr[i]!=NULL;i++) + strcatW(This->filePathName,tabStr[i]); + + if (addBkSlash) + strcatW(This->filePathName,bkSlash); + } + + for(i=0; tabStr[i]!=NULL;i++) + CoTaskMemFree(tabStr[i]); + CoTaskMemFree(tabStr); + + return S_OK; +} + +/****************************************************************************** + * CreateFileMoniker (OLE32.@) + ******************************************************************************/ +HRESULT WINAPI CreateFileMoniker(LPCOLESTR lpszPathName, LPMONIKER * ppmk) +{ + FileMonikerImpl* newFileMoniker; + HRESULT hr; + + TRACE("(%s,%p)\n",debugstr_w(lpszPathName),ppmk); + + if (!ppmk) + return E_POINTER; + + if(!lpszPathName) + return MK_E_SYNTAX; + + *ppmk=NULL; + + newFileMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(FileMonikerImpl)); + + if (!newFileMoniker) + return E_OUTOFMEMORY; + + hr = FileMonikerImpl_Construct(newFileMoniker,lpszPathName); + + if (SUCCEEDED(hr)) + hr = FileMonikerImpl_QueryInterface((IMoniker*)newFileMoniker,&IID_IMoniker,(void**)ppmk); + else + HeapFree(GetProcessHeap(),0,newFileMoniker); + + return hr; +} + +static HRESULT WINAPI FileMonikerCF_QueryInterface(LPCLASSFACTORY iface, + REFIID riid, LPVOID *ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) + { + *ppv = iface; + IUnknown_AddRef(iface); + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI FileMonikerCF_AddRef(LPCLASSFACTORY iface) +{ + return 2; /* non-heap based object */ +} + +static ULONG WINAPI FileMonikerCF_Release(LPCLASSFACTORY iface) +{ + return 1; /* non-heap based object */ +} + +static HRESULT WINAPI FileMonikerCF_CreateInstance(LPCLASSFACTORY iface, + LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv) +{ + FileMonikerImpl* newFileMoniker; + HRESULT hr; + static const WCHAR wszEmpty[] = { 0 }; + + TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv); + + *ppv = NULL; + + if (pUnk) + return CLASS_E_NOAGGREGATION; + + newFileMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(FileMonikerImpl)); + if (!newFileMoniker) + return E_OUTOFMEMORY; + + hr = FileMonikerImpl_Construct(newFileMoniker, wszEmpty); + + if (SUCCEEDED(hr)) + hr = FileMonikerImpl_QueryInterface((IMoniker*)newFileMoniker, riid, ppv); + if (FAILED(hr)) + HeapFree(GetProcessHeap(),0,newFileMoniker); + + return hr; +} + +static HRESULT WINAPI FileMonikerCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) +{ + FIXME("(%d), stub!\n",fLock); + return S_OK; +} + +static const IClassFactoryVtbl FileMonikerCFVtbl = +{ + FileMonikerCF_QueryInterface, + FileMonikerCF_AddRef, + FileMonikerCF_Release, + FileMonikerCF_CreateInstance, + FileMonikerCF_LockServer +}; +static const IClassFactoryVtbl *FileMonikerCF = &FileMonikerCFVtbl; + +HRESULT FileMonikerCF_Create(REFIID riid, LPVOID *ppv) +{ + return IClassFactory_QueryInterface((IClassFactory *)&FileMonikerCF, riid, ppv); +} diff --git a/reactos/lib/ole32/ftmarshal.c b/reactos/lib/ole32/ftmarshal.c index 24fdb7d608b..786d8d0fc5a 100644 --- a/reactos/lib/ole32/ftmarshal.c +++ b/reactos/lib/ole32/ftmarshal.c @@ -1,246 +1,246 @@ -/* - * free threaded marshaller - * - * Copyright 2002 Juergen Schmied - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <stdlib.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> -#include <assert.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "objbase.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -typedef struct _FTMarshalImpl { - IUnknownVtbl *lpVtbl; - DWORD ref; - IMarshalVtbl *lpvtblFTM; - - IUnknown *pUnkOuter; -} FTMarshalImpl; - -#define _IFTMUnknown_(This)(IUnknown*)&(This->lpVtbl) -#define _IFTMarshal_(This) (IMarshal*)&(This->lpvtblFTM) - -#define _IFTMarshall_Offset ((int)(&(((FTMarshalImpl*)0)->lpvtblFTM))) -#define _ICOM_THIS_From_IFTMarshal(class, name) class* This = (class*)(((char*)name)-_IFTMarshall_Offset); - -/* inner IUnknown to handle aggregation */ -static HRESULT WINAPI -IiFTMUnknown_fnQueryInterface (IUnknown * iface, REFIID riid, LPVOID * ppv) -{ - - FTMarshalImpl *This = (FTMarshalImpl *)iface; - - TRACE ("\n"); - *ppv = NULL; - - if (IsEqualIID (&IID_IUnknown, riid)) - *ppv = _IFTMUnknown_ (This); - else if (IsEqualIID (&IID_IMarshal, riid)) - *ppv = _IFTMarshal_ (This); - else { - FIXME ("No interface for %s.\n", debugstr_guid (riid)); - return E_NOINTERFACE; - } - IUnknown_AddRef ((IUnknown *) * ppv); - return S_OK; -} - -static ULONG WINAPI IiFTMUnknown_fnAddRef (IUnknown * iface) -{ - - FTMarshalImpl *This = (FTMarshalImpl *)iface; - - TRACE ("\n"); - return InterlockedIncrement (&This->ref); -} - -static ULONG WINAPI IiFTMUnknown_fnRelease (IUnknown * iface) -{ - - FTMarshalImpl *This = (FTMarshalImpl *)iface; - - TRACE ("\n"); - if (InterlockedDecrement (&This->ref)) - return This->ref; - HeapFree (GetProcessHeap (), 0, This); - return 0; -} - -static IUnknownVtbl iunkvt = -{ - IiFTMUnknown_fnQueryInterface, - IiFTMUnknown_fnAddRef, - IiFTMUnknown_fnRelease -}; - -static HRESULT WINAPI -FTMarshalImpl_QueryInterface (LPMARSHAL iface, REFIID riid, LPVOID * ppv) -{ - - _ICOM_THIS_From_IFTMarshal (FTMarshalImpl, iface); - - TRACE ("(%p)->(\n\tIID:\t%s,%p)\n", This, debugstr_guid (riid), ppv); - return IUnknown_QueryInterface (This->pUnkOuter, riid, ppv); -} - -static ULONG WINAPI -FTMarshalImpl_AddRef (LPMARSHAL iface) -{ - - _ICOM_THIS_From_IFTMarshal (FTMarshalImpl, iface); - - TRACE ("\n"); - return IUnknown_AddRef (This->pUnkOuter); -} - -static ULONG WINAPI -FTMarshalImpl_Release (LPMARSHAL iface) -{ - - _ICOM_THIS_From_IFTMarshal (FTMarshalImpl, iface); - - TRACE ("\n"); - return IUnknown_Release (This->pUnkOuter); -} - -static HRESULT WINAPI -FTMarshalImpl_GetUnmarshalClass (LPMARSHAL iface, REFIID riid, void *pv, DWORD dwDestContext, - void *pvDestContext, DWORD mshlflags, CLSID * pCid) -{ - FIXME ("(), stub!\n"); - return S_OK; -} - -static HRESULT WINAPI -FTMarshalImpl_GetMarshalSizeMax (LPMARSHAL iface, REFIID riid, void *pv, DWORD dwDestContext, - void *pvDestContext, DWORD mshlflags, DWORD * pSize) -{ - - IMarshal *pMarshal = NULL; - HRESULT hres; - - _ICOM_THIS_From_IFTMarshal (FTMarshalImpl, iface); - - FIXME ("(), stub!\n"); - - /* if the marshalling happens inside the same process the interface pointer is - copied between the apartments */ - if (dwDestContext == MSHCTX_INPROC || dwDestContext == MSHCTX_CROSSCTX) { - *pSize = sizeof (This); - return S_OK; - } - - /* use the standard marshaller to handle all other cases */ - CoGetStandardMarshal (riid, pv, dwDestContext, pvDestContext, mshlflags, &pMarshal); - hres = IMarshal_GetMarshalSizeMax (pMarshal, riid, pv, dwDestContext, pvDestContext, mshlflags, pSize); - IMarshal_Release (pMarshal); - return hres; -} - -static HRESULT WINAPI -FTMarshalImpl_MarshalInterface (LPMARSHAL iface, IStream * pStm, REFIID riid, void *pv, - DWORD dwDestContext, void *pvDestContext, DWORD mshlflags) -{ - - IMarshal *pMarshal = NULL; - HRESULT hres; - - _ICOM_THIS_From_IFTMarshal (FTMarshalImpl, iface); - - FIXME ("(), stub!\n"); - - /* if the marshalling happens inside the same process the interface pointer is - copied between the apartments */ - if (dwDestContext == MSHCTX_INPROC || dwDestContext == MSHCTX_CROSSCTX) { - return IStream_Write (pStm, This, sizeof (This), 0); - } - - /* use the standard marshaler to handle all other cases */ - CoGetStandardMarshal (riid, pv, dwDestContext, pvDestContext, mshlflags, &pMarshal); - hres = IMarshal_MarshalInterface (pMarshal, pStm, riid, pv, dwDestContext, pvDestContext, mshlflags); - IMarshal_Release (pMarshal); - return hres; -} - -static HRESULT WINAPI -FTMarshalImpl_UnmarshalInterface (LPMARSHAL iface, IStream * pStm, REFIID riid, void **ppv) -{ - FIXME ("(), stub!\n"); - return S_OK; -} - -static HRESULT WINAPI FTMarshalImpl_ReleaseMarshalData (LPMARSHAL iface, IStream * pStm) -{ - FIXME ("(), stub!\n"); - return S_OK; -} - -static HRESULT WINAPI FTMarshalImpl_DisconnectObject (LPMARSHAL iface, DWORD dwReserved) -{ - FIXME ("(), stub!\n"); - return S_OK; -} - -static IMarshalVtbl ftmvtbl = -{ - FTMarshalImpl_QueryInterface, - FTMarshalImpl_AddRef, - FTMarshalImpl_Release, - FTMarshalImpl_GetUnmarshalClass, - FTMarshalImpl_GetMarshalSizeMax, - FTMarshalImpl_MarshalInterface, - FTMarshalImpl_UnmarshalInterface, - FTMarshalImpl_ReleaseMarshalData, - FTMarshalImpl_DisconnectObject -}; - -/*********************************************************************** - * CoCreateFreeThreadedMarshaler [OLE32.@] - * - */ -HRESULT WINAPI CoCreateFreeThreadedMarshaler (LPUNKNOWN punkOuter, LPUNKNOWN * ppunkMarshal) -{ - - FTMarshalImpl *ftm; - - TRACE ("(%p %p)\n", punkOuter, ppunkMarshal); - - ftm = HeapAlloc (GetProcessHeap (), 0, sizeof (FTMarshalImpl)); - if (!ftm) - return E_OUTOFMEMORY; - - ftm->lpVtbl = &iunkvt; - ftm->lpvtblFTM = &ftmvtbl; - ftm->ref = 1; - ftm->pUnkOuter = punkOuter; - - *ppunkMarshal = _IFTMUnknown_ (ftm); - return S_OK; -} +/* + * free threaded marshaller + * + * Copyright 2002 Juergen Schmied + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +typedef struct _FTMarshalImpl { + IUnknownVtbl *lpVtbl; + DWORD ref; + IMarshalVtbl *lpvtblFTM; + + IUnknown *pUnkOuter; +} FTMarshalImpl; + +#define _IFTMUnknown_(This)(IUnknown*)&(This->lpVtbl) +#define _IFTMarshal_(This) (IMarshal*)&(This->lpvtblFTM) + +#define _IFTMarshall_Offset ((int)(&(((FTMarshalImpl*)0)->lpvtblFTM))) +#define _ICOM_THIS_From_IFTMarshal(class, name) class* This = (class*)(((char*)name)-_IFTMarshall_Offset); + +/* inner IUnknown to handle aggregation */ +static HRESULT WINAPI +IiFTMUnknown_fnQueryInterface (IUnknown * iface, REFIID riid, LPVOID * ppv) +{ + + FTMarshalImpl *This = (FTMarshalImpl *)iface; + + TRACE ("\n"); + *ppv = NULL; + + if (IsEqualIID (&IID_IUnknown, riid)) + *ppv = _IFTMUnknown_ (This); + else if (IsEqualIID (&IID_IMarshal, riid)) + *ppv = _IFTMarshal_ (This); + else { + FIXME ("No interface for %s.\n", debugstr_guid (riid)); + return E_NOINTERFACE; + } + IUnknown_AddRef ((IUnknown *) * ppv); + return S_OK; +} + +static ULONG WINAPI IiFTMUnknown_fnAddRef (IUnknown * iface) +{ + + FTMarshalImpl *This = (FTMarshalImpl *)iface; + + TRACE ("\n"); + return InterlockedIncrement (&This->ref); +} + +static ULONG WINAPI IiFTMUnknown_fnRelease (IUnknown * iface) +{ + + FTMarshalImpl *This = (FTMarshalImpl *)iface; + + TRACE ("\n"); + if (InterlockedDecrement (&This->ref)) + return This->ref; + HeapFree (GetProcessHeap (), 0, This); + return 0; +} + +static IUnknownVtbl iunkvt = +{ + IiFTMUnknown_fnQueryInterface, + IiFTMUnknown_fnAddRef, + IiFTMUnknown_fnRelease +}; + +static HRESULT WINAPI +FTMarshalImpl_QueryInterface (LPMARSHAL iface, REFIID riid, LPVOID * ppv) +{ + + _ICOM_THIS_From_IFTMarshal (FTMarshalImpl, iface); + + TRACE ("(%p)->(\n\tIID:\t%s,%p)\n", This, debugstr_guid (riid), ppv); + return IUnknown_QueryInterface (This->pUnkOuter, riid, ppv); +} + +static ULONG WINAPI +FTMarshalImpl_AddRef (LPMARSHAL iface) +{ + + _ICOM_THIS_From_IFTMarshal (FTMarshalImpl, iface); + + TRACE ("\n"); + return IUnknown_AddRef (This->pUnkOuter); +} + +static ULONG WINAPI +FTMarshalImpl_Release (LPMARSHAL iface) +{ + + _ICOM_THIS_From_IFTMarshal (FTMarshalImpl, iface); + + TRACE ("\n"); + return IUnknown_Release (This->pUnkOuter); +} + +static HRESULT WINAPI +FTMarshalImpl_GetUnmarshalClass (LPMARSHAL iface, REFIID riid, void *pv, DWORD dwDestContext, + void *pvDestContext, DWORD mshlflags, CLSID * pCid) +{ + FIXME ("(), stub!\n"); + return S_OK; +} + +static HRESULT WINAPI +FTMarshalImpl_GetMarshalSizeMax (LPMARSHAL iface, REFIID riid, void *pv, DWORD dwDestContext, + void *pvDestContext, DWORD mshlflags, DWORD * pSize) +{ + + IMarshal *pMarshal = NULL; + HRESULT hres; + + _ICOM_THIS_From_IFTMarshal (FTMarshalImpl, iface); + + FIXME ("(), stub!\n"); + + /* if the marshalling happens inside the same process the interface pointer is + copied between the apartments */ + if (dwDestContext == MSHCTX_INPROC || dwDestContext == MSHCTX_CROSSCTX) { + *pSize = sizeof (This); + return S_OK; + } + + /* use the standard marshaller to handle all other cases */ + CoGetStandardMarshal (riid, pv, dwDestContext, pvDestContext, mshlflags, &pMarshal); + hres = IMarshal_GetMarshalSizeMax (pMarshal, riid, pv, dwDestContext, pvDestContext, mshlflags, pSize); + IMarshal_Release (pMarshal); + return hres; +} + +static HRESULT WINAPI +FTMarshalImpl_MarshalInterface (LPMARSHAL iface, IStream * pStm, REFIID riid, void *pv, + DWORD dwDestContext, void *pvDestContext, DWORD mshlflags) +{ + + IMarshal *pMarshal = NULL; + HRESULT hres; + + _ICOM_THIS_From_IFTMarshal (FTMarshalImpl, iface); + + FIXME ("(), stub!\n"); + + /* if the marshalling happens inside the same process the interface pointer is + copied between the apartments */ + if (dwDestContext == MSHCTX_INPROC || dwDestContext == MSHCTX_CROSSCTX) { + return IStream_Write (pStm, This, sizeof (This), 0); + } + + /* use the standard marshaler to handle all other cases */ + CoGetStandardMarshal (riid, pv, dwDestContext, pvDestContext, mshlflags, &pMarshal); + hres = IMarshal_MarshalInterface (pMarshal, pStm, riid, pv, dwDestContext, pvDestContext, mshlflags); + IMarshal_Release (pMarshal); + return hres; +} + +static HRESULT WINAPI +FTMarshalImpl_UnmarshalInterface (LPMARSHAL iface, IStream * pStm, REFIID riid, void **ppv) +{ + FIXME ("(), stub!\n"); + return S_OK; +} + +static HRESULT WINAPI FTMarshalImpl_ReleaseMarshalData (LPMARSHAL iface, IStream * pStm) +{ + FIXME ("(), stub!\n"); + return S_OK; +} + +static HRESULT WINAPI FTMarshalImpl_DisconnectObject (LPMARSHAL iface, DWORD dwReserved) +{ + FIXME ("(), stub!\n"); + return S_OK; +} + +static IMarshalVtbl ftmvtbl = +{ + FTMarshalImpl_QueryInterface, + FTMarshalImpl_AddRef, + FTMarshalImpl_Release, + FTMarshalImpl_GetUnmarshalClass, + FTMarshalImpl_GetMarshalSizeMax, + FTMarshalImpl_MarshalInterface, + FTMarshalImpl_UnmarshalInterface, + FTMarshalImpl_ReleaseMarshalData, + FTMarshalImpl_DisconnectObject +}; + +/*********************************************************************** + * CoCreateFreeThreadedMarshaler [OLE32.@] + * + */ +HRESULT WINAPI CoCreateFreeThreadedMarshaler (LPUNKNOWN punkOuter, LPUNKNOWN * ppunkMarshal) +{ + + FTMarshalImpl *ftm; + + TRACE ("(%p %p)\n", punkOuter, ppunkMarshal); + + ftm = HeapAlloc (GetProcessHeap (), 0, sizeof (FTMarshalImpl)); + if (!ftm) + return E_OUTOFMEMORY; + + ftm->lpVtbl = &iunkvt; + ftm->lpvtblFTM = &ftmvtbl; + ftm->ref = 1; + ftm->pUnkOuter = punkOuter; + + *ppunkMarshal = _IFTMUnknown_ (ftm); + return S_OK; +} diff --git a/reactos/lib/ole32/git.c b/reactos/lib/ole32/git.c index 56136d6850a..d2eccbf1cbc 100644 --- a/reactos/lib/ole32/git.c +++ b/reactos/lib/ole32/git.c @@ -1,407 +1,407 @@ -/* - * Implementation of the StdGlobalInterfaceTable object - * - * The GlobalInterfaceTable (GIT) object is used to marshal interfaces between - * threading apartments (contexts). When you want to pass an interface but not - * as a parameter, it wouldn't get marshalled automatically, so you can use this - * object to insert the interface into a table, and you get back a cookie. - * Then when it's retrieved, it'll be unmarshalled into the right apartment. - * - * Copyright 2003 Mike Hearn <mike@theoretic.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <assert.h> -#include <stdlib.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "objbase.h" -#include "ole2.h" -#include "winerror.h" -#include "winreg.h" -#include "winternl.h" - -#include "compobj_private.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/**************************************************************************** - * StdGlobalInterfaceTable definition - * - * This class implements IGlobalInterfaceTable and is a process-wide singleton - * used for marshalling interfaces between threading apartments using cookies. - */ - -/* Each entry in the linked list of GIT entries */ -typedef struct StdGITEntry -{ - DWORD cookie; - IID iid; /* IID of the interface */ - IStream* stream; /* Holds the marshalled interface */ - - struct StdGITEntry* next; - struct StdGITEntry* prev; -} StdGITEntry; - -/* Class data */ -typedef struct StdGlobalInterfaceTableImpl -{ - IGlobalInterfaceTableVtbl *lpVtbl; - - ULONG ref; - struct StdGITEntry* firstEntry; - struct StdGITEntry* lastEntry; - ULONG nextCookie; - -} StdGlobalInterfaceTableImpl; - -void* StdGlobalInterfaceTableInstance; - -static CRITICAL_SECTION git_section; -static CRITICAL_SECTION_DEBUG critsect_debug = -{ - 0, 0, &git_section, - { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, - 0, 0, { 0, (DWORD)(__FILE__ ": global interface table") } -}; -static CRITICAL_SECTION git_section = { &critsect_debug, -1, 0, 0, 0, 0 }; - - -/** This destroys it again. It should revoke all the held interfaces first **/ -void StdGlobalInterfaceTable_Destroy(void* self) { - TRACE("(%p)\n", self); - FIXME("Revoke held interfaces here\n"); - - HeapFree(GetProcessHeap(), 0, self); - StdGlobalInterfaceTableInstance = NULL; -} - -/*** - * A helper function to traverse the list and find the entry that matches the cookie. - * Returns NULL if not found - */ -static StdGITEntry* -StdGlobalInterfaceTable_FindEntry(IGlobalInterfaceTable* iface, DWORD cookie) -{ - StdGlobalInterfaceTableImpl* const self = (StdGlobalInterfaceTableImpl*) iface; - StdGITEntry* e; - - TRACE("iface=%p, cookie=0x%x\n", iface, (UINT)cookie); - - EnterCriticalSection(&git_section); - e = self->firstEntry; - while (e != NULL) { - if (e->cookie == cookie) { - LeaveCriticalSection(&git_section); - return e; - } - e = e->next; - } - LeaveCriticalSection(&git_section); - - TRACE("Entry not found\n"); - return NULL; -} - -/*** - * Here's the boring boilerplate stuff for IUnknown - */ - -static HRESULT WINAPI -StdGlobalInterfaceTable_QueryInterface(IGlobalInterfaceTable* iface, - REFIID riid, void** ppvObject) -{ - /* Make sure silly coders can't crash us */ - if (ppvObject == 0) return E_INVALIDARG; - - *ppvObject = 0; /* assume we don't have the interface */ - - /* Do we implement that interface? */ - if (IsEqualIID(&IID_IUnknown, riid) || - IsEqualIID(&IID_IGlobalInterfaceTable, riid)) - *ppvObject = iface; - else - return E_NOINTERFACE; - - /* Now inc the refcount */ - IGlobalInterfaceTable_AddRef(iface); - return S_OK; -} - -static ULONG WINAPI -StdGlobalInterfaceTable_AddRef(IGlobalInterfaceTable* iface) -{ - StdGlobalInterfaceTableImpl* const self = (StdGlobalInterfaceTableImpl*) iface; - - /* InterlockedIncrement(&self->ref); */ - return self->ref; -} - -static ULONG WINAPI -StdGlobalInterfaceTable_Release(IGlobalInterfaceTable* iface) -{ - StdGlobalInterfaceTableImpl* const self = (StdGlobalInterfaceTableImpl*) iface; - - /* InterlockedDecrement(&self->ref); */ - if (self->ref == 0) { - /* Hey ho, it's time to go, so long again 'till next weeks show! */ - StdGlobalInterfaceTable_Destroy(self); - return 0; - } - - return self->ref; -} - -/*** - * Now implement the actual IGlobalInterfaceTable interface - */ - -static HRESULT WINAPI -StdGlobalInterfaceTable_RegisterInterfaceInGlobal( - IGlobalInterfaceTable* iface, IUnknown* pUnk, - REFIID riid, DWORD* pdwCookie) -{ - StdGlobalInterfaceTableImpl* const self = (StdGlobalInterfaceTableImpl*) iface; - IStream* stream = NULL; - HRESULT hres; - StdGITEntry* entry; - LARGE_INTEGER zero; - - TRACE("iface=%p, pUnk=%p, riid=%s, pdwCookie=0x%p\n", iface, pUnk, debugstr_guid(riid), pdwCookie); - - if (pUnk == NULL) return E_INVALIDARG; - - /* marshal the interface */ - TRACE("About to marshal the interface\n"); - - hres = CreateStreamOnHGlobal(0, TRUE, &stream); - if (hres) return hres; - hres = CoMarshalInterface(stream, riid, pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLESTRONG); - if (hres) - { - IStream_Release(stream); - return hres; - } - - zero.QuadPart = 0; - IStream_Seek(stream, zero, SEEK_SET, NULL); - - entry = HeapAlloc(GetProcessHeap(), 0, sizeof(StdGITEntry)); - if (entry == NULL) return E_OUTOFMEMORY; - - EnterCriticalSection(&git_section); - - entry->iid = *riid; - entry->stream = stream; - entry->cookie = self->nextCookie; - self->nextCookie++; /* inc the cookie count */ - - /* insert the new entry at the end of the list */ - entry->next = NULL; - entry->prev = self->lastEntry; - if (entry->prev) entry->prev->next = entry; - else self->firstEntry = entry; - self->lastEntry = entry; - - /* and return the cookie */ - *pdwCookie = entry->cookie; - - LeaveCriticalSection(&git_section); - - TRACE("Cookie is 0x%lx\n", entry->cookie); - return S_OK; -} - -static HRESULT WINAPI -StdGlobalInterfaceTable_RevokeInterfaceFromGlobal( - IGlobalInterfaceTable* iface, DWORD dwCookie) -{ - StdGlobalInterfaceTableImpl* const self = (StdGlobalInterfaceTableImpl*) iface; - StdGITEntry* entry; - HRESULT hr; - - TRACE("iface=%p, dwCookie=0x%x\n", iface, (UINT)dwCookie); - - entry = StdGlobalInterfaceTable_FindEntry(iface, dwCookie); - if (entry == NULL) { - TRACE("Entry not found\n"); - return E_INVALIDARG; /* not found */ - } - - /* Free the stream */ - hr = CoReleaseMarshalData(entry->stream); - if (hr != S_OK) - { - WARN("Failed to release marshal data, hr = 0x%08lx\n", hr); - return hr; - } - IStream_Release(entry->stream); - - /* chop entry out of the list, and free the memory */ - EnterCriticalSection(&git_section); - if (entry->prev) entry->prev->next = entry->next; - else self->firstEntry = entry->next; - if (entry->next) entry->next->prev = entry->prev; - else self->lastEntry = entry->prev; - LeaveCriticalSection(&git_section); - - HeapFree(GetProcessHeap(), 0, entry); - return S_OK; -} - -static HRESULT WINAPI -StdGlobalInterfaceTable_GetInterfaceFromGlobal( - IGlobalInterfaceTable* iface, DWORD dwCookie, - REFIID riid, void **ppv) -{ - StdGITEntry* entry; - HRESULT hres; - LARGE_INTEGER move; - LPUNKNOWN lpUnk; - - TRACE("dwCookie=0x%lx, riid=%s, ppv=%p\n", dwCookie, debugstr_guid(riid), ppv); - - entry = StdGlobalInterfaceTable_FindEntry(iface, dwCookie); - if (entry == NULL) return E_INVALIDARG; - - if (!IsEqualIID(&entry->iid, riid)) { - WARN("entry->iid (%s) != riid\n", debugstr_guid(&entry->iid)); - return E_INVALIDARG; - } - TRACE("entry=%p\n", entry); - - /* unmarshal the interface */ - hres = CoUnmarshalInterface(entry->stream, riid, ppv); - if (hres) { - WARN("Failed to unmarshal stream\n"); - return hres; - } - - /* rewind stream, in case it's used again */ - move.u.LowPart = 0; - move.u.HighPart = 0; - IStream_Seek(entry->stream, move, STREAM_SEEK_SET, NULL); - - /* addref it */ - lpUnk = *ppv; - IUnknown_AddRef(lpUnk); - TRACE("ppv=%p\n", *ppv); - return S_OK; -} - -/* Classfactory definition - despite what MSDN says, some programs need this */ - -static HRESULT WINAPI -GITCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) -{ - *ppv = NULL; - if (IsEqualIID(riid,&IID_IUnknown) || - IsEqualIID(riid,&IID_IGlobalInterfaceTable)) - { - *ppv = (LPVOID)iface; - return S_OK; - } - return E_NOINTERFACE; -} - -static ULONG WINAPI GITCF_AddRef(LPCLASSFACTORY iface) -{ - return 2; -} - -static ULONG WINAPI GITCF_Release(LPCLASSFACTORY iface) -{ - return 1; -} - -static HRESULT WINAPI -GITCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pUnk, - REFIID riid, LPVOID *ppv) -{ - if (IsEqualIID(riid,&IID_IGlobalInterfaceTable)) { - if (StdGlobalInterfaceTableInstance == NULL) - StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct(); - return IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, riid, ppv); - } - - FIXME("(%s), not supported.\n",debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static HRESULT WINAPI GITCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) -{ - FIXME("(%d), stub!\n",fLock); - return S_OK; -} - -static IClassFactoryVtbl GITClassFactoryVtbl = { - GITCF_QueryInterface, - GITCF_AddRef, - GITCF_Release, - GITCF_CreateInstance, - GITCF_LockServer -}; - -static IClassFactoryVtbl *PGITClassFactoryVtbl = &GITClassFactoryVtbl; - -HRESULT StdGlobalInterfaceTable_GetFactory(LPVOID *ppv) -{ - *ppv = &PGITClassFactoryVtbl; - TRACE("Returning GIT classfactory\n"); - return S_OK; -} - -/* Virtual function table */ -static IGlobalInterfaceTableVtbl StdGlobalInterfaceTableImpl_Vtbl = -{ - StdGlobalInterfaceTable_QueryInterface, - StdGlobalInterfaceTable_AddRef, - StdGlobalInterfaceTable_Release, - StdGlobalInterfaceTable_RegisterInterfaceInGlobal, - StdGlobalInterfaceTable_RevokeInterfaceFromGlobal, - StdGlobalInterfaceTable_GetInterfaceFromGlobal -}; - -/** This function constructs the GIT. It should only be called once **/ -void* StdGlobalInterfaceTable_Construct() -{ - StdGlobalInterfaceTableImpl* newGIT; - - newGIT = HeapAlloc(GetProcessHeap(), 0, sizeof(StdGlobalInterfaceTableImpl)); - if (newGIT == 0) return newGIT; - - newGIT->lpVtbl = &StdGlobalInterfaceTableImpl_Vtbl; - newGIT->ref = 1; /* Initialise the reference count */ - newGIT->firstEntry = NULL; /* we start with an empty table */ - newGIT->lastEntry = NULL; - newGIT->nextCookie = 0xf100; /* that's where windows starts, so that's where we start */ - TRACE("Created the GIT at %p\n", newGIT); - - return (void*)newGIT; -} +/* + * Implementation of the StdGlobalInterfaceTable object + * + * The GlobalInterfaceTable (GIT) object is used to marshal interfaces between + * threading apartments (contexts). When you want to pass an interface but not + * as a parameter, it wouldn't get marshalled automatically, so you can use this + * object to insert the interface into a table, and you get back a cookie. + * Then when it's retrieved, it'll be unmarshalled into the right apartment. + * + * Copyright 2003 Mike Hearn <mike@theoretic.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <assert.h> +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "objbase.h" +#include "ole2.h" +#include "winerror.h" +#include "winreg.h" +#include "winternl.h" + +#include "compobj_private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/**************************************************************************** + * StdGlobalInterfaceTable definition + * + * This class implements IGlobalInterfaceTable and is a process-wide singleton + * used for marshalling interfaces between threading apartments using cookies. + */ + +/* Each entry in the linked list of GIT entries */ +typedef struct StdGITEntry +{ + DWORD cookie; + IID iid; /* IID of the interface */ + IStream* stream; /* Holds the marshalled interface */ + + struct StdGITEntry* next; + struct StdGITEntry* prev; +} StdGITEntry; + +/* Class data */ +typedef struct StdGlobalInterfaceTableImpl +{ + IGlobalInterfaceTableVtbl *lpVtbl; + + ULONG ref; + struct StdGITEntry* firstEntry; + struct StdGITEntry* lastEntry; + ULONG nextCookie; + +} StdGlobalInterfaceTableImpl; + +void* StdGlobalInterfaceTableInstance; + +static CRITICAL_SECTION git_section; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &git_section, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": global interface table") } +}; +static CRITICAL_SECTION git_section = { &critsect_debug, -1, 0, 0, 0, 0 }; + + +/** This destroys it again. It should revoke all the held interfaces first **/ +void StdGlobalInterfaceTable_Destroy(void* self) { + TRACE("(%p)\n", self); + FIXME("Revoke held interfaces here\n"); + + HeapFree(GetProcessHeap(), 0, self); + StdGlobalInterfaceTableInstance = NULL; +} + +/*** + * A helper function to traverse the list and find the entry that matches the cookie. + * Returns NULL if not found + */ +static StdGITEntry* +StdGlobalInterfaceTable_FindEntry(IGlobalInterfaceTable* iface, DWORD cookie) +{ + StdGlobalInterfaceTableImpl* const self = (StdGlobalInterfaceTableImpl*) iface; + StdGITEntry* e; + + TRACE("iface=%p, cookie=0x%x\n", iface, (UINT)cookie); + + EnterCriticalSection(&git_section); + e = self->firstEntry; + while (e != NULL) { + if (e->cookie == cookie) { + LeaveCriticalSection(&git_section); + return e; + } + e = e->next; + } + LeaveCriticalSection(&git_section); + + TRACE("Entry not found\n"); + return NULL; +} + +/*** + * Here's the boring boilerplate stuff for IUnknown + */ + +static HRESULT WINAPI +StdGlobalInterfaceTable_QueryInterface(IGlobalInterfaceTable* iface, + REFIID riid, void** ppvObject) +{ + /* Make sure silly coders can't crash us */ + if (ppvObject == 0) return E_INVALIDARG; + + *ppvObject = 0; /* assume we don't have the interface */ + + /* Do we implement that interface? */ + if (IsEqualIID(&IID_IUnknown, riid) || + IsEqualIID(&IID_IGlobalInterfaceTable, riid)) + *ppvObject = iface; + else + return E_NOINTERFACE; + + /* Now inc the refcount */ + IGlobalInterfaceTable_AddRef(iface); + return S_OK; +} + +static ULONG WINAPI +StdGlobalInterfaceTable_AddRef(IGlobalInterfaceTable* iface) +{ + StdGlobalInterfaceTableImpl* const self = (StdGlobalInterfaceTableImpl*) iface; + + /* InterlockedIncrement(&self->ref); */ + return self->ref; +} + +static ULONG WINAPI +StdGlobalInterfaceTable_Release(IGlobalInterfaceTable* iface) +{ + StdGlobalInterfaceTableImpl* const self = (StdGlobalInterfaceTableImpl*) iface; + + /* InterlockedDecrement(&self->ref); */ + if (self->ref == 0) { + /* Hey ho, it's time to go, so long again 'till next weeks show! */ + StdGlobalInterfaceTable_Destroy(self); + return 0; + } + + return self->ref; +} + +/*** + * Now implement the actual IGlobalInterfaceTable interface + */ + +static HRESULT WINAPI +StdGlobalInterfaceTable_RegisterInterfaceInGlobal( + IGlobalInterfaceTable* iface, IUnknown* pUnk, + REFIID riid, DWORD* pdwCookie) +{ + StdGlobalInterfaceTableImpl* const self = (StdGlobalInterfaceTableImpl*) iface; + IStream* stream = NULL; + HRESULT hres; + StdGITEntry* entry; + LARGE_INTEGER zero; + + TRACE("iface=%p, pUnk=%p, riid=%s, pdwCookie=0x%p\n", iface, pUnk, debugstr_guid(riid), pdwCookie); + + if (pUnk == NULL) return E_INVALIDARG; + + /* marshal the interface */ + TRACE("About to marshal the interface\n"); + + hres = CreateStreamOnHGlobal(0, TRUE, &stream); + if (hres) return hres; + hres = CoMarshalInterface(stream, riid, pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLESTRONG); + if (hres) + { + IStream_Release(stream); + return hres; + } + + zero.QuadPart = 0; + IStream_Seek(stream, zero, SEEK_SET, NULL); + + entry = HeapAlloc(GetProcessHeap(), 0, sizeof(StdGITEntry)); + if (entry == NULL) return E_OUTOFMEMORY; + + EnterCriticalSection(&git_section); + + entry->iid = *riid; + entry->stream = stream; + entry->cookie = self->nextCookie; + self->nextCookie++; /* inc the cookie count */ + + /* insert the new entry at the end of the list */ + entry->next = NULL; + entry->prev = self->lastEntry; + if (entry->prev) entry->prev->next = entry; + else self->firstEntry = entry; + self->lastEntry = entry; + + /* and return the cookie */ + *pdwCookie = entry->cookie; + + LeaveCriticalSection(&git_section); + + TRACE("Cookie is 0x%lx\n", entry->cookie); + return S_OK; +} + +static HRESULT WINAPI +StdGlobalInterfaceTable_RevokeInterfaceFromGlobal( + IGlobalInterfaceTable* iface, DWORD dwCookie) +{ + StdGlobalInterfaceTableImpl* const self = (StdGlobalInterfaceTableImpl*) iface; + StdGITEntry* entry; + HRESULT hr; + + TRACE("iface=%p, dwCookie=0x%x\n", iface, (UINT)dwCookie); + + entry = StdGlobalInterfaceTable_FindEntry(iface, dwCookie); + if (entry == NULL) { + TRACE("Entry not found\n"); + return E_INVALIDARG; /* not found */ + } + + /* Free the stream */ + hr = CoReleaseMarshalData(entry->stream); + if (hr != S_OK) + { + WARN("Failed to release marshal data, hr = 0x%08lx\n", hr); + return hr; + } + IStream_Release(entry->stream); + + /* chop entry out of the list, and free the memory */ + EnterCriticalSection(&git_section); + if (entry->prev) entry->prev->next = entry->next; + else self->firstEntry = entry->next; + if (entry->next) entry->next->prev = entry->prev; + else self->lastEntry = entry->prev; + LeaveCriticalSection(&git_section); + + HeapFree(GetProcessHeap(), 0, entry); + return S_OK; +} + +static HRESULT WINAPI +StdGlobalInterfaceTable_GetInterfaceFromGlobal( + IGlobalInterfaceTable* iface, DWORD dwCookie, + REFIID riid, void **ppv) +{ + StdGITEntry* entry; + HRESULT hres; + LARGE_INTEGER move; + LPUNKNOWN lpUnk; + + TRACE("dwCookie=0x%lx, riid=%s, ppv=%p\n", dwCookie, debugstr_guid(riid), ppv); + + entry = StdGlobalInterfaceTable_FindEntry(iface, dwCookie); + if (entry == NULL) return E_INVALIDARG; + + if (!IsEqualIID(&entry->iid, riid)) { + WARN("entry->iid (%s) != riid\n", debugstr_guid(&entry->iid)); + return E_INVALIDARG; + } + TRACE("entry=%p\n", entry); + + /* unmarshal the interface */ + hres = CoUnmarshalInterface(entry->stream, riid, ppv); + if (hres) { + WARN("Failed to unmarshal stream\n"); + return hres; + } + + /* rewind stream, in case it's used again */ + move.u.LowPart = 0; + move.u.HighPart = 0; + IStream_Seek(entry->stream, move, STREAM_SEEK_SET, NULL); + + /* addref it */ + lpUnk = *ppv; + IUnknown_AddRef(lpUnk); + TRACE("ppv=%p\n", *ppv); + return S_OK; +} + +/* Classfactory definition - despite what MSDN says, some programs need this */ + +static HRESULT WINAPI +GITCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid,&IID_IUnknown) || + IsEqualIID(riid,&IID_IGlobalInterfaceTable)) + { + *ppv = (LPVOID)iface; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI GITCF_AddRef(LPCLASSFACTORY iface) +{ + return 2; +} + +static ULONG WINAPI GITCF_Release(LPCLASSFACTORY iface) +{ + return 1; +} + +static HRESULT WINAPI +GITCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pUnk, + REFIID riid, LPVOID *ppv) +{ + if (IsEqualIID(riid,&IID_IGlobalInterfaceTable)) { + if (StdGlobalInterfaceTableInstance == NULL) + StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct(); + return IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, riid, ppv); + } + + FIXME("(%s), not supported.\n",debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static HRESULT WINAPI GITCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) +{ + FIXME("(%d), stub!\n",fLock); + return S_OK; +} + +static IClassFactoryVtbl GITClassFactoryVtbl = { + GITCF_QueryInterface, + GITCF_AddRef, + GITCF_Release, + GITCF_CreateInstance, + GITCF_LockServer +}; + +static IClassFactoryVtbl *PGITClassFactoryVtbl = &GITClassFactoryVtbl; + +HRESULT StdGlobalInterfaceTable_GetFactory(LPVOID *ppv) +{ + *ppv = &PGITClassFactoryVtbl; + TRACE("Returning GIT classfactory\n"); + return S_OK; +} + +/* Virtual function table */ +static IGlobalInterfaceTableVtbl StdGlobalInterfaceTableImpl_Vtbl = +{ + StdGlobalInterfaceTable_QueryInterface, + StdGlobalInterfaceTable_AddRef, + StdGlobalInterfaceTable_Release, + StdGlobalInterfaceTable_RegisterInterfaceInGlobal, + StdGlobalInterfaceTable_RevokeInterfaceFromGlobal, + StdGlobalInterfaceTable_GetInterfaceFromGlobal +}; + +/** This function constructs the GIT. It should only be called once **/ +void* StdGlobalInterfaceTable_Construct() +{ + StdGlobalInterfaceTableImpl* newGIT; + + newGIT = HeapAlloc(GetProcessHeap(), 0, sizeof(StdGlobalInterfaceTableImpl)); + if (newGIT == 0) return newGIT; + + newGIT->lpVtbl = &StdGlobalInterfaceTableImpl_Vtbl; + newGIT->ref = 1; /* Initialise the reference count */ + newGIT->firstEntry = NULL; /* we start with an empty table */ + newGIT->lastEntry = NULL; + newGIT->nextCookie = 0xf100; /* that's where windows starts, so that's where we start */ + TRACE("Created the GIT at %p\n", newGIT); + + return (void*)newGIT; +} diff --git a/reactos/lib/ole32/hglobalstream.c b/reactos/lib/ole32/hglobalstream.c index 8267c72b791..a70385a2309 100644 --- a/reactos/lib/ole32/hglobalstream.c +++ b/reactos/lib/ole32/hglobalstream.c @@ -1,757 +1,757 @@ -/* - * HGLOBAL Stream implementation - * - * This file contains the implementation of the stream interface - * for streams contained supported by an HGLOBAL pointer. - * - * Copyright 1999 Francis Beaudet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <assert.h> -#include <stdlib.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "objbase.h" -#include "ole2.h" -#include "winerror.h" -#include "winreg.h" -#include "winternl.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(storage); - -/**************************************************************************** - * HGLOBALStreamImpl definition. - * - * This class imlements the IStream inteface and represents a stream - * supported by an HGLOBAL pointer. - */ -struct HGLOBALStreamImpl -{ - IStreamVtbl *lpVtbl; /* Needs to be the first item in the struct - * since we want to cast this in an IStream pointer */ - - /* - * Reference count - */ - ULONG ref; - - /* - * Support for the stream - */ - HGLOBAL supportHandle; - - /* - * This flag is TRUE if the HGLOBAL is destroyed when the stream - * is finally released. - */ - BOOL deleteOnRelease; - - /* - * Helper variable that contains the size of the stream - */ - ULARGE_INTEGER streamSize; - - /* - * This is the current position of the cursor in the stream - */ - ULARGE_INTEGER currentPosition; -}; - -typedef struct HGLOBALStreamImpl HGLOBALStreamImpl; - -/*** - * This is the destructor of the HGLOBALStreamImpl class. - * - * This method will clean-up all the resources used-up by the given HGLOBALStreamImpl - * class. The pointer passed-in to this function will be freed and will not - * be valid anymore. - */ -static void HGLOBALStreamImpl_Destroy(HGLOBALStreamImpl* This) -{ - TRACE("(%p)\n", This); - - /* - * Release the HGlobal if the constructor asked for that. - */ - if (This->deleteOnRelease) - { - GlobalFree(This->supportHandle); - This->supportHandle=0; - } - - /* - * Finally, free the memory used-up by the class. - */ - HeapFree(GetProcessHeap(), 0, This); -} - -/*** - * This implements the IUnknown method AddRef for this - * class - */ -static ULONG WINAPI HGLOBALStreamImpl_AddRef( - IStream* iface) -{ - HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface; - return InterlockedIncrement(&This->ref); -} - -/*** - * This implements the IUnknown method QueryInterface for this - * class - */ -static HRESULT WINAPI HGLOBALStreamImpl_QueryInterface( - IStream* iface, - REFIID riid, /* [in] */ - void** ppvObject) /* [iid_is][out] */ -{ - HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface; - - /* - * Perform a sanity check on the parameters. - */ - if (ppvObject==0) - return E_INVALIDARG; - - /* - * Initialize the return parameter. - */ - *ppvObject = 0; - - /* - * Compare the riid with the interface IDs implemented by this object. - */ - if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) - { - *ppvObject = (IStream*)This; - } - else if (memcmp(&IID_IStream, riid, sizeof(IID_IStream)) == 0) - { - *ppvObject = (IStream*)This; - } - - /* - * Check that we obtained an interface. - */ - if ((*ppvObject)==0) - return E_NOINTERFACE; - - /* - * Query Interface always increases the reference count by one when it is - * successful - */ - HGLOBALStreamImpl_AddRef(iface); - - return S_OK; -} - -/*** - * This implements the IUnknown method Release for this - * class - */ -static ULONG WINAPI HGLOBALStreamImpl_Release( - IStream* iface) -{ - HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface; - ULONG newRef; - - newRef = InterlockedDecrement(&This->ref); - - /* - * If the reference count goes down to 0, perform suicide. - */ - if (newRef==0) - { - HGLOBALStreamImpl_Destroy(This); - } - - return newRef; -} - -/*** - * This method is part of the ISequentialStream interface. - * - * If reads a block of information from the stream at the current - * position. It then moves the current position at the end of the - * read block - * - * See the documentation of ISequentialStream for more info. - */ -static HRESULT WINAPI HGLOBALStreamImpl_Read( - IStream* iface, - void* pv, /* [length_is][size_is][out] */ - ULONG cb, /* [in] */ - ULONG* pcbRead) /* [out] */ -{ - HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface; - - void* supportBuffer; - ULONG bytesReadBuffer; - ULONG bytesToReadFromBuffer; - - TRACE("(%p, %p, %ld, %p)\n", iface, - pv, cb, pcbRead); - - /* - * If the caller is not interested in the nubmer of bytes read, - * we use another buffer to avoid "if" statements in the code. - */ - if (pcbRead==0) - pcbRead = &bytesReadBuffer; - - /* - * Using the known size of the stream, calculate the number of bytes - * to read from the block chain - */ - bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb); - - /* - * Lock the buffer in position and copy the data. - */ - supportBuffer = GlobalLock(This->supportHandle); - - memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer); - - /* - * Move the current position to the new position - */ - This->currentPosition.u.LowPart+=bytesToReadFromBuffer; - - /* - * Return the number of bytes read. - */ - *pcbRead = bytesToReadFromBuffer; - - /* - * Cleanup - */ - GlobalUnlock(This->supportHandle); - - /* - * The function returns S_OK if the buffer was filled completely - * it returns S_FALSE if the end of the stream is reached before the - * buffer is filled - */ - if(*pcbRead == cb) - return S_OK; - - return S_FALSE; -} - -/*** - * This method is part of the ISequentialStream interface. - * - * It writes a block of information to the stream at the current - * position. It then moves the current position at the end of the - * written block. If the stream is too small to fit the block, - * the stream is grown to fit. - * - * See the documentation of ISequentialStream for more info. - */ -static HRESULT WINAPI HGLOBALStreamImpl_Write( - IStream* iface, - const void* pv, /* [size_is][in] */ - ULONG cb, /* [in] */ - ULONG* pcbWritten) /* [out] */ -{ - HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface; - - void* supportBuffer; - ULARGE_INTEGER newSize; - ULONG bytesWritten = 0; - - TRACE("(%p, %p, %ld, %p)\n", iface, - pv, cb, pcbWritten); - - /* - * If the caller is not interested in the number of bytes written, - * we use another buffer to avoid "if" statements in the code. - */ - if (pcbWritten == 0) - pcbWritten = &bytesWritten; - - if (cb == 0) - { - return S_OK; - } - else - { - newSize.u.HighPart = 0; - newSize.u.LowPart = This->currentPosition.u.LowPart + cb; - } - - /* - * Verify if we need to grow the stream - */ - if (newSize.u.LowPart > This->streamSize.u.LowPart) - { - /* grow stream */ - IStream_SetSize(iface, newSize); - } - - /* - * Lock the buffer in position and copy the data. - */ - supportBuffer = GlobalLock(This->supportHandle); - - memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb); - - /* - * Move the current position to the new position - */ - This->currentPosition.u.LowPart+=cb; - - /* - * Return the number of bytes read. - */ - *pcbWritten = cb; - - /* - * Cleanup - */ - GlobalUnlock(This->supportHandle); - - return S_OK; -} - -/*** - * This method is part of the IStream interface. - * - * It will move the current stream pointer according to the parameters - * given. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI HGLOBALStreamImpl_Seek( - IStream* iface, - LARGE_INTEGER dlibMove, /* [in] */ - DWORD dwOrigin, /* [in] */ - ULARGE_INTEGER* plibNewPosition) /* [out] */ -{ - HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface; - - ULARGE_INTEGER newPosition; - - TRACE("(%p, %lx%08lx, %ld, %p)\n", iface, dlibMove.u.HighPart, - dlibMove.u.LowPart, dwOrigin, plibNewPosition); - - /* - * The file pointer is moved depending on the given "function" - * parameter. - */ - switch (dwOrigin) - { - case STREAM_SEEK_SET: - newPosition.u.HighPart = 0; - newPosition.u.LowPart = 0; - break; - case STREAM_SEEK_CUR: - newPosition = This->currentPosition; - break; - case STREAM_SEEK_END: - newPosition = This->streamSize; - break; - default: - return STG_E_INVALIDFUNCTION; - } - - /* - * Move the actual file pointer - * If the file pointer ends-up after the end of the stream, the next Write operation will - * make the file larger. This is how it is documented. - */ - if (dlibMove.QuadPart < 0 && newPosition.QuadPart < -dlibMove.QuadPart) return STG_E_INVALIDFUNCTION; - - newPosition.QuadPart = RtlLargeIntegerAdd(newPosition.QuadPart, dlibMove.QuadPart); - - if (plibNewPosition) *plibNewPosition = newPosition; - This->currentPosition = newPosition; - - return S_OK; -} - -/*** - * This method is part of the IStream interface. - * - * It will change the size of a stream. - * - * TODO: Switch from small blocks to big blocks and vice versa. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI HGLOBALStreamImpl_SetSize( - IStream* iface, - ULARGE_INTEGER libNewSize) /* [in] */ -{ - HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface; - HGLOBAL supportHandle; - - TRACE("(%p, %ld)\n", iface, libNewSize.u.LowPart); - - /* - * As documented. - */ - if (libNewSize.u.HighPart != 0) - return STG_E_INVALIDFUNCTION; - - if (This->streamSize.u.LowPart == libNewSize.u.LowPart) - return S_OK; - - /* - * Re allocate the HGlobal to fit the new size of the stream. - */ - supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0); - - if (supportHandle == 0) - return STG_E_MEDIUMFULL; - - This->supportHandle = supportHandle; - This->streamSize.u.LowPart = libNewSize.u.LowPart; - - return S_OK; -} - -/*** - * This method is part of the IStream interface. - * - * It will copy the 'cb' Bytes to 'pstm' IStream. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI HGLOBALStreamImpl_CopyTo( - IStream* iface, - IStream* pstm, /* [unique][in] */ - ULARGE_INTEGER cb, /* [in] */ - ULARGE_INTEGER* pcbRead, /* [out] */ - ULARGE_INTEGER* pcbWritten) /* [out] */ -{ - HRESULT hr = S_OK; - BYTE tmpBuffer[128]; - ULONG bytesRead, bytesWritten, copySize; - ULARGE_INTEGER totalBytesRead; - ULARGE_INTEGER totalBytesWritten; - - TRACE("(%p, %p, %ld, %p, %p)\n", iface, pstm, - cb.u.LowPart, pcbRead, pcbWritten); - - /* - * Sanity check - */ - if ( pstm == 0 ) - return STG_E_INVALIDPOINTER; - - totalBytesRead.u.LowPart = totalBytesRead.u.HighPart = 0; - totalBytesWritten.u.LowPart = totalBytesWritten.u.HighPart = 0; - - /* - * use stack to store data temporarly - * there is surely more performant way of doing it, for now this basic - * implementation will do the job - */ - while ( cb.u.LowPart > 0 ) - { - if ( cb.u.LowPart >= 128 ) - copySize = 128; - else - copySize = cb.u.LowPart; - - IStream_Read(iface, tmpBuffer, copySize, &bytesRead); - - totalBytesRead.u.LowPart += bytesRead; - - IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten); - - totalBytesWritten.u.LowPart += bytesWritten; - - /* - * Check that read & write operations were succesfull - */ - if (bytesRead != bytesWritten) - { - hr = STG_E_MEDIUMFULL; - break; - } - - if (bytesRead!=copySize) - cb.u.LowPart = 0; - else - cb.u.LowPart -= bytesRead; - } - - /* - * Update number of bytes read and written - */ - if (pcbRead) - { - pcbRead->u.LowPart = totalBytesRead.u.LowPart; - pcbRead->u.HighPart = totalBytesRead.u.HighPart; - } - - if (pcbWritten) - { - pcbWritten->u.LowPart = totalBytesWritten.u.LowPart; - pcbWritten->u.HighPart = totalBytesWritten.u.HighPart; - } - return hr; -} - -/*** - * This method is part of the IStream interface. - * - * For streams supported by HGLOBALS, this function does nothing. - * This is what the documentation tells us. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI HGLOBALStreamImpl_Commit( - IStream* iface, - DWORD grfCommitFlags) /* [in] */ -{ - return S_OK; -} - -/*** - * This method is part of the IStream interface. - * - * For streams supported by HGLOBALS, this function does nothing. - * This is what the documentation tells us. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI HGLOBALStreamImpl_Revert( - IStream* iface) -{ - return S_OK; -} - -/*** - * This method is part of the IStream interface. - * - * For streams supported by HGLOBALS, this function does nothing. - * This is what the documentation tells us. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI HGLOBALStreamImpl_LockRegion( - IStream* iface, - ULARGE_INTEGER libOffset, /* [in] */ - ULARGE_INTEGER cb, /* [in] */ - DWORD dwLockType) /* [in] */ -{ - return S_OK; -} - -/* - * This method is part of the IStream interface. - * - * For streams supported by HGLOBALS, this function does nothing. - * This is what the documentation tells us. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI HGLOBALStreamImpl_UnlockRegion( - IStream* iface, - ULARGE_INTEGER libOffset, /* [in] */ - ULARGE_INTEGER cb, /* [in] */ - DWORD dwLockType) /* [in] */ -{ - return S_OK; -} - -/*** - * This method is part of the IStream interface. - * - * This method returns information about the current - * stream. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI HGLOBALStreamImpl_Stat( - IStream* iface, - STATSTG* pstatstg, /* [out] */ - DWORD grfStatFlag) /* [in] */ -{ - HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface; - - memset(pstatstg, 0, sizeof(STATSTG)); - - pstatstg->pwcsName = NULL; - pstatstg->type = STGTY_STREAM; - pstatstg->cbSize = This->streamSize; - - return S_OK; -} - -static HRESULT WINAPI HGLOBALStreamImpl_Clone( - IStream* iface, - IStream** ppstm) /* [out] */ -{ - ULARGE_INTEGER dummy; - LARGE_INTEGER offset; - HRESULT hr; - HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface; - TRACE(" Cloning %p (deleteOnRelease=%d seek position=%ld)\n",iface,This->deleteOnRelease,(long)This->currentPosition.QuadPart); - hr=CreateStreamOnHGlobal(This->supportHandle, FALSE, ppstm); - if(FAILED(hr)) - return hr; - offset.QuadPart=(LONGLONG)This->currentPosition.QuadPart; - HGLOBALStreamImpl_Seek(*ppstm,offset,STREAM_SEEK_SET,&dummy); - return S_OK; -} - -/* - * Virtual function table for the HGLOBALStreamImpl class. - */ -static IStreamVtbl HGLOBALStreamImpl_Vtbl = -{ - HGLOBALStreamImpl_QueryInterface, - HGLOBALStreamImpl_AddRef, - HGLOBALStreamImpl_Release, - HGLOBALStreamImpl_Read, - HGLOBALStreamImpl_Write, - HGLOBALStreamImpl_Seek, - HGLOBALStreamImpl_SetSize, - HGLOBALStreamImpl_CopyTo, - HGLOBALStreamImpl_Commit, - HGLOBALStreamImpl_Revert, - HGLOBALStreamImpl_LockRegion, - HGLOBALStreamImpl_UnlockRegion, - HGLOBALStreamImpl_Stat, - HGLOBALStreamImpl_Clone -}; - -/****************************************************************************** -** HGLOBALStreamImpl implementation -*/ - -/*** - * This is the constructor for the HGLOBALStreamImpl class. - * - * Params: - * hGlobal - Handle that will support the stream. can be NULL. - * fDeleteOnRelease - Flag set to TRUE if the HGLOBAL will be released - * when the IStream object is destroyed. - */ -HGLOBALStreamImpl* HGLOBALStreamImpl_Construct( - HGLOBAL hGlobal, - BOOL fDeleteOnRelease) -{ - HGLOBALStreamImpl* newStream; - - newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALStreamImpl)); - - if (newStream!=0) - { - /* - * Set-up the virtual function table and reference count. - */ - newStream->lpVtbl = &HGLOBALStreamImpl_Vtbl; - newStream->ref = 0; - - /* - * Initialize the support. - */ - newStream->supportHandle = hGlobal; - newStream->deleteOnRelease = fDeleteOnRelease; - - /* - * This method will allocate a handle if one is not supplied. - */ - if (!newStream->supportHandle) - { - newStream->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD | - GMEM_SHARE, 0); - } - - /* - * Start the stream at the beginning. - */ - newStream->currentPosition.u.HighPart = 0; - newStream->currentPosition.u.LowPart = 0; - - /* - * Initialize the size of the stream to the size of the handle. - */ - newStream->streamSize.u.HighPart = 0; - newStream->streamSize.u.LowPart = GlobalSize(newStream->supportHandle); - } - - return newStream; -} - - -/*********************************************************************** - * CreateStreamOnHGlobal [OLE32.@] - */ -HRESULT WINAPI CreateStreamOnHGlobal( - HGLOBAL hGlobal, - BOOL fDeleteOnRelease, - LPSTREAM* ppstm) -{ - HGLOBALStreamImpl* newStream; - - newStream = HGLOBALStreamImpl_Construct(hGlobal, - fDeleteOnRelease); - - if (newStream!=NULL) - { - return IUnknown_QueryInterface((IUnknown*)newStream, - &IID_IStream, - (void**)ppstm); - } - - return E_OUTOFMEMORY; -} - -/*********************************************************************** - * GetHGlobalFromStream [OLE32.@] - */ -HRESULT WINAPI GetHGlobalFromStream(IStream* pstm, HGLOBAL* phglobal) -{ - HGLOBALStreamImpl* pStream; - - if (pstm == NULL) - return E_INVALIDARG; - - pStream = (HGLOBALStreamImpl*) pstm; - - /* - * Verify that the stream object was created with CreateStreamOnHGlobal. - */ - if (pStream->lpVtbl == &HGLOBALStreamImpl_Vtbl) - *phglobal = pStream->supportHandle; - else - { - *phglobal = 0; - return E_INVALIDARG; - } - - return S_OK; -} +/* + * HGLOBAL Stream implementation + * + * This file contains the implementation of the stream interface + * for streams contained supported by an HGLOBAL pointer. + * + * Copyright 1999 Francis Beaudet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <assert.h> +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "objbase.h" +#include "ole2.h" +#include "winerror.h" +#include "winreg.h" +#include "winternl.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(storage); + +/**************************************************************************** + * HGLOBALStreamImpl definition. + * + * This class imlements the IStream inteface and represents a stream + * supported by an HGLOBAL pointer. + */ +struct HGLOBALStreamImpl +{ + IStreamVtbl *lpVtbl; /* Needs to be the first item in the struct + * since we want to cast this in an IStream pointer */ + + /* + * Reference count + */ + ULONG ref; + + /* + * Support for the stream + */ + HGLOBAL supportHandle; + + /* + * This flag is TRUE if the HGLOBAL is destroyed when the stream + * is finally released. + */ + BOOL deleteOnRelease; + + /* + * Helper variable that contains the size of the stream + */ + ULARGE_INTEGER streamSize; + + /* + * This is the current position of the cursor in the stream + */ + ULARGE_INTEGER currentPosition; +}; + +typedef struct HGLOBALStreamImpl HGLOBALStreamImpl; + +/*** + * This is the destructor of the HGLOBALStreamImpl class. + * + * This method will clean-up all the resources used-up by the given HGLOBALStreamImpl + * class. The pointer passed-in to this function will be freed and will not + * be valid anymore. + */ +static void HGLOBALStreamImpl_Destroy(HGLOBALStreamImpl* This) +{ + TRACE("(%p)\n", This); + + /* + * Release the HGlobal if the constructor asked for that. + */ + if (This->deleteOnRelease) + { + GlobalFree(This->supportHandle); + This->supportHandle=0; + } + + /* + * Finally, free the memory used-up by the class. + */ + HeapFree(GetProcessHeap(), 0, This); +} + +/*** + * This implements the IUnknown method AddRef for this + * class + */ +static ULONG WINAPI HGLOBALStreamImpl_AddRef( + IStream* iface) +{ + HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface; + return InterlockedIncrement(&This->ref); +} + +/*** + * This implements the IUnknown method QueryInterface for this + * class + */ +static HRESULT WINAPI HGLOBALStreamImpl_QueryInterface( + IStream* iface, + REFIID riid, /* [in] */ + void** ppvObject) /* [iid_is][out] */ +{ + HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface; + + /* + * Perform a sanity check on the parameters. + */ + if (ppvObject==0) + return E_INVALIDARG; + + /* + * Initialize the return parameter. + */ + *ppvObject = 0; + + /* + * Compare the riid with the interface IDs implemented by this object. + */ + if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) + { + *ppvObject = (IStream*)This; + } + else if (memcmp(&IID_IStream, riid, sizeof(IID_IStream)) == 0) + { + *ppvObject = (IStream*)This; + } + + /* + * Check that we obtained an interface. + */ + if ((*ppvObject)==0) + return E_NOINTERFACE; + + /* + * Query Interface always increases the reference count by one when it is + * successful + */ + HGLOBALStreamImpl_AddRef(iface); + + return S_OK; +} + +/*** + * This implements the IUnknown method Release for this + * class + */ +static ULONG WINAPI HGLOBALStreamImpl_Release( + IStream* iface) +{ + HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface; + ULONG newRef; + + newRef = InterlockedDecrement(&This->ref); + + /* + * If the reference count goes down to 0, perform suicide. + */ + if (newRef==0) + { + HGLOBALStreamImpl_Destroy(This); + } + + return newRef; +} + +/*** + * This method is part of the ISequentialStream interface. + * + * If reads a block of information from the stream at the current + * position. It then moves the current position at the end of the + * read block + * + * See the documentation of ISequentialStream for more info. + */ +static HRESULT WINAPI HGLOBALStreamImpl_Read( + IStream* iface, + void* pv, /* [length_is][size_is][out] */ + ULONG cb, /* [in] */ + ULONG* pcbRead) /* [out] */ +{ + HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface; + + void* supportBuffer; + ULONG bytesReadBuffer; + ULONG bytesToReadFromBuffer; + + TRACE("(%p, %p, %ld, %p)\n", iface, + pv, cb, pcbRead); + + /* + * If the caller is not interested in the nubmer of bytes read, + * we use another buffer to avoid "if" statements in the code. + */ + if (pcbRead==0) + pcbRead = &bytesReadBuffer; + + /* + * Using the known size of the stream, calculate the number of bytes + * to read from the block chain + */ + bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb); + + /* + * Lock the buffer in position and copy the data. + */ + supportBuffer = GlobalLock(This->supportHandle); + + memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer); + + /* + * Move the current position to the new position + */ + This->currentPosition.u.LowPart+=bytesToReadFromBuffer; + + /* + * Return the number of bytes read. + */ + *pcbRead = bytesToReadFromBuffer; + + /* + * Cleanup + */ + GlobalUnlock(This->supportHandle); + + /* + * The function returns S_OK if the buffer was filled completely + * it returns S_FALSE if the end of the stream is reached before the + * buffer is filled + */ + if(*pcbRead == cb) + return S_OK; + + return S_FALSE; +} + +/*** + * This method is part of the ISequentialStream interface. + * + * It writes a block of information to the stream at the current + * position. It then moves the current position at the end of the + * written block. If the stream is too small to fit the block, + * the stream is grown to fit. + * + * See the documentation of ISequentialStream for more info. + */ +static HRESULT WINAPI HGLOBALStreamImpl_Write( + IStream* iface, + const void* pv, /* [size_is][in] */ + ULONG cb, /* [in] */ + ULONG* pcbWritten) /* [out] */ +{ + HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface; + + void* supportBuffer; + ULARGE_INTEGER newSize; + ULONG bytesWritten = 0; + + TRACE("(%p, %p, %ld, %p)\n", iface, + pv, cb, pcbWritten); + + /* + * If the caller is not interested in the number of bytes written, + * we use another buffer to avoid "if" statements in the code. + */ + if (pcbWritten == 0) + pcbWritten = &bytesWritten; + + if (cb == 0) + { + return S_OK; + } + else + { + newSize.u.HighPart = 0; + newSize.u.LowPart = This->currentPosition.u.LowPart + cb; + } + + /* + * Verify if we need to grow the stream + */ + if (newSize.u.LowPart > This->streamSize.u.LowPart) + { + /* grow stream */ + IStream_SetSize(iface, newSize); + } + + /* + * Lock the buffer in position and copy the data. + */ + supportBuffer = GlobalLock(This->supportHandle); + + memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb); + + /* + * Move the current position to the new position + */ + This->currentPosition.u.LowPart+=cb; + + /* + * Return the number of bytes read. + */ + *pcbWritten = cb; + + /* + * Cleanup + */ + GlobalUnlock(This->supportHandle); + + return S_OK; +} + +/*** + * This method is part of the IStream interface. + * + * It will move the current stream pointer according to the parameters + * given. + * + * See the documentation of IStream for more info. + */ +static HRESULT WINAPI HGLOBALStreamImpl_Seek( + IStream* iface, + LARGE_INTEGER dlibMove, /* [in] */ + DWORD dwOrigin, /* [in] */ + ULARGE_INTEGER* plibNewPosition) /* [out] */ +{ + HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface; + + ULARGE_INTEGER newPosition; + + TRACE("(%p, %lx%08lx, %ld, %p)\n", iface, dlibMove.u.HighPart, + dlibMove.u.LowPart, dwOrigin, plibNewPosition); + + /* + * The file pointer is moved depending on the given "function" + * parameter. + */ + switch (dwOrigin) + { + case STREAM_SEEK_SET: + newPosition.u.HighPart = 0; + newPosition.u.LowPart = 0; + break; + case STREAM_SEEK_CUR: + newPosition = This->currentPosition; + break; + case STREAM_SEEK_END: + newPosition = This->streamSize; + break; + default: + return STG_E_INVALIDFUNCTION; + } + + /* + * Move the actual file pointer + * If the file pointer ends-up after the end of the stream, the next Write operation will + * make the file larger. This is how it is documented. + */ + if (dlibMove.QuadPart < 0 && newPosition.QuadPart < -dlibMove.QuadPart) return STG_E_INVALIDFUNCTION; + + newPosition.QuadPart = RtlLargeIntegerAdd(newPosition.QuadPart, dlibMove.QuadPart); + + if (plibNewPosition) *plibNewPosition = newPosition; + This->currentPosition = newPosition; + + return S_OK; +} + +/*** + * This method is part of the IStream interface. + * + * It will change the size of a stream. + * + * TODO: Switch from small blocks to big blocks and vice versa. + * + * See the documentation of IStream for more info. + */ +static HRESULT WINAPI HGLOBALStreamImpl_SetSize( + IStream* iface, + ULARGE_INTEGER libNewSize) /* [in] */ +{ + HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface; + HGLOBAL supportHandle; + + TRACE("(%p, %ld)\n", iface, libNewSize.u.LowPart); + + /* + * As documented. + */ + if (libNewSize.u.HighPart != 0) + return STG_E_INVALIDFUNCTION; + + if (This->streamSize.u.LowPart == libNewSize.u.LowPart) + return S_OK; + + /* + * Re allocate the HGlobal to fit the new size of the stream. + */ + supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0); + + if (supportHandle == 0) + return STG_E_MEDIUMFULL; + + This->supportHandle = supportHandle; + This->streamSize.u.LowPart = libNewSize.u.LowPart; + + return S_OK; +} + +/*** + * This method is part of the IStream interface. + * + * It will copy the 'cb' Bytes to 'pstm' IStream. + * + * See the documentation of IStream for more info. + */ +static HRESULT WINAPI HGLOBALStreamImpl_CopyTo( + IStream* iface, + IStream* pstm, /* [unique][in] */ + ULARGE_INTEGER cb, /* [in] */ + ULARGE_INTEGER* pcbRead, /* [out] */ + ULARGE_INTEGER* pcbWritten) /* [out] */ +{ + HRESULT hr = S_OK; + BYTE tmpBuffer[128]; + ULONG bytesRead, bytesWritten, copySize; + ULARGE_INTEGER totalBytesRead; + ULARGE_INTEGER totalBytesWritten; + + TRACE("(%p, %p, %ld, %p, %p)\n", iface, pstm, + cb.u.LowPart, pcbRead, pcbWritten); + + /* + * Sanity check + */ + if ( pstm == 0 ) + return STG_E_INVALIDPOINTER; + + totalBytesRead.u.LowPart = totalBytesRead.u.HighPart = 0; + totalBytesWritten.u.LowPart = totalBytesWritten.u.HighPart = 0; + + /* + * use stack to store data temporarly + * there is surely more performant way of doing it, for now this basic + * implementation will do the job + */ + while ( cb.u.LowPart > 0 ) + { + if ( cb.u.LowPart >= 128 ) + copySize = 128; + else + copySize = cb.u.LowPart; + + IStream_Read(iface, tmpBuffer, copySize, &bytesRead); + + totalBytesRead.u.LowPart += bytesRead; + + IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten); + + totalBytesWritten.u.LowPart += bytesWritten; + + /* + * Check that read & write operations were succesfull + */ + if (bytesRead != bytesWritten) + { + hr = STG_E_MEDIUMFULL; + break; + } + + if (bytesRead!=copySize) + cb.u.LowPart = 0; + else + cb.u.LowPart -= bytesRead; + } + + /* + * Update number of bytes read and written + */ + if (pcbRead) + { + pcbRead->u.LowPart = totalBytesRead.u.LowPart; + pcbRead->u.HighPart = totalBytesRead.u.HighPart; + } + + if (pcbWritten) + { + pcbWritten->u.LowPart = totalBytesWritten.u.LowPart; + pcbWritten->u.HighPart = totalBytesWritten.u.HighPart; + } + return hr; +} + +/*** + * This method is part of the IStream interface. + * + * For streams supported by HGLOBALS, this function does nothing. + * This is what the documentation tells us. + * + * See the documentation of IStream for more info. + */ +static HRESULT WINAPI HGLOBALStreamImpl_Commit( + IStream* iface, + DWORD grfCommitFlags) /* [in] */ +{ + return S_OK; +} + +/*** + * This method is part of the IStream interface. + * + * For streams supported by HGLOBALS, this function does nothing. + * This is what the documentation tells us. + * + * See the documentation of IStream for more info. + */ +static HRESULT WINAPI HGLOBALStreamImpl_Revert( + IStream* iface) +{ + return S_OK; +} + +/*** + * This method is part of the IStream interface. + * + * For streams supported by HGLOBALS, this function does nothing. + * This is what the documentation tells us. + * + * See the documentation of IStream for more info. + */ +static HRESULT WINAPI HGLOBALStreamImpl_LockRegion( + IStream* iface, + ULARGE_INTEGER libOffset, /* [in] */ + ULARGE_INTEGER cb, /* [in] */ + DWORD dwLockType) /* [in] */ +{ + return S_OK; +} + +/* + * This method is part of the IStream interface. + * + * For streams supported by HGLOBALS, this function does nothing. + * This is what the documentation tells us. + * + * See the documentation of IStream for more info. + */ +static HRESULT WINAPI HGLOBALStreamImpl_UnlockRegion( + IStream* iface, + ULARGE_INTEGER libOffset, /* [in] */ + ULARGE_INTEGER cb, /* [in] */ + DWORD dwLockType) /* [in] */ +{ + return S_OK; +} + +/*** + * This method is part of the IStream interface. + * + * This method returns information about the current + * stream. + * + * See the documentation of IStream for more info. + */ +static HRESULT WINAPI HGLOBALStreamImpl_Stat( + IStream* iface, + STATSTG* pstatstg, /* [out] */ + DWORD grfStatFlag) /* [in] */ +{ + HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface; + + memset(pstatstg, 0, sizeof(STATSTG)); + + pstatstg->pwcsName = NULL; + pstatstg->type = STGTY_STREAM; + pstatstg->cbSize = This->streamSize; + + return S_OK; +} + +static HRESULT WINAPI HGLOBALStreamImpl_Clone( + IStream* iface, + IStream** ppstm) /* [out] */ +{ + ULARGE_INTEGER dummy; + LARGE_INTEGER offset; + HRESULT hr; + HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface; + TRACE(" Cloning %p (deleteOnRelease=%d seek position=%ld)\n",iface,This->deleteOnRelease,(long)This->currentPosition.QuadPart); + hr=CreateStreamOnHGlobal(This->supportHandle, FALSE, ppstm); + if(FAILED(hr)) + return hr; + offset.QuadPart=(LONGLONG)This->currentPosition.QuadPart; + HGLOBALStreamImpl_Seek(*ppstm,offset,STREAM_SEEK_SET,&dummy); + return S_OK; +} + +/* + * Virtual function table for the HGLOBALStreamImpl class. + */ +static IStreamVtbl HGLOBALStreamImpl_Vtbl = +{ + HGLOBALStreamImpl_QueryInterface, + HGLOBALStreamImpl_AddRef, + HGLOBALStreamImpl_Release, + HGLOBALStreamImpl_Read, + HGLOBALStreamImpl_Write, + HGLOBALStreamImpl_Seek, + HGLOBALStreamImpl_SetSize, + HGLOBALStreamImpl_CopyTo, + HGLOBALStreamImpl_Commit, + HGLOBALStreamImpl_Revert, + HGLOBALStreamImpl_LockRegion, + HGLOBALStreamImpl_UnlockRegion, + HGLOBALStreamImpl_Stat, + HGLOBALStreamImpl_Clone +}; + +/****************************************************************************** +** HGLOBALStreamImpl implementation +*/ + +/*** + * This is the constructor for the HGLOBALStreamImpl class. + * + * Params: + * hGlobal - Handle that will support the stream. can be NULL. + * fDeleteOnRelease - Flag set to TRUE if the HGLOBAL will be released + * when the IStream object is destroyed. + */ +HGLOBALStreamImpl* HGLOBALStreamImpl_Construct( + HGLOBAL hGlobal, + BOOL fDeleteOnRelease) +{ + HGLOBALStreamImpl* newStream; + + newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALStreamImpl)); + + if (newStream!=0) + { + /* + * Set-up the virtual function table and reference count. + */ + newStream->lpVtbl = &HGLOBALStreamImpl_Vtbl; + newStream->ref = 0; + + /* + * Initialize the support. + */ + newStream->supportHandle = hGlobal; + newStream->deleteOnRelease = fDeleteOnRelease; + + /* + * This method will allocate a handle if one is not supplied. + */ + if (!newStream->supportHandle) + { + newStream->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD | + GMEM_SHARE, 0); + } + + /* + * Start the stream at the beginning. + */ + newStream->currentPosition.u.HighPart = 0; + newStream->currentPosition.u.LowPart = 0; + + /* + * Initialize the size of the stream to the size of the handle. + */ + newStream->streamSize.u.HighPart = 0; + newStream->streamSize.u.LowPart = GlobalSize(newStream->supportHandle); + } + + return newStream; +} + + +/*********************************************************************** + * CreateStreamOnHGlobal [OLE32.@] + */ +HRESULT WINAPI CreateStreamOnHGlobal( + HGLOBAL hGlobal, + BOOL fDeleteOnRelease, + LPSTREAM* ppstm) +{ + HGLOBALStreamImpl* newStream; + + newStream = HGLOBALStreamImpl_Construct(hGlobal, + fDeleteOnRelease); + + if (newStream!=NULL) + { + return IUnknown_QueryInterface((IUnknown*)newStream, + &IID_IStream, + (void**)ppstm); + } + + return E_OUTOFMEMORY; +} + +/*********************************************************************** + * GetHGlobalFromStream [OLE32.@] + */ +HRESULT WINAPI GetHGlobalFromStream(IStream* pstm, HGLOBAL* phglobal) +{ + HGLOBALStreamImpl* pStream; + + if (pstm == NULL) + return E_INVALIDARG; + + pStream = (HGLOBALStreamImpl*) pstm; + + /* + * Verify that the stream object was created with CreateStreamOnHGlobal. + */ + if (pStream->lpVtbl == &HGLOBALStreamImpl_Vtbl) + *phglobal = pStream->supportHandle; + else + { + *phglobal = 0; + return E_INVALIDARG; + } + + return S_OK; +} diff --git a/reactos/lib/ole32/ifs.c b/reactos/lib/ole32/ifs.c index 5b34864ba1c..3d8ffea385d 100644 --- a/reactos/lib/ole32/ifs.c +++ b/reactos/lib/ole32/ifs.c @@ -1,699 +1,699 @@ -/* - * basic interfaces - * - * Copyright 1997 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <ctype.h> -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "ole2.h" -#include "winerror.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(olemalloc); - -/****************************************************************************** - * IMalloc32 implementation - * - * NOTES - * For supporting CoRegisterMallocSpy the IMalloc implementation must know if - * a given memory block was allocated with a spy active. - * - *****************************************************************************/ -/* set the vtable later */ -static IMallocVtbl VT_IMalloc32; - -typedef struct { - IMallocVtbl *lpVtbl; - DWORD dummy; /* nothing, we are static */ - IMallocSpy * pSpy; /* the spy when active */ - DWORD SpyedAllocationsLeft; /* number of spyed allocations left */ - BOOL SpyReleasePending; /* CoRevokeMallocSpy called with spyed allocations left*/ - LPVOID * SpyedBlocks; /* root of the table */ - int SpyedBlockTableLength; /* size of the table*/ -} _Malloc32; - -/* this is the static object instance */ -_Malloc32 Malloc32 = {&VT_IMalloc32, 0, NULL, 0, 0, NULL, 0}; - -/* with a spy active all calls from pre to post methods are threadsave */ -static CRITICAL_SECTION IMalloc32_SpyCS; -static CRITICAL_SECTION_DEBUG critsect_debug = -{ - 0, 0, &IMalloc32_SpyCS, - { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, - 0, 0, { 0, (DWORD)(__FILE__ ": IMalloc32_SpyCS") } -}; -static CRITICAL_SECTION IMalloc32_SpyCS = { &critsect_debug, -1, 0, 0, 0, 0 }; - -/* resize the old table */ -static int SetSpyedBlockTableLength ( int NewLength ) -{ - LPVOID *NewSpyedBlocks; - - if (!Malloc32.SpyedBlocks) NewSpyedBlocks = LocalAlloc(LMEM_ZEROINIT, NewLength * sizeof(PVOID)); - else NewSpyedBlocks = LocalReAlloc(Malloc32.SpyedBlocks, NewLength * sizeof(PVOID), LMEM_ZEROINIT); - if (NewSpyedBlocks) { - Malloc32.SpyedBlocks = NewSpyedBlocks; - Malloc32.SpyedBlockTableLength = NewLength; - } - - return NewSpyedBlocks != NULL; -} - -/* add a location to the table */ -static int AddMemoryLocation(LPVOID * pMem) -{ - LPVOID * Current; - - /* allocate the table if not already allocated */ - if (!Malloc32.SpyedBlockTableLength) { - if (!SetSpyedBlockTableLength(0x1000)) return 0; - } - - /* find a free location */ - Current = Malloc32.SpyedBlocks; - while (*Current) { - Current++; - if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) { - /* no more space in table, grow it */ - if (!SetSpyedBlockTableLength( Malloc32.SpyedBlockTableLength + 0x1000 )) return 0; - } - }; - - /* put the location in our table */ - *Current = pMem; - Malloc32.SpyedAllocationsLeft++; - /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/ - return 1; -} - -static int RemoveMemoryLocation(LPVOID * pMem) -{ - LPVOID * Current; - - /* allocate the table if not already allocated */ - if (!Malloc32.SpyedBlockTableLength) { - if (!SetSpyedBlockTableLength(0x1000)) return 0; - } - - Current = Malloc32.SpyedBlocks; - - /* find the location */ - while (*Current != pMem) { - Current++; - if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) return 0; /* not found */ - } - - /* location found */ - Malloc32.SpyedAllocationsLeft--; - /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/ - *Current = NULL; - return 1; -} - -/****************************************************************************** - * IMalloc32_QueryInterface [VTABLE] - */ -static HRESULT WINAPI IMalloc_fnQueryInterface(LPMALLOC iface,REFIID refiid,LPVOID *obj) { - - TRACE("(%s,%p)\n",debugstr_guid(refiid),obj); - - if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMalloc,refiid)) { - *obj = (LPMALLOC)&Malloc32; - return S_OK; - } - return E_NOINTERFACE; -} - -/****************************************************************************** - * IMalloc32_AddRefRelease [VTABLE] - */ -static ULONG WINAPI IMalloc_fnAddRefRelease (LPMALLOC iface) { - return 1; -} - -/****************************************************************************** - * IMalloc32_Alloc [VTABLE] - */ -static LPVOID WINAPI IMalloc_fnAlloc(LPMALLOC iface, DWORD cb) { - - LPVOID addr; - - TRACE("(%ld)\n",cb); - - if(Malloc32.pSpy) { - DWORD preAllocResult; - - EnterCriticalSection(&IMalloc32_SpyCS); - preAllocResult = IMallocSpy_PreAlloc(Malloc32.pSpy, cb); - if ((cb != 0) && (preAllocResult == 0)) { - /* PreAlloc can force Alloc to fail, but not if cb == 0 */ - TRACE("returning null\n"); - LeaveCriticalSection(&IMalloc32_SpyCS); - return NULL; - } - } - - addr = HeapAlloc(GetProcessHeap(),0,cb); - - if(Malloc32.pSpy) { - addr = IMallocSpy_PostAlloc(Malloc32.pSpy, addr); - if (addr) AddMemoryLocation(addr); - LeaveCriticalSection(&IMalloc32_SpyCS); - } - - TRACE("--(%p)\n",addr); - return addr; -} - -/****************************************************************************** - * IMalloc32_Realloc [VTABLE] - */ -static LPVOID WINAPI IMalloc_fnRealloc(LPMALLOC iface,LPVOID pv,DWORD cb) { - - LPVOID pNewMemory; - - TRACE("(%p,%ld)\n",pv,cb); - - if(Malloc32.pSpy) { - LPVOID pRealMemory; - BOOL fSpyed; - - EnterCriticalSection(&IMalloc32_SpyCS); - fSpyed = RemoveMemoryLocation(pv); - cb = IMallocSpy_PreRealloc(Malloc32.pSpy, pv, cb, &pRealMemory, fSpyed); - - /* check if can release the spy */ - if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) { - IMallocSpy_Release(Malloc32.pSpy); - Malloc32.SpyReleasePending = FALSE; - Malloc32.pSpy = NULL; - } - - if (0==cb) { - /* PreRealloc can force Realloc to fail */ - LeaveCriticalSection(&IMalloc32_SpyCS); - return NULL; - } - pv = pRealMemory; - } - - if (!pv) pNewMemory = HeapAlloc(GetProcessHeap(),0,cb); - else if (cb) pNewMemory = HeapReAlloc(GetProcessHeap(),0,pv,cb); - else { - HeapFree(GetProcessHeap(),0,pv); - pNewMemory = NULL; - } - - if(Malloc32.pSpy) { - pNewMemory = IMallocSpy_PostRealloc(Malloc32.pSpy, pNewMemory, TRUE); - if (pNewMemory) AddMemoryLocation(pNewMemory); - LeaveCriticalSection(&IMalloc32_SpyCS); - } - - TRACE("--(%p)\n",pNewMemory); - return pNewMemory; -} - -/****************************************************************************** - * IMalloc32_Free [VTABLE] - */ -static VOID WINAPI IMalloc_fnFree(LPMALLOC iface,LPVOID pv) { - - BOOL fSpyed = 0; - - TRACE("(%p)\n",pv); - - if(Malloc32.pSpy) { - EnterCriticalSection(&IMalloc32_SpyCS); - fSpyed = RemoveMemoryLocation(pv); - pv = IMallocSpy_PreFree(Malloc32.pSpy, pv, fSpyed); - } - - HeapFree(GetProcessHeap(),0,pv); - - if(Malloc32.pSpy) { - IMallocSpy_PostFree(Malloc32.pSpy, fSpyed); - - /* check if can release the spy */ - if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) { - IMallocSpy_Release(Malloc32.pSpy); - Malloc32.SpyReleasePending = FALSE; - Malloc32.pSpy = NULL; - } - - LeaveCriticalSection(&IMalloc32_SpyCS); - } -} - -/****************************************************************************** - * IMalloc32_GetSize [VTABLE] - * - * NOTES - * FIXME returns: - * win95: size allocated (4 byte boundarys) - * win2k: size originally requested !!! (allocated on 8 byte boundarys) - */ -static DWORD WINAPI IMalloc_fnGetSize(LPMALLOC iface,LPVOID pv) { - - DWORD cb; - BOOL fSpyed = 0; - - TRACE("(%p)\n",pv); - - if(Malloc32.pSpy) { - EnterCriticalSection(&IMalloc32_SpyCS); - pv = IMallocSpy_PreGetSize(Malloc32.pSpy, pv, fSpyed); - } - - cb = HeapSize(GetProcessHeap(),0,pv); - - if(Malloc32.pSpy) { - cb = IMallocSpy_PostGetSize(Malloc32.pSpy, cb, fSpyed); - LeaveCriticalSection(&IMalloc32_SpyCS); - } - - return cb; -} - -/****************************************************************************** - * IMalloc32_DidAlloc [VTABLE] - */ -static INT WINAPI IMalloc_fnDidAlloc(LPMALLOC iface,LPVOID pv) { - - BOOL fSpyed = 0; - int didAlloc; - - TRACE("(%p)\n",pv); - - if(Malloc32.pSpy) { - EnterCriticalSection(&IMalloc32_SpyCS); - pv = IMallocSpy_PreDidAlloc(Malloc32.pSpy, pv, fSpyed); - } - - didAlloc = -1; - - if(Malloc32.pSpy) { - didAlloc = IMallocSpy_PostDidAlloc(Malloc32.pSpy, pv, fSpyed, didAlloc); - LeaveCriticalSection(&IMalloc32_SpyCS); - } - return didAlloc; -} - -/****************************************************************************** - * IMalloc32_HeapMinimize [VTABLE] - */ -static VOID WINAPI IMalloc_fnHeapMinimize(LPMALLOC iface) { - TRACE("()\n"); - - if(Malloc32.pSpy) { - EnterCriticalSection(&IMalloc32_SpyCS); - IMallocSpy_PreHeapMinimize(Malloc32.pSpy); - } - - if(Malloc32.pSpy) { - IMallocSpy_PostHeapMinimize(Malloc32.pSpy); - LeaveCriticalSection(&IMalloc32_SpyCS); - } -} - -static IMallocVtbl VT_IMalloc32 = -{ - IMalloc_fnQueryInterface, - IMalloc_fnAddRefRelease, - IMalloc_fnAddRefRelease, - IMalloc_fnAlloc, - IMalloc_fnRealloc, - IMalloc_fnFree, - IMalloc_fnGetSize, - IMalloc_fnDidAlloc, - IMalloc_fnHeapMinimize -}; - -/****************************************************************************** - * IMallocSpy implementation - *****************************************************************************/ - -/* set the vtable later */ -static IMallocSpyVtbl VT_IMallocSpy; - -typedef struct { - IMallocSpyVtbl *lpVtbl; - DWORD ref; -} _MallocSpy; - -/* this is the static object instance */ -_MallocSpy MallocSpy = {&VT_IMallocSpy, 0}; - -/****************************************************************************** - * IMalloc32_QueryInterface [VTABLE] - */ -static HRESULT WINAPI IMallocSpy_fnQueryInterface(LPMALLOCSPY iface,REFIID refiid,LPVOID *obj) -{ - - TRACE("(%s,%p)\n",debugstr_guid(refiid),obj); - - if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMallocSpy,refiid)) { - *obj = (LPMALLOC)&MallocSpy; - return S_OK; - } - return E_NOINTERFACE; -} - -/****************************************************************************** - * IMalloc32_AddRef [VTABLE] - */ -static ULONG WINAPI IMallocSpy_fnAddRef (LPMALLOCSPY iface) -{ - - _MallocSpy *This = (_MallocSpy *)iface; - ULONG ref = InterlockedIncrement(&This->ref); - - TRACE ("(%p)->(count=%lu)\n", This, ref - 1); - - return ref; -} - -/****************************************************************************** - * IMalloc32_AddRelease [VTABLE] - * - * NOTES - * Our MallocSpy is static. If the count reaches 0 we dump the leaks - */ -static ULONG WINAPI IMallocSpy_fnRelease (LPMALLOCSPY iface) -{ - - _MallocSpy *This = (_MallocSpy *)iface; - ULONG ref = InterlockedDecrement(&This->ref); - - TRACE ("(%p)->(count=%lu)\n", This, ref + 1); - - if (!ref) { - /* our allocation list MUST be empty here */ - } - return ref; -} - -static ULONG WINAPI IMallocSpy_fnPreAlloc(LPMALLOCSPY iface, ULONG cbRequest) -{ - _MallocSpy *This = (_MallocSpy *)iface; - TRACE ("(%p)->(%lu)\n", This, cbRequest); - return cbRequest; -} -static PVOID WINAPI IMallocSpy_fnPostAlloc(LPMALLOCSPY iface, void* pActual) -{ - _MallocSpy *This = (_MallocSpy *)iface; - TRACE ("(%p)->(%p)\n", This, pActual); - return pActual; -} - -static PVOID WINAPI IMallocSpy_fnPreFree(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed) -{ - _MallocSpy *This = (_MallocSpy *)iface; - TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed); - return pRequest; -} -static void WINAPI IMallocSpy_fnPostFree(LPMALLOCSPY iface, BOOL fSpyed) -{ - _MallocSpy *This = (_MallocSpy *)iface; - TRACE ("(%p)->(%u)\n", This, fSpyed); -} - -static ULONG WINAPI IMallocSpy_fnPreRealloc(LPMALLOCSPY iface, void* pRequest, ULONG cbRequest, void** ppNewRequest, BOOL fSpyed) -{ - _MallocSpy *This = (_MallocSpy *)iface; - TRACE ("(%p)->(%p %lu %u)\n", This, pRequest, cbRequest, fSpyed); - *ppNewRequest = pRequest; - return cbRequest; -} - -static PVOID WINAPI IMallocSpy_fnPostRealloc(LPMALLOCSPY iface, void* pActual, BOOL fSpyed) -{ - _MallocSpy *This = (_MallocSpy *)iface; - TRACE ("(%p)->(%p %u)\n", This, pActual, fSpyed); - return pActual; -} - -static PVOID WINAPI IMallocSpy_fnPreGetSize(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed) -{ - _MallocSpy *This = (_MallocSpy *)iface; - TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed); - return pRequest; -} - -static ULONG WINAPI IMallocSpy_fnPostGetSize(LPMALLOCSPY iface, ULONG cbActual, BOOL fSpyed) -{ - _MallocSpy *This = (_MallocSpy *)iface; - TRACE ("(%p)->(%lu %u)\n", This, cbActual, fSpyed); - return cbActual; -} - -static PVOID WINAPI IMallocSpy_fnPreDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed) -{ - _MallocSpy *This = (_MallocSpy *)iface; - TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed); - return pRequest; -} - -static int WINAPI IMallocSpy_fnPostDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed, int fActual) -{ - _MallocSpy *This = (_MallocSpy *)iface; - TRACE ("(%p)->(%p %u %u)\n", This, pRequest, fSpyed, fActual); - return fActual; -} - -static void WINAPI IMallocSpy_fnPreHeapMinimize(LPMALLOCSPY iface) -{ - _MallocSpy *This = (_MallocSpy *)iface; - TRACE ("(%p)->()\n", This); -} - -static void WINAPI IMallocSpy_fnPostHeapMinimize(LPMALLOCSPY iface) -{ - _MallocSpy *This = (_MallocSpy *)iface; - TRACE ("(%p)->()\n", This); -} - -static void MallocSpyDumpLeaks() { - TRACE("leaks: %lu\n", Malloc32.SpyedAllocationsLeft); -} - -static IMallocSpyVtbl VT_IMallocSpy = -{ - IMallocSpy_fnQueryInterface, - IMallocSpy_fnAddRef, - IMallocSpy_fnRelease, - IMallocSpy_fnPreAlloc, - IMallocSpy_fnPostAlloc, - IMallocSpy_fnPreFree, - IMallocSpy_fnPostFree, - IMallocSpy_fnPreRealloc, - IMallocSpy_fnPostRealloc, - IMallocSpy_fnPreGetSize, - IMallocSpy_fnPostGetSize, - IMallocSpy_fnPreDidAlloc, - IMallocSpy_fnPostDidAlloc, - IMallocSpy_fnPreHeapMinimize, - IMallocSpy_fnPostHeapMinimize -}; - -/****************************************************************************** - * CoGetMalloc [OLE32.@] - * - * Retrieves the current IMalloc interface for the process. - * - * PARAMS - * dwMemContext [I] - * lpMalloc [O] Address where memory allocator object will be stored. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - */ -HRESULT WINAPI CoGetMalloc(DWORD dwMemContext, LPMALLOC *lpMalloc) -{ - *lpMalloc = (LPMALLOC)&Malloc32; - return S_OK; -} - -/*********************************************************************** - * CoTaskMemAlloc [OLE32.@] - * - * Allocates memory using the current process memory allocator. - * - * PARAMS - * size [I] Size of the memory block to allocate. - * - * RETURNS - * Success: Pointer to newly allocated memory block. - * Failure: NULL. - */ -LPVOID WINAPI CoTaskMemAlloc(ULONG size) -{ - return IMalloc_Alloc((LPMALLOC)&Malloc32,size); -} - -/*********************************************************************** - * CoTaskMemFree [OLE32.@] - * - * Frees memory allocated from the current process memory allocator. - * - * PARAMS - * ptr [I] Memory block to free. - * - * RETURNS - * Nothing. - */ -VOID WINAPI CoTaskMemFree(LPVOID ptr) -{ - IMalloc_Free((LPMALLOC)&Malloc32, ptr); -} - -/*********************************************************************** - * CoTaskMemRealloc [OLE32.@] - * - * Allocates memory using the current process memory allocator. - * - * PARAMS - * pvOld [I] Pointer to old memory block. - * size [I] Size of the new memory block. - * - * RETURNS - * Success: Pointer to newly allocated memory block. - * Failure: NULL. - */ -LPVOID WINAPI CoTaskMemRealloc(LPVOID pvOld, ULONG size) -{ - return IMalloc_Realloc((LPMALLOC)&Malloc32, pvOld, size); -} - -/*********************************************************************** - * CoRegisterMallocSpy [OLE32.@] - * - * Registers an object that receives notifications on memory allocations and - * frees. - * - * PARAMS - * pMallocSpy [I] New spy object. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - * - * NOTES - * if a mallocspy is already registered, we can't do it again since - * only the spy knows, how to free a memory block - */ -HRESULT WINAPI CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy) -{ - IMallocSpy* pSpy; - HRESULT hres = E_INVALIDARG; - - TRACE("\n"); - - /* HACK TO ACTIVATE OUT SPY */ - if (pMallocSpy == (LPVOID)-1) pMallocSpy =(IMallocSpy*)&MallocSpy; - - if(Malloc32.pSpy) return CO_E_OBJISREG; - - EnterCriticalSection(&IMalloc32_SpyCS); - - if (SUCCEEDED(IUnknown_QueryInterface(pMallocSpy, &IID_IMallocSpy, (LPVOID*)&pSpy))) { - Malloc32.pSpy = pSpy; - hres = S_OK; - } - - LeaveCriticalSection(&IMalloc32_SpyCS); - - return hres; -} - -/*********************************************************************** - * CoRevokeMallocSpy [OLE32.@] - * - * Revokes a previousl registered object that receives notifications on memory - * allocations and frees. - * - * PARAMS - * pMallocSpy [I] New spy object. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - * - * NOTES - * we can't revoke a malloc spy as long as memory blocks allocated with - * the spy are active since only the spy knows how to free them - */ -HRESULT WINAPI CoRevokeMallocSpy(void) -{ - HRESULT hres = S_OK; - TRACE("\n"); - - EnterCriticalSection(&IMalloc32_SpyCS); - - /* if it's our spy it's time to dump the leaks */ - if (Malloc32.pSpy == (IMallocSpy*)&MallocSpy) { - MallocSpyDumpLeaks(); - } - - if (Malloc32.SpyedAllocationsLeft) { - TRACE("SpyReleasePending with %lu allocations left\n", Malloc32.SpyedAllocationsLeft); - Malloc32.SpyReleasePending = TRUE; - hres = E_ACCESSDENIED; - } else { - IMallocSpy_Release(Malloc32.pSpy); - Malloc32.pSpy = NULL; - } - LeaveCriticalSection(&IMalloc32_SpyCS); - - return S_OK; -} - -/****************************************************************************** - * IsValidInterface [OLE32.@] - * - * 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 IsValidInterface(LPUNKNOWN punk) -{ - return !( - IsBadReadPtr(punk,4) || - IsBadReadPtr(punk->lpVtbl,4) || - IsBadReadPtr(punk->lpVtbl->QueryInterface,9) || - IsBadCodePtr((FARPROC)punk->lpVtbl->QueryInterface) - ); -} +/* + * basic interfaces + * + * Copyright 1997 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <ctype.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "ole2.h" +#include "winerror.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(olemalloc); + +/****************************************************************************** + * IMalloc32 implementation + * + * NOTES + * For supporting CoRegisterMallocSpy the IMalloc implementation must know if + * a given memory block was allocated with a spy active. + * + *****************************************************************************/ +/* set the vtable later */ +static IMallocVtbl VT_IMalloc32; + +typedef struct { + IMallocVtbl *lpVtbl; + DWORD dummy; /* nothing, we are static */ + IMallocSpy * pSpy; /* the spy when active */ + DWORD SpyedAllocationsLeft; /* number of spyed allocations left */ + BOOL SpyReleasePending; /* CoRevokeMallocSpy called with spyed allocations left*/ + LPVOID * SpyedBlocks; /* root of the table */ + int SpyedBlockTableLength; /* size of the table*/ +} _Malloc32; + +/* this is the static object instance */ +_Malloc32 Malloc32 = {&VT_IMalloc32, 0, NULL, 0, 0, NULL, 0}; + +/* with a spy active all calls from pre to post methods are threadsave */ +static CRITICAL_SECTION IMalloc32_SpyCS; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &IMalloc32_SpyCS, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": IMalloc32_SpyCS") } +}; +static CRITICAL_SECTION IMalloc32_SpyCS = { &critsect_debug, -1, 0, 0, 0, 0 }; + +/* resize the old table */ +static int SetSpyedBlockTableLength ( int NewLength ) +{ + LPVOID *NewSpyedBlocks; + + if (!Malloc32.SpyedBlocks) NewSpyedBlocks = LocalAlloc(LMEM_ZEROINIT, NewLength * sizeof(PVOID)); + else NewSpyedBlocks = LocalReAlloc(Malloc32.SpyedBlocks, NewLength * sizeof(PVOID), LMEM_ZEROINIT); + if (NewSpyedBlocks) { + Malloc32.SpyedBlocks = NewSpyedBlocks; + Malloc32.SpyedBlockTableLength = NewLength; + } + + return NewSpyedBlocks != NULL; +} + +/* add a location to the table */ +static int AddMemoryLocation(LPVOID * pMem) +{ + LPVOID * Current; + + /* allocate the table if not already allocated */ + if (!Malloc32.SpyedBlockTableLength) { + if (!SetSpyedBlockTableLength(0x1000)) return 0; + } + + /* find a free location */ + Current = Malloc32.SpyedBlocks; + while (*Current) { + Current++; + if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) { + /* no more space in table, grow it */ + if (!SetSpyedBlockTableLength( Malloc32.SpyedBlockTableLength + 0x1000 )) return 0; + } + }; + + /* put the location in our table */ + *Current = pMem; + Malloc32.SpyedAllocationsLeft++; + /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/ + return 1; +} + +static int RemoveMemoryLocation(LPVOID * pMem) +{ + LPVOID * Current; + + /* allocate the table if not already allocated */ + if (!Malloc32.SpyedBlockTableLength) { + if (!SetSpyedBlockTableLength(0x1000)) return 0; + } + + Current = Malloc32.SpyedBlocks; + + /* find the location */ + while (*Current != pMem) { + Current++; + if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) return 0; /* not found */ + } + + /* location found */ + Malloc32.SpyedAllocationsLeft--; + /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/ + *Current = NULL; + return 1; +} + +/****************************************************************************** + * IMalloc32_QueryInterface [VTABLE] + */ +static HRESULT WINAPI IMalloc_fnQueryInterface(LPMALLOC iface,REFIID refiid,LPVOID *obj) { + + TRACE("(%s,%p)\n",debugstr_guid(refiid),obj); + + if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMalloc,refiid)) { + *obj = (LPMALLOC)&Malloc32; + return S_OK; + } + return E_NOINTERFACE; +} + +/****************************************************************************** + * IMalloc32_AddRefRelease [VTABLE] + */ +static ULONG WINAPI IMalloc_fnAddRefRelease (LPMALLOC iface) { + return 1; +} + +/****************************************************************************** + * IMalloc32_Alloc [VTABLE] + */ +static LPVOID WINAPI IMalloc_fnAlloc(LPMALLOC iface, DWORD cb) { + + LPVOID addr; + + TRACE("(%ld)\n",cb); + + if(Malloc32.pSpy) { + DWORD preAllocResult; + + EnterCriticalSection(&IMalloc32_SpyCS); + preAllocResult = IMallocSpy_PreAlloc(Malloc32.pSpy, cb); + if ((cb != 0) && (preAllocResult == 0)) { + /* PreAlloc can force Alloc to fail, but not if cb == 0 */ + TRACE("returning null\n"); + LeaveCriticalSection(&IMalloc32_SpyCS); + return NULL; + } + } + + addr = HeapAlloc(GetProcessHeap(),0,cb); + + if(Malloc32.pSpy) { + addr = IMallocSpy_PostAlloc(Malloc32.pSpy, addr); + if (addr) AddMemoryLocation(addr); + LeaveCriticalSection(&IMalloc32_SpyCS); + } + + TRACE("--(%p)\n",addr); + return addr; +} + +/****************************************************************************** + * IMalloc32_Realloc [VTABLE] + */ +static LPVOID WINAPI IMalloc_fnRealloc(LPMALLOC iface,LPVOID pv,DWORD cb) { + + LPVOID pNewMemory; + + TRACE("(%p,%ld)\n",pv,cb); + + if(Malloc32.pSpy) { + LPVOID pRealMemory; + BOOL fSpyed; + + EnterCriticalSection(&IMalloc32_SpyCS); + fSpyed = RemoveMemoryLocation(pv); + cb = IMallocSpy_PreRealloc(Malloc32.pSpy, pv, cb, &pRealMemory, fSpyed); + + /* check if can release the spy */ + if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) { + IMallocSpy_Release(Malloc32.pSpy); + Malloc32.SpyReleasePending = FALSE; + Malloc32.pSpy = NULL; + } + + if (0==cb) { + /* PreRealloc can force Realloc to fail */ + LeaveCriticalSection(&IMalloc32_SpyCS); + return NULL; + } + pv = pRealMemory; + } + + if (!pv) pNewMemory = HeapAlloc(GetProcessHeap(),0,cb); + else if (cb) pNewMemory = HeapReAlloc(GetProcessHeap(),0,pv,cb); + else { + HeapFree(GetProcessHeap(),0,pv); + pNewMemory = NULL; + } + + if(Malloc32.pSpy) { + pNewMemory = IMallocSpy_PostRealloc(Malloc32.pSpy, pNewMemory, TRUE); + if (pNewMemory) AddMemoryLocation(pNewMemory); + LeaveCriticalSection(&IMalloc32_SpyCS); + } + + TRACE("--(%p)\n",pNewMemory); + return pNewMemory; +} + +/****************************************************************************** + * IMalloc32_Free [VTABLE] + */ +static VOID WINAPI IMalloc_fnFree(LPMALLOC iface,LPVOID pv) { + + BOOL fSpyed = 0; + + TRACE("(%p)\n",pv); + + if(Malloc32.pSpy) { + EnterCriticalSection(&IMalloc32_SpyCS); + fSpyed = RemoveMemoryLocation(pv); + pv = IMallocSpy_PreFree(Malloc32.pSpy, pv, fSpyed); + } + + HeapFree(GetProcessHeap(),0,pv); + + if(Malloc32.pSpy) { + IMallocSpy_PostFree(Malloc32.pSpy, fSpyed); + + /* check if can release the spy */ + if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) { + IMallocSpy_Release(Malloc32.pSpy); + Malloc32.SpyReleasePending = FALSE; + Malloc32.pSpy = NULL; + } + + LeaveCriticalSection(&IMalloc32_SpyCS); + } +} + +/****************************************************************************** + * IMalloc32_GetSize [VTABLE] + * + * NOTES + * FIXME returns: + * win95: size allocated (4 byte boundarys) + * win2k: size originally requested !!! (allocated on 8 byte boundarys) + */ +static DWORD WINAPI IMalloc_fnGetSize(LPMALLOC iface,LPVOID pv) { + + DWORD cb; + BOOL fSpyed = 0; + + TRACE("(%p)\n",pv); + + if(Malloc32.pSpy) { + EnterCriticalSection(&IMalloc32_SpyCS); + pv = IMallocSpy_PreGetSize(Malloc32.pSpy, pv, fSpyed); + } + + cb = HeapSize(GetProcessHeap(),0,pv); + + if(Malloc32.pSpy) { + cb = IMallocSpy_PostGetSize(Malloc32.pSpy, cb, fSpyed); + LeaveCriticalSection(&IMalloc32_SpyCS); + } + + return cb; +} + +/****************************************************************************** + * IMalloc32_DidAlloc [VTABLE] + */ +static INT WINAPI IMalloc_fnDidAlloc(LPMALLOC iface,LPVOID pv) { + + BOOL fSpyed = 0; + int didAlloc; + + TRACE("(%p)\n",pv); + + if(Malloc32.pSpy) { + EnterCriticalSection(&IMalloc32_SpyCS); + pv = IMallocSpy_PreDidAlloc(Malloc32.pSpy, pv, fSpyed); + } + + didAlloc = -1; + + if(Malloc32.pSpy) { + didAlloc = IMallocSpy_PostDidAlloc(Malloc32.pSpy, pv, fSpyed, didAlloc); + LeaveCriticalSection(&IMalloc32_SpyCS); + } + return didAlloc; +} + +/****************************************************************************** + * IMalloc32_HeapMinimize [VTABLE] + */ +static VOID WINAPI IMalloc_fnHeapMinimize(LPMALLOC iface) { + TRACE("()\n"); + + if(Malloc32.pSpy) { + EnterCriticalSection(&IMalloc32_SpyCS); + IMallocSpy_PreHeapMinimize(Malloc32.pSpy); + } + + if(Malloc32.pSpy) { + IMallocSpy_PostHeapMinimize(Malloc32.pSpy); + LeaveCriticalSection(&IMalloc32_SpyCS); + } +} + +static IMallocVtbl VT_IMalloc32 = +{ + IMalloc_fnQueryInterface, + IMalloc_fnAddRefRelease, + IMalloc_fnAddRefRelease, + IMalloc_fnAlloc, + IMalloc_fnRealloc, + IMalloc_fnFree, + IMalloc_fnGetSize, + IMalloc_fnDidAlloc, + IMalloc_fnHeapMinimize +}; + +/****************************************************************************** + * IMallocSpy implementation + *****************************************************************************/ + +/* set the vtable later */ +static IMallocSpyVtbl VT_IMallocSpy; + +typedef struct { + IMallocSpyVtbl *lpVtbl; + DWORD ref; +} _MallocSpy; + +/* this is the static object instance */ +_MallocSpy MallocSpy = {&VT_IMallocSpy, 0}; + +/****************************************************************************** + * IMalloc32_QueryInterface [VTABLE] + */ +static HRESULT WINAPI IMallocSpy_fnQueryInterface(LPMALLOCSPY iface,REFIID refiid,LPVOID *obj) +{ + + TRACE("(%s,%p)\n",debugstr_guid(refiid),obj); + + if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMallocSpy,refiid)) { + *obj = (LPMALLOC)&MallocSpy; + return S_OK; + } + return E_NOINTERFACE; +} + +/****************************************************************************** + * IMalloc32_AddRef [VTABLE] + */ +static ULONG WINAPI IMallocSpy_fnAddRef (LPMALLOCSPY iface) +{ + + _MallocSpy *This = (_MallocSpy *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE ("(%p)->(count=%lu)\n", This, ref - 1); + + return ref; +} + +/****************************************************************************** + * IMalloc32_AddRelease [VTABLE] + * + * NOTES + * Our MallocSpy is static. If the count reaches 0 we dump the leaks + */ +static ULONG WINAPI IMallocSpy_fnRelease (LPMALLOCSPY iface) +{ + + _MallocSpy *This = (_MallocSpy *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE ("(%p)->(count=%lu)\n", This, ref + 1); + + if (!ref) { + /* our allocation list MUST be empty here */ + } + return ref; +} + +static ULONG WINAPI IMallocSpy_fnPreAlloc(LPMALLOCSPY iface, ULONG cbRequest) +{ + _MallocSpy *This = (_MallocSpy *)iface; + TRACE ("(%p)->(%lu)\n", This, cbRequest); + return cbRequest; +} +static PVOID WINAPI IMallocSpy_fnPostAlloc(LPMALLOCSPY iface, void* pActual) +{ + _MallocSpy *This = (_MallocSpy *)iface; + TRACE ("(%p)->(%p)\n", This, pActual); + return pActual; +} + +static PVOID WINAPI IMallocSpy_fnPreFree(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed) +{ + _MallocSpy *This = (_MallocSpy *)iface; + TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed); + return pRequest; +} +static void WINAPI IMallocSpy_fnPostFree(LPMALLOCSPY iface, BOOL fSpyed) +{ + _MallocSpy *This = (_MallocSpy *)iface; + TRACE ("(%p)->(%u)\n", This, fSpyed); +} + +static ULONG WINAPI IMallocSpy_fnPreRealloc(LPMALLOCSPY iface, void* pRequest, ULONG cbRequest, void** ppNewRequest, BOOL fSpyed) +{ + _MallocSpy *This = (_MallocSpy *)iface; + TRACE ("(%p)->(%p %lu %u)\n", This, pRequest, cbRequest, fSpyed); + *ppNewRequest = pRequest; + return cbRequest; +} + +static PVOID WINAPI IMallocSpy_fnPostRealloc(LPMALLOCSPY iface, void* pActual, BOOL fSpyed) +{ + _MallocSpy *This = (_MallocSpy *)iface; + TRACE ("(%p)->(%p %u)\n", This, pActual, fSpyed); + return pActual; +} + +static PVOID WINAPI IMallocSpy_fnPreGetSize(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed) +{ + _MallocSpy *This = (_MallocSpy *)iface; + TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed); + return pRequest; +} + +static ULONG WINAPI IMallocSpy_fnPostGetSize(LPMALLOCSPY iface, ULONG cbActual, BOOL fSpyed) +{ + _MallocSpy *This = (_MallocSpy *)iface; + TRACE ("(%p)->(%lu %u)\n", This, cbActual, fSpyed); + return cbActual; +} + +static PVOID WINAPI IMallocSpy_fnPreDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed) +{ + _MallocSpy *This = (_MallocSpy *)iface; + TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed); + return pRequest; +} + +static int WINAPI IMallocSpy_fnPostDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed, int fActual) +{ + _MallocSpy *This = (_MallocSpy *)iface; + TRACE ("(%p)->(%p %u %u)\n", This, pRequest, fSpyed, fActual); + return fActual; +} + +static void WINAPI IMallocSpy_fnPreHeapMinimize(LPMALLOCSPY iface) +{ + _MallocSpy *This = (_MallocSpy *)iface; + TRACE ("(%p)->()\n", This); +} + +static void WINAPI IMallocSpy_fnPostHeapMinimize(LPMALLOCSPY iface) +{ + _MallocSpy *This = (_MallocSpy *)iface; + TRACE ("(%p)->()\n", This); +} + +static void MallocSpyDumpLeaks() { + TRACE("leaks: %lu\n", Malloc32.SpyedAllocationsLeft); +} + +static IMallocSpyVtbl VT_IMallocSpy = +{ + IMallocSpy_fnQueryInterface, + IMallocSpy_fnAddRef, + IMallocSpy_fnRelease, + IMallocSpy_fnPreAlloc, + IMallocSpy_fnPostAlloc, + IMallocSpy_fnPreFree, + IMallocSpy_fnPostFree, + IMallocSpy_fnPreRealloc, + IMallocSpy_fnPostRealloc, + IMallocSpy_fnPreGetSize, + IMallocSpy_fnPostGetSize, + IMallocSpy_fnPreDidAlloc, + IMallocSpy_fnPostDidAlloc, + IMallocSpy_fnPreHeapMinimize, + IMallocSpy_fnPostHeapMinimize +}; + +/****************************************************************************** + * CoGetMalloc [OLE32.@] + * + * Retrieves the current IMalloc interface for the process. + * + * PARAMS + * dwMemContext [I] + * lpMalloc [O] Address where memory allocator object will be stored. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + */ +HRESULT WINAPI CoGetMalloc(DWORD dwMemContext, LPMALLOC *lpMalloc) +{ + *lpMalloc = (LPMALLOC)&Malloc32; + return S_OK; +} + +/*********************************************************************** + * CoTaskMemAlloc [OLE32.@] + * + * Allocates memory using the current process memory allocator. + * + * PARAMS + * size [I] Size of the memory block to allocate. + * + * RETURNS + * Success: Pointer to newly allocated memory block. + * Failure: NULL. + */ +LPVOID WINAPI CoTaskMemAlloc(ULONG size) +{ + return IMalloc_Alloc((LPMALLOC)&Malloc32,size); +} + +/*********************************************************************** + * CoTaskMemFree [OLE32.@] + * + * Frees memory allocated from the current process memory allocator. + * + * PARAMS + * ptr [I] Memory block to free. + * + * RETURNS + * Nothing. + */ +VOID WINAPI CoTaskMemFree(LPVOID ptr) +{ + IMalloc_Free((LPMALLOC)&Malloc32, ptr); +} + +/*********************************************************************** + * CoTaskMemRealloc [OLE32.@] + * + * Allocates memory using the current process memory allocator. + * + * PARAMS + * pvOld [I] Pointer to old memory block. + * size [I] Size of the new memory block. + * + * RETURNS + * Success: Pointer to newly allocated memory block. + * Failure: NULL. + */ +LPVOID WINAPI CoTaskMemRealloc(LPVOID pvOld, ULONG size) +{ + return IMalloc_Realloc((LPMALLOC)&Malloc32, pvOld, size); +} + +/*********************************************************************** + * CoRegisterMallocSpy [OLE32.@] + * + * Registers an object that receives notifications on memory allocations and + * frees. + * + * PARAMS + * pMallocSpy [I] New spy object. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * NOTES + * if a mallocspy is already registered, we can't do it again since + * only the spy knows, how to free a memory block + */ +HRESULT WINAPI CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy) +{ + IMallocSpy* pSpy; + HRESULT hres = E_INVALIDARG; + + TRACE("\n"); + + /* HACK TO ACTIVATE OUT SPY */ + if (pMallocSpy == (LPVOID)-1) pMallocSpy =(IMallocSpy*)&MallocSpy; + + if(Malloc32.pSpy) return CO_E_OBJISREG; + + EnterCriticalSection(&IMalloc32_SpyCS); + + if (SUCCEEDED(IUnknown_QueryInterface(pMallocSpy, &IID_IMallocSpy, (LPVOID*)&pSpy))) { + Malloc32.pSpy = pSpy; + hres = S_OK; + } + + LeaveCriticalSection(&IMalloc32_SpyCS); + + return hres; +} + +/*********************************************************************** + * CoRevokeMallocSpy [OLE32.@] + * + * Revokes a previousl registered object that receives notifications on memory + * allocations and frees. + * + * PARAMS + * pMallocSpy [I] New spy object. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * NOTES + * we can't revoke a malloc spy as long as memory blocks allocated with + * the spy are active since only the spy knows how to free them + */ +HRESULT WINAPI CoRevokeMallocSpy(void) +{ + HRESULT hres = S_OK; + TRACE("\n"); + + EnterCriticalSection(&IMalloc32_SpyCS); + + /* if it's our spy it's time to dump the leaks */ + if (Malloc32.pSpy == (IMallocSpy*)&MallocSpy) { + MallocSpyDumpLeaks(); + } + + if (Malloc32.SpyedAllocationsLeft) { + TRACE("SpyReleasePending with %lu allocations left\n", Malloc32.SpyedAllocationsLeft); + Malloc32.SpyReleasePending = TRUE; + hres = E_ACCESSDENIED; + } else { + IMallocSpy_Release(Malloc32.pSpy); + Malloc32.pSpy = NULL; + } + LeaveCriticalSection(&IMalloc32_SpyCS); + + return S_OK; +} + +/****************************************************************************** + * IsValidInterface [OLE32.@] + * + * 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 IsValidInterface(LPUNKNOWN punk) +{ + return !( + IsBadReadPtr(punk,4) || + IsBadReadPtr(punk->lpVtbl,4) || + IsBadReadPtr(punk->lpVtbl->QueryInterface,9) || + IsBadCodePtr((FARPROC)punk->lpVtbl->QueryInterface) + ); +} diff --git a/reactos/lib/ole32/ifs.h b/reactos/lib/ole32/ifs.h index 72a5c527219..43476594af0 100644 --- a/reactos/lib/ole32/ifs.h +++ b/reactos/lib/ole32/ifs.h @@ -1,150 +1,150 @@ -/* - * Copyright 1997 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_OLE_IFS_H -#define __WINE_OLE_IFS_H - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "objbase.h" - -typedef CHAR OLECHAR16; -typedef LPSTR LPOLESTR16; -typedef LPCSTR LPCOLESTR16; - -/*********************************************************************** - * IMalloc16 interface - */ - -#undef INTERFACE -#define INTERFACE IMalloc16 -DECLARE_INTERFACE_(IMalloc16,IUnknown) -{ - /*** IUnknown methods ***/ - STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; - STDMETHOD_(ULONG,AddRef)(THIS) PURE; - STDMETHOD_(ULONG,Release)(THIS) PURE; - /*** IMalloc16 methods ***/ - STDMETHOD_(LPVOID,Alloc)(THIS_ DWORD cb) PURE; - STDMETHOD_(LPVOID,Realloc)(THIS_ LPVOID pv, DWORD cb) PURE; - STDMETHOD_(void,Free)(THIS_ LPVOID pv) PURE; - STDMETHOD_(DWORD,GetSize)(THIS_ LPVOID pv) PURE; - STDMETHOD_(INT16,DidAlloc)(THIS_ LPVOID pv) PURE; - STDMETHOD_(LPVOID,HeapMinimize)(THIS) PURE; -}; -#undef INTERFACE - -typedef struct IMalloc16 *LPMALLOC16; - -/**********************************************************************/ - -extern LPMALLOC16 IMalloc16_Constructor(void); - -/**********************************************************************/ - -#define INTERFACE ILockBytes16 -DECLARE_INTERFACE_(ILockBytes16,IUnknown) -{ - /*** IUnknown methods ***/ - STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; - STDMETHOD_(ULONG,AddRef)(THIS) PURE; - STDMETHOD_(ULONG,Release)(THIS) PURE; - /*** ILockBytes16 methods ***/ - STDMETHOD(ReadAt)(THIS_ ULARGE_INTEGER ulOffset, void *pv, ULONG cb, ULONG *pcbRead) PURE; - STDMETHOD(WriteAt)(THIS_ ULARGE_INTEGER ulOffset, const void *pv, ULONG cb, ULONG *pcbWritten) PURE; - STDMETHOD(Flush)(THIS) PURE; - STDMETHOD(SetSize)(THIS_ ULARGE_INTEGER cb) PURE; - STDMETHOD(LockRegion)(THIS_ ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) PURE; - STDMETHOD(UnlockRegion)(THIS_ ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) PURE; - STDMETHOD(Stat)(THIS_ STATSTG *pstatstg, DWORD grfStatFlag) PURE; -}; -#undef INTERFACE - -/**********************************************************************/ - -typedef struct tagSTATSTG16 -{ - LPOLESTR16 pwcsName; - DWORD type; - ULARGE_INTEGER cbSize; - FILETIME mtime; - FILETIME ctime; - FILETIME atime; - DWORD grfMode; - DWORD grfLocksSupported; - CLSID clsid; - DWORD grfStateBits; - DWORD reserved; -} STATSTG16; - -#define INTERFACE IStream16 -DECLARE_INTERFACE_(IStream16,ISequentialStream) -{ - /*** IUnknown methods ***/ - STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; - STDMETHOD_(ULONG,AddRef)(THIS) PURE; - STDMETHOD_(ULONG,Release)(THIS) PURE; - /*** ISequentialStream methods ***/ - STDMETHOD_(HRESULT,Read)(THIS_ void* pv, ULONG cb, ULONG* pcbRead) PURE; - STDMETHOD_(HRESULT,Write)(THIS_ const void* pv, ULONG cb, ULONG* pcbWritten) PURE; - /*** IStream16 methods ***/ - STDMETHOD(Seek)(THIS_ LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) PURE; - STDMETHOD(SetSize)(THIS_ ULARGE_INTEGER libNewSize) PURE; - STDMETHOD(CopyTo)(THIS_ IStream16* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) PURE; - STDMETHOD(Commit)(THIS_ DWORD grfCommitFlags) PURE; - STDMETHOD(Revert)(THIS) PURE; - STDMETHOD(LockRegion)(THIS_ ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) PURE; - STDMETHOD(UnlockRegion)(THIS_ ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) PURE; - STDMETHOD(Stat)(THIS_ STATSTG* pstatstg, DWORD grfStatFlag) PURE; - STDMETHOD(Clone)(THIS_ IStream16** ppstm) PURE; -}; -#undef INTERFACE - -/**********************************************************************/ - -typedef OLECHAR16 **SNB16; - -#define INTERFACE IStorage16 -DECLARE_INTERFACE_(IStorage16,IUnknown) -{ - /*** IUnknown methods ***/ - STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; - STDMETHOD_(ULONG,AddRef)(THIS) PURE; - STDMETHOD_(ULONG,Release)(THIS) PURE; - /*** IStorage16 methods ***/ - STDMETHOD_(HRESULT,CreateStream)(THIS_ LPCOLESTR16 pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream16** ppstm) PURE; - STDMETHOD_(HRESULT,OpenStream)(THIS_ LPCOLESTR16 pwcsName, void* reserved1, DWORD grfMode, DWORD reserved2, IStream16** ppstm) PURE; - STDMETHOD_(HRESULT,CreateStorage)(THIS_ LPCOLESTR16 pwcsName, DWORD grfMode, DWORD dwStgFmt, DWORD reserved2, IStorage16** ppstg) PURE; - STDMETHOD_(HRESULT,OpenStorage)(THIS_ LPCOLESTR16 pwcsName, IStorage16* pstgPriority, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16** ppstg) PURE; - STDMETHOD_(HRESULT,CopyTo)(THIS_ DWORD ciidExclude, const IID* rgiidExclude, SNB16 snbExclude, IStorage16* pstgDest) PURE; - STDMETHOD_(HRESULT,MoveElementTo)(THIS_ LPCOLESTR16 pwcsName, IStorage16* pstgDest, LPCOLESTR16 pwcsNewName, DWORD grfFlags) PURE; - STDMETHOD_(HRESULT,Commit)(THIS_ DWORD grfCommitFlags) PURE; - STDMETHOD_(HRESULT,Revert)(THIS) PURE; - STDMETHOD_(HRESULT,EnumElements)(THIS_ DWORD reserved1, void* reserved2, DWORD reserved3, IEnumSTATSTG** ppenum) PURE; - STDMETHOD_(HRESULT,DestroyElement)(THIS_ LPCOLESTR16 pwcsName) PURE; - STDMETHOD_(HRESULT,RenameElement)(THIS_ LPCOLESTR16 pwcsOldName, LPCOLESTR16 pwcsNewName) PURE; - STDMETHOD_(HRESULT,SetElementTimes)(THIS_ LPCOLESTR16 pwcsName, const FILETIME* pctime, const FILETIME* patime, const FILETIME* pmtime) PURE; - STDMETHOD_(HRESULT,SetClass)(THIS_ REFCLSID clsid) PURE; - STDMETHOD_(HRESULT,SetStateBits)(THIS_ DWORD grfStateBits, DWORD grfMask) PURE; - STDMETHOD_(HRESULT,Stat)(THIS_ STATSTG* pstatstg, DWORD grfStatFlag) PURE; -}; -#undef INTERFACE - -#endif /* __WINE_OLE_IFS_H */ +/* + * Copyright 1997 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_OLE_IFS_H +#define __WINE_OLE_IFS_H + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + +typedef CHAR OLECHAR16; +typedef LPSTR LPOLESTR16; +typedef LPCSTR LPCOLESTR16; + +/*********************************************************************** + * IMalloc16 interface + */ + +#undef INTERFACE +#define INTERFACE IMalloc16 +DECLARE_INTERFACE_(IMalloc16,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IMalloc16 methods ***/ + STDMETHOD_(LPVOID,Alloc)(THIS_ DWORD cb) PURE; + STDMETHOD_(LPVOID,Realloc)(THIS_ LPVOID pv, DWORD cb) PURE; + STDMETHOD_(void,Free)(THIS_ LPVOID pv) PURE; + STDMETHOD_(DWORD,GetSize)(THIS_ LPVOID pv) PURE; + STDMETHOD_(INT16,DidAlloc)(THIS_ LPVOID pv) PURE; + STDMETHOD_(LPVOID,HeapMinimize)(THIS) PURE; +}; +#undef INTERFACE + +typedef struct IMalloc16 *LPMALLOC16; + +/**********************************************************************/ + +extern LPMALLOC16 IMalloc16_Constructor(void); + +/**********************************************************************/ + +#define INTERFACE ILockBytes16 +DECLARE_INTERFACE_(ILockBytes16,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** ILockBytes16 methods ***/ + STDMETHOD(ReadAt)(THIS_ ULARGE_INTEGER ulOffset, void *pv, ULONG cb, ULONG *pcbRead) PURE; + STDMETHOD(WriteAt)(THIS_ ULARGE_INTEGER ulOffset, const void *pv, ULONG cb, ULONG *pcbWritten) PURE; + STDMETHOD(Flush)(THIS) PURE; + STDMETHOD(SetSize)(THIS_ ULARGE_INTEGER cb) PURE; + STDMETHOD(LockRegion)(THIS_ ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) PURE; + STDMETHOD(UnlockRegion)(THIS_ ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) PURE; + STDMETHOD(Stat)(THIS_ STATSTG *pstatstg, DWORD grfStatFlag) PURE; +}; +#undef INTERFACE + +/**********************************************************************/ + +typedef struct tagSTATSTG16 +{ + LPOLESTR16 pwcsName; + DWORD type; + ULARGE_INTEGER cbSize; + FILETIME mtime; + FILETIME ctime; + FILETIME atime; + DWORD grfMode; + DWORD grfLocksSupported; + CLSID clsid; + DWORD grfStateBits; + DWORD reserved; +} STATSTG16; + +#define INTERFACE IStream16 +DECLARE_INTERFACE_(IStream16,ISequentialStream) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** ISequentialStream methods ***/ + STDMETHOD_(HRESULT,Read)(THIS_ void* pv, ULONG cb, ULONG* pcbRead) PURE; + STDMETHOD_(HRESULT,Write)(THIS_ const void* pv, ULONG cb, ULONG* pcbWritten) PURE; + /*** IStream16 methods ***/ + STDMETHOD(Seek)(THIS_ LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) PURE; + STDMETHOD(SetSize)(THIS_ ULARGE_INTEGER libNewSize) PURE; + STDMETHOD(CopyTo)(THIS_ IStream16* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) PURE; + STDMETHOD(Commit)(THIS_ DWORD grfCommitFlags) PURE; + STDMETHOD(Revert)(THIS) PURE; + STDMETHOD(LockRegion)(THIS_ ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) PURE; + STDMETHOD(UnlockRegion)(THIS_ ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) PURE; + STDMETHOD(Stat)(THIS_ STATSTG* pstatstg, DWORD grfStatFlag) PURE; + STDMETHOD(Clone)(THIS_ IStream16** ppstm) PURE; +}; +#undef INTERFACE + +/**********************************************************************/ + +typedef OLECHAR16 **SNB16; + +#define INTERFACE IStorage16 +DECLARE_INTERFACE_(IStorage16,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IStorage16 methods ***/ + STDMETHOD_(HRESULT,CreateStream)(THIS_ LPCOLESTR16 pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream16** ppstm) PURE; + STDMETHOD_(HRESULT,OpenStream)(THIS_ LPCOLESTR16 pwcsName, void* reserved1, DWORD grfMode, DWORD reserved2, IStream16** ppstm) PURE; + STDMETHOD_(HRESULT,CreateStorage)(THIS_ LPCOLESTR16 pwcsName, DWORD grfMode, DWORD dwStgFmt, DWORD reserved2, IStorage16** ppstg) PURE; + STDMETHOD_(HRESULT,OpenStorage)(THIS_ LPCOLESTR16 pwcsName, IStorage16* pstgPriority, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16** ppstg) PURE; + STDMETHOD_(HRESULT,CopyTo)(THIS_ DWORD ciidExclude, const IID* rgiidExclude, SNB16 snbExclude, IStorage16* pstgDest) PURE; + STDMETHOD_(HRESULT,MoveElementTo)(THIS_ LPCOLESTR16 pwcsName, IStorage16* pstgDest, LPCOLESTR16 pwcsNewName, DWORD grfFlags) PURE; + STDMETHOD_(HRESULT,Commit)(THIS_ DWORD grfCommitFlags) PURE; + STDMETHOD_(HRESULT,Revert)(THIS) PURE; + STDMETHOD_(HRESULT,EnumElements)(THIS_ DWORD reserved1, void* reserved2, DWORD reserved3, IEnumSTATSTG** ppenum) PURE; + STDMETHOD_(HRESULT,DestroyElement)(THIS_ LPCOLESTR16 pwcsName) PURE; + STDMETHOD_(HRESULT,RenameElement)(THIS_ LPCOLESTR16 pwcsOldName, LPCOLESTR16 pwcsNewName) PURE; + STDMETHOD_(HRESULT,SetElementTimes)(THIS_ LPCOLESTR16 pwcsName, const FILETIME* pctime, const FILETIME* patime, const FILETIME* pmtime) PURE; + STDMETHOD_(HRESULT,SetClass)(THIS_ REFCLSID clsid) PURE; + STDMETHOD_(HRESULT,SetStateBits)(THIS_ DWORD grfStateBits, DWORD grfMask) PURE; + STDMETHOD_(HRESULT,Stat)(THIS_ STATSTG* pstatstg, DWORD grfStatFlag) PURE; +}; +#undef INTERFACE + +#endif /* __WINE_OLE_IFS_H */ diff --git a/reactos/lib/ole32/itemmoniker.c b/reactos/lib/ole32/itemmoniker.c index 8358da78ba5..a387619d31d 100644 --- a/reactos/lib/ole32/itemmoniker.c +++ b/reactos/lib/ole32/itemmoniker.c @@ -1,1093 +1,1093 @@ -/*************************************************************************************** - * ItemMonikers implementation - * - * Copyright 1999 Noomen Hamza - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - ***************************************************************************************/ - -#include <assert.h> -#include <stdarg.h> -#include <string.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "winerror.h" -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "winnls.h" -#include "wine/debug.h" -#include "ole2.h" -#include "wine/unicode.h" -#include "moniker.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -const CLSID CLSID_ItemMoniker = { - 0x304, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46} -}; - -/* ItemMoniker data structure */ -typedef struct ItemMonikerImpl{ - - IMonikerVtbl* lpvtbl1; /* VTable relative to the IMoniker interface.*/ - - /* The ROT (RunningObjectTable implementation) uses the IROTData interface to test whether - * two monikers are equal. That's whay IROTData interface is implemented by monikers. - */ - IROTDataVtbl* lpvtbl2; /* VTable relative to the IROTData interface.*/ - - ULONG ref; /* reference counter for this object */ - - LPOLESTR itemName; /* item name identified by this ItemMoniker */ - - LPOLESTR itemDelimiter; /* Delimiter string */ - - IUnknown *pMarshal; /* custom marshaler */ -} ItemMonikerImpl; - -/********************************************************************************/ -/* ItemMoniker prototype functions : */ - -/* IUnknown prototype functions */ -static HRESULT WINAPI ItemMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject); -static ULONG WINAPI ItemMonikerImpl_AddRef(IMoniker* iface); -static ULONG WINAPI ItemMonikerImpl_Release(IMoniker* iface); - -/* IPersist prototype functions */ -static HRESULT WINAPI ItemMonikerImpl_GetClassID(IMoniker* iface, CLSID *pClassID); - -/* IPersistStream prototype functions */ -static HRESULT WINAPI ItemMonikerImpl_IsDirty(IMoniker* iface); -static HRESULT WINAPI ItemMonikerImpl_Load(IMoniker* iface, IStream* pStm); -static HRESULT WINAPI ItemMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty); -static HRESULT WINAPI ItemMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize); - -/* IMoniker prototype functions */ -static HRESULT WINAPI ItemMonikerImpl_BindToObject(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult); -static HRESULT WINAPI ItemMonikerImpl_BindToStorage(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult); -static HRESULT WINAPI ItemMonikerImpl_Reduce(IMoniker* iface,IBindCtx* pbc, DWORD dwReduceHowFar,IMoniker** ppmkToLeft, IMoniker** ppmkReduced); -static HRESULT WINAPI ItemMonikerImpl_ComposeWith(IMoniker* iface,IMoniker* pmkRight,BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite); -static HRESULT WINAPI ItemMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker); -static HRESULT WINAPI ItemMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker); -static HRESULT WINAPI ItemMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash); -static HRESULT WINAPI ItemMonikerImpl_IsRunning(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning); -static HRESULT WINAPI ItemMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, FILETIME* pItemTime); -static HRESULT WINAPI ItemMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk); -static HRESULT WINAPI ItemMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther, IMoniker** ppmkPrefix); -static HRESULT WINAPI ItemMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath); -static HRESULT WINAPI ItemMonikerImpl_GetDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName); -static HRESULT WINAPI ItemMonikerImpl_ParseDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut); -static HRESULT WINAPI ItemMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys); - -/* Local function used by ItemMoniker implementation */ -HRESULT WINAPI ItemMonikerImpl_Construct(ItemMonikerImpl* iface, LPCOLESTR lpszDelim,LPCOLESTR lpszPathName); -HRESULT WINAPI ItemMonikerImpl_Destroy(ItemMonikerImpl* iface); - -/********************************************************************************/ -/* IROTData prototype functions */ - -/* IUnknown prototype functions */ -static HRESULT WINAPI ItemMonikerROTDataImpl_QueryInterface(IROTData* iface,REFIID riid,VOID** ppvObject); -static ULONG WINAPI ItemMonikerROTDataImpl_AddRef(IROTData* iface); -static ULONG WINAPI ItemMonikerROTDataImpl_Release(IROTData* iface); - -/* IROTData prototype function */ -static HRESULT WINAPI ItemMonikerROTDataImpl_GetComparisonData(IROTData* iface,BYTE* pbData,ULONG cbMax,ULONG* pcbData); - -/********************************************************************************/ -/* Virtual function table for the ItemMonikerImpl class which include IPersist,*/ -/* IPersistStream and IMoniker functions. */ -static IMonikerVtbl VT_ItemMonikerImpl = - { - ItemMonikerImpl_QueryInterface, - ItemMonikerImpl_AddRef, - ItemMonikerImpl_Release, - ItemMonikerImpl_GetClassID, - ItemMonikerImpl_IsDirty, - ItemMonikerImpl_Load, - ItemMonikerImpl_Save, - ItemMonikerImpl_GetSizeMax, - ItemMonikerImpl_BindToObject, - ItemMonikerImpl_BindToStorage, - ItemMonikerImpl_Reduce, - ItemMonikerImpl_ComposeWith, - ItemMonikerImpl_Enum, - ItemMonikerImpl_IsEqual, - ItemMonikerImpl_Hash, - ItemMonikerImpl_IsRunning, - ItemMonikerImpl_GetTimeOfLastChange, - ItemMonikerImpl_Inverse, - ItemMonikerImpl_CommonPrefixWith, - ItemMonikerImpl_RelativePathTo, - ItemMonikerImpl_GetDisplayName, - ItemMonikerImpl_ParseDisplayName, - ItemMonikerImpl_IsSystemMoniker -}; - -/********************************************************************************/ -/* Virtual function table for the IROTData class. */ -static IROTDataVtbl VT_ROTDataImpl = -{ - ItemMonikerROTDataImpl_QueryInterface, - ItemMonikerROTDataImpl_AddRef, - ItemMonikerROTDataImpl_Release, - ItemMonikerROTDataImpl_GetComparisonData -}; - -/******************************************************************************* - * ItemMoniker_QueryInterface - *******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject) -{ - ItemMonikerImpl *This = (ItemMonikerImpl *)iface; - - TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject); - - /* Perform a sanity check on the parameters.*/ - if ( (This==0) || (ppvObject==0) ) - return E_INVALIDARG; - - /* Initialize the return parameter */ - *ppvObject = 0; - - /* Compare the riid with the interface IDs implemented by this object.*/ - if (IsEqualIID(&IID_IUnknown, riid) || - IsEqualIID(&IID_IPersist, riid) || - IsEqualIID(&IID_IPersistStream, riid) || - IsEqualIID(&IID_IMoniker, riid) - ) - *ppvObject = iface; - - else if (IsEqualIID(&IID_IROTData, riid)) - *ppvObject = (IROTData*)&(This->lpvtbl2); - else if (IsEqualIID(&IID_IMarshal, riid)) - { - HRESULT hr = S_OK; - if (!This->pMarshal) - hr = MonikerMarshal_Create(iface, &This->pMarshal); - if (hr != S_OK) - return hr; - return IUnknown_QueryInterface(This->pMarshal, riid, ppvObject); - } - - /* Check that we obtained an interface.*/ - if ((*ppvObject)==0) - return E_NOINTERFACE; - - /* Query Interface always increases the reference count by one when it is successful */ - ItemMonikerImpl_AddRef(iface); - - return S_OK; -} - -/****************************************************************************** - * ItemMoniker_AddRef - ******************************************************************************/ -ULONG WINAPI ItemMonikerImpl_AddRef(IMoniker* iface) -{ - ItemMonikerImpl *This = (ItemMonikerImpl *)iface; - - TRACE("(%p)\n",This); - - return InterlockedIncrement(&This->ref); -} - -/****************************************************************************** - * ItemMoniker_Release - ******************************************************************************/ -ULONG WINAPI ItemMonikerImpl_Release(IMoniker* iface) -{ - ItemMonikerImpl *This = (ItemMonikerImpl *)iface; - ULONG ref; - - TRACE("(%p)\n",This); - - ref = InterlockedDecrement(&This->ref); - - /* destroy the object if there's no more reference on it */ - if (ref == 0) ItemMonikerImpl_Destroy(This); - - return ref; -} - -/****************************************************************************** - * ItemMoniker_GetClassID - ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID) -{ - TRACE("(%p,%p)\n",iface,pClassID); - - if (pClassID==NULL) - return E_POINTER; - - *pClassID = CLSID_ItemMoniker; - - return S_OK; -} - -/****************************************************************************** - * ItemMoniker_IsDirty - ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_IsDirty(IMoniker* iface) -{ - /* Note that the OLE-provided implementations of the IPersistStream::IsDirty - method in the OLE-provided moniker interfaces always return S_FALSE because - their internal state never changes. */ - - TRACE("(%p)\n",iface); - - return S_FALSE; -} - -/****************************************************************************** - * ItemMoniker_Load - ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_Load(IMoniker* iface,IStream* pStm) -{ - - ItemMonikerImpl *This = (ItemMonikerImpl *)iface; - HRESULT res; - DWORD delimiterLength,nameLength,lenW; - CHAR *itemNameA,*itemDelimiterA; - ULONG bread; - - TRACE("\n"); - - /* for more details about data read by this function see coments of ItemMonikerImpl_Save function */ - - /* read item delimiter string length + 1 */ - res=IStream_Read(pStm,&delimiterLength,sizeof(DWORD),&bread); - if (bread != sizeof(DWORD)) - return E_FAIL; - - /* read item delimiter string */ - if (!(itemDelimiterA=HeapAlloc(GetProcessHeap(),0,delimiterLength))) - return E_OUTOFMEMORY; - res=IStream_Read(pStm,itemDelimiterA,delimiterLength,&bread); - if (bread != delimiterLength) - { - HeapFree( GetProcessHeap(), 0, itemDelimiterA ); - return E_FAIL; - } - - lenW = MultiByteToWideChar( CP_ACP, 0, itemDelimiterA, -1, NULL, 0 ); - This->itemDelimiter=HeapReAlloc(GetProcessHeap(),0,This->itemDelimiter,lenW*sizeof(WCHAR)); - if (!This->itemDelimiter) - { - HeapFree( GetProcessHeap(), 0, itemDelimiterA ); - return E_OUTOFMEMORY; - } - MultiByteToWideChar( CP_ACP, 0, itemDelimiterA, -1, This->itemDelimiter, lenW ); - HeapFree( GetProcessHeap(), 0, itemDelimiterA ); - - /* read item name string length + 1*/ - res=IStream_Read(pStm,&nameLength,sizeof(DWORD),&bread); - if (bread != sizeof(DWORD)) - return E_FAIL; - - /* read item name string */ - if (!(itemNameA=HeapAlloc(GetProcessHeap(),0,nameLength))) - return E_OUTOFMEMORY; - res=IStream_Read(pStm,itemNameA,nameLength,&bread); - if (bread != nameLength) - { - HeapFree( GetProcessHeap(), 0, itemNameA ); - return E_FAIL; - } - - lenW = MultiByteToWideChar( CP_ACP, 0, itemNameA, -1, NULL, 0 ); - This->itemName=HeapReAlloc(GetProcessHeap(),0,This->itemName,lenW*sizeof(WCHAR)); - if (!This->itemName) - { - HeapFree( GetProcessHeap(), 0, itemNameA ); - return E_OUTOFMEMORY; - } - MultiByteToWideChar( CP_ACP, 0, itemNameA, -1, This->itemName, lenW ); - HeapFree( GetProcessHeap(), 0, itemNameA ); - - return res; -} - -/****************************************************************************** - * ItemMoniker_Save - ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_Save(IMoniker* iface, - IStream* pStm,/* pointer to the stream where the object is to be saved */ - BOOL fClearDirty)/* Specifies whether to clear the dirty flag */ -{ - ItemMonikerImpl *This = (ItemMonikerImpl *)iface; - HRESULT res; - CHAR *itemNameA,*itemDelimiterA; - - /* data written by this function are : 1) DWORD : size of item delimiter string ('\0' included ) */ - /* 2) String (type A): item delimiter string ('\0' included) */ - /* 3) DWORD : size of item name string ('\0' included) */ - /* 4) String (type A): item name string ('\0' included) */ - - DWORD nameLength = WideCharToMultiByte( CP_ACP, 0, This->itemName, -1, NULL, 0, NULL, NULL); - DWORD delimiterLength = WideCharToMultiByte( CP_ACP, 0, This->itemDelimiter, -1, NULL, 0, NULL, NULL); - itemNameA=HeapAlloc(GetProcessHeap(),0,nameLength); - itemDelimiterA=HeapAlloc(GetProcessHeap(),0,delimiterLength); - WideCharToMultiByte( CP_ACP, 0, This->itemName, -1, itemNameA, nameLength, NULL, NULL); - WideCharToMultiByte( CP_ACP, 0, This->itemDelimiter, -1, itemDelimiterA, delimiterLength, NULL, NULL); - - TRACE("%p, %s\n", pStm, fClearDirty ? "TRUE" : "FALSE"); - - res=IStream_Write(pStm,&delimiterLength,sizeof(DWORD),NULL); - res=IStream_Write(pStm,itemDelimiterA,delimiterLength * sizeof(CHAR),NULL); - res=IStream_Write(pStm,&nameLength,sizeof(DWORD),NULL); - res=IStream_Write(pStm,itemNameA,nameLength * sizeof(CHAR),NULL); - - return res; -} - -/****************************************************************************** - * ItemMoniker_GetSizeMax - ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_GetSizeMax(IMoniker* iface, - ULARGE_INTEGER* pcbSize)/* Pointer to size of stream needed to save object */ -{ - ItemMonikerImpl *This = (ItemMonikerImpl *)iface; - DWORD delimiterLength=lstrlenW(This->itemDelimiter)+1; - DWORD nameLength=lstrlenW(This->itemName)+1; - - TRACE("(%p,%p)\n",iface,pcbSize); - - if (!pcbSize) - return E_POINTER; - - /* for more details see ItemMonikerImpl_Save coments */ - - pcbSize->u.LowPart = sizeof(DWORD) + /* DWORD which contains delimiter length */ - delimiterLength*4 + /* item delimiter string */ - sizeof(DWORD) + /* DWORD which contains item name length */ - nameLength*4 + /* item name string */ - 18; /* strange, but true */ - pcbSize->u.HighPart=0; - - return S_OK; -} - -/****************************************************************************** - * ItemMoniker_Construct (local function) - *******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_Construct(ItemMonikerImpl* This, LPCOLESTR lpszDelim,LPCOLESTR lpszItem) -{ - - int sizeStr1=lstrlenW(lpszItem), sizeStr2; - static const OLECHAR emptystr[1]; - LPCOLESTR delim; - - TRACE("(%p,%s,%s)\n",This,debugstr_w(lpszDelim),debugstr_w(lpszItem)); - - /* Initialize the virtual fgunction table. */ - This->lpvtbl1 = &VT_ItemMonikerImpl; - This->lpvtbl2 = &VT_ROTDataImpl; - This->ref = 0; - This->pMarshal = NULL; - - This->itemName=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr1+1)); - if (!This->itemName) - return E_OUTOFMEMORY; - lstrcpyW(This->itemName,lpszItem); - - if (!lpszDelim) - FIXME("lpszDelim is NULL. Using empty string which is possibly wrong.\n"); - - delim = lpszDelim ? lpszDelim : emptystr; - - sizeStr2=lstrlenW(delim); - This->itemDelimiter=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr2+1)); - if (!This->itemDelimiter) { - HeapFree(GetProcessHeap(),0,This->itemName); - return E_OUTOFMEMORY; - } - lstrcpyW(This->itemDelimiter,delim); - return S_OK; -} - -/****************************************************************************** - * ItemMoniker_Destroy (local function) - *******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_Destroy(ItemMonikerImpl* This) -{ - TRACE("(%p)\n",This); - - if (This->pMarshal) IUnknown_Release(This->pMarshal); - HeapFree(GetProcessHeap(),0,This->itemName); - HeapFree(GetProcessHeap(),0,This->itemDelimiter); - HeapFree(GetProcessHeap(),0,This); - - return S_OK; -} - -/****************************************************************************** - * ItemMoniker_BindToObject - ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_BindToObject(IMoniker* iface, - IBindCtx* pbc, - IMoniker* pmkToLeft, - REFIID riid, - VOID** ppvResult) -{ - ItemMonikerImpl *This = (ItemMonikerImpl *)iface; - - HRESULT res; - IID refid=IID_IOleItemContainer; - IOleItemContainer *poic=0; - - TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvResult); - - if(ppvResult ==NULL) - return E_POINTER; - - if(pmkToLeft==NULL) - return E_INVALIDARG; - - *ppvResult=0; - - res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&refid,(void**)&poic); - - if (SUCCEEDED(res)){ - - res=IOleItemContainer_GetObject(poic,This->itemName,BINDSPEED_MODERATE,pbc,riid,ppvResult); - - IOleItemContainer_Release(poic); - } - - return res; -} - -/****************************************************************************** - * ItemMoniker_BindToStorage - ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_BindToStorage(IMoniker* iface, - IBindCtx* pbc, - IMoniker* pmkToLeft, - REFIID riid, - VOID** ppvResult) -{ - ItemMonikerImpl *This = (ItemMonikerImpl *)iface; - - HRESULT res; - IOleItemContainer *poic=0; - - TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvResult); - - *ppvResult=0; - - if(pmkToLeft==NULL) - return E_INVALIDARG; - - res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IOleItemContainer,(void**)&poic); - - if (SUCCEEDED(res)){ - - res=IOleItemContainer_GetObjectStorage(poic,This->itemName,pbc,riid,ppvResult); - - IOleItemContainer_Release(poic); - } - - return res; -} - -/****************************************************************************** - * ItemMoniker_Reduce - ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_Reduce(IMoniker* iface, - IBindCtx* pbc, - DWORD dwReduceHowFar, - IMoniker** ppmkToLeft, - IMoniker** ppmkReduced) -{ - TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); - - if (ppmkReduced==NULL) - return E_POINTER; - - ItemMonikerImpl_AddRef(iface); - - *ppmkReduced=iface; - - return MK_S_REDUCED_TO_SELF; -} -/****************************************************************************** - * ItemMoniker_ComposeWith - ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_ComposeWith(IMoniker* iface, - IMoniker* pmkRight, - BOOL fOnlyIfNotGeneric, - IMoniker** ppmkComposite) -{ - HRESULT res=S_OK; - DWORD mkSys,mkSys2; - IEnumMoniker* penumMk=0; - IMoniker *pmostLeftMk=0; - IMoniker* tempMkComposite=0; - - TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite); - - if ((ppmkComposite==NULL)||(pmkRight==NULL)) - return E_POINTER; - - *ppmkComposite=0; - - IMoniker_IsSystemMoniker(pmkRight,&mkSys); - - /* If pmkRight is an anti-moniker, the returned moniker is NULL */ - if(mkSys==MKSYS_ANTIMONIKER) - return res; - - else - /* if pmkRight is a composite whose leftmost component is an anti-moniker, */ - /* the returned moniker is the composite after the leftmost anti-moniker is removed. */ - - if(mkSys==MKSYS_GENERICCOMPOSITE){ - - res=IMoniker_Enum(pmkRight,TRUE,&penumMk); - - if (FAILED(res)) - return res; - - res=IEnumMoniker_Next(penumMk,1,&pmostLeftMk,NULL); - - IMoniker_IsSystemMoniker(pmostLeftMk,&mkSys2); - - if(mkSys2==MKSYS_ANTIMONIKER){ - - IMoniker_Release(pmostLeftMk); - - tempMkComposite=iface; - IMoniker_AddRef(iface); - - while(IEnumMoniker_Next(penumMk,1,&pmostLeftMk,NULL)==S_OK){ - - res=CreateGenericComposite(tempMkComposite,pmostLeftMk,ppmkComposite); - - IMoniker_Release(tempMkComposite); - IMoniker_Release(pmostLeftMk); - - tempMkComposite=*ppmkComposite; - IMoniker_AddRef(tempMkComposite); - } - return res; - } - else - return CreateGenericComposite(iface,pmkRight,ppmkComposite); - } - /* If pmkRight is not an anti-moniker, the method combines the two monikers into a generic - composite if fOnlyIfNotGeneric is FALSE; if fOnlyIfNotGeneric is TRUE, the method returns - a NULL moniker and a return value of MK_E_NEEDGENERIC */ - else - if (!fOnlyIfNotGeneric) - return CreateGenericComposite(iface,pmkRight,ppmkComposite); - - else - return MK_E_NEEDGENERIC; -} - -/****************************************************************************** - * ItemMoniker_Enum - ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker) -{ - TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker); - - if (ppenumMoniker == NULL) - return E_POINTER; - - *ppenumMoniker = NULL; - - return S_OK; -} - -/****************************************************************************** - * ItemMoniker_IsEqual - ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker) -{ - - CLSID clsid; - LPOLESTR dispName1,dispName2; - IBindCtx* bind; - HRESULT res = S_FALSE; - - TRACE("(%p,%p)\n",iface,pmkOtherMoniker); - - if (!pmkOtherMoniker) return S_FALSE; - - - /* check if both are ItemMoniker */ - if(FAILED (IMoniker_GetClassID(pmkOtherMoniker,&clsid))) return S_FALSE; - if(!IsEqualCLSID(&clsid,&CLSID_ItemMoniker)) return S_FALSE; - - /* check if both displaynames are the same */ - if(SUCCEEDED ((res = CreateBindCtx(0,&bind)))) { - if(SUCCEEDED (IMoniker_GetDisplayName(iface,bind,NULL,&dispName1))) { - if(SUCCEEDED (IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&dispName2))) { - if(lstrcmpW(dispName1,dispName2)==0) res = S_OK; - CoTaskMemFree(dispName2); - } - CoTaskMemFree(dispName1); - } - } - return res; -} - -/****************************************************************************** - * ItemMoniker_Hash - ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash) -{ - ItemMonikerImpl *This = (ItemMonikerImpl *)iface; - - int h = 0,i,skip,len; - int off = 0; - LPOLESTR val; - - if (pdwHash==NULL) - return E_POINTER; - - val = This->itemName; - len = lstrlenW(val); - - if (len < 16) { - for (i = len ; i > 0; i--) { - h = (h * 37) + val[off++]; - } - } else { - /* only sample some characters */ - skip = len / 8; - for (i = len ; i > 0; i -= skip, off += skip) { - h = (h * 39) + val[off]; - } - } - - *pdwHash=h; - - return S_OK; -} - -/****************************************************************************** - * ItemMoniker_IsRunning - ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_IsRunning(IMoniker* iface, - IBindCtx* pbc, - IMoniker* pmkToLeft, - IMoniker* pmkNewlyRunning) -{ - IRunningObjectTable* rot; - HRESULT res; - IOleItemContainer *poic=0; - ItemMonikerImpl *This = (ItemMonikerImpl *)iface; - - TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning); - - /* If pmkToLeft is NULL, this method returns TRUE if pmkNewlyRunning is non-NULL and is equal to this */ - /* moniker. Otherwise, the method checks the ROT to see whether this moniker is running. */ - if (pmkToLeft==NULL) - if ((pmkNewlyRunning!=NULL)&&(IMoniker_IsEqual(pmkNewlyRunning,iface)==S_OK)) - return S_OK; - else { - if (pbc==NULL) - return E_POINTER; - - res=IBindCtx_GetRunningObjectTable(pbc,&rot); - - if (FAILED(res)) - return res; - - res = IRunningObjectTable_IsRunning(rot,iface); - - IRunningObjectTable_Release(rot); - } - else{ - - /* If pmkToLeft is non-NULL, the method calls IMoniker::BindToObject on the pmkToLeft parameter, */ - /* requesting an IOleItemContainer interface pointer. The method then calls IOleItemContainer::IsRunning,*/ - /* passing the string contained within this moniker. */ - - res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IOleItemContainer,(void**)&poic); - - if (SUCCEEDED(res)){ - - res=IOleItemContainer_IsRunning(poic,This->itemName); - - IOleItemContainer_Release(poic); - } - } - - return res; -} - -/****************************************************************************** - * ItemMoniker_GetTimeOfLastChange - ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_GetTimeOfLastChange(IMoniker* iface, - IBindCtx* pbc, - IMoniker* pmkToLeft, - FILETIME* pItemTime) -{ - IRunningObjectTable* rot; - HRESULT res; - IMoniker *compositeMk; - - TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pItemTime); - - if (pItemTime==NULL) - return E_INVALIDARG; - - /* If pmkToLeft is NULL, this method returns MK_E_NOTBINDABLE */ - if (pmkToLeft==NULL) - - return MK_E_NOTBINDABLE; - else { - - /* Otherwise, the method creates a composite of pmkToLeft and this moniker and uses the ROT to access */ - /* the time of last change. If the object is not in the ROT, the method calls */ - /* IMoniker::GetTimeOfLastChange on the pmkToLeft parameter. */ - - res=CreateGenericComposite(pmkToLeft,iface,&compositeMk); - - res=IBindCtx_GetRunningObjectTable(pbc,&rot); - - if (IRunningObjectTable_GetTimeOfLastChange(rot,compositeMk,pItemTime)!=S_OK) - - res=IMoniker_GetTimeOfLastChange(pmkToLeft,pbc,NULL,pItemTime); - - IMoniker_Release(compositeMk); - } - - return res; -} - -/****************************************************************************** - * ItemMoniker_Inverse - ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk) -{ - TRACE("(%p,%p)\n",iface,ppmk); - - if (ppmk==NULL) - return E_POINTER; - - return CreateAntiMoniker(ppmk); -} - -/****************************************************************************** - * ItemMoniker_CommonPrefixWith - ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix) -{ - DWORD mkSys; - - TRACE("(%p,%p)\n", pmkOther, ppmkPrefix); - - IMoniker_IsSystemMoniker(pmkOther,&mkSys); - /* If the other moniker is an item moniker that is equal to this moniker, this method sets *ppmkPrefix */ - /* to this moniker and returns MK_S_US */ - - if((mkSys==MKSYS_ITEMMONIKER) && (IMoniker_IsEqual(iface,pmkOther)==S_OK) ){ - - *ppmkPrefix=iface; - - IMoniker_AddRef(iface); - - return MK_S_US; - } - else - /* otherwise, the method calls the MonikerCommonPrefixWith function. This function correctly handles */ - /* the case where the other moniker is a generic composite. */ - return MonikerCommonPrefixWith(iface,pmkOther,ppmkPrefix); -} - -/****************************************************************************** - * ItemMoniker_RelativePathTo - ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath) -{ - TRACE("(%p,%p,%p)\n",iface,pmOther,ppmkRelPath); - - if (ppmkRelPath==NULL) - return E_POINTER; - - *ppmkRelPath=0; - - return MK_E_NOTBINDABLE; -} - -/****************************************************************************** - * ItemMoniker_GetDisplayName - ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_GetDisplayName(IMoniker* iface, - IBindCtx* pbc, - IMoniker* pmkToLeft, - LPOLESTR *ppszDisplayName) -{ - ItemMonikerImpl *This = (ItemMonikerImpl *)iface; - - TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName); - - if (ppszDisplayName==NULL) - return E_POINTER; - - if (pmkToLeft!=NULL){ - return E_INVALIDARG; - } - - *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR)*(lstrlenW(This->itemDelimiter)+lstrlenW(This->itemName)+1)); - - if (*ppszDisplayName==NULL) - return E_OUTOFMEMORY; - - lstrcpyW(*ppszDisplayName,This->itemDelimiter); - lstrcatW(*ppszDisplayName,This->itemName); - - TRACE("-- %s\n", debugstr_w(*ppszDisplayName)); - - return S_OK; -} - -/****************************************************************************** - * ItemMoniker_ParseDisplayName - ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_ParseDisplayName(IMoniker* iface, - IBindCtx* pbc, - IMoniker* pmkToLeft, - LPOLESTR pszDisplayName, - ULONG* pchEaten, - IMoniker** ppmkOut) -{ - IOleItemContainer* poic=0; - IParseDisplayName* ppdn=0; - LPOLESTR displayName; - HRESULT res; - ItemMonikerImpl *This = (ItemMonikerImpl *)iface; - - TRACE("%s\n", debugstr_w(pszDisplayName)); - - /* If pmkToLeft is NULL, this method returns MK_E_SYNTAX */ - if (pmkToLeft==NULL) - - return MK_E_SYNTAX; - - else{ - /* Otherwise, the method calls IMoniker::BindToObject on the pmkToLeft parameter, requesting an */ - /* IParseDisplayName interface pointer to the object identified by the moniker, and passes the display */ - /* name to IParseDisplayName::ParseDisplayName */ - res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IOleItemContainer,(void**)&poic); - - if (SUCCEEDED(res)){ - - res=IOleItemContainer_GetObject(poic,This->itemName,BINDSPEED_MODERATE,pbc,&IID_IParseDisplayName,(void**)&ppdn); - - res=IMoniker_GetDisplayName(iface,pbc,NULL,&displayName); - - res=IParseDisplayName_ParseDisplayName(ppdn,pbc,displayName,pchEaten,ppmkOut); - - IOleItemContainer_Release(poic); - IParseDisplayName_Release(ppdn); - } - } - return res; -} - -/****************************************************************************** - * ItemMoniker_IsSystemMoniker - ******************************************************************************/ -HRESULT WINAPI ItemMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys) -{ - TRACE("(%p,%p)\n",iface,pwdMksys); - - if (!pwdMksys) - return E_POINTER; - - (*pwdMksys)=MKSYS_ITEMMONIKER; - - return S_OK; -} - -/******************************************************************************* - * ItemMonikerIROTData_QueryInterface - *******************************************************************************/ -HRESULT WINAPI ItemMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject) -{ - - ICOM_THIS_From_IROTData(IMoniker, iface); - - TRACE("(%p,%p,%p)\n",iface,riid,ppvObject); - - return ItemMonikerImpl_QueryInterface(This, riid, ppvObject); -} - -/*********************************************************************** - * ItemMonikerIROTData_AddRef - */ -ULONG WINAPI ItemMonikerROTDataImpl_AddRef(IROTData *iface) -{ - ICOM_THIS_From_IROTData(IMoniker, iface); - - TRACE("(%p)\n",iface); - - return ItemMonikerImpl_AddRef(This); -} - -/*********************************************************************** - * ItemMonikerIROTData_Release - */ -ULONG WINAPI ItemMonikerROTDataImpl_Release(IROTData* iface) -{ - ICOM_THIS_From_IROTData(IMoniker, iface); - - TRACE("(%p)\n",iface); - - return ItemMonikerImpl_Release(This); -} - -/****************************************************************************** - * ItemMonikerIROTData_GetComparaisonData - ******************************************************************************/ -HRESULT WINAPI ItemMonikerROTDataImpl_GetComparisonData(IROTData* iface, - BYTE* pbData, - ULONG cbMax, - ULONG* pcbData) -{ - ICOM_THIS_From_IROTData(IMoniker, iface); - ItemMonikerImpl *This1 = (ItemMonikerImpl *)This; - int len = (strlenW(This1->itemName)+1); - int i; - LPWSTR pszItemName; - LPWSTR pszItemDelimiter; - - TRACE("(%p, %lu, %p)\n", pbData, cbMax, pcbData); - - *pcbData = sizeof(CLSID) + sizeof(WCHAR) + len * sizeof(WCHAR); - if (cbMax < *pcbData) - return E_OUTOFMEMORY; - - /* write CLSID */ - memcpy(pbData, &CLSID_ItemMoniker, sizeof(CLSID)); - /* write delimiter */ - pszItemDelimiter = (LPWSTR)(pbData+sizeof(CLSID)); - *pszItemDelimiter = *This1->itemDelimiter; - /* write name */ - pszItemName = pszItemDelimiter + 1; - for (i = 0; i < len; i++) - pszItemName[i] = toupperW(This1->itemName[i]); - - return S_OK; -} - -/****************************************************************************** - * CreateItemMoniker [OLE32.@] - ******************************************************************************/ -HRESULT WINAPI CreateItemMoniker(LPCOLESTR lpszDelim,LPCOLESTR lpszItem, LPMONIKER * ppmk) -{ - ItemMonikerImpl* newItemMoniker; - HRESULT hr; - - TRACE("(%s,%s,%p)\n",debugstr_w(lpszDelim),debugstr_w(lpszItem),ppmk); - - newItemMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(ItemMonikerImpl)); - - if (!newItemMoniker) - return STG_E_INSUFFICIENTMEMORY; - - hr = ItemMonikerImpl_Construct(newItemMoniker,lpszDelim,lpszItem); - - if (FAILED(hr)){ - - HeapFree(GetProcessHeap(),0,newItemMoniker); - return hr; - } - - return ItemMonikerImpl_QueryInterface((IMoniker*)newItemMoniker,&IID_IMoniker,(void**)ppmk); -} - -static HRESULT WINAPI ItemMonikerCF_QueryInterface(LPCLASSFACTORY iface, - REFIID riid, LPVOID *ppv) -{ - *ppv = NULL; - if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) - { - *ppv = iface; - IUnknown_AddRef(iface); - return S_OK; - } - return E_NOINTERFACE; -} - -static ULONG WINAPI ItemMonikerCF_AddRef(LPCLASSFACTORY iface) -{ - return 2; /* non-heap based object */ -} - -static ULONG WINAPI ItemMonikerCF_Release(LPCLASSFACTORY iface) -{ - return 1; /* non-heap based object */ -} - -static HRESULT WINAPI ItemMonikerCF_CreateInstance(LPCLASSFACTORY iface, - LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv) -{ - ItemMonikerImpl* newItemMoniker; - HRESULT hr; - static const WCHAR wszEmpty[] = { 0 }; - - TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv); - - *ppv = NULL; - - if (pUnk) - return CLASS_E_NOAGGREGATION; - - newItemMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(ItemMonikerImpl)); - if (!newItemMoniker) - return E_OUTOFMEMORY; - - hr = ItemMonikerImpl_Construct(newItemMoniker, wszEmpty, wszEmpty); - - if (SUCCEEDED(hr)) - hr = ItemMonikerImpl_QueryInterface((IMoniker*)newItemMoniker, riid, ppv); - if (FAILED(hr)) - HeapFree(GetProcessHeap(),0,newItemMoniker); - - return hr; -} - -static HRESULT WINAPI ItemMonikerCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) -{ - FIXME("(%d), stub!\n",fLock); - return S_OK; -} - -static const IClassFactoryVtbl ItemMonikerCFVtbl = -{ - ItemMonikerCF_QueryInterface, - ItemMonikerCF_AddRef, - ItemMonikerCF_Release, - ItemMonikerCF_CreateInstance, - ItemMonikerCF_LockServer -}; -static const IClassFactoryVtbl *ItemMonikerCF = &ItemMonikerCFVtbl; - -HRESULT ItemMonikerCF_Create(REFIID riid, LPVOID *ppv) -{ - return IClassFactory_QueryInterface((IClassFactory *)&ItemMonikerCF, riid, ppv); -} +/*************************************************************************************** + * ItemMonikers implementation + * + * Copyright 1999 Noomen Hamza + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + ***************************************************************************************/ + +#include <assert.h> +#include <stdarg.h> +#include <string.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "winerror.h" +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winnls.h" +#include "wine/debug.h" +#include "ole2.h" +#include "wine/unicode.h" +#include "moniker.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +const CLSID CLSID_ItemMoniker = { + 0x304, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46} +}; + +/* ItemMoniker data structure */ +typedef struct ItemMonikerImpl{ + + IMonikerVtbl* lpvtbl1; /* VTable relative to the IMoniker interface.*/ + + /* The ROT (RunningObjectTable implementation) uses the IROTData interface to test whether + * two monikers are equal. That's whay IROTData interface is implemented by monikers. + */ + IROTDataVtbl* lpvtbl2; /* VTable relative to the IROTData interface.*/ + + ULONG ref; /* reference counter for this object */ + + LPOLESTR itemName; /* item name identified by this ItemMoniker */ + + LPOLESTR itemDelimiter; /* Delimiter string */ + + IUnknown *pMarshal; /* custom marshaler */ +} ItemMonikerImpl; + +/********************************************************************************/ +/* ItemMoniker prototype functions : */ + +/* IUnknown prototype functions */ +static HRESULT WINAPI ItemMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject); +static ULONG WINAPI ItemMonikerImpl_AddRef(IMoniker* iface); +static ULONG WINAPI ItemMonikerImpl_Release(IMoniker* iface); + +/* IPersist prototype functions */ +static HRESULT WINAPI ItemMonikerImpl_GetClassID(IMoniker* iface, CLSID *pClassID); + +/* IPersistStream prototype functions */ +static HRESULT WINAPI ItemMonikerImpl_IsDirty(IMoniker* iface); +static HRESULT WINAPI ItemMonikerImpl_Load(IMoniker* iface, IStream* pStm); +static HRESULT WINAPI ItemMonikerImpl_Save(IMoniker* iface, IStream* pStm, BOOL fClearDirty); +static HRESULT WINAPI ItemMonikerImpl_GetSizeMax(IMoniker* iface, ULARGE_INTEGER* pcbSize); + +/* IMoniker prototype functions */ +static HRESULT WINAPI ItemMonikerImpl_BindToObject(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult); +static HRESULT WINAPI ItemMonikerImpl_BindToStorage(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, REFIID riid, VOID** ppvResult); +static HRESULT WINAPI ItemMonikerImpl_Reduce(IMoniker* iface,IBindCtx* pbc, DWORD dwReduceHowFar,IMoniker** ppmkToLeft, IMoniker** ppmkReduced); +static HRESULT WINAPI ItemMonikerImpl_ComposeWith(IMoniker* iface,IMoniker* pmkRight,BOOL fOnlyIfNotGeneric, IMoniker** ppmkComposite); +static HRESULT WINAPI ItemMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker); +static HRESULT WINAPI ItemMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker); +static HRESULT WINAPI ItemMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash); +static HRESULT WINAPI ItemMonikerImpl_IsRunning(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, IMoniker* pmkNewlyRunning); +static HRESULT WINAPI ItemMonikerImpl_GetTimeOfLastChange(IMoniker* iface, IBindCtx* pbc, IMoniker* pmkToLeft, FILETIME* pItemTime); +static HRESULT WINAPI ItemMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk); +static HRESULT WINAPI ItemMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther, IMoniker** ppmkPrefix); +static HRESULT WINAPI ItemMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath); +static HRESULT WINAPI ItemMonikerImpl_GetDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR *ppszDisplayName); +static HRESULT WINAPI ItemMonikerImpl_ParseDisplayName(IMoniker* iface,IBindCtx* pbc, IMoniker* pmkToLeft, LPOLESTR pszDisplayName, ULONG* pchEaten, IMoniker** ppmkOut); +static HRESULT WINAPI ItemMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys); + +/* Local function used by ItemMoniker implementation */ +HRESULT WINAPI ItemMonikerImpl_Construct(ItemMonikerImpl* iface, LPCOLESTR lpszDelim,LPCOLESTR lpszPathName); +HRESULT WINAPI ItemMonikerImpl_Destroy(ItemMonikerImpl* iface); + +/********************************************************************************/ +/* IROTData prototype functions */ + +/* IUnknown prototype functions */ +static HRESULT WINAPI ItemMonikerROTDataImpl_QueryInterface(IROTData* iface,REFIID riid,VOID** ppvObject); +static ULONG WINAPI ItemMonikerROTDataImpl_AddRef(IROTData* iface); +static ULONG WINAPI ItemMonikerROTDataImpl_Release(IROTData* iface); + +/* IROTData prototype function */ +static HRESULT WINAPI ItemMonikerROTDataImpl_GetComparisonData(IROTData* iface,BYTE* pbData,ULONG cbMax,ULONG* pcbData); + +/********************************************************************************/ +/* Virtual function table for the ItemMonikerImpl class which include IPersist,*/ +/* IPersistStream and IMoniker functions. */ +static IMonikerVtbl VT_ItemMonikerImpl = + { + ItemMonikerImpl_QueryInterface, + ItemMonikerImpl_AddRef, + ItemMonikerImpl_Release, + ItemMonikerImpl_GetClassID, + ItemMonikerImpl_IsDirty, + ItemMonikerImpl_Load, + ItemMonikerImpl_Save, + ItemMonikerImpl_GetSizeMax, + ItemMonikerImpl_BindToObject, + ItemMonikerImpl_BindToStorage, + ItemMonikerImpl_Reduce, + ItemMonikerImpl_ComposeWith, + ItemMonikerImpl_Enum, + ItemMonikerImpl_IsEqual, + ItemMonikerImpl_Hash, + ItemMonikerImpl_IsRunning, + ItemMonikerImpl_GetTimeOfLastChange, + ItemMonikerImpl_Inverse, + ItemMonikerImpl_CommonPrefixWith, + ItemMonikerImpl_RelativePathTo, + ItemMonikerImpl_GetDisplayName, + ItemMonikerImpl_ParseDisplayName, + ItemMonikerImpl_IsSystemMoniker +}; + +/********************************************************************************/ +/* Virtual function table for the IROTData class. */ +static IROTDataVtbl VT_ROTDataImpl = +{ + ItemMonikerROTDataImpl_QueryInterface, + ItemMonikerROTDataImpl_AddRef, + ItemMonikerROTDataImpl_Release, + ItemMonikerROTDataImpl_GetComparisonData +}; + +/******************************************************************************* + * ItemMoniker_QueryInterface + *******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject) +{ + ItemMonikerImpl *This = (ItemMonikerImpl *)iface; + + TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppvObject); + + /* Perform a sanity check on the parameters.*/ + if ( (This==0) || (ppvObject==0) ) + return E_INVALIDARG; + + /* Initialize the return parameter */ + *ppvObject = 0; + + /* Compare the riid with the interface IDs implemented by this object.*/ + if (IsEqualIID(&IID_IUnknown, riid) || + IsEqualIID(&IID_IPersist, riid) || + IsEqualIID(&IID_IPersistStream, riid) || + IsEqualIID(&IID_IMoniker, riid) + ) + *ppvObject = iface; + + else if (IsEqualIID(&IID_IROTData, riid)) + *ppvObject = (IROTData*)&(This->lpvtbl2); + else if (IsEqualIID(&IID_IMarshal, riid)) + { + HRESULT hr = S_OK; + if (!This->pMarshal) + hr = MonikerMarshal_Create(iface, &This->pMarshal); + if (hr != S_OK) + return hr; + return IUnknown_QueryInterface(This->pMarshal, riid, ppvObject); + } + + /* Check that we obtained an interface.*/ + if ((*ppvObject)==0) + return E_NOINTERFACE; + + /* Query Interface always increases the reference count by one when it is successful */ + ItemMonikerImpl_AddRef(iface); + + return S_OK; +} + +/****************************************************************************** + * ItemMoniker_AddRef + ******************************************************************************/ +ULONG WINAPI ItemMonikerImpl_AddRef(IMoniker* iface) +{ + ItemMonikerImpl *This = (ItemMonikerImpl *)iface; + + TRACE("(%p)\n",This); + + return InterlockedIncrement(&This->ref); +} + +/****************************************************************************** + * ItemMoniker_Release + ******************************************************************************/ +ULONG WINAPI ItemMonikerImpl_Release(IMoniker* iface) +{ + ItemMonikerImpl *This = (ItemMonikerImpl *)iface; + ULONG ref; + + TRACE("(%p)\n",This); + + ref = InterlockedDecrement(&This->ref); + + /* destroy the object if there's no more reference on it */ + if (ref == 0) ItemMonikerImpl_Destroy(This); + + return ref; +} + +/****************************************************************************** + * ItemMoniker_GetClassID + ******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_GetClassID(IMoniker* iface,CLSID *pClassID) +{ + TRACE("(%p,%p)\n",iface,pClassID); + + if (pClassID==NULL) + return E_POINTER; + + *pClassID = CLSID_ItemMoniker; + + return S_OK; +} + +/****************************************************************************** + * ItemMoniker_IsDirty + ******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_IsDirty(IMoniker* iface) +{ + /* Note that the OLE-provided implementations of the IPersistStream::IsDirty + method in the OLE-provided moniker interfaces always return S_FALSE because + their internal state never changes. */ + + TRACE("(%p)\n",iface); + + return S_FALSE; +} + +/****************************************************************************** + * ItemMoniker_Load + ******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_Load(IMoniker* iface,IStream* pStm) +{ + + ItemMonikerImpl *This = (ItemMonikerImpl *)iface; + HRESULT res; + DWORD delimiterLength,nameLength,lenW; + CHAR *itemNameA,*itemDelimiterA; + ULONG bread; + + TRACE("\n"); + + /* for more details about data read by this function see coments of ItemMonikerImpl_Save function */ + + /* read item delimiter string length + 1 */ + res=IStream_Read(pStm,&delimiterLength,sizeof(DWORD),&bread); + if (bread != sizeof(DWORD)) + return E_FAIL; + + /* read item delimiter string */ + if (!(itemDelimiterA=HeapAlloc(GetProcessHeap(),0,delimiterLength))) + return E_OUTOFMEMORY; + res=IStream_Read(pStm,itemDelimiterA,delimiterLength,&bread); + if (bread != delimiterLength) + { + HeapFree( GetProcessHeap(), 0, itemDelimiterA ); + return E_FAIL; + } + + lenW = MultiByteToWideChar( CP_ACP, 0, itemDelimiterA, -1, NULL, 0 ); + This->itemDelimiter=HeapReAlloc(GetProcessHeap(),0,This->itemDelimiter,lenW*sizeof(WCHAR)); + if (!This->itemDelimiter) + { + HeapFree( GetProcessHeap(), 0, itemDelimiterA ); + return E_OUTOFMEMORY; + } + MultiByteToWideChar( CP_ACP, 0, itemDelimiterA, -1, This->itemDelimiter, lenW ); + HeapFree( GetProcessHeap(), 0, itemDelimiterA ); + + /* read item name string length + 1*/ + res=IStream_Read(pStm,&nameLength,sizeof(DWORD),&bread); + if (bread != sizeof(DWORD)) + return E_FAIL; + + /* read item name string */ + if (!(itemNameA=HeapAlloc(GetProcessHeap(),0,nameLength))) + return E_OUTOFMEMORY; + res=IStream_Read(pStm,itemNameA,nameLength,&bread); + if (bread != nameLength) + { + HeapFree( GetProcessHeap(), 0, itemNameA ); + return E_FAIL; + } + + lenW = MultiByteToWideChar( CP_ACP, 0, itemNameA, -1, NULL, 0 ); + This->itemName=HeapReAlloc(GetProcessHeap(),0,This->itemName,lenW*sizeof(WCHAR)); + if (!This->itemName) + { + HeapFree( GetProcessHeap(), 0, itemNameA ); + return E_OUTOFMEMORY; + } + MultiByteToWideChar( CP_ACP, 0, itemNameA, -1, This->itemName, lenW ); + HeapFree( GetProcessHeap(), 0, itemNameA ); + + return res; +} + +/****************************************************************************** + * ItemMoniker_Save + ******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_Save(IMoniker* iface, + IStream* pStm,/* pointer to the stream where the object is to be saved */ + BOOL fClearDirty)/* Specifies whether to clear the dirty flag */ +{ + ItemMonikerImpl *This = (ItemMonikerImpl *)iface; + HRESULT res; + CHAR *itemNameA,*itemDelimiterA; + + /* data written by this function are : 1) DWORD : size of item delimiter string ('\0' included ) */ + /* 2) String (type A): item delimiter string ('\0' included) */ + /* 3) DWORD : size of item name string ('\0' included) */ + /* 4) String (type A): item name string ('\0' included) */ + + DWORD nameLength = WideCharToMultiByte( CP_ACP, 0, This->itemName, -1, NULL, 0, NULL, NULL); + DWORD delimiterLength = WideCharToMultiByte( CP_ACP, 0, This->itemDelimiter, -1, NULL, 0, NULL, NULL); + itemNameA=HeapAlloc(GetProcessHeap(),0,nameLength); + itemDelimiterA=HeapAlloc(GetProcessHeap(),0,delimiterLength); + WideCharToMultiByte( CP_ACP, 0, This->itemName, -1, itemNameA, nameLength, NULL, NULL); + WideCharToMultiByte( CP_ACP, 0, This->itemDelimiter, -1, itemDelimiterA, delimiterLength, NULL, NULL); + + TRACE("%p, %s\n", pStm, fClearDirty ? "TRUE" : "FALSE"); + + res=IStream_Write(pStm,&delimiterLength,sizeof(DWORD),NULL); + res=IStream_Write(pStm,itemDelimiterA,delimiterLength * sizeof(CHAR),NULL); + res=IStream_Write(pStm,&nameLength,sizeof(DWORD),NULL); + res=IStream_Write(pStm,itemNameA,nameLength * sizeof(CHAR),NULL); + + return res; +} + +/****************************************************************************** + * ItemMoniker_GetSizeMax + ******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_GetSizeMax(IMoniker* iface, + ULARGE_INTEGER* pcbSize)/* Pointer to size of stream needed to save object */ +{ + ItemMonikerImpl *This = (ItemMonikerImpl *)iface; + DWORD delimiterLength=lstrlenW(This->itemDelimiter)+1; + DWORD nameLength=lstrlenW(This->itemName)+1; + + TRACE("(%p,%p)\n",iface,pcbSize); + + if (!pcbSize) + return E_POINTER; + + /* for more details see ItemMonikerImpl_Save coments */ + + pcbSize->u.LowPart = sizeof(DWORD) + /* DWORD which contains delimiter length */ + delimiterLength*4 + /* item delimiter string */ + sizeof(DWORD) + /* DWORD which contains item name length */ + nameLength*4 + /* item name string */ + 18; /* strange, but true */ + pcbSize->u.HighPart=0; + + return S_OK; +} + +/****************************************************************************** + * ItemMoniker_Construct (local function) + *******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_Construct(ItemMonikerImpl* This, LPCOLESTR lpszDelim,LPCOLESTR lpszItem) +{ + + int sizeStr1=lstrlenW(lpszItem), sizeStr2; + static const OLECHAR emptystr[1]; + LPCOLESTR delim; + + TRACE("(%p,%s,%s)\n",This,debugstr_w(lpszDelim),debugstr_w(lpszItem)); + + /* Initialize the virtual fgunction table. */ + This->lpvtbl1 = &VT_ItemMonikerImpl; + This->lpvtbl2 = &VT_ROTDataImpl; + This->ref = 0; + This->pMarshal = NULL; + + This->itemName=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr1+1)); + if (!This->itemName) + return E_OUTOFMEMORY; + lstrcpyW(This->itemName,lpszItem); + + if (!lpszDelim) + FIXME("lpszDelim is NULL. Using empty string which is possibly wrong.\n"); + + delim = lpszDelim ? lpszDelim : emptystr; + + sizeStr2=lstrlenW(delim); + This->itemDelimiter=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr2+1)); + if (!This->itemDelimiter) { + HeapFree(GetProcessHeap(),0,This->itemName); + return E_OUTOFMEMORY; + } + lstrcpyW(This->itemDelimiter,delim); + return S_OK; +} + +/****************************************************************************** + * ItemMoniker_Destroy (local function) + *******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_Destroy(ItemMonikerImpl* This) +{ + TRACE("(%p)\n",This); + + if (This->pMarshal) IUnknown_Release(This->pMarshal); + HeapFree(GetProcessHeap(),0,This->itemName); + HeapFree(GetProcessHeap(),0,This->itemDelimiter); + HeapFree(GetProcessHeap(),0,This); + + return S_OK; +} + +/****************************************************************************** + * ItemMoniker_BindToObject + ******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_BindToObject(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + REFIID riid, + VOID** ppvResult) +{ + ItemMonikerImpl *This = (ItemMonikerImpl *)iface; + + HRESULT res; + IID refid=IID_IOleItemContainer; + IOleItemContainer *poic=0; + + TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvResult); + + if(ppvResult ==NULL) + return E_POINTER; + + if(pmkToLeft==NULL) + return E_INVALIDARG; + + *ppvResult=0; + + res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&refid,(void**)&poic); + + if (SUCCEEDED(res)){ + + res=IOleItemContainer_GetObject(poic,This->itemName,BINDSPEED_MODERATE,pbc,riid,ppvResult); + + IOleItemContainer_Release(poic); + } + + return res; +} + +/****************************************************************************** + * ItemMoniker_BindToStorage + ******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_BindToStorage(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + REFIID riid, + VOID** ppvResult) +{ + ItemMonikerImpl *This = (ItemMonikerImpl *)iface; + + HRESULT res; + IOleItemContainer *poic=0; + + TRACE("(%p,%p,%p,%s,%p)\n",iface,pbc,pmkToLeft,debugstr_guid(riid),ppvResult); + + *ppvResult=0; + + if(pmkToLeft==NULL) + return E_INVALIDARG; + + res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IOleItemContainer,(void**)&poic); + + if (SUCCEEDED(res)){ + + res=IOleItemContainer_GetObjectStorage(poic,This->itemName,pbc,riid,ppvResult); + + IOleItemContainer_Release(poic); + } + + return res; +} + +/****************************************************************************** + * ItemMoniker_Reduce + ******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_Reduce(IMoniker* iface, + IBindCtx* pbc, + DWORD dwReduceHowFar, + IMoniker** ppmkToLeft, + IMoniker** ppmkReduced) +{ + TRACE("(%p,%p,%ld,%p,%p)\n",iface,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); + + if (ppmkReduced==NULL) + return E_POINTER; + + ItemMonikerImpl_AddRef(iface); + + *ppmkReduced=iface; + + return MK_S_REDUCED_TO_SELF; +} +/****************************************************************************** + * ItemMoniker_ComposeWith + ******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_ComposeWith(IMoniker* iface, + IMoniker* pmkRight, + BOOL fOnlyIfNotGeneric, + IMoniker** ppmkComposite) +{ + HRESULT res=S_OK; + DWORD mkSys,mkSys2; + IEnumMoniker* penumMk=0; + IMoniker *pmostLeftMk=0; + IMoniker* tempMkComposite=0; + + TRACE("(%p,%p,%d,%p)\n",iface,pmkRight,fOnlyIfNotGeneric,ppmkComposite); + + if ((ppmkComposite==NULL)||(pmkRight==NULL)) + return E_POINTER; + + *ppmkComposite=0; + + IMoniker_IsSystemMoniker(pmkRight,&mkSys); + + /* If pmkRight is an anti-moniker, the returned moniker is NULL */ + if(mkSys==MKSYS_ANTIMONIKER) + return res; + + else + /* if pmkRight is a composite whose leftmost component is an anti-moniker, */ + /* the returned moniker is the composite after the leftmost anti-moniker is removed. */ + + if(mkSys==MKSYS_GENERICCOMPOSITE){ + + res=IMoniker_Enum(pmkRight,TRUE,&penumMk); + + if (FAILED(res)) + return res; + + res=IEnumMoniker_Next(penumMk,1,&pmostLeftMk,NULL); + + IMoniker_IsSystemMoniker(pmostLeftMk,&mkSys2); + + if(mkSys2==MKSYS_ANTIMONIKER){ + + IMoniker_Release(pmostLeftMk); + + tempMkComposite=iface; + IMoniker_AddRef(iface); + + while(IEnumMoniker_Next(penumMk,1,&pmostLeftMk,NULL)==S_OK){ + + res=CreateGenericComposite(tempMkComposite,pmostLeftMk,ppmkComposite); + + IMoniker_Release(tempMkComposite); + IMoniker_Release(pmostLeftMk); + + tempMkComposite=*ppmkComposite; + IMoniker_AddRef(tempMkComposite); + } + return res; + } + else + return CreateGenericComposite(iface,pmkRight,ppmkComposite); + } + /* If pmkRight is not an anti-moniker, the method combines the two monikers into a generic + composite if fOnlyIfNotGeneric is FALSE; if fOnlyIfNotGeneric is TRUE, the method returns + a NULL moniker and a return value of MK_E_NEEDGENERIC */ + else + if (!fOnlyIfNotGeneric) + return CreateGenericComposite(iface,pmkRight,ppmkComposite); + + else + return MK_E_NEEDGENERIC; +} + +/****************************************************************************** + * ItemMoniker_Enum + ******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker) +{ + TRACE("(%p,%d,%p)\n",iface,fForward,ppenumMoniker); + + if (ppenumMoniker == NULL) + return E_POINTER; + + *ppenumMoniker = NULL; + + return S_OK; +} + +/****************************************************************************** + * ItemMoniker_IsEqual + ******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker) +{ + + CLSID clsid; + LPOLESTR dispName1,dispName2; + IBindCtx* bind; + HRESULT res = S_FALSE; + + TRACE("(%p,%p)\n",iface,pmkOtherMoniker); + + if (!pmkOtherMoniker) return S_FALSE; + + + /* check if both are ItemMoniker */ + if(FAILED (IMoniker_GetClassID(pmkOtherMoniker,&clsid))) return S_FALSE; + if(!IsEqualCLSID(&clsid,&CLSID_ItemMoniker)) return S_FALSE; + + /* check if both displaynames are the same */ + if(SUCCEEDED ((res = CreateBindCtx(0,&bind)))) { + if(SUCCEEDED (IMoniker_GetDisplayName(iface,bind,NULL,&dispName1))) { + if(SUCCEEDED (IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&dispName2))) { + if(lstrcmpW(dispName1,dispName2)==0) res = S_OK; + CoTaskMemFree(dispName2); + } + CoTaskMemFree(dispName1); + } + } + return res; +} + +/****************************************************************************** + * ItemMoniker_Hash + ******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash) +{ + ItemMonikerImpl *This = (ItemMonikerImpl *)iface; + + int h = 0,i,skip,len; + int off = 0; + LPOLESTR val; + + if (pdwHash==NULL) + return E_POINTER; + + val = This->itemName; + len = lstrlenW(val); + + if (len < 16) { + for (i = len ; i > 0; i--) { + h = (h * 37) + val[off++]; + } + } else { + /* only sample some characters */ + skip = len / 8; + for (i = len ; i > 0; i -= skip, off += skip) { + h = (h * 39) + val[off]; + } + } + + *pdwHash=h; + + return S_OK; +} + +/****************************************************************************** + * ItemMoniker_IsRunning + ******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_IsRunning(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + IMoniker* pmkNewlyRunning) +{ + IRunningObjectTable* rot; + HRESULT res; + IOleItemContainer *poic=0; + ItemMonikerImpl *This = (ItemMonikerImpl *)iface; + + TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pmkNewlyRunning); + + /* If pmkToLeft is NULL, this method returns TRUE if pmkNewlyRunning is non-NULL and is equal to this */ + /* moniker. Otherwise, the method checks the ROT to see whether this moniker is running. */ + if (pmkToLeft==NULL) + if ((pmkNewlyRunning!=NULL)&&(IMoniker_IsEqual(pmkNewlyRunning,iface)==S_OK)) + return S_OK; + else { + if (pbc==NULL) + return E_POINTER; + + res=IBindCtx_GetRunningObjectTable(pbc,&rot); + + if (FAILED(res)) + return res; + + res = IRunningObjectTable_IsRunning(rot,iface); + + IRunningObjectTable_Release(rot); + } + else{ + + /* If pmkToLeft is non-NULL, the method calls IMoniker::BindToObject on the pmkToLeft parameter, */ + /* requesting an IOleItemContainer interface pointer. The method then calls IOleItemContainer::IsRunning,*/ + /* passing the string contained within this moniker. */ + + res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IOleItemContainer,(void**)&poic); + + if (SUCCEEDED(res)){ + + res=IOleItemContainer_IsRunning(poic,This->itemName); + + IOleItemContainer_Release(poic); + } + } + + return res; +} + +/****************************************************************************** + * ItemMoniker_GetTimeOfLastChange + ******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_GetTimeOfLastChange(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + FILETIME* pItemTime) +{ + IRunningObjectTable* rot; + HRESULT res; + IMoniker *compositeMk; + + TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,pItemTime); + + if (pItemTime==NULL) + return E_INVALIDARG; + + /* If pmkToLeft is NULL, this method returns MK_E_NOTBINDABLE */ + if (pmkToLeft==NULL) + + return MK_E_NOTBINDABLE; + else { + + /* Otherwise, the method creates a composite of pmkToLeft and this moniker and uses the ROT to access */ + /* the time of last change. If the object is not in the ROT, the method calls */ + /* IMoniker::GetTimeOfLastChange on the pmkToLeft parameter. */ + + res=CreateGenericComposite(pmkToLeft,iface,&compositeMk); + + res=IBindCtx_GetRunningObjectTable(pbc,&rot); + + if (IRunningObjectTable_GetTimeOfLastChange(rot,compositeMk,pItemTime)!=S_OK) + + res=IMoniker_GetTimeOfLastChange(pmkToLeft,pbc,NULL,pItemTime); + + IMoniker_Release(compositeMk); + } + + return res; +} + +/****************************************************************************** + * ItemMoniker_Inverse + ******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk) +{ + TRACE("(%p,%p)\n",iface,ppmk); + + if (ppmk==NULL) + return E_POINTER; + + return CreateAntiMoniker(ppmk); +} + +/****************************************************************************** + * ItemMoniker_CommonPrefixWith + ******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix) +{ + DWORD mkSys; + + TRACE("(%p,%p)\n", pmkOther, ppmkPrefix); + + IMoniker_IsSystemMoniker(pmkOther,&mkSys); + /* If the other moniker is an item moniker that is equal to this moniker, this method sets *ppmkPrefix */ + /* to this moniker and returns MK_S_US */ + + if((mkSys==MKSYS_ITEMMONIKER) && (IMoniker_IsEqual(iface,pmkOther)==S_OK) ){ + + *ppmkPrefix=iface; + + IMoniker_AddRef(iface); + + return MK_S_US; + } + else + /* otherwise, the method calls the MonikerCommonPrefixWith function. This function correctly handles */ + /* the case where the other moniker is a generic composite. */ + return MonikerCommonPrefixWith(iface,pmkOther,ppmkPrefix); +} + +/****************************************************************************** + * ItemMoniker_RelativePathTo + ******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath) +{ + TRACE("(%p,%p,%p)\n",iface,pmOther,ppmkRelPath); + + if (ppmkRelPath==NULL) + return E_POINTER; + + *ppmkRelPath=0; + + return MK_E_NOTBINDABLE; +} + +/****************************************************************************** + * ItemMoniker_GetDisplayName + ******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_GetDisplayName(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + LPOLESTR *ppszDisplayName) +{ + ItemMonikerImpl *This = (ItemMonikerImpl *)iface; + + TRACE("(%p,%p,%p,%p)\n",iface,pbc,pmkToLeft,ppszDisplayName); + + if (ppszDisplayName==NULL) + return E_POINTER; + + if (pmkToLeft!=NULL){ + return E_INVALIDARG; + } + + *ppszDisplayName=CoTaskMemAlloc(sizeof(WCHAR)*(lstrlenW(This->itemDelimiter)+lstrlenW(This->itemName)+1)); + + if (*ppszDisplayName==NULL) + return E_OUTOFMEMORY; + + lstrcpyW(*ppszDisplayName,This->itemDelimiter); + lstrcatW(*ppszDisplayName,This->itemName); + + TRACE("-- %s\n", debugstr_w(*ppszDisplayName)); + + return S_OK; +} + +/****************************************************************************** + * ItemMoniker_ParseDisplayName + ******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_ParseDisplayName(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + LPOLESTR pszDisplayName, + ULONG* pchEaten, + IMoniker** ppmkOut) +{ + IOleItemContainer* poic=0; + IParseDisplayName* ppdn=0; + LPOLESTR displayName; + HRESULT res; + ItemMonikerImpl *This = (ItemMonikerImpl *)iface; + + TRACE("%s\n", debugstr_w(pszDisplayName)); + + /* If pmkToLeft is NULL, this method returns MK_E_SYNTAX */ + if (pmkToLeft==NULL) + + return MK_E_SYNTAX; + + else{ + /* Otherwise, the method calls IMoniker::BindToObject on the pmkToLeft parameter, requesting an */ + /* IParseDisplayName interface pointer to the object identified by the moniker, and passes the display */ + /* name to IParseDisplayName::ParseDisplayName */ + res=IMoniker_BindToObject(pmkToLeft,pbc,NULL,&IID_IOleItemContainer,(void**)&poic); + + if (SUCCEEDED(res)){ + + res=IOleItemContainer_GetObject(poic,This->itemName,BINDSPEED_MODERATE,pbc,&IID_IParseDisplayName,(void**)&ppdn); + + res=IMoniker_GetDisplayName(iface,pbc,NULL,&displayName); + + res=IParseDisplayName_ParseDisplayName(ppdn,pbc,displayName,pchEaten,ppmkOut); + + IOleItemContainer_Release(poic); + IParseDisplayName_Release(ppdn); + } + } + return res; +} + +/****************************************************************************** + * ItemMoniker_IsSystemMoniker + ******************************************************************************/ +HRESULT WINAPI ItemMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys) +{ + TRACE("(%p,%p)\n",iface,pwdMksys); + + if (!pwdMksys) + return E_POINTER; + + (*pwdMksys)=MKSYS_ITEMMONIKER; + + return S_OK; +} + +/******************************************************************************* + * ItemMonikerIROTData_QueryInterface + *******************************************************************************/ +HRESULT WINAPI ItemMonikerROTDataImpl_QueryInterface(IROTData *iface,REFIID riid,VOID** ppvObject) +{ + + ICOM_THIS_From_IROTData(IMoniker, iface); + + TRACE("(%p,%p,%p)\n",iface,riid,ppvObject); + + return ItemMonikerImpl_QueryInterface(This, riid, ppvObject); +} + +/*********************************************************************** + * ItemMonikerIROTData_AddRef + */ +ULONG WINAPI ItemMonikerROTDataImpl_AddRef(IROTData *iface) +{ + ICOM_THIS_From_IROTData(IMoniker, iface); + + TRACE("(%p)\n",iface); + + return ItemMonikerImpl_AddRef(This); +} + +/*********************************************************************** + * ItemMonikerIROTData_Release + */ +ULONG WINAPI ItemMonikerROTDataImpl_Release(IROTData* iface) +{ + ICOM_THIS_From_IROTData(IMoniker, iface); + + TRACE("(%p)\n",iface); + + return ItemMonikerImpl_Release(This); +} + +/****************************************************************************** + * ItemMonikerIROTData_GetComparaisonData + ******************************************************************************/ +HRESULT WINAPI ItemMonikerROTDataImpl_GetComparisonData(IROTData* iface, + BYTE* pbData, + ULONG cbMax, + ULONG* pcbData) +{ + ICOM_THIS_From_IROTData(IMoniker, iface); + ItemMonikerImpl *This1 = (ItemMonikerImpl *)This; + int len = (strlenW(This1->itemName)+1); + int i; + LPWSTR pszItemName; + LPWSTR pszItemDelimiter; + + TRACE("(%p, %lu, %p)\n", pbData, cbMax, pcbData); + + *pcbData = sizeof(CLSID) + sizeof(WCHAR) + len * sizeof(WCHAR); + if (cbMax < *pcbData) + return E_OUTOFMEMORY; + + /* write CLSID */ + memcpy(pbData, &CLSID_ItemMoniker, sizeof(CLSID)); + /* write delimiter */ + pszItemDelimiter = (LPWSTR)(pbData+sizeof(CLSID)); + *pszItemDelimiter = *This1->itemDelimiter; + /* write name */ + pszItemName = pszItemDelimiter + 1; + for (i = 0; i < len; i++) + pszItemName[i] = toupperW(This1->itemName[i]); + + return S_OK; +} + +/****************************************************************************** + * CreateItemMoniker [OLE32.@] + ******************************************************************************/ +HRESULT WINAPI CreateItemMoniker(LPCOLESTR lpszDelim,LPCOLESTR lpszItem, LPMONIKER * ppmk) +{ + ItemMonikerImpl* newItemMoniker; + HRESULT hr; + + TRACE("(%s,%s,%p)\n",debugstr_w(lpszDelim),debugstr_w(lpszItem),ppmk); + + newItemMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(ItemMonikerImpl)); + + if (!newItemMoniker) + return STG_E_INSUFFICIENTMEMORY; + + hr = ItemMonikerImpl_Construct(newItemMoniker,lpszDelim,lpszItem); + + if (FAILED(hr)){ + + HeapFree(GetProcessHeap(),0,newItemMoniker); + return hr; + } + + return ItemMonikerImpl_QueryInterface((IMoniker*)newItemMoniker,&IID_IMoniker,(void**)ppmk); +} + +static HRESULT WINAPI ItemMonikerCF_QueryInterface(LPCLASSFACTORY iface, + REFIID riid, LPVOID *ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) + { + *ppv = iface; + IUnknown_AddRef(iface); + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI ItemMonikerCF_AddRef(LPCLASSFACTORY iface) +{ + return 2; /* non-heap based object */ +} + +static ULONG WINAPI ItemMonikerCF_Release(LPCLASSFACTORY iface) +{ + return 1; /* non-heap based object */ +} + +static HRESULT WINAPI ItemMonikerCF_CreateInstance(LPCLASSFACTORY iface, + LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv) +{ + ItemMonikerImpl* newItemMoniker; + HRESULT hr; + static const WCHAR wszEmpty[] = { 0 }; + + TRACE("(%p, %s, %p)\n", pUnk, debugstr_guid(riid), ppv); + + *ppv = NULL; + + if (pUnk) + return CLASS_E_NOAGGREGATION; + + newItemMoniker = HeapAlloc(GetProcessHeap(), 0, sizeof(ItemMonikerImpl)); + if (!newItemMoniker) + return E_OUTOFMEMORY; + + hr = ItemMonikerImpl_Construct(newItemMoniker, wszEmpty, wszEmpty); + + if (SUCCEEDED(hr)) + hr = ItemMonikerImpl_QueryInterface((IMoniker*)newItemMoniker, riid, ppv); + if (FAILED(hr)) + HeapFree(GetProcessHeap(),0,newItemMoniker); + + return hr; +} + +static HRESULT WINAPI ItemMonikerCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) +{ + FIXME("(%d), stub!\n",fLock); + return S_OK; +} + +static const IClassFactoryVtbl ItemMonikerCFVtbl = +{ + ItemMonikerCF_QueryInterface, + ItemMonikerCF_AddRef, + ItemMonikerCF_Release, + ItemMonikerCF_CreateInstance, + ItemMonikerCF_LockServer +}; +static const IClassFactoryVtbl *ItemMonikerCF = &ItemMonikerCFVtbl; + +HRESULT ItemMonikerCF_Create(REFIID riid, LPVOID *ppv) +{ + return IClassFactory_QueryInterface((IClassFactory *)&ItemMonikerCF, riid, ppv); +} diff --git a/reactos/lib/ole32/marshal.c b/reactos/lib/ole32/marshal.c index 12837afc7ce..92ae1179522 100644 --- a/reactos/lib/ole32/marshal.c +++ b/reactos/lib/ole32/marshal.c @@ -1,1650 +1,1650 @@ -/* - * Marshalling library - * - * Copyright 2002 Marcus Meissner - * Copyright 2004 Mike Hearn, for CodeWeavers - * Copyright 2004 Rob Shearman, for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <stdlib.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> -#include <assert.h> - -#define COBJMACROS - -#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 "wtypes.h" -#include "wine/unicode.h" - -#include "compobj_private.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -extern const CLSID CLSID_DfMarshal; - -/* number of refs given out for normal marshaling */ -#define NORMALEXTREFS 1 /* FIXME: this should be 5, but we have to wait for IRemUnknown support first */ - -/* private flag indicating that the caller does not want to notify the stub - * when the proxy disconnects or is destroyed */ -#define SORFP_NOLIFETIMEMGMT SORF_OXRES1 - -static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, REFIID riid, void **object); - -/* Marshalling just passes a unique identifier to the remote client, - * that makes it possible to find the passed interface again. - * - * So basically we need a set of values that make it unique. - * - * Note that the IUnknown_QI(ob,xiid,&ppv) always returns the SAME ppv value! - * - * A triple is used: OXID (apt id), OID (stub manager id), - * IPID (interface ptr/stub id). - * - * OXIDs identify an apartment and are network scoped - * OIDs identify a stub manager and are apartment scoped - * IPIDs identify an interface stub and are apartment scoped - */ - -inline static HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf) -{ - HRESULT hr; - CLSID clsid; - - if ((hr = CoGetPSClsid(riid, &clsid))) - return hr; - return CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, - &IID_IPSFactoryBuffer, (LPVOID*)facbuf); -} - -/* creates a new stub manager */ -HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *obj, MSHLFLAGS mshlflags) -{ - struct stub_manager *manager; - struct ifstub *ifstub; - BOOL tablemarshal; - IRpcStubBuffer *stub; - IPSFactoryBuffer *psfb; - HRESULT hr; - - hr = apartment_getoxid(apt, &stdobjref->oxid); - if (hr != S_OK) - return hr; - - hr = get_facbuf_for_iid(riid, &psfb); - if (hr != S_OK) - { - ERR("couldn't get IPSFactory buffer for interface %s\n", debugstr_guid(riid)); - return hr; - } - - hr = IPSFactoryBuffer_CreateStub(psfb, riid, obj, &stub); - IPSFactoryBuffer_Release(psfb); - if (hr != S_OK) - { - ERR("Failed to create an IRpcStubBuffer from IPSFactory for %s\n", debugstr_guid(riid)); - return hr; - } - - if (mshlflags & MSHLFLAGS_NOPING) - stdobjref->flags = SORF_NOPING; - else - stdobjref->flags = SORF_NULL; - - /* FIXME: what happens if we register an interface twice with different - * marshaling flags? */ - if ((manager = get_stub_manager_from_object(apt, obj))) - TRACE("registering new ifstub on pre-existing manager\n"); - else - { - TRACE("constructing new stub manager\n"); - - manager = new_stub_manager(apt, obj, mshlflags); - if (!manager) - { - IRpcStubBuffer_Release(stub); - return E_OUTOFMEMORY; - } - } - stdobjref->oid = manager->oid; - - tablemarshal = ((mshlflags & MSHLFLAGS_TABLESTRONG) || (mshlflags & MSHLFLAGS_TABLEWEAK)); - - ifstub = stub_manager_new_ifstub(manager, stub, obj, riid); - if (!ifstub) - { - IRpcStubBuffer_Release(stub); - stub_manager_int_release(manager); - /* FIXME: should we do another release to completely destroy the - * stub manager? */ - return E_OUTOFMEMORY; - } - - if (!tablemarshal) - { - stdobjref->cPublicRefs = NORMALEXTREFS; - stub_manager_ext_addref(manager, stdobjref->cPublicRefs); - } - else - { - stdobjref->cPublicRefs = 0; - if (mshlflags & MSHLFLAGS_TABLESTRONG) - stub_manager_ext_addref(manager, 1); - } - - /* FIXME: check return value */ - RPC_RegisterInterface(riid); - - stdobjref->ipid = ifstub->ipid; - - stub_manager_int_release(manager); - return S_OK; -} - - - -/* Client-side identity of the server object */ - -static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk); -static void proxy_manager_destroy(struct proxy_manager * This); -static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found); -static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv); - -static HRESULT WINAPI ClientIdentity_QueryInterface(IMultiQI * iface, REFIID riid, void ** ppv) -{ - HRESULT hr; - MULTI_QI mqi; - - TRACE("%s\n", debugstr_guid(riid)); - - mqi.pIID = riid; - hr = IMultiQI_QueryMultipleInterfaces(iface, 1, &mqi); - *ppv = (void *)mqi.pItf; - - return hr; -} - -static ULONG WINAPI ClientIdentity_AddRef(IMultiQI * iface) -{ - struct proxy_manager * This = (struct proxy_manager *)iface; - TRACE("%p - before %ld\n", iface, This->refs); - return InterlockedIncrement(&This->refs); -} - -static ULONG WINAPI ClientIdentity_Release(IMultiQI * iface) -{ - struct proxy_manager * This = (struct proxy_manager *)iface; - ULONG refs = InterlockedDecrement(&This->refs); - TRACE("%p - after %ld\n", iface, refs); - if (!refs) - proxy_manager_destroy(This); - return refs; -} - -static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, ULONG cMQIs, MULTI_QI *pMQIs) -{ - struct proxy_manager * This = (struct proxy_manager *)iface; - REMQIRESULT *qiresults = NULL; - ULONG nonlocal_mqis = 0; - ULONG i; - ULONG successful_mqis = 0; - IID *iids = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*iids)); - /* mapping of RemQueryInterface index to QueryMultipleInterfaces index */ - ULONG *mapping = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*mapping)); - - TRACE("cMQIs: %ld\n", cMQIs); - - /* try to get a local interface - this includes already active proxy - * interfaces and also interfaces exposed by the proxy manager */ - for (i = 0; i < cMQIs; i++) - { - TRACE("iid[%ld] = %s\n", i, debugstr_guid(pMQIs[i].pIID)); - pMQIs[i].hr = proxy_manager_query_local_interface(This, pMQIs[i].pIID, (void **)&pMQIs[i].pItf); - if (pMQIs[i].hr == S_OK) - successful_mqis++; - else - { - iids[nonlocal_mqis] = *pMQIs[i].pIID; - mapping[nonlocal_mqis] = i; - nonlocal_mqis++; - } - } - - TRACE("%ld interfaces not found locally\n", nonlocal_mqis); - - /* if we have more than one interface not found locally then we must try - * to query the remote object for it */ - if (nonlocal_mqis != 0) - { - IRemUnknown *remunk; - HRESULT hr; - IPID *ipid; - - /* get the ipid of the first entry */ - /* FIXME: should we implement ClientIdentity on the ifproxies instead - * of the proxy_manager so we use the correct ipid here? */ - ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->ipid; - - /* get IRemUnknown proxy so we can communicate with the remote object */ - hr = proxy_manager_get_remunknown(This, &remunk); - - if (hr == S_OK) - { - hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS, - nonlocal_mqis, iids, &qiresults); - if (FAILED(hr)) - ERR("IRemUnknown_RemQueryInterface failed with error 0x%08lx\n", hr); - } - - /* IRemUnknown_RemQueryInterface can return S_FALSE if only some of - * the interfaces were returned */ - if (SUCCEEDED(hr)) - { - /* try to unmarshal each object returned to us */ - for (i = 0; i < nonlocal_mqis; i++) - { - ULONG index = mapping[i]; - HRESULT hrobj = qiresults[i].hResult; - if (hrobj == S_OK) - hrobj = unmarshal_object(&qiresults[i].std, This->parent, - pMQIs[index].pIID, - (void **)&pMQIs[index].pItf); - - if (hrobj == S_OK) - successful_mqis++; - else - ERR("Failed to get pointer to interface %s\n", debugstr_guid(pMQIs[index].pIID)); - pMQIs[index].hr = hrobj; - } - } - - /* free the memory allocated by the proxy */ - CoTaskMemFree(qiresults); - } - - TRACE("%ld/%ld successfully queried\n", successful_mqis, cMQIs); - - HeapFree(GetProcessHeap(), 0, iids); - HeapFree(GetProcessHeap(), 0, mapping); - - if (successful_mqis == cMQIs) - return S_OK; /* we got all requested interfaces */ - else if (successful_mqis == 0) - return E_NOINTERFACE; /* we didn't get any interfaces */ - else - return S_FALSE; /* we got some interfaces */ -} - -static const IMultiQIVtbl ClientIdentity_Vtbl = -{ - ClientIdentity_QueryInterface, - ClientIdentity_AddRef, - ClientIdentity_Release, - ClientIdentity_QueryMultipleInterfaces -}; - -static HRESULT ifproxy_get_public_ref(struct ifproxy * This) -{ - HRESULT hr = S_OK; - - if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE)) - { - ERR("Wait failed for ifproxy %p\n", This); - return E_UNEXPECTED; - } - - if (This->refs == 0) - { - IRemUnknown *remunk = NULL; - - TRACE("getting public ref for ifproxy %p\n", This); - - hr = proxy_manager_get_remunknown(This->parent, &remunk); - if (hr == S_OK) - { - HRESULT hrref; - REMINTERFACEREF rif; - rif.ipid = This->ipid; - rif.cPublicRefs = NORMALEXTREFS; - rif.cPrivateRefs = 0; - hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref); - if (hr == S_OK && hrref == S_OK) - This->refs += NORMALEXTREFS; - else - ERR("IRemUnknown_RemAddRef returned with 0x%08lx, hrref = 0x%08lx\n", hr, hrref); - } - } - ReleaseMutex(This->parent->remoting_mutex); - - return hr; -} - -static HRESULT ifproxy_release_public_refs(struct ifproxy * This) -{ - HRESULT hr = S_OK; - - if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE)) - { - ERR("Wait failed for ifproxy %p\n", This); - return E_UNEXPECTED; - } - - if (This->refs > 0) - { - IRemUnknown *remunk = NULL; - - TRACE("releasing %ld refs\n", This->refs); - - hr = proxy_manager_get_remunknown(This->parent, &remunk); - if (hr == S_OK) - { - REMINTERFACEREF rif; - rif.ipid = This->ipid; - rif.cPublicRefs = This->refs; - rif.cPrivateRefs = 0; - hr = IRemUnknown_RemRelease(remunk, 1, &rif); - if (hr == S_OK) - This->refs = 0; - else if (hr == RPC_E_DISCONNECTED) - WARN("couldn't release references because object was " - "disconnected: oxid = %s, oid = %s\n", - wine_dbgstr_longlong(This->parent->oxid), - wine_dbgstr_longlong(This->parent->oid)); - else - ERR("IRemUnknown_RemRelease failed with error 0x%08lx\n", hr); - } - } - ReleaseMutex(This->parent->remoting_mutex); - - return hr; -} - -/* should be called inside This->parent->cs critical section */ -static void ifproxy_disconnect(struct ifproxy * This) -{ - ifproxy_release_public_refs(This); - if (This->proxy) IRpcProxyBuffer_Disconnect(This->proxy); - - IRpcChannelBuffer_Release(This->chan); - This->chan = NULL; -} - -/* should be called in This->parent->cs critical section if it is an entry in parent's list */ -static void ifproxy_destroy(struct ifproxy * This) -{ - TRACE("%p\n", This); - - /* release public references to this object so that the stub can know - * when to destroy itself */ - ifproxy_release_public_refs(This); - - list_remove(&This->entry); - - if (This->chan) - { - IRpcChannelBuffer_Release(This->chan); - This->chan = NULL; - } - - /* note: we don't call Release for This->proxy because its lifetime is - * controlled by the return value from ClientIdentity_Release, which this - * function is always called from */ - - HeapFree(GetProcessHeap(), 0, This); -} - -static HRESULT proxy_manager_construct( - APARTMENT * apt, ULONG sorflags, OXID oxid, OID oid, - struct proxy_manager ** proxy_manager) -{ - struct proxy_manager * This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); - if (!This) return E_OUTOFMEMORY; - - This->remoting_mutex = CreateMutexW(NULL, FALSE, NULL); - if (!This->remoting_mutex) - { - HeapFree(GetProcessHeap(), 0, This); - return HRESULT_FROM_WIN32(GetLastError()); - } - - This->lpVtbl = &ClientIdentity_Vtbl; - - list_init(&This->entry); - list_init(&This->interfaces); - - InitializeCriticalSection(&This->cs); - DEBUG_SET_CRITSEC_NAME(&This->cs, "proxy_manager"); - - /* the apartment the object was unmarshaled into */ - This->parent = apt; - - /* the source apartment and id of the object */ - This->oxid = oxid; - This->oid = oid; - - This->refs = 1; - - /* the DCOM draft specification states that the SORF_NOPING flag is - * proxy manager specific, not ifproxy specific, so this implies that we - * should store the STDOBJREF flags here in the proxy manager. */ - This->sorflags = sorflags; - - /* we create the IRemUnknown proxy on demand */ - This->remunk = NULL; - - EnterCriticalSection(&apt->cs); - /* FIXME: we are dependent on the ordering in here to make sure a proxy's - * IRemUnknown proxy doesn't get destroyed before the regual proxy does - * because we need the IRemUnknown proxy during the destruction of the - * regular proxy. Ideally, we should maintain a separate list for the - * IRemUnknown proxies that need late destruction */ - list_add_tail(&apt->proxies, &This->entry); - LeaveCriticalSection(&apt->cs); - - TRACE("%p created for OXID %s, OID %s\n", This, - wine_dbgstr_longlong(oxid), wine_dbgstr_longlong(oid)); - - *proxy_manager = This; - return S_OK; -} - -static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv) -{ - HRESULT hr; - struct ifproxy * ifproxy; - - TRACE("%s\n", debugstr_guid(riid)); - - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IMultiQI)) - { - *ppv = (void *)&This->lpVtbl; - IMultiQI_AddRef((IMultiQI *)&This->lpVtbl); - return S_OK; - } - - hr = proxy_manager_find_ifproxy(This, riid, &ifproxy); - if (hr == S_OK) - { - *ppv = ifproxy->iface; - IUnknown_AddRef((IUnknown *)*ppv); - return S_OK; - } - - *ppv = NULL; - return E_NOINTERFACE; -} - -static HRESULT proxy_manager_create_ifproxy( - struct proxy_manager * This, const IPID *ipid, REFIID riid, ULONG cPublicRefs, - IRpcChannelBuffer * channel, struct ifproxy ** iif_out) -{ - HRESULT hr; - IPSFactoryBuffer * psfb; - struct ifproxy * ifproxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*ifproxy)); - if (!ifproxy) return E_OUTOFMEMORY; - - list_init(&ifproxy->entry); - - ifproxy->parent = This; - ifproxy->ipid = *ipid; - ifproxy->iid = *riid; - ifproxy->refs = cPublicRefs; - ifproxy->proxy = NULL; - - assert(channel); - ifproxy->chan = channel; /* FIXME: we should take the binding strings and construct the channel in this function */ - - /* the IUnknown interface is special because it does not have a - * proxy associated with the ifproxy as we handle IUnknown ourselves */ - if (IsEqualIID(riid, &IID_IUnknown)) - { - ifproxy->iface = (void *)&This->lpVtbl; - hr = S_OK; - } - else - { - hr = get_facbuf_for_iid(riid, &psfb); - if (hr == S_OK) - { - /* important note: the outer unknown is set to the proxy manager. - * This ensures the COM identity rules are not violated, by having a - * one-to-one mapping of objects on the proxy side to objects on the - * stub side, no matter which interface you view the object through */ - hr = IPSFactoryBuffer_CreateProxy(psfb, (IUnknown *)&This->lpVtbl, riid, - &ifproxy->proxy, &ifproxy->iface); - IPSFactoryBuffer_Release(psfb); - if (hr != S_OK) - ERR("Could not create proxy for interface %s, error 0x%08lx\n", - debugstr_guid(riid), hr); - } - else - ERR("Could not get IPSFactoryBuffer for interface %s, error 0x%08lx\n", - debugstr_guid(riid), hr); - - if (hr == S_OK) - hr = IRpcProxyBuffer_Connect(ifproxy->proxy, ifproxy->chan); - } - - /* get at least one external reference to the object to keep it alive */ - if (hr == S_OK) - hr = ifproxy_get_public_ref(ifproxy); - - if (hr == S_OK) - { - EnterCriticalSection(&This->cs); - list_add_tail(&This->interfaces, &ifproxy->entry); - LeaveCriticalSection(&This->cs); - - *iif_out = ifproxy; - TRACE("ifproxy %p created for IPID %s, interface %s with %lu public refs\n", - ifproxy, debugstr_guid(ipid), debugstr_guid(riid), cPublicRefs); - } - else - ifproxy_destroy(ifproxy); - - return hr; -} - -static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found) -{ - HRESULT hr = E_NOINTERFACE; /* assume not found */ - struct list * cursor; - - EnterCriticalSection(&This->cs); - LIST_FOR_EACH(cursor, &This->interfaces) - { - struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry); - if (IsEqualIID(riid, &ifproxy->iid)) - { - *ifproxy_found = ifproxy; - hr = S_OK; - break; - } - } - LeaveCriticalSection(&This->cs); - - return hr; -} - -static void proxy_manager_disconnect(struct proxy_manager * This) -{ - struct list * cursor; - - TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid), - wine_dbgstr_longlong(This->oid)); - - EnterCriticalSection(&This->cs); - - LIST_FOR_EACH(cursor, &This->interfaces) - { - struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry); - ifproxy_disconnect(ifproxy); - } - - /* apartment is being destroyed so don't keep a pointer around to it */ - This->parent = NULL; - - LeaveCriticalSection(&This->cs); -} - -static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk) -{ - HRESULT hr = S_OK; - - /* we don't want to try and unmarshal or use IRemUnknown if we don't want - * lifetime management */ - if (This->sorflags & SORFP_NOLIFETIMEMGMT) - return S_FALSE; - - EnterCriticalSection(&This->cs); - if (This->remunk) - /* already created - return existing object */ - *remunk = This->remunk; - else if (!This->parent) - /* disconnected - we can't create IRemUnknown */ - hr = S_FALSE; - else - { - STDOBJREF stdobjref; - /* Don't want IRemUnknown lifetime management as this is IRemUnknown! - * We also don't care about whether or not the stub is still alive */ - stdobjref.flags = SORFP_NOLIFETIMEMGMT | SORF_NOPING; - stdobjref.cPublicRefs = 1; - /* oxid of destination object */ - stdobjref.oxid = This->oxid; - /* FIXME: what should be used for the oid? The DCOM draft doesn't say */ - stdobjref.oid = (OID)-1; - /* FIXME: this is a hack around not having an OXID resolver yet - - * the OXID resolver should give us the IPID of the IRemUnknown - * interface */ - stdobjref.ipid.Data1 = 0xffffffff; - stdobjref.ipid.Data2 = 0xffff; - stdobjref.ipid.Data3 = 0xffff; - assert(sizeof(stdobjref.ipid.Data4) == sizeof(stdobjref.oxid)); - memcpy(&stdobjref.ipid.Data4, &stdobjref.oxid, sizeof(OXID)); - - /* do the unmarshal */ - hr = unmarshal_object(&stdobjref, This->parent, &IID_IRemUnknown, (void**)&This->remunk); - if (hr == S_OK) - *remunk = This->remunk; - } - LeaveCriticalSection(&This->cs); - - TRACE("got IRemUnknown* pointer %p, hr = 0x%08lx\n", *remunk, hr); - - return hr; -} - -/* destroys a proxy manager, freeing the memory it used. - * Note: this function should not be called from a list iteration in the - * apartment, due to the fact that it removes itself from the apartment and - * it could add a proxy to IRemUnknown into the apartment. */ -static void proxy_manager_destroy(struct proxy_manager * This) -{ - struct list * cursor; - - TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid), - wine_dbgstr_longlong(This->oid)); - - if (This->parent) - { - EnterCriticalSection(&This->parent->cs); - - /* remove ourself from the list of proxy objects in the apartment */ - LIST_FOR_EACH(cursor, &This->parent->proxies) - { - if (cursor == &This->entry) - { - list_remove(&This->entry); - break; - } - } - - LeaveCriticalSection(&This->parent->cs); - } - - /* destroy all of the interface proxies */ - while ((cursor = list_head(&This->interfaces))) - { - struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry); - ifproxy_destroy(ifproxy); - } - - if (This->remunk) IRemUnknown_Release(This->remunk); - - DEBUG_CLEAR_CRITSEC_NAME(&This->cs); - DeleteCriticalSection(&This->cs); - - CloseHandle(This->remoting_mutex); - - HeapFree(GetProcessHeap(), 0, This); -} - -/* finds the proxy manager corresponding to a given OXID and OID that has - * been unmarshaled in the specified apartment. The caller must release the - * reference to the proxy_manager when the object is no longer used. */ -static BOOL find_proxy_manager(APARTMENT * apt, OXID oxid, OID oid, struct proxy_manager ** proxy_found) -{ - BOOL found = FALSE; - struct list * cursor; - - EnterCriticalSection(&apt->cs); - LIST_FOR_EACH(cursor, &apt->proxies) - { - struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry); - if ((oxid == proxy->oxid) && (oid == proxy->oid)) - { - *proxy_found = proxy; - ClientIdentity_AddRef((IMultiQI *)&proxy->lpVtbl); - found = TRUE; - break; - } - } - LeaveCriticalSection(&apt->cs); - return found; -} - -HRESULT apartment_disconnectproxies(struct apartment *apt) -{ - struct list * cursor; - - LIST_FOR_EACH(cursor, &apt->proxies) - { - struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry); - proxy_manager_disconnect(proxy); - } - - return S_OK; -} - -/********************** StdMarshal implementation ****************************/ -typedef struct _StdMarshalImpl -{ - const IMarshalVtbl *lpvtbl; - DWORD ref; - - IID iid; - DWORD dwDestContext; - LPVOID pvDestContext; - DWORD mshlflags; -} StdMarshalImpl; - -static HRESULT WINAPI -StdMarshalImpl_QueryInterface(LPMARSHAL iface, REFIID riid, LPVOID *ppv) -{ - *ppv = NULL; - if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IMarshal, riid)) - { - *ppv = iface; - IUnknown_AddRef(iface); - return S_OK; - } - FIXME("No interface for %s.\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI -StdMarshalImpl_AddRef(LPMARSHAL iface) -{ - StdMarshalImpl *This = (StdMarshalImpl *)iface; - return InterlockedIncrement(&This->ref); -} - -static ULONG WINAPI -StdMarshalImpl_Release(LPMARSHAL iface) -{ - StdMarshalImpl *This = (StdMarshalImpl *)iface; - ULONG ref = InterlockedDecrement(&This->ref); - - if (!ref) HeapFree(GetProcessHeap(),0,This); - return ref; -} - -static HRESULT WINAPI -StdMarshalImpl_GetUnmarshalClass( - LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, - void* pvDestContext, DWORD mshlflags, CLSID* pCid) -{ - *pCid = CLSID_DfMarshal; - return S_OK; -} - -static HRESULT WINAPI -StdMarshalImpl_GetMarshalSizeMax( - LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, - void* pvDestContext, DWORD mshlflags, DWORD* pSize) -{ - *pSize = sizeof(STDOBJREF); - return S_OK; -} - -static HRESULT WINAPI -StdMarshalImpl_MarshalInterface( - LPMARSHAL iface, IStream *pStm,REFIID riid, void* pv, DWORD dwDestContext, - void* pvDestContext, DWORD mshlflags) -{ - STDOBJREF stdobjref; - IUnknown *pUnk; - ULONG res; - HRESULT hres; - APARTMENT *apt = COM_CurrentApt(); - - TRACE("(...,%s,...)\n", debugstr_guid(riid)); - - if (!apt) - { - ERR("Apartment not initialized\n"); - return CO_E_NOTINITIALIZED; - } - - /* make sure this apartment can be reached from other threads / processes */ - RPC_StartRemoting(apt); - - hres = IUnknown_QueryInterface((LPUNKNOWN)pv, riid, (LPVOID*)&pUnk); - if (hres != S_OK) - { - ERR("object doesn't expose interface %s, failing with error 0x%08lx\n", - debugstr_guid(riid), hres); - return E_NOINTERFACE; - } - - hres = marshal_object(apt, &stdobjref, riid, pUnk, mshlflags); - - IUnknown_Release(pUnk); - - if (hres) - { - ERR("Failed to create ifstub, hres=0x%lx\n", hres); - return hres; - } - - hres = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), &res); - if (hres) return hres; - - return S_OK; -} - -/* helper for StdMarshalImpl_UnmarshalInterface - does the unmarshaling with - * no questions asked about the rules surrounding same-apartment unmarshals - * and table marshaling */ -static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, REFIID riid, void **object) -{ - struct proxy_manager *proxy_manager = NULL; - HRESULT hr = S_OK; - - assert(apt); - - TRACE("stdobjref:\n\tflags = %04lx\n\tcPublicRefs = %ld\n\toxid = %s\n\toid = %s\n\tipid = %s\n", - stdobjref->flags, stdobjref->cPublicRefs, - wine_dbgstr_longlong(stdobjref->oxid), - wine_dbgstr_longlong(stdobjref->oid), - debugstr_guid(&stdobjref->ipid)); - - /* create an a new proxy manager if one doesn't already exist for the - * object */ - if (!find_proxy_manager(apt, stdobjref->oxid, stdobjref->oid, &proxy_manager)) - { - hr = proxy_manager_construct(apt, stdobjref->flags, - stdobjref->oxid, stdobjref->oid, - &proxy_manager); - } - else - TRACE("proxy manager already created, using\n"); - - if (hr == S_OK) - { - struct ifproxy * ifproxy; - hr = proxy_manager_find_ifproxy(proxy_manager, riid, &ifproxy); - if (hr == E_NOINTERFACE) - { - IRpcChannelBuffer *chanbuf; - hr = RPC_CreateClientChannel(&stdobjref->oxid, &stdobjref->ipid, &chanbuf); - if (hr == S_OK) - hr = proxy_manager_create_ifproxy(proxy_manager, &stdobjref->ipid, - riid, stdobjref->cPublicRefs, - chanbuf, &ifproxy); - } - - if (hr == S_OK) - { - /* FIXME: push this AddRef inside proxy_manager_find_ifproxy/create_ifproxy? */ - ClientIdentity_AddRef((IMultiQI*)&proxy_manager->lpVtbl); - *object = ifproxy->iface; - } - } - - /* release our reference to the proxy manager - the client/apartment - * will hold on to the remaining reference for us */ - if (proxy_manager) ClientIdentity_Release((IMultiQI*)&proxy_manager->lpVtbl); - - return hr; -} - -static HRESULT WINAPI -StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv) -{ - struct stub_manager *stubmgr; - STDOBJREF stdobjref; - ULONG res; - HRESULT hres; - APARTMENT *apt = COM_CurrentApt(); - APARTMENT *stub_apt; - OXID oxid; - - TRACE("(...,%s,....)\n", debugstr_guid(riid)); - - /* we need an apartment to unmarshal into */ - if (!apt) - { - ERR("Apartment not initialized\n"); - return CO_E_NOTINITIALIZED; - } - - /* read STDOBJREF from wire */ - hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res); - if (hres) return hres; - - hres = apartment_getoxid(apt, &oxid); - if (hres) return hres; - - /* check if we're marshalling back to ourselves */ - if ((oxid == stdobjref.oxid) && (stubmgr = get_stub_manager(apt, stdobjref.oid))) - { - TRACE("Unmarshalling object marshalled in same apartment for iid %s, " - "returning original object %p\n", debugstr_guid(riid), stubmgr->object); - - hres = IUnknown_QueryInterface(stubmgr->object, riid, ppv); - - /* unref the ifstub. FIXME: only do this on success? */ - if (!stub_manager_is_table_marshaled(stubmgr)) - stub_manager_ext_release(stubmgr, 1); - - stub_manager_int_release(stubmgr); - return hres; - } - - /* notify stub manager about unmarshal if process-local object. - * note: if the oxid is not found then we and native will quite happily - * ignore table marshaling and normal marshaling rules regarding number of - * unmarshals, etc, but if you abuse these rules then your proxy could end - * up returning RPC_E_DISCONNECTED. */ - if ((stub_apt = apartment_findfromoxid(stdobjref.oxid, TRUE))) - { - if ((stubmgr = get_stub_manager(stub_apt, stdobjref.oid))) - { - if (!stub_manager_notify_unmarshal(stubmgr)) - hres = CO_E_OBJNOTCONNECTED; - - stub_manager_int_release(stubmgr); - } - else - { - WARN("Couldn't find object for OXID %s, OID %s, assuming disconnected\n", - wine_dbgstr_longlong(stdobjref.oxid), - wine_dbgstr_longlong(stdobjref.oid)); - hres = CO_E_OBJNOTCONNECTED; - } - - apartment_release(stub_apt); - } - else - TRACE("Treating unmarshal from OXID %s as inter-process\n", - wine_dbgstr_longlong(stdobjref.oxid)); - - if (hres == S_OK) - hres = unmarshal_object(&stdobjref, apt, riid, ppv); - - if (hres) WARN("Failed with error 0x%08lx\n", hres); - else TRACE("Successfully created proxy %p\n", *ppv); - - return hres; -} - -static HRESULT WINAPI -StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm) -{ - STDOBJREF stdobjref; - ULONG res; - HRESULT hres; - struct stub_manager *stubmgr; - APARTMENT *apt; - - TRACE("iface=%p, pStm=%p\n", iface, pStm); - - hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res); - if (hres) return hres; - - TRACE("oxid = %s, oid = %s, ipid = %s\n", - wine_dbgstr_longlong(stdobjref.oxid), - wine_dbgstr_longlong(stdobjref.oid), - wine_dbgstr_guid(&stdobjref.ipid)); - - if (!(apt = apartment_findfromoxid(stdobjref.oxid, TRUE))) - { - WARN("Could not map OXID %s to apartment object\n", - wine_dbgstr_longlong(stdobjref.oxid)); - return RPC_E_INVALID_OBJREF; - } - - if (!(stubmgr = get_stub_manager(apt, stdobjref.oid))) - { - ERR("could not map MID to stub manager, oxid=%s, oid=%s\n", - wine_dbgstr_longlong(stdobjref.oxid), wine_dbgstr_longlong(stdobjref.oid)); - return RPC_E_INVALID_OBJREF; - } - - stub_manager_release_marshal_data(stubmgr, stdobjref.cPublicRefs); - - stub_manager_int_release(stubmgr); - apartment_release(apt); - - return S_OK; -} - -static HRESULT WINAPI -StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved) -{ - FIXME("(), stub!\n"); - return S_OK; -} - -static const IMarshalVtbl VT_StdMarshal = -{ - StdMarshalImpl_QueryInterface, - StdMarshalImpl_AddRef, - StdMarshalImpl_Release, - StdMarshalImpl_GetUnmarshalClass, - StdMarshalImpl_GetMarshalSizeMax, - StdMarshalImpl_MarshalInterface, - StdMarshalImpl_UnmarshalInterface, - StdMarshalImpl_ReleaseMarshalData, - StdMarshalImpl_DisconnectObject -}; - -static HRESULT StdMarshalImpl_Construct(REFIID riid, void** ppvObject) -{ - StdMarshalImpl * pStdMarshal = - HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(StdMarshalImpl)); - if (!pStdMarshal) - return E_OUTOFMEMORY; - pStdMarshal->lpvtbl = &VT_StdMarshal; - pStdMarshal->ref = 0; - return IMarshal_QueryInterface((IMarshal*)pStdMarshal, riid, ppvObject); -} - -/*********************************************************************** - * CoGetStandardMarshal [OLE32.@] - * - * Gets or creates a standard marshal object. - * - * PARAMS - * riid [I] Interface identifier of the pUnk object. - * pUnk [I] Optional. Object to get the marshal object for. - * dwDestContext [I] Destination. Used to enable or disable optimizations. - * pvDestContext [I] Reserved. Must be NULL. - * mshlflags [I] Flags affecting the marshaling process. - * ppMarshal [O] Address where marshal object will be stored. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - * - * NOTES - * - * The function retrieves the IMarshal object associated with an object if - * that object is currently an active stub, otherwise a new marshal object is - * created. - */ -HRESULT WINAPI CoGetStandardMarshal(REFIID riid, IUnknown *pUnk, - DWORD dwDestContext, LPVOID pvDestContext, - DWORD mshlflags, LPMARSHAL *ppMarshal) -{ - StdMarshalImpl *dm; - - if (pUnk == NULL) - { - FIXME("(%s,NULL,%lx,%p,%lx,%p), unimplemented yet.\n", - debugstr_guid(riid),dwDestContext,pvDestContext,mshlflags,ppMarshal); - return E_NOTIMPL; - } - TRACE("(%s,%p,%lx,%p,%lx,%p)\n", - debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags,ppMarshal); - *ppMarshal = HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl)); - dm = (StdMarshalImpl*) *ppMarshal; - if (!dm) return E_FAIL; - dm->lpvtbl = &VT_StdMarshal; - dm->ref = 1; - - dm->iid = *riid; - dm->dwDestContext = dwDestContext; - dm->pvDestContext = pvDestContext; - dm->mshlflags = mshlflags; - return S_OK; -} - -/*********************************************************************** - * get_marshaler [internal] - * - * Retrieves an IMarshal interface for an object. - */ -static HRESULT get_marshaler(REFIID riid, IUnknown *pUnk, DWORD dwDestContext, - void *pvDestContext, DWORD mshlFlags, - LPMARSHAL *pMarshal) -{ - HRESULT hr; - - if (!pUnk) - return E_POINTER; - hr = IUnknown_QueryInterface(pUnk, &IID_IMarshal, (LPVOID*)pMarshal); - if (hr) - hr = CoGetStandardMarshal(riid, pUnk, dwDestContext, pvDestContext, - mshlFlags, pMarshal); - return hr; -} - -/*********************************************************************** - * get_unmarshaler_from_stream [internal] - * - * Creates an IMarshal* object according to the data marshaled to the stream. - * The function leaves the stream pointer at the start of the data written - * to the stream by the IMarshal* object. - */ -static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, IID *iid) -{ - HRESULT hr; - ULONG res; - OBJREF objref; - - /* read common OBJREF header */ - hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res); - if (hr || (res != FIELD_OFFSET(OBJREF, u_objref))) - { - ERR("Failed to read common OBJREF header, 0x%08lx\n", hr); - return STG_E_READFAULT; - } - - /* sanity check on header */ - if (objref.signature != OBJREF_SIGNATURE) - { - ERR("Bad OBJREF signature 0x%08lx\n", objref.signature); - return RPC_E_INVALID_OBJREF; - } - - if (iid) *iid = objref.iid; - - /* FIXME: handler marshaling */ - if (objref.flags & OBJREF_STANDARD) - { - TRACE("Using standard unmarshaling\n"); - hr = StdMarshalImpl_Construct(&IID_IMarshal, (LPVOID*)marshal); - } - else if (objref.flags & OBJREF_CUSTOM) - { - ULONG custom_header_size = FIELD_OFFSET(OBJREF, u_objref.u_custom.pData) - - FIELD_OFFSET(OBJREF, u_objref.u_custom); - TRACE("Using custom unmarshaling\n"); - /* read constant sized OR_CUSTOM data from stream */ - hr = IStream_Read(stream, &objref.u_objref.u_custom, - custom_header_size, &res); - if (hr || (res != custom_header_size)) - { - ERR("Failed to read OR_CUSTOM header, 0x%08lx\n", hr); - return STG_E_READFAULT; - } - /* now create the marshaler specified in the stream */ - hr = CoCreateInstance(&objref.u_objref.u_custom.clsid, NULL, - CLSCTX_INPROC_SERVER, &IID_IMarshal, - (LPVOID*)marshal); - } - else - { - FIXME("Invalid or unimplemented marshaling type specified: %lx\n", - objref.flags); - return RPC_E_INVALID_OBJREF; - } - - if (hr) - ERR("Failed to create marshal, 0x%08lx\n", hr); - - return hr; -} - -/*********************************************************************** - * CoGetMarshalSizeMax [OLE32.@] - * - * Gets the maximum amount of data that will be needed by a marshal. - * - * PARAMS - * pulSize [O] Address where maximum marshal size will be stored. - * riid [I] Identifier of the interface to marshal. - * pUnk [I] Pointer to the object to marshal. - * dwDestContext [I] Destination. Used to enable or disable optimizations. - * pvDestContext [I] Reserved. Must be NULL. - * mshlFlags [I] Flags that affect the marshaling. See CoMarshalInterface(). - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - * - * SEE ALSO - * CoMarshalInterface(). - */ -HRESULT WINAPI CoGetMarshalSizeMax(ULONG *pulSize, REFIID riid, IUnknown *pUnk, - DWORD dwDestContext, void *pvDestContext, - DWORD mshlFlags) -{ - HRESULT hr; - LPMARSHAL pMarshal; - CLSID marshaler_clsid; - - hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal); - if (hr) - return hr; - - hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext, - pvDestContext, mshlFlags, &marshaler_clsid); - if (hr) - { - ERR("IMarshal::GetUnmarshalClass failed, 0x%08lx\n", hr); - IMarshal_Release(pMarshal); - return hr; - } - - hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext, - pvDestContext, mshlFlags, pulSize); - /* add on the size of the common header */ - *pulSize += FIELD_OFFSET(OBJREF, u_objref); - - /* if custom marshaling, add on size of custom header */ - if (!IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal)) - *pulSize += FIELD_OFFSET(OBJREF, u_objref.u_custom.pData) - - FIELD_OFFSET(OBJREF, u_objref.u_custom); - - IMarshal_Release(pMarshal); - return hr; -} - - -/*********************************************************************** - * CoMarshalInterface [OLE32.@] - * - * Marshals an interface into a stream so that the object can then be - * unmarshaled from another COM apartment and used remotely. - * - * PARAMS - * pStream [I] Stream the object will be marshaled into. - * riid [I] Identifier of the interface to marshal. - * pUnk [I] Pointer to the object to marshal. - * dwDestContext [I] Destination. Used to enable or disable optimizations. - * pvDestContext [I] Reserved. Must be NULL. - * mshlFlags [I] Flags that affect the marshaling. See notes. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - * - * NOTES - * - * The mshlFlags parameter can take one or more of the following flags: - *| MSHLFLAGS_NORMAL - Unmarshal once, releases stub on last proxy release. - *| MSHLFLAGS_TABLESTRONG - Unmarshal many, release when CoReleaseMarshalData() called. - *| MSHLFLAGS_TABLEWEAK - Unmarshal many, releases stub on last proxy release. - *| MSHLFLAGS_NOPING - No automatic garbage collection (and so reduces network traffic). - * - * If a marshaled object is not unmarshaled, then CoReleaseMarshalData() must - * be called in order to release the resources used in the marshaling. - * - * SEE ALSO - * CoUnmarshalInterface(), CoReleaseMarshalData(). - */ -HRESULT WINAPI CoMarshalInterface(IStream *pStream, REFIID riid, IUnknown *pUnk, - DWORD dwDestContext, void *pvDestContext, - DWORD mshlFlags) -{ - HRESULT hr; - CLSID marshaler_clsid; - OBJREF objref; - LPMARSHAL pMarshal; - - TRACE("(%p, %s, %p, %lx, %p, %lx)\n", pStream, debugstr_guid(riid), pUnk, - dwDestContext, pvDestContext, mshlFlags); - - if (pUnk == NULL) - return E_INVALIDARG; - - objref.signature = OBJREF_SIGNATURE; - objref.iid = *riid; - - /* get the marshaler for the specified interface */ - hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal); - if (hr) - { - ERR("Failed to get marshaller, 0x%08lx\n", hr); - return hr; - } - - hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext, - pvDestContext, mshlFlags, &marshaler_clsid); - if (hr) - { - ERR("IMarshal::GetUnmarshalClass failed, 0x%08lx\n", hr); - goto cleanup; - } - - /* FIXME: implement handler marshaling too */ - if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal)) - { - TRACE("Using standard marshaling\n"); - objref.flags = OBJREF_STANDARD; - - /* write the common OBJREF header to the stream */ - hr = IStream_Write(pStream, &objref, FIELD_OFFSET(OBJREF, u_objref), NULL); - if (hr) - { - ERR("Failed to write OBJREF header to stream, 0x%08lx\n", hr); - goto cleanup; - } - } - else - { - TRACE("Using custom marshaling\n"); - objref.flags = OBJREF_CUSTOM; - objref.u_objref.u_custom.clsid = marshaler_clsid; - objref.u_objref.u_custom.cbExtension = 0; - objref.u_objref.u_custom.size = 0; - hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext, - pvDestContext, mshlFlags, - &objref.u_objref.u_custom.size); - if (hr) - { - ERR("Failed to get max size of marshal data, error 0x%08lx\n", hr); - goto cleanup; - } - /* write constant sized common header and OR_CUSTOM data into stream */ - hr = IStream_Write(pStream, &objref, - FIELD_OFFSET(OBJREF, u_objref.u_custom.pData), NULL); - if (hr) - { - ERR("Failed to write OR_CUSTOM header to stream with 0x%08lx\n", hr); - goto cleanup; - } - } - - TRACE("Calling IMarshal::MarshalInterace\n"); - /* call helper object to do the actual marshaling */ - hr = IMarshal_MarshalInterface(pMarshal, pStream, riid, pUnk, dwDestContext, - pvDestContext, mshlFlags); - - if (hr) - { - ERR("Failed to marshal the interface %s, %lx\n", debugstr_guid(riid), hr); - goto cleanup; - } - -cleanup: - IMarshal_Release(pMarshal); - - TRACE("completed with hr 0x%08lx\n", hr); - - return hr; -} - -/*********************************************************************** - * CoUnmarshalInterface [OLE32.@] - * - * Unmarshals an object from a stream by creating a proxy to the remote - * object, if necessary. - * - * PARAMS - * - * pStream [I] Stream containing the marshaled object. - * riid [I] Interface identifier of the object to create a proxy to. - * ppv [O] Address where proxy will be stored. - * - * RETURNS - * - * Success: S_OK. - * Failure: HRESULT code. - * - * SEE ALSO - * CoMarshalInterface(). - */ -HRESULT WINAPI CoUnmarshalInterface(IStream *pStream, REFIID riid, LPVOID *ppv) -{ - HRESULT hr; - LPMARSHAL pMarshal; - IID iid; - IUnknown *object; - - TRACE("(%p, %s, %p)\n", pStream, debugstr_guid(riid), ppv); - - hr = get_unmarshaler_from_stream(pStream, &pMarshal, &iid); - if (hr != S_OK) - return hr; - - /* call the helper object to do the actual unmarshaling */ - hr = IMarshal_UnmarshalInterface(pMarshal, pStream, &iid, (LPVOID*)&object); - if (hr) - ERR("IMarshal::UnmarshalInterface failed, 0x%08lx\n", hr); - - /* IID_NULL means use the interface ID of the marshaled object */ - if (!IsEqualIID(riid, &IID_NULL)) - iid = *riid; - - if (hr == S_OK) - { - if (!IsEqualIID(riid, &iid)) - { - TRACE("requested interface != marshalled interface, additional QI needed\n"); - hr = IUnknown_QueryInterface(object, &iid, ppv); - if (hr) - ERR("Couldn't query for interface %s, hr = 0x%08lx\n", - debugstr_guid(riid), hr); - IUnknown_Release(object); - } - else - { - *ppv = object; - } - } - - IMarshal_Release(pMarshal); - - TRACE("completed with hr 0x%lx\n", hr); - - return hr; -} - -/*********************************************************************** - * CoReleaseMarshalData [OLE32.@] - * - * Releases resources associated with an object that has been marshaled into - * a stream. - * - * PARAMS - * - * pStream [I] The stream that the object has been marshaled into. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT error code. - * - * NOTES - * - * Call this function to release resources associated with a normal or - * table-weak marshal that will not be unmarshaled, and all table-strong - * marshals when they are no longer needed. - * - * SEE ALSO - * CoMarshalInterface(), CoUnmarshalInterface(). - */ -HRESULT WINAPI CoReleaseMarshalData(IStream *pStream) -{ - HRESULT hr; - LPMARSHAL pMarshal; - - TRACE("(%p)\n", pStream); - - hr = get_unmarshaler_from_stream(pStream, &pMarshal, NULL); - if (hr != S_OK) - return hr; - - /* call the helper object to do the releasing of marshal data */ - hr = IMarshal_ReleaseMarshalData(pMarshal, pStream); - if (hr) - ERR("IMarshal::ReleaseMarshalData failed with error 0x%08lx\n", hr); - - IMarshal_Release(pMarshal); - return hr; -} - - -/*********************************************************************** - * CoMarshalInterThreadInterfaceInStream [OLE32.@] - * - * Marshal an interface across threads in the same process. - * - * PARAMS - * riid [I] Identifier of the interface to be marshalled. - * pUnk [I] Pointer to IUnknown-derived interface that will be marshalled. - * ppStm [O] Pointer to IStream object that is created and then used to store the marshalled inteface. - * - * RETURNS - * Success: S_OK - * Failure: E_OUTOFMEMORY and other COM error codes - * - * SEE ALSO - * CoMarshalInterface(), CoUnmarshalInterface() and CoGetInterfaceAndReleaseStream() - */ -HRESULT WINAPI CoMarshalInterThreadInterfaceInStream( - REFIID riid, LPUNKNOWN pUnk, LPSTREAM * ppStm) -{ - ULARGE_INTEGER xpos; - LARGE_INTEGER seekto; - HRESULT hres; - - TRACE("(%s, %p, %p)\n",debugstr_guid(riid), pUnk, ppStm); - - hres = CreateStreamOnHGlobal(0, TRUE, ppStm); - if (FAILED(hres)) return hres; - hres = CoMarshalInterface(*ppStm, riid, pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); - - /* FIXME: is this needed? */ - memset(&seekto,0,sizeof(seekto)); - IStream_Seek(*ppStm,seekto,SEEK_SET,&xpos); - - return hres; -} - -/*********************************************************************** - * CoGetInterfaceAndReleaseStream [OLE32.@] - * - * Unmarshalls an inteface from a stream and then releases the stream. - * - * PARAMS - * pStm [I] Stream that contains the marshalled inteface. - * riid [I] Interface identifier of the object to unmarshall. - * ppv [O] Address of pointer where the requested interface object will be stored. - * - * RETURNS - * Success: S_OK - * Failure: A COM error code - * - * SEE ALSO - * CoMarshalInterThreadInterfaceInStream() and CoUnmarshalInteface() - */ -HRESULT WINAPI CoGetInterfaceAndReleaseStream(LPSTREAM pStm, REFIID riid, - LPVOID *ppv) -{ - HRESULT hres; - - TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv); - - hres = CoUnmarshalInterface(pStm, riid, ppv); - IStream_Release(pStm); - return hres; -} - -static HRESULT WINAPI StdMarshalCF_QueryInterface(LPCLASSFACTORY iface, - REFIID riid, LPVOID *ppv) -{ - *ppv = NULL; - if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) - { - *ppv = (LPVOID)iface; - return S_OK; - } - return E_NOINTERFACE; -} - -static ULONG WINAPI StdMarshalCF_AddRef(LPCLASSFACTORY iface) -{ - return 2; /* non-heap based object */ -} - -static ULONG WINAPI StdMarshalCF_Release(LPCLASSFACTORY iface) -{ - return 1; /* non-heap based object */ -} - -static HRESULT WINAPI StdMarshalCF_CreateInstance(LPCLASSFACTORY iface, - LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv) -{ - if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMarshal)) - return StdMarshalImpl_Construct(riid, ppv); - - FIXME("(%s), not supported.\n",debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static HRESULT WINAPI StdMarshalCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) -{ - FIXME("(%d), stub!\n",fLock); - return S_OK; -} - -static const IClassFactoryVtbl StdMarshalCFVtbl = -{ - StdMarshalCF_QueryInterface, - StdMarshalCF_AddRef, - StdMarshalCF_Release, - StdMarshalCF_CreateInstance, - StdMarshalCF_LockServer -}; -static const IClassFactoryVtbl *StdMarshalCF = &StdMarshalCFVtbl; - -HRESULT MARSHAL_GetStandardMarshalCF(LPVOID *ppv) -{ - *ppv = &StdMarshalCF; - return S_OK; -} - -/*********************************************************************** - * CoMarshalHresult [OLE32.@] - * - * Marshals an HRESULT value into a stream. - * - * PARAMS - * pStm [I] Stream that hresult will be marshalled into. - * hresult [I] HRESULT to be marshalled. - * - * RETURNS - * Success: S_OK - * Failure: A COM error code - * - * SEE ALSO - * CoUnmarshalHresult(). - */ -HRESULT WINAPI CoMarshalHresult(LPSTREAM pStm, HRESULT hresult) -{ - return IStream_Write(pStm, &hresult, sizeof(hresult), NULL); -} - -/*********************************************************************** - * CoUnmarshalHresult [OLE32.@] - * - * Unmarshals an HRESULT value from a stream. - * - * PARAMS - * pStm [I] Stream that hresult will be unmarshalled from. - * phresult [I] Pointer to HRESULT where the value will be unmarshalled to. - * - * RETURNS - * Success: S_OK - * Failure: A COM error code - * - * SEE ALSO - * CoMarshalHresult(). - */ -HRESULT WINAPI CoUnmarshalHresult(LPSTREAM pStm, HRESULT * phresult) -{ - return IStream_Read(pStm, phresult, sizeof(*phresult), NULL); -} +/* + * Marshalling library + * + * Copyright 2002 Marcus Meissner + * Copyright 2004 Mike Hearn, for CodeWeavers + * Copyright 2004 Rob Shearman, for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#define COBJMACROS + +#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 "wtypes.h" +#include "wine/unicode.h" + +#include "compobj_private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +extern const CLSID CLSID_DfMarshal; + +/* number of refs given out for normal marshaling */ +#define NORMALEXTREFS 1 /* FIXME: this should be 5, but we have to wait for IRemUnknown support first */ + +/* private flag indicating that the caller does not want to notify the stub + * when the proxy disconnects or is destroyed */ +#define SORFP_NOLIFETIMEMGMT SORF_OXRES1 + +static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, REFIID riid, void **object); + +/* Marshalling just passes a unique identifier to the remote client, + * that makes it possible to find the passed interface again. + * + * So basically we need a set of values that make it unique. + * + * Note that the IUnknown_QI(ob,xiid,&ppv) always returns the SAME ppv value! + * + * A triple is used: OXID (apt id), OID (stub manager id), + * IPID (interface ptr/stub id). + * + * OXIDs identify an apartment and are network scoped + * OIDs identify a stub manager and are apartment scoped + * IPIDs identify an interface stub and are apartment scoped + */ + +inline static HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf) +{ + HRESULT hr; + CLSID clsid; + + if ((hr = CoGetPSClsid(riid, &clsid))) + return hr; + return CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, + &IID_IPSFactoryBuffer, (LPVOID*)facbuf); +} + +/* creates a new stub manager */ +HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *obj, MSHLFLAGS mshlflags) +{ + struct stub_manager *manager; + struct ifstub *ifstub; + BOOL tablemarshal; + IRpcStubBuffer *stub; + IPSFactoryBuffer *psfb; + HRESULT hr; + + hr = apartment_getoxid(apt, &stdobjref->oxid); + if (hr != S_OK) + return hr; + + hr = get_facbuf_for_iid(riid, &psfb); + if (hr != S_OK) + { + ERR("couldn't get IPSFactory buffer for interface %s\n", debugstr_guid(riid)); + return hr; + } + + hr = IPSFactoryBuffer_CreateStub(psfb, riid, obj, &stub); + IPSFactoryBuffer_Release(psfb); + if (hr != S_OK) + { + ERR("Failed to create an IRpcStubBuffer from IPSFactory for %s\n", debugstr_guid(riid)); + return hr; + } + + if (mshlflags & MSHLFLAGS_NOPING) + stdobjref->flags = SORF_NOPING; + else + stdobjref->flags = SORF_NULL; + + /* FIXME: what happens if we register an interface twice with different + * marshaling flags? */ + if ((manager = get_stub_manager_from_object(apt, obj))) + TRACE("registering new ifstub on pre-existing manager\n"); + else + { + TRACE("constructing new stub manager\n"); + + manager = new_stub_manager(apt, obj, mshlflags); + if (!manager) + { + IRpcStubBuffer_Release(stub); + return E_OUTOFMEMORY; + } + } + stdobjref->oid = manager->oid; + + tablemarshal = ((mshlflags & MSHLFLAGS_TABLESTRONG) || (mshlflags & MSHLFLAGS_TABLEWEAK)); + + ifstub = stub_manager_new_ifstub(manager, stub, obj, riid); + if (!ifstub) + { + IRpcStubBuffer_Release(stub); + stub_manager_int_release(manager); + /* FIXME: should we do another release to completely destroy the + * stub manager? */ + return E_OUTOFMEMORY; + } + + if (!tablemarshal) + { + stdobjref->cPublicRefs = NORMALEXTREFS; + stub_manager_ext_addref(manager, stdobjref->cPublicRefs); + } + else + { + stdobjref->cPublicRefs = 0; + if (mshlflags & MSHLFLAGS_TABLESTRONG) + stub_manager_ext_addref(manager, 1); + } + + /* FIXME: check return value */ + RPC_RegisterInterface(riid); + + stdobjref->ipid = ifstub->ipid; + + stub_manager_int_release(manager); + return S_OK; +} + + + +/* Client-side identity of the server object */ + +static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk); +static void proxy_manager_destroy(struct proxy_manager * This); +static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found); +static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv); + +static HRESULT WINAPI ClientIdentity_QueryInterface(IMultiQI * iface, REFIID riid, void ** ppv) +{ + HRESULT hr; + MULTI_QI mqi; + + TRACE("%s\n", debugstr_guid(riid)); + + mqi.pIID = riid; + hr = IMultiQI_QueryMultipleInterfaces(iface, 1, &mqi); + *ppv = (void *)mqi.pItf; + + return hr; +} + +static ULONG WINAPI ClientIdentity_AddRef(IMultiQI * iface) +{ + struct proxy_manager * This = (struct proxy_manager *)iface; + TRACE("%p - before %ld\n", iface, This->refs); + return InterlockedIncrement(&This->refs); +} + +static ULONG WINAPI ClientIdentity_Release(IMultiQI * iface) +{ + struct proxy_manager * This = (struct proxy_manager *)iface; + ULONG refs = InterlockedDecrement(&This->refs); + TRACE("%p - after %ld\n", iface, refs); + if (!refs) + proxy_manager_destroy(This); + return refs; +} + +static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, ULONG cMQIs, MULTI_QI *pMQIs) +{ + struct proxy_manager * This = (struct proxy_manager *)iface; + REMQIRESULT *qiresults = NULL; + ULONG nonlocal_mqis = 0; + ULONG i; + ULONG successful_mqis = 0; + IID *iids = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*iids)); + /* mapping of RemQueryInterface index to QueryMultipleInterfaces index */ + ULONG *mapping = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*mapping)); + + TRACE("cMQIs: %ld\n", cMQIs); + + /* try to get a local interface - this includes already active proxy + * interfaces and also interfaces exposed by the proxy manager */ + for (i = 0; i < cMQIs; i++) + { + TRACE("iid[%ld] = %s\n", i, debugstr_guid(pMQIs[i].pIID)); + pMQIs[i].hr = proxy_manager_query_local_interface(This, pMQIs[i].pIID, (void **)&pMQIs[i].pItf); + if (pMQIs[i].hr == S_OK) + successful_mqis++; + else + { + iids[nonlocal_mqis] = *pMQIs[i].pIID; + mapping[nonlocal_mqis] = i; + nonlocal_mqis++; + } + } + + TRACE("%ld interfaces not found locally\n", nonlocal_mqis); + + /* if we have more than one interface not found locally then we must try + * to query the remote object for it */ + if (nonlocal_mqis != 0) + { + IRemUnknown *remunk; + HRESULT hr; + IPID *ipid; + + /* get the ipid of the first entry */ + /* FIXME: should we implement ClientIdentity on the ifproxies instead + * of the proxy_manager so we use the correct ipid here? */ + ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->ipid; + + /* get IRemUnknown proxy so we can communicate with the remote object */ + hr = proxy_manager_get_remunknown(This, &remunk); + + if (hr == S_OK) + { + hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS, + nonlocal_mqis, iids, &qiresults); + if (FAILED(hr)) + ERR("IRemUnknown_RemQueryInterface failed with error 0x%08lx\n", hr); + } + + /* IRemUnknown_RemQueryInterface can return S_FALSE if only some of + * the interfaces were returned */ + if (SUCCEEDED(hr)) + { + /* try to unmarshal each object returned to us */ + for (i = 0; i < nonlocal_mqis; i++) + { + ULONG index = mapping[i]; + HRESULT hrobj = qiresults[i].hResult; + if (hrobj == S_OK) + hrobj = unmarshal_object(&qiresults[i].std, This->parent, + pMQIs[index].pIID, + (void **)&pMQIs[index].pItf); + + if (hrobj == S_OK) + successful_mqis++; + else + ERR("Failed to get pointer to interface %s\n", debugstr_guid(pMQIs[index].pIID)); + pMQIs[index].hr = hrobj; + } + } + + /* free the memory allocated by the proxy */ + CoTaskMemFree(qiresults); + } + + TRACE("%ld/%ld successfully queried\n", successful_mqis, cMQIs); + + HeapFree(GetProcessHeap(), 0, iids); + HeapFree(GetProcessHeap(), 0, mapping); + + if (successful_mqis == cMQIs) + return S_OK; /* we got all requested interfaces */ + else if (successful_mqis == 0) + return E_NOINTERFACE; /* we didn't get any interfaces */ + else + return S_FALSE; /* we got some interfaces */ +} + +static const IMultiQIVtbl ClientIdentity_Vtbl = +{ + ClientIdentity_QueryInterface, + ClientIdentity_AddRef, + ClientIdentity_Release, + ClientIdentity_QueryMultipleInterfaces +}; + +static HRESULT ifproxy_get_public_ref(struct ifproxy * This) +{ + HRESULT hr = S_OK; + + if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE)) + { + ERR("Wait failed for ifproxy %p\n", This); + return E_UNEXPECTED; + } + + if (This->refs == 0) + { + IRemUnknown *remunk = NULL; + + TRACE("getting public ref for ifproxy %p\n", This); + + hr = proxy_manager_get_remunknown(This->parent, &remunk); + if (hr == S_OK) + { + HRESULT hrref; + REMINTERFACEREF rif; + rif.ipid = This->ipid; + rif.cPublicRefs = NORMALEXTREFS; + rif.cPrivateRefs = 0; + hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref); + if (hr == S_OK && hrref == S_OK) + This->refs += NORMALEXTREFS; + else + ERR("IRemUnknown_RemAddRef returned with 0x%08lx, hrref = 0x%08lx\n", hr, hrref); + } + } + ReleaseMutex(This->parent->remoting_mutex); + + return hr; +} + +static HRESULT ifproxy_release_public_refs(struct ifproxy * This) +{ + HRESULT hr = S_OK; + + if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE)) + { + ERR("Wait failed for ifproxy %p\n", This); + return E_UNEXPECTED; + } + + if (This->refs > 0) + { + IRemUnknown *remunk = NULL; + + TRACE("releasing %ld refs\n", This->refs); + + hr = proxy_manager_get_remunknown(This->parent, &remunk); + if (hr == S_OK) + { + REMINTERFACEREF rif; + rif.ipid = This->ipid; + rif.cPublicRefs = This->refs; + rif.cPrivateRefs = 0; + hr = IRemUnknown_RemRelease(remunk, 1, &rif); + if (hr == S_OK) + This->refs = 0; + else if (hr == RPC_E_DISCONNECTED) + WARN("couldn't release references because object was " + "disconnected: oxid = %s, oid = %s\n", + wine_dbgstr_longlong(This->parent->oxid), + wine_dbgstr_longlong(This->parent->oid)); + else + ERR("IRemUnknown_RemRelease failed with error 0x%08lx\n", hr); + } + } + ReleaseMutex(This->parent->remoting_mutex); + + return hr; +} + +/* should be called inside This->parent->cs critical section */ +static void ifproxy_disconnect(struct ifproxy * This) +{ + ifproxy_release_public_refs(This); + if (This->proxy) IRpcProxyBuffer_Disconnect(This->proxy); + + IRpcChannelBuffer_Release(This->chan); + This->chan = NULL; +} + +/* should be called in This->parent->cs critical section if it is an entry in parent's list */ +static void ifproxy_destroy(struct ifproxy * This) +{ + TRACE("%p\n", This); + + /* release public references to this object so that the stub can know + * when to destroy itself */ + ifproxy_release_public_refs(This); + + list_remove(&This->entry); + + if (This->chan) + { + IRpcChannelBuffer_Release(This->chan); + This->chan = NULL; + } + + /* note: we don't call Release for This->proxy because its lifetime is + * controlled by the return value from ClientIdentity_Release, which this + * function is always called from */ + + HeapFree(GetProcessHeap(), 0, This); +} + +static HRESULT proxy_manager_construct( + APARTMENT * apt, ULONG sorflags, OXID oxid, OID oid, + struct proxy_manager ** proxy_manager) +{ + struct proxy_manager * This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + if (!This) return E_OUTOFMEMORY; + + This->remoting_mutex = CreateMutexW(NULL, FALSE, NULL); + if (!This->remoting_mutex) + { + HeapFree(GetProcessHeap(), 0, This); + return HRESULT_FROM_WIN32(GetLastError()); + } + + This->lpVtbl = &ClientIdentity_Vtbl; + + list_init(&This->entry); + list_init(&This->interfaces); + + InitializeCriticalSection(&This->cs); + DEBUG_SET_CRITSEC_NAME(&This->cs, "proxy_manager"); + + /* the apartment the object was unmarshaled into */ + This->parent = apt; + + /* the source apartment and id of the object */ + This->oxid = oxid; + This->oid = oid; + + This->refs = 1; + + /* the DCOM draft specification states that the SORF_NOPING flag is + * proxy manager specific, not ifproxy specific, so this implies that we + * should store the STDOBJREF flags here in the proxy manager. */ + This->sorflags = sorflags; + + /* we create the IRemUnknown proxy on demand */ + This->remunk = NULL; + + EnterCriticalSection(&apt->cs); + /* FIXME: we are dependent on the ordering in here to make sure a proxy's + * IRemUnknown proxy doesn't get destroyed before the regual proxy does + * because we need the IRemUnknown proxy during the destruction of the + * regular proxy. Ideally, we should maintain a separate list for the + * IRemUnknown proxies that need late destruction */ + list_add_tail(&apt->proxies, &This->entry); + LeaveCriticalSection(&apt->cs); + + TRACE("%p created for OXID %s, OID %s\n", This, + wine_dbgstr_longlong(oxid), wine_dbgstr_longlong(oid)); + + *proxy_manager = This; + return S_OK; +} + +static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv) +{ + HRESULT hr; + struct ifproxy * ifproxy; + + TRACE("%s\n", debugstr_guid(riid)); + + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IMultiQI)) + { + *ppv = (void *)&This->lpVtbl; + IMultiQI_AddRef((IMultiQI *)&This->lpVtbl); + return S_OK; + } + + hr = proxy_manager_find_ifproxy(This, riid, &ifproxy); + if (hr == S_OK) + { + *ppv = ifproxy->iface; + IUnknown_AddRef((IUnknown *)*ppv); + return S_OK; + } + + *ppv = NULL; + return E_NOINTERFACE; +} + +static HRESULT proxy_manager_create_ifproxy( + struct proxy_manager * This, const IPID *ipid, REFIID riid, ULONG cPublicRefs, + IRpcChannelBuffer * channel, struct ifproxy ** iif_out) +{ + HRESULT hr; + IPSFactoryBuffer * psfb; + struct ifproxy * ifproxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*ifproxy)); + if (!ifproxy) return E_OUTOFMEMORY; + + list_init(&ifproxy->entry); + + ifproxy->parent = This; + ifproxy->ipid = *ipid; + ifproxy->iid = *riid; + ifproxy->refs = cPublicRefs; + ifproxy->proxy = NULL; + + assert(channel); + ifproxy->chan = channel; /* FIXME: we should take the binding strings and construct the channel in this function */ + + /* the IUnknown interface is special because it does not have a + * proxy associated with the ifproxy as we handle IUnknown ourselves */ + if (IsEqualIID(riid, &IID_IUnknown)) + { + ifproxy->iface = (void *)&This->lpVtbl; + hr = S_OK; + } + else + { + hr = get_facbuf_for_iid(riid, &psfb); + if (hr == S_OK) + { + /* important note: the outer unknown is set to the proxy manager. + * This ensures the COM identity rules are not violated, by having a + * one-to-one mapping of objects on the proxy side to objects on the + * stub side, no matter which interface you view the object through */ + hr = IPSFactoryBuffer_CreateProxy(psfb, (IUnknown *)&This->lpVtbl, riid, + &ifproxy->proxy, &ifproxy->iface); + IPSFactoryBuffer_Release(psfb); + if (hr != S_OK) + ERR("Could not create proxy for interface %s, error 0x%08lx\n", + debugstr_guid(riid), hr); + } + else + ERR("Could not get IPSFactoryBuffer for interface %s, error 0x%08lx\n", + debugstr_guid(riid), hr); + + if (hr == S_OK) + hr = IRpcProxyBuffer_Connect(ifproxy->proxy, ifproxy->chan); + } + + /* get at least one external reference to the object to keep it alive */ + if (hr == S_OK) + hr = ifproxy_get_public_ref(ifproxy); + + if (hr == S_OK) + { + EnterCriticalSection(&This->cs); + list_add_tail(&This->interfaces, &ifproxy->entry); + LeaveCriticalSection(&This->cs); + + *iif_out = ifproxy; + TRACE("ifproxy %p created for IPID %s, interface %s with %lu public refs\n", + ifproxy, debugstr_guid(ipid), debugstr_guid(riid), cPublicRefs); + } + else + ifproxy_destroy(ifproxy); + + return hr; +} + +static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found) +{ + HRESULT hr = E_NOINTERFACE; /* assume not found */ + struct list * cursor; + + EnterCriticalSection(&This->cs); + LIST_FOR_EACH(cursor, &This->interfaces) + { + struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry); + if (IsEqualIID(riid, &ifproxy->iid)) + { + *ifproxy_found = ifproxy; + hr = S_OK; + break; + } + } + LeaveCriticalSection(&This->cs); + + return hr; +} + +static void proxy_manager_disconnect(struct proxy_manager * This) +{ + struct list * cursor; + + TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid), + wine_dbgstr_longlong(This->oid)); + + EnterCriticalSection(&This->cs); + + LIST_FOR_EACH(cursor, &This->interfaces) + { + struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry); + ifproxy_disconnect(ifproxy); + } + + /* apartment is being destroyed so don't keep a pointer around to it */ + This->parent = NULL; + + LeaveCriticalSection(&This->cs); +} + +static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk) +{ + HRESULT hr = S_OK; + + /* we don't want to try and unmarshal or use IRemUnknown if we don't want + * lifetime management */ + if (This->sorflags & SORFP_NOLIFETIMEMGMT) + return S_FALSE; + + EnterCriticalSection(&This->cs); + if (This->remunk) + /* already created - return existing object */ + *remunk = This->remunk; + else if (!This->parent) + /* disconnected - we can't create IRemUnknown */ + hr = S_FALSE; + else + { + STDOBJREF stdobjref; + /* Don't want IRemUnknown lifetime management as this is IRemUnknown! + * We also don't care about whether or not the stub is still alive */ + stdobjref.flags = SORFP_NOLIFETIMEMGMT | SORF_NOPING; + stdobjref.cPublicRefs = 1; + /* oxid of destination object */ + stdobjref.oxid = This->oxid; + /* FIXME: what should be used for the oid? The DCOM draft doesn't say */ + stdobjref.oid = (OID)-1; + /* FIXME: this is a hack around not having an OXID resolver yet - + * the OXID resolver should give us the IPID of the IRemUnknown + * interface */ + stdobjref.ipid.Data1 = 0xffffffff; + stdobjref.ipid.Data2 = 0xffff; + stdobjref.ipid.Data3 = 0xffff; + assert(sizeof(stdobjref.ipid.Data4) == sizeof(stdobjref.oxid)); + memcpy(&stdobjref.ipid.Data4, &stdobjref.oxid, sizeof(OXID)); + + /* do the unmarshal */ + hr = unmarshal_object(&stdobjref, This->parent, &IID_IRemUnknown, (void**)&This->remunk); + if (hr == S_OK) + *remunk = This->remunk; + } + LeaveCriticalSection(&This->cs); + + TRACE("got IRemUnknown* pointer %p, hr = 0x%08lx\n", *remunk, hr); + + return hr; +} + +/* destroys a proxy manager, freeing the memory it used. + * Note: this function should not be called from a list iteration in the + * apartment, due to the fact that it removes itself from the apartment and + * it could add a proxy to IRemUnknown into the apartment. */ +static void proxy_manager_destroy(struct proxy_manager * This) +{ + struct list * cursor; + + TRACE("oxid = %s, oid = %s\n", wine_dbgstr_longlong(This->oxid), + wine_dbgstr_longlong(This->oid)); + + if (This->parent) + { + EnterCriticalSection(&This->parent->cs); + + /* remove ourself from the list of proxy objects in the apartment */ + LIST_FOR_EACH(cursor, &This->parent->proxies) + { + if (cursor == &This->entry) + { + list_remove(&This->entry); + break; + } + } + + LeaveCriticalSection(&This->parent->cs); + } + + /* destroy all of the interface proxies */ + while ((cursor = list_head(&This->interfaces))) + { + struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry); + ifproxy_destroy(ifproxy); + } + + if (This->remunk) IRemUnknown_Release(This->remunk); + + DEBUG_CLEAR_CRITSEC_NAME(&This->cs); + DeleteCriticalSection(&This->cs); + + CloseHandle(This->remoting_mutex); + + HeapFree(GetProcessHeap(), 0, This); +} + +/* finds the proxy manager corresponding to a given OXID and OID that has + * been unmarshaled in the specified apartment. The caller must release the + * reference to the proxy_manager when the object is no longer used. */ +static BOOL find_proxy_manager(APARTMENT * apt, OXID oxid, OID oid, struct proxy_manager ** proxy_found) +{ + BOOL found = FALSE; + struct list * cursor; + + EnterCriticalSection(&apt->cs); + LIST_FOR_EACH(cursor, &apt->proxies) + { + struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry); + if ((oxid == proxy->oxid) && (oid == proxy->oid)) + { + *proxy_found = proxy; + ClientIdentity_AddRef((IMultiQI *)&proxy->lpVtbl); + found = TRUE; + break; + } + } + LeaveCriticalSection(&apt->cs); + return found; +} + +HRESULT apartment_disconnectproxies(struct apartment *apt) +{ + struct list * cursor; + + LIST_FOR_EACH(cursor, &apt->proxies) + { + struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry); + proxy_manager_disconnect(proxy); + } + + return S_OK; +} + +/********************** StdMarshal implementation ****************************/ +typedef struct _StdMarshalImpl +{ + const IMarshalVtbl *lpvtbl; + DWORD ref; + + IID iid; + DWORD dwDestContext; + LPVOID pvDestContext; + DWORD mshlflags; +} StdMarshalImpl; + +static HRESULT WINAPI +StdMarshalImpl_QueryInterface(LPMARSHAL iface, REFIID riid, LPVOID *ppv) +{ + *ppv = NULL; + if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IMarshal, riid)) + { + *ppv = iface; + IUnknown_AddRef(iface); + return S_OK; + } + FIXME("No interface for %s.\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI +StdMarshalImpl_AddRef(LPMARSHAL iface) +{ + StdMarshalImpl *This = (StdMarshalImpl *)iface; + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI +StdMarshalImpl_Release(LPMARSHAL iface) +{ + StdMarshalImpl *This = (StdMarshalImpl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + if (!ref) HeapFree(GetProcessHeap(),0,This); + return ref; +} + +static HRESULT WINAPI +StdMarshalImpl_GetUnmarshalClass( + LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, + void* pvDestContext, DWORD mshlflags, CLSID* pCid) +{ + *pCid = CLSID_DfMarshal; + return S_OK; +} + +static HRESULT WINAPI +StdMarshalImpl_GetMarshalSizeMax( + LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, + void* pvDestContext, DWORD mshlflags, DWORD* pSize) +{ + *pSize = sizeof(STDOBJREF); + return S_OK; +} + +static HRESULT WINAPI +StdMarshalImpl_MarshalInterface( + LPMARSHAL iface, IStream *pStm,REFIID riid, void* pv, DWORD dwDestContext, + void* pvDestContext, DWORD mshlflags) +{ + STDOBJREF stdobjref; + IUnknown *pUnk; + ULONG res; + HRESULT hres; + APARTMENT *apt = COM_CurrentApt(); + + TRACE("(...,%s,...)\n", debugstr_guid(riid)); + + if (!apt) + { + ERR("Apartment not initialized\n"); + return CO_E_NOTINITIALIZED; + } + + /* make sure this apartment can be reached from other threads / processes */ + RPC_StartRemoting(apt); + + hres = IUnknown_QueryInterface((LPUNKNOWN)pv, riid, (LPVOID*)&pUnk); + if (hres != S_OK) + { + ERR("object doesn't expose interface %s, failing with error 0x%08lx\n", + debugstr_guid(riid), hres); + return E_NOINTERFACE; + } + + hres = marshal_object(apt, &stdobjref, riid, pUnk, mshlflags); + + IUnknown_Release(pUnk); + + if (hres) + { + ERR("Failed to create ifstub, hres=0x%lx\n", hres); + return hres; + } + + hres = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), &res); + if (hres) return hres; + + return S_OK; +} + +/* helper for StdMarshalImpl_UnmarshalInterface - does the unmarshaling with + * no questions asked about the rules surrounding same-apartment unmarshals + * and table marshaling */ +static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, REFIID riid, void **object) +{ + struct proxy_manager *proxy_manager = NULL; + HRESULT hr = S_OK; + + assert(apt); + + TRACE("stdobjref:\n\tflags = %04lx\n\tcPublicRefs = %ld\n\toxid = %s\n\toid = %s\n\tipid = %s\n", + stdobjref->flags, stdobjref->cPublicRefs, + wine_dbgstr_longlong(stdobjref->oxid), + wine_dbgstr_longlong(stdobjref->oid), + debugstr_guid(&stdobjref->ipid)); + + /* create an a new proxy manager if one doesn't already exist for the + * object */ + if (!find_proxy_manager(apt, stdobjref->oxid, stdobjref->oid, &proxy_manager)) + { + hr = proxy_manager_construct(apt, stdobjref->flags, + stdobjref->oxid, stdobjref->oid, + &proxy_manager); + } + else + TRACE("proxy manager already created, using\n"); + + if (hr == S_OK) + { + struct ifproxy * ifproxy; + hr = proxy_manager_find_ifproxy(proxy_manager, riid, &ifproxy); + if (hr == E_NOINTERFACE) + { + IRpcChannelBuffer *chanbuf; + hr = RPC_CreateClientChannel(&stdobjref->oxid, &stdobjref->ipid, &chanbuf); + if (hr == S_OK) + hr = proxy_manager_create_ifproxy(proxy_manager, &stdobjref->ipid, + riid, stdobjref->cPublicRefs, + chanbuf, &ifproxy); + } + + if (hr == S_OK) + { + /* FIXME: push this AddRef inside proxy_manager_find_ifproxy/create_ifproxy? */ + ClientIdentity_AddRef((IMultiQI*)&proxy_manager->lpVtbl); + *object = ifproxy->iface; + } + } + + /* release our reference to the proxy manager - the client/apartment + * will hold on to the remaining reference for us */ + if (proxy_manager) ClientIdentity_Release((IMultiQI*)&proxy_manager->lpVtbl); + + return hr; +} + +static HRESULT WINAPI +StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv) +{ + struct stub_manager *stubmgr; + STDOBJREF stdobjref; + ULONG res; + HRESULT hres; + APARTMENT *apt = COM_CurrentApt(); + APARTMENT *stub_apt; + OXID oxid; + + TRACE("(...,%s,....)\n", debugstr_guid(riid)); + + /* we need an apartment to unmarshal into */ + if (!apt) + { + ERR("Apartment not initialized\n"); + return CO_E_NOTINITIALIZED; + } + + /* read STDOBJREF from wire */ + hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res); + if (hres) return hres; + + hres = apartment_getoxid(apt, &oxid); + if (hres) return hres; + + /* check if we're marshalling back to ourselves */ + if ((oxid == stdobjref.oxid) && (stubmgr = get_stub_manager(apt, stdobjref.oid))) + { + TRACE("Unmarshalling object marshalled in same apartment for iid %s, " + "returning original object %p\n", debugstr_guid(riid), stubmgr->object); + + hres = IUnknown_QueryInterface(stubmgr->object, riid, ppv); + + /* unref the ifstub. FIXME: only do this on success? */ + if (!stub_manager_is_table_marshaled(stubmgr)) + stub_manager_ext_release(stubmgr, 1); + + stub_manager_int_release(stubmgr); + return hres; + } + + /* notify stub manager about unmarshal if process-local object. + * note: if the oxid is not found then we and native will quite happily + * ignore table marshaling and normal marshaling rules regarding number of + * unmarshals, etc, but if you abuse these rules then your proxy could end + * up returning RPC_E_DISCONNECTED. */ + if ((stub_apt = apartment_findfromoxid(stdobjref.oxid, TRUE))) + { + if ((stubmgr = get_stub_manager(stub_apt, stdobjref.oid))) + { + if (!stub_manager_notify_unmarshal(stubmgr)) + hres = CO_E_OBJNOTCONNECTED; + + stub_manager_int_release(stubmgr); + } + else + { + WARN("Couldn't find object for OXID %s, OID %s, assuming disconnected\n", + wine_dbgstr_longlong(stdobjref.oxid), + wine_dbgstr_longlong(stdobjref.oid)); + hres = CO_E_OBJNOTCONNECTED; + } + + apartment_release(stub_apt); + } + else + TRACE("Treating unmarshal from OXID %s as inter-process\n", + wine_dbgstr_longlong(stdobjref.oxid)); + + if (hres == S_OK) + hres = unmarshal_object(&stdobjref, apt, riid, ppv); + + if (hres) WARN("Failed with error 0x%08lx\n", hres); + else TRACE("Successfully created proxy %p\n", *ppv); + + return hres; +} + +static HRESULT WINAPI +StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm) +{ + STDOBJREF stdobjref; + ULONG res; + HRESULT hres; + struct stub_manager *stubmgr; + APARTMENT *apt; + + TRACE("iface=%p, pStm=%p\n", iface, pStm); + + hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res); + if (hres) return hres; + + TRACE("oxid = %s, oid = %s, ipid = %s\n", + wine_dbgstr_longlong(stdobjref.oxid), + wine_dbgstr_longlong(stdobjref.oid), + wine_dbgstr_guid(&stdobjref.ipid)); + + if (!(apt = apartment_findfromoxid(stdobjref.oxid, TRUE))) + { + WARN("Could not map OXID %s to apartment object\n", + wine_dbgstr_longlong(stdobjref.oxid)); + return RPC_E_INVALID_OBJREF; + } + + if (!(stubmgr = get_stub_manager(apt, stdobjref.oid))) + { + ERR("could not map MID to stub manager, oxid=%s, oid=%s\n", + wine_dbgstr_longlong(stdobjref.oxid), wine_dbgstr_longlong(stdobjref.oid)); + return RPC_E_INVALID_OBJREF; + } + + stub_manager_release_marshal_data(stubmgr, stdobjref.cPublicRefs); + + stub_manager_int_release(stubmgr); + apartment_release(apt); + + return S_OK; +} + +static HRESULT WINAPI +StdMarshalImpl_DisconnectObject(LPMARSHAL iface, DWORD dwReserved) +{ + FIXME("(), stub!\n"); + return S_OK; +} + +static const IMarshalVtbl VT_StdMarshal = +{ + StdMarshalImpl_QueryInterface, + StdMarshalImpl_AddRef, + StdMarshalImpl_Release, + StdMarshalImpl_GetUnmarshalClass, + StdMarshalImpl_GetMarshalSizeMax, + StdMarshalImpl_MarshalInterface, + StdMarshalImpl_UnmarshalInterface, + StdMarshalImpl_ReleaseMarshalData, + StdMarshalImpl_DisconnectObject +}; + +static HRESULT StdMarshalImpl_Construct(REFIID riid, void** ppvObject) +{ + StdMarshalImpl * pStdMarshal = + HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(StdMarshalImpl)); + if (!pStdMarshal) + return E_OUTOFMEMORY; + pStdMarshal->lpvtbl = &VT_StdMarshal; + pStdMarshal->ref = 0; + return IMarshal_QueryInterface((IMarshal*)pStdMarshal, riid, ppvObject); +} + +/*********************************************************************** + * CoGetStandardMarshal [OLE32.@] + * + * Gets or creates a standard marshal object. + * + * PARAMS + * riid [I] Interface identifier of the pUnk object. + * pUnk [I] Optional. Object to get the marshal object for. + * dwDestContext [I] Destination. Used to enable or disable optimizations. + * pvDestContext [I] Reserved. Must be NULL. + * mshlflags [I] Flags affecting the marshaling process. + * ppMarshal [O] Address where marshal object will be stored. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * NOTES + * + * The function retrieves the IMarshal object associated with an object if + * that object is currently an active stub, otherwise a new marshal object is + * created. + */ +HRESULT WINAPI CoGetStandardMarshal(REFIID riid, IUnknown *pUnk, + DWORD dwDestContext, LPVOID pvDestContext, + DWORD mshlflags, LPMARSHAL *ppMarshal) +{ + StdMarshalImpl *dm; + + if (pUnk == NULL) + { + FIXME("(%s,NULL,%lx,%p,%lx,%p), unimplemented yet.\n", + debugstr_guid(riid),dwDestContext,pvDestContext,mshlflags,ppMarshal); + return E_NOTIMPL; + } + TRACE("(%s,%p,%lx,%p,%lx,%p)\n", + debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags,ppMarshal); + *ppMarshal = HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl)); + dm = (StdMarshalImpl*) *ppMarshal; + if (!dm) return E_FAIL; + dm->lpvtbl = &VT_StdMarshal; + dm->ref = 1; + + dm->iid = *riid; + dm->dwDestContext = dwDestContext; + dm->pvDestContext = pvDestContext; + dm->mshlflags = mshlflags; + return S_OK; +} + +/*********************************************************************** + * get_marshaler [internal] + * + * Retrieves an IMarshal interface for an object. + */ +static HRESULT get_marshaler(REFIID riid, IUnknown *pUnk, DWORD dwDestContext, + void *pvDestContext, DWORD mshlFlags, + LPMARSHAL *pMarshal) +{ + HRESULT hr; + + if (!pUnk) + return E_POINTER; + hr = IUnknown_QueryInterface(pUnk, &IID_IMarshal, (LPVOID*)pMarshal); + if (hr) + hr = CoGetStandardMarshal(riid, pUnk, dwDestContext, pvDestContext, + mshlFlags, pMarshal); + return hr; +} + +/*********************************************************************** + * get_unmarshaler_from_stream [internal] + * + * Creates an IMarshal* object according to the data marshaled to the stream. + * The function leaves the stream pointer at the start of the data written + * to the stream by the IMarshal* object. + */ +static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, IID *iid) +{ + HRESULT hr; + ULONG res; + OBJREF objref; + + /* read common OBJREF header */ + hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res); + if (hr || (res != FIELD_OFFSET(OBJREF, u_objref))) + { + ERR("Failed to read common OBJREF header, 0x%08lx\n", hr); + return STG_E_READFAULT; + } + + /* sanity check on header */ + if (objref.signature != OBJREF_SIGNATURE) + { + ERR("Bad OBJREF signature 0x%08lx\n", objref.signature); + return RPC_E_INVALID_OBJREF; + } + + if (iid) *iid = objref.iid; + + /* FIXME: handler marshaling */ + if (objref.flags & OBJREF_STANDARD) + { + TRACE("Using standard unmarshaling\n"); + hr = StdMarshalImpl_Construct(&IID_IMarshal, (LPVOID*)marshal); + } + else if (objref.flags & OBJREF_CUSTOM) + { + ULONG custom_header_size = FIELD_OFFSET(OBJREF, u_objref.u_custom.pData) - + FIELD_OFFSET(OBJREF, u_objref.u_custom); + TRACE("Using custom unmarshaling\n"); + /* read constant sized OR_CUSTOM data from stream */ + hr = IStream_Read(stream, &objref.u_objref.u_custom, + custom_header_size, &res); + if (hr || (res != custom_header_size)) + { + ERR("Failed to read OR_CUSTOM header, 0x%08lx\n", hr); + return STG_E_READFAULT; + } + /* now create the marshaler specified in the stream */ + hr = CoCreateInstance(&objref.u_objref.u_custom.clsid, NULL, + CLSCTX_INPROC_SERVER, &IID_IMarshal, + (LPVOID*)marshal); + } + else + { + FIXME("Invalid or unimplemented marshaling type specified: %lx\n", + objref.flags); + return RPC_E_INVALID_OBJREF; + } + + if (hr) + ERR("Failed to create marshal, 0x%08lx\n", hr); + + return hr; +} + +/*********************************************************************** + * CoGetMarshalSizeMax [OLE32.@] + * + * Gets the maximum amount of data that will be needed by a marshal. + * + * PARAMS + * pulSize [O] Address where maximum marshal size will be stored. + * riid [I] Identifier of the interface to marshal. + * pUnk [I] Pointer to the object to marshal. + * dwDestContext [I] Destination. Used to enable or disable optimizations. + * pvDestContext [I] Reserved. Must be NULL. + * mshlFlags [I] Flags that affect the marshaling. See CoMarshalInterface(). + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * SEE ALSO + * CoMarshalInterface(). + */ +HRESULT WINAPI CoGetMarshalSizeMax(ULONG *pulSize, REFIID riid, IUnknown *pUnk, + DWORD dwDestContext, void *pvDestContext, + DWORD mshlFlags) +{ + HRESULT hr; + LPMARSHAL pMarshal; + CLSID marshaler_clsid; + + hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal); + if (hr) + return hr; + + hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext, + pvDestContext, mshlFlags, &marshaler_clsid); + if (hr) + { + ERR("IMarshal::GetUnmarshalClass failed, 0x%08lx\n", hr); + IMarshal_Release(pMarshal); + return hr; + } + + hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext, + pvDestContext, mshlFlags, pulSize); + /* add on the size of the common header */ + *pulSize += FIELD_OFFSET(OBJREF, u_objref); + + /* if custom marshaling, add on size of custom header */ + if (!IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal)) + *pulSize += FIELD_OFFSET(OBJREF, u_objref.u_custom.pData) - + FIELD_OFFSET(OBJREF, u_objref.u_custom); + + IMarshal_Release(pMarshal); + return hr; +} + + +/*********************************************************************** + * CoMarshalInterface [OLE32.@] + * + * Marshals an interface into a stream so that the object can then be + * unmarshaled from another COM apartment and used remotely. + * + * PARAMS + * pStream [I] Stream the object will be marshaled into. + * riid [I] Identifier of the interface to marshal. + * pUnk [I] Pointer to the object to marshal. + * dwDestContext [I] Destination. Used to enable or disable optimizations. + * pvDestContext [I] Reserved. Must be NULL. + * mshlFlags [I] Flags that affect the marshaling. See notes. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * NOTES + * + * The mshlFlags parameter can take one or more of the following flags: + *| MSHLFLAGS_NORMAL - Unmarshal once, releases stub on last proxy release. + *| MSHLFLAGS_TABLESTRONG - Unmarshal many, release when CoReleaseMarshalData() called. + *| MSHLFLAGS_TABLEWEAK - Unmarshal many, releases stub on last proxy release. + *| MSHLFLAGS_NOPING - No automatic garbage collection (and so reduces network traffic). + * + * If a marshaled object is not unmarshaled, then CoReleaseMarshalData() must + * be called in order to release the resources used in the marshaling. + * + * SEE ALSO + * CoUnmarshalInterface(), CoReleaseMarshalData(). + */ +HRESULT WINAPI CoMarshalInterface(IStream *pStream, REFIID riid, IUnknown *pUnk, + DWORD dwDestContext, void *pvDestContext, + DWORD mshlFlags) +{ + HRESULT hr; + CLSID marshaler_clsid; + OBJREF objref; + LPMARSHAL pMarshal; + + TRACE("(%p, %s, %p, %lx, %p, %lx)\n", pStream, debugstr_guid(riid), pUnk, + dwDestContext, pvDestContext, mshlFlags); + + if (pUnk == NULL) + return E_INVALIDARG; + + objref.signature = OBJREF_SIGNATURE; + objref.iid = *riid; + + /* get the marshaler for the specified interface */ + hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal); + if (hr) + { + ERR("Failed to get marshaller, 0x%08lx\n", hr); + return hr; + } + + hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext, + pvDestContext, mshlFlags, &marshaler_clsid); + if (hr) + { + ERR("IMarshal::GetUnmarshalClass failed, 0x%08lx\n", hr); + goto cleanup; + } + + /* FIXME: implement handler marshaling too */ + if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal)) + { + TRACE("Using standard marshaling\n"); + objref.flags = OBJREF_STANDARD; + + /* write the common OBJREF header to the stream */ + hr = IStream_Write(pStream, &objref, FIELD_OFFSET(OBJREF, u_objref), NULL); + if (hr) + { + ERR("Failed to write OBJREF header to stream, 0x%08lx\n", hr); + goto cleanup; + } + } + else + { + TRACE("Using custom marshaling\n"); + objref.flags = OBJREF_CUSTOM; + objref.u_objref.u_custom.clsid = marshaler_clsid; + objref.u_objref.u_custom.cbExtension = 0; + objref.u_objref.u_custom.size = 0; + hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext, + pvDestContext, mshlFlags, + &objref.u_objref.u_custom.size); + if (hr) + { + ERR("Failed to get max size of marshal data, error 0x%08lx\n", hr); + goto cleanup; + } + /* write constant sized common header and OR_CUSTOM data into stream */ + hr = IStream_Write(pStream, &objref, + FIELD_OFFSET(OBJREF, u_objref.u_custom.pData), NULL); + if (hr) + { + ERR("Failed to write OR_CUSTOM header to stream with 0x%08lx\n", hr); + goto cleanup; + } + } + + TRACE("Calling IMarshal::MarshalInterace\n"); + /* call helper object to do the actual marshaling */ + hr = IMarshal_MarshalInterface(pMarshal, pStream, riid, pUnk, dwDestContext, + pvDestContext, mshlFlags); + + if (hr) + { + ERR("Failed to marshal the interface %s, %lx\n", debugstr_guid(riid), hr); + goto cleanup; + } + +cleanup: + IMarshal_Release(pMarshal); + + TRACE("completed with hr 0x%08lx\n", hr); + + return hr; +} + +/*********************************************************************** + * CoUnmarshalInterface [OLE32.@] + * + * Unmarshals an object from a stream by creating a proxy to the remote + * object, if necessary. + * + * PARAMS + * + * pStream [I] Stream containing the marshaled object. + * riid [I] Interface identifier of the object to create a proxy to. + * ppv [O] Address where proxy will be stored. + * + * RETURNS + * + * Success: S_OK. + * Failure: HRESULT code. + * + * SEE ALSO + * CoMarshalInterface(). + */ +HRESULT WINAPI CoUnmarshalInterface(IStream *pStream, REFIID riid, LPVOID *ppv) +{ + HRESULT hr; + LPMARSHAL pMarshal; + IID iid; + IUnknown *object; + + TRACE("(%p, %s, %p)\n", pStream, debugstr_guid(riid), ppv); + + hr = get_unmarshaler_from_stream(pStream, &pMarshal, &iid); + if (hr != S_OK) + return hr; + + /* call the helper object to do the actual unmarshaling */ + hr = IMarshal_UnmarshalInterface(pMarshal, pStream, &iid, (LPVOID*)&object); + if (hr) + ERR("IMarshal::UnmarshalInterface failed, 0x%08lx\n", hr); + + /* IID_NULL means use the interface ID of the marshaled object */ + if (!IsEqualIID(riid, &IID_NULL)) + iid = *riid; + + if (hr == S_OK) + { + if (!IsEqualIID(riid, &iid)) + { + TRACE("requested interface != marshalled interface, additional QI needed\n"); + hr = IUnknown_QueryInterface(object, &iid, ppv); + if (hr) + ERR("Couldn't query for interface %s, hr = 0x%08lx\n", + debugstr_guid(riid), hr); + IUnknown_Release(object); + } + else + { + *ppv = object; + } + } + + IMarshal_Release(pMarshal); + + TRACE("completed with hr 0x%lx\n", hr); + + return hr; +} + +/*********************************************************************** + * CoReleaseMarshalData [OLE32.@] + * + * Releases resources associated with an object that has been marshaled into + * a stream. + * + * PARAMS + * + * pStream [I] The stream that the object has been marshaled into. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT error code. + * + * NOTES + * + * Call this function to release resources associated with a normal or + * table-weak marshal that will not be unmarshaled, and all table-strong + * marshals when they are no longer needed. + * + * SEE ALSO + * CoMarshalInterface(), CoUnmarshalInterface(). + */ +HRESULT WINAPI CoReleaseMarshalData(IStream *pStream) +{ + HRESULT hr; + LPMARSHAL pMarshal; + + TRACE("(%p)\n", pStream); + + hr = get_unmarshaler_from_stream(pStream, &pMarshal, NULL); + if (hr != S_OK) + return hr; + + /* call the helper object to do the releasing of marshal data */ + hr = IMarshal_ReleaseMarshalData(pMarshal, pStream); + if (hr) + ERR("IMarshal::ReleaseMarshalData failed with error 0x%08lx\n", hr); + + IMarshal_Release(pMarshal); + return hr; +} + + +/*********************************************************************** + * CoMarshalInterThreadInterfaceInStream [OLE32.@] + * + * Marshal an interface across threads in the same process. + * + * PARAMS + * riid [I] Identifier of the interface to be marshalled. + * pUnk [I] Pointer to IUnknown-derived interface that will be marshalled. + * ppStm [O] Pointer to IStream object that is created and then used to store the marshalled inteface. + * + * RETURNS + * Success: S_OK + * Failure: E_OUTOFMEMORY and other COM error codes + * + * SEE ALSO + * CoMarshalInterface(), CoUnmarshalInterface() and CoGetInterfaceAndReleaseStream() + */ +HRESULT WINAPI CoMarshalInterThreadInterfaceInStream( + REFIID riid, LPUNKNOWN pUnk, LPSTREAM * ppStm) +{ + ULARGE_INTEGER xpos; + LARGE_INTEGER seekto; + HRESULT hres; + + TRACE("(%s, %p, %p)\n",debugstr_guid(riid), pUnk, ppStm); + + hres = CreateStreamOnHGlobal(0, TRUE, ppStm); + if (FAILED(hres)) return hres; + hres = CoMarshalInterface(*ppStm, riid, pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + + /* FIXME: is this needed? */ + memset(&seekto,0,sizeof(seekto)); + IStream_Seek(*ppStm,seekto,SEEK_SET,&xpos); + + return hres; +} + +/*********************************************************************** + * CoGetInterfaceAndReleaseStream [OLE32.@] + * + * Unmarshalls an inteface from a stream and then releases the stream. + * + * PARAMS + * pStm [I] Stream that contains the marshalled inteface. + * riid [I] Interface identifier of the object to unmarshall. + * ppv [O] Address of pointer where the requested interface object will be stored. + * + * RETURNS + * Success: S_OK + * Failure: A COM error code + * + * SEE ALSO + * CoMarshalInterThreadInterfaceInStream() and CoUnmarshalInteface() + */ +HRESULT WINAPI CoGetInterfaceAndReleaseStream(LPSTREAM pStm, REFIID riid, + LPVOID *ppv) +{ + HRESULT hres; + + TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv); + + hres = CoUnmarshalInterface(pStm, riid, ppv); + IStream_Release(pStm); + return hres; +} + +static HRESULT WINAPI StdMarshalCF_QueryInterface(LPCLASSFACTORY iface, + REFIID riid, LPVOID *ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) + { + *ppv = (LPVOID)iface; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI StdMarshalCF_AddRef(LPCLASSFACTORY iface) +{ + return 2; /* non-heap based object */ +} + +static ULONG WINAPI StdMarshalCF_Release(LPCLASSFACTORY iface) +{ + return 1; /* non-heap based object */ +} + +static HRESULT WINAPI StdMarshalCF_CreateInstance(LPCLASSFACTORY iface, + LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv) +{ + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IMarshal)) + return StdMarshalImpl_Construct(riid, ppv); + + FIXME("(%s), not supported.\n",debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static HRESULT WINAPI StdMarshalCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) +{ + FIXME("(%d), stub!\n",fLock); + return S_OK; +} + +static const IClassFactoryVtbl StdMarshalCFVtbl = +{ + StdMarshalCF_QueryInterface, + StdMarshalCF_AddRef, + StdMarshalCF_Release, + StdMarshalCF_CreateInstance, + StdMarshalCF_LockServer +}; +static const IClassFactoryVtbl *StdMarshalCF = &StdMarshalCFVtbl; + +HRESULT MARSHAL_GetStandardMarshalCF(LPVOID *ppv) +{ + *ppv = &StdMarshalCF; + return S_OK; +} + +/*********************************************************************** + * CoMarshalHresult [OLE32.@] + * + * Marshals an HRESULT value into a stream. + * + * PARAMS + * pStm [I] Stream that hresult will be marshalled into. + * hresult [I] HRESULT to be marshalled. + * + * RETURNS + * Success: S_OK + * Failure: A COM error code + * + * SEE ALSO + * CoUnmarshalHresult(). + */ +HRESULT WINAPI CoMarshalHresult(LPSTREAM pStm, HRESULT hresult) +{ + return IStream_Write(pStm, &hresult, sizeof(hresult), NULL); +} + +/*********************************************************************** + * CoUnmarshalHresult [OLE32.@] + * + * Unmarshals an HRESULT value from a stream. + * + * PARAMS + * pStm [I] Stream that hresult will be unmarshalled from. + * phresult [I] Pointer to HRESULT where the value will be unmarshalled to. + * + * RETURNS + * Success: S_OK + * Failure: A COM error code + * + * SEE ALSO + * CoMarshalHresult(). + */ +HRESULT WINAPI CoUnmarshalHresult(LPSTREAM pStm, HRESULT * phresult) +{ + return IStream_Read(pStm, phresult, sizeof(*phresult), NULL); +} diff --git a/reactos/lib/ole32/memlockbytes.c b/reactos/lib/ole32/memlockbytes.c index c0431e83f7c..7d7fae56d95 100644 --- a/reactos/lib/ole32/memlockbytes.c +++ b/reactos/lib/ole32/memlockbytes.c @@ -1,619 +1,619 @@ -/****************************************************************************** - * - * Global memory implementation of ILockBytes. - * - * Copyright 1999 Thuy Nguyen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <assert.h> -#include <stdarg.h> -#include <string.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "objbase.h" -#include "ole2.h" -#include "winerror.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/****************************************************************************** - * HGLOBALLockBytesImpl definition. - * - * This class imlements the ILockBytes inteface and represents a byte array - * object supported by an HGLOBAL pointer. - */ -struct HGLOBALLockBytesImpl -{ - /* - * Needs to be the first item in the struct - * since we want to cast this in an ILockBytes pointer - */ - ILockBytesVtbl *lpVtbl; - - /* - * Reference count - */ - ULONG ref; - - /* - * Support for the LockBytes object - */ - HGLOBAL supportHandle; - - /* - * This flag is TRUE if the HGLOBAL is destroyed when the object - * is finally released. - */ - BOOL deleteOnRelease; - - /* - * Helper variable that contains the size of the byte array - */ - ULARGE_INTEGER byteArraySize; -}; - -typedef struct HGLOBALLockBytesImpl HGLOBALLockBytesImpl; - -/* - * Method definition for the HGLOBALLockBytesImpl class. - */ -HGLOBALLockBytesImpl* HGLOBALLockBytesImpl_Construct( - HGLOBAL hGlobal, - BOOL fDeleteOnRelease); - -void HGLOBALLockBytesImpl_Destroy(HGLOBALLockBytesImpl* This); - -HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface( - ILockBytes* iface, - REFIID riid, /* [in] */ - void** ppvObject); /* [iid_is][out] */ - -ULONG WINAPI HGLOBALLockBytesImpl_AddRef( - ILockBytes* iface); - -ULONG WINAPI HGLOBALLockBytesImpl_Release( - ILockBytes* iface); - -HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt( - ILockBytes* iface, - ULARGE_INTEGER ulOffset, /* [in] */ - void* pv, /* [length_is][size_is][out] */ - ULONG cb, /* [in] */ - ULONG* pcbRead); /* [out] */ - -HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt( - ILockBytes* iface, - ULARGE_INTEGER ulOffset, /* [in] */ - const void* pv, /* [size_is][in] */ - ULONG cb, /* [in] */ - ULONG* pcbWritten); /* [out] */ - -HRESULT WINAPI HGLOBALLockBytesImpl_Flush( - ILockBytes* iface); - -HRESULT WINAPI HGLOBALLockBytesImpl_SetSize( - ILockBytes* iface, - ULARGE_INTEGER libNewSize); /* [in] */ - -HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion( - ILockBytes* iface, - ULARGE_INTEGER libOffset, /* [in] */ - ULARGE_INTEGER cb, /* [in] */ - DWORD dwLockType); /* [in] */ - -HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion( - ILockBytes* iface, - ULARGE_INTEGER libOffset, /* [in] */ - ULARGE_INTEGER cb, /* [in] */ - DWORD dwLockType); /* [in] */ - -HRESULT WINAPI HGLOBALLockBytesImpl_Stat( - ILockBytes* iface, - STATSTG* pstatstg, /* [out] */ - DWORD grfStatFlag); /* [in] */ - -/* - * Virtual function table for the HGLOBALLockBytesImpl class. - */ -static ILockBytesVtbl HGLOBALLockBytesImpl_Vtbl = -{ - HGLOBALLockBytesImpl_QueryInterface, - HGLOBALLockBytesImpl_AddRef, - HGLOBALLockBytesImpl_Release, - HGLOBALLockBytesImpl_ReadAt, - HGLOBALLockBytesImpl_WriteAt, - HGLOBALLockBytesImpl_Flush, - HGLOBALLockBytesImpl_SetSize, - HGLOBALLockBytesImpl_LockRegion, - HGLOBALLockBytesImpl_UnlockRegion, - HGLOBALLockBytesImpl_Stat, -}; - -/****************************************************************************** - * CreateILockBytesOnHGlobal [OLE32.@] - */ -HRESULT WINAPI CreateILockBytesOnHGlobal(HGLOBAL hGlobal, - BOOL fDeleteOnRelease, - LPLOCKBYTES* ppLkbyt) -{ - HGLOBALLockBytesImpl* newLockBytes; - - newLockBytes = HGLOBALLockBytesImpl_Construct(hGlobal, fDeleteOnRelease); - - if (newLockBytes != NULL) - { - return IUnknown_QueryInterface((IUnknown*)newLockBytes, - &IID_ILockBytes, - (void**)ppLkbyt); - } - - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * GetHGlobalFromILockBytes [OLE32.@] - */ -HRESULT WINAPI GetHGlobalFromILockBytes(ILockBytes* plkbyt, HGLOBAL* phglobal) -{ - HGLOBALLockBytesImpl* const pMemLockBytes = (HGLOBALLockBytesImpl*)plkbyt; - STATSTG stbuf; - HRESULT hres; - ULARGE_INTEGER start; - ULONG xread; - - *phglobal = 0; - if (pMemLockBytes->lpVtbl == &HGLOBALLockBytesImpl_Vtbl) { - *phglobal = pMemLockBytes->supportHandle; - if (*phglobal == 0) - return E_INVALIDARG; - return S_OK; - } - /* It is not our lockbytes implementation, so use a more generic way */ - hres = ILockBytes_Stat(plkbyt,&stbuf,0); - if (hres != S_OK) { - ERR("Cannot ILockBytes_Stat, %lx\n",hres); - return hres; - } - FIXME("cbSize is %ld\n",stbuf.cbSize.u.LowPart); - *phglobal = GlobalAlloc( GMEM_MOVEABLE|GMEM_SHARE, stbuf.cbSize.u.LowPart); - if (!*phglobal) - return E_INVALIDARG; - memset(&start,0,sizeof(start)); - hres = ILockBytes_ReadAt(plkbyt, start, GlobalLock(*phglobal), stbuf.cbSize.u.LowPart, &xread); - GlobalUnlock(*phglobal); - if (hres != S_OK) { - FIXME("%p->ReadAt failed with %lx\n",plkbyt,hres); - return hres; - } - if (stbuf.cbSize.u.LowPart != xread) { - FIXME("Read size is not requested size %ld vs %ld?\n",stbuf.cbSize.u.LowPart, xread); - } - return S_OK; -} - -/****************************************************************************** - * - * HGLOBALLockBytesImpl implementation - * - */ - -/****************************************************************************** - * This is the constructor for the HGLOBALLockBytesImpl class. - * - * Params: - * hGlobal - Handle that will support the stream. can be NULL. - * fDeleteOnRelease - Flag set to TRUE if the HGLOBAL will be released - * when the IStream object is destroyed. - */ -HGLOBALLockBytesImpl* HGLOBALLockBytesImpl_Construct(HGLOBAL hGlobal, - BOOL fDeleteOnRelease) -{ - HGLOBALLockBytesImpl* newLockBytes; - newLockBytes = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALLockBytesImpl)); - - if (newLockBytes!=0) - { - /* - * Set up the virtual function table and reference count. - */ - newLockBytes->lpVtbl = &HGLOBALLockBytesImpl_Vtbl; - newLockBytes->ref = 0; - - /* - * Initialize the support. - */ - newLockBytes->supportHandle = hGlobal; - newLockBytes->deleteOnRelease = fDeleteOnRelease; - - /* - * This method will allocate a handle if one is not supplied. - */ - if (newLockBytes->supportHandle == 0) - { - newLockBytes->supportHandle = GlobalAlloc(GMEM_MOVEABLE | - GMEM_NODISCARD, - 0); - } - - /* - * Initialize the size of the array to the size of the handle. - */ - newLockBytes->byteArraySize.u.HighPart = 0; - newLockBytes->byteArraySize.u.LowPart = GlobalSize( - newLockBytes->supportHandle); - } - - return newLockBytes; -} - -/****************************************************************************** - * This is the destructor of the HGLOBALStreamImpl class. - * - * This method will clean-up all the resources used-up by the given - * HGLOBALLockBytesImpl class. The pointer passed-in to this function will be - * freed and will not be valid anymore. - */ -void HGLOBALLockBytesImpl_Destroy(HGLOBALLockBytesImpl* This) -{ - /* - * Release the HGlobal if the constructor asked for that. - */ - if (This->deleteOnRelease) - { - GlobalFree(This->supportHandle); - This->supportHandle = 0; - } - - /* - * Finally, free the memory used-up by the class. - */ - HeapFree(GetProcessHeap(), 0, This); -} - -/****************************************************************************** - * This implements the IUnknown method QueryInterface for this - * class - */ -HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface( - ILockBytes* iface, - REFIID riid, /* [in] */ - void** ppvObject) /* [iid_is][out] */ -{ - HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface; - - /* - * Perform a sanity check on the parameters. - */ - if (ppvObject==0) - return E_INVALIDARG; - - /* - * Initialize the return parameter. - */ - *ppvObject = 0; - - /* - * Compare the riid with the interface IDs implemented by this object. - */ - if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) - { - *ppvObject = (ILockBytes*)This; - } - else if (memcmp(&IID_ILockBytes, riid, sizeof(IID_ILockBytes)) == 0) - { - *ppvObject = (ILockBytes*)This; - } - - /* - * Check that we obtained an interface. - */ - if ((*ppvObject)==0) - return E_NOINTERFACE; - - /* - * Query Interface always increases the reference count by one when it is - * successful - */ - HGLOBALLockBytesImpl_AddRef(iface); - - return S_OK; -} - -/****************************************************************************** - * This implements the IUnknown method AddRef for this - * class - */ -ULONG WINAPI HGLOBALLockBytesImpl_AddRef(ILockBytes* iface) -{ - HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface; - return InterlockedIncrement(&This->ref); -} - -/****************************************************************************** - * This implements the IUnknown method Release for this - * class - */ -ULONG WINAPI HGLOBALLockBytesImpl_Release(ILockBytes* iface) -{ - HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface; - ULONG ref; - - ref = InterlockedDecrement(&This->ref); - - /* - * If the reference count goes down to 0, perform suicide. - */ - if (ref==0) - { - HGLOBALLockBytesImpl_Destroy(This); - } - - return ref; -} - -/****************************************************************************** - * This method is part of the ILockBytes interface. - * - * It reads a block of information from the byte array at the specified - * offset. - * - * See the documentation of ILockBytes for more info. - */ -HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt( - ILockBytes* iface, - ULARGE_INTEGER ulOffset, /* [in] */ - void* pv, /* [length_is][size_is][out] */ - ULONG cb, /* [in] */ - ULONG* pcbRead) /* [out] */ -{ - HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface; - - void* supportBuffer; - ULONG bytesReadBuffer = 0; - ULONG bytesToReadFromBuffer; - - /* - * If the caller is not interested in the number of bytes read, - * we use another buffer to avoid "if" statements in the code. - */ - if (pcbRead == 0) - pcbRead = &bytesReadBuffer; - - /* - * Make sure the offset is valid. - */ - if (ulOffset.u.LowPart > This->byteArraySize.u.LowPart) - return E_FAIL; - - /* - * Using the known size of the array, calculate the number of bytes - * to read. - */ - bytesToReadFromBuffer = min(This->byteArraySize.u.LowPart - - ulOffset.u.LowPart, cb); - - /* - * Lock the buffer in position and copy the data. - */ - supportBuffer = GlobalLock(This->supportHandle); - - memcpy(pv, - (char *) supportBuffer + ulOffset.u.LowPart, - bytesToReadFromBuffer); - - /* - * Return the number of bytes read. - */ - *pcbRead = bytesToReadFromBuffer; - - /* - * Cleanup - */ - GlobalUnlock(This->supportHandle); - - /* - * The function returns S_OK if the specified number of bytes were read - * or the end of the array was reached. - * It returns STG_E_READFAULT if the number of bytes to read does not equal - * the number of bytes actually read. - */ - if(*pcbRead == cb) - return S_OK; - - return STG_E_READFAULT; -} - -/****************************************************************************** - * This method is part of the ILockBytes interface. - * - * It writes the specified bytes at the specified offset. - * position. If the array is too small, it will be resized. - * - * See the documentation of ILockBytes for more info. - */ -HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt( - ILockBytes* iface, - ULARGE_INTEGER ulOffset, /* [in] */ - const void* pv, /* [size_is][in] */ - ULONG cb, /* [in] */ - ULONG* pcbWritten) /* [out] */ -{ - HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface; - - void* supportBuffer; - ULARGE_INTEGER newSize; - ULONG bytesWritten = 0; - - /* - * If the caller is not interested in the number of bytes written, - * we use another buffer to avoid "if" statements in the code. - */ - if (pcbWritten == 0) - pcbWritten = &bytesWritten; - - if (cb == 0) - { - return S_OK; - } - else - { - newSize.u.HighPart = 0; - newSize.u.LowPart = ulOffset.u.LowPart + cb; - } - - /* - * Verify if we need to grow the stream - */ - if (newSize.u.LowPart > This->byteArraySize.u.LowPart) - { - /* grow stream */ - if (HGLOBALLockBytesImpl_SetSize(iface, newSize) == STG_E_MEDIUMFULL) - return STG_E_MEDIUMFULL; - } - - /* - * Lock the buffer in position and copy the data. - */ - supportBuffer = GlobalLock(This->supportHandle); - - memcpy((char *) supportBuffer + ulOffset.u.LowPart, pv, cb); - - /* - * Return the number of bytes written. - */ - *pcbWritten = cb; - - /* - * Cleanup - */ - GlobalUnlock(This->supportHandle); - - return S_OK; -} - -/****************************************************************************** - * This method is part of the ILockBytes interface. - * - * See the documentation of ILockBytes for more info. - */ -HRESULT WINAPI HGLOBALLockBytesImpl_Flush(ILockBytes* iface) -{ - return S_OK; -} - -/****************************************************************************** - * This method is part of the ILockBytes interface. - * - * It will change the size of the byte array. - * - * See the documentation of ILockBytes for more info. - */ -HRESULT WINAPI HGLOBALLockBytesImpl_SetSize( - ILockBytes* iface, - ULARGE_INTEGER libNewSize) /* [in] */ -{ - HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface; - HGLOBAL supportHandle; - - /* - * As documented. - */ - if (libNewSize.u.HighPart != 0) - return STG_E_INVALIDFUNCTION; - - if (This->byteArraySize.u.LowPart == libNewSize.u.LowPart) - return S_OK; - - /* - * Re allocate the HGlobal to fit the new size of the stream. - */ - supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0); - - if (supportHandle == 0) - return STG_E_MEDIUMFULL; - - This->supportHandle = supportHandle; - This->byteArraySize.u.LowPart = libNewSize.u.LowPart; - - return S_OK; -} - -/****************************************************************************** - * This method is part of the ILockBytes interface. - * - * The global memory implementation of ILockBytes does not support locking. - * - * See the documentation of ILockBytes for more info. - */ -HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion( - ILockBytes* iface, - ULARGE_INTEGER libOffset, /* [in] */ - ULARGE_INTEGER cb, /* [in] */ - DWORD dwLockType) /* [in] */ -{ - return STG_E_INVALIDFUNCTION; -} - -/****************************************************************************** - * This method is part of the ILockBytes interface. - * - * The global memory implementation of ILockBytes does not support locking. - * - * See the documentation of ILockBytes for more info. - */ -HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion( - ILockBytes* iface, - ULARGE_INTEGER libOffset, /* [in] */ - ULARGE_INTEGER cb, /* [in] */ - DWORD dwLockType) /* [in] */ -{ - return STG_E_INVALIDFUNCTION; -} - -/****************************************************************************** - * This method is part of the ILockBytes interface. - * - * This method returns information about the current - * byte array object. - * - * See the documentation of ILockBytes for more info. - */ -HRESULT WINAPI HGLOBALLockBytesImpl_Stat( - ILockBytes* iface, - STATSTG* pstatstg, /* [out] */ - DWORD grfStatFlag) /* [in] */ -{ - HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface; - - memset(pstatstg, 0, sizeof(STATSTG)); - - pstatstg->pwcsName = NULL; - pstatstg->type = STGTY_LOCKBYTES; - pstatstg->cbSize = This->byteArraySize; - - return S_OK; -} +/****************************************************************************** + * + * Global memory implementation of ILockBytes. + * + * Copyright 1999 Thuy Nguyen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <assert.h> +#include <stdarg.h> +#include <string.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "objbase.h" +#include "ole2.h" +#include "winerror.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/****************************************************************************** + * HGLOBALLockBytesImpl definition. + * + * This class imlements the ILockBytes inteface and represents a byte array + * object supported by an HGLOBAL pointer. + */ +struct HGLOBALLockBytesImpl +{ + /* + * Needs to be the first item in the struct + * since we want to cast this in an ILockBytes pointer + */ + ILockBytesVtbl *lpVtbl; + + /* + * Reference count + */ + ULONG ref; + + /* + * Support for the LockBytes object + */ + HGLOBAL supportHandle; + + /* + * This flag is TRUE if the HGLOBAL is destroyed when the object + * is finally released. + */ + BOOL deleteOnRelease; + + /* + * Helper variable that contains the size of the byte array + */ + ULARGE_INTEGER byteArraySize; +}; + +typedef struct HGLOBALLockBytesImpl HGLOBALLockBytesImpl; + +/* + * Method definition for the HGLOBALLockBytesImpl class. + */ +HGLOBALLockBytesImpl* HGLOBALLockBytesImpl_Construct( + HGLOBAL hGlobal, + BOOL fDeleteOnRelease); + +void HGLOBALLockBytesImpl_Destroy(HGLOBALLockBytesImpl* This); + +HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface( + ILockBytes* iface, + REFIID riid, /* [in] */ + void** ppvObject); /* [iid_is][out] */ + +ULONG WINAPI HGLOBALLockBytesImpl_AddRef( + ILockBytes* iface); + +ULONG WINAPI HGLOBALLockBytesImpl_Release( + ILockBytes* iface); + +HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt( + ILockBytes* iface, + ULARGE_INTEGER ulOffset, /* [in] */ + void* pv, /* [length_is][size_is][out] */ + ULONG cb, /* [in] */ + ULONG* pcbRead); /* [out] */ + +HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt( + ILockBytes* iface, + ULARGE_INTEGER ulOffset, /* [in] */ + const void* pv, /* [size_is][in] */ + ULONG cb, /* [in] */ + ULONG* pcbWritten); /* [out] */ + +HRESULT WINAPI HGLOBALLockBytesImpl_Flush( + ILockBytes* iface); + +HRESULT WINAPI HGLOBALLockBytesImpl_SetSize( + ILockBytes* iface, + ULARGE_INTEGER libNewSize); /* [in] */ + +HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion( + ILockBytes* iface, + ULARGE_INTEGER libOffset, /* [in] */ + ULARGE_INTEGER cb, /* [in] */ + DWORD dwLockType); /* [in] */ + +HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion( + ILockBytes* iface, + ULARGE_INTEGER libOffset, /* [in] */ + ULARGE_INTEGER cb, /* [in] */ + DWORD dwLockType); /* [in] */ + +HRESULT WINAPI HGLOBALLockBytesImpl_Stat( + ILockBytes* iface, + STATSTG* pstatstg, /* [out] */ + DWORD grfStatFlag); /* [in] */ + +/* + * Virtual function table for the HGLOBALLockBytesImpl class. + */ +static ILockBytesVtbl HGLOBALLockBytesImpl_Vtbl = +{ + HGLOBALLockBytesImpl_QueryInterface, + HGLOBALLockBytesImpl_AddRef, + HGLOBALLockBytesImpl_Release, + HGLOBALLockBytesImpl_ReadAt, + HGLOBALLockBytesImpl_WriteAt, + HGLOBALLockBytesImpl_Flush, + HGLOBALLockBytesImpl_SetSize, + HGLOBALLockBytesImpl_LockRegion, + HGLOBALLockBytesImpl_UnlockRegion, + HGLOBALLockBytesImpl_Stat, +}; + +/****************************************************************************** + * CreateILockBytesOnHGlobal [OLE32.@] + */ +HRESULT WINAPI CreateILockBytesOnHGlobal(HGLOBAL hGlobal, + BOOL fDeleteOnRelease, + LPLOCKBYTES* ppLkbyt) +{ + HGLOBALLockBytesImpl* newLockBytes; + + newLockBytes = HGLOBALLockBytesImpl_Construct(hGlobal, fDeleteOnRelease); + + if (newLockBytes != NULL) + { + return IUnknown_QueryInterface((IUnknown*)newLockBytes, + &IID_ILockBytes, + (void**)ppLkbyt); + } + + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * GetHGlobalFromILockBytes [OLE32.@] + */ +HRESULT WINAPI GetHGlobalFromILockBytes(ILockBytes* plkbyt, HGLOBAL* phglobal) +{ + HGLOBALLockBytesImpl* const pMemLockBytes = (HGLOBALLockBytesImpl*)plkbyt; + STATSTG stbuf; + HRESULT hres; + ULARGE_INTEGER start; + ULONG xread; + + *phglobal = 0; + if (pMemLockBytes->lpVtbl == &HGLOBALLockBytesImpl_Vtbl) { + *phglobal = pMemLockBytes->supportHandle; + if (*phglobal == 0) + return E_INVALIDARG; + return S_OK; + } + /* It is not our lockbytes implementation, so use a more generic way */ + hres = ILockBytes_Stat(plkbyt,&stbuf,0); + if (hres != S_OK) { + ERR("Cannot ILockBytes_Stat, %lx\n",hres); + return hres; + } + FIXME("cbSize is %ld\n",stbuf.cbSize.u.LowPart); + *phglobal = GlobalAlloc( GMEM_MOVEABLE|GMEM_SHARE, stbuf.cbSize.u.LowPart); + if (!*phglobal) + return E_INVALIDARG; + memset(&start,0,sizeof(start)); + hres = ILockBytes_ReadAt(plkbyt, start, GlobalLock(*phglobal), stbuf.cbSize.u.LowPart, &xread); + GlobalUnlock(*phglobal); + if (hres != S_OK) { + FIXME("%p->ReadAt failed with %lx\n",plkbyt,hres); + return hres; + } + if (stbuf.cbSize.u.LowPart != xread) { + FIXME("Read size is not requested size %ld vs %ld?\n",stbuf.cbSize.u.LowPart, xread); + } + return S_OK; +} + +/****************************************************************************** + * + * HGLOBALLockBytesImpl implementation + * + */ + +/****************************************************************************** + * This is the constructor for the HGLOBALLockBytesImpl class. + * + * Params: + * hGlobal - Handle that will support the stream. can be NULL. + * fDeleteOnRelease - Flag set to TRUE if the HGLOBAL will be released + * when the IStream object is destroyed. + */ +HGLOBALLockBytesImpl* HGLOBALLockBytesImpl_Construct(HGLOBAL hGlobal, + BOOL fDeleteOnRelease) +{ + HGLOBALLockBytesImpl* newLockBytes; + newLockBytes = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALLockBytesImpl)); + + if (newLockBytes!=0) + { + /* + * Set up the virtual function table and reference count. + */ + newLockBytes->lpVtbl = &HGLOBALLockBytesImpl_Vtbl; + newLockBytes->ref = 0; + + /* + * Initialize the support. + */ + newLockBytes->supportHandle = hGlobal; + newLockBytes->deleteOnRelease = fDeleteOnRelease; + + /* + * This method will allocate a handle if one is not supplied. + */ + if (newLockBytes->supportHandle == 0) + { + newLockBytes->supportHandle = GlobalAlloc(GMEM_MOVEABLE | + GMEM_NODISCARD, + 0); + } + + /* + * Initialize the size of the array to the size of the handle. + */ + newLockBytes->byteArraySize.u.HighPart = 0; + newLockBytes->byteArraySize.u.LowPart = GlobalSize( + newLockBytes->supportHandle); + } + + return newLockBytes; +} + +/****************************************************************************** + * This is the destructor of the HGLOBALStreamImpl class. + * + * This method will clean-up all the resources used-up by the given + * HGLOBALLockBytesImpl class. The pointer passed-in to this function will be + * freed and will not be valid anymore. + */ +void HGLOBALLockBytesImpl_Destroy(HGLOBALLockBytesImpl* This) +{ + /* + * Release the HGlobal if the constructor asked for that. + */ + if (This->deleteOnRelease) + { + GlobalFree(This->supportHandle); + This->supportHandle = 0; + } + + /* + * Finally, free the memory used-up by the class. + */ + HeapFree(GetProcessHeap(), 0, This); +} + +/****************************************************************************** + * This implements the IUnknown method QueryInterface for this + * class + */ +HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface( + ILockBytes* iface, + REFIID riid, /* [in] */ + void** ppvObject) /* [iid_is][out] */ +{ + HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface; + + /* + * Perform a sanity check on the parameters. + */ + if (ppvObject==0) + return E_INVALIDARG; + + /* + * Initialize the return parameter. + */ + *ppvObject = 0; + + /* + * Compare the riid with the interface IDs implemented by this object. + */ + if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) + { + *ppvObject = (ILockBytes*)This; + } + else if (memcmp(&IID_ILockBytes, riid, sizeof(IID_ILockBytes)) == 0) + { + *ppvObject = (ILockBytes*)This; + } + + /* + * Check that we obtained an interface. + */ + if ((*ppvObject)==0) + return E_NOINTERFACE; + + /* + * Query Interface always increases the reference count by one when it is + * successful + */ + HGLOBALLockBytesImpl_AddRef(iface); + + return S_OK; +} + +/****************************************************************************** + * This implements the IUnknown method AddRef for this + * class + */ +ULONG WINAPI HGLOBALLockBytesImpl_AddRef(ILockBytes* iface) +{ + HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface; + return InterlockedIncrement(&This->ref); +} + +/****************************************************************************** + * This implements the IUnknown method Release for this + * class + */ +ULONG WINAPI HGLOBALLockBytesImpl_Release(ILockBytes* iface) +{ + HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface; + ULONG ref; + + ref = InterlockedDecrement(&This->ref); + + /* + * If the reference count goes down to 0, perform suicide. + */ + if (ref==0) + { + HGLOBALLockBytesImpl_Destroy(This); + } + + return ref; +} + +/****************************************************************************** + * This method is part of the ILockBytes interface. + * + * It reads a block of information from the byte array at the specified + * offset. + * + * See the documentation of ILockBytes for more info. + */ +HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt( + ILockBytes* iface, + ULARGE_INTEGER ulOffset, /* [in] */ + void* pv, /* [length_is][size_is][out] */ + ULONG cb, /* [in] */ + ULONG* pcbRead) /* [out] */ +{ + HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface; + + void* supportBuffer; + ULONG bytesReadBuffer = 0; + ULONG bytesToReadFromBuffer; + + /* + * If the caller is not interested in the number of bytes read, + * we use another buffer to avoid "if" statements in the code. + */ + if (pcbRead == 0) + pcbRead = &bytesReadBuffer; + + /* + * Make sure the offset is valid. + */ + if (ulOffset.u.LowPart > This->byteArraySize.u.LowPart) + return E_FAIL; + + /* + * Using the known size of the array, calculate the number of bytes + * to read. + */ + bytesToReadFromBuffer = min(This->byteArraySize.u.LowPart - + ulOffset.u.LowPart, cb); + + /* + * Lock the buffer in position and copy the data. + */ + supportBuffer = GlobalLock(This->supportHandle); + + memcpy(pv, + (char *) supportBuffer + ulOffset.u.LowPart, + bytesToReadFromBuffer); + + /* + * Return the number of bytes read. + */ + *pcbRead = bytesToReadFromBuffer; + + /* + * Cleanup + */ + GlobalUnlock(This->supportHandle); + + /* + * The function returns S_OK if the specified number of bytes were read + * or the end of the array was reached. + * It returns STG_E_READFAULT if the number of bytes to read does not equal + * the number of bytes actually read. + */ + if(*pcbRead == cb) + return S_OK; + + return STG_E_READFAULT; +} + +/****************************************************************************** + * This method is part of the ILockBytes interface. + * + * It writes the specified bytes at the specified offset. + * position. If the array is too small, it will be resized. + * + * See the documentation of ILockBytes for more info. + */ +HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt( + ILockBytes* iface, + ULARGE_INTEGER ulOffset, /* [in] */ + const void* pv, /* [size_is][in] */ + ULONG cb, /* [in] */ + ULONG* pcbWritten) /* [out] */ +{ + HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface; + + void* supportBuffer; + ULARGE_INTEGER newSize; + ULONG bytesWritten = 0; + + /* + * If the caller is not interested in the number of bytes written, + * we use another buffer to avoid "if" statements in the code. + */ + if (pcbWritten == 0) + pcbWritten = &bytesWritten; + + if (cb == 0) + { + return S_OK; + } + else + { + newSize.u.HighPart = 0; + newSize.u.LowPart = ulOffset.u.LowPart + cb; + } + + /* + * Verify if we need to grow the stream + */ + if (newSize.u.LowPart > This->byteArraySize.u.LowPart) + { + /* grow stream */ + if (HGLOBALLockBytesImpl_SetSize(iface, newSize) == STG_E_MEDIUMFULL) + return STG_E_MEDIUMFULL; + } + + /* + * Lock the buffer in position and copy the data. + */ + supportBuffer = GlobalLock(This->supportHandle); + + memcpy((char *) supportBuffer + ulOffset.u.LowPart, pv, cb); + + /* + * Return the number of bytes written. + */ + *pcbWritten = cb; + + /* + * Cleanup + */ + GlobalUnlock(This->supportHandle); + + return S_OK; +} + +/****************************************************************************** + * This method is part of the ILockBytes interface. + * + * See the documentation of ILockBytes for more info. + */ +HRESULT WINAPI HGLOBALLockBytesImpl_Flush(ILockBytes* iface) +{ + return S_OK; +} + +/****************************************************************************** + * This method is part of the ILockBytes interface. + * + * It will change the size of the byte array. + * + * See the documentation of ILockBytes for more info. + */ +HRESULT WINAPI HGLOBALLockBytesImpl_SetSize( + ILockBytes* iface, + ULARGE_INTEGER libNewSize) /* [in] */ +{ + HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface; + HGLOBAL supportHandle; + + /* + * As documented. + */ + if (libNewSize.u.HighPart != 0) + return STG_E_INVALIDFUNCTION; + + if (This->byteArraySize.u.LowPart == libNewSize.u.LowPart) + return S_OK; + + /* + * Re allocate the HGlobal to fit the new size of the stream. + */ + supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.u.LowPart, 0); + + if (supportHandle == 0) + return STG_E_MEDIUMFULL; + + This->supportHandle = supportHandle; + This->byteArraySize.u.LowPart = libNewSize.u.LowPart; + + return S_OK; +} + +/****************************************************************************** + * This method is part of the ILockBytes interface. + * + * The global memory implementation of ILockBytes does not support locking. + * + * See the documentation of ILockBytes for more info. + */ +HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion( + ILockBytes* iface, + ULARGE_INTEGER libOffset, /* [in] */ + ULARGE_INTEGER cb, /* [in] */ + DWORD dwLockType) /* [in] */ +{ + return STG_E_INVALIDFUNCTION; +} + +/****************************************************************************** + * This method is part of the ILockBytes interface. + * + * The global memory implementation of ILockBytes does not support locking. + * + * See the documentation of ILockBytes for more info. + */ +HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion( + ILockBytes* iface, + ULARGE_INTEGER libOffset, /* [in] */ + ULARGE_INTEGER cb, /* [in] */ + DWORD dwLockType) /* [in] */ +{ + return STG_E_INVALIDFUNCTION; +} + +/****************************************************************************** + * This method is part of the ILockBytes interface. + * + * This method returns information about the current + * byte array object. + * + * See the documentation of ILockBytes for more info. + */ +HRESULT WINAPI HGLOBALLockBytesImpl_Stat( + ILockBytes* iface, + STATSTG* pstatstg, /* [out] */ + DWORD grfStatFlag) /* [in] */ +{ + HGLOBALLockBytesImpl* const This=(HGLOBALLockBytesImpl*)iface; + + memset(pstatstg, 0, sizeof(STATSTG)); + + pstatstg->pwcsName = NULL; + pstatstg->type = STGTY_LOCKBYTES; + pstatstg->cbSize = This->byteArraySize; + + return S_OK; +} diff --git a/reactos/lib/ole32/memlockbytes16.c b/reactos/lib/ole32/memlockbytes16.c index b13500e82cc..a2ae7a37f7c 100644 --- a/reactos/lib/ole32/memlockbytes16.c +++ b/reactos/lib/ole32/memlockbytes16.c @@ -1,578 +1,578 @@ -/* - * Global memory implementation of ILockBytes. - * - * Copyright 1999 Thuy Nguyen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <assert.h> -#include <stdarg.h> -#include <string.h> - -#define NONAMELESSUNION -#define NONAMELESSSTRUCT -#include "windef.h" -#include "winbase.h" -#include "wine/winbase16.h" -#include "winuser.h" -#include "objbase.h" -#include "ole2.h" -#include "winerror.h" - -#include "ifs.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/****************************************************************************** - * HGLOBALLockBytesImpl16 definition. - * - * This class imlements the ILockBytes inteface and represents a byte array - * object supported by an HGLOBAL pointer. - */ -struct HGLOBALLockBytesImpl16 -{ - /* - * Needs to be the first item in the struct - * since we want to cast this in an ILockBytes pointer - */ - ILockBytes16Vtbl *lpVtbl; - ULONG ref; - - /* - * Support for the LockBytes object - */ - HGLOBAL16 supportHandle; - - /* - * This flag is TRUE if the HGLOBAL is destroyed when the object - * is finally released. - */ - BOOL deleteOnRelease; - /* - * Helper variable that contains the size of the byte array - */ - ULARGE_INTEGER byteArraySize; -}; - -typedef struct HGLOBALLockBytesImpl16 HGLOBALLockBytesImpl16; - -HGLOBALLockBytesImpl16* HGLOBALLockBytesImpl16_Construct( - HGLOBAL16 hGlobal, - BOOL16 fDeleteOnRelease); - -void HGLOBALLockBytesImpl16_Destroy(HGLOBALLockBytesImpl16* This); - -HRESULT WINAPI HGLOBALLockBytesImpl16_QueryInterface( - ILockBytes16* iface, - REFIID riid, /* [in] */ - void** ppvObject); /* [out][iid_is] */ - -ULONG WINAPI HGLOBALLockBytesImpl16_AddRef( - ILockBytes16* iface); - -ULONG WINAPI HGLOBALLockBytesImpl16_Release( - ILockBytes16* iface); - -HRESULT WINAPI HGLOBALLockBytesImpl16_ReadAt( - ILockBytes16* iface, - ULARGE_INTEGER ulOffset, /* [in] */ - void* pv, /* [out][length_is][size_is] */ - ULONG cb, /* [in] */ - ULONG* pcbRead); /* [out] */ - -HRESULT WINAPI HGLOBALLockBytesImpl16_WriteAt( - ILockBytes16* iface, - ULARGE_INTEGER ulOffset, /* [in] */ - const void* pv, /* [in][size_is] */ - ULONG cb, /* [in] */ - ULONG* pcbWritten); /* [out] */ - -HRESULT WINAPI HGLOBALLockBytesImpl16_Flush( - ILockBytes16* iface); - -HRESULT WINAPI HGLOBALLockBytesImpl16_SetSize( - ILockBytes16* iface, - ULARGE_INTEGER libNewSize); /* [in] */ - -HRESULT WINAPI HGLOBALLockBytesImpl16_LockRegion( - ILockBytes16* iface, - ULARGE_INTEGER libOffset, /* [in] */ - ULARGE_INTEGER cb, /* [in] */ - DWORD dwLockType); /* [in] */ - -HRESULT WINAPI HGLOBALLockBytesImpl16_UnlockRegion( - ILockBytes16* iface, - ULARGE_INTEGER libOffset, /* [in] */ - ULARGE_INTEGER cb, /* [in] */ - DWORD dwLockType); /* [in] */ - -HRESULT WINAPI HGLOBALLockBytesImpl16_Stat( - ILockBytes16* iface, - STATSTG16* pstatstg, /* [out] */ - DWORD grfStatFlag); /* [in] */ - -/****************************************************************************** - * - * HGLOBALLockBytesImpl16 implementation - * - */ - -/****************************************************************************** - * This is the constructor for the HGLOBALLockBytesImpl16 class. - * - * Params: - * hGlobal - Handle that will support the stream. can be NULL. - * fDeleteOnRelease - Flag set to TRUE if the HGLOBAL16 will be released - * when the IStream object is destroyed. - */ -HGLOBALLockBytesImpl16* -HGLOBALLockBytesImpl16_Construct(HGLOBAL16 hGlobal, - BOOL16 fDeleteOnRelease) -{ - HGLOBALLockBytesImpl16* newLockBytes; - - static ILockBytes16Vtbl vt16; - static SEGPTR msegvt16; - HMODULE16 hcomp = GetModuleHandle16("OLE2"); - - - TRACE("(%x,%d)\n",hGlobal,fDeleteOnRelease); - newLockBytes = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALLockBytesImpl16)); - if (newLockBytes == NULL) - return NULL; - - /* - * Set up the virtual function table and reference count. - */ - if (!msegvt16) - { -#define VTENT(x) vt16.x = (void*)GetProcAddress16(hcomp,"HGLOBALLockBytesImpl16_"#x);assert(vt16.x) - VTENT(QueryInterface); - VTENT(AddRef); - VTENT(Release); - VTENT(ReadAt); - VTENT(WriteAt); - VTENT(Flush); - VTENT(SetSize); - VTENT(LockRegion); - VTENT(UnlockRegion); -#undef VTENT - msegvt16 = MapLS( &vt16 ); - } - newLockBytes->lpVtbl = (ILockBytes16Vtbl*)msegvt16; - newLockBytes->ref = 0; - /* - * Initialize the support. - */ - newLockBytes->supportHandle = hGlobal; - newLockBytes->deleteOnRelease = fDeleteOnRelease; - - /* - * This method will allocate a handle if one is not supplied. - */ - if (newLockBytes->supportHandle == 0) - newLockBytes->supportHandle = GlobalAlloc16(GMEM_MOVEABLE | GMEM_NODISCARD, 0); - - /* - * Initialize the size of the array to the size of the handle. - */ - newLockBytes->byteArraySize.u.HighPart = 0; - newLockBytes->byteArraySize.u.LowPart = GlobalSize16( - newLockBytes->supportHandle); - - return (HGLOBALLockBytesImpl16*)MapLS(newLockBytes); -} - -/****************************************************************************** - * This is the destructor of the HGLOBALStreamImpl class. - * - * This method will clean-up all the resources used-up by the given - * HGLOBALLockBytesImpl16 class. The pointer passed-in to this function will be - * freed and will not be valid anymore. - */ -void HGLOBALLockBytesImpl16_Destroy(HGLOBALLockBytesImpl16* This) -{ - TRACE("()\n"); - /* - * Release the HGlobal if the constructor asked for that. - */ - if (This->deleteOnRelease) - { - GlobalFree16(This->supportHandle); - This->supportHandle = 0; - } - - /* - * Finally, free the memory used-up by the class. - */ - HeapFree(GetProcessHeap(), 0, This); -} - -/****************************************************************************** - * This implements the IUnknown method QueryInterface for this - * class - */ -HRESULT WINAPI HGLOBALLockBytesImpl16_QueryInterface( - ILockBytes16* iface, /* [in] SEGPTR */ - REFIID riid, /* [in] */ - void** ppvObject) /* [out][iid_is] (ptr to SEGPTR!) */ -{ - HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)MapSL((SEGPTR)iface); - - TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppvObject); - /* - * Perform a sanity check on the parameters. - */ - if (ppvObject==0) - return E_INVALIDARG; - - /* - * Initialize the return parameter. - */ - *ppvObject = 0; - /* - * Compare the riid with the interface IDs implemented by this object. - */ - if ( !memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) || - !memcmp(&IID_ILockBytes, riid, sizeof(IID_ILockBytes)) - ) - *ppvObject = (void*)iface; - - /* - * Check that we obtained an interface. - */ - if ((*ppvObject)==0) - return E_NOINTERFACE; - - /* - * Query Interface always increases the reference count by one when it is - * successful - */ - HGLOBALLockBytesImpl16_AddRef((ILockBytes16*)This); - - return S_OK; -} - -/****************************************************************************** - * This implements the IUnknown method AddRef for this - * class - */ -ULONG WINAPI HGLOBALLockBytesImpl16_AddRef(ILockBytes16* iface) -{ - HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface; - - TRACE("(%p)\n",This); - - return InterlockedIncrement(&This->ref); -} - -/****************************************************************************** - * This implements the IUnknown method Release for this - * class - */ -ULONG WINAPI HGLOBALLockBytesImpl16_Release(ILockBytes16* iface) -{ - HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface; - ULONG ref; - - TRACE("(%p)\n",This); - - ref = InterlockedDecrement(&This->ref); - - /* - * If the reference count goes down to 0, perform suicide. - */ - if (ref==0) - HGLOBALLockBytesImpl16_Destroy(This); - return ref; -} - -/****************************************************************************** - * This method is part of the ILockBytes interface. - * - * It reads a block of information from the byte array at the specified - * offset. - * - * See the documentation of ILockBytes for more info. - */ -HRESULT WINAPI HGLOBALLockBytesImpl16_ReadAt( - ILockBytes16* iface, - ULARGE_INTEGER ulOffset, /* [in] */ - void* pv, /* [out][length_is][size_is] */ - ULONG cb, /* [in] */ - ULONG* pcbRead) /* [out] */ -{ - HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface; - - void* supportBuffer; - ULONG bytesReadBuffer = 0; - ULONG bytesToReadFromBuffer; - - TRACE("(%p,%ld,%p,%ld,%p)\n",This,ulOffset.u.LowPart,pv,cb,pcbRead); - /* - * If the caller is not interested in the number of bytes read, - * we use another buffer to avoid "if" statements in the code. - */ - if (pcbRead == 0) - pcbRead = &bytesReadBuffer; - - /* - * Make sure the offset is valid. - */ - if (ulOffset.u.LowPart > This->byteArraySize.u.LowPart) - return E_FAIL; - - /* - * Using the known size of the array, calculate the number of bytes - * to read. - */ - bytesToReadFromBuffer = min(This->byteArraySize.u.LowPart - - ulOffset.u.LowPart, cb); - - /* - * Lock the buffer in position and copy the data. - */ - supportBuffer = GlobalLock16(This->supportHandle); - - memcpy(pv, - (char *) supportBuffer + ulOffset.u.LowPart, - bytesToReadFromBuffer); - - /* - * Return the number of bytes read. - */ - *pcbRead = bytesToReadFromBuffer; - - /* - * Cleanup - */ - GlobalUnlock16(This->supportHandle); - - /* - * The function returns S_OK if the specified number of bytes were read - * or the end of the array was reached. - * It returns STG_E_READFAULT if the number of bytes to read does not equal - * the number of bytes actually read. - */ - if(*pcbRead == cb) - return S_OK; - - return STG_E_READFAULT; -} - -/****************************************************************************** - * This method is part of the ILockBytes interface. - * - * It writes the specified bytes at the specified offset. - * position. If the array is too small, it will be resized. - * - * See the documentation of ILockBytes for more info. - */ -HRESULT WINAPI HGLOBALLockBytesImpl16_WriteAt( - ILockBytes16* iface, - ULARGE_INTEGER ulOffset, /* [in] */ - const void* pv, /* [in][size_is] */ - ULONG cb, /* [in] */ - ULONG* pcbWritten) /* [out] */ -{ - HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface; - - void* supportBuffer; - ULARGE_INTEGER newSize; - ULONG bytesWritten = 0; - - TRACE("(%p,%ld,%p,%ld,%p)\n",This,ulOffset.u.LowPart,pv,cb,pcbWritten); - /* - * If the caller is not interested in the number of bytes written, - * we use another buffer to avoid "if" statements in the code. - */ - if (pcbWritten == 0) - pcbWritten = &bytesWritten; - - if (cb == 0) - return S_OK; - - newSize.u.HighPart = 0; - newSize.u.LowPart = ulOffset.u.LowPart + cb; - - /* - * Verify if we need to grow the stream - */ - if (newSize.u.LowPart > This->byteArraySize.u.LowPart) - { - /* grow stream */ - if (HGLOBALLockBytesImpl16_SetSize(iface, newSize) == STG_E_MEDIUMFULL) - return STG_E_MEDIUMFULL; - } - - /* - * Lock the buffer in position and copy the data. - */ - supportBuffer = GlobalLock16(This->supportHandle); - - memcpy((char *) supportBuffer + ulOffset.u.LowPart, pv, cb); - - /* - * Return the number of bytes written. - */ - *pcbWritten = cb; - - /* - * Cleanup - */ - GlobalUnlock16(This->supportHandle); - - return S_OK; -} - -/****************************************************************************** - * This method is part of the ILockBytes interface. - * - * See the documentation of ILockBytes for more info. - */ -HRESULT WINAPI HGLOBALLockBytesImpl16_Flush(ILockBytes16* iface) -{ - TRACE("(%p)\n",iface); - return S_OK; -} - -/****************************************************************************** - * This method is part of the ILockBytes interface. - * - * It will change the size of the byte array. - * - * See the documentation of ILockBytes for more info. - */ -HRESULT WINAPI HGLOBALLockBytesImpl16_SetSize( - ILockBytes16* iface, - ULARGE_INTEGER libNewSize) /* [in] */ -{ - HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface; - HGLOBAL16 supportHandle; - - TRACE("(%p,%ld)\n",This,libNewSize.u.LowPart); - /* - * As documented. - */ - if (libNewSize.u.HighPart != 0) - return STG_E_INVALIDFUNCTION; - - if (This->byteArraySize.u.LowPart == libNewSize.u.LowPart) - return S_OK; - - /* - * Re allocate the HGlobal to fit the new size of the stream. - */ - supportHandle = GlobalReAlloc16(This->supportHandle, libNewSize.u.LowPart, 0); - - if (supportHandle == 0) - return STG_E_MEDIUMFULL; - - This->supportHandle = supportHandle; - This->byteArraySize.u.LowPart = libNewSize.u.LowPart; - - return S_OK; -} - -/****************************************************************************** - * This method is part of the ILockBytes interface. - * - * The global memory implementation of ILockBytes does not support locking. - * - * See the documentation of ILockBytes for more info. - */ -HRESULT WINAPI HGLOBALLockBytesImpl16_LockRegion( - ILockBytes16* iface, - ULARGE_INTEGER libOffset, /* [in] */ - ULARGE_INTEGER cb, /* [in] */ - DWORD dwLockType) /* [in] */ -{ - return STG_E_INVALIDFUNCTION; -} - -/****************************************************************************** - * This method is part of the ILockBytes interface. - * - * The global memory implementation of ILockBytes does not support locking. - * - * See the documentation of ILockBytes for more info. - */ -HRESULT WINAPI HGLOBALLockBytesImpl16_UnlockRegion( - ILockBytes16* iface, - ULARGE_INTEGER libOffset, /* [in] */ - ULARGE_INTEGER cb, /* [in] */ - DWORD dwLockType) /* [in] */ -{ - return STG_E_INVALIDFUNCTION; -} - -/****************************************************************************** - * This method is part of the ILockBytes interface. - * - * This method returns information about the current - * byte array object. - * - * See the documentation of ILockBytes for more info. - */ -HRESULT WINAPI HGLOBALLockBytesImpl16_Stat( - ILockBytes16*iface, - STATSTG16* pstatstg, /* [out] */ - DWORD grfStatFlag) /* [in] */ -{ - HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface; - - memset(pstatstg, 0, sizeof(STATSTG16)); - - pstatstg->pwcsName = NULL; - pstatstg->type = STGTY_LOCKBYTES; - pstatstg->cbSize = This->byteArraySize; - - return S_OK; -} - -/****************************************************************************** - * CreateILockBytesOnHGlobal [OLE2.54] - * - * Creates an ILockBytes interface for a HGLOBAL handle. - * - * Params: - * hGlobal the global handle (16bit) - * fDeleteOnRelease delete handle on release. - * ppLkbyt pointer to ILockBytes interface. - * - * Returns: - * Staddard OLE error return codes. - * - */ -HRESULT WINAPI CreateILockBytesOnHGlobal16( - HGLOBAL16 hGlobal, /* [in] */ - BOOL16 fDeleteOnRelease, /* [in] */ - LPLOCKBYTES16 *ppLkbyt) /* [out] (ptr to SEGPTR!) */ -{ - HGLOBALLockBytesImpl16* newLockBytes; /* SEGPTR */ - - newLockBytes = HGLOBALLockBytesImpl16_Construct(hGlobal, fDeleteOnRelease); - - if (newLockBytes != NULL) - return HGLOBALLockBytesImpl16_QueryInterface((ILockBytes16*)newLockBytes, - &IID_ILockBytes, - (void**)ppLkbyt); - return E_OUTOFMEMORY; -} +/* + * Global memory implementation of ILockBytes. + * + * Copyright 1999 Thuy Nguyen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <assert.h> +#include <stdarg.h> +#include <string.h> + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winbase.h" +#include "wine/winbase16.h" +#include "winuser.h" +#include "objbase.h" +#include "ole2.h" +#include "winerror.h" + +#include "ifs.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/****************************************************************************** + * HGLOBALLockBytesImpl16 definition. + * + * This class imlements the ILockBytes inteface and represents a byte array + * object supported by an HGLOBAL pointer. + */ +struct HGLOBALLockBytesImpl16 +{ + /* + * Needs to be the first item in the struct + * since we want to cast this in an ILockBytes pointer + */ + ILockBytes16Vtbl *lpVtbl; + ULONG ref; + + /* + * Support for the LockBytes object + */ + HGLOBAL16 supportHandle; + + /* + * This flag is TRUE if the HGLOBAL is destroyed when the object + * is finally released. + */ + BOOL deleteOnRelease; + /* + * Helper variable that contains the size of the byte array + */ + ULARGE_INTEGER byteArraySize; +}; + +typedef struct HGLOBALLockBytesImpl16 HGLOBALLockBytesImpl16; + +HGLOBALLockBytesImpl16* HGLOBALLockBytesImpl16_Construct( + HGLOBAL16 hGlobal, + BOOL16 fDeleteOnRelease); + +void HGLOBALLockBytesImpl16_Destroy(HGLOBALLockBytesImpl16* This); + +HRESULT WINAPI HGLOBALLockBytesImpl16_QueryInterface( + ILockBytes16* iface, + REFIID riid, /* [in] */ + void** ppvObject); /* [out][iid_is] */ + +ULONG WINAPI HGLOBALLockBytesImpl16_AddRef( + ILockBytes16* iface); + +ULONG WINAPI HGLOBALLockBytesImpl16_Release( + ILockBytes16* iface); + +HRESULT WINAPI HGLOBALLockBytesImpl16_ReadAt( + ILockBytes16* iface, + ULARGE_INTEGER ulOffset, /* [in] */ + void* pv, /* [out][length_is][size_is] */ + ULONG cb, /* [in] */ + ULONG* pcbRead); /* [out] */ + +HRESULT WINAPI HGLOBALLockBytesImpl16_WriteAt( + ILockBytes16* iface, + ULARGE_INTEGER ulOffset, /* [in] */ + const void* pv, /* [in][size_is] */ + ULONG cb, /* [in] */ + ULONG* pcbWritten); /* [out] */ + +HRESULT WINAPI HGLOBALLockBytesImpl16_Flush( + ILockBytes16* iface); + +HRESULT WINAPI HGLOBALLockBytesImpl16_SetSize( + ILockBytes16* iface, + ULARGE_INTEGER libNewSize); /* [in] */ + +HRESULT WINAPI HGLOBALLockBytesImpl16_LockRegion( + ILockBytes16* iface, + ULARGE_INTEGER libOffset, /* [in] */ + ULARGE_INTEGER cb, /* [in] */ + DWORD dwLockType); /* [in] */ + +HRESULT WINAPI HGLOBALLockBytesImpl16_UnlockRegion( + ILockBytes16* iface, + ULARGE_INTEGER libOffset, /* [in] */ + ULARGE_INTEGER cb, /* [in] */ + DWORD dwLockType); /* [in] */ + +HRESULT WINAPI HGLOBALLockBytesImpl16_Stat( + ILockBytes16* iface, + STATSTG16* pstatstg, /* [out] */ + DWORD grfStatFlag); /* [in] */ + +/****************************************************************************** + * + * HGLOBALLockBytesImpl16 implementation + * + */ + +/****************************************************************************** + * This is the constructor for the HGLOBALLockBytesImpl16 class. + * + * Params: + * hGlobal - Handle that will support the stream. can be NULL. + * fDeleteOnRelease - Flag set to TRUE if the HGLOBAL16 will be released + * when the IStream object is destroyed. + */ +HGLOBALLockBytesImpl16* +HGLOBALLockBytesImpl16_Construct(HGLOBAL16 hGlobal, + BOOL16 fDeleteOnRelease) +{ + HGLOBALLockBytesImpl16* newLockBytes; + + static ILockBytes16Vtbl vt16; + static SEGPTR msegvt16; + HMODULE16 hcomp = GetModuleHandle16("OLE2"); + + + TRACE("(%x,%d)\n",hGlobal,fDeleteOnRelease); + newLockBytes = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALLockBytesImpl16)); + if (newLockBytes == NULL) + return NULL; + + /* + * Set up the virtual function table and reference count. + */ + if (!msegvt16) + { +#define VTENT(x) vt16.x = (void*)GetProcAddress16(hcomp,"HGLOBALLockBytesImpl16_"#x);assert(vt16.x) + VTENT(QueryInterface); + VTENT(AddRef); + VTENT(Release); + VTENT(ReadAt); + VTENT(WriteAt); + VTENT(Flush); + VTENT(SetSize); + VTENT(LockRegion); + VTENT(UnlockRegion); +#undef VTENT + msegvt16 = MapLS( &vt16 ); + } + newLockBytes->lpVtbl = (ILockBytes16Vtbl*)msegvt16; + newLockBytes->ref = 0; + /* + * Initialize the support. + */ + newLockBytes->supportHandle = hGlobal; + newLockBytes->deleteOnRelease = fDeleteOnRelease; + + /* + * This method will allocate a handle if one is not supplied. + */ + if (newLockBytes->supportHandle == 0) + newLockBytes->supportHandle = GlobalAlloc16(GMEM_MOVEABLE | GMEM_NODISCARD, 0); + + /* + * Initialize the size of the array to the size of the handle. + */ + newLockBytes->byteArraySize.u.HighPart = 0; + newLockBytes->byteArraySize.u.LowPart = GlobalSize16( + newLockBytes->supportHandle); + + return (HGLOBALLockBytesImpl16*)MapLS(newLockBytes); +} + +/****************************************************************************** + * This is the destructor of the HGLOBALStreamImpl class. + * + * This method will clean-up all the resources used-up by the given + * HGLOBALLockBytesImpl16 class. The pointer passed-in to this function will be + * freed and will not be valid anymore. + */ +void HGLOBALLockBytesImpl16_Destroy(HGLOBALLockBytesImpl16* This) +{ + TRACE("()\n"); + /* + * Release the HGlobal if the constructor asked for that. + */ + if (This->deleteOnRelease) + { + GlobalFree16(This->supportHandle); + This->supportHandle = 0; + } + + /* + * Finally, free the memory used-up by the class. + */ + HeapFree(GetProcessHeap(), 0, This); +} + +/****************************************************************************** + * This implements the IUnknown method QueryInterface for this + * class + */ +HRESULT WINAPI HGLOBALLockBytesImpl16_QueryInterface( + ILockBytes16* iface, /* [in] SEGPTR */ + REFIID riid, /* [in] */ + void** ppvObject) /* [out][iid_is] (ptr to SEGPTR!) */ +{ + HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)MapSL((SEGPTR)iface); + + TRACE("(%p,%s,%p)\n",iface,debugstr_guid(riid),ppvObject); + /* + * Perform a sanity check on the parameters. + */ + if (ppvObject==0) + return E_INVALIDARG; + + /* + * Initialize the return parameter. + */ + *ppvObject = 0; + /* + * Compare the riid with the interface IDs implemented by this object. + */ + if ( !memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) || + !memcmp(&IID_ILockBytes, riid, sizeof(IID_ILockBytes)) + ) + *ppvObject = (void*)iface; + + /* + * Check that we obtained an interface. + */ + if ((*ppvObject)==0) + return E_NOINTERFACE; + + /* + * Query Interface always increases the reference count by one when it is + * successful + */ + HGLOBALLockBytesImpl16_AddRef((ILockBytes16*)This); + + return S_OK; +} + +/****************************************************************************** + * This implements the IUnknown method AddRef for this + * class + */ +ULONG WINAPI HGLOBALLockBytesImpl16_AddRef(ILockBytes16* iface) +{ + HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface; + + TRACE("(%p)\n",This); + + return InterlockedIncrement(&This->ref); +} + +/****************************************************************************** + * This implements the IUnknown method Release for this + * class + */ +ULONG WINAPI HGLOBALLockBytesImpl16_Release(ILockBytes16* iface) +{ + HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface; + ULONG ref; + + TRACE("(%p)\n",This); + + ref = InterlockedDecrement(&This->ref); + + /* + * If the reference count goes down to 0, perform suicide. + */ + if (ref==0) + HGLOBALLockBytesImpl16_Destroy(This); + return ref; +} + +/****************************************************************************** + * This method is part of the ILockBytes interface. + * + * It reads a block of information from the byte array at the specified + * offset. + * + * See the documentation of ILockBytes for more info. + */ +HRESULT WINAPI HGLOBALLockBytesImpl16_ReadAt( + ILockBytes16* iface, + ULARGE_INTEGER ulOffset, /* [in] */ + void* pv, /* [out][length_is][size_is] */ + ULONG cb, /* [in] */ + ULONG* pcbRead) /* [out] */ +{ + HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface; + + void* supportBuffer; + ULONG bytesReadBuffer = 0; + ULONG bytesToReadFromBuffer; + + TRACE("(%p,%ld,%p,%ld,%p)\n",This,ulOffset.u.LowPart,pv,cb,pcbRead); + /* + * If the caller is not interested in the number of bytes read, + * we use another buffer to avoid "if" statements in the code. + */ + if (pcbRead == 0) + pcbRead = &bytesReadBuffer; + + /* + * Make sure the offset is valid. + */ + if (ulOffset.u.LowPart > This->byteArraySize.u.LowPart) + return E_FAIL; + + /* + * Using the known size of the array, calculate the number of bytes + * to read. + */ + bytesToReadFromBuffer = min(This->byteArraySize.u.LowPart - + ulOffset.u.LowPart, cb); + + /* + * Lock the buffer in position and copy the data. + */ + supportBuffer = GlobalLock16(This->supportHandle); + + memcpy(pv, + (char *) supportBuffer + ulOffset.u.LowPart, + bytesToReadFromBuffer); + + /* + * Return the number of bytes read. + */ + *pcbRead = bytesToReadFromBuffer; + + /* + * Cleanup + */ + GlobalUnlock16(This->supportHandle); + + /* + * The function returns S_OK if the specified number of bytes were read + * or the end of the array was reached. + * It returns STG_E_READFAULT if the number of bytes to read does not equal + * the number of bytes actually read. + */ + if(*pcbRead == cb) + return S_OK; + + return STG_E_READFAULT; +} + +/****************************************************************************** + * This method is part of the ILockBytes interface. + * + * It writes the specified bytes at the specified offset. + * position. If the array is too small, it will be resized. + * + * See the documentation of ILockBytes for more info. + */ +HRESULT WINAPI HGLOBALLockBytesImpl16_WriteAt( + ILockBytes16* iface, + ULARGE_INTEGER ulOffset, /* [in] */ + const void* pv, /* [in][size_is] */ + ULONG cb, /* [in] */ + ULONG* pcbWritten) /* [out] */ +{ + HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface; + + void* supportBuffer; + ULARGE_INTEGER newSize; + ULONG bytesWritten = 0; + + TRACE("(%p,%ld,%p,%ld,%p)\n",This,ulOffset.u.LowPart,pv,cb,pcbWritten); + /* + * If the caller is not interested in the number of bytes written, + * we use another buffer to avoid "if" statements in the code. + */ + if (pcbWritten == 0) + pcbWritten = &bytesWritten; + + if (cb == 0) + return S_OK; + + newSize.u.HighPart = 0; + newSize.u.LowPart = ulOffset.u.LowPart + cb; + + /* + * Verify if we need to grow the stream + */ + if (newSize.u.LowPart > This->byteArraySize.u.LowPart) + { + /* grow stream */ + if (HGLOBALLockBytesImpl16_SetSize(iface, newSize) == STG_E_MEDIUMFULL) + return STG_E_MEDIUMFULL; + } + + /* + * Lock the buffer in position and copy the data. + */ + supportBuffer = GlobalLock16(This->supportHandle); + + memcpy((char *) supportBuffer + ulOffset.u.LowPart, pv, cb); + + /* + * Return the number of bytes written. + */ + *pcbWritten = cb; + + /* + * Cleanup + */ + GlobalUnlock16(This->supportHandle); + + return S_OK; +} + +/****************************************************************************** + * This method is part of the ILockBytes interface. + * + * See the documentation of ILockBytes for more info. + */ +HRESULT WINAPI HGLOBALLockBytesImpl16_Flush(ILockBytes16* iface) +{ + TRACE("(%p)\n",iface); + return S_OK; +} + +/****************************************************************************** + * This method is part of the ILockBytes interface. + * + * It will change the size of the byte array. + * + * See the documentation of ILockBytes for more info. + */ +HRESULT WINAPI HGLOBALLockBytesImpl16_SetSize( + ILockBytes16* iface, + ULARGE_INTEGER libNewSize) /* [in] */ +{ + HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface; + HGLOBAL16 supportHandle; + + TRACE("(%p,%ld)\n",This,libNewSize.u.LowPart); + /* + * As documented. + */ + if (libNewSize.u.HighPart != 0) + return STG_E_INVALIDFUNCTION; + + if (This->byteArraySize.u.LowPart == libNewSize.u.LowPart) + return S_OK; + + /* + * Re allocate the HGlobal to fit the new size of the stream. + */ + supportHandle = GlobalReAlloc16(This->supportHandle, libNewSize.u.LowPart, 0); + + if (supportHandle == 0) + return STG_E_MEDIUMFULL; + + This->supportHandle = supportHandle; + This->byteArraySize.u.LowPart = libNewSize.u.LowPart; + + return S_OK; +} + +/****************************************************************************** + * This method is part of the ILockBytes interface. + * + * The global memory implementation of ILockBytes does not support locking. + * + * See the documentation of ILockBytes for more info. + */ +HRESULT WINAPI HGLOBALLockBytesImpl16_LockRegion( + ILockBytes16* iface, + ULARGE_INTEGER libOffset, /* [in] */ + ULARGE_INTEGER cb, /* [in] */ + DWORD dwLockType) /* [in] */ +{ + return STG_E_INVALIDFUNCTION; +} + +/****************************************************************************** + * This method is part of the ILockBytes interface. + * + * The global memory implementation of ILockBytes does not support locking. + * + * See the documentation of ILockBytes for more info. + */ +HRESULT WINAPI HGLOBALLockBytesImpl16_UnlockRegion( + ILockBytes16* iface, + ULARGE_INTEGER libOffset, /* [in] */ + ULARGE_INTEGER cb, /* [in] */ + DWORD dwLockType) /* [in] */ +{ + return STG_E_INVALIDFUNCTION; +} + +/****************************************************************************** + * This method is part of the ILockBytes interface. + * + * This method returns information about the current + * byte array object. + * + * See the documentation of ILockBytes for more info. + */ +HRESULT WINAPI HGLOBALLockBytesImpl16_Stat( + ILockBytes16*iface, + STATSTG16* pstatstg, /* [out] */ + DWORD grfStatFlag) /* [in] */ +{ + HGLOBALLockBytesImpl16* const This=(HGLOBALLockBytesImpl16*)iface; + + memset(pstatstg, 0, sizeof(STATSTG16)); + + pstatstg->pwcsName = NULL; + pstatstg->type = STGTY_LOCKBYTES; + pstatstg->cbSize = This->byteArraySize; + + return S_OK; +} + +/****************************************************************************** + * CreateILockBytesOnHGlobal [OLE2.54] + * + * Creates an ILockBytes interface for a HGLOBAL handle. + * + * Params: + * hGlobal the global handle (16bit) + * fDeleteOnRelease delete handle on release. + * ppLkbyt pointer to ILockBytes interface. + * + * Returns: + * Staddard OLE error return codes. + * + */ +HRESULT WINAPI CreateILockBytesOnHGlobal16( + HGLOBAL16 hGlobal, /* [in] */ + BOOL16 fDeleteOnRelease, /* [in] */ + LPLOCKBYTES16 *ppLkbyt) /* [out] (ptr to SEGPTR!) */ +{ + HGLOBALLockBytesImpl16* newLockBytes; /* SEGPTR */ + + newLockBytes = HGLOBALLockBytesImpl16_Construct(hGlobal, fDeleteOnRelease); + + if (newLockBytes != NULL) + return HGLOBALLockBytesImpl16_QueryInterface((ILockBytes16*)newLockBytes, + &IID_ILockBytes, + (void**)ppLkbyt); + return E_OUTOFMEMORY; +} diff --git a/reactos/lib/ole32/moniker.c b/reactos/lib/ole32/moniker.c index a0c09da7470..a1ffa6ef992 100644 --- a/reactos/lib/ole32/moniker.c +++ b/reactos/lib/ole32/moniker.c @@ -1,1145 +1,1145 @@ -/* - * Monikers - * - * Copyright 1998 Marcus Meissner - * Copyright 1999 Noomen Hamza - * Copyright 2005 Robert Shearman (for CodeWeavers) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * TODO: - * - IRunningObjectTable should work interprocess, but currently doesn't. - * Native (on Win2k at least) uses an undocumented RPC interface, IROT, to - * communicate with RPCSS which contains the table of marshalled data. - */ - -#include <assert.h> -#include <stdarg.h> -#include <string.h> - -#define COBJMACROS - -#include "winerror.h" -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "wtypes.h" -#include "ole2.h" - -#include "wine/list.h" -#include "wine/debug.h" - -#include "compobj_private.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/* define the structure of the running object table elements */ -struct rot_entry -{ - struct list entry; - MInterfacePointer* object; /* marshaled running object*/ - MInterfacePointer* moniker; /* marshaled moniker that identifies this object */ - MInterfacePointer* moniker_data; /* moniker comparison data that identifies this object */ - DWORD cookie; /* cookie identifying this object */ - FILETIME last_modified; -}; - -/* define the RunningObjectTableImpl structure */ -typedef struct RunningObjectTableImpl -{ - const IRunningObjectTableVtbl *lpVtbl; - ULONG ref; - - struct list rot; /* list of ROT entries */ - CRITICAL_SECTION lock; -} RunningObjectTableImpl; - -static RunningObjectTableImpl* runningObjectTableInstance = NULL; - - - -static inline HRESULT WINAPI -IrotRegister(DWORD *cookie) -{ - static DWORD last_cookie = 1; - *cookie = InterlockedIncrement(&last_cookie); - return S_OK; -} - -/* define the EnumMonikerImpl structure */ -typedef struct EnumMonikerImpl -{ - const IEnumMonikerVtbl *lpVtbl; - ULONG ref; - - MInterfacePointer **monikers; - ULONG moniker_count; - ULONG pos; -} EnumMonikerImpl; - - -/* IEnumMoniker Local functions*/ -static HRESULT WINAPI EnumMonikerImpl_CreateEnumROTMoniker(MInterfacePointer **monikers, - ULONG moniker_count, ULONG pos, IEnumMoniker **ppenumMoniker); - -static HRESULT create_stream_on_mip_ro(const MInterfacePointer *mip, IStream **stream) -{ - HGLOBAL hglobal = GlobalAlloc(0, mip->ulCntData); - void *pv = GlobalLock(hglobal); - memcpy(pv, mip->abData, mip->ulCntData); - GlobalUnlock(hglobal); - return CreateStreamOnHGlobal(hglobal, TRUE, stream); -} - -static inline void rot_entry_delete(struct rot_entry *rot_entry) -{ - /* FIXME: revoke entry from rpcss's copy of the ROT */ - if (rot_entry->object) - { - IStream *stream; - HRESULT hr; - hr = create_stream_on_mip_ro(rot_entry->object, &stream); - if (hr == S_OK) - { - CoReleaseMarshalData(stream); - IUnknown_Release(stream); - } - } - if (rot_entry->moniker) - { - IStream *stream; - HRESULT hr; - hr = create_stream_on_mip_ro(rot_entry->moniker, &stream); - if (hr == S_OK) - { - CoReleaseMarshalData(stream); - IUnknown_Release(stream); - } - } - HeapFree(GetProcessHeap(), 0, rot_entry->object); - HeapFree(GetProcessHeap(), 0, rot_entry->moniker); - HeapFree(GetProcessHeap(), 0, rot_entry->moniker_data); - HeapFree(GetProcessHeap(), 0, rot_entry); -} - -/* moniker_data must be freed with HeapFree when no longer in use */ -static HRESULT get_moniker_comparison_data(IMoniker *pMoniker, MInterfacePointer **moniker_data) -{ - HRESULT hr; - IROTData *pROTData = NULL; - ULONG size = 0; - hr = IMoniker_QueryInterface(pMoniker, &IID_IROTData, (void *)&pROTData); - if (hr != S_OK) - { - ERR("Failed to query moniker for IROTData interface, hr = 0x%08lx\n", hr); - return hr; - } - IROTData_GetComparisonData(pROTData, NULL, 0, &size); - *moniker_data = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MInterfacePointer, abData[size])); - (*moniker_data)->ulCntData = size; - hr = IROTData_GetComparisonData(pROTData, (*moniker_data)->abData, size, &size); - if (hr != S_OK) - { - ERR("Failed to copy comparison data into buffer, hr = 0x%08lx\n", hr); - HeapFree(GetProcessHeap(), 0, *moniker_data); - return hr; - } - return S_OK; -} - -/*********************************************************************** - * RunningObjectTable_QueryInterface - */ -static HRESULT WINAPI -RunningObjectTableImpl_QueryInterface(IRunningObjectTable* iface, - REFIID riid,void** ppvObject) -{ - RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; - - TRACE("(%p,%p,%p)\n",This,riid,ppvObject); - - /* validate arguments */ - - if (ppvObject==0) - return E_INVALIDARG; - - *ppvObject = 0; - - if (IsEqualIID(&IID_IUnknown, riid) || - IsEqualIID(&IID_IRunningObjectTable, riid)) - *ppvObject = (IRunningObjectTable*)This; - - if ((*ppvObject)==0) - return E_NOINTERFACE; - - IRunningObjectTable_AddRef(iface); - - return S_OK; -} - -/*********************************************************************** - * RunningObjectTable_AddRef - */ -static ULONG WINAPI -RunningObjectTableImpl_AddRef(IRunningObjectTable* iface) -{ - RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; - - TRACE("(%p)\n",This); - - return InterlockedIncrement(&This->ref); -} - -/*********************************************************************** - * RunningObjectTable_Initialize - */ -static HRESULT WINAPI -RunningObjectTableImpl_Destroy(void) -{ - struct list *cursor, *cursor2; - - TRACE("()\n"); - - if (runningObjectTableInstance==NULL) - return E_INVALIDARG; - - /* free the ROT table memory */ - LIST_FOR_EACH_SAFE(cursor, cursor2, &runningObjectTableInstance->rot) - { - struct rot_entry *rot_entry = LIST_ENTRY(cursor, struct rot_entry, entry); - list_remove(&rot_entry->entry); - rot_entry_delete(rot_entry); - } - - /* free the ROT structure memory */ - HeapFree(GetProcessHeap(),0,runningObjectTableInstance); - runningObjectTableInstance = NULL; - - return S_OK; -} - -/*********************************************************************** - * RunningObjectTable_Release - */ -static ULONG WINAPI -RunningObjectTableImpl_Release(IRunningObjectTable* iface) -{ - RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; - ULONG ref; - - TRACE("(%p)\n",This); - - ref = InterlockedDecrement(&This->ref); - - /* uninitialize ROT structure if there's no more references to it */ - if (ref == 0) - { - struct list *cursor, *cursor2; - LIST_FOR_EACH_SAFE(cursor, cursor2, &This->rot) - { - struct rot_entry *rot_entry = LIST_ENTRY(cursor, struct rot_entry, entry); - list_remove(&rot_entry->entry); - rot_entry_delete(rot_entry); - } - /* RunningObjectTable data structure will be not destroyed here ! the destruction will be done only - * when RunningObjectTableImpl_UnInitialize function is called - */ - } - - return ref; -} - -/*********************************************************************** - * RunningObjectTable_Register - * - * PARAMS - * grfFlags [in] Registration options - * punkObject [in] the object being registered - * pmkObjectName [in] the moniker of the object being registered - * pdwRegister [in] the value identifying the registration - */ -static HRESULT WINAPI -RunningObjectTableImpl_Register(IRunningObjectTable* iface, DWORD grfFlags, - IUnknown *punkObject, IMoniker *pmkObjectName, DWORD *pdwRegister) -{ - RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; - struct rot_entry *rot_entry; - HRESULT hr = S_OK; - IStream *pStream = NULL; - DWORD mshlflags; - - TRACE("(%p,%ld,%p,%p,%p)\n",This,grfFlags,punkObject,pmkObjectName,pdwRegister); - - /* - * there's only two types of register : strong and or weak registration - * (only one must be passed on parameter) - */ - if ( ( (grfFlags & ROTFLAGS_REGISTRATIONKEEPSALIVE) || !(grfFlags & ROTFLAGS_ALLOWANYCLIENT)) && - (!(grfFlags & ROTFLAGS_REGISTRATIONKEEPSALIVE) || (grfFlags & ROTFLAGS_ALLOWANYCLIENT)) && - (grfFlags) ) - { - ERR("Invalid combination of ROTFLAGS: %lx\n", grfFlags); - return E_INVALIDARG; - } - - if (punkObject==NULL || pmkObjectName==NULL || pdwRegister==NULL) - return E_INVALIDARG; - - rot_entry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*rot_entry)); - if (!rot_entry) - return E_OUTOFMEMORY; - - CoFileTimeNow(&rot_entry->last_modified); - - /* marshal object */ - hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream); - if (hr != S_OK) - { - rot_entry_delete(rot_entry); - return hr; - } - mshlflags = (grfFlags & ROTFLAGS_REGISTRATIONKEEPSALIVE) ? MSHLFLAGS_TABLESTRONG : MSHLFLAGS_TABLEWEAK; - hr = CoMarshalInterface(pStream, &IID_IUnknown, punkObject, MSHCTX_LOCAL | MSHCTX_NOSHAREDMEM, NULL, mshlflags); - /* FIXME: a cleaner way would be to create an IStream class that writes - * directly to an MInterfacePointer */ - if (hr == S_OK) - { - HGLOBAL hglobal; - hr = GetHGlobalFromStream(pStream, &hglobal); - if (hr == S_OK) - { - SIZE_T size = GlobalSize(hglobal); - const void *pv = GlobalLock(hglobal); - rot_entry->object = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MInterfacePointer, abData[size])); - rot_entry->object->ulCntData = size; - memcpy(&rot_entry->object->abData, pv, size); - GlobalUnlock(hglobal); - } - } - IStream_Release(pStream); - if (hr != S_OK) - { - rot_entry_delete(rot_entry); - return hr; - } - - hr = get_moniker_comparison_data(pmkObjectName, &rot_entry->moniker_data); - if (hr != S_OK) - { - rot_entry_delete(rot_entry); - return hr; - } - - hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream); - if (hr != S_OK) - { - rot_entry_delete(rot_entry); - return hr; - } - /* marshal moniker */ - hr = CoMarshalInterface(pStream, &IID_IMoniker, (IUnknown *)pmkObjectName, MSHCTX_LOCAL | MSHCTX_NOSHAREDMEM, NULL, MSHLFLAGS_TABLESTRONG); - /* FIXME: a cleaner way would be to create an IStream class that writes - * directly to an MInterfacePointer */ - if (hr == S_OK) - { - HGLOBAL hglobal; - hr = GetHGlobalFromStream(pStream, &hglobal); - if (hr == S_OK) - { - SIZE_T size = GlobalSize(hglobal); - const void *pv = GlobalLock(hglobal); - rot_entry->moniker = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MInterfacePointer, abData[size])); - rot_entry->moniker->ulCntData = size; - memcpy(&rot_entry->moniker->abData, pv, size); - GlobalUnlock(hglobal); - } - } - IStream_Release(pStream); - if (hr != S_OK) - { - rot_entry_delete(rot_entry); - return hr; - } - - /* FIXME: not the right signature of IrotRegister function */ - hr = IrotRegister(&rot_entry->cookie); - if (hr != S_OK) - { - rot_entry_delete(rot_entry); - return hr; - } - - /* gives a registration identifier to the registered object*/ - *pdwRegister = rot_entry->cookie; - - EnterCriticalSection(&This->lock); - /* FIXME: see if object was registered before and return MK_S_MONIKERALREADYREGISTERED */ - list_add_tail(&This->rot, &rot_entry->entry); - LeaveCriticalSection(&This->lock); - - return hr; -} - -/*********************************************************************** - * RunningObjectTable_Revoke - * - * PARAMS - * dwRegister [in] Value identifying registration to be revoked - */ -static HRESULT WINAPI -RunningObjectTableImpl_Revoke( IRunningObjectTable* iface, DWORD dwRegister) -{ - RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; - struct rot_entry *rot_entry; - - TRACE("(%p,%ld)\n",This,dwRegister); - - EnterCriticalSection(&This->lock); - LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry) - { - if (rot_entry->cookie == dwRegister) - { - list_remove(&rot_entry->entry); - LeaveCriticalSection(&This->lock); - - rot_entry_delete(rot_entry); - return S_OK; - } - } - LeaveCriticalSection(&This->lock); - - return E_INVALIDARG; -} - -/*********************************************************************** - * RunningObjectTable_IsRunning - * - * PARAMS - * pmkObjectName [in] moniker of the object whose status is desired - */ -static HRESULT WINAPI -RunningObjectTableImpl_IsRunning( IRunningObjectTable* iface, IMoniker *pmkObjectName) -{ - RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; - MInterfacePointer *moniker_data; - HRESULT hr; - struct rot_entry *rot_entry; - - TRACE("(%p,%p)\n",This,pmkObjectName); - - hr = get_moniker_comparison_data(pmkObjectName, &moniker_data); - if (hr != S_OK) - return hr; - - hr = S_FALSE; - EnterCriticalSection(&This->lock); - LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry) - { - if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) && - !memcmp(moniker_data, rot_entry->moniker_data, moniker_data->ulCntData)) - { - hr = S_OK; - break; - } - } - LeaveCriticalSection(&This->lock); - - /* FIXME: call IrotIsRunning */ - - HeapFree(GetProcessHeap(), 0, moniker_data); - - return hr; -} - -/*********************************************************************** - * RunningObjectTable_GetObject - * - * PARAMS - * pmkObjectName [in] Pointer to the moniker on the object - * ppunkObject [out] variable that receives the IUnknown interface pointer - */ -static HRESULT WINAPI -RunningObjectTableImpl_GetObject( IRunningObjectTable* iface, - IMoniker *pmkObjectName, IUnknown **ppunkObject) -{ - RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; - MInterfacePointer *moniker_data; - HRESULT hr; - struct rot_entry *rot_entry; - - TRACE("(%p,%p,%p)\n",This,pmkObjectName,ppunkObject); - - if (ppunkObject == NULL) - return E_POINTER; - - *ppunkObject = NULL; - - hr = get_moniker_comparison_data(pmkObjectName, &moniker_data); - if (hr != S_OK) - return hr; - - EnterCriticalSection(&This->lock); - LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry) - { - if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) && - !memcmp(moniker_data, rot_entry->moniker_data, moniker_data->ulCntData)) - { - IStream *pStream; - hr = create_stream_on_mip_ro(rot_entry->object, &pStream); - if (hr == S_OK) - { - hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)ppunkObject); - IStream_Release(pStream); - } - - LeaveCriticalSection(&This->lock); - HeapFree(GetProcessHeap(), 0, moniker_data); - - return hr; - } - } - LeaveCriticalSection(&This->lock); - - /* FIXME: call IrotGetObject */ - WARN("Moniker unavailable - app may require interprocess running object table\n"); - hr = MK_E_UNAVAILABLE; - - HeapFree(GetProcessHeap(), 0, moniker_data); - - return hr; -} - -/*********************************************************************** - * RunningObjectTable_NoteChangeTime - * - * PARAMS - * dwRegister [in] Value identifying registration being updated - * pfiletime [in] Pointer to structure containing object's last change time - */ -static HRESULT WINAPI -RunningObjectTableImpl_NoteChangeTime(IRunningObjectTable* iface, - DWORD dwRegister, FILETIME *pfiletime) -{ - RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; - struct rot_entry *rot_entry; - - TRACE("(%p,%ld,%p)\n",This,dwRegister,pfiletime); - - EnterCriticalSection(&This->lock); - LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry) - { - if (rot_entry->cookie == dwRegister) - { - rot_entry->last_modified = *pfiletime; - LeaveCriticalSection(&This->lock); - return S_OK; - } - } - LeaveCriticalSection(&This->lock); - - /* FIXME: call IrotNoteChangeTime */ - - return E_INVALIDARG; -} - -/*********************************************************************** - * RunningObjectTable_GetTimeOfLastChange - * - * PARAMS - * pmkObjectName [in] moniker of the object whose status is desired - * pfiletime [out] structure that receives object's last change time - */ -static HRESULT WINAPI -RunningObjectTableImpl_GetTimeOfLastChange(IRunningObjectTable* iface, - IMoniker *pmkObjectName, FILETIME *pfiletime) -{ - HRESULT hr = MK_E_UNAVAILABLE; - RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; - MInterfacePointer *moniker_data; - struct rot_entry *rot_entry; - - TRACE("(%p,%p,%p)\n",This,pmkObjectName,pfiletime); - - if (pmkObjectName==NULL || pfiletime==NULL) - return E_INVALIDARG; - - hr = get_moniker_comparison_data(pmkObjectName, &moniker_data); - if (hr != S_OK) - return hr; - - hr = MK_E_UNAVAILABLE; - - EnterCriticalSection(&This->lock); - LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry) - { - if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) && - !memcmp(moniker_data, rot_entry->moniker_data, moniker_data->ulCntData)) - { - *pfiletime = rot_entry->last_modified; - hr = S_OK; - break; - } - } - LeaveCriticalSection(&This->lock); - - /* FIXME: if (hr != S_OK) call IrotGetTimeOfLastChange */ - - HeapFree(GetProcessHeap(), 0, moniker_data); - return hr; -} - -/*********************************************************************** - * RunningObjectTable_EnumRunning - * - * PARAMS - * ppenumMoniker [out] receives the IEnumMoniker interface pointer - */ -static HRESULT WINAPI -RunningObjectTableImpl_EnumRunning(IRunningObjectTable* iface, - IEnumMoniker **ppenumMoniker) -{ - HRESULT hr; - RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; - MInterfacePointer **monikers; - ULONG moniker_count = 0; - const struct rot_entry *rot_entry; - ULONG i = 0; - - EnterCriticalSection(&This->lock); - - LIST_FOR_EACH_ENTRY( rot_entry, &This->rot, const struct rot_entry, entry ) - moniker_count++; - - monikers = HeapAlloc(GetProcessHeap(), 0, moniker_count * sizeof(*monikers)); - - LIST_FOR_EACH_ENTRY( rot_entry, &This->rot, const struct rot_entry, entry ) - { - SIZE_T size = FIELD_OFFSET(MInterfacePointer, abData[rot_entry->moniker->ulCntData]); - monikers[i] = HeapAlloc(GetProcessHeap(), 0, size); - memcpy(monikers[i], rot_entry->moniker, size); - i++; - } - - LeaveCriticalSection(&This->lock); - - /* FIXME: call IrotEnumRunning and append data */ - - hr = EnumMonikerImpl_CreateEnumROTMoniker(monikers, moniker_count, 0, ppenumMoniker); - - return hr; -} - -/****************************************************************************** - * GetRunningObjectTable (OLE2.30) - */ -HRESULT WINAPI -GetRunningObjectTable16(DWORD reserved, LPRUNNINGOBJECTTABLE *pprot) -{ - FIXME("(%ld,%p),stub!\n",reserved,pprot); - return E_NOTIMPL; -} - -/*********************************************************************** - * GetRunningObjectTable (OLE32.@) - */ -HRESULT WINAPI -GetRunningObjectTable(DWORD reserved, LPRUNNINGOBJECTTABLE *pprot) -{ - IID riid=IID_IRunningObjectTable; - HRESULT res; - - TRACE("()\n"); - - if (reserved!=0) - return E_UNEXPECTED; - - if(runningObjectTableInstance==NULL) - return CO_E_NOTINITIALIZED; - - res = IRunningObjectTable_QueryInterface((IRunningObjectTable*)runningObjectTableInstance,&riid,(void**)pprot); - - return res; -} - -/****************************************************************************** - * OleRun [OLE32.@] - */ -HRESULT WINAPI OleRun(LPUNKNOWN pUnknown) -{ - IRunnableObject *runable; - IRunnableObject *This = (IRunnableObject *)pUnknown; - LRESULT ret; - - ret = IRunnableObject_QueryInterface(This,&IID_IRunnableObject,(LPVOID*)&runable); - if (ret) - return 0; /* Appears to return no error. */ - ret = IRunnableObject_Run(runable,NULL); - IRunnableObject_Release(runable); - return ret; -} - -/****************************************************************************** - * MkParseDisplayName [OLE32.@] - */ -HRESULT WINAPI MkParseDisplayName(LPBC pbc, LPCOLESTR szUserName, - LPDWORD pchEaten, LPMONIKER *ppmk) -{ - FIXME("(%p, %s, %p, %p): stub.\n", pbc, debugstr_w(szUserName), pchEaten, *ppmk); - - if (!(IsValidInterface((LPUNKNOWN) pbc))) - return E_INVALIDARG; - - return MK_E_SYNTAX; -} - -/****************************************************************************** - * CreateClassMoniker [OLE32.@] - */ -HRESULT WINAPI CreateClassMoniker(REFCLSID rclsid, IMoniker ** ppmk) -{ - FIXME("%s\n", debugstr_guid( rclsid )); - if( ppmk ) - *ppmk = NULL; - return E_NOTIMPL; -} - -/* Virtual function table for the IRunningObjectTable class. */ -static IRunningObjectTableVtbl VT_RunningObjectTableImpl = -{ - RunningObjectTableImpl_QueryInterface, - RunningObjectTableImpl_AddRef, - RunningObjectTableImpl_Release, - RunningObjectTableImpl_Register, - RunningObjectTableImpl_Revoke, - RunningObjectTableImpl_IsRunning, - RunningObjectTableImpl_GetObject, - RunningObjectTableImpl_NoteChangeTime, - RunningObjectTableImpl_GetTimeOfLastChange, - RunningObjectTableImpl_EnumRunning -}; - -/*********************************************************************** - * RunningObjectTable_Initialize - */ -HRESULT WINAPI RunningObjectTableImpl_Initialize(void) -{ - TRACE("\n"); - - /* create the unique instance of the RunningObjectTableImpl structure */ - runningObjectTableInstance = HeapAlloc(GetProcessHeap(), 0, sizeof(RunningObjectTableImpl)); - - if (!runningObjectTableInstance) - return E_OUTOFMEMORY; - - /* initialize the virtual table function */ - runningObjectTableInstance->lpVtbl = &VT_RunningObjectTableImpl; - - /* the initial reference is set to "1" ! because if set to "0" it will be not practis when */ - /* the ROT referred many times not in the same time (all the objects in the ROT will */ - /* be removed every time the ROT is removed ) */ - runningObjectTableInstance->ref = 1; - - list_init(&runningObjectTableInstance->rot); - InitializeCriticalSection(&runningObjectTableInstance->lock); - - return S_OK; -} - -/*********************************************************************** - * RunningObjectTable_UnInitialize - */ -HRESULT WINAPI RunningObjectTableImpl_UnInitialize() -{ - TRACE("\n"); - - if (runningObjectTableInstance==NULL) - return E_POINTER; - - RunningObjectTableImpl_Release((IRunningObjectTable*)runningObjectTableInstance); - - RunningObjectTableImpl_Destroy(); - - return S_OK; -} - -/*********************************************************************** - * EnumMoniker_QueryInterface - */ -static HRESULT WINAPI EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject) -{ - EnumMonikerImpl *This = (EnumMonikerImpl *)iface; - - TRACE("(%p,%p,%p)\n",This,riid,ppvObject); - - /* validate arguments */ - if (ppvObject == NULL) - return E_INVALIDARG; - - *ppvObject = NULL; - - if (IsEqualIID(&IID_IUnknown, riid)) - *ppvObject = (IEnumMoniker*)This; - else - if (IsEqualIID(&IID_IEnumMoniker, riid)) - *ppvObject = (IEnumMoniker*)This; - - if ((*ppvObject)==NULL) - return E_NOINTERFACE; - - IEnumMoniker_AddRef(iface); - - return S_OK; -} - -/*********************************************************************** - * EnumMoniker_AddRef - */ -static ULONG WINAPI EnumMonikerImpl_AddRef(IEnumMoniker* iface) -{ - EnumMonikerImpl *This = (EnumMonikerImpl *)iface; - - TRACE("(%p)\n",This); - - return InterlockedIncrement(&This->ref); -} - -/*********************************************************************** - * EnumMoniker_release - */ -static ULONG WINAPI EnumMonikerImpl_Release(IEnumMoniker* iface) -{ - EnumMonikerImpl *This = (EnumMonikerImpl *)iface; - ULONG ref; - - TRACE("(%p)\n",This); - - ref = InterlockedDecrement(&This->ref); - - /* unitialize rot structure if there's no more reference to it*/ - if (ref == 0) - { - ULONG i; - - TRACE("(%p) Deleting\n",This); - - for (i = 0; i < This->moniker_count; i++) - HeapFree(GetProcessHeap(), 0, This->monikers[i]); - HeapFree(GetProcessHeap(), 0, This->monikers); - HeapFree(GetProcessHeap(), 0, This); - } - - return ref; -} -/*********************************************************************** - * EnmumMoniker_Next - */ -static HRESULT WINAPI EnumMonikerImpl_Next(IEnumMoniker* iface, ULONG celt, IMoniker** rgelt, ULONG * pceltFetched) -{ - ULONG i; - EnumMonikerImpl *This = (EnumMonikerImpl *)iface; - HRESULT hr = S_OK; - - TRACE("(%p) TabCurrentPos %ld Tablastindx %ld\n", This, This->pos, This->moniker_count); - - /* retrieve the requested number of moniker from the current position */ - for(i = 0; (This->pos < This->moniker_count) && (i < celt); i++) - { - IStream *stream; - hr = create_stream_on_mip_ro(This->monikers[This->pos++], &stream); - if (hr != S_OK) break; - hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void **)&rgelt[i]); - IStream_Release(stream); - if (hr != S_OK) break; - } - - if (pceltFetched != NULL) - *pceltFetched= i; - - if (hr != S_OK) - return hr; - - if (i == celt) - return S_OK; - else - return S_FALSE; - -} - -/*********************************************************************** - * EnmumMoniker_Skip - */ -static HRESULT WINAPI EnumMonikerImpl_Skip(IEnumMoniker* iface, ULONG celt) -{ - EnumMonikerImpl *This = (EnumMonikerImpl *)iface; - - TRACE("(%p)\n",This); - - if (This->pos + celt >= This->moniker_count) - return S_FALSE; - - This->pos += celt; - - return S_OK; -} - -/*********************************************************************** - * EnmumMoniker_Reset - */ -static HRESULT WINAPI EnumMonikerImpl_Reset(IEnumMoniker* iface) -{ - EnumMonikerImpl *This = (EnumMonikerImpl *)iface; - - This->pos = 0; /* set back to start of list */ - - TRACE("(%p)\n",This); - - return S_OK; -} - -/*********************************************************************** - * EnmumMoniker_Clone - */ -static HRESULT WINAPI EnumMonikerImpl_Clone(IEnumMoniker* iface, IEnumMoniker ** ppenum) -{ - EnumMonikerImpl *This = (EnumMonikerImpl *)iface; - MInterfacePointer **monikers = HeapAlloc(GetProcessHeap(), 0, sizeof(*monikers)*This->moniker_count); - ULONG i; - - TRACE("(%p)\n",This); - - for (i = 0; i < This->moniker_count; i++) - { - SIZE_T size = FIELD_OFFSET(MInterfacePointer, abData[This->monikers[i]->ulCntData]); - monikers[i] = HeapAlloc(GetProcessHeap(), 0, size); - memcpy(monikers[i], This->monikers[i], size); - } - - /* copy the enum structure */ - return EnumMonikerImpl_CreateEnumROTMoniker(monikers, This->moniker_count, - This->pos, ppenum); -} - -/* Virtual function table for the IEnumMoniker class. */ -static const IEnumMonikerVtbl VT_EnumMonikerImpl = -{ - EnumMonikerImpl_QueryInterface, - EnumMonikerImpl_AddRef, - EnumMonikerImpl_Release, - EnumMonikerImpl_Next, - EnumMonikerImpl_Skip, - EnumMonikerImpl_Reset, - EnumMonikerImpl_Clone -}; - -/*********************************************************************** - * EnumMonikerImpl_CreateEnumROTMoniker - * Used by EnumRunning to create the structure and EnumClone - * to copy the structure - */ -static HRESULT WINAPI EnumMonikerImpl_CreateEnumROTMoniker(MInterfacePointer **monikers, - ULONG moniker_count, - ULONG current_pos, - IEnumMoniker **ppenumMoniker) -{ - EnumMonikerImpl* This = NULL; - - if (!ppenumMoniker) - return E_INVALIDARG; - - This = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumMonikerImpl)); - if (!This) return E_OUTOFMEMORY; - - TRACE("(%p)\n", This); - - /* initialize the virtual table function */ - This->lpVtbl = &VT_EnumMonikerImpl; - - /* the initial reference is set to "1" */ - This->ref = 1; /* set the ref count to one */ - This->pos = 0; /* Set the list start posn to start */ - This->moniker_count = moniker_count; /* Need the same size table as ROT */ - This->monikers = monikers; - - *ppenumMoniker = (IEnumMoniker*)This; - - return S_OK; -} - - -/* Shared implementation of moniker marshaler based on saving and loading of - * monikers */ - -#define ICOM_THIS_From_IMoniker(class, name) class* This = (class*)(((char*)name)-FIELD_OFFSET(class, lpVtblMarshal)) - -typedef struct MonikerMarshal -{ - const IUnknownVtbl *lpVtbl; - const IMarshalVtbl *lpVtblMarshal; - - ULONG ref; - IMoniker *moniker; -} MonikerMarshal; - -static HRESULT WINAPI MonikerMarshalInner_QueryInterface(IUnknown *iface, REFIID riid, LPVOID *ppv) -{ - MonikerMarshal *This = (MonikerMarshal *)iface; - TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); - *ppv = NULL; - if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IMarshal, riid)) - { - *ppv = &This->lpVtblMarshal; - IUnknown_AddRef((IUnknown *)&This->lpVtblMarshal); - return S_OK; - } - FIXME("No interface for %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI MonikerMarshalInner_AddRef(IUnknown *iface) -{ - MonikerMarshal *This = (MonikerMarshal *)iface; - return InterlockedIncrement(&This->ref); -} - -static ULONG WINAPI MonikerMarshalInner_Release(IUnknown *iface) -{ - MonikerMarshal *This = (MonikerMarshal *)iface; - ULONG ref = InterlockedDecrement(&This->ref); - - if (!ref) HeapFree(GetProcessHeap(), 0, This); - return ref; -} - -static const IUnknownVtbl VT_MonikerMarshalInner = -{ - MonikerMarshalInner_QueryInterface, - MonikerMarshalInner_AddRef, - MonikerMarshalInner_Release -}; - -static HRESULT WINAPI MonikerMarshal_QueryInterface(IMarshal *iface, REFIID riid, LPVOID *ppv) -{ - ICOM_THIS_From_IMoniker(MonikerMarshal, iface); - return IMoniker_QueryInterface(This->moniker, riid, ppv); -} - -static ULONG WINAPI MonikerMarshal_AddRef(IMarshal *iface) -{ - ICOM_THIS_From_IMoniker(MonikerMarshal, iface); - return IMoniker_AddRef(This->moniker); -} - -static ULONG WINAPI MonikerMarshal_Release(IMarshal *iface) -{ - ICOM_THIS_From_IMoniker(MonikerMarshal, iface); - return IMoniker_Release(This->moniker); -} - -static HRESULT WINAPI MonikerMarshal_GetUnmarshalClass( - LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, - void* pvDestContext, DWORD mshlflags, CLSID* pCid) -{ - ICOM_THIS_From_IMoniker(MonikerMarshal, iface); - - TRACE("(%s, %p, %lx, %p, %lx, %p)\n", debugstr_guid(riid), pv, - dwDestContext, pvDestContext, mshlflags, pCid); - - return IMoniker_GetClassID(This->moniker, pCid); -} - -static HRESULT WINAPI MonikerMarshal_GetMarshalSizeMax( - LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, - void* pvDestContext, DWORD mshlflags, DWORD* pSize) -{ - ICOM_THIS_From_IMoniker(MonikerMarshal, iface); - HRESULT hr; - ULARGE_INTEGER size; - - TRACE("(%s, %p, %lx, %p, %lx, %p)\n", debugstr_guid(riid), pv, - dwDestContext, pvDestContext, mshlflags, pSize); - - hr = IMoniker_GetSizeMax(This->moniker, &size); - if (hr == S_OK) - *pSize = (DWORD)size.QuadPart; - return hr; -} - -static HRESULT WINAPI MonikerMarshal_MarshalInterface(LPMARSHAL iface, IStream *pStm, - REFIID riid, void* pv, DWORD dwDestContext, - void* pvDestContext, DWORD mshlflags) -{ - ICOM_THIS_From_IMoniker(MonikerMarshal, iface); - - TRACE("(%p, %s, %p, %lx, %p, %lx)\n", pStm, debugstr_guid(riid), pv, - dwDestContext, pvDestContext, mshlflags); - - return IMoniker_Save(This->moniker, pStm, FALSE); -} - -static HRESULT WINAPI MonikerMarshal_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv) -{ - ICOM_THIS_From_IMoniker(MonikerMarshal, iface); - HRESULT hr; - - TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv); - - hr = IMoniker_Load(This->moniker, pStm); - if (hr == S_OK) - hr = IMoniker_QueryInterface(This->moniker, riid, ppv); - return hr; -} - -static HRESULT WINAPI MonikerMarshal_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm) -{ - TRACE("()\n"); - /* can't release a state-based marshal as nothing on server side to - * release */ - return S_OK; -} - -static HRESULT WINAPI MonikerMarshal_DisconnectObject(LPMARSHAL iface, DWORD dwReserved) -{ - TRACE("()\n"); - /* can't disconnect a state-based marshal as nothing on server side to - * disconnect from */ - return S_OK; -} - -static const IMarshalVtbl VT_MonikerMarshal = -{ - MonikerMarshal_QueryInterface, - MonikerMarshal_AddRef, - MonikerMarshal_Release, - MonikerMarshal_GetUnmarshalClass, - MonikerMarshal_GetMarshalSizeMax, - MonikerMarshal_MarshalInterface, - MonikerMarshal_UnmarshalInterface, - MonikerMarshal_ReleaseMarshalData, - MonikerMarshal_DisconnectObject -}; - -HRESULT MonikerMarshal_Create(IMoniker *inner, IUnknown **outer) -{ - MonikerMarshal *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); - if (!This) return E_OUTOFMEMORY; - - This->lpVtbl = &VT_MonikerMarshalInner; - This->lpVtblMarshal = &VT_MonikerMarshal; - This->ref = 1; - This->moniker = inner; - - *outer = (IUnknown *)&This->lpVtbl; - return S_OK; -} +/* + * Monikers + * + * Copyright 1998 Marcus Meissner + * Copyright 1999 Noomen Hamza + * Copyright 2005 Robert Shearman (for CodeWeavers) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * TODO: + * - IRunningObjectTable should work interprocess, but currently doesn't. + * Native (on Win2k at least) uses an undocumented RPC interface, IROT, to + * communicate with RPCSS which contains the table of marshalled data. + */ + +#include <assert.h> +#include <stdarg.h> +#include <string.h> + +#define COBJMACROS + +#include "winerror.h" +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "wtypes.h" +#include "ole2.h" + +#include "wine/list.h" +#include "wine/debug.h" + +#include "compobj_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/* define the structure of the running object table elements */ +struct rot_entry +{ + struct list entry; + MInterfacePointer* object; /* marshaled running object*/ + MInterfacePointer* moniker; /* marshaled moniker that identifies this object */ + MInterfacePointer* moniker_data; /* moniker comparison data that identifies this object */ + DWORD cookie; /* cookie identifying this object */ + FILETIME last_modified; +}; + +/* define the RunningObjectTableImpl structure */ +typedef struct RunningObjectTableImpl +{ + const IRunningObjectTableVtbl *lpVtbl; + ULONG ref; + + struct list rot; /* list of ROT entries */ + CRITICAL_SECTION lock; +} RunningObjectTableImpl; + +static RunningObjectTableImpl* runningObjectTableInstance = NULL; + + + +static inline HRESULT WINAPI +IrotRegister(DWORD *cookie) +{ + static DWORD last_cookie = 1; + *cookie = InterlockedIncrement(&last_cookie); + return S_OK; +} + +/* define the EnumMonikerImpl structure */ +typedef struct EnumMonikerImpl +{ + const IEnumMonikerVtbl *lpVtbl; + ULONG ref; + + MInterfacePointer **monikers; + ULONG moniker_count; + ULONG pos; +} EnumMonikerImpl; + + +/* IEnumMoniker Local functions*/ +static HRESULT WINAPI EnumMonikerImpl_CreateEnumROTMoniker(MInterfacePointer **monikers, + ULONG moniker_count, ULONG pos, IEnumMoniker **ppenumMoniker); + +static HRESULT create_stream_on_mip_ro(const MInterfacePointer *mip, IStream **stream) +{ + HGLOBAL hglobal = GlobalAlloc(0, mip->ulCntData); + void *pv = GlobalLock(hglobal); + memcpy(pv, mip->abData, mip->ulCntData); + GlobalUnlock(hglobal); + return CreateStreamOnHGlobal(hglobal, TRUE, stream); +} + +static inline void rot_entry_delete(struct rot_entry *rot_entry) +{ + /* FIXME: revoke entry from rpcss's copy of the ROT */ + if (rot_entry->object) + { + IStream *stream; + HRESULT hr; + hr = create_stream_on_mip_ro(rot_entry->object, &stream); + if (hr == S_OK) + { + CoReleaseMarshalData(stream); + IUnknown_Release(stream); + } + } + if (rot_entry->moniker) + { + IStream *stream; + HRESULT hr; + hr = create_stream_on_mip_ro(rot_entry->moniker, &stream); + if (hr == S_OK) + { + CoReleaseMarshalData(stream); + IUnknown_Release(stream); + } + } + HeapFree(GetProcessHeap(), 0, rot_entry->object); + HeapFree(GetProcessHeap(), 0, rot_entry->moniker); + HeapFree(GetProcessHeap(), 0, rot_entry->moniker_data); + HeapFree(GetProcessHeap(), 0, rot_entry); +} + +/* moniker_data must be freed with HeapFree when no longer in use */ +static HRESULT get_moniker_comparison_data(IMoniker *pMoniker, MInterfacePointer **moniker_data) +{ + HRESULT hr; + IROTData *pROTData = NULL; + ULONG size = 0; + hr = IMoniker_QueryInterface(pMoniker, &IID_IROTData, (void *)&pROTData); + if (hr != S_OK) + { + ERR("Failed to query moniker for IROTData interface, hr = 0x%08lx\n", hr); + return hr; + } + IROTData_GetComparisonData(pROTData, NULL, 0, &size); + *moniker_data = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MInterfacePointer, abData[size])); + (*moniker_data)->ulCntData = size; + hr = IROTData_GetComparisonData(pROTData, (*moniker_data)->abData, size, &size); + if (hr != S_OK) + { + ERR("Failed to copy comparison data into buffer, hr = 0x%08lx\n", hr); + HeapFree(GetProcessHeap(), 0, *moniker_data); + return hr; + } + return S_OK; +} + +/*********************************************************************** + * RunningObjectTable_QueryInterface + */ +static HRESULT WINAPI +RunningObjectTableImpl_QueryInterface(IRunningObjectTable* iface, + REFIID riid,void** ppvObject) +{ + RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; + + TRACE("(%p,%p,%p)\n",This,riid,ppvObject); + + /* validate arguments */ + + if (ppvObject==0) + return E_INVALIDARG; + + *ppvObject = 0; + + if (IsEqualIID(&IID_IUnknown, riid) || + IsEqualIID(&IID_IRunningObjectTable, riid)) + *ppvObject = (IRunningObjectTable*)This; + + if ((*ppvObject)==0) + return E_NOINTERFACE; + + IRunningObjectTable_AddRef(iface); + + return S_OK; +} + +/*********************************************************************** + * RunningObjectTable_AddRef + */ +static ULONG WINAPI +RunningObjectTableImpl_AddRef(IRunningObjectTable* iface) +{ + RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; + + TRACE("(%p)\n",This); + + return InterlockedIncrement(&This->ref); +} + +/*********************************************************************** + * RunningObjectTable_Initialize + */ +static HRESULT WINAPI +RunningObjectTableImpl_Destroy(void) +{ + struct list *cursor, *cursor2; + + TRACE("()\n"); + + if (runningObjectTableInstance==NULL) + return E_INVALIDARG; + + /* free the ROT table memory */ + LIST_FOR_EACH_SAFE(cursor, cursor2, &runningObjectTableInstance->rot) + { + struct rot_entry *rot_entry = LIST_ENTRY(cursor, struct rot_entry, entry); + list_remove(&rot_entry->entry); + rot_entry_delete(rot_entry); + } + + /* free the ROT structure memory */ + HeapFree(GetProcessHeap(),0,runningObjectTableInstance); + runningObjectTableInstance = NULL; + + return S_OK; +} + +/*********************************************************************** + * RunningObjectTable_Release + */ +static ULONG WINAPI +RunningObjectTableImpl_Release(IRunningObjectTable* iface) +{ + RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; + ULONG ref; + + TRACE("(%p)\n",This); + + ref = InterlockedDecrement(&This->ref); + + /* uninitialize ROT structure if there's no more references to it */ + if (ref == 0) + { + struct list *cursor, *cursor2; + LIST_FOR_EACH_SAFE(cursor, cursor2, &This->rot) + { + struct rot_entry *rot_entry = LIST_ENTRY(cursor, struct rot_entry, entry); + list_remove(&rot_entry->entry); + rot_entry_delete(rot_entry); + } + /* RunningObjectTable data structure will be not destroyed here ! the destruction will be done only + * when RunningObjectTableImpl_UnInitialize function is called + */ + } + + return ref; +} + +/*********************************************************************** + * RunningObjectTable_Register + * + * PARAMS + * grfFlags [in] Registration options + * punkObject [in] the object being registered + * pmkObjectName [in] the moniker of the object being registered + * pdwRegister [in] the value identifying the registration + */ +static HRESULT WINAPI +RunningObjectTableImpl_Register(IRunningObjectTable* iface, DWORD grfFlags, + IUnknown *punkObject, IMoniker *pmkObjectName, DWORD *pdwRegister) +{ + RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; + struct rot_entry *rot_entry; + HRESULT hr = S_OK; + IStream *pStream = NULL; + DWORD mshlflags; + + TRACE("(%p,%ld,%p,%p,%p)\n",This,grfFlags,punkObject,pmkObjectName,pdwRegister); + + /* + * there's only two types of register : strong and or weak registration + * (only one must be passed on parameter) + */ + if ( ( (grfFlags & ROTFLAGS_REGISTRATIONKEEPSALIVE) || !(grfFlags & ROTFLAGS_ALLOWANYCLIENT)) && + (!(grfFlags & ROTFLAGS_REGISTRATIONKEEPSALIVE) || (grfFlags & ROTFLAGS_ALLOWANYCLIENT)) && + (grfFlags) ) + { + ERR("Invalid combination of ROTFLAGS: %lx\n", grfFlags); + return E_INVALIDARG; + } + + if (punkObject==NULL || pmkObjectName==NULL || pdwRegister==NULL) + return E_INVALIDARG; + + rot_entry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*rot_entry)); + if (!rot_entry) + return E_OUTOFMEMORY; + + CoFileTimeNow(&rot_entry->last_modified); + + /* marshal object */ + hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream); + if (hr != S_OK) + { + rot_entry_delete(rot_entry); + return hr; + } + mshlflags = (grfFlags & ROTFLAGS_REGISTRATIONKEEPSALIVE) ? MSHLFLAGS_TABLESTRONG : MSHLFLAGS_TABLEWEAK; + hr = CoMarshalInterface(pStream, &IID_IUnknown, punkObject, MSHCTX_LOCAL | MSHCTX_NOSHAREDMEM, NULL, mshlflags); + /* FIXME: a cleaner way would be to create an IStream class that writes + * directly to an MInterfacePointer */ + if (hr == S_OK) + { + HGLOBAL hglobal; + hr = GetHGlobalFromStream(pStream, &hglobal); + if (hr == S_OK) + { + SIZE_T size = GlobalSize(hglobal); + const void *pv = GlobalLock(hglobal); + rot_entry->object = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MInterfacePointer, abData[size])); + rot_entry->object->ulCntData = size; + memcpy(&rot_entry->object->abData, pv, size); + GlobalUnlock(hglobal); + } + } + IStream_Release(pStream); + if (hr != S_OK) + { + rot_entry_delete(rot_entry); + return hr; + } + + hr = get_moniker_comparison_data(pmkObjectName, &rot_entry->moniker_data); + if (hr != S_OK) + { + rot_entry_delete(rot_entry); + return hr; + } + + hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream); + if (hr != S_OK) + { + rot_entry_delete(rot_entry); + return hr; + } + /* marshal moniker */ + hr = CoMarshalInterface(pStream, &IID_IMoniker, (IUnknown *)pmkObjectName, MSHCTX_LOCAL | MSHCTX_NOSHAREDMEM, NULL, MSHLFLAGS_TABLESTRONG); + /* FIXME: a cleaner way would be to create an IStream class that writes + * directly to an MInterfacePointer */ + if (hr == S_OK) + { + HGLOBAL hglobal; + hr = GetHGlobalFromStream(pStream, &hglobal); + if (hr == S_OK) + { + SIZE_T size = GlobalSize(hglobal); + const void *pv = GlobalLock(hglobal); + rot_entry->moniker = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MInterfacePointer, abData[size])); + rot_entry->moniker->ulCntData = size; + memcpy(&rot_entry->moniker->abData, pv, size); + GlobalUnlock(hglobal); + } + } + IStream_Release(pStream); + if (hr != S_OK) + { + rot_entry_delete(rot_entry); + return hr; + } + + /* FIXME: not the right signature of IrotRegister function */ + hr = IrotRegister(&rot_entry->cookie); + if (hr != S_OK) + { + rot_entry_delete(rot_entry); + return hr; + } + + /* gives a registration identifier to the registered object*/ + *pdwRegister = rot_entry->cookie; + + EnterCriticalSection(&This->lock); + /* FIXME: see if object was registered before and return MK_S_MONIKERALREADYREGISTERED */ + list_add_tail(&This->rot, &rot_entry->entry); + LeaveCriticalSection(&This->lock); + + return hr; +} + +/*********************************************************************** + * RunningObjectTable_Revoke + * + * PARAMS + * dwRegister [in] Value identifying registration to be revoked + */ +static HRESULT WINAPI +RunningObjectTableImpl_Revoke( IRunningObjectTable* iface, DWORD dwRegister) +{ + RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; + struct rot_entry *rot_entry; + + TRACE("(%p,%ld)\n",This,dwRegister); + + EnterCriticalSection(&This->lock); + LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry) + { + if (rot_entry->cookie == dwRegister) + { + list_remove(&rot_entry->entry); + LeaveCriticalSection(&This->lock); + + rot_entry_delete(rot_entry); + return S_OK; + } + } + LeaveCriticalSection(&This->lock); + + return E_INVALIDARG; +} + +/*********************************************************************** + * RunningObjectTable_IsRunning + * + * PARAMS + * pmkObjectName [in] moniker of the object whose status is desired + */ +static HRESULT WINAPI +RunningObjectTableImpl_IsRunning( IRunningObjectTable* iface, IMoniker *pmkObjectName) +{ + RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; + MInterfacePointer *moniker_data; + HRESULT hr; + struct rot_entry *rot_entry; + + TRACE("(%p,%p)\n",This,pmkObjectName); + + hr = get_moniker_comparison_data(pmkObjectName, &moniker_data); + if (hr != S_OK) + return hr; + + hr = S_FALSE; + EnterCriticalSection(&This->lock); + LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry) + { + if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) && + !memcmp(moniker_data, rot_entry->moniker_data, moniker_data->ulCntData)) + { + hr = S_OK; + break; + } + } + LeaveCriticalSection(&This->lock); + + /* FIXME: call IrotIsRunning */ + + HeapFree(GetProcessHeap(), 0, moniker_data); + + return hr; +} + +/*********************************************************************** + * RunningObjectTable_GetObject + * + * PARAMS + * pmkObjectName [in] Pointer to the moniker on the object + * ppunkObject [out] variable that receives the IUnknown interface pointer + */ +static HRESULT WINAPI +RunningObjectTableImpl_GetObject( IRunningObjectTable* iface, + IMoniker *pmkObjectName, IUnknown **ppunkObject) +{ + RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; + MInterfacePointer *moniker_data; + HRESULT hr; + struct rot_entry *rot_entry; + + TRACE("(%p,%p,%p)\n",This,pmkObjectName,ppunkObject); + + if (ppunkObject == NULL) + return E_POINTER; + + *ppunkObject = NULL; + + hr = get_moniker_comparison_data(pmkObjectName, &moniker_data); + if (hr != S_OK) + return hr; + + EnterCriticalSection(&This->lock); + LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry) + { + if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) && + !memcmp(moniker_data, rot_entry->moniker_data, moniker_data->ulCntData)) + { + IStream *pStream; + hr = create_stream_on_mip_ro(rot_entry->object, &pStream); + if (hr == S_OK) + { + hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)ppunkObject); + IStream_Release(pStream); + } + + LeaveCriticalSection(&This->lock); + HeapFree(GetProcessHeap(), 0, moniker_data); + + return hr; + } + } + LeaveCriticalSection(&This->lock); + + /* FIXME: call IrotGetObject */ + WARN("Moniker unavailable - app may require interprocess running object table\n"); + hr = MK_E_UNAVAILABLE; + + HeapFree(GetProcessHeap(), 0, moniker_data); + + return hr; +} + +/*********************************************************************** + * RunningObjectTable_NoteChangeTime + * + * PARAMS + * dwRegister [in] Value identifying registration being updated + * pfiletime [in] Pointer to structure containing object's last change time + */ +static HRESULT WINAPI +RunningObjectTableImpl_NoteChangeTime(IRunningObjectTable* iface, + DWORD dwRegister, FILETIME *pfiletime) +{ + RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; + struct rot_entry *rot_entry; + + TRACE("(%p,%ld,%p)\n",This,dwRegister,pfiletime); + + EnterCriticalSection(&This->lock); + LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry) + { + if (rot_entry->cookie == dwRegister) + { + rot_entry->last_modified = *pfiletime; + LeaveCriticalSection(&This->lock); + return S_OK; + } + } + LeaveCriticalSection(&This->lock); + + /* FIXME: call IrotNoteChangeTime */ + + return E_INVALIDARG; +} + +/*********************************************************************** + * RunningObjectTable_GetTimeOfLastChange + * + * PARAMS + * pmkObjectName [in] moniker of the object whose status is desired + * pfiletime [out] structure that receives object's last change time + */ +static HRESULT WINAPI +RunningObjectTableImpl_GetTimeOfLastChange(IRunningObjectTable* iface, + IMoniker *pmkObjectName, FILETIME *pfiletime) +{ + HRESULT hr = MK_E_UNAVAILABLE; + RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; + MInterfacePointer *moniker_data; + struct rot_entry *rot_entry; + + TRACE("(%p,%p,%p)\n",This,pmkObjectName,pfiletime); + + if (pmkObjectName==NULL || pfiletime==NULL) + return E_INVALIDARG; + + hr = get_moniker_comparison_data(pmkObjectName, &moniker_data); + if (hr != S_OK) + return hr; + + hr = MK_E_UNAVAILABLE; + + EnterCriticalSection(&This->lock); + LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry) + { + if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) && + !memcmp(moniker_data, rot_entry->moniker_data, moniker_data->ulCntData)) + { + *pfiletime = rot_entry->last_modified; + hr = S_OK; + break; + } + } + LeaveCriticalSection(&This->lock); + + /* FIXME: if (hr != S_OK) call IrotGetTimeOfLastChange */ + + HeapFree(GetProcessHeap(), 0, moniker_data); + return hr; +} + +/*********************************************************************** + * RunningObjectTable_EnumRunning + * + * PARAMS + * ppenumMoniker [out] receives the IEnumMoniker interface pointer + */ +static HRESULT WINAPI +RunningObjectTableImpl_EnumRunning(IRunningObjectTable* iface, + IEnumMoniker **ppenumMoniker) +{ + HRESULT hr; + RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface; + MInterfacePointer **monikers; + ULONG moniker_count = 0; + const struct rot_entry *rot_entry; + ULONG i = 0; + + EnterCriticalSection(&This->lock); + + LIST_FOR_EACH_ENTRY( rot_entry, &This->rot, const struct rot_entry, entry ) + moniker_count++; + + monikers = HeapAlloc(GetProcessHeap(), 0, moniker_count * sizeof(*monikers)); + + LIST_FOR_EACH_ENTRY( rot_entry, &This->rot, const struct rot_entry, entry ) + { + SIZE_T size = FIELD_OFFSET(MInterfacePointer, abData[rot_entry->moniker->ulCntData]); + monikers[i] = HeapAlloc(GetProcessHeap(), 0, size); + memcpy(monikers[i], rot_entry->moniker, size); + i++; + } + + LeaveCriticalSection(&This->lock); + + /* FIXME: call IrotEnumRunning and append data */ + + hr = EnumMonikerImpl_CreateEnumROTMoniker(monikers, moniker_count, 0, ppenumMoniker); + + return hr; +} + +/****************************************************************************** + * GetRunningObjectTable (OLE2.30) + */ +HRESULT WINAPI +GetRunningObjectTable16(DWORD reserved, LPRUNNINGOBJECTTABLE *pprot) +{ + FIXME("(%ld,%p),stub!\n",reserved,pprot); + return E_NOTIMPL; +} + +/*********************************************************************** + * GetRunningObjectTable (OLE32.@) + */ +HRESULT WINAPI +GetRunningObjectTable(DWORD reserved, LPRUNNINGOBJECTTABLE *pprot) +{ + IID riid=IID_IRunningObjectTable; + HRESULT res; + + TRACE("()\n"); + + if (reserved!=0) + return E_UNEXPECTED; + + if(runningObjectTableInstance==NULL) + return CO_E_NOTINITIALIZED; + + res = IRunningObjectTable_QueryInterface((IRunningObjectTable*)runningObjectTableInstance,&riid,(void**)pprot); + + return res; +} + +/****************************************************************************** + * OleRun [OLE32.@] + */ +HRESULT WINAPI OleRun(LPUNKNOWN pUnknown) +{ + IRunnableObject *runable; + IRunnableObject *This = (IRunnableObject *)pUnknown; + LRESULT ret; + + ret = IRunnableObject_QueryInterface(This,&IID_IRunnableObject,(LPVOID*)&runable); + if (ret) + return 0; /* Appears to return no error. */ + ret = IRunnableObject_Run(runable,NULL); + IRunnableObject_Release(runable); + return ret; +} + +/****************************************************************************** + * MkParseDisplayName [OLE32.@] + */ +HRESULT WINAPI MkParseDisplayName(LPBC pbc, LPCOLESTR szUserName, + LPDWORD pchEaten, LPMONIKER *ppmk) +{ + FIXME("(%p, %s, %p, %p): stub.\n", pbc, debugstr_w(szUserName), pchEaten, *ppmk); + + if (!(IsValidInterface((LPUNKNOWN) pbc))) + return E_INVALIDARG; + + return MK_E_SYNTAX; +} + +/****************************************************************************** + * CreateClassMoniker [OLE32.@] + */ +HRESULT WINAPI CreateClassMoniker(REFCLSID rclsid, IMoniker ** ppmk) +{ + FIXME("%s\n", debugstr_guid( rclsid )); + if( ppmk ) + *ppmk = NULL; + return E_NOTIMPL; +} + +/* Virtual function table for the IRunningObjectTable class. */ +static IRunningObjectTableVtbl VT_RunningObjectTableImpl = +{ + RunningObjectTableImpl_QueryInterface, + RunningObjectTableImpl_AddRef, + RunningObjectTableImpl_Release, + RunningObjectTableImpl_Register, + RunningObjectTableImpl_Revoke, + RunningObjectTableImpl_IsRunning, + RunningObjectTableImpl_GetObject, + RunningObjectTableImpl_NoteChangeTime, + RunningObjectTableImpl_GetTimeOfLastChange, + RunningObjectTableImpl_EnumRunning +}; + +/*********************************************************************** + * RunningObjectTable_Initialize + */ +HRESULT WINAPI RunningObjectTableImpl_Initialize(void) +{ + TRACE("\n"); + + /* create the unique instance of the RunningObjectTableImpl structure */ + runningObjectTableInstance = HeapAlloc(GetProcessHeap(), 0, sizeof(RunningObjectTableImpl)); + + if (!runningObjectTableInstance) + return E_OUTOFMEMORY; + + /* initialize the virtual table function */ + runningObjectTableInstance->lpVtbl = &VT_RunningObjectTableImpl; + + /* the initial reference is set to "1" ! because if set to "0" it will be not practis when */ + /* the ROT referred many times not in the same time (all the objects in the ROT will */ + /* be removed every time the ROT is removed ) */ + runningObjectTableInstance->ref = 1; + + list_init(&runningObjectTableInstance->rot); + InitializeCriticalSection(&runningObjectTableInstance->lock); + + return S_OK; +} + +/*********************************************************************** + * RunningObjectTable_UnInitialize + */ +HRESULT WINAPI RunningObjectTableImpl_UnInitialize() +{ + TRACE("\n"); + + if (runningObjectTableInstance==NULL) + return E_POINTER; + + RunningObjectTableImpl_Release((IRunningObjectTable*)runningObjectTableInstance); + + RunningObjectTableImpl_Destroy(); + + return S_OK; +} + +/*********************************************************************** + * EnumMoniker_QueryInterface + */ +static HRESULT WINAPI EnumMonikerImpl_QueryInterface(IEnumMoniker* iface,REFIID riid,void** ppvObject) +{ + EnumMonikerImpl *This = (EnumMonikerImpl *)iface; + + TRACE("(%p,%p,%p)\n",This,riid,ppvObject); + + /* validate arguments */ + if (ppvObject == NULL) + return E_INVALIDARG; + + *ppvObject = NULL; + + if (IsEqualIID(&IID_IUnknown, riid)) + *ppvObject = (IEnumMoniker*)This; + else + if (IsEqualIID(&IID_IEnumMoniker, riid)) + *ppvObject = (IEnumMoniker*)This; + + if ((*ppvObject)==NULL) + return E_NOINTERFACE; + + IEnumMoniker_AddRef(iface); + + return S_OK; +} + +/*********************************************************************** + * EnumMoniker_AddRef + */ +static ULONG WINAPI EnumMonikerImpl_AddRef(IEnumMoniker* iface) +{ + EnumMonikerImpl *This = (EnumMonikerImpl *)iface; + + TRACE("(%p)\n",This); + + return InterlockedIncrement(&This->ref); +} + +/*********************************************************************** + * EnumMoniker_release + */ +static ULONG WINAPI EnumMonikerImpl_Release(IEnumMoniker* iface) +{ + EnumMonikerImpl *This = (EnumMonikerImpl *)iface; + ULONG ref; + + TRACE("(%p)\n",This); + + ref = InterlockedDecrement(&This->ref); + + /* unitialize rot structure if there's no more reference to it*/ + if (ref == 0) + { + ULONG i; + + TRACE("(%p) Deleting\n",This); + + for (i = 0; i < This->moniker_count; i++) + HeapFree(GetProcessHeap(), 0, This->monikers[i]); + HeapFree(GetProcessHeap(), 0, This->monikers); + HeapFree(GetProcessHeap(), 0, This); + } + + return ref; +} +/*********************************************************************** + * EnmumMoniker_Next + */ +static HRESULT WINAPI EnumMonikerImpl_Next(IEnumMoniker* iface, ULONG celt, IMoniker** rgelt, ULONG * pceltFetched) +{ + ULONG i; + EnumMonikerImpl *This = (EnumMonikerImpl *)iface; + HRESULT hr = S_OK; + + TRACE("(%p) TabCurrentPos %ld Tablastindx %ld\n", This, This->pos, This->moniker_count); + + /* retrieve the requested number of moniker from the current position */ + for(i = 0; (This->pos < This->moniker_count) && (i < celt); i++) + { + IStream *stream; + hr = create_stream_on_mip_ro(This->monikers[This->pos++], &stream); + if (hr != S_OK) break; + hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void **)&rgelt[i]); + IStream_Release(stream); + if (hr != S_OK) break; + } + + if (pceltFetched != NULL) + *pceltFetched= i; + + if (hr != S_OK) + return hr; + + if (i == celt) + return S_OK; + else + return S_FALSE; + +} + +/*********************************************************************** + * EnmumMoniker_Skip + */ +static HRESULT WINAPI EnumMonikerImpl_Skip(IEnumMoniker* iface, ULONG celt) +{ + EnumMonikerImpl *This = (EnumMonikerImpl *)iface; + + TRACE("(%p)\n",This); + + if (This->pos + celt >= This->moniker_count) + return S_FALSE; + + This->pos += celt; + + return S_OK; +} + +/*********************************************************************** + * EnmumMoniker_Reset + */ +static HRESULT WINAPI EnumMonikerImpl_Reset(IEnumMoniker* iface) +{ + EnumMonikerImpl *This = (EnumMonikerImpl *)iface; + + This->pos = 0; /* set back to start of list */ + + TRACE("(%p)\n",This); + + return S_OK; +} + +/*********************************************************************** + * EnmumMoniker_Clone + */ +static HRESULT WINAPI EnumMonikerImpl_Clone(IEnumMoniker* iface, IEnumMoniker ** ppenum) +{ + EnumMonikerImpl *This = (EnumMonikerImpl *)iface; + MInterfacePointer **monikers = HeapAlloc(GetProcessHeap(), 0, sizeof(*monikers)*This->moniker_count); + ULONG i; + + TRACE("(%p)\n",This); + + for (i = 0; i < This->moniker_count; i++) + { + SIZE_T size = FIELD_OFFSET(MInterfacePointer, abData[This->monikers[i]->ulCntData]); + monikers[i] = HeapAlloc(GetProcessHeap(), 0, size); + memcpy(monikers[i], This->monikers[i], size); + } + + /* copy the enum structure */ + return EnumMonikerImpl_CreateEnumROTMoniker(monikers, This->moniker_count, + This->pos, ppenum); +} + +/* Virtual function table for the IEnumMoniker class. */ +static const IEnumMonikerVtbl VT_EnumMonikerImpl = +{ + EnumMonikerImpl_QueryInterface, + EnumMonikerImpl_AddRef, + EnumMonikerImpl_Release, + EnumMonikerImpl_Next, + EnumMonikerImpl_Skip, + EnumMonikerImpl_Reset, + EnumMonikerImpl_Clone +}; + +/*********************************************************************** + * EnumMonikerImpl_CreateEnumROTMoniker + * Used by EnumRunning to create the structure and EnumClone + * to copy the structure + */ +static HRESULT WINAPI EnumMonikerImpl_CreateEnumROTMoniker(MInterfacePointer **monikers, + ULONG moniker_count, + ULONG current_pos, + IEnumMoniker **ppenumMoniker) +{ + EnumMonikerImpl* This = NULL; + + if (!ppenumMoniker) + return E_INVALIDARG; + + This = HeapAlloc(GetProcessHeap(), 0, sizeof(EnumMonikerImpl)); + if (!This) return E_OUTOFMEMORY; + + TRACE("(%p)\n", This); + + /* initialize the virtual table function */ + This->lpVtbl = &VT_EnumMonikerImpl; + + /* the initial reference is set to "1" */ + This->ref = 1; /* set the ref count to one */ + This->pos = 0; /* Set the list start posn to start */ + This->moniker_count = moniker_count; /* Need the same size table as ROT */ + This->monikers = monikers; + + *ppenumMoniker = (IEnumMoniker*)This; + + return S_OK; +} + + +/* Shared implementation of moniker marshaler based on saving and loading of + * monikers */ + +#define ICOM_THIS_From_IMoniker(class, name) class* This = (class*)(((char*)name)-FIELD_OFFSET(class, lpVtblMarshal)) + +typedef struct MonikerMarshal +{ + const IUnknownVtbl *lpVtbl; + const IMarshalVtbl *lpVtblMarshal; + + ULONG ref; + IMoniker *moniker; +} MonikerMarshal; + +static HRESULT WINAPI MonikerMarshalInner_QueryInterface(IUnknown *iface, REFIID riid, LPVOID *ppv) +{ + MonikerMarshal *This = (MonikerMarshal *)iface; + TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); + *ppv = NULL; + if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IMarshal, riid)) + { + *ppv = &This->lpVtblMarshal; + IUnknown_AddRef((IUnknown *)&This->lpVtblMarshal); + return S_OK; + } + FIXME("No interface for %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI MonikerMarshalInner_AddRef(IUnknown *iface) +{ + MonikerMarshal *This = (MonikerMarshal *)iface; + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI MonikerMarshalInner_Release(IUnknown *iface) +{ + MonikerMarshal *This = (MonikerMarshal *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + if (!ref) HeapFree(GetProcessHeap(), 0, This); + return ref; +} + +static const IUnknownVtbl VT_MonikerMarshalInner = +{ + MonikerMarshalInner_QueryInterface, + MonikerMarshalInner_AddRef, + MonikerMarshalInner_Release +}; + +static HRESULT WINAPI MonikerMarshal_QueryInterface(IMarshal *iface, REFIID riid, LPVOID *ppv) +{ + ICOM_THIS_From_IMoniker(MonikerMarshal, iface); + return IMoniker_QueryInterface(This->moniker, riid, ppv); +} + +static ULONG WINAPI MonikerMarshal_AddRef(IMarshal *iface) +{ + ICOM_THIS_From_IMoniker(MonikerMarshal, iface); + return IMoniker_AddRef(This->moniker); +} + +static ULONG WINAPI MonikerMarshal_Release(IMarshal *iface) +{ + ICOM_THIS_From_IMoniker(MonikerMarshal, iface); + return IMoniker_Release(This->moniker); +} + +static HRESULT WINAPI MonikerMarshal_GetUnmarshalClass( + LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, + void* pvDestContext, DWORD mshlflags, CLSID* pCid) +{ + ICOM_THIS_From_IMoniker(MonikerMarshal, iface); + + TRACE("(%s, %p, %lx, %p, %lx, %p)\n", debugstr_guid(riid), pv, + dwDestContext, pvDestContext, mshlflags, pCid); + + return IMoniker_GetClassID(This->moniker, pCid); +} + +static HRESULT WINAPI MonikerMarshal_GetMarshalSizeMax( + LPMARSHAL iface, REFIID riid, void* pv, DWORD dwDestContext, + void* pvDestContext, DWORD mshlflags, DWORD* pSize) +{ + ICOM_THIS_From_IMoniker(MonikerMarshal, iface); + HRESULT hr; + ULARGE_INTEGER size; + + TRACE("(%s, %p, %lx, %p, %lx, %p)\n", debugstr_guid(riid), pv, + dwDestContext, pvDestContext, mshlflags, pSize); + + hr = IMoniker_GetSizeMax(This->moniker, &size); + if (hr == S_OK) + *pSize = (DWORD)size.QuadPart; + return hr; +} + +static HRESULT WINAPI MonikerMarshal_MarshalInterface(LPMARSHAL iface, IStream *pStm, + REFIID riid, void* pv, DWORD dwDestContext, + void* pvDestContext, DWORD mshlflags) +{ + ICOM_THIS_From_IMoniker(MonikerMarshal, iface); + + TRACE("(%p, %s, %p, %lx, %p, %lx)\n", pStm, debugstr_guid(riid), pv, + dwDestContext, pvDestContext, mshlflags); + + return IMoniker_Save(This->moniker, pStm, FALSE); +} + +static HRESULT WINAPI MonikerMarshal_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv) +{ + ICOM_THIS_From_IMoniker(MonikerMarshal, iface); + HRESULT hr; + + TRACE("(%p, %s, %p)\n", pStm, debugstr_guid(riid), ppv); + + hr = IMoniker_Load(This->moniker, pStm); + if (hr == S_OK) + hr = IMoniker_QueryInterface(This->moniker, riid, ppv); + return hr; +} + +static HRESULT WINAPI MonikerMarshal_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm) +{ + TRACE("()\n"); + /* can't release a state-based marshal as nothing on server side to + * release */ + return S_OK; +} + +static HRESULT WINAPI MonikerMarshal_DisconnectObject(LPMARSHAL iface, DWORD dwReserved) +{ + TRACE("()\n"); + /* can't disconnect a state-based marshal as nothing on server side to + * disconnect from */ + return S_OK; +} + +static const IMarshalVtbl VT_MonikerMarshal = +{ + MonikerMarshal_QueryInterface, + MonikerMarshal_AddRef, + MonikerMarshal_Release, + MonikerMarshal_GetUnmarshalClass, + MonikerMarshal_GetMarshalSizeMax, + MonikerMarshal_MarshalInterface, + MonikerMarshal_UnmarshalInterface, + MonikerMarshal_ReleaseMarshalData, + MonikerMarshal_DisconnectObject +}; + +HRESULT MonikerMarshal_Create(IMoniker *inner, IUnknown **outer) +{ + MonikerMarshal *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + if (!This) return E_OUTOFMEMORY; + + This->lpVtbl = &VT_MonikerMarshalInner; + This->lpVtblMarshal = &VT_MonikerMarshal; + This->ref = 1; + This->moniker = inner; + + *outer = (IUnknown *)&This->lpVtbl; + return S_OK; +} diff --git a/reactos/lib/ole32/moniker.h b/reactos/lib/ole32/moniker.h index 591b61eca34..45722fa4ba5 100644 --- a/reactos/lib/ole32/moniker.h +++ b/reactos/lib/ole32/moniker.h @@ -1,17 +1,17 @@ -#ifndef __WINE_MONIKER_H__ -#define __WINE_MONIKER_H__ - -#define ICOM_THIS_From_IROTData(class, name) class* This = (class*)(((char*)name)-sizeof(void*)) - -extern const CLSID CLSID_FileMoniker; -extern const CLSID CLSID_ItemMoniker; -extern const CLSID CLSID_AntiMoniker; -extern const CLSID CLSID_CompositeMoniker; - -HRESULT FileMonikerCF_Create(REFIID riid, LPVOID *ppv); -HRESULT ItemMonikerCF_Create(REFIID riid, LPVOID *ppv); - -HRESULT MonikerMarshal_Create(IMoniker *inner, IUnknown **outer); - - -#endif /* __WINE_MONIKER_H__ */ +#ifndef __WINE_MONIKER_H__ +#define __WINE_MONIKER_H__ + +#define ICOM_THIS_From_IROTData(class, name) class* This = (class*)(((char*)name)-sizeof(void*)) + +extern const CLSID CLSID_FileMoniker; +extern const CLSID CLSID_ItemMoniker; +extern const CLSID CLSID_AntiMoniker; +extern const CLSID CLSID_CompositeMoniker; + +HRESULT FileMonikerCF_Create(REFIID riid, LPVOID *ppv); +HRESULT ItemMonikerCF_Create(REFIID riid, LPVOID *ppv); + +HRESULT MonikerMarshal_Create(IMoniker *inner, IUnknown **outer); + + +#endif /* __WINE_MONIKER_H__ */ diff --git a/reactos/lib/ole32/ole16.c b/reactos/lib/ole32/ole16.c index 1c179fcf7c4..aa1e7721a33 100644 --- a/reactos/lib/ole32/ole16.c +++ b/reactos/lib/ole32/ole16.c @@ -1,513 +1,513 @@ -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <stdlib.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> -#include <assert.h> - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "objbase.h" -#include "ole2.h" -#include "ole2ver.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 "compobj_private.h" -#include "ifs.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -HTASK16 hETask = 0; -WORD Table_ETask[62]; - -LPMALLOC16 currentMalloc16=NULL; - -/* --- IMalloc16 implementation */ - - -typedef struct -{ - /* IUnknown fields */ - IMalloc16Vtbl *lpVtbl; - DWORD ref; - /* IMalloc16 fields */ -} IMalloc16Impl; - -/****************************************************************************** - * IMalloc16_QueryInterface [COMPOBJ.500] - */ -HRESULT WINAPI IMalloc16_fnQueryInterface(IMalloc16* iface,REFIID refiid,LPVOID *obj) { - IMalloc16Impl *This = (IMalloc16Impl *)iface; - - TRACE("(%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 WINAPI IMalloc16_fnAddRef(IMalloc16* iface) { - IMalloc16Impl *This = (IMalloc16Impl *)iface; - TRACE("(%p)->AddRef()\n",This); - return 1; /* cannot be freed */ -} - -/****************************************************************************** - * IMalloc16_Release [COMPOBJ.502] - */ -ULONG WINAPI IMalloc16_fnRelease(IMalloc16* iface) { - IMalloc16Impl *This = (IMalloc16Impl *)iface; - TRACE("(%p)->Release()\n",This); - return 1; /* cannot be freed */ -} - -/****************************************************************************** - * IMalloc16_Alloc [COMPOBJ.503] - */ -SEGPTR WINAPI IMalloc16_fnAlloc(IMalloc16* iface,DWORD cb) { - IMalloc16Impl *This = (IMalloc16Impl *)iface; - TRACE("(%p)->Alloc(%ld)\n",This,cb); - return MapLS( HeapAlloc( GetProcessHeap(), 0, cb ) ); -} - -/****************************************************************************** - * IMalloc16_Free [COMPOBJ.505] - */ -VOID WINAPI IMalloc16_fnFree(IMalloc16* iface,SEGPTR pv) -{ - void *ptr = MapSL(pv); - IMalloc16Impl *This = (IMalloc16Impl *)iface; - TRACE("(%p)->Free(%08lx)\n",This,pv); - UnMapLS(pv); - HeapFree( GetProcessHeap(), 0, ptr ); -} - -/****************************************************************************** - * IMalloc16_Realloc [COMPOBJ.504] - */ -SEGPTR WINAPI IMalloc16_fnRealloc(IMalloc16* iface,SEGPTR pv,DWORD cb) -{ - SEGPTR ret; - IMalloc16Impl *This = (IMalloc16Impl *)iface; - TRACE("(%p)->Realloc(%08lx,%ld)\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 WINAPI IMalloc16_fnGetSize(const IMalloc16* iface,SEGPTR pv) -{ - IMalloc16Impl *This = (IMalloc16Impl *)iface; - TRACE("(%p)->GetSize(%08lx)\n",This,pv); - return HeapSize( GetProcessHeap(), 0, MapSL(pv) ); -} - -/****************************************************************************** - * IMalloc16_DidAlloc [COMPOBJ.507] - */ -INT16 WINAPI IMalloc16_fnDidAlloc(const IMalloc16* iface,LPVOID pv) { - IMalloc16 *This = (IMalloc16 *)iface; - TRACE("(%p)->DidAlloc(%p)\n",This,pv); - return (INT16)-1; -} - -/****************************************************************************** - * IMalloc16_HeapMinimize [COMPOBJ.508] - */ -LPVOID WINAPI IMalloc16_fnHeapMinimize(IMalloc16* iface) { - IMalloc16Impl *This = (IMalloc16Impl *)iface; - TRACE("(%p)->HeapMinimize()\n",This); - return NULL; -} - -/****************************************************************************** - * IMalloc16_Constructor [VTABLE] - */ -LPMALLOC16 -IMalloc16_Constructor() -{ - 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->lpVtbl = (IMalloc16Vtbl*)msegvt16; - This->ref = 1; - return (LPMALLOC16)MapLS( This ); -} - - -/*********************************************************************** - * CoGetMalloc [COMPOBJ.4] - * RETURNS - * The current win16 IMalloc - */ -HRESULT WINAPI CoGetMalloc16( - DWORD dwMemContext, /* [in] unknown */ - LPMALLOC16 * lpMalloc /* [out] current win16 malloc interface */ -) { - if(!currentMalloc16) - currentMalloc16 = IMalloc16_Constructor(); - *lpMalloc = currentMalloc16; - return S_OK; -} - -/*********************************************************************** - * CoCreateStandardMalloc [COMPOBJ.71] - */ -HRESULT WINAPI CoCreateStandardMalloc16(DWORD dwMemContext, - LPMALLOC16 *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( - LPVOID lpReserved /* [in] pointer to win16 malloc interface */ -) { - currentMalloc16 = (LPMALLOC16)lpReserved; - 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) -{ - TRACE("()\n"); - CoFreeAllLibraries(); -} - -/*********************************************************************** - * 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) ); -} - -/****************************************************************************** - * 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 */ - CLSID *id) /* [out] GUID converted from string */ -{ - - return __CLSIDFromStringA(idstr,id); -} - -extern BOOL WINAPI K32WOWCallback16Ex( DWORD vpfn16, DWORD dwFlags, - DWORD cbArgs, LPVOID pArgs, - LPDWORD pdwRetCode ); - -/****************************************************************************** - * _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 (CoGetMalloc16(0,&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 (!K32WOWCallback16Ex( - (DWORD)((IMalloc16Vtbl*)MapSL( - (SEGPTR)((LPMALLOC16)MapSL((SEGPTR)mllc))->lpVtbl ) - )->Alloc, - WCB16_CDECL, - 2*sizeof(DWORD), - (LPVOID)args, - (LPDWORD)ptr - )) { - ERR("CallTo16 IMalloc16 (%ld) failed\n",size); - return E_FAIL; - } - return S_OK; -} - -/****************************************************************************** - * StringFromCLSID [COMPOBJ.19] - * 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 */ - -) { - HRESULT ret; - - ret = _xmalloc16(40,(SEGPTR*)idstr); - if (ret != S_OK) - return ret; - return WINE_StringFromCLSID(id,MapSL((SEGPTR)*idstr)); -} - -/****************************************************************************** - * 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 Prog ID */ -) { - char strCLSID[50], *buf, *buf2; - DWORD buf2len; - HKEY xhkey; - HRESULT ret = S_OK; - - WINE_StringFromCLSID(clsid, strCLSID); - - buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14); - sprintf(buf,"CLSID\\%s\\ProgID", strCLSID); - if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey)) - ret = REGDB_E_CLASSNOTREG; - - HeapFree(GetProcessHeap(), 0, buf); - - if (ret == S_OK) - { - buf2 = HeapAlloc(GetProcessHeap(), 0, 255); - buf2len = 255; - if (RegQueryValueA(xhkey, NULL, buf2, &buf2len)) - ret = REGDB_E_CLASSNOTREG; - - if (ret == S_OK) - { - ret = _xmalloc16(buf2len+1, (SEGPTR*)lplpszProgID); - if (ret == S_OK) - strcpy(MapSL((SEGPTR)*lplpszProgID),buf2); - } - HeapFree(GetProcessHeap(), 0, buf2); - } - RegCloseKey(xhkey); - 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, - LPUNKNOWN 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 -) { - char buf[80]; - - WINE_StringFromCLSID(rclsid,buf); - - FIXME("(%s,%p,0x%08lx,0x%08lx,%p),stub\n", - buf,pUnk,dwClsContext,flags,lpdwRegister - ); - return 0; -} - -/****************************************************************************** - * CoRevokeClassObject [COMPOBJ.6] - * - */ -HRESULT WINAPI CoRevokeClassObject16(DWORD dwRegister) /* [in] token on class obj */ -{ - FIXME("(0x%08lx),stub!\n", dwRegister); - return 0; -} - -/****************************************************************************** - * 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); -} - -/****************************************************************************** - * CoRegisterMessageFilter [COMPOBJ.27] - */ -HRESULT WINAPI CoRegisterMessageFilter16( - LPMESSAGEFILTER lpMessageFilter, - LPMESSAGEFILTER *lplpMessageFilter -) { - FIXME("(%p,%p),stub!\n",lpMessageFilter,lplpMessageFilter); - return 0; -} - -/****************************************************************************** - * CoLockObjectExternal [COMPOBJ.63] - */ -HRESULT WINAPI CoLockObjectExternal16( - LPUNKNOWN pUnk, /* [in] object to be locked */ - BOOL16 fLock, /* [in] do lock */ - BOOL16 fLastUnlockReleases /* [in] ? */ -) { - FIXME("(%p,%d,%d),stub!\n",pUnk,fLock,fLastUnlockReleases); - return S_OK; -} - -/*********************************************************************** - * 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("(%08lx, %04x, %04x, %04x, %08lx, %04x)\n", Reason, hInst, ds, HeapSize, res1, res2); - return TRUE; -} +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "objbase.h" +#include "ole2.h" +#include "ole2ver.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 "compobj_private.h" +#include "ifs.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +HTASK16 hETask = 0; +WORD Table_ETask[62]; + +LPMALLOC16 currentMalloc16=NULL; + +/* --- IMalloc16 implementation */ + + +typedef struct +{ + /* IUnknown fields */ + IMalloc16Vtbl *lpVtbl; + DWORD ref; + /* IMalloc16 fields */ +} IMalloc16Impl; + +/****************************************************************************** + * IMalloc16_QueryInterface [COMPOBJ.500] + */ +HRESULT WINAPI IMalloc16_fnQueryInterface(IMalloc16* iface,REFIID refiid,LPVOID *obj) { + IMalloc16Impl *This = (IMalloc16Impl *)iface; + + TRACE("(%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 WINAPI IMalloc16_fnAddRef(IMalloc16* iface) { + IMalloc16Impl *This = (IMalloc16Impl *)iface; + TRACE("(%p)->AddRef()\n",This); + return 1; /* cannot be freed */ +} + +/****************************************************************************** + * IMalloc16_Release [COMPOBJ.502] + */ +ULONG WINAPI IMalloc16_fnRelease(IMalloc16* iface) { + IMalloc16Impl *This = (IMalloc16Impl *)iface; + TRACE("(%p)->Release()\n",This); + return 1; /* cannot be freed */ +} + +/****************************************************************************** + * IMalloc16_Alloc [COMPOBJ.503] + */ +SEGPTR WINAPI IMalloc16_fnAlloc(IMalloc16* iface,DWORD cb) { + IMalloc16Impl *This = (IMalloc16Impl *)iface; + TRACE("(%p)->Alloc(%ld)\n",This,cb); + return MapLS( HeapAlloc( GetProcessHeap(), 0, cb ) ); +} + +/****************************************************************************** + * IMalloc16_Free [COMPOBJ.505] + */ +VOID WINAPI IMalloc16_fnFree(IMalloc16* iface,SEGPTR pv) +{ + void *ptr = MapSL(pv); + IMalloc16Impl *This = (IMalloc16Impl *)iface; + TRACE("(%p)->Free(%08lx)\n",This,pv); + UnMapLS(pv); + HeapFree( GetProcessHeap(), 0, ptr ); +} + +/****************************************************************************** + * IMalloc16_Realloc [COMPOBJ.504] + */ +SEGPTR WINAPI IMalloc16_fnRealloc(IMalloc16* iface,SEGPTR pv,DWORD cb) +{ + SEGPTR ret; + IMalloc16Impl *This = (IMalloc16Impl *)iface; + TRACE("(%p)->Realloc(%08lx,%ld)\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 WINAPI IMalloc16_fnGetSize(const IMalloc16* iface,SEGPTR pv) +{ + IMalloc16Impl *This = (IMalloc16Impl *)iface; + TRACE("(%p)->GetSize(%08lx)\n",This,pv); + return HeapSize( GetProcessHeap(), 0, MapSL(pv) ); +} + +/****************************************************************************** + * IMalloc16_DidAlloc [COMPOBJ.507] + */ +INT16 WINAPI IMalloc16_fnDidAlloc(const IMalloc16* iface,LPVOID pv) { + IMalloc16 *This = (IMalloc16 *)iface; + TRACE("(%p)->DidAlloc(%p)\n",This,pv); + return (INT16)-1; +} + +/****************************************************************************** + * IMalloc16_HeapMinimize [COMPOBJ.508] + */ +LPVOID WINAPI IMalloc16_fnHeapMinimize(IMalloc16* iface) { + IMalloc16Impl *This = (IMalloc16Impl *)iface; + TRACE("(%p)->HeapMinimize()\n",This); + return NULL; +} + +/****************************************************************************** + * IMalloc16_Constructor [VTABLE] + */ +LPMALLOC16 +IMalloc16_Constructor() +{ + 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->lpVtbl = (IMalloc16Vtbl*)msegvt16; + This->ref = 1; + return (LPMALLOC16)MapLS( This ); +} + + +/*********************************************************************** + * CoGetMalloc [COMPOBJ.4] + * RETURNS + * The current win16 IMalloc + */ +HRESULT WINAPI CoGetMalloc16( + DWORD dwMemContext, /* [in] unknown */ + LPMALLOC16 * lpMalloc /* [out] current win16 malloc interface */ +) { + if(!currentMalloc16) + currentMalloc16 = IMalloc16_Constructor(); + *lpMalloc = currentMalloc16; + return S_OK; +} + +/*********************************************************************** + * CoCreateStandardMalloc [COMPOBJ.71] + */ +HRESULT WINAPI CoCreateStandardMalloc16(DWORD dwMemContext, + LPMALLOC16 *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( + LPVOID lpReserved /* [in] pointer to win16 malloc interface */ +) { + currentMalloc16 = (LPMALLOC16)lpReserved; + 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) +{ + TRACE("()\n"); + CoFreeAllLibraries(); +} + +/*********************************************************************** + * 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) ); +} + +/****************************************************************************** + * 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 */ + CLSID *id) /* [out] GUID converted from string */ +{ + + return __CLSIDFromStringA(idstr,id); +} + +extern BOOL WINAPI K32WOWCallback16Ex( DWORD vpfn16, DWORD dwFlags, + DWORD cbArgs, LPVOID pArgs, + LPDWORD pdwRetCode ); + +/****************************************************************************** + * _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 (CoGetMalloc16(0,&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 (!K32WOWCallback16Ex( + (DWORD)((IMalloc16Vtbl*)MapSL( + (SEGPTR)((LPMALLOC16)MapSL((SEGPTR)mllc))->lpVtbl ) + )->Alloc, + WCB16_CDECL, + 2*sizeof(DWORD), + (LPVOID)args, + (LPDWORD)ptr + )) { + ERR("CallTo16 IMalloc16 (%ld) failed\n",size); + return E_FAIL; + } + return S_OK; +} + +/****************************************************************************** + * StringFromCLSID [COMPOBJ.19] + * 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 */ + +) { + HRESULT ret; + + ret = _xmalloc16(40,(SEGPTR*)idstr); + if (ret != S_OK) + return ret; + return WINE_StringFromCLSID(id,MapSL((SEGPTR)*idstr)); +} + +/****************************************************************************** + * 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 Prog ID */ +) { + char strCLSID[50], *buf, *buf2; + DWORD buf2len; + HKEY xhkey; + HRESULT ret = S_OK; + + WINE_StringFromCLSID(clsid, strCLSID); + + buf = HeapAlloc(GetProcessHeap(), 0, strlen(strCLSID)+14); + sprintf(buf,"CLSID\\%s\\ProgID", strCLSID); + if (RegOpenKeyA(HKEY_CLASSES_ROOT, buf, &xhkey)) + ret = REGDB_E_CLASSNOTREG; + + HeapFree(GetProcessHeap(), 0, buf); + + if (ret == S_OK) + { + buf2 = HeapAlloc(GetProcessHeap(), 0, 255); + buf2len = 255; + if (RegQueryValueA(xhkey, NULL, buf2, &buf2len)) + ret = REGDB_E_CLASSNOTREG; + + if (ret == S_OK) + { + ret = _xmalloc16(buf2len+1, (SEGPTR*)lplpszProgID); + if (ret == S_OK) + strcpy(MapSL((SEGPTR)*lplpszProgID),buf2); + } + HeapFree(GetProcessHeap(), 0, buf2); + } + RegCloseKey(xhkey); + 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, + LPUNKNOWN 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 +) { + char buf[80]; + + WINE_StringFromCLSID(rclsid,buf); + + FIXME("(%s,%p,0x%08lx,0x%08lx,%p),stub\n", + buf,pUnk,dwClsContext,flags,lpdwRegister + ); + return 0; +} + +/****************************************************************************** + * CoRevokeClassObject [COMPOBJ.6] + * + */ +HRESULT WINAPI CoRevokeClassObject16(DWORD dwRegister) /* [in] token on class obj */ +{ + FIXME("(0x%08lx),stub!\n", dwRegister); + return 0; +} + +/****************************************************************************** + * 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); +} + +/****************************************************************************** + * CoRegisterMessageFilter [COMPOBJ.27] + */ +HRESULT WINAPI CoRegisterMessageFilter16( + LPMESSAGEFILTER lpMessageFilter, + LPMESSAGEFILTER *lplpMessageFilter +) { + FIXME("(%p,%p),stub!\n",lpMessageFilter,lplpMessageFilter); + return 0; +} + +/****************************************************************************** + * CoLockObjectExternal [COMPOBJ.63] + */ +HRESULT WINAPI CoLockObjectExternal16( + LPUNKNOWN pUnk, /* [in] object to be locked */ + BOOL16 fLock, /* [in] do lock */ + BOOL16 fLastUnlockReleases /* [in] ? */ +) { + FIXME("(%p,%d,%d),stub!\n",pUnk,fLock,fLastUnlockReleases); + return S_OK; +} + +/*********************************************************************** + * 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("(%08lx, %04x, %04x, %04x, %08lx, %04x)\n", Reason, hInst, ds, HeapSize, res1, res2); + return TRUE; +} diff --git a/reactos/lib/ole32/ole2.c b/reactos/lib/ole32/ole2.c index 53e123be01e..339ccd257e9 100644 --- a/reactos/lib/ole32/ole2.c +++ b/reactos/lib/ole32/ole2.c @@ -1,2753 +1,2753 @@ -/* - * OLE2 library - * - * Copyright 1995 Martin von Loewis - * Copyright 1999 Francis Beaudet - * Copyright 1999 Noel Borthwick - * Copyright 1999, 2000 Marcus Meissner - * Copyright 2005 Juan Lang - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <assert.h> -#include <stdlib.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "winreg.h" -#include "commctrl.h" -#include "ole2.h" -#include "ole2ver.h" -#include "wownt32.h" - -#include "wine/winbase16.h" -#include "wine/wingdi16.h" -#include "wine/winuser16.h" -#include "compobj_private.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); -WINE_DECLARE_DEBUG_CHANNEL(accel); - -#define HICON_16(h32) (LOWORD(h32)) -#define HICON_32(h16) ((HICON)(ULONG_PTR)(h16)) -#define HINSTANCE_32(h16) ((HINSTANCE)(ULONG_PTR)(h16)) - -/****************************************************************************** - * These are static/global variables and internal data structures that the - * OLE module uses to maintain it's state. - */ -typedef struct tagDropTargetNode -{ - HWND hwndTarget; - IDropTarget* dropTarget; - struct tagDropTargetNode* prevDropTarget; - struct tagDropTargetNode* nextDropTarget; -} DropTargetNode; - -typedef struct tagTrackerWindowInfo -{ - IDataObject* dataObject; - IDropSource* dropSource; - DWORD dwOKEffect; - DWORD* pdwEffect; - BOOL trackingDone; - HRESULT returnValue; - - BOOL escPressed; - HWND curTargetHWND; /* window the mouse is hovering over */ - HWND curDragTargetHWND; /* might be a ancestor of curTargetHWND */ - IDropTarget* curDragTarget; -} TrackerWindowInfo; - -typedef struct tagOleMenuDescriptor /* OleMenuDescriptor */ -{ - HWND hwndFrame; /* The containers frame window */ - HWND hwndActiveObject; /* The active objects window */ - OLEMENUGROUPWIDTHS mgw; /* OLE menu group widths for the shared menu */ - HMENU hmenuCombined; /* The combined menu */ - BOOL bIsServerItem; /* True if the currently open popup belongs to the server */ -} OleMenuDescriptor; - -typedef struct tagOleMenuHookItem /* OleMenu hook item in per thread hook list */ -{ - DWORD tid; /* Thread Id */ - HANDLE hHeap; /* Heap this is allocated from */ - HHOOK GetMsg_hHook; /* message hook for WH_GETMESSAGE */ - HHOOK CallWndProc_hHook; /* message hook for WH_CALLWNDPROC */ - struct tagOleMenuHookItem *next; -} OleMenuHookItem; - -static OleMenuHookItem *hook_list; - -/* - * This is the lock count on the OLE library. It is controlled by the - * OLEInitialize/OLEUninitialize methods. - */ -static ULONG OLE_moduleLockCount = 0; - -/* - * Name of our registered window class. - */ -static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32"; - -/* - * This is the head of the Drop target container. - */ -static DropTargetNode* targetListHead = NULL; - -/****************************************************************************** - * These are the prototypes of miscelaneous utility methods - */ -static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue); - -/****************************************************************************** - * These are the prototypes of the utility methods used to manage a shared menu - */ -static void OLEMenu_Initialize(void); -static void OLEMenu_UnInitialize(void); -BOOL OLEMenu_InstallHooks( DWORD tid ); -BOOL OLEMenu_UnInstallHooks( DWORD tid ); -OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid ); -static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos ); -BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor ); -LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam); -LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam); - -/****************************************************************************** - * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c) - */ -extern void OLEClipbrd_UnInitialize(void); -extern void OLEClipbrd_Initialize(void); - -/****************************************************************************** - * These are the prototypes of the utility methods used for OLE Drag n Drop - */ -static void OLEDD_Initialize(void); -static void OLEDD_UnInitialize(void); -static void OLEDD_InsertDropTarget( - DropTargetNode* nodeToAdd); -static DropTargetNode* OLEDD_ExtractDropTarget( - HWND hwndOfTarget); -static DropTargetNode* OLEDD_FindDropTarget( - HWND hwndOfTarget); -static LRESULT WINAPI OLEDD_DragTrackerWindowProc( - HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam); -static void OLEDD_TrackMouseMove( - TrackerWindowInfo* trackerInfo, - POINT mousePos, - DWORD keyState); -static void OLEDD_TrackStateChange( - TrackerWindowInfo* trackerInfo, - POINT mousePos, - DWORD keyState); -static DWORD OLEDD_GetButtonState(void); - - -/****************************************************************************** - * OleBuildVersion [OLE2.1] - * OleBuildVersion [OLE32.@] - */ -DWORD WINAPI OleBuildVersion(void) -{ - TRACE("Returning version %d, build %d.\n", rmm, rup); - return (rmm<<16)+rup; -} - -/*********************************************************************** - * OleInitialize (OLE2.2) - * OleInitialize (OLE32.@) - */ -HRESULT WINAPI OleInitialize(LPVOID reserved) -{ - HRESULT hr; - - TRACE("(%p)\n", reserved); - - /* - * The first duty of the OleInitialize is to initialize the COM libraries. - */ - hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); - - /* - * If the CoInitializeEx call failed, the OLE libraries can't be - * initialized. - */ - if (FAILED(hr)) - return hr; - - /* - * Then, it has to initialize the OLE specific modules. - * This includes: - * Clipboard - * Drag and Drop - * Object linking and Embedding - * In-place activation - */ - if (OLE_moduleLockCount==0) - { - /* - * Initialize the libraries. - */ - TRACE("() - Initializing the OLE libraries\n"); - - /* - * OLE Clipboard - */ - OLEClipbrd_Initialize(); - - /* - * Drag and Drop - */ - OLEDD_Initialize(); - - /* - * OLE shared menu - */ - OLEMenu_Initialize(); - } - - /* - * Then, we increase the lock count on the OLE module. - */ - OLE_moduleLockCount++; - - return hr; -} - -/****************************************************************************** - * OleUninitialize [OLE2.3] - * OleUninitialize [OLE32.@] - */ -void WINAPI OleUninitialize(void) -{ - TRACE("()\n"); - - /* - * Decrease the lock count on the OLE module. - */ - OLE_moduleLockCount--; - - /* - * If we hit the bottom of the lock stack, free the libraries. - */ - if (OLE_moduleLockCount==0) - { - /* - * Actually free the libraries. - */ - TRACE("() - Freeing the last reference count\n"); - - /* - * OLE Clipboard - */ - OLEClipbrd_UnInitialize(); - - /* - * Drag and Drop - */ - OLEDD_UnInitialize(); - - /* - * OLE shared menu - */ - OLEMenu_UnInitialize(); - } - - /* - * Then, uninitialize the COM libraries. - */ - CoUninitialize(); -} - -/****************************************************************************** - * OleInitializeWOW [OLE32.@] - */ -HRESULT WINAPI OleInitializeWOW(DWORD x) { - FIXME("(0x%08lx),stub!\n",x); - return 0; -} - -/*********************************************************************** - * RegisterDragDrop (OLE32.@) - */ -HRESULT WINAPI RegisterDragDrop( - HWND hwnd, - LPDROPTARGET pDropTarget) -{ - DropTargetNode* dropTargetInfo; - - TRACE("(%p,%p)\n", hwnd, pDropTarget); - - if (!pDropTarget) - return E_INVALIDARG; - - /* - * First, check if the window is already registered. - */ - dropTargetInfo = OLEDD_FindDropTarget(hwnd); - - if (dropTargetInfo!=NULL) - return DRAGDROP_E_ALREADYREGISTERED; - - /* - * If it's not there, we can add it. We first create a node for it. - */ - dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode)); - - if (dropTargetInfo==NULL) - return E_OUTOFMEMORY; - - dropTargetInfo->hwndTarget = hwnd; - dropTargetInfo->prevDropTarget = NULL; - dropTargetInfo->nextDropTarget = NULL; - - /* - * Don't forget that this is an interface pointer, need to nail it down since - * we keep a copy of it. - */ - dropTargetInfo->dropTarget = pDropTarget; - IDropTarget_AddRef(dropTargetInfo->dropTarget); - - OLEDD_InsertDropTarget(dropTargetInfo); - - return S_OK; -} - -/*********************************************************************** - * RevokeDragDrop (OLE32.@) - */ -HRESULT WINAPI RevokeDragDrop( - HWND hwnd) -{ - DropTargetNode* dropTargetInfo; - - TRACE("(%p)\n", hwnd); - - /* - * First, check if the window is already registered. - */ - dropTargetInfo = OLEDD_ExtractDropTarget(hwnd); - - /* - * If it ain't in there, it's an error. - */ - if (dropTargetInfo==NULL) - return DRAGDROP_E_NOTREGISTERED; - - /* - * If it's in there, clean-up it's used memory and - * references - */ - IDropTarget_Release(dropTargetInfo->dropTarget); - HeapFree(GetProcessHeap(), 0, dropTargetInfo); - - return S_OK; -} - -/*********************************************************************** - * OleRegGetUserType (OLE32.@) - * - * This implementation of OleRegGetUserType ignores the dwFormOfType - * parameter and always returns the full name of the object. This is - * not too bad since this is the case for many objects because of the - * way they are registered. - */ -HRESULT WINAPI OleRegGetUserType( - REFCLSID clsid, - DWORD dwFormOfType, - LPOLESTR* pszUserType) -{ - char keyName[60]; - DWORD dwKeyType; - DWORD cbData; - HKEY clsidKey; - LONG hres; - LPBYTE buffer; - HRESULT retVal; - /* - * Initialize the out parameter. - */ - *pszUserType = NULL; - - /* - * Build the key name we're looking for - */ - sprintf( keyName, "CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\", - clsid->Data1, clsid->Data2, clsid->Data3, - clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3], - clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] ); - - TRACE("(%s, %ld, %p)\n", keyName, dwFormOfType, pszUserType); - - /* - * Open the class id Key - */ - hres = RegOpenKeyA(HKEY_CLASSES_ROOT, - keyName, - &clsidKey); - - if (hres != ERROR_SUCCESS) - return REGDB_E_CLASSNOTREG; - - /* - * Retrieve the size of the name string. - */ - cbData = 0; - - hres = RegQueryValueExA(clsidKey, - "", - NULL, - &dwKeyType, - NULL, - &cbData); - - if (hres!=ERROR_SUCCESS) - { - RegCloseKey(clsidKey); - return REGDB_E_READREGDB; - } - - /* - * Allocate a buffer for the registry value. - */ - *pszUserType = CoTaskMemAlloc(cbData*2); - - if (*pszUserType==NULL) - { - RegCloseKey(clsidKey); - return E_OUTOFMEMORY; - } - - buffer = HeapAlloc(GetProcessHeap(), 0, cbData); - - if (buffer == NULL) - { - RegCloseKey(clsidKey); - CoTaskMemFree(*pszUserType); - *pszUserType=NULL; - return E_OUTOFMEMORY; - } - - hres = RegQueryValueExA(clsidKey, - "", - NULL, - &dwKeyType, - buffer, - &cbData); - - RegCloseKey(clsidKey); - - - if (hres!=ERROR_SUCCESS) - { - CoTaskMemFree(*pszUserType); - *pszUserType=NULL; - - retVal = REGDB_E_READREGDB; - } - else - { - MultiByteToWideChar( CP_ACP, 0, buffer, -1, *pszUserType, cbData /*FIXME*/ ); - retVal = S_OK; - } - HeapFree(GetProcessHeap(), 0, buffer); - - return retVal; -} - -/*********************************************************************** - * DoDragDrop [OLE32.@] - */ -HRESULT WINAPI DoDragDrop ( - IDataObject *pDataObject, /* [in] ptr to the data obj */ - IDropSource* pDropSource, /* [in] ptr to the source obj */ - DWORD dwOKEffect, /* [in] effects allowed by the source */ - DWORD *pdwEffect) /* [out] ptr to effects of the source */ -{ - TrackerWindowInfo trackerInfo; - HWND hwndTrackWindow; - MSG msg; - - TRACE("(DataObject %p, DropSource %p)\n", pDataObject, pDropSource); - - /* - * Setup the drag n drop tracking window. - */ - if (!IsValidInterface((LPUNKNOWN)pDropSource)) - return E_INVALIDARG; - - trackerInfo.dataObject = pDataObject; - trackerInfo.dropSource = pDropSource; - trackerInfo.dwOKEffect = dwOKEffect; - trackerInfo.pdwEffect = pdwEffect; - trackerInfo.trackingDone = FALSE; - trackerInfo.escPressed = FALSE; - trackerInfo.curDragTargetHWND = 0; - trackerInfo.curTargetHWND = 0; - trackerInfo.curDragTarget = 0; - - hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS, - "TrackerWindow", - WS_POPUP, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - 0, - 0, - 0, - (LPVOID)&trackerInfo); - - if (hwndTrackWindow!=0) - { - /* - * Capture the mouse input - */ - SetCapture(hwndTrackWindow); - - /* - * Pump messages. All mouse input should go the the capture window. - */ - while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) ) - { - if ( (msg.message >= WM_KEYFIRST) && - (msg.message <= WM_KEYLAST) ) - { - /* - * When keyboard messages are sent to windows on this thread, we - * want to ignore notify the drop source that the state changed. - * in the case of the Escape key, we also notify the drop source - * we give it a special meaning. - */ - if ( (msg.message==WM_KEYDOWN) && - (msg.wParam==VK_ESCAPE) ) - { - trackerInfo.escPressed = TRUE; - } - - /* - * Notify the drop source. - */ - OLEDD_TrackStateChange(&trackerInfo, - msg.pt, - OLEDD_GetButtonState()); - } - else - { - /* - * Dispatch the messages only when it's not a keyboard message. - */ - DispatchMessageA(&msg); - } - } - - /* - * Destroy the temporary window. - */ - DestroyWindow(hwndTrackWindow); - - return trackerInfo.returnValue; - } - - return E_FAIL; -} - -/*********************************************************************** - * OleQueryLinkFromData [OLE32.@] - */ -HRESULT WINAPI OleQueryLinkFromData( - IDataObject* pSrcDataObject) -{ - FIXME("(%p),stub!\n", pSrcDataObject); - return S_OK; -} - -/*********************************************************************** - * OleRegGetMiscStatus [OLE32.@] - */ -HRESULT WINAPI OleRegGetMiscStatus( - REFCLSID clsid, - DWORD dwAspect, - DWORD* pdwStatus) -{ - char keyName[60]; - HKEY clsidKey; - HKEY miscStatusKey; - HKEY aspectKey; - LONG result; - - /* - * Initialize the out parameter. - */ - *pdwStatus = 0; - - /* - * Build the key name we're looking for - */ - sprintf( keyName, "CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\", - clsid->Data1, clsid->Data2, clsid->Data3, - clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3], - clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] ); - - TRACE("(%s, %ld, %p)\n", keyName, dwAspect, pdwStatus); - - /* - * Open the class id Key - */ - result = RegOpenKeyA(HKEY_CLASSES_ROOT, - keyName, - &clsidKey); - - if (result != ERROR_SUCCESS) - return REGDB_E_CLASSNOTREG; - - /* - * Get the MiscStatus - */ - result = RegOpenKeyA(clsidKey, - "MiscStatus", - &miscStatusKey); - - - if (result != ERROR_SUCCESS) - { - RegCloseKey(clsidKey); - return REGDB_E_READREGDB; - } - - /* - * Read the default value - */ - OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus); - - /* - * Open the key specific to the requested aspect. - */ - sprintf(keyName, "%ld", dwAspect); - - result = RegOpenKeyA(miscStatusKey, - keyName, - &aspectKey); - - if (result == ERROR_SUCCESS) - { - OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus); - RegCloseKey(aspectKey); - } - - /* - * Cleanup - */ - RegCloseKey(miscStatusKey); - RegCloseKey(clsidKey); - - return S_OK; -} - -/****************************************************************************** - * OleSetContainedObject [OLE32.@] - */ -HRESULT WINAPI OleSetContainedObject( - LPUNKNOWN pUnknown, - BOOL fContained) -{ - IRunnableObject* runnable = NULL; - HRESULT hres; - - TRACE("(%p,%x), stub!\n", pUnknown, fContained); - - hres = IUnknown_QueryInterface(pUnknown, - &IID_IRunnableObject, - (void**)&runnable); - - if (SUCCEEDED(hres)) - { - hres = IRunnableObject_SetContainedObject(runnable, fContained); - - IRunnableObject_Release(runnable); - - return hres; - } - - return S_OK; -} - -/****************************************************************************** - * OleLoad [OLE32.@] - */ -HRESULT WINAPI OleLoad( - LPSTORAGE pStg, - REFIID riid, - LPOLECLIENTSITE pClientSite, - LPVOID* ppvObj) -{ - IPersistStorage* persistStorage = NULL; - IOleObject* oleObject = NULL; - STATSTG storageInfo; - HRESULT hres; - - TRACE("(%p,%p,%p,%p)\n", pStg, riid, pClientSite, ppvObj); - - /* - * TODO, Conversion ... OleDoAutoConvert - */ - - /* - * Get the class ID for the object. - */ - hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME); - - /* - * Now, try and create the handler for the object - */ - hres = CoCreateInstance(&storageInfo.clsid, - NULL, - CLSCTX_INPROC_HANDLER, - &IID_IOleObject, - (void**)&oleObject); - - /* - * If that fails, as it will most times, load the default - * OLE handler. - */ - if (FAILED(hres)) - { - hres = OleCreateDefaultHandler(&storageInfo.clsid, - NULL, - &IID_IOleObject, - (void**)&oleObject); - } - - /* - * If we couldn't find a handler... this is bad. Abort the whole thing. - */ - if (FAILED(hres)) - return hres; - - /* - * Inform the new object of it's client site. - */ - hres = IOleObject_SetClientSite(oleObject, pClientSite); - - /* - * Initialize the object with it's IPersistStorage interface. - */ - hres = IOleObject_QueryInterface(oleObject, - &IID_IPersistStorage, - (void**)&persistStorage); - - if (SUCCEEDED(hres)) - { - IPersistStorage_Load(persistStorage, pStg); - - IPersistStorage_Release(persistStorage); - persistStorage = NULL; - } - - /* - * Return the requested interface to the caller. - */ - hres = IOleObject_QueryInterface(oleObject, riid, ppvObj); - - /* - * Cleanup interfaces used internally - */ - IOleObject_Release(oleObject); - - return hres; -} - -/*********************************************************************** - * OleSave [OLE32.@] - */ -HRESULT WINAPI OleSave( - LPPERSISTSTORAGE pPS, - LPSTORAGE pStg, - BOOL fSameAsLoad) -{ - HRESULT hres; - CLSID objectClass; - - TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad); - - /* - * First, we transfer the class ID (if available) - */ - hres = IPersistStorage_GetClassID(pPS, &objectClass); - - if (SUCCEEDED(hres)) - { - WriteClassStg(pStg, &objectClass); - } - - /* - * Then, we ask the object to save itself to the - * storage. If it is successful, we commit the storage. - */ - hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad); - - if (SUCCEEDED(hres)) - { - IStorage_Commit(pStg, - STGC_DEFAULT); - } - - return hres; -} - - -/****************************************************************************** - * OleLockRunning [OLE32.@] - */ -HRESULT WINAPI OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCloses) -{ - IRunnableObject* runnable = NULL; - HRESULT hres; - - TRACE("(%p,%x,%x)\n", pUnknown, fLock, fLastUnlockCloses); - - hres = IUnknown_QueryInterface(pUnknown, - &IID_IRunnableObject, - (void**)&runnable); - - if (SUCCEEDED(hres)) - { - hres = IRunnableObject_LockRunning(runnable, fLock, fLastUnlockCloses); - - IRunnableObject_Release(runnable); - - return hres; - } - else - return E_INVALIDARG; -} - - -/************************************************************************** - * Internal methods to manage the shared OLE menu in response to the - * OLE***MenuDescriptor API - */ - -/*** - * OLEMenu_Initialize() - * - * Initializes the OLEMENU data structures. - */ -static void OLEMenu_Initialize() -{ -} - -/*** - * OLEMenu_UnInitialize() - * - * Releases the OLEMENU data structures. - */ -static void OLEMenu_UnInitialize() -{ -} - -/************************************************************************* - * OLEMenu_InstallHooks - * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC - * - * RETURNS: TRUE if message hooks were successfully installed - * FALSE on failure - */ -BOOL OLEMenu_InstallHooks( DWORD tid ) -{ - OleMenuHookItem *pHookItem = NULL; - - /* Create an entry for the hook table */ - if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0, - sizeof(OleMenuHookItem)) ) ) - return FALSE; - - pHookItem->tid = tid; - pHookItem->hHeap = GetProcessHeap(); - - /* Install a thread scope message hook for WH_GETMESSAGE */ - pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc, - 0, GetCurrentThreadId() ); - if ( !pHookItem->GetMsg_hHook ) - goto CLEANUP; - - /* Install a thread scope message hook for WH_CALLWNDPROC */ - pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc, - 0, GetCurrentThreadId() ); - if ( !pHookItem->CallWndProc_hHook ) - goto CLEANUP; - - /* Insert the hook table entry */ - pHookItem->next = hook_list; - hook_list = pHookItem; - - return TRUE; - -CLEANUP: - /* Unhook any hooks */ - if ( pHookItem->GetMsg_hHook ) - UnhookWindowsHookEx( pHookItem->GetMsg_hHook ); - if ( pHookItem->CallWndProc_hHook ) - UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ); - /* Release the hook table entry */ - HeapFree(pHookItem->hHeap, 0, pHookItem ); - - return FALSE; -} - -/************************************************************************* - * OLEMenu_UnInstallHooks - * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC - * - * RETURNS: TRUE if message hooks were successfully installed - * FALSE on failure - */ -BOOL OLEMenu_UnInstallHooks( DWORD tid ) -{ - OleMenuHookItem *pHookItem = NULL; - OleMenuHookItem **ppHook = &hook_list; - - while (*ppHook) - { - if ((*ppHook)->tid == tid) - { - pHookItem = *ppHook; - *ppHook = pHookItem->next; - break; - } - ppHook = &(*ppHook)->next; - } - if (!pHookItem) return FALSE; - - /* Uninstall the hooks installed for this thread */ - if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) ) - goto CLEANUP; - if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) ) - goto CLEANUP; - - /* Release the hook table entry */ - HeapFree(pHookItem->hHeap, 0, pHookItem ); - - return TRUE; - -CLEANUP: - /* Release the hook table entry */ - HeapFree(pHookItem->hHeap, 0, pHookItem ); - - return FALSE; -} - -/************************************************************************* - * OLEMenu_IsHookInstalled - * Tests if OLEMenu hooks have been installed for a thread - * - * RETURNS: The pointer and index of the hook table entry for the tid - * NULL and -1 for the index if no hooks were installed for this thread - */ -OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid ) -{ - OleMenuHookItem *pHookItem = NULL; - - /* Do a simple linear search for an entry whose tid matches ours. - * We really need a map but efficiency is not a concern here. */ - for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next) - { - if ( tid == pHookItem->tid ) - return pHookItem; - } - - return NULL; -} - -/*********************************************************************** - * OLEMenu_FindMainMenuIndex - * - * Used by OLEMenu API to find the top level group a menu item belongs to. - * On success pnPos contains the index of the item in the top level menu group - * - * RETURNS: TRUE if the ID was found, FALSE on failure - */ -static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos ) -{ - UINT i, nItems; - - nItems = GetMenuItemCount( hMainMenu ); - - for (i = 0; i < nItems; i++) - { - HMENU hsubmenu; - - /* Is the current item a submenu? */ - if ( (hsubmenu = GetSubMenu(hMainMenu, i)) ) - { - /* If the handle is the same we're done */ - if ( hsubmenu == hPopupMenu ) - { - if (pnPos) - *pnPos = i; - return TRUE; - } - /* Recursively search without updating pnPos */ - else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) ) - { - if (pnPos) - *pnPos = i; - return TRUE; - } - } - } - - return FALSE; -} - -/*********************************************************************** - * OLEMenu_SetIsServerMenu - * - * Checks whether a popup menu belongs to a shared menu group which is - * owned by the server, and sets the menu descriptor state accordingly. - * All menu messages from these groups should be routed to the server. - * - * RETURNS: TRUE if the popup menu is part of a server owned group - * FALSE if the popup menu is part of a container owned group - */ -BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor ) -{ - UINT nPos = 0, nWidth, i; - - pOleMenuDescriptor->bIsServerItem = FALSE; - - /* Don't bother searching if the popup is the combined menu itself */ - if ( hmenu == pOleMenuDescriptor->hmenuCombined ) - return FALSE; - - /* Find the menu item index in the shared OLE menu that this item belongs to */ - if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) ) - return FALSE; - - /* The group widths array has counts for the number of elements - * in the groups File, Edit, Container, Object, Window, Help. - * The Edit, Object & Help groups belong to the server object - * and the other three belong to the container. - * Loop through the group widths and locate the group we are a member of. - */ - for ( i = 0, nWidth = 0; i < 6; i++ ) - { - nWidth += pOleMenuDescriptor->mgw.width[i]; - if ( nPos < nWidth ) - { - /* Odd elements are server menu widths */ - pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE; - break; - } - } - - return pOleMenuDescriptor->bIsServerItem; -} - -/************************************************************************* - * OLEMenu_CallWndProc - * Thread scope WH_CALLWNDPROC hook proc filter function (callback) - * This is invoked from a message hook installed in OleSetMenuDescriptor. - */ -LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam) -{ - LPCWPSTRUCT pMsg = NULL; - HOLEMENU hOleMenu = 0; - OleMenuDescriptor *pOleMenuDescriptor = NULL; - OleMenuHookItem *pHookItem = NULL; - WORD fuFlags; - - TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam ); - - /* Check if we're being asked to process the message */ - if ( HC_ACTION != code ) - goto NEXTHOOK; - - /* Retrieve the current message being dispatched from lParam */ - pMsg = (LPCWPSTRUCT)lParam; - - /* Check if the message is destined for a window we are interested in: - * If the window has an OLEMenu property we may need to dispatch - * the menu message to its active objects window instead. */ - - hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" ); - if ( !hOleMenu ) - goto NEXTHOOK; - - /* Get the menu descriptor */ - pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu ); - if ( !pOleMenuDescriptor ) /* Bad descriptor! */ - goto NEXTHOOK; - - /* Process menu messages */ - switch( pMsg->message ) - { - case WM_INITMENU: - { - /* Reset the menu descriptor state */ - pOleMenuDescriptor->bIsServerItem = FALSE; - - /* Send this message to the server as well */ - SendMessageA( pOleMenuDescriptor->hwndActiveObject, - pMsg->message, pMsg->wParam, pMsg->lParam ); - goto NEXTHOOK; - } - - case WM_INITMENUPOPUP: - { - /* Save the state for whether this is a server owned menu */ - OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor ); - break; - } - - case WM_MENUSELECT: - { - fuFlags = HIWORD(pMsg->wParam); /* Get flags */ - if ( fuFlags & MF_SYSMENU ) - goto NEXTHOOK; - - /* Save the state for whether this is a server owned popup menu */ - else if ( fuFlags & MF_POPUP ) - OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor ); - - break; - } - - case WM_DRAWITEM: - { - LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam; - if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU ) - goto NEXTHOOK; /* Not a menu message */ - - break; - } - - default: - goto NEXTHOOK; - } - - /* If the message was for the server dispatch it accordingly */ - if ( pOleMenuDescriptor->bIsServerItem ) - { - SendMessageA( pOleMenuDescriptor->hwndActiveObject, - pMsg->message, pMsg->wParam, pMsg->lParam ); - } - -NEXTHOOK: - if ( pOleMenuDescriptor ) - GlobalUnlock( hOleMenu ); - - /* Lookup the hook item for the current thread */ - if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) ) - { - /* This should never fail!! */ - WARN("could not retrieve hHook for current thread!\n" ); - return 0; - } - - /* Pass on the message to the next hooker */ - return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam ); -} - -/************************************************************************* - * OLEMenu_GetMsgProc - * Thread scope WH_GETMESSAGE hook proc filter function (callback) - * This is invoked from a message hook installed in OleSetMenuDescriptor. - */ -LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam) -{ - LPMSG pMsg = NULL; - HOLEMENU hOleMenu = 0; - OleMenuDescriptor *pOleMenuDescriptor = NULL; - OleMenuHookItem *pHookItem = NULL; - WORD wCode; - - TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam ); - - /* Check if we're being asked to process a messages */ - if ( HC_ACTION != code ) - goto NEXTHOOK; - - /* Retrieve the current message being dispatched from lParam */ - pMsg = (LPMSG)lParam; - - /* Check if the message is destined for a window we are interested in: - * If the window has an OLEMenu property we may need to dispatch - * the menu message to its active objects window instead. */ - - hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" ); - if ( !hOleMenu ) - goto NEXTHOOK; - - /* Process menu messages */ - switch( pMsg->message ) - { - case WM_COMMAND: - { - wCode = HIWORD(pMsg->wParam); /* Get notification code */ - if ( wCode ) - goto NEXTHOOK; /* Not a menu message */ - break; - } - default: - goto NEXTHOOK; - } - - /* Get the menu descriptor */ - pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu ); - if ( !pOleMenuDescriptor ) /* Bad descriptor! */ - goto NEXTHOOK; - - /* If the message was for the server dispatch it accordingly */ - if ( pOleMenuDescriptor->bIsServerItem ) - { - /* Change the hWnd in the message to the active objects hWnd. - * The message loop which reads this message will automatically - * dispatch it to the embedded objects window. */ - pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject; - } - -NEXTHOOK: - if ( pOleMenuDescriptor ) - GlobalUnlock( hOleMenu ); - - /* Lookup the hook item for the current thread */ - if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) ) - { - /* This should never fail!! */ - WARN("could not retrieve hHook for current thread!\n" ); - return FALSE; - } - - /* Pass on the message to the next hooker */ - return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam ); -} - -/*********************************************************************** - * OleCreateMenuDescriptor [OLE32.@] - * Creates an OLE menu descriptor for OLE to use when dispatching - * menu messages and commands. - * - * PARAMS: - * hmenuCombined - Handle to the objects combined menu - * lpMenuWidths - Pointer to array of 6 LONG's indicating menus per group - * - */ -HOLEMENU WINAPI OleCreateMenuDescriptor( - HMENU hmenuCombined, - LPOLEMENUGROUPWIDTHS lpMenuWidths) -{ - HOLEMENU hOleMenu; - OleMenuDescriptor *pOleMenuDescriptor; - int i; - - if ( !hmenuCombined || !lpMenuWidths ) - return 0; - - /* Create an OLE menu descriptor */ - if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, - sizeof(OleMenuDescriptor) ) ) ) - return 0; - - pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu ); - if ( !pOleMenuDescriptor ) - return 0; - - /* Initialize menu group widths and hmenu */ - for ( i = 0; i < 6; i++ ) - pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i]; - - pOleMenuDescriptor->hmenuCombined = hmenuCombined; - pOleMenuDescriptor->bIsServerItem = FALSE; - GlobalUnlock( hOleMenu ); - - return hOleMenu; -} - -/*********************************************************************** - * OleDestroyMenuDescriptor [OLE32.@] - * Destroy the shared menu descriptor - */ -HRESULT WINAPI OleDestroyMenuDescriptor( - HOLEMENU hmenuDescriptor) -{ - if ( hmenuDescriptor ) - GlobalFree( hmenuDescriptor ); - return S_OK; -} - -/*********************************************************************** - * OleSetMenuDescriptor [OLE32.@] - * Installs or removes OLE dispatching code for the containers frame window - * FIXME: The lpFrame and lpActiveObject parameters are currently ignored - * OLE should install context sensitive help F1 filtering for the app when - * these are non null. - * - * PARAMS: - * hOleMenu Handle to composite menu descriptor - * hwndFrame Handle to containers frame window - * hwndActiveObject Handle to objects in-place activation window - * lpFrame Pointer to IOleInPlaceFrame on containers window - * lpActiveObject Pointer to IOleInPlaceActiveObject on active in-place object - * - * RETURNS: - * S_OK - menu installed correctly - * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure - */ -HRESULT WINAPI OleSetMenuDescriptor( - HOLEMENU hOleMenu, - HWND hwndFrame, - HWND hwndActiveObject, - LPOLEINPLACEFRAME lpFrame, - LPOLEINPLACEACTIVEOBJECT lpActiveObject) -{ - OleMenuDescriptor *pOleMenuDescriptor = NULL; - - /* Check args */ - if ( !hwndFrame || (hOleMenu && !hwndActiveObject) ) - return E_INVALIDARG; - - if ( lpFrame || lpActiveObject ) - { - FIXME("(%x, %p, %p, %p, %p), Context sensitive help filtering not implemented!\n", - (unsigned int)hOleMenu, - hwndFrame, - hwndActiveObject, - lpFrame, - lpActiveObject); - } - - /* Set up a message hook to intercept the containers frame window messages. - * The message filter is responsible for dispatching menu messages from the - * shared menu which are intended for the object. - */ - - if ( hOleMenu ) /* Want to install dispatching code */ - { - /* If OLEMenu hooks are already installed for this thread, fail - * Note: This effectively means that OleSetMenuDescriptor cannot - * be called twice in succession on the same frame window - * without first calling it with a null hOleMenu to uninstall */ - if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) - return E_FAIL; - - /* Get the menu descriptor */ - pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu ); - if ( !pOleMenuDescriptor ) - return E_UNEXPECTED; - - /* Update the menu descriptor */ - pOleMenuDescriptor->hwndFrame = hwndFrame; - pOleMenuDescriptor->hwndActiveObject = hwndActiveObject; - - GlobalUnlock( hOleMenu ); - pOleMenuDescriptor = NULL; - - /* Add a menu descriptor windows property to the frame window */ - SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu ); - - /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */ - if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) ) - return E_FAIL; - } - else /* Want to uninstall dispatching code */ - { - /* Uninstall the hooks */ - if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) ) - return E_FAIL; - - /* Remove the menu descriptor property from the frame window */ - RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" ); - } - - return S_OK; -} - -/****************************************************************************** - * IsAccelerator [OLE32.@] - * Mostly copied from controls/menu.c TranslateAccelerator implementation - */ -BOOL WINAPI IsAccelerator(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD* lpwCmd) -{ - LPACCEL lpAccelTbl; - int i; - - if(!lpMsg) return FALSE; - if (!hAccel) - { - WARN_(accel)("NULL accel handle\n"); - return FALSE; - } - if((lpMsg->message != WM_KEYDOWN && - lpMsg->message != WM_KEYUP && - lpMsg->message != WM_SYSKEYDOWN && - lpMsg->message != WM_SYSKEYUP && - lpMsg->message != WM_CHAR)) return FALSE; - lpAccelTbl = HeapAlloc(GetProcessHeap(), 0, cAccelEntries * sizeof(ACCEL)); - if (NULL == lpAccelTbl) - { - return FALSE; - } - if (CopyAcceleratorTableW(hAccel, lpAccelTbl, cAccelEntries) != cAccelEntries) - { - WARN_(accel)("CopyAcceleratorTableW failed\n"); - HeapFree(GetProcessHeap(), 0, lpAccelTbl); - return FALSE; - } - - TRACE_(accel)("hAccel=%p, cAccelEntries=%d," - "msg->hwnd=%p, msg->message=%04x, wParam=%08x, lParam=%08lx\n", - hAccel, cAccelEntries, - lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam); - for(i = 0; i < cAccelEntries; i++) - { - if(lpAccelTbl[i].key != lpMsg->wParam) - continue; - - if(lpMsg->message == WM_CHAR) - { - if(!(lpAccelTbl[i].fVirt & FALT) && !(lpAccelTbl[i].fVirt & FVIRTKEY)) - { - TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", lpMsg->wParam & 0xff); - goto found; - } - } - else - { - if(lpAccelTbl[i].fVirt & FVIRTKEY) - { - INT mask = 0; - TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n", - lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff); - if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT; - if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL; - if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT; - if(mask == (lpAccelTbl[i].fVirt & (FSHIFT | FCONTROL | FALT))) goto found; - TRACE_(accel)("incorrect SHIFT/CTRL/ALT-state\n"); - } - else - { - if(!(lpMsg->lParam & 0x01000000)) /* no special_key */ - { - if((lpAccelTbl[i].fVirt & FALT) && (lpMsg->lParam & 0x20000000)) - { /* ^^ ALT pressed */ - TRACE_(accel)("found accel for Alt-%c\n", lpMsg->wParam & 0xff); - goto found; - } - } - } - } - } - - WARN_(accel)("couldn't translate accelerator key\n"); - HeapFree(GetProcessHeap(), 0, lpAccelTbl); - return FALSE; - -found: - if(lpwCmd) *lpwCmd = lpAccelTbl[i].cmd; - HeapFree(GetProcessHeap(), 0, lpAccelTbl); - return TRUE; -} - -/*********************************************************************** - * ReleaseStgMedium [OLE32.@] - */ -void WINAPI ReleaseStgMedium( - STGMEDIUM* pmedium) -{ - switch (pmedium->tymed) - { - case TYMED_HGLOBAL: - { - if ( (pmedium->pUnkForRelease==0) && - (pmedium->u.hGlobal!=0) ) - GlobalFree(pmedium->u.hGlobal); - break; - } - case TYMED_FILE: - { - if (pmedium->u.lpszFileName!=0) - { - if (pmedium->pUnkForRelease==0) - { - DeleteFileW(pmedium->u.lpszFileName); - } - - CoTaskMemFree(pmedium->u.lpszFileName); - } - break; - } - case TYMED_ISTREAM: - { - if (pmedium->u.pstm!=0) - { - IStream_Release(pmedium->u.pstm); - } - break; - } - case TYMED_ISTORAGE: - { - if (pmedium->u.pstg!=0) - { - IStorage_Release(pmedium->u.pstg); - } - break; - } - case TYMED_GDI: - { - if ( (pmedium->pUnkForRelease==0) && - (pmedium->u.hBitmap!=0) ) - DeleteObject(pmedium->u.hBitmap); - break; - } - case TYMED_MFPICT: - { - if ( (pmedium->pUnkForRelease==0) && - (pmedium->u.hMetaFilePict!=0) ) - { - LPMETAFILEPICT pMP = GlobalLock(pmedium->u.hMetaFilePict); - DeleteMetaFile(pMP->hMF); - GlobalUnlock(pmedium->u.hMetaFilePict); - GlobalFree(pmedium->u.hMetaFilePict); - } - break; - } - case TYMED_ENHMF: - { - if ( (pmedium->pUnkForRelease==0) && - (pmedium->u.hEnhMetaFile!=0) ) - { - DeleteEnhMetaFile(pmedium->u.hEnhMetaFile); - } - break; - } - case TYMED_NULL: - default: - break; - } - pmedium->tymed=TYMED_NULL; - - /* - * After cleaning up, the unknown is released - */ - if (pmedium->pUnkForRelease!=0) - { - IUnknown_Release(pmedium->pUnkForRelease); - pmedium->pUnkForRelease = 0; - } -} - -/*** - * OLEDD_Initialize() - * - * Initializes the OLE drag and drop data structures. - */ -static void OLEDD_Initialize() -{ - WNDCLASSA wndClass; - - ZeroMemory (&wndClass, sizeof(WNDCLASSA)); - wndClass.style = CS_GLOBALCLASS; - wndClass.lpfnWndProc = OLEDD_DragTrackerWindowProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = sizeof(TrackerWindowInfo*); - wndClass.hCursor = 0; - wndClass.hbrBackground = 0; - wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS; - - RegisterClassA (&wndClass); -} - -/*** - * OLEDD_UnInitialize() - * - * Releases the OLE drag and drop data structures. - */ -static void OLEDD_UnInitialize() -{ - /* - * Simply empty the list. - */ - while (targetListHead!=NULL) - { - RevokeDragDrop(targetListHead->hwndTarget); - } -} - -/*** - * OLEDD_InsertDropTarget() - * - * Insert the target node in the tree. - */ -static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd) -{ - DropTargetNode* curNode; - DropTargetNode** parentNodeLink; - - /* - * Iterate the tree to find the insertion point. - */ - curNode = targetListHead; - parentNodeLink = &targetListHead; - - while (curNode!=NULL) - { - if (nodeToAdd->hwndTarget<curNode->hwndTarget) - { - /* - * If the node we want to add has a smaller HWND, go left - */ - parentNodeLink = &curNode->prevDropTarget; - curNode = curNode->prevDropTarget; - } - else if (nodeToAdd->hwndTarget>curNode->hwndTarget) - { - /* - * If the node we want to add has a larger HWND, go right - */ - parentNodeLink = &curNode->nextDropTarget; - curNode = curNode->nextDropTarget; - } - else - { - /* - * The item was found in the list. It shouldn't have been there - */ - assert(FALSE); - return; - } - } - - /* - * If we get here, we have found a spot for our item. The parentNodeLink - * pointer points to the pointer that we have to modify. - * The curNode should be NULL. We just have to establish the link and Voila! - */ - assert(curNode==NULL); - assert(parentNodeLink!=NULL); - assert(*parentNodeLink==NULL); - - *parentNodeLink=nodeToAdd; -} - -/*** - * OLEDD_ExtractDropTarget() - * - * Removes the target node from the tree. - */ -static DropTargetNode* OLEDD_ExtractDropTarget(HWND hwndOfTarget) -{ - DropTargetNode* curNode; - DropTargetNode** parentNodeLink; - - /* - * Iterate the tree to find the insertion point. - */ - curNode = targetListHead; - parentNodeLink = &targetListHead; - - while (curNode!=NULL) - { - if (hwndOfTarget<curNode->hwndTarget) - { - /* - * If the node we want to add has a smaller HWND, go left - */ - parentNodeLink = &curNode->prevDropTarget; - curNode = curNode->prevDropTarget; - } - else if (hwndOfTarget>curNode->hwndTarget) - { - /* - * If the node we want to add has a larger HWND, go right - */ - parentNodeLink = &curNode->nextDropTarget; - curNode = curNode->nextDropTarget; - } - else - { - /* - * The item was found in the list. Detach it from it's parent and - * re-insert it's kids in the tree. - */ - assert(parentNodeLink!=NULL); - assert(*parentNodeLink==curNode); - - /* - * We arbitrately re-attach the left sub-tree to the parent. - */ - *parentNodeLink = curNode->prevDropTarget; - - /* - * And we re-insert the right subtree - */ - if (curNode->nextDropTarget!=NULL) - { - OLEDD_InsertDropTarget(curNode->nextDropTarget); - } - - /* - * The node we found is still a valid node once we complete - * the unlinking of the kids. - */ - curNode->nextDropTarget=NULL; - curNode->prevDropTarget=NULL; - - return curNode; - } - } - - /* - * If we get here, the node is not in the tree - */ - return NULL; -} - -/*** - * OLEDD_FindDropTarget() - * - * Finds information about the drop target. - */ -static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget) -{ - DropTargetNode* curNode; - - /* - * Iterate the tree to find the HWND value. - */ - curNode = targetListHead; - - while (curNode!=NULL) - { - if (hwndOfTarget<curNode->hwndTarget) - { - /* - * If the node we want to add has a smaller HWND, go left - */ - curNode = curNode->prevDropTarget; - } - else if (hwndOfTarget>curNode->hwndTarget) - { - /* - * If the node we want to add has a larger HWND, go right - */ - curNode = curNode->nextDropTarget; - } - else - { - /* - * The item was found in the list. - */ - return curNode; - } - } - - /* - * If we get here, the item is not in the list - */ - return NULL; -} - -/*** - * OLEDD_DragTrackerWindowProc() - * - * This method is the WindowProcedure of the drag n drop tracking - * window. During a drag n Drop operation, an invisible window is created - * to receive the user input and act upon it. This procedure is in charge - * of this behavior. - */ -static LRESULT WINAPI OLEDD_DragTrackerWindowProc( - HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) -{ - switch (uMsg) - { - case WM_CREATE: - { - LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam; - - SetWindowLongA(hwnd, 0, (LONG)createStruct->lpCreateParams); - - - break; - } - case WM_MOUSEMOVE: - { - TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0); - POINT mousePos; - - /* - * Get the current mouse position in screen coordinates. - */ - mousePos.x = LOWORD(lParam); - mousePos.y = HIWORD(lParam); - ClientToScreen(hwnd, &mousePos); - - /* - * Track the movement of the mouse. - */ - OLEDD_TrackMouseMove(trackerInfo, mousePos, wParam); - - break; - } - case WM_LBUTTONUP: - case WM_MBUTTONUP: - case WM_RBUTTONUP: - case WM_LBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_RBUTTONDOWN: - { - TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0); - POINT mousePos; - - /* - * Get the current mouse position in screen coordinates. - */ - mousePos.x = LOWORD(lParam); - mousePos.y = HIWORD(lParam); - ClientToScreen(hwnd, &mousePos); - - /* - * Notify everyone that the button state changed - * TODO: Check if the "escape" key was pressed. - */ - OLEDD_TrackStateChange(trackerInfo, mousePos, wParam); - - break; - } - } - - /* - * This is a window proc after all. Let's call the default. - */ - return DefWindowProcA (hwnd, uMsg, wParam, lParam); -} - -/*** - * OLEDD_TrackMouseMove() - * - * This method is invoked while a drag and drop operation is in effect. - * it will generate the appropriate callbacks in the drop source - * and drop target. It will also provide the expected feedback to - * the user. - * - * params: - * trackerInfo - Pointer to the structure identifying the - * drag & drop operation that is currently - * active. - * mousePos - Current position of the mouse in screen - * coordinates. - * keyState - Contains the state of the shift keys and the - * mouse buttons (MK_LBUTTON and the like) - */ -static void OLEDD_TrackMouseMove( - TrackerWindowInfo* trackerInfo, - POINT mousePos, - DWORD keyState) -{ - HWND hwndNewTarget = 0; - HRESULT hr = S_OK; - - /* - * Get the handle of the window under the mouse - */ - hwndNewTarget = WindowFromPoint(mousePos); - - /* - * Every time, we re-initialize the effects passed to the - * IDropTarget to the effects allowed by the source. - */ - *trackerInfo->pdwEffect = trackerInfo->dwOKEffect; - - /* - * If we are hovering over the same target as before, send the - * DragOver notification - */ - if ( (trackerInfo->curDragTarget != 0) && - (trackerInfo->curTargetHWND == hwndNewTarget) ) - { - POINTL mousePosParam; - - /* - * The documentation tells me that the coordinate should be in the target - * window's coordinate space. However, the tests I made tell me the - * coordinates should be in screen coordinates. - */ - mousePosParam.x = mousePos.x; - mousePosParam.y = mousePos.y; - - IDropTarget_DragOver(trackerInfo->curDragTarget, - keyState, - mousePosParam, - trackerInfo->pdwEffect); - } - else - { - DropTargetNode* newDropTargetNode = 0; - - /* - * If we changed window, we have to notify our old target and check for - * the new one. - */ - if (trackerInfo->curDragTarget!=0) - { - IDropTarget_DragLeave(trackerInfo->curDragTarget); - } - - /* - * Make sure we're hovering over a window. - */ - if (hwndNewTarget!=0) - { - /* - * Find-out if there is a drag target under the mouse - */ - HWND nexttar = hwndNewTarget; - trackerInfo->curTargetHWND = hwndNewTarget; - - do { - newDropTargetNode = OLEDD_FindDropTarget(nexttar); - } while (!newDropTargetNode && (nexttar = GetParent(nexttar)) != 0); - if(nexttar) hwndNewTarget = nexttar; - - trackerInfo->curDragTargetHWND = hwndNewTarget; - trackerInfo->curDragTarget = newDropTargetNode ? newDropTargetNode->dropTarget : 0; - - /* - * If there is, notify it that we just dragged-in - */ - if (trackerInfo->curDragTarget!=0) - { - POINTL mousePosParam; - - /* - * The documentation tells me that the coordinate should be in the target - * window's coordinate space. However, the tests I made tell me the - * coordinates should be in screen coordinates. - */ - mousePosParam.x = mousePos.x; - mousePosParam.y = mousePos.y; - - IDropTarget_DragEnter(trackerInfo->curDragTarget, - trackerInfo->dataObject, - keyState, - mousePosParam, - trackerInfo->pdwEffect); - } - } - else - { - /* - * The mouse is not over a window so we don't track anything. - */ - trackerInfo->curDragTargetHWND = 0; - trackerInfo->curTargetHWND = 0; - trackerInfo->curDragTarget = 0; - } - } - - /* - * Now that we have done that, we have to tell the source to give - * us feedback on the work being done by the target. If we don't - * have a target, simulate no effect. - */ - if (trackerInfo->curDragTarget==0) - { - *trackerInfo->pdwEffect = DROPEFFECT_NONE; - } - - hr = IDropSource_GiveFeedback(trackerInfo->dropSource, - *trackerInfo->pdwEffect); - - /* - * When we ask for feedback from the drop source, sometimes it will - * do all the necessary work and sometimes it will not handle it - * when that's the case, we must display the standard drag and drop - * cursors. - */ - if (hr==DRAGDROP_S_USEDEFAULTCURSORS) - { - if (*trackerInfo->pdwEffect & DROPEFFECT_MOVE) - { - SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(1))); - } - else if (*trackerInfo->pdwEffect & DROPEFFECT_COPY) - { - SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(2))); - } - else if (*trackerInfo->pdwEffect & DROPEFFECT_LINK) - { - SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(3))); - } - else - { - SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(0))); - } - } -} - -/*** - * OLEDD_TrackStateChange() - * - * This method is invoked while a drag and drop operation is in effect. - * It is used to notify the drop target/drop source callbacks when - * the state of the keyboard or mouse button change. - * - * params: - * trackerInfo - Pointer to the structure identifying the - * drag & drop operation that is currently - * active. - * mousePos - Current position of the mouse in screen - * coordinates. - * keyState - Contains the state of the shift keys and the - * mouse buttons (MK_LBUTTON and the like) - */ -static void OLEDD_TrackStateChange( - TrackerWindowInfo* trackerInfo, - POINT mousePos, - DWORD keyState) -{ - /* - * Ask the drop source what to do with the operation. - */ - trackerInfo->returnValue = IDropSource_QueryContinueDrag( - trackerInfo->dropSource, - trackerInfo->escPressed, - keyState); - - /* - * All the return valued will stop the operation except the S_OK - * return value. - */ - if (trackerInfo->returnValue!=S_OK) - { - /* - * Make sure the message loop in DoDragDrop stops - */ - trackerInfo->trackingDone = TRUE; - - /* - * Release the mouse in case the drop target decides to show a popup - * or a menu or something. - */ - ReleaseCapture(); - - /* - * If we end-up over a target, drop the object in the target or - * inform the target that the operation was cancelled. - */ - if (trackerInfo->curDragTarget!=0) - { - switch (trackerInfo->returnValue) - { - /* - * If the source wants us to complete the operation, we tell - * the drop target that we just dropped the object in it. - */ - case DRAGDROP_S_DROP: - { - POINTL mousePosParam; - - /* - * The documentation tells me that the coordinate should be - * in the target window's coordinate space. However, the tests - * I made tell me the coordinates should be in screen coordinates. - */ - mousePosParam.x = mousePos.x; - mousePosParam.y = mousePos.y; - - IDropTarget_Drop(trackerInfo->curDragTarget, - trackerInfo->dataObject, - keyState, - mousePosParam, - trackerInfo->pdwEffect); - break; - } - /* - * If the source told us that we should cancel, fool the drop - * target by telling it that the mouse left it's window. - * Also set the drop effect to "NONE" in case the application - * ignores the result of DoDragDrop. - */ - case DRAGDROP_S_CANCEL: - IDropTarget_DragLeave(trackerInfo->curDragTarget); - *trackerInfo->pdwEffect = DROPEFFECT_NONE; - break; - } - } - } -} - -/*** - * OLEDD_GetButtonState() - * - * This method will use the current state of the keyboard to build - * a button state mask equivalent to the one passed in the - * WM_MOUSEMOVE wParam. - */ -static DWORD OLEDD_GetButtonState() -{ - BYTE keyboardState[256]; - DWORD keyMask = 0; - - GetKeyboardState(keyboardState); - - if ( (keyboardState[VK_SHIFT] & 0x80) !=0) - keyMask |= MK_SHIFT; - - if ( (keyboardState[VK_CONTROL] & 0x80) !=0) - keyMask |= MK_CONTROL; - - if ( (keyboardState[VK_LBUTTON] & 0x80) !=0) - keyMask |= MK_LBUTTON; - - if ( (keyboardState[VK_RBUTTON] & 0x80) !=0) - keyMask |= MK_RBUTTON; - - if ( (keyboardState[VK_MBUTTON] & 0x80) !=0) - keyMask |= MK_MBUTTON; - - return keyMask; -} - -/*** - * OLEDD_GetButtonState() - * - * This method will read the default value of the registry key in - * parameter and extract a DWORD value from it. The registry key value - * can be in a string key or a DWORD key. - * - * params: - * regKey - Key to read the default value from - * pdwValue - Pointer to the location where the DWORD - * value is returned. This value is not modified - * if the value is not found. - */ - -static void OLEUTL_ReadRegistryDWORDValue( - HKEY regKey, - DWORD* pdwValue) -{ - char buffer[20]; - DWORD dwKeyType; - DWORD cbData = 20; - LONG lres; - - lres = RegQueryValueExA(regKey, - "", - NULL, - &dwKeyType, - (LPBYTE)buffer, - &cbData); - - if (lres==ERROR_SUCCESS) - { - switch (dwKeyType) - { - case REG_DWORD: - *pdwValue = *(DWORD*)buffer; - break; - case REG_EXPAND_SZ: - case REG_MULTI_SZ: - case REG_SZ: - *pdwValue = (DWORD)strtoul(buffer, NULL, 10); - break; - } - } -} - -/****************************************************************************** - * OleDraw (OLE32.@) - * - * The operation of this function is documented literally in the WinAPI - * documentation to involve a QueryInterface for the IViewObject interface, - * followed by a call to IViewObject::Draw. - */ -HRESULT WINAPI OleDraw( - IUnknown *pUnk, - DWORD dwAspect, - HDC hdcDraw, - LPCRECT lprcBounds) -{ - HRESULT hres; - IViewObject *viewobject; - - hres = IUnknown_QueryInterface(pUnk, - &IID_IViewObject, - (void**)&viewobject); - - if (SUCCEEDED(hres)) - { - RECTL rectl; - - rectl.left = lprcBounds->left; - rectl.right = lprcBounds->right; - rectl.top = lprcBounds->top; - rectl.bottom = lprcBounds->bottom; - hres = IViewObject_Draw(viewobject, dwAspect, -1, 0, 0, 0, hdcDraw, &rectl, 0, 0, 0); - - IViewObject_Release(viewobject); - return hres; - } - else - { - return DV_E_NOIVIEWOBJECT; - } -} - -/*********************************************************************** - * OleTranslateAccelerator [OLE32.@] - */ -HRESULT WINAPI OleTranslateAccelerator (LPOLEINPLACEFRAME lpFrame, - LPOLEINPLACEFRAMEINFO lpFrameInfo, LPMSG lpmsg) -{ - WORD wID; - - TRACE("(%p,%p,%p)\n", lpFrame, lpFrameInfo, lpmsg); - - if (IsAccelerator(lpFrameInfo->haccel,lpFrameInfo->cAccelEntries,lpmsg,&wID)) - return IOleInPlaceFrame_TranslateAccelerator(lpFrame,lpmsg,wID); - - return S_FALSE; -} - -/****************************************************************************** - * OleCreate [OLE32.@] - * - */ -HRESULT WINAPI OleCreate( - REFCLSID rclsid, - REFIID riid, - DWORD renderopt, - LPFORMATETC pFormatEtc, - LPOLECLIENTSITE pClientSite, - LPSTORAGE pStg, - LPVOID* ppvObj) -{ - HRESULT hres, hres1; - IUnknown * pUnk = NULL; - - FIXME("\n\t%s\n\t%s semi-stub!\n", debugstr_guid(rclsid), debugstr_guid(riid)); - - if (SUCCEEDED((hres = CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER|CLSCTX_LOCAL_SERVER , riid, (LPVOID*)&pUnk)))) - { - if (pClientSite) - { - IOleObject * pOE; - IPersistStorage * pPS; - if (SUCCEEDED((hres = IUnknown_QueryInterface( pUnk, &IID_IOleObject, (LPVOID*)&pOE)))) - { - TRACE("trying to set clientsite %p\n", pClientSite); - hres1 = IOleObject_SetClientSite(pOE, pClientSite); - TRACE("-- result 0x%08lx\n", hres1); - IOleObject_Release(pOE); - } - if (SUCCEEDED((hres = IUnknown_QueryInterface( pUnk, &IID_IPersistStorage, (LPVOID*)&pPS)))) - { - TRACE("trying to set stg %p\n", pStg); - hres1 = IPersistStorage_InitNew(pPS, pStg); - TRACE("-- result 0x%08lx\n", hres1); - IPersistStorage_Release(pPS); - } - } - } - - *ppvObj = pUnk; - - TRACE("-- %p \n", pUnk); - return hres; -} - -/****************************************************************************** - * OleSetAutoConvert [OLE32.@] - */ -HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew) -{ - HKEY hkey = 0; - char buf[200], szClsidNew[200]; - HRESULT res = S_OK; - - /* FIXME: convert to Unicode */ - TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew)); - sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]); - WINE_StringFromCLSID(clsidNew, szClsidNew); - if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey)) - { - res = REGDB_E_CLASSNOTREG; - goto done; - } - if (RegSetValueA(hkey, "AutoConvertTo", REG_SZ, szClsidNew, strlen(szClsidNew)+1)) - { - res = REGDB_E_WRITEREGDB; - goto done; - } - -done: - if (hkey) RegCloseKey(hkey); - return res; -} - -/****************************************************************************** - * OleDoAutoConvert [OLE32.@] - */ -HRESULT WINAPI OleDoAutoConvert(IStorage *pStg, LPCLSID pClsidNew) -{ - FIXME("(%p,%p) : stub\n",pStg,pClsidNew); - return E_NOTIMPL; -} - -/*********************************************************************** - * OLE_FreeClipDataArray [internal] - * - * NOTES: - * frees the data associated with an array of CLIPDATAs - */ -static void OLE_FreeClipDataArray(ULONG count, CLIPDATA * pClipDataArray) -{ - ULONG i; - for (i = 0; i < count; i++) - if (pClipDataArray[i].pClipData) - CoTaskMemFree(pClipDataArray[i].pClipData); -} - -/*********************************************************************** - * PropSysAllocString [OLE32.@] - * NOTES: - * Basically a copy of SysAllocStringLen. - */ -BSTR WINAPI PropSysAllocString(LPCOLESTR str) -{ - DWORD bufferSize; - DWORD* newBuffer; - WCHAR* stringBuffer; - int len; - - if (!str) return 0; - - len = lstrlenW(str); - /* - * Find the length of the buffer passed-in in bytes. - */ - bufferSize = len * sizeof (WCHAR); - - /* - * Allocate a new buffer to hold the string. - * don't forget to keep an empty spot at the beginning of the - * buffer for the character count and an extra character at the - * end for the NULL. - */ - newBuffer = HeapAlloc(GetProcessHeap(), 0, - bufferSize + sizeof(WCHAR) + sizeof(DWORD)); - - /* - * If the memory allocation failed, return a null pointer. - */ - if (newBuffer==0) - return 0; - - /* - * Copy the length of the string in the placeholder. - */ - *newBuffer = bufferSize; - - /* - * Skip the byte count. - */ - newBuffer++; - - /* - * Copy the information in the buffer. - * Since it is valid to pass a NULL pointer here, we'll initialize the - * buffer to nul if it is the case. - */ - if (str != 0) - memcpy(newBuffer, str, bufferSize); - else - memset(newBuffer, 0, bufferSize); - - /* - * Make sure that there is a nul character at the end of the - * string. - */ - stringBuffer = (WCHAR*)newBuffer; - stringBuffer[len] = L'\0'; - - return (LPWSTR)stringBuffer; -} - -/*********************************************************************** - * PropSysFreeString [OLE32.@] - * NOTES - * Copy of SysFreeString. - */ -void WINAPI PropSysFreeString(LPOLESTR str) -{ - DWORD* bufferPointer; - - /* NULL is a valid parameter */ - if(!str) return; - - /* - * We have to be careful when we free a BSTR pointer, it points to - * the beginning of the string but it skips the byte count contained - * before the string. - */ - bufferPointer = (DWORD*)str; - - bufferPointer--; - - /* - * Free the memory from its "real" origin. - */ - HeapFree(GetProcessHeap(), 0, bufferPointer); -} - -/****************************************************************************** - * Check if a PROPVARIANT's type is valid. - */ -static inline HRESULT PROPVARIANT_ValidateType(VARTYPE vt) -{ - switch (vt) - { - case VT_EMPTY: - case VT_NULL: - case VT_I2: - case VT_I4: - case VT_R4: - case VT_R8: - case VT_CY: - case VT_DATE: - case VT_BSTR: - case VT_ERROR: - case VT_BOOL: - case VT_UI1: - case VT_UI2: - case VT_UI4: - case VT_I8: - case VT_UI8: - case VT_LPSTR: - case VT_LPWSTR: - case VT_FILETIME: - case VT_BLOB: - case VT_STREAM: - case VT_STORAGE: - case VT_STREAMED_OBJECT: - case VT_STORED_OBJECT: - case VT_BLOB_OBJECT: - case VT_CF: - case VT_CLSID: - case VT_I2|VT_VECTOR: - case VT_I4|VT_VECTOR: - case VT_R4|VT_VECTOR: - case VT_R8|VT_VECTOR: - case VT_CY|VT_VECTOR: - case VT_DATE|VT_VECTOR: - case VT_BSTR|VT_VECTOR: - case VT_ERROR|VT_VECTOR: - case VT_BOOL|VT_VECTOR: - case VT_VARIANT|VT_VECTOR: - case VT_UI1|VT_VECTOR: - case VT_UI2|VT_VECTOR: - case VT_UI4|VT_VECTOR: - case VT_I8|VT_VECTOR: - case VT_UI8|VT_VECTOR: - case VT_LPSTR|VT_VECTOR: - case VT_LPWSTR|VT_VECTOR: - case VT_FILETIME|VT_VECTOR: - case VT_CF|VT_VECTOR: - case VT_CLSID|VT_VECTOR: - return S_OK; - } - WARN("Bad type %d\n", vt); - return STG_E_INVALIDPARAMETER; -} - -/*********************************************************************** - * PropVariantClear [OLE32.@] - */ -HRESULT WINAPI PropVariantClear(PROPVARIANT * pvar) /* [in/out] */ -{ - HRESULT hr; - - TRACE("(%p)\n", pvar); - - if (!pvar) - return S_OK; - - hr = PROPVARIANT_ValidateType(pvar->vt); - if (FAILED(hr)) - return hr; - - switch(pvar->vt) - { - case VT_STREAM: - case VT_STREAMED_OBJECT: - case VT_STORAGE: - case VT_STORED_OBJECT: - if (pvar->u.pStream) - IUnknown_Release(pvar->u.pStream); - break; - case VT_CLSID: - case VT_LPSTR: - case VT_LPWSTR: - /* pick an arbitary typed pointer - we don't care about the type - * as we are just freeing it */ - CoTaskMemFree(pvar->u.puuid); - break; - case VT_BLOB: - case VT_BLOB_OBJECT: - CoTaskMemFree(pvar->u.blob.pBlobData); - break; - case VT_BSTR: - if (pvar->u.bstrVal) - PropSysFreeString(pvar->u.bstrVal); - break; - case VT_CF: - if (pvar->u.pclipdata) - { - OLE_FreeClipDataArray(1, pvar->u.pclipdata); - CoTaskMemFree(pvar->u.pclipdata); - } - break; - default: - if (pvar->vt & VT_VECTOR) - { - ULONG i; - - switch (pvar->vt & ~VT_VECTOR) - { - case VT_VARIANT: - FreePropVariantArray(pvar->u.capropvar.cElems, pvar->u.capropvar.pElems); - break; - case VT_CF: - OLE_FreeClipDataArray(pvar->u.caclipdata.cElems, pvar->u.caclipdata.pElems); - break; - case VT_BSTR: - for (i = 0; i < pvar->u.cabstr.cElems; i++) - PropSysFreeString(pvar->u.cabstr.pElems[i]); - break; - case VT_LPSTR: - for (i = 0; i < pvar->u.calpstr.cElems; i++) - CoTaskMemFree(pvar->u.calpstr.pElems[i]); - break; - case VT_LPWSTR: - for (i = 0; i < pvar->u.calpwstr.cElems; i++) - CoTaskMemFree(pvar->u.calpwstr.pElems[i]); - break; - } - if (pvar->vt & ~VT_VECTOR) - { - /* pick an arbitary VT_VECTOR structure - they all have the same - * memory layout */ - CoTaskMemFree(pvar->u.capropvar.pElems); - } - } - else - WARN("Invalid/unsupported type %d\n", pvar->vt); - } - - ZeroMemory(pvar, sizeof(*pvar)); - - return S_OK; -} - -/*********************************************************************** - * PropVariantCopy [OLE32.@] - */ -HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, /* [out] */ - const PROPVARIANT *pvarSrc) /* [in] */ -{ - ULONG len; - HRESULT hr; - - TRACE("(%p, %p)\n", pvarDest, pvarSrc); - - hr = PROPVARIANT_ValidateType(pvarSrc->vt); - if (FAILED(hr)) - return hr; - - /* this will deal with most cases */ - CopyMemory(pvarDest, pvarSrc, sizeof(*pvarDest)); - - switch(pvarSrc->vt) - { - case VT_STREAM: - case VT_STREAMED_OBJECT: - case VT_STORAGE: - case VT_STORED_OBJECT: - IUnknown_AddRef((LPUNKNOWN)pvarDest->u.pStream); - break; - case VT_CLSID: - pvarDest->u.puuid = CoTaskMemAlloc(sizeof(CLSID)); - CopyMemory(pvarDest->u.puuid, pvarSrc->u.puuid, sizeof(CLSID)); - break; - case VT_LPSTR: - len = strlen(pvarSrc->u.pszVal); - pvarDest->u.pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR)); - CopyMemory(pvarDest->u.pszVal, pvarSrc->u.pszVal, (len+1)*sizeof(CHAR)); - break; - case VT_LPWSTR: - len = lstrlenW(pvarSrc->u.pwszVal); - pvarDest->u.pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR)); - CopyMemory(pvarDest->u.pwszVal, pvarSrc->u.pwszVal, (len+1)*sizeof(WCHAR)); - break; - case VT_BLOB: - case VT_BLOB_OBJECT: - if (pvarSrc->u.blob.pBlobData) - { - len = pvarSrc->u.blob.cbSize; - pvarDest->u.blob.pBlobData = CoTaskMemAlloc(len); - CopyMemory(pvarDest->u.blob.pBlobData, pvarSrc->u.blob.pBlobData, len); - } - break; - case VT_BSTR: - pvarDest->u.bstrVal = PropSysAllocString(pvarSrc->u.bstrVal); - break; - case VT_CF: - if (pvarSrc->u.pclipdata) - { - len = pvarSrc->u.pclipdata->cbSize - sizeof(pvarSrc->u.pclipdata->ulClipFmt); - CoTaskMemAlloc(len); - CopyMemory(pvarDest->u.pclipdata->pClipData, pvarSrc->u.pclipdata->pClipData, len); - } - break; - default: - if (pvarSrc->vt & VT_VECTOR) - { - int elemSize; - ULONG i; - - switch(pvarSrc->vt & ~VT_VECTOR) - { - case VT_I1: elemSize = sizeof(pvarSrc->u.cVal); break; - case VT_UI1: elemSize = sizeof(pvarSrc->u.bVal); break; - case VT_I2: elemSize = sizeof(pvarSrc->u.iVal); break; - case VT_UI2: elemSize = sizeof(pvarSrc->u.uiVal); break; - case VT_BOOL: elemSize = sizeof(pvarSrc->u.boolVal); break; - case VT_I4: elemSize = sizeof(pvarSrc->u.lVal); break; - case VT_UI4: elemSize = sizeof(pvarSrc->u.ulVal); break; - case VT_R4: elemSize = sizeof(pvarSrc->u.fltVal); break; - case VT_R8: elemSize = sizeof(pvarSrc->u.dblVal); break; - case VT_ERROR: elemSize = sizeof(pvarSrc->u.scode); break; - case VT_I8: elemSize = sizeof(pvarSrc->u.hVal); break; - case VT_UI8: elemSize = sizeof(pvarSrc->u.uhVal); break; - case VT_CY: elemSize = sizeof(pvarSrc->u.cyVal); break; - case VT_DATE: elemSize = sizeof(pvarSrc->u.date); break; - case VT_FILETIME: elemSize = sizeof(pvarSrc->u.filetime); break; - case VT_CLSID: elemSize = sizeof(*pvarSrc->u.puuid); break; - case VT_CF: elemSize = sizeof(*pvarSrc->u.pclipdata); break; - case VT_BSTR: elemSize = sizeof(*pvarSrc->u.bstrVal); break; - case VT_LPSTR: elemSize = sizeof(*pvarSrc->u.pszVal); break; - case VT_LPWSTR: elemSize = sizeof(*pvarSrc->u.pwszVal); break; - - case VT_VARIANT: - default: - FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR); - return E_INVALIDARG; - } - len = pvarSrc->u.capropvar.cElems; - pvarDest->u.capropvar.pElems = CoTaskMemAlloc(len * elemSize); - if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT)) - { - for (i = 0; i < len; i++) - PropVariantCopy(&pvarDest->u.capropvar.pElems[i], &pvarSrc->u.capropvar.pElems[i]); - } - else if (pvarSrc->vt == (VT_VECTOR | VT_CF)) - { - FIXME("Copy clipformats\n"); - } - else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR)) - { - for (i = 0; i < len; i++) - pvarDest->u.cabstr.pElems[i] = PropSysAllocString(pvarSrc->u.cabstr.pElems[i]); - } - else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR)) - { - size_t strLen; - for (i = 0; i < len; i++) - { - strLen = lstrlenA(pvarSrc->u.calpstr.pElems[i]) + 1; - pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen); - memcpy(pvarDest->u.calpstr.pElems[i], - pvarSrc->u.calpstr.pElems[i], strLen); - } - } - else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR)) - { - size_t strLen; - for (i = 0; i < len; i++) - { - strLen = (lstrlenW(pvarSrc->u.calpwstr.pElems[i]) + 1) * - sizeof(WCHAR); - pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen); - memcpy(pvarDest->u.calpstr.pElems[i], - pvarSrc->u.calpstr.pElems[i], strLen); - } - } - else - CopyMemory(pvarDest->u.capropvar.pElems, pvarSrc->u.capropvar.pElems, len * elemSize); - } - else - WARN("Invalid/unsupported type %d\n", pvarSrc->vt); - } - - return S_OK; -} - -/*********************************************************************** - * FreePropVariantArray [OLE32.@] - */ -HRESULT WINAPI FreePropVariantArray(ULONG cVariants, /* [in] */ - PROPVARIANT *rgvars) /* [in/out] */ -{ - ULONG i; - - TRACE("(%lu, %p)\n", cVariants, rgvars); - - for(i = 0; i < cVariants; i++) - PropVariantClear(&rgvars[i]); - - return S_OK; -} - -/****************************************************************************** - * DllDebugObjectRPCHook (OLE32.@) - * turns on and off internal debugging, pointer is only used on macintosh - */ - -BOOL WINAPI DllDebugObjectRPCHook(BOOL b, void *dummy) -{ - FIXME("stub\n"); - return TRUE; -} +/* + * OLE2 library + * + * Copyright 1995 Martin von Loewis + * Copyright 1999 Francis Beaudet + * Copyright 1999 Noel Borthwick + * Copyright 1999, 2000 Marcus Meissner + * Copyright 2005 Juan Lang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <assert.h> +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "winreg.h" +#include "commctrl.h" +#include "ole2.h" +#include "ole2ver.h" +#include "wownt32.h" + +#include "wine/winbase16.h" +#include "wine/wingdi16.h" +#include "wine/winuser16.h" +#include "compobj_private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); +WINE_DECLARE_DEBUG_CHANNEL(accel); + +#define HICON_16(h32) (LOWORD(h32)) +#define HICON_32(h16) ((HICON)(ULONG_PTR)(h16)) +#define HINSTANCE_32(h16) ((HINSTANCE)(ULONG_PTR)(h16)) + +/****************************************************************************** + * These are static/global variables and internal data structures that the + * OLE module uses to maintain it's state. + */ +typedef struct tagDropTargetNode +{ + HWND hwndTarget; + IDropTarget* dropTarget; + struct tagDropTargetNode* prevDropTarget; + struct tagDropTargetNode* nextDropTarget; +} DropTargetNode; + +typedef struct tagTrackerWindowInfo +{ + IDataObject* dataObject; + IDropSource* dropSource; + DWORD dwOKEffect; + DWORD* pdwEffect; + BOOL trackingDone; + HRESULT returnValue; + + BOOL escPressed; + HWND curTargetHWND; /* window the mouse is hovering over */ + HWND curDragTargetHWND; /* might be a ancestor of curTargetHWND */ + IDropTarget* curDragTarget; +} TrackerWindowInfo; + +typedef struct tagOleMenuDescriptor /* OleMenuDescriptor */ +{ + HWND hwndFrame; /* The containers frame window */ + HWND hwndActiveObject; /* The active objects window */ + OLEMENUGROUPWIDTHS mgw; /* OLE menu group widths for the shared menu */ + HMENU hmenuCombined; /* The combined menu */ + BOOL bIsServerItem; /* True if the currently open popup belongs to the server */ +} OleMenuDescriptor; + +typedef struct tagOleMenuHookItem /* OleMenu hook item in per thread hook list */ +{ + DWORD tid; /* Thread Id */ + HANDLE hHeap; /* Heap this is allocated from */ + HHOOK GetMsg_hHook; /* message hook for WH_GETMESSAGE */ + HHOOK CallWndProc_hHook; /* message hook for WH_CALLWNDPROC */ + struct tagOleMenuHookItem *next; +} OleMenuHookItem; + +static OleMenuHookItem *hook_list; + +/* + * This is the lock count on the OLE library. It is controlled by the + * OLEInitialize/OLEUninitialize methods. + */ +static ULONG OLE_moduleLockCount = 0; + +/* + * Name of our registered window class. + */ +static const char OLEDD_DRAGTRACKERCLASS[] = "WineDragDropTracker32"; + +/* + * This is the head of the Drop target container. + */ +static DropTargetNode* targetListHead = NULL; + +/****************************************************************************** + * These are the prototypes of miscelaneous utility methods + */ +static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue); + +/****************************************************************************** + * These are the prototypes of the utility methods used to manage a shared menu + */ +static void OLEMenu_Initialize(void); +static void OLEMenu_UnInitialize(void); +BOOL OLEMenu_InstallHooks( DWORD tid ); +BOOL OLEMenu_UnInstallHooks( DWORD tid ); +OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid ); +static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos ); +BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor ); +LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam); + +/****************************************************************************** + * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c) + */ +extern void OLEClipbrd_UnInitialize(void); +extern void OLEClipbrd_Initialize(void); + +/****************************************************************************** + * These are the prototypes of the utility methods used for OLE Drag n Drop + */ +static void OLEDD_Initialize(void); +static void OLEDD_UnInitialize(void); +static void OLEDD_InsertDropTarget( + DropTargetNode* nodeToAdd); +static DropTargetNode* OLEDD_ExtractDropTarget( + HWND hwndOfTarget); +static DropTargetNode* OLEDD_FindDropTarget( + HWND hwndOfTarget); +static LRESULT WINAPI OLEDD_DragTrackerWindowProc( + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam); +static void OLEDD_TrackMouseMove( + TrackerWindowInfo* trackerInfo, + POINT mousePos, + DWORD keyState); +static void OLEDD_TrackStateChange( + TrackerWindowInfo* trackerInfo, + POINT mousePos, + DWORD keyState); +static DWORD OLEDD_GetButtonState(void); + + +/****************************************************************************** + * OleBuildVersion [OLE2.1] + * OleBuildVersion [OLE32.@] + */ +DWORD WINAPI OleBuildVersion(void) +{ + TRACE("Returning version %d, build %d.\n", rmm, rup); + return (rmm<<16)+rup; +} + +/*********************************************************************** + * OleInitialize (OLE2.2) + * OleInitialize (OLE32.@) + */ +HRESULT WINAPI OleInitialize(LPVOID reserved) +{ + HRESULT hr; + + TRACE("(%p)\n", reserved); + + /* + * The first duty of the OleInitialize is to initialize the COM libraries. + */ + hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + /* + * If the CoInitializeEx call failed, the OLE libraries can't be + * initialized. + */ + if (FAILED(hr)) + return hr; + + /* + * Then, it has to initialize the OLE specific modules. + * This includes: + * Clipboard + * Drag and Drop + * Object linking and Embedding + * In-place activation + */ + if (OLE_moduleLockCount==0) + { + /* + * Initialize the libraries. + */ + TRACE("() - Initializing the OLE libraries\n"); + + /* + * OLE Clipboard + */ + OLEClipbrd_Initialize(); + + /* + * Drag and Drop + */ + OLEDD_Initialize(); + + /* + * OLE shared menu + */ + OLEMenu_Initialize(); + } + + /* + * Then, we increase the lock count on the OLE module. + */ + OLE_moduleLockCount++; + + return hr; +} + +/****************************************************************************** + * OleUninitialize [OLE2.3] + * OleUninitialize [OLE32.@] + */ +void WINAPI OleUninitialize(void) +{ + TRACE("()\n"); + + /* + * Decrease the lock count on the OLE module. + */ + OLE_moduleLockCount--; + + /* + * If we hit the bottom of the lock stack, free the libraries. + */ + if (OLE_moduleLockCount==0) + { + /* + * Actually free the libraries. + */ + TRACE("() - Freeing the last reference count\n"); + + /* + * OLE Clipboard + */ + OLEClipbrd_UnInitialize(); + + /* + * Drag and Drop + */ + OLEDD_UnInitialize(); + + /* + * OLE shared menu + */ + OLEMenu_UnInitialize(); + } + + /* + * Then, uninitialize the COM libraries. + */ + CoUninitialize(); +} + +/****************************************************************************** + * OleInitializeWOW [OLE32.@] + */ +HRESULT WINAPI OleInitializeWOW(DWORD x) { + FIXME("(0x%08lx),stub!\n",x); + return 0; +} + +/*********************************************************************** + * RegisterDragDrop (OLE32.@) + */ +HRESULT WINAPI RegisterDragDrop( + HWND hwnd, + LPDROPTARGET pDropTarget) +{ + DropTargetNode* dropTargetInfo; + + TRACE("(%p,%p)\n", hwnd, pDropTarget); + + if (!pDropTarget) + return E_INVALIDARG; + + /* + * First, check if the window is already registered. + */ + dropTargetInfo = OLEDD_FindDropTarget(hwnd); + + if (dropTargetInfo!=NULL) + return DRAGDROP_E_ALREADYREGISTERED; + + /* + * If it's not there, we can add it. We first create a node for it. + */ + dropTargetInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(DropTargetNode)); + + if (dropTargetInfo==NULL) + return E_OUTOFMEMORY; + + dropTargetInfo->hwndTarget = hwnd; + dropTargetInfo->prevDropTarget = NULL; + dropTargetInfo->nextDropTarget = NULL; + + /* + * Don't forget that this is an interface pointer, need to nail it down since + * we keep a copy of it. + */ + dropTargetInfo->dropTarget = pDropTarget; + IDropTarget_AddRef(dropTargetInfo->dropTarget); + + OLEDD_InsertDropTarget(dropTargetInfo); + + return S_OK; +} + +/*********************************************************************** + * RevokeDragDrop (OLE32.@) + */ +HRESULT WINAPI RevokeDragDrop( + HWND hwnd) +{ + DropTargetNode* dropTargetInfo; + + TRACE("(%p)\n", hwnd); + + /* + * First, check if the window is already registered. + */ + dropTargetInfo = OLEDD_ExtractDropTarget(hwnd); + + /* + * If it ain't in there, it's an error. + */ + if (dropTargetInfo==NULL) + return DRAGDROP_E_NOTREGISTERED; + + /* + * If it's in there, clean-up it's used memory and + * references + */ + IDropTarget_Release(dropTargetInfo->dropTarget); + HeapFree(GetProcessHeap(), 0, dropTargetInfo); + + return S_OK; +} + +/*********************************************************************** + * OleRegGetUserType (OLE32.@) + * + * This implementation of OleRegGetUserType ignores the dwFormOfType + * parameter and always returns the full name of the object. This is + * not too bad since this is the case for many objects because of the + * way they are registered. + */ +HRESULT WINAPI OleRegGetUserType( + REFCLSID clsid, + DWORD dwFormOfType, + LPOLESTR* pszUserType) +{ + char keyName[60]; + DWORD dwKeyType; + DWORD cbData; + HKEY clsidKey; + LONG hres; + LPBYTE buffer; + HRESULT retVal; + /* + * Initialize the out parameter. + */ + *pszUserType = NULL; + + /* + * Build the key name we're looking for + */ + sprintf( keyName, "CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\", + clsid->Data1, clsid->Data2, clsid->Data3, + clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3], + clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] ); + + TRACE("(%s, %ld, %p)\n", keyName, dwFormOfType, pszUserType); + + /* + * Open the class id Key + */ + hres = RegOpenKeyA(HKEY_CLASSES_ROOT, + keyName, + &clsidKey); + + if (hres != ERROR_SUCCESS) + return REGDB_E_CLASSNOTREG; + + /* + * Retrieve the size of the name string. + */ + cbData = 0; + + hres = RegQueryValueExA(clsidKey, + "", + NULL, + &dwKeyType, + NULL, + &cbData); + + if (hres!=ERROR_SUCCESS) + { + RegCloseKey(clsidKey); + return REGDB_E_READREGDB; + } + + /* + * Allocate a buffer for the registry value. + */ + *pszUserType = CoTaskMemAlloc(cbData*2); + + if (*pszUserType==NULL) + { + RegCloseKey(clsidKey); + return E_OUTOFMEMORY; + } + + buffer = HeapAlloc(GetProcessHeap(), 0, cbData); + + if (buffer == NULL) + { + RegCloseKey(clsidKey); + CoTaskMemFree(*pszUserType); + *pszUserType=NULL; + return E_OUTOFMEMORY; + } + + hres = RegQueryValueExA(clsidKey, + "", + NULL, + &dwKeyType, + buffer, + &cbData); + + RegCloseKey(clsidKey); + + + if (hres!=ERROR_SUCCESS) + { + CoTaskMemFree(*pszUserType); + *pszUserType=NULL; + + retVal = REGDB_E_READREGDB; + } + else + { + MultiByteToWideChar( CP_ACP, 0, buffer, -1, *pszUserType, cbData /*FIXME*/ ); + retVal = S_OK; + } + HeapFree(GetProcessHeap(), 0, buffer); + + return retVal; +} + +/*********************************************************************** + * DoDragDrop [OLE32.@] + */ +HRESULT WINAPI DoDragDrop ( + IDataObject *pDataObject, /* [in] ptr to the data obj */ + IDropSource* pDropSource, /* [in] ptr to the source obj */ + DWORD dwOKEffect, /* [in] effects allowed by the source */ + DWORD *pdwEffect) /* [out] ptr to effects of the source */ +{ + TrackerWindowInfo trackerInfo; + HWND hwndTrackWindow; + MSG msg; + + TRACE("(DataObject %p, DropSource %p)\n", pDataObject, pDropSource); + + /* + * Setup the drag n drop tracking window. + */ + if (!IsValidInterface((LPUNKNOWN)pDropSource)) + return E_INVALIDARG; + + trackerInfo.dataObject = pDataObject; + trackerInfo.dropSource = pDropSource; + trackerInfo.dwOKEffect = dwOKEffect; + trackerInfo.pdwEffect = pdwEffect; + trackerInfo.trackingDone = FALSE; + trackerInfo.escPressed = FALSE; + trackerInfo.curDragTargetHWND = 0; + trackerInfo.curTargetHWND = 0; + trackerInfo.curDragTarget = 0; + + hwndTrackWindow = CreateWindowA(OLEDD_DRAGTRACKERCLASS, + "TrackerWindow", + WS_POPUP, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + 0, + 0, + 0, + (LPVOID)&trackerInfo); + + if (hwndTrackWindow!=0) + { + /* + * Capture the mouse input + */ + SetCapture(hwndTrackWindow); + + /* + * Pump messages. All mouse input should go the the capture window. + */ + while (!trackerInfo.trackingDone && GetMessageA(&msg, 0, 0, 0) ) + { + if ( (msg.message >= WM_KEYFIRST) && + (msg.message <= WM_KEYLAST) ) + { + /* + * When keyboard messages are sent to windows on this thread, we + * want to ignore notify the drop source that the state changed. + * in the case of the Escape key, we also notify the drop source + * we give it a special meaning. + */ + if ( (msg.message==WM_KEYDOWN) && + (msg.wParam==VK_ESCAPE) ) + { + trackerInfo.escPressed = TRUE; + } + + /* + * Notify the drop source. + */ + OLEDD_TrackStateChange(&trackerInfo, + msg.pt, + OLEDD_GetButtonState()); + } + else + { + /* + * Dispatch the messages only when it's not a keyboard message. + */ + DispatchMessageA(&msg); + } + } + + /* + * Destroy the temporary window. + */ + DestroyWindow(hwndTrackWindow); + + return trackerInfo.returnValue; + } + + return E_FAIL; +} + +/*********************************************************************** + * OleQueryLinkFromData [OLE32.@] + */ +HRESULT WINAPI OleQueryLinkFromData( + IDataObject* pSrcDataObject) +{ + FIXME("(%p),stub!\n", pSrcDataObject); + return S_OK; +} + +/*********************************************************************** + * OleRegGetMiscStatus [OLE32.@] + */ +HRESULT WINAPI OleRegGetMiscStatus( + REFCLSID clsid, + DWORD dwAspect, + DWORD* pdwStatus) +{ + char keyName[60]; + HKEY clsidKey; + HKEY miscStatusKey; + HKEY aspectKey; + LONG result; + + /* + * Initialize the out parameter. + */ + *pdwStatus = 0; + + /* + * Build the key name we're looking for + */ + sprintf( keyName, "CLSID\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\", + clsid->Data1, clsid->Data2, clsid->Data3, + clsid->Data4[0], clsid->Data4[1], clsid->Data4[2], clsid->Data4[3], + clsid->Data4[4], clsid->Data4[5], clsid->Data4[6], clsid->Data4[7] ); + + TRACE("(%s, %ld, %p)\n", keyName, dwAspect, pdwStatus); + + /* + * Open the class id Key + */ + result = RegOpenKeyA(HKEY_CLASSES_ROOT, + keyName, + &clsidKey); + + if (result != ERROR_SUCCESS) + return REGDB_E_CLASSNOTREG; + + /* + * Get the MiscStatus + */ + result = RegOpenKeyA(clsidKey, + "MiscStatus", + &miscStatusKey); + + + if (result != ERROR_SUCCESS) + { + RegCloseKey(clsidKey); + return REGDB_E_READREGDB; + } + + /* + * Read the default value + */ + OLEUTL_ReadRegistryDWORDValue(miscStatusKey, pdwStatus); + + /* + * Open the key specific to the requested aspect. + */ + sprintf(keyName, "%ld", dwAspect); + + result = RegOpenKeyA(miscStatusKey, + keyName, + &aspectKey); + + if (result == ERROR_SUCCESS) + { + OLEUTL_ReadRegistryDWORDValue(aspectKey, pdwStatus); + RegCloseKey(aspectKey); + } + + /* + * Cleanup + */ + RegCloseKey(miscStatusKey); + RegCloseKey(clsidKey); + + return S_OK; +} + +/****************************************************************************** + * OleSetContainedObject [OLE32.@] + */ +HRESULT WINAPI OleSetContainedObject( + LPUNKNOWN pUnknown, + BOOL fContained) +{ + IRunnableObject* runnable = NULL; + HRESULT hres; + + TRACE("(%p,%x), stub!\n", pUnknown, fContained); + + hres = IUnknown_QueryInterface(pUnknown, + &IID_IRunnableObject, + (void**)&runnable); + + if (SUCCEEDED(hres)) + { + hres = IRunnableObject_SetContainedObject(runnable, fContained); + + IRunnableObject_Release(runnable); + + return hres; + } + + return S_OK; +} + +/****************************************************************************** + * OleLoad [OLE32.@] + */ +HRESULT WINAPI OleLoad( + LPSTORAGE pStg, + REFIID riid, + LPOLECLIENTSITE pClientSite, + LPVOID* ppvObj) +{ + IPersistStorage* persistStorage = NULL; + IOleObject* oleObject = NULL; + STATSTG storageInfo; + HRESULT hres; + + TRACE("(%p,%p,%p,%p)\n", pStg, riid, pClientSite, ppvObj); + + /* + * TODO, Conversion ... OleDoAutoConvert + */ + + /* + * Get the class ID for the object. + */ + hres = IStorage_Stat(pStg, &storageInfo, STATFLAG_NONAME); + + /* + * Now, try and create the handler for the object + */ + hres = CoCreateInstance(&storageInfo.clsid, + NULL, + CLSCTX_INPROC_HANDLER, + &IID_IOleObject, + (void**)&oleObject); + + /* + * If that fails, as it will most times, load the default + * OLE handler. + */ + if (FAILED(hres)) + { + hres = OleCreateDefaultHandler(&storageInfo.clsid, + NULL, + &IID_IOleObject, + (void**)&oleObject); + } + + /* + * If we couldn't find a handler... this is bad. Abort the whole thing. + */ + if (FAILED(hres)) + return hres; + + /* + * Inform the new object of it's client site. + */ + hres = IOleObject_SetClientSite(oleObject, pClientSite); + + /* + * Initialize the object with it's IPersistStorage interface. + */ + hres = IOleObject_QueryInterface(oleObject, + &IID_IPersistStorage, + (void**)&persistStorage); + + if (SUCCEEDED(hres)) + { + IPersistStorage_Load(persistStorage, pStg); + + IPersistStorage_Release(persistStorage); + persistStorage = NULL; + } + + /* + * Return the requested interface to the caller. + */ + hres = IOleObject_QueryInterface(oleObject, riid, ppvObj); + + /* + * Cleanup interfaces used internally + */ + IOleObject_Release(oleObject); + + return hres; +} + +/*********************************************************************** + * OleSave [OLE32.@] + */ +HRESULT WINAPI OleSave( + LPPERSISTSTORAGE pPS, + LPSTORAGE pStg, + BOOL fSameAsLoad) +{ + HRESULT hres; + CLSID objectClass; + + TRACE("(%p,%p,%x)\n", pPS, pStg, fSameAsLoad); + + /* + * First, we transfer the class ID (if available) + */ + hres = IPersistStorage_GetClassID(pPS, &objectClass); + + if (SUCCEEDED(hres)) + { + WriteClassStg(pStg, &objectClass); + } + + /* + * Then, we ask the object to save itself to the + * storage. If it is successful, we commit the storage. + */ + hres = IPersistStorage_Save(pPS, pStg, fSameAsLoad); + + if (SUCCEEDED(hres)) + { + IStorage_Commit(pStg, + STGC_DEFAULT); + } + + return hres; +} + + +/****************************************************************************** + * OleLockRunning [OLE32.@] + */ +HRESULT WINAPI OleLockRunning(LPUNKNOWN pUnknown, BOOL fLock, BOOL fLastUnlockCloses) +{ + IRunnableObject* runnable = NULL; + HRESULT hres; + + TRACE("(%p,%x,%x)\n", pUnknown, fLock, fLastUnlockCloses); + + hres = IUnknown_QueryInterface(pUnknown, + &IID_IRunnableObject, + (void**)&runnable); + + if (SUCCEEDED(hres)) + { + hres = IRunnableObject_LockRunning(runnable, fLock, fLastUnlockCloses); + + IRunnableObject_Release(runnable); + + return hres; + } + else + return E_INVALIDARG; +} + + +/************************************************************************** + * Internal methods to manage the shared OLE menu in response to the + * OLE***MenuDescriptor API + */ + +/*** + * OLEMenu_Initialize() + * + * Initializes the OLEMENU data structures. + */ +static void OLEMenu_Initialize() +{ +} + +/*** + * OLEMenu_UnInitialize() + * + * Releases the OLEMENU data structures. + */ +static void OLEMenu_UnInitialize() +{ +} + +/************************************************************************* + * OLEMenu_InstallHooks + * Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC + * + * RETURNS: TRUE if message hooks were successfully installed + * FALSE on failure + */ +BOOL OLEMenu_InstallHooks( DWORD tid ) +{ + OleMenuHookItem *pHookItem = NULL; + + /* Create an entry for the hook table */ + if ( !(pHookItem = HeapAlloc(GetProcessHeap(), 0, + sizeof(OleMenuHookItem)) ) ) + return FALSE; + + pHookItem->tid = tid; + pHookItem->hHeap = GetProcessHeap(); + + /* Install a thread scope message hook for WH_GETMESSAGE */ + pHookItem->GetMsg_hHook = SetWindowsHookExA( WH_GETMESSAGE, OLEMenu_GetMsgProc, + 0, GetCurrentThreadId() ); + if ( !pHookItem->GetMsg_hHook ) + goto CLEANUP; + + /* Install a thread scope message hook for WH_CALLWNDPROC */ + pHookItem->CallWndProc_hHook = SetWindowsHookExA( WH_CALLWNDPROC, OLEMenu_CallWndProc, + 0, GetCurrentThreadId() ); + if ( !pHookItem->CallWndProc_hHook ) + goto CLEANUP; + + /* Insert the hook table entry */ + pHookItem->next = hook_list; + hook_list = pHookItem; + + return TRUE; + +CLEANUP: + /* Unhook any hooks */ + if ( pHookItem->GetMsg_hHook ) + UnhookWindowsHookEx( pHookItem->GetMsg_hHook ); + if ( pHookItem->CallWndProc_hHook ) + UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ); + /* Release the hook table entry */ + HeapFree(pHookItem->hHeap, 0, pHookItem ); + + return FALSE; +} + +/************************************************************************* + * OLEMenu_UnInstallHooks + * UnInstall thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC + * + * RETURNS: TRUE if message hooks were successfully installed + * FALSE on failure + */ +BOOL OLEMenu_UnInstallHooks( DWORD tid ) +{ + OleMenuHookItem *pHookItem = NULL; + OleMenuHookItem **ppHook = &hook_list; + + while (*ppHook) + { + if ((*ppHook)->tid == tid) + { + pHookItem = *ppHook; + *ppHook = pHookItem->next; + break; + } + ppHook = &(*ppHook)->next; + } + if (!pHookItem) return FALSE; + + /* Uninstall the hooks installed for this thread */ + if ( !UnhookWindowsHookEx( pHookItem->GetMsg_hHook ) ) + goto CLEANUP; + if ( !UnhookWindowsHookEx( pHookItem->CallWndProc_hHook ) ) + goto CLEANUP; + + /* Release the hook table entry */ + HeapFree(pHookItem->hHeap, 0, pHookItem ); + + return TRUE; + +CLEANUP: + /* Release the hook table entry */ + HeapFree(pHookItem->hHeap, 0, pHookItem ); + + return FALSE; +} + +/************************************************************************* + * OLEMenu_IsHookInstalled + * Tests if OLEMenu hooks have been installed for a thread + * + * RETURNS: The pointer and index of the hook table entry for the tid + * NULL and -1 for the index if no hooks were installed for this thread + */ +OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid ) +{ + OleMenuHookItem *pHookItem = NULL; + + /* Do a simple linear search for an entry whose tid matches ours. + * We really need a map but efficiency is not a concern here. */ + for (pHookItem = hook_list; pHookItem; pHookItem = pHookItem->next) + { + if ( tid == pHookItem->tid ) + return pHookItem; + } + + return NULL; +} + +/*********************************************************************** + * OLEMenu_FindMainMenuIndex + * + * Used by OLEMenu API to find the top level group a menu item belongs to. + * On success pnPos contains the index of the item in the top level menu group + * + * RETURNS: TRUE if the ID was found, FALSE on failure + */ +static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos ) +{ + UINT i, nItems; + + nItems = GetMenuItemCount( hMainMenu ); + + for (i = 0; i < nItems; i++) + { + HMENU hsubmenu; + + /* Is the current item a submenu? */ + if ( (hsubmenu = GetSubMenu(hMainMenu, i)) ) + { + /* If the handle is the same we're done */ + if ( hsubmenu == hPopupMenu ) + { + if (pnPos) + *pnPos = i; + return TRUE; + } + /* Recursively search without updating pnPos */ + else if ( OLEMenu_FindMainMenuIndex( hsubmenu, hPopupMenu, NULL ) ) + { + if (pnPos) + *pnPos = i; + return TRUE; + } + } + } + + return FALSE; +} + +/*********************************************************************** + * OLEMenu_SetIsServerMenu + * + * Checks whether a popup menu belongs to a shared menu group which is + * owned by the server, and sets the menu descriptor state accordingly. + * All menu messages from these groups should be routed to the server. + * + * RETURNS: TRUE if the popup menu is part of a server owned group + * FALSE if the popup menu is part of a container owned group + */ +BOOL OLEMenu_SetIsServerMenu( HMENU hmenu, OleMenuDescriptor *pOleMenuDescriptor ) +{ + UINT nPos = 0, nWidth, i; + + pOleMenuDescriptor->bIsServerItem = FALSE; + + /* Don't bother searching if the popup is the combined menu itself */ + if ( hmenu == pOleMenuDescriptor->hmenuCombined ) + return FALSE; + + /* Find the menu item index in the shared OLE menu that this item belongs to */ + if ( !OLEMenu_FindMainMenuIndex( pOleMenuDescriptor->hmenuCombined, hmenu, &nPos ) ) + return FALSE; + + /* The group widths array has counts for the number of elements + * in the groups File, Edit, Container, Object, Window, Help. + * The Edit, Object & Help groups belong to the server object + * and the other three belong to the container. + * Loop through the group widths and locate the group we are a member of. + */ + for ( i = 0, nWidth = 0; i < 6; i++ ) + { + nWidth += pOleMenuDescriptor->mgw.width[i]; + if ( nPos < nWidth ) + { + /* Odd elements are server menu widths */ + pOleMenuDescriptor->bIsServerItem = (i%2) ? TRUE : FALSE; + break; + } + } + + return pOleMenuDescriptor->bIsServerItem; +} + +/************************************************************************* + * OLEMenu_CallWndProc + * Thread scope WH_CALLWNDPROC hook proc filter function (callback) + * This is invoked from a message hook installed in OleSetMenuDescriptor. + */ +LRESULT CALLBACK OLEMenu_CallWndProc(INT code, WPARAM wParam, LPARAM lParam) +{ + LPCWPSTRUCT pMsg = NULL; + HOLEMENU hOleMenu = 0; + OleMenuDescriptor *pOleMenuDescriptor = NULL; + OleMenuHookItem *pHookItem = NULL; + WORD fuFlags; + + TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam ); + + /* Check if we're being asked to process the message */ + if ( HC_ACTION != code ) + goto NEXTHOOK; + + /* Retrieve the current message being dispatched from lParam */ + pMsg = (LPCWPSTRUCT)lParam; + + /* Check if the message is destined for a window we are interested in: + * If the window has an OLEMenu property we may need to dispatch + * the menu message to its active objects window instead. */ + + hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" ); + if ( !hOleMenu ) + goto NEXTHOOK; + + /* Get the menu descriptor */ + pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu ); + if ( !pOleMenuDescriptor ) /* Bad descriptor! */ + goto NEXTHOOK; + + /* Process menu messages */ + switch( pMsg->message ) + { + case WM_INITMENU: + { + /* Reset the menu descriptor state */ + pOleMenuDescriptor->bIsServerItem = FALSE; + + /* Send this message to the server as well */ + SendMessageA( pOleMenuDescriptor->hwndActiveObject, + pMsg->message, pMsg->wParam, pMsg->lParam ); + goto NEXTHOOK; + } + + case WM_INITMENUPOPUP: + { + /* Save the state for whether this is a server owned menu */ + OLEMenu_SetIsServerMenu( (HMENU)pMsg->wParam, pOleMenuDescriptor ); + break; + } + + case WM_MENUSELECT: + { + fuFlags = HIWORD(pMsg->wParam); /* Get flags */ + if ( fuFlags & MF_SYSMENU ) + goto NEXTHOOK; + + /* Save the state for whether this is a server owned popup menu */ + else if ( fuFlags & MF_POPUP ) + OLEMenu_SetIsServerMenu( (HMENU)pMsg->lParam, pOleMenuDescriptor ); + + break; + } + + case WM_DRAWITEM: + { + LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) pMsg->lParam; + if ( pMsg->wParam != 0 || lpdis->CtlType != ODT_MENU ) + goto NEXTHOOK; /* Not a menu message */ + + break; + } + + default: + goto NEXTHOOK; + } + + /* If the message was for the server dispatch it accordingly */ + if ( pOleMenuDescriptor->bIsServerItem ) + { + SendMessageA( pOleMenuDescriptor->hwndActiveObject, + pMsg->message, pMsg->wParam, pMsg->lParam ); + } + +NEXTHOOK: + if ( pOleMenuDescriptor ) + GlobalUnlock( hOleMenu ); + + /* Lookup the hook item for the current thread */ + if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) ) + { + /* This should never fail!! */ + WARN("could not retrieve hHook for current thread!\n" ); + return 0; + } + + /* Pass on the message to the next hooker */ + return CallNextHookEx( pHookItem->CallWndProc_hHook, code, wParam, lParam ); +} + +/************************************************************************* + * OLEMenu_GetMsgProc + * Thread scope WH_GETMESSAGE hook proc filter function (callback) + * This is invoked from a message hook installed in OleSetMenuDescriptor. + */ +LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam) +{ + LPMSG pMsg = NULL; + HOLEMENU hOleMenu = 0; + OleMenuDescriptor *pOleMenuDescriptor = NULL; + OleMenuHookItem *pHookItem = NULL; + WORD wCode; + + TRACE("%i, %04x, %08x\n", code, wParam, (unsigned)lParam ); + + /* Check if we're being asked to process a messages */ + if ( HC_ACTION != code ) + goto NEXTHOOK; + + /* Retrieve the current message being dispatched from lParam */ + pMsg = (LPMSG)lParam; + + /* Check if the message is destined for a window we are interested in: + * If the window has an OLEMenu property we may need to dispatch + * the menu message to its active objects window instead. */ + + hOleMenu = (HOLEMENU)GetPropA( pMsg->hwnd, "PROP_OLEMenuDescriptor" ); + if ( !hOleMenu ) + goto NEXTHOOK; + + /* Process menu messages */ + switch( pMsg->message ) + { + case WM_COMMAND: + { + wCode = HIWORD(pMsg->wParam); /* Get notification code */ + if ( wCode ) + goto NEXTHOOK; /* Not a menu message */ + break; + } + default: + goto NEXTHOOK; + } + + /* Get the menu descriptor */ + pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu ); + if ( !pOleMenuDescriptor ) /* Bad descriptor! */ + goto NEXTHOOK; + + /* If the message was for the server dispatch it accordingly */ + if ( pOleMenuDescriptor->bIsServerItem ) + { + /* Change the hWnd in the message to the active objects hWnd. + * The message loop which reads this message will automatically + * dispatch it to the embedded objects window. */ + pMsg->hwnd = pOleMenuDescriptor->hwndActiveObject; + } + +NEXTHOOK: + if ( pOleMenuDescriptor ) + GlobalUnlock( hOleMenu ); + + /* Lookup the hook item for the current thread */ + if ( !( pHookItem = OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) ) + { + /* This should never fail!! */ + WARN("could not retrieve hHook for current thread!\n" ); + return FALSE; + } + + /* Pass on the message to the next hooker */ + return CallNextHookEx( pHookItem->GetMsg_hHook, code, wParam, lParam ); +} + +/*********************************************************************** + * OleCreateMenuDescriptor [OLE32.@] + * Creates an OLE menu descriptor for OLE to use when dispatching + * menu messages and commands. + * + * PARAMS: + * hmenuCombined - Handle to the objects combined menu + * lpMenuWidths - Pointer to array of 6 LONG's indicating menus per group + * + */ +HOLEMENU WINAPI OleCreateMenuDescriptor( + HMENU hmenuCombined, + LPOLEMENUGROUPWIDTHS lpMenuWidths) +{ + HOLEMENU hOleMenu; + OleMenuDescriptor *pOleMenuDescriptor; + int i; + + if ( !hmenuCombined || !lpMenuWidths ) + return 0; + + /* Create an OLE menu descriptor */ + if ( !(hOleMenu = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, + sizeof(OleMenuDescriptor) ) ) ) + return 0; + + pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu ); + if ( !pOleMenuDescriptor ) + return 0; + + /* Initialize menu group widths and hmenu */ + for ( i = 0; i < 6; i++ ) + pOleMenuDescriptor->mgw.width[i] = lpMenuWidths->width[i]; + + pOleMenuDescriptor->hmenuCombined = hmenuCombined; + pOleMenuDescriptor->bIsServerItem = FALSE; + GlobalUnlock( hOleMenu ); + + return hOleMenu; +} + +/*********************************************************************** + * OleDestroyMenuDescriptor [OLE32.@] + * Destroy the shared menu descriptor + */ +HRESULT WINAPI OleDestroyMenuDescriptor( + HOLEMENU hmenuDescriptor) +{ + if ( hmenuDescriptor ) + GlobalFree( hmenuDescriptor ); + return S_OK; +} + +/*********************************************************************** + * OleSetMenuDescriptor [OLE32.@] + * Installs or removes OLE dispatching code for the containers frame window + * FIXME: The lpFrame and lpActiveObject parameters are currently ignored + * OLE should install context sensitive help F1 filtering for the app when + * these are non null. + * + * PARAMS: + * hOleMenu Handle to composite menu descriptor + * hwndFrame Handle to containers frame window + * hwndActiveObject Handle to objects in-place activation window + * lpFrame Pointer to IOleInPlaceFrame on containers window + * lpActiveObject Pointer to IOleInPlaceActiveObject on active in-place object + * + * RETURNS: + * S_OK - menu installed correctly + * E_FAIL, E_INVALIDARG, E_UNEXPECTED - failure + */ +HRESULT WINAPI OleSetMenuDescriptor( + HOLEMENU hOleMenu, + HWND hwndFrame, + HWND hwndActiveObject, + LPOLEINPLACEFRAME lpFrame, + LPOLEINPLACEACTIVEOBJECT lpActiveObject) +{ + OleMenuDescriptor *pOleMenuDescriptor = NULL; + + /* Check args */ + if ( !hwndFrame || (hOleMenu && !hwndActiveObject) ) + return E_INVALIDARG; + + if ( lpFrame || lpActiveObject ) + { + FIXME("(%x, %p, %p, %p, %p), Context sensitive help filtering not implemented!\n", + (unsigned int)hOleMenu, + hwndFrame, + hwndActiveObject, + lpFrame, + lpActiveObject); + } + + /* Set up a message hook to intercept the containers frame window messages. + * The message filter is responsible for dispatching menu messages from the + * shared menu which are intended for the object. + */ + + if ( hOleMenu ) /* Want to install dispatching code */ + { + /* If OLEMenu hooks are already installed for this thread, fail + * Note: This effectively means that OleSetMenuDescriptor cannot + * be called twice in succession on the same frame window + * without first calling it with a null hOleMenu to uninstall */ + if ( OLEMenu_IsHookInstalled( GetCurrentThreadId() ) ) + return E_FAIL; + + /* Get the menu descriptor */ + pOleMenuDescriptor = (OleMenuDescriptor *) GlobalLock( hOleMenu ); + if ( !pOleMenuDescriptor ) + return E_UNEXPECTED; + + /* Update the menu descriptor */ + pOleMenuDescriptor->hwndFrame = hwndFrame; + pOleMenuDescriptor->hwndActiveObject = hwndActiveObject; + + GlobalUnlock( hOleMenu ); + pOleMenuDescriptor = NULL; + + /* Add a menu descriptor windows property to the frame window */ + SetPropA( hwndFrame, "PROP_OLEMenuDescriptor", hOleMenu ); + + /* Install thread scope message hooks for WH_GETMESSAGE and WH_CALLWNDPROC */ + if ( !OLEMenu_InstallHooks( GetCurrentThreadId() ) ) + return E_FAIL; + } + else /* Want to uninstall dispatching code */ + { + /* Uninstall the hooks */ + if ( !OLEMenu_UnInstallHooks( GetCurrentThreadId() ) ) + return E_FAIL; + + /* Remove the menu descriptor property from the frame window */ + RemovePropA( hwndFrame, "PROP_OLEMenuDescriptor" ); + } + + return S_OK; +} + +/****************************************************************************** + * IsAccelerator [OLE32.@] + * Mostly copied from controls/menu.c TranslateAccelerator implementation + */ +BOOL WINAPI IsAccelerator(HACCEL hAccel, int cAccelEntries, LPMSG lpMsg, WORD* lpwCmd) +{ + LPACCEL lpAccelTbl; + int i; + + if(!lpMsg) return FALSE; + if (!hAccel) + { + WARN_(accel)("NULL accel handle\n"); + return FALSE; + } + if((lpMsg->message != WM_KEYDOWN && + lpMsg->message != WM_KEYUP && + lpMsg->message != WM_SYSKEYDOWN && + lpMsg->message != WM_SYSKEYUP && + lpMsg->message != WM_CHAR)) return FALSE; + lpAccelTbl = HeapAlloc(GetProcessHeap(), 0, cAccelEntries * sizeof(ACCEL)); + if (NULL == lpAccelTbl) + { + return FALSE; + } + if (CopyAcceleratorTableW(hAccel, lpAccelTbl, cAccelEntries) != cAccelEntries) + { + WARN_(accel)("CopyAcceleratorTableW failed\n"); + HeapFree(GetProcessHeap(), 0, lpAccelTbl); + return FALSE; + } + + TRACE_(accel)("hAccel=%p, cAccelEntries=%d," + "msg->hwnd=%p, msg->message=%04x, wParam=%08x, lParam=%08lx\n", + hAccel, cAccelEntries, + lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam); + for(i = 0; i < cAccelEntries; i++) + { + if(lpAccelTbl[i].key != lpMsg->wParam) + continue; + + if(lpMsg->message == WM_CHAR) + { + if(!(lpAccelTbl[i].fVirt & FALT) && !(lpAccelTbl[i].fVirt & FVIRTKEY)) + { + TRACE_(accel)("found accel for WM_CHAR: ('%c')\n", lpMsg->wParam & 0xff); + goto found; + } + } + else + { + if(lpAccelTbl[i].fVirt & FVIRTKEY) + { + INT mask = 0; + TRACE_(accel)("found accel for virt_key %04x (scan %04x)\n", + lpMsg->wParam, HIWORD(lpMsg->lParam) & 0xff); + if(GetKeyState(VK_SHIFT) & 0x8000) mask |= FSHIFT; + if(GetKeyState(VK_CONTROL) & 0x8000) mask |= FCONTROL; + if(GetKeyState(VK_MENU) & 0x8000) mask |= FALT; + if(mask == (lpAccelTbl[i].fVirt & (FSHIFT | FCONTROL | FALT))) goto found; + TRACE_(accel)("incorrect SHIFT/CTRL/ALT-state\n"); + } + else + { + if(!(lpMsg->lParam & 0x01000000)) /* no special_key */ + { + if((lpAccelTbl[i].fVirt & FALT) && (lpMsg->lParam & 0x20000000)) + { /* ^^ ALT pressed */ + TRACE_(accel)("found accel for Alt-%c\n", lpMsg->wParam & 0xff); + goto found; + } + } + } + } + } + + WARN_(accel)("couldn't translate accelerator key\n"); + HeapFree(GetProcessHeap(), 0, lpAccelTbl); + return FALSE; + +found: + if(lpwCmd) *lpwCmd = lpAccelTbl[i].cmd; + HeapFree(GetProcessHeap(), 0, lpAccelTbl); + return TRUE; +} + +/*********************************************************************** + * ReleaseStgMedium [OLE32.@] + */ +void WINAPI ReleaseStgMedium( + STGMEDIUM* pmedium) +{ + switch (pmedium->tymed) + { + case TYMED_HGLOBAL: + { + if ( (pmedium->pUnkForRelease==0) && + (pmedium->u.hGlobal!=0) ) + GlobalFree(pmedium->u.hGlobal); + break; + } + case TYMED_FILE: + { + if (pmedium->u.lpszFileName!=0) + { + if (pmedium->pUnkForRelease==0) + { + DeleteFileW(pmedium->u.lpszFileName); + } + + CoTaskMemFree(pmedium->u.lpszFileName); + } + break; + } + case TYMED_ISTREAM: + { + if (pmedium->u.pstm!=0) + { + IStream_Release(pmedium->u.pstm); + } + break; + } + case TYMED_ISTORAGE: + { + if (pmedium->u.pstg!=0) + { + IStorage_Release(pmedium->u.pstg); + } + break; + } + case TYMED_GDI: + { + if ( (pmedium->pUnkForRelease==0) && + (pmedium->u.hBitmap!=0) ) + DeleteObject(pmedium->u.hBitmap); + break; + } + case TYMED_MFPICT: + { + if ( (pmedium->pUnkForRelease==0) && + (pmedium->u.hMetaFilePict!=0) ) + { + LPMETAFILEPICT pMP = GlobalLock(pmedium->u.hMetaFilePict); + DeleteMetaFile(pMP->hMF); + GlobalUnlock(pmedium->u.hMetaFilePict); + GlobalFree(pmedium->u.hMetaFilePict); + } + break; + } + case TYMED_ENHMF: + { + if ( (pmedium->pUnkForRelease==0) && + (pmedium->u.hEnhMetaFile!=0) ) + { + DeleteEnhMetaFile(pmedium->u.hEnhMetaFile); + } + break; + } + case TYMED_NULL: + default: + break; + } + pmedium->tymed=TYMED_NULL; + + /* + * After cleaning up, the unknown is released + */ + if (pmedium->pUnkForRelease!=0) + { + IUnknown_Release(pmedium->pUnkForRelease); + pmedium->pUnkForRelease = 0; + } +} + +/*** + * OLEDD_Initialize() + * + * Initializes the OLE drag and drop data structures. + */ +static void OLEDD_Initialize() +{ + WNDCLASSA wndClass; + + ZeroMemory (&wndClass, sizeof(WNDCLASSA)); + wndClass.style = CS_GLOBALCLASS; + wndClass.lpfnWndProc = OLEDD_DragTrackerWindowProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = sizeof(TrackerWindowInfo*); + wndClass.hCursor = 0; + wndClass.hbrBackground = 0; + wndClass.lpszClassName = OLEDD_DRAGTRACKERCLASS; + + RegisterClassA (&wndClass); +} + +/*** + * OLEDD_UnInitialize() + * + * Releases the OLE drag and drop data structures. + */ +static void OLEDD_UnInitialize() +{ + /* + * Simply empty the list. + */ + while (targetListHead!=NULL) + { + RevokeDragDrop(targetListHead->hwndTarget); + } +} + +/*** + * OLEDD_InsertDropTarget() + * + * Insert the target node in the tree. + */ +static void OLEDD_InsertDropTarget(DropTargetNode* nodeToAdd) +{ + DropTargetNode* curNode; + DropTargetNode** parentNodeLink; + + /* + * Iterate the tree to find the insertion point. + */ + curNode = targetListHead; + parentNodeLink = &targetListHead; + + while (curNode!=NULL) + { + if (nodeToAdd->hwndTarget<curNode->hwndTarget) + { + /* + * If the node we want to add has a smaller HWND, go left + */ + parentNodeLink = &curNode->prevDropTarget; + curNode = curNode->prevDropTarget; + } + else if (nodeToAdd->hwndTarget>curNode->hwndTarget) + { + /* + * If the node we want to add has a larger HWND, go right + */ + parentNodeLink = &curNode->nextDropTarget; + curNode = curNode->nextDropTarget; + } + else + { + /* + * The item was found in the list. It shouldn't have been there + */ + assert(FALSE); + return; + } + } + + /* + * If we get here, we have found a spot for our item. The parentNodeLink + * pointer points to the pointer that we have to modify. + * The curNode should be NULL. We just have to establish the link and Voila! + */ + assert(curNode==NULL); + assert(parentNodeLink!=NULL); + assert(*parentNodeLink==NULL); + + *parentNodeLink=nodeToAdd; +} + +/*** + * OLEDD_ExtractDropTarget() + * + * Removes the target node from the tree. + */ +static DropTargetNode* OLEDD_ExtractDropTarget(HWND hwndOfTarget) +{ + DropTargetNode* curNode; + DropTargetNode** parentNodeLink; + + /* + * Iterate the tree to find the insertion point. + */ + curNode = targetListHead; + parentNodeLink = &targetListHead; + + while (curNode!=NULL) + { + if (hwndOfTarget<curNode->hwndTarget) + { + /* + * If the node we want to add has a smaller HWND, go left + */ + parentNodeLink = &curNode->prevDropTarget; + curNode = curNode->prevDropTarget; + } + else if (hwndOfTarget>curNode->hwndTarget) + { + /* + * If the node we want to add has a larger HWND, go right + */ + parentNodeLink = &curNode->nextDropTarget; + curNode = curNode->nextDropTarget; + } + else + { + /* + * The item was found in the list. Detach it from it's parent and + * re-insert it's kids in the tree. + */ + assert(parentNodeLink!=NULL); + assert(*parentNodeLink==curNode); + + /* + * We arbitrately re-attach the left sub-tree to the parent. + */ + *parentNodeLink = curNode->prevDropTarget; + + /* + * And we re-insert the right subtree + */ + if (curNode->nextDropTarget!=NULL) + { + OLEDD_InsertDropTarget(curNode->nextDropTarget); + } + + /* + * The node we found is still a valid node once we complete + * the unlinking of the kids. + */ + curNode->nextDropTarget=NULL; + curNode->prevDropTarget=NULL; + + return curNode; + } + } + + /* + * If we get here, the node is not in the tree + */ + return NULL; +} + +/*** + * OLEDD_FindDropTarget() + * + * Finds information about the drop target. + */ +static DropTargetNode* OLEDD_FindDropTarget(HWND hwndOfTarget) +{ + DropTargetNode* curNode; + + /* + * Iterate the tree to find the HWND value. + */ + curNode = targetListHead; + + while (curNode!=NULL) + { + if (hwndOfTarget<curNode->hwndTarget) + { + /* + * If the node we want to add has a smaller HWND, go left + */ + curNode = curNode->prevDropTarget; + } + else if (hwndOfTarget>curNode->hwndTarget) + { + /* + * If the node we want to add has a larger HWND, go right + */ + curNode = curNode->nextDropTarget; + } + else + { + /* + * The item was found in the list. + */ + return curNode; + } + } + + /* + * If we get here, the item is not in the list + */ + return NULL; +} + +/*** + * OLEDD_DragTrackerWindowProc() + * + * This method is the WindowProcedure of the drag n drop tracking + * window. During a drag n Drop operation, an invisible window is created + * to receive the user input and act upon it. This procedure is in charge + * of this behavior. + */ +static LRESULT WINAPI OLEDD_DragTrackerWindowProc( + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch (uMsg) + { + case WM_CREATE: + { + LPCREATESTRUCTA createStruct = (LPCREATESTRUCTA)lParam; + + SetWindowLongA(hwnd, 0, (LONG)createStruct->lpCreateParams); + + + break; + } + case WM_MOUSEMOVE: + { + TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0); + POINT mousePos; + + /* + * Get the current mouse position in screen coordinates. + */ + mousePos.x = LOWORD(lParam); + mousePos.y = HIWORD(lParam); + ClientToScreen(hwnd, &mousePos); + + /* + * Track the movement of the mouse. + */ + OLEDD_TrackMouseMove(trackerInfo, mousePos, wParam); + + break; + } + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + { + TrackerWindowInfo* trackerInfo = (TrackerWindowInfo*)GetWindowLongA(hwnd, 0); + POINT mousePos; + + /* + * Get the current mouse position in screen coordinates. + */ + mousePos.x = LOWORD(lParam); + mousePos.y = HIWORD(lParam); + ClientToScreen(hwnd, &mousePos); + + /* + * Notify everyone that the button state changed + * TODO: Check if the "escape" key was pressed. + */ + OLEDD_TrackStateChange(trackerInfo, mousePos, wParam); + + break; + } + } + + /* + * This is a window proc after all. Let's call the default. + */ + return DefWindowProcA (hwnd, uMsg, wParam, lParam); +} + +/*** + * OLEDD_TrackMouseMove() + * + * This method is invoked while a drag and drop operation is in effect. + * it will generate the appropriate callbacks in the drop source + * and drop target. It will also provide the expected feedback to + * the user. + * + * params: + * trackerInfo - Pointer to the structure identifying the + * drag & drop operation that is currently + * active. + * mousePos - Current position of the mouse in screen + * coordinates. + * keyState - Contains the state of the shift keys and the + * mouse buttons (MK_LBUTTON and the like) + */ +static void OLEDD_TrackMouseMove( + TrackerWindowInfo* trackerInfo, + POINT mousePos, + DWORD keyState) +{ + HWND hwndNewTarget = 0; + HRESULT hr = S_OK; + + /* + * Get the handle of the window under the mouse + */ + hwndNewTarget = WindowFromPoint(mousePos); + + /* + * Every time, we re-initialize the effects passed to the + * IDropTarget to the effects allowed by the source. + */ + *trackerInfo->pdwEffect = trackerInfo->dwOKEffect; + + /* + * If we are hovering over the same target as before, send the + * DragOver notification + */ + if ( (trackerInfo->curDragTarget != 0) && + (trackerInfo->curTargetHWND == hwndNewTarget) ) + { + POINTL mousePosParam; + + /* + * The documentation tells me that the coordinate should be in the target + * window's coordinate space. However, the tests I made tell me the + * coordinates should be in screen coordinates. + */ + mousePosParam.x = mousePos.x; + mousePosParam.y = mousePos.y; + + IDropTarget_DragOver(trackerInfo->curDragTarget, + keyState, + mousePosParam, + trackerInfo->pdwEffect); + } + else + { + DropTargetNode* newDropTargetNode = 0; + + /* + * If we changed window, we have to notify our old target and check for + * the new one. + */ + if (trackerInfo->curDragTarget!=0) + { + IDropTarget_DragLeave(trackerInfo->curDragTarget); + } + + /* + * Make sure we're hovering over a window. + */ + if (hwndNewTarget!=0) + { + /* + * Find-out if there is a drag target under the mouse + */ + HWND nexttar = hwndNewTarget; + trackerInfo->curTargetHWND = hwndNewTarget; + + do { + newDropTargetNode = OLEDD_FindDropTarget(nexttar); + } while (!newDropTargetNode && (nexttar = GetParent(nexttar)) != 0); + if(nexttar) hwndNewTarget = nexttar; + + trackerInfo->curDragTargetHWND = hwndNewTarget; + trackerInfo->curDragTarget = newDropTargetNode ? newDropTargetNode->dropTarget : 0; + + /* + * If there is, notify it that we just dragged-in + */ + if (trackerInfo->curDragTarget!=0) + { + POINTL mousePosParam; + + /* + * The documentation tells me that the coordinate should be in the target + * window's coordinate space. However, the tests I made tell me the + * coordinates should be in screen coordinates. + */ + mousePosParam.x = mousePos.x; + mousePosParam.y = mousePos.y; + + IDropTarget_DragEnter(trackerInfo->curDragTarget, + trackerInfo->dataObject, + keyState, + mousePosParam, + trackerInfo->pdwEffect); + } + } + else + { + /* + * The mouse is not over a window so we don't track anything. + */ + trackerInfo->curDragTargetHWND = 0; + trackerInfo->curTargetHWND = 0; + trackerInfo->curDragTarget = 0; + } + } + + /* + * Now that we have done that, we have to tell the source to give + * us feedback on the work being done by the target. If we don't + * have a target, simulate no effect. + */ + if (trackerInfo->curDragTarget==0) + { + *trackerInfo->pdwEffect = DROPEFFECT_NONE; + } + + hr = IDropSource_GiveFeedback(trackerInfo->dropSource, + *trackerInfo->pdwEffect); + + /* + * When we ask for feedback from the drop source, sometimes it will + * do all the necessary work and sometimes it will not handle it + * when that's the case, we must display the standard drag and drop + * cursors. + */ + if (hr==DRAGDROP_S_USEDEFAULTCURSORS) + { + if (*trackerInfo->pdwEffect & DROPEFFECT_MOVE) + { + SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(1))); + } + else if (*trackerInfo->pdwEffect & DROPEFFECT_COPY) + { + SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(2))); + } + else if (*trackerInfo->pdwEffect & DROPEFFECT_LINK) + { + SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(3))); + } + else + { + SetCursor(LoadCursorA(OLE32_hInstance, MAKEINTRESOURCEA(0))); + } + } +} + +/*** + * OLEDD_TrackStateChange() + * + * This method is invoked while a drag and drop operation is in effect. + * It is used to notify the drop target/drop source callbacks when + * the state of the keyboard or mouse button change. + * + * params: + * trackerInfo - Pointer to the structure identifying the + * drag & drop operation that is currently + * active. + * mousePos - Current position of the mouse in screen + * coordinates. + * keyState - Contains the state of the shift keys and the + * mouse buttons (MK_LBUTTON and the like) + */ +static void OLEDD_TrackStateChange( + TrackerWindowInfo* trackerInfo, + POINT mousePos, + DWORD keyState) +{ + /* + * Ask the drop source what to do with the operation. + */ + trackerInfo->returnValue = IDropSource_QueryContinueDrag( + trackerInfo->dropSource, + trackerInfo->escPressed, + keyState); + + /* + * All the return valued will stop the operation except the S_OK + * return value. + */ + if (trackerInfo->returnValue!=S_OK) + { + /* + * Make sure the message loop in DoDragDrop stops + */ + trackerInfo->trackingDone = TRUE; + + /* + * Release the mouse in case the drop target decides to show a popup + * or a menu or something. + */ + ReleaseCapture(); + + /* + * If we end-up over a target, drop the object in the target or + * inform the target that the operation was cancelled. + */ + if (trackerInfo->curDragTarget!=0) + { + switch (trackerInfo->returnValue) + { + /* + * If the source wants us to complete the operation, we tell + * the drop target that we just dropped the object in it. + */ + case DRAGDROP_S_DROP: + { + POINTL mousePosParam; + + /* + * The documentation tells me that the coordinate should be + * in the target window's coordinate space. However, the tests + * I made tell me the coordinates should be in screen coordinates. + */ + mousePosParam.x = mousePos.x; + mousePosParam.y = mousePos.y; + + IDropTarget_Drop(trackerInfo->curDragTarget, + trackerInfo->dataObject, + keyState, + mousePosParam, + trackerInfo->pdwEffect); + break; + } + /* + * If the source told us that we should cancel, fool the drop + * target by telling it that the mouse left it's window. + * Also set the drop effect to "NONE" in case the application + * ignores the result of DoDragDrop. + */ + case DRAGDROP_S_CANCEL: + IDropTarget_DragLeave(trackerInfo->curDragTarget); + *trackerInfo->pdwEffect = DROPEFFECT_NONE; + break; + } + } + } +} + +/*** + * OLEDD_GetButtonState() + * + * This method will use the current state of the keyboard to build + * a button state mask equivalent to the one passed in the + * WM_MOUSEMOVE wParam. + */ +static DWORD OLEDD_GetButtonState() +{ + BYTE keyboardState[256]; + DWORD keyMask = 0; + + GetKeyboardState(keyboardState); + + if ( (keyboardState[VK_SHIFT] & 0x80) !=0) + keyMask |= MK_SHIFT; + + if ( (keyboardState[VK_CONTROL] & 0x80) !=0) + keyMask |= MK_CONTROL; + + if ( (keyboardState[VK_LBUTTON] & 0x80) !=0) + keyMask |= MK_LBUTTON; + + if ( (keyboardState[VK_RBUTTON] & 0x80) !=0) + keyMask |= MK_RBUTTON; + + if ( (keyboardState[VK_MBUTTON] & 0x80) !=0) + keyMask |= MK_MBUTTON; + + return keyMask; +} + +/*** + * OLEDD_GetButtonState() + * + * This method will read the default value of the registry key in + * parameter and extract a DWORD value from it. The registry key value + * can be in a string key or a DWORD key. + * + * params: + * regKey - Key to read the default value from + * pdwValue - Pointer to the location where the DWORD + * value is returned. This value is not modified + * if the value is not found. + */ + +static void OLEUTL_ReadRegistryDWORDValue( + HKEY regKey, + DWORD* pdwValue) +{ + char buffer[20]; + DWORD dwKeyType; + DWORD cbData = 20; + LONG lres; + + lres = RegQueryValueExA(regKey, + "", + NULL, + &dwKeyType, + (LPBYTE)buffer, + &cbData); + + if (lres==ERROR_SUCCESS) + { + switch (dwKeyType) + { + case REG_DWORD: + *pdwValue = *(DWORD*)buffer; + break; + case REG_EXPAND_SZ: + case REG_MULTI_SZ: + case REG_SZ: + *pdwValue = (DWORD)strtoul(buffer, NULL, 10); + break; + } + } +} + +/****************************************************************************** + * OleDraw (OLE32.@) + * + * The operation of this function is documented literally in the WinAPI + * documentation to involve a QueryInterface for the IViewObject interface, + * followed by a call to IViewObject::Draw. + */ +HRESULT WINAPI OleDraw( + IUnknown *pUnk, + DWORD dwAspect, + HDC hdcDraw, + LPCRECT lprcBounds) +{ + HRESULT hres; + IViewObject *viewobject; + + hres = IUnknown_QueryInterface(pUnk, + &IID_IViewObject, + (void**)&viewobject); + + if (SUCCEEDED(hres)) + { + RECTL rectl; + + rectl.left = lprcBounds->left; + rectl.right = lprcBounds->right; + rectl.top = lprcBounds->top; + rectl.bottom = lprcBounds->bottom; + hres = IViewObject_Draw(viewobject, dwAspect, -1, 0, 0, 0, hdcDraw, &rectl, 0, 0, 0); + + IViewObject_Release(viewobject); + return hres; + } + else + { + return DV_E_NOIVIEWOBJECT; + } +} + +/*********************************************************************** + * OleTranslateAccelerator [OLE32.@] + */ +HRESULT WINAPI OleTranslateAccelerator (LPOLEINPLACEFRAME lpFrame, + LPOLEINPLACEFRAMEINFO lpFrameInfo, LPMSG lpmsg) +{ + WORD wID; + + TRACE("(%p,%p,%p)\n", lpFrame, lpFrameInfo, lpmsg); + + if (IsAccelerator(lpFrameInfo->haccel,lpFrameInfo->cAccelEntries,lpmsg,&wID)) + return IOleInPlaceFrame_TranslateAccelerator(lpFrame,lpmsg,wID); + + return S_FALSE; +} + +/****************************************************************************** + * OleCreate [OLE32.@] + * + */ +HRESULT WINAPI OleCreate( + REFCLSID rclsid, + REFIID riid, + DWORD renderopt, + LPFORMATETC pFormatEtc, + LPOLECLIENTSITE pClientSite, + LPSTORAGE pStg, + LPVOID* ppvObj) +{ + HRESULT hres, hres1; + IUnknown * pUnk = NULL; + + FIXME("\n\t%s\n\t%s semi-stub!\n", debugstr_guid(rclsid), debugstr_guid(riid)); + + if (SUCCEEDED((hres = CoCreateInstance(rclsid, 0, CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER|CLSCTX_LOCAL_SERVER , riid, (LPVOID*)&pUnk)))) + { + if (pClientSite) + { + IOleObject * pOE; + IPersistStorage * pPS; + if (SUCCEEDED((hres = IUnknown_QueryInterface( pUnk, &IID_IOleObject, (LPVOID*)&pOE)))) + { + TRACE("trying to set clientsite %p\n", pClientSite); + hres1 = IOleObject_SetClientSite(pOE, pClientSite); + TRACE("-- result 0x%08lx\n", hres1); + IOleObject_Release(pOE); + } + if (SUCCEEDED((hres = IUnknown_QueryInterface( pUnk, &IID_IPersistStorage, (LPVOID*)&pPS)))) + { + TRACE("trying to set stg %p\n", pStg); + hres1 = IPersistStorage_InitNew(pPS, pStg); + TRACE("-- result 0x%08lx\n", hres1); + IPersistStorage_Release(pPS); + } + } + } + + *ppvObj = pUnk; + + TRACE("-- %p \n", pUnk); + return hres; +} + +/****************************************************************************** + * OleSetAutoConvert [OLE32.@] + */ +HRESULT WINAPI OleSetAutoConvert(REFCLSID clsidOld, REFCLSID clsidNew) +{ + HKEY hkey = 0; + char buf[200], szClsidNew[200]; + HRESULT res = S_OK; + + /* FIXME: convert to Unicode */ + TRACE("(%s,%s)\n", debugstr_guid(clsidOld), debugstr_guid(clsidNew)); + sprintf(buf,"CLSID\\");WINE_StringFromCLSID(clsidOld,&buf[6]); + WINE_StringFromCLSID(clsidNew, szClsidNew); + if (RegOpenKeyA(HKEY_CLASSES_ROOT,buf,&hkey)) + { + res = REGDB_E_CLASSNOTREG; + goto done; + } + if (RegSetValueA(hkey, "AutoConvertTo", REG_SZ, szClsidNew, strlen(szClsidNew)+1)) + { + res = REGDB_E_WRITEREGDB; + goto done; + } + +done: + if (hkey) RegCloseKey(hkey); + return res; +} + +/****************************************************************************** + * OleDoAutoConvert [OLE32.@] + */ +HRESULT WINAPI OleDoAutoConvert(IStorage *pStg, LPCLSID pClsidNew) +{ + FIXME("(%p,%p) : stub\n",pStg,pClsidNew); + return E_NOTIMPL; +} + +/*********************************************************************** + * OLE_FreeClipDataArray [internal] + * + * NOTES: + * frees the data associated with an array of CLIPDATAs + */ +static void OLE_FreeClipDataArray(ULONG count, CLIPDATA * pClipDataArray) +{ + ULONG i; + for (i = 0; i < count; i++) + if (pClipDataArray[i].pClipData) + CoTaskMemFree(pClipDataArray[i].pClipData); +} + +/*********************************************************************** + * PropSysAllocString [OLE32.@] + * NOTES: + * Basically a copy of SysAllocStringLen. + */ +BSTR WINAPI PropSysAllocString(LPCOLESTR str) +{ + DWORD bufferSize; + DWORD* newBuffer; + WCHAR* stringBuffer; + int len; + + if (!str) return 0; + + len = lstrlenW(str); + /* + * Find the length of the buffer passed-in in bytes. + */ + bufferSize = len * sizeof (WCHAR); + + /* + * Allocate a new buffer to hold the string. + * don't forget to keep an empty spot at the beginning of the + * buffer for the character count and an extra character at the + * end for the NULL. + */ + newBuffer = HeapAlloc(GetProcessHeap(), 0, + bufferSize + sizeof(WCHAR) + sizeof(DWORD)); + + /* + * If the memory allocation failed, return a null pointer. + */ + if (newBuffer==0) + return 0; + + /* + * Copy the length of the string in the placeholder. + */ + *newBuffer = bufferSize; + + /* + * Skip the byte count. + */ + newBuffer++; + + /* + * Copy the information in the buffer. + * Since it is valid to pass a NULL pointer here, we'll initialize the + * buffer to nul if it is the case. + */ + if (str != 0) + memcpy(newBuffer, str, bufferSize); + else + memset(newBuffer, 0, bufferSize); + + /* + * Make sure that there is a nul character at the end of the + * string. + */ + stringBuffer = (WCHAR*)newBuffer; + stringBuffer[len] = L'\0'; + + return (LPWSTR)stringBuffer; +} + +/*********************************************************************** + * PropSysFreeString [OLE32.@] + * NOTES + * Copy of SysFreeString. + */ +void WINAPI PropSysFreeString(LPOLESTR str) +{ + DWORD* bufferPointer; + + /* NULL is a valid parameter */ + if(!str) return; + + /* + * We have to be careful when we free a BSTR pointer, it points to + * the beginning of the string but it skips the byte count contained + * before the string. + */ + bufferPointer = (DWORD*)str; + + bufferPointer--; + + /* + * Free the memory from its "real" origin. + */ + HeapFree(GetProcessHeap(), 0, bufferPointer); +} + +/****************************************************************************** + * Check if a PROPVARIANT's type is valid. + */ +static inline HRESULT PROPVARIANT_ValidateType(VARTYPE vt) +{ + switch (vt) + { + case VT_EMPTY: + case VT_NULL: + case VT_I2: + case VT_I4: + case VT_R4: + case VT_R8: + case VT_CY: + case VT_DATE: + case VT_BSTR: + case VT_ERROR: + case VT_BOOL: + case VT_UI1: + case VT_UI2: + case VT_UI4: + case VT_I8: + case VT_UI8: + case VT_LPSTR: + case VT_LPWSTR: + case VT_FILETIME: + case VT_BLOB: + case VT_STREAM: + case VT_STORAGE: + case VT_STREAMED_OBJECT: + case VT_STORED_OBJECT: + case VT_BLOB_OBJECT: + case VT_CF: + case VT_CLSID: + case VT_I2|VT_VECTOR: + case VT_I4|VT_VECTOR: + case VT_R4|VT_VECTOR: + case VT_R8|VT_VECTOR: + case VT_CY|VT_VECTOR: + case VT_DATE|VT_VECTOR: + case VT_BSTR|VT_VECTOR: + case VT_ERROR|VT_VECTOR: + case VT_BOOL|VT_VECTOR: + case VT_VARIANT|VT_VECTOR: + case VT_UI1|VT_VECTOR: + case VT_UI2|VT_VECTOR: + case VT_UI4|VT_VECTOR: + case VT_I8|VT_VECTOR: + case VT_UI8|VT_VECTOR: + case VT_LPSTR|VT_VECTOR: + case VT_LPWSTR|VT_VECTOR: + case VT_FILETIME|VT_VECTOR: + case VT_CF|VT_VECTOR: + case VT_CLSID|VT_VECTOR: + return S_OK; + } + WARN("Bad type %d\n", vt); + return STG_E_INVALIDPARAMETER; +} + +/*********************************************************************** + * PropVariantClear [OLE32.@] + */ +HRESULT WINAPI PropVariantClear(PROPVARIANT * pvar) /* [in/out] */ +{ + HRESULT hr; + + TRACE("(%p)\n", pvar); + + if (!pvar) + return S_OK; + + hr = PROPVARIANT_ValidateType(pvar->vt); + if (FAILED(hr)) + return hr; + + switch(pvar->vt) + { + case VT_STREAM: + case VT_STREAMED_OBJECT: + case VT_STORAGE: + case VT_STORED_OBJECT: + if (pvar->u.pStream) + IUnknown_Release(pvar->u.pStream); + break; + case VT_CLSID: + case VT_LPSTR: + case VT_LPWSTR: + /* pick an arbitary typed pointer - we don't care about the type + * as we are just freeing it */ + CoTaskMemFree(pvar->u.puuid); + break; + case VT_BLOB: + case VT_BLOB_OBJECT: + CoTaskMemFree(pvar->u.blob.pBlobData); + break; + case VT_BSTR: + if (pvar->u.bstrVal) + PropSysFreeString(pvar->u.bstrVal); + break; + case VT_CF: + if (pvar->u.pclipdata) + { + OLE_FreeClipDataArray(1, pvar->u.pclipdata); + CoTaskMemFree(pvar->u.pclipdata); + } + break; + default: + if (pvar->vt & VT_VECTOR) + { + ULONG i; + + switch (pvar->vt & ~VT_VECTOR) + { + case VT_VARIANT: + FreePropVariantArray(pvar->u.capropvar.cElems, pvar->u.capropvar.pElems); + break; + case VT_CF: + OLE_FreeClipDataArray(pvar->u.caclipdata.cElems, pvar->u.caclipdata.pElems); + break; + case VT_BSTR: + for (i = 0; i < pvar->u.cabstr.cElems; i++) + PropSysFreeString(pvar->u.cabstr.pElems[i]); + break; + case VT_LPSTR: + for (i = 0; i < pvar->u.calpstr.cElems; i++) + CoTaskMemFree(pvar->u.calpstr.pElems[i]); + break; + case VT_LPWSTR: + for (i = 0; i < pvar->u.calpwstr.cElems; i++) + CoTaskMemFree(pvar->u.calpwstr.pElems[i]); + break; + } + if (pvar->vt & ~VT_VECTOR) + { + /* pick an arbitary VT_VECTOR structure - they all have the same + * memory layout */ + CoTaskMemFree(pvar->u.capropvar.pElems); + } + } + else + WARN("Invalid/unsupported type %d\n", pvar->vt); + } + + ZeroMemory(pvar, sizeof(*pvar)); + + return S_OK; +} + +/*********************************************************************** + * PropVariantCopy [OLE32.@] + */ +HRESULT WINAPI PropVariantCopy(PROPVARIANT *pvarDest, /* [out] */ + const PROPVARIANT *pvarSrc) /* [in] */ +{ + ULONG len; + HRESULT hr; + + TRACE("(%p, %p)\n", pvarDest, pvarSrc); + + hr = PROPVARIANT_ValidateType(pvarSrc->vt); + if (FAILED(hr)) + return hr; + + /* this will deal with most cases */ + CopyMemory(pvarDest, pvarSrc, sizeof(*pvarDest)); + + switch(pvarSrc->vt) + { + case VT_STREAM: + case VT_STREAMED_OBJECT: + case VT_STORAGE: + case VT_STORED_OBJECT: + IUnknown_AddRef((LPUNKNOWN)pvarDest->u.pStream); + break; + case VT_CLSID: + pvarDest->u.puuid = CoTaskMemAlloc(sizeof(CLSID)); + CopyMemory(pvarDest->u.puuid, pvarSrc->u.puuid, sizeof(CLSID)); + break; + case VT_LPSTR: + len = strlen(pvarSrc->u.pszVal); + pvarDest->u.pszVal = CoTaskMemAlloc((len+1)*sizeof(CHAR)); + CopyMemory(pvarDest->u.pszVal, pvarSrc->u.pszVal, (len+1)*sizeof(CHAR)); + break; + case VT_LPWSTR: + len = lstrlenW(pvarSrc->u.pwszVal); + pvarDest->u.pwszVal = CoTaskMemAlloc((len+1)*sizeof(WCHAR)); + CopyMemory(pvarDest->u.pwszVal, pvarSrc->u.pwszVal, (len+1)*sizeof(WCHAR)); + break; + case VT_BLOB: + case VT_BLOB_OBJECT: + if (pvarSrc->u.blob.pBlobData) + { + len = pvarSrc->u.blob.cbSize; + pvarDest->u.blob.pBlobData = CoTaskMemAlloc(len); + CopyMemory(pvarDest->u.blob.pBlobData, pvarSrc->u.blob.pBlobData, len); + } + break; + case VT_BSTR: + pvarDest->u.bstrVal = PropSysAllocString(pvarSrc->u.bstrVal); + break; + case VT_CF: + if (pvarSrc->u.pclipdata) + { + len = pvarSrc->u.pclipdata->cbSize - sizeof(pvarSrc->u.pclipdata->ulClipFmt); + CoTaskMemAlloc(len); + CopyMemory(pvarDest->u.pclipdata->pClipData, pvarSrc->u.pclipdata->pClipData, len); + } + break; + default: + if (pvarSrc->vt & VT_VECTOR) + { + int elemSize; + ULONG i; + + switch(pvarSrc->vt & ~VT_VECTOR) + { + case VT_I1: elemSize = sizeof(pvarSrc->u.cVal); break; + case VT_UI1: elemSize = sizeof(pvarSrc->u.bVal); break; + case VT_I2: elemSize = sizeof(pvarSrc->u.iVal); break; + case VT_UI2: elemSize = sizeof(pvarSrc->u.uiVal); break; + case VT_BOOL: elemSize = sizeof(pvarSrc->u.boolVal); break; + case VT_I4: elemSize = sizeof(pvarSrc->u.lVal); break; + case VT_UI4: elemSize = sizeof(pvarSrc->u.ulVal); break; + case VT_R4: elemSize = sizeof(pvarSrc->u.fltVal); break; + case VT_R8: elemSize = sizeof(pvarSrc->u.dblVal); break; + case VT_ERROR: elemSize = sizeof(pvarSrc->u.scode); break; + case VT_I8: elemSize = sizeof(pvarSrc->u.hVal); break; + case VT_UI8: elemSize = sizeof(pvarSrc->u.uhVal); break; + case VT_CY: elemSize = sizeof(pvarSrc->u.cyVal); break; + case VT_DATE: elemSize = sizeof(pvarSrc->u.date); break; + case VT_FILETIME: elemSize = sizeof(pvarSrc->u.filetime); break; + case VT_CLSID: elemSize = sizeof(*pvarSrc->u.puuid); break; + case VT_CF: elemSize = sizeof(*pvarSrc->u.pclipdata); break; + case VT_BSTR: elemSize = sizeof(*pvarSrc->u.bstrVal); break; + case VT_LPSTR: elemSize = sizeof(*pvarSrc->u.pszVal); break; + case VT_LPWSTR: elemSize = sizeof(*pvarSrc->u.pwszVal); break; + + case VT_VARIANT: + default: + FIXME("Invalid element type: %ul\n", pvarSrc->vt & ~VT_VECTOR); + return E_INVALIDARG; + } + len = pvarSrc->u.capropvar.cElems; + pvarDest->u.capropvar.pElems = CoTaskMemAlloc(len * elemSize); + if (pvarSrc->vt == (VT_VECTOR | VT_VARIANT)) + { + for (i = 0; i < len; i++) + PropVariantCopy(&pvarDest->u.capropvar.pElems[i], &pvarSrc->u.capropvar.pElems[i]); + } + else if (pvarSrc->vt == (VT_VECTOR | VT_CF)) + { + FIXME("Copy clipformats\n"); + } + else if (pvarSrc->vt == (VT_VECTOR | VT_BSTR)) + { + for (i = 0; i < len; i++) + pvarDest->u.cabstr.pElems[i] = PropSysAllocString(pvarSrc->u.cabstr.pElems[i]); + } + else if (pvarSrc->vt == (VT_VECTOR | VT_LPSTR)) + { + size_t strLen; + for (i = 0; i < len; i++) + { + strLen = lstrlenA(pvarSrc->u.calpstr.pElems[i]) + 1; + pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen); + memcpy(pvarDest->u.calpstr.pElems[i], + pvarSrc->u.calpstr.pElems[i], strLen); + } + } + else if (pvarSrc->vt == (VT_VECTOR | VT_LPWSTR)) + { + size_t strLen; + for (i = 0; i < len; i++) + { + strLen = (lstrlenW(pvarSrc->u.calpwstr.pElems[i]) + 1) * + sizeof(WCHAR); + pvarDest->u.calpstr.pElems[i] = CoTaskMemAlloc(strLen); + memcpy(pvarDest->u.calpstr.pElems[i], + pvarSrc->u.calpstr.pElems[i], strLen); + } + } + else + CopyMemory(pvarDest->u.capropvar.pElems, pvarSrc->u.capropvar.pElems, len * elemSize); + } + else + WARN("Invalid/unsupported type %d\n", pvarSrc->vt); + } + + return S_OK; +} + +/*********************************************************************** + * FreePropVariantArray [OLE32.@] + */ +HRESULT WINAPI FreePropVariantArray(ULONG cVariants, /* [in] */ + PROPVARIANT *rgvars) /* [in/out] */ +{ + ULONG i; + + TRACE("(%lu, %p)\n", cVariants, rgvars); + + for(i = 0; i < cVariants; i++) + PropVariantClear(&rgvars[i]); + + return S_OK; +} + +/****************************************************************************** + * DllDebugObjectRPCHook (OLE32.@) + * turns on and off internal debugging, pointer is only used on macintosh + */ + +BOOL WINAPI DllDebugObjectRPCHook(BOOL b, void *dummy) +{ + FIXME("stub\n"); + return TRUE; +} diff --git a/reactos/lib/ole32/ole2_16.c b/reactos/lib/ole32/ole2_16.c index 0294708539c..a61fb6037a6 100644 --- a/reactos/lib/ole32/ole2_16.c +++ b/reactos/lib/ole32/ole2_16.c @@ -1,154 +1,154 @@ - -/* - * OLE2 library - 16 bit only interfaces - * - * Copyright 1995 Martin von Loewis - * Copyright 1999 Francis Beaudet - * Copyright 1999 Noel Borthwick - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <assert.h> -#include <stdlib.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> - -#define NONAMELESSUNION -#define NONAMELESSSTRUCT -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "commctrl.h" -#include "ole2.h" -#include "ole2ver.h" -#include "winerror.h" -#include "wownt32.h" - -#include "wine/winbase16.h" -#include "wine/wingdi16.h" -#include "wine/winuser16.h" -#include "ifs.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); -WINE_DECLARE_DEBUG_CHANNEL(accel); - -#define HICON_16(h32) (LOWORD(h32)) -#define HICON_32(h16) ((HICON)(ULONG_PTR)(h16)) -#define HINSTANCE_32(h16) ((HINSTANCE)(ULONG_PTR)(h16)) - -/*********************************************************************** - * RegisterDragDrop (OLE2.35) - */ -HRESULT WINAPI RegisterDragDrop16( - HWND16 hwnd, - LPDROPTARGET pDropTarget -) { - FIXME("(0x%04x,%p),stub!\n",hwnd,pDropTarget); - return S_OK; -} - -/*********************************************************************** - * RevokeDragDrop (OLE2.36) - */ -HRESULT WINAPI RevokeDragDrop16( - HWND16 hwnd -) { - FIXME("(0x%04x),stub!\n",hwnd); - return S_OK; -} - -/****************************************************************************** - * OleMetaFilePictFromIconAndLabel (OLE2.56) - * - * Returns a global memory handle to a metafile which contains the icon and - * label given. - * I guess the result of that should look somehow like desktop icons. - * If no hIcon is given, we load the icon via lpszSourceFile and iIconIndex. - * This code might be wrong at some places. - */ -HGLOBAL16 WINAPI OleMetaFilePictFromIconAndLabel16( - HICON16 hIcon, - LPCOLESTR16 lpszLabel, - LPCOLESTR16 lpszSourceFile, - UINT16 iIconIndex -) { - METAFILEPICT16 *mf16; - HGLOBAL16 hmf16; - HMETAFILE hmf; - INT mfSize; - HDC hdc; - - if (!hIcon) { - if (lpszSourceFile) { - HINSTANCE16 hInstance = LoadLibrary16(lpszSourceFile); - - /* load the icon at index from lpszSourceFile */ - hIcon = HICON_16(LoadIconA(HINSTANCE_32(hInstance), (LPCSTR)(DWORD)iIconIndex)); - FreeLibrary16(hInstance); - } else - return 0; - } - - FIXME("(%04x, '%s', '%s', %d): incorrect metrics, please try to correct them !\n", - hIcon, lpszLabel, lpszSourceFile, iIconIndex); - - hdc = CreateMetaFileW(NULL); - DrawIcon(hdc, 0, 0, HICON_32(hIcon)); /* FIXME */ - TextOutA(hdc, 0, 0, lpszLabel, 1); /* FIXME */ - hmf = CloseMetaFile(hdc); - - hmf16 = GlobalAlloc16(0, sizeof(METAFILEPICT16)); - mf16 = (METAFILEPICT16 *)GlobalLock16(hmf16); - mf16->mm = MM_ANISOTROPIC; - mf16->xExt = 20; /* FIXME: bogus */ - mf16->yExt = 20; /* dito */ - mfSize = GetMetaFileBitsEx(hmf, 0, 0); - mf16->hMF = GlobalAlloc16(GMEM_MOVEABLE, mfSize); - if(mf16->hMF) - { - GetMetaFileBitsEx(hmf, mfSize, GlobalLock16(mf16->hMF)); - GlobalUnlock16(mf16->hMF); - } - return hmf16; -} - - -/****************************************************************************** - * CreateItemMoniker (OLE2.27) - */ -HRESULT WINAPI CreateItemMoniker16(LPCOLESTR16 lpszDelim,LPCOLESTR16 lpszItem,LPMONIKER* ppmk) -{ - FIXME("(%s,%p),stub!\n",lpszDelim,ppmk); - *ppmk = NULL; - return E_NOTIMPL; -} - - -/****************************************************************************** - * CreateFileMoniker (OLE2.28) - */ -HRESULT WINAPI CreateFileMoniker16(LPCOLESTR16 lpszPathName,LPMONIKER* ppmk) -{ - FIXME("(%s,%p),stub!\n",lpszPathName,ppmk); - return E_NOTIMPL; -} + +/* + * OLE2 library - 16 bit only interfaces + * + * Copyright 1995 Martin von Loewis + * Copyright 1999 Francis Beaudet + * Copyright 1999 Noel Borthwick + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <assert.h> +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "commctrl.h" +#include "ole2.h" +#include "ole2ver.h" +#include "winerror.h" +#include "wownt32.h" + +#include "wine/winbase16.h" +#include "wine/wingdi16.h" +#include "wine/winuser16.h" +#include "ifs.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); +WINE_DECLARE_DEBUG_CHANNEL(accel); + +#define HICON_16(h32) (LOWORD(h32)) +#define HICON_32(h16) ((HICON)(ULONG_PTR)(h16)) +#define HINSTANCE_32(h16) ((HINSTANCE)(ULONG_PTR)(h16)) + +/*********************************************************************** + * RegisterDragDrop (OLE2.35) + */ +HRESULT WINAPI RegisterDragDrop16( + HWND16 hwnd, + LPDROPTARGET pDropTarget +) { + FIXME("(0x%04x,%p),stub!\n",hwnd,pDropTarget); + return S_OK; +} + +/*********************************************************************** + * RevokeDragDrop (OLE2.36) + */ +HRESULT WINAPI RevokeDragDrop16( + HWND16 hwnd +) { + FIXME("(0x%04x),stub!\n",hwnd); + return S_OK; +} + +/****************************************************************************** + * OleMetaFilePictFromIconAndLabel (OLE2.56) + * + * Returns a global memory handle to a metafile which contains the icon and + * label given. + * I guess the result of that should look somehow like desktop icons. + * If no hIcon is given, we load the icon via lpszSourceFile and iIconIndex. + * This code might be wrong at some places. + */ +HGLOBAL16 WINAPI OleMetaFilePictFromIconAndLabel16( + HICON16 hIcon, + LPCOLESTR16 lpszLabel, + LPCOLESTR16 lpszSourceFile, + UINT16 iIconIndex +) { + METAFILEPICT16 *mf16; + HGLOBAL16 hmf16; + HMETAFILE hmf; + INT mfSize; + HDC hdc; + + if (!hIcon) { + if (lpszSourceFile) { + HINSTANCE16 hInstance = LoadLibrary16(lpszSourceFile); + + /* load the icon at index from lpszSourceFile */ + hIcon = HICON_16(LoadIconA(HINSTANCE_32(hInstance), (LPCSTR)(DWORD)iIconIndex)); + FreeLibrary16(hInstance); + } else + return 0; + } + + FIXME("(%04x, '%s', '%s', %d): incorrect metrics, please try to correct them !\n", + hIcon, lpszLabel, lpszSourceFile, iIconIndex); + + hdc = CreateMetaFileW(NULL); + DrawIcon(hdc, 0, 0, HICON_32(hIcon)); /* FIXME */ + TextOutA(hdc, 0, 0, lpszLabel, 1); /* FIXME */ + hmf = CloseMetaFile(hdc); + + hmf16 = GlobalAlloc16(0, sizeof(METAFILEPICT16)); + mf16 = (METAFILEPICT16 *)GlobalLock16(hmf16); + mf16->mm = MM_ANISOTROPIC; + mf16->xExt = 20; /* FIXME: bogus */ + mf16->yExt = 20; /* dito */ + mfSize = GetMetaFileBitsEx(hmf, 0, 0); + mf16->hMF = GlobalAlloc16(GMEM_MOVEABLE, mfSize); + if(mf16->hMF) + { + GetMetaFileBitsEx(hmf, mfSize, GlobalLock16(mf16->hMF)); + GlobalUnlock16(mf16->hMF); + } + return hmf16; +} + + +/****************************************************************************** + * CreateItemMoniker (OLE2.27) + */ +HRESULT WINAPI CreateItemMoniker16(LPCOLESTR16 lpszDelim,LPCOLESTR16 lpszItem,LPMONIKER* ppmk) +{ + FIXME("(%s,%p),stub!\n",lpszDelim,ppmk); + *ppmk = NULL; + return E_NOTIMPL; +} + + +/****************************************************************************** + * CreateFileMoniker (OLE2.28) + */ +HRESULT WINAPI CreateFileMoniker16(LPCOLESTR16 lpszPathName,LPMONIKER* ppmk) +{ + FIXME("(%s,%p),stub!\n",lpszPathName,ppmk); + return E_NOTIMPL; +} diff --git a/reactos/lib/ole32/ole2impl.c b/reactos/lib/ole32/ole2impl.c index af46a350e16..b939623e470 100644 --- a/reactos/lib/ole32/ole2impl.c +++ b/reactos/lib/ole32/ole2impl.c @@ -1,303 +1,303 @@ -/* - * Ole 2 Create functions implementation - * - * Copyright (C) 1999-2000 Abey George - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> -#include <string.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "wine/debug.h" -#include "ole2.h" -#include "olestd.h" -#include "winreg.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -#define MAX_CLIPFORMAT_NAME 80 - -/****************************************************************************** - * OleQueryCreateFromData [OLE32.@] - * - * Author : Abey George - * Checks whether an object can become an embedded object. - * the clipboard or OLE drag and drop. - * Returns : S_OK - Format that supports Embedded object creation are present. - * OLE_E_STATIC - Format that supports static object creation are present. - * S_FALSE - No acceptable format is available. - */ - -HRESULT WINAPI OleQueryCreateFromData(LPDATAOBJECT pSrcDataObject) -{ - IEnumFORMATETC *pfmt; - FORMATETC fmt; - CHAR szFmtName[MAX_CLIPFORMAT_NAME]; - BOOL bFoundStatic = FALSE; - - HRESULT hr = IDataObject_EnumFormatEtc(pSrcDataObject, DATADIR_GET, &pfmt); - - if (hr == S_OK) - hr = IEnumFORMATETC_Next(pfmt, 1, &fmt, NULL); - - while (hr == S_OK) - { - GetClipboardFormatNameA(fmt.cfFormat, szFmtName, MAX_CLIPFORMAT_NAME-1); - - /* first, Check for Embedded Object, Embed Source or Filename */ - - if (!strcmp(szFmtName, CF_EMBEDDEDOBJECT) || !strcmp(szFmtName, CF_EMBEDSOURCE) || !strcmp(szFmtName, CF_FILENAME)) - return S_OK; - - /* Check for Metafile, Bitmap or DIB */ - - if (fmt.cfFormat == CF_METAFILEPICT || fmt.cfFormat == CF_BITMAP || fmt.cfFormat == CF_DIB) - bFoundStatic = TRUE; - - hr = IEnumFORMATETC_Next(pfmt, 1, &fmt, NULL); - } - - /* Found a static format, but no embed format */ - - if (bFoundStatic) - return OLE_S_STATIC; - - return S_FALSE; -} - -/****************************************************************************** - * OleCreateFromData [OLE32.@] - * - * Author : Abey George - * Creates an embedded object from data transfer object retrieved from - * the clipboard or OLE drag and drop. - * Returns : S_OK - Embedded object was created successfully. - * OLE_E_STATIC - OLE can create only a static object - * DV_E_FORMATETC - No acceptable format is available (only error return code) - * TODO : CF_FILENAME, CF_EMBEDEDOBJECT formats. Parameter renderopt is currently ignored. - */ - -HRESULT WINAPI OleCreateFromData(LPDATAOBJECT pSrcDataObject, REFIID riid, - DWORD renderopt, LPFORMATETC pFormatEtc, - LPOLECLIENTSITE pClientSite, LPSTORAGE pStg, - LPVOID* ppvObj) -{ - IEnumFORMATETC *pfmt; - FORMATETC fmt; - CHAR szFmtName[MAX_CLIPFORMAT_NAME]; - STGMEDIUM std; - HRESULT hr; - HRESULT hr1; - - hr = IDataObject_EnumFormatEtc(pSrcDataObject, DATADIR_GET, &pfmt); - - if (hr == S_OK) - { - memset(&std, 0, sizeof(STGMEDIUM)); - - hr = IEnumFORMATETC_Next(pfmt, 1, &fmt, NULL); - while (hr == S_OK) - { - GetClipboardFormatNameA(fmt.cfFormat, szFmtName, MAX_CLIPFORMAT_NAME-1); - - /* first, Check for Embedded Object, Embed Source or Filename */ - /* TODO: Currently checks only for Embed Source. */ - - if (!strcmp(szFmtName, CF_EMBEDSOURCE)) - { - std.tymed = TYMED_HGLOBAL; - - if ((hr1 = IDataObject_GetData(pSrcDataObject, &fmt, &std)) == S_OK) - { - ILockBytes *ptrILockBytes = 0; - IStorage *pStorage = 0; - IOleObject *pOleObject = 0; - IPersistStorage *pPersistStorage = 0; - CLSID clsID; - - /* Create ILock bytes */ - - hr1 = CreateILockBytesOnHGlobal(std.u.hGlobal, FALSE, &ptrILockBytes); - - /* Open storage on the ILock bytes */ - - if (hr1 == S_OK) - hr1 = StgOpenStorageOnILockBytes(ptrILockBytes, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &pStorage); - - /* Get Class ID from the opened storage */ - - if (hr1 == S_OK) - hr1 = ReadClassStg(pStorage, &clsID); - - /* Create default handler for Persist storage */ - - if (hr1 == S_OK) - hr1 = OleCreateDefaultHandler(&clsID, NULL, &IID_IPersistStorage, (LPVOID*)&pPersistStorage); - - /* Load the storage to Persist storage */ - - if (hr1 == S_OK) - hr1 = IPersistStorage_Load(pPersistStorage, pStorage); - - /* Query for IOleObject */ - - if (hr1 == S_OK) - hr1 = IPersistStorage_QueryInterface(pPersistStorage, &IID_IOleObject, (LPVOID*)&pOleObject); - - /* Set client site with the IOleObject */ - - if (hr1 == S_OK) - hr1 = IOleObject_SetClientSite(pOleObject, pClientSite); - - IPersistStorage_Release(pPersistStorage); - /* Query for the requested interface */ - - if (hr1 == S_OK) - hr1 = IPersistStorage_QueryInterface(pPersistStorage, riid, ppvObj); - - IPersistStorage_Release(pPersistStorage); - - IStorage_Release(pStorage); - - if (hr1 == S_OK) - return S_OK; - } - - /* Return error */ - - return DV_E_FORMATETC; - } - - hr = IEnumFORMATETC_Next(pfmt, 1, &fmt, NULL); - } - } - - return DV_E_FORMATETC; -} - - -/****************************************************************************** - * OleDuplicateData [OLE32.@] - * - * Duplicates clipboard data. - * - * PARAMS - * hSrc [I] Handle of the source clipboard data. - * cfFormat [I] The clipboard format of hSrc. - * uiFlags [I] Flags to pass to GlobalAlloc. - * - * RETURNS - * Success: handle to the duplicated data. - * Failure: NULL. - */ -HANDLE WINAPI OleDuplicateData(HANDLE hSrc, CLIPFORMAT cfFormat, - UINT uiFlags) -{ - HANDLE hDst = NULL; - - TRACE("(%p,%x,%x)\n", hSrc, cfFormat, uiFlags); - - if (!uiFlags) uiFlags = GMEM_MOVEABLE; - - switch (cfFormat) - { - case CF_ENHMETAFILE: - hDst = CopyEnhMetaFileW(hSrc, NULL); - break; - case CF_METAFILEPICT: - hDst = CopyMetaFileW(hSrc, NULL); - break; - case CF_PALETTE: - { - LOGPALETTE * logpalette; - UINT nEntries = GetPaletteEntries(hSrc, 0, 0, NULL); - if (!nEntries) return NULL; - logpalette = HeapAlloc(GetProcessHeap(), 0, - FIELD_OFFSET(LOGPALETTE, palPalEntry[nEntries])); - if (!logpalette) return NULL; - if (!GetPaletteEntries(hSrc, 0, nEntries, logpalette->palPalEntry)) - { - HeapFree(GetProcessHeap(), 0, logpalette); - return NULL; - } - logpalette->palVersion = 0x300; - logpalette->palNumEntries = (WORD)nEntries; - - hDst = CreatePalette(logpalette); - - HeapFree(GetProcessHeap(), 0, logpalette); - break; - } - case CF_BITMAP: - { - LONG size; - BITMAP bm; - if (!GetObjectW(hSrc, sizeof(bm), &bm)) - return NULL; - size = GetBitmapBits(hSrc, 0, NULL); - if (!size) return NULL; - bm.bmBits = HeapAlloc(GetProcessHeap(), 0, size); - if (!bm.bmBits) return NULL; - if (GetBitmapBits(hSrc, size, bm.bmBits)) - hDst = CreateBitmapIndirect(&bm); - HeapFree(GetProcessHeap(), 0, bm.bmBits); - break; - } - default: - { - SIZE_T size = GlobalSize(hSrc); - LPVOID pvSrc = NULL; - LPVOID pvDst = NULL; - - /* allocate space for object */ - if (!size) return NULL; - hDst = GlobalAlloc(uiFlags, size); - if (!hDst) return NULL; - - /* lock pointers */ - pvSrc = GlobalLock(hSrc); - if (!pvSrc) - { - GlobalFree(hDst); - return NULL; - } - pvDst = GlobalLock(hDst); - if (!pvDst) - { - GlobalUnlock(hSrc); - GlobalFree(hDst); - return NULL; - } - /* copy data */ - memcpy(pvDst, pvSrc, size); - - /* cleanup */ - GlobalUnlock(hDst); - GlobalUnlock(hSrc); - } - } - - TRACE("returning %p\n", hDst); - return hDst; -} +/* + * Ole 2 Create functions implementation + * + * Copyright (C) 1999-2000 Abey George + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> +#include <string.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "wine/debug.h" +#include "ole2.h" +#include "olestd.h" +#include "winreg.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +#define MAX_CLIPFORMAT_NAME 80 + +/****************************************************************************** + * OleQueryCreateFromData [OLE32.@] + * + * Author : Abey George + * Checks whether an object can become an embedded object. + * the clipboard or OLE drag and drop. + * Returns : S_OK - Format that supports Embedded object creation are present. + * OLE_E_STATIC - Format that supports static object creation are present. + * S_FALSE - No acceptable format is available. + */ + +HRESULT WINAPI OleQueryCreateFromData(LPDATAOBJECT pSrcDataObject) +{ + IEnumFORMATETC *pfmt; + FORMATETC fmt; + CHAR szFmtName[MAX_CLIPFORMAT_NAME]; + BOOL bFoundStatic = FALSE; + + HRESULT hr = IDataObject_EnumFormatEtc(pSrcDataObject, DATADIR_GET, &pfmt); + + if (hr == S_OK) + hr = IEnumFORMATETC_Next(pfmt, 1, &fmt, NULL); + + while (hr == S_OK) + { + GetClipboardFormatNameA(fmt.cfFormat, szFmtName, MAX_CLIPFORMAT_NAME-1); + + /* first, Check for Embedded Object, Embed Source or Filename */ + + if (!strcmp(szFmtName, CF_EMBEDDEDOBJECT) || !strcmp(szFmtName, CF_EMBEDSOURCE) || !strcmp(szFmtName, CF_FILENAME)) + return S_OK; + + /* Check for Metafile, Bitmap or DIB */ + + if (fmt.cfFormat == CF_METAFILEPICT || fmt.cfFormat == CF_BITMAP || fmt.cfFormat == CF_DIB) + bFoundStatic = TRUE; + + hr = IEnumFORMATETC_Next(pfmt, 1, &fmt, NULL); + } + + /* Found a static format, but no embed format */ + + if (bFoundStatic) + return OLE_S_STATIC; + + return S_FALSE; +} + +/****************************************************************************** + * OleCreateFromData [OLE32.@] + * + * Author : Abey George + * Creates an embedded object from data transfer object retrieved from + * the clipboard or OLE drag and drop. + * Returns : S_OK - Embedded object was created successfully. + * OLE_E_STATIC - OLE can create only a static object + * DV_E_FORMATETC - No acceptable format is available (only error return code) + * TODO : CF_FILENAME, CF_EMBEDEDOBJECT formats. Parameter renderopt is currently ignored. + */ + +HRESULT WINAPI OleCreateFromData(LPDATAOBJECT pSrcDataObject, REFIID riid, + DWORD renderopt, LPFORMATETC pFormatEtc, + LPOLECLIENTSITE pClientSite, LPSTORAGE pStg, + LPVOID* ppvObj) +{ + IEnumFORMATETC *pfmt; + FORMATETC fmt; + CHAR szFmtName[MAX_CLIPFORMAT_NAME]; + STGMEDIUM std; + HRESULT hr; + HRESULT hr1; + + hr = IDataObject_EnumFormatEtc(pSrcDataObject, DATADIR_GET, &pfmt); + + if (hr == S_OK) + { + memset(&std, 0, sizeof(STGMEDIUM)); + + hr = IEnumFORMATETC_Next(pfmt, 1, &fmt, NULL); + while (hr == S_OK) + { + GetClipboardFormatNameA(fmt.cfFormat, szFmtName, MAX_CLIPFORMAT_NAME-1); + + /* first, Check for Embedded Object, Embed Source or Filename */ + /* TODO: Currently checks only for Embed Source. */ + + if (!strcmp(szFmtName, CF_EMBEDSOURCE)) + { + std.tymed = TYMED_HGLOBAL; + + if ((hr1 = IDataObject_GetData(pSrcDataObject, &fmt, &std)) == S_OK) + { + ILockBytes *ptrILockBytes = 0; + IStorage *pStorage = 0; + IOleObject *pOleObject = 0; + IPersistStorage *pPersistStorage = 0; + CLSID clsID; + + /* Create ILock bytes */ + + hr1 = CreateILockBytesOnHGlobal(std.u.hGlobal, FALSE, &ptrILockBytes); + + /* Open storage on the ILock bytes */ + + if (hr1 == S_OK) + hr1 = StgOpenStorageOnILockBytes(ptrILockBytes, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &pStorage); + + /* Get Class ID from the opened storage */ + + if (hr1 == S_OK) + hr1 = ReadClassStg(pStorage, &clsID); + + /* Create default handler for Persist storage */ + + if (hr1 == S_OK) + hr1 = OleCreateDefaultHandler(&clsID, NULL, &IID_IPersistStorage, (LPVOID*)&pPersistStorage); + + /* Load the storage to Persist storage */ + + if (hr1 == S_OK) + hr1 = IPersistStorage_Load(pPersistStorage, pStorage); + + /* Query for IOleObject */ + + if (hr1 == S_OK) + hr1 = IPersistStorage_QueryInterface(pPersistStorage, &IID_IOleObject, (LPVOID*)&pOleObject); + + /* Set client site with the IOleObject */ + + if (hr1 == S_OK) + hr1 = IOleObject_SetClientSite(pOleObject, pClientSite); + + IPersistStorage_Release(pPersistStorage); + /* Query for the requested interface */ + + if (hr1 == S_OK) + hr1 = IPersistStorage_QueryInterface(pPersistStorage, riid, ppvObj); + + IPersistStorage_Release(pPersistStorage); + + IStorage_Release(pStorage); + + if (hr1 == S_OK) + return S_OK; + } + + /* Return error */ + + return DV_E_FORMATETC; + } + + hr = IEnumFORMATETC_Next(pfmt, 1, &fmt, NULL); + } + } + + return DV_E_FORMATETC; +} + + +/****************************************************************************** + * OleDuplicateData [OLE32.@] + * + * Duplicates clipboard data. + * + * PARAMS + * hSrc [I] Handle of the source clipboard data. + * cfFormat [I] The clipboard format of hSrc. + * uiFlags [I] Flags to pass to GlobalAlloc. + * + * RETURNS + * Success: handle to the duplicated data. + * Failure: NULL. + */ +HANDLE WINAPI OleDuplicateData(HANDLE hSrc, CLIPFORMAT cfFormat, + UINT uiFlags) +{ + HANDLE hDst = NULL; + + TRACE("(%p,%x,%x)\n", hSrc, cfFormat, uiFlags); + + if (!uiFlags) uiFlags = GMEM_MOVEABLE; + + switch (cfFormat) + { + case CF_ENHMETAFILE: + hDst = CopyEnhMetaFileW(hSrc, NULL); + break; + case CF_METAFILEPICT: + hDst = CopyMetaFileW(hSrc, NULL); + break; + case CF_PALETTE: + { + LOGPALETTE * logpalette; + UINT nEntries = GetPaletteEntries(hSrc, 0, 0, NULL); + if (!nEntries) return NULL; + logpalette = HeapAlloc(GetProcessHeap(), 0, + FIELD_OFFSET(LOGPALETTE, palPalEntry[nEntries])); + if (!logpalette) return NULL; + if (!GetPaletteEntries(hSrc, 0, nEntries, logpalette->palPalEntry)) + { + HeapFree(GetProcessHeap(), 0, logpalette); + return NULL; + } + logpalette->palVersion = 0x300; + logpalette->palNumEntries = (WORD)nEntries; + + hDst = CreatePalette(logpalette); + + HeapFree(GetProcessHeap(), 0, logpalette); + break; + } + case CF_BITMAP: + { + LONG size; + BITMAP bm; + if (!GetObjectW(hSrc, sizeof(bm), &bm)) + return NULL; + size = GetBitmapBits(hSrc, 0, NULL); + if (!size) return NULL; + bm.bmBits = HeapAlloc(GetProcessHeap(), 0, size); + if (!bm.bmBits) return NULL; + if (GetBitmapBits(hSrc, size, bm.bmBits)) + hDst = CreateBitmapIndirect(&bm); + HeapFree(GetProcessHeap(), 0, bm.bmBits); + break; + } + default: + { + SIZE_T size = GlobalSize(hSrc); + LPVOID pvSrc = NULL; + LPVOID pvDst = NULL; + + /* allocate space for object */ + if (!size) return NULL; + hDst = GlobalAlloc(uiFlags, size); + if (!hDst) return NULL; + + /* lock pointers */ + pvSrc = GlobalLock(hSrc); + if (!pvSrc) + { + GlobalFree(hDst); + return NULL; + } + pvDst = GlobalLock(hDst); + if (!pvDst) + { + GlobalUnlock(hSrc); + GlobalFree(hDst); + return NULL; + } + /* copy data */ + memcpy(pvDst, pvSrc, size); + + /* cleanup */ + GlobalUnlock(hDst); + GlobalUnlock(hSrc); + } + } + + TRACE("returning %p\n", hDst); + return hDst; +} diff --git a/reactos/lib/ole32/ole2nls.c b/reactos/lib/ole32/ole2nls.c index 364e7950bc8..82dff4b6b93 100644 --- a/reactos/lib/ole32/ole2nls.c +++ b/reactos/lib/ole32/ole2nls.c @@ -1,136 +1,136 @@ -/* - * OLE2NLS library - * - * Copyright 1995 Martin von Loewis - * Copyright 1998 David Lee Lambert - * Copyright 2000 Julio César Gázquez - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <string.h> -#include <stdarg.h> -#include <stdio.h> -#include <ctype.h> -#include <stdlib.h> -#include <locale.h> - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "winnls.h" -#include "winreg.h" -#include "winuser.h" -#include "winver.h" - -#include "wine/winbase16.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -static LPVOID lpNLSInfo = NULL; - -/****************************************************************************** - * GetLocaleInfoA [OLE2NLS.5] - * Is the last parameter really WORD for Win16? - */ -INT16 WINAPI GetLocaleInfo16(LCID lcid,LCTYPE LCType,LPSTR buf,INT16 len) -{ - return GetLocaleInfoA(lcid,LCType,buf,len); -} - -/****************************************************************************** - * GetStringTypeA [OLE2NLS.7] - */ -BOOL16 WINAPI GetStringType16(LCID locale,DWORD dwInfoType,LPCSTR src, - INT16 cchSrc,LPWORD chartype) -{ - return GetStringTypeExA(locale,dwInfoType,src,cchSrc,chartype); -} - -/****************************************************************************** - * GetUserDefaultLCID [OLE2NLS.1] - */ -LCID WINAPI GetUserDefaultLCID16(void) -{ - return GetUserDefaultLCID(); -} - -/****************************************************************************** - * GetSystemDefaultLCID [OLE2NLS.2] - */ -LCID WINAPI GetSystemDefaultLCID16(void) -{ - return GetSystemDefaultLCID(); -} - -/****************************************************************************** - * GetUserDefaultLangID [OLE2NLS.3] - */ -LANGID WINAPI GetUserDefaultLangID16(void) -{ - return GetUserDefaultLangID(); -} - -/****************************************************************************** - * GetSystemDefaultLangID [OLE2NLS.4] - */ -LANGID WINAPI GetSystemDefaultLangID16(void) -{ - return GetSystemDefaultLangID(); -} - -/****************************************************************************** - * LCMapStringA [OLE2NLS.6] - */ -INT16 LCMapString16(LCID lcid, DWORD mapflags, LPCSTR srcstr, INT16 srclen, - LPSTR dststr, INT16 dstlen) -{ - return LCMapStringA(lcid, mapflags, srcstr, srclen, dststr, dstlen); -} - -/*********************************************************************** - * CompareStringA (OLE2NLS.8) - */ -UINT16 WINAPI CompareString16(DWORD lcid,DWORD fdwStyle, - LPCSTR s1,DWORD l1,LPCSTR s2,DWORD l2) -{ - return (UINT16)CompareStringA(lcid,fdwStyle,s1,l1,s2,l2); -} - -/****************************************************************************** - * RegisterNLSInfoChanged [OLE2NLS.9] - */ -BOOL16 WINAPI RegisterNLSInfoChanged16(LPVOID lpNewNLSInfo) /* [???] FIXME */ -{ - FIXME("Fully implemented, but doesn't effect anything.\n"); - - if (!lpNewNLSInfo) { - lpNLSInfo = NULL; - return TRUE; - } - else { - if (!lpNLSInfo) { - lpNLSInfo = lpNewNLSInfo; - return TRUE; - } - } - - return FALSE; /* ptr not set */ -} - +/* + * OLE2NLS library + * + * Copyright 1995 Martin von Loewis + * Copyright 1998 David Lee Lambert + * Copyright 2000 Julio César Gázquez + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <string.h> +#include <stdarg.h> +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> +#include <locale.h> + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winnls.h" +#include "winreg.h" +#include "winuser.h" +#include "winver.h" + +#include "wine/winbase16.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +static LPVOID lpNLSInfo = NULL; + +/****************************************************************************** + * GetLocaleInfoA [OLE2NLS.5] + * Is the last parameter really WORD for Win16? + */ +INT16 WINAPI GetLocaleInfo16(LCID lcid,LCTYPE LCType,LPSTR buf,INT16 len) +{ + return GetLocaleInfoA(lcid,LCType,buf,len); +} + +/****************************************************************************** + * GetStringTypeA [OLE2NLS.7] + */ +BOOL16 WINAPI GetStringType16(LCID locale,DWORD dwInfoType,LPCSTR src, + INT16 cchSrc,LPWORD chartype) +{ + return GetStringTypeExA(locale,dwInfoType,src,cchSrc,chartype); +} + +/****************************************************************************** + * GetUserDefaultLCID [OLE2NLS.1] + */ +LCID WINAPI GetUserDefaultLCID16(void) +{ + return GetUserDefaultLCID(); +} + +/****************************************************************************** + * GetSystemDefaultLCID [OLE2NLS.2] + */ +LCID WINAPI GetSystemDefaultLCID16(void) +{ + return GetSystemDefaultLCID(); +} + +/****************************************************************************** + * GetUserDefaultLangID [OLE2NLS.3] + */ +LANGID WINAPI GetUserDefaultLangID16(void) +{ + return GetUserDefaultLangID(); +} + +/****************************************************************************** + * GetSystemDefaultLangID [OLE2NLS.4] + */ +LANGID WINAPI GetSystemDefaultLangID16(void) +{ + return GetSystemDefaultLangID(); +} + +/****************************************************************************** + * LCMapStringA [OLE2NLS.6] + */ +INT16 LCMapString16(LCID lcid, DWORD mapflags, LPCSTR srcstr, INT16 srclen, + LPSTR dststr, INT16 dstlen) +{ + return LCMapStringA(lcid, mapflags, srcstr, srclen, dststr, dstlen); +} + +/*********************************************************************** + * CompareStringA (OLE2NLS.8) + */ +UINT16 WINAPI CompareString16(DWORD lcid,DWORD fdwStyle, + LPCSTR s1,DWORD l1,LPCSTR s2,DWORD l2) +{ + return (UINT16)CompareStringA(lcid,fdwStyle,s1,l1,s2,l2); +} + +/****************************************************************************** + * RegisterNLSInfoChanged [OLE2NLS.9] + */ +BOOL16 WINAPI RegisterNLSInfoChanged16(LPVOID lpNewNLSInfo) /* [???] FIXME */ +{ + FIXME("Fully implemented, but doesn't effect anything.\n"); + + if (!lpNewNLSInfo) { + lpNLSInfo = NULL; + return TRUE; + } + else { + if (!lpNLSInfo) { + lpNLSInfo = lpNewNLSInfo; + return TRUE; + } + } + + return FALSE; /* ptr not set */ +} + diff --git a/reactos/lib/ole32/ole2stubs.c b/reactos/lib/ole32/ole2stubs.c index bb827871917..44970be9131 100644 --- a/reactos/lib/ole32/ole2stubs.c +++ b/reactos/lib/ole32/ole2stubs.c @@ -1,166 +1,166 @@ -/* - * Temporary place for ole2 stubs. - * - * Copyright (C) 1999 Corel Corporation - * Move these functions to dlls/ole32/ole2impl.c when you implement them. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define NONAMELESSUNION -#define NONAMELESSSTRUCT -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "ole2.h" -#include "objidl.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/****************************************************************************** - * OleCreateLinkToFile [OLE32.@] - */ -HRESULT WINAPI OleCreateLinkToFile(LPCOLESTR lpszFileName, REFIID riid, - DWORD renderopt, LPFORMATETC lpFormatEtc, - LPOLECLIENTSITE pClientSite, LPSTORAGE pStg, LPVOID* ppvObj) -{ - FIXME("(%p,%p,%li,%p,%p,%p,%p), stub!\n",lpszFileName, riid, renderopt, lpFormatEtc, pClientSite, pStg, ppvObj); - return E_NOTIMPL; -} - -/****************************************************************************** - * SetConvertStg [OLE32.@] - */ -HRESULT WINAPI SetConvertStg(LPSTORAGE pStg, BOOL fConvert) -{ - FIXME("(%p,%x), stub!\n", pStg, fConvert); - return E_NOTIMPL; -} - -/****************************************************************************** - * OleCreateLink [OLE32.@] - */ -HRESULT WINAPI OleCreateLink(LPMONIKER pmkLinkSrc, REFIID riid, DWORD renderopt, LPFORMATETC lpFormatEtc, - LPOLECLIENTSITE pClientSite, LPSTORAGE pStg, LPVOID* ppvObj) -{ - FIXME("(not shown), stub!\n"); - return E_NOTIMPL; -} - -/****************************************************************************** - * OleCreateFromFile [OLE32.@] - */ -HRESULT WINAPI OleCreateFromFile(REFCLSID rclsid, LPCOLESTR lpszFileName, REFIID riid, - DWORD renderopt, LPFORMATETC lpFormatEtc, LPOLECLIENTSITE pClientSite, LPSTORAGE pStg, LPVOID* ppvObj) -{ - FIXME("(not shown), stub!\n"); - return E_NOTIMPL; -} - - -/****************************************************************************** - * OleGetIconOfClass [OLE32.@] - */ -HGLOBAL WINAPI OleGetIconOfClass(REFCLSID rclsid, LPOLESTR lpszLabel, BOOL fUseTypeAsLabel) -{ - FIXME("(%p,%p,%x), stub!\n", rclsid, lpszLabel, fUseTypeAsLabel); - return NULL; -} - - -/****************************************************************************** - * OleCreateStaticFromData [OLE32.@] - */ -HRESULT WINAPI OleCreateStaticFromData(LPDATAOBJECT pSrcDataObj, REFIID iid, - DWORD renderopt, LPFORMATETC pFormatEtc, LPOLECLIENTSITE pClientSite, - LPSTORAGE pStg, LPVOID* ppvObj) -{ - FIXME("(not shown), stub!\n"); - return E_NOTIMPL; -} - -/****************************************************************************** - * OleCreateLinkFromData [OLE32.@] - */ - -HRESULT WINAPI OleCreateLinkFromData(LPDATAOBJECT pSrcDataObj, REFIID riid, - DWORD renderopt, LPFORMATETC pFormatEtc, - LPOLECLIENTSITE pClientSite, LPSTORAGE pStg, - LPVOID* ppvObj) -{ - FIXME("(not shown), stub!\n"); - return E_NOTIMPL; -} - -/****************************************************************************** - * OleIsRunning [OLE32.@] - */ -BOOL WINAPI OleIsRunning(LPOLEOBJECT pObject) -{ - FIXME("(%p), stub!\n", pObject); - return TRUE; -} - -/*********************************************************************** - * OleRegEnumVerbs [OLE32.@] - */ -HRESULT WINAPI OleRegEnumVerbs (REFCLSID clsid, LPENUMOLEVERB* ppenum) -{ - FIXME("(%p,%p), stub!\n", clsid, ppenum); - return OLEOBJ_E_NOVERBS; -} - -/*********************************************************************** - * OleRegEnumFormatEtc [OLE32.@] - */ -HRESULT WINAPI OleRegEnumFormatEtc ( - REFCLSID clsid, - DWORD dwDirection, - LPENUMFORMATETC* ppenumFormatetc) -{ - FIXME("(%p, %ld, %p), stub!\n", clsid, dwDirection, ppenumFormatetc); - - return E_NOTIMPL; -} - -/*********************************************************************** - * DllGetClassObject [OLE2.4] - */ -HRESULT WINAPI DllGetClassObject16(REFCLSID rclsid, REFIID iid, LPVOID *ppv) -{ - FIXME("(%s, %s, %p): stub\n", debugstr_guid(rclsid), debugstr_guid(iid), ppv); - return E_NOTIMPL; -} - -/*********************************************************************** - * OleSetClipboard [OLE2.49] - */ -HRESULT WINAPI OleSetClipboard16(IDataObject* pDataObj) -{ - FIXME("(%p): stub\n", pDataObj); - return S_OK; -} - -/*********************************************************************** - * OleGetClipboard [OLE2.50] - */ -HRESULT WINAPI OleGetClipboard16(IDataObject** ppDataObj) -{ - FIXME("(%p): stub\n", ppDataObj); - return E_NOTIMPL; -} +/* + * Temporary place for ole2 stubs. + * + * Copyright (C) 1999 Corel Corporation + * Move these functions to dlls/ole32/ole2impl.c when you implement them. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "ole2.h" +#include "objidl.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/****************************************************************************** + * OleCreateLinkToFile [OLE32.@] + */ +HRESULT WINAPI OleCreateLinkToFile(LPCOLESTR lpszFileName, REFIID riid, + DWORD renderopt, LPFORMATETC lpFormatEtc, + LPOLECLIENTSITE pClientSite, LPSTORAGE pStg, LPVOID* ppvObj) +{ + FIXME("(%p,%p,%li,%p,%p,%p,%p), stub!\n",lpszFileName, riid, renderopt, lpFormatEtc, pClientSite, pStg, ppvObj); + return E_NOTIMPL; +} + +/****************************************************************************** + * SetConvertStg [OLE32.@] + */ +HRESULT WINAPI SetConvertStg(LPSTORAGE pStg, BOOL fConvert) +{ + FIXME("(%p,%x), stub!\n", pStg, fConvert); + return E_NOTIMPL; +} + +/****************************************************************************** + * OleCreateLink [OLE32.@] + */ +HRESULT WINAPI OleCreateLink(LPMONIKER pmkLinkSrc, REFIID riid, DWORD renderopt, LPFORMATETC lpFormatEtc, + LPOLECLIENTSITE pClientSite, LPSTORAGE pStg, LPVOID* ppvObj) +{ + FIXME("(not shown), stub!\n"); + return E_NOTIMPL; +} + +/****************************************************************************** + * OleCreateFromFile [OLE32.@] + */ +HRESULT WINAPI OleCreateFromFile(REFCLSID rclsid, LPCOLESTR lpszFileName, REFIID riid, + DWORD renderopt, LPFORMATETC lpFormatEtc, LPOLECLIENTSITE pClientSite, LPSTORAGE pStg, LPVOID* ppvObj) +{ + FIXME("(not shown), stub!\n"); + return E_NOTIMPL; +} + + +/****************************************************************************** + * OleGetIconOfClass [OLE32.@] + */ +HGLOBAL WINAPI OleGetIconOfClass(REFCLSID rclsid, LPOLESTR lpszLabel, BOOL fUseTypeAsLabel) +{ + FIXME("(%p,%p,%x), stub!\n", rclsid, lpszLabel, fUseTypeAsLabel); + return NULL; +} + + +/****************************************************************************** + * OleCreateStaticFromData [OLE32.@] + */ +HRESULT WINAPI OleCreateStaticFromData(LPDATAOBJECT pSrcDataObj, REFIID iid, + DWORD renderopt, LPFORMATETC pFormatEtc, LPOLECLIENTSITE pClientSite, + LPSTORAGE pStg, LPVOID* ppvObj) +{ + FIXME("(not shown), stub!\n"); + return E_NOTIMPL; +} + +/****************************************************************************** + * OleCreateLinkFromData [OLE32.@] + */ + +HRESULT WINAPI OleCreateLinkFromData(LPDATAOBJECT pSrcDataObj, REFIID riid, + DWORD renderopt, LPFORMATETC pFormatEtc, + LPOLECLIENTSITE pClientSite, LPSTORAGE pStg, + LPVOID* ppvObj) +{ + FIXME("(not shown), stub!\n"); + return E_NOTIMPL; +} + +/****************************************************************************** + * OleIsRunning [OLE32.@] + */ +BOOL WINAPI OleIsRunning(LPOLEOBJECT pObject) +{ + FIXME("(%p), stub!\n", pObject); + return TRUE; +} + +/*********************************************************************** + * OleRegEnumVerbs [OLE32.@] + */ +HRESULT WINAPI OleRegEnumVerbs (REFCLSID clsid, LPENUMOLEVERB* ppenum) +{ + FIXME("(%p,%p), stub!\n", clsid, ppenum); + return OLEOBJ_E_NOVERBS; +} + +/*********************************************************************** + * OleRegEnumFormatEtc [OLE32.@] + */ +HRESULT WINAPI OleRegEnumFormatEtc ( + REFCLSID clsid, + DWORD dwDirection, + LPENUMFORMATETC* ppenumFormatetc) +{ + FIXME("(%p, %ld, %p), stub!\n", clsid, dwDirection, ppenumFormatetc); + + return E_NOTIMPL; +} + +/*********************************************************************** + * DllGetClassObject [OLE2.4] + */ +HRESULT WINAPI DllGetClassObject16(REFCLSID rclsid, REFIID iid, LPVOID *ppv) +{ + FIXME("(%s, %s, %p): stub\n", debugstr_guid(rclsid), debugstr_guid(iid), ppv); + return E_NOTIMPL; +} + +/*********************************************************************** + * OleSetClipboard [OLE2.49] + */ +HRESULT WINAPI OleSetClipboard16(IDataObject* pDataObj) +{ + FIXME("(%p): stub\n", pDataObj); + return S_OK; +} + +/*********************************************************************** + * OleGetClipboard [OLE2.50] + */ +HRESULT WINAPI OleGetClipboard16(IDataObject** ppDataObj) +{ + FIXME("(%p): stub\n", ppDataObj); + return E_NOTIMPL; +} diff --git a/reactos/lib/ole32/ole32_main.c b/reactos/lib/ole32/ole32_main.c index 8ba8d52473d..4a133822527 100644 --- a/reactos/lib/ole32/ole32_main.c +++ b/reactos/lib/ole32/ole32_main.c @@ -1,110 +1,110 @@ -/* - * OLE32 Initialization - * - * Copyright 2000 Huw D M Davies for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> -#include <stdio.h> - -#include "windef.h" -#include "winerror.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "objbase.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/*********************************************************************** - * OleMetafilePictFromIconAndLabel (OLE32.@) - */ -HGLOBAL WINAPI OleMetafilePictFromIconAndLabel(HICON hIcon, LPOLESTR lpszLabel, - LPOLESTR lpszSourceFile, UINT iIconIndex) -{ - METAFILEPICT mfp; - HDC hdc; - UINT dy; - HGLOBAL hmem = NULL; - LPVOID mfdata; - static const char szIconOnly[] = "IconOnly"; - - TRACE("%p %p %s %d\n", hIcon, lpszLabel, debugstr_w(lpszSourceFile), iIconIndex); - - if( !hIcon ) - return NULL; - - hdc = CreateMetaFileW(NULL); - if( !hdc ) - return NULL; - - ExtEscape(hdc, MFCOMMENT, sizeof(szIconOnly), szIconOnly, 0, NULL); - - /* FIXME: things are drawn in the wrong place */ - DrawIcon(hdc, 0, 0, hIcon); - dy = GetSystemMetrics(SM_CXICON); - if(lpszLabel) - TextOutW(hdc, 0, dy, lpszLabel, lstrlenW(lpszLabel)); - - if (lpszSourceFile) - { - char szIconIndex[10]; - int path_length = WideCharToMultiByte(CP_ACP,0,lpszSourceFile,-1,NULL,0,NULL,NULL); - if (path_length > 1) - { - char * szPath = CoTaskMemAlloc(path_length * sizeof(CHAR)); - if (szPath) - { - WideCharToMultiByte(CP_ACP,0,lpszSourceFile,-1,szPath,path_length,NULL,NULL); - ExtEscape(hdc, MFCOMMENT, path_length, szPath, 0, NULL); - CoTaskMemFree(szPath); - } - } - snprintf(szIconIndex, 10, "%u", iIconIndex); - ExtEscape(hdc, MFCOMMENT, strlen(szIconIndex)+1, szIconIndex, 0, NULL); - } - - mfp.mm = MM_ISOTROPIC; - mfp.xExt = mfp.yExt = 0; /* FIXME ? */ - mfp.hMF = CloseMetaFile(hdc); - if( !mfp.hMF ) - return NULL; - - hmem = GlobalAlloc( GMEM_MOVEABLE, sizeof(mfp) ); - if( !hmem ) - { - DeleteMetaFile(mfp.hMF); - return NULL; - } - - mfdata = GlobalLock( hmem ); - if( !mfdata ) - { - GlobalFree( hmem ); - DeleteMetaFile(mfp.hMF); - return NULL; - } - - memcpy(mfdata,&mfp,sizeof(mfp)); - GlobalUnlock( hmem ); - - TRACE("returning %p\n",hmem); - - return hmem; -} +/* + * OLE32 Initialization + * + * Copyright 2000 Huw D M Davies for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> +#include <stdio.h> + +#include "windef.h" +#include "winerror.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "objbase.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/*********************************************************************** + * OleMetafilePictFromIconAndLabel (OLE32.@) + */ +HGLOBAL WINAPI OleMetafilePictFromIconAndLabel(HICON hIcon, LPOLESTR lpszLabel, + LPOLESTR lpszSourceFile, UINT iIconIndex) +{ + METAFILEPICT mfp; + HDC hdc; + UINT dy; + HGLOBAL hmem = NULL; + LPVOID mfdata; + static const char szIconOnly[] = "IconOnly"; + + TRACE("%p %p %s %d\n", hIcon, lpszLabel, debugstr_w(lpszSourceFile), iIconIndex); + + if( !hIcon ) + return NULL; + + hdc = CreateMetaFileW(NULL); + if( !hdc ) + return NULL; + + ExtEscape(hdc, MFCOMMENT, sizeof(szIconOnly), szIconOnly, 0, NULL); + + /* FIXME: things are drawn in the wrong place */ + DrawIcon(hdc, 0, 0, hIcon); + dy = GetSystemMetrics(SM_CXICON); + if(lpszLabel) + TextOutW(hdc, 0, dy, lpszLabel, lstrlenW(lpszLabel)); + + if (lpszSourceFile) + { + char szIconIndex[10]; + int path_length = WideCharToMultiByte(CP_ACP,0,lpszSourceFile,-1,NULL,0,NULL,NULL); + if (path_length > 1) + { + char * szPath = CoTaskMemAlloc(path_length * sizeof(CHAR)); + if (szPath) + { + WideCharToMultiByte(CP_ACP,0,lpszSourceFile,-1,szPath,path_length,NULL,NULL); + ExtEscape(hdc, MFCOMMENT, path_length, szPath, 0, NULL); + CoTaskMemFree(szPath); + } + } + snprintf(szIconIndex, 10, "%u", iIconIndex); + ExtEscape(hdc, MFCOMMENT, strlen(szIconIndex)+1, szIconIndex, 0, NULL); + } + + mfp.mm = MM_ISOTROPIC; + mfp.xExt = mfp.yExt = 0; /* FIXME ? */ + mfp.hMF = CloseMetaFile(hdc); + if( !mfp.hMF ) + return NULL; + + hmem = GlobalAlloc( GMEM_MOVEABLE, sizeof(mfp) ); + if( !hmem ) + { + DeleteMetaFile(mfp.hMF); + return NULL; + } + + mfdata = GlobalLock( hmem ); + if( !mfdata ) + { + GlobalFree( hmem ); + DeleteMetaFile(mfp.hMF); + return NULL; + } + + memcpy(mfdata,&mfp,sizeof(mfp)); + GlobalUnlock( hmem ); + + TRACE("returning %p\n",hmem); + + return hmem; +} diff --git a/reactos/lib/ole32/oleobj.c b/reactos/lib/ole32/oleobj.c index c1e170e8312..2e75c571a6b 100644 --- a/reactos/lib/ole32/oleobj.c +++ b/reactos/lib/ole32/oleobj.c @@ -1,706 +1,706 @@ -/* - * OLE2 COM objects - * - * Copyright 1998 Eric Kohl - * Copyright 1999 Francis Beaudet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include <stdarg.h> -#include <string.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "winerror.h" -#include "wine/debug.h" -#include "ole2.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -#define INITIAL_SINKS 10 - -/************************************************************************** - * OleAdviseHolderImpl Implementation - */ -typedef struct OleAdviseHolderImpl -{ - IOleAdviseHolderVtbl *lpVtbl; - - DWORD ref; - - DWORD maxSinks; - IAdviseSink** arrayOfSinks; - -} OleAdviseHolderImpl; - -/************************************************************************** - * OleAdviseHolderImpl_Destructor - */ -static void OleAdviseHolderImpl_Destructor( - OleAdviseHolderImpl* ptrToDestroy) -{ - DWORD index; - TRACE("%p\n", ptrToDestroy); - - for (index = 0; index < ptrToDestroy->maxSinks; index++) - { - if (ptrToDestroy->arrayOfSinks[index]!=0) - { - IAdviseSink_Release(ptrToDestroy->arrayOfSinks[index]); - ptrToDestroy->arrayOfSinks[index] = NULL; - } - } - - HeapFree(GetProcessHeap(), - 0, - ptrToDestroy->arrayOfSinks); - - - HeapFree(GetProcessHeap(), - 0, - ptrToDestroy); -} - -/************************************************************************** - * OleAdviseHolderImpl_QueryInterface - */ -static HRESULT WINAPI OleAdviseHolderImpl_QueryInterface( - LPOLEADVISEHOLDER iface, - REFIID riid, - LPVOID* ppvObj) -{ - OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; - TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObj); - /* - * Sanity check - */ - if (ppvObj==NULL) - return E_POINTER; - - *ppvObj = NULL; - - if (IsEqualIID(riid, &IID_IUnknown)) - { - /* IUnknown */ - *ppvObj = This; - } - else if(IsEqualIID(riid, &IID_IOleAdviseHolder)) - { - /* IOleAdviseHolder */ - *ppvObj = (IOleAdviseHolder*) This; - } - - if(*ppvObj == NULL) - return E_NOINTERFACE; - - /* - * A successful QI always increments the reference count. - */ - IUnknown_AddRef((IUnknown*)*ppvObj); - - return S_OK; -} - -/****************************************************************************** - * OleAdviseHolderImpl_AddRef - */ -static ULONG WINAPI OleAdviseHolderImpl_AddRef( - LPOLEADVISEHOLDER iface) -{ - OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; - ULONG ref = InterlockedIncrement(&This->ref); - - TRACE("(%p)->(ref=%ld)\n", This, ref - 1); - - return ref; -} - -/****************************************************************************** - * OleAdviseHolderImpl_Release - */ -static ULONG WINAPI OleAdviseHolderImpl_Release( - LPOLEADVISEHOLDER iface) -{ - OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; - ULONG ref; - TRACE("(%p)->(ref=%ld)\n", This, This->ref); - ref = InterlockedDecrement(&This->ref); - - if (ref == 0) OleAdviseHolderImpl_Destructor(This); - - return ref; -} - -/****************************************************************************** - * OleAdviseHolderImpl_Advise - */ -static HRESULT WINAPI OleAdviseHolderImpl_Advise( - LPOLEADVISEHOLDER iface, - IAdviseSink* pAdvise, - DWORD* pdwConnection) -{ - DWORD index; - - OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; - - TRACE("(%p)->(%p, %p)\n", This, pAdvise, pdwConnection); - - /* - * Sanity check - */ - if (pdwConnection==NULL) - return E_POINTER; - - *pdwConnection = 0; - - /* - * Find a free spot in the array. - */ - for (index = 0; index < This->maxSinks; index++) - { - if (This->arrayOfSinks[index]==NULL) - break; - } - - /* - * If the array is full, we need to grow it. - */ - if (index == This->maxSinks) - { - DWORD i; - - This->maxSinks+=INITIAL_SINKS; - - This->arrayOfSinks = HeapReAlloc(GetProcessHeap(), - 0, - This->arrayOfSinks, - This->maxSinks*sizeof(IAdviseSink*)); - - for (i=index;i < This->maxSinks; i++) - This->arrayOfSinks[i]=0; - } - - /* - * Store the new sink - */ - This->arrayOfSinks[index] = pAdvise; - - if (This->arrayOfSinks[index]!=NULL) - IAdviseSink_AddRef(This->arrayOfSinks[index]); - - /* - * Return the index as the cookie. - * Since 0 is not a valid cookie, we will increment by - * 1 the index in the table. - */ - *pdwConnection = index+1; - - return S_OK; -} - -/****************************************************************************** - * OleAdviseHolderImpl_Unadvise - */ -static HRESULT WINAPI OleAdviseHolderImpl_Unadvise( - LPOLEADVISEHOLDER iface, - DWORD dwConnection) -{ - OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; - - TRACE("(%p)->(%lu)\n", This, dwConnection); - - /* - * So we don't return 0 as a cookie, the index was - * incremented by 1 in OleAdviseHolderImpl_Advise - * we have to compensate. - */ - dwConnection--; - - /* - * Check for invalid cookies. - */ - if (dwConnection >= This->maxSinks) - return OLE_E_NOCONNECTION; - - if (This->arrayOfSinks[dwConnection] == NULL) - return OLE_E_NOCONNECTION; - - /* - * Release the sink and mark the spot in the list as free. - */ - IAdviseSink_Release(This->arrayOfSinks[dwConnection]); - This->arrayOfSinks[dwConnection] = NULL; - - return S_OK; -} - -/****************************************************************************** - * OleAdviseHolderImpl_EnumAdvise - */ -static HRESULT WINAPI -OleAdviseHolderImpl_EnumAdvise (LPOLEADVISEHOLDER iface, IEnumSTATDATA **ppenumAdvise) -{ - OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; - FIXME("(%p)->(%p)\n", This, ppenumAdvise); - - *ppenumAdvise = NULL; - - return S_OK; -} - -/****************************************************************************** - * OleAdviseHolderImpl_SendOnRename - */ -static HRESULT WINAPI -OleAdviseHolderImpl_SendOnRename (LPOLEADVISEHOLDER iface, IMoniker *pmk) -{ - OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; - FIXME("(%p)->(%p)\n", This, pmk); - - - return S_OK; -} - -/****************************************************************************** - * OleAdviseHolderImpl_SendOnSave - */ -static HRESULT WINAPI -OleAdviseHolderImpl_SendOnSave (LPOLEADVISEHOLDER iface) -{ - OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; - FIXME("(%p)\n", This); - - return S_OK; -} - -/****************************************************************************** - * OleAdviseHolderImpl_SendOnClose - */ -static HRESULT WINAPI -OleAdviseHolderImpl_SendOnClose (LPOLEADVISEHOLDER iface) -{ - OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; - FIXME("(%p)\n", This); - - - return S_OK; -} - -/************************************************************************** - * OleAdviseHolderImpl_VTable - */ -static struct IOleAdviseHolderVtbl oahvt = -{ - OleAdviseHolderImpl_QueryInterface, - OleAdviseHolderImpl_AddRef, - OleAdviseHolderImpl_Release, - OleAdviseHolderImpl_Advise, - OleAdviseHolderImpl_Unadvise, - OleAdviseHolderImpl_EnumAdvise, - OleAdviseHolderImpl_SendOnRename, - OleAdviseHolderImpl_SendOnSave, - OleAdviseHolderImpl_SendOnClose -}; - -/************************************************************************** - * OleAdviseHolderImpl_Constructor - */ - -static LPOLEADVISEHOLDER OleAdviseHolderImpl_Constructor() -{ - OleAdviseHolderImpl* lpoah; - DWORD index; - - lpoah = HeapAlloc(GetProcessHeap(), 0, sizeof(OleAdviseHolderImpl)); - - lpoah->lpVtbl = &oahvt; - lpoah->ref = 1; - lpoah->maxSinks = INITIAL_SINKS; - lpoah->arrayOfSinks = HeapAlloc(GetProcessHeap(), - 0, - lpoah->maxSinks * sizeof(IAdviseSink*)); - - for (index = 0; index < lpoah->maxSinks; index++) - lpoah->arrayOfSinks[index]=0; - - TRACE("returning %p\n", lpoah); - return (LPOLEADVISEHOLDER)lpoah; -} - -/************************************************************************** - * DataAdviseHolder Implementation - */ -typedef struct DataAdviseConnection { - IAdviseSink *sink; - FORMATETC fmat; - DWORD advf; -} DataAdviseConnection; - -typedef struct DataAdviseHolder -{ - IDataAdviseHolderVtbl *lpVtbl; - - DWORD ref; - DWORD maxCons; - DataAdviseConnection* Connections; -} DataAdviseHolder; - -/****************************************************************************** - * DataAdviseHolder_Destructor - */ -static void DataAdviseHolder_Destructor(DataAdviseHolder* ptrToDestroy) -{ - DWORD index; - TRACE("%p\n", ptrToDestroy); - - for (index = 0; index < ptrToDestroy->maxCons; index++) - { - if (ptrToDestroy->Connections[index].sink != NULL) - { - IAdviseSink_Release(ptrToDestroy->Connections[index].sink); - ptrToDestroy->Connections[index].sink = NULL; - } - } - - HeapFree(GetProcessHeap(), 0, ptrToDestroy->Connections); - HeapFree(GetProcessHeap(), 0, ptrToDestroy); -} - -/************************************************************************ - * DataAdviseHolder_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static HRESULT WINAPI DataAdviseHolder_QueryInterface( - IDataAdviseHolder* iface, - REFIID riid, - void** ppvObject) -{ - DataAdviseHolder *This = (DataAdviseHolder *)iface; - TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject); - /* - * Perform a sanity check on the parameters. - */ - if ( (This==0) || (ppvObject==0) ) - return E_INVALIDARG; - - /* - * Initialize the return parameter. - */ - *ppvObject = 0; - - /* - * Compare the riid with the interface IDs implemented by this object. - */ - if ( (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) || - (memcmp(&IID_IDataAdviseHolder, riid, sizeof(IID_IDataAdviseHolder)) == 0) ) - { - *ppvObject = iface; - } - - /* - * Check that we obtained an interface. - */ - if ((*ppvObject)==0) - { - return E_NOINTERFACE; - } - - /* - * Query Interface always increases the reference count by one when it is - * successful. - */ - IUnknown_AddRef((IUnknown*)*ppvObject); - - return S_OK; -} - -/************************************************************************ - * DataAdviseHolder_AddRef (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI DataAdviseHolder_AddRef( - IDataAdviseHolder* iface) -{ - DataAdviseHolder *This = (DataAdviseHolder *)iface; - TRACE("(%p) (ref=%ld)\n", This, This->ref); - return InterlockedIncrement(&This->ref); -} - -/************************************************************************ - * DataAdviseHolder_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI DataAdviseHolder_Release( - IDataAdviseHolder* iface) -{ - DataAdviseHolder *This = (DataAdviseHolder *)iface; - ULONG ref; - TRACE("(%p) (ref=%ld)\n", This, This->ref); - - /* - * Decrease the reference count on this object. - */ - ref = InterlockedDecrement(&This->ref); - - /* - * If the reference count goes down to 0, perform suicide. - */ - if (ref==0) DataAdviseHolder_Destructor(This); - - return ref; -} - -/************************************************************************ - * DataAdviseHolder_Advise - * - */ -static HRESULT WINAPI DataAdviseHolder_Advise( - IDataAdviseHolder* iface, - IDataObject* pDataObject, - FORMATETC* pFetc, - DWORD advf, - IAdviseSink* pAdvise, - DWORD* pdwConnection) -{ - DWORD index; - - DataAdviseHolder *This = (DataAdviseHolder *)iface; - - TRACE("(%p)->(%p, %p, %08lx, %p, %p)\n", This, pDataObject, pFetc, advf, - pAdvise, pdwConnection); - /* - * Sanity check - */ - if (pdwConnection==NULL) - return E_POINTER; - - *pdwConnection = 0; - - /* - * Find a free spot in the array. - */ - for (index = 0; index < This->maxCons; index++) - { - if (This->Connections[index].sink == NULL) - break; - } - - /* - * If the array is full, we need to grow it. - */ - if (index == This->maxCons) - { - This->maxCons+=INITIAL_SINKS; - This->Connections = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - This->Connections, - This->maxCons*sizeof(DataAdviseConnection)); - } - /* - * Store the new sink - */ - This->Connections[index].sink = pAdvise; - memcpy(&(This->Connections[index].fmat), pFetc, sizeof(FORMATETC)); - This->Connections[index].advf = advf; - - if (This->Connections[index].sink != NULL) { - IAdviseSink_AddRef(This->Connections[index].sink); - if(advf & ADVF_PRIMEFIRST) { - IDataAdviseHolder_SendOnDataChange(iface, pDataObject, 0, advf); - } - } - /* - * Return the index as the cookie. - * Since 0 is not a valid cookie, we will increment by - * 1 the index in the table. - */ - *pdwConnection = index+1; - - return S_OK; -} - -/****************************************************************************** - * DataAdviseHolder_Unadvise - */ -static HRESULT WINAPI DataAdviseHolder_Unadvise( - IDataAdviseHolder* iface, - DWORD dwConnection) -{ - DataAdviseHolder *This = (DataAdviseHolder *)iface; - - TRACE("(%p)->(%lu)\n", This, dwConnection); - - /* - * So we don't return 0 as a cookie, the index was - * incremented by 1 in OleAdviseHolderImpl_Advise - * we have to compensate. - */ - dwConnection--; - - /* - * Check for invalid cookies. - */ - if (dwConnection >= This->maxCons) - return OLE_E_NOCONNECTION; - - if (This->Connections[dwConnection].sink == NULL) - return OLE_E_NOCONNECTION; - - /* - * Release the sink and mark the spot in the list as free. - */ - IAdviseSink_Release(This->Connections[dwConnection].sink); - memset(&(This->Connections[dwConnection]), 0, sizeof(DataAdviseConnection)); - return S_OK; -} - -static HRESULT WINAPI DataAdviseHolder_EnumAdvise( - IDataAdviseHolder* iface, - IEnumSTATDATA** ppenumAdvise) -{ - DataAdviseHolder *This = (DataAdviseHolder *)iface; - - FIXME("(%p)->(%p)\n", This, ppenumAdvise); - return E_NOTIMPL; -} - -/****************************************************************************** - * DataAdviseHolder_SendOnDataChange - */ -static HRESULT WINAPI DataAdviseHolder_SendOnDataChange( - IDataAdviseHolder* iface, - IDataObject* pDataObject, - DWORD dwReserved, - DWORD advf) -{ - DataAdviseHolder *This = (DataAdviseHolder *)iface; - DWORD index; - STGMEDIUM stg; - HRESULT res; - - TRACE("(%p)->(%p,%08lx,%08lx)\n", This, pDataObject, dwReserved, advf); - - for(index = 0; index < This->maxCons; index++) { - if(This->Connections[index].sink != NULL) { - if(!(This->Connections[index].advf & ADVF_NODATA)) { - TRACE("Calling IDataObject_GetData\n"); - res = IDataObject_GetData(pDataObject, - &(This->Connections[index].fmat), - &stg); - TRACE("returns %08lx\n", res); - } - TRACE("Calling IAdviseSink_OnDataChange\n"); - IAdviseSink_OnDataChange(This->Connections[index].sink, - &(This->Connections[index].fmat), - &stg); - TRACE("Done IAdviseSink_OnDataChange\n"); - if(This->Connections[index].advf & ADVF_ONLYONCE) { - TRACE("Removing connection\n"); - DataAdviseHolder_Unadvise(iface, index+1); - } - } - } - return S_OK; -} - -/************************************************************************** - * DataAdviseHolderImpl_VTable - */ -static struct IDataAdviseHolderVtbl DataAdviseHolderImpl_VTable = -{ - DataAdviseHolder_QueryInterface, - DataAdviseHolder_AddRef, - DataAdviseHolder_Release, - DataAdviseHolder_Advise, - DataAdviseHolder_Unadvise, - DataAdviseHolder_EnumAdvise, - DataAdviseHolder_SendOnDataChange -}; - -/****************************************************************************** - * DataAdviseHolder_Constructor - */ -static IDataAdviseHolder* DataAdviseHolder_Constructor() -{ - DataAdviseHolder* newHolder; - - newHolder = HeapAlloc(GetProcessHeap(), 0, sizeof(DataAdviseHolder)); - - newHolder->lpVtbl = &DataAdviseHolderImpl_VTable; - newHolder->ref = 1; - newHolder->maxCons = INITIAL_SINKS; - newHolder->Connections = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - newHolder->maxCons * - sizeof(DataAdviseConnection)); - - TRACE("returning %p\n", newHolder); - return (IDataAdviseHolder*)newHolder; -} - -/*********************************************************************** - * API functions - */ - -/*********************************************************************** - * CreateOleAdviseHolder [OLE32.@] - */ -HRESULT WINAPI CreateOleAdviseHolder( - LPOLEADVISEHOLDER *ppOAHolder) -{ - TRACE("(%p)\n", ppOAHolder); - - /* - * Sanity check, - */ - if (ppOAHolder==NULL) - return E_POINTER; - - *ppOAHolder = OleAdviseHolderImpl_Constructor (); - - if (*ppOAHolder != NULL) - return S_OK; - - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * CreateDataAdviseHolder [OLE32.@] - */ -HRESULT WINAPI CreateDataAdviseHolder( - LPDATAADVISEHOLDER* ppDAHolder) -{ - TRACE("(%p)\n", ppDAHolder); - - /* - * Sanity check, - */ - if (ppDAHolder==NULL) - return E_POINTER; - - *ppDAHolder = DataAdviseHolder_Constructor(); - - if (*ppDAHolder != NULL) - return S_OK; - - return E_OUTOFMEMORY; -} +/* + * OLE2 COM objects + * + * Copyright 1998 Eric Kohl + * Copyright 1999 Francis Beaudet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include <stdarg.h> +#include <string.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winerror.h" +#include "wine/debug.h" +#include "ole2.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +#define INITIAL_SINKS 10 + +/************************************************************************** + * OleAdviseHolderImpl Implementation + */ +typedef struct OleAdviseHolderImpl +{ + IOleAdviseHolderVtbl *lpVtbl; + + DWORD ref; + + DWORD maxSinks; + IAdviseSink** arrayOfSinks; + +} OleAdviseHolderImpl; + +/************************************************************************** + * OleAdviseHolderImpl_Destructor + */ +static void OleAdviseHolderImpl_Destructor( + OleAdviseHolderImpl* ptrToDestroy) +{ + DWORD index; + TRACE("%p\n", ptrToDestroy); + + for (index = 0; index < ptrToDestroy->maxSinks; index++) + { + if (ptrToDestroy->arrayOfSinks[index]!=0) + { + IAdviseSink_Release(ptrToDestroy->arrayOfSinks[index]); + ptrToDestroy->arrayOfSinks[index] = NULL; + } + } + + HeapFree(GetProcessHeap(), + 0, + ptrToDestroy->arrayOfSinks); + + + HeapFree(GetProcessHeap(), + 0, + ptrToDestroy); +} + +/************************************************************************** + * OleAdviseHolderImpl_QueryInterface + */ +static HRESULT WINAPI OleAdviseHolderImpl_QueryInterface( + LPOLEADVISEHOLDER iface, + REFIID riid, + LPVOID* ppvObj) +{ + OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; + TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObj); + /* + * Sanity check + */ + if (ppvObj==NULL) + return E_POINTER; + + *ppvObj = NULL; + + if (IsEqualIID(riid, &IID_IUnknown)) + { + /* IUnknown */ + *ppvObj = This; + } + else if(IsEqualIID(riid, &IID_IOleAdviseHolder)) + { + /* IOleAdviseHolder */ + *ppvObj = (IOleAdviseHolder*) This; + } + + if(*ppvObj == NULL) + return E_NOINTERFACE; + + /* + * A successful QI always increments the reference count. + */ + IUnknown_AddRef((IUnknown*)*ppvObj); + + return S_OK; +} + +/****************************************************************************** + * OleAdviseHolderImpl_AddRef + */ +static ULONG WINAPI OleAdviseHolderImpl_AddRef( + LPOLEADVISEHOLDER iface) +{ + OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p)->(ref=%ld)\n", This, ref - 1); + + return ref; +} + +/****************************************************************************** + * OleAdviseHolderImpl_Release + */ +static ULONG WINAPI OleAdviseHolderImpl_Release( + LPOLEADVISEHOLDER iface) +{ + OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; + ULONG ref; + TRACE("(%p)->(ref=%ld)\n", This, This->ref); + ref = InterlockedDecrement(&This->ref); + + if (ref == 0) OleAdviseHolderImpl_Destructor(This); + + return ref; +} + +/****************************************************************************** + * OleAdviseHolderImpl_Advise + */ +static HRESULT WINAPI OleAdviseHolderImpl_Advise( + LPOLEADVISEHOLDER iface, + IAdviseSink* pAdvise, + DWORD* pdwConnection) +{ + DWORD index; + + OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; + + TRACE("(%p)->(%p, %p)\n", This, pAdvise, pdwConnection); + + /* + * Sanity check + */ + if (pdwConnection==NULL) + return E_POINTER; + + *pdwConnection = 0; + + /* + * Find a free spot in the array. + */ + for (index = 0; index < This->maxSinks; index++) + { + if (This->arrayOfSinks[index]==NULL) + break; + } + + /* + * If the array is full, we need to grow it. + */ + if (index == This->maxSinks) + { + DWORD i; + + This->maxSinks+=INITIAL_SINKS; + + This->arrayOfSinks = HeapReAlloc(GetProcessHeap(), + 0, + This->arrayOfSinks, + This->maxSinks*sizeof(IAdviseSink*)); + + for (i=index;i < This->maxSinks; i++) + This->arrayOfSinks[i]=0; + } + + /* + * Store the new sink + */ + This->arrayOfSinks[index] = pAdvise; + + if (This->arrayOfSinks[index]!=NULL) + IAdviseSink_AddRef(This->arrayOfSinks[index]); + + /* + * Return the index as the cookie. + * Since 0 is not a valid cookie, we will increment by + * 1 the index in the table. + */ + *pdwConnection = index+1; + + return S_OK; +} + +/****************************************************************************** + * OleAdviseHolderImpl_Unadvise + */ +static HRESULT WINAPI OleAdviseHolderImpl_Unadvise( + LPOLEADVISEHOLDER iface, + DWORD dwConnection) +{ + OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; + + TRACE("(%p)->(%lu)\n", This, dwConnection); + + /* + * So we don't return 0 as a cookie, the index was + * incremented by 1 in OleAdviseHolderImpl_Advise + * we have to compensate. + */ + dwConnection--; + + /* + * Check for invalid cookies. + */ + if (dwConnection >= This->maxSinks) + return OLE_E_NOCONNECTION; + + if (This->arrayOfSinks[dwConnection] == NULL) + return OLE_E_NOCONNECTION; + + /* + * Release the sink and mark the spot in the list as free. + */ + IAdviseSink_Release(This->arrayOfSinks[dwConnection]); + This->arrayOfSinks[dwConnection] = NULL; + + return S_OK; +} + +/****************************************************************************** + * OleAdviseHolderImpl_EnumAdvise + */ +static HRESULT WINAPI +OleAdviseHolderImpl_EnumAdvise (LPOLEADVISEHOLDER iface, IEnumSTATDATA **ppenumAdvise) +{ + OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; + FIXME("(%p)->(%p)\n", This, ppenumAdvise); + + *ppenumAdvise = NULL; + + return S_OK; +} + +/****************************************************************************** + * OleAdviseHolderImpl_SendOnRename + */ +static HRESULT WINAPI +OleAdviseHolderImpl_SendOnRename (LPOLEADVISEHOLDER iface, IMoniker *pmk) +{ + OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; + FIXME("(%p)->(%p)\n", This, pmk); + + + return S_OK; +} + +/****************************************************************************** + * OleAdviseHolderImpl_SendOnSave + */ +static HRESULT WINAPI +OleAdviseHolderImpl_SendOnSave (LPOLEADVISEHOLDER iface) +{ + OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; + FIXME("(%p)\n", This); + + return S_OK; +} + +/****************************************************************************** + * OleAdviseHolderImpl_SendOnClose + */ +static HRESULT WINAPI +OleAdviseHolderImpl_SendOnClose (LPOLEADVISEHOLDER iface) +{ + OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; + FIXME("(%p)\n", This); + + + return S_OK; +} + +/************************************************************************** + * OleAdviseHolderImpl_VTable + */ +static struct IOleAdviseHolderVtbl oahvt = +{ + OleAdviseHolderImpl_QueryInterface, + OleAdviseHolderImpl_AddRef, + OleAdviseHolderImpl_Release, + OleAdviseHolderImpl_Advise, + OleAdviseHolderImpl_Unadvise, + OleAdviseHolderImpl_EnumAdvise, + OleAdviseHolderImpl_SendOnRename, + OleAdviseHolderImpl_SendOnSave, + OleAdviseHolderImpl_SendOnClose +}; + +/************************************************************************** + * OleAdviseHolderImpl_Constructor + */ + +static LPOLEADVISEHOLDER OleAdviseHolderImpl_Constructor() +{ + OleAdviseHolderImpl* lpoah; + DWORD index; + + lpoah = HeapAlloc(GetProcessHeap(), 0, sizeof(OleAdviseHolderImpl)); + + lpoah->lpVtbl = &oahvt; + lpoah->ref = 1; + lpoah->maxSinks = INITIAL_SINKS; + lpoah->arrayOfSinks = HeapAlloc(GetProcessHeap(), + 0, + lpoah->maxSinks * sizeof(IAdviseSink*)); + + for (index = 0; index < lpoah->maxSinks; index++) + lpoah->arrayOfSinks[index]=0; + + TRACE("returning %p\n", lpoah); + return (LPOLEADVISEHOLDER)lpoah; +} + +/************************************************************************** + * DataAdviseHolder Implementation + */ +typedef struct DataAdviseConnection { + IAdviseSink *sink; + FORMATETC fmat; + DWORD advf; +} DataAdviseConnection; + +typedef struct DataAdviseHolder +{ + IDataAdviseHolderVtbl *lpVtbl; + + DWORD ref; + DWORD maxCons; + DataAdviseConnection* Connections; +} DataAdviseHolder; + +/****************************************************************************** + * DataAdviseHolder_Destructor + */ +static void DataAdviseHolder_Destructor(DataAdviseHolder* ptrToDestroy) +{ + DWORD index; + TRACE("%p\n", ptrToDestroy); + + for (index = 0; index < ptrToDestroy->maxCons; index++) + { + if (ptrToDestroy->Connections[index].sink != NULL) + { + IAdviseSink_Release(ptrToDestroy->Connections[index].sink); + ptrToDestroy->Connections[index].sink = NULL; + } + } + + HeapFree(GetProcessHeap(), 0, ptrToDestroy->Connections); + HeapFree(GetProcessHeap(), 0, ptrToDestroy); +} + +/************************************************************************ + * DataAdviseHolder_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static HRESULT WINAPI DataAdviseHolder_QueryInterface( + IDataAdviseHolder* iface, + REFIID riid, + void** ppvObject) +{ + DataAdviseHolder *This = (DataAdviseHolder *)iface; + TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject); + /* + * Perform a sanity check on the parameters. + */ + if ( (This==0) || (ppvObject==0) ) + return E_INVALIDARG; + + /* + * Initialize the return parameter. + */ + *ppvObject = 0; + + /* + * Compare the riid with the interface IDs implemented by this object. + */ + if ( (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) || + (memcmp(&IID_IDataAdviseHolder, riid, sizeof(IID_IDataAdviseHolder)) == 0) ) + { + *ppvObject = iface; + } + + /* + * Check that we obtained an interface. + */ + if ((*ppvObject)==0) + { + return E_NOINTERFACE; + } + + /* + * Query Interface always increases the reference count by one when it is + * successful. + */ + IUnknown_AddRef((IUnknown*)*ppvObject); + + return S_OK; +} + +/************************************************************************ + * DataAdviseHolder_AddRef (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI DataAdviseHolder_AddRef( + IDataAdviseHolder* iface) +{ + DataAdviseHolder *This = (DataAdviseHolder *)iface; + TRACE("(%p) (ref=%ld)\n", This, This->ref); + return InterlockedIncrement(&This->ref); +} + +/************************************************************************ + * DataAdviseHolder_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI DataAdviseHolder_Release( + IDataAdviseHolder* iface) +{ + DataAdviseHolder *This = (DataAdviseHolder *)iface; + ULONG ref; + TRACE("(%p) (ref=%ld)\n", This, This->ref); + + /* + * Decrease the reference count on this object. + */ + ref = InterlockedDecrement(&This->ref); + + /* + * If the reference count goes down to 0, perform suicide. + */ + if (ref==0) DataAdviseHolder_Destructor(This); + + return ref; +} + +/************************************************************************ + * DataAdviseHolder_Advise + * + */ +static HRESULT WINAPI DataAdviseHolder_Advise( + IDataAdviseHolder* iface, + IDataObject* pDataObject, + FORMATETC* pFetc, + DWORD advf, + IAdviseSink* pAdvise, + DWORD* pdwConnection) +{ + DWORD index; + + DataAdviseHolder *This = (DataAdviseHolder *)iface; + + TRACE("(%p)->(%p, %p, %08lx, %p, %p)\n", This, pDataObject, pFetc, advf, + pAdvise, pdwConnection); + /* + * Sanity check + */ + if (pdwConnection==NULL) + return E_POINTER; + + *pdwConnection = 0; + + /* + * Find a free spot in the array. + */ + for (index = 0; index < This->maxCons; index++) + { + if (This->Connections[index].sink == NULL) + break; + } + + /* + * If the array is full, we need to grow it. + */ + if (index == This->maxCons) + { + This->maxCons+=INITIAL_SINKS; + This->Connections = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + This->Connections, + This->maxCons*sizeof(DataAdviseConnection)); + } + /* + * Store the new sink + */ + This->Connections[index].sink = pAdvise; + memcpy(&(This->Connections[index].fmat), pFetc, sizeof(FORMATETC)); + This->Connections[index].advf = advf; + + if (This->Connections[index].sink != NULL) { + IAdviseSink_AddRef(This->Connections[index].sink); + if(advf & ADVF_PRIMEFIRST) { + IDataAdviseHolder_SendOnDataChange(iface, pDataObject, 0, advf); + } + } + /* + * Return the index as the cookie. + * Since 0 is not a valid cookie, we will increment by + * 1 the index in the table. + */ + *pdwConnection = index+1; + + return S_OK; +} + +/****************************************************************************** + * DataAdviseHolder_Unadvise + */ +static HRESULT WINAPI DataAdviseHolder_Unadvise( + IDataAdviseHolder* iface, + DWORD dwConnection) +{ + DataAdviseHolder *This = (DataAdviseHolder *)iface; + + TRACE("(%p)->(%lu)\n", This, dwConnection); + + /* + * So we don't return 0 as a cookie, the index was + * incremented by 1 in OleAdviseHolderImpl_Advise + * we have to compensate. + */ + dwConnection--; + + /* + * Check for invalid cookies. + */ + if (dwConnection >= This->maxCons) + return OLE_E_NOCONNECTION; + + if (This->Connections[dwConnection].sink == NULL) + return OLE_E_NOCONNECTION; + + /* + * Release the sink and mark the spot in the list as free. + */ + IAdviseSink_Release(This->Connections[dwConnection].sink); + memset(&(This->Connections[dwConnection]), 0, sizeof(DataAdviseConnection)); + return S_OK; +} + +static HRESULT WINAPI DataAdviseHolder_EnumAdvise( + IDataAdviseHolder* iface, + IEnumSTATDATA** ppenumAdvise) +{ + DataAdviseHolder *This = (DataAdviseHolder *)iface; + + FIXME("(%p)->(%p)\n", This, ppenumAdvise); + return E_NOTIMPL; +} + +/****************************************************************************** + * DataAdviseHolder_SendOnDataChange + */ +static HRESULT WINAPI DataAdviseHolder_SendOnDataChange( + IDataAdviseHolder* iface, + IDataObject* pDataObject, + DWORD dwReserved, + DWORD advf) +{ + DataAdviseHolder *This = (DataAdviseHolder *)iface; + DWORD index; + STGMEDIUM stg; + HRESULT res; + + TRACE("(%p)->(%p,%08lx,%08lx)\n", This, pDataObject, dwReserved, advf); + + for(index = 0; index < This->maxCons; index++) { + if(This->Connections[index].sink != NULL) { + if(!(This->Connections[index].advf & ADVF_NODATA)) { + TRACE("Calling IDataObject_GetData\n"); + res = IDataObject_GetData(pDataObject, + &(This->Connections[index].fmat), + &stg); + TRACE("returns %08lx\n", res); + } + TRACE("Calling IAdviseSink_OnDataChange\n"); + IAdviseSink_OnDataChange(This->Connections[index].sink, + &(This->Connections[index].fmat), + &stg); + TRACE("Done IAdviseSink_OnDataChange\n"); + if(This->Connections[index].advf & ADVF_ONLYONCE) { + TRACE("Removing connection\n"); + DataAdviseHolder_Unadvise(iface, index+1); + } + } + } + return S_OK; +} + +/************************************************************************** + * DataAdviseHolderImpl_VTable + */ +static struct IDataAdviseHolderVtbl DataAdviseHolderImpl_VTable = +{ + DataAdviseHolder_QueryInterface, + DataAdviseHolder_AddRef, + DataAdviseHolder_Release, + DataAdviseHolder_Advise, + DataAdviseHolder_Unadvise, + DataAdviseHolder_EnumAdvise, + DataAdviseHolder_SendOnDataChange +}; + +/****************************************************************************** + * DataAdviseHolder_Constructor + */ +static IDataAdviseHolder* DataAdviseHolder_Constructor() +{ + DataAdviseHolder* newHolder; + + newHolder = HeapAlloc(GetProcessHeap(), 0, sizeof(DataAdviseHolder)); + + newHolder->lpVtbl = &DataAdviseHolderImpl_VTable; + newHolder->ref = 1; + newHolder->maxCons = INITIAL_SINKS; + newHolder->Connections = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + newHolder->maxCons * + sizeof(DataAdviseConnection)); + + TRACE("returning %p\n", newHolder); + return (IDataAdviseHolder*)newHolder; +} + +/*********************************************************************** + * API functions + */ + +/*********************************************************************** + * CreateOleAdviseHolder [OLE32.@] + */ +HRESULT WINAPI CreateOleAdviseHolder( + LPOLEADVISEHOLDER *ppOAHolder) +{ + TRACE("(%p)\n", ppOAHolder); + + /* + * Sanity check, + */ + if (ppOAHolder==NULL) + return E_POINTER; + + *ppOAHolder = OleAdviseHolderImpl_Constructor (); + + if (*ppOAHolder != NULL) + return S_OK; + + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * CreateDataAdviseHolder [OLE32.@] + */ +HRESULT WINAPI CreateDataAdviseHolder( + LPDATAADVISEHOLDER* ppDAHolder) +{ + TRACE("(%p)\n", ppDAHolder); + + /* + * Sanity check, + */ + if (ppDAHolder==NULL) + return E_POINTER; + + *ppDAHolder = DataAdviseHolder_Constructor(); + + if (*ppDAHolder != NULL) + return S_OK; + + return E_OUTOFMEMORY; +} diff --git a/reactos/lib/ole32/oleproxy.c b/reactos/lib/ole32/oleproxy.c index 014875e8873..e647a514f3c 100644 --- a/reactos/lib/ole32/oleproxy.c +++ b/reactos/lib/ole32/oleproxy.c @@ -1,993 +1,993 @@ -/* - * OLE32 proxy/stub handler - * - * Copyright 2002 Marcus Meissner - * Copyright 2001 Ove Kåven, TransGaming Technologies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* Documentation on MSDN: - * - * (Top level COM documentation) - * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnanchor/html/componentdevelopmentank.asp - * - * (COM Proxy) - * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/comext_1q0p.asp - * - * (COM Stub) - * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/comext_1lia.asp - * - * (Marshal) - * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/comext_1gfn.asp - * - */ - -#include "config.h" - -#include <stdlib.h> -#include <stdarg.h> -#include <stddef.h> -#include <stdio.h> -#include <string.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#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 "wtypes.h" - -#include "compobj_private.h" -#include "moniker.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -const CLSID CLSID_DfMarshal = { 0x0000030b, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} }; -const CLSID CLSID_PSFactoryBuffer = { 0x00000320, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} }; - -/* From: http://msdn.microsoft.com/library/en-us/com/cmi_m_4lda.asp - * - * The first time a client requests a pointer to an interface on a - * particular object, COM loads an IClassFactory stub in the server - * process and uses it to marshal the first pointer back to the - * client. In the client process, COM loads the generic proxy for the - * class factory object and calls its implementation of IMarshal to - * unmarshal that first pointer. COM then creates the first interface - * proxy and hands it a pointer to the RPC channel. Finally, COM returns - * the IClassFactory pointer to the client, which uses it to call - * IClassFactory::CreateInstance, passing it a reference to the interface. - * - * Back in the server process, COM now creates a new instance of the - * object, along with a stub for the requested interface. This stub marshals - * the interface pointer back to the client process, where another object - * proxy is created, this time for the object itself. Also created is a - * proxy for the requested interface, a pointer to which is returned to - * the client. With subsequent calls to other interfaces on the object, - * COM will load the appropriate interface stubs and proxies as needed. - */ -typedef struct _CFStub { - IRpcStubBufferVtbl *lpvtbl; - DWORD ref; - - LPUNKNOWN pUnkServer; -} CFStub; - -static HRESULT WINAPI -CFStub_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv) { - if (IsEqualIID(&IID_IUnknown,riid)||IsEqualIID(&IID_IRpcStubBuffer,riid)) { - *ppv = (LPVOID)iface; - IUnknown_AddRef(iface); - return S_OK; - } - FIXME("(%s), interface not supported.\n",debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI -CFStub_AddRef(LPRPCSTUBBUFFER iface) { - CFStub *This = (CFStub *)iface; - return InterlockedIncrement(&This->ref); -} - -static ULONG WINAPI -CFStub_Release(LPRPCSTUBBUFFER iface) { - CFStub *This = (CFStub *)iface; - ULONG ref; - - ref = InterlockedDecrement(&This->ref); - if (!ref) HeapFree(GetProcessHeap(),0,This); - return ref; -} - -static HRESULT WINAPI -CFStub_Connect(LPRPCSTUBBUFFER iface, IUnknown *pUnkServer) { - CFStub *This = (CFStub *)iface; - - This->pUnkServer = pUnkServer; - IUnknown_AddRef(pUnkServer); - return S_OK; -} - -static void WINAPI -CFStub_Disconnect(LPRPCSTUBBUFFER iface) { - CFStub *This = (CFStub *)iface; - - IUnknown_Release(This->pUnkServer); - This->pUnkServer = NULL; -} -static HRESULT WINAPI -CFStub_Invoke( - LPRPCSTUBBUFFER iface,RPCOLEMESSAGE* msg,IRpcChannelBuffer* chanbuf -) { - CFStub *This = (CFStub *)iface; - HRESULT hres; - - if (msg->iMethod == 3) { /* CreateInstance */ - IID iid; - IClassFactory *classfac; - IUnknown *ppv; - IStream *pStm; - STATSTG ststg; - ULARGE_INTEGER newpos; - LARGE_INTEGER seekto; - ULONG res; - - if (msg->cbBuffer < sizeof(IID)) { - FIXME("Not enough bytes in buffer (%ld instead of %d)?\n",msg->cbBuffer,sizeof(IID)); - return E_FAIL; - } - memcpy(&iid,msg->Buffer,sizeof(iid)); - TRACE("->CreateInstance(%s)\n",debugstr_guid(&iid)); - hres = IUnknown_QueryInterface(This->pUnkServer,&IID_IClassFactory,(LPVOID*)&classfac); - if (hres) { - FIXME("Ole server does not provide an IClassFactory?\n"); - return hres; - } - hres = IClassFactory_CreateInstance(classfac,NULL,&iid,(LPVOID*)&ppv); - IClassFactory_Release(classfac); - if (hres) { - msg->cbBuffer = 0; - FIXME("Failed to create an instance of %s\n",debugstr_guid(&iid)); - return hres; - } - hres = CreateStreamOnHGlobal(0,TRUE,&pStm); - if (hres) { - FIXME("Failed to create stream on hglobal\n"); - return hres; - } - hres = CoMarshalInterface(pStm,&iid,ppv,0,NULL,0); - IUnknown_Release((IUnknown*)ppv); - if (hres) { - FIXME("CoMarshalInterface failed, %lx!\n",hres); - msg->cbBuffer = 0; - return hres; - } - hres = IStream_Stat(pStm,&ststg,0); - if (hres) { - FIXME("Stat failed.\n"); - return hres; - } - - msg->cbBuffer = ststg.cbSize.u.LowPart; - - I_RpcGetBuffer((RPC_MESSAGE *)msg); - if (hres) return hres; - - seekto.u.LowPart = 0;seekto.u.HighPart = 0; - hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); - if (hres) { - FIXME("IStream_Seek failed, %lx\n",hres); - return hres; - } - hres = IStream_Read(pStm,msg->Buffer,msg->cbBuffer,&res); - if (hres) { - FIXME("Stream Read failed, %lx\n",hres); - return hres; - } - IStream_Release(pStm); - return S_OK; - } - FIXME("(%p,%p), stub!\n",msg,chanbuf); - FIXME("iMethod is %ld\n",msg->iMethod); - FIXME("cbBuffer is %ld\n",msg->cbBuffer); - return E_FAIL; -} - -static LPRPCSTUBBUFFER WINAPI -CFStub_IsIIDSupported(LPRPCSTUBBUFFER iface,REFIID riid) { - FIXME("(%s), stub!\n",debugstr_guid(riid)); - return NULL; -} - -static ULONG WINAPI -CFStub_CountRefs(LPRPCSTUBBUFFER iface) { - FIXME("(), stub!\n"); - return 1; -} - -static HRESULT WINAPI -CFStub_DebugServerQueryInterface(LPRPCSTUBBUFFER iface,void** ppv) { - FIXME("(%p), stub!\n",ppv); - return E_FAIL; -} -static void WINAPI -CFStub_DebugServerRelease(LPRPCSTUBBUFFER iface,void *pv) { - FIXME("(%p), stub!\n",pv); -} - -static IRpcStubBufferVtbl cfstubvt = { - CFStub_QueryInterface, - CFStub_AddRef, - CFStub_Release, - CFStub_Connect, - CFStub_Disconnect, - CFStub_Invoke, - CFStub_IsIIDSupported, - CFStub_CountRefs, - CFStub_DebugServerQueryInterface, - CFStub_DebugServerRelease -}; - -static HRESULT -CFStub_Construct(LPRPCSTUBBUFFER *ppv) { - CFStub *cfstub; - cfstub = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFStub)); - if (!cfstub) - return E_OUTOFMEMORY; - *ppv = (LPRPCSTUBBUFFER)cfstub; - cfstub->lpvtbl = &cfstubvt; - cfstub->ref = 1; - return S_OK; -} - -/* Since we create proxy buffers and classfactory in a pair, there is - * no need for 2 separate structs. Just put them in one, but remember - * the refcount. - */ -typedef struct _CFProxy { - const IClassFactoryVtbl *lpvtbl_cf; - const IRpcProxyBufferVtbl *lpvtbl_proxy; - DWORD ref; - - IRpcChannelBuffer *chanbuf; - IUnknown *outer_unknown; -} CFProxy; - -static HRESULT WINAPI IRpcProxyBufferImpl_QueryInterface(LPRPCPROXYBUFFER iface,REFIID riid,LPVOID *ppv) { - *ppv = NULL; - if (IsEqualIID(riid,&IID_IRpcProxyBuffer)||IsEqualIID(riid,&IID_IUnknown)) { - IRpcProxyBuffer_AddRef(iface); - *ppv = (LPVOID)iface; - return S_OK; - } - FIXME("(%s), no interface.\n",debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI IRpcProxyBufferImpl_AddRef(LPRPCPROXYBUFFER iface) { - ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface); - return InterlockedIncrement(&This->ref); -} - -static ULONG WINAPI IRpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface) { - ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface); - ULONG ref = InterlockedDecrement(&This->ref); - - if (!ref) { - IRpcChannelBuffer_Release(This->chanbuf);This->chanbuf = NULL; - HeapFree(GetProcessHeap(),0,This); - } - return ref; -} - -static HRESULT WINAPI IRpcProxyBufferImpl_Connect(LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer) { - ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface); - - This->chanbuf = pRpcChannelBuffer; - IRpcChannelBuffer_AddRef(This->chanbuf); - return S_OK; -} -static void WINAPI IRpcProxyBufferImpl_Disconnect(LPRPCPROXYBUFFER iface) { - ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface); - if (This->chanbuf) { - IRpcChannelBuffer_Release(This->chanbuf); - This->chanbuf = NULL; - } -} - -static HRESULT WINAPI -CFProxy_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) { - ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface); - if (This->outer_unknown) return IUnknown_QueryInterface(This->outer_unknown, riid, ppv); - *ppv = NULL; - if (IsEqualIID(&IID_IClassFactory,riid) || IsEqualIID(&IID_IUnknown,riid)) { - *ppv = (LPVOID)iface; - IClassFactory_AddRef(iface); - return S_OK; - } - if (IsEqualIID(riid,&IID_IMarshal)) /* just to avoid debug output */ - return E_NOINTERFACE; - FIXME("Unhandled interface: %s\n",debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI CFProxy_AddRef(LPCLASSFACTORY iface) { - ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface); - if (This->outer_unknown) return IUnknown_AddRef(This->outer_unknown); - return InterlockedIncrement(&This->ref); -} - -static ULONG WINAPI CFProxy_Release(LPCLASSFACTORY iface) { - ULONG ref; - ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface); - if (This->outer_unknown) - ref = IUnknown_Release(This->outer_unknown); - else - ref = InterlockedDecrement(&This->ref); - - if (!ref) { - if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf); - HeapFree(GetProcessHeap(),0,This); - } - return ref; -} - -static HRESULT WINAPI CFProxy_CreateInstance( - LPCLASSFACTORY iface, - LPUNKNOWN pUnkOuter,/* [in] */ - REFIID riid, /* [in] */ - LPVOID *ppv /* [out] */ -) { - ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface); - HRESULT hres; - LPSTREAM pStream; - HGLOBAL hGlobal; - ULONG srstatus; - RPCOLEMESSAGE msg; - - TRACE("(%p,%s,%p)\n",pUnkOuter,debugstr_guid(riid),ppv); - - /* Send CreateInstance to the remote classfactory. - * - * Data: Only the 'IID'. - */ - msg.iMethod = 3; - msg.cbBuffer = sizeof(*riid); - msg.Buffer = NULL; - hres = IRpcChannelBuffer_GetBuffer(This->chanbuf,&msg,&IID_IClassFactory); - if (hres) { - FIXME("IRpcChannelBuffer_GetBuffer failed with %lx?\n",hres); - return hres; - } - memcpy(msg.Buffer,riid,sizeof(*riid)); - hres = IRpcChannelBuffer_SendReceive(This->chanbuf,&msg,&srstatus); - if (hres) { - FIXME("IRpcChannelBuffer_SendReceive failed with %lx?\n",hres); - return hres; - } - - if (!msg.cbBuffer) /* interface not found on remote */ - return srstatus; - - /* We got back: [Marshalled Interface data] */ - TRACE("got %ld bytes data.\n",msg.cbBuffer); - hGlobal = GlobalAlloc(GMEM_MOVEABLE|GMEM_NODISCARD|GMEM_SHARE,msg.cbBuffer); - memcpy(GlobalLock(hGlobal),msg.Buffer,msg.cbBuffer); - hres = CreateStreamOnHGlobal(hGlobal,TRUE,&pStream); - if (hres) { - FIXME("CreateStreamOnHGlobal failed with %lx\n",hres); - return hres; - } - hres = CoUnmarshalInterface( - pStream, - riid, - ppv - ); - IStream_Release(pStream); /* Does GlobalFree hGlobal too. */ - if (hres) { - FIXME("CoMarshalInterface failed, %lx\n",hres); - return hres; - } - return S_OK; -} - -static HRESULT WINAPI CFProxy_LockServer(LPCLASSFACTORY iface,BOOL fLock) { - /*ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);*/ - FIXME("(%d), stub!\n",fLock); - /* basically: write BOOL, read empty */ - return S_OK; -} - -static IRpcProxyBufferVtbl pspbvtbl = { - IRpcProxyBufferImpl_QueryInterface, - IRpcProxyBufferImpl_AddRef, - IRpcProxyBufferImpl_Release, - IRpcProxyBufferImpl_Connect, - IRpcProxyBufferImpl_Disconnect -}; -static IClassFactoryVtbl cfproxyvt = { - CFProxy_QueryInterface, - CFProxy_AddRef, - CFProxy_Release, - CFProxy_CreateInstance, - CFProxy_LockServer -}; - -static HRESULT -CFProxy_Construct(IUnknown *pUnkOuter, LPVOID *ppv,LPVOID *ppProxy) { - CFProxy *cf; - - cf = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFProxy)); - if (!cf) - return E_OUTOFMEMORY; - - cf->lpvtbl_cf = &cfproxyvt; - cf->lpvtbl_proxy = &pspbvtbl; - /* only one reference for the proxy buffer */ - cf->ref = 1; - cf->outer_unknown = pUnkOuter; - *ppv = &(cf->lpvtbl_cf); - *ppProxy = &(cf->lpvtbl_proxy); - return S_OK; -} - - -/********************* IRemUnknown Proxy/Stub ********************************/ - -typedef struct -{ - const IRpcStubBufferVtbl *lpVtbl; - ULONG refs; - IRemUnknown *iface; -} RemUnkStub; - -static HRESULT WINAPI RemUnkStub_QueryInterface(LPRPCSTUBBUFFER iface, - REFIID riid, - LPVOID *obj) -{ - RemUnkStub *This = (RemUnkStub *)iface; - TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(riid),obj); - if (IsEqualGUID(&IID_IUnknown,riid) || - IsEqualGUID(&IID_IRpcStubBuffer,riid)) { - *obj = This; - return S_OK; - } - return E_NOINTERFACE; -} - -static ULONG WINAPI RemUnkStub_AddRef(LPRPCSTUBBUFFER iface) -{ - RemUnkStub *This = (RemUnkStub *)iface; - TRACE("(%p)->AddRef()\n",This); - return InterlockedIncrement(&This->refs); -} - -static ULONG WINAPI RemUnkStub_Release(LPRPCSTUBBUFFER iface) -{ - RemUnkStub *This = (RemUnkStub *)iface; - ULONG refs; - TRACE("(%p)->Release()\n",This); - refs = InterlockedDecrement(&This->refs); - if (!refs) - HeapFree(GetProcessHeap(), 0, This); - return refs; -} - -static HRESULT WINAPI RemUnkStub_Connect(LPRPCSTUBBUFFER iface, - LPUNKNOWN lpUnkServer) -{ - RemUnkStub *This = (RemUnkStub *)iface; - TRACE("(%p)->Connect(%p)\n",This,lpUnkServer); - This->iface = (IRemUnknown*)lpUnkServer; - IRemUnknown_AddRef(This->iface); - return S_OK; -} - -static void WINAPI RemUnkStub_Disconnect(LPRPCSTUBBUFFER iface) -{ - RemUnkStub *This = (RemUnkStub *)iface; - TRACE("(%p)->Disconnect()\n",This); - IUnknown_Release(This->iface); - This->iface = NULL; -} - -static HRESULT WINAPI RemUnkStub_Invoke(LPRPCSTUBBUFFER iface, - PRPCOLEMESSAGE pMsg, - LPRPCCHANNELBUFFER pChannel) -{ - RemUnkStub *This = (RemUnkStub *)iface; - ULONG iMethod = pMsg->iMethod; - LPBYTE buf = pMsg->Buffer; - HRESULT hr = RPC_E_INVALIDMETHOD; - - TRACE("(%p)->Invoke(%p,%p) method %ld\n", This, pMsg, pChannel, iMethod); - switch (iMethod) - { - case 3: /* RemQueryInterface */ - { - IPID ipid; - ULONG cRefs; - USHORT cIids; - IID *iids; - REMQIRESULT *pQIResults = NULL; - - /* in */ - memcpy(&ipid, buf, sizeof(ipid)); - buf += sizeof(ipid); - memcpy(&cRefs, buf, sizeof(cRefs)); - buf += sizeof(cRefs); - memcpy(&cIids, buf, sizeof(cIids)); - buf += sizeof(cIids); - iids = (IID *)buf; - - hr = IRemUnknown_RemQueryInterface(This->iface, &ipid, cRefs, cIids, iids, &pQIResults); - - /* out */ - pMsg->cbBuffer = cIids * sizeof(REMQIRESULT); - - I_RpcGetBuffer((RPC_MESSAGE *)pMsg); - if (hr) return hr; - - buf = pMsg->Buffer; - /* FIXME: pQIResults is a unique pointer so pQIResults can be NULL! */ - memcpy(buf, pQIResults, cIids * sizeof(REMQIRESULT)); - - break; - } - case 4: /* RemAddRef */ - { - USHORT cIids; - REMINTERFACEREF *ir; - HRESULT *pResults; - - /* in */ - memcpy(&cIids, buf, sizeof(USHORT)); - buf += sizeof(USHORT); - ir = (REMINTERFACEREF*)buf; - pResults = CoTaskMemAlloc(cIids * sizeof(HRESULT)); - if (!pResults) return E_OUTOFMEMORY; - - hr = IRemUnknown_RemAddRef(This->iface, cIids, ir, pResults); - - /* out */ - pMsg->cbBuffer = cIids * sizeof(HRESULT); - - I_RpcGetBuffer((RPC_MESSAGE *)pMsg); - if (!hr) - { - buf = pMsg->Buffer; - memcpy(buf, pResults, cIids * sizeof(HRESULT)); - } - - CoTaskMemFree(pResults); - - break; - } - case 5: /* RemRelease */ - { - USHORT cIids; - REMINTERFACEREF *ir; - - /* in */ - memcpy(&cIids, buf, sizeof(USHORT)); - buf += sizeof(USHORT); - ir = (REMINTERFACEREF*)buf; - - hr = IRemUnknown_RemRelease(This->iface, cIids, ir); - - /* out */ - pMsg->cbBuffer = 0; - break; - } - } - return hr; -} - -static LPRPCSTUBBUFFER WINAPI RemUnkStub_IsIIDSupported(LPRPCSTUBBUFFER iface, - REFIID riid) -{ - RemUnkStub *This = (RemUnkStub *)iface; - TRACE("(%p)->IsIIDSupported(%s)\n", This, debugstr_guid(riid)); - return IsEqualGUID(&IID_IRemUnknown, riid) ? iface : NULL; -} - -static ULONG WINAPI RemUnkStub_CountRefs(LPRPCSTUBBUFFER iface) -{ - RemUnkStub *This = (RemUnkStub *)iface; - FIXME("(%p)->CountRefs()\n", This); - return 1; -} - -static HRESULT WINAPI RemUnkStub_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, - LPVOID *ppv) -{ - RemUnkStub *This = (RemUnkStub *)iface; - FIXME("(%p)->DebugServerQueryInterface(%p)\n",This,ppv); - return E_NOINTERFACE; -} - -static void WINAPI RemUnkStub_DebugServerRelease(LPRPCSTUBBUFFER iface, - LPVOID pv) -{ - RemUnkStub *This = (RemUnkStub *)iface; - FIXME("(%p)->DebugServerRelease(%p)\n", This, pv); -} - -static const IRpcStubBufferVtbl RemUnkStub_VTable = -{ - RemUnkStub_QueryInterface, - RemUnkStub_AddRef, - RemUnkStub_Release, - RemUnkStub_Connect, - RemUnkStub_Disconnect, - RemUnkStub_Invoke, - RemUnkStub_IsIIDSupported, - RemUnkStub_CountRefs, - RemUnkStub_DebugServerQueryInterface, - RemUnkStub_DebugServerRelease -}; - -static HRESULT RemUnkStub_Construct(IRpcStubBuffer **ppStub) -{ - RemUnkStub *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); - if (!This) return E_OUTOFMEMORY; - This->lpVtbl = &RemUnkStub_VTable; - This->refs = 0; - This->iface = NULL; - *ppStub = (IRpcStubBuffer*)This; - return S_OK; -} - - -typedef struct _RemUnkProxy { - const IRemUnknownVtbl *lpvtbl_remunk; - const IRpcProxyBufferVtbl *lpvtbl_proxy; - DWORD refs; - - IRpcChannelBuffer *chan; - IUnknown *outer_unknown; -} RemUnkProxy; - -static HRESULT WINAPI RemUnkProxy_QueryInterface(LPREMUNKNOWN iface, REFIID riid, void **ppv) -{ - RemUnkProxy *This = (RemUnkProxy *)iface; - if (This->outer_unknown) - return IUnknown_QueryInterface(This->outer_unknown, riid, ppv); - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IRemUnknown)) - { - IRemUnknown_AddRef(iface); - *ppv = (LPVOID)iface; - return S_OK; - } - return E_NOINTERFACE; -} - -static ULONG WINAPI RemUnkProxy_AddRef(LPREMUNKNOWN iface) -{ - RemUnkProxy *This = (RemUnkProxy *)iface; - - TRACE("(%p)->AddRef()\n",This); - return InterlockedIncrement(&This->refs); -} - -static ULONG WINAPI RemUnkProxy_Release(LPREMUNKNOWN iface) -{ - RemUnkProxy *This = (RemUnkProxy *)iface; - ULONG refs; - - TRACE("(%p)->Release()\n",This); - if (This->outer_unknown) - refs = IUnknown_Release(This->outer_unknown); - else - refs = InterlockedDecrement(&This->refs); - - if (!refs) { - if (This->chan) IRpcChannelBuffer_Release(This->chan); - HeapFree(GetProcessHeap(),0,This); - } - return refs; -} - -static HRESULT WINAPI RemUnkProxy_RemQueryInterface(LPREMUNKNOWN iface, - REFIPID ripid, - ULONG cRefs, - USHORT cIids, - IID* iids, - REMQIRESULT** ppQIResults) -{ - RemUnkProxy *This = (RemUnkProxy *)iface; - RPCOLEMESSAGE msg; - HRESULT hr = S_OK; - ULONG status; - - TRACE("(%p)->(%s,%ld,%d,%p,%p)\n",This, - debugstr_guid(ripid),cRefs,cIids,iids,ppQIResults); - - *ppQIResults = NULL; - memset(&msg, 0, sizeof(msg)); - msg.iMethod = 3; - msg.cbBuffer = sizeof(IPID) + sizeof(ULONG) + - sizeof(USHORT) + cIids*sizeof(IID); - hr = IRpcChannelBuffer_GetBuffer(This->chan, &msg, &IID_IRemUnknown); - if (SUCCEEDED(hr)) { - LPBYTE buf = msg.Buffer; - memcpy(buf, ripid, sizeof(IPID)); - buf += sizeof(IPID); - memcpy(buf, &cRefs, sizeof(ULONG)); - buf += sizeof(ULONG); - memcpy(buf, &cIids, sizeof(USHORT)); - buf += sizeof(USHORT); - memcpy(buf, iids, cIids*sizeof(IID)); - - hr = IRpcChannelBuffer_SendReceive(This->chan, &msg, &status); - - if (SUCCEEDED(hr)) { - buf = msg.Buffer; - *ppQIResults = CoTaskMemAlloc(cIids*sizeof(REMQIRESULT)); - memcpy(*ppQIResults, buf, cIids*sizeof(REMQIRESULT)); - } - - IRpcChannelBuffer_FreeBuffer(This->chan, &msg); - } - - return hr; -} - -static HRESULT WINAPI RemUnkProxy_RemAddRef(LPREMUNKNOWN iface, - USHORT cInterfaceRefs, - REMINTERFACEREF* InterfaceRefs, - HRESULT* pResults) -{ - RemUnkProxy *This = (RemUnkProxy *)iface; - RPCOLEMESSAGE msg; - HRESULT hr = S_OK; - ULONG status; - - TRACE("(%p)->(%d,%p,%p)\n",This, - cInterfaceRefs,InterfaceRefs,pResults); - - memset(&msg, 0, sizeof(msg)); - msg.iMethod = 4; - msg.cbBuffer = sizeof(USHORT) + cInterfaceRefs*sizeof(REMINTERFACEREF); - hr = IRpcChannelBuffer_GetBuffer(This->chan, &msg, &IID_IRemUnknown); - if (SUCCEEDED(hr)) { - LPBYTE buf = msg.Buffer; - memcpy(buf, &cInterfaceRefs, sizeof(USHORT)); - buf += sizeof(USHORT); - memcpy(buf, InterfaceRefs, cInterfaceRefs*sizeof(REMINTERFACEREF)); - - hr = IRpcChannelBuffer_SendReceive(This->chan, &msg, &status); - - if (SUCCEEDED(hr)) { - buf = msg.Buffer; - memcpy(pResults, buf, cInterfaceRefs*sizeof(HRESULT)); - } - - IRpcChannelBuffer_FreeBuffer(This->chan, &msg); - } - - return hr; -} - -static HRESULT WINAPI RemUnkProxy_RemRelease(LPREMUNKNOWN iface, - USHORT cInterfaceRefs, - REMINTERFACEREF* InterfaceRefs) -{ - RemUnkProxy *This = (RemUnkProxy *)iface; - RPCOLEMESSAGE msg; - HRESULT hr = S_OK; - ULONG status; - - TRACE("(%p)->(%d,%p)\n",This, - cInterfaceRefs,InterfaceRefs); - - memset(&msg, 0, sizeof(msg)); - msg.iMethod = 5; - msg.cbBuffer = sizeof(USHORT) + cInterfaceRefs*sizeof(REMINTERFACEREF); - hr = IRpcChannelBuffer_GetBuffer(This->chan, &msg, &IID_IRemUnknown); - if (SUCCEEDED(hr)) { - LPBYTE buf = msg.Buffer; - memcpy(buf, &cInterfaceRefs, sizeof(USHORT)); - buf += sizeof(USHORT); - memcpy(buf, InterfaceRefs, cInterfaceRefs*sizeof(REMINTERFACEREF)); - - hr = IRpcChannelBuffer_SendReceive(This->chan, &msg, &status); - - IRpcChannelBuffer_FreeBuffer(This->chan, &msg); - } - - return hr; -} - -static const IRemUnknownVtbl RemUnkProxy_VTable = -{ - RemUnkProxy_QueryInterface, - RemUnkProxy_AddRef, - RemUnkProxy_Release, - RemUnkProxy_RemQueryInterface, - RemUnkProxy_RemAddRef, - RemUnkProxy_RemRelease -}; - - -static HRESULT WINAPI RURpcProxyBufferImpl_QueryInterface(LPRPCPROXYBUFFER iface,REFIID riid,LPVOID *ppv) { - *ppv = NULL; - if (IsEqualIID(riid,&IID_IRpcProxyBuffer)||IsEqualIID(riid,&IID_IUnknown)) { - IRpcProxyBuffer_AddRef(iface); - *ppv = (LPVOID)iface; - return S_OK; - } - FIXME("(%s), no interface.\n",debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI RURpcProxyBufferImpl_AddRef(LPRPCPROXYBUFFER iface) { - ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface); - return InterlockedIncrement(&This->refs); -} - -static ULONG WINAPI RURpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface) { - ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface); - ULONG ref = InterlockedDecrement(&This->refs); - - if (!ref) { - IRpcChannelBuffer_Release(This->chan);This->chan = NULL; - HeapFree(GetProcessHeap(),0,This); - } - return ref; -} - -static HRESULT WINAPI RURpcProxyBufferImpl_Connect(LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer) { - ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface); - - This->chan = pRpcChannelBuffer; - IRpcChannelBuffer_AddRef(This->chan); - return S_OK; -} -static void WINAPI RURpcProxyBufferImpl_Disconnect(LPRPCPROXYBUFFER iface) { - ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface); - if (This->chan) { - IRpcChannelBuffer_Release(This->chan); - This->chan = NULL; - } -} - - -static const IRpcProxyBufferVtbl RURpcProxyBuffer_VTable = { - RURpcProxyBufferImpl_QueryInterface, - RURpcProxyBufferImpl_AddRef, - RURpcProxyBufferImpl_Release, - RURpcProxyBufferImpl_Connect, - RURpcProxyBufferImpl_Disconnect -}; - -static HRESULT -RemUnkProxy_Construct(IUnknown *pUnkOuter, LPVOID *ppv,LPVOID *ppProxy) { - RemUnkProxy *This; - - This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*This)); - if (!This) - return E_OUTOFMEMORY; - - This->lpvtbl_remunk = &RemUnkProxy_VTable; - This->lpvtbl_proxy = &RURpcProxyBuffer_VTable; - /* only one reference for the proxy buffer */ - This->refs = 1; - This->outer_unknown = pUnkOuter; - *ppv = &(This->lpvtbl_remunk); - *ppProxy = &(This->lpvtbl_proxy); - return S_OK; -} - - -/********************* OLE Proxy/Stub Factory ********************************/ -static HRESULT WINAPI -PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) { - if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) { - *ppv = (LPVOID)iface; - /* No ref counting, static class */ - return S_OK; - } - FIXME("(%s) unknown IID?\n",debugstr_guid(iid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; } -static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; } - -static HRESULT WINAPI -PSFacBuf_CreateProxy( - LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid, - IRpcProxyBuffer **ppProxy, LPVOID *ppv -) { - if (IsEqualIID(&IID_IClassFactory,riid)) - return CFProxy_Construct(pUnkOuter, ppv,(LPVOID*)ppProxy); - else if (IsEqualIID(&IID_IRemUnknown,riid)) - return RemUnkProxy_Construct(pUnkOuter, ppv,(LPVOID*)ppProxy); - FIXME("proxying not implemented for (%s) yet!\n",debugstr_guid(riid)); - return E_FAIL; -} - -static HRESULT WINAPI -PSFacBuf_CreateStub( - LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer, - IRpcStubBuffer** ppStub -) { - HRESULT hres; - - TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub); - - if (IsEqualIID(&IID_IClassFactory, riid) || - IsEqualIID(&IID_IUnknown, riid) /* FIXME: fixup stub manager and remove this*/) { - hres = CFStub_Construct(ppStub); - if (!hres) - IRpcStubBuffer_Connect((*ppStub),pUnkServer); - return hres; - } else if (IsEqualIID(&IID_IRemUnknown,riid)) { - hres = RemUnkStub_Construct(ppStub); - if (!hres) - IRpcStubBuffer_Connect((*ppStub),pUnkServer); - return hres; - } - FIXME("stubbing not implemented for (%s) yet!\n",debugstr_guid(riid)); - return E_FAIL; -} - -static IPSFactoryBufferVtbl psfacbufvtbl = { - PSFacBuf_QueryInterface, - PSFacBuf_AddRef, - PSFacBuf_Release, - PSFacBuf_CreateProxy, - PSFacBuf_CreateStub -}; - -/* This is the whole PSFactoryBuffer object, just the vtableptr */ -static IPSFactoryBufferVtbl *lppsfac = &psfacbufvtbl; - -/*********************************************************************** - * DllGetClassObject [OLE32.@] - */ -HRESULT WINAPI OLE32_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv) -{ - *ppv = NULL; - if (IsEqualIID(rclsid, &CLSID_PSFactoryBuffer)) - return IPSFactoryBuffer_QueryInterface((IPSFactoryBuffer *)&lppsfac, iid, ppv); - if (IsEqualIID(rclsid,&CLSID_DfMarshal)&&( - IsEqualIID(iid,&IID_IClassFactory) || - IsEqualIID(iid,&IID_IUnknown) - ) - ) - return MARSHAL_GetStandardMarshalCF(ppv); - if (IsEqualIID(rclsid,&CLSID_StdGlobalInterfaceTable) && (IsEqualIID(iid,&IID_IClassFactory) || IsEqualIID(iid,&IID_IUnknown))) - return StdGlobalInterfaceTable_GetFactory(ppv); - if (IsEqualCLSID(rclsid, &CLSID_FileMoniker)) - return FileMonikerCF_Create(iid, ppv); - if (IsEqualCLSID(rclsid, &CLSID_ItemMoniker)) - return ItemMonikerCF_Create(iid, ppv); - - FIXME("\n\tCLSID:\t%s,\n\tIID:\t%s\n",debugstr_guid(rclsid),debugstr_guid(iid)); - return CLASS_E_CLASSNOTAVAILABLE; -} +/* + * OLE32 proxy/stub handler + * + * Copyright 2002 Marcus Meissner + * Copyright 2001 Ove Kåven, TransGaming Technologies + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Documentation on MSDN: + * + * (Top level COM documentation) + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnanchor/html/componentdevelopmentank.asp + * + * (COM Proxy) + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/comext_1q0p.asp + * + * (COM Stub) + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/comext_1lia.asp + * + * (Marshal) + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/comext_1gfn.asp + * + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#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 "wtypes.h" + +#include "compobj_private.h" +#include "moniker.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +const CLSID CLSID_DfMarshal = { 0x0000030b, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} }; +const CLSID CLSID_PSFactoryBuffer = { 0x00000320, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} }; + +/* From: http://msdn.microsoft.com/library/en-us/com/cmi_m_4lda.asp + * + * The first time a client requests a pointer to an interface on a + * particular object, COM loads an IClassFactory stub in the server + * process and uses it to marshal the first pointer back to the + * client. In the client process, COM loads the generic proxy for the + * class factory object and calls its implementation of IMarshal to + * unmarshal that first pointer. COM then creates the first interface + * proxy and hands it a pointer to the RPC channel. Finally, COM returns + * the IClassFactory pointer to the client, which uses it to call + * IClassFactory::CreateInstance, passing it a reference to the interface. + * + * Back in the server process, COM now creates a new instance of the + * object, along with a stub for the requested interface. This stub marshals + * the interface pointer back to the client process, where another object + * proxy is created, this time for the object itself. Also created is a + * proxy for the requested interface, a pointer to which is returned to + * the client. With subsequent calls to other interfaces on the object, + * COM will load the appropriate interface stubs and proxies as needed. + */ +typedef struct _CFStub { + IRpcStubBufferVtbl *lpvtbl; + DWORD ref; + + LPUNKNOWN pUnkServer; +} CFStub; + +static HRESULT WINAPI +CFStub_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv) { + if (IsEqualIID(&IID_IUnknown,riid)||IsEqualIID(&IID_IRpcStubBuffer,riid)) { + *ppv = (LPVOID)iface; + IUnknown_AddRef(iface); + return S_OK; + } + FIXME("(%s), interface not supported.\n",debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI +CFStub_AddRef(LPRPCSTUBBUFFER iface) { + CFStub *This = (CFStub *)iface; + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI +CFStub_Release(LPRPCSTUBBUFFER iface) { + CFStub *This = (CFStub *)iface; + ULONG ref; + + ref = InterlockedDecrement(&This->ref); + if (!ref) HeapFree(GetProcessHeap(),0,This); + return ref; +} + +static HRESULT WINAPI +CFStub_Connect(LPRPCSTUBBUFFER iface, IUnknown *pUnkServer) { + CFStub *This = (CFStub *)iface; + + This->pUnkServer = pUnkServer; + IUnknown_AddRef(pUnkServer); + return S_OK; +} + +static void WINAPI +CFStub_Disconnect(LPRPCSTUBBUFFER iface) { + CFStub *This = (CFStub *)iface; + + IUnknown_Release(This->pUnkServer); + This->pUnkServer = NULL; +} +static HRESULT WINAPI +CFStub_Invoke( + LPRPCSTUBBUFFER iface,RPCOLEMESSAGE* msg,IRpcChannelBuffer* chanbuf +) { + CFStub *This = (CFStub *)iface; + HRESULT hres; + + if (msg->iMethod == 3) { /* CreateInstance */ + IID iid; + IClassFactory *classfac; + IUnknown *ppv; + IStream *pStm; + STATSTG ststg; + ULARGE_INTEGER newpos; + LARGE_INTEGER seekto; + ULONG res; + + if (msg->cbBuffer < sizeof(IID)) { + FIXME("Not enough bytes in buffer (%ld instead of %d)?\n",msg->cbBuffer,sizeof(IID)); + return E_FAIL; + } + memcpy(&iid,msg->Buffer,sizeof(iid)); + TRACE("->CreateInstance(%s)\n",debugstr_guid(&iid)); + hres = IUnknown_QueryInterface(This->pUnkServer,&IID_IClassFactory,(LPVOID*)&classfac); + if (hres) { + FIXME("Ole server does not provide an IClassFactory?\n"); + return hres; + } + hres = IClassFactory_CreateInstance(classfac,NULL,&iid,(LPVOID*)&ppv); + IClassFactory_Release(classfac); + if (hres) { + msg->cbBuffer = 0; + FIXME("Failed to create an instance of %s\n",debugstr_guid(&iid)); + return hres; + } + hres = CreateStreamOnHGlobal(0,TRUE,&pStm); + if (hres) { + FIXME("Failed to create stream on hglobal\n"); + return hres; + } + hres = CoMarshalInterface(pStm,&iid,ppv,0,NULL,0); + IUnknown_Release((IUnknown*)ppv); + if (hres) { + FIXME("CoMarshalInterface failed, %lx!\n",hres); + msg->cbBuffer = 0; + return hres; + } + hres = IStream_Stat(pStm,&ststg,0); + if (hres) { + FIXME("Stat failed.\n"); + return hres; + } + + msg->cbBuffer = ststg.cbSize.u.LowPart; + + I_RpcGetBuffer((RPC_MESSAGE *)msg); + if (hres) return hres; + + seekto.u.LowPart = 0;seekto.u.HighPart = 0; + hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); + if (hres) { + FIXME("IStream_Seek failed, %lx\n",hres); + return hres; + } + hres = IStream_Read(pStm,msg->Buffer,msg->cbBuffer,&res); + if (hres) { + FIXME("Stream Read failed, %lx\n",hres); + return hres; + } + IStream_Release(pStm); + return S_OK; + } + FIXME("(%p,%p), stub!\n",msg,chanbuf); + FIXME("iMethod is %ld\n",msg->iMethod); + FIXME("cbBuffer is %ld\n",msg->cbBuffer); + return E_FAIL; +} + +static LPRPCSTUBBUFFER WINAPI +CFStub_IsIIDSupported(LPRPCSTUBBUFFER iface,REFIID riid) { + FIXME("(%s), stub!\n",debugstr_guid(riid)); + return NULL; +} + +static ULONG WINAPI +CFStub_CountRefs(LPRPCSTUBBUFFER iface) { + FIXME("(), stub!\n"); + return 1; +} + +static HRESULT WINAPI +CFStub_DebugServerQueryInterface(LPRPCSTUBBUFFER iface,void** ppv) { + FIXME("(%p), stub!\n",ppv); + return E_FAIL; +} +static void WINAPI +CFStub_DebugServerRelease(LPRPCSTUBBUFFER iface,void *pv) { + FIXME("(%p), stub!\n",pv); +} + +static IRpcStubBufferVtbl cfstubvt = { + CFStub_QueryInterface, + CFStub_AddRef, + CFStub_Release, + CFStub_Connect, + CFStub_Disconnect, + CFStub_Invoke, + CFStub_IsIIDSupported, + CFStub_CountRefs, + CFStub_DebugServerQueryInterface, + CFStub_DebugServerRelease +}; + +static HRESULT +CFStub_Construct(LPRPCSTUBBUFFER *ppv) { + CFStub *cfstub; + cfstub = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFStub)); + if (!cfstub) + return E_OUTOFMEMORY; + *ppv = (LPRPCSTUBBUFFER)cfstub; + cfstub->lpvtbl = &cfstubvt; + cfstub->ref = 1; + return S_OK; +} + +/* Since we create proxy buffers and classfactory in a pair, there is + * no need for 2 separate structs. Just put them in one, but remember + * the refcount. + */ +typedef struct _CFProxy { + const IClassFactoryVtbl *lpvtbl_cf; + const IRpcProxyBufferVtbl *lpvtbl_proxy; + DWORD ref; + + IRpcChannelBuffer *chanbuf; + IUnknown *outer_unknown; +} CFProxy; + +static HRESULT WINAPI IRpcProxyBufferImpl_QueryInterface(LPRPCPROXYBUFFER iface,REFIID riid,LPVOID *ppv) { + *ppv = NULL; + if (IsEqualIID(riid,&IID_IRpcProxyBuffer)||IsEqualIID(riid,&IID_IUnknown)) { + IRpcProxyBuffer_AddRef(iface); + *ppv = (LPVOID)iface; + return S_OK; + } + FIXME("(%s), no interface.\n",debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI IRpcProxyBufferImpl_AddRef(LPRPCPROXYBUFFER iface) { + ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface); + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI IRpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface) { + ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface); + ULONG ref = InterlockedDecrement(&This->ref); + + if (!ref) { + IRpcChannelBuffer_Release(This->chanbuf);This->chanbuf = NULL; + HeapFree(GetProcessHeap(),0,This); + } + return ref; +} + +static HRESULT WINAPI IRpcProxyBufferImpl_Connect(LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer) { + ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface); + + This->chanbuf = pRpcChannelBuffer; + IRpcChannelBuffer_AddRef(This->chanbuf); + return S_OK; +} +static void WINAPI IRpcProxyBufferImpl_Disconnect(LPRPCPROXYBUFFER iface) { + ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface); + if (This->chanbuf) { + IRpcChannelBuffer_Release(This->chanbuf); + This->chanbuf = NULL; + } +} + +static HRESULT WINAPI +CFProxy_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) { + ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface); + if (This->outer_unknown) return IUnknown_QueryInterface(This->outer_unknown, riid, ppv); + *ppv = NULL; + if (IsEqualIID(&IID_IClassFactory,riid) || IsEqualIID(&IID_IUnknown,riid)) { + *ppv = (LPVOID)iface; + IClassFactory_AddRef(iface); + return S_OK; + } + if (IsEqualIID(riid,&IID_IMarshal)) /* just to avoid debug output */ + return E_NOINTERFACE; + FIXME("Unhandled interface: %s\n",debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI CFProxy_AddRef(LPCLASSFACTORY iface) { + ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface); + if (This->outer_unknown) return IUnknown_AddRef(This->outer_unknown); + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI CFProxy_Release(LPCLASSFACTORY iface) { + ULONG ref; + ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface); + if (This->outer_unknown) + ref = IUnknown_Release(This->outer_unknown); + else + ref = InterlockedDecrement(&This->ref); + + if (!ref) { + if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf); + HeapFree(GetProcessHeap(),0,This); + } + return ref; +} + +static HRESULT WINAPI CFProxy_CreateInstance( + LPCLASSFACTORY iface, + LPUNKNOWN pUnkOuter,/* [in] */ + REFIID riid, /* [in] */ + LPVOID *ppv /* [out] */ +) { + ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface); + HRESULT hres; + LPSTREAM pStream; + HGLOBAL hGlobal; + ULONG srstatus; + RPCOLEMESSAGE msg; + + TRACE("(%p,%s,%p)\n",pUnkOuter,debugstr_guid(riid),ppv); + + /* Send CreateInstance to the remote classfactory. + * + * Data: Only the 'IID'. + */ + msg.iMethod = 3; + msg.cbBuffer = sizeof(*riid); + msg.Buffer = NULL; + hres = IRpcChannelBuffer_GetBuffer(This->chanbuf,&msg,&IID_IClassFactory); + if (hres) { + FIXME("IRpcChannelBuffer_GetBuffer failed with %lx?\n",hres); + return hres; + } + memcpy(msg.Buffer,riid,sizeof(*riid)); + hres = IRpcChannelBuffer_SendReceive(This->chanbuf,&msg,&srstatus); + if (hres) { + FIXME("IRpcChannelBuffer_SendReceive failed with %lx?\n",hres); + return hres; + } + + if (!msg.cbBuffer) /* interface not found on remote */ + return srstatus; + + /* We got back: [Marshalled Interface data] */ + TRACE("got %ld bytes data.\n",msg.cbBuffer); + hGlobal = GlobalAlloc(GMEM_MOVEABLE|GMEM_NODISCARD|GMEM_SHARE,msg.cbBuffer); + memcpy(GlobalLock(hGlobal),msg.Buffer,msg.cbBuffer); + hres = CreateStreamOnHGlobal(hGlobal,TRUE,&pStream); + if (hres) { + FIXME("CreateStreamOnHGlobal failed with %lx\n",hres); + return hres; + } + hres = CoUnmarshalInterface( + pStream, + riid, + ppv + ); + IStream_Release(pStream); /* Does GlobalFree hGlobal too. */ + if (hres) { + FIXME("CoMarshalInterface failed, %lx\n",hres); + return hres; + } + return S_OK; +} + +static HRESULT WINAPI CFProxy_LockServer(LPCLASSFACTORY iface,BOOL fLock) { + /*ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);*/ + FIXME("(%d), stub!\n",fLock); + /* basically: write BOOL, read empty */ + return S_OK; +} + +static IRpcProxyBufferVtbl pspbvtbl = { + IRpcProxyBufferImpl_QueryInterface, + IRpcProxyBufferImpl_AddRef, + IRpcProxyBufferImpl_Release, + IRpcProxyBufferImpl_Connect, + IRpcProxyBufferImpl_Disconnect +}; +static IClassFactoryVtbl cfproxyvt = { + CFProxy_QueryInterface, + CFProxy_AddRef, + CFProxy_Release, + CFProxy_CreateInstance, + CFProxy_LockServer +}; + +static HRESULT +CFProxy_Construct(IUnknown *pUnkOuter, LPVOID *ppv,LPVOID *ppProxy) { + CFProxy *cf; + + cf = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFProxy)); + if (!cf) + return E_OUTOFMEMORY; + + cf->lpvtbl_cf = &cfproxyvt; + cf->lpvtbl_proxy = &pspbvtbl; + /* only one reference for the proxy buffer */ + cf->ref = 1; + cf->outer_unknown = pUnkOuter; + *ppv = &(cf->lpvtbl_cf); + *ppProxy = &(cf->lpvtbl_proxy); + return S_OK; +} + + +/********************* IRemUnknown Proxy/Stub ********************************/ + +typedef struct +{ + const IRpcStubBufferVtbl *lpVtbl; + ULONG refs; + IRemUnknown *iface; +} RemUnkStub; + +static HRESULT WINAPI RemUnkStub_QueryInterface(LPRPCSTUBBUFFER iface, + REFIID riid, + LPVOID *obj) +{ + RemUnkStub *This = (RemUnkStub *)iface; + TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(riid),obj); + if (IsEqualGUID(&IID_IUnknown,riid) || + IsEqualGUID(&IID_IRpcStubBuffer,riid)) { + *obj = This; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI RemUnkStub_AddRef(LPRPCSTUBBUFFER iface) +{ + RemUnkStub *This = (RemUnkStub *)iface; + TRACE("(%p)->AddRef()\n",This); + return InterlockedIncrement(&This->refs); +} + +static ULONG WINAPI RemUnkStub_Release(LPRPCSTUBBUFFER iface) +{ + RemUnkStub *This = (RemUnkStub *)iface; + ULONG refs; + TRACE("(%p)->Release()\n",This); + refs = InterlockedDecrement(&This->refs); + if (!refs) + HeapFree(GetProcessHeap(), 0, This); + return refs; +} + +static HRESULT WINAPI RemUnkStub_Connect(LPRPCSTUBBUFFER iface, + LPUNKNOWN lpUnkServer) +{ + RemUnkStub *This = (RemUnkStub *)iface; + TRACE("(%p)->Connect(%p)\n",This,lpUnkServer); + This->iface = (IRemUnknown*)lpUnkServer; + IRemUnknown_AddRef(This->iface); + return S_OK; +} + +static void WINAPI RemUnkStub_Disconnect(LPRPCSTUBBUFFER iface) +{ + RemUnkStub *This = (RemUnkStub *)iface; + TRACE("(%p)->Disconnect()\n",This); + IUnknown_Release(This->iface); + This->iface = NULL; +} + +static HRESULT WINAPI RemUnkStub_Invoke(LPRPCSTUBBUFFER iface, + PRPCOLEMESSAGE pMsg, + LPRPCCHANNELBUFFER pChannel) +{ + RemUnkStub *This = (RemUnkStub *)iface; + ULONG iMethod = pMsg->iMethod; + LPBYTE buf = pMsg->Buffer; + HRESULT hr = RPC_E_INVALIDMETHOD; + + TRACE("(%p)->Invoke(%p,%p) method %ld\n", This, pMsg, pChannel, iMethod); + switch (iMethod) + { + case 3: /* RemQueryInterface */ + { + IPID ipid; + ULONG cRefs; + USHORT cIids; + IID *iids; + REMQIRESULT *pQIResults = NULL; + + /* in */ + memcpy(&ipid, buf, sizeof(ipid)); + buf += sizeof(ipid); + memcpy(&cRefs, buf, sizeof(cRefs)); + buf += sizeof(cRefs); + memcpy(&cIids, buf, sizeof(cIids)); + buf += sizeof(cIids); + iids = (IID *)buf; + + hr = IRemUnknown_RemQueryInterface(This->iface, &ipid, cRefs, cIids, iids, &pQIResults); + + /* out */ + pMsg->cbBuffer = cIids * sizeof(REMQIRESULT); + + I_RpcGetBuffer((RPC_MESSAGE *)pMsg); + if (hr) return hr; + + buf = pMsg->Buffer; + /* FIXME: pQIResults is a unique pointer so pQIResults can be NULL! */ + memcpy(buf, pQIResults, cIids * sizeof(REMQIRESULT)); + + break; + } + case 4: /* RemAddRef */ + { + USHORT cIids; + REMINTERFACEREF *ir; + HRESULT *pResults; + + /* in */ + memcpy(&cIids, buf, sizeof(USHORT)); + buf += sizeof(USHORT); + ir = (REMINTERFACEREF*)buf; + pResults = CoTaskMemAlloc(cIids * sizeof(HRESULT)); + if (!pResults) return E_OUTOFMEMORY; + + hr = IRemUnknown_RemAddRef(This->iface, cIids, ir, pResults); + + /* out */ + pMsg->cbBuffer = cIids * sizeof(HRESULT); + + I_RpcGetBuffer((RPC_MESSAGE *)pMsg); + if (!hr) + { + buf = pMsg->Buffer; + memcpy(buf, pResults, cIids * sizeof(HRESULT)); + } + + CoTaskMemFree(pResults); + + break; + } + case 5: /* RemRelease */ + { + USHORT cIids; + REMINTERFACEREF *ir; + + /* in */ + memcpy(&cIids, buf, sizeof(USHORT)); + buf += sizeof(USHORT); + ir = (REMINTERFACEREF*)buf; + + hr = IRemUnknown_RemRelease(This->iface, cIids, ir); + + /* out */ + pMsg->cbBuffer = 0; + break; + } + } + return hr; +} + +static LPRPCSTUBBUFFER WINAPI RemUnkStub_IsIIDSupported(LPRPCSTUBBUFFER iface, + REFIID riid) +{ + RemUnkStub *This = (RemUnkStub *)iface; + TRACE("(%p)->IsIIDSupported(%s)\n", This, debugstr_guid(riid)); + return IsEqualGUID(&IID_IRemUnknown, riid) ? iface : NULL; +} + +static ULONG WINAPI RemUnkStub_CountRefs(LPRPCSTUBBUFFER iface) +{ + RemUnkStub *This = (RemUnkStub *)iface; + FIXME("(%p)->CountRefs()\n", This); + return 1; +} + +static HRESULT WINAPI RemUnkStub_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, + LPVOID *ppv) +{ + RemUnkStub *This = (RemUnkStub *)iface; + FIXME("(%p)->DebugServerQueryInterface(%p)\n",This,ppv); + return E_NOINTERFACE; +} + +static void WINAPI RemUnkStub_DebugServerRelease(LPRPCSTUBBUFFER iface, + LPVOID pv) +{ + RemUnkStub *This = (RemUnkStub *)iface; + FIXME("(%p)->DebugServerRelease(%p)\n", This, pv); +} + +static const IRpcStubBufferVtbl RemUnkStub_VTable = +{ + RemUnkStub_QueryInterface, + RemUnkStub_AddRef, + RemUnkStub_Release, + RemUnkStub_Connect, + RemUnkStub_Disconnect, + RemUnkStub_Invoke, + RemUnkStub_IsIIDSupported, + RemUnkStub_CountRefs, + RemUnkStub_DebugServerQueryInterface, + RemUnkStub_DebugServerRelease +}; + +static HRESULT RemUnkStub_Construct(IRpcStubBuffer **ppStub) +{ + RemUnkStub *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + if (!This) return E_OUTOFMEMORY; + This->lpVtbl = &RemUnkStub_VTable; + This->refs = 0; + This->iface = NULL; + *ppStub = (IRpcStubBuffer*)This; + return S_OK; +} + + +typedef struct _RemUnkProxy { + const IRemUnknownVtbl *lpvtbl_remunk; + const IRpcProxyBufferVtbl *lpvtbl_proxy; + DWORD refs; + + IRpcChannelBuffer *chan; + IUnknown *outer_unknown; +} RemUnkProxy; + +static HRESULT WINAPI RemUnkProxy_QueryInterface(LPREMUNKNOWN iface, REFIID riid, void **ppv) +{ + RemUnkProxy *This = (RemUnkProxy *)iface; + if (This->outer_unknown) + return IUnknown_QueryInterface(This->outer_unknown, riid, ppv); + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IRemUnknown)) + { + IRemUnknown_AddRef(iface); + *ppv = (LPVOID)iface; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI RemUnkProxy_AddRef(LPREMUNKNOWN iface) +{ + RemUnkProxy *This = (RemUnkProxy *)iface; + + TRACE("(%p)->AddRef()\n",This); + return InterlockedIncrement(&This->refs); +} + +static ULONG WINAPI RemUnkProxy_Release(LPREMUNKNOWN iface) +{ + RemUnkProxy *This = (RemUnkProxy *)iface; + ULONG refs; + + TRACE("(%p)->Release()\n",This); + if (This->outer_unknown) + refs = IUnknown_Release(This->outer_unknown); + else + refs = InterlockedDecrement(&This->refs); + + if (!refs) { + if (This->chan) IRpcChannelBuffer_Release(This->chan); + HeapFree(GetProcessHeap(),0,This); + } + return refs; +} + +static HRESULT WINAPI RemUnkProxy_RemQueryInterface(LPREMUNKNOWN iface, + REFIPID ripid, + ULONG cRefs, + USHORT cIids, + IID* iids, + REMQIRESULT** ppQIResults) +{ + RemUnkProxy *This = (RemUnkProxy *)iface; + RPCOLEMESSAGE msg; + HRESULT hr = S_OK; + ULONG status; + + TRACE("(%p)->(%s,%ld,%d,%p,%p)\n",This, + debugstr_guid(ripid),cRefs,cIids,iids,ppQIResults); + + *ppQIResults = NULL; + memset(&msg, 0, sizeof(msg)); + msg.iMethod = 3; + msg.cbBuffer = sizeof(IPID) + sizeof(ULONG) + + sizeof(USHORT) + cIids*sizeof(IID); + hr = IRpcChannelBuffer_GetBuffer(This->chan, &msg, &IID_IRemUnknown); + if (SUCCEEDED(hr)) { + LPBYTE buf = msg.Buffer; + memcpy(buf, ripid, sizeof(IPID)); + buf += sizeof(IPID); + memcpy(buf, &cRefs, sizeof(ULONG)); + buf += sizeof(ULONG); + memcpy(buf, &cIids, sizeof(USHORT)); + buf += sizeof(USHORT); + memcpy(buf, iids, cIids*sizeof(IID)); + + hr = IRpcChannelBuffer_SendReceive(This->chan, &msg, &status); + + if (SUCCEEDED(hr)) { + buf = msg.Buffer; + *ppQIResults = CoTaskMemAlloc(cIids*sizeof(REMQIRESULT)); + memcpy(*ppQIResults, buf, cIids*sizeof(REMQIRESULT)); + } + + IRpcChannelBuffer_FreeBuffer(This->chan, &msg); + } + + return hr; +} + +static HRESULT WINAPI RemUnkProxy_RemAddRef(LPREMUNKNOWN iface, + USHORT cInterfaceRefs, + REMINTERFACEREF* InterfaceRefs, + HRESULT* pResults) +{ + RemUnkProxy *This = (RemUnkProxy *)iface; + RPCOLEMESSAGE msg; + HRESULT hr = S_OK; + ULONG status; + + TRACE("(%p)->(%d,%p,%p)\n",This, + cInterfaceRefs,InterfaceRefs,pResults); + + memset(&msg, 0, sizeof(msg)); + msg.iMethod = 4; + msg.cbBuffer = sizeof(USHORT) + cInterfaceRefs*sizeof(REMINTERFACEREF); + hr = IRpcChannelBuffer_GetBuffer(This->chan, &msg, &IID_IRemUnknown); + if (SUCCEEDED(hr)) { + LPBYTE buf = msg.Buffer; + memcpy(buf, &cInterfaceRefs, sizeof(USHORT)); + buf += sizeof(USHORT); + memcpy(buf, InterfaceRefs, cInterfaceRefs*sizeof(REMINTERFACEREF)); + + hr = IRpcChannelBuffer_SendReceive(This->chan, &msg, &status); + + if (SUCCEEDED(hr)) { + buf = msg.Buffer; + memcpy(pResults, buf, cInterfaceRefs*sizeof(HRESULT)); + } + + IRpcChannelBuffer_FreeBuffer(This->chan, &msg); + } + + return hr; +} + +static HRESULT WINAPI RemUnkProxy_RemRelease(LPREMUNKNOWN iface, + USHORT cInterfaceRefs, + REMINTERFACEREF* InterfaceRefs) +{ + RemUnkProxy *This = (RemUnkProxy *)iface; + RPCOLEMESSAGE msg; + HRESULT hr = S_OK; + ULONG status; + + TRACE("(%p)->(%d,%p)\n",This, + cInterfaceRefs,InterfaceRefs); + + memset(&msg, 0, sizeof(msg)); + msg.iMethod = 5; + msg.cbBuffer = sizeof(USHORT) + cInterfaceRefs*sizeof(REMINTERFACEREF); + hr = IRpcChannelBuffer_GetBuffer(This->chan, &msg, &IID_IRemUnknown); + if (SUCCEEDED(hr)) { + LPBYTE buf = msg.Buffer; + memcpy(buf, &cInterfaceRefs, sizeof(USHORT)); + buf += sizeof(USHORT); + memcpy(buf, InterfaceRefs, cInterfaceRefs*sizeof(REMINTERFACEREF)); + + hr = IRpcChannelBuffer_SendReceive(This->chan, &msg, &status); + + IRpcChannelBuffer_FreeBuffer(This->chan, &msg); + } + + return hr; +} + +static const IRemUnknownVtbl RemUnkProxy_VTable = +{ + RemUnkProxy_QueryInterface, + RemUnkProxy_AddRef, + RemUnkProxy_Release, + RemUnkProxy_RemQueryInterface, + RemUnkProxy_RemAddRef, + RemUnkProxy_RemRelease +}; + + +static HRESULT WINAPI RURpcProxyBufferImpl_QueryInterface(LPRPCPROXYBUFFER iface,REFIID riid,LPVOID *ppv) { + *ppv = NULL; + if (IsEqualIID(riid,&IID_IRpcProxyBuffer)||IsEqualIID(riid,&IID_IUnknown)) { + IRpcProxyBuffer_AddRef(iface); + *ppv = (LPVOID)iface; + return S_OK; + } + FIXME("(%s), no interface.\n",debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI RURpcProxyBufferImpl_AddRef(LPRPCPROXYBUFFER iface) { + ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface); + return InterlockedIncrement(&This->refs); +} + +static ULONG WINAPI RURpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface) { + ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface); + ULONG ref = InterlockedDecrement(&This->refs); + + if (!ref) { + IRpcChannelBuffer_Release(This->chan);This->chan = NULL; + HeapFree(GetProcessHeap(),0,This); + } + return ref; +} + +static HRESULT WINAPI RURpcProxyBufferImpl_Connect(LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer) { + ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface); + + This->chan = pRpcChannelBuffer; + IRpcChannelBuffer_AddRef(This->chan); + return S_OK; +} +static void WINAPI RURpcProxyBufferImpl_Disconnect(LPRPCPROXYBUFFER iface) { + ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface); + if (This->chan) { + IRpcChannelBuffer_Release(This->chan); + This->chan = NULL; + } +} + + +static const IRpcProxyBufferVtbl RURpcProxyBuffer_VTable = { + RURpcProxyBufferImpl_QueryInterface, + RURpcProxyBufferImpl_AddRef, + RURpcProxyBufferImpl_Release, + RURpcProxyBufferImpl_Connect, + RURpcProxyBufferImpl_Disconnect +}; + +static HRESULT +RemUnkProxy_Construct(IUnknown *pUnkOuter, LPVOID *ppv,LPVOID *ppProxy) { + RemUnkProxy *This; + + This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*This)); + if (!This) + return E_OUTOFMEMORY; + + This->lpvtbl_remunk = &RemUnkProxy_VTable; + This->lpvtbl_proxy = &RURpcProxyBuffer_VTable; + /* only one reference for the proxy buffer */ + This->refs = 1; + This->outer_unknown = pUnkOuter; + *ppv = &(This->lpvtbl_remunk); + *ppProxy = &(This->lpvtbl_proxy); + return S_OK; +} + + +/********************* OLE Proxy/Stub Factory ********************************/ +static HRESULT WINAPI +PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) { + if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) { + *ppv = (LPVOID)iface; + /* No ref counting, static class */ + return S_OK; + } + FIXME("(%s) unknown IID?\n",debugstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; } +static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; } + +static HRESULT WINAPI +PSFacBuf_CreateProxy( + LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid, + IRpcProxyBuffer **ppProxy, LPVOID *ppv +) { + if (IsEqualIID(&IID_IClassFactory,riid)) + return CFProxy_Construct(pUnkOuter, ppv,(LPVOID*)ppProxy); + else if (IsEqualIID(&IID_IRemUnknown,riid)) + return RemUnkProxy_Construct(pUnkOuter, ppv,(LPVOID*)ppProxy); + FIXME("proxying not implemented for (%s) yet!\n",debugstr_guid(riid)); + return E_FAIL; +} + +static HRESULT WINAPI +PSFacBuf_CreateStub( + LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer, + IRpcStubBuffer** ppStub +) { + HRESULT hres; + + TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub); + + if (IsEqualIID(&IID_IClassFactory, riid) || + IsEqualIID(&IID_IUnknown, riid) /* FIXME: fixup stub manager and remove this*/) { + hres = CFStub_Construct(ppStub); + if (!hres) + IRpcStubBuffer_Connect((*ppStub),pUnkServer); + return hres; + } else if (IsEqualIID(&IID_IRemUnknown,riid)) { + hres = RemUnkStub_Construct(ppStub); + if (!hres) + IRpcStubBuffer_Connect((*ppStub),pUnkServer); + return hres; + } + FIXME("stubbing not implemented for (%s) yet!\n",debugstr_guid(riid)); + return E_FAIL; +} + +static IPSFactoryBufferVtbl psfacbufvtbl = { + PSFacBuf_QueryInterface, + PSFacBuf_AddRef, + PSFacBuf_Release, + PSFacBuf_CreateProxy, + PSFacBuf_CreateStub +}; + +/* This is the whole PSFactoryBuffer object, just the vtableptr */ +static IPSFactoryBufferVtbl *lppsfac = &psfacbufvtbl; + +/*********************************************************************** + * DllGetClassObject [OLE32.@] + */ +HRESULT WINAPI OLE32_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv) +{ + *ppv = NULL; + if (IsEqualIID(rclsid, &CLSID_PSFactoryBuffer)) + return IPSFactoryBuffer_QueryInterface((IPSFactoryBuffer *)&lppsfac, iid, ppv); + if (IsEqualIID(rclsid,&CLSID_DfMarshal)&&( + IsEqualIID(iid,&IID_IClassFactory) || + IsEqualIID(iid,&IID_IUnknown) + ) + ) + return MARSHAL_GetStandardMarshalCF(ppv); + if (IsEqualIID(rclsid,&CLSID_StdGlobalInterfaceTable) && (IsEqualIID(iid,&IID_IClassFactory) || IsEqualIID(iid,&IID_IUnknown))) + return StdGlobalInterfaceTable_GetFactory(ppv); + if (IsEqualCLSID(rclsid, &CLSID_FileMoniker)) + return FileMonikerCF_Create(iid, ppv); + if (IsEqualCLSID(rclsid, &CLSID_ItemMoniker)) + return ItemMonikerCF_Create(iid, ppv); + + FIXME("\n\tCLSID:\t%s,\n\tIID:\t%s\n",debugstr_guid(rclsid),debugstr_guid(iid)); + return CLASS_E_CLASSNOTAVAILABLE; +} diff --git a/reactos/lib/ole32/olestd.h b/reactos/lib/ole32/olestd.h index 9101cebdef6..b5814fad4a4 100644 --- a/reactos/lib/ole32/olestd.h +++ b/reactos/lib/ole32/olestd.h @@ -1,56 +1,56 @@ -/* - * Copyright 2000 Abey George - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#if !defined( __WINE_OLESTD_H_ ) -#define __WINE_OLESTD_H_ - -#if !defined(__cplusplus) && !defined( __TURBOC__) -#define NONAMELESSUNION /* use strict ANSI standard (for DVOBJ.H) */ -#endif - -/* Clipboard format strings */ -#define CF_EMBEDSOURCE "Embed Source" -#define CF_EMBEDDEDOBJECT "Embedded Object" -#define CF_LINKSOURCE "Link Source" -#define CF_CUSTOMLINKSOURCE "Custom Link Source" -#define CF_OBJECTDESCRIPTOR "Object Descriptor" -#define CF_LINKSRCDESCRIPTOR "Link Source Descriptor" -#define CF_OWNERLINK "OwnerLink" -#define CF_FILENAME "FileName" - -#define OleStdQueryOleObjectData(lpformatetc) \ - (((lpformatetc)->tymed & TYMED_ISTORAGE) ? \ - NOERROR : ResultFromScode(DV_E_FORMATETC)) - -#define OleStdQueryLinkSourceData(lpformatetc) \ - (((lpformatetc)->tymed & TYMED_ISTREAM) ? \ - NOERROR : ResultFromScode(DV_E_FORMATETC)) - -#define OleStdQueryObjectDescriptorData(lpformatetc) \ - (((lpformatetc)->tymed & TYMED_HGLOBAL) ? \ - NOERROR : ResultFromScode(DV_E_FORMATETC)) - -#define OleStdQueryFormatMedium(lpformatetc, tymd) \ - (((lpformatetc)->tymed & tymd) ? \ - NOERROR : ResultFromScode(DV_E_FORMATETC)) - -/* Make an independent copy of a MetafilePict */ -#define OleStdCopyMetafilePict(hpictin, phpictout) \ - (*(phpictout) = OleDuplicateData(hpictin,CF_METAFILEPICT,GHND|GMEM_SHARE)) - -#endif /* __WINE_OLESTD_H_ */ +/* + * Copyright 2000 Abey George + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if !defined( __WINE_OLESTD_H_ ) +#define __WINE_OLESTD_H_ + +#if !defined(__cplusplus) && !defined( __TURBOC__) +#define NONAMELESSUNION /* use strict ANSI standard (for DVOBJ.H) */ +#endif + +/* Clipboard format strings */ +#define CF_EMBEDSOURCE "Embed Source" +#define CF_EMBEDDEDOBJECT "Embedded Object" +#define CF_LINKSOURCE "Link Source" +#define CF_CUSTOMLINKSOURCE "Custom Link Source" +#define CF_OBJECTDESCRIPTOR "Object Descriptor" +#define CF_LINKSRCDESCRIPTOR "Link Source Descriptor" +#define CF_OWNERLINK "OwnerLink" +#define CF_FILENAME "FileName" + +#define OleStdQueryOleObjectData(lpformatetc) \ + (((lpformatetc)->tymed & TYMED_ISTORAGE) ? \ + NOERROR : ResultFromScode(DV_E_FORMATETC)) + +#define OleStdQueryLinkSourceData(lpformatetc) \ + (((lpformatetc)->tymed & TYMED_ISTREAM) ? \ + NOERROR : ResultFromScode(DV_E_FORMATETC)) + +#define OleStdQueryObjectDescriptorData(lpformatetc) \ + (((lpformatetc)->tymed & TYMED_HGLOBAL) ? \ + NOERROR : ResultFromScode(DV_E_FORMATETC)) + +#define OleStdQueryFormatMedium(lpformatetc, tymd) \ + (((lpformatetc)->tymed & tymd) ? \ + NOERROR : ResultFromScode(DV_E_FORMATETC)) + +/* Make an independent copy of a MetafilePict */ +#define OleStdCopyMetafilePict(hpictin, phpictout) \ + (*(phpictout) = OleDuplicateData(hpictin,CF_METAFILEPICT,GHND|GMEM_SHARE)) + +#endif /* __WINE_OLESTD_H_ */ diff --git a/reactos/lib/ole32/regsvr.c b/reactos/lib/ole32/regsvr.c index c4083c9824d..07918c77fdb 100644 --- a/reactos/lib/ole32/regsvr.c +++ b/reactos/lib/ole32/regsvr.c @@ -1,498 +1,498 @@ -/* - * self-registerable dll functions for ole32.dll - * - * Copyright (C) 2003 John K. Hohm - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <stdarg.h> -#include <string.h> - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "winreg.h" -#include "winerror.h" -#include "objbase.h" - -#include "compobj_private.h" -#include "ole2.h" -#include "olectl.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/* - * Near the bottom of this file are the exported DllRegisterServer and - * DllUnregisterServer, which make all this worthwhile. - */ - -/*********************************************************************** - * interface for self-registering - */ -struct regsvr_interface -{ - IID const *iid; /* NULL for end of list */ - LPCSTR name; /* can be NULL to omit */ - IID const *base_iid; /* can be NULL to omit */ - int num_methods; /* can be <0 to omit */ - CLSID const *ps_clsid; /* can be NULL to omit */ - CLSID const *ps_clsid32; /* can be NULL to omit */ -}; - -static HRESULT register_interfaces(struct regsvr_interface const *list); -static HRESULT unregister_interfaces(struct regsvr_interface const *list); - -struct regsvr_coclass -{ - CLSID const *clsid; /* NULL for end of list */ - LPCSTR name; /* can be NULL to omit */ - LPCSTR ips; /* can be NULL to omit */ - LPCSTR ips32; /* can be NULL to omit */ - LPCSTR ips32_tmodel; /* can be NULL to omit */ -}; - -static HRESULT register_coclasses(struct regsvr_coclass const *list); -static HRESULT unregister_coclasses(struct regsvr_coclass const *list); - -/*********************************************************************** - * static string constants - */ -static WCHAR const interface_keyname[10] = { - 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 }; -static WCHAR const base_ifa_keyname[14] = { - 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', - 'e', 0 }; -static WCHAR const num_methods_keyname[11] = { - 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 }; -static WCHAR const ps_clsid_keyname[15] = { - 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', - 'i', 'd', 0 }; -static WCHAR const ps_clsid32_keyname[17] = { - 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', - 'i', 'd', '3', '2', 0 }; -static WCHAR const clsid_keyname[6] = { - 'C', 'L', 'S', 'I', 'D', 0 }; -static WCHAR const ips_keyname[13] = { - 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', - 0 }; -static WCHAR const ips32_keyname[15] = { - 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', - '3', '2', 0 }; -static char const tmodel_valuename[] = "ThreadingModel"; - -/*********************************************************************** - * static helper functions - */ -static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid); -static LONG register_key_defvalueW(HKEY base, WCHAR const *name, - WCHAR const *value); -static LONG register_key_defvalueA(HKEY base, WCHAR const *name, - char const *value); -static LONG recursive_delete_key(HKEY key); - - -/*********************************************************************** - * register_interfaces - */ -static HRESULT register_interfaces(struct regsvr_interface const *list) -{ - LONG res = ERROR_SUCCESS; - HKEY interface_key; - - res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &interface_key, NULL); - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->iid; ++list) { - WCHAR buf[39]; - HKEY iid_key; - - StringFromGUID2(list->iid, buf, 39); - res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &iid_key, NULL); - if (res != ERROR_SUCCESS) goto error_close_interface_key; - - if (list->name) { - res = RegSetValueExA(iid_key, NULL, 0, REG_SZ, - (CONST BYTE*)(list->name), - strlen(list->name) + 1); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (list->base_iid) { - register_key_guid(iid_key, base_ifa_keyname, list->base_iid); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (0 <= list->num_methods) { - static WCHAR const fmt[3] = { '%', 'd', 0 }; - HKEY key; - - res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &key, NULL); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - - wsprintfW(buf, fmt, list->num_methods); - res = RegSetValueExW(key, NULL, 0, REG_SZ, - (CONST BYTE*)buf, - (lstrlenW(buf) + 1) * sizeof(WCHAR)); - RegCloseKey(key); - - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (list->ps_clsid) { - register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (list->ps_clsid32) { - register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - error_close_iid_key: - RegCloseKey(iid_key); - } - -error_close_interface_key: - RegCloseKey(interface_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * unregister_interfaces - */ -static HRESULT unregister_interfaces(struct regsvr_interface const *list) -{ - LONG res = ERROR_SUCCESS; - HKEY interface_key; - - res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, - KEY_READ | KEY_WRITE, &interface_key); - if (res == ERROR_FILE_NOT_FOUND) return S_OK; - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->iid; ++list) { - WCHAR buf[39]; - HKEY iid_key; - - StringFromGUID2(list->iid, buf, 39); - res = RegOpenKeyExW(interface_key, buf, 0, - KEY_READ | KEY_WRITE, &iid_key); - if (res == ERROR_FILE_NOT_FOUND) { - res = ERROR_SUCCESS; - continue; - } - if (res != ERROR_SUCCESS) goto error_close_interface_key; - res = recursive_delete_key(iid_key); - RegCloseKey(iid_key); - if (res != ERROR_SUCCESS) goto error_close_interface_key; - } - -error_close_interface_key: - RegCloseKey(interface_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * register_coclasses - */ -static HRESULT register_coclasses(struct regsvr_coclass const *list) -{ - LONG res = ERROR_SUCCESS; - HKEY coclass_key; - - res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL); - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->clsid; ++list) { - WCHAR buf[39]; - HKEY clsid_key; - - StringFromGUID2(list->clsid, buf, 39); - res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL); - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - - if (list->name) { - res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ, - (CONST BYTE*)(list->name), - strlen(list->name) + 1); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->ips) { - res = register_key_defvalueA(clsid_key, ips_keyname, list->ips); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->ips32) { - HKEY ips32_key; - - res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, - &ips32_key, NULL); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - - res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ, - (CONST BYTE*)list->ips32, - lstrlenA(list->ips32) + 1); - if (res == ERROR_SUCCESS && list->ips32_tmodel) - res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ, - (CONST BYTE*)list->ips32_tmodel, - strlen(list->ips32_tmodel) + 1); - RegCloseKey(ips32_key); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - error_close_clsid_key: - RegCloseKey(clsid_key); - } - -error_close_coclass_key: - RegCloseKey(coclass_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * unregister_coclasses - */ -static HRESULT unregister_coclasses(struct regsvr_coclass const *list) -{ - LONG res = ERROR_SUCCESS; - HKEY coclass_key; - - res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, - KEY_READ | KEY_WRITE, &coclass_key); - if (res == ERROR_FILE_NOT_FOUND) return S_OK; - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->clsid; ++list) { - WCHAR buf[39]; - HKEY clsid_key; - - StringFromGUID2(list->clsid, buf, 39); - res = RegOpenKeyExW(coclass_key, buf, 0, - KEY_READ | KEY_WRITE, &clsid_key); - if (res == ERROR_FILE_NOT_FOUND) { - res = ERROR_SUCCESS; - continue; - } - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - res = recursive_delete_key(clsid_key); - RegCloseKey(clsid_key); - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - } - -error_close_coclass_key: - RegCloseKey(coclass_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * regsvr_key_guid - */ -static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) -{ - WCHAR buf[39]; - - StringFromGUID2(guid, buf, 39); - return register_key_defvalueW(base, name, buf); -} - -/*********************************************************************** - * regsvr_key_defvalueW - */ -static LONG register_key_defvalueW( - HKEY base, - WCHAR const *name, - WCHAR const *value) -{ - LONG res; - HKEY key; - - res = RegCreateKeyExW(base, name, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &key, NULL); - if (res != ERROR_SUCCESS) return res; - res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value, - (lstrlenW(value) + 1) * sizeof(WCHAR)); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * regsvr_key_defvalueA - */ -static LONG register_key_defvalueA( - HKEY base, - WCHAR const *name, - char const *value) -{ - LONG res; - HKEY key; - - res = RegCreateKeyExW(base, name, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &key, NULL); - if (res != ERROR_SUCCESS) return res; - res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value, - lstrlenA(value) + 1); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * recursive_delete_key - */ -static LONG recursive_delete_key(HKEY key) -{ - LONG res; - WCHAR subkey_name[MAX_PATH]; - DWORD cName; - HKEY subkey; - - for (;;) { - cName = sizeof(subkey_name) / sizeof(WCHAR); - res = RegEnumKeyExW(key, 0, subkey_name, &cName, - NULL, NULL, NULL, NULL); - if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) { - res = ERROR_SUCCESS; /* presumably we're done enumerating */ - break; - } - res = RegOpenKeyExW(key, subkey_name, 0, - KEY_READ | KEY_WRITE, &subkey); - if (res == ERROR_FILE_NOT_FOUND) continue; - if (res != ERROR_SUCCESS) break; - - res = recursive_delete_key(subkey); - RegCloseKey(subkey); - if (res != ERROR_SUCCESS) break; - } - - if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0); - return res; -} - -/*********************************************************************** - * coclass list - */ -static GUID const CLSID_FileMoniker = { - 0x00000303, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; - -static GUID const CLSID_ItemMoniker = { - 0x00000304, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; - -/* FIXME: DfMarshal and PSFactoryBuffer are defined elsewhere too */ - -static GUID const CLSID_DfMarshal = { - 0x0000030B, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; - -static GUID const CLSID_PSFactoryBuffer = { - 0x00000320, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; - -static struct regsvr_coclass const coclass_list[] = { - { &CLSID_FileMoniker, - "FileMoniker", - NULL, - "ole32.dll", - "Both" - }, - { &CLSID_ItemMoniker, - "ItemMoniker", - NULL, - "ole32.dll", - "Both" - }, - { &CLSID_DfMarshal, - "DfMarshal", - NULL, - "ole32.dll", - "Both" - }, - { &CLSID_PSFactoryBuffer, - "PSFactoryBuffer", - NULL, - "ole32.dll", - "Both" - }, - { &CLSID_StdGlobalInterfaceTable, - "StdGlobalInterfaceTable", - NULL, - "ole32.dll", - "Apartment" - }, - { NULL } /* list terminator */ -}; - -/*********************************************************************** - * interface list - */ - -#define INTERFACE_ENTRY(interface, base, clsid32, clsid16) { &IID_##interface, #interface, base, sizeof(interface##Vtbl)/sizeof(void*), clsid16, clsid32 } -#define STD_INTERFACE_ENTRY(interface) INTERFACE_ENTRY(interface, NULL, &CLSID_PSFactoryBuffer, NULL) - -static struct regsvr_interface const interface_list[] = { - STD_INTERFACE_ENTRY(IUnknown), - STD_INTERFACE_ENTRY(IClassFactory), - STD_INTERFACE_ENTRY(IStorage), - STD_INTERFACE_ENTRY(IStream ), - STD_INTERFACE_ENTRY(IPersistStorage), - STD_INTERFACE_ENTRY(IDataObject), - STD_INTERFACE_ENTRY(IAdviseSink), - STD_INTERFACE_ENTRY(IOleObject), - STD_INTERFACE_ENTRY(IOleClientSite), - STD_INTERFACE_ENTRY(IRemUnknown), - { NULL } /* list terminator */ -}; - -/*********************************************************************** - * DllRegisterServer (OLE32.@) - */ -HRESULT WINAPI DllRegisterServer() -{ - HRESULT hr; - - TRACE("\n"); - - hr = register_coclasses(coclass_list); - if (SUCCEEDED(hr)) - hr = register_interfaces(interface_list); - return hr; -} - -/*********************************************************************** - * DllUnregisterServer (OLE32.@) - */ -HRESULT WINAPI DllUnregisterServer() -{ - HRESULT hr; - - TRACE("\n"); - - hr = unregister_coclasses(coclass_list); - if (SUCCEEDED(hr)) - hr = unregister_interfaces(interface_list); - return hr; -} +/* + * self-registerable dll functions for ole32.dll + * + * Copyright (C) 2003 John K. Hohm + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <stdarg.h> +#include <string.h> + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "winerror.h" +#include "objbase.h" + +#include "compobj_private.h" +#include "ole2.h" +#include "olectl.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/* + * Near the bottom of this file are the exported DllRegisterServer and + * DllUnregisterServer, which make all this worthwhile. + */ + +/*********************************************************************** + * interface for self-registering + */ +struct regsvr_interface +{ + IID const *iid; /* NULL for end of list */ + LPCSTR name; /* can be NULL to omit */ + IID const *base_iid; /* can be NULL to omit */ + int num_methods; /* can be <0 to omit */ + CLSID const *ps_clsid; /* can be NULL to omit */ + CLSID const *ps_clsid32; /* can be NULL to omit */ +}; + +static HRESULT register_interfaces(struct regsvr_interface const *list); +static HRESULT unregister_interfaces(struct regsvr_interface const *list); + +struct regsvr_coclass +{ + CLSID const *clsid; /* NULL for end of list */ + LPCSTR name; /* can be NULL to omit */ + LPCSTR ips; /* can be NULL to omit */ + LPCSTR ips32; /* can be NULL to omit */ + LPCSTR ips32_tmodel; /* can be NULL to omit */ +}; + +static HRESULT register_coclasses(struct regsvr_coclass const *list); +static HRESULT unregister_coclasses(struct regsvr_coclass const *list); + +/*********************************************************************** + * static string constants + */ +static WCHAR const interface_keyname[10] = { + 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 }; +static WCHAR const base_ifa_keyname[14] = { + 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', + 'e', 0 }; +static WCHAR const num_methods_keyname[11] = { + 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 }; +static WCHAR const ps_clsid_keyname[15] = { + 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', + 'i', 'd', 0 }; +static WCHAR const ps_clsid32_keyname[17] = { + 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', + 'i', 'd', '3', '2', 0 }; +static WCHAR const clsid_keyname[6] = { + 'C', 'L', 'S', 'I', 'D', 0 }; +static WCHAR const ips_keyname[13] = { + 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', + 0 }; +static WCHAR const ips32_keyname[15] = { + 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', + '3', '2', 0 }; +static char const tmodel_valuename[] = "ThreadingModel"; + +/*********************************************************************** + * static helper functions + */ +static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid); +static LONG register_key_defvalueW(HKEY base, WCHAR const *name, + WCHAR const *value); +static LONG register_key_defvalueA(HKEY base, WCHAR const *name, + char const *value); +static LONG recursive_delete_key(HKEY key); + + +/*********************************************************************** + * register_interfaces + */ +static HRESULT register_interfaces(struct regsvr_interface const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY interface_key; + + res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &interface_key, NULL); + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->iid; ++list) { + WCHAR buf[39]; + HKEY iid_key; + + StringFromGUID2(list->iid, buf, 39); + res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &iid_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_interface_key; + + if (list->name) { + res = RegSetValueExA(iid_key, NULL, 0, REG_SZ, + (CONST BYTE*)(list->name), + strlen(list->name) + 1); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->base_iid) { + register_key_guid(iid_key, base_ifa_keyname, list->base_iid); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (0 <= list->num_methods) { + static WCHAR const fmt[3] = { '%', 'd', 0 }; + HKEY key; + + res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + + wsprintfW(buf, fmt, list->num_methods); + res = RegSetValueExW(key, NULL, 0, REG_SZ, + (CONST BYTE*)buf, + (lstrlenW(buf) + 1) * sizeof(WCHAR)); + RegCloseKey(key); + + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->ps_clsid) { + register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->ps_clsid32) { + register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + error_close_iid_key: + RegCloseKey(iid_key); + } + +error_close_interface_key: + RegCloseKey(interface_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * unregister_interfaces + */ +static HRESULT unregister_interfaces(struct regsvr_interface const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY interface_key; + + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, + KEY_READ | KEY_WRITE, &interface_key); + if (res == ERROR_FILE_NOT_FOUND) return S_OK; + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->iid; ++list) { + WCHAR buf[39]; + HKEY iid_key; + + StringFromGUID2(list->iid, buf, 39); + res = RegOpenKeyExW(interface_key, buf, 0, + KEY_READ | KEY_WRITE, &iid_key); + if (res == ERROR_FILE_NOT_FOUND) { + res = ERROR_SUCCESS; + continue; + } + if (res != ERROR_SUCCESS) goto error_close_interface_key; + res = recursive_delete_key(iid_key); + RegCloseKey(iid_key); + if (res != ERROR_SUCCESS) goto error_close_interface_key; + } + +error_close_interface_key: + RegCloseKey(interface_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * register_coclasses + */ +static HRESULT register_coclasses(struct regsvr_coclass const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY coclass_key; + + res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL); + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->clsid; ++list) { + WCHAR buf[39]; + HKEY clsid_key; + + StringFromGUID2(list->clsid, buf, 39); + res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + + if (list->name) { + res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ, + (CONST BYTE*)(list->name), + strlen(list->name) + 1); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->ips) { + res = register_key_defvalueA(clsid_key, ips_keyname, list->ips); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->ips32) { + HKEY ips32_key; + + res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, + &ips32_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ, + (CONST BYTE*)list->ips32, + lstrlenA(list->ips32) + 1); + if (res == ERROR_SUCCESS && list->ips32_tmodel) + res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ, + (CONST BYTE*)list->ips32_tmodel, + strlen(list->ips32_tmodel) + 1); + RegCloseKey(ips32_key); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + error_close_clsid_key: + RegCloseKey(clsid_key); + } + +error_close_coclass_key: + RegCloseKey(coclass_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * unregister_coclasses + */ +static HRESULT unregister_coclasses(struct regsvr_coclass const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY coclass_key; + + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, + KEY_READ | KEY_WRITE, &coclass_key); + if (res == ERROR_FILE_NOT_FOUND) return S_OK; + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->clsid; ++list) { + WCHAR buf[39]; + HKEY clsid_key; + + StringFromGUID2(list->clsid, buf, 39); + res = RegOpenKeyExW(coclass_key, buf, 0, + KEY_READ | KEY_WRITE, &clsid_key); + if (res == ERROR_FILE_NOT_FOUND) { + res = ERROR_SUCCESS; + continue; + } + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + res = recursive_delete_key(clsid_key); + RegCloseKey(clsid_key); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + } + +error_close_coclass_key: + RegCloseKey(coclass_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * regsvr_key_guid + */ +static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) +{ + WCHAR buf[39]; + + StringFromGUID2(guid, buf, 39); + return register_key_defvalueW(base, name, buf); +} + +/*********************************************************************** + * regsvr_key_defvalueW + */ +static LONG register_key_defvalueW( + HKEY base, + WCHAR const *name, + WCHAR const *value) +{ + LONG res; + HKEY key; + + res = RegCreateKeyExW(base, name, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) return res; + res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value, + (lstrlenW(value) + 1) * sizeof(WCHAR)); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * regsvr_key_defvalueA + */ +static LONG register_key_defvalueA( + HKEY base, + WCHAR const *name, + char const *value) +{ + LONG res; + HKEY key; + + res = RegCreateKeyExW(base, name, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) return res; + res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value, + lstrlenA(value) + 1); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * recursive_delete_key + */ +static LONG recursive_delete_key(HKEY key) +{ + LONG res; + WCHAR subkey_name[MAX_PATH]; + DWORD cName; + HKEY subkey; + + for (;;) { + cName = sizeof(subkey_name) / sizeof(WCHAR); + res = RegEnumKeyExW(key, 0, subkey_name, &cName, + NULL, NULL, NULL, NULL); + if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) { + res = ERROR_SUCCESS; /* presumably we're done enumerating */ + break; + } + res = RegOpenKeyExW(key, subkey_name, 0, + KEY_READ | KEY_WRITE, &subkey); + if (res == ERROR_FILE_NOT_FOUND) continue; + if (res != ERROR_SUCCESS) break; + + res = recursive_delete_key(subkey); + RegCloseKey(subkey); + if (res != ERROR_SUCCESS) break; + } + + if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0); + return res; +} + +/*********************************************************************** + * coclass list + */ +static GUID const CLSID_FileMoniker = { + 0x00000303, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; + +static GUID const CLSID_ItemMoniker = { + 0x00000304, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; + +/* FIXME: DfMarshal and PSFactoryBuffer are defined elsewhere too */ + +static GUID const CLSID_DfMarshal = { + 0x0000030B, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; + +static GUID const CLSID_PSFactoryBuffer = { + 0x00000320, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; + +static struct regsvr_coclass const coclass_list[] = { + { &CLSID_FileMoniker, + "FileMoniker", + NULL, + "ole32.dll", + "Both" + }, + { &CLSID_ItemMoniker, + "ItemMoniker", + NULL, + "ole32.dll", + "Both" + }, + { &CLSID_DfMarshal, + "DfMarshal", + NULL, + "ole32.dll", + "Both" + }, + { &CLSID_PSFactoryBuffer, + "PSFactoryBuffer", + NULL, + "ole32.dll", + "Both" + }, + { &CLSID_StdGlobalInterfaceTable, + "StdGlobalInterfaceTable", + NULL, + "ole32.dll", + "Apartment" + }, + { NULL } /* list terminator */ +}; + +/*********************************************************************** + * interface list + */ + +#define INTERFACE_ENTRY(interface, base, clsid32, clsid16) { &IID_##interface, #interface, base, sizeof(interface##Vtbl)/sizeof(void*), clsid16, clsid32 } +#define STD_INTERFACE_ENTRY(interface) INTERFACE_ENTRY(interface, NULL, &CLSID_PSFactoryBuffer, NULL) + +static struct regsvr_interface const interface_list[] = { + STD_INTERFACE_ENTRY(IUnknown), + STD_INTERFACE_ENTRY(IClassFactory), + STD_INTERFACE_ENTRY(IStorage), + STD_INTERFACE_ENTRY(IStream ), + STD_INTERFACE_ENTRY(IPersistStorage), + STD_INTERFACE_ENTRY(IDataObject), + STD_INTERFACE_ENTRY(IAdviseSink), + STD_INTERFACE_ENTRY(IOleObject), + STD_INTERFACE_ENTRY(IOleClientSite), + STD_INTERFACE_ENTRY(IRemUnknown), + { NULL } /* list terminator */ +}; + +/*********************************************************************** + * DllRegisterServer (OLE32.@) + */ +HRESULT WINAPI DllRegisterServer() +{ + HRESULT hr; + + TRACE("\n"); + + hr = register_coclasses(coclass_list); + if (SUCCEEDED(hr)) + hr = register_interfaces(interface_list); + return hr; +} + +/*********************************************************************** + * DllUnregisterServer (OLE32.@) + */ +HRESULT WINAPI DllUnregisterServer() +{ + HRESULT hr; + + TRACE("\n"); + + hr = unregister_coclasses(coclass_list); + if (SUCCEEDED(hr)) + hr = unregister_interfaces(interface_list); + return hr; +} diff --git a/reactos/lib/ole32/rpc.c b/reactos/lib/ole32/rpc.c index 19d1fe950a6..ea70611052c 100644 --- a/reactos/lib/ole32/rpc.c +++ b/reactos/lib/ole32/rpc.c @@ -1,884 +1,884 @@ -/* - * RPC Manager - * - * Copyright 2001 Ove KÃ¥ven, TransGaming Technologies - * Copyright 2002 Marcus Meissner - * Copyright 2005 Mike Hearn, Rob Shearman for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <stdlib.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> -#include <assert.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "winsvc.h" -#include "objbase.h" -#include "ole2.h" -#include "rpc.h" -#include "winerror.h" -#include "winreg.h" -#include "wtypes.h" -#include "wine/unicode.h" - -#include "compobj_private.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg); - -/* we only use one function to dispatch calls for all methods - we use the - * RPC_IF_OLE flag to tell the RPC runtime that this is the case */ -static RPC_DISPATCH_FUNCTION rpc_dispatch_table[1] = { dispatch_rpc }; /* (RO) */ -static RPC_DISPATCH_TABLE rpc_dispatch = { 1, rpc_dispatch_table }; /* (RO) */ - -static struct list registered_interfaces = LIST_INIT(registered_interfaces); /* (CS csRegIf) */ -static CRITICAL_SECTION csRegIf; -static CRITICAL_SECTION_DEBUG csRegIf_debug = -{ - 0, 0, &csRegIf, - { &csRegIf_debug.ProcessLocksList, &csRegIf_debug.ProcessLocksList }, - 0, 0, { 0, (DWORD)(__FILE__ ": dcom registered server interfaces") } -}; -static CRITICAL_SECTION csRegIf = { &csRegIf_debug, -1, 0, 0, 0, 0 }; - -static WCHAR wszPipeTransport[] = {'n','c','a','c','n','_','n','p',0}; - - -struct registered_if -{ - struct list entry; - DWORD refs; /* ref count */ - RPC_SERVER_INTERFACE If; /* interface registered with the RPC runtime */ -}; - -/* get the pipe endpoint specified of the specified apartment */ -static inline void get_rpc_endpoint(LPWSTR endpoint, const OXID *oxid) -{ - /* FIXME: should get endpoint from rpcss */ - static const WCHAR wszEndpointFormat[] = {'\\','p','i','p','e','\\','O','L','E','_','%','0','8','l','x','%','0','8','l','x',0}; - wsprintfW(endpoint, wszEndpointFormat, (DWORD)(*oxid >> 32),(DWORD)*oxid); -} - -typedef struct -{ - const IRpcChannelBufferVtbl *lpVtbl; - DWORD refs; -} RpcChannelBuffer; - -typedef struct -{ - RpcChannelBuffer super; /* superclass */ - - RPC_BINDING_HANDLE bind; /* handle to the remote server */ -} ClientRpcChannelBuffer; - -struct dispatch_params -{ - RPCOLEMESSAGE *msg; /* message */ - IRpcStubBuffer *stub; /* stub buffer, if applicable */ - IRpcChannelBuffer *chan; /* server channel buffer, if applicable */ - HANDLE handle; /* handle that will become signaled when call finishes */ - RPC_STATUS status; /* status (out) */ -}; - -static HRESULT WINAPI RpcChannelBuffer_QueryInterface(LPRPCCHANNELBUFFER iface, REFIID riid, LPVOID *ppv) -{ - *ppv = NULL; - if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown)) - { - *ppv = (LPVOID)iface; - IUnknown_AddRef(iface); - return S_OK; - } - return E_NOINTERFACE; -} - -static ULONG WINAPI RpcChannelBuffer_AddRef(LPRPCCHANNELBUFFER iface) -{ - RpcChannelBuffer *This = (RpcChannelBuffer *)iface; - return InterlockedIncrement(&This->refs); -} - -static ULONG WINAPI ServerRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface) -{ - RpcChannelBuffer *This = (RpcChannelBuffer *)iface; - ULONG ref; - - ref = InterlockedDecrement(&This->refs); - if (ref) - return ref; - - HeapFree(GetProcessHeap(), 0, This); - return 0; -} - -static ULONG WINAPI ClientRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface) -{ - ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface; - ULONG ref; - - ref = InterlockedDecrement(&This->super.refs); - if (ref) - return ref; - - RpcBindingFree(&This->bind); - HeapFree(GetProcessHeap(), 0, This); - return 0; -} - -static HRESULT WINAPI ServerRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid) -{ - RpcChannelBuffer *This = (RpcChannelBuffer *)iface; - RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; - RPC_STATUS status; - - TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid)); - - status = I_RpcGetBuffer(msg); - - TRACE("-- %ld\n", status); - - return HRESULT_FROM_WIN32(status); -} - -static HRESULT WINAPI ClientRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid) -{ - ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface; - RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; - RPC_CLIENT_INTERFACE *cif; - RPC_STATUS status; - - TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid)); - - cif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_CLIENT_INTERFACE)); - if (!cif) - return E_OUTOFMEMORY; - - cif->Length = sizeof(RPC_CLIENT_INTERFACE); - /* RPC interface ID = COM interface ID */ - cif->InterfaceId.SyntaxGUID = *riid; - /* COM objects always have a version of 0.0 */ - cif->InterfaceId.SyntaxVersion.MajorVersion = 0; - cif->InterfaceId.SyntaxVersion.MinorVersion = 0; - msg->RpcInterfaceInformation = cif; - msg->Handle = This->bind; - - status = I_RpcGetBuffer(msg); - - TRACE("-- %ld\n", status); - - return HRESULT_FROM_WIN32(status); -} - -/* this thread runs an outgoing RPC */ -static DWORD WINAPI rpc_sendreceive_thread(LPVOID param) -{ - struct dispatch_params *data = (struct dispatch_params *) param; - - /* FIXME: trap and rethrow RPC exceptions in app thread */ - data->status = I_RpcSendReceive((RPC_MESSAGE *)data->msg); - - TRACE("completed with status 0x%lx\n", data->status); - - return 0; -} - -static HRESULT WINAPI RpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus) -{ - HRESULT hr = S_OK; - RPC_STATUS status; - DWORD index; - struct dispatch_params *params; - DWORD tid; - - TRACE("(%p) iMethod=%ld\n", olemsg, olemsg->iMethod); - - params = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*params)); - if (!params) return E_OUTOFMEMORY; - - params->msg = olemsg; - params->status = RPC_S_OK; - - /* we use a separate thread here because we need to be able to - * pump the message loop in the application thread: if we do not, - * any windows created by this thread will hang and RPCs that try - * and re-enter this STA from an incoming server thread will - * deadlock. InstallShield is an example of that. - */ - params->handle = CreateThread(NULL, 0, rpc_sendreceive_thread, params, 0, &tid); - if (!params->handle) - { - ERR("Could not create RpcSendReceive thread, error %lx\n", GetLastError()); - hr = E_UNEXPECTED; - } - - if (hr == S_OK) - hr = CoWaitForMultipleHandles(0, INFINITE, 1, ¶ms->handle, &index); - CloseHandle(params->handle); - - status = params->status; - HeapFree(GetProcessHeap(), 0, params); - params = NULL; - - if (hr) return hr; - - if (pstatus) *pstatus = status; - - TRACE("RPC call status: 0x%lx\n", status); - if (status == RPC_S_OK) - hr = S_OK; - else if (status == RPC_S_CALL_FAILED) - hr = *(HRESULT *)olemsg->Buffer; - else - hr = HRESULT_FROM_WIN32(status); - - TRACE("-- 0x%08lx\n", hr); - - return hr; -} - -static HRESULT WINAPI ServerRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg) -{ - RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; - RPC_STATUS status; - - TRACE("(%p)\n", msg); - - status = I_RpcFreeBuffer(msg); - - TRACE("-- %ld\n", status); - - return HRESULT_FROM_WIN32(status); -} - -static HRESULT WINAPI ClientRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg) -{ - RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; - RPC_STATUS status; - - TRACE("(%p)\n", msg); - - status = I_RpcFreeBuffer(msg); - - HeapFree(GetProcessHeap(), 0, msg->RpcInterfaceInformation); - msg->RpcInterfaceInformation = NULL; - - TRACE("-- %ld\n", status); - - return HRESULT_FROM_WIN32(status); -} - -static HRESULT WINAPI RpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext) -{ - FIXME("(%p,%p), stub!\n", pdwDestContext, ppvDestContext); - return E_FAIL; -} - -static HRESULT WINAPI RpcChannelBuffer_IsConnected(LPRPCCHANNELBUFFER iface) -{ - TRACE("()\n"); - /* native does nothing too */ - return S_OK; -} - -static const IRpcChannelBufferVtbl ClientRpcChannelBufferVtbl = -{ - RpcChannelBuffer_QueryInterface, - RpcChannelBuffer_AddRef, - ClientRpcChannelBuffer_Release, - ClientRpcChannelBuffer_GetBuffer, - RpcChannelBuffer_SendReceive, - ClientRpcChannelBuffer_FreeBuffer, - RpcChannelBuffer_GetDestCtx, - RpcChannelBuffer_IsConnected -}; - -static const IRpcChannelBufferVtbl ServerRpcChannelBufferVtbl = -{ - RpcChannelBuffer_QueryInterface, - RpcChannelBuffer_AddRef, - ServerRpcChannelBuffer_Release, - ServerRpcChannelBuffer_GetBuffer, - RpcChannelBuffer_SendReceive, - ServerRpcChannelBuffer_FreeBuffer, - RpcChannelBuffer_GetDestCtx, - RpcChannelBuffer_IsConnected -}; - -/* returns a channel buffer for proxies */ -HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, IRpcChannelBuffer **chan) -{ - ClientRpcChannelBuffer *This; - WCHAR endpoint[200]; - RPC_BINDING_HANDLE bind; - RPC_STATUS status; - LPWSTR string_binding; - - /* connect to the apartment listener thread */ - get_rpc_endpoint(endpoint, oxid); - - TRACE("proxy pipe: connecting to endpoint: %s\n", debugstr_w(endpoint)); - - status = RpcStringBindingComposeW( - NULL, - wszPipeTransport, - NULL, - endpoint, - NULL, - &string_binding); - - if (status == RPC_S_OK) - { - status = RpcBindingFromStringBindingW(string_binding, &bind); - - if (status == RPC_S_OK) - { - IPID ipid2 = *ipid; /* why can't RpcBindingSetObject take a const? */ - status = RpcBindingSetObject(bind, &ipid2); - if (status != RPC_S_OK) - RpcBindingFree(&bind); - } - - RpcStringFreeW(&string_binding); - } - - if (status != RPC_S_OK) - { - ERR("Couldn't get binding for endpoint %s, status = %ld\n", debugstr_w(endpoint), status); - return HRESULT_FROM_WIN32(status); - } - - This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); - if (!This) - { - RpcBindingFree(&bind); - return E_OUTOFMEMORY; - } - - This->super.lpVtbl = &ClientRpcChannelBufferVtbl; - This->super.refs = 1; - This->bind = bind; - - *chan = (IRpcChannelBuffer*)This; - - return S_OK; -} - -HRESULT RPC_CreateServerChannel(IRpcChannelBuffer **chan) -{ - RpcChannelBuffer *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); - if (!This) - return E_OUTOFMEMORY; - - This->lpVtbl = &ServerRpcChannelBufferVtbl; - This->refs = 1; - - *chan = (IRpcChannelBuffer*)This; - - return S_OK; -} - - -HRESULT RPC_ExecuteCall(struct dispatch_params *params) -{ - HRESULT hr = IRpcStubBuffer_Invoke(params->stub, params->msg, params->chan); - IRpcStubBuffer_Release(params->stub); - if (params->handle) SetEvent(params->handle); - return hr; -} - -static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg) -{ - struct dispatch_params *params; - IRpcStubBuffer *stub; - APARTMENT *apt; - IPID ipid; - - RpcBindingInqObject(msg->Handle, &ipid); - - TRACE("ipid = %s, iMethod = %d\n", debugstr_guid(&ipid), msg->ProcNum); - - params = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*params)); - if (!params) return RpcRaiseException(E_OUTOFMEMORY); - - stub = ipid_to_apt_and_stubbuffer(&ipid, &apt); - if (!apt || !stub) - { - if (apt) apartment_release(apt); - /* ipid_to_apt_and_stubbuffer will already have logged the error */ - return RpcRaiseException(RPC_E_DISCONNECTED); - } - - params->msg = (RPCOLEMESSAGE *)msg; - params->stub = stub; - params->chan = NULL; /* FIXME: pass server channel */ - params->status = RPC_S_OK; - - /* Note: this is the important difference between STAs and MTAs - we - * always execute RPCs to STAs in the thread that originally created the - * apartment (i.e. the one that pumps messages to the window) */ - if (apt->model & COINIT_APARTMENTTHREADED) - { - params->handle = CreateEventW(NULL, FALSE, FALSE, NULL); - - TRACE("Calling apartment thread 0x%08lx...\n", apt->tid); - - PostMessageW(apt->win, DM_EXECUTERPC, 0, (LPARAM)params); - WaitForSingleObject(params->handle, INFINITE); - CloseHandle(params->handle); - } - else - RPC_ExecuteCall(params); - - HeapFree(GetProcessHeap(), 0, params); - - apartment_release(apt); -} - -/* stub registration */ -HRESULT RPC_RegisterInterface(REFIID riid) -{ - struct registered_if *rif; - BOOL found = FALSE; - HRESULT hr = S_OK; - - TRACE("(%s)\n", debugstr_guid(riid)); - - EnterCriticalSection(&csRegIf); - LIST_FOR_EACH_ENTRY(rif, ®istered_interfaces, struct registered_if, entry) - { - if (IsEqualGUID(&rif->If.InterfaceId.SyntaxGUID, riid)) - { - rif->refs++; - found = TRUE; - break; - } - } - if (!found) - { - TRACE("Creating new interface\n"); - - rif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*rif)); - if (rif) - { - RPC_STATUS status; - - rif->refs = 1; - rif->If.Length = sizeof(RPC_SERVER_INTERFACE); - /* RPC interface ID = COM interface ID */ - rif->If.InterfaceId.SyntaxGUID = *riid; - rif->If.DispatchTable = &rpc_dispatch; - /* all other fields are 0, including the version asCOM objects - * always have a version of 0.0 */ - status = RpcServerRegisterIfEx( - (RPC_IF_HANDLE)&rif->If, - NULL, NULL, - RPC_IF_OLE | RPC_IF_AUTOLISTEN, - RPC_C_LISTEN_MAX_CALLS_DEFAULT, - NULL); - if (status == RPC_S_OK) - list_add_tail(®istered_interfaces, &rif->entry); - else - { - ERR("RpcServerRegisterIfEx failed with error %ld\n", status); - HeapFree(GetProcessHeap(), 0, rif); - hr = HRESULT_FROM_WIN32(status); - } - } - else - hr = E_OUTOFMEMORY; - } - LeaveCriticalSection(&csRegIf); - return hr; -} - -/* stub unregistration */ -void RPC_UnregisterInterface(REFIID riid) -{ - struct registered_if *rif; - EnterCriticalSection(&csRegIf); - LIST_FOR_EACH_ENTRY(rif, ®istered_interfaces, struct registered_if, entry) - { - if (IsEqualGUID(&rif->If.InterfaceId.SyntaxGUID, riid)) - { - if (!--rif->refs) - { -#if 0 /* this is a stub in builtin and spams the console with FIXME's */ - IID iid = *riid; /* RpcServerUnregisterIf doesn't take const IID */ - RpcServerUnregisterIf((RPC_IF_HANDLE)&rif->If, &iid, 0); - list_remove(&rif->entry); - HeapFree(GetProcessHeap(), 0, rif); -#endif - } - break; - } - } - LeaveCriticalSection(&csRegIf); -} - -/* make the apartment reachable by other threads and processes and create the - * IRemUnknown object */ -void RPC_StartRemoting(struct apartment *apt) -{ - if (!InterlockedExchange(&apt->remoting_started, TRUE)) - { - WCHAR endpoint[200]; - RPC_STATUS status; - - get_rpc_endpoint(endpoint, &apt->oxid); - - status = RpcServerUseProtseqEpW( - wszPipeTransport, - RPC_C_PROTSEQ_MAX_REQS_DEFAULT, - endpoint, - NULL); - if (status != RPC_S_OK) - ERR("Couldn't register endpoint %s\n", debugstr_w(endpoint)); - - /* FIXME: move remote unknown exporting into this function */ - } - start_apartment_remote_unknown(); -} - - -static HRESULT create_server(REFCLSID rclsid) -{ - static const WCHAR embedding[] = { ' ', '-','E','m','b','e','d','d','i','n','g',0 }; - HKEY key; - char buf[200]; - HRESULT hres = E_UNEXPECTED; - char xclsid[80]; - WCHAR exe[MAX_PATH+1]; - DWORD exelen = sizeof(exe); - WCHAR command[MAX_PATH+sizeof(embedding)/sizeof(WCHAR)]; - STARTUPINFOW sinfo; - PROCESS_INFORMATION pinfo; - - WINE_StringFromCLSID((LPCLSID)rclsid,xclsid); - - sprintf(buf,"CLSID\\%s\\LocalServer32",xclsid); - hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, buf, 0, KEY_READ, &key); - - if (hres != ERROR_SUCCESS) { - WARN("CLSID %s not registered as LocalServer32\n", xclsid); - return REGDB_E_READREGDB; /* Probably */ - } - - memset(exe,0,sizeof(exe)); - hres= RegQueryValueExW(key, NULL, NULL, NULL, (LPBYTE)exe, &exelen); - RegCloseKey(key); - if (hres) { - WARN("No default value for LocalServer32 key\n"); - return REGDB_E_CLASSNOTREG; /* FIXME: check retval */ - } - - memset(&sinfo,0,sizeof(sinfo)); - sinfo.cb = sizeof(sinfo); - - /* EXE servers are started with the -Embedding switch. MSDN also claims /Embedding is used, - * 9x does -Embedding, perhaps an 9x/NT difference? - */ - - strcpyW(command, exe); - strcatW(command, embedding); - - TRACE("activating local server '%s' for %s\n", debugstr_w(command), xclsid); - - if (!CreateProcessW(exe, command, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo)) { - WARN("failed to run local server %s\n", debugstr_w(exe)); - return HRESULT_FROM_WIN32(GetLastError()); - } - CloseHandle(pinfo.hProcess); - CloseHandle(pinfo.hThread); - - return S_OK; -} - -/* - * start_local_service() - start a service given its name and parameters - */ -static DWORD start_local_service(LPCWSTR name, DWORD num, LPWSTR *params) -{ - SC_HANDLE handle, hsvc; - DWORD r = ERROR_FUNCTION_FAILED; - - TRACE("Starting service %s %ld params\n", debugstr_w(name), num); - - handle = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); - if (!handle) - return r; - hsvc = OpenServiceW(handle, name, SC_MANAGER_ALL_ACCESS); - if (hsvc) - { - if(StartServiceW(hsvc, num, (LPCWSTR*)params)) - r = ERROR_SUCCESS; - else - r = GetLastError(); - if (r == ERROR_SERVICE_ALREADY_RUNNING) - r = ERROR_SUCCESS; - CloseServiceHandle(hsvc); - } - CloseServiceHandle(handle); - - TRACE("StartService returned error %ld (%s)\n", r, r?"ok":"failed"); - - return r; -} - -/* - * create_local_service() - start a COM server in a service - * - * To start a Local Service, we read the AppID value under - * the class's CLSID key, then open the HKCR\\AppId key specified - * there and check for a LocalService value. - * - * Note: Local Services are not supported under Windows 9x - */ -static HRESULT create_local_service(REFCLSID rclsid) -{ - HRESULT hres = REGDB_E_READREGDB; - WCHAR buf[40], keyname[50]; - static const WCHAR szClsId[] = { 'C','L','S','I','D','\\',0 }; - static const WCHAR szAppId[] = { 'A','p','p','I','d',0 }; - static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 }; - static const WCHAR szLocalService[] = { 'L','o','c','a','l','S','e','r','v','i','c','e',0 }; - static const WCHAR szServiceParams[] = {'S','e','r','v','i','c','e','P','a','r','a','m','s',0}; - HKEY hkey; - LONG r; - DWORD type, sz; - - TRACE("Attempting to start Local service for %s\n", debugstr_guid(rclsid)); - - /* read the AppID value under the class's key */ - strcpyW(keyname,szClsId); - StringFromGUID2(rclsid,&keyname[6],39); - r = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &hkey); - if (r!=ERROR_SUCCESS) - return hres; - sz = sizeof buf; - r = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &sz); - RegCloseKey(hkey); - if (r!=ERROR_SUCCESS || type!=REG_SZ) - return hres; - - /* read the LocalService and ServiceParameters values from the AppID key */ - strcpyW(keyname, szAppIdKey); - strcatW(keyname, buf); - r = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &hkey); - if (r!=ERROR_SUCCESS) - return hres; - sz = sizeof buf; - r = RegQueryValueExW(hkey, szLocalService, NULL, &type, (LPBYTE)buf, &sz); - if (r==ERROR_SUCCESS && type==REG_SZ) - { - DWORD num_args = 0; - LPWSTR args[1] = { NULL }; - - /* - * FIXME: I'm not really sure how to deal with the service parameters. - * I suspect that the string returned from RegQueryValueExW - * should be split into a number of arguments by spaces. - * It would make more sense if ServiceParams contained a - * REG_MULTI_SZ here, but it's a REG_SZ for the services - * that I'm interested in for the moment. - */ - r = RegQueryValueExW(hkey, szServiceParams, NULL, &type, NULL, &sz); - if (r == ERROR_SUCCESS && type == REG_SZ && sz) - { - args[0] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz); - num_args++; - RegQueryValueExW(hkey, szServiceParams, NULL, &type, (LPBYTE)args[0], &sz); - } - r = start_local_service(buf, num_args, args); - if (r==ERROR_SUCCESS) - hres = S_OK; - HeapFree(GetProcessHeap(),0,args[0]); - } - RegCloseKey(hkey); - - return hres; -} - -#define PIPEPREF "\\\\.\\pipe\\" - -/* FIXME: should call to rpcss instead */ -HRESULT RPC_GetLocalClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv) -{ - HRESULT hres; - HANDLE hPipe; - char pipefn[200]; - DWORD res, bufferlen; - char marshalbuffer[200]; - IStream *pStm; - LARGE_INTEGER seekto; - ULARGE_INTEGER newpos; - int tries = 0; - - static const int MAXTRIES = 30; /* 30 seconds */ - - TRACE("rclsid=%s, iid=%s\n", debugstr_guid(rclsid), debugstr_guid(iid)); - - strcpy(pipefn,PIPEPREF); - WINE_StringFromCLSID(rclsid,pipefn+strlen(PIPEPREF)); - - while (tries++ < MAXTRIES) { - TRACE("waiting for %s\n", pipefn); - - WaitNamedPipeA( pipefn, NMPWAIT_WAIT_FOREVER ); - hPipe = CreateFileA(pipefn, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); - if (hPipe == INVALID_HANDLE_VALUE) { - if (tries == 1) { - if ( (hres = create_server(rclsid)) && - (hres = create_local_service(rclsid)) ) - return hres; - Sleep(1000); - } else { - WARN("Connecting to %s, no response yet, retrying: le is %lx\n",pipefn,GetLastError()); - Sleep(1000); - } - continue; - } - bufferlen = 0; - if (!ReadFile(hPipe,marshalbuffer,sizeof(marshalbuffer),&bufferlen,NULL)) { - FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid)); - Sleep(1000); - continue; - } - TRACE("read marshal id from pipe\n"); - CloseHandle(hPipe); - break; - } - - if (tries >= MAXTRIES) - return E_NOINTERFACE; - - hres = CreateStreamOnHGlobal(0,TRUE,&pStm); - if (hres) return hres; - hres = IStream_Write(pStm,marshalbuffer,bufferlen,&res); - if (hres) goto out; - seekto.u.LowPart = 0;seekto.u.HighPart = 0; - hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); - - TRACE("unmarshalling classfactory\n"); - hres = CoUnmarshalInterface(pStm,&IID_IClassFactory,ppv); -out: - IStream_Release(pStm); - return hres; -} - - -struct local_server_params -{ - CLSID clsid; - IStream *stream; -}; - -/* FIXME: should call to rpcss instead */ -static DWORD WINAPI local_server_thread(LPVOID param) -{ - struct local_server_params * lsp = (struct local_server_params *)param; - HANDLE hPipe; - char pipefn[200]; - HRESULT hres; - IStream *pStm = lsp->stream; - STATSTG ststg; - unsigned char *buffer; - int buflen; - LARGE_INTEGER seekto; - ULARGE_INTEGER newpos; - ULONG res; - - TRACE("Starting threader for %s.\n",debugstr_guid(&lsp->clsid)); - - strcpy(pipefn,PIPEPREF); - WINE_StringFromCLSID(&lsp->clsid,pipefn+strlen(PIPEPREF)); - - HeapFree(GetProcessHeap(), 0, lsp); - - hPipe = CreateNamedPipeA( pipefn, PIPE_ACCESS_DUPLEX, - PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, - 4096, 4096, 500 /* 0.5 second timeout */, NULL ); - - if (hPipe == INVALID_HANDLE_VALUE) - { - FIXME("pipe creation failed for %s, le is %ld\n",pipefn,GetLastError()); - return 1; - } - - while (1) { - if (!ConnectNamedPipe(hPipe,NULL)) { - ERR("Failure during ConnectNamedPipe %ld, ABORT!\n",GetLastError()); - break; - } - - TRACE("marshalling IClassFactory to client\n"); - - hres = IStream_Stat(pStm,&ststg,0); - if (hres) return hres; - - buflen = ststg.cbSize.u.LowPart; - buffer = HeapAlloc(GetProcessHeap(),0,buflen); - seekto.u.LowPart = 0; - seekto.u.HighPart = 0; - hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); - if (hres) { - FIXME("IStream_Seek failed, %lx\n",hres); - return hres; - } - - hres = IStream_Read(pStm,buffer,buflen,&res); - if (hres) { - FIXME("Stream Read failed, %lx\n",hres); - return hres; - } - - WriteFile(hPipe,buffer,buflen,&res,NULL); - FlushFileBuffers(hPipe); - DisconnectNamedPipe(hPipe); - - TRACE("done marshalling IClassFactory\n"); - } - CloseHandle(hPipe); - IStream_Release(pStm); - return 0; -} - -void RPC_StartLocalServer(REFCLSID clsid, IStream *stream) -{ - DWORD tid; - HANDLE thread; - struct local_server_params *lsp = HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp)); - - lsp->clsid = *clsid; - lsp->stream = stream; - - thread = CreateThread(NULL, 0, local_server_thread, lsp, 0, &tid); - CloseHandle(thread); - /* FIXME: failure handling */ -} +/* + * RPC Manager + * + * Copyright 2001 Ove KÃ¥ven, TransGaming Technologies + * Copyright 2002 Marcus Meissner + * Copyright 2005 Mike Hearn, Rob Shearman for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winsvc.h" +#include "objbase.h" +#include "ole2.h" +#include "rpc.h" +#include "winerror.h" +#include "winreg.h" +#include "wtypes.h" +#include "wine/unicode.h" + +#include "compobj_private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg); + +/* we only use one function to dispatch calls for all methods - we use the + * RPC_IF_OLE flag to tell the RPC runtime that this is the case */ +static RPC_DISPATCH_FUNCTION rpc_dispatch_table[1] = { dispatch_rpc }; /* (RO) */ +static RPC_DISPATCH_TABLE rpc_dispatch = { 1, rpc_dispatch_table }; /* (RO) */ + +static struct list registered_interfaces = LIST_INIT(registered_interfaces); /* (CS csRegIf) */ +static CRITICAL_SECTION csRegIf; +static CRITICAL_SECTION_DEBUG csRegIf_debug = +{ + 0, 0, &csRegIf, + { &csRegIf_debug.ProcessLocksList, &csRegIf_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": dcom registered server interfaces") } +}; +static CRITICAL_SECTION csRegIf = { &csRegIf_debug, -1, 0, 0, 0, 0 }; + +static WCHAR wszPipeTransport[] = {'n','c','a','c','n','_','n','p',0}; + + +struct registered_if +{ + struct list entry; + DWORD refs; /* ref count */ + RPC_SERVER_INTERFACE If; /* interface registered with the RPC runtime */ +}; + +/* get the pipe endpoint specified of the specified apartment */ +static inline void get_rpc_endpoint(LPWSTR endpoint, const OXID *oxid) +{ + /* FIXME: should get endpoint from rpcss */ + static const WCHAR wszEndpointFormat[] = {'\\','p','i','p','e','\\','O','L','E','_','%','0','8','l','x','%','0','8','l','x',0}; + wsprintfW(endpoint, wszEndpointFormat, (DWORD)(*oxid >> 32),(DWORD)*oxid); +} + +typedef struct +{ + const IRpcChannelBufferVtbl *lpVtbl; + DWORD refs; +} RpcChannelBuffer; + +typedef struct +{ + RpcChannelBuffer super; /* superclass */ + + RPC_BINDING_HANDLE bind; /* handle to the remote server */ +} ClientRpcChannelBuffer; + +struct dispatch_params +{ + RPCOLEMESSAGE *msg; /* message */ + IRpcStubBuffer *stub; /* stub buffer, if applicable */ + IRpcChannelBuffer *chan; /* server channel buffer, if applicable */ + HANDLE handle; /* handle that will become signaled when call finishes */ + RPC_STATUS status; /* status (out) */ +}; + +static HRESULT WINAPI RpcChannelBuffer_QueryInterface(LPRPCCHANNELBUFFER iface, REFIID riid, LPVOID *ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown)) + { + *ppv = (LPVOID)iface; + IUnknown_AddRef(iface); + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI RpcChannelBuffer_AddRef(LPRPCCHANNELBUFFER iface) +{ + RpcChannelBuffer *This = (RpcChannelBuffer *)iface; + return InterlockedIncrement(&This->refs); +} + +static ULONG WINAPI ServerRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface) +{ + RpcChannelBuffer *This = (RpcChannelBuffer *)iface; + ULONG ref; + + ref = InterlockedDecrement(&This->refs); + if (ref) + return ref; + + HeapFree(GetProcessHeap(), 0, This); + return 0; +} + +static ULONG WINAPI ClientRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface) +{ + ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface; + ULONG ref; + + ref = InterlockedDecrement(&This->super.refs); + if (ref) + return ref; + + RpcBindingFree(&This->bind); + HeapFree(GetProcessHeap(), 0, This); + return 0; +} + +static HRESULT WINAPI ServerRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid) +{ + RpcChannelBuffer *This = (RpcChannelBuffer *)iface; + RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; + RPC_STATUS status; + + TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid)); + + status = I_RpcGetBuffer(msg); + + TRACE("-- %ld\n", status); + + return HRESULT_FROM_WIN32(status); +} + +static HRESULT WINAPI ClientRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid) +{ + ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface; + RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; + RPC_CLIENT_INTERFACE *cif; + RPC_STATUS status; + + TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid)); + + cif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_CLIENT_INTERFACE)); + if (!cif) + return E_OUTOFMEMORY; + + cif->Length = sizeof(RPC_CLIENT_INTERFACE); + /* RPC interface ID = COM interface ID */ + cif->InterfaceId.SyntaxGUID = *riid; + /* COM objects always have a version of 0.0 */ + cif->InterfaceId.SyntaxVersion.MajorVersion = 0; + cif->InterfaceId.SyntaxVersion.MinorVersion = 0; + msg->RpcInterfaceInformation = cif; + msg->Handle = This->bind; + + status = I_RpcGetBuffer(msg); + + TRACE("-- %ld\n", status); + + return HRESULT_FROM_WIN32(status); +} + +/* this thread runs an outgoing RPC */ +static DWORD WINAPI rpc_sendreceive_thread(LPVOID param) +{ + struct dispatch_params *data = (struct dispatch_params *) param; + + /* FIXME: trap and rethrow RPC exceptions in app thread */ + data->status = I_RpcSendReceive((RPC_MESSAGE *)data->msg); + + TRACE("completed with status 0x%lx\n", data->status); + + return 0; +} + +static HRESULT WINAPI RpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus) +{ + HRESULT hr = S_OK; + RPC_STATUS status; + DWORD index; + struct dispatch_params *params; + DWORD tid; + + TRACE("(%p) iMethod=%ld\n", olemsg, olemsg->iMethod); + + params = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*params)); + if (!params) return E_OUTOFMEMORY; + + params->msg = olemsg; + params->status = RPC_S_OK; + + /* we use a separate thread here because we need to be able to + * pump the message loop in the application thread: if we do not, + * any windows created by this thread will hang and RPCs that try + * and re-enter this STA from an incoming server thread will + * deadlock. InstallShield is an example of that. + */ + params->handle = CreateThread(NULL, 0, rpc_sendreceive_thread, params, 0, &tid); + if (!params->handle) + { + ERR("Could not create RpcSendReceive thread, error %lx\n", GetLastError()); + hr = E_UNEXPECTED; + } + + if (hr == S_OK) + hr = CoWaitForMultipleHandles(0, INFINITE, 1, ¶ms->handle, &index); + CloseHandle(params->handle); + + status = params->status; + HeapFree(GetProcessHeap(), 0, params); + params = NULL; + + if (hr) return hr; + + if (pstatus) *pstatus = status; + + TRACE("RPC call status: 0x%lx\n", status); + if (status == RPC_S_OK) + hr = S_OK; + else if (status == RPC_S_CALL_FAILED) + hr = *(HRESULT *)olemsg->Buffer; + else + hr = HRESULT_FROM_WIN32(status); + + TRACE("-- 0x%08lx\n", hr); + + return hr; +} + +static HRESULT WINAPI ServerRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg) +{ + RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; + RPC_STATUS status; + + TRACE("(%p)\n", msg); + + status = I_RpcFreeBuffer(msg); + + TRACE("-- %ld\n", status); + + return HRESULT_FROM_WIN32(status); +} + +static HRESULT WINAPI ClientRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg) +{ + RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; + RPC_STATUS status; + + TRACE("(%p)\n", msg); + + status = I_RpcFreeBuffer(msg); + + HeapFree(GetProcessHeap(), 0, msg->RpcInterfaceInformation); + msg->RpcInterfaceInformation = NULL; + + TRACE("-- %ld\n", status); + + return HRESULT_FROM_WIN32(status); +} + +static HRESULT WINAPI RpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext) +{ + FIXME("(%p,%p), stub!\n", pdwDestContext, ppvDestContext); + return E_FAIL; +} + +static HRESULT WINAPI RpcChannelBuffer_IsConnected(LPRPCCHANNELBUFFER iface) +{ + TRACE("()\n"); + /* native does nothing too */ + return S_OK; +} + +static const IRpcChannelBufferVtbl ClientRpcChannelBufferVtbl = +{ + RpcChannelBuffer_QueryInterface, + RpcChannelBuffer_AddRef, + ClientRpcChannelBuffer_Release, + ClientRpcChannelBuffer_GetBuffer, + RpcChannelBuffer_SendReceive, + ClientRpcChannelBuffer_FreeBuffer, + RpcChannelBuffer_GetDestCtx, + RpcChannelBuffer_IsConnected +}; + +static const IRpcChannelBufferVtbl ServerRpcChannelBufferVtbl = +{ + RpcChannelBuffer_QueryInterface, + RpcChannelBuffer_AddRef, + ServerRpcChannelBuffer_Release, + ServerRpcChannelBuffer_GetBuffer, + RpcChannelBuffer_SendReceive, + ServerRpcChannelBuffer_FreeBuffer, + RpcChannelBuffer_GetDestCtx, + RpcChannelBuffer_IsConnected +}; + +/* returns a channel buffer for proxies */ +HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, IRpcChannelBuffer **chan) +{ + ClientRpcChannelBuffer *This; + WCHAR endpoint[200]; + RPC_BINDING_HANDLE bind; + RPC_STATUS status; + LPWSTR string_binding; + + /* connect to the apartment listener thread */ + get_rpc_endpoint(endpoint, oxid); + + TRACE("proxy pipe: connecting to endpoint: %s\n", debugstr_w(endpoint)); + + status = RpcStringBindingComposeW( + NULL, + wszPipeTransport, + NULL, + endpoint, + NULL, + &string_binding); + + if (status == RPC_S_OK) + { + status = RpcBindingFromStringBindingW(string_binding, &bind); + + if (status == RPC_S_OK) + { + IPID ipid2 = *ipid; /* why can't RpcBindingSetObject take a const? */ + status = RpcBindingSetObject(bind, &ipid2); + if (status != RPC_S_OK) + RpcBindingFree(&bind); + } + + RpcStringFreeW(&string_binding); + } + + if (status != RPC_S_OK) + { + ERR("Couldn't get binding for endpoint %s, status = %ld\n", debugstr_w(endpoint), status); + return HRESULT_FROM_WIN32(status); + } + + This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + if (!This) + { + RpcBindingFree(&bind); + return E_OUTOFMEMORY; + } + + This->super.lpVtbl = &ClientRpcChannelBufferVtbl; + This->super.refs = 1; + This->bind = bind; + + *chan = (IRpcChannelBuffer*)This; + + return S_OK; +} + +HRESULT RPC_CreateServerChannel(IRpcChannelBuffer **chan) +{ + RpcChannelBuffer *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + if (!This) + return E_OUTOFMEMORY; + + This->lpVtbl = &ServerRpcChannelBufferVtbl; + This->refs = 1; + + *chan = (IRpcChannelBuffer*)This; + + return S_OK; +} + + +HRESULT RPC_ExecuteCall(struct dispatch_params *params) +{ + HRESULT hr = IRpcStubBuffer_Invoke(params->stub, params->msg, params->chan); + IRpcStubBuffer_Release(params->stub); + if (params->handle) SetEvent(params->handle); + return hr; +} + +static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg) +{ + struct dispatch_params *params; + IRpcStubBuffer *stub; + APARTMENT *apt; + IPID ipid; + + RpcBindingInqObject(msg->Handle, &ipid); + + TRACE("ipid = %s, iMethod = %d\n", debugstr_guid(&ipid), msg->ProcNum); + + params = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*params)); + if (!params) return RpcRaiseException(E_OUTOFMEMORY); + + stub = ipid_to_apt_and_stubbuffer(&ipid, &apt); + if (!apt || !stub) + { + if (apt) apartment_release(apt); + /* ipid_to_apt_and_stubbuffer will already have logged the error */ + return RpcRaiseException(RPC_E_DISCONNECTED); + } + + params->msg = (RPCOLEMESSAGE *)msg; + params->stub = stub; + params->chan = NULL; /* FIXME: pass server channel */ + params->status = RPC_S_OK; + + /* Note: this is the important difference between STAs and MTAs - we + * always execute RPCs to STAs in the thread that originally created the + * apartment (i.e. the one that pumps messages to the window) */ + if (apt->model & COINIT_APARTMENTTHREADED) + { + params->handle = CreateEventW(NULL, FALSE, FALSE, NULL); + + TRACE("Calling apartment thread 0x%08lx...\n", apt->tid); + + PostMessageW(apt->win, DM_EXECUTERPC, 0, (LPARAM)params); + WaitForSingleObject(params->handle, INFINITE); + CloseHandle(params->handle); + } + else + RPC_ExecuteCall(params); + + HeapFree(GetProcessHeap(), 0, params); + + apartment_release(apt); +} + +/* stub registration */ +HRESULT RPC_RegisterInterface(REFIID riid) +{ + struct registered_if *rif; + BOOL found = FALSE; + HRESULT hr = S_OK; + + TRACE("(%s)\n", debugstr_guid(riid)); + + EnterCriticalSection(&csRegIf); + LIST_FOR_EACH_ENTRY(rif, ®istered_interfaces, struct registered_if, entry) + { + if (IsEqualGUID(&rif->If.InterfaceId.SyntaxGUID, riid)) + { + rif->refs++; + found = TRUE; + break; + } + } + if (!found) + { + TRACE("Creating new interface\n"); + + rif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*rif)); + if (rif) + { + RPC_STATUS status; + + rif->refs = 1; + rif->If.Length = sizeof(RPC_SERVER_INTERFACE); + /* RPC interface ID = COM interface ID */ + rif->If.InterfaceId.SyntaxGUID = *riid; + rif->If.DispatchTable = &rpc_dispatch; + /* all other fields are 0, including the version asCOM objects + * always have a version of 0.0 */ + status = RpcServerRegisterIfEx( + (RPC_IF_HANDLE)&rif->If, + NULL, NULL, + RPC_IF_OLE | RPC_IF_AUTOLISTEN, + RPC_C_LISTEN_MAX_CALLS_DEFAULT, + NULL); + if (status == RPC_S_OK) + list_add_tail(®istered_interfaces, &rif->entry); + else + { + ERR("RpcServerRegisterIfEx failed with error %ld\n", status); + HeapFree(GetProcessHeap(), 0, rif); + hr = HRESULT_FROM_WIN32(status); + } + } + else + hr = E_OUTOFMEMORY; + } + LeaveCriticalSection(&csRegIf); + return hr; +} + +/* stub unregistration */ +void RPC_UnregisterInterface(REFIID riid) +{ + struct registered_if *rif; + EnterCriticalSection(&csRegIf); + LIST_FOR_EACH_ENTRY(rif, ®istered_interfaces, struct registered_if, entry) + { + if (IsEqualGUID(&rif->If.InterfaceId.SyntaxGUID, riid)) + { + if (!--rif->refs) + { +#if 0 /* this is a stub in builtin and spams the console with FIXME's */ + IID iid = *riid; /* RpcServerUnregisterIf doesn't take const IID */ + RpcServerUnregisterIf((RPC_IF_HANDLE)&rif->If, &iid, 0); + list_remove(&rif->entry); + HeapFree(GetProcessHeap(), 0, rif); +#endif + } + break; + } + } + LeaveCriticalSection(&csRegIf); +} + +/* make the apartment reachable by other threads and processes and create the + * IRemUnknown object */ +void RPC_StartRemoting(struct apartment *apt) +{ + if (!InterlockedExchange(&apt->remoting_started, TRUE)) + { + WCHAR endpoint[200]; + RPC_STATUS status; + + get_rpc_endpoint(endpoint, &apt->oxid); + + status = RpcServerUseProtseqEpW( + wszPipeTransport, + RPC_C_PROTSEQ_MAX_REQS_DEFAULT, + endpoint, + NULL); + if (status != RPC_S_OK) + ERR("Couldn't register endpoint %s\n", debugstr_w(endpoint)); + + /* FIXME: move remote unknown exporting into this function */ + } + start_apartment_remote_unknown(); +} + + +static HRESULT create_server(REFCLSID rclsid) +{ + static const WCHAR embedding[] = { ' ', '-','E','m','b','e','d','d','i','n','g',0 }; + HKEY key; + char buf[200]; + HRESULT hres = E_UNEXPECTED; + char xclsid[80]; + WCHAR exe[MAX_PATH+1]; + DWORD exelen = sizeof(exe); + WCHAR command[MAX_PATH+sizeof(embedding)/sizeof(WCHAR)]; + STARTUPINFOW sinfo; + PROCESS_INFORMATION pinfo; + + WINE_StringFromCLSID((LPCLSID)rclsid,xclsid); + + sprintf(buf,"CLSID\\%s\\LocalServer32",xclsid); + hres = RegOpenKeyExA(HKEY_CLASSES_ROOT, buf, 0, KEY_READ, &key); + + if (hres != ERROR_SUCCESS) { + WARN("CLSID %s not registered as LocalServer32\n", xclsid); + return REGDB_E_READREGDB; /* Probably */ + } + + memset(exe,0,sizeof(exe)); + hres= RegQueryValueExW(key, NULL, NULL, NULL, (LPBYTE)exe, &exelen); + RegCloseKey(key); + if (hres) { + WARN("No default value for LocalServer32 key\n"); + return REGDB_E_CLASSNOTREG; /* FIXME: check retval */ + } + + memset(&sinfo,0,sizeof(sinfo)); + sinfo.cb = sizeof(sinfo); + + /* EXE servers are started with the -Embedding switch. MSDN also claims /Embedding is used, + * 9x does -Embedding, perhaps an 9x/NT difference? + */ + + strcpyW(command, exe); + strcatW(command, embedding); + + TRACE("activating local server '%s' for %s\n", debugstr_w(command), xclsid); + + if (!CreateProcessW(exe, command, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo)) { + WARN("failed to run local server %s\n", debugstr_w(exe)); + return HRESULT_FROM_WIN32(GetLastError()); + } + CloseHandle(pinfo.hProcess); + CloseHandle(pinfo.hThread); + + return S_OK; +} + +/* + * start_local_service() - start a service given its name and parameters + */ +static DWORD start_local_service(LPCWSTR name, DWORD num, LPWSTR *params) +{ + SC_HANDLE handle, hsvc; + DWORD r = ERROR_FUNCTION_FAILED; + + TRACE("Starting service %s %ld params\n", debugstr_w(name), num); + + handle = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (!handle) + return r; + hsvc = OpenServiceW(handle, name, SC_MANAGER_ALL_ACCESS); + if (hsvc) + { + if(StartServiceW(hsvc, num, (LPCWSTR*)params)) + r = ERROR_SUCCESS; + else + r = GetLastError(); + if (r == ERROR_SERVICE_ALREADY_RUNNING) + r = ERROR_SUCCESS; + CloseServiceHandle(hsvc); + } + CloseServiceHandle(handle); + + TRACE("StartService returned error %ld (%s)\n", r, r?"ok":"failed"); + + return r; +} + +/* + * create_local_service() - start a COM server in a service + * + * To start a Local Service, we read the AppID value under + * the class's CLSID key, then open the HKCR\\AppId key specified + * there and check for a LocalService value. + * + * Note: Local Services are not supported under Windows 9x + */ +static HRESULT create_local_service(REFCLSID rclsid) +{ + HRESULT hres = REGDB_E_READREGDB; + WCHAR buf[40], keyname[50]; + static const WCHAR szClsId[] = { 'C','L','S','I','D','\\',0 }; + static const WCHAR szAppId[] = { 'A','p','p','I','d',0 }; + static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 }; + static const WCHAR szLocalService[] = { 'L','o','c','a','l','S','e','r','v','i','c','e',0 }; + static const WCHAR szServiceParams[] = {'S','e','r','v','i','c','e','P','a','r','a','m','s',0}; + HKEY hkey; + LONG r; + DWORD type, sz; + + TRACE("Attempting to start Local service for %s\n", debugstr_guid(rclsid)); + + /* read the AppID value under the class's key */ + strcpyW(keyname,szClsId); + StringFromGUID2(rclsid,&keyname[6],39); + r = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &hkey); + if (r!=ERROR_SUCCESS) + return hres; + sz = sizeof buf; + r = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &sz); + RegCloseKey(hkey); + if (r!=ERROR_SUCCESS || type!=REG_SZ) + return hres; + + /* read the LocalService and ServiceParameters values from the AppID key */ + strcpyW(keyname, szAppIdKey); + strcatW(keyname, buf); + r = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &hkey); + if (r!=ERROR_SUCCESS) + return hres; + sz = sizeof buf; + r = RegQueryValueExW(hkey, szLocalService, NULL, &type, (LPBYTE)buf, &sz); + if (r==ERROR_SUCCESS && type==REG_SZ) + { + DWORD num_args = 0; + LPWSTR args[1] = { NULL }; + + /* + * FIXME: I'm not really sure how to deal with the service parameters. + * I suspect that the string returned from RegQueryValueExW + * should be split into a number of arguments by spaces. + * It would make more sense if ServiceParams contained a + * REG_MULTI_SZ here, but it's a REG_SZ for the services + * that I'm interested in for the moment. + */ + r = RegQueryValueExW(hkey, szServiceParams, NULL, &type, NULL, &sz); + if (r == ERROR_SUCCESS && type == REG_SZ && sz) + { + args[0] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz); + num_args++; + RegQueryValueExW(hkey, szServiceParams, NULL, &type, (LPBYTE)args[0], &sz); + } + r = start_local_service(buf, num_args, args); + if (r==ERROR_SUCCESS) + hres = S_OK; + HeapFree(GetProcessHeap(),0,args[0]); + } + RegCloseKey(hkey); + + return hres; +} + +#define PIPEPREF "\\\\.\\pipe\\" + +/* FIXME: should call to rpcss instead */ +HRESULT RPC_GetLocalClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv) +{ + HRESULT hres; + HANDLE hPipe; + char pipefn[200]; + DWORD res, bufferlen; + char marshalbuffer[200]; + IStream *pStm; + LARGE_INTEGER seekto; + ULARGE_INTEGER newpos; + int tries = 0; + + static const int MAXTRIES = 30; /* 30 seconds */ + + TRACE("rclsid=%s, iid=%s\n", debugstr_guid(rclsid), debugstr_guid(iid)); + + strcpy(pipefn,PIPEPREF); + WINE_StringFromCLSID(rclsid,pipefn+strlen(PIPEPREF)); + + while (tries++ < MAXTRIES) { + TRACE("waiting for %s\n", pipefn); + + WaitNamedPipeA( pipefn, NMPWAIT_WAIT_FOREVER ); + hPipe = CreateFileA(pipefn, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + if (hPipe == INVALID_HANDLE_VALUE) { + if (tries == 1) { + if ( (hres = create_server(rclsid)) && + (hres = create_local_service(rclsid)) ) + return hres; + Sleep(1000); + } else { + WARN("Connecting to %s, no response yet, retrying: le is %lx\n",pipefn,GetLastError()); + Sleep(1000); + } + continue; + } + bufferlen = 0; + if (!ReadFile(hPipe,marshalbuffer,sizeof(marshalbuffer),&bufferlen,NULL)) { + FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid)); + Sleep(1000); + continue; + } + TRACE("read marshal id from pipe\n"); + CloseHandle(hPipe); + break; + } + + if (tries >= MAXTRIES) + return E_NOINTERFACE; + + hres = CreateStreamOnHGlobal(0,TRUE,&pStm); + if (hres) return hres; + hres = IStream_Write(pStm,marshalbuffer,bufferlen,&res); + if (hres) goto out; + seekto.u.LowPart = 0;seekto.u.HighPart = 0; + hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); + + TRACE("unmarshalling classfactory\n"); + hres = CoUnmarshalInterface(pStm,&IID_IClassFactory,ppv); +out: + IStream_Release(pStm); + return hres; +} + + +struct local_server_params +{ + CLSID clsid; + IStream *stream; +}; + +/* FIXME: should call to rpcss instead */ +static DWORD WINAPI local_server_thread(LPVOID param) +{ + struct local_server_params * lsp = (struct local_server_params *)param; + HANDLE hPipe; + char pipefn[200]; + HRESULT hres; + IStream *pStm = lsp->stream; + STATSTG ststg; + unsigned char *buffer; + int buflen; + LARGE_INTEGER seekto; + ULARGE_INTEGER newpos; + ULONG res; + + TRACE("Starting threader for %s.\n",debugstr_guid(&lsp->clsid)); + + strcpy(pipefn,PIPEPREF); + WINE_StringFromCLSID(&lsp->clsid,pipefn+strlen(PIPEPREF)); + + HeapFree(GetProcessHeap(), 0, lsp); + + hPipe = CreateNamedPipeA( pipefn, PIPE_ACCESS_DUPLEX, + PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, + 4096, 4096, 500 /* 0.5 second timeout */, NULL ); + + if (hPipe == INVALID_HANDLE_VALUE) + { + FIXME("pipe creation failed for %s, le is %ld\n",pipefn,GetLastError()); + return 1; + } + + while (1) { + if (!ConnectNamedPipe(hPipe,NULL)) { + ERR("Failure during ConnectNamedPipe %ld, ABORT!\n",GetLastError()); + break; + } + + TRACE("marshalling IClassFactory to client\n"); + + hres = IStream_Stat(pStm,&ststg,0); + if (hres) return hres; + + buflen = ststg.cbSize.u.LowPart; + buffer = HeapAlloc(GetProcessHeap(),0,buflen); + seekto.u.LowPart = 0; + seekto.u.HighPart = 0; + hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); + if (hres) { + FIXME("IStream_Seek failed, %lx\n",hres); + return hres; + } + + hres = IStream_Read(pStm,buffer,buflen,&res); + if (hres) { + FIXME("Stream Read failed, %lx\n",hres); + return hres; + } + + WriteFile(hPipe,buffer,buflen,&res,NULL); + FlushFileBuffers(hPipe); + DisconnectNamedPipe(hPipe); + + TRACE("done marshalling IClassFactory\n"); + } + CloseHandle(hPipe); + IStream_Release(pStm); + return 0; +} + +void RPC_StartLocalServer(REFCLSID clsid, IStream *stream) +{ + DWORD tid; + HANDLE thread; + struct local_server_params *lsp = HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp)); + + lsp->clsid = *clsid; + lsp->stream = stream; + + thread = CreateThread(NULL, 0, local_server_thread, lsp, 0, &tid); + CloseHandle(thread); + /* FIXME: failure handling */ +} diff --git a/reactos/lib/ole32/stg_bigblockfile.c b/reactos/lib/ole32/stg_bigblockfile.c index 294b899797b..57123c9a85e 100644 --- a/reactos/lib/ole32/stg_bigblockfile.c +++ b/reactos/lib/ole32/stg_bigblockfile.c @@ -1,876 +1,876 @@ -/****************************************************************************** - * - * BigBlockFile - * - * This is the implementation of a file that consists of blocks of - * a predetermined size. - * This class is used in the Compound File implementation of the - * IStorage and IStream interfaces. It provides the functionality - * to read and write any blocks in the file as well as setting and - * obtaining the size of the file. - * The blocks are indexed sequentially from the start of the file - * starting with -1. - * - * TODO: - * - Support for a transacted mode - * - * Copyright 1999 Thuy Nguyen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <assert.h> -#include <stdlib.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> -#include <limits.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "winerror.h" -#include "objbase.h" -#include "ole2.h" - -#include "storage32.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(storage); - -/*********************************************************** - * Data structures used internally by the BigBlockFile - * class. - */ - -/* We map in PAGE_SIZE-sized chunks. Must be a multiple of 4096. */ -#define PAGE_SIZE 131072 - -#define BLOCKS_PER_PAGE (PAGE_SIZE / BIG_BLOCK_SIZE) - -/* We keep a list of recently-discarded pages. This controls the - * size of that list. */ -#define MAX_VICTIM_PAGES 16 - -/* This structure provides one bit for each block in a page. - * Use BIGBLOCKFILE_{Test,Set,Clear}Bit to manipulate it. */ -typedef struct -{ - unsigned int bits[BLOCKS_PER_PAGE / (CHAR_BIT * sizeof(unsigned int))]; -} BlockBits; - -/*** - * This structure identifies the paged that are mapped - * from the file and their position in memory. It is - * also used to hold a reference count to those pages. - * - * page_index identifies which PAGE_SIZE chunk from the - * file this mapping represents. (The mappings are always - * PAGE_SIZE-aligned.) - */ -struct MappedPage -{ - MappedPage *next; - MappedPage *prev; - - DWORD page_index; - LPVOID lpBytes; - LONG refcnt; - - BlockBits readable_blocks; - BlockBits writable_blocks; -}; - -/*********************************************************** - * Prototypes for private methods - */ -static void* BIGBLOCKFILE_GetMappedView(LPBIGBLOCKFILE This, - DWORD page_index); -static void BIGBLOCKFILE_ReleaseMappedPage(LPBIGBLOCKFILE This, - MappedPage *page); -static void BIGBLOCKFILE_FreeAllMappedPages(LPBIGBLOCKFILE This); -static void BIGBLOCKFILE_UnmapAllMappedPages(LPBIGBLOCKFILE This); -static void BIGBLOCKFILE_RemapAllMappedPages(LPBIGBLOCKFILE This); -static void* BIGBLOCKFILE_GetBigBlockPointer(LPBIGBLOCKFILE This, - ULONG index, - DWORD desired_access); -static MappedPage* BIGBLOCKFILE_GetPageFromPointer(LPBIGBLOCKFILE This, - void* pBlock); -static MappedPage* BIGBLOCKFILE_CreatePage(LPBIGBLOCKFILE This, - ULONG page_index); -static DWORD BIGBLOCKFILE_GetProtectMode(DWORD openFlags); -static BOOL BIGBLOCKFILE_FileInit(LPBIGBLOCKFILE This, HANDLE hFile); -static BOOL BIGBLOCKFILE_MemInit(LPBIGBLOCKFILE This, ILockBytes* plkbyt); - -/* Note that this evaluates a and b multiple times, so don't - * pass expressions with side effects. */ -#define ROUND_UP(a, b) ((((a) + (b) - 1)/(b))*(b)) - -/*********************************************************** - * Blockbits functions. - */ -static inline BOOL BIGBLOCKFILE_TestBit(const BlockBits *bb, - unsigned int index) -{ - unsigned int array_index = index / (CHAR_BIT * sizeof(unsigned int)); - unsigned int bit_index = index % (CHAR_BIT * sizeof(unsigned int)); - - return bb->bits[array_index] & (1 << bit_index); -} - -static inline void BIGBLOCKFILE_SetBit(BlockBits *bb, unsigned int index) -{ - unsigned int array_index = index / (CHAR_BIT * sizeof(unsigned int)); - unsigned int bit_index = index % (CHAR_BIT * sizeof(unsigned int)); - - bb->bits[array_index] |= (1 << bit_index); -} - -static inline void BIGBLOCKFILE_ClearBit(BlockBits *bb, unsigned int index) -{ - unsigned int array_index = index / (CHAR_BIT * sizeof(unsigned int)); - unsigned int bit_index = index % (CHAR_BIT * sizeof(unsigned int)); - - bb->bits[array_index] &= ~(1 << bit_index); -} - -static inline void BIGBLOCKFILE_Zero(BlockBits *bb) -{ - memset(bb->bits, 0, sizeof(bb->bits)); -} - -/****************************************************************************** - * BIGBLOCKFILE_Construct - * - * Construct a big block file. Create the file mapping object. - * Create the read only mapped pages list, the writable mapped page list - * and the blocks in use list. - */ -BigBlockFile * BIGBLOCKFILE_Construct( - HANDLE hFile, - ILockBytes* pLkByt, - DWORD openFlags, - ULONG blocksize, - BOOL fileBased) -{ - LPBIGBLOCKFILE This; - - This = HeapAlloc(GetProcessHeap(), 0, sizeof(BigBlockFile)); - - if (This == NULL) - return NULL; - - This->fileBased = fileBased; - - This->flProtect = BIGBLOCKFILE_GetProtectMode(openFlags); - - This->blocksize = blocksize; - - This->maplist = NULL; - This->victimhead = NULL; - This->victimtail = NULL; - This->num_victim_pages = 0; - - if (This->fileBased) - { - if (!BIGBLOCKFILE_FileInit(This, hFile)) - { - HeapFree(GetProcessHeap(), 0, This); - return NULL; - } - } - else - { - if (!BIGBLOCKFILE_MemInit(This, pLkByt)) - { - HeapFree(GetProcessHeap(), 0, This); - return NULL; - } - } - - return This; -} - -/****************************************************************************** - * BIGBLOCKFILE_FileInit - * - * Initialize a big block object supported by a file. - */ -static BOOL BIGBLOCKFILE_FileInit(LPBIGBLOCKFILE This, HANDLE hFile) -{ - This->pLkbyt = NULL; - This->hbytearray = 0; - This->pbytearray = NULL; - - This->hfile = hFile; - - if (This->hfile == INVALID_HANDLE_VALUE) - return FALSE; - - This->filesize.u.LowPart = GetFileSize(This->hfile, - &This->filesize.u.HighPart); - - if( This->filesize.u.LowPart || This->filesize.u.HighPart ) - { - /* create the file mapping object - */ - This->hfilemap = CreateFileMappingA(This->hfile, - NULL, - This->flProtect, - 0, 0, - NULL); - - if (!This->hfilemap) - { - CloseHandle(This->hfile); - return FALSE; - } - } - else - This->hfilemap = NULL; - - This->maplist = NULL; - - TRACE("file len %lu\n", This->filesize.u.LowPart); - - return TRUE; -} - -/****************************************************************************** - * BIGBLOCKFILE_MemInit - * - * Initialize a big block object supported by an ILockBytes on HGLOABL. - */ -static BOOL BIGBLOCKFILE_MemInit(LPBIGBLOCKFILE This, ILockBytes* plkbyt) -{ - This->hfile = 0; - This->hfilemap = 0; - - /* - * Retrieve the handle to the byte array from the LockByte object. - */ - if (GetHGlobalFromILockBytes(plkbyt, &(This->hbytearray)) != S_OK) - { - FIXME("May not be an ILockBytes on HGLOBAL\n"); - return FALSE; - } - - This->pLkbyt = plkbyt; - - /* - * Increment the reference count of the ILockByte object since - * we're keeping a reference to it. - */ - ILockBytes_AddRef(This->pLkbyt); - - This->filesize.u.LowPart = GlobalSize(This->hbytearray); - This->filesize.u.HighPart = 0; - - This->pbytearray = GlobalLock(This->hbytearray); - - TRACE("mem on %p len %lu\n", This->pbytearray, This->filesize.u.LowPart); - - return TRUE; -} - -/****************************************************************************** - * BIGBLOCKFILE_Destructor - * - * Destructor. Clean up, free memory. - */ -void BIGBLOCKFILE_Destructor( - LPBIGBLOCKFILE This) -{ - BIGBLOCKFILE_FreeAllMappedPages(This); - - if (This->fileBased) - { - CloseHandle(This->hfilemap); - CloseHandle(This->hfile); - } - else - { - GlobalUnlock(This->hbytearray); - ILockBytes_Release(This->pLkbyt); - } - - /* destroy this - */ - HeapFree(GetProcessHeap(), 0, This); -} - -/****************************************************************************** - * BIGBLOCKFILE_GetROBigBlock - * - * Returns the specified block in read only mode. - * Will return NULL if the block doesn't exists. - */ -void* BIGBLOCKFILE_GetROBigBlock( - LPBIGBLOCKFILE This, - ULONG index) -{ - /* - * block index starts at -1 - * translate to zero based index - */ - if (index == 0xffffffff) - index = 0; - else - index++; - - /* - * validate the block index - * - */ - if (This->blocksize * (index + 1) - > ROUND_UP(This->filesize.u.LowPart, This->blocksize)) - { - TRACE("out of range %lu vs %lu\n", This->blocksize * (index + 1), - This->filesize.u.LowPart); - return NULL; - } - - return BIGBLOCKFILE_GetBigBlockPointer(This, index, FILE_MAP_READ); -} - -/****************************************************************************** - * BIGBLOCKFILE_GetBigBlock - * - * Returns the specified block. - * Will grow the file if necessary. - */ -void* BIGBLOCKFILE_GetBigBlock(LPBIGBLOCKFILE This, ULONG index) -{ - /* - * block index starts at -1 - * translate to zero based index - */ - if (index == 0xffffffff) - index = 0; - else - index++; - - /* - * make sure that the block physically exists - */ - if ((This->blocksize * (index + 1)) > This->filesize.u.LowPart) - { - ULARGE_INTEGER newSize; - - newSize.u.HighPart = 0; - newSize.u.LowPart = This->blocksize * (index + 1); - - BIGBLOCKFILE_SetSize(This, newSize); - } - - return BIGBLOCKFILE_GetBigBlockPointer(This, index, FILE_MAP_WRITE); -} - -/****************************************************************************** - * BIGBLOCKFILE_ReleaseBigBlock - * - * Releases the specified block. - */ -void BIGBLOCKFILE_ReleaseBigBlock(LPBIGBLOCKFILE This, void *pBlock) -{ - MappedPage *page; - - if (pBlock == NULL) - return; - - page = BIGBLOCKFILE_GetPageFromPointer(This, pBlock); - - if (page == NULL) - return; - - BIGBLOCKFILE_ReleaseMappedPage(This, page); -} - -/****************************************************************************** - * BIGBLOCKFILE_SetSize - * - * Sets the size of the file. - * - */ -void BIGBLOCKFILE_SetSize(LPBIGBLOCKFILE This, ULARGE_INTEGER newSize) -{ - if (This->filesize.u.LowPart == newSize.u.LowPart) - return; - - TRACE("from %lu to %lu\n", This->filesize.u.LowPart, newSize.u.LowPart); - /* - * unmap all views, must be done before call to SetEndFile - */ - BIGBLOCKFILE_UnmapAllMappedPages(This); - - if (This->fileBased) - { - char buf[10]; - DWORD w; - - /* - * close file-mapping object, must be done before call to SetEndFile - */ - if( This->hfilemap ) - CloseHandle(This->hfilemap); - This->hfilemap = 0; - - /* - * BEGIN HACK - * This fixes a bug when saving through smbfs. - * smbmount a Windows shared directory, save a structured storage file - * to that dir: crash. - * - * The problem is that the SetFilePointer-SetEndOfFile combo below - * doesn't always succeed. The file is not grown. It seems like the - * operation is cached. By doing the WriteFile, the file is actually - * grown on disk. - * This hack is only needed when saving to smbfs. - */ - memset(buf, '0', 10); - SetFilePointer(This->hfile, newSize.u.LowPart, NULL, FILE_BEGIN); - WriteFile(This->hfile, buf, 10, &w, NULL); - /* - * END HACK - */ - - /* - * set the new end of file - */ - SetFilePointer(This->hfile, newSize.u.LowPart, NULL, FILE_BEGIN); - SetEndOfFile(This->hfile); - - /* - * re-create the file mapping object - */ - This->hfilemap = CreateFileMappingA(This->hfile, - NULL, - This->flProtect, - 0, 0, - NULL); - } - else - { - GlobalUnlock(This->hbytearray); - - /* - * Resize the byte array object. - */ - ILockBytes_SetSize(This->pLkbyt, newSize); - - /* - * Re-acquire the handle, it may have changed. - */ - GetHGlobalFromILockBytes(This->pLkbyt, &This->hbytearray); - This->pbytearray = GlobalLock(This->hbytearray); - } - - This->filesize.u.LowPart = newSize.u.LowPart; - This->filesize.u.HighPart = newSize.u.HighPart; - - BIGBLOCKFILE_RemapAllMappedPages(This); -} - -/****************************************************************************** - * BIGBLOCKFILE_GetSize - * - * Returns the size of the file. - * - */ -ULARGE_INTEGER BIGBLOCKFILE_GetSize(LPBIGBLOCKFILE This) -{ - return This->filesize; -} - -/****************************************************************************** - * BIGBLOCKFILE_AccessCheck [PRIVATE] - * - * block_index is the index within the page. - */ -static BOOL BIGBLOCKFILE_AccessCheck(MappedPage *page, ULONG block_index, - DWORD desired_access) -{ - assert(block_index < BLOCKS_PER_PAGE); - - if (desired_access == FILE_MAP_READ) - { - if (BIGBLOCKFILE_TestBit(&page->writable_blocks, block_index)) - return FALSE; - - BIGBLOCKFILE_SetBit(&page->readable_blocks, block_index); - } - else - { - assert(desired_access == FILE_MAP_WRITE); - - if (BIGBLOCKFILE_TestBit(&page->readable_blocks, block_index)) - return FALSE; - - BIGBLOCKFILE_SetBit(&page->writable_blocks, block_index); - } - - return TRUE; -} - -/****************************************************************************** - * BIGBLOCKFILE_GetBigBlockPointer [PRIVATE] - * - * Returns a pointer to the specified block. - */ -static void* BIGBLOCKFILE_GetBigBlockPointer( - LPBIGBLOCKFILE This, - ULONG block_index, - DWORD desired_access) -{ - DWORD page_index = block_index / BLOCKS_PER_PAGE; - DWORD block_on_page = block_index % BLOCKS_PER_PAGE; - - MappedPage *page = BIGBLOCKFILE_GetMappedView(This, page_index); - if (!page || !page->lpBytes) return NULL; - - if (!BIGBLOCKFILE_AccessCheck(page, block_on_page, desired_access)) - { - BIGBLOCKFILE_ReleaseMappedPage(This, page); - return NULL; - } - - return (LPBYTE)page->lpBytes + (block_on_page * This->blocksize); -} - -/****************************************************************************** - * BIGBLOCKFILE_GetMappedPageFromPointer [PRIVATE] - * - * pBlock is a pointer to a block on a page. - * The page has to be on the in-use list. (As oppsed to the victim list.) - * - * Does not increment the usage count. - */ -static MappedPage *BIGBLOCKFILE_GetPageFromPointer(LPBIGBLOCKFILE This, - void *pBlock) -{ - MappedPage *page; - - for (page = This->maplist; page != NULL; page = page->next) - { - if ((LPBYTE)pBlock >= (LPBYTE)page->lpBytes - && (LPBYTE)pBlock <= (LPBYTE)page->lpBytes + PAGE_SIZE) - break; - - } - - return page; -} - -/****************************************************************************** - * BIGBLOCKFILE_FindPageInList [PRIVATE] - * - */ -static MappedPage *BIGBLOCKFILE_FindPageInList(MappedPage *head, - ULONG page_index) -{ - for (; head != NULL; head = head->next) - { - if (head->page_index == page_index) - { - InterlockedIncrement(&head->refcnt); - break; - } - } - - return head; - -} - -static void BIGBLOCKFILE_UnlinkPage(MappedPage *page) -{ - if (page->next) page->next->prev = page->prev; - if (page->prev) page->prev->next = page->next; -} - -static void BIGBLOCKFILE_LinkHeadPage(MappedPage **head, MappedPage *page) -{ - if (*head) (*head)->prev = page; - page->next = *head; - page->prev = NULL; - *head = page; -} - -/****************************************************************************** - * BIGBLOCKFILE_GetMappedView [PRIVATE] - * - * Gets the page requested if it is already mapped. - * If it's not already mapped, this method will map it - */ -static void * BIGBLOCKFILE_GetMappedView( - LPBIGBLOCKFILE This, - DWORD page_index) -{ - MappedPage *page; - - page = BIGBLOCKFILE_FindPageInList(This->maplist, page_index); - if (!page) - { - page = BIGBLOCKFILE_FindPageInList(This->victimhead, page_index); - if (page) - { - This->num_victim_pages--; - - BIGBLOCKFILE_Zero(&page->readable_blocks); - BIGBLOCKFILE_Zero(&page->writable_blocks); - } - } - - if (page) - { - /* If the page is not already at the head of the list, move - * it there. (Also moves pages from victim to main list.) */ - if (This->maplist != page) - { - if (This->victimhead == page) This->victimhead = page->next; - if (This->victimtail == page) This->victimtail = page->prev; - - BIGBLOCKFILE_UnlinkPage(page); - - BIGBLOCKFILE_LinkHeadPage(&This->maplist, page); - } - - return page; - } - - page = BIGBLOCKFILE_CreatePage(This, page_index); - if (!page) return NULL; - - BIGBLOCKFILE_LinkHeadPage(&This->maplist, page); - - return page; -} - -static BOOL BIGBLOCKFILE_MapPage(LPBIGBLOCKFILE This, MappedPage *page) -{ - DWORD lowoffset = PAGE_SIZE * page->page_index; - - if (This->fileBased) - { - DWORD numBytesToMap; - DWORD desired_access; - - if( !This->hfilemap ) - return FALSE; - - if (lowoffset + PAGE_SIZE > This->filesize.u.LowPart) - numBytesToMap = This->filesize.u.LowPart - lowoffset; - else - numBytesToMap = PAGE_SIZE; - - if (This->flProtect == PAGE_READONLY) - desired_access = FILE_MAP_READ; - else - desired_access = FILE_MAP_WRITE; - - page->lpBytes = MapViewOfFile(This->hfilemap, desired_access, 0, - lowoffset, numBytesToMap); - } - else - { - page->lpBytes = (LPBYTE)This->pbytearray + lowoffset; - } - - TRACE("mapped page %lu to %p\n", page->page_index, page->lpBytes); - - return page->lpBytes != NULL; -} - -static MappedPage *BIGBLOCKFILE_CreatePage(LPBIGBLOCKFILE This, - ULONG page_index) -{ - MappedPage *page; - - page = HeapAlloc(GetProcessHeap(), 0, sizeof(MappedPage)); - if (page == NULL) - return NULL; - - page->page_index = page_index; - page->refcnt = 1; - - page->next = NULL; - page->prev = NULL; - - BIGBLOCKFILE_MapPage(This, page); - - BIGBLOCKFILE_Zero(&page->readable_blocks); - BIGBLOCKFILE_Zero(&page->writable_blocks); - - return page; -} - -static void BIGBLOCKFILE_UnmapPage(LPBIGBLOCKFILE This, MappedPage *page) -{ - TRACE("%ld at %p\n", page->page_index, page->lpBytes); - if (page->refcnt > 0) - ERR("unmapping inuse page %p\n", page->lpBytes); - - if (This->fileBased && page->lpBytes) - UnmapViewOfFile(page->lpBytes); - - page->lpBytes = NULL; -} - -static void BIGBLOCKFILE_DeletePage(LPBIGBLOCKFILE This, MappedPage *page) -{ - BIGBLOCKFILE_UnmapPage(This, page); - - HeapFree(GetProcessHeap(), 0, page); -} - -/****************************************************************************** - * BIGBLOCKFILE_ReleaseMappedPage [PRIVATE] - * - * Decrements the reference count of the mapped page. - */ -static void BIGBLOCKFILE_ReleaseMappedPage( - LPBIGBLOCKFILE This, - MappedPage *page) -{ - assert(This != NULL); - assert(page != NULL); - - /* If the page is no longer refenced, move it to the victim list. - * If the victim list is too long, kick somebody off. */ - if (!InterlockedDecrement(&page->refcnt)) - { - if (This->maplist == page) This->maplist = page->next; - - BIGBLOCKFILE_UnlinkPage(page); - - if (MAX_VICTIM_PAGES > 0) - { - if (This->num_victim_pages >= MAX_VICTIM_PAGES) - { - MappedPage *victim = This->victimtail; - if (victim) - { - This->victimtail = victim->prev; - if (This->victimhead == victim) - This->victimhead = victim->next; - - BIGBLOCKFILE_UnlinkPage(victim); - BIGBLOCKFILE_DeletePage(This, victim); - } - } - else This->num_victim_pages++; - - BIGBLOCKFILE_LinkHeadPage(&This->victimhead, page); - if (This->victimtail == NULL) This->victimtail = page; - } - else - BIGBLOCKFILE_DeletePage(This, page); - } -} - -static void BIGBLOCKFILE_DeleteList(LPBIGBLOCKFILE This, MappedPage *list) -{ - while (list != NULL) - { - MappedPage *next = list->next; - - BIGBLOCKFILE_DeletePage(This, list); - - list = next; - } -} - -/****************************************************************************** - * BIGBLOCKFILE_FreeAllMappedPages [PRIVATE] - * - * Unmap all currently mapped pages. - * Empty mapped pages list. - */ -static void BIGBLOCKFILE_FreeAllMappedPages( - LPBIGBLOCKFILE This) -{ - BIGBLOCKFILE_DeleteList(This, This->maplist); - BIGBLOCKFILE_DeleteList(This, This->victimhead); - - This->maplist = NULL; - This->victimhead = NULL; - This->victimtail = NULL; - This->num_victim_pages = 0; -} - -static void BIGBLOCKFILE_UnmapList(LPBIGBLOCKFILE This, MappedPage *list) -{ - for (; list != NULL; list = list->next) - { - BIGBLOCKFILE_UnmapPage(This, list); - } -} - -static void BIGBLOCKFILE_UnmapAllMappedPages(LPBIGBLOCKFILE This) -{ - BIGBLOCKFILE_UnmapList(This, This->maplist); - BIGBLOCKFILE_UnmapList(This, This->victimhead); -} - -static void BIGBLOCKFILE_RemapList(LPBIGBLOCKFILE This, MappedPage *list) -{ - while (list != NULL) - { - MappedPage *next = list->next; - - if (list->page_index * PAGE_SIZE > This->filesize.u.LowPart) - { - TRACE("discarding %lu\n", list->page_index); - - /* page is entirely outside of the file, delete it */ - BIGBLOCKFILE_UnlinkPage(list); - BIGBLOCKFILE_DeletePage(This, list); - } - else - { - /* otherwise, remap it */ - BIGBLOCKFILE_MapPage(This, list); - } - - list = next; - } -} - -static void BIGBLOCKFILE_RemapAllMappedPages(LPBIGBLOCKFILE This) -{ - BIGBLOCKFILE_RemapList(This, This->maplist); - BIGBLOCKFILE_RemapList(This, This->victimhead); -} - -/**************************************************************************** - * BIGBLOCKFILE_GetProtectMode - * - * This function will return a protection mode flag for a file-mapping object - * from the open flags of a file. - */ -static DWORD BIGBLOCKFILE_GetProtectMode(DWORD openFlags) -{ - switch(STGM_ACCESS_MODE(openFlags)) - { - case STGM_WRITE: - case STGM_READWRITE: - return PAGE_READWRITE; - } - return PAGE_READONLY; -} +/****************************************************************************** + * + * BigBlockFile + * + * This is the implementation of a file that consists of blocks of + * a predetermined size. + * This class is used in the Compound File implementation of the + * IStorage and IStream interfaces. It provides the functionality + * to read and write any blocks in the file as well as setting and + * obtaining the size of the file. + * The blocks are indexed sequentially from the start of the file + * starting with -1. + * + * TODO: + * - Support for a transacted mode + * + * Copyright 1999 Thuy Nguyen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <assert.h> +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winerror.h" +#include "objbase.h" +#include "ole2.h" + +#include "storage32.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(storage); + +/*********************************************************** + * Data structures used internally by the BigBlockFile + * class. + */ + +/* We map in PAGE_SIZE-sized chunks. Must be a multiple of 4096. */ +#define PAGE_SIZE 131072 + +#define BLOCKS_PER_PAGE (PAGE_SIZE / BIG_BLOCK_SIZE) + +/* We keep a list of recently-discarded pages. This controls the + * size of that list. */ +#define MAX_VICTIM_PAGES 16 + +/* This structure provides one bit for each block in a page. + * Use BIGBLOCKFILE_{Test,Set,Clear}Bit to manipulate it. */ +typedef struct +{ + unsigned int bits[BLOCKS_PER_PAGE / (CHAR_BIT * sizeof(unsigned int))]; +} BlockBits; + +/*** + * This structure identifies the paged that are mapped + * from the file and their position in memory. It is + * also used to hold a reference count to those pages. + * + * page_index identifies which PAGE_SIZE chunk from the + * file this mapping represents. (The mappings are always + * PAGE_SIZE-aligned.) + */ +struct MappedPage +{ + MappedPage *next; + MappedPage *prev; + + DWORD page_index; + LPVOID lpBytes; + LONG refcnt; + + BlockBits readable_blocks; + BlockBits writable_blocks; +}; + +/*********************************************************** + * Prototypes for private methods + */ +static void* BIGBLOCKFILE_GetMappedView(LPBIGBLOCKFILE This, + DWORD page_index); +static void BIGBLOCKFILE_ReleaseMappedPage(LPBIGBLOCKFILE This, + MappedPage *page); +static void BIGBLOCKFILE_FreeAllMappedPages(LPBIGBLOCKFILE This); +static void BIGBLOCKFILE_UnmapAllMappedPages(LPBIGBLOCKFILE This); +static void BIGBLOCKFILE_RemapAllMappedPages(LPBIGBLOCKFILE This); +static void* BIGBLOCKFILE_GetBigBlockPointer(LPBIGBLOCKFILE This, + ULONG index, + DWORD desired_access); +static MappedPage* BIGBLOCKFILE_GetPageFromPointer(LPBIGBLOCKFILE This, + void* pBlock); +static MappedPage* BIGBLOCKFILE_CreatePage(LPBIGBLOCKFILE This, + ULONG page_index); +static DWORD BIGBLOCKFILE_GetProtectMode(DWORD openFlags); +static BOOL BIGBLOCKFILE_FileInit(LPBIGBLOCKFILE This, HANDLE hFile); +static BOOL BIGBLOCKFILE_MemInit(LPBIGBLOCKFILE This, ILockBytes* plkbyt); + +/* Note that this evaluates a and b multiple times, so don't + * pass expressions with side effects. */ +#define ROUND_UP(a, b) ((((a) + (b) - 1)/(b))*(b)) + +/*********************************************************** + * Blockbits functions. + */ +static inline BOOL BIGBLOCKFILE_TestBit(const BlockBits *bb, + unsigned int index) +{ + unsigned int array_index = index / (CHAR_BIT * sizeof(unsigned int)); + unsigned int bit_index = index % (CHAR_BIT * sizeof(unsigned int)); + + return bb->bits[array_index] & (1 << bit_index); +} + +static inline void BIGBLOCKFILE_SetBit(BlockBits *bb, unsigned int index) +{ + unsigned int array_index = index / (CHAR_BIT * sizeof(unsigned int)); + unsigned int bit_index = index % (CHAR_BIT * sizeof(unsigned int)); + + bb->bits[array_index] |= (1 << bit_index); +} + +static inline void BIGBLOCKFILE_ClearBit(BlockBits *bb, unsigned int index) +{ + unsigned int array_index = index / (CHAR_BIT * sizeof(unsigned int)); + unsigned int bit_index = index % (CHAR_BIT * sizeof(unsigned int)); + + bb->bits[array_index] &= ~(1 << bit_index); +} + +static inline void BIGBLOCKFILE_Zero(BlockBits *bb) +{ + memset(bb->bits, 0, sizeof(bb->bits)); +} + +/****************************************************************************** + * BIGBLOCKFILE_Construct + * + * Construct a big block file. Create the file mapping object. + * Create the read only mapped pages list, the writable mapped page list + * and the blocks in use list. + */ +BigBlockFile * BIGBLOCKFILE_Construct( + HANDLE hFile, + ILockBytes* pLkByt, + DWORD openFlags, + ULONG blocksize, + BOOL fileBased) +{ + LPBIGBLOCKFILE This; + + This = HeapAlloc(GetProcessHeap(), 0, sizeof(BigBlockFile)); + + if (This == NULL) + return NULL; + + This->fileBased = fileBased; + + This->flProtect = BIGBLOCKFILE_GetProtectMode(openFlags); + + This->blocksize = blocksize; + + This->maplist = NULL; + This->victimhead = NULL; + This->victimtail = NULL; + This->num_victim_pages = 0; + + if (This->fileBased) + { + if (!BIGBLOCKFILE_FileInit(This, hFile)) + { + HeapFree(GetProcessHeap(), 0, This); + return NULL; + } + } + else + { + if (!BIGBLOCKFILE_MemInit(This, pLkByt)) + { + HeapFree(GetProcessHeap(), 0, This); + return NULL; + } + } + + return This; +} + +/****************************************************************************** + * BIGBLOCKFILE_FileInit + * + * Initialize a big block object supported by a file. + */ +static BOOL BIGBLOCKFILE_FileInit(LPBIGBLOCKFILE This, HANDLE hFile) +{ + This->pLkbyt = NULL; + This->hbytearray = 0; + This->pbytearray = NULL; + + This->hfile = hFile; + + if (This->hfile == INVALID_HANDLE_VALUE) + return FALSE; + + This->filesize.u.LowPart = GetFileSize(This->hfile, + &This->filesize.u.HighPart); + + if( This->filesize.u.LowPart || This->filesize.u.HighPart ) + { + /* create the file mapping object + */ + This->hfilemap = CreateFileMappingA(This->hfile, + NULL, + This->flProtect, + 0, 0, + NULL); + + if (!This->hfilemap) + { + CloseHandle(This->hfile); + return FALSE; + } + } + else + This->hfilemap = NULL; + + This->maplist = NULL; + + TRACE("file len %lu\n", This->filesize.u.LowPart); + + return TRUE; +} + +/****************************************************************************** + * BIGBLOCKFILE_MemInit + * + * Initialize a big block object supported by an ILockBytes on HGLOABL. + */ +static BOOL BIGBLOCKFILE_MemInit(LPBIGBLOCKFILE This, ILockBytes* plkbyt) +{ + This->hfile = 0; + This->hfilemap = 0; + + /* + * Retrieve the handle to the byte array from the LockByte object. + */ + if (GetHGlobalFromILockBytes(plkbyt, &(This->hbytearray)) != S_OK) + { + FIXME("May not be an ILockBytes on HGLOBAL\n"); + return FALSE; + } + + This->pLkbyt = plkbyt; + + /* + * Increment the reference count of the ILockByte object since + * we're keeping a reference to it. + */ + ILockBytes_AddRef(This->pLkbyt); + + This->filesize.u.LowPart = GlobalSize(This->hbytearray); + This->filesize.u.HighPart = 0; + + This->pbytearray = GlobalLock(This->hbytearray); + + TRACE("mem on %p len %lu\n", This->pbytearray, This->filesize.u.LowPart); + + return TRUE; +} + +/****************************************************************************** + * BIGBLOCKFILE_Destructor + * + * Destructor. Clean up, free memory. + */ +void BIGBLOCKFILE_Destructor( + LPBIGBLOCKFILE This) +{ + BIGBLOCKFILE_FreeAllMappedPages(This); + + if (This->fileBased) + { + CloseHandle(This->hfilemap); + CloseHandle(This->hfile); + } + else + { + GlobalUnlock(This->hbytearray); + ILockBytes_Release(This->pLkbyt); + } + + /* destroy this + */ + HeapFree(GetProcessHeap(), 0, This); +} + +/****************************************************************************** + * BIGBLOCKFILE_GetROBigBlock + * + * Returns the specified block in read only mode. + * Will return NULL if the block doesn't exists. + */ +void* BIGBLOCKFILE_GetROBigBlock( + LPBIGBLOCKFILE This, + ULONG index) +{ + /* + * block index starts at -1 + * translate to zero based index + */ + if (index == 0xffffffff) + index = 0; + else + index++; + + /* + * validate the block index + * + */ + if (This->blocksize * (index + 1) + > ROUND_UP(This->filesize.u.LowPart, This->blocksize)) + { + TRACE("out of range %lu vs %lu\n", This->blocksize * (index + 1), + This->filesize.u.LowPart); + return NULL; + } + + return BIGBLOCKFILE_GetBigBlockPointer(This, index, FILE_MAP_READ); +} + +/****************************************************************************** + * BIGBLOCKFILE_GetBigBlock + * + * Returns the specified block. + * Will grow the file if necessary. + */ +void* BIGBLOCKFILE_GetBigBlock(LPBIGBLOCKFILE This, ULONG index) +{ + /* + * block index starts at -1 + * translate to zero based index + */ + if (index == 0xffffffff) + index = 0; + else + index++; + + /* + * make sure that the block physically exists + */ + if ((This->blocksize * (index + 1)) > This->filesize.u.LowPart) + { + ULARGE_INTEGER newSize; + + newSize.u.HighPart = 0; + newSize.u.LowPart = This->blocksize * (index + 1); + + BIGBLOCKFILE_SetSize(This, newSize); + } + + return BIGBLOCKFILE_GetBigBlockPointer(This, index, FILE_MAP_WRITE); +} + +/****************************************************************************** + * BIGBLOCKFILE_ReleaseBigBlock + * + * Releases the specified block. + */ +void BIGBLOCKFILE_ReleaseBigBlock(LPBIGBLOCKFILE This, void *pBlock) +{ + MappedPage *page; + + if (pBlock == NULL) + return; + + page = BIGBLOCKFILE_GetPageFromPointer(This, pBlock); + + if (page == NULL) + return; + + BIGBLOCKFILE_ReleaseMappedPage(This, page); +} + +/****************************************************************************** + * BIGBLOCKFILE_SetSize + * + * Sets the size of the file. + * + */ +void BIGBLOCKFILE_SetSize(LPBIGBLOCKFILE This, ULARGE_INTEGER newSize) +{ + if (This->filesize.u.LowPart == newSize.u.LowPart) + return; + + TRACE("from %lu to %lu\n", This->filesize.u.LowPart, newSize.u.LowPart); + /* + * unmap all views, must be done before call to SetEndFile + */ + BIGBLOCKFILE_UnmapAllMappedPages(This); + + if (This->fileBased) + { + char buf[10]; + DWORD w; + + /* + * close file-mapping object, must be done before call to SetEndFile + */ + if( This->hfilemap ) + CloseHandle(This->hfilemap); + This->hfilemap = 0; + + /* + * BEGIN HACK + * This fixes a bug when saving through smbfs. + * smbmount a Windows shared directory, save a structured storage file + * to that dir: crash. + * + * The problem is that the SetFilePointer-SetEndOfFile combo below + * doesn't always succeed. The file is not grown. It seems like the + * operation is cached. By doing the WriteFile, the file is actually + * grown on disk. + * This hack is only needed when saving to smbfs. + */ + memset(buf, '0', 10); + SetFilePointer(This->hfile, newSize.u.LowPart, NULL, FILE_BEGIN); + WriteFile(This->hfile, buf, 10, &w, NULL); + /* + * END HACK + */ + + /* + * set the new end of file + */ + SetFilePointer(This->hfile, newSize.u.LowPart, NULL, FILE_BEGIN); + SetEndOfFile(This->hfile); + + /* + * re-create the file mapping object + */ + This->hfilemap = CreateFileMappingA(This->hfile, + NULL, + This->flProtect, + 0, 0, + NULL); + } + else + { + GlobalUnlock(This->hbytearray); + + /* + * Resize the byte array object. + */ + ILockBytes_SetSize(This->pLkbyt, newSize); + + /* + * Re-acquire the handle, it may have changed. + */ + GetHGlobalFromILockBytes(This->pLkbyt, &This->hbytearray); + This->pbytearray = GlobalLock(This->hbytearray); + } + + This->filesize.u.LowPart = newSize.u.LowPart; + This->filesize.u.HighPart = newSize.u.HighPart; + + BIGBLOCKFILE_RemapAllMappedPages(This); +} + +/****************************************************************************** + * BIGBLOCKFILE_GetSize + * + * Returns the size of the file. + * + */ +ULARGE_INTEGER BIGBLOCKFILE_GetSize(LPBIGBLOCKFILE This) +{ + return This->filesize; +} + +/****************************************************************************** + * BIGBLOCKFILE_AccessCheck [PRIVATE] + * + * block_index is the index within the page. + */ +static BOOL BIGBLOCKFILE_AccessCheck(MappedPage *page, ULONG block_index, + DWORD desired_access) +{ + assert(block_index < BLOCKS_PER_PAGE); + + if (desired_access == FILE_MAP_READ) + { + if (BIGBLOCKFILE_TestBit(&page->writable_blocks, block_index)) + return FALSE; + + BIGBLOCKFILE_SetBit(&page->readable_blocks, block_index); + } + else + { + assert(desired_access == FILE_MAP_WRITE); + + if (BIGBLOCKFILE_TestBit(&page->readable_blocks, block_index)) + return FALSE; + + BIGBLOCKFILE_SetBit(&page->writable_blocks, block_index); + } + + return TRUE; +} + +/****************************************************************************** + * BIGBLOCKFILE_GetBigBlockPointer [PRIVATE] + * + * Returns a pointer to the specified block. + */ +static void* BIGBLOCKFILE_GetBigBlockPointer( + LPBIGBLOCKFILE This, + ULONG block_index, + DWORD desired_access) +{ + DWORD page_index = block_index / BLOCKS_PER_PAGE; + DWORD block_on_page = block_index % BLOCKS_PER_PAGE; + + MappedPage *page = BIGBLOCKFILE_GetMappedView(This, page_index); + if (!page || !page->lpBytes) return NULL; + + if (!BIGBLOCKFILE_AccessCheck(page, block_on_page, desired_access)) + { + BIGBLOCKFILE_ReleaseMappedPage(This, page); + return NULL; + } + + return (LPBYTE)page->lpBytes + (block_on_page * This->blocksize); +} + +/****************************************************************************** + * BIGBLOCKFILE_GetMappedPageFromPointer [PRIVATE] + * + * pBlock is a pointer to a block on a page. + * The page has to be on the in-use list. (As oppsed to the victim list.) + * + * Does not increment the usage count. + */ +static MappedPage *BIGBLOCKFILE_GetPageFromPointer(LPBIGBLOCKFILE This, + void *pBlock) +{ + MappedPage *page; + + for (page = This->maplist; page != NULL; page = page->next) + { + if ((LPBYTE)pBlock >= (LPBYTE)page->lpBytes + && (LPBYTE)pBlock <= (LPBYTE)page->lpBytes + PAGE_SIZE) + break; + + } + + return page; +} + +/****************************************************************************** + * BIGBLOCKFILE_FindPageInList [PRIVATE] + * + */ +static MappedPage *BIGBLOCKFILE_FindPageInList(MappedPage *head, + ULONG page_index) +{ + for (; head != NULL; head = head->next) + { + if (head->page_index == page_index) + { + InterlockedIncrement(&head->refcnt); + break; + } + } + + return head; + +} + +static void BIGBLOCKFILE_UnlinkPage(MappedPage *page) +{ + if (page->next) page->next->prev = page->prev; + if (page->prev) page->prev->next = page->next; +} + +static void BIGBLOCKFILE_LinkHeadPage(MappedPage **head, MappedPage *page) +{ + if (*head) (*head)->prev = page; + page->next = *head; + page->prev = NULL; + *head = page; +} + +/****************************************************************************** + * BIGBLOCKFILE_GetMappedView [PRIVATE] + * + * Gets the page requested if it is already mapped. + * If it's not already mapped, this method will map it + */ +static void * BIGBLOCKFILE_GetMappedView( + LPBIGBLOCKFILE This, + DWORD page_index) +{ + MappedPage *page; + + page = BIGBLOCKFILE_FindPageInList(This->maplist, page_index); + if (!page) + { + page = BIGBLOCKFILE_FindPageInList(This->victimhead, page_index); + if (page) + { + This->num_victim_pages--; + + BIGBLOCKFILE_Zero(&page->readable_blocks); + BIGBLOCKFILE_Zero(&page->writable_blocks); + } + } + + if (page) + { + /* If the page is not already at the head of the list, move + * it there. (Also moves pages from victim to main list.) */ + if (This->maplist != page) + { + if (This->victimhead == page) This->victimhead = page->next; + if (This->victimtail == page) This->victimtail = page->prev; + + BIGBLOCKFILE_UnlinkPage(page); + + BIGBLOCKFILE_LinkHeadPage(&This->maplist, page); + } + + return page; + } + + page = BIGBLOCKFILE_CreatePage(This, page_index); + if (!page) return NULL; + + BIGBLOCKFILE_LinkHeadPage(&This->maplist, page); + + return page; +} + +static BOOL BIGBLOCKFILE_MapPage(LPBIGBLOCKFILE This, MappedPage *page) +{ + DWORD lowoffset = PAGE_SIZE * page->page_index; + + if (This->fileBased) + { + DWORD numBytesToMap; + DWORD desired_access; + + if( !This->hfilemap ) + return FALSE; + + if (lowoffset + PAGE_SIZE > This->filesize.u.LowPart) + numBytesToMap = This->filesize.u.LowPart - lowoffset; + else + numBytesToMap = PAGE_SIZE; + + if (This->flProtect == PAGE_READONLY) + desired_access = FILE_MAP_READ; + else + desired_access = FILE_MAP_WRITE; + + page->lpBytes = MapViewOfFile(This->hfilemap, desired_access, 0, + lowoffset, numBytesToMap); + } + else + { + page->lpBytes = (LPBYTE)This->pbytearray + lowoffset; + } + + TRACE("mapped page %lu to %p\n", page->page_index, page->lpBytes); + + return page->lpBytes != NULL; +} + +static MappedPage *BIGBLOCKFILE_CreatePage(LPBIGBLOCKFILE This, + ULONG page_index) +{ + MappedPage *page; + + page = HeapAlloc(GetProcessHeap(), 0, sizeof(MappedPage)); + if (page == NULL) + return NULL; + + page->page_index = page_index; + page->refcnt = 1; + + page->next = NULL; + page->prev = NULL; + + BIGBLOCKFILE_MapPage(This, page); + + BIGBLOCKFILE_Zero(&page->readable_blocks); + BIGBLOCKFILE_Zero(&page->writable_blocks); + + return page; +} + +static void BIGBLOCKFILE_UnmapPage(LPBIGBLOCKFILE This, MappedPage *page) +{ + TRACE("%ld at %p\n", page->page_index, page->lpBytes); + if (page->refcnt > 0) + ERR("unmapping inuse page %p\n", page->lpBytes); + + if (This->fileBased && page->lpBytes) + UnmapViewOfFile(page->lpBytes); + + page->lpBytes = NULL; +} + +static void BIGBLOCKFILE_DeletePage(LPBIGBLOCKFILE This, MappedPage *page) +{ + BIGBLOCKFILE_UnmapPage(This, page); + + HeapFree(GetProcessHeap(), 0, page); +} + +/****************************************************************************** + * BIGBLOCKFILE_ReleaseMappedPage [PRIVATE] + * + * Decrements the reference count of the mapped page. + */ +static void BIGBLOCKFILE_ReleaseMappedPage( + LPBIGBLOCKFILE This, + MappedPage *page) +{ + assert(This != NULL); + assert(page != NULL); + + /* If the page is no longer refenced, move it to the victim list. + * If the victim list is too long, kick somebody off. */ + if (!InterlockedDecrement(&page->refcnt)) + { + if (This->maplist == page) This->maplist = page->next; + + BIGBLOCKFILE_UnlinkPage(page); + + if (MAX_VICTIM_PAGES > 0) + { + if (This->num_victim_pages >= MAX_VICTIM_PAGES) + { + MappedPage *victim = This->victimtail; + if (victim) + { + This->victimtail = victim->prev; + if (This->victimhead == victim) + This->victimhead = victim->next; + + BIGBLOCKFILE_UnlinkPage(victim); + BIGBLOCKFILE_DeletePage(This, victim); + } + } + else This->num_victim_pages++; + + BIGBLOCKFILE_LinkHeadPage(&This->victimhead, page); + if (This->victimtail == NULL) This->victimtail = page; + } + else + BIGBLOCKFILE_DeletePage(This, page); + } +} + +static void BIGBLOCKFILE_DeleteList(LPBIGBLOCKFILE This, MappedPage *list) +{ + while (list != NULL) + { + MappedPage *next = list->next; + + BIGBLOCKFILE_DeletePage(This, list); + + list = next; + } +} + +/****************************************************************************** + * BIGBLOCKFILE_FreeAllMappedPages [PRIVATE] + * + * Unmap all currently mapped pages. + * Empty mapped pages list. + */ +static void BIGBLOCKFILE_FreeAllMappedPages( + LPBIGBLOCKFILE This) +{ + BIGBLOCKFILE_DeleteList(This, This->maplist); + BIGBLOCKFILE_DeleteList(This, This->victimhead); + + This->maplist = NULL; + This->victimhead = NULL; + This->victimtail = NULL; + This->num_victim_pages = 0; +} + +static void BIGBLOCKFILE_UnmapList(LPBIGBLOCKFILE This, MappedPage *list) +{ + for (; list != NULL; list = list->next) + { + BIGBLOCKFILE_UnmapPage(This, list); + } +} + +static void BIGBLOCKFILE_UnmapAllMappedPages(LPBIGBLOCKFILE This) +{ + BIGBLOCKFILE_UnmapList(This, This->maplist); + BIGBLOCKFILE_UnmapList(This, This->victimhead); +} + +static void BIGBLOCKFILE_RemapList(LPBIGBLOCKFILE This, MappedPage *list) +{ + while (list != NULL) + { + MappedPage *next = list->next; + + if (list->page_index * PAGE_SIZE > This->filesize.u.LowPart) + { + TRACE("discarding %lu\n", list->page_index); + + /* page is entirely outside of the file, delete it */ + BIGBLOCKFILE_UnlinkPage(list); + BIGBLOCKFILE_DeletePage(This, list); + } + else + { + /* otherwise, remap it */ + BIGBLOCKFILE_MapPage(This, list); + } + + list = next; + } +} + +static void BIGBLOCKFILE_RemapAllMappedPages(LPBIGBLOCKFILE This) +{ + BIGBLOCKFILE_RemapList(This, This->maplist); + BIGBLOCKFILE_RemapList(This, This->victimhead); +} + +/**************************************************************************** + * BIGBLOCKFILE_GetProtectMode + * + * This function will return a protection mode flag for a file-mapping object + * from the open flags of a file. + */ +static DWORD BIGBLOCKFILE_GetProtectMode(DWORD openFlags) +{ + switch(STGM_ACCESS_MODE(openFlags)) + { + case STGM_WRITE: + case STGM_READWRITE: + return PAGE_READWRITE; + } + return PAGE_READONLY; +} diff --git a/reactos/lib/ole32/stg_stream.c b/reactos/lib/ole32/stg_stream.c index 4273c173c8d..9fa28dae9c9 100644 --- a/reactos/lib/ole32/stg_stream.c +++ b/reactos/lib/ole32/stg_stream.c @@ -1,900 +1,900 @@ -/* - * Compound Storage (32 bit version) - * Stream implementation - * - * This file contains the implementation of the stream interface - * for streams contained in a compound storage. - * - * Copyright 1999 Francis Beaudet - * Copyright 1999 Thuy Nguyen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <assert.h> -#include <stdlib.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "winreg.h" -#include "winternl.h" -#include "wine/debug.h" - -#include "storage32.h" - -WINE_DEFAULT_DEBUG_CHANNEL(storage); - - -/*** - * This is the destructor of the StgStreamImpl class. - * - * This method will clean-up all the resources used-up by the given StgStreamImpl - * class. The pointer passed-in to this function will be freed and will not - * be valid anymore. - */ -static void StgStreamImpl_Destroy(StgStreamImpl* This) -{ - TRACE("(%p)\n", This); - - /* - * Release the reference we are holding on the parent storage. - */ - IStorage_Release((IStorage*)This->parentStorage); - This->parentStorage = 0; - - /* - * Make sure we clean-up the block chain stream objects that we were using. - */ - if (This->bigBlockChain != 0) - { - BlockChainStream_Destroy(This->bigBlockChain); - This->bigBlockChain = 0; - } - - if (This->smallBlockChain != 0) - { - SmallBlockChainStream_Destroy(This->smallBlockChain); - This->smallBlockChain = 0; - } - - /* - * Finally, free the memory used-up by the class. - */ - HeapFree(GetProcessHeap(), 0, This); -} - -/*** - * This implements the IUnknown method QueryInterface for this - * class - */ -static HRESULT WINAPI StgStreamImpl_QueryInterface( - IStream* iface, - REFIID riid, /* [in] */ - void** ppvObject) /* [iid_is][out] */ -{ - StgStreamImpl* const This=(StgStreamImpl*)iface; - - /* - * Perform a sanity check on the parameters. - */ - if (ppvObject==0) - return E_INVALIDARG; - - /* - * Initialize the return parameter. - */ - *ppvObject = 0; - - /* - * Compare the riid with the interface IDs implemented by this object. - */ - if (IsEqualGUID(&IID_IUnknown, riid)|| - IsEqualGUID(&IID_IStream, riid)) - { - *ppvObject = (IStream*)This; - } - - /* - * Check that we obtained an interface. - */ - if ((*ppvObject)==0) - return E_NOINTERFACE; - - /* - * Query Interface always increases the reference count by one when it is - * successful - */ - IStream_AddRef(iface); - - return S_OK; -} - -/*** - * This implements the IUnknown method AddRef for this - * class - */ -static ULONG WINAPI StgStreamImpl_AddRef( - IStream* iface) -{ - StgStreamImpl* const This=(StgStreamImpl*)iface; - return InterlockedIncrement(&This->ref); -} - -/*** - * This implements the IUnknown method Release for this - * class - */ -static ULONG WINAPI StgStreamImpl_Release( - IStream* iface) -{ - StgStreamImpl* const This=(StgStreamImpl*)iface; - - ULONG ref; - - ref = InterlockedDecrement(&This->ref); - - /* - * If the reference count goes down to 0, perform suicide. - */ - if (ref==0) - { - StgStreamImpl_Destroy(This); - } - - return ref; -} - -/*** - * This method will open the block chain pointed by the property - * that describes the stream. - * If the stream's size is null, no chain is opened. - */ -static void StgStreamImpl_OpenBlockChain( - StgStreamImpl* This) -{ - StgProperty curProperty; - BOOL readSucessful; - - /* - * Make sure no old object is left over. - */ - if (This->smallBlockChain != 0) - { - SmallBlockChainStream_Destroy(This->smallBlockChain); - This->smallBlockChain = 0; - } - - if (This->bigBlockChain != 0) - { - BlockChainStream_Destroy(This->bigBlockChain); - This->bigBlockChain = 0; - } - - /* - * Read the information from the property. - */ - readSucessful = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage, - This->ownerProperty, - &curProperty); - - if (readSucessful) - { - This->streamSize = curProperty.size; - - /* - * This code supports only streams that are <32 bits in size. - */ - assert(This->streamSize.u.HighPart == 0); - - if(curProperty.startingBlock == BLOCK_END_OF_CHAIN) - { - assert( (This->streamSize.u.HighPart == 0) && (This->streamSize.u.LowPart == 0) ); - } - else - { - if ( (This->streamSize.u.HighPart == 0) && - (This->streamSize.u.LowPart < LIMIT_TO_USE_SMALL_BLOCK) ) - { - This->smallBlockChain = SmallBlockChainStream_Construct( - This->parentStorage->ancestorStorage, - This->ownerProperty); - } - else - { - This->bigBlockChain = BlockChainStream_Construct( - This->parentStorage->ancestorStorage, - NULL, - This->ownerProperty); - } - } - } -} - -/*** - * This method is part of the ISequentialStream interface. - * - * It reads a block of information from the stream at the current - * position. It then moves the current position at the end of the - * read block - * - * See the documentation of ISequentialStream for more info. - */ -static HRESULT WINAPI StgStreamImpl_Read( - IStream* iface, - void* pv, /* [length_is][size_is][out] */ - ULONG cb, /* [in] */ - ULONG* pcbRead) /* [out] */ -{ - StgStreamImpl* const This=(StgStreamImpl*)iface; - - ULONG bytesReadBuffer; - ULONG bytesToReadFromBuffer; - HRESULT res = S_FALSE; - - TRACE("(%p, %p, %ld, %p)\n", - iface, pv, cb, pcbRead); - - /* - * If the caller is not interested in the number of bytes read, - * we use another buffer to avoid "if" statements in the code. - */ - if (pcbRead==0) - pcbRead = &bytesReadBuffer; - - /* - * Using the known size of the stream, calculate the number of bytes - * to read from the block chain - */ - bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb); - - /* - * Depending on the type of chain that was opened when the stream was constructed, - * we delegate the work to the method that reads the block chains. - */ - if (This->smallBlockChain!=0) - { - SmallBlockChainStream_ReadAt(This->smallBlockChain, - This->currentPosition, - bytesToReadFromBuffer, - pv, - pcbRead); - - } - else if (This->bigBlockChain!=0) - { - BlockChainStream_ReadAt(This->bigBlockChain, - This->currentPosition, - bytesToReadFromBuffer, - pv, - pcbRead); - } - else - { - /* - * Small and big block chains are both NULL. This case will happen - * when a stream starts with BLOCK_END_OF_CHAIN and has size zero. - */ - - *pcbRead = 0; - res = S_OK; - goto end; - } - - /* - * We should always be able to read the proper amount of data from the - * chain. - */ - assert(bytesToReadFromBuffer == *pcbRead); - - /* - * Advance the pointer for the number of positions read. - */ - This->currentPosition.u.LowPart += *pcbRead; - - if(*pcbRead != cb) - { - WARN("read %ld instead of the required %ld bytes !\n", *pcbRead, cb); - /* - * this used to return S_FALSE, however MSDN docu says that an app should - * be prepared to handle error in case of stream end reached, as *some* - * implementations *might* return an error (IOW: most do *not*). - * As some program fails on returning S_FALSE, I better use S_OK here. - */ - res = S_OK; - } - else - res = S_OK; - -end: - TRACE("<-- %08lx\n", res); - return res; -} - -/*** - * This method is part of the ISequentialStream interface. - * - * It writes a block of information to the stream at the current - * position. It then moves the current position at the end of the - * written block. If the stream is too small to fit the block, - * the stream is grown to fit. - * - * See the documentation of ISequentialStream for more info. - */ -static HRESULT WINAPI StgStreamImpl_Write( - IStream* iface, - const void* pv, /* [size_is][in] */ - ULONG cb, /* [in] */ - ULONG* pcbWritten) /* [out] */ -{ - StgStreamImpl* const This=(StgStreamImpl*)iface; - - ULARGE_INTEGER newSize; - ULONG bytesWritten = 0; - - TRACE("(%p, %p, %ld, %p)\n", - iface, pv, cb, pcbWritten); - - /* - * Do we have permission to write to this stream? - */ - switch(STGM_ACCESS_MODE(This->grfMode)) - { - case STGM_WRITE: - case STGM_READWRITE: - break; - default: - return STG_E_ACCESSDENIED; - } - - if (!pv) - return STG_E_INVALIDPOINTER; - - /* - * If the caller is not interested in the number of bytes written, - * we use another buffer to avoid "if" statements in the code. - */ - if (pcbWritten == 0) - pcbWritten = &bytesWritten; - - /* - * Initialize the out parameter - */ - *pcbWritten = 0; - - if (cb == 0) - { - return S_OK; - } - else - { - newSize.u.HighPart = 0; - newSize.u.LowPart = This->currentPosition.u.LowPart + cb; - } - - /* - * Verify if we need to grow the stream - */ - if (newSize.u.LowPart > This->streamSize.u.LowPart) - { - /* grow stream */ - IStream_SetSize(iface, newSize); - } - - /* - * Depending on the type of chain that was opened when the stream was constructed, - * we delegate the work to the method that readwrites to the block chains. - */ - if (This->smallBlockChain!=0) - { - SmallBlockChainStream_WriteAt(This->smallBlockChain, - This->currentPosition, - cb, - pv, - pcbWritten); - - } - else if (This->bigBlockChain!=0) - { - BlockChainStream_WriteAt(This->bigBlockChain, - This->currentPosition, - cb, - pv, - pcbWritten); - } - else - assert(FALSE); - - /* - * Advance the position pointer for the number of positions written. - */ - This->currentPosition.u.LowPart += *pcbWritten; - - return S_OK; -} - -/*** - * This method is part of the IStream interface. - * - * It will move the current stream pointer according to the parameters - * given. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI StgStreamImpl_Seek( - IStream* iface, - LARGE_INTEGER dlibMove, /* [in] */ - DWORD dwOrigin, /* [in] */ - ULARGE_INTEGER* plibNewPosition) /* [out] */ -{ - StgStreamImpl* const This=(StgStreamImpl*)iface; - - ULARGE_INTEGER newPosition; - - TRACE("(%p, %ld, %ld, %p)\n", - iface, dlibMove.u.LowPart, dwOrigin, plibNewPosition); - - /* - * The caller is allowed to pass in NULL as the new position return value. - * If it happens, we assign it to a dynamic variable to avoid special cases - * in the code below. - */ - if (plibNewPosition == 0) - { - plibNewPosition = &newPosition; - } - - /* - * The file pointer is moved depending on the given "function" - * parameter. - */ - switch (dwOrigin) - { - case STREAM_SEEK_SET: - plibNewPosition->u.HighPart = 0; - plibNewPosition->u.LowPart = 0; - break; - case STREAM_SEEK_CUR: - *plibNewPosition = This->currentPosition; - break; - case STREAM_SEEK_END: - *plibNewPosition = This->streamSize; - break; - default: - return STG_E_INVALIDFUNCTION; - } - - plibNewPosition->QuadPart = RtlLargeIntegerAdd( plibNewPosition->QuadPart, dlibMove.QuadPart ); - - /* - * tell the caller what we calculated - */ - This->currentPosition = *plibNewPosition; - - return S_OK; -} - -/*** - * This method is part of the IStream interface. - * - * It will change the size of a stream. - * - * TODO: Switch from small blocks to big blocks and vice versa. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI StgStreamImpl_SetSize( - IStream* iface, - ULARGE_INTEGER libNewSize) /* [in] */ -{ - StgStreamImpl* const This=(StgStreamImpl*)iface; - - StgProperty curProperty; - BOOL Success; - - TRACE("(%p, %ld)\n", iface, libNewSize.u.LowPart); - - /* - * As documented. - */ - if (libNewSize.u.HighPart != 0) - return STG_E_INVALIDFUNCTION; - - /* - * Do we have permission? - */ - if (!(This->grfMode & (STGM_WRITE | STGM_READWRITE))) - return STG_E_ACCESSDENIED; - - if (This->streamSize.u.LowPart == libNewSize.u.LowPart) - return S_OK; - - /* - * This will happen if we're creating a stream - */ - if ((This->smallBlockChain == 0) && (This->bigBlockChain == 0)) - { - if (libNewSize.u.LowPart < LIMIT_TO_USE_SMALL_BLOCK) - { - This->smallBlockChain = SmallBlockChainStream_Construct( - This->parentStorage->ancestorStorage, - This->ownerProperty); - } - else - { - This->bigBlockChain = BlockChainStream_Construct( - This->parentStorage->ancestorStorage, - NULL, - This->ownerProperty); - } - } - - /* - * Read this stream's property to see if it's small blocks or big blocks - */ - Success = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage, - This->ownerProperty, - &curProperty); - /* - * Determine if we have to switch from small to big blocks or vice versa - */ - if ( (This->smallBlockChain!=0) && - (curProperty.size.u.LowPart < LIMIT_TO_USE_SMALL_BLOCK) ) - { - if (libNewSize.u.LowPart >= LIMIT_TO_USE_SMALL_BLOCK) - { - /* - * Transform the small block chain into a big block chain - */ - This->bigBlockChain = Storage32Impl_SmallBlocksToBigBlocks( - This->parentStorage->ancestorStorage, - &This->smallBlockChain); - } - } - - if (This->smallBlockChain!=0) - { - Success = SmallBlockChainStream_SetSize(This->smallBlockChain, libNewSize); - } - else - { - Success = BlockChainStream_SetSize(This->bigBlockChain, libNewSize); - } - - /* - * Write the new information about this stream to the property - */ - Success = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage, - This->ownerProperty, - &curProperty); - - curProperty.size.u.HighPart = libNewSize.u.HighPart; - curProperty.size.u.LowPart = libNewSize.u.LowPart; - - if (Success) - { - StorageImpl_WriteProperty(This->parentStorage->ancestorStorage, - This->ownerProperty, - &curProperty); - } - - This->streamSize = libNewSize; - - return S_OK; -} - -/*** - * This method is part of the IStream interface. - * - * It will copy the 'cb' Bytes to 'pstm' IStream. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI StgStreamImpl_CopyTo( - IStream* iface, - IStream* pstm, /* [unique][in] */ - ULARGE_INTEGER cb, /* [in] */ - ULARGE_INTEGER* pcbRead, /* [out] */ - ULARGE_INTEGER* pcbWritten) /* [out] */ -{ - HRESULT hr = S_OK; - BYTE tmpBuffer[128]; - ULONG bytesRead, bytesWritten, copySize; - ULARGE_INTEGER totalBytesRead; - ULARGE_INTEGER totalBytesWritten; - - TRACE("(%p, %p, %ld, %p, %p)\n", - iface, pstm, cb.u.LowPart, pcbRead, pcbWritten); - - /* - * Sanity check - */ - if ( pstm == 0 ) - return STG_E_INVALIDPOINTER; - - totalBytesRead.u.LowPart = totalBytesRead.u.HighPart = 0; - totalBytesWritten.u.LowPart = totalBytesWritten.u.HighPart = 0; - - /* - * use stack to store data temporarily - * there is surely a more performant way of doing it, for now this basic - * implementation will do the job - */ - while ( cb.u.LowPart > 0 ) - { - if ( cb.u.LowPart >= 128 ) - copySize = 128; - else - copySize = cb.u.LowPart; - - IStream_Read(iface, tmpBuffer, copySize, &bytesRead); - - totalBytesRead.u.LowPart += bytesRead; - - IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten); - - totalBytesWritten.u.LowPart += bytesWritten; - - /* - * Check that read & write operations were successful - */ - if (bytesRead != bytesWritten) - { - hr = STG_E_MEDIUMFULL; - break; - } - - if (bytesRead!=copySize) - cb.u.LowPart = 0; - else - cb.u.LowPart -= bytesRead; - } - - /* - * Update number of bytes read and written - */ - if (pcbRead) - { - pcbRead->u.LowPart = totalBytesRead.u.LowPart; - pcbRead->u.HighPart = totalBytesRead.u.HighPart; - } - - if (pcbWritten) - { - pcbWritten->u.LowPart = totalBytesWritten.u.LowPart; - pcbWritten->u.HighPart = totalBytesWritten.u.HighPart; - } - return hr; -} - -/*** - * This method is part of the IStream interface. - * - * For streams contained in structured storages, this method - * does nothing. This is what the documentation tells us. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI StgStreamImpl_Commit( - IStream* iface, - DWORD grfCommitFlags) /* [in] */ -{ - return S_OK; -} - -/*** - * This method is part of the IStream interface. - * - * For streams contained in structured storages, this method - * does nothing. This is what the documentation tells us. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI StgStreamImpl_Revert( - IStream* iface) -{ - return S_OK; -} - -static HRESULT WINAPI StgStreamImpl_LockRegion( - IStream* iface, - ULARGE_INTEGER libOffset, /* [in] */ - ULARGE_INTEGER cb, /* [in] */ - DWORD dwLockType) /* [in] */ -{ - FIXME("not implemented!\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI StgStreamImpl_UnlockRegion( - IStream* iface, - ULARGE_INTEGER libOffset, /* [in] */ - ULARGE_INTEGER cb, /* [in] */ - DWORD dwLockType) /* [in] */ -{ - FIXME("not implemented!\n"); - return E_NOTIMPL; -} - -/*** - * This method is part of the IStream interface. - * - * This method returns information about the current - * stream. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI StgStreamImpl_Stat( - IStream* iface, - STATSTG* pstatstg, /* [out] */ - DWORD grfStatFlag) /* [in] */ -{ - StgStreamImpl* const This=(StgStreamImpl*)iface; - - StgProperty curProperty; - BOOL readSucessful; - - /* - * Read the information from the property. - */ - readSucessful = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage, - This->ownerProperty, - &curProperty); - - if (readSucessful) - { - StorageUtl_CopyPropertyToSTATSTG(pstatstg, - &curProperty, - grfStatFlag); - - pstatstg->grfMode = This->grfMode; - - return S_OK; - } - - return E_FAIL; -} - -/*** - * This method is part of the IStream interface. - * - * This method returns a clone of the interface that allows for - * another seek pointer - * - * See the documentation of IStream for more info. - * - * I am not totally sure what I am doing here but I presume that this - * should be basically as simple as creating a new stream with the same - * parent etc and positioning its seek cursor. - */ -static HRESULT WINAPI StgStreamImpl_Clone( - IStream* iface, - IStream** ppstm) /* [out] */ -{ - StgStreamImpl* const This=(StgStreamImpl*)iface; - HRESULT hres; - StgStreamImpl* new_stream; - LARGE_INTEGER seek_pos; - - /* - * Sanity check - */ - if ( ppstm == 0 ) - return STG_E_INVALIDPOINTER; - - new_stream = StgStreamImpl_Construct (This->parentStorage, This->grfMode, This->ownerProperty); - - if (!new_stream) - return STG_E_INSUFFICIENTMEMORY; /* Currently the only reason for new_stream=0 */ - - *ppstm = (IStream*) new_stream; - seek_pos.QuadPart = This->currentPosition.QuadPart; - - hres=StgStreamImpl_Seek (*ppstm, seek_pos, STREAM_SEEK_SET, NULL); - - assert (SUCCEEDED(hres)); - - return S_OK; -} - -/* - * Virtual function table for the StgStreamImpl class. - */ -static IStreamVtbl StgStreamImpl_Vtbl = -{ - StgStreamImpl_QueryInterface, - StgStreamImpl_AddRef, - StgStreamImpl_Release, - StgStreamImpl_Read, - StgStreamImpl_Write, - StgStreamImpl_Seek, - StgStreamImpl_SetSize, - StgStreamImpl_CopyTo, - StgStreamImpl_Commit, - StgStreamImpl_Revert, - StgStreamImpl_LockRegion, - StgStreamImpl_UnlockRegion, - StgStreamImpl_Stat, - StgStreamImpl_Clone -}; - -/****************************************************************************** -** StgStreamImpl implementation -*/ - -/*** - * This is the constructor for the StgStreamImpl class. - * - * Params: - * parentStorage - Pointer to the storage that contains the stream to open - * ownerProperty - Index of the property that points to this stream. - */ -StgStreamImpl* StgStreamImpl_Construct( - StorageBaseImpl* parentStorage, - DWORD grfMode, - ULONG ownerProperty) -{ - StgStreamImpl* newStream; - - newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(StgStreamImpl)); - - if (newStream!=0) - { - /* - * Set-up the virtual function table and reference count. - */ - newStream->lpVtbl = &StgStreamImpl_Vtbl; - newStream->ref = 0; - - /* - * We want to nail-down the reference to the storage in case the - * stream out-lives the storage in the client application. - */ - newStream->parentStorage = parentStorage; - IStorage_AddRef((IStorage*)newStream->parentStorage); - - newStream->grfMode = grfMode; - newStream->ownerProperty = ownerProperty; - - /* - * Start the stream at the beginning. - */ - newStream->currentPosition.u.HighPart = 0; - newStream->currentPosition.u.LowPart = 0; - - /* - * Initialize the rest of the data. - */ - newStream->streamSize.u.HighPart = 0; - newStream->streamSize.u.LowPart = 0; - newStream->bigBlockChain = 0; - newStream->smallBlockChain = 0; - - /* - * Read the size from the property and determine if the blocks forming - * this stream are large or small. - */ - StgStreamImpl_OpenBlockChain(newStream); - } - - return newStream; -} +/* + * Compound Storage (32 bit version) + * Stream implementation + * + * This file contains the implementation of the stream interface + * for streams contained in a compound storage. + * + * Copyright 1999 Francis Beaudet + * Copyright 1999 Thuy Nguyen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <assert.h> +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" +#include "winternl.h" +#include "wine/debug.h" + +#include "storage32.h" + +WINE_DEFAULT_DEBUG_CHANNEL(storage); + + +/*** + * This is the destructor of the StgStreamImpl class. + * + * This method will clean-up all the resources used-up by the given StgStreamImpl + * class. The pointer passed-in to this function will be freed and will not + * be valid anymore. + */ +static void StgStreamImpl_Destroy(StgStreamImpl* This) +{ + TRACE("(%p)\n", This); + + /* + * Release the reference we are holding on the parent storage. + */ + IStorage_Release((IStorage*)This->parentStorage); + This->parentStorage = 0; + + /* + * Make sure we clean-up the block chain stream objects that we were using. + */ + if (This->bigBlockChain != 0) + { + BlockChainStream_Destroy(This->bigBlockChain); + This->bigBlockChain = 0; + } + + if (This->smallBlockChain != 0) + { + SmallBlockChainStream_Destroy(This->smallBlockChain); + This->smallBlockChain = 0; + } + + /* + * Finally, free the memory used-up by the class. + */ + HeapFree(GetProcessHeap(), 0, This); +} + +/*** + * This implements the IUnknown method QueryInterface for this + * class + */ +static HRESULT WINAPI StgStreamImpl_QueryInterface( + IStream* iface, + REFIID riid, /* [in] */ + void** ppvObject) /* [iid_is][out] */ +{ + StgStreamImpl* const This=(StgStreamImpl*)iface; + + /* + * Perform a sanity check on the parameters. + */ + if (ppvObject==0) + return E_INVALIDARG; + + /* + * Initialize the return parameter. + */ + *ppvObject = 0; + + /* + * Compare the riid with the interface IDs implemented by this object. + */ + if (IsEqualGUID(&IID_IUnknown, riid)|| + IsEqualGUID(&IID_IStream, riid)) + { + *ppvObject = (IStream*)This; + } + + /* + * Check that we obtained an interface. + */ + if ((*ppvObject)==0) + return E_NOINTERFACE; + + /* + * Query Interface always increases the reference count by one when it is + * successful + */ + IStream_AddRef(iface); + + return S_OK; +} + +/*** + * This implements the IUnknown method AddRef for this + * class + */ +static ULONG WINAPI StgStreamImpl_AddRef( + IStream* iface) +{ + StgStreamImpl* const This=(StgStreamImpl*)iface; + return InterlockedIncrement(&This->ref); +} + +/*** + * This implements the IUnknown method Release for this + * class + */ +static ULONG WINAPI StgStreamImpl_Release( + IStream* iface) +{ + StgStreamImpl* const This=(StgStreamImpl*)iface; + + ULONG ref; + + ref = InterlockedDecrement(&This->ref); + + /* + * If the reference count goes down to 0, perform suicide. + */ + if (ref==0) + { + StgStreamImpl_Destroy(This); + } + + return ref; +} + +/*** + * This method will open the block chain pointed by the property + * that describes the stream. + * If the stream's size is null, no chain is opened. + */ +static void StgStreamImpl_OpenBlockChain( + StgStreamImpl* This) +{ + StgProperty curProperty; + BOOL readSucessful; + + /* + * Make sure no old object is left over. + */ + if (This->smallBlockChain != 0) + { + SmallBlockChainStream_Destroy(This->smallBlockChain); + This->smallBlockChain = 0; + } + + if (This->bigBlockChain != 0) + { + BlockChainStream_Destroy(This->bigBlockChain); + This->bigBlockChain = 0; + } + + /* + * Read the information from the property. + */ + readSucessful = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage, + This->ownerProperty, + &curProperty); + + if (readSucessful) + { + This->streamSize = curProperty.size; + + /* + * This code supports only streams that are <32 bits in size. + */ + assert(This->streamSize.u.HighPart == 0); + + if(curProperty.startingBlock == BLOCK_END_OF_CHAIN) + { + assert( (This->streamSize.u.HighPart == 0) && (This->streamSize.u.LowPart == 0) ); + } + else + { + if ( (This->streamSize.u.HighPart == 0) && + (This->streamSize.u.LowPart < LIMIT_TO_USE_SMALL_BLOCK) ) + { + This->smallBlockChain = SmallBlockChainStream_Construct( + This->parentStorage->ancestorStorage, + This->ownerProperty); + } + else + { + This->bigBlockChain = BlockChainStream_Construct( + This->parentStorage->ancestorStorage, + NULL, + This->ownerProperty); + } + } + } +} + +/*** + * This method is part of the ISequentialStream interface. + * + * It reads a block of information from the stream at the current + * position. It then moves the current position at the end of the + * read block + * + * See the documentation of ISequentialStream for more info. + */ +static HRESULT WINAPI StgStreamImpl_Read( + IStream* iface, + void* pv, /* [length_is][size_is][out] */ + ULONG cb, /* [in] */ + ULONG* pcbRead) /* [out] */ +{ + StgStreamImpl* const This=(StgStreamImpl*)iface; + + ULONG bytesReadBuffer; + ULONG bytesToReadFromBuffer; + HRESULT res = S_FALSE; + + TRACE("(%p, %p, %ld, %p)\n", + iface, pv, cb, pcbRead); + + /* + * If the caller is not interested in the number of bytes read, + * we use another buffer to avoid "if" statements in the code. + */ + if (pcbRead==0) + pcbRead = &bytesReadBuffer; + + /* + * Using the known size of the stream, calculate the number of bytes + * to read from the block chain + */ + bytesToReadFromBuffer = min( This->streamSize.u.LowPart - This->currentPosition.u.LowPart, cb); + + /* + * Depending on the type of chain that was opened when the stream was constructed, + * we delegate the work to the method that reads the block chains. + */ + if (This->smallBlockChain!=0) + { + SmallBlockChainStream_ReadAt(This->smallBlockChain, + This->currentPosition, + bytesToReadFromBuffer, + pv, + pcbRead); + + } + else if (This->bigBlockChain!=0) + { + BlockChainStream_ReadAt(This->bigBlockChain, + This->currentPosition, + bytesToReadFromBuffer, + pv, + pcbRead); + } + else + { + /* + * Small and big block chains are both NULL. This case will happen + * when a stream starts with BLOCK_END_OF_CHAIN and has size zero. + */ + + *pcbRead = 0; + res = S_OK; + goto end; + } + + /* + * We should always be able to read the proper amount of data from the + * chain. + */ + assert(bytesToReadFromBuffer == *pcbRead); + + /* + * Advance the pointer for the number of positions read. + */ + This->currentPosition.u.LowPart += *pcbRead; + + if(*pcbRead != cb) + { + WARN("read %ld instead of the required %ld bytes !\n", *pcbRead, cb); + /* + * this used to return S_FALSE, however MSDN docu says that an app should + * be prepared to handle error in case of stream end reached, as *some* + * implementations *might* return an error (IOW: most do *not*). + * As some program fails on returning S_FALSE, I better use S_OK here. + */ + res = S_OK; + } + else + res = S_OK; + +end: + TRACE("<-- %08lx\n", res); + return res; +} + +/*** + * This method is part of the ISequentialStream interface. + * + * It writes a block of information to the stream at the current + * position. It then moves the current position at the end of the + * written block. If the stream is too small to fit the block, + * the stream is grown to fit. + * + * See the documentation of ISequentialStream for more info. + */ +static HRESULT WINAPI StgStreamImpl_Write( + IStream* iface, + const void* pv, /* [size_is][in] */ + ULONG cb, /* [in] */ + ULONG* pcbWritten) /* [out] */ +{ + StgStreamImpl* const This=(StgStreamImpl*)iface; + + ULARGE_INTEGER newSize; + ULONG bytesWritten = 0; + + TRACE("(%p, %p, %ld, %p)\n", + iface, pv, cb, pcbWritten); + + /* + * Do we have permission to write to this stream? + */ + switch(STGM_ACCESS_MODE(This->grfMode)) + { + case STGM_WRITE: + case STGM_READWRITE: + break; + default: + return STG_E_ACCESSDENIED; + } + + if (!pv) + return STG_E_INVALIDPOINTER; + + /* + * If the caller is not interested in the number of bytes written, + * we use another buffer to avoid "if" statements in the code. + */ + if (pcbWritten == 0) + pcbWritten = &bytesWritten; + + /* + * Initialize the out parameter + */ + *pcbWritten = 0; + + if (cb == 0) + { + return S_OK; + } + else + { + newSize.u.HighPart = 0; + newSize.u.LowPart = This->currentPosition.u.LowPart + cb; + } + + /* + * Verify if we need to grow the stream + */ + if (newSize.u.LowPart > This->streamSize.u.LowPart) + { + /* grow stream */ + IStream_SetSize(iface, newSize); + } + + /* + * Depending on the type of chain that was opened when the stream was constructed, + * we delegate the work to the method that readwrites to the block chains. + */ + if (This->smallBlockChain!=0) + { + SmallBlockChainStream_WriteAt(This->smallBlockChain, + This->currentPosition, + cb, + pv, + pcbWritten); + + } + else if (This->bigBlockChain!=0) + { + BlockChainStream_WriteAt(This->bigBlockChain, + This->currentPosition, + cb, + pv, + pcbWritten); + } + else + assert(FALSE); + + /* + * Advance the position pointer for the number of positions written. + */ + This->currentPosition.u.LowPart += *pcbWritten; + + return S_OK; +} + +/*** + * This method is part of the IStream interface. + * + * It will move the current stream pointer according to the parameters + * given. + * + * See the documentation of IStream for more info. + */ +static HRESULT WINAPI StgStreamImpl_Seek( + IStream* iface, + LARGE_INTEGER dlibMove, /* [in] */ + DWORD dwOrigin, /* [in] */ + ULARGE_INTEGER* plibNewPosition) /* [out] */ +{ + StgStreamImpl* const This=(StgStreamImpl*)iface; + + ULARGE_INTEGER newPosition; + + TRACE("(%p, %ld, %ld, %p)\n", + iface, dlibMove.u.LowPart, dwOrigin, plibNewPosition); + + /* + * The caller is allowed to pass in NULL as the new position return value. + * If it happens, we assign it to a dynamic variable to avoid special cases + * in the code below. + */ + if (plibNewPosition == 0) + { + plibNewPosition = &newPosition; + } + + /* + * The file pointer is moved depending on the given "function" + * parameter. + */ + switch (dwOrigin) + { + case STREAM_SEEK_SET: + plibNewPosition->u.HighPart = 0; + plibNewPosition->u.LowPart = 0; + break; + case STREAM_SEEK_CUR: + *plibNewPosition = This->currentPosition; + break; + case STREAM_SEEK_END: + *plibNewPosition = This->streamSize; + break; + default: + return STG_E_INVALIDFUNCTION; + } + + plibNewPosition->QuadPart = RtlLargeIntegerAdd( plibNewPosition->QuadPart, dlibMove.QuadPart ); + + /* + * tell the caller what we calculated + */ + This->currentPosition = *plibNewPosition; + + return S_OK; +} + +/*** + * This method is part of the IStream interface. + * + * It will change the size of a stream. + * + * TODO: Switch from small blocks to big blocks and vice versa. + * + * See the documentation of IStream for more info. + */ +static HRESULT WINAPI StgStreamImpl_SetSize( + IStream* iface, + ULARGE_INTEGER libNewSize) /* [in] */ +{ + StgStreamImpl* const This=(StgStreamImpl*)iface; + + StgProperty curProperty; + BOOL Success; + + TRACE("(%p, %ld)\n", iface, libNewSize.u.LowPart); + + /* + * As documented. + */ + if (libNewSize.u.HighPart != 0) + return STG_E_INVALIDFUNCTION; + + /* + * Do we have permission? + */ + if (!(This->grfMode & (STGM_WRITE | STGM_READWRITE))) + return STG_E_ACCESSDENIED; + + if (This->streamSize.u.LowPart == libNewSize.u.LowPart) + return S_OK; + + /* + * This will happen if we're creating a stream + */ + if ((This->smallBlockChain == 0) && (This->bigBlockChain == 0)) + { + if (libNewSize.u.LowPart < LIMIT_TO_USE_SMALL_BLOCK) + { + This->smallBlockChain = SmallBlockChainStream_Construct( + This->parentStorage->ancestorStorage, + This->ownerProperty); + } + else + { + This->bigBlockChain = BlockChainStream_Construct( + This->parentStorage->ancestorStorage, + NULL, + This->ownerProperty); + } + } + + /* + * Read this stream's property to see if it's small blocks or big blocks + */ + Success = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage, + This->ownerProperty, + &curProperty); + /* + * Determine if we have to switch from small to big blocks or vice versa + */ + if ( (This->smallBlockChain!=0) && + (curProperty.size.u.LowPart < LIMIT_TO_USE_SMALL_BLOCK) ) + { + if (libNewSize.u.LowPart >= LIMIT_TO_USE_SMALL_BLOCK) + { + /* + * Transform the small block chain into a big block chain + */ + This->bigBlockChain = Storage32Impl_SmallBlocksToBigBlocks( + This->parentStorage->ancestorStorage, + &This->smallBlockChain); + } + } + + if (This->smallBlockChain!=0) + { + Success = SmallBlockChainStream_SetSize(This->smallBlockChain, libNewSize); + } + else + { + Success = BlockChainStream_SetSize(This->bigBlockChain, libNewSize); + } + + /* + * Write the new information about this stream to the property + */ + Success = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage, + This->ownerProperty, + &curProperty); + + curProperty.size.u.HighPart = libNewSize.u.HighPart; + curProperty.size.u.LowPart = libNewSize.u.LowPart; + + if (Success) + { + StorageImpl_WriteProperty(This->parentStorage->ancestorStorage, + This->ownerProperty, + &curProperty); + } + + This->streamSize = libNewSize; + + return S_OK; +} + +/*** + * This method is part of the IStream interface. + * + * It will copy the 'cb' Bytes to 'pstm' IStream. + * + * See the documentation of IStream for more info. + */ +static HRESULT WINAPI StgStreamImpl_CopyTo( + IStream* iface, + IStream* pstm, /* [unique][in] */ + ULARGE_INTEGER cb, /* [in] */ + ULARGE_INTEGER* pcbRead, /* [out] */ + ULARGE_INTEGER* pcbWritten) /* [out] */ +{ + HRESULT hr = S_OK; + BYTE tmpBuffer[128]; + ULONG bytesRead, bytesWritten, copySize; + ULARGE_INTEGER totalBytesRead; + ULARGE_INTEGER totalBytesWritten; + + TRACE("(%p, %p, %ld, %p, %p)\n", + iface, pstm, cb.u.LowPart, pcbRead, pcbWritten); + + /* + * Sanity check + */ + if ( pstm == 0 ) + return STG_E_INVALIDPOINTER; + + totalBytesRead.u.LowPart = totalBytesRead.u.HighPart = 0; + totalBytesWritten.u.LowPart = totalBytesWritten.u.HighPart = 0; + + /* + * use stack to store data temporarily + * there is surely a more performant way of doing it, for now this basic + * implementation will do the job + */ + while ( cb.u.LowPart > 0 ) + { + if ( cb.u.LowPart >= 128 ) + copySize = 128; + else + copySize = cb.u.LowPart; + + IStream_Read(iface, tmpBuffer, copySize, &bytesRead); + + totalBytesRead.u.LowPart += bytesRead; + + IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten); + + totalBytesWritten.u.LowPart += bytesWritten; + + /* + * Check that read & write operations were successful + */ + if (bytesRead != bytesWritten) + { + hr = STG_E_MEDIUMFULL; + break; + } + + if (bytesRead!=copySize) + cb.u.LowPart = 0; + else + cb.u.LowPart -= bytesRead; + } + + /* + * Update number of bytes read and written + */ + if (pcbRead) + { + pcbRead->u.LowPart = totalBytesRead.u.LowPart; + pcbRead->u.HighPart = totalBytesRead.u.HighPart; + } + + if (pcbWritten) + { + pcbWritten->u.LowPart = totalBytesWritten.u.LowPart; + pcbWritten->u.HighPart = totalBytesWritten.u.HighPart; + } + return hr; +} + +/*** + * This method is part of the IStream interface. + * + * For streams contained in structured storages, this method + * does nothing. This is what the documentation tells us. + * + * See the documentation of IStream for more info. + */ +static HRESULT WINAPI StgStreamImpl_Commit( + IStream* iface, + DWORD grfCommitFlags) /* [in] */ +{ + return S_OK; +} + +/*** + * This method is part of the IStream interface. + * + * For streams contained in structured storages, this method + * does nothing. This is what the documentation tells us. + * + * See the documentation of IStream for more info. + */ +static HRESULT WINAPI StgStreamImpl_Revert( + IStream* iface) +{ + return S_OK; +} + +static HRESULT WINAPI StgStreamImpl_LockRegion( + IStream* iface, + ULARGE_INTEGER libOffset, /* [in] */ + ULARGE_INTEGER cb, /* [in] */ + DWORD dwLockType) /* [in] */ +{ + FIXME("not implemented!\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI StgStreamImpl_UnlockRegion( + IStream* iface, + ULARGE_INTEGER libOffset, /* [in] */ + ULARGE_INTEGER cb, /* [in] */ + DWORD dwLockType) /* [in] */ +{ + FIXME("not implemented!\n"); + return E_NOTIMPL; +} + +/*** + * This method is part of the IStream interface. + * + * This method returns information about the current + * stream. + * + * See the documentation of IStream for more info. + */ +static HRESULT WINAPI StgStreamImpl_Stat( + IStream* iface, + STATSTG* pstatstg, /* [out] */ + DWORD grfStatFlag) /* [in] */ +{ + StgStreamImpl* const This=(StgStreamImpl*)iface; + + StgProperty curProperty; + BOOL readSucessful; + + /* + * Read the information from the property. + */ + readSucessful = StorageImpl_ReadProperty(This->parentStorage->ancestorStorage, + This->ownerProperty, + &curProperty); + + if (readSucessful) + { + StorageUtl_CopyPropertyToSTATSTG(pstatstg, + &curProperty, + grfStatFlag); + + pstatstg->grfMode = This->grfMode; + + return S_OK; + } + + return E_FAIL; +} + +/*** + * This method is part of the IStream interface. + * + * This method returns a clone of the interface that allows for + * another seek pointer + * + * See the documentation of IStream for more info. + * + * I am not totally sure what I am doing here but I presume that this + * should be basically as simple as creating a new stream with the same + * parent etc and positioning its seek cursor. + */ +static HRESULT WINAPI StgStreamImpl_Clone( + IStream* iface, + IStream** ppstm) /* [out] */ +{ + StgStreamImpl* const This=(StgStreamImpl*)iface; + HRESULT hres; + StgStreamImpl* new_stream; + LARGE_INTEGER seek_pos; + + /* + * Sanity check + */ + if ( ppstm == 0 ) + return STG_E_INVALIDPOINTER; + + new_stream = StgStreamImpl_Construct (This->parentStorage, This->grfMode, This->ownerProperty); + + if (!new_stream) + return STG_E_INSUFFICIENTMEMORY; /* Currently the only reason for new_stream=0 */ + + *ppstm = (IStream*) new_stream; + seek_pos.QuadPart = This->currentPosition.QuadPart; + + hres=StgStreamImpl_Seek (*ppstm, seek_pos, STREAM_SEEK_SET, NULL); + + assert (SUCCEEDED(hres)); + + return S_OK; +} + +/* + * Virtual function table for the StgStreamImpl class. + */ +static IStreamVtbl StgStreamImpl_Vtbl = +{ + StgStreamImpl_QueryInterface, + StgStreamImpl_AddRef, + StgStreamImpl_Release, + StgStreamImpl_Read, + StgStreamImpl_Write, + StgStreamImpl_Seek, + StgStreamImpl_SetSize, + StgStreamImpl_CopyTo, + StgStreamImpl_Commit, + StgStreamImpl_Revert, + StgStreamImpl_LockRegion, + StgStreamImpl_UnlockRegion, + StgStreamImpl_Stat, + StgStreamImpl_Clone +}; + +/****************************************************************************** +** StgStreamImpl implementation +*/ + +/*** + * This is the constructor for the StgStreamImpl class. + * + * Params: + * parentStorage - Pointer to the storage that contains the stream to open + * ownerProperty - Index of the property that points to this stream. + */ +StgStreamImpl* StgStreamImpl_Construct( + StorageBaseImpl* parentStorage, + DWORD grfMode, + ULONG ownerProperty) +{ + StgStreamImpl* newStream; + + newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(StgStreamImpl)); + + if (newStream!=0) + { + /* + * Set-up the virtual function table and reference count. + */ + newStream->lpVtbl = &StgStreamImpl_Vtbl; + newStream->ref = 0; + + /* + * We want to nail-down the reference to the storage in case the + * stream out-lives the storage in the client application. + */ + newStream->parentStorage = parentStorage; + IStorage_AddRef((IStorage*)newStream->parentStorage); + + newStream->grfMode = grfMode; + newStream->ownerProperty = ownerProperty; + + /* + * Start the stream at the beginning. + */ + newStream->currentPosition.u.HighPart = 0; + newStream->currentPosition.u.LowPart = 0; + + /* + * Initialize the rest of the data. + */ + newStream->streamSize.u.HighPart = 0; + newStream->streamSize.u.LowPart = 0; + newStream->bigBlockChain = 0; + newStream->smallBlockChain = 0; + + /* + * Read the size from the property and determine if the blocks forming + * this stream are large or small. + */ + StgStreamImpl_OpenBlockChain(newStream); + } + + return newStream; +} diff --git a/reactos/lib/ole32/storage.c b/reactos/lib/ole32/storage.c index 16c31764fb1..0e0b4858e00 100644 --- a/reactos/lib/ole32/storage.c +++ b/reactos/lib/ole32/storage.c @@ -1,2031 +1,2031 @@ -/* Compound Storage - * - * Implemented using the documentation of the LAOLA project at - * <URL:http://wwwwbs.cs.tu-berlin.de/~schwartz/pmh/index.html> - * (Thanks to Martin Schwartz <schwartz@cs.tu-berlin.de>) - * - * Copyright 1998 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <assert.h> -#include <time.h> -#include <stdarg.h> -#include <string.h> -#include <sys/types.h> -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#endif - -#define NONAMELESSUNION -#define NONAMELESSSTRUCT -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "winternl.h" -#include "winerror.h" -#include "wine/winbase16.h" -#include "wownt32.h" -#include "wine/unicode.h" -#include "objbase.h" -#include "wine/debug.h" - -#include "ifs.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); -WINE_DECLARE_DEBUG_CHANNEL(relay); - -struct storage_header { - BYTE magic[8]; /* 00: magic */ - BYTE unknown1[36]; /* 08: unknown */ - DWORD num_of_bbd_blocks;/* 2C: length of big datablocks */ - DWORD root_startblock;/* 30: root storage first big block */ - DWORD unknown2[2]; /* 34: unknown */ - DWORD sbd_startblock; /* 3C: small block depot first big block */ - DWORD unknown3[3]; /* 40: unknown */ - DWORD bbd_list[109]; /* 4C: big data block list (up to end of sector)*/ -}; -struct storage_pps_entry { - WCHAR pps_rawname[32];/* 00: \0 terminated widechar name */ - WORD pps_sizeofname; /* 40: namelength in bytes */ - BYTE pps_type; /* 42: flags, 1 storage/dir, 2 stream, 5 root */ - BYTE pps_unknown0; /* 43: unknown */ - DWORD pps_prev; /* 44: previous pps */ - DWORD pps_next; /* 48: next pps */ - DWORD pps_dir; /* 4C: directory pps */ - GUID pps_guid; /* 50: class ID */ - DWORD pps_unknown1; /* 60: unknown */ - FILETIME pps_ft1; /* 64: filetime1 */ - FILETIME pps_ft2; /* 70: filetime2 */ - DWORD pps_sb; /* 74: data startblock */ - DWORD pps_size; /* 78: datalength. (<0x1000)?small:big blocks*/ - DWORD pps_unknown2; /* 7C: unknown */ -}; - -#define STORAGE_CHAINENTRY_FAT 0xfffffffd -#define STORAGE_CHAINENTRY_ENDOFCHAIN 0xfffffffe -#define STORAGE_CHAINENTRY_FREE 0xffffffff - - -static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1}; - -#define BIGSIZE 512 -#define SMALLSIZE 64 - -#define SMALLBLOCKS_PER_BIGBLOCK (BIGSIZE/SMALLSIZE) - -#define READ_HEADER STORAGE_get_big_block(hf,-1,(LPBYTE)&sth);assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic))); -static IStorage16Vtbl stvt16; -static IStorage16Vtbl *segstvt16 = NULL; -static IStream16Vtbl strvt16; -static IStream16Vtbl *segstrvt16 = NULL; - -/*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/ -static void _create_istorage16(LPSTORAGE16 *stg); -static void _create_istream16(LPSTREAM16 *str); - -#define IMPLEMENTED 1 - -/* The following is taken from the CorVu implementation of docfiles, and - * documents things about the file format that are not implemented here, and - * not documented by the LAOLA project. The CorVu implementation was posted - * to wine-devel in February 2004, and released under the LGPL at the same - * time. Because that implementation is in C++, it's not directly usable in - * Wine, but does have documentation value. - * - * - * #define DF_EXT_VTOC -4 - * #define DF_VTOC_VTOC -3 - * #define DF_VTOC_EOF -2 - * #define DF_VTOC_FREE -1 - * #define DF_NAMELEN 0x20 // Maximum entry name length - 31 characters plus - * // a NUL terminator - * - * #define DF_FT_STORAGE 1 - * #define DF_FT_STREAM 2 - * #define DF_FT_LOCKBYTES 3 // Not used -- How the bloody hell did I manage - * #define DF_FT_PROPERTY 4 // Not Used -- to figure these two out? - * #define DF_FT_ROOT 5 - * - * #define DF_BLOCK_SIZE 0x200 - * #define DF_VTOC_SIZE 0x80 - * #define DF_DE_PER_BLOCK 4 - * #define DF_STREAM_BLOCK_SIZE 0x40 - * - * A DocFile is divided into blocks of 512 bytes. - * The first block contains the header. - * - * The file header contains The first 109 entries in the VTOC of VTOCs. - * - * Each block pointed to by a VTOC of VTOCs contains a VTOC, which - * includes block chains - just like FAT. This is a somewhat poor - * design for the following reasons: - * - * 1. FAT was a poor file system design to begin with, and - * has long been known to be horrendously inefficient - * for day to day operations. - * - * 2. The problem is compounded here, since the file - * level streams are generally *not* read sequentially. - * This means that a significant percentage of reads - * require seeking from the start of the chain. - * - * Data chains also contain an internal VTOC. The block size for - * the standard VTOC is 512. The block size for the internal VTOC - * is 64. - * - * Now, the 109 blocks in the VTOC of VTOCs allows for files of - * up to around 7MB. So what do you think happens if that's - * exceeded? Well, there's an entry in the header block which - * points to the first block used as additional storage for - * the VTOC of VTOCs. - * - * Now we can get up to around 15MB. Now, guess how the file - * format adds in another block to the VTOC of VTOCs. Come on, - * it's no big surprise. That's right - the last entry in each - * block extending the VTOC of VTOCs is, you guessed it, the - * block number of the next block containing an extension to - * the VTOC of VTOCs. The VTOC of VTOCs is chained!!!! - * - * So, to review: - * - * 1. If you are using a FAT file system, the location of - * your file's blocks is stored in chains. - * - * 2. At the abstract level, the file contains a VTOC of VTOCs, - * which is stored in the most inefficient possible format for - * random access - a chain (AKA list). - * - * 3. The VTOC of VTOCs contains descriptions of three file level - * streams: - * - * a. The Directory stream - * b. The Data stream - * c. The Data VTOC stream - * - * These are, of course, represented as chains. - * - * 4. The Data VTOC contains data describing the chains of blocks - * within the Data stream. - * - * That's right - we have a total of four levels of block chains! - * - * Now, is that complicated enough for you? No? OK, there's another - * complication. If an individual stream (ie. an IStream) reaches - * 4096 bytes in size, it gets moved from the Data Stream to - * a new file level stream. Now, if the stream then gets truncated - * back to less than 4096 bytes, it returns to the data stream. - * - * The effect of using this format can be seen very easily. Pick - * an arbitrary application with a grid data representation that - * can export to both Lotus 123 and Excel 5 or higher. Export - * a large file to Lotus 123 and time it. Export the same thing - * to Excel 5 and time that. The difference is the inefficiency - * of the Microsoft DocFile format. - * - * - * #define TOTAL_SIMPLE_VTOCS 109 - * - * struct DocFile_Header - * { - * df_byte iMagic1; // 0xd0 - * df_byte iMagic2; // 0xcf - * df_byte iMagic3; // 0x11 - * df_byte iMagic4; // 0xe0 - Spells D0CF11E0, or DocFile - * df_byte iMagic5; // 161 (igi upside down) - * df_byte iMagic6; // 177 (lli upside down - see below - * df_byte iMagic7; // 26 (gz upside down) - * df_byte iMagic8; // 225 (szz upside down) - see below - * df_int4 aiUnknown1[4]; - * df_int4 iVersion; // DocFile Version - 0x03003E - * df_int4 aiUnknown2[4]; - * df_int4 nVTOCs; // Number of VTOCs - * df_int4 iFirstDirBlock; // First Directory Block - * df_int4 aiUnknown3[2]; - * df_int4 iFirstDataVTOC; // First data VTOC block - * df_int4 iHasData; // 1 if there is data in the file - yes, this is important - * df_int4 iExtendedVTOC; // Extended VTOC location - * df_int4 iExtendedVTOCSize; // Size of extended VTOC (+1?) - * df_int4 aiVTOCofVTOCs[TOTAL_SIMPLE_VTOCS]; - * }; - * - * struct DocFile_VTOC - * { - * df_int4 aiBlocks[DF_VTOC_SIZE]; - * }; - * - * - * The meaning of the magic numbers - * - * 0xd0cf11e0 is DocFile with a zero on the end (sort of) - * - * If you key 177161 into a calculator, then turn the calculator - * upside down, you get igilli, which may be a reference to - * somebody's name, or to the Hebrew word for "angel". - * - * If you key 26225 into a calculator, then turn it upside down, you - * get szzgz. Microsoft has a tradition of creating nonsense words - * using the letters s, g, z and y. We think szzgz may be one of the - * Microsoft placeholder variables, along the lines of foo, bar and baz. - * Alternatively, it could be 22526, which would be gzszz. - * - * - * struct DocFile_DirEnt - * { - * df_char achEntryName[DF_NAMELEN]; // Entry Name - * df_int2 iNameLen; // Name length in bytes, including NUL terminator - * df_byte iFileType; // Entry type - * df_byte iColour; // 1 = Black, 0 = Red - * df_int4 iLeftSibling; // Next Left Sibling Entry - See below - * df_int4 iRightSibling; // Next Right Sibling Entry - * df_int4 iFirstChild; // First Child Entry - * df_byte achClassID[16]; // Class ID - * df_int4 iStateBits; // [GS]etStateBits value - * df_int4 iCreatedLow; // Low DWORD of creation time - * df_int4 iCreatedHigh; // High DWORD of creation time - * df_int4 iModifiedLow; // Low DWORD of modification time - * df_int4 iModifiedHigh; // High DWORD of modification time - * df_int4 iVTOCPosition; // VTOC Position - * df_int4 iFileSize; // Size of the stream - * df_int4 iZero; // We think this is part of the 64 bit stream size - must be 0 - * }; - * - * Siblings - * ======== - * - * Siblings are stored in an obscure but incredibly elegant - * data structure called a red-black tree. This is generally - * defined as a 2-3-4 tree stored in a binary tree. - * - * A red-black tree can always be balanced very easily. The rules - * for a red-black tree are as follows: - * - * 1. The root node is always black. - * 2. The parent of a red node is always black. - * - * There is a Java demo of red-black trees at: - * - * http://langevin.usc.edu/BST/RedBlackTree-Example.html - * - * This demo is an excellent tool for learning how red-black - * trees work, without having to go through the process of - * learning how they were derived. - * - * Within the tree, elements are ordered by the length of the - * name and within that, ASCII order by name. This causes the - * apparently bizarre reordering you see when you use dfview. - * - * This is a somewhat bizarre choice. It suggests that the - * designer of the DocFile format was trying to optimise - * searching through the directory entries. However searching - * through directory entries is a relatively rare operation. - * Reading and seeking within a stream are much more common - * operations, especially within the file level streams, yet - * these use the horrendously inefficient FAT chains. - * - * This suggests that the designer was probably somebody - * fresh out of university, who had some basic knowledge of - * basic data structures, but little knowledge of anything - * more practical. It is bizarre to attempt to optimise - * directory searches while not using a more efficient file - * block locating system than FAT (seedling/sapling/tree - * would result in a massive improvement - in fact we have - * an alternative to DocFiles that we use internally that - * uses seedling/sapling/tree and *is* far more efficient). - * - * It is worth noting that the MS implementation of red-black - * trees is incorrect (I can tell you're surprised) and - * actually causes more operations to occur than are really - * needed. Fortunately the fact that our implementation is - * correct will not cause any problems - the MS implementation - * still appears to cause the tree to satisfy the rules, albeit - * a sequence of the same insertions in the different - * implementations may result in a different, and possibly - * deeper (but never shallower) tree. - */ - - -/****************************************************************************** - * STORAGE_get_big_block [Internal] - * - * Reading OLE compound storage - */ -static BOOL -STORAGE_get_big_block(HANDLE hf,int n,BYTE *block) -{ - DWORD result; - - assert(n>=-1); - if ((SetFilePointer( hf, (n+1)*BIGSIZE, NULL, - SEEK_SET ) == INVALID_SET_FILE_POINTER) && GetLastError()) - { - WARN(" seek failed (%ld)\n",GetLastError()); - return FALSE; - } - if (!ReadFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) - { - WARN("(block size %d): read didn't read (%ld)\n",n,GetLastError()); - return FALSE; - } - return TRUE; -} - -/****************************************************************************** - * STORAGE_put_big_block [INTERNAL] - */ -static BOOL -STORAGE_put_big_block(HANDLE hf,int n,BYTE *block) -{ - DWORD result; - - assert(n>=-1); - if ((SetFilePointer( hf, (n+1)*BIGSIZE, NULL, - SEEK_SET ) == INVALID_SET_FILE_POINTER) && GetLastError()) - { - WARN("seek failed (%ld)\n",GetLastError()); - return FALSE; - } - if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) - { - WARN(" write failed (%ld)\n",GetLastError()); - return FALSE; - } - return TRUE; -} - -/****************************************************************************** - * STORAGE_get_next_big_blocknr [INTERNAL] - */ -static int -STORAGE_get_next_big_blocknr(HANDLE hf,int blocknr) { - INT bbs[BIGSIZE/sizeof(INT)]; - struct storage_header sth; - - READ_HEADER; - - assert(blocknr>>7<sth.num_of_bbd_blocks); - if (sth.bbd_list[blocknr>>7]==0xffffffff) - return -5; - if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs)) - return -5; - assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE); - return bbs[blocknr&0x7f]; -} - -/****************************************************************************** - * STORAGE_get_nth_next_big_blocknr [INTERNAL] - */ -static int -STORAGE_get_nth_next_big_blocknr(HANDLE hf,int blocknr,int nr) { - INT bbs[BIGSIZE/sizeof(INT)]; - int lastblock = -1; - struct storage_header sth; - - READ_HEADER; - - assert(blocknr>=0); - while (nr--) { - assert((blocknr>>7)<sth.num_of_bbd_blocks); - assert(sth.bbd_list[blocknr>>7]!=0xffffffff); - - /* simple caching... */ - if (lastblock!=sth.bbd_list[blocknr>>7]) { - BOOL ret = STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs); - assert(ret); - lastblock = sth.bbd_list[blocknr>>7]; - } - blocknr = bbs[blocknr&0x7f]; - } - return blocknr; -} - -/****************************************************************************** - * STORAGE_get_root_pps_entry [Internal] - */ -static BOOL -STORAGE_get_root_pps_entry(HANDLE hf,struct storage_pps_entry *pstde) { - int blocknr,i; - BYTE block[BIGSIZE]; - struct storage_pps_entry *stde=(struct storage_pps_entry*)block; - struct storage_header sth; - - READ_HEADER; - blocknr = sth.root_startblock; - while (blocknr>=0) { - BOOL ret = STORAGE_get_big_block(hf,blocknr,block); - assert(ret); - for (i=0;i<4;i++) { - if (!stde[i].pps_sizeofname) - continue; - if (stde[i].pps_type==5) { - *pstde=stde[i]; - return TRUE; - } - } - blocknr=STORAGE_get_next_big_blocknr(hf,blocknr); - } - return FALSE; -} - -/****************************************************************************** - * STORAGE_get_small_block [INTERNAL] - */ -static BOOL -STORAGE_get_small_block(HANDLE hf,int blocknr,BYTE *sblock) { - BYTE block[BIGSIZE]; - int bigblocknr; - struct storage_pps_entry root; - BOOL ret; - - assert(blocknr>=0); - ret = STORAGE_get_root_pps_entry(hf,&root); - assert(ret); - bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK); - assert(bigblocknr>=0); - ret = STORAGE_get_big_block(hf,bigblocknr,block); - assert(ret); - - memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE); - return TRUE; -} - -/****************************************************************************** - * STORAGE_put_small_block [INTERNAL] - */ -static BOOL -STORAGE_put_small_block(HANDLE hf,int blocknr,BYTE *sblock) { - BYTE block[BIGSIZE]; - int bigblocknr; - struct storage_pps_entry root; - BOOL ret; - - assert(blocknr>=0); - - ret = STORAGE_get_root_pps_entry(hf,&root); - assert(ret); - bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK); - assert(bigblocknr>=0); - ret = STORAGE_get_big_block(hf,bigblocknr,block); - assert(ret); - - memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE); - ret = STORAGE_put_big_block(hf,bigblocknr,block); - assert(ret); - return TRUE; -} - -/****************************************************************************** - * STORAGE_get_next_small_blocknr [INTERNAL] - */ -static int -STORAGE_get_next_small_blocknr(HANDLE hf,int blocknr) { - BYTE block[BIGSIZE]; - LPINT sbd = (LPINT)block; - int bigblocknr; - struct storage_header sth; - BOOL ret; - - READ_HEADER; - assert(blocknr>=0); - bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128); - assert(bigblocknr>=0); - ret = STORAGE_get_big_block(hf,bigblocknr,block); - assert(ret); - assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE); - return sbd[blocknr & (128-1)]; -} - -/****************************************************************************** - * STORAGE_get_nth_next_small_blocknr [INTERNAL] - */ -static int -STORAGE_get_nth_next_small_blocknr(HANDLE hf,int blocknr,int nr) { - int lastblocknr=-1; - BYTE block[BIGSIZE]; - LPINT sbd = (LPINT)block; - struct storage_header sth; - BOOL ret; - - READ_HEADER; - assert(blocknr>=0); - while ((nr--) && (blocknr>=0)) { - if (lastblocknr/128!=blocknr/128) { - int bigblocknr; - bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128); - assert(bigblocknr>=0); - ret = STORAGE_get_big_block(hf,bigblocknr,block); - assert(ret); - lastblocknr = blocknr; - } - assert(lastblocknr>=0); - lastblocknr=blocknr; - blocknr=sbd[blocknr & (128-1)]; - assert(blocknr!=STORAGE_CHAINENTRY_FREE); - } - return blocknr; -} - -/****************************************************************************** - * STORAGE_get_pps_entry [INTERNAL] - */ -static int -STORAGE_get_pps_entry(HANDLE hf,int n,struct storage_pps_entry *pstde) { - int blocknr; - BYTE block[BIGSIZE]; - struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3)); - struct storage_header sth; - BOOL ret; - - READ_HEADER; - /* we have 4 pps entries per big block */ - blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4); - assert(blocknr>=0); - ret = STORAGE_get_big_block(hf,blocknr,block); - assert(ret); - - *pstde=*stde; - return 1; -} - -/****************************************************************************** - * STORAGE_put_pps_entry [Internal] - */ -static int -STORAGE_put_pps_entry(HANDLE hf,int n,struct storage_pps_entry *pstde) { - int blocknr; - BYTE block[BIGSIZE]; - struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3)); - struct storage_header sth; - BOOL ret; - - READ_HEADER; - - /* we have 4 pps entries per big block */ - blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4); - assert(blocknr>=0); - ret = STORAGE_get_big_block(hf,blocknr,block); - assert(ret); - *stde=*pstde; - ret = STORAGE_put_big_block(hf,blocknr,block); - assert(ret); - return 1; -} - -/****************************************************************************** - * STORAGE_look_for_named_pps [Internal] - */ -static int -STORAGE_look_for_named_pps(HANDLE hf,int n,LPOLESTR name) { - struct storage_pps_entry stde; - int ret; - - if (n==-1) - return -1; - if (1!=STORAGE_get_pps_entry(hf,n,&stde)) - return -1; - - if (!lstrcmpW(name,stde.pps_rawname)) - return n; - if (stde.pps_prev != -1) { - ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name); - if (ret!=-1) - return ret; - } - if (stde.pps_next != -1) { - ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name); - if (ret!=-1) - return ret; - } - return -1; -} - -/****************************************************************************** - * STORAGE_dump_pps_entry [Internal] - * - * FIXME - * Function is unused - */ -void -STORAGE_dump_pps_entry(struct storage_pps_entry *stde) { - char name[33]; - - WideCharToMultiByte( CP_ACP, 0, stde->pps_rawname, -1, name, sizeof(name), NULL, NULL); - if (!stde->pps_sizeofname) - return; - DPRINTF("name: %s\n",name); - DPRINTF("type: %d\n",stde->pps_type); - DPRINTF("prev pps: %ld\n",stde->pps_prev); - DPRINTF("next pps: %ld\n",stde->pps_next); - DPRINTF("dir pps: %ld\n",stde->pps_dir); - DPRINTF("guid: %s\n",debugstr_guid(&(stde->pps_guid))); - if (stde->pps_type !=2) { - time_t t; - DWORD dw; - RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft1),&dw); - t = dw; - DPRINTF("ts1: %s\n",ctime(&t)); - RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft2),&dw); - t = dw; - DPRINTF("ts2: %s\n",ctime(&t)); - } - DPRINTF("startblock: %ld\n",stde->pps_sb); - DPRINTF("size: %ld\n",stde->pps_size); -} - -/****************************************************************************** - * STORAGE_init_storage [INTERNAL] - */ -static BOOL -STORAGE_init_storage(HANDLE hf) { - BYTE block[BIGSIZE]; - LPDWORD bbs; - struct storage_header *sth; - struct storage_pps_entry *stde; - DWORD result; - - SetFilePointer( hf, 0, NULL, SEEK_SET ); - /* block -1 is the storage header */ - sth = (struct storage_header*)block; - memcpy(sth->magic,STORAGE_magic,8); - memset(sth->unknown1,0,sizeof(sth->unknown1)); - memset(sth->unknown2,0,sizeof(sth->unknown2)); - memset(sth->unknown3,0,sizeof(sth->unknown3)); - sth->num_of_bbd_blocks = 1; - sth->root_startblock = 1; - sth->sbd_startblock = 0xffffffff; - memset(sth->bbd_list,0xff,sizeof(sth->bbd_list)); - sth->bbd_list[0] = 0; - if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE; - /* block 0 is the big block directory */ - bbs=(LPDWORD)block; - memset(block,0xff,sizeof(block)); /* mark all blocks as free */ - bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */ - bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */ - if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE; - /* block 1 is the root directory entry */ - memset(block,0x00,sizeof(block)); - stde = (struct storage_pps_entry*)block; - MultiByteToWideChar( CP_ACP, 0, "RootEntry", -1, stde->pps_rawname, - sizeof(stde->pps_rawname)/sizeof(WCHAR)); - stde->pps_sizeofname = (strlenW(stde->pps_rawname)+1) * sizeof(WCHAR); - stde->pps_type = 5; - stde->pps_dir = -1; - stde->pps_next = -1; - stde->pps_prev = -1; - stde->pps_sb = 0xffffffff; - stde->pps_size = 0; - return (WriteFile( hf, block, BIGSIZE, &result, NULL ) && result == BIGSIZE); -} - -/****************************************************************************** - * STORAGE_set_big_chain [Internal] - */ -static BOOL -STORAGE_set_big_chain(HANDLE hf,int blocknr,INT type) { - BYTE block[BIGSIZE]; - LPINT bbd = (LPINT)block; - int nextblocknr,bigblocknr; - struct storage_header sth; - BOOL ret; - - READ_HEADER; - assert(blocknr!=type); - while (blocknr>=0) { - bigblocknr = sth.bbd_list[blocknr/128]; - assert(bigblocknr>=0); - ret = STORAGE_get_big_block(hf,bigblocknr,block); - assert(ret); - - nextblocknr = bbd[blocknr&(128-1)]; - bbd[blocknr&(128-1)] = type; - if (type>=0) - return TRUE; - ret = STORAGE_put_big_block(hf,bigblocknr,block); - assert(ret); - type = STORAGE_CHAINENTRY_FREE; - blocknr = nextblocknr; - } - return TRUE; -} - -/****************************************************************************** - * STORAGE_set_small_chain [Internal] - */ -static BOOL -STORAGE_set_small_chain(HANDLE hf,int blocknr,INT type) { - BYTE block[BIGSIZE]; - LPINT sbd = (LPINT)block; - int lastblocknr,nextsmallblocknr,bigblocknr; - struct storage_header sth; - BOOL ret; - - READ_HEADER; - - assert(blocknr!=type); - lastblocknr=-129;bigblocknr=-2; - while (blocknr>=0) { - /* cache block ... */ - if (lastblocknr/128!=blocknr/128) { - bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128); - assert(bigblocknr>=0); - ret = STORAGE_get_big_block(hf,bigblocknr,block); - assert(ret); - } - lastblocknr = blocknr; - nextsmallblocknr = sbd[blocknr&(128-1)]; - sbd[blocknr&(128-1)] = type; - ret = STORAGE_put_big_block(hf,bigblocknr,block); - assert(ret); - if (type>=0) - return TRUE; - type = STORAGE_CHAINENTRY_FREE; - blocknr = nextsmallblocknr; - } - return TRUE; -} - -/****************************************************************************** - * STORAGE_get_free_big_blocknr [Internal] - */ -static int -STORAGE_get_free_big_blocknr(HANDLE hf) { - BYTE block[BIGSIZE]; - LPINT sbd = (LPINT)block; - int lastbigblocknr,i,bigblocknr; - unsigned int curblock; - struct storage_header sth; - BOOL ret; - - READ_HEADER; - curblock = 0; - lastbigblocknr = -1; - bigblocknr = sth.bbd_list[curblock]; - while (curblock<sth.num_of_bbd_blocks) { - assert(bigblocknr>=0); - ret = STORAGE_get_big_block(hf,bigblocknr,block); - assert(ret); - for (i=0;i<128;i++) - if (sbd[i]==STORAGE_CHAINENTRY_FREE) { - sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN; - ret = STORAGE_put_big_block(hf,bigblocknr,block); - assert(ret); - memset(block,0x42,sizeof(block)); - ret = STORAGE_put_big_block(hf,i+curblock*128,block); - assert(ret); - return i+curblock*128; - } - lastbigblocknr = bigblocknr; - bigblocknr = sth.bbd_list[++curblock]; - } - bigblocknr = curblock*128; - /* since we have marked all blocks from 0 up to curblock*128-1 - * the next free one is curblock*128, where we happily put our - * next large block depot. - */ - memset(block,0xff,sizeof(block)); - /* mark the block allocated and returned by this function */ - sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN; - ret = STORAGE_put_big_block(hf,bigblocknr,block); - assert(ret); - - /* if we had a bbd block already (mostlikely) we need - * to link the new one into the chain - */ - if (lastbigblocknr!=-1) { - ret = STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr); - assert(ret); - } - sth.bbd_list[curblock]=bigblocknr; - sth.num_of_bbd_blocks++; - assert(sth.num_of_bbd_blocks==curblock+1); - ret = STORAGE_put_big_block(hf,-1,(LPBYTE)&sth); - assert(ret); - - /* Set the end of the chain for the bigblockdepots */ - ret = STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN); - assert(ret); - /* add 1, for the first entry is used for the additional big block - * depot. (means we already used bigblocknr) */ - memset(block,0x42,sizeof(block)); - /* allocate this block (filled with 0x42) */ - ret = STORAGE_put_big_block(hf,bigblocknr+1,block); - assert(ret); - return bigblocknr+1; -} - - -/****************************************************************************** - * STORAGE_get_free_small_blocknr [Internal] - */ -static int -STORAGE_get_free_small_blocknr(HANDLE hf) { - BYTE block[BIGSIZE]; - LPINT sbd = (LPINT)block; - int lastbigblocknr,newblocknr,i,curblock,bigblocknr; - struct storage_pps_entry root; - struct storage_header sth; - - READ_HEADER; - bigblocknr = sth.sbd_startblock; - curblock = 0; - lastbigblocknr = -1; - newblocknr = -1; - while (bigblocknr>=0) { - if (!STORAGE_get_big_block(hf,bigblocknr,block)) - return -1; - for (i=0;i<128;i++) - if (sbd[i]==STORAGE_CHAINENTRY_FREE) { - sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN; - newblocknr = i+curblock*128; - break; - } - if (i!=128) - break; - lastbigblocknr = bigblocknr; - bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr); - curblock++; - } - if (newblocknr==-1) { - bigblocknr = STORAGE_get_free_big_blocknr(hf); - if (bigblocknr<0) - return -1; - READ_HEADER; - memset(block,0xff,sizeof(block)); - sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; - if (!STORAGE_put_big_block(hf,bigblocknr,block)) - return -1; - if (lastbigblocknr==-1) { - sth.sbd_startblock = bigblocknr; - if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */ - return -1; - } else { - if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr)) - return -1; - } - if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN)) - return -1; - newblocknr = curblock*128; - } - /* allocate enough big blocks for storing the allocated small block */ - if (!STORAGE_get_root_pps_entry(hf,&root)) - return -1; - if (root.pps_sb==-1) - lastbigblocknr = -1; - else - lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE); - while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) { - /* we need to allocate more stuff */ - bigblocknr = STORAGE_get_free_big_blocknr(hf); - if (bigblocknr<0) - return -1; - READ_HEADER; - if (root.pps_sb==-1) { - root.pps_sb = bigblocknr; - root.pps_size += BIGSIZE; - } else { - if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr)) - return -1; - root.pps_size += BIGSIZE; - } - lastbigblocknr = bigblocknr; - } - if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN)) - return -1; - if (!STORAGE_put_pps_entry(hf,0,&root)) - return -1; - return newblocknr; -} - -/****************************************************************************** - * STORAGE_get_free_pps_entry [Internal] - */ -static int -STORAGE_get_free_pps_entry(HANDLE hf) { - int blocknr, i, curblock, lastblocknr=-1; - BYTE block[BIGSIZE]; - struct storage_pps_entry *stde = (struct storage_pps_entry*)block; - struct storage_header sth; - - READ_HEADER; - blocknr = sth.root_startblock; - assert(blocknr>=0); - curblock=0; - while (blocknr>=0) { - if (!STORAGE_get_big_block(hf,blocknr,block)) - return -1; - for (i=0;i<4;i++) - if (stde[i].pps_sizeofname==0) /* free */ - return curblock*4+i; - lastblocknr = blocknr; - blocknr = STORAGE_get_next_big_blocknr(hf,blocknr); - curblock++; - } - assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN); - blocknr = STORAGE_get_free_big_blocknr(hf); - /* sth invalidated */ - if (blocknr<0) - return -1; - - if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr)) - return -1; - if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN)) - return -1; - memset(block,0,sizeof(block)); - STORAGE_put_big_block(hf,blocknr,block); - return curblock*4; -} - -/* --- IStream16 implementation */ - -typedef struct -{ - /* IUnknown fields */ - IStream16Vtbl *lpVtbl; - DWORD ref; - /* IStream16 fields */ - SEGPTR thisptr; /* pointer to this struct as segmented */ - struct storage_pps_entry stde; - int ppsent; - HANDLE hf; - ULARGE_INTEGER offset; -} IStream16Impl; - -/****************************************************************************** - * IStream16_QueryInterface [STORAGE.518] - */ -HRESULT WINAPI IStream16_fnQueryInterface( - IStream16* iface,REFIID refiid,LPVOID *obj -) { - IStream16Impl *This = (IStream16Impl *)iface; - TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj); - if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) { - *obj = This; - return 0; - } - return OLE_E_ENUM_NOMORE; - -} - -/****************************************************************************** - * IStream16_AddRef [STORAGE.519] - */ -ULONG WINAPI IStream16_fnAddRef(IStream16* iface) { - IStream16Impl *This = (IStream16Impl *)iface; - return InterlockedIncrement(&This->ref); -} - -/****************************************************************************** - * IStream16_Release [STORAGE.520] - */ -ULONG WINAPI IStream16_fnRelease(IStream16* iface) { - IStream16Impl *This = (IStream16Impl *)iface; - ULONG ref; - FlushFileBuffers(This->hf); - ref = InterlockedDecrement(&This->ref); - if (!ref) { - CloseHandle(This->hf); - UnMapLS( This->thisptr ); - HeapFree( GetProcessHeap(), 0, This ); - } - return ref; -} - -/****************************************************************************** - * IStream16_Seek [STORAGE.523] - * - * FIXME - * Does not handle 64 bits - */ -HRESULT WINAPI IStream16_fnSeek( - IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos -) { - IStream16Impl *This = (IStream16Impl *)iface; - TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.u.HighPart,offset.u.LowPart,whence,newpos); - - switch (whence) { - /* unix SEEK_xx should be the same as win95 ones */ - case SEEK_SET: - /* offset must be ==0 (<0 is invalid, and >0 cannot be handled - * right now. - */ - assert(offset.u.HighPart==0); - This->offset.u.HighPart = offset.u.HighPart; - This->offset.u.LowPart = offset.u.LowPart; - break; - case SEEK_CUR: - if (offset.u.HighPart < 0) { - /* FIXME: is this negation correct ? */ - offset.u.HighPart = -offset.u.HighPart; - offset.u.LowPart = (0xffffffff ^ offset.u.LowPart)+1; - - assert(offset.u.HighPart==0); - assert(This->offset.u.LowPart >= offset.u.LowPart); - This->offset.u.LowPart -= offset.u.LowPart; - } else { - assert(offset.u.HighPart==0); - This->offset.u.LowPart+= offset.u.LowPart; - } - break; - case SEEK_END: - assert(offset.u.HighPart==0); - This->offset.u.LowPart = This->stde.pps_size-offset.u.LowPart; - break; - } - if (This->offset.u.LowPart>This->stde.pps_size) - This->offset.u.LowPart=This->stde.pps_size; - if (newpos) *newpos = This->offset; - return S_OK; -} - -/****************************************************************************** - * IStream16_Read [STORAGE.521] - */ -HRESULT WINAPI IStream16_fnRead( - IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead -) { - IStream16Impl *This = (IStream16Impl *)iface; - BYTE block[BIGSIZE]; - ULONG *bytesread=pcbRead,xxread; - int blocknr; - LPBYTE pbv = pv; - - TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead); - if (!pcbRead) bytesread=&xxread; - *bytesread = 0; - - if (cb>This->stde.pps_size-This->offset.u.LowPart) - cb=This->stde.pps_size-This->offset.u.LowPart; - if (This->stde.pps_size < 0x1000) { - /* use small block reader */ - blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.u.LowPart/SMALLSIZE); - while (cb) { - unsigned int cc; - - if (!STORAGE_get_small_block(This->hf,blocknr,block)) { - WARN("small block read failed!!!\n"); - return E_FAIL; - } - cc = cb; - if (cc>SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1))) - cc=SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1)); - memcpy(pbv,block+(This->offset.u.LowPart&(SMALLSIZE-1)),cc); - This->offset.u.LowPart+=cc; - pbv+=cc; - *bytesread+=cc; - cb-=cc; - blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr); - } - } else { - /* use big block reader */ - blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.u.LowPart/BIGSIZE); - while (cb) { - unsigned int cc; - - if (!STORAGE_get_big_block(This->hf,blocknr,block)) { - WARN("big block read failed!!!\n"); - return E_FAIL; - } - cc = cb; - if (cc>BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1))) - cc=BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1)); - memcpy(pbv,block+(This->offset.u.LowPart&(BIGSIZE-1)),cc); - This->offset.u.LowPart+=cc; - pbv+=cc; - *bytesread+=cc; - cb-=cc; - blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr); - } - } - return S_OK; -} - -/****************************************************************************** - * IStream16_Write [STORAGE.522] - */ -HRESULT WINAPI IStream16_fnWrite( - IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite -) { - IStream16Impl *This = (IStream16Impl *)iface; - BYTE block[BIGSIZE]; - ULONG *byteswritten=pcbWrite,xxwritten; - int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc; - HANDLE hf = This->hf; - const BYTE* pbv = (const BYTE*)pv; - - if (!pcbWrite) byteswritten=&xxwritten; - *byteswritten = 0; - - TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite); - /* do we need to junk some blocks? */ - newsize = This->offset.u.LowPart+cb; - oldsize = This->stde.pps_size; - if (newsize < oldsize) { - if (oldsize < 0x1000) { - /* only small blocks */ - blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE); - - assert(blocknr>=0); - - /* will set the rest of the chain to 'free' */ - if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN)) - return E_FAIL; - } else { - if (newsize >= 0x1000) { - blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE); - assert(blocknr>=0); - - /* will set the rest of the chain to 'free' */ - if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN)) - return E_FAIL; - } else { - /* Migrate large blocks to small blocks - * (we just migrate newsize bytes) - */ - LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE); - HRESULT r = E_FAIL; - - cc = newsize; - blocknr = This->stde.pps_sb; - curdata = data; - while (cc>0) { - if (!STORAGE_get_big_block(hf,blocknr,curdata)) { - HeapFree(GetProcessHeap(),0,data); - return E_FAIL; - } - curdata += BIGSIZE; - cc -= BIGSIZE; - blocknr = STORAGE_get_next_big_blocknr(hf,blocknr); - } - /* frees complete chain for this stream */ - if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE)) - goto err; - curdata = data; - blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf); - if (blocknr<0) - goto err; - cc = newsize; - while (cc>0) { - if (!STORAGE_put_small_block(hf,blocknr,curdata)) - goto err; - cc -= SMALLSIZE; - if (cc<=0) { - if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN)) - goto err; - break; - } else { - int newblocknr = STORAGE_get_free_small_blocknr(hf); - if (newblocknr<0) - goto err; - if (!STORAGE_set_small_chain(hf,blocknr,newblocknr)) - goto err; - blocknr = newblocknr; - } - curdata += SMALLSIZE; - } - r = S_OK; - err: - HeapFree(GetProcessHeap(),0,data); - if(r != S_OK) - return r; - } - } - This->stde.pps_size = newsize; - } - - if (newsize > oldsize) { - if (oldsize >= 0x1000) { - /* should return the block right before the 'endofchain' */ - blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE); - assert(blocknr>=0); - lastblocknr = blocknr; - for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) { - blocknr = STORAGE_get_free_big_blocknr(hf); - if (blocknr<0) - return E_FAIL; - if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr)) - return E_FAIL; - lastblocknr = blocknr; - } - if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN)) - return E_FAIL; - } else { - if (newsize < 0x1000) { - /* find startblock */ - if (!oldsize) - This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf); - else - blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE); - if (blocknr<0) - return E_FAIL; - - /* allocate required new small blocks */ - lastblocknr = blocknr; - for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) { - blocknr = STORAGE_get_free_small_blocknr(hf); - if (blocknr<0) - return E_FAIL; - if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr)) - return E_FAIL; - lastblocknr = blocknr; - } - /* and terminate the chain */ - if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN)) - return E_FAIL; - } else { - if (!oldsize) { - /* no single block allocated yet */ - blocknr=STORAGE_get_free_big_blocknr(hf); - if (blocknr<0) - return E_FAIL; - This->stde.pps_sb = blocknr; - } else { - /* Migrate small blocks to big blocks */ - LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE); - HRESULT r = E_FAIL; - - cc = oldsize; - blocknr = This->stde.pps_sb; - curdata = data; - /* slurp in */ - while (cc>0) { - if (!STORAGE_get_small_block(hf,blocknr,curdata)) - goto err2; - curdata += SMALLSIZE; - cc -= SMALLSIZE; - blocknr = STORAGE_get_next_small_blocknr(hf,blocknr); - } - /* free small block chain */ - if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE)) - goto err2; - curdata = data; - blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf); - if (blocknr<0) - goto err2; - /* put the data into the big blocks */ - cc = This->stde.pps_size; - while (cc>0) { - if (!STORAGE_put_big_block(hf,blocknr,curdata)) - goto err2; - cc -= BIGSIZE; - if (cc<=0) { - if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN)) - goto err2; - break; - } else { - int newblocknr = STORAGE_get_free_big_blocknr(hf); - if (newblocknr<0) - goto err2; - if (!STORAGE_set_big_chain(hf,blocknr,newblocknr)) - goto err2; - blocknr = newblocknr; - } - curdata += BIGSIZE; - } - r = S_OK; - err2: - HeapFree(GetProcessHeap(),0,data); - if(r != S_OK) - return r; - } - /* generate big blocks to fit the new data */ - lastblocknr = blocknr; - for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) { - blocknr = STORAGE_get_free_big_blocknr(hf); - if (blocknr<0) - return E_FAIL; - if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr)) - return E_FAIL; - lastblocknr = blocknr; - } - /* terminate chain */ - if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN)) - return E_FAIL; - } - } - This->stde.pps_size = newsize; - } - - /* There are just some cases where we didn't modify it, we write it out - * everytime - */ - if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde))) - return E_FAIL; - - /* finally the write pass */ - if (This->stde.pps_size < 0x1000) { - blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.u.LowPart/SMALLSIZE); - assert(blocknr>=0); - while (cb>0) { - /* we ensured that it is allocated above */ - assert(blocknr>=0); - /* Read old block everytime, since we can have - * overlapping data at START and END of the write - */ - if (!STORAGE_get_small_block(hf,blocknr,block)) - return E_FAIL; - - cc = SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1)); - if (cc>cb) - cc=cb; - memcpy( ((LPBYTE)block)+(This->offset.u.LowPart&(SMALLSIZE-1)), - pbv+curoffset, - cc - ); - if (!STORAGE_put_small_block(hf,blocknr,block)) - return E_FAIL; - cb -= cc; - curoffset += cc; - pbv += cc; - This->offset.u.LowPart += cc; - *byteswritten += cc; - blocknr = STORAGE_get_next_small_blocknr(hf,blocknr); - } - } else { - blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.u.LowPart/BIGSIZE); - assert(blocknr>=0); - while (cb>0) { - /* we ensured that it is allocated above, so it better is */ - assert(blocknr>=0); - /* read old block everytime, since we can have - * overlapping data at START and END of the write - */ - if (!STORAGE_get_big_block(hf,blocknr,block)) - return E_FAIL; - - cc = BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1)); - if (cc>cb) - cc=cb; - memcpy( ((LPBYTE)block)+(This->offset.u.LowPart&(BIGSIZE-1)), - pbv+curoffset, - cc - ); - if (!STORAGE_put_big_block(hf,blocknr,block)) - return E_FAIL; - cb -= cc; - curoffset += cc; - pbv += cc; - This->offset.u.LowPart += cc; - *byteswritten += cc; - blocknr = STORAGE_get_next_big_blocknr(hf,blocknr); - } - } - return S_OK; -} - -/****************************************************************************** - * _create_istream16 [Internal] - */ -static void _create_istream16(LPSTREAM16 *str) { - IStream16Impl* lpst; - - if (!strvt16.QueryInterface) { - HMODULE16 wp = GetModuleHandle16("STORAGE"); - if (wp>=32) { - /* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */ -#define VTENT(xfn) strvt16.xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.xfn) - VTENT(QueryInterface); - VTENT(AddRef); - VTENT(Release); - VTENT(Read); - VTENT(Write); - VTENT(Seek); - VTENT(SetSize); - VTENT(CopyTo); - VTENT(Commit); - VTENT(Revert); - VTENT(LockRegion); - VTENT(UnlockRegion); - VTENT(Stat); - VTENT(Clone); -#undef VTENT - segstrvt16 = (IStream16Vtbl*)MapLS( &strvt16 ); - } else { -#define VTENT(xfn) strvt16.xfn = IStream16_fn##xfn; - VTENT(QueryInterface); - VTENT(AddRef); - VTENT(Release); - VTENT(Read); - VTENT(Write); - VTENT(Seek); - /* - VTENT(CopyTo); - VTENT(Commit); - VTENT(SetSize); - VTENT(Revert); - VTENT(LockRegion); - VTENT(UnlockRegion); - VTENT(Stat); - VTENT(Clone); - */ -#undef VTENT - segstrvt16 = &strvt16; - } - } - lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) ); - lpst->lpVtbl = segstrvt16; - lpst->ref = 1; - lpst->thisptr = MapLS( lpst ); - *str = (void*)lpst->thisptr; -} - - -/* --- IStream32 implementation */ - -typedef struct -{ - /* IUnknown fields */ - IStreamVtbl *lpVtbl; - DWORD ref; - /* IStream32 fields */ - struct storage_pps_entry stde; - int ppsent; - HANDLE hf; - ULARGE_INTEGER offset; -} IStream32Impl; - -/***************************************************************************** - * IStream32_QueryInterface [VTABLE] - */ -HRESULT WINAPI IStream_fnQueryInterface( - IStream* iface,REFIID refiid,LPVOID *obj -) { - IStream32Impl *This = (IStream32Impl *)iface; - - TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj); - if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) { - *obj = This; - return 0; - } - return OLE_E_ENUM_NOMORE; - -} - -/****************************************************************************** - * IStream32_AddRef [VTABLE] - */ -ULONG WINAPI IStream_fnAddRef(IStream* iface) { - IStream32Impl *This = (IStream32Impl *)iface; - return InterlockedIncrement(&This->ref); -} - -/****************************************************************************** - * IStream32_Release [VTABLE] - */ -ULONG WINAPI IStream_fnRelease(IStream* iface) { - IStream32Impl *This = (IStream32Impl *)iface; - ULONG ref; - FlushFileBuffers(This->hf); - ref = InterlockedDecrement(&This->ref); - if (!ref) { - CloseHandle(This->hf); - HeapFree( GetProcessHeap(), 0, This ); - } - return ref; -} - -/* --- IStorage16 implementation */ - -typedef struct -{ - /* IUnknown fields */ - IStorage16Vtbl *lpVtbl; - DWORD ref; - /* IStorage16 fields */ - SEGPTR thisptr; /* pointer to this struct as segmented */ - struct storage_pps_entry stde; - int ppsent; - HANDLE hf; -} IStorage16Impl; - -/****************************************************************************** - * IStorage16_QueryInterface [STORAGE.500] - */ -HRESULT WINAPI IStorage16_fnQueryInterface( - IStorage16* iface,REFIID refiid,LPVOID *obj -) { - IStorage16Impl *This = (IStorage16Impl *)iface; - - TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj); - - if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) { - *obj = This; - return 0; - } - return OLE_E_ENUM_NOMORE; -} - -/****************************************************************************** - * IStorage16_AddRef [STORAGE.501] - */ -ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) { - IStorage16Impl *This = (IStorage16Impl *)iface; - return InterlockedIncrement(&This->ref); -} - -/****************************************************************************** - * IStorage16_Release [STORAGE.502] - */ -ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) { - IStorage16Impl *This = (IStorage16Impl *)iface; - ULONG ref; - ref = InterlockedDecrement(&This->ref); - if (!ref) - { - UnMapLS( This->thisptr ); - HeapFree( GetProcessHeap(), 0, This ); - } - return ref; -} - -/****************************************************************************** - * IStorage16_Stat [STORAGE.517] - */ -HRESULT WINAPI IStorage16_fnStat( - LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag -) { - IStorage16Impl *This = (IStorage16Impl *)iface; - DWORD len = WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, NULL, 0, NULL, NULL ); - LPSTR nameA = HeapAlloc( GetProcessHeap(), 0, len ); - - TRACE("(%p)->(%p,0x%08lx)\n", - This,pstatstg,grfStatFlag - ); - WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, nameA, len, NULL, NULL ); - pstatstg->pwcsName=(LPOLESTR16)MapLS( nameA ); - pstatstg->type = This->stde.pps_type; - pstatstg->cbSize.u.LowPart = This->stde.pps_size; - pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */ - pstatstg->atime = This->stde.pps_ft2; /* FIXME */ - pstatstg->ctime = This->stde.pps_ft2; /* FIXME */ - pstatstg->grfMode = 0; /* FIXME */ - pstatstg->grfLocksSupported = 0; /* FIXME */ - pstatstg->clsid = This->stde.pps_guid; - pstatstg->grfStateBits = 0; /* FIXME */ - pstatstg->reserved = 0; - return S_OK; -} - -/****************************************************************************** - * IStorage16_Commit [STORAGE.509] - */ -HRESULT WINAPI IStorage16_fnCommit( - LPSTORAGE16 iface,DWORD commitflags -) { - IStorage16Impl *This = (IStorage16Impl *)iface; - FIXME("(%p)->(0x%08lx),STUB!\n", - This,commitflags - ); - return S_OK; -} - -/****************************************************************************** - * IStorage16_CopyTo [STORAGE.507] - */ -HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) { - IStorage16Impl *This = (IStorage16Impl *)iface; - FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n", - This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest - ); - return S_OK; -} - - -/****************************************************************************** - * IStorage16_CreateStorage [STORAGE.505] - */ -HRESULT WINAPI IStorage16_fnCreateStorage( - LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg -) { - IStorage16Impl *This = (IStorage16Impl *)iface; - IStorage16Impl* lpstg; - int ppsent,x; - struct storage_pps_entry stde; - struct storage_header sth; - HANDLE hf=This->hf; - BOOL ret; - int nPPSEntries; - - READ_HEADER; - - TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n", - This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg - ); - if (grfMode & STGM_TRANSACTED) - FIXME("We do not support transacted Compound Storage. Using direct mode.\n"); - _create_istorage16(ppstg); - lpstg = MapSL((SEGPTR)*ppstg); - lpstg->hf = This->hf; - - ppsent=STORAGE_get_free_pps_entry(lpstg->hf); - if (ppsent<0) - return E_FAIL; - stde=This->stde; - if (stde.pps_dir==-1) { - stde.pps_dir = ppsent; - x = This->ppsent; - } else { - FIXME(" use prev chain too ?\n"); - x=stde.pps_dir; - if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde)) - return E_FAIL; - while (stde.pps_next!=-1) { - x=stde.pps_next; - if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde)) - return E_FAIL; - } - stde.pps_next = ppsent; - } - ret = STORAGE_put_pps_entry(lpstg->hf,x,&stde); - assert(ret); - nPPSEntries = STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)); - assert(nPPSEntries == 1); - MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname, - sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR)); - lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR); - lpstg->stde.pps_next = -1; - lpstg->stde.pps_prev = -1; - lpstg->stde.pps_dir = -1; - lpstg->stde.pps_sb = -1; - lpstg->stde.pps_size = 0; - lpstg->stde.pps_type = 1; - lpstg->ppsent = ppsent; - /* FIXME: timestamps? */ - if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde))) - return E_FAIL; - return S_OK; -} - -/****************************************************************************** - * IStorage16_CreateStream [STORAGE.503] - */ -HRESULT WINAPI IStorage16_fnCreateStream( - LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm -) { - IStorage16Impl *This = (IStorage16Impl *)iface; - IStream16Impl* lpstr; - int ppsent,x; - struct storage_pps_entry stde; - BOOL ret; - int nPPSEntries; - - TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n", - This,pwcsName,grfMode,reserved1,reserved2,ppstm - ); - if (grfMode & STGM_TRANSACTED) - FIXME("We do not support transacted Compound Storage. Using direct mode.\n"); - _create_istream16(ppstm); - lpstr = MapSL((SEGPTR)*ppstm); - DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(), - &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS ); - lpstr->offset.u.LowPart = 0; - lpstr->offset.u.HighPart = 0; - - ppsent=STORAGE_get_free_pps_entry(lpstr->hf); - if (ppsent<0) - return E_FAIL; - stde=This->stde; - if (stde.pps_next==-1) - x=This->ppsent; - else - while (stde.pps_next!=-1) { - x=stde.pps_next; - if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde)) - return E_FAIL; - } - stde.pps_next = ppsent; - ret = STORAGE_put_pps_entry(lpstr->hf,x,&stde); - assert(ret); - nPPSEntries = STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)); - assert(nPPSEntries == 1); - MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname, - sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR)); - lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR); - lpstr->stde.pps_next = -1; - lpstr->stde.pps_prev = -1; - lpstr->stde.pps_dir = -1; - lpstr->stde.pps_sb = -1; - lpstr->stde.pps_size = 0; - lpstr->stde.pps_type = 2; - lpstr->ppsent = ppsent; - /* FIXME: timestamps? */ - if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde))) - return E_FAIL; - return S_OK; -} - -/****************************************************************************** - * IStorage16_OpenStorage [STORAGE.506] - */ -HRESULT WINAPI IStorage16_fnOpenStorage( - LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg -) { - IStorage16Impl *This = (IStorage16Impl *)iface; - IStream16Impl* lpstg; - WCHAR name[33]; - int newpps; - - TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n", - This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg - ); - if (grfMode & STGM_TRANSACTED) - FIXME("We do not support transacted Compound Storage. Using direct mode.\n"); - _create_istorage16(ppstg); - lpstg = MapSL((SEGPTR)*ppstg); - DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(), - &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS ); - MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR)); - newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name); - if (newpps==-1) { - IStream16_fnRelease((IStream16*)lpstg); - return E_FAIL; - } - - if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) { - IStream16_fnRelease((IStream16*)lpstg); - return E_FAIL; - } - lpstg->ppsent = newpps; - return S_OK; -} - -/****************************************************************************** - * IStorage16_OpenStream [STORAGE.504] - */ -HRESULT WINAPI IStorage16_fnOpenStream( - LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm -) { - IStorage16Impl *This = (IStorage16Impl *)iface; - IStream16Impl* lpstr; - WCHAR name[33]; - int newpps; - - TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n", - This,pwcsName,reserved1,grfMode,reserved2,ppstm - ); - if (grfMode & STGM_TRANSACTED) - FIXME("We do not support transacted Compound Storage. Using direct mode.\n"); - _create_istream16(ppstm); - lpstr = MapSL((SEGPTR)*ppstm); - DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(), - &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS ); - MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR)); - newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name); - if (newpps==-1) { - IStream16_fnRelease((IStream16*)lpstr); - return E_FAIL; - } - - if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) { - IStream16_fnRelease((IStream16*)lpstr); - return E_FAIL; - } - lpstr->offset.u.LowPart = 0; - lpstr->offset.u.HighPart = 0; - lpstr->ppsent = newpps; - return S_OK; -} - -/****************************************************************************** - * _create_istorage16 [INTERNAL] - */ -static void _create_istorage16(LPSTORAGE16 *stg) { - IStorage16Impl* lpst; - - if (!stvt16.QueryInterface) { - HMODULE16 wp = GetModuleHandle16("STORAGE"); - if (wp>=32) { -#define VTENT(xfn) stvt16.xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn); - VTENT(QueryInterface) - VTENT(AddRef) - VTENT(Release) - VTENT(CreateStream) - VTENT(OpenStream) - VTENT(CreateStorage) - VTENT(OpenStorage) - VTENT(CopyTo) - VTENT(MoveElementTo) - VTENT(Commit) - VTENT(Revert) - VTENT(EnumElements) - VTENT(DestroyElement) - VTENT(RenameElement) - VTENT(SetElementTimes) - VTENT(SetClass) - VTENT(SetStateBits) - VTENT(Stat) -#undef VTENT - segstvt16 = (IStorage16Vtbl*)MapLS( &stvt16 ); - } else { -#define VTENT(xfn) stvt16.xfn = IStorage16_fn##xfn; - VTENT(QueryInterface) - VTENT(AddRef) - VTENT(Release) - VTENT(CreateStream) - VTENT(OpenStream) - VTENT(CreateStorage) - VTENT(OpenStorage) - VTENT(CopyTo) - VTENT(Commit) - /* not (yet) implemented ... - VTENT(MoveElementTo) - VTENT(Revert) - VTENT(EnumElements) - VTENT(DestroyElement) - VTENT(RenameElement) - VTENT(SetElementTimes) - VTENT(SetClass) - VTENT(SetStateBits) - VTENT(Stat) - */ -#undef VTENT - segstvt16 = &stvt16; - } - } - lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) ); - lpst->lpVtbl = segstvt16; - lpst->ref = 1; - lpst->thisptr = MapLS(lpst); - *stg = (void*)lpst->thisptr; -} - -/****************************************************************************** - * Storage API functions - */ - -/****************************************************************************** - * StgCreateDocFileA [STORAGE.1] - */ -HRESULT WINAPI StgCreateDocFile16( - LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen -) { - HANDLE hf; - int i,ret; - IStorage16Impl* lpstg; - struct storage_pps_entry stde; - - TRACE("(%s,0x%08lx,0x%08lx,%p)\n", - pwcsName,grfMode,reserved,ppstgOpen - ); - _create_istorage16(ppstgOpen); - hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0); - if (hf==INVALID_HANDLE_VALUE) { - WARN("couldn't open file for storage:%ld\n",GetLastError()); - return E_FAIL; - } - lpstg = MapSL((SEGPTR)*ppstgOpen); - lpstg->hf = hf; - /* FIXME: check for existence before overwriting? */ - if (!STORAGE_init_storage(hf)) { - CloseHandle(hf); - return E_FAIL; - } - i=0;ret=0; - while (!ret) { /* neither 1 nor <0 */ - ret=STORAGE_get_pps_entry(hf,i,&stde); - if ((ret==1) && (stde.pps_type==5)) { - lpstg->stde = stde; - lpstg->ppsent = i; - break; - } - i++; - } - if (ret!=1) { - IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */ - return E_FAIL; - } - - return S_OK; -} - -/****************************************************************************** - * StgIsStorageFile [STORAGE.5] - */ -HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) { - UNICODE_STRING strW; - HRESULT ret; - - RtlCreateUnicodeStringFromAsciiz(&strW, fn); - ret = StgIsStorageFile( strW.Buffer ); - RtlFreeUnicodeString( &strW ); - - return ret; -} - -/****************************************************************************** - * StgOpenStorage [STORAGE.3] - */ -HRESULT WINAPI StgOpenStorage16( - LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode, - SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen -) { - HANDLE hf; - int ret,i; - IStorage16Impl* lpstg; - struct storage_pps_entry stde; - - TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n", - pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen - ); - _create_istorage16(ppstgOpen); - hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); - if (hf==INVALID_HANDLE_VALUE) { - WARN("Couldn't open file for storage\n"); - return E_FAIL; - } - lpstg = MapSL((SEGPTR)*ppstgOpen); - lpstg->hf = hf; - - i=0;ret=0; - while (!ret) { /* neither 1 nor <0 */ - ret=STORAGE_get_pps_entry(hf,i,&stde); - if ((ret==1) && (stde.pps_type==5)) { - lpstg->stde=stde; - break; - } - i++; - } - if (ret!=1) { - IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */ - return E_FAIL; - } - return S_OK; - -} - -/****************************************************************************** - * StgIsStorageILockBytes [STORAGE.6] - * - * Determines if the ILockBytes contains a storage object. - */ -HRESULT WINAPI StgIsStorageILockBytes16(SEGPTR plkbyt) -{ - DWORD args[6]; - HRESULT hres; - HANDLE16 hsig; - - args[0] = (DWORD)plkbyt; /* iface */ - args[1] = args[2] = 0; /* ULARGE_INTEGER offset */ - args[3] = (DWORD)K32WOWGlobalAllocLock16( 0, 8, &hsig ); /* sig */ - args[4] = 8; - args[5] = 0; - - if (!K32WOWCallback16Ex( - (DWORD)((ILockBytes16Vtbl*)MapSL( - (SEGPTR)((LPLOCKBYTES16)MapSL(plkbyt))->lpVtbl) - )->ReadAt, - WCB16_PASCAL, - 6*sizeof(DWORD), - (LPVOID)args, - (LPDWORD)&hres - )) { - ERR("CallTo16 ILockBytes16::ReadAt() failed, hres %lx\n",hres); - return hres; - } - if (memcmp(MapSL(args[3]), STORAGE_magic, sizeof(STORAGE_magic)) == 0) { - K32WOWGlobalUnlockFree16(args[3]); - return S_OK; - } - K32WOWGlobalUnlockFree16(args[3]); - return S_FALSE; -} - -/****************************************************************************** - * StgOpenStorageOnILockBytes [STORAGE.4] - */ -HRESULT WINAPI StgOpenStorageOnILockBytes16( - ILockBytes16 *plkbyt, - IStorage16 *pstgPriority, - DWORD grfMode, - SNB16 snbExclude, - DWORD reserved, - IStorage16 **ppstgOpen) -{ - IStorage16Impl* lpstg; - - if ((plkbyt == 0) || (ppstgOpen == 0)) - return STG_E_INVALIDPOINTER; - - *ppstgOpen = 0; - - _create_istorage16(ppstgOpen); - lpstg = MapSL((SEGPTR)*ppstgOpen); - - /* just teach it to use HANDLE instead of ilockbytes :/ */ - - return S_OK; -} +/* Compound Storage + * + * Implemented using the documentation of the LAOLA project at + * <URL:http://wwwwbs.cs.tu-berlin.de/~schwartz/pmh/index.html> + * (Thanks to Martin Schwartz <schwartz@cs.tu-berlin.de>) + * + * Copyright 1998 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <assert.h> +#include <time.h> +#include <stdarg.h> +#include <string.h> +#include <sys/types.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winternl.h" +#include "winerror.h" +#include "wine/winbase16.h" +#include "wownt32.h" +#include "wine/unicode.h" +#include "objbase.h" +#include "wine/debug.h" + +#include "ifs.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); +WINE_DECLARE_DEBUG_CHANNEL(relay); + +struct storage_header { + BYTE magic[8]; /* 00: magic */ + BYTE unknown1[36]; /* 08: unknown */ + DWORD num_of_bbd_blocks;/* 2C: length of big datablocks */ + DWORD root_startblock;/* 30: root storage first big block */ + DWORD unknown2[2]; /* 34: unknown */ + DWORD sbd_startblock; /* 3C: small block depot first big block */ + DWORD unknown3[3]; /* 40: unknown */ + DWORD bbd_list[109]; /* 4C: big data block list (up to end of sector)*/ +}; +struct storage_pps_entry { + WCHAR pps_rawname[32];/* 00: \0 terminated widechar name */ + WORD pps_sizeofname; /* 40: namelength in bytes */ + BYTE pps_type; /* 42: flags, 1 storage/dir, 2 stream, 5 root */ + BYTE pps_unknown0; /* 43: unknown */ + DWORD pps_prev; /* 44: previous pps */ + DWORD pps_next; /* 48: next pps */ + DWORD pps_dir; /* 4C: directory pps */ + GUID pps_guid; /* 50: class ID */ + DWORD pps_unknown1; /* 60: unknown */ + FILETIME pps_ft1; /* 64: filetime1 */ + FILETIME pps_ft2; /* 70: filetime2 */ + DWORD pps_sb; /* 74: data startblock */ + DWORD pps_size; /* 78: datalength. (<0x1000)?small:big blocks*/ + DWORD pps_unknown2; /* 7C: unknown */ +}; + +#define STORAGE_CHAINENTRY_FAT 0xfffffffd +#define STORAGE_CHAINENTRY_ENDOFCHAIN 0xfffffffe +#define STORAGE_CHAINENTRY_FREE 0xffffffff + + +static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1}; + +#define BIGSIZE 512 +#define SMALLSIZE 64 + +#define SMALLBLOCKS_PER_BIGBLOCK (BIGSIZE/SMALLSIZE) + +#define READ_HEADER STORAGE_get_big_block(hf,-1,(LPBYTE)&sth);assert(!memcmp(STORAGE_magic,sth.magic,sizeof(STORAGE_magic))); +static IStorage16Vtbl stvt16; +static IStorage16Vtbl *segstvt16 = NULL; +static IStream16Vtbl strvt16; +static IStream16Vtbl *segstrvt16 = NULL; + +/*ULONG WINAPI IStorage16_AddRef(LPSTORAGE16 this);*/ +static void _create_istorage16(LPSTORAGE16 *stg); +static void _create_istream16(LPSTREAM16 *str); + +#define IMPLEMENTED 1 + +/* The following is taken from the CorVu implementation of docfiles, and + * documents things about the file format that are not implemented here, and + * not documented by the LAOLA project. The CorVu implementation was posted + * to wine-devel in February 2004, and released under the LGPL at the same + * time. Because that implementation is in C++, it's not directly usable in + * Wine, but does have documentation value. + * + * + * #define DF_EXT_VTOC -4 + * #define DF_VTOC_VTOC -3 + * #define DF_VTOC_EOF -2 + * #define DF_VTOC_FREE -1 + * #define DF_NAMELEN 0x20 // Maximum entry name length - 31 characters plus + * // a NUL terminator + * + * #define DF_FT_STORAGE 1 + * #define DF_FT_STREAM 2 + * #define DF_FT_LOCKBYTES 3 // Not used -- How the bloody hell did I manage + * #define DF_FT_PROPERTY 4 // Not Used -- to figure these two out? + * #define DF_FT_ROOT 5 + * + * #define DF_BLOCK_SIZE 0x200 + * #define DF_VTOC_SIZE 0x80 + * #define DF_DE_PER_BLOCK 4 + * #define DF_STREAM_BLOCK_SIZE 0x40 + * + * A DocFile is divided into blocks of 512 bytes. + * The first block contains the header. + * + * The file header contains The first 109 entries in the VTOC of VTOCs. + * + * Each block pointed to by a VTOC of VTOCs contains a VTOC, which + * includes block chains - just like FAT. This is a somewhat poor + * design for the following reasons: + * + * 1. FAT was a poor file system design to begin with, and + * has long been known to be horrendously inefficient + * for day to day operations. + * + * 2. The problem is compounded here, since the file + * level streams are generally *not* read sequentially. + * This means that a significant percentage of reads + * require seeking from the start of the chain. + * + * Data chains also contain an internal VTOC. The block size for + * the standard VTOC is 512. The block size for the internal VTOC + * is 64. + * + * Now, the 109 blocks in the VTOC of VTOCs allows for files of + * up to around 7MB. So what do you think happens if that's + * exceeded? Well, there's an entry in the header block which + * points to the first block used as additional storage for + * the VTOC of VTOCs. + * + * Now we can get up to around 15MB. Now, guess how the file + * format adds in another block to the VTOC of VTOCs. Come on, + * it's no big surprise. That's right - the last entry in each + * block extending the VTOC of VTOCs is, you guessed it, the + * block number of the next block containing an extension to + * the VTOC of VTOCs. The VTOC of VTOCs is chained!!!! + * + * So, to review: + * + * 1. If you are using a FAT file system, the location of + * your file's blocks is stored in chains. + * + * 2. At the abstract level, the file contains a VTOC of VTOCs, + * which is stored in the most inefficient possible format for + * random access - a chain (AKA list). + * + * 3. The VTOC of VTOCs contains descriptions of three file level + * streams: + * + * a. The Directory stream + * b. The Data stream + * c. The Data VTOC stream + * + * These are, of course, represented as chains. + * + * 4. The Data VTOC contains data describing the chains of blocks + * within the Data stream. + * + * That's right - we have a total of four levels of block chains! + * + * Now, is that complicated enough for you? No? OK, there's another + * complication. If an individual stream (ie. an IStream) reaches + * 4096 bytes in size, it gets moved from the Data Stream to + * a new file level stream. Now, if the stream then gets truncated + * back to less than 4096 bytes, it returns to the data stream. + * + * The effect of using this format can be seen very easily. Pick + * an arbitrary application with a grid data representation that + * can export to both Lotus 123 and Excel 5 or higher. Export + * a large file to Lotus 123 and time it. Export the same thing + * to Excel 5 and time that. The difference is the inefficiency + * of the Microsoft DocFile format. + * + * + * #define TOTAL_SIMPLE_VTOCS 109 + * + * struct DocFile_Header + * { + * df_byte iMagic1; // 0xd0 + * df_byte iMagic2; // 0xcf + * df_byte iMagic3; // 0x11 + * df_byte iMagic4; // 0xe0 - Spells D0CF11E0, or DocFile + * df_byte iMagic5; // 161 (igi upside down) + * df_byte iMagic6; // 177 (lli upside down - see below + * df_byte iMagic7; // 26 (gz upside down) + * df_byte iMagic8; // 225 (szz upside down) - see below + * df_int4 aiUnknown1[4]; + * df_int4 iVersion; // DocFile Version - 0x03003E + * df_int4 aiUnknown2[4]; + * df_int4 nVTOCs; // Number of VTOCs + * df_int4 iFirstDirBlock; // First Directory Block + * df_int4 aiUnknown3[2]; + * df_int4 iFirstDataVTOC; // First data VTOC block + * df_int4 iHasData; // 1 if there is data in the file - yes, this is important + * df_int4 iExtendedVTOC; // Extended VTOC location + * df_int4 iExtendedVTOCSize; // Size of extended VTOC (+1?) + * df_int4 aiVTOCofVTOCs[TOTAL_SIMPLE_VTOCS]; + * }; + * + * struct DocFile_VTOC + * { + * df_int4 aiBlocks[DF_VTOC_SIZE]; + * }; + * + * + * The meaning of the magic numbers + * + * 0xd0cf11e0 is DocFile with a zero on the end (sort of) + * + * If you key 177161 into a calculator, then turn the calculator + * upside down, you get igilli, which may be a reference to + * somebody's name, or to the Hebrew word for "angel". + * + * If you key 26225 into a calculator, then turn it upside down, you + * get szzgz. Microsoft has a tradition of creating nonsense words + * using the letters s, g, z and y. We think szzgz may be one of the + * Microsoft placeholder variables, along the lines of foo, bar and baz. + * Alternatively, it could be 22526, which would be gzszz. + * + * + * struct DocFile_DirEnt + * { + * df_char achEntryName[DF_NAMELEN]; // Entry Name + * df_int2 iNameLen; // Name length in bytes, including NUL terminator + * df_byte iFileType; // Entry type + * df_byte iColour; // 1 = Black, 0 = Red + * df_int4 iLeftSibling; // Next Left Sibling Entry - See below + * df_int4 iRightSibling; // Next Right Sibling Entry + * df_int4 iFirstChild; // First Child Entry + * df_byte achClassID[16]; // Class ID + * df_int4 iStateBits; // [GS]etStateBits value + * df_int4 iCreatedLow; // Low DWORD of creation time + * df_int4 iCreatedHigh; // High DWORD of creation time + * df_int4 iModifiedLow; // Low DWORD of modification time + * df_int4 iModifiedHigh; // High DWORD of modification time + * df_int4 iVTOCPosition; // VTOC Position + * df_int4 iFileSize; // Size of the stream + * df_int4 iZero; // We think this is part of the 64 bit stream size - must be 0 + * }; + * + * Siblings + * ======== + * + * Siblings are stored in an obscure but incredibly elegant + * data structure called a red-black tree. This is generally + * defined as a 2-3-4 tree stored in a binary tree. + * + * A red-black tree can always be balanced very easily. The rules + * for a red-black tree are as follows: + * + * 1. The root node is always black. + * 2. The parent of a red node is always black. + * + * There is a Java demo of red-black trees at: + * + * http://langevin.usc.edu/BST/RedBlackTree-Example.html + * + * This demo is an excellent tool for learning how red-black + * trees work, without having to go through the process of + * learning how they were derived. + * + * Within the tree, elements are ordered by the length of the + * name and within that, ASCII order by name. This causes the + * apparently bizarre reordering you see when you use dfview. + * + * This is a somewhat bizarre choice. It suggests that the + * designer of the DocFile format was trying to optimise + * searching through the directory entries. However searching + * through directory entries is a relatively rare operation. + * Reading and seeking within a stream are much more common + * operations, especially within the file level streams, yet + * these use the horrendously inefficient FAT chains. + * + * This suggests that the designer was probably somebody + * fresh out of university, who had some basic knowledge of + * basic data structures, but little knowledge of anything + * more practical. It is bizarre to attempt to optimise + * directory searches while not using a more efficient file + * block locating system than FAT (seedling/sapling/tree + * would result in a massive improvement - in fact we have + * an alternative to DocFiles that we use internally that + * uses seedling/sapling/tree and *is* far more efficient). + * + * It is worth noting that the MS implementation of red-black + * trees is incorrect (I can tell you're surprised) and + * actually causes more operations to occur than are really + * needed. Fortunately the fact that our implementation is + * correct will not cause any problems - the MS implementation + * still appears to cause the tree to satisfy the rules, albeit + * a sequence of the same insertions in the different + * implementations may result in a different, and possibly + * deeper (but never shallower) tree. + */ + + +/****************************************************************************** + * STORAGE_get_big_block [Internal] + * + * Reading OLE compound storage + */ +static BOOL +STORAGE_get_big_block(HANDLE hf,int n,BYTE *block) +{ + DWORD result; + + assert(n>=-1); + if ((SetFilePointer( hf, (n+1)*BIGSIZE, NULL, + SEEK_SET ) == INVALID_SET_FILE_POINTER) && GetLastError()) + { + WARN(" seek failed (%ld)\n",GetLastError()); + return FALSE; + } + if (!ReadFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) + { + WARN("(block size %d): read didn't read (%ld)\n",n,GetLastError()); + return FALSE; + } + return TRUE; +} + +/****************************************************************************** + * STORAGE_put_big_block [INTERNAL] + */ +static BOOL +STORAGE_put_big_block(HANDLE hf,int n,BYTE *block) +{ + DWORD result; + + assert(n>=-1); + if ((SetFilePointer( hf, (n+1)*BIGSIZE, NULL, + SEEK_SET ) == INVALID_SET_FILE_POINTER) && GetLastError()) + { + WARN("seek failed (%ld)\n",GetLastError()); + return FALSE; + } + if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) + { + WARN(" write failed (%ld)\n",GetLastError()); + return FALSE; + } + return TRUE; +} + +/****************************************************************************** + * STORAGE_get_next_big_blocknr [INTERNAL] + */ +static int +STORAGE_get_next_big_blocknr(HANDLE hf,int blocknr) { + INT bbs[BIGSIZE/sizeof(INT)]; + struct storage_header sth; + + READ_HEADER; + + assert(blocknr>>7<sth.num_of_bbd_blocks); + if (sth.bbd_list[blocknr>>7]==0xffffffff) + return -5; + if (!STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs)) + return -5; + assert(bbs[blocknr&0x7f]!=STORAGE_CHAINENTRY_FREE); + return bbs[blocknr&0x7f]; +} + +/****************************************************************************** + * STORAGE_get_nth_next_big_blocknr [INTERNAL] + */ +static int +STORAGE_get_nth_next_big_blocknr(HANDLE hf,int blocknr,int nr) { + INT bbs[BIGSIZE/sizeof(INT)]; + int lastblock = -1; + struct storage_header sth; + + READ_HEADER; + + assert(blocknr>=0); + while (nr--) { + assert((blocknr>>7)<sth.num_of_bbd_blocks); + assert(sth.bbd_list[blocknr>>7]!=0xffffffff); + + /* simple caching... */ + if (lastblock!=sth.bbd_list[blocknr>>7]) { + BOOL ret = STORAGE_get_big_block(hf,sth.bbd_list[blocknr>>7],(LPBYTE)bbs); + assert(ret); + lastblock = sth.bbd_list[blocknr>>7]; + } + blocknr = bbs[blocknr&0x7f]; + } + return blocknr; +} + +/****************************************************************************** + * STORAGE_get_root_pps_entry [Internal] + */ +static BOOL +STORAGE_get_root_pps_entry(HANDLE hf,struct storage_pps_entry *pstde) { + int blocknr,i; + BYTE block[BIGSIZE]; + struct storage_pps_entry *stde=(struct storage_pps_entry*)block; + struct storage_header sth; + + READ_HEADER; + blocknr = sth.root_startblock; + while (blocknr>=0) { + BOOL ret = STORAGE_get_big_block(hf,blocknr,block); + assert(ret); + for (i=0;i<4;i++) { + if (!stde[i].pps_sizeofname) + continue; + if (stde[i].pps_type==5) { + *pstde=stde[i]; + return TRUE; + } + } + blocknr=STORAGE_get_next_big_blocknr(hf,blocknr); + } + return FALSE; +} + +/****************************************************************************** + * STORAGE_get_small_block [INTERNAL] + */ +static BOOL +STORAGE_get_small_block(HANDLE hf,int blocknr,BYTE *sblock) { + BYTE block[BIGSIZE]; + int bigblocknr; + struct storage_pps_entry root; + BOOL ret; + + assert(blocknr>=0); + ret = STORAGE_get_root_pps_entry(hf,&root); + assert(ret); + bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK); + assert(bigblocknr>=0); + ret = STORAGE_get_big_block(hf,bigblocknr,block); + assert(ret); + + memcpy(sblock,((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),SMALLSIZE); + return TRUE; +} + +/****************************************************************************** + * STORAGE_put_small_block [INTERNAL] + */ +static BOOL +STORAGE_put_small_block(HANDLE hf,int blocknr,BYTE *sblock) { + BYTE block[BIGSIZE]; + int bigblocknr; + struct storage_pps_entry root; + BOOL ret; + + assert(blocknr>=0); + + ret = STORAGE_get_root_pps_entry(hf,&root); + assert(ret); + bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,blocknr/SMALLBLOCKS_PER_BIGBLOCK); + assert(bigblocknr>=0); + ret = STORAGE_get_big_block(hf,bigblocknr,block); + assert(ret); + + memcpy(((LPBYTE)block)+SMALLSIZE*(blocknr&(SMALLBLOCKS_PER_BIGBLOCK-1)),sblock,SMALLSIZE); + ret = STORAGE_put_big_block(hf,bigblocknr,block); + assert(ret); + return TRUE; +} + +/****************************************************************************** + * STORAGE_get_next_small_blocknr [INTERNAL] + */ +static int +STORAGE_get_next_small_blocknr(HANDLE hf,int blocknr) { + BYTE block[BIGSIZE]; + LPINT sbd = (LPINT)block; + int bigblocknr; + struct storage_header sth; + BOOL ret; + + READ_HEADER; + assert(blocknr>=0); + bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128); + assert(bigblocknr>=0); + ret = STORAGE_get_big_block(hf,bigblocknr,block); + assert(ret); + assert(sbd[blocknr & 127]!=STORAGE_CHAINENTRY_FREE); + return sbd[blocknr & (128-1)]; +} + +/****************************************************************************** + * STORAGE_get_nth_next_small_blocknr [INTERNAL] + */ +static int +STORAGE_get_nth_next_small_blocknr(HANDLE hf,int blocknr,int nr) { + int lastblocknr=-1; + BYTE block[BIGSIZE]; + LPINT sbd = (LPINT)block; + struct storage_header sth; + BOOL ret; + + READ_HEADER; + assert(blocknr>=0); + while ((nr--) && (blocknr>=0)) { + if (lastblocknr/128!=blocknr/128) { + int bigblocknr; + bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128); + assert(bigblocknr>=0); + ret = STORAGE_get_big_block(hf,bigblocknr,block); + assert(ret); + lastblocknr = blocknr; + } + assert(lastblocknr>=0); + lastblocknr=blocknr; + blocknr=sbd[blocknr & (128-1)]; + assert(blocknr!=STORAGE_CHAINENTRY_FREE); + } + return blocknr; +} + +/****************************************************************************** + * STORAGE_get_pps_entry [INTERNAL] + */ +static int +STORAGE_get_pps_entry(HANDLE hf,int n,struct storage_pps_entry *pstde) { + int blocknr; + BYTE block[BIGSIZE]; + struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3)); + struct storage_header sth; + BOOL ret; + + READ_HEADER; + /* we have 4 pps entries per big block */ + blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4); + assert(blocknr>=0); + ret = STORAGE_get_big_block(hf,blocknr,block); + assert(ret); + + *pstde=*stde; + return 1; +} + +/****************************************************************************** + * STORAGE_put_pps_entry [Internal] + */ +static int +STORAGE_put_pps_entry(HANDLE hf,int n,struct storage_pps_entry *pstde) { + int blocknr; + BYTE block[BIGSIZE]; + struct storage_pps_entry *stde = (struct storage_pps_entry*)(((LPBYTE)block)+128*(n&3)); + struct storage_header sth; + BOOL ret; + + READ_HEADER; + + /* we have 4 pps entries per big block */ + blocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.root_startblock,n/4); + assert(blocknr>=0); + ret = STORAGE_get_big_block(hf,blocknr,block); + assert(ret); + *stde=*pstde; + ret = STORAGE_put_big_block(hf,blocknr,block); + assert(ret); + return 1; +} + +/****************************************************************************** + * STORAGE_look_for_named_pps [Internal] + */ +static int +STORAGE_look_for_named_pps(HANDLE hf,int n,LPOLESTR name) { + struct storage_pps_entry stde; + int ret; + + if (n==-1) + return -1; + if (1!=STORAGE_get_pps_entry(hf,n,&stde)) + return -1; + + if (!lstrcmpW(name,stde.pps_rawname)) + return n; + if (stde.pps_prev != -1) { + ret=STORAGE_look_for_named_pps(hf,stde.pps_prev,name); + if (ret!=-1) + return ret; + } + if (stde.pps_next != -1) { + ret=STORAGE_look_for_named_pps(hf,stde.pps_next,name); + if (ret!=-1) + return ret; + } + return -1; +} + +/****************************************************************************** + * STORAGE_dump_pps_entry [Internal] + * + * FIXME + * Function is unused + */ +void +STORAGE_dump_pps_entry(struct storage_pps_entry *stde) { + char name[33]; + + WideCharToMultiByte( CP_ACP, 0, stde->pps_rawname, -1, name, sizeof(name), NULL, NULL); + if (!stde->pps_sizeofname) + return; + DPRINTF("name: %s\n",name); + DPRINTF("type: %d\n",stde->pps_type); + DPRINTF("prev pps: %ld\n",stde->pps_prev); + DPRINTF("next pps: %ld\n",stde->pps_next); + DPRINTF("dir pps: %ld\n",stde->pps_dir); + DPRINTF("guid: %s\n",debugstr_guid(&(stde->pps_guid))); + if (stde->pps_type !=2) { + time_t t; + DWORD dw; + RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft1),&dw); + t = dw; + DPRINTF("ts1: %s\n",ctime(&t)); + RtlTimeToSecondsSince1970((LARGE_INTEGER *)&(stde->pps_ft2),&dw); + t = dw; + DPRINTF("ts2: %s\n",ctime(&t)); + } + DPRINTF("startblock: %ld\n",stde->pps_sb); + DPRINTF("size: %ld\n",stde->pps_size); +} + +/****************************************************************************** + * STORAGE_init_storage [INTERNAL] + */ +static BOOL +STORAGE_init_storage(HANDLE hf) { + BYTE block[BIGSIZE]; + LPDWORD bbs; + struct storage_header *sth; + struct storage_pps_entry *stde; + DWORD result; + + SetFilePointer( hf, 0, NULL, SEEK_SET ); + /* block -1 is the storage header */ + sth = (struct storage_header*)block; + memcpy(sth->magic,STORAGE_magic,8); + memset(sth->unknown1,0,sizeof(sth->unknown1)); + memset(sth->unknown2,0,sizeof(sth->unknown2)); + memset(sth->unknown3,0,sizeof(sth->unknown3)); + sth->num_of_bbd_blocks = 1; + sth->root_startblock = 1; + sth->sbd_startblock = 0xffffffff; + memset(sth->bbd_list,0xff,sizeof(sth->bbd_list)); + sth->bbd_list[0] = 0; + if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE; + /* block 0 is the big block directory */ + bbs=(LPDWORD)block; + memset(block,0xff,sizeof(block)); /* mark all blocks as free */ + bbs[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for this block */ + bbs[1]=STORAGE_CHAINENTRY_ENDOFCHAIN; /* for directory entry */ + if (!WriteFile( hf, block, BIGSIZE, &result, NULL ) || result != BIGSIZE) return FALSE; + /* block 1 is the root directory entry */ + memset(block,0x00,sizeof(block)); + stde = (struct storage_pps_entry*)block; + MultiByteToWideChar( CP_ACP, 0, "RootEntry", -1, stde->pps_rawname, + sizeof(stde->pps_rawname)/sizeof(WCHAR)); + stde->pps_sizeofname = (strlenW(stde->pps_rawname)+1) * sizeof(WCHAR); + stde->pps_type = 5; + stde->pps_dir = -1; + stde->pps_next = -1; + stde->pps_prev = -1; + stde->pps_sb = 0xffffffff; + stde->pps_size = 0; + return (WriteFile( hf, block, BIGSIZE, &result, NULL ) && result == BIGSIZE); +} + +/****************************************************************************** + * STORAGE_set_big_chain [Internal] + */ +static BOOL +STORAGE_set_big_chain(HANDLE hf,int blocknr,INT type) { + BYTE block[BIGSIZE]; + LPINT bbd = (LPINT)block; + int nextblocknr,bigblocknr; + struct storage_header sth; + BOOL ret; + + READ_HEADER; + assert(blocknr!=type); + while (blocknr>=0) { + bigblocknr = sth.bbd_list[blocknr/128]; + assert(bigblocknr>=0); + ret = STORAGE_get_big_block(hf,bigblocknr,block); + assert(ret); + + nextblocknr = bbd[blocknr&(128-1)]; + bbd[blocknr&(128-1)] = type; + if (type>=0) + return TRUE; + ret = STORAGE_put_big_block(hf,bigblocknr,block); + assert(ret); + type = STORAGE_CHAINENTRY_FREE; + blocknr = nextblocknr; + } + return TRUE; +} + +/****************************************************************************** + * STORAGE_set_small_chain [Internal] + */ +static BOOL +STORAGE_set_small_chain(HANDLE hf,int blocknr,INT type) { + BYTE block[BIGSIZE]; + LPINT sbd = (LPINT)block; + int lastblocknr,nextsmallblocknr,bigblocknr; + struct storage_header sth; + BOOL ret; + + READ_HEADER; + + assert(blocknr!=type); + lastblocknr=-129;bigblocknr=-2; + while (blocknr>=0) { + /* cache block ... */ + if (lastblocknr/128!=blocknr/128) { + bigblocknr = STORAGE_get_nth_next_big_blocknr(hf,sth.sbd_startblock,blocknr/128); + assert(bigblocknr>=0); + ret = STORAGE_get_big_block(hf,bigblocknr,block); + assert(ret); + } + lastblocknr = blocknr; + nextsmallblocknr = sbd[blocknr&(128-1)]; + sbd[blocknr&(128-1)] = type; + ret = STORAGE_put_big_block(hf,bigblocknr,block); + assert(ret); + if (type>=0) + return TRUE; + type = STORAGE_CHAINENTRY_FREE; + blocknr = nextsmallblocknr; + } + return TRUE; +} + +/****************************************************************************** + * STORAGE_get_free_big_blocknr [Internal] + */ +static int +STORAGE_get_free_big_blocknr(HANDLE hf) { + BYTE block[BIGSIZE]; + LPINT sbd = (LPINT)block; + int lastbigblocknr,i,bigblocknr; + unsigned int curblock; + struct storage_header sth; + BOOL ret; + + READ_HEADER; + curblock = 0; + lastbigblocknr = -1; + bigblocknr = sth.bbd_list[curblock]; + while (curblock<sth.num_of_bbd_blocks) { + assert(bigblocknr>=0); + ret = STORAGE_get_big_block(hf,bigblocknr,block); + assert(ret); + for (i=0;i<128;i++) + if (sbd[i]==STORAGE_CHAINENTRY_FREE) { + sbd[i] = STORAGE_CHAINENTRY_ENDOFCHAIN; + ret = STORAGE_put_big_block(hf,bigblocknr,block); + assert(ret); + memset(block,0x42,sizeof(block)); + ret = STORAGE_put_big_block(hf,i+curblock*128,block); + assert(ret); + return i+curblock*128; + } + lastbigblocknr = bigblocknr; + bigblocknr = sth.bbd_list[++curblock]; + } + bigblocknr = curblock*128; + /* since we have marked all blocks from 0 up to curblock*128-1 + * the next free one is curblock*128, where we happily put our + * next large block depot. + */ + memset(block,0xff,sizeof(block)); + /* mark the block allocated and returned by this function */ + sbd[1] = STORAGE_CHAINENTRY_ENDOFCHAIN; + ret = STORAGE_put_big_block(hf,bigblocknr,block); + assert(ret); + + /* if we had a bbd block already (mostlikely) we need + * to link the new one into the chain + */ + if (lastbigblocknr!=-1) { + ret = STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr); + assert(ret); + } + sth.bbd_list[curblock]=bigblocknr; + sth.num_of_bbd_blocks++; + assert(sth.num_of_bbd_blocks==curblock+1); + ret = STORAGE_put_big_block(hf,-1,(LPBYTE)&sth); + assert(ret); + + /* Set the end of the chain for the bigblockdepots */ + ret = STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN); + assert(ret); + /* add 1, for the first entry is used for the additional big block + * depot. (means we already used bigblocknr) */ + memset(block,0x42,sizeof(block)); + /* allocate this block (filled with 0x42) */ + ret = STORAGE_put_big_block(hf,bigblocknr+1,block); + assert(ret); + return bigblocknr+1; +} + + +/****************************************************************************** + * STORAGE_get_free_small_blocknr [Internal] + */ +static int +STORAGE_get_free_small_blocknr(HANDLE hf) { + BYTE block[BIGSIZE]; + LPINT sbd = (LPINT)block; + int lastbigblocknr,newblocknr,i,curblock,bigblocknr; + struct storage_pps_entry root; + struct storage_header sth; + + READ_HEADER; + bigblocknr = sth.sbd_startblock; + curblock = 0; + lastbigblocknr = -1; + newblocknr = -1; + while (bigblocknr>=0) { + if (!STORAGE_get_big_block(hf,bigblocknr,block)) + return -1; + for (i=0;i<128;i++) + if (sbd[i]==STORAGE_CHAINENTRY_FREE) { + sbd[i]=STORAGE_CHAINENTRY_ENDOFCHAIN; + newblocknr = i+curblock*128; + break; + } + if (i!=128) + break; + lastbigblocknr = bigblocknr; + bigblocknr = STORAGE_get_next_big_blocknr(hf,bigblocknr); + curblock++; + } + if (newblocknr==-1) { + bigblocknr = STORAGE_get_free_big_blocknr(hf); + if (bigblocknr<0) + return -1; + READ_HEADER; + memset(block,0xff,sizeof(block)); + sbd[0]=STORAGE_CHAINENTRY_ENDOFCHAIN; + if (!STORAGE_put_big_block(hf,bigblocknr,block)) + return -1; + if (lastbigblocknr==-1) { + sth.sbd_startblock = bigblocknr; + if (!STORAGE_put_big_block(hf,-1,(LPBYTE)&sth)) /* need to write it */ + return -1; + } else { + if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr)) + return -1; + } + if (!STORAGE_set_big_chain(hf,bigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN)) + return -1; + newblocknr = curblock*128; + } + /* allocate enough big blocks for storing the allocated small block */ + if (!STORAGE_get_root_pps_entry(hf,&root)) + return -1; + if (root.pps_sb==-1) + lastbigblocknr = -1; + else + lastbigblocknr = STORAGE_get_nth_next_big_blocknr(hf,root.pps_sb,(root.pps_size-1)/BIGSIZE); + while (root.pps_size < (newblocknr*SMALLSIZE+SMALLSIZE-1)) { + /* we need to allocate more stuff */ + bigblocknr = STORAGE_get_free_big_blocknr(hf); + if (bigblocknr<0) + return -1; + READ_HEADER; + if (root.pps_sb==-1) { + root.pps_sb = bigblocknr; + root.pps_size += BIGSIZE; + } else { + if (!STORAGE_set_big_chain(hf,lastbigblocknr,bigblocknr)) + return -1; + root.pps_size += BIGSIZE; + } + lastbigblocknr = bigblocknr; + } + if (!STORAGE_set_big_chain(hf,lastbigblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN)) + return -1; + if (!STORAGE_put_pps_entry(hf,0,&root)) + return -1; + return newblocknr; +} + +/****************************************************************************** + * STORAGE_get_free_pps_entry [Internal] + */ +static int +STORAGE_get_free_pps_entry(HANDLE hf) { + int blocknr, i, curblock, lastblocknr=-1; + BYTE block[BIGSIZE]; + struct storage_pps_entry *stde = (struct storage_pps_entry*)block; + struct storage_header sth; + + READ_HEADER; + blocknr = sth.root_startblock; + assert(blocknr>=0); + curblock=0; + while (blocknr>=0) { + if (!STORAGE_get_big_block(hf,blocknr,block)) + return -1; + for (i=0;i<4;i++) + if (stde[i].pps_sizeofname==0) /* free */ + return curblock*4+i; + lastblocknr = blocknr; + blocknr = STORAGE_get_next_big_blocknr(hf,blocknr); + curblock++; + } + assert(blocknr==STORAGE_CHAINENTRY_ENDOFCHAIN); + blocknr = STORAGE_get_free_big_blocknr(hf); + /* sth invalidated */ + if (blocknr<0) + return -1; + + if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr)) + return -1; + if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN)) + return -1; + memset(block,0,sizeof(block)); + STORAGE_put_big_block(hf,blocknr,block); + return curblock*4; +} + +/* --- IStream16 implementation */ + +typedef struct +{ + /* IUnknown fields */ + IStream16Vtbl *lpVtbl; + DWORD ref; + /* IStream16 fields */ + SEGPTR thisptr; /* pointer to this struct as segmented */ + struct storage_pps_entry stde; + int ppsent; + HANDLE hf; + ULARGE_INTEGER offset; +} IStream16Impl; + +/****************************************************************************** + * IStream16_QueryInterface [STORAGE.518] + */ +HRESULT WINAPI IStream16_fnQueryInterface( + IStream16* iface,REFIID refiid,LPVOID *obj +) { + IStream16Impl *This = (IStream16Impl *)iface; + TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj); + if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) { + *obj = This; + return 0; + } + return OLE_E_ENUM_NOMORE; + +} + +/****************************************************************************** + * IStream16_AddRef [STORAGE.519] + */ +ULONG WINAPI IStream16_fnAddRef(IStream16* iface) { + IStream16Impl *This = (IStream16Impl *)iface; + return InterlockedIncrement(&This->ref); +} + +/****************************************************************************** + * IStream16_Release [STORAGE.520] + */ +ULONG WINAPI IStream16_fnRelease(IStream16* iface) { + IStream16Impl *This = (IStream16Impl *)iface; + ULONG ref; + FlushFileBuffers(This->hf); + ref = InterlockedDecrement(&This->ref); + if (!ref) { + CloseHandle(This->hf); + UnMapLS( This->thisptr ); + HeapFree( GetProcessHeap(), 0, This ); + } + return ref; +} + +/****************************************************************************** + * IStream16_Seek [STORAGE.523] + * + * FIXME + * Does not handle 64 bits + */ +HRESULT WINAPI IStream16_fnSeek( + IStream16* iface,LARGE_INTEGER offset,DWORD whence,ULARGE_INTEGER *newpos +) { + IStream16Impl *This = (IStream16Impl *)iface; + TRACE_(relay)("(%p)->([%ld.%ld],%ld,%p)\n",This,offset.u.HighPart,offset.u.LowPart,whence,newpos); + + switch (whence) { + /* unix SEEK_xx should be the same as win95 ones */ + case SEEK_SET: + /* offset must be ==0 (<0 is invalid, and >0 cannot be handled + * right now. + */ + assert(offset.u.HighPart==0); + This->offset.u.HighPart = offset.u.HighPart; + This->offset.u.LowPart = offset.u.LowPart; + break; + case SEEK_CUR: + if (offset.u.HighPart < 0) { + /* FIXME: is this negation correct ? */ + offset.u.HighPart = -offset.u.HighPart; + offset.u.LowPart = (0xffffffff ^ offset.u.LowPart)+1; + + assert(offset.u.HighPart==0); + assert(This->offset.u.LowPart >= offset.u.LowPart); + This->offset.u.LowPart -= offset.u.LowPart; + } else { + assert(offset.u.HighPart==0); + This->offset.u.LowPart+= offset.u.LowPart; + } + break; + case SEEK_END: + assert(offset.u.HighPart==0); + This->offset.u.LowPart = This->stde.pps_size-offset.u.LowPart; + break; + } + if (This->offset.u.LowPart>This->stde.pps_size) + This->offset.u.LowPart=This->stde.pps_size; + if (newpos) *newpos = This->offset; + return S_OK; +} + +/****************************************************************************** + * IStream16_Read [STORAGE.521] + */ +HRESULT WINAPI IStream16_fnRead( + IStream16* iface,void *pv,ULONG cb,ULONG *pcbRead +) { + IStream16Impl *This = (IStream16Impl *)iface; + BYTE block[BIGSIZE]; + ULONG *bytesread=pcbRead,xxread; + int blocknr; + LPBYTE pbv = pv; + + TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbRead); + if (!pcbRead) bytesread=&xxread; + *bytesread = 0; + + if (cb>This->stde.pps_size-This->offset.u.LowPart) + cb=This->stde.pps_size-This->offset.u.LowPart; + if (This->stde.pps_size < 0x1000) { + /* use small block reader */ + blocknr = STORAGE_get_nth_next_small_blocknr(This->hf,This->stde.pps_sb,This->offset.u.LowPart/SMALLSIZE); + while (cb) { + unsigned int cc; + + if (!STORAGE_get_small_block(This->hf,blocknr,block)) { + WARN("small block read failed!!!\n"); + return E_FAIL; + } + cc = cb; + if (cc>SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1))) + cc=SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1)); + memcpy(pbv,block+(This->offset.u.LowPart&(SMALLSIZE-1)),cc); + This->offset.u.LowPart+=cc; + pbv+=cc; + *bytesread+=cc; + cb-=cc; + blocknr = STORAGE_get_next_small_blocknr(This->hf,blocknr); + } + } else { + /* use big block reader */ + blocknr = STORAGE_get_nth_next_big_blocknr(This->hf,This->stde.pps_sb,This->offset.u.LowPart/BIGSIZE); + while (cb) { + unsigned int cc; + + if (!STORAGE_get_big_block(This->hf,blocknr,block)) { + WARN("big block read failed!!!\n"); + return E_FAIL; + } + cc = cb; + if (cc>BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1))) + cc=BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1)); + memcpy(pbv,block+(This->offset.u.LowPart&(BIGSIZE-1)),cc); + This->offset.u.LowPart+=cc; + pbv+=cc; + *bytesread+=cc; + cb-=cc; + blocknr=STORAGE_get_next_big_blocknr(This->hf,blocknr); + } + } + return S_OK; +} + +/****************************************************************************** + * IStream16_Write [STORAGE.522] + */ +HRESULT WINAPI IStream16_fnWrite( + IStream16* iface,const void *pv,ULONG cb,ULONG *pcbWrite +) { + IStream16Impl *This = (IStream16Impl *)iface; + BYTE block[BIGSIZE]; + ULONG *byteswritten=pcbWrite,xxwritten; + int oldsize,newsize,i,curoffset=0,lastblocknr,blocknr,cc; + HANDLE hf = This->hf; + const BYTE* pbv = (const BYTE*)pv; + + if (!pcbWrite) byteswritten=&xxwritten; + *byteswritten = 0; + + TRACE_(relay)("(%p)->(%p,%ld,%p)\n",This,pv,cb,pcbWrite); + /* do we need to junk some blocks? */ + newsize = This->offset.u.LowPart+cb; + oldsize = This->stde.pps_size; + if (newsize < oldsize) { + if (oldsize < 0x1000) { + /* only small blocks */ + blocknr=STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,newsize/SMALLSIZE); + + assert(blocknr>=0); + + /* will set the rest of the chain to 'free' */ + if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN)) + return E_FAIL; + } else { + if (newsize >= 0x1000) { + blocknr=STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,newsize/BIGSIZE); + assert(blocknr>=0); + + /* will set the rest of the chain to 'free' */ + if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN)) + return E_FAIL; + } else { + /* Migrate large blocks to small blocks + * (we just migrate newsize bytes) + */ + LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,newsize+BIGSIZE); + HRESULT r = E_FAIL; + + cc = newsize; + blocknr = This->stde.pps_sb; + curdata = data; + while (cc>0) { + if (!STORAGE_get_big_block(hf,blocknr,curdata)) { + HeapFree(GetProcessHeap(),0,data); + return E_FAIL; + } + curdata += BIGSIZE; + cc -= BIGSIZE; + blocknr = STORAGE_get_next_big_blocknr(hf,blocknr); + } + /* frees complete chain for this stream */ + if (!STORAGE_set_big_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE)) + goto err; + curdata = data; + blocknr = This->stde.pps_sb = STORAGE_get_free_small_blocknr(hf); + if (blocknr<0) + goto err; + cc = newsize; + while (cc>0) { + if (!STORAGE_put_small_block(hf,blocknr,curdata)) + goto err; + cc -= SMALLSIZE; + if (cc<=0) { + if (!STORAGE_set_small_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN)) + goto err; + break; + } else { + int newblocknr = STORAGE_get_free_small_blocknr(hf); + if (newblocknr<0) + goto err; + if (!STORAGE_set_small_chain(hf,blocknr,newblocknr)) + goto err; + blocknr = newblocknr; + } + curdata += SMALLSIZE; + } + r = S_OK; + err: + HeapFree(GetProcessHeap(),0,data); + if(r != S_OK) + return r; + } + } + This->stde.pps_size = newsize; + } + + if (newsize > oldsize) { + if (oldsize >= 0x1000) { + /* should return the block right before the 'endofchain' */ + blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/BIGSIZE); + assert(blocknr>=0); + lastblocknr = blocknr; + for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) { + blocknr = STORAGE_get_free_big_blocknr(hf); + if (blocknr<0) + return E_FAIL; + if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr)) + return E_FAIL; + lastblocknr = blocknr; + } + if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN)) + return E_FAIL; + } else { + if (newsize < 0x1000) { + /* find startblock */ + if (!oldsize) + This->stde.pps_sb = blocknr = STORAGE_get_free_small_blocknr(hf); + else + blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->stde.pps_size/SMALLSIZE); + if (blocknr<0) + return E_FAIL; + + /* allocate required new small blocks */ + lastblocknr = blocknr; + for (i=oldsize/SMALLSIZE;i<newsize/SMALLSIZE;i++) { + blocknr = STORAGE_get_free_small_blocknr(hf); + if (blocknr<0) + return E_FAIL; + if (!STORAGE_set_small_chain(hf,lastblocknr,blocknr)) + return E_FAIL; + lastblocknr = blocknr; + } + /* and terminate the chain */ + if (!STORAGE_set_small_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN)) + return E_FAIL; + } else { + if (!oldsize) { + /* no single block allocated yet */ + blocknr=STORAGE_get_free_big_blocknr(hf); + if (blocknr<0) + return E_FAIL; + This->stde.pps_sb = blocknr; + } else { + /* Migrate small blocks to big blocks */ + LPBYTE curdata,data = HeapAlloc(GetProcessHeap(),0,oldsize+BIGSIZE); + HRESULT r = E_FAIL; + + cc = oldsize; + blocknr = This->stde.pps_sb; + curdata = data; + /* slurp in */ + while (cc>0) { + if (!STORAGE_get_small_block(hf,blocknr,curdata)) + goto err2; + curdata += SMALLSIZE; + cc -= SMALLSIZE; + blocknr = STORAGE_get_next_small_blocknr(hf,blocknr); + } + /* free small block chain */ + if (!STORAGE_set_small_chain(hf,This->stde.pps_sb,STORAGE_CHAINENTRY_FREE)) + goto err2; + curdata = data; + blocknr = This->stde.pps_sb = STORAGE_get_free_big_blocknr(hf); + if (blocknr<0) + goto err2; + /* put the data into the big blocks */ + cc = This->stde.pps_size; + while (cc>0) { + if (!STORAGE_put_big_block(hf,blocknr,curdata)) + goto err2; + cc -= BIGSIZE; + if (cc<=0) { + if (!STORAGE_set_big_chain(hf,blocknr,STORAGE_CHAINENTRY_ENDOFCHAIN)) + goto err2; + break; + } else { + int newblocknr = STORAGE_get_free_big_blocknr(hf); + if (newblocknr<0) + goto err2; + if (!STORAGE_set_big_chain(hf,blocknr,newblocknr)) + goto err2; + blocknr = newblocknr; + } + curdata += BIGSIZE; + } + r = S_OK; + err2: + HeapFree(GetProcessHeap(),0,data); + if(r != S_OK) + return r; + } + /* generate big blocks to fit the new data */ + lastblocknr = blocknr; + for (i=oldsize/BIGSIZE;i<newsize/BIGSIZE;i++) { + blocknr = STORAGE_get_free_big_blocknr(hf); + if (blocknr<0) + return E_FAIL; + if (!STORAGE_set_big_chain(hf,lastblocknr,blocknr)) + return E_FAIL; + lastblocknr = blocknr; + } + /* terminate chain */ + if (!STORAGE_set_big_chain(hf,lastblocknr,STORAGE_CHAINENTRY_ENDOFCHAIN)) + return E_FAIL; + } + } + This->stde.pps_size = newsize; + } + + /* There are just some cases where we didn't modify it, we write it out + * everytime + */ + if (!STORAGE_put_pps_entry(hf,This->ppsent,&(This->stde))) + return E_FAIL; + + /* finally the write pass */ + if (This->stde.pps_size < 0x1000) { + blocknr = STORAGE_get_nth_next_small_blocknr(hf,This->stde.pps_sb,This->offset.u.LowPart/SMALLSIZE); + assert(blocknr>=0); + while (cb>0) { + /* we ensured that it is allocated above */ + assert(blocknr>=0); + /* Read old block everytime, since we can have + * overlapping data at START and END of the write + */ + if (!STORAGE_get_small_block(hf,blocknr,block)) + return E_FAIL; + + cc = SMALLSIZE-(This->offset.u.LowPart&(SMALLSIZE-1)); + if (cc>cb) + cc=cb; + memcpy( ((LPBYTE)block)+(This->offset.u.LowPart&(SMALLSIZE-1)), + pbv+curoffset, + cc + ); + if (!STORAGE_put_small_block(hf,blocknr,block)) + return E_FAIL; + cb -= cc; + curoffset += cc; + pbv += cc; + This->offset.u.LowPart += cc; + *byteswritten += cc; + blocknr = STORAGE_get_next_small_blocknr(hf,blocknr); + } + } else { + blocknr = STORAGE_get_nth_next_big_blocknr(hf,This->stde.pps_sb,This->offset.u.LowPart/BIGSIZE); + assert(blocknr>=0); + while (cb>0) { + /* we ensured that it is allocated above, so it better is */ + assert(blocknr>=0); + /* read old block everytime, since we can have + * overlapping data at START and END of the write + */ + if (!STORAGE_get_big_block(hf,blocknr,block)) + return E_FAIL; + + cc = BIGSIZE-(This->offset.u.LowPart&(BIGSIZE-1)); + if (cc>cb) + cc=cb; + memcpy( ((LPBYTE)block)+(This->offset.u.LowPart&(BIGSIZE-1)), + pbv+curoffset, + cc + ); + if (!STORAGE_put_big_block(hf,blocknr,block)) + return E_FAIL; + cb -= cc; + curoffset += cc; + pbv += cc; + This->offset.u.LowPart += cc; + *byteswritten += cc; + blocknr = STORAGE_get_next_big_blocknr(hf,blocknr); + } + } + return S_OK; +} + +/****************************************************************************** + * _create_istream16 [Internal] + */ +static void _create_istream16(LPSTREAM16 *str) { + IStream16Impl* lpst; + + if (!strvt16.QueryInterface) { + HMODULE16 wp = GetModuleHandle16("STORAGE"); + if (wp>=32) { + /* FIXME: what is This GetProcAddress16. Should the name be IStream16_QueryInterface of IStream16_fnQueryInterface */ +#define VTENT(xfn) strvt16.xfn = (void*)GetProcAddress16(wp,"IStream16_"#xfn);assert(strvt16.xfn) + VTENT(QueryInterface); + VTENT(AddRef); + VTENT(Release); + VTENT(Read); + VTENT(Write); + VTENT(Seek); + VTENT(SetSize); + VTENT(CopyTo); + VTENT(Commit); + VTENT(Revert); + VTENT(LockRegion); + VTENT(UnlockRegion); + VTENT(Stat); + VTENT(Clone); +#undef VTENT + segstrvt16 = (IStream16Vtbl*)MapLS( &strvt16 ); + } else { +#define VTENT(xfn) strvt16.xfn = IStream16_fn##xfn; + VTENT(QueryInterface); + VTENT(AddRef); + VTENT(Release); + VTENT(Read); + VTENT(Write); + VTENT(Seek); + /* + VTENT(CopyTo); + VTENT(Commit); + VTENT(SetSize); + VTENT(Revert); + VTENT(LockRegion); + VTENT(UnlockRegion); + VTENT(Stat); + VTENT(Clone); + */ +#undef VTENT + segstrvt16 = &strvt16; + } + } + lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) ); + lpst->lpVtbl = segstrvt16; + lpst->ref = 1; + lpst->thisptr = MapLS( lpst ); + *str = (void*)lpst->thisptr; +} + + +/* --- IStream32 implementation */ + +typedef struct +{ + /* IUnknown fields */ + IStreamVtbl *lpVtbl; + DWORD ref; + /* IStream32 fields */ + struct storage_pps_entry stde; + int ppsent; + HANDLE hf; + ULARGE_INTEGER offset; +} IStream32Impl; + +/***************************************************************************** + * IStream32_QueryInterface [VTABLE] + */ +HRESULT WINAPI IStream_fnQueryInterface( + IStream* iface,REFIID refiid,LPVOID *obj +) { + IStream32Impl *This = (IStream32Impl *)iface; + + TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj); + if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) { + *obj = This; + return 0; + } + return OLE_E_ENUM_NOMORE; + +} + +/****************************************************************************** + * IStream32_AddRef [VTABLE] + */ +ULONG WINAPI IStream_fnAddRef(IStream* iface) { + IStream32Impl *This = (IStream32Impl *)iface; + return InterlockedIncrement(&This->ref); +} + +/****************************************************************************** + * IStream32_Release [VTABLE] + */ +ULONG WINAPI IStream_fnRelease(IStream* iface) { + IStream32Impl *This = (IStream32Impl *)iface; + ULONG ref; + FlushFileBuffers(This->hf); + ref = InterlockedDecrement(&This->ref); + if (!ref) { + CloseHandle(This->hf); + HeapFree( GetProcessHeap(), 0, This ); + } + return ref; +} + +/* --- IStorage16 implementation */ + +typedef struct +{ + /* IUnknown fields */ + IStorage16Vtbl *lpVtbl; + DWORD ref; + /* IStorage16 fields */ + SEGPTR thisptr; /* pointer to this struct as segmented */ + struct storage_pps_entry stde; + int ppsent; + HANDLE hf; +} IStorage16Impl; + +/****************************************************************************** + * IStorage16_QueryInterface [STORAGE.500] + */ +HRESULT WINAPI IStorage16_fnQueryInterface( + IStorage16* iface,REFIID refiid,LPVOID *obj +) { + IStorage16Impl *This = (IStorage16Impl *)iface; + + TRACE_(relay)("(%p)->(%s,%p)\n",This,debugstr_guid(refiid),obj); + + if (!memcmp(&IID_IUnknown,refiid,sizeof(IID_IUnknown))) { + *obj = This; + return 0; + } + return OLE_E_ENUM_NOMORE; +} + +/****************************************************************************** + * IStorage16_AddRef [STORAGE.501] + */ +ULONG WINAPI IStorage16_fnAddRef(IStorage16* iface) { + IStorage16Impl *This = (IStorage16Impl *)iface; + return InterlockedIncrement(&This->ref); +} + +/****************************************************************************** + * IStorage16_Release [STORAGE.502] + */ +ULONG WINAPI IStorage16_fnRelease(IStorage16* iface) { + IStorage16Impl *This = (IStorage16Impl *)iface; + ULONG ref; + ref = InterlockedDecrement(&This->ref); + if (!ref) + { + UnMapLS( This->thisptr ); + HeapFree( GetProcessHeap(), 0, This ); + } + return ref; +} + +/****************************************************************************** + * IStorage16_Stat [STORAGE.517] + */ +HRESULT WINAPI IStorage16_fnStat( + LPSTORAGE16 iface,STATSTG16 *pstatstg, DWORD grfStatFlag +) { + IStorage16Impl *This = (IStorage16Impl *)iface; + DWORD len = WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, NULL, 0, NULL, NULL ); + LPSTR nameA = HeapAlloc( GetProcessHeap(), 0, len ); + + TRACE("(%p)->(%p,0x%08lx)\n", + This,pstatstg,grfStatFlag + ); + WideCharToMultiByte( CP_ACP, 0, This->stde.pps_rawname, -1, nameA, len, NULL, NULL ); + pstatstg->pwcsName=(LPOLESTR16)MapLS( nameA ); + pstatstg->type = This->stde.pps_type; + pstatstg->cbSize.u.LowPart = This->stde.pps_size; + pstatstg->mtime = This->stde.pps_ft1; /* FIXME */ /* why? */ + pstatstg->atime = This->stde.pps_ft2; /* FIXME */ + pstatstg->ctime = This->stde.pps_ft2; /* FIXME */ + pstatstg->grfMode = 0; /* FIXME */ + pstatstg->grfLocksSupported = 0; /* FIXME */ + pstatstg->clsid = This->stde.pps_guid; + pstatstg->grfStateBits = 0; /* FIXME */ + pstatstg->reserved = 0; + return S_OK; +} + +/****************************************************************************** + * IStorage16_Commit [STORAGE.509] + */ +HRESULT WINAPI IStorage16_fnCommit( + LPSTORAGE16 iface,DWORD commitflags +) { + IStorage16Impl *This = (IStorage16Impl *)iface; + FIXME("(%p)->(0x%08lx),STUB!\n", + This,commitflags + ); + return S_OK; +} + +/****************************************************************************** + * IStorage16_CopyTo [STORAGE.507] + */ +HRESULT WINAPI IStorage16_fnCopyTo(LPSTORAGE16 iface,DWORD ciidExclude,const IID *rgiidExclude,SNB16 SNB16Exclude,IStorage16 *pstgDest) { + IStorage16Impl *This = (IStorage16Impl *)iface; + FIXME("IStorage16(%p)->(0x%08lx,%s,%p,%p),stub!\n", + This,ciidExclude,debugstr_guid(rgiidExclude),SNB16Exclude,pstgDest + ); + return S_OK; +} + + +/****************************************************************************** + * IStorage16_CreateStorage [STORAGE.505] + */ +HRESULT WINAPI IStorage16_fnCreateStorage( + LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD dwStgFormat,DWORD reserved2, IStorage16 **ppstg +) { + IStorage16Impl *This = (IStorage16Impl *)iface; + IStorage16Impl* lpstg; + int ppsent,x; + struct storage_pps_entry stde; + struct storage_header sth; + HANDLE hf=This->hf; + BOOL ret; + int nPPSEntries; + + READ_HEADER; + + TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n", + This,pwcsName,grfMode,dwStgFormat,reserved2,ppstg + ); + if (grfMode & STGM_TRANSACTED) + FIXME("We do not support transacted Compound Storage. Using direct mode.\n"); + _create_istorage16(ppstg); + lpstg = MapSL((SEGPTR)*ppstg); + lpstg->hf = This->hf; + + ppsent=STORAGE_get_free_pps_entry(lpstg->hf); + if (ppsent<0) + return E_FAIL; + stde=This->stde; + if (stde.pps_dir==-1) { + stde.pps_dir = ppsent; + x = This->ppsent; + } else { + FIXME(" use prev chain too ?\n"); + x=stde.pps_dir; + if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde)) + return E_FAIL; + while (stde.pps_next!=-1) { + x=stde.pps_next; + if (1!=STORAGE_get_pps_entry(lpstg->hf,x,&stde)) + return E_FAIL; + } + stde.pps_next = ppsent; + } + ret = STORAGE_put_pps_entry(lpstg->hf,x,&stde); + assert(ret); + nPPSEntries = STORAGE_get_pps_entry(lpstg->hf,ppsent,&(lpstg->stde)); + assert(nPPSEntries == 1); + MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstg->stde.pps_rawname, + sizeof(lpstg->stde.pps_rawname)/sizeof(WCHAR)); + lpstg->stde.pps_sizeofname = (strlenW(lpstg->stde.pps_rawname)+1)*sizeof(WCHAR); + lpstg->stde.pps_next = -1; + lpstg->stde.pps_prev = -1; + lpstg->stde.pps_dir = -1; + lpstg->stde.pps_sb = -1; + lpstg->stde.pps_size = 0; + lpstg->stde.pps_type = 1; + lpstg->ppsent = ppsent; + /* FIXME: timestamps? */ + if (!STORAGE_put_pps_entry(lpstg->hf,ppsent,&(lpstg->stde))) + return E_FAIL; + return S_OK; +} + +/****************************************************************************** + * IStorage16_CreateStream [STORAGE.503] + */ +HRESULT WINAPI IStorage16_fnCreateStream( + LPSTORAGE16 iface,LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved1,DWORD reserved2, IStream16 **ppstm +) { + IStorage16Impl *This = (IStorage16Impl *)iface; + IStream16Impl* lpstr; + int ppsent,x; + struct storage_pps_entry stde; + BOOL ret; + int nPPSEntries; + + TRACE("(%p)->(%s,0x%08lx,0x%08lx,0x%08lx,%p)\n", + This,pwcsName,grfMode,reserved1,reserved2,ppstm + ); + if (grfMode & STGM_TRANSACTED) + FIXME("We do not support transacted Compound Storage. Using direct mode.\n"); + _create_istream16(ppstm); + lpstr = MapSL((SEGPTR)*ppstm); + DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(), + &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS ); + lpstr->offset.u.LowPart = 0; + lpstr->offset.u.HighPart = 0; + + ppsent=STORAGE_get_free_pps_entry(lpstr->hf); + if (ppsent<0) + return E_FAIL; + stde=This->stde; + if (stde.pps_next==-1) + x=This->ppsent; + else + while (stde.pps_next!=-1) { + x=stde.pps_next; + if (1!=STORAGE_get_pps_entry(lpstr->hf,x,&stde)) + return E_FAIL; + } + stde.pps_next = ppsent; + ret = STORAGE_put_pps_entry(lpstr->hf,x,&stde); + assert(ret); + nPPSEntries = STORAGE_get_pps_entry(lpstr->hf,ppsent,&(lpstr->stde)); + assert(nPPSEntries == 1); + MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, lpstr->stde.pps_rawname, + sizeof(lpstr->stde.pps_rawname)/sizeof(WCHAR)); + lpstr->stde.pps_sizeofname = (strlenW(lpstr->stde.pps_rawname)+1) * sizeof(WCHAR); + lpstr->stde.pps_next = -1; + lpstr->stde.pps_prev = -1; + lpstr->stde.pps_dir = -1; + lpstr->stde.pps_sb = -1; + lpstr->stde.pps_size = 0; + lpstr->stde.pps_type = 2; + lpstr->ppsent = ppsent; + /* FIXME: timestamps? */ + if (!STORAGE_put_pps_entry(lpstr->hf,ppsent,&(lpstr->stde))) + return E_FAIL; + return S_OK; +} + +/****************************************************************************** + * IStorage16_OpenStorage [STORAGE.506] + */ +HRESULT WINAPI IStorage16_fnOpenStorage( + LPSTORAGE16 iface,LPCOLESTR16 pwcsName, IStorage16 *pstgPrio, DWORD grfMode, SNB16 snbExclude, DWORD reserved, IStorage16 **ppstg +) { + IStorage16Impl *This = (IStorage16Impl *)iface; + IStream16Impl* lpstg; + WCHAR name[33]; + int newpps; + + TRACE_(relay)("(%p)->(%s,%p,0x%08lx,%p,0x%08lx,%p)\n", + This,pwcsName,pstgPrio,grfMode,snbExclude,reserved,ppstg + ); + if (grfMode & STGM_TRANSACTED) + FIXME("We do not support transacted Compound Storage. Using direct mode.\n"); + _create_istorage16(ppstg); + lpstg = MapSL((SEGPTR)*ppstg); + DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(), + &lpstg->hf, 0, TRUE, DUPLICATE_SAME_ACCESS ); + MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR)); + newpps = STORAGE_look_for_named_pps(lpstg->hf,This->stde.pps_dir,name); + if (newpps==-1) { + IStream16_fnRelease((IStream16*)lpstg); + return E_FAIL; + } + + if (1!=STORAGE_get_pps_entry(lpstg->hf,newpps,&(lpstg->stde))) { + IStream16_fnRelease((IStream16*)lpstg); + return E_FAIL; + } + lpstg->ppsent = newpps; + return S_OK; +} + +/****************************************************************************** + * IStorage16_OpenStream [STORAGE.504] + */ +HRESULT WINAPI IStorage16_fnOpenStream( + LPSTORAGE16 iface,LPCOLESTR16 pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream16 **ppstm +) { + IStorage16Impl *This = (IStorage16Impl *)iface; + IStream16Impl* lpstr; + WCHAR name[33]; + int newpps; + + TRACE_(relay)("(%p)->(%s,%p,0x%08lx,0x%08lx,%p)\n", + This,pwcsName,reserved1,grfMode,reserved2,ppstm + ); + if (grfMode & STGM_TRANSACTED) + FIXME("We do not support transacted Compound Storage. Using direct mode.\n"); + _create_istream16(ppstm); + lpstr = MapSL((SEGPTR)*ppstm); + DuplicateHandle( GetCurrentProcess(), This->hf, GetCurrentProcess(), + &lpstr->hf, 0, TRUE, DUPLICATE_SAME_ACCESS ); + MultiByteToWideChar( CP_ACP, 0, pwcsName, -1, name, sizeof(name)/sizeof(WCHAR)); + newpps = STORAGE_look_for_named_pps(lpstr->hf,This->stde.pps_dir,name); + if (newpps==-1) { + IStream16_fnRelease((IStream16*)lpstr); + return E_FAIL; + } + + if (1!=STORAGE_get_pps_entry(lpstr->hf,newpps,&(lpstr->stde))) { + IStream16_fnRelease((IStream16*)lpstr); + return E_FAIL; + } + lpstr->offset.u.LowPart = 0; + lpstr->offset.u.HighPart = 0; + lpstr->ppsent = newpps; + return S_OK; +} + +/****************************************************************************** + * _create_istorage16 [INTERNAL] + */ +static void _create_istorage16(LPSTORAGE16 *stg) { + IStorage16Impl* lpst; + + if (!stvt16.QueryInterface) { + HMODULE16 wp = GetModuleHandle16("STORAGE"); + if (wp>=32) { +#define VTENT(xfn) stvt16.xfn = (void*)GetProcAddress16(wp,"IStorage16_"#xfn); + VTENT(QueryInterface) + VTENT(AddRef) + VTENT(Release) + VTENT(CreateStream) + VTENT(OpenStream) + VTENT(CreateStorage) + VTENT(OpenStorage) + VTENT(CopyTo) + VTENT(MoveElementTo) + VTENT(Commit) + VTENT(Revert) + VTENT(EnumElements) + VTENT(DestroyElement) + VTENT(RenameElement) + VTENT(SetElementTimes) + VTENT(SetClass) + VTENT(SetStateBits) + VTENT(Stat) +#undef VTENT + segstvt16 = (IStorage16Vtbl*)MapLS( &stvt16 ); + } else { +#define VTENT(xfn) stvt16.xfn = IStorage16_fn##xfn; + VTENT(QueryInterface) + VTENT(AddRef) + VTENT(Release) + VTENT(CreateStream) + VTENT(OpenStream) + VTENT(CreateStorage) + VTENT(OpenStorage) + VTENT(CopyTo) + VTENT(Commit) + /* not (yet) implemented ... + VTENT(MoveElementTo) + VTENT(Revert) + VTENT(EnumElements) + VTENT(DestroyElement) + VTENT(RenameElement) + VTENT(SetElementTimes) + VTENT(SetClass) + VTENT(SetStateBits) + VTENT(Stat) + */ +#undef VTENT + segstvt16 = &stvt16; + } + } + lpst = HeapAlloc( GetProcessHeap(), 0, sizeof(*lpst) ); + lpst->lpVtbl = segstvt16; + lpst->ref = 1; + lpst->thisptr = MapLS(lpst); + *stg = (void*)lpst->thisptr; +} + +/****************************************************************************** + * Storage API functions + */ + +/****************************************************************************** + * StgCreateDocFileA [STORAGE.1] + */ +HRESULT WINAPI StgCreateDocFile16( + LPCOLESTR16 pwcsName,DWORD grfMode,DWORD reserved,IStorage16 **ppstgOpen +) { + HANDLE hf; + int i,ret; + IStorage16Impl* lpstg; + struct storage_pps_entry stde; + + TRACE("(%s,0x%08lx,0x%08lx,%p)\n", + pwcsName,grfMode,reserved,ppstgOpen + ); + _create_istorage16(ppstgOpen); + hf = CreateFileA(pwcsName,GENERIC_READ|GENERIC_WRITE,0,NULL,CREATE_NEW,0,0); + if (hf==INVALID_HANDLE_VALUE) { + WARN("couldn't open file for storage:%ld\n",GetLastError()); + return E_FAIL; + } + lpstg = MapSL((SEGPTR)*ppstgOpen); + lpstg->hf = hf; + /* FIXME: check for existence before overwriting? */ + if (!STORAGE_init_storage(hf)) { + CloseHandle(hf); + return E_FAIL; + } + i=0;ret=0; + while (!ret) { /* neither 1 nor <0 */ + ret=STORAGE_get_pps_entry(hf,i,&stde); + if ((ret==1) && (stde.pps_type==5)) { + lpstg->stde = stde; + lpstg->ppsent = i; + break; + } + i++; + } + if (ret!=1) { + IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */ + return E_FAIL; + } + + return S_OK; +} + +/****************************************************************************** + * StgIsStorageFile [STORAGE.5] + */ +HRESULT WINAPI StgIsStorageFile16(LPCOLESTR16 fn) { + UNICODE_STRING strW; + HRESULT ret; + + RtlCreateUnicodeStringFromAsciiz(&strW, fn); + ret = StgIsStorageFile( strW.Buffer ); + RtlFreeUnicodeString( &strW ); + + return ret; +} + +/****************************************************************************** + * StgOpenStorage [STORAGE.3] + */ +HRESULT WINAPI StgOpenStorage16( + LPCOLESTR16 pwcsName,IStorage16 *pstgPriority,DWORD grfMode, + SNB16 snbExclude,DWORD reserved, IStorage16 **ppstgOpen +) { + HANDLE hf; + int ret,i; + IStorage16Impl* lpstg; + struct storage_pps_entry stde; + + TRACE("(%s,%p,0x%08lx,%p,%ld,%p)\n", + pwcsName,pstgPriority,grfMode,snbExclude,reserved,ppstgOpen + ); + _create_istorage16(ppstgOpen); + hf = CreateFileA(pwcsName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); + if (hf==INVALID_HANDLE_VALUE) { + WARN("Couldn't open file for storage\n"); + return E_FAIL; + } + lpstg = MapSL((SEGPTR)*ppstgOpen); + lpstg->hf = hf; + + i=0;ret=0; + while (!ret) { /* neither 1 nor <0 */ + ret=STORAGE_get_pps_entry(hf,i,&stde); + if ((ret==1) && (stde.pps_type==5)) { + lpstg->stde=stde; + break; + } + i++; + } + if (ret!=1) { + IStorage16_fnRelease((IStorage16*)lpstg); /* will remove it */ + return E_FAIL; + } + return S_OK; + +} + +/****************************************************************************** + * StgIsStorageILockBytes [STORAGE.6] + * + * Determines if the ILockBytes contains a storage object. + */ +HRESULT WINAPI StgIsStorageILockBytes16(SEGPTR plkbyt) +{ + DWORD args[6]; + HRESULT hres; + HANDLE16 hsig; + + args[0] = (DWORD)plkbyt; /* iface */ + args[1] = args[2] = 0; /* ULARGE_INTEGER offset */ + args[3] = (DWORD)K32WOWGlobalAllocLock16( 0, 8, &hsig ); /* sig */ + args[4] = 8; + args[5] = 0; + + if (!K32WOWCallback16Ex( + (DWORD)((ILockBytes16Vtbl*)MapSL( + (SEGPTR)((LPLOCKBYTES16)MapSL(plkbyt))->lpVtbl) + )->ReadAt, + WCB16_PASCAL, + 6*sizeof(DWORD), + (LPVOID)args, + (LPDWORD)&hres + )) { + ERR("CallTo16 ILockBytes16::ReadAt() failed, hres %lx\n",hres); + return hres; + } + if (memcmp(MapSL(args[3]), STORAGE_magic, sizeof(STORAGE_magic)) == 0) { + K32WOWGlobalUnlockFree16(args[3]); + return S_OK; + } + K32WOWGlobalUnlockFree16(args[3]); + return S_FALSE; +} + +/****************************************************************************** + * StgOpenStorageOnILockBytes [STORAGE.4] + */ +HRESULT WINAPI StgOpenStorageOnILockBytes16( + ILockBytes16 *plkbyt, + IStorage16 *pstgPriority, + DWORD grfMode, + SNB16 snbExclude, + DWORD reserved, + IStorage16 **ppstgOpen) +{ + IStorage16Impl* lpstg; + + if ((plkbyt == 0) || (ppstgOpen == 0)) + return STG_E_INVALIDPOINTER; + + *ppstgOpen = 0; + + _create_istorage16(ppstgOpen); + lpstg = MapSL((SEGPTR)*ppstgOpen); + + /* just teach it to use HANDLE instead of ilockbytes :/ */ + + return S_OK; +} diff --git a/reactos/lib/ole32/storage32.c b/reactos/lib/ole32/storage32.c index d88d6803c80..249c766e134 100644 --- a/reactos/lib/ole32/storage32.c +++ b/reactos/lib/ole32/storage32.c @@ -1,7657 +1,7657 @@ -/* - * Compound Storage (32 bit version) - * Storage implementation - * - * This file contains the compound file implementation - * of the storage interface. - * - * Copyright 1999 Francis Beaudet - * Copyright 1999 Sylvain St-Germain - * Copyright 1999 Thuy Nguyen - * Copyright 2005 Mike McCormack - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <assert.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "winuser.h" -#include "wine/unicode.h" -#include "wine/debug.h" - -#include "storage32.h" -#include "ole2.h" /* For Write/ReadClassStm */ - -#include "winreg.h" -#include "wine/wingdi16.h" - -WINE_DEFAULT_DEBUG_CHANNEL(storage); - -#define FILE_BEGIN 0 - -/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */ -#define OLESTREAM_ID 0x501 -#define OLESTREAM_MAX_STR_LEN 255 - -static const char rootPropertyName[] = "Root Entry"; - - -/* OLESTREAM memory structure to use for Get and Put Routines */ -/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */ -typedef struct -{ - DWORD dwOleID; - DWORD dwTypeID; - DWORD dwOleTypeNameLength; - CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN]; - CHAR *pstrOleObjFileName; - DWORD dwOleObjFileNameLength; - DWORD dwMetaFileWidth; - DWORD dwMetaFileHeight; - CHAR strUnknown[8]; /* don't know what is this 8 byts information in OLE stream. */ - DWORD dwDataLength; - BYTE *pData; -}OLECONVERT_OLESTREAM_DATA; - -/* CompObj Stream structure */ -/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */ -typedef struct -{ - BYTE byUnknown1[12]; - CLSID clsid; - DWORD dwCLSIDNameLength; - CHAR strCLSIDName[OLESTREAM_MAX_STR_LEN]; - DWORD dwOleTypeNameLength; - CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN]; - DWORD dwProgIDNameLength; - CHAR strProgIDName[OLESTREAM_MAX_STR_LEN]; - BYTE byUnknown2[16]; -}OLECONVERT_ISTORAGE_COMPOBJ; - - -/* Ole Presention Stream structure */ -/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */ -typedef struct -{ - BYTE byUnknown1[28]; - DWORD dwExtentX; - DWORD dwExtentY; - DWORD dwSize; - BYTE *pData; -}OLECONVERT_ISTORAGE_OLEPRES; - - - -/*********************************************************************** - * Forward declaration of internal functions used by the method DestroyElement - */ -static HRESULT deleteStorageProperty( - StorageImpl *parentStorage, - ULONG foundPropertyIndexToDelete, - StgProperty propertyToDelete); - -static HRESULT deleteStreamProperty( - StorageImpl *parentStorage, - ULONG foundPropertyIndexToDelete, - StgProperty propertyToDelete); - -static HRESULT findPlaceholder( - StorageImpl *storage, - ULONG propertyIndexToStore, - ULONG storagePropertyIndex, - INT typeOfRelation); - -static HRESULT adjustPropertyChain( - StorageImpl *This, - StgProperty propertyToDelete, - StgProperty parentProperty, - ULONG parentPropertyId, - INT typeOfRelation); - -/*********************************************************************** - * Declaration of the functions used to manipulate StgProperty - */ - -static ULONG getFreeProperty( - StorageImpl *storage); - -static void updatePropertyChain( - StorageImpl *storage, - ULONG newPropertyIndex, - StgProperty newProperty); - -static LONG propertyNameCmp( - const OLECHAR *newProperty, - const OLECHAR *currentProperty); - - -/*********************************************************************** - * Declaration of miscellaneous functions... - */ -static HRESULT validateSTGM(DWORD stgmValue); - -static DWORD GetShareModeFromSTGM(DWORD stgm); -static DWORD GetAccessModeFromSTGM(DWORD stgm); -static DWORD GetCreationModeFromSTGM(DWORD stgm); - -extern IPropertySetStorageVtbl IPropertySetStorage_Vtbl; - - - -/************************************************************************ -** Storage32BaseImpl implementatiion -*/ - -/************************************************************************ - * Storage32BaseImpl_QueryInterface (IUnknown) - * - * This method implements the common QueryInterface for all IStorage32 - * implementations contained in this file. - * - * See Windows documentation for more details on IUnknown methods. - */ -HRESULT WINAPI StorageBaseImpl_QueryInterface( - IStorage* iface, - REFIID riid, - void** ppvObject) -{ - StorageBaseImpl *This = (StorageBaseImpl *)iface; - /* - * Perform a sanity check on the parameters. - */ - if ( (This==0) || (ppvObject==0) ) - return E_INVALIDARG; - - /* - * Initialize the return parameter. - */ - *ppvObject = 0; - - /* - * Compare the riid with the interface IDs implemented by this object. - */ - if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) - { - *ppvObject = (IStorage*)This; - } - else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStorage)) == 0) - { - *ppvObject = (IStorage*)This; - } - else if (memcmp(&IID_IPropertySetStorage, riid, sizeof(IID_IPropertySetStorage)) == 0) - { - *ppvObject = (IStorage*)&This->pssVtbl; - } - - /* - * Check that we obtained an interface. - */ - if ((*ppvObject)==0) - return E_NOINTERFACE; - - /* - * Query Interface always increases the reference count by one when it is - * successful - */ - IStorage_AddRef(iface); - - return S_OK; -} - -/************************************************************************ - * Storage32BaseImpl_AddRef (IUnknown) - * - * This method implements the common AddRef for all IStorage32 - * implementations contained in this file. - * - * See Windows documentation for more details on IUnknown methods. - */ -ULONG WINAPI StorageBaseImpl_AddRef( - IStorage* iface) -{ - StorageBaseImpl *This = (StorageBaseImpl *)iface; - ULONG ref = InterlockedIncrement(&This->ref); - - TRACE("(%p) AddRef to %ld\n", This, ref); - - return ref; -} - -/************************************************************************ - * Storage32BaseImpl_Release (IUnknown) - * - * This method implements the common Release for all IStorage32 - * implementations contained in this file. - * - * See Windows documentation for more details on IUnknown methods. - */ -ULONG WINAPI StorageBaseImpl_Release( - IStorage* iface) -{ - StorageBaseImpl *This = (StorageBaseImpl *)iface; - /* - * Decrease the reference count on this object. - */ - ULONG ref = InterlockedDecrement(&This->ref); - - TRACE("(%p) ReleaseRef to %ld\n", This, ref); - - /* - * If the reference count goes down to 0, perform suicide. - */ - if (ref == 0) - { - /* - * Since we are using a system of base-classes, we want to call the - * destructor of the appropriate derived class. To do this, we are - * using virtual functions to implement the destructor. - */ - This->v_destructor(This); - } - - return ref; -} - -/************************************************************************ - * Storage32BaseImpl_OpenStream (IStorage) - * - * This method will open the specified stream object from the current storage. - * - * See Windows documentation for more details on IStorage methods. - */ -HRESULT WINAPI StorageBaseImpl_OpenStream( - IStorage* iface, - const OLECHAR* pwcsName, /* [string][in] */ - void* reserved1, /* [unique][in] */ - DWORD grfMode, /* [in] */ - DWORD reserved2, /* [in] */ - IStream** ppstm) /* [out] */ -{ - StorageBaseImpl *This = (StorageBaseImpl *)iface; - IEnumSTATSTGImpl* propertyEnumeration; - StgStreamImpl* newStream; - StgProperty currentProperty; - ULONG foundPropertyIndex; - HRESULT res = STG_E_UNKNOWN; - DWORD parent_grfMode; - - TRACE("(%p, %s, %p, %lx, %ld, %p)\n", - iface, debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm); - - /* - * Perform a sanity check on the parameters. - */ - if ( (pwcsName==NULL) || (ppstm==0) ) - { - res = E_INVALIDARG; - goto end; - } - - /* - * Initialize the out parameter - */ - *ppstm = NULL; - - /* - * Validate the STGM flags - */ - if ( FAILED( validateSTGM(grfMode) )) - { - res = STG_E_INVALIDFLAG; - goto end; - } - - /* - * As documented. - */ - if ( STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE || - (grfMode & STGM_DELETEONRELEASE) || - (grfMode & STGM_TRANSACTED) ) - { - res = STG_E_INVALIDFUNCTION; - goto end; - } - - /* - * Check that we're compatible with the parent's storage mode - */ - parent_grfMode = STGM_ACCESS_MODE( This->ancestorStorage->base.openFlags ); - if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( parent_grfMode ) ) - { - res = STG_E_ACCESSDENIED; - goto end; - } - - /* - * Create a property enumeration to search the properties - */ - propertyEnumeration = IEnumSTATSTGImpl_Construct( - This->ancestorStorage, - This->rootPropertySetIndex); - - /* - * Search the enumeration for the property with the given name - */ - foundPropertyIndex = IEnumSTATSTGImpl_FindProperty( - propertyEnumeration, - pwcsName, - ¤tProperty); - - /* - * Delete the property enumeration since we don't need it anymore - */ - IEnumSTATSTGImpl_Destroy(propertyEnumeration); - - /* - * If it was found, construct the stream object and return a pointer to it. - */ - if ( (foundPropertyIndex!=PROPERTY_NULL) && - (currentProperty.propertyType==PROPTYPE_STREAM) ) - { - newStream = StgStreamImpl_Construct(This, grfMode, foundPropertyIndex); - - if (newStream!=0) - { - newStream->grfMode = grfMode; - *ppstm = (IStream*)newStream; - - /* - * Since we are returning a pointer to the interface, we have to - * nail down the reference. - */ - IStream_AddRef(*ppstm); - - res = S_OK; - goto end; - } - - res = E_OUTOFMEMORY; - goto end; - } - - res = STG_E_FILENOTFOUND; - -end: - if (res == S_OK) - TRACE("<-- IStream %p\n", *ppstm); - TRACE("<-- %08lx\n", res); - return res; -} - -/************************************************************************ - * Storage32BaseImpl_OpenStorage (IStorage) - * - * This method will open a new storage object from the current storage. - * - * See Windows documentation for more details on IStorage methods. - */ -HRESULT WINAPI StorageBaseImpl_OpenStorage( - IStorage* iface, - const OLECHAR* pwcsName, /* [string][unique][in] */ - IStorage* pstgPriority, /* [unique][in] */ - DWORD grfMode, /* [in] */ - SNB snbExclude, /* [unique][in] */ - DWORD reserved, /* [in] */ - IStorage** ppstg) /* [out] */ -{ - StorageBaseImpl *This = (StorageBaseImpl *)iface; - StorageInternalImpl* newStorage; - IEnumSTATSTGImpl* propertyEnumeration; - StgProperty currentProperty; - ULONG foundPropertyIndex; - HRESULT res = STG_E_UNKNOWN; - DWORD parent_grfMode; - - TRACE("(%p, %s, %p, %lx, %p, %ld, %p)\n", - iface, debugstr_w(pwcsName), pstgPriority, - grfMode, snbExclude, reserved, ppstg); - - /* - * Perform a sanity check on the parameters. - */ - if ( (This==0) || (pwcsName==NULL) || (ppstg==0) ) - { - res = E_INVALIDARG; - goto end; - } - - /* as documented */ - if (snbExclude != NULL) - { - res = STG_E_INVALIDPARAMETER; - goto end; - } - - /* - * Validate the STGM flags - */ - if ( FAILED( validateSTGM(grfMode) )) - { - res = STG_E_INVALIDFLAG; - goto end; - } - - /* - * As documented. - */ - if ( STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE || - (grfMode & STGM_DELETEONRELEASE) || - (grfMode & STGM_PRIORITY) ) - { - res = STG_E_INVALIDFUNCTION; - goto end; - } - - /* - * Check that we're compatible with the parent's storage mode - */ - parent_grfMode = STGM_ACCESS_MODE( This->ancestorStorage->base.openFlags ); - if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( parent_grfMode ) ) - { - res = STG_E_ACCESSDENIED; - goto end; - } - - /* - * Initialize the out parameter - */ - *ppstg = NULL; - - /* - * Create a property enumeration to search the properties - */ - propertyEnumeration = IEnumSTATSTGImpl_Construct( - This->ancestorStorage, - This->rootPropertySetIndex); - - /* - * Search the enumeration for the property with the given name - */ - foundPropertyIndex = IEnumSTATSTGImpl_FindProperty( - propertyEnumeration, - pwcsName, - ¤tProperty); - - /* - * Delete the property enumeration since we don't need it anymore - */ - IEnumSTATSTGImpl_Destroy(propertyEnumeration); - - /* - * If it was found, construct the stream object and return a pointer to it. - */ - if ( (foundPropertyIndex!=PROPERTY_NULL) && - (currentProperty.propertyType==PROPTYPE_STORAGE) ) - { - /* - * Construct a new Storage object - */ - newStorage = StorageInternalImpl_Construct( - This->ancestorStorage, - grfMode, - foundPropertyIndex); - - if (newStorage != 0) - { - *ppstg = (IStorage*)newStorage; - - /* - * Since we are returning a pointer to the interface, - * we have to nail down the reference. - */ - StorageBaseImpl_AddRef(*ppstg); - - res = S_OK; - goto end; - } - - res = STG_E_INSUFFICIENTMEMORY; - goto end; - } - - res = STG_E_FILENOTFOUND; - -end: - TRACE("<-- %08lx\n", res); - return res; -} - -/************************************************************************ - * Storage32BaseImpl_EnumElements (IStorage) - * - * This method will create an enumerator object that can be used to - * retrieve informatino about all the properties in the storage object. - * - * See Windows documentation for more details on IStorage methods. - */ -HRESULT WINAPI StorageBaseImpl_EnumElements( - IStorage* iface, - DWORD reserved1, /* [in] */ - void* reserved2, /* [size_is][unique][in] */ - DWORD reserved3, /* [in] */ - IEnumSTATSTG** ppenum) /* [out] */ -{ - StorageBaseImpl *This = (StorageBaseImpl *)iface; - IEnumSTATSTGImpl* newEnum; - - TRACE("(%p, %ld, %p, %ld, %p)\n", - iface, reserved1, reserved2, reserved3, ppenum); - - /* - * Perform a sanity check on the parameters. - */ - if ( (This==0) || (ppenum==0)) - return E_INVALIDARG; - - /* - * Construct the enumerator. - */ - newEnum = IEnumSTATSTGImpl_Construct( - This->ancestorStorage, - This->rootPropertySetIndex); - - if (newEnum!=0) - { - *ppenum = (IEnumSTATSTG*)newEnum; - - /* - * Don't forget to nail down a reference to the new object before - * returning it. - */ - IEnumSTATSTG_AddRef(*ppenum); - - return S_OK; - } - - return E_OUTOFMEMORY; -} - -/************************************************************************ - * Storage32BaseImpl_Stat (IStorage) - * - * This method will retrieve information about this storage object. - * - * See Windows documentation for more details on IStorage methods. - */ -HRESULT WINAPI StorageBaseImpl_Stat( - IStorage* iface, - STATSTG* pstatstg, /* [out] */ - DWORD grfStatFlag) /* [in] */ -{ - StorageBaseImpl *This = (StorageBaseImpl *)iface; - StgProperty curProperty; - BOOL readSuccessful; - HRESULT res = STG_E_UNKNOWN; - - TRACE("(%p, %p, %lx)\n", - iface, pstatstg, grfStatFlag); - - /* - * Perform a sanity check on the parameters. - */ - if ( (This==0) || (pstatstg==0)) - { - res = E_INVALIDARG; - goto end; - } - - /* - * Read the information from the property. - */ - readSuccessful = StorageImpl_ReadProperty( - This->ancestorStorage, - This->rootPropertySetIndex, - &curProperty); - - if (readSuccessful) - { - StorageUtl_CopyPropertyToSTATSTG( - pstatstg, - &curProperty, - grfStatFlag); - - res = S_OK; - goto end; - } - - res = E_FAIL; - -end: - if (res == S_OK) - { - TRACE("<-- STATSTG: pwcsName: %s, type: %ld, cbSize.Low/High: %ld/%ld, grfMode: %08lx, grfLocksSupported: %ld, grfStateBits: %08lx\n", debugstr_w(pstatstg->pwcsName), pstatstg->type, pstatstg->cbSize.u.LowPart, pstatstg->cbSize.u.HighPart, pstatstg->grfMode, pstatstg->grfLocksSupported, pstatstg->grfStateBits); - } - TRACE("<-- %08lx\n", res); - return res; -} - -/************************************************************************ - * Storage32BaseImpl_RenameElement (IStorage) - * - * This method will rename the specified element. - * - * See Windows documentation for more details on IStorage methods. - * - * Implementation notes: The method used to rename consists of creating a clone - * of the deleted StgProperty object setting it with the new name and to - * perform a DestroyElement of the old StgProperty. - */ -HRESULT WINAPI StorageBaseImpl_RenameElement( - IStorage* iface, - const OLECHAR* pwcsOldName, /* [in] */ - const OLECHAR* pwcsNewName) /* [in] */ -{ - StorageBaseImpl *This = (StorageBaseImpl *)iface; - IEnumSTATSTGImpl* propertyEnumeration; - StgProperty currentProperty; - ULONG foundPropertyIndex; - - TRACE("(%p, %s, %s)\n", - iface, debugstr_w(pwcsOldName), debugstr_w(pwcsNewName)); - - /* - * Create a property enumeration to search the properties - */ - propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage, - This->rootPropertySetIndex); - - /* - * Search the enumeration for the new property name - */ - foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration, - pwcsNewName, - ¤tProperty); - - if (foundPropertyIndex != PROPERTY_NULL) - { - /* - * There is already a property with the new name - */ - IEnumSTATSTGImpl_Destroy(propertyEnumeration); - return STG_E_FILEALREADYEXISTS; - } - - IEnumSTATSTG_Reset((IEnumSTATSTG*)propertyEnumeration); - - /* - * Search the enumeration for the old property name - */ - foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration, - pwcsOldName, - ¤tProperty); - - /* - * Delete the property enumeration since we don't need it anymore - */ - IEnumSTATSTGImpl_Destroy(propertyEnumeration); - - if (foundPropertyIndex != PROPERTY_NULL) - { - StgProperty renamedProperty; - ULONG renamedPropertyIndex; - - /* - * Setup a new property for the renamed property - */ - renamedProperty.sizeOfNameString = - ( lstrlenW(pwcsNewName)+1 ) * sizeof(WCHAR); - - if (renamedProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN) - return STG_E_INVALIDNAME; - - strcpyW(renamedProperty.name, pwcsNewName); - - renamedProperty.propertyType = currentProperty.propertyType; - renamedProperty.startingBlock = currentProperty.startingBlock; - renamedProperty.size.u.LowPart = currentProperty.size.u.LowPart; - renamedProperty.size.u.HighPart = currentProperty.size.u.HighPart; - - renamedProperty.previousProperty = PROPERTY_NULL; - renamedProperty.nextProperty = PROPERTY_NULL; - - /* - * Bring the dirProperty link in case it is a storage and in which - * case the renamed storage elements don't require to be reorganized. - */ - renamedProperty.dirProperty = currentProperty.dirProperty; - - /* call CoFileTime to get the current time - renamedProperty.timeStampS1 - renamedProperty.timeStampD1 - renamedProperty.timeStampS2 - renamedProperty.timeStampD2 - renamedProperty.propertyUniqueID - */ - - /* - * Obtain a free property in the property chain - */ - renamedPropertyIndex = getFreeProperty(This->ancestorStorage); - - /* - * Save the new property into the new property spot - */ - StorageImpl_WriteProperty( - This->ancestorStorage, - renamedPropertyIndex, - &renamedProperty); - - /* - * Find a spot in the property chain for our newly created property. - */ - updatePropertyChain( - (StorageImpl*)This, - renamedPropertyIndex, - renamedProperty); - - /* - * At this point the renamed property has been inserted in the tree, - * now, before to Destroy the old property we must zeroed it's dirProperty - * otherwise the DestroyProperty below will zap it all and we do not want - * this to happen. - * Also, we fake that the old property is a storage so the DestroyProperty - * will not do a SetSize(0) on the stream data. - * - * This means that we need to tweek the StgProperty if it is a stream or a - * non empty storage. - */ - StorageImpl_ReadProperty(This->ancestorStorage, - foundPropertyIndex, - ¤tProperty); - - currentProperty.dirProperty = PROPERTY_NULL; - currentProperty.propertyType = PROPTYPE_STORAGE; - StorageImpl_WriteProperty( - This->ancestorStorage, - foundPropertyIndex, - ¤tProperty); - - /* - * Invoke Destroy to get rid of the ole property and automatically redo - * the linking of it's previous and next members... - */ - IStorage_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName); - - } - else - { - /* - * There is no property with the old name - */ - return STG_E_FILENOTFOUND; - } - - return S_OK; -} - -/************************************************************************ - * Storage32BaseImpl_CreateStream (IStorage) - * - * This method will create a stream object within this storage - * - * See Windows documentation for more details on IStorage methods. - */ -HRESULT WINAPI StorageBaseImpl_CreateStream( - IStorage* iface, - const OLECHAR* pwcsName, /* [string][in] */ - DWORD grfMode, /* [in] */ - DWORD reserved1, /* [in] */ - DWORD reserved2, /* [in] */ - IStream** ppstm) /* [out] */ -{ - StorageBaseImpl *This = (StorageBaseImpl *)iface; - IEnumSTATSTGImpl* propertyEnumeration; - StgStreamImpl* newStream; - StgProperty currentProperty, newStreamProperty; - ULONG foundPropertyIndex, newPropertyIndex; - DWORD parent_grfMode; - - TRACE("(%p, %s, %lx, %ld, %ld, %p)\n", - iface, debugstr_w(pwcsName), grfMode, - reserved1, reserved2, ppstm); - - /* - * Validate parameters - */ - if (ppstm == 0) - return STG_E_INVALIDPOINTER; - - if (pwcsName == 0) - return STG_E_INVALIDNAME; - - if (reserved1 || reserved2) - return STG_E_INVALIDPARAMETER; - - /* - * Validate the STGM flags - */ - if ( FAILED( validateSTGM(grfMode) )) - return STG_E_INVALIDFLAG; - - if (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE) - return STG_E_INVALIDFLAG; - - /* - * As documented. - */ - if ((grfMode & STGM_DELETEONRELEASE) || - (grfMode & STGM_TRANSACTED)) - return STG_E_INVALIDFUNCTION; - - /* - * Check that we're compatible with the parent's storage mode - */ - parent_grfMode = STGM_ACCESS_MODE( This->ancestorStorage->base.openFlags ); - if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( parent_grfMode ) ) - return STG_E_ACCESSDENIED; - - /* - * Initialize the out parameter - */ - *ppstm = 0; - - /* - * Create a property enumeration to search the properties - */ - propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage, - This->rootPropertySetIndex); - - foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration, - pwcsName, - ¤tProperty); - - IEnumSTATSTGImpl_Destroy(propertyEnumeration); - - if (foundPropertyIndex != PROPERTY_NULL) - { - /* - * An element with this name already exists - */ - if (STGM_CREATE_MODE(grfMode) == STGM_CREATE) - { - IStorage_DestroyElement(iface, pwcsName); - } - else - return STG_E_FILEALREADYEXISTS; - } - - /* - * memset the empty property - */ - memset(&newStreamProperty, 0, sizeof(StgProperty)); - - newStreamProperty.sizeOfNameString = - ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR); - - if (newStreamProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN) - return STG_E_INVALIDNAME; - - strcpyW(newStreamProperty.name, pwcsName); - - newStreamProperty.propertyType = PROPTYPE_STREAM; - newStreamProperty.startingBlock = BLOCK_END_OF_CHAIN; - newStreamProperty.size.u.LowPart = 0; - newStreamProperty.size.u.HighPart = 0; - - newStreamProperty.previousProperty = PROPERTY_NULL; - newStreamProperty.nextProperty = PROPERTY_NULL; - newStreamProperty.dirProperty = PROPERTY_NULL; - - /* call CoFileTime to get the current time - newStreamProperty.timeStampS1 - newStreamProperty.timeStampD1 - newStreamProperty.timeStampS2 - newStreamProperty.timeStampD2 - */ - - /* newStreamProperty.propertyUniqueID */ - - /* - * Get a free property or create a new one - */ - newPropertyIndex = getFreeProperty(This->ancestorStorage); - - /* - * Save the new property into the new property spot - */ - StorageImpl_WriteProperty( - This->ancestorStorage, - newPropertyIndex, - &newStreamProperty); - - /* - * Find a spot in the property chain for our newly created property. - */ - updatePropertyChain( - (StorageImpl*)This, - newPropertyIndex, - newStreamProperty); - - /* - * Open the stream to return it. - */ - newStream = StgStreamImpl_Construct(This, grfMode, newPropertyIndex); - - if (newStream != 0) - { - *ppstm = (IStream*)newStream; - - /* - * Since we are returning a pointer to the interface, we have to nail down - * the reference. - */ - IStream_AddRef(*ppstm); - } - else - { - return STG_E_INSUFFICIENTMEMORY; - } - - return S_OK; -} - -/************************************************************************ - * Storage32BaseImpl_SetClass (IStorage) - * - * This method will write the specified CLSID in the property of this - * storage. - * - * See Windows documentation for more details on IStorage methods. - */ -HRESULT WINAPI StorageBaseImpl_SetClass( - IStorage* iface, - REFCLSID clsid) /* [in] */ -{ - StorageBaseImpl *This = (StorageBaseImpl *)iface; - HRESULT hRes = E_FAIL; - StgProperty curProperty; - BOOL success; - - TRACE("(%p, %p)\n", iface, clsid); - - success = StorageImpl_ReadProperty(This->ancestorStorage, - This->rootPropertySetIndex, - &curProperty); - if (success) - { - curProperty.propertyUniqueID = *clsid; - - success = StorageImpl_WriteProperty(This->ancestorStorage, - This->rootPropertySetIndex, - &curProperty); - if (success) - hRes = S_OK; - } - - return hRes; -} - -/************************************************************************ -** Storage32Impl implementation -*/ - -/************************************************************************ - * Storage32Impl_CreateStorage (IStorage) - * - * This method will create the storage object within the provided storage. - * - * See Windows documentation for more details on IStorage methods. - */ -HRESULT WINAPI StorageImpl_CreateStorage( - IStorage* iface, - const OLECHAR *pwcsName, /* [string][in] */ - DWORD grfMode, /* [in] */ - DWORD reserved1, /* [in] */ - DWORD reserved2, /* [in] */ - IStorage **ppstg) /* [out] */ -{ - StorageImpl* const This=(StorageImpl*)iface; - - IEnumSTATSTGImpl *propertyEnumeration; - StgProperty currentProperty; - StgProperty newProperty; - ULONG foundPropertyIndex; - ULONG newPropertyIndex; - HRESULT hr; - DWORD parent_grfMode; - - TRACE("(%p, %s, %lx, %ld, %ld, %p)\n", - iface, debugstr_w(pwcsName), grfMode, - reserved1, reserved2, ppstg); - - /* - * Validate parameters - */ - if (ppstg == 0) - return STG_E_INVALIDPOINTER; - - if (pwcsName == 0) - return STG_E_INVALIDNAME; - - /* - * Validate the STGM flags - */ - if ( FAILED( validateSTGM(grfMode) ) || - (grfMode & STGM_DELETEONRELEASE) ) - return STG_E_INVALIDFLAG; - - /* - * Check that we're compatible with the parent's storage mode - */ - parent_grfMode = STGM_ACCESS_MODE( This->base.ancestorStorage->base.openFlags ); - if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( parent_grfMode ) ) - return STG_E_ACCESSDENIED; - - /* - * Initialize the out parameter - */ - *ppstg = 0; - - /* - * Create a property enumeration and search the properties - */ - propertyEnumeration = IEnumSTATSTGImpl_Construct( This->base.ancestorStorage, - This->base.rootPropertySetIndex); - - foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration, - pwcsName, - ¤tProperty); - IEnumSTATSTGImpl_Destroy(propertyEnumeration); - - if (foundPropertyIndex != PROPERTY_NULL) - { - /* - * An element with this name already exists - */ - if (STGM_CREATE_MODE(grfMode) == STGM_CREATE) - IStorage_DestroyElement(iface, pwcsName); - else - return STG_E_FILEALREADYEXISTS; - } - - /* - * memset the empty property - */ - memset(&newProperty, 0, sizeof(StgProperty)); - - newProperty.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR); - - if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN) - return STG_E_INVALIDNAME; - - strcpyW(newProperty.name, pwcsName); - - newProperty.propertyType = PROPTYPE_STORAGE; - newProperty.startingBlock = BLOCK_END_OF_CHAIN; - newProperty.size.u.LowPart = 0; - newProperty.size.u.HighPart = 0; - - newProperty.previousProperty = PROPERTY_NULL; - newProperty.nextProperty = PROPERTY_NULL; - newProperty.dirProperty = PROPERTY_NULL; - - /* call CoFileTime to get the current time - newProperty.timeStampS1 - newProperty.timeStampD1 - newProperty.timeStampS2 - newProperty.timeStampD2 - */ - - /* newStorageProperty.propertyUniqueID */ - - /* - * Obtain a free property in the property chain - */ - newPropertyIndex = getFreeProperty(This->base.ancestorStorage); - - /* - * Save the new property into the new property spot - */ - StorageImpl_WriteProperty( - This->base.ancestorStorage, - newPropertyIndex, - &newProperty); - - /* - * Find a spot in the property chain for our newly created property. - */ - updatePropertyChain( - This, - newPropertyIndex, - newProperty); - - /* - * Open it to get a pointer to return. - */ - hr = IStorage_OpenStorage( - iface, - (const OLECHAR*)pwcsName, - 0, - grfMode, - 0, - 0, - ppstg); - - if( (hr != S_OK) || (*ppstg == NULL)) - { - return hr; - } - - - return S_OK; -} - - -/*************************************************************************** - * - * Internal Method - * - * Get a free property or create a new one. - */ -static ULONG getFreeProperty( - StorageImpl *storage) -{ - ULONG currentPropertyIndex = 0; - ULONG newPropertyIndex = PROPERTY_NULL; - BOOL readSuccessful = TRUE; - StgProperty currentProperty; - - do - { - /* - * Start by reading the root property - */ - readSuccessful = StorageImpl_ReadProperty(storage->base.ancestorStorage, - currentPropertyIndex, - ¤tProperty); - if (readSuccessful) - { - if (currentProperty.sizeOfNameString == 0) - { - /* - * The property existis and is available, we found it. - */ - newPropertyIndex = currentPropertyIndex; - } - } - else - { - /* - * We exhausted the property list, we will create more space below - */ - newPropertyIndex = currentPropertyIndex; - } - currentPropertyIndex++; - - } while (newPropertyIndex == PROPERTY_NULL); - - /* - * grow the property chain - */ - if (! readSuccessful) - { - StgProperty emptyProperty; - ULARGE_INTEGER newSize; - ULONG propertyIndex; - ULONG lastProperty = 0; - ULONG blockCount = 0; - - /* - * obtain the new count of property blocks - */ - blockCount = BlockChainStream_GetCount( - storage->base.ancestorStorage->rootBlockChain)+1; - - /* - * initialize the size used by the property stream - */ - newSize.u.HighPart = 0; - newSize.u.LowPart = storage->bigBlockSize * blockCount; - - /* - * add a property block to the property chain - */ - BlockChainStream_SetSize(storage->base.ancestorStorage->rootBlockChain, newSize); - - /* - * memset the empty property in order to initialize the unused newly - * created property - */ - memset(&emptyProperty, 0, sizeof(StgProperty)); - - /* - * initialize them - */ - lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount; - - for( - propertyIndex = newPropertyIndex; - propertyIndex < lastProperty; - propertyIndex++) - { - StorageImpl_WriteProperty( - storage->base.ancestorStorage, - propertyIndex, - &emptyProperty); - } - } - - return newPropertyIndex; -} - -/**************************************************************************** - * - * Internal Method - * - * Case insensitive comparaison of StgProperty.name by first considering - * their size. - * - * Returns <0 when newPrpoerty < currentProperty - * >0 when newPrpoerty > currentProperty - * 0 when newPrpoerty == currentProperty - */ -static LONG propertyNameCmp( - const OLECHAR *newProperty, - const OLECHAR *currentProperty) -{ - LONG diff = lstrlenW(newProperty) - lstrlenW(currentProperty); - - if (diff == 0) - { - /* - * We compare the string themselves only when they are of the same length - */ - diff = lstrcmpiW( newProperty, currentProperty); - } - - return diff; -} - -/**************************************************************************** - * - * Internal Method - * - * Properly link this new element in the property chain. - */ -static void updatePropertyChain( - StorageImpl *storage, - ULONG newPropertyIndex, - StgProperty newProperty) -{ - StgProperty currentProperty; - - /* - * Read the root property - */ - StorageImpl_ReadProperty(storage->base.ancestorStorage, - storage->base.rootPropertySetIndex, - ¤tProperty); - - if (currentProperty.dirProperty != PROPERTY_NULL) - { - /* - * The root storage contains some element, therefore, start the research - * for the appropriate location. - */ - BOOL found = 0; - ULONG current, next, previous, currentPropertyId; - - /* - * Keep the StgProperty sequence number of the storage first property - */ - currentPropertyId = currentProperty.dirProperty; - - /* - * Read - */ - StorageImpl_ReadProperty(storage->base.ancestorStorage, - currentProperty.dirProperty, - ¤tProperty); - - previous = currentProperty.previousProperty; - next = currentProperty.nextProperty; - current = currentPropertyId; - - while (found == 0) - { - LONG diff = propertyNameCmp( newProperty.name, currentProperty.name); - - if (diff < 0) - { - if (previous != PROPERTY_NULL) - { - StorageImpl_ReadProperty(storage->base.ancestorStorage, - previous, - ¤tProperty); - current = previous; - } - else - { - currentProperty.previousProperty = newPropertyIndex; - StorageImpl_WriteProperty(storage->base.ancestorStorage, - current, - ¤tProperty); - found = 1; - } - } - else if (diff > 0) - { - if (next != PROPERTY_NULL) - { - StorageImpl_ReadProperty(storage->base.ancestorStorage, - next, - ¤tProperty); - current = next; - } - else - { - currentProperty.nextProperty = newPropertyIndex; - StorageImpl_WriteProperty(storage->base.ancestorStorage, - current, - ¤tProperty); - found = 1; - } - } - else - { - /* - * Trying to insert an item with the same name in the - * subtree structure. - */ - assert(FALSE); - } - - previous = currentProperty.previousProperty; - next = currentProperty.nextProperty; - } - } - else - { - /* - * The root storage is empty, link the new property to it's dir property - */ - currentProperty.dirProperty = newPropertyIndex; - StorageImpl_WriteProperty(storage->base.ancestorStorage, - storage->base.rootPropertySetIndex, - ¤tProperty); - } -} - - -/************************************************************************* - * CopyTo (IStorage) - */ -HRESULT WINAPI StorageImpl_CopyTo( - IStorage* iface, - DWORD ciidExclude, /* [in] */ - const IID* rgiidExclude, /* [size_is][unique][in] */ - SNB snbExclude, /* [unique][in] */ - IStorage* pstgDest) /* [unique][in] */ -{ - IEnumSTATSTG *elements = 0; - STATSTG curElement, strStat; - HRESULT hr; - IStorage *pstgTmp, *pstgChild; - IStream *pstrTmp, *pstrChild; - - if ((ciidExclude != 0) || (rgiidExclude != NULL) || (snbExclude != NULL)) - FIXME("Exclude option not implemented\n"); - - TRACE("(%p, %ld, %p, %p, %p)\n", - iface, ciidExclude, rgiidExclude, - snbExclude, pstgDest); - - /* - * Perform a sanity check - */ - if ( pstgDest == 0 ) - return STG_E_INVALIDPOINTER; - - /* - * Enumerate the elements - */ - hr = IStorage_EnumElements( iface, 0, 0, 0, &elements ); - - if ( hr != S_OK ) - return hr; - - /* - * set the class ID - */ - IStorage_Stat( iface, &curElement, STATFLAG_NONAME); - IStorage_SetClass( pstgDest, &curElement.clsid ); - - do - { - /* - * Obtain the next element - */ - hr = IEnumSTATSTG_Next( elements, 1, &curElement, NULL ); - - if ( hr == S_FALSE ) - { - hr = S_OK; /* done, every element has been copied */ - break; - } - - if (curElement.type == STGTY_STORAGE) - { - /* - * open child source storage - */ - hr = IStorage_OpenStorage( iface, curElement.pwcsName, NULL, - STGM_READ|STGM_SHARE_EXCLUSIVE, - NULL, 0, &pstgChild ); - - if (hr != S_OK) - break; - - /* - * Check if destination storage is not a child of the source - * storage, which will cause an infinite loop - */ - if (pstgChild == pstgDest) - { - IEnumSTATSTG_Release(elements); - - return STG_E_ACCESSDENIED; - } - - /* - * create a new storage in destination storage - */ - hr = IStorage_CreateStorage( pstgDest, curElement.pwcsName, - STGM_FAILIFTHERE|STGM_WRITE|STGM_SHARE_EXCLUSIVE, - 0, 0, - &pstgTmp ); - /* - * if it already exist, don't create a new one use this one - */ - if (hr == STG_E_FILEALREADYEXISTS) - { - hr = IStorage_OpenStorage( pstgDest, curElement.pwcsName, NULL, - STGM_WRITE|STGM_SHARE_EXCLUSIVE, - NULL, 0, &pstgTmp ); - } - - if (hr != S_OK) - break; - - - /* - * do the copy recursively - */ - hr = IStorage_CopyTo( pstgChild, ciidExclude, rgiidExclude, - snbExclude, pstgTmp ); - - IStorage_Release( pstgTmp ); - IStorage_Release( pstgChild ); - } - else if (curElement.type == STGTY_STREAM) - { - /* - * create a new stream in destination storage. If the stream already - * exist, it will be deleted and a new one will be created. - */ - hr = IStorage_CreateStream( pstgDest, curElement.pwcsName, - STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE, - 0, 0, &pstrTmp ); - - if (hr != S_OK) - break; - - /* - * open child stream storage - */ - hr = IStorage_OpenStream( iface, curElement.pwcsName, NULL, - STGM_READ|STGM_SHARE_EXCLUSIVE, - 0, &pstrChild ); - - if (hr != S_OK) - break; - - /* - * Get the size of the source stream - */ - IStream_Stat( pstrChild, &strStat, STATFLAG_NONAME ); - - /* - * Set the size of the destination stream. - */ - IStream_SetSize(pstrTmp, strStat.cbSize); - - /* - * do the copy - */ - hr = IStream_CopyTo( pstrChild, pstrTmp, strStat.cbSize, - NULL, NULL ); - - IStream_Release( pstrTmp ); - IStream_Release( pstrChild ); - } - else - { - WARN("unknown element type: %ld\n", curElement.type); - } - - } while (hr == S_OK); - - /* - * Clean-up - */ - IEnumSTATSTG_Release(elements); - - return hr; -} - -/************************************************************************* - * MoveElementTo (IStorage) - */ -HRESULT WINAPI StorageImpl_MoveElementTo( - IStorage* iface, - const OLECHAR *pwcsName, /* [string][in] */ - IStorage *pstgDest, /* [unique][in] */ - const OLECHAR *pwcsNewName,/* [string][in] */ - DWORD grfFlags) /* [in] */ -{ - FIXME("not implemented!\n"); - return E_NOTIMPL; -} - -/************************************************************************* - * Commit (IStorage) - */ -HRESULT WINAPI StorageImpl_Commit( - IStorage* iface, - DWORD grfCommitFlags)/* [in] */ -{ - FIXME("(%ld): stub!\n", grfCommitFlags); - return S_OK; -} - -/************************************************************************* - * Revert (IStorage) - */ -HRESULT WINAPI StorageImpl_Revert( - IStorage* iface) -{ - FIXME("not implemented!\n"); - return E_NOTIMPL; -} - -/************************************************************************* - * DestroyElement (IStorage) - * - * Stategy: This implementation is build this way for simplicity not for speed. - * I always delete the top most element of the enumeration and adjust - * the deleted element pointer all the time. This takes longer to - * do but allow to reinvoke DestroyElement whenever we encounter a - * storage object. The optimisation reside in the usage of another - * enumeration stategy that would give all the leaves of a storage - * first. (postfix order) - */ -HRESULT WINAPI StorageImpl_DestroyElement( - IStorage* iface, - const OLECHAR *pwcsName)/* [string][in] */ -{ - StorageImpl* const This=(StorageImpl*)iface; - - IEnumSTATSTGImpl* propertyEnumeration; - HRESULT hr = S_OK; - BOOL res; - StgProperty propertyToDelete; - StgProperty parentProperty; - ULONG foundPropertyIndexToDelete; - ULONG typeOfRelation; - ULONG parentPropertyId; - - TRACE("(%p, %s)\n", - iface, debugstr_w(pwcsName)); - - /* - * Perform a sanity check on the parameters. - */ - if (pwcsName==NULL) - return STG_E_INVALIDPOINTER; - - /* - * Create a property enumeration to search the property with the given name - */ - propertyEnumeration = IEnumSTATSTGImpl_Construct( - This->base.ancestorStorage, - This->base.rootPropertySetIndex); - - foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty( - propertyEnumeration, - pwcsName, - &propertyToDelete); - - IEnumSTATSTGImpl_Destroy(propertyEnumeration); - - if ( foundPropertyIndexToDelete == PROPERTY_NULL ) - { - return STG_E_FILENOTFOUND; - } - - /* - * Find the parent property of the property to delete (the one that - * link to it). If This->dirProperty == foundPropertyIndexToDelete, - * the parent is This. Otherwise, the parent is one of it's sibling... - */ - - /* - * First, read This's StgProperty.. - */ - res = StorageImpl_ReadProperty( - This->base.ancestorStorage, - This->base.rootPropertySetIndex, - &parentProperty); - - assert(res); - - /* - * Second, check to see if by any chance the actual storage (This) is not - * the parent of the property to delete... We never know... - */ - if ( parentProperty.dirProperty == foundPropertyIndexToDelete ) - { - /* - * Set data as it would have been done in the else part... - */ - typeOfRelation = PROPERTY_RELATION_DIR; - parentPropertyId = This->base.rootPropertySetIndex; - } - else - { - /* - * Create a property enumeration to search the parent properties, and - * delete it once done. - */ - IEnumSTATSTGImpl* propertyEnumeration2; - - propertyEnumeration2 = IEnumSTATSTGImpl_Construct( - This->base.ancestorStorage, - This->base.rootPropertySetIndex); - - typeOfRelation = IEnumSTATSTGImpl_FindParentProperty( - propertyEnumeration2, - foundPropertyIndexToDelete, - &parentProperty, - &parentPropertyId); - - IEnumSTATSTGImpl_Destroy(propertyEnumeration2); - } - - if ( propertyToDelete.propertyType == PROPTYPE_STORAGE ) - { - hr = deleteStorageProperty( - This, - foundPropertyIndexToDelete, - propertyToDelete); - } - else if ( propertyToDelete.propertyType == PROPTYPE_STREAM ) - { - hr = deleteStreamProperty( - This, - foundPropertyIndexToDelete, - propertyToDelete); - } - - if (hr!=S_OK) - return hr; - - /* - * Adjust the property chain - */ - hr = adjustPropertyChain( - This, - propertyToDelete, - parentProperty, - parentPropertyId, - typeOfRelation); - - return hr; -} - - -/************************************************************************ - * StorageImpl_Stat (IStorage) - * - * This method will retrieve information about this storage object. - * - * See Windows documentation for more details on IStorage methods. - */ -HRESULT WINAPI StorageImpl_Stat( IStorage* iface, - STATSTG* pstatstg, /* [out] */ - DWORD grfStatFlag) /* [in] */ -{ - StorageImpl* const This = (StorageImpl*)iface; - HRESULT result = StorageBaseImpl_Stat( iface, pstatstg, grfStatFlag ); - - if ( !FAILED(result) && ((grfStatFlag & STATFLAG_NONAME) == 0) && This->pwcsName ) - { - CoTaskMemFree(pstatstg->pwcsName); - pstatstg->pwcsName = CoTaskMemAlloc((lstrlenW(This->pwcsName)+1)*sizeof(WCHAR)); - strcpyW(pstatstg->pwcsName, This->pwcsName); - } - - return result; -} - - - -/********************************************************************* - * - * Internal Method - * - * Perform the deletion of a complete storage node - * - */ -static HRESULT deleteStorageProperty( - StorageImpl *parentStorage, - ULONG indexOfPropertyToDelete, - StgProperty propertyToDelete) -{ - IEnumSTATSTG *elements = 0; - IStorage *childStorage = 0; - STATSTG currentElement; - HRESULT hr; - HRESULT destroyHr = S_OK; - - /* - * Open the storage and enumerate it - */ - hr = StorageBaseImpl_OpenStorage( - (IStorage*)parentStorage, - propertyToDelete.name, - 0, - STGM_SHARE_EXCLUSIVE, - 0, - 0, - &childStorage); - - if (hr != S_OK) - { - return hr; - } - - /* - * Enumerate the elements - */ - IStorage_EnumElements( childStorage, 0, 0, 0, &elements); - - do - { - /* - * Obtain the next element - */ - hr = IEnumSTATSTG_Next(elements, 1, ¤tElement, NULL); - if (hr==S_OK) - { - destroyHr = StorageImpl_DestroyElement( - (IStorage*)childStorage, - (OLECHAR*)currentElement.pwcsName); - - CoTaskMemFree(currentElement.pwcsName); - } - - /* - * We need to Reset the enumeration every time because we delete elements - * and the enumeration could be invalid - */ - IEnumSTATSTG_Reset(elements); - - } while ((hr == S_OK) && (destroyHr == S_OK)); - - /* - * Invalidate the property by zeroing it's name member. - */ - propertyToDelete.sizeOfNameString = 0; - - StorageImpl_WriteProperty(parentStorage->base.ancestorStorage, - indexOfPropertyToDelete, - &propertyToDelete); - - IStorage_Release(childStorage); - IEnumSTATSTG_Release(elements); - - return destroyHr; -} - -/********************************************************************* - * - * Internal Method - * - * Perform the deletion of a stream node - * - */ -static HRESULT deleteStreamProperty( - StorageImpl *parentStorage, - ULONG indexOfPropertyToDelete, - StgProperty propertyToDelete) -{ - IStream *pis; - HRESULT hr; - ULARGE_INTEGER size; - - size.u.HighPart = 0; - size.u.LowPart = 0; - - hr = StorageBaseImpl_OpenStream( - (IStorage*)parentStorage, - (OLECHAR*)propertyToDelete.name, - NULL, - STGM_WRITE | STGM_SHARE_EXCLUSIVE, - 0, - &pis); - - if (hr!=S_OK) - { - return(hr); - } - - /* - * Zap the stream - */ - hr = IStream_SetSize(pis, size); - - if(hr != S_OK) - { - return hr; - } - - /* - * Release the stream object. - */ - IStream_Release(pis); - - /* - * Invalidate the property by zeroing it's name member. - */ - propertyToDelete.sizeOfNameString = 0; - - /* - * Here we should re-read the property so we get the updated pointer - * but since we are here to zap it, I don't do it... - */ - StorageImpl_WriteProperty( - parentStorage->base.ancestorStorage, - indexOfPropertyToDelete, - &propertyToDelete); - - return S_OK; -} - -/********************************************************************* - * - * Internal Method - * - * Finds a placeholder for the StgProperty within the Storage - * - */ -static HRESULT findPlaceholder( - StorageImpl *storage, - ULONG propertyIndexToStore, - ULONG storePropertyIndex, - INT typeOfRelation) -{ - StgProperty storeProperty; - HRESULT hr = S_OK; - BOOL res = TRUE; - - /* - * Read the storage property - */ - res = StorageImpl_ReadProperty( - storage->base.ancestorStorage, - storePropertyIndex, - &storeProperty); - - if(! res) - { - return E_FAIL; - } - - if (typeOfRelation == PROPERTY_RELATION_PREVIOUS) - { - if (storeProperty.previousProperty != PROPERTY_NULL) - { - return findPlaceholder( - storage, - propertyIndexToStore, - storeProperty.previousProperty, - typeOfRelation); - } - else - { - storeProperty.previousProperty = propertyIndexToStore; - } - } - else if (typeOfRelation == PROPERTY_RELATION_NEXT) - { - if (storeProperty.nextProperty != PROPERTY_NULL) - { - return findPlaceholder( - storage, - propertyIndexToStore, - storeProperty.nextProperty, - typeOfRelation); - } - else - { - storeProperty.nextProperty = propertyIndexToStore; - } - } - else if (typeOfRelation == PROPERTY_RELATION_DIR) - { - if (storeProperty.dirProperty != PROPERTY_NULL) - { - return findPlaceholder( - storage, - propertyIndexToStore, - storeProperty.dirProperty, - typeOfRelation); - } - else - { - storeProperty.dirProperty = propertyIndexToStore; - } - } - - hr = StorageImpl_WriteProperty( - storage->base.ancestorStorage, - storePropertyIndex, - &storeProperty); - - if(! hr) - { - return E_FAIL; - } - - return S_OK; -} - -/************************************************************************* - * - * Internal Method - * - * This method takes the previous and the next property link of a property - * to be deleted and find them a place in the Storage. - */ -static HRESULT adjustPropertyChain( - StorageImpl *This, - StgProperty propertyToDelete, - StgProperty parentProperty, - ULONG parentPropertyId, - INT typeOfRelation) -{ - ULONG newLinkProperty = PROPERTY_NULL; - BOOL needToFindAPlaceholder = FALSE; - ULONG storeNode = PROPERTY_NULL; - ULONG toStoreNode = PROPERTY_NULL; - INT relationType = 0; - HRESULT hr = S_OK; - BOOL res = TRUE; - - if (typeOfRelation == PROPERTY_RELATION_PREVIOUS) - { - if (propertyToDelete.previousProperty != PROPERTY_NULL) - { - /* - * Set the parent previous to the property to delete previous - */ - newLinkProperty = propertyToDelete.previousProperty; - - if (propertyToDelete.nextProperty != PROPERTY_NULL) - { - /* - * We also need to find a storage for the other link, setup variables - * to do this at the end... - */ - needToFindAPlaceholder = TRUE; - storeNode = propertyToDelete.previousProperty; - toStoreNode = propertyToDelete.nextProperty; - relationType = PROPERTY_RELATION_NEXT; - } - } - else if (propertyToDelete.nextProperty != PROPERTY_NULL) - { - /* - * Set the parent previous to the property to delete next - */ - newLinkProperty = propertyToDelete.nextProperty; - } - - /* - * Link it for real... - */ - parentProperty.previousProperty = newLinkProperty; - - } - else if (typeOfRelation == PROPERTY_RELATION_NEXT) - { - if (propertyToDelete.previousProperty != PROPERTY_NULL) - { - /* - * Set the parent next to the property to delete next previous - */ - newLinkProperty = propertyToDelete.previousProperty; - - if (propertyToDelete.nextProperty != PROPERTY_NULL) - { - /* - * We also need to find a storage for the other link, setup variables - * to do this at the end... - */ - needToFindAPlaceholder = TRUE; - storeNode = propertyToDelete.previousProperty; - toStoreNode = propertyToDelete.nextProperty; - relationType = PROPERTY_RELATION_NEXT; - } - } - else if (propertyToDelete.nextProperty != PROPERTY_NULL) - { - /* - * Set the parent next to the property to delete next - */ - newLinkProperty = propertyToDelete.nextProperty; - } - - /* - * Link it for real... - */ - parentProperty.nextProperty = newLinkProperty; - } - else /* (typeOfRelation == PROPERTY_RELATION_DIR) */ - { - if (propertyToDelete.previousProperty != PROPERTY_NULL) - { - /* - * Set the parent dir to the property to delete previous - */ - newLinkProperty = propertyToDelete.previousProperty; - - if (propertyToDelete.nextProperty != PROPERTY_NULL) - { - /* - * We also need to find a storage for the other link, setup variables - * to do this at the end... - */ - needToFindAPlaceholder = TRUE; - storeNode = propertyToDelete.previousProperty; - toStoreNode = propertyToDelete.nextProperty; - relationType = PROPERTY_RELATION_NEXT; - } - } - else if (propertyToDelete.nextProperty != PROPERTY_NULL) - { - /* - * Set the parent dir to the property to delete next - */ - newLinkProperty = propertyToDelete.nextProperty; - } - - /* - * Link it for real... - */ - parentProperty.dirProperty = newLinkProperty; - } - - /* - * Write back the parent property - */ - res = StorageImpl_WriteProperty( - This->base.ancestorStorage, - parentPropertyId, - &parentProperty); - if(! res) - { - return E_FAIL; - } - - /* - * If a placeholder is required for the other link, then, find one and - * get out of here... - */ - if (needToFindAPlaceholder) - { - hr = findPlaceholder( - This, - toStoreNode, - storeNode, - relationType); - } - - return hr; -} - - -/****************************************************************************** - * SetElementTimes (IStorage) - */ -HRESULT WINAPI StorageImpl_SetElementTimes( - IStorage* iface, - const OLECHAR *pwcsName,/* [string][in] */ - const FILETIME *pctime, /* [in] */ - const FILETIME *patime, /* [in] */ - const FILETIME *pmtime) /* [in] */ -{ - FIXME("(%s,...), stub!\n",debugstr_w(pwcsName)); - return S_OK; -} - -/****************************************************************************** - * SetStateBits (IStorage) - */ -HRESULT WINAPI StorageImpl_SetStateBits( - IStorage* iface, - DWORD grfStateBits,/* [in] */ - DWORD grfMask) /* [in] */ -{ - FIXME("not implemented!\n"); - return E_NOTIMPL; -} - -/* - * Virtual function table for the IStorage32Impl class. - */ -static IStorageVtbl Storage32Impl_Vtbl = -{ - StorageBaseImpl_QueryInterface, - StorageBaseImpl_AddRef, - StorageBaseImpl_Release, - StorageBaseImpl_CreateStream, - StorageBaseImpl_OpenStream, - StorageImpl_CreateStorage, - StorageBaseImpl_OpenStorage, - StorageImpl_CopyTo, - StorageImpl_MoveElementTo, - StorageImpl_Commit, - StorageImpl_Revert, - StorageBaseImpl_EnumElements, - StorageImpl_DestroyElement, - StorageBaseImpl_RenameElement, - StorageImpl_SetElementTimes, - StorageBaseImpl_SetClass, - StorageImpl_SetStateBits, - StorageImpl_Stat -}; - -HRESULT StorageImpl_Construct( - StorageImpl* This, - HANDLE hFile, - LPCOLESTR pwcsName, - ILockBytes* pLkbyt, - DWORD openFlags, - BOOL fileBased, - BOOL fileCreate) -{ - HRESULT hr = S_OK; - StgProperty currentProperty; - BOOL readSuccessful; - ULONG currentPropertyIndex; - - if ( FAILED( validateSTGM(openFlags) )) - return STG_E_INVALIDFLAG; - - memset(This, 0, sizeof(StorageImpl)); - - /* - * Initialize the virtual function table. - */ - This->base.lpVtbl = &Storage32Impl_Vtbl; - This->base.pssVtbl = &IPropertySetStorage_Vtbl; - This->base.v_destructor = &StorageImpl_Destroy; - This->base.openFlags = openFlags; - - /* - * This is the top-level storage so initialize the ancestor pointer - * to this. - */ - This->base.ancestorStorage = This; - - /* - * Initialize the physical support of the storage. - */ - This->hFile = hFile; - - /* - * Store copy of file path. - */ - if(pwcsName) { - This->pwcsName = HeapAlloc(GetProcessHeap(), 0, - (lstrlenW(pwcsName)+1)*sizeof(WCHAR)); - if (!This->pwcsName) - return STG_E_INSUFFICIENTMEMORY; - strcpyW(This->pwcsName, pwcsName); - } - - /* - * Initialize the big block cache. - */ - This->bigBlockSize = DEF_BIG_BLOCK_SIZE; - This->smallBlockSize = DEF_SMALL_BLOCK_SIZE; - This->bigBlockFile = BIGBLOCKFILE_Construct(hFile, - pLkbyt, - openFlags, - This->bigBlockSize, - fileBased); - - if (This->bigBlockFile == 0) - return E_FAIL; - - if (fileCreate) - { - ULARGE_INTEGER size; - BYTE* bigBlockBuffer; - - /* - * Initialize all header variables: - * - The big block depot consists of one block and it is at block 0 - * - The properties start at block 1 - * - There is no small block depot - */ - memset( This->bigBlockDepotStart, - BLOCK_UNUSED, - sizeof(This->bigBlockDepotStart)); - - This->bigBlockDepotCount = 1; - This->bigBlockDepotStart[0] = 0; - This->rootStartBlock = 1; - This->smallBlockDepotStart = BLOCK_END_OF_CHAIN; - This->bigBlockSizeBits = DEF_BIG_BLOCK_SIZE_BITS; - This->smallBlockSizeBits = DEF_SMALL_BLOCK_SIZE_BITS; - This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN; - This->extBigBlockDepotCount = 0; - - StorageImpl_SaveFileHeader(This); - - /* - * Add one block for the big block depot and one block for the properties - */ - size.u.HighPart = 0; - size.u.LowPart = This->bigBlockSize * 3; - BIGBLOCKFILE_SetSize(This->bigBlockFile, size); - - /* - * Initialize the big block depot - */ - bigBlockBuffer = StorageImpl_GetBigBlock(This, 0); - memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize); - StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL); - StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN); - StorageImpl_ReleaseBigBlock(This, bigBlockBuffer); - } - else - { - /* - * Load the header for the file. - */ - hr = StorageImpl_LoadFileHeader(This); - - if (FAILED(hr)) - { - BIGBLOCKFILE_Destructor(This->bigBlockFile); - - return hr; - } - } - - /* - * There is no block depot cached yet. - */ - This->indexBlockDepotCached = 0xFFFFFFFF; - - /* - * Start searching for free blocks with block 0. - */ - This->prevFreeBlock = 0; - - /* - * Create the block chain abstractions. - */ - if(!(This->rootBlockChain = - BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL))) - return STG_E_READFAULT; - - if(!(This->smallBlockDepotChain = - BlockChainStream_Construct(This, &This->smallBlockDepotStart, - PROPERTY_NULL))) - return STG_E_READFAULT; - - /* - * Write the root property - */ - if (fileCreate) - { - StgProperty rootProp; - /* - * Initialize the property chain - */ - memset(&rootProp, 0, sizeof(rootProp)); - MultiByteToWideChar( CP_ACP, 0, rootPropertyName, -1, rootProp.name, - sizeof(rootProp.name)/sizeof(WCHAR) ); - rootProp.sizeOfNameString = (strlenW(rootProp.name)+1) * sizeof(WCHAR); - rootProp.propertyType = PROPTYPE_ROOT; - rootProp.previousProperty = PROPERTY_NULL; - rootProp.nextProperty = PROPERTY_NULL; - rootProp.dirProperty = PROPERTY_NULL; - rootProp.startingBlock = BLOCK_END_OF_CHAIN; - rootProp.size.u.HighPart = 0; - rootProp.size.u.LowPart = 0; - - StorageImpl_WriteProperty(This, 0, &rootProp); - } - - /* - * Find the ID of the root in the property sets. - */ - currentPropertyIndex = 0; - - do - { - readSuccessful = StorageImpl_ReadProperty( - This, - currentPropertyIndex, - ¤tProperty); - - if (readSuccessful) - { - if ( (currentProperty.sizeOfNameString != 0 ) && - (currentProperty.propertyType == PROPTYPE_ROOT) ) - { - This->base.rootPropertySetIndex = currentPropertyIndex; - } - } - - currentPropertyIndex++; - - } while (readSuccessful && (This->base.rootPropertySetIndex == PROPERTY_NULL) ); - - if (!readSuccessful) - { - /* TODO CLEANUP */ - return STG_E_READFAULT; - } - - /* - * Create the block chain abstraction for the small block root chain. - */ - if(!(This->smallBlockRootChain = - BlockChainStream_Construct(This, NULL, This->base.rootPropertySetIndex))) - return STG_E_READFAULT; - - return hr; -} - -void StorageImpl_Destroy(StorageBaseImpl* iface) -{ - StorageImpl *This = (StorageImpl*) iface; - TRACE("(%p)\n", This); - - HeapFree(GetProcessHeap(), 0, This->pwcsName); - - BlockChainStream_Destroy(This->smallBlockRootChain); - BlockChainStream_Destroy(This->rootBlockChain); - BlockChainStream_Destroy(This->smallBlockDepotChain); - - BIGBLOCKFILE_Destructor(This->bigBlockFile); - HeapFree(GetProcessHeap(), 0, This); -} - -/****************************************************************************** - * Storage32Impl_GetNextFreeBigBlock - * - * Returns the index of the next free big block. - * If the big block depot is filled, this method will enlarge it. - * - */ -ULONG StorageImpl_GetNextFreeBigBlock( - StorageImpl* This) -{ - ULONG depotBlockIndexPos; - void *depotBuffer; - ULONG depotBlockOffset; - ULONG blocksPerDepot = This->bigBlockSize / sizeof(ULONG); - ULONG nextBlockIndex = BLOCK_SPECIAL; - int depotIndex = 0; - ULONG freeBlock = BLOCK_UNUSED; - - depotIndex = This->prevFreeBlock / blocksPerDepot; - depotBlockOffset = (This->prevFreeBlock % blocksPerDepot) * sizeof(ULONG); - - /* - * Scan the entire big block depot until we find a block marked free - */ - while (nextBlockIndex != BLOCK_UNUSED) - { - if (depotIndex < COUNT_BBDEPOTINHEADER) - { - depotBlockIndexPos = This->bigBlockDepotStart[depotIndex]; - - /* - * Grow the primary depot. - */ - if (depotBlockIndexPos == BLOCK_UNUSED) - { - depotBlockIndexPos = depotIndex*blocksPerDepot; - - /* - * Add a block depot. - */ - Storage32Impl_AddBlockDepot(This, depotBlockIndexPos); - This->bigBlockDepotCount++; - This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos; - - /* - * Flag it as a block depot. - */ - StorageImpl_SetNextBlockInChain(This, - depotBlockIndexPos, - BLOCK_SPECIAL); - - /* Save new header information. - */ - StorageImpl_SaveFileHeader(This); - } - } - else - { - depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex); - - if (depotBlockIndexPos == BLOCK_UNUSED) - { - /* - * Grow the extended depot. - */ - ULONG extIndex = BLOCK_UNUSED; - ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER; - ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1); - - if (extBlockOffset == 0) - { - /* We need an extended block. - */ - extIndex = Storage32Impl_AddExtBlockDepot(This); - This->extBigBlockDepotCount++; - depotBlockIndexPos = extIndex + 1; - } - else - depotBlockIndexPos = depotIndex * blocksPerDepot; - - /* - * Add a block depot and mark it in the extended block. - */ - Storage32Impl_AddBlockDepot(This, depotBlockIndexPos); - This->bigBlockDepotCount++; - Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos); - - /* Flag the block depot. - */ - StorageImpl_SetNextBlockInChain(This, - depotBlockIndexPos, - BLOCK_SPECIAL); - - /* If necessary, flag the extended depot block. - */ - if (extIndex != BLOCK_UNUSED) - StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT); - - /* Save header information. - */ - StorageImpl_SaveFileHeader(This); - } - } - - depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos); - - if (depotBuffer != 0) - { - while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) && - ( nextBlockIndex != BLOCK_UNUSED)) - { - StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex); - - if (nextBlockIndex == BLOCK_UNUSED) - { - freeBlock = (depotIndex * blocksPerDepot) + - (depotBlockOffset/sizeof(ULONG)); - } - - depotBlockOffset += sizeof(ULONG); - } - - StorageImpl_ReleaseBigBlock(This, depotBuffer); - } - - depotIndex++; - depotBlockOffset = 0; - } - - This->prevFreeBlock = freeBlock; - - return freeBlock; -} - -/****************************************************************************** - * Storage32Impl_AddBlockDepot - * - * This will create a depot block, essentially it is a block initialized - * to BLOCK_UNUSEDs. - */ -void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex) -{ - BYTE* blockBuffer; - - blockBuffer = StorageImpl_GetBigBlock(This, blockIndex); - - /* - * Initialize blocks as free - */ - memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize); - - StorageImpl_ReleaseBigBlock(This, blockBuffer); -} - -/****************************************************************************** - * Storage32Impl_GetExtDepotBlock - * - * Returns the index of the block that corresponds to the specified depot - * index. This method is only for depot indexes equal or greater than - * COUNT_BBDEPOTINHEADER. - */ -ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex) -{ - ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1; - ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER; - ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock; - ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock; - ULONG blockIndex = BLOCK_UNUSED; - ULONG extBlockIndex = This->extBigBlockDepotStart; - - assert(depotIndex >= COUNT_BBDEPOTINHEADER); - - if (This->extBigBlockDepotStart == BLOCK_END_OF_CHAIN) - return BLOCK_UNUSED; - - while (extBlockCount > 0) - { - extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex); - extBlockCount--; - } - - if (extBlockIndex != BLOCK_UNUSED) - { - BYTE* depotBuffer; - - depotBuffer = StorageImpl_GetROBigBlock(This, extBlockIndex); - - if (depotBuffer != 0) - { - StorageUtl_ReadDWord(depotBuffer, - extBlockOffset * sizeof(ULONG), - &blockIndex); - - StorageImpl_ReleaseBigBlock(This, depotBuffer); - } - } - - return blockIndex; -} - -/****************************************************************************** - * Storage32Impl_SetExtDepotBlock - * - * Associates the specified block index to the specified depot index. - * This method is only for depot indexes equal or greater than - * COUNT_BBDEPOTINHEADER. - */ -void Storage32Impl_SetExtDepotBlock(StorageImpl* This, - ULONG depotIndex, - ULONG blockIndex) -{ - ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1; - ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER; - ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock; - ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock; - ULONG extBlockIndex = This->extBigBlockDepotStart; - - assert(depotIndex >= COUNT_BBDEPOTINHEADER); - - while (extBlockCount > 0) - { - extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex); - extBlockCount--; - } - - if (extBlockIndex != BLOCK_UNUSED) - { - BYTE* depotBuffer; - - depotBuffer = StorageImpl_GetBigBlock(This, extBlockIndex); - - if (depotBuffer != 0) - { - StorageUtl_WriteDWord(depotBuffer, - extBlockOffset * sizeof(ULONG), - blockIndex); - - StorageImpl_ReleaseBigBlock(This, depotBuffer); - } - } -} - -/****************************************************************************** - * Storage32Impl_AddExtBlockDepot - * - * Creates an extended depot block. - */ -ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This) -{ - ULONG numExtBlocks = This->extBigBlockDepotCount; - ULONG nextExtBlock = This->extBigBlockDepotStart; - BYTE* depotBuffer = NULL; - ULONG index = BLOCK_UNUSED; - ULONG nextBlockOffset = This->bigBlockSize - sizeof(ULONG); - ULONG blocksPerDepotBlock = This->bigBlockSize / sizeof(ULONG); - ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1; - - index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) * - blocksPerDepotBlock; - - if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN)) - { - /* - * The first extended block. - */ - This->extBigBlockDepotStart = index; - } - else - { - unsigned int i; - /* - * Follow the chain to the last one. - */ - for (i = 0; i < (numExtBlocks - 1); i++) - { - nextExtBlock = Storage32Impl_GetNextExtendedBlock(This, nextExtBlock); - } - - /* - * Add the new extended block to the chain. - */ - depotBuffer = StorageImpl_GetBigBlock(This, nextExtBlock); - StorageUtl_WriteDWord(depotBuffer, nextBlockOffset, index); - StorageImpl_ReleaseBigBlock(This, depotBuffer); - } - - /* - * Initialize this block. - */ - depotBuffer = StorageImpl_GetBigBlock(This, index); - memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize); - StorageImpl_ReleaseBigBlock(This, depotBuffer); - - return index; -} - -/****************************************************************************** - * Storage32Impl_FreeBigBlock - * - * This method will flag the specified block as free in the big block depot. - */ -void StorageImpl_FreeBigBlock( - StorageImpl* This, - ULONG blockIndex) -{ - StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED); - - if (blockIndex < This->prevFreeBlock) - This->prevFreeBlock = blockIndex; -} - -/************************************************************************ - * Storage32Impl_GetNextBlockInChain - * - * This method will retrieve the block index of the next big block in - * in the chain. - * - * Params: This - Pointer to the Storage object. - * blockIndex - Index of the block to retrieve the chain - * for. - * nextBlockIndex - receives the return value. - * - * Returns: This method returns the index of the next block in the chain. - * It will return the constants: - * BLOCK_SPECIAL - If the block given was not part of a - * chain. - * BLOCK_END_OF_CHAIN - If the block given was the last in - * a chain. - * BLOCK_UNUSED - If the block given was not past of a chain - * and is available. - * BLOCK_EXTBBDEPOT - This block is part of the extended - * big block depot. - * - * See Windows documentation for more details on IStorage methods. - */ -HRESULT StorageImpl_GetNextBlockInChain( - StorageImpl* This, - ULONG blockIndex, - ULONG* nextBlockIndex) -{ - ULONG offsetInDepot = blockIndex * sizeof (ULONG); - ULONG depotBlockCount = offsetInDepot / This->bigBlockSize; - ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize; - void* depotBuffer; - ULONG depotBlockIndexPos; - int index; - - *nextBlockIndex = BLOCK_SPECIAL; - - if(depotBlockCount >= This->bigBlockDepotCount) - { - WARN("depotBlockCount %ld, bigBlockDepotCount %ld\n", depotBlockCount, - This->bigBlockDepotCount); - return STG_E_READFAULT; - } - - /* - * Cache the currently accessed depot block. - */ - if (depotBlockCount != This->indexBlockDepotCached) - { - This->indexBlockDepotCached = depotBlockCount; - - if (depotBlockCount < COUNT_BBDEPOTINHEADER) - { - depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount]; - } - else - { - /* - * We have to look in the extended depot. - */ - depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount); - } - - depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos); - - if (!depotBuffer) - return STG_E_READFAULT; - - for (index = 0; index < NUM_BLOCKS_PER_DEPOT_BLOCK; index++) - { - StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), nextBlockIndex); - This->blockDepotCached[index] = *nextBlockIndex; - } - StorageImpl_ReleaseBigBlock(This, depotBuffer); - } - - *nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)]; - - return S_OK; -} - -/****************************************************************************** - * Storage32Impl_GetNextExtendedBlock - * - * Given an extended block this method will return the next extended block. - * - * NOTES: - * The last ULONG of an extended block is the block index of the next - * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the - * depot. - * - * Return values: - * - The index of the next extended block - * - BLOCK_UNUSED: there is no next extended block. - * - Any other return values denotes failure. - */ -ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex) -{ - ULONG nextBlockIndex = BLOCK_SPECIAL; - ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG); - void* depotBuffer; - - depotBuffer = StorageImpl_GetROBigBlock(This, blockIndex); - - if (depotBuffer!=0) - { - StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex); - - StorageImpl_ReleaseBigBlock(This, depotBuffer); - } - - return nextBlockIndex; -} - -/****************************************************************************** - * Storage32Impl_SetNextBlockInChain - * - * This method will write the index of the specified block's next block - * in the big block depot. - * - * For example: to create the chain 3 -> 1 -> 7 -> End of Chain - * do the following - * - * Storage32Impl_SetNextBlockInChain(This, 3, 1); - * Storage32Impl_SetNextBlockInChain(This, 1, 7); - * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN); - * - */ -void StorageImpl_SetNextBlockInChain( - StorageImpl* This, - ULONG blockIndex, - ULONG nextBlock) -{ - ULONG offsetInDepot = blockIndex * sizeof (ULONG); - ULONG depotBlockCount = offsetInDepot / This->bigBlockSize; - ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize; - ULONG depotBlockIndexPos; - void* depotBuffer; - - assert(depotBlockCount < This->bigBlockDepotCount); - assert(blockIndex != nextBlock); - - if (depotBlockCount < COUNT_BBDEPOTINHEADER) - { - depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount]; - } - else - { - /* - * We have to look in the extended depot. - */ - depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount); - } - - depotBuffer = StorageImpl_GetBigBlock(This, depotBlockIndexPos); - - if (depotBuffer!=0) - { - StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock); - StorageImpl_ReleaseBigBlock(This, depotBuffer); - } - - /* - * Update the cached block depot, if necessary. - */ - if (depotBlockCount == This->indexBlockDepotCached) - { - This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock; - } -} - -/****************************************************************************** - * Storage32Impl_LoadFileHeader - * - * This method will read in the file header, i.e. big block index -1. - */ -HRESULT StorageImpl_LoadFileHeader( - StorageImpl* This) -{ - HRESULT hr = STG_E_FILENOTFOUND; - void* headerBigBlock = NULL; - int index; - - /* - * Get a pointer to the big block of data containing the header. - */ - headerBigBlock = StorageImpl_GetROBigBlock(This, -1); - - /* - * Extract the information from the header. - */ - if (headerBigBlock!=0) - { - /* - * Check for the "magic number" signature and return an error if it is not - * found. - */ - if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0) - { - StorageImpl_ReleaseBigBlock(This, headerBigBlock); - return STG_E_OLDFORMAT; - } - - if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0) - { - StorageImpl_ReleaseBigBlock(This, headerBigBlock); - return STG_E_INVALIDHEADER; - } - - StorageUtl_ReadWord( - headerBigBlock, - OFFSET_BIGBLOCKSIZEBITS, - &This->bigBlockSizeBits); - - StorageUtl_ReadWord( - headerBigBlock, - OFFSET_SMALLBLOCKSIZEBITS, - &This->smallBlockSizeBits); - - StorageUtl_ReadDWord( - headerBigBlock, - OFFSET_BBDEPOTCOUNT, - &This->bigBlockDepotCount); - - StorageUtl_ReadDWord( - headerBigBlock, - OFFSET_ROOTSTARTBLOCK, - &This->rootStartBlock); - - StorageUtl_ReadDWord( - headerBigBlock, - OFFSET_SBDEPOTSTART, - &This->smallBlockDepotStart); - - StorageUtl_ReadDWord( - headerBigBlock, - OFFSET_EXTBBDEPOTSTART, - &This->extBigBlockDepotStart); - - StorageUtl_ReadDWord( - headerBigBlock, - OFFSET_EXTBBDEPOTCOUNT, - &This->extBigBlockDepotCount); - - for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++) - { - StorageUtl_ReadDWord( - headerBigBlock, - OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index), - &(This->bigBlockDepotStart[index])); - } - - /* - * Make the bitwise arithmetic to get the size of the blocks in bytes. - */ - if ((1 << 2) == 4) - { - This->bigBlockSize = 0x000000001 << (DWORD)This->bigBlockSizeBits; - This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits; - } - else - { - This->bigBlockSize = 0x000000001 >> (DWORD)This->bigBlockSizeBits; - This->smallBlockSize = 0x000000001 >> (DWORD)This->smallBlockSizeBits; - } - - /* - * Right now, the code is making some assumptions about the size of the - * blocks, just make sure they are what we're expecting. - */ - if (This->bigBlockSize != DEF_BIG_BLOCK_SIZE || - This->smallBlockSize != DEF_SMALL_BLOCK_SIZE) - { - WARN("Broken OLE storage file\n"); - hr = STG_E_INVALIDHEADER; - } - else - hr = S_OK; - - /* - * Release the block. - */ - StorageImpl_ReleaseBigBlock(This, headerBigBlock); - } - - return hr; -} - -/****************************************************************************** - * Storage32Impl_SaveFileHeader - * - * This method will save to the file the header, i.e. big block -1. - */ -void StorageImpl_SaveFileHeader( - StorageImpl* This) -{ - BYTE headerBigBlock[BIG_BLOCK_SIZE]; - int index; - BOOL success; - - /* - * Get a pointer to the big block of data containing the header. - */ - success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock); - - /* - * If the block read failed, the file is probably new. - */ - if (!success) - { - /* - * Initialize for all unknown fields. - */ - memset(headerBigBlock, 0, BIG_BLOCK_SIZE); - - /* - * Initialize the magic number. - */ - memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic)); - - /* - * And a bunch of things we don't know what they mean - */ - StorageUtl_WriteWord(headerBigBlock, 0x18, 0x3b); - StorageUtl_WriteWord(headerBigBlock, 0x1a, 0x3); - StorageUtl_WriteWord(headerBigBlock, 0x1c, (WORD)-2); - StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000); - } - - /* - * Write the information to the header. - */ - StorageUtl_WriteWord( - headerBigBlock, - OFFSET_BIGBLOCKSIZEBITS, - This->bigBlockSizeBits); - - StorageUtl_WriteWord( - headerBigBlock, - OFFSET_SMALLBLOCKSIZEBITS, - This->smallBlockSizeBits); - - StorageUtl_WriteDWord( - headerBigBlock, - OFFSET_BBDEPOTCOUNT, - This->bigBlockDepotCount); - - StorageUtl_WriteDWord( - headerBigBlock, - OFFSET_ROOTSTARTBLOCK, - This->rootStartBlock); - - StorageUtl_WriteDWord( - headerBigBlock, - OFFSET_SBDEPOTSTART, - This->smallBlockDepotStart); - - StorageUtl_WriteDWord( - headerBigBlock, - OFFSET_SBDEPOTCOUNT, - This->smallBlockDepotChain ? - BlockChainStream_GetCount(This->smallBlockDepotChain) : 0); - - StorageUtl_WriteDWord( - headerBigBlock, - OFFSET_EXTBBDEPOTSTART, - This->extBigBlockDepotStart); - - StorageUtl_WriteDWord( - headerBigBlock, - OFFSET_EXTBBDEPOTCOUNT, - This->extBigBlockDepotCount); - - for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++) - { - StorageUtl_WriteDWord( - headerBigBlock, - OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index), - (This->bigBlockDepotStart[index])); - } - - /* - * Write the big block back to the file. - */ - StorageImpl_WriteBigBlock(This, -1, headerBigBlock); -} - -/****************************************************************************** - * Storage32Impl_ReadProperty - * - * This method will read the specified property from the property chain. - */ -BOOL StorageImpl_ReadProperty( - StorageImpl* This, - ULONG index, - StgProperty* buffer) -{ - BYTE currentProperty[PROPSET_BLOCK_SIZE]; - ULARGE_INTEGER offsetInPropSet; - BOOL readSuccessful; - ULONG bytesRead; - - offsetInPropSet.u.HighPart = 0; - offsetInPropSet.u.LowPart = index * PROPSET_BLOCK_SIZE; - - readSuccessful = BlockChainStream_ReadAt( - This->rootBlockChain, - offsetInPropSet, - PROPSET_BLOCK_SIZE, - currentProperty, - &bytesRead); - - if (readSuccessful) - { - /* replace the name of root entry (often "Root Entry") by the file name */ - WCHAR *propName = (index == This->base.rootPropertySetIndex) ? - This->filename : (WCHAR *)currentProperty+OFFSET_PS_NAME; - - memset(buffer->name, 0, sizeof(buffer->name)); - memcpy( - buffer->name, - propName, - PROPERTY_NAME_BUFFER_LEN ); - TRACE("storage name: %s\n", debugstr_w(buffer->name)); - - memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1); - - StorageUtl_ReadWord( - currentProperty, - OFFSET_PS_NAMELENGTH, - &buffer->sizeOfNameString); - - StorageUtl_ReadDWord( - currentProperty, - OFFSET_PS_PREVIOUSPROP, - &buffer->previousProperty); - - StorageUtl_ReadDWord( - currentProperty, - OFFSET_PS_NEXTPROP, - &buffer->nextProperty); - - StorageUtl_ReadDWord( - currentProperty, - OFFSET_PS_DIRPROP, - &buffer->dirProperty); - - StorageUtl_ReadGUID( - currentProperty, - OFFSET_PS_GUID, - &buffer->propertyUniqueID); - - StorageUtl_ReadDWord( - currentProperty, - OFFSET_PS_TSS1, - &buffer->timeStampS1); - - StorageUtl_ReadDWord( - currentProperty, - OFFSET_PS_TSD1, - &buffer->timeStampD1); - - StorageUtl_ReadDWord( - currentProperty, - OFFSET_PS_TSS2, - &buffer->timeStampS2); - - StorageUtl_ReadDWord( - currentProperty, - OFFSET_PS_TSD2, - &buffer->timeStampD2); - - StorageUtl_ReadDWord( - currentProperty, - OFFSET_PS_STARTBLOCK, - &buffer->startingBlock); - - StorageUtl_ReadDWord( - currentProperty, - OFFSET_PS_SIZE, - &buffer->size.u.LowPart); - - buffer->size.u.HighPart = 0; - } - - return readSuccessful; -} - -/********************************************************************* - * Write the specified property into the property chain - */ -BOOL StorageImpl_WriteProperty( - StorageImpl* This, - ULONG index, - StgProperty* buffer) -{ - BYTE currentProperty[PROPSET_BLOCK_SIZE]; - ULARGE_INTEGER offsetInPropSet; - BOOL writeSuccessful; - ULONG bytesWritten; - - offsetInPropSet.u.HighPart = 0; - offsetInPropSet.u.LowPart = index * PROPSET_BLOCK_SIZE; - - memset(currentProperty, 0, PROPSET_BLOCK_SIZE); - - memcpy( - currentProperty + OFFSET_PS_NAME, - buffer->name, - PROPERTY_NAME_BUFFER_LEN ); - - memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1); - - StorageUtl_WriteWord( - currentProperty, - OFFSET_PS_NAMELENGTH, - buffer->sizeOfNameString); - - StorageUtl_WriteDWord( - currentProperty, - OFFSET_PS_PREVIOUSPROP, - buffer->previousProperty); - - StorageUtl_WriteDWord( - currentProperty, - OFFSET_PS_NEXTPROP, - buffer->nextProperty); - - StorageUtl_WriteDWord( - currentProperty, - OFFSET_PS_DIRPROP, - buffer->dirProperty); - - StorageUtl_WriteGUID( - currentProperty, - OFFSET_PS_GUID, - &buffer->propertyUniqueID); - - StorageUtl_WriteDWord( - currentProperty, - OFFSET_PS_TSS1, - buffer->timeStampS1); - - StorageUtl_WriteDWord( - currentProperty, - OFFSET_PS_TSD1, - buffer->timeStampD1); - - StorageUtl_WriteDWord( - currentProperty, - OFFSET_PS_TSS2, - buffer->timeStampS2); - - StorageUtl_WriteDWord( - currentProperty, - OFFSET_PS_TSD2, - buffer->timeStampD2); - - StorageUtl_WriteDWord( - currentProperty, - OFFSET_PS_STARTBLOCK, - buffer->startingBlock); - - StorageUtl_WriteDWord( - currentProperty, - OFFSET_PS_SIZE, - buffer->size.u.LowPart); - - writeSuccessful = BlockChainStream_WriteAt(This->rootBlockChain, - offsetInPropSet, - PROPSET_BLOCK_SIZE, - currentProperty, - &bytesWritten); - return writeSuccessful; -} - -BOOL StorageImpl_ReadBigBlock( - StorageImpl* This, - ULONG blockIndex, - void* buffer) -{ - void* bigBlockBuffer; - - bigBlockBuffer = StorageImpl_GetROBigBlock(This, blockIndex); - - if (bigBlockBuffer!=0) - { - memcpy(buffer, bigBlockBuffer, This->bigBlockSize); - - StorageImpl_ReleaseBigBlock(This, bigBlockBuffer); - - return TRUE; - } - - return FALSE; -} - -BOOL StorageImpl_WriteBigBlock( - StorageImpl* This, - ULONG blockIndex, - void* buffer) -{ - void* bigBlockBuffer; - - bigBlockBuffer = StorageImpl_GetBigBlock(This, blockIndex); - - if (bigBlockBuffer!=0) - { - memcpy(bigBlockBuffer, buffer, This->bigBlockSize); - - StorageImpl_ReleaseBigBlock(This, bigBlockBuffer); - - return TRUE; - } - - return FALSE; -} - -void* StorageImpl_GetROBigBlock( - StorageImpl* This, - ULONG blockIndex) -{ - return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex); -} - -void* StorageImpl_GetBigBlock( - StorageImpl* This, - ULONG blockIndex) -{ - return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex); -} - -void StorageImpl_ReleaseBigBlock( - StorageImpl* This, - void* pBigBlock) -{ - BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock); -} - -/****************************************************************************** - * Storage32Impl_SmallBlocksToBigBlocks - * - * This method will convert a small block chain to a big block chain. - * The small block chain will be destroyed. - */ -BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks( - StorageImpl* This, - SmallBlockChainStream** ppsbChain) -{ - ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN; - ULARGE_INTEGER size, offset; - ULONG cbRead, cbWritten, cbTotalRead, cbTotalWritten; - ULONG propertyIndex; - BOOL successRead, successWrite; - StgProperty chainProperty; - BYTE *buffer; - BlockChainStream *bbTempChain = NULL; - BlockChainStream *bigBlockChain = NULL; - - /* - * Create a temporary big block chain that doesn't have - * an associated property. This temporary chain will be - * used to copy data from small blocks to big blocks. - */ - bbTempChain = BlockChainStream_Construct(This, - &bbHeadOfChain, - PROPERTY_NULL); - if(!bbTempChain) return NULL; - /* - * Grow the big block chain. - */ - size = SmallBlockChainStream_GetSize(*ppsbChain); - BlockChainStream_SetSize(bbTempChain, size); - - /* - * Copy the contents of the small block chain to the big block chain - * by small block size increments. - */ - offset.u.LowPart = 0; - offset.u.HighPart = 0; - cbTotalRead = 0; - cbTotalWritten = 0; - - buffer = HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE); - do - { - successRead = SmallBlockChainStream_ReadAt(*ppsbChain, - offset, - DEF_SMALL_BLOCK_SIZE, - buffer, - &cbRead); - cbTotalRead += cbRead; - - successWrite = BlockChainStream_WriteAt(bbTempChain, - offset, - cbRead, - buffer, - &cbWritten); - cbTotalWritten += cbWritten; - - offset.u.LowPart += This->smallBlockSize; - - } while (successRead && successWrite); - HeapFree(GetProcessHeap(),0,buffer); - - assert(cbTotalRead == cbTotalWritten); - - /* - * Destroy the small block chain. - */ - propertyIndex = (*ppsbChain)->ownerPropertyIndex; - size.u.HighPart = 0; - size.u.LowPart = 0; - SmallBlockChainStream_SetSize(*ppsbChain, size); - SmallBlockChainStream_Destroy(*ppsbChain); - *ppsbChain = 0; - - /* - * Change the property information. This chain is now a big block chain - * and it doesn't reside in the small blocks chain anymore. - */ - StorageImpl_ReadProperty(This, propertyIndex, &chainProperty); - - chainProperty.startingBlock = bbHeadOfChain; - - StorageImpl_WriteProperty(This, propertyIndex, &chainProperty); - - /* - * Destroy the temporary propertyless big block chain. - * Create a new big block chain associated with this property. - */ - BlockChainStream_Destroy(bbTempChain); - bigBlockChain = BlockChainStream_Construct(This, - NULL, - propertyIndex); - - return bigBlockChain; -} - -void StorageInternalImpl_Destroy( StorageBaseImpl *iface) -{ - StorageInternalImpl* This = (StorageInternalImpl*) iface; - - StorageBaseImpl_Release((IStorage*)This->base.ancestorStorage); - HeapFree(GetProcessHeap(), 0, This); -} - -/****************************************************************************** -** -** Storage32InternalImpl_Commit -** -** The non-root storages cannot be opened in transacted mode thus this function -** does nothing. -*/ -HRESULT WINAPI StorageInternalImpl_Commit( - IStorage* iface, - DWORD grfCommitFlags) /* [in] */ -{ - return S_OK; -} - -/****************************************************************************** -** -** Storage32InternalImpl_Revert -** -** The non-root storages cannot be opened in transacted mode thus this function -** does nothing. -*/ -HRESULT WINAPI StorageInternalImpl_Revert( - IStorage* iface) -{ - return S_OK; -} - -void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This) -{ - IStorage_Release((IStorage*)This->parentStorage); - HeapFree(GetProcessHeap(), 0, This->stackToVisit); - HeapFree(GetProcessHeap(), 0, This); -} - -HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface( - IEnumSTATSTG* iface, - REFIID riid, - void** ppvObject) -{ - IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; - - /* - * Perform a sanity check on the parameters. - */ - if (ppvObject==0) - return E_INVALIDARG; - - /* - * Initialize the return parameter. - */ - *ppvObject = 0; - - /* - * Compare the riid with the interface IDs implemented by this object. - */ - if (IsEqualGUID(&IID_IUnknown, riid) || - IsEqualGUID(&IID_IStorage, riid)) - { - *ppvObject = (IEnumSTATSTG*)This; - IEnumSTATSTG_AddRef((IEnumSTATSTG*)This); - return S_OK; - } - - return E_NOINTERFACE; -} - -ULONG WINAPI IEnumSTATSTGImpl_AddRef( - IEnumSTATSTG* iface) -{ - IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; - return InterlockedIncrement(&This->ref); -} - -ULONG WINAPI IEnumSTATSTGImpl_Release( - IEnumSTATSTG* iface) -{ - IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; - - ULONG newRef; - - newRef = InterlockedDecrement(&This->ref); - - /* - * If the reference count goes down to 0, perform suicide. - */ - if (newRef==0) - { - IEnumSTATSTGImpl_Destroy(This); - } - - return newRef; -} - -HRESULT WINAPI IEnumSTATSTGImpl_Next( - IEnumSTATSTG* iface, - ULONG celt, - STATSTG* rgelt, - ULONG* pceltFetched) -{ - IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; - - StgProperty currentProperty; - STATSTG* currentReturnStruct = rgelt; - ULONG objectFetched = 0; - ULONG currentSearchNode; - - /* - * Perform a sanity check on the parameters. - */ - if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) ) - return E_INVALIDARG; - - /* - * To avoid the special case, get another pointer to a ULONG value if - * the caller didn't supply one. - */ - if (pceltFetched==0) - pceltFetched = &objectFetched; - - /* - * Start the iteration, we will iterate until we hit the end of the - * linked list or until we hit the number of items to iterate through - */ - *pceltFetched = 0; - - /* - * Start with the node at the top of the stack. - */ - currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); - - while ( ( *pceltFetched < celt) && - ( currentSearchNode!=PROPERTY_NULL) ) - { - /* - * Remove the top node from the stack - */ - IEnumSTATSTGImpl_PopSearchNode(This, TRUE); - - /* - * Read the property from the storage. - */ - StorageImpl_ReadProperty(This->parentStorage, - currentSearchNode, - ¤tProperty); - - /* - * Copy the information to the return buffer. - */ - StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct, - ¤tProperty, - STATFLAG_DEFAULT); - - /* - * Step to the next item in the iteration - */ - (*pceltFetched)++; - currentReturnStruct++; - - /* - * Push the next search node in the search stack. - */ - IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty); - - /* - * continue the iteration. - */ - currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); - } - - if (*pceltFetched == celt) - return S_OK; - - return S_FALSE; -} - - -HRESULT WINAPI IEnumSTATSTGImpl_Skip( - IEnumSTATSTG* iface, - ULONG celt) -{ - IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; - - StgProperty currentProperty; - ULONG objectFetched = 0; - ULONG currentSearchNode; - - /* - * Start with the node at the top of the stack. - */ - currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); - - while ( (objectFetched < celt) && - (currentSearchNode!=PROPERTY_NULL) ) - { - /* - * Remove the top node from the stack - */ - IEnumSTATSTGImpl_PopSearchNode(This, TRUE); - - /* - * Read the property from the storage. - */ - StorageImpl_ReadProperty(This->parentStorage, - currentSearchNode, - ¤tProperty); - - /* - * Step to the next item in the iteration - */ - objectFetched++; - - /* - * Push the next search node in the search stack. - */ - IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty); - - /* - * continue the iteration. - */ - currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); - } - - if (objectFetched == celt) - return S_OK; - - return S_FALSE; -} - -HRESULT WINAPI IEnumSTATSTGImpl_Reset( - IEnumSTATSTG* iface) -{ - IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; - - StgProperty rootProperty; - BOOL readSuccessful; - - /* - * Re-initialize the search stack to an empty stack - */ - This->stackSize = 0; - - /* - * Read the root property from the storage. - */ - readSuccessful = StorageImpl_ReadProperty( - This->parentStorage, - This->firstPropertyNode, - &rootProperty); - - if (readSuccessful) - { - assert(rootProperty.sizeOfNameString!=0); - - /* - * Push the search node in the search stack. - */ - IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty); - } - - return S_OK; -} - -HRESULT WINAPI IEnumSTATSTGImpl_Clone( - IEnumSTATSTG* iface, - IEnumSTATSTG** ppenum) -{ - IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; - - IEnumSTATSTGImpl* newClone; - - /* - * Perform a sanity check on the parameters. - */ - if (ppenum==0) - return E_INVALIDARG; - - newClone = IEnumSTATSTGImpl_Construct(This->parentStorage, - This->firstPropertyNode); - - - /* - * The new clone enumeration must point to the same current node as - * the ole one. - */ - newClone->stackSize = This->stackSize ; - newClone->stackMaxSize = This->stackMaxSize ; - newClone->stackToVisit = - HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize); - - memcpy( - newClone->stackToVisit, - This->stackToVisit, - sizeof(ULONG) * newClone->stackSize); - - *ppenum = (IEnumSTATSTG*)newClone; - - /* - * Don't forget to nail down a reference to the clone before - * returning it. - */ - IEnumSTATSTGImpl_AddRef(*ppenum); - - return S_OK; -} - -INT IEnumSTATSTGImpl_FindParentProperty( - IEnumSTATSTGImpl *This, - ULONG childProperty, - StgProperty *currentProperty, - ULONG *thisNodeId) -{ - ULONG currentSearchNode; - ULONG foundNode; - - /* - * To avoid the special case, get another pointer to a ULONG value if - * the caller didn't supply one. - */ - if (thisNodeId==0) - thisNodeId = &foundNode; - - /* - * Start with the node at the top of the stack. - */ - currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); - - - while (currentSearchNode!=PROPERTY_NULL) - { - /* - * Store the current node in the returned parameters - */ - *thisNodeId = currentSearchNode; - - /* - * Remove the top node from the stack - */ - IEnumSTATSTGImpl_PopSearchNode(This, TRUE); - - /* - * Read the property from the storage. - */ - StorageImpl_ReadProperty( - This->parentStorage, - currentSearchNode, - currentProperty); - - if (currentProperty->previousProperty == childProperty) - return PROPERTY_RELATION_PREVIOUS; - - else if (currentProperty->nextProperty == childProperty) - return PROPERTY_RELATION_NEXT; - - else if (currentProperty->dirProperty == childProperty) - return PROPERTY_RELATION_DIR; - - /* - * Push the next search node in the search stack. - */ - IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty); - - /* - * continue the iteration. - */ - currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); - } - - return PROPERTY_NULL; -} - -ULONG IEnumSTATSTGImpl_FindProperty( - IEnumSTATSTGImpl* This, - const OLECHAR* lpszPropName, - StgProperty* currentProperty) -{ - ULONG currentSearchNode; - - /* - * Start with the node at the top of the stack. - */ - currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); - - while (currentSearchNode!=PROPERTY_NULL) - { - /* - * Remove the top node from the stack - */ - IEnumSTATSTGImpl_PopSearchNode(This, TRUE); - - /* - * Read the property from the storage. - */ - StorageImpl_ReadProperty(This->parentStorage, - currentSearchNode, - currentProperty); - - if ( propertyNameCmp( - (const OLECHAR*)currentProperty->name, - (const OLECHAR*)lpszPropName) == 0) - return currentSearchNode; - - /* - * Push the next search node in the search stack. - */ - IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty); - - /* - * continue the iteration. - */ - currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); - } - - return PROPERTY_NULL; -} - -void IEnumSTATSTGImpl_PushSearchNode( - IEnumSTATSTGImpl* This, - ULONG nodeToPush) -{ - StgProperty rootProperty; - BOOL readSuccessful; - - /* - * First, make sure we're not trying to push an unexisting node. - */ - if (nodeToPush==PROPERTY_NULL) - return; - - /* - * First push the node to the stack - */ - if (This->stackSize == This->stackMaxSize) - { - This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT; - - This->stackToVisit = HeapReAlloc( - GetProcessHeap(), - 0, - This->stackToVisit, - sizeof(ULONG) * This->stackMaxSize); - } - - This->stackToVisit[This->stackSize] = nodeToPush; - This->stackSize++; - - /* - * Read the root property from the storage. - */ - readSuccessful = StorageImpl_ReadProperty( - This->parentStorage, - nodeToPush, - &rootProperty); - - if (readSuccessful) - { - assert(rootProperty.sizeOfNameString!=0); - - /* - * Push the previous search node in the search stack. - */ - IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty); - } -} - -ULONG IEnumSTATSTGImpl_PopSearchNode( - IEnumSTATSTGImpl* This, - BOOL remove) -{ - ULONG topNode; - - if (This->stackSize == 0) - return PROPERTY_NULL; - - topNode = This->stackToVisit[This->stackSize-1]; - - if (remove) - This->stackSize--; - - return topNode; -} - -/* - * Virtual function table for the IEnumSTATSTGImpl class. - */ -static IEnumSTATSTGVtbl IEnumSTATSTGImpl_Vtbl = -{ - IEnumSTATSTGImpl_QueryInterface, - IEnumSTATSTGImpl_AddRef, - IEnumSTATSTGImpl_Release, - IEnumSTATSTGImpl_Next, - IEnumSTATSTGImpl_Skip, - IEnumSTATSTGImpl_Reset, - IEnumSTATSTGImpl_Clone -}; - -/****************************************************************************** -** IEnumSTATSTGImpl implementation -*/ - -IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct( - StorageImpl* parentStorage, - ULONG firstPropertyNode) -{ - IEnumSTATSTGImpl* newEnumeration; - - newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl)); - - if (newEnumeration!=0) - { - /* - * Set-up the virtual function table and reference count. - */ - newEnumeration->lpVtbl = &IEnumSTATSTGImpl_Vtbl; - newEnumeration->ref = 0; - - /* - * We want to nail-down the reference to the storage in case the - * enumeration out-lives the storage in the client application. - */ - newEnumeration->parentStorage = parentStorage; - IStorage_AddRef((IStorage*)newEnumeration->parentStorage); - - newEnumeration->firstPropertyNode = firstPropertyNode; - - /* - * Initialize the search stack - */ - newEnumeration->stackSize = 0; - newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT; - newEnumeration->stackToVisit = - HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT); - - /* - * Make sure the current node of the iterator is the first one. - */ - IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration); - } - - return newEnumeration; -} - -/* - * Virtual function table for the Storage32InternalImpl class. - */ -static IStorageVtbl Storage32InternalImpl_Vtbl = -{ - StorageBaseImpl_QueryInterface, - StorageBaseImpl_AddRef, - StorageBaseImpl_Release, - StorageBaseImpl_CreateStream, - StorageBaseImpl_OpenStream, - StorageImpl_CreateStorage, - StorageBaseImpl_OpenStorage, - StorageImpl_CopyTo, - StorageImpl_MoveElementTo, - StorageInternalImpl_Commit, - StorageInternalImpl_Revert, - StorageBaseImpl_EnumElements, - StorageImpl_DestroyElement, - StorageBaseImpl_RenameElement, - StorageImpl_SetElementTimes, - StorageBaseImpl_SetClass, - StorageImpl_SetStateBits, - StorageBaseImpl_Stat -}; - -/****************************************************************************** -** Storage32InternalImpl implementation -*/ - -StorageInternalImpl* StorageInternalImpl_Construct( - StorageImpl* ancestorStorage, - DWORD openFlags, - ULONG rootPropertyIndex) -{ - StorageInternalImpl* newStorage; - - /* - * Allocate space for the new storage object - */ - newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl)); - - if (newStorage!=0) - { - memset(newStorage, 0, sizeof(StorageInternalImpl)); - - /* - * Initialize the virtual function table. - */ - newStorage->base.lpVtbl = &Storage32InternalImpl_Vtbl; - newStorage->base.v_destructor = &StorageInternalImpl_Destroy; - newStorage->base.openFlags = openFlags; - - /* - * Keep the ancestor storage pointer and nail a reference to it. - */ - newStorage->base.ancestorStorage = ancestorStorage; - StorageBaseImpl_AddRef((IStorage*)(newStorage->base.ancestorStorage)); - - /* - * Keep the index of the root property set for this storage, - */ - newStorage->base.rootPropertySetIndex = rootPropertyIndex; - - return newStorage; - } - - return 0; -} - -/****************************************************************************** -** StorageUtl implementation -*/ - -void StorageUtl_ReadWord(const BYTE* buffer, ULONG offset, WORD* value) -{ - WORD tmp; - - memcpy(&tmp, buffer+offset, sizeof(WORD)); - *value = le16toh(tmp); -} - -void StorageUtl_WriteWord(BYTE* buffer, ULONG offset, WORD value) -{ - value = htole16(value); - memcpy(buffer+offset, &value, sizeof(WORD)); -} - -void StorageUtl_ReadDWord(const BYTE* buffer, ULONG offset, DWORD* value) -{ - DWORD tmp; - - memcpy(&tmp, buffer+offset, sizeof(DWORD)); - *value = le32toh(tmp); -} - -void StorageUtl_WriteDWord(BYTE* buffer, ULONG offset, DWORD value) -{ - value = htole32(value); - memcpy(buffer+offset, &value, sizeof(DWORD)); -} - -void StorageUtl_ReadULargeInteger(const BYTE* buffer, ULONG offset, - ULARGE_INTEGER* value) -{ -#ifdef WORDS_BIGENDIAN - ULARGE_INTEGER tmp; - - memcpy(&tmp, buffer + offset, sizeof(ULARGE_INTEGER)); - value->u.LowPart = htole32(tmp.u.HighPart); - value->u.HighPart = htole32(tmp.u.LowPart); -#else - memcpy(value, buffer + offset, sizeof(ULARGE_INTEGER)); -#endif -} - -void StorageUtl_WriteULargeInteger(BYTE* buffer, ULONG offset, - const ULARGE_INTEGER *value) -{ -#ifdef WORDS_BIGENDIAN - ULARGE_INTEGER tmp; - - tmp.u.LowPart = htole32(value->u.HighPart); - tmp.u.HighPart = htole32(value->u.LowPart); - memcpy(buffer + offset, &tmp, sizeof(ULARGE_INTEGER)); -#else - memcpy(buffer + offset, value, sizeof(ULARGE_INTEGER)); -#endif -} - -void StorageUtl_ReadGUID(const BYTE* buffer, ULONG offset, GUID* value) -{ - StorageUtl_ReadDWord(buffer, offset, &(value->Data1)); - StorageUtl_ReadWord(buffer, offset+4, &(value->Data2)); - StorageUtl_ReadWord(buffer, offset+6, &(value->Data3)); - - memcpy(value->Data4, buffer+offset+8, sizeof(value->Data4)); -} - -void StorageUtl_WriteGUID(BYTE* buffer, ULONG offset, const GUID* value) -{ - StorageUtl_WriteDWord(buffer, offset, value->Data1); - StorageUtl_WriteWord(buffer, offset+4, value->Data2); - StorageUtl_WriteWord(buffer, offset+6, value->Data3); - - memcpy(buffer+offset+8, value->Data4, sizeof(value->Data4)); -} - -void StorageUtl_CopyPropertyToSTATSTG( - STATSTG* destination, - StgProperty* source, - int statFlags) -{ - /* - * The copy of the string occurs only when the flag is not set - */ - if( ((statFlags & STATFLAG_NONAME) != 0) || - (source->name == NULL) || - (source->name[0] == 0) ) - { - destination->pwcsName = 0; - } - else - { - destination->pwcsName = - CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR)); - - strcpyW((LPWSTR)destination->pwcsName, source->name); - } - - switch (source->propertyType) - { - case PROPTYPE_STORAGE: - case PROPTYPE_ROOT: - destination->type = STGTY_STORAGE; - break; - case PROPTYPE_STREAM: - destination->type = STGTY_STREAM; - break; - default: - destination->type = STGTY_STREAM; - break; - } - - destination->cbSize = source->size; -/* - currentReturnStruct->mtime = {0}; TODO - currentReturnStruct->ctime = {0}; - currentReturnStruct->atime = {0}; -*/ - destination->grfMode = 0; - destination->grfLocksSupported = 0; - destination->clsid = source->propertyUniqueID; - destination->grfStateBits = 0; - destination->reserved = 0; -} - -/****************************************************************************** -** BlockChainStream implementation -*/ - -BlockChainStream* BlockChainStream_Construct( - StorageImpl* parentStorage, - ULONG* headOfStreamPlaceHolder, - ULONG propertyIndex) -{ - BlockChainStream* newStream; - ULONG blockIndex; - - newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream)); - - newStream->parentStorage = parentStorage; - newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder; - newStream->ownerPropertyIndex = propertyIndex; - newStream->lastBlockNoInSequence = 0xFFFFFFFF; - newStream->tailIndex = BLOCK_END_OF_CHAIN; - newStream->numBlocks = 0; - - blockIndex = BlockChainStream_GetHeadOfChain(newStream); - - while (blockIndex != BLOCK_END_OF_CHAIN) - { - newStream->numBlocks++; - newStream->tailIndex = blockIndex; - - if(FAILED(StorageImpl_GetNextBlockInChain( - parentStorage, - blockIndex, - &blockIndex))) - { - HeapFree(GetProcessHeap(), 0, newStream); - return NULL; - } - } - - return newStream; -} - -void BlockChainStream_Destroy(BlockChainStream* This) -{ - HeapFree(GetProcessHeap(), 0, This); -} - -/****************************************************************************** - * BlockChainStream_GetHeadOfChain - * - * Returns the head of this stream chain. - * Some special chains don't have properties, their heads are kept in - * This->headOfStreamPlaceHolder. - * - */ -ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This) -{ - StgProperty chainProperty; - BOOL readSuccessful; - - if (This->headOfStreamPlaceHolder != 0) - return *(This->headOfStreamPlaceHolder); - - if (This->ownerPropertyIndex != PROPERTY_NULL) - { - readSuccessful = StorageImpl_ReadProperty( - This->parentStorage, - This->ownerPropertyIndex, - &chainProperty); - - if (readSuccessful) - { - return chainProperty.startingBlock; - } - } - - return BLOCK_END_OF_CHAIN; -} - -/****************************************************************************** - * BlockChainStream_GetCount - * - * Returns the number of blocks that comprises this chain. - * This is not the size of the stream as the last block may not be full! - * - */ -ULONG BlockChainStream_GetCount(BlockChainStream* This) -{ - ULONG blockIndex; - ULONG count = 0; - - blockIndex = BlockChainStream_GetHeadOfChain(This); - - while (blockIndex != BLOCK_END_OF_CHAIN) - { - count++; - - if(FAILED(StorageImpl_GetNextBlockInChain( - This->parentStorage, - blockIndex, - &blockIndex))) - return 0; - } - - return count; -} - -/****************************************************************************** - * BlockChainStream_ReadAt - * - * Reads a specified number of bytes from this chain at the specified offset. - * bytesRead may be NULL. - * Failure will be returned if the specified number of bytes has not been read. - */ -BOOL BlockChainStream_ReadAt(BlockChainStream* This, - ULARGE_INTEGER offset, - ULONG size, - void* buffer, - ULONG* bytesRead) -{ - ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize; - ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->bigBlockSize; - ULONG bytesToReadInBuffer; - ULONG blockIndex; - BYTE* bufferWalker; - BYTE* bigBlockBuffer; - - /* - * Find the first block in the stream that contains part of the buffer. - */ - if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) || - (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) || - (blockNoInSequence < This->lastBlockNoInSequence) ) - { - blockIndex = BlockChainStream_GetHeadOfChain(This); - This->lastBlockNoInSequence = blockNoInSequence; - } - else - { - ULONG temp = blockNoInSequence; - - blockIndex = This->lastBlockNoInSequenceIndex; - blockNoInSequence -= This->lastBlockNoInSequence; - This->lastBlockNoInSequence = temp; - } - - while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN)) - { - if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex))) - return FALSE; - blockNoInSequence--; - } - - This->lastBlockNoInSequenceIndex = blockIndex; - - /* - * Start reading the buffer. - */ - *bytesRead = 0; - bufferWalker = buffer; - - while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) ) - { - /* - * Calculate how many bytes we can copy from this big block. - */ - bytesToReadInBuffer = - min(This->parentStorage->bigBlockSize - offsetInBlock, size); - - /* - * Copy those bytes to the buffer - */ - bigBlockBuffer = - StorageImpl_GetROBigBlock(This->parentStorage, blockIndex); - - memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer); - - StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer); - - /* - * Step to the next big block. - */ - if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex))) - return FALSE; - - bufferWalker += bytesToReadInBuffer; - size -= bytesToReadInBuffer; - *bytesRead += bytesToReadInBuffer; - offsetInBlock = 0; /* There is no offset on the next block */ - - } - - return (size == 0); -} - -/****************************************************************************** - * BlockChainStream_WriteAt - * - * Writes the specified number of bytes to this chain at the specified offset. - * bytesWritten may be NULL. - * Will fail if not all specified number of bytes have been written. - */ -BOOL BlockChainStream_WriteAt(BlockChainStream* This, - ULARGE_INTEGER offset, - ULONG size, - const void* buffer, - ULONG* bytesWritten) -{ - ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize; - ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->bigBlockSize; - ULONG bytesToWrite; - ULONG blockIndex; - const BYTE* bufferWalker; - BYTE* bigBlockBuffer; - - /* - * Find the first block in the stream that contains part of the buffer. - */ - if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) || - (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) || - (blockNoInSequence < This->lastBlockNoInSequence) ) - { - blockIndex = BlockChainStream_GetHeadOfChain(This); - This->lastBlockNoInSequence = blockNoInSequence; - } - else - { - ULONG temp = blockNoInSequence; - - blockIndex = This->lastBlockNoInSequenceIndex; - blockNoInSequence -= This->lastBlockNoInSequence; - This->lastBlockNoInSequence = temp; - } - - while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN)) - { - if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, - &blockIndex))) - return FALSE; - blockNoInSequence--; - } - - This->lastBlockNoInSequenceIndex = blockIndex; - - /* - * Here, I'm casting away the constness on the buffer variable - * This is OK since we don't intend to modify that buffer. - */ - *bytesWritten = 0; - bufferWalker = (const BYTE*)buffer; - - while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) ) - { - /* - * Calculate how many bytes we can copy from this big block. - */ - bytesToWrite = - min(This->parentStorage->bigBlockSize - offsetInBlock, size); - - /* - * Copy those bytes to the buffer - */ - bigBlockBuffer = StorageImpl_GetBigBlock(This->parentStorage, blockIndex); - - memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite); - - StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer); - - /* - * Step to the next big block. - */ - if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, - &blockIndex))) - return FALSE; - bufferWalker += bytesToWrite; - size -= bytesToWrite; - *bytesWritten += bytesToWrite; - offsetInBlock = 0; /* There is no offset on the next block */ - } - - return (size == 0); -} - -/****************************************************************************** - * BlockChainStream_Shrink - * - * Shrinks this chain in the big block depot. - */ -BOOL BlockChainStream_Shrink(BlockChainStream* This, - ULARGE_INTEGER newSize) -{ - ULONG blockIndex, extraBlock; - ULONG numBlocks; - ULONG count = 1; - - /* - * Reset the last accessed block cache. - */ - This->lastBlockNoInSequence = 0xFFFFFFFF; - This->lastBlockNoInSequenceIndex = BLOCK_END_OF_CHAIN; - - /* - * Figure out how many blocks are needed to contain the new size - */ - numBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize; - - if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0) - numBlocks++; - - blockIndex = BlockChainStream_GetHeadOfChain(This); - - /* - * Go to the new end of chain - */ - while (count < numBlocks) - { - if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, - &blockIndex))) - return FALSE; - count++; - } - - /* Get the next block before marking the new end */ - if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, - &extraBlock))) - return FALSE; - - /* Mark the new end of chain */ - StorageImpl_SetNextBlockInChain( - This->parentStorage, - blockIndex, - BLOCK_END_OF_CHAIN); - - This->tailIndex = blockIndex; - This->numBlocks = numBlocks; - - /* - * Mark the extra blocks as free - */ - while (extraBlock != BLOCK_END_OF_CHAIN) - { - if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock, - &blockIndex))) - return FALSE; - StorageImpl_FreeBigBlock(This->parentStorage, extraBlock); - extraBlock = blockIndex; - } - - return TRUE; -} - -/****************************************************************************** - * BlockChainStream_Enlarge - * - * Grows this chain in the big block depot. - */ -BOOL BlockChainStream_Enlarge(BlockChainStream* This, - ULARGE_INTEGER newSize) -{ - ULONG blockIndex, currentBlock; - ULONG newNumBlocks; - ULONG oldNumBlocks = 0; - - blockIndex = BlockChainStream_GetHeadOfChain(This); - - /* - * Empty chain. Create the head. - */ - if (blockIndex == BLOCK_END_OF_CHAIN) - { - blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage); - StorageImpl_SetNextBlockInChain(This->parentStorage, - blockIndex, - BLOCK_END_OF_CHAIN); - - if (This->headOfStreamPlaceHolder != 0) - { - *(This->headOfStreamPlaceHolder) = blockIndex; - } - else - { - StgProperty chainProp; - assert(This->ownerPropertyIndex != PROPERTY_NULL); - - StorageImpl_ReadProperty( - This->parentStorage, - This->ownerPropertyIndex, - &chainProp); - - chainProp.startingBlock = blockIndex; - - StorageImpl_WriteProperty( - This->parentStorage, - This->ownerPropertyIndex, - &chainProp); - } - - This->tailIndex = blockIndex; - This->numBlocks = 1; - } - - /* - * Figure out how many blocks are needed to contain this stream - */ - newNumBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize; - - if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0) - newNumBlocks++; - - /* - * Go to the current end of chain - */ - if (This->tailIndex == BLOCK_END_OF_CHAIN) - { - currentBlock = blockIndex; - - while (blockIndex != BLOCK_END_OF_CHAIN) - { - This->numBlocks++; - currentBlock = blockIndex; - - if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock, - &blockIndex))) - return FALSE; - } - - This->tailIndex = currentBlock; - } - - currentBlock = This->tailIndex; - oldNumBlocks = This->numBlocks; - - /* - * Add new blocks to the chain - */ - if (oldNumBlocks < newNumBlocks) - { - while (oldNumBlocks < newNumBlocks) - { - blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage); - - StorageImpl_SetNextBlockInChain( - This->parentStorage, - currentBlock, - blockIndex); - - StorageImpl_SetNextBlockInChain( - This->parentStorage, - blockIndex, - BLOCK_END_OF_CHAIN); - - currentBlock = blockIndex; - oldNumBlocks++; - } - - This->tailIndex = blockIndex; - This->numBlocks = newNumBlocks; - } - - return TRUE; -} - -/****************************************************************************** - * BlockChainStream_SetSize - * - * Sets the size of this stream. The big block depot will be updated. - * The file will grow if we grow the chain. - * - * TODO: Free the actual blocks in the file when we shrink the chain. - * Currently, the blocks are still in the file. So the file size - * doesn't shrink even if we shrink streams. - */ -BOOL BlockChainStream_SetSize( - BlockChainStream* This, - ULARGE_INTEGER newSize) -{ - ULARGE_INTEGER size = BlockChainStream_GetSize(This); - - if (newSize.u.LowPart == size.u.LowPart) - return TRUE; - - if (newSize.u.LowPart < size.u.LowPart) - { - BlockChainStream_Shrink(This, newSize); - } - else - { - ULARGE_INTEGER fileSize = - BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile); - - ULONG diff = newSize.u.LowPart - size.u.LowPart; - - /* - * Make sure the file stays a multiple of blocksize - */ - if ((diff % This->parentStorage->bigBlockSize) != 0) - diff += (This->parentStorage->bigBlockSize - - (diff % This->parentStorage->bigBlockSize) ); - - fileSize.u.LowPart += diff; - BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize); - - BlockChainStream_Enlarge(This, newSize); - } - - return TRUE; -} - -/****************************************************************************** - * BlockChainStream_GetSize - * - * Returns the size of this chain. - * Will return the block count if this chain doesn't have a property. - */ -ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This) -{ - StgProperty chainProperty; - - if(This->headOfStreamPlaceHolder == NULL) - { - /* - * This chain is a data stream read the property and return - * the appropriate size - */ - StorageImpl_ReadProperty( - This->parentStorage, - This->ownerPropertyIndex, - &chainProperty); - - return chainProperty.size; - } - else - { - /* - * this chain is a chain that does not have a property, figure out the - * size by making the product number of used blocks times the - * size of them - */ - ULARGE_INTEGER result; - result.u.HighPart = 0; - - result.u.LowPart = - BlockChainStream_GetCount(This) * - This->parentStorage->bigBlockSize; - - return result; - } -} - -/****************************************************************************** -** SmallBlockChainStream implementation -*/ - -SmallBlockChainStream* SmallBlockChainStream_Construct( - StorageImpl* parentStorage, - ULONG propertyIndex) -{ - SmallBlockChainStream* newStream; - - newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream)); - - newStream->parentStorage = parentStorage; - newStream->ownerPropertyIndex = propertyIndex; - - return newStream; -} - -void SmallBlockChainStream_Destroy( - SmallBlockChainStream* This) -{ - HeapFree(GetProcessHeap(), 0, This); -} - -/****************************************************************************** - * SmallBlockChainStream_GetHeadOfChain - * - * Returns the head of this chain of small blocks. - */ -ULONG SmallBlockChainStream_GetHeadOfChain( - SmallBlockChainStream* This) -{ - StgProperty chainProperty; - BOOL readSuccessful; - - if (This->ownerPropertyIndex) - { - readSuccessful = StorageImpl_ReadProperty( - This->parentStorage, - This->ownerPropertyIndex, - &chainProperty); - - if (readSuccessful) - { - return chainProperty.startingBlock; - } - - } - - return BLOCK_END_OF_CHAIN; -} - -/****************************************************************************** - * SmallBlockChainStream_GetNextBlockInChain - * - * Returns the index of the next small block in this chain. - * - * Return Values: - * - BLOCK_END_OF_CHAIN: end of this chain - * - BLOCK_UNUSED: small block 'blockIndex' is free - */ -HRESULT SmallBlockChainStream_GetNextBlockInChain( - SmallBlockChainStream* This, - ULONG blockIndex, - ULONG* nextBlockInChain) -{ - ULARGE_INTEGER offsetOfBlockInDepot; - DWORD buffer; - ULONG bytesRead; - BOOL success; - - *nextBlockInChain = BLOCK_END_OF_CHAIN; - - offsetOfBlockInDepot.u.HighPart = 0; - offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG); - - /* - * Read those bytes in the buffer from the small block file. - */ - success = BlockChainStream_ReadAt( - This->parentStorage->smallBlockDepotChain, - offsetOfBlockInDepot, - sizeof(DWORD), - &buffer, - &bytesRead); - - if (success) - { - StorageUtl_ReadDWord((BYTE *)&buffer, 0, nextBlockInChain); - return S_OK; - } - - return STG_E_READFAULT; -} - -/****************************************************************************** - * SmallBlockChainStream_SetNextBlockInChain - * - * Writes the index of the next block of the specified block in the small - * block depot. - * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock. - * To flag a block as free use BLOCK_UNUSED as nextBlock. - */ -void SmallBlockChainStream_SetNextBlockInChain( - SmallBlockChainStream* This, - ULONG blockIndex, - ULONG nextBlock) -{ - ULARGE_INTEGER offsetOfBlockInDepot; - DWORD buffer; - ULONG bytesWritten; - - offsetOfBlockInDepot.u.HighPart = 0; - offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG); - - StorageUtl_WriteDWord((BYTE *)&buffer, 0, nextBlock); - - /* - * Read those bytes in the buffer from the small block file. - */ - BlockChainStream_WriteAt( - This->parentStorage->smallBlockDepotChain, - offsetOfBlockInDepot, - sizeof(DWORD), - &buffer, - &bytesWritten); -} - -/****************************************************************************** - * SmallBlockChainStream_FreeBlock - * - * Flag small block 'blockIndex' as free in the small block depot. - */ -void SmallBlockChainStream_FreeBlock( - SmallBlockChainStream* This, - ULONG blockIndex) -{ - SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED); -} - -/****************************************************************************** - * SmallBlockChainStream_GetNextFreeBlock - * - * Returns the index of a free small block. The small block depot will be - * enlarged if necessary. The small block chain will also be enlarged if - * necessary. - */ -ULONG SmallBlockChainStream_GetNextFreeBlock( - SmallBlockChainStream* This) -{ - ULARGE_INTEGER offsetOfBlockInDepot; - DWORD buffer; - ULONG bytesRead; - ULONG blockIndex = 0; - ULONG nextBlockIndex = BLOCK_END_OF_CHAIN; - BOOL success = TRUE; - ULONG smallBlocksPerBigBlock; - - offsetOfBlockInDepot.u.HighPart = 0; - - /* - * Scan the small block depot for a free block - */ - while (nextBlockIndex != BLOCK_UNUSED) - { - offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG); - - success = BlockChainStream_ReadAt( - This->parentStorage->smallBlockDepotChain, - offsetOfBlockInDepot, - sizeof(DWORD), - &buffer, - &bytesRead); - - /* - * If we run out of space for the small block depot, enlarge it - */ - if (success) - { - StorageUtl_ReadDWord((BYTE *)&buffer, 0, &nextBlockIndex); - - if (nextBlockIndex != BLOCK_UNUSED) - blockIndex++; - } - else - { - ULONG count = - BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain); - - ULONG sbdIndex = This->parentStorage->smallBlockDepotStart; - ULONG nextBlock, newsbdIndex; - BYTE* smallBlockDepot; - - nextBlock = sbdIndex; - while (nextBlock != BLOCK_END_OF_CHAIN) - { - sbdIndex = nextBlock; - StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex, &nextBlock); - } - - newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage); - if (sbdIndex != BLOCK_END_OF_CHAIN) - StorageImpl_SetNextBlockInChain( - This->parentStorage, - sbdIndex, - newsbdIndex); - - StorageImpl_SetNextBlockInChain( - This->parentStorage, - newsbdIndex, - BLOCK_END_OF_CHAIN); - - /* - * Initialize all the small blocks to free - */ - smallBlockDepot = - StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex); - - memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize); - StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot); - - if (count == 0) - { - /* - * We have just created the small block depot. - */ - StgProperty rootProp; - ULONG sbStartIndex; - - /* - * Save it in the header - */ - This->parentStorage->smallBlockDepotStart = newsbdIndex; - StorageImpl_SaveFileHeader(This->parentStorage); - - /* - * And allocate the first big block that will contain small blocks - */ - sbStartIndex = - StorageImpl_GetNextFreeBigBlock(This->parentStorage); - - StorageImpl_SetNextBlockInChain( - This->parentStorage, - sbStartIndex, - BLOCK_END_OF_CHAIN); - - StorageImpl_ReadProperty( - This->parentStorage, - This->parentStorage->base.rootPropertySetIndex, - &rootProp); - - rootProp.startingBlock = sbStartIndex; - rootProp.size.u.HighPart = 0; - rootProp.size.u.LowPart = This->parentStorage->bigBlockSize; - - StorageImpl_WriteProperty( - This->parentStorage, - This->parentStorage->base.rootPropertySetIndex, - &rootProp); - } - } - } - - smallBlocksPerBigBlock = - This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize; - - /* - * Verify if we have to allocate big blocks to contain small blocks - */ - if (blockIndex % smallBlocksPerBigBlock == 0) - { - StgProperty rootProp; - ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1; - - StorageImpl_ReadProperty( - This->parentStorage, - This->parentStorage->base.rootPropertySetIndex, - &rootProp); - - if (rootProp.size.u.LowPart < - (blocksRequired * This->parentStorage->bigBlockSize)) - { - rootProp.size.u.LowPart += This->parentStorage->bigBlockSize; - - BlockChainStream_SetSize( - This->parentStorage->smallBlockRootChain, - rootProp.size); - - StorageImpl_WriteProperty( - This->parentStorage, - This->parentStorage->base.rootPropertySetIndex, - &rootProp); - } - } - - return blockIndex; -} - -/****************************************************************************** - * SmallBlockChainStream_ReadAt - * - * Reads a specified number of bytes from this chain at the specified offset. - * bytesRead may be NULL. - * Failure will be returned if the specified number of bytes has not been read. - */ -BOOL SmallBlockChainStream_ReadAt( - SmallBlockChainStream* This, - ULARGE_INTEGER offset, - ULONG size, - void* buffer, - ULONG* bytesRead) -{ - ULARGE_INTEGER offsetInBigBlockFile; - ULONG blockNoInSequence = - offset.u.LowPart / This->parentStorage->smallBlockSize; - - ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize; - ULONG bytesToReadInBuffer; - ULONG blockIndex; - ULONG bytesReadFromBigBlockFile; - BYTE* bufferWalker; - - /* - * This should never happen on a small block file. - */ - assert(offset.u.HighPart==0); - - /* - * Find the first block in the stream that contains part of the buffer. - */ - blockIndex = SmallBlockChainStream_GetHeadOfChain(This); - - while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN)) - { - if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, - &blockIndex))) - return FALSE; - blockNoInSequence--; - } - - /* - * Start reading the buffer. - */ - *bytesRead = 0; - bufferWalker = buffer; - - while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) ) - { - /* - * Calculate how many bytes we can copy from this small block. - */ - bytesToReadInBuffer = - min(This->parentStorage->smallBlockSize - offsetInBlock, size); - - /* - * Calculate the offset of the small block in the small block file. - */ - offsetInBigBlockFile.u.HighPart = 0; - offsetInBigBlockFile.u.LowPart = - blockIndex * This->parentStorage->smallBlockSize; - - offsetInBigBlockFile.u.LowPart += offsetInBlock; - - /* - * Read those bytes in the buffer from the small block file. - */ - BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain, - offsetInBigBlockFile, - bytesToReadInBuffer, - bufferWalker, - &bytesReadFromBigBlockFile); - - assert(bytesReadFromBigBlockFile == bytesToReadInBuffer); - - /* - * Step to the next big block. - */ - if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex))) - return FALSE; - bufferWalker += bytesToReadInBuffer; - size -= bytesToReadInBuffer; - *bytesRead += bytesToReadInBuffer; - offsetInBlock = 0; /* There is no offset on the next block */ - } - - return (size == 0); -} - -/****************************************************************************** - * SmallBlockChainStream_WriteAt - * - * Writes the specified number of bytes to this chain at the specified offset. - * bytesWritten may be NULL. - * Will fail if not all specified number of bytes have been written. - */ -BOOL SmallBlockChainStream_WriteAt( - SmallBlockChainStream* This, - ULARGE_INTEGER offset, - ULONG size, - const void* buffer, - ULONG* bytesWritten) -{ - ULARGE_INTEGER offsetInBigBlockFile; - ULONG blockNoInSequence = - offset.u.LowPart / This->parentStorage->smallBlockSize; - - ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize; - ULONG bytesToWriteInBuffer; - ULONG blockIndex; - ULONG bytesWrittenFromBigBlockFile; - const BYTE* bufferWalker; - - /* - * This should never happen on a small block file. - */ - assert(offset.u.HighPart==0); - - /* - * Find the first block in the stream that contains part of the buffer. - */ - blockIndex = SmallBlockChainStream_GetHeadOfChain(This); - - while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN)) - { - if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex))) - return FALSE; - blockNoInSequence--; - } - - /* - * Start writing the buffer. - * - * Here, I'm casting away the constness on the buffer variable - * This is OK since we don't intend to modify that buffer. - */ - *bytesWritten = 0; - bufferWalker = (const BYTE*)buffer; - while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) ) - { - /* - * Calculate how many bytes we can copy to this small block. - */ - bytesToWriteInBuffer = - min(This->parentStorage->smallBlockSize - offsetInBlock, size); - - /* - * Calculate the offset of the small block in the small block file. - */ - offsetInBigBlockFile.u.HighPart = 0; - offsetInBigBlockFile.u.LowPart = - blockIndex * This->parentStorage->smallBlockSize; - - offsetInBigBlockFile.u.LowPart += offsetInBlock; - - /* - * Write those bytes in the buffer to the small block file. - */ - BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain, - offsetInBigBlockFile, - bytesToWriteInBuffer, - bufferWalker, - &bytesWrittenFromBigBlockFile); - - assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer); - - /* - * Step to the next big block. - */ - if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, - &blockIndex))) - return FALSE; - bufferWalker += bytesToWriteInBuffer; - size -= bytesToWriteInBuffer; - *bytesWritten += bytesToWriteInBuffer; - offsetInBlock = 0; /* There is no offset on the next block */ - } - - return (size == 0); -} - -/****************************************************************************** - * SmallBlockChainStream_Shrink - * - * Shrinks this chain in the small block depot. - */ -BOOL SmallBlockChainStream_Shrink( - SmallBlockChainStream* This, - ULARGE_INTEGER newSize) -{ - ULONG blockIndex, extraBlock; - ULONG numBlocks; - ULONG count = 0; - - numBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize; - - if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0) - numBlocks++; - - blockIndex = SmallBlockChainStream_GetHeadOfChain(This); - - /* - * Go to the new end of chain - */ - while (count < numBlocks) - { - if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, - &blockIndex))) - return FALSE; - count++; - } - - /* - * If the count is 0, we have a special case, the head of the chain was - * just freed. - */ - if (count == 0) - { - StgProperty chainProp; - - StorageImpl_ReadProperty(This->parentStorage, - This->ownerPropertyIndex, - &chainProp); - - chainProp.startingBlock = BLOCK_END_OF_CHAIN; - - StorageImpl_WriteProperty(This->parentStorage, - This->ownerPropertyIndex, - &chainProp); - - /* - * We start freeing the chain at the head block. - */ - extraBlock = blockIndex; - } - else - { - /* Get the next block before marking the new end */ - if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, - &extraBlock))) - return FALSE; - - /* Mark the new end of chain */ - SmallBlockChainStream_SetNextBlockInChain( - This, - blockIndex, - BLOCK_END_OF_CHAIN); - } - - /* - * Mark the extra blocks as free - */ - while (extraBlock != BLOCK_END_OF_CHAIN) - { - if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, extraBlock, - &blockIndex))) - return FALSE; - SmallBlockChainStream_FreeBlock(This, extraBlock); - extraBlock = blockIndex; - } - - return TRUE; -} - -/****************************************************************************** - * SmallBlockChainStream_Enlarge - * - * Grows this chain in the small block depot. - */ -BOOL SmallBlockChainStream_Enlarge( - SmallBlockChainStream* This, - ULARGE_INTEGER newSize) -{ - ULONG blockIndex, currentBlock; - ULONG newNumBlocks; - ULONG oldNumBlocks = 0; - - blockIndex = SmallBlockChainStream_GetHeadOfChain(This); - - /* - * Empty chain - */ - if (blockIndex == BLOCK_END_OF_CHAIN) - { - - StgProperty chainProp; - - StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex, - &chainProp); - - chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This); - - StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex, - &chainProp); - - blockIndex = chainProp.startingBlock; - SmallBlockChainStream_SetNextBlockInChain( - This, - blockIndex, - BLOCK_END_OF_CHAIN); - } - - currentBlock = blockIndex; - - /* - * Figure out how many blocks are needed to contain this stream - */ - newNumBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize; - - if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0) - newNumBlocks++; - - /* - * Go to the current end of chain - */ - while (blockIndex != BLOCK_END_OF_CHAIN) - { - oldNumBlocks++; - currentBlock = blockIndex; - if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, currentBlock, &blockIndex))) - return FALSE; - } - - /* - * Add new blocks to the chain - */ - while (oldNumBlocks < newNumBlocks) - { - blockIndex = SmallBlockChainStream_GetNextFreeBlock(This); - SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex); - - SmallBlockChainStream_SetNextBlockInChain( - This, - blockIndex, - BLOCK_END_OF_CHAIN); - - currentBlock = blockIndex; - oldNumBlocks++; - } - - return TRUE; -} - -/****************************************************************************** - * SmallBlockChainStream_GetCount - * - * Returns the number of blocks that comprises this chain. - * This is not the size of this chain as the last block may not be full! - */ -ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This) -{ - ULONG blockIndex; - ULONG count = 0; - - blockIndex = SmallBlockChainStream_GetHeadOfChain(This); - - while (blockIndex != BLOCK_END_OF_CHAIN) - { - count++; - - if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex))) - return 0; - } - - return count; -} - -/****************************************************************************** - * SmallBlockChainStream_SetSize - * - * Sets the size of this stream. - * The file will grow if we grow the chain. - * - * TODO: Free the actual blocks in the file when we shrink the chain. - * Currently, the blocks are still in the file. So the file size - * doesn't shrink even if we shrink streams. - */ -BOOL SmallBlockChainStream_SetSize( - SmallBlockChainStream* This, - ULARGE_INTEGER newSize) -{ - ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This); - - if (newSize.u.LowPart == size.u.LowPart) - return TRUE; - - if (newSize.u.LowPart < size.u.LowPart) - { - SmallBlockChainStream_Shrink(This, newSize); - } - else - { - SmallBlockChainStream_Enlarge(This, newSize); - } - - return TRUE; -} - -/****************************************************************************** - * SmallBlockChainStream_GetSize - * - * Returns the size of this chain. - */ -ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This) -{ - StgProperty chainProperty; - - StorageImpl_ReadProperty( - This->parentStorage, - This->ownerPropertyIndex, - &chainProperty); - - return chainProperty.size; -} - -/****************************************************************************** - * StgCreateDocfile [OLE32.@] - */ -HRESULT WINAPI StgCreateDocfile( - LPCOLESTR pwcsName, - DWORD grfMode, - DWORD reserved, - IStorage **ppstgOpen) -{ - StorageImpl* newStorage = 0; - HANDLE hFile = INVALID_HANDLE_VALUE; - HRESULT hr = STG_E_INVALIDFLAG; - DWORD shareMode; - DWORD accessMode; - DWORD creationMode; - DWORD fileAttributes; - WCHAR tempFileName[MAX_PATH]; - - TRACE("(%s, %lx, %ld, %p)\n", - debugstr_w(pwcsName), grfMode, - reserved, ppstgOpen); - - /* - * Validate the parameters - */ - if (ppstgOpen == 0) - return STG_E_INVALIDPOINTER; - if (reserved != 0) - return STG_E_INVALIDPARAMETER; - - /* - * Validate the STGM flags - */ - if ( FAILED( validateSTGM(grfMode) )) - goto end; - - /* StgCreateDocFile always opens for write */ - switch(STGM_ACCESS_MODE(grfMode)) - { - case STGM_WRITE: - case STGM_READWRITE: - break; - default: - goto end; - } - - /* can't share write */ - switch(STGM_SHARE_MODE(grfMode)) - { - case STGM_SHARE_EXCLUSIVE: - case STGM_SHARE_DENY_WRITE: - break; - default: - goto end; - } - - /* shared reading requires transacted mode */ - if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE && - !(grfMode&STGM_TRANSACTED) ) - goto end; - - /* - * Generate a unique name. - */ - if (pwcsName == 0) - { - WCHAR tempPath[MAX_PATH]; - static const WCHAR prefix[] = { 'S', 'T', 'O', 0 }; - - if (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE) - goto end; - - memset(tempPath, 0, sizeof(tempPath)); - memset(tempFileName, 0, sizeof(tempFileName)); - - if ((GetTempPathW(MAX_PATH, tempPath)) == 0 ) - tempPath[0] = '.'; - - if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0) - pwcsName = tempFileName; - else - { - hr = STG_E_INSUFFICIENTMEMORY; - goto end; - } - - creationMode = TRUNCATE_EXISTING; - } - else - { - creationMode = GetCreationModeFromSTGM(grfMode); - } - - /* - * Interpret the STGM value grfMode - */ - shareMode = GetShareModeFromSTGM(grfMode); - accessMode = GetAccessModeFromSTGM(grfMode); - - if (grfMode & STGM_DELETEONRELEASE) - fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE; - else - fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS; - - if (grfMode & STGM_TRANSACTED) - FIXME("Transacted mode not implemented.\n"); - - /* - * Initialize the "out" parameter. - */ - *ppstgOpen = 0; - - hFile = CreateFileW(pwcsName, - accessMode, - shareMode, - NULL, - creationMode, - fileAttributes, - 0); - - if (hFile == INVALID_HANDLE_VALUE) - { - if(GetLastError() == ERROR_FILE_EXISTS) - hr = STG_E_FILEALREADYEXISTS; - else - hr = E_FAIL; - goto end; - } - - /* - * Allocate and initialize the new IStorage32object. - */ - newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl)); - - if (newStorage == 0) - { - hr = STG_E_INSUFFICIENTMEMORY; - goto end; - } - - hr = StorageImpl_Construct( - newStorage, - hFile, - pwcsName, - NULL, - grfMode, - TRUE, - TRUE); - - if (FAILED(hr)) - { - HeapFree(GetProcessHeap(), 0, newStorage); - goto end; - } - - /* - * Get an "out" pointer for the caller. - */ - hr = StorageBaseImpl_QueryInterface( - (IStorage*)newStorage, - (REFIID)&IID_IStorage, - (void**)ppstgOpen); -end: - TRACE("<-- %p r = %08lx\n", *ppstgOpen, hr); - - return hr; -} - -/****************************************************************************** - * StgCreateStorageEx [OLE32.@] - */ -HRESULT WINAPI StgCreateStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen) -{ - TRACE("(%s, %lx, %lx, %lx, %p, %p, %p, %p)\n", debugstr_w(pwcsName), - grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen); - - if (stgfmt != STGFMT_FILE && grfAttrs != 0) - { - ERR("grfAttrs must be 0 if stgfmt != STGFMT_FILE\n"); - return STG_E_INVALIDPARAMETER; - } - - if (stgfmt != STGFMT_FILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING) - { - ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_FILE\n"); - return STG_E_INVALIDPARAMETER; - } - - if (stgfmt == STGFMT_FILE) - { - ERR("Cannot use STGFMT_FILE - this is NTFS only\n"); - return STG_E_INVALIDPARAMETER; - } - - if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE) - { - FIXME("Stub: calling StgCreateDocfile, but ignoring pStgOptions and grfAttrs\n"); - return StgCreateDocfile(pwcsName, grfMode, 0, (IStorage **)ppObjectOpen); - } - - ERR("Invalid stgfmt argument\n"); - return STG_E_INVALIDPARAMETER; -} - -/****************************************************************************** - * StgCreatePropSetStg [OLE32.@] - */ -HRESULT WINAPI StgCreatePropSetStg(IStorage *pstg, DWORD reserved, - IPropertySetStorage **ppPropSetStg) -{ - HRESULT hr; - - TRACE("(%p, 0x%lx, %p): stub\n", pstg, reserved, ppPropSetStg); - if (reserved) - hr = STG_E_INVALIDPARAMETER; - else - hr = StorageBaseImpl_QueryInterface(pstg, &IID_IPropertySetStorage, - (void**)ppPropSetStg); - return hr; -} - -/****************************************************************************** - * StgOpenStorageEx [OLE32.@] - */ -HRESULT WINAPI StgOpenStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen) -{ - TRACE("(%s, %lx, %lx, %lx, %p, %p, %p, %p)\n", debugstr_w(pwcsName), - grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen); - - if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0) - { - ERR("grfAttrs must be 0 if stgfmt != STGFMT_DOCFILE\n"); - return STG_E_INVALIDPARAMETER; - } - - if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING) - { - ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_DOCFILE\n"); - return STG_E_INVALIDPARAMETER; - } - - if (stgfmt == STGFMT_FILE) - { - ERR("Cannot use STGFMT_FILE - this is NTFS only\n"); - return STG_E_INVALIDPARAMETER; - } - - if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE || stgfmt == STGFMT_ANY) - { - if (stgfmt == STGFMT_ANY) - WARN("STGFMT_ANY assuming storage\n"); - FIXME("Stub: calling StgOpenStorage, but ignoring pStgOptions and grfAttrs\n"); - return StgOpenStorage(pwcsName, NULL, grfMode, (SNB)NULL, 0, (IStorage **)ppObjectOpen); - } - - ERR("Invalid stgfmt argument\n"); - return STG_E_INVALIDPARAMETER; -} - - -/****************************************************************************** - * StgOpenStorage [OLE32.@] - */ -HRESULT WINAPI StgOpenStorage( - const OLECHAR *pwcsName, - IStorage *pstgPriority, - DWORD grfMode, - SNB snbExclude, - DWORD reserved, - IStorage **ppstgOpen) -{ - StorageImpl* newStorage = 0; - HRESULT hr = S_OK; - HANDLE hFile = 0; - DWORD shareMode; - DWORD accessMode; - WCHAR fullname[MAX_PATH]; - DWORD length; - - TRACE("(%s, %p, %lx, %p, %ld, %p)\n", - debugstr_w(pwcsName), pstgPriority, grfMode, - snbExclude, reserved, ppstgOpen); - - /* - * Perform sanity checks - */ - if (pwcsName == 0) - { - hr = STG_E_INVALIDNAME; - goto end; - } - - if (ppstgOpen == 0) - { - hr = STG_E_INVALIDPOINTER; - goto end; - } - - if (reserved) - { - hr = STG_E_INVALIDPARAMETER; - goto end; - } - - /* - * Validate the sharing mode - */ - switch(STGM_SHARE_MODE(grfMode)) - { - case STGM_SHARE_EXCLUSIVE: - case STGM_SHARE_DENY_WRITE: - break; - default: - hr = STG_E_INVALIDFLAG; - goto end; - } - - /* - * Validate the STGM flags - */ - if ( FAILED( validateSTGM(grfMode) ) || - (grfMode&STGM_CREATE)) - { - hr = STG_E_INVALIDFLAG; - goto end; - } - - /* shared reading requires transacted mode */ - if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE && - STGM_ACCESS_MODE(grfMode) == STGM_READWRITE && - !(grfMode&STGM_TRANSACTED) ) - { - hr = STG_E_INVALIDFLAG; - goto end; - } - - /* - * Interpret the STGM value grfMode - */ - shareMode = GetShareModeFromSTGM(grfMode); - accessMode = GetAccessModeFromSTGM(grfMode); - - /* - * Initialize the "out" parameter. - */ - *ppstgOpen = 0; - - hFile = CreateFileW( pwcsName, - accessMode, - shareMode, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, - 0); - - if (hFile==INVALID_HANDLE_VALUE) - { - DWORD last_error = GetLastError(); - - hr = E_FAIL; - - switch (last_error) - { - case ERROR_FILE_NOT_FOUND: - hr = STG_E_FILENOTFOUND; - break; - - case ERROR_PATH_NOT_FOUND: - hr = STG_E_PATHNOTFOUND; - break; - - case ERROR_ACCESS_DENIED: - case ERROR_WRITE_PROTECT: - hr = STG_E_ACCESSDENIED; - break; - - case ERROR_SHARING_VIOLATION: - hr = STG_E_SHAREVIOLATION; - break; - - default: - hr = E_FAIL; - } - - goto end; - } - - /* - * Refuse to open the file if it's too small to be a structured storage file - * FIXME: verify the file when reading instead of here - */ - length = GetFileSize(hFile, NULL); - if (length < 0x100) - { - CloseHandle(hFile); - hr = STG_E_FILEALREADYEXISTS; - goto end; - } - - /* - * Allocate and initialize the new IStorage32object. - */ - newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl)); - - if (newStorage == 0) - { - hr = STG_E_INSUFFICIENTMEMORY; - goto end; - } - - /* if the file's length was zero, initialize the storage */ - hr = StorageImpl_Construct( - newStorage, - hFile, - pwcsName, - NULL, - grfMode, - TRUE, - FALSE ); - - if (FAILED(hr)) - { - HeapFree(GetProcessHeap(), 0, newStorage); - /* - * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS - */ - if(hr == STG_E_INVALIDHEADER) - hr = STG_E_FILEALREADYEXISTS; - goto end; - } - - /* prepare the file name string given in lieu of the root property name */ - GetFullPathNameW(pwcsName, MAX_PATH, fullname, NULL); - memcpy(newStorage->filename, fullname, PROPERTY_NAME_BUFFER_LEN); - newStorage->filename[PROPERTY_NAME_BUFFER_LEN-1] = '\0'; - - /* - * Get an "out" pointer for the caller. - */ - hr = StorageBaseImpl_QueryInterface( - (IStorage*)newStorage, - (REFIID)&IID_IStorage, - (void**)ppstgOpen); - -end: - TRACE("<-- %08lx, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL); - return hr; -} - -/****************************************************************************** - * StgCreateDocfileOnILockBytes [OLE32.@] - */ -HRESULT WINAPI StgCreateDocfileOnILockBytes( - ILockBytes *plkbyt, - DWORD grfMode, - DWORD reserved, - IStorage** ppstgOpen) -{ - StorageImpl* newStorage = 0; - HRESULT hr = S_OK; - - /* - * Validate the parameters - */ - if ((ppstgOpen == 0) || (plkbyt == 0)) - return STG_E_INVALIDPOINTER; - - /* - * Allocate and initialize the new IStorage object. - */ - newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl)); - - if (newStorage == 0) - return STG_E_INSUFFICIENTMEMORY; - - hr = StorageImpl_Construct( - newStorage, - 0, - 0, - plkbyt, - grfMode, - FALSE, - TRUE); - - if (FAILED(hr)) - { - HeapFree(GetProcessHeap(), 0, newStorage); - return hr; - } - - /* - * Get an "out" pointer for the caller. - */ - hr = StorageBaseImpl_QueryInterface( - (IStorage*)newStorage, - (REFIID)&IID_IStorage, - (void**)ppstgOpen); - - return hr; -} - -/****************************************************************************** - * StgOpenStorageOnILockBytes [OLE32.@] - */ -HRESULT WINAPI StgOpenStorageOnILockBytes( - ILockBytes *plkbyt, - IStorage *pstgPriority, - DWORD grfMode, - SNB snbExclude, - DWORD reserved, - IStorage **ppstgOpen) -{ - StorageImpl* newStorage = 0; - HRESULT hr = S_OK; - - /* - * Perform a sanity check - */ - if ((plkbyt == 0) || (ppstgOpen == 0)) - return STG_E_INVALIDPOINTER; - - /* - * Validate the STGM flags - */ - if ( FAILED( validateSTGM(grfMode) )) - return STG_E_INVALIDFLAG; - - /* - * Initialize the "out" parameter. - */ - *ppstgOpen = 0; - - /* - * Allocate and initialize the new IStorage object. - */ - newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl)); - - if (newStorage == 0) - return STG_E_INSUFFICIENTMEMORY; - - hr = StorageImpl_Construct( - newStorage, - 0, - 0, - plkbyt, - grfMode, - FALSE, - FALSE); - - if (FAILED(hr)) - { - HeapFree(GetProcessHeap(), 0, newStorage); - return hr; - } - - /* - * Get an "out" pointer for the caller. - */ - hr = StorageBaseImpl_QueryInterface( - (IStorage*)newStorage, - (REFIID)&IID_IStorage, - (void**)ppstgOpen); - - return hr; -} - -/****************************************************************************** - * StgSetTimes [ole32.@] - * StgSetTimes [OLE32.@] - * - * - */ -HRESULT WINAPI StgSetTimes(OLECHAR const *str, FILETIME const *pctime, - FILETIME const *patime, FILETIME const *pmtime) -{ - IStorage *stg = NULL; - HRESULT r; - - TRACE("%s %p %p %p\n", debugstr_w(str), pctime, patime, pmtime); - - r = StgOpenStorage(str, NULL, STGM_READWRITE | STGM_SHARE_DENY_WRITE, - 0, 0, &stg); - if( SUCCEEDED(r) ) - { - r = IStorage_SetElementTimes(stg, NULL, pctime, patime, pmtime); - IStorage_Release(stg); - } - - return r; -} - -/****************************************************************************** - * StgIsStorageILockBytes [OLE32.@] - * - * Determines if the ILockBytes contains a storage object. - */ -HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt) -{ - BYTE sig[8]; - ULARGE_INTEGER offset; - - offset.u.HighPart = 0; - offset.u.LowPart = 0; - - ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL); - - if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0) - return S_OK; - - return S_FALSE; -} - -/****************************************************************************** - * WriteClassStg [OLE32.@] - * - * This method will store the specified CLSID in the specified storage object - */ -HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid) -{ - HRESULT hRes; - - assert(pStg != 0); - - hRes = IStorage_SetClass(pStg, rclsid); - - return hRes; -} - -/*********************************************************************** - * ReadClassStg (OLE32.@) - * - * This method reads the CLSID previously written to a storage object with the WriteClassStg. - */ -HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){ - - STATSTG pstatstg; - HRESULT hRes; - - TRACE("()\n"); - - if(pclsid==NULL) - return E_POINTER; - /* - * read a STATSTG structure (contains the clsid) from the storage - */ - hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_DEFAULT); - - if(SUCCEEDED(hRes)) - *pclsid=pstatstg.clsid; - - return hRes; -} - -/*********************************************************************** - * OleLoadFromStream (OLE32.@) - * - * This function loads an object from stream - */ -HRESULT WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj) -{ - CLSID clsid; - HRESULT res; - LPPERSISTSTREAM xstm; - - TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(iidInterface),ppvObj); - - res=ReadClassStm(pStm,&clsid); - if (!SUCCEEDED(res)) - return res; - res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj); - if (!SUCCEEDED(res)) - return res; - res=IUnknown_QueryInterface((IUnknown*)*ppvObj,&IID_IPersistStream,(LPVOID*)&xstm); - if (!SUCCEEDED(res)) { - IUnknown_Release((IUnknown*)*ppvObj); - return res; - } - res=IPersistStream_Load(xstm,pStm); - IPersistStream_Release(xstm); - /* FIXME: all refcounts ok at this point? I think they should be: - * pStm : unchanged - * ppvObj : 1 - * xstm : 0 (released) - */ - return res; -} - -/*********************************************************************** - * OleSaveToStream (OLE32.@) - * - * This function saves an object with the IPersistStream interface on it - * to the specified stream. - */ -HRESULT WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm) -{ - - CLSID clsid; - HRESULT res; - - TRACE("(%p,%p)\n",pPStm,pStm); - - res=IPersistStream_GetClassID(pPStm,&clsid); - - if (SUCCEEDED(res)){ - - res=WriteClassStm(pStm,&clsid); - - if (SUCCEEDED(res)) - - res=IPersistStream_Save(pPStm,pStm,TRUE); - } - - TRACE("Finished Save\n"); - return res; -} - -/**************************************************************************** - * This method validate a STGM parameter that can contain the values below - * - * The stgm modes in 0x0000ffff are not bit masks, but distinct 4 bit values. - * The stgm values contained in 0xffff0000 are bitmasks. - * - * STGM_DIRECT 0x00000000 - * STGM_TRANSACTED 0x00010000 - * STGM_SIMPLE 0x08000000 - * - * STGM_READ 0x00000000 - * STGM_WRITE 0x00000001 - * STGM_READWRITE 0x00000002 - * - * STGM_SHARE_DENY_NONE 0x00000040 - * STGM_SHARE_DENY_READ 0x00000030 - * STGM_SHARE_DENY_WRITE 0x00000020 - * STGM_SHARE_EXCLUSIVE 0x00000010 - * - * STGM_PRIORITY 0x00040000 - * STGM_DELETEONRELEASE 0x04000000 - * - * STGM_CREATE 0x00001000 - * STGM_CONVERT 0x00020000 - * STGM_FAILIFTHERE 0x00000000 - * - * STGM_NOSCRATCH 0x00100000 - * STGM_NOSNAPSHOT 0x00200000 - */ -static HRESULT validateSTGM(DWORD stgm) -{ - DWORD access = STGM_ACCESS_MODE(stgm); - DWORD share = STGM_SHARE_MODE(stgm); - DWORD create = STGM_CREATE_MODE(stgm); - - if (stgm&~STGM_KNOWN_FLAGS) - { - ERR("unknown flags %08lx\n", stgm); - return E_FAIL; - } - - switch (access) - { - case STGM_READ: - case STGM_WRITE: - case STGM_READWRITE: - break; - default: - return E_FAIL; - } - - switch (share) - { - case STGM_SHARE_DENY_NONE: - case STGM_SHARE_DENY_READ: - case STGM_SHARE_DENY_WRITE: - case STGM_SHARE_EXCLUSIVE: - break; - default: - return E_FAIL; - } - - switch (create) - { - case STGM_CREATE: - case STGM_FAILIFTHERE: - break; - default: - return E_FAIL; - } - - /* - * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE - */ - if ( (stgm & STGM_TRANSACTED) && (stgm & STGM_SIMPLE) ) - return E_FAIL; - - /* - * STGM_CREATE | STGM_CONVERT - * if both are false, STGM_FAILIFTHERE is set to TRUE - */ - if ( create == STGM_CREATE && (stgm & STGM_CONVERT) ) - return E_FAIL; - - /* - * STGM_NOSCRATCH requires STGM_TRANSACTED - */ - if ( (stgm & STGM_NOSCRATCH) && !(stgm & STGM_TRANSACTED) ) - return E_FAIL; - - /* - * STGM_NOSNAPSHOT requires STGM_TRANSACTED and - * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE` - */ - if ( (stgm & STGM_NOSNAPSHOT) && - (!(stgm & STGM_TRANSACTED) || - share == STGM_SHARE_EXCLUSIVE || - share == STGM_SHARE_DENY_WRITE) ) - return E_FAIL; - - return S_OK; -} - -/**************************************************************************** - * GetShareModeFromSTGM - * - * This method will return a share mode flag from a STGM value. - * The STGM value is assumed valid. - */ -static DWORD GetShareModeFromSTGM(DWORD stgm) -{ - switch (STGM_SHARE_MODE(stgm)) - { - case STGM_SHARE_DENY_NONE: - return FILE_SHARE_READ | FILE_SHARE_WRITE; - case STGM_SHARE_DENY_READ: - return FILE_SHARE_WRITE; - case STGM_SHARE_DENY_WRITE: - return FILE_SHARE_READ; - case STGM_SHARE_EXCLUSIVE: - return 0; - } - ERR("Invalid share mode!\n"); - assert(0); - return 0; -} - -/**************************************************************************** - * GetAccessModeFromSTGM - * - * This method will return an access mode flag from a STGM value. - * The STGM value is assumed valid. - */ -static DWORD GetAccessModeFromSTGM(DWORD stgm) -{ - switch (STGM_ACCESS_MODE(stgm)) - { - case STGM_READ: - return GENERIC_READ; - case STGM_WRITE: - case STGM_READWRITE: - return GENERIC_READ | GENERIC_WRITE; - } - ERR("Invalid access mode!\n"); - assert(0); - return 0; -} - -/**************************************************************************** - * GetCreationModeFromSTGM - * - * This method will return a creation mode flag from a STGM value. - * The STGM value is assumed valid. - */ -static DWORD GetCreationModeFromSTGM(DWORD stgm) -{ - switch(STGM_CREATE_MODE(stgm)) - { - case STGM_CREATE: - return CREATE_ALWAYS; - case STGM_CONVERT: - FIXME("STGM_CONVERT not implemented!\n"); - return CREATE_NEW; - case STGM_FAILIFTHERE: - return CREATE_NEW; - } - ERR("Invalid create mode!\n"); - assert(0); - return 0; -} - - -/************************************************************************* - * OLECONVERT_LoadOLE10 [Internal] - * - * Loads the OLE10 STREAM to memory - * - * PARAMS - * pOleStream [I] The OLESTREAM - * pData [I] Data Structure for the OLESTREAM Data - * - * RETURNS - * Success: S_OK - * Failure: CONVERT10_E_OLESTREAM_GET for invalid Get - * CONVERT10_E_OLESTREAM_FMT if the OLEID is invalide - * - * NOTES - * This function is used by OleConvertOLESTREAMToIStorage only. - * - * Memory allocated for pData must be freed by the caller - */ -HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1) -{ - DWORD dwSize; - HRESULT hRes = S_OK; - int nTryCnt=0; - int max_try = 6; - - pData->pData = NULL; - pData->pstrOleObjFileName = (CHAR *) NULL; - - for( nTryCnt=0;nTryCnt < max_try; nTryCnt++) - { - /* Get the OleID */ - dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID)); - if(dwSize != sizeof(pData->dwOleID)) - { - hRes = CONVERT10_E_OLESTREAM_GET; - } - else if(pData->dwOleID != OLESTREAM_ID) - { - hRes = CONVERT10_E_OLESTREAM_FMT; - } - else - { - hRes = S_OK; - break; - } - } - - if(hRes == S_OK) - { - /* Get the TypeID...more info needed for this field */ - dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID)); - if(dwSize != sizeof(pData->dwTypeID)) - { - hRes = CONVERT10_E_OLESTREAM_GET; - } - } - if(hRes == S_OK) - { - if(pData->dwTypeID != 0) - { - /* Get the length of the OleTypeName */ - dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength)); - if(dwSize != sizeof(pData->dwOleTypeNameLength)) - { - hRes = CONVERT10_E_OLESTREAM_GET; - } - - if(hRes == S_OK) - { - if(pData->dwOleTypeNameLength > 0) - { - /* Get the OleTypeName */ - dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->strOleTypeName, pData->dwOleTypeNameLength); - if(dwSize != pData->dwOleTypeNameLength) - { - hRes = CONVERT10_E_OLESTREAM_GET; - } - } - } - if(bStrem1) - { - dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength)); - if(dwSize != sizeof(pData->dwOleObjFileNameLength)) - { - hRes = CONVERT10_E_OLESTREAM_GET; - } - if(hRes == S_OK) - { - if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */ - pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength); - pData->pstrOleObjFileName = HeapAlloc(GetProcessHeap(), 0, pData->dwOleObjFileNameLength); - if(pData->pstrOleObjFileName) - { - dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->pstrOleObjFileName),pData->dwOleObjFileNameLength); - if(dwSize != pData->dwOleObjFileNameLength) - { - hRes = CONVERT10_E_OLESTREAM_GET; - } - } - else - hRes = CONVERT10_E_OLESTREAM_GET; - } - } - else - { - /* Get the Width of the Metafile */ - dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth)); - if(dwSize != sizeof(pData->dwMetaFileWidth)) - { - hRes = CONVERT10_E_OLESTREAM_GET; - } - if(hRes == S_OK) - { - /* Get the Height of the Metafile */ - dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight)); - if(dwSize != sizeof(pData->dwMetaFileHeight)) - { - hRes = CONVERT10_E_OLESTREAM_GET; - } - } - } - if(hRes == S_OK) - { - /* Get the Length of the Data */ - dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength)); - if(dwSize != sizeof(pData->dwDataLength)) - { - hRes = CONVERT10_E_OLESTREAM_GET; - } - } - - if(hRes == S_OK) /* I don't know what is this 8 byts information is we have to figure out */ - { - if(!bStrem1) /* if it is a second OLE stream data */ - { - pData->dwDataLength -= 8; - dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->strUnknown), sizeof(pData->strUnknown)); - if(dwSize != sizeof(pData->strUnknown)) - { - hRes = CONVERT10_E_OLESTREAM_GET; - } - } - } - if(hRes == S_OK) - { - if(pData->dwDataLength > 0) - { - pData->pData = HeapAlloc(GetProcessHeap(),0,pData->dwDataLength); - - /* Get Data (ex. IStorage, Metafile, or BMP) */ - if(pData->pData) - { - dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength); - if(dwSize != pData->dwDataLength) - { - hRes = CONVERT10_E_OLESTREAM_GET; - } - } - else - { - hRes = CONVERT10_E_OLESTREAM_GET; - } - } - } - } - } - return hRes; -} - -/************************************************************************* - * OLECONVERT_SaveOLE10 [Internal] - * - * Saves the OLE10 STREAM From memory - * - * PARAMS - * pData [I] Data Structure for the OLESTREAM Data - * pOleStream [I] The OLESTREAM to save - * - * RETURNS - * Success: S_OK - * Failure: CONVERT10_E_OLESTREAM_PUT for invalid Put - * - * NOTES - * This function is used by OleConvertIStorageToOLESTREAM only. - * - */ -HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream) -{ - DWORD dwSize; - HRESULT hRes = S_OK; - - - /* Set the OleID */ - dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID)); - if(dwSize != sizeof(pData->dwOleID)) - { - hRes = CONVERT10_E_OLESTREAM_PUT; - } - - if(hRes == S_OK) - { - /* Set the TypeID */ - dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID)); - if(dwSize != sizeof(pData->dwTypeID)) - { - hRes = CONVERT10_E_OLESTREAM_PUT; - } - } - - if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK) - { - /* Set the Length of the OleTypeName */ - dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength)); - if(dwSize != sizeof(pData->dwOleTypeNameLength)) - { - hRes = CONVERT10_E_OLESTREAM_PUT; - } - - if(hRes == S_OK) - { - if(pData->dwOleTypeNameLength > 0) - { - /* Set the OleTypeName */ - dwSize = pOleStream->lpstbl->Put(pOleStream, (void *) pData->strOleTypeName, pData->dwOleTypeNameLength); - if(dwSize != pData->dwOleTypeNameLength) - { - hRes = CONVERT10_E_OLESTREAM_PUT; - } - } - } - - if(hRes == S_OK) - { - /* Set the width of the Metafile */ - dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth)); - if(dwSize != sizeof(pData->dwMetaFileWidth)) - { - hRes = CONVERT10_E_OLESTREAM_PUT; - } - } - - if(hRes == S_OK) - { - /* Set the height of the Metafile */ - dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight)); - if(dwSize != sizeof(pData->dwMetaFileHeight)) - { - hRes = CONVERT10_E_OLESTREAM_PUT; - } - } - - if(hRes == S_OK) - { - /* Set the length of the Data */ - dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength)); - if(dwSize != sizeof(pData->dwDataLength)) - { - hRes = CONVERT10_E_OLESTREAM_PUT; - } - } - - if(hRes == S_OK) - { - if(pData->dwDataLength > 0) - { - /* Set the Data (eg. IStorage, Metafile, Bitmap) */ - dwSize = pOleStream->lpstbl->Put(pOleStream, (void *) pData->pData, pData->dwDataLength); - if(dwSize != pData->dwDataLength) - { - hRes = CONVERT10_E_OLESTREAM_PUT; - } - } - } - } - return hRes; -} - -/************************************************************************* - * OLECONVERT_GetOLE20FromOLE10[Internal] - * - * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk, - * opens it, and copies the content to the dest IStorage for - * OleConvertOLESTREAMToIStorage - * - * - * PARAMS - * pDestStorage [I] The IStorage to copy the data to - * pBuffer [I] Buffer that contains the IStorage from the OLESTREAM - * nBufferLength [I] The size of the buffer - * - * RETURNS - * Nothing - * - * NOTES - * - * - */ -void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, BYTE *pBuffer, DWORD nBufferLength) -{ - HRESULT hRes; - HANDLE hFile; - IStorage *pTempStorage; - DWORD dwNumOfBytesWritten; - WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH]; - static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0}; - - /* Create a temp File */ - GetTempPathW(MAX_PATH, wstrTempDir); - GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile); - hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - - if(hFile != INVALID_HANDLE_VALUE) - { - /* Write IStorage Data to File */ - WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL); - CloseHandle(hFile); - - /* Open and copy temp storage to the Dest Storage */ - hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage); - if(hRes == S_OK) - { - hRes = StorageImpl_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage); - StorageBaseImpl_Release(pTempStorage); - } - DeleteFileW(wstrTempFile); - } -} - - -/************************************************************************* - * OLECONVERT_WriteOLE20ToBuffer [Internal] - * - * Saves the OLE10 STREAM From memory - * - * PARAMS - * pStorage [I] The Src IStorage to copy - * pData [I] The Dest Memory to write to. - * - * RETURNS - * The size in bytes allocated for pData - * - * NOTES - * Memory allocated for pData must be freed by the caller - * - * Used by OleConvertIStorageToOLESTREAM only. - * - */ -DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData) -{ - HANDLE hFile; - HRESULT hRes; - DWORD nDataLength = 0; - IStorage *pTempStorage; - WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH]; - static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0}; - - *pData = NULL; - - /* Create temp Storage */ - GetTempPathW(MAX_PATH, wstrTempDir); - GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile); - hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTempStorage); - - if(hRes == S_OK) - { - /* Copy Src Storage to the Temp Storage */ - StorageImpl_CopyTo(pStorage, 0, NULL, NULL, pTempStorage); - StorageBaseImpl_Release(pTempStorage); - - /* Open Temp Storage as a file and copy to memory */ - hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - if(hFile != INVALID_HANDLE_VALUE) - { - nDataLength = GetFileSize(hFile, NULL); - *pData = HeapAlloc(GetProcessHeap(),0,nDataLength); - ReadFile(hFile, *pData, nDataLength, &nDataLength, 0); - CloseHandle(hFile); - } - DeleteFileW(wstrTempFile); - } - return nDataLength; -} - -/************************************************************************* - * OLECONVERT_CreateOleStream [Internal] - * - * Creates the "\001OLE" stream in the IStorage if necessary. - * - * PARAMS - * pStorage [I] Dest storage to create the stream in - * - * RETURNS - * Nothing - * - * NOTES - * This function is used by OleConvertOLESTREAMToIStorage only. - * - * This stream is still unknown, MS Word seems to have extra data - * but since the data is stored in the OLESTREAM there should be - * no need to recreate the stream. If the stream is manually - * deleted it will create it with this default data. - * - */ -void OLECONVERT_CreateOleStream(LPSTORAGE pStorage) -{ - HRESULT hRes; - IStream *pStream; - static const WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0}; - BYTE pOleStreamHeader [] = - { - 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 - }; - - /* Create stream if not present */ - hRes = IStorage_CreateStream(pStorage, wstrStreamName, - STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream ); - - if(hRes == S_OK) - { - /* Write default Data */ - hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL); - IStream_Release(pStream); - } -} - -/* write a string to a stream, preceded by its length */ -static HRESULT STREAM_WriteString( IStream *stm, LPCWSTR string ) -{ - HRESULT r; - LPSTR str; - DWORD len = 0; - - if( string ) - len = WideCharToMultiByte( CP_ACP, 0, string, -1, NULL, 0, NULL, NULL); - r = IStream_Write( stm, &len, sizeof(len), NULL); - if( FAILED( r ) ) - return r; - if(len == 0) - return r; - str = CoTaskMemAlloc( len ); - WideCharToMultiByte( CP_ACP, 0, string, -1, str, len, NULL, NULL); - r = IStream_Write( stm, str, len, NULL); - CoTaskMemFree( str ); - return r; -} - -/* read a string preceded by its length from a stream */ -static HRESULT STREAM_ReadString( IStream *stm, LPWSTR *string ) -{ - HRESULT r; - DWORD len, count = 0; - LPSTR str; - LPWSTR wstr; - - r = IStream_Read( stm, &len, sizeof(len), &count ); - if( FAILED( r ) ) - return r; - if( count != sizeof(len) ) - return E_OUTOFMEMORY; - - TRACE("%ld bytes\n",len); - - str = CoTaskMemAlloc( len ); - if( !str ) - return E_OUTOFMEMORY; - count = 0; - r = IStream_Read( stm, str, len, &count ); - if( FAILED( r ) ) - return r; - if( count != len ) - { - CoTaskMemFree( str ); - return E_OUTOFMEMORY; - } - - TRACE("Read string %s\n",debugstr_an(str,len)); - - len = MultiByteToWideChar( CP_ACP, 0, str, count, NULL, 0 ); - wstr = CoTaskMemAlloc( (len + 1)*sizeof (WCHAR) ); - if( wstr ) - MultiByteToWideChar( CP_ACP, 0, str, count, wstr, len ); - CoTaskMemFree( str ); - - *string = wstr; - - return r; -} - - -static HRESULT STORAGE_WriteCompObj( LPSTORAGE pstg, CLSID *clsid, - LPCWSTR lpszUserType, LPCWSTR szClipName, LPCWSTR szProgIDName ) -{ - IStream *pstm; - HRESULT r = S_OK; - static const WCHAR szwStreamName[] = {1, 'C', 'o', 'm', 'p', 'O', 'b', 'j', 0}; - - static const BYTE unknown1[12] = - { 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF}; - static const BYTE unknown2[16] = - { 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - TRACE("%p %s %s %s %s\n", pstg, debugstr_guid(clsid), - debugstr_w(lpszUserType), debugstr_w(szClipName), - debugstr_w(szProgIDName)); - - /* Create a CompObj stream if it doesn't exist */ - r = IStorage_CreateStream(pstg, szwStreamName, - STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pstm ); - if( FAILED (r) ) - return r; - - /* Write CompObj Structure to stream */ - r = IStream_Write(pstm, unknown1, sizeof(unknown1), NULL); - - if( SUCCEEDED( r ) ) - r = WriteClassStm( pstm, clsid ); - - if( SUCCEEDED( r ) ) - r = STREAM_WriteString( pstm, lpszUserType ); - if( SUCCEEDED( r ) ) - r = STREAM_WriteString( pstm, szClipName ); - if( SUCCEEDED( r ) ) - r = STREAM_WriteString( pstm, szProgIDName ); - if( SUCCEEDED( r ) ) - r = IStream_Write(pstm, unknown2, sizeof(unknown2), NULL); - - IStream_Release( pstm ); - - return r; -} - -/*********************************************************************** - * WriteFmtUserTypeStg (OLE32.@) - */ -HRESULT WINAPI WriteFmtUserTypeStg( - LPSTORAGE pstg, CLIPFORMAT cf, LPOLESTR lpszUserType) -{ - HRESULT r; - WCHAR szwClipName[0x40]; - CLSID clsid = CLSID_NULL; - LPWSTR wstrProgID = NULL; - DWORD n; - - TRACE("(%p,%x,%s)\n",pstg,cf,debugstr_w(lpszUserType)); - - /* get the clipboard format name */ - n = GetClipboardFormatNameW( cf, szwClipName, sizeof(szwClipName) ); - szwClipName[n]=0; - - TRACE("Clipboard name is %s\n", debugstr_w(szwClipName)); - - /* FIXME: There's room to save a CLSID and its ProgID, but - the CLSID is not looked up in the registry and in all the - tests I wrote it was CLSID_NULL. Where does it come from? - */ - - /* get the real program ID. This may fail, but that's fine */ - ProgIDFromCLSID(&clsid, &wstrProgID); - - TRACE("progid is %s\n",debugstr_w(wstrProgID)); - - r = STORAGE_WriteCompObj( pstg, &clsid, - lpszUserType, szwClipName, wstrProgID ); - - CoTaskMemFree(wstrProgID); - - return r; -} - - -/****************************************************************************** - * ReadFmtUserTypeStg [OLE32.@] - */ -HRESULT WINAPI ReadFmtUserTypeStg (LPSTORAGE pstg, CLIPFORMAT* pcf, LPOLESTR* lplpszUserType) -{ - HRESULT r; - IStream *stm = 0; - static const WCHAR szCompObj[] = { 1, 'C','o','m','p','O','b','j', 0 }; - unsigned char unknown1[12]; - unsigned char unknown2[16]; - DWORD count; - LPWSTR szProgIDName = NULL, szCLSIDName = NULL, szOleTypeName = NULL; - CLSID clsid; - - TRACE("(%p,%p,%p)\n", pstg, pcf, lplpszUserType); - - r = IStorage_OpenStream( pstg, szCompObj, NULL, - STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm ); - if( FAILED ( r ) ) - { - WARN("Failed to open stream r = %08lx\n", r); - return r; - } - - /* read the various parts of the structure */ - r = IStream_Read( stm, unknown1, sizeof(unknown1), &count ); - if( FAILED( r ) || ( count != sizeof(unknown1) ) ) - goto end; - r = ReadClassStm( stm, &clsid ); - if( FAILED( r ) ) - goto end; - - r = STREAM_ReadString( stm, &szCLSIDName ); - if( FAILED( r ) ) - goto end; - - r = STREAM_ReadString( stm, &szOleTypeName ); - if( FAILED( r ) ) - goto end; - - r = STREAM_ReadString( stm, &szProgIDName ); - if( FAILED( r ) ) - goto end; - - r = IStream_Read( stm, unknown2, sizeof(unknown2), &count ); - if( FAILED( r ) || ( count != sizeof(unknown2) ) ) - goto end; - - /* ok, success... now we just need to store what we found */ - if( pcf ) - *pcf = RegisterClipboardFormatW( szOleTypeName ); - CoTaskMemFree( szOleTypeName ); - - if( lplpszUserType ) - *lplpszUserType = szCLSIDName; - CoTaskMemFree( szProgIDName ); - -end: - IStream_Release( stm ); - - return r; -} - - -/************************************************************************* - * OLECONVERT_CreateCompObjStream [Internal] - * - * Creates a "\001CompObj" is the destination IStorage if necessary. - * - * PARAMS - * pStorage [I] The dest IStorage to create the CompObj Stream - * if necessary. - * strOleTypeName [I] The ProgID - * - * RETURNS - * Success: S_OK - * Failure: REGDB_E_CLASSNOTREG if cannot reconstruct the stream - * - * NOTES - * This function is used by OleConvertOLESTREAMToIStorage only. - * - * The stream data is stored in the OLESTREAM and there should be - * no need to recreate the stream. If the stream is manually - * deleted it will attempt to create it by querying the registry. - * - * - */ -HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName) -{ - IStream *pStream; - HRESULT hStorageRes, hRes = S_OK; - OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj; - static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0}; - WCHAR bufferW[OLESTREAM_MAX_STR_LEN]; - - BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}; - BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71}; - - /* Initialize the CompObj structure */ - memset(&IStorageCompObj, 0, sizeof(IStorageCompObj)); - memcpy(&(IStorageCompObj.byUnknown1), pCompObjUnknown1, sizeof(pCompObjUnknown1)); - memcpy(&(IStorageCompObj.byUnknown2), pCompObjUnknown2, sizeof(pCompObjUnknown2)); - - - /* Create a CompObj stream if it doesn't exist */ - hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName, - STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream ); - if(hStorageRes == S_OK) - { - /* copy the OleTypeName to the compobj struct */ - IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1; - strcpy(IStorageCompObj.strOleTypeName, strOleTypeName); - - /* copy the OleTypeName to the compobj struct */ - /* Note: in the test made, these were Identical */ - IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1; - strcpy(IStorageCompObj.strProgIDName, strOleTypeName); - - /* Get the CLSID */ - MultiByteToWideChar( CP_ACP, 0, IStorageCompObj.strProgIDName, -1, - bufferW, OLESTREAM_MAX_STR_LEN ); - hRes = CLSIDFromProgID(bufferW, &(IStorageCompObj.clsid)); - - if(hRes == S_OK) - { - HKEY hKey; - LONG hErr; - /* Get the CLSID Default Name from the Registry */ - hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey); - if(hErr == ERROR_SUCCESS) - { - char strTemp[OLESTREAM_MAX_STR_LEN]; - IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN; - hErr = RegQueryValueA(hKey, NULL, strTemp, &(IStorageCompObj.dwCLSIDNameLength)); - if(hErr == ERROR_SUCCESS) - { - strcpy(IStorageCompObj.strCLSIDName, strTemp); - } - RegCloseKey(hKey); - } - } - - /* Write CompObj Structure to stream */ - hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL); - - WriteClassStm(pStream,&(IStorageCompObj.clsid)); - - hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL); - if(IStorageCompObj.dwCLSIDNameLength > 0) - { - hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL); - } - hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL); - if(IStorageCompObj.dwOleTypeNameLength > 0) - { - hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL); - } - hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL); - if(IStorageCompObj.dwProgIDNameLength > 0) - { - hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL); - } - hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL); - IStream_Release(pStream); - } - return hRes; -} - - -/************************************************************************* - * OLECONVERT_CreateOlePresStream[Internal] - * - * Creates the "\002OlePres000" Stream with the Metafile data - * - * PARAMS - * pStorage [I] The dest IStorage to create \002OLEPres000 stream in. - * dwExtentX [I] Width of the Metafile - * dwExtentY [I] Height of the Metafile - * pData [I] Metafile data - * dwDataLength [I] Size of the Metafile data - * - * RETURNS - * Success: S_OK - * Failure: CONVERT10_E_OLESTREAM_PUT for invalid Put - * - * NOTES - * This function is used by OleConvertOLESTREAMToIStorage only. - * - */ -void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength) -{ - HRESULT hRes; - IStream *pStream; - static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0}; - BYTE pOlePresStreamHeader [] = - { - 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 - }; - - BYTE pOlePresStreamHeaderEmpty [] = - { - 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 - }; - - /* Create the OlePres000 Stream */ - hRes = IStorage_CreateStream(pStorage, wstrStreamName, - STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream ); - - if(hRes == S_OK) - { - DWORD nHeaderSize; - OLECONVERT_ISTORAGE_OLEPRES OlePres; - - memset(&OlePres, 0, sizeof(OlePres)); - /* Do we have any metafile data to save */ - if(dwDataLength > 0) - { - memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader)); - nHeaderSize = sizeof(pOlePresStreamHeader); - } - else - { - memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty)); - nHeaderSize = sizeof(pOlePresStreamHeaderEmpty); - } - /* Set width and height of the metafile */ - OlePres.dwExtentX = dwExtentX; - OlePres.dwExtentY = -dwExtentY; - - /* Set Data and Length */ - if(dwDataLength > sizeof(METAFILEPICT16)) - { - OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16); - OlePres.pData = &(pData[8]); - } - /* Save OlePres000 Data to Stream */ - hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL); - hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL); - hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL); - hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL); - if(OlePres.dwSize > 0) - { - hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL); - } - IStream_Release(pStream); - } -} - -/************************************************************************* - * OLECONVERT_CreateOle10NativeStream [Internal] - * - * Creates the "\001Ole10Native" Stream (should contain a BMP) - * - * PARAMS - * pStorage [I] Dest storage to create the stream in - * pData [I] Ole10 Native Data (ex. bmp) - * dwDataLength [I] Size of the Ole10 Native Data - * - * RETURNS - * Nothing - * - * NOTES - * This function is used by OleConvertOLESTREAMToIStorage only. - * - * Might need to verify the data and return appropriate error message - * - */ -void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, BYTE *pData, DWORD dwDataLength) -{ - HRESULT hRes; - IStream *pStream; - static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0}; - - /* Create the Ole10Native Stream */ - hRes = IStorage_CreateStream(pStorage, wstrStreamName, - STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream ); - - if(hRes == S_OK) - { - /* Write info to stream */ - hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL); - hRes = IStream_Write(pStream, pData, dwDataLength, NULL); - IStream_Release(pStream); - } - -} - -/************************************************************************* - * OLECONVERT_GetOLE10ProgID [Internal] - * - * Finds the ProgID (or OleTypeID) from the IStorage - * - * PARAMS - * pStorage [I] The Src IStorage to get the ProgID - * strProgID [I] the ProgID string to get - * dwSize [I] the size of the string - * - * RETURNS - * Success: S_OK - * Failure: REGDB_E_CLASSNOTREG if cannot reconstruct the stream - * - * NOTES - * This function is used by OleConvertIStorageToOLESTREAM only. - * - * - */ -HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize) -{ - HRESULT hRes; - IStream *pStream; - LARGE_INTEGER iSeekPos; - OLECONVERT_ISTORAGE_COMPOBJ CompObj; - static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0}; - - /* Open the CompObj Stream */ - hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL, - STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream ); - if(hRes == S_OK) - { - - /*Get the OleType from the CompObj Stream */ - iSeekPos.u.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid); - iSeekPos.u.HighPart = 0; - - IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL); - IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL); - iSeekPos.u.LowPart = CompObj.dwCLSIDNameLength; - IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL); - IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL); - iSeekPos.u.LowPart = CompObj.dwOleTypeNameLength; - IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL); - - IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL); - if(*dwSize > 0) - { - IStream_Read(pStream, strProgID, *dwSize, NULL); - } - IStream_Release(pStream); - } - else - { - STATSTG stat; - LPOLESTR wstrProgID; - - /* Get the OleType from the registry */ - REFCLSID clsid = &(stat.clsid); - IStorage_Stat(pStorage, &stat, STATFLAG_NONAME); - hRes = ProgIDFromCLSID(clsid, &wstrProgID); - if(hRes == S_OK) - { - *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE); - } - - } - return hRes; -} - -/************************************************************************* - * OLECONVERT_GetOle10PresData [Internal] - * - * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream - * - * PARAMS - * pStorage [I] Src IStroage - * pOleStream [I] Dest OleStream Mem Struct - * - * RETURNS - * Nothing - * - * NOTES - * This function is used by OleConvertIStorageToOLESTREAM only. - * - * Memory allocated for pData must be freed by the caller - * - * - */ -void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData) -{ - - HRESULT hRes; - IStream *pStream; - static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0}; - - /* Initialize Default data for OLESTREAM */ - pOleStreamData[0].dwOleID = OLESTREAM_ID; - pOleStreamData[0].dwTypeID = 2; - pOleStreamData[1].dwOleID = OLESTREAM_ID; - pOleStreamData[1].dwTypeID = 0; - pOleStreamData[0].dwMetaFileWidth = 0; - pOleStreamData[0].dwMetaFileHeight = 0; - pOleStreamData[0].pData = NULL; - pOleStreamData[1].pData = NULL; - - /* Open Ole10Native Stream */ - hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL, - STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream ); - if(hRes == S_OK) - { - - /* Read Size and Data */ - IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL); - if(pOleStreamData->dwDataLength > 0) - { - pOleStreamData->pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength); - IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL); - } - IStream_Release(pStream); - } - -} - - -/************************************************************************* - * OLECONVERT_GetOle20PresData[Internal] - * - * Converts IStorage "/002OlePres000" stream to a OLE10 Stream - * - * PARAMS - * pStorage [I] Src IStroage - * pOleStreamData [I] Dest OleStream Mem Struct - * - * RETURNS - * Nothing - * - * NOTES - * This function is used by OleConvertIStorageToOLESTREAM only. - * - * Memory allocated for pData must be freed by the caller - */ -void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData) -{ - HRESULT hRes; - IStream *pStream; - OLECONVERT_ISTORAGE_OLEPRES olePress; - static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0}; - - /* Initialize Default data for OLESTREAM */ - pOleStreamData[0].dwOleID = OLESTREAM_ID; - pOleStreamData[0].dwTypeID = 2; - pOleStreamData[0].dwMetaFileWidth = 0; - pOleStreamData[0].dwMetaFileHeight = 0; - pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData)); - pOleStreamData[1].dwOleID = OLESTREAM_ID; - pOleStreamData[1].dwTypeID = 0; - pOleStreamData[1].dwOleTypeNameLength = 0; - pOleStreamData[1].strOleTypeName[0] = 0; - pOleStreamData[1].dwMetaFileWidth = 0; - pOleStreamData[1].dwMetaFileHeight = 0; - pOleStreamData[1].pData = NULL; - pOleStreamData[1].dwDataLength = 0; - - - /* Open OlePress000 stream */ - hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL, - STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream ); - if(hRes == S_OK) - { - LARGE_INTEGER iSeekPos; - METAFILEPICT16 MetaFilePict; - static const char strMetafilePictName[] = "METAFILEPICT"; - - /* Set the TypeID for a Metafile */ - pOleStreamData[1].dwTypeID = 5; - - /* Set the OleTypeName to Metafile */ - pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1; - strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName); - - iSeekPos.u.HighPart = 0; - iSeekPos.u.LowPart = sizeof(olePress.byUnknown1); - - /* Get Presentation Data */ - IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL); - IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL); - IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL); - IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL); - - /*Set width and Height */ - pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX; - pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY; - if(olePress.dwSize > 0) - { - /* Set Length */ - pOleStreamData[1].dwDataLength = olePress.dwSize + sizeof(METAFILEPICT16); - - /* Set MetaFilePict struct */ - MetaFilePict.mm = 8; - MetaFilePict.xExt = olePress.dwExtentX; - MetaFilePict.yExt = olePress.dwExtentY; - MetaFilePict.hMF = 0; - - /* Get Metafile Data */ - pOleStreamData[1].pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength); - memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict)); - IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL); - } - IStream_Release(pStream); - } -} - -/************************************************************************* - * OleConvertOLESTREAMToIStorage [OLE32.@] - * - * Read info on MSDN - * - * TODO - * DVTARGETDEVICE paramenter is not handled - * Still unsure of some mem fields for OLE 10 Stream - * Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj", - * and "\001OLE" streams - * - */ -HRESULT WINAPI OleConvertOLESTREAMToIStorage ( - LPOLESTREAM pOleStream, - LPSTORAGE pstg, - const DVTARGETDEVICE* ptd) -{ - int i; - HRESULT hRes=S_OK; - OLECONVERT_OLESTREAM_DATA pOleStreamData[2]; - - memset(pOleStreamData, 0, sizeof(pOleStreamData)); - - if(ptd != NULL) - { - FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n"); - } - - if(pstg == NULL || pOleStream == NULL) - { - hRes = E_INVALIDARG; - } - - if(hRes == S_OK) - { - /* Load the OLESTREAM to Memory */ - hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE); - } - - if(hRes == S_OK) - { - /* Load the OLESTREAM to Memory (part 2)*/ - hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE); - } - - if(hRes == S_OK) - { - - if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic)) - { - /* Do we have the IStorage Data in the OLESTREAM */ - if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0) - { - OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength); - OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength); - } - else - { - /* It must be an original OLE 1.0 source */ - OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength); - } - } - else - { - /* It must be an original OLE 1.0 source */ - OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength); - } - - /* Create CompObj Stream if necessary */ - hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName); - if(hRes == S_OK) - { - /*Create the Ole Stream if necessary */ - OLECONVERT_CreateOleStream(pstg); - } - } - - - /* Free allocated memory */ - for(i=0; i < 2; i++) - { - HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData); - HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName); - pOleStreamData[i].pstrOleObjFileName = NULL; - } - return hRes; -} - -/************************************************************************* - * OleConvertIStorageToOLESTREAM [OLE32.@] - * - * Read info on MSDN - * - * Read info on MSDN - * - * TODO - * Still unsure of some mem fields for OLE 10 Stream - * Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj", - * and "\001OLE" streams. - * - */ -HRESULT WINAPI OleConvertIStorageToOLESTREAM ( - LPSTORAGE pstg, - LPOLESTREAM pOleStream) -{ - int i; - HRESULT hRes = S_OK; - IStream *pStream; - OLECONVERT_OLESTREAM_DATA pOleStreamData[2]; - static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0}; - - - memset(pOleStreamData, 0, sizeof(pOleStreamData)); - - if(pstg == NULL || pOleStream == NULL) - { - hRes = E_INVALIDARG; - } - if(hRes == S_OK) - { - /* Get the ProgID */ - pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN; - hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength)); - } - if(hRes == S_OK) - { - /* Was it originally Ole10 */ - hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream); - if(hRes == S_OK) - { - IStream_Release(pStream); - /* Get Presentation Data for Ole10Native */ - OLECONVERT_GetOle10PresData(pstg, pOleStreamData); - } - else - { - /* Get Presentation Data (OLE20) */ - OLECONVERT_GetOle20PresData(pstg, pOleStreamData); - } - - /* Save OLESTREAM */ - hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream); - if(hRes == S_OK) - { - hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream); - } - - } - - /* Free allocated memory */ - for(i=0; i < 2; i++) - { - HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData); - } - - return hRes; -} - -/*********************************************************************** - * GetConvertStg (OLE32.@) - */ -HRESULT WINAPI GetConvertStg(IStorage *stg) { - FIXME("unimplemented stub!\n"); - return E_FAIL; -} - -/****************************************************************************** - * StgIsStorageFile [OLE32.@] - */ -HRESULT WINAPI -StgIsStorageFile(LPCOLESTR fn) -{ - HANDLE hf; - BYTE magic[8]; - DWORD bytes_read; - - TRACE("(\'%s\')\n", debugstr_w(fn)); - hf = CreateFileW(fn, GENERIC_READ, - FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - - if (hf == INVALID_HANDLE_VALUE) - return STG_E_FILENOTFOUND; - - if (!ReadFile(hf, magic, 8, &bytes_read, NULL)) - { - WARN(" unable to read file\n"); - CloseHandle(hf); - return S_FALSE; - } - - CloseHandle(hf); - - if (bytes_read != 8) { - WARN(" too short\n"); - return S_FALSE; - } - - if (!memcmp(magic,STORAGE_magic,8)) { - WARN(" -> YES\n"); - return S_OK; - } - - WARN(" -> Invalid header.\n"); - return S_FALSE; -} +/* + * Compound Storage (32 bit version) + * Storage implementation + * + * This file contains the compound file implementation + * of the storage interface. + * + * Copyright 1999 Francis Beaudet + * Copyright 1999 Sylvain St-Germain + * Copyright 1999 Thuy Nguyen + * Copyright 2005 Mike McCormack + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <assert.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winuser.h" +#include "wine/unicode.h" +#include "wine/debug.h" + +#include "storage32.h" +#include "ole2.h" /* For Write/ReadClassStm */ + +#include "winreg.h" +#include "wine/wingdi16.h" + +WINE_DEFAULT_DEBUG_CHANNEL(storage); + +#define FILE_BEGIN 0 + +/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */ +#define OLESTREAM_ID 0x501 +#define OLESTREAM_MAX_STR_LEN 255 + +static const char rootPropertyName[] = "Root Entry"; + + +/* OLESTREAM memory structure to use for Get and Put Routines */ +/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */ +typedef struct +{ + DWORD dwOleID; + DWORD dwTypeID; + DWORD dwOleTypeNameLength; + CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN]; + CHAR *pstrOleObjFileName; + DWORD dwOleObjFileNameLength; + DWORD dwMetaFileWidth; + DWORD dwMetaFileHeight; + CHAR strUnknown[8]; /* don't know what is this 8 byts information in OLE stream. */ + DWORD dwDataLength; + BYTE *pData; +}OLECONVERT_OLESTREAM_DATA; + +/* CompObj Stream structure */ +/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */ +typedef struct +{ + BYTE byUnknown1[12]; + CLSID clsid; + DWORD dwCLSIDNameLength; + CHAR strCLSIDName[OLESTREAM_MAX_STR_LEN]; + DWORD dwOleTypeNameLength; + CHAR strOleTypeName[OLESTREAM_MAX_STR_LEN]; + DWORD dwProgIDNameLength; + CHAR strProgIDName[OLESTREAM_MAX_STR_LEN]; + BYTE byUnknown2[16]; +}OLECONVERT_ISTORAGE_COMPOBJ; + + +/* Ole Presention Stream structure */ +/* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */ +typedef struct +{ + BYTE byUnknown1[28]; + DWORD dwExtentX; + DWORD dwExtentY; + DWORD dwSize; + BYTE *pData; +}OLECONVERT_ISTORAGE_OLEPRES; + + + +/*********************************************************************** + * Forward declaration of internal functions used by the method DestroyElement + */ +static HRESULT deleteStorageProperty( + StorageImpl *parentStorage, + ULONG foundPropertyIndexToDelete, + StgProperty propertyToDelete); + +static HRESULT deleteStreamProperty( + StorageImpl *parentStorage, + ULONG foundPropertyIndexToDelete, + StgProperty propertyToDelete); + +static HRESULT findPlaceholder( + StorageImpl *storage, + ULONG propertyIndexToStore, + ULONG storagePropertyIndex, + INT typeOfRelation); + +static HRESULT adjustPropertyChain( + StorageImpl *This, + StgProperty propertyToDelete, + StgProperty parentProperty, + ULONG parentPropertyId, + INT typeOfRelation); + +/*********************************************************************** + * Declaration of the functions used to manipulate StgProperty + */ + +static ULONG getFreeProperty( + StorageImpl *storage); + +static void updatePropertyChain( + StorageImpl *storage, + ULONG newPropertyIndex, + StgProperty newProperty); + +static LONG propertyNameCmp( + const OLECHAR *newProperty, + const OLECHAR *currentProperty); + + +/*********************************************************************** + * Declaration of miscellaneous functions... + */ +static HRESULT validateSTGM(DWORD stgmValue); + +static DWORD GetShareModeFromSTGM(DWORD stgm); +static DWORD GetAccessModeFromSTGM(DWORD stgm); +static DWORD GetCreationModeFromSTGM(DWORD stgm); + +extern IPropertySetStorageVtbl IPropertySetStorage_Vtbl; + + + +/************************************************************************ +** Storage32BaseImpl implementatiion +*/ + +/************************************************************************ + * Storage32BaseImpl_QueryInterface (IUnknown) + * + * This method implements the common QueryInterface for all IStorage32 + * implementations contained in this file. + * + * See Windows documentation for more details on IUnknown methods. + */ +HRESULT WINAPI StorageBaseImpl_QueryInterface( + IStorage* iface, + REFIID riid, + void** ppvObject) +{ + StorageBaseImpl *This = (StorageBaseImpl *)iface; + /* + * Perform a sanity check on the parameters. + */ + if ( (This==0) || (ppvObject==0) ) + return E_INVALIDARG; + + /* + * Initialize the return parameter. + */ + *ppvObject = 0; + + /* + * Compare the riid with the interface IDs implemented by this object. + */ + if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) + { + *ppvObject = (IStorage*)This; + } + else if (memcmp(&IID_IStorage, riid, sizeof(IID_IStorage)) == 0) + { + *ppvObject = (IStorage*)This; + } + else if (memcmp(&IID_IPropertySetStorage, riid, sizeof(IID_IPropertySetStorage)) == 0) + { + *ppvObject = (IStorage*)&This->pssVtbl; + } + + /* + * Check that we obtained an interface. + */ + if ((*ppvObject)==0) + return E_NOINTERFACE; + + /* + * Query Interface always increases the reference count by one when it is + * successful + */ + IStorage_AddRef(iface); + + return S_OK; +} + +/************************************************************************ + * Storage32BaseImpl_AddRef (IUnknown) + * + * This method implements the common AddRef for all IStorage32 + * implementations contained in this file. + * + * See Windows documentation for more details on IUnknown methods. + */ +ULONG WINAPI StorageBaseImpl_AddRef( + IStorage* iface) +{ + StorageBaseImpl *This = (StorageBaseImpl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) AddRef to %ld\n", This, ref); + + return ref; +} + +/************************************************************************ + * Storage32BaseImpl_Release (IUnknown) + * + * This method implements the common Release for all IStorage32 + * implementations contained in this file. + * + * See Windows documentation for more details on IUnknown methods. + */ +ULONG WINAPI StorageBaseImpl_Release( + IStorage* iface) +{ + StorageBaseImpl *This = (StorageBaseImpl *)iface; + /* + * Decrease the reference count on this object. + */ + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ReleaseRef to %ld\n", This, ref); + + /* + * If the reference count goes down to 0, perform suicide. + */ + if (ref == 0) + { + /* + * Since we are using a system of base-classes, we want to call the + * destructor of the appropriate derived class. To do this, we are + * using virtual functions to implement the destructor. + */ + This->v_destructor(This); + } + + return ref; +} + +/************************************************************************ + * Storage32BaseImpl_OpenStream (IStorage) + * + * This method will open the specified stream object from the current storage. + * + * See Windows documentation for more details on IStorage methods. + */ +HRESULT WINAPI StorageBaseImpl_OpenStream( + IStorage* iface, + const OLECHAR* pwcsName, /* [string][in] */ + void* reserved1, /* [unique][in] */ + DWORD grfMode, /* [in] */ + DWORD reserved2, /* [in] */ + IStream** ppstm) /* [out] */ +{ + StorageBaseImpl *This = (StorageBaseImpl *)iface; + IEnumSTATSTGImpl* propertyEnumeration; + StgStreamImpl* newStream; + StgProperty currentProperty; + ULONG foundPropertyIndex; + HRESULT res = STG_E_UNKNOWN; + DWORD parent_grfMode; + + TRACE("(%p, %s, %p, %lx, %ld, %p)\n", + iface, debugstr_w(pwcsName), reserved1, grfMode, reserved2, ppstm); + + /* + * Perform a sanity check on the parameters. + */ + if ( (pwcsName==NULL) || (ppstm==0) ) + { + res = E_INVALIDARG; + goto end; + } + + /* + * Initialize the out parameter + */ + *ppstm = NULL; + + /* + * Validate the STGM flags + */ + if ( FAILED( validateSTGM(grfMode) )) + { + res = STG_E_INVALIDFLAG; + goto end; + } + + /* + * As documented. + */ + if ( STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE || + (grfMode & STGM_DELETEONRELEASE) || + (grfMode & STGM_TRANSACTED) ) + { + res = STG_E_INVALIDFUNCTION; + goto end; + } + + /* + * Check that we're compatible with the parent's storage mode + */ + parent_grfMode = STGM_ACCESS_MODE( This->ancestorStorage->base.openFlags ); + if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( parent_grfMode ) ) + { + res = STG_E_ACCESSDENIED; + goto end; + } + + /* + * Create a property enumeration to search the properties + */ + propertyEnumeration = IEnumSTATSTGImpl_Construct( + This->ancestorStorage, + This->rootPropertySetIndex); + + /* + * Search the enumeration for the property with the given name + */ + foundPropertyIndex = IEnumSTATSTGImpl_FindProperty( + propertyEnumeration, + pwcsName, + ¤tProperty); + + /* + * Delete the property enumeration since we don't need it anymore + */ + IEnumSTATSTGImpl_Destroy(propertyEnumeration); + + /* + * If it was found, construct the stream object and return a pointer to it. + */ + if ( (foundPropertyIndex!=PROPERTY_NULL) && + (currentProperty.propertyType==PROPTYPE_STREAM) ) + { + newStream = StgStreamImpl_Construct(This, grfMode, foundPropertyIndex); + + if (newStream!=0) + { + newStream->grfMode = grfMode; + *ppstm = (IStream*)newStream; + + /* + * Since we are returning a pointer to the interface, we have to + * nail down the reference. + */ + IStream_AddRef(*ppstm); + + res = S_OK; + goto end; + } + + res = E_OUTOFMEMORY; + goto end; + } + + res = STG_E_FILENOTFOUND; + +end: + if (res == S_OK) + TRACE("<-- IStream %p\n", *ppstm); + TRACE("<-- %08lx\n", res); + return res; +} + +/************************************************************************ + * Storage32BaseImpl_OpenStorage (IStorage) + * + * This method will open a new storage object from the current storage. + * + * See Windows documentation for more details on IStorage methods. + */ +HRESULT WINAPI StorageBaseImpl_OpenStorage( + IStorage* iface, + const OLECHAR* pwcsName, /* [string][unique][in] */ + IStorage* pstgPriority, /* [unique][in] */ + DWORD grfMode, /* [in] */ + SNB snbExclude, /* [unique][in] */ + DWORD reserved, /* [in] */ + IStorage** ppstg) /* [out] */ +{ + StorageBaseImpl *This = (StorageBaseImpl *)iface; + StorageInternalImpl* newStorage; + IEnumSTATSTGImpl* propertyEnumeration; + StgProperty currentProperty; + ULONG foundPropertyIndex; + HRESULT res = STG_E_UNKNOWN; + DWORD parent_grfMode; + + TRACE("(%p, %s, %p, %lx, %p, %ld, %p)\n", + iface, debugstr_w(pwcsName), pstgPriority, + grfMode, snbExclude, reserved, ppstg); + + /* + * Perform a sanity check on the parameters. + */ + if ( (This==0) || (pwcsName==NULL) || (ppstg==0) ) + { + res = E_INVALIDARG; + goto end; + } + + /* as documented */ + if (snbExclude != NULL) + { + res = STG_E_INVALIDPARAMETER; + goto end; + } + + /* + * Validate the STGM flags + */ + if ( FAILED( validateSTGM(grfMode) )) + { + res = STG_E_INVALIDFLAG; + goto end; + } + + /* + * As documented. + */ + if ( STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE || + (grfMode & STGM_DELETEONRELEASE) || + (grfMode & STGM_PRIORITY) ) + { + res = STG_E_INVALIDFUNCTION; + goto end; + } + + /* + * Check that we're compatible with the parent's storage mode + */ + parent_grfMode = STGM_ACCESS_MODE( This->ancestorStorage->base.openFlags ); + if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( parent_grfMode ) ) + { + res = STG_E_ACCESSDENIED; + goto end; + } + + /* + * Initialize the out parameter + */ + *ppstg = NULL; + + /* + * Create a property enumeration to search the properties + */ + propertyEnumeration = IEnumSTATSTGImpl_Construct( + This->ancestorStorage, + This->rootPropertySetIndex); + + /* + * Search the enumeration for the property with the given name + */ + foundPropertyIndex = IEnumSTATSTGImpl_FindProperty( + propertyEnumeration, + pwcsName, + ¤tProperty); + + /* + * Delete the property enumeration since we don't need it anymore + */ + IEnumSTATSTGImpl_Destroy(propertyEnumeration); + + /* + * If it was found, construct the stream object and return a pointer to it. + */ + if ( (foundPropertyIndex!=PROPERTY_NULL) && + (currentProperty.propertyType==PROPTYPE_STORAGE) ) + { + /* + * Construct a new Storage object + */ + newStorage = StorageInternalImpl_Construct( + This->ancestorStorage, + grfMode, + foundPropertyIndex); + + if (newStorage != 0) + { + *ppstg = (IStorage*)newStorage; + + /* + * Since we are returning a pointer to the interface, + * we have to nail down the reference. + */ + StorageBaseImpl_AddRef(*ppstg); + + res = S_OK; + goto end; + } + + res = STG_E_INSUFFICIENTMEMORY; + goto end; + } + + res = STG_E_FILENOTFOUND; + +end: + TRACE("<-- %08lx\n", res); + return res; +} + +/************************************************************************ + * Storage32BaseImpl_EnumElements (IStorage) + * + * This method will create an enumerator object that can be used to + * retrieve informatino about all the properties in the storage object. + * + * See Windows documentation for more details on IStorage methods. + */ +HRESULT WINAPI StorageBaseImpl_EnumElements( + IStorage* iface, + DWORD reserved1, /* [in] */ + void* reserved2, /* [size_is][unique][in] */ + DWORD reserved3, /* [in] */ + IEnumSTATSTG** ppenum) /* [out] */ +{ + StorageBaseImpl *This = (StorageBaseImpl *)iface; + IEnumSTATSTGImpl* newEnum; + + TRACE("(%p, %ld, %p, %ld, %p)\n", + iface, reserved1, reserved2, reserved3, ppenum); + + /* + * Perform a sanity check on the parameters. + */ + if ( (This==0) || (ppenum==0)) + return E_INVALIDARG; + + /* + * Construct the enumerator. + */ + newEnum = IEnumSTATSTGImpl_Construct( + This->ancestorStorage, + This->rootPropertySetIndex); + + if (newEnum!=0) + { + *ppenum = (IEnumSTATSTG*)newEnum; + + /* + * Don't forget to nail down a reference to the new object before + * returning it. + */ + IEnumSTATSTG_AddRef(*ppenum); + + return S_OK; + } + + return E_OUTOFMEMORY; +} + +/************************************************************************ + * Storage32BaseImpl_Stat (IStorage) + * + * This method will retrieve information about this storage object. + * + * See Windows documentation for more details on IStorage methods. + */ +HRESULT WINAPI StorageBaseImpl_Stat( + IStorage* iface, + STATSTG* pstatstg, /* [out] */ + DWORD grfStatFlag) /* [in] */ +{ + StorageBaseImpl *This = (StorageBaseImpl *)iface; + StgProperty curProperty; + BOOL readSuccessful; + HRESULT res = STG_E_UNKNOWN; + + TRACE("(%p, %p, %lx)\n", + iface, pstatstg, grfStatFlag); + + /* + * Perform a sanity check on the parameters. + */ + if ( (This==0) || (pstatstg==0)) + { + res = E_INVALIDARG; + goto end; + } + + /* + * Read the information from the property. + */ + readSuccessful = StorageImpl_ReadProperty( + This->ancestorStorage, + This->rootPropertySetIndex, + &curProperty); + + if (readSuccessful) + { + StorageUtl_CopyPropertyToSTATSTG( + pstatstg, + &curProperty, + grfStatFlag); + + res = S_OK; + goto end; + } + + res = E_FAIL; + +end: + if (res == S_OK) + { + TRACE("<-- STATSTG: pwcsName: %s, type: %ld, cbSize.Low/High: %ld/%ld, grfMode: %08lx, grfLocksSupported: %ld, grfStateBits: %08lx\n", debugstr_w(pstatstg->pwcsName), pstatstg->type, pstatstg->cbSize.u.LowPart, pstatstg->cbSize.u.HighPart, pstatstg->grfMode, pstatstg->grfLocksSupported, pstatstg->grfStateBits); + } + TRACE("<-- %08lx\n", res); + return res; +} + +/************************************************************************ + * Storage32BaseImpl_RenameElement (IStorage) + * + * This method will rename the specified element. + * + * See Windows documentation for more details on IStorage methods. + * + * Implementation notes: The method used to rename consists of creating a clone + * of the deleted StgProperty object setting it with the new name and to + * perform a DestroyElement of the old StgProperty. + */ +HRESULT WINAPI StorageBaseImpl_RenameElement( + IStorage* iface, + const OLECHAR* pwcsOldName, /* [in] */ + const OLECHAR* pwcsNewName) /* [in] */ +{ + StorageBaseImpl *This = (StorageBaseImpl *)iface; + IEnumSTATSTGImpl* propertyEnumeration; + StgProperty currentProperty; + ULONG foundPropertyIndex; + + TRACE("(%p, %s, %s)\n", + iface, debugstr_w(pwcsOldName), debugstr_w(pwcsNewName)); + + /* + * Create a property enumeration to search the properties + */ + propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage, + This->rootPropertySetIndex); + + /* + * Search the enumeration for the new property name + */ + foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration, + pwcsNewName, + ¤tProperty); + + if (foundPropertyIndex != PROPERTY_NULL) + { + /* + * There is already a property with the new name + */ + IEnumSTATSTGImpl_Destroy(propertyEnumeration); + return STG_E_FILEALREADYEXISTS; + } + + IEnumSTATSTG_Reset((IEnumSTATSTG*)propertyEnumeration); + + /* + * Search the enumeration for the old property name + */ + foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration, + pwcsOldName, + ¤tProperty); + + /* + * Delete the property enumeration since we don't need it anymore + */ + IEnumSTATSTGImpl_Destroy(propertyEnumeration); + + if (foundPropertyIndex != PROPERTY_NULL) + { + StgProperty renamedProperty; + ULONG renamedPropertyIndex; + + /* + * Setup a new property for the renamed property + */ + renamedProperty.sizeOfNameString = + ( lstrlenW(pwcsNewName)+1 ) * sizeof(WCHAR); + + if (renamedProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN) + return STG_E_INVALIDNAME; + + strcpyW(renamedProperty.name, pwcsNewName); + + renamedProperty.propertyType = currentProperty.propertyType; + renamedProperty.startingBlock = currentProperty.startingBlock; + renamedProperty.size.u.LowPart = currentProperty.size.u.LowPart; + renamedProperty.size.u.HighPart = currentProperty.size.u.HighPart; + + renamedProperty.previousProperty = PROPERTY_NULL; + renamedProperty.nextProperty = PROPERTY_NULL; + + /* + * Bring the dirProperty link in case it is a storage and in which + * case the renamed storage elements don't require to be reorganized. + */ + renamedProperty.dirProperty = currentProperty.dirProperty; + + /* call CoFileTime to get the current time + renamedProperty.timeStampS1 + renamedProperty.timeStampD1 + renamedProperty.timeStampS2 + renamedProperty.timeStampD2 + renamedProperty.propertyUniqueID + */ + + /* + * Obtain a free property in the property chain + */ + renamedPropertyIndex = getFreeProperty(This->ancestorStorage); + + /* + * Save the new property into the new property spot + */ + StorageImpl_WriteProperty( + This->ancestorStorage, + renamedPropertyIndex, + &renamedProperty); + + /* + * Find a spot in the property chain for our newly created property. + */ + updatePropertyChain( + (StorageImpl*)This, + renamedPropertyIndex, + renamedProperty); + + /* + * At this point the renamed property has been inserted in the tree, + * now, before to Destroy the old property we must zeroed it's dirProperty + * otherwise the DestroyProperty below will zap it all and we do not want + * this to happen. + * Also, we fake that the old property is a storage so the DestroyProperty + * will not do a SetSize(0) on the stream data. + * + * This means that we need to tweek the StgProperty if it is a stream or a + * non empty storage. + */ + StorageImpl_ReadProperty(This->ancestorStorage, + foundPropertyIndex, + ¤tProperty); + + currentProperty.dirProperty = PROPERTY_NULL; + currentProperty.propertyType = PROPTYPE_STORAGE; + StorageImpl_WriteProperty( + This->ancestorStorage, + foundPropertyIndex, + ¤tProperty); + + /* + * Invoke Destroy to get rid of the ole property and automatically redo + * the linking of it's previous and next members... + */ + IStorage_DestroyElement((IStorage*)This->ancestorStorage, pwcsOldName); + + } + else + { + /* + * There is no property with the old name + */ + return STG_E_FILENOTFOUND; + } + + return S_OK; +} + +/************************************************************************ + * Storage32BaseImpl_CreateStream (IStorage) + * + * This method will create a stream object within this storage + * + * See Windows documentation for more details on IStorage methods. + */ +HRESULT WINAPI StorageBaseImpl_CreateStream( + IStorage* iface, + const OLECHAR* pwcsName, /* [string][in] */ + DWORD grfMode, /* [in] */ + DWORD reserved1, /* [in] */ + DWORD reserved2, /* [in] */ + IStream** ppstm) /* [out] */ +{ + StorageBaseImpl *This = (StorageBaseImpl *)iface; + IEnumSTATSTGImpl* propertyEnumeration; + StgStreamImpl* newStream; + StgProperty currentProperty, newStreamProperty; + ULONG foundPropertyIndex, newPropertyIndex; + DWORD parent_grfMode; + + TRACE("(%p, %s, %lx, %ld, %ld, %p)\n", + iface, debugstr_w(pwcsName), grfMode, + reserved1, reserved2, ppstm); + + /* + * Validate parameters + */ + if (ppstm == 0) + return STG_E_INVALIDPOINTER; + + if (pwcsName == 0) + return STG_E_INVALIDNAME; + + if (reserved1 || reserved2) + return STG_E_INVALIDPARAMETER; + + /* + * Validate the STGM flags + */ + if ( FAILED( validateSTGM(grfMode) )) + return STG_E_INVALIDFLAG; + + if (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE) + return STG_E_INVALIDFLAG; + + /* + * As documented. + */ + if ((grfMode & STGM_DELETEONRELEASE) || + (grfMode & STGM_TRANSACTED)) + return STG_E_INVALIDFUNCTION; + + /* + * Check that we're compatible with the parent's storage mode + */ + parent_grfMode = STGM_ACCESS_MODE( This->ancestorStorage->base.openFlags ); + if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( parent_grfMode ) ) + return STG_E_ACCESSDENIED; + + /* + * Initialize the out parameter + */ + *ppstm = 0; + + /* + * Create a property enumeration to search the properties + */ + propertyEnumeration = IEnumSTATSTGImpl_Construct(This->ancestorStorage, + This->rootPropertySetIndex); + + foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration, + pwcsName, + ¤tProperty); + + IEnumSTATSTGImpl_Destroy(propertyEnumeration); + + if (foundPropertyIndex != PROPERTY_NULL) + { + /* + * An element with this name already exists + */ + if (STGM_CREATE_MODE(grfMode) == STGM_CREATE) + { + IStorage_DestroyElement(iface, pwcsName); + } + else + return STG_E_FILEALREADYEXISTS; + } + + /* + * memset the empty property + */ + memset(&newStreamProperty, 0, sizeof(StgProperty)); + + newStreamProperty.sizeOfNameString = + ( lstrlenW(pwcsName)+1 ) * sizeof(WCHAR); + + if (newStreamProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN) + return STG_E_INVALIDNAME; + + strcpyW(newStreamProperty.name, pwcsName); + + newStreamProperty.propertyType = PROPTYPE_STREAM; + newStreamProperty.startingBlock = BLOCK_END_OF_CHAIN; + newStreamProperty.size.u.LowPart = 0; + newStreamProperty.size.u.HighPart = 0; + + newStreamProperty.previousProperty = PROPERTY_NULL; + newStreamProperty.nextProperty = PROPERTY_NULL; + newStreamProperty.dirProperty = PROPERTY_NULL; + + /* call CoFileTime to get the current time + newStreamProperty.timeStampS1 + newStreamProperty.timeStampD1 + newStreamProperty.timeStampS2 + newStreamProperty.timeStampD2 + */ + + /* newStreamProperty.propertyUniqueID */ + + /* + * Get a free property or create a new one + */ + newPropertyIndex = getFreeProperty(This->ancestorStorage); + + /* + * Save the new property into the new property spot + */ + StorageImpl_WriteProperty( + This->ancestorStorage, + newPropertyIndex, + &newStreamProperty); + + /* + * Find a spot in the property chain for our newly created property. + */ + updatePropertyChain( + (StorageImpl*)This, + newPropertyIndex, + newStreamProperty); + + /* + * Open the stream to return it. + */ + newStream = StgStreamImpl_Construct(This, grfMode, newPropertyIndex); + + if (newStream != 0) + { + *ppstm = (IStream*)newStream; + + /* + * Since we are returning a pointer to the interface, we have to nail down + * the reference. + */ + IStream_AddRef(*ppstm); + } + else + { + return STG_E_INSUFFICIENTMEMORY; + } + + return S_OK; +} + +/************************************************************************ + * Storage32BaseImpl_SetClass (IStorage) + * + * This method will write the specified CLSID in the property of this + * storage. + * + * See Windows documentation for more details on IStorage methods. + */ +HRESULT WINAPI StorageBaseImpl_SetClass( + IStorage* iface, + REFCLSID clsid) /* [in] */ +{ + StorageBaseImpl *This = (StorageBaseImpl *)iface; + HRESULT hRes = E_FAIL; + StgProperty curProperty; + BOOL success; + + TRACE("(%p, %p)\n", iface, clsid); + + success = StorageImpl_ReadProperty(This->ancestorStorage, + This->rootPropertySetIndex, + &curProperty); + if (success) + { + curProperty.propertyUniqueID = *clsid; + + success = StorageImpl_WriteProperty(This->ancestorStorage, + This->rootPropertySetIndex, + &curProperty); + if (success) + hRes = S_OK; + } + + return hRes; +} + +/************************************************************************ +** Storage32Impl implementation +*/ + +/************************************************************************ + * Storage32Impl_CreateStorage (IStorage) + * + * This method will create the storage object within the provided storage. + * + * See Windows documentation for more details on IStorage methods. + */ +HRESULT WINAPI StorageImpl_CreateStorage( + IStorage* iface, + const OLECHAR *pwcsName, /* [string][in] */ + DWORD grfMode, /* [in] */ + DWORD reserved1, /* [in] */ + DWORD reserved2, /* [in] */ + IStorage **ppstg) /* [out] */ +{ + StorageImpl* const This=(StorageImpl*)iface; + + IEnumSTATSTGImpl *propertyEnumeration; + StgProperty currentProperty; + StgProperty newProperty; + ULONG foundPropertyIndex; + ULONG newPropertyIndex; + HRESULT hr; + DWORD parent_grfMode; + + TRACE("(%p, %s, %lx, %ld, %ld, %p)\n", + iface, debugstr_w(pwcsName), grfMode, + reserved1, reserved2, ppstg); + + /* + * Validate parameters + */ + if (ppstg == 0) + return STG_E_INVALIDPOINTER; + + if (pwcsName == 0) + return STG_E_INVALIDNAME; + + /* + * Validate the STGM flags + */ + if ( FAILED( validateSTGM(grfMode) ) || + (grfMode & STGM_DELETEONRELEASE) ) + return STG_E_INVALIDFLAG; + + /* + * Check that we're compatible with the parent's storage mode + */ + parent_grfMode = STGM_ACCESS_MODE( This->base.ancestorStorage->base.openFlags ); + if ( STGM_ACCESS_MODE( grfMode ) > STGM_ACCESS_MODE( parent_grfMode ) ) + return STG_E_ACCESSDENIED; + + /* + * Initialize the out parameter + */ + *ppstg = 0; + + /* + * Create a property enumeration and search the properties + */ + propertyEnumeration = IEnumSTATSTGImpl_Construct( This->base.ancestorStorage, + This->base.rootPropertySetIndex); + + foundPropertyIndex = IEnumSTATSTGImpl_FindProperty(propertyEnumeration, + pwcsName, + ¤tProperty); + IEnumSTATSTGImpl_Destroy(propertyEnumeration); + + if (foundPropertyIndex != PROPERTY_NULL) + { + /* + * An element with this name already exists + */ + if (STGM_CREATE_MODE(grfMode) == STGM_CREATE) + IStorage_DestroyElement(iface, pwcsName); + else + return STG_E_FILEALREADYEXISTS; + } + + /* + * memset the empty property + */ + memset(&newProperty, 0, sizeof(StgProperty)); + + newProperty.sizeOfNameString = (lstrlenW(pwcsName)+1)*sizeof(WCHAR); + + if (newProperty.sizeOfNameString > PROPERTY_NAME_BUFFER_LEN) + return STG_E_INVALIDNAME; + + strcpyW(newProperty.name, pwcsName); + + newProperty.propertyType = PROPTYPE_STORAGE; + newProperty.startingBlock = BLOCK_END_OF_CHAIN; + newProperty.size.u.LowPart = 0; + newProperty.size.u.HighPart = 0; + + newProperty.previousProperty = PROPERTY_NULL; + newProperty.nextProperty = PROPERTY_NULL; + newProperty.dirProperty = PROPERTY_NULL; + + /* call CoFileTime to get the current time + newProperty.timeStampS1 + newProperty.timeStampD1 + newProperty.timeStampS2 + newProperty.timeStampD2 + */ + + /* newStorageProperty.propertyUniqueID */ + + /* + * Obtain a free property in the property chain + */ + newPropertyIndex = getFreeProperty(This->base.ancestorStorage); + + /* + * Save the new property into the new property spot + */ + StorageImpl_WriteProperty( + This->base.ancestorStorage, + newPropertyIndex, + &newProperty); + + /* + * Find a spot in the property chain for our newly created property. + */ + updatePropertyChain( + This, + newPropertyIndex, + newProperty); + + /* + * Open it to get a pointer to return. + */ + hr = IStorage_OpenStorage( + iface, + (const OLECHAR*)pwcsName, + 0, + grfMode, + 0, + 0, + ppstg); + + if( (hr != S_OK) || (*ppstg == NULL)) + { + return hr; + } + + + return S_OK; +} + + +/*************************************************************************** + * + * Internal Method + * + * Get a free property or create a new one. + */ +static ULONG getFreeProperty( + StorageImpl *storage) +{ + ULONG currentPropertyIndex = 0; + ULONG newPropertyIndex = PROPERTY_NULL; + BOOL readSuccessful = TRUE; + StgProperty currentProperty; + + do + { + /* + * Start by reading the root property + */ + readSuccessful = StorageImpl_ReadProperty(storage->base.ancestorStorage, + currentPropertyIndex, + ¤tProperty); + if (readSuccessful) + { + if (currentProperty.sizeOfNameString == 0) + { + /* + * The property existis and is available, we found it. + */ + newPropertyIndex = currentPropertyIndex; + } + } + else + { + /* + * We exhausted the property list, we will create more space below + */ + newPropertyIndex = currentPropertyIndex; + } + currentPropertyIndex++; + + } while (newPropertyIndex == PROPERTY_NULL); + + /* + * grow the property chain + */ + if (! readSuccessful) + { + StgProperty emptyProperty; + ULARGE_INTEGER newSize; + ULONG propertyIndex; + ULONG lastProperty = 0; + ULONG blockCount = 0; + + /* + * obtain the new count of property blocks + */ + blockCount = BlockChainStream_GetCount( + storage->base.ancestorStorage->rootBlockChain)+1; + + /* + * initialize the size used by the property stream + */ + newSize.u.HighPart = 0; + newSize.u.LowPart = storage->bigBlockSize * blockCount; + + /* + * add a property block to the property chain + */ + BlockChainStream_SetSize(storage->base.ancestorStorage->rootBlockChain, newSize); + + /* + * memset the empty property in order to initialize the unused newly + * created property + */ + memset(&emptyProperty, 0, sizeof(StgProperty)); + + /* + * initialize them + */ + lastProperty = storage->bigBlockSize / PROPSET_BLOCK_SIZE * blockCount; + + for( + propertyIndex = newPropertyIndex; + propertyIndex < lastProperty; + propertyIndex++) + { + StorageImpl_WriteProperty( + storage->base.ancestorStorage, + propertyIndex, + &emptyProperty); + } + } + + return newPropertyIndex; +} + +/**************************************************************************** + * + * Internal Method + * + * Case insensitive comparaison of StgProperty.name by first considering + * their size. + * + * Returns <0 when newPrpoerty < currentProperty + * >0 when newPrpoerty > currentProperty + * 0 when newPrpoerty == currentProperty + */ +static LONG propertyNameCmp( + const OLECHAR *newProperty, + const OLECHAR *currentProperty) +{ + LONG diff = lstrlenW(newProperty) - lstrlenW(currentProperty); + + if (diff == 0) + { + /* + * We compare the string themselves only when they are of the same length + */ + diff = lstrcmpiW( newProperty, currentProperty); + } + + return diff; +} + +/**************************************************************************** + * + * Internal Method + * + * Properly link this new element in the property chain. + */ +static void updatePropertyChain( + StorageImpl *storage, + ULONG newPropertyIndex, + StgProperty newProperty) +{ + StgProperty currentProperty; + + /* + * Read the root property + */ + StorageImpl_ReadProperty(storage->base.ancestorStorage, + storage->base.rootPropertySetIndex, + ¤tProperty); + + if (currentProperty.dirProperty != PROPERTY_NULL) + { + /* + * The root storage contains some element, therefore, start the research + * for the appropriate location. + */ + BOOL found = 0; + ULONG current, next, previous, currentPropertyId; + + /* + * Keep the StgProperty sequence number of the storage first property + */ + currentPropertyId = currentProperty.dirProperty; + + /* + * Read + */ + StorageImpl_ReadProperty(storage->base.ancestorStorage, + currentProperty.dirProperty, + ¤tProperty); + + previous = currentProperty.previousProperty; + next = currentProperty.nextProperty; + current = currentPropertyId; + + while (found == 0) + { + LONG diff = propertyNameCmp( newProperty.name, currentProperty.name); + + if (diff < 0) + { + if (previous != PROPERTY_NULL) + { + StorageImpl_ReadProperty(storage->base.ancestorStorage, + previous, + ¤tProperty); + current = previous; + } + else + { + currentProperty.previousProperty = newPropertyIndex; + StorageImpl_WriteProperty(storage->base.ancestorStorage, + current, + ¤tProperty); + found = 1; + } + } + else if (diff > 0) + { + if (next != PROPERTY_NULL) + { + StorageImpl_ReadProperty(storage->base.ancestorStorage, + next, + ¤tProperty); + current = next; + } + else + { + currentProperty.nextProperty = newPropertyIndex; + StorageImpl_WriteProperty(storage->base.ancestorStorage, + current, + ¤tProperty); + found = 1; + } + } + else + { + /* + * Trying to insert an item with the same name in the + * subtree structure. + */ + assert(FALSE); + } + + previous = currentProperty.previousProperty; + next = currentProperty.nextProperty; + } + } + else + { + /* + * The root storage is empty, link the new property to it's dir property + */ + currentProperty.dirProperty = newPropertyIndex; + StorageImpl_WriteProperty(storage->base.ancestorStorage, + storage->base.rootPropertySetIndex, + ¤tProperty); + } +} + + +/************************************************************************* + * CopyTo (IStorage) + */ +HRESULT WINAPI StorageImpl_CopyTo( + IStorage* iface, + DWORD ciidExclude, /* [in] */ + const IID* rgiidExclude, /* [size_is][unique][in] */ + SNB snbExclude, /* [unique][in] */ + IStorage* pstgDest) /* [unique][in] */ +{ + IEnumSTATSTG *elements = 0; + STATSTG curElement, strStat; + HRESULT hr; + IStorage *pstgTmp, *pstgChild; + IStream *pstrTmp, *pstrChild; + + if ((ciidExclude != 0) || (rgiidExclude != NULL) || (snbExclude != NULL)) + FIXME("Exclude option not implemented\n"); + + TRACE("(%p, %ld, %p, %p, %p)\n", + iface, ciidExclude, rgiidExclude, + snbExclude, pstgDest); + + /* + * Perform a sanity check + */ + if ( pstgDest == 0 ) + return STG_E_INVALIDPOINTER; + + /* + * Enumerate the elements + */ + hr = IStorage_EnumElements( iface, 0, 0, 0, &elements ); + + if ( hr != S_OK ) + return hr; + + /* + * set the class ID + */ + IStorage_Stat( iface, &curElement, STATFLAG_NONAME); + IStorage_SetClass( pstgDest, &curElement.clsid ); + + do + { + /* + * Obtain the next element + */ + hr = IEnumSTATSTG_Next( elements, 1, &curElement, NULL ); + + if ( hr == S_FALSE ) + { + hr = S_OK; /* done, every element has been copied */ + break; + } + + if (curElement.type == STGTY_STORAGE) + { + /* + * open child source storage + */ + hr = IStorage_OpenStorage( iface, curElement.pwcsName, NULL, + STGM_READ|STGM_SHARE_EXCLUSIVE, + NULL, 0, &pstgChild ); + + if (hr != S_OK) + break; + + /* + * Check if destination storage is not a child of the source + * storage, which will cause an infinite loop + */ + if (pstgChild == pstgDest) + { + IEnumSTATSTG_Release(elements); + + return STG_E_ACCESSDENIED; + } + + /* + * create a new storage in destination storage + */ + hr = IStorage_CreateStorage( pstgDest, curElement.pwcsName, + STGM_FAILIFTHERE|STGM_WRITE|STGM_SHARE_EXCLUSIVE, + 0, 0, + &pstgTmp ); + /* + * if it already exist, don't create a new one use this one + */ + if (hr == STG_E_FILEALREADYEXISTS) + { + hr = IStorage_OpenStorage( pstgDest, curElement.pwcsName, NULL, + STGM_WRITE|STGM_SHARE_EXCLUSIVE, + NULL, 0, &pstgTmp ); + } + + if (hr != S_OK) + break; + + + /* + * do the copy recursively + */ + hr = IStorage_CopyTo( pstgChild, ciidExclude, rgiidExclude, + snbExclude, pstgTmp ); + + IStorage_Release( pstgTmp ); + IStorage_Release( pstgChild ); + } + else if (curElement.type == STGTY_STREAM) + { + /* + * create a new stream in destination storage. If the stream already + * exist, it will be deleted and a new one will be created. + */ + hr = IStorage_CreateStream( pstgDest, curElement.pwcsName, + STGM_CREATE|STGM_WRITE|STGM_SHARE_EXCLUSIVE, + 0, 0, &pstrTmp ); + + if (hr != S_OK) + break; + + /* + * open child stream storage + */ + hr = IStorage_OpenStream( iface, curElement.pwcsName, NULL, + STGM_READ|STGM_SHARE_EXCLUSIVE, + 0, &pstrChild ); + + if (hr != S_OK) + break; + + /* + * Get the size of the source stream + */ + IStream_Stat( pstrChild, &strStat, STATFLAG_NONAME ); + + /* + * Set the size of the destination stream. + */ + IStream_SetSize(pstrTmp, strStat.cbSize); + + /* + * do the copy + */ + hr = IStream_CopyTo( pstrChild, pstrTmp, strStat.cbSize, + NULL, NULL ); + + IStream_Release( pstrTmp ); + IStream_Release( pstrChild ); + } + else + { + WARN("unknown element type: %ld\n", curElement.type); + } + + } while (hr == S_OK); + + /* + * Clean-up + */ + IEnumSTATSTG_Release(elements); + + return hr; +} + +/************************************************************************* + * MoveElementTo (IStorage) + */ +HRESULT WINAPI StorageImpl_MoveElementTo( + IStorage* iface, + const OLECHAR *pwcsName, /* [string][in] */ + IStorage *pstgDest, /* [unique][in] */ + const OLECHAR *pwcsNewName,/* [string][in] */ + DWORD grfFlags) /* [in] */ +{ + FIXME("not implemented!\n"); + return E_NOTIMPL; +} + +/************************************************************************* + * Commit (IStorage) + */ +HRESULT WINAPI StorageImpl_Commit( + IStorage* iface, + DWORD grfCommitFlags)/* [in] */ +{ + FIXME("(%ld): stub!\n", grfCommitFlags); + return S_OK; +} + +/************************************************************************* + * Revert (IStorage) + */ +HRESULT WINAPI StorageImpl_Revert( + IStorage* iface) +{ + FIXME("not implemented!\n"); + return E_NOTIMPL; +} + +/************************************************************************* + * DestroyElement (IStorage) + * + * Stategy: This implementation is build this way for simplicity not for speed. + * I always delete the top most element of the enumeration and adjust + * the deleted element pointer all the time. This takes longer to + * do but allow to reinvoke DestroyElement whenever we encounter a + * storage object. The optimisation reside in the usage of another + * enumeration stategy that would give all the leaves of a storage + * first. (postfix order) + */ +HRESULT WINAPI StorageImpl_DestroyElement( + IStorage* iface, + const OLECHAR *pwcsName)/* [string][in] */ +{ + StorageImpl* const This=(StorageImpl*)iface; + + IEnumSTATSTGImpl* propertyEnumeration; + HRESULT hr = S_OK; + BOOL res; + StgProperty propertyToDelete; + StgProperty parentProperty; + ULONG foundPropertyIndexToDelete; + ULONG typeOfRelation; + ULONG parentPropertyId; + + TRACE("(%p, %s)\n", + iface, debugstr_w(pwcsName)); + + /* + * Perform a sanity check on the parameters. + */ + if (pwcsName==NULL) + return STG_E_INVALIDPOINTER; + + /* + * Create a property enumeration to search the property with the given name + */ + propertyEnumeration = IEnumSTATSTGImpl_Construct( + This->base.ancestorStorage, + This->base.rootPropertySetIndex); + + foundPropertyIndexToDelete = IEnumSTATSTGImpl_FindProperty( + propertyEnumeration, + pwcsName, + &propertyToDelete); + + IEnumSTATSTGImpl_Destroy(propertyEnumeration); + + if ( foundPropertyIndexToDelete == PROPERTY_NULL ) + { + return STG_E_FILENOTFOUND; + } + + /* + * Find the parent property of the property to delete (the one that + * link to it). If This->dirProperty == foundPropertyIndexToDelete, + * the parent is This. Otherwise, the parent is one of it's sibling... + */ + + /* + * First, read This's StgProperty.. + */ + res = StorageImpl_ReadProperty( + This->base.ancestorStorage, + This->base.rootPropertySetIndex, + &parentProperty); + + assert(res); + + /* + * Second, check to see if by any chance the actual storage (This) is not + * the parent of the property to delete... We never know... + */ + if ( parentProperty.dirProperty == foundPropertyIndexToDelete ) + { + /* + * Set data as it would have been done in the else part... + */ + typeOfRelation = PROPERTY_RELATION_DIR; + parentPropertyId = This->base.rootPropertySetIndex; + } + else + { + /* + * Create a property enumeration to search the parent properties, and + * delete it once done. + */ + IEnumSTATSTGImpl* propertyEnumeration2; + + propertyEnumeration2 = IEnumSTATSTGImpl_Construct( + This->base.ancestorStorage, + This->base.rootPropertySetIndex); + + typeOfRelation = IEnumSTATSTGImpl_FindParentProperty( + propertyEnumeration2, + foundPropertyIndexToDelete, + &parentProperty, + &parentPropertyId); + + IEnumSTATSTGImpl_Destroy(propertyEnumeration2); + } + + if ( propertyToDelete.propertyType == PROPTYPE_STORAGE ) + { + hr = deleteStorageProperty( + This, + foundPropertyIndexToDelete, + propertyToDelete); + } + else if ( propertyToDelete.propertyType == PROPTYPE_STREAM ) + { + hr = deleteStreamProperty( + This, + foundPropertyIndexToDelete, + propertyToDelete); + } + + if (hr!=S_OK) + return hr; + + /* + * Adjust the property chain + */ + hr = adjustPropertyChain( + This, + propertyToDelete, + parentProperty, + parentPropertyId, + typeOfRelation); + + return hr; +} + + +/************************************************************************ + * StorageImpl_Stat (IStorage) + * + * This method will retrieve information about this storage object. + * + * See Windows documentation for more details on IStorage methods. + */ +HRESULT WINAPI StorageImpl_Stat( IStorage* iface, + STATSTG* pstatstg, /* [out] */ + DWORD grfStatFlag) /* [in] */ +{ + StorageImpl* const This = (StorageImpl*)iface; + HRESULT result = StorageBaseImpl_Stat( iface, pstatstg, grfStatFlag ); + + if ( !FAILED(result) && ((grfStatFlag & STATFLAG_NONAME) == 0) && This->pwcsName ) + { + CoTaskMemFree(pstatstg->pwcsName); + pstatstg->pwcsName = CoTaskMemAlloc((lstrlenW(This->pwcsName)+1)*sizeof(WCHAR)); + strcpyW(pstatstg->pwcsName, This->pwcsName); + } + + return result; +} + + + +/********************************************************************* + * + * Internal Method + * + * Perform the deletion of a complete storage node + * + */ +static HRESULT deleteStorageProperty( + StorageImpl *parentStorage, + ULONG indexOfPropertyToDelete, + StgProperty propertyToDelete) +{ + IEnumSTATSTG *elements = 0; + IStorage *childStorage = 0; + STATSTG currentElement; + HRESULT hr; + HRESULT destroyHr = S_OK; + + /* + * Open the storage and enumerate it + */ + hr = StorageBaseImpl_OpenStorage( + (IStorage*)parentStorage, + propertyToDelete.name, + 0, + STGM_SHARE_EXCLUSIVE, + 0, + 0, + &childStorage); + + if (hr != S_OK) + { + return hr; + } + + /* + * Enumerate the elements + */ + IStorage_EnumElements( childStorage, 0, 0, 0, &elements); + + do + { + /* + * Obtain the next element + */ + hr = IEnumSTATSTG_Next(elements, 1, ¤tElement, NULL); + if (hr==S_OK) + { + destroyHr = StorageImpl_DestroyElement( + (IStorage*)childStorage, + (OLECHAR*)currentElement.pwcsName); + + CoTaskMemFree(currentElement.pwcsName); + } + + /* + * We need to Reset the enumeration every time because we delete elements + * and the enumeration could be invalid + */ + IEnumSTATSTG_Reset(elements); + + } while ((hr == S_OK) && (destroyHr == S_OK)); + + /* + * Invalidate the property by zeroing it's name member. + */ + propertyToDelete.sizeOfNameString = 0; + + StorageImpl_WriteProperty(parentStorage->base.ancestorStorage, + indexOfPropertyToDelete, + &propertyToDelete); + + IStorage_Release(childStorage); + IEnumSTATSTG_Release(elements); + + return destroyHr; +} + +/********************************************************************* + * + * Internal Method + * + * Perform the deletion of a stream node + * + */ +static HRESULT deleteStreamProperty( + StorageImpl *parentStorage, + ULONG indexOfPropertyToDelete, + StgProperty propertyToDelete) +{ + IStream *pis; + HRESULT hr; + ULARGE_INTEGER size; + + size.u.HighPart = 0; + size.u.LowPart = 0; + + hr = StorageBaseImpl_OpenStream( + (IStorage*)parentStorage, + (OLECHAR*)propertyToDelete.name, + NULL, + STGM_WRITE | STGM_SHARE_EXCLUSIVE, + 0, + &pis); + + if (hr!=S_OK) + { + return(hr); + } + + /* + * Zap the stream + */ + hr = IStream_SetSize(pis, size); + + if(hr != S_OK) + { + return hr; + } + + /* + * Release the stream object. + */ + IStream_Release(pis); + + /* + * Invalidate the property by zeroing it's name member. + */ + propertyToDelete.sizeOfNameString = 0; + + /* + * Here we should re-read the property so we get the updated pointer + * but since we are here to zap it, I don't do it... + */ + StorageImpl_WriteProperty( + parentStorage->base.ancestorStorage, + indexOfPropertyToDelete, + &propertyToDelete); + + return S_OK; +} + +/********************************************************************* + * + * Internal Method + * + * Finds a placeholder for the StgProperty within the Storage + * + */ +static HRESULT findPlaceholder( + StorageImpl *storage, + ULONG propertyIndexToStore, + ULONG storePropertyIndex, + INT typeOfRelation) +{ + StgProperty storeProperty; + HRESULT hr = S_OK; + BOOL res = TRUE; + + /* + * Read the storage property + */ + res = StorageImpl_ReadProperty( + storage->base.ancestorStorage, + storePropertyIndex, + &storeProperty); + + if(! res) + { + return E_FAIL; + } + + if (typeOfRelation == PROPERTY_RELATION_PREVIOUS) + { + if (storeProperty.previousProperty != PROPERTY_NULL) + { + return findPlaceholder( + storage, + propertyIndexToStore, + storeProperty.previousProperty, + typeOfRelation); + } + else + { + storeProperty.previousProperty = propertyIndexToStore; + } + } + else if (typeOfRelation == PROPERTY_RELATION_NEXT) + { + if (storeProperty.nextProperty != PROPERTY_NULL) + { + return findPlaceholder( + storage, + propertyIndexToStore, + storeProperty.nextProperty, + typeOfRelation); + } + else + { + storeProperty.nextProperty = propertyIndexToStore; + } + } + else if (typeOfRelation == PROPERTY_RELATION_DIR) + { + if (storeProperty.dirProperty != PROPERTY_NULL) + { + return findPlaceholder( + storage, + propertyIndexToStore, + storeProperty.dirProperty, + typeOfRelation); + } + else + { + storeProperty.dirProperty = propertyIndexToStore; + } + } + + hr = StorageImpl_WriteProperty( + storage->base.ancestorStorage, + storePropertyIndex, + &storeProperty); + + if(! hr) + { + return E_FAIL; + } + + return S_OK; +} + +/************************************************************************* + * + * Internal Method + * + * This method takes the previous and the next property link of a property + * to be deleted and find them a place in the Storage. + */ +static HRESULT adjustPropertyChain( + StorageImpl *This, + StgProperty propertyToDelete, + StgProperty parentProperty, + ULONG parentPropertyId, + INT typeOfRelation) +{ + ULONG newLinkProperty = PROPERTY_NULL; + BOOL needToFindAPlaceholder = FALSE; + ULONG storeNode = PROPERTY_NULL; + ULONG toStoreNode = PROPERTY_NULL; + INT relationType = 0; + HRESULT hr = S_OK; + BOOL res = TRUE; + + if (typeOfRelation == PROPERTY_RELATION_PREVIOUS) + { + if (propertyToDelete.previousProperty != PROPERTY_NULL) + { + /* + * Set the parent previous to the property to delete previous + */ + newLinkProperty = propertyToDelete.previousProperty; + + if (propertyToDelete.nextProperty != PROPERTY_NULL) + { + /* + * We also need to find a storage for the other link, setup variables + * to do this at the end... + */ + needToFindAPlaceholder = TRUE; + storeNode = propertyToDelete.previousProperty; + toStoreNode = propertyToDelete.nextProperty; + relationType = PROPERTY_RELATION_NEXT; + } + } + else if (propertyToDelete.nextProperty != PROPERTY_NULL) + { + /* + * Set the parent previous to the property to delete next + */ + newLinkProperty = propertyToDelete.nextProperty; + } + + /* + * Link it for real... + */ + parentProperty.previousProperty = newLinkProperty; + + } + else if (typeOfRelation == PROPERTY_RELATION_NEXT) + { + if (propertyToDelete.previousProperty != PROPERTY_NULL) + { + /* + * Set the parent next to the property to delete next previous + */ + newLinkProperty = propertyToDelete.previousProperty; + + if (propertyToDelete.nextProperty != PROPERTY_NULL) + { + /* + * We also need to find a storage for the other link, setup variables + * to do this at the end... + */ + needToFindAPlaceholder = TRUE; + storeNode = propertyToDelete.previousProperty; + toStoreNode = propertyToDelete.nextProperty; + relationType = PROPERTY_RELATION_NEXT; + } + } + else if (propertyToDelete.nextProperty != PROPERTY_NULL) + { + /* + * Set the parent next to the property to delete next + */ + newLinkProperty = propertyToDelete.nextProperty; + } + + /* + * Link it for real... + */ + parentProperty.nextProperty = newLinkProperty; + } + else /* (typeOfRelation == PROPERTY_RELATION_DIR) */ + { + if (propertyToDelete.previousProperty != PROPERTY_NULL) + { + /* + * Set the parent dir to the property to delete previous + */ + newLinkProperty = propertyToDelete.previousProperty; + + if (propertyToDelete.nextProperty != PROPERTY_NULL) + { + /* + * We also need to find a storage for the other link, setup variables + * to do this at the end... + */ + needToFindAPlaceholder = TRUE; + storeNode = propertyToDelete.previousProperty; + toStoreNode = propertyToDelete.nextProperty; + relationType = PROPERTY_RELATION_NEXT; + } + } + else if (propertyToDelete.nextProperty != PROPERTY_NULL) + { + /* + * Set the parent dir to the property to delete next + */ + newLinkProperty = propertyToDelete.nextProperty; + } + + /* + * Link it for real... + */ + parentProperty.dirProperty = newLinkProperty; + } + + /* + * Write back the parent property + */ + res = StorageImpl_WriteProperty( + This->base.ancestorStorage, + parentPropertyId, + &parentProperty); + if(! res) + { + return E_FAIL; + } + + /* + * If a placeholder is required for the other link, then, find one and + * get out of here... + */ + if (needToFindAPlaceholder) + { + hr = findPlaceholder( + This, + toStoreNode, + storeNode, + relationType); + } + + return hr; +} + + +/****************************************************************************** + * SetElementTimes (IStorage) + */ +HRESULT WINAPI StorageImpl_SetElementTimes( + IStorage* iface, + const OLECHAR *pwcsName,/* [string][in] */ + const FILETIME *pctime, /* [in] */ + const FILETIME *patime, /* [in] */ + const FILETIME *pmtime) /* [in] */ +{ + FIXME("(%s,...), stub!\n",debugstr_w(pwcsName)); + return S_OK; +} + +/****************************************************************************** + * SetStateBits (IStorage) + */ +HRESULT WINAPI StorageImpl_SetStateBits( + IStorage* iface, + DWORD grfStateBits,/* [in] */ + DWORD grfMask) /* [in] */ +{ + FIXME("not implemented!\n"); + return E_NOTIMPL; +} + +/* + * Virtual function table for the IStorage32Impl class. + */ +static IStorageVtbl Storage32Impl_Vtbl = +{ + StorageBaseImpl_QueryInterface, + StorageBaseImpl_AddRef, + StorageBaseImpl_Release, + StorageBaseImpl_CreateStream, + StorageBaseImpl_OpenStream, + StorageImpl_CreateStorage, + StorageBaseImpl_OpenStorage, + StorageImpl_CopyTo, + StorageImpl_MoveElementTo, + StorageImpl_Commit, + StorageImpl_Revert, + StorageBaseImpl_EnumElements, + StorageImpl_DestroyElement, + StorageBaseImpl_RenameElement, + StorageImpl_SetElementTimes, + StorageBaseImpl_SetClass, + StorageImpl_SetStateBits, + StorageImpl_Stat +}; + +HRESULT StorageImpl_Construct( + StorageImpl* This, + HANDLE hFile, + LPCOLESTR pwcsName, + ILockBytes* pLkbyt, + DWORD openFlags, + BOOL fileBased, + BOOL fileCreate) +{ + HRESULT hr = S_OK; + StgProperty currentProperty; + BOOL readSuccessful; + ULONG currentPropertyIndex; + + if ( FAILED( validateSTGM(openFlags) )) + return STG_E_INVALIDFLAG; + + memset(This, 0, sizeof(StorageImpl)); + + /* + * Initialize the virtual function table. + */ + This->base.lpVtbl = &Storage32Impl_Vtbl; + This->base.pssVtbl = &IPropertySetStorage_Vtbl; + This->base.v_destructor = &StorageImpl_Destroy; + This->base.openFlags = openFlags; + + /* + * This is the top-level storage so initialize the ancestor pointer + * to this. + */ + This->base.ancestorStorage = This; + + /* + * Initialize the physical support of the storage. + */ + This->hFile = hFile; + + /* + * Store copy of file path. + */ + if(pwcsName) { + This->pwcsName = HeapAlloc(GetProcessHeap(), 0, + (lstrlenW(pwcsName)+1)*sizeof(WCHAR)); + if (!This->pwcsName) + return STG_E_INSUFFICIENTMEMORY; + strcpyW(This->pwcsName, pwcsName); + } + + /* + * Initialize the big block cache. + */ + This->bigBlockSize = DEF_BIG_BLOCK_SIZE; + This->smallBlockSize = DEF_SMALL_BLOCK_SIZE; + This->bigBlockFile = BIGBLOCKFILE_Construct(hFile, + pLkbyt, + openFlags, + This->bigBlockSize, + fileBased); + + if (This->bigBlockFile == 0) + return E_FAIL; + + if (fileCreate) + { + ULARGE_INTEGER size; + BYTE* bigBlockBuffer; + + /* + * Initialize all header variables: + * - The big block depot consists of one block and it is at block 0 + * - The properties start at block 1 + * - There is no small block depot + */ + memset( This->bigBlockDepotStart, + BLOCK_UNUSED, + sizeof(This->bigBlockDepotStart)); + + This->bigBlockDepotCount = 1; + This->bigBlockDepotStart[0] = 0; + This->rootStartBlock = 1; + This->smallBlockDepotStart = BLOCK_END_OF_CHAIN; + This->bigBlockSizeBits = DEF_BIG_BLOCK_SIZE_BITS; + This->smallBlockSizeBits = DEF_SMALL_BLOCK_SIZE_BITS; + This->extBigBlockDepotStart = BLOCK_END_OF_CHAIN; + This->extBigBlockDepotCount = 0; + + StorageImpl_SaveFileHeader(This); + + /* + * Add one block for the big block depot and one block for the properties + */ + size.u.HighPart = 0; + size.u.LowPart = This->bigBlockSize * 3; + BIGBLOCKFILE_SetSize(This->bigBlockFile, size); + + /* + * Initialize the big block depot + */ + bigBlockBuffer = StorageImpl_GetBigBlock(This, 0); + memset(bigBlockBuffer, BLOCK_UNUSED, This->bigBlockSize); + StorageUtl_WriteDWord(bigBlockBuffer, 0, BLOCK_SPECIAL); + StorageUtl_WriteDWord(bigBlockBuffer, sizeof(ULONG), BLOCK_END_OF_CHAIN); + StorageImpl_ReleaseBigBlock(This, bigBlockBuffer); + } + else + { + /* + * Load the header for the file. + */ + hr = StorageImpl_LoadFileHeader(This); + + if (FAILED(hr)) + { + BIGBLOCKFILE_Destructor(This->bigBlockFile); + + return hr; + } + } + + /* + * There is no block depot cached yet. + */ + This->indexBlockDepotCached = 0xFFFFFFFF; + + /* + * Start searching for free blocks with block 0. + */ + This->prevFreeBlock = 0; + + /* + * Create the block chain abstractions. + */ + if(!(This->rootBlockChain = + BlockChainStream_Construct(This, &This->rootStartBlock, PROPERTY_NULL))) + return STG_E_READFAULT; + + if(!(This->smallBlockDepotChain = + BlockChainStream_Construct(This, &This->smallBlockDepotStart, + PROPERTY_NULL))) + return STG_E_READFAULT; + + /* + * Write the root property + */ + if (fileCreate) + { + StgProperty rootProp; + /* + * Initialize the property chain + */ + memset(&rootProp, 0, sizeof(rootProp)); + MultiByteToWideChar( CP_ACP, 0, rootPropertyName, -1, rootProp.name, + sizeof(rootProp.name)/sizeof(WCHAR) ); + rootProp.sizeOfNameString = (strlenW(rootProp.name)+1) * sizeof(WCHAR); + rootProp.propertyType = PROPTYPE_ROOT; + rootProp.previousProperty = PROPERTY_NULL; + rootProp.nextProperty = PROPERTY_NULL; + rootProp.dirProperty = PROPERTY_NULL; + rootProp.startingBlock = BLOCK_END_OF_CHAIN; + rootProp.size.u.HighPart = 0; + rootProp.size.u.LowPart = 0; + + StorageImpl_WriteProperty(This, 0, &rootProp); + } + + /* + * Find the ID of the root in the property sets. + */ + currentPropertyIndex = 0; + + do + { + readSuccessful = StorageImpl_ReadProperty( + This, + currentPropertyIndex, + ¤tProperty); + + if (readSuccessful) + { + if ( (currentProperty.sizeOfNameString != 0 ) && + (currentProperty.propertyType == PROPTYPE_ROOT) ) + { + This->base.rootPropertySetIndex = currentPropertyIndex; + } + } + + currentPropertyIndex++; + + } while (readSuccessful && (This->base.rootPropertySetIndex == PROPERTY_NULL) ); + + if (!readSuccessful) + { + /* TODO CLEANUP */ + return STG_E_READFAULT; + } + + /* + * Create the block chain abstraction for the small block root chain. + */ + if(!(This->smallBlockRootChain = + BlockChainStream_Construct(This, NULL, This->base.rootPropertySetIndex))) + return STG_E_READFAULT; + + return hr; +} + +void StorageImpl_Destroy(StorageBaseImpl* iface) +{ + StorageImpl *This = (StorageImpl*) iface; + TRACE("(%p)\n", This); + + HeapFree(GetProcessHeap(), 0, This->pwcsName); + + BlockChainStream_Destroy(This->smallBlockRootChain); + BlockChainStream_Destroy(This->rootBlockChain); + BlockChainStream_Destroy(This->smallBlockDepotChain); + + BIGBLOCKFILE_Destructor(This->bigBlockFile); + HeapFree(GetProcessHeap(), 0, This); +} + +/****************************************************************************** + * Storage32Impl_GetNextFreeBigBlock + * + * Returns the index of the next free big block. + * If the big block depot is filled, this method will enlarge it. + * + */ +ULONG StorageImpl_GetNextFreeBigBlock( + StorageImpl* This) +{ + ULONG depotBlockIndexPos; + void *depotBuffer; + ULONG depotBlockOffset; + ULONG blocksPerDepot = This->bigBlockSize / sizeof(ULONG); + ULONG nextBlockIndex = BLOCK_SPECIAL; + int depotIndex = 0; + ULONG freeBlock = BLOCK_UNUSED; + + depotIndex = This->prevFreeBlock / blocksPerDepot; + depotBlockOffset = (This->prevFreeBlock % blocksPerDepot) * sizeof(ULONG); + + /* + * Scan the entire big block depot until we find a block marked free + */ + while (nextBlockIndex != BLOCK_UNUSED) + { + if (depotIndex < COUNT_BBDEPOTINHEADER) + { + depotBlockIndexPos = This->bigBlockDepotStart[depotIndex]; + + /* + * Grow the primary depot. + */ + if (depotBlockIndexPos == BLOCK_UNUSED) + { + depotBlockIndexPos = depotIndex*blocksPerDepot; + + /* + * Add a block depot. + */ + Storage32Impl_AddBlockDepot(This, depotBlockIndexPos); + This->bigBlockDepotCount++; + This->bigBlockDepotStart[depotIndex] = depotBlockIndexPos; + + /* + * Flag it as a block depot. + */ + StorageImpl_SetNextBlockInChain(This, + depotBlockIndexPos, + BLOCK_SPECIAL); + + /* Save new header information. + */ + StorageImpl_SaveFileHeader(This); + } + } + else + { + depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotIndex); + + if (depotBlockIndexPos == BLOCK_UNUSED) + { + /* + * Grow the extended depot. + */ + ULONG extIndex = BLOCK_UNUSED; + ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER; + ULONG extBlockOffset = numExtBlocks % (blocksPerDepot - 1); + + if (extBlockOffset == 0) + { + /* We need an extended block. + */ + extIndex = Storage32Impl_AddExtBlockDepot(This); + This->extBigBlockDepotCount++; + depotBlockIndexPos = extIndex + 1; + } + else + depotBlockIndexPos = depotIndex * blocksPerDepot; + + /* + * Add a block depot and mark it in the extended block. + */ + Storage32Impl_AddBlockDepot(This, depotBlockIndexPos); + This->bigBlockDepotCount++; + Storage32Impl_SetExtDepotBlock(This, depotIndex, depotBlockIndexPos); + + /* Flag the block depot. + */ + StorageImpl_SetNextBlockInChain(This, + depotBlockIndexPos, + BLOCK_SPECIAL); + + /* If necessary, flag the extended depot block. + */ + if (extIndex != BLOCK_UNUSED) + StorageImpl_SetNextBlockInChain(This, extIndex, BLOCK_EXTBBDEPOT); + + /* Save header information. + */ + StorageImpl_SaveFileHeader(This); + } + } + + depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos); + + if (depotBuffer != 0) + { + while ( ( (depotBlockOffset/sizeof(ULONG) ) < blocksPerDepot) && + ( nextBlockIndex != BLOCK_UNUSED)) + { + StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex); + + if (nextBlockIndex == BLOCK_UNUSED) + { + freeBlock = (depotIndex * blocksPerDepot) + + (depotBlockOffset/sizeof(ULONG)); + } + + depotBlockOffset += sizeof(ULONG); + } + + StorageImpl_ReleaseBigBlock(This, depotBuffer); + } + + depotIndex++; + depotBlockOffset = 0; + } + + This->prevFreeBlock = freeBlock; + + return freeBlock; +} + +/****************************************************************************** + * Storage32Impl_AddBlockDepot + * + * This will create a depot block, essentially it is a block initialized + * to BLOCK_UNUSEDs. + */ +void Storage32Impl_AddBlockDepot(StorageImpl* This, ULONG blockIndex) +{ + BYTE* blockBuffer; + + blockBuffer = StorageImpl_GetBigBlock(This, blockIndex); + + /* + * Initialize blocks as free + */ + memset(blockBuffer, BLOCK_UNUSED, This->bigBlockSize); + + StorageImpl_ReleaseBigBlock(This, blockBuffer); +} + +/****************************************************************************** + * Storage32Impl_GetExtDepotBlock + * + * Returns the index of the block that corresponds to the specified depot + * index. This method is only for depot indexes equal or greater than + * COUNT_BBDEPOTINHEADER. + */ +ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, ULONG depotIndex) +{ + ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1; + ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER; + ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock; + ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock; + ULONG blockIndex = BLOCK_UNUSED; + ULONG extBlockIndex = This->extBigBlockDepotStart; + + assert(depotIndex >= COUNT_BBDEPOTINHEADER); + + if (This->extBigBlockDepotStart == BLOCK_END_OF_CHAIN) + return BLOCK_UNUSED; + + while (extBlockCount > 0) + { + extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex); + extBlockCount--; + } + + if (extBlockIndex != BLOCK_UNUSED) + { + BYTE* depotBuffer; + + depotBuffer = StorageImpl_GetROBigBlock(This, extBlockIndex); + + if (depotBuffer != 0) + { + StorageUtl_ReadDWord(depotBuffer, + extBlockOffset * sizeof(ULONG), + &blockIndex); + + StorageImpl_ReleaseBigBlock(This, depotBuffer); + } + } + + return blockIndex; +} + +/****************************************************************************** + * Storage32Impl_SetExtDepotBlock + * + * Associates the specified block index to the specified depot index. + * This method is only for depot indexes equal or greater than + * COUNT_BBDEPOTINHEADER. + */ +void Storage32Impl_SetExtDepotBlock(StorageImpl* This, + ULONG depotIndex, + ULONG blockIndex) +{ + ULONG depotBlocksPerExtBlock = (This->bigBlockSize / sizeof(ULONG)) - 1; + ULONG numExtBlocks = depotIndex - COUNT_BBDEPOTINHEADER; + ULONG extBlockCount = numExtBlocks / depotBlocksPerExtBlock; + ULONG extBlockOffset = numExtBlocks % depotBlocksPerExtBlock; + ULONG extBlockIndex = This->extBigBlockDepotStart; + + assert(depotIndex >= COUNT_BBDEPOTINHEADER); + + while (extBlockCount > 0) + { + extBlockIndex = Storage32Impl_GetNextExtendedBlock(This, extBlockIndex); + extBlockCount--; + } + + if (extBlockIndex != BLOCK_UNUSED) + { + BYTE* depotBuffer; + + depotBuffer = StorageImpl_GetBigBlock(This, extBlockIndex); + + if (depotBuffer != 0) + { + StorageUtl_WriteDWord(depotBuffer, + extBlockOffset * sizeof(ULONG), + blockIndex); + + StorageImpl_ReleaseBigBlock(This, depotBuffer); + } + } +} + +/****************************************************************************** + * Storage32Impl_AddExtBlockDepot + * + * Creates an extended depot block. + */ +ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This) +{ + ULONG numExtBlocks = This->extBigBlockDepotCount; + ULONG nextExtBlock = This->extBigBlockDepotStart; + BYTE* depotBuffer = NULL; + ULONG index = BLOCK_UNUSED; + ULONG nextBlockOffset = This->bigBlockSize - sizeof(ULONG); + ULONG blocksPerDepotBlock = This->bigBlockSize / sizeof(ULONG); + ULONG depotBlocksPerExtBlock = blocksPerDepotBlock - 1; + + index = (COUNT_BBDEPOTINHEADER + (numExtBlocks * depotBlocksPerExtBlock)) * + blocksPerDepotBlock; + + if ((numExtBlocks == 0) && (nextExtBlock == BLOCK_END_OF_CHAIN)) + { + /* + * The first extended block. + */ + This->extBigBlockDepotStart = index; + } + else + { + unsigned int i; + /* + * Follow the chain to the last one. + */ + for (i = 0; i < (numExtBlocks - 1); i++) + { + nextExtBlock = Storage32Impl_GetNextExtendedBlock(This, nextExtBlock); + } + + /* + * Add the new extended block to the chain. + */ + depotBuffer = StorageImpl_GetBigBlock(This, nextExtBlock); + StorageUtl_WriteDWord(depotBuffer, nextBlockOffset, index); + StorageImpl_ReleaseBigBlock(This, depotBuffer); + } + + /* + * Initialize this block. + */ + depotBuffer = StorageImpl_GetBigBlock(This, index); + memset(depotBuffer, BLOCK_UNUSED, This->bigBlockSize); + StorageImpl_ReleaseBigBlock(This, depotBuffer); + + return index; +} + +/****************************************************************************** + * Storage32Impl_FreeBigBlock + * + * This method will flag the specified block as free in the big block depot. + */ +void StorageImpl_FreeBigBlock( + StorageImpl* This, + ULONG blockIndex) +{ + StorageImpl_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED); + + if (blockIndex < This->prevFreeBlock) + This->prevFreeBlock = blockIndex; +} + +/************************************************************************ + * Storage32Impl_GetNextBlockInChain + * + * This method will retrieve the block index of the next big block in + * in the chain. + * + * Params: This - Pointer to the Storage object. + * blockIndex - Index of the block to retrieve the chain + * for. + * nextBlockIndex - receives the return value. + * + * Returns: This method returns the index of the next block in the chain. + * It will return the constants: + * BLOCK_SPECIAL - If the block given was not part of a + * chain. + * BLOCK_END_OF_CHAIN - If the block given was the last in + * a chain. + * BLOCK_UNUSED - If the block given was not past of a chain + * and is available. + * BLOCK_EXTBBDEPOT - This block is part of the extended + * big block depot. + * + * See Windows documentation for more details on IStorage methods. + */ +HRESULT StorageImpl_GetNextBlockInChain( + StorageImpl* This, + ULONG blockIndex, + ULONG* nextBlockIndex) +{ + ULONG offsetInDepot = blockIndex * sizeof (ULONG); + ULONG depotBlockCount = offsetInDepot / This->bigBlockSize; + ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize; + void* depotBuffer; + ULONG depotBlockIndexPos; + int index; + + *nextBlockIndex = BLOCK_SPECIAL; + + if(depotBlockCount >= This->bigBlockDepotCount) + { + WARN("depotBlockCount %ld, bigBlockDepotCount %ld\n", depotBlockCount, + This->bigBlockDepotCount); + return STG_E_READFAULT; + } + + /* + * Cache the currently accessed depot block. + */ + if (depotBlockCount != This->indexBlockDepotCached) + { + This->indexBlockDepotCached = depotBlockCount; + + if (depotBlockCount < COUNT_BBDEPOTINHEADER) + { + depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount]; + } + else + { + /* + * We have to look in the extended depot. + */ + depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount); + } + + depotBuffer = StorageImpl_GetROBigBlock(This, depotBlockIndexPos); + + if (!depotBuffer) + return STG_E_READFAULT; + + for (index = 0; index < NUM_BLOCKS_PER_DEPOT_BLOCK; index++) + { + StorageUtl_ReadDWord(depotBuffer, index*sizeof(ULONG), nextBlockIndex); + This->blockDepotCached[index] = *nextBlockIndex; + } + StorageImpl_ReleaseBigBlock(This, depotBuffer); + } + + *nextBlockIndex = This->blockDepotCached[depotBlockOffset/sizeof(ULONG)]; + + return S_OK; +} + +/****************************************************************************** + * Storage32Impl_GetNextExtendedBlock + * + * Given an extended block this method will return the next extended block. + * + * NOTES: + * The last ULONG of an extended block is the block index of the next + * extended block. Extended blocks are marked as BLOCK_EXTBBDEPOT in the + * depot. + * + * Return values: + * - The index of the next extended block + * - BLOCK_UNUSED: there is no next extended block. + * - Any other return values denotes failure. + */ +ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, ULONG blockIndex) +{ + ULONG nextBlockIndex = BLOCK_SPECIAL; + ULONG depotBlockOffset = This->bigBlockSize - sizeof(ULONG); + void* depotBuffer; + + depotBuffer = StorageImpl_GetROBigBlock(This, blockIndex); + + if (depotBuffer!=0) + { + StorageUtl_ReadDWord(depotBuffer, depotBlockOffset, &nextBlockIndex); + + StorageImpl_ReleaseBigBlock(This, depotBuffer); + } + + return nextBlockIndex; +} + +/****************************************************************************** + * Storage32Impl_SetNextBlockInChain + * + * This method will write the index of the specified block's next block + * in the big block depot. + * + * For example: to create the chain 3 -> 1 -> 7 -> End of Chain + * do the following + * + * Storage32Impl_SetNextBlockInChain(This, 3, 1); + * Storage32Impl_SetNextBlockInChain(This, 1, 7); + * Storage32Impl_SetNextBlockInChain(This, 7, BLOCK_END_OF_CHAIN); + * + */ +void StorageImpl_SetNextBlockInChain( + StorageImpl* This, + ULONG blockIndex, + ULONG nextBlock) +{ + ULONG offsetInDepot = blockIndex * sizeof (ULONG); + ULONG depotBlockCount = offsetInDepot / This->bigBlockSize; + ULONG depotBlockOffset = offsetInDepot % This->bigBlockSize; + ULONG depotBlockIndexPos; + void* depotBuffer; + + assert(depotBlockCount < This->bigBlockDepotCount); + assert(blockIndex != nextBlock); + + if (depotBlockCount < COUNT_BBDEPOTINHEADER) + { + depotBlockIndexPos = This->bigBlockDepotStart[depotBlockCount]; + } + else + { + /* + * We have to look in the extended depot. + */ + depotBlockIndexPos = Storage32Impl_GetExtDepotBlock(This, depotBlockCount); + } + + depotBuffer = StorageImpl_GetBigBlock(This, depotBlockIndexPos); + + if (depotBuffer!=0) + { + StorageUtl_WriteDWord(depotBuffer, depotBlockOffset, nextBlock); + StorageImpl_ReleaseBigBlock(This, depotBuffer); + } + + /* + * Update the cached block depot, if necessary. + */ + if (depotBlockCount == This->indexBlockDepotCached) + { + This->blockDepotCached[depotBlockOffset/sizeof(ULONG)] = nextBlock; + } +} + +/****************************************************************************** + * Storage32Impl_LoadFileHeader + * + * This method will read in the file header, i.e. big block index -1. + */ +HRESULT StorageImpl_LoadFileHeader( + StorageImpl* This) +{ + HRESULT hr = STG_E_FILENOTFOUND; + void* headerBigBlock = NULL; + int index; + + /* + * Get a pointer to the big block of data containing the header. + */ + headerBigBlock = StorageImpl_GetROBigBlock(This, -1); + + /* + * Extract the information from the header. + */ + if (headerBigBlock!=0) + { + /* + * Check for the "magic number" signature and return an error if it is not + * found. + */ + if (memcmp(headerBigBlock, STORAGE_oldmagic, sizeof(STORAGE_oldmagic))==0) + { + StorageImpl_ReleaseBigBlock(This, headerBigBlock); + return STG_E_OLDFORMAT; + } + + if (memcmp(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic))!=0) + { + StorageImpl_ReleaseBigBlock(This, headerBigBlock); + return STG_E_INVALIDHEADER; + } + + StorageUtl_ReadWord( + headerBigBlock, + OFFSET_BIGBLOCKSIZEBITS, + &This->bigBlockSizeBits); + + StorageUtl_ReadWord( + headerBigBlock, + OFFSET_SMALLBLOCKSIZEBITS, + &This->smallBlockSizeBits); + + StorageUtl_ReadDWord( + headerBigBlock, + OFFSET_BBDEPOTCOUNT, + &This->bigBlockDepotCount); + + StorageUtl_ReadDWord( + headerBigBlock, + OFFSET_ROOTSTARTBLOCK, + &This->rootStartBlock); + + StorageUtl_ReadDWord( + headerBigBlock, + OFFSET_SBDEPOTSTART, + &This->smallBlockDepotStart); + + StorageUtl_ReadDWord( + headerBigBlock, + OFFSET_EXTBBDEPOTSTART, + &This->extBigBlockDepotStart); + + StorageUtl_ReadDWord( + headerBigBlock, + OFFSET_EXTBBDEPOTCOUNT, + &This->extBigBlockDepotCount); + + for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++) + { + StorageUtl_ReadDWord( + headerBigBlock, + OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index), + &(This->bigBlockDepotStart[index])); + } + + /* + * Make the bitwise arithmetic to get the size of the blocks in bytes. + */ + if ((1 << 2) == 4) + { + This->bigBlockSize = 0x000000001 << (DWORD)This->bigBlockSizeBits; + This->smallBlockSize = 0x000000001 << (DWORD)This->smallBlockSizeBits; + } + else + { + This->bigBlockSize = 0x000000001 >> (DWORD)This->bigBlockSizeBits; + This->smallBlockSize = 0x000000001 >> (DWORD)This->smallBlockSizeBits; + } + + /* + * Right now, the code is making some assumptions about the size of the + * blocks, just make sure they are what we're expecting. + */ + if (This->bigBlockSize != DEF_BIG_BLOCK_SIZE || + This->smallBlockSize != DEF_SMALL_BLOCK_SIZE) + { + WARN("Broken OLE storage file\n"); + hr = STG_E_INVALIDHEADER; + } + else + hr = S_OK; + + /* + * Release the block. + */ + StorageImpl_ReleaseBigBlock(This, headerBigBlock); + } + + return hr; +} + +/****************************************************************************** + * Storage32Impl_SaveFileHeader + * + * This method will save to the file the header, i.e. big block -1. + */ +void StorageImpl_SaveFileHeader( + StorageImpl* This) +{ + BYTE headerBigBlock[BIG_BLOCK_SIZE]; + int index; + BOOL success; + + /* + * Get a pointer to the big block of data containing the header. + */ + success = StorageImpl_ReadBigBlock(This, -1, headerBigBlock); + + /* + * If the block read failed, the file is probably new. + */ + if (!success) + { + /* + * Initialize for all unknown fields. + */ + memset(headerBigBlock, 0, BIG_BLOCK_SIZE); + + /* + * Initialize the magic number. + */ + memcpy(headerBigBlock, STORAGE_magic, sizeof(STORAGE_magic)); + + /* + * And a bunch of things we don't know what they mean + */ + StorageUtl_WriteWord(headerBigBlock, 0x18, 0x3b); + StorageUtl_WriteWord(headerBigBlock, 0x1a, 0x3); + StorageUtl_WriteWord(headerBigBlock, 0x1c, (WORD)-2); + StorageUtl_WriteDWord(headerBigBlock, 0x38, (DWORD)0x1000); + } + + /* + * Write the information to the header. + */ + StorageUtl_WriteWord( + headerBigBlock, + OFFSET_BIGBLOCKSIZEBITS, + This->bigBlockSizeBits); + + StorageUtl_WriteWord( + headerBigBlock, + OFFSET_SMALLBLOCKSIZEBITS, + This->smallBlockSizeBits); + + StorageUtl_WriteDWord( + headerBigBlock, + OFFSET_BBDEPOTCOUNT, + This->bigBlockDepotCount); + + StorageUtl_WriteDWord( + headerBigBlock, + OFFSET_ROOTSTARTBLOCK, + This->rootStartBlock); + + StorageUtl_WriteDWord( + headerBigBlock, + OFFSET_SBDEPOTSTART, + This->smallBlockDepotStart); + + StorageUtl_WriteDWord( + headerBigBlock, + OFFSET_SBDEPOTCOUNT, + This->smallBlockDepotChain ? + BlockChainStream_GetCount(This->smallBlockDepotChain) : 0); + + StorageUtl_WriteDWord( + headerBigBlock, + OFFSET_EXTBBDEPOTSTART, + This->extBigBlockDepotStart); + + StorageUtl_WriteDWord( + headerBigBlock, + OFFSET_EXTBBDEPOTCOUNT, + This->extBigBlockDepotCount); + + for (index = 0; index < COUNT_BBDEPOTINHEADER; index ++) + { + StorageUtl_WriteDWord( + headerBigBlock, + OFFSET_BBDEPOTSTART + (sizeof(ULONG)*index), + (This->bigBlockDepotStart[index])); + } + + /* + * Write the big block back to the file. + */ + StorageImpl_WriteBigBlock(This, -1, headerBigBlock); +} + +/****************************************************************************** + * Storage32Impl_ReadProperty + * + * This method will read the specified property from the property chain. + */ +BOOL StorageImpl_ReadProperty( + StorageImpl* This, + ULONG index, + StgProperty* buffer) +{ + BYTE currentProperty[PROPSET_BLOCK_SIZE]; + ULARGE_INTEGER offsetInPropSet; + BOOL readSuccessful; + ULONG bytesRead; + + offsetInPropSet.u.HighPart = 0; + offsetInPropSet.u.LowPart = index * PROPSET_BLOCK_SIZE; + + readSuccessful = BlockChainStream_ReadAt( + This->rootBlockChain, + offsetInPropSet, + PROPSET_BLOCK_SIZE, + currentProperty, + &bytesRead); + + if (readSuccessful) + { + /* replace the name of root entry (often "Root Entry") by the file name */ + WCHAR *propName = (index == This->base.rootPropertySetIndex) ? + This->filename : (WCHAR *)currentProperty+OFFSET_PS_NAME; + + memset(buffer->name, 0, sizeof(buffer->name)); + memcpy( + buffer->name, + propName, + PROPERTY_NAME_BUFFER_LEN ); + TRACE("storage name: %s\n", debugstr_w(buffer->name)); + + memcpy(&buffer->propertyType, currentProperty + OFFSET_PS_PROPERTYTYPE, 1); + + StorageUtl_ReadWord( + currentProperty, + OFFSET_PS_NAMELENGTH, + &buffer->sizeOfNameString); + + StorageUtl_ReadDWord( + currentProperty, + OFFSET_PS_PREVIOUSPROP, + &buffer->previousProperty); + + StorageUtl_ReadDWord( + currentProperty, + OFFSET_PS_NEXTPROP, + &buffer->nextProperty); + + StorageUtl_ReadDWord( + currentProperty, + OFFSET_PS_DIRPROP, + &buffer->dirProperty); + + StorageUtl_ReadGUID( + currentProperty, + OFFSET_PS_GUID, + &buffer->propertyUniqueID); + + StorageUtl_ReadDWord( + currentProperty, + OFFSET_PS_TSS1, + &buffer->timeStampS1); + + StorageUtl_ReadDWord( + currentProperty, + OFFSET_PS_TSD1, + &buffer->timeStampD1); + + StorageUtl_ReadDWord( + currentProperty, + OFFSET_PS_TSS2, + &buffer->timeStampS2); + + StorageUtl_ReadDWord( + currentProperty, + OFFSET_PS_TSD2, + &buffer->timeStampD2); + + StorageUtl_ReadDWord( + currentProperty, + OFFSET_PS_STARTBLOCK, + &buffer->startingBlock); + + StorageUtl_ReadDWord( + currentProperty, + OFFSET_PS_SIZE, + &buffer->size.u.LowPart); + + buffer->size.u.HighPart = 0; + } + + return readSuccessful; +} + +/********************************************************************* + * Write the specified property into the property chain + */ +BOOL StorageImpl_WriteProperty( + StorageImpl* This, + ULONG index, + StgProperty* buffer) +{ + BYTE currentProperty[PROPSET_BLOCK_SIZE]; + ULARGE_INTEGER offsetInPropSet; + BOOL writeSuccessful; + ULONG bytesWritten; + + offsetInPropSet.u.HighPart = 0; + offsetInPropSet.u.LowPart = index * PROPSET_BLOCK_SIZE; + + memset(currentProperty, 0, PROPSET_BLOCK_SIZE); + + memcpy( + currentProperty + OFFSET_PS_NAME, + buffer->name, + PROPERTY_NAME_BUFFER_LEN ); + + memcpy(currentProperty + OFFSET_PS_PROPERTYTYPE, &buffer->propertyType, 1); + + StorageUtl_WriteWord( + currentProperty, + OFFSET_PS_NAMELENGTH, + buffer->sizeOfNameString); + + StorageUtl_WriteDWord( + currentProperty, + OFFSET_PS_PREVIOUSPROP, + buffer->previousProperty); + + StorageUtl_WriteDWord( + currentProperty, + OFFSET_PS_NEXTPROP, + buffer->nextProperty); + + StorageUtl_WriteDWord( + currentProperty, + OFFSET_PS_DIRPROP, + buffer->dirProperty); + + StorageUtl_WriteGUID( + currentProperty, + OFFSET_PS_GUID, + &buffer->propertyUniqueID); + + StorageUtl_WriteDWord( + currentProperty, + OFFSET_PS_TSS1, + buffer->timeStampS1); + + StorageUtl_WriteDWord( + currentProperty, + OFFSET_PS_TSD1, + buffer->timeStampD1); + + StorageUtl_WriteDWord( + currentProperty, + OFFSET_PS_TSS2, + buffer->timeStampS2); + + StorageUtl_WriteDWord( + currentProperty, + OFFSET_PS_TSD2, + buffer->timeStampD2); + + StorageUtl_WriteDWord( + currentProperty, + OFFSET_PS_STARTBLOCK, + buffer->startingBlock); + + StorageUtl_WriteDWord( + currentProperty, + OFFSET_PS_SIZE, + buffer->size.u.LowPart); + + writeSuccessful = BlockChainStream_WriteAt(This->rootBlockChain, + offsetInPropSet, + PROPSET_BLOCK_SIZE, + currentProperty, + &bytesWritten); + return writeSuccessful; +} + +BOOL StorageImpl_ReadBigBlock( + StorageImpl* This, + ULONG blockIndex, + void* buffer) +{ + void* bigBlockBuffer; + + bigBlockBuffer = StorageImpl_GetROBigBlock(This, blockIndex); + + if (bigBlockBuffer!=0) + { + memcpy(buffer, bigBlockBuffer, This->bigBlockSize); + + StorageImpl_ReleaseBigBlock(This, bigBlockBuffer); + + return TRUE; + } + + return FALSE; +} + +BOOL StorageImpl_WriteBigBlock( + StorageImpl* This, + ULONG blockIndex, + void* buffer) +{ + void* bigBlockBuffer; + + bigBlockBuffer = StorageImpl_GetBigBlock(This, blockIndex); + + if (bigBlockBuffer!=0) + { + memcpy(bigBlockBuffer, buffer, This->bigBlockSize); + + StorageImpl_ReleaseBigBlock(This, bigBlockBuffer); + + return TRUE; + } + + return FALSE; +} + +void* StorageImpl_GetROBigBlock( + StorageImpl* This, + ULONG blockIndex) +{ + return BIGBLOCKFILE_GetROBigBlock(This->bigBlockFile, blockIndex); +} + +void* StorageImpl_GetBigBlock( + StorageImpl* This, + ULONG blockIndex) +{ + return BIGBLOCKFILE_GetBigBlock(This->bigBlockFile, blockIndex); +} + +void StorageImpl_ReleaseBigBlock( + StorageImpl* This, + void* pBigBlock) +{ + BIGBLOCKFILE_ReleaseBigBlock(This->bigBlockFile, pBigBlock); +} + +/****************************************************************************** + * Storage32Impl_SmallBlocksToBigBlocks + * + * This method will convert a small block chain to a big block chain. + * The small block chain will be destroyed. + */ +BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks( + StorageImpl* This, + SmallBlockChainStream** ppsbChain) +{ + ULONG bbHeadOfChain = BLOCK_END_OF_CHAIN; + ULARGE_INTEGER size, offset; + ULONG cbRead, cbWritten, cbTotalRead, cbTotalWritten; + ULONG propertyIndex; + BOOL successRead, successWrite; + StgProperty chainProperty; + BYTE *buffer; + BlockChainStream *bbTempChain = NULL; + BlockChainStream *bigBlockChain = NULL; + + /* + * Create a temporary big block chain that doesn't have + * an associated property. This temporary chain will be + * used to copy data from small blocks to big blocks. + */ + bbTempChain = BlockChainStream_Construct(This, + &bbHeadOfChain, + PROPERTY_NULL); + if(!bbTempChain) return NULL; + /* + * Grow the big block chain. + */ + size = SmallBlockChainStream_GetSize(*ppsbChain); + BlockChainStream_SetSize(bbTempChain, size); + + /* + * Copy the contents of the small block chain to the big block chain + * by small block size increments. + */ + offset.u.LowPart = 0; + offset.u.HighPart = 0; + cbTotalRead = 0; + cbTotalWritten = 0; + + buffer = HeapAlloc(GetProcessHeap(),0,DEF_SMALL_BLOCK_SIZE); + do + { + successRead = SmallBlockChainStream_ReadAt(*ppsbChain, + offset, + DEF_SMALL_BLOCK_SIZE, + buffer, + &cbRead); + cbTotalRead += cbRead; + + successWrite = BlockChainStream_WriteAt(bbTempChain, + offset, + cbRead, + buffer, + &cbWritten); + cbTotalWritten += cbWritten; + + offset.u.LowPart += This->smallBlockSize; + + } while (successRead && successWrite); + HeapFree(GetProcessHeap(),0,buffer); + + assert(cbTotalRead == cbTotalWritten); + + /* + * Destroy the small block chain. + */ + propertyIndex = (*ppsbChain)->ownerPropertyIndex; + size.u.HighPart = 0; + size.u.LowPart = 0; + SmallBlockChainStream_SetSize(*ppsbChain, size); + SmallBlockChainStream_Destroy(*ppsbChain); + *ppsbChain = 0; + + /* + * Change the property information. This chain is now a big block chain + * and it doesn't reside in the small blocks chain anymore. + */ + StorageImpl_ReadProperty(This, propertyIndex, &chainProperty); + + chainProperty.startingBlock = bbHeadOfChain; + + StorageImpl_WriteProperty(This, propertyIndex, &chainProperty); + + /* + * Destroy the temporary propertyless big block chain. + * Create a new big block chain associated with this property. + */ + BlockChainStream_Destroy(bbTempChain); + bigBlockChain = BlockChainStream_Construct(This, + NULL, + propertyIndex); + + return bigBlockChain; +} + +void StorageInternalImpl_Destroy( StorageBaseImpl *iface) +{ + StorageInternalImpl* This = (StorageInternalImpl*) iface; + + StorageBaseImpl_Release((IStorage*)This->base.ancestorStorage); + HeapFree(GetProcessHeap(), 0, This); +} + +/****************************************************************************** +** +** Storage32InternalImpl_Commit +** +** The non-root storages cannot be opened in transacted mode thus this function +** does nothing. +*/ +HRESULT WINAPI StorageInternalImpl_Commit( + IStorage* iface, + DWORD grfCommitFlags) /* [in] */ +{ + return S_OK; +} + +/****************************************************************************** +** +** Storage32InternalImpl_Revert +** +** The non-root storages cannot be opened in transacted mode thus this function +** does nothing. +*/ +HRESULT WINAPI StorageInternalImpl_Revert( + IStorage* iface) +{ + return S_OK; +} + +void IEnumSTATSTGImpl_Destroy(IEnumSTATSTGImpl* This) +{ + IStorage_Release((IStorage*)This->parentStorage); + HeapFree(GetProcessHeap(), 0, This->stackToVisit); + HeapFree(GetProcessHeap(), 0, This); +} + +HRESULT WINAPI IEnumSTATSTGImpl_QueryInterface( + IEnumSTATSTG* iface, + REFIID riid, + void** ppvObject) +{ + IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; + + /* + * Perform a sanity check on the parameters. + */ + if (ppvObject==0) + return E_INVALIDARG; + + /* + * Initialize the return parameter. + */ + *ppvObject = 0; + + /* + * Compare the riid with the interface IDs implemented by this object. + */ + if (IsEqualGUID(&IID_IUnknown, riid) || + IsEqualGUID(&IID_IStorage, riid)) + { + *ppvObject = (IEnumSTATSTG*)This; + IEnumSTATSTG_AddRef((IEnumSTATSTG*)This); + return S_OK; + } + + return E_NOINTERFACE; +} + +ULONG WINAPI IEnumSTATSTGImpl_AddRef( + IEnumSTATSTG* iface) +{ + IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; + return InterlockedIncrement(&This->ref); +} + +ULONG WINAPI IEnumSTATSTGImpl_Release( + IEnumSTATSTG* iface) +{ + IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; + + ULONG newRef; + + newRef = InterlockedDecrement(&This->ref); + + /* + * If the reference count goes down to 0, perform suicide. + */ + if (newRef==0) + { + IEnumSTATSTGImpl_Destroy(This); + } + + return newRef; +} + +HRESULT WINAPI IEnumSTATSTGImpl_Next( + IEnumSTATSTG* iface, + ULONG celt, + STATSTG* rgelt, + ULONG* pceltFetched) +{ + IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; + + StgProperty currentProperty; + STATSTG* currentReturnStruct = rgelt; + ULONG objectFetched = 0; + ULONG currentSearchNode; + + /* + * Perform a sanity check on the parameters. + */ + if ( (rgelt==0) || ( (celt!=1) && (pceltFetched==0) ) ) + return E_INVALIDARG; + + /* + * To avoid the special case, get another pointer to a ULONG value if + * the caller didn't supply one. + */ + if (pceltFetched==0) + pceltFetched = &objectFetched; + + /* + * Start the iteration, we will iterate until we hit the end of the + * linked list or until we hit the number of items to iterate through + */ + *pceltFetched = 0; + + /* + * Start with the node at the top of the stack. + */ + currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); + + while ( ( *pceltFetched < celt) && + ( currentSearchNode!=PROPERTY_NULL) ) + { + /* + * Remove the top node from the stack + */ + IEnumSTATSTGImpl_PopSearchNode(This, TRUE); + + /* + * Read the property from the storage. + */ + StorageImpl_ReadProperty(This->parentStorage, + currentSearchNode, + ¤tProperty); + + /* + * Copy the information to the return buffer. + */ + StorageUtl_CopyPropertyToSTATSTG(currentReturnStruct, + ¤tProperty, + STATFLAG_DEFAULT); + + /* + * Step to the next item in the iteration + */ + (*pceltFetched)++; + currentReturnStruct++; + + /* + * Push the next search node in the search stack. + */ + IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty); + + /* + * continue the iteration. + */ + currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); + } + + if (*pceltFetched == celt) + return S_OK; + + return S_FALSE; +} + + +HRESULT WINAPI IEnumSTATSTGImpl_Skip( + IEnumSTATSTG* iface, + ULONG celt) +{ + IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; + + StgProperty currentProperty; + ULONG objectFetched = 0; + ULONG currentSearchNode; + + /* + * Start with the node at the top of the stack. + */ + currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); + + while ( (objectFetched < celt) && + (currentSearchNode!=PROPERTY_NULL) ) + { + /* + * Remove the top node from the stack + */ + IEnumSTATSTGImpl_PopSearchNode(This, TRUE); + + /* + * Read the property from the storage. + */ + StorageImpl_ReadProperty(This->parentStorage, + currentSearchNode, + ¤tProperty); + + /* + * Step to the next item in the iteration + */ + objectFetched++; + + /* + * Push the next search node in the search stack. + */ + IEnumSTATSTGImpl_PushSearchNode(This, currentProperty.nextProperty); + + /* + * continue the iteration. + */ + currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); + } + + if (objectFetched == celt) + return S_OK; + + return S_FALSE; +} + +HRESULT WINAPI IEnumSTATSTGImpl_Reset( + IEnumSTATSTG* iface) +{ + IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; + + StgProperty rootProperty; + BOOL readSuccessful; + + /* + * Re-initialize the search stack to an empty stack + */ + This->stackSize = 0; + + /* + * Read the root property from the storage. + */ + readSuccessful = StorageImpl_ReadProperty( + This->parentStorage, + This->firstPropertyNode, + &rootProperty); + + if (readSuccessful) + { + assert(rootProperty.sizeOfNameString!=0); + + /* + * Push the search node in the search stack. + */ + IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.dirProperty); + } + + return S_OK; +} + +HRESULT WINAPI IEnumSTATSTGImpl_Clone( + IEnumSTATSTG* iface, + IEnumSTATSTG** ppenum) +{ + IEnumSTATSTGImpl* const This=(IEnumSTATSTGImpl*)iface; + + IEnumSTATSTGImpl* newClone; + + /* + * Perform a sanity check on the parameters. + */ + if (ppenum==0) + return E_INVALIDARG; + + newClone = IEnumSTATSTGImpl_Construct(This->parentStorage, + This->firstPropertyNode); + + + /* + * The new clone enumeration must point to the same current node as + * the ole one. + */ + newClone->stackSize = This->stackSize ; + newClone->stackMaxSize = This->stackMaxSize ; + newClone->stackToVisit = + HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG) * newClone->stackMaxSize); + + memcpy( + newClone->stackToVisit, + This->stackToVisit, + sizeof(ULONG) * newClone->stackSize); + + *ppenum = (IEnumSTATSTG*)newClone; + + /* + * Don't forget to nail down a reference to the clone before + * returning it. + */ + IEnumSTATSTGImpl_AddRef(*ppenum); + + return S_OK; +} + +INT IEnumSTATSTGImpl_FindParentProperty( + IEnumSTATSTGImpl *This, + ULONG childProperty, + StgProperty *currentProperty, + ULONG *thisNodeId) +{ + ULONG currentSearchNode; + ULONG foundNode; + + /* + * To avoid the special case, get another pointer to a ULONG value if + * the caller didn't supply one. + */ + if (thisNodeId==0) + thisNodeId = &foundNode; + + /* + * Start with the node at the top of the stack. + */ + currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); + + + while (currentSearchNode!=PROPERTY_NULL) + { + /* + * Store the current node in the returned parameters + */ + *thisNodeId = currentSearchNode; + + /* + * Remove the top node from the stack + */ + IEnumSTATSTGImpl_PopSearchNode(This, TRUE); + + /* + * Read the property from the storage. + */ + StorageImpl_ReadProperty( + This->parentStorage, + currentSearchNode, + currentProperty); + + if (currentProperty->previousProperty == childProperty) + return PROPERTY_RELATION_PREVIOUS; + + else if (currentProperty->nextProperty == childProperty) + return PROPERTY_RELATION_NEXT; + + else if (currentProperty->dirProperty == childProperty) + return PROPERTY_RELATION_DIR; + + /* + * Push the next search node in the search stack. + */ + IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty); + + /* + * continue the iteration. + */ + currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); + } + + return PROPERTY_NULL; +} + +ULONG IEnumSTATSTGImpl_FindProperty( + IEnumSTATSTGImpl* This, + const OLECHAR* lpszPropName, + StgProperty* currentProperty) +{ + ULONG currentSearchNode; + + /* + * Start with the node at the top of the stack. + */ + currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); + + while (currentSearchNode!=PROPERTY_NULL) + { + /* + * Remove the top node from the stack + */ + IEnumSTATSTGImpl_PopSearchNode(This, TRUE); + + /* + * Read the property from the storage. + */ + StorageImpl_ReadProperty(This->parentStorage, + currentSearchNode, + currentProperty); + + if ( propertyNameCmp( + (const OLECHAR*)currentProperty->name, + (const OLECHAR*)lpszPropName) == 0) + return currentSearchNode; + + /* + * Push the next search node in the search stack. + */ + IEnumSTATSTGImpl_PushSearchNode(This, currentProperty->nextProperty); + + /* + * continue the iteration. + */ + currentSearchNode = IEnumSTATSTGImpl_PopSearchNode(This, FALSE); + } + + return PROPERTY_NULL; +} + +void IEnumSTATSTGImpl_PushSearchNode( + IEnumSTATSTGImpl* This, + ULONG nodeToPush) +{ + StgProperty rootProperty; + BOOL readSuccessful; + + /* + * First, make sure we're not trying to push an unexisting node. + */ + if (nodeToPush==PROPERTY_NULL) + return; + + /* + * First push the node to the stack + */ + if (This->stackSize == This->stackMaxSize) + { + This->stackMaxSize += ENUMSTATSGT_SIZE_INCREMENT; + + This->stackToVisit = HeapReAlloc( + GetProcessHeap(), + 0, + This->stackToVisit, + sizeof(ULONG) * This->stackMaxSize); + } + + This->stackToVisit[This->stackSize] = nodeToPush; + This->stackSize++; + + /* + * Read the root property from the storage. + */ + readSuccessful = StorageImpl_ReadProperty( + This->parentStorage, + nodeToPush, + &rootProperty); + + if (readSuccessful) + { + assert(rootProperty.sizeOfNameString!=0); + + /* + * Push the previous search node in the search stack. + */ + IEnumSTATSTGImpl_PushSearchNode(This, rootProperty.previousProperty); + } +} + +ULONG IEnumSTATSTGImpl_PopSearchNode( + IEnumSTATSTGImpl* This, + BOOL remove) +{ + ULONG topNode; + + if (This->stackSize == 0) + return PROPERTY_NULL; + + topNode = This->stackToVisit[This->stackSize-1]; + + if (remove) + This->stackSize--; + + return topNode; +} + +/* + * Virtual function table for the IEnumSTATSTGImpl class. + */ +static IEnumSTATSTGVtbl IEnumSTATSTGImpl_Vtbl = +{ + IEnumSTATSTGImpl_QueryInterface, + IEnumSTATSTGImpl_AddRef, + IEnumSTATSTGImpl_Release, + IEnumSTATSTGImpl_Next, + IEnumSTATSTGImpl_Skip, + IEnumSTATSTGImpl_Reset, + IEnumSTATSTGImpl_Clone +}; + +/****************************************************************************** +** IEnumSTATSTGImpl implementation +*/ + +IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct( + StorageImpl* parentStorage, + ULONG firstPropertyNode) +{ + IEnumSTATSTGImpl* newEnumeration; + + newEnumeration = HeapAlloc(GetProcessHeap(), 0, sizeof(IEnumSTATSTGImpl)); + + if (newEnumeration!=0) + { + /* + * Set-up the virtual function table and reference count. + */ + newEnumeration->lpVtbl = &IEnumSTATSTGImpl_Vtbl; + newEnumeration->ref = 0; + + /* + * We want to nail-down the reference to the storage in case the + * enumeration out-lives the storage in the client application. + */ + newEnumeration->parentStorage = parentStorage; + IStorage_AddRef((IStorage*)newEnumeration->parentStorage); + + newEnumeration->firstPropertyNode = firstPropertyNode; + + /* + * Initialize the search stack + */ + newEnumeration->stackSize = 0; + newEnumeration->stackMaxSize = ENUMSTATSGT_SIZE_INCREMENT; + newEnumeration->stackToVisit = + HeapAlloc(GetProcessHeap(), 0, sizeof(ULONG)*ENUMSTATSGT_SIZE_INCREMENT); + + /* + * Make sure the current node of the iterator is the first one. + */ + IEnumSTATSTGImpl_Reset((IEnumSTATSTG*)newEnumeration); + } + + return newEnumeration; +} + +/* + * Virtual function table for the Storage32InternalImpl class. + */ +static IStorageVtbl Storage32InternalImpl_Vtbl = +{ + StorageBaseImpl_QueryInterface, + StorageBaseImpl_AddRef, + StorageBaseImpl_Release, + StorageBaseImpl_CreateStream, + StorageBaseImpl_OpenStream, + StorageImpl_CreateStorage, + StorageBaseImpl_OpenStorage, + StorageImpl_CopyTo, + StorageImpl_MoveElementTo, + StorageInternalImpl_Commit, + StorageInternalImpl_Revert, + StorageBaseImpl_EnumElements, + StorageImpl_DestroyElement, + StorageBaseImpl_RenameElement, + StorageImpl_SetElementTimes, + StorageBaseImpl_SetClass, + StorageImpl_SetStateBits, + StorageBaseImpl_Stat +}; + +/****************************************************************************** +** Storage32InternalImpl implementation +*/ + +StorageInternalImpl* StorageInternalImpl_Construct( + StorageImpl* ancestorStorage, + DWORD openFlags, + ULONG rootPropertyIndex) +{ + StorageInternalImpl* newStorage; + + /* + * Allocate space for the new storage object + */ + newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageInternalImpl)); + + if (newStorage!=0) + { + memset(newStorage, 0, sizeof(StorageInternalImpl)); + + /* + * Initialize the virtual function table. + */ + newStorage->base.lpVtbl = &Storage32InternalImpl_Vtbl; + newStorage->base.v_destructor = &StorageInternalImpl_Destroy; + newStorage->base.openFlags = openFlags; + + /* + * Keep the ancestor storage pointer and nail a reference to it. + */ + newStorage->base.ancestorStorage = ancestorStorage; + StorageBaseImpl_AddRef((IStorage*)(newStorage->base.ancestorStorage)); + + /* + * Keep the index of the root property set for this storage, + */ + newStorage->base.rootPropertySetIndex = rootPropertyIndex; + + return newStorage; + } + + return 0; +} + +/****************************************************************************** +** StorageUtl implementation +*/ + +void StorageUtl_ReadWord(const BYTE* buffer, ULONG offset, WORD* value) +{ + WORD tmp; + + memcpy(&tmp, buffer+offset, sizeof(WORD)); + *value = le16toh(tmp); +} + +void StorageUtl_WriteWord(BYTE* buffer, ULONG offset, WORD value) +{ + value = htole16(value); + memcpy(buffer+offset, &value, sizeof(WORD)); +} + +void StorageUtl_ReadDWord(const BYTE* buffer, ULONG offset, DWORD* value) +{ + DWORD tmp; + + memcpy(&tmp, buffer+offset, sizeof(DWORD)); + *value = le32toh(tmp); +} + +void StorageUtl_WriteDWord(BYTE* buffer, ULONG offset, DWORD value) +{ + value = htole32(value); + memcpy(buffer+offset, &value, sizeof(DWORD)); +} + +void StorageUtl_ReadULargeInteger(const BYTE* buffer, ULONG offset, + ULARGE_INTEGER* value) +{ +#ifdef WORDS_BIGENDIAN + ULARGE_INTEGER tmp; + + memcpy(&tmp, buffer + offset, sizeof(ULARGE_INTEGER)); + value->u.LowPart = htole32(tmp.u.HighPart); + value->u.HighPart = htole32(tmp.u.LowPart); +#else + memcpy(value, buffer + offset, sizeof(ULARGE_INTEGER)); +#endif +} + +void StorageUtl_WriteULargeInteger(BYTE* buffer, ULONG offset, + const ULARGE_INTEGER *value) +{ +#ifdef WORDS_BIGENDIAN + ULARGE_INTEGER tmp; + + tmp.u.LowPart = htole32(value->u.HighPart); + tmp.u.HighPart = htole32(value->u.LowPart); + memcpy(buffer + offset, &tmp, sizeof(ULARGE_INTEGER)); +#else + memcpy(buffer + offset, value, sizeof(ULARGE_INTEGER)); +#endif +} + +void StorageUtl_ReadGUID(const BYTE* buffer, ULONG offset, GUID* value) +{ + StorageUtl_ReadDWord(buffer, offset, &(value->Data1)); + StorageUtl_ReadWord(buffer, offset+4, &(value->Data2)); + StorageUtl_ReadWord(buffer, offset+6, &(value->Data3)); + + memcpy(value->Data4, buffer+offset+8, sizeof(value->Data4)); +} + +void StorageUtl_WriteGUID(BYTE* buffer, ULONG offset, const GUID* value) +{ + StorageUtl_WriteDWord(buffer, offset, value->Data1); + StorageUtl_WriteWord(buffer, offset+4, value->Data2); + StorageUtl_WriteWord(buffer, offset+6, value->Data3); + + memcpy(buffer+offset+8, value->Data4, sizeof(value->Data4)); +} + +void StorageUtl_CopyPropertyToSTATSTG( + STATSTG* destination, + StgProperty* source, + int statFlags) +{ + /* + * The copy of the string occurs only when the flag is not set + */ + if( ((statFlags & STATFLAG_NONAME) != 0) || + (source->name == NULL) || + (source->name[0] == 0) ) + { + destination->pwcsName = 0; + } + else + { + destination->pwcsName = + CoTaskMemAlloc((lstrlenW(source->name)+1)*sizeof(WCHAR)); + + strcpyW((LPWSTR)destination->pwcsName, source->name); + } + + switch (source->propertyType) + { + case PROPTYPE_STORAGE: + case PROPTYPE_ROOT: + destination->type = STGTY_STORAGE; + break; + case PROPTYPE_STREAM: + destination->type = STGTY_STREAM; + break; + default: + destination->type = STGTY_STREAM; + break; + } + + destination->cbSize = source->size; +/* + currentReturnStruct->mtime = {0}; TODO + currentReturnStruct->ctime = {0}; + currentReturnStruct->atime = {0}; +*/ + destination->grfMode = 0; + destination->grfLocksSupported = 0; + destination->clsid = source->propertyUniqueID; + destination->grfStateBits = 0; + destination->reserved = 0; +} + +/****************************************************************************** +** BlockChainStream implementation +*/ + +BlockChainStream* BlockChainStream_Construct( + StorageImpl* parentStorage, + ULONG* headOfStreamPlaceHolder, + ULONG propertyIndex) +{ + BlockChainStream* newStream; + ULONG blockIndex; + + newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(BlockChainStream)); + + newStream->parentStorage = parentStorage; + newStream->headOfStreamPlaceHolder = headOfStreamPlaceHolder; + newStream->ownerPropertyIndex = propertyIndex; + newStream->lastBlockNoInSequence = 0xFFFFFFFF; + newStream->tailIndex = BLOCK_END_OF_CHAIN; + newStream->numBlocks = 0; + + blockIndex = BlockChainStream_GetHeadOfChain(newStream); + + while (blockIndex != BLOCK_END_OF_CHAIN) + { + newStream->numBlocks++; + newStream->tailIndex = blockIndex; + + if(FAILED(StorageImpl_GetNextBlockInChain( + parentStorage, + blockIndex, + &blockIndex))) + { + HeapFree(GetProcessHeap(), 0, newStream); + return NULL; + } + } + + return newStream; +} + +void BlockChainStream_Destroy(BlockChainStream* This) +{ + HeapFree(GetProcessHeap(), 0, This); +} + +/****************************************************************************** + * BlockChainStream_GetHeadOfChain + * + * Returns the head of this stream chain. + * Some special chains don't have properties, their heads are kept in + * This->headOfStreamPlaceHolder. + * + */ +ULONG BlockChainStream_GetHeadOfChain(BlockChainStream* This) +{ + StgProperty chainProperty; + BOOL readSuccessful; + + if (This->headOfStreamPlaceHolder != 0) + return *(This->headOfStreamPlaceHolder); + + if (This->ownerPropertyIndex != PROPERTY_NULL) + { + readSuccessful = StorageImpl_ReadProperty( + This->parentStorage, + This->ownerPropertyIndex, + &chainProperty); + + if (readSuccessful) + { + return chainProperty.startingBlock; + } + } + + return BLOCK_END_OF_CHAIN; +} + +/****************************************************************************** + * BlockChainStream_GetCount + * + * Returns the number of blocks that comprises this chain. + * This is not the size of the stream as the last block may not be full! + * + */ +ULONG BlockChainStream_GetCount(BlockChainStream* This) +{ + ULONG blockIndex; + ULONG count = 0; + + blockIndex = BlockChainStream_GetHeadOfChain(This); + + while (blockIndex != BLOCK_END_OF_CHAIN) + { + count++; + + if(FAILED(StorageImpl_GetNextBlockInChain( + This->parentStorage, + blockIndex, + &blockIndex))) + return 0; + } + + return count; +} + +/****************************************************************************** + * BlockChainStream_ReadAt + * + * Reads a specified number of bytes from this chain at the specified offset. + * bytesRead may be NULL. + * Failure will be returned if the specified number of bytes has not been read. + */ +BOOL BlockChainStream_ReadAt(BlockChainStream* This, + ULARGE_INTEGER offset, + ULONG size, + void* buffer, + ULONG* bytesRead) +{ + ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize; + ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->bigBlockSize; + ULONG bytesToReadInBuffer; + ULONG blockIndex; + BYTE* bufferWalker; + BYTE* bigBlockBuffer; + + /* + * Find the first block in the stream that contains part of the buffer. + */ + if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) || + (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) || + (blockNoInSequence < This->lastBlockNoInSequence) ) + { + blockIndex = BlockChainStream_GetHeadOfChain(This); + This->lastBlockNoInSequence = blockNoInSequence; + } + else + { + ULONG temp = blockNoInSequence; + + blockIndex = This->lastBlockNoInSequenceIndex; + blockNoInSequence -= This->lastBlockNoInSequence; + This->lastBlockNoInSequence = temp; + } + + while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN)) + { + if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex))) + return FALSE; + blockNoInSequence--; + } + + This->lastBlockNoInSequenceIndex = blockIndex; + + /* + * Start reading the buffer. + */ + *bytesRead = 0; + bufferWalker = buffer; + + while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) ) + { + /* + * Calculate how many bytes we can copy from this big block. + */ + bytesToReadInBuffer = + min(This->parentStorage->bigBlockSize - offsetInBlock, size); + + /* + * Copy those bytes to the buffer + */ + bigBlockBuffer = + StorageImpl_GetROBigBlock(This->parentStorage, blockIndex); + + memcpy(bufferWalker, bigBlockBuffer + offsetInBlock, bytesToReadInBuffer); + + StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer); + + /* + * Step to the next big block. + */ + if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, &blockIndex))) + return FALSE; + + bufferWalker += bytesToReadInBuffer; + size -= bytesToReadInBuffer; + *bytesRead += bytesToReadInBuffer; + offsetInBlock = 0; /* There is no offset on the next block */ + + } + + return (size == 0); +} + +/****************************************************************************** + * BlockChainStream_WriteAt + * + * Writes the specified number of bytes to this chain at the specified offset. + * bytesWritten may be NULL. + * Will fail if not all specified number of bytes have been written. + */ +BOOL BlockChainStream_WriteAt(BlockChainStream* This, + ULARGE_INTEGER offset, + ULONG size, + const void* buffer, + ULONG* bytesWritten) +{ + ULONG blockNoInSequence = offset.u.LowPart / This->parentStorage->bigBlockSize; + ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->bigBlockSize; + ULONG bytesToWrite; + ULONG blockIndex; + const BYTE* bufferWalker; + BYTE* bigBlockBuffer; + + /* + * Find the first block in the stream that contains part of the buffer. + */ + if ( (This->lastBlockNoInSequence == 0xFFFFFFFF) || + (This->lastBlockNoInSequenceIndex == BLOCK_END_OF_CHAIN) || + (blockNoInSequence < This->lastBlockNoInSequence) ) + { + blockIndex = BlockChainStream_GetHeadOfChain(This); + This->lastBlockNoInSequence = blockNoInSequence; + } + else + { + ULONG temp = blockNoInSequence; + + blockIndex = This->lastBlockNoInSequenceIndex; + blockNoInSequence -= This->lastBlockNoInSequence; + This->lastBlockNoInSequence = temp; + } + + while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN)) + { + if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, + &blockIndex))) + return FALSE; + blockNoInSequence--; + } + + This->lastBlockNoInSequenceIndex = blockIndex; + + /* + * Here, I'm casting away the constness on the buffer variable + * This is OK since we don't intend to modify that buffer. + */ + *bytesWritten = 0; + bufferWalker = (const BYTE*)buffer; + + while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) ) + { + /* + * Calculate how many bytes we can copy from this big block. + */ + bytesToWrite = + min(This->parentStorage->bigBlockSize - offsetInBlock, size); + + /* + * Copy those bytes to the buffer + */ + bigBlockBuffer = StorageImpl_GetBigBlock(This->parentStorage, blockIndex); + + memcpy(bigBlockBuffer + offsetInBlock, bufferWalker, bytesToWrite); + + StorageImpl_ReleaseBigBlock(This->parentStorage, bigBlockBuffer); + + /* + * Step to the next big block. + */ + if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, + &blockIndex))) + return FALSE; + bufferWalker += bytesToWrite; + size -= bytesToWrite; + *bytesWritten += bytesToWrite; + offsetInBlock = 0; /* There is no offset on the next block */ + } + + return (size == 0); +} + +/****************************************************************************** + * BlockChainStream_Shrink + * + * Shrinks this chain in the big block depot. + */ +BOOL BlockChainStream_Shrink(BlockChainStream* This, + ULARGE_INTEGER newSize) +{ + ULONG blockIndex, extraBlock; + ULONG numBlocks; + ULONG count = 1; + + /* + * Reset the last accessed block cache. + */ + This->lastBlockNoInSequence = 0xFFFFFFFF; + This->lastBlockNoInSequenceIndex = BLOCK_END_OF_CHAIN; + + /* + * Figure out how many blocks are needed to contain the new size + */ + numBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize; + + if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0) + numBlocks++; + + blockIndex = BlockChainStream_GetHeadOfChain(This); + + /* + * Go to the new end of chain + */ + while (count < numBlocks) + { + if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, + &blockIndex))) + return FALSE; + count++; + } + + /* Get the next block before marking the new end */ + if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, blockIndex, + &extraBlock))) + return FALSE; + + /* Mark the new end of chain */ + StorageImpl_SetNextBlockInChain( + This->parentStorage, + blockIndex, + BLOCK_END_OF_CHAIN); + + This->tailIndex = blockIndex; + This->numBlocks = numBlocks; + + /* + * Mark the extra blocks as free + */ + while (extraBlock != BLOCK_END_OF_CHAIN) + { + if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, extraBlock, + &blockIndex))) + return FALSE; + StorageImpl_FreeBigBlock(This->parentStorage, extraBlock); + extraBlock = blockIndex; + } + + return TRUE; +} + +/****************************************************************************** + * BlockChainStream_Enlarge + * + * Grows this chain in the big block depot. + */ +BOOL BlockChainStream_Enlarge(BlockChainStream* This, + ULARGE_INTEGER newSize) +{ + ULONG blockIndex, currentBlock; + ULONG newNumBlocks; + ULONG oldNumBlocks = 0; + + blockIndex = BlockChainStream_GetHeadOfChain(This); + + /* + * Empty chain. Create the head. + */ + if (blockIndex == BLOCK_END_OF_CHAIN) + { + blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage); + StorageImpl_SetNextBlockInChain(This->parentStorage, + blockIndex, + BLOCK_END_OF_CHAIN); + + if (This->headOfStreamPlaceHolder != 0) + { + *(This->headOfStreamPlaceHolder) = blockIndex; + } + else + { + StgProperty chainProp; + assert(This->ownerPropertyIndex != PROPERTY_NULL); + + StorageImpl_ReadProperty( + This->parentStorage, + This->ownerPropertyIndex, + &chainProp); + + chainProp.startingBlock = blockIndex; + + StorageImpl_WriteProperty( + This->parentStorage, + This->ownerPropertyIndex, + &chainProp); + } + + This->tailIndex = blockIndex; + This->numBlocks = 1; + } + + /* + * Figure out how many blocks are needed to contain this stream + */ + newNumBlocks = newSize.u.LowPart / This->parentStorage->bigBlockSize; + + if ((newSize.u.LowPart % This->parentStorage->bigBlockSize) != 0) + newNumBlocks++; + + /* + * Go to the current end of chain + */ + if (This->tailIndex == BLOCK_END_OF_CHAIN) + { + currentBlock = blockIndex; + + while (blockIndex != BLOCK_END_OF_CHAIN) + { + This->numBlocks++; + currentBlock = blockIndex; + + if(FAILED(StorageImpl_GetNextBlockInChain(This->parentStorage, currentBlock, + &blockIndex))) + return FALSE; + } + + This->tailIndex = currentBlock; + } + + currentBlock = This->tailIndex; + oldNumBlocks = This->numBlocks; + + /* + * Add new blocks to the chain + */ + if (oldNumBlocks < newNumBlocks) + { + while (oldNumBlocks < newNumBlocks) + { + blockIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage); + + StorageImpl_SetNextBlockInChain( + This->parentStorage, + currentBlock, + blockIndex); + + StorageImpl_SetNextBlockInChain( + This->parentStorage, + blockIndex, + BLOCK_END_OF_CHAIN); + + currentBlock = blockIndex; + oldNumBlocks++; + } + + This->tailIndex = blockIndex; + This->numBlocks = newNumBlocks; + } + + return TRUE; +} + +/****************************************************************************** + * BlockChainStream_SetSize + * + * Sets the size of this stream. The big block depot will be updated. + * The file will grow if we grow the chain. + * + * TODO: Free the actual blocks in the file when we shrink the chain. + * Currently, the blocks are still in the file. So the file size + * doesn't shrink even if we shrink streams. + */ +BOOL BlockChainStream_SetSize( + BlockChainStream* This, + ULARGE_INTEGER newSize) +{ + ULARGE_INTEGER size = BlockChainStream_GetSize(This); + + if (newSize.u.LowPart == size.u.LowPart) + return TRUE; + + if (newSize.u.LowPart < size.u.LowPart) + { + BlockChainStream_Shrink(This, newSize); + } + else + { + ULARGE_INTEGER fileSize = + BIGBLOCKFILE_GetSize(This->parentStorage->bigBlockFile); + + ULONG diff = newSize.u.LowPart - size.u.LowPart; + + /* + * Make sure the file stays a multiple of blocksize + */ + if ((diff % This->parentStorage->bigBlockSize) != 0) + diff += (This->parentStorage->bigBlockSize - + (diff % This->parentStorage->bigBlockSize) ); + + fileSize.u.LowPart += diff; + BIGBLOCKFILE_SetSize(This->parentStorage->bigBlockFile, fileSize); + + BlockChainStream_Enlarge(This, newSize); + } + + return TRUE; +} + +/****************************************************************************** + * BlockChainStream_GetSize + * + * Returns the size of this chain. + * Will return the block count if this chain doesn't have a property. + */ +ULARGE_INTEGER BlockChainStream_GetSize(BlockChainStream* This) +{ + StgProperty chainProperty; + + if(This->headOfStreamPlaceHolder == NULL) + { + /* + * This chain is a data stream read the property and return + * the appropriate size + */ + StorageImpl_ReadProperty( + This->parentStorage, + This->ownerPropertyIndex, + &chainProperty); + + return chainProperty.size; + } + else + { + /* + * this chain is a chain that does not have a property, figure out the + * size by making the product number of used blocks times the + * size of them + */ + ULARGE_INTEGER result; + result.u.HighPart = 0; + + result.u.LowPart = + BlockChainStream_GetCount(This) * + This->parentStorage->bigBlockSize; + + return result; + } +} + +/****************************************************************************** +** SmallBlockChainStream implementation +*/ + +SmallBlockChainStream* SmallBlockChainStream_Construct( + StorageImpl* parentStorage, + ULONG propertyIndex) +{ + SmallBlockChainStream* newStream; + + newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(SmallBlockChainStream)); + + newStream->parentStorage = parentStorage; + newStream->ownerPropertyIndex = propertyIndex; + + return newStream; +} + +void SmallBlockChainStream_Destroy( + SmallBlockChainStream* This) +{ + HeapFree(GetProcessHeap(), 0, This); +} + +/****************************************************************************** + * SmallBlockChainStream_GetHeadOfChain + * + * Returns the head of this chain of small blocks. + */ +ULONG SmallBlockChainStream_GetHeadOfChain( + SmallBlockChainStream* This) +{ + StgProperty chainProperty; + BOOL readSuccessful; + + if (This->ownerPropertyIndex) + { + readSuccessful = StorageImpl_ReadProperty( + This->parentStorage, + This->ownerPropertyIndex, + &chainProperty); + + if (readSuccessful) + { + return chainProperty.startingBlock; + } + + } + + return BLOCK_END_OF_CHAIN; +} + +/****************************************************************************** + * SmallBlockChainStream_GetNextBlockInChain + * + * Returns the index of the next small block in this chain. + * + * Return Values: + * - BLOCK_END_OF_CHAIN: end of this chain + * - BLOCK_UNUSED: small block 'blockIndex' is free + */ +HRESULT SmallBlockChainStream_GetNextBlockInChain( + SmallBlockChainStream* This, + ULONG blockIndex, + ULONG* nextBlockInChain) +{ + ULARGE_INTEGER offsetOfBlockInDepot; + DWORD buffer; + ULONG bytesRead; + BOOL success; + + *nextBlockInChain = BLOCK_END_OF_CHAIN; + + offsetOfBlockInDepot.u.HighPart = 0; + offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG); + + /* + * Read those bytes in the buffer from the small block file. + */ + success = BlockChainStream_ReadAt( + This->parentStorage->smallBlockDepotChain, + offsetOfBlockInDepot, + sizeof(DWORD), + &buffer, + &bytesRead); + + if (success) + { + StorageUtl_ReadDWord((BYTE *)&buffer, 0, nextBlockInChain); + return S_OK; + } + + return STG_E_READFAULT; +} + +/****************************************************************************** + * SmallBlockChainStream_SetNextBlockInChain + * + * Writes the index of the next block of the specified block in the small + * block depot. + * To set the end of chain use BLOCK_END_OF_CHAIN as nextBlock. + * To flag a block as free use BLOCK_UNUSED as nextBlock. + */ +void SmallBlockChainStream_SetNextBlockInChain( + SmallBlockChainStream* This, + ULONG blockIndex, + ULONG nextBlock) +{ + ULARGE_INTEGER offsetOfBlockInDepot; + DWORD buffer; + ULONG bytesWritten; + + offsetOfBlockInDepot.u.HighPart = 0; + offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG); + + StorageUtl_WriteDWord((BYTE *)&buffer, 0, nextBlock); + + /* + * Read those bytes in the buffer from the small block file. + */ + BlockChainStream_WriteAt( + This->parentStorage->smallBlockDepotChain, + offsetOfBlockInDepot, + sizeof(DWORD), + &buffer, + &bytesWritten); +} + +/****************************************************************************** + * SmallBlockChainStream_FreeBlock + * + * Flag small block 'blockIndex' as free in the small block depot. + */ +void SmallBlockChainStream_FreeBlock( + SmallBlockChainStream* This, + ULONG blockIndex) +{ + SmallBlockChainStream_SetNextBlockInChain(This, blockIndex, BLOCK_UNUSED); +} + +/****************************************************************************** + * SmallBlockChainStream_GetNextFreeBlock + * + * Returns the index of a free small block. The small block depot will be + * enlarged if necessary. The small block chain will also be enlarged if + * necessary. + */ +ULONG SmallBlockChainStream_GetNextFreeBlock( + SmallBlockChainStream* This) +{ + ULARGE_INTEGER offsetOfBlockInDepot; + DWORD buffer; + ULONG bytesRead; + ULONG blockIndex = 0; + ULONG nextBlockIndex = BLOCK_END_OF_CHAIN; + BOOL success = TRUE; + ULONG smallBlocksPerBigBlock; + + offsetOfBlockInDepot.u.HighPart = 0; + + /* + * Scan the small block depot for a free block + */ + while (nextBlockIndex != BLOCK_UNUSED) + { + offsetOfBlockInDepot.u.LowPart = blockIndex * sizeof(ULONG); + + success = BlockChainStream_ReadAt( + This->parentStorage->smallBlockDepotChain, + offsetOfBlockInDepot, + sizeof(DWORD), + &buffer, + &bytesRead); + + /* + * If we run out of space for the small block depot, enlarge it + */ + if (success) + { + StorageUtl_ReadDWord((BYTE *)&buffer, 0, &nextBlockIndex); + + if (nextBlockIndex != BLOCK_UNUSED) + blockIndex++; + } + else + { + ULONG count = + BlockChainStream_GetCount(This->parentStorage->smallBlockDepotChain); + + ULONG sbdIndex = This->parentStorage->smallBlockDepotStart; + ULONG nextBlock, newsbdIndex; + BYTE* smallBlockDepot; + + nextBlock = sbdIndex; + while (nextBlock != BLOCK_END_OF_CHAIN) + { + sbdIndex = nextBlock; + StorageImpl_GetNextBlockInChain(This->parentStorage, sbdIndex, &nextBlock); + } + + newsbdIndex = StorageImpl_GetNextFreeBigBlock(This->parentStorage); + if (sbdIndex != BLOCK_END_OF_CHAIN) + StorageImpl_SetNextBlockInChain( + This->parentStorage, + sbdIndex, + newsbdIndex); + + StorageImpl_SetNextBlockInChain( + This->parentStorage, + newsbdIndex, + BLOCK_END_OF_CHAIN); + + /* + * Initialize all the small blocks to free + */ + smallBlockDepot = + StorageImpl_GetBigBlock(This->parentStorage, newsbdIndex); + + memset(smallBlockDepot, BLOCK_UNUSED, This->parentStorage->bigBlockSize); + StorageImpl_ReleaseBigBlock(This->parentStorage, smallBlockDepot); + + if (count == 0) + { + /* + * We have just created the small block depot. + */ + StgProperty rootProp; + ULONG sbStartIndex; + + /* + * Save it in the header + */ + This->parentStorage->smallBlockDepotStart = newsbdIndex; + StorageImpl_SaveFileHeader(This->parentStorage); + + /* + * And allocate the first big block that will contain small blocks + */ + sbStartIndex = + StorageImpl_GetNextFreeBigBlock(This->parentStorage); + + StorageImpl_SetNextBlockInChain( + This->parentStorage, + sbStartIndex, + BLOCK_END_OF_CHAIN); + + StorageImpl_ReadProperty( + This->parentStorage, + This->parentStorage->base.rootPropertySetIndex, + &rootProp); + + rootProp.startingBlock = sbStartIndex; + rootProp.size.u.HighPart = 0; + rootProp.size.u.LowPart = This->parentStorage->bigBlockSize; + + StorageImpl_WriteProperty( + This->parentStorage, + This->parentStorage->base.rootPropertySetIndex, + &rootProp); + } + } + } + + smallBlocksPerBigBlock = + This->parentStorage->bigBlockSize / This->parentStorage->smallBlockSize; + + /* + * Verify if we have to allocate big blocks to contain small blocks + */ + if (blockIndex % smallBlocksPerBigBlock == 0) + { + StgProperty rootProp; + ULONG blocksRequired = (blockIndex / smallBlocksPerBigBlock) + 1; + + StorageImpl_ReadProperty( + This->parentStorage, + This->parentStorage->base.rootPropertySetIndex, + &rootProp); + + if (rootProp.size.u.LowPart < + (blocksRequired * This->parentStorage->bigBlockSize)) + { + rootProp.size.u.LowPart += This->parentStorage->bigBlockSize; + + BlockChainStream_SetSize( + This->parentStorage->smallBlockRootChain, + rootProp.size); + + StorageImpl_WriteProperty( + This->parentStorage, + This->parentStorage->base.rootPropertySetIndex, + &rootProp); + } + } + + return blockIndex; +} + +/****************************************************************************** + * SmallBlockChainStream_ReadAt + * + * Reads a specified number of bytes from this chain at the specified offset. + * bytesRead may be NULL. + * Failure will be returned if the specified number of bytes has not been read. + */ +BOOL SmallBlockChainStream_ReadAt( + SmallBlockChainStream* This, + ULARGE_INTEGER offset, + ULONG size, + void* buffer, + ULONG* bytesRead) +{ + ULARGE_INTEGER offsetInBigBlockFile; + ULONG blockNoInSequence = + offset.u.LowPart / This->parentStorage->smallBlockSize; + + ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize; + ULONG bytesToReadInBuffer; + ULONG blockIndex; + ULONG bytesReadFromBigBlockFile; + BYTE* bufferWalker; + + /* + * This should never happen on a small block file. + */ + assert(offset.u.HighPart==0); + + /* + * Find the first block in the stream that contains part of the buffer. + */ + blockIndex = SmallBlockChainStream_GetHeadOfChain(This); + + while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN)) + { + if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, + &blockIndex))) + return FALSE; + blockNoInSequence--; + } + + /* + * Start reading the buffer. + */ + *bytesRead = 0; + bufferWalker = buffer; + + while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) ) + { + /* + * Calculate how many bytes we can copy from this small block. + */ + bytesToReadInBuffer = + min(This->parentStorage->smallBlockSize - offsetInBlock, size); + + /* + * Calculate the offset of the small block in the small block file. + */ + offsetInBigBlockFile.u.HighPart = 0; + offsetInBigBlockFile.u.LowPart = + blockIndex * This->parentStorage->smallBlockSize; + + offsetInBigBlockFile.u.LowPart += offsetInBlock; + + /* + * Read those bytes in the buffer from the small block file. + */ + BlockChainStream_ReadAt(This->parentStorage->smallBlockRootChain, + offsetInBigBlockFile, + bytesToReadInBuffer, + bufferWalker, + &bytesReadFromBigBlockFile); + + assert(bytesReadFromBigBlockFile == bytesToReadInBuffer); + + /* + * Step to the next big block. + */ + if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex))) + return FALSE; + bufferWalker += bytesToReadInBuffer; + size -= bytesToReadInBuffer; + *bytesRead += bytesToReadInBuffer; + offsetInBlock = 0; /* There is no offset on the next block */ + } + + return (size == 0); +} + +/****************************************************************************** + * SmallBlockChainStream_WriteAt + * + * Writes the specified number of bytes to this chain at the specified offset. + * bytesWritten may be NULL. + * Will fail if not all specified number of bytes have been written. + */ +BOOL SmallBlockChainStream_WriteAt( + SmallBlockChainStream* This, + ULARGE_INTEGER offset, + ULONG size, + const void* buffer, + ULONG* bytesWritten) +{ + ULARGE_INTEGER offsetInBigBlockFile; + ULONG blockNoInSequence = + offset.u.LowPart / This->parentStorage->smallBlockSize; + + ULONG offsetInBlock = offset.u.LowPart % This->parentStorage->smallBlockSize; + ULONG bytesToWriteInBuffer; + ULONG blockIndex; + ULONG bytesWrittenFromBigBlockFile; + const BYTE* bufferWalker; + + /* + * This should never happen on a small block file. + */ + assert(offset.u.HighPart==0); + + /* + * Find the first block in the stream that contains part of the buffer. + */ + blockIndex = SmallBlockChainStream_GetHeadOfChain(This); + + while ( (blockNoInSequence > 0) && (blockIndex != BLOCK_END_OF_CHAIN)) + { + if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex))) + return FALSE; + blockNoInSequence--; + } + + /* + * Start writing the buffer. + * + * Here, I'm casting away the constness on the buffer variable + * This is OK since we don't intend to modify that buffer. + */ + *bytesWritten = 0; + bufferWalker = (const BYTE*)buffer; + while ( (size > 0) && (blockIndex != BLOCK_END_OF_CHAIN) ) + { + /* + * Calculate how many bytes we can copy to this small block. + */ + bytesToWriteInBuffer = + min(This->parentStorage->smallBlockSize - offsetInBlock, size); + + /* + * Calculate the offset of the small block in the small block file. + */ + offsetInBigBlockFile.u.HighPart = 0; + offsetInBigBlockFile.u.LowPart = + blockIndex * This->parentStorage->smallBlockSize; + + offsetInBigBlockFile.u.LowPart += offsetInBlock; + + /* + * Write those bytes in the buffer to the small block file. + */ + BlockChainStream_WriteAt(This->parentStorage->smallBlockRootChain, + offsetInBigBlockFile, + bytesToWriteInBuffer, + bufferWalker, + &bytesWrittenFromBigBlockFile); + + assert(bytesWrittenFromBigBlockFile == bytesToWriteInBuffer); + + /* + * Step to the next big block. + */ + if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, + &blockIndex))) + return FALSE; + bufferWalker += bytesToWriteInBuffer; + size -= bytesToWriteInBuffer; + *bytesWritten += bytesToWriteInBuffer; + offsetInBlock = 0; /* There is no offset on the next block */ + } + + return (size == 0); +} + +/****************************************************************************** + * SmallBlockChainStream_Shrink + * + * Shrinks this chain in the small block depot. + */ +BOOL SmallBlockChainStream_Shrink( + SmallBlockChainStream* This, + ULARGE_INTEGER newSize) +{ + ULONG blockIndex, extraBlock; + ULONG numBlocks; + ULONG count = 0; + + numBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize; + + if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0) + numBlocks++; + + blockIndex = SmallBlockChainStream_GetHeadOfChain(This); + + /* + * Go to the new end of chain + */ + while (count < numBlocks) + { + if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, + &blockIndex))) + return FALSE; + count++; + } + + /* + * If the count is 0, we have a special case, the head of the chain was + * just freed. + */ + if (count == 0) + { + StgProperty chainProp; + + StorageImpl_ReadProperty(This->parentStorage, + This->ownerPropertyIndex, + &chainProp); + + chainProp.startingBlock = BLOCK_END_OF_CHAIN; + + StorageImpl_WriteProperty(This->parentStorage, + This->ownerPropertyIndex, + &chainProp); + + /* + * We start freeing the chain at the head block. + */ + extraBlock = blockIndex; + } + else + { + /* Get the next block before marking the new end */ + if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, + &extraBlock))) + return FALSE; + + /* Mark the new end of chain */ + SmallBlockChainStream_SetNextBlockInChain( + This, + blockIndex, + BLOCK_END_OF_CHAIN); + } + + /* + * Mark the extra blocks as free + */ + while (extraBlock != BLOCK_END_OF_CHAIN) + { + if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, extraBlock, + &blockIndex))) + return FALSE; + SmallBlockChainStream_FreeBlock(This, extraBlock); + extraBlock = blockIndex; + } + + return TRUE; +} + +/****************************************************************************** + * SmallBlockChainStream_Enlarge + * + * Grows this chain in the small block depot. + */ +BOOL SmallBlockChainStream_Enlarge( + SmallBlockChainStream* This, + ULARGE_INTEGER newSize) +{ + ULONG blockIndex, currentBlock; + ULONG newNumBlocks; + ULONG oldNumBlocks = 0; + + blockIndex = SmallBlockChainStream_GetHeadOfChain(This); + + /* + * Empty chain + */ + if (blockIndex == BLOCK_END_OF_CHAIN) + { + + StgProperty chainProp; + + StorageImpl_ReadProperty(This->parentStorage, This->ownerPropertyIndex, + &chainProp); + + chainProp.startingBlock = SmallBlockChainStream_GetNextFreeBlock(This); + + StorageImpl_WriteProperty(This->parentStorage, This->ownerPropertyIndex, + &chainProp); + + blockIndex = chainProp.startingBlock; + SmallBlockChainStream_SetNextBlockInChain( + This, + blockIndex, + BLOCK_END_OF_CHAIN); + } + + currentBlock = blockIndex; + + /* + * Figure out how many blocks are needed to contain this stream + */ + newNumBlocks = newSize.u.LowPart / This->parentStorage->smallBlockSize; + + if ((newSize.u.LowPart % This->parentStorage->smallBlockSize) != 0) + newNumBlocks++; + + /* + * Go to the current end of chain + */ + while (blockIndex != BLOCK_END_OF_CHAIN) + { + oldNumBlocks++; + currentBlock = blockIndex; + if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, currentBlock, &blockIndex))) + return FALSE; + } + + /* + * Add new blocks to the chain + */ + while (oldNumBlocks < newNumBlocks) + { + blockIndex = SmallBlockChainStream_GetNextFreeBlock(This); + SmallBlockChainStream_SetNextBlockInChain(This, currentBlock, blockIndex); + + SmallBlockChainStream_SetNextBlockInChain( + This, + blockIndex, + BLOCK_END_OF_CHAIN); + + currentBlock = blockIndex; + oldNumBlocks++; + } + + return TRUE; +} + +/****************************************************************************** + * SmallBlockChainStream_GetCount + * + * Returns the number of blocks that comprises this chain. + * This is not the size of this chain as the last block may not be full! + */ +ULONG SmallBlockChainStream_GetCount(SmallBlockChainStream* This) +{ + ULONG blockIndex; + ULONG count = 0; + + blockIndex = SmallBlockChainStream_GetHeadOfChain(This); + + while (blockIndex != BLOCK_END_OF_CHAIN) + { + count++; + + if(FAILED(SmallBlockChainStream_GetNextBlockInChain(This, blockIndex, &blockIndex))) + return 0; + } + + return count; +} + +/****************************************************************************** + * SmallBlockChainStream_SetSize + * + * Sets the size of this stream. + * The file will grow if we grow the chain. + * + * TODO: Free the actual blocks in the file when we shrink the chain. + * Currently, the blocks are still in the file. So the file size + * doesn't shrink even if we shrink streams. + */ +BOOL SmallBlockChainStream_SetSize( + SmallBlockChainStream* This, + ULARGE_INTEGER newSize) +{ + ULARGE_INTEGER size = SmallBlockChainStream_GetSize(This); + + if (newSize.u.LowPart == size.u.LowPart) + return TRUE; + + if (newSize.u.LowPart < size.u.LowPart) + { + SmallBlockChainStream_Shrink(This, newSize); + } + else + { + SmallBlockChainStream_Enlarge(This, newSize); + } + + return TRUE; +} + +/****************************************************************************** + * SmallBlockChainStream_GetSize + * + * Returns the size of this chain. + */ +ULARGE_INTEGER SmallBlockChainStream_GetSize(SmallBlockChainStream* This) +{ + StgProperty chainProperty; + + StorageImpl_ReadProperty( + This->parentStorage, + This->ownerPropertyIndex, + &chainProperty); + + return chainProperty.size; +} + +/****************************************************************************** + * StgCreateDocfile [OLE32.@] + */ +HRESULT WINAPI StgCreateDocfile( + LPCOLESTR pwcsName, + DWORD grfMode, + DWORD reserved, + IStorage **ppstgOpen) +{ + StorageImpl* newStorage = 0; + HANDLE hFile = INVALID_HANDLE_VALUE; + HRESULT hr = STG_E_INVALIDFLAG; + DWORD shareMode; + DWORD accessMode; + DWORD creationMode; + DWORD fileAttributes; + WCHAR tempFileName[MAX_PATH]; + + TRACE("(%s, %lx, %ld, %p)\n", + debugstr_w(pwcsName), grfMode, + reserved, ppstgOpen); + + /* + * Validate the parameters + */ + if (ppstgOpen == 0) + return STG_E_INVALIDPOINTER; + if (reserved != 0) + return STG_E_INVALIDPARAMETER; + + /* + * Validate the STGM flags + */ + if ( FAILED( validateSTGM(grfMode) )) + goto end; + + /* StgCreateDocFile always opens for write */ + switch(STGM_ACCESS_MODE(grfMode)) + { + case STGM_WRITE: + case STGM_READWRITE: + break; + default: + goto end; + } + + /* can't share write */ + switch(STGM_SHARE_MODE(grfMode)) + { + case STGM_SHARE_EXCLUSIVE: + case STGM_SHARE_DENY_WRITE: + break; + default: + goto end; + } + + /* shared reading requires transacted mode */ + if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE && + !(grfMode&STGM_TRANSACTED) ) + goto end; + + /* + * Generate a unique name. + */ + if (pwcsName == 0) + { + WCHAR tempPath[MAX_PATH]; + static const WCHAR prefix[] = { 'S', 'T', 'O', 0 }; + + if (STGM_SHARE_MODE(grfMode) != STGM_SHARE_EXCLUSIVE) + goto end; + + memset(tempPath, 0, sizeof(tempPath)); + memset(tempFileName, 0, sizeof(tempFileName)); + + if ((GetTempPathW(MAX_PATH, tempPath)) == 0 ) + tempPath[0] = '.'; + + if (GetTempFileNameW(tempPath, prefix, 0, tempFileName) != 0) + pwcsName = tempFileName; + else + { + hr = STG_E_INSUFFICIENTMEMORY; + goto end; + } + + creationMode = TRUNCATE_EXISTING; + } + else + { + creationMode = GetCreationModeFromSTGM(grfMode); + } + + /* + * Interpret the STGM value grfMode + */ + shareMode = GetShareModeFromSTGM(grfMode); + accessMode = GetAccessModeFromSTGM(grfMode); + + if (grfMode & STGM_DELETEONRELEASE) + fileAttributes = FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE; + else + fileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS; + + if (grfMode & STGM_TRANSACTED) + FIXME("Transacted mode not implemented.\n"); + + /* + * Initialize the "out" parameter. + */ + *ppstgOpen = 0; + + hFile = CreateFileW(pwcsName, + accessMode, + shareMode, + NULL, + creationMode, + fileAttributes, + 0); + + if (hFile == INVALID_HANDLE_VALUE) + { + if(GetLastError() == ERROR_FILE_EXISTS) + hr = STG_E_FILEALREADYEXISTS; + else + hr = E_FAIL; + goto end; + } + + /* + * Allocate and initialize the new IStorage32object. + */ + newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl)); + + if (newStorage == 0) + { + hr = STG_E_INSUFFICIENTMEMORY; + goto end; + } + + hr = StorageImpl_Construct( + newStorage, + hFile, + pwcsName, + NULL, + grfMode, + TRUE, + TRUE); + + if (FAILED(hr)) + { + HeapFree(GetProcessHeap(), 0, newStorage); + goto end; + } + + /* + * Get an "out" pointer for the caller. + */ + hr = StorageBaseImpl_QueryInterface( + (IStorage*)newStorage, + (REFIID)&IID_IStorage, + (void**)ppstgOpen); +end: + TRACE("<-- %p r = %08lx\n", *ppstgOpen, hr); + + return hr; +} + +/****************************************************************************** + * StgCreateStorageEx [OLE32.@] + */ +HRESULT WINAPI StgCreateStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen) +{ + TRACE("(%s, %lx, %lx, %lx, %p, %p, %p, %p)\n", debugstr_w(pwcsName), + grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen); + + if (stgfmt != STGFMT_FILE && grfAttrs != 0) + { + ERR("grfAttrs must be 0 if stgfmt != STGFMT_FILE\n"); + return STG_E_INVALIDPARAMETER; + } + + if (stgfmt != STGFMT_FILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING) + { + ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_FILE\n"); + return STG_E_INVALIDPARAMETER; + } + + if (stgfmt == STGFMT_FILE) + { + ERR("Cannot use STGFMT_FILE - this is NTFS only\n"); + return STG_E_INVALIDPARAMETER; + } + + if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE) + { + FIXME("Stub: calling StgCreateDocfile, but ignoring pStgOptions and grfAttrs\n"); + return StgCreateDocfile(pwcsName, grfMode, 0, (IStorage **)ppObjectOpen); + } + + ERR("Invalid stgfmt argument\n"); + return STG_E_INVALIDPARAMETER; +} + +/****************************************************************************** + * StgCreatePropSetStg [OLE32.@] + */ +HRESULT WINAPI StgCreatePropSetStg(IStorage *pstg, DWORD reserved, + IPropertySetStorage **ppPropSetStg) +{ + HRESULT hr; + + TRACE("(%p, 0x%lx, %p): stub\n", pstg, reserved, ppPropSetStg); + if (reserved) + hr = STG_E_INVALIDPARAMETER; + else + hr = StorageBaseImpl_QueryInterface(pstg, &IID_IPropertySetStorage, + (void**)ppPropSetStg); + return hr; +} + +/****************************************************************************** + * StgOpenStorageEx [OLE32.@] + */ +HRESULT WINAPI StgOpenStorageEx(const WCHAR* pwcsName, DWORD grfMode, DWORD stgfmt, DWORD grfAttrs, STGOPTIONS* pStgOptions, void* reserved, REFIID riid, void** ppObjectOpen) +{ + TRACE("(%s, %lx, %lx, %lx, %p, %p, %p, %p)\n", debugstr_w(pwcsName), + grfMode, stgfmt, grfAttrs, pStgOptions, reserved, riid, ppObjectOpen); + + if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0) + { + ERR("grfAttrs must be 0 if stgfmt != STGFMT_DOCFILE\n"); + return STG_E_INVALIDPARAMETER; + } + + if (stgfmt != STGFMT_DOCFILE && grfAttrs != 0 && grfAttrs != FILE_FLAG_NO_BUFFERING) + { + ERR("grfAttrs must be 0 or FILE_FLAG_NO_BUFFERING if stgfmt == STGFMT_DOCFILE\n"); + return STG_E_INVALIDPARAMETER; + } + + if (stgfmt == STGFMT_FILE) + { + ERR("Cannot use STGFMT_FILE - this is NTFS only\n"); + return STG_E_INVALIDPARAMETER; + } + + if (stgfmt == STGFMT_STORAGE || stgfmt == STGFMT_DOCFILE || stgfmt == STGFMT_ANY) + { + if (stgfmt == STGFMT_ANY) + WARN("STGFMT_ANY assuming storage\n"); + FIXME("Stub: calling StgOpenStorage, but ignoring pStgOptions and grfAttrs\n"); + return StgOpenStorage(pwcsName, NULL, grfMode, (SNB)NULL, 0, (IStorage **)ppObjectOpen); + } + + ERR("Invalid stgfmt argument\n"); + return STG_E_INVALIDPARAMETER; +} + + +/****************************************************************************** + * StgOpenStorage [OLE32.@] + */ +HRESULT WINAPI StgOpenStorage( + const OLECHAR *pwcsName, + IStorage *pstgPriority, + DWORD grfMode, + SNB snbExclude, + DWORD reserved, + IStorage **ppstgOpen) +{ + StorageImpl* newStorage = 0; + HRESULT hr = S_OK; + HANDLE hFile = 0; + DWORD shareMode; + DWORD accessMode; + WCHAR fullname[MAX_PATH]; + DWORD length; + + TRACE("(%s, %p, %lx, %p, %ld, %p)\n", + debugstr_w(pwcsName), pstgPriority, grfMode, + snbExclude, reserved, ppstgOpen); + + /* + * Perform sanity checks + */ + if (pwcsName == 0) + { + hr = STG_E_INVALIDNAME; + goto end; + } + + if (ppstgOpen == 0) + { + hr = STG_E_INVALIDPOINTER; + goto end; + } + + if (reserved) + { + hr = STG_E_INVALIDPARAMETER; + goto end; + } + + /* + * Validate the sharing mode + */ + switch(STGM_SHARE_MODE(grfMode)) + { + case STGM_SHARE_EXCLUSIVE: + case STGM_SHARE_DENY_WRITE: + break; + default: + hr = STG_E_INVALIDFLAG; + goto end; + } + + /* + * Validate the STGM flags + */ + if ( FAILED( validateSTGM(grfMode) ) || + (grfMode&STGM_CREATE)) + { + hr = STG_E_INVALIDFLAG; + goto end; + } + + /* shared reading requires transacted mode */ + if( STGM_SHARE_MODE(grfMode) == STGM_SHARE_DENY_WRITE && + STGM_ACCESS_MODE(grfMode) == STGM_READWRITE && + !(grfMode&STGM_TRANSACTED) ) + { + hr = STG_E_INVALIDFLAG; + goto end; + } + + /* + * Interpret the STGM value grfMode + */ + shareMode = GetShareModeFromSTGM(grfMode); + accessMode = GetAccessModeFromSTGM(grfMode); + + /* + * Initialize the "out" parameter. + */ + *ppstgOpen = 0; + + hFile = CreateFileW( pwcsName, + accessMode, + shareMode, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, + 0); + + if (hFile==INVALID_HANDLE_VALUE) + { + DWORD last_error = GetLastError(); + + hr = E_FAIL; + + switch (last_error) + { + case ERROR_FILE_NOT_FOUND: + hr = STG_E_FILENOTFOUND; + break; + + case ERROR_PATH_NOT_FOUND: + hr = STG_E_PATHNOTFOUND; + break; + + case ERROR_ACCESS_DENIED: + case ERROR_WRITE_PROTECT: + hr = STG_E_ACCESSDENIED; + break; + + case ERROR_SHARING_VIOLATION: + hr = STG_E_SHAREVIOLATION; + break; + + default: + hr = E_FAIL; + } + + goto end; + } + + /* + * Refuse to open the file if it's too small to be a structured storage file + * FIXME: verify the file when reading instead of here + */ + length = GetFileSize(hFile, NULL); + if (length < 0x100) + { + CloseHandle(hFile); + hr = STG_E_FILEALREADYEXISTS; + goto end; + } + + /* + * Allocate and initialize the new IStorage32object. + */ + newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl)); + + if (newStorage == 0) + { + hr = STG_E_INSUFFICIENTMEMORY; + goto end; + } + + /* if the file's length was zero, initialize the storage */ + hr = StorageImpl_Construct( + newStorage, + hFile, + pwcsName, + NULL, + grfMode, + TRUE, + FALSE ); + + if (FAILED(hr)) + { + HeapFree(GetProcessHeap(), 0, newStorage); + /* + * According to the docs if the file is not a storage, return STG_E_FILEALREADYEXISTS + */ + if(hr == STG_E_INVALIDHEADER) + hr = STG_E_FILEALREADYEXISTS; + goto end; + } + + /* prepare the file name string given in lieu of the root property name */ + GetFullPathNameW(pwcsName, MAX_PATH, fullname, NULL); + memcpy(newStorage->filename, fullname, PROPERTY_NAME_BUFFER_LEN); + newStorage->filename[PROPERTY_NAME_BUFFER_LEN-1] = '\0'; + + /* + * Get an "out" pointer for the caller. + */ + hr = StorageBaseImpl_QueryInterface( + (IStorage*)newStorage, + (REFIID)&IID_IStorage, + (void**)ppstgOpen); + +end: + TRACE("<-- %08lx, IStorage %p\n", hr, ppstgOpen ? *ppstgOpen : NULL); + return hr; +} + +/****************************************************************************** + * StgCreateDocfileOnILockBytes [OLE32.@] + */ +HRESULT WINAPI StgCreateDocfileOnILockBytes( + ILockBytes *plkbyt, + DWORD grfMode, + DWORD reserved, + IStorage** ppstgOpen) +{ + StorageImpl* newStorage = 0; + HRESULT hr = S_OK; + + /* + * Validate the parameters + */ + if ((ppstgOpen == 0) || (plkbyt == 0)) + return STG_E_INVALIDPOINTER; + + /* + * Allocate and initialize the new IStorage object. + */ + newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl)); + + if (newStorage == 0) + return STG_E_INSUFFICIENTMEMORY; + + hr = StorageImpl_Construct( + newStorage, + 0, + 0, + plkbyt, + grfMode, + FALSE, + TRUE); + + if (FAILED(hr)) + { + HeapFree(GetProcessHeap(), 0, newStorage); + return hr; + } + + /* + * Get an "out" pointer for the caller. + */ + hr = StorageBaseImpl_QueryInterface( + (IStorage*)newStorage, + (REFIID)&IID_IStorage, + (void**)ppstgOpen); + + return hr; +} + +/****************************************************************************** + * StgOpenStorageOnILockBytes [OLE32.@] + */ +HRESULT WINAPI StgOpenStorageOnILockBytes( + ILockBytes *plkbyt, + IStorage *pstgPriority, + DWORD grfMode, + SNB snbExclude, + DWORD reserved, + IStorage **ppstgOpen) +{ + StorageImpl* newStorage = 0; + HRESULT hr = S_OK; + + /* + * Perform a sanity check + */ + if ((plkbyt == 0) || (ppstgOpen == 0)) + return STG_E_INVALIDPOINTER; + + /* + * Validate the STGM flags + */ + if ( FAILED( validateSTGM(grfMode) )) + return STG_E_INVALIDFLAG; + + /* + * Initialize the "out" parameter. + */ + *ppstgOpen = 0; + + /* + * Allocate and initialize the new IStorage object. + */ + newStorage = HeapAlloc(GetProcessHeap(), 0, sizeof(StorageImpl)); + + if (newStorage == 0) + return STG_E_INSUFFICIENTMEMORY; + + hr = StorageImpl_Construct( + newStorage, + 0, + 0, + plkbyt, + grfMode, + FALSE, + FALSE); + + if (FAILED(hr)) + { + HeapFree(GetProcessHeap(), 0, newStorage); + return hr; + } + + /* + * Get an "out" pointer for the caller. + */ + hr = StorageBaseImpl_QueryInterface( + (IStorage*)newStorage, + (REFIID)&IID_IStorage, + (void**)ppstgOpen); + + return hr; +} + +/****************************************************************************** + * StgSetTimes [ole32.@] + * StgSetTimes [OLE32.@] + * + * + */ +HRESULT WINAPI StgSetTimes(OLECHAR const *str, FILETIME const *pctime, + FILETIME const *patime, FILETIME const *pmtime) +{ + IStorage *stg = NULL; + HRESULT r; + + TRACE("%s %p %p %p\n", debugstr_w(str), pctime, patime, pmtime); + + r = StgOpenStorage(str, NULL, STGM_READWRITE | STGM_SHARE_DENY_WRITE, + 0, 0, &stg); + if( SUCCEEDED(r) ) + { + r = IStorage_SetElementTimes(stg, NULL, pctime, patime, pmtime); + IStorage_Release(stg); + } + + return r; +} + +/****************************************************************************** + * StgIsStorageILockBytes [OLE32.@] + * + * Determines if the ILockBytes contains a storage object. + */ +HRESULT WINAPI StgIsStorageILockBytes(ILockBytes *plkbyt) +{ + BYTE sig[8]; + ULARGE_INTEGER offset; + + offset.u.HighPart = 0; + offset.u.LowPart = 0; + + ILockBytes_ReadAt(plkbyt, offset, sig, sizeof(sig), NULL); + + if (memcmp(sig, STORAGE_magic, sizeof(STORAGE_magic)) == 0) + return S_OK; + + return S_FALSE; +} + +/****************************************************************************** + * WriteClassStg [OLE32.@] + * + * This method will store the specified CLSID in the specified storage object + */ +HRESULT WINAPI WriteClassStg(IStorage* pStg, REFCLSID rclsid) +{ + HRESULT hRes; + + assert(pStg != 0); + + hRes = IStorage_SetClass(pStg, rclsid); + + return hRes; +} + +/*********************************************************************** + * ReadClassStg (OLE32.@) + * + * This method reads the CLSID previously written to a storage object with the WriteClassStg. + */ +HRESULT WINAPI ReadClassStg(IStorage *pstg,CLSID *pclsid){ + + STATSTG pstatstg; + HRESULT hRes; + + TRACE("()\n"); + + if(pclsid==NULL) + return E_POINTER; + /* + * read a STATSTG structure (contains the clsid) from the storage + */ + hRes=IStorage_Stat(pstg,&pstatstg,STATFLAG_DEFAULT); + + if(SUCCEEDED(hRes)) + *pclsid=pstatstg.clsid; + + return hRes; +} + +/*********************************************************************** + * OleLoadFromStream (OLE32.@) + * + * This function loads an object from stream + */ +HRESULT WINAPI OleLoadFromStream(IStream *pStm,REFIID iidInterface,void** ppvObj) +{ + CLSID clsid; + HRESULT res; + LPPERSISTSTREAM xstm; + + TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(iidInterface),ppvObj); + + res=ReadClassStm(pStm,&clsid); + if (!SUCCEEDED(res)) + return res; + res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj); + if (!SUCCEEDED(res)) + return res; + res=IUnknown_QueryInterface((IUnknown*)*ppvObj,&IID_IPersistStream,(LPVOID*)&xstm); + if (!SUCCEEDED(res)) { + IUnknown_Release((IUnknown*)*ppvObj); + return res; + } + res=IPersistStream_Load(xstm,pStm); + IPersistStream_Release(xstm); + /* FIXME: all refcounts ok at this point? I think they should be: + * pStm : unchanged + * ppvObj : 1 + * xstm : 0 (released) + */ + return res; +} + +/*********************************************************************** + * OleSaveToStream (OLE32.@) + * + * This function saves an object with the IPersistStream interface on it + * to the specified stream. + */ +HRESULT WINAPI OleSaveToStream(IPersistStream *pPStm,IStream *pStm) +{ + + CLSID clsid; + HRESULT res; + + TRACE("(%p,%p)\n",pPStm,pStm); + + res=IPersistStream_GetClassID(pPStm,&clsid); + + if (SUCCEEDED(res)){ + + res=WriteClassStm(pStm,&clsid); + + if (SUCCEEDED(res)) + + res=IPersistStream_Save(pPStm,pStm,TRUE); + } + + TRACE("Finished Save\n"); + return res; +} + +/**************************************************************************** + * This method validate a STGM parameter that can contain the values below + * + * The stgm modes in 0x0000ffff are not bit masks, but distinct 4 bit values. + * The stgm values contained in 0xffff0000 are bitmasks. + * + * STGM_DIRECT 0x00000000 + * STGM_TRANSACTED 0x00010000 + * STGM_SIMPLE 0x08000000 + * + * STGM_READ 0x00000000 + * STGM_WRITE 0x00000001 + * STGM_READWRITE 0x00000002 + * + * STGM_SHARE_DENY_NONE 0x00000040 + * STGM_SHARE_DENY_READ 0x00000030 + * STGM_SHARE_DENY_WRITE 0x00000020 + * STGM_SHARE_EXCLUSIVE 0x00000010 + * + * STGM_PRIORITY 0x00040000 + * STGM_DELETEONRELEASE 0x04000000 + * + * STGM_CREATE 0x00001000 + * STGM_CONVERT 0x00020000 + * STGM_FAILIFTHERE 0x00000000 + * + * STGM_NOSCRATCH 0x00100000 + * STGM_NOSNAPSHOT 0x00200000 + */ +static HRESULT validateSTGM(DWORD stgm) +{ + DWORD access = STGM_ACCESS_MODE(stgm); + DWORD share = STGM_SHARE_MODE(stgm); + DWORD create = STGM_CREATE_MODE(stgm); + + if (stgm&~STGM_KNOWN_FLAGS) + { + ERR("unknown flags %08lx\n", stgm); + return E_FAIL; + } + + switch (access) + { + case STGM_READ: + case STGM_WRITE: + case STGM_READWRITE: + break; + default: + return E_FAIL; + } + + switch (share) + { + case STGM_SHARE_DENY_NONE: + case STGM_SHARE_DENY_READ: + case STGM_SHARE_DENY_WRITE: + case STGM_SHARE_EXCLUSIVE: + break; + default: + return E_FAIL; + } + + switch (create) + { + case STGM_CREATE: + case STGM_FAILIFTHERE: + break; + default: + return E_FAIL; + } + + /* + * STGM_DIRECT | STGM_TRANSACTED | STGM_SIMPLE + */ + if ( (stgm & STGM_TRANSACTED) && (stgm & STGM_SIMPLE) ) + return E_FAIL; + + /* + * STGM_CREATE | STGM_CONVERT + * if both are false, STGM_FAILIFTHERE is set to TRUE + */ + if ( create == STGM_CREATE && (stgm & STGM_CONVERT) ) + return E_FAIL; + + /* + * STGM_NOSCRATCH requires STGM_TRANSACTED + */ + if ( (stgm & STGM_NOSCRATCH) && !(stgm & STGM_TRANSACTED) ) + return E_FAIL; + + /* + * STGM_NOSNAPSHOT requires STGM_TRANSACTED and + * not STGM_SHARE_EXCLUSIVE or STGM_SHARE_DENY_WRITE` + */ + if ( (stgm & STGM_NOSNAPSHOT) && + (!(stgm & STGM_TRANSACTED) || + share == STGM_SHARE_EXCLUSIVE || + share == STGM_SHARE_DENY_WRITE) ) + return E_FAIL; + + return S_OK; +} + +/**************************************************************************** + * GetShareModeFromSTGM + * + * This method will return a share mode flag from a STGM value. + * The STGM value is assumed valid. + */ +static DWORD GetShareModeFromSTGM(DWORD stgm) +{ + switch (STGM_SHARE_MODE(stgm)) + { + case STGM_SHARE_DENY_NONE: + return FILE_SHARE_READ | FILE_SHARE_WRITE; + case STGM_SHARE_DENY_READ: + return FILE_SHARE_WRITE; + case STGM_SHARE_DENY_WRITE: + return FILE_SHARE_READ; + case STGM_SHARE_EXCLUSIVE: + return 0; + } + ERR("Invalid share mode!\n"); + assert(0); + return 0; +} + +/**************************************************************************** + * GetAccessModeFromSTGM + * + * This method will return an access mode flag from a STGM value. + * The STGM value is assumed valid. + */ +static DWORD GetAccessModeFromSTGM(DWORD stgm) +{ + switch (STGM_ACCESS_MODE(stgm)) + { + case STGM_READ: + return GENERIC_READ; + case STGM_WRITE: + case STGM_READWRITE: + return GENERIC_READ | GENERIC_WRITE; + } + ERR("Invalid access mode!\n"); + assert(0); + return 0; +} + +/**************************************************************************** + * GetCreationModeFromSTGM + * + * This method will return a creation mode flag from a STGM value. + * The STGM value is assumed valid. + */ +static DWORD GetCreationModeFromSTGM(DWORD stgm) +{ + switch(STGM_CREATE_MODE(stgm)) + { + case STGM_CREATE: + return CREATE_ALWAYS; + case STGM_CONVERT: + FIXME("STGM_CONVERT not implemented!\n"); + return CREATE_NEW; + case STGM_FAILIFTHERE: + return CREATE_NEW; + } + ERR("Invalid create mode!\n"); + assert(0); + return 0; +} + + +/************************************************************************* + * OLECONVERT_LoadOLE10 [Internal] + * + * Loads the OLE10 STREAM to memory + * + * PARAMS + * pOleStream [I] The OLESTREAM + * pData [I] Data Structure for the OLESTREAM Data + * + * RETURNS + * Success: S_OK + * Failure: CONVERT10_E_OLESTREAM_GET for invalid Get + * CONVERT10_E_OLESTREAM_FMT if the OLEID is invalide + * + * NOTES + * This function is used by OleConvertOLESTREAMToIStorage only. + * + * Memory allocated for pData must be freed by the caller + */ +HRESULT OLECONVERT_LoadOLE10(LPOLESTREAM pOleStream, OLECONVERT_OLESTREAM_DATA *pData, BOOL bStrem1) +{ + DWORD dwSize; + HRESULT hRes = S_OK; + int nTryCnt=0; + int max_try = 6; + + pData->pData = NULL; + pData->pstrOleObjFileName = (CHAR *) NULL; + + for( nTryCnt=0;nTryCnt < max_try; nTryCnt++) + { + /* Get the OleID */ + dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID)); + if(dwSize != sizeof(pData->dwOleID)) + { + hRes = CONVERT10_E_OLESTREAM_GET; + } + else if(pData->dwOleID != OLESTREAM_ID) + { + hRes = CONVERT10_E_OLESTREAM_FMT; + } + else + { + hRes = S_OK; + break; + } + } + + if(hRes == S_OK) + { + /* Get the TypeID...more info needed for this field */ + dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID)); + if(dwSize != sizeof(pData->dwTypeID)) + { + hRes = CONVERT10_E_OLESTREAM_GET; + } + } + if(hRes == S_OK) + { + if(pData->dwTypeID != 0) + { + /* Get the length of the OleTypeName */ + dwSize = pOleStream->lpstbl->Get(pOleStream, (void *) &(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength)); + if(dwSize != sizeof(pData->dwOleTypeNameLength)) + { + hRes = CONVERT10_E_OLESTREAM_GET; + } + + if(hRes == S_OK) + { + if(pData->dwOleTypeNameLength > 0) + { + /* Get the OleTypeName */ + dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->strOleTypeName, pData->dwOleTypeNameLength); + if(dwSize != pData->dwOleTypeNameLength) + { + hRes = CONVERT10_E_OLESTREAM_GET; + } + } + } + if(bStrem1) + { + dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwOleObjFileNameLength), sizeof(pData->dwOleObjFileNameLength)); + if(dwSize != sizeof(pData->dwOleObjFileNameLength)) + { + hRes = CONVERT10_E_OLESTREAM_GET; + } + if(hRes == S_OK) + { + if(pData->dwOleObjFileNameLength < 1) /* there is no file name exist */ + pData->dwOleObjFileNameLength = sizeof(pData->dwOleObjFileNameLength); + pData->pstrOleObjFileName = HeapAlloc(GetProcessHeap(), 0, pData->dwOleObjFileNameLength); + if(pData->pstrOleObjFileName) + { + dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->pstrOleObjFileName),pData->dwOleObjFileNameLength); + if(dwSize != pData->dwOleObjFileNameLength) + { + hRes = CONVERT10_E_OLESTREAM_GET; + } + } + else + hRes = CONVERT10_E_OLESTREAM_GET; + } + } + else + { + /* Get the Width of the Metafile */ + dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth)); + if(dwSize != sizeof(pData->dwMetaFileWidth)) + { + hRes = CONVERT10_E_OLESTREAM_GET; + } + if(hRes == S_OK) + { + /* Get the Height of the Metafile */ + dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight)); + if(dwSize != sizeof(pData->dwMetaFileHeight)) + { + hRes = CONVERT10_E_OLESTREAM_GET; + } + } + } + if(hRes == S_OK) + { + /* Get the Length of the Data */ + dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength)); + if(dwSize != sizeof(pData->dwDataLength)) + { + hRes = CONVERT10_E_OLESTREAM_GET; + } + } + + if(hRes == S_OK) /* I don't know what is this 8 byts information is we have to figure out */ + { + if(!bStrem1) /* if it is a second OLE stream data */ + { + pData->dwDataLength -= 8; + dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)(pData->strUnknown), sizeof(pData->strUnknown)); + if(dwSize != sizeof(pData->strUnknown)) + { + hRes = CONVERT10_E_OLESTREAM_GET; + } + } + } + if(hRes == S_OK) + { + if(pData->dwDataLength > 0) + { + pData->pData = HeapAlloc(GetProcessHeap(),0,pData->dwDataLength); + + /* Get Data (ex. IStorage, Metafile, or BMP) */ + if(pData->pData) + { + dwSize = pOleStream->lpstbl->Get(pOleStream, (void *)pData->pData, pData->dwDataLength); + if(dwSize != pData->dwDataLength) + { + hRes = CONVERT10_E_OLESTREAM_GET; + } + } + else + { + hRes = CONVERT10_E_OLESTREAM_GET; + } + } + } + } + } + return hRes; +} + +/************************************************************************* + * OLECONVERT_SaveOLE10 [Internal] + * + * Saves the OLE10 STREAM From memory + * + * PARAMS + * pData [I] Data Structure for the OLESTREAM Data + * pOleStream [I] The OLESTREAM to save + * + * RETURNS + * Success: S_OK + * Failure: CONVERT10_E_OLESTREAM_PUT for invalid Put + * + * NOTES + * This function is used by OleConvertIStorageToOLESTREAM only. + * + */ +HRESULT OLECONVERT_SaveOLE10(OLECONVERT_OLESTREAM_DATA *pData, LPOLESTREAM pOleStream) +{ + DWORD dwSize; + HRESULT hRes = S_OK; + + + /* Set the OleID */ + dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleID), sizeof(pData->dwOleID)); + if(dwSize != sizeof(pData->dwOleID)) + { + hRes = CONVERT10_E_OLESTREAM_PUT; + } + + if(hRes == S_OK) + { + /* Set the TypeID */ + dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwTypeID), sizeof(pData->dwTypeID)); + if(dwSize != sizeof(pData->dwTypeID)) + { + hRes = CONVERT10_E_OLESTREAM_PUT; + } + } + + if(pData->dwOleID == OLESTREAM_ID && pData->dwTypeID != 0 && hRes == S_OK) + { + /* Set the Length of the OleTypeName */ + dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwOleTypeNameLength), sizeof(pData->dwOleTypeNameLength)); + if(dwSize != sizeof(pData->dwOleTypeNameLength)) + { + hRes = CONVERT10_E_OLESTREAM_PUT; + } + + if(hRes == S_OK) + { + if(pData->dwOleTypeNameLength > 0) + { + /* Set the OleTypeName */ + dwSize = pOleStream->lpstbl->Put(pOleStream, (void *) pData->strOleTypeName, pData->dwOleTypeNameLength); + if(dwSize != pData->dwOleTypeNameLength) + { + hRes = CONVERT10_E_OLESTREAM_PUT; + } + } + } + + if(hRes == S_OK) + { + /* Set the width of the Metafile */ + dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileWidth), sizeof(pData->dwMetaFileWidth)); + if(dwSize != sizeof(pData->dwMetaFileWidth)) + { + hRes = CONVERT10_E_OLESTREAM_PUT; + } + } + + if(hRes == S_OK) + { + /* Set the height of the Metafile */ + dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwMetaFileHeight), sizeof(pData->dwMetaFileHeight)); + if(dwSize != sizeof(pData->dwMetaFileHeight)) + { + hRes = CONVERT10_E_OLESTREAM_PUT; + } + } + + if(hRes == S_OK) + { + /* Set the length of the Data */ + dwSize = pOleStream->lpstbl->Put(pOleStream, (void *)&(pData->dwDataLength), sizeof(pData->dwDataLength)); + if(dwSize != sizeof(pData->dwDataLength)) + { + hRes = CONVERT10_E_OLESTREAM_PUT; + } + } + + if(hRes == S_OK) + { + if(pData->dwDataLength > 0) + { + /* Set the Data (eg. IStorage, Metafile, Bitmap) */ + dwSize = pOleStream->lpstbl->Put(pOleStream, (void *) pData->pData, pData->dwDataLength); + if(dwSize != pData->dwDataLength) + { + hRes = CONVERT10_E_OLESTREAM_PUT; + } + } + } + } + return hRes; +} + +/************************************************************************* + * OLECONVERT_GetOLE20FromOLE10[Internal] + * + * This function copies OLE10 Data (the IStorage in the OLESTREAM) to disk, + * opens it, and copies the content to the dest IStorage for + * OleConvertOLESTREAMToIStorage + * + * + * PARAMS + * pDestStorage [I] The IStorage to copy the data to + * pBuffer [I] Buffer that contains the IStorage from the OLESTREAM + * nBufferLength [I] The size of the buffer + * + * RETURNS + * Nothing + * + * NOTES + * + * + */ +void OLECONVERT_GetOLE20FromOLE10(LPSTORAGE pDestStorage, BYTE *pBuffer, DWORD nBufferLength) +{ + HRESULT hRes; + HANDLE hFile; + IStorage *pTempStorage; + DWORD dwNumOfBytesWritten; + WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH]; + static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0}; + + /* Create a temp File */ + GetTempPathW(MAX_PATH, wstrTempDir); + GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile); + hFile = CreateFileW(wstrTempFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + + if(hFile != INVALID_HANDLE_VALUE) + { + /* Write IStorage Data to File */ + WriteFile(hFile, pBuffer, nBufferLength, &dwNumOfBytesWritten, NULL); + CloseHandle(hFile); + + /* Open and copy temp storage to the Dest Storage */ + hRes = StgOpenStorage(wstrTempFile, NULL, STGM_READ, NULL, 0, &pTempStorage); + if(hRes == S_OK) + { + hRes = StorageImpl_CopyTo(pTempStorage, 0, NULL, NULL, pDestStorage); + StorageBaseImpl_Release(pTempStorage); + } + DeleteFileW(wstrTempFile); + } +} + + +/************************************************************************* + * OLECONVERT_WriteOLE20ToBuffer [Internal] + * + * Saves the OLE10 STREAM From memory + * + * PARAMS + * pStorage [I] The Src IStorage to copy + * pData [I] The Dest Memory to write to. + * + * RETURNS + * The size in bytes allocated for pData + * + * NOTES + * Memory allocated for pData must be freed by the caller + * + * Used by OleConvertIStorageToOLESTREAM only. + * + */ +DWORD OLECONVERT_WriteOLE20ToBuffer(LPSTORAGE pStorage, BYTE **pData) +{ + HANDLE hFile; + HRESULT hRes; + DWORD nDataLength = 0; + IStorage *pTempStorage; + WCHAR wstrTempDir[MAX_PATH], wstrTempFile[MAX_PATH]; + static const WCHAR wstrPrefix[] = {'s', 'i', 's', 0}; + + *pData = NULL; + + /* Create temp Storage */ + GetTempPathW(MAX_PATH, wstrTempDir); + GetTempFileNameW(wstrTempDir, wstrPrefix, 0, wstrTempFile); + hRes = StgCreateDocfile(wstrTempFile, STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pTempStorage); + + if(hRes == S_OK) + { + /* Copy Src Storage to the Temp Storage */ + StorageImpl_CopyTo(pStorage, 0, NULL, NULL, pTempStorage); + StorageBaseImpl_Release(pTempStorage); + + /* Open Temp Storage as a file and copy to memory */ + hFile = CreateFileW(wstrTempFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if(hFile != INVALID_HANDLE_VALUE) + { + nDataLength = GetFileSize(hFile, NULL); + *pData = HeapAlloc(GetProcessHeap(),0,nDataLength); + ReadFile(hFile, *pData, nDataLength, &nDataLength, 0); + CloseHandle(hFile); + } + DeleteFileW(wstrTempFile); + } + return nDataLength; +} + +/************************************************************************* + * OLECONVERT_CreateOleStream [Internal] + * + * Creates the "\001OLE" stream in the IStorage if necessary. + * + * PARAMS + * pStorage [I] Dest storage to create the stream in + * + * RETURNS + * Nothing + * + * NOTES + * This function is used by OleConvertOLESTREAMToIStorage only. + * + * This stream is still unknown, MS Word seems to have extra data + * but since the data is stored in the OLESTREAM there should be + * no need to recreate the stream. If the stream is manually + * deleted it will create it with this default data. + * + */ +void OLECONVERT_CreateOleStream(LPSTORAGE pStorage) +{ + HRESULT hRes; + IStream *pStream; + static const WCHAR wstrStreamName[] = {1,'O', 'l', 'e', 0}; + BYTE pOleStreamHeader [] = + { + 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + + /* Create stream if not present */ + hRes = IStorage_CreateStream(pStorage, wstrStreamName, + STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream ); + + if(hRes == S_OK) + { + /* Write default Data */ + hRes = IStream_Write(pStream, pOleStreamHeader, sizeof(pOleStreamHeader), NULL); + IStream_Release(pStream); + } +} + +/* write a string to a stream, preceded by its length */ +static HRESULT STREAM_WriteString( IStream *stm, LPCWSTR string ) +{ + HRESULT r; + LPSTR str; + DWORD len = 0; + + if( string ) + len = WideCharToMultiByte( CP_ACP, 0, string, -1, NULL, 0, NULL, NULL); + r = IStream_Write( stm, &len, sizeof(len), NULL); + if( FAILED( r ) ) + return r; + if(len == 0) + return r; + str = CoTaskMemAlloc( len ); + WideCharToMultiByte( CP_ACP, 0, string, -1, str, len, NULL, NULL); + r = IStream_Write( stm, str, len, NULL); + CoTaskMemFree( str ); + return r; +} + +/* read a string preceded by its length from a stream */ +static HRESULT STREAM_ReadString( IStream *stm, LPWSTR *string ) +{ + HRESULT r; + DWORD len, count = 0; + LPSTR str; + LPWSTR wstr; + + r = IStream_Read( stm, &len, sizeof(len), &count ); + if( FAILED( r ) ) + return r; + if( count != sizeof(len) ) + return E_OUTOFMEMORY; + + TRACE("%ld bytes\n",len); + + str = CoTaskMemAlloc( len ); + if( !str ) + return E_OUTOFMEMORY; + count = 0; + r = IStream_Read( stm, str, len, &count ); + if( FAILED( r ) ) + return r; + if( count != len ) + { + CoTaskMemFree( str ); + return E_OUTOFMEMORY; + } + + TRACE("Read string %s\n",debugstr_an(str,len)); + + len = MultiByteToWideChar( CP_ACP, 0, str, count, NULL, 0 ); + wstr = CoTaskMemAlloc( (len + 1)*sizeof (WCHAR) ); + if( wstr ) + MultiByteToWideChar( CP_ACP, 0, str, count, wstr, len ); + CoTaskMemFree( str ); + + *string = wstr; + + return r; +} + + +static HRESULT STORAGE_WriteCompObj( LPSTORAGE pstg, CLSID *clsid, + LPCWSTR lpszUserType, LPCWSTR szClipName, LPCWSTR szProgIDName ) +{ + IStream *pstm; + HRESULT r = S_OK; + static const WCHAR szwStreamName[] = {1, 'C', 'o', 'm', 'p', 'O', 'b', 'j', 0}; + + static const BYTE unknown1[12] = + { 0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF}; + static const BYTE unknown2[16] = + { 0xF4, 0x39, 0xB2, 0x71, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + TRACE("%p %s %s %s %s\n", pstg, debugstr_guid(clsid), + debugstr_w(lpszUserType), debugstr_w(szClipName), + debugstr_w(szProgIDName)); + + /* Create a CompObj stream if it doesn't exist */ + r = IStorage_CreateStream(pstg, szwStreamName, + STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pstm ); + if( FAILED (r) ) + return r; + + /* Write CompObj Structure to stream */ + r = IStream_Write(pstm, unknown1, sizeof(unknown1), NULL); + + if( SUCCEEDED( r ) ) + r = WriteClassStm( pstm, clsid ); + + if( SUCCEEDED( r ) ) + r = STREAM_WriteString( pstm, lpszUserType ); + if( SUCCEEDED( r ) ) + r = STREAM_WriteString( pstm, szClipName ); + if( SUCCEEDED( r ) ) + r = STREAM_WriteString( pstm, szProgIDName ); + if( SUCCEEDED( r ) ) + r = IStream_Write(pstm, unknown2, sizeof(unknown2), NULL); + + IStream_Release( pstm ); + + return r; +} + +/*********************************************************************** + * WriteFmtUserTypeStg (OLE32.@) + */ +HRESULT WINAPI WriteFmtUserTypeStg( + LPSTORAGE pstg, CLIPFORMAT cf, LPOLESTR lpszUserType) +{ + HRESULT r; + WCHAR szwClipName[0x40]; + CLSID clsid = CLSID_NULL; + LPWSTR wstrProgID = NULL; + DWORD n; + + TRACE("(%p,%x,%s)\n",pstg,cf,debugstr_w(lpszUserType)); + + /* get the clipboard format name */ + n = GetClipboardFormatNameW( cf, szwClipName, sizeof(szwClipName) ); + szwClipName[n]=0; + + TRACE("Clipboard name is %s\n", debugstr_w(szwClipName)); + + /* FIXME: There's room to save a CLSID and its ProgID, but + the CLSID is not looked up in the registry and in all the + tests I wrote it was CLSID_NULL. Where does it come from? + */ + + /* get the real program ID. This may fail, but that's fine */ + ProgIDFromCLSID(&clsid, &wstrProgID); + + TRACE("progid is %s\n",debugstr_w(wstrProgID)); + + r = STORAGE_WriteCompObj( pstg, &clsid, + lpszUserType, szwClipName, wstrProgID ); + + CoTaskMemFree(wstrProgID); + + return r; +} + + +/****************************************************************************** + * ReadFmtUserTypeStg [OLE32.@] + */ +HRESULT WINAPI ReadFmtUserTypeStg (LPSTORAGE pstg, CLIPFORMAT* pcf, LPOLESTR* lplpszUserType) +{ + HRESULT r; + IStream *stm = 0; + static const WCHAR szCompObj[] = { 1, 'C','o','m','p','O','b','j', 0 }; + unsigned char unknown1[12]; + unsigned char unknown2[16]; + DWORD count; + LPWSTR szProgIDName = NULL, szCLSIDName = NULL, szOleTypeName = NULL; + CLSID clsid; + + TRACE("(%p,%p,%p)\n", pstg, pcf, lplpszUserType); + + r = IStorage_OpenStream( pstg, szCompObj, NULL, + STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm ); + if( FAILED ( r ) ) + { + WARN("Failed to open stream r = %08lx\n", r); + return r; + } + + /* read the various parts of the structure */ + r = IStream_Read( stm, unknown1, sizeof(unknown1), &count ); + if( FAILED( r ) || ( count != sizeof(unknown1) ) ) + goto end; + r = ReadClassStm( stm, &clsid ); + if( FAILED( r ) ) + goto end; + + r = STREAM_ReadString( stm, &szCLSIDName ); + if( FAILED( r ) ) + goto end; + + r = STREAM_ReadString( stm, &szOleTypeName ); + if( FAILED( r ) ) + goto end; + + r = STREAM_ReadString( stm, &szProgIDName ); + if( FAILED( r ) ) + goto end; + + r = IStream_Read( stm, unknown2, sizeof(unknown2), &count ); + if( FAILED( r ) || ( count != sizeof(unknown2) ) ) + goto end; + + /* ok, success... now we just need to store what we found */ + if( pcf ) + *pcf = RegisterClipboardFormatW( szOleTypeName ); + CoTaskMemFree( szOleTypeName ); + + if( lplpszUserType ) + *lplpszUserType = szCLSIDName; + CoTaskMemFree( szProgIDName ); + +end: + IStream_Release( stm ); + + return r; +} + + +/************************************************************************* + * OLECONVERT_CreateCompObjStream [Internal] + * + * Creates a "\001CompObj" is the destination IStorage if necessary. + * + * PARAMS + * pStorage [I] The dest IStorage to create the CompObj Stream + * if necessary. + * strOleTypeName [I] The ProgID + * + * RETURNS + * Success: S_OK + * Failure: REGDB_E_CLASSNOTREG if cannot reconstruct the stream + * + * NOTES + * This function is used by OleConvertOLESTREAMToIStorage only. + * + * The stream data is stored in the OLESTREAM and there should be + * no need to recreate the stream. If the stream is manually + * deleted it will attempt to create it by querying the registry. + * + * + */ +HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName) +{ + IStream *pStream; + HRESULT hStorageRes, hRes = S_OK; + OLECONVERT_ISTORAGE_COMPOBJ IStorageCompObj; + static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0}; + WCHAR bufferW[OLESTREAM_MAX_STR_LEN]; + + BYTE pCompObjUnknown1[] = {0x01, 0x00, 0xFE, 0xFF, 0x03, 0x0A, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}; + BYTE pCompObjUnknown2[] = {0xF4, 0x39, 0xB2, 0x71}; + + /* Initialize the CompObj structure */ + memset(&IStorageCompObj, 0, sizeof(IStorageCompObj)); + memcpy(&(IStorageCompObj.byUnknown1), pCompObjUnknown1, sizeof(pCompObjUnknown1)); + memcpy(&(IStorageCompObj.byUnknown2), pCompObjUnknown2, sizeof(pCompObjUnknown2)); + + + /* Create a CompObj stream if it doesn't exist */ + hStorageRes = IStorage_CreateStream(pStorage, wstrStreamName, + STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream ); + if(hStorageRes == S_OK) + { + /* copy the OleTypeName to the compobj struct */ + IStorageCompObj.dwOleTypeNameLength = strlen(strOleTypeName)+1; + strcpy(IStorageCompObj.strOleTypeName, strOleTypeName); + + /* copy the OleTypeName to the compobj struct */ + /* Note: in the test made, these were Identical */ + IStorageCompObj.dwProgIDNameLength = strlen(strOleTypeName)+1; + strcpy(IStorageCompObj.strProgIDName, strOleTypeName); + + /* Get the CLSID */ + MultiByteToWideChar( CP_ACP, 0, IStorageCompObj.strProgIDName, -1, + bufferW, OLESTREAM_MAX_STR_LEN ); + hRes = CLSIDFromProgID(bufferW, &(IStorageCompObj.clsid)); + + if(hRes == S_OK) + { + HKEY hKey; + LONG hErr; + /* Get the CLSID Default Name from the Registry */ + hErr = RegOpenKeyA(HKEY_CLASSES_ROOT, IStorageCompObj.strProgIDName, &hKey); + if(hErr == ERROR_SUCCESS) + { + char strTemp[OLESTREAM_MAX_STR_LEN]; + IStorageCompObj.dwCLSIDNameLength = OLESTREAM_MAX_STR_LEN; + hErr = RegQueryValueA(hKey, NULL, strTemp, &(IStorageCompObj.dwCLSIDNameLength)); + if(hErr == ERROR_SUCCESS) + { + strcpy(IStorageCompObj.strCLSIDName, strTemp); + } + RegCloseKey(hKey); + } + } + + /* Write CompObj Structure to stream */ + hRes = IStream_Write(pStream, IStorageCompObj.byUnknown1, sizeof(IStorageCompObj.byUnknown1), NULL); + + WriteClassStm(pStream,&(IStorageCompObj.clsid)); + + hRes = IStream_Write(pStream, &(IStorageCompObj.dwCLSIDNameLength), sizeof(IStorageCompObj.dwCLSIDNameLength), NULL); + if(IStorageCompObj.dwCLSIDNameLength > 0) + { + hRes = IStream_Write(pStream, IStorageCompObj.strCLSIDName, IStorageCompObj.dwCLSIDNameLength, NULL); + } + hRes = IStream_Write(pStream, &(IStorageCompObj.dwOleTypeNameLength) , sizeof(IStorageCompObj.dwOleTypeNameLength), NULL); + if(IStorageCompObj.dwOleTypeNameLength > 0) + { + hRes = IStream_Write(pStream, IStorageCompObj.strOleTypeName , IStorageCompObj.dwOleTypeNameLength, NULL); + } + hRes = IStream_Write(pStream, &(IStorageCompObj.dwProgIDNameLength) , sizeof(IStorageCompObj.dwProgIDNameLength), NULL); + if(IStorageCompObj.dwProgIDNameLength > 0) + { + hRes = IStream_Write(pStream, IStorageCompObj.strProgIDName , IStorageCompObj.dwProgIDNameLength, NULL); + } + hRes = IStream_Write(pStream, IStorageCompObj.byUnknown2 , sizeof(IStorageCompObj.byUnknown2), NULL); + IStream_Release(pStream); + } + return hRes; +} + + +/************************************************************************* + * OLECONVERT_CreateOlePresStream[Internal] + * + * Creates the "\002OlePres000" Stream with the Metafile data + * + * PARAMS + * pStorage [I] The dest IStorage to create \002OLEPres000 stream in. + * dwExtentX [I] Width of the Metafile + * dwExtentY [I] Height of the Metafile + * pData [I] Metafile data + * dwDataLength [I] Size of the Metafile data + * + * RETURNS + * Success: S_OK + * Failure: CONVERT10_E_OLESTREAM_PUT for invalid Put + * + * NOTES + * This function is used by OleConvertOLESTREAMToIStorage only. + * + */ +void OLECONVERT_CreateOlePresStream(LPSTORAGE pStorage, DWORD dwExtentX, DWORD dwExtentY , BYTE *pData, DWORD dwDataLength) +{ + HRESULT hRes; + IStream *pStream; + static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0}; + BYTE pOlePresStreamHeader [] = + { + 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + + BYTE pOlePresStreamHeaderEmpty [] = + { + 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + + /* Create the OlePres000 Stream */ + hRes = IStorage_CreateStream(pStorage, wstrStreamName, + STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream ); + + if(hRes == S_OK) + { + DWORD nHeaderSize; + OLECONVERT_ISTORAGE_OLEPRES OlePres; + + memset(&OlePres, 0, sizeof(OlePres)); + /* Do we have any metafile data to save */ + if(dwDataLength > 0) + { + memcpy(OlePres.byUnknown1, pOlePresStreamHeader, sizeof(pOlePresStreamHeader)); + nHeaderSize = sizeof(pOlePresStreamHeader); + } + else + { + memcpy(OlePres.byUnknown1, pOlePresStreamHeaderEmpty, sizeof(pOlePresStreamHeaderEmpty)); + nHeaderSize = sizeof(pOlePresStreamHeaderEmpty); + } + /* Set width and height of the metafile */ + OlePres.dwExtentX = dwExtentX; + OlePres.dwExtentY = -dwExtentY; + + /* Set Data and Length */ + if(dwDataLength > sizeof(METAFILEPICT16)) + { + OlePres.dwSize = dwDataLength - sizeof(METAFILEPICT16); + OlePres.pData = &(pData[8]); + } + /* Save OlePres000 Data to Stream */ + hRes = IStream_Write(pStream, OlePres.byUnknown1, nHeaderSize, NULL); + hRes = IStream_Write(pStream, &(OlePres.dwExtentX), sizeof(OlePres.dwExtentX), NULL); + hRes = IStream_Write(pStream, &(OlePres.dwExtentY), sizeof(OlePres.dwExtentY), NULL); + hRes = IStream_Write(pStream, &(OlePres.dwSize), sizeof(OlePres.dwSize), NULL); + if(OlePres.dwSize > 0) + { + hRes = IStream_Write(pStream, OlePres.pData, OlePres.dwSize, NULL); + } + IStream_Release(pStream); + } +} + +/************************************************************************* + * OLECONVERT_CreateOle10NativeStream [Internal] + * + * Creates the "\001Ole10Native" Stream (should contain a BMP) + * + * PARAMS + * pStorage [I] Dest storage to create the stream in + * pData [I] Ole10 Native Data (ex. bmp) + * dwDataLength [I] Size of the Ole10 Native Data + * + * RETURNS + * Nothing + * + * NOTES + * This function is used by OleConvertOLESTREAMToIStorage only. + * + * Might need to verify the data and return appropriate error message + * + */ +void OLECONVERT_CreateOle10NativeStream(LPSTORAGE pStorage, BYTE *pData, DWORD dwDataLength) +{ + HRESULT hRes; + IStream *pStream; + static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0}; + + /* Create the Ole10Native Stream */ + hRes = IStorage_CreateStream(pStorage, wstrStreamName, + STGM_CREATE | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pStream ); + + if(hRes == S_OK) + { + /* Write info to stream */ + hRes = IStream_Write(pStream, &dwDataLength, sizeof(dwDataLength), NULL); + hRes = IStream_Write(pStream, pData, dwDataLength, NULL); + IStream_Release(pStream); + } + +} + +/************************************************************************* + * OLECONVERT_GetOLE10ProgID [Internal] + * + * Finds the ProgID (or OleTypeID) from the IStorage + * + * PARAMS + * pStorage [I] The Src IStorage to get the ProgID + * strProgID [I] the ProgID string to get + * dwSize [I] the size of the string + * + * RETURNS + * Success: S_OK + * Failure: REGDB_E_CLASSNOTREG if cannot reconstruct the stream + * + * NOTES + * This function is used by OleConvertIStorageToOLESTREAM only. + * + * + */ +HRESULT OLECONVERT_GetOLE10ProgID(LPSTORAGE pStorage, char *strProgID, DWORD *dwSize) +{ + HRESULT hRes; + IStream *pStream; + LARGE_INTEGER iSeekPos; + OLECONVERT_ISTORAGE_COMPOBJ CompObj; + static const WCHAR wstrStreamName[] = {1,'C', 'o', 'm', 'p', 'O', 'b', 'j', 0}; + + /* Open the CompObj Stream */ + hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL, + STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream ); + if(hRes == S_OK) + { + + /*Get the OleType from the CompObj Stream */ + iSeekPos.u.LowPart = sizeof(CompObj.byUnknown1) + sizeof(CompObj.clsid); + iSeekPos.u.HighPart = 0; + + IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL); + IStream_Read(pStream, &CompObj.dwCLSIDNameLength, sizeof(CompObj.dwCLSIDNameLength), NULL); + iSeekPos.u.LowPart = CompObj.dwCLSIDNameLength; + IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL); + IStream_Read(pStream, &CompObj.dwOleTypeNameLength, sizeof(CompObj.dwOleTypeNameLength), NULL); + iSeekPos.u.LowPart = CompObj.dwOleTypeNameLength; + IStream_Seek(pStream, iSeekPos, STREAM_SEEK_CUR , NULL); + + IStream_Read(pStream, dwSize, sizeof(*dwSize), NULL); + if(*dwSize > 0) + { + IStream_Read(pStream, strProgID, *dwSize, NULL); + } + IStream_Release(pStream); + } + else + { + STATSTG stat; + LPOLESTR wstrProgID; + + /* Get the OleType from the registry */ + REFCLSID clsid = &(stat.clsid); + IStorage_Stat(pStorage, &stat, STATFLAG_NONAME); + hRes = ProgIDFromCLSID(clsid, &wstrProgID); + if(hRes == S_OK) + { + *dwSize = WideCharToMultiByte(CP_ACP, 0, wstrProgID, -1, strProgID, *dwSize, NULL, FALSE); + } + + } + return hRes; +} + +/************************************************************************* + * OLECONVERT_GetOle10PresData [Internal] + * + * Converts IStorage "/001Ole10Native" stream to a OLE10 Stream + * + * PARAMS + * pStorage [I] Src IStroage + * pOleStream [I] Dest OleStream Mem Struct + * + * RETURNS + * Nothing + * + * NOTES + * This function is used by OleConvertIStorageToOLESTREAM only. + * + * Memory allocated for pData must be freed by the caller + * + * + */ +void OLECONVERT_GetOle10PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData) +{ + + HRESULT hRes; + IStream *pStream; + static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0}; + + /* Initialize Default data for OLESTREAM */ + pOleStreamData[0].dwOleID = OLESTREAM_ID; + pOleStreamData[0].dwTypeID = 2; + pOleStreamData[1].dwOleID = OLESTREAM_ID; + pOleStreamData[1].dwTypeID = 0; + pOleStreamData[0].dwMetaFileWidth = 0; + pOleStreamData[0].dwMetaFileHeight = 0; + pOleStreamData[0].pData = NULL; + pOleStreamData[1].pData = NULL; + + /* Open Ole10Native Stream */ + hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL, + STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream ); + if(hRes == S_OK) + { + + /* Read Size and Data */ + IStream_Read(pStream, &(pOleStreamData->dwDataLength), sizeof(pOleStreamData->dwDataLength), NULL); + if(pOleStreamData->dwDataLength > 0) + { + pOleStreamData->pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData->dwDataLength); + IStream_Read(pStream, pOleStreamData->pData, pOleStreamData->dwDataLength, NULL); + } + IStream_Release(pStream); + } + +} + + +/************************************************************************* + * OLECONVERT_GetOle20PresData[Internal] + * + * Converts IStorage "/002OlePres000" stream to a OLE10 Stream + * + * PARAMS + * pStorage [I] Src IStroage + * pOleStreamData [I] Dest OleStream Mem Struct + * + * RETURNS + * Nothing + * + * NOTES + * This function is used by OleConvertIStorageToOLESTREAM only. + * + * Memory allocated for pData must be freed by the caller + */ +void OLECONVERT_GetOle20PresData(LPSTORAGE pStorage, OLECONVERT_OLESTREAM_DATA *pOleStreamData) +{ + HRESULT hRes; + IStream *pStream; + OLECONVERT_ISTORAGE_OLEPRES olePress; + static const WCHAR wstrStreamName[] = {2, 'O', 'l', 'e', 'P', 'r', 'e', 's', '0', '0', '0', 0}; + + /* Initialize Default data for OLESTREAM */ + pOleStreamData[0].dwOleID = OLESTREAM_ID; + pOleStreamData[0].dwTypeID = 2; + pOleStreamData[0].dwMetaFileWidth = 0; + pOleStreamData[0].dwMetaFileHeight = 0; + pOleStreamData[0].dwDataLength = OLECONVERT_WriteOLE20ToBuffer(pStorage, &(pOleStreamData[0].pData)); + pOleStreamData[1].dwOleID = OLESTREAM_ID; + pOleStreamData[1].dwTypeID = 0; + pOleStreamData[1].dwOleTypeNameLength = 0; + pOleStreamData[1].strOleTypeName[0] = 0; + pOleStreamData[1].dwMetaFileWidth = 0; + pOleStreamData[1].dwMetaFileHeight = 0; + pOleStreamData[1].pData = NULL; + pOleStreamData[1].dwDataLength = 0; + + + /* Open OlePress000 stream */ + hRes = IStorage_OpenStream(pStorage, wstrStreamName, NULL, + STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream ); + if(hRes == S_OK) + { + LARGE_INTEGER iSeekPos; + METAFILEPICT16 MetaFilePict; + static const char strMetafilePictName[] = "METAFILEPICT"; + + /* Set the TypeID for a Metafile */ + pOleStreamData[1].dwTypeID = 5; + + /* Set the OleTypeName to Metafile */ + pOleStreamData[1].dwOleTypeNameLength = strlen(strMetafilePictName) +1; + strcpy(pOleStreamData[1].strOleTypeName, strMetafilePictName); + + iSeekPos.u.HighPart = 0; + iSeekPos.u.LowPart = sizeof(olePress.byUnknown1); + + /* Get Presentation Data */ + IStream_Seek(pStream, iSeekPos, STREAM_SEEK_SET, NULL); + IStream_Read(pStream, &(olePress.dwExtentX), sizeof(olePress.dwExtentX), NULL); + IStream_Read(pStream, &(olePress.dwExtentY), sizeof(olePress.dwExtentY), NULL); + IStream_Read(pStream, &(olePress.dwSize), sizeof(olePress.dwSize), NULL); + + /*Set width and Height */ + pOleStreamData[1].dwMetaFileWidth = olePress.dwExtentX; + pOleStreamData[1].dwMetaFileHeight = -olePress.dwExtentY; + if(olePress.dwSize > 0) + { + /* Set Length */ + pOleStreamData[1].dwDataLength = olePress.dwSize + sizeof(METAFILEPICT16); + + /* Set MetaFilePict struct */ + MetaFilePict.mm = 8; + MetaFilePict.xExt = olePress.dwExtentX; + MetaFilePict.yExt = olePress.dwExtentY; + MetaFilePict.hMF = 0; + + /* Get Metafile Data */ + pOleStreamData[1].pData = HeapAlloc(GetProcessHeap(),0,pOleStreamData[1].dwDataLength); + memcpy(pOleStreamData[1].pData, &MetaFilePict, sizeof(MetaFilePict)); + IStream_Read(pStream, &(pOleStreamData[1].pData[sizeof(MetaFilePict)]), pOleStreamData[1].dwDataLength-sizeof(METAFILEPICT16), NULL); + } + IStream_Release(pStream); + } +} + +/************************************************************************* + * OleConvertOLESTREAMToIStorage [OLE32.@] + * + * Read info on MSDN + * + * TODO + * DVTARGETDEVICE paramenter is not handled + * Still unsure of some mem fields for OLE 10 Stream + * Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj", + * and "\001OLE" streams + * + */ +HRESULT WINAPI OleConvertOLESTREAMToIStorage ( + LPOLESTREAM pOleStream, + LPSTORAGE pstg, + const DVTARGETDEVICE* ptd) +{ + int i; + HRESULT hRes=S_OK; + OLECONVERT_OLESTREAM_DATA pOleStreamData[2]; + + memset(pOleStreamData, 0, sizeof(pOleStreamData)); + + if(ptd != NULL) + { + FIXME("DVTARGETDEVICE is not NULL, unhandled parameter\n"); + } + + if(pstg == NULL || pOleStream == NULL) + { + hRes = E_INVALIDARG; + } + + if(hRes == S_OK) + { + /* Load the OLESTREAM to Memory */ + hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[0], TRUE); + } + + if(hRes == S_OK) + { + /* Load the OLESTREAM to Memory (part 2)*/ + hRes = OLECONVERT_LoadOLE10(pOleStream, &pOleStreamData[1], FALSE); + } + + if(hRes == S_OK) + { + + if(pOleStreamData[0].dwDataLength > sizeof(STORAGE_magic)) + { + /* Do we have the IStorage Data in the OLESTREAM */ + if(memcmp(pOleStreamData[0].pData, STORAGE_magic, sizeof(STORAGE_magic)) ==0) + { + OLECONVERT_GetOLE20FromOLE10(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength); + OLECONVERT_CreateOlePresStream(pstg, pOleStreamData[1].dwMetaFileWidth, pOleStreamData[1].dwMetaFileHeight, pOleStreamData[1].pData, pOleStreamData[1].dwDataLength); + } + else + { + /* It must be an original OLE 1.0 source */ + OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength); + } + } + else + { + /* It must be an original OLE 1.0 source */ + OLECONVERT_CreateOle10NativeStream(pstg, pOleStreamData[0].pData, pOleStreamData[0].dwDataLength); + } + + /* Create CompObj Stream if necessary */ + hRes = OLECONVERT_CreateCompObjStream(pstg, pOleStreamData[0].strOleTypeName); + if(hRes == S_OK) + { + /*Create the Ole Stream if necessary */ + OLECONVERT_CreateOleStream(pstg); + } + } + + + /* Free allocated memory */ + for(i=0; i < 2; i++) + { + HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData); + HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName); + pOleStreamData[i].pstrOleObjFileName = NULL; + } + return hRes; +} + +/************************************************************************* + * OleConvertIStorageToOLESTREAM [OLE32.@] + * + * Read info on MSDN + * + * Read info on MSDN + * + * TODO + * Still unsure of some mem fields for OLE 10 Stream + * Still some unknowns for the IStorage: "\002OlePres000", "\001CompObj", + * and "\001OLE" streams. + * + */ +HRESULT WINAPI OleConvertIStorageToOLESTREAM ( + LPSTORAGE pstg, + LPOLESTREAM pOleStream) +{ + int i; + HRESULT hRes = S_OK; + IStream *pStream; + OLECONVERT_OLESTREAM_DATA pOleStreamData[2]; + static const WCHAR wstrStreamName[] = {1, 'O', 'l', 'e', '1', '0', 'N', 'a', 't', 'i', 'v', 'e', 0}; + + + memset(pOleStreamData, 0, sizeof(pOleStreamData)); + + if(pstg == NULL || pOleStream == NULL) + { + hRes = E_INVALIDARG; + } + if(hRes == S_OK) + { + /* Get the ProgID */ + pOleStreamData[0].dwOleTypeNameLength = OLESTREAM_MAX_STR_LEN; + hRes = OLECONVERT_GetOLE10ProgID(pstg, pOleStreamData[0].strOleTypeName, &(pOleStreamData[0].dwOleTypeNameLength)); + } + if(hRes == S_OK) + { + /* Was it originally Ole10 */ + hRes = IStorage_OpenStream(pstg, wstrStreamName, 0, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream); + if(hRes == S_OK) + { + IStream_Release(pStream); + /* Get Presentation Data for Ole10Native */ + OLECONVERT_GetOle10PresData(pstg, pOleStreamData); + } + else + { + /* Get Presentation Data (OLE20) */ + OLECONVERT_GetOle20PresData(pstg, pOleStreamData); + } + + /* Save OLESTREAM */ + hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[0]), pOleStream); + if(hRes == S_OK) + { + hRes = OLECONVERT_SaveOLE10(&(pOleStreamData[1]), pOleStream); + } + + } + + /* Free allocated memory */ + for(i=0; i < 2; i++) + { + HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData); + } + + return hRes; +} + +/*********************************************************************** + * GetConvertStg (OLE32.@) + */ +HRESULT WINAPI GetConvertStg(IStorage *stg) { + FIXME("unimplemented stub!\n"); + return E_FAIL; +} + +/****************************************************************************** + * StgIsStorageFile [OLE32.@] + */ +HRESULT WINAPI +StgIsStorageFile(LPCOLESTR fn) +{ + HANDLE hf; + BYTE magic[8]; + DWORD bytes_read; + + TRACE("(\'%s\')\n", debugstr_w(fn)); + hf = CreateFileW(fn, GENERIC_READ, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + + if (hf == INVALID_HANDLE_VALUE) + return STG_E_FILENOTFOUND; + + if (!ReadFile(hf, magic, 8, &bytes_read, NULL)) + { + WARN(" unable to read file\n"); + CloseHandle(hf); + return S_FALSE; + } + + CloseHandle(hf); + + if (bytes_read != 8) { + WARN(" too short\n"); + return S_FALSE; + } + + if (!memcmp(magic,STORAGE_magic,8)) { + WARN(" -> YES\n"); + return S_OK; + } + + WARN(" -> Invalid header.\n"); + return S_FALSE; +} diff --git a/reactos/lib/ole32/storage32.h b/reactos/lib/ole32/storage32.h index c96bfe139de..32d1dbc3ed5 100644 --- a/reactos/lib/ole32/storage32.h +++ b/reactos/lib/ole32/storage32.h @@ -1,695 +1,695 @@ -/* - * Compound Storage (32 bit version) - * - * Implemented using the documentation of the LAOLA project at - * <URL:http://wwwwbs.cs.tu-berlin.de/~schwartz/pmh/index.html> - * (Thanks to Martin Schwartz <schwartz@cs.tu-berlin.de>) - * - * This include file contains definitions of types and function - * prototypes that are used in the many files implementing the - * storage functionality - * - * Copyright 1998,1999 Francis Beaudet - * Copyright 1998,1999 Thuy Nguyen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef __STORAGE32_H__ -#define __STORAGE32_H__ - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winnt.h" -#include "objbase.h" -#include "winreg.h" -#include "winternl.h" - -/* - * Definitions for the file format offsets. - */ -static const ULONG OFFSET_BIGBLOCKSIZEBITS = 0x0000001e; -static const ULONG OFFSET_SMALLBLOCKSIZEBITS = 0x00000020; -static const ULONG OFFSET_BBDEPOTCOUNT = 0x0000002C; -static const ULONG OFFSET_ROOTSTARTBLOCK = 0x00000030; -static const ULONG OFFSET_SBDEPOTSTART = 0x0000003C; -static const ULONG OFFSET_SBDEPOTCOUNT = 0x00000040; -static const ULONG OFFSET_EXTBBDEPOTSTART = 0x00000044; -static const ULONG OFFSET_EXTBBDEPOTCOUNT = 0x00000048; -static const ULONG OFFSET_BBDEPOTSTART = 0x0000004C; -static const ULONG OFFSET_PS_NAME = 0x00000000; -static const ULONG OFFSET_PS_NAMELENGTH = 0x00000040; -static const ULONG OFFSET_PS_PROPERTYTYPE = 0x00000042; -static const ULONG OFFSET_PS_PREVIOUSPROP = 0x00000044; -static const ULONG OFFSET_PS_NEXTPROP = 0x00000048; -static const ULONG OFFSET_PS_DIRPROP = 0x0000004C; -static const ULONG OFFSET_PS_GUID = 0x00000050; -static const ULONG OFFSET_PS_TSS1 = 0x00000064; -static const ULONG OFFSET_PS_TSD1 = 0x00000068; -static const ULONG OFFSET_PS_TSS2 = 0x0000006C; -static const ULONG OFFSET_PS_TSD2 = 0x00000070; -static const ULONG OFFSET_PS_STARTBLOCK = 0x00000074; -static const ULONG OFFSET_PS_SIZE = 0x00000078; -static const WORD DEF_BIG_BLOCK_SIZE_BITS = 0x0009; -static const WORD DEF_SMALL_BLOCK_SIZE_BITS = 0x0006; -static const WORD DEF_BIG_BLOCK_SIZE = 0x0200; -static const WORD DEF_SMALL_BLOCK_SIZE = 0x0040; -static const ULONG BLOCK_EXTBBDEPOT = 0xFFFFFFFC; -static const ULONG BLOCK_SPECIAL = 0xFFFFFFFD; -static const ULONG BLOCK_END_OF_CHAIN = 0xFFFFFFFE; -static const ULONG BLOCK_UNUSED = 0xFFFFFFFF; -static const ULONG PROPERTY_NULL = 0xFFFFFFFF; - -#define PROPERTY_NAME_MAX_LEN 0x20 -#define PROPERTY_NAME_BUFFER_LEN 0x40 - -#define PROPSET_BLOCK_SIZE 0x00000080 - -/* - * Property type of relation - */ -#define PROPERTY_RELATION_PREVIOUS 0 -#define PROPERTY_RELATION_NEXT 1 -#define PROPERTY_RELATION_DIR 2 - -/* - * Property type constants - */ -#define PROPTYPE_STORAGE 0x01 -#define PROPTYPE_STREAM 0x02 -#define PROPTYPE_ROOT 0x05 - -/* - * These defines assume a hardcoded blocksize. The code will assert - * if the blocksize is different. Some changes will have to be done if it - * becomes the case. - */ -#define BIG_BLOCK_SIZE 0x200 -#define COUNT_BBDEPOTINHEADER 109 -#define LIMIT_TO_USE_SMALL_BLOCK 0x1000 -#define NUM_BLOCKS_PER_DEPOT_BLOCK 128 - -#define STGM_ACCESS_MODE(stgm) ((stgm)&0x0000f) -#define STGM_SHARE_MODE(stgm) ((stgm)&0x000f0) -#define STGM_CREATE_MODE(stgm) ((stgm)&0x0f000) - -#define STGM_KNOWN_FLAGS (0xf0ff | \ - STGM_TRANSACTED | STGM_CONVERT | STGM_PRIORITY | STGM_NOSCRATCH | \ - STGM_NOSNAPSHOT | STGM_DIRECT_SWMR | STGM_DELETEONRELEASE | STGM_SIMPLE) - -/* - * These are signatures to detect the type of Document file. - */ -static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1}; -static const BYTE STORAGE_oldmagic[8] ={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d}; - -/* - * Forward declarations of all the structures used by the storage - * module. - */ -typedef struct StorageBaseImpl StorageBaseImpl; -typedef struct StorageImpl StorageImpl; -typedef struct StorageInternalImpl StorageInternalImpl; -typedef struct BlockChainStream BlockChainStream; -typedef struct SmallBlockChainStream SmallBlockChainStream; -typedef struct IEnumSTATSTGImpl IEnumSTATSTGImpl; -typedef struct StgProperty StgProperty; -typedef struct StgStreamImpl StgStreamImpl; - -/* - * This utility structure is used to read/write the information in a storage - * property. - */ -struct StgProperty -{ - WCHAR name[PROPERTY_NAME_MAX_LEN]; - WORD sizeOfNameString; - BYTE propertyType; - ULONG previousProperty; - ULONG nextProperty; - ULONG dirProperty; - GUID propertyUniqueID; - ULONG timeStampS1; - ULONG timeStampD1; - ULONG timeStampS2; - ULONG timeStampD2; - ULONG startingBlock; - ULARGE_INTEGER size; -}; - -/************************************************************************* - * Big Block File support - * - * The big block file is an abstraction of a flat file separated in - * same sized blocks. The implementation for the methods described in - * this section appear in stg_bigblockfile.c - */ - -/* - * Declaration of the data structures - */ -typedef struct BigBlockFile BigBlockFile,*LPBIGBLOCKFILE; -typedef struct MappedPage MappedPage,*LPMAPPEDPAGE; - -struct BigBlockFile -{ - BOOL fileBased; - ULARGE_INTEGER filesize; - ULONG blocksize; - HANDLE hfile; - HANDLE hfilemap; - DWORD flProtect; - MappedPage *maplist; - MappedPage *victimhead, *victimtail; - ULONG num_victim_pages; - ILockBytes *pLkbyt; - HGLOBAL hbytearray; - LPVOID pbytearray; -}; - -/* - * Declaration of the functions used to manipulate the BigBlockFile - * data structure. - */ -BigBlockFile* BIGBLOCKFILE_Construct(HANDLE hFile, - ILockBytes* pLkByt, - DWORD openFlags, - ULONG blocksize, - BOOL fileBased); -void BIGBLOCKFILE_Destructor(LPBIGBLOCKFILE This); -void* BIGBLOCKFILE_GetBigBlock(LPBIGBLOCKFILE This, ULONG index); -void* BIGBLOCKFILE_GetROBigBlock(LPBIGBLOCKFILE This, ULONG index); -void BIGBLOCKFILE_ReleaseBigBlock(LPBIGBLOCKFILE This, void *pBlock); -void BIGBLOCKFILE_SetSize(LPBIGBLOCKFILE This, ULARGE_INTEGER newSize); -ULARGE_INTEGER BIGBLOCKFILE_GetSize(LPBIGBLOCKFILE This); - -/************************************************************************* - * Ole Convert support - */ - -void OLECONVERT_CreateOleStream(LPSTORAGE pStorage); -HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName); - -/**************************************************************************** - * Storage32BaseImpl definitions. - * - * This structure defines the base information contained in all implementations - * of IStorage32 contained in this file storage implementation. - * - * In OOP terms, this is the base class for all the IStorage32 implementations - * contained in this file. - */ -struct StorageBaseImpl -{ - IStorageVtbl *lpVtbl; /* Needs to be the first item in the struct - * since we want to cast this in a Storage32 pointer */ - - IPropertySetStorageVtbl *pssVtbl; /* interface for adding a properties stream */ - - /* - * Reference count of this object - */ - ULONG ref; - - /* - * Ancestor storage (top level) - */ - StorageImpl* ancestorStorage; - - /* - * Index of the property for the root of - * this storage - */ - ULONG rootPropertySetIndex; - - /* - * virtual Destructor method. - */ - void (*v_destructor)(StorageBaseImpl*); - - /* - * flags that this storage was opened or created with - */ - DWORD openFlags; -}; - - -/**************************************************************************** - * Storage32Impl definitions. - * - * This implementation of the IStorage32 interface represents a root - * storage. Basically, a document file. - */ -struct StorageImpl -{ - struct StorageBaseImpl base; - - /* - * The following data members are specific to the Storage32Impl - * class - */ - HANDLE hFile; /* Physical support for the Docfile */ - LPOLESTR pwcsName; /* Full path of the document file */ - - /* FIXME: should this be in Storage32BaseImpl ? */ - WCHAR filename[PROPERTY_NAME_BUFFER_LEN]; - - /* - * File header - */ - WORD bigBlockSizeBits; - WORD smallBlockSizeBits; - ULONG bigBlockSize; - ULONG smallBlockSize; - ULONG bigBlockDepotCount; - ULONG rootStartBlock; - ULONG smallBlockDepotStart; - ULONG extBigBlockDepotStart; - ULONG extBigBlockDepotCount; - ULONG bigBlockDepotStart[COUNT_BBDEPOTINHEADER]; - - ULONG blockDepotCached[NUM_BLOCKS_PER_DEPOT_BLOCK]; - ULONG indexBlockDepotCached; - ULONG prevFreeBlock; - - /* - * Abstraction of the big block chains for the chains of the header. - */ - BlockChainStream* rootBlockChain; - BlockChainStream* smallBlockDepotChain; - BlockChainStream* smallBlockRootChain; - - /* - * Pointer to the big block file abstraction - */ - BigBlockFile* bigBlockFile; -}; - -void StorageImpl_Destroy( - StorageBaseImpl* This); - -HRESULT StorageImpl_Construct( - StorageImpl* This, - HANDLE hFile, - LPCOLESTR pwcsName, - ILockBytes* pLkbyt, - DWORD openFlags, - BOOL fileBased, - BOOL fileCreate); - -BOOL StorageImpl_ReadBigBlock( - StorageImpl* This, - ULONG blockIndex, - void* buffer); - -BOOL StorageImpl_WriteBigBlock( - StorageImpl* This, - ULONG blockIndex, - void* buffer); - -void* StorageImpl_GetROBigBlock( - StorageImpl* This, - ULONG blockIndex); - -void* StorageImpl_GetBigBlock( - StorageImpl* This, - ULONG blockIndex); - -void StorageImpl_ReleaseBigBlock( - StorageImpl* This, - void* pBigBlock); - -ULONG StorageImpl_GetNextFreeBigBlock( - StorageImpl* This); - -void StorageImpl_FreeBigBlock( - StorageImpl* This, - ULONG blockIndex); - -HRESULT StorageImpl_GetNextBlockInChain( - StorageImpl* This, - ULONG blockIndex, - ULONG* nextBlockIndex); - -void StorageImpl_SetNextBlockInChain( - StorageImpl* This, - ULONG blockIndex, - ULONG nextBlock); - -HRESULT StorageImpl_LoadFileHeader( - StorageImpl* This); - -void StorageImpl_SaveFileHeader( - StorageImpl* This); - -BOOL StorageImpl_ReadProperty( - StorageImpl* This, - ULONG index, - StgProperty* buffer); - -BOOL StorageImpl_WriteProperty( - StorageImpl* This, - ULONG index, - StgProperty* buffer); - -BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks( - StorageImpl* This, - SmallBlockChainStream** ppsbChain); - -ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, - ULONG blockIndex); - -void Storage32Impl_AddBlockDepot(StorageImpl* This, - ULONG blockIndex); - -ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This); - -ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, - ULONG depotIndex); - -void Storage32Impl_SetExtDepotBlock(StorageImpl* This, - ULONG depotIndex, - ULONG blockIndex); -/**************************************************************************** - * Storage32InternalImpl definitions. - * - * Definition of the implementation structure for the IStorage32 interface. - * This one implements the IStorage32 interface for storage that are - * inside another storage. - */ -struct StorageInternalImpl -{ - struct StorageBaseImpl base; - - /* - * There is no specific data for this class. - */ -}; - -/* - * Method definitions for the Storage32InternalImpl class. - */ -StorageInternalImpl* StorageInternalImpl_Construct( - StorageImpl* ancestorStorage, - DWORD openFlags, - ULONG rootTropertyIndex); - -void StorageInternalImpl_Destroy( - StorageBaseImpl* This); - -HRESULT WINAPI StorageInternalImpl_Commit( - IStorage* iface, - DWORD grfCommitFlags); /* [in] */ - -HRESULT WINAPI StorageInternalImpl_Revert( - IStorage* iface); - - -/**************************************************************************** - * IEnumSTATSTGImpl definitions. - * - * Definition of the implementation structure for the IEnumSTATSTGImpl interface. - * This class allows iterating through the content of a storage and to find - * specific items inside it. - */ -struct IEnumSTATSTGImpl -{ - IEnumSTATSTGVtbl *lpVtbl; /* Needs to be the first item in the struct - * since we want to cast this in an IEnumSTATSTG pointer */ - - ULONG ref; /* Reference count */ - StorageImpl* parentStorage; /* Reference to the parent storage */ - ULONG firstPropertyNode; /* Index of the root of the storage to enumerate */ - - /* - * The current implementation of the IEnumSTATSTGImpl class uses a stack - * to walk the property sets to get the content of a storage. This stack - * is implemented by the following 3 data members - */ - ULONG stackSize; - ULONG stackMaxSize; - ULONG* stackToVisit; - -#define ENUMSTATSGT_SIZE_INCREMENT 10 -}; - -IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct( - StorageImpl* This, - ULONG firstPropertyNode); - -void IEnumSTATSTGImpl_Destroy( - IEnumSTATSTGImpl* This); - -void IEnumSTATSTGImpl_PushSearchNode( - IEnumSTATSTGImpl* This, - ULONG nodeToPush); - -ULONG IEnumSTATSTGImpl_PopSearchNode( - IEnumSTATSTGImpl* This, - BOOL remove); - -ULONG IEnumSTATSTGImpl_FindProperty( - IEnumSTATSTGImpl* This, - const OLECHAR* lpszPropName, - StgProperty* buffer); - -INT IEnumSTATSTGImpl_FindParentProperty( - IEnumSTATSTGImpl *This, - ULONG childProperty, - StgProperty *currentProperty, - ULONG *propertyId); - - -/**************************************************************************** - * StgStreamImpl definitions. - * - * This class imlements the IStream32 inteface and represents a stream - * located inside a storage object. - */ -struct StgStreamImpl -{ - IStreamVtbl *lpVtbl; /* Needs to be the first item in the struct - * since we want to cast this to an IStream pointer */ - - /* - * Reference count - */ - ULONG ref; - - /* - * Storage that is the parent(owner) of the stream - */ - StorageBaseImpl* parentStorage; - - /* - * Access mode of this stream. - */ - DWORD grfMode; - - /* - * Index of the property that owns (points to) this stream. - */ - ULONG ownerProperty; - - /* - * Helper variable that contains the size of the stream - */ - ULARGE_INTEGER streamSize; - - /* - * This is the current position of the cursor in the stream - */ - ULARGE_INTEGER currentPosition; - - /* - * The information in the stream is represented by a chain of small blocks - * or a chain of large blocks. Depending on the case, one of the two - * following variabled points to that information. - */ - BlockChainStream* bigBlockChain; - SmallBlockChainStream* smallBlockChain; -}; - -/* - * Method definition for the StgStreamImpl class. - */ -StgStreamImpl* StgStreamImpl_Construct( - StorageBaseImpl* parentStorage, - DWORD grfMode, - ULONG ownerProperty); - - -/****************************************************************************** - * Endian conversion macros - */ -#ifdef WORDS_BIGENDIAN - -#define htole32(x) RtlUlongByteSwap(x) -#define htole16(x) RtlUshortByteSwap(x) -#define le32toh(x) RtlUlongByteSwap(x) -#define le16toh(x) RtlUshortByteSwap(x) - -#else - -#define htole32(x) (x) -#define htole16(x) (x) -#define le32toh(x) (x) -#define le16toh(x) (x) - -#endif - -/****************************************************************************** - * The StorageUtl_ functions are miscellaneous utility functions. Most of which - * are abstractions used to read values from file buffers without having to - * worry about bit order - */ -void StorageUtl_ReadWord(const BYTE* buffer, ULONG offset, WORD* value); -void StorageUtl_WriteWord(BYTE* buffer, ULONG offset, WORD value); -void StorageUtl_ReadDWord(const BYTE* buffer, ULONG offset, DWORD* value); -void StorageUtl_WriteDWord(BYTE* buffer, ULONG offset, DWORD value); -void StorageUtl_ReadULargeInteger(const BYTE* buffer, ULONG offset, - ULARGE_INTEGER* value); -void StorageUtl_WriteULargeInteger(BYTE* buffer, ULONG offset, - const ULARGE_INTEGER *value); -void StorageUtl_ReadGUID(const BYTE* buffer, ULONG offset, GUID* value); -void StorageUtl_WriteGUID(BYTE* buffer, ULONG offset, const GUID* value); -void StorageUtl_CopyPropertyToSTATSTG(STATSTG* destination, - StgProperty* source, - int statFlags); - -/**************************************************************************** - * BlockChainStream definitions. - * - * The BlockChainStream class is a utility class that is used to create an - * abstraction of the big block chains in the storage file. - */ -struct BlockChainStream -{ - StorageImpl* parentStorage; - ULONG* headOfStreamPlaceHolder; - ULONG ownerPropertyIndex; - ULONG lastBlockNoInSequence; - ULONG lastBlockNoInSequenceIndex; - ULONG tailIndex; - ULONG numBlocks; -}; - -/* - * Methods for the BlockChainStream class. - */ -BlockChainStream* BlockChainStream_Construct( - StorageImpl* parentStorage, - ULONG* headOfStreamPlaceHolder, - ULONG propertyIndex); - -void BlockChainStream_Destroy( - BlockChainStream* This); - -ULONG BlockChainStream_GetHeadOfChain( - BlockChainStream* This); - -BOOL BlockChainStream_ReadAt( - BlockChainStream* This, - ULARGE_INTEGER offset, - ULONG size, - void* buffer, - ULONG* bytesRead); - -BOOL BlockChainStream_WriteAt( - BlockChainStream* This, - ULARGE_INTEGER offset, - ULONG size, - const void* buffer, - ULONG* bytesWritten); - -BOOL BlockChainStream_SetSize( - BlockChainStream* This, - ULARGE_INTEGER newSize); - -ULARGE_INTEGER BlockChainStream_GetSize( - BlockChainStream* This); - -ULONG BlockChainStream_GetCount( - BlockChainStream* This); - -/**************************************************************************** - * SmallBlockChainStream definitions. - * - * The SmallBlockChainStream class is a utility class that is used to create an - * abstraction of the small block chains in the storage file. - */ -struct SmallBlockChainStream -{ - StorageImpl* parentStorage; - ULONG ownerPropertyIndex; -}; - -/* - * Methods of the SmallBlockChainStream class. - */ -SmallBlockChainStream* SmallBlockChainStream_Construct( - StorageImpl* parentStorage, - ULONG propertyIndex); - -void SmallBlockChainStream_Destroy( - SmallBlockChainStream* This); - -ULONG SmallBlockChainStream_GetHeadOfChain( - SmallBlockChainStream* This); - -HRESULT SmallBlockChainStream_GetNextBlockInChain( - SmallBlockChainStream* This, - ULONG blockIndex, - ULONG* nextBlockIndex); - -void SmallBlockChainStream_SetNextBlockInChain( - SmallBlockChainStream* This, - ULONG blockIndex, - ULONG nextBlock); - -void SmallBlockChainStream_FreeBlock( - SmallBlockChainStream* This, - ULONG blockIndex); - -ULONG SmallBlockChainStream_GetNextFreeBlock( - SmallBlockChainStream* This); - -BOOL SmallBlockChainStream_ReadAt( - SmallBlockChainStream* This, - ULARGE_INTEGER offset, - ULONG size, - void* buffer, - ULONG* bytesRead); - -BOOL SmallBlockChainStream_WriteAt( - SmallBlockChainStream* This, - ULARGE_INTEGER offset, - ULONG size, - const void* buffer, - ULONG* bytesWritten); - -BOOL SmallBlockChainStream_SetSize( - SmallBlockChainStream* This, - ULARGE_INTEGER newSize); - -ULARGE_INTEGER SmallBlockChainStream_GetSize( - SmallBlockChainStream* This); - -ULONG SmallBlockChainStream_GetCount( - SmallBlockChainStream* This); - - -#endif /* __STORAGE32_H__ */ +/* + * Compound Storage (32 bit version) + * + * Implemented using the documentation of the LAOLA project at + * <URL:http://wwwwbs.cs.tu-berlin.de/~schwartz/pmh/index.html> + * (Thanks to Martin Schwartz <schwartz@cs.tu-berlin.de>) + * + * This include file contains definitions of types and function + * prototypes that are used in the many files implementing the + * storage functionality + * + * Copyright 1998,1999 Francis Beaudet + * Copyright 1998,1999 Thuy Nguyen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __STORAGE32_H__ +#define __STORAGE32_H__ + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winnt.h" +#include "objbase.h" +#include "winreg.h" +#include "winternl.h" + +/* + * Definitions for the file format offsets. + */ +static const ULONG OFFSET_BIGBLOCKSIZEBITS = 0x0000001e; +static const ULONG OFFSET_SMALLBLOCKSIZEBITS = 0x00000020; +static const ULONG OFFSET_BBDEPOTCOUNT = 0x0000002C; +static const ULONG OFFSET_ROOTSTARTBLOCK = 0x00000030; +static const ULONG OFFSET_SBDEPOTSTART = 0x0000003C; +static const ULONG OFFSET_SBDEPOTCOUNT = 0x00000040; +static const ULONG OFFSET_EXTBBDEPOTSTART = 0x00000044; +static const ULONG OFFSET_EXTBBDEPOTCOUNT = 0x00000048; +static const ULONG OFFSET_BBDEPOTSTART = 0x0000004C; +static const ULONG OFFSET_PS_NAME = 0x00000000; +static const ULONG OFFSET_PS_NAMELENGTH = 0x00000040; +static const ULONG OFFSET_PS_PROPERTYTYPE = 0x00000042; +static const ULONG OFFSET_PS_PREVIOUSPROP = 0x00000044; +static const ULONG OFFSET_PS_NEXTPROP = 0x00000048; +static const ULONG OFFSET_PS_DIRPROP = 0x0000004C; +static const ULONG OFFSET_PS_GUID = 0x00000050; +static const ULONG OFFSET_PS_TSS1 = 0x00000064; +static const ULONG OFFSET_PS_TSD1 = 0x00000068; +static const ULONG OFFSET_PS_TSS2 = 0x0000006C; +static const ULONG OFFSET_PS_TSD2 = 0x00000070; +static const ULONG OFFSET_PS_STARTBLOCK = 0x00000074; +static const ULONG OFFSET_PS_SIZE = 0x00000078; +static const WORD DEF_BIG_BLOCK_SIZE_BITS = 0x0009; +static const WORD DEF_SMALL_BLOCK_SIZE_BITS = 0x0006; +static const WORD DEF_BIG_BLOCK_SIZE = 0x0200; +static const WORD DEF_SMALL_BLOCK_SIZE = 0x0040; +static const ULONG BLOCK_EXTBBDEPOT = 0xFFFFFFFC; +static const ULONG BLOCK_SPECIAL = 0xFFFFFFFD; +static const ULONG BLOCK_END_OF_CHAIN = 0xFFFFFFFE; +static const ULONG BLOCK_UNUSED = 0xFFFFFFFF; +static const ULONG PROPERTY_NULL = 0xFFFFFFFF; + +#define PROPERTY_NAME_MAX_LEN 0x20 +#define PROPERTY_NAME_BUFFER_LEN 0x40 + +#define PROPSET_BLOCK_SIZE 0x00000080 + +/* + * Property type of relation + */ +#define PROPERTY_RELATION_PREVIOUS 0 +#define PROPERTY_RELATION_NEXT 1 +#define PROPERTY_RELATION_DIR 2 + +/* + * Property type constants + */ +#define PROPTYPE_STORAGE 0x01 +#define PROPTYPE_STREAM 0x02 +#define PROPTYPE_ROOT 0x05 + +/* + * These defines assume a hardcoded blocksize. The code will assert + * if the blocksize is different. Some changes will have to be done if it + * becomes the case. + */ +#define BIG_BLOCK_SIZE 0x200 +#define COUNT_BBDEPOTINHEADER 109 +#define LIMIT_TO_USE_SMALL_BLOCK 0x1000 +#define NUM_BLOCKS_PER_DEPOT_BLOCK 128 + +#define STGM_ACCESS_MODE(stgm) ((stgm)&0x0000f) +#define STGM_SHARE_MODE(stgm) ((stgm)&0x000f0) +#define STGM_CREATE_MODE(stgm) ((stgm)&0x0f000) + +#define STGM_KNOWN_FLAGS (0xf0ff | \ + STGM_TRANSACTED | STGM_CONVERT | STGM_PRIORITY | STGM_NOSCRATCH | \ + STGM_NOSNAPSHOT | STGM_DIRECT_SWMR | STGM_DELETEONRELEASE | STGM_SIMPLE) + +/* + * These are signatures to detect the type of Document file. + */ +static const BYTE STORAGE_magic[8] ={0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1}; +static const BYTE STORAGE_oldmagic[8] ={0xd0,0xcf,0x11,0xe0,0x0e,0x11,0xfc,0x0d}; + +/* + * Forward declarations of all the structures used by the storage + * module. + */ +typedef struct StorageBaseImpl StorageBaseImpl; +typedef struct StorageImpl StorageImpl; +typedef struct StorageInternalImpl StorageInternalImpl; +typedef struct BlockChainStream BlockChainStream; +typedef struct SmallBlockChainStream SmallBlockChainStream; +typedef struct IEnumSTATSTGImpl IEnumSTATSTGImpl; +typedef struct StgProperty StgProperty; +typedef struct StgStreamImpl StgStreamImpl; + +/* + * This utility structure is used to read/write the information in a storage + * property. + */ +struct StgProperty +{ + WCHAR name[PROPERTY_NAME_MAX_LEN]; + WORD sizeOfNameString; + BYTE propertyType; + ULONG previousProperty; + ULONG nextProperty; + ULONG dirProperty; + GUID propertyUniqueID; + ULONG timeStampS1; + ULONG timeStampD1; + ULONG timeStampS2; + ULONG timeStampD2; + ULONG startingBlock; + ULARGE_INTEGER size; +}; + +/************************************************************************* + * Big Block File support + * + * The big block file is an abstraction of a flat file separated in + * same sized blocks. The implementation for the methods described in + * this section appear in stg_bigblockfile.c + */ + +/* + * Declaration of the data structures + */ +typedef struct BigBlockFile BigBlockFile,*LPBIGBLOCKFILE; +typedef struct MappedPage MappedPage,*LPMAPPEDPAGE; + +struct BigBlockFile +{ + BOOL fileBased; + ULARGE_INTEGER filesize; + ULONG blocksize; + HANDLE hfile; + HANDLE hfilemap; + DWORD flProtect; + MappedPage *maplist; + MappedPage *victimhead, *victimtail; + ULONG num_victim_pages; + ILockBytes *pLkbyt; + HGLOBAL hbytearray; + LPVOID pbytearray; +}; + +/* + * Declaration of the functions used to manipulate the BigBlockFile + * data structure. + */ +BigBlockFile* BIGBLOCKFILE_Construct(HANDLE hFile, + ILockBytes* pLkByt, + DWORD openFlags, + ULONG blocksize, + BOOL fileBased); +void BIGBLOCKFILE_Destructor(LPBIGBLOCKFILE This); +void* BIGBLOCKFILE_GetBigBlock(LPBIGBLOCKFILE This, ULONG index); +void* BIGBLOCKFILE_GetROBigBlock(LPBIGBLOCKFILE This, ULONG index); +void BIGBLOCKFILE_ReleaseBigBlock(LPBIGBLOCKFILE This, void *pBlock); +void BIGBLOCKFILE_SetSize(LPBIGBLOCKFILE This, ULARGE_INTEGER newSize); +ULARGE_INTEGER BIGBLOCKFILE_GetSize(LPBIGBLOCKFILE This); + +/************************************************************************* + * Ole Convert support + */ + +void OLECONVERT_CreateOleStream(LPSTORAGE pStorage); +HRESULT OLECONVERT_CreateCompObjStream(LPSTORAGE pStorage, LPCSTR strOleTypeName); + +/**************************************************************************** + * Storage32BaseImpl definitions. + * + * This structure defines the base information contained in all implementations + * of IStorage32 contained in this file storage implementation. + * + * In OOP terms, this is the base class for all the IStorage32 implementations + * contained in this file. + */ +struct StorageBaseImpl +{ + IStorageVtbl *lpVtbl; /* Needs to be the first item in the struct + * since we want to cast this in a Storage32 pointer */ + + IPropertySetStorageVtbl *pssVtbl; /* interface for adding a properties stream */ + + /* + * Reference count of this object + */ + ULONG ref; + + /* + * Ancestor storage (top level) + */ + StorageImpl* ancestorStorage; + + /* + * Index of the property for the root of + * this storage + */ + ULONG rootPropertySetIndex; + + /* + * virtual Destructor method. + */ + void (*v_destructor)(StorageBaseImpl*); + + /* + * flags that this storage was opened or created with + */ + DWORD openFlags; +}; + + +/**************************************************************************** + * Storage32Impl definitions. + * + * This implementation of the IStorage32 interface represents a root + * storage. Basically, a document file. + */ +struct StorageImpl +{ + struct StorageBaseImpl base; + + /* + * The following data members are specific to the Storage32Impl + * class + */ + HANDLE hFile; /* Physical support for the Docfile */ + LPOLESTR pwcsName; /* Full path of the document file */ + + /* FIXME: should this be in Storage32BaseImpl ? */ + WCHAR filename[PROPERTY_NAME_BUFFER_LEN]; + + /* + * File header + */ + WORD bigBlockSizeBits; + WORD smallBlockSizeBits; + ULONG bigBlockSize; + ULONG smallBlockSize; + ULONG bigBlockDepotCount; + ULONG rootStartBlock; + ULONG smallBlockDepotStart; + ULONG extBigBlockDepotStart; + ULONG extBigBlockDepotCount; + ULONG bigBlockDepotStart[COUNT_BBDEPOTINHEADER]; + + ULONG blockDepotCached[NUM_BLOCKS_PER_DEPOT_BLOCK]; + ULONG indexBlockDepotCached; + ULONG prevFreeBlock; + + /* + * Abstraction of the big block chains for the chains of the header. + */ + BlockChainStream* rootBlockChain; + BlockChainStream* smallBlockDepotChain; + BlockChainStream* smallBlockRootChain; + + /* + * Pointer to the big block file abstraction + */ + BigBlockFile* bigBlockFile; +}; + +void StorageImpl_Destroy( + StorageBaseImpl* This); + +HRESULT StorageImpl_Construct( + StorageImpl* This, + HANDLE hFile, + LPCOLESTR pwcsName, + ILockBytes* pLkbyt, + DWORD openFlags, + BOOL fileBased, + BOOL fileCreate); + +BOOL StorageImpl_ReadBigBlock( + StorageImpl* This, + ULONG blockIndex, + void* buffer); + +BOOL StorageImpl_WriteBigBlock( + StorageImpl* This, + ULONG blockIndex, + void* buffer); + +void* StorageImpl_GetROBigBlock( + StorageImpl* This, + ULONG blockIndex); + +void* StorageImpl_GetBigBlock( + StorageImpl* This, + ULONG blockIndex); + +void StorageImpl_ReleaseBigBlock( + StorageImpl* This, + void* pBigBlock); + +ULONG StorageImpl_GetNextFreeBigBlock( + StorageImpl* This); + +void StorageImpl_FreeBigBlock( + StorageImpl* This, + ULONG blockIndex); + +HRESULT StorageImpl_GetNextBlockInChain( + StorageImpl* This, + ULONG blockIndex, + ULONG* nextBlockIndex); + +void StorageImpl_SetNextBlockInChain( + StorageImpl* This, + ULONG blockIndex, + ULONG nextBlock); + +HRESULT StorageImpl_LoadFileHeader( + StorageImpl* This); + +void StorageImpl_SaveFileHeader( + StorageImpl* This); + +BOOL StorageImpl_ReadProperty( + StorageImpl* This, + ULONG index, + StgProperty* buffer); + +BOOL StorageImpl_WriteProperty( + StorageImpl* This, + ULONG index, + StgProperty* buffer); + +BlockChainStream* Storage32Impl_SmallBlocksToBigBlocks( + StorageImpl* This, + SmallBlockChainStream** ppsbChain); + +ULONG Storage32Impl_GetNextExtendedBlock(StorageImpl* This, + ULONG blockIndex); + +void Storage32Impl_AddBlockDepot(StorageImpl* This, + ULONG blockIndex); + +ULONG Storage32Impl_AddExtBlockDepot(StorageImpl* This); + +ULONG Storage32Impl_GetExtDepotBlock(StorageImpl* This, + ULONG depotIndex); + +void Storage32Impl_SetExtDepotBlock(StorageImpl* This, + ULONG depotIndex, + ULONG blockIndex); +/**************************************************************************** + * Storage32InternalImpl definitions. + * + * Definition of the implementation structure for the IStorage32 interface. + * This one implements the IStorage32 interface for storage that are + * inside another storage. + */ +struct StorageInternalImpl +{ + struct StorageBaseImpl base; + + /* + * There is no specific data for this class. + */ +}; + +/* + * Method definitions for the Storage32InternalImpl class. + */ +StorageInternalImpl* StorageInternalImpl_Construct( + StorageImpl* ancestorStorage, + DWORD openFlags, + ULONG rootTropertyIndex); + +void StorageInternalImpl_Destroy( + StorageBaseImpl* This); + +HRESULT WINAPI StorageInternalImpl_Commit( + IStorage* iface, + DWORD grfCommitFlags); /* [in] */ + +HRESULT WINAPI StorageInternalImpl_Revert( + IStorage* iface); + + +/**************************************************************************** + * IEnumSTATSTGImpl definitions. + * + * Definition of the implementation structure for the IEnumSTATSTGImpl interface. + * This class allows iterating through the content of a storage and to find + * specific items inside it. + */ +struct IEnumSTATSTGImpl +{ + IEnumSTATSTGVtbl *lpVtbl; /* Needs to be the first item in the struct + * since we want to cast this in an IEnumSTATSTG pointer */ + + ULONG ref; /* Reference count */ + StorageImpl* parentStorage; /* Reference to the parent storage */ + ULONG firstPropertyNode; /* Index of the root of the storage to enumerate */ + + /* + * The current implementation of the IEnumSTATSTGImpl class uses a stack + * to walk the property sets to get the content of a storage. This stack + * is implemented by the following 3 data members + */ + ULONG stackSize; + ULONG stackMaxSize; + ULONG* stackToVisit; + +#define ENUMSTATSGT_SIZE_INCREMENT 10 +}; + +IEnumSTATSTGImpl* IEnumSTATSTGImpl_Construct( + StorageImpl* This, + ULONG firstPropertyNode); + +void IEnumSTATSTGImpl_Destroy( + IEnumSTATSTGImpl* This); + +void IEnumSTATSTGImpl_PushSearchNode( + IEnumSTATSTGImpl* This, + ULONG nodeToPush); + +ULONG IEnumSTATSTGImpl_PopSearchNode( + IEnumSTATSTGImpl* This, + BOOL remove); + +ULONG IEnumSTATSTGImpl_FindProperty( + IEnumSTATSTGImpl* This, + const OLECHAR* lpszPropName, + StgProperty* buffer); + +INT IEnumSTATSTGImpl_FindParentProperty( + IEnumSTATSTGImpl *This, + ULONG childProperty, + StgProperty *currentProperty, + ULONG *propertyId); + + +/**************************************************************************** + * StgStreamImpl definitions. + * + * This class imlements the IStream32 inteface and represents a stream + * located inside a storage object. + */ +struct StgStreamImpl +{ + IStreamVtbl *lpVtbl; /* Needs to be the first item in the struct + * since we want to cast this to an IStream pointer */ + + /* + * Reference count + */ + ULONG ref; + + /* + * Storage that is the parent(owner) of the stream + */ + StorageBaseImpl* parentStorage; + + /* + * Access mode of this stream. + */ + DWORD grfMode; + + /* + * Index of the property that owns (points to) this stream. + */ + ULONG ownerProperty; + + /* + * Helper variable that contains the size of the stream + */ + ULARGE_INTEGER streamSize; + + /* + * This is the current position of the cursor in the stream + */ + ULARGE_INTEGER currentPosition; + + /* + * The information in the stream is represented by a chain of small blocks + * or a chain of large blocks. Depending on the case, one of the two + * following variabled points to that information. + */ + BlockChainStream* bigBlockChain; + SmallBlockChainStream* smallBlockChain; +}; + +/* + * Method definition for the StgStreamImpl class. + */ +StgStreamImpl* StgStreamImpl_Construct( + StorageBaseImpl* parentStorage, + DWORD grfMode, + ULONG ownerProperty); + + +/****************************************************************************** + * Endian conversion macros + */ +#ifdef WORDS_BIGENDIAN + +#define htole32(x) RtlUlongByteSwap(x) +#define htole16(x) RtlUshortByteSwap(x) +#define le32toh(x) RtlUlongByteSwap(x) +#define le16toh(x) RtlUshortByteSwap(x) + +#else + +#define htole32(x) (x) +#define htole16(x) (x) +#define le32toh(x) (x) +#define le16toh(x) (x) + +#endif + +/****************************************************************************** + * The StorageUtl_ functions are miscellaneous utility functions. Most of which + * are abstractions used to read values from file buffers without having to + * worry about bit order + */ +void StorageUtl_ReadWord(const BYTE* buffer, ULONG offset, WORD* value); +void StorageUtl_WriteWord(BYTE* buffer, ULONG offset, WORD value); +void StorageUtl_ReadDWord(const BYTE* buffer, ULONG offset, DWORD* value); +void StorageUtl_WriteDWord(BYTE* buffer, ULONG offset, DWORD value); +void StorageUtl_ReadULargeInteger(const BYTE* buffer, ULONG offset, + ULARGE_INTEGER* value); +void StorageUtl_WriteULargeInteger(BYTE* buffer, ULONG offset, + const ULARGE_INTEGER *value); +void StorageUtl_ReadGUID(const BYTE* buffer, ULONG offset, GUID* value); +void StorageUtl_WriteGUID(BYTE* buffer, ULONG offset, const GUID* value); +void StorageUtl_CopyPropertyToSTATSTG(STATSTG* destination, + StgProperty* source, + int statFlags); + +/**************************************************************************** + * BlockChainStream definitions. + * + * The BlockChainStream class is a utility class that is used to create an + * abstraction of the big block chains in the storage file. + */ +struct BlockChainStream +{ + StorageImpl* parentStorage; + ULONG* headOfStreamPlaceHolder; + ULONG ownerPropertyIndex; + ULONG lastBlockNoInSequence; + ULONG lastBlockNoInSequenceIndex; + ULONG tailIndex; + ULONG numBlocks; +}; + +/* + * Methods for the BlockChainStream class. + */ +BlockChainStream* BlockChainStream_Construct( + StorageImpl* parentStorage, + ULONG* headOfStreamPlaceHolder, + ULONG propertyIndex); + +void BlockChainStream_Destroy( + BlockChainStream* This); + +ULONG BlockChainStream_GetHeadOfChain( + BlockChainStream* This); + +BOOL BlockChainStream_ReadAt( + BlockChainStream* This, + ULARGE_INTEGER offset, + ULONG size, + void* buffer, + ULONG* bytesRead); + +BOOL BlockChainStream_WriteAt( + BlockChainStream* This, + ULARGE_INTEGER offset, + ULONG size, + const void* buffer, + ULONG* bytesWritten); + +BOOL BlockChainStream_SetSize( + BlockChainStream* This, + ULARGE_INTEGER newSize); + +ULARGE_INTEGER BlockChainStream_GetSize( + BlockChainStream* This); + +ULONG BlockChainStream_GetCount( + BlockChainStream* This); + +/**************************************************************************** + * SmallBlockChainStream definitions. + * + * The SmallBlockChainStream class is a utility class that is used to create an + * abstraction of the small block chains in the storage file. + */ +struct SmallBlockChainStream +{ + StorageImpl* parentStorage; + ULONG ownerPropertyIndex; +}; + +/* + * Methods of the SmallBlockChainStream class. + */ +SmallBlockChainStream* SmallBlockChainStream_Construct( + StorageImpl* parentStorage, + ULONG propertyIndex); + +void SmallBlockChainStream_Destroy( + SmallBlockChainStream* This); + +ULONG SmallBlockChainStream_GetHeadOfChain( + SmallBlockChainStream* This); + +HRESULT SmallBlockChainStream_GetNextBlockInChain( + SmallBlockChainStream* This, + ULONG blockIndex, + ULONG* nextBlockIndex); + +void SmallBlockChainStream_SetNextBlockInChain( + SmallBlockChainStream* This, + ULONG blockIndex, + ULONG nextBlock); + +void SmallBlockChainStream_FreeBlock( + SmallBlockChainStream* This, + ULONG blockIndex); + +ULONG SmallBlockChainStream_GetNextFreeBlock( + SmallBlockChainStream* This); + +BOOL SmallBlockChainStream_ReadAt( + SmallBlockChainStream* This, + ULARGE_INTEGER offset, + ULONG size, + void* buffer, + ULONG* bytesRead); + +BOOL SmallBlockChainStream_WriteAt( + SmallBlockChainStream* This, + ULARGE_INTEGER offset, + ULONG size, + const void* buffer, + ULONG* bytesWritten); + +BOOL SmallBlockChainStream_SetSize( + SmallBlockChainStream* This, + ULARGE_INTEGER newSize); + +ULARGE_INTEGER SmallBlockChainStream_GetSize( + SmallBlockChainStream* This); + +ULONG SmallBlockChainStream_GetCount( + SmallBlockChainStream* This); + + +#endif /* __STORAGE32_H__ */ diff --git a/reactos/lib/ole32/stubmanager.c b/reactos/lib/ole32/stubmanager.c index 156ed847ca4..998d1ed47ef 100644 --- a/reactos/lib/ole32/stubmanager.c +++ b/reactos/lib/ole32/stubmanager.c @@ -1,742 +1,742 @@ -/* - * A stub manager is an object that controls interface stubs. It is - * identified by an OID (object identifier) and acts as the network - * identity of the object. There can be many stub managers in a - * process or apartment. - * - * Copyright 2002 Marcus Meissner - * Copyright 2004 Mike Hearn for CodeWeavers - * Copyright 2004 Robert Shearman (for CodeWeavers) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include <assert.h> -#include <stdarg.h> -#include <limits.h> - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "objbase.h" -#include "ole2.h" -#include "ole2ver.h" -#include "rpc.h" -#include "wine/debug.h" -#include "compobj_private.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -static void stub_manager_delete_ifstub(struct stub_manager *m, struct ifstub *ifstub); -static struct ifstub *stub_manager_ipid_to_ifstub(struct stub_manager *m, const IPID *ipid); - -/* creates a new stub manager and adds it into the apartment. caller must - * release stub manager when it is no longer required. the apartment and - * external refs together take one implicit ref */ -struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object, MSHLFLAGS mshlflags) -{ - struct stub_manager *sm; - - assert( apt ); - - sm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct stub_manager)); - if (!sm) return NULL; - - list_init(&sm->ifstubs); - - InitializeCriticalSection(&sm->lock); - DEBUG_SET_CRITSEC_NAME(&sm->lock, "stub_manager"); - - IUnknown_AddRef(object); - sm->object = object; - sm->apt = apt; - - /* start off with 2 references because the stub is in the apartment - * and the caller will also hold a reference */ - sm->refs = 2; - - /* yes, that's right, this starts at zero. that's zero EXTERNAL - * refs, ie nobody has unmarshalled anything yet. we can't have - * negative refs because the stub manager cannot be explicitly - * killed, it has to die by somebody unmarshalling then releasing - * the marshalled ifptr. - */ - sm->extrefs = 0; - - if (mshlflags & MSHLFLAGS_TABLESTRONG) - sm->state = STUBSTATE_TABLE_STRONG; - else if (mshlflags & MSHLFLAGS_TABLEWEAK) - sm->state = STUBSTATE_TABLE_WEAK_UNMARSHALED; - else - sm->state = STUBSTATE_NORMAL_MARSHALED; - - EnterCriticalSection(&apt->cs); - sm->oid = apt->oidc++; - list_add_head(&apt->stubmgrs, &sm->entry); - LeaveCriticalSection(&apt->cs); - - TRACE("Created new stub manager (oid=%s) at %p for object with IUnknown %p\n", wine_dbgstr_longlong(sm->oid), sm, object); - - return sm; -} - -/* m->apt->cs must be held on entry to this function */ -static void stub_manager_delete(struct stub_manager *m) -{ - struct list *cursor; - - TRACE("destroying %p (oid=%s)\n", m, wine_dbgstr_longlong(m->oid)); - - list_remove(&m->entry); - - /* release every ifstub */ - while ((cursor = list_head(&m->ifstubs))) - { - struct ifstub *ifstub = LIST_ENTRY(cursor, struct ifstub, entry); - stub_manager_delete_ifstub(m, ifstub); - } - - IUnknown_Release(m->object); - - DEBUG_CLEAR_CRITSEC_NAME(&m->lock); - DeleteCriticalSection(&m->lock); - - HeapFree(GetProcessHeap(), 0, m); -} - -/* gets the stub manager associated with an object - caller must have - * a reference to the apartment while a reference to the stub manager is held. - * it must also call release on the stub manager when it is no longer needed */ -struct stub_manager *get_stub_manager_from_object(APARTMENT *apt, void *object) -{ - struct stub_manager *result = NULL; - struct list *cursor; - - EnterCriticalSection(&apt->cs); - LIST_FOR_EACH( cursor, &apt->stubmgrs ) - { - struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry ); - - if (m->object == object) - { - result = m; - stub_manager_int_addref(result); - break; - } - } - LeaveCriticalSection(&apt->cs); - - if (result) - TRACE("found %p for object %p\n", result, object); - else - TRACE("not found for object %p\n", object); - - return result; -} - -/* removes the apartment reference to an object, destroying it when no other - * threads have a reference to it */ -void apartment_disconnectobject(struct apartment *apt, void *object) -{ - int found = FALSE; - struct stub_manager *stubmgr; - - EnterCriticalSection(&apt->cs); - LIST_FOR_EACH_ENTRY( stubmgr, &apt->stubmgrs, struct stub_manager, entry ) - { - if (stubmgr->object == object) - { - found = TRUE; - stub_manager_int_release(stubmgr); - break; - } - } - LeaveCriticalSection(&apt->cs); - - if (found) - TRACE("disconnect object %p\n", object); - else - WARN("couldn't find object %p\n", object); -} - -/* gets the stub manager associated with an object id - caller must have - * a reference to the apartment while a reference to the stub manager is held. - * it must also call release on the stub manager when it is no longer needed */ -struct stub_manager *get_stub_manager(APARTMENT *apt, OID oid) -{ - struct stub_manager *result = NULL; - struct list *cursor; - - EnterCriticalSection(&apt->cs); - LIST_FOR_EACH( cursor, &apt->stubmgrs ) - { - struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry ); - - if (m->oid == oid) - { - result = m; - stub_manager_int_addref(result); - break; - } - } - LeaveCriticalSection(&apt->cs); - - if (result) - TRACE("found %p for oid %s\n", result, wine_dbgstr_longlong(oid)); - else - TRACE("not found for oid %s\n", wine_dbgstr_longlong(oid)); - - return result; -} - -/* increments the internal refcount */ -ULONG stub_manager_int_addref(struct stub_manager *This) -{ - ULONG refs; - - EnterCriticalSection(&This->apt->cs); - refs = ++This->refs; - LeaveCriticalSection(&This->apt->cs); - - TRACE("before %ld\n", refs - 1); - - return refs; -} - -/* decrements the internal refcount */ -ULONG stub_manager_int_release(struct stub_manager *This) -{ - ULONG refs; - APARTMENT *apt = This->apt; - - EnterCriticalSection(&apt->cs); - refs = --This->refs; - - TRACE("after %ld\n", refs); - - if (!refs) - stub_manager_delete(This); - LeaveCriticalSection(&apt->cs); - - return refs; -} - -/* add some external references (ie from a client that unmarshaled an ifptr) */ -ULONG stub_manager_ext_addref(struct stub_manager *m, ULONG refs) -{ - ULONG rc; - - EnterCriticalSection(&m->lock); - - /* make sure we don't overflow extrefs */ - refs = min(refs, (ULONG_MAX-1 - m->extrefs)); - rc = (m->extrefs += refs); - - LeaveCriticalSection(&m->lock); - - TRACE("added %lu refs to %p (oid %s), rc is now %lu\n", refs, m, wine_dbgstr_longlong(m->oid), rc); - - return rc; -} - -/* remove some external references */ -ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs) -{ - ULONG rc; - - EnterCriticalSection(&m->lock); - - /* make sure we don't underflow extrefs */ - refs = min(refs, m->extrefs); - rc = (m->extrefs -= refs); - - LeaveCriticalSection(&m->lock); - - TRACE("removed %lu refs from %p (oid %s), rc is now %lu\n", refs, m, wine_dbgstr_longlong(m->oid), rc); - - if (rc == 0) - stub_manager_int_release(m); - - return rc; -} - -static struct ifstub *stub_manager_ipid_to_ifstub(struct stub_manager *m, const IPID *ipid) -{ - struct list *cursor; - struct ifstub *result = NULL; - - EnterCriticalSection(&m->lock); - LIST_FOR_EACH( cursor, &m->ifstubs ) - { - struct ifstub *ifstub = LIST_ENTRY( cursor, struct ifstub, entry ); - - if (IsEqualGUID(ipid, &ifstub->ipid)) - { - result = ifstub; - break; - } - } - LeaveCriticalSection(&m->lock); - - return result; -} - -/* gets the stub manager associated with an ipid - caller must have - * a reference to the apartment while a reference to the stub manager is held. - * it must also call release on the stub manager when it is no longer needed */ -static struct stub_manager *get_stub_manager_from_ipid(APARTMENT *apt, const IPID *ipid) -{ - struct stub_manager *result = NULL; - struct list *cursor; - - EnterCriticalSection(&apt->cs); - LIST_FOR_EACH( cursor, &apt->stubmgrs ) - { - struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry ); - - if (stub_manager_ipid_to_ifstub(m, ipid)) - { - result = m; - stub_manager_int_addref(result); - break; - } - } - LeaveCriticalSection(&apt->cs); - - if (result) - TRACE("found %p for ipid %s\n", result, debugstr_guid(ipid)); - else - ERR("not found for ipid %s\n", debugstr_guid(ipid)); - - return result; -} - -HRESULT ipid_to_stub_manager(const IPID *ipid, APARTMENT **stub_apt, struct stub_manager **stubmgr_ret) -{ - /* FIXME: hack for IRemUnknown */ - if (ipid->Data2 == 0xffff) - *stub_apt = apartment_findfromoxid(*(OXID *)ipid->Data4, TRUE); - else - *stub_apt = apartment_findfromtid(ipid->Data2); - if (!*stub_apt) - { - ERR("Couldn't find apartment corresponding to TID 0x%04x\n", ipid->Data2); - return RPC_E_INVALID_OBJECT; - } - *stubmgr_ret = get_stub_manager_from_ipid(*stub_apt, ipid); - if (!*stubmgr_ret) - { - apartment_release(*stub_apt); - *stub_apt = NULL; - return RPC_E_INVALID_OBJECT; - } - return S_OK; -} - -/* gets the apartment and IRpcStubBuffer from an object. the caller must - * release the references to both objects */ -IRpcStubBuffer *ipid_to_apt_and_stubbuffer(const IPID *ipid, APARTMENT **stub_apt) -{ - IRpcStubBuffer *ret = NULL; - struct stub_manager *stubmgr; - struct ifstub *ifstub; - HRESULT hr; - - *stub_apt = NULL; - - hr = ipid_to_stub_manager(ipid, stub_apt, &stubmgr); - if (hr != S_OK) return NULL; - - ifstub = stub_manager_ipid_to_ifstub(stubmgr, ipid); - if (ifstub) - ret = ifstub->stubbuffer; - - if (ret) IRpcStubBuffer_AddRef(ret); - - stub_manager_int_release(stubmgr); - - return ret; -} - -/* generates an ipid in the following format (similar to native version): - * Data1 = apartment-local ipid counter - * Data2 = apartment creator thread ID - * Data3 = process ID - * Data4 = random value - */ -static inline HRESULT generate_ipid(struct stub_manager *m, IPID *ipid) -{ - HRESULT hr; - hr = UuidCreate(ipid); - if (FAILED(hr)) - { - ERR("couldn't create IPID for stub manager %p\n", m); - UuidCreateNil(ipid); - return hr; - } - - ipid->Data1 = InterlockedIncrement(&m->apt->ipidc); - ipid->Data2 = (USHORT)m->apt->tid; - ipid->Data3 = (USHORT)GetCurrentProcessId(); - return S_OK; -} - -/* registers a new interface stub COM object with the stub manager and returns registration record */ -struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *sb, IUnknown *iptr, REFIID iid) -{ - struct ifstub *stub; - - TRACE("oid=%s, stubbuffer=%p, iptr=%p, iid=%s\n", - wine_dbgstr_longlong(m->oid), sb, iptr, debugstr_guid(iid)); - - stub = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct ifstub)); - if (!stub) return NULL; - - stub->stubbuffer = sb; - IUnknown_AddRef(sb); - - /* no need to ref this, same object as sb */ - stub->iface = iptr; - - stub->iid = *iid; - - /* FIXME: hack for IRemUnknown because we don't notify SCM of our IPID - * yet, so we need to use a well-known one */ - if (IsEqualIID(iid, &IID_IRemUnknown)) - { - stub->ipid.Data1 = 0xffffffff; - stub->ipid.Data2 = 0xffff; - stub->ipid.Data3 = 0xffff; - assert(sizeof(stub->ipid.Data4) == sizeof(m->apt->oxid)); - memcpy(&stub->ipid.Data4, &m->apt->oxid, sizeof(OXID)); - } - else - generate_ipid(m, &stub->ipid); - - EnterCriticalSection(&m->lock); - list_add_head(&m->ifstubs, &stub->entry); - LeaveCriticalSection(&m->lock); - - TRACE("ifstub %p created with ipid %s\n", stub, debugstr_guid(&stub->ipid)); - - return stub; -} - -static void stub_manager_delete_ifstub(struct stub_manager *m, struct ifstub *ifstub) -{ - TRACE("m=%p, m->oid=%s, ipid=%s\n", m, wine_dbgstr_longlong(m->oid), debugstr_guid(&ifstub->ipid)); - - list_remove(&ifstub->entry); - - RPC_UnregisterInterface(&ifstub->iid); - - IUnknown_Release(ifstub->stubbuffer); - IUnknown_Release(ifstub->iface); - - HeapFree(GetProcessHeap(), 0, ifstub); -} - -/* returns TRUE if it is possible to unmarshal, FALSE otherwise. */ -BOOL stub_manager_notify_unmarshal(struct stub_manager *m) -{ - BOOL ret; - - EnterCriticalSection(&m->lock); - - switch (m->state) - { - case STUBSTATE_TABLE_STRONG: - case STUBSTATE_TABLE_WEAK_MARSHALED: - /* no transition */ - ret = TRUE; - break; - case STUBSTATE_TABLE_WEAK_UNMARSHALED: - m->state = STUBSTATE_TABLE_WEAK_MARSHALED; - ret = TRUE; - break; - case STUBSTATE_NORMAL_MARSHALED: - m->state = STUBSTATE_NORMAL_UNMARSHALED; - ret = TRUE; - break; - default: - WARN("object OID %s already unmarshaled\n", - wine_dbgstr_longlong(m->oid)); - ret = FALSE; - break; - } - - LeaveCriticalSection(&m->lock); - - return ret; -} - -void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs) -{ - EnterCriticalSection(&m->lock); - - switch (m->state) - { - case STUBSTATE_NORMAL_MARSHALED: - case STUBSTATE_NORMAL_UNMARSHALED: /* FIXME: check this */ - /* nothing to change */ - break; - case STUBSTATE_TABLE_WEAK_UNMARSHALED: - case STUBSTATE_TABLE_STRONG: - refs = 1; - break; - case STUBSTATE_TABLE_WEAK_MARSHALED: - refs = 0; /* like native */ - break; - } - - stub_manager_ext_release(m, refs); - - LeaveCriticalSection(&m->lock); -} - -/* is an ifstub table marshaled? */ -BOOL stub_manager_is_table_marshaled(struct stub_manager *m) -{ - BOOL ret; - - EnterCriticalSection(&m->lock); - ret = ((m->state == STUBSTATE_TABLE_STRONG) || - (m->state == STUBSTATE_TABLE_WEAK_MARSHALED) || - (m->state == STUBSTATE_TABLE_WEAK_UNMARSHALED)); - LeaveCriticalSection(&m->lock); - - return ret; -} - - -/***************************************************************************** - * - * IRemUnknown implementation - * - * - * Note: this object is not related to the lifetime of a stub_manager, but it - * interacts with stub managers. - */ - -const IID IID_IRemUnknown = { 0x00000131, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} }; - -typedef struct rem_unknown -{ - const IRemUnknownVtbl *lpVtbl; - ULONG refs; -} RemUnknown; - -static const IRemUnknownVtbl RemUnknown_Vtbl; - - -/* construct an IRemUnknown object with one outstanding reference */ -static HRESULT RemUnknown_Construct(IRemUnknown **ppRemUnknown) -{ - RemUnknown *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); - - if (!This) return E_OUTOFMEMORY; - - This->lpVtbl = &RemUnknown_Vtbl; - This->refs = 1; - - *ppRemUnknown = (IRemUnknown *)This; - return S_OK; -} - -static HRESULT WINAPI RemUnknown_QueryInterface(IRemUnknown *iface, REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IRemUnknown)) - { - *ppv = (LPVOID)iface; - IRemUnknown_AddRef(iface); - return S_OK; - } - - FIXME("No interface for iid %s\n", debugstr_guid(riid)); - - *ppv = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI RemUnknown_AddRef(IRemUnknown *iface) -{ - ULONG refs; - RemUnknown *This = (RemUnknown *)iface; - - refs = InterlockedIncrement(&This->refs); - - TRACE("%p before: %ld\n", iface, refs-1); - return refs; -} - -static ULONG WINAPI RemUnknown_Release(IRemUnknown *iface) -{ - ULONG refs; - RemUnknown *This = (RemUnknown *)iface; - - refs = InterlockedDecrement(&This->refs); - if (!refs) - HeapFree(GetProcessHeap(), 0, This); - - TRACE("%p after: %ld\n", iface, refs); - return refs; -} - -static HRESULT WINAPI RemUnknown_RemQueryInterface(IRemUnknown *iface, - REFIPID ripid, ULONG cRefs, USHORT cIids, IID *iids /* [size_is(cIids)] */, - REMQIRESULT **ppQIResults /* [size_is(,cIids)] */) -{ - HRESULT hr; - USHORT i; - USHORT successful_qis = 0; - APARTMENT *apt; - struct stub_manager *stubmgr; - - TRACE("(%p)->(%s, %ld, %d, %p, %p)\n", iface, debugstr_guid(ripid), cRefs, cIids, iids, ppQIResults); - - hr = ipid_to_stub_manager(ripid, &apt, &stubmgr); - if (hr != S_OK) return hr; - - *ppQIResults = CoTaskMemAlloc(sizeof(REMQIRESULT) * cIids); - - for (i = 0; i < cIids; i++) - { - HRESULT hrobj = marshal_object(apt, &(*ppQIResults)[i].std, &iids[i], - stubmgr->object, MSHLFLAGS_NORMAL); - if (hrobj == S_OK) - successful_qis++; - (*ppQIResults)[i].hResult = hrobj; - } - - stub_manager_int_release(stubmgr); - apartment_release(apt); - - if (successful_qis == cIids) - return S_OK; /* we got all requested interfaces */ - else if (successful_qis == 0) - return E_NOINTERFACE; /* we didn't get any interfaces */ - else - return S_FALSE; /* we got some interfaces */ -} - -static HRESULT WINAPI RemUnknown_RemAddRef(IRemUnknown *iface, - USHORT cInterfaceRefs, - REMINTERFACEREF* InterfaceRefs /* [size_is(cInterfaceRefs)] */, - HRESULT *pResults /* [size_is(cInterfaceRefs)] */) -{ - HRESULT hr = S_OK; - USHORT i; - - TRACE("(%p)->(%d, %p, %p)\n", iface, cInterfaceRefs, InterfaceRefs, pResults); - - for (i = 0; i < cInterfaceRefs; i++) - { - APARTMENT *apt; - struct stub_manager *stubmgr; - - pResults[i] = ipid_to_stub_manager(&InterfaceRefs[i].ipid, &apt, &stubmgr); - if (pResults[i] != S_OK) - { - hr = S_FALSE; - continue; - } - - stub_manager_ext_addref(stubmgr, InterfaceRefs[i].cPublicRefs); - if (InterfaceRefs[i].cPrivateRefs) - FIXME("Adding %ld refs securely not implemented\n", InterfaceRefs[i].cPrivateRefs); - - stub_manager_int_release(stubmgr); - apartment_release(apt); - } - - return hr; -} - -static HRESULT WINAPI RemUnknown_RemRelease(IRemUnknown *iface, - USHORT cInterfaceRefs, - REMINTERFACEREF* InterfaceRefs /* [size_is(cInterfaceRefs)] */) -{ - HRESULT hr = S_OK; - USHORT i; - - TRACE("(%p)->(%d, %p)\n", iface, cInterfaceRefs, InterfaceRefs); - - for (i = 0; i < cInterfaceRefs; i++) - { - APARTMENT *apt; - struct stub_manager *stubmgr; - - hr = ipid_to_stub_manager(&InterfaceRefs[i].ipid, &apt, &stubmgr); - if (hr != S_OK) - { - hr = E_INVALIDARG; - /* FIXME: we should undo any changes already made in this function */ - break; - } - - stub_manager_ext_release(stubmgr, InterfaceRefs[i].cPublicRefs); - if (InterfaceRefs[i].cPrivateRefs) - FIXME("Releasing %ld refs securely not implemented\n", InterfaceRefs[i].cPrivateRefs); - - stub_manager_int_release(stubmgr); - apartment_release(apt); - } - - return hr; -} - -static const IRemUnknownVtbl RemUnknown_Vtbl = -{ - RemUnknown_QueryInterface, - RemUnknown_AddRef, - RemUnknown_Release, - RemUnknown_RemQueryInterface, - RemUnknown_RemAddRef, - RemUnknown_RemRelease -}; - -/* starts the IRemUnknown listener for the current apartment */ -HRESULT start_apartment_remote_unknown() -{ - IRemUnknown *pRemUnknown; - HRESULT hr = S_OK; - APARTMENT *apt = COM_CurrentApt(); - - EnterCriticalSection(&apt->cs); - if (!apt->remunk_exported) - { - /* create the IRemUnknown object */ - hr = RemUnknown_Construct(&pRemUnknown); - if (hr == S_OK) - { - STDOBJREF stdobjref; /* dummy - not used */ - /* register it with the stub manager */ - hr = marshal_object(apt, &stdobjref, &IID_IRemUnknown, (IUnknown *)pRemUnknown, MSHLFLAGS_NORMAL); - /* release our reference to the object as the stub manager will manage the life cycle for us */ - IRemUnknown_Release(pRemUnknown); - if (hr == S_OK) - apt->remunk_exported = TRUE; - } - } - LeaveCriticalSection(&apt->cs); - return hr; -} +/* + * A stub manager is an object that controls interface stubs. It is + * identified by an OID (object identifier) and acts as the network + * identity of the object. There can be many stub managers in a + * process or apartment. + * + * Copyright 2002 Marcus Meissner + * Copyright 2004 Mike Hearn for CodeWeavers + * Copyright 2004 Robert Shearman (for CodeWeavers) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include <assert.h> +#include <stdarg.h> +#include <limits.h> + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "objbase.h" +#include "ole2.h" +#include "ole2ver.h" +#include "rpc.h" +#include "wine/debug.h" +#include "compobj_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +static void stub_manager_delete_ifstub(struct stub_manager *m, struct ifstub *ifstub); +static struct ifstub *stub_manager_ipid_to_ifstub(struct stub_manager *m, const IPID *ipid); + +/* creates a new stub manager and adds it into the apartment. caller must + * release stub manager when it is no longer required. the apartment and + * external refs together take one implicit ref */ +struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object, MSHLFLAGS mshlflags) +{ + struct stub_manager *sm; + + assert( apt ); + + sm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct stub_manager)); + if (!sm) return NULL; + + list_init(&sm->ifstubs); + + InitializeCriticalSection(&sm->lock); + DEBUG_SET_CRITSEC_NAME(&sm->lock, "stub_manager"); + + IUnknown_AddRef(object); + sm->object = object; + sm->apt = apt; + + /* start off with 2 references because the stub is in the apartment + * and the caller will also hold a reference */ + sm->refs = 2; + + /* yes, that's right, this starts at zero. that's zero EXTERNAL + * refs, ie nobody has unmarshalled anything yet. we can't have + * negative refs because the stub manager cannot be explicitly + * killed, it has to die by somebody unmarshalling then releasing + * the marshalled ifptr. + */ + sm->extrefs = 0; + + if (mshlflags & MSHLFLAGS_TABLESTRONG) + sm->state = STUBSTATE_TABLE_STRONG; + else if (mshlflags & MSHLFLAGS_TABLEWEAK) + sm->state = STUBSTATE_TABLE_WEAK_UNMARSHALED; + else + sm->state = STUBSTATE_NORMAL_MARSHALED; + + EnterCriticalSection(&apt->cs); + sm->oid = apt->oidc++; + list_add_head(&apt->stubmgrs, &sm->entry); + LeaveCriticalSection(&apt->cs); + + TRACE("Created new stub manager (oid=%s) at %p for object with IUnknown %p\n", wine_dbgstr_longlong(sm->oid), sm, object); + + return sm; +} + +/* m->apt->cs must be held on entry to this function */ +static void stub_manager_delete(struct stub_manager *m) +{ + struct list *cursor; + + TRACE("destroying %p (oid=%s)\n", m, wine_dbgstr_longlong(m->oid)); + + list_remove(&m->entry); + + /* release every ifstub */ + while ((cursor = list_head(&m->ifstubs))) + { + struct ifstub *ifstub = LIST_ENTRY(cursor, struct ifstub, entry); + stub_manager_delete_ifstub(m, ifstub); + } + + IUnknown_Release(m->object); + + DEBUG_CLEAR_CRITSEC_NAME(&m->lock); + DeleteCriticalSection(&m->lock); + + HeapFree(GetProcessHeap(), 0, m); +} + +/* gets the stub manager associated with an object - caller must have + * a reference to the apartment while a reference to the stub manager is held. + * it must also call release on the stub manager when it is no longer needed */ +struct stub_manager *get_stub_manager_from_object(APARTMENT *apt, void *object) +{ + struct stub_manager *result = NULL; + struct list *cursor; + + EnterCriticalSection(&apt->cs); + LIST_FOR_EACH( cursor, &apt->stubmgrs ) + { + struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry ); + + if (m->object == object) + { + result = m; + stub_manager_int_addref(result); + break; + } + } + LeaveCriticalSection(&apt->cs); + + if (result) + TRACE("found %p for object %p\n", result, object); + else + TRACE("not found for object %p\n", object); + + return result; +} + +/* removes the apartment reference to an object, destroying it when no other + * threads have a reference to it */ +void apartment_disconnectobject(struct apartment *apt, void *object) +{ + int found = FALSE; + struct stub_manager *stubmgr; + + EnterCriticalSection(&apt->cs); + LIST_FOR_EACH_ENTRY( stubmgr, &apt->stubmgrs, struct stub_manager, entry ) + { + if (stubmgr->object == object) + { + found = TRUE; + stub_manager_int_release(stubmgr); + break; + } + } + LeaveCriticalSection(&apt->cs); + + if (found) + TRACE("disconnect object %p\n", object); + else + WARN("couldn't find object %p\n", object); +} + +/* gets the stub manager associated with an object id - caller must have + * a reference to the apartment while a reference to the stub manager is held. + * it must also call release on the stub manager when it is no longer needed */ +struct stub_manager *get_stub_manager(APARTMENT *apt, OID oid) +{ + struct stub_manager *result = NULL; + struct list *cursor; + + EnterCriticalSection(&apt->cs); + LIST_FOR_EACH( cursor, &apt->stubmgrs ) + { + struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry ); + + if (m->oid == oid) + { + result = m; + stub_manager_int_addref(result); + break; + } + } + LeaveCriticalSection(&apt->cs); + + if (result) + TRACE("found %p for oid %s\n", result, wine_dbgstr_longlong(oid)); + else + TRACE("not found for oid %s\n", wine_dbgstr_longlong(oid)); + + return result; +} + +/* increments the internal refcount */ +ULONG stub_manager_int_addref(struct stub_manager *This) +{ + ULONG refs; + + EnterCriticalSection(&This->apt->cs); + refs = ++This->refs; + LeaveCriticalSection(&This->apt->cs); + + TRACE("before %ld\n", refs - 1); + + return refs; +} + +/* decrements the internal refcount */ +ULONG stub_manager_int_release(struct stub_manager *This) +{ + ULONG refs; + APARTMENT *apt = This->apt; + + EnterCriticalSection(&apt->cs); + refs = --This->refs; + + TRACE("after %ld\n", refs); + + if (!refs) + stub_manager_delete(This); + LeaveCriticalSection(&apt->cs); + + return refs; +} + +/* add some external references (ie from a client that unmarshaled an ifptr) */ +ULONG stub_manager_ext_addref(struct stub_manager *m, ULONG refs) +{ + ULONG rc; + + EnterCriticalSection(&m->lock); + + /* make sure we don't overflow extrefs */ + refs = min(refs, (ULONG_MAX-1 - m->extrefs)); + rc = (m->extrefs += refs); + + LeaveCriticalSection(&m->lock); + + TRACE("added %lu refs to %p (oid %s), rc is now %lu\n", refs, m, wine_dbgstr_longlong(m->oid), rc); + + return rc; +} + +/* remove some external references */ +ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs) +{ + ULONG rc; + + EnterCriticalSection(&m->lock); + + /* make sure we don't underflow extrefs */ + refs = min(refs, m->extrefs); + rc = (m->extrefs -= refs); + + LeaveCriticalSection(&m->lock); + + TRACE("removed %lu refs from %p (oid %s), rc is now %lu\n", refs, m, wine_dbgstr_longlong(m->oid), rc); + + if (rc == 0) + stub_manager_int_release(m); + + return rc; +} + +static struct ifstub *stub_manager_ipid_to_ifstub(struct stub_manager *m, const IPID *ipid) +{ + struct list *cursor; + struct ifstub *result = NULL; + + EnterCriticalSection(&m->lock); + LIST_FOR_EACH( cursor, &m->ifstubs ) + { + struct ifstub *ifstub = LIST_ENTRY( cursor, struct ifstub, entry ); + + if (IsEqualGUID(ipid, &ifstub->ipid)) + { + result = ifstub; + break; + } + } + LeaveCriticalSection(&m->lock); + + return result; +} + +/* gets the stub manager associated with an ipid - caller must have + * a reference to the apartment while a reference to the stub manager is held. + * it must also call release on the stub manager when it is no longer needed */ +static struct stub_manager *get_stub_manager_from_ipid(APARTMENT *apt, const IPID *ipid) +{ + struct stub_manager *result = NULL; + struct list *cursor; + + EnterCriticalSection(&apt->cs); + LIST_FOR_EACH( cursor, &apt->stubmgrs ) + { + struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry ); + + if (stub_manager_ipid_to_ifstub(m, ipid)) + { + result = m; + stub_manager_int_addref(result); + break; + } + } + LeaveCriticalSection(&apt->cs); + + if (result) + TRACE("found %p for ipid %s\n", result, debugstr_guid(ipid)); + else + ERR("not found for ipid %s\n", debugstr_guid(ipid)); + + return result; +} + +HRESULT ipid_to_stub_manager(const IPID *ipid, APARTMENT **stub_apt, struct stub_manager **stubmgr_ret) +{ + /* FIXME: hack for IRemUnknown */ + if (ipid->Data2 == 0xffff) + *stub_apt = apartment_findfromoxid(*(OXID *)ipid->Data4, TRUE); + else + *stub_apt = apartment_findfromtid(ipid->Data2); + if (!*stub_apt) + { + ERR("Couldn't find apartment corresponding to TID 0x%04x\n", ipid->Data2); + return RPC_E_INVALID_OBJECT; + } + *stubmgr_ret = get_stub_manager_from_ipid(*stub_apt, ipid); + if (!*stubmgr_ret) + { + apartment_release(*stub_apt); + *stub_apt = NULL; + return RPC_E_INVALID_OBJECT; + } + return S_OK; +} + +/* gets the apartment and IRpcStubBuffer from an object. the caller must + * release the references to both objects */ +IRpcStubBuffer *ipid_to_apt_and_stubbuffer(const IPID *ipid, APARTMENT **stub_apt) +{ + IRpcStubBuffer *ret = NULL; + struct stub_manager *stubmgr; + struct ifstub *ifstub; + HRESULT hr; + + *stub_apt = NULL; + + hr = ipid_to_stub_manager(ipid, stub_apt, &stubmgr); + if (hr != S_OK) return NULL; + + ifstub = stub_manager_ipid_to_ifstub(stubmgr, ipid); + if (ifstub) + ret = ifstub->stubbuffer; + + if (ret) IRpcStubBuffer_AddRef(ret); + + stub_manager_int_release(stubmgr); + + return ret; +} + +/* generates an ipid in the following format (similar to native version): + * Data1 = apartment-local ipid counter + * Data2 = apartment creator thread ID + * Data3 = process ID + * Data4 = random value + */ +static inline HRESULT generate_ipid(struct stub_manager *m, IPID *ipid) +{ + HRESULT hr; + hr = UuidCreate(ipid); + if (FAILED(hr)) + { + ERR("couldn't create IPID for stub manager %p\n", m); + UuidCreateNil(ipid); + return hr; + } + + ipid->Data1 = InterlockedIncrement(&m->apt->ipidc); + ipid->Data2 = (USHORT)m->apt->tid; + ipid->Data3 = (USHORT)GetCurrentProcessId(); + return S_OK; +} + +/* registers a new interface stub COM object with the stub manager and returns registration record */ +struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *sb, IUnknown *iptr, REFIID iid) +{ + struct ifstub *stub; + + TRACE("oid=%s, stubbuffer=%p, iptr=%p, iid=%s\n", + wine_dbgstr_longlong(m->oid), sb, iptr, debugstr_guid(iid)); + + stub = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct ifstub)); + if (!stub) return NULL; + + stub->stubbuffer = sb; + IUnknown_AddRef(sb); + + /* no need to ref this, same object as sb */ + stub->iface = iptr; + + stub->iid = *iid; + + /* FIXME: hack for IRemUnknown because we don't notify SCM of our IPID + * yet, so we need to use a well-known one */ + if (IsEqualIID(iid, &IID_IRemUnknown)) + { + stub->ipid.Data1 = 0xffffffff; + stub->ipid.Data2 = 0xffff; + stub->ipid.Data3 = 0xffff; + assert(sizeof(stub->ipid.Data4) == sizeof(m->apt->oxid)); + memcpy(&stub->ipid.Data4, &m->apt->oxid, sizeof(OXID)); + } + else + generate_ipid(m, &stub->ipid); + + EnterCriticalSection(&m->lock); + list_add_head(&m->ifstubs, &stub->entry); + LeaveCriticalSection(&m->lock); + + TRACE("ifstub %p created with ipid %s\n", stub, debugstr_guid(&stub->ipid)); + + return stub; +} + +static void stub_manager_delete_ifstub(struct stub_manager *m, struct ifstub *ifstub) +{ + TRACE("m=%p, m->oid=%s, ipid=%s\n", m, wine_dbgstr_longlong(m->oid), debugstr_guid(&ifstub->ipid)); + + list_remove(&ifstub->entry); + + RPC_UnregisterInterface(&ifstub->iid); + + IUnknown_Release(ifstub->stubbuffer); + IUnknown_Release(ifstub->iface); + + HeapFree(GetProcessHeap(), 0, ifstub); +} + +/* returns TRUE if it is possible to unmarshal, FALSE otherwise. */ +BOOL stub_manager_notify_unmarshal(struct stub_manager *m) +{ + BOOL ret; + + EnterCriticalSection(&m->lock); + + switch (m->state) + { + case STUBSTATE_TABLE_STRONG: + case STUBSTATE_TABLE_WEAK_MARSHALED: + /* no transition */ + ret = TRUE; + break; + case STUBSTATE_TABLE_WEAK_UNMARSHALED: + m->state = STUBSTATE_TABLE_WEAK_MARSHALED; + ret = TRUE; + break; + case STUBSTATE_NORMAL_MARSHALED: + m->state = STUBSTATE_NORMAL_UNMARSHALED; + ret = TRUE; + break; + default: + WARN("object OID %s already unmarshaled\n", + wine_dbgstr_longlong(m->oid)); + ret = FALSE; + break; + } + + LeaveCriticalSection(&m->lock); + + return ret; +} + +void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs) +{ + EnterCriticalSection(&m->lock); + + switch (m->state) + { + case STUBSTATE_NORMAL_MARSHALED: + case STUBSTATE_NORMAL_UNMARSHALED: /* FIXME: check this */ + /* nothing to change */ + break; + case STUBSTATE_TABLE_WEAK_UNMARSHALED: + case STUBSTATE_TABLE_STRONG: + refs = 1; + break; + case STUBSTATE_TABLE_WEAK_MARSHALED: + refs = 0; /* like native */ + break; + } + + stub_manager_ext_release(m, refs); + + LeaveCriticalSection(&m->lock); +} + +/* is an ifstub table marshaled? */ +BOOL stub_manager_is_table_marshaled(struct stub_manager *m) +{ + BOOL ret; + + EnterCriticalSection(&m->lock); + ret = ((m->state == STUBSTATE_TABLE_STRONG) || + (m->state == STUBSTATE_TABLE_WEAK_MARSHALED) || + (m->state == STUBSTATE_TABLE_WEAK_UNMARSHALED)); + LeaveCriticalSection(&m->lock); + + return ret; +} + + +/***************************************************************************** + * + * IRemUnknown implementation + * + * + * Note: this object is not related to the lifetime of a stub_manager, but it + * interacts with stub managers. + */ + +const IID IID_IRemUnknown = { 0x00000131, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} }; + +typedef struct rem_unknown +{ + const IRemUnknownVtbl *lpVtbl; + ULONG refs; +} RemUnknown; + +static const IRemUnknownVtbl RemUnknown_Vtbl; + + +/* construct an IRemUnknown object with one outstanding reference */ +static HRESULT RemUnknown_Construct(IRemUnknown **ppRemUnknown) +{ + RemUnknown *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + + if (!This) return E_OUTOFMEMORY; + + This->lpVtbl = &RemUnknown_Vtbl; + This->refs = 1; + + *ppRemUnknown = (IRemUnknown *)This; + return S_OK; +} + +static HRESULT WINAPI RemUnknown_QueryInterface(IRemUnknown *iface, REFIID riid, void **ppv) +{ + TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); + + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IRemUnknown)) + { + *ppv = (LPVOID)iface; + IRemUnknown_AddRef(iface); + return S_OK; + } + + FIXME("No interface for iid %s\n", debugstr_guid(riid)); + + *ppv = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI RemUnknown_AddRef(IRemUnknown *iface) +{ + ULONG refs; + RemUnknown *This = (RemUnknown *)iface; + + refs = InterlockedIncrement(&This->refs); + + TRACE("%p before: %ld\n", iface, refs-1); + return refs; +} + +static ULONG WINAPI RemUnknown_Release(IRemUnknown *iface) +{ + ULONG refs; + RemUnknown *This = (RemUnknown *)iface; + + refs = InterlockedDecrement(&This->refs); + if (!refs) + HeapFree(GetProcessHeap(), 0, This); + + TRACE("%p after: %ld\n", iface, refs); + return refs; +} + +static HRESULT WINAPI RemUnknown_RemQueryInterface(IRemUnknown *iface, + REFIPID ripid, ULONG cRefs, USHORT cIids, IID *iids /* [size_is(cIids)] */, + REMQIRESULT **ppQIResults /* [size_is(,cIids)] */) +{ + HRESULT hr; + USHORT i; + USHORT successful_qis = 0; + APARTMENT *apt; + struct stub_manager *stubmgr; + + TRACE("(%p)->(%s, %ld, %d, %p, %p)\n", iface, debugstr_guid(ripid), cRefs, cIids, iids, ppQIResults); + + hr = ipid_to_stub_manager(ripid, &apt, &stubmgr); + if (hr != S_OK) return hr; + + *ppQIResults = CoTaskMemAlloc(sizeof(REMQIRESULT) * cIids); + + for (i = 0; i < cIids; i++) + { + HRESULT hrobj = marshal_object(apt, &(*ppQIResults)[i].std, &iids[i], + stubmgr->object, MSHLFLAGS_NORMAL); + if (hrobj == S_OK) + successful_qis++; + (*ppQIResults)[i].hResult = hrobj; + } + + stub_manager_int_release(stubmgr); + apartment_release(apt); + + if (successful_qis == cIids) + return S_OK; /* we got all requested interfaces */ + else if (successful_qis == 0) + return E_NOINTERFACE; /* we didn't get any interfaces */ + else + return S_FALSE; /* we got some interfaces */ +} + +static HRESULT WINAPI RemUnknown_RemAddRef(IRemUnknown *iface, + USHORT cInterfaceRefs, + REMINTERFACEREF* InterfaceRefs /* [size_is(cInterfaceRefs)] */, + HRESULT *pResults /* [size_is(cInterfaceRefs)] */) +{ + HRESULT hr = S_OK; + USHORT i; + + TRACE("(%p)->(%d, %p, %p)\n", iface, cInterfaceRefs, InterfaceRefs, pResults); + + for (i = 0; i < cInterfaceRefs; i++) + { + APARTMENT *apt; + struct stub_manager *stubmgr; + + pResults[i] = ipid_to_stub_manager(&InterfaceRefs[i].ipid, &apt, &stubmgr); + if (pResults[i] != S_OK) + { + hr = S_FALSE; + continue; + } + + stub_manager_ext_addref(stubmgr, InterfaceRefs[i].cPublicRefs); + if (InterfaceRefs[i].cPrivateRefs) + FIXME("Adding %ld refs securely not implemented\n", InterfaceRefs[i].cPrivateRefs); + + stub_manager_int_release(stubmgr); + apartment_release(apt); + } + + return hr; +} + +static HRESULT WINAPI RemUnknown_RemRelease(IRemUnknown *iface, + USHORT cInterfaceRefs, + REMINTERFACEREF* InterfaceRefs /* [size_is(cInterfaceRefs)] */) +{ + HRESULT hr = S_OK; + USHORT i; + + TRACE("(%p)->(%d, %p)\n", iface, cInterfaceRefs, InterfaceRefs); + + for (i = 0; i < cInterfaceRefs; i++) + { + APARTMENT *apt; + struct stub_manager *stubmgr; + + hr = ipid_to_stub_manager(&InterfaceRefs[i].ipid, &apt, &stubmgr); + if (hr != S_OK) + { + hr = E_INVALIDARG; + /* FIXME: we should undo any changes already made in this function */ + break; + } + + stub_manager_ext_release(stubmgr, InterfaceRefs[i].cPublicRefs); + if (InterfaceRefs[i].cPrivateRefs) + FIXME("Releasing %ld refs securely not implemented\n", InterfaceRefs[i].cPrivateRefs); + + stub_manager_int_release(stubmgr); + apartment_release(apt); + } + + return hr; +} + +static const IRemUnknownVtbl RemUnknown_Vtbl = +{ + RemUnknown_QueryInterface, + RemUnknown_AddRef, + RemUnknown_Release, + RemUnknown_RemQueryInterface, + RemUnknown_RemAddRef, + RemUnknown_RemRelease +}; + +/* starts the IRemUnknown listener for the current apartment */ +HRESULT start_apartment_remote_unknown() +{ + IRemUnknown *pRemUnknown; + HRESULT hr = S_OK; + APARTMENT *apt = COM_CurrentApt(); + + EnterCriticalSection(&apt->cs); + if (!apt->remunk_exported) + { + /* create the IRemUnknown object */ + hr = RemUnknown_Construct(&pRemUnknown); + if (hr == S_OK) + { + STDOBJREF stdobjref; /* dummy - not used */ + /* register it with the stub manager */ + hr = marshal_object(apt, &stdobjref, &IID_IRemUnknown, (IUnknown *)pRemUnknown, MSHLFLAGS_NORMAL); + /* release our reference to the object as the stub manager will manage the life cycle for us */ + IRemUnknown_Release(pRemUnknown); + if (hr == S_OK) + apt->remunk_exported = TRUE; + } + } + LeaveCriticalSection(&apt->cs); + return hr; +} diff --git a/reactos/lib/oleaut32/connpt.c b/reactos/lib/oleaut32/connpt.c index 1993619aaf3..b2afb6a872c 100644 --- a/reactos/lib/oleaut32/connpt.c +++ b/reactos/lib/oleaut32/connpt.c @@ -1,628 +1,628 @@ -/* - * Implementation of a generic ConnectionPoint object. - * - * Copyright 2000 Huw D M Davies for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTES: - * See one exported function here is CreateConnectionPoint, see - * comments just above that function for information. - */ - -#include <assert.h> -#include <stdarg.h> -#include <string.h> - -#define COBJMACROS - -#include "winerror.h" -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "ole2.h" -#include "olectl.h" -#include "connpt.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -#define MAXSINKS 10 - -/************************************************************************ - * Implementation of IConnectionPoint - */ -typedef struct ConnectionPointImpl { - - IConnectionPointVtbl *lpvtbl; - - /* IUnknown of our main object*/ - IUnknown *Obj; - - /* Reference count */ - DWORD ref; - - /* IID of sink interface */ - IID iid; - - /* Array of sink IUnknowns */ - IUnknown **sinks; - DWORD maxSinks; - - DWORD nSinks; -} ConnectionPointImpl; - -static IConnectionPointVtbl ConnectionPointImpl_VTable; - - -/************************************************************************ - * Implementation of IEnumConnections - */ -typedef struct EnumConnectionsImpl { - - IEnumConnectionsVtbl *lpvtbl; - - DWORD ref; - - /* IUnknown of ConnectionPoint, used for ref counting */ - IUnknown *pUnk; - - /* Connection Data */ - CONNECTDATA *pCD; - DWORD nConns; - - /* Next connection to enumerate from */ - DWORD nCur; - -} EnumConnectionsImpl; - -static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk, - DWORD nSinks, - CONNECTDATA *pCD); - - -/************************************************************************ - * ConnectionPointImpl_Construct - */ -static ConnectionPointImpl *ConnectionPointImpl_Construct(IUnknown *pUnk, - REFIID riid) -{ - ConnectionPointImpl *Obj; - - Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj)); - Obj->lpvtbl = &ConnectionPointImpl_VTable; - Obj->Obj = pUnk; - Obj->ref = 1; - Obj->iid = *riid; - Obj->maxSinks = MAXSINKS; - Obj->sinks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(IUnknown*) * MAXSINKS); - Obj->nSinks = 0; - return Obj; -} - -/************************************************************************ - * ConnectionPointImpl_Destroy - */ -static void ConnectionPointImpl_Destroy(ConnectionPointImpl *Obj) -{ - DWORD i; - for(i = 0; i < Obj->maxSinks; i++) { - if(Obj->sinks[i]) { - IUnknown_Release(Obj->sinks[i]); - Obj->sinks[i] = NULL; - } - } - HeapFree(GetProcessHeap(), 0, Obj->sinks); - HeapFree(GetProcessHeap(), 0, Obj); - return; -} - -static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface); -/************************************************************************ - * ConnectionPointImpl_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static HRESULT WINAPI ConnectionPointImpl_QueryInterface( - IConnectionPoint* iface, - REFIID riid, - void** ppvObject) -{ - ConnectionPointImpl *This = (ConnectionPointImpl *)iface; - TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject); - - /* - * Perform a sanity check on the parameters. - */ - if ( (This==0) || (ppvObject==0) ) - return E_INVALIDARG; - - /* - * Initialize the return parameter. - */ - *ppvObject = 0; - - /* - * Compare the riid with the interface IDs implemented by this object. - */ - if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) - { - *ppvObject = (IConnectionPoint*)This; - } - else if (memcmp(&IID_IConnectionPoint, riid, sizeof(IID_IConnectionPoint)) == 0) - { - *ppvObject = (IConnectionPoint*)This; - } - - /* - * Check that we obtained an interface. - */ - if ((*ppvObject)==0) - { - FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid)); - return E_NOINTERFACE; - } - - /* - * Query Interface always increases the reference count by one when it is - * successful - */ - ConnectionPointImpl_AddRef((IConnectionPoint*)This); - - return S_OK; -} - - -/************************************************************************ - * ConnectionPointImpl_AddRef (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface) -{ - ConnectionPointImpl *This = (ConnectionPointImpl *)iface; - ULONG refCount = InterlockedIncrement(&This->ref); - - TRACE("(%p)->(ref before=%ld)\n", This, refCount - 1); - - return refCount; -} - -/************************************************************************ - * ConnectionPointImpl_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI ConnectionPointImpl_Release( - IConnectionPoint* iface) -{ - ConnectionPointImpl *This = (ConnectionPointImpl *)iface; - ULONG refCount = InterlockedDecrement(&This->ref); - - TRACE("(%p)->(ref before=%ld)\n", This, refCount + 1); - - /* - * If the reference count goes down to 0, perform suicide. - */ - if (!refCount) ConnectionPointImpl_Destroy(This); - - return refCount; -} - -/************************************************************************ - * ConnectionPointImpl_GetConnectionInterface (IConnectionPoint) - * - */ -static HRESULT WINAPI ConnectionPointImpl_GetConnectionInterface( - IConnectionPoint *iface, - IID *piid) -{ - ConnectionPointImpl *This = (ConnectionPointImpl *)iface; - TRACE("(%p)->(%p) returning %s\n", This, piid, debugstr_guid(&(This->iid))); - *piid = This->iid; - return S_OK; -} - -/************************************************************************ - * ConnectionPointImpl_GetConnectionPointContainer (IConnectionPoint) - * - */ -static HRESULT WINAPI ConnectionPointImpl_GetConnectionPointContainer( - IConnectionPoint *iface, - IConnectionPointContainer **ppCPC) -{ - ConnectionPointImpl *This = (ConnectionPointImpl *)iface; - TRACE("(%p)->(%p)\n", This, ppCPC); - - return IUnknown_QueryInterface(This->Obj, - &IID_IConnectionPointContainer, - (LPVOID)ppCPC); -} - -/************************************************************************ - * ConnectionPointImpl_Advise (IConnectionPoint) - * - */ -static HRESULT WINAPI ConnectionPointImpl_Advise(IConnectionPoint *iface, - IUnknown *lpUnk, - DWORD *pdwCookie) -{ - DWORD i; - ConnectionPointImpl *This = (ConnectionPointImpl *)iface; - IUnknown *lpSink; - TRACE("(%p)->(%p, %p)\n", This, lpUnk, pdwCookie); - - *pdwCookie = 0; - if(FAILED(IUnknown_QueryInterface(lpUnk, &This->iid, (LPVOID)&lpSink))) - return CONNECT_E_CANNOTCONNECT; - - for(i = 0; i < This->maxSinks; i++) { - if(This->sinks[i] == NULL) - break; - } - if(i == This->maxSinks) { - This->maxSinks += MAXSINKS; - This->sinks = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->sinks, - This->maxSinks * sizeof(IUnknown *)); - } - This->sinks[i] = lpSink; - This->nSinks++; - *pdwCookie = i + 1; - return S_OK; -} - - -/************************************************************************ - * ConnectionPointImpl_Unadvise (IConnectionPoint) - * - */ -static HRESULT WINAPI ConnectionPointImpl_Unadvise(IConnectionPoint *iface, - DWORD dwCookie) -{ - ConnectionPointImpl *This = (ConnectionPointImpl *)iface; - TRACE("(%p)->(%ld)\n", This, dwCookie); - - if(dwCookie == 0 || dwCookie > This->maxSinks) return E_INVALIDARG; - - if(This->sinks[dwCookie-1] == NULL) return CONNECT_E_NOCONNECTION; - - IUnknown_Release(This->sinks[dwCookie-1]); - This->sinks[dwCookie-1] = NULL; - This->nSinks--; - return S_OK; -} - -/************************************************************************ - * ConnectionPointImpl_EnumConnections (IConnectionPoint) - * - */ -static HRESULT WINAPI ConnectionPointImpl_EnumConnections( - IConnectionPoint *iface, - LPENUMCONNECTIONS *ppEnum) -{ - ConnectionPointImpl *This = (ConnectionPointImpl *)iface; - CONNECTDATA *pCD; - DWORD i, nextslot; - EnumConnectionsImpl *EnumObj; - HRESULT hr; - - TRACE("(%p)->(%p)\n", This, ppEnum); - - *ppEnum = NULL; - - if(This->nSinks == 0) return OLE_E_NOCONNECTION; - - pCD = HeapAlloc(GetProcessHeap(), 0, sizeof(CONNECTDATA) * This->nSinks); - - for(i = 0, nextslot = 0; i < This->maxSinks; i++) { - if(This->sinks[i] != NULL) { - pCD[nextslot].pUnk = This->sinks[i]; - pCD[nextslot].dwCookie = i + 1; - nextslot++; - } - } - assert(nextslot == This->nSinks); - - /* Bump the ref count of this object up by one. It gets Released in - IEnumConnections_Release */ - IUnknown_AddRef((IUnknown*)This); - - EnumObj = EnumConnectionsImpl_Construct((IUnknown*)This, This->nSinks, pCD); - hr = IEnumConnections_QueryInterface((IEnumConnections*)EnumObj, - &IID_IEnumConnections, (LPVOID)ppEnum); - IEnumConnections_Release((IEnumConnections*)EnumObj); - - HeapFree(GetProcessHeap(), 0, pCD); - return hr; -} - -static IConnectionPointVtbl ConnectionPointImpl_VTable = -{ - ConnectionPointImpl_QueryInterface, - ConnectionPointImpl_AddRef, - ConnectionPointImpl_Release, - ConnectionPointImpl_GetConnectionInterface, - ConnectionPointImpl_GetConnectionPointContainer, - ConnectionPointImpl_Advise, - ConnectionPointImpl_Unadvise, - ConnectionPointImpl_EnumConnections -}; - - -static IEnumConnectionsVtbl EnumConnectionsImpl_VTable; -static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface); - -/************************************************************************ - * EnumConnectionsImpl_Construct - */ -static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk, - DWORD nSinks, - CONNECTDATA *pCD) -{ - EnumConnectionsImpl *Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj)); - DWORD i; - - Obj->lpvtbl = &EnumConnectionsImpl_VTable; - Obj->ref = 1; - Obj->pUnk = pUnk; - Obj->pCD = HeapAlloc(GetProcessHeap(), 0, nSinks * sizeof(CONNECTDATA)); - Obj->nConns = nSinks; - Obj->nCur = 0; - - for(i = 0; i < nSinks; i++) { - Obj->pCD[i] = pCD[i]; - IUnknown_AddRef(Obj->pCD[i].pUnk); - } - return Obj; -} - -/************************************************************************ - * EnumConnectionsImpl_Destroy - */ -static void EnumConnectionsImpl_Destroy(EnumConnectionsImpl *Obj) -{ - DWORD i; - - for(i = 0; i < Obj->nConns; i++) - IUnknown_Release(Obj->pCD[i].pUnk); - - HeapFree(GetProcessHeap(), 0, Obj->pCD); - HeapFree(GetProcessHeap(), 0, Obj); - return; -} - -/************************************************************************ - * EnumConnectionsImpl_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static HRESULT WINAPI EnumConnectionsImpl_QueryInterface( - IEnumConnections* iface, - REFIID riid, - void** ppvObject) -{ - ConnectionPointImpl *This = (ConnectionPointImpl *)iface; - TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject); - - /* - * Perform a sanity check on the parameters. - */ - if ( (This==0) || (ppvObject==0) ) - return E_INVALIDARG; - - /* - * Initialize the return parameter. - */ - *ppvObject = 0; - - /* - * Compare the riid with the interface IDs implemented by this object. - */ - if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) - { - *ppvObject = (IEnumConnections*)This; - } - else if (memcmp(&IID_IEnumConnections, riid, sizeof(IID_IEnumConnections)) == 0) - { - *ppvObject = (IEnumConnections*)This; - } - - /* - * Check that we obtained an interface. - */ - if ((*ppvObject)==0) - { - FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid)); - return E_NOINTERFACE; - } - - /* - * Query Interface always increases the reference count by one when it is - * successful - */ - EnumConnectionsImpl_AddRef((IEnumConnections*)This); - - return S_OK; -} - - -/************************************************************************ - * EnumConnectionsImpl_AddRef (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface) -{ - EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface; - ULONG refCount = InterlockedIncrement(&This->ref); - - TRACE("(%p)->(ref before=%ld)\n", This, refCount - 1); - - IUnknown_AddRef(This->pUnk); - return refCount; -} - -/************************************************************************ - * EnumConnectionsImpl_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI EnumConnectionsImpl_Release(IEnumConnections* iface) -{ - EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface; - ULONG refCount = InterlockedDecrement(&This->ref); - - TRACE("(%p)->(ref before=%ld)\n", This, refCount + 1); - - IUnknown_Release(This->pUnk); - - /* - * If the reference count goes down to 0, perform suicide. - */ - if (!refCount) EnumConnectionsImpl_Destroy(This); - - return refCount; -} - -/************************************************************************ - * EnumConnectionsImpl_Next (IEnumConnections) - * - */ -static HRESULT WINAPI EnumConnectionsImpl_Next(IEnumConnections* iface, - ULONG cConn, LPCONNECTDATA pCD, - ULONG *pEnum) -{ - EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface; - DWORD nRet = 0; - TRACE("(%p)->(%ld, %p, %p)\n", This, cConn, pCD, pEnum); - - if(pEnum == NULL) { - if(cConn != 1) - return E_POINTER; - } else - *pEnum = 0; - - if(This->nCur >= This->nConns) - return S_FALSE; - - while(This->nCur < This->nConns && cConn) { - *pCD++ = This->pCD[This->nCur]; - IUnknown_AddRef(This->pCD[This->nCur].pUnk); - This->nCur++; - cConn--; - nRet++; - } - - if(pEnum) - *pEnum = nRet; - - return S_OK; -} - - -/************************************************************************ - * EnumConnectionsImpl_Skip (IEnumConnections) - * - */ -static HRESULT WINAPI EnumConnectionsImpl_Skip(IEnumConnections* iface, - ULONG cSkip) -{ - EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface; - TRACE("(%p)->(%ld)\n", This, cSkip); - - if(This->nCur + cSkip >= This->nConns) - return S_FALSE; - - This->nCur += cSkip; - - return S_OK; -} - - -/************************************************************************ - * EnumConnectionsImpl_Reset (IEnumConnections) - * - */ -static HRESULT WINAPI EnumConnectionsImpl_Reset(IEnumConnections* iface) -{ - EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface; - TRACE("(%p)\n", This); - - This->nCur = 0; - - return S_OK; -} - - -/************************************************************************ - * EnumConnectionsImpl_Clone (IEnumConnections) - * - */ -static HRESULT WINAPI EnumConnectionsImpl_Clone(IEnumConnections* iface, - LPENUMCONNECTIONS *ppEnum) -{ - EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface; - EnumConnectionsImpl *newObj; - TRACE("(%p)->(%p)\n", This, ppEnum); - - newObj = EnumConnectionsImpl_Construct(This->pUnk, This->nConns, This->pCD); - newObj->nCur = This->nCur; - *ppEnum = (LPENUMCONNECTIONS)newObj; - IUnknown_AddRef(This->pUnk); - return S_OK; -} - -static IEnumConnectionsVtbl EnumConnectionsImpl_VTable = -{ - EnumConnectionsImpl_QueryInterface, - EnumConnectionsImpl_AddRef, - EnumConnectionsImpl_Release, - EnumConnectionsImpl_Next, - EnumConnectionsImpl_Skip, - EnumConnectionsImpl_Reset, - EnumConnectionsImpl_Clone -}; - -/************************************************************************ - * - * The exported function to create the connection point. - * NB not a windows API - * - * PARAMS - * pUnk [in] IUnknown of object to which the ConnectionPoint is associated. - * Needed to access IConnectionPointContainer. - * - * riid [in] IID of sink interface that this ConnectionPoint manages - * - * pCP [out] returns IConnectionPoint - * - */ -HRESULT CreateConnectionPoint(IUnknown *pUnk, REFIID riid, - IConnectionPoint **pCP) -{ - ConnectionPointImpl *Obj; - HRESULT hr; - - Obj = ConnectionPointImpl_Construct(pUnk, riid); - if(!Obj) return E_OUTOFMEMORY; - - hr = IConnectionPoint_QueryInterface((IConnectionPoint *)Obj, - &IID_IConnectionPoint, (LPVOID)pCP); - IConnectionPoint_Release((IConnectionPoint *)Obj); - return hr; -} +/* + * Implementation of a generic ConnectionPoint object. + * + * Copyright 2000 Huw D M Davies for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES: + * See one exported function here is CreateConnectionPoint, see + * comments just above that function for information. + */ + +#include <assert.h> +#include <stdarg.h> +#include <string.h> + +#define COBJMACROS + +#include "winerror.h" +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "ole2.h" +#include "olectl.h" +#include "connpt.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +#define MAXSINKS 10 + +/************************************************************************ + * Implementation of IConnectionPoint + */ +typedef struct ConnectionPointImpl { + + IConnectionPointVtbl *lpvtbl; + + /* IUnknown of our main object*/ + IUnknown *Obj; + + /* Reference count */ + DWORD ref; + + /* IID of sink interface */ + IID iid; + + /* Array of sink IUnknowns */ + IUnknown **sinks; + DWORD maxSinks; + + DWORD nSinks; +} ConnectionPointImpl; + +static IConnectionPointVtbl ConnectionPointImpl_VTable; + + +/************************************************************************ + * Implementation of IEnumConnections + */ +typedef struct EnumConnectionsImpl { + + IEnumConnectionsVtbl *lpvtbl; + + DWORD ref; + + /* IUnknown of ConnectionPoint, used for ref counting */ + IUnknown *pUnk; + + /* Connection Data */ + CONNECTDATA *pCD; + DWORD nConns; + + /* Next connection to enumerate from */ + DWORD nCur; + +} EnumConnectionsImpl; + +static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk, + DWORD nSinks, + CONNECTDATA *pCD); + + +/************************************************************************ + * ConnectionPointImpl_Construct + */ +static ConnectionPointImpl *ConnectionPointImpl_Construct(IUnknown *pUnk, + REFIID riid) +{ + ConnectionPointImpl *Obj; + + Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj)); + Obj->lpvtbl = &ConnectionPointImpl_VTable; + Obj->Obj = pUnk; + Obj->ref = 1; + Obj->iid = *riid; + Obj->maxSinks = MAXSINKS; + Obj->sinks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(IUnknown*) * MAXSINKS); + Obj->nSinks = 0; + return Obj; +} + +/************************************************************************ + * ConnectionPointImpl_Destroy + */ +static void ConnectionPointImpl_Destroy(ConnectionPointImpl *Obj) +{ + DWORD i; + for(i = 0; i < Obj->maxSinks; i++) { + if(Obj->sinks[i]) { + IUnknown_Release(Obj->sinks[i]); + Obj->sinks[i] = NULL; + } + } + HeapFree(GetProcessHeap(), 0, Obj->sinks); + HeapFree(GetProcessHeap(), 0, Obj); + return; +} + +static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface); +/************************************************************************ + * ConnectionPointImpl_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static HRESULT WINAPI ConnectionPointImpl_QueryInterface( + IConnectionPoint* iface, + REFIID riid, + void** ppvObject) +{ + ConnectionPointImpl *This = (ConnectionPointImpl *)iface; + TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject); + + /* + * Perform a sanity check on the parameters. + */ + if ( (This==0) || (ppvObject==0) ) + return E_INVALIDARG; + + /* + * Initialize the return parameter. + */ + *ppvObject = 0; + + /* + * Compare the riid with the interface IDs implemented by this object. + */ + if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) + { + *ppvObject = (IConnectionPoint*)This; + } + else if (memcmp(&IID_IConnectionPoint, riid, sizeof(IID_IConnectionPoint)) == 0) + { + *ppvObject = (IConnectionPoint*)This; + } + + /* + * Check that we obtained an interface. + */ + if ((*ppvObject)==0) + { + FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid)); + return E_NOINTERFACE; + } + + /* + * Query Interface always increases the reference count by one when it is + * successful + */ + ConnectionPointImpl_AddRef((IConnectionPoint*)This); + + return S_OK; +} + + +/************************************************************************ + * ConnectionPointImpl_AddRef (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface) +{ + ConnectionPointImpl *This = (ConnectionPointImpl *)iface; + ULONG refCount = InterlockedIncrement(&This->ref); + + TRACE("(%p)->(ref before=%ld)\n", This, refCount - 1); + + return refCount; +} + +/************************************************************************ + * ConnectionPointImpl_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI ConnectionPointImpl_Release( + IConnectionPoint* iface) +{ + ConnectionPointImpl *This = (ConnectionPointImpl *)iface; + ULONG refCount = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(ref before=%ld)\n", This, refCount + 1); + + /* + * If the reference count goes down to 0, perform suicide. + */ + if (!refCount) ConnectionPointImpl_Destroy(This); + + return refCount; +} + +/************************************************************************ + * ConnectionPointImpl_GetConnectionInterface (IConnectionPoint) + * + */ +static HRESULT WINAPI ConnectionPointImpl_GetConnectionInterface( + IConnectionPoint *iface, + IID *piid) +{ + ConnectionPointImpl *This = (ConnectionPointImpl *)iface; + TRACE("(%p)->(%p) returning %s\n", This, piid, debugstr_guid(&(This->iid))); + *piid = This->iid; + return S_OK; +} + +/************************************************************************ + * ConnectionPointImpl_GetConnectionPointContainer (IConnectionPoint) + * + */ +static HRESULT WINAPI ConnectionPointImpl_GetConnectionPointContainer( + IConnectionPoint *iface, + IConnectionPointContainer **ppCPC) +{ + ConnectionPointImpl *This = (ConnectionPointImpl *)iface; + TRACE("(%p)->(%p)\n", This, ppCPC); + + return IUnknown_QueryInterface(This->Obj, + &IID_IConnectionPointContainer, + (LPVOID)ppCPC); +} + +/************************************************************************ + * ConnectionPointImpl_Advise (IConnectionPoint) + * + */ +static HRESULT WINAPI ConnectionPointImpl_Advise(IConnectionPoint *iface, + IUnknown *lpUnk, + DWORD *pdwCookie) +{ + DWORD i; + ConnectionPointImpl *This = (ConnectionPointImpl *)iface; + IUnknown *lpSink; + TRACE("(%p)->(%p, %p)\n", This, lpUnk, pdwCookie); + + *pdwCookie = 0; + if(FAILED(IUnknown_QueryInterface(lpUnk, &This->iid, (LPVOID)&lpSink))) + return CONNECT_E_CANNOTCONNECT; + + for(i = 0; i < This->maxSinks; i++) { + if(This->sinks[i] == NULL) + break; + } + if(i == This->maxSinks) { + This->maxSinks += MAXSINKS; + This->sinks = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->sinks, + This->maxSinks * sizeof(IUnknown *)); + } + This->sinks[i] = lpSink; + This->nSinks++; + *pdwCookie = i + 1; + return S_OK; +} + + +/************************************************************************ + * ConnectionPointImpl_Unadvise (IConnectionPoint) + * + */ +static HRESULT WINAPI ConnectionPointImpl_Unadvise(IConnectionPoint *iface, + DWORD dwCookie) +{ + ConnectionPointImpl *This = (ConnectionPointImpl *)iface; + TRACE("(%p)->(%ld)\n", This, dwCookie); + + if(dwCookie == 0 || dwCookie > This->maxSinks) return E_INVALIDARG; + + if(This->sinks[dwCookie-1] == NULL) return CONNECT_E_NOCONNECTION; + + IUnknown_Release(This->sinks[dwCookie-1]); + This->sinks[dwCookie-1] = NULL; + This->nSinks--; + return S_OK; +} + +/************************************************************************ + * ConnectionPointImpl_EnumConnections (IConnectionPoint) + * + */ +static HRESULT WINAPI ConnectionPointImpl_EnumConnections( + IConnectionPoint *iface, + LPENUMCONNECTIONS *ppEnum) +{ + ConnectionPointImpl *This = (ConnectionPointImpl *)iface; + CONNECTDATA *pCD; + DWORD i, nextslot; + EnumConnectionsImpl *EnumObj; + HRESULT hr; + + TRACE("(%p)->(%p)\n", This, ppEnum); + + *ppEnum = NULL; + + if(This->nSinks == 0) return OLE_E_NOCONNECTION; + + pCD = HeapAlloc(GetProcessHeap(), 0, sizeof(CONNECTDATA) * This->nSinks); + + for(i = 0, nextslot = 0; i < This->maxSinks; i++) { + if(This->sinks[i] != NULL) { + pCD[nextslot].pUnk = This->sinks[i]; + pCD[nextslot].dwCookie = i + 1; + nextslot++; + } + } + assert(nextslot == This->nSinks); + + /* Bump the ref count of this object up by one. It gets Released in + IEnumConnections_Release */ + IUnknown_AddRef((IUnknown*)This); + + EnumObj = EnumConnectionsImpl_Construct((IUnknown*)This, This->nSinks, pCD); + hr = IEnumConnections_QueryInterface((IEnumConnections*)EnumObj, + &IID_IEnumConnections, (LPVOID)ppEnum); + IEnumConnections_Release((IEnumConnections*)EnumObj); + + HeapFree(GetProcessHeap(), 0, pCD); + return hr; +} + +static IConnectionPointVtbl ConnectionPointImpl_VTable = +{ + ConnectionPointImpl_QueryInterface, + ConnectionPointImpl_AddRef, + ConnectionPointImpl_Release, + ConnectionPointImpl_GetConnectionInterface, + ConnectionPointImpl_GetConnectionPointContainer, + ConnectionPointImpl_Advise, + ConnectionPointImpl_Unadvise, + ConnectionPointImpl_EnumConnections +}; + + +static IEnumConnectionsVtbl EnumConnectionsImpl_VTable; +static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface); + +/************************************************************************ + * EnumConnectionsImpl_Construct + */ +static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk, + DWORD nSinks, + CONNECTDATA *pCD) +{ + EnumConnectionsImpl *Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj)); + DWORD i; + + Obj->lpvtbl = &EnumConnectionsImpl_VTable; + Obj->ref = 1; + Obj->pUnk = pUnk; + Obj->pCD = HeapAlloc(GetProcessHeap(), 0, nSinks * sizeof(CONNECTDATA)); + Obj->nConns = nSinks; + Obj->nCur = 0; + + for(i = 0; i < nSinks; i++) { + Obj->pCD[i] = pCD[i]; + IUnknown_AddRef(Obj->pCD[i].pUnk); + } + return Obj; +} + +/************************************************************************ + * EnumConnectionsImpl_Destroy + */ +static void EnumConnectionsImpl_Destroy(EnumConnectionsImpl *Obj) +{ + DWORD i; + + for(i = 0; i < Obj->nConns; i++) + IUnknown_Release(Obj->pCD[i].pUnk); + + HeapFree(GetProcessHeap(), 0, Obj->pCD); + HeapFree(GetProcessHeap(), 0, Obj); + return; +} + +/************************************************************************ + * EnumConnectionsImpl_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static HRESULT WINAPI EnumConnectionsImpl_QueryInterface( + IEnumConnections* iface, + REFIID riid, + void** ppvObject) +{ + ConnectionPointImpl *This = (ConnectionPointImpl *)iface; + TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject); + + /* + * Perform a sanity check on the parameters. + */ + if ( (This==0) || (ppvObject==0) ) + return E_INVALIDARG; + + /* + * Initialize the return parameter. + */ + *ppvObject = 0; + + /* + * Compare the riid with the interface IDs implemented by this object. + */ + if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) + { + *ppvObject = (IEnumConnections*)This; + } + else if (memcmp(&IID_IEnumConnections, riid, sizeof(IID_IEnumConnections)) == 0) + { + *ppvObject = (IEnumConnections*)This; + } + + /* + * Check that we obtained an interface. + */ + if ((*ppvObject)==0) + { + FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid)); + return E_NOINTERFACE; + } + + /* + * Query Interface always increases the reference count by one when it is + * successful + */ + EnumConnectionsImpl_AddRef((IEnumConnections*)This); + + return S_OK; +} + + +/************************************************************************ + * EnumConnectionsImpl_AddRef (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface) +{ + EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface; + ULONG refCount = InterlockedIncrement(&This->ref); + + TRACE("(%p)->(ref before=%ld)\n", This, refCount - 1); + + IUnknown_AddRef(This->pUnk); + return refCount; +} + +/************************************************************************ + * EnumConnectionsImpl_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI EnumConnectionsImpl_Release(IEnumConnections* iface) +{ + EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface; + ULONG refCount = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(ref before=%ld)\n", This, refCount + 1); + + IUnknown_Release(This->pUnk); + + /* + * If the reference count goes down to 0, perform suicide. + */ + if (!refCount) EnumConnectionsImpl_Destroy(This); + + return refCount; +} + +/************************************************************************ + * EnumConnectionsImpl_Next (IEnumConnections) + * + */ +static HRESULT WINAPI EnumConnectionsImpl_Next(IEnumConnections* iface, + ULONG cConn, LPCONNECTDATA pCD, + ULONG *pEnum) +{ + EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface; + DWORD nRet = 0; + TRACE("(%p)->(%ld, %p, %p)\n", This, cConn, pCD, pEnum); + + if(pEnum == NULL) { + if(cConn != 1) + return E_POINTER; + } else + *pEnum = 0; + + if(This->nCur >= This->nConns) + return S_FALSE; + + while(This->nCur < This->nConns && cConn) { + *pCD++ = This->pCD[This->nCur]; + IUnknown_AddRef(This->pCD[This->nCur].pUnk); + This->nCur++; + cConn--; + nRet++; + } + + if(pEnum) + *pEnum = nRet; + + return S_OK; +} + + +/************************************************************************ + * EnumConnectionsImpl_Skip (IEnumConnections) + * + */ +static HRESULT WINAPI EnumConnectionsImpl_Skip(IEnumConnections* iface, + ULONG cSkip) +{ + EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface; + TRACE("(%p)->(%ld)\n", This, cSkip); + + if(This->nCur + cSkip >= This->nConns) + return S_FALSE; + + This->nCur += cSkip; + + return S_OK; +} + + +/************************************************************************ + * EnumConnectionsImpl_Reset (IEnumConnections) + * + */ +static HRESULT WINAPI EnumConnectionsImpl_Reset(IEnumConnections* iface) +{ + EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface; + TRACE("(%p)\n", This); + + This->nCur = 0; + + return S_OK; +} + + +/************************************************************************ + * EnumConnectionsImpl_Clone (IEnumConnections) + * + */ +static HRESULT WINAPI EnumConnectionsImpl_Clone(IEnumConnections* iface, + LPENUMCONNECTIONS *ppEnum) +{ + EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface; + EnumConnectionsImpl *newObj; + TRACE("(%p)->(%p)\n", This, ppEnum); + + newObj = EnumConnectionsImpl_Construct(This->pUnk, This->nConns, This->pCD); + newObj->nCur = This->nCur; + *ppEnum = (LPENUMCONNECTIONS)newObj; + IUnknown_AddRef(This->pUnk); + return S_OK; +} + +static IEnumConnectionsVtbl EnumConnectionsImpl_VTable = +{ + EnumConnectionsImpl_QueryInterface, + EnumConnectionsImpl_AddRef, + EnumConnectionsImpl_Release, + EnumConnectionsImpl_Next, + EnumConnectionsImpl_Skip, + EnumConnectionsImpl_Reset, + EnumConnectionsImpl_Clone +}; + +/************************************************************************ + * + * The exported function to create the connection point. + * NB not a windows API + * + * PARAMS + * pUnk [in] IUnknown of object to which the ConnectionPoint is associated. + * Needed to access IConnectionPointContainer. + * + * riid [in] IID of sink interface that this ConnectionPoint manages + * + * pCP [out] returns IConnectionPoint + * + */ +HRESULT CreateConnectionPoint(IUnknown *pUnk, REFIID riid, + IConnectionPoint **pCP) +{ + ConnectionPointImpl *Obj; + HRESULT hr; + + Obj = ConnectionPointImpl_Construct(pUnk, riid); + if(!Obj) return E_OUTOFMEMORY; + + hr = IConnectionPoint_QueryInterface((IConnectionPoint *)Obj, + &IID_IConnectionPoint, (LPVOID)pCP); + IConnectionPoint_Release((IConnectionPoint *)Obj); + return hr; +} diff --git a/reactos/lib/oleaut32/connpt.h b/reactos/lib/oleaut32/connpt.h index 307e17d6ea3..b8fbb3a46d9 100644 --- a/reactos/lib/oleaut32/connpt.h +++ b/reactos/lib/oleaut32/connpt.h @@ -1,24 +1,24 @@ -/* - * Copyright 2000 Huw D M Davies for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _CONNPT_H -#define _CONNPT_H - -HRESULT CreateConnectionPoint(IUnknown *pUnk, REFIID riid, IConnectionPoint **pCP); - -#endif /* _CONNPT_H */ +/* + * Copyright 2000 Huw D M Davies for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _CONNPT_H +#define _CONNPT_H + +HRESULT CreateConnectionPoint(IUnknown *pUnk, REFIID riid, IConnectionPoint **pCP); + +#endif /* _CONNPT_H */ diff --git a/reactos/lib/oleaut32/cursoricon.h b/reactos/lib/oleaut32/cursoricon.h index 62f053cd997..78fc63140cc 100644 --- a/reactos/lib/oleaut32/cursoricon.h +++ b/reactos/lib/oleaut32/cursoricon.h @@ -1,89 +1,89 @@ -/* - * Cursor and icon definitions - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_CURSORICON_H -#define __WINE_CURSORICON_H - -#include <windef.h> - -#include <pshpack1.h> - -typedef struct -{ - BYTE bWidth; - BYTE bHeight; - BYTE bColorCount; - BYTE bReserved; -} ICONRESDIR; - -typedef struct -{ - WORD wWidth; - WORD wHeight; -} CURSORDIR; - -typedef struct -{ union - { ICONRESDIR icon; - CURSORDIR cursor; - } ResInfo; - WORD wPlanes; - WORD wBitCount; - DWORD dwBytesInRes; - WORD wResId; -} CURSORICONDIRENTRY; - -typedef struct -{ - WORD idReserved; - WORD idType; - WORD idCount; - CURSORICONDIRENTRY idEntries[1]; -} CURSORICONDIR; - -typedef struct { - BYTE bWidth; - BYTE bHeight; - BYTE bColorCount; - BYTE bReserved; - WORD xHotspot; - WORD yHotspot; - DWORD dwDIBSize; - DWORD dwDIBOffset; -} CURSORICONFILEDIRENTRY; - -typedef struct -{ - WORD idReserved; - WORD idType; - WORD idCount; - CURSORICONFILEDIRENTRY idEntries[1]; -} CURSORICONFILEDIR; - - -#include <poppack.h> - -#define CID_RESOURCE 0x0001 -#define CID_WIN32 0x0004 -#define CID_NONSHARED 0x0008 - -extern void CURSORICON_FreeModuleIcons( HMODULE16 hModule ); - -#endif /* __WINE_CURSORICON_H */ +/* + * Cursor and icon definitions + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_CURSORICON_H +#define __WINE_CURSORICON_H + +#include <windef.h> + +#include <pshpack1.h> + +typedef struct +{ + BYTE bWidth; + BYTE bHeight; + BYTE bColorCount; + BYTE bReserved; +} ICONRESDIR; + +typedef struct +{ + WORD wWidth; + WORD wHeight; +} CURSORDIR; + +typedef struct +{ union + { ICONRESDIR icon; + CURSORDIR cursor; + } ResInfo; + WORD wPlanes; + WORD wBitCount; + DWORD dwBytesInRes; + WORD wResId; +} CURSORICONDIRENTRY; + +typedef struct +{ + WORD idReserved; + WORD idType; + WORD idCount; + CURSORICONDIRENTRY idEntries[1]; +} CURSORICONDIR; + +typedef struct { + BYTE bWidth; + BYTE bHeight; + BYTE bColorCount; + BYTE bReserved; + WORD xHotspot; + WORD yHotspot; + DWORD dwDIBSize; + DWORD dwDIBOffset; +} CURSORICONFILEDIRENTRY; + +typedef struct +{ + WORD idReserved; + WORD idType; + WORD idCount; + CURSORICONFILEDIRENTRY idEntries[1]; +} CURSORICONFILEDIR; + + +#include <poppack.h> + +#define CID_RESOURCE 0x0001 +#define CID_WIN32 0x0004 +#define CID_NONSHARED 0x0008 + +extern void CURSORICON_FreeModuleIcons( HMODULE16 hModule ); + +#endif /* __WINE_CURSORICON_H */ diff --git a/reactos/lib/oleaut32/dispatch.c b/reactos/lib/oleaut32/dispatch.c index 66bed47500e..37514b303a1 100644 --- a/reactos/lib/oleaut32/dispatch.c +++ b/reactos/lib/oleaut32/dispatch.c @@ -1,457 +1,457 @@ -/** - * Dispatch API functions - * - * Copyright 2000 Francois Jacques, Macadamian Technologies Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * TODO: Type coercion is implemented in variant.c but not called yet. - */ - -#include "config.h" - -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <stdio.h> -#include <ctype.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "objbase.h" -#include "oleauto.h" -#include "winerror.h" -#include "winreg.h" -#include "winnls.h" /* for PRIMARYLANGID */ - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); -WINE_DECLARE_DEBUG_CHANNEL(typelib); - -static IDispatch * WINAPI StdDispatch_Construct(IUnknown * punkOuter, void * pvThis, ITypeInfo * pTypeInfo); - -/****************************************************************************** - * DispInvoke (OLEAUT32.30) - * - * Call an object method using the information from its type library. - * - * RETURNS - * Success: S_OK. - * Failure: Returns DISP_E_EXCEPTION and updates pexcepinfo if an exception occurs. - * DISP_E_BADPARAMCOUNT if the number of parameters is incorrect. - * DISP_E_MEMBERNOTFOUND if the method does not exist. - * puArgErr is updated if a parameter error (see notes) occurs. - * Otherwise, returns the result of calling ITypeInfo_Invoke(). - * - * NOTES - * Parameter errors include the following: - *| DISP_E_BADVARTYPE - *| E_INVALIDARG An argument was invalid - *| DISP_E_TYPEMISMATCH, - *| DISP_E_OVERFLOW An argument was valid but could not be coerced - *| DISP_E_PARAMNOTOPTIONAL A non optional parameter was not passed - *| DISP_E_PARAMNOTFOUND A parameter was passed that was not expected by the method - * This call defers to ITypeInfo_Invoke(). - */ -HRESULT WINAPI DispInvoke( - VOID *_this, /* [in] Object to call method on */ - ITypeInfo *ptinfo, /* [in] Object type info */ - DISPID dispidMember, /* [in] DISPID of the member (e.g. from GetIDsOfNames()) */ - USHORT wFlags, /* [in] Kind of method call (DISPATCH_ flags from "oaidl.h") */ - DISPPARAMS *pparams, /* [in] Array of method arguments */ - VARIANT *pvarResult, /* [out] Destination for the result of the call */ - EXCEPINFO *pexcepinfo, /* [out] Destination for exception information */ - UINT *puArgErr) /* [out] Destination for bad argument */ -{ - /** - * TODO: - * For each param, call DispGetParam to perform type coercion - */ - FIXME("Coercion of arguments not implemented\n"); - - return ITypeInfo_Invoke(ptinfo, _this, dispidMember, wFlags, - pparams, pvarResult, pexcepinfo, puArgErr); -} - -/****************************************************************************** - * DispGetIDsOfNames (OLEAUT32.29) - * - * Convert a set of parameter names to DISPID's for DispInvoke(). - * - * RETURNS - * Success: S_OK. - * Failure: An HRESULT error code. - * - * NOTES - * This call defers to ITypeInfo_GetIDsOfNames(). The ITypeInfo interface passed - * as ptinfo contains the information to map names to DISPID's. - */ -HRESULT WINAPI DispGetIDsOfNames( - ITypeInfo *ptinfo, /* [in] Object's type info */ - OLECHAR **rgszNames, /* [in] Array of names to get DISPID's for */ - UINT cNames, /* [in] Number of names in rgszNames */ - DISPID *rgdispid) /* [out] Destination for converted DISPID's */ -{ - return ITypeInfo_GetIDsOfNames(ptinfo, rgszNames, cNames, rgdispid); -} - -/****************************************************************************** - * DispGetParam (OLEAUT32.28) - * - * Retrive a parameter from a DISPPARAMS structure and coerce it to the - * specified variant type. - * - * NOTES - * Coercion is done using system (0) locale. - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_PARAMNOTFOUND, if position is invalid. or - * DISP_E_TYPEMISMATCH, if the coercion failed. puArgErr is - * set to the index of the argument in pdispparams. - */ -HRESULT WINAPI DispGetParam( - DISPPARAMS *pdispparams, /* [in] Parameter list */ - UINT position, /* [in] Position of parameter to coerce in pdispparams */ - VARTYPE vtTarg, /* [in] Type of value to coerce to */ - VARIANT *pvarResult, /* [out] Destination for resulting variant */ - UINT *puArgErr) /* [out] Destination for error code */ -{ - /* position is counted backwards */ - UINT pos; - HRESULT hr; - - TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n", - position, pdispparams->cArgs, pdispparams->cNamedArgs); - if (position < pdispparams->cArgs) { - /* positional arg? */ - pos = pdispparams->cArgs - position - 1; - } else { - /* FIXME: is this how to handle named args? */ - for (pos=0; pos<pdispparams->cNamedArgs; pos++) - if (pdispparams->rgdispidNamedArgs[pos] == position) break; - - if (pos==pdispparams->cNamedArgs) - return DISP_E_PARAMNOTFOUND; - } - hr = VariantChangeType(pvarResult, - &pdispparams->rgvarg[pos], - 0, vtTarg); - if (hr == DISP_E_TYPEMISMATCH) *puArgErr = pos; - return hr; -} - -/****************************************************************************** - * CreateStdDispatch [OLEAUT32.32] - * - * Create and return a standard IDispatch object. - * - * RETURNS - * Success: S_OK. ppunkStdDisp contains the new object. - * Failure: An HRESULT error code. - * - * NOTES - * Outer unknown appears to be completely ignored. - */ -HRESULT WINAPI CreateStdDispatch( - IUnknown* punkOuter, - void* pvThis, - ITypeInfo* ptinfo, - IUnknown** ppunkStdDisp) -{ - TRACE("(%p, %p, %p, %p)\n", punkOuter, pvThis, ptinfo, ppunkStdDisp); - - *ppunkStdDisp = (LPUNKNOWN)StdDispatch_Construct(punkOuter, pvThis, ptinfo); - if (!*ppunkStdDisp) - return E_OUTOFMEMORY; - return S_OK; -} - - -/****************************************************************************** - * IDispatch {OLEAUT32} - * - * NOTES - * The IDispatch interface provides a single interface to dispatch method calls, - * regardless of whether the object to be called is in or out of process, - * local or remote (e.g. being called over a network). This interface is late-bound - * (linked at run-time), as opposed to early-bound (linked at compile time). - * - * The interface is used by objects that wish to called by scripting - * languages such as VBA, in order to minimise the amount of COM and C/C++ - * knowledge required, or by objects that wish to live out of process from code - * that will call their methods. - * - * Method, property and parameter names can be localised. The details required to - * map names to methods and parameters are collected in a type library, usually - * output by an IDL compiler using the objects IDL description. This information is - * accessible programatically through the ITypeLib interface (for a type library), - * and the ITypeInfo interface (for an object within the type library). Type information - * can also be created at run-time using CreateDispTypeInfo(). - * - * WRAPPERS - * Instead of using IDispatch directly, there are several wrapper functions available - * to simplify the process of calling an objects methods through IDispatch. - * - * A standard implementation of an IDispatch object is created by calling - * CreateStdDispatch(). Numeric Id values for the parameters and methods (DISPID's) - * of an object of interest are retrieved by calling DispGetIDsOfNames(). DispGetParam() - * retrieves information about a particular parameter. Finally the DispInvoke() - * function is responsable for actually calling methods on an object. - * - * METHODS - */ - -typedef struct -{ - IDispatchVtbl *lpVtbl; - void * pvThis; - ITypeInfo * pTypeInfo; - ULONG ref; -} StdDispatch; - -/****************************************************************************** - * IDispatch_QueryInterface {OLEAUT32} - * - * See IUnknown_QueryInterface. - */ -static HRESULT WINAPI StdDispatch_QueryInterface( - LPDISPATCH iface, - REFIID riid, - void** ppvObject) -{ - StdDispatch *This = (StdDispatch *)iface; - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject); - - if (IsEqualIID(riid, &IID_IDispatch) || - IsEqualIID(riid, &IID_IUnknown)) - { - *ppvObject = (LPVOID)This; - IUnknown_AddRef((LPUNKNOWN)*ppvObject); - return S_OK; - } - return E_NOINTERFACE; -} - -/****************************************************************************** - * IDispatch_AddRef {OLEAUT32} - * - * See IUnknown_AddRef. - */ -static ULONG WINAPI StdDispatch_AddRef(LPDISPATCH iface) -{ - StdDispatch *This = (StdDispatch *)iface; - ULONG refCount = InterlockedIncrement(&This->ref); - - TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1); - - return refCount; -} - -/****************************************************************************** - * IDispatch_Release {OLEAUT32} - * - * See IUnknown_Release. - */ -static ULONG WINAPI StdDispatch_Release(LPDISPATCH iface) -{ - StdDispatch *This = (StdDispatch *)iface; - ULONG refCount = InterlockedDecrement(&This->ref); - - TRACE("(%p)->(ref before=%lu)\n", This, refCount + 1); - - if (!refCount) - { - ITypeInfo_Release(This->pTypeInfo); - CoTaskMemFree(This); - } - - return refCount; -} - -/****************************************************************************** - * IDispatch_GetTypeInfoCount {OLEAUT32} - * - * Get the count of type information in an IDispatch interface. - * - * PARAMS - * iface [I] IDispatch interface - * pctinfo [O] Destination for the count - * - * RETURNS - * Success: S_OK. pctinfo is updated with the count. This is always 1 if - * the object provides type information, and 0 if it does not. - * Failure: E_NOTIMPL. The object does not provide type information. - * - * NOTES - * See IDispatch() and IDispatch_GetTypeInfo(). - */ -static HRESULT WINAPI StdDispatch_GetTypeInfoCount(LPDISPATCH iface, UINT * pctinfo) -{ - StdDispatch *This = (StdDispatch *)iface; - TRACE("(%p)\n", pctinfo); - - *pctinfo = This->pTypeInfo ? 1 : 0; - return S_OK; -} - -/****************************************************************************** - * IDispatch_GetTypeInfo {OLEAUT32} - * - * Get type information from an IDispatch interface. - * - * PARAMS - * iface [I] IDispatch interface - * iTInfo [I] Index of type information. - * lcid [I] Locale of the type information to get - * ppTInfo [O] Destination for the ITypeInfo object - * - * RETURNS - * Success: S_OK. ppTInfo is updated with the objects type information - * Failure: DISP_E_BADINDEX, if iTInfo is any value other than 0. - * - * NOTES - * See IDispatch. - */ -static HRESULT WINAPI StdDispatch_GetTypeInfo(LPDISPATCH iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) -{ - StdDispatch *This = (StdDispatch *)iface; - TRACE("(%d, %lx, %p)\n", iTInfo, lcid, ppTInfo); - - *ppTInfo = NULL; - if (iTInfo != 0) - return DISP_E_BADINDEX; - - if (This->pTypeInfo) - { - *ppTInfo = This->pTypeInfo; - ITypeInfo_AddRef(*ppTInfo); - } - return S_OK; -} - -/****************************************************************************** - * IDispatch_GetIDsOfNames {OLEAUT32} - * - * Convert a methods name and an optional set of parameter names into DISPID's - * for passing to IDispatch_Invoke(). - * - * PARAMS - * iface [I] IDispatch interface - * riid [I] Reserved, set to IID_NULL - * rgszNames [I] Name to convert - * cNames [I] Number of names in rgszNames - * lcid [I] Locale of the type information to convert from - * rgDispId [O] Destination for converted DISPID's. - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_UNKNOWNNAME, if any of the names is invalid. - * DISP_E_UNKNOWNLCID if lcid is invalid. - * Otherwise, an An HRESULT error code. - * - * NOTES - * This call defers to ITypeInfo_GetIDsOfNames(), using the ITypeInfo object - * contained within the IDispatch object. - * The first member of the names list must be a method name. The names following - * the method name are the parameters for that method. - */ -static HRESULT WINAPI StdDispatch_GetIDsOfNames(LPDISPATCH iface, REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgDispId) -{ - StdDispatch *This = (StdDispatch *)iface; - TRACE("(%s, %p, %d, 0x%lx, %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); - - if (!IsEqualGUID(riid, &IID_NULL)) - { - FIXME(" expected riid == IID_NULL\n"); - return E_INVALIDARG; - } - return DispGetIDsOfNames(This->pTypeInfo, rgszNames, cNames, rgDispId); -} - -/****************************************************************************** - * IDispatch_Invoke {OLEAUT32} - * - * Call an object method. - * - * PARAMS - * iface [I] IDispatch interface - * dispIdMember [I] DISPID of the method (from GetIDsOfNames()) - * riid [I] Reserved, set to IID_NULL - * lcid [I] Locale of the type information to convert parameters with - * wFlags, [I] Kind of method call (DISPATCH_ flags from "oaidl.h") - * pDispParams [I] Array of method arguments - * pVarResult [O] Destination for the result of the call - * pExcepInfo [O] Destination for exception information - * puArgErr [O] Destination for bad argument - * - * RETURNS - * Success: S_OK. - * Failure: See DispInvoke() for failure cases. - * - * NOTES - * See DispInvoke() and IDispatch(). - */ -static HRESULT WINAPI StdDispatch_Invoke(LPDISPATCH iface, DISPID dispIdMember, REFIID riid, LCID lcid, - WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult, - EXCEPINFO * pExcepInfo, UINT * puArgErr) -{ - StdDispatch *This = (StdDispatch *)iface; - TRACE("(%ld, %s, 0x%lx, 0x%x, %p, %p, %p, %p)\n", dispIdMember, debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); - - if (!IsEqualGUID(riid, &IID_NULL)) - { - FIXME(" expected riid == IID_NULL\n"); - return E_INVALIDARG; - } - return DispInvoke(This->pvThis, This->pTypeInfo, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); -} - -static IDispatchVtbl StdDispatch_VTable = -{ - StdDispatch_QueryInterface, - StdDispatch_AddRef, - StdDispatch_Release, - StdDispatch_GetTypeInfoCount, - StdDispatch_GetTypeInfo, - StdDispatch_GetIDsOfNames, - StdDispatch_Invoke -}; - -static IDispatch * WINAPI StdDispatch_Construct( - IUnknown * punkOuter, - void * pvThis, - ITypeInfo * pTypeInfo) -{ - StdDispatch * pStdDispatch; - - pStdDispatch = CoTaskMemAlloc(sizeof(StdDispatch)); - if (!pStdDispatch) - return (IDispatch *)pStdDispatch; - - pStdDispatch->lpVtbl = &StdDispatch_VTable; - pStdDispatch->pvThis = pvThis; - pStdDispatch->pTypeInfo = pTypeInfo; - pStdDispatch->ref = 1; - - /* we keep a reference to the type info so prevent it from - * being destroyed until we are done with it */ - ITypeInfo_AddRef(pTypeInfo); - - return (IDispatch *)pStdDispatch; -} +/** + * Dispatch API functions + * + * Copyright 2000 Francois Jacques, Macadamian Technologies Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * TODO: Type coercion is implemented in variant.c but not called yet. + */ + +#include "config.h" + +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <stdio.h> +#include <ctype.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" +#include "oleauto.h" +#include "winerror.h" +#include "winreg.h" +#include "winnls.h" /* for PRIMARYLANGID */ + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); +WINE_DECLARE_DEBUG_CHANNEL(typelib); + +static IDispatch * WINAPI StdDispatch_Construct(IUnknown * punkOuter, void * pvThis, ITypeInfo * pTypeInfo); + +/****************************************************************************** + * DispInvoke (OLEAUT32.30) + * + * Call an object method using the information from its type library. + * + * RETURNS + * Success: S_OK. + * Failure: Returns DISP_E_EXCEPTION and updates pexcepinfo if an exception occurs. + * DISP_E_BADPARAMCOUNT if the number of parameters is incorrect. + * DISP_E_MEMBERNOTFOUND if the method does not exist. + * puArgErr is updated if a parameter error (see notes) occurs. + * Otherwise, returns the result of calling ITypeInfo_Invoke(). + * + * NOTES + * Parameter errors include the following: + *| DISP_E_BADVARTYPE + *| E_INVALIDARG An argument was invalid + *| DISP_E_TYPEMISMATCH, + *| DISP_E_OVERFLOW An argument was valid but could not be coerced + *| DISP_E_PARAMNOTOPTIONAL A non optional parameter was not passed + *| DISP_E_PARAMNOTFOUND A parameter was passed that was not expected by the method + * This call defers to ITypeInfo_Invoke(). + */ +HRESULT WINAPI DispInvoke( + VOID *_this, /* [in] Object to call method on */ + ITypeInfo *ptinfo, /* [in] Object type info */ + DISPID dispidMember, /* [in] DISPID of the member (e.g. from GetIDsOfNames()) */ + USHORT wFlags, /* [in] Kind of method call (DISPATCH_ flags from "oaidl.h") */ + DISPPARAMS *pparams, /* [in] Array of method arguments */ + VARIANT *pvarResult, /* [out] Destination for the result of the call */ + EXCEPINFO *pexcepinfo, /* [out] Destination for exception information */ + UINT *puArgErr) /* [out] Destination for bad argument */ +{ + /** + * TODO: + * For each param, call DispGetParam to perform type coercion + */ + FIXME("Coercion of arguments not implemented\n"); + + return ITypeInfo_Invoke(ptinfo, _this, dispidMember, wFlags, + pparams, pvarResult, pexcepinfo, puArgErr); +} + +/****************************************************************************** + * DispGetIDsOfNames (OLEAUT32.29) + * + * Convert a set of parameter names to DISPID's for DispInvoke(). + * + * RETURNS + * Success: S_OK. + * Failure: An HRESULT error code. + * + * NOTES + * This call defers to ITypeInfo_GetIDsOfNames(). The ITypeInfo interface passed + * as ptinfo contains the information to map names to DISPID's. + */ +HRESULT WINAPI DispGetIDsOfNames( + ITypeInfo *ptinfo, /* [in] Object's type info */ + OLECHAR **rgszNames, /* [in] Array of names to get DISPID's for */ + UINT cNames, /* [in] Number of names in rgszNames */ + DISPID *rgdispid) /* [out] Destination for converted DISPID's */ +{ + return ITypeInfo_GetIDsOfNames(ptinfo, rgszNames, cNames, rgdispid); +} + +/****************************************************************************** + * DispGetParam (OLEAUT32.28) + * + * Retrive a parameter from a DISPPARAMS structure and coerce it to the + * specified variant type. + * + * NOTES + * Coercion is done using system (0) locale. + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_PARAMNOTFOUND, if position is invalid. or + * DISP_E_TYPEMISMATCH, if the coercion failed. puArgErr is + * set to the index of the argument in pdispparams. + */ +HRESULT WINAPI DispGetParam( + DISPPARAMS *pdispparams, /* [in] Parameter list */ + UINT position, /* [in] Position of parameter to coerce in pdispparams */ + VARTYPE vtTarg, /* [in] Type of value to coerce to */ + VARIANT *pvarResult, /* [out] Destination for resulting variant */ + UINT *puArgErr) /* [out] Destination for error code */ +{ + /* position is counted backwards */ + UINT pos; + HRESULT hr; + + TRACE("position=%d, cArgs=%d, cNamedArgs=%d\n", + position, pdispparams->cArgs, pdispparams->cNamedArgs); + if (position < pdispparams->cArgs) { + /* positional arg? */ + pos = pdispparams->cArgs - position - 1; + } else { + /* FIXME: is this how to handle named args? */ + for (pos=0; pos<pdispparams->cNamedArgs; pos++) + if (pdispparams->rgdispidNamedArgs[pos] == position) break; + + if (pos==pdispparams->cNamedArgs) + return DISP_E_PARAMNOTFOUND; + } + hr = VariantChangeType(pvarResult, + &pdispparams->rgvarg[pos], + 0, vtTarg); + if (hr == DISP_E_TYPEMISMATCH) *puArgErr = pos; + return hr; +} + +/****************************************************************************** + * CreateStdDispatch [OLEAUT32.32] + * + * Create and return a standard IDispatch object. + * + * RETURNS + * Success: S_OK. ppunkStdDisp contains the new object. + * Failure: An HRESULT error code. + * + * NOTES + * Outer unknown appears to be completely ignored. + */ +HRESULT WINAPI CreateStdDispatch( + IUnknown* punkOuter, + void* pvThis, + ITypeInfo* ptinfo, + IUnknown** ppunkStdDisp) +{ + TRACE("(%p, %p, %p, %p)\n", punkOuter, pvThis, ptinfo, ppunkStdDisp); + + *ppunkStdDisp = (LPUNKNOWN)StdDispatch_Construct(punkOuter, pvThis, ptinfo); + if (!*ppunkStdDisp) + return E_OUTOFMEMORY; + return S_OK; +} + + +/****************************************************************************** + * IDispatch {OLEAUT32} + * + * NOTES + * The IDispatch interface provides a single interface to dispatch method calls, + * regardless of whether the object to be called is in or out of process, + * local or remote (e.g. being called over a network). This interface is late-bound + * (linked at run-time), as opposed to early-bound (linked at compile time). + * + * The interface is used by objects that wish to called by scripting + * languages such as VBA, in order to minimise the amount of COM and C/C++ + * knowledge required, or by objects that wish to live out of process from code + * that will call their methods. + * + * Method, property and parameter names can be localised. The details required to + * map names to methods and parameters are collected in a type library, usually + * output by an IDL compiler using the objects IDL description. This information is + * accessible programatically through the ITypeLib interface (for a type library), + * and the ITypeInfo interface (for an object within the type library). Type information + * can also be created at run-time using CreateDispTypeInfo(). + * + * WRAPPERS + * Instead of using IDispatch directly, there are several wrapper functions available + * to simplify the process of calling an objects methods through IDispatch. + * + * A standard implementation of an IDispatch object is created by calling + * CreateStdDispatch(). Numeric Id values for the parameters and methods (DISPID's) + * of an object of interest are retrieved by calling DispGetIDsOfNames(). DispGetParam() + * retrieves information about a particular parameter. Finally the DispInvoke() + * function is responsable for actually calling methods on an object. + * + * METHODS + */ + +typedef struct +{ + IDispatchVtbl *lpVtbl; + void * pvThis; + ITypeInfo * pTypeInfo; + ULONG ref; +} StdDispatch; + +/****************************************************************************** + * IDispatch_QueryInterface {OLEAUT32} + * + * See IUnknown_QueryInterface. + */ +static HRESULT WINAPI StdDispatch_QueryInterface( + LPDISPATCH iface, + REFIID riid, + void** ppvObject) +{ + StdDispatch *This = (StdDispatch *)iface; + TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject); + + if (IsEqualIID(riid, &IID_IDispatch) || + IsEqualIID(riid, &IID_IUnknown)) + { + *ppvObject = (LPVOID)This; + IUnknown_AddRef((LPUNKNOWN)*ppvObject); + return S_OK; + } + return E_NOINTERFACE; +} + +/****************************************************************************** + * IDispatch_AddRef {OLEAUT32} + * + * See IUnknown_AddRef. + */ +static ULONG WINAPI StdDispatch_AddRef(LPDISPATCH iface) +{ + StdDispatch *This = (StdDispatch *)iface; + ULONG refCount = InterlockedIncrement(&This->ref); + + TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1); + + return refCount; +} + +/****************************************************************************** + * IDispatch_Release {OLEAUT32} + * + * See IUnknown_Release. + */ +static ULONG WINAPI StdDispatch_Release(LPDISPATCH iface) +{ + StdDispatch *This = (StdDispatch *)iface; + ULONG refCount = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(ref before=%lu)\n", This, refCount + 1); + + if (!refCount) + { + ITypeInfo_Release(This->pTypeInfo); + CoTaskMemFree(This); + } + + return refCount; +} + +/****************************************************************************** + * IDispatch_GetTypeInfoCount {OLEAUT32} + * + * Get the count of type information in an IDispatch interface. + * + * PARAMS + * iface [I] IDispatch interface + * pctinfo [O] Destination for the count + * + * RETURNS + * Success: S_OK. pctinfo is updated with the count. This is always 1 if + * the object provides type information, and 0 if it does not. + * Failure: E_NOTIMPL. The object does not provide type information. + * + * NOTES + * See IDispatch() and IDispatch_GetTypeInfo(). + */ +static HRESULT WINAPI StdDispatch_GetTypeInfoCount(LPDISPATCH iface, UINT * pctinfo) +{ + StdDispatch *This = (StdDispatch *)iface; + TRACE("(%p)\n", pctinfo); + + *pctinfo = This->pTypeInfo ? 1 : 0; + return S_OK; +} + +/****************************************************************************** + * IDispatch_GetTypeInfo {OLEAUT32} + * + * Get type information from an IDispatch interface. + * + * PARAMS + * iface [I] IDispatch interface + * iTInfo [I] Index of type information. + * lcid [I] Locale of the type information to get + * ppTInfo [O] Destination for the ITypeInfo object + * + * RETURNS + * Success: S_OK. ppTInfo is updated with the objects type information + * Failure: DISP_E_BADINDEX, if iTInfo is any value other than 0. + * + * NOTES + * See IDispatch. + */ +static HRESULT WINAPI StdDispatch_GetTypeInfo(LPDISPATCH iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) +{ + StdDispatch *This = (StdDispatch *)iface; + TRACE("(%d, %lx, %p)\n", iTInfo, lcid, ppTInfo); + + *ppTInfo = NULL; + if (iTInfo != 0) + return DISP_E_BADINDEX; + + if (This->pTypeInfo) + { + *ppTInfo = This->pTypeInfo; + ITypeInfo_AddRef(*ppTInfo); + } + return S_OK; +} + +/****************************************************************************** + * IDispatch_GetIDsOfNames {OLEAUT32} + * + * Convert a methods name and an optional set of parameter names into DISPID's + * for passing to IDispatch_Invoke(). + * + * PARAMS + * iface [I] IDispatch interface + * riid [I] Reserved, set to IID_NULL + * rgszNames [I] Name to convert + * cNames [I] Number of names in rgszNames + * lcid [I] Locale of the type information to convert from + * rgDispId [O] Destination for converted DISPID's. + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_UNKNOWNNAME, if any of the names is invalid. + * DISP_E_UNKNOWNLCID if lcid is invalid. + * Otherwise, an An HRESULT error code. + * + * NOTES + * This call defers to ITypeInfo_GetIDsOfNames(), using the ITypeInfo object + * contained within the IDispatch object. + * The first member of the names list must be a method name. The names following + * the method name are the parameters for that method. + */ +static HRESULT WINAPI StdDispatch_GetIDsOfNames(LPDISPATCH iface, REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgDispId) +{ + StdDispatch *This = (StdDispatch *)iface; + TRACE("(%s, %p, %d, 0x%lx, %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId); + + if (!IsEqualGUID(riid, &IID_NULL)) + { + FIXME(" expected riid == IID_NULL\n"); + return E_INVALIDARG; + } + return DispGetIDsOfNames(This->pTypeInfo, rgszNames, cNames, rgDispId); +} + +/****************************************************************************** + * IDispatch_Invoke {OLEAUT32} + * + * Call an object method. + * + * PARAMS + * iface [I] IDispatch interface + * dispIdMember [I] DISPID of the method (from GetIDsOfNames()) + * riid [I] Reserved, set to IID_NULL + * lcid [I] Locale of the type information to convert parameters with + * wFlags, [I] Kind of method call (DISPATCH_ flags from "oaidl.h") + * pDispParams [I] Array of method arguments + * pVarResult [O] Destination for the result of the call + * pExcepInfo [O] Destination for exception information + * puArgErr [O] Destination for bad argument + * + * RETURNS + * Success: S_OK. + * Failure: See DispInvoke() for failure cases. + * + * NOTES + * See DispInvoke() and IDispatch(). + */ +static HRESULT WINAPI StdDispatch_Invoke(LPDISPATCH iface, DISPID dispIdMember, REFIID riid, LCID lcid, + WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult, + EXCEPINFO * pExcepInfo, UINT * puArgErr) +{ + StdDispatch *This = (StdDispatch *)iface; + TRACE("(%ld, %s, 0x%lx, 0x%x, %p, %p, %p, %p)\n", dispIdMember, debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); + + if (!IsEqualGUID(riid, &IID_NULL)) + { + FIXME(" expected riid == IID_NULL\n"); + return E_INVALIDARG; + } + return DispInvoke(This->pvThis, This->pTypeInfo, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static IDispatchVtbl StdDispatch_VTable = +{ + StdDispatch_QueryInterface, + StdDispatch_AddRef, + StdDispatch_Release, + StdDispatch_GetTypeInfoCount, + StdDispatch_GetTypeInfo, + StdDispatch_GetIDsOfNames, + StdDispatch_Invoke +}; + +static IDispatch * WINAPI StdDispatch_Construct( + IUnknown * punkOuter, + void * pvThis, + ITypeInfo * pTypeInfo) +{ + StdDispatch * pStdDispatch; + + pStdDispatch = CoTaskMemAlloc(sizeof(StdDispatch)); + if (!pStdDispatch) + return (IDispatch *)pStdDispatch; + + pStdDispatch->lpVtbl = &StdDispatch_VTable; + pStdDispatch->pvThis = pvThis; + pStdDispatch->pTypeInfo = pTypeInfo; + pStdDispatch->ref = 1; + + /* we keep a reference to the type info so prevent it from + * being destroyed until we are done with it */ + ITypeInfo_AddRef(pTypeInfo); + + return (IDispatch *)pStdDispatch; +} diff --git a/reactos/lib/oleaut32/hash.c b/reactos/lib/oleaut32/hash.c index fa6fb544b22..ce2f0e41232 100644 --- a/reactos/lib/oleaut32/hash.c +++ b/reactos/lib/oleaut32/hash.c @@ -1,644 +1,644 @@ -/* - * Oleaut32 hash functions - * - * Copyright 1999 Corel Corporation - * Copyright 2001-2003 Jon Griffiths - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "objbase.h" -#include "oaidl.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -static const unsigned char Lookup_16[128 * 3] = { - /* Common */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, - 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, - 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, - 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x00, 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, - 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, - 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, - 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, - 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, - - /* Windows */ - 0x7F, 0x7F, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x7F, 0x89, 0x53, 0x8B, 0x8C, - 0x7F, 0x7F, 0x7F, 0x7F, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x96, 0x98, 0x99, - 0x53, 0x9B, 0x8C, 0x7F, 0x7F, 0x55, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x96, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, - 0x49, 0x49, 0x44, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0xD7, 0x4F, 0x55, 0x55, - 0x55, 0x55, 0x55, 0xDE, 0xDF, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43, - 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x44, 0x4E, 0x4F, 0x4F, 0x4F, - 0x4F, 0x4F, 0xF7, 0x4F, 0x55, 0x55, 0x55, 0x55, 0x55, 0xDE, 0x55, - - /* Mac */ - 0x41, 0x41, 0x43, 0x45, 0x4E, 0x4F, 0x55, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x4E, 0x4F, 0x4F, 0x4F, - 0x4F, 0x4F, 0x55, 0x55, 0x55, 0x55, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0x41, 0x4F, 0xB0, 0xB1, 0xB2, 0xB3, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0x41, 0x4F, 0xBD, 0x41, 0x4F, 0xC0, - 0xC1, 0xC2, 0xC3, 0x46, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0x41, 0x41, 0x4F, - 0xCE, 0xCE, 0xD0, 0xD0, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0x55, 0x55, 0xDA, - 0xDB, 0xDC, 0xDD, 0x3F, 0x3F, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0x41, 0x45, 0x41, - 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x4F, 0x4F, 0x3F, 0x4F, 0x55, 0x55, 0x55, - 0x49, 0x7F, 0xF7, 0x7F, 0xF9, 0xFA, 0xFB, 0x3F, 0xFD, 0xFE, 0x7F -}; - -static const unsigned char Lookup_32[128 * 3] = { - /* Common */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, - 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, - 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, - 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x00, 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, - 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, - 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, - 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, - 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, - - /* Windows */ - 0x7F, 0x7F, 0x82, 0x7F, 0x84, 0x85, 0x86, 0x87, 0x7F, 0x89, 0x53, 0x8B, 0x53, - 0x54, 0x5A, 0x5A, 0x7F, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x96, 0x7F, 0x99, - 0x53, 0x9B, 0x53, 0x54, 0x5A, 0x5A, 0xA0, 0x7F, 0xA2, 0x4C, 0xA4, 0x41, 0xA6, - 0xA7, 0xA8, 0xA9, 0x53, 0xAB, 0xAC, 0x96, 0xAE, 0x5A, 0xB0, 0xB1, 0xB2, 0x4C, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x41, 0x53, 0xBB, 0x4C, 0xBD, 0x4C, 0x5A, 0x52, - 0x41, 0x41, 0x41, 0x41, 0x4C, 0x43, 0x43, 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, - 0x49, 0x44, 0xD0, 0x4E, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0xD7, 0x52, 0x55, 0x55, - 0x55, 0x55, 0x59, 0x54, 0xDF, 0x52, 0x41, 0x41, 0x41, 0x41, 0x4C, 0x43, 0x43, - 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x44, 0xD0, 0x4E, 0x4E, 0x4F, 0x4F, - 0x4F, 0x4F, 0xF7, 0x52, 0x55, 0x55, 0x55, 0x55, 0x59, 0x54, 0xFF, - - /* Mac */ - 0x41, 0x41, 0x41, 0x45, 0x41, 0x4F, 0x55, 0x41, 0x41, 0x43, 0x41, 0x43, 0x43, - 0x43, 0x45, 0x5A, 0x5A, 0x44, 0x49, 0x44, 0x45, 0x45, 0x45, 0x4F, 0x45, 0x4F, - 0x4F, 0x4F, 0x55, 0x45, 0x45, 0x55, 0xA0, 0xA1, 0x45, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0xAA, 0x45, 0xAC, 0xAD, 0x47, 0x49, 0x49, 0x49, 0xB2, 0xB3, - 0x49, 0x4B, 0xB6, 0xB7, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4E, 0x4E, - 0x4E, 0xC2, 0xC3, 0x4E, 0x4E, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0x4E, 0x4F, 0x4F, - 0x4F, 0x4F, 0xD0, 0xD0, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0x4F, 0x52, 0x52, - 0x52, 0xDC, 0xDD, 0x52, 0x52, 0x52, 0x53, 0xE2, 0xE3, 0x53, 0x53, 0x53, 0x41, - 0x54, 0x54, 0x49, 0x5A, 0x5A, 0x55, 0x4F, 0x4F, 0x55, 0x55, 0x55, 0x55, 0x55, - 0x55, 0x55, 0x55, 0x59, 0x59, 0x4B, 0x5A, 0x4C, 0x4C, 0x47, 0xFF -}; - -static const unsigned char Lookup_48[128 * 3] = { - /* Common */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, - 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, - 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, - 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x00, 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, - 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, - 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, - 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, - 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, - - /* Windows */ - 0x7F, 0x7F, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x7F, 0x89, 0x53, 0x8B, 0x8C, - 0x7F, 0x7F, 0x7F, 0x7F, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x96, 0x98, 0x99, - 0x53, 0x9B, 0x8C, 0x7F, 0x7F, 0x59, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x96, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0xC6, 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, - 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0xD7, 0x4F, 0x55, 0x55, - 0x55, 0x55, 0x59, 0xDE, 0xDF, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0xC6, 0x43, - 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0x4F, 0x4F, - 0x4F, 0x4F, 0xF7, 0x4F, 0x55, 0x55, 0x55, 0x55, 0x59, 0xDE, 0x59, - - /* Mac */ - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, - 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, - 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAB, 0xAD, 0xAE, 0xAE, 0xB0, 0xB1, 0xB2, 0xB3, - 0xA7, 0xB5, 0xB6, 0xB7, 0xB8, 0xB8, 0xBA, 0xBA, 0xBC, 0xBC, 0xBE, 0xBE, 0xB7, - 0xC1, 0xC2, 0xC3, 0x46, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCB, 0xCD, - 0xCD, 0xC1, 0xD0, 0xD0, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD8, 0xDA, - 0xDA, 0xDC, 0xDD, 0xDD, 0x9F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, - 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F -}; - -static const unsigned char Lookup_64[128 * 3] = { - /* Common */ - 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, - 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, - 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x00, 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, - 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, - 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, - 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, - 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, - -/* Windows */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x96, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, - 0x49, 0x49, 0x44, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0xD7, 0x4F, 0x55, 0x55, - 0x55, 0x55, 0x55, 0xDE, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - /* Mac */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x96, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, - 0x49, 0x49, 0x44, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0xD7, 0x4F, 0x55, 0x55, - 0x55, 0x55, 0x55, 0xDE, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -static const unsigned char Lookup_80[128 * 3] = { - /* Common */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, - 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, - 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, - 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x00, 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, - 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, - 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, - 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, - 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, - -/* Windows */ - 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, - - /* Mac */ - 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, -}; - -static const unsigned char Lookup_112[128 * 3] = { - /* Common */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, - 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, - 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, - 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x00, 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, - 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, - 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, - 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, - 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, - -/* Windows */ - 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, - - /* Mac */ - 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, -}; - -static const unsigned char Lookup_128[128 * 3] = { - /* Common */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, - 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, - 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, - 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, - 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, - 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, - 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, - 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x00, - -/* Windows */ - 0x00, 0x00, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x00, 0x89, 0x00, 0x8B, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x2D, 0x2D, 0x00, 0x99, - 0x00, 0x9B, 0x00, 0x00, 0x00, 0x00, 0x09, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0x00, 0xAB, 0xAC, 0x2D, 0xAE, 0x2D, 0xB0, 0xB1, 0x32, 0x33, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xBA, - 0xA2, 0xC2, 0xC3, 0xC4, 0xB8, 0xC6, 0xB9, 0xC8, 0xBA, 0xCA, 0xCB, 0xCC, 0xCD, - 0xCE, 0xBC, 0xD0, 0xD1, 0x00, 0xD3, 0xD4, 0xBE, 0xD6, 0xD7, 0xD8, 0xBF, 0xBA, - 0xBE, 0xA2, 0xB8, 0xB9, 0xBA, 0xBE, 0xA2, 0xC2, 0xC3, 0xC4, 0xB8, 0xC6, 0xB9, - 0xC8, 0xBA, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xBC, 0xD0, 0xD1, 0xD3, 0xD3, 0xD4, - 0xBE, 0xD6, 0xD7, 0xD8, 0xBF, 0xBA, 0xBE, 0xBC, 0xBE, 0xBF, 0x00, - - /* Mac */ - 0x41, 0x31, 0x32, 0x45, 0x33, 0x4F, 0x55, 0x87, 0x41, 0x41, 0x41, 0x00, 0x8C, - 0x43, 0x45, 0x45, 0x45, 0x45, 0x92, 0x93, 0x49, 0x49, 0x96, 0x97, 0x98, 0x4F, - 0x4F, 0x9B, 0x3F, 0x55, 0x55, 0x55, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xAB, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xB0, - 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0x09, 0xBD, 0xCC, 0xB0, - 0xB6, 0xCF, 0x2D, 0x2D, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xB8, 0xAB, 0xC3, 0xBD, - 0xB6, 0xB8, 0xAB, 0xC3, 0xBF, 0xBD, 0xB0, 0xB5, 0xBE, 0xA2, 0xB6, 0xBC, 0xA1, - 0xB8, 0xAB, 0xA5, 0xBA, 0xA4, 0xBB, 0xC1, 0xC3, 0xA6, 0xBF, 0xC4, 0xAA, 0xC6, - 0xA3, 0xBF, 0xAA, 0xCC, 0xBD, 0xB7, 0xAB, 0xBD, 0xAB, 0xBD, 0x3F, -}; - -static const unsigned char Lookup_144[128 * 3] = { - /* Common */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, - 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, - 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, - 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, - 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, - 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, - 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, - 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x00, - -/* Windows */ - 0x00, 0x00, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x00, 0x89, 0x53, 0x8B, 0x8C, - 0x00, 0x00, 0x00, 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x2D, 0x2D, 0x98, 0x99, - 0x53, 0x9B, 0x8C, 0x00, 0x00, 0x59, 0x09, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x2D, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, - 0xC1, 0x41, 0x41, 0x41, 0x41, 0xC6, 0x43, 0x45, 0xC9, 0x45, 0x45, 0x49, 0xCD, - 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0xD3, 0x4F, 0x4F, 0xD6, 0xD7, 0xD6, 0x55, 0xDA, - 0x55, 0x55, 0xDD, 0xDE, 0xDF, 0x41, 0xC1, 0x41, 0x41, 0x41, 0x41, 0xC6, 0x43, - 0x45, 0xC9, 0x45, 0x45, 0x49, 0xCD, 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0xD3, 0x4F, - 0x4F, 0xD6, 0xF7, 0xD6, 0x55, 0xDA, 0x55, 0x55, 0xDD, 0xDE, 0x59, - - /* Mac */ - 0x00, 0x00, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x00, 0x89, 0x53, 0x8B, 0x8C, - 0x00, 0x00, 0x00, 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x2D, 0x2D, 0x98, 0x99, - 0x53, 0x9B, 0x8C, 0x00, 0x00, 0x59, 0x09, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x2D, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, - 0xC1, 0x41, 0x41, 0x41, 0x41, 0xC6, 0x43, 0x45, 0xC9, 0x45, 0x45, 0x49, 0xCD, - 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0xD3, 0x4F, 0x4F, 0xD6, 0xD7, 0xD6, 0x55, 0xDA, - 0x55, 0x55, 0xDD, 0xDE, 0xDF, 0x41, 0xC1, 0x41, 0x41, 0x41, 0x41, 0xC6, 0x43, - 0x45, 0xC9, 0x45, 0x45, 0x49, 0xCD, 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0xD3, 0x4F, - 0x4F, 0xD6, 0xF7, 0xD6, 0x55, 0xDA, 0x55, 0x55, 0xDD, 0xDE, 0x59, -}; - -static const unsigned char Lookup_160[128 * 3] = { - /* Common */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, - 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, - 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, - 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, - 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, - 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, - 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, - 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x00, - -/* Windows */ - 0x00, 0x00, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x00, 0x89, 0x53, 0x8B, 0x8C, - 0x00, 0x00, 0x00, 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x2D, 0x2D, 0x98, 0x99, - 0x53, 0x9B, 0x8C, 0x00, 0x00, 0x59, 0x09, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x2D, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0xC6, 0xC7, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, - 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0xD6, 0xD7, 0x4F, 0x55, 0x55, - 0x55, 0xDC, 0xDD, 0xDE, 0xDF, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0xC6, 0xC7, - 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0x4F, 0x4F, - 0x4F, 0xD6, 0xF7, 0x4F, 0x55, 0x55, 0x55, 0xDC, 0xDD, 0xDE, 0x59, - - /* Mac */ - 0x00, 0x00, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x00, 0x89, 0x53, 0x8B, 0x8C, - 0x00, 0x00, 0x00, 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x2D, 0x2D, 0x98, 0x99, - 0x53, 0x9B, 0x8C, 0x00, 0x00, 0x59, 0x09, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x2D, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0xC6, 0xC7, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, - 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0xD6, 0xD7, 0x4F, 0x55, 0x55, - 0x55, 0xDC, 0xDD, 0xDE, 0xDF, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0xC6, 0xC7, - 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0x4F, 0x4F, - 0x4F, 0xD6, 0xF7, 0x4F, 0x55, 0x55, 0x55, 0xDC, 0xDD, 0xDE, 0x59, -}; - -static const unsigned char Lookup_176[128 * 3] = { - /* Common */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, - 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, - 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, - 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, - 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, - 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, - 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, - 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x00, - - /* Windows */ - 0x00, 0x00, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x00, 0x89, 0x53, 0x8B, 0x8C, - 0x00, 0x00, 0x00, 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x2D, 0x2D, 0x98, 0x99, - 0x53, 0x9B, 0x8C, 0x00, 0x00, 0x59, 0x09, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x2D, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, - 0x41, 0x41, 0x41, 0xC4, 0xC5, 0xC4, 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, - 0x49, 0x49, 0x44, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0xD6, 0xD7, 0xD6, 0x55, 0x55, - 0x55, 0x59, 0x59, 0xDE, 0xDF, 0x41, 0x41, 0x41, 0x41, 0xC4, 0xC5, 0xC4, 0x43, - 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x44, 0x4E, 0x4F, 0x4F, 0x4F, - 0x4F, 0xD6, 0xF7, 0xD6, 0x55, 0x55, 0x55, 0x59, 0x59, 0xDE, 0x59, - - /* Mac */ - 0x80, 0x81, 0x43, 0x45, 0x4E, 0x85, 0x59, 0x41, 0x41, 0x41, 0x80, 0x41, 0x81, - 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x4E, 0x4F, 0x4F, 0x4F, - 0x85, 0x4F, 0x55, 0x55, 0x55, 0x59, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0x80, 0x85, 0xB0, 0xB1, 0xB2, 0xB3, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0x41, 0x4F, 0xBD, 0x80, 0x85, 0xC0, - 0xC1, 0xC2, 0xC3, 0x46, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0x09, 0x41, 0x41, 0x4F, - 0xCE, 0xCE, 0x2D, 0x2D, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0x59, 0x59, 0xDA, - 0xDB, 0xDC, 0xDD, 0x3F, 0x3F, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0x41, 0x45, 0x41, - 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x4F, 0x4F, 0x3F, 0x4F, 0x55, 0x55, 0x55, - 0x49, 0x00, 0xF7, 0x00, 0xF9, 0xFA, 0xFB, 0x3F, 0xFD, 0xFE, 0x00 -}; - -static const unsigned char Lookup_208[128 * 3] = { - /* Common */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, - 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, - 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, - 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, - 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, - 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, - 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, - 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, - -/* Windows */ - 0x80, 0x81, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x5E, 0x89, 0x8A, 0x8B, 0x8C, - 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, - 0x9A, 0x9B, 0x8C, 0x9D, 0x00, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, - 0xC1, 0xC2, 0xC1, 0xC1, 0xC1, 0xC1, 0xC7, 0xC8, 0xC9, 0xC9, 0xCB, 0xCC, 0xCD, - 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, - 0xDB, 0x00, 0xDD, 0xDE, 0xDF, 0x41, 0xE1, 0x41, 0xE3, 0xE4, 0xE5, 0xE6, 0x43, - 0x45, 0x45, 0x45, 0x45, 0xEC, 0xEC, 0x49, 0x49, 0xF0, 0xF1, 0xF2, 0xF3, 0x4F, - 0xF5, 0xF6, 0xF7, 0xF8, 0x55, 0xFA, 0x55, 0x55, 0x00, 0x00, 0xFF, - - /* Mac */ - 0x41, 0x81, 0x43, 0x45, 0x4E, 0x4F, 0x55, 0x41, 0x41, 0x41, 0x41, 0x8B, 0x8C, - 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x93, 0x49, 0x49, 0x4E, 0x4F, 0x98, 0x4F, - 0x4F, 0x9B, 0x55, 0x55, 0x55, 0x55, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, - 0xC1, 0xC2, 0xC1, 0xC1, 0xC1, 0xC1, 0xC7, 0xC8, 0xC9, 0xC9, 0xCB, 0xCC, 0xCD, - 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, - 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0x00, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, - 0xE8, 0xE9, 0xE9, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, - 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, -}; - -static const unsigned char Lookup_224[128 * 3] = { - /* Common */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, - 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, - 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, - 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, - 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, - 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, - 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, - 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, - -/* Windows */ - 0x80, 0x81, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x5E, 0x89, 0x8A, 0x8B, 0x8C, - 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, - 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, - 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, - 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, - 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, - 0xE8, 0xE9, 0xEA, 0xEA, 0xEC, 0xED, 0xED, 0xEF, 0xEF, 0xF1, 0xF2, 0xF3, 0xF3, - 0xF5, 0xF5, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0x00, 0x00, 0xFF, - - /* Mac */ - 0x41, 0x41, 0x43, 0x45, 0x4E, 0x4F, 0x55, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x4E, 0x4F, 0x4F, 0x4F, - 0x4F, 0x4F, 0x55, 0x55, 0x55, 0x55, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, - 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, - 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, - 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, - 0xE8, 0xE9, 0xEA, 0xEA, 0xEC, 0xED, 0xED, 0xEF, 0xEF, 0xF1, 0xF2, 0xF3, 0xF3, - 0xF5, 0xF5, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, -}; - -/*********************************************************************** - * LHashValOfNameSysA (OLEAUT32.166) - * - * Produce a string hash value. - * - * PARAMS - * skind [I] Type of the system. - * lcid [I] Locale id for the hash. - * lpStr [I] String to hash. - * - * RETURNS - * Success: The hash value of the string. - * Failure: 0, if lpStr is NULL. - * - * NOTES - * This function produces a two part hash: The high word is based on - * skind and lcid, while the low word is based on a repeated string - * hash of skind/str. - */ -ULONG WINAPI LHashValOfNameSysA( SYSKIND skind, LCID lcid, LPCSTR lpStr) -{ - ULONG nOffset, nMask = skind == SYS_MAC ? 1 : 0; - ULONG nHiWord, nLoWord = 0x0deadbee; - const unsigned char *str = (const unsigned char *)lpStr, *pnLookup = NULL; - - if (!str) - return 0; - - lcid = ConvertDefaultLocale(lcid); - - switch (PRIMARYLANGID(LANGIDFROMLCID(lcid))) - { - default: - ERR("Unknown lcid %lx, treating as latin-based, please report\n", lcid); - /* .. Fall Through .. */ - case LANG_AFRIKAANS: case LANG_ALBANIAN: case LANG_ARMENIAN: - case LANG_ASSAMESE: case LANG_AZERI: case LANG_BASQUE: - case LANG_BELARUSIAN: case LANG_BENGALI: case LANG_BULGARIAN: - case LANG_CATALAN: case LANG_DANISH: case LANG_DIVEHI: - case LANG_DUTCH: case LANG_ENGLISH: case LANG_ESTONIAN: - case LANG_FAEROESE: case LANG_FINNISH: case LANG_FRENCH: - case LANG_GALICIAN: case LANG_GEORGIAN: case LANG_GERMAN: - case LANG_GUJARATI: case LANG_HINDI: case LANG_INDONESIAN: - case LANG_ITALIAN: case LANG_KANNADA: case LANG_KASHMIRI: - case LANG_KAZAK: case LANG_KONKANI: case LANG_KYRGYZ: - case LANG_LATVIAN: case LANG_LITHUANIAN: case LANG_MACEDONIAN: - case LANG_MALAY: case LANG_MALAYALAM: case LANG_MANIPURI: - case LANG_MARATHI: case LANG_MONGOLIAN: case LANG_NEPALI: - case LANG_ORIYA: case LANG_PORTUGUESE: case LANG_PUNJABI: - case LANG_ROMANIAN: case LANG_SANSKRIT: case LANG_SERBIAN: - case LANG_SINDHI: case LANG_SLOVENIAN: case LANG_SWAHILI: - case LANG_SWEDISH: case LANG_SYRIAC: case LANG_TAMIL: - case LANG_TATAR: case LANG_TELUGU: case LANG_THAI: - case LANG_UKRAINIAN: case LANG_URDU: case LANG_UZBEK: - case LANG_VIETNAMESE: case LANG_GAELIC: case LANG_MALTESE: - case LANG_MAORI: case LANG_RHAETO_ROMANCE: - case LANG_SAAMI: case LANG_SORBIAN: case LANG_SUTU: - case LANG_TSONGA: case LANG_TSWANA: case LANG_VENDA: - case LANG_XHOSA: case LANG_ZULU: case LANG_ESPERANTO: - case LANG_WALON: case LANG_CORNISH: case LANG_WELSH: - case LANG_BRETON: - nOffset = 16; - pnLookup = Lookup_16; - break; - case LANG_CZECH: case LANG_HUNGARIAN: case LANG_POLISH: - case LANG_SLOVAK: case LANG_SPANISH: - nOffset = 32; - pnLookup = Lookup_32; - break; - case LANG_HEBREW: - nOffset = 48; - pnLookup = Lookup_48; - break; - case LANG_JAPANESE: - nOffset = 64; - pnLookup = Lookup_64; - break; - case LANG_KOREAN: - nOffset = 80; - pnLookup = Lookup_80; - break; - case LANG_CHINESE: - nOffset = 112; - pnLookup = Lookup_112; - break; - case LANG_GREEK: - nOffset = 128; - pnLookup = Lookup_128; - break; - case LANG_ICELANDIC: - nOffset = 144; - pnLookup = Lookup_144; - break; - case LANG_TURKISH: - nOffset = 160; - pnLookup = Lookup_160; - break; - case LANG_NORWEGIAN: - if (SUBLANGID(LANGIDFROMLCID(lcid)) == SUBLANG_NORWEGIAN_NYNORSK) - { - nOffset = 176; - pnLookup = Lookup_176; - } - else - { - nOffset = 16; - pnLookup = Lookup_16; - } - break; - case LANG_ARABIC: - case LANG_FARSI: - nOffset = 208; - pnLookup = Lookup_208; - break; - case LANG_RUSSIAN: - nOffset = 224; - pnLookup = Lookup_224; - break; - } - - nHiWord = (nOffset | nMask) << 16; - - while (*str) - { - ULONG newLoWord = 0, i; - - /* Cumulative prime multiplication (*37) with modulo 2^32 wrap-around */ - for (i = 0; i < 37; i++) - newLoWord += nLoWord; - - nLoWord = newLoWord + pnLookup[*str > 0x7f && nMask ? *str + 0x80 : *str]; - str++; - } - /* Constrain to a prime modulo and sizeof(WORD) */ - nLoWord = (nLoWord % 65599) & 0xffff; - - return nHiWord | nLoWord; -} - -/*********************************************************************** - * LHashValOfNameSys (OLEAUT32.165) - * - * See LHashValOfNameSysA. - */ -ULONG WINAPI LHashValOfNameSys(SYSKIND skind, LCID lcid, LPCOLESTR str) -{ - LPSTR strA; - ULONG res; - INT len; - - if (!str) return 0; - len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL ); - strA = HeapAlloc( GetProcessHeap(), 0, len ); - WideCharToMultiByte( CP_ACP, 0, str, -1, strA, len, NULL, NULL ); - res = LHashValOfNameSysA(skind, lcid, strA); - HeapFree(GetProcessHeap(), 0, strA); - return res; -} +/* + * Oleaut32 hash functions + * + * Copyright 1999 Corel Corporation + * Copyright 2001-2003 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "objbase.h" +#include "oaidl.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +static const unsigned char Lookup_16[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x00, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + + /* Windows */ + 0x7F, 0x7F, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x7F, 0x89, 0x53, 0x8B, 0x8C, + 0x7F, 0x7F, 0x7F, 0x7F, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x96, 0x98, 0x99, + 0x53, 0x9B, 0x8C, 0x7F, 0x7F, 0x55, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x96, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, + 0x49, 0x49, 0x44, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0xD7, 0x4F, 0x55, 0x55, + 0x55, 0x55, 0x55, 0xDE, 0xDF, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43, + 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x44, 0x4E, 0x4F, 0x4F, 0x4F, + 0x4F, 0x4F, 0xF7, 0x4F, 0x55, 0x55, 0x55, 0x55, 0x55, 0xDE, 0x55, + + /* Mac */ + 0x41, 0x41, 0x43, 0x45, 0x4E, 0x4F, 0x55, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x4E, 0x4F, 0x4F, 0x4F, + 0x4F, 0x4F, 0x55, 0x55, 0x55, 0x55, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0x41, 0x4F, 0xB0, 0xB1, 0xB2, 0xB3, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0x41, 0x4F, 0xBD, 0x41, 0x4F, 0xC0, + 0xC1, 0xC2, 0xC3, 0x46, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0x41, 0x41, 0x4F, + 0xCE, 0xCE, 0xD0, 0xD0, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0x55, 0x55, 0xDA, + 0xDB, 0xDC, 0xDD, 0x3F, 0x3F, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0x41, 0x45, 0x41, + 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x4F, 0x4F, 0x3F, 0x4F, 0x55, 0x55, 0x55, + 0x49, 0x7F, 0xF7, 0x7F, 0xF9, 0xFA, 0xFB, 0x3F, 0xFD, 0xFE, 0x7F +}; + +static const unsigned char Lookup_32[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x00, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + + /* Windows */ + 0x7F, 0x7F, 0x82, 0x7F, 0x84, 0x85, 0x86, 0x87, 0x7F, 0x89, 0x53, 0x8B, 0x53, + 0x54, 0x5A, 0x5A, 0x7F, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x96, 0x7F, 0x99, + 0x53, 0x9B, 0x53, 0x54, 0x5A, 0x5A, 0xA0, 0x7F, 0xA2, 0x4C, 0xA4, 0x41, 0xA6, + 0xA7, 0xA8, 0xA9, 0x53, 0xAB, 0xAC, 0x96, 0xAE, 0x5A, 0xB0, 0xB1, 0xB2, 0x4C, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x41, 0x53, 0xBB, 0x4C, 0xBD, 0x4C, 0x5A, 0x52, + 0x41, 0x41, 0x41, 0x41, 0x4C, 0x43, 0x43, 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, + 0x49, 0x44, 0xD0, 0x4E, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0xD7, 0x52, 0x55, 0x55, + 0x55, 0x55, 0x59, 0x54, 0xDF, 0x52, 0x41, 0x41, 0x41, 0x41, 0x4C, 0x43, 0x43, + 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x44, 0xD0, 0x4E, 0x4E, 0x4F, 0x4F, + 0x4F, 0x4F, 0xF7, 0x52, 0x55, 0x55, 0x55, 0x55, 0x59, 0x54, 0xFF, + + /* Mac */ + 0x41, 0x41, 0x41, 0x45, 0x41, 0x4F, 0x55, 0x41, 0x41, 0x43, 0x41, 0x43, 0x43, + 0x43, 0x45, 0x5A, 0x5A, 0x44, 0x49, 0x44, 0x45, 0x45, 0x45, 0x4F, 0x45, 0x4F, + 0x4F, 0x4F, 0x55, 0x45, 0x45, 0x55, 0xA0, 0xA1, 0x45, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xAA, 0x45, 0xAC, 0xAD, 0x47, 0x49, 0x49, 0x49, 0xB2, 0xB3, + 0x49, 0x4B, 0xB6, 0xB7, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4E, 0x4E, + 0x4E, 0xC2, 0xC3, 0x4E, 0x4E, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0x4E, 0x4F, 0x4F, + 0x4F, 0x4F, 0xD0, 0xD0, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0x4F, 0x52, 0x52, + 0x52, 0xDC, 0xDD, 0x52, 0x52, 0x52, 0x53, 0xE2, 0xE3, 0x53, 0x53, 0x53, 0x41, + 0x54, 0x54, 0x49, 0x5A, 0x5A, 0x55, 0x4F, 0x4F, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x59, 0x59, 0x4B, 0x5A, 0x4C, 0x4C, 0x47, 0xFF +}; + +static const unsigned char Lookup_48[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x00, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + + /* Windows */ + 0x7F, 0x7F, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x7F, 0x89, 0x53, 0x8B, 0x8C, + 0x7F, 0x7F, 0x7F, 0x7F, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x96, 0x98, 0x99, + 0x53, 0x9B, 0x8C, 0x7F, 0x7F, 0x59, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x96, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0xC6, 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, + 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0xD7, 0x4F, 0x55, 0x55, + 0x55, 0x55, 0x59, 0xDE, 0xDF, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0xC6, 0x43, + 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0x4F, 0x4F, + 0x4F, 0x4F, 0xF7, 0x4F, 0x55, 0x55, 0x55, 0x55, 0x59, 0xDE, 0x59, + + /* Mac */ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, + 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAB, 0xAD, 0xAE, 0xAE, 0xB0, 0xB1, 0xB2, 0xB3, + 0xA7, 0xB5, 0xB6, 0xB7, 0xB8, 0xB8, 0xBA, 0xBA, 0xBC, 0xBC, 0xBE, 0xBE, 0xB7, + 0xC1, 0xC2, 0xC3, 0x46, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCB, 0xCD, + 0xCD, 0xC1, 0xD0, 0xD0, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD8, 0xDA, + 0xDA, 0xDC, 0xDD, 0xDD, 0x9F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, + 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F +}; + +static const unsigned char Lookup_64[128 * 3] = { + /* Common */ + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x00, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + +/* Windows */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x96, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, + 0x49, 0x49, 0x44, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0xD7, 0x4F, 0x55, 0x55, + 0x55, 0x55, 0x55, 0xDE, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* Mac */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x96, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, + 0x49, 0x49, 0x44, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0xD7, 0x4F, 0x55, 0x55, + 0x55, 0x55, 0x55, 0xDE, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const unsigned char Lookup_80[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x00, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + +/* Windows */ + 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, + + /* Mac */ + 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, +}; + +static const unsigned char Lookup_112[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x00, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + +/* Windows */ + 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, + + /* Mac */ + 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, +}; + +static const unsigned char Lookup_128[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x00, + +/* Windows */ + 0x00, 0x00, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x00, 0x89, 0x00, 0x8B, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x2D, 0x2D, 0x00, 0x99, + 0x00, 0x9B, 0x00, 0x00, 0x00, 0x00, 0x09, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0x00, 0xAB, 0xAC, 0x2D, 0xAE, 0x2D, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xBA, + 0xA2, 0xC2, 0xC3, 0xC4, 0xB8, 0xC6, 0xB9, 0xC8, 0xBA, 0xCA, 0xCB, 0xCC, 0xCD, + 0xCE, 0xBC, 0xD0, 0xD1, 0x00, 0xD3, 0xD4, 0xBE, 0xD6, 0xD7, 0xD8, 0xBF, 0xBA, + 0xBE, 0xA2, 0xB8, 0xB9, 0xBA, 0xBE, 0xA2, 0xC2, 0xC3, 0xC4, 0xB8, 0xC6, 0xB9, + 0xC8, 0xBA, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xBC, 0xD0, 0xD1, 0xD3, 0xD3, 0xD4, + 0xBE, 0xD6, 0xD7, 0xD8, 0xBF, 0xBA, 0xBE, 0xBC, 0xBE, 0xBF, 0x00, + + /* Mac */ + 0x41, 0x31, 0x32, 0x45, 0x33, 0x4F, 0x55, 0x87, 0x41, 0x41, 0x41, 0x00, 0x8C, + 0x43, 0x45, 0x45, 0x45, 0x45, 0x92, 0x93, 0x49, 0x49, 0x96, 0x97, 0x98, 0x4F, + 0x4F, 0x9B, 0x3F, 0x55, 0x55, 0x55, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xAB, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xB0, + 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0x09, 0xBD, 0xCC, 0xB0, + 0xB6, 0xCF, 0x2D, 0x2D, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xB8, 0xAB, 0xC3, 0xBD, + 0xB6, 0xB8, 0xAB, 0xC3, 0xBF, 0xBD, 0xB0, 0xB5, 0xBE, 0xA2, 0xB6, 0xBC, 0xA1, + 0xB8, 0xAB, 0xA5, 0xBA, 0xA4, 0xBB, 0xC1, 0xC3, 0xA6, 0xBF, 0xC4, 0xAA, 0xC6, + 0xA3, 0xBF, 0xAA, 0xCC, 0xBD, 0xB7, 0xAB, 0xBD, 0xAB, 0xBD, 0x3F, +}; + +static const unsigned char Lookup_144[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x00, + +/* Windows */ + 0x00, 0x00, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x00, 0x89, 0x53, 0x8B, 0x8C, + 0x00, 0x00, 0x00, 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x2D, 0x2D, 0x98, 0x99, + 0x53, 0x9B, 0x8C, 0x00, 0x00, 0x59, 0x09, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x2D, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, + 0xC1, 0x41, 0x41, 0x41, 0x41, 0xC6, 0x43, 0x45, 0xC9, 0x45, 0x45, 0x49, 0xCD, + 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0xD3, 0x4F, 0x4F, 0xD6, 0xD7, 0xD6, 0x55, 0xDA, + 0x55, 0x55, 0xDD, 0xDE, 0xDF, 0x41, 0xC1, 0x41, 0x41, 0x41, 0x41, 0xC6, 0x43, + 0x45, 0xC9, 0x45, 0x45, 0x49, 0xCD, 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0xD3, 0x4F, + 0x4F, 0xD6, 0xF7, 0xD6, 0x55, 0xDA, 0x55, 0x55, 0xDD, 0xDE, 0x59, + + /* Mac */ + 0x00, 0x00, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x00, 0x89, 0x53, 0x8B, 0x8C, + 0x00, 0x00, 0x00, 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x2D, 0x2D, 0x98, 0x99, + 0x53, 0x9B, 0x8C, 0x00, 0x00, 0x59, 0x09, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x2D, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, + 0xC1, 0x41, 0x41, 0x41, 0x41, 0xC6, 0x43, 0x45, 0xC9, 0x45, 0x45, 0x49, 0xCD, + 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0xD3, 0x4F, 0x4F, 0xD6, 0xD7, 0xD6, 0x55, 0xDA, + 0x55, 0x55, 0xDD, 0xDE, 0xDF, 0x41, 0xC1, 0x41, 0x41, 0x41, 0x41, 0xC6, 0x43, + 0x45, 0xC9, 0x45, 0x45, 0x49, 0xCD, 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0xD3, 0x4F, + 0x4F, 0xD6, 0xF7, 0xD6, 0x55, 0xDA, 0x55, 0x55, 0xDD, 0xDE, 0x59, +}; + +static const unsigned char Lookup_160[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x00, + +/* Windows */ + 0x00, 0x00, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x00, 0x89, 0x53, 0x8B, 0x8C, + 0x00, 0x00, 0x00, 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x2D, 0x2D, 0x98, 0x99, + 0x53, 0x9B, 0x8C, 0x00, 0x00, 0x59, 0x09, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x2D, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0xC6, 0xC7, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, + 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0xD6, 0xD7, 0x4F, 0x55, 0x55, + 0x55, 0xDC, 0xDD, 0xDE, 0xDF, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0xC6, 0xC7, + 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0x4F, 0x4F, + 0x4F, 0xD6, 0xF7, 0x4F, 0x55, 0x55, 0x55, 0xDC, 0xDD, 0xDE, 0x59, + + /* Mac */ + 0x00, 0x00, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x00, 0x89, 0x53, 0x8B, 0x8C, + 0x00, 0x00, 0x00, 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x2D, 0x2D, 0x98, 0x99, + 0x53, 0x9B, 0x8C, 0x00, 0x00, 0x59, 0x09, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x2D, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0xC6, 0xC7, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, + 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0xD6, 0xD7, 0x4F, 0x55, 0x55, + 0x55, 0xDC, 0xDD, 0xDE, 0xDF, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0xC6, 0xC7, + 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0x4F, 0x4F, + 0x4F, 0xD6, 0xF7, 0x4F, 0x55, 0x55, 0x55, 0xDC, 0xDD, 0xDE, 0x59, +}; + +static const unsigned char Lookup_176[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x00, + + /* Windows */ + 0x00, 0x00, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x00, 0x89, 0x53, 0x8B, 0x8C, + 0x00, 0x00, 0x00, 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x2D, 0x2D, 0x98, 0x99, + 0x53, 0x9B, 0x8C, 0x00, 0x00, 0x59, 0x09, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x2D, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, + 0x41, 0x41, 0x41, 0xC4, 0xC5, 0xC4, 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, + 0x49, 0x49, 0x44, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0xD6, 0xD7, 0xD6, 0x55, 0x55, + 0x55, 0x59, 0x59, 0xDE, 0xDF, 0x41, 0x41, 0x41, 0x41, 0xC4, 0xC5, 0xC4, 0x43, + 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x44, 0x4E, 0x4F, 0x4F, 0x4F, + 0x4F, 0xD6, 0xF7, 0xD6, 0x55, 0x55, 0x55, 0x59, 0x59, 0xDE, 0x59, + + /* Mac */ + 0x80, 0x81, 0x43, 0x45, 0x4E, 0x85, 0x59, 0x41, 0x41, 0x41, 0x80, 0x41, 0x81, + 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x4E, 0x4F, 0x4F, 0x4F, + 0x85, 0x4F, 0x55, 0x55, 0x55, 0x59, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0x80, 0x85, 0xB0, 0xB1, 0xB2, 0xB3, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0x41, 0x4F, 0xBD, 0x80, 0x85, 0xC0, + 0xC1, 0xC2, 0xC3, 0x46, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0x09, 0x41, 0x41, 0x4F, + 0xCE, 0xCE, 0x2D, 0x2D, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0x59, 0x59, 0xDA, + 0xDB, 0xDC, 0xDD, 0x3F, 0x3F, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0x41, 0x45, 0x41, + 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x4F, 0x4F, 0x3F, 0x4F, 0x55, 0x55, 0x55, + 0x49, 0x00, 0xF7, 0x00, 0xF9, 0xFA, 0xFB, 0x3F, 0xFD, 0xFE, 0x00 +}; + +static const unsigned char Lookup_208[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + +/* Windows */ + 0x80, 0x81, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x5E, 0x89, 0x8A, 0x8B, 0x8C, + 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9A, 0x9B, 0x8C, 0x9D, 0x00, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, + 0xC1, 0xC2, 0xC1, 0xC1, 0xC1, 0xC1, 0xC7, 0xC8, 0xC9, 0xC9, 0xCB, 0xCC, 0xCD, + 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, + 0xDB, 0x00, 0xDD, 0xDE, 0xDF, 0x41, 0xE1, 0x41, 0xE3, 0xE4, 0xE5, 0xE6, 0x43, + 0x45, 0x45, 0x45, 0x45, 0xEC, 0xEC, 0x49, 0x49, 0xF0, 0xF1, 0xF2, 0xF3, 0x4F, + 0xF5, 0xF6, 0xF7, 0xF8, 0x55, 0xFA, 0x55, 0x55, 0x00, 0x00, 0xFF, + + /* Mac */ + 0x41, 0x81, 0x43, 0x45, 0x4E, 0x4F, 0x55, 0x41, 0x41, 0x41, 0x41, 0x8B, 0x8C, + 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x93, 0x49, 0x49, 0x4E, 0x4F, 0x98, 0x4F, + 0x4F, 0x9B, 0x55, 0x55, 0x55, 0x55, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, + 0xC1, 0xC2, 0xC1, 0xC1, 0xC1, 0xC1, 0xC7, 0xC8, 0xC9, 0xC9, 0xCB, 0xCC, 0xCD, + 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, + 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0x00, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + 0xE8, 0xE9, 0xE9, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, + 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, +}; + +static const unsigned char Lookup_224[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + +/* Windows */ + 0x80, 0x81, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x5E, 0x89, 0x8A, 0x8B, 0x8C, + 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, + 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, + 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, + 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + 0xE8, 0xE9, 0xEA, 0xEA, 0xEC, 0xED, 0xED, 0xEF, 0xEF, 0xF1, 0xF2, 0xF3, 0xF3, + 0xF5, 0xF5, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0x00, 0x00, 0xFF, + + /* Mac */ + 0x41, 0x41, 0x43, 0x45, 0x4E, 0x4F, 0x55, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x4E, 0x4F, 0x4F, 0x4F, + 0x4F, 0x4F, 0x55, 0x55, 0x55, 0x55, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, + 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, + 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, + 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + 0xE8, 0xE9, 0xEA, 0xEA, 0xEC, 0xED, 0xED, 0xEF, 0xEF, 0xF1, 0xF2, 0xF3, 0xF3, + 0xF5, 0xF5, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, +}; + +/*********************************************************************** + * LHashValOfNameSysA (OLEAUT32.166) + * + * Produce a string hash value. + * + * PARAMS + * skind [I] Type of the system. + * lcid [I] Locale id for the hash. + * lpStr [I] String to hash. + * + * RETURNS + * Success: The hash value of the string. + * Failure: 0, if lpStr is NULL. + * + * NOTES + * This function produces a two part hash: The high word is based on + * skind and lcid, while the low word is based on a repeated string + * hash of skind/str. + */ +ULONG WINAPI LHashValOfNameSysA( SYSKIND skind, LCID lcid, LPCSTR lpStr) +{ + ULONG nOffset, nMask = skind == SYS_MAC ? 1 : 0; + ULONG nHiWord, nLoWord = 0x0deadbee; + const unsigned char *str = (const unsigned char *)lpStr, *pnLookup = NULL; + + if (!str) + return 0; + + lcid = ConvertDefaultLocale(lcid); + + switch (PRIMARYLANGID(LANGIDFROMLCID(lcid))) + { + default: + ERR("Unknown lcid %lx, treating as latin-based, please report\n", lcid); + /* .. Fall Through .. */ + case LANG_AFRIKAANS: case LANG_ALBANIAN: case LANG_ARMENIAN: + case LANG_ASSAMESE: case LANG_AZERI: case LANG_BASQUE: + case LANG_BELARUSIAN: case LANG_BENGALI: case LANG_BULGARIAN: + case LANG_CATALAN: case LANG_DANISH: case LANG_DIVEHI: + case LANG_DUTCH: case LANG_ENGLISH: case LANG_ESTONIAN: + case LANG_FAEROESE: case LANG_FINNISH: case LANG_FRENCH: + case LANG_GALICIAN: case LANG_GEORGIAN: case LANG_GERMAN: + case LANG_GUJARATI: case LANG_HINDI: case LANG_INDONESIAN: + case LANG_ITALIAN: case LANG_KANNADA: case LANG_KASHMIRI: + case LANG_KAZAK: case LANG_KONKANI: case LANG_KYRGYZ: + case LANG_LATVIAN: case LANG_LITHUANIAN: case LANG_MACEDONIAN: + case LANG_MALAY: case LANG_MALAYALAM: case LANG_MANIPURI: + case LANG_MARATHI: case LANG_MONGOLIAN: case LANG_NEPALI: + case LANG_ORIYA: case LANG_PORTUGUESE: case LANG_PUNJABI: + case LANG_ROMANIAN: case LANG_SANSKRIT: case LANG_SERBIAN: + case LANG_SINDHI: case LANG_SLOVENIAN: case LANG_SWAHILI: + case LANG_SWEDISH: case LANG_SYRIAC: case LANG_TAMIL: + case LANG_TATAR: case LANG_TELUGU: case LANG_THAI: + case LANG_UKRAINIAN: case LANG_URDU: case LANG_UZBEK: + case LANG_VIETNAMESE: case LANG_GAELIC: case LANG_MALTESE: + case LANG_MAORI: case LANG_RHAETO_ROMANCE: + case LANG_SAAMI: case LANG_SORBIAN: case LANG_SUTU: + case LANG_TSONGA: case LANG_TSWANA: case LANG_VENDA: + case LANG_XHOSA: case LANG_ZULU: case LANG_ESPERANTO: + case LANG_WALON: case LANG_CORNISH: case LANG_WELSH: + case LANG_BRETON: + nOffset = 16; + pnLookup = Lookup_16; + break; + case LANG_CZECH: case LANG_HUNGARIAN: case LANG_POLISH: + case LANG_SLOVAK: case LANG_SPANISH: + nOffset = 32; + pnLookup = Lookup_32; + break; + case LANG_HEBREW: + nOffset = 48; + pnLookup = Lookup_48; + break; + case LANG_JAPANESE: + nOffset = 64; + pnLookup = Lookup_64; + break; + case LANG_KOREAN: + nOffset = 80; + pnLookup = Lookup_80; + break; + case LANG_CHINESE: + nOffset = 112; + pnLookup = Lookup_112; + break; + case LANG_GREEK: + nOffset = 128; + pnLookup = Lookup_128; + break; + case LANG_ICELANDIC: + nOffset = 144; + pnLookup = Lookup_144; + break; + case LANG_TURKISH: + nOffset = 160; + pnLookup = Lookup_160; + break; + case LANG_NORWEGIAN: + if (SUBLANGID(LANGIDFROMLCID(lcid)) == SUBLANG_NORWEGIAN_NYNORSK) + { + nOffset = 176; + pnLookup = Lookup_176; + } + else + { + nOffset = 16; + pnLookup = Lookup_16; + } + break; + case LANG_ARABIC: + case LANG_FARSI: + nOffset = 208; + pnLookup = Lookup_208; + break; + case LANG_RUSSIAN: + nOffset = 224; + pnLookup = Lookup_224; + break; + } + + nHiWord = (nOffset | nMask) << 16; + + while (*str) + { + ULONG newLoWord = 0, i; + + /* Cumulative prime multiplication (*37) with modulo 2^32 wrap-around */ + for (i = 0; i < 37; i++) + newLoWord += nLoWord; + + nLoWord = newLoWord + pnLookup[*str > 0x7f && nMask ? *str + 0x80 : *str]; + str++; + } + /* Constrain to a prime modulo and sizeof(WORD) */ + nLoWord = (nLoWord % 65599) & 0xffff; + + return nHiWord | nLoWord; +} + +/*********************************************************************** + * LHashValOfNameSys (OLEAUT32.165) + * + * See LHashValOfNameSysA. + */ +ULONG WINAPI LHashValOfNameSys(SYSKIND skind, LCID lcid, LPCOLESTR str) +{ + LPSTR strA; + ULONG res; + INT len; + + if (!str) return 0; + len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL ); + strA = HeapAlloc( GetProcessHeap(), 0, len ); + WideCharToMultiByte( CP_ACP, 0, str, -1, strA, len, NULL, NULL ); + res = LHashValOfNameSysA(skind, lcid, strA); + HeapFree(GetProcessHeap(), 0, strA); + return res; +} diff --git a/reactos/lib/oleaut32/oaidl_p.c b/reactos/lib/oleaut32/oaidl_p.c index 0d7f8545bce..18109da829f 100644 --- a/reactos/lib/oleaut32/oaidl_p.c +++ b/reactos/lib/oleaut32/oaidl_p.c @@ -1,13781 +1,13781 @@ -/* This file contains the proxy/stub code for core COM interfaces. - - It is usually generated directly by MIDL, however this file has - been tweaked since then to account for slight differences in the way - gcc and MSVC++ compile it. In particular, in some functions REFIIDs - declared on the stack have been converted to plain IID* in order to eliminate - the constness of the REFIID type, ensuring that the zero initializer is not - discarded. - - Therefore, please do not regenerate this file. -*/ - -/* File created by MIDL compiler version 5.01.0164 */ -/* at Tue Jan 07 22:24:52 2003 - */ -/* Compiler settings for oaidl.idl: - Os (OptLev=s), W1, Zp8, env=Win32, ms_ext, c_ext - error checks: allocation ref bounds_check enum stub_data -*/ -/*@@MIDL_FILE_HEADING( ) */ - - -/* verify that the <rpcproxy.h> version is high enough to compile this file*/ -#ifndef __REDQ_RPCPROXY_H_VERSION__ -#define __REQUIRED_RPCPROXY_H_VERSION__ 440 -#endif - - -#include <stdarg.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "objbase.h" -#include "rpcproxy.h" -#ifndef __RPCPROXY_H_VERSION__ -#error this stub requires an updated version of <rpcproxy.h> -#endif /* __RPCPROXY_H_VERSION__ */ - - -#include "oaidl.h" - -#define TYPE_FORMAT_STRING_SIZE 1907 -#define PROC_FORMAT_STRING_SIZE 495 - -typedef struct _MIDL_TYPE_FORMAT_STRING - { - short Pad; - unsigned char Format[ TYPE_FORMAT_STRING_SIZE ]; - } MIDL_TYPE_FORMAT_STRING; - -typedef struct _MIDL_PROC_FORMAT_STRING - { - short Pad; - unsigned char Format[ PROC_FORMAT_STRING_SIZE ]; - } MIDL_PROC_FORMAT_STRING; - - -static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString; -static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString; - - -/* Standard interface: __MIDL_itf_oaidl_0000, ver. 0.0, - GUID={0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} */ - - -/* Standard interface: IOleAutomationTypes, ver. 1.0, - GUID={0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} */ - - -/* Object interface: IUnknown, ver. 0.0, - GUID={0x00000000,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ - - -/* Object interface: IDispatch, ver. 0.0, - GUID={0x00020400,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ - - -static const MIDL_STUB_DESC Object_StubDesc; - - -HRESULT STDMETHODCALLTYPE IDispatch_GetTypeInfoCount_Proxy( - IDispatch __RPC_FAR * This, - /* [out] */ UINT __RPC_FAR *pctinfo) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 3); - - - - if(!pctinfo) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[0] ); - - *pctinfo = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], - ( void __RPC_FAR * )pctinfo); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB IDispatch_GetTypeInfoCount_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - UINT _M0; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - UINT __RPC_FAR *pctinfo; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pctinfo = 0; - RpcTryFinally - { - pctinfo = &_M0; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((IDispatch*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetTypeInfoCount((IDispatch *) ((CStdStubBuffer *)This)->pvServerObject,pctinfo); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U + 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( UINT __RPC_FAR * )_StubMsg.Buffer = *pctinfo; - _StubMsg.Buffer += sizeof(UINT); - - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE IDispatch_GetTypeInfo_Proxy( - IDispatch __RPC_FAR * This, - /* [in] */ UINT iTInfo, - /* [in] */ LCID lcid, - /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(ppTInfo) - { - MIDL_memset( - ppTInfo, - 0, - sizeof( ITypeInfo __RPC_FAR *__RPC_FAR * )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 4); - - - - if(!ppTInfo) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U + 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( UINT __RPC_FAR * )_StubMsg.Buffer = iTInfo; - _StubMsg.Buffer += sizeof(UINT); - - *( LCID __RPC_FAR * )_StubMsg.Buffer = lcid; - _StubMsg.Buffer += sizeof(LCID); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[6] ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&ppTInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[6], - ( void __RPC_FAR * )ppTInfo); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB IDispatch_GetTypeInfo_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - ITypeInfo __RPC_FAR *_M1; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - UINT iTInfo; - LCID lcid; - ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - ppTInfo = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[6] ); - - iTInfo = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - lcid = *( LCID __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(LCID); - - ppTInfo = &_M1; - _M1 = 0; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((IDispatch*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetTypeInfo( - (IDispatch *) ((CStdStubBuffer *)This)->pvServerObject, - iTInfo, - lcid, - ppTInfo); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 0U + 4U; - NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)ppTInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)ppTInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)ppTInfo, - &__MIDL_TypeFormatString.Format[6] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE IDispatch_GetIDsOfNames_Proxy( - IDispatch __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [size_is][in] */ LPOLESTR __RPC_FAR *rgszNames, - /* [in] */ UINT cNames, - /* [in] */ LCID lcid, - /* [size_is][out] */ DISPID __RPC_FAR *rgDispId) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 5); - - - - if(!riid) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!rgszNames) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!rgDispId) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U + 7U + 7U + 7U; - NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)riid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - _StubMsg.MaxCount = cNames; - - NdrConformantArrayBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)rgszNames, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[54] ); - - NdrProxyGetBuffer(This, &_StubMsg); - NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)riid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - _StubMsg.MaxCount = cNames; - - NdrConformantArrayMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)rgszNames, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[54] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( UINT __RPC_FAR * )_StubMsg.Buffer = cNames; - _StubMsg.Buffer += sizeof(UINT); - - *( LCID __RPC_FAR * )_StubMsg.Buffer = lcid; - _StubMsg.Buffer += sizeof(LCID); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[16] ); - - NdrConformantArrayUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&rgDispId, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[88], - (unsigned char)0 ); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - _StubMsg.MaxCount = cNames; - - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[84], - ( void __RPC_FAR * )rgDispId); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB IDispatch_GetIDsOfNames_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - UINT cNames; - LCID lcid; - DISPID __RPC_FAR *rgDispId; - LPOLESTR __RPC_FAR *rgszNames; - IID* riid = 0; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - rgszNames = 0; - rgDispId = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[16] ); - - NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&riid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], - (unsigned char)0 ); - - NdrConformantArrayUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&rgszNames, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[54], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - cNames = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - - lcid = *( LCID __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(LCID); - - rgDispId = NdrAllocate(&_StubMsg,cNames * 4); - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((IDispatch*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetIDsOfNames( - (IDispatch *) ((CStdStubBuffer *)This)->pvServerObject, - riid, - rgszNames, - cNames, - lcid, - rgDispId); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U + 7U; - _StubMsg.MaxCount = cNames; - - NdrConformantArrayBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)rgDispId, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[88] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - _StubMsg.MaxCount = cNames; - - NdrConformantArrayMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)rgDispId, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[88] ); - - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - _StubMsg.MaxCount = cNames; - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)rgszNames, - &__MIDL_TypeFormatString.Format[50] ); - - if ( rgDispId ) - _StubMsg.pfnFree( rgDispId ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE IDispatch_RemoteInvoke_Proxy( - IDispatch __RPC_FAR * This, - /* [in] */ DISPID dispIdMember, - /* [in] */ REFIID riid, - /* [in] */ LCID lcid, - /* [in] */ DWORD dwFlags, - /* [in] */ DISPPARAMS __RPC_FAR *pDispParams, - /* [out] */ VARIANT __RPC_FAR *pVarResult, - /* [out] */ EXCEPINFO __RPC_FAR *pExcepInfo, - /* [out] */ UINT __RPC_FAR *pArgErr, - /* [in] */ UINT cVarRef, - /* [size_is][in] */ UINT __RPC_FAR *rgVarRefIdx, - /* [size_is][out][in] */ VARIANTARG __RPC_FAR *rgVarRef) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pVarResult) - { - MIDL_memset( - pVarResult, - 0, - sizeof( VARIANT )); - } - if(pExcepInfo) - { - MIDL_memset( - pExcepInfo, - 0, - sizeof( EXCEPINFO )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 6); - - - - if(!riid) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pDispParams) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pVarResult) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pExcepInfo) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pArgErr) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!rgVarRefIdx) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!rgVarRef) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U + 4U + 11U + 7U + 4U + 11U + 7U + 7U; - NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)riid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrComplexStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pDispParams, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1080] ); - - _StubMsg.MaxCount = cVarRef; - - NdrConformantArrayBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)rgVarRefIdx, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1170] ); - - _StubMsg.MaxCount = cVarRef; - - NdrComplexArrayBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)rgVarRef, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1184] ); - - NdrProxyGetBuffer(This, &_StubMsg); - *( DISPID __RPC_FAR * )_StubMsg.Buffer = dispIdMember; - _StubMsg.Buffer += sizeof(DISPID); - - NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)riid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - *( LCID __RPC_FAR * )_StubMsg.Buffer = lcid; - _StubMsg.Buffer += sizeof(LCID); - - *( DWORD __RPC_FAR * )_StubMsg.Buffer = dwFlags; - _StubMsg.Buffer += sizeof(DWORD); - - NdrComplexStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pDispParams, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1080] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( UINT __RPC_FAR * )_StubMsg.Buffer = cVarRef; - _StubMsg.Buffer += sizeof(UINT); - - _StubMsg.MaxCount = cVarRef; - - NdrConformantArrayMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)rgVarRefIdx, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1170] ); - - _StubMsg.MaxCount = cVarRef; - - NdrComplexArrayMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)rgVarRef, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1184] ); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[34] ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pVarResult, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110], - (unsigned char)0 ); - - NdrComplexStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pExcepInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1138], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *pArgErr = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - NdrComplexArrayUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&rgVarRef, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1184], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1102], - ( void __RPC_FAR * )pVarResult); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1120], - ( void __RPC_FAR * )pExcepInfo); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], - ( void __RPC_FAR * )pArgErr); - _StubMsg.MaxCount = cVarRef; - - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1180], - ( void __RPC_FAR * )rgVarRef); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB IDispatch_RemoteInvoke_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - VARIANT _M6; - UINT _M7; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - EXCEPINFO _pExcepInfoM; - UINT cVarRef; - DISPID dispIdMember; - DWORD dwFlags; - LCID lcid; - UINT __RPC_FAR *pArgErr; - DISPPARAMS __RPC_FAR *pDispParams; - EXCEPINFO __RPC_FAR *pExcepInfo; - VARIANT __RPC_FAR *pVarResult; - VARIANTARG __RPC_FAR *rgVarRef; - UINT __RPC_FAR *rgVarRefIdx; - IID* riid = 0; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pDispParams = 0; - pVarResult = 0; - pExcepInfo = 0; - pArgErr = 0; - rgVarRefIdx = 0; - rgVarRef = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[34] ); - - dispIdMember = *( DISPID __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(DISPID); - - NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&riid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], - (unsigned char)0 ); - - lcid = *( LCID __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(LCID); - - dwFlags = *( DWORD __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(DWORD); - - NdrComplexStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pDispParams, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1080], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - cVarRef = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - NdrConformantArrayUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&rgVarRefIdx, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1170], - (unsigned char)0 ); - - NdrComplexArrayUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&rgVarRef, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1184], - (unsigned char)0 ); - - pVarResult = &_M6; - MIDL_memset( - pVarResult, - 0, - sizeof( VARIANT )); - pExcepInfo = &_pExcepInfoM; - pArgErr = &_M7; - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = IDispatch_Invoke_Stub( - (IDispatch *) ((CStdStubBuffer *)This)->pvServerObject, - dispIdMember, - riid, - lcid, - dwFlags, - pDispParams, - pVarResult, - pExcepInfo, - pArgErr, - cVarRef, - rgVarRefIdx, - rgVarRef); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 8U + 7U + 11U + 7U + 7U; - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pVarResult, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); - - NdrComplexStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pExcepInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1138] ); - - _StubMsg.MaxCount = cVarRef; - - NdrComplexArrayBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)rgVarRef, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1184] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pVarResult, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); - - NdrComplexStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pExcepInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1138] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( UINT __RPC_FAR * )_StubMsg.Buffer = *pArgErr; - _StubMsg.Buffer += sizeof(UINT); - - _StubMsg.MaxCount = cVarRef; - - NdrComplexArrayMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)rgVarRef, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1184] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pDispParams, - &__MIDL_TypeFormatString.Format[98] ); - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pVarResult, - &__MIDL_TypeFormatString.Format[1102] ); - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pExcepInfo, - &__MIDL_TypeFormatString.Format[1120] ); - - _StubMsg.MaxCount = cVarRef; - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)rgVarRef, - &__MIDL_TypeFormatString.Format[1180] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - -const CINTERFACE_PROXY_VTABLE(7) _IDispatchProxyVtbl = -{ - { &IID_IDispatch }, - { - IUnknown_QueryInterface_Proxy, - IUnknown_AddRef_Proxy, - IUnknown_Release_Proxy , - IDispatch_GetTypeInfoCount_Proxy , - IDispatch_GetTypeInfo_Proxy , - IDispatch_GetIDsOfNames_Proxy , - IDispatch_Invoke_Proxy - } -}; - - -static const PRPC_STUB_FUNCTION IDispatch_table[] = -{ - IDispatch_GetTypeInfoCount_Stub, - IDispatch_GetTypeInfo_Stub, - IDispatch_GetIDsOfNames_Stub, - IDispatch_RemoteInvoke_Stub -}; - -const CInterfaceStubVtbl _IDispatchStubVtbl = -{ - { - &IID_IDispatch, - 0, - 7, - &IDispatch_table[-3] - }, - { CStdStubBuffer_METHODS } -}; - - -/* Object interface: IEnumVARIANT, ver. 0.0, - GUID={0x00020404,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ - - -extern const MIDL_STUB_DESC Object_StubDesc; - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE IEnumVARIANT_RemoteNext_Proxy( - IEnumVARIANT __RPC_FAR * This, - /* [in] */ ULONG celt, - /* [length_is][size_is][out] */ VARIANT __RPC_FAR *rgVar, - /* [out] */ ULONG __RPC_FAR *pCeltFetched) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(rgVar) - { - MIDL_memset( - rgVar, - 0, - celt * sizeof( VARIANT )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 3); - - - - if(!rgVar) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pCeltFetched) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( ULONG __RPC_FAR * )_StubMsg.Buffer = celt; - _StubMsg.Buffer += sizeof(ULONG); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[72] ); - - NdrComplexArrayUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&rgVar, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1206], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *pCeltFetched = *( ULONG __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(ULONG); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - _StubMsg.MaxCount = celt; - _StubMsg.Offset = 0; - _StubMsg.ActualCount = _StubMsg.MaxCount; - - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1202], - ( void __RPC_FAR * )rgVar); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], - ( void __RPC_FAR * )pCeltFetched); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB IEnumVARIANT_RemoteNext_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - ULONG _M11; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - ULONG celt; - ULONG __RPC_FAR *pCeltFetched; - VARIANT __RPC_FAR *rgVar; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - rgVar = 0; - pCeltFetched = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[72] ); - - celt = *( ULONG __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(ULONG); - - rgVar = NdrAllocate(&_StubMsg,celt * 16); - pCeltFetched = &_M11; - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = IEnumVARIANT_Next_Stub( - (IEnumVARIANT *) ((CStdStubBuffer *)This)->pvServerObject, - celt, - rgVar, - pCeltFetched); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 12U + 7U + 7U; - _StubMsg.MaxCount = celt; - _StubMsg.Offset = 0; - _StubMsg.ActualCount = pCeltFetched ? *pCeltFetched : 0; - - NdrComplexArrayBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)rgVar, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1206] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - _StubMsg.MaxCount = celt; - _StubMsg.Offset = 0; - _StubMsg.ActualCount = pCeltFetched ? *pCeltFetched : 0; - - NdrComplexArrayMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)rgVar, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1206] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( ULONG __RPC_FAR * )_StubMsg.Buffer = *pCeltFetched; - _StubMsg.Buffer += sizeof(ULONG); - - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - _StubMsg.MaxCount = celt; - _StubMsg.Offset = 0; - _StubMsg.ActualCount = pCeltFetched ? *pCeltFetched : 0; - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)rgVar, - &__MIDL_TypeFormatString.Format[1202] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE IEnumVARIANT_Skip_Proxy( - IEnumVARIANT __RPC_FAR * This, - /* [in] */ ULONG celt) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 4); - - - - RpcTryFinally - { - - _StubMsg.BufferLength = 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( ULONG __RPC_FAR * )_StubMsg.Buffer = celt; - _StubMsg.Buffer += sizeof(ULONG); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[84] ); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB IEnumVARIANT_Skip_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - ULONG celt; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[84] ); - - celt = *( ULONG __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(ULONG); - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((IEnumVARIANT*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> Skip((IEnumVARIANT *) ((CStdStubBuffer *)This)->pvServerObject,celt); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE IEnumVARIANT_Reset_Proxy( - IEnumVARIANT __RPC_FAR * This) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 5); - - - - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[88] ); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB IEnumVARIANT_Reset_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - RpcTryFinally - { - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((IEnumVARIANT*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> Reset((IEnumVARIANT *) ((CStdStubBuffer *)This)->pvServerObject); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE IEnumVARIANT_Clone_Proxy( - IEnumVARIANT __RPC_FAR * This, - /* [out] */ IEnumVARIANT __RPC_FAR *__RPC_FAR *ppEnum) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(ppEnum) - { - MIDL_memset( - ppEnum, - 0, - sizeof( IEnumVARIANT __RPC_FAR *__RPC_FAR * )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 6); - - - - if(!ppEnum) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[90] ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&ppEnum, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1224], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1224], - ( void __RPC_FAR * )ppEnum); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB IEnumVARIANT_Clone_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - IEnumVARIANT __RPC_FAR *_M12; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - IEnumVARIANT __RPC_FAR *__RPC_FAR *ppEnum; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - ppEnum = 0; - RpcTryFinally - { - ppEnum = &_M12; - _M12 = 0; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((IEnumVARIANT*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> Clone((IEnumVARIANT *) ((CStdStubBuffer *)This)->pvServerObject,ppEnum); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 0U + 4U; - NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)ppEnum, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1224] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)ppEnum, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1224] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)ppEnum, - &__MIDL_TypeFormatString.Format[1224] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - -const CINTERFACE_PROXY_VTABLE(7) _IEnumVARIANTProxyVtbl = -{ - { &IID_IEnumVARIANT }, - { - IUnknown_QueryInterface_Proxy, - IUnknown_AddRef_Proxy, - IUnknown_Release_Proxy , - IEnumVARIANT_Next_Proxy , - IEnumVARIANT_Skip_Proxy , - IEnumVARIANT_Reset_Proxy , - IEnumVARIANT_Clone_Proxy - } -}; - - -static const PRPC_STUB_FUNCTION IEnumVARIANT_table[] = -{ - IEnumVARIANT_RemoteNext_Stub, - IEnumVARIANT_Skip_Stub, - IEnumVARIANT_Reset_Stub, - IEnumVARIANT_Clone_Stub -}; - -const CInterfaceStubVtbl _IEnumVARIANTStubVtbl = -{ - { - &IID_IEnumVARIANT, - 0, - 7, - &IEnumVARIANT_table[-3] - }, - { CStdStubBuffer_METHODS } -}; - - -/* Object interface: ITypeComp, ver. 0.0, - GUID={0x00020403,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ - - -extern const MIDL_STUB_DESC Object_StubDesc; - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeComp_RemoteBind_Proxy( - ITypeComp __RPC_FAR * This, - /* [in] */ LPOLESTR szName, - /* [in] */ ULONG lHashVal, - /* [in] */ WORD wFlags, - /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo, - /* [out] */ DESCKIND __RPC_FAR *pDescKind, - /* [out] */ LPFUNCDESC __RPC_FAR *ppFuncDesc, - /* [out] */ LPVARDESC __RPC_FAR *ppVarDesc, - /* [out] */ ITypeComp __RPC_FAR *__RPC_FAR *ppTypeComp, - /* [out] */ CLEANLOCALSTORAGE __RPC_FAR *pDummy) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(ppTInfo) - { - MIDL_memset( - ppTInfo, - 0, - sizeof( ITypeInfo __RPC_FAR *__RPC_FAR * )); - } - if(ppFuncDesc) - { - *ppFuncDesc = 0; - } - if(ppVarDesc) - { - *ppVarDesc = 0; - } - if(ppTypeComp) - { - MIDL_memset( - ppTypeComp, - 0, - sizeof( ITypeComp __RPC_FAR *__RPC_FAR * )); - } - if(pDummy) - { - MIDL_memset( - pDummy, - 0, - sizeof( CLEANLOCALSTORAGE )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 3); - - - - if(!szName) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!ppTInfo) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pDescKind) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!ppFuncDesc) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!ppVarDesc) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!ppTypeComp) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pDummy) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 12U + 10U + 4U; - NdrConformantStringBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)szName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); - - NdrProxyGetBuffer(This, &_StubMsg); - NdrConformantStringMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)szName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( ULONG __RPC_FAR * )_StubMsg.Buffer = lHashVal; - _StubMsg.Buffer += sizeof(ULONG); - - *( WORD __RPC_FAR * )_StubMsg.Buffer = wFlags; - _StubMsg.Buffer += sizeof(WORD); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[96] ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&ppTInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6], - (unsigned char)0 ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pDescKind, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1250], - (unsigned char)0 ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&ppFuncDesc, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1254], - (unsigned char)0 ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&ppVarDesc, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1464], - (unsigned char)0 ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&ppTypeComp, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1540], - (unsigned char)0 ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pDummy, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1568], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[6], - ( void __RPC_FAR * )ppTInfo); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1250], - ( void __RPC_FAR * )pDescKind); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1254], - ( void __RPC_FAR * )ppFuncDesc); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1464], - ( void __RPC_FAR * )ppVarDesc); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1540], - ( void __RPC_FAR * )ppTypeComp); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1562], - ( void __RPC_FAR * )pDummy); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeComp_RemoteBind_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - ITypeInfo __RPC_FAR *_M15; - DESCKIND _M16; - LPFUNCDESC _M17; - LPVARDESC _M18; - ITypeComp __RPC_FAR *_M19; - CLEANLOCALSTORAGE _M20; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - ULONG lHashVal; - DESCKIND __RPC_FAR *pDescKind; - CLEANLOCALSTORAGE __RPC_FAR *pDummy; - LPFUNCDESC __RPC_FAR *ppFuncDesc; - ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo; - ITypeComp __RPC_FAR *__RPC_FAR *ppTypeComp; - LPVARDESC __RPC_FAR *ppVarDesc; - LPOLESTR szName; - WORD wFlags; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - szName = 0; - ppTInfo = 0; - pDescKind = 0; - ppFuncDesc = 0; - ppVarDesc = 0; - ppTypeComp = 0; - pDummy = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[96] ); - - NdrConformantStringUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&szName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - lHashVal = *( ULONG __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(ULONG); - - wFlags = *( WORD __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(WORD); - - ppTInfo = &_M15; - _M15 = 0; - pDescKind = &_M16; - ppFuncDesc = &_M17; - _M17 = 0; - ppVarDesc = &_M18; - _M18 = 0; - ppTypeComp = &_M19; - _M19 = 0; - pDummy = &_M20; - MIDL_memset( - pDummy, - 0, - sizeof( CLEANLOCALSTORAGE )); - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeComp_Bind_Stub( - (ITypeComp *) ((CStdStubBuffer *)This)->pvServerObject, - szName, - lHashVal, - wFlags, - ppTInfo, - pDescKind, - ppFuncDesc, - ppVarDesc, - ppTypeComp, - pDummy); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 0U + 4U + 4U + 15U + 0U + 11U + 7U; - NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)ppTInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); - - NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)ppFuncDesc, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1254] ); - - NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)ppVarDesc, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1464] ); - - NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)ppTypeComp, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1540] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)ppTInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); - - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pDescKind, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1250] ); - - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)ppFuncDesc, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1254] ); - - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)ppVarDesc, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1464] ); - - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)ppTypeComp, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1540] ); - - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pDummy, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1568] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)ppTInfo, - &__MIDL_TypeFormatString.Format[6] ); - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)ppFuncDesc, - &__MIDL_TypeFormatString.Format[1254] ); - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)ppVarDesc, - &__MIDL_TypeFormatString.Format[1464] ); - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)ppTypeComp, - &__MIDL_TypeFormatString.Format[1540] ); - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pDummy, - &__MIDL_TypeFormatString.Format[1562] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeComp_RemoteBindType_Proxy( - ITypeComp __RPC_FAR * This, - /* [in] */ LPOLESTR szName, - /* [in] */ ULONG lHashVal, - /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(ppTInfo) - { - MIDL_memset( - ppTInfo, - 0, - sizeof( ITypeInfo __RPC_FAR *__RPC_FAR * )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 4); - - - - if(!szName) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!ppTInfo) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 12U + 10U; - NdrConformantStringBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)szName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); - - NdrProxyGetBuffer(This, &_StubMsg); - NdrConformantStringMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)szName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( ULONG __RPC_FAR * )_StubMsg.Buffer = lHashVal; - _StubMsg.Buffer += sizeof(ULONG); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[130] ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&ppTInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[6], - ( void __RPC_FAR * )ppTInfo); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeComp_RemoteBindType_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - ITypeInfo __RPC_FAR *_M23; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - ULONG lHashVal; - ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo; - LPOLESTR szName; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - szName = 0; - ppTInfo = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[130] ); - - NdrConformantStringUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&szName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - lHashVal = *( ULONG __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(ULONG); - - ppTInfo = &_M23; - _M23 = 0; - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeComp_BindType_Stub( - (ITypeComp *) ((CStdStubBuffer *)This)->pvServerObject, - szName, - lHashVal, - ppTInfo); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 0U + 4U; - NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)ppTInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)ppTInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)ppTInfo, - &__MIDL_TypeFormatString.Format[6] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - -const CINTERFACE_PROXY_VTABLE(5) _ITypeCompProxyVtbl = -{ - { &IID_ITypeComp }, - { - IUnknown_QueryInterface_Proxy, - IUnknown_AddRef_Proxy, - IUnknown_Release_Proxy , - ITypeComp_Bind_Proxy , - ITypeComp_BindType_Proxy - } -}; - - -static const PRPC_STUB_FUNCTION ITypeComp_table[] = -{ - ITypeComp_RemoteBind_Stub, - ITypeComp_RemoteBindType_Stub -}; - -const CInterfaceStubVtbl _ITypeCompStubVtbl = -{ - { - &IID_ITypeComp, - 0, - 5, - &ITypeComp_table[-3] - }, - { CStdStubBuffer_METHODS } -}; - - -/* Object interface: ITypeInfo, ver. 0.0, - GUID={0x00020401,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ - - -extern const MIDL_STUB_DESC Object_StubDesc; - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_RemoteGetTypeAttr_Proxy( - ITypeInfo __RPC_FAR * This, - /* [out] */ LPTYPEATTR __RPC_FAR *ppTypeAttr, - /* [out] */ CLEANLOCALSTORAGE __RPC_FAR *pDummy) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(ppTypeAttr) - { - *ppTypeAttr = 0; - } - if(pDummy) - { - MIDL_memset( - pDummy, - 0, - sizeof( CLEANLOCALSTORAGE )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 3); - - - - if(!ppTypeAttr) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pDummy) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[142] ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&ppTypeAttr, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1578], - (unsigned char)0 ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pDummy, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1644], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1578], - ( void __RPC_FAR * )ppTypeAttr); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1638], - ( void __RPC_FAR * )pDummy); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo_RemoteGetTypeAttr_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - LPTYPEATTR _M24; - CLEANLOCALSTORAGE _M25; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - CLEANLOCALSTORAGE __RPC_FAR *pDummy; - LPTYPEATTR __RPC_FAR *ppTypeAttr; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - ppTypeAttr = 0; - pDummy = 0; - RpcTryFinally - { - ppTypeAttr = &_M24; - _M24 = 0; - pDummy = &_M25; - MIDL_memset( - pDummy, - 0, - sizeof( CLEANLOCALSTORAGE )); - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeInfo_GetTypeAttr_Stub( - (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, - ppTypeAttr, - pDummy); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 8U + 11U + 7U; - NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)ppTypeAttr, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1578] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)ppTypeAttr, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1578] ); - - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pDummy, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1644] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)ppTypeAttr, - &__MIDL_TypeFormatString.Format[1578] ); - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pDummy, - &__MIDL_TypeFormatString.Format[1638] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeInfo_GetTypeComp_Proxy( - ITypeInfo __RPC_FAR * This, - /* [out] */ ITypeComp __RPC_FAR *__RPC_FAR *ppTComp) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(ppTComp) - { - MIDL_memset( - ppTComp, - 0, - sizeof( ITypeComp __RPC_FAR *__RPC_FAR * )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 4); - - - - if(!ppTComp) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[152] ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&ppTComp, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1540], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1540], - ( void __RPC_FAR * )ppTComp); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo_GetTypeComp_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - ITypeComp __RPC_FAR *_M26; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - ITypeComp __RPC_FAR *__RPC_FAR *ppTComp; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - ppTComp = 0; - RpcTryFinally - { - ppTComp = &_M26; - _M26 = 0; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetTypeComp((ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject,ppTComp); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 0U + 4U; - NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)ppTComp, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1540] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)ppTComp, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1540] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)ppTComp, - &__MIDL_TypeFormatString.Format[1540] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_RemoteGetFuncDesc_Proxy( - ITypeInfo __RPC_FAR * This, - /* [in] */ UINT index, - /* [out] */ LPFUNCDESC __RPC_FAR *ppFuncDesc, - /* [out] */ CLEANLOCALSTORAGE __RPC_FAR *pDummy) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(ppFuncDesc) - { - *ppFuncDesc = 0; - } - if(pDummy) - { - MIDL_memset( - pDummy, - 0, - sizeof( CLEANLOCALSTORAGE )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 5); - - - - if(!ppFuncDesc) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pDummy) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( UINT __RPC_FAR * )_StubMsg.Buffer = index; - _StubMsg.Buffer += sizeof(UINT); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[158] ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&ppFuncDesc, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1254], - (unsigned char)0 ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pDummy, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1660], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1254], - ( void __RPC_FAR * )ppFuncDesc); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1654], - ( void __RPC_FAR * )pDummy); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo_RemoteGetFuncDesc_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - LPFUNCDESC _M27; - CLEANLOCALSTORAGE _M28; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - UINT index; - CLEANLOCALSTORAGE __RPC_FAR *pDummy; - LPFUNCDESC __RPC_FAR *ppFuncDesc; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - ppFuncDesc = 0; - pDummy = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[158] ); - - index = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - ppFuncDesc = &_M27; - _M27 = 0; - pDummy = &_M28; - MIDL_memset( - pDummy, - 0, - sizeof( CLEANLOCALSTORAGE )); - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeInfo_GetFuncDesc_Stub( - (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, - index, - ppFuncDesc, - pDummy); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 8U + 11U + 7U; - NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)ppFuncDesc, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1254] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)ppFuncDesc, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1254] ); - - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pDummy, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1660] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)ppFuncDesc, - &__MIDL_TypeFormatString.Format[1254] ); - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pDummy, - &__MIDL_TypeFormatString.Format[1654] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_RemoteGetVarDesc_Proxy( - ITypeInfo __RPC_FAR * This, - /* [in] */ UINT index, - /* [out] */ LPVARDESC __RPC_FAR *ppVarDesc, - /* [out] */ CLEANLOCALSTORAGE __RPC_FAR *pDummy) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(ppVarDesc) - { - *ppVarDesc = 0; - } - if(pDummy) - { - MIDL_memset( - pDummy, - 0, - sizeof( CLEANLOCALSTORAGE )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 6); - - - - if(!ppVarDesc) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pDummy) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( UINT __RPC_FAR * )_StubMsg.Buffer = index; - _StubMsg.Buffer += sizeof(UINT); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[170] ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&ppVarDesc, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1464], - (unsigned char)0 ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pDummy, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1676], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1464], - ( void __RPC_FAR * )ppVarDesc); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1670], - ( void __RPC_FAR * )pDummy); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo_RemoteGetVarDesc_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - LPVARDESC _M29; - CLEANLOCALSTORAGE _M30; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - UINT index; - CLEANLOCALSTORAGE __RPC_FAR *pDummy; - LPVARDESC __RPC_FAR *ppVarDesc; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - ppVarDesc = 0; - pDummy = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[170] ); - - index = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - ppVarDesc = &_M29; - _M29 = 0; - pDummy = &_M30; - MIDL_memset( - pDummy, - 0, - sizeof( CLEANLOCALSTORAGE )); - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeInfo_GetVarDesc_Stub( - (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, - index, - ppVarDesc, - pDummy); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 8U + 11U + 7U; - NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)ppVarDesc, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1464] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)ppVarDesc, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1464] ); - - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pDummy, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1676] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)ppVarDesc, - &__MIDL_TypeFormatString.Format[1464] ); - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pDummy, - &__MIDL_TypeFormatString.Format[1670] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_RemoteGetNames_Proxy( - ITypeInfo __RPC_FAR * This, - /* [in] */ MEMBERID memid, - /* [length_is][size_is][out] */ BSTR __RPC_FAR *rgBstrNames, - /* [in] */ UINT cMaxNames, - /* [out] */ UINT __RPC_FAR *pcNames) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(rgBstrNames) - { - MIDL_memset( - rgBstrNames, - 0, - cMaxNames * sizeof( BSTR )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 7); - - - - if(!rgBstrNames) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pcNames) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U + 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( MEMBERID __RPC_FAR * )_StubMsg.Buffer = memid; - _StubMsg.Buffer += sizeof(MEMBERID); - - *( UINT __RPC_FAR * )_StubMsg.Buffer = cMaxNames; - _StubMsg.Buffer += sizeof(UINT); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[182] ); - - NdrComplexArrayUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&rgBstrNames, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1690], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *pcNames = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - _StubMsg.MaxCount = cMaxNames; - _StubMsg.Offset = 0; - _StubMsg.ActualCount = _StubMsg.MaxCount; - - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1686], - ( void __RPC_FAR * )rgBstrNames); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], - ( void __RPC_FAR * )pcNames); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo_RemoteGetNames_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - UINT _M34; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - UINT cMaxNames; - MEMBERID memid; - UINT __RPC_FAR *pcNames; - BSTR __RPC_FAR *rgBstrNames; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - rgBstrNames = 0; - pcNames = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[182] ); - - memid = *( MEMBERID __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(MEMBERID); - - cMaxNames = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - rgBstrNames = NdrAllocate(&_StubMsg,cMaxNames * 4); - pcNames = &_M34; - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeInfo_GetNames_Stub( - (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, - memid, - rgBstrNames, - cMaxNames, - pcNames); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 12U + 7U + 7U; - _StubMsg.MaxCount = cMaxNames; - _StubMsg.Offset = 0; - _StubMsg.ActualCount = pcNames ? *pcNames : 0; - - NdrComplexArrayBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)rgBstrNames, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1690] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - _StubMsg.MaxCount = cMaxNames; - _StubMsg.Offset = 0; - _StubMsg.ActualCount = pcNames ? *pcNames : 0; - - NdrComplexArrayMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)rgBstrNames, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1690] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( UINT __RPC_FAR * )_StubMsg.Buffer = *pcNames; - _StubMsg.Buffer += sizeof(UINT); - - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - _StubMsg.MaxCount = cMaxNames; - _StubMsg.Offset = 0; - _StubMsg.ActualCount = pcNames ? *pcNames : 0; - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)rgBstrNames, - &__MIDL_TypeFormatString.Format[1686] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeInfo_GetRefTypeOfImplType_Proxy( - ITypeInfo __RPC_FAR * This, - /* [in] */ UINT index, - /* [out] */ HREFTYPE __RPC_FAR *pRefType) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 8); - - - - if(!pRefType) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( UINT __RPC_FAR * )_StubMsg.Buffer = index; - _StubMsg.Buffer += sizeof(UINT); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[196] ); - - *pRefType = *( HREFTYPE __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HREFTYPE); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], - ( void __RPC_FAR * )pRefType); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo_GetRefTypeOfImplType_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HREFTYPE _M35; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - UINT index; - HREFTYPE __RPC_FAR *pRefType; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pRefType = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[196] ); - - index = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - pRefType = &_M35; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetRefTypeOfImplType( - (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, - index, - pRefType); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U + 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( HREFTYPE __RPC_FAR * )_StubMsg.Buffer = *pRefType; - _StubMsg.Buffer += sizeof(HREFTYPE); - - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeInfo_GetImplTypeFlags_Proxy( - ITypeInfo __RPC_FAR * This, - /* [in] */ UINT index, - /* [out] */ INT __RPC_FAR *pImplTypeFlags) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 9); - - - - if(!pImplTypeFlags) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( UINT __RPC_FAR * )_StubMsg.Buffer = index; - _StubMsg.Buffer += sizeof(UINT); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[196] ); - - *pImplTypeFlags = *( INT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(INT); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], - ( void __RPC_FAR * )pImplTypeFlags); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo_GetImplTypeFlags_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - INT _M36; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - UINT index; - INT __RPC_FAR *pImplTypeFlags; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pImplTypeFlags = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[196] ); - - index = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - pImplTypeFlags = &_M36; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetImplTypeFlags( - (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, - index, - pImplTypeFlags); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U + 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( INT __RPC_FAR * )_StubMsg.Buffer = *pImplTypeFlags; - _StubMsg.Buffer += sizeof(INT); - - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_LocalGetIDsOfNames_Proxy( - ITypeInfo __RPC_FAR * This) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 10); - - - - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[88] ); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo_LocalGetIDsOfNames_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - RpcTryFinally - { - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeInfo_GetIDsOfNames_Stub((ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_LocalInvoke_Proxy( - ITypeInfo __RPC_FAR * This) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 11); - - - - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[88] ); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo_LocalInvoke_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - RpcTryFinally - { - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeInfo_Invoke_Stub((ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_RemoteGetDocumentation_Proxy( - ITypeInfo __RPC_FAR * This, - /* [in] */ MEMBERID memid, - /* [in] */ DWORD refPtrFlags, - /* [out] */ BSTR __RPC_FAR *pBstrName, - /* [out] */ BSTR __RPC_FAR *pBstrDocString, - /* [out] */ DWORD __RPC_FAR *pdwHelpContext, - /* [out] */ BSTR __RPC_FAR *pBstrHelpFile) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pBstrName) - { - MIDL_memset( - pBstrName, - 0, - sizeof( BSTR )); - } - if(pBstrDocString) - { - MIDL_memset( - pBstrDocString, - 0, - sizeof( BSTR )); - } - if(pBstrHelpFile) - { - MIDL_memset( - pBstrHelpFile, - 0, - sizeof( BSTR )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 12); - - - - if(!pBstrName) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pBstrDocString) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pdwHelpContext) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pBstrHelpFile) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U + 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( MEMBERID __RPC_FAR * )_StubMsg.Buffer = memid; - _StubMsg.Buffer += sizeof(MEMBERID); - - *( DWORD __RPC_FAR * )_StubMsg.Buffer = refPtrFlags; - _StubMsg.Buffer += sizeof(DWORD); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[204] ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], - (unsigned char)0 ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrDocString, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *pdwHelpContext = *( DWORD __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(DWORD); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrHelpFile, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], - ( void __RPC_FAR * )pBstrName); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], - ( void __RPC_FAR * )pBstrDocString); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], - ( void __RPC_FAR * )pdwHelpContext); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], - ( void __RPC_FAR * )pBstrHelpFile); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo_RemoteGetDocumentation_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - BSTR _M37; - BSTR _M38; - DWORD _M39; - BSTR _M40; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - MEMBERID memid; - BSTR __RPC_FAR *pBstrDocString; - BSTR __RPC_FAR *pBstrHelpFile; - BSTR __RPC_FAR *pBstrName; - DWORD __RPC_FAR *pdwHelpContext; - DWORD refPtrFlags; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pBstrName = 0; - pBstrDocString = 0; - pdwHelpContext = 0; - pBstrHelpFile = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[204] ); - - memid = *( MEMBERID __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(MEMBERID); - - refPtrFlags = *( DWORD __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(DWORD); - - pBstrName = &_M37; - MIDL_memset( - pBstrName, - 0, - sizeof( BSTR )); - pBstrDocString = &_M38; - MIDL_memset( - pBstrDocString, - 0, - sizeof( BSTR )); - pdwHelpContext = &_M39; - pBstrHelpFile = &_M40; - MIDL_memset( - pBstrHelpFile, - 0, - sizeof( BSTR )); - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeInfo_GetDocumentation_Stub( - (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, - memid, - refPtrFlags, - pBstrName, - pBstrDocString, - pdwHelpContext, - pBstrHelpFile); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 8U + 15U + 11U + 11U + 11U; - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pBstrName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pBstrDocString, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pBstrHelpFile, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pBstrName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pBstrDocString, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( DWORD __RPC_FAR * )_StubMsg.Buffer = *pdwHelpContext; - _StubMsg.Buffer += sizeof(DWORD); - - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pBstrHelpFile, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pBstrName, - &__MIDL_TypeFormatString.Format[1708] ); - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pBstrDocString, - &__MIDL_TypeFormatString.Format[1708] ); - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pBstrHelpFile, - &__MIDL_TypeFormatString.Format[1708] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_RemoteGetDllEntry_Proxy( - ITypeInfo __RPC_FAR * This, - /* [in] */ MEMBERID memid, - /* [in] */ INVOKEKIND invKind, - /* [in] */ DWORD refPtrFlags, - /* [out] */ BSTR __RPC_FAR *pBstrDllName, - /* [out] */ BSTR __RPC_FAR *pBstrName, - /* [out] */ WORD __RPC_FAR *pwOrdinal) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pBstrDllName) - { - MIDL_memset( - pBstrDllName, - 0, - sizeof( BSTR )); - } - if(pBstrName) - { - MIDL_memset( - pBstrName, - 0, - sizeof( BSTR )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 13); - - - - if(!pBstrDllName) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pBstrName) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pwOrdinal) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U + 4U + 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( MEMBERID __RPC_FAR * )_StubMsg.Buffer = memid; - _StubMsg.Buffer += sizeof(MEMBERID); - - NdrSimpleTypeMarshall( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( unsigned char __RPC_FAR * )&invKind, - 14); - *( DWORD __RPC_FAR * )_StubMsg.Buffer = refPtrFlags; - _StubMsg.Buffer += sizeof(DWORD); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[226] ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrDllName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], - (unsigned char)0 ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 1) & ~ 0x1); - *pwOrdinal = *( WORD __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(WORD); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], - ( void __RPC_FAR * )pBstrDllName); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], - ( void __RPC_FAR * )pBstrName); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1712], - ( void __RPC_FAR * )pwOrdinal); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo_RemoteGetDllEntry_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - BSTR _M41; - BSTR _M42; - WORD _M43; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - INVOKEKIND invKind; - MEMBERID memid; - BSTR __RPC_FAR *pBstrDllName; - BSTR __RPC_FAR *pBstrName; - WORD __RPC_FAR *pwOrdinal; - DWORD refPtrFlags; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pBstrDllName = 0; - pBstrName = 0; - pwOrdinal = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[226] ); - - memid = *( MEMBERID __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(MEMBERID); - - NdrSimpleTypeUnmarshall( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( unsigned char __RPC_FAR * )&invKind, - 14); - refPtrFlags = *( DWORD __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(DWORD); - - pBstrDllName = &_M41; - MIDL_memset( - pBstrDllName, - 0, - sizeof( BSTR )); - pBstrName = &_M42; - MIDL_memset( - pBstrName, - 0, - sizeof( BSTR )); - pwOrdinal = &_M43; - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeInfo_GetDllEntry_Stub( - (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, - memid, - invKind, - refPtrFlags, - pBstrDllName, - pBstrName, - pwOrdinal); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 8U + 15U + 5U + 10U; - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pBstrDllName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pBstrName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pBstrDllName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pBstrName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 1) & ~ 0x1); - *( WORD __RPC_FAR * )_StubMsg.Buffer = *pwOrdinal; - _StubMsg.Buffer += sizeof(WORD); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pBstrDllName, - &__MIDL_TypeFormatString.Format[1708] ); - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pBstrName, - &__MIDL_TypeFormatString.Format[1708] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeInfo_GetRefTypeInfo_Proxy( - ITypeInfo __RPC_FAR * This, - /* [in] */ HREFTYPE hRefType, - /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(ppTInfo) - { - MIDL_memset( - ppTInfo, - 0, - sizeof( ITypeInfo __RPC_FAR *__RPC_FAR * )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 14); - - - - if(!ppTInfo) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( HREFTYPE __RPC_FAR * )_StubMsg.Buffer = hRefType; - _StubMsg.Buffer += sizeof(HREFTYPE); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[246] ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&ppTInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[6], - ( void __RPC_FAR * )ppTInfo); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo_GetRefTypeInfo_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - ITypeInfo __RPC_FAR *_M44; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - HREFTYPE hRefType; - ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - ppTInfo = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[246] ); - - hRefType = *( HREFTYPE __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HREFTYPE); - - ppTInfo = &_M44; - _M44 = 0; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetRefTypeInfo( - (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, - hRefType, - ppTInfo); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 0U + 4U; - NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)ppTInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)ppTInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)ppTInfo, - &__MIDL_TypeFormatString.Format[6] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_LocalAddressOfMember_Proxy( - ITypeInfo __RPC_FAR * This) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 15); - - - - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[88] ); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo_LocalAddressOfMember_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - RpcTryFinally - { - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeInfo_AddressOfMember_Stub((ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_RemoteCreateInstance_Proxy( - ITypeInfo __RPC_FAR * This, - /* [in] */ REFIID riid, - /* [iid_is][out] */ IUnknown __RPC_FAR *__RPC_FAR *ppvObj) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(ppvObj) - { - MIDL_memset( - ppvObj, - 0, - sizeof( IUnknown __RPC_FAR *__RPC_FAR * )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 16); - - - - if(!riid) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!ppvObj) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)riid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxyGetBuffer(This, &_StubMsg); - NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)riid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[254] ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&ppvObj, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1716], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - _StubMsg.MaxCount = (unsigned long) ( riid ); - - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1716], - ( void __RPC_FAR * )ppvObj); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo_RemoteCreateInstance_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - IUnknown __RPC_FAR *__RPC_FAR *_M45; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - IUnknown __RPC_FAR *__RPC_FAR *ppvObj; - IID* riid = 0; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - ppvObj = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[254] ); - - NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&riid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], - (unsigned char)0 ); - - ppvObj = (void *)&_M45; - _M45 = 0; - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeInfo_CreateInstance_Stub( - (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, - riid, - ppvObj); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 0U + 4U; - _StubMsg.MaxCount = (unsigned long) ( riid ); - - NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)ppvObj, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1716] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - _StubMsg.MaxCount = (unsigned long) ( riid ); - - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)ppvObj, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1716] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - _StubMsg.MaxCount = (unsigned long) ( riid ); - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)ppvObj, - &__MIDL_TypeFormatString.Format[1716] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeInfo_GetMops_Proxy( - ITypeInfo __RPC_FAR * This, - /* [in] */ MEMBERID memid, - /* [out] */ BSTR __RPC_FAR *pBstrMops) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pBstrMops) - { - MIDL_memset( - pBstrMops, - 0, - sizeof( BSTR )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 17); - - - - if(!pBstrMops) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( MEMBERID __RPC_FAR * )_StubMsg.Buffer = memid; - _StubMsg.Buffer += sizeof(MEMBERID); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[264] ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrMops, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], - ( void __RPC_FAR * )pBstrMops); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo_GetMops_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - BSTR _M46; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - MEMBERID memid; - BSTR __RPC_FAR *pBstrMops; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pBstrMops = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[264] ); - - memid = *( MEMBERID __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(MEMBERID); - - pBstrMops = &_M46; - MIDL_memset( - pBstrMops, - 0, - sizeof( BSTR )); - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetMops( - (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, - memid, - pBstrMops); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 8U + 11U; - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pBstrMops, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pBstrMops, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pBstrMops, - &__MIDL_TypeFormatString.Format[1708] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_RemoteGetContainingTypeLib_Proxy( - ITypeInfo __RPC_FAR * This, - /* [out] */ ITypeLib __RPC_FAR *__RPC_FAR *ppTLib, - /* [out] */ UINT __RPC_FAR *pIndex) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(ppTLib) - { - MIDL_memset( - ppTLib, - 0, - sizeof( ITypeLib __RPC_FAR *__RPC_FAR * )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 18); - - - - if(!ppTLib) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pIndex) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[272] ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&ppTLib, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1726], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *pIndex = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1726], - ( void __RPC_FAR * )ppTLib); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], - ( void __RPC_FAR * )pIndex); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo_RemoteGetContainingTypeLib_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - ITypeLib __RPC_FAR *_M47; - UINT _M48; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - UINT __RPC_FAR *pIndex; - ITypeLib __RPC_FAR *__RPC_FAR *ppTLib; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - ppTLib = 0; - pIndex = 0; - RpcTryFinally - { - ppTLib = &_M47; - _M47 = 0; - pIndex = &_M48; - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeInfo_GetContainingTypeLib_Stub( - (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, - ppTLib, - pIndex); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 0U + 4U + 4U; - NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)ppTLib, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1726] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)ppTLib, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1726] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( UINT __RPC_FAR * )_StubMsg.Buffer = *pIndex; - _StubMsg.Buffer += sizeof(UINT); - - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)ppTLib, - &__MIDL_TypeFormatString.Format[1726] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_LocalReleaseTypeAttr_Proxy( - ITypeInfo __RPC_FAR * This) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 19); - - - - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[88] ); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo_LocalReleaseTypeAttr_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - RpcTryFinally - { - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeInfo_ReleaseTypeAttr_Stub((ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_LocalReleaseFuncDesc_Proxy( - ITypeInfo __RPC_FAR * This) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 20); - - - - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[88] ); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo_LocalReleaseFuncDesc_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - RpcTryFinally - { - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeInfo_ReleaseFuncDesc_Stub((ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_LocalReleaseVarDesc_Proxy( - ITypeInfo __RPC_FAR * This) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 21); - - - - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[88] ); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo_LocalReleaseVarDesc_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - RpcTryFinally - { - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeInfo_ReleaseVarDesc_Stub((ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - -const CINTERFACE_PROXY_VTABLE(22) _ITypeInfoProxyVtbl = -{ - { &IID_ITypeInfo }, - { - IUnknown_QueryInterface_Proxy, - IUnknown_AddRef_Proxy, - IUnknown_Release_Proxy , - ITypeInfo_GetTypeAttr_Proxy , - ITypeInfo_GetTypeComp_Proxy , - ITypeInfo_GetFuncDesc_Proxy , - ITypeInfo_GetVarDesc_Proxy , - ITypeInfo_GetNames_Proxy , - ITypeInfo_GetRefTypeOfImplType_Proxy , - ITypeInfo_GetImplTypeFlags_Proxy , - ITypeInfo_GetIDsOfNames_Proxy , - ITypeInfo_Invoke_Proxy , - ITypeInfo_GetDocumentation_Proxy , - ITypeInfo_GetDllEntry_Proxy , - ITypeInfo_GetRefTypeInfo_Proxy , - ITypeInfo_AddressOfMember_Proxy , - ITypeInfo_CreateInstance_Proxy , - ITypeInfo_GetMops_Proxy , - ITypeInfo_GetContainingTypeLib_Proxy , - ITypeInfo_ReleaseTypeAttr_Proxy , - ITypeInfo_ReleaseFuncDesc_Proxy , - ITypeInfo_ReleaseVarDesc_Proxy - } -}; - - -static const PRPC_STUB_FUNCTION ITypeInfo_table[] = -{ - ITypeInfo_RemoteGetTypeAttr_Stub, - ITypeInfo_GetTypeComp_Stub, - ITypeInfo_RemoteGetFuncDesc_Stub, - ITypeInfo_RemoteGetVarDesc_Stub, - ITypeInfo_RemoteGetNames_Stub, - ITypeInfo_GetRefTypeOfImplType_Stub, - ITypeInfo_GetImplTypeFlags_Stub, - ITypeInfo_LocalGetIDsOfNames_Stub, - ITypeInfo_LocalInvoke_Stub, - ITypeInfo_RemoteGetDocumentation_Stub, - ITypeInfo_RemoteGetDllEntry_Stub, - ITypeInfo_GetRefTypeInfo_Stub, - ITypeInfo_LocalAddressOfMember_Stub, - ITypeInfo_RemoteCreateInstance_Stub, - ITypeInfo_GetMops_Stub, - ITypeInfo_RemoteGetContainingTypeLib_Stub, - ITypeInfo_LocalReleaseTypeAttr_Stub, - ITypeInfo_LocalReleaseFuncDesc_Stub, - ITypeInfo_LocalReleaseVarDesc_Stub -}; - -const CInterfaceStubVtbl _ITypeInfoStubVtbl = -{ - { - &IID_ITypeInfo, - 0, - 22, - &ITypeInfo_table[-3] - }, - { CStdStubBuffer_METHODS } -}; - - -/* Object interface: ITypeInfo2, ver. 0.0, - GUID={0x00020412,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ - - -extern const MIDL_STUB_DESC Object_StubDesc; - - -HRESULT STDMETHODCALLTYPE ITypeInfo2_GetTypeKind_Proxy( - ITypeInfo2 __RPC_FAR * This, - /* [out] */ TYPEKIND __RPC_FAR *pTypeKind) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 22); - - - - if(!pTypeKind) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[282] ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pTypeKind, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1250], - (unsigned char)0 ); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1250], - ( void __RPC_FAR * )pTypeKind); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo2_GetTypeKind_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - TYPEKIND _M49; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - TYPEKIND __RPC_FAR *pTypeKind; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pTypeKind = 0; - RpcTryFinally - { - pTypeKind = &_M49; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetTypeKind((ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject,pTypeKind); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U + 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pTypeKind, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1250] ); - - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeInfo2_GetTypeFlags_Proxy( - ITypeInfo2 __RPC_FAR * This, - /* [out] */ ULONG __RPC_FAR *pTypeFlags) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 23); - - - - if(!pTypeFlags) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[0] ); - - *pTypeFlags = *( ULONG __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(ULONG); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], - ( void __RPC_FAR * )pTypeFlags); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo2_GetTypeFlags_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - ULONG _M50; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - ULONG __RPC_FAR *pTypeFlags; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pTypeFlags = 0; - RpcTryFinally - { - pTypeFlags = &_M50; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetTypeFlags((ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject,pTypeFlags); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U + 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( ULONG __RPC_FAR * )_StubMsg.Buffer = *pTypeFlags; - _StubMsg.Buffer += sizeof(ULONG); - - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeInfo2_GetFuncIndexOfMemId_Proxy( - ITypeInfo2 __RPC_FAR * This, - /* [in] */ MEMBERID memid, - /* [in] */ INVOKEKIND invKind, - /* [out] */ UINT __RPC_FAR *pFuncIndex) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 24); - - - - if(!pFuncIndex) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U + 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( MEMBERID __RPC_FAR * )_StubMsg.Buffer = memid; - _StubMsg.Buffer += sizeof(MEMBERID); - - NdrSimpleTypeMarshall( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( unsigned char __RPC_FAR * )&invKind, - 14); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[288] ); - - *pFuncIndex = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], - ( void __RPC_FAR * )pFuncIndex); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo2_GetFuncIndexOfMemId_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - UINT _M51; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - INVOKEKIND invKind; - MEMBERID memid; - UINT __RPC_FAR *pFuncIndex; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pFuncIndex = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[288] ); - - memid = *( MEMBERID __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(MEMBERID); - - NdrSimpleTypeUnmarshall( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( unsigned char __RPC_FAR * )&invKind, - 14); - pFuncIndex = &_M51; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetFuncIndexOfMemId( - (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, - memid, - invKind, - pFuncIndex); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U + 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( UINT __RPC_FAR * )_StubMsg.Buffer = *pFuncIndex; - _StubMsg.Buffer += sizeof(UINT); - - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeInfo2_GetVarIndexOfMemId_Proxy( - ITypeInfo2 __RPC_FAR * This, - /* [in] */ MEMBERID memid, - /* [out] */ UINT __RPC_FAR *pVarIndex) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 25); - - - - if(!pVarIndex) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( MEMBERID __RPC_FAR * )_StubMsg.Buffer = memid; - _StubMsg.Buffer += sizeof(MEMBERID); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[196] ); - - *pVarIndex = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], - ( void __RPC_FAR * )pVarIndex); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo2_GetVarIndexOfMemId_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - UINT _M52; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - MEMBERID memid; - UINT __RPC_FAR *pVarIndex; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pVarIndex = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[196] ); - - memid = *( MEMBERID __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(MEMBERID); - - pVarIndex = &_M52; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetVarIndexOfMemId( - (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, - memid, - pVarIndex); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U + 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( UINT __RPC_FAR * )_StubMsg.Buffer = *pVarIndex; - _StubMsg.Buffer += sizeof(UINT); - - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeInfo2_GetCustData_Proxy( - ITypeInfo2 __RPC_FAR * This, - /* [in] */ REFGUID guid, - /* [out] */ VARIANT __RPC_FAR *pVarVal) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pVarVal) - { - MIDL_memset( - pVarVal, - 0, - sizeof( VARIANT )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 26); - - - - if(!guid) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pVarVal) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)guid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxyGetBuffer(This, &_StubMsg); - NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)guid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[298] ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pVarVal, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1102], - ( void __RPC_FAR * )pVarVal); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo2_GetCustData_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - VARIANT _M53; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - REFGUID guid = 0; - VARIANT __RPC_FAR *pVarVal; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pVarVal = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[298] ); - - NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&guid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], - (unsigned char)0 ); - - pVarVal = &_M53; - MIDL_memset( - pVarVal, - 0, - sizeof( VARIANT )); - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetCustData( - (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, - guid, - pVarVal); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 8U + 11U; - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pVarVal, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pVarVal, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pVarVal, - &__MIDL_TypeFormatString.Format[1102] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeInfo2_GetFuncCustData_Proxy( - ITypeInfo2 __RPC_FAR * This, - /* [in] */ UINT index, - /* [in] */ REFGUID guid, - /* [out] */ VARIANT __RPC_FAR *pVarVal) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pVarVal) - { - MIDL_memset( - pVarVal, - 0, - sizeof( VARIANT )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 27); - - - - if(!guid) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pVarVal) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U + 4U; - NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)guid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxyGetBuffer(This, &_StubMsg); - *( UINT __RPC_FAR * )_StubMsg.Buffer = index; - _StubMsg.Buffer += sizeof(UINT); - - NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)guid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[308] ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pVarVal, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1102], - ( void __RPC_FAR * )pVarVal); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo2_GetFuncCustData_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - VARIANT _M54; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - REFGUID guid = 0; - UINT index; - VARIANT __RPC_FAR *pVarVal; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pVarVal = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[308] ); - - index = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&guid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], - (unsigned char)0 ); - - pVarVal = &_M54; - MIDL_memset( - pVarVal, - 0, - sizeof( VARIANT )); - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetFuncCustData( - (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, - index, - guid, - pVarVal); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 8U + 11U; - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pVarVal, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pVarVal, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pVarVal, - &__MIDL_TypeFormatString.Format[1102] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeInfo2_GetParamCustData_Proxy( - ITypeInfo2 __RPC_FAR * This, - /* [in] */ UINT indexFunc, - /* [in] */ UINT indexParam, - /* [in] */ REFGUID guid, - /* [out] */ VARIANT __RPC_FAR *pVarVal) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pVarVal) - { - MIDL_memset( - pVarVal, - 0, - sizeof( VARIANT )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 28); - - - - if(!guid) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pVarVal) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U + 4U + 0U; - NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)guid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxyGetBuffer(This, &_StubMsg); - *( UINT __RPC_FAR * )_StubMsg.Buffer = indexFunc; - _StubMsg.Buffer += sizeof(UINT); - - *( UINT __RPC_FAR * )_StubMsg.Buffer = indexParam; - _StubMsg.Buffer += sizeof(UINT); - - NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)guid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[320] ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pVarVal, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1102], - ( void __RPC_FAR * )pVarVal); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo2_GetParamCustData_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - VARIANT _M55; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - REFGUID guid = 0; - UINT indexFunc; - UINT indexParam; - VARIANT __RPC_FAR *pVarVal; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pVarVal = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[320] ); - - indexFunc = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - indexParam = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&guid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], - (unsigned char)0 ); - - pVarVal = &_M55; - MIDL_memset( - pVarVal, - 0, - sizeof( VARIANT )); - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetParamCustData( - (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, - indexFunc, - indexParam, - guid, - pVarVal); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 8U + 11U; - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pVarVal, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pVarVal, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pVarVal, - &__MIDL_TypeFormatString.Format[1102] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeInfo2_GetVarCustData_Proxy( - ITypeInfo2 __RPC_FAR * This, - /* [in] */ UINT index, - /* [in] */ REFGUID guid, - /* [out] */ VARIANT __RPC_FAR *pVarVal) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pVarVal) - { - MIDL_memset( - pVarVal, - 0, - sizeof( VARIANT )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 29); - - - - if(!guid) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pVarVal) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U + 4U; - NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)guid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxyGetBuffer(This, &_StubMsg); - *( UINT __RPC_FAR * )_StubMsg.Buffer = index; - _StubMsg.Buffer += sizeof(UINT); - - NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)guid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[308] ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pVarVal, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1102], - ( void __RPC_FAR * )pVarVal); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo2_GetVarCustData_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - VARIANT _M56; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - REFGUID guid = 0; - UINT index; - VARIANT __RPC_FAR *pVarVal; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pVarVal = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[308] ); - - index = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&guid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], - (unsigned char)0 ); - - pVarVal = &_M56; - MIDL_memset( - pVarVal, - 0, - sizeof( VARIANT )); - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetVarCustData( - (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, - index, - guid, - pVarVal); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 8U + 11U; - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pVarVal, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pVarVal, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pVarVal, - &__MIDL_TypeFormatString.Format[1102] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeInfo2_GetImplTypeCustData_Proxy( - ITypeInfo2 __RPC_FAR * This, - /* [in] */ UINT index, - /* [in] */ REFGUID guid, - /* [out] */ VARIANT __RPC_FAR *pVarVal) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pVarVal) - { - MIDL_memset( - pVarVal, - 0, - sizeof( VARIANT )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 30); - - - - if(!guid) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pVarVal) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U + 4U; - NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)guid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxyGetBuffer(This, &_StubMsg); - *( UINT __RPC_FAR * )_StubMsg.Buffer = index; - _StubMsg.Buffer += sizeof(UINT); - - NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)guid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[308] ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pVarVal, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1102], - ( void __RPC_FAR * )pVarVal); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo2_GetImplTypeCustData_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - VARIANT _M57; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - REFGUID guid = 0; - UINT index; - VARIANT __RPC_FAR *pVarVal; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pVarVal = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[308] ); - - index = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&guid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], - (unsigned char)0 ); - - pVarVal = &_M57; - MIDL_memset( - pVarVal, - 0, - sizeof( VARIANT )); - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetImplTypeCustData( - (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, - index, - guid, - pVarVal); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 8U + 11U; - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pVarVal, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pVarVal, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pVarVal, - &__MIDL_TypeFormatString.Format[1102] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo2_RemoteGetDocumentation2_Proxy( - ITypeInfo2 __RPC_FAR * This, - /* [in] */ MEMBERID memid, - /* [in] */ LCID lcid, - /* [in] */ DWORD refPtrFlags, - /* [out] */ BSTR __RPC_FAR *pbstrHelpString, - /* [out] */ DWORD __RPC_FAR *pdwHelpStringContext, - /* [out] */ BSTR __RPC_FAR *pbstrHelpStringDll) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pbstrHelpString) - { - MIDL_memset( - pbstrHelpString, - 0, - sizeof( BSTR )); - } - if(pbstrHelpStringDll) - { - MIDL_memset( - pbstrHelpStringDll, - 0, - sizeof( BSTR )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 31); - - - - if(!pbstrHelpString) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pdwHelpStringContext) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pbstrHelpStringDll) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U + 4U + 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( MEMBERID __RPC_FAR * )_StubMsg.Buffer = memid; - _StubMsg.Buffer += sizeof(MEMBERID); - - *( LCID __RPC_FAR * )_StubMsg.Buffer = lcid; - _StubMsg.Buffer += sizeof(LCID); - - *( DWORD __RPC_FAR * )_StubMsg.Buffer = refPtrFlags; - _StubMsg.Buffer += sizeof(DWORD); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[334] ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pbstrHelpString, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *pdwHelpStringContext = *( DWORD __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(DWORD); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pbstrHelpStringDll, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], - ( void __RPC_FAR * )pbstrHelpString); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], - ( void __RPC_FAR * )pdwHelpStringContext); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], - ( void __RPC_FAR * )pbstrHelpStringDll); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo2_RemoteGetDocumentation2_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - BSTR _M58; - DWORD _M59; - BSTR _M60; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - LCID lcid; - MEMBERID memid; - BSTR __RPC_FAR *pbstrHelpString; - BSTR __RPC_FAR *pbstrHelpStringDll; - DWORD __RPC_FAR *pdwHelpStringContext; - DWORD refPtrFlags; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pbstrHelpString = 0; - pdwHelpStringContext = 0; - pbstrHelpStringDll = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[334] ); - - memid = *( MEMBERID __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(MEMBERID); - - lcid = *( LCID __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(LCID); - - refPtrFlags = *( DWORD __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(DWORD); - - pbstrHelpString = &_M58; - MIDL_memset( - pbstrHelpString, - 0, - sizeof( BSTR )); - pdwHelpStringContext = &_M59; - pbstrHelpStringDll = &_M60; - MIDL_memset( - pbstrHelpStringDll, - 0, - sizeof( BSTR )); - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeInfo2_GetDocumentation2_Stub( - (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, - memid, - lcid, - refPtrFlags, - pbstrHelpString, - pdwHelpStringContext, - pbstrHelpStringDll); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 8U + 11U + 11U + 11U; - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pbstrHelpString, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pbstrHelpStringDll, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pbstrHelpString, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( DWORD __RPC_FAR * )_StubMsg.Buffer = *pdwHelpStringContext; - _StubMsg.Buffer += sizeof(DWORD); - - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pbstrHelpStringDll, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pbstrHelpString, - &__MIDL_TypeFormatString.Format[1708] ); - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pbstrHelpStringDll, - &__MIDL_TypeFormatString.Format[1708] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeInfo2_GetAllCustData_Proxy( - ITypeInfo2 __RPC_FAR * This, - /* [out] */ CUSTDATA __RPC_FAR *pCustData) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pCustData) - { - MIDL_memset( - pCustData, - 0, - sizeof( CUSTDATA )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 32); - - - - if(!pCustData) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[354] ); - - NdrComplexStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pCustData, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1748], - ( void __RPC_FAR * )pCustData); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo2_GetAllCustData_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - CUSTDATA _pCustDataM; - CUSTDATA __RPC_FAR *pCustData; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pCustData = 0; - RpcTryFinally - { - pCustData = &_pCustDataM; - pCustData -> prgCustData = 0; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetAllCustData((ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject,pCustData); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 0U + 11U; - NdrComplexStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pCustData, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrComplexStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pCustData, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pCustData, - &__MIDL_TypeFormatString.Format[1748] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeInfo2_GetAllFuncCustData_Proxy( - ITypeInfo2 __RPC_FAR * This, - /* [in] */ UINT index, - /* [out] */ CUSTDATA __RPC_FAR *pCustData) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pCustData) - { - MIDL_memset( - pCustData, - 0, - sizeof( CUSTDATA )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 33); - - - - if(!pCustData) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( UINT __RPC_FAR * )_StubMsg.Buffer = index; - _StubMsg.Buffer += sizeof(UINT); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[360] ); - - NdrComplexStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pCustData, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1748], - ( void __RPC_FAR * )pCustData); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo2_GetAllFuncCustData_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - CUSTDATA _pCustDataM; - UINT index; - CUSTDATA __RPC_FAR *pCustData; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pCustData = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[360] ); - - index = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - pCustData = &_pCustDataM; - pCustData -> prgCustData = 0; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetAllFuncCustData( - (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, - index, - pCustData); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 0U + 11U; - NdrComplexStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pCustData, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrComplexStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pCustData, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pCustData, - &__MIDL_TypeFormatString.Format[1748] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeInfo2_GetAllParamCustData_Proxy( - ITypeInfo2 __RPC_FAR * This, - /* [in] */ UINT indexFunc, - /* [in] */ UINT indexParam, - /* [out] */ CUSTDATA __RPC_FAR *pCustData) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pCustData) - { - MIDL_memset( - pCustData, - 0, - sizeof( CUSTDATA )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 34); - - - - if(!pCustData) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U + 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( UINT __RPC_FAR * )_StubMsg.Buffer = indexFunc; - _StubMsg.Buffer += sizeof(UINT); - - *( UINT __RPC_FAR * )_StubMsg.Buffer = indexParam; - _StubMsg.Buffer += sizeof(UINT); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[368] ); - - NdrComplexStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pCustData, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1748], - ( void __RPC_FAR * )pCustData); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo2_GetAllParamCustData_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - CUSTDATA _pCustDataM; - UINT indexFunc; - UINT indexParam; - CUSTDATA __RPC_FAR *pCustData; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pCustData = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[368] ); - - indexFunc = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - indexParam = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - pCustData = &_pCustDataM; - pCustData -> prgCustData = 0; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetAllParamCustData( - (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, - indexFunc, - indexParam, - pCustData); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 0U + 11U; - NdrComplexStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pCustData, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrComplexStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pCustData, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pCustData, - &__MIDL_TypeFormatString.Format[1748] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeInfo2_GetAllVarCustData_Proxy( - ITypeInfo2 __RPC_FAR * This, - /* [in] */ UINT index, - /* [out] */ CUSTDATA __RPC_FAR *pCustData) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pCustData) - { - MIDL_memset( - pCustData, - 0, - sizeof( CUSTDATA )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 35); - - - - if(!pCustData) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( UINT __RPC_FAR * )_StubMsg.Buffer = index; - _StubMsg.Buffer += sizeof(UINT); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[360] ); - - NdrComplexStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pCustData, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1748], - ( void __RPC_FAR * )pCustData); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo2_GetAllVarCustData_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - CUSTDATA _pCustDataM; - UINT index; - CUSTDATA __RPC_FAR *pCustData; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pCustData = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[360] ); - - index = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - pCustData = &_pCustDataM; - pCustData -> prgCustData = 0; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetAllVarCustData( - (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, - index, - pCustData); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 0U + 11U; - NdrComplexStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pCustData, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrComplexStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pCustData, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pCustData, - &__MIDL_TypeFormatString.Format[1748] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeInfo2_GetAllImplTypeCustData_Proxy( - ITypeInfo2 __RPC_FAR * This, - /* [in] */ UINT index, - /* [out] */ CUSTDATA __RPC_FAR *pCustData) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pCustData) - { - MIDL_memset( - pCustData, - 0, - sizeof( CUSTDATA )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 36); - - - - if(!pCustData) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( UINT __RPC_FAR * )_StubMsg.Buffer = index; - _StubMsg.Buffer += sizeof(UINT); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[360] ); - - NdrComplexStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pCustData, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1748], - ( void __RPC_FAR * )pCustData); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeInfo2_GetAllImplTypeCustData_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - CUSTDATA _pCustDataM; - UINT index; - CUSTDATA __RPC_FAR *pCustData; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pCustData = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[360] ); - - index = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - pCustData = &_pCustDataM; - pCustData -> prgCustData = 0; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetAllImplTypeCustData( - (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, - index, - pCustData); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 0U + 11U; - NdrComplexStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pCustData, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrComplexStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pCustData, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pCustData, - &__MIDL_TypeFormatString.Format[1748] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - -const CINTERFACE_PROXY_VTABLE(37) _ITypeInfo2ProxyVtbl = -{ - { &IID_ITypeInfo2 }, - { - IUnknown_QueryInterface_Proxy, - IUnknown_AddRef_Proxy, - IUnknown_Release_Proxy , - ITypeInfo_GetTypeAttr_Proxy , - ITypeInfo_GetTypeComp_Proxy , - ITypeInfo_GetFuncDesc_Proxy , - ITypeInfo_GetVarDesc_Proxy , - ITypeInfo_GetNames_Proxy , - ITypeInfo_GetRefTypeOfImplType_Proxy , - ITypeInfo_GetImplTypeFlags_Proxy , - ITypeInfo_GetIDsOfNames_Proxy , - ITypeInfo_Invoke_Proxy , - ITypeInfo_GetDocumentation_Proxy , - ITypeInfo_GetDllEntry_Proxy , - ITypeInfo_GetRefTypeInfo_Proxy , - ITypeInfo_AddressOfMember_Proxy , - ITypeInfo_CreateInstance_Proxy , - ITypeInfo_GetMops_Proxy , - ITypeInfo_GetContainingTypeLib_Proxy , - ITypeInfo_ReleaseTypeAttr_Proxy , - ITypeInfo_ReleaseFuncDesc_Proxy , - ITypeInfo_ReleaseVarDesc_Proxy , - ITypeInfo2_GetTypeKind_Proxy , - ITypeInfo2_GetTypeFlags_Proxy , - ITypeInfo2_GetFuncIndexOfMemId_Proxy , - ITypeInfo2_GetVarIndexOfMemId_Proxy , - ITypeInfo2_GetCustData_Proxy , - ITypeInfo2_GetFuncCustData_Proxy , - ITypeInfo2_GetParamCustData_Proxy , - ITypeInfo2_GetVarCustData_Proxy , - ITypeInfo2_GetImplTypeCustData_Proxy , - ITypeInfo2_GetDocumentation2_Proxy , - ITypeInfo2_GetAllCustData_Proxy , - ITypeInfo2_GetAllFuncCustData_Proxy , - ITypeInfo2_GetAllParamCustData_Proxy , - ITypeInfo2_GetAllVarCustData_Proxy , - ITypeInfo2_GetAllImplTypeCustData_Proxy - } -}; - - -static const PRPC_STUB_FUNCTION ITypeInfo2_table[] = -{ - ITypeInfo_RemoteGetTypeAttr_Stub, - ITypeInfo_GetTypeComp_Stub, - ITypeInfo_RemoteGetFuncDesc_Stub, - ITypeInfo_RemoteGetVarDesc_Stub, - ITypeInfo_RemoteGetNames_Stub, - ITypeInfo_GetRefTypeOfImplType_Stub, - ITypeInfo_GetImplTypeFlags_Stub, - ITypeInfo_LocalGetIDsOfNames_Stub, - ITypeInfo_LocalInvoke_Stub, - ITypeInfo_RemoteGetDocumentation_Stub, - ITypeInfo_RemoteGetDllEntry_Stub, - ITypeInfo_GetRefTypeInfo_Stub, - ITypeInfo_LocalAddressOfMember_Stub, - ITypeInfo_RemoteCreateInstance_Stub, - ITypeInfo_GetMops_Stub, - ITypeInfo_RemoteGetContainingTypeLib_Stub, - ITypeInfo_LocalReleaseTypeAttr_Stub, - ITypeInfo_LocalReleaseFuncDesc_Stub, - ITypeInfo_LocalReleaseVarDesc_Stub, - ITypeInfo2_GetTypeKind_Stub, - ITypeInfo2_GetTypeFlags_Stub, - ITypeInfo2_GetFuncIndexOfMemId_Stub, - ITypeInfo2_GetVarIndexOfMemId_Stub, - ITypeInfo2_GetCustData_Stub, - ITypeInfo2_GetFuncCustData_Stub, - ITypeInfo2_GetParamCustData_Stub, - ITypeInfo2_GetVarCustData_Stub, - ITypeInfo2_GetImplTypeCustData_Stub, - ITypeInfo2_RemoteGetDocumentation2_Stub, - ITypeInfo2_GetAllCustData_Stub, - ITypeInfo2_GetAllFuncCustData_Stub, - ITypeInfo2_GetAllParamCustData_Stub, - ITypeInfo2_GetAllVarCustData_Stub, - ITypeInfo2_GetAllImplTypeCustData_Stub -}; - -const CInterfaceStubVtbl _ITypeInfo2StubVtbl = -{ - { - &IID_ITypeInfo2, - 0, - 37, - &ITypeInfo2_table[-3] - }, - { CStdStubBuffer_METHODS } -}; - - -/* Object interface: ITypeLib, ver. 0.0, - GUID={0x00020402,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ - - -extern const MIDL_STUB_DESC Object_StubDesc; - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeLib_RemoteGetTypeInfoCount_Proxy( - ITypeLib __RPC_FAR * This, - /* [out] */ UINT __RPC_FAR *pcTInfo) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 3); - - - - if(!pcTInfo) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[0] ); - - *pcTInfo = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], - ( void __RPC_FAR * )pcTInfo); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeLib_RemoteGetTypeInfoCount_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - UINT _M61; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - UINT __RPC_FAR *pcTInfo; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pcTInfo = 0; - RpcTryFinally - { - pcTInfo = &_M61; - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeLib_GetTypeInfoCount_Stub((ITypeLib *) ((CStdStubBuffer *)This)->pvServerObject,pcTInfo); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U + 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( UINT __RPC_FAR * )_StubMsg.Buffer = *pcTInfo; - _StubMsg.Buffer += sizeof(UINT); - - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeLib_GetTypeInfo_Proxy( - ITypeLib __RPC_FAR * This, - /* [in] */ UINT index, - /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(ppTInfo) - { - MIDL_memset( - ppTInfo, - 0, - sizeof( ITypeInfo __RPC_FAR *__RPC_FAR * )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 4); - - - - if(!ppTInfo) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( UINT __RPC_FAR * )_StubMsg.Buffer = index; - _StubMsg.Buffer += sizeof(UINT); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[246] ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&ppTInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[6], - ( void __RPC_FAR * )ppTInfo); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeLib_GetTypeInfo_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - ITypeInfo __RPC_FAR *_M62; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - UINT index; - ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - ppTInfo = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[246] ); - - index = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - ppTInfo = &_M62; - _M62 = 0; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeLib*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetTypeInfo( - (ITypeLib *) ((CStdStubBuffer *)This)->pvServerObject, - index, - ppTInfo); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 0U + 4U; - NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)ppTInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)ppTInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)ppTInfo, - &__MIDL_TypeFormatString.Format[6] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeLib_GetTypeInfoType_Proxy( - ITypeLib __RPC_FAR * This, - /* [in] */ UINT index, - /* [out] */ TYPEKIND __RPC_FAR *pTKind) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 5); - - - - if(!pTKind) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( UINT __RPC_FAR * )_StubMsg.Buffer = index; - _StubMsg.Buffer += sizeof(UINT); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[378] ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pTKind, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1250], - (unsigned char)0 ); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1250], - ( void __RPC_FAR * )pTKind); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeLib_GetTypeInfoType_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - TYPEKIND _M63; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - UINT index; - TYPEKIND __RPC_FAR *pTKind; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pTKind = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[378] ); - - index = *( UINT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(UINT); - - pTKind = &_M63; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeLib*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetTypeInfoType( - (ITypeLib *) ((CStdStubBuffer *)This)->pvServerObject, - index, - pTKind); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U + 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pTKind, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1250] ); - - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeLib_GetTypeInfoOfGuid_Proxy( - ITypeLib __RPC_FAR * This, - /* [in] */ REFGUID guid, - /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTinfo) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(ppTinfo) - { - MIDL_memset( - ppTinfo, - 0, - sizeof( ITypeInfo __RPC_FAR *__RPC_FAR * )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 6); - - - - if(!guid) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!ppTinfo) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)guid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxyGetBuffer(This, &_StubMsg); - NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)guid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[386] ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&ppTinfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[6], - ( void __RPC_FAR * )ppTinfo); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeLib_GetTypeInfoOfGuid_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - ITypeInfo __RPC_FAR *_M64; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - REFGUID guid = 0; - ITypeInfo __RPC_FAR *__RPC_FAR *ppTinfo; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - ppTinfo = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[386] ); - - NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&guid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], - (unsigned char)0 ); - - ppTinfo = &_M64; - _M64 = 0; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeLib*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetTypeInfoOfGuid( - (ITypeLib *) ((CStdStubBuffer *)This)->pvServerObject, - guid, - ppTinfo); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 0U + 4U; - NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)ppTinfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)ppTinfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)ppTinfo, - &__MIDL_TypeFormatString.Format[6] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeLib_RemoteGetLibAttr_Proxy( - ITypeLib __RPC_FAR * This, - /* [out] */ LPTLIBATTR __RPC_FAR *ppTLibAttr, - /* [out] */ CLEANLOCALSTORAGE __RPC_FAR *pDummy) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(ppTLibAttr) - { - *ppTLibAttr = 0; - } - if(pDummy) - { - MIDL_memset( - pDummy, - 0, - sizeof( CLEANLOCALSTORAGE )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 7); - - - - if(!ppTLibAttr) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pDummy) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[396] ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&ppTLibAttr, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1804], - (unsigned char)0 ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pDummy, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1838], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1804], - ( void __RPC_FAR * )ppTLibAttr); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1832], - ( void __RPC_FAR * )pDummy); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeLib_RemoteGetLibAttr_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - LPTLIBATTR _M65; - CLEANLOCALSTORAGE _M66; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - CLEANLOCALSTORAGE __RPC_FAR *pDummy; - LPTLIBATTR __RPC_FAR *ppTLibAttr; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - ppTLibAttr = 0; - pDummy = 0; - RpcTryFinally - { - ppTLibAttr = &_M65; - _M65 = 0; - pDummy = &_M66; - MIDL_memset( - pDummy, - 0, - sizeof( CLEANLOCALSTORAGE )); - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeLib_GetLibAttr_Stub( - (ITypeLib *) ((CStdStubBuffer *)This)->pvServerObject, - ppTLibAttr, - pDummy); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 8U + 11U + 7U; - NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)ppTLibAttr, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1804] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)ppTLibAttr, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1804] ); - - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pDummy, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1838] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)ppTLibAttr, - &__MIDL_TypeFormatString.Format[1804] ); - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pDummy, - &__MIDL_TypeFormatString.Format[1832] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeLib_GetTypeComp_Proxy( - ITypeLib __RPC_FAR * This, - /* [out] */ ITypeComp __RPC_FAR *__RPC_FAR *ppTComp) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(ppTComp) - { - MIDL_memset( - ppTComp, - 0, - sizeof( ITypeComp __RPC_FAR *__RPC_FAR * )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 8); - - - - if(!ppTComp) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[152] ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&ppTComp, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1540], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1540], - ( void __RPC_FAR * )ppTComp); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeLib_GetTypeComp_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - ITypeComp __RPC_FAR *_M67; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - ITypeComp __RPC_FAR *__RPC_FAR *ppTComp; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - ppTComp = 0; - RpcTryFinally - { - ppTComp = &_M67; - _M67 = 0; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeLib*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetTypeComp((ITypeLib *) ((CStdStubBuffer *)This)->pvServerObject,ppTComp); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 0U + 4U; - NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)ppTComp, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1540] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)ppTComp, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1540] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)ppTComp, - &__MIDL_TypeFormatString.Format[1540] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeLib_RemoteGetDocumentation_Proxy( - ITypeLib __RPC_FAR * This, - /* [in] */ INT index, - /* [in] */ DWORD refPtrFlags, - /* [out] */ BSTR __RPC_FAR *pBstrName, - /* [out] */ BSTR __RPC_FAR *pBstrDocString, - /* [out] */ DWORD __RPC_FAR *pdwHelpContext, - /* [out] */ BSTR __RPC_FAR *pBstrHelpFile) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pBstrName) - { - MIDL_memset( - pBstrName, - 0, - sizeof( BSTR )); - } - if(pBstrDocString) - { - MIDL_memset( - pBstrDocString, - 0, - sizeof( BSTR )); - } - if(pBstrHelpFile) - { - MIDL_memset( - pBstrHelpFile, - 0, - sizeof( BSTR )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 9); - - - - if(!pBstrName) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pBstrDocString) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pdwHelpContext) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pBstrHelpFile) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U + 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( INT __RPC_FAR * )_StubMsg.Buffer = index; - _StubMsg.Buffer += sizeof(INT); - - *( DWORD __RPC_FAR * )_StubMsg.Buffer = refPtrFlags; - _StubMsg.Buffer += sizeof(DWORD); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[204] ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], - (unsigned char)0 ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrDocString, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *pdwHelpContext = *( DWORD __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(DWORD); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrHelpFile, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], - ( void __RPC_FAR * )pBstrName); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], - ( void __RPC_FAR * )pBstrDocString); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], - ( void __RPC_FAR * )pdwHelpContext); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], - ( void __RPC_FAR * )pBstrHelpFile); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeLib_RemoteGetDocumentation_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - BSTR _M68; - BSTR _M69; - DWORD _M70; - BSTR _M71; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - INT index; - BSTR __RPC_FAR *pBstrDocString; - BSTR __RPC_FAR *pBstrHelpFile; - BSTR __RPC_FAR *pBstrName; - DWORD __RPC_FAR *pdwHelpContext; - DWORD refPtrFlags; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pBstrName = 0; - pBstrDocString = 0; - pdwHelpContext = 0; - pBstrHelpFile = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[204] ); - - index = *( INT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(INT); - - refPtrFlags = *( DWORD __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(DWORD); - - pBstrName = &_M68; - MIDL_memset( - pBstrName, - 0, - sizeof( BSTR )); - pBstrDocString = &_M69; - MIDL_memset( - pBstrDocString, - 0, - sizeof( BSTR )); - pdwHelpContext = &_M70; - pBstrHelpFile = &_M71; - MIDL_memset( - pBstrHelpFile, - 0, - sizeof( BSTR )); - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeLib_GetDocumentation_Stub( - (ITypeLib *) ((CStdStubBuffer *)This)->pvServerObject, - index, - refPtrFlags, - pBstrName, - pBstrDocString, - pdwHelpContext, - pBstrHelpFile); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 8U + 15U + 11U + 11U + 11U; - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pBstrName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pBstrDocString, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pBstrHelpFile, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pBstrName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pBstrDocString, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( DWORD __RPC_FAR * )_StubMsg.Buffer = *pdwHelpContext; - _StubMsg.Buffer += sizeof(DWORD); - - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pBstrHelpFile, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pBstrName, - &__MIDL_TypeFormatString.Format[1708] ); - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pBstrDocString, - &__MIDL_TypeFormatString.Format[1708] ); - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pBstrHelpFile, - &__MIDL_TypeFormatString.Format[1708] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeLib_RemoteIsName_Proxy( - ITypeLib __RPC_FAR * This, - /* [in] */ LPOLESTR szNameBuf, - /* [in] */ ULONG lHashVal, - /* [out] */ BOOL __RPC_FAR *pfName, - /* [out] */ BSTR __RPC_FAR *pBstrLibName) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pBstrLibName) - { - MIDL_memset( - pBstrLibName, - 0, - sizeof( BSTR )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 10); - - - - if(!szNameBuf) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pfName) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pBstrLibName) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 12U + 10U; - NdrConformantStringBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)szNameBuf, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); - - NdrProxyGetBuffer(This, &_StubMsg); - NdrConformantStringMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)szNameBuf, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( ULONG __RPC_FAR * )_StubMsg.Buffer = lHashVal; - _StubMsg.Buffer += sizeof(ULONG); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[406] ); - - *pfName = *( BOOL __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(BOOL); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrLibName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], - ( void __RPC_FAR * )pfName); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], - ( void __RPC_FAR * )pBstrLibName); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeLib_RemoteIsName_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - BOOL _M74; - BSTR _M75; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - ULONG lHashVal; - BSTR __RPC_FAR *pBstrLibName; - BOOL __RPC_FAR *pfName; - LPOLESTR szNameBuf; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - szNameBuf = 0; - pfName = 0; - pBstrLibName = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[406] ); - - NdrConformantStringUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&szNameBuf, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - lHashVal = *( ULONG __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(ULONG); - - pfName = &_M74; - pBstrLibName = &_M75; - MIDL_memset( - pBstrLibName, - 0, - sizeof( BSTR )); - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeLib_IsName_Stub( - (ITypeLib *) ((CStdStubBuffer *)This)->pvServerObject, - szNameBuf, - lHashVal, - pfName, - pBstrLibName); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U + 4U + 11U; - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pBstrLibName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( BOOL __RPC_FAR * )_StubMsg.Buffer = *pfName; - _StubMsg.Buffer += sizeof(BOOL); - - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pBstrLibName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pBstrLibName, - &__MIDL_TypeFormatString.Format[1708] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeLib_RemoteFindName_Proxy( - ITypeLib __RPC_FAR * This, - /* [in] */ LPOLESTR szNameBuf, - /* [in] */ ULONG lHashVal, - /* [length_is][size_is][out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo, - /* [length_is][size_is][out] */ MEMBERID __RPC_FAR *rgMemId, - /* [out][in] */ USHORT __RPC_FAR *pcFound, - /* [out] */ BSTR __RPC_FAR *pBstrLibName) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(ppTInfo) - { - MIDL_memset( - ppTInfo, - 0, - *pcFound * sizeof( ITypeInfo __RPC_FAR *__RPC_FAR * )); - } - if(pBstrLibName) - { - MIDL_memset( - pBstrLibName, - 0, - sizeof( BSTR )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 11); - - - - if(!szNameBuf) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!ppTInfo) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!rgMemId) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pcFound) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pBstrLibName) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 12U + 10U + 4U; - NdrConformantStringBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)szNameBuf, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); - - NdrProxyGetBuffer(This, &_StubMsg); - NdrConformantStringMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)szNameBuf, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( ULONG __RPC_FAR * )_StubMsg.Buffer = lHashVal; - _StubMsg.Buffer += sizeof(ULONG); - - *( USHORT __RPC_FAR * )_StubMsg.Buffer = *pcFound; - _StubMsg.Buffer += sizeof(USHORT); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[422] ); - - NdrComplexArrayUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&ppTInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1852], - (unsigned char)0 ); - - NdrConformantVaryingArrayUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&rgMemId, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1874], - (unsigned char)0 ); - - *pcFound = *( USHORT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(USHORT); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrLibName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - _StubMsg.MaxCount = pcFound ? *pcFound : 0; - _StubMsg.Offset = 0; - _StubMsg.ActualCount = _StubMsg.MaxCount; - - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1848], - ( void __RPC_FAR * )ppTInfo); - _StubMsg.MaxCount = pcFound ? *pcFound : 0; - _StubMsg.Offset = 0; - _StubMsg.ActualCount = _StubMsg.MaxCount; - - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1870], - ( void __RPC_FAR * )rgMemId); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1888], - ( void __RPC_FAR * )pcFound); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], - ( void __RPC_FAR * )pBstrLibName); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeLib_RemoteFindName_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - BSTR _M84; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - ULONG lHashVal; - BSTR __RPC_FAR *pBstrLibName; - USHORT __RPC_FAR *pcFound; - ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo; - MEMBERID __RPC_FAR *rgMemId; - LPOLESTR szNameBuf; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - szNameBuf = 0; - ppTInfo = 0; - rgMemId = 0; - pcFound = 0; - pBstrLibName = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[422] ); - - NdrConformantStringUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&szNameBuf, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - lHashVal = *( ULONG __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(ULONG); - - pcFound = ( USHORT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof( USHORT ); - - ppTInfo = NdrAllocate(&_StubMsg,*pcFound * 4); - rgMemId = NdrAllocate(&_StubMsg,*pcFound * 4); - pBstrLibName = &_M84; - MIDL_memset( - pBstrLibName, - 0, - sizeof( BSTR )); - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeLib_FindName_Stub( - (ITypeLib *) ((CStdStubBuffer *)This)->pvServerObject, - szNameBuf, - lHashVal, - ppTInfo, - rgMemId, - pcFound, - pBstrLibName); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 12U + 15U + 4U + 14U + 11U; - _StubMsg.MaxCount = pcFound ? *pcFound : 0; - _StubMsg.Offset = 0; - _StubMsg.ActualCount = pcFound ? *pcFound : 0; - - NdrComplexArrayBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)ppTInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1852] ); - - _StubMsg.MaxCount = pcFound ? *pcFound : 0; - _StubMsg.Offset = 0; - _StubMsg.ActualCount = pcFound ? *pcFound : 0; - - NdrConformantVaryingArrayBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)rgMemId, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1874] ); - - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pBstrLibName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - _StubMsg.MaxCount = pcFound ? *pcFound : 0; - _StubMsg.Offset = 0; - _StubMsg.ActualCount = pcFound ? *pcFound : 0; - - NdrComplexArrayMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)ppTInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1852] ); - - _StubMsg.MaxCount = pcFound ? *pcFound : 0; - _StubMsg.Offset = 0; - _StubMsg.ActualCount = pcFound ? *pcFound : 0; - - NdrConformantVaryingArrayMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)rgMemId, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1874] ); - - *( USHORT __RPC_FAR * )_StubMsg.Buffer = *pcFound; - _StubMsg.Buffer += sizeof(USHORT); - - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pBstrLibName, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - _StubMsg.MaxCount = pcFound ? *pcFound : 0; - _StubMsg.Offset = 0; - _StubMsg.ActualCount = pcFound ? *pcFound : 0; - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)ppTInfo, - &__MIDL_TypeFormatString.Format[1848] ); - - _StubMsg.MaxCount = pcFound ? *pcFound : 0; - _StubMsg.Offset = 0; - _StubMsg.ActualCount = pcFound ? *pcFound : 0; - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)rgMemId, - &__MIDL_TypeFormatString.Format[1870] ); - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pBstrLibName, - &__MIDL_TypeFormatString.Format[1708] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeLib_LocalReleaseTLibAttr_Proxy( - ITypeLib __RPC_FAR * This) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 12); - - - - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[88] ); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeLib_LocalReleaseTLibAttr_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - RpcTryFinally - { - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeLib_ReleaseTLibAttr_Stub((ITypeLib *) ((CStdStubBuffer *)This)->pvServerObject); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - -const CINTERFACE_PROXY_VTABLE(13) _ITypeLibProxyVtbl = -{ - { &IID_ITypeLib }, - { - IUnknown_QueryInterface_Proxy, - IUnknown_AddRef_Proxy, - IUnknown_Release_Proxy , - ITypeLib_GetTypeInfoCount_Proxy , - ITypeLib_GetTypeInfo_Proxy , - ITypeLib_GetTypeInfoType_Proxy , - ITypeLib_GetTypeInfoOfGuid_Proxy , - ITypeLib_GetLibAttr_Proxy , - ITypeLib_GetTypeComp_Proxy , - ITypeLib_GetDocumentation_Proxy , - ITypeLib_IsName_Proxy , - ITypeLib_FindName_Proxy , - ITypeLib_ReleaseTLibAttr_Proxy - } -}; - - -static const PRPC_STUB_FUNCTION ITypeLib_table[] = -{ - ITypeLib_RemoteGetTypeInfoCount_Stub, - ITypeLib_GetTypeInfo_Stub, - ITypeLib_GetTypeInfoType_Stub, - ITypeLib_GetTypeInfoOfGuid_Stub, - ITypeLib_RemoteGetLibAttr_Stub, - ITypeLib_GetTypeComp_Stub, - ITypeLib_RemoteGetDocumentation_Stub, - ITypeLib_RemoteIsName_Stub, - ITypeLib_RemoteFindName_Stub, - ITypeLib_LocalReleaseTLibAttr_Stub -}; - -const CInterfaceStubVtbl _ITypeLibStubVtbl = -{ - { - &IID_ITypeLib, - 0, - 13, - &ITypeLib_table[-3] - }, - { CStdStubBuffer_METHODS } -}; - - -/* Object interface: ITypeLib2, ver. 0.0, - GUID={0x00020411,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ - - -extern const MIDL_STUB_DESC Object_StubDesc; - - -HRESULT STDMETHODCALLTYPE ITypeLib2_GetCustData_Proxy( - ITypeLib2 __RPC_FAR * This, - /* [in] */ REFGUID guid, - /* [out] */ VARIANT __RPC_FAR *pVarVal) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pVarVal) - { - MIDL_memset( - pVarVal, - 0, - sizeof( VARIANT )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 13); - - - - if(!guid) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pVarVal) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)guid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxyGetBuffer(This, &_StubMsg); - NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)guid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[298] ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pVarVal, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1102], - ( void __RPC_FAR * )pVarVal); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeLib2_GetCustData_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - VARIANT _M85; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - REFGUID guid = 0; - VARIANT __RPC_FAR *pVarVal; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pVarVal = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[298] ); - - NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&guid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], - (unsigned char)0 ); - - pVarVal = &_M85; - MIDL_memset( - pVarVal, - 0, - sizeof( VARIANT )); - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeLib2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetCustData( - (ITypeLib2 *) ((CStdStubBuffer *)This)->pvServerObject, - guid, - pVarVal); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 8U + 11U; - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pVarVal, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pVarVal, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pVarVal, - &__MIDL_TypeFormatString.Format[1102] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeLib2_RemoteGetLibStatistics_Proxy( - ITypeLib2 __RPC_FAR * This, - /* [out] */ ULONG __RPC_FAR *pcUniqueNames, - /* [out] */ ULONG __RPC_FAR *pcchUniqueNames) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 14); - - - - if(!pcUniqueNames) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pcchUniqueNames) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[446] ); - - *pcUniqueNames = *( ULONG __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(ULONG); - - *pcchUniqueNames = *( ULONG __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(ULONG); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], - ( void __RPC_FAR * )pcUniqueNames); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], - ( void __RPC_FAR * )pcchUniqueNames); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeLib2_RemoteGetLibStatistics_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - ULONG _M86; - ULONG _M87; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - ULONG __RPC_FAR *pcUniqueNames; - ULONG __RPC_FAR *pcchUniqueNames; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pcUniqueNames = 0; - pcchUniqueNames = 0; - RpcTryFinally - { - pcUniqueNames = &_M86; - pcchUniqueNames = &_M87; - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeLib2_GetLibStatistics_Stub( - (ITypeLib2 *) ((CStdStubBuffer *)This)->pvServerObject, - pcUniqueNames, - pcchUniqueNames); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U + 4U + 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( ULONG __RPC_FAR * )_StubMsg.Buffer = *pcUniqueNames; - _StubMsg.Buffer += sizeof(ULONG); - - *( ULONG __RPC_FAR * )_StubMsg.Buffer = *pcchUniqueNames; - _StubMsg.Buffer += sizeof(ULONG); - - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeLib2_RemoteGetDocumentation2_Proxy( - ITypeLib2 __RPC_FAR * This, - /* [in] */ INT index, - /* [in] */ LCID lcid, - /* [in] */ DWORD refPtrFlags, - /* [out] */ BSTR __RPC_FAR *pbstrHelpString, - /* [out] */ DWORD __RPC_FAR *pdwHelpStringContext, - /* [out] */ BSTR __RPC_FAR *pbstrHelpStringDll) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pbstrHelpString) - { - MIDL_memset( - pbstrHelpString, - 0, - sizeof( BSTR )); - } - if(pbstrHelpStringDll) - { - MIDL_memset( - pbstrHelpStringDll, - 0, - sizeof( BSTR )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 15); - - - - if(!pbstrHelpString) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pdwHelpStringContext) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!pbstrHelpStringDll) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 4U + 4U + 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( INT __RPC_FAR * )_StubMsg.Buffer = index; - _StubMsg.Buffer += sizeof(INT); - - *( LCID __RPC_FAR * )_StubMsg.Buffer = lcid; - _StubMsg.Buffer += sizeof(LCID); - - *( DWORD __RPC_FAR * )_StubMsg.Buffer = refPtrFlags; - _StubMsg.Buffer += sizeof(DWORD); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[334] ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pbstrHelpString, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *pdwHelpStringContext = *( DWORD __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(DWORD); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pbstrHelpStringDll, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], - ( void __RPC_FAR * )pbstrHelpString); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], - ( void __RPC_FAR * )pdwHelpStringContext); - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], - ( void __RPC_FAR * )pbstrHelpStringDll); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeLib2_RemoteGetDocumentation2_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - BSTR _M88; - DWORD _M89; - BSTR _M90; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - INT index; - LCID lcid; - BSTR __RPC_FAR *pbstrHelpString; - BSTR __RPC_FAR *pbstrHelpStringDll; - DWORD __RPC_FAR *pdwHelpStringContext; - DWORD refPtrFlags; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pbstrHelpString = 0; - pdwHelpStringContext = 0; - pbstrHelpStringDll = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[334] ); - - index = *( INT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(INT); - - lcid = *( LCID __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(LCID); - - refPtrFlags = *( DWORD __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(DWORD); - - pbstrHelpString = &_M88; - MIDL_memset( - pbstrHelpString, - 0, - sizeof( BSTR )); - pdwHelpStringContext = &_M89; - pbstrHelpStringDll = &_M90; - MIDL_memset( - pbstrHelpStringDll, - 0, - sizeof( BSTR )); - - *_pdwStubPhase = STUB_CALL_SERVER; - - - _RetVal = ITypeLib2_GetDocumentation2_Stub( - (ITypeLib2 *) ((CStdStubBuffer *)This)->pvServerObject, - index, - lcid, - refPtrFlags, - pbstrHelpString, - pdwHelpStringContext, - pbstrHelpStringDll); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 8U + 11U + 11U + 11U; - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pbstrHelpString, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pbstrHelpStringDll, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pbstrHelpString, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( DWORD __RPC_FAR * )_StubMsg.Buffer = *pdwHelpStringContext; - _StubMsg.Buffer += sizeof(DWORD); - - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pbstrHelpStringDll, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pbstrHelpString, - &__MIDL_TypeFormatString.Format[1708] ); - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pbstrHelpStringDll, - &__MIDL_TypeFormatString.Format[1708] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ITypeLib2_GetAllCustData_Proxy( - ITypeLib2 __RPC_FAR * This, - /* [out] */ CUSTDATA __RPC_FAR *pCustData) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pCustData) - { - MIDL_memset( - pCustData, - 0, - sizeof( CUSTDATA )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 16); - - - - if(!pCustData) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[354] ); - - NdrComplexStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pCustData, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1748], - ( void __RPC_FAR * )pCustData); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeLib2_GetAllCustData_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - CUSTDATA _pCustDataM; - CUSTDATA __RPC_FAR *pCustData; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pCustData = 0; - RpcTryFinally - { - pCustData = &_pCustDataM; - pCustData -> prgCustData = 0; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeLib2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetAllCustData((ITypeLib2 *) ((CStdStubBuffer *)This)->pvServerObject,pCustData); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 0U + 11U; - NdrComplexStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pCustData, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrComplexStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pCustData, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pCustData, - &__MIDL_TypeFormatString.Format[1748] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - -const CINTERFACE_PROXY_VTABLE(17) _ITypeLib2ProxyVtbl = -{ - { &IID_ITypeLib2 }, - { - IUnknown_QueryInterface_Proxy, - IUnknown_AddRef_Proxy, - IUnknown_Release_Proxy , - ITypeLib_GetTypeInfoCount_Proxy , - ITypeLib_GetTypeInfo_Proxy , - ITypeLib_GetTypeInfoType_Proxy , - ITypeLib_GetTypeInfoOfGuid_Proxy , - ITypeLib_GetLibAttr_Proxy , - ITypeLib_GetTypeComp_Proxy , - ITypeLib_GetDocumentation_Proxy , - ITypeLib_IsName_Proxy , - ITypeLib_FindName_Proxy , - ITypeLib_ReleaseTLibAttr_Proxy , - ITypeLib2_GetCustData_Proxy , - ITypeLib2_GetLibStatistics_Proxy , - ITypeLib2_GetDocumentation2_Proxy , - ITypeLib2_GetAllCustData_Proxy - } -}; - - -static const PRPC_STUB_FUNCTION ITypeLib2_table[] = -{ - ITypeLib_RemoteGetTypeInfoCount_Stub, - ITypeLib_GetTypeInfo_Stub, - ITypeLib_GetTypeInfoType_Stub, - ITypeLib_GetTypeInfoOfGuid_Stub, - ITypeLib_RemoteGetLibAttr_Stub, - ITypeLib_GetTypeComp_Stub, - ITypeLib_RemoteGetDocumentation_Stub, - ITypeLib_RemoteIsName_Stub, - ITypeLib_RemoteFindName_Stub, - ITypeLib_LocalReleaseTLibAttr_Stub, - ITypeLib2_GetCustData_Stub, - ITypeLib2_RemoteGetLibStatistics_Stub, - ITypeLib2_RemoteGetDocumentation2_Stub, - ITypeLib2_GetAllCustData_Stub -}; - -const CInterfaceStubVtbl _ITypeLib2StubVtbl = -{ - { - &IID_ITypeLib2, - 0, - 17, - &ITypeLib2_table[-3] - }, - { CStdStubBuffer_METHODS } -}; - - -/* Object interface: ITypeChangeEvents, ver. 0.0, - GUID={0x00020410,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ - - -/* Object interface: IErrorInfo, ver. 0.0, - GUID={0x1CF2B120,0x547D,0x101B,{0x8E,0x65,0x08,0x00,0x2B,0x2B,0xD1,0x19}} */ - - -extern const MIDL_STUB_DESC Object_StubDesc; - - -HRESULT STDMETHODCALLTYPE IErrorInfo_GetGUID_Proxy( - IErrorInfo __RPC_FAR * This, - /* [out] */ GUID __RPC_FAR *pGUID) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pGUID) - { - MIDL_memset( - pGUID, - 0, - sizeof( IID )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 3); - - - - if(!pGUID) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[456] ); - - NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pGUID, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], - (unsigned char)0 ); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1892], - ( void __RPC_FAR * )pGUID); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB IErrorInfo_GetGUID_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - IID _pGUIDM; - GUID __RPC_FAR *pGUID; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pGUID = 0; - RpcTryFinally - { - pGUID = &_pGUIDM; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((IErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetGUID((IErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,pGUID); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 0U + 11U; - NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pGUID, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pGUID, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE IErrorInfo_GetSource_Proxy( - IErrorInfo __RPC_FAR * This, - /* [out] */ BSTR __RPC_FAR *pBstrSource) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pBstrSource) - { - MIDL_memset( - pBstrSource, - 0, - sizeof( BSTR )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 4); - - - - if(!pBstrSource) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[462] ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrSource, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], - ( void __RPC_FAR * )pBstrSource); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB IErrorInfo_GetSource_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - BSTR _M91; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - BSTR __RPC_FAR *pBstrSource; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pBstrSource = 0; - RpcTryFinally - { - pBstrSource = &_M91; - MIDL_memset( - pBstrSource, - 0, - sizeof( BSTR )); - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((IErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetSource((IErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,pBstrSource); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 8U + 11U; - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pBstrSource, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pBstrSource, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pBstrSource, - &__MIDL_TypeFormatString.Format[1708] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE IErrorInfo_GetDescription_Proxy( - IErrorInfo __RPC_FAR * This, - /* [out] */ BSTR __RPC_FAR *pBstrDescription) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pBstrDescription) - { - MIDL_memset( - pBstrDescription, - 0, - sizeof( BSTR )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 5); - - - - if(!pBstrDescription) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[462] ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrDescription, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], - ( void __RPC_FAR * )pBstrDescription); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB IErrorInfo_GetDescription_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - BSTR _M92; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - BSTR __RPC_FAR *pBstrDescription; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pBstrDescription = 0; - RpcTryFinally - { - pBstrDescription = &_M92; - MIDL_memset( - pBstrDescription, - 0, - sizeof( BSTR )); - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((IErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetDescription((IErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,pBstrDescription); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 8U + 11U; - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pBstrDescription, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pBstrDescription, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pBstrDescription, - &__MIDL_TypeFormatString.Format[1708] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE IErrorInfo_GetHelpFile_Proxy( - IErrorInfo __RPC_FAR * This, - /* [out] */ BSTR __RPC_FAR *pBstrHelpFile) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(pBstrHelpFile) - { - MIDL_memset( - pBstrHelpFile, - 0, - sizeof( BSTR )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 6); - - - - if(!pBstrHelpFile) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[462] ); - - NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrHelpFile, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], - ( void __RPC_FAR * )pBstrHelpFile); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB IErrorInfo_GetHelpFile_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - BSTR _M93; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - BSTR __RPC_FAR *pBstrHelpFile; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pBstrHelpFile = 0; - RpcTryFinally - { - pBstrHelpFile = &_M93; - MIDL_memset( - pBstrHelpFile, - 0, - sizeof( BSTR )); - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((IErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetHelpFile((IErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,pBstrHelpFile); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 8U + 11U; - NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pBstrHelpFile, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pBstrHelpFile, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pBstrHelpFile, - &__MIDL_TypeFormatString.Format[1708] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE IErrorInfo_GetHelpContext_Proxy( - IErrorInfo __RPC_FAR * This, - /* [out] */ DWORD __RPC_FAR *pdwHelpContext) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 7); - - - - if(!pdwHelpContext) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrProxyGetBuffer(This, &_StubMsg); - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[0] ); - - *pdwHelpContext = *( DWORD __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(DWORD); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], - ( void __RPC_FAR * )pdwHelpContext); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB IErrorInfo_GetHelpContext_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - DWORD _M94; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - DWORD __RPC_FAR *pdwHelpContext; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pdwHelpContext = 0; - RpcTryFinally - { - pdwHelpContext = &_M94; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((IErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetHelpContext((IErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,pdwHelpContext); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U + 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( DWORD __RPC_FAR * )_StubMsg.Buffer = *pdwHelpContext; - _StubMsg.Buffer += sizeof(DWORD); - - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - -const CINTERFACE_PROXY_VTABLE(8) _IErrorInfoProxyVtbl = -{ - { &IID_IErrorInfo }, - { - IUnknown_QueryInterface_Proxy, - IUnknown_AddRef_Proxy, - IUnknown_Release_Proxy , - IErrorInfo_GetGUID_Proxy , - IErrorInfo_GetSource_Proxy , - IErrorInfo_GetDescription_Proxy , - IErrorInfo_GetHelpFile_Proxy , - IErrorInfo_GetHelpContext_Proxy - } -}; - - -static const PRPC_STUB_FUNCTION IErrorInfo_table[] = -{ - IErrorInfo_GetGUID_Stub, - IErrorInfo_GetSource_Stub, - IErrorInfo_GetDescription_Stub, - IErrorInfo_GetHelpFile_Stub, - IErrorInfo_GetHelpContext_Stub -}; - -const CInterfaceStubVtbl _IErrorInfoStubVtbl = -{ - { - &IID_IErrorInfo, - 0, - 8, - &IErrorInfo_table[-3] - }, - { CStdStubBuffer_METHODS } -}; - - -/* Object interface: ICreateErrorInfo, ver. 0.0, - GUID={0x22F03340,0x547D,0x101B,{0x8E,0x65,0x08,0x00,0x2B,0x2B,0xD1,0x19}} */ - - -extern const MIDL_STUB_DESC Object_StubDesc; - - -HRESULT STDMETHODCALLTYPE ICreateErrorInfo_SetGUID_Proxy( - ICreateErrorInfo __RPC_FAR * This, - /* [in] */ REFGUID rguid) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 3); - - - - if(!rguid) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)rguid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxyGetBuffer(This, &_StubMsg); - NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)rguid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[468] ); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ICreateErrorInfo_SetGUID_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - REFGUID rguid = 0; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[468] ); - - NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&rguid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], - (unsigned char)0 ); - - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ICreateErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> SetGUID((ICreateErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,rguid); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ICreateErrorInfo_SetSource_Proxy( - ICreateErrorInfo __RPC_FAR * This, - /* [in] */ LPOLESTR szSource) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 4); - - - - if(!szSource) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 12U; - NdrConformantStringBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)szSource, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); - - NdrProxyGetBuffer(This, &_StubMsg); - NdrConformantStringMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)szSource, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[474] ); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ICreateErrorInfo_SetSource_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - LPOLESTR szSource; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - szSource = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[474] ); - - NdrConformantStringUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&szSource, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248], - (unsigned char)0 ); - - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ICreateErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> SetSource((ICreateErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,szSource); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U; - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ICreateErrorInfo_SetDescription_Proxy( - ICreateErrorInfo __RPC_FAR * This, - /* [in] */ LPOLESTR szDescription) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 5); - - - - if(!szDescription) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 12U; - NdrConformantStringBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)szDescription, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); - - NdrProxyGetBuffer(This, &_StubMsg); - NdrConformantStringMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)szDescription, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[474] ); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ICreateErrorInfo_SetDescription_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - LPOLESTR szDescription; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - szDescription = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[474] ); - - NdrConformantStringUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&szDescription, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248], - (unsigned char)0 ); - - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ICreateErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> SetDescription((ICreateErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,szDescription); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U; - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ICreateErrorInfo_SetHelpFile_Proxy( - ICreateErrorInfo __RPC_FAR * This, - /* [in] */ LPOLESTR szHelpFile) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 6); - - - - if(!szHelpFile) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 12U; - NdrConformantStringBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)szHelpFile, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); - - NdrProxyGetBuffer(This, &_StubMsg); - NdrConformantStringMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)szHelpFile, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[474] ); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ICreateErrorInfo_SetHelpFile_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - LPOLESTR szHelpFile; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - szHelpFile = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[474] ); - - NdrConformantStringUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&szHelpFile, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248], - (unsigned char)0 ); - - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ICreateErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> SetHelpFile((ICreateErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,szHelpFile); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U; - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - - -HRESULT STDMETHODCALLTYPE ICreateErrorInfo_SetHelpContext_Proxy( - ICreateErrorInfo __RPC_FAR * This, - /* [in] */ DWORD dwHelpContext) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 7); - - - - RpcTryFinally - { - - _StubMsg.BufferLength = 4U; - NdrProxyGetBuffer(This, &_StubMsg); - *( DWORD __RPC_FAR * )_StubMsg.Buffer = dwHelpContext; - _StubMsg.Buffer += sizeof(DWORD); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[84] ); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ICreateErrorInfo_SetHelpContext_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - DWORD dwHelpContext; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[84] ); - - dwHelpContext = *( DWORD __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(DWORD); - - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ICreateErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> SetHelpContext((ICreateErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,dwHelpContext); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - -const CINTERFACE_PROXY_VTABLE(8) _ICreateErrorInfoProxyVtbl = -{ - { &IID_ICreateErrorInfo }, - { - IUnknown_QueryInterface_Proxy, - IUnknown_AddRef_Proxy, - IUnknown_Release_Proxy , - ICreateErrorInfo_SetGUID_Proxy , - ICreateErrorInfo_SetSource_Proxy , - ICreateErrorInfo_SetDescription_Proxy , - ICreateErrorInfo_SetHelpFile_Proxy , - ICreateErrorInfo_SetHelpContext_Proxy - } -}; - - -static const PRPC_STUB_FUNCTION ICreateErrorInfo_table[] = -{ - ICreateErrorInfo_SetGUID_Stub, - ICreateErrorInfo_SetSource_Stub, - ICreateErrorInfo_SetDescription_Stub, - ICreateErrorInfo_SetHelpFile_Stub, - ICreateErrorInfo_SetHelpContext_Stub -}; - -const CInterfaceStubVtbl _ICreateErrorInfoStubVtbl = -{ - { - &IID_ICreateErrorInfo, - 0, - 8, - &ICreateErrorInfo_table[-3] - }, - { CStdStubBuffer_METHODS } -}; - - -/* Object interface: ISupportErrorInfo, ver. 0.0, - GUID={0xDF0B3D60,0x548F,0x101B,{0x8E,0x65,0x08,0x00,0x2B,0x2B,0xD1,0x19}} */ - - -extern const MIDL_STUB_DESC Object_StubDesc; - - -HRESULT STDMETHODCALLTYPE ISupportErrorInfo_InterfaceSupportsErrorInfo_Proxy( - ISupportErrorInfo __RPC_FAR * This, - /* [in] */ REFIID riid) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 3); - - - - if(!riid) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U; - NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)riid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxyGetBuffer(This, &_StubMsg); - NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)riid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[468] ); - - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ISupportErrorInfo_InterfaceSupportsErrorInfo_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - IID* riid = 0; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[468] ); - - NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&riid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], - (unsigned char)0 ); - - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ISupportErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> InterfaceSupportsErrorInfo((ISupportErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,riid); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 4U; - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - -const CINTERFACE_PROXY_VTABLE(4) _ISupportErrorInfoProxyVtbl = -{ - { &IID_ISupportErrorInfo }, - { - IUnknown_QueryInterface_Proxy, - IUnknown_AddRef_Proxy, - IUnknown_Release_Proxy , - ISupportErrorInfo_InterfaceSupportsErrorInfo_Proxy - } -}; - - -static const PRPC_STUB_FUNCTION ISupportErrorInfo_table[] = -{ - ISupportErrorInfo_InterfaceSupportsErrorInfo_Stub -}; - -const CInterfaceStubVtbl _ISupportErrorInfoStubVtbl = -{ - { - &IID_ISupportErrorInfo, - 0, - 4, - &ISupportErrorInfo_table[-3] - }, - { CStdStubBuffer_METHODS } -}; - - -/* Object interface: ITypeFactory, ver. 0.0, - GUID={0x0000002E,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ - - -extern const MIDL_STUB_DESC Object_StubDesc; - - -HRESULT STDMETHODCALLTYPE ITypeFactory_CreateFromTypeInfo_Proxy( - ITypeFactory __RPC_FAR * This, - /* [in] */ ITypeInfo __RPC_FAR *pTypeInfo, - /* [in] */ REFIID riid, - /* [iid_is][out] */ IUnknown __RPC_FAR *__RPC_FAR *ppv) -{ - - HRESULT _RetVal; - - RPC_MESSAGE _RpcMessage; - - MIDL_STUB_MESSAGE _StubMsg; - - if(ppv) - { - MIDL_memset( - ppv, - 0, - sizeof( IUnknown __RPC_FAR *__RPC_FAR * )); - } - RpcTryExcept - { - NdrProxyInitialize( - ( void __RPC_FAR * )This, - ( PRPC_MESSAGE )&_RpcMessage, - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PMIDL_STUB_DESC )&Object_StubDesc, - 3); - - - - if(!riid) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - if(!ppv) - { - RpcRaiseException(RPC_X_NULL_REF_POINTER); - } - RpcTryFinally - { - - _StubMsg.BufferLength = 0U + 0U; - NdrInterfacePointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)pTypeInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[10] ); - - NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)riid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxyGetBuffer(This, &_StubMsg); - NdrInterfacePointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)pTypeInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[10] ); - - NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)riid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); - - NdrProxySendReceive(This, &_StubMsg); - - if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[480] ); - - NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&ppv, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1896], - (unsigned char)0 ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrProxyFreeBuffer(This, &_StubMsg); - - } - RpcEndFinally - - } - RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) - { - _StubMsg.MaxCount = (unsigned long) ( riid ); - - NdrClearOutParameters( - ( PMIDL_STUB_MESSAGE )&_StubMsg, - ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1896], - ( void __RPC_FAR * )ppv); - _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); - } - RpcEndExcept - return _RetVal; -} - -void __RPC_STUB ITypeFactory_CreateFromTypeInfo_Stub( - IRpcStubBuffer *This, - IRpcChannelBuffer *_pRpcChannelBuffer, - PRPC_MESSAGE _pRpcMessage, - DWORD *_pdwStubPhase) -{ - IUnknown __RPC_FAR *__RPC_FAR *_M101; - HRESULT _RetVal; - MIDL_STUB_MESSAGE _StubMsg; - ITypeInfo __RPC_FAR *pTypeInfo; - IUnknown __RPC_FAR *__RPC_FAR *ppv; - IID* riid = 0; - -NdrStubInitialize( - _pRpcMessage, - &_StubMsg, - &Object_StubDesc, - _pRpcChannelBuffer); - pTypeInfo = 0; - ppv = 0; - RpcTryFinally - { - if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) - NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[480] ); - - NdrInterfacePointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&pTypeInfo, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[10], - (unsigned char)0 ); - - NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR * __RPC_FAR *)&riid, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], - (unsigned char)0 ); - - ppv = (void *)&_M101; - _M101 = 0; - - *_pdwStubPhase = STUB_CALL_SERVER; - _RetVal = (((ITypeFactory*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> CreateFromTypeInfo( - (ITypeFactory *) ((CStdStubBuffer *)This)->pvServerObject, - pTypeInfo, - riid, - ppv); - - *_pdwStubPhase = STUB_MARSHAL; - - _StubMsg.BufferLength = 0U + 4U; - _StubMsg.MaxCount = (unsigned long) ( riid ); - - NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, - (unsigned char __RPC_FAR *)ppv, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1896] ); - - _StubMsg.BufferLength += 16; - - NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); - _StubMsg.MaxCount = (unsigned long) ( riid ); - - NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, - (unsigned char __RPC_FAR *)ppv, - (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1896] ); - - _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); - *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; - _StubMsg.Buffer += sizeof(HRESULT); - - } - RpcFinally - { - NdrInterfacePointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)pTypeInfo, - &__MIDL_TypeFormatString.Format[10] ); - - _StubMsg.MaxCount = (unsigned long) ( riid ); - - NdrPointerFree( &_StubMsg, - (unsigned char __RPC_FAR *)ppv, - &__MIDL_TypeFormatString.Format[1896] ); - - } - RpcEndFinally - _pRpcMessage->BufferLength = - (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); - -} - -static const USER_MARSHAL_ROUTINE_QUADRUPLE UserMarshalRoutines[3] = - { - { - (USER_MARSHAL_SIZING_ROUTINE)VARIANT_UserSize, - (USER_MARSHAL_MARSHALLING_ROUTINE)VARIANT_UserMarshal, - (USER_MARSHAL_UNMARSHALLING_ROUTINE)VARIANT_UserUnmarshal, - (USER_MARSHAL_FREEING_ROUTINE)VARIANT_UserFree - }, - { - (USER_MARSHAL_SIZING_ROUTINE)BSTR_UserSize, - (USER_MARSHAL_MARSHALLING_ROUTINE)BSTR_UserMarshal, - (USER_MARSHAL_UNMARSHALLING_ROUTINE)BSTR_UserUnmarshal, - (USER_MARSHAL_FREEING_ROUTINE)BSTR_UserFree - }, - { - (USER_MARSHAL_SIZING_ROUTINE)CLEANLOCALSTORAGE_UserSize, - (USER_MARSHAL_MARSHALLING_ROUTINE)CLEANLOCALSTORAGE_UserMarshal, - (USER_MARSHAL_UNMARSHALLING_ROUTINE)CLEANLOCALSTORAGE_UserUnmarshal, - (USER_MARSHAL_FREEING_ROUTINE)CLEANLOCALSTORAGE_UserFree - } - - }; - -static const MIDL_STUB_DESC Object_StubDesc = - { - 0, - NdrOleAllocate, - NdrOleFree, - { 0 }, - 0, - 0, - 0, - 0, - __MIDL_TypeFormatString.Format, - 1, /* -error bounds_check flag */ - 0x20000, /* Ndr library version */ - 0, - 0x50100a4, /* MIDL Version 5.1.164 */ - 0, - UserMarshalRoutines, - 0, /* notify & notify_flag routine table */ - 1, /* Flags */ - 0, /* Reserved3 */ - 0, /* Reserved4 */ - 0 /* Reserved5 */ - }; - -const CINTERFACE_PROXY_VTABLE(4) _ITypeFactoryProxyVtbl = -{ - { &IID_ITypeFactory }, - { - IUnknown_QueryInterface_Proxy, - IUnknown_AddRef_Proxy, - IUnknown_Release_Proxy , - ITypeFactory_CreateFromTypeInfo_Proxy - } -}; - - -static const PRPC_STUB_FUNCTION ITypeFactory_table[] = -{ - ITypeFactory_CreateFromTypeInfo_Stub -}; - -const CInterfaceStubVtbl _ITypeFactoryStubVtbl = -{ - { - &IID_ITypeFactory, - 0, - 4, - &ITypeFactory_table[-3] - }, - { CStdStubBuffer_METHODS } -}; - - -/* Object interface: ITypeMarshal, ver. 0.0, - GUID={0x0000002D,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ - - -/* Object interface: IRecordInfo, ver. 0.0, - GUID={0x0000002F,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ - - -/* Object interface: ICreateTypeInfo, ver. 0.0, - GUID={0x00020405,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ - - -/* Object interface: ICreateTypeInfo2, ver. 0.0, - GUID={0x0002040E,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ - - -/* Object interface: ICreateTypeLib, ver. 0.0, - GUID={0x00020406,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ - - -/* Object interface: ICreateTypeLib2, ver. 0.0, - GUID={0x0002040F,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ - -#if !defined(__RPC_WIN32__) -#error Invalid build platform for this stub. -#endif - -#if !(TARGET_IS_NT40_OR_LATER) -#error You need a Windows NT 4.0 or later to run this stub because it uses these features: -#error [wire_marshal] or [user_marshal] attribute. -#error However, your C/C++ compilation flags indicate you intend to run this app on earlier systems. -#error This app will die there with the RPC_X_WRONG_STUB_VERSION error. -#endif - - -static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString = - { - 0, - { - - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 2 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ -/* 4 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 6 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 8 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 10 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 12 */ NdrFcShort( 0x6 ), /* Type Offset=6 */ -/* 14 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 16 */ - 0x4d, /* FC_IN_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 18 */ NdrFcShort( 0x1c ), /* Type Offset=28 */ -/* 20 */ - 0x4d, /* FC_IN_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 22 */ NdrFcShort( 0x32 ), /* Type Offset=50 */ -/* 24 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 26 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 28 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 30 */ NdrFcShort( 0x54 ), /* Type Offset=84 */ -/* 32 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 34 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 36 */ - 0x4d, /* FC_IN_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 38 */ NdrFcShort( 0x1c ), /* Type Offset=28 */ -/* 40 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 42 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 44 */ - 0x4d, /* FC_IN_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 46 */ NdrFcShort( 0x62 ), /* Type Offset=98 */ -/* 48 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 50 */ NdrFcShort( 0x44e ), /* Type Offset=1102 */ -/* 52 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 54 */ NdrFcShort( 0x460 ), /* Type Offset=1120 */ -/* 56 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 58 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ -/* 60 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 62 */ - 0x4d, /* FC_IN_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 64 */ NdrFcShort( 0x48e ), /* Type Offset=1166 */ -/* 66 */ - 0x50, /* FC_IN_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 68 */ NdrFcShort( 0x49c ), /* Type Offset=1180 */ -/* 70 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 72 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 74 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 76 */ NdrFcShort( 0x4b2 ), /* Type Offset=1202 */ -/* 78 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 80 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ -/* 82 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 84 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 86 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 88 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 90 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 92 */ NdrFcShort( 0x4c8 ), /* Type Offset=1224 */ -/* 94 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 96 */ - 0x4d, /* FC_IN_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 98 */ NdrFcShort( 0x4de ), /* Type Offset=1246 */ -/* 100 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 102 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x6, /* FC_SHORT */ -/* 104 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 106 */ NdrFcShort( 0x6 ), /* Type Offset=6 */ -/* 108 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 110 */ NdrFcShort( 0x4e2 ), /* Type Offset=1250 */ -/* 112 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 114 */ NdrFcShort( 0x4e6 ), /* Type Offset=1254 */ -/* 116 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 118 */ NdrFcShort( 0x5b8 ), /* Type Offset=1464 */ -/* 120 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 122 */ NdrFcShort( 0x604 ), /* Type Offset=1540 */ -/* 124 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 126 */ NdrFcShort( 0x61a ), /* Type Offset=1562 */ -/* 128 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 130 */ - 0x4d, /* FC_IN_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 132 */ NdrFcShort( 0x4de ), /* Type Offset=1246 */ -/* 134 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 136 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 138 */ NdrFcShort( 0x6 ), /* Type Offset=6 */ -/* 140 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 142 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 144 */ NdrFcShort( 0x62a ), /* Type Offset=1578 */ -/* 146 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 148 */ NdrFcShort( 0x666 ), /* Type Offset=1638 */ -/* 150 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 152 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 154 */ NdrFcShort( 0x604 ), /* Type Offset=1540 */ -/* 156 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 158 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 160 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 162 */ NdrFcShort( 0x4e6 ), /* Type Offset=1254 */ -/* 164 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 166 */ NdrFcShort( 0x676 ), /* Type Offset=1654 */ -/* 168 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 170 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 172 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 174 */ NdrFcShort( 0x5b8 ), /* Type Offset=1464 */ -/* 176 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 178 */ NdrFcShort( 0x686 ), /* Type Offset=1670 */ -/* 180 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 182 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 184 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 186 */ NdrFcShort( 0x696 ), /* Type Offset=1686 */ -/* 188 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 190 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 192 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ -/* 194 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 196 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 198 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 200 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ -/* 202 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 204 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 206 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 208 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 210 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ -/* 212 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 214 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ -/* 216 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 218 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ -/* 220 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 222 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ -/* 224 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 226 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 228 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0xe, /* FC_ENUM32 */ -/* 230 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 232 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 234 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ -/* 236 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 238 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ -/* 240 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 242 */ NdrFcShort( 0x6b0 ), /* Type Offset=1712 */ -/* 244 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 246 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 248 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 250 */ NdrFcShort( 0x6 ), /* Type Offset=6 */ -/* 252 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 254 */ - 0x4d, /* FC_IN_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 256 */ NdrFcShort( 0x1c ), /* Type Offset=28 */ -/* 258 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 260 */ NdrFcShort( 0x6b4 ), /* Type Offset=1716 */ -/* 262 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 264 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 266 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 268 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ -/* 270 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 272 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 274 */ NdrFcShort( 0x6be ), /* Type Offset=1726 */ -/* 276 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 278 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ -/* 280 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 282 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 284 */ NdrFcShort( 0x4e2 ), /* Type Offset=1250 */ -/* 286 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 288 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 290 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0xe, /* FC_ENUM32 */ -/* 292 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 294 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ -/* 296 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 298 */ - 0x4d, /* FC_IN_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 300 */ NdrFcShort( 0x1c ), /* Type Offset=28 */ -/* 302 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 304 */ NdrFcShort( 0x44e ), /* Type Offset=1102 */ -/* 306 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 308 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 310 */ - 0x4d, /* FC_IN_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 312 */ NdrFcShort( 0x1c ), /* Type Offset=28 */ -/* 314 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 316 */ NdrFcShort( 0x44e ), /* Type Offset=1102 */ -/* 318 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 320 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 322 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 324 */ - 0x4d, /* FC_IN_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 326 */ NdrFcShort( 0x1c ), /* Type Offset=28 */ -/* 328 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 330 */ NdrFcShort( 0x44e ), /* Type Offset=1102 */ -/* 332 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 334 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 336 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 338 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 340 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 342 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ -/* 344 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 346 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ -/* 348 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 350 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ -/* 352 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 354 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 356 */ NdrFcShort( 0x6d4 ), /* Type Offset=1748 */ -/* 358 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 360 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 362 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 364 */ NdrFcShort( 0x6d4 ), /* Type Offset=1748 */ -/* 366 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 368 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 370 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 372 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 374 */ NdrFcShort( 0x6d4 ), /* Type Offset=1748 */ -/* 376 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 378 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 380 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 382 */ NdrFcShort( 0x4e2 ), /* Type Offset=1250 */ -/* 384 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 386 */ - 0x4d, /* FC_IN_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 388 */ NdrFcShort( 0x1c ), /* Type Offset=28 */ -/* 390 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 392 */ NdrFcShort( 0x6 ), /* Type Offset=6 */ -/* 394 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 396 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 398 */ NdrFcShort( 0x70c ), /* Type Offset=1804 */ -/* 400 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 402 */ NdrFcShort( 0x728 ), /* Type Offset=1832 */ -/* 404 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 406 */ - 0x4d, /* FC_IN_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 408 */ NdrFcShort( 0x4de ), /* Type Offset=1246 */ -/* 410 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 412 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 414 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ -/* 416 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 418 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ -/* 420 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 422 */ - 0x4d, /* FC_IN_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 424 */ NdrFcShort( 0x4de ), /* Type Offset=1246 */ -/* 426 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 428 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 430 */ NdrFcShort( 0x738 ), /* Type Offset=1848 */ -/* 432 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 434 */ NdrFcShort( 0x74e ), /* Type Offset=1870 */ -/* 436 */ - 0x50, /* FC_IN_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 438 */ NdrFcShort( 0x760 ), /* Type Offset=1888 */ -/* 440 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 442 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ -/* 444 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 446 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 448 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ -/* 450 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 452 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ -/* 454 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 456 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 458 */ NdrFcShort( 0x764 ), /* Type Offset=1892 */ -/* 460 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 462 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 464 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ -/* 466 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 468 */ - 0x4d, /* FC_IN_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 470 */ NdrFcShort( 0x1c ), /* Type Offset=28 */ -/* 472 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 474 */ - 0x4d, /* FC_IN_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 476 */ NdrFcShort( 0x4de ), /* Type Offset=1246 */ -/* 478 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ -/* 480 */ - 0x4d, /* FC_IN_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 482 */ NdrFcShort( 0xa ), /* Type Offset=10 */ -/* 484 */ - 0x4d, /* FC_IN_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 486 */ NdrFcShort( 0x1c ), /* Type Offset=28 */ -/* 488 */ - 0x51, /* FC_OUT_PARAM */ -#ifndef _ALPHA_ - 0x1, /* x86, MIPS & PPC Stack size = 1 */ -#else - 0x2, /* Alpha Stack size = 2 */ -#endif -/* 490 */ NdrFcShort( 0x768 ), /* Type Offset=1896 */ -/* 492 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ - 0x8, /* FC_LONG */ - - 0x0 - } - }; - -static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString = - { - 0, - { - NdrFcShort( 0x0 ), /* 0 */ -/* 2 */ - 0x11, 0xc, /* FC_RP [alloced_on_stack] [simple_pointer] */ -/* 4 */ 0x8, /* FC_LONG */ - 0x5c, /* FC_PAD */ -/* 6 */ - 0x11, 0x14, /* FC_RP [alloced_on_stack] */ -/* 8 */ NdrFcShort( 0x2 ), /* Offset= 2 (10) */ -/* 10 */ - 0x2f, /* FC_IP */ - 0x5a, /* FC_CONSTANT_IID */ -/* 12 */ NdrFcLong( 0x20401 ), /* 132097 */ -/* 16 */ NdrFcShort( 0x0 ), /* 0 */ -/* 18 */ NdrFcShort( 0x0 ), /* 0 */ -/* 20 */ 0xc0, /* 192 */ - 0x0, /* 0 */ -/* 22 */ 0x0, /* 0 */ - 0x0, /* 0 */ -/* 24 */ 0x0, /* 0 */ - 0x0, /* 0 */ -/* 26 */ 0x0, /* 0 */ - 0x46, /* 70 */ -/* 28 */ - 0x11, 0x0, /* FC_RP */ -/* 30 */ NdrFcShort( 0x8 ), /* Offset= 8 (38) */ -/* 32 */ - 0x1d, /* FC_SMFARRAY */ - 0x0, /* 0 */ -/* 34 */ NdrFcShort( 0x8 ), /* 8 */ -/* 36 */ 0x2, /* FC_CHAR */ - 0x5b, /* FC_END */ -/* 38 */ - 0x15, /* FC_STRUCT */ - 0x3, /* 3 */ -/* 40 */ NdrFcShort( 0x10 ), /* 16 */ -/* 42 */ 0x8, /* FC_LONG */ - 0x6, /* FC_SHORT */ -/* 44 */ 0x6, /* FC_SHORT */ - 0x4c, /* FC_EMBEDDED_COMPLEX */ -/* 46 */ 0x0, /* 0 */ - NdrFcShort( 0xfffffff1 ), /* Offset= -15 (32) */ - 0x5b, /* FC_END */ -/* 50 */ - 0x11, 0x0, /* FC_RP */ -/* 52 */ NdrFcShort( 0x2 ), /* Offset= 2 (54) */ -/* 54 */ - 0x1b, /* FC_CARRAY */ - 0x3, /* 3 */ -/* 56 */ NdrFcShort( 0x4 ), /* 4 */ -/* 58 */ 0x29, /* Corr desc: parameter, FC_ULONG */ - 0x0, /* */ -#ifndef _ALPHA_ -/* 60 */ NdrFcShort( 0xc ), /* x86, MIPS, PPC Stack size/offset = 12 */ -#else - NdrFcShort( 0x18 ), /* Alpha Stack size/offset = 24 */ -#endif -/* 62 */ - 0x4b, /* FC_PP */ - 0x5c, /* FC_PAD */ -/* 64 */ - 0x48, /* FC_VARIABLE_REPEAT */ - 0x49, /* FC_FIXED_OFFSET */ -/* 66 */ NdrFcShort( 0x4 ), /* 4 */ -/* 68 */ NdrFcShort( 0x0 ), /* 0 */ -/* 70 */ NdrFcShort( 0x1 ), /* 1 */ -/* 72 */ NdrFcShort( 0x0 ), /* 0 */ -/* 74 */ NdrFcShort( 0x0 ), /* 0 */ -/* 76 */ 0x12, 0x8, /* FC_UP [simple_pointer] */ -/* 78 */ - 0x25, /* FC_C_WSTRING */ - 0x5c, /* FC_PAD */ -/* 80 */ - 0x5b, /* FC_END */ - - 0x8, /* FC_LONG */ -/* 82 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 84 */ - 0x11, 0x0, /* FC_RP */ -/* 86 */ NdrFcShort( 0x2 ), /* Offset= 2 (88) */ -/* 88 */ - 0x1b, /* FC_CARRAY */ - 0x3, /* 3 */ -/* 90 */ NdrFcShort( 0x4 ), /* 4 */ -/* 92 */ 0x29, /* Corr desc: parameter, FC_ULONG */ - 0x0, /* */ -#ifndef _ALPHA_ -/* 94 */ NdrFcShort( 0xc ), /* x86, MIPS, PPC Stack size/offset = 12 */ -#else - NdrFcShort( 0x18 ), /* Alpha Stack size/offset = 24 */ -#endif -/* 96 */ 0x8, /* FC_LONG */ - 0x5b, /* FC_END */ -/* 98 */ - 0x11, 0x0, /* FC_RP */ -/* 100 */ NdrFcShort( 0x3d4 ), /* Offset= 980 (1080) */ -/* 102 */ - 0x12, 0x0, /* FC_UP */ -/* 104 */ NdrFcShort( 0x396 ), /* Offset= 918 (1022) */ -/* 106 */ - 0x2b, /* FC_NON_ENCAPSULATED_UNION */ - 0x7, /* FC_USHORT */ -/* 108 */ 0x7, /* Corr desc: FC_USHORT */ - 0x0, /* */ -/* 110 */ NdrFcShort( 0xfff8 ), /* -8 */ -/* 112 */ NdrFcShort( 0x2 ), /* Offset= 2 (114) */ -/* 114 */ NdrFcShort( 0x10 ), /* 16 */ -/* 116 */ NdrFcShort( 0x2b ), /* 43 */ -/* 118 */ NdrFcLong( 0x0 ), /* 0 */ -/* 122 */ NdrFcShort( 0x0 ), /* Offset= 0 (122) */ -/* 124 */ NdrFcLong( 0x1 ), /* 1 */ -/* 128 */ NdrFcShort( 0x0 ), /* Offset= 0 (128) */ -/* 130 */ NdrFcLong( 0x10 ), /* 16 */ -/* 134 */ NdrFcShort( 0x8002 ), /* Simple arm type: FC_CHAR */ -/* 136 */ NdrFcLong( 0x12 ), /* 18 */ -/* 140 */ NdrFcShort( 0x8006 ), /* Simple arm type: FC_SHORT */ -/* 142 */ NdrFcLong( 0x13 ), /* 19 */ -/* 146 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ -/* 148 */ NdrFcLong( 0x16 ), /* 22 */ -/* 152 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ -/* 154 */ NdrFcLong( 0x17 ), /* 23 */ -/* 158 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ -/* 160 */ NdrFcLong( 0x11 ), /* 17 */ -/* 164 */ NdrFcShort( 0x8002 ), /* Simple arm type: FC_CHAR */ -/* 166 */ NdrFcLong( 0x2 ), /* 2 */ -/* 170 */ NdrFcShort( 0x8006 ), /* Simple arm type: FC_SHORT */ -/* 172 */ NdrFcLong( 0x3 ), /* 3 */ -/* 176 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ -/* 178 */ NdrFcLong( 0x4 ), /* 4 */ -/* 182 */ NdrFcShort( 0x800a ), /* Simple arm type: FC_FLOAT */ -/* 184 */ NdrFcLong( 0x5 ), /* 5 */ -/* 188 */ NdrFcShort( 0x800c ), /* Simple arm type: FC_DOUBLE */ -/* 190 */ NdrFcLong( 0xb ), /* 11 */ -/* 194 */ NdrFcShort( 0x8006 ), /* Simple arm type: FC_SHORT */ -/* 196 */ NdrFcLong( 0xa ), /* 10 */ -/* 200 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ -/* 202 */ NdrFcLong( 0x7 ), /* 7 */ -/* 206 */ NdrFcShort( 0x800c ), /* Simple arm type: FC_DOUBLE */ -/* 208 */ NdrFcLong( 0x8 ), /* 8 */ -/* 212 */ NdrFcShort( 0xa6 ), /* Offset= 166 (378) */ -/* 214 */ NdrFcLong( 0x6 ), /* 6 */ -/* 218 */ NdrFcShort( 0xb8 ), /* Offset= 184 (402) */ -/* 220 */ NdrFcLong( 0xe ), /* 14 */ -/* 224 */ NdrFcShort( 0xb8 ), /* Offset= 184 (408) */ -/* 226 */ NdrFcLong( 0xd ), /* 13 */ -/* 230 */ NdrFcShort( 0xbe ), /* Offset= 190 (420) */ -/* 232 */ NdrFcLong( 0x9 ), /* 9 */ -/* 236 */ NdrFcShort( 0xca ), /* Offset= 202 (438) */ -/* 238 */ NdrFcLong( 0x2000 ), /* 8192 */ -/* 242 */ NdrFcShort( 0xd6 ), /* Offset= 214 (456) */ -/* 244 */ NdrFcLong( 0x4010 ), /* 16400 */ -/* 248 */ NdrFcShort( 0x2ce ), /* Offset= 718 (966) */ -/* 250 */ NdrFcLong( 0x4012 ), /* 16402 */ -/* 254 */ NdrFcShort( 0x2cc ), /* Offset= 716 (970) */ -/* 256 */ NdrFcLong( 0x4013 ), /* 16403 */ -/* 260 */ NdrFcShort( 0x2ca ), /* Offset= 714 (974) */ -/* 262 */ NdrFcLong( 0x4016 ), /* 16406 */ -/* 266 */ NdrFcShort( 0x2c4 ), /* Offset= 708 (974) */ -/* 268 */ NdrFcLong( 0x4017 ), /* 16407 */ -/* 272 */ NdrFcShort( 0x2be ), /* Offset= 702 (974) */ -/* 274 */ NdrFcLong( 0x4011 ), /* 16401 */ -/* 278 */ NdrFcShort( 0x2b0 ), /* Offset= 688 (966) */ -/* 280 */ NdrFcLong( 0x4002 ), /* 16386 */ -/* 284 */ NdrFcShort( 0x2ae ), /* Offset= 686 (970) */ -/* 286 */ NdrFcLong( 0x4003 ), /* 16387 */ -/* 290 */ NdrFcShort( 0x2ac ), /* Offset= 684 (974) */ -/* 292 */ NdrFcLong( 0x4004 ), /* 16388 */ -/* 296 */ NdrFcShort( 0x2aa ), /* Offset= 682 (978) */ -/* 298 */ NdrFcLong( 0x4005 ), /* 16389 */ -/* 302 */ NdrFcShort( 0x2a8 ), /* Offset= 680 (982) */ -/* 304 */ NdrFcLong( 0x400b ), /* 16395 */ -/* 308 */ NdrFcShort( 0x296 ), /* Offset= 662 (970) */ -/* 310 */ NdrFcLong( 0x400a ), /* 16394 */ -/* 314 */ NdrFcShort( 0x294 ), /* Offset= 660 (974) */ -/* 316 */ NdrFcLong( 0x4007 ), /* 16391 */ -/* 320 */ NdrFcShort( 0x296 ), /* Offset= 662 (982) */ -/* 322 */ NdrFcLong( 0x4008 ), /* 16392 */ -/* 326 */ NdrFcShort( 0x294 ), /* Offset= 660 (986) */ -/* 328 */ NdrFcLong( 0x400c ), /* 16396 */ -/* 332 */ NdrFcShort( 0x292 ), /* Offset= 658 (990) */ -/* 334 */ NdrFcLong( 0x4006 ), /* 16390 */ -/* 338 */ NdrFcShort( 0x294 ), /* Offset= 660 (998) */ -/* 340 */ NdrFcLong( 0x400e ), /* 16398 */ -/* 344 */ NdrFcShort( 0x292 ), /* Offset= 658 (1002) */ -/* 346 */ NdrFcLong( 0x400d ), /* 16397 */ -/* 350 */ NdrFcShort( 0x290 ), /* Offset= 656 (1006) */ -/* 352 */ NdrFcLong( 0x4009 ), /* 16393 */ -/* 356 */ NdrFcShort( 0x28e ), /* Offset= 654 (1010) */ -/* 358 */ NdrFcLong( 0x6000 ), /* 24576 */ -/* 362 */ NdrFcShort( 0x28c ), /* Offset= 652 (1014) */ -/* 364 */ NdrFcLong( 0x24 ), /* 36 */ -/* 368 */ NdrFcShort( 0x28a ), /* Offset= 650 (1018) */ -/* 370 */ NdrFcLong( 0x4024 ), /* 16420 */ -/* 374 */ NdrFcShort( 0x284 ), /* Offset= 644 (1018) */ -/* 376 */ NdrFcShort( 0xffffffff ), /* Offset= -1 (375) */ -/* 378 */ - 0x12, 0x0, /* FC_UP */ -/* 380 */ NdrFcShort( 0xc ), /* Offset= 12 (392) */ -/* 382 */ - 0x1b, /* FC_CARRAY */ - 0x1, /* 1 */ -/* 384 */ NdrFcShort( 0x2 ), /* 2 */ -/* 386 */ 0x9, /* Corr desc: FC_ULONG */ - 0x0, /* */ -/* 388 */ NdrFcShort( 0xfffc ), /* -4 */ -/* 390 */ 0x6, /* FC_SHORT */ - 0x5b, /* FC_END */ -/* 392 */ - 0x17, /* FC_CSTRUCT */ - 0x3, /* 3 */ -/* 394 */ NdrFcShort( 0x8 ), /* 8 */ -/* 396 */ NdrFcShort( 0xfffffff2 ), /* Offset= -14 (382) */ -/* 398 */ 0x8, /* FC_LONG */ - 0x8, /* FC_LONG */ -/* 400 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 402 */ - 0x15, /* FC_STRUCT */ - 0x7, /* 7 */ -/* 404 */ NdrFcShort( 0x8 ), /* 8 */ -/* 406 */ 0xb, /* FC_HYPER */ - 0x5b, /* FC_END */ -/* 408 */ - 0x15, /* FC_STRUCT */ - 0x7, /* 7 */ -/* 410 */ NdrFcShort( 0x10 ), /* 16 */ -/* 412 */ 0x6, /* FC_SHORT */ - 0x2, /* FC_CHAR */ -/* 414 */ 0x2, /* FC_CHAR */ - 0x38, /* FC_ALIGNM4 */ -/* 416 */ 0x8, /* FC_LONG */ - 0x39, /* FC_ALIGNM8 */ -/* 418 */ 0xb, /* FC_HYPER */ - 0x5b, /* FC_END */ -/* 420 */ - 0x2f, /* FC_IP */ - 0x5a, /* FC_CONSTANT_IID */ -/* 422 */ NdrFcLong( 0x0 ), /* 0 */ -/* 426 */ NdrFcShort( 0x0 ), /* 0 */ -/* 428 */ NdrFcShort( 0x0 ), /* 0 */ -/* 430 */ 0xc0, /* 192 */ - 0x0, /* 0 */ -/* 432 */ 0x0, /* 0 */ - 0x0, /* 0 */ -/* 434 */ 0x0, /* 0 */ - 0x0, /* 0 */ -/* 436 */ 0x0, /* 0 */ - 0x46, /* 70 */ -/* 438 */ - 0x2f, /* FC_IP */ - 0x5a, /* FC_CONSTANT_IID */ -/* 440 */ NdrFcLong( 0x20400 ), /* 132096 */ -/* 444 */ NdrFcShort( 0x0 ), /* 0 */ -/* 446 */ NdrFcShort( 0x0 ), /* 0 */ -/* 448 */ 0xc0, /* 192 */ - 0x0, /* 0 */ -/* 450 */ 0x0, /* 0 */ - 0x0, /* 0 */ -/* 452 */ 0x0, /* 0 */ - 0x0, /* 0 */ -/* 454 */ 0x0, /* 0 */ - 0x46, /* 70 */ -/* 456 */ - 0x12, 0x0, /* FC_UP */ -/* 458 */ NdrFcShort( 0x1ea ), /* Offset= 490 (948) */ -/* 460 */ - 0x2a, /* FC_ENCAPSULATED_UNION */ - 0x49, /* 73 */ -/* 462 */ NdrFcShort( 0x18 ), /* 24 */ -/* 464 */ NdrFcShort( 0xa ), /* 10 */ -/* 466 */ NdrFcLong( 0x8 ), /* 8 */ -/* 470 */ NdrFcShort( 0x58 ), /* Offset= 88 (558) */ -/* 472 */ NdrFcLong( 0xd ), /* 13 */ -/* 476 */ NdrFcShort( 0x78 ), /* Offset= 120 (596) */ -/* 478 */ NdrFcLong( 0x9 ), /* 9 */ -/* 482 */ NdrFcShort( 0x94 ), /* Offset= 148 (630) */ -/* 484 */ NdrFcLong( 0xc ), /* 12 */ -/* 488 */ NdrFcShort( 0xbc ), /* Offset= 188 (676) */ -/* 490 */ NdrFcLong( 0x24 ), /* 36 */ -/* 494 */ NdrFcShort( 0x114 ), /* Offset= 276 (770) */ -/* 496 */ NdrFcLong( 0x800d ), /* 32781 */ -/* 500 */ NdrFcShort( 0x11e ), /* Offset= 286 (786) */ -/* 502 */ NdrFcLong( 0x10 ), /* 16 */ -/* 506 */ NdrFcShort( 0x136 ), /* Offset= 310 (816) */ -/* 508 */ NdrFcLong( 0x2 ), /* 2 */ -/* 512 */ NdrFcShort( 0x14e ), /* Offset= 334 (846) */ -/* 514 */ NdrFcLong( 0x3 ), /* 3 */ -/* 518 */ NdrFcShort( 0x166 ), /* Offset= 358 (876) */ -/* 520 */ NdrFcLong( 0x14 ), /* 20 */ -/* 524 */ NdrFcShort( 0x17e ), /* Offset= 382 (906) */ -/* 526 */ NdrFcShort( 0xffffffff ), /* Offset= -1 (525) */ -/* 528 */ - 0x1b, /* FC_CARRAY */ - 0x3, /* 3 */ -/* 530 */ NdrFcShort( 0x4 ), /* 4 */ -/* 532 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ - 0x0, /* */ -/* 534 */ NdrFcShort( 0x0 ), /* 0 */ -/* 536 */ - 0x4b, /* FC_PP */ - 0x5c, /* FC_PAD */ -/* 538 */ - 0x48, /* FC_VARIABLE_REPEAT */ - 0x49, /* FC_FIXED_OFFSET */ -/* 540 */ NdrFcShort( 0x4 ), /* 4 */ -/* 542 */ NdrFcShort( 0x0 ), /* 0 */ -/* 544 */ NdrFcShort( 0x1 ), /* 1 */ -/* 546 */ NdrFcShort( 0x0 ), /* 0 */ -/* 548 */ NdrFcShort( 0x0 ), /* 0 */ -/* 550 */ 0x12, 0x0, /* FC_UP */ -/* 552 */ NdrFcShort( 0xffffff60 ), /* Offset= -160 (392) */ -/* 554 */ - 0x5b, /* FC_END */ - - 0x8, /* FC_LONG */ -/* 556 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 558 */ - 0x16, /* FC_PSTRUCT */ - 0x3, /* 3 */ -/* 560 */ NdrFcShort( 0x8 ), /* 8 */ -/* 562 */ - 0x4b, /* FC_PP */ - 0x5c, /* FC_PAD */ -/* 564 */ - 0x46, /* FC_NO_REPEAT */ - 0x5c, /* FC_PAD */ -/* 566 */ NdrFcShort( 0x4 ), /* 4 */ -/* 568 */ NdrFcShort( 0x4 ), /* 4 */ -/* 570 */ 0x11, 0x0, /* FC_RP */ -/* 572 */ NdrFcShort( 0xffffffd4 ), /* Offset= -44 (528) */ -/* 574 */ - 0x5b, /* FC_END */ - - 0x8, /* FC_LONG */ -/* 576 */ 0x8, /* FC_LONG */ - 0x5b, /* FC_END */ -/* 578 */ - 0x21, /* FC_BOGUS_ARRAY */ - 0x3, /* 3 */ -/* 580 */ NdrFcShort( 0x0 ), /* 0 */ -/* 582 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ - 0x0, /* */ -/* 584 */ NdrFcShort( 0x0 ), /* 0 */ -/* 586 */ NdrFcLong( 0xffffffff ), /* -1 */ -/* 590 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 592 */ NdrFcShort( 0xffffff54 ), /* Offset= -172 (420) */ -/* 594 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 596 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x3, /* 3 */ -/* 598 */ NdrFcShort( 0x8 ), /* 8 */ -/* 600 */ NdrFcShort( 0x0 ), /* 0 */ -/* 602 */ NdrFcShort( 0x6 ), /* Offset= 6 (608) */ -/* 604 */ 0x8, /* FC_LONG */ - 0x36, /* FC_POINTER */ -/* 606 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 608 */ - 0x11, 0x0, /* FC_RP */ -/* 610 */ NdrFcShort( 0xffffffe0 ), /* Offset= -32 (578) */ -/* 612 */ - 0x21, /* FC_BOGUS_ARRAY */ - 0x3, /* 3 */ -/* 614 */ NdrFcShort( 0x0 ), /* 0 */ -/* 616 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ - 0x0, /* */ -/* 618 */ NdrFcShort( 0x0 ), /* 0 */ -/* 620 */ NdrFcLong( 0xffffffff ), /* -1 */ -/* 624 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 626 */ NdrFcShort( 0xffffff44 ), /* Offset= -188 (438) */ -/* 628 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 630 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x3, /* 3 */ -/* 632 */ NdrFcShort( 0x8 ), /* 8 */ -/* 634 */ NdrFcShort( 0x0 ), /* 0 */ -/* 636 */ NdrFcShort( 0x6 ), /* Offset= 6 (642) */ -/* 638 */ 0x8, /* FC_LONG */ - 0x36, /* FC_POINTER */ -/* 640 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 642 */ - 0x11, 0x0, /* FC_RP */ -/* 644 */ NdrFcShort( 0xffffffe0 ), /* Offset= -32 (612) */ -/* 646 */ - 0x1b, /* FC_CARRAY */ - 0x3, /* 3 */ -/* 648 */ NdrFcShort( 0x4 ), /* 4 */ -/* 650 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ - 0x0, /* */ -/* 652 */ NdrFcShort( 0x0 ), /* 0 */ -/* 654 */ - 0x4b, /* FC_PP */ - 0x5c, /* FC_PAD */ -/* 656 */ - 0x48, /* FC_VARIABLE_REPEAT */ - 0x49, /* FC_FIXED_OFFSET */ -/* 658 */ NdrFcShort( 0x4 ), /* 4 */ -/* 660 */ NdrFcShort( 0x0 ), /* 0 */ -/* 662 */ NdrFcShort( 0x1 ), /* 1 */ -/* 664 */ NdrFcShort( 0x0 ), /* 0 */ -/* 666 */ NdrFcShort( 0x0 ), /* 0 */ -/* 668 */ 0x12, 0x0, /* FC_UP */ -/* 670 */ NdrFcShort( 0x160 ), /* Offset= 352 (1022) */ -/* 672 */ - 0x5b, /* FC_END */ - - 0x8, /* FC_LONG */ -/* 674 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 676 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x3, /* 3 */ -/* 678 */ NdrFcShort( 0x8 ), /* 8 */ -/* 680 */ NdrFcShort( 0x0 ), /* 0 */ -/* 682 */ NdrFcShort( 0x6 ), /* Offset= 6 (688) */ -/* 684 */ 0x8, /* FC_LONG */ - 0x36, /* FC_POINTER */ -/* 686 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 688 */ - 0x11, 0x0, /* FC_RP */ -/* 690 */ NdrFcShort( 0xffffffd4 ), /* Offset= -44 (646) */ -/* 692 */ - 0x2f, /* FC_IP */ - 0x5a, /* FC_CONSTANT_IID */ -/* 694 */ NdrFcLong( 0x2f ), /* 47 */ -/* 698 */ NdrFcShort( 0x0 ), /* 0 */ -/* 700 */ NdrFcShort( 0x0 ), /* 0 */ -/* 702 */ 0xc0, /* 192 */ - 0x0, /* 0 */ -/* 704 */ 0x0, /* 0 */ - 0x0, /* 0 */ -/* 706 */ 0x0, /* 0 */ - 0x0, /* 0 */ -/* 708 */ 0x0, /* 0 */ - 0x46, /* 70 */ -/* 710 */ - 0x1b, /* FC_CARRAY */ - 0x0, /* 0 */ -/* 712 */ NdrFcShort( 0x1 ), /* 1 */ -/* 714 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ - 0x0, /* */ -/* 716 */ NdrFcShort( 0x4 ), /* 4 */ -/* 718 */ 0x1, /* FC_BYTE */ - 0x5b, /* FC_END */ -/* 720 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x3, /* 3 */ -/* 722 */ NdrFcShort( 0x10 ), /* 16 */ -/* 724 */ NdrFcShort( 0x0 ), /* 0 */ -/* 726 */ NdrFcShort( 0xa ), /* Offset= 10 (736) */ -/* 728 */ 0x8, /* FC_LONG */ - 0x8, /* FC_LONG */ -/* 730 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 732 */ NdrFcShort( 0xffffffd8 ), /* Offset= -40 (692) */ -/* 734 */ 0x36, /* FC_POINTER */ - 0x5b, /* FC_END */ -/* 736 */ - 0x12, 0x0, /* FC_UP */ -/* 738 */ NdrFcShort( 0xffffffe4 ), /* Offset= -28 (710) */ -/* 740 */ - 0x1b, /* FC_CARRAY */ - 0x3, /* 3 */ -/* 742 */ NdrFcShort( 0x4 ), /* 4 */ -/* 744 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ - 0x0, /* */ -/* 746 */ NdrFcShort( 0x0 ), /* 0 */ -/* 748 */ - 0x4b, /* FC_PP */ - 0x5c, /* FC_PAD */ -/* 750 */ - 0x48, /* FC_VARIABLE_REPEAT */ - 0x49, /* FC_FIXED_OFFSET */ -/* 752 */ NdrFcShort( 0x4 ), /* 4 */ -/* 754 */ NdrFcShort( 0x0 ), /* 0 */ -/* 756 */ NdrFcShort( 0x1 ), /* 1 */ -/* 758 */ NdrFcShort( 0x0 ), /* 0 */ -/* 760 */ NdrFcShort( 0x0 ), /* 0 */ -/* 762 */ 0x12, 0x0, /* FC_UP */ -/* 764 */ NdrFcShort( 0xffffffd4 ), /* Offset= -44 (720) */ -/* 766 */ - 0x5b, /* FC_END */ - - 0x8, /* FC_LONG */ -/* 768 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 770 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x3, /* 3 */ -/* 772 */ NdrFcShort( 0x8 ), /* 8 */ -/* 774 */ NdrFcShort( 0x0 ), /* 0 */ -/* 776 */ NdrFcShort( 0x6 ), /* Offset= 6 (782) */ -/* 778 */ 0x8, /* FC_LONG */ - 0x36, /* FC_POINTER */ -/* 780 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 782 */ - 0x11, 0x0, /* FC_RP */ -/* 784 */ NdrFcShort( 0xffffffd4 ), /* Offset= -44 (740) */ -/* 786 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x3, /* 3 */ -/* 788 */ NdrFcShort( 0x18 ), /* 24 */ -/* 790 */ NdrFcShort( 0x0 ), /* 0 */ -/* 792 */ NdrFcShort( 0xa ), /* Offset= 10 (802) */ -/* 794 */ 0x8, /* FC_LONG */ - 0x36, /* FC_POINTER */ -/* 796 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 798 */ NdrFcShort( 0xfffffd08 ), /* Offset= -760 (38) */ -/* 800 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 802 */ - 0x11, 0x0, /* FC_RP */ -/* 804 */ NdrFcShort( 0xffffff1e ), /* Offset= -226 (578) */ -/* 806 */ - 0x1b, /* FC_CARRAY */ - 0x0, /* 0 */ -/* 808 */ NdrFcShort( 0x1 ), /* 1 */ -/* 810 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ - 0x0, /* */ -/* 812 */ NdrFcShort( 0x0 ), /* 0 */ -/* 814 */ 0x1, /* FC_BYTE */ - 0x5b, /* FC_END */ -/* 816 */ - 0x16, /* FC_PSTRUCT */ - 0x3, /* 3 */ -/* 818 */ NdrFcShort( 0x8 ), /* 8 */ -/* 820 */ - 0x4b, /* FC_PP */ - 0x5c, /* FC_PAD */ -/* 822 */ - 0x46, /* FC_NO_REPEAT */ - 0x5c, /* FC_PAD */ -/* 824 */ NdrFcShort( 0x4 ), /* 4 */ -/* 826 */ NdrFcShort( 0x4 ), /* 4 */ -/* 828 */ 0x12, 0x0, /* FC_UP */ -/* 830 */ NdrFcShort( 0xffffffe8 ), /* Offset= -24 (806) */ -/* 832 */ - 0x5b, /* FC_END */ - - 0x8, /* FC_LONG */ -/* 834 */ 0x8, /* FC_LONG */ - 0x5b, /* FC_END */ -/* 836 */ - 0x1b, /* FC_CARRAY */ - 0x1, /* 1 */ -/* 838 */ NdrFcShort( 0x2 ), /* 2 */ -/* 840 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ - 0x0, /* */ -/* 842 */ NdrFcShort( 0x0 ), /* 0 */ -/* 844 */ 0x6, /* FC_SHORT */ - 0x5b, /* FC_END */ -/* 846 */ - 0x16, /* FC_PSTRUCT */ - 0x3, /* 3 */ -/* 848 */ NdrFcShort( 0x8 ), /* 8 */ -/* 850 */ - 0x4b, /* FC_PP */ - 0x5c, /* FC_PAD */ -/* 852 */ - 0x46, /* FC_NO_REPEAT */ - 0x5c, /* FC_PAD */ -/* 854 */ NdrFcShort( 0x4 ), /* 4 */ -/* 856 */ NdrFcShort( 0x4 ), /* 4 */ -/* 858 */ 0x12, 0x0, /* FC_UP */ -/* 860 */ NdrFcShort( 0xffffffe8 ), /* Offset= -24 (836) */ -/* 862 */ - 0x5b, /* FC_END */ - - 0x8, /* FC_LONG */ -/* 864 */ 0x8, /* FC_LONG */ - 0x5b, /* FC_END */ -/* 866 */ - 0x1b, /* FC_CARRAY */ - 0x3, /* 3 */ -/* 868 */ NdrFcShort( 0x4 ), /* 4 */ -/* 870 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ - 0x0, /* */ -/* 872 */ NdrFcShort( 0x0 ), /* 0 */ -/* 874 */ 0x8, /* FC_LONG */ - 0x5b, /* FC_END */ -/* 876 */ - 0x16, /* FC_PSTRUCT */ - 0x3, /* 3 */ -/* 878 */ NdrFcShort( 0x8 ), /* 8 */ -/* 880 */ - 0x4b, /* FC_PP */ - 0x5c, /* FC_PAD */ -/* 882 */ - 0x46, /* FC_NO_REPEAT */ - 0x5c, /* FC_PAD */ -/* 884 */ NdrFcShort( 0x4 ), /* 4 */ -/* 886 */ NdrFcShort( 0x4 ), /* 4 */ -/* 888 */ 0x12, 0x0, /* FC_UP */ -/* 890 */ NdrFcShort( 0xffffffe8 ), /* Offset= -24 (866) */ -/* 892 */ - 0x5b, /* FC_END */ - - 0x8, /* FC_LONG */ -/* 894 */ 0x8, /* FC_LONG */ - 0x5b, /* FC_END */ -/* 896 */ - 0x1b, /* FC_CARRAY */ - 0x7, /* 7 */ -/* 898 */ NdrFcShort( 0x8 ), /* 8 */ -/* 900 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ - 0x0, /* */ -/* 902 */ NdrFcShort( 0x0 ), /* 0 */ -/* 904 */ 0xb, /* FC_HYPER */ - 0x5b, /* FC_END */ -/* 906 */ - 0x16, /* FC_PSTRUCT */ - 0x3, /* 3 */ -/* 908 */ NdrFcShort( 0x8 ), /* 8 */ -/* 910 */ - 0x4b, /* FC_PP */ - 0x5c, /* FC_PAD */ -/* 912 */ - 0x46, /* FC_NO_REPEAT */ - 0x5c, /* FC_PAD */ -/* 914 */ NdrFcShort( 0x4 ), /* 4 */ -/* 916 */ NdrFcShort( 0x4 ), /* 4 */ -/* 918 */ 0x12, 0x0, /* FC_UP */ -/* 920 */ NdrFcShort( 0xffffffe8 ), /* Offset= -24 (896) */ -/* 922 */ - 0x5b, /* FC_END */ - - 0x8, /* FC_LONG */ -/* 924 */ 0x8, /* FC_LONG */ - 0x5b, /* FC_END */ -/* 926 */ - 0x15, /* FC_STRUCT */ - 0x3, /* 3 */ -/* 928 */ NdrFcShort( 0x8 ), /* 8 */ -/* 930 */ 0x8, /* FC_LONG */ - 0x8, /* FC_LONG */ -/* 932 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 934 */ - 0x1b, /* FC_CARRAY */ - 0x3, /* 3 */ -/* 936 */ NdrFcShort( 0x8 ), /* 8 */ -/* 938 */ 0x7, /* Corr desc: FC_USHORT */ - 0x0, /* */ -/* 940 */ NdrFcShort( 0xffd8 ), /* -40 */ -/* 942 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 944 */ NdrFcShort( 0xffffffee ), /* Offset= -18 (926) */ -/* 946 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 948 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x3, /* 3 */ -/* 950 */ NdrFcShort( 0x28 ), /* 40 */ -/* 952 */ NdrFcShort( 0xffffffee ), /* Offset= -18 (934) */ -/* 954 */ NdrFcShort( 0x0 ), /* Offset= 0 (954) */ -/* 956 */ 0x6, /* FC_SHORT */ - 0x6, /* FC_SHORT */ -/* 958 */ 0x38, /* FC_ALIGNM4 */ - 0x8, /* FC_LONG */ -/* 960 */ 0x8, /* FC_LONG */ - 0x4c, /* FC_EMBEDDED_COMPLEX */ -/* 962 */ 0x0, /* 0 */ - NdrFcShort( 0xfffffe09 ), /* Offset= -503 (460) */ - 0x5b, /* FC_END */ -/* 966 */ - 0x12, 0x8, /* FC_UP [simple_pointer] */ -/* 968 */ 0x2, /* FC_CHAR */ - 0x5c, /* FC_PAD */ -/* 970 */ - 0x12, 0x8, /* FC_UP [simple_pointer] */ -/* 972 */ 0x6, /* FC_SHORT */ - 0x5c, /* FC_PAD */ -/* 974 */ - 0x12, 0x8, /* FC_UP [simple_pointer] */ -/* 976 */ 0x8, /* FC_LONG */ - 0x5c, /* FC_PAD */ -/* 978 */ - 0x12, 0x8, /* FC_UP [simple_pointer] */ -/* 980 */ 0xa, /* FC_FLOAT */ - 0x5c, /* FC_PAD */ -/* 982 */ - 0x12, 0x8, /* FC_UP [simple_pointer] */ -/* 984 */ 0xc, /* FC_DOUBLE */ - 0x5c, /* FC_PAD */ -/* 986 */ - 0x12, 0x10, /* FC_UP */ -/* 988 */ NdrFcShort( 0xfffffd9e ), /* Offset= -610 (378) */ -/* 990 */ - 0x12, 0x10, /* FC_UP */ -/* 992 */ NdrFcShort( 0x2 ), /* Offset= 2 (994) */ -/* 994 */ - 0x12, 0x0, /* FC_UP */ -/* 996 */ NdrFcShort( 0xfffffc1c ), /* Offset= -996 (0) */ -/* 998 */ - 0x12, 0x0, /* FC_UP */ -/* 1000 */ NdrFcShort( 0xfffffdaa ), /* Offset= -598 (402) */ -/* 1002 */ - 0x12, 0x0, /* FC_UP */ -/* 1004 */ NdrFcShort( 0xfffffdac ), /* Offset= -596 (408) */ -/* 1006 */ - 0x12, 0x10, /* FC_UP */ -/* 1008 */ NdrFcShort( 0xfffffdb4 ), /* Offset= -588 (420) */ -/* 1010 */ - 0x12, 0x10, /* FC_UP */ -/* 1012 */ NdrFcShort( 0xfffffdc2 ), /* Offset= -574 (438) */ -/* 1014 */ - 0x12, 0x10, /* FC_UP */ -/* 1016 */ NdrFcShort( 0xfffffdd0 ), /* Offset= -560 (456) */ -/* 1018 */ - 0x12, 0x0, /* FC_UP */ -/* 1020 */ NdrFcShort( 0xfffffed4 ), /* Offset= -300 (720) */ -/* 1022 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x7, /* 7 */ -/* 1024 */ NdrFcShort( 0x20 ), /* 32 */ -/* 1026 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1028 */ NdrFcShort( 0x0 ), /* Offset= 0 (1028) */ -/* 1030 */ 0x8, /* FC_LONG */ - 0x8, /* FC_LONG */ -/* 1032 */ 0x6, /* FC_SHORT */ - 0x6, /* FC_SHORT */ -/* 1034 */ 0x6, /* FC_SHORT */ - 0x6, /* FC_SHORT */ -/* 1036 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1038 */ NdrFcShort( 0xfffffc5c ), /* Offset= -932 (106) */ -/* 1040 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 1042 */ 0xb4, /* FC_USER_MARSHAL */ - 0x83, /* 131 */ -/* 1044 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1046 */ NdrFcShort( 0x10 ), /* 16 */ -/* 1048 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1050 */ NdrFcShort( 0xfffffc4c ), /* Offset= -948 (102) */ -/* 1052 */ - 0x21, /* FC_BOGUS_ARRAY */ - 0x3, /* 3 */ -/* 1054 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1056 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ - 0x0, /* */ -/* 1058 */ NdrFcShort( 0x8 ), /* 8 */ -/* 1060 */ NdrFcLong( 0xffffffff ), /* -1 */ -/* 1064 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1066 */ NdrFcShort( 0xffffffe8 ), /* Offset= -24 (1042) */ -/* 1068 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 1070 */ - 0x1b, /* FC_CARRAY */ - 0x3, /* 3 */ -/* 1072 */ NdrFcShort( 0x4 ), /* 4 */ -/* 1074 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ - 0x0, /* */ -/* 1076 */ NdrFcShort( 0xc ), /* 12 */ -/* 1078 */ 0x8, /* FC_LONG */ - 0x5b, /* FC_END */ -/* 1080 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x3, /* 3 */ -/* 1082 */ NdrFcShort( 0x10 ), /* 16 */ -/* 1084 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1086 */ NdrFcShort( 0x8 ), /* Offset= 8 (1094) */ -/* 1088 */ 0x36, /* FC_POINTER */ - 0x36, /* FC_POINTER */ -/* 1090 */ 0x8, /* FC_LONG */ - 0x8, /* FC_LONG */ -/* 1092 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 1094 */ - 0x12, 0x0, /* FC_UP */ -/* 1096 */ NdrFcShort( 0xffffffd4 ), /* Offset= -44 (1052) */ -/* 1098 */ - 0x12, 0x0, /* FC_UP */ -/* 1100 */ NdrFcShort( 0xffffffe2 ), /* Offset= -30 (1070) */ -/* 1102 */ - 0x11, 0x4, /* FC_RP [alloced_on_stack] */ -/* 1104 */ NdrFcShort( 0x6 ), /* Offset= 6 (1110) */ -/* 1106 */ - 0x13, 0x0, /* FC_OP */ -/* 1108 */ NdrFcShort( 0xffffffaa ), /* Offset= -86 (1022) */ -/* 1110 */ 0xb4, /* FC_USER_MARSHAL */ - 0x83, /* 131 */ -/* 1112 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1114 */ NdrFcShort( 0x10 ), /* 16 */ -/* 1116 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1118 */ NdrFcShort( 0xfffffff4 ), /* Offset= -12 (1106) */ -/* 1120 */ - 0x11, 0x4, /* FC_RP [alloced_on_stack] */ -/* 1122 */ NdrFcShort( 0x10 ), /* Offset= 16 (1138) */ -/* 1124 */ - 0x13, 0x0, /* FC_OP */ -/* 1126 */ NdrFcShort( 0xfffffd22 ), /* Offset= -734 (392) */ -/* 1128 */ 0xb4, /* FC_USER_MARSHAL */ - 0x83, /* 131 */ -/* 1130 */ NdrFcShort( 0x1 ), /* 1 */ -/* 1132 */ NdrFcShort( 0x4 ), /* 4 */ -/* 1134 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1136 */ NdrFcShort( 0xfffffff4 ), /* Offset= -12 (1124) */ -/* 1138 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x3, /* 3 */ -/* 1140 */ NdrFcShort( 0x20 ), /* 32 */ -/* 1142 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1144 */ NdrFcShort( 0x0 ), /* Offset= 0 (1144) */ -/* 1146 */ 0x6, /* FC_SHORT */ - 0x6, /* FC_SHORT */ -/* 1148 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1150 */ NdrFcShort( 0xffffffea ), /* Offset= -22 (1128) */ -/* 1152 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1154 */ NdrFcShort( 0xffffffe6 ), /* Offset= -26 (1128) */ -/* 1156 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1158 */ NdrFcShort( 0xffffffe2 ), /* Offset= -30 (1128) */ -/* 1160 */ 0x38, /* FC_ALIGNM4 */ - 0x8, /* FC_LONG */ -/* 1162 */ 0x8, /* FC_LONG */ - 0x8, /* FC_LONG */ -/* 1164 */ 0x8, /* FC_LONG */ - 0x5b, /* FC_END */ -/* 1166 */ - 0x11, 0x0, /* FC_RP */ -/* 1168 */ NdrFcShort( 0x2 ), /* Offset= 2 (1170) */ -/* 1170 */ - 0x1b, /* FC_CARRAY */ - 0x3, /* 3 */ -/* 1172 */ NdrFcShort( 0x4 ), /* 4 */ -/* 1174 */ 0x29, /* Corr desc: parameter, FC_ULONG */ - 0x0, /* */ -#ifndef _ALPHA_ -/* 1176 */ NdrFcShort( 0x24 ), /* x86, MIPS, PPC Stack size/offset = 36 */ -#else - NdrFcShort( 0x48 ), /* Alpha Stack size/offset = 72 */ -#endif -/* 1178 */ 0x8, /* FC_LONG */ - 0x5b, /* FC_END */ -/* 1180 */ - 0x11, 0x0, /* FC_RP */ -/* 1182 */ NdrFcShort( 0x2 ), /* Offset= 2 (1184) */ -/* 1184 */ - 0x21, /* FC_BOGUS_ARRAY */ - 0x3, /* 3 */ -/* 1186 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1188 */ 0x29, /* Corr desc: parameter, FC_ULONG */ - 0x0, /* */ -#ifndef _ALPHA_ -/* 1190 */ NdrFcShort( 0x24 ), /* x86, MIPS, PPC Stack size/offset = 36 */ -#else - NdrFcShort( 0x48 ), /* Alpha Stack size/offset = 72 */ -#endif -/* 1192 */ NdrFcLong( 0xffffffff ), /* -1 */ -/* 1196 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1198 */ NdrFcShort( 0xffffffa8 ), /* Offset= -88 (1110) */ -/* 1200 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 1202 */ - 0x11, 0x0, /* FC_RP */ -/* 1204 */ NdrFcShort( 0x2 ), /* Offset= 2 (1206) */ -/* 1206 */ - 0x21, /* FC_BOGUS_ARRAY */ - 0x3, /* 3 */ -/* 1208 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1210 */ 0x29, /* Corr desc: parameter, FC_ULONG */ - 0x0, /* */ -#ifndef _ALPHA_ -/* 1212 */ NdrFcShort( 0x4 ), /* x86, MIPS, PPC Stack size/offset = 4 */ -#else - NdrFcShort( 0x8 ), /* Alpha Stack size/offset = 8 */ -#endif -/* 1214 */ 0x29, /* Corr desc: parameter, FC_ULONG */ - 0x54, /* FC_DEREFERENCE */ -#ifndef _ALPHA_ -/* 1216 */ NdrFcShort( 0xc ), /* x86, MIPS, PPC Stack size/offset = 12 */ -#else - NdrFcShort( 0x18 ), /* Alpha Stack size/offset = 24 */ -#endif -/* 1218 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1220 */ NdrFcShort( 0xffffff92 ), /* Offset= -110 (1110) */ -/* 1222 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 1224 */ - 0x11, 0x14, /* FC_RP [alloced_on_stack] */ -/* 1226 */ NdrFcShort( 0x2 ), /* Offset= 2 (1228) */ -/* 1228 */ - 0x2f, /* FC_IP */ - 0x5a, /* FC_CONSTANT_IID */ -/* 1230 */ NdrFcLong( 0x20404 ), /* 132100 */ -/* 1234 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1236 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1238 */ 0xc0, /* 192 */ - 0x0, /* 0 */ -/* 1240 */ 0x0, /* 0 */ - 0x0, /* 0 */ -/* 1242 */ 0x0, /* 0 */ - 0x0, /* 0 */ -/* 1244 */ 0x0, /* 0 */ - 0x46, /* 70 */ -/* 1246 */ - 0x11, 0x8, /* FC_RP [simple_pointer] */ -/* 1248 */ - 0x25, /* FC_C_WSTRING */ - 0x5c, /* FC_PAD */ -/* 1250 */ - 0x11, 0xc, /* FC_RP [alloced_on_stack] [simple_pointer] */ -/* 1252 */ 0xe, /* FC_ENUM32 */ - 0x5c, /* FC_PAD */ -/* 1254 */ - 0x11, 0x14, /* FC_RP [alloced_on_stack] */ -/* 1256 */ NdrFcShort( 0x2 ), /* Offset= 2 (1258) */ -/* 1258 */ - 0x13, 0x0, /* FC_OP */ -/* 1260 */ NdrFcShort( 0xaa ), /* Offset= 170 (1430) */ -/* 1262 */ - 0x2b, /* FC_NON_ENCAPSULATED_UNION */ - 0x7, /* FC_USHORT */ -/* 1264 */ 0x7, /* Corr desc: FC_USHORT */ - 0x0, /* */ -/* 1266 */ NdrFcShort( 0x4 ), /* 4 */ -/* 1268 */ NdrFcShort( 0x2 ), /* Offset= 2 (1270) */ -/* 1270 */ NdrFcShort( 0x4 ), /* 4 */ -/* 1272 */ NdrFcShort( 0x4 ), /* 4 */ -/* 1274 */ NdrFcLong( 0x1a ), /* 26 */ -/* 1278 */ NdrFcShort( 0x16 ), /* Offset= 22 (1300) */ -/* 1280 */ NdrFcLong( 0x1b ), /* 27 */ -/* 1284 */ NdrFcShort( 0x10 ), /* Offset= 16 (1300) */ -/* 1286 */ NdrFcLong( 0x1c ), /* 28 */ -/* 1290 */ NdrFcShort( 0xe ), /* Offset= 14 (1304) */ -/* 1292 */ NdrFcLong( 0x1d ), /* 29 */ -/* 1296 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ -/* 1298 */ NdrFcShort( 0x0 ), /* Offset= 0 (1298) */ -/* 1300 */ - 0x13, 0x0, /* FC_OP */ -/* 1302 */ NdrFcShort( 0x24 ), /* Offset= 36 (1338) */ -/* 1304 */ - 0x13, 0x0, /* FC_OP */ -/* 1306 */ NdrFcShort( 0x10 ), /* Offset= 16 (1322) */ -/* 1308 */ - 0x1b, /* FC_CARRAY */ - 0x3, /* 3 */ -/* 1310 */ NdrFcShort( 0x8 ), /* 8 */ -/* 1312 */ 0x7, /* Corr desc: FC_USHORT */ - 0x0, /* */ -/* 1314 */ NdrFcShort( 0xfffc ), /* -4 */ -/* 1316 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1318 */ NdrFcShort( 0xfffffe78 ), /* Offset= -392 (926) */ -/* 1320 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 1322 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x3, /* 3 */ -/* 1324 */ NdrFcShort( 0x4 ), /* 4 */ -/* 1326 */ NdrFcShort( 0xffffffee ), /* Offset= -18 (1308) */ -/* 1328 */ NdrFcShort( 0x0 ), /* Offset= 0 (1328) */ -/* 1330 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1332 */ NdrFcShort( 0x6 ), /* Offset= 6 (1338) */ -/* 1334 */ 0x6, /* FC_SHORT */ - 0x3e, /* FC_STRUCTPAD2 */ -/* 1336 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 1338 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x3, /* 3 */ -/* 1340 */ NdrFcShort( 0x8 ), /* 8 */ -/* 1342 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1344 */ NdrFcShort( 0x0 ), /* Offset= 0 (1344) */ -/* 1346 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1348 */ NdrFcShort( 0xffffffaa ), /* Offset= -86 (1262) */ -/* 1350 */ 0x6, /* FC_SHORT */ - 0x3e, /* FC_STRUCTPAD2 */ -/* 1352 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 1354 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x3, /* 3 */ -/* 1356 */ NdrFcShort( 0x18 ), /* 24 */ -/* 1358 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1360 */ NdrFcShort( 0x0 ), /* Offset= 0 (1360) */ -/* 1362 */ 0x8, /* FC_LONG */ - 0x4c, /* FC_EMBEDDED_COMPLEX */ -/* 1364 */ 0x4, /* 4 */ - NdrFcShort( 0xffffff01 ), /* Offset= -255 (1110) */ - 0x5b, /* FC_END */ -/* 1368 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x3, /* 3 */ -/* 1370 */ NdrFcShort( 0x8 ), /* 8 */ -/* 1372 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1374 */ NdrFcShort( 0x6 ), /* Offset= 6 (1380) */ -/* 1376 */ 0x36, /* FC_POINTER */ - 0x6, /* FC_SHORT */ -/* 1378 */ 0x3e, /* FC_STRUCTPAD2 */ - 0x5b, /* FC_END */ -/* 1380 */ - 0x13, 0x0, /* FC_OP */ -/* 1382 */ NdrFcShort( 0xffffffe4 ), /* Offset= -28 (1354) */ -/* 1384 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x3, /* 3 */ -/* 1386 */ NdrFcShort( 0x10 ), /* 16 */ -/* 1388 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1390 */ NdrFcShort( 0x0 ), /* Offset= 0 (1390) */ -/* 1392 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1394 */ NdrFcShort( 0xffffffc8 ), /* Offset= -56 (1338) */ -/* 1396 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1398 */ NdrFcShort( 0xffffffe2 ), /* Offset= -30 (1368) */ -/* 1400 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 1402 */ - 0x1b, /* FC_CARRAY */ - 0x3, /* 3 */ -/* 1404 */ NdrFcShort( 0x4 ), /* 4 */ -/* 1406 */ 0x16, /* Corr desc: field pointer, FC_SHORT */ - 0x0, /* */ -/* 1408 */ NdrFcShort( 0x1e ), /* 30 */ -/* 1410 */ 0x8, /* FC_LONG */ - 0x5b, /* FC_END */ -/* 1412 */ - 0x21, /* FC_BOGUS_ARRAY */ - 0x3, /* 3 */ -/* 1414 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1416 */ 0x16, /* Corr desc: field pointer, FC_SHORT */ - 0x0, /* */ -/* 1418 */ NdrFcShort( 0x18 ), /* 24 */ -/* 1420 */ NdrFcLong( 0xffffffff ), /* -1 */ -/* 1424 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1426 */ NdrFcShort( 0xffffffd6 ), /* Offset= -42 (1384) */ -/* 1428 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 1430 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x3, /* 3 */ -/* 1432 */ NdrFcShort( 0x34 ), /* 52 */ -/* 1434 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1436 */ NdrFcShort( 0x14 ), /* Offset= 20 (1456) */ -/* 1438 */ 0x8, /* FC_LONG */ - 0x36, /* FC_POINTER */ -/* 1440 */ 0x36, /* FC_POINTER */ - 0xe, /* FC_ENUM32 */ -/* 1442 */ 0xe, /* FC_ENUM32 */ - 0xe, /* FC_ENUM32 */ -/* 1444 */ 0x6, /* FC_SHORT */ - 0x6, /* FC_SHORT */ -/* 1446 */ 0x6, /* FC_SHORT */ - 0x6, /* FC_SHORT */ -/* 1448 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1450 */ NdrFcShort( 0xffffffbe ), /* Offset= -66 (1384) */ -/* 1452 */ 0x6, /* FC_SHORT */ - 0x3e, /* FC_STRUCTPAD2 */ -/* 1454 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 1456 */ - 0x13, 0x0, /* FC_OP */ -/* 1458 */ NdrFcShort( 0xffffffc8 ), /* Offset= -56 (1402) */ -/* 1460 */ - 0x13, 0x0, /* FC_OP */ -/* 1462 */ NdrFcShort( 0xffffffce ), /* Offset= -50 (1412) */ -/* 1464 */ - 0x11, 0x14, /* FC_RP [alloced_on_stack] */ -/* 1466 */ NdrFcShort( 0x2 ), /* Offset= 2 (1468) */ -/* 1468 */ - 0x13, 0x0, /* FC_OP */ -/* 1470 */ NdrFcShort( 0x2c ), /* Offset= 44 (1514) */ -/* 1472 */ - 0x2b, /* FC_NON_ENCAPSULATED_UNION */ - 0x8, /* FC_LONG */ -/* 1474 */ 0x8, /* Corr desc: FC_LONG */ - 0x0, /* */ -/* 1476 */ NdrFcShort( 0x18 ), /* 24 */ -/* 1478 */ NdrFcShort( 0x2 ), /* Offset= 2 (1480) */ -/* 1480 */ NdrFcShort( 0x4 ), /* 4 */ -/* 1482 */ NdrFcShort( 0x4 ), /* 4 */ -/* 1484 */ NdrFcLong( 0x0 ), /* 0 */ -/* 1488 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ -/* 1490 */ NdrFcLong( 0x3 ), /* 3 */ -/* 1494 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ -/* 1496 */ NdrFcLong( 0x1 ), /* 1 */ -/* 1500 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ -/* 1502 */ NdrFcLong( 0x2 ), /* 2 */ -/* 1506 */ NdrFcShort( 0x4 ), /* Offset= 4 (1510) */ -/* 1508 */ NdrFcShort( 0xffffffff ), /* Offset= -1 (1507) */ -/* 1510 */ - 0x13, 0x0, /* FC_OP */ -/* 1512 */ NdrFcShort( 0xfffffe6e ), /* Offset= -402 (1110) */ -/* 1514 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x3, /* 3 */ -/* 1516 */ NdrFcShort( 0x24 ), /* 36 */ -/* 1518 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1520 */ NdrFcShort( 0x10 ), /* Offset= 16 (1536) */ -/* 1522 */ 0x8, /* FC_LONG */ - 0x36, /* FC_POINTER */ -/* 1524 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1526 */ NdrFcShort( 0xffffffca ), /* Offset= -54 (1472) */ -/* 1528 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1530 */ NdrFcShort( 0xffffff6e ), /* Offset= -146 (1384) */ -/* 1532 */ 0x6, /* FC_SHORT */ - 0x38, /* FC_ALIGNM4 */ -/* 1534 */ 0xe, /* FC_ENUM32 */ - 0x5b, /* FC_END */ -/* 1536 */ - 0x13, 0x8, /* FC_OP [simple_pointer] */ -/* 1538 */ - 0x25, /* FC_C_WSTRING */ - 0x5c, /* FC_PAD */ -/* 1540 */ - 0x11, 0x14, /* FC_RP [alloced_on_stack] */ -/* 1542 */ NdrFcShort( 0x2 ), /* Offset= 2 (1544) */ -/* 1544 */ - 0x2f, /* FC_IP */ - 0x5a, /* FC_CONSTANT_IID */ -/* 1546 */ NdrFcLong( 0x20403 ), /* 132099 */ -/* 1550 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1552 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1554 */ 0xc0, /* 192 */ - 0x0, /* 0 */ -/* 1556 */ 0x0, /* 0 */ - 0x0, /* 0 */ -/* 1558 */ 0x0, /* 0 */ - 0x0, /* 0 */ -/* 1560 */ 0x0, /* 0 */ - 0x46, /* 70 */ -/* 1562 */ - 0x11, 0x4, /* FC_RP [alloced_on_stack] */ -/* 1564 */ NdrFcShort( 0x4 ), /* Offset= 4 (1568) */ -/* 1566 */ 0x8, /* FC_LONG */ - 0x5c, /* FC_PAD */ -/* 1568 */ 0xb4, /* FC_USER_MARSHAL */ - 0x3, /* 3 */ -/* 1570 */ NdrFcShort( 0x2 ), /* 2 */ -/* 1572 */ NdrFcShort( 0xc ), /* 12 */ -/* 1574 */ NdrFcShort( 0x4 ), /* 4 */ -/* 1576 */ NdrFcShort( 0xfffffff6 ), /* Offset= -10 (1566) */ -/* 1578 */ - 0x11, 0x14, /* FC_RP [alloced_on_stack] */ -/* 1580 */ NdrFcShort( 0x2 ), /* Offset= 2 (1582) */ -/* 1582 */ - 0x13, 0x0, /* FC_OP */ -/* 1584 */ NdrFcShort( 0xe ), /* Offset= 14 (1598) */ -/* 1586 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x3, /* 3 */ -/* 1588 */ NdrFcShort( 0x8 ), /* 8 */ -/* 1590 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1592 */ NdrFcShort( 0x0 ), /* Offset= 0 (1592) */ -/* 1594 */ 0x8, /* FC_LONG */ - 0x6, /* FC_SHORT */ -/* 1596 */ 0x3e, /* FC_STRUCTPAD2 */ - 0x5b, /* FC_END */ -/* 1598 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x3, /* 3 */ -/* 1600 */ NdrFcShort( 0x4c ), /* 76 */ -/* 1602 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1604 */ NdrFcShort( 0x1e ), /* Offset= 30 (1634) */ -/* 1606 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1608 */ NdrFcShort( 0xfffff9de ), /* Offset= -1570 (38) */ -/* 1610 */ 0x8, /* FC_LONG */ - 0x8, /* FC_LONG */ -/* 1612 */ 0x8, /* FC_LONG */ - 0x8, /* FC_LONG */ -/* 1614 */ 0x36, /* FC_POINTER */ - 0x8, /* FC_LONG */ -/* 1616 */ 0xe, /* FC_ENUM32 */ - 0x6, /* FC_SHORT */ -/* 1618 */ 0x6, /* FC_SHORT */ - 0x6, /* FC_SHORT */ -/* 1620 */ 0x6, /* FC_SHORT */ - 0x6, /* FC_SHORT */ -/* 1622 */ 0x6, /* FC_SHORT */ - 0x6, /* FC_SHORT */ -/* 1624 */ 0x6, /* FC_SHORT */ - 0x4c, /* FC_EMBEDDED_COMPLEX */ -/* 1626 */ 0x0, /* 0 */ - NdrFcShort( 0xfffffedf ), /* Offset= -289 (1338) */ - 0x4c, /* FC_EMBEDDED_COMPLEX */ -/* 1630 */ 0x0, /* 0 */ - NdrFcShort( 0xffffffd3 ), /* Offset= -45 (1586) */ - 0x5b, /* FC_END */ -/* 1634 */ - 0x13, 0x8, /* FC_OP [simple_pointer] */ -/* 1636 */ - 0x25, /* FC_C_WSTRING */ - 0x5c, /* FC_PAD */ -/* 1638 */ - 0x11, 0x4, /* FC_RP [alloced_on_stack] */ -/* 1640 */ NdrFcShort( 0x4 ), /* Offset= 4 (1644) */ -/* 1642 */ 0x8, /* FC_LONG */ - 0x5c, /* FC_PAD */ -/* 1644 */ 0xb4, /* FC_USER_MARSHAL */ - 0x3, /* 3 */ -/* 1646 */ NdrFcShort( 0x2 ), /* 2 */ -/* 1648 */ NdrFcShort( 0xc ), /* 12 */ -/* 1650 */ NdrFcShort( 0x4 ), /* 4 */ -/* 1652 */ NdrFcShort( 0xfffffff6 ), /* Offset= -10 (1642) */ -/* 1654 */ - 0x11, 0x4, /* FC_RP [alloced_on_stack] */ -/* 1656 */ NdrFcShort( 0x4 ), /* Offset= 4 (1660) */ -/* 1658 */ 0x8, /* FC_LONG */ - 0x5c, /* FC_PAD */ -/* 1660 */ 0xb4, /* FC_USER_MARSHAL */ - 0x3, /* 3 */ -/* 1662 */ NdrFcShort( 0x2 ), /* 2 */ -/* 1664 */ NdrFcShort( 0xc ), /* 12 */ -/* 1666 */ NdrFcShort( 0x4 ), /* 4 */ -/* 1668 */ NdrFcShort( 0xfffffff6 ), /* Offset= -10 (1658) */ -/* 1670 */ - 0x11, 0x4, /* FC_RP [alloced_on_stack] */ -/* 1672 */ NdrFcShort( 0x4 ), /* Offset= 4 (1676) */ -/* 1674 */ 0x8, /* FC_LONG */ - 0x5c, /* FC_PAD */ -/* 1676 */ 0xb4, /* FC_USER_MARSHAL */ - 0x3, /* 3 */ -/* 1678 */ NdrFcShort( 0x2 ), /* 2 */ -/* 1680 */ NdrFcShort( 0xc ), /* 12 */ -/* 1682 */ NdrFcShort( 0x4 ), /* 4 */ -/* 1684 */ NdrFcShort( 0xfffffff6 ), /* Offset= -10 (1674) */ -/* 1686 */ - 0x11, 0x0, /* FC_RP */ -/* 1688 */ NdrFcShort( 0x2 ), /* Offset= 2 (1690) */ -/* 1690 */ - 0x21, /* FC_BOGUS_ARRAY */ - 0x3, /* 3 */ -/* 1692 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1694 */ 0x29, /* Corr desc: parameter, FC_ULONG */ - 0x0, /* */ -#ifndef _ALPHA_ -/* 1696 */ NdrFcShort( 0xc ), /* x86, MIPS, PPC Stack size/offset = 12 */ -#else - NdrFcShort( 0x18 ), /* Alpha Stack size/offset = 24 */ -#endif -/* 1698 */ 0x29, /* Corr desc: parameter, FC_ULONG */ - 0x54, /* FC_DEREFERENCE */ -#ifndef _ALPHA_ -/* 1700 */ NdrFcShort( 0x10 ), /* x86, MIPS, PPC Stack size/offset = 16 */ -#else - NdrFcShort( 0x20 ), /* Alpha Stack size/offset = 32 */ -#endif -/* 1702 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1704 */ NdrFcShort( 0xfffffdc0 ), /* Offset= -576 (1128) */ -/* 1706 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 1708 */ - 0x11, 0x4, /* FC_RP [alloced_on_stack] */ -/* 1710 */ NdrFcShort( 0xfffffdba ), /* Offset= -582 (1128) */ -/* 1712 */ - 0x11, 0xc, /* FC_RP [alloced_on_stack] [simple_pointer] */ -/* 1714 */ 0x6, /* FC_SHORT */ - 0x5c, /* FC_PAD */ -/* 1716 */ - 0x11, 0x14, /* FC_RP [alloced_on_stack] */ -/* 1718 */ NdrFcShort( 0x2 ), /* Offset= 2 (1720) */ -/* 1720 */ - 0x2f, /* FC_IP */ - 0x5c, /* FC_PAD */ -/* 1722 */ 0x28, /* Corr desc: parameter, FC_LONG */ - 0x0, /* */ -#ifndef _ALPHA_ -/* 1724 */ NdrFcShort( 0x4 ), /* x86, MIPS, PPC Stack size/offset = 4 */ -#else - NdrFcShort( 0x8 ), /* Alpha Stack size/offset = 8 */ -#endif -/* 1726 */ - 0x11, 0x14, /* FC_RP [alloced_on_stack] */ -/* 1728 */ NdrFcShort( 0x2 ), /* Offset= 2 (1730) */ -/* 1730 */ - 0x2f, /* FC_IP */ - 0x5a, /* FC_CONSTANT_IID */ -/* 1732 */ NdrFcLong( 0x20402 ), /* 132098 */ -/* 1736 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1738 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1740 */ 0xc0, /* 192 */ - 0x0, /* 0 */ -/* 1742 */ 0x0, /* 0 */ - 0x0, /* 0 */ -/* 1744 */ 0x0, /* 0 */ - 0x0, /* 0 */ -/* 1746 */ 0x0, /* 0 */ - 0x46, /* 70 */ -/* 1748 */ - 0x11, 0x4, /* FC_RP [alloced_on_stack] */ -/* 1750 */ NdrFcShort( 0x26 ), /* Offset= 38 (1788) */ -/* 1752 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x3, /* 3 */ -/* 1754 */ NdrFcShort( 0x20 ), /* 32 */ -/* 1756 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1758 */ NdrFcShort( 0x0 ), /* Offset= 0 (1758) */ -/* 1760 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1762 */ NdrFcShort( 0xfffff944 ), /* Offset= -1724 (38) */ -/* 1764 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1766 */ NdrFcShort( 0xfffffd70 ), /* Offset= -656 (1110) */ -/* 1768 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 1770 */ - 0x21, /* FC_BOGUS_ARRAY */ - 0x3, /* 3 */ -/* 1772 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1774 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ - 0x0, /* */ -/* 1776 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1778 */ NdrFcLong( 0xffffffff ), /* -1 */ -/* 1782 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1784 */ NdrFcShort( 0xffffffe0 ), /* Offset= -32 (1752) */ -/* 1786 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 1788 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x3, /* 3 */ -/* 1790 */ NdrFcShort( 0x8 ), /* 8 */ -/* 1792 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1794 */ NdrFcShort( 0x6 ), /* Offset= 6 (1800) */ -/* 1796 */ 0x8, /* FC_LONG */ - 0x36, /* FC_POINTER */ -/* 1798 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 1800 */ - 0x13, 0x0, /* FC_OP */ -/* 1802 */ NdrFcShort( 0xffffffe0 ), /* Offset= -32 (1770) */ -/* 1804 */ - 0x11, 0x14, /* FC_RP [alloced_on_stack] */ -/* 1806 */ NdrFcShort( 0x2 ), /* Offset= 2 (1808) */ -/* 1808 */ - 0x13, 0x0, /* FC_OP */ -/* 1810 */ NdrFcShort( 0x2 ), /* Offset= 2 (1812) */ -/* 1812 */ - 0x1a, /* FC_BOGUS_STRUCT */ - 0x3, /* 3 */ -/* 1814 */ NdrFcShort( 0x20 ), /* 32 */ -/* 1816 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1818 */ NdrFcShort( 0x0 ), /* Offset= 0 (1818) */ -/* 1820 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1822 */ NdrFcShort( 0xfffff908 ), /* Offset= -1784 (38) */ -/* 1824 */ 0x8, /* FC_LONG */ - 0xe, /* FC_ENUM32 */ -/* 1826 */ 0x6, /* FC_SHORT */ - 0x6, /* FC_SHORT */ -/* 1828 */ 0x6, /* FC_SHORT */ - 0x3e, /* FC_STRUCTPAD2 */ -/* 1830 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 1832 */ - 0x11, 0x4, /* FC_RP [alloced_on_stack] */ -/* 1834 */ NdrFcShort( 0x4 ), /* Offset= 4 (1838) */ -/* 1836 */ 0x8, /* FC_LONG */ - 0x5c, /* FC_PAD */ -/* 1838 */ 0xb4, /* FC_USER_MARSHAL */ - 0x3, /* 3 */ -/* 1840 */ NdrFcShort( 0x2 ), /* 2 */ -/* 1842 */ NdrFcShort( 0xc ), /* 12 */ -/* 1844 */ NdrFcShort( 0x4 ), /* 4 */ -/* 1846 */ NdrFcShort( 0xfffffff6 ), /* Offset= -10 (1836) */ -/* 1848 */ - 0x11, 0x0, /* FC_RP */ -/* 1850 */ NdrFcShort( 0x2 ), /* Offset= 2 (1852) */ -/* 1852 */ - 0x21, /* FC_BOGUS_ARRAY */ - 0x3, /* 3 */ -/* 1854 */ NdrFcShort( 0x0 ), /* 0 */ -/* 1856 */ 0x27, /* Corr desc: parameter, FC_USHORT */ - 0x54, /* FC_DEREFERENCE */ -#ifndef _ALPHA_ -/* 1858 */ NdrFcShort( 0x14 ), /* x86, MIPS, PPC Stack size/offset = 20 */ -#else - NdrFcShort( 0x28 ), /* Alpha Stack size/offset = 40 */ -#endif -/* 1860 */ 0x27, /* Corr desc: parameter, FC_USHORT */ - 0x54, /* FC_DEREFERENCE */ -#ifndef _ALPHA_ -/* 1862 */ NdrFcShort( 0x14 ), /* x86, MIPS, PPC Stack size/offset = 20 */ -#else - NdrFcShort( 0x28 ), /* Alpha Stack size/offset = 40 */ -#endif -/* 1864 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ - 0x0, /* 0 */ -/* 1866 */ NdrFcShort( 0xfffff8c0 ), /* Offset= -1856 (10) */ -/* 1868 */ 0x5c, /* FC_PAD */ - 0x5b, /* FC_END */ -/* 1870 */ - 0x11, 0x0, /* FC_RP */ -/* 1872 */ NdrFcShort( 0x2 ), /* Offset= 2 (1874) */ -/* 1874 */ - 0x1c, /* FC_CVARRAY */ - 0x3, /* 3 */ -/* 1876 */ NdrFcShort( 0x4 ), /* 4 */ -/* 1878 */ 0x27, /* Corr desc: parameter, FC_USHORT */ - 0x54, /* FC_DEREFERENCE */ -#ifndef _ALPHA_ -/* 1880 */ NdrFcShort( 0x14 ), /* x86, MIPS, PPC Stack size/offset = 20 */ -#else - NdrFcShort( 0x28 ), /* Alpha Stack size/offset = 40 */ -#endif -/* 1882 */ 0x27, /* Corr desc: parameter, FC_USHORT */ - 0x54, /* FC_DEREFERENCE */ -#ifndef _ALPHA_ -/* 1884 */ NdrFcShort( 0x14 ), /* x86, MIPS, PPC Stack size/offset = 20 */ -#else - NdrFcShort( 0x28 ), /* Alpha Stack size/offset = 40 */ -#endif -/* 1886 */ 0x8, /* FC_LONG */ - 0x5b, /* FC_END */ -/* 1888 */ - 0x11, 0x8, /* FC_RP [simple_pointer] */ -/* 1890 */ 0x6, /* FC_SHORT */ - 0x5c, /* FC_PAD */ -/* 1892 */ - 0x11, 0x4, /* FC_RP [alloced_on_stack] */ -/* 1894 */ NdrFcShort( 0xfffff8c0 ), /* Offset= -1856 (38) */ -/* 1896 */ - 0x11, 0x14, /* FC_RP [alloced_on_stack] */ -/* 1898 */ NdrFcShort( 0x2 ), /* Offset= 2 (1900) */ -/* 1900 */ - 0x2f, /* FC_IP */ - 0x5c, /* FC_PAD */ -/* 1902 */ 0x28, /* Corr desc: parameter, FC_LONG */ - 0x0, /* */ -#ifndef _ALPHA_ -/* 1904 */ NdrFcShort( 0x8 ), /* x86, MIPS, PPC Stack size/offset = 8 */ -#else - NdrFcShort( 0x10 ), /* Alpha Stack size/offset = 16 */ -#endif - - 0x0 - } - }; - -const CInterfaceProxyVtbl * _oaidl_ProxyVtblList[] = -{ - ( CInterfaceProxyVtbl *) &_IDispatchProxyVtbl, - ( CInterfaceProxyVtbl *) &_ITypeInfoProxyVtbl, - ( CInterfaceProxyVtbl *) &_ITypeLibProxyVtbl, - ( CInterfaceProxyVtbl *) &_ITypeCompProxyVtbl, - ( CInterfaceProxyVtbl *) &_IEnumVARIANTProxyVtbl, - ( CInterfaceProxyVtbl *) &_ITypeLib2ProxyVtbl, - ( CInterfaceProxyVtbl *) &_ITypeInfo2ProxyVtbl, - ( CInterfaceProxyVtbl *) &_IErrorInfoProxyVtbl, - ( CInterfaceProxyVtbl *) &_ITypeFactoryProxyVtbl, - ( CInterfaceProxyVtbl *) &_ICreateErrorInfoProxyVtbl, - ( CInterfaceProxyVtbl *) &_ISupportErrorInfoProxyVtbl, - 0 -}; - -const CInterfaceStubVtbl * _oaidl_StubVtblList[] = -{ - ( CInterfaceStubVtbl *) &_IDispatchStubVtbl, - ( CInterfaceStubVtbl *) &_ITypeInfoStubVtbl, - ( CInterfaceStubVtbl *) &_ITypeLibStubVtbl, - ( CInterfaceStubVtbl *) &_ITypeCompStubVtbl, - ( CInterfaceStubVtbl *) &_IEnumVARIANTStubVtbl, - ( CInterfaceStubVtbl *) &_ITypeLib2StubVtbl, - ( CInterfaceStubVtbl *) &_ITypeInfo2StubVtbl, - ( CInterfaceStubVtbl *) &_IErrorInfoStubVtbl, - ( CInterfaceStubVtbl *) &_ITypeFactoryStubVtbl, - ( CInterfaceStubVtbl *) &_ICreateErrorInfoStubVtbl, - ( CInterfaceStubVtbl *) &_ISupportErrorInfoStubVtbl, - 0 -}; - -PCInterfaceName const _oaidl_InterfaceNamesList[] = -{ - "IDispatch", - "ITypeInfo", - "ITypeLib", - "ITypeComp", - "IEnumVARIANT", - "ITypeLib2", - "ITypeInfo2", - "IErrorInfo", - "ITypeFactory", - "ICreateErrorInfo", - "ISupportErrorInfo", - 0 -}; - - -#define _oaidl_CHECK_IID(n) IID_GENERIC_CHECK_IID( _oaidl, pIID, n) - -int __stdcall _oaidl_IID_Lookup( const IID * pIID, int * pIndex ) -{ - IID_BS_LOOKUP_SETUP - - IID_BS_LOOKUP_INITIAL_TEST( _oaidl, 11, 8 ) - IID_BS_LOOKUP_NEXT_TEST( _oaidl, 4 ) - IID_BS_LOOKUP_NEXT_TEST( _oaidl, 2 ) - IID_BS_LOOKUP_NEXT_TEST( _oaidl, 1 ) - IID_BS_LOOKUP_RETURN_RESULT( _oaidl, 11, *pIndex ) - -} - -const ExtendedProxyFileInfo oaidl_ProxyFileInfo = -{ - (PCInterfaceProxyVtblList *) & _oaidl_ProxyVtblList, - (PCInterfaceStubVtblList *) & _oaidl_StubVtblList, - (const PCInterfaceName * ) & _oaidl_InterfaceNamesList, - 0, /* no delegation */ - & _oaidl_IID_Lookup, - 11, - 1, - 0, /* table of [async_uuid] interfaces */ - 0, /* Filler1 */ - 0, /* Filler2 */ - 0 /* Filler3 */ -}; +/* This file contains the proxy/stub code for core COM interfaces. + + It is usually generated directly by MIDL, however this file has + been tweaked since then to account for slight differences in the way + gcc and MSVC++ compile it. In particular, in some functions REFIIDs + declared on the stack have been converted to plain IID* in order to eliminate + the constness of the REFIID type, ensuring that the zero initializer is not + discarded. + + Therefore, please do not regenerate this file. +*/ + +/* File created by MIDL compiler version 5.01.0164 */ +/* at Tue Jan 07 22:24:52 2003 + */ +/* Compiler settings for oaidl.idl: + Os (OptLev=s), W1, Zp8, env=Win32, ms_ext, c_ext + error checks: allocation ref bounds_check enum stub_data +*/ +/*@@MIDL_FILE_HEADING( ) */ + + +/* verify that the <rpcproxy.h> version is high enough to compile this file*/ +#ifndef __REDQ_RPCPROXY_H_VERSION__ +#define __REQUIRED_RPCPROXY_H_VERSION__ 440 +#endif + + +#include <stdarg.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" +#include "rpcproxy.h" +#ifndef __RPCPROXY_H_VERSION__ +#error this stub requires an updated version of <rpcproxy.h> +#endif /* __RPCPROXY_H_VERSION__ */ + + +#include "oaidl.h" + +#define TYPE_FORMAT_STRING_SIZE 1907 +#define PROC_FORMAT_STRING_SIZE 495 + +typedef struct _MIDL_TYPE_FORMAT_STRING + { + short Pad; + unsigned char Format[ TYPE_FORMAT_STRING_SIZE ]; + } MIDL_TYPE_FORMAT_STRING; + +typedef struct _MIDL_PROC_FORMAT_STRING + { + short Pad; + unsigned char Format[ PROC_FORMAT_STRING_SIZE ]; + } MIDL_PROC_FORMAT_STRING; + + +static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString; +static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString; + + +/* Standard interface: __MIDL_itf_oaidl_0000, ver. 0.0, + GUID={0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} */ + + +/* Standard interface: IOleAutomationTypes, ver. 1.0, + GUID={0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}} */ + + +/* Object interface: IUnknown, ver. 0.0, + GUID={0x00000000,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ + + +/* Object interface: IDispatch, ver. 0.0, + GUID={0x00020400,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ + + +static const MIDL_STUB_DESC Object_StubDesc; + + +HRESULT STDMETHODCALLTYPE IDispatch_GetTypeInfoCount_Proxy( + IDispatch __RPC_FAR * This, + /* [out] */ UINT __RPC_FAR *pctinfo) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 3); + + + + if(!pctinfo) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[0] ); + + *pctinfo = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], + ( void __RPC_FAR * )pctinfo); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB IDispatch_GetTypeInfoCount_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + UINT _M0; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + UINT __RPC_FAR *pctinfo; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pctinfo = 0; + RpcTryFinally + { + pctinfo = &_M0; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((IDispatch*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetTypeInfoCount((IDispatch *) ((CStdStubBuffer *)This)->pvServerObject,pctinfo); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U + 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( UINT __RPC_FAR * )_StubMsg.Buffer = *pctinfo; + _StubMsg.Buffer += sizeof(UINT); + + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE IDispatch_GetTypeInfo_Proxy( + IDispatch __RPC_FAR * This, + /* [in] */ UINT iTInfo, + /* [in] */ LCID lcid, + /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(ppTInfo) + { + MIDL_memset( + ppTInfo, + 0, + sizeof( ITypeInfo __RPC_FAR *__RPC_FAR * )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 4); + + + + if(!ppTInfo) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U + 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( UINT __RPC_FAR * )_StubMsg.Buffer = iTInfo; + _StubMsg.Buffer += sizeof(UINT); + + *( LCID __RPC_FAR * )_StubMsg.Buffer = lcid; + _StubMsg.Buffer += sizeof(LCID); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[6] ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&ppTInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[6], + ( void __RPC_FAR * )ppTInfo); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB IDispatch_GetTypeInfo_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + ITypeInfo __RPC_FAR *_M1; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + UINT iTInfo; + LCID lcid; + ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + ppTInfo = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[6] ); + + iTInfo = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + lcid = *( LCID __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(LCID); + + ppTInfo = &_M1; + _M1 = 0; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((IDispatch*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetTypeInfo( + (IDispatch *) ((CStdStubBuffer *)This)->pvServerObject, + iTInfo, + lcid, + ppTInfo); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 0U + 4U; + NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)ppTInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)ppTInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)ppTInfo, + &__MIDL_TypeFormatString.Format[6] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE IDispatch_GetIDsOfNames_Proxy( + IDispatch __RPC_FAR * This, + /* [in] */ REFIID riid, + /* [size_is][in] */ LPOLESTR __RPC_FAR *rgszNames, + /* [in] */ UINT cNames, + /* [in] */ LCID lcid, + /* [size_is][out] */ DISPID __RPC_FAR *rgDispId) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 5); + + + + if(!riid) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!rgszNames) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!rgDispId) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U + 7U + 7U + 7U; + NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)riid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + _StubMsg.MaxCount = cNames; + + NdrConformantArrayBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)rgszNames, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[54] ); + + NdrProxyGetBuffer(This, &_StubMsg); + NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)riid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + _StubMsg.MaxCount = cNames; + + NdrConformantArrayMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)rgszNames, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[54] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( UINT __RPC_FAR * )_StubMsg.Buffer = cNames; + _StubMsg.Buffer += sizeof(UINT); + + *( LCID __RPC_FAR * )_StubMsg.Buffer = lcid; + _StubMsg.Buffer += sizeof(LCID); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[16] ); + + NdrConformantArrayUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&rgDispId, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[88], + (unsigned char)0 ); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + _StubMsg.MaxCount = cNames; + + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[84], + ( void __RPC_FAR * )rgDispId); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB IDispatch_GetIDsOfNames_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + UINT cNames; + LCID lcid; + DISPID __RPC_FAR *rgDispId; + LPOLESTR __RPC_FAR *rgszNames; + IID* riid = 0; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + rgszNames = 0; + rgDispId = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[16] ); + + NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&riid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], + (unsigned char)0 ); + + NdrConformantArrayUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&rgszNames, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[54], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + cNames = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + + lcid = *( LCID __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(LCID); + + rgDispId = NdrAllocate(&_StubMsg,cNames * 4); + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((IDispatch*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetIDsOfNames( + (IDispatch *) ((CStdStubBuffer *)This)->pvServerObject, + riid, + rgszNames, + cNames, + lcid, + rgDispId); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U + 7U; + _StubMsg.MaxCount = cNames; + + NdrConformantArrayBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)rgDispId, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[88] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + _StubMsg.MaxCount = cNames; + + NdrConformantArrayMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)rgDispId, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[88] ); + + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + _StubMsg.MaxCount = cNames; + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)rgszNames, + &__MIDL_TypeFormatString.Format[50] ); + + if ( rgDispId ) + _StubMsg.pfnFree( rgDispId ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE IDispatch_RemoteInvoke_Proxy( + IDispatch __RPC_FAR * This, + /* [in] */ DISPID dispIdMember, + /* [in] */ REFIID riid, + /* [in] */ LCID lcid, + /* [in] */ DWORD dwFlags, + /* [in] */ DISPPARAMS __RPC_FAR *pDispParams, + /* [out] */ VARIANT __RPC_FAR *pVarResult, + /* [out] */ EXCEPINFO __RPC_FAR *pExcepInfo, + /* [out] */ UINT __RPC_FAR *pArgErr, + /* [in] */ UINT cVarRef, + /* [size_is][in] */ UINT __RPC_FAR *rgVarRefIdx, + /* [size_is][out][in] */ VARIANTARG __RPC_FAR *rgVarRef) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pVarResult) + { + MIDL_memset( + pVarResult, + 0, + sizeof( VARIANT )); + } + if(pExcepInfo) + { + MIDL_memset( + pExcepInfo, + 0, + sizeof( EXCEPINFO )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 6); + + + + if(!riid) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pDispParams) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pVarResult) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pExcepInfo) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pArgErr) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!rgVarRefIdx) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!rgVarRef) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U + 4U + 11U + 7U + 4U + 11U + 7U + 7U; + NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)riid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrComplexStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pDispParams, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1080] ); + + _StubMsg.MaxCount = cVarRef; + + NdrConformantArrayBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)rgVarRefIdx, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1170] ); + + _StubMsg.MaxCount = cVarRef; + + NdrComplexArrayBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)rgVarRef, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1184] ); + + NdrProxyGetBuffer(This, &_StubMsg); + *( DISPID __RPC_FAR * )_StubMsg.Buffer = dispIdMember; + _StubMsg.Buffer += sizeof(DISPID); + + NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)riid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + *( LCID __RPC_FAR * )_StubMsg.Buffer = lcid; + _StubMsg.Buffer += sizeof(LCID); + + *( DWORD __RPC_FAR * )_StubMsg.Buffer = dwFlags; + _StubMsg.Buffer += sizeof(DWORD); + + NdrComplexStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pDispParams, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1080] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( UINT __RPC_FAR * )_StubMsg.Buffer = cVarRef; + _StubMsg.Buffer += sizeof(UINT); + + _StubMsg.MaxCount = cVarRef; + + NdrConformantArrayMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)rgVarRefIdx, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1170] ); + + _StubMsg.MaxCount = cVarRef; + + NdrComplexArrayMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)rgVarRef, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1184] ); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[34] ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pVarResult, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110], + (unsigned char)0 ); + + NdrComplexStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pExcepInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1138], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *pArgErr = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + NdrComplexArrayUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&rgVarRef, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1184], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1102], + ( void __RPC_FAR * )pVarResult); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1120], + ( void __RPC_FAR * )pExcepInfo); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], + ( void __RPC_FAR * )pArgErr); + _StubMsg.MaxCount = cVarRef; + + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1180], + ( void __RPC_FAR * )rgVarRef); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB IDispatch_RemoteInvoke_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + VARIANT _M6; + UINT _M7; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + EXCEPINFO _pExcepInfoM; + UINT cVarRef; + DISPID dispIdMember; + DWORD dwFlags; + LCID lcid; + UINT __RPC_FAR *pArgErr; + DISPPARAMS __RPC_FAR *pDispParams; + EXCEPINFO __RPC_FAR *pExcepInfo; + VARIANT __RPC_FAR *pVarResult; + VARIANTARG __RPC_FAR *rgVarRef; + UINT __RPC_FAR *rgVarRefIdx; + IID* riid = 0; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pDispParams = 0; + pVarResult = 0; + pExcepInfo = 0; + pArgErr = 0; + rgVarRefIdx = 0; + rgVarRef = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[34] ); + + dispIdMember = *( DISPID __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(DISPID); + + NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&riid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], + (unsigned char)0 ); + + lcid = *( LCID __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(LCID); + + dwFlags = *( DWORD __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(DWORD); + + NdrComplexStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pDispParams, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1080], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + cVarRef = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + NdrConformantArrayUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&rgVarRefIdx, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1170], + (unsigned char)0 ); + + NdrComplexArrayUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&rgVarRef, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1184], + (unsigned char)0 ); + + pVarResult = &_M6; + MIDL_memset( + pVarResult, + 0, + sizeof( VARIANT )); + pExcepInfo = &_pExcepInfoM; + pArgErr = &_M7; + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = IDispatch_Invoke_Stub( + (IDispatch *) ((CStdStubBuffer *)This)->pvServerObject, + dispIdMember, + riid, + lcid, + dwFlags, + pDispParams, + pVarResult, + pExcepInfo, + pArgErr, + cVarRef, + rgVarRefIdx, + rgVarRef); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 8U + 7U + 11U + 7U + 7U; + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pVarResult, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); + + NdrComplexStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pExcepInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1138] ); + + _StubMsg.MaxCount = cVarRef; + + NdrComplexArrayBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)rgVarRef, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1184] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pVarResult, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); + + NdrComplexStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pExcepInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1138] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( UINT __RPC_FAR * )_StubMsg.Buffer = *pArgErr; + _StubMsg.Buffer += sizeof(UINT); + + _StubMsg.MaxCount = cVarRef; + + NdrComplexArrayMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)rgVarRef, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1184] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pDispParams, + &__MIDL_TypeFormatString.Format[98] ); + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pVarResult, + &__MIDL_TypeFormatString.Format[1102] ); + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pExcepInfo, + &__MIDL_TypeFormatString.Format[1120] ); + + _StubMsg.MaxCount = cVarRef; + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)rgVarRef, + &__MIDL_TypeFormatString.Format[1180] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + +const CINTERFACE_PROXY_VTABLE(7) _IDispatchProxyVtbl = +{ + { &IID_IDispatch }, + { + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + IDispatch_GetTypeInfoCount_Proxy , + IDispatch_GetTypeInfo_Proxy , + IDispatch_GetIDsOfNames_Proxy , + IDispatch_Invoke_Proxy + } +}; + + +static const PRPC_STUB_FUNCTION IDispatch_table[] = +{ + IDispatch_GetTypeInfoCount_Stub, + IDispatch_GetTypeInfo_Stub, + IDispatch_GetIDsOfNames_Stub, + IDispatch_RemoteInvoke_Stub +}; + +const CInterfaceStubVtbl _IDispatchStubVtbl = +{ + { + &IID_IDispatch, + 0, + 7, + &IDispatch_table[-3] + }, + { CStdStubBuffer_METHODS } +}; + + +/* Object interface: IEnumVARIANT, ver. 0.0, + GUID={0x00020404,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE IEnumVARIANT_RemoteNext_Proxy( + IEnumVARIANT __RPC_FAR * This, + /* [in] */ ULONG celt, + /* [length_is][size_is][out] */ VARIANT __RPC_FAR *rgVar, + /* [out] */ ULONG __RPC_FAR *pCeltFetched) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(rgVar) + { + MIDL_memset( + rgVar, + 0, + celt * sizeof( VARIANT )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 3); + + + + if(!rgVar) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pCeltFetched) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( ULONG __RPC_FAR * )_StubMsg.Buffer = celt; + _StubMsg.Buffer += sizeof(ULONG); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[72] ); + + NdrComplexArrayUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&rgVar, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1206], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *pCeltFetched = *( ULONG __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(ULONG); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + _StubMsg.MaxCount = celt; + _StubMsg.Offset = 0; + _StubMsg.ActualCount = _StubMsg.MaxCount; + + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1202], + ( void __RPC_FAR * )rgVar); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], + ( void __RPC_FAR * )pCeltFetched); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB IEnumVARIANT_RemoteNext_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + ULONG _M11; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + ULONG celt; + ULONG __RPC_FAR *pCeltFetched; + VARIANT __RPC_FAR *rgVar; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + rgVar = 0; + pCeltFetched = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[72] ); + + celt = *( ULONG __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(ULONG); + + rgVar = NdrAllocate(&_StubMsg,celt * 16); + pCeltFetched = &_M11; + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = IEnumVARIANT_Next_Stub( + (IEnumVARIANT *) ((CStdStubBuffer *)This)->pvServerObject, + celt, + rgVar, + pCeltFetched); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 12U + 7U + 7U; + _StubMsg.MaxCount = celt; + _StubMsg.Offset = 0; + _StubMsg.ActualCount = pCeltFetched ? *pCeltFetched : 0; + + NdrComplexArrayBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)rgVar, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1206] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + _StubMsg.MaxCount = celt; + _StubMsg.Offset = 0; + _StubMsg.ActualCount = pCeltFetched ? *pCeltFetched : 0; + + NdrComplexArrayMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)rgVar, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1206] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( ULONG __RPC_FAR * )_StubMsg.Buffer = *pCeltFetched; + _StubMsg.Buffer += sizeof(ULONG); + + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + _StubMsg.MaxCount = celt; + _StubMsg.Offset = 0; + _StubMsg.ActualCount = pCeltFetched ? *pCeltFetched : 0; + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)rgVar, + &__MIDL_TypeFormatString.Format[1202] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE IEnumVARIANT_Skip_Proxy( + IEnumVARIANT __RPC_FAR * This, + /* [in] */ ULONG celt) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 4); + + + + RpcTryFinally + { + + _StubMsg.BufferLength = 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( ULONG __RPC_FAR * )_StubMsg.Buffer = celt; + _StubMsg.Buffer += sizeof(ULONG); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[84] ); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB IEnumVARIANT_Skip_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + ULONG celt; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[84] ); + + celt = *( ULONG __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(ULONG); + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((IEnumVARIANT*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> Skip((IEnumVARIANT *) ((CStdStubBuffer *)This)->pvServerObject,celt); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE IEnumVARIANT_Reset_Proxy( + IEnumVARIANT __RPC_FAR * This) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 5); + + + + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[88] ); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB IEnumVARIANT_Reset_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + RpcTryFinally + { + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((IEnumVARIANT*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> Reset((IEnumVARIANT *) ((CStdStubBuffer *)This)->pvServerObject); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE IEnumVARIANT_Clone_Proxy( + IEnumVARIANT __RPC_FAR * This, + /* [out] */ IEnumVARIANT __RPC_FAR *__RPC_FAR *ppEnum) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(ppEnum) + { + MIDL_memset( + ppEnum, + 0, + sizeof( IEnumVARIANT __RPC_FAR *__RPC_FAR * )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 6); + + + + if(!ppEnum) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[90] ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&ppEnum, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1224], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1224], + ( void __RPC_FAR * )ppEnum); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB IEnumVARIANT_Clone_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + IEnumVARIANT __RPC_FAR *_M12; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + IEnumVARIANT __RPC_FAR *__RPC_FAR *ppEnum; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + ppEnum = 0; + RpcTryFinally + { + ppEnum = &_M12; + _M12 = 0; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((IEnumVARIANT*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> Clone((IEnumVARIANT *) ((CStdStubBuffer *)This)->pvServerObject,ppEnum); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 0U + 4U; + NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)ppEnum, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1224] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)ppEnum, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1224] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)ppEnum, + &__MIDL_TypeFormatString.Format[1224] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + +const CINTERFACE_PROXY_VTABLE(7) _IEnumVARIANTProxyVtbl = +{ + { &IID_IEnumVARIANT }, + { + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + IEnumVARIANT_Next_Proxy , + IEnumVARIANT_Skip_Proxy , + IEnumVARIANT_Reset_Proxy , + IEnumVARIANT_Clone_Proxy + } +}; + + +static const PRPC_STUB_FUNCTION IEnumVARIANT_table[] = +{ + IEnumVARIANT_RemoteNext_Stub, + IEnumVARIANT_Skip_Stub, + IEnumVARIANT_Reset_Stub, + IEnumVARIANT_Clone_Stub +}; + +const CInterfaceStubVtbl _IEnumVARIANTStubVtbl = +{ + { + &IID_IEnumVARIANT, + 0, + 7, + &IEnumVARIANT_table[-3] + }, + { CStdStubBuffer_METHODS } +}; + + +/* Object interface: ITypeComp, ver. 0.0, + GUID={0x00020403,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeComp_RemoteBind_Proxy( + ITypeComp __RPC_FAR * This, + /* [in] */ LPOLESTR szName, + /* [in] */ ULONG lHashVal, + /* [in] */ WORD wFlags, + /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo, + /* [out] */ DESCKIND __RPC_FAR *pDescKind, + /* [out] */ LPFUNCDESC __RPC_FAR *ppFuncDesc, + /* [out] */ LPVARDESC __RPC_FAR *ppVarDesc, + /* [out] */ ITypeComp __RPC_FAR *__RPC_FAR *ppTypeComp, + /* [out] */ CLEANLOCALSTORAGE __RPC_FAR *pDummy) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(ppTInfo) + { + MIDL_memset( + ppTInfo, + 0, + sizeof( ITypeInfo __RPC_FAR *__RPC_FAR * )); + } + if(ppFuncDesc) + { + *ppFuncDesc = 0; + } + if(ppVarDesc) + { + *ppVarDesc = 0; + } + if(ppTypeComp) + { + MIDL_memset( + ppTypeComp, + 0, + sizeof( ITypeComp __RPC_FAR *__RPC_FAR * )); + } + if(pDummy) + { + MIDL_memset( + pDummy, + 0, + sizeof( CLEANLOCALSTORAGE )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 3); + + + + if(!szName) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!ppTInfo) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pDescKind) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!ppFuncDesc) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!ppVarDesc) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!ppTypeComp) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pDummy) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 12U + 10U + 4U; + NdrConformantStringBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)szName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); + + NdrProxyGetBuffer(This, &_StubMsg); + NdrConformantStringMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)szName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( ULONG __RPC_FAR * )_StubMsg.Buffer = lHashVal; + _StubMsg.Buffer += sizeof(ULONG); + + *( WORD __RPC_FAR * )_StubMsg.Buffer = wFlags; + _StubMsg.Buffer += sizeof(WORD); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[96] ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&ppTInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6], + (unsigned char)0 ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pDescKind, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1250], + (unsigned char)0 ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&ppFuncDesc, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1254], + (unsigned char)0 ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&ppVarDesc, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1464], + (unsigned char)0 ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&ppTypeComp, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1540], + (unsigned char)0 ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pDummy, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1568], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[6], + ( void __RPC_FAR * )ppTInfo); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1250], + ( void __RPC_FAR * )pDescKind); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1254], + ( void __RPC_FAR * )ppFuncDesc); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1464], + ( void __RPC_FAR * )ppVarDesc); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1540], + ( void __RPC_FAR * )ppTypeComp); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1562], + ( void __RPC_FAR * )pDummy); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeComp_RemoteBind_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + ITypeInfo __RPC_FAR *_M15; + DESCKIND _M16; + LPFUNCDESC _M17; + LPVARDESC _M18; + ITypeComp __RPC_FAR *_M19; + CLEANLOCALSTORAGE _M20; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + ULONG lHashVal; + DESCKIND __RPC_FAR *pDescKind; + CLEANLOCALSTORAGE __RPC_FAR *pDummy; + LPFUNCDESC __RPC_FAR *ppFuncDesc; + ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo; + ITypeComp __RPC_FAR *__RPC_FAR *ppTypeComp; + LPVARDESC __RPC_FAR *ppVarDesc; + LPOLESTR szName; + WORD wFlags; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + szName = 0; + ppTInfo = 0; + pDescKind = 0; + ppFuncDesc = 0; + ppVarDesc = 0; + ppTypeComp = 0; + pDummy = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[96] ); + + NdrConformantStringUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&szName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + lHashVal = *( ULONG __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(ULONG); + + wFlags = *( WORD __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(WORD); + + ppTInfo = &_M15; + _M15 = 0; + pDescKind = &_M16; + ppFuncDesc = &_M17; + _M17 = 0; + ppVarDesc = &_M18; + _M18 = 0; + ppTypeComp = &_M19; + _M19 = 0; + pDummy = &_M20; + MIDL_memset( + pDummy, + 0, + sizeof( CLEANLOCALSTORAGE )); + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeComp_Bind_Stub( + (ITypeComp *) ((CStdStubBuffer *)This)->pvServerObject, + szName, + lHashVal, + wFlags, + ppTInfo, + pDescKind, + ppFuncDesc, + ppVarDesc, + ppTypeComp, + pDummy); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 0U + 4U + 4U + 15U + 0U + 11U + 7U; + NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)ppTInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); + + NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)ppFuncDesc, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1254] ); + + NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)ppVarDesc, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1464] ); + + NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)ppTypeComp, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1540] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)ppTInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); + + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pDescKind, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1250] ); + + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)ppFuncDesc, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1254] ); + + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)ppVarDesc, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1464] ); + + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)ppTypeComp, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1540] ); + + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pDummy, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1568] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)ppTInfo, + &__MIDL_TypeFormatString.Format[6] ); + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)ppFuncDesc, + &__MIDL_TypeFormatString.Format[1254] ); + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)ppVarDesc, + &__MIDL_TypeFormatString.Format[1464] ); + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)ppTypeComp, + &__MIDL_TypeFormatString.Format[1540] ); + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pDummy, + &__MIDL_TypeFormatString.Format[1562] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeComp_RemoteBindType_Proxy( + ITypeComp __RPC_FAR * This, + /* [in] */ LPOLESTR szName, + /* [in] */ ULONG lHashVal, + /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(ppTInfo) + { + MIDL_memset( + ppTInfo, + 0, + sizeof( ITypeInfo __RPC_FAR *__RPC_FAR * )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 4); + + + + if(!szName) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!ppTInfo) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 12U + 10U; + NdrConformantStringBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)szName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); + + NdrProxyGetBuffer(This, &_StubMsg); + NdrConformantStringMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)szName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( ULONG __RPC_FAR * )_StubMsg.Buffer = lHashVal; + _StubMsg.Buffer += sizeof(ULONG); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[130] ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&ppTInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[6], + ( void __RPC_FAR * )ppTInfo); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeComp_RemoteBindType_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + ITypeInfo __RPC_FAR *_M23; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + ULONG lHashVal; + ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo; + LPOLESTR szName; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + szName = 0; + ppTInfo = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[130] ); + + NdrConformantStringUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&szName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + lHashVal = *( ULONG __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(ULONG); + + ppTInfo = &_M23; + _M23 = 0; + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeComp_BindType_Stub( + (ITypeComp *) ((CStdStubBuffer *)This)->pvServerObject, + szName, + lHashVal, + ppTInfo); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 0U + 4U; + NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)ppTInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)ppTInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)ppTInfo, + &__MIDL_TypeFormatString.Format[6] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + +const CINTERFACE_PROXY_VTABLE(5) _ITypeCompProxyVtbl = +{ + { &IID_ITypeComp }, + { + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + ITypeComp_Bind_Proxy , + ITypeComp_BindType_Proxy + } +}; + + +static const PRPC_STUB_FUNCTION ITypeComp_table[] = +{ + ITypeComp_RemoteBind_Stub, + ITypeComp_RemoteBindType_Stub +}; + +const CInterfaceStubVtbl _ITypeCompStubVtbl = +{ + { + &IID_ITypeComp, + 0, + 5, + &ITypeComp_table[-3] + }, + { CStdStubBuffer_METHODS } +}; + + +/* Object interface: ITypeInfo, ver. 0.0, + GUID={0x00020401,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_RemoteGetTypeAttr_Proxy( + ITypeInfo __RPC_FAR * This, + /* [out] */ LPTYPEATTR __RPC_FAR *ppTypeAttr, + /* [out] */ CLEANLOCALSTORAGE __RPC_FAR *pDummy) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(ppTypeAttr) + { + *ppTypeAttr = 0; + } + if(pDummy) + { + MIDL_memset( + pDummy, + 0, + sizeof( CLEANLOCALSTORAGE )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 3); + + + + if(!ppTypeAttr) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pDummy) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[142] ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&ppTypeAttr, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1578], + (unsigned char)0 ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pDummy, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1644], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1578], + ( void __RPC_FAR * )ppTypeAttr); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1638], + ( void __RPC_FAR * )pDummy); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo_RemoteGetTypeAttr_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + LPTYPEATTR _M24; + CLEANLOCALSTORAGE _M25; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + CLEANLOCALSTORAGE __RPC_FAR *pDummy; + LPTYPEATTR __RPC_FAR *ppTypeAttr; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + ppTypeAttr = 0; + pDummy = 0; + RpcTryFinally + { + ppTypeAttr = &_M24; + _M24 = 0; + pDummy = &_M25; + MIDL_memset( + pDummy, + 0, + sizeof( CLEANLOCALSTORAGE )); + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeInfo_GetTypeAttr_Stub( + (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, + ppTypeAttr, + pDummy); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 8U + 11U + 7U; + NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)ppTypeAttr, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1578] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)ppTypeAttr, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1578] ); + + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pDummy, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1644] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)ppTypeAttr, + &__MIDL_TypeFormatString.Format[1578] ); + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pDummy, + &__MIDL_TypeFormatString.Format[1638] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeInfo_GetTypeComp_Proxy( + ITypeInfo __RPC_FAR * This, + /* [out] */ ITypeComp __RPC_FAR *__RPC_FAR *ppTComp) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(ppTComp) + { + MIDL_memset( + ppTComp, + 0, + sizeof( ITypeComp __RPC_FAR *__RPC_FAR * )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 4); + + + + if(!ppTComp) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[152] ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&ppTComp, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1540], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1540], + ( void __RPC_FAR * )ppTComp); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo_GetTypeComp_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + ITypeComp __RPC_FAR *_M26; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + ITypeComp __RPC_FAR *__RPC_FAR *ppTComp; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + ppTComp = 0; + RpcTryFinally + { + ppTComp = &_M26; + _M26 = 0; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetTypeComp((ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject,ppTComp); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 0U + 4U; + NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)ppTComp, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1540] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)ppTComp, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1540] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)ppTComp, + &__MIDL_TypeFormatString.Format[1540] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_RemoteGetFuncDesc_Proxy( + ITypeInfo __RPC_FAR * This, + /* [in] */ UINT index, + /* [out] */ LPFUNCDESC __RPC_FAR *ppFuncDesc, + /* [out] */ CLEANLOCALSTORAGE __RPC_FAR *pDummy) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(ppFuncDesc) + { + *ppFuncDesc = 0; + } + if(pDummy) + { + MIDL_memset( + pDummy, + 0, + sizeof( CLEANLOCALSTORAGE )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 5); + + + + if(!ppFuncDesc) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pDummy) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( UINT __RPC_FAR * )_StubMsg.Buffer = index; + _StubMsg.Buffer += sizeof(UINT); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[158] ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&ppFuncDesc, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1254], + (unsigned char)0 ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pDummy, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1660], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1254], + ( void __RPC_FAR * )ppFuncDesc); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1654], + ( void __RPC_FAR * )pDummy); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo_RemoteGetFuncDesc_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + LPFUNCDESC _M27; + CLEANLOCALSTORAGE _M28; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + UINT index; + CLEANLOCALSTORAGE __RPC_FAR *pDummy; + LPFUNCDESC __RPC_FAR *ppFuncDesc; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + ppFuncDesc = 0; + pDummy = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[158] ); + + index = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + ppFuncDesc = &_M27; + _M27 = 0; + pDummy = &_M28; + MIDL_memset( + pDummy, + 0, + sizeof( CLEANLOCALSTORAGE )); + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeInfo_GetFuncDesc_Stub( + (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, + index, + ppFuncDesc, + pDummy); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 8U + 11U + 7U; + NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)ppFuncDesc, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1254] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)ppFuncDesc, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1254] ); + + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pDummy, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1660] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)ppFuncDesc, + &__MIDL_TypeFormatString.Format[1254] ); + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pDummy, + &__MIDL_TypeFormatString.Format[1654] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_RemoteGetVarDesc_Proxy( + ITypeInfo __RPC_FAR * This, + /* [in] */ UINT index, + /* [out] */ LPVARDESC __RPC_FAR *ppVarDesc, + /* [out] */ CLEANLOCALSTORAGE __RPC_FAR *pDummy) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(ppVarDesc) + { + *ppVarDesc = 0; + } + if(pDummy) + { + MIDL_memset( + pDummy, + 0, + sizeof( CLEANLOCALSTORAGE )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 6); + + + + if(!ppVarDesc) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pDummy) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( UINT __RPC_FAR * )_StubMsg.Buffer = index; + _StubMsg.Buffer += sizeof(UINT); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[170] ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&ppVarDesc, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1464], + (unsigned char)0 ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pDummy, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1676], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1464], + ( void __RPC_FAR * )ppVarDesc); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1670], + ( void __RPC_FAR * )pDummy); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo_RemoteGetVarDesc_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + LPVARDESC _M29; + CLEANLOCALSTORAGE _M30; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + UINT index; + CLEANLOCALSTORAGE __RPC_FAR *pDummy; + LPVARDESC __RPC_FAR *ppVarDesc; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + ppVarDesc = 0; + pDummy = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[170] ); + + index = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + ppVarDesc = &_M29; + _M29 = 0; + pDummy = &_M30; + MIDL_memset( + pDummy, + 0, + sizeof( CLEANLOCALSTORAGE )); + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeInfo_GetVarDesc_Stub( + (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, + index, + ppVarDesc, + pDummy); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 8U + 11U + 7U; + NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)ppVarDesc, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1464] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)ppVarDesc, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1464] ); + + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pDummy, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1676] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)ppVarDesc, + &__MIDL_TypeFormatString.Format[1464] ); + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pDummy, + &__MIDL_TypeFormatString.Format[1670] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_RemoteGetNames_Proxy( + ITypeInfo __RPC_FAR * This, + /* [in] */ MEMBERID memid, + /* [length_is][size_is][out] */ BSTR __RPC_FAR *rgBstrNames, + /* [in] */ UINT cMaxNames, + /* [out] */ UINT __RPC_FAR *pcNames) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(rgBstrNames) + { + MIDL_memset( + rgBstrNames, + 0, + cMaxNames * sizeof( BSTR )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 7); + + + + if(!rgBstrNames) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pcNames) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U + 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( MEMBERID __RPC_FAR * )_StubMsg.Buffer = memid; + _StubMsg.Buffer += sizeof(MEMBERID); + + *( UINT __RPC_FAR * )_StubMsg.Buffer = cMaxNames; + _StubMsg.Buffer += sizeof(UINT); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[182] ); + + NdrComplexArrayUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&rgBstrNames, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1690], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *pcNames = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + _StubMsg.MaxCount = cMaxNames; + _StubMsg.Offset = 0; + _StubMsg.ActualCount = _StubMsg.MaxCount; + + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1686], + ( void __RPC_FAR * )rgBstrNames); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], + ( void __RPC_FAR * )pcNames); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo_RemoteGetNames_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + UINT _M34; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + UINT cMaxNames; + MEMBERID memid; + UINT __RPC_FAR *pcNames; + BSTR __RPC_FAR *rgBstrNames; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + rgBstrNames = 0; + pcNames = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[182] ); + + memid = *( MEMBERID __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(MEMBERID); + + cMaxNames = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + rgBstrNames = NdrAllocate(&_StubMsg,cMaxNames * 4); + pcNames = &_M34; + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeInfo_GetNames_Stub( + (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, + memid, + rgBstrNames, + cMaxNames, + pcNames); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 12U + 7U + 7U; + _StubMsg.MaxCount = cMaxNames; + _StubMsg.Offset = 0; + _StubMsg.ActualCount = pcNames ? *pcNames : 0; + + NdrComplexArrayBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)rgBstrNames, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1690] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + _StubMsg.MaxCount = cMaxNames; + _StubMsg.Offset = 0; + _StubMsg.ActualCount = pcNames ? *pcNames : 0; + + NdrComplexArrayMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)rgBstrNames, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1690] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( UINT __RPC_FAR * )_StubMsg.Buffer = *pcNames; + _StubMsg.Buffer += sizeof(UINT); + + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + _StubMsg.MaxCount = cMaxNames; + _StubMsg.Offset = 0; + _StubMsg.ActualCount = pcNames ? *pcNames : 0; + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)rgBstrNames, + &__MIDL_TypeFormatString.Format[1686] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeInfo_GetRefTypeOfImplType_Proxy( + ITypeInfo __RPC_FAR * This, + /* [in] */ UINT index, + /* [out] */ HREFTYPE __RPC_FAR *pRefType) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 8); + + + + if(!pRefType) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( UINT __RPC_FAR * )_StubMsg.Buffer = index; + _StubMsg.Buffer += sizeof(UINT); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[196] ); + + *pRefType = *( HREFTYPE __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HREFTYPE); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], + ( void __RPC_FAR * )pRefType); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo_GetRefTypeOfImplType_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HREFTYPE _M35; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + UINT index; + HREFTYPE __RPC_FAR *pRefType; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pRefType = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[196] ); + + index = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + pRefType = &_M35; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetRefTypeOfImplType( + (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, + index, + pRefType); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U + 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( HREFTYPE __RPC_FAR * )_StubMsg.Buffer = *pRefType; + _StubMsg.Buffer += sizeof(HREFTYPE); + + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeInfo_GetImplTypeFlags_Proxy( + ITypeInfo __RPC_FAR * This, + /* [in] */ UINT index, + /* [out] */ INT __RPC_FAR *pImplTypeFlags) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 9); + + + + if(!pImplTypeFlags) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( UINT __RPC_FAR * )_StubMsg.Buffer = index; + _StubMsg.Buffer += sizeof(UINT); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[196] ); + + *pImplTypeFlags = *( INT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(INT); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], + ( void __RPC_FAR * )pImplTypeFlags); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo_GetImplTypeFlags_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + INT _M36; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + UINT index; + INT __RPC_FAR *pImplTypeFlags; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pImplTypeFlags = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[196] ); + + index = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + pImplTypeFlags = &_M36; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetImplTypeFlags( + (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, + index, + pImplTypeFlags); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U + 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( INT __RPC_FAR * )_StubMsg.Buffer = *pImplTypeFlags; + _StubMsg.Buffer += sizeof(INT); + + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_LocalGetIDsOfNames_Proxy( + ITypeInfo __RPC_FAR * This) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 10); + + + + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[88] ); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo_LocalGetIDsOfNames_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + RpcTryFinally + { + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeInfo_GetIDsOfNames_Stub((ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_LocalInvoke_Proxy( + ITypeInfo __RPC_FAR * This) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 11); + + + + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[88] ); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo_LocalInvoke_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + RpcTryFinally + { + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeInfo_Invoke_Stub((ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_RemoteGetDocumentation_Proxy( + ITypeInfo __RPC_FAR * This, + /* [in] */ MEMBERID memid, + /* [in] */ DWORD refPtrFlags, + /* [out] */ BSTR __RPC_FAR *pBstrName, + /* [out] */ BSTR __RPC_FAR *pBstrDocString, + /* [out] */ DWORD __RPC_FAR *pdwHelpContext, + /* [out] */ BSTR __RPC_FAR *pBstrHelpFile) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pBstrName) + { + MIDL_memset( + pBstrName, + 0, + sizeof( BSTR )); + } + if(pBstrDocString) + { + MIDL_memset( + pBstrDocString, + 0, + sizeof( BSTR )); + } + if(pBstrHelpFile) + { + MIDL_memset( + pBstrHelpFile, + 0, + sizeof( BSTR )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 12); + + + + if(!pBstrName) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pBstrDocString) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pdwHelpContext) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pBstrHelpFile) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U + 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( MEMBERID __RPC_FAR * )_StubMsg.Buffer = memid; + _StubMsg.Buffer += sizeof(MEMBERID); + + *( DWORD __RPC_FAR * )_StubMsg.Buffer = refPtrFlags; + _StubMsg.Buffer += sizeof(DWORD); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[204] ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], + (unsigned char)0 ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrDocString, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *pdwHelpContext = *( DWORD __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(DWORD); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrHelpFile, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], + ( void __RPC_FAR * )pBstrName); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], + ( void __RPC_FAR * )pBstrDocString); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], + ( void __RPC_FAR * )pdwHelpContext); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], + ( void __RPC_FAR * )pBstrHelpFile); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo_RemoteGetDocumentation_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + BSTR _M37; + BSTR _M38; + DWORD _M39; + BSTR _M40; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + MEMBERID memid; + BSTR __RPC_FAR *pBstrDocString; + BSTR __RPC_FAR *pBstrHelpFile; + BSTR __RPC_FAR *pBstrName; + DWORD __RPC_FAR *pdwHelpContext; + DWORD refPtrFlags; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pBstrName = 0; + pBstrDocString = 0; + pdwHelpContext = 0; + pBstrHelpFile = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[204] ); + + memid = *( MEMBERID __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(MEMBERID); + + refPtrFlags = *( DWORD __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(DWORD); + + pBstrName = &_M37; + MIDL_memset( + pBstrName, + 0, + sizeof( BSTR )); + pBstrDocString = &_M38; + MIDL_memset( + pBstrDocString, + 0, + sizeof( BSTR )); + pdwHelpContext = &_M39; + pBstrHelpFile = &_M40; + MIDL_memset( + pBstrHelpFile, + 0, + sizeof( BSTR )); + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeInfo_GetDocumentation_Stub( + (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, + memid, + refPtrFlags, + pBstrName, + pBstrDocString, + pdwHelpContext, + pBstrHelpFile); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 8U + 15U + 11U + 11U + 11U; + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pBstrName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pBstrDocString, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pBstrHelpFile, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pBstrName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pBstrDocString, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( DWORD __RPC_FAR * )_StubMsg.Buffer = *pdwHelpContext; + _StubMsg.Buffer += sizeof(DWORD); + + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pBstrHelpFile, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pBstrName, + &__MIDL_TypeFormatString.Format[1708] ); + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pBstrDocString, + &__MIDL_TypeFormatString.Format[1708] ); + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pBstrHelpFile, + &__MIDL_TypeFormatString.Format[1708] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_RemoteGetDllEntry_Proxy( + ITypeInfo __RPC_FAR * This, + /* [in] */ MEMBERID memid, + /* [in] */ INVOKEKIND invKind, + /* [in] */ DWORD refPtrFlags, + /* [out] */ BSTR __RPC_FAR *pBstrDllName, + /* [out] */ BSTR __RPC_FAR *pBstrName, + /* [out] */ WORD __RPC_FAR *pwOrdinal) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pBstrDllName) + { + MIDL_memset( + pBstrDllName, + 0, + sizeof( BSTR )); + } + if(pBstrName) + { + MIDL_memset( + pBstrName, + 0, + sizeof( BSTR )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 13); + + + + if(!pBstrDllName) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pBstrName) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pwOrdinal) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U + 4U + 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( MEMBERID __RPC_FAR * )_StubMsg.Buffer = memid; + _StubMsg.Buffer += sizeof(MEMBERID); + + NdrSimpleTypeMarshall( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( unsigned char __RPC_FAR * )&invKind, + 14); + *( DWORD __RPC_FAR * )_StubMsg.Buffer = refPtrFlags; + _StubMsg.Buffer += sizeof(DWORD); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[226] ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrDllName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], + (unsigned char)0 ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 1) & ~ 0x1); + *pwOrdinal = *( WORD __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(WORD); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], + ( void __RPC_FAR * )pBstrDllName); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], + ( void __RPC_FAR * )pBstrName); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1712], + ( void __RPC_FAR * )pwOrdinal); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo_RemoteGetDllEntry_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + BSTR _M41; + BSTR _M42; + WORD _M43; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + INVOKEKIND invKind; + MEMBERID memid; + BSTR __RPC_FAR *pBstrDllName; + BSTR __RPC_FAR *pBstrName; + WORD __RPC_FAR *pwOrdinal; + DWORD refPtrFlags; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pBstrDllName = 0; + pBstrName = 0; + pwOrdinal = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[226] ); + + memid = *( MEMBERID __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(MEMBERID); + + NdrSimpleTypeUnmarshall( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( unsigned char __RPC_FAR * )&invKind, + 14); + refPtrFlags = *( DWORD __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(DWORD); + + pBstrDllName = &_M41; + MIDL_memset( + pBstrDllName, + 0, + sizeof( BSTR )); + pBstrName = &_M42; + MIDL_memset( + pBstrName, + 0, + sizeof( BSTR )); + pwOrdinal = &_M43; + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeInfo_GetDllEntry_Stub( + (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, + memid, + invKind, + refPtrFlags, + pBstrDllName, + pBstrName, + pwOrdinal); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 8U + 15U + 5U + 10U; + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pBstrDllName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pBstrName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pBstrDllName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pBstrName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 1) & ~ 0x1); + *( WORD __RPC_FAR * )_StubMsg.Buffer = *pwOrdinal; + _StubMsg.Buffer += sizeof(WORD); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pBstrDllName, + &__MIDL_TypeFormatString.Format[1708] ); + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pBstrName, + &__MIDL_TypeFormatString.Format[1708] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeInfo_GetRefTypeInfo_Proxy( + ITypeInfo __RPC_FAR * This, + /* [in] */ HREFTYPE hRefType, + /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(ppTInfo) + { + MIDL_memset( + ppTInfo, + 0, + sizeof( ITypeInfo __RPC_FAR *__RPC_FAR * )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 14); + + + + if(!ppTInfo) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( HREFTYPE __RPC_FAR * )_StubMsg.Buffer = hRefType; + _StubMsg.Buffer += sizeof(HREFTYPE); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[246] ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&ppTInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[6], + ( void __RPC_FAR * )ppTInfo); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo_GetRefTypeInfo_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + ITypeInfo __RPC_FAR *_M44; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + HREFTYPE hRefType; + ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + ppTInfo = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[246] ); + + hRefType = *( HREFTYPE __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HREFTYPE); + + ppTInfo = &_M44; + _M44 = 0; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetRefTypeInfo( + (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, + hRefType, + ppTInfo); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 0U + 4U; + NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)ppTInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)ppTInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)ppTInfo, + &__MIDL_TypeFormatString.Format[6] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_LocalAddressOfMember_Proxy( + ITypeInfo __RPC_FAR * This) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 15); + + + + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[88] ); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo_LocalAddressOfMember_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + RpcTryFinally + { + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeInfo_AddressOfMember_Stub((ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_RemoteCreateInstance_Proxy( + ITypeInfo __RPC_FAR * This, + /* [in] */ REFIID riid, + /* [iid_is][out] */ IUnknown __RPC_FAR *__RPC_FAR *ppvObj) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(ppvObj) + { + MIDL_memset( + ppvObj, + 0, + sizeof( IUnknown __RPC_FAR *__RPC_FAR * )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 16); + + + + if(!riid) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!ppvObj) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)riid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxyGetBuffer(This, &_StubMsg); + NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)riid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[254] ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&ppvObj, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1716], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + _StubMsg.MaxCount = (unsigned long) ( riid ); + + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1716], + ( void __RPC_FAR * )ppvObj); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo_RemoteCreateInstance_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + IUnknown __RPC_FAR *__RPC_FAR *_M45; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + IUnknown __RPC_FAR *__RPC_FAR *ppvObj; + IID* riid = 0; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + ppvObj = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[254] ); + + NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&riid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], + (unsigned char)0 ); + + ppvObj = (void *)&_M45; + _M45 = 0; + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeInfo_CreateInstance_Stub( + (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, + riid, + ppvObj); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 0U + 4U; + _StubMsg.MaxCount = (unsigned long) ( riid ); + + NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)ppvObj, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1716] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + _StubMsg.MaxCount = (unsigned long) ( riid ); + + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)ppvObj, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1716] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + _StubMsg.MaxCount = (unsigned long) ( riid ); + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)ppvObj, + &__MIDL_TypeFormatString.Format[1716] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeInfo_GetMops_Proxy( + ITypeInfo __RPC_FAR * This, + /* [in] */ MEMBERID memid, + /* [out] */ BSTR __RPC_FAR *pBstrMops) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pBstrMops) + { + MIDL_memset( + pBstrMops, + 0, + sizeof( BSTR )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 17); + + + + if(!pBstrMops) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( MEMBERID __RPC_FAR * )_StubMsg.Buffer = memid; + _StubMsg.Buffer += sizeof(MEMBERID); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[264] ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrMops, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], + ( void __RPC_FAR * )pBstrMops); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo_GetMops_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + BSTR _M46; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + MEMBERID memid; + BSTR __RPC_FAR *pBstrMops; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pBstrMops = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[264] ); + + memid = *( MEMBERID __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(MEMBERID); + + pBstrMops = &_M46; + MIDL_memset( + pBstrMops, + 0, + sizeof( BSTR )); + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetMops( + (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, + memid, + pBstrMops); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 8U + 11U; + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pBstrMops, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pBstrMops, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pBstrMops, + &__MIDL_TypeFormatString.Format[1708] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_RemoteGetContainingTypeLib_Proxy( + ITypeInfo __RPC_FAR * This, + /* [out] */ ITypeLib __RPC_FAR *__RPC_FAR *ppTLib, + /* [out] */ UINT __RPC_FAR *pIndex) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(ppTLib) + { + MIDL_memset( + ppTLib, + 0, + sizeof( ITypeLib __RPC_FAR *__RPC_FAR * )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 18); + + + + if(!ppTLib) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pIndex) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[272] ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&ppTLib, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1726], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *pIndex = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1726], + ( void __RPC_FAR * )ppTLib); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], + ( void __RPC_FAR * )pIndex); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo_RemoteGetContainingTypeLib_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + ITypeLib __RPC_FAR *_M47; + UINT _M48; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + UINT __RPC_FAR *pIndex; + ITypeLib __RPC_FAR *__RPC_FAR *ppTLib; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + ppTLib = 0; + pIndex = 0; + RpcTryFinally + { + ppTLib = &_M47; + _M47 = 0; + pIndex = &_M48; + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeInfo_GetContainingTypeLib_Stub( + (ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject, + ppTLib, + pIndex); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 0U + 4U + 4U; + NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)ppTLib, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1726] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)ppTLib, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1726] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( UINT __RPC_FAR * )_StubMsg.Buffer = *pIndex; + _StubMsg.Buffer += sizeof(UINT); + + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)ppTLib, + &__MIDL_TypeFormatString.Format[1726] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_LocalReleaseTypeAttr_Proxy( + ITypeInfo __RPC_FAR * This) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 19); + + + + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[88] ); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo_LocalReleaseTypeAttr_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + RpcTryFinally + { + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeInfo_ReleaseTypeAttr_Stub((ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_LocalReleaseFuncDesc_Proxy( + ITypeInfo __RPC_FAR * This) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 20); + + + + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[88] ); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo_LocalReleaseFuncDesc_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + RpcTryFinally + { + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeInfo_ReleaseFuncDesc_Stub((ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo_LocalReleaseVarDesc_Proxy( + ITypeInfo __RPC_FAR * This) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 21); + + + + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[88] ); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo_LocalReleaseVarDesc_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + RpcTryFinally + { + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeInfo_ReleaseVarDesc_Stub((ITypeInfo *) ((CStdStubBuffer *)This)->pvServerObject); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + +const CINTERFACE_PROXY_VTABLE(22) _ITypeInfoProxyVtbl = +{ + { &IID_ITypeInfo }, + { + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + ITypeInfo_GetTypeAttr_Proxy , + ITypeInfo_GetTypeComp_Proxy , + ITypeInfo_GetFuncDesc_Proxy , + ITypeInfo_GetVarDesc_Proxy , + ITypeInfo_GetNames_Proxy , + ITypeInfo_GetRefTypeOfImplType_Proxy , + ITypeInfo_GetImplTypeFlags_Proxy , + ITypeInfo_GetIDsOfNames_Proxy , + ITypeInfo_Invoke_Proxy , + ITypeInfo_GetDocumentation_Proxy , + ITypeInfo_GetDllEntry_Proxy , + ITypeInfo_GetRefTypeInfo_Proxy , + ITypeInfo_AddressOfMember_Proxy , + ITypeInfo_CreateInstance_Proxy , + ITypeInfo_GetMops_Proxy , + ITypeInfo_GetContainingTypeLib_Proxy , + ITypeInfo_ReleaseTypeAttr_Proxy , + ITypeInfo_ReleaseFuncDesc_Proxy , + ITypeInfo_ReleaseVarDesc_Proxy + } +}; + + +static const PRPC_STUB_FUNCTION ITypeInfo_table[] = +{ + ITypeInfo_RemoteGetTypeAttr_Stub, + ITypeInfo_GetTypeComp_Stub, + ITypeInfo_RemoteGetFuncDesc_Stub, + ITypeInfo_RemoteGetVarDesc_Stub, + ITypeInfo_RemoteGetNames_Stub, + ITypeInfo_GetRefTypeOfImplType_Stub, + ITypeInfo_GetImplTypeFlags_Stub, + ITypeInfo_LocalGetIDsOfNames_Stub, + ITypeInfo_LocalInvoke_Stub, + ITypeInfo_RemoteGetDocumentation_Stub, + ITypeInfo_RemoteGetDllEntry_Stub, + ITypeInfo_GetRefTypeInfo_Stub, + ITypeInfo_LocalAddressOfMember_Stub, + ITypeInfo_RemoteCreateInstance_Stub, + ITypeInfo_GetMops_Stub, + ITypeInfo_RemoteGetContainingTypeLib_Stub, + ITypeInfo_LocalReleaseTypeAttr_Stub, + ITypeInfo_LocalReleaseFuncDesc_Stub, + ITypeInfo_LocalReleaseVarDesc_Stub +}; + +const CInterfaceStubVtbl _ITypeInfoStubVtbl = +{ + { + &IID_ITypeInfo, + 0, + 22, + &ITypeInfo_table[-3] + }, + { CStdStubBuffer_METHODS } +}; + + +/* Object interface: ITypeInfo2, ver. 0.0, + GUID={0x00020412,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +HRESULT STDMETHODCALLTYPE ITypeInfo2_GetTypeKind_Proxy( + ITypeInfo2 __RPC_FAR * This, + /* [out] */ TYPEKIND __RPC_FAR *pTypeKind) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 22); + + + + if(!pTypeKind) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[282] ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pTypeKind, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1250], + (unsigned char)0 ); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1250], + ( void __RPC_FAR * )pTypeKind); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo2_GetTypeKind_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + TYPEKIND _M49; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + TYPEKIND __RPC_FAR *pTypeKind; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pTypeKind = 0; + RpcTryFinally + { + pTypeKind = &_M49; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetTypeKind((ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject,pTypeKind); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U + 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pTypeKind, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1250] ); + + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeInfo2_GetTypeFlags_Proxy( + ITypeInfo2 __RPC_FAR * This, + /* [out] */ ULONG __RPC_FAR *pTypeFlags) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 23); + + + + if(!pTypeFlags) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[0] ); + + *pTypeFlags = *( ULONG __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(ULONG); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], + ( void __RPC_FAR * )pTypeFlags); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo2_GetTypeFlags_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + ULONG _M50; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + ULONG __RPC_FAR *pTypeFlags; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pTypeFlags = 0; + RpcTryFinally + { + pTypeFlags = &_M50; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetTypeFlags((ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject,pTypeFlags); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U + 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( ULONG __RPC_FAR * )_StubMsg.Buffer = *pTypeFlags; + _StubMsg.Buffer += sizeof(ULONG); + + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeInfo2_GetFuncIndexOfMemId_Proxy( + ITypeInfo2 __RPC_FAR * This, + /* [in] */ MEMBERID memid, + /* [in] */ INVOKEKIND invKind, + /* [out] */ UINT __RPC_FAR *pFuncIndex) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 24); + + + + if(!pFuncIndex) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U + 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( MEMBERID __RPC_FAR * )_StubMsg.Buffer = memid; + _StubMsg.Buffer += sizeof(MEMBERID); + + NdrSimpleTypeMarshall( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( unsigned char __RPC_FAR * )&invKind, + 14); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[288] ); + + *pFuncIndex = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], + ( void __RPC_FAR * )pFuncIndex); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo2_GetFuncIndexOfMemId_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + UINT _M51; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + INVOKEKIND invKind; + MEMBERID memid; + UINT __RPC_FAR *pFuncIndex; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pFuncIndex = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[288] ); + + memid = *( MEMBERID __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(MEMBERID); + + NdrSimpleTypeUnmarshall( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( unsigned char __RPC_FAR * )&invKind, + 14); + pFuncIndex = &_M51; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetFuncIndexOfMemId( + (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, + memid, + invKind, + pFuncIndex); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U + 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( UINT __RPC_FAR * )_StubMsg.Buffer = *pFuncIndex; + _StubMsg.Buffer += sizeof(UINT); + + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeInfo2_GetVarIndexOfMemId_Proxy( + ITypeInfo2 __RPC_FAR * This, + /* [in] */ MEMBERID memid, + /* [out] */ UINT __RPC_FAR *pVarIndex) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 25); + + + + if(!pVarIndex) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( MEMBERID __RPC_FAR * )_StubMsg.Buffer = memid; + _StubMsg.Buffer += sizeof(MEMBERID); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[196] ); + + *pVarIndex = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], + ( void __RPC_FAR * )pVarIndex); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo2_GetVarIndexOfMemId_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + UINT _M52; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + MEMBERID memid; + UINT __RPC_FAR *pVarIndex; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pVarIndex = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[196] ); + + memid = *( MEMBERID __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(MEMBERID); + + pVarIndex = &_M52; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetVarIndexOfMemId( + (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, + memid, + pVarIndex); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U + 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( UINT __RPC_FAR * )_StubMsg.Buffer = *pVarIndex; + _StubMsg.Buffer += sizeof(UINT); + + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeInfo2_GetCustData_Proxy( + ITypeInfo2 __RPC_FAR * This, + /* [in] */ REFGUID guid, + /* [out] */ VARIANT __RPC_FAR *pVarVal) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pVarVal) + { + MIDL_memset( + pVarVal, + 0, + sizeof( VARIANT )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 26); + + + + if(!guid) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pVarVal) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)guid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxyGetBuffer(This, &_StubMsg); + NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)guid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[298] ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pVarVal, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1102], + ( void __RPC_FAR * )pVarVal); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo2_GetCustData_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + VARIANT _M53; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + REFGUID guid = 0; + VARIANT __RPC_FAR *pVarVal; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pVarVal = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[298] ); + + NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&guid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], + (unsigned char)0 ); + + pVarVal = &_M53; + MIDL_memset( + pVarVal, + 0, + sizeof( VARIANT )); + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetCustData( + (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, + guid, + pVarVal); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 8U + 11U; + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pVarVal, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pVarVal, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pVarVal, + &__MIDL_TypeFormatString.Format[1102] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeInfo2_GetFuncCustData_Proxy( + ITypeInfo2 __RPC_FAR * This, + /* [in] */ UINT index, + /* [in] */ REFGUID guid, + /* [out] */ VARIANT __RPC_FAR *pVarVal) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pVarVal) + { + MIDL_memset( + pVarVal, + 0, + sizeof( VARIANT )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 27); + + + + if(!guid) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pVarVal) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U + 4U; + NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)guid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxyGetBuffer(This, &_StubMsg); + *( UINT __RPC_FAR * )_StubMsg.Buffer = index; + _StubMsg.Buffer += sizeof(UINT); + + NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)guid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[308] ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pVarVal, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1102], + ( void __RPC_FAR * )pVarVal); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo2_GetFuncCustData_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + VARIANT _M54; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + REFGUID guid = 0; + UINT index; + VARIANT __RPC_FAR *pVarVal; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pVarVal = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[308] ); + + index = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&guid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], + (unsigned char)0 ); + + pVarVal = &_M54; + MIDL_memset( + pVarVal, + 0, + sizeof( VARIANT )); + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetFuncCustData( + (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, + index, + guid, + pVarVal); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 8U + 11U; + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pVarVal, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pVarVal, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pVarVal, + &__MIDL_TypeFormatString.Format[1102] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeInfo2_GetParamCustData_Proxy( + ITypeInfo2 __RPC_FAR * This, + /* [in] */ UINT indexFunc, + /* [in] */ UINT indexParam, + /* [in] */ REFGUID guid, + /* [out] */ VARIANT __RPC_FAR *pVarVal) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pVarVal) + { + MIDL_memset( + pVarVal, + 0, + sizeof( VARIANT )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 28); + + + + if(!guid) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pVarVal) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U + 4U + 0U; + NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)guid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxyGetBuffer(This, &_StubMsg); + *( UINT __RPC_FAR * )_StubMsg.Buffer = indexFunc; + _StubMsg.Buffer += sizeof(UINT); + + *( UINT __RPC_FAR * )_StubMsg.Buffer = indexParam; + _StubMsg.Buffer += sizeof(UINT); + + NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)guid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[320] ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pVarVal, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1102], + ( void __RPC_FAR * )pVarVal); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo2_GetParamCustData_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + VARIANT _M55; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + REFGUID guid = 0; + UINT indexFunc; + UINT indexParam; + VARIANT __RPC_FAR *pVarVal; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pVarVal = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[320] ); + + indexFunc = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + indexParam = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&guid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], + (unsigned char)0 ); + + pVarVal = &_M55; + MIDL_memset( + pVarVal, + 0, + sizeof( VARIANT )); + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetParamCustData( + (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, + indexFunc, + indexParam, + guid, + pVarVal); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 8U + 11U; + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pVarVal, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pVarVal, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pVarVal, + &__MIDL_TypeFormatString.Format[1102] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeInfo2_GetVarCustData_Proxy( + ITypeInfo2 __RPC_FAR * This, + /* [in] */ UINT index, + /* [in] */ REFGUID guid, + /* [out] */ VARIANT __RPC_FAR *pVarVal) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pVarVal) + { + MIDL_memset( + pVarVal, + 0, + sizeof( VARIANT )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 29); + + + + if(!guid) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pVarVal) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U + 4U; + NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)guid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxyGetBuffer(This, &_StubMsg); + *( UINT __RPC_FAR * )_StubMsg.Buffer = index; + _StubMsg.Buffer += sizeof(UINT); + + NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)guid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[308] ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pVarVal, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1102], + ( void __RPC_FAR * )pVarVal); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo2_GetVarCustData_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + VARIANT _M56; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + REFGUID guid = 0; + UINT index; + VARIANT __RPC_FAR *pVarVal; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pVarVal = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[308] ); + + index = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&guid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], + (unsigned char)0 ); + + pVarVal = &_M56; + MIDL_memset( + pVarVal, + 0, + sizeof( VARIANT )); + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetVarCustData( + (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, + index, + guid, + pVarVal); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 8U + 11U; + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pVarVal, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pVarVal, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pVarVal, + &__MIDL_TypeFormatString.Format[1102] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeInfo2_GetImplTypeCustData_Proxy( + ITypeInfo2 __RPC_FAR * This, + /* [in] */ UINT index, + /* [in] */ REFGUID guid, + /* [out] */ VARIANT __RPC_FAR *pVarVal) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pVarVal) + { + MIDL_memset( + pVarVal, + 0, + sizeof( VARIANT )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 30); + + + + if(!guid) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pVarVal) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U + 4U; + NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)guid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxyGetBuffer(This, &_StubMsg); + *( UINT __RPC_FAR * )_StubMsg.Buffer = index; + _StubMsg.Buffer += sizeof(UINT); + + NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)guid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[308] ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pVarVal, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1102], + ( void __RPC_FAR * )pVarVal); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo2_GetImplTypeCustData_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + VARIANT _M57; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + REFGUID guid = 0; + UINT index; + VARIANT __RPC_FAR *pVarVal; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pVarVal = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[308] ); + + index = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&guid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], + (unsigned char)0 ); + + pVarVal = &_M57; + MIDL_memset( + pVarVal, + 0, + sizeof( VARIANT )); + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetImplTypeCustData( + (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, + index, + guid, + pVarVal); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 8U + 11U; + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pVarVal, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pVarVal, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pVarVal, + &__MIDL_TypeFormatString.Format[1102] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeInfo2_RemoteGetDocumentation2_Proxy( + ITypeInfo2 __RPC_FAR * This, + /* [in] */ MEMBERID memid, + /* [in] */ LCID lcid, + /* [in] */ DWORD refPtrFlags, + /* [out] */ BSTR __RPC_FAR *pbstrHelpString, + /* [out] */ DWORD __RPC_FAR *pdwHelpStringContext, + /* [out] */ BSTR __RPC_FAR *pbstrHelpStringDll) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pbstrHelpString) + { + MIDL_memset( + pbstrHelpString, + 0, + sizeof( BSTR )); + } + if(pbstrHelpStringDll) + { + MIDL_memset( + pbstrHelpStringDll, + 0, + sizeof( BSTR )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 31); + + + + if(!pbstrHelpString) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pdwHelpStringContext) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pbstrHelpStringDll) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U + 4U + 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( MEMBERID __RPC_FAR * )_StubMsg.Buffer = memid; + _StubMsg.Buffer += sizeof(MEMBERID); + + *( LCID __RPC_FAR * )_StubMsg.Buffer = lcid; + _StubMsg.Buffer += sizeof(LCID); + + *( DWORD __RPC_FAR * )_StubMsg.Buffer = refPtrFlags; + _StubMsg.Buffer += sizeof(DWORD); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[334] ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pbstrHelpString, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *pdwHelpStringContext = *( DWORD __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(DWORD); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pbstrHelpStringDll, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], + ( void __RPC_FAR * )pbstrHelpString); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], + ( void __RPC_FAR * )pdwHelpStringContext); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], + ( void __RPC_FAR * )pbstrHelpStringDll); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo2_RemoteGetDocumentation2_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + BSTR _M58; + DWORD _M59; + BSTR _M60; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + LCID lcid; + MEMBERID memid; + BSTR __RPC_FAR *pbstrHelpString; + BSTR __RPC_FAR *pbstrHelpStringDll; + DWORD __RPC_FAR *pdwHelpStringContext; + DWORD refPtrFlags; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pbstrHelpString = 0; + pdwHelpStringContext = 0; + pbstrHelpStringDll = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[334] ); + + memid = *( MEMBERID __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(MEMBERID); + + lcid = *( LCID __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(LCID); + + refPtrFlags = *( DWORD __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(DWORD); + + pbstrHelpString = &_M58; + MIDL_memset( + pbstrHelpString, + 0, + sizeof( BSTR )); + pdwHelpStringContext = &_M59; + pbstrHelpStringDll = &_M60; + MIDL_memset( + pbstrHelpStringDll, + 0, + sizeof( BSTR )); + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeInfo2_GetDocumentation2_Stub( + (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, + memid, + lcid, + refPtrFlags, + pbstrHelpString, + pdwHelpStringContext, + pbstrHelpStringDll); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 8U + 11U + 11U + 11U; + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pbstrHelpString, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pbstrHelpStringDll, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pbstrHelpString, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( DWORD __RPC_FAR * )_StubMsg.Buffer = *pdwHelpStringContext; + _StubMsg.Buffer += sizeof(DWORD); + + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pbstrHelpStringDll, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pbstrHelpString, + &__MIDL_TypeFormatString.Format[1708] ); + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pbstrHelpStringDll, + &__MIDL_TypeFormatString.Format[1708] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeInfo2_GetAllCustData_Proxy( + ITypeInfo2 __RPC_FAR * This, + /* [out] */ CUSTDATA __RPC_FAR *pCustData) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pCustData) + { + MIDL_memset( + pCustData, + 0, + sizeof( CUSTDATA )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 32); + + + + if(!pCustData) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[354] ); + + NdrComplexStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pCustData, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1748], + ( void __RPC_FAR * )pCustData); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo2_GetAllCustData_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + CUSTDATA _pCustDataM; + CUSTDATA __RPC_FAR *pCustData; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pCustData = 0; + RpcTryFinally + { + pCustData = &_pCustDataM; + pCustData -> prgCustData = 0; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetAllCustData((ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject,pCustData); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 0U + 11U; + NdrComplexStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pCustData, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrComplexStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pCustData, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pCustData, + &__MIDL_TypeFormatString.Format[1748] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeInfo2_GetAllFuncCustData_Proxy( + ITypeInfo2 __RPC_FAR * This, + /* [in] */ UINT index, + /* [out] */ CUSTDATA __RPC_FAR *pCustData) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pCustData) + { + MIDL_memset( + pCustData, + 0, + sizeof( CUSTDATA )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 33); + + + + if(!pCustData) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( UINT __RPC_FAR * )_StubMsg.Buffer = index; + _StubMsg.Buffer += sizeof(UINT); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[360] ); + + NdrComplexStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pCustData, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1748], + ( void __RPC_FAR * )pCustData); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo2_GetAllFuncCustData_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + CUSTDATA _pCustDataM; + UINT index; + CUSTDATA __RPC_FAR *pCustData; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pCustData = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[360] ); + + index = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + pCustData = &_pCustDataM; + pCustData -> prgCustData = 0; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetAllFuncCustData( + (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, + index, + pCustData); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 0U + 11U; + NdrComplexStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pCustData, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrComplexStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pCustData, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pCustData, + &__MIDL_TypeFormatString.Format[1748] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeInfo2_GetAllParamCustData_Proxy( + ITypeInfo2 __RPC_FAR * This, + /* [in] */ UINT indexFunc, + /* [in] */ UINT indexParam, + /* [out] */ CUSTDATA __RPC_FAR *pCustData) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pCustData) + { + MIDL_memset( + pCustData, + 0, + sizeof( CUSTDATA )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 34); + + + + if(!pCustData) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U + 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( UINT __RPC_FAR * )_StubMsg.Buffer = indexFunc; + _StubMsg.Buffer += sizeof(UINT); + + *( UINT __RPC_FAR * )_StubMsg.Buffer = indexParam; + _StubMsg.Buffer += sizeof(UINT); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[368] ); + + NdrComplexStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pCustData, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1748], + ( void __RPC_FAR * )pCustData); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo2_GetAllParamCustData_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + CUSTDATA _pCustDataM; + UINT indexFunc; + UINT indexParam; + CUSTDATA __RPC_FAR *pCustData; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pCustData = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[368] ); + + indexFunc = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + indexParam = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + pCustData = &_pCustDataM; + pCustData -> prgCustData = 0; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetAllParamCustData( + (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, + indexFunc, + indexParam, + pCustData); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 0U + 11U; + NdrComplexStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pCustData, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrComplexStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pCustData, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pCustData, + &__MIDL_TypeFormatString.Format[1748] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeInfo2_GetAllVarCustData_Proxy( + ITypeInfo2 __RPC_FAR * This, + /* [in] */ UINT index, + /* [out] */ CUSTDATA __RPC_FAR *pCustData) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pCustData) + { + MIDL_memset( + pCustData, + 0, + sizeof( CUSTDATA )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 35); + + + + if(!pCustData) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( UINT __RPC_FAR * )_StubMsg.Buffer = index; + _StubMsg.Buffer += sizeof(UINT); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[360] ); + + NdrComplexStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pCustData, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1748], + ( void __RPC_FAR * )pCustData); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo2_GetAllVarCustData_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + CUSTDATA _pCustDataM; + UINT index; + CUSTDATA __RPC_FAR *pCustData; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pCustData = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[360] ); + + index = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + pCustData = &_pCustDataM; + pCustData -> prgCustData = 0; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetAllVarCustData( + (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, + index, + pCustData); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 0U + 11U; + NdrComplexStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pCustData, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrComplexStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pCustData, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pCustData, + &__MIDL_TypeFormatString.Format[1748] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeInfo2_GetAllImplTypeCustData_Proxy( + ITypeInfo2 __RPC_FAR * This, + /* [in] */ UINT index, + /* [out] */ CUSTDATA __RPC_FAR *pCustData) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pCustData) + { + MIDL_memset( + pCustData, + 0, + sizeof( CUSTDATA )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 36); + + + + if(!pCustData) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( UINT __RPC_FAR * )_StubMsg.Buffer = index; + _StubMsg.Buffer += sizeof(UINT); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[360] ); + + NdrComplexStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pCustData, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1748], + ( void __RPC_FAR * )pCustData); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeInfo2_GetAllImplTypeCustData_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + CUSTDATA _pCustDataM; + UINT index; + CUSTDATA __RPC_FAR *pCustData; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pCustData = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[360] ); + + index = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + pCustData = &_pCustDataM; + pCustData -> prgCustData = 0; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeInfo2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetAllImplTypeCustData( + (ITypeInfo2 *) ((CStdStubBuffer *)This)->pvServerObject, + index, + pCustData); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 0U + 11U; + NdrComplexStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pCustData, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrComplexStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pCustData, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pCustData, + &__MIDL_TypeFormatString.Format[1748] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + +const CINTERFACE_PROXY_VTABLE(37) _ITypeInfo2ProxyVtbl = +{ + { &IID_ITypeInfo2 }, + { + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + ITypeInfo_GetTypeAttr_Proxy , + ITypeInfo_GetTypeComp_Proxy , + ITypeInfo_GetFuncDesc_Proxy , + ITypeInfo_GetVarDesc_Proxy , + ITypeInfo_GetNames_Proxy , + ITypeInfo_GetRefTypeOfImplType_Proxy , + ITypeInfo_GetImplTypeFlags_Proxy , + ITypeInfo_GetIDsOfNames_Proxy , + ITypeInfo_Invoke_Proxy , + ITypeInfo_GetDocumentation_Proxy , + ITypeInfo_GetDllEntry_Proxy , + ITypeInfo_GetRefTypeInfo_Proxy , + ITypeInfo_AddressOfMember_Proxy , + ITypeInfo_CreateInstance_Proxy , + ITypeInfo_GetMops_Proxy , + ITypeInfo_GetContainingTypeLib_Proxy , + ITypeInfo_ReleaseTypeAttr_Proxy , + ITypeInfo_ReleaseFuncDesc_Proxy , + ITypeInfo_ReleaseVarDesc_Proxy , + ITypeInfo2_GetTypeKind_Proxy , + ITypeInfo2_GetTypeFlags_Proxy , + ITypeInfo2_GetFuncIndexOfMemId_Proxy , + ITypeInfo2_GetVarIndexOfMemId_Proxy , + ITypeInfo2_GetCustData_Proxy , + ITypeInfo2_GetFuncCustData_Proxy , + ITypeInfo2_GetParamCustData_Proxy , + ITypeInfo2_GetVarCustData_Proxy , + ITypeInfo2_GetImplTypeCustData_Proxy , + ITypeInfo2_GetDocumentation2_Proxy , + ITypeInfo2_GetAllCustData_Proxy , + ITypeInfo2_GetAllFuncCustData_Proxy , + ITypeInfo2_GetAllParamCustData_Proxy , + ITypeInfo2_GetAllVarCustData_Proxy , + ITypeInfo2_GetAllImplTypeCustData_Proxy + } +}; + + +static const PRPC_STUB_FUNCTION ITypeInfo2_table[] = +{ + ITypeInfo_RemoteGetTypeAttr_Stub, + ITypeInfo_GetTypeComp_Stub, + ITypeInfo_RemoteGetFuncDesc_Stub, + ITypeInfo_RemoteGetVarDesc_Stub, + ITypeInfo_RemoteGetNames_Stub, + ITypeInfo_GetRefTypeOfImplType_Stub, + ITypeInfo_GetImplTypeFlags_Stub, + ITypeInfo_LocalGetIDsOfNames_Stub, + ITypeInfo_LocalInvoke_Stub, + ITypeInfo_RemoteGetDocumentation_Stub, + ITypeInfo_RemoteGetDllEntry_Stub, + ITypeInfo_GetRefTypeInfo_Stub, + ITypeInfo_LocalAddressOfMember_Stub, + ITypeInfo_RemoteCreateInstance_Stub, + ITypeInfo_GetMops_Stub, + ITypeInfo_RemoteGetContainingTypeLib_Stub, + ITypeInfo_LocalReleaseTypeAttr_Stub, + ITypeInfo_LocalReleaseFuncDesc_Stub, + ITypeInfo_LocalReleaseVarDesc_Stub, + ITypeInfo2_GetTypeKind_Stub, + ITypeInfo2_GetTypeFlags_Stub, + ITypeInfo2_GetFuncIndexOfMemId_Stub, + ITypeInfo2_GetVarIndexOfMemId_Stub, + ITypeInfo2_GetCustData_Stub, + ITypeInfo2_GetFuncCustData_Stub, + ITypeInfo2_GetParamCustData_Stub, + ITypeInfo2_GetVarCustData_Stub, + ITypeInfo2_GetImplTypeCustData_Stub, + ITypeInfo2_RemoteGetDocumentation2_Stub, + ITypeInfo2_GetAllCustData_Stub, + ITypeInfo2_GetAllFuncCustData_Stub, + ITypeInfo2_GetAllParamCustData_Stub, + ITypeInfo2_GetAllVarCustData_Stub, + ITypeInfo2_GetAllImplTypeCustData_Stub +}; + +const CInterfaceStubVtbl _ITypeInfo2StubVtbl = +{ + { + &IID_ITypeInfo2, + 0, + 37, + &ITypeInfo2_table[-3] + }, + { CStdStubBuffer_METHODS } +}; + + +/* Object interface: ITypeLib, ver. 0.0, + GUID={0x00020402,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeLib_RemoteGetTypeInfoCount_Proxy( + ITypeLib __RPC_FAR * This, + /* [out] */ UINT __RPC_FAR *pcTInfo) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 3); + + + + if(!pcTInfo) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[0] ); + + *pcTInfo = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], + ( void __RPC_FAR * )pcTInfo); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeLib_RemoteGetTypeInfoCount_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + UINT _M61; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + UINT __RPC_FAR *pcTInfo; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pcTInfo = 0; + RpcTryFinally + { + pcTInfo = &_M61; + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeLib_GetTypeInfoCount_Stub((ITypeLib *) ((CStdStubBuffer *)This)->pvServerObject,pcTInfo); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U + 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( UINT __RPC_FAR * )_StubMsg.Buffer = *pcTInfo; + _StubMsg.Buffer += sizeof(UINT); + + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeLib_GetTypeInfo_Proxy( + ITypeLib __RPC_FAR * This, + /* [in] */ UINT index, + /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(ppTInfo) + { + MIDL_memset( + ppTInfo, + 0, + sizeof( ITypeInfo __RPC_FAR *__RPC_FAR * )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 4); + + + + if(!ppTInfo) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( UINT __RPC_FAR * )_StubMsg.Buffer = index; + _StubMsg.Buffer += sizeof(UINT); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[246] ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&ppTInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[6], + ( void __RPC_FAR * )ppTInfo); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeLib_GetTypeInfo_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + ITypeInfo __RPC_FAR *_M62; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + UINT index; + ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + ppTInfo = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[246] ); + + index = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + ppTInfo = &_M62; + _M62 = 0; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeLib*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetTypeInfo( + (ITypeLib *) ((CStdStubBuffer *)This)->pvServerObject, + index, + ppTInfo); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 0U + 4U; + NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)ppTInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)ppTInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)ppTInfo, + &__MIDL_TypeFormatString.Format[6] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeLib_GetTypeInfoType_Proxy( + ITypeLib __RPC_FAR * This, + /* [in] */ UINT index, + /* [out] */ TYPEKIND __RPC_FAR *pTKind) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 5); + + + + if(!pTKind) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( UINT __RPC_FAR * )_StubMsg.Buffer = index; + _StubMsg.Buffer += sizeof(UINT); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[378] ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pTKind, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1250], + (unsigned char)0 ); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1250], + ( void __RPC_FAR * )pTKind); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeLib_GetTypeInfoType_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + TYPEKIND _M63; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + UINT index; + TYPEKIND __RPC_FAR *pTKind; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pTKind = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[378] ); + + index = *( UINT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(UINT); + + pTKind = &_M63; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeLib*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetTypeInfoType( + (ITypeLib *) ((CStdStubBuffer *)This)->pvServerObject, + index, + pTKind); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U + 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pTKind, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1250] ); + + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeLib_GetTypeInfoOfGuid_Proxy( + ITypeLib __RPC_FAR * This, + /* [in] */ REFGUID guid, + /* [out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTinfo) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(ppTinfo) + { + MIDL_memset( + ppTinfo, + 0, + sizeof( ITypeInfo __RPC_FAR *__RPC_FAR * )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 6); + + + + if(!guid) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!ppTinfo) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)guid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxyGetBuffer(This, &_StubMsg); + NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)guid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[386] ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&ppTinfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[6], + ( void __RPC_FAR * )ppTinfo); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeLib_GetTypeInfoOfGuid_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + ITypeInfo __RPC_FAR *_M64; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + REFGUID guid = 0; + ITypeInfo __RPC_FAR *__RPC_FAR *ppTinfo; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + ppTinfo = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[386] ); + + NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&guid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], + (unsigned char)0 ); + + ppTinfo = &_M64; + _M64 = 0; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeLib*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetTypeInfoOfGuid( + (ITypeLib *) ((CStdStubBuffer *)This)->pvServerObject, + guid, + ppTinfo); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 0U + 4U; + NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)ppTinfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)ppTinfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[6] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)ppTinfo, + &__MIDL_TypeFormatString.Format[6] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeLib_RemoteGetLibAttr_Proxy( + ITypeLib __RPC_FAR * This, + /* [out] */ LPTLIBATTR __RPC_FAR *ppTLibAttr, + /* [out] */ CLEANLOCALSTORAGE __RPC_FAR *pDummy) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(ppTLibAttr) + { + *ppTLibAttr = 0; + } + if(pDummy) + { + MIDL_memset( + pDummy, + 0, + sizeof( CLEANLOCALSTORAGE )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 7); + + + + if(!ppTLibAttr) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pDummy) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[396] ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&ppTLibAttr, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1804], + (unsigned char)0 ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pDummy, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1838], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1804], + ( void __RPC_FAR * )ppTLibAttr); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1832], + ( void __RPC_FAR * )pDummy); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeLib_RemoteGetLibAttr_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + LPTLIBATTR _M65; + CLEANLOCALSTORAGE _M66; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + CLEANLOCALSTORAGE __RPC_FAR *pDummy; + LPTLIBATTR __RPC_FAR *ppTLibAttr; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + ppTLibAttr = 0; + pDummy = 0; + RpcTryFinally + { + ppTLibAttr = &_M65; + _M65 = 0; + pDummy = &_M66; + MIDL_memset( + pDummy, + 0, + sizeof( CLEANLOCALSTORAGE )); + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeLib_GetLibAttr_Stub( + (ITypeLib *) ((CStdStubBuffer *)This)->pvServerObject, + ppTLibAttr, + pDummy); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 8U + 11U + 7U; + NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)ppTLibAttr, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1804] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)ppTLibAttr, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1804] ); + + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pDummy, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1838] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)ppTLibAttr, + &__MIDL_TypeFormatString.Format[1804] ); + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pDummy, + &__MIDL_TypeFormatString.Format[1832] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeLib_GetTypeComp_Proxy( + ITypeLib __RPC_FAR * This, + /* [out] */ ITypeComp __RPC_FAR *__RPC_FAR *ppTComp) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(ppTComp) + { + MIDL_memset( + ppTComp, + 0, + sizeof( ITypeComp __RPC_FAR *__RPC_FAR * )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 8); + + + + if(!ppTComp) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[152] ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&ppTComp, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1540], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1540], + ( void __RPC_FAR * )ppTComp); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeLib_GetTypeComp_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + ITypeComp __RPC_FAR *_M67; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + ITypeComp __RPC_FAR *__RPC_FAR *ppTComp; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + ppTComp = 0; + RpcTryFinally + { + ppTComp = &_M67; + _M67 = 0; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeLib*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetTypeComp((ITypeLib *) ((CStdStubBuffer *)This)->pvServerObject,ppTComp); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 0U + 4U; + NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)ppTComp, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1540] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)ppTComp, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1540] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)ppTComp, + &__MIDL_TypeFormatString.Format[1540] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeLib_RemoteGetDocumentation_Proxy( + ITypeLib __RPC_FAR * This, + /* [in] */ INT index, + /* [in] */ DWORD refPtrFlags, + /* [out] */ BSTR __RPC_FAR *pBstrName, + /* [out] */ BSTR __RPC_FAR *pBstrDocString, + /* [out] */ DWORD __RPC_FAR *pdwHelpContext, + /* [out] */ BSTR __RPC_FAR *pBstrHelpFile) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pBstrName) + { + MIDL_memset( + pBstrName, + 0, + sizeof( BSTR )); + } + if(pBstrDocString) + { + MIDL_memset( + pBstrDocString, + 0, + sizeof( BSTR )); + } + if(pBstrHelpFile) + { + MIDL_memset( + pBstrHelpFile, + 0, + sizeof( BSTR )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 9); + + + + if(!pBstrName) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pBstrDocString) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pdwHelpContext) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pBstrHelpFile) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U + 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( INT __RPC_FAR * )_StubMsg.Buffer = index; + _StubMsg.Buffer += sizeof(INT); + + *( DWORD __RPC_FAR * )_StubMsg.Buffer = refPtrFlags; + _StubMsg.Buffer += sizeof(DWORD); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[204] ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], + (unsigned char)0 ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrDocString, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *pdwHelpContext = *( DWORD __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(DWORD); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrHelpFile, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], + ( void __RPC_FAR * )pBstrName); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], + ( void __RPC_FAR * )pBstrDocString); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], + ( void __RPC_FAR * )pdwHelpContext); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], + ( void __RPC_FAR * )pBstrHelpFile); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeLib_RemoteGetDocumentation_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + BSTR _M68; + BSTR _M69; + DWORD _M70; + BSTR _M71; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + INT index; + BSTR __RPC_FAR *pBstrDocString; + BSTR __RPC_FAR *pBstrHelpFile; + BSTR __RPC_FAR *pBstrName; + DWORD __RPC_FAR *pdwHelpContext; + DWORD refPtrFlags; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pBstrName = 0; + pBstrDocString = 0; + pdwHelpContext = 0; + pBstrHelpFile = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[204] ); + + index = *( INT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(INT); + + refPtrFlags = *( DWORD __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(DWORD); + + pBstrName = &_M68; + MIDL_memset( + pBstrName, + 0, + sizeof( BSTR )); + pBstrDocString = &_M69; + MIDL_memset( + pBstrDocString, + 0, + sizeof( BSTR )); + pdwHelpContext = &_M70; + pBstrHelpFile = &_M71; + MIDL_memset( + pBstrHelpFile, + 0, + sizeof( BSTR )); + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeLib_GetDocumentation_Stub( + (ITypeLib *) ((CStdStubBuffer *)This)->pvServerObject, + index, + refPtrFlags, + pBstrName, + pBstrDocString, + pdwHelpContext, + pBstrHelpFile); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 8U + 15U + 11U + 11U + 11U; + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pBstrName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pBstrDocString, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pBstrHelpFile, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pBstrName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pBstrDocString, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( DWORD __RPC_FAR * )_StubMsg.Buffer = *pdwHelpContext; + _StubMsg.Buffer += sizeof(DWORD); + + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pBstrHelpFile, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pBstrName, + &__MIDL_TypeFormatString.Format[1708] ); + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pBstrDocString, + &__MIDL_TypeFormatString.Format[1708] ); + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pBstrHelpFile, + &__MIDL_TypeFormatString.Format[1708] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeLib_RemoteIsName_Proxy( + ITypeLib __RPC_FAR * This, + /* [in] */ LPOLESTR szNameBuf, + /* [in] */ ULONG lHashVal, + /* [out] */ BOOL __RPC_FAR *pfName, + /* [out] */ BSTR __RPC_FAR *pBstrLibName) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pBstrLibName) + { + MIDL_memset( + pBstrLibName, + 0, + sizeof( BSTR )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 10); + + + + if(!szNameBuf) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pfName) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pBstrLibName) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 12U + 10U; + NdrConformantStringBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)szNameBuf, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); + + NdrProxyGetBuffer(This, &_StubMsg); + NdrConformantStringMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)szNameBuf, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( ULONG __RPC_FAR * )_StubMsg.Buffer = lHashVal; + _StubMsg.Buffer += sizeof(ULONG); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[406] ); + + *pfName = *( BOOL __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(BOOL); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrLibName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], + ( void __RPC_FAR * )pfName); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], + ( void __RPC_FAR * )pBstrLibName); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeLib_RemoteIsName_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + BOOL _M74; + BSTR _M75; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + ULONG lHashVal; + BSTR __RPC_FAR *pBstrLibName; + BOOL __RPC_FAR *pfName; + LPOLESTR szNameBuf; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + szNameBuf = 0; + pfName = 0; + pBstrLibName = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[406] ); + + NdrConformantStringUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&szNameBuf, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + lHashVal = *( ULONG __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(ULONG); + + pfName = &_M74; + pBstrLibName = &_M75; + MIDL_memset( + pBstrLibName, + 0, + sizeof( BSTR )); + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeLib_IsName_Stub( + (ITypeLib *) ((CStdStubBuffer *)This)->pvServerObject, + szNameBuf, + lHashVal, + pfName, + pBstrLibName); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U + 4U + 11U; + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pBstrLibName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( BOOL __RPC_FAR * )_StubMsg.Buffer = *pfName; + _StubMsg.Buffer += sizeof(BOOL); + + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pBstrLibName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pBstrLibName, + &__MIDL_TypeFormatString.Format[1708] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeLib_RemoteFindName_Proxy( + ITypeLib __RPC_FAR * This, + /* [in] */ LPOLESTR szNameBuf, + /* [in] */ ULONG lHashVal, + /* [length_is][size_is][out] */ ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo, + /* [length_is][size_is][out] */ MEMBERID __RPC_FAR *rgMemId, + /* [out][in] */ USHORT __RPC_FAR *pcFound, + /* [out] */ BSTR __RPC_FAR *pBstrLibName) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(ppTInfo) + { + MIDL_memset( + ppTInfo, + 0, + *pcFound * sizeof( ITypeInfo __RPC_FAR *__RPC_FAR * )); + } + if(pBstrLibName) + { + MIDL_memset( + pBstrLibName, + 0, + sizeof( BSTR )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 11); + + + + if(!szNameBuf) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!ppTInfo) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!rgMemId) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pcFound) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pBstrLibName) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 12U + 10U + 4U; + NdrConformantStringBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)szNameBuf, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); + + NdrProxyGetBuffer(This, &_StubMsg); + NdrConformantStringMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)szNameBuf, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( ULONG __RPC_FAR * )_StubMsg.Buffer = lHashVal; + _StubMsg.Buffer += sizeof(ULONG); + + *( USHORT __RPC_FAR * )_StubMsg.Buffer = *pcFound; + _StubMsg.Buffer += sizeof(USHORT); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[422] ); + + NdrComplexArrayUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&ppTInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1852], + (unsigned char)0 ); + + NdrConformantVaryingArrayUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&rgMemId, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1874], + (unsigned char)0 ); + + *pcFound = *( USHORT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(USHORT); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrLibName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + _StubMsg.MaxCount = pcFound ? *pcFound : 0; + _StubMsg.Offset = 0; + _StubMsg.ActualCount = _StubMsg.MaxCount; + + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1848], + ( void __RPC_FAR * )ppTInfo); + _StubMsg.MaxCount = pcFound ? *pcFound : 0; + _StubMsg.Offset = 0; + _StubMsg.ActualCount = _StubMsg.MaxCount; + + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1870], + ( void __RPC_FAR * )rgMemId); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1888], + ( void __RPC_FAR * )pcFound); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], + ( void __RPC_FAR * )pBstrLibName); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeLib_RemoteFindName_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + BSTR _M84; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + ULONG lHashVal; + BSTR __RPC_FAR *pBstrLibName; + USHORT __RPC_FAR *pcFound; + ITypeInfo __RPC_FAR *__RPC_FAR *ppTInfo; + MEMBERID __RPC_FAR *rgMemId; + LPOLESTR szNameBuf; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + szNameBuf = 0; + ppTInfo = 0; + rgMemId = 0; + pcFound = 0; + pBstrLibName = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[422] ); + + NdrConformantStringUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&szNameBuf, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + lHashVal = *( ULONG __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(ULONG); + + pcFound = ( USHORT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof( USHORT ); + + ppTInfo = NdrAllocate(&_StubMsg,*pcFound * 4); + rgMemId = NdrAllocate(&_StubMsg,*pcFound * 4); + pBstrLibName = &_M84; + MIDL_memset( + pBstrLibName, + 0, + sizeof( BSTR )); + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeLib_FindName_Stub( + (ITypeLib *) ((CStdStubBuffer *)This)->pvServerObject, + szNameBuf, + lHashVal, + ppTInfo, + rgMemId, + pcFound, + pBstrLibName); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 12U + 15U + 4U + 14U + 11U; + _StubMsg.MaxCount = pcFound ? *pcFound : 0; + _StubMsg.Offset = 0; + _StubMsg.ActualCount = pcFound ? *pcFound : 0; + + NdrComplexArrayBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)ppTInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1852] ); + + _StubMsg.MaxCount = pcFound ? *pcFound : 0; + _StubMsg.Offset = 0; + _StubMsg.ActualCount = pcFound ? *pcFound : 0; + + NdrConformantVaryingArrayBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)rgMemId, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1874] ); + + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pBstrLibName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + _StubMsg.MaxCount = pcFound ? *pcFound : 0; + _StubMsg.Offset = 0; + _StubMsg.ActualCount = pcFound ? *pcFound : 0; + + NdrComplexArrayMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)ppTInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1852] ); + + _StubMsg.MaxCount = pcFound ? *pcFound : 0; + _StubMsg.Offset = 0; + _StubMsg.ActualCount = pcFound ? *pcFound : 0; + + NdrConformantVaryingArrayMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)rgMemId, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1874] ); + + *( USHORT __RPC_FAR * )_StubMsg.Buffer = *pcFound; + _StubMsg.Buffer += sizeof(USHORT); + + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pBstrLibName, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + _StubMsg.MaxCount = pcFound ? *pcFound : 0; + _StubMsg.Offset = 0; + _StubMsg.ActualCount = pcFound ? *pcFound : 0; + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)ppTInfo, + &__MIDL_TypeFormatString.Format[1848] ); + + _StubMsg.MaxCount = pcFound ? *pcFound : 0; + _StubMsg.Offset = 0; + _StubMsg.ActualCount = pcFound ? *pcFound : 0; + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)rgMemId, + &__MIDL_TypeFormatString.Format[1870] ); + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pBstrLibName, + &__MIDL_TypeFormatString.Format[1708] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeLib_LocalReleaseTLibAttr_Proxy( + ITypeLib __RPC_FAR * This) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 12); + + + + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[88] ); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeLib_LocalReleaseTLibAttr_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + RpcTryFinally + { + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeLib_ReleaseTLibAttr_Stub((ITypeLib *) ((CStdStubBuffer *)This)->pvServerObject); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + +const CINTERFACE_PROXY_VTABLE(13) _ITypeLibProxyVtbl = +{ + { &IID_ITypeLib }, + { + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + ITypeLib_GetTypeInfoCount_Proxy , + ITypeLib_GetTypeInfo_Proxy , + ITypeLib_GetTypeInfoType_Proxy , + ITypeLib_GetTypeInfoOfGuid_Proxy , + ITypeLib_GetLibAttr_Proxy , + ITypeLib_GetTypeComp_Proxy , + ITypeLib_GetDocumentation_Proxy , + ITypeLib_IsName_Proxy , + ITypeLib_FindName_Proxy , + ITypeLib_ReleaseTLibAttr_Proxy + } +}; + + +static const PRPC_STUB_FUNCTION ITypeLib_table[] = +{ + ITypeLib_RemoteGetTypeInfoCount_Stub, + ITypeLib_GetTypeInfo_Stub, + ITypeLib_GetTypeInfoType_Stub, + ITypeLib_GetTypeInfoOfGuid_Stub, + ITypeLib_RemoteGetLibAttr_Stub, + ITypeLib_GetTypeComp_Stub, + ITypeLib_RemoteGetDocumentation_Stub, + ITypeLib_RemoteIsName_Stub, + ITypeLib_RemoteFindName_Stub, + ITypeLib_LocalReleaseTLibAttr_Stub +}; + +const CInterfaceStubVtbl _ITypeLibStubVtbl = +{ + { + &IID_ITypeLib, + 0, + 13, + &ITypeLib_table[-3] + }, + { CStdStubBuffer_METHODS } +}; + + +/* Object interface: ITypeLib2, ver. 0.0, + GUID={0x00020411,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +HRESULT STDMETHODCALLTYPE ITypeLib2_GetCustData_Proxy( + ITypeLib2 __RPC_FAR * This, + /* [in] */ REFGUID guid, + /* [out] */ VARIANT __RPC_FAR *pVarVal) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pVarVal) + { + MIDL_memset( + pVarVal, + 0, + sizeof( VARIANT )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 13); + + + + if(!guid) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pVarVal) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)guid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxyGetBuffer(This, &_StubMsg); + NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)guid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[298] ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pVarVal, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1102], + ( void __RPC_FAR * )pVarVal); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeLib2_GetCustData_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + VARIANT _M85; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + REFGUID guid = 0; + VARIANT __RPC_FAR *pVarVal; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pVarVal = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[298] ); + + NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&guid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], + (unsigned char)0 ); + + pVarVal = &_M85; + MIDL_memset( + pVarVal, + 0, + sizeof( VARIANT )); + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeLib2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetCustData( + (ITypeLib2 *) ((CStdStubBuffer *)This)->pvServerObject, + guid, + pVarVal); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 8U + 11U; + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pVarVal, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pVarVal, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1110] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pVarVal, + &__MIDL_TypeFormatString.Format[1102] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeLib2_RemoteGetLibStatistics_Proxy( + ITypeLib2 __RPC_FAR * This, + /* [out] */ ULONG __RPC_FAR *pcUniqueNames, + /* [out] */ ULONG __RPC_FAR *pcchUniqueNames) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 14); + + + + if(!pcUniqueNames) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pcchUniqueNames) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[446] ); + + *pcUniqueNames = *( ULONG __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(ULONG); + + *pcchUniqueNames = *( ULONG __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(ULONG); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], + ( void __RPC_FAR * )pcUniqueNames); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], + ( void __RPC_FAR * )pcchUniqueNames); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeLib2_RemoteGetLibStatistics_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + ULONG _M86; + ULONG _M87; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + ULONG __RPC_FAR *pcUniqueNames; + ULONG __RPC_FAR *pcchUniqueNames; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pcUniqueNames = 0; + pcchUniqueNames = 0; + RpcTryFinally + { + pcUniqueNames = &_M86; + pcchUniqueNames = &_M87; + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeLib2_GetLibStatistics_Stub( + (ITypeLib2 *) ((CStdStubBuffer *)This)->pvServerObject, + pcUniqueNames, + pcchUniqueNames); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U + 4U + 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( ULONG __RPC_FAR * )_StubMsg.Buffer = *pcUniqueNames; + _StubMsg.Buffer += sizeof(ULONG); + + *( ULONG __RPC_FAR * )_StubMsg.Buffer = *pcchUniqueNames; + _StubMsg.Buffer += sizeof(ULONG); + + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +/* [call_as] */ HRESULT STDMETHODCALLTYPE ITypeLib2_RemoteGetDocumentation2_Proxy( + ITypeLib2 __RPC_FAR * This, + /* [in] */ INT index, + /* [in] */ LCID lcid, + /* [in] */ DWORD refPtrFlags, + /* [out] */ BSTR __RPC_FAR *pbstrHelpString, + /* [out] */ DWORD __RPC_FAR *pdwHelpStringContext, + /* [out] */ BSTR __RPC_FAR *pbstrHelpStringDll) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pbstrHelpString) + { + MIDL_memset( + pbstrHelpString, + 0, + sizeof( BSTR )); + } + if(pbstrHelpStringDll) + { + MIDL_memset( + pbstrHelpStringDll, + 0, + sizeof( BSTR )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 15); + + + + if(!pbstrHelpString) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pdwHelpStringContext) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!pbstrHelpStringDll) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 4U + 4U + 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( INT __RPC_FAR * )_StubMsg.Buffer = index; + _StubMsg.Buffer += sizeof(INT); + + *( LCID __RPC_FAR * )_StubMsg.Buffer = lcid; + _StubMsg.Buffer += sizeof(LCID); + + *( DWORD __RPC_FAR * )_StubMsg.Buffer = refPtrFlags; + _StubMsg.Buffer += sizeof(DWORD); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[334] ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pbstrHelpString, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *pdwHelpStringContext = *( DWORD __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(DWORD); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pbstrHelpStringDll, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], + ( void __RPC_FAR * )pbstrHelpString); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], + ( void __RPC_FAR * )pdwHelpStringContext); + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], + ( void __RPC_FAR * )pbstrHelpStringDll); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeLib2_RemoteGetDocumentation2_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + BSTR _M88; + DWORD _M89; + BSTR _M90; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + INT index; + LCID lcid; + BSTR __RPC_FAR *pbstrHelpString; + BSTR __RPC_FAR *pbstrHelpStringDll; + DWORD __RPC_FAR *pdwHelpStringContext; + DWORD refPtrFlags; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pbstrHelpString = 0; + pdwHelpStringContext = 0; + pbstrHelpStringDll = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[334] ); + + index = *( INT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(INT); + + lcid = *( LCID __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(LCID); + + refPtrFlags = *( DWORD __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(DWORD); + + pbstrHelpString = &_M88; + MIDL_memset( + pbstrHelpString, + 0, + sizeof( BSTR )); + pdwHelpStringContext = &_M89; + pbstrHelpStringDll = &_M90; + MIDL_memset( + pbstrHelpStringDll, + 0, + sizeof( BSTR )); + + *_pdwStubPhase = STUB_CALL_SERVER; + + + _RetVal = ITypeLib2_GetDocumentation2_Stub( + (ITypeLib2 *) ((CStdStubBuffer *)This)->pvServerObject, + index, + lcid, + refPtrFlags, + pbstrHelpString, + pdwHelpStringContext, + pbstrHelpStringDll); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 8U + 11U + 11U + 11U; + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pbstrHelpString, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pbstrHelpStringDll, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pbstrHelpString, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( DWORD __RPC_FAR * )_StubMsg.Buffer = *pdwHelpStringContext; + _StubMsg.Buffer += sizeof(DWORD); + + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pbstrHelpStringDll, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pbstrHelpString, + &__MIDL_TypeFormatString.Format[1708] ); + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pbstrHelpStringDll, + &__MIDL_TypeFormatString.Format[1708] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ITypeLib2_GetAllCustData_Proxy( + ITypeLib2 __RPC_FAR * This, + /* [out] */ CUSTDATA __RPC_FAR *pCustData) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pCustData) + { + MIDL_memset( + pCustData, + 0, + sizeof( CUSTDATA )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 16); + + + + if(!pCustData) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[354] ); + + NdrComplexStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pCustData, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1748], + ( void __RPC_FAR * )pCustData); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeLib2_GetAllCustData_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + CUSTDATA _pCustDataM; + CUSTDATA __RPC_FAR *pCustData; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pCustData = 0; + RpcTryFinally + { + pCustData = &_pCustDataM; + pCustData -> prgCustData = 0; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeLib2*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetAllCustData((ITypeLib2 *) ((CStdStubBuffer *)This)->pvServerObject,pCustData); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 0U + 11U; + NdrComplexStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pCustData, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrComplexStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pCustData, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1788] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pCustData, + &__MIDL_TypeFormatString.Format[1748] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + +const CINTERFACE_PROXY_VTABLE(17) _ITypeLib2ProxyVtbl = +{ + { &IID_ITypeLib2 }, + { + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + ITypeLib_GetTypeInfoCount_Proxy , + ITypeLib_GetTypeInfo_Proxy , + ITypeLib_GetTypeInfoType_Proxy , + ITypeLib_GetTypeInfoOfGuid_Proxy , + ITypeLib_GetLibAttr_Proxy , + ITypeLib_GetTypeComp_Proxy , + ITypeLib_GetDocumentation_Proxy , + ITypeLib_IsName_Proxy , + ITypeLib_FindName_Proxy , + ITypeLib_ReleaseTLibAttr_Proxy , + ITypeLib2_GetCustData_Proxy , + ITypeLib2_GetLibStatistics_Proxy , + ITypeLib2_GetDocumentation2_Proxy , + ITypeLib2_GetAllCustData_Proxy + } +}; + + +static const PRPC_STUB_FUNCTION ITypeLib2_table[] = +{ + ITypeLib_RemoteGetTypeInfoCount_Stub, + ITypeLib_GetTypeInfo_Stub, + ITypeLib_GetTypeInfoType_Stub, + ITypeLib_GetTypeInfoOfGuid_Stub, + ITypeLib_RemoteGetLibAttr_Stub, + ITypeLib_GetTypeComp_Stub, + ITypeLib_RemoteGetDocumentation_Stub, + ITypeLib_RemoteIsName_Stub, + ITypeLib_RemoteFindName_Stub, + ITypeLib_LocalReleaseTLibAttr_Stub, + ITypeLib2_GetCustData_Stub, + ITypeLib2_RemoteGetLibStatistics_Stub, + ITypeLib2_RemoteGetDocumentation2_Stub, + ITypeLib2_GetAllCustData_Stub +}; + +const CInterfaceStubVtbl _ITypeLib2StubVtbl = +{ + { + &IID_ITypeLib2, + 0, + 17, + &ITypeLib2_table[-3] + }, + { CStdStubBuffer_METHODS } +}; + + +/* Object interface: ITypeChangeEvents, ver. 0.0, + GUID={0x00020410,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ + + +/* Object interface: IErrorInfo, ver. 0.0, + GUID={0x1CF2B120,0x547D,0x101B,{0x8E,0x65,0x08,0x00,0x2B,0x2B,0xD1,0x19}} */ + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +HRESULT STDMETHODCALLTYPE IErrorInfo_GetGUID_Proxy( + IErrorInfo __RPC_FAR * This, + /* [out] */ GUID __RPC_FAR *pGUID) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pGUID) + { + MIDL_memset( + pGUID, + 0, + sizeof( IID )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 3); + + + + if(!pGUID) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[456] ); + + NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pGUID, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], + (unsigned char)0 ); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1892], + ( void __RPC_FAR * )pGUID); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB IErrorInfo_GetGUID_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + IID _pGUIDM; + GUID __RPC_FAR *pGUID; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pGUID = 0; + RpcTryFinally + { + pGUID = &_pGUIDM; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((IErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetGUID((IErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,pGUID); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 0U + 11U; + NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pGUID, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pGUID, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE IErrorInfo_GetSource_Proxy( + IErrorInfo __RPC_FAR * This, + /* [out] */ BSTR __RPC_FAR *pBstrSource) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pBstrSource) + { + MIDL_memset( + pBstrSource, + 0, + sizeof( BSTR )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 4); + + + + if(!pBstrSource) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[462] ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrSource, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], + ( void __RPC_FAR * )pBstrSource); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB IErrorInfo_GetSource_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + BSTR _M91; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + BSTR __RPC_FAR *pBstrSource; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pBstrSource = 0; + RpcTryFinally + { + pBstrSource = &_M91; + MIDL_memset( + pBstrSource, + 0, + sizeof( BSTR )); + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((IErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetSource((IErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,pBstrSource); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 8U + 11U; + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pBstrSource, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pBstrSource, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pBstrSource, + &__MIDL_TypeFormatString.Format[1708] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE IErrorInfo_GetDescription_Proxy( + IErrorInfo __RPC_FAR * This, + /* [out] */ BSTR __RPC_FAR *pBstrDescription) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pBstrDescription) + { + MIDL_memset( + pBstrDescription, + 0, + sizeof( BSTR )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 5); + + + + if(!pBstrDescription) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[462] ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrDescription, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], + ( void __RPC_FAR * )pBstrDescription); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB IErrorInfo_GetDescription_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + BSTR _M92; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + BSTR __RPC_FAR *pBstrDescription; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pBstrDescription = 0; + RpcTryFinally + { + pBstrDescription = &_M92; + MIDL_memset( + pBstrDescription, + 0, + sizeof( BSTR )); + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((IErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetDescription((IErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,pBstrDescription); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 8U + 11U; + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pBstrDescription, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pBstrDescription, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pBstrDescription, + &__MIDL_TypeFormatString.Format[1708] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE IErrorInfo_GetHelpFile_Proxy( + IErrorInfo __RPC_FAR * This, + /* [out] */ BSTR __RPC_FAR *pBstrHelpFile) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(pBstrHelpFile) + { + MIDL_memset( + pBstrHelpFile, + 0, + sizeof( BSTR )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 6); + + + + if(!pBstrHelpFile) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[462] ); + + NdrUserMarshalUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pBstrHelpFile, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1708], + ( void __RPC_FAR * )pBstrHelpFile); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB IErrorInfo_GetHelpFile_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + BSTR _M93; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + BSTR __RPC_FAR *pBstrHelpFile; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pBstrHelpFile = 0; + RpcTryFinally + { + pBstrHelpFile = &_M93; + MIDL_memset( + pBstrHelpFile, + 0, + sizeof( BSTR )); + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((IErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetHelpFile((IErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,pBstrHelpFile); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 8U + 11U; + NdrUserMarshalBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pBstrHelpFile, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + NdrUserMarshalMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pBstrHelpFile, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1128] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pBstrHelpFile, + &__MIDL_TypeFormatString.Format[1708] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE IErrorInfo_GetHelpContext_Proxy( + IErrorInfo __RPC_FAR * This, + /* [out] */ DWORD __RPC_FAR *pdwHelpContext) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 7); + + + + if(!pdwHelpContext) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrProxyGetBuffer(This, &_StubMsg); + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[0] ); + + *pdwHelpContext = *( DWORD __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(DWORD); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[2], + ( void __RPC_FAR * )pdwHelpContext); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB IErrorInfo_GetHelpContext_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + DWORD _M94; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + DWORD __RPC_FAR *pdwHelpContext; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pdwHelpContext = 0; + RpcTryFinally + { + pdwHelpContext = &_M94; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((IErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> GetHelpContext((IErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,pdwHelpContext); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U + 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( DWORD __RPC_FAR * )_StubMsg.Buffer = *pdwHelpContext; + _StubMsg.Buffer += sizeof(DWORD); + + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + +const CINTERFACE_PROXY_VTABLE(8) _IErrorInfoProxyVtbl = +{ + { &IID_IErrorInfo }, + { + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + IErrorInfo_GetGUID_Proxy , + IErrorInfo_GetSource_Proxy , + IErrorInfo_GetDescription_Proxy , + IErrorInfo_GetHelpFile_Proxy , + IErrorInfo_GetHelpContext_Proxy + } +}; + + +static const PRPC_STUB_FUNCTION IErrorInfo_table[] = +{ + IErrorInfo_GetGUID_Stub, + IErrorInfo_GetSource_Stub, + IErrorInfo_GetDescription_Stub, + IErrorInfo_GetHelpFile_Stub, + IErrorInfo_GetHelpContext_Stub +}; + +const CInterfaceStubVtbl _IErrorInfoStubVtbl = +{ + { + &IID_IErrorInfo, + 0, + 8, + &IErrorInfo_table[-3] + }, + { CStdStubBuffer_METHODS } +}; + + +/* Object interface: ICreateErrorInfo, ver. 0.0, + GUID={0x22F03340,0x547D,0x101B,{0x8E,0x65,0x08,0x00,0x2B,0x2B,0xD1,0x19}} */ + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +HRESULT STDMETHODCALLTYPE ICreateErrorInfo_SetGUID_Proxy( + ICreateErrorInfo __RPC_FAR * This, + /* [in] */ REFGUID rguid) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 3); + + + + if(!rguid) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)rguid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxyGetBuffer(This, &_StubMsg); + NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)rguid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[468] ); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ICreateErrorInfo_SetGUID_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + REFGUID rguid = 0; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[468] ); + + NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&rguid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], + (unsigned char)0 ); + + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ICreateErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> SetGUID((ICreateErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,rguid); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ICreateErrorInfo_SetSource_Proxy( + ICreateErrorInfo __RPC_FAR * This, + /* [in] */ LPOLESTR szSource) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 4); + + + + if(!szSource) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 12U; + NdrConformantStringBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)szSource, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); + + NdrProxyGetBuffer(This, &_StubMsg); + NdrConformantStringMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)szSource, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[474] ); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ICreateErrorInfo_SetSource_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + LPOLESTR szSource; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + szSource = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[474] ); + + NdrConformantStringUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&szSource, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248], + (unsigned char)0 ); + + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ICreateErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> SetSource((ICreateErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,szSource); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U; + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ICreateErrorInfo_SetDescription_Proxy( + ICreateErrorInfo __RPC_FAR * This, + /* [in] */ LPOLESTR szDescription) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 5); + + + + if(!szDescription) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 12U; + NdrConformantStringBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)szDescription, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); + + NdrProxyGetBuffer(This, &_StubMsg); + NdrConformantStringMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)szDescription, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[474] ); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ICreateErrorInfo_SetDescription_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + LPOLESTR szDescription; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + szDescription = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[474] ); + + NdrConformantStringUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&szDescription, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248], + (unsigned char)0 ); + + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ICreateErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> SetDescription((ICreateErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,szDescription); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U; + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ICreateErrorInfo_SetHelpFile_Proxy( + ICreateErrorInfo __RPC_FAR * This, + /* [in] */ LPOLESTR szHelpFile) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 6); + + + + if(!szHelpFile) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 12U; + NdrConformantStringBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)szHelpFile, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); + + NdrProxyGetBuffer(This, &_StubMsg); + NdrConformantStringMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)szHelpFile, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248] ); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[474] ); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ICreateErrorInfo_SetHelpFile_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + LPOLESTR szHelpFile; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + szHelpFile = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[474] ); + + NdrConformantStringUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&szHelpFile, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1248], + (unsigned char)0 ); + + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ICreateErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> SetHelpFile((ICreateErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,szHelpFile); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U; + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + + +HRESULT STDMETHODCALLTYPE ICreateErrorInfo_SetHelpContext_Proxy( + ICreateErrorInfo __RPC_FAR * This, + /* [in] */ DWORD dwHelpContext) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 7); + + + + RpcTryFinally + { + + _StubMsg.BufferLength = 4U; + NdrProxyGetBuffer(This, &_StubMsg); + *( DWORD __RPC_FAR * )_StubMsg.Buffer = dwHelpContext; + _StubMsg.Buffer += sizeof(DWORD); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[84] ); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ICreateErrorInfo_SetHelpContext_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + DWORD dwHelpContext; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[84] ); + + dwHelpContext = *( DWORD __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(DWORD); + + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ICreateErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> SetHelpContext((ICreateErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,dwHelpContext); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + +const CINTERFACE_PROXY_VTABLE(8) _ICreateErrorInfoProxyVtbl = +{ + { &IID_ICreateErrorInfo }, + { + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + ICreateErrorInfo_SetGUID_Proxy , + ICreateErrorInfo_SetSource_Proxy , + ICreateErrorInfo_SetDescription_Proxy , + ICreateErrorInfo_SetHelpFile_Proxy , + ICreateErrorInfo_SetHelpContext_Proxy + } +}; + + +static const PRPC_STUB_FUNCTION ICreateErrorInfo_table[] = +{ + ICreateErrorInfo_SetGUID_Stub, + ICreateErrorInfo_SetSource_Stub, + ICreateErrorInfo_SetDescription_Stub, + ICreateErrorInfo_SetHelpFile_Stub, + ICreateErrorInfo_SetHelpContext_Stub +}; + +const CInterfaceStubVtbl _ICreateErrorInfoStubVtbl = +{ + { + &IID_ICreateErrorInfo, + 0, + 8, + &ICreateErrorInfo_table[-3] + }, + { CStdStubBuffer_METHODS } +}; + + +/* Object interface: ISupportErrorInfo, ver. 0.0, + GUID={0xDF0B3D60,0x548F,0x101B,{0x8E,0x65,0x08,0x00,0x2B,0x2B,0xD1,0x19}} */ + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +HRESULT STDMETHODCALLTYPE ISupportErrorInfo_InterfaceSupportsErrorInfo_Proxy( + ISupportErrorInfo __RPC_FAR * This, + /* [in] */ REFIID riid) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 3); + + + + if(!riid) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U; + NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)riid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxyGetBuffer(This, &_StubMsg); + NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)riid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[468] ); + + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ISupportErrorInfo_InterfaceSupportsErrorInfo_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + IID* riid = 0; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[468] ); + + NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&riid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], + (unsigned char)0 ); + + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ISupportErrorInfo*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> InterfaceSupportsErrorInfo((ISupportErrorInfo *) ((CStdStubBuffer *)This)->pvServerObject,riid); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 4U; + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + +const CINTERFACE_PROXY_VTABLE(4) _ISupportErrorInfoProxyVtbl = +{ + { &IID_ISupportErrorInfo }, + { + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + ISupportErrorInfo_InterfaceSupportsErrorInfo_Proxy + } +}; + + +static const PRPC_STUB_FUNCTION ISupportErrorInfo_table[] = +{ + ISupportErrorInfo_InterfaceSupportsErrorInfo_Stub +}; + +const CInterfaceStubVtbl _ISupportErrorInfoStubVtbl = +{ + { + &IID_ISupportErrorInfo, + 0, + 4, + &ISupportErrorInfo_table[-3] + }, + { CStdStubBuffer_METHODS } +}; + + +/* Object interface: ITypeFactory, ver. 0.0, + GUID={0x0000002E,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ + + +extern const MIDL_STUB_DESC Object_StubDesc; + + +HRESULT STDMETHODCALLTYPE ITypeFactory_CreateFromTypeInfo_Proxy( + ITypeFactory __RPC_FAR * This, + /* [in] */ ITypeInfo __RPC_FAR *pTypeInfo, + /* [in] */ REFIID riid, + /* [iid_is][out] */ IUnknown __RPC_FAR *__RPC_FAR *ppv) +{ + + HRESULT _RetVal; + + RPC_MESSAGE _RpcMessage; + + MIDL_STUB_MESSAGE _StubMsg; + + if(ppv) + { + MIDL_memset( + ppv, + 0, + sizeof( IUnknown __RPC_FAR *__RPC_FAR * )); + } + RpcTryExcept + { + NdrProxyInitialize( + ( void __RPC_FAR * )This, + ( PRPC_MESSAGE )&_RpcMessage, + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PMIDL_STUB_DESC )&Object_StubDesc, + 3); + + + + if(!riid) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + if(!ppv) + { + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + RpcTryFinally + { + + _StubMsg.BufferLength = 0U + 0U; + NdrInterfacePointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)pTypeInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[10] ); + + NdrSimpleStructBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)riid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxyGetBuffer(This, &_StubMsg); + NdrInterfacePointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)pTypeInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[10] ); + + NdrSimpleStructMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)riid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38] ); + + NdrProxySendReceive(This, &_StubMsg); + + if ( (_RpcMessage.DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[480] ); + + NdrPointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&ppv, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1896], + (unsigned char)0 ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + _RetVal = *( HRESULT __RPC_FAR * )_StubMsg.Buffer; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrProxyFreeBuffer(This, &_StubMsg); + + } + RpcEndFinally + + } + RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE) + { + _StubMsg.MaxCount = (unsigned long) ( riid ); + + NdrClearOutParameters( + ( PMIDL_STUB_MESSAGE )&_StubMsg, + ( PFORMAT_STRING )&__MIDL_TypeFormatString.Format[1896], + ( void __RPC_FAR * )ppv); + _RetVal = NdrProxyErrorHandler(RpcExceptionCode()); + } + RpcEndExcept + return _RetVal; +} + +void __RPC_STUB ITypeFactory_CreateFromTypeInfo_Stub( + IRpcStubBuffer *This, + IRpcChannelBuffer *_pRpcChannelBuffer, + PRPC_MESSAGE _pRpcMessage, + DWORD *_pdwStubPhase) +{ + IUnknown __RPC_FAR *__RPC_FAR *_M101; + HRESULT _RetVal; + MIDL_STUB_MESSAGE _StubMsg; + ITypeInfo __RPC_FAR *pTypeInfo; + IUnknown __RPC_FAR *__RPC_FAR *ppv; + IID* riid = 0; + +NdrStubInitialize( + _pRpcMessage, + &_StubMsg, + &Object_StubDesc, + _pRpcChannelBuffer); + pTypeInfo = 0; + ppv = 0; + RpcTryFinally + { + if ( (_pRpcMessage->DataRepresentation & 0X0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION ) + NdrConvert( (PMIDL_STUB_MESSAGE) &_StubMsg, (PFORMAT_STRING) &__MIDL_ProcFormatString.Format[480] ); + + NdrInterfacePointerUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&pTypeInfo, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[10], + (unsigned char)0 ); + + NdrSimpleStructUnmarshall( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR * __RPC_FAR *)&riid, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[38], + (unsigned char)0 ); + + ppv = (void *)&_M101; + _M101 = 0; + + *_pdwStubPhase = STUB_CALL_SERVER; + _RetVal = (((ITypeFactory*) ((CStdStubBuffer *)This)->pvServerObject)->lpVtbl) -> CreateFromTypeInfo( + (ITypeFactory *) ((CStdStubBuffer *)This)->pvServerObject, + pTypeInfo, + riid, + ppv); + + *_pdwStubPhase = STUB_MARSHAL; + + _StubMsg.BufferLength = 0U + 4U; + _StubMsg.MaxCount = (unsigned long) ( riid ); + + NdrPointerBufferSize( (PMIDL_STUB_MESSAGE) &_StubMsg, + (unsigned char __RPC_FAR *)ppv, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1896] ); + + _StubMsg.BufferLength += 16; + + NdrStubGetBuffer(This, _pRpcChannelBuffer, &_StubMsg); + _StubMsg.MaxCount = (unsigned long) ( riid ); + + NdrPointerMarshall( (PMIDL_STUB_MESSAGE)& _StubMsg, + (unsigned char __RPC_FAR *)ppv, + (PFORMAT_STRING) &__MIDL_TypeFormatString.Format[1896] ); + + _StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~ 0x3); + *( HRESULT __RPC_FAR * )_StubMsg.Buffer = _RetVal; + _StubMsg.Buffer += sizeof(HRESULT); + + } + RpcFinally + { + NdrInterfacePointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)pTypeInfo, + &__MIDL_TypeFormatString.Format[10] ); + + _StubMsg.MaxCount = (unsigned long) ( riid ); + + NdrPointerFree( &_StubMsg, + (unsigned char __RPC_FAR *)ppv, + &__MIDL_TypeFormatString.Format[1896] ); + + } + RpcEndFinally + _pRpcMessage->BufferLength = + (unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer); + +} + +static const USER_MARSHAL_ROUTINE_QUADRUPLE UserMarshalRoutines[3] = + { + { + (USER_MARSHAL_SIZING_ROUTINE)VARIANT_UserSize, + (USER_MARSHAL_MARSHALLING_ROUTINE)VARIANT_UserMarshal, + (USER_MARSHAL_UNMARSHALLING_ROUTINE)VARIANT_UserUnmarshal, + (USER_MARSHAL_FREEING_ROUTINE)VARIANT_UserFree + }, + { + (USER_MARSHAL_SIZING_ROUTINE)BSTR_UserSize, + (USER_MARSHAL_MARSHALLING_ROUTINE)BSTR_UserMarshal, + (USER_MARSHAL_UNMARSHALLING_ROUTINE)BSTR_UserUnmarshal, + (USER_MARSHAL_FREEING_ROUTINE)BSTR_UserFree + }, + { + (USER_MARSHAL_SIZING_ROUTINE)CLEANLOCALSTORAGE_UserSize, + (USER_MARSHAL_MARSHALLING_ROUTINE)CLEANLOCALSTORAGE_UserMarshal, + (USER_MARSHAL_UNMARSHALLING_ROUTINE)CLEANLOCALSTORAGE_UserUnmarshal, + (USER_MARSHAL_FREEING_ROUTINE)CLEANLOCALSTORAGE_UserFree + } + + }; + +static const MIDL_STUB_DESC Object_StubDesc = + { + 0, + NdrOleAllocate, + NdrOleFree, + { 0 }, + 0, + 0, + 0, + 0, + __MIDL_TypeFormatString.Format, + 1, /* -error bounds_check flag */ + 0x20000, /* Ndr library version */ + 0, + 0x50100a4, /* MIDL Version 5.1.164 */ + 0, + UserMarshalRoutines, + 0, /* notify & notify_flag routine table */ + 1, /* Flags */ + 0, /* Reserved3 */ + 0, /* Reserved4 */ + 0 /* Reserved5 */ + }; + +const CINTERFACE_PROXY_VTABLE(4) _ITypeFactoryProxyVtbl = +{ + { &IID_ITypeFactory }, + { + IUnknown_QueryInterface_Proxy, + IUnknown_AddRef_Proxy, + IUnknown_Release_Proxy , + ITypeFactory_CreateFromTypeInfo_Proxy + } +}; + + +static const PRPC_STUB_FUNCTION ITypeFactory_table[] = +{ + ITypeFactory_CreateFromTypeInfo_Stub +}; + +const CInterfaceStubVtbl _ITypeFactoryStubVtbl = +{ + { + &IID_ITypeFactory, + 0, + 4, + &ITypeFactory_table[-3] + }, + { CStdStubBuffer_METHODS } +}; + + +/* Object interface: ITypeMarshal, ver. 0.0, + GUID={0x0000002D,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ + + +/* Object interface: IRecordInfo, ver. 0.0, + GUID={0x0000002F,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ + + +/* Object interface: ICreateTypeInfo, ver. 0.0, + GUID={0x00020405,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ + + +/* Object interface: ICreateTypeInfo2, ver. 0.0, + GUID={0x0002040E,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ + + +/* Object interface: ICreateTypeLib, ver. 0.0, + GUID={0x00020406,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ + + +/* Object interface: ICreateTypeLib2, ver. 0.0, + GUID={0x0002040F,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}} */ + +#if !defined(__RPC_WIN32__) +#error Invalid build platform for this stub. +#endif + +#if !(TARGET_IS_NT40_OR_LATER) +#error You need a Windows NT 4.0 or later to run this stub because it uses these features: +#error [wire_marshal] or [user_marshal] attribute. +#error However, your C/C++ compilation flags indicate you intend to run this app on earlier systems. +#error This app will die there with the RPC_X_WRONG_STUB_VERSION error. +#endif + + +static const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString = + { + 0, + { + + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 2 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ +/* 4 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 6 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 8 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 10 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 12 */ NdrFcShort( 0x6 ), /* Type Offset=6 */ +/* 14 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 16 */ + 0x4d, /* FC_IN_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 18 */ NdrFcShort( 0x1c ), /* Type Offset=28 */ +/* 20 */ + 0x4d, /* FC_IN_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 22 */ NdrFcShort( 0x32 ), /* Type Offset=50 */ +/* 24 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 26 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 28 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 30 */ NdrFcShort( 0x54 ), /* Type Offset=84 */ +/* 32 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 34 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 36 */ + 0x4d, /* FC_IN_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 38 */ NdrFcShort( 0x1c ), /* Type Offset=28 */ +/* 40 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 42 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 44 */ + 0x4d, /* FC_IN_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 46 */ NdrFcShort( 0x62 ), /* Type Offset=98 */ +/* 48 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 50 */ NdrFcShort( 0x44e ), /* Type Offset=1102 */ +/* 52 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 54 */ NdrFcShort( 0x460 ), /* Type Offset=1120 */ +/* 56 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 58 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ +/* 60 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 62 */ + 0x4d, /* FC_IN_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 64 */ NdrFcShort( 0x48e ), /* Type Offset=1166 */ +/* 66 */ + 0x50, /* FC_IN_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 68 */ NdrFcShort( 0x49c ), /* Type Offset=1180 */ +/* 70 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 72 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 74 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 76 */ NdrFcShort( 0x4b2 ), /* Type Offset=1202 */ +/* 78 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 80 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ +/* 82 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 84 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 86 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 88 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 90 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 92 */ NdrFcShort( 0x4c8 ), /* Type Offset=1224 */ +/* 94 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 96 */ + 0x4d, /* FC_IN_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 98 */ NdrFcShort( 0x4de ), /* Type Offset=1246 */ +/* 100 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 102 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x6, /* FC_SHORT */ +/* 104 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 106 */ NdrFcShort( 0x6 ), /* Type Offset=6 */ +/* 108 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 110 */ NdrFcShort( 0x4e2 ), /* Type Offset=1250 */ +/* 112 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 114 */ NdrFcShort( 0x4e6 ), /* Type Offset=1254 */ +/* 116 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 118 */ NdrFcShort( 0x5b8 ), /* Type Offset=1464 */ +/* 120 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 122 */ NdrFcShort( 0x604 ), /* Type Offset=1540 */ +/* 124 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 126 */ NdrFcShort( 0x61a ), /* Type Offset=1562 */ +/* 128 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 130 */ + 0x4d, /* FC_IN_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 132 */ NdrFcShort( 0x4de ), /* Type Offset=1246 */ +/* 134 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 136 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 138 */ NdrFcShort( 0x6 ), /* Type Offset=6 */ +/* 140 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 142 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 144 */ NdrFcShort( 0x62a ), /* Type Offset=1578 */ +/* 146 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 148 */ NdrFcShort( 0x666 ), /* Type Offset=1638 */ +/* 150 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 152 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 154 */ NdrFcShort( 0x604 ), /* Type Offset=1540 */ +/* 156 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 158 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 160 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 162 */ NdrFcShort( 0x4e6 ), /* Type Offset=1254 */ +/* 164 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 166 */ NdrFcShort( 0x676 ), /* Type Offset=1654 */ +/* 168 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 170 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 172 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 174 */ NdrFcShort( 0x5b8 ), /* Type Offset=1464 */ +/* 176 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 178 */ NdrFcShort( 0x686 ), /* Type Offset=1670 */ +/* 180 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 182 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 184 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 186 */ NdrFcShort( 0x696 ), /* Type Offset=1686 */ +/* 188 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 190 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 192 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ +/* 194 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 196 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 198 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 200 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ +/* 202 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 204 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 206 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 208 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 210 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ +/* 212 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 214 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ +/* 216 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 218 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ +/* 220 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 222 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ +/* 224 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 226 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 228 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0xe, /* FC_ENUM32 */ +/* 230 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 232 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 234 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ +/* 236 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 238 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ +/* 240 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 242 */ NdrFcShort( 0x6b0 ), /* Type Offset=1712 */ +/* 244 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 246 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 248 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 250 */ NdrFcShort( 0x6 ), /* Type Offset=6 */ +/* 252 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 254 */ + 0x4d, /* FC_IN_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 256 */ NdrFcShort( 0x1c ), /* Type Offset=28 */ +/* 258 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 260 */ NdrFcShort( 0x6b4 ), /* Type Offset=1716 */ +/* 262 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 264 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 266 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 268 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ +/* 270 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 272 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 274 */ NdrFcShort( 0x6be ), /* Type Offset=1726 */ +/* 276 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 278 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ +/* 280 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 282 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 284 */ NdrFcShort( 0x4e2 ), /* Type Offset=1250 */ +/* 286 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 288 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 290 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0xe, /* FC_ENUM32 */ +/* 292 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 294 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ +/* 296 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 298 */ + 0x4d, /* FC_IN_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 300 */ NdrFcShort( 0x1c ), /* Type Offset=28 */ +/* 302 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 304 */ NdrFcShort( 0x44e ), /* Type Offset=1102 */ +/* 306 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 308 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 310 */ + 0x4d, /* FC_IN_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 312 */ NdrFcShort( 0x1c ), /* Type Offset=28 */ +/* 314 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 316 */ NdrFcShort( 0x44e ), /* Type Offset=1102 */ +/* 318 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 320 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 322 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 324 */ + 0x4d, /* FC_IN_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 326 */ NdrFcShort( 0x1c ), /* Type Offset=28 */ +/* 328 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 330 */ NdrFcShort( 0x44e ), /* Type Offset=1102 */ +/* 332 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 334 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 336 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 338 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 340 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 342 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ +/* 344 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 346 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ +/* 348 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 350 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ +/* 352 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 354 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 356 */ NdrFcShort( 0x6d4 ), /* Type Offset=1748 */ +/* 358 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 360 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 362 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 364 */ NdrFcShort( 0x6d4 ), /* Type Offset=1748 */ +/* 366 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 368 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 370 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 372 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 374 */ NdrFcShort( 0x6d4 ), /* Type Offset=1748 */ +/* 376 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 378 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 380 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 382 */ NdrFcShort( 0x4e2 ), /* Type Offset=1250 */ +/* 384 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 386 */ + 0x4d, /* FC_IN_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 388 */ NdrFcShort( 0x1c ), /* Type Offset=28 */ +/* 390 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 392 */ NdrFcShort( 0x6 ), /* Type Offset=6 */ +/* 394 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 396 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 398 */ NdrFcShort( 0x70c ), /* Type Offset=1804 */ +/* 400 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 402 */ NdrFcShort( 0x728 ), /* Type Offset=1832 */ +/* 404 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 406 */ + 0x4d, /* FC_IN_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 408 */ NdrFcShort( 0x4de ), /* Type Offset=1246 */ +/* 410 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 412 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 414 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ +/* 416 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 418 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ +/* 420 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 422 */ + 0x4d, /* FC_IN_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 424 */ NdrFcShort( 0x4de ), /* Type Offset=1246 */ +/* 426 */ 0x4e, /* FC_IN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 428 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 430 */ NdrFcShort( 0x738 ), /* Type Offset=1848 */ +/* 432 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 434 */ NdrFcShort( 0x74e ), /* Type Offset=1870 */ +/* 436 */ + 0x50, /* FC_IN_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 438 */ NdrFcShort( 0x760 ), /* Type Offset=1888 */ +/* 440 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 442 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ +/* 444 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 446 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 448 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ +/* 450 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 452 */ NdrFcShort( 0x2 ), /* Type Offset=2 */ +/* 454 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 456 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 458 */ NdrFcShort( 0x764 ), /* Type Offset=1892 */ +/* 460 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 462 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 464 */ NdrFcShort( 0x6ac ), /* Type Offset=1708 */ +/* 466 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 468 */ + 0x4d, /* FC_IN_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 470 */ NdrFcShort( 0x1c ), /* Type Offset=28 */ +/* 472 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 474 */ + 0x4d, /* FC_IN_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 476 */ NdrFcShort( 0x4de ), /* Type Offset=1246 */ +/* 478 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ +/* 480 */ + 0x4d, /* FC_IN_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 482 */ NdrFcShort( 0xa ), /* Type Offset=10 */ +/* 484 */ + 0x4d, /* FC_IN_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 486 */ NdrFcShort( 0x1c ), /* Type Offset=28 */ +/* 488 */ + 0x51, /* FC_OUT_PARAM */ +#ifndef _ALPHA_ + 0x1, /* x86, MIPS & PPC Stack size = 1 */ +#else + 0x2, /* Alpha Stack size = 2 */ +#endif +/* 490 */ NdrFcShort( 0x768 ), /* Type Offset=1896 */ +/* 492 */ 0x53, /* FC_RETURN_PARAM_BASETYPE */ + 0x8, /* FC_LONG */ + + 0x0 + } + }; + +static const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString = + { + 0, + { + NdrFcShort( 0x0 ), /* 0 */ +/* 2 */ + 0x11, 0xc, /* FC_RP [alloced_on_stack] [simple_pointer] */ +/* 4 */ 0x8, /* FC_LONG */ + 0x5c, /* FC_PAD */ +/* 6 */ + 0x11, 0x14, /* FC_RP [alloced_on_stack] */ +/* 8 */ NdrFcShort( 0x2 ), /* Offset= 2 (10) */ +/* 10 */ + 0x2f, /* FC_IP */ + 0x5a, /* FC_CONSTANT_IID */ +/* 12 */ NdrFcLong( 0x20401 ), /* 132097 */ +/* 16 */ NdrFcShort( 0x0 ), /* 0 */ +/* 18 */ NdrFcShort( 0x0 ), /* 0 */ +/* 20 */ 0xc0, /* 192 */ + 0x0, /* 0 */ +/* 22 */ 0x0, /* 0 */ + 0x0, /* 0 */ +/* 24 */ 0x0, /* 0 */ + 0x0, /* 0 */ +/* 26 */ 0x0, /* 0 */ + 0x46, /* 70 */ +/* 28 */ + 0x11, 0x0, /* FC_RP */ +/* 30 */ NdrFcShort( 0x8 ), /* Offset= 8 (38) */ +/* 32 */ + 0x1d, /* FC_SMFARRAY */ + 0x0, /* 0 */ +/* 34 */ NdrFcShort( 0x8 ), /* 8 */ +/* 36 */ 0x2, /* FC_CHAR */ + 0x5b, /* FC_END */ +/* 38 */ + 0x15, /* FC_STRUCT */ + 0x3, /* 3 */ +/* 40 */ NdrFcShort( 0x10 ), /* 16 */ +/* 42 */ 0x8, /* FC_LONG */ + 0x6, /* FC_SHORT */ +/* 44 */ 0x6, /* FC_SHORT */ + 0x4c, /* FC_EMBEDDED_COMPLEX */ +/* 46 */ 0x0, /* 0 */ + NdrFcShort( 0xfffffff1 ), /* Offset= -15 (32) */ + 0x5b, /* FC_END */ +/* 50 */ + 0x11, 0x0, /* FC_RP */ +/* 52 */ NdrFcShort( 0x2 ), /* Offset= 2 (54) */ +/* 54 */ + 0x1b, /* FC_CARRAY */ + 0x3, /* 3 */ +/* 56 */ NdrFcShort( 0x4 ), /* 4 */ +/* 58 */ 0x29, /* Corr desc: parameter, FC_ULONG */ + 0x0, /* */ +#ifndef _ALPHA_ +/* 60 */ NdrFcShort( 0xc ), /* x86, MIPS, PPC Stack size/offset = 12 */ +#else + NdrFcShort( 0x18 ), /* Alpha Stack size/offset = 24 */ +#endif +/* 62 */ + 0x4b, /* FC_PP */ + 0x5c, /* FC_PAD */ +/* 64 */ + 0x48, /* FC_VARIABLE_REPEAT */ + 0x49, /* FC_FIXED_OFFSET */ +/* 66 */ NdrFcShort( 0x4 ), /* 4 */ +/* 68 */ NdrFcShort( 0x0 ), /* 0 */ +/* 70 */ NdrFcShort( 0x1 ), /* 1 */ +/* 72 */ NdrFcShort( 0x0 ), /* 0 */ +/* 74 */ NdrFcShort( 0x0 ), /* 0 */ +/* 76 */ 0x12, 0x8, /* FC_UP [simple_pointer] */ +/* 78 */ + 0x25, /* FC_C_WSTRING */ + 0x5c, /* FC_PAD */ +/* 80 */ + 0x5b, /* FC_END */ + + 0x8, /* FC_LONG */ +/* 82 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 84 */ + 0x11, 0x0, /* FC_RP */ +/* 86 */ NdrFcShort( 0x2 ), /* Offset= 2 (88) */ +/* 88 */ + 0x1b, /* FC_CARRAY */ + 0x3, /* 3 */ +/* 90 */ NdrFcShort( 0x4 ), /* 4 */ +/* 92 */ 0x29, /* Corr desc: parameter, FC_ULONG */ + 0x0, /* */ +#ifndef _ALPHA_ +/* 94 */ NdrFcShort( 0xc ), /* x86, MIPS, PPC Stack size/offset = 12 */ +#else + NdrFcShort( 0x18 ), /* Alpha Stack size/offset = 24 */ +#endif +/* 96 */ 0x8, /* FC_LONG */ + 0x5b, /* FC_END */ +/* 98 */ + 0x11, 0x0, /* FC_RP */ +/* 100 */ NdrFcShort( 0x3d4 ), /* Offset= 980 (1080) */ +/* 102 */ + 0x12, 0x0, /* FC_UP */ +/* 104 */ NdrFcShort( 0x396 ), /* Offset= 918 (1022) */ +/* 106 */ + 0x2b, /* FC_NON_ENCAPSULATED_UNION */ + 0x7, /* FC_USHORT */ +/* 108 */ 0x7, /* Corr desc: FC_USHORT */ + 0x0, /* */ +/* 110 */ NdrFcShort( 0xfff8 ), /* -8 */ +/* 112 */ NdrFcShort( 0x2 ), /* Offset= 2 (114) */ +/* 114 */ NdrFcShort( 0x10 ), /* 16 */ +/* 116 */ NdrFcShort( 0x2b ), /* 43 */ +/* 118 */ NdrFcLong( 0x0 ), /* 0 */ +/* 122 */ NdrFcShort( 0x0 ), /* Offset= 0 (122) */ +/* 124 */ NdrFcLong( 0x1 ), /* 1 */ +/* 128 */ NdrFcShort( 0x0 ), /* Offset= 0 (128) */ +/* 130 */ NdrFcLong( 0x10 ), /* 16 */ +/* 134 */ NdrFcShort( 0x8002 ), /* Simple arm type: FC_CHAR */ +/* 136 */ NdrFcLong( 0x12 ), /* 18 */ +/* 140 */ NdrFcShort( 0x8006 ), /* Simple arm type: FC_SHORT */ +/* 142 */ NdrFcLong( 0x13 ), /* 19 */ +/* 146 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ +/* 148 */ NdrFcLong( 0x16 ), /* 22 */ +/* 152 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ +/* 154 */ NdrFcLong( 0x17 ), /* 23 */ +/* 158 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ +/* 160 */ NdrFcLong( 0x11 ), /* 17 */ +/* 164 */ NdrFcShort( 0x8002 ), /* Simple arm type: FC_CHAR */ +/* 166 */ NdrFcLong( 0x2 ), /* 2 */ +/* 170 */ NdrFcShort( 0x8006 ), /* Simple arm type: FC_SHORT */ +/* 172 */ NdrFcLong( 0x3 ), /* 3 */ +/* 176 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ +/* 178 */ NdrFcLong( 0x4 ), /* 4 */ +/* 182 */ NdrFcShort( 0x800a ), /* Simple arm type: FC_FLOAT */ +/* 184 */ NdrFcLong( 0x5 ), /* 5 */ +/* 188 */ NdrFcShort( 0x800c ), /* Simple arm type: FC_DOUBLE */ +/* 190 */ NdrFcLong( 0xb ), /* 11 */ +/* 194 */ NdrFcShort( 0x8006 ), /* Simple arm type: FC_SHORT */ +/* 196 */ NdrFcLong( 0xa ), /* 10 */ +/* 200 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ +/* 202 */ NdrFcLong( 0x7 ), /* 7 */ +/* 206 */ NdrFcShort( 0x800c ), /* Simple arm type: FC_DOUBLE */ +/* 208 */ NdrFcLong( 0x8 ), /* 8 */ +/* 212 */ NdrFcShort( 0xa6 ), /* Offset= 166 (378) */ +/* 214 */ NdrFcLong( 0x6 ), /* 6 */ +/* 218 */ NdrFcShort( 0xb8 ), /* Offset= 184 (402) */ +/* 220 */ NdrFcLong( 0xe ), /* 14 */ +/* 224 */ NdrFcShort( 0xb8 ), /* Offset= 184 (408) */ +/* 226 */ NdrFcLong( 0xd ), /* 13 */ +/* 230 */ NdrFcShort( 0xbe ), /* Offset= 190 (420) */ +/* 232 */ NdrFcLong( 0x9 ), /* 9 */ +/* 236 */ NdrFcShort( 0xca ), /* Offset= 202 (438) */ +/* 238 */ NdrFcLong( 0x2000 ), /* 8192 */ +/* 242 */ NdrFcShort( 0xd6 ), /* Offset= 214 (456) */ +/* 244 */ NdrFcLong( 0x4010 ), /* 16400 */ +/* 248 */ NdrFcShort( 0x2ce ), /* Offset= 718 (966) */ +/* 250 */ NdrFcLong( 0x4012 ), /* 16402 */ +/* 254 */ NdrFcShort( 0x2cc ), /* Offset= 716 (970) */ +/* 256 */ NdrFcLong( 0x4013 ), /* 16403 */ +/* 260 */ NdrFcShort( 0x2ca ), /* Offset= 714 (974) */ +/* 262 */ NdrFcLong( 0x4016 ), /* 16406 */ +/* 266 */ NdrFcShort( 0x2c4 ), /* Offset= 708 (974) */ +/* 268 */ NdrFcLong( 0x4017 ), /* 16407 */ +/* 272 */ NdrFcShort( 0x2be ), /* Offset= 702 (974) */ +/* 274 */ NdrFcLong( 0x4011 ), /* 16401 */ +/* 278 */ NdrFcShort( 0x2b0 ), /* Offset= 688 (966) */ +/* 280 */ NdrFcLong( 0x4002 ), /* 16386 */ +/* 284 */ NdrFcShort( 0x2ae ), /* Offset= 686 (970) */ +/* 286 */ NdrFcLong( 0x4003 ), /* 16387 */ +/* 290 */ NdrFcShort( 0x2ac ), /* Offset= 684 (974) */ +/* 292 */ NdrFcLong( 0x4004 ), /* 16388 */ +/* 296 */ NdrFcShort( 0x2aa ), /* Offset= 682 (978) */ +/* 298 */ NdrFcLong( 0x4005 ), /* 16389 */ +/* 302 */ NdrFcShort( 0x2a8 ), /* Offset= 680 (982) */ +/* 304 */ NdrFcLong( 0x400b ), /* 16395 */ +/* 308 */ NdrFcShort( 0x296 ), /* Offset= 662 (970) */ +/* 310 */ NdrFcLong( 0x400a ), /* 16394 */ +/* 314 */ NdrFcShort( 0x294 ), /* Offset= 660 (974) */ +/* 316 */ NdrFcLong( 0x4007 ), /* 16391 */ +/* 320 */ NdrFcShort( 0x296 ), /* Offset= 662 (982) */ +/* 322 */ NdrFcLong( 0x4008 ), /* 16392 */ +/* 326 */ NdrFcShort( 0x294 ), /* Offset= 660 (986) */ +/* 328 */ NdrFcLong( 0x400c ), /* 16396 */ +/* 332 */ NdrFcShort( 0x292 ), /* Offset= 658 (990) */ +/* 334 */ NdrFcLong( 0x4006 ), /* 16390 */ +/* 338 */ NdrFcShort( 0x294 ), /* Offset= 660 (998) */ +/* 340 */ NdrFcLong( 0x400e ), /* 16398 */ +/* 344 */ NdrFcShort( 0x292 ), /* Offset= 658 (1002) */ +/* 346 */ NdrFcLong( 0x400d ), /* 16397 */ +/* 350 */ NdrFcShort( 0x290 ), /* Offset= 656 (1006) */ +/* 352 */ NdrFcLong( 0x4009 ), /* 16393 */ +/* 356 */ NdrFcShort( 0x28e ), /* Offset= 654 (1010) */ +/* 358 */ NdrFcLong( 0x6000 ), /* 24576 */ +/* 362 */ NdrFcShort( 0x28c ), /* Offset= 652 (1014) */ +/* 364 */ NdrFcLong( 0x24 ), /* 36 */ +/* 368 */ NdrFcShort( 0x28a ), /* Offset= 650 (1018) */ +/* 370 */ NdrFcLong( 0x4024 ), /* 16420 */ +/* 374 */ NdrFcShort( 0x284 ), /* Offset= 644 (1018) */ +/* 376 */ NdrFcShort( 0xffffffff ), /* Offset= -1 (375) */ +/* 378 */ + 0x12, 0x0, /* FC_UP */ +/* 380 */ NdrFcShort( 0xc ), /* Offset= 12 (392) */ +/* 382 */ + 0x1b, /* FC_CARRAY */ + 0x1, /* 1 */ +/* 384 */ NdrFcShort( 0x2 ), /* 2 */ +/* 386 */ 0x9, /* Corr desc: FC_ULONG */ + 0x0, /* */ +/* 388 */ NdrFcShort( 0xfffc ), /* -4 */ +/* 390 */ 0x6, /* FC_SHORT */ + 0x5b, /* FC_END */ +/* 392 */ + 0x17, /* FC_CSTRUCT */ + 0x3, /* 3 */ +/* 394 */ NdrFcShort( 0x8 ), /* 8 */ +/* 396 */ NdrFcShort( 0xfffffff2 ), /* Offset= -14 (382) */ +/* 398 */ 0x8, /* FC_LONG */ + 0x8, /* FC_LONG */ +/* 400 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 402 */ + 0x15, /* FC_STRUCT */ + 0x7, /* 7 */ +/* 404 */ NdrFcShort( 0x8 ), /* 8 */ +/* 406 */ 0xb, /* FC_HYPER */ + 0x5b, /* FC_END */ +/* 408 */ + 0x15, /* FC_STRUCT */ + 0x7, /* 7 */ +/* 410 */ NdrFcShort( 0x10 ), /* 16 */ +/* 412 */ 0x6, /* FC_SHORT */ + 0x2, /* FC_CHAR */ +/* 414 */ 0x2, /* FC_CHAR */ + 0x38, /* FC_ALIGNM4 */ +/* 416 */ 0x8, /* FC_LONG */ + 0x39, /* FC_ALIGNM8 */ +/* 418 */ 0xb, /* FC_HYPER */ + 0x5b, /* FC_END */ +/* 420 */ + 0x2f, /* FC_IP */ + 0x5a, /* FC_CONSTANT_IID */ +/* 422 */ NdrFcLong( 0x0 ), /* 0 */ +/* 426 */ NdrFcShort( 0x0 ), /* 0 */ +/* 428 */ NdrFcShort( 0x0 ), /* 0 */ +/* 430 */ 0xc0, /* 192 */ + 0x0, /* 0 */ +/* 432 */ 0x0, /* 0 */ + 0x0, /* 0 */ +/* 434 */ 0x0, /* 0 */ + 0x0, /* 0 */ +/* 436 */ 0x0, /* 0 */ + 0x46, /* 70 */ +/* 438 */ + 0x2f, /* FC_IP */ + 0x5a, /* FC_CONSTANT_IID */ +/* 440 */ NdrFcLong( 0x20400 ), /* 132096 */ +/* 444 */ NdrFcShort( 0x0 ), /* 0 */ +/* 446 */ NdrFcShort( 0x0 ), /* 0 */ +/* 448 */ 0xc0, /* 192 */ + 0x0, /* 0 */ +/* 450 */ 0x0, /* 0 */ + 0x0, /* 0 */ +/* 452 */ 0x0, /* 0 */ + 0x0, /* 0 */ +/* 454 */ 0x0, /* 0 */ + 0x46, /* 70 */ +/* 456 */ + 0x12, 0x0, /* FC_UP */ +/* 458 */ NdrFcShort( 0x1ea ), /* Offset= 490 (948) */ +/* 460 */ + 0x2a, /* FC_ENCAPSULATED_UNION */ + 0x49, /* 73 */ +/* 462 */ NdrFcShort( 0x18 ), /* 24 */ +/* 464 */ NdrFcShort( 0xa ), /* 10 */ +/* 466 */ NdrFcLong( 0x8 ), /* 8 */ +/* 470 */ NdrFcShort( 0x58 ), /* Offset= 88 (558) */ +/* 472 */ NdrFcLong( 0xd ), /* 13 */ +/* 476 */ NdrFcShort( 0x78 ), /* Offset= 120 (596) */ +/* 478 */ NdrFcLong( 0x9 ), /* 9 */ +/* 482 */ NdrFcShort( 0x94 ), /* Offset= 148 (630) */ +/* 484 */ NdrFcLong( 0xc ), /* 12 */ +/* 488 */ NdrFcShort( 0xbc ), /* Offset= 188 (676) */ +/* 490 */ NdrFcLong( 0x24 ), /* 36 */ +/* 494 */ NdrFcShort( 0x114 ), /* Offset= 276 (770) */ +/* 496 */ NdrFcLong( 0x800d ), /* 32781 */ +/* 500 */ NdrFcShort( 0x11e ), /* Offset= 286 (786) */ +/* 502 */ NdrFcLong( 0x10 ), /* 16 */ +/* 506 */ NdrFcShort( 0x136 ), /* Offset= 310 (816) */ +/* 508 */ NdrFcLong( 0x2 ), /* 2 */ +/* 512 */ NdrFcShort( 0x14e ), /* Offset= 334 (846) */ +/* 514 */ NdrFcLong( 0x3 ), /* 3 */ +/* 518 */ NdrFcShort( 0x166 ), /* Offset= 358 (876) */ +/* 520 */ NdrFcLong( 0x14 ), /* 20 */ +/* 524 */ NdrFcShort( 0x17e ), /* Offset= 382 (906) */ +/* 526 */ NdrFcShort( 0xffffffff ), /* Offset= -1 (525) */ +/* 528 */ + 0x1b, /* FC_CARRAY */ + 0x3, /* 3 */ +/* 530 */ NdrFcShort( 0x4 ), /* 4 */ +/* 532 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 534 */ NdrFcShort( 0x0 ), /* 0 */ +/* 536 */ + 0x4b, /* FC_PP */ + 0x5c, /* FC_PAD */ +/* 538 */ + 0x48, /* FC_VARIABLE_REPEAT */ + 0x49, /* FC_FIXED_OFFSET */ +/* 540 */ NdrFcShort( 0x4 ), /* 4 */ +/* 542 */ NdrFcShort( 0x0 ), /* 0 */ +/* 544 */ NdrFcShort( 0x1 ), /* 1 */ +/* 546 */ NdrFcShort( 0x0 ), /* 0 */ +/* 548 */ NdrFcShort( 0x0 ), /* 0 */ +/* 550 */ 0x12, 0x0, /* FC_UP */ +/* 552 */ NdrFcShort( 0xffffff60 ), /* Offset= -160 (392) */ +/* 554 */ + 0x5b, /* FC_END */ + + 0x8, /* FC_LONG */ +/* 556 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 558 */ + 0x16, /* FC_PSTRUCT */ + 0x3, /* 3 */ +/* 560 */ NdrFcShort( 0x8 ), /* 8 */ +/* 562 */ + 0x4b, /* FC_PP */ + 0x5c, /* FC_PAD */ +/* 564 */ + 0x46, /* FC_NO_REPEAT */ + 0x5c, /* FC_PAD */ +/* 566 */ NdrFcShort( 0x4 ), /* 4 */ +/* 568 */ NdrFcShort( 0x4 ), /* 4 */ +/* 570 */ 0x11, 0x0, /* FC_RP */ +/* 572 */ NdrFcShort( 0xffffffd4 ), /* Offset= -44 (528) */ +/* 574 */ + 0x5b, /* FC_END */ + + 0x8, /* FC_LONG */ +/* 576 */ 0x8, /* FC_LONG */ + 0x5b, /* FC_END */ +/* 578 */ + 0x21, /* FC_BOGUS_ARRAY */ + 0x3, /* 3 */ +/* 580 */ NdrFcShort( 0x0 ), /* 0 */ +/* 582 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 584 */ NdrFcShort( 0x0 ), /* 0 */ +/* 586 */ NdrFcLong( 0xffffffff ), /* -1 */ +/* 590 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 592 */ NdrFcShort( 0xffffff54 ), /* Offset= -172 (420) */ +/* 594 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 596 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 598 */ NdrFcShort( 0x8 ), /* 8 */ +/* 600 */ NdrFcShort( 0x0 ), /* 0 */ +/* 602 */ NdrFcShort( 0x6 ), /* Offset= 6 (608) */ +/* 604 */ 0x8, /* FC_LONG */ + 0x36, /* FC_POINTER */ +/* 606 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 608 */ + 0x11, 0x0, /* FC_RP */ +/* 610 */ NdrFcShort( 0xffffffe0 ), /* Offset= -32 (578) */ +/* 612 */ + 0x21, /* FC_BOGUS_ARRAY */ + 0x3, /* 3 */ +/* 614 */ NdrFcShort( 0x0 ), /* 0 */ +/* 616 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 618 */ NdrFcShort( 0x0 ), /* 0 */ +/* 620 */ NdrFcLong( 0xffffffff ), /* -1 */ +/* 624 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 626 */ NdrFcShort( 0xffffff44 ), /* Offset= -188 (438) */ +/* 628 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 630 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 632 */ NdrFcShort( 0x8 ), /* 8 */ +/* 634 */ NdrFcShort( 0x0 ), /* 0 */ +/* 636 */ NdrFcShort( 0x6 ), /* Offset= 6 (642) */ +/* 638 */ 0x8, /* FC_LONG */ + 0x36, /* FC_POINTER */ +/* 640 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 642 */ + 0x11, 0x0, /* FC_RP */ +/* 644 */ NdrFcShort( 0xffffffe0 ), /* Offset= -32 (612) */ +/* 646 */ + 0x1b, /* FC_CARRAY */ + 0x3, /* 3 */ +/* 648 */ NdrFcShort( 0x4 ), /* 4 */ +/* 650 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 652 */ NdrFcShort( 0x0 ), /* 0 */ +/* 654 */ + 0x4b, /* FC_PP */ + 0x5c, /* FC_PAD */ +/* 656 */ + 0x48, /* FC_VARIABLE_REPEAT */ + 0x49, /* FC_FIXED_OFFSET */ +/* 658 */ NdrFcShort( 0x4 ), /* 4 */ +/* 660 */ NdrFcShort( 0x0 ), /* 0 */ +/* 662 */ NdrFcShort( 0x1 ), /* 1 */ +/* 664 */ NdrFcShort( 0x0 ), /* 0 */ +/* 666 */ NdrFcShort( 0x0 ), /* 0 */ +/* 668 */ 0x12, 0x0, /* FC_UP */ +/* 670 */ NdrFcShort( 0x160 ), /* Offset= 352 (1022) */ +/* 672 */ + 0x5b, /* FC_END */ + + 0x8, /* FC_LONG */ +/* 674 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 676 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 678 */ NdrFcShort( 0x8 ), /* 8 */ +/* 680 */ NdrFcShort( 0x0 ), /* 0 */ +/* 682 */ NdrFcShort( 0x6 ), /* Offset= 6 (688) */ +/* 684 */ 0x8, /* FC_LONG */ + 0x36, /* FC_POINTER */ +/* 686 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 688 */ + 0x11, 0x0, /* FC_RP */ +/* 690 */ NdrFcShort( 0xffffffd4 ), /* Offset= -44 (646) */ +/* 692 */ + 0x2f, /* FC_IP */ + 0x5a, /* FC_CONSTANT_IID */ +/* 694 */ NdrFcLong( 0x2f ), /* 47 */ +/* 698 */ NdrFcShort( 0x0 ), /* 0 */ +/* 700 */ NdrFcShort( 0x0 ), /* 0 */ +/* 702 */ 0xc0, /* 192 */ + 0x0, /* 0 */ +/* 704 */ 0x0, /* 0 */ + 0x0, /* 0 */ +/* 706 */ 0x0, /* 0 */ + 0x0, /* 0 */ +/* 708 */ 0x0, /* 0 */ + 0x46, /* 70 */ +/* 710 */ + 0x1b, /* FC_CARRAY */ + 0x0, /* 0 */ +/* 712 */ NdrFcShort( 0x1 ), /* 1 */ +/* 714 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 716 */ NdrFcShort( 0x4 ), /* 4 */ +/* 718 */ 0x1, /* FC_BYTE */ + 0x5b, /* FC_END */ +/* 720 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 722 */ NdrFcShort( 0x10 ), /* 16 */ +/* 724 */ NdrFcShort( 0x0 ), /* 0 */ +/* 726 */ NdrFcShort( 0xa ), /* Offset= 10 (736) */ +/* 728 */ 0x8, /* FC_LONG */ + 0x8, /* FC_LONG */ +/* 730 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 732 */ NdrFcShort( 0xffffffd8 ), /* Offset= -40 (692) */ +/* 734 */ 0x36, /* FC_POINTER */ + 0x5b, /* FC_END */ +/* 736 */ + 0x12, 0x0, /* FC_UP */ +/* 738 */ NdrFcShort( 0xffffffe4 ), /* Offset= -28 (710) */ +/* 740 */ + 0x1b, /* FC_CARRAY */ + 0x3, /* 3 */ +/* 742 */ NdrFcShort( 0x4 ), /* 4 */ +/* 744 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 746 */ NdrFcShort( 0x0 ), /* 0 */ +/* 748 */ + 0x4b, /* FC_PP */ + 0x5c, /* FC_PAD */ +/* 750 */ + 0x48, /* FC_VARIABLE_REPEAT */ + 0x49, /* FC_FIXED_OFFSET */ +/* 752 */ NdrFcShort( 0x4 ), /* 4 */ +/* 754 */ NdrFcShort( 0x0 ), /* 0 */ +/* 756 */ NdrFcShort( 0x1 ), /* 1 */ +/* 758 */ NdrFcShort( 0x0 ), /* 0 */ +/* 760 */ NdrFcShort( 0x0 ), /* 0 */ +/* 762 */ 0x12, 0x0, /* FC_UP */ +/* 764 */ NdrFcShort( 0xffffffd4 ), /* Offset= -44 (720) */ +/* 766 */ + 0x5b, /* FC_END */ + + 0x8, /* FC_LONG */ +/* 768 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 770 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 772 */ NdrFcShort( 0x8 ), /* 8 */ +/* 774 */ NdrFcShort( 0x0 ), /* 0 */ +/* 776 */ NdrFcShort( 0x6 ), /* Offset= 6 (782) */ +/* 778 */ 0x8, /* FC_LONG */ + 0x36, /* FC_POINTER */ +/* 780 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 782 */ + 0x11, 0x0, /* FC_RP */ +/* 784 */ NdrFcShort( 0xffffffd4 ), /* Offset= -44 (740) */ +/* 786 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 788 */ NdrFcShort( 0x18 ), /* 24 */ +/* 790 */ NdrFcShort( 0x0 ), /* 0 */ +/* 792 */ NdrFcShort( 0xa ), /* Offset= 10 (802) */ +/* 794 */ 0x8, /* FC_LONG */ + 0x36, /* FC_POINTER */ +/* 796 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 798 */ NdrFcShort( 0xfffffd08 ), /* Offset= -760 (38) */ +/* 800 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 802 */ + 0x11, 0x0, /* FC_RP */ +/* 804 */ NdrFcShort( 0xffffff1e ), /* Offset= -226 (578) */ +/* 806 */ + 0x1b, /* FC_CARRAY */ + 0x0, /* 0 */ +/* 808 */ NdrFcShort( 0x1 ), /* 1 */ +/* 810 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 812 */ NdrFcShort( 0x0 ), /* 0 */ +/* 814 */ 0x1, /* FC_BYTE */ + 0x5b, /* FC_END */ +/* 816 */ + 0x16, /* FC_PSTRUCT */ + 0x3, /* 3 */ +/* 818 */ NdrFcShort( 0x8 ), /* 8 */ +/* 820 */ + 0x4b, /* FC_PP */ + 0x5c, /* FC_PAD */ +/* 822 */ + 0x46, /* FC_NO_REPEAT */ + 0x5c, /* FC_PAD */ +/* 824 */ NdrFcShort( 0x4 ), /* 4 */ +/* 826 */ NdrFcShort( 0x4 ), /* 4 */ +/* 828 */ 0x12, 0x0, /* FC_UP */ +/* 830 */ NdrFcShort( 0xffffffe8 ), /* Offset= -24 (806) */ +/* 832 */ + 0x5b, /* FC_END */ + + 0x8, /* FC_LONG */ +/* 834 */ 0x8, /* FC_LONG */ + 0x5b, /* FC_END */ +/* 836 */ + 0x1b, /* FC_CARRAY */ + 0x1, /* 1 */ +/* 838 */ NdrFcShort( 0x2 ), /* 2 */ +/* 840 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 842 */ NdrFcShort( 0x0 ), /* 0 */ +/* 844 */ 0x6, /* FC_SHORT */ + 0x5b, /* FC_END */ +/* 846 */ + 0x16, /* FC_PSTRUCT */ + 0x3, /* 3 */ +/* 848 */ NdrFcShort( 0x8 ), /* 8 */ +/* 850 */ + 0x4b, /* FC_PP */ + 0x5c, /* FC_PAD */ +/* 852 */ + 0x46, /* FC_NO_REPEAT */ + 0x5c, /* FC_PAD */ +/* 854 */ NdrFcShort( 0x4 ), /* 4 */ +/* 856 */ NdrFcShort( 0x4 ), /* 4 */ +/* 858 */ 0x12, 0x0, /* FC_UP */ +/* 860 */ NdrFcShort( 0xffffffe8 ), /* Offset= -24 (836) */ +/* 862 */ + 0x5b, /* FC_END */ + + 0x8, /* FC_LONG */ +/* 864 */ 0x8, /* FC_LONG */ + 0x5b, /* FC_END */ +/* 866 */ + 0x1b, /* FC_CARRAY */ + 0x3, /* 3 */ +/* 868 */ NdrFcShort( 0x4 ), /* 4 */ +/* 870 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 872 */ NdrFcShort( 0x0 ), /* 0 */ +/* 874 */ 0x8, /* FC_LONG */ + 0x5b, /* FC_END */ +/* 876 */ + 0x16, /* FC_PSTRUCT */ + 0x3, /* 3 */ +/* 878 */ NdrFcShort( 0x8 ), /* 8 */ +/* 880 */ + 0x4b, /* FC_PP */ + 0x5c, /* FC_PAD */ +/* 882 */ + 0x46, /* FC_NO_REPEAT */ + 0x5c, /* FC_PAD */ +/* 884 */ NdrFcShort( 0x4 ), /* 4 */ +/* 886 */ NdrFcShort( 0x4 ), /* 4 */ +/* 888 */ 0x12, 0x0, /* FC_UP */ +/* 890 */ NdrFcShort( 0xffffffe8 ), /* Offset= -24 (866) */ +/* 892 */ + 0x5b, /* FC_END */ + + 0x8, /* FC_LONG */ +/* 894 */ 0x8, /* FC_LONG */ + 0x5b, /* FC_END */ +/* 896 */ + 0x1b, /* FC_CARRAY */ + 0x7, /* 7 */ +/* 898 */ NdrFcShort( 0x8 ), /* 8 */ +/* 900 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 902 */ NdrFcShort( 0x0 ), /* 0 */ +/* 904 */ 0xb, /* FC_HYPER */ + 0x5b, /* FC_END */ +/* 906 */ + 0x16, /* FC_PSTRUCT */ + 0x3, /* 3 */ +/* 908 */ NdrFcShort( 0x8 ), /* 8 */ +/* 910 */ + 0x4b, /* FC_PP */ + 0x5c, /* FC_PAD */ +/* 912 */ + 0x46, /* FC_NO_REPEAT */ + 0x5c, /* FC_PAD */ +/* 914 */ NdrFcShort( 0x4 ), /* 4 */ +/* 916 */ NdrFcShort( 0x4 ), /* 4 */ +/* 918 */ 0x12, 0x0, /* FC_UP */ +/* 920 */ NdrFcShort( 0xffffffe8 ), /* Offset= -24 (896) */ +/* 922 */ + 0x5b, /* FC_END */ + + 0x8, /* FC_LONG */ +/* 924 */ 0x8, /* FC_LONG */ + 0x5b, /* FC_END */ +/* 926 */ + 0x15, /* FC_STRUCT */ + 0x3, /* 3 */ +/* 928 */ NdrFcShort( 0x8 ), /* 8 */ +/* 930 */ 0x8, /* FC_LONG */ + 0x8, /* FC_LONG */ +/* 932 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 934 */ + 0x1b, /* FC_CARRAY */ + 0x3, /* 3 */ +/* 936 */ NdrFcShort( 0x8 ), /* 8 */ +/* 938 */ 0x7, /* Corr desc: FC_USHORT */ + 0x0, /* */ +/* 940 */ NdrFcShort( 0xffd8 ), /* -40 */ +/* 942 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 944 */ NdrFcShort( 0xffffffee ), /* Offset= -18 (926) */ +/* 946 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 948 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 950 */ NdrFcShort( 0x28 ), /* 40 */ +/* 952 */ NdrFcShort( 0xffffffee ), /* Offset= -18 (934) */ +/* 954 */ NdrFcShort( 0x0 ), /* Offset= 0 (954) */ +/* 956 */ 0x6, /* FC_SHORT */ + 0x6, /* FC_SHORT */ +/* 958 */ 0x38, /* FC_ALIGNM4 */ + 0x8, /* FC_LONG */ +/* 960 */ 0x8, /* FC_LONG */ + 0x4c, /* FC_EMBEDDED_COMPLEX */ +/* 962 */ 0x0, /* 0 */ + NdrFcShort( 0xfffffe09 ), /* Offset= -503 (460) */ + 0x5b, /* FC_END */ +/* 966 */ + 0x12, 0x8, /* FC_UP [simple_pointer] */ +/* 968 */ 0x2, /* FC_CHAR */ + 0x5c, /* FC_PAD */ +/* 970 */ + 0x12, 0x8, /* FC_UP [simple_pointer] */ +/* 972 */ 0x6, /* FC_SHORT */ + 0x5c, /* FC_PAD */ +/* 974 */ + 0x12, 0x8, /* FC_UP [simple_pointer] */ +/* 976 */ 0x8, /* FC_LONG */ + 0x5c, /* FC_PAD */ +/* 978 */ + 0x12, 0x8, /* FC_UP [simple_pointer] */ +/* 980 */ 0xa, /* FC_FLOAT */ + 0x5c, /* FC_PAD */ +/* 982 */ + 0x12, 0x8, /* FC_UP [simple_pointer] */ +/* 984 */ 0xc, /* FC_DOUBLE */ + 0x5c, /* FC_PAD */ +/* 986 */ + 0x12, 0x10, /* FC_UP */ +/* 988 */ NdrFcShort( 0xfffffd9e ), /* Offset= -610 (378) */ +/* 990 */ + 0x12, 0x10, /* FC_UP */ +/* 992 */ NdrFcShort( 0x2 ), /* Offset= 2 (994) */ +/* 994 */ + 0x12, 0x0, /* FC_UP */ +/* 996 */ NdrFcShort( 0xfffffc1c ), /* Offset= -996 (0) */ +/* 998 */ + 0x12, 0x0, /* FC_UP */ +/* 1000 */ NdrFcShort( 0xfffffdaa ), /* Offset= -598 (402) */ +/* 1002 */ + 0x12, 0x0, /* FC_UP */ +/* 1004 */ NdrFcShort( 0xfffffdac ), /* Offset= -596 (408) */ +/* 1006 */ + 0x12, 0x10, /* FC_UP */ +/* 1008 */ NdrFcShort( 0xfffffdb4 ), /* Offset= -588 (420) */ +/* 1010 */ + 0x12, 0x10, /* FC_UP */ +/* 1012 */ NdrFcShort( 0xfffffdc2 ), /* Offset= -574 (438) */ +/* 1014 */ + 0x12, 0x10, /* FC_UP */ +/* 1016 */ NdrFcShort( 0xfffffdd0 ), /* Offset= -560 (456) */ +/* 1018 */ + 0x12, 0x0, /* FC_UP */ +/* 1020 */ NdrFcShort( 0xfffffed4 ), /* Offset= -300 (720) */ +/* 1022 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x7, /* 7 */ +/* 1024 */ NdrFcShort( 0x20 ), /* 32 */ +/* 1026 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1028 */ NdrFcShort( 0x0 ), /* Offset= 0 (1028) */ +/* 1030 */ 0x8, /* FC_LONG */ + 0x8, /* FC_LONG */ +/* 1032 */ 0x6, /* FC_SHORT */ + 0x6, /* FC_SHORT */ +/* 1034 */ 0x6, /* FC_SHORT */ + 0x6, /* FC_SHORT */ +/* 1036 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1038 */ NdrFcShort( 0xfffffc5c ), /* Offset= -932 (106) */ +/* 1040 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 1042 */ 0xb4, /* FC_USER_MARSHAL */ + 0x83, /* 131 */ +/* 1044 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1046 */ NdrFcShort( 0x10 ), /* 16 */ +/* 1048 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1050 */ NdrFcShort( 0xfffffc4c ), /* Offset= -948 (102) */ +/* 1052 */ + 0x21, /* FC_BOGUS_ARRAY */ + 0x3, /* 3 */ +/* 1054 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1056 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 1058 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1060 */ NdrFcLong( 0xffffffff ), /* -1 */ +/* 1064 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1066 */ NdrFcShort( 0xffffffe8 ), /* Offset= -24 (1042) */ +/* 1068 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 1070 */ + 0x1b, /* FC_CARRAY */ + 0x3, /* 3 */ +/* 1072 */ NdrFcShort( 0x4 ), /* 4 */ +/* 1074 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 1076 */ NdrFcShort( 0xc ), /* 12 */ +/* 1078 */ 0x8, /* FC_LONG */ + 0x5b, /* FC_END */ +/* 1080 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 1082 */ NdrFcShort( 0x10 ), /* 16 */ +/* 1084 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1086 */ NdrFcShort( 0x8 ), /* Offset= 8 (1094) */ +/* 1088 */ 0x36, /* FC_POINTER */ + 0x36, /* FC_POINTER */ +/* 1090 */ 0x8, /* FC_LONG */ + 0x8, /* FC_LONG */ +/* 1092 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 1094 */ + 0x12, 0x0, /* FC_UP */ +/* 1096 */ NdrFcShort( 0xffffffd4 ), /* Offset= -44 (1052) */ +/* 1098 */ + 0x12, 0x0, /* FC_UP */ +/* 1100 */ NdrFcShort( 0xffffffe2 ), /* Offset= -30 (1070) */ +/* 1102 */ + 0x11, 0x4, /* FC_RP [alloced_on_stack] */ +/* 1104 */ NdrFcShort( 0x6 ), /* Offset= 6 (1110) */ +/* 1106 */ + 0x13, 0x0, /* FC_OP */ +/* 1108 */ NdrFcShort( 0xffffffaa ), /* Offset= -86 (1022) */ +/* 1110 */ 0xb4, /* FC_USER_MARSHAL */ + 0x83, /* 131 */ +/* 1112 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1114 */ NdrFcShort( 0x10 ), /* 16 */ +/* 1116 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1118 */ NdrFcShort( 0xfffffff4 ), /* Offset= -12 (1106) */ +/* 1120 */ + 0x11, 0x4, /* FC_RP [alloced_on_stack] */ +/* 1122 */ NdrFcShort( 0x10 ), /* Offset= 16 (1138) */ +/* 1124 */ + 0x13, 0x0, /* FC_OP */ +/* 1126 */ NdrFcShort( 0xfffffd22 ), /* Offset= -734 (392) */ +/* 1128 */ 0xb4, /* FC_USER_MARSHAL */ + 0x83, /* 131 */ +/* 1130 */ NdrFcShort( 0x1 ), /* 1 */ +/* 1132 */ NdrFcShort( 0x4 ), /* 4 */ +/* 1134 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1136 */ NdrFcShort( 0xfffffff4 ), /* Offset= -12 (1124) */ +/* 1138 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 1140 */ NdrFcShort( 0x20 ), /* 32 */ +/* 1142 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1144 */ NdrFcShort( 0x0 ), /* Offset= 0 (1144) */ +/* 1146 */ 0x6, /* FC_SHORT */ + 0x6, /* FC_SHORT */ +/* 1148 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1150 */ NdrFcShort( 0xffffffea ), /* Offset= -22 (1128) */ +/* 1152 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1154 */ NdrFcShort( 0xffffffe6 ), /* Offset= -26 (1128) */ +/* 1156 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1158 */ NdrFcShort( 0xffffffe2 ), /* Offset= -30 (1128) */ +/* 1160 */ 0x38, /* FC_ALIGNM4 */ + 0x8, /* FC_LONG */ +/* 1162 */ 0x8, /* FC_LONG */ + 0x8, /* FC_LONG */ +/* 1164 */ 0x8, /* FC_LONG */ + 0x5b, /* FC_END */ +/* 1166 */ + 0x11, 0x0, /* FC_RP */ +/* 1168 */ NdrFcShort( 0x2 ), /* Offset= 2 (1170) */ +/* 1170 */ + 0x1b, /* FC_CARRAY */ + 0x3, /* 3 */ +/* 1172 */ NdrFcShort( 0x4 ), /* 4 */ +/* 1174 */ 0x29, /* Corr desc: parameter, FC_ULONG */ + 0x0, /* */ +#ifndef _ALPHA_ +/* 1176 */ NdrFcShort( 0x24 ), /* x86, MIPS, PPC Stack size/offset = 36 */ +#else + NdrFcShort( 0x48 ), /* Alpha Stack size/offset = 72 */ +#endif +/* 1178 */ 0x8, /* FC_LONG */ + 0x5b, /* FC_END */ +/* 1180 */ + 0x11, 0x0, /* FC_RP */ +/* 1182 */ NdrFcShort( 0x2 ), /* Offset= 2 (1184) */ +/* 1184 */ + 0x21, /* FC_BOGUS_ARRAY */ + 0x3, /* 3 */ +/* 1186 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1188 */ 0x29, /* Corr desc: parameter, FC_ULONG */ + 0x0, /* */ +#ifndef _ALPHA_ +/* 1190 */ NdrFcShort( 0x24 ), /* x86, MIPS, PPC Stack size/offset = 36 */ +#else + NdrFcShort( 0x48 ), /* Alpha Stack size/offset = 72 */ +#endif +/* 1192 */ NdrFcLong( 0xffffffff ), /* -1 */ +/* 1196 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1198 */ NdrFcShort( 0xffffffa8 ), /* Offset= -88 (1110) */ +/* 1200 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 1202 */ + 0x11, 0x0, /* FC_RP */ +/* 1204 */ NdrFcShort( 0x2 ), /* Offset= 2 (1206) */ +/* 1206 */ + 0x21, /* FC_BOGUS_ARRAY */ + 0x3, /* 3 */ +/* 1208 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1210 */ 0x29, /* Corr desc: parameter, FC_ULONG */ + 0x0, /* */ +#ifndef _ALPHA_ +/* 1212 */ NdrFcShort( 0x4 ), /* x86, MIPS, PPC Stack size/offset = 4 */ +#else + NdrFcShort( 0x8 ), /* Alpha Stack size/offset = 8 */ +#endif +/* 1214 */ 0x29, /* Corr desc: parameter, FC_ULONG */ + 0x54, /* FC_DEREFERENCE */ +#ifndef _ALPHA_ +/* 1216 */ NdrFcShort( 0xc ), /* x86, MIPS, PPC Stack size/offset = 12 */ +#else + NdrFcShort( 0x18 ), /* Alpha Stack size/offset = 24 */ +#endif +/* 1218 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1220 */ NdrFcShort( 0xffffff92 ), /* Offset= -110 (1110) */ +/* 1222 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 1224 */ + 0x11, 0x14, /* FC_RP [alloced_on_stack] */ +/* 1226 */ NdrFcShort( 0x2 ), /* Offset= 2 (1228) */ +/* 1228 */ + 0x2f, /* FC_IP */ + 0x5a, /* FC_CONSTANT_IID */ +/* 1230 */ NdrFcLong( 0x20404 ), /* 132100 */ +/* 1234 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1236 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1238 */ 0xc0, /* 192 */ + 0x0, /* 0 */ +/* 1240 */ 0x0, /* 0 */ + 0x0, /* 0 */ +/* 1242 */ 0x0, /* 0 */ + 0x0, /* 0 */ +/* 1244 */ 0x0, /* 0 */ + 0x46, /* 70 */ +/* 1246 */ + 0x11, 0x8, /* FC_RP [simple_pointer] */ +/* 1248 */ + 0x25, /* FC_C_WSTRING */ + 0x5c, /* FC_PAD */ +/* 1250 */ + 0x11, 0xc, /* FC_RP [alloced_on_stack] [simple_pointer] */ +/* 1252 */ 0xe, /* FC_ENUM32 */ + 0x5c, /* FC_PAD */ +/* 1254 */ + 0x11, 0x14, /* FC_RP [alloced_on_stack] */ +/* 1256 */ NdrFcShort( 0x2 ), /* Offset= 2 (1258) */ +/* 1258 */ + 0x13, 0x0, /* FC_OP */ +/* 1260 */ NdrFcShort( 0xaa ), /* Offset= 170 (1430) */ +/* 1262 */ + 0x2b, /* FC_NON_ENCAPSULATED_UNION */ + 0x7, /* FC_USHORT */ +/* 1264 */ 0x7, /* Corr desc: FC_USHORT */ + 0x0, /* */ +/* 1266 */ NdrFcShort( 0x4 ), /* 4 */ +/* 1268 */ NdrFcShort( 0x2 ), /* Offset= 2 (1270) */ +/* 1270 */ NdrFcShort( 0x4 ), /* 4 */ +/* 1272 */ NdrFcShort( 0x4 ), /* 4 */ +/* 1274 */ NdrFcLong( 0x1a ), /* 26 */ +/* 1278 */ NdrFcShort( 0x16 ), /* Offset= 22 (1300) */ +/* 1280 */ NdrFcLong( 0x1b ), /* 27 */ +/* 1284 */ NdrFcShort( 0x10 ), /* Offset= 16 (1300) */ +/* 1286 */ NdrFcLong( 0x1c ), /* 28 */ +/* 1290 */ NdrFcShort( 0xe ), /* Offset= 14 (1304) */ +/* 1292 */ NdrFcLong( 0x1d ), /* 29 */ +/* 1296 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ +/* 1298 */ NdrFcShort( 0x0 ), /* Offset= 0 (1298) */ +/* 1300 */ + 0x13, 0x0, /* FC_OP */ +/* 1302 */ NdrFcShort( 0x24 ), /* Offset= 36 (1338) */ +/* 1304 */ + 0x13, 0x0, /* FC_OP */ +/* 1306 */ NdrFcShort( 0x10 ), /* Offset= 16 (1322) */ +/* 1308 */ + 0x1b, /* FC_CARRAY */ + 0x3, /* 3 */ +/* 1310 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1312 */ 0x7, /* Corr desc: FC_USHORT */ + 0x0, /* */ +/* 1314 */ NdrFcShort( 0xfffc ), /* -4 */ +/* 1316 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1318 */ NdrFcShort( 0xfffffe78 ), /* Offset= -392 (926) */ +/* 1320 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 1322 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 1324 */ NdrFcShort( 0x4 ), /* 4 */ +/* 1326 */ NdrFcShort( 0xffffffee ), /* Offset= -18 (1308) */ +/* 1328 */ NdrFcShort( 0x0 ), /* Offset= 0 (1328) */ +/* 1330 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1332 */ NdrFcShort( 0x6 ), /* Offset= 6 (1338) */ +/* 1334 */ 0x6, /* FC_SHORT */ + 0x3e, /* FC_STRUCTPAD2 */ +/* 1336 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 1338 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 1340 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1342 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1344 */ NdrFcShort( 0x0 ), /* Offset= 0 (1344) */ +/* 1346 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1348 */ NdrFcShort( 0xffffffaa ), /* Offset= -86 (1262) */ +/* 1350 */ 0x6, /* FC_SHORT */ + 0x3e, /* FC_STRUCTPAD2 */ +/* 1352 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 1354 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 1356 */ NdrFcShort( 0x18 ), /* 24 */ +/* 1358 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1360 */ NdrFcShort( 0x0 ), /* Offset= 0 (1360) */ +/* 1362 */ 0x8, /* FC_LONG */ + 0x4c, /* FC_EMBEDDED_COMPLEX */ +/* 1364 */ 0x4, /* 4 */ + NdrFcShort( 0xffffff01 ), /* Offset= -255 (1110) */ + 0x5b, /* FC_END */ +/* 1368 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 1370 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1372 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1374 */ NdrFcShort( 0x6 ), /* Offset= 6 (1380) */ +/* 1376 */ 0x36, /* FC_POINTER */ + 0x6, /* FC_SHORT */ +/* 1378 */ 0x3e, /* FC_STRUCTPAD2 */ + 0x5b, /* FC_END */ +/* 1380 */ + 0x13, 0x0, /* FC_OP */ +/* 1382 */ NdrFcShort( 0xffffffe4 ), /* Offset= -28 (1354) */ +/* 1384 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 1386 */ NdrFcShort( 0x10 ), /* 16 */ +/* 1388 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1390 */ NdrFcShort( 0x0 ), /* Offset= 0 (1390) */ +/* 1392 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1394 */ NdrFcShort( 0xffffffc8 ), /* Offset= -56 (1338) */ +/* 1396 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1398 */ NdrFcShort( 0xffffffe2 ), /* Offset= -30 (1368) */ +/* 1400 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 1402 */ + 0x1b, /* FC_CARRAY */ + 0x3, /* 3 */ +/* 1404 */ NdrFcShort( 0x4 ), /* 4 */ +/* 1406 */ 0x16, /* Corr desc: field pointer, FC_SHORT */ + 0x0, /* */ +/* 1408 */ NdrFcShort( 0x1e ), /* 30 */ +/* 1410 */ 0x8, /* FC_LONG */ + 0x5b, /* FC_END */ +/* 1412 */ + 0x21, /* FC_BOGUS_ARRAY */ + 0x3, /* 3 */ +/* 1414 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1416 */ 0x16, /* Corr desc: field pointer, FC_SHORT */ + 0x0, /* */ +/* 1418 */ NdrFcShort( 0x18 ), /* 24 */ +/* 1420 */ NdrFcLong( 0xffffffff ), /* -1 */ +/* 1424 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1426 */ NdrFcShort( 0xffffffd6 ), /* Offset= -42 (1384) */ +/* 1428 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 1430 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 1432 */ NdrFcShort( 0x34 ), /* 52 */ +/* 1434 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1436 */ NdrFcShort( 0x14 ), /* Offset= 20 (1456) */ +/* 1438 */ 0x8, /* FC_LONG */ + 0x36, /* FC_POINTER */ +/* 1440 */ 0x36, /* FC_POINTER */ + 0xe, /* FC_ENUM32 */ +/* 1442 */ 0xe, /* FC_ENUM32 */ + 0xe, /* FC_ENUM32 */ +/* 1444 */ 0x6, /* FC_SHORT */ + 0x6, /* FC_SHORT */ +/* 1446 */ 0x6, /* FC_SHORT */ + 0x6, /* FC_SHORT */ +/* 1448 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1450 */ NdrFcShort( 0xffffffbe ), /* Offset= -66 (1384) */ +/* 1452 */ 0x6, /* FC_SHORT */ + 0x3e, /* FC_STRUCTPAD2 */ +/* 1454 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 1456 */ + 0x13, 0x0, /* FC_OP */ +/* 1458 */ NdrFcShort( 0xffffffc8 ), /* Offset= -56 (1402) */ +/* 1460 */ + 0x13, 0x0, /* FC_OP */ +/* 1462 */ NdrFcShort( 0xffffffce ), /* Offset= -50 (1412) */ +/* 1464 */ + 0x11, 0x14, /* FC_RP [alloced_on_stack] */ +/* 1466 */ NdrFcShort( 0x2 ), /* Offset= 2 (1468) */ +/* 1468 */ + 0x13, 0x0, /* FC_OP */ +/* 1470 */ NdrFcShort( 0x2c ), /* Offset= 44 (1514) */ +/* 1472 */ + 0x2b, /* FC_NON_ENCAPSULATED_UNION */ + 0x8, /* FC_LONG */ +/* 1474 */ 0x8, /* Corr desc: FC_LONG */ + 0x0, /* */ +/* 1476 */ NdrFcShort( 0x18 ), /* 24 */ +/* 1478 */ NdrFcShort( 0x2 ), /* Offset= 2 (1480) */ +/* 1480 */ NdrFcShort( 0x4 ), /* 4 */ +/* 1482 */ NdrFcShort( 0x4 ), /* 4 */ +/* 1484 */ NdrFcLong( 0x0 ), /* 0 */ +/* 1488 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ +/* 1490 */ NdrFcLong( 0x3 ), /* 3 */ +/* 1494 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ +/* 1496 */ NdrFcLong( 0x1 ), /* 1 */ +/* 1500 */ NdrFcShort( 0x8008 ), /* Simple arm type: FC_LONG */ +/* 1502 */ NdrFcLong( 0x2 ), /* 2 */ +/* 1506 */ NdrFcShort( 0x4 ), /* Offset= 4 (1510) */ +/* 1508 */ NdrFcShort( 0xffffffff ), /* Offset= -1 (1507) */ +/* 1510 */ + 0x13, 0x0, /* FC_OP */ +/* 1512 */ NdrFcShort( 0xfffffe6e ), /* Offset= -402 (1110) */ +/* 1514 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 1516 */ NdrFcShort( 0x24 ), /* 36 */ +/* 1518 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1520 */ NdrFcShort( 0x10 ), /* Offset= 16 (1536) */ +/* 1522 */ 0x8, /* FC_LONG */ + 0x36, /* FC_POINTER */ +/* 1524 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1526 */ NdrFcShort( 0xffffffca ), /* Offset= -54 (1472) */ +/* 1528 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1530 */ NdrFcShort( 0xffffff6e ), /* Offset= -146 (1384) */ +/* 1532 */ 0x6, /* FC_SHORT */ + 0x38, /* FC_ALIGNM4 */ +/* 1534 */ 0xe, /* FC_ENUM32 */ + 0x5b, /* FC_END */ +/* 1536 */ + 0x13, 0x8, /* FC_OP [simple_pointer] */ +/* 1538 */ + 0x25, /* FC_C_WSTRING */ + 0x5c, /* FC_PAD */ +/* 1540 */ + 0x11, 0x14, /* FC_RP [alloced_on_stack] */ +/* 1542 */ NdrFcShort( 0x2 ), /* Offset= 2 (1544) */ +/* 1544 */ + 0x2f, /* FC_IP */ + 0x5a, /* FC_CONSTANT_IID */ +/* 1546 */ NdrFcLong( 0x20403 ), /* 132099 */ +/* 1550 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1552 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1554 */ 0xc0, /* 192 */ + 0x0, /* 0 */ +/* 1556 */ 0x0, /* 0 */ + 0x0, /* 0 */ +/* 1558 */ 0x0, /* 0 */ + 0x0, /* 0 */ +/* 1560 */ 0x0, /* 0 */ + 0x46, /* 70 */ +/* 1562 */ + 0x11, 0x4, /* FC_RP [alloced_on_stack] */ +/* 1564 */ NdrFcShort( 0x4 ), /* Offset= 4 (1568) */ +/* 1566 */ 0x8, /* FC_LONG */ + 0x5c, /* FC_PAD */ +/* 1568 */ 0xb4, /* FC_USER_MARSHAL */ + 0x3, /* 3 */ +/* 1570 */ NdrFcShort( 0x2 ), /* 2 */ +/* 1572 */ NdrFcShort( 0xc ), /* 12 */ +/* 1574 */ NdrFcShort( 0x4 ), /* 4 */ +/* 1576 */ NdrFcShort( 0xfffffff6 ), /* Offset= -10 (1566) */ +/* 1578 */ + 0x11, 0x14, /* FC_RP [alloced_on_stack] */ +/* 1580 */ NdrFcShort( 0x2 ), /* Offset= 2 (1582) */ +/* 1582 */ + 0x13, 0x0, /* FC_OP */ +/* 1584 */ NdrFcShort( 0xe ), /* Offset= 14 (1598) */ +/* 1586 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 1588 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1590 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1592 */ NdrFcShort( 0x0 ), /* Offset= 0 (1592) */ +/* 1594 */ 0x8, /* FC_LONG */ + 0x6, /* FC_SHORT */ +/* 1596 */ 0x3e, /* FC_STRUCTPAD2 */ + 0x5b, /* FC_END */ +/* 1598 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 1600 */ NdrFcShort( 0x4c ), /* 76 */ +/* 1602 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1604 */ NdrFcShort( 0x1e ), /* Offset= 30 (1634) */ +/* 1606 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1608 */ NdrFcShort( 0xfffff9de ), /* Offset= -1570 (38) */ +/* 1610 */ 0x8, /* FC_LONG */ + 0x8, /* FC_LONG */ +/* 1612 */ 0x8, /* FC_LONG */ + 0x8, /* FC_LONG */ +/* 1614 */ 0x36, /* FC_POINTER */ + 0x8, /* FC_LONG */ +/* 1616 */ 0xe, /* FC_ENUM32 */ + 0x6, /* FC_SHORT */ +/* 1618 */ 0x6, /* FC_SHORT */ + 0x6, /* FC_SHORT */ +/* 1620 */ 0x6, /* FC_SHORT */ + 0x6, /* FC_SHORT */ +/* 1622 */ 0x6, /* FC_SHORT */ + 0x6, /* FC_SHORT */ +/* 1624 */ 0x6, /* FC_SHORT */ + 0x4c, /* FC_EMBEDDED_COMPLEX */ +/* 1626 */ 0x0, /* 0 */ + NdrFcShort( 0xfffffedf ), /* Offset= -289 (1338) */ + 0x4c, /* FC_EMBEDDED_COMPLEX */ +/* 1630 */ 0x0, /* 0 */ + NdrFcShort( 0xffffffd3 ), /* Offset= -45 (1586) */ + 0x5b, /* FC_END */ +/* 1634 */ + 0x13, 0x8, /* FC_OP [simple_pointer] */ +/* 1636 */ + 0x25, /* FC_C_WSTRING */ + 0x5c, /* FC_PAD */ +/* 1638 */ + 0x11, 0x4, /* FC_RP [alloced_on_stack] */ +/* 1640 */ NdrFcShort( 0x4 ), /* Offset= 4 (1644) */ +/* 1642 */ 0x8, /* FC_LONG */ + 0x5c, /* FC_PAD */ +/* 1644 */ 0xb4, /* FC_USER_MARSHAL */ + 0x3, /* 3 */ +/* 1646 */ NdrFcShort( 0x2 ), /* 2 */ +/* 1648 */ NdrFcShort( 0xc ), /* 12 */ +/* 1650 */ NdrFcShort( 0x4 ), /* 4 */ +/* 1652 */ NdrFcShort( 0xfffffff6 ), /* Offset= -10 (1642) */ +/* 1654 */ + 0x11, 0x4, /* FC_RP [alloced_on_stack] */ +/* 1656 */ NdrFcShort( 0x4 ), /* Offset= 4 (1660) */ +/* 1658 */ 0x8, /* FC_LONG */ + 0x5c, /* FC_PAD */ +/* 1660 */ 0xb4, /* FC_USER_MARSHAL */ + 0x3, /* 3 */ +/* 1662 */ NdrFcShort( 0x2 ), /* 2 */ +/* 1664 */ NdrFcShort( 0xc ), /* 12 */ +/* 1666 */ NdrFcShort( 0x4 ), /* 4 */ +/* 1668 */ NdrFcShort( 0xfffffff6 ), /* Offset= -10 (1658) */ +/* 1670 */ + 0x11, 0x4, /* FC_RP [alloced_on_stack] */ +/* 1672 */ NdrFcShort( 0x4 ), /* Offset= 4 (1676) */ +/* 1674 */ 0x8, /* FC_LONG */ + 0x5c, /* FC_PAD */ +/* 1676 */ 0xb4, /* FC_USER_MARSHAL */ + 0x3, /* 3 */ +/* 1678 */ NdrFcShort( 0x2 ), /* 2 */ +/* 1680 */ NdrFcShort( 0xc ), /* 12 */ +/* 1682 */ NdrFcShort( 0x4 ), /* 4 */ +/* 1684 */ NdrFcShort( 0xfffffff6 ), /* Offset= -10 (1674) */ +/* 1686 */ + 0x11, 0x0, /* FC_RP */ +/* 1688 */ NdrFcShort( 0x2 ), /* Offset= 2 (1690) */ +/* 1690 */ + 0x21, /* FC_BOGUS_ARRAY */ + 0x3, /* 3 */ +/* 1692 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1694 */ 0x29, /* Corr desc: parameter, FC_ULONG */ + 0x0, /* */ +#ifndef _ALPHA_ +/* 1696 */ NdrFcShort( 0xc ), /* x86, MIPS, PPC Stack size/offset = 12 */ +#else + NdrFcShort( 0x18 ), /* Alpha Stack size/offset = 24 */ +#endif +/* 1698 */ 0x29, /* Corr desc: parameter, FC_ULONG */ + 0x54, /* FC_DEREFERENCE */ +#ifndef _ALPHA_ +/* 1700 */ NdrFcShort( 0x10 ), /* x86, MIPS, PPC Stack size/offset = 16 */ +#else + NdrFcShort( 0x20 ), /* Alpha Stack size/offset = 32 */ +#endif +/* 1702 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1704 */ NdrFcShort( 0xfffffdc0 ), /* Offset= -576 (1128) */ +/* 1706 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 1708 */ + 0x11, 0x4, /* FC_RP [alloced_on_stack] */ +/* 1710 */ NdrFcShort( 0xfffffdba ), /* Offset= -582 (1128) */ +/* 1712 */ + 0x11, 0xc, /* FC_RP [alloced_on_stack] [simple_pointer] */ +/* 1714 */ 0x6, /* FC_SHORT */ + 0x5c, /* FC_PAD */ +/* 1716 */ + 0x11, 0x14, /* FC_RP [alloced_on_stack] */ +/* 1718 */ NdrFcShort( 0x2 ), /* Offset= 2 (1720) */ +/* 1720 */ + 0x2f, /* FC_IP */ + 0x5c, /* FC_PAD */ +/* 1722 */ 0x28, /* Corr desc: parameter, FC_LONG */ + 0x0, /* */ +#ifndef _ALPHA_ +/* 1724 */ NdrFcShort( 0x4 ), /* x86, MIPS, PPC Stack size/offset = 4 */ +#else + NdrFcShort( 0x8 ), /* Alpha Stack size/offset = 8 */ +#endif +/* 1726 */ + 0x11, 0x14, /* FC_RP [alloced_on_stack] */ +/* 1728 */ NdrFcShort( 0x2 ), /* Offset= 2 (1730) */ +/* 1730 */ + 0x2f, /* FC_IP */ + 0x5a, /* FC_CONSTANT_IID */ +/* 1732 */ NdrFcLong( 0x20402 ), /* 132098 */ +/* 1736 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1738 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1740 */ 0xc0, /* 192 */ + 0x0, /* 0 */ +/* 1742 */ 0x0, /* 0 */ + 0x0, /* 0 */ +/* 1744 */ 0x0, /* 0 */ + 0x0, /* 0 */ +/* 1746 */ 0x0, /* 0 */ + 0x46, /* 70 */ +/* 1748 */ + 0x11, 0x4, /* FC_RP [alloced_on_stack] */ +/* 1750 */ NdrFcShort( 0x26 ), /* Offset= 38 (1788) */ +/* 1752 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 1754 */ NdrFcShort( 0x20 ), /* 32 */ +/* 1756 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1758 */ NdrFcShort( 0x0 ), /* Offset= 0 (1758) */ +/* 1760 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1762 */ NdrFcShort( 0xfffff944 ), /* Offset= -1724 (38) */ +/* 1764 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1766 */ NdrFcShort( 0xfffffd70 ), /* Offset= -656 (1110) */ +/* 1768 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 1770 */ + 0x21, /* FC_BOGUS_ARRAY */ + 0x3, /* 3 */ +/* 1772 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1774 */ 0x19, /* Corr desc: field pointer, FC_ULONG */ + 0x0, /* */ +/* 1776 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1778 */ NdrFcLong( 0xffffffff ), /* -1 */ +/* 1782 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1784 */ NdrFcShort( 0xffffffe0 ), /* Offset= -32 (1752) */ +/* 1786 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 1788 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 1790 */ NdrFcShort( 0x8 ), /* 8 */ +/* 1792 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1794 */ NdrFcShort( 0x6 ), /* Offset= 6 (1800) */ +/* 1796 */ 0x8, /* FC_LONG */ + 0x36, /* FC_POINTER */ +/* 1798 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 1800 */ + 0x13, 0x0, /* FC_OP */ +/* 1802 */ NdrFcShort( 0xffffffe0 ), /* Offset= -32 (1770) */ +/* 1804 */ + 0x11, 0x14, /* FC_RP [alloced_on_stack] */ +/* 1806 */ NdrFcShort( 0x2 ), /* Offset= 2 (1808) */ +/* 1808 */ + 0x13, 0x0, /* FC_OP */ +/* 1810 */ NdrFcShort( 0x2 ), /* Offset= 2 (1812) */ +/* 1812 */ + 0x1a, /* FC_BOGUS_STRUCT */ + 0x3, /* 3 */ +/* 1814 */ NdrFcShort( 0x20 ), /* 32 */ +/* 1816 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1818 */ NdrFcShort( 0x0 ), /* Offset= 0 (1818) */ +/* 1820 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1822 */ NdrFcShort( 0xfffff908 ), /* Offset= -1784 (38) */ +/* 1824 */ 0x8, /* FC_LONG */ + 0xe, /* FC_ENUM32 */ +/* 1826 */ 0x6, /* FC_SHORT */ + 0x6, /* FC_SHORT */ +/* 1828 */ 0x6, /* FC_SHORT */ + 0x3e, /* FC_STRUCTPAD2 */ +/* 1830 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 1832 */ + 0x11, 0x4, /* FC_RP [alloced_on_stack] */ +/* 1834 */ NdrFcShort( 0x4 ), /* Offset= 4 (1838) */ +/* 1836 */ 0x8, /* FC_LONG */ + 0x5c, /* FC_PAD */ +/* 1838 */ 0xb4, /* FC_USER_MARSHAL */ + 0x3, /* 3 */ +/* 1840 */ NdrFcShort( 0x2 ), /* 2 */ +/* 1842 */ NdrFcShort( 0xc ), /* 12 */ +/* 1844 */ NdrFcShort( 0x4 ), /* 4 */ +/* 1846 */ NdrFcShort( 0xfffffff6 ), /* Offset= -10 (1836) */ +/* 1848 */ + 0x11, 0x0, /* FC_RP */ +/* 1850 */ NdrFcShort( 0x2 ), /* Offset= 2 (1852) */ +/* 1852 */ + 0x21, /* FC_BOGUS_ARRAY */ + 0x3, /* 3 */ +/* 1854 */ NdrFcShort( 0x0 ), /* 0 */ +/* 1856 */ 0x27, /* Corr desc: parameter, FC_USHORT */ + 0x54, /* FC_DEREFERENCE */ +#ifndef _ALPHA_ +/* 1858 */ NdrFcShort( 0x14 ), /* x86, MIPS, PPC Stack size/offset = 20 */ +#else + NdrFcShort( 0x28 ), /* Alpha Stack size/offset = 40 */ +#endif +/* 1860 */ 0x27, /* Corr desc: parameter, FC_USHORT */ + 0x54, /* FC_DEREFERENCE */ +#ifndef _ALPHA_ +/* 1862 */ NdrFcShort( 0x14 ), /* x86, MIPS, PPC Stack size/offset = 20 */ +#else + NdrFcShort( 0x28 ), /* Alpha Stack size/offset = 40 */ +#endif +/* 1864 */ 0x4c, /* FC_EMBEDDED_COMPLEX */ + 0x0, /* 0 */ +/* 1866 */ NdrFcShort( 0xfffff8c0 ), /* Offset= -1856 (10) */ +/* 1868 */ 0x5c, /* FC_PAD */ + 0x5b, /* FC_END */ +/* 1870 */ + 0x11, 0x0, /* FC_RP */ +/* 1872 */ NdrFcShort( 0x2 ), /* Offset= 2 (1874) */ +/* 1874 */ + 0x1c, /* FC_CVARRAY */ + 0x3, /* 3 */ +/* 1876 */ NdrFcShort( 0x4 ), /* 4 */ +/* 1878 */ 0x27, /* Corr desc: parameter, FC_USHORT */ + 0x54, /* FC_DEREFERENCE */ +#ifndef _ALPHA_ +/* 1880 */ NdrFcShort( 0x14 ), /* x86, MIPS, PPC Stack size/offset = 20 */ +#else + NdrFcShort( 0x28 ), /* Alpha Stack size/offset = 40 */ +#endif +/* 1882 */ 0x27, /* Corr desc: parameter, FC_USHORT */ + 0x54, /* FC_DEREFERENCE */ +#ifndef _ALPHA_ +/* 1884 */ NdrFcShort( 0x14 ), /* x86, MIPS, PPC Stack size/offset = 20 */ +#else + NdrFcShort( 0x28 ), /* Alpha Stack size/offset = 40 */ +#endif +/* 1886 */ 0x8, /* FC_LONG */ + 0x5b, /* FC_END */ +/* 1888 */ + 0x11, 0x8, /* FC_RP [simple_pointer] */ +/* 1890 */ 0x6, /* FC_SHORT */ + 0x5c, /* FC_PAD */ +/* 1892 */ + 0x11, 0x4, /* FC_RP [alloced_on_stack] */ +/* 1894 */ NdrFcShort( 0xfffff8c0 ), /* Offset= -1856 (38) */ +/* 1896 */ + 0x11, 0x14, /* FC_RP [alloced_on_stack] */ +/* 1898 */ NdrFcShort( 0x2 ), /* Offset= 2 (1900) */ +/* 1900 */ + 0x2f, /* FC_IP */ + 0x5c, /* FC_PAD */ +/* 1902 */ 0x28, /* Corr desc: parameter, FC_LONG */ + 0x0, /* */ +#ifndef _ALPHA_ +/* 1904 */ NdrFcShort( 0x8 ), /* x86, MIPS, PPC Stack size/offset = 8 */ +#else + NdrFcShort( 0x10 ), /* Alpha Stack size/offset = 16 */ +#endif + + 0x0 + } + }; + +const CInterfaceProxyVtbl * _oaidl_ProxyVtblList[] = +{ + ( CInterfaceProxyVtbl *) &_IDispatchProxyVtbl, + ( CInterfaceProxyVtbl *) &_ITypeInfoProxyVtbl, + ( CInterfaceProxyVtbl *) &_ITypeLibProxyVtbl, + ( CInterfaceProxyVtbl *) &_ITypeCompProxyVtbl, + ( CInterfaceProxyVtbl *) &_IEnumVARIANTProxyVtbl, + ( CInterfaceProxyVtbl *) &_ITypeLib2ProxyVtbl, + ( CInterfaceProxyVtbl *) &_ITypeInfo2ProxyVtbl, + ( CInterfaceProxyVtbl *) &_IErrorInfoProxyVtbl, + ( CInterfaceProxyVtbl *) &_ITypeFactoryProxyVtbl, + ( CInterfaceProxyVtbl *) &_ICreateErrorInfoProxyVtbl, + ( CInterfaceProxyVtbl *) &_ISupportErrorInfoProxyVtbl, + 0 +}; + +const CInterfaceStubVtbl * _oaidl_StubVtblList[] = +{ + ( CInterfaceStubVtbl *) &_IDispatchStubVtbl, + ( CInterfaceStubVtbl *) &_ITypeInfoStubVtbl, + ( CInterfaceStubVtbl *) &_ITypeLibStubVtbl, + ( CInterfaceStubVtbl *) &_ITypeCompStubVtbl, + ( CInterfaceStubVtbl *) &_IEnumVARIANTStubVtbl, + ( CInterfaceStubVtbl *) &_ITypeLib2StubVtbl, + ( CInterfaceStubVtbl *) &_ITypeInfo2StubVtbl, + ( CInterfaceStubVtbl *) &_IErrorInfoStubVtbl, + ( CInterfaceStubVtbl *) &_ITypeFactoryStubVtbl, + ( CInterfaceStubVtbl *) &_ICreateErrorInfoStubVtbl, + ( CInterfaceStubVtbl *) &_ISupportErrorInfoStubVtbl, + 0 +}; + +PCInterfaceName const _oaidl_InterfaceNamesList[] = +{ + "IDispatch", + "ITypeInfo", + "ITypeLib", + "ITypeComp", + "IEnumVARIANT", + "ITypeLib2", + "ITypeInfo2", + "IErrorInfo", + "ITypeFactory", + "ICreateErrorInfo", + "ISupportErrorInfo", + 0 +}; + + +#define _oaidl_CHECK_IID(n) IID_GENERIC_CHECK_IID( _oaidl, pIID, n) + +int __stdcall _oaidl_IID_Lookup( const IID * pIID, int * pIndex ) +{ + IID_BS_LOOKUP_SETUP + + IID_BS_LOOKUP_INITIAL_TEST( _oaidl, 11, 8 ) + IID_BS_LOOKUP_NEXT_TEST( _oaidl, 4 ) + IID_BS_LOOKUP_NEXT_TEST( _oaidl, 2 ) + IID_BS_LOOKUP_NEXT_TEST( _oaidl, 1 ) + IID_BS_LOOKUP_RETURN_RESULT( _oaidl, 11, *pIndex ) + +} + +const ExtendedProxyFileInfo oaidl_ProxyFileInfo = +{ + (PCInterfaceProxyVtblList *) & _oaidl_ProxyVtblList, + (PCInterfaceStubVtblList *) & _oaidl_StubVtblList, + (const PCInterfaceName * ) & _oaidl_InterfaceNamesList, + 0, /* no delegation */ + & _oaidl_IID_Lookup, + 11, + 1, + 0, /* table of [async_uuid] interfaces */ + 0, /* Filler1 */ + 0, /* Filler2 */ + 0 /* Filler3 */ +}; diff --git a/reactos/lib/oleaut32/ole2disp.c b/reactos/lib/oleaut32/ole2disp.c index 8fc355cbfab..1d8104921eb 100644 --- a/reactos/lib/oleaut32/ole2disp.c +++ b/reactos/lib/oleaut32/ole2disp.c @@ -1,249 +1,249 @@ -/* - * OLE2DISP library - * - * Copyright 1995 Martin von Loewis - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <stdarg.h> -#include <string.h> - -#include "wine/windef16.h" -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "ole2.h" -#include "oleauto.h" -#include "winerror.h" - -#include "ole2disp.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/* This implementation of the BSTR API is 16-bit only. It - represents BSTR as a 16:16 far pointer, and the strings - as ISO-8859 */ - -/****************************************************************************** - * BSTR_AllocBytes [Internal] - */ -static BSTR16 BSTR_AllocBytes(int n) -{ - void *ptr = HeapAlloc( GetProcessHeap(), 0, n ); - return (BSTR16)MapLS(ptr); -} - -/****************************************************************************** - * BSTR_Free [INTERNAL] - */ -static void BSTR_Free(BSTR16 in) -{ - void *ptr = MapSL( (SEGPTR)in ); - UnMapLS( (SEGPTR)in ); - HeapFree( GetProcessHeap(), 0, ptr ); -} - -/****************************************************************************** - * BSTR_GetAddr [INTERNAL] - */ -static void* BSTR_GetAddr(BSTR16 in) -{ - return in ? MapSL((SEGPTR)in) : 0; -} - -/****************************************************************************** - * SysAllocString [OLE2DISP.2] - * - * Create a BSTR16 from an OLESTR16 (16 Bit). - * - * PARAMS - * oleStr [I] Source to create BSTR16 from - * - * RETURNS - * Success: A BSTR16 allocated with SysAllocStringLen16(). - * Failure: NULL, if oleStr is NULL. - */ -BSTR16 WINAPI SysAllocString16(LPCOLESTR16 oleStr) -{ - BSTR16 out; - - if (!oleStr) return 0; - - out = BSTR_AllocBytes(strlen(oleStr)+1); - if (!out) return 0; - strcpy(BSTR_GetAddr(out),oleStr); - return out; -} - -/****************************************************************************** - * SysReallocString [OLE2DISP.3] - * - * Change the length of a previously created BSTR16 (16 Bit). - * - * PARAMS - * pbstr [I] BSTR16 to change the length of - * oleStr [I] New source for pbstr - * - * RETURNS - * Success: 1 - * Failure: 0. - * - * NOTES - * SysAllocStringStringLen16(). - */ -INT16 WINAPI SysReAllocString16(LPBSTR16 pbstr,LPCOLESTR16 oleStr) -{ - BSTR16 new=SysAllocString16(oleStr); - BSTR_Free(*pbstr); - *pbstr=new; - return 1; -} - -/****************************************************************************** - * SysAllocStringLen [OLE2DISP.4] - * - * Create a BSTR16 from an OLESTR16 of a given character length (16 Bit). - * - * PARAMS - * oleStr [I] Source to create BSTR16 from - * len [I] Length of oleStr in wide characters - * - * RETURNS - * Success: A newly allocated BSTR16 from SysAllocStringByteLen16() - * Failure: NULL, if len is >= 0x80000000, or memory allocation fails. - * - * NOTES - * See SysAllocStringByteLen16(). - */ -BSTR16 WINAPI SysAllocStringLen16(const char *oleStr, int len) -{ - BSTR16 out=BSTR_AllocBytes(len+1); - - if (!out) - return 0; - - /* - * Copy the information in the buffer. - * Since it is valid to pass a NULL pointer here, we'll initialize the - * buffer to nul if it is the case. - */ - if (oleStr != 0) - strcpy(BSTR_GetAddr(out),oleStr); - else - memset(BSTR_GetAddr(out), 0, len+1); - - return out; -} - -/****************************************************************************** - * SysReAllocStringLen [OLE2DISP.5] - * - * Change the length of a previously created BSTR16 (16 Bit). - * - * PARAMS - * pbstr [I] BSTR16 to change the length of - * oleStr [I] New source for pbstr - * len [I] Length of oleStr in characters - * - * RETURNS - * Success: 1. The size of pbstr is updated. - * Failure: 0, if len >= 0x8000 or memory allocation fails. - * - * NOTES - * See SysAllocStringByteLen16(). - * *pbstr may be changed by this function. - */ -int WINAPI SysReAllocStringLen16(BSTR16 *old,const char *in,int len) -{ - /* FIXME: Check input length */ - BSTR16 new=SysAllocStringLen16(in,len); - BSTR_Free(*old); - *old=new; - return 1; -} - -/****************************************************************************** - * SysFreeString [OLE2DISP.6] - * - * Free a BSTR16 (16 Bit). - * - * PARAMS - * str [I] String to free. - * - * RETURNS - * Nothing. - */ -void WINAPI SysFreeString16(BSTR16 str) -{ - BSTR_Free(str); -} - -/****************************************************************************** - * SysStringLen [OLE2DISP.7] - * - * Get the allocated length of a BSTR16 in characters (16 Bit). - * - * PARAMS - * str [I] BSTR16 to find the length of - * - * RETURNS - * The allocated length of str, or 0 if str is NULL. - */ -int WINAPI SysStringLen16(BSTR16 str) -{ - return strlen(BSTR_GetAddr(str)); -} - -/****************************************************************************** - * CreateDispTypeInfo [OLE2DISP.31] - */ -HRESULT WINAPI CreateDispTypeInfo16( - INTERFACEDATA *pidata, - LCID lcid, - ITypeInfo **pptinfo) -{ - FIXME("(%p,%ld,%p),stub\n",pidata,lcid,pptinfo); - return E_NOTIMPL; -} - -/****************************************************************************** - * CreateStdDispatch [OLE2DISP.32] - */ -HRESULT WINAPI CreateStdDispatch16( - IUnknown* punkOuter, - void* pvThis, - ITypeInfo* ptinfo, - IUnknown** ppunkStdDisp) -{ - FIXME("(%p,%p,%p,%p),stub\n",punkOuter, pvThis, ptinfo, - ppunkStdDisp); - return 0; -} - -/****************************************************************************** - * RegisterActiveObject [OLE2DISP.35] - */ -HRESULT WINAPI RegisterActiveObject16( - IUnknown *punk, REFCLSID rclsid, DWORD dwFlags, unsigned long *pdwRegister -) { - FIXME("(%p,%s,0x%08lx,%p):stub\n",punk,debugstr_guid(rclsid),dwFlags,pdwRegister); - return E_NOTIMPL; -} +/* + * OLE2DISP library + * + * Copyright 1995 Martin von Loewis + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <stdarg.h> +#include <string.h> + +#include "wine/windef16.h" +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "ole2.h" +#include "oleauto.h" +#include "winerror.h" + +#include "ole2disp.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/* This implementation of the BSTR API is 16-bit only. It + represents BSTR as a 16:16 far pointer, and the strings + as ISO-8859 */ + +/****************************************************************************** + * BSTR_AllocBytes [Internal] + */ +static BSTR16 BSTR_AllocBytes(int n) +{ + void *ptr = HeapAlloc( GetProcessHeap(), 0, n ); + return (BSTR16)MapLS(ptr); +} + +/****************************************************************************** + * BSTR_Free [INTERNAL] + */ +static void BSTR_Free(BSTR16 in) +{ + void *ptr = MapSL( (SEGPTR)in ); + UnMapLS( (SEGPTR)in ); + HeapFree( GetProcessHeap(), 0, ptr ); +} + +/****************************************************************************** + * BSTR_GetAddr [INTERNAL] + */ +static void* BSTR_GetAddr(BSTR16 in) +{ + return in ? MapSL((SEGPTR)in) : 0; +} + +/****************************************************************************** + * SysAllocString [OLE2DISP.2] + * + * Create a BSTR16 from an OLESTR16 (16 Bit). + * + * PARAMS + * oleStr [I] Source to create BSTR16 from + * + * RETURNS + * Success: A BSTR16 allocated with SysAllocStringLen16(). + * Failure: NULL, if oleStr is NULL. + */ +BSTR16 WINAPI SysAllocString16(LPCOLESTR16 oleStr) +{ + BSTR16 out; + + if (!oleStr) return 0; + + out = BSTR_AllocBytes(strlen(oleStr)+1); + if (!out) return 0; + strcpy(BSTR_GetAddr(out),oleStr); + return out; +} + +/****************************************************************************** + * SysReallocString [OLE2DISP.3] + * + * Change the length of a previously created BSTR16 (16 Bit). + * + * PARAMS + * pbstr [I] BSTR16 to change the length of + * oleStr [I] New source for pbstr + * + * RETURNS + * Success: 1 + * Failure: 0. + * + * NOTES + * SysAllocStringStringLen16(). + */ +INT16 WINAPI SysReAllocString16(LPBSTR16 pbstr,LPCOLESTR16 oleStr) +{ + BSTR16 new=SysAllocString16(oleStr); + BSTR_Free(*pbstr); + *pbstr=new; + return 1; +} + +/****************************************************************************** + * SysAllocStringLen [OLE2DISP.4] + * + * Create a BSTR16 from an OLESTR16 of a given character length (16 Bit). + * + * PARAMS + * oleStr [I] Source to create BSTR16 from + * len [I] Length of oleStr in wide characters + * + * RETURNS + * Success: A newly allocated BSTR16 from SysAllocStringByteLen16() + * Failure: NULL, if len is >= 0x80000000, or memory allocation fails. + * + * NOTES + * See SysAllocStringByteLen16(). + */ +BSTR16 WINAPI SysAllocStringLen16(const char *oleStr, int len) +{ + BSTR16 out=BSTR_AllocBytes(len+1); + + if (!out) + return 0; + + /* + * Copy the information in the buffer. + * Since it is valid to pass a NULL pointer here, we'll initialize the + * buffer to nul if it is the case. + */ + if (oleStr != 0) + strcpy(BSTR_GetAddr(out),oleStr); + else + memset(BSTR_GetAddr(out), 0, len+1); + + return out; +} + +/****************************************************************************** + * SysReAllocStringLen [OLE2DISP.5] + * + * Change the length of a previously created BSTR16 (16 Bit). + * + * PARAMS + * pbstr [I] BSTR16 to change the length of + * oleStr [I] New source for pbstr + * len [I] Length of oleStr in characters + * + * RETURNS + * Success: 1. The size of pbstr is updated. + * Failure: 0, if len >= 0x8000 or memory allocation fails. + * + * NOTES + * See SysAllocStringByteLen16(). + * *pbstr may be changed by this function. + */ +int WINAPI SysReAllocStringLen16(BSTR16 *old,const char *in,int len) +{ + /* FIXME: Check input length */ + BSTR16 new=SysAllocStringLen16(in,len); + BSTR_Free(*old); + *old=new; + return 1; +} + +/****************************************************************************** + * SysFreeString [OLE2DISP.6] + * + * Free a BSTR16 (16 Bit). + * + * PARAMS + * str [I] String to free. + * + * RETURNS + * Nothing. + */ +void WINAPI SysFreeString16(BSTR16 str) +{ + BSTR_Free(str); +} + +/****************************************************************************** + * SysStringLen [OLE2DISP.7] + * + * Get the allocated length of a BSTR16 in characters (16 Bit). + * + * PARAMS + * str [I] BSTR16 to find the length of + * + * RETURNS + * The allocated length of str, or 0 if str is NULL. + */ +int WINAPI SysStringLen16(BSTR16 str) +{ + return strlen(BSTR_GetAddr(str)); +} + +/****************************************************************************** + * CreateDispTypeInfo [OLE2DISP.31] + */ +HRESULT WINAPI CreateDispTypeInfo16( + INTERFACEDATA *pidata, + LCID lcid, + ITypeInfo **pptinfo) +{ + FIXME("(%p,%ld,%p),stub\n",pidata,lcid,pptinfo); + return E_NOTIMPL; +} + +/****************************************************************************** + * CreateStdDispatch [OLE2DISP.32] + */ +HRESULT WINAPI CreateStdDispatch16( + IUnknown* punkOuter, + void* pvThis, + ITypeInfo* ptinfo, + IUnknown** ppunkStdDisp) +{ + FIXME("(%p,%p,%p,%p),stub\n",punkOuter, pvThis, ptinfo, + ppunkStdDisp); + return 0; +} + +/****************************************************************************** + * RegisterActiveObject [OLE2DISP.35] + */ +HRESULT WINAPI RegisterActiveObject16( + IUnknown *punk, REFCLSID rclsid, DWORD dwFlags, unsigned long *pdwRegister +) { + FIXME("(%p,%s,0x%08lx,%p):stub\n",punk,debugstr_guid(rclsid),dwFlags,pdwRegister); + return E_NOTIMPL; +} diff --git a/reactos/lib/oleaut32/ole2disp.h b/reactos/lib/oleaut32/ole2disp.h index 2ca2d09d34d..ec7c1c74e3c 100644 --- a/reactos/lib/oleaut32/ole2disp.h +++ b/reactos/lib/oleaut32/ole2disp.h @@ -1,42 +1,42 @@ -/* - * Copyright 1995 Martin von Loewis - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_OLEAUT32_OLE2DISP_H -#define __WINE_OLEAUT32_OLE2DISP_H - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "wtypes.h" -#include "wine/windef16.h" - -typedef CHAR OLECHAR16; -typedef LPSTR LPOLESTR16; -typedef LPCSTR LPCOLESTR16; -typedef OLECHAR16 *BSTR16; -typedef BSTR16 *LPBSTR16; - -BSTR16 WINAPI SysAllocString16(LPCOLESTR16); -BSTR16 WINAPI SysAllocStringLen16(const char*, int); -VOID WINAPI SysFreeString16(BSTR16); -INT16 WINAPI SysReAllocString16(LPBSTR16,LPCOLESTR16); -int WINAPI SysReAllocStringLen16(BSTR16*, const char*, int); -int WINAPI SysStringLen16(BSTR16); - -#endif /* !defined(__WINE_OLEAUT32_OLE2DISP_H) */ +/* + * Copyright 1995 Martin von Loewis + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_OLEAUT32_OLE2DISP_H +#define __WINE_OLEAUT32_OLE2DISP_H + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "wtypes.h" +#include "wine/windef16.h" + +typedef CHAR OLECHAR16; +typedef LPSTR LPOLESTR16; +typedef LPCSTR LPCOLESTR16; +typedef OLECHAR16 *BSTR16; +typedef BSTR16 *LPBSTR16; + +BSTR16 WINAPI SysAllocString16(LPCOLESTR16); +BSTR16 WINAPI SysAllocStringLen16(const char*, int); +VOID WINAPI SysFreeString16(BSTR16); +INT16 WINAPI SysReAllocString16(LPBSTR16,LPCOLESTR16); +int WINAPI SysReAllocStringLen16(BSTR16*, const char*, int); +int WINAPI SysStringLen16(BSTR16); + +#endif /* !defined(__WINE_OLEAUT32_OLE2DISP_H) */ diff --git a/reactos/lib/oleaut32/oleaut.c b/reactos/lib/oleaut32/oleaut.c index 6105baa83b9..1527fed33b7 100644 --- a/reactos/lib/oleaut32/oleaut.c +++ b/reactos/lib/oleaut32/oleaut.c @@ -1,732 +1,732 @@ -/* - * OLEAUT32 - * - * Copyright 1999, 2000 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> -#include <string.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winerror.h" - -#include "ole2.h" -#include "olectl.h" -#include "oleauto.h" - -#include "tmarshal.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/* The OLE Automation ProxyStub Interface Class (aka Typelib Marshaler) */ -extern const GUID CLSID_PSOAInterface; - -/* IDispatch marshaler */ -extern const GUID CLSID_PSDispatch; - -static BOOL BSTR_bCache = TRUE; /* Cache allocations to minimise alloc calls? */ - -HMODULE OLEAUT32_hModule = NULL; - -/****************************************************************************** - * BSTR {OLEAUT32} - * - * NOTES - * BSTR is a simple typedef for a wide-character string used as the principle - * string type in ole automation. When encapsulated in a Variant type they are - * automatically copied and destroyed as the variant is processed. - * - * The low level BSTR Api allows manipulation of these strings and is used by - * higher level Api calls to manage the strings transparently to the caller. - * - * Internally the BSTR type is allocated with space for a DWORD byte count before - * the string data begins. This is undocumented and non-system code should not - * access the count directly. Use SysStringLen() or SysStringByteLen() - * instead. Note that the byte count does not include the terminating NUL. - * - * To create a new BSTR, use SysAllocString(), SysAllocStringLen() or - * SysAllocStringByteLen(). To change the size of an existing BSTR, use SysReAllocString() - * or SysReAllocStringLen(). Finally to destroy a string use SysFreeString(). - * - * BSTR's are cached by Ole Automation by default. To override this behaviour - * either set the environment variable 'OANOCACHE', or call SetOaNoCache(). - * - * SEE ALSO - * 'Inside OLE, second edition' by Kraig Brockshmidt. - */ - -/****************************************************************************** - * SysStringLen [OLEAUT32.7] - * - * Get the allocated length of a BSTR in wide characters. - * - * PARAMS - * str [I] BSTR to find the length of - * - * RETURNS - * The allocated length of str, or 0 if str is NULL. - * - * NOTES - * See BSTR. - * The returned length may be different from the length of the string as - * calculated by lstrlenW(), since it returns the length that was used to - * allocate the string by SysAllocStringLen(). - */ -UINT WINAPI SysStringLen(BSTR str) -{ - DWORD* bufferPointer; - - if (!str) return 0; - /* - * The length of the string (in bytes) is contained in a DWORD placed - * just before the BSTR pointer - */ - bufferPointer = (DWORD*)str; - - bufferPointer--; - - return (int)(*bufferPointer/sizeof(WCHAR)); -} - -/****************************************************************************** - * SysStringByteLen [OLEAUT32.149] - * - * Get the allocated length of a BSTR in bytes. - * - * PARAMS - * str [I] BSTR to find the length of - * - * RETURNS - * The allocated length of str, or 0 if str is NULL. - * - * NOTES - * See SysStringLen(), BSTR(). - */ -UINT WINAPI SysStringByteLen(BSTR str) -{ - DWORD* bufferPointer; - - if (!str) return 0; - /* - * The length of the string (in bytes) is contained in a DWORD placed - * just before the BSTR pointer - */ - bufferPointer = (DWORD*)str; - - bufferPointer--; - - return (int)(*bufferPointer); -} - -/****************************************************************************** - * SysAllocString [OLEAUT32.2] - * - * Create a BSTR from an OLESTR. - * - * PARAMS - * str [I] Source to create BSTR from - * - * RETURNS - * Success: A BSTR allocated with SysAllocStringLen(). - * Failure: NULL, if oleStr is NULL. - * - * NOTES - * See BSTR. - * MSDN (October 2001) incorrectly states that NULL is returned if oleStr has - * a length of 0. Native Win32 and this implementation both return a valid - * empty BSTR in this case. - */ -BSTR WINAPI SysAllocString(LPCOLESTR str) -{ - if (!str) return 0; - - /* Delegate this to the SysAllocStringLen32 method. */ - return SysAllocStringLen(str, lstrlenW(str)); -} - -/****************************************************************************** - * SysFreeString [OLEAUT32.6] - * - * Free a BSTR. - * - * PARAMS - * str [I] BSTR to free. - * - * RETURNS - * Nothing. - * - * NOTES - * See BSTR. - * str may be NULL, in which case this function does nothing. - */ -void WINAPI SysFreeString(BSTR str) -{ - DWORD* bufferPointer; - - /* NULL is a valid parameter */ - if(!str) return; - - /* - * We have to be careful when we free a BSTR pointer, it points to - * the beginning of the string but it skips the byte count contained - * before the string. - */ - bufferPointer = (DWORD*)str; - - bufferPointer--; - - /* - * Free the memory from its "real" origin. - */ - HeapFree(GetProcessHeap(), 0, bufferPointer); -} - -/****************************************************************************** - * SysAllocStringLen [OLEAUT32.4] - * - * Create a BSTR from an OLESTR of a given wide character length. - * - * PARAMS - * str [I] Source to create BSTR from - * len [I] Length of oleStr in wide characters - * - * RETURNS - * Success: A newly allocated BSTR from SysAllocStringByteLen() - * Failure: NULL, if len is >= 0x80000000, or memory allocation fails. - * - * NOTES - * See BSTR(), SysAllocStringByteLen(). - */ -BSTR WINAPI SysAllocStringLen(const OLECHAR *str, unsigned int len) -{ - DWORD bufferSize; - DWORD* newBuffer; - WCHAR* stringBuffer; - - /* - * Find the length of the buffer passed-in in bytes. - */ - bufferSize = len * sizeof (WCHAR); - - /* - * Allocate a new buffer to hold the string. - * don't forget to keep an empty spot at the beginning of the - * buffer for the character count and an extra character at the - * end for the NULL. - */ - newBuffer = HeapAlloc(GetProcessHeap(), 0, - bufferSize + sizeof(WCHAR) + sizeof(DWORD)); - - /* - * If the memory allocation failed, return a null pointer. - */ - if (newBuffer==0) - return 0; - - /* - * Copy the length of the string in the placeholder. - */ - *newBuffer = bufferSize; - - /* - * Skip the byte count. - */ - newBuffer++; - - /* - * Copy the information in the buffer. - * Since it is valid to pass a NULL pointer here, we'll initialize the - * buffer to nul if it is the case. - */ - if (str != 0) - memcpy(newBuffer, str, bufferSize); - else - memset(newBuffer, 0, bufferSize); - - /* - * Make sure that there is a nul character at the end of the - * string. - */ - stringBuffer = (WCHAR*)newBuffer; - stringBuffer[len] = L'\0'; - - return (LPWSTR)stringBuffer; -} - -/****************************************************************************** - * SysReAllocStringLen [OLEAUT32.5] - * - * Change the length of a previously created BSTR. - * - * PARAMS - * old [O] BSTR to change the length of - * str [I] New source for pbstr - * len [I] Length of oleStr in wide characters - * - * RETURNS - * Success: 1. The size of pbstr is updated. - * Failure: 0, if len >= 0x80000000 or memory allocation fails. - * - * NOTES - * See BSTR(), SysAllocStringByteLen(). - * *pbstr may be changed by this function. - */ -int WINAPI SysReAllocStringLen(BSTR* old, const OLECHAR* str, unsigned int len) -{ - if (*old!=NULL) { - DWORD newbytelen = len*sizeof(WCHAR); - DWORD *ptr = HeapReAlloc(GetProcessHeap(),0,((DWORD*)*old)-1,newbytelen+sizeof(WCHAR)+sizeof(DWORD)); - *old = (BSTR)(ptr+1); - *ptr = newbytelen; - if (str) { - memcpy(*old, str, newbytelen); - (*old)[len] = 0; - } else { - /* Subtle hidden feature: The old string data is still there - * when 'in' is NULL! - * Some Microsoft program needs it. - */ - } - } else { - /* - * Allocate the new string - */ - *old = SysAllocStringLen(str, len); - } - - return 1; -} - -/****************************************************************************** - * SysAllocStringByteLen [OLEAUT32.150] - * - * Create a BSTR from an OLESTR of a given byte length. - * - * PARAMS - * str [I] Source to create BSTR from - * len [I] Length of oleStr in bytes - * - * RETURNS - * Success: A newly allocated BSTR - * Failure: NULL, if len is >= 0x80000000, or memory allocation fails. - * - * NOTES - * -If len is 0 or oleStr is NULL the resulting string is empty (""). - * -This function always NUL terminates the resulting BSTR. - * -oleStr may be either an LPCSTR or LPCOLESTR, since it is copied - * without checking for a terminating NUL. - * See BSTR. - */ -BSTR WINAPI SysAllocStringByteLen(LPCSTR str, UINT len) -{ - DWORD* newBuffer; - char* stringBuffer; - - /* - * Allocate a new buffer to hold the string. - * don't forget to keep an empty spot at the beginning of the - * buffer for the character count and an extra character at the - * end for the NULL. - */ - newBuffer = HeapAlloc(GetProcessHeap(), 0, - len + sizeof(WCHAR) + sizeof(DWORD)); - - /* - * If the memory allocation failed, return a null pointer. - */ - if (newBuffer==0) - return 0; - - /* - * Copy the length of the string in the placeholder. - */ - *newBuffer = len; - - /* - * Skip the byte count. - */ - newBuffer++; - - /* - * Copy the information in the buffer. - * Since it is valid to pass a NULL pointer here, we'll initialize the - * buffer to nul if it is the case. - */ - if (str != 0) - memcpy(newBuffer, str, len); - - /* - * Make sure that there is a nul character at the end of the - * string. - */ - stringBuffer = (char *)newBuffer; - stringBuffer[len] = 0; - stringBuffer[len+1] = 0; - - return (LPWSTR)stringBuffer; -} - -/****************************************************************************** - * SysReAllocString [OLEAUT32.3] - * - * Change the length of a previously created BSTR. - * - * PARAMS - * old [I/O] BSTR to change the length of - * str [I] New source for pbstr - * - * RETURNS - * Success: 1 - * Failure: 0. - * - * NOTES - * See BSTR(), SysAllocStringStringLen(). - */ -INT WINAPI SysReAllocString(LPBSTR old,LPCOLESTR str) -{ - /* - * Sanity check - */ - if (old==NULL) - return 0; - - /* - * Make sure we free the old string. - */ - if (*old!=NULL) - SysFreeString(*old); - - /* - * Allocate the new string - */ - *old = SysAllocString(str); - - return 1; -} - -/****************************************************************************** - * SetOaNoCache (OLEAUT32.327) - * - * Instruct Ole Automation not to cache BSTR allocations. - * - * PARAMS - * None. - * - * RETURNS - * Nothing. - * - * NOTES - * See BSTR. - */ -void WINAPI SetOaNoCache(void) -{ - BSTR_bCache = FALSE; -} - -static WCHAR _delimiter[2] = {'!',0}; /* default delimiter apparently */ -static WCHAR *pdelimiter = &_delimiter[0]; - -/*********************************************************************** - * RegisterActiveObject (OLEAUT32.33) - */ -HRESULT WINAPI RegisterActiveObject( - LPUNKNOWN punk,REFCLSID rcid,DWORD dwFlags,LPDWORD pdwRegister -) { - WCHAR guidbuf[80]; - HRESULT ret; - LPRUNNINGOBJECTTABLE runobtable; - LPMONIKER moniker; - - StringFromGUID2(rcid,guidbuf,39); - ret = CreateItemMoniker(pdelimiter,guidbuf,&moniker); - if (FAILED(ret)) - return ret; - ret = GetRunningObjectTable(0,&runobtable); - if (FAILED(ret)) { - IMoniker_Release(moniker); - return ret; - } - ret = IRunningObjectTable_Register(runobtable,dwFlags,punk,moniker,pdwRegister); - IRunningObjectTable_Release(runobtable); - IMoniker_Release(moniker); - return ret; -} - -/*********************************************************************** - * RevokeActiveObject (OLEAUT32.34) - */ -HRESULT WINAPI RevokeActiveObject(DWORD xregister,LPVOID reserved) -{ - LPRUNNINGOBJECTTABLE runobtable; - HRESULT ret; - - ret = GetRunningObjectTable(0,&runobtable); - if (FAILED(ret)) return ret; - ret = IRunningObjectTable_Revoke(runobtable,xregister); - if (SUCCEEDED(ret)) ret = S_OK; - IRunningObjectTable_Release(runobtable); - return ret; -} - -/*********************************************************************** - * GetActiveObject (OLEAUT32.35) - */ -HRESULT WINAPI GetActiveObject(REFCLSID rcid,LPVOID preserved,LPUNKNOWN *ppunk) -{ - WCHAR guidbuf[80]; - HRESULT ret; - LPRUNNINGOBJECTTABLE runobtable; - LPMONIKER moniker; - - StringFromGUID2(rcid,guidbuf,39); - ret = CreateItemMoniker(pdelimiter,guidbuf,&moniker); - if (FAILED(ret)) - return ret; - ret = GetRunningObjectTable(0,&runobtable); - if (FAILED(ret)) { - IMoniker_Release(moniker); - return ret; - } - ret = IRunningObjectTable_GetObject(runobtable,moniker,ppunk); - IRunningObjectTable_Release(runobtable); - IMoniker_Release(moniker); - return ret; -} - - -/*********************************************************************** - * OaBuildVersion [OLEAUT32.170] - * - * Get the Ole Automation build version. - * - * PARAMS - * None - * - * RETURNS - * The build version. - * - * NOTES - * Known oleaut32.dll versions: - *| OLE Ver. Comments Date Build Ver. - *| -------- ------------------------- ---- --------- - *| OLE 2.1 NT 1993-95 10 3023 - *| OLE 2.1 10 3027 - *| Win32s Ver 1.1e 20 4049 - *| OLE 2.20 W95/NT 1993-96 20 4112 - *| OLE 2.20 W95/NT 1993-96 20 4118 - *| OLE 2.20 W95/NT 1993-96 20 4122 - *| OLE 2.30 W95/NT 1993-98 30 4265 - *| OLE 2.40 NT?? 1993-98 40 4267 - *| OLE 2.40 W98 SE orig. file 1993-98 40 4275 - *| OLE 2.40 W2K orig. file 1993-XX 40 4514 - * - * Currently the versions returned are 2.20 for Win3.1, 2.30 for Win95 & NT 3.51, - * and 2.40 for all later versions. The build number is maximum, i.e. 0xffff. - */ -ULONG WINAPI OaBuildVersion() -{ - switch(GetVersion() & 0x8000ffff) /* mask off build number */ - { - case 0x80000a03: /* WIN31 */ - return MAKELONG(0xffff, 20); - case 0x00003303: /* NT351 */ - return MAKELONG(0xffff, 30); - case 0x80000004: /* WIN95; I'd like to use the "standard" w95 minor - version here (30), but as we still use w95 - as default winver (which is good IMHO), I better - play safe and use the latest value for w95 for now. - Change this as soon as default winver gets changed - to something more recent */ - case 0x80000a04: /* WIN98 */ - case 0x00000004: /* NT40 */ - case 0x00000005: /* W2K */ - case 0x00000105: /* WinXP */ - return MAKELONG(0xffff, 40); - default: - FIXME("Version value not known yet. Please investigate it !\n"); - return MAKELONG(0xffff, 40); /* for now return the same value as for w2k */ - } -} - -/****************************************************************************** - * OleTranslateColor [OLEAUT32.421] - * - * Convert an OLE_COLOR to a COLORREF. - * - * PARAMS - * clr [I] Color to convert - * hpal [I] Handle to a palette for the conversion - * pColorRef [O] Destination for converted color, or NULL to test if the conversion is ok - * - * RETURNS - * Success: S_OK. The conversion is ok, and pColorRef contains the converted color if non-NULL. - * Failure: E_INVALIDARG, if any argument is invalid. - * - * FIXME - * Document the conversion rules. - */ -HRESULT WINAPI OleTranslateColor( - OLE_COLOR clr, - HPALETTE hpal, - COLORREF* pColorRef) -{ - COLORREF colorref; - BYTE b = HIBYTE(HIWORD(clr)); - - TRACE("(%08lx, %p, %p):stub\n", clr, hpal, pColorRef); - - /* - * In case pColorRef is NULL, provide our own to simplify the code. - */ - if (pColorRef == NULL) - pColorRef = &colorref; - - switch (b) - { - case 0x00: - { - if (hpal != 0) - *pColorRef = PALETTERGB(GetRValue(clr), - GetGValue(clr), - GetBValue(clr)); - else - *pColorRef = clr; - - break; - } - - case 0x01: - { - if (hpal != 0) - { - PALETTEENTRY pe; - /* - * Validate the palette index. - */ - if (GetPaletteEntries(hpal, LOWORD(clr), 1, &pe) == 0) - return E_INVALIDARG; - } - - *pColorRef = clr; - - break; - } - - case 0x02: - *pColorRef = clr; - break; - - case 0x80: - { - int index = LOBYTE(LOWORD(clr)); - - /* - * Validate GetSysColor index. - */ - if ((index < COLOR_SCROLLBAR) || (index > COLOR_MENUBAR)) - return E_INVALIDARG; - - *pColorRef = GetSysColor(index); - - break; - } - - default: - return E_INVALIDARG; - } - - return S_OK; -} - -extern HRESULT OLEAUTPS_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv); - -extern void _get_STDFONT_CF(LPVOID); -extern void _get_STDPIC_CF(LPVOID); - -/*********************************************************************** - * DllGetClassObject (OLEAUT32.1) - */ -HRESULT WINAPI OLEAUT32_DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv) -{ - *ppv = NULL; - if (IsEqualGUID(rclsid,&CLSID_StdFont)) { - if (IsEqualGUID(iid,&IID_IClassFactory)) { - _get_STDFONT_CF(ppv); - IClassFactory_AddRef((IClassFactory*)*ppv); - return S_OK; - } - } - if (IsEqualGUID(rclsid,&CLSID_StdPicture)) { - if (IsEqualGUID(iid,&IID_IClassFactory)) { - _get_STDPIC_CF(ppv); - IClassFactory_AddRef((IClassFactory*)*ppv); - return S_OK; - } - } - if (IsEqualGUID(rclsid,&CLSID_PSDispatch)) { - return OLEAUTPS_DllGetClassObject(rclsid,iid,ppv); - } - if (IsEqualGUID(rclsid,&CLSID_PSOAInterface)) { - if (S_OK==TypeLibFac_DllGetClassObject(rclsid,iid,ppv)) - return S_OK; - /*FALLTHROUGH*/ - } - FIXME("\n\tCLSID:\t%s,\n\tIID:\t%s\n",debugstr_guid(rclsid),debugstr_guid(iid)); - return CLASS_E_CLASSNOTAVAILABLE; -} - -/*********************************************************************** - * DllCanUnloadNow (OLEAUT32.410) - * - * Determine if this dll can be unloaded from the callers address space. - * - * PARAMS - * None. - * - * RETURNS - * Always returns S_FALSE. This dll cannot be unloaded. - */ -HRESULT WINAPI OLEAUT32_DllCanUnloadNow(void) -{ - return S_FALSE; -} - -/***************************************************************************** - * DllMain [OLEAUT32.@] - */ -BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved) -{ - TRACE("(%p,%lu,%p)\n", hInstDll, fdwReason, lpvReserved); - - switch (fdwReason) { - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(hInstDll); - OLEAUT32_hModule = (HMODULE)hInstDll; - break; - case DLL_PROCESS_DETACH: - break; - }; - - return TRUE; -} +/* + * OLEAUT32 + * + * Copyright 1999, 2000 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> +#include <string.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winerror.h" + +#include "ole2.h" +#include "olectl.h" +#include "oleauto.h" + +#include "tmarshal.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/* The OLE Automation ProxyStub Interface Class (aka Typelib Marshaler) */ +extern const GUID CLSID_PSOAInterface; + +/* IDispatch marshaler */ +extern const GUID CLSID_PSDispatch; + +static BOOL BSTR_bCache = TRUE; /* Cache allocations to minimise alloc calls? */ + +HMODULE OLEAUT32_hModule = NULL; + +/****************************************************************************** + * BSTR {OLEAUT32} + * + * NOTES + * BSTR is a simple typedef for a wide-character string used as the principle + * string type in ole automation. When encapsulated in a Variant type they are + * automatically copied and destroyed as the variant is processed. + * + * The low level BSTR Api allows manipulation of these strings and is used by + * higher level Api calls to manage the strings transparently to the caller. + * + * Internally the BSTR type is allocated with space for a DWORD byte count before + * the string data begins. This is undocumented and non-system code should not + * access the count directly. Use SysStringLen() or SysStringByteLen() + * instead. Note that the byte count does not include the terminating NUL. + * + * To create a new BSTR, use SysAllocString(), SysAllocStringLen() or + * SysAllocStringByteLen(). To change the size of an existing BSTR, use SysReAllocString() + * or SysReAllocStringLen(). Finally to destroy a string use SysFreeString(). + * + * BSTR's are cached by Ole Automation by default. To override this behaviour + * either set the environment variable 'OANOCACHE', or call SetOaNoCache(). + * + * SEE ALSO + * 'Inside OLE, second edition' by Kraig Brockshmidt. + */ + +/****************************************************************************** + * SysStringLen [OLEAUT32.7] + * + * Get the allocated length of a BSTR in wide characters. + * + * PARAMS + * str [I] BSTR to find the length of + * + * RETURNS + * The allocated length of str, or 0 if str is NULL. + * + * NOTES + * See BSTR. + * The returned length may be different from the length of the string as + * calculated by lstrlenW(), since it returns the length that was used to + * allocate the string by SysAllocStringLen(). + */ +UINT WINAPI SysStringLen(BSTR str) +{ + DWORD* bufferPointer; + + if (!str) return 0; + /* + * The length of the string (in bytes) is contained in a DWORD placed + * just before the BSTR pointer + */ + bufferPointer = (DWORD*)str; + + bufferPointer--; + + return (int)(*bufferPointer/sizeof(WCHAR)); +} + +/****************************************************************************** + * SysStringByteLen [OLEAUT32.149] + * + * Get the allocated length of a BSTR in bytes. + * + * PARAMS + * str [I] BSTR to find the length of + * + * RETURNS + * The allocated length of str, or 0 if str is NULL. + * + * NOTES + * See SysStringLen(), BSTR(). + */ +UINT WINAPI SysStringByteLen(BSTR str) +{ + DWORD* bufferPointer; + + if (!str) return 0; + /* + * The length of the string (in bytes) is contained in a DWORD placed + * just before the BSTR pointer + */ + bufferPointer = (DWORD*)str; + + bufferPointer--; + + return (int)(*bufferPointer); +} + +/****************************************************************************** + * SysAllocString [OLEAUT32.2] + * + * Create a BSTR from an OLESTR. + * + * PARAMS + * str [I] Source to create BSTR from + * + * RETURNS + * Success: A BSTR allocated with SysAllocStringLen(). + * Failure: NULL, if oleStr is NULL. + * + * NOTES + * See BSTR. + * MSDN (October 2001) incorrectly states that NULL is returned if oleStr has + * a length of 0. Native Win32 and this implementation both return a valid + * empty BSTR in this case. + */ +BSTR WINAPI SysAllocString(LPCOLESTR str) +{ + if (!str) return 0; + + /* Delegate this to the SysAllocStringLen32 method. */ + return SysAllocStringLen(str, lstrlenW(str)); +} + +/****************************************************************************** + * SysFreeString [OLEAUT32.6] + * + * Free a BSTR. + * + * PARAMS + * str [I] BSTR to free. + * + * RETURNS + * Nothing. + * + * NOTES + * See BSTR. + * str may be NULL, in which case this function does nothing. + */ +void WINAPI SysFreeString(BSTR str) +{ + DWORD* bufferPointer; + + /* NULL is a valid parameter */ + if(!str) return; + + /* + * We have to be careful when we free a BSTR pointer, it points to + * the beginning of the string but it skips the byte count contained + * before the string. + */ + bufferPointer = (DWORD*)str; + + bufferPointer--; + + /* + * Free the memory from its "real" origin. + */ + HeapFree(GetProcessHeap(), 0, bufferPointer); +} + +/****************************************************************************** + * SysAllocStringLen [OLEAUT32.4] + * + * Create a BSTR from an OLESTR of a given wide character length. + * + * PARAMS + * str [I] Source to create BSTR from + * len [I] Length of oleStr in wide characters + * + * RETURNS + * Success: A newly allocated BSTR from SysAllocStringByteLen() + * Failure: NULL, if len is >= 0x80000000, or memory allocation fails. + * + * NOTES + * See BSTR(), SysAllocStringByteLen(). + */ +BSTR WINAPI SysAllocStringLen(const OLECHAR *str, unsigned int len) +{ + DWORD bufferSize; + DWORD* newBuffer; + WCHAR* stringBuffer; + + /* + * Find the length of the buffer passed-in in bytes. + */ + bufferSize = len * sizeof (WCHAR); + + /* + * Allocate a new buffer to hold the string. + * don't forget to keep an empty spot at the beginning of the + * buffer for the character count and an extra character at the + * end for the NULL. + */ + newBuffer = HeapAlloc(GetProcessHeap(), 0, + bufferSize + sizeof(WCHAR) + sizeof(DWORD)); + + /* + * If the memory allocation failed, return a null pointer. + */ + if (newBuffer==0) + return 0; + + /* + * Copy the length of the string in the placeholder. + */ + *newBuffer = bufferSize; + + /* + * Skip the byte count. + */ + newBuffer++; + + /* + * Copy the information in the buffer. + * Since it is valid to pass a NULL pointer here, we'll initialize the + * buffer to nul if it is the case. + */ + if (str != 0) + memcpy(newBuffer, str, bufferSize); + else + memset(newBuffer, 0, bufferSize); + + /* + * Make sure that there is a nul character at the end of the + * string. + */ + stringBuffer = (WCHAR*)newBuffer; + stringBuffer[len] = L'\0'; + + return (LPWSTR)stringBuffer; +} + +/****************************************************************************** + * SysReAllocStringLen [OLEAUT32.5] + * + * Change the length of a previously created BSTR. + * + * PARAMS + * old [O] BSTR to change the length of + * str [I] New source for pbstr + * len [I] Length of oleStr in wide characters + * + * RETURNS + * Success: 1. The size of pbstr is updated. + * Failure: 0, if len >= 0x80000000 or memory allocation fails. + * + * NOTES + * See BSTR(), SysAllocStringByteLen(). + * *pbstr may be changed by this function. + */ +int WINAPI SysReAllocStringLen(BSTR* old, const OLECHAR* str, unsigned int len) +{ + if (*old!=NULL) { + DWORD newbytelen = len*sizeof(WCHAR); + DWORD *ptr = HeapReAlloc(GetProcessHeap(),0,((DWORD*)*old)-1,newbytelen+sizeof(WCHAR)+sizeof(DWORD)); + *old = (BSTR)(ptr+1); + *ptr = newbytelen; + if (str) { + memcpy(*old, str, newbytelen); + (*old)[len] = 0; + } else { + /* Subtle hidden feature: The old string data is still there + * when 'in' is NULL! + * Some Microsoft program needs it. + */ + } + } else { + /* + * Allocate the new string + */ + *old = SysAllocStringLen(str, len); + } + + return 1; +} + +/****************************************************************************** + * SysAllocStringByteLen [OLEAUT32.150] + * + * Create a BSTR from an OLESTR of a given byte length. + * + * PARAMS + * str [I] Source to create BSTR from + * len [I] Length of oleStr in bytes + * + * RETURNS + * Success: A newly allocated BSTR + * Failure: NULL, if len is >= 0x80000000, or memory allocation fails. + * + * NOTES + * -If len is 0 or oleStr is NULL the resulting string is empty (""). + * -This function always NUL terminates the resulting BSTR. + * -oleStr may be either an LPCSTR or LPCOLESTR, since it is copied + * without checking for a terminating NUL. + * See BSTR. + */ +BSTR WINAPI SysAllocStringByteLen(LPCSTR str, UINT len) +{ + DWORD* newBuffer; + char* stringBuffer; + + /* + * Allocate a new buffer to hold the string. + * don't forget to keep an empty spot at the beginning of the + * buffer for the character count and an extra character at the + * end for the NULL. + */ + newBuffer = HeapAlloc(GetProcessHeap(), 0, + len + sizeof(WCHAR) + sizeof(DWORD)); + + /* + * If the memory allocation failed, return a null pointer. + */ + if (newBuffer==0) + return 0; + + /* + * Copy the length of the string in the placeholder. + */ + *newBuffer = len; + + /* + * Skip the byte count. + */ + newBuffer++; + + /* + * Copy the information in the buffer. + * Since it is valid to pass a NULL pointer here, we'll initialize the + * buffer to nul if it is the case. + */ + if (str != 0) + memcpy(newBuffer, str, len); + + /* + * Make sure that there is a nul character at the end of the + * string. + */ + stringBuffer = (char *)newBuffer; + stringBuffer[len] = 0; + stringBuffer[len+1] = 0; + + return (LPWSTR)stringBuffer; +} + +/****************************************************************************** + * SysReAllocString [OLEAUT32.3] + * + * Change the length of a previously created BSTR. + * + * PARAMS + * old [I/O] BSTR to change the length of + * str [I] New source for pbstr + * + * RETURNS + * Success: 1 + * Failure: 0. + * + * NOTES + * See BSTR(), SysAllocStringStringLen(). + */ +INT WINAPI SysReAllocString(LPBSTR old,LPCOLESTR str) +{ + /* + * Sanity check + */ + if (old==NULL) + return 0; + + /* + * Make sure we free the old string. + */ + if (*old!=NULL) + SysFreeString(*old); + + /* + * Allocate the new string + */ + *old = SysAllocString(str); + + return 1; +} + +/****************************************************************************** + * SetOaNoCache (OLEAUT32.327) + * + * Instruct Ole Automation not to cache BSTR allocations. + * + * PARAMS + * None. + * + * RETURNS + * Nothing. + * + * NOTES + * See BSTR. + */ +void WINAPI SetOaNoCache(void) +{ + BSTR_bCache = FALSE; +} + +static WCHAR _delimiter[2] = {'!',0}; /* default delimiter apparently */ +static WCHAR *pdelimiter = &_delimiter[0]; + +/*********************************************************************** + * RegisterActiveObject (OLEAUT32.33) + */ +HRESULT WINAPI RegisterActiveObject( + LPUNKNOWN punk,REFCLSID rcid,DWORD dwFlags,LPDWORD pdwRegister +) { + WCHAR guidbuf[80]; + HRESULT ret; + LPRUNNINGOBJECTTABLE runobtable; + LPMONIKER moniker; + + StringFromGUID2(rcid,guidbuf,39); + ret = CreateItemMoniker(pdelimiter,guidbuf,&moniker); + if (FAILED(ret)) + return ret; + ret = GetRunningObjectTable(0,&runobtable); + if (FAILED(ret)) { + IMoniker_Release(moniker); + return ret; + } + ret = IRunningObjectTable_Register(runobtable,dwFlags,punk,moniker,pdwRegister); + IRunningObjectTable_Release(runobtable); + IMoniker_Release(moniker); + return ret; +} + +/*********************************************************************** + * RevokeActiveObject (OLEAUT32.34) + */ +HRESULT WINAPI RevokeActiveObject(DWORD xregister,LPVOID reserved) +{ + LPRUNNINGOBJECTTABLE runobtable; + HRESULT ret; + + ret = GetRunningObjectTable(0,&runobtable); + if (FAILED(ret)) return ret; + ret = IRunningObjectTable_Revoke(runobtable,xregister); + if (SUCCEEDED(ret)) ret = S_OK; + IRunningObjectTable_Release(runobtable); + return ret; +} + +/*********************************************************************** + * GetActiveObject (OLEAUT32.35) + */ +HRESULT WINAPI GetActiveObject(REFCLSID rcid,LPVOID preserved,LPUNKNOWN *ppunk) +{ + WCHAR guidbuf[80]; + HRESULT ret; + LPRUNNINGOBJECTTABLE runobtable; + LPMONIKER moniker; + + StringFromGUID2(rcid,guidbuf,39); + ret = CreateItemMoniker(pdelimiter,guidbuf,&moniker); + if (FAILED(ret)) + return ret; + ret = GetRunningObjectTable(0,&runobtable); + if (FAILED(ret)) { + IMoniker_Release(moniker); + return ret; + } + ret = IRunningObjectTable_GetObject(runobtable,moniker,ppunk); + IRunningObjectTable_Release(runobtable); + IMoniker_Release(moniker); + return ret; +} + + +/*********************************************************************** + * OaBuildVersion [OLEAUT32.170] + * + * Get the Ole Automation build version. + * + * PARAMS + * None + * + * RETURNS + * The build version. + * + * NOTES + * Known oleaut32.dll versions: + *| OLE Ver. Comments Date Build Ver. + *| -------- ------------------------- ---- --------- + *| OLE 2.1 NT 1993-95 10 3023 + *| OLE 2.1 10 3027 + *| Win32s Ver 1.1e 20 4049 + *| OLE 2.20 W95/NT 1993-96 20 4112 + *| OLE 2.20 W95/NT 1993-96 20 4118 + *| OLE 2.20 W95/NT 1993-96 20 4122 + *| OLE 2.30 W95/NT 1993-98 30 4265 + *| OLE 2.40 NT?? 1993-98 40 4267 + *| OLE 2.40 W98 SE orig. file 1993-98 40 4275 + *| OLE 2.40 W2K orig. file 1993-XX 40 4514 + * + * Currently the versions returned are 2.20 for Win3.1, 2.30 for Win95 & NT 3.51, + * and 2.40 for all later versions. The build number is maximum, i.e. 0xffff. + */ +ULONG WINAPI OaBuildVersion() +{ + switch(GetVersion() & 0x8000ffff) /* mask off build number */ + { + case 0x80000a03: /* WIN31 */ + return MAKELONG(0xffff, 20); + case 0x00003303: /* NT351 */ + return MAKELONG(0xffff, 30); + case 0x80000004: /* WIN95; I'd like to use the "standard" w95 minor + version here (30), but as we still use w95 + as default winver (which is good IMHO), I better + play safe and use the latest value for w95 for now. + Change this as soon as default winver gets changed + to something more recent */ + case 0x80000a04: /* WIN98 */ + case 0x00000004: /* NT40 */ + case 0x00000005: /* W2K */ + case 0x00000105: /* WinXP */ + return MAKELONG(0xffff, 40); + default: + FIXME("Version value not known yet. Please investigate it !\n"); + return MAKELONG(0xffff, 40); /* for now return the same value as for w2k */ + } +} + +/****************************************************************************** + * OleTranslateColor [OLEAUT32.421] + * + * Convert an OLE_COLOR to a COLORREF. + * + * PARAMS + * clr [I] Color to convert + * hpal [I] Handle to a palette for the conversion + * pColorRef [O] Destination for converted color, or NULL to test if the conversion is ok + * + * RETURNS + * Success: S_OK. The conversion is ok, and pColorRef contains the converted color if non-NULL. + * Failure: E_INVALIDARG, if any argument is invalid. + * + * FIXME + * Document the conversion rules. + */ +HRESULT WINAPI OleTranslateColor( + OLE_COLOR clr, + HPALETTE hpal, + COLORREF* pColorRef) +{ + COLORREF colorref; + BYTE b = HIBYTE(HIWORD(clr)); + + TRACE("(%08lx, %p, %p):stub\n", clr, hpal, pColorRef); + + /* + * In case pColorRef is NULL, provide our own to simplify the code. + */ + if (pColorRef == NULL) + pColorRef = &colorref; + + switch (b) + { + case 0x00: + { + if (hpal != 0) + *pColorRef = PALETTERGB(GetRValue(clr), + GetGValue(clr), + GetBValue(clr)); + else + *pColorRef = clr; + + break; + } + + case 0x01: + { + if (hpal != 0) + { + PALETTEENTRY pe; + /* + * Validate the palette index. + */ + if (GetPaletteEntries(hpal, LOWORD(clr), 1, &pe) == 0) + return E_INVALIDARG; + } + + *pColorRef = clr; + + break; + } + + case 0x02: + *pColorRef = clr; + break; + + case 0x80: + { + int index = LOBYTE(LOWORD(clr)); + + /* + * Validate GetSysColor index. + */ + if ((index < COLOR_SCROLLBAR) || (index > COLOR_MENUBAR)) + return E_INVALIDARG; + + *pColorRef = GetSysColor(index); + + break; + } + + default: + return E_INVALIDARG; + } + + return S_OK; +} + +extern HRESULT OLEAUTPS_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv); + +extern void _get_STDFONT_CF(LPVOID); +extern void _get_STDPIC_CF(LPVOID); + +/*********************************************************************** + * DllGetClassObject (OLEAUT32.1) + */ +HRESULT WINAPI OLEAUT32_DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv) +{ + *ppv = NULL; + if (IsEqualGUID(rclsid,&CLSID_StdFont)) { + if (IsEqualGUID(iid,&IID_IClassFactory)) { + _get_STDFONT_CF(ppv); + IClassFactory_AddRef((IClassFactory*)*ppv); + return S_OK; + } + } + if (IsEqualGUID(rclsid,&CLSID_StdPicture)) { + if (IsEqualGUID(iid,&IID_IClassFactory)) { + _get_STDPIC_CF(ppv); + IClassFactory_AddRef((IClassFactory*)*ppv); + return S_OK; + } + } + if (IsEqualGUID(rclsid,&CLSID_PSDispatch)) { + return OLEAUTPS_DllGetClassObject(rclsid,iid,ppv); + } + if (IsEqualGUID(rclsid,&CLSID_PSOAInterface)) { + if (S_OK==TypeLibFac_DllGetClassObject(rclsid,iid,ppv)) + return S_OK; + /*FALLTHROUGH*/ + } + FIXME("\n\tCLSID:\t%s,\n\tIID:\t%s\n",debugstr_guid(rclsid),debugstr_guid(iid)); + return CLASS_E_CLASSNOTAVAILABLE; +} + +/*********************************************************************** + * DllCanUnloadNow (OLEAUT32.410) + * + * Determine if this dll can be unloaded from the callers address space. + * + * PARAMS + * None. + * + * RETURNS + * Always returns S_FALSE. This dll cannot be unloaded. + */ +HRESULT WINAPI OLEAUT32_DllCanUnloadNow(void) +{ + return S_FALSE; +} + +/***************************************************************************** + * DllMain [OLEAUT32.@] + */ +BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved) +{ + TRACE("(%p,%lu,%p)\n", hInstDll, fdwReason, lpvReserved); + + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hInstDll); + OLEAUT32_hModule = (HMODULE)hInstDll; + break; + case DLL_PROCESS_DETACH: + break; + }; + + return TRUE; +} diff --git a/reactos/lib/oleaut32/olefont.c b/reactos/lib/oleaut32/olefont.c index 6ad98e2eb7d..eaceefe2d82 100644 --- a/reactos/lib/oleaut32/olefont.c +++ b/reactos/lib/oleaut32/olefont.c @@ -1,2149 +1,2149 @@ -/* - * OLE Font encapsulation implementation - * - * This file contains an implementation of the IFont - * interface and the OleCreateFontIndirect API call. - * - * Copyright 1999 Francis Beaudet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include <assert.h> -#include <stdarg.h> -#include <string.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "winerror.h" -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "wine/unicode.h" -#include "objbase.h" -#include "oleauto.h" /* for SysAllocString(....) */ -#include "ole2.h" -#include "olectl.h" -#include "wine/debug.h" -#include "connpt.h" /* for CreateConnectionPoint */ - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/*********************************************************************** - * Declaration of constants used when serializing the font object. - */ -#define FONTPERSIST_ITALIC 0x02 -#define FONTPERSIST_UNDERLINE 0x04 -#define FONTPERSIST_STRIKETHROUGH 0x08 - -/*********************************************************************** - * Declaration of the implementation class for the IFont interface - */ -typedef struct OLEFontImpl OLEFontImpl; - -struct OLEFontImpl -{ - /* - * This class supports many interfaces. IUnknown, IFont, - * IDispatch, IDispFont IPersistStream and IConnectionPointContainer. - * The first two are supported by the first vtable, the next two are - * supported by the second table and the last two have their own. - */ - IFontVtbl* lpvtbl1; - IDispatchVtbl* lpvtbl2; - IPersistStreamVtbl* lpvtbl3; - IConnectionPointContainerVtbl* lpvtbl4; - IPersistPropertyBagVtbl* lpvtbl5; - IPersistStreamInitVtbl* lpvtbl6; - /* - * Reference count for that instance of the class. - */ - ULONG ref; - - /* - * This structure contains the description of the class. - */ - FONTDESC description; - - /* - * Contain the font associated with this object. - */ - HFONT gdiFont; - - /* - * Font lock count. - */ - DWORD fontLock; - - /* - * Size ratio - */ - long cyLogical; - long cyHimetric; - - IConnectionPoint *pCP; -}; - -/* - * Here, I define utility macros to help with the casting of the - * "this" parameter. - * There is a version to accommodate all of the VTables implemented - * by this object. - */ -#define _ICOM_THIS_From_IDispatch(class, name) class* this = (class*)(((char*)name)-sizeof(void*)) -#define _ICOM_THIS_From_IPersistStream(class, name) class* this = (class*)(((char*)name)-2*sizeof(void*)) -#define _ICOM_THIS_From_IConnectionPointContainer(class, name) class* this = (class*)(((char*)name)-3*sizeof(void*)) -#define _ICOM_THIS_From_IPersistPropertyBag(class, name) class* this = (class*)(((char*)name)-4*sizeof(void*)) -#define _ICOM_THIS_From_IPersistStreamInit(class, name) class* this = (class*)(((char*)name)-5*sizeof(void*)) - - -/*********************************************************************** - * Prototypes for the implementation functions for the IFont - * interface - */ -static OLEFontImpl* OLEFontImpl_Construct(LPFONTDESC fontDesc); -static void OLEFontImpl_Destroy(OLEFontImpl* fontDesc); -static HRESULT WINAPI OLEFontImpl_QueryInterface(IFont* iface, REFIID riid, VOID** ppvoid); -static ULONG WINAPI OLEFontImpl_AddRef(IFont* iface); -static ULONG WINAPI OLEFontImpl_Release(IFont* iface); -static HRESULT WINAPI OLEFontImpl_get_Name(IFont* iface, BSTR* pname); -static HRESULT WINAPI OLEFontImpl_put_Name(IFont* iface, BSTR name); -static HRESULT WINAPI OLEFontImpl_get_Size(IFont* iface, CY* psize); -static HRESULT WINAPI OLEFontImpl_put_Size(IFont* iface, CY size); -static HRESULT WINAPI OLEFontImpl_get_Bold(IFont* iface, BOOL* pbold); -static HRESULT WINAPI OLEFontImpl_put_Bold(IFont* iface, BOOL bold); -static HRESULT WINAPI OLEFontImpl_get_Italic(IFont* iface, BOOL* pitalic); -static HRESULT WINAPI OLEFontImpl_put_Italic(IFont* iface, BOOL italic); -static HRESULT WINAPI OLEFontImpl_get_Underline(IFont* iface, BOOL* punderline); -static HRESULT WINAPI OLEFontImpl_put_Underline(IFont* iface, BOOL underline); -static HRESULT WINAPI OLEFontImpl_get_Strikethrough(IFont* iface, BOOL* pstrikethrough); -static HRESULT WINAPI OLEFontImpl_put_Strikethrough(IFont* iface, BOOL strikethrough); -static HRESULT WINAPI OLEFontImpl_get_Weight(IFont* iface, short* pweight); -static HRESULT WINAPI OLEFontImpl_put_Weight(IFont* iface, short weight); -static HRESULT WINAPI OLEFontImpl_get_Charset(IFont* iface, short* pcharset); -static HRESULT WINAPI OLEFontImpl_put_Charset(IFont* iface, short charset); -static HRESULT WINAPI OLEFontImpl_get_hFont(IFont* iface, HFONT* phfont); -static HRESULT WINAPI OLEFontImpl_Clone(IFont* iface, IFont** ppfont); -static HRESULT WINAPI OLEFontImpl_IsEqual(IFont* iface, IFont* pFontOther); -static HRESULT WINAPI OLEFontImpl_SetRatio(IFont* iface, LONG cyLogical, LONG cyHimetric); -static HRESULT WINAPI OLEFontImpl_QueryTextMetrics(IFont* iface, TEXTMETRICOLE* ptm); -static HRESULT WINAPI OLEFontImpl_AddRefHfont(IFont* iface, HFONT hfont); -static HRESULT WINAPI OLEFontImpl_ReleaseHfont(IFont* iface, HFONT hfont); -static HRESULT WINAPI OLEFontImpl_SetHdc(IFont* iface, HDC hdc); - -/*********************************************************************** - * Prototypes for the implementation functions for the IDispatch - * interface - */ -static HRESULT WINAPI OLEFontImpl_IDispatch_QueryInterface(IDispatch* iface, - REFIID riid, - VOID** ppvoid); -static ULONG WINAPI OLEFontImpl_IDispatch_AddRef(IDispatch* iface); -static ULONG WINAPI OLEFontImpl_IDispatch_Release(IDispatch* iface); -static HRESULT WINAPI OLEFontImpl_GetTypeInfoCount(IDispatch* iface, - unsigned int* pctinfo); -static HRESULT WINAPI OLEFontImpl_GetTypeInfo(IDispatch* iface, - UINT iTInfo, - LCID lcid, - ITypeInfo** ppTInfo); -static HRESULT WINAPI OLEFontImpl_GetIDsOfNames(IDispatch* iface, - REFIID riid, - LPOLESTR* rgszNames, - UINT cNames, - LCID lcid, - DISPID* rgDispId); -static HRESULT WINAPI OLEFontImpl_Invoke(IDispatch* iface, - DISPID dispIdMember, - REFIID riid, - LCID lcid, - WORD wFlags, - DISPPARAMS* pDispParams, - VARIANT* pVarResult, - EXCEPINFO* pExepInfo, - UINT* puArgErr); - -/*********************************************************************** - * Prototypes for the implementation functions for the IPersistStream - * interface - */ -static HRESULT WINAPI OLEFontImpl_IPersistStream_QueryInterface(IPersistStream* iface, - REFIID riid, - VOID** ppvoid); -static ULONG WINAPI OLEFontImpl_IPersistStream_AddRef(IPersistStream* iface); -static ULONG WINAPI OLEFontImpl_IPersistStream_Release(IPersistStream* iface); -static HRESULT WINAPI OLEFontImpl_GetClassID(IPersistStream* iface, - CLSID* pClassID); -static HRESULT WINAPI OLEFontImpl_IsDirty(IPersistStream* iface); -static HRESULT WINAPI OLEFontImpl_Load(IPersistStream* iface, - IStream* pLoadStream); -static HRESULT WINAPI OLEFontImpl_Save(IPersistStream* iface, - IStream* pOutStream, - BOOL fClearDirty); -static HRESULT WINAPI OLEFontImpl_GetSizeMax(IPersistStream* iface, - ULARGE_INTEGER* pcbSize); - -/*********************************************************************** - * Prototypes for the implementation functions for the - * IConnectionPointContainer interface - */ -static HRESULT WINAPI OLEFontImpl_IConnectionPointContainer_QueryInterface( - IConnectionPointContainer* iface, - REFIID riid, - VOID** ppvoid); -static ULONG WINAPI OLEFontImpl_IConnectionPointContainer_AddRef( - IConnectionPointContainer* iface); -static ULONG WINAPI OLEFontImpl_IConnectionPointContainer_Release( - IConnectionPointContainer* iface); -static HRESULT WINAPI OLEFontImpl_EnumConnectionPoints( - IConnectionPointContainer* iface, - IEnumConnectionPoints **ppEnum); -static HRESULT WINAPI OLEFontImpl_FindConnectionPoint( - IConnectionPointContainer* iface, - REFIID riid, - IConnectionPoint **ppCp); - -/* - * Virtual function tables for the OLEFontImpl class. - */ -static IFontVtbl OLEFontImpl_VTable = -{ - OLEFontImpl_QueryInterface, - OLEFontImpl_AddRef, - OLEFontImpl_Release, - OLEFontImpl_get_Name, - OLEFontImpl_put_Name, - OLEFontImpl_get_Size, - OLEFontImpl_put_Size, - OLEFontImpl_get_Bold, - OLEFontImpl_put_Bold, - OLEFontImpl_get_Italic, - OLEFontImpl_put_Italic, - OLEFontImpl_get_Underline, - OLEFontImpl_put_Underline, - OLEFontImpl_get_Strikethrough, - OLEFontImpl_put_Strikethrough, - OLEFontImpl_get_Weight, - OLEFontImpl_put_Weight, - OLEFontImpl_get_Charset, - OLEFontImpl_put_Charset, - OLEFontImpl_get_hFont, - OLEFontImpl_Clone, - OLEFontImpl_IsEqual, - OLEFontImpl_SetRatio, - OLEFontImpl_QueryTextMetrics, - OLEFontImpl_AddRefHfont, - OLEFontImpl_ReleaseHfont, - OLEFontImpl_SetHdc -}; - -static IDispatchVtbl OLEFontImpl_IDispatch_VTable = -{ - OLEFontImpl_IDispatch_QueryInterface, - OLEFontImpl_IDispatch_AddRef, - OLEFontImpl_IDispatch_Release, - OLEFontImpl_GetTypeInfoCount, - OLEFontImpl_GetTypeInfo, - OLEFontImpl_GetIDsOfNames, - OLEFontImpl_Invoke -}; - -static IPersistStreamVtbl OLEFontImpl_IPersistStream_VTable = -{ - OLEFontImpl_IPersistStream_QueryInterface, - OLEFontImpl_IPersistStream_AddRef, - OLEFontImpl_IPersistStream_Release, - OLEFontImpl_GetClassID, - OLEFontImpl_IsDirty, - OLEFontImpl_Load, - OLEFontImpl_Save, - OLEFontImpl_GetSizeMax -}; - -static IConnectionPointContainerVtbl - OLEFontImpl_IConnectionPointContainer_VTable = -{ - OLEFontImpl_IConnectionPointContainer_QueryInterface, - OLEFontImpl_IConnectionPointContainer_AddRef, - OLEFontImpl_IConnectionPointContainer_Release, - OLEFontImpl_EnumConnectionPoints, - OLEFontImpl_FindConnectionPoint -}; - -static IPersistPropertyBagVtbl OLEFontImpl_IPersistPropertyBag_VTable; -static IPersistStreamInitVtbl OLEFontImpl_IPersistStreamInit_VTable; -/****************************************************************************** - * OleCreateFontIndirect [OLEAUT32.420] - */ -HRESULT WINAPI OleCreateFontIndirect( - LPFONTDESC lpFontDesc, - REFIID riid, - LPVOID* ppvObj) -{ - OLEFontImpl* newFont = 0; - HRESULT hr = S_OK; - - TRACE("(%p, %s, %p)\n", lpFontDesc, debugstr_guid(riid), ppvObj); - /* - * Sanity check - */ - if (ppvObj==0) - return E_POINTER; - - *ppvObj = 0; - - if (!lpFontDesc) { - FONTDESC fd; - - static const WCHAR fname[] = { 'S','y','s','t','e','m',0 }; - - fd.cbSizeofstruct = sizeof(fd); - fd.lpstrName = (WCHAR*)fname; - fd.cySize.s.Lo = 80000; - fd.cySize.s.Hi = 0; - fd.sWeight = 0; - fd.sCharset = 0; - fd.fItalic = 0; - fd.fUnderline = 0; - fd.fStrikethrough = 0; - lpFontDesc = &fd; - } - - /* - * Try to construct a new instance of the class. - */ - newFont = OLEFontImpl_Construct(lpFontDesc); - - if (newFont == 0) - return E_OUTOFMEMORY; - - /* - * Make sure it supports the interface required by the caller. - */ - hr = IFont_QueryInterface((IFont*)newFont, riid, ppvObj); - - /* - * Release the reference obtained in the constructor. If - * the QueryInterface was unsuccessful, it will free the class. - */ - IFont_Release((IFont*)newFont); - - return hr; -} - - -/*********************************************************************** - * Implementation of the OLEFontImpl class. - */ - -/*********************************************************************** - * OLEFont_SendNotify (internal) - * - * Sends notification messages of changed properties to any interested - * connections. - */ -static void OLEFont_SendNotify(OLEFontImpl* this, DISPID dispID) -{ - IEnumConnections *pEnum; - CONNECTDATA CD; - HRESULT hres; - - hres = IConnectionPoint_EnumConnections(this->pCP, &pEnum); - if (FAILED(hres)) /* When we have 0 connections. */ - return; - - while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) { - IPropertyNotifySink *sink; - - IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink); - IPropertyNotifySink_OnChanged(sink, dispID); - IPropertyNotifySink_Release(sink); - IUnknown_Release(CD.pUnk); - } - IEnumConnections_Release(pEnum); - return; -} - -/************************************************************************ - * OLEFontImpl_Construct - * - * This method will construct a new instance of the OLEFontImpl - * class. - * - * The caller of this method must release the object when it's - * done with it. - */ -static OLEFontImpl* OLEFontImpl_Construct(LPFONTDESC fontDesc) -{ - OLEFontImpl* newObject = 0; - - /* - * Allocate space for the object. - */ - newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(OLEFontImpl)); - - if (newObject==0) - return newObject; - - /* - * Initialize the virtual function table. - */ - newObject->lpvtbl1 = &OLEFontImpl_VTable; - newObject->lpvtbl2 = &OLEFontImpl_IDispatch_VTable; - newObject->lpvtbl3 = &OLEFontImpl_IPersistStream_VTable; - newObject->lpvtbl4 = &OLEFontImpl_IConnectionPointContainer_VTable; - newObject->lpvtbl5 = &OLEFontImpl_IPersistPropertyBag_VTable; - newObject->lpvtbl6 = &OLEFontImpl_IPersistStreamInit_VTable; - - /* - * Start with one reference count. The caller of this function - * must release the interface pointer when it is done. - */ - newObject->ref = 1; - - /* - * Copy the description of the font in the object. - */ - assert(fontDesc->cbSizeofstruct >= sizeof(FONTDESC)); - - newObject->description.cbSizeofstruct = sizeof(FONTDESC); - newObject->description.lpstrName = HeapAlloc(GetProcessHeap(), - 0, - (lstrlenW(fontDesc->lpstrName)+1) * sizeof(WCHAR)); - strcpyW(newObject->description.lpstrName, fontDesc->lpstrName); - newObject->description.cySize = fontDesc->cySize; - newObject->description.sWeight = fontDesc->sWeight; - newObject->description.sCharset = fontDesc->sCharset; - newObject->description.fItalic = fontDesc->fItalic; - newObject->description.fUnderline = fontDesc->fUnderline; - newObject->description.fStrikethrough = fontDesc->fStrikethrough; - - /* - * Initializing all the other members. - */ - newObject->gdiFont = 0; - newObject->fontLock = 0; - newObject->cyLogical = 72L; - newObject->cyHimetric = 2540L; - CreateConnectionPoint((IUnknown*)newObject, &IID_IPropertyNotifySink, &newObject->pCP); - TRACE("returning %p\n", newObject); - return newObject; -} - -/************************************************************************ - * OLEFontImpl_Destroy - * - * This method is called by the Release method when the reference - * count goes down to 0. It will free all resources used by - * this object. - */ -static void OLEFontImpl_Destroy(OLEFontImpl* fontDesc) -{ - TRACE("(%p)\n", fontDesc); - - HeapFree(GetProcessHeap(), 0, fontDesc->description.lpstrName); - - if (fontDesc->gdiFont!=0) - DeleteObject(fontDesc->gdiFont); - - HeapFree(GetProcessHeap(), 0, fontDesc); -} - -/************************************************************************ - * OLEFontImpl_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -HRESULT WINAPI OLEFontImpl_QueryInterface( - IFont* iface, - REFIID riid, - void** ppvObject) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%s, %p)\n", this, debugstr_guid(riid), ppvObject); - - /* - * Perform a sanity check on the parameters. - */ - if ( (this==0) || (ppvObject==0) ) - return E_INVALIDARG; - - /* - * Initialize the return parameter. - */ - *ppvObject = 0; - - /* - * Compare the riid with the interface IDs implemented by this object. - */ - if (IsEqualGUID(&IID_IUnknown, riid)) - *ppvObject = (IFont*)this; - if (IsEqualGUID(&IID_IFont, riid)) - *ppvObject = (IFont*)this; - if (IsEqualGUID(&IID_IDispatch, riid)) - *ppvObject = (IDispatch*)&(this->lpvtbl2); - if (IsEqualGUID(&IID_IFontDisp, riid)) - *ppvObject = (IDispatch*)&(this->lpvtbl2); - if (IsEqualGUID(&IID_IPersistStream, riid)) - *ppvObject = (IPersistStream*)&(this->lpvtbl3); - if (IsEqualGUID(&IID_IConnectionPointContainer, riid)) - *ppvObject = (IConnectionPointContainer*)&(this->lpvtbl4); - if (IsEqualGUID(&IID_IPersistPropertyBag, riid)) - *ppvObject = (IPersistPropertyBag*)&(this->lpvtbl5); - if (IsEqualGUID(&IID_IPersistStreamInit, riid)) - *ppvObject = (IPersistStreamInit*)&(this->lpvtbl6); - - /* - * Check that we obtained an interface. - */ - if ((*ppvObject)==0) - { - FIXME("() : asking for unsupported interface %s\n",debugstr_guid(riid)); - return E_NOINTERFACE; - } - OLEFontImpl_AddRef((IFont*)this); - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_AddRef (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -ULONG WINAPI OLEFontImpl_AddRef( - IFont* iface) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(ref=%ld)\n", this, this->ref); - return InterlockedIncrement(&this->ref); -} - -/************************************************************************ - * OLEFontImpl_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -ULONG WINAPI OLEFontImpl_Release( - IFont* iface) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - ULONG ret; - TRACE("(%p)->(ref=%ld)\n", this, this->ref); - - /* - * Decrease the reference count on this object. - */ - ret = InterlockedDecrement(&this->ref); - - /* - * If the reference count goes down to 0, perform suicide. - */ - if (ret==0) OLEFontImpl_Destroy(this); - - return ret; -} - -/************************************************************************ - * OLEFontImpl_get_Name (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_get_Name( - IFont* iface, - BSTR* pname) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%p)\n", this, pname); - /* - * Sanity check. - */ - if (pname==0) - return E_POINTER; - - if (this->description.lpstrName!=0) - *pname = SysAllocString(this->description.lpstrName); - else - *pname = 0; - - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_put_Name (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_put_Name( - IFont* iface, - BSTR name) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%p)\n", this, name); - - if (this->description.lpstrName==0) - { - this->description.lpstrName = HeapAlloc(GetProcessHeap(), - 0, - (lstrlenW(name)+1) * sizeof(WCHAR)); - } - else - { - this->description.lpstrName = HeapReAlloc(GetProcessHeap(), - 0, - this->description.lpstrName, - (lstrlenW(name)+1) * sizeof(WCHAR)); - } - - if (this->description.lpstrName==0) - return E_OUTOFMEMORY; - - strcpyW(this->description.lpstrName, name); - TRACE("new name %s\n", debugstr_w(this->description.lpstrName)); - OLEFont_SendNotify(this, DISPID_FONT_NAME); - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_get_Size (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_get_Size( - IFont* iface, - CY* psize) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%p)\n", this, psize); - - /* - * Sanity check - */ - if (psize==0) - return E_POINTER; - - psize->s.Hi = 0; - psize->s.Lo = this->description.cySize.s.Lo; - - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_put_Size (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_put_Size( - IFont* iface, - CY size) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%ld)\n", this, size.s.Lo); - this->description.cySize.s.Hi = 0; - this->description.cySize.s.Lo = size.s.Lo; - OLEFont_SendNotify(this, DISPID_FONT_SIZE); - - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_get_Bold (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_get_Bold( - IFont* iface, - BOOL* pbold) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%p)\n", this, pbold); - /* - * Sanity check - */ - if (pbold==0) - return E_POINTER; - - *pbold = this->description.sWeight > 550; - - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_put_Bold (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_put_Bold( - IFont* iface, - BOOL bold) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%d)\n", this, bold); - this->description.sWeight = bold ? FW_BOLD : FW_NORMAL; - OLEFont_SendNotify(this, DISPID_FONT_BOLD); - - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_get_Italic (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_get_Italic( - IFont* iface, - BOOL* pitalic) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%p)\n", this, pitalic); - /* - * Sanity check - */ - if (pitalic==0) - return E_POINTER; - - *pitalic = this->description.fItalic; - - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_put_Italic (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_put_Italic( - IFont* iface, - BOOL italic) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%d)\n", this, italic); - - this->description.fItalic = italic; - - OLEFont_SendNotify(this, DISPID_FONT_ITALIC); - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_get_Underline (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_get_Underline( - IFont* iface, - BOOL* punderline) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%p)\n", this, punderline); - - /* - * Sanity check - */ - if (punderline==0) - return E_POINTER; - - *punderline = this->description.fUnderline; - - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_put_Underline (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_put_Underline( - IFont* iface, - BOOL underline) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%d)\n", this, underline); - - this->description.fUnderline = underline; - - OLEFont_SendNotify(this, DISPID_FONT_UNDER); - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_get_Strikethrough (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_get_Strikethrough( - IFont* iface, - BOOL* pstrikethrough) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%p)\n", this, pstrikethrough); - - /* - * Sanity check - */ - if (pstrikethrough==0) - return E_POINTER; - - *pstrikethrough = this->description.fStrikethrough; - - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_put_Strikethrough (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_put_Strikethrough( - IFont* iface, - BOOL strikethrough) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%d)\n", this, strikethrough); - - this->description.fStrikethrough = strikethrough; - OLEFont_SendNotify(this, DISPID_FONT_STRIKE); - - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_get_Weight (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_get_Weight( - IFont* iface, - short* pweight) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%p)\n", this, pweight); - - /* - * Sanity check - */ - if (pweight==0) - return E_POINTER; - - *pweight = this->description.sWeight; - - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_put_Weight (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_put_Weight( - IFont* iface, - short weight) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%d)\n", this, weight); - - this->description.sWeight = weight; - - OLEFont_SendNotify(this, DISPID_FONT_WEIGHT); - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_get_Charset (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_get_Charset( - IFont* iface, - short* pcharset) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%p)\n", this, pcharset); - - /* - * Sanity check - */ - if (pcharset==0) - return E_POINTER; - - *pcharset = this->description.sCharset; - - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_put_Charset (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_put_Charset( - IFont* iface, - short charset) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%d)\n", this, charset); - - this->description.sCharset = charset; - OLEFont_SendNotify(this, DISPID_FONT_CHARSET); - - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_get_hFont (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_get_hFont( - IFont* iface, - HFONT* phfont) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%p)\n", this, phfont); - if (phfont==NULL) - return E_POINTER; - - /* - * Realize the font if necessary - */ - if (this->gdiFont==0) -{ - LOGFONTW logFont; - INT fontHeight; - CY cySize; - - /* - * The height of the font returned by the get_Size property is the - * height of the font in points multiplied by 10000... Using some - * simple conversions and the ratio given by the application, it can - * be converted to a height in pixels. - */ - IFont_get_Size(iface, &cySize); - - fontHeight = MulDiv( cySize.s.Lo, this->cyLogical, this->cyHimetric ); - - memset(&logFont, 0, sizeof(LOGFONTW)); - - logFont.lfHeight = ((fontHeight%10000L)>5000L) ? (-fontHeight/10000L)-1 : - (-fontHeight/10000L); - logFont.lfItalic = this->description.fItalic; - logFont.lfUnderline = this->description.fUnderline; - logFont.lfStrikeOut = this->description.fStrikethrough; - logFont.lfWeight = this->description.sWeight; - logFont.lfCharSet = this->description.sCharset; - logFont.lfOutPrecision = OUT_CHARACTER_PRECIS; - logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; - logFont.lfQuality = DEFAULT_QUALITY; - logFont.lfPitchAndFamily = DEFAULT_PITCH; - strcpyW(logFont.lfFaceName,this->description.lpstrName); - - this->gdiFont = CreateFontIndirectW(&logFont); - } - - *phfont = this->gdiFont; - TRACE("Returning %p\n", *phfont); - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_Clone (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_Clone( - IFont* iface, - IFont** ppfont) -{ - OLEFontImpl* newObject = 0; - LOGFONTW logFont; - INT fontHeight; - CY cySize; - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%p)\n", this, ppfont); - - if (ppfont == NULL) - return E_POINTER; - - *ppfont = NULL; - - /* - * Allocate space for the object. - */ - newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(OLEFontImpl)); - - if (newObject==NULL) - return E_OUTOFMEMORY; - - *newObject = *this; - - /* We need to alloc new memory for the string, otherwise - * we free memory twice. - */ - newObject->description.lpstrName = HeapAlloc( - GetProcessHeap(),0, - (1+strlenW(this->description.lpstrName))*2 - ); - strcpyW(newObject->description.lpstrName, this->description.lpstrName); - /* We need to clone the HFONT too. This is just cut & paste from above */ - IFont_get_Size(iface, &cySize); - - fontHeight = MulDiv(cySize.s.Lo, this->cyLogical,this->cyHimetric); - - memset(&logFont, 0, sizeof(LOGFONTW)); - - logFont.lfHeight = ((fontHeight%10000L)>5000L) ? (-fontHeight/10000L)-1 : - (-fontHeight/10000L); - logFont.lfItalic = this->description.fItalic; - logFont.lfUnderline = this->description.fUnderline; - logFont.lfStrikeOut = this->description.fStrikethrough; - logFont.lfWeight = this->description.sWeight; - logFont.lfCharSet = this->description.sCharset; - logFont.lfOutPrecision = OUT_CHARACTER_PRECIS; - logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; - logFont.lfQuality = DEFAULT_QUALITY; - logFont.lfPitchAndFamily = DEFAULT_PITCH; - strcpyW(logFont.lfFaceName,this->description.lpstrName); - - newObject->gdiFont = CreateFontIndirectW(&logFont); - - - /* The cloned object starts with a reference count of 1 */ - newObject->ref = 1; - - *ppfont = (IFont*)newObject; - - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_IsEqual (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_IsEqual( - IFont* iface, - IFont* pFontOther) -{ - FIXME("(%p, %p), stub!\n",iface,pFontOther); - return E_NOTIMPL; -} - -/************************************************************************ - * OLEFontImpl_SetRatio (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_SetRatio( - IFont* iface, - LONG cyLogical, - LONG cyHimetric) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%ld, %ld)\n", this, cyLogical, cyHimetric); - - this->cyLogical = cyLogical; - this->cyHimetric = cyHimetric; - - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_QueryTextMetrics (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_QueryTextMetrics( - IFont* iface, - TEXTMETRICOLE* ptm) -{ - HDC hdcRef; - HFONT hOldFont, hNewFont; - - hdcRef = GetDC(0); - OLEFontImpl_get_hFont(iface, &hNewFont); - hOldFont = SelectObject(hdcRef, hNewFont); - GetTextMetricsW(hdcRef, ptm); - SelectObject(hdcRef, hOldFont); - ReleaseDC(0, hdcRef); - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_AddRefHfont (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_AddRefHfont( - IFont* iface, - HFONT hfont) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%p) (lock=%ld)\n", this, hfont, this->fontLock); - - if ( (hfont == 0) || - (hfont != this->gdiFont) ) - return E_INVALIDARG; - - this->fontLock++; - - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_ReleaseHfont (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_ReleaseHfont( - IFont* iface, - HFONT hfont) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - TRACE("(%p)->(%p) (lock=%ld)\n", this, hfont, this->fontLock); - - if ( (hfont == 0) || - (hfont != this->gdiFont) ) - return E_INVALIDARG; - - this->fontLock--; - - /* - * If we just released our last font reference, destroy it. - */ - if (this->fontLock==0) - { - DeleteObject(this->gdiFont); - this->gdiFont = 0; - } - - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_SetHdc (IFont) - * - * See Windows documentation for more details on IFont methods. - */ -static HRESULT WINAPI OLEFontImpl_SetHdc( - IFont* iface, - HDC hdc) -{ - OLEFontImpl *this = (OLEFontImpl *)iface; - FIXME("(%p)->(%p): Stub\n", this, hdc); - return E_NOTIMPL; -} - -/************************************************************************ - * OLEFontImpl_IDispatch_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static HRESULT WINAPI OLEFontImpl_IDispatch_QueryInterface( - IDispatch* iface, - REFIID riid, - VOID** ppvoid) -{ - _ICOM_THIS_From_IDispatch(IFont, iface); - - return IFont_QueryInterface(this, riid, ppvoid); -} - -/************************************************************************ - * OLEFontImpl_IDispatch_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI OLEFontImpl_IDispatch_Release( - IDispatch* iface) -{ - _ICOM_THIS_From_IDispatch(IFont, iface); - - return IFont_Release(this); -} - -/************************************************************************ - * OLEFontImpl_IDispatch_AddRef (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI OLEFontImpl_IDispatch_AddRef( - IDispatch* iface) -{ - _ICOM_THIS_From_IDispatch(IFont, iface); - - return IFont_AddRef(this); -} - -/************************************************************************ - * OLEFontImpl_GetTypeInfoCount (IDispatch) - * - * See Windows documentation for more details on IDispatch methods. - */ -static HRESULT WINAPI OLEFontImpl_GetTypeInfoCount( - IDispatch* iface, - unsigned int* pctinfo) -{ - _ICOM_THIS_From_IDispatch(IFont, iface); - FIXME("(%p)->(%p): Stub\n", this, pctinfo); - - return E_NOTIMPL; -} - -/************************************************************************ - * OLEFontImpl_GetTypeInfo (IDispatch) - * - * See Windows documentation for more details on IDispatch methods. - */ -static HRESULT WINAPI OLEFontImpl_GetTypeInfo( - IDispatch* iface, - UINT iTInfo, - LCID lcid, - ITypeInfo** ppTInfo) -{ - static const WCHAR stdole32tlb[] = {'s','t','d','o','l','e','3','2','.','t','l','b',0}; - ITypeLib *tl; - HRESULT hres; - - _ICOM_THIS_From_IDispatch(OLEFontImpl, iface); - TRACE("(%p, iTInfo=%d, lcid=%04x, %p)\n", this, iTInfo, (int)lcid, ppTInfo); - if (iTInfo != 0) - return E_FAIL; - hres = LoadTypeLib(stdole32tlb, &tl); - if (FAILED(hres)) { - ERR("Could not load the stdole32.tlb?\n"); - return hres; - } - hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IDispatch, ppTInfo); - if (FAILED(hres)) { - FIXME("Did not IDispatch typeinfo from typelib, hres %lx\n",hres); - } - return hres; -} - -/************************************************************************ - * OLEFontImpl_GetIDsOfNames (IDispatch) - * - * See Windows documentation for more details on IDispatch methods. - */ -static HRESULT WINAPI OLEFontImpl_GetIDsOfNames( - IDispatch* iface, - REFIID riid, - LPOLESTR* rgszNames, - UINT cNames, - LCID lcid, - DISPID* rgDispId) -{ - _ICOM_THIS_From_IDispatch(IFont, iface); - FIXME("(%p,%s,%p,%d,%04x,%p), stub!\n", this, debugstr_guid(riid), rgszNames, - cNames, (int)lcid, rgDispId - ); - return E_NOTIMPL; -} - -/************************************************************************ - * OLEFontImpl_Invoke (IDispatch) - * - * See Windows documentation for more details on IDispatch methods. - * - * Note: Do not call _put_Xxx methods, since setting things here - * should not call notify functions as I found out debugging the generic - * MS VB5 installer. - */ -static HRESULT WINAPI OLEFontImpl_Invoke( - IDispatch* iface, - DISPID dispIdMember, - REFIID riid, - LCID lcid, - WORD wFlags, - DISPPARAMS* pDispParams, - VARIANT* pVarResult, - EXCEPINFO* pExepInfo, - UINT* puArgErr) -{ - _ICOM_THIS_From_IDispatch(IFont, iface); - OLEFontImpl *xthis = (OLEFontImpl*)this; - - switch (dispIdMember) { - case DISPID_FONT_NAME: - switch (wFlags) { - case DISPATCH_PROPERTYGET: - case DISPATCH_PROPERTYGET|DISPATCH_METHOD: - V_VT(pVarResult) = VT_BSTR; - return OLEFontImpl_get_Name(this, &V_BSTR(pVarResult)); - case DISPATCH_PROPERTYPUT: { - BSTR name; - BOOL freename; - - if (V_VT(&pDispParams->rgvarg[0]) == VT_DISPATCH) { - IFont *font; - HRESULT hr = S_OK; - - hr = IUnknown_QueryInterface(V_DISPATCH(&pDispParams->rgvarg[0]), &IID_IFont, (void **) &font); - if (FAILED(hr)) - { - FIXME("dispatch value for name property is not an OleFont, returning hr=0x%lx\n", hr); - return hr; - } - - hr = IFont_get_Name(font, &name); /* this allocates a new BSTR so free it later */ - if (FAILED(hr)) return hr; - - IUnknown_Release(font); - - freename = TRUE; - } else if (V_VT(&pDispParams->rgvarg[0]) == VT_BSTR) { - name = V_BSTR(&pDispParams->rgvarg[0]); - freename = FALSE; - } else { - FIXME("app is trying to set name property with a non BSTR, non dispatch value. returning E_FAIL\n"); - return E_FAIL; - } - - TRACE("name is %s\n", debugstr_w(name)); - - if (!xthis->description.lpstrName) - xthis->description.lpstrName = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(name)+1) * sizeof(WCHAR)); - else - xthis->description.lpstrName = HeapReAlloc(GetProcessHeap(), 0, xthis->description.lpstrName, (lstrlenW(name)+1) * sizeof(WCHAR)); - - if (xthis->description.lpstrName==0) - return E_OUTOFMEMORY; - strcpyW(xthis->description.lpstrName, name); - - if (freename) SysFreeString(name); - - return S_OK; - } - } - break; - case DISPID_FONT_BOLD: - switch (wFlags) { - case DISPATCH_PROPERTYGET: - case DISPATCH_PROPERTYGET|DISPATCH_METHOD: - V_VT(pVarResult) = VT_BOOL; - return OLEFontImpl_get_Bold(this, (BOOL*)&V_BOOL(pVarResult)); - case DISPATCH_PROPERTYPUT: - if (V_VT(&pDispParams->rgvarg[0]) != VT_BOOL) { - FIXME("DISPID_FONT_BOLD/put, vt is %d, not VT_BOOL.\n",V_VT(&pDispParams->rgvarg[0])); - return E_FAIL; - } else { - xthis->description.sWeight = V_BOOL(&pDispParams->rgvarg[0]) ? FW_BOLD : FW_NORMAL; - return S_OK; - } - } - break; - case DISPID_FONT_ITALIC: - switch (wFlags) { - case DISPATCH_PROPERTYGET: - case DISPATCH_PROPERTYGET|DISPATCH_METHOD: - V_VT(pVarResult) = VT_BOOL; - return OLEFontImpl_get_Italic(this, (BOOL*)&V_BOOL(pVarResult)); - case DISPATCH_PROPERTYPUT: - if (V_VT(&pDispParams->rgvarg[0]) != VT_BOOL) { - FIXME("DISPID_FONT_ITALIC/put, vt is %d, not VT_BOOL.\n",V_VT(&pDispParams->rgvarg[0])); - return E_FAIL; - } else { - xthis->description.fItalic = V_BOOL(&pDispParams->rgvarg[0]); - return S_OK; - } - } - break; - case DISPID_FONT_UNDER: - switch (wFlags) { - case DISPATCH_PROPERTYGET: - case DISPATCH_PROPERTYGET|DISPATCH_METHOD: - V_VT(pVarResult) = VT_BOOL; - return OLEFontImpl_get_Underline(this, (BOOL*)&V_BOOL(pVarResult)); - case DISPATCH_PROPERTYPUT: - if (V_VT(&pDispParams->rgvarg[0]) != VT_BOOL) { - FIXME("DISPID_FONT_UNDER/put, vt is %d, not VT_BOOL.\n",V_VT(&pDispParams->rgvarg[0])); - return E_FAIL; - } else { - xthis->description.fUnderline = V_BOOL(&pDispParams->rgvarg[0]); - return S_OK; - } - } - break; - case DISPID_FONT_STRIKE: - switch (wFlags) { - case DISPATCH_PROPERTYGET: - case DISPATCH_PROPERTYGET|DISPATCH_METHOD: - V_VT(pVarResult) = VT_BOOL; - return OLEFontImpl_get_Strikethrough(this, (BOOL*)&V_BOOL(pVarResult)); - case DISPATCH_PROPERTYPUT: - if (V_VT(&pDispParams->rgvarg[0]) != VT_BOOL) { - FIXME("DISPID_FONT_STRIKE/put, vt is %d, not VT_BOOL.\n",V_VT(&pDispParams->rgvarg[0])); - return E_FAIL; - } else { - xthis->description.fStrikethrough = V_BOOL(&pDispParams->rgvarg[0]); - return S_OK; - } - } - break; - case DISPID_FONT_SIZE: - switch (wFlags) { - case DISPATCH_PROPERTYPUT: { - assert (pDispParams->cArgs == 1); - xthis->description.cySize.s.Hi = 0; - if (V_VT(&pDispParams->rgvarg[0]) != VT_CY) { - if (V_VT(&pDispParams->rgvarg[0]) == VT_I2) { - xthis->description.cySize.s.Lo = V_I2(&pDispParams->rgvarg[0]) * 10000; - } else { - FIXME("property put for Size with vt %d unsupported!\n",V_VT(&pDispParams->rgvarg[0])); - } - } else { - xthis->description.cySize.s.Lo = V_CY(&pDispParams->rgvarg[0]).s.Lo; - } - return S_OK; - } - case DISPATCH_PROPERTYGET: - case DISPATCH_PROPERTYGET|DISPATCH_METHOD: - V_VT(pVarResult) = VT_CY; - return OLEFontImpl_get_Size(this, &V_CY(pVarResult)); - } - break; - case DISPID_FONT_CHARSET: - switch (wFlags) { - case DISPATCH_PROPERTYPUT: - assert (pDispParams->cArgs == 1); - if (V_VT(&pDispParams->rgvarg[0]) != VT_I2) - FIXME("varg of first disparg is not VT_I2, but %d\n",V_VT(&pDispParams->rgvarg[0])); - xthis->description.sCharset = V_I2(&pDispParams->rgvarg[0]); - return S_OK; - case DISPATCH_PROPERTYGET: - case DISPATCH_PROPERTYGET|DISPATCH_METHOD: - V_VT(pVarResult) = VT_I2; - return OLEFontImpl_get_Charset(this, &V_I2(pVarResult)); - } - break; - } - FIXME("%p->(%ld,%s,%lx,%x,%p,%p,%p,%p), unhandled dispid/flag!\n", - this,dispIdMember,debugstr_guid(riid),lcid, - wFlags,pDispParams,pVarResult,pExepInfo,puArgErr - ); - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_IPersistStream_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static HRESULT WINAPI OLEFontImpl_IPersistStream_QueryInterface( - IPersistStream* iface, - REFIID riid, - VOID** ppvoid) -{ - _ICOM_THIS_From_IPersistStream(IFont, iface); - - return IFont_QueryInterface(this, riid, ppvoid); -} - -/************************************************************************ - * OLEFontImpl_IPersistStream_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI OLEFontImpl_IPersistStream_Release( - IPersistStream* iface) -{ - _ICOM_THIS_From_IPersistStream(IFont, iface); - - return IFont_Release(this); -} - -/************************************************************************ - * OLEFontImpl_IPersistStream_AddRef (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI OLEFontImpl_IPersistStream_AddRef( - IPersistStream* iface) -{ - _ICOM_THIS_From_IPersistStream(IFont, iface); - - return IFont_AddRef(this); -} - -/************************************************************************ - * OLEFontImpl_GetClassID (IPersistStream) - * - * See Windows documentation for more details on IPersistStream methods. - */ -static HRESULT WINAPI OLEFontImpl_GetClassID( - IPersistStream* iface, - CLSID* pClassID) -{ - TRACE("(%p,%p)\n",iface,pClassID); - if (pClassID==0) - return E_POINTER; - - memcpy(pClassID, &CLSID_StdFont, sizeof(CLSID_StdFont)); - - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_IsDirty (IPersistStream) - * - * See Windows documentation for more details on IPersistStream methods. - */ -static HRESULT WINAPI OLEFontImpl_IsDirty( - IPersistStream* iface) -{ - TRACE("(%p)\n",iface); - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_Load (IPersistStream) - * - * See Windows documentation for more details on IPersistStream methods. - * - * This is the format of the standard font serialization as far as I - * know - * - * Offset Type Value Comment - * 0x0000 Byte Unknown Probably a version number, contains 0x01 - * 0x0001 Short Charset Charset value from the FONTDESC structure - * 0x0003 Byte Attributes Flags defined as follows: - * 00000010 - Italic - * 00000100 - Underline - * 00001000 - Strikethrough - * 0x0004 Short Weight Weight value from FONTDESC structure - * 0x0006 DWORD size "Low" portion of the cySize member of the FONTDESC - * structure/ - * 0x000A Byte name length Length of the font name string (no null character) - * 0x000B String name Name of the font (ASCII, no nul character) - */ -static HRESULT WINAPI OLEFontImpl_Load( - IPersistStream* iface, - IStream* pLoadStream) -{ - char readBuffer[0x100]; - ULONG cbRead; - BYTE bVersion; - BYTE bAttributes; - BYTE bStringSize; - INT len; - - _ICOM_THIS_From_IPersistStream(OLEFontImpl, iface); - - /* - * Read the version byte - */ - IStream_Read(pLoadStream, &bVersion, 1, &cbRead); - - if ( (cbRead!=1) || - (bVersion!=0x01) ) - return E_FAIL; - - /* - * Charset - */ - IStream_Read(pLoadStream, &this->description.sCharset, 2, &cbRead); - - if (cbRead!=2) - return E_FAIL; - - /* - * Attributes - */ - IStream_Read(pLoadStream, &bAttributes, 1, &cbRead); - - if (cbRead!=1) - return E_FAIL; - - this->description.fItalic = (bAttributes & FONTPERSIST_ITALIC) != 0; - this->description.fStrikethrough = (bAttributes & FONTPERSIST_STRIKETHROUGH) != 0; - this->description.fUnderline = (bAttributes & FONTPERSIST_UNDERLINE) != 0; - - /* - * Weight - */ - IStream_Read(pLoadStream, &this->description.sWeight, 2, &cbRead); - - if (cbRead!=2) - return E_FAIL; - - /* - * Size - */ - IStream_Read(pLoadStream, &this->description.cySize.s.Lo, 4, &cbRead); - - if (cbRead!=4) - return E_FAIL; - - this->description.cySize.s.Hi = 0; - - /* - * FontName - */ - IStream_Read(pLoadStream, &bStringSize, 1, &cbRead); - - if (cbRead!=1) - return E_FAIL; - - IStream_Read(pLoadStream, readBuffer, bStringSize, &cbRead); - - if (cbRead!=bStringSize) - return E_FAIL; - - HeapFree(GetProcessHeap(), 0, this->description.lpstrName); - - len = MultiByteToWideChar( CP_ACP, 0, readBuffer, bStringSize, NULL, 0 ); - this->description.lpstrName = HeapAlloc( GetProcessHeap(), 0, (len+1) * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, readBuffer, bStringSize, this->description.lpstrName, len ); - this->description.lpstrName[len] = 0; - - /* Ensure use of this font causes a new one to be created @@@@ */ - DeleteObject(this->gdiFont); - this->gdiFont = 0; - - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_Save (IPersistStream) - * - * See Windows documentation for more details on IPersistStream methods. - */ -static HRESULT WINAPI OLEFontImpl_Save( - IPersistStream* iface, - IStream* pOutStream, - BOOL fClearDirty) -{ - char* writeBuffer = NULL; - ULONG cbWritten; - BYTE bVersion = 0x01; - BYTE bAttributes; - BYTE bStringSize; - - _ICOM_THIS_From_IPersistStream(OLEFontImpl, iface); - - /* - * Read the version byte - */ - IStream_Write(pOutStream, &bVersion, 1, &cbWritten); - - if (cbWritten!=1) - return E_FAIL; - - /* - * Charset - */ - IStream_Write(pOutStream, &this->description.sCharset, 2, &cbWritten); - - if (cbWritten!=2) - return E_FAIL; - - /* - * Attributes - */ - bAttributes = 0; - - if (this->description.fItalic) - bAttributes |= FONTPERSIST_ITALIC; - - if (this->description.fStrikethrough) - bAttributes |= FONTPERSIST_STRIKETHROUGH; - - if (this->description.fUnderline) - bAttributes |= FONTPERSIST_UNDERLINE; - - IStream_Write(pOutStream, &bAttributes, 1, &cbWritten); - - if (cbWritten!=1) - return E_FAIL; - - /* - * Weight - */ - IStream_Write(pOutStream, &this->description.sWeight, 2, &cbWritten); - - if (cbWritten!=2) - return E_FAIL; - - /* - * Size - */ - IStream_Write(pOutStream, &this->description.cySize.s.Lo, 4, &cbWritten); - - if (cbWritten!=4) - return E_FAIL; - - /* - * FontName - */ - if (this->description.lpstrName!=0) - bStringSize = WideCharToMultiByte( CP_ACP, 0, this->description.lpstrName, - strlenW(this->description.lpstrName), NULL, 0, NULL, NULL ); - else - bStringSize = 0; - - IStream_Write(pOutStream, &bStringSize, 1, &cbWritten); - - if (cbWritten!=1) - return E_FAIL; - - if (bStringSize!=0) - { - if (!(writeBuffer = HeapAlloc( GetProcessHeap(), 0, bStringSize ))) return E_OUTOFMEMORY; - WideCharToMultiByte( CP_ACP, 0, this->description.lpstrName, - strlenW(this->description.lpstrName), - writeBuffer, bStringSize, NULL, NULL ); - - IStream_Write(pOutStream, writeBuffer, bStringSize, &cbWritten); - HeapFree(GetProcessHeap(), 0, writeBuffer); - - if (cbWritten!=bStringSize) - return E_FAIL; - } - - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_GetSizeMax (IPersistStream) - * - * See Windows documentation for more details on IPersistStream methods. - */ -static HRESULT WINAPI OLEFontImpl_GetSizeMax( - IPersistStream* iface, - ULARGE_INTEGER* pcbSize) -{ - _ICOM_THIS_From_IPersistStream(OLEFontImpl, iface); - - if (pcbSize==NULL) - return E_POINTER; - - pcbSize->u.HighPart = 0; - pcbSize->u.LowPart = 0; - - pcbSize->u.LowPart += sizeof(BYTE); /* Version */ - pcbSize->u.LowPart += sizeof(WORD); /* Lang code */ - pcbSize->u.LowPart += sizeof(BYTE); /* Flags */ - pcbSize->u.LowPart += sizeof(WORD); /* Weight */ - pcbSize->u.LowPart += sizeof(DWORD); /* Size */ - pcbSize->u.LowPart += sizeof(BYTE); /* StrLength */ - - if (this->description.lpstrName!=0) - pcbSize->u.LowPart += lstrlenW(this->description.lpstrName); - - return S_OK; -} - -/************************************************************************ - * OLEFontImpl_IConnectionPointContainer_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static HRESULT WINAPI OLEFontImpl_IConnectionPointContainer_QueryInterface( - IConnectionPointContainer* iface, - REFIID riid, - VOID** ppvoid) -{ - _ICOM_THIS_From_IConnectionPointContainer(OLEFontImpl, iface); - - return IFont_QueryInterface((IFont*)this, riid, ppvoid); -} - -/************************************************************************ - * OLEFontImpl_IConnectionPointContainer_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI OLEFontImpl_IConnectionPointContainer_Release( - IConnectionPointContainer* iface) -{ - _ICOM_THIS_From_IConnectionPointContainer(OLEFontImpl, iface); - - return IFont_Release((IFont*)this); -} - -/************************************************************************ - * OLEFontImpl_IConnectionPointContainer_AddRef (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI OLEFontImpl_IConnectionPointContainer_AddRef( - IConnectionPointContainer* iface) -{ - _ICOM_THIS_From_IConnectionPointContainer(OLEFontImpl, iface); - - return IFont_AddRef((IFont*)this); -} - -/************************************************************************ - * OLEFontImpl_EnumConnectionPoints (IConnectionPointContainer) - * - * See Windows documentation for more details on IConnectionPointContainer - * methods. - */ -static HRESULT WINAPI OLEFontImpl_EnumConnectionPoints( - IConnectionPointContainer* iface, - IEnumConnectionPoints **ppEnum) -{ - _ICOM_THIS_From_IConnectionPointContainer(OLEFontImpl, iface); - - FIXME("(%p)->(%p): stub\n", this, ppEnum); - return E_NOTIMPL; -} - -/************************************************************************ - * OLEFontImpl_FindConnectionPoint (IConnectionPointContainer) - * - * See Windows documentation for more details on IConnectionPointContainer - * methods. - */ -static HRESULT WINAPI OLEFontImpl_FindConnectionPoint( - IConnectionPointContainer* iface, - REFIID riid, - IConnectionPoint **ppCp) -{ - _ICOM_THIS_From_IConnectionPointContainer(OLEFontImpl, iface); - TRACE("(%p)->(%s, %p): stub\n", this, debugstr_guid(riid), ppCp); - - if(memcmp(riid, &IID_IPropertyNotifySink, sizeof(IID_IPropertyNotifySink)) == 0) { - return IConnectionPoint_QueryInterface(this->pCP, &IID_IConnectionPoint, - (LPVOID)ppCp); - } else { - FIXME("Tried to find connection point on %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; - } -} - -/************************************************************************ - * OLEFontImpl implementation of IPersistPropertyBag. - */ -static HRESULT WINAPI OLEFontImpl_IPersistPropertyBag_QueryInterface( - IPersistPropertyBag *iface, REFIID riid, LPVOID *ppvObj -) { - _ICOM_THIS_From_IPersistPropertyBag(IFont, iface); - return IFont_QueryInterface(this,riid,ppvObj); -} - -static ULONG WINAPI OLEFontImpl_IPersistPropertyBag_AddRef( - IPersistPropertyBag *iface -) { - _ICOM_THIS_From_IPersistPropertyBag(IFont, iface); - return IFont_AddRef(this); -} - -static ULONG WINAPI OLEFontImpl_IPersistPropertyBag_Release( - IPersistPropertyBag *iface -) { - _ICOM_THIS_From_IPersistPropertyBag(IFont, iface); - return IFont_Release(this); -} - -static HRESULT WINAPI OLEFontImpl_IPersistPropertyBag_GetClassID( - IPersistPropertyBag *iface, CLSID *classid -) { - FIXME("(%p,%p), stub!\n", iface, classid); - return E_FAIL; -} - -static HRESULT WINAPI OLEFontImpl_IPersistPropertyBag_InitNew( - IPersistPropertyBag *iface -) { - FIXME("(%p), stub!\n", iface); - return S_OK; -} - -static HRESULT WINAPI OLEFontImpl_IPersistPropertyBag_Load( - IPersistPropertyBag *iface, IPropertyBag* pPropBag, IErrorLog* pErrorLog -) { -/* (from Visual Basic 6 property bag) - Name = "MS Sans Serif" - Size = 13.8 - Charset = 0 - Weight = 400 - Underline = 0 'False - Italic = 0 'False - Strikethrough = 0 'False -*/ - static const WCHAR sAttrName[] = {'N','a','m','e',0}; - static const WCHAR sAttrSize[] = {'S','i','z','e',0}; - static const WCHAR sAttrCharset[] = {'C','h','a','r','s','e','t',0}; - static const WCHAR sAttrWeight[] = {'W','e','i','g','h','t',0}; - static const WCHAR sAttrUnderline[] = {'U','n','d','e','r','l','i','n','e',0}; - static const WCHAR sAttrItalic[] = {'I','t','a','l','i','c',0}; - static const WCHAR sAttrStrikethrough[] = {'S','t','r','i','k','e','t','h','r','o','u','g','h',0}; - VARIANT rawAttr; - VARIANT valueAttr; - HRESULT iRes = S_OK; - _ICOM_THIS_From_IPersistPropertyBag(IFont, iface); - - VariantInit(&rawAttr); - VariantInit(&valueAttr); - - if (iRes == S_OK) { - iRes = IPropertyBag_Read(pPropBag, sAttrName, &rawAttr, pErrorLog); - if (iRes == S_OK) - { - iRes = VariantChangeType(&rawAttr, &valueAttr, 0, VT_BSTR); - if (iRes == S_OK) - iRes = IFont_put_Name(this, V_BSTR(&valueAttr)); - } - else if (iRes == E_INVALIDARG) - iRes = S_OK; - VariantClear(&rawAttr); - VariantClear(&valueAttr); - } - - if (iRes == S_OK) { - iRes = IPropertyBag_Read(pPropBag, sAttrSize, &rawAttr, pErrorLog); - if (iRes == S_OK) - { - iRes = VariantChangeType(&rawAttr, &valueAttr, 0, VT_CY); - if (iRes == S_OK) - iRes = IFont_put_Size(this, V_CY(&valueAttr)); - } - else if (iRes == E_INVALIDARG) - iRes = S_OK; - VariantClear(&rawAttr); - VariantClear(&valueAttr); - } - - if (iRes == S_OK) { - iRes = IPropertyBag_Read(pPropBag, sAttrCharset, &rawAttr, pErrorLog); - if (iRes == S_OK) - { - iRes = VariantChangeType(&rawAttr, &valueAttr, 0, VT_I2); - if (iRes == S_OK) - iRes = IFont_put_Charset(this, V_I2(&valueAttr)); - } - else if (iRes == E_INVALIDARG) - iRes = S_OK; - VariantClear(&rawAttr); - VariantClear(&valueAttr); - } - - if (iRes == S_OK) { - iRes = IPropertyBag_Read(pPropBag, sAttrWeight, &rawAttr, pErrorLog); - if (iRes == S_OK) - { - iRes = VariantChangeType(&rawAttr, &valueAttr, 0, VT_I2); - if (iRes == S_OK) - iRes = IFont_put_Weight(this, V_I2(&valueAttr)); - } - else if (iRes == E_INVALIDARG) - iRes = S_OK; - VariantClear(&rawAttr); - VariantClear(&valueAttr); - - } - - if (iRes == S_OK) { - iRes = IPropertyBag_Read(pPropBag, sAttrUnderline, &rawAttr, pErrorLog); - if (iRes == S_OK) - { - iRes = VariantChangeType(&rawAttr, &valueAttr, 0, VT_BOOL); - if (iRes == S_OK) - iRes = IFont_put_Underline(this, V_BOOL(&valueAttr)); - } - else if (iRes == E_INVALIDARG) - iRes = S_OK; - VariantClear(&rawAttr); - VariantClear(&valueAttr); - } - - if (iRes == S_OK) { - iRes = IPropertyBag_Read(pPropBag, sAttrItalic, &rawAttr, pErrorLog); - if (iRes == S_OK) - { - iRes = VariantChangeType(&rawAttr, &valueAttr, 0, VT_BOOL); - if (iRes == S_OK) - iRes = IFont_put_Italic(this, V_BOOL(&valueAttr)); - } - else if (iRes == E_INVALIDARG) - iRes = S_OK; - VariantClear(&rawAttr); - VariantClear(&valueAttr); - } - - if (iRes == S_OK) { - iRes = IPropertyBag_Read(pPropBag, sAttrStrikethrough, &rawAttr, pErrorLog); - if (iRes == S_OK) - { - iRes = VariantChangeType(&rawAttr, &valueAttr, 0, VT_BOOL); - if (iRes == S_OK) - IFont_put_Strikethrough(this, V_BOOL(&valueAttr)); - } - else if (iRes == E_INVALIDARG) - iRes = S_OK; - VariantClear(&rawAttr); - VariantClear(&valueAttr); - } - - if (FAILED(iRes)) - WARN("-- 0x%08lx\n", iRes); - return iRes; -} - -static HRESULT WINAPI OLEFontImpl_IPersistPropertyBag_Save( - IPersistPropertyBag *iface, IPropertyBag* pPropBag, BOOL fClearDirty, - BOOL fSaveAllProperties -) { - FIXME("(%p,%p,%d,%d), stub!\n", iface, pPropBag, fClearDirty, fSaveAllProperties); - return E_FAIL; -} - -static IPersistPropertyBagVtbl OLEFontImpl_IPersistPropertyBag_VTable = -{ - OLEFontImpl_IPersistPropertyBag_QueryInterface, - OLEFontImpl_IPersistPropertyBag_AddRef, - OLEFontImpl_IPersistPropertyBag_Release, - - OLEFontImpl_IPersistPropertyBag_GetClassID, - OLEFontImpl_IPersistPropertyBag_InitNew, - OLEFontImpl_IPersistPropertyBag_Load, - OLEFontImpl_IPersistPropertyBag_Save -}; - -/************************************************************************ - * OLEFontImpl implementation of IPersistStreamInit. - */ -static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_QueryInterface( - IPersistStreamInit *iface, REFIID riid, LPVOID *ppvObj -) { - _ICOM_THIS_From_IPersistStreamInit(IFont, iface); - return IFont_QueryInterface(this,riid,ppvObj); -} - -static ULONG WINAPI OLEFontImpl_IPersistStreamInit_AddRef( - IPersistStreamInit *iface -) { - _ICOM_THIS_From_IPersistStreamInit(IFont, iface); - return IFont_AddRef(this); -} - -static ULONG WINAPI OLEFontImpl_IPersistStreamInit_Release( - IPersistStreamInit *iface -) { - _ICOM_THIS_From_IPersistStreamInit(IFont, iface); - return IFont_Release(this); -} - -static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_GetClassID( - IPersistStreamInit *iface, CLSID *classid -) { - FIXME("(%p,%p), stub!\n", iface, classid); - return E_FAIL; -} - -static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_IsDirty( - IPersistStreamInit *iface -) { - FIXME("(%p), stub!\n", iface); - return E_FAIL; -} - -static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_Load( - IPersistStreamInit *iface, LPSTREAM pStm -) { - FIXME("(%p,%p), stub!\n", iface, pStm); - return E_FAIL; -} - -static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_Save( - IPersistStreamInit *iface, LPSTREAM pStm, BOOL fClearDirty -) { - FIXME("(%p,%p,%d), stub!\n", iface, pStm, fClearDirty); - return E_FAIL; -} - -static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_GetSizeMax( - IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize -) { - FIXME("(%p,%p), stub!\n", iface, pcbSize); - return E_FAIL; -} - -static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_InitNew( - IPersistStreamInit *iface -) { - FIXME("(%p), stub!\n", iface); - return S_OK; -} - -static IPersistStreamInitVtbl OLEFontImpl_IPersistStreamInit_VTable = -{ - OLEFontImpl_IPersistStreamInit_QueryInterface, - OLEFontImpl_IPersistStreamInit_AddRef, - OLEFontImpl_IPersistStreamInit_Release, - - OLEFontImpl_IPersistStreamInit_GetClassID, - OLEFontImpl_IPersistStreamInit_IsDirty, - OLEFontImpl_IPersistStreamInit_Load, - OLEFontImpl_IPersistStreamInit_Save, - OLEFontImpl_IPersistStreamInit_GetSizeMax, - OLEFontImpl_IPersistStreamInit_InitNew -}; - -/******************************************************************************* - * StdFont ClassFactory - */ -typedef struct -{ - /* IUnknown fields */ - IClassFactoryVtbl *lpVtbl; - DWORD ref; -} IClassFactoryImpl; - -static HRESULT WINAPI -SFCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - - FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj); - return E_NOINTERFACE; -} - -static ULONG WINAPI -SFCF_AddRef(LPCLASSFACTORY iface) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - return InterlockedIncrement(&This->ref); -} - -static ULONG WINAPI SFCF_Release(LPCLASSFACTORY iface) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - /* static class, won't be freed */ - return InterlockedDecrement(&This->ref); -} - -static HRESULT WINAPI SFCF_CreateInstance( - LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj -) { - return OleCreateFontIndirect(NULL,riid,ppobj); - -} - -static HRESULT WINAPI SFCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - FIXME("(%p)->(%d),stub!\n",This,dolock); - return S_OK; -} - -static IClassFactoryVtbl SFCF_Vtbl = { - SFCF_QueryInterface, - SFCF_AddRef, - SFCF_Release, - SFCF_CreateInstance, - SFCF_LockServer -}; -static IClassFactoryImpl STDFONT_CF = {&SFCF_Vtbl, 1 }; - -void _get_STDFONT_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDFONT_CF; } +/* + * OLE Font encapsulation implementation + * + * This file contains an implementation of the IFont + * interface and the OleCreateFontIndirect API call. + * + * Copyright 1999 Francis Beaudet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <assert.h> +#include <stdarg.h> +#include <string.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "winerror.h" +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "wine/unicode.h" +#include "objbase.h" +#include "oleauto.h" /* for SysAllocString(....) */ +#include "ole2.h" +#include "olectl.h" +#include "wine/debug.h" +#include "connpt.h" /* for CreateConnectionPoint */ + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/*********************************************************************** + * Declaration of constants used when serializing the font object. + */ +#define FONTPERSIST_ITALIC 0x02 +#define FONTPERSIST_UNDERLINE 0x04 +#define FONTPERSIST_STRIKETHROUGH 0x08 + +/*********************************************************************** + * Declaration of the implementation class for the IFont interface + */ +typedef struct OLEFontImpl OLEFontImpl; + +struct OLEFontImpl +{ + /* + * This class supports many interfaces. IUnknown, IFont, + * IDispatch, IDispFont IPersistStream and IConnectionPointContainer. + * The first two are supported by the first vtable, the next two are + * supported by the second table and the last two have their own. + */ + IFontVtbl* lpvtbl1; + IDispatchVtbl* lpvtbl2; + IPersistStreamVtbl* lpvtbl3; + IConnectionPointContainerVtbl* lpvtbl4; + IPersistPropertyBagVtbl* lpvtbl5; + IPersistStreamInitVtbl* lpvtbl6; + /* + * Reference count for that instance of the class. + */ + ULONG ref; + + /* + * This structure contains the description of the class. + */ + FONTDESC description; + + /* + * Contain the font associated with this object. + */ + HFONT gdiFont; + + /* + * Font lock count. + */ + DWORD fontLock; + + /* + * Size ratio + */ + long cyLogical; + long cyHimetric; + + IConnectionPoint *pCP; +}; + +/* + * Here, I define utility macros to help with the casting of the + * "this" parameter. + * There is a version to accommodate all of the VTables implemented + * by this object. + */ +#define _ICOM_THIS_From_IDispatch(class, name) class* this = (class*)(((char*)name)-sizeof(void*)) +#define _ICOM_THIS_From_IPersistStream(class, name) class* this = (class*)(((char*)name)-2*sizeof(void*)) +#define _ICOM_THIS_From_IConnectionPointContainer(class, name) class* this = (class*)(((char*)name)-3*sizeof(void*)) +#define _ICOM_THIS_From_IPersistPropertyBag(class, name) class* this = (class*)(((char*)name)-4*sizeof(void*)) +#define _ICOM_THIS_From_IPersistStreamInit(class, name) class* this = (class*)(((char*)name)-5*sizeof(void*)) + + +/*********************************************************************** + * Prototypes for the implementation functions for the IFont + * interface + */ +static OLEFontImpl* OLEFontImpl_Construct(LPFONTDESC fontDesc); +static void OLEFontImpl_Destroy(OLEFontImpl* fontDesc); +static HRESULT WINAPI OLEFontImpl_QueryInterface(IFont* iface, REFIID riid, VOID** ppvoid); +static ULONG WINAPI OLEFontImpl_AddRef(IFont* iface); +static ULONG WINAPI OLEFontImpl_Release(IFont* iface); +static HRESULT WINAPI OLEFontImpl_get_Name(IFont* iface, BSTR* pname); +static HRESULT WINAPI OLEFontImpl_put_Name(IFont* iface, BSTR name); +static HRESULT WINAPI OLEFontImpl_get_Size(IFont* iface, CY* psize); +static HRESULT WINAPI OLEFontImpl_put_Size(IFont* iface, CY size); +static HRESULT WINAPI OLEFontImpl_get_Bold(IFont* iface, BOOL* pbold); +static HRESULT WINAPI OLEFontImpl_put_Bold(IFont* iface, BOOL bold); +static HRESULT WINAPI OLEFontImpl_get_Italic(IFont* iface, BOOL* pitalic); +static HRESULT WINAPI OLEFontImpl_put_Italic(IFont* iface, BOOL italic); +static HRESULT WINAPI OLEFontImpl_get_Underline(IFont* iface, BOOL* punderline); +static HRESULT WINAPI OLEFontImpl_put_Underline(IFont* iface, BOOL underline); +static HRESULT WINAPI OLEFontImpl_get_Strikethrough(IFont* iface, BOOL* pstrikethrough); +static HRESULT WINAPI OLEFontImpl_put_Strikethrough(IFont* iface, BOOL strikethrough); +static HRESULT WINAPI OLEFontImpl_get_Weight(IFont* iface, short* pweight); +static HRESULT WINAPI OLEFontImpl_put_Weight(IFont* iface, short weight); +static HRESULT WINAPI OLEFontImpl_get_Charset(IFont* iface, short* pcharset); +static HRESULT WINAPI OLEFontImpl_put_Charset(IFont* iface, short charset); +static HRESULT WINAPI OLEFontImpl_get_hFont(IFont* iface, HFONT* phfont); +static HRESULT WINAPI OLEFontImpl_Clone(IFont* iface, IFont** ppfont); +static HRESULT WINAPI OLEFontImpl_IsEqual(IFont* iface, IFont* pFontOther); +static HRESULT WINAPI OLEFontImpl_SetRatio(IFont* iface, LONG cyLogical, LONG cyHimetric); +static HRESULT WINAPI OLEFontImpl_QueryTextMetrics(IFont* iface, TEXTMETRICOLE* ptm); +static HRESULT WINAPI OLEFontImpl_AddRefHfont(IFont* iface, HFONT hfont); +static HRESULT WINAPI OLEFontImpl_ReleaseHfont(IFont* iface, HFONT hfont); +static HRESULT WINAPI OLEFontImpl_SetHdc(IFont* iface, HDC hdc); + +/*********************************************************************** + * Prototypes for the implementation functions for the IDispatch + * interface + */ +static HRESULT WINAPI OLEFontImpl_IDispatch_QueryInterface(IDispatch* iface, + REFIID riid, + VOID** ppvoid); +static ULONG WINAPI OLEFontImpl_IDispatch_AddRef(IDispatch* iface); +static ULONG WINAPI OLEFontImpl_IDispatch_Release(IDispatch* iface); +static HRESULT WINAPI OLEFontImpl_GetTypeInfoCount(IDispatch* iface, + unsigned int* pctinfo); +static HRESULT WINAPI OLEFontImpl_GetTypeInfo(IDispatch* iface, + UINT iTInfo, + LCID lcid, + ITypeInfo** ppTInfo); +static HRESULT WINAPI OLEFontImpl_GetIDsOfNames(IDispatch* iface, + REFIID riid, + LPOLESTR* rgszNames, + UINT cNames, + LCID lcid, + DISPID* rgDispId); +static HRESULT WINAPI OLEFontImpl_Invoke(IDispatch* iface, + DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS* pDispParams, + VARIANT* pVarResult, + EXCEPINFO* pExepInfo, + UINT* puArgErr); + +/*********************************************************************** + * Prototypes for the implementation functions for the IPersistStream + * interface + */ +static HRESULT WINAPI OLEFontImpl_IPersistStream_QueryInterface(IPersistStream* iface, + REFIID riid, + VOID** ppvoid); +static ULONG WINAPI OLEFontImpl_IPersistStream_AddRef(IPersistStream* iface); +static ULONG WINAPI OLEFontImpl_IPersistStream_Release(IPersistStream* iface); +static HRESULT WINAPI OLEFontImpl_GetClassID(IPersistStream* iface, + CLSID* pClassID); +static HRESULT WINAPI OLEFontImpl_IsDirty(IPersistStream* iface); +static HRESULT WINAPI OLEFontImpl_Load(IPersistStream* iface, + IStream* pLoadStream); +static HRESULT WINAPI OLEFontImpl_Save(IPersistStream* iface, + IStream* pOutStream, + BOOL fClearDirty); +static HRESULT WINAPI OLEFontImpl_GetSizeMax(IPersistStream* iface, + ULARGE_INTEGER* pcbSize); + +/*********************************************************************** + * Prototypes for the implementation functions for the + * IConnectionPointContainer interface + */ +static HRESULT WINAPI OLEFontImpl_IConnectionPointContainer_QueryInterface( + IConnectionPointContainer* iface, + REFIID riid, + VOID** ppvoid); +static ULONG WINAPI OLEFontImpl_IConnectionPointContainer_AddRef( + IConnectionPointContainer* iface); +static ULONG WINAPI OLEFontImpl_IConnectionPointContainer_Release( + IConnectionPointContainer* iface); +static HRESULT WINAPI OLEFontImpl_EnumConnectionPoints( + IConnectionPointContainer* iface, + IEnumConnectionPoints **ppEnum); +static HRESULT WINAPI OLEFontImpl_FindConnectionPoint( + IConnectionPointContainer* iface, + REFIID riid, + IConnectionPoint **ppCp); + +/* + * Virtual function tables for the OLEFontImpl class. + */ +static IFontVtbl OLEFontImpl_VTable = +{ + OLEFontImpl_QueryInterface, + OLEFontImpl_AddRef, + OLEFontImpl_Release, + OLEFontImpl_get_Name, + OLEFontImpl_put_Name, + OLEFontImpl_get_Size, + OLEFontImpl_put_Size, + OLEFontImpl_get_Bold, + OLEFontImpl_put_Bold, + OLEFontImpl_get_Italic, + OLEFontImpl_put_Italic, + OLEFontImpl_get_Underline, + OLEFontImpl_put_Underline, + OLEFontImpl_get_Strikethrough, + OLEFontImpl_put_Strikethrough, + OLEFontImpl_get_Weight, + OLEFontImpl_put_Weight, + OLEFontImpl_get_Charset, + OLEFontImpl_put_Charset, + OLEFontImpl_get_hFont, + OLEFontImpl_Clone, + OLEFontImpl_IsEqual, + OLEFontImpl_SetRatio, + OLEFontImpl_QueryTextMetrics, + OLEFontImpl_AddRefHfont, + OLEFontImpl_ReleaseHfont, + OLEFontImpl_SetHdc +}; + +static IDispatchVtbl OLEFontImpl_IDispatch_VTable = +{ + OLEFontImpl_IDispatch_QueryInterface, + OLEFontImpl_IDispatch_AddRef, + OLEFontImpl_IDispatch_Release, + OLEFontImpl_GetTypeInfoCount, + OLEFontImpl_GetTypeInfo, + OLEFontImpl_GetIDsOfNames, + OLEFontImpl_Invoke +}; + +static IPersistStreamVtbl OLEFontImpl_IPersistStream_VTable = +{ + OLEFontImpl_IPersistStream_QueryInterface, + OLEFontImpl_IPersistStream_AddRef, + OLEFontImpl_IPersistStream_Release, + OLEFontImpl_GetClassID, + OLEFontImpl_IsDirty, + OLEFontImpl_Load, + OLEFontImpl_Save, + OLEFontImpl_GetSizeMax +}; + +static IConnectionPointContainerVtbl + OLEFontImpl_IConnectionPointContainer_VTable = +{ + OLEFontImpl_IConnectionPointContainer_QueryInterface, + OLEFontImpl_IConnectionPointContainer_AddRef, + OLEFontImpl_IConnectionPointContainer_Release, + OLEFontImpl_EnumConnectionPoints, + OLEFontImpl_FindConnectionPoint +}; + +static IPersistPropertyBagVtbl OLEFontImpl_IPersistPropertyBag_VTable; +static IPersistStreamInitVtbl OLEFontImpl_IPersistStreamInit_VTable; +/****************************************************************************** + * OleCreateFontIndirect [OLEAUT32.420] + */ +HRESULT WINAPI OleCreateFontIndirect( + LPFONTDESC lpFontDesc, + REFIID riid, + LPVOID* ppvObj) +{ + OLEFontImpl* newFont = 0; + HRESULT hr = S_OK; + + TRACE("(%p, %s, %p)\n", lpFontDesc, debugstr_guid(riid), ppvObj); + /* + * Sanity check + */ + if (ppvObj==0) + return E_POINTER; + + *ppvObj = 0; + + if (!lpFontDesc) { + FONTDESC fd; + + static const WCHAR fname[] = { 'S','y','s','t','e','m',0 }; + + fd.cbSizeofstruct = sizeof(fd); + fd.lpstrName = (WCHAR*)fname; + fd.cySize.s.Lo = 80000; + fd.cySize.s.Hi = 0; + fd.sWeight = 0; + fd.sCharset = 0; + fd.fItalic = 0; + fd.fUnderline = 0; + fd.fStrikethrough = 0; + lpFontDesc = &fd; + } + + /* + * Try to construct a new instance of the class. + */ + newFont = OLEFontImpl_Construct(lpFontDesc); + + if (newFont == 0) + return E_OUTOFMEMORY; + + /* + * Make sure it supports the interface required by the caller. + */ + hr = IFont_QueryInterface((IFont*)newFont, riid, ppvObj); + + /* + * Release the reference obtained in the constructor. If + * the QueryInterface was unsuccessful, it will free the class. + */ + IFont_Release((IFont*)newFont); + + return hr; +} + + +/*********************************************************************** + * Implementation of the OLEFontImpl class. + */ + +/*********************************************************************** + * OLEFont_SendNotify (internal) + * + * Sends notification messages of changed properties to any interested + * connections. + */ +static void OLEFont_SendNotify(OLEFontImpl* this, DISPID dispID) +{ + IEnumConnections *pEnum; + CONNECTDATA CD; + HRESULT hres; + + hres = IConnectionPoint_EnumConnections(this->pCP, &pEnum); + if (FAILED(hres)) /* When we have 0 connections. */ + return; + + while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) { + IPropertyNotifySink *sink; + + IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink); + IPropertyNotifySink_OnChanged(sink, dispID); + IPropertyNotifySink_Release(sink); + IUnknown_Release(CD.pUnk); + } + IEnumConnections_Release(pEnum); + return; +} + +/************************************************************************ + * OLEFontImpl_Construct + * + * This method will construct a new instance of the OLEFontImpl + * class. + * + * The caller of this method must release the object when it's + * done with it. + */ +static OLEFontImpl* OLEFontImpl_Construct(LPFONTDESC fontDesc) +{ + OLEFontImpl* newObject = 0; + + /* + * Allocate space for the object. + */ + newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(OLEFontImpl)); + + if (newObject==0) + return newObject; + + /* + * Initialize the virtual function table. + */ + newObject->lpvtbl1 = &OLEFontImpl_VTable; + newObject->lpvtbl2 = &OLEFontImpl_IDispatch_VTable; + newObject->lpvtbl3 = &OLEFontImpl_IPersistStream_VTable; + newObject->lpvtbl4 = &OLEFontImpl_IConnectionPointContainer_VTable; + newObject->lpvtbl5 = &OLEFontImpl_IPersistPropertyBag_VTable; + newObject->lpvtbl6 = &OLEFontImpl_IPersistStreamInit_VTable; + + /* + * Start with one reference count. The caller of this function + * must release the interface pointer when it is done. + */ + newObject->ref = 1; + + /* + * Copy the description of the font in the object. + */ + assert(fontDesc->cbSizeofstruct >= sizeof(FONTDESC)); + + newObject->description.cbSizeofstruct = sizeof(FONTDESC); + newObject->description.lpstrName = HeapAlloc(GetProcessHeap(), + 0, + (lstrlenW(fontDesc->lpstrName)+1) * sizeof(WCHAR)); + strcpyW(newObject->description.lpstrName, fontDesc->lpstrName); + newObject->description.cySize = fontDesc->cySize; + newObject->description.sWeight = fontDesc->sWeight; + newObject->description.sCharset = fontDesc->sCharset; + newObject->description.fItalic = fontDesc->fItalic; + newObject->description.fUnderline = fontDesc->fUnderline; + newObject->description.fStrikethrough = fontDesc->fStrikethrough; + + /* + * Initializing all the other members. + */ + newObject->gdiFont = 0; + newObject->fontLock = 0; + newObject->cyLogical = 72L; + newObject->cyHimetric = 2540L; + CreateConnectionPoint((IUnknown*)newObject, &IID_IPropertyNotifySink, &newObject->pCP); + TRACE("returning %p\n", newObject); + return newObject; +} + +/************************************************************************ + * OLEFontImpl_Destroy + * + * This method is called by the Release method when the reference + * count goes down to 0. It will free all resources used by + * this object. + */ +static void OLEFontImpl_Destroy(OLEFontImpl* fontDesc) +{ + TRACE("(%p)\n", fontDesc); + + HeapFree(GetProcessHeap(), 0, fontDesc->description.lpstrName); + + if (fontDesc->gdiFont!=0) + DeleteObject(fontDesc->gdiFont); + + HeapFree(GetProcessHeap(), 0, fontDesc); +} + +/************************************************************************ + * OLEFontImpl_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +HRESULT WINAPI OLEFontImpl_QueryInterface( + IFont* iface, + REFIID riid, + void** ppvObject) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%s, %p)\n", this, debugstr_guid(riid), ppvObject); + + /* + * Perform a sanity check on the parameters. + */ + if ( (this==0) || (ppvObject==0) ) + return E_INVALIDARG; + + /* + * Initialize the return parameter. + */ + *ppvObject = 0; + + /* + * Compare the riid with the interface IDs implemented by this object. + */ + if (IsEqualGUID(&IID_IUnknown, riid)) + *ppvObject = (IFont*)this; + if (IsEqualGUID(&IID_IFont, riid)) + *ppvObject = (IFont*)this; + if (IsEqualGUID(&IID_IDispatch, riid)) + *ppvObject = (IDispatch*)&(this->lpvtbl2); + if (IsEqualGUID(&IID_IFontDisp, riid)) + *ppvObject = (IDispatch*)&(this->lpvtbl2); + if (IsEqualGUID(&IID_IPersistStream, riid)) + *ppvObject = (IPersistStream*)&(this->lpvtbl3); + if (IsEqualGUID(&IID_IConnectionPointContainer, riid)) + *ppvObject = (IConnectionPointContainer*)&(this->lpvtbl4); + if (IsEqualGUID(&IID_IPersistPropertyBag, riid)) + *ppvObject = (IPersistPropertyBag*)&(this->lpvtbl5); + if (IsEqualGUID(&IID_IPersistStreamInit, riid)) + *ppvObject = (IPersistStreamInit*)&(this->lpvtbl6); + + /* + * Check that we obtained an interface. + */ + if ((*ppvObject)==0) + { + FIXME("() : asking for unsupported interface %s\n",debugstr_guid(riid)); + return E_NOINTERFACE; + } + OLEFontImpl_AddRef((IFont*)this); + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_AddRef (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +ULONG WINAPI OLEFontImpl_AddRef( + IFont* iface) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(ref=%ld)\n", this, this->ref); + return InterlockedIncrement(&this->ref); +} + +/************************************************************************ + * OLEFontImpl_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +ULONG WINAPI OLEFontImpl_Release( + IFont* iface) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + ULONG ret; + TRACE("(%p)->(ref=%ld)\n", this, this->ref); + + /* + * Decrease the reference count on this object. + */ + ret = InterlockedDecrement(&this->ref); + + /* + * If the reference count goes down to 0, perform suicide. + */ + if (ret==0) OLEFontImpl_Destroy(this); + + return ret; +} + +/************************************************************************ + * OLEFontImpl_get_Name (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_get_Name( + IFont* iface, + BSTR* pname) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%p)\n", this, pname); + /* + * Sanity check. + */ + if (pname==0) + return E_POINTER; + + if (this->description.lpstrName!=0) + *pname = SysAllocString(this->description.lpstrName); + else + *pname = 0; + + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_put_Name (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_put_Name( + IFont* iface, + BSTR name) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%p)\n", this, name); + + if (this->description.lpstrName==0) + { + this->description.lpstrName = HeapAlloc(GetProcessHeap(), + 0, + (lstrlenW(name)+1) * sizeof(WCHAR)); + } + else + { + this->description.lpstrName = HeapReAlloc(GetProcessHeap(), + 0, + this->description.lpstrName, + (lstrlenW(name)+1) * sizeof(WCHAR)); + } + + if (this->description.lpstrName==0) + return E_OUTOFMEMORY; + + strcpyW(this->description.lpstrName, name); + TRACE("new name %s\n", debugstr_w(this->description.lpstrName)); + OLEFont_SendNotify(this, DISPID_FONT_NAME); + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_get_Size (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_get_Size( + IFont* iface, + CY* psize) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%p)\n", this, psize); + + /* + * Sanity check + */ + if (psize==0) + return E_POINTER; + + psize->s.Hi = 0; + psize->s.Lo = this->description.cySize.s.Lo; + + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_put_Size (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_put_Size( + IFont* iface, + CY size) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%ld)\n", this, size.s.Lo); + this->description.cySize.s.Hi = 0; + this->description.cySize.s.Lo = size.s.Lo; + OLEFont_SendNotify(this, DISPID_FONT_SIZE); + + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_get_Bold (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_get_Bold( + IFont* iface, + BOOL* pbold) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%p)\n", this, pbold); + /* + * Sanity check + */ + if (pbold==0) + return E_POINTER; + + *pbold = this->description.sWeight > 550; + + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_put_Bold (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_put_Bold( + IFont* iface, + BOOL bold) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%d)\n", this, bold); + this->description.sWeight = bold ? FW_BOLD : FW_NORMAL; + OLEFont_SendNotify(this, DISPID_FONT_BOLD); + + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_get_Italic (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_get_Italic( + IFont* iface, + BOOL* pitalic) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%p)\n", this, pitalic); + /* + * Sanity check + */ + if (pitalic==0) + return E_POINTER; + + *pitalic = this->description.fItalic; + + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_put_Italic (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_put_Italic( + IFont* iface, + BOOL italic) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%d)\n", this, italic); + + this->description.fItalic = italic; + + OLEFont_SendNotify(this, DISPID_FONT_ITALIC); + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_get_Underline (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_get_Underline( + IFont* iface, + BOOL* punderline) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%p)\n", this, punderline); + + /* + * Sanity check + */ + if (punderline==0) + return E_POINTER; + + *punderline = this->description.fUnderline; + + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_put_Underline (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_put_Underline( + IFont* iface, + BOOL underline) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%d)\n", this, underline); + + this->description.fUnderline = underline; + + OLEFont_SendNotify(this, DISPID_FONT_UNDER); + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_get_Strikethrough (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_get_Strikethrough( + IFont* iface, + BOOL* pstrikethrough) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%p)\n", this, pstrikethrough); + + /* + * Sanity check + */ + if (pstrikethrough==0) + return E_POINTER; + + *pstrikethrough = this->description.fStrikethrough; + + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_put_Strikethrough (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_put_Strikethrough( + IFont* iface, + BOOL strikethrough) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%d)\n", this, strikethrough); + + this->description.fStrikethrough = strikethrough; + OLEFont_SendNotify(this, DISPID_FONT_STRIKE); + + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_get_Weight (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_get_Weight( + IFont* iface, + short* pweight) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%p)\n", this, pweight); + + /* + * Sanity check + */ + if (pweight==0) + return E_POINTER; + + *pweight = this->description.sWeight; + + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_put_Weight (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_put_Weight( + IFont* iface, + short weight) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%d)\n", this, weight); + + this->description.sWeight = weight; + + OLEFont_SendNotify(this, DISPID_FONT_WEIGHT); + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_get_Charset (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_get_Charset( + IFont* iface, + short* pcharset) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%p)\n", this, pcharset); + + /* + * Sanity check + */ + if (pcharset==0) + return E_POINTER; + + *pcharset = this->description.sCharset; + + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_put_Charset (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_put_Charset( + IFont* iface, + short charset) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%d)\n", this, charset); + + this->description.sCharset = charset; + OLEFont_SendNotify(this, DISPID_FONT_CHARSET); + + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_get_hFont (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_get_hFont( + IFont* iface, + HFONT* phfont) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%p)\n", this, phfont); + if (phfont==NULL) + return E_POINTER; + + /* + * Realize the font if necessary + */ + if (this->gdiFont==0) +{ + LOGFONTW logFont; + INT fontHeight; + CY cySize; + + /* + * The height of the font returned by the get_Size property is the + * height of the font in points multiplied by 10000... Using some + * simple conversions and the ratio given by the application, it can + * be converted to a height in pixels. + */ + IFont_get_Size(iface, &cySize); + + fontHeight = MulDiv( cySize.s.Lo, this->cyLogical, this->cyHimetric ); + + memset(&logFont, 0, sizeof(LOGFONTW)); + + logFont.lfHeight = ((fontHeight%10000L)>5000L) ? (-fontHeight/10000L)-1 : + (-fontHeight/10000L); + logFont.lfItalic = this->description.fItalic; + logFont.lfUnderline = this->description.fUnderline; + logFont.lfStrikeOut = this->description.fStrikethrough; + logFont.lfWeight = this->description.sWeight; + logFont.lfCharSet = this->description.sCharset; + logFont.lfOutPrecision = OUT_CHARACTER_PRECIS; + logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; + logFont.lfQuality = DEFAULT_QUALITY; + logFont.lfPitchAndFamily = DEFAULT_PITCH; + strcpyW(logFont.lfFaceName,this->description.lpstrName); + + this->gdiFont = CreateFontIndirectW(&logFont); + } + + *phfont = this->gdiFont; + TRACE("Returning %p\n", *phfont); + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_Clone (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_Clone( + IFont* iface, + IFont** ppfont) +{ + OLEFontImpl* newObject = 0; + LOGFONTW logFont; + INT fontHeight; + CY cySize; + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%p)\n", this, ppfont); + + if (ppfont == NULL) + return E_POINTER; + + *ppfont = NULL; + + /* + * Allocate space for the object. + */ + newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(OLEFontImpl)); + + if (newObject==NULL) + return E_OUTOFMEMORY; + + *newObject = *this; + + /* We need to alloc new memory for the string, otherwise + * we free memory twice. + */ + newObject->description.lpstrName = HeapAlloc( + GetProcessHeap(),0, + (1+strlenW(this->description.lpstrName))*2 + ); + strcpyW(newObject->description.lpstrName, this->description.lpstrName); + /* We need to clone the HFONT too. This is just cut & paste from above */ + IFont_get_Size(iface, &cySize); + + fontHeight = MulDiv(cySize.s.Lo, this->cyLogical,this->cyHimetric); + + memset(&logFont, 0, sizeof(LOGFONTW)); + + logFont.lfHeight = ((fontHeight%10000L)>5000L) ? (-fontHeight/10000L)-1 : + (-fontHeight/10000L); + logFont.lfItalic = this->description.fItalic; + logFont.lfUnderline = this->description.fUnderline; + logFont.lfStrikeOut = this->description.fStrikethrough; + logFont.lfWeight = this->description.sWeight; + logFont.lfCharSet = this->description.sCharset; + logFont.lfOutPrecision = OUT_CHARACTER_PRECIS; + logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; + logFont.lfQuality = DEFAULT_QUALITY; + logFont.lfPitchAndFamily = DEFAULT_PITCH; + strcpyW(logFont.lfFaceName,this->description.lpstrName); + + newObject->gdiFont = CreateFontIndirectW(&logFont); + + + /* The cloned object starts with a reference count of 1 */ + newObject->ref = 1; + + *ppfont = (IFont*)newObject; + + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_IsEqual (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_IsEqual( + IFont* iface, + IFont* pFontOther) +{ + FIXME("(%p, %p), stub!\n",iface,pFontOther); + return E_NOTIMPL; +} + +/************************************************************************ + * OLEFontImpl_SetRatio (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_SetRatio( + IFont* iface, + LONG cyLogical, + LONG cyHimetric) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%ld, %ld)\n", this, cyLogical, cyHimetric); + + this->cyLogical = cyLogical; + this->cyHimetric = cyHimetric; + + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_QueryTextMetrics (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_QueryTextMetrics( + IFont* iface, + TEXTMETRICOLE* ptm) +{ + HDC hdcRef; + HFONT hOldFont, hNewFont; + + hdcRef = GetDC(0); + OLEFontImpl_get_hFont(iface, &hNewFont); + hOldFont = SelectObject(hdcRef, hNewFont); + GetTextMetricsW(hdcRef, ptm); + SelectObject(hdcRef, hOldFont); + ReleaseDC(0, hdcRef); + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_AddRefHfont (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_AddRefHfont( + IFont* iface, + HFONT hfont) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%p) (lock=%ld)\n", this, hfont, this->fontLock); + + if ( (hfont == 0) || + (hfont != this->gdiFont) ) + return E_INVALIDARG; + + this->fontLock++; + + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_ReleaseHfont (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_ReleaseHfont( + IFont* iface, + HFONT hfont) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + TRACE("(%p)->(%p) (lock=%ld)\n", this, hfont, this->fontLock); + + if ( (hfont == 0) || + (hfont != this->gdiFont) ) + return E_INVALIDARG; + + this->fontLock--; + + /* + * If we just released our last font reference, destroy it. + */ + if (this->fontLock==0) + { + DeleteObject(this->gdiFont); + this->gdiFont = 0; + } + + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_SetHdc (IFont) + * + * See Windows documentation for more details on IFont methods. + */ +static HRESULT WINAPI OLEFontImpl_SetHdc( + IFont* iface, + HDC hdc) +{ + OLEFontImpl *this = (OLEFontImpl *)iface; + FIXME("(%p)->(%p): Stub\n", this, hdc); + return E_NOTIMPL; +} + +/************************************************************************ + * OLEFontImpl_IDispatch_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static HRESULT WINAPI OLEFontImpl_IDispatch_QueryInterface( + IDispatch* iface, + REFIID riid, + VOID** ppvoid) +{ + _ICOM_THIS_From_IDispatch(IFont, iface); + + return IFont_QueryInterface(this, riid, ppvoid); +} + +/************************************************************************ + * OLEFontImpl_IDispatch_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI OLEFontImpl_IDispatch_Release( + IDispatch* iface) +{ + _ICOM_THIS_From_IDispatch(IFont, iface); + + return IFont_Release(this); +} + +/************************************************************************ + * OLEFontImpl_IDispatch_AddRef (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI OLEFontImpl_IDispatch_AddRef( + IDispatch* iface) +{ + _ICOM_THIS_From_IDispatch(IFont, iface); + + return IFont_AddRef(this); +} + +/************************************************************************ + * OLEFontImpl_GetTypeInfoCount (IDispatch) + * + * See Windows documentation for more details on IDispatch methods. + */ +static HRESULT WINAPI OLEFontImpl_GetTypeInfoCount( + IDispatch* iface, + unsigned int* pctinfo) +{ + _ICOM_THIS_From_IDispatch(IFont, iface); + FIXME("(%p)->(%p): Stub\n", this, pctinfo); + + return E_NOTIMPL; +} + +/************************************************************************ + * OLEFontImpl_GetTypeInfo (IDispatch) + * + * See Windows documentation for more details on IDispatch methods. + */ +static HRESULT WINAPI OLEFontImpl_GetTypeInfo( + IDispatch* iface, + UINT iTInfo, + LCID lcid, + ITypeInfo** ppTInfo) +{ + static const WCHAR stdole32tlb[] = {'s','t','d','o','l','e','3','2','.','t','l','b',0}; + ITypeLib *tl; + HRESULT hres; + + _ICOM_THIS_From_IDispatch(OLEFontImpl, iface); + TRACE("(%p, iTInfo=%d, lcid=%04x, %p)\n", this, iTInfo, (int)lcid, ppTInfo); + if (iTInfo != 0) + return E_FAIL; + hres = LoadTypeLib(stdole32tlb, &tl); + if (FAILED(hres)) { + ERR("Could not load the stdole32.tlb?\n"); + return hres; + } + hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IDispatch, ppTInfo); + if (FAILED(hres)) { + FIXME("Did not IDispatch typeinfo from typelib, hres %lx\n",hres); + } + return hres; +} + +/************************************************************************ + * OLEFontImpl_GetIDsOfNames (IDispatch) + * + * See Windows documentation for more details on IDispatch methods. + */ +static HRESULT WINAPI OLEFontImpl_GetIDsOfNames( + IDispatch* iface, + REFIID riid, + LPOLESTR* rgszNames, + UINT cNames, + LCID lcid, + DISPID* rgDispId) +{ + _ICOM_THIS_From_IDispatch(IFont, iface); + FIXME("(%p,%s,%p,%d,%04x,%p), stub!\n", this, debugstr_guid(riid), rgszNames, + cNames, (int)lcid, rgDispId + ); + return E_NOTIMPL; +} + +/************************************************************************ + * OLEFontImpl_Invoke (IDispatch) + * + * See Windows documentation for more details on IDispatch methods. + * + * Note: Do not call _put_Xxx methods, since setting things here + * should not call notify functions as I found out debugging the generic + * MS VB5 installer. + */ +static HRESULT WINAPI OLEFontImpl_Invoke( + IDispatch* iface, + DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS* pDispParams, + VARIANT* pVarResult, + EXCEPINFO* pExepInfo, + UINT* puArgErr) +{ + _ICOM_THIS_From_IDispatch(IFont, iface); + OLEFontImpl *xthis = (OLEFontImpl*)this; + + switch (dispIdMember) { + case DISPID_FONT_NAME: + switch (wFlags) { + case DISPATCH_PROPERTYGET: + case DISPATCH_PROPERTYGET|DISPATCH_METHOD: + V_VT(pVarResult) = VT_BSTR; + return OLEFontImpl_get_Name(this, &V_BSTR(pVarResult)); + case DISPATCH_PROPERTYPUT: { + BSTR name; + BOOL freename; + + if (V_VT(&pDispParams->rgvarg[0]) == VT_DISPATCH) { + IFont *font; + HRESULT hr = S_OK; + + hr = IUnknown_QueryInterface(V_DISPATCH(&pDispParams->rgvarg[0]), &IID_IFont, (void **) &font); + if (FAILED(hr)) + { + FIXME("dispatch value for name property is not an OleFont, returning hr=0x%lx\n", hr); + return hr; + } + + hr = IFont_get_Name(font, &name); /* this allocates a new BSTR so free it later */ + if (FAILED(hr)) return hr; + + IUnknown_Release(font); + + freename = TRUE; + } else if (V_VT(&pDispParams->rgvarg[0]) == VT_BSTR) { + name = V_BSTR(&pDispParams->rgvarg[0]); + freename = FALSE; + } else { + FIXME("app is trying to set name property with a non BSTR, non dispatch value. returning E_FAIL\n"); + return E_FAIL; + } + + TRACE("name is %s\n", debugstr_w(name)); + + if (!xthis->description.lpstrName) + xthis->description.lpstrName = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(name)+1) * sizeof(WCHAR)); + else + xthis->description.lpstrName = HeapReAlloc(GetProcessHeap(), 0, xthis->description.lpstrName, (lstrlenW(name)+1) * sizeof(WCHAR)); + + if (xthis->description.lpstrName==0) + return E_OUTOFMEMORY; + strcpyW(xthis->description.lpstrName, name); + + if (freename) SysFreeString(name); + + return S_OK; + } + } + break; + case DISPID_FONT_BOLD: + switch (wFlags) { + case DISPATCH_PROPERTYGET: + case DISPATCH_PROPERTYGET|DISPATCH_METHOD: + V_VT(pVarResult) = VT_BOOL; + return OLEFontImpl_get_Bold(this, (BOOL*)&V_BOOL(pVarResult)); + case DISPATCH_PROPERTYPUT: + if (V_VT(&pDispParams->rgvarg[0]) != VT_BOOL) { + FIXME("DISPID_FONT_BOLD/put, vt is %d, not VT_BOOL.\n",V_VT(&pDispParams->rgvarg[0])); + return E_FAIL; + } else { + xthis->description.sWeight = V_BOOL(&pDispParams->rgvarg[0]) ? FW_BOLD : FW_NORMAL; + return S_OK; + } + } + break; + case DISPID_FONT_ITALIC: + switch (wFlags) { + case DISPATCH_PROPERTYGET: + case DISPATCH_PROPERTYGET|DISPATCH_METHOD: + V_VT(pVarResult) = VT_BOOL; + return OLEFontImpl_get_Italic(this, (BOOL*)&V_BOOL(pVarResult)); + case DISPATCH_PROPERTYPUT: + if (V_VT(&pDispParams->rgvarg[0]) != VT_BOOL) { + FIXME("DISPID_FONT_ITALIC/put, vt is %d, not VT_BOOL.\n",V_VT(&pDispParams->rgvarg[0])); + return E_FAIL; + } else { + xthis->description.fItalic = V_BOOL(&pDispParams->rgvarg[0]); + return S_OK; + } + } + break; + case DISPID_FONT_UNDER: + switch (wFlags) { + case DISPATCH_PROPERTYGET: + case DISPATCH_PROPERTYGET|DISPATCH_METHOD: + V_VT(pVarResult) = VT_BOOL; + return OLEFontImpl_get_Underline(this, (BOOL*)&V_BOOL(pVarResult)); + case DISPATCH_PROPERTYPUT: + if (V_VT(&pDispParams->rgvarg[0]) != VT_BOOL) { + FIXME("DISPID_FONT_UNDER/put, vt is %d, not VT_BOOL.\n",V_VT(&pDispParams->rgvarg[0])); + return E_FAIL; + } else { + xthis->description.fUnderline = V_BOOL(&pDispParams->rgvarg[0]); + return S_OK; + } + } + break; + case DISPID_FONT_STRIKE: + switch (wFlags) { + case DISPATCH_PROPERTYGET: + case DISPATCH_PROPERTYGET|DISPATCH_METHOD: + V_VT(pVarResult) = VT_BOOL; + return OLEFontImpl_get_Strikethrough(this, (BOOL*)&V_BOOL(pVarResult)); + case DISPATCH_PROPERTYPUT: + if (V_VT(&pDispParams->rgvarg[0]) != VT_BOOL) { + FIXME("DISPID_FONT_STRIKE/put, vt is %d, not VT_BOOL.\n",V_VT(&pDispParams->rgvarg[0])); + return E_FAIL; + } else { + xthis->description.fStrikethrough = V_BOOL(&pDispParams->rgvarg[0]); + return S_OK; + } + } + break; + case DISPID_FONT_SIZE: + switch (wFlags) { + case DISPATCH_PROPERTYPUT: { + assert (pDispParams->cArgs == 1); + xthis->description.cySize.s.Hi = 0; + if (V_VT(&pDispParams->rgvarg[0]) != VT_CY) { + if (V_VT(&pDispParams->rgvarg[0]) == VT_I2) { + xthis->description.cySize.s.Lo = V_I2(&pDispParams->rgvarg[0]) * 10000; + } else { + FIXME("property put for Size with vt %d unsupported!\n",V_VT(&pDispParams->rgvarg[0])); + } + } else { + xthis->description.cySize.s.Lo = V_CY(&pDispParams->rgvarg[0]).s.Lo; + } + return S_OK; + } + case DISPATCH_PROPERTYGET: + case DISPATCH_PROPERTYGET|DISPATCH_METHOD: + V_VT(pVarResult) = VT_CY; + return OLEFontImpl_get_Size(this, &V_CY(pVarResult)); + } + break; + case DISPID_FONT_CHARSET: + switch (wFlags) { + case DISPATCH_PROPERTYPUT: + assert (pDispParams->cArgs == 1); + if (V_VT(&pDispParams->rgvarg[0]) != VT_I2) + FIXME("varg of first disparg is not VT_I2, but %d\n",V_VT(&pDispParams->rgvarg[0])); + xthis->description.sCharset = V_I2(&pDispParams->rgvarg[0]); + return S_OK; + case DISPATCH_PROPERTYGET: + case DISPATCH_PROPERTYGET|DISPATCH_METHOD: + V_VT(pVarResult) = VT_I2; + return OLEFontImpl_get_Charset(this, &V_I2(pVarResult)); + } + break; + } + FIXME("%p->(%ld,%s,%lx,%x,%p,%p,%p,%p), unhandled dispid/flag!\n", + this,dispIdMember,debugstr_guid(riid),lcid, + wFlags,pDispParams,pVarResult,pExepInfo,puArgErr + ); + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_IPersistStream_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static HRESULT WINAPI OLEFontImpl_IPersistStream_QueryInterface( + IPersistStream* iface, + REFIID riid, + VOID** ppvoid) +{ + _ICOM_THIS_From_IPersistStream(IFont, iface); + + return IFont_QueryInterface(this, riid, ppvoid); +} + +/************************************************************************ + * OLEFontImpl_IPersistStream_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI OLEFontImpl_IPersistStream_Release( + IPersistStream* iface) +{ + _ICOM_THIS_From_IPersistStream(IFont, iface); + + return IFont_Release(this); +} + +/************************************************************************ + * OLEFontImpl_IPersistStream_AddRef (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI OLEFontImpl_IPersistStream_AddRef( + IPersistStream* iface) +{ + _ICOM_THIS_From_IPersistStream(IFont, iface); + + return IFont_AddRef(this); +} + +/************************************************************************ + * OLEFontImpl_GetClassID (IPersistStream) + * + * See Windows documentation for more details on IPersistStream methods. + */ +static HRESULT WINAPI OLEFontImpl_GetClassID( + IPersistStream* iface, + CLSID* pClassID) +{ + TRACE("(%p,%p)\n",iface,pClassID); + if (pClassID==0) + return E_POINTER; + + memcpy(pClassID, &CLSID_StdFont, sizeof(CLSID_StdFont)); + + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_IsDirty (IPersistStream) + * + * See Windows documentation for more details on IPersistStream methods. + */ +static HRESULT WINAPI OLEFontImpl_IsDirty( + IPersistStream* iface) +{ + TRACE("(%p)\n",iface); + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_Load (IPersistStream) + * + * See Windows documentation for more details on IPersistStream methods. + * + * This is the format of the standard font serialization as far as I + * know + * + * Offset Type Value Comment + * 0x0000 Byte Unknown Probably a version number, contains 0x01 + * 0x0001 Short Charset Charset value from the FONTDESC structure + * 0x0003 Byte Attributes Flags defined as follows: + * 00000010 - Italic + * 00000100 - Underline + * 00001000 - Strikethrough + * 0x0004 Short Weight Weight value from FONTDESC structure + * 0x0006 DWORD size "Low" portion of the cySize member of the FONTDESC + * structure/ + * 0x000A Byte name length Length of the font name string (no null character) + * 0x000B String name Name of the font (ASCII, no nul character) + */ +static HRESULT WINAPI OLEFontImpl_Load( + IPersistStream* iface, + IStream* pLoadStream) +{ + char readBuffer[0x100]; + ULONG cbRead; + BYTE bVersion; + BYTE bAttributes; + BYTE bStringSize; + INT len; + + _ICOM_THIS_From_IPersistStream(OLEFontImpl, iface); + + /* + * Read the version byte + */ + IStream_Read(pLoadStream, &bVersion, 1, &cbRead); + + if ( (cbRead!=1) || + (bVersion!=0x01) ) + return E_FAIL; + + /* + * Charset + */ + IStream_Read(pLoadStream, &this->description.sCharset, 2, &cbRead); + + if (cbRead!=2) + return E_FAIL; + + /* + * Attributes + */ + IStream_Read(pLoadStream, &bAttributes, 1, &cbRead); + + if (cbRead!=1) + return E_FAIL; + + this->description.fItalic = (bAttributes & FONTPERSIST_ITALIC) != 0; + this->description.fStrikethrough = (bAttributes & FONTPERSIST_STRIKETHROUGH) != 0; + this->description.fUnderline = (bAttributes & FONTPERSIST_UNDERLINE) != 0; + + /* + * Weight + */ + IStream_Read(pLoadStream, &this->description.sWeight, 2, &cbRead); + + if (cbRead!=2) + return E_FAIL; + + /* + * Size + */ + IStream_Read(pLoadStream, &this->description.cySize.s.Lo, 4, &cbRead); + + if (cbRead!=4) + return E_FAIL; + + this->description.cySize.s.Hi = 0; + + /* + * FontName + */ + IStream_Read(pLoadStream, &bStringSize, 1, &cbRead); + + if (cbRead!=1) + return E_FAIL; + + IStream_Read(pLoadStream, readBuffer, bStringSize, &cbRead); + + if (cbRead!=bStringSize) + return E_FAIL; + + HeapFree(GetProcessHeap(), 0, this->description.lpstrName); + + len = MultiByteToWideChar( CP_ACP, 0, readBuffer, bStringSize, NULL, 0 ); + this->description.lpstrName = HeapAlloc( GetProcessHeap(), 0, (len+1) * sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, readBuffer, bStringSize, this->description.lpstrName, len ); + this->description.lpstrName[len] = 0; + + /* Ensure use of this font causes a new one to be created @@@@ */ + DeleteObject(this->gdiFont); + this->gdiFont = 0; + + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_Save (IPersistStream) + * + * See Windows documentation for more details on IPersistStream methods. + */ +static HRESULT WINAPI OLEFontImpl_Save( + IPersistStream* iface, + IStream* pOutStream, + BOOL fClearDirty) +{ + char* writeBuffer = NULL; + ULONG cbWritten; + BYTE bVersion = 0x01; + BYTE bAttributes; + BYTE bStringSize; + + _ICOM_THIS_From_IPersistStream(OLEFontImpl, iface); + + /* + * Read the version byte + */ + IStream_Write(pOutStream, &bVersion, 1, &cbWritten); + + if (cbWritten!=1) + return E_FAIL; + + /* + * Charset + */ + IStream_Write(pOutStream, &this->description.sCharset, 2, &cbWritten); + + if (cbWritten!=2) + return E_FAIL; + + /* + * Attributes + */ + bAttributes = 0; + + if (this->description.fItalic) + bAttributes |= FONTPERSIST_ITALIC; + + if (this->description.fStrikethrough) + bAttributes |= FONTPERSIST_STRIKETHROUGH; + + if (this->description.fUnderline) + bAttributes |= FONTPERSIST_UNDERLINE; + + IStream_Write(pOutStream, &bAttributes, 1, &cbWritten); + + if (cbWritten!=1) + return E_FAIL; + + /* + * Weight + */ + IStream_Write(pOutStream, &this->description.sWeight, 2, &cbWritten); + + if (cbWritten!=2) + return E_FAIL; + + /* + * Size + */ + IStream_Write(pOutStream, &this->description.cySize.s.Lo, 4, &cbWritten); + + if (cbWritten!=4) + return E_FAIL; + + /* + * FontName + */ + if (this->description.lpstrName!=0) + bStringSize = WideCharToMultiByte( CP_ACP, 0, this->description.lpstrName, + strlenW(this->description.lpstrName), NULL, 0, NULL, NULL ); + else + bStringSize = 0; + + IStream_Write(pOutStream, &bStringSize, 1, &cbWritten); + + if (cbWritten!=1) + return E_FAIL; + + if (bStringSize!=0) + { + if (!(writeBuffer = HeapAlloc( GetProcessHeap(), 0, bStringSize ))) return E_OUTOFMEMORY; + WideCharToMultiByte( CP_ACP, 0, this->description.lpstrName, + strlenW(this->description.lpstrName), + writeBuffer, bStringSize, NULL, NULL ); + + IStream_Write(pOutStream, writeBuffer, bStringSize, &cbWritten); + HeapFree(GetProcessHeap(), 0, writeBuffer); + + if (cbWritten!=bStringSize) + return E_FAIL; + } + + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_GetSizeMax (IPersistStream) + * + * See Windows documentation for more details on IPersistStream methods. + */ +static HRESULT WINAPI OLEFontImpl_GetSizeMax( + IPersistStream* iface, + ULARGE_INTEGER* pcbSize) +{ + _ICOM_THIS_From_IPersistStream(OLEFontImpl, iface); + + if (pcbSize==NULL) + return E_POINTER; + + pcbSize->u.HighPart = 0; + pcbSize->u.LowPart = 0; + + pcbSize->u.LowPart += sizeof(BYTE); /* Version */ + pcbSize->u.LowPart += sizeof(WORD); /* Lang code */ + pcbSize->u.LowPart += sizeof(BYTE); /* Flags */ + pcbSize->u.LowPart += sizeof(WORD); /* Weight */ + pcbSize->u.LowPart += sizeof(DWORD); /* Size */ + pcbSize->u.LowPart += sizeof(BYTE); /* StrLength */ + + if (this->description.lpstrName!=0) + pcbSize->u.LowPart += lstrlenW(this->description.lpstrName); + + return S_OK; +} + +/************************************************************************ + * OLEFontImpl_IConnectionPointContainer_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static HRESULT WINAPI OLEFontImpl_IConnectionPointContainer_QueryInterface( + IConnectionPointContainer* iface, + REFIID riid, + VOID** ppvoid) +{ + _ICOM_THIS_From_IConnectionPointContainer(OLEFontImpl, iface); + + return IFont_QueryInterface((IFont*)this, riid, ppvoid); +} + +/************************************************************************ + * OLEFontImpl_IConnectionPointContainer_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI OLEFontImpl_IConnectionPointContainer_Release( + IConnectionPointContainer* iface) +{ + _ICOM_THIS_From_IConnectionPointContainer(OLEFontImpl, iface); + + return IFont_Release((IFont*)this); +} + +/************************************************************************ + * OLEFontImpl_IConnectionPointContainer_AddRef (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI OLEFontImpl_IConnectionPointContainer_AddRef( + IConnectionPointContainer* iface) +{ + _ICOM_THIS_From_IConnectionPointContainer(OLEFontImpl, iface); + + return IFont_AddRef((IFont*)this); +} + +/************************************************************************ + * OLEFontImpl_EnumConnectionPoints (IConnectionPointContainer) + * + * See Windows documentation for more details on IConnectionPointContainer + * methods. + */ +static HRESULT WINAPI OLEFontImpl_EnumConnectionPoints( + IConnectionPointContainer* iface, + IEnumConnectionPoints **ppEnum) +{ + _ICOM_THIS_From_IConnectionPointContainer(OLEFontImpl, iface); + + FIXME("(%p)->(%p): stub\n", this, ppEnum); + return E_NOTIMPL; +} + +/************************************************************************ + * OLEFontImpl_FindConnectionPoint (IConnectionPointContainer) + * + * See Windows documentation for more details on IConnectionPointContainer + * methods. + */ +static HRESULT WINAPI OLEFontImpl_FindConnectionPoint( + IConnectionPointContainer* iface, + REFIID riid, + IConnectionPoint **ppCp) +{ + _ICOM_THIS_From_IConnectionPointContainer(OLEFontImpl, iface); + TRACE("(%p)->(%s, %p): stub\n", this, debugstr_guid(riid), ppCp); + + if(memcmp(riid, &IID_IPropertyNotifySink, sizeof(IID_IPropertyNotifySink)) == 0) { + return IConnectionPoint_QueryInterface(this->pCP, &IID_IConnectionPoint, + (LPVOID)ppCp); + } else { + FIXME("Tried to find connection point on %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; + } +} + +/************************************************************************ + * OLEFontImpl implementation of IPersistPropertyBag. + */ +static HRESULT WINAPI OLEFontImpl_IPersistPropertyBag_QueryInterface( + IPersistPropertyBag *iface, REFIID riid, LPVOID *ppvObj +) { + _ICOM_THIS_From_IPersistPropertyBag(IFont, iface); + return IFont_QueryInterface(this,riid,ppvObj); +} + +static ULONG WINAPI OLEFontImpl_IPersistPropertyBag_AddRef( + IPersistPropertyBag *iface +) { + _ICOM_THIS_From_IPersistPropertyBag(IFont, iface); + return IFont_AddRef(this); +} + +static ULONG WINAPI OLEFontImpl_IPersistPropertyBag_Release( + IPersistPropertyBag *iface +) { + _ICOM_THIS_From_IPersistPropertyBag(IFont, iface); + return IFont_Release(this); +} + +static HRESULT WINAPI OLEFontImpl_IPersistPropertyBag_GetClassID( + IPersistPropertyBag *iface, CLSID *classid +) { + FIXME("(%p,%p), stub!\n", iface, classid); + return E_FAIL; +} + +static HRESULT WINAPI OLEFontImpl_IPersistPropertyBag_InitNew( + IPersistPropertyBag *iface +) { + FIXME("(%p), stub!\n", iface); + return S_OK; +} + +static HRESULT WINAPI OLEFontImpl_IPersistPropertyBag_Load( + IPersistPropertyBag *iface, IPropertyBag* pPropBag, IErrorLog* pErrorLog +) { +/* (from Visual Basic 6 property bag) + Name = "MS Sans Serif" + Size = 13.8 + Charset = 0 + Weight = 400 + Underline = 0 'False + Italic = 0 'False + Strikethrough = 0 'False +*/ + static const WCHAR sAttrName[] = {'N','a','m','e',0}; + static const WCHAR sAttrSize[] = {'S','i','z','e',0}; + static const WCHAR sAttrCharset[] = {'C','h','a','r','s','e','t',0}; + static const WCHAR sAttrWeight[] = {'W','e','i','g','h','t',0}; + static const WCHAR sAttrUnderline[] = {'U','n','d','e','r','l','i','n','e',0}; + static const WCHAR sAttrItalic[] = {'I','t','a','l','i','c',0}; + static const WCHAR sAttrStrikethrough[] = {'S','t','r','i','k','e','t','h','r','o','u','g','h',0}; + VARIANT rawAttr; + VARIANT valueAttr; + HRESULT iRes = S_OK; + _ICOM_THIS_From_IPersistPropertyBag(IFont, iface); + + VariantInit(&rawAttr); + VariantInit(&valueAttr); + + if (iRes == S_OK) { + iRes = IPropertyBag_Read(pPropBag, sAttrName, &rawAttr, pErrorLog); + if (iRes == S_OK) + { + iRes = VariantChangeType(&rawAttr, &valueAttr, 0, VT_BSTR); + if (iRes == S_OK) + iRes = IFont_put_Name(this, V_BSTR(&valueAttr)); + } + else if (iRes == E_INVALIDARG) + iRes = S_OK; + VariantClear(&rawAttr); + VariantClear(&valueAttr); + } + + if (iRes == S_OK) { + iRes = IPropertyBag_Read(pPropBag, sAttrSize, &rawAttr, pErrorLog); + if (iRes == S_OK) + { + iRes = VariantChangeType(&rawAttr, &valueAttr, 0, VT_CY); + if (iRes == S_OK) + iRes = IFont_put_Size(this, V_CY(&valueAttr)); + } + else if (iRes == E_INVALIDARG) + iRes = S_OK; + VariantClear(&rawAttr); + VariantClear(&valueAttr); + } + + if (iRes == S_OK) { + iRes = IPropertyBag_Read(pPropBag, sAttrCharset, &rawAttr, pErrorLog); + if (iRes == S_OK) + { + iRes = VariantChangeType(&rawAttr, &valueAttr, 0, VT_I2); + if (iRes == S_OK) + iRes = IFont_put_Charset(this, V_I2(&valueAttr)); + } + else if (iRes == E_INVALIDARG) + iRes = S_OK; + VariantClear(&rawAttr); + VariantClear(&valueAttr); + } + + if (iRes == S_OK) { + iRes = IPropertyBag_Read(pPropBag, sAttrWeight, &rawAttr, pErrorLog); + if (iRes == S_OK) + { + iRes = VariantChangeType(&rawAttr, &valueAttr, 0, VT_I2); + if (iRes == S_OK) + iRes = IFont_put_Weight(this, V_I2(&valueAttr)); + } + else if (iRes == E_INVALIDARG) + iRes = S_OK; + VariantClear(&rawAttr); + VariantClear(&valueAttr); + + } + + if (iRes == S_OK) { + iRes = IPropertyBag_Read(pPropBag, sAttrUnderline, &rawAttr, pErrorLog); + if (iRes == S_OK) + { + iRes = VariantChangeType(&rawAttr, &valueAttr, 0, VT_BOOL); + if (iRes == S_OK) + iRes = IFont_put_Underline(this, V_BOOL(&valueAttr)); + } + else if (iRes == E_INVALIDARG) + iRes = S_OK; + VariantClear(&rawAttr); + VariantClear(&valueAttr); + } + + if (iRes == S_OK) { + iRes = IPropertyBag_Read(pPropBag, sAttrItalic, &rawAttr, pErrorLog); + if (iRes == S_OK) + { + iRes = VariantChangeType(&rawAttr, &valueAttr, 0, VT_BOOL); + if (iRes == S_OK) + iRes = IFont_put_Italic(this, V_BOOL(&valueAttr)); + } + else if (iRes == E_INVALIDARG) + iRes = S_OK; + VariantClear(&rawAttr); + VariantClear(&valueAttr); + } + + if (iRes == S_OK) { + iRes = IPropertyBag_Read(pPropBag, sAttrStrikethrough, &rawAttr, pErrorLog); + if (iRes == S_OK) + { + iRes = VariantChangeType(&rawAttr, &valueAttr, 0, VT_BOOL); + if (iRes == S_OK) + IFont_put_Strikethrough(this, V_BOOL(&valueAttr)); + } + else if (iRes == E_INVALIDARG) + iRes = S_OK; + VariantClear(&rawAttr); + VariantClear(&valueAttr); + } + + if (FAILED(iRes)) + WARN("-- 0x%08lx\n", iRes); + return iRes; +} + +static HRESULT WINAPI OLEFontImpl_IPersistPropertyBag_Save( + IPersistPropertyBag *iface, IPropertyBag* pPropBag, BOOL fClearDirty, + BOOL fSaveAllProperties +) { + FIXME("(%p,%p,%d,%d), stub!\n", iface, pPropBag, fClearDirty, fSaveAllProperties); + return E_FAIL; +} + +static IPersistPropertyBagVtbl OLEFontImpl_IPersistPropertyBag_VTable = +{ + OLEFontImpl_IPersistPropertyBag_QueryInterface, + OLEFontImpl_IPersistPropertyBag_AddRef, + OLEFontImpl_IPersistPropertyBag_Release, + + OLEFontImpl_IPersistPropertyBag_GetClassID, + OLEFontImpl_IPersistPropertyBag_InitNew, + OLEFontImpl_IPersistPropertyBag_Load, + OLEFontImpl_IPersistPropertyBag_Save +}; + +/************************************************************************ + * OLEFontImpl implementation of IPersistStreamInit. + */ +static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_QueryInterface( + IPersistStreamInit *iface, REFIID riid, LPVOID *ppvObj +) { + _ICOM_THIS_From_IPersistStreamInit(IFont, iface); + return IFont_QueryInterface(this,riid,ppvObj); +} + +static ULONG WINAPI OLEFontImpl_IPersistStreamInit_AddRef( + IPersistStreamInit *iface +) { + _ICOM_THIS_From_IPersistStreamInit(IFont, iface); + return IFont_AddRef(this); +} + +static ULONG WINAPI OLEFontImpl_IPersistStreamInit_Release( + IPersistStreamInit *iface +) { + _ICOM_THIS_From_IPersistStreamInit(IFont, iface); + return IFont_Release(this); +} + +static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_GetClassID( + IPersistStreamInit *iface, CLSID *classid +) { + FIXME("(%p,%p), stub!\n", iface, classid); + return E_FAIL; +} + +static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_IsDirty( + IPersistStreamInit *iface +) { + FIXME("(%p), stub!\n", iface); + return E_FAIL; +} + +static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_Load( + IPersistStreamInit *iface, LPSTREAM pStm +) { + FIXME("(%p,%p), stub!\n", iface, pStm); + return E_FAIL; +} + +static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_Save( + IPersistStreamInit *iface, LPSTREAM pStm, BOOL fClearDirty +) { + FIXME("(%p,%p,%d), stub!\n", iface, pStm, fClearDirty); + return E_FAIL; +} + +static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_GetSizeMax( + IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize +) { + FIXME("(%p,%p), stub!\n", iface, pcbSize); + return E_FAIL; +} + +static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_InitNew( + IPersistStreamInit *iface +) { + FIXME("(%p), stub!\n", iface); + return S_OK; +} + +static IPersistStreamInitVtbl OLEFontImpl_IPersistStreamInit_VTable = +{ + OLEFontImpl_IPersistStreamInit_QueryInterface, + OLEFontImpl_IPersistStreamInit_AddRef, + OLEFontImpl_IPersistStreamInit_Release, + + OLEFontImpl_IPersistStreamInit_GetClassID, + OLEFontImpl_IPersistStreamInit_IsDirty, + OLEFontImpl_IPersistStreamInit_Load, + OLEFontImpl_IPersistStreamInit_Save, + OLEFontImpl_IPersistStreamInit_GetSizeMax, + OLEFontImpl_IPersistStreamInit_InitNew +}; + +/******************************************************************************* + * StdFont ClassFactory + */ +typedef struct +{ + /* IUnknown fields */ + IClassFactoryVtbl *lpVtbl; + DWORD ref; +} IClassFactoryImpl; + +static HRESULT WINAPI +SFCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + + FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj); + return E_NOINTERFACE; +} + +static ULONG WINAPI +SFCF_AddRef(LPCLASSFACTORY iface) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI SFCF_Release(LPCLASSFACTORY iface) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + /* static class, won't be freed */ + return InterlockedDecrement(&This->ref); +} + +static HRESULT WINAPI SFCF_CreateInstance( + LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj +) { + return OleCreateFontIndirect(NULL,riid,ppobj); + +} + +static HRESULT WINAPI SFCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + FIXME("(%p)->(%d),stub!\n",This,dolock); + return S_OK; +} + +static IClassFactoryVtbl SFCF_Vtbl = { + SFCF_QueryInterface, + SFCF_AddRef, + SFCF_Release, + SFCF_CreateInstance, + SFCF_LockServer +}; +static IClassFactoryImpl STDFONT_CF = {&SFCF_Vtbl, 1 }; + +void _get_STDFONT_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDFONT_CF; } diff --git a/reactos/lib/oleaut32/olepicture.c b/reactos/lib/oleaut32/olepicture.c index 1eb9195ea06..b0d35327f01 100644 --- a/reactos/lib/oleaut32/olepicture.c +++ b/reactos/lib/oleaut32/olepicture.c @@ -1,2239 +1,2239 @@ -/* - * OLE Picture object - * - * Implementation of OLE IPicture and related interfaces - * - * Copyright 2000 Huw D M Davies for CodeWeavers. - * Copyright 2001 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * BUGS - * - * Support PICTYPE_BITMAP and PICTYPE_ICON, altough only bitmaps very well.. - * Lots of methods are just stubs. - * - * - * NOTES (or things that msdn doesn't tell you) - * - * The width and height properties are returned in HIMETRIC units (0.01mm) - * IPicture::Render also uses these to select a region of the src picture. - * A bitmap's size is converted into these units by using the screen resolution - * thus an 8x8 bitmap on a 96dpi screen has a size of 212x212 (8/96 * 2540). - * - */ - -#include "config.h" -#include "wine/port.h" - -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#endif -#include <stdarg.h> -#include <stdio.h> -#include <string.h> - -/* Must be before wine includes, the header has things conflicting with - * WINE headers. - */ -#ifdef HAVE_GIF_LIB_H -# include <gif_lib.h> -# ifndef SONAME_LIBUNGIF -# define SONAME_LIBUNGIF "libungif.so" -# endif -# ifndef SONAME_LIBGIF -# define SONAME_LIBGIF "libgif.so" -# endif -#endif - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "winerror.h" -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "ole2.h" -#include "olectl.h" -#include "oleauto.h" -#include "connpt.h" -#include "urlmon.h" -#include "wine/debug.h" -#include "wine/unicode.h" - -#include "wine/wingdi16.h" -#include "cursoricon.h" - -#ifdef HAVE_JPEGLIB_H -/* This is a hack, so jpeglib.h does not redefine INT32 and the like*/ -#define XMD_H -#define UINT8 JPEG_UINT8 -#define UINT16 JPEG_UINT16 -#undef FAR -# include <jpeglib.h> -#undef UINT16 -#ifndef SONAME_LIBJPEG -#define SONAME_LIBJPEG "libjpeg.so" -#endif -#endif - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/************************************************************************* - * Declaration of implementation class - */ - -typedef struct OLEPictureImpl { - - /* - * IPicture handles IUnknown - */ - - IPictureVtbl *lpvtbl1; - IDispatchVtbl *lpvtbl2; - IPersistStreamVtbl *lpvtbl3; - IConnectionPointContainerVtbl *lpvtbl4; - - /* Object reference count */ - DWORD ref; - - /* We own the object and must destroy it ourselves */ - BOOL fOwn; - - /* Picture description */ - PICTDESC desc; - - /* These are the pixel size of a bitmap */ - DWORD origWidth; - DWORD origHeight; - - /* And these are the size of the picture converted into HIMETRIC units */ - OLE_XSIZE_HIMETRIC himetricWidth; - OLE_YSIZE_HIMETRIC himetricHeight; - - IConnectionPoint *pCP; - - BOOL keepOrigFormat; - HDC hDCCur; - - /* Bitmap transparency mask */ - HBITMAP hbmMask; - HBITMAP hbmXor; - COLORREF rgbTrans; - - /* data */ - void* data; - int datalen; - BOOL bIsDirty; /* Set to TRUE if picture has changed */ - unsigned int loadtime_magic; /* If a length header was found, saves value */ - unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */ -} OLEPictureImpl; - -/* - * Macros to retrieve pointer to IUnknown (IPicture) from the other VTables. - */ -#define ICOM_THIS_From_IDispatch(impl, name) \ - impl *This = (impl*)(((char*)name)-sizeof(void*)); -#define ICOM_THIS_From_IPersistStream(impl, name) \ - impl *This = (impl*)(((char*)name)-2*sizeof(void*)); -#define ICOM_THIS_From_IConnectionPointContainer(impl, name) \ - impl *This = (impl*)(((char*)name)-3*sizeof(void*)); - -/* - * Predeclare VTables. They get initialized at the end. - */ -static IPictureVtbl OLEPictureImpl_VTable; -static IDispatchVtbl OLEPictureImpl_IDispatch_VTable; -static IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable; -static IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable; - -/*********************************************************************** - * Implementation of the OLEPictureImpl class. - */ - -static void OLEPictureImpl_SetBitmap(OLEPictureImpl*This) { - BITMAP bm; - HDC hdcRef; - - TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap); - if(GetObjectA(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) { - ERR("GetObject fails\n"); - return; - } - This->origWidth = bm.bmWidth; - This->origHeight = bm.bmHeight; - /* The width and height are stored in HIMETRIC units (0.01 mm), - so we take our pixel width divide by pixels per inch and - multiply by 25.4 * 100 */ - /* Should we use GetBitmapDimension if available? */ - hdcRef = CreateCompatibleDC(0); - This->himetricWidth =(bm.bmWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX); - This->himetricHeight=(bm.bmHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY); - DeleteDC(hdcRef); -} - -static void OLEPictureImpl_SetIcon(OLEPictureImpl * This) -{ - ICONINFO infoIcon; - - TRACE("icon handle %p\n", This->desc.u.icon.hicon); - if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) { - HDC hdcRef; - BITMAP bm; - - TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor); - if(GetObjectA(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) { - ERR("GetObject fails on icon bitmap\n"); - return; - } - - This->origWidth = bm.bmWidth; - This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2; - /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */ - hdcRef = GetDC(0); - This->himetricWidth = (This->origWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX); - This->himetricHeight= (This->origHeight *2540)/GetDeviceCaps(hdcRef, LOGPIXELSY); - ReleaseDC(0, hdcRef); - - DeleteObject(infoIcon.hbmMask); - if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor); - } else { - ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon); - } -} - -/************************************************************************ - * OLEPictureImpl_Construct - * - * This method will construct a new instance of the OLEPictureImpl - * class. - * - * The caller of this method must release the object when it's - * done with it. - */ -static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn) -{ - OLEPictureImpl* newObject = 0; - - if (pictDesc) - TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType); - - /* - * Allocate space for the object. - */ - newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl)); - - if (newObject==0) - return newObject; - - /* - * Initialize the virtual function table. - */ - newObject->lpvtbl1 = &OLEPictureImpl_VTable; - newObject->lpvtbl2 = &OLEPictureImpl_IDispatch_VTable; - newObject->lpvtbl3 = &OLEPictureImpl_IPersistStream_VTable; - newObject->lpvtbl4 = &OLEPictureImpl_IConnectionPointContainer_VTable; - - CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP); - - /* - * Start with one reference count. The caller of this function - * must release the interface pointer when it is done. - */ - newObject->ref = 1; - newObject->hDCCur = 0; - - newObject->fOwn = fOwn; - - /* dunno about original value */ - newObject->keepOrigFormat = TRUE; - - newObject->hbmMask = NULL; - newObject->hbmXor = NULL; - newObject->loadtime_magic = 0xdeadbeef; - newObject->loadtime_format = 0; - newObject->bIsDirty = FALSE; - - if (pictDesc) { - if(pictDesc->cbSizeofstruct != sizeof(PICTDESC)) { - FIXME("struct size = %d\n", pictDesc->cbSizeofstruct); - } - memcpy(&newObject->desc, pictDesc, sizeof(PICTDESC)); - - - switch(pictDesc->picType) { - case PICTYPE_BITMAP: - OLEPictureImpl_SetBitmap(newObject); - break; - - case PICTYPE_METAFILE: - TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta); - newObject->himetricWidth = pictDesc->u.wmf.xExt; - newObject->himetricHeight = pictDesc->u.wmf.yExt; - break; - - case PICTYPE_NONE: - /* not sure what to do here */ - newObject->himetricWidth = newObject->himetricHeight = 0; - break; - - case PICTYPE_ICON: - OLEPictureImpl_SetIcon(newObject); - break; - case PICTYPE_ENHMETAFILE: - default: - FIXME("Unsupported type %d\n", pictDesc->picType); - newObject->himetricWidth = newObject->himetricHeight = 0; - break; - } - } else { - newObject->desc.picType = PICTYPE_UNINITIALIZED; - } - - TRACE("returning %p\n", newObject); - return newObject; -} - -/************************************************************************ - * OLEPictureImpl_Destroy - * - * This method is called by the Release method when the reference - * count goes down to 0. It will free all resources used by - * this object. */ -static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj) -{ - TRACE("(%p)\n", Obj); - - if(Obj->fOwn) { /* We need to destroy the picture */ - switch(Obj->desc.picType) { - case PICTYPE_BITMAP: - DeleteObject(Obj->desc.u.bmp.hbitmap); - if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask); - if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor); - break; - case PICTYPE_METAFILE: - DeleteMetaFile(Obj->desc.u.wmf.hmeta); - break; - case PICTYPE_ICON: - DestroyIcon(Obj->desc.u.icon.hicon); - break; - case PICTYPE_ENHMETAFILE: - DeleteEnhMetaFile(Obj->desc.u.emf.hemf); - break; - default: - FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType); - break; - } - } - HeapFree(GetProcessHeap(), 0, Obj->data); - HeapFree(GetProcessHeap(), 0, Obj); -} - -static ULONG WINAPI OLEPictureImpl_AddRef(IPicture* iface); - -/************************************************************************ - * OLEPictureImpl_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static HRESULT WINAPI OLEPictureImpl_QueryInterface( - IPicture* iface, - REFIID riid, - void** ppvObject) -{ - OLEPictureImpl *This = (OLEPictureImpl *)iface; - TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject); - - /* - * Perform a sanity check on the parameters. - */ - if ( (This==0) || (ppvObject==0) ) - return E_INVALIDARG; - - /* - * Initialize the return parameter. - */ - *ppvObject = 0; - - /* - * Compare the riid with the interface IDs implemented by this object. - */ - if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) - { - *ppvObject = (IPicture*)This; - } - else if (memcmp(&IID_IPicture, riid, sizeof(IID_IPicture)) == 0) - { - *ppvObject = (IPicture*)This; - } - else if (memcmp(&IID_IDispatch, riid, sizeof(IID_IDispatch)) == 0) - { - *ppvObject = (IDispatch*)&(This->lpvtbl2); - } - else if (memcmp(&IID_IPictureDisp, riid, sizeof(IID_IPictureDisp)) == 0) - { - *ppvObject = (IDispatch*)&(This->lpvtbl2); - } - else if (memcmp(&IID_IPersistStream, riid, sizeof(IID_IPersistStream)) == 0) - { - *ppvObject = (IPersistStream*)&(This->lpvtbl3); - } - else if (memcmp(&IID_IConnectionPointContainer, riid, sizeof(IID_IConnectionPointContainer)) == 0) - { - *ppvObject = (IConnectionPointContainer*)&(This->lpvtbl4); - } - /* - * Check that we obtained an interface. - */ - if ((*ppvObject)==0) - { - FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid)); - return E_NOINTERFACE; - } - - /* - * Query Interface always increases the reference count by one when it is - * successful - */ - OLEPictureImpl_AddRef((IPicture*)This); - - return S_OK; -} -/*********************************************************************** - * OLEPicture_SendNotify (internal) - * - * Sends notification messages of changed properties to any interested - * connections. - */ -static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID) -{ - IEnumConnections *pEnum; - CONNECTDATA CD; - - if (IConnectionPoint_EnumConnections(this->pCP, &pEnum)) - return; - while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) { - IPropertyNotifySink *sink; - - IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink); - IPropertyNotifySink_OnChanged(sink, dispID); - IPropertyNotifySink_Release(sink); - IUnknown_Release(CD.pUnk); - } - IEnumConnections_Release(pEnum); - return; -} - -/************************************************************************ - * OLEPictureImpl_AddRef (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI OLEPictureImpl_AddRef( - IPicture* iface) -{ - OLEPictureImpl *This = (OLEPictureImpl *)iface; - ULONG refCount = InterlockedIncrement(&This->ref); - - TRACE("(%p)->(ref before=%ld)\n", This, refCount - 1); - - return refCount; -} - -/************************************************************************ - * OLEPictureImpl_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI OLEPictureImpl_Release( - IPicture* iface) -{ - OLEPictureImpl *This = (OLEPictureImpl *)iface; - ULONG refCount = InterlockedDecrement(&This->ref); - - TRACE("(%p)->(ref before=%ld)\n", This, refCount + 1); - - /* - * If the reference count goes down to 0, perform suicide. - */ - if (!refCount) OLEPictureImpl_Destroy(This); - - return refCount; -} - - -/************************************************************************ - * OLEPictureImpl_get_Handle - */ -static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface, - OLE_HANDLE *phandle) -{ - OLEPictureImpl *This = (OLEPictureImpl *)iface; - TRACE("(%p)->(%p)\n", This, phandle); - switch(This->desc.picType) { - case PICTYPE_BITMAP: - *phandle = (OLE_HANDLE)This->desc.u.bmp.hbitmap; - break; - case PICTYPE_METAFILE: - *phandle = (OLE_HANDLE)This->desc.u.wmf.hmeta; - break; - case PICTYPE_ICON: - *phandle = (OLE_HANDLE)This->desc.u.icon.hicon; - break; - case PICTYPE_ENHMETAFILE: - *phandle = (OLE_HANDLE)This->desc.u.emf.hemf; - break; - default: - FIXME("Unimplemented type %d\n", This->desc.picType); - return E_NOTIMPL; - } - TRACE("returning handle %08x\n", *phandle); - return S_OK; -} - -/************************************************************************ - * OLEPictureImpl_get_hPal - */ -static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface, - OLE_HANDLE *phandle) -{ - OLEPictureImpl *This = (OLEPictureImpl *)iface; - FIXME("(%p)->(%p): stub\n", This, phandle); - return E_NOTIMPL; -} - -/************************************************************************ - * OLEPictureImpl_get_Type - */ -static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface, - short *ptype) -{ - OLEPictureImpl *This = (OLEPictureImpl *)iface; - TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType); - *ptype = This->desc.picType; - return S_OK; -} - -/************************************************************************ - * OLEPictureImpl_get_Width - */ -static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface, - OLE_XSIZE_HIMETRIC *pwidth) -{ - OLEPictureImpl *This = (OLEPictureImpl *)iface; - TRACE("(%p)->(%p): width is %ld\n", This, pwidth, This->himetricWidth); - *pwidth = This->himetricWidth; - return S_OK; -} - -/************************************************************************ - * OLEPictureImpl_get_Height - */ -static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface, - OLE_YSIZE_HIMETRIC *pheight) -{ - OLEPictureImpl *This = (OLEPictureImpl *)iface; - TRACE("(%p)->(%p): height is %ld\n", This, pheight, This->himetricHeight); - *pheight = This->himetricHeight; - return S_OK; -} - -/************************************************************************ - * OLEPictureImpl_Render - */ -static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc, - LONG x, LONG y, LONG cx, LONG cy, - OLE_XPOS_HIMETRIC xSrc, - OLE_YPOS_HIMETRIC ySrc, - OLE_XSIZE_HIMETRIC cxSrc, - OLE_YSIZE_HIMETRIC cySrc, - LPCRECT prcWBounds) -{ - OLEPictureImpl *This = (OLEPictureImpl *)iface; - TRACE("(%p)->(%p, (%ld,%ld), (%ld,%ld) <- (%ld,%ld), (%ld,%ld), %p)\n", - This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds); - if(prcWBounds) - TRACE("prcWBounds (%ld,%ld) - (%ld,%ld)\n", prcWBounds->left, prcWBounds->top, - prcWBounds->right, prcWBounds->bottom); - - /* - * While the documentation suggests this to be here (or after rendering?) - * it does cause an endless recursion in my sample app. -MM 20010804 - OLEPicture_SendNotify(This,DISPID_PICT_RENDER); - */ - - switch(This->desc.picType) { - case PICTYPE_BITMAP: - { - HBITMAP hbmpOld; - HDC hdcBmp; - - /* Set a mapping mode that maps bitmap pixels into HIMETRIC units. - NB y-axis gets flipped */ - - hdcBmp = CreateCompatibleDC(0); - SetMapMode(hdcBmp, MM_ANISOTROPIC); - SetWindowOrgEx(hdcBmp, 0, 0, NULL); - SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL); - SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL); - SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL); - - if (This->hbmMask) { - HDC hdcMask = CreateCompatibleDC(0); - HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask); - - hbmpOld = SelectObject(hdcBmp, This->hbmXor); - - SetMapMode(hdcMask, MM_ANISOTROPIC); - SetWindowOrgEx(hdcMask, 0, 0, NULL); - SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL); - SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL); - SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL); - - SetBkColor(hdc, RGB(255, 255, 255)); - SetTextColor(hdc, RGB(0, 0, 0)); - StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND); - StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT); - - SelectObject(hdcMask, hOldbm); - DeleteDC(hdcMask); - } else { - hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap); - StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY); - } - - SelectObject(hdcBmp, hbmpOld); - DeleteDC(hdcBmp); - } - break; - case PICTYPE_ICON: - FIXME("Not quite correct implementation of rendering icons...\n"); - DrawIcon(hdc,x,y,This->desc.u.icon.hicon); - break; - - case PICTYPE_METAFILE: - case PICTYPE_ENHMETAFILE: - default: - FIXME("type %d not implemented\n", This->desc.picType); - return E_NOTIMPL; - } - return S_OK; -} - -/************************************************************************ - * OLEPictureImpl_set_hPal - */ -static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface, - OLE_HANDLE hpal) -{ - OLEPictureImpl *This = (OLEPictureImpl *)iface; - FIXME("(%p)->(%08x): stub\n", This, hpal); - OLEPicture_SendNotify(This,DISPID_PICT_HPAL); - return E_NOTIMPL; -} - -/************************************************************************ - * OLEPictureImpl_get_CurDC - */ -static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface, - HDC *phdc) -{ - OLEPictureImpl *This = (OLEPictureImpl *)iface; - TRACE("(%p), returning %p\n", This, This->hDCCur); - if (phdc) *phdc = This->hDCCur; - return S_OK; -} - -/************************************************************************ - * OLEPictureImpl_SelectPicture - */ -static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface, - HDC hdcIn, - HDC *phdcOut, - OLE_HANDLE *phbmpOut) -{ - OLEPictureImpl *This = (OLEPictureImpl *)iface; - TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut); - if (This->desc.picType == PICTYPE_BITMAP) { - SelectObject(hdcIn,This->desc.u.bmp.hbitmap); - - if (phdcOut) - *phdcOut = This->hDCCur; - This->hDCCur = hdcIn; - if (phbmpOut) - *phbmpOut = (OLE_HANDLE)This->desc.u.bmp.hbitmap; - return S_OK; - } else { - FIXME("Don't know how to select picture type %d\n",This->desc.picType); - return E_FAIL; - } -} - -/************************************************************************ - * OLEPictureImpl_get_KeepOriginalFormat - */ -static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface, - BOOL *pfKeep) -{ - OLEPictureImpl *This = (OLEPictureImpl *)iface; - TRACE("(%p)->(%p)\n", This, pfKeep); - if (!pfKeep) - return E_POINTER; - *pfKeep = This->keepOrigFormat; - return S_OK; -} - -/************************************************************************ - * OLEPictureImpl_put_KeepOriginalFormat - */ -static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface, - BOOL keep) -{ - OLEPictureImpl *This = (OLEPictureImpl *)iface; - TRACE("(%p)->(%d)\n", This, keep); - This->keepOrigFormat = keep; - /* FIXME: what DISPID notification here? */ - return S_OK; -} - -/************************************************************************ - * OLEPictureImpl_PictureChanged - */ -static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface) -{ - OLEPictureImpl *This = (OLEPictureImpl *)iface; - TRACE("(%p)->()\n", This); - OLEPicture_SendNotify(This,DISPID_PICT_HANDLE); - This->bIsDirty = TRUE; - return S_OK; -} - -/************************************************************************ - * OLEPictureImpl_SaveAsFile - */ -static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface, - IStream *pstream, - BOOL SaveMemCopy, - LONG *pcbSize) -{ - OLEPictureImpl *This = (OLEPictureImpl *)iface; - FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize); - return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize); -} - -/************************************************************************ - * OLEPictureImpl_get_Attributes - */ -static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface, - DWORD *pdwAttr) -{ - OLEPictureImpl *This = (OLEPictureImpl *)iface; - TRACE("(%p)->(%p).\n", This, pdwAttr); - *pdwAttr = 0; - switch (This->desc.picType) { - case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */ - case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break; - case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break; - default:FIXME("Unknown pictype %d\n",This->desc.picType);break; - } - return S_OK; -} - - -/************************************************************************ - * IConnectionPointContainer - */ - -static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface( - IConnectionPointContainer* iface, - REFIID riid, - VOID** ppvoid -) { - ICOM_THIS_From_IConnectionPointContainer(IPicture,iface); - - return IPicture_QueryInterface(This,riid,ppvoid); -} - -static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef( - IConnectionPointContainer* iface) -{ - ICOM_THIS_From_IConnectionPointContainer(IPicture, iface); - - return IPicture_AddRef(This); -} - -static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release( - IConnectionPointContainer* iface) -{ - ICOM_THIS_From_IConnectionPointContainer(IPicture, iface); - - return IPicture_Release(This); -} - -static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints( - IConnectionPointContainer* iface, - IEnumConnectionPoints** ppEnum -) { - ICOM_THIS_From_IConnectionPointContainer(IPicture, iface); - - FIXME("(%p,%p), stub!\n",This,ppEnum); - return E_NOTIMPL; -} - -static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint( - IConnectionPointContainer* iface, - REFIID riid, - IConnectionPoint **ppCP -) { - ICOM_THIS_From_IConnectionPointContainer(OLEPictureImpl, iface); - TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP); - if (!ppCP) - return E_POINTER; - *ppCP = NULL; - if (IsEqualGUID(riid,&IID_IPropertyNotifySink)) - return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP); - FIXME("tried to find connection point on %s?\n",debugstr_guid(riid)); - return 0x80040200; -} -/************************************************************************ - * IPersistStream - */ -/************************************************************************ - * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface( - IPersistStream* iface, - REFIID riid, - VOID** ppvoid) -{ - ICOM_THIS_From_IPersistStream(IPicture, iface); - - return IPicture_QueryInterface(This, riid, ppvoid); -} - -/************************************************************************ - * OLEPictureImpl_IPersistStream_AddRef (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef( - IPersistStream* iface) -{ - ICOM_THIS_From_IPersistStream(IPicture, iface); - - return IPicture_AddRef(This); -} - -/************************************************************************ - * OLEPictureImpl_IPersistStream_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI OLEPictureImpl_IPersistStream_Release( - IPersistStream* iface) -{ - ICOM_THIS_From_IPersistStream(IPicture, iface); - - return IPicture_Release(This); -} - -/************************************************************************ - * OLEPictureImpl_IPersistStream_GetClassID - */ -static HRESULT WINAPI OLEPictureImpl_GetClassID( - IPersistStream* iface,CLSID* pClassID) -{ - ICOM_THIS_From_IPersistStream(IPicture, iface); - FIXME("(%p),stub!\n",This); - return E_FAIL; -} - -/************************************************************************ - * OLEPictureImpl_IPersistStream_IsDirty - */ -static HRESULT WINAPI OLEPictureImpl_IsDirty( - IPersistStream* iface) -{ - ICOM_THIS_From_IPersistStream(IPicture, iface); - FIXME("(%p),stub!\n",This); - return E_NOTIMPL; -} - -#ifdef HAVE_JPEGLIB_H - -static void *libjpeg_handle; -#define MAKE_FUNCPTR(f) static typeof(f) * p##f -MAKE_FUNCPTR(jpeg_std_error); -MAKE_FUNCPTR(jpeg_CreateDecompress); -MAKE_FUNCPTR(jpeg_read_header); -MAKE_FUNCPTR(jpeg_start_decompress); -MAKE_FUNCPTR(jpeg_read_scanlines); -MAKE_FUNCPTR(jpeg_finish_decompress); -MAKE_FUNCPTR(jpeg_destroy_decompress); -#undef MAKE_FUNCPTR - -static void *load_libjpeg(void) -{ - if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) { - -#define LOAD_FUNCPTR(f) \ - if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \ - libjpeg_handle = NULL; \ - return NULL; \ - } - - LOAD_FUNCPTR(jpeg_std_error); - LOAD_FUNCPTR(jpeg_CreateDecompress); - LOAD_FUNCPTR(jpeg_read_header); - LOAD_FUNCPTR(jpeg_start_decompress); - LOAD_FUNCPTR(jpeg_read_scanlines); - LOAD_FUNCPTR(jpeg_finish_decompress); - LOAD_FUNCPTR(jpeg_destroy_decompress); -#undef LOAD_FUNCPTR - } - return libjpeg_handle; -} - -/* for the jpeg decompressor source manager. */ -static void _jpeg_init_source(j_decompress_ptr cinfo) { } - -static boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) { - ERR("(), should not get here.\n"); - return FALSE; -} - -static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) { - TRACE("Skipping %ld bytes...\n", num_bytes); - cinfo->src->next_input_byte += num_bytes; - cinfo->src->bytes_in_buffer -= num_bytes; -} - -static boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) { - ERR("(desired=%d), should not get here.\n",desired); - return FALSE; -} -static void _jpeg_term_source(j_decompress_ptr cinfo) { } -#endif /* HAVE_JPEGLIB_H */ - -#ifdef HAVE_GIF_LIB_H - -static void *libungif_handle; -#define MAKE_FUNCPTR(f) static typeof(f) * p##f -MAKE_FUNCPTR(DGifOpen); -MAKE_FUNCPTR(DGifSlurp); -MAKE_FUNCPTR(DGifCloseFile); -#undef MAKE_FUNCPTR - -struct gifdata { - unsigned char *data; - unsigned int curoff; - unsigned int len; -}; - -static void *load_libungif(void) -{ - if(((libungif_handle = wine_dlopen(SONAME_LIBUNGIF, RTLD_NOW, NULL, 0)) != NULL) || - ((libungif_handle = wine_dlopen(SONAME_LIBGIF , RTLD_NOW, NULL, 0)) != NULL) - ) { - -#define LOAD_FUNCPTR(f) \ - if((p##f = wine_dlsym(libungif_handle, #f, NULL, 0)) == NULL) { \ - libungif_handle = NULL; \ - return NULL; \ - } - - LOAD_FUNCPTR(DGifOpen); - LOAD_FUNCPTR(DGifSlurp); - LOAD_FUNCPTR(DGifCloseFile); -#undef LOAD_FUNCPTR - } - return libungif_handle; -} - -static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) { - struct gifdata *gd = (struct gifdata*)gif->UserData; - - if (len+gd->curoff > gd->len) { - FIXME("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff); - len = gd->len - gd->curoff; - } - memcpy(data, gd->data+gd->curoff, len); - gd->curoff += len; - return len; -} - -#endif /* HAVE_GIF_LIB_H */ - -/************************************************************************ - * OLEPictureImpl_IPersistStream_Load (IUnknown) - * - * Loads the binary data from the IStream. Starts at current position. - * There appears to be an 2 DWORD header: - * DWORD magic; - * DWORD len; - * - * Currently implemented: BITMAP, ICON, JPEG, GIF - */ -static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) { - HRESULT hr = E_FAIL; - ULONG xread; - BYTE *xbuf; - DWORD header[2]; - WORD magic; - STATSTG statstg; - ICOM_THIS_From_IPersistStream(OLEPictureImpl, iface); - - TRACE("(%p,%p)\n",This,pStm); - - /* Sometimes we have a header, sometimes we don't. Apply some guesses to find - * out whether we do. - * - * UPDATE: the IStream can be mapped to a plain file instead of a stream in a - * compound file. This may explain most, if not all, of the cases of "no header", - * and the header validation should take this into account. At least in Visual Basic 6, - * resource streams, valid headers are - * header[0] == "lt\0\0", - * header[1] == length_of_stream. - */ - hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME); - if (hr) - FIXME("Stat failed with hres %lx\n",hr); - hr=IStream_Read(pStm,header,8,&xread); - if (hr || xread!=8) { - FIXME("Failure while reading picture header (hr is %lx, nread is %ld).\n",hr,xread); - return hr; - } - if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */ - !memcmp(&(header[0]), "BM", 2) || /* BMP header */ - !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */ - header[1] > statstg.cbSize.QuadPart || (header[1]==0)) {/* Incorrect header, assume none. */ - xread = 8; - xbuf = This->data = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,statstg.cbSize.QuadPart); - memcpy(xbuf,&header,8); - This->datalen = statstg.cbSize.QuadPart; - while (xread < This->datalen) { - ULONG nread; - hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread); - xread+=nread; - if (hr || !nread) - break; - } - if (xread != This->datalen) - FIXME("Could only read %ld of %d bytes in no-header case?\n",xread,This->datalen); - } else { - xread = 0; - xbuf = This->data = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,header[1]); - This->datalen = header[1]; - while (xread < header[1]) { - ULONG nread; - hr = IStream_Read(pStm,xbuf+xread,header[1]-xread,&nread); - xread+=nread; - if (hr || !nread) - break; - } - if (xread != header[1]) - FIXME("Could only read %ld of %ld bytes?\n",xread,header[1]); - } - magic = xbuf[0] + (xbuf[1]<<8); - switch (magic) { - case 0x4947: { /* GIF */ -#ifdef HAVE_GIF_LIB_H - struct gifdata gd; - GifFileType *gif; - BITMAPINFO *bmi; - HDC hdcref; - LPBYTE bytes; - int i,j,ret; - GifImageDesc *gid; - SavedImage *si; - ColorMapObject *cm; - int transparent = -1; - ExtensionBlock *eb; - int padding; - - if(!libungif_handle) { - if(!load_libungif()) { - FIXME("Failed reading GIF because unable to find %s/%s\n", SONAME_LIBUNGIF, SONAME_LIBGIF); - return E_FAIL; - } - } - - gd.data = xbuf; - gd.curoff = 0; - gd.len = xread; - gif = pDGifOpen((void*)&gd, _gif_inputfunc); - ret = pDGifSlurp(gif); - if (ret == GIF_ERROR) { - FIXME("Failed reading GIF using libgif.\n"); - return E_FAIL; - } - TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight); - TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor); - TRACE("imgcnt %d\n", gif->ImageCount); - if (gif->ImageCount<1) { - FIXME("GIF stream does not have images inside?\n"); - return E_FAIL; - } - TRACE("curimage: %d x %d, on %dx%d, interlace %d\n", - gif->Image.Width, gif->Image.Height, - gif->Image.Left, gif->Image.Top, - gif->Image.Interlace - ); - /* */ - padding = (gif->SWidth+3) & ~3; - bmi = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(1<<gif->SColorResolution)*sizeof(RGBQUAD)); - bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight); - si = gif->SavedImages+0; - gid = &(si->ImageDesc); - cm = gid->ColorMap; - if (!cm) cm = gif->SColorMap; - - /* look for the transparent color extension */ - for (i = 0; i < si->ExtensionBlockCount; ++i) { - eb = si->ExtensionBlocks + i; - if (eb->Function == 0xF9 && eb->ByteCount == 4) { - if ((eb->Bytes[0] & 1) == 1) { - transparent = (unsigned char)eb->Bytes[3]; - } - } - } - - for (i=0;i<(1<<gif->SColorResolution);i++) { - bmi->bmiColors[i].rgbRed = cm->Colors[i].Red; - bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green; - bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue; - if (i == transparent) { - This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed, - bmi->bmiColors[i].rgbGreen, - bmi->bmiColors[i].rgbBlue); - } - } - - /* Map to in picture coordinates */ - for (i = 0, j = 0; i < gid->Height; i++) { - if (gif->Image.Interlace) { - memcpy( - bytes + (gid->Top + j) * padding + gid->Left, - si->RasterBits + i * gid->Width, - gid->Width); - - /* Lower bits of interlaced counter encode current interlace */ - if (j & 1) j += 2; /* Currently filling odd rows */ - else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */ - else j += 8; /* Currently filling every 8th row or 4th row in-between */ - - if (j >= gid->Height && i < gid->Height && (j & 1) == 0) { - /* End of current interlace, go to next interlace */ - if (j & 2) j = 1; /* Next iteration fills odd rows */ - else if (j & 4) j = 2; /* Next iteration fills even rows not mod 4 and not mod 8 */ - else j = 4; /* Next iteration fills rows in-between rows mod 6 */ - } - } else { - memcpy( - bytes + (gid->Top + i) * padding + gid->Left, - si->RasterBits + i * gid->Width, - gid->Width); - } - } - - bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi->bmiHeader.biWidth = gif->SWidth; - bmi->bmiHeader.biHeight = -gif->SHeight; - bmi->bmiHeader.biPlanes = 1; - bmi->bmiHeader.biBitCount = 8; - bmi->bmiHeader.biCompression = BI_RGB; - bmi->bmiHeader.biSizeImage = padding*gif->SHeight; - bmi->bmiHeader.biXPelsPerMeter = 0; - bmi->bmiHeader.biYPelsPerMeter = 0; - bmi->bmiHeader.biClrUsed = 1 << gif->SColorResolution; - bmi->bmiHeader.biClrImportant = 0; - - hdcref = GetDC(0); - This->desc.u.bmp.hbitmap=CreateDIBitmap( - hdcref, - &bmi->bmiHeader, - CBM_INIT, - bytes, - bmi, - DIB_RGB_COLORS - ); - - if (transparent > -1) { - /* Create the Mask */ - HDC hdc = CreateCompatibleDC(0); - HDC hdcMask = CreateCompatibleDC(0); - HBITMAP hOldbitmap; - HBITMAP hOldbitmapmask; - - unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2; - HBITMAP hTempMask; - - This->hbmXor = CreateDIBitmap( - hdcref, - &bmi->bmiHeader, - CBM_INIT, - bytes, - bmi, - DIB_RGB_COLORS - ); - - bmi->bmiColors[0].rgbRed = 0; - bmi->bmiColors[0].rgbGreen = 0; - bmi->bmiColors[0].rgbBlue = 0; - bmi->bmiColors[1].rgbRed = 255; - bmi->bmiColors[1].rgbGreen = 255; - bmi->bmiColors[1].rgbBlue = 255; - - bmi->bmiHeader.biBitCount = 1; - bmi->bmiHeader.biSizeImage = monopadding*gif->SHeight; - bmi->bmiHeader.biClrUsed = 2; - - for (i = 0; i < gif->SHeight; i++) { - unsigned char * colorPointer = bytes + padding * i; - unsigned char * monoPointer = bytes + monopadding * i; - for (j = 0; j < gif->SWidth; j++) { - unsigned char pixel = colorPointer[j]; - if ((j & 7) == 0) monoPointer[j >> 3] = 0; - if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7)); - } - } - hdcref = GetDC(0); - hTempMask = CreateDIBitmap( - hdcref, - &bmi->bmiHeader, - CBM_INIT, - bytes, - bmi, - DIB_RGB_COLORS - ); - DeleteDC(hdcref); - - bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight; - This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL); - hOldbitmap = SelectObject(hdc, hTempMask); - hOldbitmapmask = SelectObject(hdcMask, This->hbmMask); - - SetBkColor(hdc, RGB(255, 255, 255)); - BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY); - - /* We no longer need the original bitmap, so we apply the first - transformation with the mask to speed up the rendering */ - SelectObject(hdc, This->hbmXor); - SetBkColor(hdc, RGB(0,0,0)); - SetTextColor(hdc, RGB(255,255,255)); - BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, - hdcMask, 0, 0, SRCAND); - - SelectObject(hdc, hOldbitmap); - SelectObject(hdcMask, hOldbitmapmask); - DeleteDC(hdcMask); - DeleteDC(hdc); - DeleteObject(hTempMask); - } - - DeleteDC(hdcref); - This->desc.picType = PICTYPE_BITMAP; - OLEPictureImpl_SetBitmap(This); - pDGifCloseFile(gif); - HeapFree(GetProcessHeap(),0,bytes); - return S_OK; -#else - FIXME("Trying to load GIF, but no support for libgif/libungif compiled in.\n"); - return E_FAIL; -#endif - } - case 0xd8ff: { /* JPEG */ -#ifdef HAVE_JPEGLIB_H - struct jpeg_decompress_struct jd; - struct jpeg_error_mgr jerr; - int ret; - JDIMENSION x; - JSAMPROW samprow,oldsamprow; - BITMAPINFOHEADER bmi; - LPBYTE bits; - HDC hdcref; - struct jpeg_source_mgr xjsm; - LPBYTE oldbits; - unsigned int i; - - if(!libjpeg_handle) { - if(!load_libjpeg()) { - FIXME("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG); - return E_FAIL; - } - } - - /* This is basically so we can use in-memory data for jpeg decompression. - * We need to have all the functions. - */ - xjsm.next_input_byte = xbuf; - xjsm.bytes_in_buffer = xread; - xjsm.init_source = _jpeg_init_source; - xjsm.fill_input_buffer = _jpeg_fill_input_buffer; - xjsm.skip_input_data = _jpeg_skip_input_data; - xjsm.resync_to_restart = _jpeg_resync_to_restart; - xjsm.term_source = _jpeg_term_source; - - jd.err = pjpeg_std_error(&jerr); - /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h - * jpeg_create_decompress(&jd); */ - pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, (size_t) sizeof(struct jpeg_decompress_struct)); - jd.src = &xjsm; - ret=pjpeg_read_header(&jd,TRUE); - jd.out_color_space = JCS_RGB; - pjpeg_start_decompress(&jd); - if (ret != JPEG_HEADER_OK) { - ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret); - HeapFree(GetProcessHeap(),0,xbuf); - return E_FAIL; - } - - bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, - (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) ); - samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components); - - oldbits = bits; - oldsamprow = samprow; - while ( jd.output_scanline<jd.output_height ) { - x = pjpeg_read_scanlines(&jd,&samprow,1); - if (x != 1) { - FIXME("failed to read current scanline?\n"); - break; - } - /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */ - for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) { - *(bits++) = *(samprow+2); - *(bits++) = *(samprow+1); - *(bits++) = *(samprow); - } - bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3); - samprow = oldsamprow; - } - bits = oldbits; - - bmi.biSize = sizeof(bmi); - bmi.biWidth = jd.output_width; - bmi.biHeight = -jd.output_height; - bmi.biPlanes = 1; - bmi.biBitCount = jd.output_components<<3; - bmi.biCompression = BI_RGB; - bmi.biSizeImage = jd.output_height*jd.output_width*jd.output_components; - bmi.biXPelsPerMeter = 0; - bmi.biYPelsPerMeter = 0; - bmi.biClrUsed = 0; - bmi.biClrImportant = 0; - - HeapFree(GetProcessHeap(),0,samprow); - pjpeg_finish_decompress(&jd); - pjpeg_destroy_decompress(&jd); - hdcref = GetDC(0); - This->desc.u.bmp.hbitmap=CreateDIBitmap( - hdcref, - &bmi, - CBM_INIT, - bits, - (BITMAPINFO*)&bmi, - DIB_RGB_COLORS - ); - DeleteDC(hdcref); - This->desc.picType = PICTYPE_BITMAP; - OLEPictureImpl_SetBitmap(This); - hr = S_OK; - HeapFree(GetProcessHeap(),0,bits); -#else - ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n"); - hr = E_FAIL; -#endif - break; - } - case 0x4d42: { /* Bitmap */ - BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf; - BITMAPINFO *bi = (BITMAPINFO*)(bfh+1); - HDC hdcref; - - /* Does not matter whether this is a coreheader or not, we only use - * components which are in both - */ - hdcref = GetDC(0); - This->desc.u.bmp.hbitmap = CreateDIBitmap( - hdcref, - &(bi->bmiHeader), - CBM_INIT, - xbuf+bfh->bfOffBits, - bi, - DIB_RGB_COLORS - ); - DeleteDC(hdcref); - This->desc.picType = PICTYPE_BITMAP; - OLEPictureImpl_SetBitmap(This); - hr = S_OK; - break; - } - case 0x0000: { /* ICON , first word is dwReserved */ - HICON hicon; - CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf; - HDC hdcRef; - int i; - - /* - FIXME("icon.idReserved=%d\n",cifd->idReserved); - FIXME("icon.idType=%d\n",cifd->idType); - FIXME("icon.idCount=%d\n",cifd->idCount); - - for (i=0;i<cifd->idCount;i++) { - FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth); - FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight); - FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount); - FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved); - FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot); - FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot); - FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize); - FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset); - } - */ - i=0; - /* If we have more than one icon, try to find the best. - * this currently means '32 pixel wide'. - */ - if (cifd->idCount!=1) { - for (i=0;i<cifd->idCount;i++) { - if (cifd->idEntries[i].bWidth == 32) - break; - } - if (i==cifd->idCount) i=0; - } - - hicon = CreateIconFromResourceEx( - xbuf+cifd->idEntries[i].dwDIBOffset, - cifd->idEntries[i].dwDIBSize, - TRUE, /* is icon */ - 0x00030000, - cifd->idEntries[i].bWidth, - cifd->idEntries[i].bHeight, - 0 - ); - if (!hicon) { - FIXME("CreateIcon failed.\n"); - hr = E_FAIL; - } else { - This->desc.picType = PICTYPE_ICON; - This->desc.u.icon.hicon = hicon; - This->origWidth = cifd->idEntries[i].bWidth; - This->origHeight = cifd->idEntries[i].bHeight; - hdcRef = CreateCompatibleDC(0); - This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX); - This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY); - DeleteDC(hdcRef); - hr = S_OK; - } - break; - } - default: - { - unsigned int i; - FIXME("Unknown magic %04x, %ld read bytes:\n",magic,xread); - hr=E_FAIL; - for (i=0;i<xread+8;i++) { - if (i<8) MESSAGE("%02x ",((unsigned char*)&header)[i]); - else MESSAGE("%02x ",xbuf[i-8]); - if (i % 10 == 9) MESSAGE("\n"); - } - MESSAGE("\n"); - break; - } - } - This->bIsDirty = FALSE; - - /* FIXME: this notify is not really documented */ - if (hr==S_OK) - OLEPicture_SendNotify(This,DISPID_PICT_TYPE); - return hr; -} - -static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength); -static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength); -static HRESULT WINAPI OLEPictureImpl_Save( - IPersistStream* iface,IStream*pStm,BOOL fClearDirty) -{ - HRESULT hResult = E_NOTIMPL; - void * pIconData; - unsigned int iDataSize; - ULONG dummy; - int iSerializeResult = 0; - - ICOM_THIS_From_IPersistStream(OLEPictureImpl, iface); - - switch (This->desc.picType) { - case PICTYPE_ICON: - if (This->bIsDirty) { - if (serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) { - if (This->loadtime_magic != 0xdeadbeef) { - DWORD header[2]; - - header[0] = This->loadtime_magic; - header[1] = iDataSize; - IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy); - } - IStream_Write(pStm, pIconData, iDataSize, &dummy); - - HeapFree(GetProcessHeap(), 0, This->data); - This->data = pIconData; - This->datalen = iDataSize; - hResult = S_OK; - } else { - FIXME("(%p,%p,%d), unable to serializeIcon()!\n",This,pStm,fClearDirty); - hResult = E_FAIL; - } - } else { - if (This->loadtime_magic != 0xdeadbeef) { - DWORD header[2]; - - header[0] = This->loadtime_magic; - header[1] = This->datalen; - IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy); - } - IStream_Write(pStm, This->data, This->datalen, &dummy); - hResult = S_OK; - } - break; - case PICTYPE_BITMAP: - if (This->bIsDirty) { - switch (This->keepOrigFormat ? This->loadtime_format : 0x4d42) { - case 0x4d42: - iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize); - break; - case 0xd8ff: - FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty); - break; - case 0x4947: - FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty); - break; - default: - FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty); - break; - } - if (iSerializeResult) { - /* - if (This->loadtime_magic != 0xdeadbeef) { - */ - if (1) { - DWORD header[2]; - - header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c; - header[1] = iDataSize; - IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy); - } - IStream_Write(pStm, pIconData, iDataSize, &dummy); - - HeapFree(GetProcessHeap(), 0, This->data); - This->data = pIconData; - This->datalen = iDataSize; - hResult = S_OK; - } - } else { - /* - if (This->loadtime_magic != 0xdeadbeef) { - */ - if (1) { - DWORD header[2]; - - header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c; - header[1] = This->datalen; - IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy); - } - IStream_Write(pStm, This->data, This->datalen, &dummy); - hResult = S_OK; - } - break; - case PICTYPE_METAFILE: - FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty); - break; - case PICTYPE_ENHMETAFILE: - FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty); - break; - default: - FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty); - break; - } - if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE; - return hResult; -} - -static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength) -{ - int iSuccess = 0; - HDC hDC; - BITMAPINFO * pInfoBitmap; - int iNumPaletteEntries; - unsigned char * pPixelData; - BITMAPFILEHEADER * pFileHeader; - BITMAPINFO * pInfoHeader; - - pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); - - /* Find out bitmap size and padded length */ - hDC = GetDC(0); - pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader); - GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS); - - /* Fetch bitmap palette & pixel data */ - - pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage); - GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS); - - /* Calculate the total length required for the BMP data */ - if (pInfoBitmap->bmiHeader.biClrUsed != 0) { - iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed; - if (iNumPaletteEntries > 256) iNumPaletteEntries = 256; - } else { - if (pInfoBitmap->bmiHeader.biBitCount <= 8) - iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount; - else - iNumPaletteEntries = 0; - } - *pLength = - sizeof(BITMAPFILEHEADER) + - sizeof(BITMAPINFOHEADER) + - iNumPaletteEntries * sizeof(RGBQUAD) + - pInfoBitmap->bmiHeader.biSizeImage; - *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength); - - /* Fill the BITMAPFILEHEADER */ - pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer); - pFileHeader->bfType = 0x4d42; - pFileHeader->bfSize = *pLength; - pFileHeader->bfOffBits = - sizeof(BITMAPFILEHEADER) + - sizeof(BITMAPINFOHEADER) + - iNumPaletteEntries * sizeof(RGBQUAD); - - /* Fill the BITMAPINFOHEADER and the palette data */ - pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER)); - memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD)); - memcpy( - (unsigned char *)(*ppBuffer) + - sizeof(BITMAPFILEHEADER) + - sizeof(BITMAPINFOHEADER) + - iNumPaletteEntries * sizeof(RGBQUAD), - pPixelData, pInfoBitmap->bmiHeader.biSizeImage); - iSuccess = 1; - - HeapFree(GetProcessHeap(), 0, pPixelData); - HeapFree(GetProcessHeap(), 0, pInfoBitmap); - return iSuccess; -} - -static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength) -{ - ICONINFO infoIcon; - int iSuccess = 0; - - *ppBuffer = NULL; *pLength = 0; - if (GetIconInfo(hIcon, &infoIcon)) { - HDC hDC; - BITMAPINFO * pInfoBitmap; - unsigned char * pIconData = NULL; - unsigned int iDataSize = 0; - - pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); - - /* Find out icon size */ - hDC = GetDC(0); - pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader); - GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS); - if (1) { - /* Auxiliary pointers */ - CURSORICONFILEDIR * pIconDir; - CURSORICONFILEDIRENTRY * pIconEntry; - BITMAPINFOHEADER * pIconBitmapHeader; - unsigned int iOffsetPalette; - unsigned int iOffsetColorData; - unsigned int iOffsetMaskData; - - unsigned int iLengthScanLineColor; - unsigned int iLengthScanLineMask; - unsigned int iNumEntriesPalette; - - iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2; - iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2; -/* - FIXME("DEBUG: bitmap size is %d x %d\n", - pInfoBitmap->bmiHeader.biWidth, - pInfoBitmap->bmiHeader.biHeight); - FIXME("DEBUG: bitmap bpp is %d\n", - pInfoBitmap->bmiHeader.biBitCount); - FIXME("DEBUG: bitmap nplanes is %d\n", - pInfoBitmap->bmiHeader.biPlanes); - FIXME("DEBUG: bitmap biSizeImage is %lu\n", - pInfoBitmap->bmiHeader.biSizeImage); -*/ - /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */ - iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER); - pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize); - - /* Fill out the CURSORICONFILEDIR */ - pIconDir = (CURSORICONFILEDIR *)pIconData; - pIconDir->idType = 1; - pIconDir->idCount = 1; - - /* Fill out the CURSORICONFILEDIRENTRY */ - pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD)); - pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth; - pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight; - pIconEntry->bColorCount = - (pInfoBitmap->bmiHeader.biBitCount < 8) - ? 1 << pInfoBitmap->bmiHeader.biBitCount - : 0; - pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes; - pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount; - pIconEntry->dwDIBSize = 0; - pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY); - - /* Fill out the BITMAPINFOHEADER */ - pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY)); - memcpy(pIconBitmapHeader, &pInfoBitmap->bmiHeader, sizeof(BITMAPINFOHEADER)); - - /* Find out whether a palette exists for the bitmap */ - if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB) - || (pInfoBitmap->bmiHeader.biBitCount == 24) - || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) { - iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed; - if (iNumEntriesPalette > 256) iNumEntriesPalette = 256; - } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32) - && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) { - iNumEntriesPalette = 3; - } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) { - iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount; - } else { - iNumEntriesPalette = 0; - } - - /* Add bitmap size and header size to icon data size. */ - iOffsetPalette = iDataSize; - iDataSize += iNumEntriesPalette * sizeof(DWORD); - iOffsetColorData = iDataSize; - iDataSize += pIconBitmapHeader->biSizeImage; - iOffsetMaskData = iDataSize; - iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask; - pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask; - pIconBitmapHeader->biHeight *= 2; - pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize); - pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD)); - pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY)); - pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY)); - - /* Get the actual bitmap data from the icon bitmap */ - GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight, - pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS); - if (iNumEntriesPalette > 0) { - memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors, - iNumEntriesPalette * sizeof(RGBQUAD)); - } - - /* Reset all values so that GetDIBits call succeeds */ - memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData); - memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); - pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader); -/* - if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS) - && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, - pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) { - - printf("ERROR: unable to get bitmap mask (error %lu)\n", - GetLastError()); - - } -*/ - GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS); - GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS); - - /* Write out everything produced so far to the stream */ - *ppBuffer = pIconData; *pLength = iDataSize; - iSuccess = 1; - } else { -/* - printf("ERROR: unable to get bitmap information via GetDIBits() (error %lu)\n", - GetLastError()); -*/ - } - /* - Remarks (from MSDN entry on GetIconInfo): - - GetIconInfo creates bitmaps for the hbmMask and hbmColor - members of ICONINFO. The calling application must manage - these bitmaps and delete them when they are no longer - necessary. - */ - if (hDC) ReleaseDC(0, hDC); - DeleteObject(infoIcon.hbmMask); - if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor); - HeapFree(GetProcessHeap(), 0, pInfoBitmap); - } else { - printf("ERROR: Unable to get icon information (error %lu)\n", - GetLastError()); - } - return iSuccess; -} - -static HRESULT WINAPI OLEPictureImpl_GetSizeMax( - IPersistStream* iface,ULARGE_INTEGER*pcbSize) -{ - ICOM_THIS_From_IPersistStream(IPicture, iface); - FIXME("(%p,%p),stub!\n",This,pcbSize); - return E_NOTIMPL; -} - -/************************************************************************ - * IDispatch - */ -/************************************************************************ - * OLEPictureImpl_IDispatch_QueryInterface (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface( - IDispatch* iface, - REFIID riid, - VOID** ppvoid) -{ - ICOM_THIS_From_IDispatch(IPicture, iface); - - return IPicture_QueryInterface(This, riid, ppvoid); -} - -/************************************************************************ - * OLEPictureImpl_IDispatch_AddRef (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef( - IDispatch* iface) -{ - ICOM_THIS_From_IDispatch(IPicture, iface); - - return IPicture_AddRef(This); -} - -/************************************************************************ - * OLEPictureImpl_IDispatch_Release (IUnknown) - * - * See Windows documentation for more details on IUnknown methods. - */ -static ULONG WINAPI OLEPictureImpl_IDispatch_Release( - IDispatch* iface) -{ - ICOM_THIS_From_IDispatch(IPicture, iface); - - return IPicture_Release(This); -} - -/************************************************************************ - * OLEPictureImpl_GetTypeInfoCount (IDispatch) - * - * See Windows documentation for more details on IDispatch methods. - */ -static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount( - IDispatch* iface, - unsigned int* pctinfo) -{ - FIXME("():Stub\n"); - - return E_NOTIMPL; -} - -/************************************************************************ - * OLEPictureImpl_GetTypeInfo (IDispatch) - * - * See Windows documentation for more details on IDispatch methods. - */ -static HRESULT WINAPI OLEPictureImpl_GetTypeInfo( - IDispatch* iface, - UINT iTInfo, - LCID lcid, - ITypeInfo** ppTInfo) -{ - FIXME("():Stub\n"); - - return E_NOTIMPL; -} - -/************************************************************************ - * OLEPictureImpl_GetIDsOfNames (IDispatch) - * - * See Windows documentation for more details on IDispatch methods. - */ -static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames( - IDispatch* iface, - REFIID riid, - LPOLESTR* rgszNames, - UINT cNames, - LCID lcid, - DISPID* rgDispId) -{ - FIXME("():Stub\n"); - - return E_NOTIMPL; -} - -/************************************************************************ - * OLEPictureImpl_Invoke (IDispatch) - * - * See Windows documentation for more details on IDispatch methods. - */ -static HRESULT WINAPI OLEPictureImpl_Invoke( - IDispatch* iface, - DISPID dispIdMember, - REFIID riid, - LCID lcid, - WORD wFlags, - DISPPARAMS* pDispParams, - VARIANT* pVarResult, - EXCEPINFO* pExepInfo, - UINT* puArgErr) -{ - FIXME("(dispid: %ld):Stub\n",dispIdMember); - - VariantInit(pVarResult); - V_VT(pVarResult) = VT_BOOL; - V_BOOL(pVarResult) = FALSE; - return S_OK; -} - - -static IPictureVtbl OLEPictureImpl_VTable = -{ - OLEPictureImpl_QueryInterface, - OLEPictureImpl_AddRef, - OLEPictureImpl_Release, - OLEPictureImpl_get_Handle, - OLEPictureImpl_get_hPal, - OLEPictureImpl_get_Type, - OLEPictureImpl_get_Width, - OLEPictureImpl_get_Height, - OLEPictureImpl_Render, - OLEPictureImpl_set_hPal, - OLEPictureImpl_get_CurDC, - OLEPictureImpl_SelectPicture, - OLEPictureImpl_get_KeepOriginalFormat, - OLEPictureImpl_put_KeepOriginalFormat, - OLEPictureImpl_PictureChanged, - OLEPictureImpl_SaveAsFile, - OLEPictureImpl_get_Attributes -}; - -static IDispatchVtbl OLEPictureImpl_IDispatch_VTable = -{ - OLEPictureImpl_IDispatch_QueryInterface, - OLEPictureImpl_IDispatch_AddRef, - OLEPictureImpl_IDispatch_Release, - OLEPictureImpl_GetTypeInfoCount, - OLEPictureImpl_GetTypeInfo, - OLEPictureImpl_GetIDsOfNames, - OLEPictureImpl_Invoke -}; - -static IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable = -{ - OLEPictureImpl_IPersistStream_QueryInterface, - OLEPictureImpl_IPersistStream_AddRef, - OLEPictureImpl_IPersistStream_Release, - OLEPictureImpl_GetClassID, - OLEPictureImpl_IsDirty, - OLEPictureImpl_Load, - OLEPictureImpl_Save, - OLEPictureImpl_GetSizeMax -}; - -static IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable = -{ - OLEPictureImpl_IConnectionPointContainer_QueryInterface, - OLEPictureImpl_IConnectionPointContainer_AddRef, - OLEPictureImpl_IConnectionPointContainer_Release, - OLEPictureImpl_EnumConnectionPoints, - OLEPictureImpl_FindConnectionPoint -}; - -/*********************************************************************** - * OleCreatePictureIndirect (OLEAUT32.419) - */ -HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid, - BOOL fOwn, LPVOID *ppvObj ) -{ - OLEPictureImpl* newPict = NULL; - HRESULT hr = S_OK; - - TRACE("(%p,%p,%d,%p)\n", lpPictDesc, riid, fOwn, ppvObj); - - /* - * Sanity check - */ - if (ppvObj==0) - return E_POINTER; - - *ppvObj = NULL; - - /* - * Try to construct a new instance of the class. - */ - newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn); - - if (newPict == NULL) - return E_OUTOFMEMORY; - - /* - * Make sure it supports the interface required by the caller. - */ - hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj); - - /* - * Release the reference obtained in the constructor. If - * the QueryInterface was unsuccessful, it will free the class. - */ - IPicture_Release((IPicture*)newPict); - - return hr; -} - - -/*********************************************************************** - * OleLoadPicture (OLEAUT32.418) - */ -HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode, - REFIID riid, LPVOID *ppvObj ) -{ - LPPERSISTSTREAM ps; - IPicture *newpic; - HRESULT hr; - - TRACE("(%p,%ld,%d,%s,%p), partially implemented.\n", - lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj); - - hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic); - if (hr) - return hr; - hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps); - if (hr) { - FIXME("Could not get IPersistStream iface from Ole Picture?\n"); - IPicture_Release(newpic); - *ppvObj = NULL; - return hr; - } - IPersistStream_Load(ps,lpstream); - IPersistStream_Release(ps); - hr = IPicture_QueryInterface(newpic,riid,ppvObj); - if (hr) - FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid)); - IPicture_Release(newpic); - return hr; -} - -/*********************************************************************** - * OleLoadPictureEx (OLEAUT32.401) - */ -HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode, - REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj ) -{ - LPPERSISTSTREAM ps; - IPicture *newpic; - HRESULT hr; - - FIXME("(%p,%ld,%d,%s,x=%ld,y=%ld,f=%lx,%p), partially implemented.\n", - lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj); - - hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic); - if (hr) - return hr; - hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps); - if (hr) { - FIXME("Could not get IPersistStream iface from Ole Picture?\n"); - IPicture_Release(newpic); - *ppvObj = NULL; - return hr; - } - IPersistStream_Load(ps,lpstream); - IPersistStream_Release(ps); - hr = IPicture_QueryInterface(newpic,riid,ppvObj); - if (hr) - FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid)); - IPicture_Release(newpic); - return hr; -} - -/*********************************************************************** - * OleLoadPicturePath (OLEAUT32.424) - */ -HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller, - DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid, - LPVOID *ppvRet ) -{ - static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 }; - IPicture *ipicture; - HANDLE hFile; - DWORD dwFileSize; - HGLOBAL hGlobal = NULL; - DWORD dwBytesRead = 0; - IStream *stream; - BOOL bRead; - IPersistStream *pStream; - HRESULT hRes; - - TRACE("(%s,%p,%ld,%08lx,%s,%p): stub\n", - debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved, - debugstr_guid(riid), ppvRet); - - if (!ppvRet) return E_POINTER; - - if (strncmpW(szURLorPath, file, 7) == 0) { - szURLorPath += 7; - - hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, - 0, NULL); - if (hFile == INVALID_HANDLE_VALUE) - return E_UNEXPECTED; - - dwFileSize = GetFileSize(hFile, NULL); - if (dwFileSize != INVALID_FILE_SIZE ) - { - hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize); - if ( hGlobal) - { - bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL); - if (!bRead) - { - GlobalFree(hGlobal); - hGlobal = 0; - } - } - } - CloseHandle(hFile); - - if (!hGlobal) - return E_UNEXPECTED; - - hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream); - if (FAILED(hRes)) - { - GlobalFree(hGlobal); - return hRes; - } - } else { - IMoniker *pmnk; - IBindCtx *pbc; - - hRes = CreateBindCtx(0, &pbc); - if (SUCCEEDED(hRes)) - { - hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk); - if (SUCCEEDED(hRes)) - { - hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream); - IMoniker_Release(pmnk); - } - IBindCtx_Release(pbc); - } - if (FAILED(hRes)) - return hRes; - } - - hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER, - &IID_IPicture, (LPVOID*)&ipicture); - if (hRes != S_OK) { - IStream_Release(stream); - return hRes; - } - - hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream); - if (hRes) { - IStream_Release(stream); - IPicture_Release(ipicture); - return hRes; - } - - hRes = IPersistStream_Load(pStream, stream); - IPersistStream_Release(pStream); - IStream_Release(stream); - - if (hRes) { - IPicture_Release(ipicture); - return hRes; - } - - hRes = IPicture_QueryInterface(ipicture,riid,ppvRet); - if (hRes) - FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid)); - - IPicture_Release(ipicture); - return hRes; -} - -/******************************************************************************* - * StdPic ClassFactory - */ -typedef struct -{ - /* IUnknown fields */ - IClassFactoryVtbl *lpVtbl; - DWORD ref; -} IClassFactoryImpl; - -static HRESULT WINAPI -SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - - FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj); - return E_NOINTERFACE; -} - -static ULONG WINAPI -SPCF_AddRef(LPCLASSFACTORY iface) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - return InterlockedIncrement(&This->ref); -} - -static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - /* static class, won't be freed */ - return InterlockedDecrement(&This->ref); -} - -static HRESULT WINAPI SPCF_CreateInstance( - LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj -) { - /* Creates an uninitialized picture */ - return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj); - -} - -static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - FIXME("(%p)->(%d),stub!\n",This,dolock); - return S_OK; -} - -static IClassFactoryVtbl SPCF_Vtbl = { - SPCF_QueryInterface, - SPCF_AddRef, - SPCF_Release, - SPCF_CreateInstance, - SPCF_LockServer -}; -static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 }; - -void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; } +/* + * OLE Picture object + * + * Implementation of OLE IPicture and related interfaces + * + * Copyright 2000 Huw D M Davies for CodeWeavers. + * Copyright 2001 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * BUGS + * + * Support PICTYPE_BITMAP and PICTYPE_ICON, altough only bitmaps very well.. + * Lots of methods are just stubs. + * + * + * NOTES (or things that msdn doesn't tell you) + * + * The width and height properties are returned in HIMETRIC units (0.01mm) + * IPicture::Render also uses these to select a region of the src picture. + * A bitmap's size is converted into these units by using the screen resolution + * thus an 8x8 bitmap on a 96dpi screen has a size of 212x212 (8/96 * 2540). + * + */ + +#include "config.h" +#include "wine/port.h" + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +/* Must be before wine includes, the header has things conflicting with + * WINE headers. + */ +#ifdef HAVE_GIF_LIB_H +# include <gif_lib.h> +# ifndef SONAME_LIBUNGIF +# define SONAME_LIBUNGIF "libungif.so" +# endif +# ifndef SONAME_LIBGIF +# define SONAME_LIBGIF "libgif.so" +# endif +#endif + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "winerror.h" +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "ole2.h" +#include "olectl.h" +#include "oleauto.h" +#include "connpt.h" +#include "urlmon.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +#include "wine/wingdi16.h" +#include "cursoricon.h" + +#ifdef HAVE_JPEGLIB_H +/* This is a hack, so jpeglib.h does not redefine INT32 and the like*/ +#define XMD_H +#define UINT8 JPEG_UINT8 +#define UINT16 JPEG_UINT16 +#undef FAR +# include <jpeglib.h> +#undef UINT16 +#ifndef SONAME_LIBJPEG +#define SONAME_LIBJPEG "libjpeg.so" +#endif +#endif + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/************************************************************************* + * Declaration of implementation class + */ + +typedef struct OLEPictureImpl { + + /* + * IPicture handles IUnknown + */ + + IPictureVtbl *lpvtbl1; + IDispatchVtbl *lpvtbl2; + IPersistStreamVtbl *lpvtbl3; + IConnectionPointContainerVtbl *lpvtbl4; + + /* Object reference count */ + DWORD ref; + + /* We own the object and must destroy it ourselves */ + BOOL fOwn; + + /* Picture description */ + PICTDESC desc; + + /* These are the pixel size of a bitmap */ + DWORD origWidth; + DWORD origHeight; + + /* And these are the size of the picture converted into HIMETRIC units */ + OLE_XSIZE_HIMETRIC himetricWidth; + OLE_YSIZE_HIMETRIC himetricHeight; + + IConnectionPoint *pCP; + + BOOL keepOrigFormat; + HDC hDCCur; + + /* Bitmap transparency mask */ + HBITMAP hbmMask; + HBITMAP hbmXor; + COLORREF rgbTrans; + + /* data */ + void* data; + int datalen; + BOOL bIsDirty; /* Set to TRUE if picture has changed */ + unsigned int loadtime_magic; /* If a length header was found, saves value */ + unsigned int loadtime_format; /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */ +} OLEPictureImpl; + +/* + * Macros to retrieve pointer to IUnknown (IPicture) from the other VTables. + */ +#define ICOM_THIS_From_IDispatch(impl, name) \ + impl *This = (impl*)(((char*)name)-sizeof(void*)); +#define ICOM_THIS_From_IPersistStream(impl, name) \ + impl *This = (impl*)(((char*)name)-2*sizeof(void*)); +#define ICOM_THIS_From_IConnectionPointContainer(impl, name) \ + impl *This = (impl*)(((char*)name)-3*sizeof(void*)); + +/* + * Predeclare VTables. They get initialized at the end. + */ +static IPictureVtbl OLEPictureImpl_VTable; +static IDispatchVtbl OLEPictureImpl_IDispatch_VTable; +static IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable; +static IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable; + +/*********************************************************************** + * Implementation of the OLEPictureImpl class. + */ + +static void OLEPictureImpl_SetBitmap(OLEPictureImpl*This) { + BITMAP bm; + HDC hdcRef; + + TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap); + if(GetObjectA(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) { + ERR("GetObject fails\n"); + return; + } + This->origWidth = bm.bmWidth; + This->origHeight = bm.bmHeight; + /* The width and height are stored in HIMETRIC units (0.01 mm), + so we take our pixel width divide by pixels per inch and + multiply by 25.4 * 100 */ + /* Should we use GetBitmapDimension if available? */ + hdcRef = CreateCompatibleDC(0); + This->himetricWidth =(bm.bmWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX); + This->himetricHeight=(bm.bmHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY); + DeleteDC(hdcRef); +} + +static void OLEPictureImpl_SetIcon(OLEPictureImpl * This) +{ + ICONINFO infoIcon; + + TRACE("icon handle %p\n", This->desc.u.icon.hicon); + if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) { + HDC hdcRef; + BITMAP bm; + + TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor); + if(GetObjectA(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) { + ERR("GetObject fails on icon bitmap\n"); + return; + } + + This->origWidth = bm.bmWidth; + This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2; + /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */ + hdcRef = GetDC(0); + This->himetricWidth = (This->origWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX); + This->himetricHeight= (This->origHeight *2540)/GetDeviceCaps(hdcRef, LOGPIXELSY); + ReleaseDC(0, hdcRef); + + DeleteObject(infoIcon.hbmMask); + if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor); + } else { + ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon); + } +} + +/************************************************************************ + * OLEPictureImpl_Construct + * + * This method will construct a new instance of the OLEPictureImpl + * class. + * + * The caller of this method must release the object when it's + * done with it. + */ +static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn) +{ + OLEPictureImpl* newObject = 0; + + if (pictDesc) + TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType); + + /* + * Allocate space for the object. + */ + newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl)); + + if (newObject==0) + return newObject; + + /* + * Initialize the virtual function table. + */ + newObject->lpvtbl1 = &OLEPictureImpl_VTable; + newObject->lpvtbl2 = &OLEPictureImpl_IDispatch_VTable; + newObject->lpvtbl3 = &OLEPictureImpl_IPersistStream_VTable; + newObject->lpvtbl4 = &OLEPictureImpl_IConnectionPointContainer_VTable; + + CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP); + + /* + * Start with one reference count. The caller of this function + * must release the interface pointer when it is done. + */ + newObject->ref = 1; + newObject->hDCCur = 0; + + newObject->fOwn = fOwn; + + /* dunno about original value */ + newObject->keepOrigFormat = TRUE; + + newObject->hbmMask = NULL; + newObject->hbmXor = NULL; + newObject->loadtime_magic = 0xdeadbeef; + newObject->loadtime_format = 0; + newObject->bIsDirty = FALSE; + + if (pictDesc) { + if(pictDesc->cbSizeofstruct != sizeof(PICTDESC)) { + FIXME("struct size = %d\n", pictDesc->cbSizeofstruct); + } + memcpy(&newObject->desc, pictDesc, sizeof(PICTDESC)); + + + switch(pictDesc->picType) { + case PICTYPE_BITMAP: + OLEPictureImpl_SetBitmap(newObject); + break; + + case PICTYPE_METAFILE: + TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta); + newObject->himetricWidth = pictDesc->u.wmf.xExt; + newObject->himetricHeight = pictDesc->u.wmf.yExt; + break; + + case PICTYPE_NONE: + /* not sure what to do here */ + newObject->himetricWidth = newObject->himetricHeight = 0; + break; + + case PICTYPE_ICON: + OLEPictureImpl_SetIcon(newObject); + break; + case PICTYPE_ENHMETAFILE: + default: + FIXME("Unsupported type %d\n", pictDesc->picType); + newObject->himetricWidth = newObject->himetricHeight = 0; + break; + } + } else { + newObject->desc.picType = PICTYPE_UNINITIALIZED; + } + + TRACE("returning %p\n", newObject); + return newObject; +} + +/************************************************************************ + * OLEPictureImpl_Destroy + * + * This method is called by the Release method when the reference + * count goes down to 0. It will free all resources used by + * this object. */ +static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj) +{ + TRACE("(%p)\n", Obj); + + if(Obj->fOwn) { /* We need to destroy the picture */ + switch(Obj->desc.picType) { + case PICTYPE_BITMAP: + DeleteObject(Obj->desc.u.bmp.hbitmap); + if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask); + if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor); + break; + case PICTYPE_METAFILE: + DeleteMetaFile(Obj->desc.u.wmf.hmeta); + break; + case PICTYPE_ICON: + DestroyIcon(Obj->desc.u.icon.hicon); + break; + case PICTYPE_ENHMETAFILE: + DeleteEnhMetaFile(Obj->desc.u.emf.hemf); + break; + default: + FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType); + break; + } + } + HeapFree(GetProcessHeap(), 0, Obj->data); + HeapFree(GetProcessHeap(), 0, Obj); +} + +static ULONG WINAPI OLEPictureImpl_AddRef(IPicture* iface); + +/************************************************************************ + * OLEPictureImpl_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static HRESULT WINAPI OLEPictureImpl_QueryInterface( + IPicture* iface, + REFIID riid, + void** ppvObject) +{ + OLEPictureImpl *This = (OLEPictureImpl *)iface; + TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject); + + /* + * Perform a sanity check on the parameters. + */ + if ( (This==0) || (ppvObject==0) ) + return E_INVALIDARG; + + /* + * Initialize the return parameter. + */ + *ppvObject = 0; + + /* + * Compare the riid with the interface IDs implemented by this object. + */ + if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0) + { + *ppvObject = (IPicture*)This; + } + else if (memcmp(&IID_IPicture, riid, sizeof(IID_IPicture)) == 0) + { + *ppvObject = (IPicture*)This; + } + else if (memcmp(&IID_IDispatch, riid, sizeof(IID_IDispatch)) == 0) + { + *ppvObject = (IDispatch*)&(This->lpvtbl2); + } + else if (memcmp(&IID_IPictureDisp, riid, sizeof(IID_IPictureDisp)) == 0) + { + *ppvObject = (IDispatch*)&(This->lpvtbl2); + } + else if (memcmp(&IID_IPersistStream, riid, sizeof(IID_IPersistStream)) == 0) + { + *ppvObject = (IPersistStream*)&(This->lpvtbl3); + } + else if (memcmp(&IID_IConnectionPointContainer, riid, sizeof(IID_IConnectionPointContainer)) == 0) + { + *ppvObject = (IConnectionPointContainer*)&(This->lpvtbl4); + } + /* + * Check that we obtained an interface. + */ + if ((*ppvObject)==0) + { + FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid)); + return E_NOINTERFACE; + } + + /* + * Query Interface always increases the reference count by one when it is + * successful + */ + OLEPictureImpl_AddRef((IPicture*)This); + + return S_OK; +} +/*********************************************************************** + * OLEPicture_SendNotify (internal) + * + * Sends notification messages of changed properties to any interested + * connections. + */ +static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID) +{ + IEnumConnections *pEnum; + CONNECTDATA CD; + + if (IConnectionPoint_EnumConnections(this->pCP, &pEnum)) + return; + while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) { + IPropertyNotifySink *sink; + + IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink); + IPropertyNotifySink_OnChanged(sink, dispID); + IPropertyNotifySink_Release(sink); + IUnknown_Release(CD.pUnk); + } + IEnumConnections_Release(pEnum); + return; +} + +/************************************************************************ + * OLEPictureImpl_AddRef (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI OLEPictureImpl_AddRef( + IPicture* iface) +{ + OLEPictureImpl *This = (OLEPictureImpl *)iface; + ULONG refCount = InterlockedIncrement(&This->ref); + + TRACE("(%p)->(ref before=%ld)\n", This, refCount - 1); + + return refCount; +} + +/************************************************************************ + * OLEPictureImpl_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI OLEPictureImpl_Release( + IPicture* iface) +{ + OLEPictureImpl *This = (OLEPictureImpl *)iface; + ULONG refCount = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(ref before=%ld)\n", This, refCount + 1); + + /* + * If the reference count goes down to 0, perform suicide. + */ + if (!refCount) OLEPictureImpl_Destroy(This); + + return refCount; +} + + +/************************************************************************ + * OLEPictureImpl_get_Handle + */ +static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface, + OLE_HANDLE *phandle) +{ + OLEPictureImpl *This = (OLEPictureImpl *)iface; + TRACE("(%p)->(%p)\n", This, phandle); + switch(This->desc.picType) { + case PICTYPE_BITMAP: + *phandle = (OLE_HANDLE)This->desc.u.bmp.hbitmap; + break; + case PICTYPE_METAFILE: + *phandle = (OLE_HANDLE)This->desc.u.wmf.hmeta; + break; + case PICTYPE_ICON: + *phandle = (OLE_HANDLE)This->desc.u.icon.hicon; + break; + case PICTYPE_ENHMETAFILE: + *phandle = (OLE_HANDLE)This->desc.u.emf.hemf; + break; + default: + FIXME("Unimplemented type %d\n", This->desc.picType); + return E_NOTIMPL; + } + TRACE("returning handle %08x\n", *phandle); + return S_OK; +} + +/************************************************************************ + * OLEPictureImpl_get_hPal + */ +static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface, + OLE_HANDLE *phandle) +{ + OLEPictureImpl *This = (OLEPictureImpl *)iface; + FIXME("(%p)->(%p): stub\n", This, phandle); + return E_NOTIMPL; +} + +/************************************************************************ + * OLEPictureImpl_get_Type + */ +static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface, + short *ptype) +{ + OLEPictureImpl *This = (OLEPictureImpl *)iface; + TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType); + *ptype = This->desc.picType; + return S_OK; +} + +/************************************************************************ + * OLEPictureImpl_get_Width + */ +static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface, + OLE_XSIZE_HIMETRIC *pwidth) +{ + OLEPictureImpl *This = (OLEPictureImpl *)iface; + TRACE("(%p)->(%p): width is %ld\n", This, pwidth, This->himetricWidth); + *pwidth = This->himetricWidth; + return S_OK; +} + +/************************************************************************ + * OLEPictureImpl_get_Height + */ +static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface, + OLE_YSIZE_HIMETRIC *pheight) +{ + OLEPictureImpl *This = (OLEPictureImpl *)iface; + TRACE("(%p)->(%p): height is %ld\n", This, pheight, This->himetricHeight); + *pheight = This->himetricHeight; + return S_OK; +} + +/************************************************************************ + * OLEPictureImpl_Render + */ +static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc, + LONG x, LONG y, LONG cx, LONG cy, + OLE_XPOS_HIMETRIC xSrc, + OLE_YPOS_HIMETRIC ySrc, + OLE_XSIZE_HIMETRIC cxSrc, + OLE_YSIZE_HIMETRIC cySrc, + LPCRECT prcWBounds) +{ + OLEPictureImpl *This = (OLEPictureImpl *)iface; + TRACE("(%p)->(%p, (%ld,%ld), (%ld,%ld) <- (%ld,%ld), (%ld,%ld), %p)\n", + This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds); + if(prcWBounds) + TRACE("prcWBounds (%ld,%ld) - (%ld,%ld)\n", prcWBounds->left, prcWBounds->top, + prcWBounds->right, prcWBounds->bottom); + + /* + * While the documentation suggests this to be here (or after rendering?) + * it does cause an endless recursion in my sample app. -MM 20010804 + OLEPicture_SendNotify(This,DISPID_PICT_RENDER); + */ + + switch(This->desc.picType) { + case PICTYPE_BITMAP: + { + HBITMAP hbmpOld; + HDC hdcBmp; + + /* Set a mapping mode that maps bitmap pixels into HIMETRIC units. + NB y-axis gets flipped */ + + hdcBmp = CreateCompatibleDC(0); + SetMapMode(hdcBmp, MM_ANISOTROPIC); + SetWindowOrgEx(hdcBmp, 0, 0, NULL); + SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL); + SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL); + SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL); + + if (This->hbmMask) { + HDC hdcMask = CreateCompatibleDC(0); + HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask); + + hbmpOld = SelectObject(hdcBmp, This->hbmXor); + + SetMapMode(hdcMask, MM_ANISOTROPIC); + SetWindowOrgEx(hdcMask, 0, 0, NULL); + SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL); + SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL); + SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL); + + SetBkColor(hdc, RGB(255, 255, 255)); + SetTextColor(hdc, RGB(0, 0, 0)); + StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND); + StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT); + + SelectObject(hdcMask, hOldbm); + DeleteDC(hdcMask); + } else { + hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap); + StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY); + } + + SelectObject(hdcBmp, hbmpOld); + DeleteDC(hdcBmp); + } + break; + case PICTYPE_ICON: + FIXME("Not quite correct implementation of rendering icons...\n"); + DrawIcon(hdc,x,y,This->desc.u.icon.hicon); + break; + + case PICTYPE_METAFILE: + case PICTYPE_ENHMETAFILE: + default: + FIXME("type %d not implemented\n", This->desc.picType); + return E_NOTIMPL; + } + return S_OK; +} + +/************************************************************************ + * OLEPictureImpl_set_hPal + */ +static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface, + OLE_HANDLE hpal) +{ + OLEPictureImpl *This = (OLEPictureImpl *)iface; + FIXME("(%p)->(%08x): stub\n", This, hpal); + OLEPicture_SendNotify(This,DISPID_PICT_HPAL); + return E_NOTIMPL; +} + +/************************************************************************ + * OLEPictureImpl_get_CurDC + */ +static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface, + HDC *phdc) +{ + OLEPictureImpl *This = (OLEPictureImpl *)iface; + TRACE("(%p), returning %p\n", This, This->hDCCur); + if (phdc) *phdc = This->hDCCur; + return S_OK; +} + +/************************************************************************ + * OLEPictureImpl_SelectPicture + */ +static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface, + HDC hdcIn, + HDC *phdcOut, + OLE_HANDLE *phbmpOut) +{ + OLEPictureImpl *This = (OLEPictureImpl *)iface; + TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut); + if (This->desc.picType == PICTYPE_BITMAP) { + SelectObject(hdcIn,This->desc.u.bmp.hbitmap); + + if (phdcOut) + *phdcOut = This->hDCCur; + This->hDCCur = hdcIn; + if (phbmpOut) + *phbmpOut = (OLE_HANDLE)This->desc.u.bmp.hbitmap; + return S_OK; + } else { + FIXME("Don't know how to select picture type %d\n",This->desc.picType); + return E_FAIL; + } +} + +/************************************************************************ + * OLEPictureImpl_get_KeepOriginalFormat + */ +static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface, + BOOL *pfKeep) +{ + OLEPictureImpl *This = (OLEPictureImpl *)iface; + TRACE("(%p)->(%p)\n", This, pfKeep); + if (!pfKeep) + return E_POINTER; + *pfKeep = This->keepOrigFormat; + return S_OK; +} + +/************************************************************************ + * OLEPictureImpl_put_KeepOriginalFormat + */ +static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface, + BOOL keep) +{ + OLEPictureImpl *This = (OLEPictureImpl *)iface; + TRACE("(%p)->(%d)\n", This, keep); + This->keepOrigFormat = keep; + /* FIXME: what DISPID notification here? */ + return S_OK; +} + +/************************************************************************ + * OLEPictureImpl_PictureChanged + */ +static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface) +{ + OLEPictureImpl *This = (OLEPictureImpl *)iface; + TRACE("(%p)->()\n", This); + OLEPicture_SendNotify(This,DISPID_PICT_HANDLE); + This->bIsDirty = TRUE; + return S_OK; +} + +/************************************************************************ + * OLEPictureImpl_SaveAsFile + */ +static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface, + IStream *pstream, + BOOL SaveMemCopy, + LONG *pcbSize) +{ + OLEPictureImpl *This = (OLEPictureImpl *)iface; + FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize); + return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize); +} + +/************************************************************************ + * OLEPictureImpl_get_Attributes + */ +static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface, + DWORD *pdwAttr) +{ + OLEPictureImpl *This = (OLEPictureImpl *)iface; + TRACE("(%p)->(%p).\n", This, pdwAttr); + *pdwAttr = 0; + switch (This->desc.picType) { + case PICTYPE_BITMAP: if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break; /* not 'truly' scalable, see MSDN. */ + case PICTYPE_ICON: *pdwAttr = PICTURE_TRANSPARENT;break; + case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break; + default:FIXME("Unknown pictype %d\n",This->desc.picType);break; + } + return S_OK; +} + + +/************************************************************************ + * IConnectionPointContainer + */ + +static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface( + IConnectionPointContainer* iface, + REFIID riid, + VOID** ppvoid +) { + ICOM_THIS_From_IConnectionPointContainer(IPicture,iface); + + return IPicture_QueryInterface(This,riid,ppvoid); +} + +static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef( + IConnectionPointContainer* iface) +{ + ICOM_THIS_From_IConnectionPointContainer(IPicture, iface); + + return IPicture_AddRef(This); +} + +static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release( + IConnectionPointContainer* iface) +{ + ICOM_THIS_From_IConnectionPointContainer(IPicture, iface); + + return IPicture_Release(This); +} + +static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints( + IConnectionPointContainer* iface, + IEnumConnectionPoints** ppEnum +) { + ICOM_THIS_From_IConnectionPointContainer(IPicture, iface); + + FIXME("(%p,%p), stub!\n",This,ppEnum); + return E_NOTIMPL; +} + +static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint( + IConnectionPointContainer* iface, + REFIID riid, + IConnectionPoint **ppCP +) { + ICOM_THIS_From_IConnectionPointContainer(OLEPictureImpl, iface); + TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP); + if (!ppCP) + return E_POINTER; + *ppCP = NULL; + if (IsEqualGUID(riid,&IID_IPropertyNotifySink)) + return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP); + FIXME("tried to find connection point on %s?\n",debugstr_guid(riid)); + return 0x80040200; +} +/************************************************************************ + * IPersistStream + */ +/************************************************************************ + * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface( + IPersistStream* iface, + REFIID riid, + VOID** ppvoid) +{ + ICOM_THIS_From_IPersistStream(IPicture, iface); + + return IPicture_QueryInterface(This, riid, ppvoid); +} + +/************************************************************************ + * OLEPictureImpl_IPersistStream_AddRef (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef( + IPersistStream* iface) +{ + ICOM_THIS_From_IPersistStream(IPicture, iface); + + return IPicture_AddRef(This); +} + +/************************************************************************ + * OLEPictureImpl_IPersistStream_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI OLEPictureImpl_IPersistStream_Release( + IPersistStream* iface) +{ + ICOM_THIS_From_IPersistStream(IPicture, iface); + + return IPicture_Release(This); +} + +/************************************************************************ + * OLEPictureImpl_IPersistStream_GetClassID + */ +static HRESULT WINAPI OLEPictureImpl_GetClassID( + IPersistStream* iface,CLSID* pClassID) +{ + ICOM_THIS_From_IPersistStream(IPicture, iface); + FIXME("(%p),stub!\n",This); + return E_FAIL; +} + +/************************************************************************ + * OLEPictureImpl_IPersistStream_IsDirty + */ +static HRESULT WINAPI OLEPictureImpl_IsDirty( + IPersistStream* iface) +{ + ICOM_THIS_From_IPersistStream(IPicture, iface); + FIXME("(%p),stub!\n",This); + return E_NOTIMPL; +} + +#ifdef HAVE_JPEGLIB_H + +static void *libjpeg_handle; +#define MAKE_FUNCPTR(f) static typeof(f) * p##f +MAKE_FUNCPTR(jpeg_std_error); +MAKE_FUNCPTR(jpeg_CreateDecompress); +MAKE_FUNCPTR(jpeg_read_header); +MAKE_FUNCPTR(jpeg_start_decompress); +MAKE_FUNCPTR(jpeg_read_scanlines); +MAKE_FUNCPTR(jpeg_finish_decompress); +MAKE_FUNCPTR(jpeg_destroy_decompress); +#undef MAKE_FUNCPTR + +static void *load_libjpeg(void) +{ + if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) { + +#define LOAD_FUNCPTR(f) \ + if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \ + libjpeg_handle = NULL; \ + return NULL; \ + } + + LOAD_FUNCPTR(jpeg_std_error); + LOAD_FUNCPTR(jpeg_CreateDecompress); + LOAD_FUNCPTR(jpeg_read_header); + LOAD_FUNCPTR(jpeg_start_decompress); + LOAD_FUNCPTR(jpeg_read_scanlines); + LOAD_FUNCPTR(jpeg_finish_decompress); + LOAD_FUNCPTR(jpeg_destroy_decompress); +#undef LOAD_FUNCPTR + } + return libjpeg_handle; +} + +/* for the jpeg decompressor source manager. */ +static void _jpeg_init_source(j_decompress_ptr cinfo) { } + +static boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) { + ERR("(), should not get here.\n"); + return FALSE; +} + +static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) { + TRACE("Skipping %ld bytes...\n", num_bytes); + cinfo->src->next_input_byte += num_bytes; + cinfo->src->bytes_in_buffer -= num_bytes; +} + +static boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) { + ERR("(desired=%d), should not get here.\n",desired); + return FALSE; +} +static void _jpeg_term_source(j_decompress_ptr cinfo) { } +#endif /* HAVE_JPEGLIB_H */ + +#ifdef HAVE_GIF_LIB_H + +static void *libungif_handle; +#define MAKE_FUNCPTR(f) static typeof(f) * p##f +MAKE_FUNCPTR(DGifOpen); +MAKE_FUNCPTR(DGifSlurp); +MAKE_FUNCPTR(DGifCloseFile); +#undef MAKE_FUNCPTR + +struct gifdata { + unsigned char *data; + unsigned int curoff; + unsigned int len; +}; + +static void *load_libungif(void) +{ + if(((libungif_handle = wine_dlopen(SONAME_LIBUNGIF, RTLD_NOW, NULL, 0)) != NULL) || + ((libungif_handle = wine_dlopen(SONAME_LIBGIF , RTLD_NOW, NULL, 0)) != NULL) + ) { + +#define LOAD_FUNCPTR(f) \ + if((p##f = wine_dlsym(libungif_handle, #f, NULL, 0)) == NULL) { \ + libungif_handle = NULL; \ + return NULL; \ + } + + LOAD_FUNCPTR(DGifOpen); + LOAD_FUNCPTR(DGifSlurp); + LOAD_FUNCPTR(DGifCloseFile); +#undef LOAD_FUNCPTR + } + return libungif_handle; +} + +static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) { + struct gifdata *gd = (struct gifdata*)gif->UserData; + + if (len+gd->curoff > gd->len) { + FIXME("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff); + len = gd->len - gd->curoff; + } + memcpy(data, gd->data+gd->curoff, len); + gd->curoff += len; + return len; +} + +#endif /* HAVE_GIF_LIB_H */ + +/************************************************************************ + * OLEPictureImpl_IPersistStream_Load (IUnknown) + * + * Loads the binary data from the IStream. Starts at current position. + * There appears to be an 2 DWORD header: + * DWORD magic; + * DWORD len; + * + * Currently implemented: BITMAP, ICON, JPEG, GIF + */ +static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) { + HRESULT hr = E_FAIL; + ULONG xread; + BYTE *xbuf; + DWORD header[2]; + WORD magic; + STATSTG statstg; + ICOM_THIS_From_IPersistStream(OLEPictureImpl, iface); + + TRACE("(%p,%p)\n",This,pStm); + + /* Sometimes we have a header, sometimes we don't. Apply some guesses to find + * out whether we do. + * + * UPDATE: the IStream can be mapped to a plain file instead of a stream in a + * compound file. This may explain most, if not all, of the cases of "no header", + * and the header validation should take this into account. At least in Visual Basic 6, + * resource streams, valid headers are + * header[0] == "lt\0\0", + * header[1] == length_of_stream. + */ + hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME); + if (hr) + FIXME("Stat failed with hres %lx\n",hr); + hr=IStream_Read(pStm,header,8,&xread); + if (hr || xread!=8) { + FIXME("Failure while reading picture header (hr is %lx, nread is %ld).\n",hr,xread); + return hr; + } + if (!memcmp(&(header[0]), "GIF8", 4) || /* GIF header */ + !memcmp(&(header[0]), "BM", 2) || /* BMP header */ + !memcmp(&(header[0]), "\xff\xd8", 2) || /* JPEG header */ + header[1] > statstg.cbSize.QuadPart || (header[1]==0)) {/* Incorrect header, assume none. */ + xread = 8; + xbuf = This->data = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,statstg.cbSize.QuadPart); + memcpy(xbuf,&header,8); + This->datalen = statstg.cbSize.QuadPart; + while (xread < This->datalen) { + ULONG nread; + hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread); + xread+=nread; + if (hr || !nread) + break; + } + if (xread != This->datalen) + FIXME("Could only read %ld of %d bytes in no-header case?\n",xread,This->datalen); + } else { + xread = 0; + xbuf = This->data = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,header[1]); + This->datalen = header[1]; + while (xread < header[1]) { + ULONG nread; + hr = IStream_Read(pStm,xbuf+xread,header[1]-xread,&nread); + xread+=nread; + if (hr || !nread) + break; + } + if (xread != header[1]) + FIXME("Could only read %ld of %ld bytes?\n",xread,header[1]); + } + magic = xbuf[0] + (xbuf[1]<<8); + switch (magic) { + case 0x4947: { /* GIF */ +#ifdef HAVE_GIF_LIB_H + struct gifdata gd; + GifFileType *gif; + BITMAPINFO *bmi; + HDC hdcref; + LPBYTE bytes; + int i,j,ret; + GifImageDesc *gid; + SavedImage *si; + ColorMapObject *cm; + int transparent = -1; + ExtensionBlock *eb; + int padding; + + if(!libungif_handle) { + if(!load_libungif()) { + FIXME("Failed reading GIF because unable to find %s/%s\n", SONAME_LIBUNGIF, SONAME_LIBGIF); + return E_FAIL; + } + } + + gd.data = xbuf; + gd.curoff = 0; + gd.len = xread; + gif = pDGifOpen((void*)&gd, _gif_inputfunc); + ret = pDGifSlurp(gif); + if (ret == GIF_ERROR) { + FIXME("Failed reading GIF using libgif.\n"); + return E_FAIL; + } + TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight); + TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor); + TRACE("imgcnt %d\n", gif->ImageCount); + if (gif->ImageCount<1) { + FIXME("GIF stream does not have images inside?\n"); + return E_FAIL; + } + TRACE("curimage: %d x %d, on %dx%d, interlace %d\n", + gif->Image.Width, gif->Image.Height, + gif->Image.Left, gif->Image.Top, + gif->Image.Interlace + ); + /* */ + padding = (gif->SWidth+3) & ~3; + bmi = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(1<<gif->SColorResolution)*sizeof(RGBQUAD)); + bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight); + si = gif->SavedImages+0; + gid = &(si->ImageDesc); + cm = gid->ColorMap; + if (!cm) cm = gif->SColorMap; + + /* look for the transparent color extension */ + for (i = 0; i < si->ExtensionBlockCount; ++i) { + eb = si->ExtensionBlocks + i; + if (eb->Function == 0xF9 && eb->ByteCount == 4) { + if ((eb->Bytes[0] & 1) == 1) { + transparent = (unsigned char)eb->Bytes[3]; + } + } + } + + for (i=0;i<(1<<gif->SColorResolution);i++) { + bmi->bmiColors[i].rgbRed = cm->Colors[i].Red; + bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green; + bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue; + if (i == transparent) { + This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed, + bmi->bmiColors[i].rgbGreen, + bmi->bmiColors[i].rgbBlue); + } + } + + /* Map to in picture coordinates */ + for (i = 0, j = 0; i < gid->Height; i++) { + if (gif->Image.Interlace) { + memcpy( + bytes + (gid->Top + j) * padding + gid->Left, + si->RasterBits + i * gid->Width, + gid->Width); + + /* Lower bits of interlaced counter encode current interlace */ + if (j & 1) j += 2; /* Currently filling odd rows */ + else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */ + else j += 8; /* Currently filling every 8th row or 4th row in-between */ + + if (j >= gid->Height && i < gid->Height && (j & 1) == 0) { + /* End of current interlace, go to next interlace */ + if (j & 2) j = 1; /* Next iteration fills odd rows */ + else if (j & 4) j = 2; /* Next iteration fills even rows not mod 4 and not mod 8 */ + else j = 4; /* Next iteration fills rows in-between rows mod 6 */ + } + } else { + memcpy( + bytes + (gid->Top + i) * padding + gid->Left, + si->RasterBits + i * gid->Width, + gid->Width); + } + } + + bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi->bmiHeader.biWidth = gif->SWidth; + bmi->bmiHeader.biHeight = -gif->SHeight; + bmi->bmiHeader.biPlanes = 1; + bmi->bmiHeader.biBitCount = 8; + bmi->bmiHeader.biCompression = BI_RGB; + bmi->bmiHeader.biSizeImage = padding*gif->SHeight; + bmi->bmiHeader.biXPelsPerMeter = 0; + bmi->bmiHeader.biYPelsPerMeter = 0; + bmi->bmiHeader.biClrUsed = 1 << gif->SColorResolution; + bmi->bmiHeader.biClrImportant = 0; + + hdcref = GetDC(0); + This->desc.u.bmp.hbitmap=CreateDIBitmap( + hdcref, + &bmi->bmiHeader, + CBM_INIT, + bytes, + bmi, + DIB_RGB_COLORS + ); + + if (transparent > -1) { + /* Create the Mask */ + HDC hdc = CreateCompatibleDC(0); + HDC hdcMask = CreateCompatibleDC(0); + HBITMAP hOldbitmap; + HBITMAP hOldbitmapmask; + + unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2; + HBITMAP hTempMask; + + This->hbmXor = CreateDIBitmap( + hdcref, + &bmi->bmiHeader, + CBM_INIT, + bytes, + bmi, + DIB_RGB_COLORS + ); + + bmi->bmiColors[0].rgbRed = 0; + bmi->bmiColors[0].rgbGreen = 0; + bmi->bmiColors[0].rgbBlue = 0; + bmi->bmiColors[1].rgbRed = 255; + bmi->bmiColors[1].rgbGreen = 255; + bmi->bmiColors[1].rgbBlue = 255; + + bmi->bmiHeader.biBitCount = 1; + bmi->bmiHeader.biSizeImage = monopadding*gif->SHeight; + bmi->bmiHeader.biClrUsed = 2; + + for (i = 0; i < gif->SHeight; i++) { + unsigned char * colorPointer = bytes + padding * i; + unsigned char * monoPointer = bytes + monopadding * i; + for (j = 0; j < gif->SWidth; j++) { + unsigned char pixel = colorPointer[j]; + if ((j & 7) == 0) monoPointer[j >> 3] = 0; + if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7)); + } + } + hdcref = GetDC(0); + hTempMask = CreateDIBitmap( + hdcref, + &bmi->bmiHeader, + CBM_INIT, + bytes, + bmi, + DIB_RGB_COLORS + ); + DeleteDC(hdcref); + + bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight; + This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL); + hOldbitmap = SelectObject(hdc, hTempMask); + hOldbitmapmask = SelectObject(hdcMask, This->hbmMask); + + SetBkColor(hdc, RGB(255, 255, 255)); + BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY); + + /* We no longer need the original bitmap, so we apply the first + transformation with the mask to speed up the rendering */ + SelectObject(hdc, This->hbmXor); + SetBkColor(hdc, RGB(0,0,0)); + SetTextColor(hdc, RGB(255,255,255)); + BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, + hdcMask, 0, 0, SRCAND); + + SelectObject(hdc, hOldbitmap); + SelectObject(hdcMask, hOldbitmapmask); + DeleteDC(hdcMask); + DeleteDC(hdc); + DeleteObject(hTempMask); + } + + DeleteDC(hdcref); + This->desc.picType = PICTYPE_BITMAP; + OLEPictureImpl_SetBitmap(This); + pDGifCloseFile(gif); + HeapFree(GetProcessHeap(),0,bytes); + return S_OK; +#else + FIXME("Trying to load GIF, but no support for libgif/libungif compiled in.\n"); + return E_FAIL; +#endif + } + case 0xd8ff: { /* JPEG */ +#ifdef HAVE_JPEGLIB_H + struct jpeg_decompress_struct jd; + struct jpeg_error_mgr jerr; + int ret; + JDIMENSION x; + JSAMPROW samprow,oldsamprow; + BITMAPINFOHEADER bmi; + LPBYTE bits; + HDC hdcref; + struct jpeg_source_mgr xjsm; + LPBYTE oldbits; + unsigned int i; + + if(!libjpeg_handle) { + if(!load_libjpeg()) { + FIXME("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG); + return E_FAIL; + } + } + + /* This is basically so we can use in-memory data for jpeg decompression. + * We need to have all the functions. + */ + xjsm.next_input_byte = xbuf; + xjsm.bytes_in_buffer = xread; + xjsm.init_source = _jpeg_init_source; + xjsm.fill_input_buffer = _jpeg_fill_input_buffer; + xjsm.skip_input_data = _jpeg_skip_input_data; + xjsm.resync_to_restart = _jpeg_resync_to_restart; + xjsm.term_source = _jpeg_term_source; + + jd.err = pjpeg_std_error(&jerr); + /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h + * jpeg_create_decompress(&jd); */ + pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, (size_t) sizeof(struct jpeg_decompress_struct)); + jd.src = &xjsm; + ret=pjpeg_read_header(&jd,TRUE); + jd.out_color_space = JCS_RGB; + pjpeg_start_decompress(&jd); + if (ret != JPEG_HEADER_OK) { + ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret); + HeapFree(GetProcessHeap(),0,xbuf); + return E_FAIL; + } + + bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, + (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) ); + samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components); + + oldbits = bits; + oldsamprow = samprow; + while ( jd.output_scanline<jd.output_height ) { + x = pjpeg_read_scanlines(&jd,&samprow,1); + if (x != 1) { + FIXME("failed to read current scanline?\n"); + break; + } + /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */ + for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) { + *(bits++) = *(samprow+2); + *(bits++) = *(samprow+1); + *(bits++) = *(samprow); + } + bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3); + samprow = oldsamprow; + } + bits = oldbits; + + bmi.biSize = sizeof(bmi); + bmi.biWidth = jd.output_width; + bmi.biHeight = -jd.output_height; + bmi.biPlanes = 1; + bmi.biBitCount = jd.output_components<<3; + bmi.biCompression = BI_RGB; + bmi.biSizeImage = jd.output_height*jd.output_width*jd.output_components; + bmi.biXPelsPerMeter = 0; + bmi.biYPelsPerMeter = 0; + bmi.biClrUsed = 0; + bmi.biClrImportant = 0; + + HeapFree(GetProcessHeap(),0,samprow); + pjpeg_finish_decompress(&jd); + pjpeg_destroy_decompress(&jd); + hdcref = GetDC(0); + This->desc.u.bmp.hbitmap=CreateDIBitmap( + hdcref, + &bmi, + CBM_INIT, + bits, + (BITMAPINFO*)&bmi, + DIB_RGB_COLORS + ); + DeleteDC(hdcref); + This->desc.picType = PICTYPE_BITMAP; + OLEPictureImpl_SetBitmap(This); + hr = S_OK; + HeapFree(GetProcessHeap(),0,bits); +#else + ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n"); + hr = E_FAIL; +#endif + break; + } + case 0x4d42: { /* Bitmap */ + BITMAPFILEHEADER *bfh = (BITMAPFILEHEADER*)xbuf; + BITMAPINFO *bi = (BITMAPINFO*)(bfh+1); + HDC hdcref; + + /* Does not matter whether this is a coreheader or not, we only use + * components which are in both + */ + hdcref = GetDC(0); + This->desc.u.bmp.hbitmap = CreateDIBitmap( + hdcref, + &(bi->bmiHeader), + CBM_INIT, + xbuf+bfh->bfOffBits, + bi, + DIB_RGB_COLORS + ); + DeleteDC(hdcref); + This->desc.picType = PICTYPE_BITMAP; + OLEPictureImpl_SetBitmap(This); + hr = S_OK; + break; + } + case 0x0000: { /* ICON , first word is dwReserved */ + HICON hicon; + CURSORICONFILEDIR *cifd = (CURSORICONFILEDIR*)xbuf; + HDC hdcRef; + int i; + + /* + FIXME("icon.idReserved=%d\n",cifd->idReserved); + FIXME("icon.idType=%d\n",cifd->idType); + FIXME("icon.idCount=%d\n",cifd->idCount); + + for (i=0;i<cifd->idCount;i++) { + FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth); + FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight); + FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount); + FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved); + FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot); + FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot); + FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize); + FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset); + } + */ + i=0; + /* If we have more than one icon, try to find the best. + * this currently means '32 pixel wide'. + */ + if (cifd->idCount!=1) { + for (i=0;i<cifd->idCount;i++) { + if (cifd->idEntries[i].bWidth == 32) + break; + } + if (i==cifd->idCount) i=0; + } + + hicon = CreateIconFromResourceEx( + xbuf+cifd->idEntries[i].dwDIBOffset, + cifd->idEntries[i].dwDIBSize, + TRUE, /* is icon */ + 0x00030000, + cifd->idEntries[i].bWidth, + cifd->idEntries[i].bHeight, + 0 + ); + if (!hicon) { + FIXME("CreateIcon failed.\n"); + hr = E_FAIL; + } else { + This->desc.picType = PICTYPE_ICON; + This->desc.u.icon.hicon = hicon; + This->origWidth = cifd->idEntries[i].bWidth; + This->origHeight = cifd->idEntries[i].bHeight; + hdcRef = CreateCompatibleDC(0); + This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX); + This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY); + DeleteDC(hdcRef); + hr = S_OK; + } + break; + } + default: + { + unsigned int i; + FIXME("Unknown magic %04x, %ld read bytes:\n",magic,xread); + hr=E_FAIL; + for (i=0;i<xread+8;i++) { + if (i<8) MESSAGE("%02x ",((unsigned char*)&header)[i]); + else MESSAGE("%02x ",xbuf[i-8]); + if (i % 10 == 9) MESSAGE("\n"); + } + MESSAGE("\n"); + break; + } + } + This->bIsDirty = FALSE; + + /* FIXME: this notify is not really documented */ + if (hr==S_OK) + OLEPicture_SendNotify(This,DISPID_PICT_TYPE); + return hr; +} + +static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength); +static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength); +static HRESULT WINAPI OLEPictureImpl_Save( + IPersistStream* iface,IStream*pStm,BOOL fClearDirty) +{ + HRESULT hResult = E_NOTIMPL; + void * pIconData; + unsigned int iDataSize; + ULONG dummy; + int iSerializeResult = 0; + + ICOM_THIS_From_IPersistStream(OLEPictureImpl, iface); + + switch (This->desc.picType) { + case PICTYPE_ICON: + if (This->bIsDirty) { + if (serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) { + if (This->loadtime_magic != 0xdeadbeef) { + DWORD header[2]; + + header[0] = This->loadtime_magic; + header[1] = iDataSize; + IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy); + } + IStream_Write(pStm, pIconData, iDataSize, &dummy); + + HeapFree(GetProcessHeap(), 0, This->data); + This->data = pIconData; + This->datalen = iDataSize; + hResult = S_OK; + } else { + FIXME("(%p,%p,%d), unable to serializeIcon()!\n",This,pStm,fClearDirty); + hResult = E_FAIL; + } + } else { + if (This->loadtime_magic != 0xdeadbeef) { + DWORD header[2]; + + header[0] = This->loadtime_magic; + header[1] = This->datalen; + IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy); + } + IStream_Write(pStm, This->data, This->datalen, &dummy); + hResult = S_OK; + } + break; + case PICTYPE_BITMAP: + if (This->bIsDirty) { + switch (This->keepOrigFormat ? This->loadtime_format : 0x4d42) { + case 0x4d42: + iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize); + break; + case 0xd8ff: + FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty); + break; + case 0x4947: + FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty); + break; + default: + FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty); + break; + } + if (iSerializeResult) { + /* + if (This->loadtime_magic != 0xdeadbeef) { + */ + if (1) { + DWORD header[2]; + + header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c; + header[1] = iDataSize; + IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy); + } + IStream_Write(pStm, pIconData, iDataSize, &dummy); + + HeapFree(GetProcessHeap(), 0, This->data); + This->data = pIconData; + This->datalen = iDataSize; + hResult = S_OK; + } + } else { + /* + if (This->loadtime_magic != 0xdeadbeef) { + */ + if (1) { + DWORD header[2]; + + header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c; + header[1] = This->datalen; + IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy); + } + IStream_Write(pStm, This->data, This->datalen, &dummy); + hResult = S_OK; + } + break; + case PICTYPE_METAFILE: + FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty); + break; + case PICTYPE_ENHMETAFILE: + FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty); + break; + default: + FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty); + break; + } + if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE; + return hResult; +} + +static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength) +{ + int iSuccess = 0; + HDC hDC; + BITMAPINFO * pInfoBitmap; + int iNumPaletteEntries; + unsigned char * pPixelData; + BITMAPFILEHEADER * pFileHeader; + BITMAPINFO * pInfoHeader; + + pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); + + /* Find out bitmap size and padded length */ + hDC = GetDC(0); + pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader); + GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS); + + /* Fetch bitmap palette & pixel data */ + + pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage); + GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS); + + /* Calculate the total length required for the BMP data */ + if (pInfoBitmap->bmiHeader.biClrUsed != 0) { + iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed; + if (iNumPaletteEntries > 256) iNumPaletteEntries = 256; + } else { + if (pInfoBitmap->bmiHeader.biBitCount <= 8) + iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount; + else + iNumPaletteEntries = 0; + } + *pLength = + sizeof(BITMAPFILEHEADER) + + sizeof(BITMAPINFOHEADER) + + iNumPaletteEntries * sizeof(RGBQUAD) + + pInfoBitmap->bmiHeader.biSizeImage; + *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength); + + /* Fill the BITMAPFILEHEADER */ + pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer); + pFileHeader->bfType = 0x4d42; + pFileHeader->bfSize = *pLength; + pFileHeader->bfOffBits = + sizeof(BITMAPFILEHEADER) + + sizeof(BITMAPINFOHEADER) + + iNumPaletteEntries * sizeof(RGBQUAD); + + /* Fill the BITMAPINFOHEADER and the palette data */ + pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER)); + memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD)); + memcpy( + (unsigned char *)(*ppBuffer) + + sizeof(BITMAPFILEHEADER) + + sizeof(BITMAPINFOHEADER) + + iNumPaletteEntries * sizeof(RGBQUAD), + pPixelData, pInfoBitmap->bmiHeader.biSizeImage); + iSuccess = 1; + + HeapFree(GetProcessHeap(), 0, pPixelData); + HeapFree(GetProcessHeap(), 0, pInfoBitmap); + return iSuccess; +} + +static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength) +{ + ICONINFO infoIcon; + int iSuccess = 0; + + *ppBuffer = NULL; *pLength = 0; + if (GetIconInfo(hIcon, &infoIcon)) { + HDC hDC; + BITMAPINFO * pInfoBitmap; + unsigned char * pIconData = NULL; + unsigned int iDataSize = 0; + + pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); + + /* Find out icon size */ + hDC = GetDC(0); + pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader); + GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS); + if (1) { + /* Auxiliary pointers */ + CURSORICONFILEDIR * pIconDir; + CURSORICONFILEDIRENTRY * pIconEntry; + BITMAPINFOHEADER * pIconBitmapHeader; + unsigned int iOffsetPalette; + unsigned int iOffsetColorData; + unsigned int iOffsetMaskData; + + unsigned int iLengthScanLineColor; + unsigned int iLengthScanLineMask; + unsigned int iNumEntriesPalette; + + iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2; + iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2; +/* + FIXME("DEBUG: bitmap size is %d x %d\n", + pInfoBitmap->bmiHeader.biWidth, + pInfoBitmap->bmiHeader.biHeight); + FIXME("DEBUG: bitmap bpp is %d\n", + pInfoBitmap->bmiHeader.biBitCount); + FIXME("DEBUG: bitmap nplanes is %d\n", + pInfoBitmap->bmiHeader.biPlanes); + FIXME("DEBUG: bitmap biSizeImage is %lu\n", + pInfoBitmap->bmiHeader.biSizeImage); +*/ + /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */ + iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER); + pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize); + + /* Fill out the CURSORICONFILEDIR */ + pIconDir = (CURSORICONFILEDIR *)pIconData; + pIconDir->idType = 1; + pIconDir->idCount = 1; + + /* Fill out the CURSORICONFILEDIRENTRY */ + pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD)); + pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth; + pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight; + pIconEntry->bColorCount = + (pInfoBitmap->bmiHeader.biBitCount < 8) + ? 1 << pInfoBitmap->bmiHeader.biBitCount + : 0; + pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes; + pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount; + pIconEntry->dwDIBSize = 0; + pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY); + + /* Fill out the BITMAPINFOHEADER */ + pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY)); + memcpy(pIconBitmapHeader, &pInfoBitmap->bmiHeader, sizeof(BITMAPINFOHEADER)); + + /* Find out whether a palette exists for the bitmap */ + if ( (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB) + || (pInfoBitmap->bmiHeader.biBitCount == 24) + || (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) { + iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed; + if (iNumEntriesPalette > 256) iNumEntriesPalette = 256; + } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32) + && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) { + iNumEntriesPalette = 3; + } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) { + iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount; + } else { + iNumEntriesPalette = 0; + } + + /* Add bitmap size and header size to icon data size. */ + iOffsetPalette = iDataSize; + iDataSize += iNumEntriesPalette * sizeof(DWORD); + iOffsetColorData = iDataSize; + iDataSize += pIconBitmapHeader->biSizeImage; + iOffsetMaskData = iDataSize; + iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask; + pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask; + pIconBitmapHeader->biHeight *= 2; + pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize); + pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD)); + pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY)); + pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY)); + + /* Get the actual bitmap data from the icon bitmap */ + GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight, + pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS); + if (iNumEntriesPalette > 0) { + memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors, + iNumEntriesPalette * sizeof(RGBQUAD)); + } + + /* Reset all values so that GetDIBits call succeeds */ + memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData); + memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); + pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader); +/* + if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS) + && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, + pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) { + + printf("ERROR: unable to get bitmap mask (error %lu)\n", + GetLastError()); + + } +*/ + GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS); + GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS); + + /* Write out everything produced so far to the stream */ + *ppBuffer = pIconData; *pLength = iDataSize; + iSuccess = 1; + } else { +/* + printf("ERROR: unable to get bitmap information via GetDIBits() (error %lu)\n", + GetLastError()); +*/ + } + /* + Remarks (from MSDN entry on GetIconInfo): + + GetIconInfo creates bitmaps for the hbmMask and hbmColor + members of ICONINFO. The calling application must manage + these bitmaps and delete them when they are no longer + necessary. + */ + if (hDC) ReleaseDC(0, hDC); + DeleteObject(infoIcon.hbmMask); + if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor); + HeapFree(GetProcessHeap(), 0, pInfoBitmap); + } else { + printf("ERROR: Unable to get icon information (error %lu)\n", + GetLastError()); + } + return iSuccess; +} + +static HRESULT WINAPI OLEPictureImpl_GetSizeMax( + IPersistStream* iface,ULARGE_INTEGER*pcbSize) +{ + ICOM_THIS_From_IPersistStream(IPicture, iface); + FIXME("(%p,%p),stub!\n",This,pcbSize); + return E_NOTIMPL; +} + +/************************************************************************ + * IDispatch + */ +/************************************************************************ + * OLEPictureImpl_IDispatch_QueryInterface (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface( + IDispatch* iface, + REFIID riid, + VOID** ppvoid) +{ + ICOM_THIS_From_IDispatch(IPicture, iface); + + return IPicture_QueryInterface(This, riid, ppvoid); +} + +/************************************************************************ + * OLEPictureImpl_IDispatch_AddRef (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef( + IDispatch* iface) +{ + ICOM_THIS_From_IDispatch(IPicture, iface); + + return IPicture_AddRef(This); +} + +/************************************************************************ + * OLEPictureImpl_IDispatch_Release (IUnknown) + * + * See Windows documentation for more details on IUnknown methods. + */ +static ULONG WINAPI OLEPictureImpl_IDispatch_Release( + IDispatch* iface) +{ + ICOM_THIS_From_IDispatch(IPicture, iface); + + return IPicture_Release(This); +} + +/************************************************************************ + * OLEPictureImpl_GetTypeInfoCount (IDispatch) + * + * See Windows documentation for more details on IDispatch methods. + */ +static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount( + IDispatch* iface, + unsigned int* pctinfo) +{ + FIXME("():Stub\n"); + + return E_NOTIMPL; +} + +/************************************************************************ + * OLEPictureImpl_GetTypeInfo (IDispatch) + * + * See Windows documentation for more details on IDispatch methods. + */ +static HRESULT WINAPI OLEPictureImpl_GetTypeInfo( + IDispatch* iface, + UINT iTInfo, + LCID lcid, + ITypeInfo** ppTInfo) +{ + FIXME("():Stub\n"); + + return E_NOTIMPL; +} + +/************************************************************************ + * OLEPictureImpl_GetIDsOfNames (IDispatch) + * + * See Windows documentation for more details on IDispatch methods. + */ +static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames( + IDispatch* iface, + REFIID riid, + LPOLESTR* rgszNames, + UINT cNames, + LCID lcid, + DISPID* rgDispId) +{ + FIXME("():Stub\n"); + + return E_NOTIMPL; +} + +/************************************************************************ + * OLEPictureImpl_Invoke (IDispatch) + * + * See Windows documentation for more details on IDispatch methods. + */ +static HRESULT WINAPI OLEPictureImpl_Invoke( + IDispatch* iface, + DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS* pDispParams, + VARIANT* pVarResult, + EXCEPINFO* pExepInfo, + UINT* puArgErr) +{ + FIXME("(dispid: %ld):Stub\n",dispIdMember); + + VariantInit(pVarResult); + V_VT(pVarResult) = VT_BOOL; + V_BOOL(pVarResult) = FALSE; + return S_OK; +} + + +static IPictureVtbl OLEPictureImpl_VTable = +{ + OLEPictureImpl_QueryInterface, + OLEPictureImpl_AddRef, + OLEPictureImpl_Release, + OLEPictureImpl_get_Handle, + OLEPictureImpl_get_hPal, + OLEPictureImpl_get_Type, + OLEPictureImpl_get_Width, + OLEPictureImpl_get_Height, + OLEPictureImpl_Render, + OLEPictureImpl_set_hPal, + OLEPictureImpl_get_CurDC, + OLEPictureImpl_SelectPicture, + OLEPictureImpl_get_KeepOriginalFormat, + OLEPictureImpl_put_KeepOriginalFormat, + OLEPictureImpl_PictureChanged, + OLEPictureImpl_SaveAsFile, + OLEPictureImpl_get_Attributes +}; + +static IDispatchVtbl OLEPictureImpl_IDispatch_VTable = +{ + OLEPictureImpl_IDispatch_QueryInterface, + OLEPictureImpl_IDispatch_AddRef, + OLEPictureImpl_IDispatch_Release, + OLEPictureImpl_GetTypeInfoCount, + OLEPictureImpl_GetTypeInfo, + OLEPictureImpl_GetIDsOfNames, + OLEPictureImpl_Invoke +}; + +static IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable = +{ + OLEPictureImpl_IPersistStream_QueryInterface, + OLEPictureImpl_IPersistStream_AddRef, + OLEPictureImpl_IPersistStream_Release, + OLEPictureImpl_GetClassID, + OLEPictureImpl_IsDirty, + OLEPictureImpl_Load, + OLEPictureImpl_Save, + OLEPictureImpl_GetSizeMax +}; + +static IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable = +{ + OLEPictureImpl_IConnectionPointContainer_QueryInterface, + OLEPictureImpl_IConnectionPointContainer_AddRef, + OLEPictureImpl_IConnectionPointContainer_Release, + OLEPictureImpl_EnumConnectionPoints, + OLEPictureImpl_FindConnectionPoint +}; + +/*********************************************************************** + * OleCreatePictureIndirect (OLEAUT32.419) + */ +HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid, + BOOL fOwn, LPVOID *ppvObj ) +{ + OLEPictureImpl* newPict = NULL; + HRESULT hr = S_OK; + + TRACE("(%p,%p,%d,%p)\n", lpPictDesc, riid, fOwn, ppvObj); + + /* + * Sanity check + */ + if (ppvObj==0) + return E_POINTER; + + *ppvObj = NULL; + + /* + * Try to construct a new instance of the class. + */ + newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn); + + if (newPict == NULL) + return E_OUTOFMEMORY; + + /* + * Make sure it supports the interface required by the caller. + */ + hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj); + + /* + * Release the reference obtained in the constructor. If + * the QueryInterface was unsuccessful, it will free the class. + */ + IPicture_Release((IPicture*)newPict); + + return hr; +} + + +/*********************************************************************** + * OleLoadPicture (OLEAUT32.418) + */ +HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode, + REFIID riid, LPVOID *ppvObj ) +{ + LPPERSISTSTREAM ps; + IPicture *newpic; + HRESULT hr; + + TRACE("(%p,%ld,%d,%s,%p), partially implemented.\n", + lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj); + + hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic); + if (hr) + return hr; + hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps); + if (hr) { + FIXME("Could not get IPersistStream iface from Ole Picture?\n"); + IPicture_Release(newpic); + *ppvObj = NULL; + return hr; + } + IPersistStream_Load(ps,lpstream); + IPersistStream_Release(ps); + hr = IPicture_QueryInterface(newpic,riid,ppvObj); + if (hr) + FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid)); + IPicture_Release(newpic); + return hr; +} + +/*********************************************************************** + * OleLoadPictureEx (OLEAUT32.401) + */ +HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode, + REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj ) +{ + LPPERSISTSTREAM ps; + IPicture *newpic; + HRESULT hr; + + FIXME("(%p,%ld,%d,%s,x=%ld,y=%ld,f=%lx,%p), partially implemented.\n", + lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj); + + hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic); + if (hr) + return hr; + hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps); + if (hr) { + FIXME("Could not get IPersistStream iface from Ole Picture?\n"); + IPicture_Release(newpic); + *ppvObj = NULL; + return hr; + } + IPersistStream_Load(ps,lpstream); + IPersistStream_Release(ps); + hr = IPicture_QueryInterface(newpic,riid,ppvObj); + if (hr) + FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid)); + IPicture_Release(newpic); + return hr; +} + +/*********************************************************************** + * OleLoadPicturePath (OLEAUT32.424) + */ +HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller, + DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid, + LPVOID *ppvRet ) +{ + static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 }; + IPicture *ipicture; + HANDLE hFile; + DWORD dwFileSize; + HGLOBAL hGlobal = NULL; + DWORD dwBytesRead = 0; + IStream *stream; + BOOL bRead; + IPersistStream *pStream; + HRESULT hRes; + + TRACE("(%s,%p,%ld,%08lx,%s,%p): stub\n", + debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved, + debugstr_guid(riid), ppvRet); + + if (!ppvRet) return E_POINTER; + + if (strncmpW(szURLorPath, file, 7) == 0) { + szURLorPath += 7; + + hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, + 0, NULL); + if (hFile == INVALID_HANDLE_VALUE) + return E_UNEXPECTED; + + dwFileSize = GetFileSize(hFile, NULL); + if (dwFileSize != INVALID_FILE_SIZE ) + { + hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize); + if ( hGlobal) + { + bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL); + if (!bRead) + { + GlobalFree(hGlobal); + hGlobal = 0; + } + } + } + CloseHandle(hFile); + + if (!hGlobal) + return E_UNEXPECTED; + + hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream); + if (FAILED(hRes)) + { + GlobalFree(hGlobal); + return hRes; + } + } else { + IMoniker *pmnk; + IBindCtx *pbc; + + hRes = CreateBindCtx(0, &pbc); + if (SUCCEEDED(hRes)) + { + hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk); + if (SUCCEEDED(hRes)) + { + hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream); + IMoniker_Release(pmnk); + } + IBindCtx_Release(pbc); + } + if (FAILED(hRes)) + return hRes; + } + + hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER, + &IID_IPicture, (LPVOID*)&ipicture); + if (hRes != S_OK) { + IStream_Release(stream); + return hRes; + } + + hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream); + if (hRes) { + IStream_Release(stream); + IPicture_Release(ipicture); + return hRes; + } + + hRes = IPersistStream_Load(pStream, stream); + IPersistStream_Release(pStream); + IStream_Release(stream); + + if (hRes) { + IPicture_Release(ipicture); + return hRes; + } + + hRes = IPicture_QueryInterface(ipicture,riid,ppvRet); + if (hRes) + FIXME("Failed to get interface %s from IPicture.\n",debugstr_guid(riid)); + + IPicture_Release(ipicture); + return hRes; +} + +/******************************************************************************* + * StdPic ClassFactory + */ +typedef struct +{ + /* IUnknown fields */ + IClassFactoryVtbl *lpVtbl; + DWORD ref; +} IClassFactoryImpl; + +static HRESULT WINAPI +SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + + FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj); + return E_NOINTERFACE; +} + +static ULONG WINAPI +SPCF_AddRef(LPCLASSFACTORY iface) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + /* static class, won't be freed */ + return InterlockedDecrement(&This->ref); +} + +static HRESULT WINAPI SPCF_CreateInstance( + LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj +) { + /* Creates an uninitialized picture */ + return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj); + +} + +static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + FIXME("(%p)->(%d),stub!\n",This,dolock); + return S_OK; +} + +static IClassFactoryVtbl SPCF_Vtbl = { + SPCF_QueryInterface, + SPCF_AddRef, + SPCF_Release, + SPCF_CreateInstance, + SPCF_LockServer +}; +static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 }; + +void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; } diff --git a/reactos/lib/oleaut32/regsvr.c b/reactos/lib/oleaut32/regsvr.c index 2c1e851b200..03c472e73a2 100644 --- a/reactos/lib/oleaut32/regsvr.c +++ b/reactos/lib/oleaut32/regsvr.c @@ -1,931 +1,931 @@ -/* - * self-registerable dll functions for oleaut32.dll - * - * Copyright (C) 2003 John K. Hohm - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> -#include <string.h> - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "winreg.h" -#include "winerror.h" - -#include "ole2.h" -#include "olectl.h" -#include "oleauto.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/* - * Near the bottom of this file are the exported DllRegisterServer and - * DllUnregisterServer, which make all this worthwhile. - */ - -/*********************************************************************** - * interface for self-registering - */ -struct regsvr_interface -{ - IID const *iid; /* NULL for end of list */ - LPCSTR name; /* can be NULL to omit */ - IID const *base_iid; /* can be NULL to omit */ - int num_methods; /* can be <0 to omit */ - CLSID const *ps_clsid; /* can be NULL to omit */ - CLSID const *ps_clsid32; /* can be NULL to omit */ -}; - -static HRESULT register_interfaces(struct regsvr_interface const *list); -static HRESULT unregister_interfaces(struct regsvr_interface const *list); - -struct regsvr_coclass -{ - CLSID const *clsid; /* NULL for end of list */ - LPCSTR name; /* can be NULL to omit */ - LPCSTR ips; /* can be NULL to omit */ - LPCSTR ips32; /* can be NULL to omit */ - LPCSTR ips32_tmodel; /* can be NULL to omit */ - LPCSTR clsid_str; /* can be NULL to omit */ - LPCSTR progid; /* can be NULL to omit */ -}; - -static HRESULT register_coclasses(struct regsvr_coclass const *list); -static HRESULT unregister_coclasses(struct regsvr_coclass const *list); - -/*********************************************************************** - * static string constants - */ -static WCHAR const interface_keyname[10] = { - 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 }; -static WCHAR const base_ifa_keyname[14] = { - 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', - 'e', 0 }; -static WCHAR const num_methods_keyname[11] = { - 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 }; -static WCHAR const ps_clsid_keyname[15] = { - 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', - 'i', 'd', 0 }; -static WCHAR const ps_clsid32_keyname[17] = { - 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', - 'i', 'd', '3', '2', 0 }; -static WCHAR const clsid_keyname[6] = { - 'C', 'L', 'S', 'I', 'D', 0 }; -static WCHAR const ips_keyname[13] = { - 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', - 0 }; -static WCHAR const ips32_keyname[15] = { - 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', - '3', '2', 0 }; -static WCHAR const progid_keyname[7] = { - 'P', 'r', 'o', 'g', 'I', 'D', 0 }; -static char const tmodel_valuename[] = "ThreadingModel"; - -/*********************************************************************** - * static helper functions - */ -static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid); -static LONG register_key_defvalueW(HKEY base, WCHAR const *name, - WCHAR const *value); -static LONG register_key_defvalueA(HKEY base, WCHAR const *name, - char const *value); -static LONG recursive_delete_key(HKEY key); -static LONG recursive_delete_keyA(HKEY base, char const *name); -static LONG recursive_delete_keyW(HKEY base, WCHAR const *name); - -/*********************************************************************** - * register_interfaces - */ -static HRESULT register_interfaces(struct regsvr_interface const *list) -{ - LONG res = ERROR_SUCCESS; - HKEY interface_key; - - res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &interface_key, NULL); - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->iid; ++list) { - WCHAR buf[39]; - HKEY iid_key; - - StringFromGUID2(list->iid, buf, 39); - res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &iid_key, NULL); - if (res != ERROR_SUCCESS) goto error_close_interface_key; - - if (list->name) { - res = RegSetValueExA(iid_key, NULL, 0, REG_SZ, - (CONST BYTE*)(list->name), - strlen(list->name) + 1); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (list->base_iid) { - register_key_guid(iid_key, base_ifa_keyname, list->base_iid); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (0 <= list->num_methods) { - static WCHAR const fmt[3] = { '%', 'd', 0 }; - HKEY key; - - res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &key, NULL); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - - wsprintfW(buf, fmt, list->num_methods); - res = RegSetValueExW(key, NULL, 0, REG_SZ, - (CONST BYTE*)buf, - (lstrlenW(buf) + 1) * sizeof(WCHAR)); - RegCloseKey(key); - - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (list->ps_clsid) { - register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (list->ps_clsid32) { - register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - error_close_iid_key: - RegCloseKey(iid_key); - } - -error_close_interface_key: - RegCloseKey(interface_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * unregister_interfaces - */ -static HRESULT unregister_interfaces(struct regsvr_interface const *list) -{ - LONG res = ERROR_SUCCESS; - HKEY interface_key; - - res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, - KEY_READ | KEY_WRITE, &interface_key); - if (res == ERROR_FILE_NOT_FOUND) return S_OK; - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->iid; ++list) { - WCHAR buf[39]; - - StringFromGUID2(list->iid, buf, 39); - res = recursive_delete_keyW(interface_key, buf); - } - - RegCloseKey(interface_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * register_coclasses - */ -static HRESULT register_coclasses(struct regsvr_coclass const *list) -{ - LONG res = ERROR_SUCCESS; - HKEY coclass_key; - - res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL); - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->clsid; ++list) { - WCHAR buf[39]; - HKEY clsid_key; - - StringFromGUID2(list->clsid, buf, 39); - res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL); - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - - if (list->name) { - res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ, - (CONST BYTE*)(list->name), - strlen(list->name) + 1); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->ips) { - res = register_key_defvalueA(clsid_key, ips_keyname, list->ips); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->ips32) { - HKEY ips32_key; - - res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, - &ips32_key, NULL); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - - res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ, - (CONST BYTE*)list->ips32, - lstrlenA(list->ips32) + 1); - if (res == ERROR_SUCCESS && list->ips32_tmodel) - res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ, - (CONST BYTE*)list->ips32_tmodel, - strlen(list->ips32_tmodel) + 1); - RegCloseKey(ips32_key); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->clsid_str) { - res = register_key_defvalueA(clsid_key, clsid_keyname, - list->clsid_str); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->progid) { - HKEY progid_key; - - res = register_key_defvalueA(clsid_key, progid_keyname, - list->progid); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - - res = RegCreateKeyExA(HKEY_CLASSES_ROOT, list->progid, 0, - NULL, 0, KEY_READ | KEY_WRITE, NULL, - &progid_key, NULL); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - - res = register_key_defvalueW(progid_key, clsid_keyname, buf); - RegCloseKey(progid_key); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - error_close_clsid_key: - RegCloseKey(clsid_key); - } - -error_close_coclass_key: - RegCloseKey(coclass_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * unregister_coclasses - */ -static HRESULT unregister_coclasses(struct regsvr_coclass const *list) -{ - LONG res = ERROR_SUCCESS; - HKEY coclass_key; - - res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, - KEY_READ | KEY_WRITE, &coclass_key); - if (res == ERROR_FILE_NOT_FOUND) return S_OK; - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->clsid; ++list) { - WCHAR buf[39]; - - StringFromGUID2(list->clsid, buf, 39); - res = recursive_delete_keyW(coclass_key, buf); - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - - if (list->progid) { - res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid); - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - } - } - -error_close_coclass_key: - RegCloseKey(coclass_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * regsvr_key_guid - */ -static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) -{ - WCHAR buf[39]; - - StringFromGUID2(guid, buf, 39); - return register_key_defvalueW(base, name, buf); -} - -/*********************************************************************** - * regsvr_key_defvalueW - */ -static LONG register_key_defvalueW( - HKEY base, - WCHAR const *name, - WCHAR const *value) -{ - LONG res; - HKEY key; - - res = RegCreateKeyExW(base, name, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &key, NULL); - if (res != ERROR_SUCCESS) return res; - res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value, - (lstrlenW(value) + 1) * sizeof(WCHAR)); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * regsvr_key_defvalueA - */ -static LONG register_key_defvalueA( - HKEY base, - WCHAR const *name, - char const *value) -{ - LONG res; - HKEY key; - - res = RegCreateKeyExW(base, name, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &key, NULL); - if (res != ERROR_SUCCESS) return res; - res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value, - lstrlenA(value) + 1); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * recursive_delete_key - */ -static LONG recursive_delete_key(HKEY key) -{ - LONG res; - WCHAR subkey_name[MAX_PATH]; - DWORD cName; - HKEY subkey; - - for (;;) { - cName = sizeof(subkey_name) / sizeof(WCHAR); - res = RegEnumKeyExW(key, 0, subkey_name, &cName, - NULL, NULL, NULL, NULL); - if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) { - res = ERROR_SUCCESS; /* presumably we're done enumerating */ - break; - } - res = RegOpenKeyExW(key, subkey_name, 0, - KEY_READ | KEY_WRITE, &subkey); - if (res == ERROR_FILE_NOT_FOUND) continue; - if (res != ERROR_SUCCESS) break; - - res = recursive_delete_key(subkey); - RegCloseKey(subkey); - if (res != ERROR_SUCCESS) break; - } - - if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0); - return res; -} - -/*********************************************************************** - * recursive_delete_keyA - */ -static LONG recursive_delete_keyA(HKEY base, char const *name) -{ - LONG res; - HKEY key; - - res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key); - if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; - if (res != ERROR_SUCCESS) return res; - res = recursive_delete_key(key); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * recursive_delete_keyW - */ -static LONG recursive_delete_keyW(HKEY base, WCHAR const *name) -{ - LONG res; - HKEY key; - - res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key); - if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; - if (res != ERROR_SUCCESS) return res; - res = recursive_delete_key(key); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * coclass list - */ -static GUID const CLSID_RecordInfo = { - 0x0000002F, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; - -extern GUID const CLSID_PSDispatch; - -static GUID const CLSID_PSEnumVariant = { - 0x00020421, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; - -static GUID const CLSID_PSTypeInfo = { - 0x00020422, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; - -static GUID const CLSID_PSTypeLib = { - 0x00020423, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; - -extern GUID const CLSID_PSOAInterface; - -static GUID const CLSID_PSTypeComp = { - 0x00020425, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; - -static GUID const CLSID_OldFont = { - 0x46763EE0, 0xCAB2, 0x11CE, {0x8C,0x20,0x00,0xAA,0x00,0x51,0xE5,0xD4} }; - -static GUID const CLSID_PSFactoryBuffer = { - 0xB196B286, 0xBAB4, 0x101A, {0xB6,0x9C,0x00,0xAA,0x00,0x34,0x1D,0x07} }; - -static struct regsvr_coclass const coclass_list[] = { - { &CLSID_RecordInfo, - "CLSID_RecordInfo", - NULL, - "oleaut32.dll", - "Both" - }, - { &CLSID_PSDispatch, - "PSDispatch", - "ole2disp.dll", - "oleaut32.dll", - "Both" - }, - { &CLSID_StdFont, - "CLSID_StdFont", - NULL, - "oleaut32.dll", - "Both", - "Standard Font", - "StdFont" - }, - { &CLSID_StdPicture, - "CLSID_StdPict", - NULL, - "oleaut32.dll", - "Apartment", - "Standard Picture", - "StdPicture" - }, - { &CLSID_PSEnumVariant, - "PSEnumVariant", - "ole2disp.dll", - "oleaut32.dll", - "Both" - }, - { &CLSID_PSTypeInfo, - "PSTypeInfo", - "ole2disp.dll", - "oleaut32.dll", - "Both" - }, - { &CLSID_PSTypeLib, - "PSTypeLib", - "ole2disp.dll", - "oleaut32.dll", - "Both" - }, - { &CLSID_PSOAInterface, - "PSOAInterface", - "ole2disp.dll", - "oleaut32.dll", - "Both" - }, - { &CLSID_PSTypeComp, - "PSTypeComp", - "ole2disp.dll", - "oleaut32.dll", - "Both" - }, - { &CLSID_OldFont, - "Obsolete Font", - NULL, - "oleaut32.dll", - NULL, - "Obsolete Font", - "OldFont" - }, - { &CLSID_PSFactoryBuffer, - "PSFactoryBuffer", - NULL, - "oleaut32.dll", - "Both" - }, - { NULL } /* list terminator */ -}; - -/*********************************************************************** - * interface list - */ - -/* FIXME: these interfaces should be defined in ocidl.idl */ - -static IID const IID_IFontEventsDisp = { - 0x4EF6100A, 0xAF88, 0x11D0, {0x98,0x46,0x00,0xC0,0x4F,0xC2,0x99,0x93} }; - -static IID const IID_IProvideMultipleClassInfo = { - 0xA7ABA9C1, 0x8983, 0x11CF, {0x8F,0x20,0x00,0x80,0x5F,0x2C,0xD0,0x64} }; - -static struct regsvr_interface const interface_list[] = { - { &IID_IDispatch, - "IDispatch", - NULL, - 7, - &CLSID_PSDispatch, - &CLSID_PSDispatch - }, - { &IID_ITypeInfo, - "ITypeInfo", - NULL, - 22, - NULL, - &CLSID_PSTypeInfo - }, - { &IID_ITypeLib, - "ITypeLib", - NULL, - 13, - NULL, - &CLSID_PSTypeLib - }, - { &IID_ITypeComp, - "ITypeComp", - NULL, - 5, - NULL, - &CLSID_PSTypeComp - }, - { &IID_IEnumVARIANT, - "IEnumVARIANT", - NULL, - 15, - NULL, - &CLSID_PSEnumVariant - }, - { &IID_ICreateTypeInfo, - "ICreateTypeInfo", - NULL, - 26, - NULL, - NULL - }, - { &IID_ICreateTypeLib, - "ICreateTypeLib", - NULL, - 13, - NULL, - NULL - }, - { &IID_ITypeInfo2, - "ITypeInfo2", - NULL, - 32, - NULL, - &CLSID_PSDispatch - }, - { &IID_ITypeLib2, - "ITypeLib2", - NULL, - 16, - NULL, - &CLSID_PSDispatch - }, - { &IID_IPropertyPage2, - "IPropertyPage2", - NULL, - 15, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IErrorInfo, - "IErrorInfo", - NULL, - 8, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_ICreateErrorInfo, - "ICreateErrorInfo", - NULL, - 8, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IPersistPropertyBag2, - "IPersistPropertyBag2", - NULL, - 8, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IPropertyBag2, - "IPropertyBag2", - NULL, - 8, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IErrorLog, - "IErrorLog", - NULL, - 4, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IPerPropertyBrowsing, - "IPerPropertyBrowsing", - NULL, - 7, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IPersistPropertyBag, - "IPersistPropertyBag", - NULL, - 7, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IAdviseSinkEx, - "IAdviseSinkEx", - NULL, - 9, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IFontEventsDisp, - "IFontEventsDisp", - NULL, - 7, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IPropertyBag, - "IPropertyBag", - NULL, - 5, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IPointerInactive, - "IPointerInactive", - NULL, - 6, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_ISimpleFrameSite, - "ISimpleFrameSite", - NULL, - 5, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IPicture, - "IPicture", - NULL, - 17, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IPictureDisp, - "IPictureDisp", - NULL, - 7, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IPersistStreamInit, - "IPersistStreamInit", - NULL, - 9, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IOleUndoUnit, - "IOleUndoUnit", - NULL, - 7, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IPropertyNotifySink, - "IPropertyNotifySink", - NULL, - 5, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IOleInPlaceSiteEx, - "IOleInPlaceSiteEx", - NULL, - 18, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IOleParentUndoUnit, - "IOleParentUndoUnit", - NULL, - 12, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IProvideClassInfo2, - "IProvideClassInfo2", - NULL, - 5, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IProvideMultipleClassInfo, - "IProvideMultipleClassInfo", - NULL, - 7, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IProvideClassInfo, - "IProvideClassInfo", - NULL, - 4, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IConnectionPointContainer, - "IConnectionPointContainer", - NULL, - 5, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IEnumConnectionPoints, - "IEnumConnectionPoints", - NULL, - 7, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IConnectionPoint, - "IConnectionPoint", - NULL, - 8, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IEnumConnections, - "IEnumConnections", - NULL, - 7, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IOleControl, - "IOleControl", - NULL, - 7, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IOleControlSite, - "IOleControlSite", - NULL, - 10, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_ISpecifyPropertyPages, - "ISpecifyPropertyPages", - NULL, - 4, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IPropertyPageSite, - "IPropertyPageSite", - NULL, - 7, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IPropertyPage, - "IPropertyPage", - NULL, - 14, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IClassFactory2, - "IClassFactory2", - NULL, - 8, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IEnumOleUndoUnits, - "IEnumOleUndoUnits", - NULL, - 7, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IPersistMemory, - "IPersistMemory", - NULL, - 9, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IFont, - "IFont", - NULL, - 27, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IFontDisp, - "IFontDisp", - NULL, - 7, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IQuickActivate, - "IQuickActivate", - NULL, - 6, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IOleUndoManager, - "IOleUndoManager", - NULL, - 15, - NULL, - &CLSID_PSFactoryBuffer - }, - { &IID_IObjectWithSite, - "IObjectWithSite", - NULL, - 5, - NULL, - &CLSID_PSFactoryBuffer - }, - { NULL } /* list terminator */ -}; - -/*********************************************************************** - * DllRegisterServer (OLEAUT32.320) - */ -HRESULT WINAPI OLEAUT32_DllRegisterServer() -{ - HRESULT hr; - - TRACE("\n"); - - hr = register_coclasses(coclass_list); - if (SUCCEEDED(hr)) - hr = register_interfaces(interface_list); - return hr; -} - -/*********************************************************************** - * DllUnregisterServer (OLEAUT32.321) - */ -HRESULT WINAPI OLEAUT32_DllUnregisterServer() -{ - HRESULT hr; - - TRACE("\n"); - - hr = unregister_coclasses(coclass_list); - if (SUCCEEDED(hr)) - hr = unregister_interfaces(interface_list); - return hr; -} +/* + * self-registerable dll functions for oleaut32.dll + * + * Copyright (C) 2003 John K. Hohm + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> +#include <string.h> + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "winerror.h" + +#include "ole2.h" +#include "olectl.h" +#include "oleauto.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/* + * Near the bottom of this file are the exported DllRegisterServer and + * DllUnregisterServer, which make all this worthwhile. + */ + +/*********************************************************************** + * interface for self-registering + */ +struct regsvr_interface +{ + IID const *iid; /* NULL for end of list */ + LPCSTR name; /* can be NULL to omit */ + IID const *base_iid; /* can be NULL to omit */ + int num_methods; /* can be <0 to omit */ + CLSID const *ps_clsid; /* can be NULL to omit */ + CLSID const *ps_clsid32; /* can be NULL to omit */ +}; + +static HRESULT register_interfaces(struct regsvr_interface const *list); +static HRESULT unregister_interfaces(struct regsvr_interface const *list); + +struct regsvr_coclass +{ + CLSID const *clsid; /* NULL for end of list */ + LPCSTR name; /* can be NULL to omit */ + LPCSTR ips; /* can be NULL to omit */ + LPCSTR ips32; /* can be NULL to omit */ + LPCSTR ips32_tmodel; /* can be NULL to omit */ + LPCSTR clsid_str; /* can be NULL to omit */ + LPCSTR progid; /* can be NULL to omit */ +}; + +static HRESULT register_coclasses(struct regsvr_coclass const *list); +static HRESULT unregister_coclasses(struct regsvr_coclass const *list); + +/*********************************************************************** + * static string constants + */ +static WCHAR const interface_keyname[10] = { + 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 }; +static WCHAR const base_ifa_keyname[14] = { + 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', + 'e', 0 }; +static WCHAR const num_methods_keyname[11] = { + 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 }; +static WCHAR const ps_clsid_keyname[15] = { + 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', + 'i', 'd', 0 }; +static WCHAR const ps_clsid32_keyname[17] = { + 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', + 'i', 'd', '3', '2', 0 }; +static WCHAR const clsid_keyname[6] = { + 'C', 'L', 'S', 'I', 'D', 0 }; +static WCHAR const ips_keyname[13] = { + 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', + 0 }; +static WCHAR const ips32_keyname[15] = { + 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', + '3', '2', 0 }; +static WCHAR const progid_keyname[7] = { + 'P', 'r', 'o', 'g', 'I', 'D', 0 }; +static char const tmodel_valuename[] = "ThreadingModel"; + +/*********************************************************************** + * static helper functions + */ +static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid); +static LONG register_key_defvalueW(HKEY base, WCHAR const *name, + WCHAR const *value); +static LONG register_key_defvalueA(HKEY base, WCHAR const *name, + char const *value); +static LONG recursive_delete_key(HKEY key); +static LONG recursive_delete_keyA(HKEY base, char const *name); +static LONG recursive_delete_keyW(HKEY base, WCHAR const *name); + +/*********************************************************************** + * register_interfaces + */ +static HRESULT register_interfaces(struct regsvr_interface const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY interface_key; + + res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &interface_key, NULL); + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->iid; ++list) { + WCHAR buf[39]; + HKEY iid_key; + + StringFromGUID2(list->iid, buf, 39); + res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &iid_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_interface_key; + + if (list->name) { + res = RegSetValueExA(iid_key, NULL, 0, REG_SZ, + (CONST BYTE*)(list->name), + strlen(list->name) + 1); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->base_iid) { + register_key_guid(iid_key, base_ifa_keyname, list->base_iid); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (0 <= list->num_methods) { + static WCHAR const fmt[3] = { '%', 'd', 0 }; + HKEY key; + + res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + + wsprintfW(buf, fmt, list->num_methods); + res = RegSetValueExW(key, NULL, 0, REG_SZ, + (CONST BYTE*)buf, + (lstrlenW(buf) + 1) * sizeof(WCHAR)); + RegCloseKey(key); + + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->ps_clsid) { + register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->ps_clsid32) { + register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + error_close_iid_key: + RegCloseKey(iid_key); + } + +error_close_interface_key: + RegCloseKey(interface_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * unregister_interfaces + */ +static HRESULT unregister_interfaces(struct regsvr_interface const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY interface_key; + + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, + KEY_READ | KEY_WRITE, &interface_key); + if (res == ERROR_FILE_NOT_FOUND) return S_OK; + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->iid; ++list) { + WCHAR buf[39]; + + StringFromGUID2(list->iid, buf, 39); + res = recursive_delete_keyW(interface_key, buf); + } + + RegCloseKey(interface_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * register_coclasses + */ +static HRESULT register_coclasses(struct regsvr_coclass const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY coclass_key; + + res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL); + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->clsid; ++list) { + WCHAR buf[39]; + HKEY clsid_key; + + StringFromGUID2(list->clsid, buf, 39); + res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + + if (list->name) { + res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ, + (CONST BYTE*)(list->name), + strlen(list->name) + 1); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->ips) { + res = register_key_defvalueA(clsid_key, ips_keyname, list->ips); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->ips32) { + HKEY ips32_key; + + res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, + &ips32_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ, + (CONST BYTE*)list->ips32, + lstrlenA(list->ips32) + 1); + if (res == ERROR_SUCCESS && list->ips32_tmodel) + res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ, + (CONST BYTE*)list->ips32_tmodel, + strlen(list->ips32_tmodel) + 1); + RegCloseKey(ips32_key); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->clsid_str) { + res = register_key_defvalueA(clsid_key, clsid_keyname, + list->clsid_str); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->progid) { + HKEY progid_key; + + res = register_key_defvalueA(clsid_key, progid_keyname, + list->progid); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = RegCreateKeyExA(HKEY_CLASSES_ROOT, list->progid, 0, + NULL, 0, KEY_READ | KEY_WRITE, NULL, + &progid_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = register_key_defvalueW(progid_key, clsid_keyname, buf); + RegCloseKey(progid_key); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + error_close_clsid_key: + RegCloseKey(clsid_key); + } + +error_close_coclass_key: + RegCloseKey(coclass_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * unregister_coclasses + */ +static HRESULT unregister_coclasses(struct regsvr_coclass const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY coclass_key; + + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, + KEY_READ | KEY_WRITE, &coclass_key); + if (res == ERROR_FILE_NOT_FOUND) return S_OK; + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->clsid; ++list) { + WCHAR buf[39]; + + StringFromGUID2(list->clsid, buf, 39); + res = recursive_delete_keyW(coclass_key, buf); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + + if (list->progid) { + res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + } + } + +error_close_coclass_key: + RegCloseKey(coclass_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * regsvr_key_guid + */ +static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) +{ + WCHAR buf[39]; + + StringFromGUID2(guid, buf, 39); + return register_key_defvalueW(base, name, buf); +} + +/*********************************************************************** + * regsvr_key_defvalueW + */ +static LONG register_key_defvalueW( + HKEY base, + WCHAR const *name, + WCHAR const *value) +{ + LONG res; + HKEY key; + + res = RegCreateKeyExW(base, name, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) return res; + res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value, + (lstrlenW(value) + 1) * sizeof(WCHAR)); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * regsvr_key_defvalueA + */ +static LONG register_key_defvalueA( + HKEY base, + WCHAR const *name, + char const *value) +{ + LONG res; + HKEY key; + + res = RegCreateKeyExW(base, name, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) return res; + res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value, + lstrlenA(value) + 1); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * recursive_delete_key + */ +static LONG recursive_delete_key(HKEY key) +{ + LONG res; + WCHAR subkey_name[MAX_PATH]; + DWORD cName; + HKEY subkey; + + for (;;) { + cName = sizeof(subkey_name) / sizeof(WCHAR); + res = RegEnumKeyExW(key, 0, subkey_name, &cName, + NULL, NULL, NULL, NULL); + if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) { + res = ERROR_SUCCESS; /* presumably we're done enumerating */ + break; + } + res = RegOpenKeyExW(key, subkey_name, 0, + KEY_READ | KEY_WRITE, &subkey); + if (res == ERROR_FILE_NOT_FOUND) continue; + if (res != ERROR_SUCCESS) break; + + res = recursive_delete_key(subkey); + RegCloseKey(subkey); + if (res != ERROR_SUCCESS) break; + } + + if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0); + return res; +} + +/*********************************************************************** + * recursive_delete_keyA + */ +static LONG recursive_delete_keyA(HKEY base, char const *name) +{ + LONG res; + HKEY key; + + res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key); + if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; + if (res != ERROR_SUCCESS) return res; + res = recursive_delete_key(key); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * recursive_delete_keyW + */ +static LONG recursive_delete_keyW(HKEY base, WCHAR const *name) +{ + LONG res; + HKEY key; + + res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key); + if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; + if (res != ERROR_SUCCESS) return res; + res = recursive_delete_key(key); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * coclass list + */ +static GUID const CLSID_RecordInfo = { + 0x0000002F, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; + +extern GUID const CLSID_PSDispatch; + +static GUID const CLSID_PSEnumVariant = { + 0x00020421, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; + +static GUID const CLSID_PSTypeInfo = { + 0x00020422, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; + +static GUID const CLSID_PSTypeLib = { + 0x00020423, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; + +extern GUID const CLSID_PSOAInterface; + +static GUID const CLSID_PSTypeComp = { + 0x00020425, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} }; + +static GUID const CLSID_OldFont = { + 0x46763EE0, 0xCAB2, 0x11CE, {0x8C,0x20,0x00,0xAA,0x00,0x51,0xE5,0xD4} }; + +static GUID const CLSID_PSFactoryBuffer = { + 0xB196B286, 0xBAB4, 0x101A, {0xB6,0x9C,0x00,0xAA,0x00,0x34,0x1D,0x07} }; + +static struct regsvr_coclass const coclass_list[] = { + { &CLSID_RecordInfo, + "CLSID_RecordInfo", + NULL, + "oleaut32.dll", + "Both" + }, + { &CLSID_PSDispatch, + "PSDispatch", + "ole2disp.dll", + "oleaut32.dll", + "Both" + }, + { &CLSID_StdFont, + "CLSID_StdFont", + NULL, + "oleaut32.dll", + "Both", + "Standard Font", + "StdFont" + }, + { &CLSID_StdPicture, + "CLSID_StdPict", + NULL, + "oleaut32.dll", + "Apartment", + "Standard Picture", + "StdPicture" + }, + { &CLSID_PSEnumVariant, + "PSEnumVariant", + "ole2disp.dll", + "oleaut32.dll", + "Both" + }, + { &CLSID_PSTypeInfo, + "PSTypeInfo", + "ole2disp.dll", + "oleaut32.dll", + "Both" + }, + { &CLSID_PSTypeLib, + "PSTypeLib", + "ole2disp.dll", + "oleaut32.dll", + "Both" + }, + { &CLSID_PSOAInterface, + "PSOAInterface", + "ole2disp.dll", + "oleaut32.dll", + "Both" + }, + { &CLSID_PSTypeComp, + "PSTypeComp", + "ole2disp.dll", + "oleaut32.dll", + "Both" + }, + { &CLSID_OldFont, + "Obsolete Font", + NULL, + "oleaut32.dll", + NULL, + "Obsolete Font", + "OldFont" + }, + { &CLSID_PSFactoryBuffer, + "PSFactoryBuffer", + NULL, + "oleaut32.dll", + "Both" + }, + { NULL } /* list terminator */ +}; + +/*********************************************************************** + * interface list + */ + +/* FIXME: these interfaces should be defined in ocidl.idl */ + +static IID const IID_IFontEventsDisp = { + 0x4EF6100A, 0xAF88, 0x11D0, {0x98,0x46,0x00,0xC0,0x4F,0xC2,0x99,0x93} }; + +static IID const IID_IProvideMultipleClassInfo = { + 0xA7ABA9C1, 0x8983, 0x11CF, {0x8F,0x20,0x00,0x80,0x5F,0x2C,0xD0,0x64} }; + +static struct regsvr_interface const interface_list[] = { + { &IID_IDispatch, + "IDispatch", + NULL, + 7, + &CLSID_PSDispatch, + &CLSID_PSDispatch + }, + { &IID_ITypeInfo, + "ITypeInfo", + NULL, + 22, + NULL, + &CLSID_PSTypeInfo + }, + { &IID_ITypeLib, + "ITypeLib", + NULL, + 13, + NULL, + &CLSID_PSTypeLib + }, + { &IID_ITypeComp, + "ITypeComp", + NULL, + 5, + NULL, + &CLSID_PSTypeComp + }, + { &IID_IEnumVARIANT, + "IEnumVARIANT", + NULL, + 15, + NULL, + &CLSID_PSEnumVariant + }, + { &IID_ICreateTypeInfo, + "ICreateTypeInfo", + NULL, + 26, + NULL, + NULL + }, + { &IID_ICreateTypeLib, + "ICreateTypeLib", + NULL, + 13, + NULL, + NULL + }, + { &IID_ITypeInfo2, + "ITypeInfo2", + NULL, + 32, + NULL, + &CLSID_PSDispatch + }, + { &IID_ITypeLib2, + "ITypeLib2", + NULL, + 16, + NULL, + &CLSID_PSDispatch + }, + { &IID_IPropertyPage2, + "IPropertyPage2", + NULL, + 15, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IErrorInfo, + "IErrorInfo", + NULL, + 8, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_ICreateErrorInfo, + "ICreateErrorInfo", + NULL, + 8, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IPersistPropertyBag2, + "IPersistPropertyBag2", + NULL, + 8, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IPropertyBag2, + "IPropertyBag2", + NULL, + 8, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IErrorLog, + "IErrorLog", + NULL, + 4, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IPerPropertyBrowsing, + "IPerPropertyBrowsing", + NULL, + 7, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IPersistPropertyBag, + "IPersistPropertyBag", + NULL, + 7, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IAdviseSinkEx, + "IAdviseSinkEx", + NULL, + 9, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IFontEventsDisp, + "IFontEventsDisp", + NULL, + 7, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IPropertyBag, + "IPropertyBag", + NULL, + 5, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IPointerInactive, + "IPointerInactive", + NULL, + 6, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_ISimpleFrameSite, + "ISimpleFrameSite", + NULL, + 5, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IPicture, + "IPicture", + NULL, + 17, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IPictureDisp, + "IPictureDisp", + NULL, + 7, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IPersistStreamInit, + "IPersistStreamInit", + NULL, + 9, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IOleUndoUnit, + "IOleUndoUnit", + NULL, + 7, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IPropertyNotifySink, + "IPropertyNotifySink", + NULL, + 5, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IOleInPlaceSiteEx, + "IOleInPlaceSiteEx", + NULL, + 18, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IOleParentUndoUnit, + "IOleParentUndoUnit", + NULL, + 12, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IProvideClassInfo2, + "IProvideClassInfo2", + NULL, + 5, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IProvideMultipleClassInfo, + "IProvideMultipleClassInfo", + NULL, + 7, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IProvideClassInfo, + "IProvideClassInfo", + NULL, + 4, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IConnectionPointContainer, + "IConnectionPointContainer", + NULL, + 5, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IEnumConnectionPoints, + "IEnumConnectionPoints", + NULL, + 7, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IConnectionPoint, + "IConnectionPoint", + NULL, + 8, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IEnumConnections, + "IEnumConnections", + NULL, + 7, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IOleControl, + "IOleControl", + NULL, + 7, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IOleControlSite, + "IOleControlSite", + NULL, + 10, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_ISpecifyPropertyPages, + "ISpecifyPropertyPages", + NULL, + 4, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IPropertyPageSite, + "IPropertyPageSite", + NULL, + 7, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IPropertyPage, + "IPropertyPage", + NULL, + 14, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IClassFactory2, + "IClassFactory2", + NULL, + 8, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IEnumOleUndoUnits, + "IEnumOleUndoUnits", + NULL, + 7, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IPersistMemory, + "IPersistMemory", + NULL, + 9, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IFont, + "IFont", + NULL, + 27, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IFontDisp, + "IFontDisp", + NULL, + 7, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IQuickActivate, + "IQuickActivate", + NULL, + 6, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IOleUndoManager, + "IOleUndoManager", + NULL, + 15, + NULL, + &CLSID_PSFactoryBuffer + }, + { &IID_IObjectWithSite, + "IObjectWithSite", + NULL, + 5, + NULL, + &CLSID_PSFactoryBuffer + }, + { NULL } /* list terminator */ +}; + +/*********************************************************************** + * DllRegisterServer (OLEAUT32.320) + */ +HRESULT WINAPI OLEAUT32_DllRegisterServer() +{ + HRESULT hr; + + TRACE("\n"); + + hr = register_coclasses(coclass_list); + if (SUCCEEDED(hr)) + hr = register_interfaces(interface_list); + return hr; +} + +/*********************************************************************** + * DllUnregisterServer (OLEAUT32.321) + */ +HRESULT WINAPI OLEAUT32_DllUnregisterServer() +{ + HRESULT hr; + + TRACE("\n"); + + hr = unregister_coclasses(coclass_list); + if (SUCCEEDED(hr)) + hr = unregister_interfaces(interface_list); + return hr; +} diff --git a/reactos/lib/oleaut32/resource.h b/reactos/lib/oleaut32/resource.h index b3adfe623c7..ab0ffc1c54f 100644 --- a/reactos/lib/oleaut32/resource.h +++ b/reactos/lib/oleaut32/resource.h @@ -1,46 +1,46 @@ -/* - * Resource defines for oleaut32 - * - * Copyright 2003 Jon Griffiths - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef WINE_OLEAUT32_RESOURCE_H -#define WINE_OLEAUT32_RESOURCE_H - -/* Localised boolean text */ -#define IDS_TRUE 100 -#define IDS_FALSE 101 -#define IDS_YES 102 -#define IDS_NO 103 -#define IDS_ON 104 -#define IDS_OFF 105 -/* Alternative month names. Note in XP these are localised only for Russian, - * Polish and Arabic. - */ -#define IDS_MTH_1 106 -#define IDS_MTH_2 107 -#define IDS_MTH_3 108 -#define IDS_MTH_4 109 -#define IDS_MTH_5 110 -#define IDS_MTH_6 111 -#define IDS_MTH_7 112 -#define IDS_MTH_8 113 -#define IDS_MTH_9 114 -#define IDS_MTH_10 115 -#define IDS_MTH_11 116 -#define IDS_MTH_12 117 - -#endif /* WINE_OLEAUT32_RESOURCE_H */ +/* + * Resource defines for oleaut32 + * + * Copyright 2003 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef WINE_OLEAUT32_RESOURCE_H +#define WINE_OLEAUT32_RESOURCE_H + +/* Localised boolean text */ +#define IDS_TRUE 100 +#define IDS_FALSE 101 +#define IDS_YES 102 +#define IDS_NO 103 +#define IDS_ON 104 +#define IDS_OFF 105 +/* Alternative month names. Note in XP these are localised only for Russian, + * Polish and Arabic. + */ +#define IDS_MTH_1 106 +#define IDS_MTH_2 107 +#define IDS_MTH_3 108 +#define IDS_MTH_4 109 +#define IDS_MTH_5 110 +#define IDS_MTH_6 111 +#define IDS_MTH_7 112 +#define IDS_MTH_8 113 +#define IDS_MTH_9 114 +#define IDS_MTH_10 115 +#define IDS_MTH_11 116 +#define IDS_MTH_12 117 + +#endif /* WINE_OLEAUT32_RESOURCE_H */ diff --git a/reactos/lib/oleaut32/safearray.c b/reactos/lib/oleaut32/safearray.c index 90bcf6464d5..e984895acaa 100644 --- a/reactos/lib/oleaut32/safearray.c +++ b/reactos/lib/oleaut32/safearray.c @@ -1,1734 +1,1734 @@ -/************************************************************************* - * OLE Automation - SafeArray - * - * This file contains the implementation of the SafeArray functions. - * - * Copyright 1999 Sylvain St-Germain - * Copyright 2002-2003 Marcus Meissner - * Copyright 2003 Jon Griffiths - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -/* Memory Layout of a SafeArray: - * - * -0x10: start of memory. - * -0x10: GUID for VT_DISPATCH and VT_UNKNOWN safearrays (if FADF_HAVEIID) - * -0x04: DWORD varianttype; (for all others, except VT_RECORD) (if FADF_HAVEVARTYPE) - * -0x4: IRecordInfo* iface; (if FADF_RECORD, for VT_RECORD (can be NULL)) - * 0x00: SAFEARRAY, - * 0x10: SAFEARRAYBOUNDS[0...] - */ - -#include "config.h" - -#include <string.h> -#include <stdarg.h> -#include <stdio.h> - -#define COBJMACROS - -#include "windef.h" -#include "winerror.h" -#include "winbase.h" -#include "variant.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(variant); - -/************************************************************************ - * SafeArray {OLEAUT32} - * - * NOTES - * The SafeArray data type provides the underlying interface for Ole - * Automations arrays, used for example to represent array types in - * Visual Basic(tm) and to gather user defined parameters for invocation through - * an IDispatch interface. - * - * Safe arrays provide bounds checking and automatically manage the data - * types they contain, for example handing reference counting and copying - * of interface pointers. User defined types can be stored in arrays - * using the IRecordInfo interface. - * - * There are two types of SafeArray, normal and vectors. Normal arrays can have - * multiple dimensions and the data for the array is allocated separately from - * the array header. This is the most flexible type of array. Vectors, on the - * other hand, are fixed in size and consist of a single allocated block, and a - * single dimension. - * - * DATATYPES - * The following types of data can be stored within a SafeArray. - * Numeric: - *| VT_I1, VT_UI1, VT_I2, VT_UI2, VT_I4, VT_UI4, VT_I8, VT_UI8, VT_INT, VT_UINT, - *| VT_R4, VT_R8, VT_CY, VT_DECIMAL - * Interfaces: - *| VT_DISPATCH, VT_UNKNOWN, VT_RECORD - * Other: - *| VT_VARIANT, VT_INT_PTR, VT_UINT_PTR, VT_BOOL, VT_ERROR, VT_DATE, VT_BSTR - * - * FUNCTIONS - * BstrFromVector() - * VectorFromBstr() - */ - -/* Undocumented hidden space before the start of a SafeArray descriptor */ -#define SAFEARRAY_HIDDEN_SIZE sizeof(GUID) - -/* Allocate memory */ -static inline LPVOID SAFEARRAY_Malloc(ULONG ulSize) -{ - /* FIXME: Memory should be allocated and freed using a per-thread IMalloc - * instance returned from CoGetMalloc(). - */ - return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ulSize); -} - -/* Free memory */ -static inline BOOL SAFEARRAY_Free(LPVOID lpData) -{ - return HeapFree(GetProcessHeap(), 0, lpData); -} - -/* Get the size of a supported VT type (0 means unsupported) */ -static DWORD SAFEARRAY_GetVTSize(VARTYPE vt) -{ - switch (vt) - { - case VT_I1: - case VT_UI1: return sizeof(BYTE); - case VT_BOOL: - case VT_I2: - case VT_UI2: return sizeof(SHORT); - case VT_I4: - case VT_UI4: - case VT_R4: - case VT_ERROR: return sizeof(LONG); - case VT_R8: - case VT_I8: - case VT_UI8: return sizeof(LONG64); - case VT_INT: - case VT_UINT: return sizeof(INT); - case VT_INT_PTR: - case VT_UINT_PTR: return sizeof(UINT_PTR); - case VT_CY: return sizeof(CY); - case VT_DATE: return sizeof(DATE); - case VT_BSTR: return sizeof(BSTR); - case VT_DISPATCH: return sizeof(LPDISPATCH); - case VT_VARIANT: return sizeof(VARIANT); - case VT_UNKNOWN: return sizeof(LPUNKNOWN); - case VT_DECIMAL: return sizeof(DECIMAL); - /* Note: Return a non-zero size to indicate vt is valid. The actual size - * of a UDT is taken from the result of IRecordInfo_GetSize(). - */ - case VT_RECORD: return 32; - } - return 0; -} - -/* Set the hidden data for an array */ -static inline void SAFEARRAY_SetHiddenDWORD(SAFEARRAY* psa, DWORD dw) -{ - /* Implementation data is stored in the 4 bytes before the header */ - LPDWORD lpDw = (LPDWORD)psa; - lpDw[-1] = dw; -} - -/* Get the hidden data from an array */ -static inline DWORD SAFEARRAY_GetHiddenDWORD(SAFEARRAY* psa) -{ - LPDWORD lpDw = (LPDWORD)psa; - return lpDw[-1]; -} - -/* Get the number of cells in a SafeArray */ -static ULONG SAFEARRAY_GetCellCount(const SAFEARRAY *psa) -{ - const SAFEARRAYBOUND* psab = psa->rgsabound; - USHORT cCount = psa->cDims; - ULONG ulNumCells = 1; - - while (cCount--) - { - /* This is a valid bordercase. See testcases. -Marcus */ - if (!psab->cElements) - return 0; - ulNumCells *= psab->cElements; - psab++; - } - return ulNumCells; -} - -/* Get the 0 based index of an index into a dimension */ -static inline ULONG SAFEARRAY_GetDimensionIndex(SAFEARRAYBOUND *psab, ULONG ulIndex) -{ - return ulIndex - psab->lLbound; -} - -/* Get the size of a dimension in cells */ -static inline ULONG SAFEARRAY_GetDimensionCells(SAFEARRAY *psa, ULONG ulDim) -{ - ULONG size = psa->rgsabound[0].cElements; - - while (ulDim) - { - size *= psa->rgsabound[ulDim].cElements; - ulDim--; - } - return size; -} - -/* Allocate a descriptor for an array */ -static HRESULT SAFEARRAY_AllocDescriptor(ULONG ulSize, SAFEARRAY **ppsaOut) -{ - *ppsaOut = (SAFEARRAY*)((char*)SAFEARRAY_Malloc(ulSize + SAFEARRAY_HIDDEN_SIZE) + SAFEARRAY_HIDDEN_SIZE); - - if (!*ppsaOut) - return E_UNEXPECTED; - - return S_OK; -} - -/* Set the features of an array */ -static void SAFEARRAY_SetFeatures(VARTYPE vt, SAFEARRAY *psa) -{ - /* Set the IID if we have one, otherwise set the type */ - if (vt == VT_DISPATCH) - { - psa->fFeatures = FADF_HAVEIID; - SafeArraySetIID(psa, &IID_IDispatch); - } - else if (vt == VT_UNKNOWN) - { - psa->fFeatures = FADF_HAVEIID; - SafeArraySetIID(psa, &IID_IUnknown); - } - else if (vt == VT_RECORD) - psa->fFeatures = FADF_RECORD; - else - { - psa->fFeatures = FADF_HAVEVARTYPE; - SAFEARRAY_SetHiddenDWORD(psa, vt); - } -} - -/* Create an array */ -static SAFEARRAY* SAFEARRAY_Create(VARTYPE vt, UINT cDims, SAFEARRAYBOUND *rgsabound, ULONG ulSize) -{ - SAFEARRAY *psa = NULL; - - if (!rgsabound) - return NULL; - - if (SUCCEEDED(SafeArrayAllocDescriptorEx(vt, cDims, &psa))) - { - switch (vt) - { - case VT_BSTR: psa->fFeatures |= FADF_BSTR; break; - case VT_UNKNOWN: psa->fFeatures |= FADF_UNKNOWN; break; - case VT_DISPATCH: psa->fFeatures |= FADF_DISPATCH; break; - case VT_VARIANT: psa->fFeatures |= FADF_VARIANT; break; - } - - memcpy(psa->rgsabound, rgsabound, cDims * sizeof(SAFEARRAYBOUND)); - - if (ulSize) - psa->cbElements = ulSize; - - if (FAILED(SafeArrayAllocData(psa))) - { - SafeArrayDestroyDescriptor(psa); - psa = NULL; - } - } - return psa; -} - -/* Create an array as a vector */ -static SAFEARRAY* SAFEARRAY_CreateVector(VARTYPE vt, LONG lLbound, ULONG cElements, ULONG ulSize) -{ - SAFEARRAY *psa = NULL; - - if (ulSize || (vt == VT_RECORD)) - { - /* Allocate the header and data together */ - if (SUCCEEDED(SAFEARRAY_AllocDescriptor(sizeof(SAFEARRAY) + ulSize * cElements, &psa))) - { - SAFEARRAY_SetFeatures(vt, psa); - - psa->cDims = 1; - psa->fFeatures |= FADF_CREATEVECTOR; - psa->pvData = &psa[1]; /* Data follows the header */ - psa->cbElements = ulSize; - psa->rgsabound[0].cElements = cElements; - psa->rgsabound[0].lLbound = lLbound; - - switch (vt) - { - case VT_BSTR: psa->fFeatures |= FADF_BSTR; break; - case VT_UNKNOWN: psa->fFeatures |= FADF_UNKNOWN; break; - case VT_DISPATCH: psa->fFeatures |= FADF_DISPATCH; break; - case VT_VARIANT: psa->fFeatures |= FADF_VARIANT; break; - } - } - } - return psa; -} - -/* Free data items in an array */ -static HRESULT SAFEARRAY_DestroyData(SAFEARRAY *psa, ULONG ulStartCell) -{ - if (psa->pvData && !(psa->fFeatures & FADF_DATADELETED)) - { - ULONG ulCellCount = SAFEARRAY_GetCellCount(psa); - - if (ulStartCell > ulCellCount) { - FIXME("unexpted ulcellcount %ld, start %ld\n",ulCellCount,ulStartCell); - return E_UNEXPECTED; - } - - ulCellCount -= ulStartCell; - - if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH)) - { - LPUNKNOWN *lpUnknown = (LPUNKNOWN *)psa->pvData + ulStartCell * psa->cbElements; - - while(ulCellCount--) - { - if (*lpUnknown) - IUnknown_Release(*lpUnknown); - lpUnknown++; - } - } - else if (psa->fFeatures & (FADF_RECORD)) - { - IRecordInfo *lpRecInfo; - - if (SUCCEEDED(SafeArrayGetRecordInfo(psa, &lpRecInfo))) - { - PBYTE pRecordData = (PBYTE)psa->pvData; - while(ulCellCount--) - { - IRecordInfo_RecordClear(lpRecInfo, pRecordData); - pRecordData += psa->cbElements; - } - IRecordInfo_Release(lpRecInfo); - } - } - else if (psa->fFeatures & FADF_BSTR) - { - BSTR* lpBstr = (BSTR*)psa->pvData + ulStartCell * psa->cbElements; - - while(ulCellCount--) - { - if (*lpBstr) - SysFreeString(*lpBstr); - lpBstr++; - } - } - else if (psa->fFeatures & FADF_VARIANT) - { - VARIANT* lpVariant = (VARIANT*)psa->pvData + ulStartCell * psa->cbElements; - - while(ulCellCount--) - { - HRESULT hRet = VariantClear(lpVariant); - - if (FAILED(hRet)) FIXME("VariantClear of element failed!\n"); - lpVariant++; - } - } - } - return S_OK; -} - -/* Copy data items from one array to another */ -static HRESULT SAFEARRAY_CopyData(SAFEARRAY *psa, SAFEARRAY *dest) -{ - if (!psa->pvData || !dest->pvData || psa->fFeatures & FADF_DATADELETED) - return E_INVALIDARG; - else - { - ULONG ulCellCount = SAFEARRAY_GetCellCount(psa); - - dest->fFeatures = (dest->fFeatures & FADF_CREATEVECTOR) | - (psa->fFeatures & ~(FADF_CREATEVECTOR|FADF_DATADELETED)); - - if (psa->fFeatures & FADF_VARIANT) - { - VARIANT* lpVariant = (VARIANT*)psa->pvData; - VARIANT* lpDest = (VARIANT*)dest->pvData; - - while(ulCellCount--) - { - HRESULT hRet; - - hRet = VariantCopy(lpDest, lpVariant); - if (FAILED(hRet)) FIXME("VariantCopy failed with 0x%lx\n", hRet); - lpVariant++; - lpDest++; - } - } - else if (psa->fFeatures & FADF_BSTR) - { - BSTR* lpBstr = (BSTR*)psa->pvData; - BSTR* lpDest = (BSTR*)dest->pvData; - - while(ulCellCount--) - { - if (*lpBstr) - { - *lpDest = SysAllocStringByteLen((char*)*lpBstr, SysStringByteLen(*lpBstr)); - if (!*lpDest) - return E_OUTOFMEMORY; - } - else - *lpDest = NULL; - lpBstr++; - lpDest++; - } - } - else - { - /* Copy the data over */ - memcpy(dest->pvData, psa->pvData, ulCellCount * psa->cbElements); - - if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH)) - { - LPUNKNOWN *lpUnknown = (LPUNKNOWN *)dest->pvData; - - while(ulCellCount--) - { - if (*lpUnknown) - IUnknown_AddRef(*lpUnknown); - lpUnknown++; - } - } - } - - if (psa->fFeatures & FADF_RECORD) - { - IRecordInfo* pRecInfo = NULL; - - SafeArrayGetRecordInfo(psa, &pRecInfo); - SafeArraySetRecordInfo(dest, pRecInfo); - - if (pRecInfo) - { - /* Release because Get() adds a reference */ - IRecordInfo_Release(pRecInfo); - } - } - else if (psa->fFeatures & FADF_HAVEIID) - { - GUID guid; - SafeArrayGetIID(psa, &guid); - SafeArraySetIID(dest, &guid); - } - else if (psa->fFeatures & FADF_HAVEVARTYPE) - { - SAFEARRAY_SetHiddenDWORD(dest, SAFEARRAY_GetHiddenDWORD(psa)); - } - } - return S_OK; -} - -/************************************************************************* - * SafeArrayAllocDescriptor (OLEAUT32.36) - * - * Allocate and initialise a descriptor for a SafeArray. - * - * PARAMS - * cDims [I] Number of dimensions of the array - * ppsaOut [O] Destination for new descriptor - * - * RETURNS - * Success: S_OK. ppsaOut is filled with a newly allocated descriptor. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI SafeArrayAllocDescriptor(UINT cDims, SAFEARRAY **ppsaOut) -{ - LONG allocSize; - - TRACE("(%d,%p)\n", cDims, ppsaOut); - - if (!cDims || cDims >= 0x10000) /* Maximum 65535 dimensions */ - return E_INVALIDARG; - - if (!ppsaOut) - return E_POINTER; - - /* We need enough space for the header and its bounds */ - allocSize = sizeof(SAFEARRAY) + sizeof(SAFEARRAYBOUND) * (cDims - 1); - - if (FAILED(SAFEARRAY_AllocDescriptor(allocSize, ppsaOut))) - return E_UNEXPECTED; - - (*ppsaOut)->cDims = cDims; - - TRACE("(%d): %lu bytes allocated for descriptor.\n", cDims, allocSize); - return S_OK; -} - -/************************************************************************* - * SafeArrayAllocDescriptorEx (OLEAUT32.41) - * - * Allocate and initialise a descriptor for a SafeArray of a given type. - * - * PARAMS - * vt [I] The type of items to store in the array - * cDims [I] Number of dimensions of the array - * ppsaOut [O] Destination for new descriptor - * - * RETURNS - * Success: S_OK. ppsaOut is filled with a newly allocated descriptor. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * - This function does not chack that vt is an allowed VARTYPE. - * - Unlike SafeArrayAllocDescriptor(), vt is associated with the array. - * See SafeArray. - */ -HRESULT WINAPI SafeArrayAllocDescriptorEx(VARTYPE vt, UINT cDims, SAFEARRAY **ppsaOut) -{ - ULONG cbElements; - HRESULT hRet = E_UNEXPECTED; - - TRACE("(%d->%s,%d,%p)\n", vt, debugstr_vt(vt), cDims, ppsaOut); - - cbElements = SAFEARRAY_GetVTSize(vt); - if (!cbElements) - WARN("Creating a descriptor with an invalid VARTYPE!\n"); - - hRet = SafeArrayAllocDescriptor(cDims, ppsaOut); - - if (SUCCEEDED(hRet)) - { - SAFEARRAY_SetFeatures(vt, *ppsaOut); - (*ppsaOut)->cbElements = cbElements; - } - return hRet; -} - -/************************************************************************* - * SafeArrayAllocData (OLEAUT32.37) - * - * Allocate the data area of a SafeArray. - * - * PARAMS - * psa [I] SafeArray to allocate the data area of. - * - * RETURNS - * Success: S_OK. The data area is allocated and initialised. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI SafeArrayAllocData(SAFEARRAY *psa) -{ - HRESULT hRet = E_INVALIDARG; - - TRACE("(%p)\n", psa); - - if (psa) - { - ULONG ulSize = SAFEARRAY_GetCellCount(psa); - - hRet = E_OUTOFMEMORY; - - if (psa->cbElements) - { - psa->pvData = SAFEARRAY_Malloc(ulSize * psa->cbElements); - - if (psa->pvData) - { - hRet = S_OK; - TRACE("%lu bytes allocated for data at %p (%lu objects).\n", - ulSize * psa->cbElements, psa->pvData, ulSize); - } - } - } - return hRet; -} - -/************************************************************************* - * SafeArrayCreate (OLEAUT32.15) - * - * Create a new SafeArray. - * - * PARAMS - * vt [I] Type to store in the safe array - * cDims [I] Number of array dimensions - * rgsabound [I] Bounds of the array dimensions - * - * RETURNS - * Success: A pointer to a new array object. - * Failure: NULL, if any parameter is invalid or memory allocation fails. - * - * NOTES - * Win32 allows arrays with 0 sized dimensions. This bug is not reproduced - * in the Wine implementation. - * See SafeArray. - */ -SAFEARRAY* WINAPI SafeArrayCreate(VARTYPE vt, UINT cDims, SAFEARRAYBOUND *rgsabound) -{ - TRACE("(%d->%s,%d,%p)\n", vt, debugstr_vt(vt), cDims, rgsabound); - - if (vt == VT_RECORD) - return NULL; - - return SAFEARRAY_Create(vt, cDims, rgsabound, 0); -} - -/************************************************************************* - * SafeArrayCreateEx (OLEAUT32.15) - * - * Create a new SafeArray. - * - * PARAMS - * vt [I] Type to store in the safe array - * cDims [I] Number of array dimensions - * rgsabound [I] Bounds of the array dimensions - * pvExtra [I] Extra data - * - * RETURNS - * Success: A pointer to a new array object. - * Failure: NULL, if any parameter is invalid or memory allocation fails. - * - * NOTES - * See SafeArray. - */ -SAFEARRAY* WINAPI SafeArrayCreateEx(VARTYPE vt, UINT cDims, SAFEARRAYBOUND *rgsabound, LPVOID pvExtra) -{ - ULONG ulSize = 0; - IRecordInfo* iRecInfo = (IRecordInfo*)pvExtra; - SAFEARRAY* psa; - - TRACE("(%d->%s,%d,%p,%p)\n", vt, debugstr_vt(vt), cDims, rgsabound, pvExtra); - - if (vt == VT_RECORD) - { - if (!iRecInfo) - return NULL; - IRecordInfo_GetSize(iRecInfo, &ulSize); - } - psa = SAFEARRAY_Create(vt, cDims, rgsabound, ulSize); - - if (pvExtra) - { - switch(vt) - { - case VT_RECORD: - SafeArraySetRecordInfo(psa, pvExtra); - break; - case VT_UNKNOWN: - case VT_DISPATCH: - SafeArraySetIID(psa, pvExtra); - break; - } - } - return psa; -} - -/************************************************************************ - * SafeArrayCreateVector (OLEAUT32.411) - * - * Create a one dimensional, contiguous SafeArray. - * - * PARAMS - * vt [I] Type to store in the safe array - * lLbound [I] Lower bound of the array - * cElements [I] Number of elements in the array - * - * RETURNS - * Success: A pointer to a new array object. - * Failure: NULL, if any parameter is invalid or memory allocation fails. - * - * NOTES - * See SafeArray. - */ -SAFEARRAY* WINAPI SafeArrayCreateVector(VARTYPE vt, LONG lLbound, ULONG cElements) -{ - TRACE("(%d->%s,%ld,%ld\n", vt, debugstr_vt(vt), lLbound, cElements); - - if (vt == VT_RECORD) - return NULL; - - return SAFEARRAY_CreateVector(vt, lLbound, cElements, SAFEARRAY_GetVTSize(vt)); -} - -/************************************************************************ - * SafeArrayCreateVectorEx (OLEAUT32.411) - * - * Create a one dimensional, contiguous SafeArray. - * - * PARAMS - * vt [I] Type to store in the safe array - * lLbound [I] Lower bound of the array - * cElements [I] Number of elements in the array - * pvExtra [I] Extra data - * - * RETURNS - * Success: A pointer to a new array object. - * Failure: NULL, if any parameter is invalid or memory allocation fails. - * - * NOTES - * See SafeArray. - */ -SAFEARRAY* WINAPI SafeArrayCreateVectorEx(VARTYPE vt, LONG lLbound, ULONG cElements, LPVOID pvExtra) -{ - ULONG ulSize; - IRecordInfo* iRecInfo = (IRecordInfo*)pvExtra; - SAFEARRAY* psa; - - TRACE("(%d->%s,%ld,%ld,%p\n", vt, debugstr_vt(vt), lLbound, cElements, pvExtra); - - if (vt == VT_RECORD) - { - if (!iRecInfo) - return NULL; - IRecordInfo_GetSize(iRecInfo, &ulSize); - } - else - ulSize = SAFEARRAY_GetVTSize(vt); - - psa = SAFEARRAY_CreateVector(vt, lLbound, cElements, ulSize); - - if (pvExtra) - { - switch(vt) - { - case VT_RECORD: - SafeArraySetRecordInfo(psa, iRecInfo); - break; - case VT_UNKNOWN: - case VT_DISPATCH: - SafeArraySetIID(psa, pvExtra); - break; - } - } - return psa; -} - -/************************************************************************* - * SafeArrayDestroyDescriptor (OLEAUT32.38) - * - * Destroy a SafeArray. - * - * PARAMS - * psa [I] SafeArray to destroy. - * - * RETURNS - * Success: S_OK. The resources used by the array are freed. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI SafeArrayDestroyDescriptor(SAFEARRAY *psa) -{ - TRACE("(%p)\n", psa); - - if (psa) - { - LPVOID lpv = (char*)psa - SAFEARRAY_HIDDEN_SIZE; - - if (psa->cLocks) - return DISP_E_ARRAYISLOCKED; /* Can't destroy a locked array */ - - if (psa->fFeatures & FADF_RECORD) - SafeArraySetRecordInfo(psa, NULL); - - if (psa->fFeatures & FADF_CREATEVECTOR && - !(psa->fFeatures & FADF_DATADELETED)) - SAFEARRAY_DestroyData(psa, 0); /* Data not previously deleted */ - - if (!SAFEARRAY_Free(lpv)) - return E_UNEXPECTED; - } - return S_OK; -} - -/************************************************************************* - * SafeArrayLock (OLEAUT32.21) - * - * Increment the lock counter of a SafeArray. - * - * PARAMS - * psa [O] SafeArray to lock - * - * RETURNS - * Success: S_OK. The array lock is incremented. - * Failure: E_INVALIDARG if psa is NULL, or E_UNEXPECTED if too many locks - * are held on the array at once. - * - * NOTES - * In Win32 these locks are not thread safe. - * See SafeArray. - */ -HRESULT WINAPI SafeArrayLock(SAFEARRAY *psa) -{ - ULONG ulLocks; - - TRACE("(%p)\n", psa); - - if (!psa) - return E_INVALIDARG; - - ulLocks = InterlockedIncrement(&psa->cLocks); - - if (ulLocks > 0xffff) /* Maximum of 16384 locks at a time */ - { - WARN("Out of locks!\n"); - InterlockedDecrement(&psa->cLocks); - return E_UNEXPECTED; - } - return S_OK; -} - -/************************************************************************* - * SafeArrayUnlock (OLEAUT32.22) - * - * Decrement the lock counter of a SafeArray. - * - * PARAMS - * psa [O] SafeArray to unlock - * - * RETURNS - * Success: S_OK. The array lock is decremented. - * Failure: E_INVALIDARG if psa is NULL, or E_UNEXPECTED if no locks are - * held on the array. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI SafeArrayUnlock(SAFEARRAY *psa) -{ - TRACE("(%p)\n", psa); - - if (!psa) - return E_INVALIDARG; - - if ((LONG)InterlockedDecrement(&psa->cLocks) < 0) - { - WARN("Unlocked but no lock held!\n"); - InterlockedIncrement(&psa->cLocks); - return E_UNEXPECTED; - } - return S_OK; -} - -/************************************************************************* - * SafeArrayPutElement (OLEAUT32.26) - * - * Put an item into a SafeArray. - * - * PARAMS - * psa [I] SafeArray to insert into - * rgIndices [I] Indices to insert at - * pvData [I] Data to insert - * - * RETURNS - * Success: S_OK. The item is inserted - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI SafeArrayPutElement(SAFEARRAY *psa, LONG *rgIndices, void *pvData) -{ - HRESULT hRet; - - TRACE("(%p,%p,%p)\n", psa, rgIndices, pvData); - - if (!psa || !rgIndices) - return E_INVALIDARG; - - if (!pvData) - { - ERR("Invalid pvData would crash under Win32!\n"); - return E_INVALIDARG; - } - - hRet = SafeArrayLock(psa); - - if (SUCCEEDED(hRet)) - { - PVOID lpvDest; - - hRet = SafeArrayPtrOfIndex(psa, rgIndices, &lpvDest); - - if (SUCCEEDED(hRet)) - { - if (psa->fFeatures & FADF_VARIANT) - { - VARIANT* lpVariant = (VARIANT*)pvData; - VARIANT* lpDest = (VARIANT*)lpvDest; - - hRet = VariantClear(lpDest); - if (FAILED(hRet)) FIXME("VariantClear failed with 0x%lx\n", hRet); - hRet = VariantCopy(lpDest, lpVariant); - if (FAILED(hRet)) FIXME("VariantCopy failed with 0x%lx\n", hRet); - } - else if (psa->fFeatures & FADF_BSTR) - { - BSTR lpBstr = (BSTR)pvData; - BSTR* lpDest = (BSTR*)lpvDest; - - if (*lpDest) - SysFreeString(*lpDest); - - if (lpBstr) - { - *lpDest = SysAllocStringByteLen((char*)lpBstr, SysStringByteLen(lpBstr)); - if (!*lpDest) - hRet = E_OUTOFMEMORY; - } - else - *lpDest = NULL; - } - else - { - if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH)) - { - LPUNKNOWN lpUnknown = (LPUNKNOWN)pvData; - LPUNKNOWN *lpDest = (LPUNKNOWN *)lpvDest; - - if (lpUnknown) - IUnknown_AddRef(lpUnknown); - if (*lpDest) - IUnknown_Release(*lpDest); - *lpDest = lpUnknown; - } else { - /* Copy the data over */ - memcpy(lpvDest, pvData, psa->cbElements); - } - } - } - SafeArrayUnlock(psa); - } - return hRet; -} - - -/************************************************************************* - * SafeArrayGetElement (OLEAUT32.25) - * - * Get an item from a SafeArray. - * - * PARAMS - * psa [I] SafeArray to get from - * rgIndices [I] Indices to get from - * pvData [O] Destination for data - * - * RETURNS - * Success: S_OK. The item data is returned in pvData. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI SafeArrayGetElement(SAFEARRAY *psa, LONG *rgIndices, void *pvData) -{ - HRESULT hRet; - - TRACE("(%p,%p,%p)\n", psa, rgIndices, pvData); - - if (!psa || !rgIndices || !pvData) - return E_INVALIDARG; - - hRet = SafeArrayLock(psa); - - if (SUCCEEDED(hRet)) - { - PVOID lpvSrc; - - hRet = SafeArrayPtrOfIndex(psa, rgIndices, &lpvSrc); - - if (SUCCEEDED(hRet)) - { - if (psa->fFeatures & FADF_VARIANT) - { - VARIANT* lpVariant = (VARIANT*)lpvSrc; - VARIANT* lpDest = (VARIANT*)pvData; - - /* The original content of pvData is ignored. */ - V_VT(lpDest) = VT_EMPTY; - hRet = VariantCopy(lpDest, lpVariant); - if (FAILED(hRet)) FIXME("VariantCopy failed with 0x%lx\n", hRet); - } - else if (psa->fFeatures & FADF_BSTR) - { - BSTR* lpBstr = (BSTR*)lpvSrc; - BSTR* lpDest = (BSTR*)pvData; - - if (*lpBstr) - { - *lpDest = SysAllocStringByteLen((char*)*lpBstr, SysStringByteLen(*lpBstr)); - if (!*lpBstr) - hRet = E_OUTOFMEMORY; - } - else - *lpDest = NULL; - } - else - { - if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH)) - { - LPUNKNOWN *lpUnknown = (LPUNKNOWN *)lpvSrc; - - if (*lpUnknown) - IUnknown_AddRef(*lpUnknown); - } - /* Copy the data over */ - memcpy(pvData, lpvSrc, psa->cbElements); - } - } - SafeArrayUnlock(psa); - } - return hRet; -} - -/************************************************************************* - * SafeArrayGetUBound (OLEAUT32.19) - * - * Get the upper bound for a given SafeArray dimension - * - * PARAMS - * psa [I] Array to get dimension upper bound from - * nDim [I] The dimension number to get the upper bound of - * plUbound [O] Destination for the upper bound - * - * RETURNS - * Success: S_OK. plUbound contains the dimensions upper bound. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI SafeArrayGetUBound(SAFEARRAY *psa, UINT nDim, LONG *plUbound) -{ - TRACE("(%p,%d,%p)\n", psa, nDim, plUbound); - - if (!psa || !plUbound) - return E_INVALIDARG; - - if(!nDim || nDim > psa->cDims) - return DISP_E_BADINDEX; - - *plUbound = psa->rgsabound[nDim - 1].lLbound + - psa->rgsabound[nDim - 1].cElements - 1; - - return S_OK; -} - -/************************************************************************* - * SafeArrayGetLBound (OLEAUT32.20) - * - * Get the lower bound for a given SafeArray dimension - * - * PARAMS - * psa [I] Array to get dimension lower bound from - * nDim [I] The dimension number to get the lowe bound of - * plLbound [O] Destination for the lower bound - * - * RETURNS - * Success: S_OK. plUbound contains the dimensions lower bound. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI SafeArrayGetLBound(SAFEARRAY *psa, UINT nDim, LONG *plLbound) -{ - TRACE("(%p,%d,%p)\n", psa, nDim, plLbound); - - if (!psa || !plLbound) - return E_INVALIDARG; - - if(!nDim || nDim > psa->cDims) - return DISP_E_BADINDEX; - - *plLbound = psa->rgsabound[nDim - 1].lLbound; - return S_OK; -} - -/************************************************************************* - * SafeArrayGetDim (OLEAUT32.17) - * - * Get the number of dimensions in a SafeArray. - * - * PARAMS - * psa [I] Array to get the dimensions of - * - * RETURNS - * The number of array dimensions in psa, or 0 if psa is NULL. - * - * NOTES - * See SafeArray. - */ -UINT WINAPI SafeArrayGetDim(SAFEARRAY *psa) -{ - TRACE("(%p) returning %ld\n", psa, psa ? psa->cDims : 0ul); - return psa ? psa->cDims : 0; -} - -/************************************************************************* - * SafeArrayGetElemsize (OLEAUT32.18) - * - * Get the size of an element in a SafeArray. - * - * PARAMS - * psa [I] Array to get the element size from - * - * RETURNS - * The size of a single element in psa, or 0 if psa is NULL. - * - * NOTES - * See SafeArray. - */ -UINT WINAPI SafeArrayGetElemsize(SAFEARRAY *psa) -{ - TRACE("(%p) returning %ld\n", psa, psa ? psa->cbElements : 0ul); - return psa ? psa->cbElements : 0; -} - -/************************************************************************* - * SafeArrayAccessData (OLEAUT32.23) - * - * Lock a SafeArray and return a pointer to its data. - * - * PARAMS - * psa [I] Array to get the data pointer from - * ppvData [O] Destination for the arrays data pointer - * - * RETURNS - * Success: S_OK. ppvData contains the arrays data pointer, and the array - * is locked. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI SafeArrayAccessData(SAFEARRAY *psa, void **ppvData) -{ - TRACE("(%p,%p)\n", psa, ppvData); - - if(!psa || !ppvData) - return E_INVALIDARG; - - if (SUCCEEDED(SafeArrayLock(psa))) - { - *ppvData = psa->pvData; - return S_OK; - } - *ppvData = NULL; - return E_UNEXPECTED; -} - - -/************************************************************************* - * SafeArrayUnaccessData (OLEAUT32.24) - * - * Unlock a SafeArray after accessing its data. - * - * PARAMS - * psa [I] Array to unlock - * - * RETURNS - * Success: S_OK. The array is unlocked. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI SafeArrayUnaccessData(SAFEARRAY *psa) -{ - TRACE("(%p)\n", psa); - return SafeArrayUnlock(psa); -} - -/************************************************************************ - * SafeArrayPtrOfIndex (OLEAUT32.148) - * - * Get the address of an item in a SafeArray. - * - * PARAMS - * psa [I] Array to get the items address from - * rgIndices [I] Index of the item in the array - * ppvData [O] Destination for item address - * - * RETURNS - * Success: S_OK. ppvData contains a pointer to the item. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * This function does not lock the array. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI SafeArrayPtrOfIndex(SAFEARRAY *psa, LONG *rgIndices, void **ppvData) -{ - USHORT dim; - ULONG cell = 0, dimensionSize = 1; - SAFEARRAYBOUND* psab; - LONG c1; - - TRACE("(%p,%p,%p)\n", psa, rgIndices, ppvData); - - /* The general formula for locating the cell number of an entry in an n - * dimensional array (where cn = coordinate in dimension dn) is: - * - * c1 + c2 * sizeof(d1) + c3 * sizeof(d2) ... + cn * sizeof(c(n-1)) - * - * We calculate the size of the last dimension at each step through the - * dimensions to avoid recursing to calculate the last dimensions size. - */ - if (!psa || !rgIndices || !ppvData) - return E_INVALIDARG; - - psab = psa->rgsabound; - c1 = *rgIndices++; - - if (c1 < psab->lLbound || c1 >= psab->lLbound + (LONG)psab->cElements) - return DISP_E_BADINDEX; /* Initial index out of bounds */ - - for (dim = 1; dim < psa->cDims; dim++) - { - dimensionSize *= psab->cElements; - - psab++; - - if (!psab->cElements || - *rgIndices < psab->lLbound || - *rgIndices >= psab->lLbound + (LONG)psab->cElements) - return DISP_E_BADINDEX; /* Index out of bounds */ - - cell += (*rgIndices - psab->lLbound) * dimensionSize; - rgIndices++; - } - - cell += (c1 - psa->rgsabound[0].lLbound); - - *ppvData = (char*)psa->pvData + cell * psa->cbElements; - return S_OK; -} - -/************************************************************************ - * SafeArrayDestroyData (OLEAUT32.39) - * - * Destroy the data associated with a SafeArray. - * - * PARAMS - * psa [I] Array to delete the data from - * - * RETURNS - * Success: S_OK. All items and the item data are freed. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI SafeArrayDestroyData(SAFEARRAY *psa) -{ - TRACE("(%p)\n", psa); - - if (!psa) - return E_INVALIDARG; - - if (psa->cLocks) - return DISP_E_ARRAYISLOCKED; /* Can't delete a locked array */ - - /* If static, keep pvData and don't free */ - if (psa->pvData && !(psa->fFeatures & FADF_STATIC)) - { - /* Delete the actual item data */ - if (FAILED(SAFEARRAY_DestroyData(psa, 0))) - return E_UNEXPECTED; - - /* If this is not a vector, free the data memory block */ - if (!(psa->fFeatures & FADF_CREATEVECTOR)) - { - if (!SAFEARRAY_Free(psa->pvData)) - return E_UNEXPECTED; - psa->pvData = NULL; - } - else - psa->fFeatures |= FADF_DATADELETED; /* Mark the data deleted */ - - } - return S_OK; -} - -/************************************************************************ - * SafeArrayCopyData (OLEAUT32.412) - * - * Copy all data from one SafeArray to another. - * - * PARAMS - * psaSource [I] Source for copy - * psaTarget [O] Destination for copy - * - * RETURNS - * Success: S_OK. psaTarget contains a copy of psaSource. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * The two arrays must have the same number of dimensions and elements. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI SafeArrayCopyData(SAFEARRAY *psaSource, SAFEARRAY *psaTarget) -{ - int dim; - - TRACE("(%p,%p)\n", psaSource, psaTarget); - - if (!psaSource || !psaTarget || - psaSource->cDims != psaTarget->cDims || - psaSource->cbElements != psaTarget->cbElements) - return E_INVALIDARG; - - /* Each dimension must be the same size */ - for (dim = psaSource->cDims - 1; dim >= 0 ; dim--) - if (psaSource->rgsabound[dim].cElements != - psaTarget->rgsabound[dim].cElements) - return E_INVALIDARG; - - if (SUCCEEDED(SAFEARRAY_DestroyData(psaTarget, 0)) && - SUCCEEDED(SAFEARRAY_CopyData(psaSource, psaTarget))) - return S_OK; - return E_UNEXPECTED; -} - -/************************************************************************ - * SafeArrayDestroy (OLEAUT32.16) - * - * Destroy a SafeArray. - * - * PARAMS - * psa [I] Array to destroy - * - * RETURNS - * Success: S_OK. All resources used by the array are freed. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI SafeArrayDestroy(SAFEARRAY *psa) -{ - TRACE("(%p)\n", psa); - - if(!psa) - return S_OK; - - if(psa->cLocks > 0) - return DISP_E_ARRAYISLOCKED; - - /* Native doesn't check to see if the free succeeds */ - SafeArrayDestroyData(psa); - SafeArrayDestroyDescriptor(psa); - return S_OK; -} - -/************************************************************************ - * SafeArrayCopy (OLEAUT32.27) - * - * Make a duplicate of a SafeArray. - * - * PARAMS - * psa [I] Source for copy - * ppsaOut [O] Destination for new copy - * - * RETURNS - * Success: S_OK. ppsaOut contains a copy of the array. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI SafeArrayCopy(SAFEARRAY *psa, SAFEARRAY **ppsaOut) -{ - HRESULT hRet; - - TRACE("(%p,%p)\n", psa, ppsaOut); - - if (!ppsaOut) - return E_INVALIDARG; - - *ppsaOut = NULL; - - if (!psa) - return S_OK; /* Handles copying of NULL arrays */ - - if (psa->fFeatures & (FADF_RECORD|FADF_HAVEIID|FADF_HAVEVARTYPE)) - { - VARTYPE vt; - if (FAILED(SafeArrayGetVartype(psa, &vt))) - hRet = E_UNEXPECTED; - else - hRet = SafeArrayAllocDescriptorEx(vt, psa->cDims, ppsaOut); - } - else - { - hRet = SafeArrayAllocDescriptor(psa->cDims, ppsaOut); - if (SUCCEEDED(hRet)) - { - (*ppsaOut)->fFeatures = psa->fFeatures & ~FADF_CREATEVECTOR; - (*ppsaOut)->cbElements = psa->cbElements; - } - } - - if (SUCCEEDED(hRet)) - { - /* Copy dimension bounds */ - memcpy((*ppsaOut)->rgsabound, psa->rgsabound, psa->cDims * sizeof(SAFEARRAYBOUND)); - - (*ppsaOut)->pvData = SAFEARRAY_Malloc(SAFEARRAY_GetCellCount(psa) * psa->cbElements); - - if ((*ppsaOut)->pvData) - { - hRet = SAFEARRAY_CopyData(psa, *ppsaOut); - - if (SUCCEEDED(hRet)) - return hRet; - - SAFEARRAY_Free((*ppsaOut)->pvData); - } - SafeArrayDestroyDescriptor(*ppsaOut); - } - *ppsaOut = NULL; - return hRet; -} - -/************************************************************************ - * SafeArrayRedim (OLEAUT32.40) - * - * Changes the characteristics of the last dimension of a SafeArray - * - * PARAMS - * psa [I] Array to change - * psabound [I] New bound details for the last dimension - * - * RETURNS - * Success: S_OK. psa is updated to reflect the new bounds. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI SafeArrayRedim(SAFEARRAY *psa, SAFEARRAYBOUND *psabound) -{ - SAFEARRAYBOUND *oldBounds; - - TRACE("(%p,%p)\n", psa, psabound); - - if (!psa || psa->fFeatures & FADF_FIXEDSIZE || !psabound) - return E_INVALIDARG; - - if (psa->cLocks > 0) - return DISP_E_ARRAYISLOCKED; - - if (FAILED(SafeArrayLock(psa))) - return E_UNEXPECTED; - - oldBounds = &psa->rgsabound[psa->cDims - 1]; - oldBounds->lLbound = psabound->lLbound; - - if (psabound->cElements != oldBounds->cElements) - { - if (psabound->cElements < oldBounds->cElements) - { - /* Shorten the final dimension. */ - ULONG ulStartCell = psa->cDims == 1 ? 0 : SAFEARRAY_GetDimensionCells(psa, psa->cDims - 1); - - ulStartCell += psabound->cElements; - SAFEARRAY_DestroyData(psa, ulStartCell); - } - else - { - /* Lengthen the final dimension */ - ULONG ulOldSize, ulNewSize; - PVOID pvNewData; - - ulOldSize = SAFEARRAY_GetCellCount(psa) * psa->cbElements; - if (ulOldSize) - ulNewSize = (ulOldSize / oldBounds->cElements) * psabound->cElements; - else { - int oldelems = oldBounds->cElements; - oldBounds->cElements = psabound->cElements; - ulNewSize = SAFEARRAY_GetCellCount(psa) * psa->cbElements; - oldBounds->cElements = oldelems; - } - - if (!(pvNewData = SAFEARRAY_Malloc(ulNewSize))) - { - SafeArrayUnlock(psa); - return E_UNEXPECTED; - } - - memcpy(pvNewData, psa->pvData, ulOldSize); - SAFEARRAY_Free(psa->pvData); - psa->pvData = pvNewData; - } - oldBounds->cElements = psabound->cElements; - } - - SafeArrayUnlock(psa); - return S_OK; -} - -/************************************************************************ - * SafeArrayGetVartype (OLEAUT32.77) - * - * Get the type of the items in a SafeArray. - * - * PARAMS - * psa [I] Array to get the type from - * pvt [O] Destination for the type - * - * RETURNS - * Success: S_OK. pvt contains the type of the items. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI SafeArrayGetVartype(SAFEARRAY* psa, VARTYPE* pvt) -{ - TRACE("(%p,%p)\n", psa, pvt); - - if (!psa || !pvt) - return E_INVALIDARG; - - if (psa->fFeatures & FADF_RECORD) - *pvt = VT_RECORD; - else if (psa->fFeatures & FADF_HAVEIID) - *pvt = VT_UNKNOWN; - else if (psa->fFeatures & FADF_HAVEVARTYPE) - { - VARTYPE vt = SAFEARRAY_GetHiddenDWORD(psa); - *pvt = vt; - } - else - return E_INVALIDARG; - - return S_OK; -} - -/************************************************************************ - * SafeArraySetRecordInfo (OLEAUT32.@) - * - * Set the record info for a SafeArray. - * - * PARAMS - * psa [I] Array to set the record info for - * pRinfo [I] Record info - * - * RETURNS - * Success: S_OK. The record info is stored with the array. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI SafeArraySetRecordInfo(SAFEARRAY *psa, IRecordInfo *pRinfo) -{ - IRecordInfo** dest = (IRecordInfo**)psa; - - TRACE("(%p,%p)\n", psa, pRinfo); - - if (!psa || !(psa->fFeatures & FADF_RECORD)) - return E_INVALIDARG; - - if (pRinfo) - IRecordInfo_AddRef(pRinfo); - - if (dest[-1]) - IRecordInfo_Release(dest[-1]); - - dest[-1] = pRinfo; - return S_OK; -} - -/************************************************************************ - * SafeArrayGetRecordInfo (OLEAUT32.@) - * - * Get the record info from a SafeArray. - * - * PARAMS - * psa [I] Array to get the record info from - * pRinfo [O] Destination for the record info - * - * RETURNS - * Success: S_OK. pRinfo contains the record info, or NULL if there was none. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI SafeArrayGetRecordInfo(SAFEARRAY *psa, IRecordInfo **pRinfo) -{ - IRecordInfo** src = (IRecordInfo**)psa; - - TRACE("(%p,%p)\n", psa, pRinfo); - - if (!psa || !pRinfo || !(psa->fFeatures & FADF_RECORD)) - return E_INVALIDARG; - - *pRinfo = src[-1]; - - if (*pRinfo) - IRecordInfo_AddRef(*pRinfo); - return S_OK; -} - -/************************************************************************ - * SafeArraySetIID (OLEAUT32.@) - * - * Set the IID for a SafeArray. - * - * PARAMS - * psa [I] Array to set the IID from - * guid [I] IID - * - * RETURNS - * Success: S_OK. The IID is stored with the array - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI SafeArraySetIID(SAFEARRAY *psa, REFGUID guid) -{ - GUID* dest = (GUID*)psa; - - TRACE("(%p,%s)\n", psa, debugstr_guid(guid)); - - if (!psa || !guid || !(psa->fFeatures & FADF_HAVEIID)) - return E_INVALIDARG; - - dest[-1] = *guid; - return S_OK; -} - -/************************************************************************ - * SafeArrayGetIID (OLEAUT32.@) - * - * Get the IID from a SafeArray. - * - * PARAMS - * psa [I] Array to get the ID from - * pGuid [O] Destination for the IID - * - * RETURNS - * Success: S_OK. pRinfo contains the IID, or NULL if there was none. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI SafeArrayGetIID(SAFEARRAY *psa, GUID *pGuid) -{ - GUID* src = (GUID*)psa; - - TRACE("(%p,%p)\n", psa, pGuid); - - if (!psa || !pGuid || !(psa->fFeatures & FADF_HAVEIID)) - return E_INVALIDARG; - - *pGuid = src[-1]; - return S_OK; -} - -/************************************************************************ - * VectorFromBstr (OLEAUT32.@) - * - * Create a SafeArray Vector from the bytes of a BSTR. - * - * PARAMS - * bstr [I] String to get bytes from - * ppsa [O] Destination for the array - * - * RETURNS - * Success: S_OK. ppsa contains the strings bytes as a VT_UI1 array. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI VectorFromBstr(BSTR bstr, SAFEARRAY **ppsa) -{ - SAFEARRAYBOUND sab; - - TRACE("(%p,%p)\n", bstr, ppsa); - - if (!ppsa) - return E_INVALIDARG; - - sab.lLbound = 0; - sab.cElements = SysStringByteLen(bstr); - - *ppsa = SAFEARRAY_Create(VT_UI1, 1, &sab, 0); - - if (*ppsa) - { - memcpy((*ppsa)->pvData, bstr, sab.cElements); - return S_OK; - } - return E_OUTOFMEMORY; -} - -/************************************************************************ - * BstrFromVector (OLEAUT32.@) - * - * Create a BSTR from a SafeArray. - * - * PARAMS - * psa [I] Source array - * pbstr [O] Destination for output BSTR - * - * RETURNS - * Success: S_OK. pbstr contains the arrays data. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * psa must be a 1 dimensional array of a 1 byte type. - * - * NOTES - * See SafeArray. - */ -HRESULT WINAPI BstrFromVector(SAFEARRAY *psa, BSTR *pbstr) -{ - TRACE("(%p,%p)\n", psa, pbstr); - - if (!pbstr) - return E_INVALIDARG; - - *pbstr = NULL; - - if (!psa || psa->cbElements != 1 || psa->cDims != 1) - return E_INVALIDARG; - - *pbstr = SysAllocStringByteLen(psa->pvData, psa->rgsabound[0].cElements); - if (!*pbstr) - return E_OUTOFMEMORY; - return S_OK; -} +/************************************************************************* + * OLE Automation - SafeArray + * + * This file contains the implementation of the SafeArray functions. + * + * Copyright 1999 Sylvain St-Germain + * Copyright 2002-2003 Marcus Meissner + * Copyright 2003 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* Memory Layout of a SafeArray: + * + * -0x10: start of memory. + * -0x10: GUID for VT_DISPATCH and VT_UNKNOWN safearrays (if FADF_HAVEIID) + * -0x04: DWORD varianttype; (for all others, except VT_RECORD) (if FADF_HAVEVARTYPE) + * -0x4: IRecordInfo* iface; (if FADF_RECORD, for VT_RECORD (can be NULL)) + * 0x00: SAFEARRAY, + * 0x10: SAFEARRAYBOUNDS[0...] + */ + +#include "config.h" + +#include <string.h> +#include <stdarg.h> +#include <stdio.h> + +#define COBJMACROS + +#include "windef.h" +#include "winerror.h" +#include "winbase.h" +#include "variant.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(variant); + +/************************************************************************ + * SafeArray {OLEAUT32} + * + * NOTES + * The SafeArray data type provides the underlying interface for Ole + * Automations arrays, used for example to represent array types in + * Visual Basic(tm) and to gather user defined parameters for invocation through + * an IDispatch interface. + * + * Safe arrays provide bounds checking and automatically manage the data + * types they contain, for example handing reference counting and copying + * of interface pointers. User defined types can be stored in arrays + * using the IRecordInfo interface. + * + * There are two types of SafeArray, normal and vectors. Normal arrays can have + * multiple dimensions and the data for the array is allocated separately from + * the array header. This is the most flexible type of array. Vectors, on the + * other hand, are fixed in size and consist of a single allocated block, and a + * single dimension. + * + * DATATYPES + * The following types of data can be stored within a SafeArray. + * Numeric: + *| VT_I1, VT_UI1, VT_I2, VT_UI2, VT_I4, VT_UI4, VT_I8, VT_UI8, VT_INT, VT_UINT, + *| VT_R4, VT_R8, VT_CY, VT_DECIMAL + * Interfaces: + *| VT_DISPATCH, VT_UNKNOWN, VT_RECORD + * Other: + *| VT_VARIANT, VT_INT_PTR, VT_UINT_PTR, VT_BOOL, VT_ERROR, VT_DATE, VT_BSTR + * + * FUNCTIONS + * BstrFromVector() + * VectorFromBstr() + */ + +/* Undocumented hidden space before the start of a SafeArray descriptor */ +#define SAFEARRAY_HIDDEN_SIZE sizeof(GUID) + +/* Allocate memory */ +static inline LPVOID SAFEARRAY_Malloc(ULONG ulSize) +{ + /* FIXME: Memory should be allocated and freed using a per-thread IMalloc + * instance returned from CoGetMalloc(). + */ + return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ulSize); +} + +/* Free memory */ +static inline BOOL SAFEARRAY_Free(LPVOID lpData) +{ + return HeapFree(GetProcessHeap(), 0, lpData); +} + +/* Get the size of a supported VT type (0 means unsupported) */ +static DWORD SAFEARRAY_GetVTSize(VARTYPE vt) +{ + switch (vt) + { + case VT_I1: + case VT_UI1: return sizeof(BYTE); + case VT_BOOL: + case VT_I2: + case VT_UI2: return sizeof(SHORT); + case VT_I4: + case VT_UI4: + case VT_R4: + case VT_ERROR: return sizeof(LONG); + case VT_R8: + case VT_I8: + case VT_UI8: return sizeof(LONG64); + case VT_INT: + case VT_UINT: return sizeof(INT); + case VT_INT_PTR: + case VT_UINT_PTR: return sizeof(UINT_PTR); + case VT_CY: return sizeof(CY); + case VT_DATE: return sizeof(DATE); + case VT_BSTR: return sizeof(BSTR); + case VT_DISPATCH: return sizeof(LPDISPATCH); + case VT_VARIANT: return sizeof(VARIANT); + case VT_UNKNOWN: return sizeof(LPUNKNOWN); + case VT_DECIMAL: return sizeof(DECIMAL); + /* Note: Return a non-zero size to indicate vt is valid. The actual size + * of a UDT is taken from the result of IRecordInfo_GetSize(). + */ + case VT_RECORD: return 32; + } + return 0; +} + +/* Set the hidden data for an array */ +static inline void SAFEARRAY_SetHiddenDWORD(SAFEARRAY* psa, DWORD dw) +{ + /* Implementation data is stored in the 4 bytes before the header */ + LPDWORD lpDw = (LPDWORD)psa; + lpDw[-1] = dw; +} + +/* Get the hidden data from an array */ +static inline DWORD SAFEARRAY_GetHiddenDWORD(SAFEARRAY* psa) +{ + LPDWORD lpDw = (LPDWORD)psa; + return lpDw[-1]; +} + +/* Get the number of cells in a SafeArray */ +static ULONG SAFEARRAY_GetCellCount(const SAFEARRAY *psa) +{ + const SAFEARRAYBOUND* psab = psa->rgsabound; + USHORT cCount = psa->cDims; + ULONG ulNumCells = 1; + + while (cCount--) + { + /* This is a valid bordercase. See testcases. -Marcus */ + if (!psab->cElements) + return 0; + ulNumCells *= psab->cElements; + psab++; + } + return ulNumCells; +} + +/* Get the 0 based index of an index into a dimension */ +static inline ULONG SAFEARRAY_GetDimensionIndex(SAFEARRAYBOUND *psab, ULONG ulIndex) +{ + return ulIndex - psab->lLbound; +} + +/* Get the size of a dimension in cells */ +static inline ULONG SAFEARRAY_GetDimensionCells(SAFEARRAY *psa, ULONG ulDim) +{ + ULONG size = psa->rgsabound[0].cElements; + + while (ulDim) + { + size *= psa->rgsabound[ulDim].cElements; + ulDim--; + } + return size; +} + +/* Allocate a descriptor for an array */ +static HRESULT SAFEARRAY_AllocDescriptor(ULONG ulSize, SAFEARRAY **ppsaOut) +{ + *ppsaOut = (SAFEARRAY*)((char*)SAFEARRAY_Malloc(ulSize + SAFEARRAY_HIDDEN_SIZE) + SAFEARRAY_HIDDEN_SIZE); + + if (!*ppsaOut) + return E_UNEXPECTED; + + return S_OK; +} + +/* Set the features of an array */ +static void SAFEARRAY_SetFeatures(VARTYPE vt, SAFEARRAY *psa) +{ + /* Set the IID if we have one, otherwise set the type */ + if (vt == VT_DISPATCH) + { + psa->fFeatures = FADF_HAVEIID; + SafeArraySetIID(psa, &IID_IDispatch); + } + else if (vt == VT_UNKNOWN) + { + psa->fFeatures = FADF_HAVEIID; + SafeArraySetIID(psa, &IID_IUnknown); + } + else if (vt == VT_RECORD) + psa->fFeatures = FADF_RECORD; + else + { + psa->fFeatures = FADF_HAVEVARTYPE; + SAFEARRAY_SetHiddenDWORD(psa, vt); + } +} + +/* Create an array */ +static SAFEARRAY* SAFEARRAY_Create(VARTYPE vt, UINT cDims, SAFEARRAYBOUND *rgsabound, ULONG ulSize) +{ + SAFEARRAY *psa = NULL; + + if (!rgsabound) + return NULL; + + if (SUCCEEDED(SafeArrayAllocDescriptorEx(vt, cDims, &psa))) + { + switch (vt) + { + case VT_BSTR: psa->fFeatures |= FADF_BSTR; break; + case VT_UNKNOWN: psa->fFeatures |= FADF_UNKNOWN; break; + case VT_DISPATCH: psa->fFeatures |= FADF_DISPATCH; break; + case VT_VARIANT: psa->fFeatures |= FADF_VARIANT; break; + } + + memcpy(psa->rgsabound, rgsabound, cDims * sizeof(SAFEARRAYBOUND)); + + if (ulSize) + psa->cbElements = ulSize; + + if (FAILED(SafeArrayAllocData(psa))) + { + SafeArrayDestroyDescriptor(psa); + psa = NULL; + } + } + return psa; +} + +/* Create an array as a vector */ +static SAFEARRAY* SAFEARRAY_CreateVector(VARTYPE vt, LONG lLbound, ULONG cElements, ULONG ulSize) +{ + SAFEARRAY *psa = NULL; + + if (ulSize || (vt == VT_RECORD)) + { + /* Allocate the header and data together */ + if (SUCCEEDED(SAFEARRAY_AllocDescriptor(sizeof(SAFEARRAY) + ulSize * cElements, &psa))) + { + SAFEARRAY_SetFeatures(vt, psa); + + psa->cDims = 1; + psa->fFeatures |= FADF_CREATEVECTOR; + psa->pvData = &psa[1]; /* Data follows the header */ + psa->cbElements = ulSize; + psa->rgsabound[0].cElements = cElements; + psa->rgsabound[0].lLbound = lLbound; + + switch (vt) + { + case VT_BSTR: psa->fFeatures |= FADF_BSTR; break; + case VT_UNKNOWN: psa->fFeatures |= FADF_UNKNOWN; break; + case VT_DISPATCH: psa->fFeatures |= FADF_DISPATCH; break; + case VT_VARIANT: psa->fFeatures |= FADF_VARIANT; break; + } + } + } + return psa; +} + +/* Free data items in an array */ +static HRESULT SAFEARRAY_DestroyData(SAFEARRAY *psa, ULONG ulStartCell) +{ + if (psa->pvData && !(psa->fFeatures & FADF_DATADELETED)) + { + ULONG ulCellCount = SAFEARRAY_GetCellCount(psa); + + if (ulStartCell > ulCellCount) { + FIXME("unexpted ulcellcount %ld, start %ld\n",ulCellCount,ulStartCell); + return E_UNEXPECTED; + } + + ulCellCount -= ulStartCell; + + if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH)) + { + LPUNKNOWN *lpUnknown = (LPUNKNOWN *)psa->pvData + ulStartCell * psa->cbElements; + + while(ulCellCount--) + { + if (*lpUnknown) + IUnknown_Release(*lpUnknown); + lpUnknown++; + } + } + else if (psa->fFeatures & (FADF_RECORD)) + { + IRecordInfo *lpRecInfo; + + if (SUCCEEDED(SafeArrayGetRecordInfo(psa, &lpRecInfo))) + { + PBYTE pRecordData = (PBYTE)psa->pvData; + while(ulCellCount--) + { + IRecordInfo_RecordClear(lpRecInfo, pRecordData); + pRecordData += psa->cbElements; + } + IRecordInfo_Release(lpRecInfo); + } + } + else if (psa->fFeatures & FADF_BSTR) + { + BSTR* lpBstr = (BSTR*)psa->pvData + ulStartCell * psa->cbElements; + + while(ulCellCount--) + { + if (*lpBstr) + SysFreeString(*lpBstr); + lpBstr++; + } + } + else if (psa->fFeatures & FADF_VARIANT) + { + VARIANT* lpVariant = (VARIANT*)psa->pvData + ulStartCell * psa->cbElements; + + while(ulCellCount--) + { + HRESULT hRet = VariantClear(lpVariant); + + if (FAILED(hRet)) FIXME("VariantClear of element failed!\n"); + lpVariant++; + } + } + } + return S_OK; +} + +/* Copy data items from one array to another */ +static HRESULT SAFEARRAY_CopyData(SAFEARRAY *psa, SAFEARRAY *dest) +{ + if (!psa->pvData || !dest->pvData || psa->fFeatures & FADF_DATADELETED) + return E_INVALIDARG; + else + { + ULONG ulCellCount = SAFEARRAY_GetCellCount(psa); + + dest->fFeatures = (dest->fFeatures & FADF_CREATEVECTOR) | + (psa->fFeatures & ~(FADF_CREATEVECTOR|FADF_DATADELETED)); + + if (psa->fFeatures & FADF_VARIANT) + { + VARIANT* lpVariant = (VARIANT*)psa->pvData; + VARIANT* lpDest = (VARIANT*)dest->pvData; + + while(ulCellCount--) + { + HRESULT hRet; + + hRet = VariantCopy(lpDest, lpVariant); + if (FAILED(hRet)) FIXME("VariantCopy failed with 0x%lx\n", hRet); + lpVariant++; + lpDest++; + } + } + else if (psa->fFeatures & FADF_BSTR) + { + BSTR* lpBstr = (BSTR*)psa->pvData; + BSTR* lpDest = (BSTR*)dest->pvData; + + while(ulCellCount--) + { + if (*lpBstr) + { + *lpDest = SysAllocStringByteLen((char*)*lpBstr, SysStringByteLen(*lpBstr)); + if (!*lpDest) + return E_OUTOFMEMORY; + } + else + *lpDest = NULL; + lpBstr++; + lpDest++; + } + } + else + { + /* Copy the data over */ + memcpy(dest->pvData, psa->pvData, ulCellCount * psa->cbElements); + + if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH)) + { + LPUNKNOWN *lpUnknown = (LPUNKNOWN *)dest->pvData; + + while(ulCellCount--) + { + if (*lpUnknown) + IUnknown_AddRef(*lpUnknown); + lpUnknown++; + } + } + } + + if (psa->fFeatures & FADF_RECORD) + { + IRecordInfo* pRecInfo = NULL; + + SafeArrayGetRecordInfo(psa, &pRecInfo); + SafeArraySetRecordInfo(dest, pRecInfo); + + if (pRecInfo) + { + /* Release because Get() adds a reference */ + IRecordInfo_Release(pRecInfo); + } + } + else if (psa->fFeatures & FADF_HAVEIID) + { + GUID guid; + SafeArrayGetIID(psa, &guid); + SafeArraySetIID(dest, &guid); + } + else if (psa->fFeatures & FADF_HAVEVARTYPE) + { + SAFEARRAY_SetHiddenDWORD(dest, SAFEARRAY_GetHiddenDWORD(psa)); + } + } + return S_OK; +} + +/************************************************************************* + * SafeArrayAllocDescriptor (OLEAUT32.36) + * + * Allocate and initialise a descriptor for a SafeArray. + * + * PARAMS + * cDims [I] Number of dimensions of the array + * ppsaOut [O] Destination for new descriptor + * + * RETURNS + * Success: S_OK. ppsaOut is filled with a newly allocated descriptor. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI SafeArrayAllocDescriptor(UINT cDims, SAFEARRAY **ppsaOut) +{ + LONG allocSize; + + TRACE("(%d,%p)\n", cDims, ppsaOut); + + if (!cDims || cDims >= 0x10000) /* Maximum 65535 dimensions */ + return E_INVALIDARG; + + if (!ppsaOut) + return E_POINTER; + + /* We need enough space for the header and its bounds */ + allocSize = sizeof(SAFEARRAY) + sizeof(SAFEARRAYBOUND) * (cDims - 1); + + if (FAILED(SAFEARRAY_AllocDescriptor(allocSize, ppsaOut))) + return E_UNEXPECTED; + + (*ppsaOut)->cDims = cDims; + + TRACE("(%d): %lu bytes allocated for descriptor.\n", cDims, allocSize); + return S_OK; +} + +/************************************************************************* + * SafeArrayAllocDescriptorEx (OLEAUT32.41) + * + * Allocate and initialise a descriptor for a SafeArray of a given type. + * + * PARAMS + * vt [I] The type of items to store in the array + * cDims [I] Number of dimensions of the array + * ppsaOut [O] Destination for new descriptor + * + * RETURNS + * Success: S_OK. ppsaOut is filled with a newly allocated descriptor. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * - This function does not chack that vt is an allowed VARTYPE. + * - Unlike SafeArrayAllocDescriptor(), vt is associated with the array. + * See SafeArray. + */ +HRESULT WINAPI SafeArrayAllocDescriptorEx(VARTYPE vt, UINT cDims, SAFEARRAY **ppsaOut) +{ + ULONG cbElements; + HRESULT hRet = E_UNEXPECTED; + + TRACE("(%d->%s,%d,%p)\n", vt, debugstr_vt(vt), cDims, ppsaOut); + + cbElements = SAFEARRAY_GetVTSize(vt); + if (!cbElements) + WARN("Creating a descriptor with an invalid VARTYPE!\n"); + + hRet = SafeArrayAllocDescriptor(cDims, ppsaOut); + + if (SUCCEEDED(hRet)) + { + SAFEARRAY_SetFeatures(vt, *ppsaOut); + (*ppsaOut)->cbElements = cbElements; + } + return hRet; +} + +/************************************************************************* + * SafeArrayAllocData (OLEAUT32.37) + * + * Allocate the data area of a SafeArray. + * + * PARAMS + * psa [I] SafeArray to allocate the data area of. + * + * RETURNS + * Success: S_OK. The data area is allocated and initialised. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI SafeArrayAllocData(SAFEARRAY *psa) +{ + HRESULT hRet = E_INVALIDARG; + + TRACE("(%p)\n", psa); + + if (psa) + { + ULONG ulSize = SAFEARRAY_GetCellCount(psa); + + hRet = E_OUTOFMEMORY; + + if (psa->cbElements) + { + psa->pvData = SAFEARRAY_Malloc(ulSize * psa->cbElements); + + if (psa->pvData) + { + hRet = S_OK; + TRACE("%lu bytes allocated for data at %p (%lu objects).\n", + ulSize * psa->cbElements, psa->pvData, ulSize); + } + } + } + return hRet; +} + +/************************************************************************* + * SafeArrayCreate (OLEAUT32.15) + * + * Create a new SafeArray. + * + * PARAMS + * vt [I] Type to store in the safe array + * cDims [I] Number of array dimensions + * rgsabound [I] Bounds of the array dimensions + * + * RETURNS + * Success: A pointer to a new array object. + * Failure: NULL, if any parameter is invalid or memory allocation fails. + * + * NOTES + * Win32 allows arrays with 0 sized dimensions. This bug is not reproduced + * in the Wine implementation. + * See SafeArray. + */ +SAFEARRAY* WINAPI SafeArrayCreate(VARTYPE vt, UINT cDims, SAFEARRAYBOUND *rgsabound) +{ + TRACE("(%d->%s,%d,%p)\n", vt, debugstr_vt(vt), cDims, rgsabound); + + if (vt == VT_RECORD) + return NULL; + + return SAFEARRAY_Create(vt, cDims, rgsabound, 0); +} + +/************************************************************************* + * SafeArrayCreateEx (OLEAUT32.15) + * + * Create a new SafeArray. + * + * PARAMS + * vt [I] Type to store in the safe array + * cDims [I] Number of array dimensions + * rgsabound [I] Bounds of the array dimensions + * pvExtra [I] Extra data + * + * RETURNS + * Success: A pointer to a new array object. + * Failure: NULL, if any parameter is invalid or memory allocation fails. + * + * NOTES + * See SafeArray. + */ +SAFEARRAY* WINAPI SafeArrayCreateEx(VARTYPE vt, UINT cDims, SAFEARRAYBOUND *rgsabound, LPVOID pvExtra) +{ + ULONG ulSize = 0; + IRecordInfo* iRecInfo = (IRecordInfo*)pvExtra; + SAFEARRAY* psa; + + TRACE("(%d->%s,%d,%p,%p)\n", vt, debugstr_vt(vt), cDims, rgsabound, pvExtra); + + if (vt == VT_RECORD) + { + if (!iRecInfo) + return NULL; + IRecordInfo_GetSize(iRecInfo, &ulSize); + } + psa = SAFEARRAY_Create(vt, cDims, rgsabound, ulSize); + + if (pvExtra) + { + switch(vt) + { + case VT_RECORD: + SafeArraySetRecordInfo(psa, pvExtra); + break; + case VT_UNKNOWN: + case VT_DISPATCH: + SafeArraySetIID(psa, pvExtra); + break; + } + } + return psa; +} + +/************************************************************************ + * SafeArrayCreateVector (OLEAUT32.411) + * + * Create a one dimensional, contiguous SafeArray. + * + * PARAMS + * vt [I] Type to store in the safe array + * lLbound [I] Lower bound of the array + * cElements [I] Number of elements in the array + * + * RETURNS + * Success: A pointer to a new array object. + * Failure: NULL, if any parameter is invalid or memory allocation fails. + * + * NOTES + * See SafeArray. + */ +SAFEARRAY* WINAPI SafeArrayCreateVector(VARTYPE vt, LONG lLbound, ULONG cElements) +{ + TRACE("(%d->%s,%ld,%ld\n", vt, debugstr_vt(vt), lLbound, cElements); + + if (vt == VT_RECORD) + return NULL; + + return SAFEARRAY_CreateVector(vt, lLbound, cElements, SAFEARRAY_GetVTSize(vt)); +} + +/************************************************************************ + * SafeArrayCreateVectorEx (OLEAUT32.411) + * + * Create a one dimensional, contiguous SafeArray. + * + * PARAMS + * vt [I] Type to store in the safe array + * lLbound [I] Lower bound of the array + * cElements [I] Number of elements in the array + * pvExtra [I] Extra data + * + * RETURNS + * Success: A pointer to a new array object. + * Failure: NULL, if any parameter is invalid or memory allocation fails. + * + * NOTES + * See SafeArray. + */ +SAFEARRAY* WINAPI SafeArrayCreateVectorEx(VARTYPE vt, LONG lLbound, ULONG cElements, LPVOID pvExtra) +{ + ULONG ulSize; + IRecordInfo* iRecInfo = (IRecordInfo*)pvExtra; + SAFEARRAY* psa; + + TRACE("(%d->%s,%ld,%ld,%p\n", vt, debugstr_vt(vt), lLbound, cElements, pvExtra); + + if (vt == VT_RECORD) + { + if (!iRecInfo) + return NULL; + IRecordInfo_GetSize(iRecInfo, &ulSize); + } + else + ulSize = SAFEARRAY_GetVTSize(vt); + + psa = SAFEARRAY_CreateVector(vt, lLbound, cElements, ulSize); + + if (pvExtra) + { + switch(vt) + { + case VT_RECORD: + SafeArraySetRecordInfo(psa, iRecInfo); + break; + case VT_UNKNOWN: + case VT_DISPATCH: + SafeArraySetIID(psa, pvExtra); + break; + } + } + return psa; +} + +/************************************************************************* + * SafeArrayDestroyDescriptor (OLEAUT32.38) + * + * Destroy a SafeArray. + * + * PARAMS + * psa [I] SafeArray to destroy. + * + * RETURNS + * Success: S_OK. The resources used by the array are freed. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI SafeArrayDestroyDescriptor(SAFEARRAY *psa) +{ + TRACE("(%p)\n", psa); + + if (psa) + { + LPVOID lpv = (char*)psa - SAFEARRAY_HIDDEN_SIZE; + + if (psa->cLocks) + return DISP_E_ARRAYISLOCKED; /* Can't destroy a locked array */ + + if (psa->fFeatures & FADF_RECORD) + SafeArraySetRecordInfo(psa, NULL); + + if (psa->fFeatures & FADF_CREATEVECTOR && + !(psa->fFeatures & FADF_DATADELETED)) + SAFEARRAY_DestroyData(psa, 0); /* Data not previously deleted */ + + if (!SAFEARRAY_Free(lpv)) + return E_UNEXPECTED; + } + return S_OK; +} + +/************************************************************************* + * SafeArrayLock (OLEAUT32.21) + * + * Increment the lock counter of a SafeArray. + * + * PARAMS + * psa [O] SafeArray to lock + * + * RETURNS + * Success: S_OK. The array lock is incremented. + * Failure: E_INVALIDARG if psa is NULL, or E_UNEXPECTED if too many locks + * are held on the array at once. + * + * NOTES + * In Win32 these locks are not thread safe. + * See SafeArray. + */ +HRESULT WINAPI SafeArrayLock(SAFEARRAY *psa) +{ + ULONG ulLocks; + + TRACE("(%p)\n", psa); + + if (!psa) + return E_INVALIDARG; + + ulLocks = InterlockedIncrement(&psa->cLocks); + + if (ulLocks > 0xffff) /* Maximum of 16384 locks at a time */ + { + WARN("Out of locks!\n"); + InterlockedDecrement(&psa->cLocks); + return E_UNEXPECTED; + } + return S_OK; +} + +/************************************************************************* + * SafeArrayUnlock (OLEAUT32.22) + * + * Decrement the lock counter of a SafeArray. + * + * PARAMS + * psa [O] SafeArray to unlock + * + * RETURNS + * Success: S_OK. The array lock is decremented. + * Failure: E_INVALIDARG if psa is NULL, or E_UNEXPECTED if no locks are + * held on the array. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI SafeArrayUnlock(SAFEARRAY *psa) +{ + TRACE("(%p)\n", psa); + + if (!psa) + return E_INVALIDARG; + + if ((LONG)InterlockedDecrement(&psa->cLocks) < 0) + { + WARN("Unlocked but no lock held!\n"); + InterlockedIncrement(&psa->cLocks); + return E_UNEXPECTED; + } + return S_OK; +} + +/************************************************************************* + * SafeArrayPutElement (OLEAUT32.26) + * + * Put an item into a SafeArray. + * + * PARAMS + * psa [I] SafeArray to insert into + * rgIndices [I] Indices to insert at + * pvData [I] Data to insert + * + * RETURNS + * Success: S_OK. The item is inserted + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI SafeArrayPutElement(SAFEARRAY *psa, LONG *rgIndices, void *pvData) +{ + HRESULT hRet; + + TRACE("(%p,%p,%p)\n", psa, rgIndices, pvData); + + if (!psa || !rgIndices) + return E_INVALIDARG; + + if (!pvData) + { + ERR("Invalid pvData would crash under Win32!\n"); + return E_INVALIDARG; + } + + hRet = SafeArrayLock(psa); + + if (SUCCEEDED(hRet)) + { + PVOID lpvDest; + + hRet = SafeArrayPtrOfIndex(psa, rgIndices, &lpvDest); + + if (SUCCEEDED(hRet)) + { + if (psa->fFeatures & FADF_VARIANT) + { + VARIANT* lpVariant = (VARIANT*)pvData; + VARIANT* lpDest = (VARIANT*)lpvDest; + + hRet = VariantClear(lpDest); + if (FAILED(hRet)) FIXME("VariantClear failed with 0x%lx\n", hRet); + hRet = VariantCopy(lpDest, lpVariant); + if (FAILED(hRet)) FIXME("VariantCopy failed with 0x%lx\n", hRet); + } + else if (psa->fFeatures & FADF_BSTR) + { + BSTR lpBstr = (BSTR)pvData; + BSTR* lpDest = (BSTR*)lpvDest; + + if (*lpDest) + SysFreeString(*lpDest); + + if (lpBstr) + { + *lpDest = SysAllocStringByteLen((char*)lpBstr, SysStringByteLen(lpBstr)); + if (!*lpDest) + hRet = E_OUTOFMEMORY; + } + else + *lpDest = NULL; + } + else + { + if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH)) + { + LPUNKNOWN lpUnknown = (LPUNKNOWN)pvData; + LPUNKNOWN *lpDest = (LPUNKNOWN *)lpvDest; + + if (lpUnknown) + IUnknown_AddRef(lpUnknown); + if (*lpDest) + IUnknown_Release(*lpDest); + *lpDest = lpUnknown; + } else { + /* Copy the data over */ + memcpy(lpvDest, pvData, psa->cbElements); + } + } + } + SafeArrayUnlock(psa); + } + return hRet; +} + + +/************************************************************************* + * SafeArrayGetElement (OLEAUT32.25) + * + * Get an item from a SafeArray. + * + * PARAMS + * psa [I] SafeArray to get from + * rgIndices [I] Indices to get from + * pvData [O] Destination for data + * + * RETURNS + * Success: S_OK. The item data is returned in pvData. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI SafeArrayGetElement(SAFEARRAY *psa, LONG *rgIndices, void *pvData) +{ + HRESULT hRet; + + TRACE("(%p,%p,%p)\n", psa, rgIndices, pvData); + + if (!psa || !rgIndices || !pvData) + return E_INVALIDARG; + + hRet = SafeArrayLock(psa); + + if (SUCCEEDED(hRet)) + { + PVOID lpvSrc; + + hRet = SafeArrayPtrOfIndex(psa, rgIndices, &lpvSrc); + + if (SUCCEEDED(hRet)) + { + if (psa->fFeatures & FADF_VARIANT) + { + VARIANT* lpVariant = (VARIANT*)lpvSrc; + VARIANT* lpDest = (VARIANT*)pvData; + + /* The original content of pvData is ignored. */ + V_VT(lpDest) = VT_EMPTY; + hRet = VariantCopy(lpDest, lpVariant); + if (FAILED(hRet)) FIXME("VariantCopy failed with 0x%lx\n", hRet); + } + else if (psa->fFeatures & FADF_BSTR) + { + BSTR* lpBstr = (BSTR*)lpvSrc; + BSTR* lpDest = (BSTR*)pvData; + + if (*lpBstr) + { + *lpDest = SysAllocStringByteLen((char*)*lpBstr, SysStringByteLen(*lpBstr)); + if (!*lpBstr) + hRet = E_OUTOFMEMORY; + } + else + *lpDest = NULL; + } + else + { + if (psa->fFeatures & (FADF_UNKNOWN|FADF_DISPATCH)) + { + LPUNKNOWN *lpUnknown = (LPUNKNOWN *)lpvSrc; + + if (*lpUnknown) + IUnknown_AddRef(*lpUnknown); + } + /* Copy the data over */ + memcpy(pvData, lpvSrc, psa->cbElements); + } + } + SafeArrayUnlock(psa); + } + return hRet; +} + +/************************************************************************* + * SafeArrayGetUBound (OLEAUT32.19) + * + * Get the upper bound for a given SafeArray dimension + * + * PARAMS + * psa [I] Array to get dimension upper bound from + * nDim [I] The dimension number to get the upper bound of + * plUbound [O] Destination for the upper bound + * + * RETURNS + * Success: S_OK. plUbound contains the dimensions upper bound. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI SafeArrayGetUBound(SAFEARRAY *psa, UINT nDim, LONG *plUbound) +{ + TRACE("(%p,%d,%p)\n", psa, nDim, plUbound); + + if (!psa || !plUbound) + return E_INVALIDARG; + + if(!nDim || nDim > psa->cDims) + return DISP_E_BADINDEX; + + *plUbound = psa->rgsabound[nDim - 1].lLbound + + psa->rgsabound[nDim - 1].cElements - 1; + + return S_OK; +} + +/************************************************************************* + * SafeArrayGetLBound (OLEAUT32.20) + * + * Get the lower bound for a given SafeArray dimension + * + * PARAMS + * psa [I] Array to get dimension lower bound from + * nDim [I] The dimension number to get the lowe bound of + * plLbound [O] Destination for the lower bound + * + * RETURNS + * Success: S_OK. plUbound contains the dimensions lower bound. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI SafeArrayGetLBound(SAFEARRAY *psa, UINT nDim, LONG *plLbound) +{ + TRACE("(%p,%d,%p)\n", psa, nDim, plLbound); + + if (!psa || !plLbound) + return E_INVALIDARG; + + if(!nDim || nDim > psa->cDims) + return DISP_E_BADINDEX; + + *plLbound = psa->rgsabound[nDim - 1].lLbound; + return S_OK; +} + +/************************************************************************* + * SafeArrayGetDim (OLEAUT32.17) + * + * Get the number of dimensions in a SafeArray. + * + * PARAMS + * psa [I] Array to get the dimensions of + * + * RETURNS + * The number of array dimensions in psa, or 0 if psa is NULL. + * + * NOTES + * See SafeArray. + */ +UINT WINAPI SafeArrayGetDim(SAFEARRAY *psa) +{ + TRACE("(%p) returning %ld\n", psa, psa ? psa->cDims : 0ul); + return psa ? psa->cDims : 0; +} + +/************************************************************************* + * SafeArrayGetElemsize (OLEAUT32.18) + * + * Get the size of an element in a SafeArray. + * + * PARAMS + * psa [I] Array to get the element size from + * + * RETURNS + * The size of a single element in psa, or 0 if psa is NULL. + * + * NOTES + * See SafeArray. + */ +UINT WINAPI SafeArrayGetElemsize(SAFEARRAY *psa) +{ + TRACE("(%p) returning %ld\n", psa, psa ? psa->cbElements : 0ul); + return psa ? psa->cbElements : 0; +} + +/************************************************************************* + * SafeArrayAccessData (OLEAUT32.23) + * + * Lock a SafeArray and return a pointer to its data. + * + * PARAMS + * psa [I] Array to get the data pointer from + * ppvData [O] Destination for the arrays data pointer + * + * RETURNS + * Success: S_OK. ppvData contains the arrays data pointer, and the array + * is locked. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI SafeArrayAccessData(SAFEARRAY *psa, void **ppvData) +{ + TRACE("(%p,%p)\n", psa, ppvData); + + if(!psa || !ppvData) + return E_INVALIDARG; + + if (SUCCEEDED(SafeArrayLock(psa))) + { + *ppvData = psa->pvData; + return S_OK; + } + *ppvData = NULL; + return E_UNEXPECTED; +} + + +/************************************************************************* + * SafeArrayUnaccessData (OLEAUT32.24) + * + * Unlock a SafeArray after accessing its data. + * + * PARAMS + * psa [I] Array to unlock + * + * RETURNS + * Success: S_OK. The array is unlocked. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI SafeArrayUnaccessData(SAFEARRAY *psa) +{ + TRACE("(%p)\n", psa); + return SafeArrayUnlock(psa); +} + +/************************************************************************ + * SafeArrayPtrOfIndex (OLEAUT32.148) + * + * Get the address of an item in a SafeArray. + * + * PARAMS + * psa [I] Array to get the items address from + * rgIndices [I] Index of the item in the array + * ppvData [O] Destination for item address + * + * RETURNS + * Success: S_OK. ppvData contains a pointer to the item. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * This function does not lock the array. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI SafeArrayPtrOfIndex(SAFEARRAY *psa, LONG *rgIndices, void **ppvData) +{ + USHORT dim; + ULONG cell = 0, dimensionSize = 1; + SAFEARRAYBOUND* psab; + LONG c1; + + TRACE("(%p,%p,%p)\n", psa, rgIndices, ppvData); + + /* The general formula for locating the cell number of an entry in an n + * dimensional array (where cn = coordinate in dimension dn) is: + * + * c1 + c2 * sizeof(d1) + c3 * sizeof(d2) ... + cn * sizeof(c(n-1)) + * + * We calculate the size of the last dimension at each step through the + * dimensions to avoid recursing to calculate the last dimensions size. + */ + if (!psa || !rgIndices || !ppvData) + return E_INVALIDARG; + + psab = psa->rgsabound; + c1 = *rgIndices++; + + if (c1 < psab->lLbound || c1 >= psab->lLbound + (LONG)psab->cElements) + return DISP_E_BADINDEX; /* Initial index out of bounds */ + + for (dim = 1; dim < psa->cDims; dim++) + { + dimensionSize *= psab->cElements; + + psab++; + + if (!psab->cElements || + *rgIndices < psab->lLbound || + *rgIndices >= psab->lLbound + (LONG)psab->cElements) + return DISP_E_BADINDEX; /* Index out of bounds */ + + cell += (*rgIndices - psab->lLbound) * dimensionSize; + rgIndices++; + } + + cell += (c1 - psa->rgsabound[0].lLbound); + + *ppvData = (char*)psa->pvData + cell * psa->cbElements; + return S_OK; +} + +/************************************************************************ + * SafeArrayDestroyData (OLEAUT32.39) + * + * Destroy the data associated with a SafeArray. + * + * PARAMS + * psa [I] Array to delete the data from + * + * RETURNS + * Success: S_OK. All items and the item data are freed. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI SafeArrayDestroyData(SAFEARRAY *psa) +{ + TRACE("(%p)\n", psa); + + if (!psa) + return E_INVALIDARG; + + if (psa->cLocks) + return DISP_E_ARRAYISLOCKED; /* Can't delete a locked array */ + + /* If static, keep pvData and don't free */ + if (psa->pvData && !(psa->fFeatures & FADF_STATIC)) + { + /* Delete the actual item data */ + if (FAILED(SAFEARRAY_DestroyData(psa, 0))) + return E_UNEXPECTED; + + /* If this is not a vector, free the data memory block */ + if (!(psa->fFeatures & FADF_CREATEVECTOR)) + { + if (!SAFEARRAY_Free(psa->pvData)) + return E_UNEXPECTED; + psa->pvData = NULL; + } + else + psa->fFeatures |= FADF_DATADELETED; /* Mark the data deleted */ + + } + return S_OK; +} + +/************************************************************************ + * SafeArrayCopyData (OLEAUT32.412) + * + * Copy all data from one SafeArray to another. + * + * PARAMS + * psaSource [I] Source for copy + * psaTarget [O] Destination for copy + * + * RETURNS + * Success: S_OK. psaTarget contains a copy of psaSource. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * The two arrays must have the same number of dimensions and elements. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI SafeArrayCopyData(SAFEARRAY *psaSource, SAFEARRAY *psaTarget) +{ + int dim; + + TRACE("(%p,%p)\n", psaSource, psaTarget); + + if (!psaSource || !psaTarget || + psaSource->cDims != psaTarget->cDims || + psaSource->cbElements != psaTarget->cbElements) + return E_INVALIDARG; + + /* Each dimension must be the same size */ + for (dim = psaSource->cDims - 1; dim >= 0 ; dim--) + if (psaSource->rgsabound[dim].cElements != + psaTarget->rgsabound[dim].cElements) + return E_INVALIDARG; + + if (SUCCEEDED(SAFEARRAY_DestroyData(psaTarget, 0)) && + SUCCEEDED(SAFEARRAY_CopyData(psaSource, psaTarget))) + return S_OK; + return E_UNEXPECTED; +} + +/************************************************************************ + * SafeArrayDestroy (OLEAUT32.16) + * + * Destroy a SafeArray. + * + * PARAMS + * psa [I] Array to destroy + * + * RETURNS + * Success: S_OK. All resources used by the array are freed. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI SafeArrayDestroy(SAFEARRAY *psa) +{ + TRACE("(%p)\n", psa); + + if(!psa) + return S_OK; + + if(psa->cLocks > 0) + return DISP_E_ARRAYISLOCKED; + + /* Native doesn't check to see if the free succeeds */ + SafeArrayDestroyData(psa); + SafeArrayDestroyDescriptor(psa); + return S_OK; +} + +/************************************************************************ + * SafeArrayCopy (OLEAUT32.27) + * + * Make a duplicate of a SafeArray. + * + * PARAMS + * psa [I] Source for copy + * ppsaOut [O] Destination for new copy + * + * RETURNS + * Success: S_OK. ppsaOut contains a copy of the array. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI SafeArrayCopy(SAFEARRAY *psa, SAFEARRAY **ppsaOut) +{ + HRESULT hRet; + + TRACE("(%p,%p)\n", psa, ppsaOut); + + if (!ppsaOut) + return E_INVALIDARG; + + *ppsaOut = NULL; + + if (!psa) + return S_OK; /* Handles copying of NULL arrays */ + + if (psa->fFeatures & (FADF_RECORD|FADF_HAVEIID|FADF_HAVEVARTYPE)) + { + VARTYPE vt; + if (FAILED(SafeArrayGetVartype(psa, &vt))) + hRet = E_UNEXPECTED; + else + hRet = SafeArrayAllocDescriptorEx(vt, psa->cDims, ppsaOut); + } + else + { + hRet = SafeArrayAllocDescriptor(psa->cDims, ppsaOut); + if (SUCCEEDED(hRet)) + { + (*ppsaOut)->fFeatures = psa->fFeatures & ~FADF_CREATEVECTOR; + (*ppsaOut)->cbElements = psa->cbElements; + } + } + + if (SUCCEEDED(hRet)) + { + /* Copy dimension bounds */ + memcpy((*ppsaOut)->rgsabound, psa->rgsabound, psa->cDims * sizeof(SAFEARRAYBOUND)); + + (*ppsaOut)->pvData = SAFEARRAY_Malloc(SAFEARRAY_GetCellCount(psa) * psa->cbElements); + + if ((*ppsaOut)->pvData) + { + hRet = SAFEARRAY_CopyData(psa, *ppsaOut); + + if (SUCCEEDED(hRet)) + return hRet; + + SAFEARRAY_Free((*ppsaOut)->pvData); + } + SafeArrayDestroyDescriptor(*ppsaOut); + } + *ppsaOut = NULL; + return hRet; +} + +/************************************************************************ + * SafeArrayRedim (OLEAUT32.40) + * + * Changes the characteristics of the last dimension of a SafeArray + * + * PARAMS + * psa [I] Array to change + * psabound [I] New bound details for the last dimension + * + * RETURNS + * Success: S_OK. psa is updated to reflect the new bounds. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI SafeArrayRedim(SAFEARRAY *psa, SAFEARRAYBOUND *psabound) +{ + SAFEARRAYBOUND *oldBounds; + + TRACE("(%p,%p)\n", psa, psabound); + + if (!psa || psa->fFeatures & FADF_FIXEDSIZE || !psabound) + return E_INVALIDARG; + + if (psa->cLocks > 0) + return DISP_E_ARRAYISLOCKED; + + if (FAILED(SafeArrayLock(psa))) + return E_UNEXPECTED; + + oldBounds = &psa->rgsabound[psa->cDims - 1]; + oldBounds->lLbound = psabound->lLbound; + + if (psabound->cElements != oldBounds->cElements) + { + if (psabound->cElements < oldBounds->cElements) + { + /* Shorten the final dimension. */ + ULONG ulStartCell = psa->cDims == 1 ? 0 : SAFEARRAY_GetDimensionCells(psa, psa->cDims - 1); + + ulStartCell += psabound->cElements; + SAFEARRAY_DestroyData(psa, ulStartCell); + } + else + { + /* Lengthen the final dimension */ + ULONG ulOldSize, ulNewSize; + PVOID pvNewData; + + ulOldSize = SAFEARRAY_GetCellCount(psa) * psa->cbElements; + if (ulOldSize) + ulNewSize = (ulOldSize / oldBounds->cElements) * psabound->cElements; + else { + int oldelems = oldBounds->cElements; + oldBounds->cElements = psabound->cElements; + ulNewSize = SAFEARRAY_GetCellCount(psa) * psa->cbElements; + oldBounds->cElements = oldelems; + } + + if (!(pvNewData = SAFEARRAY_Malloc(ulNewSize))) + { + SafeArrayUnlock(psa); + return E_UNEXPECTED; + } + + memcpy(pvNewData, psa->pvData, ulOldSize); + SAFEARRAY_Free(psa->pvData); + psa->pvData = pvNewData; + } + oldBounds->cElements = psabound->cElements; + } + + SafeArrayUnlock(psa); + return S_OK; +} + +/************************************************************************ + * SafeArrayGetVartype (OLEAUT32.77) + * + * Get the type of the items in a SafeArray. + * + * PARAMS + * psa [I] Array to get the type from + * pvt [O] Destination for the type + * + * RETURNS + * Success: S_OK. pvt contains the type of the items. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI SafeArrayGetVartype(SAFEARRAY* psa, VARTYPE* pvt) +{ + TRACE("(%p,%p)\n", psa, pvt); + + if (!psa || !pvt) + return E_INVALIDARG; + + if (psa->fFeatures & FADF_RECORD) + *pvt = VT_RECORD; + else if (psa->fFeatures & FADF_HAVEIID) + *pvt = VT_UNKNOWN; + else if (psa->fFeatures & FADF_HAVEVARTYPE) + { + VARTYPE vt = SAFEARRAY_GetHiddenDWORD(psa); + *pvt = vt; + } + else + return E_INVALIDARG; + + return S_OK; +} + +/************************************************************************ + * SafeArraySetRecordInfo (OLEAUT32.@) + * + * Set the record info for a SafeArray. + * + * PARAMS + * psa [I] Array to set the record info for + * pRinfo [I] Record info + * + * RETURNS + * Success: S_OK. The record info is stored with the array. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI SafeArraySetRecordInfo(SAFEARRAY *psa, IRecordInfo *pRinfo) +{ + IRecordInfo** dest = (IRecordInfo**)psa; + + TRACE("(%p,%p)\n", psa, pRinfo); + + if (!psa || !(psa->fFeatures & FADF_RECORD)) + return E_INVALIDARG; + + if (pRinfo) + IRecordInfo_AddRef(pRinfo); + + if (dest[-1]) + IRecordInfo_Release(dest[-1]); + + dest[-1] = pRinfo; + return S_OK; +} + +/************************************************************************ + * SafeArrayGetRecordInfo (OLEAUT32.@) + * + * Get the record info from a SafeArray. + * + * PARAMS + * psa [I] Array to get the record info from + * pRinfo [O] Destination for the record info + * + * RETURNS + * Success: S_OK. pRinfo contains the record info, or NULL if there was none. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI SafeArrayGetRecordInfo(SAFEARRAY *psa, IRecordInfo **pRinfo) +{ + IRecordInfo** src = (IRecordInfo**)psa; + + TRACE("(%p,%p)\n", psa, pRinfo); + + if (!psa || !pRinfo || !(psa->fFeatures & FADF_RECORD)) + return E_INVALIDARG; + + *pRinfo = src[-1]; + + if (*pRinfo) + IRecordInfo_AddRef(*pRinfo); + return S_OK; +} + +/************************************************************************ + * SafeArraySetIID (OLEAUT32.@) + * + * Set the IID for a SafeArray. + * + * PARAMS + * psa [I] Array to set the IID from + * guid [I] IID + * + * RETURNS + * Success: S_OK. The IID is stored with the array + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI SafeArraySetIID(SAFEARRAY *psa, REFGUID guid) +{ + GUID* dest = (GUID*)psa; + + TRACE("(%p,%s)\n", psa, debugstr_guid(guid)); + + if (!psa || !guid || !(psa->fFeatures & FADF_HAVEIID)) + return E_INVALIDARG; + + dest[-1] = *guid; + return S_OK; +} + +/************************************************************************ + * SafeArrayGetIID (OLEAUT32.@) + * + * Get the IID from a SafeArray. + * + * PARAMS + * psa [I] Array to get the ID from + * pGuid [O] Destination for the IID + * + * RETURNS + * Success: S_OK. pRinfo contains the IID, or NULL if there was none. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI SafeArrayGetIID(SAFEARRAY *psa, GUID *pGuid) +{ + GUID* src = (GUID*)psa; + + TRACE("(%p,%p)\n", psa, pGuid); + + if (!psa || !pGuid || !(psa->fFeatures & FADF_HAVEIID)) + return E_INVALIDARG; + + *pGuid = src[-1]; + return S_OK; +} + +/************************************************************************ + * VectorFromBstr (OLEAUT32.@) + * + * Create a SafeArray Vector from the bytes of a BSTR. + * + * PARAMS + * bstr [I] String to get bytes from + * ppsa [O] Destination for the array + * + * RETURNS + * Success: S_OK. ppsa contains the strings bytes as a VT_UI1 array. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI VectorFromBstr(BSTR bstr, SAFEARRAY **ppsa) +{ + SAFEARRAYBOUND sab; + + TRACE("(%p,%p)\n", bstr, ppsa); + + if (!ppsa) + return E_INVALIDARG; + + sab.lLbound = 0; + sab.cElements = SysStringByteLen(bstr); + + *ppsa = SAFEARRAY_Create(VT_UI1, 1, &sab, 0); + + if (*ppsa) + { + memcpy((*ppsa)->pvData, bstr, sab.cElements); + return S_OK; + } + return E_OUTOFMEMORY; +} + +/************************************************************************ + * BstrFromVector (OLEAUT32.@) + * + * Create a BSTR from a SafeArray. + * + * PARAMS + * psa [I] Source array + * pbstr [O] Destination for output BSTR + * + * RETURNS + * Success: S_OK. pbstr contains the arrays data. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * psa must be a 1 dimensional array of a 1 byte type. + * + * NOTES + * See SafeArray. + */ +HRESULT WINAPI BstrFromVector(SAFEARRAY *psa, BSTR *pbstr) +{ + TRACE("(%p,%p)\n", psa, pbstr); + + if (!pbstr) + return E_INVALIDARG; + + *pbstr = NULL; + + if (!psa || psa->cbElements != 1 || psa->cDims != 1) + return E_INVALIDARG; + + *pbstr = SysAllocStringByteLen(psa->pvData, psa->rgsabound[0].cElements); + if (!*pbstr) + return E_OUTOFMEMORY; + return S_OK; +} diff --git a/reactos/lib/oleaut32/stubs.c b/reactos/lib/oleaut32/stubs.c index 3252bcd543b..e1f8b709aa9 100644 --- a/reactos/lib/oleaut32/stubs.c +++ b/reactos/lib/oleaut32/stubs.c @@ -1,66 +1,66 @@ -/* - * OlePro32 Stubs - * - * Copyright 1999 Corel Corporation - * - * Sean Langley - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "wine/debug.h" -#include "ole2.h" -#include "olectl.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/*********************************************************************** - * OleIconToCursor (OLEAUT32.415) - */ -HCURSOR WINAPI OleIconToCursor( HINSTANCE hinstExe, HICON hicon) -{ - FIXME("(%p,%p), not implemented (olepro32.dll)\n",hinstExe,hicon); - return S_OK; -} - -/*********************************************************************** - * OleCreatePropertyFrameIndirect (OLEAUT32.416) - */ -HRESULT WINAPI OleCreatePropertyFrameIndirect( LPOCPFIPARAMS lpParams) -{ - FIXME("(%p), not implemented (olepro32.dll)\n",lpParams); - return S_OK; -} - -/*********************************************************************** - * OleCreatePropertyFrame (OLEAUT32.417) - */ -HRESULT WINAPI OleCreatePropertyFrame( - HWND hwndOwner, UINT x, UINT y, LPCOLESTR lpszCaption,ULONG cObjects, - LPUNKNOWN* ppUnk, ULONG cPages, LPCLSID pPageClsID, LCID lcid, - DWORD dwReserved, LPVOID pvReserved ) -{ - FIXME("(%p,%d,%d,%s,%ld,%p,%ld,%p,%x,%ld,%p), not implemented (olepro32.dll)\n", - hwndOwner,x,y,debugstr_w(lpszCaption),cObjects,ppUnk,cPages, - pPageClsID, (int)lcid,dwReserved,pvReserved); - return S_OK; -} - +/* + * OlePro32 Stubs + * + * Copyright 1999 Corel Corporation + * + * Sean Langley + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "wine/debug.h" +#include "ole2.h" +#include "olectl.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/*********************************************************************** + * OleIconToCursor (OLEAUT32.415) + */ +HCURSOR WINAPI OleIconToCursor( HINSTANCE hinstExe, HICON hicon) +{ + FIXME("(%p,%p), not implemented (olepro32.dll)\n",hinstExe,hicon); + return S_OK; +} + +/*********************************************************************** + * OleCreatePropertyFrameIndirect (OLEAUT32.416) + */ +HRESULT WINAPI OleCreatePropertyFrameIndirect( LPOCPFIPARAMS lpParams) +{ + FIXME("(%p), not implemented (olepro32.dll)\n",lpParams); + return S_OK; +} + +/*********************************************************************** + * OleCreatePropertyFrame (OLEAUT32.417) + */ +HRESULT WINAPI OleCreatePropertyFrame( + HWND hwndOwner, UINT x, UINT y, LPCOLESTR lpszCaption,ULONG cObjects, + LPUNKNOWN* ppUnk, ULONG cPages, LPCLSID pPageClsID, LCID lcid, + DWORD dwReserved, LPVOID pvReserved ) +{ + FIXME("(%p,%d,%d,%s,%ld,%p,%ld,%p,%x,%ld,%p), not implemented (olepro32.dll)\n", + hwndOwner,x,y,debugstr_w(lpszCaption),cObjects,ppUnk,cPages, + pPageClsID, (int)lcid,dwReserved,pvReserved); + return S_OK; +} + diff --git a/reactos/lib/oleaut32/tmarshal.c b/reactos/lib/oleaut32/tmarshal.c index 12aafdb4cec..5f78bd4c957 100644 --- a/reactos/lib/oleaut32/tmarshal.c +++ b/reactos/lib/oleaut32/tmarshal.c @@ -1,2272 +1,2272 @@ -/* - * TYPELIB Marshaler - * - * Copyright 2002,2005 Marcus Meissner - * - * The olerelay debug channel allows you to see calls marshalled by - * the typelib marshaller. It is not a generic COM relaying system. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <assert.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <stdio.h> -#include <ctype.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "winerror.h" -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "winreg.h" -#include "winuser.h" - -#include "ole2.h" -#include "typelib.h" -#include "wine/debug.h" - -static const WCHAR riidW[5] = {'r','i','i','d',0}; -static const WCHAR pdispparamsW[] = {'p','d','i','s','p','p','a','r','a','m','s',0}; -static const WCHAR ppvObjectW[] = {'p','p','v','O','b','j','e','c','t',0}; -static const WCHAR IDispatchW[] = { 'I','D','i','s','p','a','t','c','h',0}; -static const WCHAR GetIDsOfNamesW[] = { 'G','e','t','I','D','s','O','f','N','a','m','e','s',0}; - -WINE_DEFAULT_DEBUG_CHANNEL(ole); -WINE_DECLARE_DEBUG_CHANNEL(olerelay); - -#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) - -typedef struct _marshal_state { - LPBYTE base; - int size; - int curoff; - - BOOL thisisiid; - IID iid; /* HACK: for VT_VOID */ -} marshal_state; - -/* used in the olerelay code to avoid having the L"" stuff added by debugstr_w */ -static char *relaystr(WCHAR *in) { - char *tmp = (char *)debugstr_w(in); - tmp += 2; - tmp[strlen(tmp)-1] = '\0'; - return tmp; -} - -static HRESULT -xbuf_add(marshal_state *buf, LPBYTE stuff, DWORD size) { - while (buf->size - buf->curoff < size) { - if (buf->base) { - buf->size += 100; - buf->base = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,buf->base,buf->size); - if (!buf->base) - return E_OUTOFMEMORY; - } else { - buf->base = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,32); - buf->size = 32; - if (!buf->base) - return E_OUTOFMEMORY; - } - } - memcpy(buf->base+buf->curoff,stuff,size); - buf->curoff += size; - return S_OK; -} - -static HRESULT -xbuf_get(marshal_state *buf, LPBYTE stuff, DWORD size) { - if (buf->size < buf->curoff+size) return E_FAIL; - memcpy(stuff,buf->base+buf->curoff,size); - buf->curoff += size; - return S_OK; -} - -static HRESULT -xbuf_skip(marshal_state *buf, DWORD size) { - if (buf->size < buf->curoff+size) return E_FAIL; - buf->curoff += size; - return S_OK; -} - -static HRESULT -_unmarshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN *pUnk) { - IStream *pStm; - ULARGE_INTEGER newpos; - LARGE_INTEGER seekto; - ULONG res; - HRESULT hres; - DWORD xsize; - - TRACE("...%s...\n",debugstr_guid(riid)); - - *pUnk = NULL; - hres = xbuf_get(buf,(LPBYTE)&xsize,sizeof(xsize)); - if (hres) { - ERR("xbuf_get failed\n"); - return hres; - } - - if (xsize == 0) return S_OK; - - hres = CreateStreamOnHGlobal(0,TRUE,&pStm); - if (hres) { - ERR("Stream create failed %lx\n",hres); - return hres; - } - - hres = IStream_Write(pStm,buf->base+buf->curoff,xsize,&res); - if (hres) { - ERR("stream write %lx\n",hres); - return hres; - } - - memset(&seekto,0,sizeof(seekto)); - hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); - if (hres) { - ERR("Failed Seek %lx\n",hres); - return hres; - } - - hres = CoUnmarshalInterface(pStm,riid,(LPVOID*)pUnk); - if (hres) { - ERR("Unmarshalling interface %s failed with %lx\n",debugstr_guid(riid),hres); - return hres; - } - - IStream_Release(pStm); - return xbuf_skip(buf,xsize); -} - -static HRESULT -_marshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN pUnk) { - LPUNKNOWN newiface = NULL; - LPBYTE tempbuf = NULL; - IStream *pStm = NULL; - STATSTG ststg; - ULARGE_INTEGER newpos; - LARGE_INTEGER seekto; - ULONG res; - DWORD xsize; - HRESULT hres; - - if (!pUnk) { - /* this is valid, if for instance we serialize - * a VT_DISPATCH with NULL ptr which apparently - * can happen. S_OK to make sure we continue - * serializing. - */ - ERR("pUnk is NULL?\n"); - xsize = 0; - return xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize)); - } - - hres = E_FAIL; - - TRACE("...%s...\n",debugstr_guid(riid)); - hres = IUnknown_QueryInterface(pUnk,riid,(LPVOID*)&newiface); - if (hres) { - WARN("%p does not support iface %s\n",pUnk,debugstr_guid(riid)); - goto fail; - } - - hres = CreateStreamOnHGlobal(0,TRUE,&pStm); - if (hres) { - ERR("Stream create failed %lx\n",hres); - goto fail; - } - - hres = CoMarshalInterface(pStm,riid,newiface,0,NULL,0); - if (hres) { - ERR("Marshalling interface %s failed with %lx\n", debugstr_guid(riid), hres); - goto fail; - } - - hres = IStream_Stat(pStm,&ststg,0); - if (hres) { - ERR("Stream stat failed\n"); - goto fail; - } - - tempbuf = HeapAlloc(GetProcessHeap(), 0, ststg.cbSize.u.LowPart); - memset(&seekto,0,sizeof(seekto)); - hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); - if (hres) { - ERR("Failed Seek %lx\n",hres); - goto fail; - } - - hres = IStream_Read(pStm,tempbuf,ststg.cbSize.u.LowPart,&res); - if (hres) { - ERR("Failed Read %lx\n",hres); - goto fail; - } - - xsize = ststg.cbSize.u.LowPart; - xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize)); - hres = xbuf_add(buf,tempbuf,ststg.cbSize.u.LowPart); - - HeapFree(GetProcessHeap(),0,tempbuf); - IUnknown_Release(newiface); - IStream_Release(pStm); - - return hres; - -fail: - xsize = 0; - xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize)); - if (pStm) IUnknown_Release(pStm); - if (newiface) IUnknown_Release(newiface); - HeapFree(GetProcessHeap(), 0, tempbuf); - return hres; -} - -/********************* OLE Proxy/Stub Factory ********************************/ -static HRESULT WINAPI -PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) { - if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) { - *ppv = (LPVOID)iface; - /* No ref counting, static class */ - return S_OK; - } - FIXME("(%s) unknown IID?\n",debugstr_guid(iid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; } -static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; } - -static HRESULT -_get_typeinfo_for_iid(REFIID riid, ITypeInfo**ti) { - HRESULT hres; - HKEY ikey; - char tlguid[200],typelibkey[300],interfacekey[300],ver[100]; - char tlfn[260]; - OLECHAR tlfnW[260]; - DWORD tlguidlen, verlen, type, tlfnlen; - ITypeLib *tl; - - sprintf( interfacekey, "Interface\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\Typelib", - riid->Data1, riid->Data2, riid->Data3, - riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3], - riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7] - ); - - if (RegOpenKeyA(HKEY_CLASSES_ROOT,interfacekey,&ikey)) { - ERR("No %s key found.\n",interfacekey); - return E_FAIL; - } - type = (1<<REG_SZ); - tlguidlen = sizeof(tlguid); - if (RegQueryValueExA(ikey,NULL,NULL,&type,tlguid,&tlguidlen)) { - ERR("Getting typelib guid failed.\n"); - RegCloseKey(ikey); - return E_FAIL; - } - type = (1<<REG_SZ); - verlen = sizeof(ver); - if (RegQueryValueExA(ikey,"Version",NULL,&type,ver,&verlen)) { - ERR("Could not get version value?\n"); - RegCloseKey(ikey); - return E_FAIL; - } - RegCloseKey(ikey); - sprintf(typelibkey,"Typelib\\%s\\%s\\0\\win32",tlguid,ver); - tlfnlen = sizeof(tlfn); - if (RegQueryValueA(HKEY_CLASSES_ROOT,typelibkey,tlfn,&tlfnlen)) { - ERR("Could not get typelib fn?\n"); - return E_FAIL; - } - MultiByteToWideChar(CP_ACP, 0, tlfn, -1, tlfnW, -1); - hres = LoadTypeLib(tlfnW,&tl); - if (hres) { - ERR("Failed to load typelib for %s, but it should be there.\n",debugstr_guid(riid)); - return hres; - } - hres = ITypeLib_GetTypeInfoOfGuid(tl,riid,ti); - if (hres) { - ERR("typelib does not contain info for %s?\n",debugstr_guid(riid)); - ITypeLib_Release(tl); - return hres; - } - /* FIXME: do this? ITypeLib_Release(tl); */ - return hres; -} - -/* Determine nr of functions. Since we use the toplevel interface and all - * inherited ones have lower numbers, we are ok to not to descent into - * the inheritance tree I think. - */ -static int _nroffuncs(ITypeInfo *tinfo) { - int n, max = 0; - FUNCDESC *fdesc; - HRESULT hres; - - n=0; - while (1) { - hres = ITypeInfo_GetFuncDesc(tinfo,n,&fdesc); - if (hres) - return max+1; - if (fdesc->oVft/4 > max) - max = fdesc->oVft/4; - n++; - } - /*NOTREACHED*/ -} - -#ifdef __i386__ - -#include "pshpack1.h" - -typedef struct _TMAsmProxy { - BYTE popleax; - BYTE pushlval; - BYTE nr; - BYTE pushleax; - BYTE lcall; - DWORD xcall; - BYTE lret; - WORD bytestopop; -} TMAsmProxy; - -#include "poppack.h" - -#else /* __i386__ */ -# error You need to implement stubless proxies for your architecture -#endif - -typedef struct _TMProxyImpl { - LPVOID *lpvtbl; - IRpcProxyBufferVtbl *lpvtbl2; - ULONG ref; - - TMAsmProxy *asmstubs; - ITypeInfo* tinfo; - IRpcChannelBuffer* chanbuf; - IID iid; - CRITICAL_SECTION crit; - IUnknown *outerunknown; -} TMProxyImpl; - -static HRESULT WINAPI -TMProxyImpl_QueryInterface(LPRPCPROXYBUFFER iface, REFIID riid, LPVOID *ppv) -{ - TRACE("()\n"); - if (IsEqualIID(riid,&IID_IUnknown)||IsEqualIID(riid,&IID_IRpcProxyBuffer)) { - *ppv = (LPVOID)iface; - IRpcProxyBuffer_AddRef(iface); - return S_OK; - } - FIXME("no interface for %s\n",debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI -TMProxyImpl_AddRef(LPRPCPROXYBUFFER iface) -{ - ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface); - ULONG refCount = InterlockedIncrement(&This->ref); - - TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1); - - return refCount; -} - -static ULONG WINAPI -TMProxyImpl_Release(LPRPCPROXYBUFFER iface) -{ - ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface); - ULONG refCount = InterlockedDecrement(&This->ref); - - TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1); - - if (!refCount) - { - DeleteCriticalSection(&This->crit); - if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf); - VirtualFree(This->asmstubs, 0, MEM_RELEASE); - CoTaskMemFree(This); - } - return refCount; -} - -static HRESULT WINAPI -TMProxyImpl_Connect( - LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer) -{ - ICOM_THIS_MULTI(TMProxyImpl, lpvtbl2, iface); - - TRACE("(%p)\n", pRpcChannelBuffer); - - EnterCriticalSection(&This->crit); - - IRpcChannelBuffer_AddRef(pRpcChannelBuffer); - This->chanbuf = pRpcChannelBuffer; - - LeaveCriticalSection(&This->crit); - - return S_OK; -} - -static void WINAPI -TMProxyImpl_Disconnect(LPRPCPROXYBUFFER iface) -{ - ICOM_THIS_MULTI(TMProxyImpl, lpvtbl2, iface); - - TRACE("()\n"); - - EnterCriticalSection(&This->crit); - - IRpcChannelBuffer_Release(This->chanbuf); - This->chanbuf = NULL; - - LeaveCriticalSection(&This->crit); -} - - -static IRpcProxyBufferVtbl tmproxyvtable = { - TMProxyImpl_QueryInterface, - TMProxyImpl_AddRef, - TMProxyImpl_Release, - TMProxyImpl_Connect, - TMProxyImpl_Disconnect -}; - -/* how much space do we use on stack in DWORD steps. */ -int -_argsize(DWORD vt) { - switch (vt) { - case VT_DATE: - return sizeof(DATE)/sizeof(DWORD); - case VT_VARIANT: - return (sizeof(VARIANT)+3)/sizeof(DWORD); - default: - return 1; - } -} - -static int -_xsize(TYPEDESC *td) { - switch (td->vt) { - case VT_DATE: - return sizeof(DATE); - case VT_VARIANT: - return sizeof(VARIANT)+3; - case VT_CARRAY: { - int i, arrsize = 1; - ARRAYDESC *adesc = td->u.lpadesc; - - for (i=0;i<adesc->cDims;i++) - arrsize *= adesc->rgbounds[i].cElements; - return arrsize*_xsize(&adesc->tdescElem); - } - case VT_UI2: - case VT_I2: - return 2; - case VT_UI1: - case VT_I1: - return 1; - default: - return 4; - } -} - -static HRESULT -serialize_param( - ITypeInfo *tinfo, - BOOL writeit, - BOOL debugout, - BOOL dealloc, - TYPEDESC *tdesc, - DWORD *arg, - marshal_state *buf) -{ - HRESULT hres = S_OK; - - TRACE("(tdesc.vt %d)\n",tdesc->vt); - - switch (tdesc->vt) { - case VT_EMPTY: /* nothing. empty variant for instance */ - return S_OK; - case VT_BOOL: - case VT_ERROR: - case VT_UINT: - case VT_I4: - case VT_R4: - case VT_UI4: - hres = S_OK; - if (debugout) TRACE_(olerelay)("%lx",*arg); - if (writeit) - hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD)); - return hres; - case VT_I2: - case VT_UI2: - hres = S_OK; - if (debugout) TRACE_(olerelay)("%04lx",*arg & 0xffff); - if (writeit) - hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD)); - return hres; - case VT_I1: - case VT_UI1: - hres = S_OK; - if (debugout) TRACE_(olerelay)("%02lx",*arg & 0xff); - if (writeit) - hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD)); - return hres; - case VT_I4|VT_BYREF: - hres = S_OK; - if (debugout) TRACE_(olerelay)("&0x%lx",*arg); - if (writeit) - hres = xbuf_add(buf,(LPBYTE)(DWORD*)*arg,sizeof(DWORD)); - /* do not dealloc at this time */ - return hres; - case VT_VARIANT: { - TYPEDESC tdesc2; - VARIANT *vt = (VARIANT*)arg; - DWORD vttype = V_VT(vt); - - if (debugout) TRACE_(olerelay)("Vt(%ld)(",vttype); - tdesc2.vt = vttype; - if (writeit) { - hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype)); - if (hres) return hres; - } - /* need to recurse since we need to free the stuff */ - hres = serialize_param(tinfo,writeit,debugout,dealloc,&tdesc2,&(V_I4(vt)),buf); - if (debugout) TRACE_(olerelay)(")"); - return hres; - } - case VT_BSTR|VT_BYREF: { - if (debugout) TRACE_(olerelay)("[byref]'%s'", *(BSTR*)*arg ? relaystr(*((BSTR*)*arg)) : "<bstr NULL>"); - if (writeit) { - /* ptr to ptr to magic widestring, basically */ - BSTR *bstr = (BSTR *) *arg; - if (!*bstr) { - /* -1 means "null string" which is equivalent to empty string */ - DWORD fakelen = -1; - xbuf_add(buf, (LPBYTE)&fakelen,4); - } else { - /* BSTRs store the length behind the first character */ - DWORD *len = ((DWORD *)(*bstr))-1; - hres = xbuf_add(buf, (LPBYTE) len, *len + 4); - if (hres) return hres; - } - } - - if (dealloc && arg) { - BSTR *str = *((BSTR **)arg); - SysFreeString(*str); - } - return S_OK; - } - - case VT_BSTR: { - if (debugout) { - if (*arg) - TRACE_(olerelay)("%s",relaystr((WCHAR*)*arg)); - else - TRACE_(olerelay)("<bstr NULL>"); - } - if (writeit) { - if (!*arg) { - DWORD fakelen = -1; - hres = xbuf_add(buf,(LPBYTE)&fakelen,4); - if (hres) - return hres; - } else { - DWORD *bstr = ((DWORD*)(*arg))-1; - - hres = xbuf_add(buf,(LPBYTE)bstr,bstr[0]+4); - if (hres) - return hres; - } - } - - if (dealloc && arg) - SysFreeString((BSTR)*arg); - return S_OK; - } - case VT_PTR: { - DWORD cookie; - - if (debugout) TRACE_(olerelay)("*"); - /* Write always, so the other side knows when it gets a NULL pointer. - */ - cookie = *arg ? 0x42424242 : 0; - hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie)); - if (hres) - return hres; - if (!*arg) { - if (debugout) TRACE_(olerelay)("NULL"); - return S_OK; - } - hres = serialize_param(tinfo,writeit,debugout,dealloc,tdesc->u.lptdesc,(DWORD*)*arg,buf); - if (dealloc) HeapFree(GetProcessHeap(),0,(LPVOID)arg); - return hres; - } - case VT_UNKNOWN: - if (debugout) TRACE_(olerelay)("unk(0x%lx)",*arg); - if (writeit) - hres = _marshal_interface(buf,&IID_IUnknown,(LPUNKNOWN)*arg); - return hres; - case VT_DISPATCH: - if (debugout) TRACE_(olerelay)("idisp(0x%lx)",*arg); - if (writeit) - hres = _marshal_interface(buf,&IID_IDispatch,(LPUNKNOWN)*arg); - return hres; - case VT_VOID: - if (debugout) TRACE_(olerelay)("<void>"); - return S_OK; - case VT_USERDEFINED: { - ITypeInfo *tinfo2; - TYPEATTR *tattr; - - hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2); - if (hres) { - ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype); - return hres; - } - ITypeInfo_GetTypeAttr(tinfo2,&tattr); - switch (tattr->typekind) { - case TKIND_DISPATCH: - case TKIND_INTERFACE: - if (writeit) - hres=_marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg); - break; - case TKIND_RECORD: { - int i; - if (debugout) TRACE_(olerelay)("{"); - for (i=0;i<tattr->cVars;i++) { - VARDESC *vdesc; - ELEMDESC *elem2; - TYPEDESC *tdesc2; - - hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc); - if (hres) { - ERR("Could not get vardesc of %d\n",i); - return hres; - } - /* Need them for hack below */ - /* - memset(names,0,sizeof(names)); - hres = ITypeInfo_GetNames(tinfo2,vdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames); - if (nrofnames > sizeof(names)/sizeof(names[0])) { - ERR("Need more names!\n"); - } - if (!hres && debugout) - TRACE_(olerelay)("%s=",relaystr(names[0])); - */ - elem2 = &vdesc->elemdescVar; - tdesc2 = &elem2->tdesc; - hres = serialize_param( - tinfo2, - writeit, - debugout, - dealloc, - tdesc2, - (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst), - buf - ); - if (hres!=S_OK) - return hres; - if (debugout && (i<(tattr->cVars-1))) - TRACE_(olerelay)(","); - } - if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID))) - memcpy(&(buf->iid),arg,sizeof(buf->iid)); - if (debugout) TRACE_(olerelay)("}"); - break; - } - default: - FIXME("Unhandled typekind %d\n",tattr->typekind); - hres = E_FAIL; - break; - } - ITypeInfo_Release(tinfo2); - return hres; - } - case VT_CARRAY: { - ARRAYDESC *adesc = tdesc->u.lpadesc; - int i, arrsize = 1; - - if (debugout) TRACE_(olerelay)("carr"); - for (i=0;i<adesc->cDims;i++) { - if (debugout) TRACE_(olerelay)("[%ld]",adesc->rgbounds[i].cElements); - arrsize *= adesc->rgbounds[i].cElements; - } - if (debugout) TRACE_(olerelay)("(vt %d)",adesc->tdescElem.vt); - if (debugout) TRACE_(olerelay)("["); - for (i=0;i<arrsize;i++) { - hres = serialize_param(tinfo, writeit, debugout, dealloc, &adesc->tdescElem, (DWORD*)((LPBYTE)arg+i*_xsize(&adesc->tdescElem)), buf); - if (hres) - return hres; - if (debugout && (i<arrsize-1)) TRACE_(olerelay)(","); - } - if (debugout) TRACE_(olerelay)("]"); - return S_OK; - } - default: - ERR("Unhandled marshal type %d.\n",tdesc->vt); - return S_OK; - } -} - -/* IDL desc: - * HRESULT GetIDsOfNames( - * [in] REFIID riid, args[1] - * [in, size_is(cNames)] LPOLESTR *rgszNames, args[2] - * [in] UINT cNames, args[3] - * [in] LCID lcid, args[4] - * [out, size_is(cNames)] DISPID *rgDispId); args[5] - * - * line format: - * IID iid; - * DWORD cNames; - * LPOLESTR rgszNames[cNames]; - * DWORD bytestrlen (incl 0) - * BYTE data[bytestrlen] (incl 0) - * LCID - */ -static HRESULT -serialize_IDispatch_GetIDsOfNames( - BOOL inputparams, - BOOL debugout, - DWORD *args, - marshal_state *buf) -{ - HRESULT hres; - DWORD cNames = args[2]; - LPOLESTR *rgszNames = (LPOLESTR*)args[1]; - int i; - - if (inputparams) { - if (debugout) TRACE_(olerelay)("riid=%s,",debugstr_guid((REFIID)args[0])); - hres = xbuf_add(buf, (LPBYTE)args[0], sizeof(IID)); - if (hres) { - FIXME("serialize of IID failed.\n"); - return hres; - } - if (debugout) TRACE_(olerelay)("cNames=%ld,",cNames); - hres = xbuf_add(buf, (LPBYTE)&cNames, sizeof(DWORD)); - if (hres) { - FIXME("serialize of cNames failed.\n"); - return hres; - } - if (debugout) TRACE_(olerelay)("rgszNames=["); - for (i=0;i<cNames;i++) { - DWORD len = 2*(lstrlenW(rgszNames[i])+1); - - if (debugout) TRACE_(olerelay)("%s,",relaystr(rgszNames[i])); - hres = xbuf_add(buf, (LPBYTE)&len, sizeof(DWORD)); - if (hres) { - FIXME("serialize of len failed.\n"); - return hres; - } - hres = xbuf_add(buf, (LPBYTE)rgszNames[i], len); - if (hres) { - FIXME("serialize of rgszNames[i] failed.\n"); - return hres; - } - } - if (debugout) TRACE_(olerelay)("],lcid=%04lx)",args[3]); - hres = xbuf_add(buf, (LPBYTE)&args[3], sizeof(DWORD)); - if (hres) { - FIXME("serialize of lcid failed.\n"); - return hres; - } - } else { - DISPID *rgDispId = (DISPID*)args[4]; - - hres = xbuf_add(buf, (LPBYTE)rgDispId, sizeof(DISPID) * cNames); - if (hres) { - FIXME("serialize of rgDispId failed.\n"); - return hres; - } - if (debugout) { - TRACE_(olerelay)("riid=[in],rgszNames=[in],cNames=[in],rgDispId=["); - for (i=0;i<cNames;i++) - TRACE_(olerelay)("%08lx,",rgDispId[i]); - TRACE_(olerelay)("])"); - } - HeapFree(GetProcessHeap(),0,(IID*)args[0]); - rgszNames = (LPOLESTR*)args[1]; - for (i=0;i<cNames;i++) HeapFree(GetProcessHeap(),0,rgszNames[i]); - HeapFree(GetProcessHeap(),0,rgszNames); - HeapFree(GetProcessHeap(),0,rgDispId); - } - return S_OK; -} - -static HRESULT -deserialize_IDispatch_GetIDsOfNames( - BOOL inputparams, - BOOL debugout, - DWORD *args, - marshal_state *buf) -{ - HRESULT hres; - DWORD cNames; - LPOLESTR *rgszNames; - int i; - - if (inputparams) { - args[0] = (DWORD)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IID)); - if (!args[0]) return E_FAIL; - hres = xbuf_get(buf, (LPBYTE)args[0], sizeof(IID)); - if (hres) { - FIXME("deserialize of IID failed.\n"); - return hres; - } - if (debugout) TRACE_(olerelay)("riid=%s,",debugstr_guid((REFIID)args[0])); - - hres = xbuf_get(buf, (LPBYTE)&cNames, sizeof(DWORD)); - if (hres) { - FIXME("deserialize of cNames failed.\n"); - return hres; - } - args[2] = cNames; - if (debugout) TRACE_(olerelay)("cNames=%ld,",cNames); - if (debugout) TRACE_(olerelay)("rgszNames=["); - rgszNames = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LPOLESTR) * cNames); - if (!rgszNames) return E_FAIL; - args[1] = (DWORD)rgszNames; - for (i=0;i<cNames;i++) { - DWORD len; - - hres = xbuf_get(buf, (LPBYTE)&len, sizeof(DWORD)); - if (hres) { - FIXME("serialize of len failed.\n"); - return hres; - } - rgszNames[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len); - if (!rgszNames[i]) { - FIXME("heapalloc of %ld bytes failed\n", len); - return E_FAIL; - } - hres = xbuf_get(buf, (LPBYTE)rgszNames[i], len); - if (hres) { - FIXME("serialize of rgszNames[i] failed.\n"); - return hres; - } - if (debugout) TRACE_(olerelay)("%s,",relaystr(rgszNames[i])); - } - hres = xbuf_get(buf, (LPBYTE)&args[3], sizeof(DWORD)); - if (hres) { - FIXME("deserialize of lcid failed.\n"); - return hres; - } - if (debugout) TRACE_(olerelay)("],lcid=%04lx,rgDispId=[out])",args[3]); - args[4] = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPID) * cNames); - } else { - hres = xbuf_get(buf, (LPBYTE)args[4], sizeof(DISPID) * args[2]); - if (hres) { - FIXME("serialize of rgDispId failed.\n"); - return hres; - } - if (debugout) { - TRACE_(olerelay)("dispid=["); - for (i=0;i<args[2];i++) - TRACE_(olerelay)("%08lx,",((DISPID*)args[4])[i]); - TRACE_(olerelay)("])"); - } - } - return S_OK; -} - -static HRESULT -serialize_LPVOID_ptr( - ITypeInfo *tinfo, - BOOL writeit, - BOOL debugout, - BOOL dealloc, - TYPEDESC *tdesc, - DWORD *arg, - marshal_state *buf) -{ - HRESULT hres; - DWORD cookie; - - if ((tdesc->vt != VT_PTR) || - (tdesc->u.lptdesc->vt != VT_PTR) || - (tdesc->u.lptdesc->u.lptdesc->vt != VT_VOID) - ) { - FIXME("ppvObject not expressed as VT_PTR -> VT_PTR -> VT_VOID?\n"); - return E_FAIL; - } - cookie = (*(DWORD*)*arg) ? 0x42424242: 0x0; - if (writeit) { - hres = xbuf_add(buf, (LPVOID)&cookie, sizeof(cookie)); - if (hres) - return hres; - } - if (!*(DWORD*)*arg) { - if (debugout) TRACE_(olerelay)("<lpvoid NULL>"); - return S_OK; - } - if (debugout) - TRACE_(olerelay)("ppv(%p)",*(LPUNKNOWN*)*arg); - if (writeit) { - hres = _marshal_interface(buf,&(buf->iid),*(LPUNKNOWN*)*arg); - if (hres) - return hres; - } - if (dealloc) - HeapFree(GetProcessHeap(),0,(LPVOID)*arg); - return S_OK; -} - -static HRESULT -serialize_DISPPARAM_ptr( - ITypeInfo *tinfo, - BOOL writeit, - BOOL debugout, - BOOL dealloc, - TYPEDESC *tdesc, - DWORD *arg, - marshal_state *buf) -{ - DWORD cookie; - HRESULT hres; - DISPPARAMS *disp; - int i; - - if ((tdesc->vt != VT_PTR) || (tdesc->u.lptdesc->vt != VT_USERDEFINED)) { - FIXME("DISPPARAMS not expressed as VT_PTR -> VT_USERDEFINED?\n"); - return E_FAIL; - } - - cookie = *arg ? 0x42424242 : 0x0; - if (writeit) { - hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie)); - if (hres) - return hres; - } - if (!*arg) { - if (debugout) TRACE_(olerelay)("<DISPPARAMS NULL>"); - return S_OK; - } - disp = (DISPPARAMS*)*arg; - if (writeit) { - hres = xbuf_add(buf,(LPBYTE)&disp->cArgs,sizeof(disp->cArgs)); - if (hres) - return hres; - } - if (debugout) TRACE_(olerelay)("D{"); - for (i=0;i<disp->cArgs;i++) { - TYPEDESC vtdesc; - - vtdesc.vt = VT_VARIANT; - serialize_param( - tinfo, - writeit, - debugout, - dealloc, - &vtdesc, - (DWORD*)(disp->rgvarg+i), - buf - ); - if (debugout && (i<disp->cArgs-1)) - TRACE_(olerelay)(","); - } - if (dealloc) - HeapFree(GetProcessHeap(),0,disp->rgvarg); - if (writeit) { - hres = xbuf_add(buf,(LPBYTE)&disp->cNamedArgs,sizeof(disp->cNamedArgs)); - if (hres) - return hres; - } - if (debugout) TRACE_(olerelay)("}{"); - for (i=0;i<disp->cNamedArgs;i++) { - TYPEDESC vtdesc; - - vtdesc.vt = VT_UINT; - serialize_param( - tinfo, - writeit, - debugout, - dealloc, - &vtdesc, - (DWORD*)(disp->rgdispidNamedArgs+i), - buf - ); - if (debugout && (i<disp->cNamedArgs-1)) - TRACE_(olerelay)(","); - } - if (debugout) TRACE_(olerelay)("}"); - if (dealloc) { - HeapFree(GetProcessHeap(),0,disp->rgdispidNamedArgs); - HeapFree(GetProcessHeap(),0,disp); - } - return S_OK; -} - -static HRESULT -deserialize_param( - ITypeInfo *tinfo, - BOOL readit, - BOOL debugout, - BOOL alloc, - TYPEDESC *tdesc, - DWORD *arg, - marshal_state *buf) -{ - HRESULT hres = S_OK; - - TRACE("vt %d at %p\n",tdesc->vt,arg); - - while (1) { - switch (tdesc->vt) { - case VT_EMPTY: - if (debugout) TRACE_(olerelay)("<empty>"); - return S_OK; - case VT_NULL: - if (debugout) TRACE_(olerelay)("<null>"); - return S_OK; - case VT_VARIANT: { - VARIANT *vt = (VARIANT*)arg; - - if (readit) { - DWORD vttype; - TYPEDESC tdesc2; - hres = xbuf_get(buf,(LPBYTE)&vttype,sizeof(vttype)); - if (hres) { - FIXME("vt type not read?\n"); - return hres; - } - memset(&tdesc2,0,sizeof(tdesc2)); - tdesc2.vt = vttype; - V_VT(vt) = vttype; - if (debugout) TRACE_(olerelay)("Vt(%ld)(",vttype); - hres = deserialize_param(tinfo, readit, debugout, alloc, &tdesc2, &(V_I4(vt)), buf); - TRACE_(olerelay)(")"); - return hres; - } else { - VariantInit(vt); - return S_OK; - } - } - case VT_ERROR: - case VT_BOOL: - case VT_I4: - case VT_UINT: - case VT_R4: - case VT_UI4: - if (readit) { - hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD)); - if (hres) ERR("Failed to read integer 4 byte\n"); - } - if (debugout) TRACE_(olerelay)("%lx",*arg); - return hres; - case VT_I2: - case VT_UI2: - if (readit) { - DWORD x; - hres = xbuf_get(buf,(LPBYTE)&x,sizeof(DWORD)); - if (hres) ERR("Failed to read integer 4 byte\n"); - memcpy(arg,&x,2); - } - if (debugout) TRACE_(olerelay)("%04lx",*arg & 0xffff); - return hres; - case VT_I1: - case VT_UI1: - if (readit) { - DWORD x; - hres = xbuf_get(buf,(LPBYTE)&x,sizeof(DWORD)); - if (hres) ERR("Failed to read integer 4 byte\n"); - memcpy(arg,&x,1); - } - if (debugout) TRACE_(olerelay)("%02lx",*arg & 0xff); - return hres; - case VT_I4|VT_BYREF: - hres = S_OK; - if (alloc) - *arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD)); - if (readit) { - hres = xbuf_get(buf,(LPBYTE)*arg,sizeof(DWORD)); - if (hres) ERR("Failed to read integer 4 byte\n"); - } - if (debugout) TRACE_(olerelay)("&0x%lx",*(DWORD*)*arg); - return hres; - case VT_BSTR|VT_BYREF: { - BSTR **bstr = (BSTR **)arg; - WCHAR *str; - DWORD len; - - if (readit) { - hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD)); - if (hres) { - ERR("failed to read bstr klen\n"); - return hres; - } - if (len == -1) { - *bstr = CoTaskMemAlloc(sizeof(BSTR *)); - **bstr = NULL; - if (debugout) TRACE_(olerelay)("<bstr NULL>"); - } else { - str = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,len+sizeof(WCHAR)); - hres = xbuf_get(buf,(LPBYTE)str,len); - if (hres) { - ERR("Failed to read BSTR.\n"); - return hres; - } - *bstr = CoTaskMemAlloc(sizeof(BSTR *)); - **bstr = SysAllocStringLen(str,len); - if (debugout) TRACE_(olerelay)("%s",relaystr(str)); - HeapFree(GetProcessHeap(),0,str); - } - } else { - *bstr = NULL; - } - return S_OK; - } - case VT_BSTR: { - WCHAR *str; - DWORD len; - - if (readit) { - hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD)); - if (hres) { - ERR("failed to read bstr klen\n"); - return hres; - } - if (len == -1) { - *arg = 0; - if (debugout) TRACE_(olerelay)("<bstr NULL>"); - } else { - str = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,len+sizeof(WCHAR)); - hres = xbuf_get(buf,(LPBYTE)str,len); - if (hres) { - ERR("Failed to read BSTR.\n"); - return hres; - } - *arg = (DWORD)SysAllocStringLen(str,len); - if (debugout) TRACE_(olerelay)("%s",relaystr(str)); - HeapFree(GetProcessHeap(),0,str); - } - } else { - *arg = 0; - } - return S_OK; - } - case VT_PTR: { - DWORD cookie; - BOOL derefhere = 0; - - derefhere = (tdesc->u.lptdesc->vt != VT_USERDEFINED); - /* read it in all cases, we need to know if we have - * NULL pointer or not. - */ - hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie)); - if (hres) { - ERR("Failed to load pointer cookie.\n"); - return hres; - } - if (cookie != 0x42424242) { - /* we read a NULL ptr from the remote side */ - if (debugout) TRACE_(olerelay)("NULL"); - *arg = 0; - return S_OK; - } - if (debugout) TRACE_(olerelay)("*"); - if (alloc) { - /* Allocate space for the referenced struct */ - if (derefhere) - *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc)); - } - if (derefhere) - return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, (LPDWORD)*arg, buf); - else - return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, arg, buf); - } - case VT_UNKNOWN: - /* FIXME: UNKNOWN is unknown ..., but allocate 4 byte for it */ - if (alloc) - *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD)); - hres = S_OK; - if (readit) - hres = _unmarshal_interface(buf,&IID_IUnknown,(LPUNKNOWN*)arg); - if (debugout) - TRACE_(olerelay)("unk(%p)",arg); - return hres; - case VT_DISPATCH: - hres = S_OK; - if (readit) - hres = _unmarshal_interface(buf,&IID_IDispatch,(LPUNKNOWN*)arg); - if (debugout) - TRACE_(olerelay)("idisp(%p)",arg); - return hres; - case VT_VOID: - if (debugout) TRACE_(olerelay)("<void>"); - return S_OK; - case VT_USERDEFINED: { - ITypeInfo *tinfo2; - TYPEATTR *tattr; - - hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2); - if (hres) { - ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype); - return hres; - } - hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr); - if (hres) { - ERR("Could not get typeattr in VT_USERDEFINED.\n"); - } else { - switch (tattr->typekind) { - case TKIND_DISPATCH: - case TKIND_INTERFACE: - if (readit) - hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg); - break; - case TKIND_RECORD: { - int i; - - if (alloc) - *arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,tattr->cbSizeInstance); - - if (debugout) TRACE_(olerelay)("{"); - for (i=0;i<tattr->cVars;i++) { - VARDESC *vdesc; - - hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc); - if (hres) { - ERR("Could not get vardesc of %d\n",i); - return hres; - } - hres = deserialize_param( - tinfo2, - readit, - debugout, - alloc, - &vdesc->elemdescVar.tdesc, - (DWORD*)(((LPBYTE)*arg)+vdesc->u.oInst), - buf - ); - if (debugout && (i<tattr->cVars-1)) TRACE_(olerelay)(","); - } - if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID))) - memcpy(&(buf->iid),(LPBYTE)*arg,sizeof(buf->iid)); - if (debugout) TRACE_(olerelay)("}"); - break; - } - default: - ERR("Unhandled typekind %d\n",tattr->typekind); - hres = E_FAIL; - break; - } - } - if (hres) - ERR("failed to stuballoc in TKIND_RECORD.\n"); - ITypeInfo_Release(tinfo2); - return hres; - } - case VT_CARRAY: { - /* arg is pointing to the start of the array. */ - ARRAYDESC *adesc = tdesc->u.lpadesc; - int arrsize,i; - arrsize = 1; - if (adesc->cDims > 1) FIXME("cDims > 1 in VT_CARRAY. Does it work?\n"); - for (i=0;i<adesc->cDims;i++) - arrsize *= adesc->rgbounds[i].cElements; - for (i=0;i<arrsize;i++) - deserialize_param( - tinfo, - readit, - debugout, - alloc, - &adesc->tdescElem, - (DWORD*)((LPBYTE)(arg)+i*_xsize(&adesc->tdescElem)), - buf - ); - return S_OK; - } - default: - ERR("No handler for VT type %d!\n",tdesc->vt); - return S_OK; - } - } -} - -static HRESULT -deserialize_LPVOID_ptr( - ITypeInfo *tinfo, - BOOL readit, - BOOL debugout, - BOOL alloc, - TYPEDESC *tdesc, - DWORD *arg, - marshal_state *buf -) { - HRESULT hres; - DWORD cookie; - - if ((tdesc->vt != VT_PTR) || - (tdesc->u.lptdesc->vt != VT_PTR) || - (tdesc->u.lptdesc->u.lptdesc->vt != VT_VOID) - ) { - FIXME("ppvObject not expressed as VT_PTR -> VT_PTR -> VT_VOID?\n"); - return E_FAIL; - } - if (alloc) - *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LPVOID)); - if (readit) { - hres = xbuf_get(buf, (LPVOID)&cookie, sizeof(cookie)); - if (hres) - return hres; - if (cookie != 0x42424242) { - *(DWORD*)*arg = 0; - if (debugout) TRACE_(olerelay)("<lpvoid NULL>"); - return S_OK; - } - } - if (readit) { - hres = _unmarshal_interface(buf,&buf->iid,(LPUNKNOWN*)*arg); - if (hres) { - FIXME("_unmarshal_interface of %s , %p failed with %lx\n", debugstr_guid(&buf->iid), (LPUNKNOWN*)*arg, hres); - return hres; - } - } - if (debugout) TRACE_(olerelay)("ppv(%p)",(LPVOID)*arg); - return S_OK; -} - -static HRESULT -deserialize_DISPPARAM_ptr( - ITypeInfo *tinfo, - BOOL readit, - BOOL debugout, - BOOL alloc, - TYPEDESC *tdesc, - DWORD *arg, - marshal_state *buf) -{ - DWORD cookie; - DISPPARAMS *disps; - HRESULT hres; - int i; - - if ((tdesc->vt != VT_PTR) || (tdesc->u.lptdesc->vt != VT_USERDEFINED)) { - FIXME("DISPPARAMS not expressed as VT_PTR -> VT_USERDEFINED?\n"); - return E_FAIL; - } - if (readit) { - hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie)); - if (hres) - return hres; - if (cookie == 0) { - *arg = 0; - if (debugout) TRACE_(olerelay)("<DISPPARAMS NULL>"); - return S_OK; - } - } - if (alloc) - *arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPPARAMS)); - disps = (DISPPARAMS*)*arg; - if (!readit) - return S_OK; - hres = xbuf_get(buf, (LPBYTE)&disps->cArgs, sizeof(disps->cArgs)); - if (hres) - return hres; - if (alloc) - disps->rgvarg = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(VARIANT)*disps->cArgs); - if (debugout) TRACE_(olerelay)("D{"); - for (i=0; i< disps->cArgs; i++) { - TYPEDESC vdesc; - - vdesc.vt = VT_VARIANT; - hres = deserialize_param( - tinfo, - readit, - debugout, - alloc, - &vdesc, - (DWORD*)(disps->rgvarg+i), - buf - ); - } - if (debugout) TRACE_(olerelay)("}{"); - hres = xbuf_get(buf, (LPBYTE)&disps->cNamedArgs, sizeof(disps->cNamedArgs)); - if (hres) - return hres; - if (disps->cNamedArgs) { - if (alloc) - disps->rgdispidNamedArgs = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPID)*disps->cNamedArgs); - for (i=0; i< disps->cNamedArgs; i++) { - TYPEDESC vdesc; - - vdesc.vt = VT_UINT; - hres = deserialize_param( - tinfo, - readit, - debugout, - alloc, - &vdesc, - (DWORD*)(disps->rgdispidNamedArgs+i), - buf - ); - if (debugout && i<(disps->cNamedArgs-1)) TRACE_(olerelay)(","); - } - } - if (debugout) TRACE_(olerelay)("}"); - return S_OK; -} - -/* Searches function, also in inherited interfaces */ -static HRESULT -_get_funcdesc( - ITypeInfo *tinfo, int iMethod, FUNCDESC **fdesc, BSTR *iname, BSTR *fname) -{ - int i = 0, j = 0; - HRESULT hres; - - if (fname) *fname = NULL; - if (iname) *iname = NULL; - - while (1) { - hres = ITypeInfo_GetFuncDesc(tinfo, i, fdesc); - if (hres) { - ITypeInfo *tinfo2; - HREFTYPE href; - TYPEATTR *attr; - - hres = ITypeInfo_GetTypeAttr(tinfo, &attr); - if (hres) { - ERR("GetTypeAttr failed with %lx\n",hres); - return hres; - } - /* Not found, so look in inherited ifaces. */ - for (j=0;j<attr->cImplTypes;j++) { - hres = ITypeInfo_GetRefTypeOfImplType(tinfo, j, &href); - if (hres) { - ERR("Did not find a reftype for interface offset %d?\n",j); - break; - } - hres = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2); - if (hres) { - ERR("Did not find a typeinfo for reftype %ld?\n",href); - continue; - } - hres = _get_funcdesc(tinfo2,iMethod,fdesc,iname,fname); - ITypeInfo_Release(tinfo2); - if (!hres) return S_OK; - } - return hres; - } - if (((*fdesc)->oVft/4) == iMethod) { - if (fname) - ITypeInfo_GetDocumentation(tinfo,(*fdesc)->memid,fname,NULL,NULL,NULL); - if (iname) - ITypeInfo_GetDocumentation(tinfo,-1,iname,NULL,NULL,NULL); - return S_OK; - } - i++; - } -} - -static DWORD -xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */) -{ - DWORD *args = ((DWORD*)&tpinfo)+1, *xargs; - FUNCDESC *fdesc; - HRESULT hres; - int i, relaydeb = TRACE_ON(olerelay); - marshal_state buf; - RPCOLEMESSAGE msg; - ULONG status; - BSTR fname,iname; - BSTR names[10]; - int nrofnames; - int is_idispatch_getidsofnames = 0; - DWORD remoteresult = 0; - - EnterCriticalSection(&tpinfo->crit); - - hres = _get_funcdesc(tpinfo->tinfo,method,&fdesc,&iname,&fname); - if (hres) { - ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method); - LeaveCriticalSection(&tpinfo->crit); - return E_FAIL; - } - - if (!tpinfo->chanbuf) - { - WARN("Tried to use disconnected proxy\n"); - LeaveCriticalSection(&tpinfo->crit); - return RPC_E_DISCONNECTED; - } - - if (relaydeb) { - TRACE_(olerelay)("->"); - if (iname) - TRACE_(olerelay)("%s:",relaystr(iname)); - if (fname) - TRACE_(olerelay)("%s(%d)",relaystr(fname),method); - else - TRACE_(olerelay)("%d",method); - TRACE_(olerelay)("("); - } - if (iname && fname && !lstrcmpW(iname,IDispatchW) && !lstrcmpW(fname,GetIDsOfNamesW)) - is_idispatch_getidsofnames = 1; - - if (iname) SysFreeString(iname); - if (fname) SysFreeString(fname); - - memset(&buf,0,sizeof(buf)); - buf.iid = IID_IUnknown; - - /* Special IDispatch::GetIDsOfNames() serializer */ - if (is_idispatch_getidsofnames) { - hres = serialize_IDispatch_GetIDsOfNames(TRUE,relaydeb,args,&buf); - if (hres != S_OK) { - FIXME("serialize of IDispatch::GetIDsOfNames failed!\n"); - return hres; - } - goto afterserialize; - } - - /* special QueryInterface serialize */ - if (method == 0) { - xbuf_add(&buf,(LPBYTE)args[0],sizeof(IID)); - if (relaydeb) TRACE_(olerelay)("riid=%s,[out])",debugstr_guid((REFIID)args[0])); - goto afterserialize; - } - - /* normal typelib driven serializing */ - - /* Need them for hack below */ - memset(names,0,sizeof(names)); - if (ITypeInfo_GetNames(tpinfo->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames)) - nrofnames = 0; - if (nrofnames > sizeof(names)/sizeof(names[0])) - ERR("Need more names!\n"); - - xargs = args; - for (i=0;i<fdesc->cParams;i++) { - ELEMDESC *elem = fdesc->lprgelemdescParam+i; - BOOL isserialized = FALSE; - if (relaydeb) { - if (i) TRACE_(olerelay)(","); - if (i+1<nrofnames && names[i+1]) - TRACE_(olerelay)("%s=",relaystr(names[i+1])); - } - /* No need to marshal other data than FIN and any VT_PTR. */ - if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN) && (elem->tdesc.vt != VT_PTR)) { - xargs+=_argsize(elem->tdesc.vt); - if (relaydeb) TRACE_(olerelay)("[out]"); - continue; - } - if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) { - /* If the parameter is 'riid', we use it as interface IID - * for a later ppvObject serialization. - */ - buf.thisisiid = !lstrcmpW(names[i+1],riidW); - - /* DISPPARAMS* needs special serializer */ - if (!lstrcmpW(names[i+1],pdispparamsW)) { - hres = serialize_DISPPARAM_ptr( - tpinfo->tinfo, - elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN, - relaydeb, - FALSE, - &elem->tdesc, - xargs, - &buf - ); - isserialized = TRUE; - } - if (!lstrcmpW(names[i+1],ppvObjectW)) { - hres = serialize_LPVOID_ptr( - tpinfo->tinfo, - elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN, - relaydeb, - FALSE, - &elem->tdesc, - xargs, - &buf - ); - if (hres == S_OK) - isserialized = TRUE; - } - } - if (!isserialized) - hres = serialize_param( - tpinfo->tinfo, - elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN, - relaydeb, - FALSE, - &elem->tdesc, - xargs, - &buf - ); - - if (hres) { - ERR("Failed to serialize param, hres %lx\n",hres); - break; - } - xargs+=_argsize(elem->tdesc.vt); - } - if (relaydeb) TRACE_(olerelay)(")"); - -afterserialize: - memset(&msg,0,sizeof(msg)); - msg.cbBuffer = buf.curoff; - msg.iMethod = method; - hres = IRpcChannelBuffer_GetBuffer(tpinfo->chanbuf,&msg,&(tpinfo->iid)); - if (hres) { - ERR("RpcChannelBuffer GetBuffer failed, %lx\n",hres); - LeaveCriticalSection(&tpinfo->crit); - return hres; - } - memcpy(msg.Buffer,buf.base,buf.curoff); - if (relaydeb) TRACE_(olerelay)("\n"); - hres = IRpcChannelBuffer_SendReceive(tpinfo->chanbuf,&msg,&status); - if (hres) { - ERR("RpcChannelBuffer SendReceive failed, %lx\n",hres); - LeaveCriticalSection(&tpinfo->crit); - return hres; - } - - if (relaydeb) TRACE_(olerelay)(" status = %08lx (",status); - if (buf.base) - buf.base = HeapReAlloc(GetProcessHeap(),0,buf.base,msg.cbBuffer); - else - buf.base = HeapAlloc(GetProcessHeap(),0,msg.cbBuffer); - buf.size = msg.cbBuffer; - memcpy(buf.base,msg.Buffer,buf.size); - buf.curoff = 0; - - /* Special IDispatch::GetIDsOfNames() deserializer */ - if (is_idispatch_getidsofnames) { - hres = deserialize_IDispatch_GetIDsOfNames(FALSE,relaydeb,args,&buf); - if (hres != S_OK) { - FIXME("deserialize of IDispatch::GetIDsOfNames failed!\n"); - return hres; - } - goto after_deserialize; - } - /* Special QueryInterface deserializer */ - if (method == 0) { - _unmarshal_interface(&buf,(REFIID)args[0],(LPUNKNOWN*)args[1]); - if (relaydeb) TRACE_(olerelay)("[in],%p",*((DWORD**)args[1])); - goto after_deserialize; - } - - /* generic deserializer using typelib description */ - xargs = args; - status = S_OK; - for (i=0;i<fdesc->cParams;i++) { - ELEMDESC *elem = fdesc->lprgelemdescParam+i; - BOOL isdeserialized = FALSE; - - if (relaydeb) { - if (i) TRACE_(olerelay)(","); - if (i+1<nrofnames && names[i+1]) TRACE_(olerelay)("%s=",relaystr(names[i+1])); - } - /* No need to marshal other data than FOUT and any VT_PTR */ - if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) && (elem->tdesc.vt != VT_PTR)) { - xargs += _argsize(elem->tdesc.vt); - if (relaydeb) TRACE_(olerelay)("[in]"); - continue; - } - if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) { - /* If the parameter is 'riid', we use it as interface IID - * for a later ppvObject serialization. - */ - buf.thisisiid = !lstrcmpW(names[i+1],riidW); - - /* deserialize DISPPARAM */ - if (!lstrcmpW(names[i+1],pdispparamsW)) { - hres = deserialize_DISPPARAM_ptr( - tpinfo->tinfo, - elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT, - relaydeb, - FALSE, - &(elem->tdesc), - xargs, - &buf - ); - if (hres) { - ERR("Failed to deserialize DISPPARAM*, hres %lx\n",hres); - break; - } - isdeserialized = TRUE; - } - if (!lstrcmpW(names[i+1],ppvObjectW)) { - hres = deserialize_LPVOID_ptr( - tpinfo->tinfo, - elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT, - relaydeb, - FALSE, - &elem->tdesc, - xargs, - &buf - ); - if (hres == S_OK) - isdeserialized = TRUE; - } - } - if (!isdeserialized) - hres = deserialize_param( - tpinfo->tinfo, - elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT, - relaydeb, - FALSE, - &(elem->tdesc), - xargs, - &buf - ); - if (hres) { - ERR("Failed to unmarshall param, hres %lx\n",hres); - status = hres; - break; - } - xargs += _argsize(elem->tdesc.vt); - } -after_deserialize: - hres = xbuf_get(&buf, (LPBYTE)&remoteresult, sizeof(DWORD)); - if (hres != S_OK) - return hres; - if (relaydeb) TRACE_(olerelay)(") = %08lx\n", remoteresult); - - if (status != S_OK) /* OLE/COM internal error */ - return status; - - HeapFree(GetProcessHeap(),0,buf.base); - LeaveCriticalSection(&tpinfo->crit); - return remoteresult; -} - -HRESULT WINAPI ProxyIUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) -{ - TMProxyImpl *proxy = (TMProxyImpl *)iface; - - TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); - - if (proxy->outerunknown) - return IUnknown_QueryInterface(proxy->outerunknown, riid, ppv); - - FIXME("No interface\n"); - return E_NOINTERFACE; -} - -ULONG WINAPI ProxyIUnknown_AddRef(IUnknown *iface) -{ - TMProxyImpl *proxy = (TMProxyImpl *)iface; - - TRACE("\n"); - - if (proxy->outerunknown) - return IUnknown_AddRef(proxy->outerunknown); - - return 2; /* FIXME */ -} - -ULONG WINAPI ProxyIUnknown_Release(IUnknown *iface) -{ - TMProxyImpl *proxy = (TMProxyImpl *)iface; - - TRACE("\n"); - - if (proxy->outerunknown) - return IUnknown_Release(proxy->outerunknown); - - return 1; /* FIXME */ -} - -static HRESULT WINAPI -PSFacBuf_CreateProxy( - LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid, - IRpcProxyBuffer **ppProxy, LPVOID *ppv) -{ - HRESULT hres; - ITypeInfo *tinfo; - int i, nroffuncs; - FUNCDESC *fdesc; - TMProxyImpl *proxy; - - TRACE("(...%s...)\n",debugstr_guid(riid)); - hres = _get_typeinfo_for_iid(riid,&tinfo); - if (hres) { - ERR("No typeinfo for %s?\n",debugstr_guid(riid)); - return hres; - } - nroffuncs = _nroffuncs(tinfo); - proxy = CoTaskMemAlloc(sizeof(TMProxyImpl)); - if (!proxy) return E_OUTOFMEMORY; - - assert(sizeof(TMAsmProxy) == 12); - - proxy->outerunknown = pUnkOuter; - proxy->asmstubs = VirtualAlloc(NULL, sizeof(TMAsmProxy) * nroffuncs, MEM_COMMIT, PAGE_EXECUTE_READWRITE); - if (!proxy->asmstubs) { - ERR("Could not commit pages for proxy thunks\n"); - CoTaskMemFree(proxy); - return E_OUTOFMEMORY; - } - - InitializeCriticalSection(&proxy->crit); - - proxy->lpvtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPBYTE)*nroffuncs); - for (i=0;i<nroffuncs;i++) { - TMAsmProxy *xasm = proxy->asmstubs+i; - - switch (i) { - case 0: - proxy->lpvtbl[i] = ProxyIUnknown_QueryInterface; - break; - case 1: - proxy->lpvtbl[i] = ProxyIUnknown_AddRef; - break; - case 2: - proxy->lpvtbl[i] = ProxyIUnknown_Release; - break; - default: { - int j; - /* nrofargs without This */ - int nrofargs; - hres = _get_funcdesc(tinfo,i,&fdesc,NULL,NULL); - if (hres) { - ERR("GetFuncDesc %lx should not fail here.\n",hres); - return hres; - } - /* some args take more than 4 byte on the stack */ - nrofargs = 0; - for (j=0;j<fdesc->cParams;j++) - nrofargs += _argsize(fdesc->lprgelemdescParam[j].tdesc.vt); - - if (fdesc->callconv != CC_STDCALL) { - ERR("calling convention is not stdcall????\n"); - return E_FAIL; - } -/* popl %eax - return ptr - * pushl <nr> - * pushl %eax - * call xCall - * lret <nr> (+4) - * - * - * arg3 arg2 arg1 <method> <returnptr> - */ - xasm->popleax = 0x58; - xasm->pushlval = 0x6a; - xasm->nr = i; - xasm->pushleax = 0x50; - xasm->lcall = 0xe8; /* relative jump */ - xasm->xcall = (DWORD)xCall; - xasm->xcall -= (DWORD)&(xasm->lret); - xasm->lret = 0xc2; - xasm->bytestopop= (nrofargs+2)*4; /* pop args, This, iMethod */ - proxy->lpvtbl[i] = xasm; - break; - } - } - } - proxy->lpvtbl2 = &tmproxyvtable; - /* 1 reference for the proxy and 1 for the object */ - proxy->ref = 2; - proxy->tinfo = tinfo; - memcpy(&proxy->iid,riid,sizeof(*riid)); - proxy->chanbuf = 0; - *ppv = (LPVOID)proxy; - *ppProxy = (IRpcProxyBuffer *)&(proxy->lpvtbl2); - return S_OK; -} - -typedef struct _TMStubImpl { - IRpcStubBufferVtbl *lpvtbl; - ULONG ref; - - LPUNKNOWN pUnk; - ITypeInfo *tinfo; - IID iid; -} TMStubImpl; - -static HRESULT WINAPI -TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv) -{ - if (IsEqualIID(riid,&IID_IRpcStubBuffer)||IsEqualIID(riid,&IID_IUnknown)){ - *ppv = (LPVOID)iface; - IRpcStubBuffer_AddRef(iface); - return S_OK; - } - FIXME("%s, not supported IID.\n",debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI -TMStubImpl_AddRef(LPRPCSTUBBUFFER iface) -{ - TMStubImpl *This = (TMStubImpl *)iface; - ULONG refCount = InterlockedIncrement(&This->ref); - - TRACE("(%p)->(ref before=%lu)\n", This, refCount - 1); - - return refCount; -} - -static ULONG WINAPI -TMStubImpl_Release(LPRPCSTUBBUFFER iface) -{ - TMStubImpl *This = (TMStubImpl *)iface; - ULONG refCount = InterlockedDecrement(&This->ref); - - TRACE("(%p)->(ref before=%lu)\n", This, refCount + 1); - - if (!refCount) - { - IRpcStubBuffer_Disconnect(iface); - CoTaskMemFree(This); - } - return refCount; -} - -static HRESULT WINAPI -TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer) -{ - TMStubImpl *This = (TMStubImpl *)iface; - - TRACE("(%p)->(%p)\n", This, pUnkServer); - - IUnknown_AddRef(pUnkServer); - This->pUnk = pUnkServer; - return S_OK; -} - -static void WINAPI -TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface) -{ - TMStubImpl *This = (TMStubImpl *)iface; - - TRACE("(%p)->()\n", This); - - IUnknown_Release(This->pUnk); - This->pUnk = NULL; - return; -} - -static HRESULT WINAPI -TMStubImpl_Invoke( - LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf) -{ - int i; - FUNCDESC *fdesc; - TMStubImpl *This = (TMStubImpl *)iface; - HRESULT hres; - DWORD *args, res, *xargs, nrofargs; - marshal_state buf; - int nrofnames; - BSTR names[10]; - BSTR fname = NULL,iname = NULL; - BOOL is_idispatch_getidsofnames = 0; - - memset(&buf,0,sizeof(buf)); - buf.size = xmsg->cbBuffer; - buf.base = HeapAlloc(GetProcessHeap(), 0, xmsg->cbBuffer); - memcpy(buf.base, xmsg->Buffer, xmsg->cbBuffer); - buf.curoff = 0; - buf.iid = IID_IUnknown; - - TRACE("...\n"); - if (xmsg->iMethod == 0) { /* QI */ - IID xiid; - /* in: IID, out: <iface> */ - - xbuf_get(&buf,(LPBYTE)&xiid,sizeof(xiid)); - buf.curoff = 0; - hres = _marshal_interface(&buf,&xiid,This->pUnk); - xmsg->Buffer = buf.base; /* Might have been reallocated */ - xmsg->cbBuffer = buf.size; - return hres; - } - hres = _get_funcdesc(This->tinfo,xmsg->iMethod,&fdesc,&iname,&fname); - if (hres) { - ERR("GetFuncDesc on method %ld failed with %lx\n",xmsg->iMethod,hres); - return hres; - } - - if (iname && fname && !lstrcmpW(iname, IDispatchW) && !lstrcmpW(fname, GetIDsOfNamesW)) - is_idispatch_getidsofnames = 1; - - if (iname) SysFreeString (iname); - if (fname) SysFreeString (fname); - - /* Need them for hack below */ - memset(names,0,sizeof(names)); - ITypeInfo_GetNames(This->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames); - if (nrofnames > sizeof(names)/sizeof(names[0])) { - ERR("Need more names!\n"); - } - - /*dump_FUNCDESC(fdesc);*/ - nrofargs = 0; - for (i=0;i<fdesc->cParams;i++) - nrofargs += _argsize(fdesc->lprgelemdescParam[i].tdesc.vt); - args = HeapAlloc(GetProcessHeap(),0,(nrofargs+1)*sizeof(DWORD)); - if (!args) return E_OUTOFMEMORY; - - if (is_idispatch_getidsofnames) { - hres = deserialize_IDispatch_GetIDsOfNames(TRUE,FALSE,args+1,&buf); - if (hres != S_OK) { - FIXME("deserialize_IDispatch_GetIDsOfNames failed!\n"); - return hres; - } - xargs = args+1+5; - goto afterdeserialize; - } - - /* Allocate all stuff used by call. */ - xargs = args+1; - for (i=0;i<fdesc->cParams;i++) { - ELEMDESC *elem = fdesc->lprgelemdescParam+i; - BOOL isdeserialized = FALSE; - - if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) { - /* If the parameter is 'riid', we use it as interface IID - * for a later ppvObject serialization. - */ - buf.thisisiid = !lstrcmpW(names[i+1],riidW); - - /* deserialize DISPPARAM */ - if (!lstrcmpW(names[i+1],pdispparamsW)) { - hres = deserialize_DISPPARAM_ptr( - This->tinfo, - elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN, - FALSE, - TRUE, - &(elem->tdesc), - xargs, - &buf - ); - if (hres) { - ERR("Failed to deserialize DISPPARAM*, hres %lx\n",hres); - break; - } - isdeserialized = TRUE; - } - if (!lstrcmpW(names[i+1],ppvObjectW)) { - hres = deserialize_LPVOID_ptr( - This->tinfo, - elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN, - FALSE, - TRUE, - &elem->tdesc, - xargs, - &buf - ); - if (hres == S_OK) - isdeserialized = TRUE; - } - } - if (!isdeserialized) - hres = deserialize_param( - This->tinfo, - elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN, - FALSE, - TRUE, - &(elem->tdesc), - xargs, - &buf - ); - xargs += _argsize(elem->tdesc.vt); - if (hres) { - ERR("Failed to deserialize param %s, hres %lx\n",relaystr(names[i+1]),hres); - break; - } - } -afterdeserialize: - hres = IUnknown_QueryInterface(This->pUnk,&(This->iid),(LPVOID*)&(args[0])); - if (hres) { - ERR("Does not support iface %s, returning %lx\n",debugstr_guid(&(This->iid)), hres); - return hres; - } - res = _invoke( - (*((FARPROC**)args[0]))[fdesc->oVft/4], - fdesc->callconv, - (xargs-args), - args - ); - IUnknown_Release((LPUNKNOWN)args[0]); - buf.curoff = 0; - - /* special IDispatch::GetIDsOfNames serializer */ - if (is_idispatch_getidsofnames) { - hres = serialize_IDispatch_GetIDsOfNames(FALSE,FALSE,args+1,&buf); - if (hres != S_OK) { - FIXME("serialize of IDispatch::GetIDsOfNames failed!\n"); - return hres; - } - goto afterserialize; - } - xargs = args+1; - for (i=0;i<fdesc->cParams;i++) { - ELEMDESC *elem = fdesc->lprgelemdescParam+i; - BOOL isserialized = FALSE; - - if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) { - /* If the parameter is 'riid', we use it as interface IID - * for a later ppvObject serialization. - */ - buf.thisisiid = !lstrcmpW(names[i+1],riidW); - - /* DISPPARAMS* needs special serializer */ - if (!lstrcmpW(names[i+1],pdispparamsW)) { - hres = serialize_DISPPARAM_ptr( - This->tinfo, - elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT, - FALSE, - TRUE, - &elem->tdesc, - xargs, - &buf - ); - isserialized = TRUE; - } - if (!lstrcmpW(names[i+1],ppvObjectW)) { - hres = serialize_LPVOID_ptr( - This->tinfo, - elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT, - FALSE, - TRUE, - &elem->tdesc, - xargs, - &buf - ); - if (hres == S_OK) - isserialized = TRUE; - } - } - if (!isserialized) - hres = serialize_param( - This->tinfo, - elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT, - FALSE, - TRUE, - &elem->tdesc, - xargs, - &buf - ); - xargs += _argsize(elem->tdesc.vt); - if (hres) { - ERR("Failed to stuballoc param, hres %lx\n",hres); - break; - } - } -afterserialize: - hres = xbuf_add (&buf, (LPBYTE)&res, sizeof(DWORD)); - if (hres != S_OK) - return hres; - - xmsg->cbBuffer = buf.curoff; - I_RpcGetBuffer((RPC_MESSAGE *)xmsg); - memcpy(xmsg->Buffer, buf.base, buf.curoff); - HeapFree(GetProcessHeap(),0,args); - return S_OK; -} - -static LPRPCSTUBBUFFER WINAPI -TMStubImpl_IsIIDSupported(LPRPCSTUBBUFFER iface, REFIID riid) { - FIXME("Huh (%s)?\n",debugstr_guid(riid)); - return NULL; -} - -static ULONG WINAPI -TMStubImpl_CountRefs(LPRPCSTUBBUFFER iface) { - TMStubImpl *This = (TMStubImpl *)iface; - - return This->ref; /*FIXME? */ -} - -static HRESULT WINAPI -TMStubImpl_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, LPVOID *ppv) { - return E_NOTIMPL; -} - -static void WINAPI -TMStubImpl_DebugServerRelease(LPRPCSTUBBUFFER iface, LPVOID ppv) { - return; -} - -IRpcStubBufferVtbl tmstubvtbl = { - TMStubImpl_QueryInterface, - TMStubImpl_AddRef, - TMStubImpl_Release, - TMStubImpl_Connect, - TMStubImpl_Disconnect, - TMStubImpl_Invoke, - TMStubImpl_IsIIDSupported, - TMStubImpl_CountRefs, - TMStubImpl_DebugServerQueryInterface, - TMStubImpl_DebugServerRelease -}; - -static HRESULT WINAPI -PSFacBuf_CreateStub( - LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer, - IRpcStubBuffer** ppStub -) { - HRESULT hres; - ITypeInfo *tinfo; - TMStubImpl *stub; - - TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub); - hres = _get_typeinfo_for_iid(riid,&tinfo); - if (hres) { - ERR("No typeinfo for %s?\n",debugstr_guid(riid)); - return hres; - } - stub = CoTaskMemAlloc(sizeof(TMStubImpl)); - if (!stub) - return E_OUTOFMEMORY; - stub->lpvtbl = &tmstubvtbl; - stub->ref = 1; - stub->tinfo = tinfo; - memcpy(&(stub->iid),riid,sizeof(*riid)); - hres = IRpcStubBuffer_Connect((LPRPCSTUBBUFFER)stub,pUnkServer); - *ppStub = (LPRPCSTUBBUFFER)stub; - TRACE("IRpcStubBuffer: %p\n", stub); - if (hres) - ERR("Connect to pUnkServer failed?\n"); - return hres; -} - -static IPSFactoryBufferVtbl psfacbufvtbl = { - PSFacBuf_QueryInterface, - PSFacBuf_AddRef, - PSFacBuf_Release, - PSFacBuf_CreateProxy, - PSFacBuf_CreateStub -}; - -/* This is the whole PSFactoryBuffer object, just the vtableptr */ -static IPSFactoryBufferVtbl *lppsfac = &psfacbufvtbl; - -/*********************************************************************** - * DllGetClassObject [OLE32.63] - */ -HRESULT WINAPI -TypeLibFac_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv) -{ - if (IsEqualIID(iid,&IID_IPSFactoryBuffer)) { - *ppv = &lppsfac; - return S_OK; - } - return E_NOINTERFACE; -} +/* + * TYPELIB Marshaler + * + * Copyright 2002,2005 Marcus Meissner + * + * The olerelay debug channel allows you to see calls marshalled by + * the typelib marshaller. It is not a generic COM relaying system. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <stdio.h> +#include <ctype.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "winerror.h" +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winreg.h" +#include "winuser.h" + +#include "ole2.h" +#include "typelib.h" +#include "wine/debug.h" + +static const WCHAR riidW[5] = {'r','i','i','d',0}; +static const WCHAR pdispparamsW[] = {'p','d','i','s','p','p','a','r','a','m','s',0}; +static const WCHAR ppvObjectW[] = {'p','p','v','O','b','j','e','c','t',0}; +static const WCHAR IDispatchW[] = { 'I','D','i','s','p','a','t','c','h',0}; +static const WCHAR GetIDsOfNamesW[] = { 'G','e','t','I','D','s','O','f','N','a','m','e','s',0}; + +WINE_DEFAULT_DEBUG_CHANNEL(ole); +WINE_DECLARE_DEBUG_CHANNEL(olerelay); + +#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) + +typedef struct _marshal_state { + LPBYTE base; + int size; + int curoff; + + BOOL thisisiid; + IID iid; /* HACK: for VT_VOID */ +} marshal_state; + +/* used in the olerelay code to avoid having the L"" stuff added by debugstr_w */ +static char *relaystr(WCHAR *in) { + char *tmp = (char *)debugstr_w(in); + tmp += 2; + tmp[strlen(tmp)-1] = '\0'; + return tmp; +} + +static HRESULT +xbuf_add(marshal_state *buf, LPBYTE stuff, DWORD size) { + while (buf->size - buf->curoff < size) { + if (buf->base) { + buf->size += 100; + buf->base = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,buf->base,buf->size); + if (!buf->base) + return E_OUTOFMEMORY; + } else { + buf->base = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,32); + buf->size = 32; + if (!buf->base) + return E_OUTOFMEMORY; + } + } + memcpy(buf->base+buf->curoff,stuff,size); + buf->curoff += size; + return S_OK; +} + +static HRESULT +xbuf_get(marshal_state *buf, LPBYTE stuff, DWORD size) { + if (buf->size < buf->curoff+size) return E_FAIL; + memcpy(stuff,buf->base+buf->curoff,size); + buf->curoff += size; + return S_OK; +} + +static HRESULT +xbuf_skip(marshal_state *buf, DWORD size) { + if (buf->size < buf->curoff+size) return E_FAIL; + buf->curoff += size; + return S_OK; +} + +static HRESULT +_unmarshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN *pUnk) { + IStream *pStm; + ULARGE_INTEGER newpos; + LARGE_INTEGER seekto; + ULONG res; + HRESULT hres; + DWORD xsize; + + TRACE("...%s...\n",debugstr_guid(riid)); + + *pUnk = NULL; + hres = xbuf_get(buf,(LPBYTE)&xsize,sizeof(xsize)); + if (hres) { + ERR("xbuf_get failed\n"); + return hres; + } + + if (xsize == 0) return S_OK; + + hres = CreateStreamOnHGlobal(0,TRUE,&pStm); + if (hres) { + ERR("Stream create failed %lx\n",hres); + return hres; + } + + hres = IStream_Write(pStm,buf->base+buf->curoff,xsize,&res); + if (hres) { + ERR("stream write %lx\n",hres); + return hres; + } + + memset(&seekto,0,sizeof(seekto)); + hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); + if (hres) { + ERR("Failed Seek %lx\n",hres); + return hres; + } + + hres = CoUnmarshalInterface(pStm,riid,(LPVOID*)pUnk); + if (hres) { + ERR("Unmarshalling interface %s failed with %lx\n",debugstr_guid(riid),hres); + return hres; + } + + IStream_Release(pStm); + return xbuf_skip(buf,xsize); +} + +static HRESULT +_marshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN pUnk) { + LPUNKNOWN newiface = NULL; + LPBYTE tempbuf = NULL; + IStream *pStm = NULL; + STATSTG ststg; + ULARGE_INTEGER newpos; + LARGE_INTEGER seekto; + ULONG res; + DWORD xsize; + HRESULT hres; + + if (!pUnk) { + /* this is valid, if for instance we serialize + * a VT_DISPATCH with NULL ptr which apparently + * can happen. S_OK to make sure we continue + * serializing. + */ + ERR("pUnk is NULL?\n"); + xsize = 0; + return xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize)); + } + + hres = E_FAIL; + + TRACE("...%s...\n",debugstr_guid(riid)); + hres = IUnknown_QueryInterface(pUnk,riid,(LPVOID*)&newiface); + if (hres) { + WARN("%p does not support iface %s\n",pUnk,debugstr_guid(riid)); + goto fail; + } + + hres = CreateStreamOnHGlobal(0,TRUE,&pStm); + if (hres) { + ERR("Stream create failed %lx\n",hres); + goto fail; + } + + hres = CoMarshalInterface(pStm,riid,newiface,0,NULL,0); + if (hres) { + ERR("Marshalling interface %s failed with %lx\n", debugstr_guid(riid), hres); + goto fail; + } + + hres = IStream_Stat(pStm,&ststg,0); + if (hres) { + ERR("Stream stat failed\n"); + goto fail; + } + + tempbuf = HeapAlloc(GetProcessHeap(), 0, ststg.cbSize.u.LowPart); + memset(&seekto,0,sizeof(seekto)); + hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); + if (hres) { + ERR("Failed Seek %lx\n",hres); + goto fail; + } + + hres = IStream_Read(pStm,tempbuf,ststg.cbSize.u.LowPart,&res); + if (hres) { + ERR("Failed Read %lx\n",hres); + goto fail; + } + + xsize = ststg.cbSize.u.LowPart; + xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize)); + hres = xbuf_add(buf,tempbuf,ststg.cbSize.u.LowPart); + + HeapFree(GetProcessHeap(),0,tempbuf); + IUnknown_Release(newiface); + IStream_Release(pStm); + + return hres; + +fail: + xsize = 0; + xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize)); + if (pStm) IUnknown_Release(pStm); + if (newiface) IUnknown_Release(newiface); + HeapFree(GetProcessHeap(), 0, tempbuf); + return hres; +} + +/********************* OLE Proxy/Stub Factory ********************************/ +static HRESULT WINAPI +PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) { + if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) { + *ppv = (LPVOID)iface; + /* No ref counting, static class */ + return S_OK; + } + FIXME("(%s) unknown IID?\n",debugstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; } +static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; } + +static HRESULT +_get_typeinfo_for_iid(REFIID riid, ITypeInfo**ti) { + HRESULT hres; + HKEY ikey; + char tlguid[200],typelibkey[300],interfacekey[300],ver[100]; + char tlfn[260]; + OLECHAR tlfnW[260]; + DWORD tlguidlen, verlen, type, tlfnlen; + ITypeLib *tl; + + sprintf( interfacekey, "Interface\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\Typelib", + riid->Data1, riid->Data2, riid->Data3, + riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3], + riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7] + ); + + if (RegOpenKeyA(HKEY_CLASSES_ROOT,interfacekey,&ikey)) { + ERR("No %s key found.\n",interfacekey); + return E_FAIL; + } + type = (1<<REG_SZ); + tlguidlen = sizeof(tlguid); + if (RegQueryValueExA(ikey,NULL,NULL,&type,tlguid,&tlguidlen)) { + ERR("Getting typelib guid failed.\n"); + RegCloseKey(ikey); + return E_FAIL; + } + type = (1<<REG_SZ); + verlen = sizeof(ver); + if (RegQueryValueExA(ikey,"Version",NULL,&type,ver,&verlen)) { + ERR("Could not get version value?\n"); + RegCloseKey(ikey); + return E_FAIL; + } + RegCloseKey(ikey); + sprintf(typelibkey,"Typelib\\%s\\%s\\0\\win32",tlguid,ver); + tlfnlen = sizeof(tlfn); + if (RegQueryValueA(HKEY_CLASSES_ROOT,typelibkey,tlfn,&tlfnlen)) { + ERR("Could not get typelib fn?\n"); + return E_FAIL; + } + MultiByteToWideChar(CP_ACP, 0, tlfn, -1, tlfnW, -1); + hres = LoadTypeLib(tlfnW,&tl); + if (hres) { + ERR("Failed to load typelib for %s, but it should be there.\n",debugstr_guid(riid)); + return hres; + } + hres = ITypeLib_GetTypeInfoOfGuid(tl,riid,ti); + if (hres) { + ERR("typelib does not contain info for %s?\n",debugstr_guid(riid)); + ITypeLib_Release(tl); + return hres; + } + /* FIXME: do this? ITypeLib_Release(tl); */ + return hres; +} + +/* Determine nr of functions. Since we use the toplevel interface and all + * inherited ones have lower numbers, we are ok to not to descent into + * the inheritance tree I think. + */ +static int _nroffuncs(ITypeInfo *tinfo) { + int n, max = 0; + FUNCDESC *fdesc; + HRESULT hres; + + n=0; + while (1) { + hres = ITypeInfo_GetFuncDesc(tinfo,n,&fdesc); + if (hres) + return max+1; + if (fdesc->oVft/4 > max) + max = fdesc->oVft/4; + n++; + } + /*NOTREACHED*/ +} + +#ifdef __i386__ + +#include "pshpack1.h" + +typedef struct _TMAsmProxy { + BYTE popleax; + BYTE pushlval; + BYTE nr; + BYTE pushleax; + BYTE lcall; + DWORD xcall; + BYTE lret; + WORD bytestopop; +} TMAsmProxy; + +#include "poppack.h" + +#else /* __i386__ */ +# error You need to implement stubless proxies for your architecture +#endif + +typedef struct _TMProxyImpl { + LPVOID *lpvtbl; + IRpcProxyBufferVtbl *lpvtbl2; + ULONG ref; + + TMAsmProxy *asmstubs; + ITypeInfo* tinfo; + IRpcChannelBuffer* chanbuf; + IID iid; + CRITICAL_SECTION crit; + IUnknown *outerunknown; +} TMProxyImpl; + +static HRESULT WINAPI +TMProxyImpl_QueryInterface(LPRPCPROXYBUFFER iface, REFIID riid, LPVOID *ppv) +{ + TRACE("()\n"); + if (IsEqualIID(riid,&IID_IUnknown)||IsEqualIID(riid,&IID_IRpcProxyBuffer)) { + *ppv = (LPVOID)iface; + IRpcProxyBuffer_AddRef(iface); + return S_OK; + } + FIXME("no interface for %s\n",debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI +TMProxyImpl_AddRef(LPRPCPROXYBUFFER iface) +{ + ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface); + ULONG refCount = InterlockedIncrement(&This->ref); + + TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1); + + return refCount; +} + +static ULONG WINAPI +TMProxyImpl_Release(LPRPCPROXYBUFFER iface) +{ + ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface); + ULONG refCount = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1); + + if (!refCount) + { + DeleteCriticalSection(&This->crit); + if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf); + VirtualFree(This->asmstubs, 0, MEM_RELEASE); + CoTaskMemFree(This); + } + return refCount; +} + +static HRESULT WINAPI +TMProxyImpl_Connect( + LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer) +{ + ICOM_THIS_MULTI(TMProxyImpl, lpvtbl2, iface); + + TRACE("(%p)\n", pRpcChannelBuffer); + + EnterCriticalSection(&This->crit); + + IRpcChannelBuffer_AddRef(pRpcChannelBuffer); + This->chanbuf = pRpcChannelBuffer; + + LeaveCriticalSection(&This->crit); + + return S_OK; +} + +static void WINAPI +TMProxyImpl_Disconnect(LPRPCPROXYBUFFER iface) +{ + ICOM_THIS_MULTI(TMProxyImpl, lpvtbl2, iface); + + TRACE("()\n"); + + EnterCriticalSection(&This->crit); + + IRpcChannelBuffer_Release(This->chanbuf); + This->chanbuf = NULL; + + LeaveCriticalSection(&This->crit); +} + + +static IRpcProxyBufferVtbl tmproxyvtable = { + TMProxyImpl_QueryInterface, + TMProxyImpl_AddRef, + TMProxyImpl_Release, + TMProxyImpl_Connect, + TMProxyImpl_Disconnect +}; + +/* how much space do we use on stack in DWORD steps. */ +int +_argsize(DWORD vt) { + switch (vt) { + case VT_DATE: + return sizeof(DATE)/sizeof(DWORD); + case VT_VARIANT: + return (sizeof(VARIANT)+3)/sizeof(DWORD); + default: + return 1; + } +} + +static int +_xsize(TYPEDESC *td) { + switch (td->vt) { + case VT_DATE: + return sizeof(DATE); + case VT_VARIANT: + return sizeof(VARIANT)+3; + case VT_CARRAY: { + int i, arrsize = 1; + ARRAYDESC *adesc = td->u.lpadesc; + + for (i=0;i<adesc->cDims;i++) + arrsize *= adesc->rgbounds[i].cElements; + return arrsize*_xsize(&adesc->tdescElem); + } + case VT_UI2: + case VT_I2: + return 2; + case VT_UI1: + case VT_I1: + return 1; + default: + return 4; + } +} + +static HRESULT +serialize_param( + ITypeInfo *tinfo, + BOOL writeit, + BOOL debugout, + BOOL dealloc, + TYPEDESC *tdesc, + DWORD *arg, + marshal_state *buf) +{ + HRESULT hres = S_OK; + + TRACE("(tdesc.vt %d)\n",tdesc->vt); + + switch (tdesc->vt) { + case VT_EMPTY: /* nothing. empty variant for instance */ + return S_OK; + case VT_BOOL: + case VT_ERROR: + case VT_UINT: + case VT_I4: + case VT_R4: + case VT_UI4: + hres = S_OK; + if (debugout) TRACE_(olerelay)("%lx",*arg); + if (writeit) + hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD)); + return hres; + case VT_I2: + case VT_UI2: + hres = S_OK; + if (debugout) TRACE_(olerelay)("%04lx",*arg & 0xffff); + if (writeit) + hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD)); + return hres; + case VT_I1: + case VT_UI1: + hres = S_OK; + if (debugout) TRACE_(olerelay)("%02lx",*arg & 0xff); + if (writeit) + hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD)); + return hres; + case VT_I4|VT_BYREF: + hres = S_OK; + if (debugout) TRACE_(olerelay)("&0x%lx",*arg); + if (writeit) + hres = xbuf_add(buf,(LPBYTE)(DWORD*)*arg,sizeof(DWORD)); + /* do not dealloc at this time */ + return hres; + case VT_VARIANT: { + TYPEDESC tdesc2; + VARIANT *vt = (VARIANT*)arg; + DWORD vttype = V_VT(vt); + + if (debugout) TRACE_(olerelay)("Vt(%ld)(",vttype); + tdesc2.vt = vttype; + if (writeit) { + hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype)); + if (hres) return hres; + } + /* need to recurse since we need to free the stuff */ + hres = serialize_param(tinfo,writeit,debugout,dealloc,&tdesc2,&(V_I4(vt)),buf); + if (debugout) TRACE_(olerelay)(")"); + return hres; + } + case VT_BSTR|VT_BYREF: { + if (debugout) TRACE_(olerelay)("[byref]'%s'", *(BSTR*)*arg ? relaystr(*((BSTR*)*arg)) : "<bstr NULL>"); + if (writeit) { + /* ptr to ptr to magic widestring, basically */ + BSTR *bstr = (BSTR *) *arg; + if (!*bstr) { + /* -1 means "null string" which is equivalent to empty string */ + DWORD fakelen = -1; + xbuf_add(buf, (LPBYTE)&fakelen,4); + } else { + /* BSTRs store the length behind the first character */ + DWORD *len = ((DWORD *)(*bstr))-1; + hres = xbuf_add(buf, (LPBYTE) len, *len + 4); + if (hres) return hres; + } + } + + if (dealloc && arg) { + BSTR *str = *((BSTR **)arg); + SysFreeString(*str); + } + return S_OK; + } + + case VT_BSTR: { + if (debugout) { + if (*arg) + TRACE_(olerelay)("%s",relaystr((WCHAR*)*arg)); + else + TRACE_(olerelay)("<bstr NULL>"); + } + if (writeit) { + if (!*arg) { + DWORD fakelen = -1; + hres = xbuf_add(buf,(LPBYTE)&fakelen,4); + if (hres) + return hres; + } else { + DWORD *bstr = ((DWORD*)(*arg))-1; + + hres = xbuf_add(buf,(LPBYTE)bstr,bstr[0]+4); + if (hres) + return hres; + } + } + + if (dealloc && arg) + SysFreeString((BSTR)*arg); + return S_OK; + } + case VT_PTR: { + DWORD cookie; + + if (debugout) TRACE_(olerelay)("*"); + /* Write always, so the other side knows when it gets a NULL pointer. + */ + cookie = *arg ? 0x42424242 : 0; + hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie)); + if (hres) + return hres; + if (!*arg) { + if (debugout) TRACE_(olerelay)("NULL"); + return S_OK; + } + hres = serialize_param(tinfo,writeit,debugout,dealloc,tdesc->u.lptdesc,(DWORD*)*arg,buf); + if (dealloc) HeapFree(GetProcessHeap(),0,(LPVOID)arg); + return hres; + } + case VT_UNKNOWN: + if (debugout) TRACE_(olerelay)("unk(0x%lx)",*arg); + if (writeit) + hres = _marshal_interface(buf,&IID_IUnknown,(LPUNKNOWN)*arg); + return hres; + case VT_DISPATCH: + if (debugout) TRACE_(olerelay)("idisp(0x%lx)",*arg); + if (writeit) + hres = _marshal_interface(buf,&IID_IDispatch,(LPUNKNOWN)*arg); + return hres; + case VT_VOID: + if (debugout) TRACE_(olerelay)("<void>"); + return S_OK; + case VT_USERDEFINED: { + ITypeInfo *tinfo2; + TYPEATTR *tattr; + + hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2); + if (hres) { + ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype); + return hres; + } + ITypeInfo_GetTypeAttr(tinfo2,&tattr); + switch (tattr->typekind) { + case TKIND_DISPATCH: + case TKIND_INTERFACE: + if (writeit) + hres=_marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg); + break; + case TKIND_RECORD: { + int i; + if (debugout) TRACE_(olerelay)("{"); + for (i=0;i<tattr->cVars;i++) { + VARDESC *vdesc; + ELEMDESC *elem2; + TYPEDESC *tdesc2; + + hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc); + if (hres) { + ERR("Could not get vardesc of %d\n",i); + return hres; + } + /* Need them for hack below */ + /* + memset(names,0,sizeof(names)); + hres = ITypeInfo_GetNames(tinfo2,vdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames); + if (nrofnames > sizeof(names)/sizeof(names[0])) { + ERR("Need more names!\n"); + } + if (!hres && debugout) + TRACE_(olerelay)("%s=",relaystr(names[0])); + */ + elem2 = &vdesc->elemdescVar; + tdesc2 = &elem2->tdesc; + hres = serialize_param( + tinfo2, + writeit, + debugout, + dealloc, + tdesc2, + (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst), + buf + ); + if (hres!=S_OK) + return hres; + if (debugout && (i<(tattr->cVars-1))) + TRACE_(olerelay)(","); + } + if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID))) + memcpy(&(buf->iid),arg,sizeof(buf->iid)); + if (debugout) TRACE_(olerelay)("}"); + break; + } + default: + FIXME("Unhandled typekind %d\n",tattr->typekind); + hres = E_FAIL; + break; + } + ITypeInfo_Release(tinfo2); + return hres; + } + case VT_CARRAY: { + ARRAYDESC *adesc = tdesc->u.lpadesc; + int i, arrsize = 1; + + if (debugout) TRACE_(olerelay)("carr"); + for (i=0;i<adesc->cDims;i++) { + if (debugout) TRACE_(olerelay)("[%ld]",adesc->rgbounds[i].cElements); + arrsize *= adesc->rgbounds[i].cElements; + } + if (debugout) TRACE_(olerelay)("(vt %d)",adesc->tdescElem.vt); + if (debugout) TRACE_(olerelay)("["); + for (i=0;i<arrsize;i++) { + hres = serialize_param(tinfo, writeit, debugout, dealloc, &adesc->tdescElem, (DWORD*)((LPBYTE)arg+i*_xsize(&adesc->tdescElem)), buf); + if (hres) + return hres; + if (debugout && (i<arrsize-1)) TRACE_(olerelay)(","); + } + if (debugout) TRACE_(olerelay)("]"); + return S_OK; + } + default: + ERR("Unhandled marshal type %d.\n",tdesc->vt); + return S_OK; + } +} + +/* IDL desc: + * HRESULT GetIDsOfNames( + * [in] REFIID riid, args[1] + * [in, size_is(cNames)] LPOLESTR *rgszNames, args[2] + * [in] UINT cNames, args[3] + * [in] LCID lcid, args[4] + * [out, size_is(cNames)] DISPID *rgDispId); args[5] + * + * line format: + * IID iid; + * DWORD cNames; + * LPOLESTR rgszNames[cNames]; + * DWORD bytestrlen (incl 0) + * BYTE data[bytestrlen] (incl 0) + * LCID + */ +static HRESULT +serialize_IDispatch_GetIDsOfNames( + BOOL inputparams, + BOOL debugout, + DWORD *args, + marshal_state *buf) +{ + HRESULT hres; + DWORD cNames = args[2]; + LPOLESTR *rgszNames = (LPOLESTR*)args[1]; + int i; + + if (inputparams) { + if (debugout) TRACE_(olerelay)("riid=%s,",debugstr_guid((REFIID)args[0])); + hres = xbuf_add(buf, (LPBYTE)args[0], sizeof(IID)); + if (hres) { + FIXME("serialize of IID failed.\n"); + return hres; + } + if (debugout) TRACE_(olerelay)("cNames=%ld,",cNames); + hres = xbuf_add(buf, (LPBYTE)&cNames, sizeof(DWORD)); + if (hres) { + FIXME("serialize of cNames failed.\n"); + return hres; + } + if (debugout) TRACE_(olerelay)("rgszNames=["); + for (i=0;i<cNames;i++) { + DWORD len = 2*(lstrlenW(rgszNames[i])+1); + + if (debugout) TRACE_(olerelay)("%s,",relaystr(rgszNames[i])); + hres = xbuf_add(buf, (LPBYTE)&len, sizeof(DWORD)); + if (hres) { + FIXME("serialize of len failed.\n"); + return hres; + } + hres = xbuf_add(buf, (LPBYTE)rgszNames[i], len); + if (hres) { + FIXME("serialize of rgszNames[i] failed.\n"); + return hres; + } + } + if (debugout) TRACE_(olerelay)("],lcid=%04lx)",args[3]); + hres = xbuf_add(buf, (LPBYTE)&args[3], sizeof(DWORD)); + if (hres) { + FIXME("serialize of lcid failed.\n"); + return hres; + } + } else { + DISPID *rgDispId = (DISPID*)args[4]; + + hres = xbuf_add(buf, (LPBYTE)rgDispId, sizeof(DISPID) * cNames); + if (hres) { + FIXME("serialize of rgDispId failed.\n"); + return hres; + } + if (debugout) { + TRACE_(olerelay)("riid=[in],rgszNames=[in],cNames=[in],rgDispId=["); + for (i=0;i<cNames;i++) + TRACE_(olerelay)("%08lx,",rgDispId[i]); + TRACE_(olerelay)("])"); + } + HeapFree(GetProcessHeap(),0,(IID*)args[0]); + rgszNames = (LPOLESTR*)args[1]; + for (i=0;i<cNames;i++) HeapFree(GetProcessHeap(),0,rgszNames[i]); + HeapFree(GetProcessHeap(),0,rgszNames); + HeapFree(GetProcessHeap(),0,rgDispId); + } + return S_OK; +} + +static HRESULT +deserialize_IDispatch_GetIDsOfNames( + BOOL inputparams, + BOOL debugout, + DWORD *args, + marshal_state *buf) +{ + HRESULT hres; + DWORD cNames; + LPOLESTR *rgszNames; + int i; + + if (inputparams) { + args[0] = (DWORD)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IID)); + if (!args[0]) return E_FAIL; + hres = xbuf_get(buf, (LPBYTE)args[0], sizeof(IID)); + if (hres) { + FIXME("deserialize of IID failed.\n"); + return hres; + } + if (debugout) TRACE_(olerelay)("riid=%s,",debugstr_guid((REFIID)args[0])); + + hres = xbuf_get(buf, (LPBYTE)&cNames, sizeof(DWORD)); + if (hres) { + FIXME("deserialize of cNames failed.\n"); + return hres; + } + args[2] = cNames; + if (debugout) TRACE_(olerelay)("cNames=%ld,",cNames); + if (debugout) TRACE_(olerelay)("rgszNames=["); + rgszNames = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LPOLESTR) * cNames); + if (!rgszNames) return E_FAIL; + args[1] = (DWORD)rgszNames; + for (i=0;i<cNames;i++) { + DWORD len; + + hres = xbuf_get(buf, (LPBYTE)&len, sizeof(DWORD)); + if (hres) { + FIXME("serialize of len failed.\n"); + return hres; + } + rgszNames[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len); + if (!rgszNames[i]) { + FIXME("heapalloc of %ld bytes failed\n", len); + return E_FAIL; + } + hres = xbuf_get(buf, (LPBYTE)rgszNames[i], len); + if (hres) { + FIXME("serialize of rgszNames[i] failed.\n"); + return hres; + } + if (debugout) TRACE_(olerelay)("%s,",relaystr(rgszNames[i])); + } + hres = xbuf_get(buf, (LPBYTE)&args[3], sizeof(DWORD)); + if (hres) { + FIXME("deserialize of lcid failed.\n"); + return hres; + } + if (debugout) TRACE_(olerelay)("],lcid=%04lx,rgDispId=[out])",args[3]); + args[4] = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPID) * cNames); + } else { + hres = xbuf_get(buf, (LPBYTE)args[4], sizeof(DISPID) * args[2]); + if (hres) { + FIXME("serialize of rgDispId failed.\n"); + return hres; + } + if (debugout) { + TRACE_(olerelay)("dispid=["); + for (i=0;i<args[2];i++) + TRACE_(olerelay)("%08lx,",((DISPID*)args[4])[i]); + TRACE_(olerelay)("])"); + } + } + return S_OK; +} + +static HRESULT +serialize_LPVOID_ptr( + ITypeInfo *tinfo, + BOOL writeit, + BOOL debugout, + BOOL dealloc, + TYPEDESC *tdesc, + DWORD *arg, + marshal_state *buf) +{ + HRESULT hres; + DWORD cookie; + + if ((tdesc->vt != VT_PTR) || + (tdesc->u.lptdesc->vt != VT_PTR) || + (tdesc->u.lptdesc->u.lptdesc->vt != VT_VOID) + ) { + FIXME("ppvObject not expressed as VT_PTR -> VT_PTR -> VT_VOID?\n"); + return E_FAIL; + } + cookie = (*(DWORD*)*arg) ? 0x42424242: 0x0; + if (writeit) { + hres = xbuf_add(buf, (LPVOID)&cookie, sizeof(cookie)); + if (hres) + return hres; + } + if (!*(DWORD*)*arg) { + if (debugout) TRACE_(olerelay)("<lpvoid NULL>"); + return S_OK; + } + if (debugout) + TRACE_(olerelay)("ppv(%p)",*(LPUNKNOWN*)*arg); + if (writeit) { + hres = _marshal_interface(buf,&(buf->iid),*(LPUNKNOWN*)*arg); + if (hres) + return hres; + } + if (dealloc) + HeapFree(GetProcessHeap(),0,(LPVOID)*arg); + return S_OK; +} + +static HRESULT +serialize_DISPPARAM_ptr( + ITypeInfo *tinfo, + BOOL writeit, + BOOL debugout, + BOOL dealloc, + TYPEDESC *tdesc, + DWORD *arg, + marshal_state *buf) +{ + DWORD cookie; + HRESULT hres; + DISPPARAMS *disp; + int i; + + if ((tdesc->vt != VT_PTR) || (tdesc->u.lptdesc->vt != VT_USERDEFINED)) { + FIXME("DISPPARAMS not expressed as VT_PTR -> VT_USERDEFINED?\n"); + return E_FAIL; + } + + cookie = *arg ? 0x42424242 : 0x0; + if (writeit) { + hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie)); + if (hres) + return hres; + } + if (!*arg) { + if (debugout) TRACE_(olerelay)("<DISPPARAMS NULL>"); + return S_OK; + } + disp = (DISPPARAMS*)*arg; + if (writeit) { + hres = xbuf_add(buf,(LPBYTE)&disp->cArgs,sizeof(disp->cArgs)); + if (hres) + return hres; + } + if (debugout) TRACE_(olerelay)("D{"); + for (i=0;i<disp->cArgs;i++) { + TYPEDESC vtdesc; + + vtdesc.vt = VT_VARIANT; + serialize_param( + tinfo, + writeit, + debugout, + dealloc, + &vtdesc, + (DWORD*)(disp->rgvarg+i), + buf + ); + if (debugout && (i<disp->cArgs-1)) + TRACE_(olerelay)(","); + } + if (dealloc) + HeapFree(GetProcessHeap(),0,disp->rgvarg); + if (writeit) { + hres = xbuf_add(buf,(LPBYTE)&disp->cNamedArgs,sizeof(disp->cNamedArgs)); + if (hres) + return hres; + } + if (debugout) TRACE_(olerelay)("}{"); + for (i=0;i<disp->cNamedArgs;i++) { + TYPEDESC vtdesc; + + vtdesc.vt = VT_UINT; + serialize_param( + tinfo, + writeit, + debugout, + dealloc, + &vtdesc, + (DWORD*)(disp->rgdispidNamedArgs+i), + buf + ); + if (debugout && (i<disp->cNamedArgs-1)) + TRACE_(olerelay)(","); + } + if (debugout) TRACE_(olerelay)("}"); + if (dealloc) { + HeapFree(GetProcessHeap(),0,disp->rgdispidNamedArgs); + HeapFree(GetProcessHeap(),0,disp); + } + return S_OK; +} + +static HRESULT +deserialize_param( + ITypeInfo *tinfo, + BOOL readit, + BOOL debugout, + BOOL alloc, + TYPEDESC *tdesc, + DWORD *arg, + marshal_state *buf) +{ + HRESULT hres = S_OK; + + TRACE("vt %d at %p\n",tdesc->vt,arg); + + while (1) { + switch (tdesc->vt) { + case VT_EMPTY: + if (debugout) TRACE_(olerelay)("<empty>"); + return S_OK; + case VT_NULL: + if (debugout) TRACE_(olerelay)("<null>"); + return S_OK; + case VT_VARIANT: { + VARIANT *vt = (VARIANT*)arg; + + if (readit) { + DWORD vttype; + TYPEDESC tdesc2; + hres = xbuf_get(buf,(LPBYTE)&vttype,sizeof(vttype)); + if (hres) { + FIXME("vt type not read?\n"); + return hres; + } + memset(&tdesc2,0,sizeof(tdesc2)); + tdesc2.vt = vttype; + V_VT(vt) = vttype; + if (debugout) TRACE_(olerelay)("Vt(%ld)(",vttype); + hres = deserialize_param(tinfo, readit, debugout, alloc, &tdesc2, &(V_I4(vt)), buf); + TRACE_(olerelay)(")"); + return hres; + } else { + VariantInit(vt); + return S_OK; + } + } + case VT_ERROR: + case VT_BOOL: + case VT_I4: + case VT_UINT: + case VT_R4: + case VT_UI4: + if (readit) { + hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD)); + if (hres) ERR("Failed to read integer 4 byte\n"); + } + if (debugout) TRACE_(olerelay)("%lx",*arg); + return hres; + case VT_I2: + case VT_UI2: + if (readit) { + DWORD x; + hres = xbuf_get(buf,(LPBYTE)&x,sizeof(DWORD)); + if (hres) ERR("Failed to read integer 4 byte\n"); + memcpy(arg,&x,2); + } + if (debugout) TRACE_(olerelay)("%04lx",*arg & 0xffff); + return hres; + case VT_I1: + case VT_UI1: + if (readit) { + DWORD x; + hres = xbuf_get(buf,(LPBYTE)&x,sizeof(DWORD)); + if (hres) ERR("Failed to read integer 4 byte\n"); + memcpy(arg,&x,1); + } + if (debugout) TRACE_(olerelay)("%02lx",*arg & 0xff); + return hres; + case VT_I4|VT_BYREF: + hres = S_OK; + if (alloc) + *arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD)); + if (readit) { + hres = xbuf_get(buf,(LPBYTE)*arg,sizeof(DWORD)); + if (hres) ERR("Failed to read integer 4 byte\n"); + } + if (debugout) TRACE_(olerelay)("&0x%lx",*(DWORD*)*arg); + return hres; + case VT_BSTR|VT_BYREF: { + BSTR **bstr = (BSTR **)arg; + WCHAR *str; + DWORD len; + + if (readit) { + hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD)); + if (hres) { + ERR("failed to read bstr klen\n"); + return hres; + } + if (len == -1) { + *bstr = CoTaskMemAlloc(sizeof(BSTR *)); + **bstr = NULL; + if (debugout) TRACE_(olerelay)("<bstr NULL>"); + } else { + str = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,len+sizeof(WCHAR)); + hres = xbuf_get(buf,(LPBYTE)str,len); + if (hres) { + ERR("Failed to read BSTR.\n"); + return hres; + } + *bstr = CoTaskMemAlloc(sizeof(BSTR *)); + **bstr = SysAllocStringLen(str,len); + if (debugout) TRACE_(olerelay)("%s",relaystr(str)); + HeapFree(GetProcessHeap(),0,str); + } + } else { + *bstr = NULL; + } + return S_OK; + } + case VT_BSTR: { + WCHAR *str; + DWORD len; + + if (readit) { + hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD)); + if (hres) { + ERR("failed to read bstr klen\n"); + return hres; + } + if (len == -1) { + *arg = 0; + if (debugout) TRACE_(olerelay)("<bstr NULL>"); + } else { + str = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,len+sizeof(WCHAR)); + hres = xbuf_get(buf,(LPBYTE)str,len); + if (hres) { + ERR("Failed to read BSTR.\n"); + return hres; + } + *arg = (DWORD)SysAllocStringLen(str,len); + if (debugout) TRACE_(olerelay)("%s",relaystr(str)); + HeapFree(GetProcessHeap(),0,str); + } + } else { + *arg = 0; + } + return S_OK; + } + case VT_PTR: { + DWORD cookie; + BOOL derefhere = 0; + + derefhere = (tdesc->u.lptdesc->vt != VT_USERDEFINED); + /* read it in all cases, we need to know if we have + * NULL pointer or not. + */ + hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie)); + if (hres) { + ERR("Failed to load pointer cookie.\n"); + return hres; + } + if (cookie != 0x42424242) { + /* we read a NULL ptr from the remote side */ + if (debugout) TRACE_(olerelay)("NULL"); + *arg = 0; + return S_OK; + } + if (debugout) TRACE_(olerelay)("*"); + if (alloc) { + /* Allocate space for the referenced struct */ + if (derefhere) + *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc)); + } + if (derefhere) + return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, (LPDWORD)*arg, buf); + else + return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, arg, buf); + } + case VT_UNKNOWN: + /* FIXME: UNKNOWN is unknown ..., but allocate 4 byte for it */ + if (alloc) + *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD)); + hres = S_OK; + if (readit) + hres = _unmarshal_interface(buf,&IID_IUnknown,(LPUNKNOWN*)arg); + if (debugout) + TRACE_(olerelay)("unk(%p)",arg); + return hres; + case VT_DISPATCH: + hres = S_OK; + if (readit) + hres = _unmarshal_interface(buf,&IID_IDispatch,(LPUNKNOWN*)arg); + if (debugout) + TRACE_(olerelay)("idisp(%p)",arg); + return hres; + case VT_VOID: + if (debugout) TRACE_(olerelay)("<void>"); + return S_OK; + case VT_USERDEFINED: { + ITypeInfo *tinfo2; + TYPEATTR *tattr; + + hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2); + if (hres) { + ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype); + return hres; + } + hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr); + if (hres) { + ERR("Could not get typeattr in VT_USERDEFINED.\n"); + } else { + switch (tattr->typekind) { + case TKIND_DISPATCH: + case TKIND_INTERFACE: + if (readit) + hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg); + break; + case TKIND_RECORD: { + int i; + + if (alloc) + *arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,tattr->cbSizeInstance); + + if (debugout) TRACE_(olerelay)("{"); + for (i=0;i<tattr->cVars;i++) { + VARDESC *vdesc; + + hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc); + if (hres) { + ERR("Could not get vardesc of %d\n",i); + return hres; + } + hres = deserialize_param( + tinfo2, + readit, + debugout, + alloc, + &vdesc->elemdescVar.tdesc, + (DWORD*)(((LPBYTE)*arg)+vdesc->u.oInst), + buf + ); + if (debugout && (i<tattr->cVars-1)) TRACE_(olerelay)(","); + } + if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID))) + memcpy(&(buf->iid),(LPBYTE)*arg,sizeof(buf->iid)); + if (debugout) TRACE_(olerelay)("}"); + break; + } + default: + ERR("Unhandled typekind %d\n",tattr->typekind); + hres = E_FAIL; + break; + } + } + if (hres) + ERR("failed to stuballoc in TKIND_RECORD.\n"); + ITypeInfo_Release(tinfo2); + return hres; + } + case VT_CARRAY: { + /* arg is pointing to the start of the array. */ + ARRAYDESC *adesc = tdesc->u.lpadesc; + int arrsize,i; + arrsize = 1; + if (adesc->cDims > 1) FIXME("cDims > 1 in VT_CARRAY. Does it work?\n"); + for (i=0;i<adesc->cDims;i++) + arrsize *= adesc->rgbounds[i].cElements; + for (i=0;i<arrsize;i++) + deserialize_param( + tinfo, + readit, + debugout, + alloc, + &adesc->tdescElem, + (DWORD*)((LPBYTE)(arg)+i*_xsize(&adesc->tdescElem)), + buf + ); + return S_OK; + } + default: + ERR("No handler for VT type %d!\n",tdesc->vt); + return S_OK; + } + } +} + +static HRESULT +deserialize_LPVOID_ptr( + ITypeInfo *tinfo, + BOOL readit, + BOOL debugout, + BOOL alloc, + TYPEDESC *tdesc, + DWORD *arg, + marshal_state *buf +) { + HRESULT hres; + DWORD cookie; + + if ((tdesc->vt != VT_PTR) || + (tdesc->u.lptdesc->vt != VT_PTR) || + (tdesc->u.lptdesc->u.lptdesc->vt != VT_VOID) + ) { + FIXME("ppvObject not expressed as VT_PTR -> VT_PTR -> VT_VOID?\n"); + return E_FAIL; + } + if (alloc) + *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LPVOID)); + if (readit) { + hres = xbuf_get(buf, (LPVOID)&cookie, sizeof(cookie)); + if (hres) + return hres; + if (cookie != 0x42424242) { + *(DWORD*)*arg = 0; + if (debugout) TRACE_(olerelay)("<lpvoid NULL>"); + return S_OK; + } + } + if (readit) { + hres = _unmarshal_interface(buf,&buf->iid,(LPUNKNOWN*)*arg); + if (hres) { + FIXME("_unmarshal_interface of %s , %p failed with %lx\n", debugstr_guid(&buf->iid), (LPUNKNOWN*)*arg, hres); + return hres; + } + } + if (debugout) TRACE_(olerelay)("ppv(%p)",(LPVOID)*arg); + return S_OK; +} + +static HRESULT +deserialize_DISPPARAM_ptr( + ITypeInfo *tinfo, + BOOL readit, + BOOL debugout, + BOOL alloc, + TYPEDESC *tdesc, + DWORD *arg, + marshal_state *buf) +{ + DWORD cookie; + DISPPARAMS *disps; + HRESULT hres; + int i; + + if ((tdesc->vt != VT_PTR) || (tdesc->u.lptdesc->vt != VT_USERDEFINED)) { + FIXME("DISPPARAMS not expressed as VT_PTR -> VT_USERDEFINED?\n"); + return E_FAIL; + } + if (readit) { + hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie)); + if (hres) + return hres; + if (cookie == 0) { + *arg = 0; + if (debugout) TRACE_(olerelay)("<DISPPARAMS NULL>"); + return S_OK; + } + } + if (alloc) + *arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPPARAMS)); + disps = (DISPPARAMS*)*arg; + if (!readit) + return S_OK; + hres = xbuf_get(buf, (LPBYTE)&disps->cArgs, sizeof(disps->cArgs)); + if (hres) + return hres; + if (alloc) + disps->rgvarg = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(VARIANT)*disps->cArgs); + if (debugout) TRACE_(olerelay)("D{"); + for (i=0; i< disps->cArgs; i++) { + TYPEDESC vdesc; + + vdesc.vt = VT_VARIANT; + hres = deserialize_param( + tinfo, + readit, + debugout, + alloc, + &vdesc, + (DWORD*)(disps->rgvarg+i), + buf + ); + } + if (debugout) TRACE_(olerelay)("}{"); + hres = xbuf_get(buf, (LPBYTE)&disps->cNamedArgs, sizeof(disps->cNamedArgs)); + if (hres) + return hres; + if (disps->cNamedArgs) { + if (alloc) + disps->rgdispidNamedArgs = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPID)*disps->cNamedArgs); + for (i=0; i< disps->cNamedArgs; i++) { + TYPEDESC vdesc; + + vdesc.vt = VT_UINT; + hres = deserialize_param( + tinfo, + readit, + debugout, + alloc, + &vdesc, + (DWORD*)(disps->rgdispidNamedArgs+i), + buf + ); + if (debugout && i<(disps->cNamedArgs-1)) TRACE_(olerelay)(","); + } + } + if (debugout) TRACE_(olerelay)("}"); + return S_OK; +} + +/* Searches function, also in inherited interfaces */ +static HRESULT +_get_funcdesc( + ITypeInfo *tinfo, int iMethod, FUNCDESC **fdesc, BSTR *iname, BSTR *fname) +{ + int i = 0, j = 0; + HRESULT hres; + + if (fname) *fname = NULL; + if (iname) *iname = NULL; + + while (1) { + hres = ITypeInfo_GetFuncDesc(tinfo, i, fdesc); + if (hres) { + ITypeInfo *tinfo2; + HREFTYPE href; + TYPEATTR *attr; + + hres = ITypeInfo_GetTypeAttr(tinfo, &attr); + if (hres) { + ERR("GetTypeAttr failed with %lx\n",hres); + return hres; + } + /* Not found, so look in inherited ifaces. */ + for (j=0;j<attr->cImplTypes;j++) { + hres = ITypeInfo_GetRefTypeOfImplType(tinfo, j, &href); + if (hres) { + ERR("Did not find a reftype for interface offset %d?\n",j); + break; + } + hres = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2); + if (hres) { + ERR("Did not find a typeinfo for reftype %ld?\n",href); + continue; + } + hres = _get_funcdesc(tinfo2,iMethod,fdesc,iname,fname); + ITypeInfo_Release(tinfo2); + if (!hres) return S_OK; + } + return hres; + } + if (((*fdesc)->oVft/4) == iMethod) { + if (fname) + ITypeInfo_GetDocumentation(tinfo,(*fdesc)->memid,fname,NULL,NULL,NULL); + if (iname) + ITypeInfo_GetDocumentation(tinfo,-1,iname,NULL,NULL,NULL); + return S_OK; + } + i++; + } +} + +static DWORD +xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */) +{ + DWORD *args = ((DWORD*)&tpinfo)+1, *xargs; + FUNCDESC *fdesc; + HRESULT hres; + int i, relaydeb = TRACE_ON(olerelay); + marshal_state buf; + RPCOLEMESSAGE msg; + ULONG status; + BSTR fname,iname; + BSTR names[10]; + int nrofnames; + int is_idispatch_getidsofnames = 0; + DWORD remoteresult = 0; + + EnterCriticalSection(&tpinfo->crit); + + hres = _get_funcdesc(tpinfo->tinfo,method,&fdesc,&iname,&fname); + if (hres) { + ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method); + LeaveCriticalSection(&tpinfo->crit); + return E_FAIL; + } + + if (!tpinfo->chanbuf) + { + WARN("Tried to use disconnected proxy\n"); + LeaveCriticalSection(&tpinfo->crit); + return RPC_E_DISCONNECTED; + } + + if (relaydeb) { + TRACE_(olerelay)("->"); + if (iname) + TRACE_(olerelay)("%s:",relaystr(iname)); + if (fname) + TRACE_(olerelay)("%s(%d)",relaystr(fname),method); + else + TRACE_(olerelay)("%d",method); + TRACE_(olerelay)("("); + } + if (iname && fname && !lstrcmpW(iname,IDispatchW) && !lstrcmpW(fname,GetIDsOfNamesW)) + is_idispatch_getidsofnames = 1; + + if (iname) SysFreeString(iname); + if (fname) SysFreeString(fname); + + memset(&buf,0,sizeof(buf)); + buf.iid = IID_IUnknown; + + /* Special IDispatch::GetIDsOfNames() serializer */ + if (is_idispatch_getidsofnames) { + hres = serialize_IDispatch_GetIDsOfNames(TRUE,relaydeb,args,&buf); + if (hres != S_OK) { + FIXME("serialize of IDispatch::GetIDsOfNames failed!\n"); + return hres; + } + goto afterserialize; + } + + /* special QueryInterface serialize */ + if (method == 0) { + xbuf_add(&buf,(LPBYTE)args[0],sizeof(IID)); + if (relaydeb) TRACE_(olerelay)("riid=%s,[out])",debugstr_guid((REFIID)args[0])); + goto afterserialize; + } + + /* normal typelib driven serializing */ + + /* Need them for hack below */ + memset(names,0,sizeof(names)); + if (ITypeInfo_GetNames(tpinfo->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames)) + nrofnames = 0; + if (nrofnames > sizeof(names)/sizeof(names[0])) + ERR("Need more names!\n"); + + xargs = args; + for (i=0;i<fdesc->cParams;i++) { + ELEMDESC *elem = fdesc->lprgelemdescParam+i; + BOOL isserialized = FALSE; + if (relaydeb) { + if (i) TRACE_(olerelay)(","); + if (i+1<nrofnames && names[i+1]) + TRACE_(olerelay)("%s=",relaystr(names[i+1])); + } + /* No need to marshal other data than FIN and any VT_PTR. */ + if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN) && (elem->tdesc.vt != VT_PTR)) { + xargs+=_argsize(elem->tdesc.vt); + if (relaydeb) TRACE_(olerelay)("[out]"); + continue; + } + if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) { + /* If the parameter is 'riid', we use it as interface IID + * for a later ppvObject serialization. + */ + buf.thisisiid = !lstrcmpW(names[i+1],riidW); + + /* DISPPARAMS* needs special serializer */ + if (!lstrcmpW(names[i+1],pdispparamsW)) { + hres = serialize_DISPPARAM_ptr( + tpinfo->tinfo, + elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN, + relaydeb, + FALSE, + &elem->tdesc, + xargs, + &buf + ); + isserialized = TRUE; + } + if (!lstrcmpW(names[i+1],ppvObjectW)) { + hres = serialize_LPVOID_ptr( + tpinfo->tinfo, + elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN, + relaydeb, + FALSE, + &elem->tdesc, + xargs, + &buf + ); + if (hres == S_OK) + isserialized = TRUE; + } + } + if (!isserialized) + hres = serialize_param( + tpinfo->tinfo, + elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN, + relaydeb, + FALSE, + &elem->tdesc, + xargs, + &buf + ); + + if (hres) { + ERR("Failed to serialize param, hres %lx\n",hres); + break; + } + xargs+=_argsize(elem->tdesc.vt); + } + if (relaydeb) TRACE_(olerelay)(")"); + +afterserialize: + memset(&msg,0,sizeof(msg)); + msg.cbBuffer = buf.curoff; + msg.iMethod = method; + hres = IRpcChannelBuffer_GetBuffer(tpinfo->chanbuf,&msg,&(tpinfo->iid)); + if (hres) { + ERR("RpcChannelBuffer GetBuffer failed, %lx\n",hres); + LeaveCriticalSection(&tpinfo->crit); + return hres; + } + memcpy(msg.Buffer,buf.base,buf.curoff); + if (relaydeb) TRACE_(olerelay)("\n"); + hres = IRpcChannelBuffer_SendReceive(tpinfo->chanbuf,&msg,&status); + if (hres) { + ERR("RpcChannelBuffer SendReceive failed, %lx\n",hres); + LeaveCriticalSection(&tpinfo->crit); + return hres; + } + + if (relaydeb) TRACE_(olerelay)(" status = %08lx (",status); + if (buf.base) + buf.base = HeapReAlloc(GetProcessHeap(),0,buf.base,msg.cbBuffer); + else + buf.base = HeapAlloc(GetProcessHeap(),0,msg.cbBuffer); + buf.size = msg.cbBuffer; + memcpy(buf.base,msg.Buffer,buf.size); + buf.curoff = 0; + + /* Special IDispatch::GetIDsOfNames() deserializer */ + if (is_idispatch_getidsofnames) { + hres = deserialize_IDispatch_GetIDsOfNames(FALSE,relaydeb,args,&buf); + if (hres != S_OK) { + FIXME("deserialize of IDispatch::GetIDsOfNames failed!\n"); + return hres; + } + goto after_deserialize; + } + /* Special QueryInterface deserializer */ + if (method == 0) { + _unmarshal_interface(&buf,(REFIID)args[0],(LPUNKNOWN*)args[1]); + if (relaydeb) TRACE_(olerelay)("[in],%p",*((DWORD**)args[1])); + goto after_deserialize; + } + + /* generic deserializer using typelib description */ + xargs = args; + status = S_OK; + for (i=0;i<fdesc->cParams;i++) { + ELEMDESC *elem = fdesc->lprgelemdescParam+i; + BOOL isdeserialized = FALSE; + + if (relaydeb) { + if (i) TRACE_(olerelay)(","); + if (i+1<nrofnames && names[i+1]) TRACE_(olerelay)("%s=",relaystr(names[i+1])); + } + /* No need to marshal other data than FOUT and any VT_PTR */ + if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) && (elem->tdesc.vt != VT_PTR)) { + xargs += _argsize(elem->tdesc.vt); + if (relaydeb) TRACE_(olerelay)("[in]"); + continue; + } + if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) { + /* If the parameter is 'riid', we use it as interface IID + * for a later ppvObject serialization. + */ + buf.thisisiid = !lstrcmpW(names[i+1],riidW); + + /* deserialize DISPPARAM */ + if (!lstrcmpW(names[i+1],pdispparamsW)) { + hres = deserialize_DISPPARAM_ptr( + tpinfo->tinfo, + elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT, + relaydeb, + FALSE, + &(elem->tdesc), + xargs, + &buf + ); + if (hres) { + ERR("Failed to deserialize DISPPARAM*, hres %lx\n",hres); + break; + } + isdeserialized = TRUE; + } + if (!lstrcmpW(names[i+1],ppvObjectW)) { + hres = deserialize_LPVOID_ptr( + tpinfo->tinfo, + elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT, + relaydeb, + FALSE, + &elem->tdesc, + xargs, + &buf + ); + if (hres == S_OK) + isdeserialized = TRUE; + } + } + if (!isdeserialized) + hres = deserialize_param( + tpinfo->tinfo, + elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT, + relaydeb, + FALSE, + &(elem->tdesc), + xargs, + &buf + ); + if (hres) { + ERR("Failed to unmarshall param, hres %lx\n",hres); + status = hres; + break; + } + xargs += _argsize(elem->tdesc.vt); + } +after_deserialize: + hres = xbuf_get(&buf, (LPBYTE)&remoteresult, sizeof(DWORD)); + if (hres != S_OK) + return hres; + if (relaydeb) TRACE_(olerelay)(") = %08lx\n", remoteresult); + + if (status != S_OK) /* OLE/COM internal error */ + return status; + + HeapFree(GetProcessHeap(),0,buf.base); + LeaveCriticalSection(&tpinfo->crit); + return remoteresult; +} + +HRESULT WINAPI ProxyIUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) +{ + TMProxyImpl *proxy = (TMProxyImpl *)iface; + + TRACE("(%s, %p)\n", debugstr_guid(riid), ppv); + + if (proxy->outerunknown) + return IUnknown_QueryInterface(proxy->outerunknown, riid, ppv); + + FIXME("No interface\n"); + return E_NOINTERFACE; +} + +ULONG WINAPI ProxyIUnknown_AddRef(IUnknown *iface) +{ + TMProxyImpl *proxy = (TMProxyImpl *)iface; + + TRACE("\n"); + + if (proxy->outerunknown) + return IUnknown_AddRef(proxy->outerunknown); + + return 2; /* FIXME */ +} + +ULONG WINAPI ProxyIUnknown_Release(IUnknown *iface) +{ + TMProxyImpl *proxy = (TMProxyImpl *)iface; + + TRACE("\n"); + + if (proxy->outerunknown) + return IUnknown_Release(proxy->outerunknown); + + return 1; /* FIXME */ +} + +static HRESULT WINAPI +PSFacBuf_CreateProxy( + LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid, + IRpcProxyBuffer **ppProxy, LPVOID *ppv) +{ + HRESULT hres; + ITypeInfo *tinfo; + int i, nroffuncs; + FUNCDESC *fdesc; + TMProxyImpl *proxy; + + TRACE("(...%s...)\n",debugstr_guid(riid)); + hres = _get_typeinfo_for_iid(riid,&tinfo); + if (hres) { + ERR("No typeinfo for %s?\n",debugstr_guid(riid)); + return hres; + } + nroffuncs = _nroffuncs(tinfo); + proxy = CoTaskMemAlloc(sizeof(TMProxyImpl)); + if (!proxy) return E_OUTOFMEMORY; + + assert(sizeof(TMAsmProxy) == 12); + + proxy->outerunknown = pUnkOuter; + proxy->asmstubs = VirtualAlloc(NULL, sizeof(TMAsmProxy) * nroffuncs, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if (!proxy->asmstubs) { + ERR("Could not commit pages for proxy thunks\n"); + CoTaskMemFree(proxy); + return E_OUTOFMEMORY; + } + + InitializeCriticalSection(&proxy->crit); + + proxy->lpvtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPBYTE)*nroffuncs); + for (i=0;i<nroffuncs;i++) { + TMAsmProxy *xasm = proxy->asmstubs+i; + + switch (i) { + case 0: + proxy->lpvtbl[i] = ProxyIUnknown_QueryInterface; + break; + case 1: + proxy->lpvtbl[i] = ProxyIUnknown_AddRef; + break; + case 2: + proxy->lpvtbl[i] = ProxyIUnknown_Release; + break; + default: { + int j; + /* nrofargs without This */ + int nrofargs; + hres = _get_funcdesc(tinfo,i,&fdesc,NULL,NULL); + if (hres) { + ERR("GetFuncDesc %lx should not fail here.\n",hres); + return hres; + } + /* some args take more than 4 byte on the stack */ + nrofargs = 0; + for (j=0;j<fdesc->cParams;j++) + nrofargs += _argsize(fdesc->lprgelemdescParam[j].tdesc.vt); + + if (fdesc->callconv != CC_STDCALL) { + ERR("calling convention is not stdcall????\n"); + return E_FAIL; + } +/* popl %eax - return ptr + * pushl <nr> + * pushl %eax + * call xCall + * lret <nr> (+4) + * + * + * arg3 arg2 arg1 <method> <returnptr> + */ + xasm->popleax = 0x58; + xasm->pushlval = 0x6a; + xasm->nr = i; + xasm->pushleax = 0x50; + xasm->lcall = 0xe8; /* relative jump */ + xasm->xcall = (DWORD)xCall; + xasm->xcall -= (DWORD)&(xasm->lret); + xasm->lret = 0xc2; + xasm->bytestopop= (nrofargs+2)*4; /* pop args, This, iMethod */ + proxy->lpvtbl[i] = xasm; + break; + } + } + } + proxy->lpvtbl2 = &tmproxyvtable; + /* 1 reference for the proxy and 1 for the object */ + proxy->ref = 2; + proxy->tinfo = tinfo; + memcpy(&proxy->iid,riid,sizeof(*riid)); + proxy->chanbuf = 0; + *ppv = (LPVOID)proxy; + *ppProxy = (IRpcProxyBuffer *)&(proxy->lpvtbl2); + return S_OK; +} + +typedef struct _TMStubImpl { + IRpcStubBufferVtbl *lpvtbl; + ULONG ref; + + LPUNKNOWN pUnk; + ITypeInfo *tinfo; + IID iid; +} TMStubImpl; + +static HRESULT WINAPI +TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv) +{ + if (IsEqualIID(riid,&IID_IRpcStubBuffer)||IsEqualIID(riid,&IID_IUnknown)){ + *ppv = (LPVOID)iface; + IRpcStubBuffer_AddRef(iface); + return S_OK; + } + FIXME("%s, not supported IID.\n",debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI +TMStubImpl_AddRef(LPRPCSTUBBUFFER iface) +{ + TMStubImpl *This = (TMStubImpl *)iface; + ULONG refCount = InterlockedIncrement(&This->ref); + + TRACE("(%p)->(ref before=%lu)\n", This, refCount - 1); + + return refCount; +} + +static ULONG WINAPI +TMStubImpl_Release(LPRPCSTUBBUFFER iface) +{ + TMStubImpl *This = (TMStubImpl *)iface; + ULONG refCount = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(ref before=%lu)\n", This, refCount + 1); + + if (!refCount) + { + IRpcStubBuffer_Disconnect(iface); + CoTaskMemFree(This); + } + return refCount; +} + +static HRESULT WINAPI +TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer) +{ + TMStubImpl *This = (TMStubImpl *)iface; + + TRACE("(%p)->(%p)\n", This, pUnkServer); + + IUnknown_AddRef(pUnkServer); + This->pUnk = pUnkServer; + return S_OK; +} + +static void WINAPI +TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface) +{ + TMStubImpl *This = (TMStubImpl *)iface; + + TRACE("(%p)->()\n", This); + + IUnknown_Release(This->pUnk); + This->pUnk = NULL; + return; +} + +static HRESULT WINAPI +TMStubImpl_Invoke( + LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf) +{ + int i; + FUNCDESC *fdesc; + TMStubImpl *This = (TMStubImpl *)iface; + HRESULT hres; + DWORD *args, res, *xargs, nrofargs; + marshal_state buf; + int nrofnames; + BSTR names[10]; + BSTR fname = NULL,iname = NULL; + BOOL is_idispatch_getidsofnames = 0; + + memset(&buf,0,sizeof(buf)); + buf.size = xmsg->cbBuffer; + buf.base = HeapAlloc(GetProcessHeap(), 0, xmsg->cbBuffer); + memcpy(buf.base, xmsg->Buffer, xmsg->cbBuffer); + buf.curoff = 0; + buf.iid = IID_IUnknown; + + TRACE("...\n"); + if (xmsg->iMethod == 0) { /* QI */ + IID xiid; + /* in: IID, out: <iface> */ + + xbuf_get(&buf,(LPBYTE)&xiid,sizeof(xiid)); + buf.curoff = 0; + hres = _marshal_interface(&buf,&xiid,This->pUnk); + xmsg->Buffer = buf.base; /* Might have been reallocated */ + xmsg->cbBuffer = buf.size; + return hres; + } + hres = _get_funcdesc(This->tinfo,xmsg->iMethod,&fdesc,&iname,&fname); + if (hres) { + ERR("GetFuncDesc on method %ld failed with %lx\n",xmsg->iMethod,hres); + return hres; + } + + if (iname && fname && !lstrcmpW(iname, IDispatchW) && !lstrcmpW(fname, GetIDsOfNamesW)) + is_idispatch_getidsofnames = 1; + + if (iname) SysFreeString (iname); + if (fname) SysFreeString (fname); + + /* Need them for hack below */ + memset(names,0,sizeof(names)); + ITypeInfo_GetNames(This->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames); + if (nrofnames > sizeof(names)/sizeof(names[0])) { + ERR("Need more names!\n"); + } + + /*dump_FUNCDESC(fdesc);*/ + nrofargs = 0; + for (i=0;i<fdesc->cParams;i++) + nrofargs += _argsize(fdesc->lprgelemdescParam[i].tdesc.vt); + args = HeapAlloc(GetProcessHeap(),0,(nrofargs+1)*sizeof(DWORD)); + if (!args) return E_OUTOFMEMORY; + + if (is_idispatch_getidsofnames) { + hres = deserialize_IDispatch_GetIDsOfNames(TRUE,FALSE,args+1,&buf); + if (hres != S_OK) { + FIXME("deserialize_IDispatch_GetIDsOfNames failed!\n"); + return hres; + } + xargs = args+1+5; + goto afterdeserialize; + } + + /* Allocate all stuff used by call. */ + xargs = args+1; + for (i=0;i<fdesc->cParams;i++) { + ELEMDESC *elem = fdesc->lprgelemdescParam+i; + BOOL isdeserialized = FALSE; + + if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) { + /* If the parameter is 'riid', we use it as interface IID + * for a later ppvObject serialization. + */ + buf.thisisiid = !lstrcmpW(names[i+1],riidW); + + /* deserialize DISPPARAM */ + if (!lstrcmpW(names[i+1],pdispparamsW)) { + hres = deserialize_DISPPARAM_ptr( + This->tinfo, + elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN, + FALSE, + TRUE, + &(elem->tdesc), + xargs, + &buf + ); + if (hres) { + ERR("Failed to deserialize DISPPARAM*, hres %lx\n",hres); + break; + } + isdeserialized = TRUE; + } + if (!lstrcmpW(names[i+1],ppvObjectW)) { + hres = deserialize_LPVOID_ptr( + This->tinfo, + elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN, + FALSE, + TRUE, + &elem->tdesc, + xargs, + &buf + ); + if (hres == S_OK) + isdeserialized = TRUE; + } + } + if (!isdeserialized) + hres = deserialize_param( + This->tinfo, + elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN, + FALSE, + TRUE, + &(elem->tdesc), + xargs, + &buf + ); + xargs += _argsize(elem->tdesc.vt); + if (hres) { + ERR("Failed to deserialize param %s, hres %lx\n",relaystr(names[i+1]),hres); + break; + } + } +afterdeserialize: + hres = IUnknown_QueryInterface(This->pUnk,&(This->iid),(LPVOID*)&(args[0])); + if (hres) { + ERR("Does not support iface %s, returning %lx\n",debugstr_guid(&(This->iid)), hres); + return hres; + } + res = _invoke( + (*((FARPROC**)args[0]))[fdesc->oVft/4], + fdesc->callconv, + (xargs-args), + args + ); + IUnknown_Release((LPUNKNOWN)args[0]); + buf.curoff = 0; + + /* special IDispatch::GetIDsOfNames serializer */ + if (is_idispatch_getidsofnames) { + hres = serialize_IDispatch_GetIDsOfNames(FALSE,FALSE,args+1,&buf); + if (hres != S_OK) { + FIXME("serialize of IDispatch::GetIDsOfNames failed!\n"); + return hres; + } + goto afterserialize; + } + xargs = args+1; + for (i=0;i<fdesc->cParams;i++) { + ELEMDESC *elem = fdesc->lprgelemdescParam+i; + BOOL isserialized = FALSE; + + if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) { + /* If the parameter is 'riid', we use it as interface IID + * for a later ppvObject serialization. + */ + buf.thisisiid = !lstrcmpW(names[i+1],riidW); + + /* DISPPARAMS* needs special serializer */ + if (!lstrcmpW(names[i+1],pdispparamsW)) { + hres = serialize_DISPPARAM_ptr( + This->tinfo, + elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT, + FALSE, + TRUE, + &elem->tdesc, + xargs, + &buf + ); + isserialized = TRUE; + } + if (!lstrcmpW(names[i+1],ppvObjectW)) { + hres = serialize_LPVOID_ptr( + This->tinfo, + elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT, + FALSE, + TRUE, + &elem->tdesc, + xargs, + &buf + ); + if (hres == S_OK) + isserialized = TRUE; + } + } + if (!isserialized) + hres = serialize_param( + This->tinfo, + elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT, + FALSE, + TRUE, + &elem->tdesc, + xargs, + &buf + ); + xargs += _argsize(elem->tdesc.vt); + if (hres) { + ERR("Failed to stuballoc param, hres %lx\n",hres); + break; + } + } +afterserialize: + hres = xbuf_add (&buf, (LPBYTE)&res, sizeof(DWORD)); + if (hres != S_OK) + return hres; + + xmsg->cbBuffer = buf.curoff; + I_RpcGetBuffer((RPC_MESSAGE *)xmsg); + memcpy(xmsg->Buffer, buf.base, buf.curoff); + HeapFree(GetProcessHeap(),0,args); + return S_OK; +} + +static LPRPCSTUBBUFFER WINAPI +TMStubImpl_IsIIDSupported(LPRPCSTUBBUFFER iface, REFIID riid) { + FIXME("Huh (%s)?\n",debugstr_guid(riid)); + return NULL; +} + +static ULONG WINAPI +TMStubImpl_CountRefs(LPRPCSTUBBUFFER iface) { + TMStubImpl *This = (TMStubImpl *)iface; + + return This->ref; /*FIXME? */ +} + +static HRESULT WINAPI +TMStubImpl_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, LPVOID *ppv) { + return E_NOTIMPL; +} + +static void WINAPI +TMStubImpl_DebugServerRelease(LPRPCSTUBBUFFER iface, LPVOID ppv) { + return; +} + +IRpcStubBufferVtbl tmstubvtbl = { + TMStubImpl_QueryInterface, + TMStubImpl_AddRef, + TMStubImpl_Release, + TMStubImpl_Connect, + TMStubImpl_Disconnect, + TMStubImpl_Invoke, + TMStubImpl_IsIIDSupported, + TMStubImpl_CountRefs, + TMStubImpl_DebugServerQueryInterface, + TMStubImpl_DebugServerRelease +}; + +static HRESULT WINAPI +PSFacBuf_CreateStub( + LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer, + IRpcStubBuffer** ppStub +) { + HRESULT hres; + ITypeInfo *tinfo; + TMStubImpl *stub; + + TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub); + hres = _get_typeinfo_for_iid(riid,&tinfo); + if (hres) { + ERR("No typeinfo for %s?\n",debugstr_guid(riid)); + return hres; + } + stub = CoTaskMemAlloc(sizeof(TMStubImpl)); + if (!stub) + return E_OUTOFMEMORY; + stub->lpvtbl = &tmstubvtbl; + stub->ref = 1; + stub->tinfo = tinfo; + memcpy(&(stub->iid),riid,sizeof(*riid)); + hres = IRpcStubBuffer_Connect((LPRPCSTUBBUFFER)stub,pUnkServer); + *ppStub = (LPRPCSTUBBUFFER)stub; + TRACE("IRpcStubBuffer: %p\n", stub); + if (hres) + ERR("Connect to pUnkServer failed?\n"); + return hres; +} + +static IPSFactoryBufferVtbl psfacbufvtbl = { + PSFacBuf_QueryInterface, + PSFacBuf_AddRef, + PSFacBuf_Release, + PSFacBuf_CreateProxy, + PSFacBuf_CreateStub +}; + +/* This is the whole PSFactoryBuffer object, just the vtableptr */ +static IPSFactoryBufferVtbl *lppsfac = &psfacbufvtbl; + +/*********************************************************************** + * DllGetClassObject [OLE32.63] + */ +HRESULT WINAPI +TypeLibFac_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv) +{ + if (IsEqualIID(iid,&IID_IPSFactoryBuffer)) { + *ppv = &lppsfac; + return S_OK; + } + return E_NOINTERFACE; +} diff --git a/reactos/lib/oleaut32/tmarshal.h b/reactos/lib/oleaut32/tmarshal.h index 87c33063275..20dc32bd17f 100644 --- a/reactos/lib/oleaut32/tmarshal.h +++ b/reactos/lib/oleaut32/tmarshal.h @@ -1,24 +1,24 @@ -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef TMARSHAL_H -#define TMARSHAL_H -HRESULT WINAPI -TypeLibFac_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv); - -#endif +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TMARSHAL_H +#define TMARSHAL_H +HRESULT WINAPI +TypeLibFac_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv); + +#endif diff --git a/reactos/lib/oleaut32/typelib.c b/reactos/lib/oleaut32/typelib.c index 1b8361c50e9..5cba2bb3167 100644 --- a/reactos/lib/oleaut32/typelib.c +++ b/reactos/lib/oleaut32/typelib.c @@ -1,5968 +1,5968 @@ -/* - * TYPELIB - * - * Copyright 1997 Marcus Meissner - * 1999 Rein Klazes - * 2000 Francois Jacques - * 2001 Huw D M Davies for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * -------------------------------------------------------------------------------------- - * Known problems (2000, Francois Jacques) - * - * - Tested using OLEVIEW (Platform SDK tool) only. - * - * - dual interface dispinterfaces. vtable-interface ITypeInfo instances are - * creating by doing a straight copy of the dispinterface instance and just changing - * its typekind. Pointed structures aren't copied - only the address of the pointers. - * So when you release the dispinterface, you delete the vtable-interface structures - * as well... fortunately, clean up of structures is not implemented. - * - * - locale stuff is partially implemented but hasn't been tested. - * - * - typelib file is still read in its entirety, but it is released now. - * - some garbage is read from function names on some very rare occasions. - * - * -------------------------------------------------------------------------------------- - * Known problems left from previous implementation (1999, Rein Klazes) : - * - * -. Data structures are straightforward, but slow for look-ups. - * -. (related) nothing is hashed - * -. there are a number of stubs in ITypeLib and ITypeInfo interfaces. Most - * of them I don't know yet how to implement them. - * -. Most error return values are just guessed not checked with windows - * behaviour. - * -. didn't bother with a c++ interface - * -. lousy fatal error handling - * -. some methods just return pointers to internal data structures, this is - * partly laziness, partly I want to check how windows does it. - * - */ - -#include "config.h" -#include "wine/port.h" - -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <stdio.h> -#include <ctype.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "winerror.h" -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "winreg.h" -#include "winuser.h" - -#include "wine/unicode.h" -#include "objbase.h" -#include "typelib.h" -#include "wine/debug.h" -#include "variant.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); -WINE_DECLARE_DEBUG_CHANNEL(typelib); - -/* The OLE Automation ProxyStub Interface Class (aka Typelib Marshaler) */ -const GUID CLSID_PSOAInterface = { 0x00020424, 0, 0, { 0xC0, 0, 0, 0, 0, 0, 0, 0x46 } }; - -/**************************************************************************** - * FromLExxx - * - * Takes p_iVal (which is in little endian) and returns it - * in the host machine's byte order. - */ -#ifdef WORDS_BIGENDIAN -static WORD FromLEWord(WORD p_iVal) -{ - return (((p_iVal & 0x00FF) << 8) | - ((p_iVal & 0xFF00) >> 8)); -} - - -static DWORD FromLEDWord(DWORD p_iVal) -{ - return (((p_iVal & 0x000000FF) << 24) | - ((p_iVal & 0x0000FF00) << 8) | - ((p_iVal & 0x00FF0000) >> 8) | - ((p_iVal & 0xFF000000) >> 24)); -} -#else -#define FromLEWord(X) (X) -#define FromLEDWord(X) (X) -#endif - - -/**************************************************************************** - * FromLExxx - * - * Fix byte order in any structure if necessary - */ -#ifdef WORDS_BIGENDIAN -static void FromLEWords(void *p_Val, int p_iSize) -{ - WORD *Val = p_Val; - - p_iSize /= sizeof(WORD); - - while (p_iSize) { - *Val = FromLEWord(*Val); - Val++; - p_iSize--; - } -} - - -static void FromLEDWords(void *p_Val, int p_iSize) -{ - DWORD *Val = p_Val; - - p_iSize /= sizeof(DWORD); - - while (p_iSize) { - *Val = FromLEDWord(*Val); - Val++; - p_iSize--; - } -} -#else -#define FromLEWords(X,Y) /*nothing*/ -#define FromLEDWords(X,Y) /*nothing*/ -#endif - -/* get the path of a typelib key, in the form "Typelib\\<guid>\\<maj>.<min>" */ -/* buffer must be at least 60 characters long */ -static WCHAR *get_typelib_key( REFGUID guid, WORD wMaj, WORD wMin, WCHAR *buffer ) -{ - static const WCHAR TypelibW[] = {'T','y','p','e','l','i','b','\\',0}; - static const WCHAR VersionFormatW[] = {'\\','%','u','.','%','u',0}; - - memcpy( buffer, TypelibW, sizeof(TypelibW) ); - StringFromGUID2( guid, buffer + strlenW(buffer), 40 ); - sprintfW( buffer + strlenW(buffer), VersionFormatW, wMaj, wMin ); - return buffer; -} - -/* get the path of an interface key, in the form "Interface\\<guid>" */ -/* buffer must be at least 50 characters long */ -static WCHAR *get_interface_key( REFGUID guid, WCHAR *buffer ) -{ - static const WCHAR InterfaceW[] = {'I','n','t','e','r','f','a','c','e','\\',0}; - - memcpy( buffer, InterfaceW, sizeof(InterfaceW) ); - StringFromGUID2( guid, buffer + strlenW(buffer), 40 ); - return buffer; -} - -/* get the lcid subkey for a typelib, in the form "<lcid>\\<syskind>" */ -/* buffer must be at least 16 characters long */ -static WCHAR *get_lcid_subkey( LCID lcid, SYSKIND syskind, WCHAR *buffer ) -{ - static const WCHAR LcidFormatW[] = {'%','l','x','\\',0}; - static const WCHAR win16W[] = {'w','i','n','1','6',0}; - static const WCHAR win32W[] = {'w','i','n','3','2',0}; - - sprintfW( buffer, LcidFormatW, lcid ); - switch(syskind) - { - case SYS_WIN16: strcatW( buffer, win16W ); break; - case SYS_WIN32: strcatW( buffer, win32W ); break; - default: - TRACE("Typelib is for unsupported syskind %i\n", syskind); - return NULL; - } - return buffer; -} - - -/**************************************************************************** - * QueryPathOfRegTypeLib [OLEAUT32.164] - * RETURNS - * path of typelib - */ -HRESULT WINAPI -QueryPathOfRegTypeLib( - REFGUID guid, /* [in] referenced guid */ - WORD wMaj, /* [in] major version */ - WORD wMin, /* [in] minor version */ - LCID lcid, /* [in] locale id */ - LPBSTR path ) /* [out] path of typelib */ -{ - HRESULT hr = E_FAIL; - LCID myLCID = lcid; - HKEY hkey; - WCHAR buffer[60]; - WCHAR Path[MAX_PATH]; - - if ( !HIWORD(guid) ) - { - FIXME("(guid %p,%d,%d,0x%04lx,%p),stub!\n", guid, wMaj, wMin, lcid, path); - return E_FAIL; - } - - get_typelib_key( guid, wMaj, wMin, buffer ); - - if (RegOpenKeyW( HKEY_CLASSES_ROOT, buffer, &hkey ) != ERROR_SUCCESS) - { - TRACE_(typelib)("%s not found\n", debugstr_w(buffer)); - return E_FAIL; - } - - while (hr != S_OK) - { - DWORD dwPathLen = sizeof(Path); - - get_lcid_subkey( myLCID, SYS_WIN32, buffer ); - - if (RegQueryValueW(hkey, buffer, Path, &dwPathLen)) - { - if (!lcid) - break; - else if (myLCID == lcid) - { - /* try with sub-langid */ - myLCID = SUBLANGID(lcid); - } - else if ((myLCID == SUBLANGID(lcid)) && myLCID) - { - /* try with system langid */ - myLCID = 0; - } - else - { - break; - } - } - else - { - *path = SysAllocString( Path ); - hr = S_OK; - } - } - RegCloseKey( hkey ); - return hr; -} - -/****************************************************************************** - * CreateTypeLib [OLEAUT32.160] creates a typelib - * - * RETURNS - * Success: S_OK - * Failure: Status - */ -HRESULT WINAPI CreateTypeLib( - SYSKIND syskind, LPCOLESTR szFile, ICreateTypeLib** ppctlib -) { - FIXME("(%d,%s,%p), stub!\n",syskind,debugstr_w(szFile),ppctlib); - return E_FAIL; -} -/****************************************************************************** - * LoadTypeLib [OLEAUT32.161] - * Loads and registers a type library - * NOTES - * Docs: OLECHAR FAR* szFile - * Docs: iTypeLib FAR* FAR* pptLib - * - * RETURNS - * Success: S_OK - * Failure: Status - */ -int TLB_ReadTypeLib(LPCWSTR file, INT index, ITypeLib2 **ppTypelib); - -HRESULT WINAPI LoadTypeLib( - const OLECHAR *szFile,/* [in] Name of file to load from */ - ITypeLib * *pptLib) /* [out] Pointer to pointer to loaded type library */ -{ - TRACE("(%s,%p)\n",debugstr_w(szFile), pptLib); - return LoadTypeLibEx(szFile, REGKIND_DEFAULT, pptLib); -} - -/****************************************************************************** - * LoadTypeLibEx [OLEAUT32.183] - * Loads and optionally registers a type library - * - * RETURNS - * Success: S_OK - * Failure: Status - */ -HRESULT WINAPI LoadTypeLibEx( - LPCOLESTR szFile, /* [in] Name of file to load from */ - REGKIND regkind, /* [in] Specify kind of registration */ - ITypeLib **pptLib) /* [out] Pointer to pointer to loaded type library */ -{ - WCHAR szPath[MAX_PATH+1], szFileCopy[MAX_PATH+1]; - WCHAR *pIndexStr; - HRESULT res; - INT index = 1; - - TRACE("(%s,%d,%p)\n",debugstr_w(szFile), regkind, pptLib); - - /* by default try and load using LoadLibrary (for builtin stdole32.tlb) */ - memcpy(szPath, szFile, (strlenW(szFile)+1)*sizeof(WCHAR)); - - *pptLib = NULL; - if(!SearchPathW(NULL,szFile,NULL,sizeof(szPath)/sizeof(WCHAR),szPath, - NULL)) { - - /* Look for a trailing '\\' followed by an index */ - pIndexStr = strrchrW(szFile, '\\'); - if(pIndexStr && pIndexStr != szFile && *++pIndexStr != '\0') { - index = atoiW(pIndexStr); - memcpy(szFileCopy, szFile, - (pIndexStr - szFile - 1) * sizeof(WCHAR)); - szFileCopy[pIndexStr - szFile - 1] = '\0'; - if(!SearchPathW(NULL,szFileCopy,NULL,sizeof(szPath)/sizeof(WCHAR), - szPath,NULL)) - return TYPE_E_CANTLOADLIBRARY; - if (GetFileAttributesW(szFileCopy) & FILE_ATTRIBUTE_DIRECTORY) - return TYPE_E_CANTLOADLIBRARY; - } - } - - TRACE("File %s index %d\n", debugstr_w(szPath), index); - - res = TLB_ReadTypeLib(szPath, index, (ITypeLib2**)pptLib); - - if (SUCCEEDED(res)) - switch(regkind) - { - case REGKIND_DEFAULT: - /* don't register typelibs supplied with full path. Experimentation confirms the following */ - if ((!szFile) || - ((szFile[0] == '\\') && (szFile[1] == '\\')) || - (szFile[0] && (szFile[1] == ':'))) break; - /* else fall-through */ - - case REGKIND_REGISTER: - if (!SUCCEEDED(res = RegisterTypeLib(*pptLib, (LPOLESTR)szPath, NULL))) - { - IUnknown_Release(*pptLib); - *pptLib = 0; - } - break; - case REGKIND_NONE: - break; - } - - TRACE(" returns %08lx\n",res); - return res; -} - -/****************************************************************************** - * LoadRegTypeLib [OLEAUT32.162] - */ -HRESULT WINAPI LoadRegTypeLib( - REFGUID rguid, /* [in] referenced guid */ - WORD wVerMajor, /* [in] major version */ - WORD wVerMinor, /* [in] minor version */ - LCID lcid, /* [in] locale id */ - ITypeLib **ppTLib) /* [out] path of typelib */ -{ - BSTR bstr=NULL; - HRESULT res=QueryPathOfRegTypeLib( rguid, wVerMajor, wVerMinor, lcid, &bstr); - - if(SUCCEEDED(res)) - { - res= LoadTypeLib(bstr, ppTLib); - SysFreeString(bstr); - } - - TRACE("(IID: %s) load %s (%p)\n",debugstr_guid(rguid), SUCCEEDED(res)? "SUCCESS":"FAILED", *ppTLib); - - return res; -} - - -/* some string constants shared between RegisterTypeLib and UnRegisterTypeLib */ -static const WCHAR TypeLibW[] = {'T','y','p','e','L','i','b',0}; -static const WCHAR FLAGSW[] = {'F','L','A','G','S',0}; -static const WCHAR HELPDIRW[] = {'H','E','L','P','D','I','R',0}; -static const WCHAR ProxyStubClsidW[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d',0}; -static const WCHAR ProxyStubClsid32W[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0}; - -/****************************************************************************** - * RegisterTypeLib [OLEAUT32.163] - * Adds information about a type library to the System Registry - * NOTES - * Docs: ITypeLib FAR * ptlib - * Docs: OLECHAR FAR* szFullPath - * Docs: OLECHAR FAR* szHelpDir - * - * RETURNS - * Success: S_OK - * Failure: Status - */ -HRESULT WINAPI RegisterTypeLib( - ITypeLib * ptlib, /* [in] Pointer to the library*/ - OLECHAR * szFullPath, /* [in] full Path of the library*/ - OLECHAR * szHelpDir) /* [in] dir to the helpfile for the library, - may be NULL*/ -{ - static const WCHAR PSOA[] = {'{','0','0','0','2','0','4','2','4','-', - '0','0','0','0','-','0','0','0','0','-','C','0','0','0','-', - '0','0','0','0','0','0','0','0','0','0','4','6','}',0}; - HRESULT res; - TLIBATTR *attr; - WCHAR keyName[60]; - WCHAR tmp[16]; - HKEY key, subKey; - UINT types, tidx; - TYPEKIND kind; - DWORD disposition; - - if (ptlib == NULL || szFullPath == NULL) - return E_INVALIDARG; - - if (!SUCCEEDED(ITypeLib_GetLibAttr(ptlib, &attr))) - return E_FAIL; - - get_typelib_key( &attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, keyName ); - - res = S_OK; - if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0, - KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS) - { - LPOLESTR doc; - - /* Set the human-readable name of the typelib */ - if (SUCCEEDED(ITypeLib_GetDocumentation(ptlib, -1, NULL, &doc, NULL, NULL))) - { - if (RegSetValueExW(key, NULL, 0, REG_SZ, - (BYTE *)doc, (lstrlenW(doc)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS) - res = E_FAIL; - - SysFreeString(doc); - } - else - res = E_FAIL; - - /* Make up the name of the typelib path subkey */ - if (!get_lcid_subkey( attr->lcid, attr->syskind, tmp )) res = E_FAIL; - - /* Create the typelib path subkey */ - if (res == S_OK && RegCreateKeyExW(key, tmp, 0, NULL, 0, - KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) - { - if (RegSetValueExW(subKey, NULL, 0, REG_SZ, - (BYTE *)szFullPath, (lstrlenW(szFullPath)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS) - res = E_FAIL; - - RegCloseKey(subKey); - } - else - res = E_FAIL; - - /* Create the flags subkey */ - if (res == S_OK && RegCreateKeyExW(key, FLAGSW, 0, NULL, 0, - KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) - { - /* FIXME: is %u correct? */ - static const WCHAR formatW[] = {'%','u',0}; - WCHAR buf[20]; - sprintfW(buf, formatW, attr->wLibFlags); - if (RegSetValueExW(subKey, NULL, 0, REG_SZ, - (BYTE *)buf, (strlenW(buf) + 1)*sizeof(WCHAR) ) != ERROR_SUCCESS) - res = E_FAIL; - - RegCloseKey(subKey); - } - else - res = E_FAIL; - - /* create the helpdir subkey */ - if (res == S_OK && RegCreateKeyExW(key, HELPDIRW, 0, NULL, 0, - KEY_WRITE, NULL, &subKey, &disposition) == ERROR_SUCCESS) - { - BOOL freeHelpDir = FALSE; - OLECHAR* pIndexStr; - - /* if we created a new key, and helpDir was null, set the helpdir - to the directory which contains the typelib. However, - if we just opened an existing key, we leave the helpdir alone */ - if ((disposition == REG_CREATED_NEW_KEY) && (szHelpDir == NULL)) { - szHelpDir = SysAllocString(szFullPath); - pIndexStr = strrchrW(szHelpDir, '\\'); - if (pIndexStr) { - *pIndexStr = 0; - } - freeHelpDir = TRUE; - } - - /* if we have an szHelpDir, set it! */ - if (szHelpDir != NULL) { - if (RegSetValueExW(subKey, NULL, 0, REG_SZ, - (BYTE *)szHelpDir, (lstrlenW(szHelpDir)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS) { - res = E_FAIL; - } - } - - /* tidy up */ - if (freeHelpDir) SysFreeString(szHelpDir); - RegCloseKey(subKey); - - } else { - res = E_FAIL; - } - - RegCloseKey(key); - } - else - res = E_FAIL; - - /* register OLE Automation-compatible interfaces for this typelib */ - types = ITypeLib_GetTypeInfoCount(ptlib); - for (tidx=0; tidx<types; tidx++) { - if (SUCCEEDED(ITypeLib_GetTypeInfoType(ptlib, tidx, &kind))) { - LPOLESTR name = NULL; - ITypeInfo *tinfo = NULL; - - ITypeLib_GetDocumentation(ptlib, tidx, &name, NULL, NULL, NULL); - - switch (kind) { - case TKIND_INTERFACE: - TRACE_(typelib)("%d: interface %s\n", tidx, debugstr_w(name)); - ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo); - break; - - case TKIND_DISPATCH: - TRACE_(typelib)("%d: dispinterface %s\n", tidx, debugstr_w(name)); - ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo); - break; - - default: - TRACE_(typelib)("%d: %s\n", tidx, debugstr_w(name)); - break; - } - - if (tinfo) { - TYPEATTR *tattr = NULL; - ITypeInfo_GetTypeAttr(tinfo, &tattr); - - if (tattr) { - TRACE_(typelib)("guid=%s, flags=%04x (", - debugstr_guid(&tattr->guid), - tattr->wTypeFlags); - - if (TRACE_ON(typelib)) { -#define XX(x) if (TYPEFLAG_##x & tattr->wTypeFlags) MESSAGE(#x"|"); - XX(FAPPOBJECT); - XX(FCANCREATE); - XX(FLICENSED); - XX(FPREDECLID); - XX(FHIDDEN); - XX(FCONTROL); - XX(FDUAL); - XX(FNONEXTENSIBLE); - XX(FOLEAUTOMATION); - XX(FRESTRICTED); - XX(FAGGREGATABLE); - XX(FREPLACEABLE); - XX(FDISPATCHABLE); - XX(FREVERSEBIND); - XX(FPROXY); -#undef XX - MESSAGE("\n"); - } - - /* - * FIXME: The 1 is just here until we implement rpcrt4 - * stub/proxy handling. Until then it helps IShield - * v6 to work. - */ - if (1 || (tattr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)) - { - if (!(tattr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)) { - FIXME("Registering non-oleautomation interface!\n"); - } - - /* register interface<->typelib coupling */ - get_interface_key( &tattr->guid, keyName ); - if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0, - KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS) - { - if (name) - RegSetValueExW(key, NULL, 0, REG_SZ, - (BYTE *)name, (strlenW(name)+1) * sizeof(OLECHAR)); - - if (RegCreateKeyExW(key, ProxyStubClsidW, 0, NULL, 0, - KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) { - RegSetValueExW(subKey, NULL, 0, REG_SZ, - (BYTE*)PSOA, sizeof PSOA); - RegCloseKey(subKey); - } - - if (RegCreateKeyExW(key, ProxyStubClsid32W, 0, NULL, 0, - KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) { - RegSetValueExW(subKey, NULL, 0, REG_SZ, - (BYTE*)PSOA, sizeof PSOA); - RegCloseKey(subKey); - } - - if (RegCreateKeyExW(key, TypeLibW, 0, NULL, 0, - KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) - { - WCHAR buffer[40]; - static const WCHAR fmtver[] = {'%','u','.','%','u',0 }; - static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0}; - - StringFromGUID2(&attr->guid, buffer, 40); - RegSetValueExW(subKey, NULL, 0, REG_SZ, - (BYTE *)buffer, (strlenW(buffer)+1) * sizeof(WCHAR)); - sprintfW(buffer, fmtver, attr->wMajorVerNum, attr->wMinorVerNum); - RegSetValueExW(subKey, VersionW, 0, REG_SZ, - (BYTE*)buffer, (strlenW(buffer)+1) * sizeof(WCHAR)); - RegCloseKey(subKey); - } - - RegCloseKey(key); - } - } - - ITypeInfo_ReleaseTypeAttr(tinfo, tattr); - } - - ITypeInfo_Release(tinfo); - } - - SysFreeString(name); - } - } - - ITypeLib_ReleaseTLibAttr(ptlib, attr); - - return res; -} - - -/****************************************************************************** - * UnRegisterTypeLib [OLEAUT32.186] - * Removes information about a type library from the System Registry - * NOTES - * - * RETURNS - * Success: S_OK - * Failure: Status - */ -HRESULT WINAPI UnRegisterTypeLib( - REFGUID libid, /* [in] Guid of the library */ - WORD wVerMajor, /* [in] major version */ - WORD wVerMinor, /* [in] minor version */ - LCID lcid, /* [in] locale id */ - SYSKIND syskind) -{ - BSTR tlibPath = NULL; - DWORD tmpLength; - WCHAR keyName[60]; - WCHAR subKeyName[50]; - int result = S_OK; - DWORD i = 0; - BOOL deleteOtherStuff; - HKEY key = NULL; - HKEY subKey = NULL; - TYPEATTR* typeAttr = NULL; - TYPEKIND kind; - ITypeInfo* typeInfo = NULL; - ITypeLib* typeLib = NULL; - int numTypes; - - TRACE("(IID: %s): stub\n",debugstr_guid(libid)); - - /* Create the path to the key */ - get_typelib_key( libid, wVerMajor, wVerMinor, keyName ); - - if (syskind != SYS_WIN16 && syskind != SYS_WIN32) - { - TRACE("Unsupported syskind %i\n", syskind); - result = E_INVALIDARG; - goto end; - } - - /* get the path to the typelib on disk */ - if (QueryPathOfRegTypeLib(libid, wVerMajor, wVerMinor, lcid, &tlibPath) != S_OK) { - result = E_INVALIDARG; - goto end; - } - - /* Try and open the key to the type library. */ - if (RegOpenKeyExW(HKEY_CLASSES_ROOT, keyName, 0, KEY_READ | KEY_WRITE, &key) != S_OK) { - result = E_INVALIDARG; - goto end; - } - - /* Try and load the type library */ - if (LoadTypeLibEx(tlibPath, REGKIND_NONE, &typeLib)) { - result = TYPE_E_INVALIDSTATE; - goto end; - } - - /* remove any types registered with this typelib */ - numTypes = ITypeLib_GetTypeInfoCount(typeLib); - for (i=0; i<numTypes; i++) { - /* get the kind of type */ - if (ITypeLib_GetTypeInfoType(typeLib, i, &kind) != S_OK) { - goto enddeleteloop; - } - - /* skip non-interfaces, and get type info for the type */ - if ((kind != TKIND_INTERFACE) && (kind != TKIND_DISPATCH)) { - goto enddeleteloop; - } - if (ITypeLib_GetTypeInfo(typeLib, i, &typeInfo) != S_OK) { - goto enddeleteloop; - } - if (ITypeInfo_GetTypeAttr(typeInfo, &typeAttr) != S_OK) { - goto enddeleteloop; - } - - /* the path to the type */ - get_interface_key( &typeAttr->guid, subKeyName ); - - /* Delete its bits */ - if (RegOpenKeyExW(HKEY_CLASSES_ROOT, subKeyName, 0, KEY_WRITE, &subKey) != S_OK) { - goto enddeleteloop; - } - RegDeleteKeyW(subKey, ProxyStubClsidW); - RegDeleteKeyW(subKey, ProxyStubClsid32W); - RegDeleteKeyW(subKey, TypeLibW); - RegCloseKey(subKey); - subKey = NULL; - RegDeleteKeyW(HKEY_CLASSES_ROOT, subKeyName); - -enddeleteloop: - if (typeAttr) ITypeInfo_ReleaseTypeAttr(typeInfo, typeAttr); - typeAttr = NULL; - if (typeInfo) ITypeInfo_Release(typeInfo); - typeInfo = NULL; - } - - /* Now, delete the type library path subkey */ - get_lcid_subkey( lcid, syskind, subKeyName ); - RegDeleteKeyW(key, subKeyName); - *strrchrW( subKeyName, '\\' ) = 0; /* remove last path component */ - RegDeleteKeyW(key, subKeyName); - - /* check if there is anything besides the FLAGS/HELPDIR keys. - If there is, we don't delete them */ - tmpLength = sizeof(subKeyName)/sizeof(WCHAR); - deleteOtherStuff = TRUE; - i = 0; - while(RegEnumKeyExW(key, i++, subKeyName, &tmpLength, NULL, NULL, NULL, NULL) == S_OK) { - tmpLength = sizeof(subKeyName)/sizeof(WCHAR); - - /* if its not FLAGS or HELPDIR, then we must keep the rest of the key */ - if (!strcmpW(subKeyName, FLAGSW)) continue; - if (!strcmpW(subKeyName, HELPDIRW)) continue; - deleteOtherStuff = FALSE; - break; - } - - /* only delete the other parts of the key if we're absolutely sure */ - if (deleteOtherStuff) { - RegDeleteKeyW(key, FLAGSW); - RegDeleteKeyW(key, HELPDIRW); - RegCloseKey(key); - key = NULL; - - RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName); - *strrchrW( keyName, '\\' ) = 0; /* remove last path component */ - RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName); - } - -end: - if (tlibPath) SysFreeString(tlibPath); - if (typeLib) ITypeLib_Release(typeLib); - if (subKey) RegCloseKey(subKey); - if (key) RegCloseKey(key); - return result; -} - -/*======================= ITypeLib implementation =======================*/ - -typedef struct tagTLBCustData -{ - GUID guid; - VARIANT data; - struct tagTLBCustData* next; -} TLBCustData; - -/* data structure for import typelibs */ -typedef struct tagTLBImpLib -{ - int offset; /* offset in the file (MSFT) - offset in nametable (SLTG) - just used to identify library while reading - data from file */ - GUID guid; /* libid */ - BSTR name; /* name */ - - LCID lcid; /* lcid of imported typelib */ - - WORD wVersionMajor; /* major version number */ - WORD wVersionMinor; /* minor version number */ - - struct tagITypeLibImpl *pImpTypeLib; /* pointer to loaded typelib, or - NULL if not yet loaded */ - struct tagTLBImpLib * next; -} TLBImpLib; - -/* internal ITypeLib data */ -typedef struct tagITypeLibImpl -{ - ITypeLib2Vtbl *lpVtbl; - ITypeCompVtbl *lpVtblTypeComp; - ULONG ref; - TLIBATTR LibAttr; /* guid,lcid,syskind,version,flags */ - - /* strings can be stored in tlb as multibyte strings BUT they are *always* - * exported to the application as a UNICODE string. - */ - BSTR Name; - BSTR DocString; - BSTR HelpFile; - BSTR HelpStringDll; - unsigned long dwHelpContext; - int TypeInfoCount; /* nr of typeinfo's in librarry */ - struct tagITypeInfoImpl *pTypeInfo; /* linked list of type info data */ - int ctCustData; /* number of items in cust data list */ - TLBCustData * pCustData; /* linked list to cust data */ - TLBImpLib * pImpLibs; /* linked list to all imported typelibs */ - TYPEDESC * pTypeDesc; /* array of TypeDescriptions found in the - libary. Only used while read MSFT - typelibs */ - - /* typelibs are cached, keyed by path and index, so store the linked list info within them */ - struct tagITypeLibImpl *next, *prev; - WCHAR *path; - INT index; -} ITypeLibImpl; - -static struct ITypeLib2Vtbl tlbvt; -static struct ITypeCompVtbl tlbtcvt; - -#define _ITypeComp_Offset(impl) ((int)(&(((impl*)0)->lpVtblTypeComp))) -#define ICOM_THIS_From_ITypeComp(impl, iface) impl* This = (impl*)(((char*)iface)-_ITypeComp_Offset(impl)) - -/* ITypeLib methods */ -static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength); -static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength); - -/*======================= ITypeInfo implementation =======================*/ - -/* data for referenced types */ -typedef struct tagTLBRefType -{ - INT index; /* Type index for internal ref or for external ref - it the format is SLTG. -2 indicates to - use guid */ - - GUID guid; /* guid of the referenced type */ - /* if index == TLB_REF_USE_GUID */ - - HREFTYPE reference; /* The href of this ref */ - TLBImpLib *pImpTLInfo; /* If ref is external ptr to library data - TLB_REF_INTERNAL for internal refs - TLB_REF_NOT_FOUND for broken refs */ - - struct tagTLBRefType * next; -} TLBRefType; - -#define TLB_REF_USE_GUID -2 - -#define TLB_REF_INTERNAL (void*)-2 -#define TLB_REF_NOT_FOUND (void*)-1 - -/* internal Parameter data */ -typedef struct tagTLBParDesc -{ - BSTR Name; - int ctCustData; - TLBCustData * pCustData; /* linked list to cust data */ -} TLBParDesc; - -/* internal Function data */ -typedef struct tagTLBFuncDesc -{ - FUNCDESC funcdesc; /* lots of info on the function and its attributes. */ - BSTR Name; /* the name of this function */ - TLBParDesc *pParamDesc; /* array with param names and custom data */ - int helpcontext; - int HelpStringContext; - BSTR HelpString; - BSTR Entry; /* if its Hiword==0, it numeric; -1 is not present*/ - int ctCustData; - TLBCustData * pCustData; /* linked list to cust data; */ - struct tagTLBFuncDesc * next; -} TLBFuncDesc; - -/* internal Variable data */ -typedef struct tagTLBVarDesc -{ - VARDESC vardesc; /* lots of info on the variable and its attributes. */ - BSTR Name; /* the name of this variable */ - int HelpContext; - int HelpStringContext; /* FIXME: where? */ - BSTR HelpString; - int ctCustData; - TLBCustData * pCustData;/* linked list to cust data; */ - struct tagTLBVarDesc * next; -} TLBVarDesc; - -/* internal implemented interface data */ -typedef struct tagTLBImplType -{ - HREFTYPE hRef; /* hRef of interface */ - int implflags; /* IMPLFLAG_*s */ - int ctCustData; - TLBCustData * pCustData;/* linked list to custom data; */ - struct tagTLBImplType *next; -} TLBImplType; - -/* internal TypeInfo data */ -typedef struct tagITypeInfoImpl -{ - ITypeInfo2Vtbl *lpVtbl; - ITypeCompVtbl *lpVtblTypeComp; - ULONG ref; - TYPEATTR TypeAttr ; /* _lots_ of type information. */ - ITypeLibImpl * pTypeLib; /* back pointer to typelib */ - int index; /* index in this typelib; */ - /* type libs seem to store the doc strings in ascii - * so why should we do it in unicode? - */ - BSTR Name; - BSTR DocString; - unsigned long dwHelpContext; - unsigned long dwHelpStringContext; - - /* functions */ - TLBFuncDesc * funclist; /* linked list with function descriptions */ - - /* variables */ - TLBVarDesc * varlist; /* linked list with variable descriptions */ - - /* Implemented Interfaces */ - TLBImplType * impltypelist; - - TLBRefType * reflist; - int ctCustData; - TLBCustData * pCustData; /* linked list to cust data; */ - struct tagITypeInfoImpl * next; -} ITypeInfoImpl; - -static struct ITypeInfo2Vtbl tinfvt; -static struct ITypeCompVtbl tcompvt; - -static ITypeInfo2 * WINAPI ITypeInfo_Constructor(void); - -typedef struct tagTLBContext -{ - unsigned int oStart; /* start of TLB in file */ - unsigned int pos; /* current pos */ - unsigned int length; /* total length */ - void *mapping; /* memory mapping */ - MSFT_SegDir * pTblDir; - ITypeLibImpl* pLibInfo; -} TLBContext; - - -static void MSFT_DoRefType(TLBContext *pcx, ITypeInfoImpl *pTI, int offset); - -/* - debug -*/ -static void dump_TypeDesc(TYPEDESC *pTD,char *szVarType) { - if (pTD->vt & VT_RESERVED) - szVarType += strlen(strcpy(szVarType, "reserved | ")); - if (pTD->vt & VT_BYREF) - szVarType += strlen(strcpy(szVarType, "ref to ")); - if (pTD->vt & VT_ARRAY) - szVarType += strlen(strcpy(szVarType, "array of ")); - if (pTD->vt & VT_VECTOR) - szVarType += strlen(strcpy(szVarType, "vector of ")); - switch(pTD->vt & VT_TYPEMASK) { - case VT_UI1: sprintf(szVarType, "VT_UI1"); break; - case VT_I2: sprintf(szVarType, "VT_I2"); break; - case VT_I4: sprintf(szVarType, "VT_I4"); break; - case VT_R4: sprintf(szVarType, "VT_R4"); break; - case VT_R8: sprintf(szVarType, "VT_R8"); break; - case VT_BOOL: sprintf(szVarType, "VT_BOOL"); break; - case VT_ERROR: sprintf(szVarType, "VT_ERROR"); break; - case VT_CY: sprintf(szVarType, "VT_CY"); break; - case VT_DATE: sprintf(szVarType, "VT_DATE"); break; - case VT_BSTR: sprintf(szVarType, "VT_BSTR"); break; - case VT_UNKNOWN: sprintf(szVarType, "VT_UNKNOWN"); break; - case VT_DISPATCH: sprintf(szVarType, "VT_DISPATCH"); break; - case VT_I1: sprintf(szVarType, "VT_I1"); break; - case VT_UI2: sprintf(szVarType, "VT_UI2"); break; - case VT_UI4: sprintf(szVarType, "VT_UI4"); break; - case VT_INT: sprintf(szVarType, "VT_INT"); break; - case VT_UINT: sprintf(szVarType, "VT_UINT"); break; - case VT_VARIANT: sprintf(szVarType, "VT_VARIANT"); break; - case VT_VOID: sprintf(szVarType, "VT_VOID"); break; - case VT_HRESULT: sprintf(szVarType, "VT_HRESULT"); break; - case VT_USERDEFINED: sprintf(szVarType, "VT_USERDEFINED ref = %lx", - pTD->u.hreftype); break; - case VT_PTR: sprintf(szVarType, "ptr to "); - dump_TypeDesc(pTD->u.lptdesc, szVarType + 7); - break; - case VT_SAFEARRAY: sprintf(szVarType, "safearray of "); - dump_TypeDesc(pTD->u.lptdesc, szVarType + 13); - break; - case VT_CARRAY: sprintf(szVarType, "%d dim array of ", - pTD->u.lpadesc->cDims); /* FIXME print out sizes */ - dump_TypeDesc(&pTD->u.lpadesc->tdescElem, szVarType + strlen(szVarType)); - break; - - default: sprintf(szVarType, "unknown(%d)", pTD->vt & VT_TYPEMASK); break; - } -} - -void dump_ELEMDESC(ELEMDESC *edesc) { - char buf[200]; - dump_TypeDesc(&edesc->tdesc,buf); - MESSAGE("\t\ttdesc.vartype %d (%s)\n",edesc->tdesc.vt,buf); - MESSAGE("\t\tu.parmadesc.flags %x\n",edesc->u.paramdesc.wParamFlags); - MESSAGE("\t\tu.parmadesc.lpex %p\n",edesc->u.paramdesc.pparamdescex); -} -void dump_FUNCDESC(FUNCDESC *funcdesc) { - int i; - MESSAGE("memid is %08lx\n",funcdesc->memid); - for (i=0;i<funcdesc->cParams;i++) { - MESSAGE("Param %d:\n",i); - dump_ELEMDESC(funcdesc->lprgelemdescParam+i); - } - MESSAGE("\tfunckind: %d (",funcdesc->funckind); - switch (funcdesc->funckind) { - case FUNC_VIRTUAL: MESSAGE("virtual");break; - case FUNC_PUREVIRTUAL: MESSAGE("pure virtual");break; - case FUNC_NONVIRTUAL: MESSAGE("nonvirtual");break; - case FUNC_STATIC: MESSAGE("static");break; - case FUNC_DISPATCH: MESSAGE("dispatch");break; - default: MESSAGE("unknown");break; - } - MESSAGE(")\n\tinvkind: %d (",funcdesc->invkind); - switch (funcdesc->invkind) { - case INVOKE_FUNC: MESSAGE("func");break; - case INVOKE_PROPERTYGET: MESSAGE("property get");break; - case INVOKE_PROPERTYPUT: MESSAGE("property put");break; - case INVOKE_PROPERTYPUTREF: MESSAGE("property put ref");break; - } - MESSAGE(")\n\tcallconv: %d (",funcdesc->callconv); - switch (funcdesc->callconv) { - case CC_CDECL: MESSAGE("cdecl");break; - case CC_PASCAL: MESSAGE("pascal");break; - case CC_STDCALL: MESSAGE("stdcall");break; - case CC_SYSCALL: MESSAGE("syscall");break; - default:break; - } - MESSAGE(")\n\toVft: %d\n", funcdesc->oVft); - MESSAGE("\tcParamsOpt: %d\n", funcdesc->cParamsOpt); - MESSAGE("\twFlags: %x\n", funcdesc->wFuncFlags); - - MESSAGE("\telemdescFunc (return value type):\n"); - dump_ELEMDESC(&funcdesc->elemdescFunc); -} - -void dump_IDLDESC(IDLDESC *idl) { - MESSAGE("\t\twIdlflags: %d\n",idl->wIDLFlags); -} - -static const char * typekind_desc[] = -{ - "TKIND_ENUM", - "TKIND_RECORD", - "TKIND_MODULE", - "TKIND_INTERFACE", - "TKIND_DISPATCH", - "TKIND_COCLASS", - "TKIND_ALIAS", - "TKIND_UNION", - "TKIND_MAX" -}; - -void dump_TYPEATTR(TYPEATTR *tattr) { - char buf[200]; - MESSAGE("\tguid: %s\n",debugstr_guid(&tattr->guid)); - MESSAGE("\tlcid: %ld\n",tattr->lcid); - MESSAGE("\tmemidConstructor: %ld\n",tattr->memidConstructor); - MESSAGE("\tmemidDestructor: %ld\n",tattr->memidDestructor); - MESSAGE("\tschema: %s\n",debugstr_w(tattr->lpstrSchema)); - MESSAGE("\tsizeInstance: %ld\n",tattr->cbSizeInstance); - MESSAGE("\tkind:%s\n", typekind_desc[tattr->typekind]); - MESSAGE("\tcFuncs: %d\n", tattr->cFuncs); - MESSAGE("\tcVars: %d\n", tattr->cVars); - MESSAGE("\tcImplTypes: %d\n", tattr->cImplTypes); - MESSAGE("\tcbSizeVft: %d\n", tattr->cbSizeVft); - MESSAGE("\tcbAlignment: %d\n", tattr->cbAlignment); - MESSAGE("\twTypeFlags: %d\n", tattr->wTypeFlags); - MESSAGE("\tVernum: %d.%d\n", tattr->wMajorVerNum,tattr->wMinorVerNum); - dump_TypeDesc(&tattr->tdescAlias,buf); - MESSAGE("\ttypedesc: %s\n", buf); - dump_IDLDESC(&tattr->idldescType); -} - -static void dump_TLBFuncDescOne(TLBFuncDesc * pfd) -{ - int i; - if (!TRACE_ON(typelib)) - return; - MESSAGE("%s(%u)\n", debugstr_w(pfd->Name), pfd->funcdesc.cParams); - for (i=0;i<pfd->funcdesc.cParams;i++) - MESSAGE("\tparm%d: %s\n",i,debugstr_w(pfd->pParamDesc[i].Name)); - - - dump_FUNCDESC(&(pfd->funcdesc)); - - MESSAGE("\thelpstring: %s\n", debugstr_w(pfd->HelpString)); - MESSAGE("\tentry: %s\n", debugstr_w(pfd->Entry)); -} -static void dump_TLBFuncDesc(TLBFuncDesc * pfd) -{ - while (pfd) - { - dump_TLBFuncDescOne(pfd); - pfd = pfd->next; - }; -} -static void dump_TLBVarDesc(TLBVarDesc * pvd) -{ - while (pvd) - { - TRACE_(typelib)("%s\n", debugstr_w(pvd->Name)); - pvd = pvd->next; - }; -} - -static void dump_TLBImpLib(TLBImpLib *import) -{ - TRACE_(typelib)("%s %s\n", debugstr_guid(&(import->guid)), - debugstr_w(import->name)); - TRACE_(typelib)("v%d.%d lcid=%lx offset=%x\n", import->wVersionMajor, - import->wVersionMinor, import->lcid, import->offset); -} - -static void dump_TLBRefType(TLBRefType * prt) -{ - while (prt) - { - TRACE_(typelib)("href:0x%08lx\n", prt->reference); - if(prt->index == -1) - TRACE_(typelib)("%s\n", debugstr_guid(&(prt->guid))); - else - TRACE_(typelib)("type no: %d\n", prt->index); - - if(prt->pImpTLInfo != TLB_REF_INTERNAL && - prt->pImpTLInfo != TLB_REF_NOT_FOUND) { - TRACE_(typelib)("in lib\n"); - dump_TLBImpLib(prt->pImpTLInfo); - } - prt = prt->next; - }; -} - -static void dump_TLBImplType(TLBImplType * impl) -{ - while (impl) { - TRACE_(typelib)( - "implementing/inheriting interface hRef = %lx implflags %x\n", - impl->hRef, impl->implflags); - impl = impl->next; - } -} - -void dump_Variant(VARIANT * pvar) -{ - SYSTEMTIME st; - - TRACE("%p->{%s%s", pvar, debugstr_VT(pvar), debugstr_VF(pvar)); - - if (pvar) - { - if (V_ISBYREF(pvar) || V_TYPE(pvar) == VT_UNKNOWN || - V_TYPE(pvar) == VT_DISPATCH || V_TYPE(pvar) == VT_RECORD) - { - TRACE(",%p", V_BYREF(pvar)); - } - else if (V_ISARRAY(pvar) || V_ISVECTOR(pvar)) - { - TRACE(",FIXME"); - } - else switch (V_TYPE(pvar)) - { - case VT_I1: TRACE(",%d", V_I1(pvar)); break; - case VT_UI1: TRACE(",%d", V_UI1(pvar)); break; - case VT_I2: TRACE(",%d", V_I2(pvar)); break; - case VT_UI2: TRACE(",%d", V_UI2(pvar)); break; - case VT_INT: - case VT_I4: TRACE(",%ld", V_I4(pvar)); break; - case VT_UINT: - case VT_UI4: TRACE(",%ld", V_UI4(pvar)); break; - case VT_I8: TRACE(",0x%08lx,0x%08lx", (ULONG)(V_I8(pvar) >> 32), - (ULONG)(V_I8(pvar) & 0xffffffff)); break; - case VT_UI8: TRACE(",0x%08lx,0x%08lx", (ULONG)(V_UI8(pvar) >> 32), - (ULONG)(V_UI8(pvar) & 0xffffffff)); break; - case VT_R4: TRACE(",%3.3e", V_R4(pvar)); break; - case VT_R8: TRACE(",%3.3e", V_R8(pvar)); break; - case VT_BOOL: TRACE(",%s", V_BOOL(pvar) ? "TRUE" : "FALSE"); break; - case VT_BSTR: TRACE(",%s", debugstr_w(V_BSTR(pvar))); break; - case VT_CY: TRACE(",0x%08lx,0x%08lx", V_CY(pvar).s.Hi, - V_CY(pvar).s.Lo); break; - case VT_DATE: - if(!VariantTimeToSystemTime(V_DATE(pvar), &st)) - TRACE(",<invalid>"); - else - TRACE(",%04d/%02d/%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay, - st.wHour, st.wMinute, st.wSecond); - break; - case VT_ERROR: - case VT_VOID: - case VT_USERDEFINED: - case VT_EMPTY: - case VT_NULL: break; - default: TRACE(",?"); break; - } - } - TRACE("}\n"); -} - -static void dump_DispParms(DISPPARAMS * pdp) -{ - int index = 0; - - TRACE("args=%u named args=%u\n", pdp->cArgs, pdp->cNamedArgs); - - while (index < pdp->cArgs) - { - dump_Variant( &pdp->rgvarg[index] ); - ++index; - } -} - -static void dump_TypeInfo(ITypeInfoImpl * pty) -{ - TRACE("%p ref=%lu\n", pty, pty->ref); - TRACE("attr:%s\n", debugstr_guid(&(pty->TypeAttr.guid))); - TRACE("kind:%s\n", typekind_desc[pty->TypeAttr.typekind]); - TRACE("fct:%u var:%u impl:%u\n", - pty->TypeAttr.cFuncs, pty->TypeAttr.cVars, pty->TypeAttr.cImplTypes); - TRACE("parent tlb:%p index in TLB:%u\n",pty->pTypeLib, pty->index); - TRACE("%s %s\n", debugstr_w(pty->Name), debugstr_w(pty->DocString)); - dump_TLBFuncDesc(pty->funclist); - dump_TLBVarDesc(pty->varlist); - dump_TLBImplType(pty->impltypelist); -} - -void dump_VARDESC(VARDESC *v) -{ - MESSAGE("memid %ld\n",v->memid); - MESSAGE("lpstrSchema %s\n",debugstr_w(v->lpstrSchema)); - MESSAGE("oInst %ld\n",v->u.oInst); - dump_ELEMDESC(&(v->elemdescVar)); - MESSAGE("wVarFlags %x\n",v->wVarFlags); - MESSAGE("varkind %d\n",v->varkind); -} - -static TYPEDESC stndTypeDesc[VT_LPWSTR+1]= -{ - /* VT_LPWSTR is largest type that */ - /* may appear in type description*/ - {{0}, 0},{{0}, 1},{{0}, 2},{{0}, 3},{{0}, 4}, - {{0}, 5},{{0}, 6},{{0}, 7},{{0}, 8},{{0}, 9}, - {{0},10},{{0},11},{{0},12},{{0},13},{{0},14}, - {{0},15},{{0},16},{{0},17},{{0},18},{{0},19}, - {{0},20},{{0},21},{{0},22},{{0},23},{{0},24}, - {{0},25},{{0},26},{{0},27},{{0},28},{{0},29}, - {{0},30},{{0},31} -}; - -static void TLB_abort() -{ - DebugBreak(); -} -static void * TLB_Alloc(unsigned size) -{ - void * ret; - if((ret=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size))==NULL){ - /* FIXME */ - ERR("cannot allocate memory\n"); - } - return ret; -} - -static void TLB_Free(void * ptr) -{ - HeapFree(GetProcessHeap(), 0, ptr); -} - -/* deep copy a typedesc */ -static void copy_typedesc(TYPEDESC *out, const TYPEDESC *in) -{ - out->vt = in->vt; - switch(in->vt) { - case VT_PTR: - out->u.lptdesc = HeapAlloc(GetProcessHeap(), 0, sizeof(TYPEDESC)); - copy_typedesc(out->u.lptdesc, in->u.lptdesc); - break; - case VT_USERDEFINED: - out->u.hreftype = in->u.hreftype; - break; - case VT_CARRAY: - out->u.lpadesc = HeapAlloc(GetProcessHeap(), 0, sizeof(ARRAYDESC) + - (in->u.lpadesc->cDims - 1) * sizeof(SAFEARRAYBOUND)); - copy_typedesc(&out->u.lpadesc->tdescElem, &in->u.lpadesc->tdescElem); - out->u.lpadesc->cDims = in->u.lpadesc->cDims; - memcpy(out->u.lpadesc->rgbounds, in->u.lpadesc->rgbounds, in->u.lpadesc->cDims * sizeof(SAFEARRAYBOUND)); - break; - default: - break; - } -} - -/* free()s any allocated memory pointed to by the tdesc. NB does not - free the tdesc itself - this is because the tdesc is typically part - of a larger structure */ -static void free_deep_typedesc(TYPEDESC *tdesc) -{ - switch(tdesc->vt) { - case VT_PTR: - free_deep_typedesc(tdesc->u.lptdesc); - HeapFree(GetProcessHeap(), 0, tdesc->u.lptdesc); - tdesc->u.lptdesc = NULL; - break; - case VT_CARRAY: - free_deep_typedesc(&tdesc->u.lpadesc->tdescElem); - HeapFree(GetProcessHeap(), 0, tdesc->u.lpadesc); - tdesc->u.lpadesc = NULL; - break; - default: - break; - } -} - -/********************************************************************** - * - * Functions for reading MSFT typelibs (those created by CreateTypeLib2) - */ -/* read function */ -DWORD MSFT_Read(void *buffer, DWORD count, TLBContext *pcx, long where ) -{ - TRACE_(typelib)("pos=0x%08x len=0x%08lx 0x%08x 0x%08x 0x%08lx\n", - pcx->pos, count, pcx->oStart, pcx->length, where); - - if (where != DO_NOT_SEEK) - { - where += pcx->oStart; - if (where > pcx->length) - { - /* FIXME */ - ERR("seek beyond end (%ld/%d)\n", where, pcx->length ); - TLB_abort(); - } - pcx->pos = where; - } - if (pcx->pos + count > pcx->length) count = pcx->length - pcx->pos; - memcpy( buffer, (char *)pcx->mapping + pcx->pos, count ); - pcx->pos += count; - return count; -} - -static DWORD MSFT_ReadLEDWords(void *buffer, DWORD count, TLBContext *pcx, - long where ) -{ - DWORD ret; - - ret = MSFT_Read(buffer, count, pcx, where); - FromLEDWords(buffer, ret); - - return ret; -} - -static DWORD MSFT_ReadLEWords(void *buffer, DWORD count, TLBContext *pcx, - long where ) -{ - DWORD ret; - - ret = MSFT_Read(buffer, count, pcx, where); - FromLEWords(buffer, ret); - - return ret; -} - -static void MSFT_ReadGuid( GUID *pGuid, int offset, TLBContext *pcx) -{ - if(offset<0 || pcx->pTblDir->pGuidTab.offset <0){ - memset(pGuid,0, sizeof(GUID)); - return; - } - MSFT_Read(pGuid, sizeof(GUID), pcx, pcx->pTblDir->pGuidTab.offset+offset ); - pGuid->Data1 = FromLEDWord(pGuid->Data1); - pGuid->Data2 = FromLEWord(pGuid->Data2); - pGuid->Data3 = FromLEWord(pGuid->Data3); - TRACE_(typelib)("%s\n", debugstr_guid(pGuid)); -} - -BSTR MSFT_ReadName( TLBContext *pcx, int offset) -{ - char * name; - MSFT_NameIntro niName; - int lengthInChars; - WCHAR* pwstring = NULL; - BSTR bstrName = NULL; - - MSFT_ReadLEDWords(&niName, sizeof(niName), pcx, - pcx->pTblDir->pNametab.offset+offset); - niName.namelen &= 0xFF; /* FIXME: correct ? */ - name=TLB_Alloc((niName.namelen & 0xff) +1); - MSFT_Read(name, (niName.namelen & 0xff), pcx, DO_NOT_SEEK); - name[niName.namelen & 0xff]='\0'; - - lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, - name, -1, NULL, 0); - - /* no invalid characters in string */ - if (lengthInChars) - { - pwstring = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*lengthInChars); - - /* don't check for invalid character since this has been done previously */ - MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, pwstring, lengthInChars); - - bstrName = SysAllocStringLen(pwstring, lengthInChars); - lengthInChars = SysStringLen(bstrName); - HeapFree(GetProcessHeap(), 0, pwstring); - } - - TRACE_(typelib)("%s %d\n", debugstr_w(bstrName), lengthInChars); - return bstrName; -} - -BSTR MSFT_ReadString( TLBContext *pcx, int offset) -{ - char * string; - INT16 length; - int lengthInChars; - BSTR bstr = NULL; - - if(offset<0) return NULL; - MSFT_ReadLEWords(&length, sizeof(INT16), pcx, pcx->pTblDir->pStringtab.offset+offset); - if(length <= 0) return 0; - string=TLB_Alloc(length +1); - MSFT_Read(string, length, pcx, DO_NOT_SEEK); - string[length]='\0'; - - lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, - string, -1, NULL, 0); - - /* no invalid characters in string */ - if (lengthInChars) - { - WCHAR* pwstring = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*lengthInChars); - - /* don't check for invalid character since this has been done previously */ - MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, string, -1, pwstring, lengthInChars); - - bstr = SysAllocStringLen(pwstring, lengthInChars); - lengthInChars = SysStringLen(bstr); - HeapFree(GetProcessHeap(), 0, pwstring); - } - - TRACE_(typelib)("%s %d\n", debugstr_w(bstr), lengthInChars); - return bstr; -} -/* - * read a value and fill a VARIANT structure - */ -static void MSFT_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx ) -{ - int size; - - TRACE_(typelib)("\n"); - - if(offset <0) { /* data are packed in here */ - V_VT(pVar) = (offset & 0x7c000000 )>> 26; - V_I2(pVar) = offset & 0x3ffffff; - return; - } - MSFT_ReadLEWords(&(V_VT(pVar)), sizeof(VARTYPE), pcx, - pcx->pTblDir->pCustData.offset + offset ); - TRACE_(typelib)("Vartype = %x\n", V_VT(pVar)); - switch (V_VT(pVar)){ - case VT_EMPTY: /* FIXME: is this right? */ - case VT_NULL: /* FIXME: is this right? */ - case VT_I2 : /* this should not happen */ - case VT_I4 : - case VT_R4 : - case VT_ERROR : - case VT_BOOL : - case VT_I1 : - case VT_UI1 : - case VT_UI2 : - case VT_UI4 : - case VT_INT : - case VT_UINT : - case VT_VOID : /* FIXME: is this right? */ - case VT_HRESULT : - size=4; break; - case VT_R8 : - case VT_CY : - case VT_DATE : - case VT_I8 : - case VT_UI8 : - case VT_DECIMAL : /* FIXME: is this right? */ - case VT_FILETIME : - size=8;break; - /* pointer types with known behaviour */ - case VT_BSTR :{ - char * ptr; - MSFT_ReadLEDWords(&size, sizeof(INT), pcx, DO_NOT_SEEK ); - if(size < 0) { - FIXME("BSTR length = %d?\n", size); - } else { - ptr=TLB_Alloc(size);/* allocate temp buffer */ - MSFT_Read(ptr, size, pcx, DO_NOT_SEEK);/* read string (ANSI) */ - V_BSTR(pVar)=SysAllocStringLen(NULL,size); - /* FIXME: do we need a AtoW conversion here? */ - V_UNION(pVar, bstrVal[size])=L'\0'; - while(size--) V_UNION(pVar, bstrVal[size])=ptr[size]; - TLB_Free(ptr); - } - } - size=-4; break; - /* FIXME: this will not work AT ALL when the variant contains a pointer */ - case VT_DISPATCH : - case VT_VARIANT : - case VT_UNKNOWN : - case VT_PTR : - case VT_SAFEARRAY : - case VT_CARRAY : - case VT_USERDEFINED : - case VT_LPSTR : - case VT_LPWSTR : - case VT_BLOB : - case VT_STREAM : - case VT_STORAGE : - case VT_STREAMED_OBJECT : - case VT_STORED_OBJECT : - case VT_BLOB_OBJECT : - case VT_CF : - case VT_CLSID : - default: - size=0; - FIXME("VARTYPE %d is not supported, setting pointer to NULL\n", - V_VT(pVar)); - } - - if(size>0) /* (big|small) endian correct? */ - MSFT_Read(&(V_I2(pVar)), size, pcx, DO_NOT_SEEK ); - return; -} -/* - * create a linked list with custom data - */ -static int MSFT_CustData( TLBContext *pcx, int offset, TLBCustData** ppCustData ) -{ - MSFT_CDGuid entry; - TLBCustData* pNew; - int count=0; - - TRACE_(typelib)("\n"); - - while(offset >=0){ - count++; - pNew=TLB_Alloc(sizeof(TLBCustData)); - MSFT_ReadLEDWords(&entry, sizeof(entry), pcx, pcx->pTblDir->pCDGuids.offset+offset); - MSFT_ReadGuid(&(pNew->guid), entry.GuidOffset , pcx); - MSFT_ReadValue(&(pNew->data), entry.DataOffset, pcx); - /* add new custom data at head of the list */ - pNew->next=*ppCustData; - *ppCustData=pNew; - offset = entry.next; - } - return count; -} - -static void MSFT_GetTdesc(TLBContext *pcx, INT type, TYPEDESC *pTd, - ITypeInfoImpl *pTI) -{ - if(type <0) - pTd->vt=type & VT_TYPEMASK; - else - *pTd=pcx->pLibInfo->pTypeDesc[type/(2*sizeof(INT))]; - - if(pTd->vt == VT_USERDEFINED) - MSFT_DoRefType(pcx, pTI, pTd->u.hreftype); - - TRACE_(typelib)("vt type = %X\n", pTd->vt); -} - -static void -MSFT_DoFuncs(TLBContext* pcx, - ITypeInfoImpl* pTI, - int cFuncs, - int cVars, - int offset, - TLBFuncDesc** pptfd) -{ - /* - * member information is stored in a data structure at offset - * indicated by the memoffset field of the typeinfo structure - * There are several distinctive parts. - * The first part starts with a field that holds the total length - * of this (first) part excluding this field. Then follow the records, - * for each member there is one record. - * - * The first entry is always the length of the record (including this - * length word). - * The rest of the record depends on the type of the member. If there is - * a field indicating the member type (function, variable, interface, etc) - * I have not found it yet. At this time we depend on the information - * in the type info and the usual order how things are stored. - * - * Second follows an array sized nrMEM*sizeof(INT) with a member id - * for each member; - * - * Third is an equal sized array with file offsets to the name entry - * of each member. - * - * The fourth and last (?) part is an array with offsets to the records - * in the first part of this file segment. - */ - - int infolen, nameoffset, reclength, nrattributes, i; - int recoffset = offset + sizeof(INT); - - char recbuf[512]; - MSFT_FuncRecord * pFuncRec=(MSFT_FuncRecord *) recbuf; - - TRACE_(typelib)("\n"); - - MSFT_ReadLEDWords(&infolen, sizeof(INT), pcx, offset); - - for ( i = 0; i < cFuncs ; i++ ) - { - *pptfd = TLB_Alloc(sizeof(TLBFuncDesc)); - - /* name, eventually add to a hash table */ - MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx, - offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT)); - - (*pptfd)->Name = MSFT_ReadName(pcx, nameoffset); - - /* read the function information record */ - MSFT_ReadLEDWords(&reclength, sizeof(INT), pcx, recoffset); - - reclength &= 0x1ff; - - MSFT_ReadLEDWords(pFuncRec, reclength - sizeof(INT), pcx, DO_NOT_SEEK); - - /* do the attributes */ - nrattributes = (reclength - pFuncRec->nrargs * 3 * sizeof(int) - 0x18) - / sizeof(int); - - if ( nrattributes > 0 ) - { - (*pptfd)->helpcontext = pFuncRec->OptAttr[0] ; - - if ( nrattributes > 1 ) - { - (*pptfd)->HelpString = MSFT_ReadString(pcx, - pFuncRec->OptAttr[1]) ; - - if ( nrattributes > 2 ) - { - if ( pFuncRec->FKCCIC & 0x2000 ) - { - (*pptfd)->Entry = (WCHAR*) pFuncRec->OptAttr[2] ; - } - else - { - (*pptfd)->Entry = MSFT_ReadString(pcx, - pFuncRec->OptAttr[2]); - } - if( nrattributes > 5 ) - { - (*pptfd)->HelpStringContext = pFuncRec->OptAttr[5] ; - - if ( nrattributes > 6 && pFuncRec->FKCCIC & 0x80 ) - { - MSFT_CustData(pcx, - pFuncRec->OptAttr[6], - &(*pptfd)->pCustData); - } - } - } - } - } - - /* fill the FuncDesc Structure */ - MSFT_ReadLEDWords( & (*pptfd)->funcdesc.memid, sizeof(INT), pcx, - offset + infolen + ( i + 1) * sizeof(INT)); - - (*pptfd)->funcdesc.funckind = (pFuncRec->FKCCIC) & 0x7; - (*pptfd)->funcdesc.invkind = (pFuncRec->FKCCIC) >> 3 & 0xF; - (*pptfd)->funcdesc.callconv = (pFuncRec->FKCCIC) >> 8 & 0xF; - (*pptfd)->funcdesc.cParams = pFuncRec->nrargs ; - (*pptfd)->funcdesc.cParamsOpt = pFuncRec->nroargs ; - (*pptfd)->funcdesc.oVft = pFuncRec->VtableOffset ; - (*pptfd)->funcdesc.wFuncFlags = LOWORD(pFuncRec->Flags) ; - - MSFT_GetTdesc(pcx, - pFuncRec->DataType, - &(*pptfd)->funcdesc.elemdescFunc.tdesc, - pTI); - - /* do the parameters/arguments */ - if(pFuncRec->nrargs) - { - int j = 0; - MSFT_ParameterInfo paraminfo; - - (*pptfd)->funcdesc.lprgelemdescParam = - TLB_Alloc(pFuncRec->nrargs * sizeof(ELEMDESC)); - - (*pptfd)->pParamDesc = - TLB_Alloc(pFuncRec->nrargs * sizeof(TLBParDesc)); - - MSFT_ReadLEDWords(¶minfo, sizeof(paraminfo), pcx, - recoffset + reclength - pFuncRec->nrargs * sizeof(MSFT_ParameterInfo)); - - for ( j = 0 ; j < pFuncRec->nrargs ; j++ ) - { - TYPEDESC* lpArgTypeDesc = 0; - - MSFT_GetTdesc(pcx, - paraminfo.DataType, - &(*pptfd)->funcdesc.lprgelemdescParam[j].tdesc, - pTI); - - (*pptfd)->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags = paraminfo.Flags; - - (*pptfd)->pParamDesc[j].Name = (void *) paraminfo.oName; - - /* SEEK value = jump to offset, - * from there jump to the end of record, - * go back by (j-1) arguments - */ - MSFT_ReadLEDWords( ¶minfo , - sizeof(MSFT_ParameterInfo), pcx, - recoffset + reclength - ((pFuncRec->nrargs - j - 1) - * sizeof(MSFT_ParameterInfo))); - lpArgTypeDesc = - & ((*pptfd)->funcdesc.lprgelemdescParam[j].tdesc); - - while ( lpArgTypeDesc != NULL ) - { - switch ( lpArgTypeDesc->vt ) - { - case VT_PTR: - lpArgTypeDesc = lpArgTypeDesc->u.lptdesc; - break; - - case VT_CARRAY: - lpArgTypeDesc = & (lpArgTypeDesc->u.lpadesc->tdescElem); - break; - - case VT_USERDEFINED: - MSFT_DoRefType(pcx, pTI, - lpArgTypeDesc->u.hreftype); - - lpArgTypeDesc = NULL; - break; - - default: - lpArgTypeDesc = NULL; - } - } - } - - - /* parameter is the return value! */ - if ( paraminfo.Flags & PARAMFLAG_FRETVAL ) - { - TYPEDESC* lpArgTypeDesc; - - (*pptfd)->funcdesc.elemdescFunc = - (*pptfd)->funcdesc.lprgelemdescParam[j]; - - lpArgTypeDesc = & ((*pptfd)->funcdesc.elemdescFunc.tdesc) ; - - while ( lpArgTypeDesc != NULL ) - { - switch ( lpArgTypeDesc->vt ) - { - case VT_PTR: - lpArgTypeDesc = lpArgTypeDesc->u.lptdesc; - break; - case VT_CARRAY: - lpArgTypeDesc = - & (lpArgTypeDesc->u.lpadesc->tdescElem); - - break; - - case VT_USERDEFINED: - MSFT_DoRefType(pcx, - pTI, - lpArgTypeDesc->u.hreftype); - - lpArgTypeDesc = NULL; - break; - - default: - lpArgTypeDesc = NULL; - } - } - } - - /* second time around */ - for(j=0;j<pFuncRec->nrargs;j++) - { - /* name */ - (*pptfd)->pParamDesc[j].Name = - MSFT_ReadName( pcx, (int)(*pptfd)->pParamDesc[j].Name ); - - /* default value */ - if ( (PARAMFLAG_FHASDEFAULT & - (*pptfd)->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags) && - ((pFuncRec->FKCCIC) & 0x1000) ) - { - INT* pInt = (INT *)((char *)pFuncRec + - reclength - - (pFuncRec->nrargs * 4 + 1) * sizeof(INT) ); - - PARAMDESC* pParamDesc = & (*pptfd)->funcdesc.lprgelemdescParam[j].u.paramdesc; - - pParamDesc->pparamdescex = TLB_Alloc(sizeof(PARAMDESCEX)); - pParamDesc->pparamdescex->cBytes = sizeof(PARAMDESCEX); - - MSFT_ReadValue(&(pParamDesc->pparamdescex->varDefaultValue), - pInt[j], pcx); - } - /* custom info */ - if ( nrattributes > 7 + j && pFuncRec->FKCCIC & 0x80 ) - { - MSFT_CustData(pcx, - pFuncRec->OptAttr[7+j], - &(*pptfd)->pParamDesc[j].pCustData); - } - } - } - - /* scode is not used: archaic win16 stuff FIXME: right? */ - (*pptfd)->funcdesc.cScodes = 0 ; - (*pptfd)->funcdesc.lprgscode = NULL ; - - pptfd = & ((*pptfd)->next); - recoffset += reclength; - } -} - -static void MSFT_DoVars(TLBContext *pcx, ITypeInfoImpl *pTI, int cFuncs, - int cVars, int offset, TLBVarDesc ** pptvd) -{ - int infolen, nameoffset, reclength; - char recbuf[256]; - MSFT_VarRecord * pVarRec=(MSFT_VarRecord *) recbuf; - int i; - int recoffset; - - TRACE_(typelib)("\n"); - - MSFT_ReadLEDWords(&infolen,sizeof(INT), pcx, offset); - MSFT_ReadLEDWords(&recoffset,sizeof(INT), pcx, offset + infolen + - ((cFuncs+cVars)*2+cFuncs + 1)*sizeof(INT)); - recoffset += offset+sizeof(INT); - for(i=0;i<cVars;i++){ - *pptvd=TLB_Alloc(sizeof(TLBVarDesc)); - /* name, eventually add to a hash table */ - MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx, - offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT)); - (*pptvd)->Name=MSFT_ReadName(pcx, nameoffset); - /* read the variable information record */ - MSFT_ReadLEDWords(&reclength, sizeof(INT), pcx, recoffset); - reclength &=0xff; - MSFT_ReadLEDWords(pVarRec, reclength - sizeof(INT), pcx, DO_NOT_SEEK); - /* Optional data */ - if(reclength >(6*sizeof(INT)) ) - (*pptvd)->HelpContext=pVarRec->HelpContext; - if(reclength >(7*sizeof(INT)) ) - (*pptvd)->HelpString = MSFT_ReadString(pcx, pVarRec->oHelpString) ; - if(reclength >(8*sizeof(INT)) ) - if(reclength >(9*sizeof(INT)) ) - (*pptvd)->HelpStringContext=pVarRec->HelpStringContext; - /* fill the VarDesc Structure */ - MSFT_ReadLEDWords(&(*pptvd)->vardesc.memid, sizeof(INT), pcx, - offset + infolen + ( i + 1) * sizeof(INT)); - (*pptvd)->vardesc.varkind = pVarRec->VarKind; - (*pptvd)->vardesc.wVarFlags = pVarRec->Flags; - MSFT_GetTdesc(pcx, pVarRec->DataType, - &(*pptvd)->vardesc.elemdescVar.tdesc, pTI); -/* (*pptvd)->vardesc.lpstrSchema; is reserved (SDK) FIXME?? */ - if(pVarRec->VarKind == VAR_CONST ){ - (*pptvd)->vardesc.u.lpvarValue=TLB_Alloc(sizeof(VARIANT)); - MSFT_ReadValue((*pptvd)->vardesc.u.lpvarValue, - pVarRec->OffsValue, pcx); - } else - (*pptvd)->vardesc.u.oInst=pVarRec->OffsValue; - pptvd=&((*pptvd)->next); - recoffset += reclength; - } -} -/* fill in data for a hreftype (offset). When the referenced type is contained - * in the typelib, it's just an (file) offset in the type info base dir. - * If comes from import, it's an offset+1 in the ImpInfo table - * */ -static void MSFT_DoRefType(TLBContext *pcx, ITypeInfoImpl *pTI, - int offset) -{ - int j; - TLBRefType **ppRefType = &pTI->reflist; - - TRACE_(typelib)("TLB context %p, TLB offset %x\n", pcx, offset); - - while(*ppRefType) { - if((*ppRefType)->reference == offset) - return; - ppRefType = &(*ppRefType)->next; - } - - *ppRefType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(**ppRefType)); - - if(!MSFT_HREFTYPE_INTHISFILE( offset)) { - /* external typelib */ - MSFT_ImpInfo impinfo; - TLBImpLib *pImpLib=(pcx->pLibInfo->pImpLibs); - - TRACE_(typelib)("offset %x, masked offset %x\n", offset, offset + (offset & 0xfffffffc)); - - MSFT_ReadLEDWords(&impinfo, sizeof(impinfo), pcx, - pcx->pTblDir->pImpInfo.offset + (offset & 0xfffffffc)); - for(j=0;pImpLib;j++){ /* search the known offsets of all import libraries */ - if(pImpLib->offset==impinfo.oImpFile) break; - pImpLib=pImpLib->next; - } - if(pImpLib){ - (*ppRefType)->reference=offset; - (*ppRefType)->pImpTLInfo = pImpLib; - MSFT_ReadGuid(&(*ppRefType)->guid, impinfo.oGuid, pcx); - (*ppRefType)->index = TLB_REF_USE_GUID; - }else{ - ERR("Cannot find a reference\n"); - (*ppRefType)->reference=-1; - (*ppRefType)->pImpTLInfo=TLB_REF_NOT_FOUND; - } - }else{ - /* in this typelib */ - (*ppRefType)->index = MSFT_HREFTYPE_INDEX(offset); - (*ppRefType)->reference=offset; - (*ppRefType)->pImpTLInfo=TLB_REF_INTERNAL; - } -} - -/* process Implemented Interfaces of a com class */ -static void MSFT_DoImplTypes(TLBContext *pcx, ITypeInfoImpl *pTI, int count, - int offset) -{ - int i; - MSFT_RefRecord refrec; - TLBImplType **ppImpl = &pTI->impltypelist; - - TRACE_(typelib)("\n"); - - for(i=0;i<count;i++){ - if(offset<0) break; /* paranoia */ - *ppImpl=TLB_Alloc(sizeof(**ppImpl)); - MSFT_ReadLEDWords(&refrec,sizeof(refrec),pcx,offset+pcx->pTblDir->pRefTab.offset); - MSFT_DoRefType(pcx, pTI, refrec.reftype); - (*ppImpl)->hRef = refrec.reftype; - (*ppImpl)->implflags=refrec.flags; - (*ppImpl)->ctCustData= - MSFT_CustData(pcx, refrec.oCustData, &(*ppImpl)->pCustData); - offset=refrec.onext; - ppImpl=&((*ppImpl)->next); - } -} -/* - * process a typeinfo record - */ -ITypeInfoImpl * MSFT_DoTypeInfo( - TLBContext *pcx, - int count, - ITypeLibImpl * pLibInfo) -{ - MSFT_TypeInfoBase tiBase; - ITypeInfoImpl *ptiRet; - - TRACE_(typelib)("count=%u\n", count); - - ptiRet = (ITypeInfoImpl*) ITypeInfo_Constructor(); - MSFT_ReadLEDWords(&tiBase, sizeof(tiBase) ,pcx , - pcx->pTblDir->pTypeInfoTab.offset+count*sizeof(tiBase)); -/* this is where we are coming from */ - ptiRet->pTypeLib = pLibInfo; - ptiRet->index=count; -/* fill in the typeattr fields */ - WARN("Assign constructor/destructor memid\n"); - - MSFT_ReadGuid(&ptiRet->TypeAttr.guid, tiBase.posguid, pcx); - ptiRet->TypeAttr.lcid=pLibInfo->LibAttr.lcid; /* FIXME: correct? */ - ptiRet->TypeAttr.memidConstructor=MEMBERID_NIL ;/* FIXME */ - ptiRet->TypeAttr.memidDestructor=MEMBERID_NIL ; /* FIXME */ - ptiRet->TypeAttr.lpstrSchema=NULL; /* reserved */ - ptiRet->TypeAttr.cbSizeInstance=tiBase.size; - ptiRet->TypeAttr.typekind=tiBase.typekind & 0xF; - ptiRet->TypeAttr.cFuncs=LOWORD(tiBase.cElement); - ptiRet->TypeAttr.cVars=HIWORD(tiBase.cElement); - ptiRet->TypeAttr.cbAlignment=(tiBase.typekind >> 11 )& 0x1F; /* there are more flags there */ - ptiRet->TypeAttr.wTypeFlags=tiBase.flags; - ptiRet->TypeAttr.wMajorVerNum=LOWORD(tiBase.version); - ptiRet->TypeAttr.wMinorVerNum=HIWORD(tiBase.version); - ptiRet->TypeAttr.cImplTypes=tiBase.cImplTypes; - ptiRet->TypeAttr.cbSizeVft=tiBase.cbSizeVft; /* FIXME: this is only the non inherited part */ - if(ptiRet->TypeAttr.typekind == TKIND_ALIAS) - MSFT_GetTdesc(pcx, tiBase.datatype1, - &ptiRet->TypeAttr.tdescAlias, ptiRet); - -/* FIXME: */ -/* IDLDESC idldescType; *//* never saw this one != zero */ - -/* name, eventually add to a hash table */ - ptiRet->Name=MSFT_ReadName(pcx, tiBase.NameOffset); - TRACE_(typelib)("reading %s\n", debugstr_w(ptiRet->Name)); - /* help info */ - ptiRet->DocString=MSFT_ReadString(pcx, tiBase.docstringoffs); - ptiRet->dwHelpStringContext=tiBase.helpstringcontext; - ptiRet->dwHelpContext=tiBase.helpcontext; -/* note: InfoType's Help file and HelpStringDll come from the containing - * library. Further HelpString and Docstring appear to be the same thing :( - */ - /* functions */ - if(ptiRet->TypeAttr.cFuncs >0 ) - MSFT_DoFuncs(pcx, ptiRet, ptiRet->TypeAttr.cFuncs, - ptiRet->TypeAttr.cVars, - tiBase.memoffset, & ptiRet->funclist); - /* variables */ - if(ptiRet->TypeAttr.cVars >0 ) - MSFT_DoVars(pcx, ptiRet, ptiRet->TypeAttr.cFuncs, - ptiRet->TypeAttr.cVars, - tiBase.memoffset, & ptiRet->varlist); - if(ptiRet->TypeAttr.cImplTypes >0 ) { - switch(ptiRet->TypeAttr.typekind) - { - case TKIND_COCLASS: - MSFT_DoImplTypes(pcx, ptiRet, ptiRet->TypeAttr.cImplTypes , - tiBase.datatype1); - break; - case TKIND_DISPATCH: - ptiRet->impltypelist=TLB_Alloc(sizeof(TLBImplType)); - - if (tiBase.datatype1 != -1) - { - MSFT_DoRefType(pcx, ptiRet, tiBase.datatype1); - ptiRet->impltypelist->hRef = tiBase.datatype1; - } - else - { /* FIXME: This is a really bad hack to add IDispatch */ - const char* szStdOle = "stdole2.tlb\0"; - int nStdOleLen = strlen(szStdOle); - TLBRefType **ppRef = &ptiRet->reflist; - - while(*ppRef) { - if((*ppRef)->reference == -1) - break; - ppRef = &(*ppRef)->next; - } - if(!*ppRef) { - *ppRef = TLB_Alloc(sizeof(**ppRef)); - (*ppRef)->guid = IID_IDispatch; - (*ppRef)->reference = -1; - (*ppRef)->index = TLB_REF_USE_GUID; - (*ppRef)->pImpTLInfo = TLB_Alloc(sizeof(TLBImpLib)); - (*ppRef)->pImpTLInfo->guid = IID_StdOle; - (*ppRef)->pImpTLInfo->name = SysAllocStringLen(NULL, - nStdOleLen + 1); - - MultiByteToWideChar(CP_ACP, - MB_PRECOMPOSED, - szStdOle, - -1, - (*ppRef)->pImpTLInfo->name, - SysStringLen((*ppRef)->pImpTLInfo->name)); - - (*ppRef)->pImpTLInfo->lcid = 0; - (*ppRef)->pImpTLInfo->wVersionMajor = 2; - (*ppRef)->pImpTLInfo->wVersionMinor = 0; - } - } - break; - default: - ptiRet->impltypelist=TLB_Alloc(sizeof(TLBImplType)); - MSFT_DoRefType(pcx, ptiRet, tiBase.datatype1); - ptiRet->impltypelist->hRef = tiBase.datatype1; - break; - } - } - ptiRet->ctCustData= - MSFT_CustData(pcx, tiBase.oCustData, &ptiRet->pCustData); - - TRACE_(typelib)("%s guid: %s kind:%s\n", - debugstr_w(ptiRet->Name), - debugstr_guid(&ptiRet->TypeAttr.guid), - typekind_desc[ptiRet->TypeAttr.typekind]); - - return ptiRet; -} - -/* Because type library parsing has some degree of overhead, and some apps repeatedly load the same - * typelibs over and over, we cache them here. According to MSDN Microsoft have a similar scheme in - * place. This will cause a deliberate memory leak, but generally losing RAM for cycles is an acceptable - * tradeoff here. - */ -static ITypeLibImpl *tlb_cache_first; -static CRITICAL_SECTION cache_section; -static CRITICAL_SECTION_DEBUG cache_section_debug = -{ - 0, 0, &cache_section, - { &cache_section_debug.ProcessLocksList, &cache_section_debug.ProcessLocksList }, - 0, 0, { 0, (DWORD)(__FILE__ ": typelib loader cache") } -}; -static CRITICAL_SECTION cache_section = { &cache_section_debug, -1, 0, 0, 0, 0 }; - - -/**************************************************************************** - * TLB_ReadTypeLib - * - * find the type of the typelib file and map the typelib resource into - * the memory - */ -#define MSFT_SIGNATURE 0x5446534D /* "MSFT" */ -#define SLTG_SIGNATURE 0x47544c53 /* "SLTG" */ -int TLB_ReadTypeLib(LPCWSTR pszFileName, INT index, ITypeLib2 **ppTypeLib) -{ - ITypeLibImpl *entry; - int ret = TYPE_E_CANTLOADLIBRARY; - DWORD dwSignature = 0; - HANDLE hFile; - - TRACE_(typelib)("%s:%d\n", debugstr_w(pszFileName), index); - - *ppTypeLib = NULL; - - /* We look the path up in the typelib cache. If found, we just addref it, and return the pointer. */ - EnterCriticalSection(&cache_section); - for (entry = tlb_cache_first; entry != NULL; entry = entry->next) - { - if (!strcmpiW(entry->path, pszFileName) && entry->index == index) - { - TRACE("cache hit\n"); - *ppTypeLib = (ITypeLib2*)entry; - ITypeLib_AddRef(*ppTypeLib); - LeaveCriticalSection(&cache_section); - return S_OK; - } - } - LeaveCriticalSection(&cache_section); - - /* check the signature of the file */ - hFile = CreateFileW( pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); - if (INVALID_HANDLE_VALUE != hFile) - { - HANDLE hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL ); - if (hMapping) - { - LPVOID pBase = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0); - if(pBase) - { - /* retrieve file size */ - DWORD dwTLBLength = GetFileSize(hFile, NULL); - - /* first try to load as *.tlb */ - dwSignature = FromLEDWord(*((DWORD*) pBase)); - if ( dwSignature == MSFT_SIGNATURE) - { - *ppTypeLib = ITypeLib2_Constructor_MSFT(pBase, dwTLBLength); - } - else if ( dwSignature == SLTG_SIGNATURE) - { - *ppTypeLib = ITypeLib2_Constructor_SLTG(pBase, dwTLBLength); - } - UnmapViewOfFile(pBase); - } - CloseHandle(hMapping); - } - CloseHandle(hFile); - } - else - { - TRACE("not found, trying to load %s as library\n", debugstr_w(pszFileName)); - } - - /* if the file is a DLL or not found, try loading it with LoadLibrary */ - if (((WORD)dwSignature == IMAGE_DOS_SIGNATURE) || (dwSignature == 0)) - { - /* find the typelibrary resource*/ - HINSTANCE hinstDLL = LoadLibraryExW(pszFileName, 0, DONT_RESOLVE_DLL_REFERENCES| - LOAD_LIBRARY_AS_DATAFILE|LOAD_WITH_ALTERED_SEARCH_PATH); - if (hinstDLL) - { - static const WCHAR TYPELIBW[] = {'T','Y','P','E','L','I','B',0}; - HRSRC hrsrc = FindResourceW(hinstDLL, MAKEINTRESOURCEW(index), TYPELIBW); - if (hrsrc) - { - HGLOBAL hGlobal = LoadResource(hinstDLL, hrsrc); - if (hGlobal) - { - LPVOID pBase = LockResource(hGlobal); - DWORD dwTLBLength = SizeofResource(hinstDLL, hrsrc); - - if (pBase) - { - /* try to load as incore resource */ - dwSignature = FromLEDWord(*((DWORD*) pBase)); - if ( dwSignature == MSFT_SIGNATURE) - { - *ppTypeLib = ITypeLib2_Constructor_MSFT(pBase, dwTLBLength); - } - else if ( dwSignature == SLTG_SIGNATURE) - { - *ppTypeLib = ITypeLib2_Constructor_SLTG(pBase, dwTLBLength); - } - else - { - FIXME("Header type magic 0x%08lx not supported.\n",dwSignature); - } - } - FreeResource( hGlobal ); - } - } - FreeLibrary(hinstDLL); - } - } - - if(*ppTypeLib) { - ITypeLibImpl *impl = (ITypeLibImpl*)*ppTypeLib; - - TRACE("adding to cache\n"); - impl->path = HeapAlloc(GetProcessHeap(), 0, (strlenW(pszFileName)+1) * sizeof(WCHAR)); - lstrcpyW(impl->path, pszFileName); - /* We should really canonicalise the path here. */ - impl->index = index; - - /* FIXME: check if it has added already in the meantime */ - EnterCriticalSection(&cache_section); - if ((impl->next = tlb_cache_first) != NULL) impl->next->prev = impl; - impl->prev = NULL; - tlb_cache_first = impl; - LeaveCriticalSection(&cache_section); - ret = S_OK; - } else - ERR("Loading of typelib %s failed with error %ld\n", debugstr_w(pszFileName), GetLastError()); - - return ret; -} - -/*================== ITypeLib(2) Methods ===================================*/ - -/**************************************************************************** - * ITypeLib2_Constructor_MSFT - * - * loading an MSFT typelib from an in-memory image - */ -static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength) -{ - TLBContext cx; - long lPSegDir; - MSFT_Header tlbHeader; - MSFT_SegDir tlbSegDir; - ITypeLibImpl * pTypeLibImpl; - - TRACE("%p, TLB length = %ld\n", pLib, dwTLBLength); - - pTypeLibImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeLibImpl)); - if (!pTypeLibImpl) return NULL; - - pTypeLibImpl->lpVtbl = &tlbvt; - pTypeLibImpl->lpVtblTypeComp = &tlbtcvt; - pTypeLibImpl->ref = 1; - - /* get pointer to beginning of typelib data */ - cx.pos = 0; - cx.oStart=0; - cx.mapping = pLib; - cx.pLibInfo = pTypeLibImpl; - cx.length = dwTLBLength; - - /* read header */ - MSFT_ReadLEDWords((void*)&tlbHeader, sizeof(tlbHeader), &cx, 0); - TRACE("header:\n"); - TRACE("\tmagic1=0x%08x ,magic2=0x%08x\n",tlbHeader.magic1,tlbHeader.magic2 ); - if (tlbHeader.magic1 != MSFT_SIGNATURE) { - FIXME("Header type magic 0x%08x not supported.\n",tlbHeader.magic1); - return NULL; - } - /* there is a small amount of information here until the next important - * part: - * the segment directory . Try to calculate the amount of data */ - lPSegDir = sizeof(tlbHeader) + (tlbHeader.nrtypeinfos)*4 + ((tlbHeader.varflags & HELPDLLFLAG)? 4 :0); - - /* now read the segment directory */ - TRACE("read segment directory (at %ld)\n",lPSegDir); - MSFT_ReadLEDWords(&tlbSegDir, sizeof(tlbSegDir), &cx, lPSegDir); - cx.pTblDir = &tlbSegDir; - - /* just check two entries */ - if ( tlbSegDir.pTypeInfoTab.res0c != 0x0F || tlbSegDir.pImpInfo.res0c != 0x0F) - { - ERR("cannot find the table directory, ptr=0x%lx\n",lPSegDir); - HeapFree(GetProcessHeap(),0,pTypeLibImpl); - return NULL; - } - - /* now fill our internal data */ - /* TLIBATTR fields */ - MSFT_ReadGuid(&pTypeLibImpl->LibAttr.guid, tlbHeader.posguid, &cx); - - /* pTypeLibImpl->LibAttr.lcid = tlbHeader.lcid;*/ - /* Windows seems to have zero here, is this correct? */ - if(SUBLANGID(tlbHeader.lcid) == SUBLANG_NEUTRAL) - pTypeLibImpl->LibAttr.lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(tlbHeader.lcid),0),0); - else - pTypeLibImpl->LibAttr.lcid = 0; - - pTypeLibImpl->LibAttr.syskind = tlbHeader.varflags & 0x0f; /* check the mask */ - pTypeLibImpl->LibAttr.wMajorVerNum = LOWORD(tlbHeader.version); - pTypeLibImpl->LibAttr.wMinorVerNum = HIWORD(tlbHeader.version); - pTypeLibImpl->LibAttr.wLibFlags = (WORD) tlbHeader.flags & 0xffff;/* check mask */ - - /* name, eventually add to a hash table */ - pTypeLibImpl->Name = MSFT_ReadName(&cx, tlbHeader.NameOffset); - - /* help info */ - pTypeLibImpl->DocString = MSFT_ReadString(&cx, tlbHeader.helpstring); - pTypeLibImpl->HelpFile = MSFT_ReadString(&cx, tlbHeader.helpfile); - - if( tlbHeader.varflags & HELPDLLFLAG) - { - int offset; - MSFT_ReadLEDWords(&offset, sizeof(offset), &cx, sizeof(tlbHeader)); - pTypeLibImpl->HelpStringDll = MSFT_ReadString(&cx, offset); - } - - pTypeLibImpl->dwHelpContext = tlbHeader.helpstringcontext; - - /* custom data */ - if(tlbHeader.CustomDataOffset >= 0) - { - pTypeLibImpl->ctCustData = MSFT_CustData(&cx, tlbHeader.CustomDataOffset, &pTypeLibImpl->pCustData); - } - - /* fill in typedescriptions */ - if(tlbSegDir.pTypdescTab.length > 0) - { - int i, j, cTD = tlbSegDir.pTypdescTab.length / (2*sizeof(INT)); - INT16 td[4]; - pTypeLibImpl->pTypeDesc = TLB_Alloc( cTD * sizeof(TYPEDESC)); - MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pTypdescTab.offset); - for(i=0; i<cTD; ) - { - /* FIXME: add several sanity checks here */ - pTypeLibImpl->pTypeDesc[i].vt = td[0] & VT_TYPEMASK; - if(td[0] == VT_PTR || td[0] == VT_SAFEARRAY) - { - /* FIXME: check safearray */ - if(td[3] < 0) - pTypeLibImpl->pTypeDesc[i].u.lptdesc= & stndTypeDesc[td[2]]; - else - pTypeLibImpl->pTypeDesc[i].u.lptdesc= & pTypeLibImpl->pTypeDesc[td[2]/8]; - } - else if(td[0] == VT_CARRAY) - { - /* array descr table here */ - pTypeLibImpl->pTypeDesc[i].u.lpadesc = (void *)((int) td[2]); /* temp store offset in*/ - } - else if(td[0] == VT_USERDEFINED) - { - pTypeLibImpl->pTypeDesc[i].u.hreftype = MAKELONG(td[2],td[3]); - } - if(++i<cTD) MSFT_ReadLEWords(td, sizeof(td), &cx, DO_NOT_SEEK); - } - - /* second time around to fill the array subscript info */ - for(i=0;i<cTD;i++) - { - if(pTypeLibImpl->pTypeDesc[i].vt != VT_CARRAY) continue; - if(tlbSegDir.pArrayDescriptions.offset>0) - { - MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pArrayDescriptions.offset + (int) pTypeLibImpl->pTypeDesc[i].u.lpadesc); - pTypeLibImpl->pTypeDesc[i].u.lpadesc = TLB_Alloc(sizeof(ARRAYDESC)+sizeof(SAFEARRAYBOUND)*(td[3]-1)); - - if(td[1]<0) - pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem.vt = td[0] & VT_TYPEMASK; - else - pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem = stndTypeDesc[td[0]/8]; - - pTypeLibImpl->pTypeDesc[i].u.lpadesc->cDims = td[2]; - - for(j = 0; j<td[2]; j++) - { - MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].cElements, - sizeof(INT), &cx, DO_NOT_SEEK); - MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].lLbound, - sizeof(INT), &cx, DO_NOT_SEEK); - } - } - else - { - pTypeLibImpl->pTypeDesc[i].u.lpadesc = NULL; - ERR("didn't find array description data\n"); - } - } - } - - /* imported type libs */ - if(tlbSegDir.pImpFiles.offset>0) - { - TLBImpLib **ppImpLib = &(pTypeLibImpl->pImpLibs); - int oGuid, offset = tlbSegDir.pImpFiles.offset; - UINT16 size; - - while(offset < tlbSegDir.pImpFiles.offset +tlbSegDir.pImpFiles.length) - { - char *name; - DWORD len; - - *ppImpLib = TLB_Alloc(sizeof(TLBImpLib)); - (*ppImpLib)->offset = offset - tlbSegDir.pImpFiles.offset; - MSFT_ReadLEDWords(&oGuid, sizeof(INT), &cx, offset); - - MSFT_ReadLEDWords(&(*ppImpLib)->lcid, sizeof(LCID), &cx, DO_NOT_SEEK); - MSFT_ReadLEWords(&(*ppImpLib)->wVersionMajor, sizeof(WORD), &cx, DO_NOT_SEEK); - MSFT_ReadLEWords(&(*ppImpLib)->wVersionMinor, sizeof(WORD), &cx, DO_NOT_SEEK); - MSFT_ReadLEWords(& size, sizeof(UINT16), &cx, DO_NOT_SEEK); - - size >>= 2; - name = TLB_Alloc(size+1); - MSFT_Read(name, size, &cx, DO_NOT_SEEK); - len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 ); - (*ppImpLib)->name = TLB_Alloc(len * sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, name, -1, (*ppImpLib)->name, len ); - TLB_Free(name); - - MSFT_ReadGuid(&(*ppImpLib)->guid, oGuid, &cx); - offset = (offset + sizeof(INT) + sizeof(DWORD) + sizeof(LCID) + sizeof(UINT16) + size + 3) & ~3; - - ppImpLib = &(*ppImpLib)->next; - } - } - - /* type info's */ - if(tlbHeader.nrtypeinfos >= 0 ) - { - /*pTypeLibImpl->TypeInfoCount=tlbHeader.nrtypeinfos; */ - ITypeInfoImpl **ppTI = &(pTypeLibImpl->pTypeInfo); - int i; - - for(i = 0; i<(int)tlbHeader.nrtypeinfos; i++) - { - *ppTI = MSFT_DoTypeInfo(&cx, i, pTypeLibImpl); - - ppTI = &((*ppTI)->next); - (pTypeLibImpl->TypeInfoCount)++; - } - } - - TRACE("(%p)\n", pTypeLibImpl); - return (ITypeLib2*) pTypeLibImpl; -} - - -static BSTR TLB_MultiByteToBSTR(char *ptr) -{ - DWORD len; - WCHAR *nameW; - BSTR ret; - - len = MultiByteToWideChar(CP_ACP, 0, ptr, -1, NULL, 0); - nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, ptr, -1, nameW, len); - ret = SysAllocString(nameW); - HeapFree(GetProcessHeap(), 0, nameW); - return ret; -} - -static BOOL TLB_GUIDFromString(char *str, GUID *guid) -{ - char b[3]; - int i; - short s; - - if(sscanf(str, "%lx-%hx-%hx-%hx", &guid->Data1, &guid->Data2, &guid->Data3, &s) != 4) { - FIXME("Can't parse guid %s\n", debugstr_guid(guid)); - return FALSE; - } - - guid->Data4[0] = s >> 8; - guid->Data4[1] = s & 0xff; - - b[2] = '\0'; - for(i = 0; i < 6; i++) { - memcpy(b, str + 24 + 2 * i, 2); - guid->Data4[i + 2] = strtol(b, NULL, 16); - } - return TRUE; -} - -static WORD SLTG_ReadString(char *ptr, BSTR *pBstr) -{ - WORD bytelen; - DWORD len; - WCHAR *nameW; - - *pBstr = NULL; - bytelen = *(WORD*)ptr; - if(bytelen == 0xffff) return 2; - len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, NULL, 0); - nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); - len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, nameW, len); - *pBstr = SysAllocStringLen(nameW, len); - HeapFree(GetProcessHeap(), 0, nameW); - return bytelen + 2; -} - -static WORD SLTG_ReadStringA(char *ptr, char **str) -{ - WORD bytelen; - - *str = NULL; - bytelen = *(WORD*)ptr; - if(bytelen == 0xffff) return 2; - *str = HeapAlloc(GetProcessHeap(), 0, bytelen + 1); - memcpy(*str, ptr + 2, bytelen); - (*str)[bytelen] = '\0'; - return bytelen + 2; -} - -static DWORD SLTG_ReadLibBlk(LPVOID pLibBlk, ITypeLibImpl *pTypeLibImpl) -{ - char *ptr = pLibBlk; - WORD w; - - if((w = *(WORD*)ptr) != SLTG_LIBBLK_MAGIC) { - FIXME("libblk magic = %04x\n", w); - return 0; - } - - ptr += 6; - if((w = *(WORD*)ptr) != 0xffff) { - FIXME("LibBlk.res06 = %04x. Assumung string and skipping\n", w); - ptr += w; - } - ptr += 2; - - ptr += SLTG_ReadString(ptr, &pTypeLibImpl->DocString); - - ptr += SLTG_ReadString(ptr, &pTypeLibImpl->HelpFile); - - pTypeLibImpl->dwHelpContext = *(DWORD*)ptr; - ptr += 4; - - pTypeLibImpl->LibAttr.syskind = *(WORD*)ptr; - ptr += 2; - - if(SUBLANGID(*(WORD*)ptr) == SUBLANG_NEUTRAL) - pTypeLibImpl->LibAttr.lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(*(WORD*)ptr),0),0); - else - pTypeLibImpl->LibAttr.lcid = 0; - ptr += 2; - - ptr += 4; /* skip res12 */ - - pTypeLibImpl->LibAttr.wLibFlags = *(WORD*)ptr; - ptr += 2; - - pTypeLibImpl->LibAttr.wMajorVerNum = *(WORD*)ptr; - ptr += 2; - - pTypeLibImpl->LibAttr.wMinorVerNum = *(WORD*)ptr; - ptr += 2; - - memcpy(&pTypeLibImpl->LibAttr.guid, ptr, sizeof(GUID)); - ptr += sizeof(GUID); - - return ptr - (char*)pLibBlk; -} - -static WORD *SLTG_DoType(WORD *pType, char *pBlk, ELEMDESC *pElem) -{ - BOOL done = FALSE; - TYPEDESC *pTD = &pElem->tdesc; - - /* Handle [in/out] first */ - if((*pType & 0xc000) == 0xc000) - pElem->u.paramdesc.wParamFlags = PARAMFLAG_NONE; - else if(*pType & 0x8000) - pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN | PARAMFLAG_FOUT; - else if(*pType & 0x4000) - pElem->u.paramdesc.wParamFlags = PARAMFLAG_FOUT; - else - pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN; - - if(*pType & 0x2000) - pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FLCID; - - if(*pType & 0x80) - pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FRETVAL; - - while(!done) { - if((*pType & 0xe00) == 0xe00) { - pTD->vt = VT_PTR; - pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(TYPEDESC)); - pTD = pTD->u.lptdesc; - } - switch(*pType & 0x7f) { - case VT_PTR: - pTD->vt = VT_PTR; - pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(TYPEDESC)); - pTD = pTD->u.lptdesc; - break; - - case VT_USERDEFINED: - pTD->vt = VT_USERDEFINED; - pTD->u.hreftype = *(++pType) / 4; - done = TRUE; - break; - - case VT_CARRAY: - { - /* *(pType+1) is offset to a SAFEARRAY, *(pType+2) is type of - array */ - - SAFEARRAY *pSA = (SAFEARRAY *)(pBlk + *(++pType)); - - pTD->vt = VT_CARRAY; - pTD->u.lpadesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(ARRAYDESC) + - (pSA->cDims - 1) * sizeof(SAFEARRAYBOUND)); - pTD->u.lpadesc->cDims = pSA->cDims; - memcpy(pTD->u.lpadesc->rgbounds, pSA->rgsabound, - pSA->cDims * sizeof(SAFEARRAYBOUND)); - - pTD = &pTD->u.lpadesc->tdescElem; - break; - } - - case VT_SAFEARRAY: - { - /* FIXME: *(pType+1) gives an offset to SAFEARRAY, is this - useful? */ - - pType++; - pTD->vt = VT_SAFEARRAY; - pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(TYPEDESC)); - pTD = pTD->u.lptdesc; - break; - } - default: - pTD->vt = *pType & 0x7f; - done = TRUE; - break; - } - pType++; - } - return pType; -} - - -static void SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeInfoImpl *pTI, - char *pNameTable) -{ - int ref; - char *name; - TLBRefType **ppRefType; - - if(pRef->magic != SLTG_REF_MAGIC) { - FIXME("Ref magic = %x\n", pRef->magic); - return; - } - name = ( (char*)(&pRef->names) + pRef->number); - - ppRefType = &pTI->reflist; - for(ref = 0; ref < pRef->number >> 3; ref++) { - char *refname; - unsigned int lib_offs, type_num; - - *ppRefType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(**ppRefType)); - - name += SLTG_ReadStringA(name, &refname); - if(sscanf(refname, "*\\R%x*#%x", &lib_offs, &type_num) != 2) - FIXME("Can't sscanf ref\n"); - if(lib_offs != 0xffff) { - TLBImpLib **import = &pTI->pTypeLib->pImpLibs; - - while(*import) { - if((*import)->offset == lib_offs) - break; - import = &(*import)->next; - } - if(!*import) { - char fname[MAX_PATH+1]; - int len; - - *import = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(**import)); - (*import)->offset = lib_offs; - TLB_GUIDFromString( pNameTable + lib_offs + 4, - &(*import)->guid); - if(sscanf(pNameTable + lib_offs + 40, "}#%hd.%hd#%lx#%s", - &(*import)->wVersionMajor, - &(*import)->wVersionMinor, - &(*import)->lcid, fname) != 4) { - FIXME("can't sscanf ref %s\n", - pNameTable + lib_offs + 40); - } - len = strlen(fname); - if(fname[len-1] != '#') - FIXME("fname = %s\n", fname); - fname[len-1] = '\0'; - (*import)->name = TLB_MultiByteToBSTR(fname); - } - (*ppRefType)->pImpTLInfo = *import; - } else { /* internal ref */ - (*ppRefType)->pImpTLInfo = TLB_REF_INTERNAL; - } - (*ppRefType)->reference = ref; - (*ppRefType)->index = type_num; - - HeapFree(GetProcessHeap(), 0, refname); - ppRefType = &(*ppRefType)->next; - } - if((BYTE)*name != SLTG_REF_MAGIC) - FIXME("End of ref block magic = %x\n", *name); - dump_TLBRefType(pTI->reflist); -} - -static char *SLTG_DoImpls(char *pBlk, ITypeInfoImpl *pTI, - BOOL OneOnly) -{ - SLTG_ImplInfo *info; - TLBImplType **ppImplType = &pTI->impltypelist; - /* I don't really get this structure, usually it's 0x16 bytes - long, but iuser.tlb contains some that are 0x18 bytes long. - That's ok because we can use the next ptr to jump to the next - one. But how do we know the length of the last one? The WORD - at offs 0x8 might be the clue. For now I'm just assuming that - the last one is the regular 0x16 bytes. */ - - info = (SLTG_ImplInfo*)pBlk; - while(1) { - *ppImplType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(**ppImplType)); - (*ppImplType)->hRef = info->ref; - (*ppImplType)->implflags = info->impltypeflags; - pTI->TypeAttr.cImplTypes++; - ppImplType = &(*ppImplType)->next; - - if(info->next == 0xffff) - break; - if(OneOnly) - FIXME("Interface inheriting more than one interface\n"); - info = (SLTG_ImplInfo*)(pBlk + info->next); - } - info++; /* see comment at top of function */ - return (char*)info; -} - -static SLTG_TypeInfoTail *SLTG_ProcessCoClass(char *pBlk, ITypeInfoImpl *pTI, - char *pNameTable) -{ - SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk; - SLTG_MemberHeader *pMemHeader; - char *pFirstItem, *pNextItem; - - if(pTIHeader->href_table != 0xffffffff) { - SLTG_DoRefs((SLTG_RefInfo*)(pBlk + pTIHeader->href_table), pTI, - pNameTable); - } - - - pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table); - - pFirstItem = pNextItem = (char*)(pMemHeader + 1); - - if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) { - pNextItem = SLTG_DoImpls(pFirstItem, pTI, FALSE); - } - - return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra); -} - - -static SLTG_TypeInfoTail *SLTG_ProcessInterface(char *pBlk, ITypeInfoImpl *pTI, - char *pNameTable) -{ - SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk; - SLTG_MemberHeader *pMemHeader; - SLTG_Function *pFunc; - char *pFirstItem, *pNextItem; - TLBFuncDesc **ppFuncDesc = &pTI->funclist; - int num = 0; - - if(pTIHeader->href_table != 0xffffffff) { - SLTG_DoRefs((SLTG_RefInfo*)(pBlk + pTIHeader->href_table), pTI, - pNameTable); - } - - pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table); - - pFirstItem = pNextItem = (char*)(pMemHeader + 1); - - if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) { - pNextItem = SLTG_DoImpls(pFirstItem, pTI, TRUE); - } - - for(pFunc = (SLTG_Function*)pNextItem, num = 1; 1; - pFunc = (SLTG_Function*)(pFirstItem + pFunc->next), num++) { - - int param; - WORD *pType, *pArg; - - if(pFunc->magic != SLTG_FUNCTION_MAGIC && - pFunc->magic != SLTG_FUNCTION_WITH_FLAGS_MAGIC) { - FIXME("func magic = %02x\n", pFunc->magic); - return NULL; - } - *ppFuncDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(**ppFuncDesc)); - (*ppFuncDesc)->Name = TLB_MultiByteToBSTR(pFunc->name + pNameTable); - - (*ppFuncDesc)->funcdesc.memid = pFunc->dispid; - (*ppFuncDesc)->funcdesc.invkind = pFunc->inv >> 4; - (*ppFuncDesc)->funcdesc.callconv = pFunc->nacc & 0x7; - (*ppFuncDesc)->funcdesc.cParams = pFunc->nacc >> 3; - (*ppFuncDesc)->funcdesc.cParamsOpt = (pFunc->retnextopt & 0x7e) >> 1; - (*ppFuncDesc)->funcdesc.oVft = pFunc->vtblpos; - - if(pFunc->magic == SLTG_FUNCTION_WITH_FLAGS_MAGIC) - (*ppFuncDesc)->funcdesc.wFuncFlags = pFunc->funcflags; - - if(pFunc->retnextopt & 0x80) - pType = &pFunc->rettype; - else - pType = (WORD*)(pFirstItem + pFunc->rettype); - - - SLTG_DoType(pType, pFirstItem, &(*ppFuncDesc)->funcdesc.elemdescFunc); - - (*ppFuncDesc)->funcdesc.lprgelemdescParam = - HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - (*ppFuncDesc)->funcdesc.cParams * sizeof(ELEMDESC)); - (*ppFuncDesc)->pParamDesc = - HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - (*ppFuncDesc)->funcdesc.cParams * sizeof(TLBParDesc)); - - pArg = (WORD*)(pFirstItem + pFunc->arg_off); - - for(param = 0; param < (*ppFuncDesc)->funcdesc.cParams; param++) { - char *paramName = pNameTable + *pArg; - BOOL HaveOffs; - /* If arg type follows then paramName points to the 2nd - letter of the name, else the next WORD is an offset to - the arg type and paramName points to the first letter. - So let's take one char off paramName and see if we're - pointing at an alpha-numeric char. However if *pArg is - 0xffff or 0xfffe then the param has no name, the former - meaning that the next WORD is the type, the latter - meaning the the next WORD is an offset to the type. */ - - HaveOffs = FALSE; - if(*pArg == 0xffff) - paramName = NULL; - else if(*pArg == 0xfffe) { - paramName = NULL; - HaveOffs = TRUE; - } - else if(!isalnum(*(paramName-1))) - HaveOffs = TRUE; - - pArg++; - - if(HaveOffs) { /* the next word is an offset to type */ - pType = (WORD*)(pFirstItem + *pArg); - SLTG_DoType(pType, pFirstItem, - &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param]); - pArg++; - } else { - if(paramName) - paramName--; - pArg = SLTG_DoType(pArg, pFirstItem, - &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param]); - } - - /* Are we an optional param ? */ - if((*ppFuncDesc)->funcdesc.cParams - param <= - (*ppFuncDesc)->funcdesc.cParamsOpt) - (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].u.paramdesc.wParamFlags |= PARAMFLAG_FOPT; - - if(paramName) { - (*ppFuncDesc)->pParamDesc[param].Name = - TLB_MultiByteToBSTR(paramName); - } - } - - ppFuncDesc = &((*ppFuncDesc)->next); - if(pFunc->next == 0xffff) break; - } - pTI->TypeAttr.cFuncs = num; - dump_TLBFuncDesc(pTI->funclist); - return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra); -} - -static SLTG_TypeInfoTail *SLTG_ProcessRecord(char *pBlk, ITypeInfoImpl *pTI, - char *pNameTable) -{ - SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk; - SLTG_MemberHeader *pMemHeader; - SLTG_RecordItem *pItem; - char *pFirstItem; - TLBVarDesc **ppVarDesc = &pTI->varlist; - int num = 0; - WORD *pType; - char buf[300]; - - pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table); - - pFirstItem = (char*)(pMemHeader + 1); - for(pItem = (SLTG_RecordItem *)pFirstItem, num = 1; 1; - pItem = (SLTG_RecordItem *)(pFirstItem + pItem->next), num++) { - if(pItem->magic != SLTG_RECORD_MAGIC) { - FIXME("record magic = %02x\n", pItem->magic); - return NULL; - } - *ppVarDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(**ppVarDesc)); - (*ppVarDesc)->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable); - (*ppVarDesc)->vardesc.memid = pItem->memid; - (*ppVarDesc)->vardesc.u.oInst = pItem->byte_offs; - (*ppVarDesc)->vardesc.varkind = VAR_PERINSTANCE; - - if(pItem->typepos == 0x02) - pType = &pItem->type; - else if(pItem->typepos == 0x00) - pType = (WORD*)(pFirstItem + pItem->type); - else { - FIXME("typepos = %02x\n", pItem->typepos); - break; - } - - SLTG_DoType(pType, pFirstItem, - &(*ppVarDesc)->vardesc.elemdescVar); - - /* FIXME("helpcontext, helpstring\n"); */ - - dump_TypeDesc(&(*ppVarDesc)->vardesc.elemdescVar.tdesc, buf); - - ppVarDesc = &((*ppVarDesc)->next); - if(pItem->next == 0xffff) break; - } - pTI->TypeAttr.cVars = num; - return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra); -} - -static SLTG_TypeInfoTail *SLTG_ProcessAlias(char *pBlk, ITypeInfoImpl *pTI, - char *pNameTable) -{ - SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk; - SLTG_MemberHeader *pMemHeader; - SLTG_AliasItem *pItem; - int i, mustbelast; - - pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table); - pItem = (SLTG_AliasItem*)(pMemHeader + 1); - - mustbelast = 0; - /* This is used for creating a TYPEDESC chain in case of VT_USERDEFINED */ - for (i = 0 ; i<pMemHeader->cbExtra/4 ; i++) { - if (pItem->vt == 0xffff) { - if (i<(pMemHeader->cbExtra/4-1)) - FIXME("Endmarker too early in process alias data!\n"); - break; - } - if (mustbelast) { - FIXME("Chain extends over last entry?\n"); - break; - } - if (pItem->vt == VT_USERDEFINED) { - pTI->TypeAttr.tdescAlias.vt = pItem->vt; - /* guessing here ... */ - FIXME("Guessing TKIND_ALIAS of VT_USERDEFINED with hreftype 0x%x\n",pItem->res02); - pTI->TypeAttr.tdescAlias.u.hreftype = pItem->res02; - mustbelast = 1; - } else { - FIXME("alias %d: 0x%x\n",i,pItem->vt); - FIXME("alias %d: 0x%x\n",i,pItem->res02); - } - pItem++; - } - return (SLTG_TypeInfoTail*)((char*)(pMemHeader + 1)+pMemHeader->cbExtra); -} - -static SLTG_TypeInfoTail *SLTG_ProcessDispatch(char *pBlk, ITypeInfoImpl *pTI, - char *pNameTable) -{ - SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk; - SLTG_MemberHeader *pMemHeader; - SLTG_AliasItem *pItem; - - pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table); - pItem = (SLTG_AliasItem*)(pMemHeader + 1); - FIXME("memh.cbExtra is %ld\n",pMemHeader->cbExtra); - FIXME("offset 0 0x%x\n",*(WORD*)pItem); - return (SLTG_TypeInfoTail*)((char*)(pMemHeader + 1)+pMemHeader->cbExtra); -} - -static SLTG_TypeInfoTail *SLTG_ProcessEnum(char *pBlk, ITypeInfoImpl *pTI, - char *pNameTable) -{ - SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk; - SLTG_MemberHeader *pMemHeader; - SLTG_EnumItem *pItem; - char *pFirstItem; - TLBVarDesc **ppVarDesc = &pTI->varlist; - int num = 0; - - pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table); - - pFirstItem = (char*)(pMemHeader + 1); - for(pItem = (SLTG_EnumItem *)pFirstItem, num = 1; 1; - pItem = (SLTG_EnumItem *)(pFirstItem + pItem->next), num++) { - if(pItem->magic != SLTG_ENUMITEM_MAGIC) { - FIXME("enumitem magic = %04x\n", pItem->magic); - return NULL; - } - *ppVarDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(**ppVarDesc)); - (*ppVarDesc)->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable); - (*ppVarDesc)->vardesc.memid = pItem->memid; - (*ppVarDesc)->vardesc.u.lpvarValue = HeapAlloc(GetProcessHeap(), 0, - sizeof(VARIANT)); - V_VT((*ppVarDesc)->vardesc.u.lpvarValue) = VT_INT; - V_UNION((*ppVarDesc)->vardesc.u.lpvarValue, intVal) = - *(INT*)(pItem->value + pFirstItem); - (*ppVarDesc)->vardesc.elemdescVar.tdesc.vt = VT_I4; - (*ppVarDesc)->vardesc.varkind = VAR_CONST; - /* FIXME("helpcontext, helpstring\n"); */ - - ppVarDesc = &((*ppVarDesc)->next); - if(pItem->next == 0xffff) break; - } - pTI->TypeAttr.cVars = num; - return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra); -} - -/* Because SLTG_OtherTypeInfo is such a painful struct, we make a more - managable copy of it into this */ -typedef struct { - WORD small_no; - char *index_name; - char *other_name; - WORD res1a; - WORD name_offs; - WORD more_bytes; - char *extra; - WORD res20; - DWORD helpcontext; - WORD res26; - GUID uuid; -} SLTG_InternalOtherTypeInfo; - -/**************************************************************************** - * ITypeLib2_Constructor_SLTG - * - * loading a SLTG typelib from an in-memory image - */ -static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength) -{ - ITypeLibImpl *pTypeLibImpl; - SLTG_Header *pHeader; - SLTG_BlkEntry *pBlkEntry; - SLTG_Magic *pMagic; - SLTG_Index *pIndex; - SLTG_Pad9 *pPad9; - LPVOID pBlk, pFirstBlk; - SLTG_LibBlk *pLibBlk; - SLTG_InternalOtherTypeInfo *pOtherTypeInfoBlks; - char *pAfterOTIBlks = NULL; - char *pNameTable, *ptr; - int i; - DWORD len, order; - ITypeInfoImpl **ppTypeInfoImpl; - - TRACE("%p, TLB length = %ld\n", pLib, dwTLBLength); - - pTypeLibImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeLibImpl)); - if (!pTypeLibImpl) return NULL; - - pTypeLibImpl->lpVtbl = &tlbvt; - pTypeLibImpl->ref = 1; - - pHeader = pLib; - - TRACE("header:\n"); - TRACE("\tmagic=0x%08lx, file blocks = %d\n", pHeader->SLTG_magic, - pHeader->nrOfFileBlks ); - if (pHeader->SLTG_magic != SLTG_SIGNATURE) { - FIXME("Header type magic 0x%08lx not supported.\n", - pHeader->SLTG_magic); - return NULL; - } - - /* There are pHeader->nrOfFileBlks - 2 TypeInfo records in this typelib */ - pTypeLibImpl->TypeInfoCount = pHeader->nrOfFileBlks - 2; - - /* This points to pHeader->nrOfFileBlks - 1 of SLTG_BlkEntry */ - pBlkEntry = (SLTG_BlkEntry*)(pHeader + 1); - - /* Next we have a magic block */ - pMagic = (SLTG_Magic*)(pBlkEntry + pHeader->nrOfFileBlks - 1); - - /* Let's see if we're still in sync */ - if(memcmp(pMagic->CompObj_magic, SLTG_COMPOBJ_MAGIC, - sizeof(SLTG_COMPOBJ_MAGIC))) { - FIXME("CompObj magic = %s\n", pMagic->CompObj_magic); - return NULL; - } - if(memcmp(pMagic->dir_magic, SLTG_DIR_MAGIC, - sizeof(SLTG_DIR_MAGIC))) { - FIXME("dir magic = %s\n", pMagic->dir_magic); - return NULL; - } - - pIndex = (SLTG_Index*)(pMagic+1); - - pPad9 = (SLTG_Pad9*)(pIndex + pTypeLibImpl->TypeInfoCount); - - pFirstBlk = (LPVOID)(pPad9 + 1); - - /* We'll set up a ptr to the main library block, which is the last one. */ - - for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0; - pBlkEntry[order].next != 0; - order = pBlkEntry[order].next - 1, i++) { - pBlk = (char*)pBlk + pBlkEntry[order].len; - } - pLibBlk = pBlk; - - len = SLTG_ReadLibBlk(pLibBlk, pTypeLibImpl); - - /* Now there's 0x40 bytes of 0xffff with the numbers 0 to TypeInfoCount - interspersed */ - - len += 0x40; - - /* And now TypeInfoCount of SLTG_OtherTypeInfo */ - - pOtherTypeInfoBlks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(*pOtherTypeInfoBlks) * - pTypeLibImpl->TypeInfoCount); - - - ptr = (char*)pLibBlk + len; - - for(i = 0; i < pTypeLibImpl->TypeInfoCount; i++) { - WORD w, extra; - len = 0; - - pOtherTypeInfoBlks[i].small_no = *(WORD*)ptr; - - w = *(WORD*)(ptr + 2); - if(w != 0xffff) { - len += w; - pOtherTypeInfoBlks[i].index_name = HeapAlloc(GetProcessHeap(),0, - w+1); - memcpy(pOtherTypeInfoBlks[i].index_name, ptr + 4, w); - pOtherTypeInfoBlks[i].index_name[w] = '\0'; - } - w = *(WORD*)(ptr + 4 + len); - if(w != 0xffff) { - TRACE("\twith %s\n", debugstr_an(ptr + 6 + len, w)); - len += w; - pOtherTypeInfoBlks[i].other_name = HeapAlloc(GetProcessHeap(),0, - w+1); - memcpy(pOtherTypeInfoBlks[i].other_name, ptr + 6 + len, w); - pOtherTypeInfoBlks[i].other_name[w] = '\0'; - } - pOtherTypeInfoBlks[i].res1a = *(WORD*)(ptr + len + 6); - pOtherTypeInfoBlks[i].name_offs = *(WORD*)(ptr + len + 8); - extra = pOtherTypeInfoBlks[i].more_bytes = *(WORD*)(ptr + 10 + len); - if(extra) { - pOtherTypeInfoBlks[i].extra = HeapAlloc(GetProcessHeap(),0, - extra); - memcpy(pOtherTypeInfoBlks[i].extra, ptr + 12, extra); - len += extra; - } - pOtherTypeInfoBlks[i].res20 = *(WORD*)(ptr + 12 + len); - pOtherTypeInfoBlks[i].helpcontext = *(DWORD*)(ptr + 14 + len); - pOtherTypeInfoBlks[i].res26 = *(WORD*)(ptr + 18 + len); - memcpy(&pOtherTypeInfoBlks[i].uuid, ptr + 20 + len, sizeof(GUID)); - len += sizeof(SLTG_OtherTypeInfo); - ptr += len; - } - - pAfterOTIBlks = ptr; - - /* Skip this WORD and get the next DWORD */ - len = *(DWORD*)(pAfterOTIBlks + 2); - - /* Now add this to pLibBLk look at what we're pointing at and - possibly add 0x20, then add 0x216, sprinkle a bit a magic - dust and we should be pointing at the beginning of the name - table */ - - pNameTable = (char*)pLibBlk + len; - - switch(*(WORD*)pNameTable) { - case 0xffff: - break; - case 0x0200: - pNameTable += 0x20; - break; - default: - FIXME("pNameTable jump = %x\n", *(WORD*)pNameTable); - break; - } - - pNameTable += 0x216; - - pNameTable += 2; - - TRACE("Library name is %s\n", pNameTable + pLibBlk->name); - - pTypeLibImpl->Name = TLB_MultiByteToBSTR(pNameTable + pLibBlk->name); - - - /* Hopefully we now have enough ptrs set up to actually read in - some TypeInfos. It's not clear which order to do them in, so - I'll just follow the links along the BlkEntry chain and read - them in in the order in which they're in the file */ - - ppTypeInfoImpl = &(pTypeLibImpl->pTypeInfo); - - for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0; - pBlkEntry[order].next != 0; - order = pBlkEntry[order].next - 1, i++) { - - SLTG_TypeInfoHeader *pTIHeader; - SLTG_TypeInfoTail *pTITail; - - if(strcmp(pBlkEntry[order].index_string + (char*)pMagic, - pOtherTypeInfoBlks[i].index_name)) { - FIXME("Index strings don't match\n"); - return NULL; - } - - pTIHeader = pBlk; - if(pTIHeader->magic != SLTG_TIHEADER_MAGIC) { - FIXME("TypeInfoHeader magic = %04x\n", pTIHeader->magic); - return NULL; - } - *ppTypeInfoImpl = (ITypeInfoImpl*)ITypeInfo_Constructor(); - (*ppTypeInfoImpl)->pTypeLib = pTypeLibImpl; - (*ppTypeInfoImpl)->index = i; - (*ppTypeInfoImpl)->Name = TLB_MultiByteToBSTR( - pOtherTypeInfoBlks[i].name_offs + - pNameTable); - (*ppTypeInfoImpl)->dwHelpContext = pOtherTypeInfoBlks[i].helpcontext; - memcpy(&((*ppTypeInfoImpl)->TypeAttr.guid), &pOtherTypeInfoBlks[i].uuid, - sizeof(GUID)); - (*ppTypeInfoImpl)->TypeAttr.typekind = pTIHeader->typekind; - (*ppTypeInfoImpl)->TypeAttr.wMajorVerNum = pTIHeader->major_version; - (*ppTypeInfoImpl)->TypeAttr.wMinorVerNum = pTIHeader->minor_version; - (*ppTypeInfoImpl)->TypeAttr.wTypeFlags = - (pTIHeader->typeflags1 >> 3) | (pTIHeader->typeflags2 << 5); - - if((pTIHeader->typeflags1 & 7) != 2) - FIXME("typeflags1 = %02x\n", pTIHeader->typeflags1); - if(pTIHeader->typeflags3 != 2) - FIXME("typeflags3 = %02x\n", pTIHeader->typeflags3); - - TRACE("TypeInfo %s of kind %s guid %s typeflags %04x\n", - debugstr_w((*ppTypeInfoImpl)->Name), - typekind_desc[pTIHeader->typekind], - debugstr_guid(&(*ppTypeInfoImpl)->TypeAttr.guid), - (*ppTypeInfoImpl)->TypeAttr.wTypeFlags); - - switch(pTIHeader->typekind) { - case TKIND_ENUM: - pTITail = SLTG_ProcessEnum(pBlk, *ppTypeInfoImpl, pNameTable); - break; - - case TKIND_RECORD: - pTITail = SLTG_ProcessRecord(pBlk, *ppTypeInfoImpl, pNameTable); - break; - - case TKIND_INTERFACE: - pTITail = SLTG_ProcessInterface(pBlk, *ppTypeInfoImpl, pNameTable); - break; - - case TKIND_COCLASS: - pTITail = SLTG_ProcessCoClass(pBlk, *ppTypeInfoImpl, pNameTable); - break; - - case TKIND_ALIAS: - pTITail = SLTG_ProcessAlias(pBlk, *ppTypeInfoImpl, pNameTable); - if (pTITail->tdescalias_vt) - (*ppTypeInfoImpl)->TypeAttr.tdescAlias.vt = pTITail->tdescalias_vt; - break; - - case TKIND_DISPATCH: - pTITail = SLTG_ProcessDispatch(pBlk, *ppTypeInfoImpl, pNameTable); - break; - - default: - FIXME("Not processing typekind %d\n", pTIHeader->typekind); - pTITail = NULL; - break; - - } - - if(pTITail) { /* could get cFuncs, cVars and cImplTypes from here - but we've already set those */ - (*ppTypeInfoImpl)->TypeAttr.cbAlignment = pTITail->cbAlignment; - (*ppTypeInfoImpl)->TypeAttr.cbSizeInstance = pTITail->cbSizeInstance; - (*ppTypeInfoImpl)->TypeAttr.cbSizeVft = pTITail->cbSizeVft; - -#define X(x) TRACE("tt "#x": %x\n",pTITail->res##x); - X(06); - X(08); - X(0a); - X(0c); - X(0e); - X(10); - X(12); - X(16); - X(18); - X(1a); - X(1c); - X(1e); - X(24); - X(26); - X(2a); - X(2c); - X(2e); - X(30); - X(32); - X(34); - } - ppTypeInfoImpl = &((*ppTypeInfoImpl)->next); - pBlk = (char*)pBlk + pBlkEntry[order].len; - } - - if(i != pTypeLibImpl->TypeInfoCount) { - FIXME("Somehow processed %d TypeInfos\n", i); - return NULL; - } - - HeapFree(GetProcessHeap(), 0, pOtherTypeInfoBlks); - return (ITypeLib2*)pTypeLibImpl; -} - -/* ITypeLib::QueryInterface - */ -static HRESULT WINAPI ITypeLib2_fnQueryInterface( - ITypeLib2 * iface, - REFIID riid, - VOID **ppvObject) -{ - ITypeLibImpl *This = (ITypeLibImpl *)iface; - - TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid)); - - *ppvObject=NULL; - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid,&IID_ITypeLib)|| - IsEqualIID(riid,&IID_ITypeLib2)) - { - *ppvObject = This; - } - - if(*ppvObject) - { - ITypeLib2_AddRef(iface); - TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject); - return S_OK; - } - TRACE("-- Interface: E_NOINTERFACE\n"); - return E_NOINTERFACE; -} - -/* ITypeLib::AddRef - */ -static ULONG WINAPI ITypeLib2_fnAddRef( ITypeLib2 *iface) -{ - ITypeLibImpl *This = (ITypeLibImpl *)iface; - ULONG ref = InterlockedIncrement(&This->ref); - - TRACE("(%p)->ref was %lu\n",This, ref - 1); - - return ref; -} - -/* ITypeLib::Release - */ -static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface) -{ - ITypeLibImpl *This = (ITypeLibImpl *)iface; - ULONG ref = InterlockedDecrement(&This->ref); - - TRACE("(%p)->(%lu)\n",This, ref); - - if (!ref) - { - /* remove cache entry */ - TRACE("removing from cache list\n"); - EnterCriticalSection(&cache_section); - if (This->next) This->next->prev = This->prev; - if (This->prev) This->prev->next = This->next; - else tlb_cache_first = This->next; - LeaveCriticalSection(&cache_section); - - /* FIXME destroy child objects */ - TRACE(" destroying ITypeLib(%p)\n",This); - - if (This->Name) - { - SysFreeString(This->Name); - This->Name = NULL; - } - - if (This->DocString) - { - SysFreeString(This->DocString); - This->DocString = NULL; - } - - if (This->HelpFile) - { - SysFreeString(This->HelpFile); - This->HelpFile = NULL; - } - - if (This->HelpStringDll) - { - SysFreeString(This->HelpStringDll); - This->HelpStringDll = NULL; - } - - if (This->pTypeInfo) /* can be NULL */ - ITypeInfo_Release((ITypeInfo*) This->pTypeInfo); - HeapFree(GetProcessHeap(),0,This); - return 0; - } - - return ref; -} - -/* ITypeLib::GetTypeInfoCount - * - * Returns the number of type descriptions in the type library - */ -static UINT WINAPI ITypeLib2_fnGetTypeInfoCount( ITypeLib2 *iface) -{ - ITypeLibImpl *This = (ITypeLibImpl *)iface; - TRACE("(%p)->count is %d\n",This, This->TypeInfoCount); - return This->TypeInfoCount; -} - -/* ITypeLib::GetTypeInfo - * - * retrieves the specified type description in the library. - */ -static HRESULT WINAPI ITypeLib2_fnGetTypeInfo( - ITypeLib2 *iface, - UINT index, - ITypeInfo **ppTInfo) -{ - int i; - - ITypeLibImpl *This = (ITypeLibImpl *)iface; - ITypeInfoImpl *pTypeInfo = This->pTypeInfo; - - TRACE("(%p)->(index=%d) \n", This, index); - - if (!ppTInfo) return E_INVALIDARG; - - /* search element n in list */ - for(i=0; i < index; i++) - { - pTypeInfo = pTypeInfo->next; - if (!pTypeInfo) - { - TRACE("-- element not found\n"); - return TYPE_E_ELEMENTNOTFOUND; - } - } - - *ppTInfo = (ITypeInfo *) pTypeInfo; - - ITypeInfo_AddRef(*ppTInfo); - TRACE("-- found (%p)\n",*ppTInfo); - return S_OK; -} - - -/* ITypeLibs::GetTypeInfoType - * - * Retrieves the type of a type description. - */ -static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType( - ITypeLib2 *iface, - UINT index, - TYPEKIND *pTKind) -{ - ITypeLibImpl *This = (ITypeLibImpl *)iface; - int i; - ITypeInfoImpl *pTInfo = This->pTypeInfo; - - TRACE("(%p) index %d \n",This, index); - - if(!pTKind) return E_INVALIDARG; - - /* search element n in list */ - for(i=0; i < index; i++) - { - if(!pTInfo) - { - TRACE("-- element not found\n"); - return TYPE_E_ELEMENTNOTFOUND; - } - pTInfo = pTInfo->next; - } - - *pTKind = pTInfo->TypeAttr.typekind; - TRACE("-- found Type (%d)\n", *pTKind); - return S_OK; -} - -/* ITypeLib::GetTypeInfoOfGuid - * - * Retrieves the type description that corresponds to the specified GUID. - * - */ -static HRESULT WINAPI ITypeLib2_fnGetTypeInfoOfGuid( - ITypeLib2 *iface, - REFGUID guid, - ITypeInfo **ppTInfo) -{ - ITypeLibImpl *This = (ITypeLibImpl *)iface; - ITypeInfoImpl *pTypeInfo = This->pTypeInfo; /* head of list */ - - TRACE("(%p)\n\tguid:\t%s)\n",This,debugstr_guid(guid)); - - if (!pTypeInfo) return TYPE_E_ELEMENTNOTFOUND; - - /* search linked list for guid */ - while( !IsEqualIID(guid,&pTypeInfo->TypeAttr.guid) ) - { - pTypeInfo = pTypeInfo->next; - - if (!pTypeInfo) - { - /* end of list reached */ - TRACE("-- element not found\n"); - return TYPE_E_ELEMENTNOTFOUND; - } - } - - TRACE("-- found (%p, %s)\n", - pTypeInfo, - debugstr_w(pTypeInfo->Name)); - - *ppTInfo = (ITypeInfo*)pTypeInfo; - ITypeInfo_AddRef(*ppTInfo); - return S_OK; -} - -/* ITypeLib::GetLibAttr - * - * Retrieves the structure that contains the library's attributes. - * - */ -static HRESULT WINAPI ITypeLib2_fnGetLibAttr( - ITypeLib2 *iface, - LPTLIBATTR *ppTLibAttr) -{ - ITypeLibImpl *This = (ITypeLibImpl *)iface; - TRACE("(%p)\n",This); - *ppTLibAttr = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppTLibAttr)); - memcpy(*ppTLibAttr, &This->LibAttr, sizeof(**ppTLibAttr)); - return S_OK; -} - -/* ITypeLib::GetTypeComp - * - * Enables a client compiler to bind to a library's types, variables, - * constants, and global functions. - * - */ -static HRESULT WINAPI ITypeLib2_fnGetTypeComp( - ITypeLib2 *iface, - ITypeComp **ppTComp) -{ - ITypeLibImpl *This = (ITypeLibImpl *)iface; - - TRACE("(%p)->(%p)\n",This,ppTComp); - *ppTComp = (ITypeComp *)&This->lpVtblTypeComp; - ITypeComp_AddRef(*ppTComp); - - return S_OK; -} - -/* ITypeLib::GetDocumentation - * - * Retrieves the library's documentation string, the complete Help file name - * and path, and the context identifier for the library Help topic in the Help - * file. - * - * On a successful return all non-null BSTR pointers will have been set, - * possibly to NULL. - */ -static HRESULT WINAPI ITypeLib2_fnGetDocumentation( - ITypeLib2 *iface, - INT index, - BSTR *pBstrName, - BSTR *pBstrDocString, - DWORD *pdwHelpContext, - BSTR *pBstrHelpFile) -{ - ITypeLibImpl *This = (ITypeLibImpl *)iface; - - HRESULT result = E_INVALIDARG; - - ITypeInfo *pTInfo; - - - TRACE("(%p) index %d Name(%p) DocString(%p) HelpContext(%p) HelpFile(%p)\n", - This, index, - pBstrName, pBstrDocString, - pdwHelpContext, pBstrHelpFile); - - if(index<0) - { - /* documentation for the typelib */ - if(pBstrName) - { - if (This->Name) - if(!(*pBstrName = SysAllocString(This->Name))) goto memerr1;else; - else - *pBstrName = NULL; - } - if(pBstrDocString) - { - if (This->DocString) - if(!(*pBstrDocString = SysAllocString(This->DocString))) goto memerr2;else; - else if (This->Name) - if(!(*pBstrDocString = SysAllocString(This->Name))) goto memerr2;else; - else - *pBstrDocString = NULL; - } - if(pdwHelpContext) - { - *pdwHelpContext = This->dwHelpContext; - } - if(pBstrHelpFile) - { - if (This->HelpFile) - if(!(*pBstrHelpFile = SysAllocString(This->HelpFile))) goto memerr3;else; - else - *pBstrHelpFile = NULL; - } - - result = S_OK; - } - else - { - /* for a typeinfo */ - result = ITypeLib2_fnGetTypeInfo(iface, index, &pTInfo); - - if(SUCCEEDED(result)) - { - result = ITypeInfo_GetDocumentation(pTInfo, - MEMBERID_NIL, - pBstrName, - pBstrDocString, - pdwHelpContext, pBstrHelpFile); - - ITypeInfo_Release(pTInfo); - } - } - return result; -memerr3: - if (pBstrDocString) SysFreeString (*pBstrDocString); -memerr2: - if (pBstrName) SysFreeString (*pBstrName); -memerr1: - return STG_E_INSUFFICIENTMEMORY; -} - -/* ITypeLib::IsName - * - * Indicates whether a passed-in string contains the name of a type or member - * described in the library. - * - */ -static HRESULT WINAPI ITypeLib2_fnIsName( - ITypeLib2 *iface, - LPOLESTR szNameBuf, - ULONG lHashVal, - BOOL *pfName) -{ - ITypeLibImpl *This = (ITypeLibImpl *)iface; - ITypeInfoImpl *pTInfo; - TLBFuncDesc *pFInfo; - TLBVarDesc *pVInfo; - int i; - UINT nNameBufLen = SysStringLen(szNameBuf); - - TRACE("(%p)->(%s,%08lx,%p)\n", This, debugstr_w(szNameBuf), lHashVal, - pfName); - - *pfName=TRUE; - for(pTInfo=This->pTypeInfo;pTInfo;pTInfo=pTInfo->next){ - if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit; - for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) { - if(!memcmp(szNameBuf,pFInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit; - for(i=0;i<pFInfo->funcdesc.cParams;i++) - if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name, nNameBufLen)) - goto ITypeLib2_fnIsName_exit; - } - for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next) - if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit; - - } - *pfName=FALSE; - -ITypeLib2_fnIsName_exit: - TRACE("(%p)slow! search for %s: %s found!\n", This, - debugstr_w(szNameBuf), *pfName?"NOT":""); - - return S_OK; -} - -/* ITypeLib::FindName - * - * Finds occurrences of a type description in a type library. This may be used - * to quickly verify that a name exists in a type library. - * - */ -static HRESULT WINAPI ITypeLib2_fnFindName( - ITypeLib2 *iface, - LPOLESTR szNameBuf, - ULONG lHashVal, - ITypeInfo **ppTInfo, - MEMBERID *rgMemId, - UINT16 *pcFound) -{ - ITypeLibImpl *This = (ITypeLibImpl *)iface; - ITypeInfoImpl *pTInfo; - TLBFuncDesc *pFInfo; - TLBVarDesc *pVInfo; - int i,j = 0; - - UINT nNameBufLen = SysStringLen(szNameBuf); - - for(pTInfo=This->pTypeInfo;pTInfo && j<*pcFound; pTInfo=pTInfo->next){ - if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit; - for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) { - if(!memcmp(szNameBuf,pFInfo->Name,nNameBufLen)) goto ITypeLib2_fnFindName_exit; - for(i=0;i<pFInfo->funcdesc.cParams;i++) - if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name,nNameBufLen)) - goto ITypeLib2_fnFindName_exit; - } - for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next) - if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit; - continue; -ITypeLib2_fnFindName_exit: - ITypeInfo_AddRef((ITypeInfo*)pTInfo); - ppTInfo[j]=(LPTYPEINFO)pTInfo; - j++; - } - TRACE("(%p)slow! search for %d with %s: found %d TypeInfo's!\n", - This, *pcFound, debugstr_w(szNameBuf), j); - - *pcFound=j; - - return S_OK; -} - -/* ITypeLib::ReleaseTLibAttr - * - * Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr. - * - */ -static VOID WINAPI ITypeLib2_fnReleaseTLibAttr( - ITypeLib2 *iface, - TLIBATTR *pTLibAttr) -{ - ITypeLibImpl *This = (ITypeLibImpl *)iface; - TRACE("freeing (%p)\n",This); - HeapFree(GetProcessHeap(),0,pTLibAttr); - -} - -/* ITypeLib2::GetCustData - * - * gets the custom data - */ -static HRESULT WINAPI ITypeLib2_fnGetCustData( - ITypeLib2 * iface, - REFGUID guid, - VARIANT *pVarVal) -{ - ITypeLibImpl *This = (ITypeLibImpl *)iface; - TLBCustData *pCData; - - for(pCData=This->pCustData; pCData; pCData = pCData->next) - { - if( IsEqualIID(guid, &pCData->guid)) break; - } - - TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT"); - - if(pCData) - { - VariantInit( pVarVal); - VariantCopy( pVarVal, &pCData->data); - return S_OK; - } - return E_INVALIDARG; /* FIXME: correct? */ -} - -/* ITypeLib2::GetLibStatistics - * - * Returns statistics about a type library that are required for efficient - * sizing of hash tables. - * - */ -static HRESULT WINAPI ITypeLib2_fnGetLibStatistics( - ITypeLib2 * iface, - ULONG *pcUniqueNames, - ULONG *pcchUniqueNames) -{ - ITypeLibImpl *This = (ITypeLibImpl *)iface; - - FIXME("(%p): stub!\n", This); - - if(pcUniqueNames) *pcUniqueNames=1; - if(pcchUniqueNames) *pcchUniqueNames=1; - return S_OK; -} - -/* ITypeLib2::GetDocumentation2 - * - * Retrieves the library's documentation string, the complete Help file name - * and path, the localization context to use, and the context ID for the - * library Help topic in the Help file. - * - */ -static HRESULT WINAPI ITypeLib2_fnGetDocumentation2( - ITypeLib2 * iface, - INT index, - LCID lcid, - BSTR *pbstrHelpString, - DWORD *pdwHelpStringContext, - BSTR *pbstrHelpStringDll) -{ - ITypeLibImpl *This = (ITypeLibImpl *)iface; - HRESULT result; - ITypeInfo *pTInfo; - - FIXME("(%p) index %d lcid %ld half implemented stub!\n", This, index, lcid); - - /* the help string should be obtained from the helpstringdll, - * using the _DLLGetDocumentation function, based on the supplied - * lcid. Nice to do sometime... - */ - if(index<0) - { - /* documentation for the typelib */ - if(pbstrHelpString) - *pbstrHelpString=SysAllocString(This->DocString); - if(pdwHelpStringContext) - *pdwHelpStringContext=This->dwHelpContext; - if(pbstrHelpStringDll) - *pbstrHelpStringDll=SysAllocString(This->HelpStringDll); - - result = S_OK; - } - else - { - /* for a typeinfo */ - result=ITypeLib2_GetTypeInfo(iface, index, &pTInfo); - - if(SUCCEEDED(result)) - { - ITypeInfo2 * pTInfo2; - result = ITypeInfo_QueryInterface(pTInfo, - &IID_ITypeInfo2, - (LPVOID*) &pTInfo2); - - if(SUCCEEDED(result)) - { - result = ITypeInfo2_GetDocumentation2(pTInfo2, - MEMBERID_NIL, - lcid, - pbstrHelpString, - pdwHelpStringContext, - pbstrHelpStringDll); - - ITypeInfo2_Release(pTInfo2); - } - - ITypeInfo_Release(pTInfo); - } - } - return result; -} - -/* ITypeLib2::GetAllCustData - * - * Gets all custom data items for the library. - * - */ -static HRESULT WINAPI ITypeLib2_fnGetAllCustData( - ITypeLib2 * iface, - CUSTDATA *pCustData) -{ - ITypeLibImpl *This = (ITypeLibImpl *)iface; - TLBCustData *pCData; - int i; - TRACE("(%p) returning %d items\n", This, This->ctCustData); - pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM)); - if(pCustData->prgCustData ){ - pCustData->cCustData=This->ctCustData; - for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){ - pCustData->prgCustData[i].guid=pCData->guid; - VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data); - } - }else{ - ERR(" OUT OF MEMORY! \n"); - return E_OUTOFMEMORY; - } - return S_OK; -} - -static ITypeLib2Vtbl tlbvt = { - ITypeLib2_fnQueryInterface, - ITypeLib2_fnAddRef, - ITypeLib2_fnRelease, - ITypeLib2_fnGetTypeInfoCount, - ITypeLib2_fnGetTypeInfo, - ITypeLib2_fnGetTypeInfoType, - ITypeLib2_fnGetTypeInfoOfGuid, - ITypeLib2_fnGetLibAttr, - ITypeLib2_fnGetTypeComp, - ITypeLib2_fnGetDocumentation, - ITypeLib2_fnIsName, - ITypeLib2_fnFindName, - ITypeLib2_fnReleaseTLibAttr, - - ITypeLib2_fnGetCustData, - ITypeLib2_fnGetLibStatistics, - ITypeLib2_fnGetDocumentation2, - ITypeLib2_fnGetAllCustData - }; - - -static HRESULT WINAPI ITypeLibComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv) -{ - ICOM_THIS_From_ITypeComp(ITypeLibImpl, iface); - - return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv); -} - -static ULONG WINAPI ITypeLibComp_fnAddRef(ITypeComp * iface) -{ - ICOM_THIS_From_ITypeComp(ITypeLibImpl, iface); - - return ITypeInfo_AddRef((ITypeInfo *)This); -} - -static ULONG WINAPI ITypeLibComp_fnRelease(ITypeComp * iface) -{ - ICOM_THIS_From_ITypeComp(ITypeLibImpl, iface); - - return ITypeInfo_Release((ITypeInfo *)This); -} - -static HRESULT WINAPI ITypeLibComp_fnBind( - ITypeComp * iface, - OLECHAR * szName, - ULONG lHash, - WORD wFlags, - ITypeInfo ** ppTInfo, - DESCKIND * pDescKind, - BINDPTR * pBindPtr) -{ - FIXME("(%s, %lx, 0x%x, %p, %p, %p): stub\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr); - return E_NOTIMPL; -} - -static HRESULT WINAPI ITypeLibComp_fnBindType( - ITypeComp * iface, - OLECHAR * szName, - ULONG lHash, - ITypeInfo ** ppTInfo, - ITypeComp ** ppTComp) -{ - FIXME("(%s, %lx, %p, %p): stub\n", debugstr_w(szName), lHash, ppTInfo, ppTComp); - return E_NOTIMPL; -} - -static ITypeCompVtbl tlbtcvt = -{ - - ITypeLibComp_fnQueryInterface, - ITypeLibComp_fnAddRef, - ITypeLibComp_fnRelease, - - ITypeLibComp_fnBind, - ITypeLibComp_fnBindType -}; - -/*================== ITypeInfo(2) Methods ===================================*/ -static ITypeInfo2 * WINAPI ITypeInfo_Constructor(void) -{ - ITypeInfoImpl * pTypeInfoImpl; - - pTypeInfoImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeInfoImpl)); - if (pTypeInfoImpl) - { - pTypeInfoImpl->lpVtbl = &tinfvt; - pTypeInfoImpl->lpVtblTypeComp = &tcompvt; - pTypeInfoImpl->ref=1; - } - TRACE("(%p)\n", pTypeInfoImpl); - return (ITypeInfo2*) pTypeInfoImpl; -} - -/* ITypeInfo::QueryInterface - */ -static HRESULT WINAPI ITypeInfo_fnQueryInterface( - ITypeInfo2 *iface, - REFIID riid, - VOID **ppvObject) -{ - ITypeLibImpl *This = (ITypeLibImpl *)iface; - - TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid)); - - *ppvObject=NULL; - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid,&IID_ITypeInfo)|| - IsEqualIID(riid,&IID_ITypeInfo2)) - *ppvObject = This; - - if(*ppvObject){ - ITypeInfo_AddRef(iface); - TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject); - return S_OK; - } - TRACE("-- Interface: E_NOINTERFACE\n"); - return E_NOINTERFACE; -} - -/* ITypeInfo::AddRef - */ -static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - ULONG ref = InterlockedIncrement(&This->ref); - - ITypeLib2_AddRef((ITypeLib2*)This->pTypeLib); - - TRACE("(%p)->ref is %lu\n",This, ref); - return ref; -} - -/* ITypeInfo::Release - */ -static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - ULONG ref = InterlockedDecrement(&This->ref); - - TRACE("(%p)->(%lu)\n",This, ref); - - if (ref) { - /* We don't release ITypeLib when ref=0 because - it means that function is called by ITypeLib2_Release */ - ITypeLib2_Release((ITypeLib2*)This->pTypeLib); - } else { - FIXME("destroy child objects\n"); - - TRACE("destroying ITypeInfo(%p)\n",This); - if (This->Name) - { - SysFreeString(This->Name); - This->Name = 0; - } - - if (This->DocString) - { - SysFreeString(This->DocString); - This->DocString = 0; - } - - if (This->next) - { - ITypeInfo_Release((ITypeInfo*)This->next); - } - - HeapFree(GetProcessHeap(),0,This); - return 0; - } - return ref; -} - -/* ITypeInfo::GetTypeAttr - * - * Retrieves a TYPEATTR structure that contains the attributes of the type - * description. - * - */ -static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface, - LPTYPEATTR *ppTypeAttr) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - TRACE("(%p)\n",This); - *ppTypeAttr = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppTypeAttr)); - memcpy(*ppTypeAttr, &This->TypeAttr, sizeof(**ppTypeAttr)); - - if(This->TypeAttr.typekind == TKIND_ALIAS) /* need to deep copy typedesc */ - copy_typedesc(&(*ppTypeAttr)->tdescAlias, &This->TypeAttr.tdescAlias); - - if((*ppTypeAttr)->typekind == TKIND_DISPATCH && (*ppTypeAttr)->wTypeFlags & TYPEFLAG_FDUAL) { - (*ppTypeAttr)->cFuncs = (*ppTypeAttr)->cbSizeVft / 4; /* This should include all the inherited - funcs */ - (*ppTypeAttr)->cbSizeVft = 28; /* This is always the size of IDispatch's vtbl */ - (*ppTypeAttr)->wTypeFlags &= ~TYPEFLAG_FOLEAUTOMATION; - } - return S_OK; -} - -/* ITypeInfo::GetTypeComp - * - * Retrieves the ITypeComp interface for the type description, which enables a - * client compiler to bind to the type description's members. - * - */ -static HRESULT WINAPI ITypeInfo_fnGetTypeComp( ITypeInfo2 *iface, - ITypeComp * *ppTComp) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - - TRACE("(%p)->(%p) stub!\n", This, ppTComp); - - *ppTComp = (ITypeComp *)&This->lpVtblTypeComp; - ITypeComp_AddRef(*ppTComp); - return S_OK; -} - -/* ITypeInfo::GetFuncDesc - * - * Retrieves the FUNCDESC structure that contains information about a - * specified function. - * - */ -static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index, - LPFUNCDESC *ppFuncDesc) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - int i; - TLBFuncDesc * pFDesc; - TRACE("(%p) index %d\n", This, index); - for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, pFDesc=pFDesc->next) - ; - if(pFDesc){ - /* FIXME: must do a copy here */ - *ppFuncDesc=&pFDesc->funcdesc; - return S_OK; - } - return E_INVALIDARG; -} - -/* ITypeInfo::GetVarDesc - * - * Retrieves a VARDESC structure that describes the specified variable. - * - */ -static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index, - LPVARDESC *ppVarDesc) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - int i; - TLBVarDesc * pVDesc; - TRACE("(%p) index %d\n", This, index); - for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next) - ; - if(pVDesc){ - /* FIXME: must do a copy here */ - *ppVarDesc=&pVDesc->vardesc; - return S_OK; - } - return E_INVALIDARG; -} - -/* ITypeInfo_GetNames - * - * Retrieves the variable with the specified member ID (or the name of the - * property or method and its parameters) that correspond to the specified - * function ID. - */ -static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid, - BSTR *rgBstrNames, UINT cMaxNames, UINT *pcNames) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - TLBFuncDesc * pFDesc; - TLBVarDesc * pVDesc; - int i; - TRACE("(%p) memid=0x%08lx Maxname=%d\n", This, memid, cMaxNames); - for(pFDesc=This->funclist; pFDesc && pFDesc->funcdesc.memid != memid; pFDesc=pFDesc->next); - if(pFDesc) - { - /* function found, now return function and parameter names */ - for(i=0; i<cMaxNames && i <= pFDesc->funcdesc.cParams; i++) - { - if(!i) - *rgBstrNames=SysAllocString(pFDesc->Name); - else - rgBstrNames[i]=SysAllocString(pFDesc->pParamDesc[i-1].Name); - } - *pcNames=i; - } - else - { - for(pVDesc=This->varlist; pVDesc && pVDesc->vardesc.memid != memid; pVDesc=pVDesc->next); - if(pVDesc) - { - *rgBstrNames=SysAllocString(pVDesc->Name); - *pcNames=1; - } - else - { - if(This->TypeAttr.cImplTypes && - (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) { - /* recursive search */ - ITypeInfo *pTInfo; - HRESULT result; - result=ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, - &pTInfo); - if(SUCCEEDED(result)) - { - result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames); - ITypeInfo_Release(pTInfo); - return result; - } - WARN("Could not search inherited interface!\n"); - } - else - { - WARN("no names found\n"); - } - *pcNames=0; - return TYPE_E_ELEMENTNOTFOUND; - } - } - return S_OK; -} - - -/* ITypeInfo::GetRefTypeOfImplType - * - * If a type description describes a COM class, it retrieves the type - * description of the implemented interface types. For an interface, - * GetRefTypeOfImplType returns the type information for inherited interfaces, - * if any exist. - * - */ -static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType( - ITypeInfo2 *iface, - UINT index, - HREFTYPE *pRefType) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - int(i); - TLBImplType *pImpl = This->impltypelist; - - TRACE("(%p) index %d\n", This, index); - if (TRACE_ON(ole)) dump_TypeInfo(This); - - if(index==(UINT)-1) - { - /* only valid on dual interfaces; - retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH - */ - if( This->TypeAttr.typekind != TKIND_DISPATCH) return E_INVALIDARG; - - if (This->TypeAttr.wTypeFlags & TYPEFLAG_FDISPATCHABLE && - This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL ) - { - *pRefType = -1; - } - else - { - if (!pImpl) return TYPE_E_ELEMENTNOTFOUND; - *pRefType = pImpl->hRef; - } - } - else - { - /* get element n from linked list */ - for(i=0; pImpl && i<index; i++) - { - pImpl = pImpl->next; - } - - if (!pImpl) return TYPE_E_ELEMENTNOTFOUND; - - *pRefType = pImpl->hRef; - - TRACE("-- 0x%08lx\n", pImpl->hRef ); - } - - return S_OK; - -} - -/* ITypeInfo::GetImplTypeFlags - * - * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface - * or base interface in a type description. - */ -static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface, - UINT index, INT *pImplTypeFlags) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - int i; - TLBImplType *pImpl; - - TRACE("(%p) index %d\n", This, index); - for(i=0, pImpl=This->impltypelist; i<index && pImpl; - i++, pImpl=pImpl->next) - ; - if(i==index && pImpl){ - *pImplTypeFlags=pImpl->implflags; - return S_OK; - } - *pImplTypeFlags=0; - return TYPE_E_ELEMENTNOTFOUND; -} - -/* GetIDsOfNames - * Maps between member names and member IDs, and parameter names and - * parameter IDs. - */ -static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface, - LPOLESTR *rgszNames, UINT cNames, MEMBERID *pMemId) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - TLBFuncDesc * pFDesc; - TLBVarDesc * pVDesc; - HRESULT ret=S_OK; - - TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames), - cNames); - for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) { - int i, j; - if(!lstrcmpiW(*rgszNames, pFDesc->Name)) { - if(cNames) *pMemId=pFDesc->funcdesc.memid; - for(i=1; i < cNames; i++){ - for(j=0; j<pFDesc->funcdesc.cParams; j++) - if(!lstrcmpiW(rgszNames[i],pFDesc->pParamDesc[j].Name)) - break; - if( j<pFDesc->funcdesc.cParams) - pMemId[i]=j; - else - ret=DISP_E_UNKNOWNNAME; - }; - return ret; - } - } - for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) { - if(!lstrcmpiW(*rgszNames, pVDesc->Name)) { - if(cNames) *pMemId=pVDesc->vardesc.memid; - return ret; - } - } - /* not found, see if this is and interface with an inheritance */ - if(This->TypeAttr.cImplTypes && - (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) { - /* recursive search */ - ITypeInfo *pTInfo; - ret=ITypeInfo_GetRefTypeInfo(iface, - This->impltypelist->hRef, &pTInfo); - if(SUCCEEDED(ret)){ - ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId ); - ITypeInfo_Release(pTInfo); - return ret; - } - WARN("Could not search inherited interface!\n"); - } else - WARN("no names found\n"); - return DISP_E_UNKNOWNNAME; -} - -/* ITypeInfo::Invoke - * - * Invokes a method, or accesses a property of an object, that implements the - * interface described by the type description. - */ -DWORD -_invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) { - DWORD res; - - if (TRACE_ON(ole)) { - int i; - TRACE("Calling %p(",func); - for (i=0;i<nrargs;i++) TRACE("%08lx,",args[i]); - TRACE(")\n"); - } - - switch (callconv) { - case CC_STDCALL: - - switch (nrargs) { - case 0: - res = func(); - break; - case 1: - res = func(args[0]); - break; - case 2: - res = func(args[0],args[1]); - break; - case 3: - res = func(args[0],args[1],args[2]); - break; - case 4: - res = func(args[0],args[1],args[2],args[3]); - break; - case 5: - res = func(args[0],args[1],args[2],args[3],args[4]); - break; - case 6: - res = func(args[0],args[1],args[2],args[3],args[4],args[5]); - break; - case 7: - res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6]); - break; - case 8: - res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]); - break; - case 9: - res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]); - break; - case 10: - res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]); - break; - case 11: - res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]); - break; - default: - FIXME("unsupported number of arguments %d in stdcall\n",nrargs); - res = -1; - break; - } - break; - default: - FIXME("unsupported calling convention %d\n",callconv); - res = -1; - break; - } - TRACE("returns %08lx\n",res); - return res; -} - -extern int _argsize(DWORD vt); - -/**************************************************************************** - * Helper functions for Dispcall / Invoke, which copies one variant - * with target type onto the argument stack. - */ -static HRESULT -_copy_arg( ITypeInfo2 *tinfo, TYPEDESC *tdesc, - DWORD *argpos, VARIANT *arg, VARTYPE vt -) { - UINT arglen = _argsize(vt)*sizeof(DWORD); - VARIANT va; - - if ((vt==VT_PTR) && tdesc && (tdesc->u.lptdesc->vt == VT_VARIANT)) { - memcpy(argpos,&arg,sizeof(void*)); - return S_OK; - } - - if (V_VT(arg) == vt) { - memcpy(argpos, &V_I4(arg), arglen); - return S_OK; - } - - if (V_ISARRAY(arg) && (vt == VT_SAFEARRAY)) { - memcpy(argpos, &V_ARRAY(arg), sizeof(SAFEARRAY*)); - return S_OK; - } - - if (vt == VT_VARIANT) { - memcpy(argpos, arg, arglen); - return S_OK; - } - /* Deref BYREF vars if there is need */ - if(V_ISBYREF(arg) && ((V_VT(arg) & ~VT_BYREF)==vt)) { - memcpy(argpos,(void*)V_I4(arg), arglen); - return S_OK; - } - if (vt==VT_UNKNOWN && V_VT(arg)==VT_DISPATCH) { - /* in this context, if the type lib specifies IUnknown*, giving an - IDispatch* is correct; so, don't invoke VariantChangeType */ - memcpy(argpos,&V_I4(arg), arglen); - return S_OK; - } - if ((vt == VT_PTR) && tdesc) - return _copy_arg(tinfo, tdesc->u.lptdesc, argpos, arg, tdesc->u.lptdesc->vt); - - if ((vt == VT_USERDEFINED) && tdesc && tinfo) { - ITypeInfo *tinfo2 = NULL; - TYPEATTR *tattr = NULL; - HRESULT hres; - - hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2); - if (hres) { - FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED, " - "while coercing from vt 0x%x. Copying 4 byte.\n", - tdesc->u.hreftype,V_VT(arg)); - memcpy(argpos, &V_I4(arg), 4); - return S_OK; - } - hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr); - if( hres ) - { - ERR("GetTypeAttr failed\n"); - ITypeInfo_Release(tinfo2); - return hres; - } - switch (tattr->typekind) { - case TKIND_ENUM: - switch ( V_VT( arg ) ) { - case VT_I2: - *argpos = V_I2(arg); - hres = S_OK; - break; - case VT_I4: - memcpy(argpos, &V_I4(arg), 4); - hres = S_OK; - break; - default: - FIXME("vt 0x%x -> TKIND_ENUM unhandled.\n",V_VT(arg)); - hres = E_FAIL; - break; - } - break; - - case TKIND_ALIAS: - tdesc = &(tattr->tdescAlias); - hres = _copy_arg((ITypeInfo2*)tinfo2, tdesc, argpos, arg, tdesc->vt); - break; - - case TKIND_INTERFACE: - if (V_VT(arg) == VT_DISPATCH) { - IDispatch *disp; - if (IsEqualIID(&IID_IDispatch,&(tattr->guid))) { - memcpy(argpos, &V_DISPATCH(arg), 4); - hres = S_OK; - break; - } - hres=IUnknown_QueryInterface(V_DISPATCH(arg), - &IID_IDispatch,(LPVOID*)&disp); - if (SUCCEEDED(hres)) { - memcpy(argpos,&disp,4); - IUnknown_Release(V_DISPATCH(arg)); - hres = S_OK; - break; - } - FIXME("Failed to query IDispatch interface from %s while " - "converting to VT_DISPATCH!\n",debugstr_guid(&(tattr->guid))); - hres = E_FAIL; - break; - } - if (V_VT(arg) == VT_UNKNOWN) { - memcpy(argpos, &V_UNKNOWN(arg), 4); - hres = S_OK; - break; - } - FIXME("vt 0x%x -> TKIND_INTERFACE(%s) unhandled\n", - V_VT(arg),debugstr_guid(&(tattr->guid))); - hres = E_FAIL; - break; - - case TKIND_DISPATCH: - if (V_VT(arg) == VT_DISPATCH) { - memcpy(argpos, &V_DISPATCH(arg), 4); - hres = S_OK; - } - else { - hres = E_FAIL; - FIXME("TKIND_DISPATCH unhandled for target vt 0x%x.\n",V_VT(arg)); - } - break; - case TKIND_RECORD: - FIXME("TKIND_RECORD unhandled.\n"); - hres = E_FAIL; - break; - default: - FIXME("TKIND %d unhandled.\n",tattr->typekind); - hres = E_FAIL; - break; - } - ITypeInfo_ReleaseTypeAttr(tinfo2, tattr); - ITypeInfo_Release(tinfo2); - return hres; - } - - VariantInit(&va); - if (VariantChangeType(&va,arg,0,vt)==S_OK) { - memcpy(argpos,&V_I4(&va), arglen); - FIXME("Should not use VariantChangeType here." - " (conversion from 0x%x -> 0x%x) %08lx\n", - V_VT(arg), vt, *argpos - ); - return S_OK; - } - ERR("Set arg to disparg type 0x%x vs 0x%x\n",V_VT(arg),vt); - return E_FAIL; -} - -/*********************************************************************** - * DispCallFunc (OLEAUT32.@) - */ -HRESULT WINAPI -DispCallFunc( - void* pvInstance, ULONG oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals, - VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult -) { - int i, argsize, argspos; - DWORD *args; - HRESULT hres; - - TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n", - pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult) - ); - /* DispCallFunc is only used to invoke methods belonging to an IDispatch-derived COM interface. - So we need to add a first parameter to the list of arguments, to supply the interface pointer */ - argsize = 1; - for (i=0;i<cActuals;i++) { - TRACE("arg %d: type %d, size %d\n",i,prgvt[i],_argsize(prgvt[i])); - dump_Variant(prgpvarg[i]); - argsize += _argsize(prgvt[i]); - } - args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*argsize); - args[0] = (DWORD)pvInstance; /* this is the fake IDispatch interface pointer */ - argspos = 1; - for (i=0;i<cActuals;i++) { - VARIANT *arg = prgpvarg[i]; - TRACE("Storing arg %d (%d as %d)\n",i,V_VT(arg),prgvt[i]); - _copy_arg(NULL, NULL, &args[argspos], arg, prgvt[i]); - argspos += _argsize(prgvt[i]); - } - - if(pvargResult!=NULL && V_VT(pvargResult)==VT_EMPTY) - { - _invoke((*(FARPROC**)pvInstance)[oVft/4],cc,argsize,args); - hres=S_OK; - } - else - { - FIXME("Do not know how to handle pvargResult %p. Expect crash ...\n",pvargResult); - hres = _invoke((*(FARPROC**)pvInstance)[oVft/4],cc,argsize,args); - FIXME("Method returned %lx\n",hres); - } - HeapFree(GetProcessHeap(),0,args); - return hres; -} - -static HRESULT WINAPI ITypeInfo_fnInvoke( - ITypeInfo2 *iface, - VOID *pIUnk, - MEMBERID memid, - UINT16 dwFlags, - DISPPARAMS *pDispParams, - VARIANT *pVarResult, - EXCEPINFO *pExcepInfo, - UINT *pArgErr) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - int i; - unsigned int func_index, var_index; - TYPEKIND type_kind; - HRESULT hres; - - TRACE("(%p)(%p,id=%ld,flags=0x%08x,%p,%p,%p,%p) partial stub!\n", - This,pIUnk,memid,dwFlags,pDispParams,pVarResult,pExcepInfo,pArgErr - ); - dump_DispParms(pDispParams); - - hres = ITypeInfo2_GetFuncIndexOfMemId(iface, memid, dwFlags, &func_index); - if (SUCCEEDED(hres)) { - FUNCDESC *func_desc; - - hres = ITypeInfo2_GetFuncDesc(iface, func_index, &func_desc); - if(FAILED(hres)) return hres; - - switch (func_desc->funckind) { - case FUNC_PUREVIRTUAL: - case FUNC_VIRTUAL: { - DWORD res; - int numargs, numargs2, argspos, args2pos; - DWORD *args , *args2; - VARIANT *rgvarg = HeapAlloc(GetProcessHeap(), 0, sizeof(VARIANT) * func_desc->cParams); - memcpy(rgvarg,pDispParams->rgvarg,sizeof(VARIANT)*pDispParams->cArgs); - - hres = S_OK; - numargs = 1; numargs2 = 0; - for (i = 0; i < func_desc->cParams; i++) { - if (i<pDispParams->cArgs) - numargs += _argsize(func_desc->lprgelemdescParam[i].tdesc.vt); - else { - numargs += 1; /* sizeof(lpvoid) */ - numargs2 += _argsize(func_desc->lprgelemdescParam[i].tdesc.vt); - } - } - - args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*numargs); - args2 = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*numargs2); - - args[0] = (DWORD)pIUnk; - argspos = 1; args2pos = 0; - for (i = 0; i < func_desc->cParams; i++) { - int arglen = _argsize(func_desc->lprgelemdescParam[i].tdesc.vt); - if (i<pDispParams->cArgs) { - VARIANT *arg = &rgvarg[pDispParams->cArgs-i-1]; - TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc; - USHORT paramFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags; - if (paramFlags & PARAMFLAG_FOPT) { - if(i < func_desc->cParams - func_desc->cParamsOpt) - ERR("Parameter has PARAMFLAG_FOPT flag but is not one of last cParamOpt parameters\n"); - if(V_VT(arg) == VT_EMPTY - || ((V_ISBYREF(arg)) && !V_BYREF(arg))) { - /* FIXME: Documentation says that we do this when parameter is left unspecified. - How to determine it? */ - - if(paramFlags & PARAMFLAG_FHASDEFAULT) - FIXME("PARAMFLAG_FHASDEFAULT flag not supported\n"); - V_VT(arg) = VT_ERROR; - V_ERROR(arg) = DISP_E_PARAMNOTFOUND; - arglen = _argsize(VT_ERROR); - } - } - hres = _copy_arg(iface, tdesc, &args[argspos], arg, tdesc->vt); - if (FAILED(hres)) goto func_fail; - argspos += arglen; - } else if(func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags & PARAMFLAG_FOPT) { - VARIANT *arg = &rgvarg[i]; - TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc; - if(i < func_desc->cParams - func_desc->cParamsOpt) - ERR("Parameter has PARAMFLAG_FOPT flag but is not one of last cParamOpt parameters\n"); - if(func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) - FIXME("PARAMFLAG_FHASDEFAULT flag not supported\n"); - V_VT(arg) = VT_ERROR; - V_ERROR(arg) = DISP_E_PARAMNOTFOUND; - arglen = _argsize(VT_ERROR); - hres = _copy_arg(iface, tdesc, &args[argspos], arg, tdesc->vt); - if (FAILED(hres)) goto func_fail; - argspos += arglen; - } else { - TYPEDESC *tdesc = &(func_desc->lprgelemdescParam[i].tdesc); - if (tdesc->vt != VT_PTR) - FIXME("set %d to pointer for get (type is %d)\n",i,tdesc->vt); - /*FIXME: give pointers for the rest, so propertyget works*/ - args[argspos] = (DWORD)&args2[args2pos]; - - /* If pointer to variant, pass reference it. */ - if ((tdesc->vt == VT_PTR) && - (tdesc->u.lptdesc->vt == VT_VARIANT) && - pVarResult - ) - args[argspos]= (DWORD)pVarResult; - argspos += 1; - args2pos += arglen; - } - } - if (func_desc->cParamsOpt < 0) - FIXME("Does not support optional parameters (%d)\n", func_desc->cParamsOpt); - - res = _invoke((*(FARPROC**)pIUnk)[func_desc->oVft/4], - func_desc->callconv, - numargs, - args - ); - - if (pVarResult && (dwFlags & (DISPATCH_PROPERTYGET))) { - args2pos = 0; - for (i = 0; i < func_desc->cParams - pDispParams->cArgs; i++) { - int arglen = _argsize(func_desc->lprgelemdescParam[i].tdesc.vt); - TYPEDESC *tdesc = &(func_desc->lprgelemdescParam[i + pDispParams->cArgs].tdesc); - TYPEDESC i4_tdesc; - i4_tdesc.vt = VT_I4; - - /* If we are a pointer to a variant, we are done already */ - if ((tdesc->vt==VT_PTR)&&(tdesc->u.lptdesc->vt==VT_VARIANT)) - continue; - - VariantInit(pVarResult); - memcpy(&V_INT(pVarResult),&args2[args2pos],arglen*sizeof(DWORD)); - - if (tdesc->vt == VT_PTR) - tdesc = tdesc->u.lptdesc; - if (tdesc->vt == VT_USERDEFINED) { - ITypeInfo *tinfo2; - TYPEATTR *tattr; - - hres = ITypeInfo_GetRefTypeInfo(iface,tdesc->u.hreftype,&tinfo2); - if (FAILED(hres)) { - FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED, while coercing. Copying 4 byte.\n",tdesc->u.hreftype); - goto func_fail; - } - ITypeInfo_GetTypeAttr(tinfo2,&tattr); - switch (tattr->typekind) { - case TKIND_ENUM: - /* force the return type to be VT_I4 */ - tdesc = &i4_tdesc; - break; - case TKIND_ALIAS: - TRACE("TKIND_ALIAS to vt 0x%x\n",tattr->tdescAlias.vt); - tdesc = &(tattr->tdescAlias); - break; - - case TKIND_INTERFACE: - FIXME("TKIND_INTERFACE unhandled.\n"); - break; - case TKIND_DISPATCH: - FIXME("TKIND_DISPATCH unhandled.\n"); - break; - case TKIND_RECORD: - FIXME("TKIND_RECORD unhandled.\n"); - break; - default: - FIXME("TKIND %d unhandled.\n",tattr->typekind); - break; - } - ITypeInfo_Release(tinfo2); - } - V_VT(pVarResult) = tdesc->vt; - - /* HACK: VB5 likes this. - * I do not know why. There is 1 example in MSDN which uses - * this which appears broken (mixes int vals and - * IDispatch*.). - */ - if ((tdesc->vt == VT_PTR) && (dwFlags & DISPATCH_METHOD)) - V_VT(pVarResult) = VT_DISPATCH; - TRACE("storing into variant:\n"); - dump_Variant(pVarResult); - args2pos += arglen; - } - } -func_fail: - HeapFree(GetProcessHeap(), 0, rgvarg); - HeapFree(GetProcessHeap(),0,args2); - HeapFree(GetProcessHeap(),0,args); - break; - } - case FUNC_DISPATCH: { - IDispatch *disp; - - hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp); - if (SUCCEEDED(hres)) { - FIXME("Calling Invoke in IDispatch iface. untested!\n"); - hres = IDispatch_Invoke( - disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,dwFlags,pDispParams, - pVarResult,pExcepInfo,pArgErr - ); - if (FAILED(hres)) - FIXME("IDispatch::Invoke failed with %08lx. (Could be not a real error?)\n", hres); - IDispatch_Release(disp); - } else - FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n"); - break; - } - default: - FIXME("Unknown function invocation type %d\n", func_desc->funckind); - hres = E_FAIL; - break; - } - - ITypeInfo2_ReleaseFuncDesc(iface, func_desc); - return hres; - - } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) { - VARDESC *var_desc; - - hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc); - if(FAILED(hres)) return hres; - - FIXME("varseek: Found memid, but variable-based invoking not supported\n"); - dump_VARDESC(var_desc); - ITypeInfo2_ReleaseVarDesc(iface, var_desc); - return E_NOTIMPL; - } - - /* not found, look for it in inherited interfaces */ - ITypeInfo2_GetTypeKind(iface, &type_kind); - if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) { - HREFTYPE ref_type; - if(SUCCEEDED(ITypeInfo2_GetRefTypeOfImplType(iface, 0, &ref_type))) { - /* recursive search */ - ITypeInfo *pTInfo; - hres = ITypeInfo_GetRefTypeInfo(iface, ref_type, &pTInfo); - if(SUCCEEDED(hres)){ - hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,dwFlags,pDispParams,pVarResult,pExcepInfo,pArgErr); - ITypeInfo_Release(pTInfo); - return hres; - } - WARN("Could not search inherited interface!\n"); - } - } - ERR("did not find member id %08lx, flags %d!\n", memid, dwFlags); - return DISP_E_MEMBERNOTFOUND; -} - -/* ITypeInfo::GetDocumentation - * - * Retrieves the documentation string, the complete Help file name and path, - * and the context ID for the Help topic for a specified type description. - * - * (Can be tested by the Visual Basic Editor in Word for instance.) - */ -static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface, - MEMBERID memid, BSTR *pBstrName, BSTR *pBstrDocString, - DWORD *pdwHelpContext, BSTR *pBstrHelpFile) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - TLBFuncDesc * pFDesc; - TLBVarDesc * pVDesc; - TRACE("(%p) memid %ld Name(%p) DocString(%p)" - " HelpContext(%p) HelpFile(%p)\n", - This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile); - if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */ - if(pBstrName) - *pBstrName=SysAllocString(This->Name); - if(pBstrDocString) - *pBstrDocString=SysAllocString(This->DocString); - if(pdwHelpContext) - *pdwHelpContext=This->dwHelpContext; - if(pBstrHelpFile) - *pBstrHelpFile=SysAllocString(This->DocString);/* FIXME */ - return S_OK; - }else {/* for a member */ - for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) - if(pFDesc->funcdesc.memid==memid){ - if(pBstrName) - *pBstrName = SysAllocString(pFDesc->Name); - if(pBstrDocString) - *pBstrDocString=SysAllocString(pFDesc->HelpString); - if(pdwHelpContext) - *pdwHelpContext=pFDesc->helpcontext; - return S_OK; - } - for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) - if(pVDesc->vardesc.memid==memid){ - if(pBstrName) - *pBstrName = SysAllocString(pVDesc->Name); - if(pBstrDocString) - *pBstrDocString=SysAllocString(pVDesc->HelpString); - if(pdwHelpContext) - *pdwHelpContext=pVDesc->HelpContext; - return S_OK; - } - } - return TYPE_E_ELEMENTNOTFOUND; -} - -/* ITypeInfo::GetDllEntry - * - * Retrieves a description or specification of an entry point for a function - * in a DLL. - */ -static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid, - INVOKEKIND invKind, BSTR *pBstrDllName, BSTR *pBstrName, - WORD *pwOrdinal) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - TLBFuncDesc *pFDesc; - - FIXME("(%p, memid %lx, %d, %p, %p, %p), partial stub!\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal); - - for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) - if(pFDesc->funcdesc.memid==memid){ - dump_TypeInfo(This); - dump_TLBFuncDescOne(pFDesc); - - /* FIXME: This is wrong, but how do you find that out? */ - if (pBstrDllName) { - static const WCHAR oleaut32W[] = {'O','L','E','A','U','T','3','2','.','D','L','L',0}; - *pBstrDllName = SysAllocString(oleaut32W); - } - - if (HIWORD(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) { - if (pBstrName) - *pBstrName = SysAllocString(pFDesc->Entry); - if (pwOrdinal) - *pwOrdinal = -1; - return S_OK; - } - if (pBstrName) - *pBstrName = NULL; - if (pwOrdinal) - *pwOrdinal = (DWORD)pFDesc->Entry; - return S_OK; - } - return E_FAIL; -} - -/* ITypeInfo::GetRefTypeInfo - * - * If a type description references other type descriptions, it retrieves - * the referenced type descriptions. - */ -static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo( - ITypeInfo2 *iface, - HREFTYPE hRefType, - ITypeInfo **ppTInfo) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - HRESULT result = E_FAIL; - - - if (hRefType == -1 && - (((ITypeInfoImpl*) This)->TypeAttr.typekind == TKIND_DISPATCH) && - (((ITypeInfoImpl*) This)->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL)) - { - /* when we meet a DUAL dispinterface, we must create the interface - * version of it. - */ - ITypeInfoImpl* pTypeInfoImpl = (ITypeInfoImpl*) ITypeInfo_Constructor(); - - - /* the interface version contains the same information as the dispinterface - * copy the contents of the structs. - */ - *pTypeInfoImpl = *This; - pTypeInfoImpl->ref = 1; - - /* change the type to interface */ - pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE; - - *ppTInfo = (ITypeInfo*) pTypeInfoImpl; - - ITypeInfo_AddRef((ITypeInfo*) pTypeInfoImpl); - - result = S_OK; - - } else { - TLBRefType *pRefType; - for(pRefType = This->reflist; pRefType; pRefType = pRefType->next) { - if(pRefType->reference == hRefType) - break; - } - if(!pRefType) - FIXME("Can't find pRefType for ref %lx\n", hRefType); - if(pRefType && hRefType != -1) { - ITypeLib *pTLib = NULL; - - if(pRefType->pImpTLInfo == TLB_REF_INTERNAL) { - int Index; - result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index); - } else { - if(pRefType->pImpTLInfo->pImpTypeLib) { - TRACE("typeinfo in imported typelib that is already loaded\n"); - pTLib = (ITypeLib*)pRefType->pImpTLInfo->pImpTypeLib; - ITypeLib2_AddRef((ITypeLib*) pTLib); - result = S_OK; - } else { - TRACE("typeinfo in imported typelib that isn't already loaded\n"); - result = LoadRegTypeLib( &pRefType->pImpTLInfo->guid, - pRefType->pImpTLInfo->wVersionMajor, - pRefType->pImpTLInfo->wVersionMinor, - pRefType->pImpTLInfo->lcid, - &pTLib); - - if(!SUCCEEDED(result)) { - BSTR libnam=SysAllocString(pRefType->pImpTLInfo->name); - result=LoadTypeLib(libnam, &pTLib); - SysFreeString(libnam); - } - if(SUCCEEDED(result)) { - pRefType->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib; - ITypeLib2_AddRef(pTLib); - } - } - } - if(SUCCEEDED(result)) { - if(pRefType->index == TLB_REF_USE_GUID) - result = ITypeLib2_GetTypeInfoOfGuid(pTLib, - &pRefType->guid, - ppTInfo); - else - result = ITypeLib2_GetTypeInfo(pTLib, pRefType->index, - ppTInfo); - } - if (pTLib != NULL) - ITypeLib2_Release(pTLib); - } - } - - TRACE("(%p) hreftype 0x%04lx loaded %s (%p)\n", This, hRefType, - SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo); - return result; -} - -/* ITypeInfo::AddressOfMember - * - * Retrieves the addresses of static functions or variables, such as those - * defined in a DLL. - */ -static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface, - MEMBERID memid, INVOKEKIND invKind, PVOID *ppv) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - FIXME("(%p) stub!\n", This); - return S_OK; -} - -/* ITypeInfo::CreateInstance - * - * Creates a new instance of a type that describes a component object class - * (coclass). - */ -static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface, - IUnknown *pUnk, REFIID riid, VOID **ppvObj) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - FIXME("(%p) stub!\n", This); - return S_OK; -} - -/* ITypeInfo::GetMops - * - * Retrieves marshalling information. - */ -static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid, - BSTR *pBstrMops) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - FIXME("(%p) stub!\n", This); - return S_OK; -} - -/* ITypeInfo::GetContainingTypeLib - * - * Retrieves the containing type library and the index of the type description - * within that type library. - */ -static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface, - ITypeLib * *ppTLib, UINT *pIndex) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - - /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */ - if (pIndex) { - *pIndex=This->index; - TRACE("returning pIndex=%d\n", *pIndex); - } - - if (ppTLib) { - *ppTLib=(LPTYPELIB )(This->pTypeLib); - ITypeLib2_AddRef(*ppTLib); - TRACE("returning ppTLib=%p\n", *ppTLib); - } - - return S_OK; -} - -/* ITypeInfo::ReleaseTypeAttr - * - * Releases a TYPEATTR previously returned by GetTypeAttr. - * - */ -static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface, - TYPEATTR* pTypeAttr) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - TRACE("(%p)->(%p)\n", This, pTypeAttr); - if(This->TypeAttr.typekind == TKIND_ALIAS) - free_deep_typedesc(&pTypeAttr->tdescAlias); - HeapFree(GetProcessHeap(), 0, pTypeAttr); -} - -/* ITypeInfo::ReleaseFuncDesc - * - * Releases a FUNCDESC previously returned by GetFuncDesc. * - */ -static void WINAPI ITypeInfo_fnReleaseFuncDesc( - ITypeInfo2 *iface, - FUNCDESC *pFuncDesc) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - TRACE("(%p)->(%p)\n", This, pFuncDesc); -} - -/* ITypeInfo::ReleaseVarDesc - * - * Releases a VARDESC previously returned by GetVarDesc. - */ -static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface, - VARDESC *pVarDesc) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - TRACE("(%p)->(%p)\n", This, pVarDesc); -} - -/* ITypeInfo2::GetTypeKind - * - * Returns the TYPEKIND enumeration quickly, without doing any allocations. - * - */ -static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface, - TYPEKIND *pTypeKind) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - *pTypeKind=This->TypeAttr.typekind; - TRACE("(%p) type 0x%0x\n", This,*pTypeKind); - return S_OK; -} - -/* ITypeInfo2::GetTypeFlags - * - * Returns the type flags without any allocations. This returns a DWORD type - * flag, which expands the type flags without growing the TYPEATTR (type - * attribute). - * - */ -static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - *pTypeFlags=This->TypeAttr.wTypeFlags; - TRACE("(%p) flags 0x%lx\n", This,*pTypeFlags); - return S_OK; -} - -/* ITypeInfo2::GetFuncIndexOfMemId - * Binds to a specific member based on a known DISPID, where the member name - * is not known (for example, when binding to a default member). - * - */ -static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface, - MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - TLBFuncDesc *pFuncInfo; - int i; - HRESULT result; - - for(i = 0, pFuncInfo = This->funclist; pFuncInfo; i++, pFuncInfo=pFuncInfo->next) - if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind)) - break; - if(pFuncInfo) { - *pFuncIndex = i; - result = S_OK; - } else - result = TYPE_E_ELEMENTNOTFOUND; - - TRACE("(%p) memid 0x%08lx invKind 0x%04x -> %s\n", This, - memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED"); - return result; -} - -/* TypeInfo2::GetVarIndexOfMemId - * - * Binds to a specific member based on a known DISPID, where the member name - * is not known (for example, when binding to a default member). - * - */ -static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface, - MEMBERID memid, UINT *pVarIndex) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - TLBVarDesc *pVarInfo; - int i; - HRESULT result; - for(i=0, pVarInfo=This->varlist; pVarInfo && - memid != pVarInfo->vardesc.memid; i++, pVarInfo=pVarInfo->next) - ; - if(pVarInfo) { - *pVarIndex = i; - result = S_OK; - } else - result = TYPE_E_ELEMENTNOTFOUND; - - TRACE("(%p) memid 0x%08lx -> %s\n", This, - memid, SUCCEEDED(result) ? "SUCCESS" : "FAILED"); - return result; -} - -/* ITypeInfo2::GetCustData - * - * Gets the custom data - */ -static HRESULT WINAPI ITypeInfo2_fnGetCustData( - ITypeInfo2 * iface, - REFGUID guid, - VARIANT *pVarVal) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - TLBCustData *pCData; - - for(pCData=This->pCustData; pCData; pCData = pCData->next) - if( IsEqualIID(guid, &pCData->guid)) break; - - TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT"); - - if(pCData) - { - VariantInit( pVarVal); - VariantCopy( pVarVal, &pCData->data); - return S_OK; - } - return E_INVALIDARG; /* FIXME: correct? */ -} - -/* ITypeInfo2::GetFuncCustData - * - * Gets the custom data - */ -static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData( - ITypeInfo2 * iface, - UINT index, - REFGUID guid, - VARIANT *pVarVal) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - TLBCustData *pCData=NULL; - TLBFuncDesc * pFDesc; - int i; - for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, - pFDesc=pFDesc->next); - - if(pFDesc) - for(pCData=pFDesc->pCustData; pCData; pCData = pCData->next) - if( IsEqualIID(guid, &pCData->guid)) break; - - TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT"); - - if(pCData){ - VariantInit( pVarVal); - VariantCopy( pVarVal, &pCData->data); - return S_OK; - } - return E_INVALIDARG; /* FIXME: correct? */ -} - -/* ITypeInfo2::GetParamCustData - * - * Gets the custom data - */ -static HRESULT WINAPI ITypeInfo2_fnGetParamCustData( - ITypeInfo2 * iface, - UINT indexFunc, - UINT indexParam, - REFGUID guid, - VARIANT *pVarVal) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - TLBCustData *pCData=NULL; - TLBFuncDesc * pFDesc; - int i; - - for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,pFDesc=pFDesc->next); - - if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams) - for(pCData=pFDesc->pParamDesc[indexParam].pCustData; pCData; - pCData = pCData->next) - if( IsEqualIID(guid, &pCData->guid)) break; - - TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT"); - - if(pCData) - { - VariantInit( pVarVal); - VariantCopy( pVarVal, &pCData->data); - return S_OK; - } - return E_INVALIDARG; /* FIXME: correct? */ -} - -/* ITypeInfo2::GetVarCustData - * - * Gets the custom data - */ -static HRESULT WINAPI ITypeInfo2_fnGetVarCustData( - ITypeInfo2 * iface, - UINT index, - REFGUID guid, - VARIANT *pVarVal) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - TLBCustData *pCData=NULL; - TLBVarDesc * pVDesc; - int i; - - for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next); - - if(pVDesc) - { - for(pCData=pVDesc->pCustData; pCData; pCData = pCData->next) - { - if( IsEqualIID(guid, &pCData->guid)) break; - } - } - - TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT"); - - if(pCData) - { - VariantInit( pVarVal); - VariantCopy( pVarVal, &pCData->data); - return S_OK; - } - return E_INVALIDARG; /* FIXME: correct? */ -} - -/* ITypeInfo2::GetImplCustData - * - * Gets the custom data - */ -static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData( - ITypeInfo2 * iface, - UINT index, - REFGUID guid, - VARIANT *pVarVal) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - TLBCustData *pCData=NULL; - TLBImplType * pRDesc; - int i; - - for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++, pRDesc=pRDesc->next); - - if(pRDesc) - { - for(pCData=pRDesc->pCustData; pCData; pCData = pCData->next) - { - if( IsEqualIID(guid, &pCData->guid)) break; - } - } - - TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT"); - - if(pCData) - { - VariantInit( pVarVal); - VariantCopy( pVarVal, &pCData->data); - return S_OK; - } - return E_INVALIDARG; /* FIXME: correct? */ -} - -/* ITypeInfo2::GetDocumentation2 - * - * Retrieves the documentation string, the complete Help file name and path, - * the localization context to use, and the context ID for the library Help - * topic in the Help file. - * - */ -static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2( - ITypeInfo2 * iface, - MEMBERID memid, - LCID lcid, - BSTR *pbstrHelpString, - DWORD *pdwHelpStringContext, - BSTR *pbstrHelpStringDll) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - TLBFuncDesc * pFDesc; - TLBVarDesc * pVDesc; - TRACE("(%p) memid %ld lcid(0x%lx) HelpString(%p) " - "HelpStringContext(%p) HelpStringDll(%p)\n", - This, memid, lcid, pbstrHelpString, pdwHelpStringContext, - pbstrHelpStringDll ); - /* the help string should be obtained from the helpstringdll, - * using the _DLLGetDocumentation function, based on the supplied - * lcid. Nice to do sometime... - */ - if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */ - if(pbstrHelpString) - *pbstrHelpString=SysAllocString(This->Name); - if(pdwHelpStringContext) - *pdwHelpStringContext=This->dwHelpStringContext; - if(pbstrHelpStringDll) - *pbstrHelpStringDll= - SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */ - return S_OK; - }else {/* for a member */ - for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) - if(pFDesc->funcdesc.memid==memid){ - if(pbstrHelpString) - *pbstrHelpString=SysAllocString(pFDesc->HelpString); - if(pdwHelpStringContext) - *pdwHelpStringContext=pFDesc->HelpStringContext; - if(pbstrHelpStringDll) - *pbstrHelpStringDll= - SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */ - return S_OK; - } - for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) - if(pVDesc->vardesc.memid==memid){ - if(pbstrHelpString) - *pbstrHelpString=SysAllocString(pVDesc->HelpString); - if(pdwHelpStringContext) - *pdwHelpStringContext=pVDesc->HelpStringContext; - if(pbstrHelpStringDll) - *pbstrHelpStringDll= - SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */ - return S_OK; - } - } - return TYPE_E_ELEMENTNOTFOUND; -} - -/* ITypeInfo2::GetAllCustData - * - * Gets all custom data items for the Type info. - * - */ -static HRESULT WINAPI ITypeInfo2_fnGetAllCustData( - ITypeInfo2 * iface, - CUSTDATA *pCustData) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - TLBCustData *pCData; - int i; - - TRACE("(%p) returning %d items\n", This, This->ctCustData); - - pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM)); - if(pCustData->prgCustData ){ - pCustData->cCustData=This->ctCustData; - for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){ - pCustData->prgCustData[i].guid=pCData->guid; - VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data); - } - }else{ - ERR(" OUT OF MEMORY! \n"); - return E_OUTOFMEMORY; - } - return S_OK; -} - -/* ITypeInfo2::GetAllFuncCustData - * - * Gets all custom data items for the specified Function - * - */ -static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData( - ITypeInfo2 * iface, - UINT index, - CUSTDATA *pCustData) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - TLBCustData *pCData; - TLBFuncDesc * pFDesc; - int i; - TRACE("(%p) index %d\n", This, index); - for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, - pFDesc=pFDesc->next) - ; - if(pFDesc){ - pCustData->prgCustData = - TLB_Alloc(pFDesc->ctCustData * sizeof(CUSTDATAITEM)); - if(pCustData->prgCustData ){ - pCustData->cCustData=pFDesc->ctCustData; - for(i=0, pCData=pFDesc->pCustData; pCData; i++, - pCData = pCData->next){ - pCustData->prgCustData[i].guid=pCData->guid; - VariantCopy(& pCustData->prgCustData[i].varValue, - & pCData->data); - } - }else{ - ERR(" OUT OF MEMORY! \n"); - return E_OUTOFMEMORY; - } - return S_OK; - } - return TYPE_E_ELEMENTNOTFOUND; -} - -/* ITypeInfo2::GetAllParamCustData - * - * Gets all custom data items for the Functions - * - */ -static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface, - UINT indexFunc, UINT indexParam, CUSTDATA *pCustData) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - TLBCustData *pCData=NULL; - TLBFuncDesc * pFDesc; - int i; - TRACE("(%p) index %d\n", This, indexFunc); - for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++, - pFDesc=pFDesc->next) - ; - if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams){ - pCustData->prgCustData = - TLB_Alloc(pFDesc->pParamDesc[indexParam].ctCustData * - sizeof(CUSTDATAITEM)); - if(pCustData->prgCustData ){ - pCustData->cCustData=pFDesc->pParamDesc[indexParam].ctCustData; - for(i=0, pCData=pFDesc->pParamDesc[indexParam].pCustData; - pCData; i++, pCData = pCData->next){ - pCustData->prgCustData[i].guid=pCData->guid; - VariantCopy(& pCustData->prgCustData[i].varValue, - & pCData->data); - } - }else{ - ERR(" OUT OF MEMORY! \n"); - return E_OUTOFMEMORY; - } - return S_OK; - } - return TYPE_E_ELEMENTNOTFOUND; -} - -/* ITypeInfo2::GetAllVarCustData - * - * Gets all custom data items for the specified Variable - * - */ -static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface, - UINT index, CUSTDATA *pCustData) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - TLBCustData *pCData; - TLBVarDesc * pVDesc; - int i; - TRACE("(%p) index %d\n", This, index); - for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, - pVDesc=pVDesc->next) - ; - if(pVDesc){ - pCustData->prgCustData = - TLB_Alloc(pVDesc->ctCustData * sizeof(CUSTDATAITEM)); - if(pCustData->prgCustData ){ - pCustData->cCustData=pVDesc->ctCustData; - for(i=0, pCData=pVDesc->pCustData; pCData; i++, - pCData = pCData->next){ - pCustData->prgCustData[i].guid=pCData->guid; - VariantCopy(& pCustData->prgCustData[i].varValue, - & pCData->data); - } - }else{ - ERR(" OUT OF MEMORY! \n"); - return E_OUTOFMEMORY; - } - return S_OK; - } - return TYPE_E_ELEMENTNOTFOUND; -} - -/* ITypeInfo2::GetAllImplCustData - * - * Gets all custom data items for the specified implementation type - * - */ -static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData( - ITypeInfo2 * iface, - UINT index, - CUSTDATA *pCustData) -{ - ITypeInfoImpl *This = (ITypeInfoImpl *)iface; - TLBCustData *pCData; - TLBImplType * pRDesc; - int i; - TRACE("(%p) index %d\n", This, index); - for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++, - pRDesc=pRDesc->next) - ; - if(pRDesc){ - pCustData->prgCustData = - TLB_Alloc(pRDesc->ctCustData * sizeof(CUSTDATAITEM)); - if(pCustData->prgCustData ){ - pCustData->cCustData=pRDesc->ctCustData; - for(i=0, pCData=pRDesc->pCustData; pCData; i++, - pCData = pCData->next){ - pCustData->prgCustData[i].guid=pCData->guid; - VariantCopy(& pCustData->prgCustData[i].varValue, - & pCData->data); - } - }else{ - ERR(" OUT OF MEMORY! \n"); - return E_OUTOFMEMORY; - } - return S_OK; - } - return TYPE_E_ELEMENTNOTFOUND; -} - -static ITypeInfo2Vtbl tinfvt = -{ - - ITypeInfo_fnQueryInterface, - ITypeInfo_fnAddRef, - ITypeInfo_fnRelease, - - ITypeInfo_fnGetTypeAttr, - ITypeInfo_fnGetTypeComp, - ITypeInfo_fnGetFuncDesc, - ITypeInfo_fnGetVarDesc, - ITypeInfo_fnGetNames, - ITypeInfo_fnGetRefTypeOfImplType, - ITypeInfo_fnGetImplTypeFlags, - ITypeInfo_fnGetIDsOfNames, - ITypeInfo_fnInvoke, - ITypeInfo_fnGetDocumentation, - ITypeInfo_fnGetDllEntry, - ITypeInfo_fnGetRefTypeInfo, - ITypeInfo_fnAddressOfMember, - ITypeInfo_fnCreateInstance, - ITypeInfo_fnGetMops, - ITypeInfo_fnGetContainingTypeLib, - ITypeInfo_fnReleaseTypeAttr, - ITypeInfo_fnReleaseFuncDesc, - ITypeInfo_fnReleaseVarDesc, - - ITypeInfo2_fnGetTypeKind, - ITypeInfo2_fnGetTypeFlags, - ITypeInfo2_fnGetFuncIndexOfMemId, - ITypeInfo2_fnGetVarIndexOfMemId, - ITypeInfo2_fnGetCustData, - ITypeInfo2_fnGetFuncCustData, - ITypeInfo2_fnGetParamCustData, - ITypeInfo2_fnGetVarCustData, - ITypeInfo2_fnGetImplTypeCustData, - ITypeInfo2_fnGetDocumentation2, - ITypeInfo2_fnGetAllCustData, - ITypeInfo2_fnGetAllFuncCustData, - ITypeInfo2_fnGetAllParamCustData, - ITypeInfo2_fnGetAllVarCustData, - ITypeInfo2_fnGetAllImplTypeCustData, -}; - -/****************************************************************************** - * CreateDispTypeInfo [OLEAUT32.31] - * - * Build type information for an object so it can be called through an - * IDispatch interface. - * - * RETURNS - * Success: S_OK. pptinfo contains the created ITypeInfo object. - * Failure: E_INVALIDARG, if one or more arguments is invalid. - * - * NOTES - * This call allows an objects methods to be accessed through IDispatch, by - * building an ITypeInfo object that IDispatch can use to call through. - */ -HRESULT WINAPI CreateDispTypeInfo( - INTERFACEDATA *pidata, /* [I] Description of the interface to build type info for */ - LCID lcid, /* [I] Locale Id */ - ITypeInfo **pptinfo) /* [O] Destination for created ITypeInfo object */ -{ - ITypeInfoImpl *pTIImpl; - int param, func; - TLBFuncDesc **ppFuncDesc; - - pTIImpl = (ITypeInfoImpl*)ITypeInfo_Constructor(); - pTIImpl->pTypeLib = NULL; - pTIImpl->index = 0; - pTIImpl->Name = NULL; - pTIImpl->dwHelpContext = -1; - memset(&pTIImpl->TypeAttr.guid, 0, sizeof(GUID)); - pTIImpl->TypeAttr.lcid = lcid; - pTIImpl->TypeAttr.typekind = TKIND_COCLASS; - pTIImpl->TypeAttr.wMajorVerNum = 0; - pTIImpl->TypeAttr.wMinorVerNum = 0; - pTIImpl->TypeAttr.cbAlignment = 2; - pTIImpl->TypeAttr.cbSizeInstance = -1; - pTIImpl->TypeAttr.cbSizeVft = -1; - pTIImpl->TypeAttr.cFuncs = 0; - pTIImpl->TypeAttr.cImplTypes = 1; - pTIImpl->TypeAttr.cVars = 0; - pTIImpl->TypeAttr.wTypeFlags = 0; - - ppFuncDesc = &pTIImpl->funclist; - for(func = 0; func < pidata->cMembers; func++) { - METHODDATA *md = pidata->pmethdata + func; - *ppFuncDesc = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppFuncDesc)); - (*ppFuncDesc)->Name = SysAllocString(md->szName); - (*ppFuncDesc)->funcdesc.memid = md->dispid; - (*ppFuncDesc)->funcdesc.invkind = md->wFlags; - (*ppFuncDesc)->funcdesc.callconv = md->cc; - (*ppFuncDesc)->funcdesc.cParams = md->cArgs; - (*ppFuncDesc)->funcdesc.cParamsOpt = 0; - (*ppFuncDesc)->funcdesc.oVft = md->iMeth; - (*ppFuncDesc)->funcdesc.wFuncFlags = 0; /*??*/ - (*ppFuncDesc)->funcdesc.elemdescFunc.tdesc.vt = md->vtReturn; - (*ppFuncDesc)->funcdesc.lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - md->cArgs * sizeof(ELEMDESC)); - (*ppFuncDesc)->pParamDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - md->cArgs * sizeof(TLBParDesc)); - for(param = 0; param < md->cArgs; param++) { - (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt; - (*ppFuncDesc)->pParamDesc[param].Name = SysAllocString(md->ppdata[param].szName); - } - ppFuncDesc = &(*ppFuncDesc)->next; - } - *pptinfo = (ITypeInfo*)pTIImpl; - return S_OK; - -} - -static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv) -{ - ICOM_THIS_From_ITypeComp(ITypeInfoImpl, iface); - - return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv); -} - -static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface) -{ - ICOM_THIS_From_ITypeComp(ITypeInfoImpl, iface); - - return ITypeInfo_AddRef((ITypeInfo *)This); -} - -static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface) -{ - ICOM_THIS_From_ITypeComp(ITypeInfoImpl, iface); - - return ITypeInfo_Release((ITypeInfo *)This); -} - -static HRESULT WINAPI ITypeComp_fnBind( - ITypeComp * iface, - OLECHAR * szName, - ULONG lHash, - WORD wFlags, - ITypeInfo ** ppTInfo, - DESCKIND * pDescKind, - BINDPTR * pBindPtr) -{ - ICOM_THIS_From_ITypeComp(ITypeInfoImpl, iface); - TLBFuncDesc * pFDesc; - TLBVarDesc * pVDesc; - - TRACE("(%s, %lx, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr); - - for(pFDesc = This->funclist; pFDesc; pFDesc = pFDesc->next) - if (pFDesc->funcdesc.invkind & wFlags) - if (!strcmpW(pFDesc->Name, szName)) { - break; - } - - if (pFDesc) - { - *pDescKind = DESCKIND_FUNCDESC; - pBindPtr->lpfuncdesc = &pFDesc->funcdesc; - *ppTInfo = (ITypeInfo *)&This->lpVtbl; - return S_OK; - } else { - if (!(wFlags & ~(INVOKE_PROPERTYGET))) - { - for(pVDesc = This->varlist; pVDesc; pVDesc = pVDesc->next) { - if (!strcmpW(pVDesc->Name, szName)) { - *pDescKind = DESCKIND_VARDESC; - pBindPtr->lpvardesc = &pVDesc->vardesc; - *ppTInfo = (ITypeInfo *)&This->lpVtbl; - return S_OK; - } - } - } - } - /* not found, look for it in inherited interfaces */ - if (This->TypeAttr.cImplTypes && - (This->TypeAttr.typekind == TKIND_INTERFACE || This->TypeAttr.typekind == TKIND_DISPATCH)) { - /* recursive search */ - ITypeInfo *pTInfo; - ITypeComp *pTComp; - HRESULT hr; - hr=ITypeInfo_GetRefTypeInfo((ITypeInfo *)&This->lpVtbl, This->impltypelist->hRef, &pTInfo); - if (SUCCEEDED(hr)) - { - hr = ITypeInfo_GetTypeComp(pTInfo,&pTComp); - ITypeInfo_Release(pTInfo); - } - if (SUCCEEDED(hr)) - { - hr = ITypeComp_Bind(pTComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr); - ITypeComp_Release(pTComp); - return hr; - } - WARN("Could not search inherited interface!\n"); - } - ERR("did not find member with name %s, flags 0x%x!\n", debugstr_w(szName), wFlags); - *pDescKind = DESCKIND_NONE; - pBindPtr->lpfuncdesc = NULL; - *ppTInfo = NULL; - return DISP_E_MEMBERNOTFOUND; -} - -static HRESULT WINAPI ITypeComp_fnBindType( - ITypeComp * iface, - OLECHAR * szName, - ULONG lHash, - ITypeInfo ** ppTInfo, - ITypeComp ** ppTComp) -{ - TRACE("(%s, %lx, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp); - - /* strange behaviour (does nothing) but like the - * original */ - - if (!ppTInfo || !ppTComp) - return E_POINTER; - - *ppTInfo = NULL; - *ppTComp = NULL; - - return S_OK; -} - -static ITypeCompVtbl tcompvt = -{ - - ITypeComp_fnQueryInterface, - ITypeComp_fnAddRef, - ITypeComp_fnRelease, - - ITypeComp_fnBind, - ITypeComp_fnBindType -}; +/* + * TYPELIB + * + * Copyright 1997 Marcus Meissner + * 1999 Rein Klazes + * 2000 Francois Jacques + * 2001 Huw D M Davies for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * -------------------------------------------------------------------------------------- + * Known problems (2000, Francois Jacques) + * + * - Tested using OLEVIEW (Platform SDK tool) only. + * + * - dual interface dispinterfaces. vtable-interface ITypeInfo instances are + * creating by doing a straight copy of the dispinterface instance and just changing + * its typekind. Pointed structures aren't copied - only the address of the pointers. + * So when you release the dispinterface, you delete the vtable-interface structures + * as well... fortunately, clean up of structures is not implemented. + * + * - locale stuff is partially implemented but hasn't been tested. + * + * - typelib file is still read in its entirety, but it is released now. + * - some garbage is read from function names on some very rare occasions. + * + * -------------------------------------------------------------------------------------- + * Known problems left from previous implementation (1999, Rein Klazes) : + * + * -. Data structures are straightforward, but slow for look-ups. + * -. (related) nothing is hashed + * -. there are a number of stubs in ITypeLib and ITypeInfo interfaces. Most + * of them I don't know yet how to implement them. + * -. Most error return values are just guessed not checked with windows + * behaviour. + * -. didn't bother with a c++ interface + * -. lousy fatal error handling + * -. some methods just return pointers to internal data structures, this is + * partly laziness, partly I want to check how windows does it. + * + */ + +#include "config.h" +#include "wine/port.h" + +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <stdio.h> +#include <ctype.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "winerror.h" +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winreg.h" +#include "winuser.h" + +#include "wine/unicode.h" +#include "objbase.h" +#include "typelib.h" +#include "wine/debug.h" +#include "variant.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); +WINE_DECLARE_DEBUG_CHANNEL(typelib); + +/* The OLE Automation ProxyStub Interface Class (aka Typelib Marshaler) */ +const GUID CLSID_PSOAInterface = { 0x00020424, 0, 0, { 0xC0, 0, 0, 0, 0, 0, 0, 0x46 } }; + +/**************************************************************************** + * FromLExxx + * + * Takes p_iVal (which is in little endian) and returns it + * in the host machine's byte order. + */ +#ifdef WORDS_BIGENDIAN +static WORD FromLEWord(WORD p_iVal) +{ + return (((p_iVal & 0x00FF) << 8) | + ((p_iVal & 0xFF00) >> 8)); +} + + +static DWORD FromLEDWord(DWORD p_iVal) +{ + return (((p_iVal & 0x000000FF) << 24) | + ((p_iVal & 0x0000FF00) << 8) | + ((p_iVal & 0x00FF0000) >> 8) | + ((p_iVal & 0xFF000000) >> 24)); +} +#else +#define FromLEWord(X) (X) +#define FromLEDWord(X) (X) +#endif + + +/**************************************************************************** + * FromLExxx + * + * Fix byte order in any structure if necessary + */ +#ifdef WORDS_BIGENDIAN +static void FromLEWords(void *p_Val, int p_iSize) +{ + WORD *Val = p_Val; + + p_iSize /= sizeof(WORD); + + while (p_iSize) { + *Val = FromLEWord(*Val); + Val++; + p_iSize--; + } +} + + +static void FromLEDWords(void *p_Val, int p_iSize) +{ + DWORD *Val = p_Val; + + p_iSize /= sizeof(DWORD); + + while (p_iSize) { + *Val = FromLEDWord(*Val); + Val++; + p_iSize--; + } +} +#else +#define FromLEWords(X,Y) /*nothing*/ +#define FromLEDWords(X,Y) /*nothing*/ +#endif + +/* get the path of a typelib key, in the form "Typelib\\<guid>\\<maj>.<min>" */ +/* buffer must be at least 60 characters long */ +static WCHAR *get_typelib_key( REFGUID guid, WORD wMaj, WORD wMin, WCHAR *buffer ) +{ + static const WCHAR TypelibW[] = {'T','y','p','e','l','i','b','\\',0}; + static const WCHAR VersionFormatW[] = {'\\','%','u','.','%','u',0}; + + memcpy( buffer, TypelibW, sizeof(TypelibW) ); + StringFromGUID2( guid, buffer + strlenW(buffer), 40 ); + sprintfW( buffer + strlenW(buffer), VersionFormatW, wMaj, wMin ); + return buffer; +} + +/* get the path of an interface key, in the form "Interface\\<guid>" */ +/* buffer must be at least 50 characters long */ +static WCHAR *get_interface_key( REFGUID guid, WCHAR *buffer ) +{ + static const WCHAR InterfaceW[] = {'I','n','t','e','r','f','a','c','e','\\',0}; + + memcpy( buffer, InterfaceW, sizeof(InterfaceW) ); + StringFromGUID2( guid, buffer + strlenW(buffer), 40 ); + return buffer; +} + +/* get the lcid subkey for a typelib, in the form "<lcid>\\<syskind>" */ +/* buffer must be at least 16 characters long */ +static WCHAR *get_lcid_subkey( LCID lcid, SYSKIND syskind, WCHAR *buffer ) +{ + static const WCHAR LcidFormatW[] = {'%','l','x','\\',0}; + static const WCHAR win16W[] = {'w','i','n','1','6',0}; + static const WCHAR win32W[] = {'w','i','n','3','2',0}; + + sprintfW( buffer, LcidFormatW, lcid ); + switch(syskind) + { + case SYS_WIN16: strcatW( buffer, win16W ); break; + case SYS_WIN32: strcatW( buffer, win32W ); break; + default: + TRACE("Typelib is for unsupported syskind %i\n", syskind); + return NULL; + } + return buffer; +} + + +/**************************************************************************** + * QueryPathOfRegTypeLib [OLEAUT32.164] + * RETURNS + * path of typelib + */ +HRESULT WINAPI +QueryPathOfRegTypeLib( + REFGUID guid, /* [in] referenced guid */ + WORD wMaj, /* [in] major version */ + WORD wMin, /* [in] minor version */ + LCID lcid, /* [in] locale id */ + LPBSTR path ) /* [out] path of typelib */ +{ + HRESULT hr = E_FAIL; + LCID myLCID = lcid; + HKEY hkey; + WCHAR buffer[60]; + WCHAR Path[MAX_PATH]; + + if ( !HIWORD(guid) ) + { + FIXME("(guid %p,%d,%d,0x%04lx,%p),stub!\n", guid, wMaj, wMin, lcid, path); + return E_FAIL; + } + + get_typelib_key( guid, wMaj, wMin, buffer ); + + if (RegOpenKeyW( HKEY_CLASSES_ROOT, buffer, &hkey ) != ERROR_SUCCESS) + { + TRACE_(typelib)("%s not found\n", debugstr_w(buffer)); + return E_FAIL; + } + + while (hr != S_OK) + { + DWORD dwPathLen = sizeof(Path); + + get_lcid_subkey( myLCID, SYS_WIN32, buffer ); + + if (RegQueryValueW(hkey, buffer, Path, &dwPathLen)) + { + if (!lcid) + break; + else if (myLCID == lcid) + { + /* try with sub-langid */ + myLCID = SUBLANGID(lcid); + } + else if ((myLCID == SUBLANGID(lcid)) && myLCID) + { + /* try with system langid */ + myLCID = 0; + } + else + { + break; + } + } + else + { + *path = SysAllocString( Path ); + hr = S_OK; + } + } + RegCloseKey( hkey ); + return hr; +} + +/****************************************************************************** + * CreateTypeLib [OLEAUT32.160] creates a typelib + * + * RETURNS + * Success: S_OK + * Failure: Status + */ +HRESULT WINAPI CreateTypeLib( + SYSKIND syskind, LPCOLESTR szFile, ICreateTypeLib** ppctlib +) { + FIXME("(%d,%s,%p), stub!\n",syskind,debugstr_w(szFile),ppctlib); + return E_FAIL; +} +/****************************************************************************** + * LoadTypeLib [OLEAUT32.161] + * Loads and registers a type library + * NOTES + * Docs: OLECHAR FAR* szFile + * Docs: iTypeLib FAR* FAR* pptLib + * + * RETURNS + * Success: S_OK + * Failure: Status + */ +int TLB_ReadTypeLib(LPCWSTR file, INT index, ITypeLib2 **ppTypelib); + +HRESULT WINAPI LoadTypeLib( + const OLECHAR *szFile,/* [in] Name of file to load from */ + ITypeLib * *pptLib) /* [out] Pointer to pointer to loaded type library */ +{ + TRACE("(%s,%p)\n",debugstr_w(szFile), pptLib); + return LoadTypeLibEx(szFile, REGKIND_DEFAULT, pptLib); +} + +/****************************************************************************** + * LoadTypeLibEx [OLEAUT32.183] + * Loads and optionally registers a type library + * + * RETURNS + * Success: S_OK + * Failure: Status + */ +HRESULT WINAPI LoadTypeLibEx( + LPCOLESTR szFile, /* [in] Name of file to load from */ + REGKIND regkind, /* [in] Specify kind of registration */ + ITypeLib **pptLib) /* [out] Pointer to pointer to loaded type library */ +{ + WCHAR szPath[MAX_PATH+1], szFileCopy[MAX_PATH+1]; + WCHAR *pIndexStr; + HRESULT res; + INT index = 1; + + TRACE("(%s,%d,%p)\n",debugstr_w(szFile), regkind, pptLib); + + /* by default try and load using LoadLibrary (for builtin stdole32.tlb) */ + memcpy(szPath, szFile, (strlenW(szFile)+1)*sizeof(WCHAR)); + + *pptLib = NULL; + if(!SearchPathW(NULL,szFile,NULL,sizeof(szPath)/sizeof(WCHAR),szPath, + NULL)) { + + /* Look for a trailing '\\' followed by an index */ + pIndexStr = strrchrW(szFile, '\\'); + if(pIndexStr && pIndexStr != szFile && *++pIndexStr != '\0') { + index = atoiW(pIndexStr); + memcpy(szFileCopy, szFile, + (pIndexStr - szFile - 1) * sizeof(WCHAR)); + szFileCopy[pIndexStr - szFile - 1] = '\0'; + if(!SearchPathW(NULL,szFileCopy,NULL,sizeof(szPath)/sizeof(WCHAR), + szPath,NULL)) + return TYPE_E_CANTLOADLIBRARY; + if (GetFileAttributesW(szFileCopy) & FILE_ATTRIBUTE_DIRECTORY) + return TYPE_E_CANTLOADLIBRARY; + } + } + + TRACE("File %s index %d\n", debugstr_w(szPath), index); + + res = TLB_ReadTypeLib(szPath, index, (ITypeLib2**)pptLib); + + if (SUCCEEDED(res)) + switch(regkind) + { + case REGKIND_DEFAULT: + /* don't register typelibs supplied with full path. Experimentation confirms the following */ + if ((!szFile) || + ((szFile[0] == '\\') && (szFile[1] == '\\')) || + (szFile[0] && (szFile[1] == ':'))) break; + /* else fall-through */ + + case REGKIND_REGISTER: + if (!SUCCEEDED(res = RegisterTypeLib(*pptLib, (LPOLESTR)szPath, NULL))) + { + IUnknown_Release(*pptLib); + *pptLib = 0; + } + break; + case REGKIND_NONE: + break; + } + + TRACE(" returns %08lx\n",res); + return res; +} + +/****************************************************************************** + * LoadRegTypeLib [OLEAUT32.162] + */ +HRESULT WINAPI LoadRegTypeLib( + REFGUID rguid, /* [in] referenced guid */ + WORD wVerMajor, /* [in] major version */ + WORD wVerMinor, /* [in] minor version */ + LCID lcid, /* [in] locale id */ + ITypeLib **ppTLib) /* [out] path of typelib */ +{ + BSTR bstr=NULL; + HRESULT res=QueryPathOfRegTypeLib( rguid, wVerMajor, wVerMinor, lcid, &bstr); + + if(SUCCEEDED(res)) + { + res= LoadTypeLib(bstr, ppTLib); + SysFreeString(bstr); + } + + TRACE("(IID: %s) load %s (%p)\n",debugstr_guid(rguid), SUCCEEDED(res)? "SUCCESS":"FAILED", *ppTLib); + + return res; +} + + +/* some string constants shared between RegisterTypeLib and UnRegisterTypeLib */ +static const WCHAR TypeLibW[] = {'T','y','p','e','L','i','b',0}; +static const WCHAR FLAGSW[] = {'F','L','A','G','S',0}; +static const WCHAR HELPDIRW[] = {'H','E','L','P','D','I','R',0}; +static const WCHAR ProxyStubClsidW[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d',0}; +static const WCHAR ProxyStubClsid32W[] = {'P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0}; + +/****************************************************************************** + * RegisterTypeLib [OLEAUT32.163] + * Adds information about a type library to the System Registry + * NOTES + * Docs: ITypeLib FAR * ptlib + * Docs: OLECHAR FAR* szFullPath + * Docs: OLECHAR FAR* szHelpDir + * + * RETURNS + * Success: S_OK + * Failure: Status + */ +HRESULT WINAPI RegisterTypeLib( + ITypeLib * ptlib, /* [in] Pointer to the library*/ + OLECHAR * szFullPath, /* [in] full Path of the library*/ + OLECHAR * szHelpDir) /* [in] dir to the helpfile for the library, + may be NULL*/ +{ + static const WCHAR PSOA[] = {'{','0','0','0','2','0','4','2','4','-', + '0','0','0','0','-','0','0','0','0','-','C','0','0','0','-', + '0','0','0','0','0','0','0','0','0','0','4','6','}',0}; + HRESULT res; + TLIBATTR *attr; + WCHAR keyName[60]; + WCHAR tmp[16]; + HKEY key, subKey; + UINT types, tidx; + TYPEKIND kind; + DWORD disposition; + + if (ptlib == NULL || szFullPath == NULL) + return E_INVALIDARG; + + if (!SUCCEEDED(ITypeLib_GetLibAttr(ptlib, &attr))) + return E_FAIL; + + get_typelib_key( &attr->guid, attr->wMajorVerNum, attr->wMinorVerNum, keyName ); + + res = S_OK; + if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0, + KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS) + { + LPOLESTR doc; + + /* Set the human-readable name of the typelib */ + if (SUCCEEDED(ITypeLib_GetDocumentation(ptlib, -1, NULL, &doc, NULL, NULL))) + { + if (RegSetValueExW(key, NULL, 0, REG_SZ, + (BYTE *)doc, (lstrlenW(doc)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS) + res = E_FAIL; + + SysFreeString(doc); + } + else + res = E_FAIL; + + /* Make up the name of the typelib path subkey */ + if (!get_lcid_subkey( attr->lcid, attr->syskind, tmp )) res = E_FAIL; + + /* Create the typelib path subkey */ + if (res == S_OK && RegCreateKeyExW(key, tmp, 0, NULL, 0, + KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) + { + if (RegSetValueExW(subKey, NULL, 0, REG_SZ, + (BYTE *)szFullPath, (lstrlenW(szFullPath)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS) + res = E_FAIL; + + RegCloseKey(subKey); + } + else + res = E_FAIL; + + /* Create the flags subkey */ + if (res == S_OK && RegCreateKeyExW(key, FLAGSW, 0, NULL, 0, + KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) + { + /* FIXME: is %u correct? */ + static const WCHAR formatW[] = {'%','u',0}; + WCHAR buf[20]; + sprintfW(buf, formatW, attr->wLibFlags); + if (RegSetValueExW(subKey, NULL, 0, REG_SZ, + (BYTE *)buf, (strlenW(buf) + 1)*sizeof(WCHAR) ) != ERROR_SUCCESS) + res = E_FAIL; + + RegCloseKey(subKey); + } + else + res = E_FAIL; + + /* create the helpdir subkey */ + if (res == S_OK && RegCreateKeyExW(key, HELPDIRW, 0, NULL, 0, + KEY_WRITE, NULL, &subKey, &disposition) == ERROR_SUCCESS) + { + BOOL freeHelpDir = FALSE; + OLECHAR* pIndexStr; + + /* if we created a new key, and helpDir was null, set the helpdir + to the directory which contains the typelib. However, + if we just opened an existing key, we leave the helpdir alone */ + if ((disposition == REG_CREATED_NEW_KEY) && (szHelpDir == NULL)) { + szHelpDir = SysAllocString(szFullPath); + pIndexStr = strrchrW(szHelpDir, '\\'); + if (pIndexStr) { + *pIndexStr = 0; + } + freeHelpDir = TRUE; + } + + /* if we have an szHelpDir, set it! */ + if (szHelpDir != NULL) { + if (RegSetValueExW(subKey, NULL, 0, REG_SZ, + (BYTE *)szHelpDir, (lstrlenW(szHelpDir)+1) * sizeof(OLECHAR)) != ERROR_SUCCESS) { + res = E_FAIL; + } + } + + /* tidy up */ + if (freeHelpDir) SysFreeString(szHelpDir); + RegCloseKey(subKey); + + } else { + res = E_FAIL; + } + + RegCloseKey(key); + } + else + res = E_FAIL; + + /* register OLE Automation-compatible interfaces for this typelib */ + types = ITypeLib_GetTypeInfoCount(ptlib); + for (tidx=0; tidx<types; tidx++) { + if (SUCCEEDED(ITypeLib_GetTypeInfoType(ptlib, tidx, &kind))) { + LPOLESTR name = NULL; + ITypeInfo *tinfo = NULL; + + ITypeLib_GetDocumentation(ptlib, tidx, &name, NULL, NULL, NULL); + + switch (kind) { + case TKIND_INTERFACE: + TRACE_(typelib)("%d: interface %s\n", tidx, debugstr_w(name)); + ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo); + break; + + case TKIND_DISPATCH: + TRACE_(typelib)("%d: dispinterface %s\n", tidx, debugstr_w(name)); + ITypeLib_GetTypeInfo(ptlib, tidx, &tinfo); + break; + + default: + TRACE_(typelib)("%d: %s\n", tidx, debugstr_w(name)); + break; + } + + if (tinfo) { + TYPEATTR *tattr = NULL; + ITypeInfo_GetTypeAttr(tinfo, &tattr); + + if (tattr) { + TRACE_(typelib)("guid=%s, flags=%04x (", + debugstr_guid(&tattr->guid), + tattr->wTypeFlags); + + if (TRACE_ON(typelib)) { +#define XX(x) if (TYPEFLAG_##x & tattr->wTypeFlags) MESSAGE(#x"|"); + XX(FAPPOBJECT); + XX(FCANCREATE); + XX(FLICENSED); + XX(FPREDECLID); + XX(FHIDDEN); + XX(FCONTROL); + XX(FDUAL); + XX(FNONEXTENSIBLE); + XX(FOLEAUTOMATION); + XX(FRESTRICTED); + XX(FAGGREGATABLE); + XX(FREPLACEABLE); + XX(FDISPATCHABLE); + XX(FREVERSEBIND); + XX(FPROXY); +#undef XX + MESSAGE("\n"); + } + + /* + * FIXME: The 1 is just here until we implement rpcrt4 + * stub/proxy handling. Until then it helps IShield + * v6 to work. + */ + if (1 || (tattr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)) + { + if (!(tattr->wTypeFlags & TYPEFLAG_FOLEAUTOMATION)) { + FIXME("Registering non-oleautomation interface!\n"); + } + + /* register interface<->typelib coupling */ + get_interface_key( &tattr->guid, keyName ); + if (RegCreateKeyExW(HKEY_CLASSES_ROOT, keyName, 0, NULL, 0, + KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS) + { + if (name) + RegSetValueExW(key, NULL, 0, REG_SZ, + (BYTE *)name, (strlenW(name)+1) * sizeof(OLECHAR)); + + if (RegCreateKeyExW(key, ProxyStubClsidW, 0, NULL, 0, + KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) { + RegSetValueExW(subKey, NULL, 0, REG_SZ, + (BYTE*)PSOA, sizeof PSOA); + RegCloseKey(subKey); + } + + if (RegCreateKeyExW(key, ProxyStubClsid32W, 0, NULL, 0, + KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) { + RegSetValueExW(subKey, NULL, 0, REG_SZ, + (BYTE*)PSOA, sizeof PSOA); + RegCloseKey(subKey); + } + + if (RegCreateKeyExW(key, TypeLibW, 0, NULL, 0, + KEY_WRITE, NULL, &subKey, NULL) == ERROR_SUCCESS) + { + WCHAR buffer[40]; + static const WCHAR fmtver[] = {'%','u','.','%','u',0 }; + static const WCHAR VersionW[] = {'V','e','r','s','i','o','n',0}; + + StringFromGUID2(&attr->guid, buffer, 40); + RegSetValueExW(subKey, NULL, 0, REG_SZ, + (BYTE *)buffer, (strlenW(buffer)+1) * sizeof(WCHAR)); + sprintfW(buffer, fmtver, attr->wMajorVerNum, attr->wMinorVerNum); + RegSetValueExW(subKey, VersionW, 0, REG_SZ, + (BYTE*)buffer, (strlenW(buffer)+1) * sizeof(WCHAR)); + RegCloseKey(subKey); + } + + RegCloseKey(key); + } + } + + ITypeInfo_ReleaseTypeAttr(tinfo, tattr); + } + + ITypeInfo_Release(tinfo); + } + + SysFreeString(name); + } + } + + ITypeLib_ReleaseTLibAttr(ptlib, attr); + + return res; +} + + +/****************************************************************************** + * UnRegisterTypeLib [OLEAUT32.186] + * Removes information about a type library from the System Registry + * NOTES + * + * RETURNS + * Success: S_OK + * Failure: Status + */ +HRESULT WINAPI UnRegisterTypeLib( + REFGUID libid, /* [in] Guid of the library */ + WORD wVerMajor, /* [in] major version */ + WORD wVerMinor, /* [in] minor version */ + LCID lcid, /* [in] locale id */ + SYSKIND syskind) +{ + BSTR tlibPath = NULL; + DWORD tmpLength; + WCHAR keyName[60]; + WCHAR subKeyName[50]; + int result = S_OK; + DWORD i = 0; + BOOL deleteOtherStuff; + HKEY key = NULL; + HKEY subKey = NULL; + TYPEATTR* typeAttr = NULL; + TYPEKIND kind; + ITypeInfo* typeInfo = NULL; + ITypeLib* typeLib = NULL; + int numTypes; + + TRACE("(IID: %s): stub\n",debugstr_guid(libid)); + + /* Create the path to the key */ + get_typelib_key( libid, wVerMajor, wVerMinor, keyName ); + + if (syskind != SYS_WIN16 && syskind != SYS_WIN32) + { + TRACE("Unsupported syskind %i\n", syskind); + result = E_INVALIDARG; + goto end; + } + + /* get the path to the typelib on disk */ + if (QueryPathOfRegTypeLib(libid, wVerMajor, wVerMinor, lcid, &tlibPath) != S_OK) { + result = E_INVALIDARG; + goto end; + } + + /* Try and open the key to the type library. */ + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, keyName, 0, KEY_READ | KEY_WRITE, &key) != S_OK) { + result = E_INVALIDARG; + goto end; + } + + /* Try and load the type library */ + if (LoadTypeLibEx(tlibPath, REGKIND_NONE, &typeLib)) { + result = TYPE_E_INVALIDSTATE; + goto end; + } + + /* remove any types registered with this typelib */ + numTypes = ITypeLib_GetTypeInfoCount(typeLib); + for (i=0; i<numTypes; i++) { + /* get the kind of type */ + if (ITypeLib_GetTypeInfoType(typeLib, i, &kind) != S_OK) { + goto enddeleteloop; + } + + /* skip non-interfaces, and get type info for the type */ + if ((kind != TKIND_INTERFACE) && (kind != TKIND_DISPATCH)) { + goto enddeleteloop; + } + if (ITypeLib_GetTypeInfo(typeLib, i, &typeInfo) != S_OK) { + goto enddeleteloop; + } + if (ITypeInfo_GetTypeAttr(typeInfo, &typeAttr) != S_OK) { + goto enddeleteloop; + } + + /* the path to the type */ + get_interface_key( &typeAttr->guid, subKeyName ); + + /* Delete its bits */ + if (RegOpenKeyExW(HKEY_CLASSES_ROOT, subKeyName, 0, KEY_WRITE, &subKey) != S_OK) { + goto enddeleteloop; + } + RegDeleteKeyW(subKey, ProxyStubClsidW); + RegDeleteKeyW(subKey, ProxyStubClsid32W); + RegDeleteKeyW(subKey, TypeLibW); + RegCloseKey(subKey); + subKey = NULL; + RegDeleteKeyW(HKEY_CLASSES_ROOT, subKeyName); + +enddeleteloop: + if (typeAttr) ITypeInfo_ReleaseTypeAttr(typeInfo, typeAttr); + typeAttr = NULL; + if (typeInfo) ITypeInfo_Release(typeInfo); + typeInfo = NULL; + } + + /* Now, delete the type library path subkey */ + get_lcid_subkey( lcid, syskind, subKeyName ); + RegDeleteKeyW(key, subKeyName); + *strrchrW( subKeyName, '\\' ) = 0; /* remove last path component */ + RegDeleteKeyW(key, subKeyName); + + /* check if there is anything besides the FLAGS/HELPDIR keys. + If there is, we don't delete them */ + tmpLength = sizeof(subKeyName)/sizeof(WCHAR); + deleteOtherStuff = TRUE; + i = 0; + while(RegEnumKeyExW(key, i++, subKeyName, &tmpLength, NULL, NULL, NULL, NULL) == S_OK) { + tmpLength = sizeof(subKeyName)/sizeof(WCHAR); + + /* if its not FLAGS or HELPDIR, then we must keep the rest of the key */ + if (!strcmpW(subKeyName, FLAGSW)) continue; + if (!strcmpW(subKeyName, HELPDIRW)) continue; + deleteOtherStuff = FALSE; + break; + } + + /* only delete the other parts of the key if we're absolutely sure */ + if (deleteOtherStuff) { + RegDeleteKeyW(key, FLAGSW); + RegDeleteKeyW(key, HELPDIRW); + RegCloseKey(key); + key = NULL; + + RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName); + *strrchrW( keyName, '\\' ) = 0; /* remove last path component */ + RegDeleteKeyW(HKEY_CLASSES_ROOT, keyName); + } + +end: + if (tlibPath) SysFreeString(tlibPath); + if (typeLib) ITypeLib_Release(typeLib); + if (subKey) RegCloseKey(subKey); + if (key) RegCloseKey(key); + return result; +} + +/*======================= ITypeLib implementation =======================*/ + +typedef struct tagTLBCustData +{ + GUID guid; + VARIANT data; + struct tagTLBCustData* next; +} TLBCustData; + +/* data structure for import typelibs */ +typedef struct tagTLBImpLib +{ + int offset; /* offset in the file (MSFT) + offset in nametable (SLTG) + just used to identify library while reading + data from file */ + GUID guid; /* libid */ + BSTR name; /* name */ + + LCID lcid; /* lcid of imported typelib */ + + WORD wVersionMajor; /* major version number */ + WORD wVersionMinor; /* minor version number */ + + struct tagITypeLibImpl *pImpTypeLib; /* pointer to loaded typelib, or + NULL if not yet loaded */ + struct tagTLBImpLib * next; +} TLBImpLib; + +/* internal ITypeLib data */ +typedef struct tagITypeLibImpl +{ + ITypeLib2Vtbl *lpVtbl; + ITypeCompVtbl *lpVtblTypeComp; + ULONG ref; + TLIBATTR LibAttr; /* guid,lcid,syskind,version,flags */ + + /* strings can be stored in tlb as multibyte strings BUT they are *always* + * exported to the application as a UNICODE string. + */ + BSTR Name; + BSTR DocString; + BSTR HelpFile; + BSTR HelpStringDll; + unsigned long dwHelpContext; + int TypeInfoCount; /* nr of typeinfo's in librarry */ + struct tagITypeInfoImpl *pTypeInfo; /* linked list of type info data */ + int ctCustData; /* number of items in cust data list */ + TLBCustData * pCustData; /* linked list to cust data */ + TLBImpLib * pImpLibs; /* linked list to all imported typelibs */ + TYPEDESC * pTypeDesc; /* array of TypeDescriptions found in the + libary. Only used while read MSFT + typelibs */ + + /* typelibs are cached, keyed by path and index, so store the linked list info within them */ + struct tagITypeLibImpl *next, *prev; + WCHAR *path; + INT index; +} ITypeLibImpl; + +static struct ITypeLib2Vtbl tlbvt; +static struct ITypeCompVtbl tlbtcvt; + +#define _ITypeComp_Offset(impl) ((int)(&(((impl*)0)->lpVtblTypeComp))) +#define ICOM_THIS_From_ITypeComp(impl, iface) impl* This = (impl*)(((char*)iface)-_ITypeComp_Offset(impl)) + +/* ITypeLib methods */ +static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength); +static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength); + +/*======================= ITypeInfo implementation =======================*/ + +/* data for referenced types */ +typedef struct tagTLBRefType +{ + INT index; /* Type index for internal ref or for external ref + it the format is SLTG. -2 indicates to + use guid */ + + GUID guid; /* guid of the referenced type */ + /* if index == TLB_REF_USE_GUID */ + + HREFTYPE reference; /* The href of this ref */ + TLBImpLib *pImpTLInfo; /* If ref is external ptr to library data + TLB_REF_INTERNAL for internal refs + TLB_REF_NOT_FOUND for broken refs */ + + struct tagTLBRefType * next; +} TLBRefType; + +#define TLB_REF_USE_GUID -2 + +#define TLB_REF_INTERNAL (void*)-2 +#define TLB_REF_NOT_FOUND (void*)-1 + +/* internal Parameter data */ +typedef struct tagTLBParDesc +{ + BSTR Name; + int ctCustData; + TLBCustData * pCustData; /* linked list to cust data */ +} TLBParDesc; + +/* internal Function data */ +typedef struct tagTLBFuncDesc +{ + FUNCDESC funcdesc; /* lots of info on the function and its attributes. */ + BSTR Name; /* the name of this function */ + TLBParDesc *pParamDesc; /* array with param names and custom data */ + int helpcontext; + int HelpStringContext; + BSTR HelpString; + BSTR Entry; /* if its Hiword==0, it numeric; -1 is not present*/ + int ctCustData; + TLBCustData * pCustData; /* linked list to cust data; */ + struct tagTLBFuncDesc * next; +} TLBFuncDesc; + +/* internal Variable data */ +typedef struct tagTLBVarDesc +{ + VARDESC vardesc; /* lots of info on the variable and its attributes. */ + BSTR Name; /* the name of this variable */ + int HelpContext; + int HelpStringContext; /* FIXME: where? */ + BSTR HelpString; + int ctCustData; + TLBCustData * pCustData;/* linked list to cust data; */ + struct tagTLBVarDesc * next; +} TLBVarDesc; + +/* internal implemented interface data */ +typedef struct tagTLBImplType +{ + HREFTYPE hRef; /* hRef of interface */ + int implflags; /* IMPLFLAG_*s */ + int ctCustData; + TLBCustData * pCustData;/* linked list to custom data; */ + struct tagTLBImplType *next; +} TLBImplType; + +/* internal TypeInfo data */ +typedef struct tagITypeInfoImpl +{ + ITypeInfo2Vtbl *lpVtbl; + ITypeCompVtbl *lpVtblTypeComp; + ULONG ref; + TYPEATTR TypeAttr ; /* _lots_ of type information. */ + ITypeLibImpl * pTypeLib; /* back pointer to typelib */ + int index; /* index in this typelib; */ + /* type libs seem to store the doc strings in ascii + * so why should we do it in unicode? + */ + BSTR Name; + BSTR DocString; + unsigned long dwHelpContext; + unsigned long dwHelpStringContext; + + /* functions */ + TLBFuncDesc * funclist; /* linked list with function descriptions */ + + /* variables */ + TLBVarDesc * varlist; /* linked list with variable descriptions */ + + /* Implemented Interfaces */ + TLBImplType * impltypelist; + + TLBRefType * reflist; + int ctCustData; + TLBCustData * pCustData; /* linked list to cust data; */ + struct tagITypeInfoImpl * next; +} ITypeInfoImpl; + +static struct ITypeInfo2Vtbl tinfvt; +static struct ITypeCompVtbl tcompvt; + +static ITypeInfo2 * WINAPI ITypeInfo_Constructor(void); + +typedef struct tagTLBContext +{ + unsigned int oStart; /* start of TLB in file */ + unsigned int pos; /* current pos */ + unsigned int length; /* total length */ + void *mapping; /* memory mapping */ + MSFT_SegDir * pTblDir; + ITypeLibImpl* pLibInfo; +} TLBContext; + + +static void MSFT_DoRefType(TLBContext *pcx, ITypeInfoImpl *pTI, int offset); + +/* + debug +*/ +static void dump_TypeDesc(TYPEDESC *pTD,char *szVarType) { + if (pTD->vt & VT_RESERVED) + szVarType += strlen(strcpy(szVarType, "reserved | ")); + if (pTD->vt & VT_BYREF) + szVarType += strlen(strcpy(szVarType, "ref to ")); + if (pTD->vt & VT_ARRAY) + szVarType += strlen(strcpy(szVarType, "array of ")); + if (pTD->vt & VT_VECTOR) + szVarType += strlen(strcpy(szVarType, "vector of ")); + switch(pTD->vt & VT_TYPEMASK) { + case VT_UI1: sprintf(szVarType, "VT_UI1"); break; + case VT_I2: sprintf(szVarType, "VT_I2"); break; + case VT_I4: sprintf(szVarType, "VT_I4"); break; + case VT_R4: sprintf(szVarType, "VT_R4"); break; + case VT_R8: sprintf(szVarType, "VT_R8"); break; + case VT_BOOL: sprintf(szVarType, "VT_BOOL"); break; + case VT_ERROR: sprintf(szVarType, "VT_ERROR"); break; + case VT_CY: sprintf(szVarType, "VT_CY"); break; + case VT_DATE: sprintf(szVarType, "VT_DATE"); break; + case VT_BSTR: sprintf(szVarType, "VT_BSTR"); break; + case VT_UNKNOWN: sprintf(szVarType, "VT_UNKNOWN"); break; + case VT_DISPATCH: sprintf(szVarType, "VT_DISPATCH"); break; + case VT_I1: sprintf(szVarType, "VT_I1"); break; + case VT_UI2: sprintf(szVarType, "VT_UI2"); break; + case VT_UI4: sprintf(szVarType, "VT_UI4"); break; + case VT_INT: sprintf(szVarType, "VT_INT"); break; + case VT_UINT: sprintf(szVarType, "VT_UINT"); break; + case VT_VARIANT: sprintf(szVarType, "VT_VARIANT"); break; + case VT_VOID: sprintf(szVarType, "VT_VOID"); break; + case VT_HRESULT: sprintf(szVarType, "VT_HRESULT"); break; + case VT_USERDEFINED: sprintf(szVarType, "VT_USERDEFINED ref = %lx", + pTD->u.hreftype); break; + case VT_PTR: sprintf(szVarType, "ptr to "); + dump_TypeDesc(pTD->u.lptdesc, szVarType + 7); + break; + case VT_SAFEARRAY: sprintf(szVarType, "safearray of "); + dump_TypeDesc(pTD->u.lptdesc, szVarType + 13); + break; + case VT_CARRAY: sprintf(szVarType, "%d dim array of ", + pTD->u.lpadesc->cDims); /* FIXME print out sizes */ + dump_TypeDesc(&pTD->u.lpadesc->tdescElem, szVarType + strlen(szVarType)); + break; + + default: sprintf(szVarType, "unknown(%d)", pTD->vt & VT_TYPEMASK); break; + } +} + +void dump_ELEMDESC(ELEMDESC *edesc) { + char buf[200]; + dump_TypeDesc(&edesc->tdesc,buf); + MESSAGE("\t\ttdesc.vartype %d (%s)\n",edesc->tdesc.vt,buf); + MESSAGE("\t\tu.parmadesc.flags %x\n",edesc->u.paramdesc.wParamFlags); + MESSAGE("\t\tu.parmadesc.lpex %p\n",edesc->u.paramdesc.pparamdescex); +} +void dump_FUNCDESC(FUNCDESC *funcdesc) { + int i; + MESSAGE("memid is %08lx\n",funcdesc->memid); + for (i=0;i<funcdesc->cParams;i++) { + MESSAGE("Param %d:\n",i); + dump_ELEMDESC(funcdesc->lprgelemdescParam+i); + } + MESSAGE("\tfunckind: %d (",funcdesc->funckind); + switch (funcdesc->funckind) { + case FUNC_VIRTUAL: MESSAGE("virtual");break; + case FUNC_PUREVIRTUAL: MESSAGE("pure virtual");break; + case FUNC_NONVIRTUAL: MESSAGE("nonvirtual");break; + case FUNC_STATIC: MESSAGE("static");break; + case FUNC_DISPATCH: MESSAGE("dispatch");break; + default: MESSAGE("unknown");break; + } + MESSAGE(")\n\tinvkind: %d (",funcdesc->invkind); + switch (funcdesc->invkind) { + case INVOKE_FUNC: MESSAGE("func");break; + case INVOKE_PROPERTYGET: MESSAGE("property get");break; + case INVOKE_PROPERTYPUT: MESSAGE("property put");break; + case INVOKE_PROPERTYPUTREF: MESSAGE("property put ref");break; + } + MESSAGE(")\n\tcallconv: %d (",funcdesc->callconv); + switch (funcdesc->callconv) { + case CC_CDECL: MESSAGE("cdecl");break; + case CC_PASCAL: MESSAGE("pascal");break; + case CC_STDCALL: MESSAGE("stdcall");break; + case CC_SYSCALL: MESSAGE("syscall");break; + default:break; + } + MESSAGE(")\n\toVft: %d\n", funcdesc->oVft); + MESSAGE("\tcParamsOpt: %d\n", funcdesc->cParamsOpt); + MESSAGE("\twFlags: %x\n", funcdesc->wFuncFlags); + + MESSAGE("\telemdescFunc (return value type):\n"); + dump_ELEMDESC(&funcdesc->elemdescFunc); +} + +void dump_IDLDESC(IDLDESC *idl) { + MESSAGE("\t\twIdlflags: %d\n",idl->wIDLFlags); +} + +static const char * typekind_desc[] = +{ + "TKIND_ENUM", + "TKIND_RECORD", + "TKIND_MODULE", + "TKIND_INTERFACE", + "TKIND_DISPATCH", + "TKIND_COCLASS", + "TKIND_ALIAS", + "TKIND_UNION", + "TKIND_MAX" +}; + +void dump_TYPEATTR(TYPEATTR *tattr) { + char buf[200]; + MESSAGE("\tguid: %s\n",debugstr_guid(&tattr->guid)); + MESSAGE("\tlcid: %ld\n",tattr->lcid); + MESSAGE("\tmemidConstructor: %ld\n",tattr->memidConstructor); + MESSAGE("\tmemidDestructor: %ld\n",tattr->memidDestructor); + MESSAGE("\tschema: %s\n",debugstr_w(tattr->lpstrSchema)); + MESSAGE("\tsizeInstance: %ld\n",tattr->cbSizeInstance); + MESSAGE("\tkind:%s\n", typekind_desc[tattr->typekind]); + MESSAGE("\tcFuncs: %d\n", tattr->cFuncs); + MESSAGE("\tcVars: %d\n", tattr->cVars); + MESSAGE("\tcImplTypes: %d\n", tattr->cImplTypes); + MESSAGE("\tcbSizeVft: %d\n", tattr->cbSizeVft); + MESSAGE("\tcbAlignment: %d\n", tattr->cbAlignment); + MESSAGE("\twTypeFlags: %d\n", tattr->wTypeFlags); + MESSAGE("\tVernum: %d.%d\n", tattr->wMajorVerNum,tattr->wMinorVerNum); + dump_TypeDesc(&tattr->tdescAlias,buf); + MESSAGE("\ttypedesc: %s\n", buf); + dump_IDLDESC(&tattr->idldescType); +} + +static void dump_TLBFuncDescOne(TLBFuncDesc * pfd) +{ + int i; + if (!TRACE_ON(typelib)) + return; + MESSAGE("%s(%u)\n", debugstr_w(pfd->Name), pfd->funcdesc.cParams); + for (i=0;i<pfd->funcdesc.cParams;i++) + MESSAGE("\tparm%d: %s\n",i,debugstr_w(pfd->pParamDesc[i].Name)); + + + dump_FUNCDESC(&(pfd->funcdesc)); + + MESSAGE("\thelpstring: %s\n", debugstr_w(pfd->HelpString)); + MESSAGE("\tentry: %s\n", debugstr_w(pfd->Entry)); +} +static void dump_TLBFuncDesc(TLBFuncDesc * pfd) +{ + while (pfd) + { + dump_TLBFuncDescOne(pfd); + pfd = pfd->next; + }; +} +static void dump_TLBVarDesc(TLBVarDesc * pvd) +{ + while (pvd) + { + TRACE_(typelib)("%s\n", debugstr_w(pvd->Name)); + pvd = pvd->next; + }; +} + +static void dump_TLBImpLib(TLBImpLib *import) +{ + TRACE_(typelib)("%s %s\n", debugstr_guid(&(import->guid)), + debugstr_w(import->name)); + TRACE_(typelib)("v%d.%d lcid=%lx offset=%x\n", import->wVersionMajor, + import->wVersionMinor, import->lcid, import->offset); +} + +static void dump_TLBRefType(TLBRefType * prt) +{ + while (prt) + { + TRACE_(typelib)("href:0x%08lx\n", prt->reference); + if(prt->index == -1) + TRACE_(typelib)("%s\n", debugstr_guid(&(prt->guid))); + else + TRACE_(typelib)("type no: %d\n", prt->index); + + if(prt->pImpTLInfo != TLB_REF_INTERNAL && + prt->pImpTLInfo != TLB_REF_NOT_FOUND) { + TRACE_(typelib)("in lib\n"); + dump_TLBImpLib(prt->pImpTLInfo); + } + prt = prt->next; + }; +} + +static void dump_TLBImplType(TLBImplType * impl) +{ + while (impl) { + TRACE_(typelib)( + "implementing/inheriting interface hRef = %lx implflags %x\n", + impl->hRef, impl->implflags); + impl = impl->next; + } +} + +void dump_Variant(VARIANT * pvar) +{ + SYSTEMTIME st; + + TRACE("%p->{%s%s", pvar, debugstr_VT(pvar), debugstr_VF(pvar)); + + if (pvar) + { + if (V_ISBYREF(pvar) || V_TYPE(pvar) == VT_UNKNOWN || + V_TYPE(pvar) == VT_DISPATCH || V_TYPE(pvar) == VT_RECORD) + { + TRACE(",%p", V_BYREF(pvar)); + } + else if (V_ISARRAY(pvar) || V_ISVECTOR(pvar)) + { + TRACE(",FIXME"); + } + else switch (V_TYPE(pvar)) + { + case VT_I1: TRACE(",%d", V_I1(pvar)); break; + case VT_UI1: TRACE(",%d", V_UI1(pvar)); break; + case VT_I2: TRACE(",%d", V_I2(pvar)); break; + case VT_UI2: TRACE(",%d", V_UI2(pvar)); break; + case VT_INT: + case VT_I4: TRACE(",%ld", V_I4(pvar)); break; + case VT_UINT: + case VT_UI4: TRACE(",%ld", V_UI4(pvar)); break; + case VT_I8: TRACE(",0x%08lx,0x%08lx", (ULONG)(V_I8(pvar) >> 32), + (ULONG)(V_I8(pvar) & 0xffffffff)); break; + case VT_UI8: TRACE(",0x%08lx,0x%08lx", (ULONG)(V_UI8(pvar) >> 32), + (ULONG)(V_UI8(pvar) & 0xffffffff)); break; + case VT_R4: TRACE(",%3.3e", V_R4(pvar)); break; + case VT_R8: TRACE(",%3.3e", V_R8(pvar)); break; + case VT_BOOL: TRACE(",%s", V_BOOL(pvar) ? "TRUE" : "FALSE"); break; + case VT_BSTR: TRACE(",%s", debugstr_w(V_BSTR(pvar))); break; + case VT_CY: TRACE(",0x%08lx,0x%08lx", V_CY(pvar).s.Hi, + V_CY(pvar).s.Lo); break; + case VT_DATE: + if(!VariantTimeToSystemTime(V_DATE(pvar), &st)) + TRACE(",<invalid>"); + else + TRACE(",%04d/%02d/%02d %02d:%02d:%02d", st.wYear, st.wMonth, st.wDay, + st.wHour, st.wMinute, st.wSecond); + break; + case VT_ERROR: + case VT_VOID: + case VT_USERDEFINED: + case VT_EMPTY: + case VT_NULL: break; + default: TRACE(",?"); break; + } + } + TRACE("}\n"); +} + +static void dump_DispParms(DISPPARAMS * pdp) +{ + int index = 0; + + TRACE("args=%u named args=%u\n", pdp->cArgs, pdp->cNamedArgs); + + while (index < pdp->cArgs) + { + dump_Variant( &pdp->rgvarg[index] ); + ++index; + } +} + +static void dump_TypeInfo(ITypeInfoImpl * pty) +{ + TRACE("%p ref=%lu\n", pty, pty->ref); + TRACE("attr:%s\n", debugstr_guid(&(pty->TypeAttr.guid))); + TRACE("kind:%s\n", typekind_desc[pty->TypeAttr.typekind]); + TRACE("fct:%u var:%u impl:%u\n", + pty->TypeAttr.cFuncs, pty->TypeAttr.cVars, pty->TypeAttr.cImplTypes); + TRACE("parent tlb:%p index in TLB:%u\n",pty->pTypeLib, pty->index); + TRACE("%s %s\n", debugstr_w(pty->Name), debugstr_w(pty->DocString)); + dump_TLBFuncDesc(pty->funclist); + dump_TLBVarDesc(pty->varlist); + dump_TLBImplType(pty->impltypelist); +} + +void dump_VARDESC(VARDESC *v) +{ + MESSAGE("memid %ld\n",v->memid); + MESSAGE("lpstrSchema %s\n",debugstr_w(v->lpstrSchema)); + MESSAGE("oInst %ld\n",v->u.oInst); + dump_ELEMDESC(&(v->elemdescVar)); + MESSAGE("wVarFlags %x\n",v->wVarFlags); + MESSAGE("varkind %d\n",v->varkind); +} + +static TYPEDESC stndTypeDesc[VT_LPWSTR+1]= +{ + /* VT_LPWSTR is largest type that */ + /* may appear in type description*/ + {{0}, 0},{{0}, 1},{{0}, 2},{{0}, 3},{{0}, 4}, + {{0}, 5},{{0}, 6},{{0}, 7},{{0}, 8},{{0}, 9}, + {{0},10},{{0},11},{{0},12},{{0},13},{{0},14}, + {{0},15},{{0},16},{{0},17},{{0},18},{{0},19}, + {{0},20},{{0},21},{{0},22},{{0},23},{{0},24}, + {{0},25},{{0},26},{{0},27},{{0},28},{{0},29}, + {{0},30},{{0},31} +}; + +static void TLB_abort() +{ + DebugBreak(); +} +static void * TLB_Alloc(unsigned size) +{ + void * ret; + if((ret=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size))==NULL){ + /* FIXME */ + ERR("cannot allocate memory\n"); + } + return ret; +} + +static void TLB_Free(void * ptr) +{ + HeapFree(GetProcessHeap(), 0, ptr); +} + +/* deep copy a typedesc */ +static void copy_typedesc(TYPEDESC *out, const TYPEDESC *in) +{ + out->vt = in->vt; + switch(in->vt) { + case VT_PTR: + out->u.lptdesc = HeapAlloc(GetProcessHeap(), 0, sizeof(TYPEDESC)); + copy_typedesc(out->u.lptdesc, in->u.lptdesc); + break; + case VT_USERDEFINED: + out->u.hreftype = in->u.hreftype; + break; + case VT_CARRAY: + out->u.lpadesc = HeapAlloc(GetProcessHeap(), 0, sizeof(ARRAYDESC) + + (in->u.lpadesc->cDims - 1) * sizeof(SAFEARRAYBOUND)); + copy_typedesc(&out->u.lpadesc->tdescElem, &in->u.lpadesc->tdescElem); + out->u.lpadesc->cDims = in->u.lpadesc->cDims; + memcpy(out->u.lpadesc->rgbounds, in->u.lpadesc->rgbounds, in->u.lpadesc->cDims * sizeof(SAFEARRAYBOUND)); + break; + default: + break; + } +} + +/* free()s any allocated memory pointed to by the tdesc. NB does not + free the tdesc itself - this is because the tdesc is typically part + of a larger structure */ +static void free_deep_typedesc(TYPEDESC *tdesc) +{ + switch(tdesc->vt) { + case VT_PTR: + free_deep_typedesc(tdesc->u.lptdesc); + HeapFree(GetProcessHeap(), 0, tdesc->u.lptdesc); + tdesc->u.lptdesc = NULL; + break; + case VT_CARRAY: + free_deep_typedesc(&tdesc->u.lpadesc->tdescElem); + HeapFree(GetProcessHeap(), 0, tdesc->u.lpadesc); + tdesc->u.lpadesc = NULL; + break; + default: + break; + } +} + +/********************************************************************** + * + * Functions for reading MSFT typelibs (those created by CreateTypeLib2) + */ +/* read function */ +DWORD MSFT_Read(void *buffer, DWORD count, TLBContext *pcx, long where ) +{ + TRACE_(typelib)("pos=0x%08x len=0x%08lx 0x%08x 0x%08x 0x%08lx\n", + pcx->pos, count, pcx->oStart, pcx->length, where); + + if (where != DO_NOT_SEEK) + { + where += pcx->oStart; + if (where > pcx->length) + { + /* FIXME */ + ERR("seek beyond end (%ld/%d)\n", where, pcx->length ); + TLB_abort(); + } + pcx->pos = where; + } + if (pcx->pos + count > pcx->length) count = pcx->length - pcx->pos; + memcpy( buffer, (char *)pcx->mapping + pcx->pos, count ); + pcx->pos += count; + return count; +} + +static DWORD MSFT_ReadLEDWords(void *buffer, DWORD count, TLBContext *pcx, + long where ) +{ + DWORD ret; + + ret = MSFT_Read(buffer, count, pcx, where); + FromLEDWords(buffer, ret); + + return ret; +} + +static DWORD MSFT_ReadLEWords(void *buffer, DWORD count, TLBContext *pcx, + long where ) +{ + DWORD ret; + + ret = MSFT_Read(buffer, count, pcx, where); + FromLEWords(buffer, ret); + + return ret; +} + +static void MSFT_ReadGuid( GUID *pGuid, int offset, TLBContext *pcx) +{ + if(offset<0 || pcx->pTblDir->pGuidTab.offset <0){ + memset(pGuid,0, sizeof(GUID)); + return; + } + MSFT_Read(pGuid, sizeof(GUID), pcx, pcx->pTblDir->pGuidTab.offset+offset ); + pGuid->Data1 = FromLEDWord(pGuid->Data1); + pGuid->Data2 = FromLEWord(pGuid->Data2); + pGuid->Data3 = FromLEWord(pGuid->Data3); + TRACE_(typelib)("%s\n", debugstr_guid(pGuid)); +} + +BSTR MSFT_ReadName( TLBContext *pcx, int offset) +{ + char * name; + MSFT_NameIntro niName; + int lengthInChars; + WCHAR* pwstring = NULL; + BSTR bstrName = NULL; + + MSFT_ReadLEDWords(&niName, sizeof(niName), pcx, + pcx->pTblDir->pNametab.offset+offset); + niName.namelen &= 0xFF; /* FIXME: correct ? */ + name=TLB_Alloc((niName.namelen & 0xff) +1); + MSFT_Read(name, (niName.namelen & 0xff), pcx, DO_NOT_SEEK); + name[niName.namelen & 0xff]='\0'; + + lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, + name, -1, NULL, 0); + + /* no invalid characters in string */ + if (lengthInChars) + { + pwstring = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*lengthInChars); + + /* don't check for invalid character since this has been done previously */ + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, pwstring, lengthInChars); + + bstrName = SysAllocStringLen(pwstring, lengthInChars); + lengthInChars = SysStringLen(bstrName); + HeapFree(GetProcessHeap(), 0, pwstring); + } + + TRACE_(typelib)("%s %d\n", debugstr_w(bstrName), lengthInChars); + return bstrName; +} + +BSTR MSFT_ReadString( TLBContext *pcx, int offset) +{ + char * string; + INT16 length; + int lengthInChars; + BSTR bstr = NULL; + + if(offset<0) return NULL; + MSFT_ReadLEWords(&length, sizeof(INT16), pcx, pcx->pTblDir->pStringtab.offset+offset); + if(length <= 0) return 0; + string=TLB_Alloc(length +1); + MSFT_Read(string, length, pcx, DO_NOT_SEEK); + string[length]='\0'; + + lengthInChars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, + string, -1, NULL, 0); + + /* no invalid characters in string */ + if (lengthInChars) + { + WCHAR* pwstring = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*lengthInChars); + + /* don't check for invalid character since this has been done previously */ + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, string, -1, pwstring, lengthInChars); + + bstr = SysAllocStringLen(pwstring, lengthInChars); + lengthInChars = SysStringLen(bstr); + HeapFree(GetProcessHeap(), 0, pwstring); + } + + TRACE_(typelib)("%s %d\n", debugstr_w(bstr), lengthInChars); + return bstr; +} +/* + * read a value and fill a VARIANT structure + */ +static void MSFT_ReadValue( VARIANT * pVar, int offset, TLBContext *pcx ) +{ + int size; + + TRACE_(typelib)("\n"); + + if(offset <0) { /* data are packed in here */ + V_VT(pVar) = (offset & 0x7c000000 )>> 26; + V_I2(pVar) = offset & 0x3ffffff; + return; + } + MSFT_ReadLEWords(&(V_VT(pVar)), sizeof(VARTYPE), pcx, + pcx->pTblDir->pCustData.offset + offset ); + TRACE_(typelib)("Vartype = %x\n", V_VT(pVar)); + switch (V_VT(pVar)){ + case VT_EMPTY: /* FIXME: is this right? */ + case VT_NULL: /* FIXME: is this right? */ + case VT_I2 : /* this should not happen */ + case VT_I4 : + case VT_R4 : + case VT_ERROR : + case VT_BOOL : + case VT_I1 : + case VT_UI1 : + case VT_UI2 : + case VT_UI4 : + case VT_INT : + case VT_UINT : + case VT_VOID : /* FIXME: is this right? */ + case VT_HRESULT : + size=4; break; + case VT_R8 : + case VT_CY : + case VT_DATE : + case VT_I8 : + case VT_UI8 : + case VT_DECIMAL : /* FIXME: is this right? */ + case VT_FILETIME : + size=8;break; + /* pointer types with known behaviour */ + case VT_BSTR :{ + char * ptr; + MSFT_ReadLEDWords(&size, sizeof(INT), pcx, DO_NOT_SEEK ); + if(size < 0) { + FIXME("BSTR length = %d?\n", size); + } else { + ptr=TLB_Alloc(size);/* allocate temp buffer */ + MSFT_Read(ptr, size, pcx, DO_NOT_SEEK);/* read string (ANSI) */ + V_BSTR(pVar)=SysAllocStringLen(NULL,size); + /* FIXME: do we need a AtoW conversion here? */ + V_UNION(pVar, bstrVal[size])=L'\0'; + while(size--) V_UNION(pVar, bstrVal[size])=ptr[size]; + TLB_Free(ptr); + } + } + size=-4; break; + /* FIXME: this will not work AT ALL when the variant contains a pointer */ + case VT_DISPATCH : + case VT_VARIANT : + case VT_UNKNOWN : + case VT_PTR : + case VT_SAFEARRAY : + case VT_CARRAY : + case VT_USERDEFINED : + case VT_LPSTR : + case VT_LPWSTR : + case VT_BLOB : + case VT_STREAM : + case VT_STORAGE : + case VT_STREAMED_OBJECT : + case VT_STORED_OBJECT : + case VT_BLOB_OBJECT : + case VT_CF : + case VT_CLSID : + default: + size=0; + FIXME("VARTYPE %d is not supported, setting pointer to NULL\n", + V_VT(pVar)); + } + + if(size>0) /* (big|small) endian correct? */ + MSFT_Read(&(V_I2(pVar)), size, pcx, DO_NOT_SEEK ); + return; +} +/* + * create a linked list with custom data + */ +static int MSFT_CustData( TLBContext *pcx, int offset, TLBCustData** ppCustData ) +{ + MSFT_CDGuid entry; + TLBCustData* pNew; + int count=0; + + TRACE_(typelib)("\n"); + + while(offset >=0){ + count++; + pNew=TLB_Alloc(sizeof(TLBCustData)); + MSFT_ReadLEDWords(&entry, sizeof(entry), pcx, pcx->pTblDir->pCDGuids.offset+offset); + MSFT_ReadGuid(&(pNew->guid), entry.GuidOffset , pcx); + MSFT_ReadValue(&(pNew->data), entry.DataOffset, pcx); + /* add new custom data at head of the list */ + pNew->next=*ppCustData; + *ppCustData=pNew; + offset = entry.next; + } + return count; +} + +static void MSFT_GetTdesc(TLBContext *pcx, INT type, TYPEDESC *pTd, + ITypeInfoImpl *pTI) +{ + if(type <0) + pTd->vt=type & VT_TYPEMASK; + else + *pTd=pcx->pLibInfo->pTypeDesc[type/(2*sizeof(INT))]; + + if(pTd->vt == VT_USERDEFINED) + MSFT_DoRefType(pcx, pTI, pTd->u.hreftype); + + TRACE_(typelib)("vt type = %X\n", pTd->vt); +} + +static void +MSFT_DoFuncs(TLBContext* pcx, + ITypeInfoImpl* pTI, + int cFuncs, + int cVars, + int offset, + TLBFuncDesc** pptfd) +{ + /* + * member information is stored in a data structure at offset + * indicated by the memoffset field of the typeinfo structure + * There are several distinctive parts. + * The first part starts with a field that holds the total length + * of this (first) part excluding this field. Then follow the records, + * for each member there is one record. + * + * The first entry is always the length of the record (including this + * length word). + * The rest of the record depends on the type of the member. If there is + * a field indicating the member type (function, variable, interface, etc) + * I have not found it yet. At this time we depend on the information + * in the type info and the usual order how things are stored. + * + * Second follows an array sized nrMEM*sizeof(INT) with a member id + * for each member; + * + * Third is an equal sized array with file offsets to the name entry + * of each member. + * + * The fourth and last (?) part is an array with offsets to the records + * in the first part of this file segment. + */ + + int infolen, nameoffset, reclength, nrattributes, i; + int recoffset = offset + sizeof(INT); + + char recbuf[512]; + MSFT_FuncRecord * pFuncRec=(MSFT_FuncRecord *) recbuf; + + TRACE_(typelib)("\n"); + + MSFT_ReadLEDWords(&infolen, sizeof(INT), pcx, offset); + + for ( i = 0; i < cFuncs ; i++ ) + { + *pptfd = TLB_Alloc(sizeof(TLBFuncDesc)); + + /* name, eventually add to a hash table */ + MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx, + offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT)); + + (*pptfd)->Name = MSFT_ReadName(pcx, nameoffset); + + /* read the function information record */ + MSFT_ReadLEDWords(&reclength, sizeof(INT), pcx, recoffset); + + reclength &= 0x1ff; + + MSFT_ReadLEDWords(pFuncRec, reclength - sizeof(INT), pcx, DO_NOT_SEEK); + + /* do the attributes */ + nrattributes = (reclength - pFuncRec->nrargs * 3 * sizeof(int) - 0x18) + / sizeof(int); + + if ( nrattributes > 0 ) + { + (*pptfd)->helpcontext = pFuncRec->OptAttr[0] ; + + if ( nrattributes > 1 ) + { + (*pptfd)->HelpString = MSFT_ReadString(pcx, + pFuncRec->OptAttr[1]) ; + + if ( nrattributes > 2 ) + { + if ( pFuncRec->FKCCIC & 0x2000 ) + { + (*pptfd)->Entry = (WCHAR*) pFuncRec->OptAttr[2] ; + } + else + { + (*pptfd)->Entry = MSFT_ReadString(pcx, + pFuncRec->OptAttr[2]); + } + if( nrattributes > 5 ) + { + (*pptfd)->HelpStringContext = pFuncRec->OptAttr[5] ; + + if ( nrattributes > 6 && pFuncRec->FKCCIC & 0x80 ) + { + MSFT_CustData(pcx, + pFuncRec->OptAttr[6], + &(*pptfd)->pCustData); + } + } + } + } + } + + /* fill the FuncDesc Structure */ + MSFT_ReadLEDWords( & (*pptfd)->funcdesc.memid, sizeof(INT), pcx, + offset + infolen + ( i + 1) * sizeof(INT)); + + (*pptfd)->funcdesc.funckind = (pFuncRec->FKCCIC) & 0x7; + (*pptfd)->funcdesc.invkind = (pFuncRec->FKCCIC) >> 3 & 0xF; + (*pptfd)->funcdesc.callconv = (pFuncRec->FKCCIC) >> 8 & 0xF; + (*pptfd)->funcdesc.cParams = pFuncRec->nrargs ; + (*pptfd)->funcdesc.cParamsOpt = pFuncRec->nroargs ; + (*pptfd)->funcdesc.oVft = pFuncRec->VtableOffset ; + (*pptfd)->funcdesc.wFuncFlags = LOWORD(pFuncRec->Flags) ; + + MSFT_GetTdesc(pcx, + pFuncRec->DataType, + &(*pptfd)->funcdesc.elemdescFunc.tdesc, + pTI); + + /* do the parameters/arguments */ + if(pFuncRec->nrargs) + { + int j = 0; + MSFT_ParameterInfo paraminfo; + + (*pptfd)->funcdesc.lprgelemdescParam = + TLB_Alloc(pFuncRec->nrargs * sizeof(ELEMDESC)); + + (*pptfd)->pParamDesc = + TLB_Alloc(pFuncRec->nrargs * sizeof(TLBParDesc)); + + MSFT_ReadLEDWords(¶minfo, sizeof(paraminfo), pcx, + recoffset + reclength - pFuncRec->nrargs * sizeof(MSFT_ParameterInfo)); + + for ( j = 0 ; j < pFuncRec->nrargs ; j++ ) + { + TYPEDESC* lpArgTypeDesc = 0; + + MSFT_GetTdesc(pcx, + paraminfo.DataType, + &(*pptfd)->funcdesc.lprgelemdescParam[j].tdesc, + pTI); + + (*pptfd)->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags = paraminfo.Flags; + + (*pptfd)->pParamDesc[j].Name = (void *) paraminfo.oName; + + /* SEEK value = jump to offset, + * from there jump to the end of record, + * go back by (j-1) arguments + */ + MSFT_ReadLEDWords( ¶minfo , + sizeof(MSFT_ParameterInfo), pcx, + recoffset + reclength - ((pFuncRec->nrargs - j - 1) + * sizeof(MSFT_ParameterInfo))); + lpArgTypeDesc = + & ((*pptfd)->funcdesc.lprgelemdescParam[j].tdesc); + + while ( lpArgTypeDesc != NULL ) + { + switch ( lpArgTypeDesc->vt ) + { + case VT_PTR: + lpArgTypeDesc = lpArgTypeDesc->u.lptdesc; + break; + + case VT_CARRAY: + lpArgTypeDesc = & (lpArgTypeDesc->u.lpadesc->tdescElem); + break; + + case VT_USERDEFINED: + MSFT_DoRefType(pcx, pTI, + lpArgTypeDesc->u.hreftype); + + lpArgTypeDesc = NULL; + break; + + default: + lpArgTypeDesc = NULL; + } + } + } + + + /* parameter is the return value! */ + if ( paraminfo.Flags & PARAMFLAG_FRETVAL ) + { + TYPEDESC* lpArgTypeDesc; + + (*pptfd)->funcdesc.elemdescFunc = + (*pptfd)->funcdesc.lprgelemdescParam[j]; + + lpArgTypeDesc = & ((*pptfd)->funcdesc.elemdescFunc.tdesc) ; + + while ( lpArgTypeDesc != NULL ) + { + switch ( lpArgTypeDesc->vt ) + { + case VT_PTR: + lpArgTypeDesc = lpArgTypeDesc->u.lptdesc; + break; + case VT_CARRAY: + lpArgTypeDesc = + & (lpArgTypeDesc->u.lpadesc->tdescElem); + + break; + + case VT_USERDEFINED: + MSFT_DoRefType(pcx, + pTI, + lpArgTypeDesc->u.hreftype); + + lpArgTypeDesc = NULL; + break; + + default: + lpArgTypeDesc = NULL; + } + } + } + + /* second time around */ + for(j=0;j<pFuncRec->nrargs;j++) + { + /* name */ + (*pptfd)->pParamDesc[j].Name = + MSFT_ReadName( pcx, (int)(*pptfd)->pParamDesc[j].Name ); + + /* default value */ + if ( (PARAMFLAG_FHASDEFAULT & + (*pptfd)->funcdesc.lprgelemdescParam[j].u.paramdesc.wParamFlags) && + ((pFuncRec->FKCCIC) & 0x1000) ) + { + INT* pInt = (INT *)((char *)pFuncRec + + reclength - + (pFuncRec->nrargs * 4 + 1) * sizeof(INT) ); + + PARAMDESC* pParamDesc = & (*pptfd)->funcdesc.lprgelemdescParam[j].u.paramdesc; + + pParamDesc->pparamdescex = TLB_Alloc(sizeof(PARAMDESCEX)); + pParamDesc->pparamdescex->cBytes = sizeof(PARAMDESCEX); + + MSFT_ReadValue(&(pParamDesc->pparamdescex->varDefaultValue), + pInt[j], pcx); + } + /* custom info */ + if ( nrattributes > 7 + j && pFuncRec->FKCCIC & 0x80 ) + { + MSFT_CustData(pcx, + pFuncRec->OptAttr[7+j], + &(*pptfd)->pParamDesc[j].pCustData); + } + } + } + + /* scode is not used: archaic win16 stuff FIXME: right? */ + (*pptfd)->funcdesc.cScodes = 0 ; + (*pptfd)->funcdesc.lprgscode = NULL ; + + pptfd = & ((*pptfd)->next); + recoffset += reclength; + } +} + +static void MSFT_DoVars(TLBContext *pcx, ITypeInfoImpl *pTI, int cFuncs, + int cVars, int offset, TLBVarDesc ** pptvd) +{ + int infolen, nameoffset, reclength; + char recbuf[256]; + MSFT_VarRecord * pVarRec=(MSFT_VarRecord *) recbuf; + int i; + int recoffset; + + TRACE_(typelib)("\n"); + + MSFT_ReadLEDWords(&infolen,sizeof(INT), pcx, offset); + MSFT_ReadLEDWords(&recoffset,sizeof(INT), pcx, offset + infolen + + ((cFuncs+cVars)*2+cFuncs + 1)*sizeof(INT)); + recoffset += offset+sizeof(INT); + for(i=0;i<cVars;i++){ + *pptvd=TLB_Alloc(sizeof(TLBVarDesc)); + /* name, eventually add to a hash table */ + MSFT_ReadLEDWords(&nameoffset, sizeof(INT), pcx, + offset + infolen + (cFuncs + cVars + i + 1) * sizeof(INT)); + (*pptvd)->Name=MSFT_ReadName(pcx, nameoffset); + /* read the variable information record */ + MSFT_ReadLEDWords(&reclength, sizeof(INT), pcx, recoffset); + reclength &=0xff; + MSFT_ReadLEDWords(pVarRec, reclength - sizeof(INT), pcx, DO_NOT_SEEK); + /* Optional data */ + if(reclength >(6*sizeof(INT)) ) + (*pptvd)->HelpContext=pVarRec->HelpContext; + if(reclength >(7*sizeof(INT)) ) + (*pptvd)->HelpString = MSFT_ReadString(pcx, pVarRec->oHelpString) ; + if(reclength >(8*sizeof(INT)) ) + if(reclength >(9*sizeof(INT)) ) + (*pptvd)->HelpStringContext=pVarRec->HelpStringContext; + /* fill the VarDesc Structure */ + MSFT_ReadLEDWords(&(*pptvd)->vardesc.memid, sizeof(INT), pcx, + offset + infolen + ( i + 1) * sizeof(INT)); + (*pptvd)->vardesc.varkind = pVarRec->VarKind; + (*pptvd)->vardesc.wVarFlags = pVarRec->Flags; + MSFT_GetTdesc(pcx, pVarRec->DataType, + &(*pptvd)->vardesc.elemdescVar.tdesc, pTI); +/* (*pptvd)->vardesc.lpstrSchema; is reserved (SDK) FIXME?? */ + if(pVarRec->VarKind == VAR_CONST ){ + (*pptvd)->vardesc.u.lpvarValue=TLB_Alloc(sizeof(VARIANT)); + MSFT_ReadValue((*pptvd)->vardesc.u.lpvarValue, + pVarRec->OffsValue, pcx); + } else + (*pptvd)->vardesc.u.oInst=pVarRec->OffsValue; + pptvd=&((*pptvd)->next); + recoffset += reclength; + } +} +/* fill in data for a hreftype (offset). When the referenced type is contained + * in the typelib, it's just an (file) offset in the type info base dir. + * If comes from import, it's an offset+1 in the ImpInfo table + * */ +static void MSFT_DoRefType(TLBContext *pcx, ITypeInfoImpl *pTI, + int offset) +{ + int j; + TLBRefType **ppRefType = &pTI->reflist; + + TRACE_(typelib)("TLB context %p, TLB offset %x\n", pcx, offset); + + while(*ppRefType) { + if((*ppRefType)->reference == offset) + return; + ppRefType = &(*ppRefType)->next; + } + + *ppRefType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(**ppRefType)); + + if(!MSFT_HREFTYPE_INTHISFILE( offset)) { + /* external typelib */ + MSFT_ImpInfo impinfo; + TLBImpLib *pImpLib=(pcx->pLibInfo->pImpLibs); + + TRACE_(typelib)("offset %x, masked offset %x\n", offset, offset + (offset & 0xfffffffc)); + + MSFT_ReadLEDWords(&impinfo, sizeof(impinfo), pcx, + pcx->pTblDir->pImpInfo.offset + (offset & 0xfffffffc)); + for(j=0;pImpLib;j++){ /* search the known offsets of all import libraries */ + if(pImpLib->offset==impinfo.oImpFile) break; + pImpLib=pImpLib->next; + } + if(pImpLib){ + (*ppRefType)->reference=offset; + (*ppRefType)->pImpTLInfo = pImpLib; + MSFT_ReadGuid(&(*ppRefType)->guid, impinfo.oGuid, pcx); + (*ppRefType)->index = TLB_REF_USE_GUID; + }else{ + ERR("Cannot find a reference\n"); + (*ppRefType)->reference=-1; + (*ppRefType)->pImpTLInfo=TLB_REF_NOT_FOUND; + } + }else{ + /* in this typelib */ + (*ppRefType)->index = MSFT_HREFTYPE_INDEX(offset); + (*ppRefType)->reference=offset; + (*ppRefType)->pImpTLInfo=TLB_REF_INTERNAL; + } +} + +/* process Implemented Interfaces of a com class */ +static void MSFT_DoImplTypes(TLBContext *pcx, ITypeInfoImpl *pTI, int count, + int offset) +{ + int i; + MSFT_RefRecord refrec; + TLBImplType **ppImpl = &pTI->impltypelist; + + TRACE_(typelib)("\n"); + + for(i=0;i<count;i++){ + if(offset<0) break; /* paranoia */ + *ppImpl=TLB_Alloc(sizeof(**ppImpl)); + MSFT_ReadLEDWords(&refrec,sizeof(refrec),pcx,offset+pcx->pTblDir->pRefTab.offset); + MSFT_DoRefType(pcx, pTI, refrec.reftype); + (*ppImpl)->hRef = refrec.reftype; + (*ppImpl)->implflags=refrec.flags; + (*ppImpl)->ctCustData= + MSFT_CustData(pcx, refrec.oCustData, &(*ppImpl)->pCustData); + offset=refrec.onext; + ppImpl=&((*ppImpl)->next); + } +} +/* + * process a typeinfo record + */ +ITypeInfoImpl * MSFT_DoTypeInfo( + TLBContext *pcx, + int count, + ITypeLibImpl * pLibInfo) +{ + MSFT_TypeInfoBase tiBase; + ITypeInfoImpl *ptiRet; + + TRACE_(typelib)("count=%u\n", count); + + ptiRet = (ITypeInfoImpl*) ITypeInfo_Constructor(); + MSFT_ReadLEDWords(&tiBase, sizeof(tiBase) ,pcx , + pcx->pTblDir->pTypeInfoTab.offset+count*sizeof(tiBase)); +/* this is where we are coming from */ + ptiRet->pTypeLib = pLibInfo; + ptiRet->index=count; +/* fill in the typeattr fields */ + WARN("Assign constructor/destructor memid\n"); + + MSFT_ReadGuid(&ptiRet->TypeAttr.guid, tiBase.posguid, pcx); + ptiRet->TypeAttr.lcid=pLibInfo->LibAttr.lcid; /* FIXME: correct? */ + ptiRet->TypeAttr.memidConstructor=MEMBERID_NIL ;/* FIXME */ + ptiRet->TypeAttr.memidDestructor=MEMBERID_NIL ; /* FIXME */ + ptiRet->TypeAttr.lpstrSchema=NULL; /* reserved */ + ptiRet->TypeAttr.cbSizeInstance=tiBase.size; + ptiRet->TypeAttr.typekind=tiBase.typekind & 0xF; + ptiRet->TypeAttr.cFuncs=LOWORD(tiBase.cElement); + ptiRet->TypeAttr.cVars=HIWORD(tiBase.cElement); + ptiRet->TypeAttr.cbAlignment=(tiBase.typekind >> 11 )& 0x1F; /* there are more flags there */ + ptiRet->TypeAttr.wTypeFlags=tiBase.flags; + ptiRet->TypeAttr.wMajorVerNum=LOWORD(tiBase.version); + ptiRet->TypeAttr.wMinorVerNum=HIWORD(tiBase.version); + ptiRet->TypeAttr.cImplTypes=tiBase.cImplTypes; + ptiRet->TypeAttr.cbSizeVft=tiBase.cbSizeVft; /* FIXME: this is only the non inherited part */ + if(ptiRet->TypeAttr.typekind == TKIND_ALIAS) + MSFT_GetTdesc(pcx, tiBase.datatype1, + &ptiRet->TypeAttr.tdescAlias, ptiRet); + +/* FIXME: */ +/* IDLDESC idldescType; *//* never saw this one != zero */ + +/* name, eventually add to a hash table */ + ptiRet->Name=MSFT_ReadName(pcx, tiBase.NameOffset); + TRACE_(typelib)("reading %s\n", debugstr_w(ptiRet->Name)); + /* help info */ + ptiRet->DocString=MSFT_ReadString(pcx, tiBase.docstringoffs); + ptiRet->dwHelpStringContext=tiBase.helpstringcontext; + ptiRet->dwHelpContext=tiBase.helpcontext; +/* note: InfoType's Help file and HelpStringDll come from the containing + * library. Further HelpString and Docstring appear to be the same thing :( + */ + /* functions */ + if(ptiRet->TypeAttr.cFuncs >0 ) + MSFT_DoFuncs(pcx, ptiRet, ptiRet->TypeAttr.cFuncs, + ptiRet->TypeAttr.cVars, + tiBase.memoffset, & ptiRet->funclist); + /* variables */ + if(ptiRet->TypeAttr.cVars >0 ) + MSFT_DoVars(pcx, ptiRet, ptiRet->TypeAttr.cFuncs, + ptiRet->TypeAttr.cVars, + tiBase.memoffset, & ptiRet->varlist); + if(ptiRet->TypeAttr.cImplTypes >0 ) { + switch(ptiRet->TypeAttr.typekind) + { + case TKIND_COCLASS: + MSFT_DoImplTypes(pcx, ptiRet, ptiRet->TypeAttr.cImplTypes , + tiBase.datatype1); + break; + case TKIND_DISPATCH: + ptiRet->impltypelist=TLB_Alloc(sizeof(TLBImplType)); + + if (tiBase.datatype1 != -1) + { + MSFT_DoRefType(pcx, ptiRet, tiBase.datatype1); + ptiRet->impltypelist->hRef = tiBase.datatype1; + } + else + { /* FIXME: This is a really bad hack to add IDispatch */ + const char* szStdOle = "stdole2.tlb\0"; + int nStdOleLen = strlen(szStdOle); + TLBRefType **ppRef = &ptiRet->reflist; + + while(*ppRef) { + if((*ppRef)->reference == -1) + break; + ppRef = &(*ppRef)->next; + } + if(!*ppRef) { + *ppRef = TLB_Alloc(sizeof(**ppRef)); + (*ppRef)->guid = IID_IDispatch; + (*ppRef)->reference = -1; + (*ppRef)->index = TLB_REF_USE_GUID; + (*ppRef)->pImpTLInfo = TLB_Alloc(sizeof(TLBImpLib)); + (*ppRef)->pImpTLInfo->guid = IID_StdOle; + (*ppRef)->pImpTLInfo->name = SysAllocStringLen(NULL, + nStdOleLen + 1); + + MultiByteToWideChar(CP_ACP, + MB_PRECOMPOSED, + szStdOle, + -1, + (*ppRef)->pImpTLInfo->name, + SysStringLen((*ppRef)->pImpTLInfo->name)); + + (*ppRef)->pImpTLInfo->lcid = 0; + (*ppRef)->pImpTLInfo->wVersionMajor = 2; + (*ppRef)->pImpTLInfo->wVersionMinor = 0; + } + } + break; + default: + ptiRet->impltypelist=TLB_Alloc(sizeof(TLBImplType)); + MSFT_DoRefType(pcx, ptiRet, tiBase.datatype1); + ptiRet->impltypelist->hRef = tiBase.datatype1; + break; + } + } + ptiRet->ctCustData= + MSFT_CustData(pcx, tiBase.oCustData, &ptiRet->pCustData); + + TRACE_(typelib)("%s guid: %s kind:%s\n", + debugstr_w(ptiRet->Name), + debugstr_guid(&ptiRet->TypeAttr.guid), + typekind_desc[ptiRet->TypeAttr.typekind]); + + return ptiRet; +} + +/* Because type library parsing has some degree of overhead, and some apps repeatedly load the same + * typelibs over and over, we cache them here. According to MSDN Microsoft have a similar scheme in + * place. This will cause a deliberate memory leak, but generally losing RAM for cycles is an acceptable + * tradeoff here. + */ +static ITypeLibImpl *tlb_cache_first; +static CRITICAL_SECTION cache_section; +static CRITICAL_SECTION_DEBUG cache_section_debug = +{ + 0, 0, &cache_section, + { &cache_section_debug.ProcessLocksList, &cache_section_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": typelib loader cache") } +}; +static CRITICAL_SECTION cache_section = { &cache_section_debug, -1, 0, 0, 0, 0 }; + + +/**************************************************************************** + * TLB_ReadTypeLib + * + * find the type of the typelib file and map the typelib resource into + * the memory + */ +#define MSFT_SIGNATURE 0x5446534D /* "MSFT" */ +#define SLTG_SIGNATURE 0x47544c53 /* "SLTG" */ +int TLB_ReadTypeLib(LPCWSTR pszFileName, INT index, ITypeLib2 **ppTypeLib) +{ + ITypeLibImpl *entry; + int ret = TYPE_E_CANTLOADLIBRARY; + DWORD dwSignature = 0; + HANDLE hFile; + + TRACE_(typelib)("%s:%d\n", debugstr_w(pszFileName), index); + + *ppTypeLib = NULL; + + /* We look the path up in the typelib cache. If found, we just addref it, and return the pointer. */ + EnterCriticalSection(&cache_section); + for (entry = tlb_cache_first; entry != NULL; entry = entry->next) + { + if (!strcmpiW(entry->path, pszFileName) && entry->index == index) + { + TRACE("cache hit\n"); + *ppTypeLib = (ITypeLib2*)entry; + ITypeLib_AddRef(*ppTypeLib); + LeaveCriticalSection(&cache_section); + return S_OK; + } + } + LeaveCriticalSection(&cache_section); + + /* check the signature of the file */ + hFile = CreateFileW( pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); + if (INVALID_HANDLE_VALUE != hFile) + { + HANDLE hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL ); + if (hMapping) + { + LPVOID pBase = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0); + if(pBase) + { + /* retrieve file size */ + DWORD dwTLBLength = GetFileSize(hFile, NULL); + + /* first try to load as *.tlb */ + dwSignature = FromLEDWord(*((DWORD*) pBase)); + if ( dwSignature == MSFT_SIGNATURE) + { + *ppTypeLib = ITypeLib2_Constructor_MSFT(pBase, dwTLBLength); + } + else if ( dwSignature == SLTG_SIGNATURE) + { + *ppTypeLib = ITypeLib2_Constructor_SLTG(pBase, dwTLBLength); + } + UnmapViewOfFile(pBase); + } + CloseHandle(hMapping); + } + CloseHandle(hFile); + } + else + { + TRACE("not found, trying to load %s as library\n", debugstr_w(pszFileName)); + } + + /* if the file is a DLL or not found, try loading it with LoadLibrary */ + if (((WORD)dwSignature == IMAGE_DOS_SIGNATURE) || (dwSignature == 0)) + { + /* find the typelibrary resource*/ + HINSTANCE hinstDLL = LoadLibraryExW(pszFileName, 0, DONT_RESOLVE_DLL_REFERENCES| + LOAD_LIBRARY_AS_DATAFILE|LOAD_WITH_ALTERED_SEARCH_PATH); + if (hinstDLL) + { + static const WCHAR TYPELIBW[] = {'T','Y','P','E','L','I','B',0}; + HRSRC hrsrc = FindResourceW(hinstDLL, MAKEINTRESOURCEW(index), TYPELIBW); + if (hrsrc) + { + HGLOBAL hGlobal = LoadResource(hinstDLL, hrsrc); + if (hGlobal) + { + LPVOID pBase = LockResource(hGlobal); + DWORD dwTLBLength = SizeofResource(hinstDLL, hrsrc); + + if (pBase) + { + /* try to load as incore resource */ + dwSignature = FromLEDWord(*((DWORD*) pBase)); + if ( dwSignature == MSFT_SIGNATURE) + { + *ppTypeLib = ITypeLib2_Constructor_MSFT(pBase, dwTLBLength); + } + else if ( dwSignature == SLTG_SIGNATURE) + { + *ppTypeLib = ITypeLib2_Constructor_SLTG(pBase, dwTLBLength); + } + else + { + FIXME("Header type magic 0x%08lx not supported.\n",dwSignature); + } + } + FreeResource( hGlobal ); + } + } + FreeLibrary(hinstDLL); + } + } + + if(*ppTypeLib) { + ITypeLibImpl *impl = (ITypeLibImpl*)*ppTypeLib; + + TRACE("adding to cache\n"); + impl->path = HeapAlloc(GetProcessHeap(), 0, (strlenW(pszFileName)+1) * sizeof(WCHAR)); + lstrcpyW(impl->path, pszFileName); + /* We should really canonicalise the path here. */ + impl->index = index; + + /* FIXME: check if it has added already in the meantime */ + EnterCriticalSection(&cache_section); + if ((impl->next = tlb_cache_first) != NULL) impl->next->prev = impl; + impl->prev = NULL; + tlb_cache_first = impl; + LeaveCriticalSection(&cache_section); + ret = S_OK; + } else + ERR("Loading of typelib %s failed with error %ld\n", debugstr_w(pszFileName), GetLastError()); + + return ret; +} + +/*================== ITypeLib(2) Methods ===================================*/ + +/**************************************************************************** + * ITypeLib2_Constructor_MSFT + * + * loading an MSFT typelib from an in-memory image + */ +static ITypeLib2* ITypeLib2_Constructor_MSFT(LPVOID pLib, DWORD dwTLBLength) +{ + TLBContext cx; + long lPSegDir; + MSFT_Header tlbHeader; + MSFT_SegDir tlbSegDir; + ITypeLibImpl * pTypeLibImpl; + + TRACE("%p, TLB length = %ld\n", pLib, dwTLBLength); + + pTypeLibImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeLibImpl)); + if (!pTypeLibImpl) return NULL; + + pTypeLibImpl->lpVtbl = &tlbvt; + pTypeLibImpl->lpVtblTypeComp = &tlbtcvt; + pTypeLibImpl->ref = 1; + + /* get pointer to beginning of typelib data */ + cx.pos = 0; + cx.oStart=0; + cx.mapping = pLib; + cx.pLibInfo = pTypeLibImpl; + cx.length = dwTLBLength; + + /* read header */ + MSFT_ReadLEDWords((void*)&tlbHeader, sizeof(tlbHeader), &cx, 0); + TRACE("header:\n"); + TRACE("\tmagic1=0x%08x ,magic2=0x%08x\n",tlbHeader.magic1,tlbHeader.magic2 ); + if (tlbHeader.magic1 != MSFT_SIGNATURE) { + FIXME("Header type magic 0x%08x not supported.\n",tlbHeader.magic1); + return NULL; + } + /* there is a small amount of information here until the next important + * part: + * the segment directory . Try to calculate the amount of data */ + lPSegDir = sizeof(tlbHeader) + (tlbHeader.nrtypeinfos)*4 + ((tlbHeader.varflags & HELPDLLFLAG)? 4 :0); + + /* now read the segment directory */ + TRACE("read segment directory (at %ld)\n",lPSegDir); + MSFT_ReadLEDWords(&tlbSegDir, sizeof(tlbSegDir), &cx, lPSegDir); + cx.pTblDir = &tlbSegDir; + + /* just check two entries */ + if ( tlbSegDir.pTypeInfoTab.res0c != 0x0F || tlbSegDir.pImpInfo.res0c != 0x0F) + { + ERR("cannot find the table directory, ptr=0x%lx\n",lPSegDir); + HeapFree(GetProcessHeap(),0,pTypeLibImpl); + return NULL; + } + + /* now fill our internal data */ + /* TLIBATTR fields */ + MSFT_ReadGuid(&pTypeLibImpl->LibAttr.guid, tlbHeader.posguid, &cx); + + /* pTypeLibImpl->LibAttr.lcid = tlbHeader.lcid;*/ + /* Windows seems to have zero here, is this correct? */ + if(SUBLANGID(tlbHeader.lcid) == SUBLANG_NEUTRAL) + pTypeLibImpl->LibAttr.lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(tlbHeader.lcid),0),0); + else + pTypeLibImpl->LibAttr.lcid = 0; + + pTypeLibImpl->LibAttr.syskind = tlbHeader.varflags & 0x0f; /* check the mask */ + pTypeLibImpl->LibAttr.wMajorVerNum = LOWORD(tlbHeader.version); + pTypeLibImpl->LibAttr.wMinorVerNum = HIWORD(tlbHeader.version); + pTypeLibImpl->LibAttr.wLibFlags = (WORD) tlbHeader.flags & 0xffff;/* check mask */ + + /* name, eventually add to a hash table */ + pTypeLibImpl->Name = MSFT_ReadName(&cx, tlbHeader.NameOffset); + + /* help info */ + pTypeLibImpl->DocString = MSFT_ReadString(&cx, tlbHeader.helpstring); + pTypeLibImpl->HelpFile = MSFT_ReadString(&cx, tlbHeader.helpfile); + + if( tlbHeader.varflags & HELPDLLFLAG) + { + int offset; + MSFT_ReadLEDWords(&offset, sizeof(offset), &cx, sizeof(tlbHeader)); + pTypeLibImpl->HelpStringDll = MSFT_ReadString(&cx, offset); + } + + pTypeLibImpl->dwHelpContext = tlbHeader.helpstringcontext; + + /* custom data */ + if(tlbHeader.CustomDataOffset >= 0) + { + pTypeLibImpl->ctCustData = MSFT_CustData(&cx, tlbHeader.CustomDataOffset, &pTypeLibImpl->pCustData); + } + + /* fill in typedescriptions */ + if(tlbSegDir.pTypdescTab.length > 0) + { + int i, j, cTD = tlbSegDir.pTypdescTab.length / (2*sizeof(INT)); + INT16 td[4]; + pTypeLibImpl->pTypeDesc = TLB_Alloc( cTD * sizeof(TYPEDESC)); + MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pTypdescTab.offset); + for(i=0; i<cTD; ) + { + /* FIXME: add several sanity checks here */ + pTypeLibImpl->pTypeDesc[i].vt = td[0] & VT_TYPEMASK; + if(td[0] == VT_PTR || td[0] == VT_SAFEARRAY) + { + /* FIXME: check safearray */ + if(td[3] < 0) + pTypeLibImpl->pTypeDesc[i].u.lptdesc= & stndTypeDesc[td[2]]; + else + pTypeLibImpl->pTypeDesc[i].u.lptdesc= & pTypeLibImpl->pTypeDesc[td[2]/8]; + } + else if(td[0] == VT_CARRAY) + { + /* array descr table here */ + pTypeLibImpl->pTypeDesc[i].u.lpadesc = (void *)((int) td[2]); /* temp store offset in*/ + } + else if(td[0] == VT_USERDEFINED) + { + pTypeLibImpl->pTypeDesc[i].u.hreftype = MAKELONG(td[2],td[3]); + } + if(++i<cTD) MSFT_ReadLEWords(td, sizeof(td), &cx, DO_NOT_SEEK); + } + + /* second time around to fill the array subscript info */ + for(i=0;i<cTD;i++) + { + if(pTypeLibImpl->pTypeDesc[i].vt != VT_CARRAY) continue; + if(tlbSegDir.pArrayDescriptions.offset>0) + { + MSFT_ReadLEWords(td, sizeof(td), &cx, tlbSegDir.pArrayDescriptions.offset + (int) pTypeLibImpl->pTypeDesc[i].u.lpadesc); + pTypeLibImpl->pTypeDesc[i].u.lpadesc = TLB_Alloc(sizeof(ARRAYDESC)+sizeof(SAFEARRAYBOUND)*(td[3]-1)); + + if(td[1]<0) + pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem.vt = td[0] & VT_TYPEMASK; + else + pTypeLibImpl->pTypeDesc[i].u.lpadesc->tdescElem = stndTypeDesc[td[0]/8]; + + pTypeLibImpl->pTypeDesc[i].u.lpadesc->cDims = td[2]; + + for(j = 0; j<td[2]; j++) + { + MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].cElements, + sizeof(INT), &cx, DO_NOT_SEEK); + MSFT_ReadLEDWords(& pTypeLibImpl->pTypeDesc[i].u.lpadesc->rgbounds[j].lLbound, + sizeof(INT), &cx, DO_NOT_SEEK); + } + } + else + { + pTypeLibImpl->pTypeDesc[i].u.lpadesc = NULL; + ERR("didn't find array description data\n"); + } + } + } + + /* imported type libs */ + if(tlbSegDir.pImpFiles.offset>0) + { + TLBImpLib **ppImpLib = &(pTypeLibImpl->pImpLibs); + int oGuid, offset = tlbSegDir.pImpFiles.offset; + UINT16 size; + + while(offset < tlbSegDir.pImpFiles.offset +tlbSegDir.pImpFiles.length) + { + char *name; + DWORD len; + + *ppImpLib = TLB_Alloc(sizeof(TLBImpLib)); + (*ppImpLib)->offset = offset - tlbSegDir.pImpFiles.offset; + MSFT_ReadLEDWords(&oGuid, sizeof(INT), &cx, offset); + + MSFT_ReadLEDWords(&(*ppImpLib)->lcid, sizeof(LCID), &cx, DO_NOT_SEEK); + MSFT_ReadLEWords(&(*ppImpLib)->wVersionMajor, sizeof(WORD), &cx, DO_NOT_SEEK); + MSFT_ReadLEWords(&(*ppImpLib)->wVersionMinor, sizeof(WORD), &cx, DO_NOT_SEEK); + MSFT_ReadLEWords(& size, sizeof(UINT16), &cx, DO_NOT_SEEK); + + size >>= 2; + name = TLB_Alloc(size+1); + MSFT_Read(name, size, &cx, DO_NOT_SEEK); + len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 ); + (*ppImpLib)->name = TLB_Alloc(len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, name, -1, (*ppImpLib)->name, len ); + TLB_Free(name); + + MSFT_ReadGuid(&(*ppImpLib)->guid, oGuid, &cx); + offset = (offset + sizeof(INT) + sizeof(DWORD) + sizeof(LCID) + sizeof(UINT16) + size + 3) & ~3; + + ppImpLib = &(*ppImpLib)->next; + } + } + + /* type info's */ + if(tlbHeader.nrtypeinfos >= 0 ) + { + /*pTypeLibImpl->TypeInfoCount=tlbHeader.nrtypeinfos; */ + ITypeInfoImpl **ppTI = &(pTypeLibImpl->pTypeInfo); + int i; + + for(i = 0; i<(int)tlbHeader.nrtypeinfos; i++) + { + *ppTI = MSFT_DoTypeInfo(&cx, i, pTypeLibImpl); + + ppTI = &((*ppTI)->next); + (pTypeLibImpl->TypeInfoCount)++; + } + } + + TRACE("(%p)\n", pTypeLibImpl); + return (ITypeLib2*) pTypeLibImpl; +} + + +static BSTR TLB_MultiByteToBSTR(char *ptr) +{ + DWORD len; + WCHAR *nameW; + BSTR ret; + + len = MultiByteToWideChar(CP_ACP, 0, ptr, -1, NULL, 0); + nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, ptr, -1, nameW, len); + ret = SysAllocString(nameW); + HeapFree(GetProcessHeap(), 0, nameW); + return ret; +} + +static BOOL TLB_GUIDFromString(char *str, GUID *guid) +{ + char b[3]; + int i; + short s; + + if(sscanf(str, "%lx-%hx-%hx-%hx", &guid->Data1, &guid->Data2, &guid->Data3, &s) != 4) { + FIXME("Can't parse guid %s\n", debugstr_guid(guid)); + return FALSE; + } + + guid->Data4[0] = s >> 8; + guid->Data4[1] = s & 0xff; + + b[2] = '\0'; + for(i = 0; i < 6; i++) { + memcpy(b, str + 24 + 2 * i, 2); + guid->Data4[i + 2] = strtol(b, NULL, 16); + } + return TRUE; +} + +static WORD SLTG_ReadString(char *ptr, BSTR *pBstr) +{ + WORD bytelen; + DWORD len; + WCHAR *nameW; + + *pBstr = NULL; + bytelen = *(WORD*)ptr; + if(bytelen == 0xffff) return 2; + len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, NULL, 0); + nameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + len = MultiByteToWideChar(CP_ACP, 0, ptr + 2, bytelen, nameW, len); + *pBstr = SysAllocStringLen(nameW, len); + HeapFree(GetProcessHeap(), 0, nameW); + return bytelen + 2; +} + +static WORD SLTG_ReadStringA(char *ptr, char **str) +{ + WORD bytelen; + + *str = NULL; + bytelen = *(WORD*)ptr; + if(bytelen == 0xffff) return 2; + *str = HeapAlloc(GetProcessHeap(), 0, bytelen + 1); + memcpy(*str, ptr + 2, bytelen); + (*str)[bytelen] = '\0'; + return bytelen + 2; +} + +static DWORD SLTG_ReadLibBlk(LPVOID pLibBlk, ITypeLibImpl *pTypeLibImpl) +{ + char *ptr = pLibBlk; + WORD w; + + if((w = *(WORD*)ptr) != SLTG_LIBBLK_MAGIC) { + FIXME("libblk magic = %04x\n", w); + return 0; + } + + ptr += 6; + if((w = *(WORD*)ptr) != 0xffff) { + FIXME("LibBlk.res06 = %04x. Assumung string and skipping\n", w); + ptr += w; + } + ptr += 2; + + ptr += SLTG_ReadString(ptr, &pTypeLibImpl->DocString); + + ptr += SLTG_ReadString(ptr, &pTypeLibImpl->HelpFile); + + pTypeLibImpl->dwHelpContext = *(DWORD*)ptr; + ptr += 4; + + pTypeLibImpl->LibAttr.syskind = *(WORD*)ptr; + ptr += 2; + + if(SUBLANGID(*(WORD*)ptr) == SUBLANG_NEUTRAL) + pTypeLibImpl->LibAttr.lcid = MAKELCID(MAKELANGID(PRIMARYLANGID(*(WORD*)ptr),0),0); + else + pTypeLibImpl->LibAttr.lcid = 0; + ptr += 2; + + ptr += 4; /* skip res12 */ + + pTypeLibImpl->LibAttr.wLibFlags = *(WORD*)ptr; + ptr += 2; + + pTypeLibImpl->LibAttr.wMajorVerNum = *(WORD*)ptr; + ptr += 2; + + pTypeLibImpl->LibAttr.wMinorVerNum = *(WORD*)ptr; + ptr += 2; + + memcpy(&pTypeLibImpl->LibAttr.guid, ptr, sizeof(GUID)); + ptr += sizeof(GUID); + + return ptr - (char*)pLibBlk; +} + +static WORD *SLTG_DoType(WORD *pType, char *pBlk, ELEMDESC *pElem) +{ + BOOL done = FALSE; + TYPEDESC *pTD = &pElem->tdesc; + + /* Handle [in/out] first */ + if((*pType & 0xc000) == 0xc000) + pElem->u.paramdesc.wParamFlags = PARAMFLAG_NONE; + else if(*pType & 0x8000) + pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN | PARAMFLAG_FOUT; + else if(*pType & 0x4000) + pElem->u.paramdesc.wParamFlags = PARAMFLAG_FOUT; + else + pElem->u.paramdesc.wParamFlags = PARAMFLAG_FIN; + + if(*pType & 0x2000) + pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FLCID; + + if(*pType & 0x80) + pElem->u.paramdesc.wParamFlags |= PARAMFLAG_FRETVAL; + + while(!done) { + if((*pType & 0xe00) == 0xe00) { + pTD->vt = VT_PTR; + pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(TYPEDESC)); + pTD = pTD->u.lptdesc; + } + switch(*pType & 0x7f) { + case VT_PTR: + pTD->vt = VT_PTR; + pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(TYPEDESC)); + pTD = pTD->u.lptdesc; + break; + + case VT_USERDEFINED: + pTD->vt = VT_USERDEFINED; + pTD->u.hreftype = *(++pType) / 4; + done = TRUE; + break; + + case VT_CARRAY: + { + /* *(pType+1) is offset to a SAFEARRAY, *(pType+2) is type of + array */ + + SAFEARRAY *pSA = (SAFEARRAY *)(pBlk + *(++pType)); + + pTD->vt = VT_CARRAY; + pTD->u.lpadesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(ARRAYDESC) + + (pSA->cDims - 1) * sizeof(SAFEARRAYBOUND)); + pTD->u.lpadesc->cDims = pSA->cDims; + memcpy(pTD->u.lpadesc->rgbounds, pSA->rgsabound, + pSA->cDims * sizeof(SAFEARRAYBOUND)); + + pTD = &pTD->u.lpadesc->tdescElem; + break; + } + + case VT_SAFEARRAY: + { + /* FIXME: *(pType+1) gives an offset to SAFEARRAY, is this + useful? */ + + pType++; + pTD->vt = VT_SAFEARRAY; + pTD->u.lptdesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(TYPEDESC)); + pTD = pTD->u.lptdesc; + break; + } + default: + pTD->vt = *pType & 0x7f; + done = TRUE; + break; + } + pType++; + } + return pType; +} + + +static void SLTG_DoRefs(SLTG_RefInfo *pRef, ITypeInfoImpl *pTI, + char *pNameTable) +{ + int ref; + char *name; + TLBRefType **ppRefType; + + if(pRef->magic != SLTG_REF_MAGIC) { + FIXME("Ref magic = %x\n", pRef->magic); + return; + } + name = ( (char*)(&pRef->names) + pRef->number); + + ppRefType = &pTI->reflist; + for(ref = 0; ref < pRef->number >> 3; ref++) { + char *refname; + unsigned int lib_offs, type_num; + + *ppRefType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(**ppRefType)); + + name += SLTG_ReadStringA(name, &refname); + if(sscanf(refname, "*\\R%x*#%x", &lib_offs, &type_num) != 2) + FIXME("Can't sscanf ref\n"); + if(lib_offs != 0xffff) { + TLBImpLib **import = &pTI->pTypeLib->pImpLibs; + + while(*import) { + if((*import)->offset == lib_offs) + break; + import = &(*import)->next; + } + if(!*import) { + char fname[MAX_PATH+1]; + int len; + + *import = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(**import)); + (*import)->offset = lib_offs; + TLB_GUIDFromString( pNameTable + lib_offs + 4, + &(*import)->guid); + if(sscanf(pNameTable + lib_offs + 40, "}#%hd.%hd#%lx#%s", + &(*import)->wVersionMajor, + &(*import)->wVersionMinor, + &(*import)->lcid, fname) != 4) { + FIXME("can't sscanf ref %s\n", + pNameTable + lib_offs + 40); + } + len = strlen(fname); + if(fname[len-1] != '#') + FIXME("fname = %s\n", fname); + fname[len-1] = '\0'; + (*import)->name = TLB_MultiByteToBSTR(fname); + } + (*ppRefType)->pImpTLInfo = *import; + } else { /* internal ref */ + (*ppRefType)->pImpTLInfo = TLB_REF_INTERNAL; + } + (*ppRefType)->reference = ref; + (*ppRefType)->index = type_num; + + HeapFree(GetProcessHeap(), 0, refname); + ppRefType = &(*ppRefType)->next; + } + if((BYTE)*name != SLTG_REF_MAGIC) + FIXME("End of ref block magic = %x\n", *name); + dump_TLBRefType(pTI->reflist); +} + +static char *SLTG_DoImpls(char *pBlk, ITypeInfoImpl *pTI, + BOOL OneOnly) +{ + SLTG_ImplInfo *info; + TLBImplType **ppImplType = &pTI->impltypelist; + /* I don't really get this structure, usually it's 0x16 bytes + long, but iuser.tlb contains some that are 0x18 bytes long. + That's ok because we can use the next ptr to jump to the next + one. But how do we know the length of the last one? The WORD + at offs 0x8 might be the clue. For now I'm just assuming that + the last one is the regular 0x16 bytes. */ + + info = (SLTG_ImplInfo*)pBlk; + while(1) { + *ppImplType = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(**ppImplType)); + (*ppImplType)->hRef = info->ref; + (*ppImplType)->implflags = info->impltypeflags; + pTI->TypeAttr.cImplTypes++; + ppImplType = &(*ppImplType)->next; + + if(info->next == 0xffff) + break; + if(OneOnly) + FIXME("Interface inheriting more than one interface\n"); + info = (SLTG_ImplInfo*)(pBlk + info->next); + } + info++; /* see comment at top of function */ + return (char*)info; +} + +static SLTG_TypeInfoTail *SLTG_ProcessCoClass(char *pBlk, ITypeInfoImpl *pTI, + char *pNameTable) +{ + SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk; + SLTG_MemberHeader *pMemHeader; + char *pFirstItem, *pNextItem; + + if(pTIHeader->href_table != 0xffffffff) { + SLTG_DoRefs((SLTG_RefInfo*)(pBlk + pTIHeader->href_table), pTI, + pNameTable); + } + + + pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table); + + pFirstItem = pNextItem = (char*)(pMemHeader + 1); + + if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) { + pNextItem = SLTG_DoImpls(pFirstItem, pTI, FALSE); + } + + return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra); +} + + +static SLTG_TypeInfoTail *SLTG_ProcessInterface(char *pBlk, ITypeInfoImpl *pTI, + char *pNameTable) +{ + SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk; + SLTG_MemberHeader *pMemHeader; + SLTG_Function *pFunc; + char *pFirstItem, *pNextItem; + TLBFuncDesc **ppFuncDesc = &pTI->funclist; + int num = 0; + + if(pTIHeader->href_table != 0xffffffff) { + SLTG_DoRefs((SLTG_RefInfo*)(pBlk + pTIHeader->href_table), pTI, + pNameTable); + } + + pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table); + + pFirstItem = pNextItem = (char*)(pMemHeader + 1); + + if(*(WORD*)pFirstItem == SLTG_IMPL_MAGIC) { + pNextItem = SLTG_DoImpls(pFirstItem, pTI, TRUE); + } + + for(pFunc = (SLTG_Function*)pNextItem, num = 1; 1; + pFunc = (SLTG_Function*)(pFirstItem + pFunc->next), num++) { + + int param; + WORD *pType, *pArg; + + if(pFunc->magic != SLTG_FUNCTION_MAGIC && + pFunc->magic != SLTG_FUNCTION_WITH_FLAGS_MAGIC) { + FIXME("func magic = %02x\n", pFunc->magic); + return NULL; + } + *ppFuncDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(**ppFuncDesc)); + (*ppFuncDesc)->Name = TLB_MultiByteToBSTR(pFunc->name + pNameTable); + + (*ppFuncDesc)->funcdesc.memid = pFunc->dispid; + (*ppFuncDesc)->funcdesc.invkind = pFunc->inv >> 4; + (*ppFuncDesc)->funcdesc.callconv = pFunc->nacc & 0x7; + (*ppFuncDesc)->funcdesc.cParams = pFunc->nacc >> 3; + (*ppFuncDesc)->funcdesc.cParamsOpt = (pFunc->retnextopt & 0x7e) >> 1; + (*ppFuncDesc)->funcdesc.oVft = pFunc->vtblpos; + + if(pFunc->magic == SLTG_FUNCTION_WITH_FLAGS_MAGIC) + (*ppFuncDesc)->funcdesc.wFuncFlags = pFunc->funcflags; + + if(pFunc->retnextopt & 0x80) + pType = &pFunc->rettype; + else + pType = (WORD*)(pFirstItem + pFunc->rettype); + + + SLTG_DoType(pType, pFirstItem, &(*ppFuncDesc)->funcdesc.elemdescFunc); + + (*ppFuncDesc)->funcdesc.lprgelemdescParam = + HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + (*ppFuncDesc)->funcdesc.cParams * sizeof(ELEMDESC)); + (*ppFuncDesc)->pParamDesc = + HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + (*ppFuncDesc)->funcdesc.cParams * sizeof(TLBParDesc)); + + pArg = (WORD*)(pFirstItem + pFunc->arg_off); + + for(param = 0; param < (*ppFuncDesc)->funcdesc.cParams; param++) { + char *paramName = pNameTable + *pArg; + BOOL HaveOffs; + /* If arg type follows then paramName points to the 2nd + letter of the name, else the next WORD is an offset to + the arg type and paramName points to the first letter. + So let's take one char off paramName and see if we're + pointing at an alpha-numeric char. However if *pArg is + 0xffff or 0xfffe then the param has no name, the former + meaning that the next WORD is the type, the latter + meaning the the next WORD is an offset to the type. */ + + HaveOffs = FALSE; + if(*pArg == 0xffff) + paramName = NULL; + else if(*pArg == 0xfffe) { + paramName = NULL; + HaveOffs = TRUE; + } + else if(!isalnum(*(paramName-1))) + HaveOffs = TRUE; + + pArg++; + + if(HaveOffs) { /* the next word is an offset to type */ + pType = (WORD*)(pFirstItem + *pArg); + SLTG_DoType(pType, pFirstItem, + &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param]); + pArg++; + } else { + if(paramName) + paramName--; + pArg = SLTG_DoType(pArg, pFirstItem, + &(*ppFuncDesc)->funcdesc.lprgelemdescParam[param]); + } + + /* Are we an optional param ? */ + if((*ppFuncDesc)->funcdesc.cParams - param <= + (*ppFuncDesc)->funcdesc.cParamsOpt) + (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].u.paramdesc.wParamFlags |= PARAMFLAG_FOPT; + + if(paramName) { + (*ppFuncDesc)->pParamDesc[param].Name = + TLB_MultiByteToBSTR(paramName); + } + } + + ppFuncDesc = &((*ppFuncDesc)->next); + if(pFunc->next == 0xffff) break; + } + pTI->TypeAttr.cFuncs = num; + dump_TLBFuncDesc(pTI->funclist); + return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra); +} + +static SLTG_TypeInfoTail *SLTG_ProcessRecord(char *pBlk, ITypeInfoImpl *pTI, + char *pNameTable) +{ + SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk; + SLTG_MemberHeader *pMemHeader; + SLTG_RecordItem *pItem; + char *pFirstItem; + TLBVarDesc **ppVarDesc = &pTI->varlist; + int num = 0; + WORD *pType; + char buf[300]; + + pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table); + + pFirstItem = (char*)(pMemHeader + 1); + for(pItem = (SLTG_RecordItem *)pFirstItem, num = 1; 1; + pItem = (SLTG_RecordItem *)(pFirstItem + pItem->next), num++) { + if(pItem->magic != SLTG_RECORD_MAGIC) { + FIXME("record magic = %02x\n", pItem->magic); + return NULL; + } + *ppVarDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(**ppVarDesc)); + (*ppVarDesc)->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable); + (*ppVarDesc)->vardesc.memid = pItem->memid; + (*ppVarDesc)->vardesc.u.oInst = pItem->byte_offs; + (*ppVarDesc)->vardesc.varkind = VAR_PERINSTANCE; + + if(pItem->typepos == 0x02) + pType = &pItem->type; + else if(pItem->typepos == 0x00) + pType = (WORD*)(pFirstItem + pItem->type); + else { + FIXME("typepos = %02x\n", pItem->typepos); + break; + } + + SLTG_DoType(pType, pFirstItem, + &(*ppVarDesc)->vardesc.elemdescVar); + + /* FIXME("helpcontext, helpstring\n"); */ + + dump_TypeDesc(&(*ppVarDesc)->vardesc.elemdescVar.tdesc, buf); + + ppVarDesc = &((*ppVarDesc)->next); + if(pItem->next == 0xffff) break; + } + pTI->TypeAttr.cVars = num; + return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra); +} + +static SLTG_TypeInfoTail *SLTG_ProcessAlias(char *pBlk, ITypeInfoImpl *pTI, + char *pNameTable) +{ + SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk; + SLTG_MemberHeader *pMemHeader; + SLTG_AliasItem *pItem; + int i, mustbelast; + + pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table); + pItem = (SLTG_AliasItem*)(pMemHeader + 1); + + mustbelast = 0; + /* This is used for creating a TYPEDESC chain in case of VT_USERDEFINED */ + for (i = 0 ; i<pMemHeader->cbExtra/4 ; i++) { + if (pItem->vt == 0xffff) { + if (i<(pMemHeader->cbExtra/4-1)) + FIXME("Endmarker too early in process alias data!\n"); + break; + } + if (mustbelast) { + FIXME("Chain extends over last entry?\n"); + break; + } + if (pItem->vt == VT_USERDEFINED) { + pTI->TypeAttr.tdescAlias.vt = pItem->vt; + /* guessing here ... */ + FIXME("Guessing TKIND_ALIAS of VT_USERDEFINED with hreftype 0x%x\n",pItem->res02); + pTI->TypeAttr.tdescAlias.u.hreftype = pItem->res02; + mustbelast = 1; + } else { + FIXME("alias %d: 0x%x\n",i,pItem->vt); + FIXME("alias %d: 0x%x\n",i,pItem->res02); + } + pItem++; + } + return (SLTG_TypeInfoTail*)((char*)(pMemHeader + 1)+pMemHeader->cbExtra); +} + +static SLTG_TypeInfoTail *SLTG_ProcessDispatch(char *pBlk, ITypeInfoImpl *pTI, + char *pNameTable) +{ + SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk; + SLTG_MemberHeader *pMemHeader; + SLTG_AliasItem *pItem; + + pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table); + pItem = (SLTG_AliasItem*)(pMemHeader + 1); + FIXME("memh.cbExtra is %ld\n",pMemHeader->cbExtra); + FIXME("offset 0 0x%x\n",*(WORD*)pItem); + return (SLTG_TypeInfoTail*)((char*)(pMemHeader + 1)+pMemHeader->cbExtra); +} + +static SLTG_TypeInfoTail *SLTG_ProcessEnum(char *pBlk, ITypeInfoImpl *pTI, + char *pNameTable) +{ + SLTG_TypeInfoHeader *pTIHeader = (SLTG_TypeInfoHeader*)pBlk; + SLTG_MemberHeader *pMemHeader; + SLTG_EnumItem *pItem; + char *pFirstItem; + TLBVarDesc **ppVarDesc = &pTI->varlist; + int num = 0; + + pMemHeader = (SLTG_MemberHeader*)(pBlk + pTIHeader->elem_table); + + pFirstItem = (char*)(pMemHeader + 1); + for(pItem = (SLTG_EnumItem *)pFirstItem, num = 1; 1; + pItem = (SLTG_EnumItem *)(pFirstItem + pItem->next), num++) { + if(pItem->magic != SLTG_ENUMITEM_MAGIC) { + FIXME("enumitem magic = %04x\n", pItem->magic); + return NULL; + } + *ppVarDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(**ppVarDesc)); + (*ppVarDesc)->Name = TLB_MultiByteToBSTR(pItem->name + pNameTable); + (*ppVarDesc)->vardesc.memid = pItem->memid; + (*ppVarDesc)->vardesc.u.lpvarValue = HeapAlloc(GetProcessHeap(), 0, + sizeof(VARIANT)); + V_VT((*ppVarDesc)->vardesc.u.lpvarValue) = VT_INT; + V_UNION((*ppVarDesc)->vardesc.u.lpvarValue, intVal) = + *(INT*)(pItem->value + pFirstItem); + (*ppVarDesc)->vardesc.elemdescVar.tdesc.vt = VT_I4; + (*ppVarDesc)->vardesc.varkind = VAR_CONST; + /* FIXME("helpcontext, helpstring\n"); */ + + ppVarDesc = &((*ppVarDesc)->next); + if(pItem->next == 0xffff) break; + } + pTI->TypeAttr.cVars = num; + return (SLTG_TypeInfoTail*)(pFirstItem + pMemHeader->cbExtra); +} + +/* Because SLTG_OtherTypeInfo is such a painful struct, we make a more + managable copy of it into this */ +typedef struct { + WORD small_no; + char *index_name; + char *other_name; + WORD res1a; + WORD name_offs; + WORD more_bytes; + char *extra; + WORD res20; + DWORD helpcontext; + WORD res26; + GUID uuid; +} SLTG_InternalOtherTypeInfo; + +/**************************************************************************** + * ITypeLib2_Constructor_SLTG + * + * loading a SLTG typelib from an in-memory image + */ +static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength) +{ + ITypeLibImpl *pTypeLibImpl; + SLTG_Header *pHeader; + SLTG_BlkEntry *pBlkEntry; + SLTG_Magic *pMagic; + SLTG_Index *pIndex; + SLTG_Pad9 *pPad9; + LPVOID pBlk, pFirstBlk; + SLTG_LibBlk *pLibBlk; + SLTG_InternalOtherTypeInfo *pOtherTypeInfoBlks; + char *pAfterOTIBlks = NULL; + char *pNameTable, *ptr; + int i; + DWORD len, order; + ITypeInfoImpl **ppTypeInfoImpl; + + TRACE("%p, TLB length = %ld\n", pLib, dwTLBLength); + + pTypeLibImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeLibImpl)); + if (!pTypeLibImpl) return NULL; + + pTypeLibImpl->lpVtbl = &tlbvt; + pTypeLibImpl->ref = 1; + + pHeader = pLib; + + TRACE("header:\n"); + TRACE("\tmagic=0x%08lx, file blocks = %d\n", pHeader->SLTG_magic, + pHeader->nrOfFileBlks ); + if (pHeader->SLTG_magic != SLTG_SIGNATURE) { + FIXME("Header type magic 0x%08lx not supported.\n", + pHeader->SLTG_magic); + return NULL; + } + + /* There are pHeader->nrOfFileBlks - 2 TypeInfo records in this typelib */ + pTypeLibImpl->TypeInfoCount = pHeader->nrOfFileBlks - 2; + + /* This points to pHeader->nrOfFileBlks - 1 of SLTG_BlkEntry */ + pBlkEntry = (SLTG_BlkEntry*)(pHeader + 1); + + /* Next we have a magic block */ + pMagic = (SLTG_Magic*)(pBlkEntry + pHeader->nrOfFileBlks - 1); + + /* Let's see if we're still in sync */ + if(memcmp(pMagic->CompObj_magic, SLTG_COMPOBJ_MAGIC, + sizeof(SLTG_COMPOBJ_MAGIC))) { + FIXME("CompObj magic = %s\n", pMagic->CompObj_magic); + return NULL; + } + if(memcmp(pMagic->dir_magic, SLTG_DIR_MAGIC, + sizeof(SLTG_DIR_MAGIC))) { + FIXME("dir magic = %s\n", pMagic->dir_magic); + return NULL; + } + + pIndex = (SLTG_Index*)(pMagic+1); + + pPad9 = (SLTG_Pad9*)(pIndex + pTypeLibImpl->TypeInfoCount); + + pFirstBlk = (LPVOID)(pPad9 + 1); + + /* We'll set up a ptr to the main library block, which is the last one. */ + + for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0; + pBlkEntry[order].next != 0; + order = pBlkEntry[order].next - 1, i++) { + pBlk = (char*)pBlk + pBlkEntry[order].len; + } + pLibBlk = pBlk; + + len = SLTG_ReadLibBlk(pLibBlk, pTypeLibImpl); + + /* Now there's 0x40 bytes of 0xffff with the numbers 0 to TypeInfoCount + interspersed */ + + len += 0x40; + + /* And now TypeInfoCount of SLTG_OtherTypeInfo */ + + pOtherTypeInfoBlks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(*pOtherTypeInfoBlks) * + pTypeLibImpl->TypeInfoCount); + + + ptr = (char*)pLibBlk + len; + + for(i = 0; i < pTypeLibImpl->TypeInfoCount; i++) { + WORD w, extra; + len = 0; + + pOtherTypeInfoBlks[i].small_no = *(WORD*)ptr; + + w = *(WORD*)(ptr + 2); + if(w != 0xffff) { + len += w; + pOtherTypeInfoBlks[i].index_name = HeapAlloc(GetProcessHeap(),0, + w+1); + memcpy(pOtherTypeInfoBlks[i].index_name, ptr + 4, w); + pOtherTypeInfoBlks[i].index_name[w] = '\0'; + } + w = *(WORD*)(ptr + 4 + len); + if(w != 0xffff) { + TRACE("\twith %s\n", debugstr_an(ptr + 6 + len, w)); + len += w; + pOtherTypeInfoBlks[i].other_name = HeapAlloc(GetProcessHeap(),0, + w+1); + memcpy(pOtherTypeInfoBlks[i].other_name, ptr + 6 + len, w); + pOtherTypeInfoBlks[i].other_name[w] = '\0'; + } + pOtherTypeInfoBlks[i].res1a = *(WORD*)(ptr + len + 6); + pOtherTypeInfoBlks[i].name_offs = *(WORD*)(ptr + len + 8); + extra = pOtherTypeInfoBlks[i].more_bytes = *(WORD*)(ptr + 10 + len); + if(extra) { + pOtherTypeInfoBlks[i].extra = HeapAlloc(GetProcessHeap(),0, + extra); + memcpy(pOtherTypeInfoBlks[i].extra, ptr + 12, extra); + len += extra; + } + pOtherTypeInfoBlks[i].res20 = *(WORD*)(ptr + 12 + len); + pOtherTypeInfoBlks[i].helpcontext = *(DWORD*)(ptr + 14 + len); + pOtherTypeInfoBlks[i].res26 = *(WORD*)(ptr + 18 + len); + memcpy(&pOtherTypeInfoBlks[i].uuid, ptr + 20 + len, sizeof(GUID)); + len += sizeof(SLTG_OtherTypeInfo); + ptr += len; + } + + pAfterOTIBlks = ptr; + + /* Skip this WORD and get the next DWORD */ + len = *(DWORD*)(pAfterOTIBlks + 2); + + /* Now add this to pLibBLk look at what we're pointing at and + possibly add 0x20, then add 0x216, sprinkle a bit a magic + dust and we should be pointing at the beginning of the name + table */ + + pNameTable = (char*)pLibBlk + len; + + switch(*(WORD*)pNameTable) { + case 0xffff: + break; + case 0x0200: + pNameTable += 0x20; + break; + default: + FIXME("pNameTable jump = %x\n", *(WORD*)pNameTable); + break; + } + + pNameTable += 0x216; + + pNameTable += 2; + + TRACE("Library name is %s\n", pNameTable + pLibBlk->name); + + pTypeLibImpl->Name = TLB_MultiByteToBSTR(pNameTable + pLibBlk->name); + + + /* Hopefully we now have enough ptrs set up to actually read in + some TypeInfos. It's not clear which order to do them in, so + I'll just follow the links along the BlkEntry chain and read + them in in the order in which they're in the file */ + + ppTypeInfoImpl = &(pTypeLibImpl->pTypeInfo); + + for(pBlk = pFirstBlk, order = pHeader->first_blk - 1, i = 0; + pBlkEntry[order].next != 0; + order = pBlkEntry[order].next - 1, i++) { + + SLTG_TypeInfoHeader *pTIHeader; + SLTG_TypeInfoTail *pTITail; + + if(strcmp(pBlkEntry[order].index_string + (char*)pMagic, + pOtherTypeInfoBlks[i].index_name)) { + FIXME("Index strings don't match\n"); + return NULL; + } + + pTIHeader = pBlk; + if(pTIHeader->magic != SLTG_TIHEADER_MAGIC) { + FIXME("TypeInfoHeader magic = %04x\n", pTIHeader->magic); + return NULL; + } + *ppTypeInfoImpl = (ITypeInfoImpl*)ITypeInfo_Constructor(); + (*ppTypeInfoImpl)->pTypeLib = pTypeLibImpl; + (*ppTypeInfoImpl)->index = i; + (*ppTypeInfoImpl)->Name = TLB_MultiByteToBSTR( + pOtherTypeInfoBlks[i].name_offs + + pNameTable); + (*ppTypeInfoImpl)->dwHelpContext = pOtherTypeInfoBlks[i].helpcontext; + memcpy(&((*ppTypeInfoImpl)->TypeAttr.guid), &pOtherTypeInfoBlks[i].uuid, + sizeof(GUID)); + (*ppTypeInfoImpl)->TypeAttr.typekind = pTIHeader->typekind; + (*ppTypeInfoImpl)->TypeAttr.wMajorVerNum = pTIHeader->major_version; + (*ppTypeInfoImpl)->TypeAttr.wMinorVerNum = pTIHeader->minor_version; + (*ppTypeInfoImpl)->TypeAttr.wTypeFlags = + (pTIHeader->typeflags1 >> 3) | (pTIHeader->typeflags2 << 5); + + if((pTIHeader->typeflags1 & 7) != 2) + FIXME("typeflags1 = %02x\n", pTIHeader->typeflags1); + if(pTIHeader->typeflags3 != 2) + FIXME("typeflags3 = %02x\n", pTIHeader->typeflags3); + + TRACE("TypeInfo %s of kind %s guid %s typeflags %04x\n", + debugstr_w((*ppTypeInfoImpl)->Name), + typekind_desc[pTIHeader->typekind], + debugstr_guid(&(*ppTypeInfoImpl)->TypeAttr.guid), + (*ppTypeInfoImpl)->TypeAttr.wTypeFlags); + + switch(pTIHeader->typekind) { + case TKIND_ENUM: + pTITail = SLTG_ProcessEnum(pBlk, *ppTypeInfoImpl, pNameTable); + break; + + case TKIND_RECORD: + pTITail = SLTG_ProcessRecord(pBlk, *ppTypeInfoImpl, pNameTable); + break; + + case TKIND_INTERFACE: + pTITail = SLTG_ProcessInterface(pBlk, *ppTypeInfoImpl, pNameTable); + break; + + case TKIND_COCLASS: + pTITail = SLTG_ProcessCoClass(pBlk, *ppTypeInfoImpl, pNameTable); + break; + + case TKIND_ALIAS: + pTITail = SLTG_ProcessAlias(pBlk, *ppTypeInfoImpl, pNameTable); + if (pTITail->tdescalias_vt) + (*ppTypeInfoImpl)->TypeAttr.tdescAlias.vt = pTITail->tdescalias_vt; + break; + + case TKIND_DISPATCH: + pTITail = SLTG_ProcessDispatch(pBlk, *ppTypeInfoImpl, pNameTable); + break; + + default: + FIXME("Not processing typekind %d\n", pTIHeader->typekind); + pTITail = NULL; + break; + + } + + if(pTITail) { /* could get cFuncs, cVars and cImplTypes from here + but we've already set those */ + (*ppTypeInfoImpl)->TypeAttr.cbAlignment = pTITail->cbAlignment; + (*ppTypeInfoImpl)->TypeAttr.cbSizeInstance = pTITail->cbSizeInstance; + (*ppTypeInfoImpl)->TypeAttr.cbSizeVft = pTITail->cbSizeVft; + +#define X(x) TRACE("tt "#x": %x\n",pTITail->res##x); + X(06); + X(08); + X(0a); + X(0c); + X(0e); + X(10); + X(12); + X(16); + X(18); + X(1a); + X(1c); + X(1e); + X(24); + X(26); + X(2a); + X(2c); + X(2e); + X(30); + X(32); + X(34); + } + ppTypeInfoImpl = &((*ppTypeInfoImpl)->next); + pBlk = (char*)pBlk + pBlkEntry[order].len; + } + + if(i != pTypeLibImpl->TypeInfoCount) { + FIXME("Somehow processed %d TypeInfos\n", i); + return NULL; + } + + HeapFree(GetProcessHeap(), 0, pOtherTypeInfoBlks); + return (ITypeLib2*)pTypeLibImpl; +} + +/* ITypeLib::QueryInterface + */ +static HRESULT WINAPI ITypeLib2_fnQueryInterface( + ITypeLib2 * iface, + REFIID riid, + VOID **ppvObject) +{ + ITypeLibImpl *This = (ITypeLibImpl *)iface; + + TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid)); + + *ppvObject=NULL; + if(IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid,&IID_ITypeLib)|| + IsEqualIID(riid,&IID_ITypeLib2)) + { + *ppvObject = This; + } + + if(*ppvObject) + { + ITypeLib2_AddRef(iface); + TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject); + return S_OK; + } + TRACE("-- Interface: E_NOINTERFACE\n"); + return E_NOINTERFACE; +} + +/* ITypeLib::AddRef + */ +static ULONG WINAPI ITypeLib2_fnAddRef( ITypeLib2 *iface) +{ + ITypeLibImpl *This = (ITypeLibImpl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p)->ref was %lu\n",This, ref - 1); + + return ref; +} + +/* ITypeLib::Release + */ +static ULONG WINAPI ITypeLib2_fnRelease( ITypeLib2 *iface) +{ + ITypeLibImpl *This = (ITypeLibImpl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(%lu)\n",This, ref); + + if (!ref) + { + /* remove cache entry */ + TRACE("removing from cache list\n"); + EnterCriticalSection(&cache_section); + if (This->next) This->next->prev = This->prev; + if (This->prev) This->prev->next = This->next; + else tlb_cache_first = This->next; + LeaveCriticalSection(&cache_section); + + /* FIXME destroy child objects */ + TRACE(" destroying ITypeLib(%p)\n",This); + + if (This->Name) + { + SysFreeString(This->Name); + This->Name = NULL; + } + + if (This->DocString) + { + SysFreeString(This->DocString); + This->DocString = NULL; + } + + if (This->HelpFile) + { + SysFreeString(This->HelpFile); + This->HelpFile = NULL; + } + + if (This->HelpStringDll) + { + SysFreeString(This->HelpStringDll); + This->HelpStringDll = NULL; + } + + if (This->pTypeInfo) /* can be NULL */ + ITypeInfo_Release((ITypeInfo*) This->pTypeInfo); + HeapFree(GetProcessHeap(),0,This); + return 0; + } + + return ref; +} + +/* ITypeLib::GetTypeInfoCount + * + * Returns the number of type descriptions in the type library + */ +static UINT WINAPI ITypeLib2_fnGetTypeInfoCount( ITypeLib2 *iface) +{ + ITypeLibImpl *This = (ITypeLibImpl *)iface; + TRACE("(%p)->count is %d\n",This, This->TypeInfoCount); + return This->TypeInfoCount; +} + +/* ITypeLib::GetTypeInfo + * + * retrieves the specified type description in the library. + */ +static HRESULT WINAPI ITypeLib2_fnGetTypeInfo( + ITypeLib2 *iface, + UINT index, + ITypeInfo **ppTInfo) +{ + int i; + + ITypeLibImpl *This = (ITypeLibImpl *)iface; + ITypeInfoImpl *pTypeInfo = This->pTypeInfo; + + TRACE("(%p)->(index=%d) \n", This, index); + + if (!ppTInfo) return E_INVALIDARG; + + /* search element n in list */ + for(i=0; i < index; i++) + { + pTypeInfo = pTypeInfo->next; + if (!pTypeInfo) + { + TRACE("-- element not found\n"); + return TYPE_E_ELEMENTNOTFOUND; + } + } + + *ppTInfo = (ITypeInfo *) pTypeInfo; + + ITypeInfo_AddRef(*ppTInfo); + TRACE("-- found (%p)\n",*ppTInfo); + return S_OK; +} + + +/* ITypeLibs::GetTypeInfoType + * + * Retrieves the type of a type description. + */ +static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType( + ITypeLib2 *iface, + UINT index, + TYPEKIND *pTKind) +{ + ITypeLibImpl *This = (ITypeLibImpl *)iface; + int i; + ITypeInfoImpl *pTInfo = This->pTypeInfo; + + TRACE("(%p) index %d \n",This, index); + + if(!pTKind) return E_INVALIDARG; + + /* search element n in list */ + for(i=0; i < index; i++) + { + if(!pTInfo) + { + TRACE("-- element not found\n"); + return TYPE_E_ELEMENTNOTFOUND; + } + pTInfo = pTInfo->next; + } + + *pTKind = pTInfo->TypeAttr.typekind; + TRACE("-- found Type (%d)\n", *pTKind); + return S_OK; +} + +/* ITypeLib::GetTypeInfoOfGuid + * + * Retrieves the type description that corresponds to the specified GUID. + * + */ +static HRESULT WINAPI ITypeLib2_fnGetTypeInfoOfGuid( + ITypeLib2 *iface, + REFGUID guid, + ITypeInfo **ppTInfo) +{ + ITypeLibImpl *This = (ITypeLibImpl *)iface; + ITypeInfoImpl *pTypeInfo = This->pTypeInfo; /* head of list */ + + TRACE("(%p)\n\tguid:\t%s)\n",This,debugstr_guid(guid)); + + if (!pTypeInfo) return TYPE_E_ELEMENTNOTFOUND; + + /* search linked list for guid */ + while( !IsEqualIID(guid,&pTypeInfo->TypeAttr.guid) ) + { + pTypeInfo = pTypeInfo->next; + + if (!pTypeInfo) + { + /* end of list reached */ + TRACE("-- element not found\n"); + return TYPE_E_ELEMENTNOTFOUND; + } + } + + TRACE("-- found (%p, %s)\n", + pTypeInfo, + debugstr_w(pTypeInfo->Name)); + + *ppTInfo = (ITypeInfo*)pTypeInfo; + ITypeInfo_AddRef(*ppTInfo); + return S_OK; +} + +/* ITypeLib::GetLibAttr + * + * Retrieves the structure that contains the library's attributes. + * + */ +static HRESULT WINAPI ITypeLib2_fnGetLibAttr( + ITypeLib2 *iface, + LPTLIBATTR *ppTLibAttr) +{ + ITypeLibImpl *This = (ITypeLibImpl *)iface; + TRACE("(%p)\n",This); + *ppTLibAttr = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppTLibAttr)); + memcpy(*ppTLibAttr, &This->LibAttr, sizeof(**ppTLibAttr)); + return S_OK; +} + +/* ITypeLib::GetTypeComp + * + * Enables a client compiler to bind to a library's types, variables, + * constants, and global functions. + * + */ +static HRESULT WINAPI ITypeLib2_fnGetTypeComp( + ITypeLib2 *iface, + ITypeComp **ppTComp) +{ + ITypeLibImpl *This = (ITypeLibImpl *)iface; + + TRACE("(%p)->(%p)\n",This,ppTComp); + *ppTComp = (ITypeComp *)&This->lpVtblTypeComp; + ITypeComp_AddRef(*ppTComp); + + return S_OK; +} + +/* ITypeLib::GetDocumentation + * + * Retrieves the library's documentation string, the complete Help file name + * and path, and the context identifier for the library Help topic in the Help + * file. + * + * On a successful return all non-null BSTR pointers will have been set, + * possibly to NULL. + */ +static HRESULT WINAPI ITypeLib2_fnGetDocumentation( + ITypeLib2 *iface, + INT index, + BSTR *pBstrName, + BSTR *pBstrDocString, + DWORD *pdwHelpContext, + BSTR *pBstrHelpFile) +{ + ITypeLibImpl *This = (ITypeLibImpl *)iface; + + HRESULT result = E_INVALIDARG; + + ITypeInfo *pTInfo; + + + TRACE("(%p) index %d Name(%p) DocString(%p) HelpContext(%p) HelpFile(%p)\n", + This, index, + pBstrName, pBstrDocString, + pdwHelpContext, pBstrHelpFile); + + if(index<0) + { + /* documentation for the typelib */ + if(pBstrName) + { + if (This->Name) + if(!(*pBstrName = SysAllocString(This->Name))) goto memerr1;else; + else + *pBstrName = NULL; + } + if(pBstrDocString) + { + if (This->DocString) + if(!(*pBstrDocString = SysAllocString(This->DocString))) goto memerr2;else; + else if (This->Name) + if(!(*pBstrDocString = SysAllocString(This->Name))) goto memerr2;else; + else + *pBstrDocString = NULL; + } + if(pdwHelpContext) + { + *pdwHelpContext = This->dwHelpContext; + } + if(pBstrHelpFile) + { + if (This->HelpFile) + if(!(*pBstrHelpFile = SysAllocString(This->HelpFile))) goto memerr3;else; + else + *pBstrHelpFile = NULL; + } + + result = S_OK; + } + else + { + /* for a typeinfo */ + result = ITypeLib2_fnGetTypeInfo(iface, index, &pTInfo); + + if(SUCCEEDED(result)) + { + result = ITypeInfo_GetDocumentation(pTInfo, + MEMBERID_NIL, + pBstrName, + pBstrDocString, + pdwHelpContext, pBstrHelpFile); + + ITypeInfo_Release(pTInfo); + } + } + return result; +memerr3: + if (pBstrDocString) SysFreeString (*pBstrDocString); +memerr2: + if (pBstrName) SysFreeString (*pBstrName); +memerr1: + return STG_E_INSUFFICIENTMEMORY; +} + +/* ITypeLib::IsName + * + * Indicates whether a passed-in string contains the name of a type or member + * described in the library. + * + */ +static HRESULT WINAPI ITypeLib2_fnIsName( + ITypeLib2 *iface, + LPOLESTR szNameBuf, + ULONG lHashVal, + BOOL *pfName) +{ + ITypeLibImpl *This = (ITypeLibImpl *)iface; + ITypeInfoImpl *pTInfo; + TLBFuncDesc *pFInfo; + TLBVarDesc *pVInfo; + int i; + UINT nNameBufLen = SysStringLen(szNameBuf); + + TRACE("(%p)->(%s,%08lx,%p)\n", This, debugstr_w(szNameBuf), lHashVal, + pfName); + + *pfName=TRUE; + for(pTInfo=This->pTypeInfo;pTInfo;pTInfo=pTInfo->next){ + if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit; + for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) { + if(!memcmp(szNameBuf,pFInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit; + for(i=0;i<pFInfo->funcdesc.cParams;i++) + if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name, nNameBufLen)) + goto ITypeLib2_fnIsName_exit; + } + for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next) + if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnIsName_exit; + + } + *pfName=FALSE; + +ITypeLib2_fnIsName_exit: + TRACE("(%p)slow! search for %s: %s found!\n", This, + debugstr_w(szNameBuf), *pfName?"NOT":""); + + return S_OK; +} + +/* ITypeLib::FindName + * + * Finds occurrences of a type description in a type library. This may be used + * to quickly verify that a name exists in a type library. + * + */ +static HRESULT WINAPI ITypeLib2_fnFindName( + ITypeLib2 *iface, + LPOLESTR szNameBuf, + ULONG lHashVal, + ITypeInfo **ppTInfo, + MEMBERID *rgMemId, + UINT16 *pcFound) +{ + ITypeLibImpl *This = (ITypeLibImpl *)iface; + ITypeInfoImpl *pTInfo; + TLBFuncDesc *pFInfo; + TLBVarDesc *pVInfo; + int i,j = 0; + + UINT nNameBufLen = SysStringLen(szNameBuf); + + for(pTInfo=This->pTypeInfo;pTInfo && j<*pcFound; pTInfo=pTInfo->next){ + if(!memcmp(szNameBuf,pTInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit; + for(pFInfo=pTInfo->funclist;pFInfo;pFInfo=pFInfo->next) { + if(!memcmp(szNameBuf,pFInfo->Name,nNameBufLen)) goto ITypeLib2_fnFindName_exit; + for(i=0;i<pFInfo->funcdesc.cParams;i++) + if(!memcmp(szNameBuf,pFInfo->pParamDesc[i].Name,nNameBufLen)) + goto ITypeLib2_fnFindName_exit; + } + for(pVInfo=pTInfo->varlist;pVInfo;pVInfo=pVInfo->next) + if(!memcmp(szNameBuf,pVInfo->Name, nNameBufLen)) goto ITypeLib2_fnFindName_exit; + continue; +ITypeLib2_fnFindName_exit: + ITypeInfo_AddRef((ITypeInfo*)pTInfo); + ppTInfo[j]=(LPTYPEINFO)pTInfo; + j++; + } + TRACE("(%p)slow! search for %d with %s: found %d TypeInfo's!\n", + This, *pcFound, debugstr_w(szNameBuf), j); + + *pcFound=j; + + return S_OK; +} + +/* ITypeLib::ReleaseTLibAttr + * + * Releases the TLIBATTR originally obtained from ITypeLib::GetLibAttr. + * + */ +static VOID WINAPI ITypeLib2_fnReleaseTLibAttr( + ITypeLib2 *iface, + TLIBATTR *pTLibAttr) +{ + ITypeLibImpl *This = (ITypeLibImpl *)iface; + TRACE("freeing (%p)\n",This); + HeapFree(GetProcessHeap(),0,pTLibAttr); + +} + +/* ITypeLib2::GetCustData + * + * gets the custom data + */ +static HRESULT WINAPI ITypeLib2_fnGetCustData( + ITypeLib2 * iface, + REFGUID guid, + VARIANT *pVarVal) +{ + ITypeLibImpl *This = (ITypeLibImpl *)iface; + TLBCustData *pCData; + + for(pCData=This->pCustData; pCData; pCData = pCData->next) + { + if( IsEqualIID(guid, &pCData->guid)) break; + } + + TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT"); + + if(pCData) + { + VariantInit( pVarVal); + VariantCopy( pVarVal, &pCData->data); + return S_OK; + } + return E_INVALIDARG; /* FIXME: correct? */ +} + +/* ITypeLib2::GetLibStatistics + * + * Returns statistics about a type library that are required for efficient + * sizing of hash tables. + * + */ +static HRESULT WINAPI ITypeLib2_fnGetLibStatistics( + ITypeLib2 * iface, + ULONG *pcUniqueNames, + ULONG *pcchUniqueNames) +{ + ITypeLibImpl *This = (ITypeLibImpl *)iface; + + FIXME("(%p): stub!\n", This); + + if(pcUniqueNames) *pcUniqueNames=1; + if(pcchUniqueNames) *pcchUniqueNames=1; + return S_OK; +} + +/* ITypeLib2::GetDocumentation2 + * + * Retrieves the library's documentation string, the complete Help file name + * and path, the localization context to use, and the context ID for the + * library Help topic in the Help file. + * + */ +static HRESULT WINAPI ITypeLib2_fnGetDocumentation2( + ITypeLib2 * iface, + INT index, + LCID lcid, + BSTR *pbstrHelpString, + DWORD *pdwHelpStringContext, + BSTR *pbstrHelpStringDll) +{ + ITypeLibImpl *This = (ITypeLibImpl *)iface; + HRESULT result; + ITypeInfo *pTInfo; + + FIXME("(%p) index %d lcid %ld half implemented stub!\n", This, index, lcid); + + /* the help string should be obtained from the helpstringdll, + * using the _DLLGetDocumentation function, based on the supplied + * lcid. Nice to do sometime... + */ + if(index<0) + { + /* documentation for the typelib */ + if(pbstrHelpString) + *pbstrHelpString=SysAllocString(This->DocString); + if(pdwHelpStringContext) + *pdwHelpStringContext=This->dwHelpContext; + if(pbstrHelpStringDll) + *pbstrHelpStringDll=SysAllocString(This->HelpStringDll); + + result = S_OK; + } + else + { + /* for a typeinfo */ + result=ITypeLib2_GetTypeInfo(iface, index, &pTInfo); + + if(SUCCEEDED(result)) + { + ITypeInfo2 * pTInfo2; + result = ITypeInfo_QueryInterface(pTInfo, + &IID_ITypeInfo2, + (LPVOID*) &pTInfo2); + + if(SUCCEEDED(result)) + { + result = ITypeInfo2_GetDocumentation2(pTInfo2, + MEMBERID_NIL, + lcid, + pbstrHelpString, + pdwHelpStringContext, + pbstrHelpStringDll); + + ITypeInfo2_Release(pTInfo2); + } + + ITypeInfo_Release(pTInfo); + } + } + return result; +} + +/* ITypeLib2::GetAllCustData + * + * Gets all custom data items for the library. + * + */ +static HRESULT WINAPI ITypeLib2_fnGetAllCustData( + ITypeLib2 * iface, + CUSTDATA *pCustData) +{ + ITypeLibImpl *This = (ITypeLibImpl *)iface; + TLBCustData *pCData; + int i; + TRACE("(%p) returning %d items\n", This, This->ctCustData); + pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM)); + if(pCustData->prgCustData ){ + pCustData->cCustData=This->ctCustData; + for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){ + pCustData->prgCustData[i].guid=pCData->guid; + VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data); + } + }else{ + ERR(" OUT OF MEMORY! \n"); + return E_OUTOFMEMORY; + } + return S_OK; +} + +static ITypeLib2Vtbl tlbvt = { + ITypeLib2_fnQueryInterface, + ITypeLib2_fnAddRef, + ITypeLib2_fnRelease, + ITypeLib2_fnGetTypeInfoCount, + ITypeLib2_fnGetTypeInfo, + ITypeLib2_fnGetTypeInfoType, + ITypeLib2_fnGetTypeInfoOfGuid, + ITypeLib2_fnGetLibAttr, + ITypeLib2_fnGetTypeComp, + ITypeLib2_fnGetDocumentation, + ITypeLib2_fnIsName, + ITypeLib2_fnFindName, + ITypeLib2_fnReleaseTLibAttr, + + ITypeLib2_fnGetCustData, + ITypeLib2_fnGetLibStatistics, + ITypeLib2_fnGetDocumentation2, + ITypeLib2_fnGetAllCustData + }; + + +static HRESULT WINAPI ITypeLibComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv) +{ + ICOM_THIS_From_ITypeComp(ITypeLibImpl, iface); + + return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv); +} + +static ULONG WINAPI ITypeLibComp_fnAddRef(ITypeComp * iface) +{ + ICOM_THIS_From_ITypeComp(ITypeLibImpl, iface); + + return ITypeInfo_AddRef((ITypeInfo *)This); +} + +static ULONG WINAPI ITypeLibComp_fnRelease(ITypeComp * iface) +{ + ICOM_THIS_From_ITypeComp(ITypeLibImpl, iface); + + return ITypeInfo_Release((ITypeInfo *)This); +} + +static HRESULT WINAPI ITypeLibComp_fnBind( + ITypeComp * iface, + OLECHAR * szName, + ULONG lHash, + WORD wFlags, + ITypeInfo ** ppTInfo, + DESCKIND * pDescKind, + BINDPTR * pBindPtr) +{ + FIXME("(%s, %lx, 0x%x, %p, %p, %p): stub\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr); + return E_NOTIMPL; +} + +static HRESULT WINAPI ITypeLibComp_fnBindType( + ITypeComp * iface, + OLECHAR * szName, + ULONG lHash, + ITypeInfo ** ppTInfo, + ITypeComp ** ppTComp) +{ + FIXME("(%s, %lx, %p, %p): stub\n", debugstr_w(szName), lHash, ppTInfo, ppTComp); + return E_NOTIMPL; +} + +static ITypeCompVtbl tlbtcvt = +{ + + ITypeLibComp_fnQueryInterface, + ITypeLibComp_fnAddRef, + ITypeLibComp_fnRelease, + + ITypeLibComp_fnBind, + ITypeLibComp_fnBindType +}; + +/*================== ITypeInfo(2) Methods ===================================*/ +static ITypeInfo2 * WINAPI ITypeInfo_Constructor(void) +{ + ITypeInfoImpl * pTypeInfoImpl; + + pTypeInfoImpl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ITypeInfoImpl)); + if (pTypeInfoImpl) + { + pTypeInfoImpl->lpVtbl = &tinfvt; + pTypeInfoImpl->lpVtblTypeComp = &tcompvt; + pTypeInfoImpl->ref=1; + } + TRACE("(%p)\n", pTypeInfoImpl); + return (ITypeInfo2*) pTypeInfoImpl; +} + +/* ITypeInfo::QueryInterface + */ +static HRESULT WINAPI ITypeInfo_fnQueryInterface( + ITypeInfo2 *iface, + REFIID riid, + VOID **ppvObject) +{ + ITypeLibImpl *This = (ITypeLibImpl *)iface; + + TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid)); + + *ppvObject=NULL; + if(IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid,&IID_ITypeInfo)|| + IsEqualIID(riid,&IID_ITypeInfo2)) + *ppvObject = This; + + if(*ppvObject){ + ITypeInfo_AddRef(iface); + TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject); + return S_OK; + } + TRACE("-- Interface: E_NOINTERFACE\n"); + return E_NOINTERFACE; +} + +/* ITypeInfo::AddRef + */ +static ULONG WINAPI ITypeInfo_fnAddRef( ITypeInfo2 *iface) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + ITypeLib2_AddRef((ITypeLib2*)This->pTypeLib); + + TRACE("(%p)->ref is %lu\n",This, ref); + return ref; +} + +/* ITypeInfo::Release + */ +static ULONG WINAPI ITypeInfo_fnRelease(ITypeInfo2 *iface) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(%lu)\n",This, ref); + + if (ref) { + /* We don't release ITypeLib when ref=0 because + it means that function is called by ITypeLib2_Release */ + ITypeLib2_Release((ITypeLib2*)This->pTypeLib); + } else { + FIXME("destroy child objects\n"); + + TRACE("destroying ITypeInfo(%p)\n",This); + if (This->Name) + { + SysFreeString(This->Name); + This->Name = 0; + } + + if (This->DocString) + { + SysFreeString(This->DocString); + This->DocString = 0; + } + + if (This->next) + { + ITypeInfo_Release((ITypeInfo*)This->next); + } + + HeapFree(GetProcessHeap(),0,This); + return 0; + } + return ref; +} + +/* ITypeInfo::GetTypeAttr + * + * Retrieves a TYPEATTR structure that contains the attributes of the type + * description. + * + */ +static HRESULT WINAPI ITypeInfo_fnGetTypeAttr( ITypeInfo2 *iface, + LPTYPEATTR *ppTypeAttr) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + TRACE("(%p)\n",This); + *ppTypeAttr = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppTypeAttr)); + memcpy(*ppTypeAttr, &This->TypeAttr, sizeof(**ppTypeAttr)); + + if(This->TypeAttr.typekind == TKIND_ALIAS) /* need to deep copy typedesc */ + copy_typedesc(&(*ppTypeAttr)->tdescAlias, &This->TypeAttr.tdescAlias); + + if((*ppTypeAttr)->typekind == TKIND_DISPATCH && (*ppTypeAttr)->wTypeFlags & TYPEFLAG_FDUAL) { + (*ppTypeAttr)->cFuncs = (*ppTypeAttr)->cbSizeVft / 4; /* This should include all the inherited + funcs */ + (*ppTypeAttr)->cbSizeVft = 28; /* This is always the size of IDispatch's vtbl */ + (*ppTypeAttr)->wTypeFlags &= ~TYPEFLAG_FOLEAUTOMATION; + } + return S_OK; +} + +/* ITypeInfo::GetTypeComp + * + * Retrieves the ITypeComp interface for the type description, which enables a + * client compiler to bind to the type description's members. + * + */ +static HRESULT WINAPI ITypeInfo_fnGetTypeComp( ITypeInfo2 *iface, + ITypeComp * *ppTComp) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + + TRACE("(%p)->(%p) stub!\n", This, ppTComp); + + *ppTComp = (ITypeComp *)&This->lpVtblTypeComp; + ITypeComp_AddRef(*ppTComp); + return S_OK; +} + +/* ITypeInfo::GetFuncDesc + * + * Retrieves the FUNCDESC structure that contains information about a + * specified function. + * + */ +static HRESULT WINAPI ITypeInfo_fnGetFuncDesc( ITypeInfo2 *iface, UINT index, + LPFUNCDESC *ppFuncDesc) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + int i; + TLBFuncDesc * pFDesc; + TRACE("(%p) index %d\n", This, index); + for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, pFDesc=pFDesc->next) + ; + if(pFDesc){ + /* FIXME: must do a copy here */ + *ppFuncDesc=&pFDesc->funcdesc; + return S_OK; + } + return E_INVALIDARG; +} + +/* ITypeInfo::GetVarDesc + * + * Retrieves a VARDESC structure that describes the specified variable. + * + */ +static HRESULT WINAPI ITypeInfo_fnGetVarDesc( ITypeInfo2 *iface, UINT index, + LPVARDESC *ppVarDesc) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + int i; + TLBVarDesc * pVDesc; + TRACE("(%p) index %d\n", This, index); + for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next) + ; + if(pVDesc){ + /* FIXME: must do a copy here */ + *ppVarDesc=&pVDesc->vardesc; + return S_OK; + } + return E_INVALIDARG; +} + +/* ITypeInfo_GetNames + * + * Retrieves the variable with the specified member ID (or the name of the + * property or method and its parameters) that correspond to the specified + * function ID. + */ +static HRESULT WINAPI ITypeInfo_fnGetNames( ITypeInfo2 *iface, MEMBERID memid, + BSTR *rgBstrNames, UINT cMaxNames, UINT *pcNames) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + TLBFuncDesc * pFDesc; + TLBVarDesc * pVDesc; + int i; + TRACE("(%p) memid=0x%08lx Maxname=%d\n", This, memid, cMaxNames); + for(pFDesc=This->funclist; pFDesc && pFDesc->funcdesc.memid != memid; pFDesc=pFDesc->next); + if(pFDesc) + { + /* function found, now return function and parameter names */ + for(i=0; i<cMaxNames && i <= pFDesc->funcdesc.cParams; i++) + { + if(!i) + *rgBstrNames=SysAllocString(pFDesc->Name); + else + rgBstrNames[i]=SysAllocString(pFDesc->pParamDesc[i-1].Name); + } + *pcNames=i; + } + else + { + for(pVDesc=This->varlist; pVDesc && pVDesc->vardesc.memid != memid; pVDesc=pVDesc->next); + if(pVDesc) + { + *rgBstrNames=SysAllocString(pVDesc->Name); + *pcNames=1; + } + else + { + if(This->TypeAttr.cImplTypes && + (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) { + /* recursive search */ + ITypeInfo *pTInfo; + HRESULT result; + result=ITypeInfo_GetRefTypeInfo(iface, This->impltypelist->hRef, + &pTInfo); + if(SUCCEEDED(result)) + { + result=ITypeInfo_GetNames(pTInfo, memid, rgBstrNames, cMaxNames, pcNames); + ITypeInfo_Release(pTInfo); + return result; + } + WARN("Could not search inherited interface!\n"); + } + else + { + WARN("no names found\n"); + } + *pcNames=0; + return TYPE_E_ELEMENTNOTFOUND; + } + } + return S_OK; +} + + +/* ITypeInfo::GetRefTypeOfImplType + * + * If a type description describes a COM class, it retrieves the type + * description of the implemented interface types. For an interface, + * GetRefTypeOfImplType returns the type information for inherited interfaces, + * if any exist. + * + */ +static HRESULT WINAPI ITypeInfo_fnGetRefTypeOfImplType( + ITypeInfo2 *iface, + UINT index, + HREFTYPE *pRefType) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + int(i); + TLBImplType *pImpl = This->impltypelist; + + TRACE("(%p) index %d\n", This, index); + if (TRACE_ON(ole)) dump_TypeInfo(This); + + if(index==(UINT)-1) + { + /* only valid on dual interfaces; + retrieve the associated TKIND_INTERFACE handle for the current TKIND_DISPATCH + */ + if( This->TypeAttr.typekind != TKIND_DISPATCH) return E_INVALIDARG; + + if (This->TypeAttr.wTypeFlags & TYPEFLAG_FDISPATCHABLE && + This->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL ) + { + *pRefType = -1; + } + else + { + if (!pImpl) return TYPE_E_ELEMENTNOTFOUND; + *pRefType = pImpl->hRef; + } + } + else + { + /* get element n from linked list */ + for(i=0; pImpl && i<index; i++) + { + pImpl = pImpl->next; + } + + if (!pImpl) return TYPE_E_ELEMENTNOTFOUND; + + *pRefType = pImpl->hRef; + + TRACE("-- 0x%08lx\n", pImpl->hRef ); + } + + return S_OK; + +} + +/* ITypeInfo::GetImplTypeFlags + * + * Retrieves the IMPLTYPEFLAGS enumeration for one implemented interface + * or base interface in a type description. + */ +static HRESULT WINAPI ITypeInfo_fnGetImplTypeFlags( ITypeInfo2 *iface, + UINT index, INT *pImplTypeFlags) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + int i; + TLBImplType *pImpl; + + TRACE("(%p) index %d\n", This, index); + for(i=0, pImpl=This->impltypelist; i<index && pImpl; + i++, pImpl=pImpl->next) + ; + if(i==index && pImpl){ + *pImplTypeFlags=pImpl->implflags; + return S_OK; + } + *pImplTypeFlags=0; + return TYPE_E_ELEMENTNOTFOUND; +} + +/* GetIDsOfNames + * Maps between member names and member IDs, and parameter names and + * parameter IDs. + */ +static HRESULT WINAPI ITypeInfo_fnGetIDsOfNames( ITypeInfo2 *iface, + LPOLESTR *rgszNames, UINT cNames, MEMBERID *pMemId) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + TLBFuncDesc * pFDesc; + TLBVarDesc * pVDesc; + HRESULT ret=S_OK; + + TRACE("(%p) Name %s cNames %d\n", This, debugstr_w(*rgszNames), + cNames); + for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) { + int i, j; + if(!lstrcmpiW(*rgszNames, pFDesc->Name)) { + if(cNames) *pMemId=pFDesc->funcdesc.memid; + for(i=1; i < cNames; i++){ + for(j=0; j<pFDesc->funcdesc.cParams; j++) + if(!lstrcmpiW(rgszNames[i],pFDesc->pParamDesc[j].Name)) + break; + if( j<pFDesc->funcdesc.cParams) + pMemId[i]=j; + else + ret=DISP_E_UNKNOWNNAME; + }; + return ret; + } + } + for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) { + if(!lstrcmpiW(*rgszNames, pVDesc->Name)) { + if(cNames) *pMemId=pVDesc->vardesc.memid; + return ret; + } + } + /* not found, see if this is and interface with an inheritance */ + if(This->TypeAttr.cImplTypes && + (This->TypeAttr.typekind==TKIND_INTERFACE || This->TypeAttr.typekind==TKIND_DISPATCH)) { + /* recursive search */ + ITypeInfo *pTInfo; + ret=ITypeInfo_GetRefTypeInfo(iface, + This->impltypelist->hRef, &pTInfo); + if(SUCCEEDED(ret)){ + ret=ITypeInfo_GetIDsOfNames(pTInfo, rgszNames, cNames, pMemId ); + ITypeInfo_Release(pTInfo); + return ret; + } + WARN("Could not search inherited interface!\n"); + } else + WARN("no names found\n"); + return DISP_E_UNKNOWNNAME; +} + +/* ITypeInfo::Invoke + * + * Invokes a method, or accesses a property of an object, that implements the + * interface described by the type description. + */ +DWORD +_invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args) { + DWORD res; + + if (TRACE_ON(ole)) { + int i; + TRACE("Calling %p(",func); + for (i=0;i<nrargs;i++) TRACE("%08lx,",args[i]); + TRACE(")\n"); + } + + switch (callconv) { + case CC_STDCALL: + + switch (nrargs) { + case 0: + res = func(); + break; + case 1: + res = func(args[0]); + break; + case 2: + res = func(args[0],args[1]); + break; + case 3: + res = func(args[0],args[1],args[2]); + break; + case 4: + res = func(args[0],args[1],args[2],args[3]); + break; + case 5: + res = func(args[0],args[1],args[2],args[3],args[4]); + break; + case 6: + res = func(args[0],args[1],args[2],args[3],args[4],args[5]); + break; + case 7: + res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6]); + break; + case 8: + res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7]); + break; + case 9: + res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]); + break; + case 10: + res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9]); + break; + case 11: + res = func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],args[9],args[10]); + break; + default: + FIXME("unsupported number of arguments %d in stdcall\n",nrargs); + res = -1; + break; + } + break; + default: + FIXME("unsupported calling convention %d\n",callconv); + res = -1; + break; + } + TRACE("returns %08lx\n",res); + return res; +} + +extern int _argsize(DWORD vt); + +/**************************************************************************** + * Helper functions for Dispcall / Invoke, which copies one variant + * with target type onto the argument stack. + */ +static HRESULT +_copy_arg( ITypeInfo2 *tinfo, TYPEDESC *tdesc, + DWORD *argpos, VARIANT *arg, VARTYPE vt +) { + UINT arglen = _argsize(vt)*sizeof(DWORD); + VARIANT va; + + if ((vt==VT_PTR) && tdesc && (tdesc->u.lptdesc->vt == VT_VARIANT)) { + memcpy(argpos,&arg,sizeof(void*)); + return S_OK; + } + + if (V_VT(arg) == vt) { + memcpy(argpos, &V_I4(arg), arglen); + return S_OK; + } + + if (V_ISARRAY(arg) && (vt == VT_SAFEARRAY)) { + memcpy(argpos, &V_ARRAY(arg), sizeof(SAFEARRAY*)); + return S_OK; + } + + if (vt == VT_VARIANT) { + memcpy(argpos, arg, arglen); + return S_OK; + } + /* Deref BYREF vars if there is need */ + if(V_ISBYREF(arg) && ((V_VT(arg) & ~VT_BYREF)==vt)) { + memcpy(argpos,(void*)V_I4(arg), arglen); + return S_OK; + } + if (vt==VT_UNKNOWN && V_VT(arg)==VT_DISPATCH) { + /* in this context, if the type lib specifies IUnknown*, giving an + IDispatch* is correct; so, don't invoke VariantChangeType */ + memcpy(argpos,&V_I4(arg), arglen); + return S_OK; + } + if ((vt == VT_PTR) && tdesc) + return _copy_arg(tinfo, tdesc->u.lptdesc, argpos, arg, tdesc->u.lptdesc->vt); + + if ((vt == VT_USERDEFINED) && tdesc && tinfo) { + ITypeInfo *tinfo2 = NULL; + TYPEATTR *tattr = NULL; + HRESULT hres; + + hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2); + if (hres) { + FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED, " + "while coercing from vt 0x%x. Copying 4 byte.\n", + tdesc->u.hreftype,V_VT(arg)); + memcpy(argpos, &V_I4(arg), 4); + return S_OK; + } + hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr); + if( hres ) + { + ERR("GetTypeAttr failed\n"); + ITypeInfo_Release(tinfo2); + return hres; + } + switch (tattr->typekind) { + case TKIND_ENUM: + switch ( V_VT( arg ) ) { + case VT_I2: + *argpos = V_I2(arg); + hres = S_OK; + break; + case VT_I4: + memcpy(argpos, &V_I4(arg), 4); + hres = S_OK; + break; + default: + FIXME("vt 0x%x -> TKIND_ENUM unhandled.\n",V_VT(arg)); + hres = E_FAIL; + break; + } + break; + + case TKIND_ALIAS: + tdesc = &(tattr->tdescAlias); + hres = _copy_arg((ITypeInfo2*)tinfo2, tdesc, argpos, arg, tdesc->vt); + break; + + case TKIND_INTERFACE: + if (V_VT(arg) == VT_DISPATCH) { + IDispatch *disp; + if (IsEqualIID(&IID_IDispatch,&(tattr->guid))) { + memcpy(argpos, &V_DISPATCH(arg), 4); + hres = S_OK; + break; + } + hres=IUnknown_QueryInterface(V_DISPATCH(arg), + &IID_IDispatch,(LPVOID*)&disp); + if (SUCCEEDED(hres)) { + memcpy(argpos,&disp,4); + IUnknown_Release(V_DISPATCH(arg)); + hres = S_OK; + break; + } + FIXME("Failed to query IDispatch interface from %s while " + "converting to VT_DISPATCH!\n",debugstr_guid(&(tattr->guid))); + hres = E_FAIL; + break; + } + if (V_VT(arg) == VT_UNKNOWN) { + memcpy(argpos, &V_UNKNOWN(arg), 4); + hres = S_OK; + break; + } + FIXME("vt 0x%x -> TKIND_INTERFACE(%s) unhandled\n", + V_VT(arg),debugstr_guid(&(tattr->guid))); + hres = E_FAIL; + break; + + case TKIND_DISPATCH: + if (V_VT(arg) == VT_DISPATCH) { + memcpy(argpos, &V_DISPATCH(arg), 4); + hres = S_OK; + } + else { + hres = E_FAIL; + FIXME("TKIND_DISPATCH unhandled for target vt 0x%x.\n",V_VT(arg)); + } + break; + case TKIND_RECORD: + FIXME("TKIND_RECORD unhandled.\n"); + hres = E_FAIL; + break; + default: + FIXME("TKIND %d unhandled.\n",tattr->typekind); + hres = E_FAIL; + break; + } + ITypeInfo_ReleaseTypeAttr(tinfo2, tattr); + ITypeInfo_Release(tinfo2); + return hres; + } + + VariantInit(&va); + if (VariantChangeType(&va,arg,0,vt)==S_OK) { + memcpy(argpos,&V_I4(&va), arglen); + FIXME("Should not use VariantChangeType here." + " (conversion from 0x%x -> 0x%x) %08lx\n", + V_VT(arg), vt, *argpos + ); + return S_OK; + } + ERR("Set arg to disparg type 0x%x vs 0x%x\n",V_VT(arg),vt); + return E_FAIL; +} + +/*********************************************************************** + * DispCallFunc (OLEAUT32.@) + */ +HRESULT WINAPI +DispCallFunc( + void* pvInstance, ULONG oVft, CALLCONV cc, VARTYPE vtReturn, UINT cActuals, + VARTYPE* prgvt, VARIANTARG** prgpvarg, VARIANT* pvargResult +) { + int i, argsize, argspos; + DWORD *args; + HRESULT hres; + + TRACE("(%p, %ld, %d, %d, %d, %p, %p, %p (vt=%d))\n", + pvInstance, oVft, cc, vtReturn, cActuals, prgvt, prgpvarg, pvargResult, V_VT(pvargResult) + ); + /* DispCallFunc is only used to invoke methods belonging to an IDispatch-derived COM interface. + So we need to add a first parameter to the list of arguments, to supply the interface pointer */ + argsize = 1; + for (i=0;i<cActuals;i++) { + TRACE("arg %d: type %d, size %d\n",i,prgvt[i],_argsize(prgvt[i])); + dump_Variant(prgpvarg[i]); + argsize += _argsize(prgvt[i]); + } + args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*argsize); + args[0] = (DWORD)pvInstance; /* this is the fake IDispatch interface pointer */ + argspos = 1; + for (i=0;i<cActuals;i++) { + VARIANT *arg = prgpvarg[i]; + TRACE("Storing arg %d (%d as %d)\n",i,V_VT(arg),prgvt[i]); + _copy_arg(NULL, NULL, &args[argspos], arg, prgvt[i]); + argspos += _argsize(prgvt[i]); + } + + if(pvargResult!=NULL && V_VT(pvargResult)==VT_EMPTY) + { + _invoke((*(FARPROC**)pvInstance)[oVft/4],cc,argsize,args); + hres=S_OK; + } + else + { + FIXME("Do not know how to handle pvargResult %p. Expect crash ...\n",pvargResult); + hres = _invoke((*(FARPROC**)pvInstance)[oVft/4],cc,argsize,args); + FIXME("Method returned %lx\n",hres); + } + HeapFree(GetProcessHeap(),0,args); + return hres; +} + +static HRESULT WINAPI ITypeInfo_fnInvoke( + ITypeInfo2 *iface, + VOID *pIUnk, + MEMBERID memid, + UINT16 dwFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, + UINT *pArgErr) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + int i; + unsigned int func_index, var_index; + TYPEKIND type_kind; + HRESULT hres; + + TRACE("(%p)(%p,id=%ld,flags=0x%08x,%p,%p,%p,%p) partial stub!\n", + This,pIUnk,memid,dwFlags,pDispParams,pVarResult,pExcepInfo,pArgErr + ); + dump_DispParms(pDispParams); + + hres = ITypeInfo2_GetFuncIndexOfMemId(iface, memid, dwFlags, &func_index); + if (SUCCEEDED(hres)) { + FUNCDESC *func_desc; + + hres = ITypeInfo2_GetFuncDesc(iface, func_index, &func_desc); + if(FAILED(hres)) return hres; + + switch (func_desc->funckind) { + case FUNC_PUREVIRTUAL: + case FUNC_VIRTUAL: { + DWORD res; + int numargs, numargs2, argspos, args2pos; + DWORD *args , *args2; + VARIANT *rgvarg = HeapAlloc(GetProcessHeap(), 0, sizeof(VARIANT) * func_desc->cParams); + memcpy(rgvarg,pDispParams->rgvarg,sizeof(VARIANT)*pDispParams->cArgs); + + hres = S_OK; + numargs = 1; numargs2 = 0; + for (i = 0; i < func_desc->cParams; i++) { + if (i<pDispParams->cArgs) + numargs += _argsize(func_desc->lprgelemdescParam[i].tdesc.vt); + else { + numargs += 1; /* sizeof(lpvoid) */ + numargs2 += _argsize(func_desc->lprgelemdescParam[i].tdesc.vt); + } + } + + args = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*numargs); + args2 = HeapAlloc(GetProcessHeap(),0,sizeof(DWORD)*numargs2); + + args[0] = (DWORD)pIUnk; + argspos = 1; args2pos = 0; + for (i = 0; i < func_desc->cParams; i++) { + int arglen = _argsize(func_desc->lprgelemdescParam[i].tdesc.vt); + if (i<pDispParams->cArgs) { + VARIANT *arg = &rgvarg[pDispParams->cArgs-i-1]; + TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc; + USHORT paramFlags = func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags; + if (paramFlags & PARAMFLAG_FOPT) { + if(i < func_desc->cParams - func_desc->cParamsOpt) + ERR("Parameter has PARAMFLAG_FOPT flag but is not one of last cParamOpt parameters\n"); + if(V_VT(arg) == VT_EMPTY + || ((V_ISBYREF(arg)) && !V_BYREF(arg))) { + /* FIXME: Documentation says that we do this when parameter is left unspecified. + How to determine it? */ + + if(paramFlags & PARAMFLAG_FHASDEFAULT) + FIXME("PARAMFLAG_FHASDEFAULT flag not supported\n"); + V_VT(arg) = VT_ERROR; + V_ERROR(arg) = DISP_E_PARAMNOTFOUND; + arglen = _argsize(VT_ERROR); + } + } + hres = _copy_arg(iface, tdesc, &args[argspos], arg, tdesc->vt); + if (FAILED(hres)) goto func_fail; + argspos += arglen; + } else if(func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags & PARAMFLAG_FOPT) { + VARIANT *arg = &rgvarg[i]; + TYPEDESC *tdesc = &func_desc->lprgelemdescParam[i].tdesc; + if(i < func_desc->cParams - func_desc->cParamsOpt) + ERR("Parameter has PARAMFLAG_FOPT flag but is not one of last cParamOpt parameters\n"); + if(func_desc->lprgelemdescParam[i].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) + FIXME("PARAMFLAG_FHASDEFAULT flag not supported\n"); + V_VT(arg) = VT_ERROR; + V_ERROR(arg) = DISP_E_PARAMNOTFOUND; + arglen = _argsize(VT_ERROR); + hres = _copy_arg(iface, tdesc, &args[argspos], arg, tdesc->vt); + if (FAILED(hres)) goto func_fail; + argspos += arglen; + } else { + TYPEDESC *tdesc = &(func_desc->lprgelemdescParam[i].tdesc); + if (tdesc->vt != VT_PTR) + FIXME("set %d to pointer for get (type is %d)\n",i,tdesc->vt); + /*FIXME: give pointers for the rest, so propertyget works*/ + args[argspos] = (DWORD)&args2[args2pos]; + + /* If pointer to variant, pass reference it. */ + if ((tdesc->vt == VT_PTR) && + (tdesc->u.lptdesc->vt == VT_VARIANT) && + pVarResult + ) + args[argspos]= (DWORD)pVarResult; + argspos += 1; + args2pos += arglen; + } + } + if (func_desc->cParamsOpt < 0) + FIXME("Does not support optional parameters (%d)\n", func_desc->cParamsOpt); + + res = _invoke((*(FARPROC**)pIUnk)[func_desc->oVft/4], + func_desc->callconv, + numargs, + args + ); + + if (pVarResult && (dwFlags & (DISPATCH_PROPERTYGET))) { + args2pos = 0; + for (i = 0; i < func_desc->cParams - pDispParams->cArgs; i++) { + int arglen = _argsize(func_desc->lprgelemdescParam[i].tdesc.vt); + TYPEDESC *tdesc = &(func_desc->lprgelemdescParam[i + pDispParams->cArgs].tdesc); + TYPEDESC i4_tdesc; + i4_tdesc.vt = VT_I4; + + /* If we are a pointer to a variant, we are done already */ + if ((tdesc->vt==VT_PTR)&&(tdesc->u.lptdesc->vt==VT_VARIANT)) + continue; + + VariantInit(pVarResult); + memcpy(&V_INT(pVarResult),&args2[args2pos],arglen*sizeof(DWORD)); + + if (tdesc->vt == VT_PTR) + tdesc = tdesc->u.lptdesc; + if (tdesc->vt == VT_USERDEFINED) { + ITypeInfo *tinfo2; + TYPEATTR *tattr; + + hres = ITypeInfo_GetRefTypeInfo(iface,tdesc->u.hreftype,&tinfo2); + if (FAILED(hres)) { + FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED, while coercing. Copying 4 byte.\n",tdesc->u.hreftype); + goto func_fail; + } + ITypeInfo_GetTypeAttr(tinfo2,&tattr); + switch (tattr->typekind) { + case TKIND_ENUM: + /* force the return type to be VT_I4 */ + tdesc = &i4_tdesc; + break; + case TKIND_ALIAS: + TRACE("TKIND_ALIAS to vt 0x%x\n",tattr->tdescAlias.vt); + tdesc = &(tattr->tdescAlias); + break; + + case TKIND_INTERFACE: + FIXME("TKIND_INTERFACE unhandled.\n"); + break; + case TKIND_DISPATCH: + FIXME("TKIND_DISPATCH unhandled.\n"); + break; + case TKIND_RECORD: + FIXME("TKIND_RECORD unhandled.\n"); + break; + default: + FIXME("TKIND %d unhandled.\n",tattr->typekind); + break; + } + ITypeInfo_Release(tinfo2); + } + V_VT(pVarResult) = tdesc->vt; + + /* HACK: VB5 likes this. + * I do not know why. There is 1 example in MSDN which uses + * this which appears broken (mixes int vals and + * IDispatch*.). + */ + if ((tdesc->vt == VT_PTR) && (dwFlags & DISPATCH_METHOD)) + V_VT(pVarResult) = VT_DISPATCH; + TRACE("storing into variant:\n"); + dump_Variant(pVarResult); + args2pos += arglen; + } + } +func_fail: + HeapFree(GetProcessHeap(), 0, rgvarg); + HeapFree(GetProcessHeap(),0,args2); + HeapFree(GetProcessHeap(),0,args); + break; + } + case FUNC_DISPATCH: { + IDispatch *disp; + + hres = IUnknown_QueryInterface((LPUNKNOWN)pIUnk,&IID_IDispatch,(LPVOID*)&disp); + if (SUCCEEDED(hres)) { + FIXME("Calling Invoke in IDispatch iface. untested!\n"); + hres = IDispatch_Invoke( + disp,memid,&IID_NULL,LOCALE_USER_DEFAULT,dwFlags,pDispParams, + pVarResult,pExcepInfo,pArgErr + ); + if (FAILED(hres)) + FIXME("IDispatch::Invoke failed with %08lx. (Could be not a real error?)\n", hres); + IDispatch_Release(disp); + } else + FIXME("FUNC_DISPATCH used on object without IDispatch iface?\n"); + break; + } + default: + FIXME("Unknown function invocation type %d\n", func_desc->funckind); + hres = E_FAIL; + break; + } + + ITypeInfo2_ReleaseFuncDesc(iface, func_desc); + return hres; + + } else if(SUCCEEDED(hres = ITypeInfo2_GetVarIndexOfMemId(iface, memid, &var_index))) { + VARDESC *var_desc; + + hres = ITypeInfo2_GetVarDesc(iface, var_index, &var_desc); + if(FAILED(hres)) return hres; + + FIXME("varseek: Found memid, but variable-based invoking not supported\n"); + dump_VARDESC(var_desc); + ITypeInfo2_ReleaseVarDesc(iface, var_desc); + return E_NOTIMPL; + } + + /* not found, look for it in inherited interfaces */ + ITypeInfo2_GetTypeKind(iface, &type_kind); + if(type_kind == TKIND_INTERFACE || type_kind == TKIND_DISPATCH) { + HREFTYPE ref_type; + if(SUCCEEDED(ITypeInfo2_GetRefTypeOfImplType(iface, 0, &ref_type))) { + /* recursive search */ + ITypeInfo *pTInfo; + hres = ITypeInfo_GetRefTypeInfo(iface, ref_type, &pTInfo); + if(SUCCEEDED(hres)){ + hres = ITypeInfo_Invoke(pTInfo,pIUnk,memid,dwFlags,pDispParams,pVarResult,pExcepInfo,pArgErr); + ITypeInfo_Release(pTInfo); + return hres; + } + WARN("Could not search inherited interface!\n"); + } + } + ERR("did not find member id %08lx, flags %d!\n", memid, dwFlags); + return DISP_E_MEMBERNOTFOUND; +} + +/* ITypeInfo::GetDocumentation + * + * Retrieves the documentation string, the complete Help file name and path, + * and the context ID for the Help topic for a specified type description. + * + * (Can be tested by the Visual Basic Editor in Word for instance.) + */ +static HRESULT WINAPI ITypeInfo_fnGetDocumentation( ITypeInfo2 *iface, + MEMBERID memid, BSTR *pBstrName, BSTR *pBstrDocString, + DWORD *pdwHelpContext, BSTR *pBstrHelpFile) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + TLBFuncDesc * pFDesc; + TLBVarDesc * pVDesc; + TRACE("(%p) memid %ld Name(%p) DocString(%p)" + " HelpContext(%p) HelpFile(%p)\n", + This, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile); + if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */ + if(pBstrName) + *pBstrName=SysAllocString(This->Name); + if(pBstrDocString) + *pBstrDocString=SysAllocString(This->DocString); + if(pdwHelpContext) + *pdwHelpContext=This->dwHelpContext; + if(pBstrHelpFile) + *pBstrHelpFile=SysAllocString(This->DocString);/* FIXME */ + return S_OK; + }else {/* for a member */ + for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) + if(pFDesc->funcdesc.memid==memid){ + if(pBstrName) + *pBstrName = SysAllocString(pFDesc->Name); + if(pBstrDocString) + *pBstrDocString=SysAllocString(pFDesc->HelpString); + if(pdwHelpContext) + *pdwHelpContext=pFDesc->helpcontext; + return S_OK; + } + for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) + if(pVDesc->vardesc.memid==memid){ + if(pBstrName) + *pBstrName = SysAllocString(pVDesc->Name); + if(pBstrDocString) + *pBstrDocString=SysAllocString(pVDesc->HelpString); + if(pdwHelpContext) + *pdwHelpContext=pVDesc->HelpContext; + return S_OK; + } + } + return TYPE_E_ELEMENTNOTFOUND; +} + +/* ITypeInfo::GetDllEntry + * + * Retrieves a description or specification of an entry point for a function + * in a DLL. + */ +static HRESULT WINAPI ITypeInfo_fnGetDllEntry( ITypeInfo2 *iface, MEMBERID memid, + INVOKEKIND invKind, BSTR *pBstrDllName, BSTR *pBstrName, + WORD *pwOrdinal) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + TLBFuncDesc *pFDesc; + + FIXME("(%p, memid %lx, %d, %p, %p, %p), partial stub!\n", This, memid, invKind, pBstrDllName, pBstrName, pwOrdinal); + + for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) + if(pFDesc->funcdesc.memid==memid){ + dump_TypeInfo(This); + dump_TLBFuncDescOne(pFDesc); + + /* FIXME: This is wrong, but how do you find that out? */ + if (pBstrDllName) { + static const WCHAR oleaut32W[] = {'O','L','E','A','U','T','3','2','.','D','L','L',0}; + *pBstrDllName = SysAllocString(oleaut32W); + } + + if (HIWORD(pFDesc->Entry) && (pFDesc->Entry != (void*)-1)) { + if (pBstrName) + *pBstrName = SysAllocString(pFDesc->Entry); + if (pwOrdinal) + *pwOrdinal = -1; + return S_OK; + } + if (pBstrName) + *pBstrName = NULL; + if (pwOrdinal) + *pwOrdinal = (DWORD)pFDesc->Entry; + return S_OK; + } + return E_FAIL; +} + +/* ITypeInfo::GetRefTypeInfo + * + * If a type description references other type descriptions, it retrieves + * the referenced type descriptions. + */ +static HRESULT WINAPI ITypeInfo_fnGetRefTypeInfo( + ITypeInfo2 *iface, + HREFTYPE hRefType, + ITypeInfo **ppTInfo) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + HRESULT result = E_FAIL; + + + if (hRefType == -1 && + (((ITypeInfoImpl*) This)->TypeAttr.typekind == TKIND_DISPATCH) && + (((ITypeInfoImpl*) This)->TypeAttr.wTypeFlags & TYPEFLAG_FDUAL)) + { + /* when we meet a DUAL dispinterface, we must create the interface + * version of it. + */ + ITypeInfoImpl* pTypeInfoImpl = (ITypeInfoImpl*) ITypeInfo_Constructor(); + + + /* the interface version contains the same information as the dispinterface + * copy the contents of the structs. + */ + *pTypeInfoImpl = *This; + pTypeInfoImpl->ref = 1; + + /* change the type to interface */ + pTypeInfoImpl->TypeAttr.typekind = TKIND_INTERFACE; + + *ppTInfo = (ITypeInfo*) pTypeInfoImpl; + + ITypeInfo_AddRef((ITypeInfo*) pTypeInfoImpl); + + result = S_OK; + + } else { + TLBRefType *pRefType; + for(pRefType = This->reflist; pRefType; pRefType = pRefType->next) { + if(pRefType->reference == hRefType) + break; + } + if(!pRefType) + FIXME("Can't find pRefType for ref %lx\n", hRefType); + if(pRefType && hRefType != -1) { + ITypeLib *pTLib = NULL; + + if(pRefType->pImpTLInfo == TLB_REF_INTERNAL) { + int Index; + result = ITypeInfo_GetContainingTypeLib(iface, &pTLib, &Index); + } else { + if(pRefType->pImpTLInfo->pImpTypeLib) { + TRACE("typeinfo in imported typelib that is already loaded\n"); + pTLib = (ITypeLib*)pRefType->pImpTLInfo->pImpTypeLib; + ITypeLib2_AddRef((ITypeLib*) pTLib); + result = S_OK; + } else { + TRACE("typeinfo in imported typelib that isn't already loaded\n"); + result = LoadRegTypeLib( &pRefType->pImpTLInfo->guid, + pRefType->pImpTLInfo->wVersionMajor, + pRefType->pImpTLInfo->wVersionMinor, + pRefType->pImpTLInfo->lcid, + &pTLib); + + if(!SUCCEEDED(result)) { + BSTR libnam=SysAllocString(pRefType->pImpTLInfo->name); + result=LoadTypeLib(libnam, &pTLib); + SysFreeString(libnam); + } + if(SUCCEEDED(result)) { + pRefType->pImpTLInfo->pImpTypeLib = (ITypeLibImpl*)pTLib; + ITypeLib2_AddRef(pTLib); + } + } + } + if(SUCCEEDED(result)) { + if(pRefType->index == TLB_REF_USE_GUID) + result = ITypeLib2_GetTypeInfoOfGuid(pTLib, + &pRefType->guid, + ppTInfo); + else + result = ITypeLib2_GetTypeInfo(pTLib, pRefType->index, + ppTInfo); + } + if (pTLib != NULL) + ITypeLib2_Release(pTLib); + } + } + + TRACE("(%p) hreftype 0x%04lx loaded %s (%p)\n", This, hRefType, + SUCCEEDED(result)? "SUCCESS":"FAILURE", *ppTInfo); + return result; +} + +/* ITypeInfo::AddressOfMember + * + * Retrieves the addresses of static functions or variables, such as those + * defined in a DLL. + */ +static HRESULT WINAPI ITypeInfo_fnAddressOfMember( ITypeInfo2 *iface, + MEMBERID memid, INVOKEKIND invKind, PVOID *ppv) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + FIXME("(%p) stub!\n", This); + return S_OK; +} + +/* ITypeInfo::CreateInstance + * + * Creates a new instance of a type that describes a component object class + * (coclass). + */ +static HRESULT WINAPI ITypeInfo_fnCreateInstance( ITypeInfo2 *iface, + IUnknown *pUnk, REFIID riid, VOID **ppvObj) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + FIXME("(%p) stub!\n", This); + return S_OK; +} + +/* ITypeInfo::GetMops + * + * Retrieves marshalling information. + */ +static HRESULT WINAPI ITypeInfo_fnGetMops( ITypeInfo2 *iface, MEMBERID memid, + BSTR *pBstrMops) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + FIXME("(%p) stub!\n", This); + return S_OK; +} + +/* ITypeInfo::GetContainingTypeLib + * + * Retrieves the containing type library and the index of the type description + * within that type library. + */ +static HRESULT WINAPI ITypeInfo_fnGetContainingTypeLib( ITypeInfo2 *iface, + ITypeLib * *ppTLib, UINT *pIndex) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + + /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */ + if (pIndex) { + *pIndex=This->index; + TRACE("returning pIndex=%d\n", *pIndex); + } + + if (ppTLib) { + *ppTLib=(LPTYPELIB )(This->pTypeLib); + ITypeLib2_AddRef(*ppTLib); + TRACE("returning ppTLib=%p\n", *ppTLib); + } + + return S_OK; +} + +/* ITypeInfo::ReleaseTypeAttr + * + * Releases a TYPEATTR previously returned by GetTypeAttr. + * + */ +static void WINAPI ITypeInfo_fnReleaseTypeAttr( ITypeInfo2 *iface, + TYPEATTR* pTypeAttr) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + TRACE("(%p)->(%p)\n", This, pTypeAttr); + if(This->TypeAttr.typekind == TKIND_ALIAS) + free_deep_typedesc(&pTypeAttr->tdescAlias); + HeapFree(GetProcessHeap(), 0, pTypeAttr); +} + +/* ITypeInfo::ReleaseFuncDesc + * + * Releases a FUNCDESC previously returned by GetFuncDesc. * + */ +static void WINAPI ITypeInfo_fnReleaseFuncDesc( + ITypeInfo2 *iface, + FUNCDESC *pFuncDesc) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + TRACE("(%p)->(%p)\n", This, pFuncDesc); +} + +/* ITypeInfo::ReleaseVarDesc + * + * Releases a VARDESC previously returned by GetVarDesc. + */ +static void WINAPI ITypeInfo_fnReleaseVarDesc( ITypeInfo2 *iface, + VARDESC *pVarDesc) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + TRACE("(%p)->(%p)\n", This, pVarDesc); +} + +/* ITypeInfo2::GetTypeKind + * + * Returns the TYPEKIND enumeration quickly, without doing any allocations. + * + */ +static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( ITypeInfo2 * iface, + TYPEKIND *pTypeKind) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + *pTypeKind=This->TypeAttr.typekind; + TRACE("(%p) type 0x%0x\n", This,*pTypeKind); + return S_OK; +} + +/* ITypeInfo2::GetTypeFlags + * + * Returns the type flags without any allocations. This returns a DWORD type + * flag, which expands the type flags without growing the TYPEATTR (type + * attribute). + * + */ +static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( ITypeInfo2 *iface, ULONG *pTypeFlags) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + *pTypeFlags=This->TypeAttr.wTypeFlags; + TRACE("(%p) flags 0x%lx\n", This,*pTypeFlags); + return S_OK; +} + +/* ITypeInfo2::GetFuncIndexOfMemId + * Binds to a specific member based on a known DISPID, where the member name + * is not known (for example, when binding to a default member). + * + */ +static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( ITypeInfo2 * iface, + MEMBERID memid, INVOKEKIND invKind, UINT *pFuncIndex) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + TLBFuncDesc *pFuncInfo; + int i; + HRESULT result; + + for(i = 0, pFuncInfo = This->funclist; pFuncInfo; i++, pFuncInfo=pFuncInfo->next) + if(memid == pFuncInfo->funcdesc.memid && (invKind & pFuncInfo->funcdesc.invkind)) + break; + if(pFuncInfo) { + *pFuncIndex = i; + result = S_OK; + } else + result = TYPE_E_ELEMENTNOTFOUND; + + TRACE("(%p) memid 0x%08lx invKind 0x%04x -> %s\n", This, + memid, invKind, SUCCEEDED(result) ? "SUCCESS" : "FAILED"); + return result; +} + +/* TypeInfo2::GetVarIndexOfMemId + * + * Binds to a specific member based on a known DISPID, where the member name + * is not known (for example, when binding to a default member). + * + */ +static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( ITypeInfo2 * iface, + MEMBERID memid, UINT *pVarIndex) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + TLBVarDesc *pVarInfo; + int i; + HRESULT result; + for(i=0, pVarInfo=This->varlist; pVarInfo && + memid != pVarInfo->vardesc.memid; i++, pVarInfo=pVarInfo->next) + ; + if(pVarInfo) { + *pVarIndex = i; + result = S_OK; + } else + result = TYPE_E_ELEMENTNOTFOUND; + + TRACE("(%p) memid 0x%08lx -> %s\n", This, + memid, SUCCEEDED(result) ? "SUCCESS" : "FAILED"); + return result; +} + +/* ITypeInfo2::GetCustData + * + * Gets the custom data + */ +static HRESULT WINAPI ITypeInfo2_fnGetCustData( + ITypeInfo2 * iface, + REFGUID guid, + VARIANT *pVarVal) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + TLBCustData *pCData; + + for(pCData=This->pCustData; pCData; pCData = pCData->next) + if( IsEqualIID(guid, &pCData->guid)) break; + + TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT"); + + if(pCData) + { + VariantInit( pVarVal); + VariantCopy( pVarVal, &pCData->data); + return S_OK; + } + return E_INVALIDARG; /* FIXME: correct? */ +} + +/* ITypeInfo2::GetFuncCustData + * + * Gets the custom data + */ +static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData( + ITypeInfo2 * iface, + UINT index, + REFGUID guid, + VARIANT *pVarVal) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + TLBCustData *pCData=NULL; + TLBFuncDesc * pFDesc; + int i; + for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, + pFDesc=pFDesc->next); + + if(pFDesc) + for(pCData=pFDesc->pCustData; pCData; pCData = pCData->next) + if( IsEqualIID(guid, &pCData->guid)) break; + + TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT"); + + if(pCData){ + VariantInit( pVarVal); + VariantCopy( pVarVal, &pCData->data); + return S_OK; + } + return E_INVALIDARG; /* FIXME: correct? */ +} + +/* ITypeInfo2::GetParamCustData + * + * Gets the custom data + */ +static HRESULT WINAPI ITypeInfo2_fnGetParamCustData( + ITypeInfo2 * iface, + UINT indexFunc, + UINT indexParam, + REFGUID guid, + VARIANT *pVarVal) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + TLBCustData *pCData=NULL; + TLBFuncDesc * pFDesc; + int i; + + for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++,pFDesc=pFDesc->next); + + if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams) + for(pCData=pFDesc->pParamDesc[indexParam].pCustData; pCData; + pCData = pCData->next) + if( IsEqualIID(guid, &pCData->guid)) break; + + TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT"); + + if(pCData) + { + VariantInit( pVarVal); + VariantCopy( pVarVal, &pCData->data); + return S_OK; + } + return E_INVALIDARG; /* FIXME: correct? */ +} + +/* ITypeInfo2::GetVarCustData + * + * Gets the custom data + */ +static HRESULT WINAPI ITypeInfo2_fnGetVarCustData( + ITypeInfo2 * iface, + UINT index, + REFGUID guid, + VARIANT *pVarVal) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + TLBCustData *pCData=NULL; + TLBVarDesc * pVDesc; + int i; + + for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, pVDesc=pVDesc->next); + + if(pVDesc) + { + for(pCData=pVDesc->pCustData; pCData; pCData = pCData->next) + { + if( IsEqualIID(guid, &pCData->guid)) break; + } + } + + TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT"); + + if(pCData) + { + VariantInit( pVarVal); + VariantCopy( pVarVal, &pCData->data); + return S_OK; + } + return E_INVALIDARG; /* FIXME: correct? */ +} + +/* ITypeInfo2::GetImplCustData + * + * Gets the custom data + */ +static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData( + ITypeInfo2 * iface, + UINT index, + REFGUID guid, + VARIANT *pVarVal) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + TLBCustData *pCData=NULL; + TLBImplType * pRDesc; + int i; + + for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++, pRDesc=pRDesc->next); + + if(pRDesc) + { + for(pCData=pRDesc->pCustData; pCData; pCData = pCData->next) + { + if( IsEqualIID(guid, &pCData->guid)) break; + } + } + + TRACE("(%p) guid %s %s found!x)\n", This, debugstr_guid(guid), pCData? "" : "NOT"); + + if(pCData) + { + VariantInit( pVarVal); + VariantCopy( pVarVal, &pCData->data); + return S_OK; + } + return E_INVALIDARG; /* FIXME: correct? */ +} + +/* ITypeInfo2::GetDocumentation2 + * + * Retrieves the documentation string, the complete Help file name and path, + * the localization context to use, and the context ID for the library Help + * topic in the Help file. + * + */ +static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2( + ITypeInfo2 * iface, + MEMBERID memid, + LCID lcid, + BSTR *pbstrHelpString, + DWORD *pdwHelpStringContext, + BSTR *pbstrHelpStringDll) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + TLBFuncDesc * pFDesc; + TLBVarDesc * pVDesc; + TRACE("(%p) memid %ld lcid(0x%lx) HelpString(%p) " + "HelpStringContext(%p) HelpStringDll(%p)\n", + This, memid, lcid, pbstrHelpString, pdwHelpStringContext, + pbstrHelpStringDll ); + /* the help string should be obtained from the helpstringdll, + * using the _DLLGetDocumentation function, based on the supplied + * lcid. Nice to do sometime... + */ + if(memid==MEMBERID_NIL){ /* documentation for the typeinfo */ + if(pbstrHelpString) + *pbstrHelpString=SysAllocString(This->Name); + if(pdwHelpStringContext) + *pdwHelpStringContext=This->dwHelpStringContext; + if(pbstrHelpStringDll) + *pbstrHelpStringDll= + SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */ + return S_OK; + }else {/* for a member */ + for(pFDesc=This->funclist; pFDesc; pFDesc=pFDesc->next) + if(pFDesc->funcdesc.memid==memid){ + if(pbstrHelpString) + *pbstrHelpString=SysAllocString(pFDesc->HelpString); + if(pdwHelpStringContext) + *pdwHelpStringContext=pFDesc->HelpStringContext; + if(pbstrHelpStringDll) + *pbstrHelpStringDll= + SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */ + return S_OK; + } + for(pVDesc=This->varlist; pVDesc; pVDesc=pVDesc->next) + if(pVDesc->vardesc.memid==memid){ + if(pbstrHelpString) + *pbstrHelpString=SysAllocString(pVDesc->HelpString); + if(pdwHelpStringContext) + *pdwHelpStringContext=pVDesc->HelpStringContext; + if(pbstrHelpStringDll) + *pbstrHelpStringDll= + SysAllocString(This->pTypeLib->HelpStringDll);/* FIXME */ + return S_OK; + } + } + return TYPE_E_ELEMENTNOTFOUND; +} + +/* ITypeInfo2::GetAllCustData + * + * Gets all custom data items for the Type info. + * + */ +static HRESULT WINAPI ITypeInfo2_fnGetAllCustData( + ITypeInfo2 * iface, + CUSTDATA *pCustData) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + TLBCustData *pCData; + int i; + + TRACE("(%p) returning %d items\n", This, This->ctCustData); + + pCustData->prgCustData = TLB_Alloc(This->ctCustData * sizeof(CUSTDATAITEM)); + if(pCustData->prgCustData ){ + pCustData->cCustData=This->ctCustData; + for(i=0, pCData=This->pCustData; pCData; i++, pCData = pCData->next){ + pCustData->prgCustData[i].guid=pCData->guid; + VariantCopy(& pCustData->prgCustData[i].varValue, & pCData->data); + } + }else{ + ERR(" OUT OF MEMORY! \n"); + return E_OUTOFMEMORY; + } + return S_OK; +} + +/* ITypeInfo2::GetAllFuncCustData + * + * Gets all custom data items for the specified Function + * + */ +static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData( + ITypeInfo2 * iface, + UINT index, + CUSTDATA *pCustData) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + TLBCustData *pCData; + TLBFuncDesc * pFDesc; + int i; + TRACE("(%p) index %d\n", This, index); + for(i=0, pFDesc=This->funclist; i!=index && pFDesc; i++, + pFDesc=pFDesc->next) + ; + if(pFDesc){ + pCustData->prgCustData = + TLB_Alloc(pFDesc->ctCustData * sizeof(CUSTDATAITEM)); + if(pCustData->prgCustData ){ + pCustData->cCustData=pFDesc->ctCustData; + for(i=0, pCData=pFDesc->pCustData; pCData; i++, + pCData = pCData->next){ + pCustData->prgCustData[i].guid=pCData->guid; + VariantCopy(& pCustData->prgCustData[i].varValue, + & pCData->data); + } + }else{ + ERR(" OUT OF MEMORY! \n"); + return E_OUTOFMEMORY; + } + return S_OK; + } + return TYPE_E_ELEMENTNOTFOUND; +} + +/* ITypeInfo2::GetAllParamCustData + * + * Gets all custom data items for the Functions + * + */ +static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( ITypeInfo2 * iface, + UINT indexFunc, UINT indexParam, CUSTDATA *pCustData) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + TLBCustData *pCData=NULL; + TLBFuncDesc * pFDesc; + int i; + TRACE("(%p) index %d\n", This, indexFunc); + for(i=0, pFDesc=This->funclist; i!=indexFunc && pFDesc; i++, + pFDesc=pFDesc->next) + ; + if(pFDesc && indexParam >=0 && indexParam<pFDesc->funcdesc.cParams){ + pCustData->prgCustData = + TLB_Alloc(pFDesc->pParamDesc[indexParam].ctCustData * + sizeof(CUSTDATAITEM)); + if(pCustData->prgCustData ){ + pCustData->cCustData=pFDesc->pParamDesc[indexParam].ctCustData; + for(i=0, pCData=pFDesc->pParamDesc[indexParam].pCustData; + pCData; i++, pCData = pCData->next){ + pCustData->prgCustData[i].guid=pCData->guid; + VariantCopy(& pCustData->prgCustData[i].varValue, + & pCData->data); + } + }else{ + ERR(" OUT OF MEMORY! \n"); + return E_OUTOFMEMORY; + } + return S_OK; + } + return TYPE_E_ELEMENTNOTFOUND; +} + +/* ITypeInfo2::GetAllVarCustData + * + * Gets all custom data items for the specified Variable + * + */ +static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( ITypeInfo2 * iface, + UINT index, CUSTDATA *pCustData) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + TLBCustData *pCData; + TLBVarDesc * pVDesc; + int i; + TRACE("(%p) index %d\n", This, index); + for(i=0, pVDesc=This->varlist; i!=index && pVDesc; i++, + pVDesc=pVDesc->next) + ; + if(pVDesc){ + pCustData->prgCustData = + TLB_Alloc(pVDesc->ctCustData * sizeof(CUSTDATAITEM)); + if(pCustData->prgCustData ){ + pCustData->cCustData=pVDesc->ctCustData; + for(i=0, pCData=pVDesc->pCustData; pCData; i++, + pCData = pCData->next){ + pCustData->prgCustData[i].guid=pCData->guid; + VariantCopy(& pCustData->prgCustData[i].varValue, + & pCData->data); + } + }else{ + ERR(" OUT OF MEMORY! \n"); + return E_OUTOFMEMORY; + } + return S_OK; + } + return TYPE_E_ELEMENTNOTFOUND; +} + +/* ITypeInfo2::GetAllImplCustData + * + * Gets all custom data items for the specified implementation type + * + */ +static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData( + ITypeInfo2 * iface, + UINT index, + CUSTDATA *pCustData) +{ + ITypeInfoImpl *This = (ITypeInfoImpl *)iface; + TLBCustData *pCData; + TLBImplType * pRDesc; + int i; + TRACE("(%p) index %d\n", This, index); + for(i=0, pRDesc=This->impltypelist; i!=index && pRDesc; i++, + pRDesc=pRDesc->next) + ; + if(pRDesc){ + pCustData->prgCustData = + TLB_Alloc(pRDesc->ctCustData * sizeof(CUSTDATAITEM)); + if(pCustData->prgCustData ){ + pCustData->cCustData=pRDesc->ctCustData; + for(i=0, pCData=pRDesc->pCustData; pCData; i++, + pCData = pCData->next){ + pCustData->prgCustData[i].guid=pCData->guid; + VariantCopy(& pCustData->prgCustData[i].varValue, + & pCData->data); + } + }else{ + ERR(" OUT OF MEMORY! \n"); + return E_OUTOFMEMORY; + } + return S_OK; + } + return TYPE_E_ELEMENTNOTFOUND; +} + +static ITypeInfo2Vtbl tinfvt = +{ + + ITypeInfo_fnQueryInterface, + ITypeInfo_fnAddRef, + ITypeInfo_fnRelease, + + ITypeInfo_fnGetTypeAttr, + ITypeInfo_fnGetTypeComp, + ITypeInfo_fnGetFuncDesc, + ITypeInfo_fnGetVarDesc, + ITypeInfo_fnGetNames, + ITypeInfo_fnGetRefTypeOfImplType, + ITypeInfo_fnGetImplTypeFlags, + ITypeInfo_fnGetIDsOfNames, + ITypeInfo_fnInvoke, + ITypeInfo_fnGetDocumentation, + ITypeInfo_fnGetDllEntry, + ITypeInfo_fnGetRefTypeInfo, + ITypeInfo_fnAddressOfMember, + ITypeInfo_fnCreateInstance, + ITypeInfo_fnGetMops, + ITypeInfo_fnGetContainingTypeLib, + ITypeInfo_fnReleaseTypeAttr, + ITypeInfo_fnReleaseFuncDesc, + ITypeInfo_fnReleaseVarDesc, + + ITypeInfo2_fnGetTypeKind, + ITypeInfo2_fnGetTypeFlags, + ITypeInfo2_fnGetFuncIndexOfMemId, + ITypeInfo2_fnGetVarIndexOfMemId, + ITypeInfo2_fnGetCustData, + ITypeInfo2_fnGetFuncCustData, + ITypeInfo2_fnGetParamCustData, + ITypeInfo2_fnGetVarCustData, + ITypeInfo2_fnGetImplTypeCustData, + ITypeInfo2_fnGetDocumentation2, + ITypeInfo2_fnGetAllCustData, + ITypeInfo2_fnGetAllFuncCustData, + ITypeInfo2_fnGetAllParamCustData, + ITypeInfo2_fnGetAllVarCustData, + ITypeInfo2_fnGetAllImplTypeCustData, +}; + +/****************************************************************************** + * CreateDispTypeInfo [OLEAUT32.31] + * + * Build type information for an object so it can be called through an + * IDispatch interface. + * + * RETURNS + * Success: S_OK. pptinfo contains the created ITypeInfo object. + * Failure: E_INVALIDARG, if one or more arguments is invalid. + * + * NOTES + * This call allows an objects methods to be accessed through IDispatch, by + * building an ITypeInfo object that IDispatch can use to call through. + */ +HRESULT WINAPI CreateDispTypeInfo( + INTERFACEDATA *pidata, /* [I] Description of the interface to build type info for */ + LCID lcid, /* [I] Locale Id */ + ITypeInfo **pptinfo) /* [O] Destination for created ITypeInfo object */ +{ + ITypeInfoImpl *pTIImpl; + int param, func; + TLBFuncDesc **ppFuncDesc; + + pTIImpl = (ITypeInfoImpl*)ITypeInfo_Constructor(); + pTIImpl->pTypeLib = NULL; + pTIImpl->index = 0; + pTIImpl->Name = NULL; + pTIImpl->dwHelpContext = -1; + memset(&pTIImpl->TypeAttr.guid, 0, sizeof(GUID)); + pTIImpl->TypeAttr.lcid = lcid; + pTIImpl->TypeAttr.typekind = TKIND_COCLASS; + pTIImpl->TypeAttr.wMajorVerNum = 0; + pTIImpl->TypeAttr.wMinorVerNum = 0; + pTIImpl->TypeAttr.cbAlignment = 2; + pTIImpl->TypeAttr.cbSizeInstance = -1; + pTIImpl->TypeAttr.cbSizeVft = -1; + pTIImpl->TypeAttr.cFuncs = 0; + pTIImpl->TypeAttr.cImplTypes = 1; + pTIImpl->TypeAttr.cVars = 0; + pTIImpl->TypeAttr.wTypeFlags = 0; + + ppFuncDesc = &pTIImpl->funclist; + for(func = 0; func < pidata->cMembers; func++) { + METHODDATA *md = pidata->pmethdata + func; + *ppFuncDesc = HeapAlloc(GetProcessHeap(), 0, sizeof(**ppFuncDesc)); + (*ppFuncDesc)->Name = SysAllocString(md->szName); + (*ppFuncDesc)->funcdesc.memid = md->dispid; + (*ppFuncDesc)->funcdesc.invkind = md->wFlags; + (*ppFuncDesc)->funcdesc.callconv = md->cc; + (*ppFuncDesc)->funcdesc.cParams = md->cArgs; + (*ppFuncDesc)->funcdesc.cParamsOpt = 0; + (*ppFuncDesc)->funcdesc.oVft = md->iMeth; + (*ppFuncDesc)->funcdesc.wFuncFlags = 0; /*??*/ + (*ppFuncDesc)->funcdesc.elemdescFunc.tdesc.vt = md->vtReturn; + (*ppFuncDesc)->funcdesc.lprgelemdescParam = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + md->cArgs * sizeof(ELEMDESC)); + (*ppFuncDesc)->pParamDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + md->cArgs * sizeof(TLBParDesc)); + for(param = 0; param < md->cArgs; param++) { + (*ppFuncDesc)->funcdesc.lprgelemdescParam[param].tdesc.vt = md->ppdata[param].vt; + (*ppFuncDesc)->pParamDesc[param].Name = SysAllocString(md->ppdata[param].szName); + } + ppFuncDesc = &(*ppFuncDesc)->next; + } + *pptinfo = (ITypeInfo*)pTIImpl; + return S_OK; + +} + +static HRESULT WINAPI ITypeComp_fnQueryInterface(ITypeComp * iface, REFIID riid, LPVOID * ppv) +{ + ICOM_THIS_From_ITypeComp(ITypeInfoImpl, iface); + + return ITypeInfo_QueryInterface((ITypeInfo *)This, riid, ppv); +} + +static ULONG WINAPI ITypeComp_fnAddRef(ITypeComp * iface) +{ + ICOM_THIS_From_ITypeComp(ITypeInfoImpl, iface); + + return ITypeInfo_AddRef((ITypeInfo *)This); +} + +static ULONG WINAPI ITypeComp_fnRelease(ITypeComp * iface) +{ + ICOM_THIS_From_ITypeComp(ITypeInfoImpl, iface); + + return ITypeInfo_Release((ITypeInfo *)This); +} + +static HRESULT WINAPI ITypeComp_fnBind( + ITypeComp * iface, + OLECHAR * szName, + ULONG lHash, + WORD wFlags, + ITypeInfo ** ppTInfo, + DESCKIND * pDescKind, + BINDPTR * pBindPtr) +{ + ICOM_THIS_From_ITypeComp(ITypeInfoImpl, iface); + TLBFuncDesc * pFDesc; + TLBVarDesc * pVDesc; + + TRACE("(%s, %lx, 0x%x, %p, %p, %p)\n", debugstr_w(szName), lHash, wFlags, ppTInfo, pDescKind, pBindPtr); + + for(pFDesc = This->funclist; pFDesc; pFDesc = pFDesc->next) + if (pFDesc->funcdesc.invkind & wFlags) + if (!strcmpW(pFDesc->Name, szName)) { + break; + } + + if (pFDesc) + { + *pDescKind = DESCKIND_FUNCDESC; + pBindPtr->lpfuncdesc = &pFDesc->funcdesc; + *ppTInfo = (ITypeInfo *)&This->lpVtbl; + return S_OK; + } else { + if (!(wFlags & ~(INVOKE_PROPERTYGET))) + { + for(pVDesc = This->varlist; pVDesc; pVDesc = pVDesc->next) { + if (!strcmpW(pVDesc->Name, szName)) { + *pDescKind = DESCKIND_VARDESC; + pBindPtr->lpvardesc = &pVDesc->vardesc; + *ppTInfo = (ITypeInfo *)&This->lpVtbl; + return S_OK; + } + } + } + } + /* not found, look for it in inherited interfaces */ + if (This->TypeAttr.cImplTypes && + (This->TypeAttr.typekind == TKIND_INTERFACE || This->TypeAttr.typekind == TKIND_DISPATCH)) { + /* recursive search */ + ITypeInfo *pTInfo; + ITypeComp *pTComp; + HRESULT hr; + hr=ITypeInfo_GetRefTypeInfo((ITypeInfo *)&This->lpVtbl, This->impltypelist->hRef, &pTInfo); + if (SUCCEEDED(hr)) + { + hr = ITypeInfo_GetTypeComp(pTInfo,&pTComp); + ITypeInfo_Release(pTInfo); + } + if (SUCCEEDED(hr)) + { + hr = ITypeComp_Bind(pTComp, szName, lHash, wFlags, ppTInfo, pDescKind, pBindPtr); + ITypeComp_Release(pTComp); + return hr; + } + WARN("Could not search inherited interface!\n"); + } + ERR("did not find member with name %s, flags 0x%x!\n", debugstr_w(szName), wFlags); + *pDescKind = DESCKIND_NONE; + pBindPtr->lpfuncdesc = NULL; + *ppTInfo = NULL; + return DISP_E_MEMBERNOTFOUND; +} + +static HRESULT WINAPI ITypeComp_fnBindType( + ITypeComp * iface, + OLECHAR * szName, + ULONG lHash, + ITypeInfo ** ppTInfo, + ITypeComp ** ppTComp) +{ + TRACE("(%s, %lx, %p, %p)\n", debugstr_w(szName), lHash, ppTInfo, ppTComp); + + /* strange behaviour (does nothing) but like the + * original */ + + if (!ppTInfo || !ppTComp) + return E_POINTER; + + *ppTInfo = NULL; + *ppTComp = NULL; + + return S_OK; +} + +static ITypeCompVtbl tcompvt = +{ + + ITypeComp_fnQueryInterface, + ITypeComp_fnAddRef, + ITypeComp_fnRelease, + + ITypeComp_fnBind, + ITypeComp_fnBindType +}; diff --git a/reactos/lib/oleaut32/typelib.h b/reactos/lib/oleaut32/typelib.h index 0276b33d0df..e519aa7a18b 100644 --- a/reactos/lib/oleaut32/typelib.h +++ b/reactos/lib/oleaut32/typelib.h @@ -1,600 +1,600 @@ -/* - * typelib.h internal wine data structures - * used to decode typelib's - * - * Copyright 1999 Rein KLazes - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _WINE_TYPELIB_H -#define _WINE_TYPELIB_H - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "oleauto.h" -#include "wine/windef16.h" - -#define HELPDLLFLAG (0x0100) -#define DO_NOT_SEEK (-1) - -#define MSFT_HREFTYPE_INTHISFILE(href) (!((href) & 3)) -#define MSFT_HREFTYPE_INDEX(href) ((href) /sizeof(MSFT_TypeInfoBase)) - -/*-------------------------FILE STRUCTURES-----------------------------------*/ - -/* There are two known file formats, those created with ICreateTypeLib - * have the signature "SLTG" as their first four bytes, while those created - * with ICreateTypeLib2 have "MSFT". - */ - -/***************************************************** - * MSFT typelibs - * - * These are TypeLibs created with ICreateTypeLib2 - * - */ - -/* - * structure of the typelib type2 header - * it is at the beginning of a type lib file - * - */ -typedef struct tagMSFT_Header { -/*0x00*/INT magic1; /* 0x5446534D "MSFT" */ - INT magic2; /* 0x00010002 version nr? */ - INT posguid; /* position of libid in guid table */ - /* (should be, else -1) */ - INT lcid; /* locale id */ -/*0x10*/INT lcid2; - INT varflags; /* (largely) unknown flags ,seems to be always 41 */ - /* becomes 0x51 with a helpfile defined */ - /* if help dll defined it's 0x151 */ - /* update : the lower nibble is syskind */ - INT version; /* set with SetVersion() */ - INT flags; /* set with SetFlags() */ -/*0x20*/INT nrtypeinfos; /* number of typeinfo's (till so far) */ - INT helpstring; /* position of help string in stringtable */ - INT helpstringcontext; - INT helpcontext; -/*0x30*/INT nametablecount; /* number of names in name table */ - INT nametablechars; /* nr of characters in name table */ - INT NameOffset; /* offset of name in name table */ - INT helpfile; /* position of helpfile in stringtable */ -/*0x40*/INT CustomDataOffset; /* if -1 no custom data, else it is offset */ - /* in customer data/guid offset table */ - INT res44; /* unknown always: 0x20 (guid hash size?) */ - INT res48; /* unknown always: 0x80 (name hash size?) */ - INT dispatchpos; /* HREFTYPE to IDispatch, or -1 if no IDispatch */ -/*0x50*/INT res50; /* is zero becomes one when an interface is derived */ -} MSFT_Header; - -/* segments in the type lib file have a structure like this: */ -typedef struct tagMSFT_pSeg { - INT offset; /* absolute offset in file */ - INT length; /* length of segment */ - INT res08; /* unknown always -1 */ - INT res0c; /* unknown always 0x0f in the header */ - /* 0x03 in the typeinfo_data */ -} MSFT_pSeg; - -/* layout of the main segment directory */ -typedef struct tagMSFT_SegDir { -/*1*/MSFT_pSeg pTypeInfoTab; /* each type info get an entry of 0x64 bytes */ - /* (25 ints) */ -/*2*/MSFT_pSeg pImpInfo; /* table with info for imported types */ -/*3*/MSFT_pSeg pImpFiles; /* import libaries */ -/*4*/MSFT_pSeg pRefTab; /* References table */ -/*5*/MSFT_pSeg pLibtab; /* always exists, alway same size (0x80) */ - /* hash table w offsets to guid????? */ -/*6*/MSFT_pSeg pGuidTab; /* all guids are stored here together with */ - /* offset in some table???? */ -/*7*/MSFT_pSeg res07; /* always created, alway same size (0x200) */ - /* purpose largely unknown */ -/*8*/MSFT_pSeg pNametab; /* name tables */ -/*9*/MSFT_pSeg pStringtab; /* string table */ -/*A*/MSFT_pSeg pTypdescTab; /* table with type descriptors */ -/*B*/MSFT_pSeg pArrayDescriptions; -/*C*/MSFT_pSeg pCustData; /* data table, used for custom data and default */ - /* parameter values */ -/*D*/MSFT_pSeg pCDGuids; /* table with offsets for the guids and into */ - /* the customer data table */ -/*E*/MSFT_pSeg res0e; /* unknown */ -/*F*/MSFT_pSeg res0f; /* unknown */ -} MSFT_SegDir; - - -/* base type info data */ -typedef struct tagMSFT_TypeInfoBase { -/*000*/ INT typekind; /* it is the TKIND_xxx */ - /* some byte alignment stuf */ - INT memoffset; /* points past the file, if no elements */ - INT res2; /* zero if no element, N*0x40 */ - INT res3; /* -1 if no lement, (N-1)*0x38 */ -/*010*/ INT res4; /* always? 3 */ - INT res5; /* always? zero */ - INT cElement; /* counts elements, HI=cVars, LO=cFuncs */ - INT res7; /* always? zero */ -/*020*/ INT res8; /* always? zero */ - INT res9; /* always? zero */ - INT resA; /* always? zero */ - INT posguid; /* position in guid table */ -/*030*/ INT flags; /* Typeflags */ - INT NameOffset; /* offset in name table */ - INT version; /* element version */ - INT docstringoffs; /* offset of docstring in string tab */ -/*040*/ INT helpstringcontext; /* */ - INT helpcontext; /* */ - INT oCustData; /* offset in customer data table */ -#ifdef WORDS_BIGENDIAN - INT16 cbSizeVft; /* virtual table size, not including inherits */ - INT16 cImplTypes; /* nr of implemented interfaces */ -#else - INT16 cImplTypes; /* nr of implemented interfaces */ - INT16 cbSizeVft; /* virtual table size, not including inherits */ -#endif -/*050*/ INT size; /* size in bytes, at least for structures */ - /* FIXME: name of this field */ - INT datatype1; /* position in type description table */ - /* or in base intefaces */ - /* if coclass: offset in reftable */ - /* if interface: reference to inherited if */ - INT datatype2; /* if 0x8000, entry above is valid */ - /* actually dunno */ - /* else it is zero? */ - INT res18; /* always? 0 */ -/*060*/ INT res19; /* always? -1 */ - } MSFT_TypeInfoBase; - -/* layout of an entry with information on imported types */ -typedef struct tagMSFT_ImpInfo { - INT res0; /* unknown */ - INT oImpFile; /* offset inthe Import File table */ - INT oGuid; /* offset in Guid table */ - } MSFT_ImpInfo; - -/* function description data */ -typedef struct { -/* INT recsize; record size including some xtra stuff */ - INT DataType; /* data type of the member, eg return of function */ - INT Flags; /* something to do with attribute flags (LOWORD) */ -#ifdef WORDS_BIGENDIAN - INT16 funcdescsize; /* size of reconstituted FUNCDESC and related structs */ - INT16 VtableOffset; /* offset in vtable */ -#else - INT16 VtableOffset; /* offset in vtable */ - INT16 funcdescsize; /* size of reconstituted FUNCDESC and related structs */ -#endif - INT FKCCIC; /* bit string with the following */ - /* meaning (bit 0 is the msb): */ - /* bit 2 indicates that oEntry is numeric */ - /* bit 3 that parameter has default values */ - /* calling convention (bits 4-7 ) */ - /* bit 8 indicates that custom data is present */ - /* Invocation kind (bits 9-12 ) */ - /* function kind (eg virtual), bits 13-15 */ -#ifdef WORDS_BIGENDIAN - INT16 nroargs; /* nr of optional arguments */ - INT16 nrargs; /* number of arguments (including optional ????) */ -#else - INT16 nrargs; /* number of arguments (including optional ????) */ - INT16 nroargs; /* nr of optional arguments */ -#endif - /* optional attribute fields, the number of them is variable */ - INT OptAttr[1]; -/* -0* INT helpcontext; -1* INT oHelpString; -2* INT oEntry; // either offset in string table or numeric as it is // -3* INT res9; // unknown (-1) // -4* INT resA; // unknown (-1) // -5* INT HelpStringContext; - // these are controlled by a bit set in the FKCCIC field // -6* INT oCustData; // custom data for function // -7* INT oArgCustData[1]; // custom data per argument // -*/ -} MSFT_FuncRecord; - -/* after this may follow an array with default value pointers if the - * appropriate bit in the FKCCIC field has been set: - * INT oDefautlValue[nrargs]; - */ - - /* Parameter info one per argument*/ -typedef struct { - INT DataType; - INT oName; - INT Flags; - } MSFT_ParameterInfo; - -/* Variable description data */ -typedef struct { -/* INT recsize; // record size including some xtra stuff */ - INT DataType; /* data type of the variable */ - INT Flags; /* VarFlags (LOWORD) */ -#ifdef WORDS_BIGENDIAN - INT16 vardescsize; /* size of reconstituted VARDESC and related structs */ - INT16 VarKind; /* VarKind */ -#else - INT16 VarKind; /* VarKind */ - INT16 vardescsize; /* size of reconstituted VARDESC and related structs */ -#endif - INT OffsValue; /* value of the variable or the offset */ - /* in the data structure */ - /* optional attribute fields, the number of them is variable */ - /* controlled by record length */ - INT HelpContext; - INT oHelpString; - INT res9; /* unknown (-1) */ - INT oCustData; /* custom data for variable */ - INT HelpStringContext; - -} MSFT_VarRecord; - -/* Structure of the reference data */ -typedef struct { - INT reftype; /* either offset in type info table, then it's */ - /* a multiple of 64 */ - /* or offset in the external reference table */ - /* with an offset of 1 */ - INT flags; - INT oCustData; /* custom data */ - INT onext; /* next offset, -1 if last */ -} MSFT_RefRecord; - -/* this is how a guid is stored */ -typedef struct { - GUID guid; - INT hreftype; /* -2 for the typelib guid, typeinfo offset - for typeinfo guid, low two bits are 01 if - this is an imported typeinfo, low two bits - are 10 if this is an imported typelib (used - by imported typeinfos) */ - INT next_hash; /* offset to next guid in the hash bucket */ -} MSFT_GuidEntry; -/* some data preceding entries in the name table */ -typedef struct { - INT hreftype; /* is -1 if name is for neither a typeinfo, - a variable, or a function (that is, name - is for a typelib or a function parameter). - otherwise is the offset of the first - typeinfo that this name refers to (either - to the typeinfo itself or to a member of - the typeinfo */ - INT next_hash; /* offset to next name in the hash bucket */ - INT namelen; /* only lower 8 bits are valid, - lower-middle 8 bits are unknown (flags?), - upper 16 bits are hash code */ -} MSFT_NameIntro; -/* the custom data table directory has enties like this */ -typedef struct { - INT GuidOffset; - INT DataOffset; - INT next; /* next offset in the table, -1 if it's the last */ -} MSFT_CDGuid; - - -/*********************************************************** - * - * SLTG typelibs. - * - * These are created with ICreateTypeLib - * - */ - -#include "pshpack1.h" - -typedef struct { -/*00*/ DWORD SLTG_magic; /* 0x47544c53 == "SLTG" */ -/*04*/ WORD nrOfFileBlks; /* no of SLTG_BlkEntry's + 1 */ -/*06*/ WORD res06; /* ?? always 9 */ -/*08*/ WORD res08; /* some kind of len/offset ?? */ -/*0a*/ WORD first_blk; /* 1 based index into blk entries that - corresponds to first block in file */ -/*0c*/ DWORD res0c; /* always 0x000204ff */ -/*10*/ DWORD res10; /* always 0x00000000 */ -/*14*/ DWORD res14; /* always 0x000000c0 */ -/*18*/ DWORD res18; /* always 0x46000000 */ -/*1c*/ DWORD res1c; /* always 0x00000044 */ -/*20*/ DWORD res20; /* always 0xffff0000 */ -} SLTG_Header; - -/* This gets followed by a list of block entries */ -typedef struct { -/*00*/ DWORD len; -/*04*/ WORD index_string; /* offs from start of SLTG_Magic to index string */ -/*06*/ WORD next; -} SLTG_BlkEntry; - -/* The order of the blocks in the file is given by starting at Block - entry firt_blk and stepping through using the next pointer */ - -/* These then get followed by this magic */ -typedef struct { -/*00*/ BYTE res00; /* always 0x01 */ -/*01*/ CHAR CompObj_magic[8]; /* always "CompObj" */ -/*09*/ CHAR dir_magic[4]; /* always "dir" */ -} SLTG_Magic; - -#define SLTG_COMPOBJ_MAGIC "CompObj" -#define SLTG_DIR_MAGIC "dir" - -/* Next we have SLTG_Header.nrOfFileBlks - 2 of Index strings. These -are presumably unique to within the file and look something like -"AAAAAAAAAA" with the first character incremented from 'A' to ensure -uniqueness. I guess successive chars increment when we need to wrap -the first one. */ - -typedef struct { -/*00*/ CHAR string[11]; -} SLTG_Index; - - -/* This is followed by SLTG_pad9 */ -typedef struct { -/*00*/ CHAR pad[9]; /* 9 '\0's */ -} SLTG_Pad9; - - -/* Now we have the noOfFileBlks - 1 worth of blocks. The length of -each block is given by its entry in SLTG_BlkEntry. */ - -/* type SLTG_NAME in rather like a BSTR except that the length in -bytes is given by the first WORD and the string contains 8bit chars */ - -typedef WORD SLTG_Name; - -/* The main library block looks like this. This one seems to come last */ - -typedef struct { -/*00*/ WORD magic; /* 0x51cc */ -/*02*/ WORD res02; /* 0x0003, 0x0004 */ -/*04*/ WORD name; /* offset to name in name table */ -/*06*/ SLTG_Name res06; /* maybe this is just WORD == 0xffff */ - SLTG_Name helpstring; - SLTG_Name helpfile; - DWORD helpcontext; - WORD syskind; /* == 1 for win32, 0 for win16 */ - WORD lcid; /* == 0x409, 0x809 etc */ - DWORD res12; /* == 0 */ - WORD libflags; /* LIBFLAG_* */ - WORD maj_vers; - WORD min_vers; - GUID uuid; -} SLTG_LibBlk; - -#define SLTG_LIBBLK_MAGIC 0x51cc - -/* we then get 0x40 bytes worth of 0xffff or small numbers followed by - nrOfFileBlks - 2 of these */ -typedef struct { - WORD small_no; - SLTG_Name index_name; /* This refers to a name in the directory */ - SLTG_Name other_name; /* Another one of these weird names */ - WORD res1a; /* 0xffff */ - WORD name_offs; /* offset to name in name table */ - WORD more_bytes; /* if this is non-zero we get this many - bytes before the next element, which seem - to reference the docstring of the type ? */ - WORD res20; /* 0xffff */ - DWORD helpcontext; - WORD res26; /* 0xffff */ - GUID uuid; -} SLTG_OtherTypeInfo; - -/* Next we get WORD 0x0003 followed by a DWORD which if we add to -0x216 gives the offset to the name table from the start of the LibBlk -struct */ - -typedef struct { -/*00*/ WORD magic; /* 0x0501 */ -/*02*/ DWORD href_table; /* if not 0xffffffff, then byte offset from - beginning of struct to href table */ -/*06*/ DWORD res06; /* 0xffffffff */ -/*0a*/ DWORD elem_table; /* offset to members */ -/*0e*/ DWORD res0e; /* 0xffffffff */ -/*12*/ WORD major_version; /* major version number */ -/*14*/ WORD minor_version; /* minor version number */ -/*16*/ DWORD res16; /* 0xfffe0000 */ -/*1a*/ BYTE typeflags1;/* 0x02 | top 5 bits hold l5sbs of TYPEFLAGS */ -/*1b*/ BYTE typeflags2;/* TYPEFLAGS >> 5 */ -/*1c*/ BYTE typeflags3;/* 0x02*/ -/*1d*/ BYTE typekind; /* 0x03 == TKIND_INTERFACE etc. */ -/*1e*/ DWORD res1e; /* 0x00000000 or 0xffffffff */ -} SLTG_TypeInfoHeader; - -#define SLTG_TIHEADER_MAGIC 0x0501 - -typedef struct { -/*00*/ WORD cFuncs; -/*02*/ WORD cVars; -/*04*/ WORD cImplTypes; -/*06*/ WORD res06; -/*08*/ WORD res08; -/*0a*/ WORD res0a; -/*0c*/ WORD res0c; -/*0e*/ WORD res0e; -/*10*/ WORD res10; -/*12*/ WORD res12; -/*14*/ WORD tdescalias_vt; /* for TKIND_ALIAS */ -/*16*/ WORD res16; -/*18*/ WORD res18; -/*1a*/ WORD res1a; -/*1c*/ WORD res1c; -/*1e*/ WORD res1e; -/*20*/ WORD cbSizeInstance; -/*22*/ WORD cbAlignment; -/*24*/ WORD res24; -/*26*/ WORD res26; -/*28*/ WORD cbSizeVft; -/*2a*/ WORD res2a; -/*2c*/ WORD res2c; -/*2e*/ WORD res2e; -/*30*/ WORD res30; -/*32*/ WORD res32; -/*34*/ WORD res34; -} SLTG_TypeInfoTail; - -typedef struct { -/*00*/ WORD res00; /* 0x0001 sometimes 0x0003 ?? */ -/*02*/ WORD res02; /* 0xffff */ -/*04*/ BYTE res04; /* 0x01 */ -/*05*/ DWORD cbExtra; /* No of bytes that follow */ -} SLTG_MemberHeader; - -typedef struct { -/*00*/ WORD magic; /* 0x120a */ -/*02*/ WORD next; /* offset in bytes to next block from start of block - group, 0xffff if last item */ -/*04*/ WORD name; /* offset to name within name table */ -/*06*/ WORD value; /* offset to value from start of block group */ -/*08*/ WORD res08; /* 0x56 */ -/*0a*/ DWORD memid; /* memid */ -/*0e*/ WORD helpcontext;/* 0xfffe == no context, 0x0001 == stored in EnumInfo struct, else offset - to value from start of block group */ -/*10*/ WORD helpstring;/* offset from start of block group to string offset */ -} SLTG_EnumItem; - -#define SLTG_ENUMITEM_MAGIC 0x120a - -typedef struct { -/*00*/ WORD vt; /* vartype, 0xffff marks end. */ -/*02*/ WORD res02; /* ?, 0xffff marks end */ -} SLTG_AliasItem; - -#define SLTG_ALIASITEM_MAGIC 0x001d - - -typedef struct { - BYTE magic; /* 0x4c or 0x6c */ - BYTE inv; /* high nibble is INVOKE_KIND, low nibble = 2 */ - WORD next; /* byte offset from beginning of group to next fn */ - WORD name; /* Offset within name table to name */ - DWORD dispid; /* dispid */ - WORD helpcontext; /* helpcontext (again 1 is special) */ - WORD helpstring;/* helpstring offset to offset */ - WORD arg_off; /* offset to args from start of block */ - BYTE nacc; /* lowest 3bits are CALLCONV, rest are no of args */ - BYTE retnextopt;/* if 0x80 bit set ret type follows else next WORD - is offset to ret type. No of optional args is - middle 6 bits */ - WORD rettype; /* return type VT_?? or offset to ret type */ - WORD vtblpos; /* position in vtbl? */ - WORD funcflags; /* present if magic == 0x6c */ -/* Param list starts, repeat next two as required */ -#if 0 - WORD name; /* offset to 2nd letter of name */ - WORD+ type; /* VT_ of param */ -#endif -} SLTG_Function; - -#define SLTG_FUNCTION_MAGIC 0x4c -#define SLTG_FUNCTION_WITH_FLAGS_MAGIC 0x6c - -typedef struct { -/*00*/ BYTE magic; /* 0xdf */ -/*01*/ BYTE res01; /* 0x00 */ -/*02*/ DWORD res02; /* 0xffffffff */ -/*06*/ DWORD res06; /* 0xffffffff */ -/*0a*/ DWORD res0a; /* 0xffffffff */ -/*0e*/ DWORD res0e; /* 0xffffffff */ -/*12*/ DWORD res12; /* 0xffffffff */ -/*16*/ DWORD res16; /* 0xffffffff */ -/*1a*/ DWORD res1a; /* 0xffffffff */ -/*1e*/ DWORD res1e; /* 0xffffffff */ -/*22*/ DWORD res22; /* 0xffffffff */ -/*26*/ DWORD res26; /* 0xffffffff */ -/*2a*/ DWORD res2a; /* 0xffffffff */ -/*2e*/ DWORD res2e; /* 0xffffffff */ -/*32*/ DWORD res32; /* 0xffffffff */ -/*36*/ DWORD res36; /* 0xffffffff */ -/*3a*/ DWORD res3a; /* 0xffffffff */ -/*3e*/ DWORD res3e; /* 0xffffffff */ -/*42*/ WORD res42; /* 0xffff */ -/*44*/ DWORD number; /* this is 8 times the number of refs */ -/*48*/ /* Now we have number bytes (8 for each ref) of SLTG_UnknownRefInfo */ - -/*50*/ WORD res50; /* 0xffff */ -/*52*/ BYTE res52; /* 0x01 */ -/*53*/ DWORD res53; /* 0x00000000 */ -/*57*/ SLTG_Name names[1]; - /* Now we have number/8 SLTG_Names (first WORD is no of bytes in the ascii - * string). Strings look like "*\Rxxxx*#n". If xxxx == ffff then the - * ref refers to the nth type listed in this library (0 based). Else - * the xxxx (which maybe fewer than 4 digits) is the offset into the name - * table to a string "*\G{<guid>}#1.0#0#C:\WINNT\System32\stdole32.tlb#" - * The guid is the typelib guid; the ref again refers to the nth type of - * the imported typelib. - */ - -/*xx*/ BYTE resxx; /* 0xdf */ - -} SLTG_RefInfo; - -#define SLTG_REF_MAGIC 0xdf - -typedef struct { - WORD res00; /* 0x0001 */ - BYTE res02; /* 0x02 */ - BYTE res03; /* 0x40 if internal ref, 0x00 if external ? */ - WORD res04; /* 0xffff */ - WORD res06; /* 0x0000, 0x0013 or 0xffff ?? */ -} SLTG_UnknownRefInfo; - -typedef struct { - WORD res00; /* 0x004a */ - WORD next; /* byte offs to next interface */ - WORD res04; /* 0xffff */ - BYTE impltypeflags; /* IMPLTYPEFLAG_* */ - BYTE res07; /* 0x80 */ - WORD res08; /* 0x0012, 0x0028 ?? */ - WORD ref; /* number in ref table ? */ - WORD res0c; /* 0x4000 */ - WORD res0e; /* 0xfffe */ - WORD res10; /* 0xffff */ - WORD res12; /* 0x001d */ - WORD pos_in_table; /* 0x0, 0x4, ? */ -} SLTG_ImplInfo; - -#define SLTG_IMPL_MAGIC 0x004a - -typedef struct { - BYTE magic; /* 0x0a */ - BYTE typepos; - WORD next; - WORD name; - WORD byte_offs; /* pos in struct */ - WORD type; /* if typepos == 0x02 this is the type, else offset to type */ - DWORD memid; - WORD helpcontext; /* ?? */ - WORD helpstring; /* ?? */ -} SLTG_RecordItem; - -#define SLTG_RECORD_MAGIC 0x0a - - -/* CARRAYs look like this -WORD type == VT_CARRAY -WORD offset from start of block to SAFEARRAY -WORD typeofarray -*/ - -extern DWORD _invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args); -extern void dump_Variant(VARIANT * pvar); -#include "poppack.h" - -/*---------------------------END--------------------------------------------*/ -#endif +/* + * typelib.h internal wine data structures + * used to decode typelib's + * + * Copyright 1999 Rein KLazes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _WINE_TYPELIB_H +#define _WINE_TYPELIB_H + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "oleauto.h" +#include "wine/windef16.h" + +#define HELPDLLFLAG (0x0100) +#define DO_NOT_SEEK (-1) + +#define MSFT_HREFTYPE_INTHISFILE(href) (!((href) & 3)) +#define MSFT_HREFTYPE_INDEX(href) ((href) /sizeof(MSFT_TypeInfoBase)) + +/*-------------------------FILE STRUCTURES-----------------------------------*/ + +/* There are two known file formats, those created with ICreateTypeLib + * have the signature "SLTG" as their first four bytes, while those created + * with ICreateTypeLib2 have "MSFT". + */ + +/***************************************************** + * MSFT typelibs + * + * These are TypeLibs created with ICreateTypeLib2 + * + */ + +/* + * structure of the typelib type2 header + * it is at the beginning of a type lib file + * + */ +typedef struct tagMSFT_Header { +/*0x00*/INT magic1; /* 0x5446534D "MSFT" */ + INT magic2; /* 0x00010002 version nr? */ + INT posguid; /* position of libid in guid table */ + /* (should be, else -1) */ + INT lcid; /* locale id */ +/*0x10*/INT lcid2; + INT varflags; /* (largely) unknown flags ,seems to be always 41 */ + /* becomes 0x51 with a helpfile defined */ + /* if help dll defined it's 0x151 */ + /* update : the lower nibble is syskind */ + INT version; /* set with SetVersion() */ + INT flags; /* set with SetFlags() */ +/*0x20*/INT nrtypeinfos; /* number of typeinfo's (till so far) */ + INT helpstring; /* position of help string in stringtable */ + INT helpstringcontext; + INT helpcontext; +/*0x30*/INT nametablecount; /* number of names in name table */ + INT nametablechars; /* nr of characters in name table */ + INT NameOffset; /* offset of name in name table */ + INT helpfile; /* position of helpfile in stringtable */ +/*0x40*/INT CustomDataOffset; /* if -1 no custom data, else it is offset */ + /* in customer data/guid offset table */ + INT res44; /* unknown always: 0x20 (guid hash size?) */ + INT res48; /* unknown always: 0x80 (name hash size?) */ + INT dispatchpos; /* HREFTYPE to IDispatch, or -1 if no IDispatch */ +/*0x50*/INT res50; /* is zero becomes one when an interface is derived */ +} MSFT_Header; + +/* segments in the type lib file have a structure like this: */ +typedef struct tagMSFT_pSeg { + INT offset; /* absolute offset in file */ + INT length; /* length of segment */ + INT res08; /* unknown always -1 */ + INT res0c; /* unknown always 0x0f in the header */ + /* 0x03 in the typeinfo_data */ +} MSFT_pSeg; + +/* layout of the main segment directory */ +typedef struct tagMSFT_SegDir { +/*1*/MSFT_pSeg pTypeInfoTab; /* each type info get an entry of 0x64 bytes */ + /* (25 ints) */ +/*2*/MSFT_pSeg pImpInfo; /* table with info for imported types */ +/*3*/MSFT_pSeg pImpFiles; /* import libaries */ +/*4*/MSFT_pSeg pRefTab; /* References table */ +/*5*/MSFT_pSeg pLibtab; /* always exists, alway same size (0x80) */ + /* hash table w offsets to guid????? */ +/*6*/MSFT_pSeg pGuidTab; /* all guids are stored here together with */ + /* offset in some table???? */ +/*7*/MSFT_pSeg res07; /* always created, alway same size (0x200) */ + /* purpose largely unknown */ +/*8*/MSFT_pSeg pNametab; /* name tables */ +/*9*/MSFT_pSeg pStringtab; /* string table */ +/*A*/MSFT_pSeg pTypdescTab; /* table with type descriptors */ +/*B*/MSFT_pSeg pArrayDescriptions; +/*C*/MSFT_pSeg pCustData; /* data table, used for custom data and default */ + /* parameter values */ +/*D*/MSFT_pSeg pCDGuids; /* table with offsets for the guids and into */ + /* the customer data table */ +/*E*/MSFT_pSeg res0e; /* unknown */ +/*F*/MSFT_pSeg res0f; /* unknown */ +} MSFT_SegDir; + + +/* base type info data */ +typedef struct tagMSFT_TypeInfoBase { +/*000*/ INT typekind; /* it is the TKIND_xxx */ + /* some byte alignment stuf */ + INT memoffset; /* points past the file, if no elements */ + INT res2; /* zero if no element, N*0x40 */ + INT res3; /* -1 if no lement, (N-1)*0x38 */ +/*010*/ INT res4; /* always? 3 */ + INT res5; /* always? zero */ + INT cElement; /* counts elements, HI=cVars, LO=cFuncs */ + INT res7; /* always? zero */ +/*020*/ INT res8; /* always? zero */ + INT res9; /* always? zero */ + INT resA; /* always? zero */ + INT posguid; /* position in guid table */ +/*030*/ INT flags; /* Typeflags */ + INT NameOffset; /* offset in name table */ + INT version; /* element version */ + INT docstringoffs; /* offset of docstring in string tab */ +/*040*/ INT helpstringcontext; /* */ + INT helpcontext; /* */ + INT oCustData; /* offset in customer data table */ +#ifdef WORDS_BIGENDIAN + INT16 cbSizeVft; /* virtual table size, not including inherits */ + INT16 cImplTypes; /* nr of implemented interfaces */ +#else + INT16 cImplTypes; /* nr of implemented interfaces */ + INT16 cbSizeVft; /* virtual table size, not including inherits */ +#endif +/*050*/ INT size; /* size in bytes, at least for structures */ + /* FIXME: name of this field */ + INT datatype1; /* position in type description table */ + /* or in base intefaces */ + /* if coclass: offset in reftable */ + /* if interface: reference to inherited if */ + INT datatype2; /* if 0x8000, entry above is valid */ + /* actually dunno */ + /* else it is zero? */ + INT res18; /* always? 0 */ +/*060*/ INT res19; /* always? -1 */ + } MSFT_TypeInfoBase; + +/* layout of an entry with information on imported types */ +typedef struct tagMSFT_ImpInfo { + INT res0; /* unknown */ + INT oImpFile; /* offset inthe Import File table */ + INT oGuid; /* offset in Guid table */ + } MSFT_ImpInfo; + +/* function description data */ +typedef struct { +/* INT recsize; record size including some xtra stuff */ + INT DataType; /* data type of the member, eg return of function */ + INT Flags; /* something to do with attribute flags (LOWORD) */ +#ifdef WORDS_BIGENDIAN + INT16 funcdescsize; /* size of reconstituted FUNCDESC and related structs */ + INT16 VtableOffset; /* offset in vtable */ +#else + INT16 VtableOffset; /* offset in vtable */ + INT16 funcdescsize; /* size of reconstituted FUNCDESC and related structs */ +#endif + INT FKCCIC; /* bit string with the following */ + /* meaning (bit 0 is the msb): */ + /* bit 2 indicates that oEntry is numeric */ + /* bit 3 that parameter has default values */ + /* calling convention (bits 4-7 ) */ + /* bit 8 indicates that custom data is present */ + /* Invocation kind (bits 9-12 ) */ + /* function kind (eg virtual), bits 13-15 */ +#ifdef WORDS_BIGENDIAN + INT16 nroargs; /* nr of optional arguments */ + INT16 nrargs; /* number of arguments (including optional ????) */ +#else + INT16 nrargs; /* number of arguments (including optional ????) */ + INT16 nroargs; /* nr of optional arguments */ +#endif + /* optional attribute fields, the number of them is variable */ + INT OptAttr[1]; +/* +0* INT helpcontext; +1* INT oHelpString; +2* INT oEntry; // either offset in string table or numeric as it is // +3* INT res9; // unknown (-1) // +4* INT resA; // unknown (-1) // +5* INT HelpStringContext; + // these are controlled by a bit set in the FKCCIC field // +6* INT oCustData; // custom data for function // +7* INT oArgCustData[1]; // custom data per argument // +*/ +} MSFT_FuncRecord; + +/* after this may follow an array with default value pointers if the + * appropriate bit in the FKCCIC field has been set: + * INT oDefautlValue[nrargs]; + */ + + /* Parameter info one per argument*/ +typedef struct { + INT DataType; + INT oName; + INT Flags; + } MSFT_ParameterInfo; + +/* Variable description data */ +typedef struct { +/* INT recsize; // record size including some xtra stuff */ + INT DataType; /* data type of the variable */ + INT Flags; /* VarFlags (LOWORD) */ +#ifdef WORDS_BIGENDIAN + INT16 vardescsize; /* size of reconstituted VARDESC and related structs */ + INT16 VarKind; /* VarKind */ +#else + INT16 VarKind; /* VarKind */ + INT16 vardescsize; /* size of reconstituted VARDESC and related structs */ +#endif + INT OffsValue; /* value of the variable or the offset */ + /* in the data structure */ + /* optional attribute fields, the number of them is variable */ + /* controlled by record length */ + INT HelpContext; + INT oHelpString; + INT res9; /* unknown (-1) */ + INT oCustData; /* custom data for variable */ + INT HelpStringContext; + +} MSFT_VarRecord; + +/* Structure of the reference data */ +typedef struct { + INT reftype; /* either offset in type info table, then it's */ + /* a multiple of 64 */ + /* or offset in the external reference table */ + /* with an offset of 1 */ + INT flags; + INT oCustData; /* custom data */ + INT onext; /* next offset, -1 if last */ +} MSFT_RefRecord; + +/* this is how a guid is stored */ +typedef struct { + GUID guid; + INT hreftype; /* -2 for the typelib guid, typeinfo offset + for typeinfo guid, low two bits are 01 if + this is an imported typeinfo, low two bits + are 10 if this is an imported typelib (used + by imported typeinfos) */ + INT next_hash; /* offset to next guid in the hash bucket */ +} MSFT_GuidEntry; +/* some data preceding entries in the name table */ +typedef struct { + INT hreftype; /* is -1 if name is for neither a typeinfo, + a variable, or a function (that is, name + is for a typelib or a function parameter). + otherwise is the offset of the first + typeinfo that this name refers to (either + to the typeinfo itself or to a member of + the typeinfo */ + INT next_hash; /* offset to next name in the hash bucket */ + INT namelen; /* only lower 8 bits are valid, + lower-middle 8 bits are unknown (flags?), + upper 16 bits are hash code */ +} MSFT_NameIntro; +/* the custom data table directory has enties like this */ +typedef struct { + INT GuidOffset; + INT DataOffset; + INT next; /* next offset in the table, -1 if it's the last */ +} MSFT_CDGuid; + + +/*********************************************************** + * + * SLTG typelibs. + * + * These are created with ICreateTypeLib + * + */ + +#include "pshpack1.h" + +typedef struct { +/*00*/ DWORD SLTG_magic; /* 0x47544c53 == "SLTG" */ +/*04*/ WORD nrOfFileBlks; /* no of SLTG_BlkEntry's + 1 */ +/*06*/ WORD res06; /* ?? always 9 */ +/*08*/ WORD res08; /* some kind of len/offset ?? */ +/*0a*/ WORD first_blk; /* 1 based index into blk entries that + corresponds to first block in file */ +/*0c*/ DWORD res0c; /* always 0x000204ff */ +/*10*/ DWORD res10; /* always 0x00000000 */ +/*14*/ DWORD res14; /* always 0x000000c0 */ +/*18*/ DWORD res18; /* always 0x46000000 */ +/*1c*/ DWORD res1c; /* always 0x00000044 */ +/*20*/ DWORD res20; /* always 0xffff0000 */ +} SLTG_Header; + +/* This gets followed by a list of block entries */ +typedef struct { +/*00*/ DWORD len; +/*04*/ WORD index_string; /* offs from start of SLTG_Magic to index string */ +/*06*/ WORD next; +} SLTG_BlkEntry; + +/* The order of the blocks in the file is given by starting at Block + entry firt_blk and stepping through using the next pointer */ + +/* These then get followed by this magic */ +typedef struct { +/*00*/ BYTE res00; /* always 0x01 */ +/*01*/ CHAR CompObj_magic[8]; /* always "CompObj" */ +/*09*/ CHAR dir_magic[4]; /* always "dir" */ +} SLTG_Magic; + +#define SLTG_COMPOBJ_MAGIC "CompObj" +#define SLTG_DIR_MAGIC "dir" + +/* Next we have SLTG_Header.nrOfFileBlks - 2 of Index strings. These +are presumably unique to within the file and look something like +"AAAAAAAAAA" with the first character incremented from 'A' to ensure +uniqueness. I guess successive chars increment when we need to wrap +the first one. */ + +typedef struct { +/*00*/ CHAR string[11]; +} SLTG_Index; + + +/* This is followed by SLTG_pad9 */ +typedef struct { +/*00*/ CHAR pad[9]; /* 9 '\0's */ +} SLTG_Pad9; + + +/* Now we have the noOfFileBlks - 1 worth of blocks. The length of +each block is given by its entry in SLTG_BlkEntry. */ + +/* type SLTG_NAME in rather like a BSTR except that the length in +bytes is given by the first WORD and the string contains 8bit chars */ + +typedef WORD SLTG_Name; + +/* The main library block looks like this. This one seems to come last */ + +typedef struct { +/*00*/ WORD magic; /* 0x51cc */ +/*02*/ WORD res02; /* 0x0003, 0x0004 */ +/*04*/ WORD name; /* offset to name in name table */ +/*06*/ SLTG_Name res06; /* maybe this is just WORD == 0xffff */ + SLTG_Name helpstring; + SLTG_Name helpfile; + DWORD helpcontext; + WORD syskind; /* == 1 for win32, 0 for win16 */ + WORD lcid; /* == 0x409, 0x809 etc */ + DWORD res12; /* == 0 */ + WORD libflags; /* LIBFLAG_* */ + WORD maj_vers; + WORD min_vers; + GUID uuid; +} SLTG_LibBlk; + +#define SLTG_LIBBLK_MAGIC 0x51cc + +/* we then get 0x40 bytes worth of 0xffff or small numbers followed by + nrOfFileBlks - 2 of these */ +typedef struct { + WORD small_no; + SLTG_Name index_name; /* This refers to a name in the directory */ + SLTG_Name other_name; /* Another one of these weird names */ + WORD res1a; /* 0xffff */ + WORD name_offs; /* offset to name in name table */ + WORD more_bytes; /* if this is non-zero we get this many + bytes before the next element, which seem + to reference the docstring of the type ? */ + WORD res20; /* 0xffff */ + DWORD helpcontext; + WORD res26; /* 0xffff */ + GUID uuid; +} SLTG_OtherTypeInfo; + +/* Next we get WORD 0x0003 followed by a DWORD which if we add to +0x216 gives the offset to the name table from the start of the LibBlk +struct */ + +typedef struct { +/*00*/ WORD magic; /* 0x0501 */ +/*02*/ DWORD href_table; /* if not 0xffffffff, then byte offset from + beginning of struct to href table */ +/*06*/ DWORD res06; /* 0xffffffff */ +/*0a*/ DWORD elem_table; /* offset to members */ +/*0e*/ DWORD res0e; /* 0xffffffff */ +/*12*/ WORD major_version; /* major version number */ +/*14*/ WORD minor_version; /* minor version number */ +/*16*/ DWORD res16; /* 0xfffe0000 */ +/*1a*/ BYTE typeflags1;/* 0x02 | top 5 bits hold l5sbs of TYPEFLAGS */ +/*1b*/ BYTE typeflags2;/* TYPEFLAGS >> 5 */ +/*1c*/ BYTE typeflags3;/* 0x02*/ +/*1d*/ BYTE typekind; /* 0x03 == TKIND_INTERFACE etc. */ +/*1e*/ DWORD res1e; /* 0x00000000 or 0xffffffff */ +} SLTG_TypeInfoHeader; + +#define SLTG_TIHEADER_MAGIC 0x0501 + +typedef struct { +/*00*/ WORD cFuncs; +/*02*/ WORD cVars; +/*04*/ WORD cImplTypes; +/*06*/ WORD res06; +/*08*/ WORD res08; +/*0a*/ WORD res0a; +/*0c*/ WORD res0c; +/*0e*/ WORD res0e; +/*10*/ WORD res10; +/*12*/ WORD res12; +/*14*/ WORD tdescalias_vt; /* for TKIND_ALIAS */ +/*16*/ WORD res16; +/*18*/ WORD res18; +/*1a*/ WORD res1a; +/*1c*/ WORD res1c; +/*1e*/ WORD res1e; +/*20*/ WORD cbSizeInstance; +/*22*/ WORD cbAlignment; +/*24*/ WORD res24; +/*26*/ WORD res26; +/*28*/ WORD cbSizeVft; +/*2a*/ WORD res2a; +/*2c*/ WORD res2c; +/*2e*/ WORD res2e; +/*30*/ WORD res30; +/*32*/ WORD res32; +/*34*/ WORD res34; +} SLTG_TypeInfoTail; + +typedef struct { +/*00*/ WORD res00; /* 0x0001 sometimes 0x0003 ?? */ +/*02*/ WORD res02; /* 0xffff */ +/*04*/ BYTE res04; /* 0x01 */ +/*05*/ DWORD cbExtra; /* No of bytes that follow */ +} SLTG_MemberHeader; + +typedef struct { +/*00*/ WORD magic; /* 0x120a */ +/*02*/ WORD next; /* offset in bytes to next block from start of block + group, 0xffff if last item */ +/*04*/ WORD name; /* offset to name within name table */ +/*06*/ WORD value; /* offset to value from start of block group */ +/*08*/ WORD res08; /* 0x56 */ +/*0a*/ DWORD memid; /* memid */ +/*0e*/ WORD helpcontext;/* 0xfffe == no context, 0x0001 == stored in EnumInfo struct, else offset + to value from start of block group */ +/*10*/ WORD helpstring;/* offset from start of block group to string offset */ +} SLTG_EnumItem; + +#define SLTG_ENUMITEM_MAGIC 0x120a + +typedef struct { +/*00*/ WORD vt; /* vartype, 0xffff marks end. */ +/*02*/ WORD res02; /* ?, 0xffff marks end */ +} SLTG_AliasItem; + +#define SLTG_ALIASITEM_MAGIC 0x001d + + +typedef struct { + BYTE magic; /* 0x4c or 0x6c */ + BYTE inv; /* high nibble is INVOKE_KIND, low nibble = 2 */ + WORD next; /* byte offset from beginning of group to next fn */ + WORD name; /* Offset within name table to name */ + DWORD dispid; /* dispid */ + WORD helpcontext; /* helpcontext (again 1 is special) */ + WORD helpstring;/* helpstring offset to offset */ + WORD arg_off; /* offset to args from start of block */ + BYTE nacc; /* lowest 3bits are CALLCONV, rest are no of args */ + BYTE retnextopt;/* if 0x80 bit set ret type follows else next WORD + is offset to ret type. No of optional args is + middle 6 bits */ + WORD rettype; /* return type VT_?? or offset to ret type */ + WORD vtblpos; /* position in vtbl? */ + WORD funcflags; /* present if magic == 0x6c */ +/* Param list starts, repeat next two as required */ +#if 0 + WORD name; /* offset to 2nd letter of name */ + WORD+ type; /* VT_ of param */ +#endif +} SLTG_Function; + +#define SLTG_FUNCTION_MAGIC 0x4c +#define SLTG_FUNCTION_WITH_FLAGS_MAGIC 0x6c + +typedef struct { +/*00*/ BYTE magic; /* 0xdf */ +/*01*/ BYTE res01; /* 0x00 */ +/*02*/ DWORD res02; /* 0xffffffff */ +/*06*/ DWORD res06; /* 0xffffffff */ +/*0a*/ DWORD res0a; /* 0xffffffff */ +/*0e*/ DWORD res0e; /* 0xffffffff */ +/*12*/ DWORD res12; /* 0xffffffff */ +/*16*/ DWORD res16; /* 0xffffffff */ +/*1a*/ DWORD res1a; /* 0xffffffff */ +/*1e*/ DWORD res1e; /* 0xffffffff */ +/*22*/ DWORD res22; /* 0xffffffff */ +/*26*/ DWORD res26; /* 0xffffffff */ +/*2a*/ DWORD res2a; /* 0xffffffff */ +/*2e*/ DWORD res2e; /* 0xffffffff */ +/*32*/ DWORD res32; /* 0xffffffff */ +/*36*/ DWORD res36; /* 0xffffffff */ +/*3a*/ DWORD res3a; /* 0xffffffff */ +/*3e*/ DWORD res3e; /* 0xffffffff */ +/*42*/ WORD res42; /* 0xffff */ +/*44*/ DWORD number; /* this is 8 times the number of refs */ +/*48*/ /* Now we have number bytes (8 for each ref) of SLTG_UnknownRefInfo */ + +/*50*/ WORD res50; /* 0xffff */ +/*52*/ BYTE res52; /* 0x01 */ +/*53*/ DWORD res53; /* 0x00000000 */ +/*57*/ SLTG_Name names[1]; + /* Now we have number/8 SLTG_Names (first WORD is no of bytes in the ascii + * string). Strings look like "*\Rxxxx*#n". If xxxx == ffff then the + * ref refers to the nth type listed in this library (0 based). Else + * the xxxx (which maybe fewer than 4 digits) is the offset into the name + * table to a string "*\G{<guid>}#1.0#0#C:\WINNT\System32\stdole32.tlb#" + * The guid is the typelib guid; the ref again refers to the nth type of + * the imported typelib. + */ + +/*xx*/ BYTE resxx; /* 0xdf */ + +} SLTG_RefInfo; + +#define SLTG_REF_MAGIC 0xdf + +typedef struct { + WORD res00; /* 0x0001 */ + BYTE res02; /* 0x02 */ + BYTE res03; /* 0x40 if internal ref, 0x00 if external ? */ + WORD res04; /* 0xffff */ + WORD res06; /* 0x0000, 0x0013 or 0xffff ?? */ +} SLTG_UnknownRefInfo; + +typedef struct { + WORD res00; /* 0x004a */ + WORD next; /* byte offs to next interface */ + WORD res04; /* 0xffff */ + BYTE impltypeflags; /* IMPLTYPEFLAG_* */ + BYTE res07; /* 0x80 */ + WORD res08; /* 0x0012, 0x0028 ?? */ + WORD ref; /* number in ref table ? */ + WORD res0c; /* 0x4000 */ + WORD res0e; /* 0xfffe */ + WORD res10; /* 0xffff */ + WORD res12; /* 0x001d */ + WORD pos_in_table; /* 0x0, 0x4, ? */ +} SLTG_ImplInfo; + +#define SLTG_IMPL_MAGIC 0x004a + +typedef struct { + BYTE magic; /* 0x0a */ + BYTE typepos; + WORD next; + WORD name; + WORD byte_offs; /* pos in struct */ + WORD type; /* if typepos == 0x02 this is the type, else offset to type */ + DWORD memid; + WORD helpcontext; /* ?? */ + WORD helpstring; /* ?? */ +} SLTG_RecordItem; + +#define SLTG_RECORD_MAGIC 0x0a + + +/* CARRAYs look like this +WORD type == VT_CARRAY +WORD offset from start of block to SAFEARRAY +WORD typeofarray +*/ + +extern DWORD _invoke(FARPROC func,CALLCONV callconv, int nrargs, DWORD *args); +extern void dump_Variant(VARIANT * pvar); +#include "poppack.h" + +/*---------------------------END--------------------------------------------*/ +#endif diff --git a/reactos/lib/oleaut32/typelib16.c b/reactos/lib/oleaut32/typelib16.c index b48debd1d94..01abb2d9dd8 100644 --- a/reactos/lib/oleaut32/typelib16.c +++ b/reactos/lib/oleaut32/typelib16.c @@ -1,179 +1,179 @@ -/* - * TYPELIB 16bit part. - * - * Copyright 1997 Marcus Meissner - * Copyright 1999 Rein Klazes - * Copyright 2000 Francois Jacques - * Copyright 2001 Huw D M Davies for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" -#include "wine/port.h" - -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <stdio.h> -#include <ctype.h> - -#include "winerror.h" -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "winreg.h" -#include "winuser.h" - -#include "objbase.h" -#include "ole2disp.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/************************************************************************* - * TYPELIB {TYPELIB} - * - * This dll is the 16 bit version of the Typelib API, part the original - * implementation of Ole automation. It and its companion ole2disp.dll were - * superseded by oleaut32.dll which provides 32 bit implementations of these - * functions and greatly extends the Ole Api. - * - * Winelib developers cannot use these functions directly, they are implemented - * solely for backwards compatibility with existing legacy applications. - * - * SEE ALSO - * oleaut32(), ole2disp(). - */ - -/**************************************************************************** - * QueryPathOfRegTypeLib [TYPELIB.14] - * - * Get the registry key of a registered type library. - * - * RETURNS - * Success: S_OK. path is updated with the key name - * Failure: E_FAIL, if guid was not found in the registry - * - * NOTES - * The key takes the form "Classes\Typelib\<guid>\<major>.<minor>\<lcid>\win16\" - */ -HRESULT WINAPI -QueryPathOfRegTypeLib16( - REFGUID guid, /* [in] Guid to get the key name for */ - WORD wMaj, /* [in] Major version */ - WORD wMin, /* [in] Minor version */ - LCID lcid, /* [in] Locale Id */ - LPBSTR16 path) /* [out] Destination for the registry key name */ -{ - char xguid[80]; - char typelibkey[100],pathname[260]; - DWORD plen; - - TRACE("\n"); - - if (HIWORD(guid)) { - sprintf( typelibkey, "SOFTWARE\\Classes\\Typelib\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\%d.%d\\%lx\\win16", - guid->Data1, guid->Data2, guid->Data3, - guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], - guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7], - wMaj,wMin,lcid); - } else { - sprintf(xguid,"<guid 0x%08lx>",(DWORD)guid); - FIXME("(%s,%d,%d,0x%04lx,%p),can't handle non-string guids.\n",xguid,wMaj,wMin,(DWORD)lcid,path); - return E_FAIL; - } - plen = sizeof(pathname); - if (RegQueryValueA(HKEY_LOCAL_MACHINE,typelibkey,pathname,&plen)) { - /* try again without lang specific id */ - if (SUBLANGID(lcid)) - return QueryPathOfRegTypeLib16(guid,wMaj,wMin,PRIMARYLANGID(lcid),path); - FIXME("key %s not found\n",typelibkey); - return E_FAIL; - } - *path = SysAllocString16(pathname); - return S_OK; -} - -/****************************************************************************** - * LoadTypeLib [TYPELIB.3] - * - * Load and register a type library. - * - * RETURNS - * Success: S_OK. pptLib contains the type libraries ITypeLib interface. - * Failure: An HRESULT error code. - * - * NOTES - * Both parameters are FAR pointers. - */ -HRESULT WINAPI LoadTypeLib16( - LPOLESTR szFile, /* [in] Name of file to load from */ - ITypeLib** pptLib) /* [out] Destination for loaded ITypeLib interface */ -{ - FIXME("(%s,%p): stub\n",debugstr_w((LPWSTR)szFile),pptLib); - - if (pptLib!=0) - *pptLib=0; - - return E_FAIL; -} - -/**************************************************************************** - * OaBuildVersion (TYPELIB.15) - * - * Get the Ole Automation build version. - * - * PARAMS - * None - * - * RETURNS - * The build version. - * - * NOTES - * Known typelib.dll versions: - *| OLE Ver. Comments Date Build Ver. - *| -------- ------------------------- ---- --------- - *| OLE 2.01 Call not available 1993 N/A - *| OLE 2.02 1993-94 02 3002 - *| OLE 2.03 23 730 - *| OLE 2.03 03 3025 - *| OLE 2.03 W98 SE orig. file !! 1993-95 10 3024 - *| OLE 2.1 NT 1993-95 ?? ??? - *| OLE 2.3.1 W95 23 700 - *| OLE2 4.0 NT4SP6 1993-98 40 4277 - */ -DWORD WINAPI OaBuildVersion16(void) -{ - /* FIXME: I'd like to return the highest currently known version value - * in case the user didn't force a --winver, but I don't know how - * to retrieve the "versionForced" info from misc/version.c :( - * (this would be useful in other places, too) */ - FIXME("If you get version error messages, please report them\n"); - switch(GetVersion() & 0x8000ffff) /* mask off build number */ - { - case 0x80000a03: /* WIN31 */ - return MAKELONG(3027, 3); /* WfW 3.11 */ - case 0x80000004: /* WIN95 */ - return MAKELONG(700, 23); /* Win95A */ - case 0x80000a04: /* WIN98 */ - return MAKELONG(3024, 10); /* W98 SE */ - case 0x00000004: /* NT4 */ - return MAKELONG(4277, 40); /* NT4 SP6 */ - default: - FIXME("Version value not known yet. Please investigate it!\n"); - return 0; - } -} +/* + * TYPELIB 16bit part. + * + * Copyright 1997 Marcus Meissner + * Copyright 1999 Rein Klazes + * Copyright 2000 Francois Jacques + * Copyright 2001 Huw D M Davies for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "wine/port.h" + +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <stdio.h> +#include <ctype.h> + +#include "winerror.h" +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winreg.h" +#include "winuser.h" + +#include "objbase.h" +#include "ole2disp.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/************************************************************************* + * TYPELIB {TYPELIB} + * + * This dll is the 16 bit version of the Typelib API, part the original + * implementation of Ole automation. It and its companion ole2disp.dll were + * superseded by oleaut32.dll which provides 32 bit implementations of these + * functions and greatly extends the Ole Api. + * + * Winelib developers cannot use these functions directly, they are implemented + * solely for backwards compatibility with existing legacy applications. + * + * SEE ALSO + * oleaut32(), ole2disp(). + */ + +/**************************************************************************** + * QueryPathOfRegTypeLib [TYPELIB.14] + * + * Get the registry key of a registered type library. + * + * RETURNS + * Success: S_OK. path is updated with the key name + * Failure: E_FAIL, if guid was not found in the registry + * + * NOTES + * The key takes the form "Classes\Typelib\<guid>\<major>.<minor>\<lcid>\win16\" + */ +HRESULT WINAPI +QueryPathOfRegTypeLib16( + REFGUID guid, /* [in] Guid to get the key name for */ + WORD wMaj, /* [in] Major version */ + WORD wMin, /* [in] Minor version */ + LCID lcid, /* [in] Locale Id */ + LPBSTR16 path) /* [out] Destination for the registry key name */ +{ + char xguid[80]; + char typelibkey[100],pathname[260]; + DWORD plen; + + TRACE("\n"); + + if (HIWORD(guid)) { + sprintf( typelibkey, "SOFTWARE\\Classes\\Typelib\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\%d.%d\\%lx\\win16", + guid->Data1, guid->Data2, guid->Data3, + guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], + guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7], + wMaj,wMin,lcid); + } else { + sprintf(xguid,"<guid 0x%08lx>",(DWORD)guid); + FIXME("(%s,%d,%d,0x%04lx,%p),can't handle non-string guids.\n",xguid,wMaj,wMin,(DWORD)lcid,path); + return E_FAIL; + } + plen = sizeof(pathname); + if (RegQueryValueA(HKEY_LOCAL_MACHINE,typelibkey,pathname,&plen)) { + /* try again without lang specific id */ + if (SUBLANGID(lcid)) + return QueryPathOfRegTypeLib16(guid,wMaj,wMin,PRIMARYLANGID(lcid),path); + FIXME("key %s not found\n",typelibkey); + return E_FAIL; + } + *path = SysAllocString16(pathname); + return S_OK; +} + +/****************************************************************************** + * LoadTypeLib [TYPELIB.3] + * + * Load and register a type library. + * + * RETURNS + * Success: S_OK. pptLib contains the type libraries ITypeLib interface. + * Failure: An HRESULT error code. + * + * NOTES + * Both parameters are FAR pointers. + */ +HRESULT WINAPI LoadTypeLib16( + LPOLESTR szFile, /* [in] Name of file to load from */ + ITypeLib** pptLib) /* [out] Destination for loaded ITypeLib interface */ +{ + FIXME("(%s,%p): stub\n",debugstr_w((LPWSTR)szFile),pptLib); + + if (pptLib!=0) + *pptLib=0; + + return E_FAIL; +} + +/**************************************************************************** + * OaBuildVersion (TYPELIB.15) + * + * Get the Ole Automation build version. + * + * PARAMS + * None + * + * RETURNS + * The build version. + * + * NOTES + * Known typelib.dll versions: + *| OLE Ver. Comments Date Build Ver. + *| -------- ------------------------- ---- --------- + *| OLE 2.01 Call not available 1993 N/A + *| OLE 2.02 1993-94 02 3002 + *| OLE 2.03 23 730 + *| OLE 2.03 03 3025 + *| OLE 2.03 W98 SE orig. file !! 1993-95 10 3024 + *| OLE 2.1 NT 1993-95 ?? ??? + *| OLE 2.3.1 W95 23 700 + *| OLE2 4.0 NT4SP6 1993-98 40 4277 + */ +DWORD WINAPI OaBuildVersion16(void) +{ + /* FIXME: I'd like to return the highest currently known version value + * in case the user didn't force a --winver, but I don't know how + * to retrieve the "versionForced" info from misc/version.c :( + * (this would be useful in other places, too) */ + FIXME("If you get version error messages, please report them\n"); + switch(GetVersion() & 0x8000ffff) /* mask off build number */ + { + case 0x80000a03: /* WIN31 */ + return MAKELONG(3027, 3); /* WfW 3.11 */ + case 0x80000004: /* WIN95 */ + return MAKELONG(700, 23); /* Win95A */ + case 0x80000a04: /* WIN98 */ + return MAKELONG(3024, 10); /* W98 SE */ + case 0x00000004: /* NT4 */ + return MAKELONG(4277, 40); /* NT4 SP6 */ + default: + FIXME("Version value not known yet. Please investigate it!\n"); + return 0; + } +} diff --git a/reactos/lib/oleaut32/typelib2.c b/reactos/lib/oleaut32/typelib2.c index aba0b6a82ea..cf34267d7f3 100644 --- a/reactos/lib/oleaut32/typelib2.c +++ b/reactos/lib/oleaut32/typelib2.c @@ -1,3913 +1,3913 @@ -/* - * TYPELIB2 - * - * Copyright 2004 Alastair Bridgewater - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * -------------------------------------------------------------------------------------- - * Known problems: - * - * Badly incomplete. - * - * Only works on little-endian systems. - * - */ - -#include "config.h" -#include "wine/port.h" - -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <stdio.h> -#include <ctype.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "winerror.h" -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "winreg.h" -#include "winuser.h" - -#include "wine/unicode.h" -#include "objbase.h" -#include "typelib.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(typelib2); -/* WINE_DEFAULT_DEBUG_CHANNEL(ole); */ - - -/****************************************************************************** - * ICreateTypeLib2 {OLEAUT32} - * - * NOTES - * The ICreateTypeLib2 interface provides an interface whereby one may create - * new type library (.tlb) files. - * - * This interface inherits from ICreateTypeLib, and can be freely cast back - * and forth between an ICreateTypeLib and an ICreateTypeLib2 on local clients. - * This dispensation applies only to ICreateTypeLib objects obtained on MSFT - * format type libraries (those made through CreateTypeLib2). - * - * METHODS - */ - -/****************************************************************************** - * ICreateTypeInfo2 {OLEAUT32} - * - * NOTES - * The ICreateTypeInfo2 interface provides an interface whereby one may add - * type information to type library (.tlb) files. - * - * This interface inherits from ICreateTypeInfo, and can be freely cast back - * and forth between an ICreateTypeInfo and an ICreateTypeInfo2 on local clients. - * This dispensation applies only to ICreateTypeInfo objects obtained on MSFT - * format type libraries (those made through CreateTypeLib2). - * - * METHODS - */ - -/****************************************************************************** - * ITypeLib2 {OLEAUT32} - * - * NOTES - * The ITypeLib2 interface provides an interface whereby one may query MSFT - * format type library (.tlb) files. - * - * This interface inherits from ITypeLib, and can be freely cast back and - * forth between an ITypeLib and an ITypeLib2 on local clients. This - * dispensation applies only to ITypeLib objects obtained on MSFT format type - * libraries (those made through CreateTypeLib2). - * - * METHODS - */ - -/****************************************************************************** - * ITypeInfo2 {OLEAUT32} - * - * NOTES - * The ITypeInfo2 interface provides an interface whereby one may query type - * information stored in MSFT format type library (.tlb) files. - * - * This interface inherits from ITypeInfo, and can be freely cast back and - * forth between an ITypeInfo and an ITypeInfo2 on local clients. This - * dispensation applies only to ITypeInfo objects obtained on MSFT format type - * libraries (those made through CreateTypeLib2). - * - * METHODS - */ - -/*================== Implementation Structures ===================================*/ - -enum MSFT_segment_index { - MSFT_SEG_TYPEINFO = 0, /* type information */ - MSFT_SEG_IMPORTINFO, /* import information */ - MSFT_SEG_IMPORTFILES, /* import filenames */ - MSFT_SEG_REFERENCES, /* references (?) */ - MSFT_SEG_GUIDHASH, /* hash table for guids? */ - MSFT_SEG_GUID, /* guid storage */ - MSFT_SEG_NAMEHASH, /* hash table for names */ - MSFT_SEG_NAME, /* name storage */ - MSFT_SEG_STRING, /* string storage */ - MSFT_SEG_TYPEDESC, /* type descriptions */ - MSFT_SEG_ARRAYDESC, /* array descriptions */ - MSFT_SEG_CUSTDATA, /* custom data */ - MSFT_SEG_CUSTDATAGUID, /* custom data guids */ - MSFT_SEG_UNKNOWN, /* ??? */ - MSFT_SEG_UNKNOWN2, /* ??? */ - MSFT_SEG_MAX /* total number of segments */ -}; - -typedef struct tagMSFT_ImpFile { - int guid; - LCID lcid; - int version; - char filename[0]; /* preceded by two bytes of encoded (length << 2) + flags in the low two bits. */ -} MSFT_ImpFile; - -typedef struct tagICreateTypeLib2Impl -{ - ICreateTypeLib2Vtbl *lpVtbl; - ITypeLib2Vtbl *lpVtblTypeLib2; - - ULONG ref; - - WCHAR *filename; - - MSFT_Header typelib_header; - MSFT_pSeg typelib_segdir[MSFT_SEG_MAX]; - char *typelib_segment_data[MSFT_SEG_MAX]; - int typelib_segment_block_length[MSFT_SEG_MAX]; - - INT typelib_typeinfo_offsets[0x200]; /* Hope that's enough. */ - - INT *typelib_namehash_segment; - INT *typelib_guidhash_segment; - - struct tagICreateTypeInfo2Impl *typeinfos; - struct tagICreateTypeInfo2Impl *last_typeinfo; -} ICreateTypeLib2Impl; - -#define _ITypeLib2_Offset(impl) ((int)(&(((impl*)0)->lpVtblTypeLib2))) -#define ICOM_THIS_From_ITypeLib2(impl, iface) impl* This = (impl*)(((char*)iface)-_ITypeLib2_Offset(impl)) - -typedef struct tagICreateTypeInfo2Impl -{ - ICreateTypeInfo2Vtbl *lpVtbl; - ITypeInfo2Vtbl *lpVtblTypeInfo2; - - ULONG ref; - - ICreateTypeLib2Impl *typelib; - MSFT_TypeInfoBase *typeinfo; - - INT *typedata; - int typedata_allocated; - int typedata_length; - - int indices[42]; - int names[42]; - int offsets[42]; - - int datawidth; - - struct tagICreateTypeInfo2Impl *next_typeinfo; -} ICreateTypeInfo2Impl; - -#define _ITypeInfo2_Offset(impl) ((int)(&(((impl*)0)->lpVtblTypeInfo2))) -#define ICOM_THIS_From_ITypeInfo2(impl, iface) impl* This = (impl*)(((char*)iface)-_ITypeInfo2_Offset(impl)) - -static ULONG WINAPI ICreateTypeLib2_fnRelease(ICreateTypeLib2 *iface); - - -/*================== Internal functions ===================================*/ - -/**************************************************************************** - * ctl2_init_header - * - * Initializes the type library header of a new typelib. - */ -static void ctl2_init_header( - ICreateTypeLib2Impl *This) /* [I] The typelib to initialize. */ -{ - This->typelib_header.magic1 = 0x5446534d; - This->typelib_header.magic2 = 0x00010002; - This->typelib_header.posguid = -1; - This->typelib_header.lcid = 0x0409; /* or do we use the current one? */ - This->typelib_header.lcid2 = 0x0409; - This->typelib_header.varflags = 0x40; - This->typelib_header.version = 0; - This->typelib_header.flags = 0; - This->typelib_header.nrtypeinfos = 0; - This->typelib_header.helpstring = -1; - This->typelib_header.helpstringcontext = 0; - This->typelib_header.helpcontext = 0; - This->typelib_header.nametablecount = 0; - This->typelib_header.nametablechars = 0; - This->typelib_header.NameOffset = -1; - This->typelib_header.helpfile = -1; - This->typelib_header.CustomDataOffset = -1; - This->typelib_header.res44 = 0x20; - This->typelib_header.res48 = 0x80; - This->typelib_header.dispatchpos = -1; - This->typelib_header.res50 = 0; -} - -/**************************************************************************** - * ctl2_init_segdir - * - * Initializes the segment directory of a new typelib. - */ -static void ctl2_init_segdir( - ICreateTypeLib2Impl *This) /* [I] The typelib to initialize. */ -{ - int i; - MSFT_pSeg *segdir; - - segdir = &This->typelib_segdir[MSFT_SEG_TYPEINFO]; - - for (i = 0; i < 15; i++) { - segdir[i].offset = -1; - segdir[i].length = 0; - segdir[i].res08 = -1; - segdir[i].res0c = 0x0f; - } -} - -/**************************************************************************** - * ctl2_hash_guid - * - * Generates a hash key from a GUID. - * - * RETURNS - * - * The hash key for the GUID. - */ -static int ctl2_hash_guid( - REFGUID guid) /* [I] The guid to find. */ -{ - int hash; - int i; - - hash = 0; - for (i = 0; i < 8; i ++) { - hash ^= ((const short *)guid)[i]; - } - - return (hash & 0xf) | ((hash & 0x10) & (0 - !!(hash & 0xe0))); -} - -/**************************************************************************** - * ctl2_find_guid - * - * Locates a guid in a type library. - * - * RETURNS - * - * The offset into the GUID segment of the guid, or -1 if not found. - */ -static int ctl2_find_guid( - ICreateTypeLib2Impl *This, /* [I] The typelib to operate against. */ - int hash_key, /* [I] The hash key for the guid. */ - REFGUID guid) /* [I] The guid to find. */ -{ - int offset; - MSFT_GuidEntry *guidentry; - - offset = This->typelib_guidhash_segment[hash_key]; - while (offset != -1) { - guidentry = (MSFT_GuidEntry *)&This->typelib_segment_data[MSFT_SEG_GUID][offset]; - - if (!memcmp(guidentry, guid, sizeof(GUID))) return offset; - - offset = guidentry->next_hash; - } - - return offset; -} - -/**************************************************************************** - * ctl2_find_name - * - * Locates a name in a type library. - * - * RETURNS - * - * The offset into the NAME segment of the name, or -1 if not found. - * - * NOTES - * - * The name must be encoded as with ctl2_encode_name(). - */ -static int ctl2_find_name( - ICreateTypeLib2Impl *This, /* [I] The typelib to operate against. */ - char *name) /* [I] The encoded name to find. */ -{ - int offset; - int *namestruct; - - offset = This->typelib_namehash_segment[name[2] & 0x7f]; - while (offset != -1) { - namestruct = (int *)&This->typelib_segment_data[MSFT_SEG_NAME][offset]; - - if (!((namestruct[2] ^ *((int *)name)) & 0xffff00ff)) { - /* hash codes and lengths match, final test */ - if (!strncasecmp(name+4, (void *)(namestruct+3), name[0])) break; - } - - /* move to next item in hash bucket */ - offset = namestruct[1]; - } - - return offset; -} - -/**************************************************************************** - * ctl2_encode_name - * - * Encodes a name string to a form suitable for storing into a type library - * or comparing to a name stored in a type library. - * - * RETURNS - * - * The length of the encoded name, including padding and length+hash fields. - * - * NOTES - * - * Will throw an exception if name or result are NULL. Is not multithread - * safe in the slightest. - */ -static int ctl2_encode_name( - ICreateTypeLib2Impl *This, /* [I] The typelib to operate against (used for LCID only). */ - const WCHAR *name, /* [I] The name string to encode. */ - char **result) /* [O] A pointer to a pointer to receive the encoded name. */ -{ - int length; - static char converted_name[0x104]; - int offset; - int value; - - length = WideCharToMultiByte(CP_ACP, 0, name, strlenW(name), converted_name+4, 0x100, NULL, NULL); - converted_name[0] = length & 0xff; - - converted_name[length + 4] = 0; - - converted_name[1] = 0x00; - - value = LHashValOfNameSysA(This->typelib_header.varflags & 0x0f, This->typelib_header.lcid, converted_name + 4); - - converted_name[2] = value; - converted_name[3] = value >> 8; - - for (offset = (4 - length) & 3; offset; offset--) converted_name[length + offset + 3] = 0x57; - - *result = converted_name; - - return (length + 7) & ~3; -} - -/**************************************************************************** - * ctl2_encode_string - * - * Encodes a string to a form suitable for storing into a type library or - * comparing to a string stored in a type library. - * - * RETURNS - * - * The length of the encoded string, including padding and length fields. - * - * NOTES - * - * Will throw an exception if string or result are NULL. Is not multithread - * safe in the slightest. - */ -static int ctl2_encode_string( - ICreateTypeLib2Impl *This, /* [I] The typelib to operate against (not used?). */ - const WCHAR *string, /* [I] The string to encode. */ - char **result) /* [O] A pointer to a pointer to receive the encoded string. */ -{ - int length; - static char converted_string[0x104]; - int offset; - - length = WideCharToMultiByte(CP_ACP, 0, string, strlenW(string), converted_string+2, 0x102, NULL, NULL); - converted_string[0] = length & 0xff; - converted_string[1] = (length >> 8) & 0xff; - - for (offset = (4 - (length + 2)) & 3; offset; offset--) converted_string[length + offset + 1] = 0x57; - - *result = converted_string; - - return (length + 5) & ~3; -} - -/**************************************************************************** - * ctl2_alloc_segment - * - * Allocates memory from a segment in a type library. - * - * RETURNS - * - * Success: The offset within the segment of the new data area. - * Failure: -1 (this is invariably an out of memory condition). - * - * BUGS - * - * Does not (yet) handle the case where the allocated segment memory needs to grow. - */ -static int ctl2_alloc_segment( - ICreateTypeLib2Impl *This, /* [I] The type library in which to allocate. */ - enum MSFT_segment_index segment, /* [I] The segment in which to allocate. */ - int size, /* [I] The amount to allocate. */ - int block_size) /* [I] Initial allocation block size, or 0 for default. */ -{ - int offset; - - if(!This->typelib_segment_data[segment]) { - if (!block_size) block_size = 0x2000; - - This->typelib_segment_block_length[segment] = block_size; - This->typelib_segment_data[segment] = HeapAlloc(GetProcessHeap(), 0, block_size); - if (!This->typelib_segment_data[segment]) return -1; - memset(This->typelib_segment_data[segment], 0x57, block_size); - } - - while ((This->typelib_segdir[segment].length + size) > This->typelib_segment_block_length[segment]) { - char *block; - - block_size = This->typelib_segment_block_length[segment]; - block = HeapReAlloc(GetProcessHeap(), 0, This->typelib_segment_data[segment], block_size << 1); - if (!block) return -1; - - if (segment == MSFT_SEG_TYPEINFO) { - /* TypeInfos have a direct pointer to their memory space, so we have to fix them up. */ - ICreateTypeInfo2Impl *typeinfo; - - for (typeinfo = This->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) { - typeinfo->typeinfo = (void *)&block[((char *)typeinfo->typeinfo) - This->typelib_segment_data[segment]]; - } - } - - memset(block + block_size, 0x57, block_size); - This->typelib_segment_block_length[segment] = block_size << 1; - This->typelib_segment_data[segment] = block; - } - - offset = This->typelib_segdir[segment].length; - This->typelib_segdir[segment].length += size; - - return offset; -} - -/**************************************************************************** - * ctl2_alloc_typeinfo - * - * Allocates and initializes a typeinfo structure in a type library. - * - * RETURNS - * - * Success: The offset of the new typeinfo. - * Failure: -1 (this is invariably an out of memory condition). - */ -static int ctl2_alloc_typeinfo( - ICreateTypeLib2Impl *This, /* [I] The type library to allocate in. */ - int nameoffset) /* [I] The offset of the name for this typeinfo. */ -{ - int offset; - MSFT_TypeInfoBase *typeinfo; - - offset = ctl2_alloc_segment(This, MSFT_SEG_TYPEINFO, sizeof(MSFT_TypeInfoBase), 0); - if (offset == -1) return -1; - - This->typelib_typeinfo_offsets[This->typelib_header.nrtypeinfos++] = offset; - - typeinfo = (void *)(This->typelib_segment_data[MSFT_SEG_TYPEINFO] + offset); - - typeinfo->typekind = (This->typelib_header.nrtypeinfos - 1) << 16; - typeinfo->memoffset = -1; /* should be EOF if no elements */ - typeinfo->res2 = 0; - typeinfo->res3 = -1; - typeinfo->res4 = 3; - typeinfo->res5 = 0; - typeinfo->cElement = 0; - typeinfo->res7 = 0; - typeinfo->res8 = 0; - typeinfo->res9 = 0; - typeinfo->resA = 0; - typeinfo->posguid = -1; - typeinfo->flags = 0; - typeinfo->NameOffset = nameoffset; - typeinfo->version = 0; - typeinfo->docstringoffs = -1; - typeinfo->helpstringcontext = 0; - typeinfo->helpcontext = 0; - typeinfo->oCustData = -1; - typeinfo->cbSizeVft = 0; - typeinfo->cImplTypes = 0; - typeinfo->size = 0; - typeinfo->datatype1 = -1; - typeinfo->datatype2 = 0; - typeinfo->res18 = 0; - typeinfo->res19 = -1; - - return offset; -} - -/**************************************************************************** - * ctl2_alloc_guid - * - * Allocates and initializes a GUID structure in a type library. Also updates - * the GUID hash table as needed. - * - * RETURNS - * - * Success: The offset of the new GUID. - * Failure: -1 (this is invariably an out of memory condition). - */ -static int ctl2_alloc_guid( - ICreateTypeLib2Impl *This, /* [I] The type library to allocate in. */ - MSFT_GuidEntry *guid) /* [I] The GUID to store. */ -{ - int offset; - MSFT_GuidEntry *guid_space; - int hash_key; - - hash_key = ctl2_hash_guid(&guid->guid); - - offset = ctl2_find_guid(This, hash_key, &guid->guid); - if (offset != -1) return offset; - - offset = ctl2_alloc_segment(This, MSFT_SEG_GUID, sizeof(MSFT_GuidEntry), 0); - if (offset == -1) return -1; - - guid_space = (void *)(This->typelib_segment_data[MSFT_SEG_GUID] + offset); - *guid_space = *guid; - - guid_space->next_hash = This->typelib_guidhash_segment[hash_key]; - This->typelib_guidhash_segment[hash_key] = offset; - - return offset; -} - -/**************************************************************************** - * ctl2_alloc_name - * - * Allocates and initializes a name within a type library. Also updates the - * name hash table as needed. - * - * RETURNS - * - * Success: The offset within the segment of the new name. - * Failure: -1 (this is invariably an out of memory condition). - */ -static int ctl2_alloc_name( - ICreateTypeLib2Impl *This, /* [I] The type library to allocate in. */ - const WCHAR *name) /* [I] The name to store. */ -{ - int length; - int offset; - MSFT_NameIntro *name_space; - char *encoded_name; - - length = ctl2_encode_name(This, name, &encoded_name); - - offset = ctl2_find_name(This, encoded_name); - if (offset != -1) return offset; - - offset = ctl2_alloc_segment(This, MSFT_SEG_NAME, length + 8, 0); - if (offset == -1) return -1; - - name_space = (void *)(This->typelib_segment_data[MSFT_SEG_NAME] + offset); - name_space->hreftype = -1; - name_space->next_hash = -1; - memcpy(&name_space->namelen, encoded_name, length); - - if (This->typelib_namehash_segment[encoded_name[2] & 0x7f] != -1) - name_space->next_hash = This->typelib_namehash_segment[encoded_name[2] & 0x7f]; - - This->typelib_namehash_segment[encoded_name[2] & 0x7f] = offset; - - This->typelib_header.nametablecount += 1; - This->typelib_header.nametablechars += *encoded_name; - - return offset; -} - -/**************************************************************************** - * ctl2_alloc_string - * - * Allocates and initializes a string in a type library. - * - * RETURNS - * - * Success: The offset within the segment of the new string. - * Failure: -1 (this is invariably an out of memory condition). - */ -static int ctl2_alloc_string( - ICreateTypeLib2Impl *This, /* [I] The type library to allocate in. */ - const WCHAR *string) /* [I] The string to store. */ -{ - int length; - int offset; - char *string_space; - char *encoded_string; - - length = ctl2_encode_string(This, string, &encoded_string); - - for (offset = 0; offset < This->typelib_segdir[MSFT_SEG_STRING].length; - offset += ((((This->typelib_segment_data[MSFT_SEG_STRING][offset + 1] << 8) & 0xff) - | (This->typelib_segment_data[MSFT_SEG_STRING][offset + 0] & 0xff)) + 5) & ~3) { - if (!memcmp(encoded_string, This->typelib_segment_data[MSFT_SEG_STRING] + offset, length)) return offset; - } - - offset = ctl2_alloc_segment(This, MSFT_SEG_STRING, length, 0); - if (offset == -1) return -1; - - string_space = This->typelib_segment_data[MSFT_SEG_STRING] + offset; - memcpy(string_space, encoded_string, length); - - return offset; -} - -/**************************************************************************** - * ctl2_alloc_importinfo - * - * Allocates and initializes an import information structure in a type library. - * - * RETURNS - * - * Success: The offset of the new importinfo. - * Failure: -1 (this is invariably an out of memory condition). - */ -static int ctl2_alloc_importinfo( - ICreateTypeLib2Impl *This, /* [I] The type library to allocate in. */ - MSFT_ImpInfo *impinfo) /* [I] The import information to store. */ -{ - int offset; - MSFT_ImpInfo *impinfo_space; - - for (offset = 0; - offset < This->typelib_segdir[MSFT_SEG_IMPORTINFO].length; - offset += sizeof(MSFT_ImpInfo)) { - if (!memcmp(&(This->typelib_segment_data[MSFT_SEG_IMPORTINFO][offset]), - impinfo, sizeof(MSFT_ImpInfo))) { - return offset; - } - } - - offset = ctl2_alloc_segment(This, MSFT_SEG_IMPORTINFO, sizeof(MSFT_ImpInfo), 0); - if (offset == -1) return -1; - - impinfo_space = (void *)(This->typelib_segment_data[MSFT_SEG_IMPORTINFO] + offset); - *impinfo_space = *impinfo; - - return offset; -} - -/**************************************************************************** - * ctl2_alloc_importfile - * - * Allocates and initializes an import file definition in a type library. - * - * RETURNS - * - * Success: The offset of the new importinfo. - * Failure: -1 (this is invariably an out of memory condition). - */ -static int ctl2_alloc_importfile( - ICreateTypeLib2Impl *This, /* [I] The type library to allocate in. */ - int guidoffset, /* [I] The offset to the GUID for the imported library. */ - int major_version, /* [I] The major version number of the imported library. */ - int minor_version, /* [I] The minor version number of the imported library. */ - const WCHAR *filename) /* [I] The filename of the imported library. */ -{ - int length; - int offset; - MSFT_ImpFile *importfile; - char *encoded_string; - - length = ctl2_encode_string(This, filename, &encoded_string); - - encoded_string[0] <<= 2; - encoded_string[0] |= 1; - - for (offset = 0; offset < This->typelib_segdir[MSFT_SEG_IMPORTFILES].length; - offset += ((((This->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset + 0xd] << 8) & 0xff) - | (This->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset + 0xc] & 0xff)) >> 2) + 0xc) { - if (!memcmp(encoded_string, This->typelib_segment_data[MSFT_SEG_IMPORTFILES] + offset + 0xc, length)) return offset; - } - - offset = ctl2_alloc_segment(This, MSFT_SEG_IMPORTFILES, length + 0xc, 0); - if (offset == -1) return -1; - - importfile = (MSFT_ImpFile *)&This->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset]; - importfile->guid = guidoffset; - importfile->lcid = This->typelib_header.lcid2; - importfile->version = major_version | (minor_version << 16); - memcpy(&importfile->filename, encoded_string, length); - - return offset; -} - -/**************************************************************************** - * ctl2_alloc_custdata - * - * Allocates and initializes a "custom data" value in a type library. - * - * RETURNS - * - * Success: The offset of the new custdata. - * Failure: - * - * -1: Out of memory. - * -2: Unable to encode VARIANT data (typically a bug). - */ -static int ctl2_alloc_custdata( - ICreateTypeLib2Impl *This, /* [I] The type library in which to encode the value. */ - VARIANT *pVarVal) /* [I] The value to encode. */ -{ - int offset; - - TRACE("(%p,%p(%d))\n",This,pVarVal,V_VT(pVarVal)); - - switch (V_VT(pVarVal)) { - case VT_UI4: - offset = ctl2_alloc_segment(This, MSFT_SEG_CUSTDATA, 8, 0); - if (offset == -1) return offset; - - *((unsigned short *)&This->typelib_segment_data[MSFT_SEG_CUSTDATA][offset]) = VT_UI4; - *((unsigned long *)&This->typelib_segment_data[MSFT_SEG_CUSTDATA][offset+2]) = V_UI4(pVarVal); - break; - - default: - FIXME("Unknown variable encoding vt %d.\n", V_VT(pVarVal)); - return -2; - } - - return offset; -} - -/**************************************************************************** - * ctl2_set_custdata - * - * Adds a custom data element to an object in a type library. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_INVALIDARG or E_OUTOFMEMORY. - */ -static HRESULT ctl2_set_custdata( - ICreateTypeLib2Impl *This, /* [I] The type library to store the custom data in. */ - REFGUID guid, /* [I] The GUID used as a key to retrieve the custom data. */ - VARIANT *pVarVal, /* [I] The custom data itself. */ - int *offset) /* [I/O] The list of custom data to prepend to. */ -{ - MSFT_GuidEntry guidentry; - int dataoffset; - int guidoffset; - int custoffset; - int *custdata; - - guidentry.guid = *guid; - - guidentry.hreftype = -1; - guidentry.next_hash = -1; - - guidoffset = ctl2_alloc_guid(This, &guidentry); - if (guidoffset == -1) return E_OUTOFMEMORY; - dataoffset = ctl2_alloc_custdata(This, pVarVal); - if (dataoffset == -1) return E_OUTOFMEMORY; - if (dataoffset == -2) return E_INVALIDARG; - - custoffset = ctl2_alloc_segment(This, MSFT_SEG_CUSTDATAGUID, 12, 0); - if (custoffset == -1) return E_OUTOFMEMORY; - - custdata = (int *)&This->typelib_segment_data[MSFT_SEG_CUSTDATAGUID][custoffset]; - custdata[0] = guidoffset; - custdata[1] = dataoffset; - custdata[2] = *offset; - *offset = custoffset; - - return S_OK; -} - -/**************************************************************************** - * ctl2_encode_typedesc - * - * Encodes a type description, storing information in the TYPEDESC and ARRAYDESC - * segments as needed. - * - * RETURNS - * - * Success: 0. - * Failure: -1. - */ -static int ctl2_encode_typedesc( - ICreateTypeLib2Impl *This, /* [I] The type library in which to encode the TYPEDESC. */ - TYPEDESC *tdesc, /* [I] The type description to encode. */ - int *encoded_tdesc, /* [O] The encoded type description. */ - int *width, /* [O] The width of the type, or NULL. */ - int *alignment, /* [O] The alignment of the type, or NULL. */ - int *decoded_size) /* [O] The total size of the unencoded TYPEDESCs, including nested descs. */ -{ - int default_tdesc; - int scratch; - int typeoffset; - int arrayoffset; - int *typedata; - int *arraydata; - int target_type; - int child_size; - - default_tdesc = 0x80000000 | (tdesc->vt << 16) | tdesc->vt; - if (!width) width = &scratch; - if (!alignment) alignment = &scratch; - if (!decoded_size) decoded_size = &scratch; - - *decoded_size = 0; - - switch (tdesc->vt) { - case VT_UI1: - case VT_I1: - *encoded_tdesc = default_tdesc; - *width = 1; - *alignment = 1; - break; - - case VT_INT: - *encoded_tdesc = 0x80000000 | (VT_I4 << 16) | VT_INT; - if ((This->typelib_header.varflags & 0x0f) == SYS_WIN16) { - *width = 2; - *alignment = 2; - } else { - *width = 4; - *alignment = 4; - } - break; - - case VT_UINT: - *encoded_tdesc = 0x80000000 | (VT_UI4 << 16) | VT_UINT; - if ((This->typelib_header.varflags & 0x0f) == SYS_WIN16) { - *width = 2; - *alignment = 2; - } else { - *width = 4; - *alignment = 4; - } - break; - - case VT_UI2: - case VT_I2: - case VT_BOOL: - *encoded_tdesc = default_tdesc; - *width = 2; - *alignment = 2; - break; - - case VT_I4: - case VT_UI4: - case VT_R4: - case VT_ERROR: - case VT_BSTR: - case VT_HRESULT: - *encoded_tdesc = default_tdesc; - *width = 4; - *alignment = 4; - break; - - case VT_CY: - *encoded_tdesc = default_tdesc; - *width = 8; - *alignment = 4; /* guess? */ - break; - - case VT_VOID: - *encoded_tdesc = 0x80000000 | (VT_EMPTY << 16) | tdesc->vt; - *width = 0; - *alignment = 1; - break; - - case VT_PTR: - /* FIXME: Make with the error checking. */ - FIXME("PTR vartype, may not work correctly.\n"); - - ctl2_encode_typedesc(This, tdesc->u.lptdesc, &target_type, NULL, NULL, &child_size); - - for (typeoffset = 0; typeoffset < This->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) { - typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; - if (((typedata[0] & 0xffff) == VT_PTR) && (typedata[1] == target_type)) break; - } - - if (typeoffset == This->typelib_segdir[MSFT_SEG_TYPEDESC].length) { - int mix_field; - - if (target_type & 0x80000000) { - mix_field = ((target_type >> 16) & 0x3fff) | VT_BYREF; - } else { - typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][target_type]; - mix_field = ((typedata[0] >> 16) == 0x7fff)? 0x7fff: 0x7ffe; - } - - typeoffset = ctl2_alloc_segment(This, MSFT_SEG_TYPEDESC, 8, 0); - typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; - - typedata[0] = (mix_field << 16) | VT_PTR; - typedata[1] = target_type; - } - - *encoded_tdesc = typeoffset; - - *width = 4; - *alignment = 4; - *decoded_size = sizeof(TYPEDESC) + child_size; - break; - - case VT_SAFEARRAY: - /* FIXME: Make with the error checking. */ - FIXME("SAFEARRAY vartype, may not work correctly.\n"); - - ctl2_encode_typedesc(This, tdesc->u.lptdesc, &target_type, NULL, NULL, &child_size); - - for (typeoffset = 0; typeoffset < This->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) { - typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; - if (((typedata[0] & 0xffff) == VT_SAFEARRAY) && (typedata[1] == target_type)) break; - } - - if (typeoffset == This->typelib_segdir[MSFT_SEG_TYPEDESC].length) { - int mix_field; - - if (target_type & 0x80000000) { - mix_field = ((target_type >> 16) & VT_TYPEMASK) | VT_ARRAY; - } else { - typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][target_type]; - mix_field = ((typedata[0] >> 16) == 0x7fff)? 0x7fff: 0x7ffe; - } - - typeoffset = ctl2_alloc_segment(This, MSFT_SEG_TYPEDESC, 8, 0); - typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; - - typedata[0] = (mix_field << 16) | VT_SAFEARRAY; - typedata[1] = target_type; - } - - *encoded_tdesc = typeoffset; - - *width = 4; - *alignment = 4; - *decoded_size = sizeof(TYPEDESC) + child_size; - break; - - case VT_CARRAY: - { - /* FIXME: Make with the error checking. */ - int num_dims = tdesc->u.lpadesc->cDims, elements = 1, dim; - - ctl2_encode_typedesc(This, &tdesc->u.lpadesc->tdescElem, &target_type, width, alignment, NULL); - arrayoffset = ctl2_alloc_segment(This, MSFT_SEG_ARRAYDESC, (2 + 2 * num_dims) * sizeof(int), 0); - arraydata = (void *)&This->typelib_segment_data[MSFT_SEG_ARRAYDESC][arrayoffset]; - - arraydata[0] = target_type; - arraydata[1] = num_dims; - arraydata[1] |= ((num_dims * 2 * sizeof(int)) << 16); - arraydata += 2; - - for(dim = 0; dim < num_dims; dim++) { - arraydata[0] = tdesc->u.lpadesc->rgbounds[dim].cElements; - arraydata[1] = tdesc->u.lpadesc->rgbounds[dim].lLbound; - elements *= tdesc->u.lpadesc->rgbounds[dim].cElements; - arraydata += 2; - } - typeoffset = ctl2_alloc_segment(This, MSFT_SEG_TYPEDESC, 8, 0); - typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; - - typedata[0] = (0x7ffe << 16) | VT_CARRAY; - typedata[1] = arrayoffset; - - *encoded_tdesc = typeoffset; - *width = *width * elements; - *decoded_size = sizeof(ARRAYDESC) + (num_dims - 1) * sizeof(SAFEARRAYBOUND); - - break; - } - case VT_USERDEFINED: - TRACE("USERDEFINED.\n"); - for (typeoffset = 0; typeoffset < This->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) { - typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; - if ((typedata[0] == ((0x7fff << 16) | VT_USERDEFINED)) && (typedata[1] == tdesc->u.hreftype)) break; - } - - if (typeoffset == This->typelib_segdir[MSFT_SEG_TYPEDESC].length) { - typeoffset = ctl2_alloc_segment(This, MSFT_SEG_TYPEDESC, 8, 0); - typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; - - typedata[0] = (0x7fff << 16) | VT_USERDEFINED; - typedata[1] = tdesc->u.hreftype; - } - - *encoded_tdesc = typeoffset; - *width = 0; - *alignment = 1; - break; - - default: - FIXME("Unrecognized type %d.\n", tdesc->vt); - *encoded_tdesc = default_tdesc; - *width = 0; - *alignment = 1; - break; - } - - return 0; -} - -/**************************************************************************** - * ctl2_find_nth_reference - * - * Finds a reference by index into the linked list of reference records. - * - * RETURNS - * - * Success: Offset of the desired reference record. - * Failure: -1. - */ -static int ctl2_find_nth_reference( - ICreateTypeLib2Impl *This, /* [I] The type library in which to search. */ - int offset, /* [I] The starting offset of the reference list. */ - int index) /* [I] The index of the reference to find. */ -{ - MSFT_RefRecord *ref; - - for (; index && (offset != -1); index--) { - ref = (MSFT_RefRecord *)&This->typelib_segment_data[MSFT_SEG_REFERENCES][offset]; - offset = ref->onext; - } - - return offset; -} - -/**************************************************************************** - * ctl2_find_typeinfo_from_offset - * - * Finds an ITypeInfo given an offset into the TYPEINFO segment. - * - * RETURNS - * - * Success: S_OK. - * Failure: TYPE_E_ELEMENTNOTFOUND. - */ -static HRESULT ctl2_find_typeinfo_from_offset( - ICreateTypeLib2Impl *This, /* [I] The typelib to find the typeinfo in. */ - int offset, /* [I] The offset of the desired typeinfo. */ - ITypeInfo **ppTinfo) /* [I] The typeinfo found. */ -{ - void *typeinfodata; - ICreateTypeInfo2Impl *typeinfo; - - typeinfodata = &This->typelib_segment_data[MSFT_SEG_TYPEINFO][offset]; - - for (typeinfo = This->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) { - if (typeinfo->typeinfo == typeinfodata) { - *ppTinfo = (ITypeInfo *)&typeinfo->lpVtblTypeInfo2; - ITypeInfo2_AddRef(*ppTinfo); - return S_OK; - } - } - - ERR("Failed to find typeinfo, invariant varied.\n"); - - return TYPE_E_ELEMENTNOTFOUND; -} - -/*================== ICreateTypeInfo2 Implementation ===================================*/ - -/****************************************************************************** - * ICreateTypeInfo2_QueryInterface {OLEAUT32} - * - * See IUnknown_QueryInterface. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnQueryInterface( - ICreateTypeInfo2 * iface, - REFIID riid, - VOID **ppvObject) -{ - ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; - - TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid)); - - *ppvObject=NULL; - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid,&IID_ICreateTypeInfo)|| - IsEqualIID(riid,&IID_ICreateTypeInfo2)) - { - *ppvObject = This; - } else if (IsEqualIID(riid, &IID_ITypeInfo) || - IsEqualIID(riid, &IID_ITypeInfo2)) { - *ppvObject = &This->lpVtblTypeInfo2; - } - - if(*ppvObject) - { - ICreateTypeLib2_AddRef(iface); - TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject); - return S_OK; - } - TRACE("-- Interface: E_NOINTERFACE\n"); - return E_NOINTERFACE; -} - -/****************************************************************************** - * ICreateTypeInfo2_AddRef {OLEAUT32} - * - * See IUnknown_AddRef. - */ -static ULONG WINAPI ICreateTypeInfo2_fnAddRef(ICreateTypeInfo2 *iface) -{ - ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; - ULONG ref = InterlockedIncrement(&This->ref); - - TRACE("(%p)->ref was %lu\n",This, ref - 1); - - return ref; -} - -/****************************************************************************** - * ICreateTypeInfo2_Release {OLEAUT32} - * - * See IUnknown_Release. - */ -static ULONG WINAPI ICreateTypeInfo2_fnRelease(ICreateTypeInfo2 *iface) -{ - ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; - ULONG ref = InterlockedDecrement(&This->ref); - - TRACE("(%p)->(%lu)\n",This, ref); - - if (!ref) { - if (This->typelib) { - ICreateTypeLib2_fnRelease((ICreateTypeLib2 *)This->typelib); - This->typelib = NULL; - } - - /* ICreateTypeLib2 frees all ICreateTypeInfos when it releases. */ - /* HeapFree(GetProcessHeap(),0,This); */ - return 0; - } - - return ref; -} - - -/****************************************************************************** - * ICreateTypeInfo2_SetGuid {OLEAUT32} - * - * See ICreateTypeInfo_SetGuid. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetGuid(ICreateTypeInfo2 *iface, REFGUID guid) -{ - ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; - - MSFT_GuidEntry guidentry; - int offset; - - TRACE("(%p,%s)\n", iface, debugstr_guid(guid)); - - guidentry.guid = *guid; - guidentry.hreftype = This->typelib->typelib_typeinfo_offsets[This->typeinfo->typekind >> 16]; - guidentry.next_hash = -1; - - offset = ctl2_alloc_guid(This->typelib, &guidentry); - - if (offset == -1) return E_OUTOFMEMORY; - - This->typeinfo->posguid = offset; - - if (IsEqualIID(guid, &IID_IDispatch)) { - This->typelib->typelib_header.dispatchpos = This->typelib->typelib_typeinfo_offsets[This->typeinfo->typekind >> 16]; - } - - return S_OK; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetTypeFlags {OLEAUT32} - * - * See ICreateTypeInfo_SetTypeFlags. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetTypeFlags(ICreateTypeInfo2 *iface, UINT uTypeFlags) -{ - ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; - - TRACE("(%p,0x%x)\n", iface, uTypeFlags); - - This->typeinfo->flags = uTypeFlags; - - if (uTypeFlags & 0x1000) { - MSFT_GuidEntry foo; - int guidoffset; - int fileoffset; - MSFT_ImpInfo impinfo; - static const WCHAR stdole2tlb[] = { 's','t','d','o','l','e','2','.','t','l','b',0 }; - - foo.guid = IID_StdOle; - foo.hreftype = 2; - foo.next_hash = -1; - guidoffset = ctl2_alloc_guid(This->typelib, &foo); - if (guidoffset == -1) return E_OUTOFMEMORY; - - fileoffset = ctl2_alloc_importfile(This->typelib, guidoffset, 2, 0, stdole2tlb); - if (fileoffset == -1) return E_OUTOFMEMORY; - - foo.guid = IID_IDispatch; - foo.hreftype = 1; - foo.next_hash = -1; - guidoffset = ctl2_alloc_guid(This->typelib, &foo); - if (guidoffset == -1) return E_OUTOFMEMORY; - - impinfo.res0 = 0x03010000; - impinfo.oImpFile = fileoffset; - impinfo.oGuid = guidoffset; - ctl2_alloc_importinfo(This->typelib, &impinfo); - - This->typelib->typelib_header.dispatchpos = 1; - This->typelib->typelib_header.res50 = 1; - - This->typeinfo->typekind |= 0x10; - This->typeinfo->typekind &= ~0x0f; - This->typeinfo->typekind |= TKIND_DISPATCH; - } - - return S_OK; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetDocString {OLEAUT32} - * - * See ICreateTypeInfo_SetDocString. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetDocString( - ICreateTypeInfo2* iface, - LPOLESTR pStrDoc) -{ - ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; - - int offset; - - TRACE("(%p,%s)\n", iface, debugstr_w(pStrDoc)); - - offset = ctl2_alloc_string(This->typelib, pStrDoc); - if (offset == -1) return E_OUTOFMEMORY; - This->typeinfo->docstringoffs = offset; - return S_OK; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetHelpContext {OLEAUT32} - * - * See ICreateTypeInfo_SetHelpContext. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetHelpContext( - ICreateTypeInfo2* iface, - DWORD dwHelpContext) -{ - ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; - - TRACE("(%p,%ld)\n", iface, dwHelpContext); - - This->typeinfo->helpcontext = dwHelpContext; - - return S_OK; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetVersion {OLEAUT32} - * - * See ICreateTypeInfo_SetVersion. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetVersion( - ICreateTypeInfo2* iface, - WORD wMajorVerNum, - WORD wMinorVerNum) -{ - ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; - - TRACE("(%p,%d,%d)\n", iface, wMajorVerNum, wMinorVerNum); - - This->typeinfo->version = wMajorVerNum | (wMinorVerNum << 16); - return S_OK; -} - -/****************************************************************************** - * ICreateTypeInfo2_AddRefTypeInfo {OLEAUT32} - * - * See ICreateTypeInfo_AddRefTypeInfo. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnAddRefTypeInfo( - ICreateTypeInfo2* iface, - ITypeInfo* pTInfo, - HREFTYPE* phRefType) -{ - ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; - - ITypeLib *container; - int index; - HRESULT res; - - TRACE("(%p,%p,%p)\n", iface, pTInfo, phRefType); - - /* - * If this is one of ours, we set *phRefType to the TYPEINFO offset of - * the referred TypeInfo. Otherwise, we presumably have more magic to do. - * - * Unfortunately, we can't rely on the passed-in TypeInfo even having the - * same internal structure as one of ours. It could be from another - * implementation of ITypeInfo. So we need to do the following... - */ - res = ITypeInfo_GetContainingTypeLib(pTInfo, &container, &index); - if (!SUCCEEDED(res)) { - TRACE("failed to find containing typelib.\n"); - return res; - } - - if (container == (ITypeLib *)&This->typelib->lpVtblTypeLib2) { - *phRefType = This->typelib->typelib_typeinfo_offsets[index]; - } else { - FIXME("(%p,%p,%p), pTInfo from different typelib.\n", iface, pTInfo, phRefType); - } - - ITypeLib_Release(container); - return S_OK; -} - -/****************************************************************************** - * ICreateTypeInfo2_AddFuncDesc {OLEAUT32} - * - * See ICreateTypeInfo_AddFuncDesc. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnAddFuncDesc( - ICreateTypeInfo2* iface, - UINT index, - FUNCDESC* pFuncDesc) -{ - ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; - - int offset; - int *typedata; - int i; - int decoded_size; - - FIXME("(%p,%d,%p), stub!\n", iface, index, pFuncDesc); - FIXME("{%ld,%p,%p,%d,%d,%d,%d,%d,%d,%d,{%d},%d}\n", pFuncDesc->memid, pFuncDesc->lprgscode, pFuncDesc->lprgelemdescParam, pFuncDesc->funckind, pFuncDesc->invkind, pFuncDesc->callconv, pFuncDesc->cParams, pFuncDesc->cParamsOpt, pFuncDesc->oVft, pFuncDesc->cScodes, pFuncDesc->elemdescFunc.tdesc.vt, pFuncDesc->wFuncFlags); -/* FIXME("{%d, %d}\n", pFuncDesc->lprgelemdescParam[0].tdesc.vt, pFuncDesc->lprgelemdescParam[1].tdesc.vt); */ -/* return E_OUTOFMEMORY; */ - - if (!This->typedata) { - This->typedata = HeapAlloc(GetProcessHeap(), 0, 0x2000); - This->typedata[0] = 0; - } - - /* allocate type data space for us */ - offset = This->typedata[0]; - This->typedata[0] += 0x18 + (pFuncDesc->cParams * 12); - typedata = This->typedata + (offset >> 2) + 1; - - /* fill out the basic type information */ - typedata[0] = (0x18 + (pFuncDesc->cParams * 12)) | (index << 16); - ctl2_encode_typedesc(This->typelib, &pFuncDesc->elemdescFunc.tdesc, &typedata[1], NULL, NULL, &decoded_size); - typedata[2] = pFuncDesc->wFuncFlags; - typedata[3] = ((sizeof(FUNCDESC) + decoded_size) << 16) | This->typeinfo->cbSizeVft; - typedata[4] = (index << 16) | (pFuncDesc->callconv << 8) | 9; - typedata[5] = pFuncDesc->cParams; - - /* NOTE: High word of typedata[3] is total size of FUNCDESC + size of all ELEMDESCs for params + TYPEDESCs for pointer params and return types. */ - /* That is, total memory allocation required to reconstitute the FUNCDESC in its entirety. */ - typedata[3] += (sizeof(ELEMDESC) * pFuncDesc->cParams) << 16; - - for (i = 0; i < pFuncDesc->cParams; i++) { - ctl2_encode_typedesc(This->typelib, &pFuncDesc->lprgelemdescParam[i].tdesc, &typedata[6+(i*3)], NULL, NULL, &decoded_size); - typedata[7+(i*3)] = -1; - typedata[8+(i*3)] = pFuncDesc->lprgelemdescParam[i].u.paramdesc.wParamFlags; - typedata[3] += decoded_size << 16; - -#if 0 - /* FIXME: Doesn't work. Doesn't even come up with usable VTs for varDefaultValue. */ - if (pFuncDesc->lprgelemdescParam[i].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) { - ctl2_alloc_custdata(This->typelib, &pFuncDesc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue); - } -#endif - } - - /* update the index data */ - This->indices[index] = ((0x6000 | This->typeinfo->cImplTypes) << 16) | index; - This->names[index] = -1; - This->offsets[index] = offset; - - /* ??? */ - if (!This->typeinfo->res2) This->typeinfo->res2 = 0x20; - This->typeinfo->res2 <<= 1; - - /* ??? */ - if (This->typeinfo->res3 == -1) This->typeinfo->res3 = 0; - This->typeinfo->res3 += 0x38; - - /* ??? */ - if (index < 2) This->typeinfo->res2 += pFuncDesc->cParams << 4; - This->typeinfo->res3 += pFuncDesc->cParams << 4; - - /* adjust size of VTBL */ - This->typeinfo->cbSizeVft += 4; - - /* Increment the number of function elements */ - This->typeinfo->cElement += 1; - - return S_OK; -} - -/****************************************************************************** - * ICreateTypeInfo2_AddImplType {OLEAUT32} - * - * See ICreateTypeInfo_AddImplType. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnAddImplType( - ICreateTypeInfo2* iface, - UINT index, - HREFTYPE hRefType) -{ - ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; - - TRACE("(%p,%d,%ld)\n", iface, index, hRefType); - - if ((This->typeinfo->typekind & 15) == TKIND_COCLASS) { - int offset; - MSFT_RefRecord *ref; - - if (index == 0) { - if (This->typeinfo->datatype1 != -1) return TYPE_E_ELEMENTNOTFOUND; - - offset = ctl2_alloc_segment(This->typelib, MSFT_SEG_REFERENCES, sizeof(MSFT_RefRecord), 0); - if (offset == -1) return E_OUTOFMEMORY; - - This->typeinfo->datatype1 = offset; - } else { - int lastoffset; - - lastoffset = ctl2_find_nth_reference(This->typelib, This->typeinfo->datatype1, index - 1); - if (lastoffset == -1) return TYPE_E_ELEMENTNOTFOUND; - - ref = (MSFT_RefRecord *)&This->typelib->typelib_segment_data[MSFT_SEG_REFERENCES][lastoffset]; - if (ref->onext != -1) return TYPE_E_ELEMENTNOTFOUND; - - offset = ctl2_alloc_segment(This->typelib, MSFT_SEG_REFERENCES, sizeof(MSFT_RefRecord), 0); - if (offset == -1) return E_OUTOFMEMORY; - - ref->onext = offset; - } - - ref = (MSFT_RefRecord *)&This->typelib->typelib_segment_data[MSFT_SEG_REFERENCES][offset]; - - ref->reftype = hRefType; - ref->flags = 0; - ref->oCustData = -1; - ref->onext = -1; - } else if ((This->typeinfo->typekind & 15) == TKIND_DISPATCH) { - FIXME("dispatch case unhandled.\n"); - } else if ((This->typeinfo->typekind & 15) == TKIND_INTERFACE) { - if (This->typeinfo->cImplTypes) { - return (index == 1)? TYPE_E_BADMODULEKIND: TYPE_E_ELEMENTNOTFOUND; - } - - if (index != 0) return TYPE_E_ELEMENTNOTFOUND; - - This->typeinfo->cImplTypes++; - - /* hacked values for IDispatch only, and maybe only for stdole. */ - This->typeinfo->cbSizeVft += 0x0c; /* hack */ - This->typeinfo->datatype1 = hRefType; - This->typeinfo->datatype2 = (3 << 16) | 1; /* ? */ - } else { - FIXME("AddImplType unsupported on typekind %d\n", This->typeinfo->typekind & 15); - return E_OUTOFMEMORY; - } - - return S_OK; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetImplTypeFlags {OLEAUT32} - * - * See ICreateTypeInfo_SetImplTypeFlags. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetImplTypeFlags( - ICreateTypeInfo2* iface, - UINT index, - INT implTypeFlags) -{ - ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; - int offset; - MSFT_RefRecord *ref; - - TRACE("(%p,%d,0x%x)\n", iface, index, implTypeFlags); - - if ((This->typeinfo->typekind & 15) != TKIND_COCLASS) { - return TYPE_E_BADMODULEKIND; - } - - offset = ctl2_find_nth_reference(This->typelib, This->typeinfo->datatype1, index); - if (offset == -1) return TYPE_E_ELEMENTNOTFOUND; - - ref = (MSFT_RefRecord *)&This->typelib->typelib_segment_data[MSFT_SEG_REFERENCES][offset]; - ref->flags = implTypeFlags; - - return S_OK; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetAlignment {OLEAUT32} - * - * See ICreateTypeInfo_SetAlignment. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetAlignment( - ICreateTypeInfo2* iface, - WORD cbAlignment) -{ - ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; - - TRACE("(%p,%d)\n", iface, cbAlignment); - - if (!cbAlignment) return E_INVALIDARG; - if (cbAlignment > 16) return E_INVALIDARG; - - This->typeinfo->typekind &= ~0xffc0; - This->typeinfo->typekind |= cbAlignment << 6; - - /* FIXME: There's probably some way to simplify this. */ - switch (This->typeinfo->typekind & 15) { - case TKIND_ALIAS: - default: - break; - - case TKIND_ENUM: - case TKIND_INTERFACE: - case TKIND_DISPATCH: - case TKIND_COCLASS: - if (cbAlignment > 4) cbAlignment = 4; - break; - - case TKIND_RECORD: - case TKIND_MODULE: - case TKIND_UNION: - cbAlignment = 1; - break; - } - - This->typeinfo->typekind |= cbAlignment << 11; - - return S_OK; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetSchema {OLEAUT32} - * - * See ICreateTypeInfo_SetSchema. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetSchema( - ICreateTypeInfo2* iface, - LPOLESTR pStrSchema) -{ - FIXME("(%p,%s), stub!\n", iface, debugstr_w(pStrSchema)); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_AddVarDesc {OLEAUT32} - * - * See ICreateTypeInfo_AddVarDesc. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnAddVarDesc( - ICreateTypeInfo2* iface, - UINT index, - VARDESC* pVarDesc) -{ - ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; - int offset; - INT *typedata; - int var_datawidth; - int var_alignment; - int var_type_size; - int alignment; - - TRACE("(%p,%d,%p), stub!\n", iface, index, pVarDesc); - TRACE("%ld, %p, %ld, {{%lx, %d}, {%p, %x}}, 0x%x, %d\n", pVarDesc->memid, pVarDesc->lpstrSchema, pVarDesc->u.oInst, - pVarDesc->elemdescVar.tdesc.u.hreftype, pVarDesc->elemdescVar.tdesc.vt, - pVarDesc->elemdescVar.u.paramdesc.pparamdescex, pVarDesc->elemdescVar.u.paramdesc.wParamFlags, - pVarDesc->wVarFlags, pVarDesc->varkind); - - if ((This->typeinfo->cElement >> 16) != index) { - TRACE("Out-of-order element.\n"); - return TYPE_E_ELEMENTNOTFOUND; - } - - if (!This->typedata) { - This->typedata = HeapAlloc(GetProcessHeap(), 0, 0x2000); - This->typedata[0] = 0; - } - - /* allocate type data space for us */ - offset = This->typedata[0]; - This->typedata[0] += 0x14; - typedata = This->typedata + (offset >> 2) + 1; - - /* fill out the basic type information */ - typedata[0] = 0x14 | (index << 16); - typedata[2] = pVarDesc->wVarFlags; - typedata[3] = (sizeof(VARDESC) << 16) | 0; - - /* update the index data */ - This->indices[index] = 0x40000000 + index; - This->names[index] = -1; - This->offsets[index] = offset; - - /* figure out type widths and whatnot */ - ctl2_encode_typedesc(This->typelib, &pVarDesc->elemdescVar.tdesc, - &typedata[1], &var_datawidth, &var_alignment, - &var_type_size); - - /* pad out starting position to data width */ - This->datawidth += var_alignment - 1; - This->datawidth &= ~(var_alignment - 1); - typedata[4] = This->datawidth; - - /* add the new variable to the total data width */ - This->datawidth += var_datawidth; - - /* add type description size to total required allocation */ - typedata[3] += var_type_size << 16; - - /* fix type alignment */ - alignment = (This->typeinfo->typekind >> 11) & 0x1f; - if (alignment < var_alignment) { - alignment = var_alignment; - This->typeinfo->typekind &= ~0xf800; - This->typeinfo->typekind |= alignment << 11; - } - - /* ??? */ - if (!This->typeinfo->res2) This->typeinfo->res2 = 0x1a; - if ((index == 0) || (index == 1) || (index == 2) || (index == 4) || (index == 9)) { - This->typeinfo->res2 <<= 1; - } - - /* ??? */ - if (This->typeinfo->res3 == -1) This->typeinfo->res3 = 0; - This->typeinfo->res3 += 0x2c; - - /* increment the number of variable elements */ - This->typeinfo->cElement += 0x10000; - - /* pad data width to alignment */ - This->typeinfo->size = (This->datawidth + (alignment - 1)) & ~(alignment - 1); - - return S_OK; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetFuncAndParamNames {OLEAUT32} - * - * See ICreateTypeInfo_SetFuncAndParamNames. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncAndParamNames( - ICreateTypeInfo2* iface, - UINT index, - LPOLESTR* rgszNames, - UINT cNames) -{ - ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; - - int i; - int offset; - char *namedata; - - FIXME("(%p,%d,%s,%d), stub!\n", iface, index, debugstr_w(*rgszNames), cNames); - - offset = ctl2_alloc_name(This->typelib, rgszNames[0]); - This->names[index] = offset; - - namedata = This->typelib->typelib_segment_data[MSFT_SEG_NAME] + offset; - namedata[9] &= ~0x10; - if (*((INT *)namedata) == -1) { - *((INT *)namedata) = This->typelib->typelib_typeinfo_offsets[This->typeinfo->typekind >> 16]; - } - - for (i = 1; i < cNames; i++) { - /* FIXME: Almost certainly easy to break */ - int *paramdata = &This->typedata[This->offsets[index] >> 2]; - - offset = ctl2_alloc_name(This->typelib, rgszNames[i]); - paramdata[(i * 3) + 5] = offset; - } - - return S_OK; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetVarName {OLEAUT32} - * - * See ICreateTypeInfo_SetVarName. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetVarName( - ICreateTypeInfo2* iface, - UINT index, - LPOLESTR szName) -{ - ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; - int offset; - char *namedata; - - TRACE("(%p,%d,%s), stub!\n", iface, index, debugstr_w(szName)); - - if ((This->typeinfo->cElement >> 16) <= index) { - TRACE("Out-of-order element.\n"); - return TYPE_E_ELEMENTNOTFOUND; - } - - offset = ctl2_alloc_name(This->typelib, szName); - if (offset == -1) return E_OUTOFMEMORY; - - namedata = This->typelib->typelib_segment_data[MSFT_SEG_NAME] + offset; - if (*((INT *)namedata) == -1) { - *((INT *)namedata) = This->typelib->typelib_typeinfo_offsets[This->typeinfo->typekind >> 16]; - namedata[9] |= 0x10; - } - if ((This->typeinfo->typekind & 15) == TKIND_ENUM) { - namedata[9] |= 0x20; - } - This->names[index] = offset; - - return S_OK; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetTypeDescAlias {OLEAUT32} - * - * See ICreateTypeInfo_SetTypeDescAlias. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetTypeDescAlias( - ICreateTypeInfo2* iface, - TYPEDESC* pTDescAlias) -{ - ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; - - int encoded_typedesc; - int width; - - if ((This->typeinfo->typekind & 15) != TKIND_ALIAS) { - return TYPE_E_WRONGTYPEKIND; - } - - FIXME("(%p,%p), hack!\n", iface, pTDescAlias); - - if (ctl2_encode_typedesc(This->typelib, pTDescAlias, &encoded_typedesc, &width, NULL, NULL) == -1) { - return E_OUTOFMEMORY; - } - - This->typeinfo->size = width; - This->typeinfo->datatype1 = encoded_typedesc; - - return S_OK; -} - -/****************************************************************************** - * ICreateTypeInfo2_DefineFuncAsDllEntry {OLEAUT32} - * - * See ICreateTypeInfo_DefineFuncAsDllEntry. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnDefineFuncAsDllEntry( - ICreateTypeInfo2* iface, - UINT index, - LPOLESTR szDllName, - LPOLESTR szProcName) -{ - FIXME("(%p,%d,%s,%s), stub!\n", iface, index, debugstr_w(szDllName), debugstr_w(szProcName)); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetFuncDocString {OLEAUT32} - * - * See ICreateTypeInfo_SetFuncDocString. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncDocString( - ICreateTypeInfo2* iface, - UINT index, - LPOLESTR szDocString) -{ - FIXME("(%p,%d,%s), stub!\n", iface, index, debugstr_w(szDocString)); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetVarDocString {OLEAUT32} - * - * See ICreateTypeInfo_SetVarDocString. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetVarDocString( - ICreateTypeInfo2* iface, - UINT index, - LPOLESTR szDocString) -{ - ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; - - FIXME("(%p,%d,%s), stub!\n", iface, index, debugstr_w(szDocString)); - - ctl2_alloc_string(This->typelib, szDocString); - - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetFuncHelpContext {OLEAUT32} - * - * See ICreateTypeInfo_SetFuncHelpContext. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncHelpContext( - ICreateTypeInfo2* iface, - UINT index, - DWORD dwHelpContext) -{ - FIXME("(%p,%d,%ld), stub!\n", iface, index, dwHelpContext); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetVarHelpContext {OLEAUT32} - * - * See ICreateTypeInfo_SetVarHelpContext. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetVarHelpContext( - ICreateTypeInfo2* iface, - UINT index, - DWORD dwHelpContext) -{ - FIXME("(%p,%d,%ld), stub!\n", iface, index, dwHelpContext); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetMops {OLEAUT32} - * - * See ICreateTypeInfo_SetMops. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetMops( - ICreateTypeInfo2* iface, - UINT index, - BSTR bstrMops) -{ - FIXME("(%p,%d,%p), stub!\n", iface, index, bstrMops); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetTypeIdldesc {OLEAUT32} - * - * See ICreateTypeInfo_SetTypeIdldesc. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetTypeIdldesc( - ICreateTypeInfo2* iface, - IDLDESC* pIdlDesc) -{ - FIXME("(%p,%p), stub!\n", iface, pIdlDesc); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_LayOut {OLEAUT32} - * - * See ICreateTypeInfo_LayOut. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnLayOut( - ICreateTypeInfo2* iface) -{ - TRACE("(%p), stub!\n", iface); -/* return E_OUTOFMEMORY; */ - return S_OK; -} - -/****************************************************************************** - * ICreateTypeInfo2_DeleteFuncDesc {OLEAUT32} - * - * Delete a function description from a type. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnDeleteFuncDesc( - ICreateTypeInfo2* iface, /* [I] The typeinfo from which to delete a function. */ - UINT index) /* [I] The index of the function to delete. */ -{ - FIXME("(%p,%d), stub!\n", iface, index); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_DeleteFuncDescByMemId {OLEAUT32} - * - * Delete a function description from a type. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnDeleteFuncDescByMemId( - ICreateTypeInfo2* iface, /* [I] The typeinfo from which to delete a function. */ - MEMBERID memid, /* [I] The member id of the function to delete. */ - INVOKEKIND invKind) /* [I] The invocation type of the function to delete. (?) */ -{ - FIXME("(%p,%ld,%d), stub!\n", iface, memid, invKind); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_DeleteVarDesc {OLEAUT32} - * - * Delete a variable description from a type. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY, E_INVALIDARG, TYPE_E_IOERROR, - * TYPE_E_INVDATAREAD, TYPE_E_UNSUPFORMAT or TYPE_E_INVALIDSTATE. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnDeleteVarDesc( - ICreateTypeInfo2* iface, /* [I] The typeinfo from which to delete the variable description. */ - UINT index) /* [I] The index of the variable description to delete. */ -{ - FIXME("(%p,%d), stub!\n", iface, index); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_DeleteVarDescByMemId {OLEAUT32} - * - * Delete a variable description from a type. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY, E_INVALIDARG, TYPE_E_IOERROR, - * TYPE_E_INVDATAREAD, TYPE_E_UNSUPFORMAT or TYPE_E_INVALIDSTATE. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnDeleteVarDescByMemId( - ICreateTypeInfo2* iface, /* [I] The typeinfo from which to delete the variable description. */ - MEMBERID memid) /* [I] The member id of the variable description to delete. */ -{ - FIXME("(%p,%ld), stub!\n", iface, memid); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_DeleteImplType {OLEAUT32} - * - * Delete an interface implementation from a type. (?) - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnDeleteImplType( - ICreateTypeInfo2* iface, /* [I] The typeinfo from which to delete. */ - UINT index) /* [I] The index of the interface to delete. */ -{ - FIXME("(%p,%d), stub!\n", iface, index); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetCustData {OLEAUT32} - * - * Set the custom data for a type. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetCustData( - ICreateTypeInfo2* iface, /* [I] The typeinfo in which to set the custom data. */ - REFGUID guid, /* [I] The GUID used as a key to retrieve the custom data. */ - VARIANT* pVarVal) /* [I] The custom data. */ -{ - FIXME("(%p,%s,%p), stub!\n", iface, debugstr_guid(guid), pVarVal); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetFuncCustData {OLEAUT32} - * - * Set the custom data for a function. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncCustData( - ICreateTypeInfo2* iface, /* [I] The typeinfo in which to set the custom data. */ - UINT index, /* [I] The index of the function for which to set the custom data. */ - REFGUID guid, /* [I] The GUID used as a key to retrieve the custom data. */ - VARIANT* pVarVal) /* [I] The custom data. */ -{ - FIXME("(%p,%d,%s,%p), stub!\n", iface, index, debugstr_guid(guid), pVarVal); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetParamCustData {OLEAUT32} - * - * Set the custom data for a function parameter. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetParamCustData( - ICreateTypeInfo2* iface, /* [I] The typeinfo in which to set the custom data. */ - UINT indexFunc, /* [I] The index of the function on which the parameter resides. */ - UINT indexParam, /* [I] The index of the parameter on which to set the custom data. */ - REFGUID guid, /* [I] The GUID used as a key to retrieve the custom data. */ - VARIANT* pVarVal) /* [I] The custom data. */ -{ - FIXME("(%p,%d,%d,%s,%p), stub!\n", iface, indexFunc, indexParam, debugstr_guid(guid), pVarVal); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetVarCustData {OLEAUT32} - * - * Set the custom data for a variable. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetVarCustData( - ICreateTypeInfo2* iface, /* [I] The typeinfo in which to set the custom data. */ - UINT index, /* [I] The index of the variable on which to set the custom data. */ - REFGUID guid, /* [I] The GUID used as a key to retrieve the custom data. */ - VARIANT* pVarVal) /* [I] The custom data. */ -{ - FIXME("(%p,%d,%s,%p), stub!\n", iface, index, debugstr_guid(guid), pVarVal); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetImplTypeCustData {OLEAUT32} - * - * Set the custom data for an implemented interface. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetImplTypeCustData( - ICreateTypeInfo2* iface, /* [I] The typeinfo on which to set the custom data. */ - UINT index, /* [I] The index of the implemented interface on which to set the custom data. */ - REFGUID guid, /* [I] The GUID used as a key to retrieve the custom data. */ - VARIANT* pVarVal) /* [I] The custom data. */ -{ - FIXME("(%p,%d,%s,%p), stub!\n", iface, index, debugstr_guid(guid), pVarVal); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetHelpStringContext {OLEAUT32} - * - * Set the help string context for the typeinfo. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetHelpStringContext( - ICreateTypeInfo2* iface, /* [I] The typeinfo on which to set the help string context. */ - ULONG dwHelpStringContext) /* [I] The help string context. */ -{ - FIXME("(%p,%ld), stub!\n", iface, dwHelpStringContext); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetFuncHelpStringContext {OLEAUT32} - * - * Set the help string context for a function. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncHelpStringContext( - ICreateTypeInfo2* iface, /* [I] The typeinfo on which to set the help string context. */ - UINT index, /* [I] The index for the function on which to set the help string context. */ - ULONG dwHelpStringContext) /* [I] The help string context. */ -{ - FIXME("(%p,%d,%ld), stub!\n", iface, index, dwHelpStringContext); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetVarHelpStringContext {OLEAUT32} - * - * Set the help string context for a variable. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetVarHelpStringContext( - ICreateTypeInfo2* iface, /* [I] The typeinfo on which to set the help string context. */ - UINT index, /* [I] The index of the variable on which to set the help string context. */ - ULONG dwHelpStringContext) /* [I] The help string context */ -{ - FIXME("(%p,%d,%ld), stub!\n", iface, index, dwHelpStringContext); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_Invalidate {OLEAUT32} - * - * Undocumented function. (!) - */ -static HRESULT WINAPI ICreateTypeInfo2_fnInvalidate( - ICreateTypeInfo2* iface) -{ - FIXME("(%p), stub!\n", iface); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeInfo2_SetName {OLEAUT32} - * - * Set the name for a typeinfo. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of STG_E_INSUFFICIENTMEMORY, E_OUTOFMEMORY, E_INVALIDARG or TYPE_E_INVALIDSTATE. - */ -static HRESULT WINAPI ICreateTypeInfo2_fnSetName( - ICreateTypeInfo2* iface, - LPOLESTR szName) -{ - FIXME("(%p,%s), stub!\n", iface, debugstr_w(szName)); - return E_OUTOFMEMORY; -} - -/*================== ITypeInfo2 Implementation ===================================*/ - -/****************************************************************************** - * ITypeInfo2_QueryInterface {OLEAUT32} - * - * See IUnknown_QueryInterface. - */ -static HRESULT WINAPI ITypeInfo2_fnQueryInterface(ITypeInfo2 * iface, REFIID riid, LPVOID * ppv) -{ - ICOM_THIS_From_ITypeInfo2(ICreateTypeInfo2Impl, iface); - - return ICreateTypeInfo2_QueryInterface((ICreateTypeInfo2 *)This, riid, ppv); -} - -/****************************************************************************** - * ITypeInfo2_AddRef {OLEAUT32} - * - * See IUnknown_AddRef. - */ -static ULONG WINAPI ITypeInfo2_fnAddRef(ITypeInfo2 * iface) -{ - ICOM_THIS_From_ITypeInfo2(ICreateTypeInfo2Impl, iface); - - return ICreateTypeInfo2_AddRef((ICreateTypeInfo2 *)This); -} - -/****************************************************************************** - * ITypeInfo2_Release {OLEAUT32} - * - * See IUnknown_Release. - */ -static ULONG WINAPI ITypeInfo2_fnRelease(ITypeInfo2 * iface) -{ - ICOM_THIS_From_ITypeInfo2(ICreateTypeInfo2Impl, iface); - - return ICreateTypeInfo2_Release((ICreateTypeInfo2 *)This); -} - -/****************************************************************************** - * ITypeInfo2_GetTypeAttr {OLEAUT32} - * - * See ITypeInfo_GetTypeAttr. - */ -static HRESULT WINAPI ITypeInfo2_fnGetTypeAttr( - ITypeInfo2* iface, - TYPEATTR** ppTypeAttr) -{ - FIXME("(%p,%p), stub!\n", iface, ppTypeAttr); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetTypeComp {OLEAUT32} - * - * See ITypeInfo_GetTypeComp. - */ -static HRESULT WINAPI ITypeInfo2_fnGetTypeComp( - ITypeInfo2* iface, - ITypeComp** ppTComp) -{ - FIXME("(%p,%p), stub!\n", iface, ppTComp); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetFuncDesc {OLEAUT32} - * - * See ITypeInfo_GetFuncDesc. - */ -static HRESULT WINAPI ITypeInfo2_fnGetFuncDesc( - ITypeInfo2* iface, - UINT index, - FUNCDESC** ppFuncDesc) -{ - FIXME("(%p,%d,%p), stub!\n", iface, index, ppFuncDesc); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetVarDesc {OLEAUT32} - * - * See ITypeInfo_GetVarDesc. - */ -static HRESULT WINAPI ITypeInfo2_fnGetVarDesc( - ITypeInfo2* iface, - UINT index, - VARDESC** ppVarDesc) -{ - FIXME("(%p,%d,%p), stub!\n", iface, index, ppVarDesc); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetNames {OLEAUT32} - * - * See ITypeInfo_GetNames. - */ -static HRESULT WINAPI ITypeInfo2_fnGetNames( - ITypeInfo2* iface, - MEMBERID memid, - BSTR* rgBstrNames, - UINT cMaxNames, - UINT* pcNames) -{ - FIXME("(%p,%ld,%p,%d,%p), stub!\n", iface, memid, rgBstrNames, cMaxNames, pcNames); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetRefTypeOfImplType {OLEAUT32} - * - * See ITypeInfo_GetRefTypeOfImplType. - */ -static HRESULT WINAPI ITypeInfo2_fnGetRefTypeOfImplType( - ITypeInfo2* iface, - UINT index, - HREFTYPE* pRefType) -{ - FIXME("(%p,%d,%p), stub!\n", iface, index, pRefType); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetImplTypeFlags {OLEAUT32} - * - * See ITypeInfo_GetImplTypeFlags. - */ -static HRESULT WINAPI ITypeInfo2_fnGetImplTypeFlags( - ITypeInfo2* iface, - UINT index, - INT* pImplTypeFlags) -{ - FIXME("(%p,%d,%p), stub!\n", iface, index, pImplTypeFlags); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetIDsOfNames {OLEAUT32} - * - * See ITypeInfo_GetIDsOfNames. - */ -static HRESULT WINAPI ITypeInfo2_fnGetIDsOfNames( - ITypeInfo2* iface, - LPOLESTR* rgszNames, - UINT cNames, - MEMBERID* pMemId) -{ - FIXME("(%p,%p,%d,%p), stub!\n", iface, rgszNames, cNames, pMemId); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_Invoke {OLEAUT32} - * - * See ITypeInfo_Invoke. - */ -static HRESULT WINAPI ITypeInfo2_fnInvoke( - ITypeInfo2* iface, - PVOID pvInstance, - MEMBERID memid, - WORD wFlags, - DISPPARAMS* pDispParams, - VARIANT* pVarResult, - EXCEPINFO* pExcepInfo, - UINT* puArgErr) -{ - FIXME("(%p,%p,%ld,%x,%p,%p,%p,%p), stub!\n", iface, pvInstance, memid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetDocumentation {OLEAUT32} - * - * See ITypeInfo_GetDocumentation. - */ -static HRESULT WINAPI ITypeInfo2_fnGetDocumentation( - ITypeInfo2* iface, - MEMBERID memid, - BSTR* pBstrName, - BSTR* pBstrDocString, - DWORD* pdwHelpContext, - BSTR* pBstrHelpFile) -{ - FIXME("(%p,%ld,%p,%p,%p,%p), stub!\n", iface, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetDllEntry {OLEAUT32} - * - * See ITypeInfo_GetDllEntry. - */ -static HRESULT WINAPI ITypeInfo2_fnGetDllEntry( - ITypeInfo2* iface, - MEMBERID memid, - INVOKEKIND invKind, - BSTR* pBstrDllName, - BSTR* pBstrName, - WORD* pwOrdinal) -{ - FIXME("(%p,%ld,%d,%p,%p,%p), stub!\n", iface, memid, invKind, pBstrDllName, pBstrName, pwOrdinal); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetRefTypeInfo {OLEAUT32} - * - * See ITypeInfo_GetRefTypeInfo. - */ -static HRESULT WINAPI ITypeInfo2_fnGetRefTypeInfo( - ITypeInfo2* iface, - HREFTYPE hRefType, - ITypeInfo** ppTInfo) -{ - FIXME("(%p,%ld,%p), stub!\n", iface, hRefType, ppTInfo); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_AddressOfMember {OLEAUT32} - * - * See ITypeInfo_AddressOfMember. - */ -static HRESULT WINAPI ITypeInfo2_fnAddressOfMember( - ITypeInfo2* iface, - MEMBERID memid, - INVOKEKIND invKind, - PVOID* ppv) -{ - FIXME("(%p,%ld,%d,%p), stub!\n", iface, memid, invKind, ppv); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_CreateInstance {OLEAUT32} - * - * See ITypeInfo_CreateInstance. - */ -static HRESULT WINAPI ITypeInfo2_fnCreateInstance( - ITypeInfo2* iface, - IUnknown* pUnkOuter, - REFIID riid, - PVOID* ppvObj) -{ - FIXME("(%p,%p,%s,%p), stub!\n", iface, pUnkOuter, debugstr_guid(riid), ppvObj); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetMops {OLEAUT32} - * - * See ITypeInfo_GetMops. - */ -static HRESULT WINAPI ITypeInfo2_fnGetMops( - ITypeInfo2* iface, - MEMBERID memid, - BSTR* pBstrMops) -{ - FIXME("(%p,%ld,%p), stub!\n", iface, memid, pBstrMops); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetContainingTypeLib {OLEAUT32} - * - * See ITypeInfo_GetContainingTypeLib. - */ -static HRESULT WINAPI ITypeInfo2_fnGetContainingTypeLib( - ITypeInfo2* iface, - ITypeLib** ppTLib, - UINT* pIndex) -{ - ICOM_THIS_From_ITypeInfo2(ICreateTypeInfo2Impl, iface); - - TRACE("(%p,%p,%p)\n", iface, ppTLib, pIndex); - - *ppTLib = (ITypeLib *)&This->typelib->lpVtblTypeLib2; - This->typelib->ref++; - *pIndex = This->typeinfo->typekind >> 16; - - return S_OK; -} - -/****************************************************************************** - * ITypeInfo2_ReleaseTypeAttr {OLEAUT32} - * - * See ITypeInfo_ReleaseTypeAttr. - */ -static void WINAPI ITypeInfo2_fnReleaseTypeAttr( - ITypeInfo2* iface, - TYPEATTR* pTypeAttr) -{ - FIXME("(%p,%p), stub!\n", iface, pTypeAttr); -} - -/****************************************************************************** - * ITypeInfo2_ReleaseFuncDesc {OLEAUT32} - * - * See ITypeInfo_ReleaseFuncDesc. - */ -static void WINAPI ITypeInfo2_fnReleaseFuncDesc( - ITypeInfo2* iface, - FUNCDESC* pFuncDesc) -{ - FIXME("(%p,%p), stub!\n", iface, pFuncDesc); -} - -/****************************************************************************** - * ITypeInfo2_ReleaseVarDesc {OLEAUT32} - * - * See ITypeInfo_ReleaseVarDesc. - */ -static void WINAPI ITypeInfo2_fnReleaseVarDesc( - ITypeInfo2* iface, - VARDESC* pVarDesc) -{ - FIXME("(%p,%p), stub!\n", iface, pVarDesc); -} - -/****************************************************************************** - * ITypeInfo2_GetTypeKind {OLEAUT32} - * - * Get the TYPEKIND value for a TypeInfo. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( - ITypeInfo2* iface, /* [I] The TypeInfo to obtain the typekind for. */ - TYPEKIND* pTypeKind) /* [O] The typekind for this TypeInfo. */ -{ - FIXME("(%p,%p), stub!\n", iface, pTypeKind); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetTypeFlags {OLEAUT32} - * - * Get the Type Flags for a TypeInfo. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( - ITypeInfo2* iface, /* [I] The TypeInfo to obtain the typeflags for. */ - ULONG* pTypeFlags) /* [O] The type flags for this TypeInfo. */ -{ - FIXME("(%p,%p), stub!\n", iface, pTypeFlags); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetFuncIndexOfMemId {OLEAUT32} - * - * Gets the index of a function given its member id. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( - ITypeInfo2* iface, /* [I] The TypeInfo in which to find the function. */ - MEMBERID memid, /* [I] The member id for the function. */ - INVOKEKIND invKind, /* [I] The invocation kind for the function. */ - UINT* pFuncIndex) /* [O] The index of the function. */ -{ - FIXME("(%p,%ld,%d,%p), stub!\n", iface, memid, invKind, pFuncIndex); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetVarIndexOfMemId {OLEAUT32} - * - * Gets the index of a variable given its member id. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( - ITypeInfo2* iface, /* [I] The TypeInfo in which to find the variable. */ - MEMBERID memid, /* [I] The member id for the variable. */ - UINT* pVarIndex) /* [O] The index of the variable. */ -{ - FIXME("(%p,%ld,%p), stub!\n", iface, memid, pVarIndex); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetCustData {OLEAUT32} - * - * Gets a custom data element from a TypeInfo. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ITypeInfo2_fnGetCustData( - ITypeInfo2* iface, /* [I] The TypeInfo in which to find the custom data. */ - REFGUID guid, /* [I] The GUID under which the custom data is stored. */ - VARIANT* pVarVal) /* [O] The custom data. */ -{ - FIXME("(%p,%s,%p), stub!\n", iface, debugstr_guid(guid), pVarVal); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetFuncCustData {OLEAUT32} - * - * Gets a custom data element from a function. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData( - ITypeInfo2* iface, /* [I] The TypeInfo in which to find the custom data. */ - UINT index, /* [I] The index of the function for which to retrieve the custom data. */ - REFGUID guid, /* [I] The GUID under which the custom data is stored. */ - VARIANT* pVarVal) /* [O] The custom data. */ -{ - FIXME("(%p,%d,%s,%p), stub!\n", iface, index, debugstr_guid(guid), pVarVal); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetParamCustData {OLEAUT32} - * - * Gets a custom data element from a parameter. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ITypeInfo2_fnGetParamCustData( - ITypeInfo2* iface, /* [I] The TypeInfo in which to find the custom data. */ - UINT indexFunc, /* [I] The index of the function for which to retrieve the custom data. */ - UINT indexParam, /* [I] The index of the parameter for which to retrieve the custom data. */ - REFGUID guid, /* [I] The GUID under which the custom data is stored. */ - VARIANT* pVarVal) /* [O] The custom data. */ -{ - FIXME("(%p,%d,%d,%s,%p), stub!\n", iface, indexFunc, indexParam, debugstr_guid(guid), pVarVal); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetVarCustData {OLEAUT32} - * - * Gets a custom data element from a variable. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ITypeInfo2_fnGetVarCustData( - ITypeInfo2* iface, /* [I] The TypeInfo in which to find the custom data. */ - UINT index, /* [I] The index of the variable for which to retrieve the custom data. */ - REFGUID guid, /* [I] The GUID under which the custom data is stored. */ - VARIANT* pVarVal) /* [O] The custom data. */ -{ - FIXME("(%p,%d,%s,%p), stub!\n", iface, index, debugstr_guid(guid), pVarVal); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetImplTypeCustData {OLEAUT32} - * - * Gets a custom data element from an implemented type of a TypeInfo. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData( - ITypeInfo2* iface, /* [I] The TypeInfo in which to find the custom data. */ - UINT index, /* [I] The index of the implemented type for which to retrieve the custom data. */ - REFGUID guid, /* [I] The GUID under which the custom data is stored. */ - VARIANT* pVarVal) /* [O] The custom data. */ -{ - FIXME("(%p,%d,%s,%p), stub!\n", iface, index, debugstr_guid(guid), pVarVal); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetDocumentation2 {OLEAUT32} - * - * Gets some documentation from a TypeInfo in a locale-aware fashion. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of STG_E_INSUFFICIENTMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2( - ITypeInfo2* iface, /* [I] The TypeInfo to retrieve the documentation from. */ - MEMBERID memid, /* [I] The member id (why?). */ - LCID lcid, /* [I] The locale (why?). */ - BSTR* pbstrHelpString, /* [O] The help string. */ - DWORD* pdwHelpStringContext, /* [O] The help string context. */ - BSTR* pbstrHelpStringDll) /* [O] The help file name. */ -{ - FIXME("(%p,%ld,%ld,%p,%p,%p), stub!\n", iface, memid, lcid, pbstrHelpString, pdwHelpStringContext, pbstrHelpStringDll); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetAllCustData {OLEAUT32} - * - * Gets all of the custom data associated with a TypeInfo. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ITypeInfo2_fnGetAllCustData( - ITypeInfo2* iface, /* [I] The TypeInfo in which to find the custom data. */ - CUSTDATA* pCustData) /* [O] A pointer to the custom data. */ -{ - FIXME("(%p,%p), stub!\n", iface, pCustData); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetAllFuncCustData {OLEAUT32} - * - * Gets all of the custom data associated with a function. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData( - ITypeInfo2* iface, /* [I] The TypeInfo in which to find the custom data. */ - UINT index, /* [I] The index of the function for which to retrieve the custom data. */ - CUSTDATA* pCustData) /* [O] A pointer to the custom data. */ -{ - FIXME("(%p,%d,%p), stub!\n", iface, index, pCustData); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetAllParamCustData {OLEAUT32} - * - * Gets all of the custom data associated with a parameter. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( - ITypeInfo2* iface, /* [I] The TypeInfo in which to find the custom data. */ - UINT indexFunc, /* [I] The index of the function for which to retrieve the custom data. */ - UINT indexParam, /* [I] The index of the parameter for which to retrieve the custom data. */ - CUSTDATA* pCustData) /* [O] A pointer to the custom data. */ -{ - FIXME("(%p,%d,%d,%p), stub!\n", iface, indexFunc, indexParam, pCustData); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetAllVarCustData {OLEAUT32} - * - * Gets all of the custom data associated with a variable. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( - ITypeInfo2* iface, /* [I] The TypeInfo in which to find the custom data. */ - UINT index, /* [I] The index of the variable for which to retrieve the custom data. */ - CUSTDATA* pCustData) /* [O] A pointer to the custom data. */ -{ - FIXME("(%p,%d,%p), stub!\n", iface, index, pCustData); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeInfo2_GetAllImplTypeCustData {OLEAUT32} - * - * Gets all of the custom data associated with an implemented type. - * - * RETURNS - * - * Success: S_OK. - * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData( - ITypeInfo2* iface, /* [I] The TypeInfo in which to find the custom data. */ - UINT index, /* [I] The index of the implemented type for which to retrieve the custom data. */ - CUSTDATA* pCustData) /* [O] A pointer to the custom data. */ -{ - FIXME("(%p,%d,%p), stub!\n", iface, index, pCustData); - return E_OUTOFMEMORY; -} - - -/*================== ICreateTypeInfo2 & ITypeInfo2 VTABLEs And Creation ===================================*/ - -static ICreateTypeInfo2Vtbl ctypeinfo2vt = -{ - - ICreateTypeInfo2_fnQueryInterface, - ICreateTypeInfo2_fnAddRef, - ICreateTypeInfo2_fnRelease, - - ICreateTypeInfo2_fnSetGuid, - ICreateTypeInfo2_fnSetTypeFlags, - ICreateTypeInfo2_fnSetDocString, - ICreateTypeInfo2_fnSetHelpContext, - ICreateTypeInfo2_fnSetVersion, - ICreateTypeInfo2_fnAddRefTypeInfo, - ICreateTypeInfo2_fnAddFuncDesc, - ICreateTypeInfo2_fnAddImplType, - ICreateTypeInfo2_fnSetImplTypeFlags, - ICreateTypeInfo2_fnSetAlignment, - ICreateTypeInfo2_fnSetSchema, - ICreateTypeInfo2_fnAddVarDesc, - ICreateTypeInfo2_fnSetFuncAndParamNames, - ICreateTypeInfo2_fnSetVarName, - ICreateTypeInfo2_fnSetTypeDescAlias, - ICreateTypeInfo2_fnDefineFuncAsDllEntry, - ICreateTypeInfo2_fnSetFuncDocString, - ICreateTypeInfo2_fnSetVarDocString, - ICreateTypeInfo2_fnSetFuncHelpContext, - ICreateTypeInfo2_fnSetVarHelpContext, - ICreateTypeInfo2_fnSetMops, - ICreateTypeInfo2_fnSetTypeIdldesc, - ICreateTypeInfo2_fnLayOut, - - ICreateTypeInfo2_fnDeleteFuncDesc, - ICreateTypeInfo2_fnDeleteFuncDescByMemId, - ICreateTypeInfo2_fnDeleteVarDesc, - ICreateTypeInfo2_fnDeleteVarDescByMemId, - ICreateTypeInfo2_fnDeleteImplType, - ICreateTypeInfo2_fnSetCustData, - ICreateTypeInfo2_fnSetFuncCustData, - ICreateTypeInfo2_fnSetParamCustData, - ICreateTypeInfo2_fnSetVarCustData, - ICreateTypeInfo2_fnSetImplTypeCustData, - ICreateTypeInfo2_fnSetHelpStringContext, - ICreateTypeInfo2_fnSetFuncHelpStringContext, - ICreateTypeInfo2_fnSetVarHelpStringContext, - ICreateTypeInfo2_fnInvalidate, - ICreateTypeInfo2_fnSetName -}; - -static ITypeInfo2Vtbl typeinfo2vt = -{ - - ITypeInfo2_fnQueryInterface, - ITypeInfo2_fnAddRef, - ITypeInfo2_fnRelease, - - ITypeInfo2_fnGetTypeAttr, - ITypeInfo2_fnGetTypeComp, - ITypeInfo2_fnGetFuncDesc, - ITypeInfo2_fnGetVarDesc, - ITypeInfo2_fnGetNames, - ITypeInfo2_fnGetRefTypeOfImplType, - ITypeInfo2_fnGetImplTypeFlags, - ITypeInfo2_fnGetIDsOfNames, - ITypeInfo2_fnInvoke, - ITypeInfo2_fnGetDocumentation, - ITypeInfo2_fnGetDllEntry, - ITypeInfo2_fnGetRefTypeInfo, - ITypeInfo2_fnAddressOfMember, - ITypeInfo2_fnCreateInstance, - ITypeInfo2_fnGetMops, - ITypeInfo2_fnGetContainingTypeLib, - ITypeInfo2_fnReleaseTypeAttr, - ITypeInfo2_fnReleaseFuncDesc, - ITypeInfo2_fnReleaseVarDesc, - - ITypeInfo2_fnGetTypeKind, - ITypeInfo2_fnGetTypeFlags, - ITypeInfo2_fnGetFuncIndexOfMemId, - ITypeInfo2_fnGetVarIndexOfMemId, - ITypeInfo2_fnGetCustData, - ITypeInfo2_fnGetFuncCustData, - ITypeInfo2_fnGetParamCustData, - ITypeInfo2_fnGetVarCustData, - ITypeInfo2_fnGetImplTypeCustData, - ITypeInfo2_fnGetDocumentation2, - ITypeInfo2_fnGetAllCustData, - ITypeInfo2_fnGetAllFuncCustData, - ITypeInfo2_fnGetAllParamCustData, - ITypeInfo2_fnGetAllVarCustData, - ITypeInfo2_fnGetAllImplTypeCustData, -}; - -static ICreateTypeInfo2 *ICreateTypeInfo2_Constructor(ICreateTypeLib2Impl *typelib, WCHAR *szName, TYPEKIND tkind) -{ - ICreateTypeInfo2Impl *pCreateTypeInfo2Impl; - - int nameoffset; - int typeinfo_offset; - MSFT_TypeInfoBase *typeinfo; - - TRACE("Constructing ICreateTypeInfo2 for %s with tkind %d\n", debugstr_w(szName), tkind); - - pCreateTypeInfo2Impl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ICreateTypeInfo2Impl)); - if (!pCreateTypeInfo2Impl) return NULL; - - pCreateTypeInfo2Impl->lpVtbl = &ctypeinfo2vt; - pCreateTypeInfo2Impl->lpVtblTypeInfo2 = &typeinfo2vt; - pCreateTypeInfo2Impl->ref = 1; - - pCreateTypeInfo2Impl->typelib = typelib; - typelib->ref++; - - nameoffset = ctl2_alloc_name(typelib, szName); - typeinfo_offset = ctl2_alloc_typeinfo(typelib, nameoffset); - typeinfo = (MSFT_TypeInfoBase *)&typelib->typelib_segment_data[MSFT_SEG_TYPEINFO][typeinfo_offset]; - - typelib->typelib_segment_data[MSFT_SEG_NAME][nameoffset + 9] = 0x38; - *((int *)&typelib->typelib_segment_data[MSFT_SEG_NAME][nameoffset]) = typeinfo_offset; - - pCreateTypeInfo2Impl->typeinfo = typeinfo; - - typeinfo->typekind |= tkind | 0x20; - ICreateTypeInfo2_SetAlignment((ICreateTypeInfo2 *)pCreateTypeInfo2Impl, 4); - - switch (tkind) { - case TKIND_ENUM: - case TKIND_INTERFACE: - case TKIND_DISPATCH: - case TKIND_COCLASS: - typeinfo->size = 4; - break; - - case TKIND_RECORD: - case TKIND_UNION: - typeinfo->size = 0; - break; - - case TKIND_MODULE: - typeinfo->size = 2; - break; - - case TKIND_ALIAS: - typeinfo->size = -0x75; - break; - - default: - FIXME("(%s,%d), unrecognized typekind %d\n", debugstr_w(szName), tkind, tkind); - typeinfo->size = 0xdeadbeef; - break; - } - - if (typelib->last_typeinfo) typelib->last_typeinfo->next_typeinfo = pCreateTypeInfo2Impl; - typelib->last_typeinfo = pCreateTypeInfo2Impl; - if (!typelib->typeinfos) typelib->typeinfos = pCreateTypeInfo2Impl; - - TRACE(" -- %p\n", pCreateTypeInfo2Impl); - - return (ICreateTypeInfo2 *)pCreateTypeInfo2Impl; -} - - -/*================== ICreateTypeLib2 Implementation ===================================*/ - -/****************************************************************************** - * ICreateTypeLib2_QueryInterface {OLEAUT32} - * - * See IUnknown_QueryInterface. - */ -static HRESULT WINAPI ICreateTypeLib2_fnQueryInterface( - ICreateTypeLib2 * iface, - REFIID riid, - VOID **ppvObject) -{ - ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; - - TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid)); - - *ppvObject=NULL; - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid,&IID_ICreateTypeLib)|| - IsEqualIID(riid,&IID_ICreateTypeLib2)) - { - *ppvObject = This; - } else if (IsEqualIID(riid, &IID_ITypeLib) || - IsEqualIID(riid, &IID_ITypeLib2)) { - *ppvObject = &This->lpVtblTypeLib2; - } - - if(*ppvObject) - { - ICreateTypeLib2_AddRef(iface); - TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject); - return S_OK; - } - TRACE("-- Interface: E_NOINTERFACE\n"); - return E_NOINTERFACE; -} - -/****************************************************************************** - * ICreateTypeLib2_AddRef {OLEAUT32} - * - * See IUnknown_AddRef. - */ -static ULONG WINAPI ICreateTypeLib2_fnAddRef(ICreateTypeLib2 *iface) -{ - ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; - ULONG ref = InterlockedIncrement(&This->ref); - - TRACE("(%p)->ref was %lu\n",This, ref - 1); - - return ref; -} - -/****************************************************************************** - * ICreateTypeLib2_Release {OLEAUT32} - * - * See IUnknown_Release. - */ -static ULONG WINAPI ICreateTypeLib2_fnRelease(ICreateTypeLib2 *iface) -{ - ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; - ULONG ref = InterlockedDecrement(&This->ref); - - TRACE("(%p)->(%lu)\n",This, ref); - - if (!ref) { - int i; - - for (i = 0; i < MSFT_SEG_MAX; i++) { - HeapFree(GetProcessHeap(), 0, This->typelib_segment_data[i]); - This->typelib_segment_data[i] = NULL; - } - - HeapFree(GetProcessHeap(), 0, This->filename); - This->filename = NULL; - - while (This->typeinfos) { - ICreateTypeInfo2Impl *typeinfo = This->typeinfos; - This->typeinfos = typeinfo->next_typeinfo; - HeapFree(GetProcessHeap(), 0, typeinfo->typedata); - HeapFree(GetProcessHeap(), 0, typeinfo); - } - - HeapFree(GetProcessHeap(),0,This); - return 0; - } - - return ref; -} - - -/****************************************************************************** - * ICreateTypeLib2_CreateTypeInfo {OLEAUT32} - * - * See ICreateTypeLib_CreateTypeInfo. - */ -static HRESULT WINAPI ICreateTypeLib2_fnCreateTypeInfo( - ICreateTypeLib2 * iface, - LPOLESTR szName, - TYPEKIND tkind, - ICreateTypeInfo **ppCTInfo) -{ - ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; - - TRACE("(%p,%s,%d,%p)\n", iface, debugstr_w(szName), tkind, ppCTInfo); - - *ppCTInfo = (ICreateTypeInfo *)ICreateTypeInfo2_Constructor(This, szName, tkind); - - if (!*ppCTInfo) return E_OUTOFMEMORY; - - return S_OK; -} - -/****************************************************************************** - * ICreateTypeLib2_SetName {OLEAUT32} - * - * See ICreateTypeLib_SetName. - */ -static HRESULT WINAPI ICreateTypeLib2_fnSetName( - ICreateTypeLib2 * iface, - LPOLESTR szName) -{ - ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; - - int offset; - - TRACE("(%p,%s)\n", iface, debugstr_w(szName)); - - offset = ctl2_alloc_name(This, szName); - if (offset == -1) return E_OUTOFMEMORY; - This->typelib_header.NameOffset = offset; - return S_OK; -} - -/****************************************************************************** - * ICreateTypeLib2_SetVersion {OLEAUT32} - * - * See ICreateTypeLib_SetVersion. - */ -static HRESULT WINAPI ICreateTypeLib2_fnSetVersion(ICreateTypeLib2 * iface, WORD wMajorVerNum, WORD wMinorVerNum) -{ - ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; - - TRACE("(%p,%d,%d)\n", iface, wMajorVerNum, wMinorVerNum); - - This->typelib_header.version = wMajorVerNum | (wMinorVerNum << 16); - return S_OK; -} - -/****************************************************************************** - * ICreateTypeLib2_SetGuid {OLEAUT32} - * - * See ICreateTypeLib_SetGuid. - */ -static HRESULT WINAPI ICreateTypeLib2_fnSetGuid(ICreateTypeLib2 * iface, REFGUID guid) -{ - ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; - - MSFT_GuidEntry guidentry; - int offset; - - TRACE("(%p,%s)\n", iface, debugstr_guid(guid)); - - guidentry.guid = *guid; - guidentry.hreftype = -2; - guidentry.next_hash = -1; - - offset = ctl2_alloc_guid(This, &guidentry); - - if (offset == -1) return E_OUTOFMEMORY; - - This->typelib_header.posguid = offset; - - return S_OK; -} - -/****************************************************************************** - * ICreateTypeLib2_SetDocString {OLEAUT32} - * - * See ICreateTypeLib_SetDocString. - */ -static HRESULT WINAPI ICreateTypeLib2_fnSetDocString(ICreateTypeLib2 * iface, LPOLESTR szDoc) -{ - ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; - - int offset; - - TRACE("(%p,%s)\n", iface, debugstr_w(szDoc)); - - offset = ctl2_alloc_string(This, szDoc); - if (offset == -1) return E_OUTOFMEMORY; - This->typelib_header.helpstring = offset; - return S_OK; -} - -/****************************************************************************** - * ICreateTypeLib2_SetHelpFileName {OLEAUT32} - * - * See ICreateTypeLib_SetHelpFileName. - */ -static HRESULT WINAPI ICreateTypeLib2_fnSetHelpFileName(ICreateTypeLib2 * iface, LPOLESTR szHelpFileName) -{ - ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; - - int offset; - - TRACE("(%p,%s)\n", iface, debugstr_w(szHelpFileName)); - - offset = ctl2_alloc_string(This, szHelpFileName); - if (offset == -1) return E_OUTOFMEMORY; - This->typelib_header.helpfile = offset; - This->typelib_header.varflags |= 0x10; - return S_OK; -} - -/****************************************************************************** - * ICreateTypeLib2_SetHelpContext {OLEAUT32} - * - * See ICreateTypeLib_SetHelpContext. - */ -static HRESULT WINAPI ICreateTypeLib2_fnSetHelpContext(ICreateTypeLib2 * iface, DWORD dwHelpContext) -{ - FIXME("(%p,%ld), stub!\n", iface, dwHelpContext); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeLib2_SetLcid {OLEAUT32} - * - * See ICreateTypeLib_SetLcid. - */ -static HRESULT WINAPI ICreateTypeLib2_fnSetLcid(ICreateTypeLib2 * iface, LCID lcid) -{ - ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; - - TRACE("(%p,%ld)\n", iface, lcid); - - This->typelib_header.lcid2 = lcid; - - return S_OK; -} - -/****************************************************************************** - * ICreateTypeLib2_SetLibFlags {OLEAUT32} - * - * See ICreateTypeLib_SetLibFlags. - */ -static HRESULT WINAPI ICreateTypeLib2_fnSetLibFlags(ICreateTypeLib2 * iface, UINT uLibFlags) -{ - ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; - - TRACE("(%p,0x%x)\n", iface, uLibFlags); - - This->typelib_header.flags = uLibFlags; - - return S_OK; -} - -static int ctl2_write_chunk(HANDLE hFile, void *segment, int length) -{ - DWORD dwWritten; - if (!WriteFile(hFile, segment, length, &dwWritten, 0)) { - CloseHandle(hFile); - return 0; - } - return -1; -} - -static int ctl2_write_segment(ICreateTypeLib2Impl *This, HANDLE hFile, int segment) -{ - DWORD dwWritten; - if (!WriteFile(hFile, This->typelib_segment_data[segment], - This->typelib_segdir[segment].length, &dwWritten, 0)) { - CloseHandle(hFile); - return 0; - } - - return -1; -} - -static void ctl2_finalize_typeinfos(ICreateTypeLib2Impl *This, int filesize) -{ - ICreateTypeInfo2Impl *typeinfo; - - for (typeinfo = This->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) { - typeinfo->typeinfo->memoffset = filesize; - if (typeinfo->typedata) { - ICreateTypeInfo2_fnLayOut((ICreateTypeInfo2 *)typeinfo); - filesize += typeinfo->typedata[0] + ((typeinfo->typeinfo->cElement >> 16) * 12) + ((typeinfo->typeinfo->cElement & 0xffff) * 12) + 4; - } - } -} - -static int ctl2_finalize_segment(ICreateTypeLib2Impl *This, int filepos, int segment) -{ - if (This->typelib_segdir[segment].length) { - This->typelib_segdir[segment].offset = filepos; - } else { - This->typelib_segdir[segment].offset = -1; - } - - return This->typelib_segdir[segment].length; -} - -static void ctl2_write_typeinfos(ICreateTypeLib2Impl *This, HANDLE hFile) -{ - ICreateTypeInfo2Impl *typeinfo; - - for (typeinfo = This->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) { - if (!typeinfo->typedata) continue; - - ctl2_write_chunk(hFile, typeinfo->typedata, typeinfo->typedata[0] + 4); - ctl2_write_chunk(hFile, typeinfo->indices, ((typeinfo->typeinfo->cElement & 0xffff) + (typeinfo->typeinfo->cElement >> 16)) * 4); - ctl2_write_chunk(hFile, typeinfo->names, ((typeinfo->typeinfo->cElement & 0xffff) + (typeinfo->typeinfo->cElement >> 16)) * 4); - ctl2_write_chunk(hFile, typeinfo->offsets, ((typeinfo->typeinfo->cElement & 0xffff) + (typeinfo->typeinfo->cElement >> 16)) * 4); - } -} - -/****************************************************************************** - * ICreateTypeLib2_SaveAllChanges {OLEAUT32} - * - * See ICreateTypeLib_SaveAllChanges. - */ -static HRESULT WINAPI ICreateTypeLib2_fnSaveAllChanges(ICreateTypeLib2 * iface) -{ - ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; - - int retval; - int filepos; - HANDLE hFile; - - TRACE("(%p)\n", iface); - - retval = TYPE_E_IOERROR; - - hFile = CreateFileW(This->filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - if (hFile == INVALID_HANDLE_VALUE) return retval; - - filepos = sizeof(MSFT_Header) + sizeof(MSFT_SegDir); - filepos += This->typelib_header.nrtypeinfos * 4; - - filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_TYPEINFO); - filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_GUIDHASH); - filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_GUID); - filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_IMPORTINFO); - filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_IMPORTFILES); - filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_REFERENCES); - filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_NAMEHASH); - filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_NAME); - filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_STRING); - filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_TYPEDESC); - filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_ARRAYDESC); - filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_CUSTDATA); - filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_CUSTDATAGUID); - - ctl2_finalize_typeinfos(This, filepos); - - if (!ctl2_write_chunk(hFile, &This->typelib_header, sizeof(This->typelib_header))) return retval; - if (!ctl2_write_chunk(hFile, This->typelib_typeinfo_offsets, This->typelib_header.nrtypeinfos * 4)) return retval; - if (!ctl2_write_chunk(hFile, &This->typelib_segdir, sizeof(This->typelib_segdir))) return retval; - if (!ctl2_write_segment(This, hFile, MSFT_SEG_TYPEINFO )) return retval; - if (!ctl2_write_segment(This, hFile, MSFT_SEG_GUIDHASH )) return retval; - if (!ctl2_write_segment(This, hFile, MSFT_SEG_GUID )) return retval; - if (!ctl2_write_segment(This, hFile, MSFT_SEG_IMPORTINFO )) return retval; - if (!ctl2_write_segment(This, hFile, MSFT_SEG_IMPORTFILES )) return retval; - if (!ctl2_write_segment(This, hFile, MSFT_SEG_REFERENCES )) return retval; - if (!ctl2_write_segment(This, hFile, MSFT_SEG_NAMEHASH )) return retval; - if (!ctl2_write_segment(This, hFile, MSFT_SEG_NAME )) return retval; - if (!ctl2_write_segment(This, hFile, MSFT_SEG_STRING )) return retval; - if (!ctl2_write_segment(This, hFile, MSFT_SEG_TYPEDESC )) return retval; - if (!ctl2_write_segment(This, hFile, MSFT_SEG_ARRAYDESC )) return retval; - if (!ctl2_write_segment(This, hFile, MSFT_SEG_CUSTDATA )) return retval; - if (!ctl2_write_segment(This, hFile, MSFT_SEG_CUSTDATAGUID)) return retval; - - ctl2_write_typeinfos(This, hFile); - - if (!CloseHandle(hFile)) return retval; - - retval = S_OK; - return retval; -} - - -/****************************************************************************** - * ICreateTypeLib2_DeleteTypeInfo {OLEAUT32} - * - * Deletes a named TypeInfo from a type library. - * - * RETURNS - * - * Success: S_OK - * Failure: E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ICreateTypeLib2_fnDeleteTypeInfo( - ICreateTypeLib2 * iface, /* [I] The type library to delete from. */ - LPOLESTR szName) /* [I] The name of the typeinfo to delete. */ -{ - FIXME("(%p,%s), stub!\n", iface, debugstr_w(szName)); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeLib2_SetCustData {OLEAUT32} - * - * Sets custom data for a type library. - * - * RETURNS - * - * Success: S_OK - * Failure: E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ICreateTypeLib2_fnSetCustData( - ICreateTypeLib2 * iface, /* [I] The type library to store the custom data in. */ - REFGUID guid, /* [I] The GUID used as a key to retrieve the custom data. */ - VARIANT *pVarVal) /* [I] The custom data itself. */ -{ - ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; - - TRACE("(%p,%s,%p)\n", iface, debugstr_guid(guid), pVarVal); - - return ctl2_set_custdata(This, guid, pVarVal, &This->typelib_header.CustomDataOffset); -} - -/****************************************************************************** - * ICreateTypeLib2_SetHelpStringContext {OLEAUT32} - * - * Sets a context number for the library help string. - * - * RETURNS - * - * Success: S_OK - * Failure: E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ICreateTypeLib2_fnSetHelpStringContext( - ICreateTypeLib2 * iface, /* [I] The type library to set the help string context for. */ - ULONG dwHelpStringContext) /* [I] The help string context. */ -{ - FIXME("(%p,%ld), stub!\n", iface, dwHelpStringContext); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeLib2_SetHelpStringDll {OLEAUT32} - * - * Sets the DLL used to look up localized help strings. - * - * RETURNS - * - * Success: S_OK - * Failure: E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ICreateTypeLib2_fnSetHelpStringDll( - ICreateTypeLib2 * iface, /* [I] The type library to set the help DLL for. */ - LPOLESTR szFileName) /* [I] The name of the help DLL. */ -{ - FIXME("(%p,%s), stub!\n", iface, debugstr_w(szFileName)); - return E_OUTOFMEMORY; -} - -/*================== ITypeLib2 Implementation ===================================*/ - -/****************************************************************************** - * ITypeLib2_QueryInterface {OLEAUT32} - * - * See IUnknown_QueryInterface. - */ -static HRESULT WINAPI ITypeLib2_fnQueryInterface(ITypeLib2 * iface, REFIID riid, LPVOID * ppv) -{ - ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); - - return ICreateTypeLib2_QueryInterface((ICreateTypeLib2 *)This, riid, ppv); -} - -/****************************************************************************** - * ITypeLib2_AddRef {OLEAUT32} - * - * See IUnknown_AddRef. - */ -static ULONG WINAPI ITypeLib2_fnAddRef(ITypeLib2 * iface) -{ - ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); - - return ICreateTypeLib2_AddRef((ICreateTypeLib2 *)This); -} - -/****************************************************************************** - * ITypeLib2_Release {OLEAUT32} - * - * See IUnknown_Release. - */ -static ULONG WINAPI ITypeLib2_fnRelease(ITypeLib2 * iface) -{ - ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); - - return ICreateTypeLib2_Release((ICreateTypeLib2 *)This); -} - -/****************************************************************************** - * ITypeLib2_GetTypeInfoCount {OLEAUT32} - * - * See ITypeLib_GetTypeInfoCount. - */ -static UINT WINAPI ITypeLib2_fnGetTypeInfoCount( - ITypeLib2 * iface) -{ - ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); - - TRACE("(%p)\n", iface); - - return This->typelib_header.nrtypeinfos; -} - -/****************************************************************************** - * ITypeLib2_GetTypeInfo {OLEAUT32} - * - * See ITypeLib_GetTypeInfo. - */ -static HRESULT WINAPI ITypeLib2_fnGetTypeInfo( - ITypeLib2 * iface, - UINT index, - ITypeInfo** ppTInfo) -{ - ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); - - TRACE("(%p,%d,%p)\n", iface, index, ppTInfo); - - if ((index < 0) || (index >= This->typelib_header.nrtypeinfos)) { - return TYPE_E_ELEMENTNOTFOUND; - } - - return ctl2_find_typeinfo_from_offset(This, This->typelib_typeinfo_offsets[index], ppTInfo); -} - -/****************************************************************************** - * ITypeLib2_GetTypeInfoType {OLEAUT32} - * - * See ITypeLib_GetTypeInfoType. - */ -static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType( - ITypeLib2 * iface, - UINT index, - TYPEKIND* pTKind) -{ - ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); - - TRACE("(%p,%d,%p)\n", iface, index, pTKind); - - if ((index < 0) || (index >= This->typelib_header.nrtypeinfos)) { - return TYPE_E_ELEMENTNOTFOUND; - } - - *pTKind = (This->typelib_segment_data[MSFT_SEG_TYPEINFO][This->typelib_typeinfo_offsets[index]]) & 15; - - return S_OK; -} - -/****************************************************************************** - * ITypeLib2_GetTypeInfoOfGuid {OLEAUT32} - * - * See ITypeLib_GetTypeInfoOfGuid. - */ -static HRESULT WINAPI ITypeLib2_fnGetTypeInfoOfGuid( - ITypeLib2 * iface, - REFGUID guid, - ITypeInfo** ppTinfo) -{ - ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); - - int guidoffset; - int typeinfo; - - TRACE("(%p,%s,%p)\n", iface, debugstr_guid(guid), ppTinfo); - - guidoffset = ctl2_find_guid(This, ctl2_hash_guid(guid), guid); - if (guidoffset == -1) return TYPE_E_ELEMENTNOTFOUND; - - typeinfo = ((MSFT_GuidEntry *)&This->typelib_segment_data[MSFT_SEG_GUID][guidoffset])->hreftype; - if (typeinfo < 0) return TYPE_E_ELEMENTNOTFOUND; - - return ctl2_find_typeinfo_from_offset(This, typeinfo, ppTinfo); -} - -/****************************************************************************** - * ITypeLib2_GetLibAttr {OLEAUT32} - * - * See ITypeLib_GetLibAttr. - */ -static HRESULT WINAPI ITypeLib2_fnGetLibAttr( - ITypeLib2 * iface, - TLIBATTR** ppTLibAttr) -{ -/* ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); */ - - FIXME("(%p,%p), stub!\n", iface, ppTLibAttr); - - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeLib2_GetTypeComp {OLEAUT32} - * - * See ITypeLib_GetTypeComp. - */ -static HRESULT WINAPI ITypeLib2_fnGetTypeComp( - ITypeLib2 * iface, - ITypeComp** ppTComp) -{ -/* ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); */ - - FIXME("(%p,%p), stub!\n", iface, ppTComp); - - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeLib2_GetDocumentation {OLEAUT32} - * - * See ITypeLib_GetDocumentation. - */ -static HRESULT WINAPI ITypeLib2_fnGetDocumentation( - ITypeLib2 * iface, - INT index, - BSTR* pBstrName, - BSTR* pBstrDocString, - DWORD* pdwHelpContext, - BSTR* pBstrHelpFile) -{ -/* ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); */ - - FIXME("(%p,%d,%p,%p,%p,%p), stub!\n", iface, index, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile); - - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeLib2_IsName {OLEAUT32} - * - * See ITypeLib_IsName. - */ -static HRESULT WINAPI ITypeLib2_fnIsName( - ITypeLib2 * iface, - LPOLESTR szNameBuf, - ULONG lHashVal, - BOOL* pfName) -{ - ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); - - char *encoded_name; - int nameoffset; - MSFT_NameIntro *nameintro; - - TRACE("(%p,%s,%lx,%p)\n", iface, debugstr_w(szNameBuf), lHashVal, pfName); - - ctl2_encode_name(This, szNameBuf, &encoded_name); - nameoffset = ctl2_find_name(This, encoded_name); - - *pfName = 0; - - if (nameoffset == -1) return S_OK; - - nameintro = (MSFT_NameIntro *)(&This->typelib_segment_data[MSFT_SEG_NAME][nameoffset]); - if (nameintro->hreftype == -1) return S_OK; - - *pfName = 1; - - FIXME("Should be decoding our copy of the name over szNameBuf.\n"); - - return S_OK; -} - -/****************************************************************************** - * ITypeLib2_FindName {OLEAUT32} - * - * See ITypeLib_FindName. - */ -static HRESULT WINAPI ITypeLib2_fnFindName( - ITypeLib2 * iface, - LPOLESTR szNameBuf, - ULONG lHashVal, - ITypeInfo** ppTInfo, - MEMBERID* rgMemId, - USHORT* pcFound) -{ -/* ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); */ - - FIXME("(%p,%s,%lx,%p,%p,%p), stub!\n", iface, debugstr_w(szNameBuf), lHashVal, ppTInfo, rgMemId, pcFound); - - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ITypeLib2_ReleaseTLibAttr {OLEAUT32} - * - * See ITypeLib_ReleaseTLibAttr. - */ -static void WINAPI ITypeLib2_fnReleaseTLibAttr( - ITypeLib2 * iface, - TLIBATTR* pTLibAttr) -{ -/* ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); */ - - FIXME("(%p,%p), stub!\n", iface, pTLibAttr); -} - -/****************************************************************************** - * ICreateTypeLib2_GetCustData {OLEAUT32} - * - * Retrieves a custom data value stored on a type library. - * - * RETURNS - * - * Success: S_OK - * Failure: E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ITypeLib2_fnGetCustData( - ITypeLib2 * iface, /* [I] The type library in which to find the custom data. */ - REFGUID guid, /* [I] The GUID under which the custom data is stored. */ - VARIANT* pVarVal) /* [O] The custom data. */ -{ -/* ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); */ - - FIXME("(%p,%s,%p), stub!\n", iface, debugstr_guid(guid), pVarVal); - - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeLib2_GetLibStatistics {OLEAUT32} - * - * Retrieves some statistics about names in a type library, supposedly for - * hash table optimization purposes. - * - * RETURNS - * - * Success: S_OK - * Failure: E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ITypeLib2_fnGetLibStatistics( - ITypeLib2 * iface, /* [I] The type library to get statistics about. */ - ULONG* pcUniqueNames, /* [O] The number of unique names in the type library. */ - ULONG* pcchUniqueNames) /* [O] The number of changed (?) characters in names in the type library. */ -{ -/* ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); */ - - FIXME("(%p,%p,%p), stub!\n", iface, pcUniqueNames, pcchUniqueNames); - - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeLib2_GetDocumentation2 {OLEAUT32} - * - * Obtain locale-aware help string information. - * - * RETURNS - * - * Success: S_OK - * Failure: STG_E_INSUFFICIENTMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ITypeLib2_fnGetDocumentation2( - ITypeLib2 * iface, - INT index, - LCID lcid, - BSTR* pbstrHelpString, - DWORD* pdwHelpStringContext, - BSTR* pbstrHelpStringDll) -{ -/* ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); */ - - FIXME("(%p,%d,%ld,%p,%p,%p), stub!\n", iface, index, lcid, pbstrHelpString, pdwHelpStringContext, pbstrHelpStringDll); - - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * ICreateTypeLib2_GetAllCustData {OLEAUT32} - * - * Retrieve all of the custom data for a type library. - * - * RETURNS - * - * Success: S_OK - * Failure: E_OUTOFMEMORY or E_INVALIDARG. - */ -static HRESULT WINAPI ITypeLib2_fnGetAllCustData( - ITypeLib2 * iface, /* [I] The type library in which to find the custom data. */ - CUSTDATA* pCustData) /* [O] The structure in which to place the custom data. */ -{ -/* ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); */ - - FIXME("(%p,%p), stub!\n", iface, pCustData); - - return E_OUTOFMEMORY; -} - - -/*================== ICreateTypeLib2 & ITypeLib2 VTABLEs And Creation ===================================*/ - -static ICreateTypeLib2Vtbl ctypelib2vt = -{ - - ICreateTypeLib2_fnQueryInterface, - ICreateTypeLib2_fnAddRef, - ICreateTypeLib2_fnRelease, - - ICreateTypeLib2_fnCreateTypeInfo, - ICreateTypeLib2_fnSetName, - ICreateTypeLib2_fnSetVersion, - ICreateTypeLib2_fnSetGuid, - ICreateTypeLib2_fnSetDocString, - ICreateTypeLib2_fnSetHelpFileName, - ICreateTypeLib2_fnSetHelpContext, - ICreateTypeLib2_fnSetLcid, - ICreateTypeLib2_fnSetLibFlags, - ICreateTypeLib2_fnSaveAllChanges, - - ICreateTypeLib2_fnDeleteTypeInfo, - ICreateTypeLib2_fnSetCustData, - ICreateTypeLib2_fnSetHelpStringContext, - ICreateTypeLib2_fnSetHelpStringDll -}; - -static ITypeLib2Vtbl typelib2vt = -{ - - ITypeLib2_fnQueryInterface, - ITypeLib2_fnAddRef, - ITypeLib2_fnRelease, - - ITypeLib2_fnGetTypeInfoCount, - ITypeLib2_fnGetTypeInfo, - ITypeLib2_fnGetTypeInfoType, - ITypeLib2_fnGetTypeInfoOfGuid, - ITypeLib2_fnGetLibAttr, - ITypeLib2_fnGetTypeComp, - ITypeLib2_fnGetDocumentation, - ITypeLib2_fnIsName, - ITypeLib2_fnFindName, - ITypeLib2_fnReleaseTLibAttr, - - ITypeLib2_fnGetCustData, - ITypeLib2_fnGetLibStatistics, - ITypeLib2_fnGetDocumentation2, - ITypeLib2_fnGetAllCustData, -}; - -static ICreateTypeLib2 *ICreateTypeLib2_Constructor(SYSKIND syskind, LPCOLESTR szFile) -{ - ICreateTypeLib2Impl *pCreateTypeLib2Impl; - int failed = 0; - - TRACE("Constructing ICreateTypeLib2 (%d, %s)\n", syskind, debugstr_w(szFile)); - - pCreateTypeLib2Impl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ICreateTypeLib2Impl)); - if (!pCreateTypeLib2Impl) return NULL; - - pCreateTypeLib2Impl->filename = HeapAlloc(GetProcessHeap(), 0, (strlenW(szFile) + 1) * sizeof(WCHAR)); - if (!pCreateTypeLib2Impl->filename) { - HeapFree(GetProcessHeap(), 0, pCreateTypeLib2Impl); - return NULL; - } - strcpyW(pCreateTypeLib2Impl->filename, szFile); - - ctl2_init_header(pCreateTypeLib2Impl); - ctl2_init_segdir(pCreateTypeLib2Impl); - - pCreateTypeLib2Impl->typelib_header.varflags |= syskind; - - /* - * The following two calls return an offset or -1 if out of memory. We - * specifically need an offset of 0, however, so... - */ - if (ctl2_alloc_segment(pCreateTypeLib2Impl, MSFT_SEG_GUIDHASH, 0x80, 0x80)) { failed = 1; } - if (ctl2_alloc_segment(pCreateTypeLib2Impl, MSFT_SEG_NAMEHASH, 0x200, 0x200)) { failed = 1; } - - pCreateTypeLib2Impl->typelib_guidhash_segment = (int *)pCreateTypeLib2Impl->typelib_segment_data[MSFT_SEG_GUIDHASH]; - pCreateTypeLib2Impl->typelib_namehash_segment = (int *)pCreateTypeLib2Impl->typelib_segment_data[MSFT_SEG_NAMEHASH]; - - memset(pCreateTypeLib2Impl->typelib_guidhash_segment, 0xff, 0x80); - memset(pCreateTypeLib2Impl->typelib_namehash_segment, 0xff, 0x200); - - pCreateTypeLib2Impl->lpVtbl = &ctypelib2vt; - pCreateTypeLib2Impl->lpVtblTypeLib2 = &typelib2vt; - pCreateTypeLib2Impl->ref = 1; - - if (failed) { - ICreateTypeLib2_fnRelease((ICreateTypeLib2 *)pCreateTypeLib2Impl); - return 0; - } - - return (ICreateTypeLib2 *)pCreateTypeLib2Impl; -} - -/****************************************************************************** - * CreateTypeLib2 [OLEAUT32.180] - * - * Obtains an ICreateTypeLib2 object for creating a new-style (MSFT) type - * library. - * - * NOTES - * - * See also CreateTypeLib. - * - * RETURNS - * Success: S_OK - * Failure: Status - */ -HRESULT WINAPI CreateTypeLib2( - SYSKIND syskind, /* [I] System type library is for */ - LPCOLESTR szFile, /* [I] Type library file name */ - ICreateTypeLib2** ppctlib) /* [O] Storage for object returned */ -{ - TRACE("(%d,%s,%p)\n", syskind, debugstr_w(szFile), ppctlib); - - if (!szFile) return E_INVALIDARG; - *ppctlib = ICreateTypeLib2_Constructor(syskind, szFile); - return (*ppctlib)? S_OK: E_OUTOFMEMORY; -} - -/****************************************************************************** - * ClearCustData (OLEAUT32.171) - * - * Clear a custom data types' data. - * - * PARAMS - * lpCust [I] The custom data type instance - * - * RETURNS - * Nothing. - */ -void WINAPI ClearCustData(LPCUSTDATA lpCust) -{ - if (lpCust && lpCust->cCustData) - { - if (lpCust->prgCustData) - { - DWORD i; - - for (i = 0; i < lpCust->cCustData; i++) - VariantClear(&lpCust->prgCustData[i].varValue); - - /* FIXME - Should be using a per-thread IMalloc */ - HeapFree(GetProcessHeap(), 0, lpCust->prgCustData); - lpCust->prgCustData = NULL; - } - lpCust->cCustData = 0; - } -} +/* + * TYPELIB2 + * + * Copyright 2004 Alastair Bridgewater + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * -------------------------------------------------------------------------------------- + * Known problems: + * + * Badly incomplete. + * + * Only works on little-endian systems. + * + */ + +#include "config.h" +#include "wine/port.h" + +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <stdio.h> +#include <ctype.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "winerror.h" +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winreg.h" +#include "winuser.h" + +#include "wine/unicode.h" +#include "objbase.h" +#include "typelib.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(typelib2); +/* WINE_DEFAULT_DEBUG_CHANNEL(ole); */ + + +/****************************************************************************** + * ICreateTypeLib2 {OLEAUT32} + * + * NOTES + * The ICreateTypeLib2 interface provides an interface whereby one may create + * new type library (.tlb) files. + * + * This interface inherits from ICreateTypeLib, and can be freely cast back + * and forth between an ICreateTypeLib and an ICreateTypeLib2 on local clients. + * This dispensation applies only to ICreateTypeLib objects obtained on MSFT + * format type libraries (those made through CreateTypeLib2). + * + * METHODS + */ + +/****************************************************************************** + * ICreateTypeInfo2 {OLEAUT32} + * + * NOTES + * The ICreateTypeInfo2 interface provides an interface whereby one may add + * type information to type library (.tlb) files. + * + * This interface inherits from ICreateTypeInfo, and can be freely cast back + * and forth between an ICreateTypeInfo and an ICreateTypeInfo2 on local clients. + * This dispensation applies only to ICreateTypeInfo objects obtained on MSFT + * format type libraries (those made through CreateTypeLib2). + * + * METHODS + */ + +/****************************************************************************** + * ITypeLib2 {OLEAUT32} + * + * NOTES + * The ITypeLib2 interface provides an interface whereby one may query MSFT + * format type library (.tlb) files. + * + * This interface inherits from ITypeLib, and can be freely cast back and + * forth between an ITypeLib and an ITypeLib2 on local clients. This + * dispensation applies only to ITypeLib objects obtained on MSFT format type + * libraries (those made through CreateTypeLib2). + * + * METHODS + */ + +/****************************************************************************** + * ITypeInfo2 {OLEAUT32} + * + * NOTES + * The ITypeInfo2 interface provides an interface whereby one may query type + * information stored in MSFT format type library (.tlb) files. + * + * This interface inherits from ITypeInfo, and can be freely cast back and + * forth between an ITypeInfo and an ITypeInfo2 on local clients. This + * dispensation applies only to ITypeInfo objects obtained on MSFT format type + * libraries (those made through CreateTypeLib2). + * + * METHODS + */ + +/*================== Implementation Structures ===================================*/ + +enum MSFT_segment_index { + MSFT_SEG_TYPEINFO = 0, /* type information */ + MSFT_SEG_IMPORTINFO, /* import information */ + MSFT_SEG_IMPORTFILES, /* import filenames */ + MSFT_SEG_REFERENCES, /* references (?) */ + MSFT_SEG_GUIDHASH, /* hash table for guids? */ + MSFT_SEG_GUID, /* guid storage */ + MSFT_SEG_NAMEHASH, /* hash table for names */ + MSFT_SEG_NAME, /* name storage */ + MSFT_SEG_STRING, /* string storage */ + MSFT_SEG_TYPEDESC, /* type descriptions */ + MSFT_SEG_ARRAYDESC, /* array descriptions */ + MSFT_SEG_CUSTDATA, /* custom data */ + MSFT_SEG_CUSTDATAGUID, /* custom data guids */ + MSFT_SEG_UNKNOWN, /* ??? */ + MSFT_SEG_UNKNOWN2, /* ??? */ + MSFT_SEG_MAX /* total number of segments */ +}; + +typedef struct tagMSFT_ImpFile { + int guid; + LCID lcid; + int version; + char filename[0]; /* preceded by two bytes of encoded (length << 2) + flags in the low two bits. */ +} MSFT_ImpFile; + +typedef struct tagICreateTypeLib2Impl +{ + ICreateTypeLib2Vtbl *lpVtbl; + ITypeLib2Vtbl *lpVtblTypeLib2; + + ULONG ref; + + WCHAR *filename; + + MSFT_Header typelib_header; + MSFT_pSeg typelib_segdir[MSFT_SEG_MAX]; + char *typelib_segment_data[MSFT_SEG_MAX]; + int typelib_segment_block_length[MSFT_SEG_MAX]; + + INT typelib_typeinfo_offsets[0x200]; /* Hope that's enough. */ + + INT *typelib_namehash_segment; + INT *typelib_guidhash_segment; + + struct tagICreateTypeInfo2Impl *typeinfos; + struct tagICreateTypeInfo2Impl *last_typeinfo; +} ICreateTypeLib2Impl; + +#define _ITypeLib2_Offset(impl) ((int)(&(((impl*)0)->lpVtblTypeLib2))) +#define ICOM_THIS_From_ITypeLib2(impl, iface) impl* This = (impl*)(((char*)iface)-_ITypeLib2_Offset(impl)) + +typedef struct tagICreateTypeInfo2Impl +{ + ICreateTypeInfo2Vtbl *lpVtbl; + ITypeInfo2Vtbl *lpVtblTypeInfo2; + + ULONG ref; + + ICreateTypeLib2Impl *typelib; + MSFT_TypeInfoBase *typeinfo; + + INT *typedata; + int typedata_allocated; + int typedata_length; + + int indices[42]; + int names[42]; + int offsets[42]; + + int datawidth; + + struct tagICreateTypeInfo2Impl *next_typeinfo; +} ICreateTypeInfo2Impl; + +#define _ITypeInfo2_Offset(impl) ((int)(&(((impl*)0)->lpVtblTypeInfo2))) +#define ICOM_THIS_From_ITypeInfo2(impl, iface) impl* This = (impl*)(((char*)iface)-_ITypeInfo2_Offset(impl)) + +static ULONG WINAPI ICreateTypeLib2_fnRelease(ICreateTypeLib2 *iface); + + +/*================== Internal functions ===================================*/ + +/**************************************************************************** + * ctl2_init_header + * + * Initializes the type library header of a new typelib. + */ +static void ctl2_init_header( + ICreateTypeLib2Impl *This) /* [I] The typelib to initialize. */ +{ + This->typelib_header.magic1 = 0x5446534d; + This->typelib_header.magic2 = 0x00010002; + This->typelib_header.posguid = -1; + This->typelib_header.lcid = 0x0409; /* or do we use the current one? */ + This->typelib_header.lcid2 = 0x0409; + This->typelib_header.varflags = 0x40; + This->typelib_header.version = 0; + This->typelib_header.flags = 0; + This->typelib_header.nrtypeinfos = 0; + This->typelib_header.helpstring = -1; + This->typelib_header.helpstringcontext = 0; + This->typelib_header.helpcontext = 0; + This->typelib_header.nametablecount = 0; + This->typelib_header.nametablechars = 0; + This->typelib_header.NameOffset = -1; + This->typelib_header.helpfile = -1; + This->typelib_header.CustomDataOffset = -1; + This->typelib_header.res44 = 0x20; + This->typelib_header.res48 = 0x80; + This->typelib_header.dispatchpos = -1; + This->typelib_header.res50 = 0; +} + +/**************************************************************************** + * ctl2_init_segdir + * + * Initializes the segment directory of a new typelib. + */ +static void ctl2_init_segdir( + ICreateTypeLib2Impl *This) /* [I] The typelib to initialize. */ +{ + int i; + MSFT_pSeg *segdir; + + segdir = &This->typelib_segdir[MSFT_SEG_TYPEINFO]; + + for (i = 0; i < 15; i++) { + segdir[i].offset = -1; + segdir[i].length = 0; + segdir[i].res08 = -1; + segdir[i].res0c = 0x0f; + } +} + +/**************************************************************************** + * ctl2_hash_guid + * + * Generates a hash key from a GUID. + * + * RETURNS + * + * The hash key for the GUID. + */ +static int ctl2_hash_guid( + REFGUID guid) /* [I] The guid to find. */ +{ + int hash; + int i; + + hash = 0; + for (i = 0; i < 8; i ++) { + hash ^= ((const short *)guid)[i]; + } + + return (hash & 0xf) | ((hash & 0x10) & (0 - !!(hash & 0xe0))); +} + +/**************************************************************************** + * ctl2_find_guid + * + * Locates a guid in a type library. + * + * RETURNS + * + * The offset into the GUID segment of the guid, or -1 if not found. + */ +static int ctl2_find_guid( + ICreateTypeLib2Impl *This, /* [I] The typelib to operate against. */ + int hash_key, /* [I] The hash key for the guid. */ + REFGUID guid) /* [I] The guid to find. */ +{ + int offset; + MSFT_GuidEntry *guidentry; + + offset = This->typelib_guidhash_segment[hash_key]; + while (offset != -1) { + guidentry = (MSFT_GuidEntry *)&This->typelib_segment_data[MSFT_SEG_GUID][offset]; + + if (!memcmp(guidentry, guid, sizeof(GUID))) return offset; + + offset = guidentry->next_hash; + } + + return offset; +} + +/**************************************************************************** + * ctl2_find_name + * + * Locates a name in a type library. + * + * RETURNS + * + * The offset into the NAME segment of the name, or -1 if not found. + * + * NOTES + * + * The name must be encoded as with ctl2_encode_name(). + */ +static int ctl2_find_name( + ICreateTypeLib2Impl *This, /* [I] The typelib to operate against. */ + char *name) /* [I] The encoded name to find. */ +{ + int offset; + int *namestruct; + + offset = This->typelib_namehash_segment[name[2] & 0x7f]; + while (offset != -1) { + namestruct = (int *)&This->typelib_segment_data[MSFT_SEG_NAME][offset]; + + if (!((namestruct[2] ^ *((int *)name)) & 0xffff00ff)) { + /* hash codes and lengths match, final test */ + if (!strncasecmp(name+4, (void *)(namestruct+3), name[0])) break; + } + + /* move to next item in hash bucket */ + offset = namestruct[1]; + } + + return offset; +} + +/**************************************************************************** + * ctl2_encode_name + * + * Encodes a name string to a form suitable for storing into a type library + * or comparing to a name stored in a type library. + * + * RETURNS + * + * The length of the encoded name, including padding and length+hash fields. + * + * NOTES + * + * Will throw an exception if name or result are NULL. Is not multithread + * safe in the slightest. + */ +static int ctl2_encode_name( + ICreateTypeLib2Impl *This, /* [I] The typelib to operate against (used for LCID only). */ + const WCHAR *name, /* [I] The name string to encode. */ + char **result) /* [O] A pointer to a pointer to receive the encoded name. */ +{ + int length; + static char converted_name[0x104]; + int offset; + int value; + + length = WideCharToMultiByte(CP_ACP, 0, name, strlenW(name), converted_name+4, 0x100, NULL, NULL); + converted_name[0] = length & 0xff; + + converted_name[length + 4] = 0; + + converted_name[1] = 0x00; + + value = LHashValOfNameSysA(This->typelib_header.varflags & 0x0f, This->typelib_header.lcid, converted_name + 4); + + converted_name[2] = value; + converted_name[3] = value >> 8; + + for (offset = (4 - length) & 3; offset; offset--) converted_name[length + offset + 3] = 0x57; + + *result = converted_name; + + return (length + 7) & ~3; +} + +/**************************************************************************** + * ctl2_encode_string + * + * Encodes a string to a form suitable for storing into a type library or + * comparing to a string stored in a type library. + * + * RETURNS + * + * The length of the encoded string, including padding and length fields. + * + * NOTES + * + * Will throw an exception if string or result are NULL. Is not multithread + * safe in the slightest. + */ +static int ctl2_encode_string( + ICreateTypeLib2Impl *This, /* [I] The typelib to operate against (not used?). */ + const WCHAR *string, /* [I] The string to encode. */ + char **result) /* [O] A pointer to a pointer to receive the encoded string. */ +{ + int length; + static char converted_string[0x104]; + int offset; + + length = WideCharToMultiByte(CP_ACP, 0, string, strlenW(string), converted_string+2, 0x102, NULL, NULL); + converted_string[0] = length & 0xff; + converted_string[1] = (length >> 8) & 0xff; + + for (offset = (4 - (length + 2)) & 3; offset; offset--) converted_string[length + offset + 1] = 0x57; + + *result = converted_string; + + return (length + 5) & ~3; +} + +/**************************************************************************** + * ctl2_alloc_segment + * + * Allocates memory from a segment in a type library. + * + * RETURNS + * + * Success: The offset within the segment of the new data area. + * Failure: -1 (this is invariably an out of memory condition). + * + * BUGS + * + * Does not (yet) handle the case where the allocated segment memory needs to grow. + */ +static int ctl2_alloc_segment( + ICreateTypeLib2Impl *This, /* [I] The type library in which to allocate. */ + enum MSFT_segment_index segment, /* [I] The segment in which to allocate. */ + int size, /* [I] The amount to allocate. */ + int block_size) /* [I] Initial allocation block size, or 0 for default. */ +{ + int offset; + + if(!This->typelib_segment_data[segment]) { + if (!block_size) block_size = 0x2000; + + This->typelib_segment_block_length[segment] = block_size; + This->typelib_segment_data[segment] = HeapAlloc(GetProcessHeap(), 0, block_size); + if (!This->typelib_segment_data[segment]) return -1; + memset(This->typelib_segment_data[segment], 0x57, block_size); + } + + while ((This->typelib_segdir[segment].length + size) > This->typelib_segment_block_length[segment]) { + char *block; + + block_size = This->typelib_segment_block_length[segment]; + block = HeapReAlloc(GetProcessHeap(), 0, This->typelib_segment_data[segment], block_size << 1); + if (!block) return -1; + + if (segment == MSFT_SEG_TYPEINFO) { + /* TypeInfos have a direct pointer to their memory space, so we have to fix them up. */ + ICreateTypeInfo2Impl *typeinfo; + + for (typeinfo = This->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) { + typeinfo->typeinfo = (void *)&block[((char *)typeinfo->typeinfo) - This->typelib_segment_data[segment]]; + } + } + + memset(block + block_size, 0x57, block_size); + This->typelib_segment_block_length[segment] = block_size << 1; + This->typelib_segment_data[segment] = block; + } + + offset = This->typelib_segdir[segment].length; + This->typelib_segdir[segment].length += size; + + return offset; +} + +/**************************************************************************** + * ctl2_alloc_typeinfo + * + * Allocates and initializes a typeinfo structure in a type library. + * + * RETURNS + * + * Success: The offset of the new typeinfo. + * Failure: -1 (this is invariably an out of memory condition). + */ +static int ctl2_alloc_typeinfo( + ICreateTypeLib2Impl *This, /* [I] The type library to allocate in. */ + int nameoffset) /* [I] The offset of the name for this typeinfo. */ +{ + int offset; + MSFT_TypeInfoBase *typeinfo; + + offset = ctl2_alloc_segment(This, MSFT_SEG_TYPEINFO, sizeof(MSFT_TypeInfoBase), 0); + if (offset == -1) return -1; + + This->typelib_typeinfo_offsets[This->typelib_header.nrtypeinfos++] = offset; + + typeinfo = (void *)(This->typelib_segment_data[MSFT_SEG_TYPEINFO] + offset); + + typeinfo->typekind = (This->typelib_header.nrtypeinfos - 1) << 16; + typeinfo->memoffset = -1; /* should be EOF if no elements */ + typeinfo->res2 = 0; + typeinfo->res3 = -1; + typeinfo->res4 = 3; + typeinfo->res5 = 0; + typeinfo->cElement = 0; + typeinfo->res7 = 0; + typeinfo->res8 = 0; + typeinfo->res9 = 0; + typeinfo->resA = 0; + typeinfo->posguid = -1; + typeinfo->flags = 0; + typeinfo->NameOffset = nameoffset; + typeinfo->version = 0; + typeinfo->docstringoffs = -1; + typeinfo->helpstringcontext = 0; + typeinfo->helpcontext = 0; + typeinfo->oCustData = -1; + typeinfo->cbSizeVft = 0; + typeinfo->cImplTypes = 0; + typeinfo->size = 0; + typeinfo->datatype1 = -1; + typeinfo->datatype2 = 0; + typeinfo->res18 = 0; + typeinfo->res19 = -1; + + return offset; +} + +/**************************************************************************** + * ctl2_alloc_guid + * + * Allocates and initializes a GUID structure in a type library. Also updates + * the GUID hash table as needed. + * + * RETURNS + * + * Success: The offset of the new GUID. + * Failure: -1 (this is invariably an out of memory condition). + */ +static int ctl2_alloc_guid( + ICreateTypeLib2Impl *This, /* [I] The type library to allocate in. */ + MSFT_GuidEntry *guid) /* [I] The GUID to store. */ +{ + int offset; + MSFT_GuidEntry *guid_space; + int hash_key; + + hash_key = ctl2_hash_guid(&guid->guid); + + offset = ctl2_find_guid(This, hash_key, &guid->guid); + if (offset != -1) return offset; + + offset = ctl2_alloc_segment(This, MSFT_SEG_GUID, sizeof(MSFT_GuidEntry), 0); + if (offset == -1) return -1; + + guid_space = (void *)(This->typelib_segment_data[MSFT_SEG_GUID] + offset); + *guid_space = *guid; + + guid_space->next_hash = This->typelib_guidhash_segment[hash_key]; + This->typelib_guidhash_segment[hash_key] = offset; + + return offset; +} + +/**************************************************************************** + * ctl2_alloc_name + * + * Allocates and initializes a name within a type library. Also updates the + * name hash table as needed. + * + * RETURNS + * + * Success: The offset within the segment of the new name. + * Failure: -1 (this is invariably an out of memory condition). + */ +static int ctl2_alloc_name( + ICreateTypeLib2Impl *This, /* [I] The type library to allocate in. */ + const WCHAR *name) /* [I] The name to store. */ +{ + int length; + int offset; + MSFT_NameIntro *name_space; + char *encoded_name; + + length = ctl2_encode_name(This, name, &encoded_name); + + offset = ctl2_find_name(This, encoded_name); + if (offset != -1) return offset; + + offset = ctl2_alloc_segment(This, MSFT_SEG_NAME, length + 8, 0); + if (offset == -1) return -1; + + name_space = (void *)(This->typelib_segment_data[MSFT_SEG_NAME] + offset); + name_space->hreftype = -1; + name_space->next_hash = -1; + memcpy(&name_space->namelen, encoded_name, length); + + if (This->typelib_namehash_segment[encoded_name[2] & 0x7f] != -1) + name_space->next_hash = This->typelib_namehash_segment[encoded_name[2] & 0x7f]; + + This->typelib_namehash_segment[encoded_name[2] & 0x7f] = offset; + + This->typelib_header.nametablecount += 1; + This->typelib_header.nametablechars += *encoded_name; + + return offset; +} + +/**************************************************************************** + * ctl2_alloc_string + * + * Allocates and initializes a string in a type library. + * + * RETURNS + * + * Success: The offset within the segment of the new string. + * Failure: -1 (this is invariably an out of memory condition). + */ +static int ctl2_alloc_string( + ICreateTypeLib2Impl *This, /* [I] The type library to allocate in. */ + const WCHAR *string) /* [I] The string to store. */ +{ + int length; + int offset; + char *string_space; + char *encoded_string; + + length = ctl2_encode_string(This, string, &encoded_string); + + for (offset = 0; offset < This->typelib_segdir[MSFT_SEG_STRING].length; + offset += ((((This->typelib_segment_data[MSFT_SEG_STRING][offset + 1] << 8) & 0xff) + | (This->typelib_segment_data[MSFT_SEG_STRING][offset + 0] & 0xff)) + 5) & ~3) { + if (!memcmp(encoded_string, This->typelib_segment_data[MSFT_SEG_STRING] + offset, length)) return offset; + } + + offset = ctl2_alloc_segment(This, MSFT_SEG_STRING, length, 0); + if (offset == -1) return -1; + + string_space = This->typelib_segment_data[MSFT_SEG_STRING] + offset; + memcpy(string_space, encoded_string, length); + + return offset; +} + +/**************************************************************************** + * ctl2_alloc_importinfo + * + * Allocates and initializes an import information structure in a type library. + * + * RETURNS + * + * Success: The offset of the new importinfo. + * Failure: -1 (this is invariably an out of memory condition). + */ +static int ctl2_alloc_importinfo( + ICreateTypeLib2Impl *This, /* [I] The type library to allocate in. */ + MSFT_ImpInfo *impinfo) /* [I] The import information to store. */ +{ + int offset; + MSFT_ImpInfo *impinfo_space; + + for (offset = 0; + offset < This->typelib_segdir[MSFT_SEG_IMPORTINFO].length; + offset += sizeof(MSFT_ImpInfo)) { + if (!memcmp(&(This->typelib_segment_data[MSFT_SEG_IMPORTINFO][offset]), + impinfo, sizeof(MSFT_ImpInfo))) { + return offset; + } + } + + offset = ctl2_alloc_segment(This, MSFT_SEG_IMPORTINFO, sizeof(MSFT_ImpInfo), 0); + if (offset == -1) return -1; + + impinfo_space = (void *)(This->typelib_segment_data[MSFT_SEG_IMPORTINFO] + offset); + *impinfo_space = *impinfo; + + return offset; +} + +/**************************************************************************** + * ctl2_alloc_importfile + * + * Allocates and initializes an import file definition in a type library. + * + * RETURNS + * + * Success: The offset of the new importinfo. + * Failure: -1 (this is invariably an out of memory condition). + */ +static int ctl2_alloc_importfile( + ICreateTypeLib2Impl *This, /* [I] The type library to allocate in. */ + int guidoffset, /* [I] The offset to the GUID for the imported library. */ + int major_version, /* [I] The major version number of the imported library. */ + int minor_version, /* [I] The minor version number of the imported library. */ + const WCHAR *filename) /* [I] The filename of the imported library. */ +{ + int length; + int offset; + MSFT_ImpFile *importfile; + char *encoded_string; + + length = ctl2_encode_string(This, filename, &encoded_string); + + encoded_string[0] <<= 2; + encoded_string[0] |= 1; + + for (offset = 0; offset < This->typelib_segdir[MSFT_SEG_IMPORTFILES].length; + offset += ((((This->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset + 0xd] << 8) & 0xff) + | (This->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset + 0xc] & 0xff)) >> 2) + 0xc) { + if (!memcmp(encoded_string, This->typelib_segment_data[MSFT_SEG_IMPORTFILES] + offset + 0xc, length)) return offset; + } + + offset = ctl2_alloc_segment(This, MSFT_SEG_IMPORTFILES, length + 0xc, 0); + if (offset == -1) return -1; + + importfile = (MSFT_ImpFile *)&This->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset]; + importfile->guid = guidoffset; + importfile->lcid = This->typelib_header.lcid2; + importfile->version = major_version | (minor_version << 16); + memcpy(&importfile->filename, encoded_string, length); + + return offset; +} + +/**************************************************************************** + * ctl2_alloc_custdata + * + * Allocates and initializes a "custom data" value in a type library. + * + * RETURNS + * + * Success: The offset of the new custdata. + * Failure: + * + * -1: Out of memory. + * -2: Unable to encode VARIANT data (typically a bug). + */ +static int ctl2_alloc_custdata( + ICreateTypeLib2Impl *This, /* [I] The type library in which to encode the value. */ + VARIANT *pVarVal) /* [I] The value to encode. */ +{ + int offset; + + TRACE("(%p,%p(%d))\n",This,pVarVal,V_VT(pVarVal)); + + switch (V_VT(pVarVal)) { + case VT_UI4: + offset = ctl2_alloc_segment(This, MSFT_SEG_CUSTDATA, 8, 0); + if (offset == -1) return offset; + + *((unsigned short *)&This->typelib_segment_data[MSFT_SEG_CUSTDATA][offset]) = VT_UI4; + *((unsigned long *)&This->typelib_segment_data[MSFT_SEG_CUSTDATA][offset+2]) = V_UI4(pVarVal); + break; + + default: + FIXME("Unknown variable encoding vt %d.\n", V_VT(pVarVal)); + return -2; + } + + return offset; +} + +/**************************************************************************** + * ctl2_set_custdata + * + * Adds a custom data element to an object in a type library. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_INVALIDARG or E_OUTOFMEMORY. + */ +static HRESULT ctl2_set_custdata( + ICreateTypeLib2Impl *This, /* [I] The type library to store the custom data in. */ + REFGUID guid, /* [I] The GUID used as a key to retrieve the custom data. */ + VARIANT *pVarVal, /* [I] The custom data itself. */ + int *offset) /* [I/O] The list of custom data to prepend to. */ +{ + MSFT_GuidEntry guidentry; + int dataoffset; + int guidoffset; + int custoffset; + int *custdata; + + guidentry.guid = *guid; + + guidentry.hreftype = -1; + guidentry.next_hash = -1; + + guidoffset = ctl2_alloc_guid(This, &guidentry); + if (guidoffset == -1) return E_OUTOFMEMORY; + dataoffset = ctl2_alloc_custdata(This, pVarVal); + if (dataoffset == -1) return E_OUTOFMEMORY; + if (dataoffset == -2) return E_INVALIDARG; + + custoffset = ctl2_alloc_segment(This, MSFT_SEG_CUSTDATAGUID, 12, 0); + if (custoffset == -1) return E_OUTOFMEMORY; + + custdata = (int *)&This->typelib_segment_data[MSFT_SEG_CUSTDATAGUID][custoffset]; + custdata[0] = guidoffset; + custdata[1] = dataoffset; + custdata[2] = *offset; + *offset = custoffset; + + return S_OK; +} + +/**************************************************************************** + * ctl2_encode_typedesc + * + * Encodes a type description, storing information in the TYPEDESC and ARRAYDESC + * segments as needed. + * + * RETURNS + * + * Success: 0. + * Failure: -1. + */ +static int ctl2_encode_typedesc( + ICreateTypeLib2Impl *This, /* [I] The type library in which to encode the TYPEDESC. */ + TYPEDESC *tdesc, /* [I] The type description to encode. */ + int *encoded_tdesc, /* [O] The encoded type description. */ + int *width, /* [O] The width of the type, or NULL. */ + int *alignment, /* [O] The alignment of the type, or NULL. */ + int *decoded_size) /* [O] The total size of the unencoded TYPEDESCs, including nested descs. */ +{ + int default_tdesc; + int scratch; + int typeoffset; + int arrayoffset; + int *typedata; + int *arraydata; + int target_type; + int child_size; + + default_tdesc = 0x80000000 | (tdesc->vt << 16) | tdesc->vt; + if (!width) width = &scratch; + if (!alignment) alignment = &scratch; + if (!decoded_size) decoded_size = &scratch; + + *decoded_size = 0; + + switch (tdesc->vt) { + case VT_UI1: + case VT_I1: + *encoded_tdesc = default_tdesc; + *width = 1; + *alignment = 1; + break; + + case VT_INT: + *encoded_tdesc = 0x80000000 | (VT_I4 << 16) | VT_INT; + if ((This->typelib_header.varflags & 0x0f) == SYS_WIN16) { + *width = 2; + *alignment = 2; + } else { + *width = 4; + *alignment = 4; + } + break; + + case VT_UINT: + *encoded_tdesc = 0x80000000 | (VT_UI4 << 16) | VT_UINT; + if ((This->typelib_header.varflags & 0x0f) == SYS_WIN16) { + *width = 2; + *alignment = 2; + } else { + *width = 4; + *alignment = 4; + } + break; + + case VT_UI2: + case VT_I2: + case VT_BOOL: + *encoded_tdesc = default_tdesc; + *width = 2; + *alignment = 2; + break; + + case VT_I4: + case VT_UI4: + case VT_R4: + case VT_ERROR: + case VT_BSTR: + case VT_HRESULT: + *encoded_tdesc = default_tdesc; + *width = 4; + *alignment = 4; + break; + + case VT_CY: + *encoded_tdesc = default_tdesc; + *width = 8; + *alignment = 4; /* guess? */ + break; + + case VT_VOID: + *encoded_tdesc = 0x80000000 | (VT_EMPTY << 16) | tdesc->vt; + *width = 0; + *alignment = 1; + break; + + case VT_PTR: + /* FIXME: Make with the error checking. */ + FIXME("PTR vartype, may not work correctly.\n"); + + ctl2_encode_typedesc(This, tdesc->u.lptdesc, &target_type, NULL, NULL, &child_size); + + for (typeoffset = 0; typeoffset < This->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) { + typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; + if (((typedata[0] & 0xffff) == VT_PTR) && (typedata[1] == target_type)) break; + } + + if (typeoffset == This->typelib_segdir[MSFT_SEG_TYPEDESC].length) { + int mix_field; + + if (target_type & 0x80000000) { + mix_field = ((target_type >> 16) & 0x3fff) | VT_BYREF; + } else { + typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][target_type]; + mix_field = ((typedata[0] >> 16) == 0x7fff)? 0x7fff: 0x7ffe; + } + + typeoffset = ctl2_alloc_segment(This, MSFT_SEG_TYPEDESC, 8, 0); + typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; + + typedata[0] = (mix_field << 16) | VT_PTR; + typedata[1] = target_type; + } + + *encoded_tdesc = typeoffset; + + *width = 4; + *alignment = 4; + *decoded_size = sizeof(TYPEDESC) + child_size; + break; + + case VT_SAFEARRAY: + /* FIXME: Make with the error checking. */ + FIXME("SAFEARRAY vartype, may not work correctly.\n"); + + ctl2_encode_typedesc(This, tdesc->u.lptdesc, &target_type, NULL, NULL, &child_size); + + for (typeoffset = 0; typeoffset < This->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) { + typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; + if (((typedata[0] & 0xffff) == VT_SAFEARRAY) && (typedata[1] == target_type)) break; + } + + if (typeoffset == This->typelib_segdir[MSFT_SEG_TYPEDESC].length) { + int mix_field; + + if (target_type & 0x80000000) { + mix_field = ((target_type >> 16) & VT_TYPEMASK) | VT_ARRAY; + } else { + typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][target_type]; + mix_field = ((typedata[0] >> 16) == 0x7fff)? 0x7fff: 0x7ffe; + } + + typeoffset = ctl2_alloc_segment(This, MSFT_SEG_TYPEDESC, 8, 0); + typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; + + typedata[0] = (mix_field << 16) | VT_SAFEARRAY; + typedata[1] = target_type; + } + + *encoded_tdesc = typeoffset; + + *width = 4; + *alignment = 4; + *decoded_size = sizeof(TYPEDESC) + child_size; + break; + + case VT_CARRAY: + { + /* FIXME: Make with the error checking. */ + int num_dims = tdesc->u.lpadesc->cDims, elements = 1, dim; + + ctl2_encode_typedesc(This, &tdesc->u.lpadesc->tdescElem, &target_type, width, alignment, NULL); + arrayoffset = ctl2_alloc_segment(This, MSFT_SEG_ARRAYDESC, (2 + 2 * num_dims) * sizeof(int), 0); + arraydata = (void *)&This->typelib_segment_data[MSFT_SEG_ARRAYDESC][arrayoffset]; + + arraydata[0] = target_type; + arraydata[1] = num_dims; + arraydata[1] |= ((num_dims * 2 * sizeof(int)) << 16); + arraydata += 2; + + for(dim = 0; dim < num_dims; dim++) { + arraydata[0] = tdesc->u.lpadesc->rgbounds[dim].cElements; + arraydata[1] = tdesc->u.lpadesc->rgbounds[dim].lLbound; + elements *= tdesc->u.lpadesc->rgbounds[dim].cElements; + arraydata += 2; + } + typeoffset = ctl2_alloc_segment(This, MSFT_SEG_TYPEDESC, 8, 0); + typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; + + typedata[0] = (0x7ffe << 16) | VT_CARRAY; + typedata[1] = arrayoffset; + + *encoded_tdesc = typeoffset; + *width = *width * elements; + *decoded_size = sizeof(ARRAYDESC) + (num_dims - 1) * sizeof(SAFEARRAYBOUND); + + break; + } + case VT_USERDEFINED: + TRACE("USERDEFINED.\n"); + for (typeoffset = 0; typeoffset < This->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) { + typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; + if ((typedata[0] == ((0x7fff << 16) | VT_USERDEFINED)) && (typedata[1] == tdesc->u.hreftype)) break; + } + + if (typeoffset == This->typelib_segdir[MSFT_SEG_TYPEDESC].length) { + typeoffset = ctl2_alloc_segment(This, MSFT_SEG_TYPEDESC, 8, 0); + typedata = (void *)&This->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; + + typedata[0] = (0x7fff << 16) | VT_USERDEFINED; + typedata[1] = tdesc->u.hreftype; + } + + *encoded_tdesc = typeoffset; + *width = 0; + *alignment = 1; + break; + + default: + FIXME("Unrecognized type %d.\n", tdesc->vt); + *encoded_tdesc = default_tdesc; + *width = 0; + *alignment = 1; + break; + } + + return 0; +} + +/**************************************************************************** + * ctl2_find_nth_reference + * + * Finds a reference by index into the linked list of reference records. + * + * RETURNS + * + * Success: Offset of the desired reference record. + * Failure: -1. + */ +static int ctl2_find_nth_reference( + ICreateTypeLib2Impl *This, /* [I] The type library in which to search. */ + int offset, /* [I] The starting offset of the reference list. */ + int index) /* [I] The index of the reference to find. */ +{ + MSFT_RefRecord *ref; + + for (; index && (offset != -1); index--) { + ref = (MSFT_RefRecord *)&This->typelib_segment_data[MSFT_SEG_REFERENCES][offset]; + offset = ref->onext; + } + + return offset; +} + +/**************************************************************************** + * ctl2_find_typeinfo_from_offset + * + * Finds an ITypeInfo given an offset into the TYPEINFO segment. + * + * RETURNS + * + * Success: S_OK. + * Failure: TYPE_E_ELEMENTNOTFOUND. + */ +static HRESULT ctl2_find_typeinfo_from_offset( + ICreateTypeLib2Impl *This, /* [I] The typelib to find the typeinfo in. */ + int offset, /* [I] The offset of the desired typeinfo. */ + ITypeInfo **ppTinfo) /* [I] The typeinfo found. */ +{ + void *typeinfodata; + ICreateTypeInfo2Impl *typeinfo; + + typeinfodata = &This->typelib_segment_data[MSFT_SEG_TYPEINFO][offset]; + + for (typeinfo = This->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) { + if (typeinfo->typeinfo == typeinfodata) { + *ppTinfo = (ITypeInfo *)&typeinfo->lpVtblTypeInfo2; + ITypeInfo2_AddRef(*ppTinfo); + return S_OK; + } + } + + ERR("Failed to find typeinfo, invariant varied.\n"); + + return TYPE_E_ELEMENTNOTFOUND; +} + +/*================== ICreateTypeInfo2 Implementation ===================================*/ + +/****************************************************************************** + * ICreateTypeInfo2_QueryInterface {OLEAUT32} + * + * See IUnknown_QueryInterface. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnQueryInterface( + ICreateTypeInfo2 * iface, + REFIID riid, + VOID **ppvObject) +{ + ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; + + TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid)); + + *ppvObject=NULL; + if(IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid,&IID_ICreateTypeInfo)|| + IsEqualIID(riid,&IID_ICreateTypeInfo2)) + { + *ppvObject = This; + } else if (IsEqualIID(riid, &IID_ITypeInfo) || + IsEqualIID(riid, &IID_ITypeInfo2)) { + *ppvObject = &This->lpVtblTypeInfo2; + } + + if(*ppvObject) + { + ICreateTypeLib2_AddRef(iface); + TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject); + return S_OK; + } + TRACE("-- Interface: E_NOINTERFACE\n"); + return E_NOINTERFACE; +} + +/****************************************************************************** + * ICreateTypeInfo2_AddRef {OLEAUT32} + * + * See IUnknown_AddRef. + */ +static ULONG WINAPI ICreateTypeInfo2_fnAddRef(ICreateTypeInfo2 *iface) +{ + ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p)->ref was %lu\n",This, ref - 1); + + return ref; +} + +/****************************************************************************** + * ICreateTypeInfo2_Release {OLEAUT32} + * + * See IUnknown_Release. + */ +static ULONG WINAPI ICreateTypeInfo2_fnRelease(ICreateTypeInfo2 *iface) +{ + ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(%lu)\n",This, ref); + + if (!ref) { + if (This->typelib) { + ICreateTypeLib2_fnRelease((ICreateTypeLib2 *)This->typelib); + This->typelib = NULL; + } + + /* ICreateTypeLib2 frees all ICreateTypeInfos when it releases. */ + /* HeapFree(GetProcessHeap(),0,This); */ + return 0; + } + + return ref; +} + + +/****************************************************************************** + * ICreateTypeInfo2_SetGuid {OLEAUT32} + * + * See ICreateTypeInfo_SetGuid. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetGuid(ICreateTypeInfo2 *iface, REFGUID guid) +{ + ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; + + MSFT_GuidEntry guidentry; + int offset; + + TRACE("(%p,%s)\n", iface, debugstr_guid(guid)); + + guidentry.guid = *guid; + guidentry.hreftype = This->typelib->typelib_typeinfo_offsets[This->typeinfo->typekind >> 16]; + guidentry.next_hash = -1; + + offset = ctl2_alloc_guid(This->typelib, &guidentry); + + if (offset == -1) return E_OUTOFMEMORY; + + This->typeinfo->posguid = offset; + + if (IsEqualIID(guid, &IID_IDispatch)) { + This->typelib->typelib_header.dispatchpos = This->typelib->typelib_typeinfo_offsets[This->typeinfo->typekind >> 16]; + } + + return S_OK; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetTypeFlags {OLEAUT32} + * + * See ICreateTypeInfo_SetTypeFlags. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetTypeFlags(ICreateTypeInfo2 *iface, UINT uTypeFlags) +{ + ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; + + TRACE("(%p,0x%x)\n", iface, uTypeFlags); + + This->typeinfo->flags = uTypeFlags; + + if (uTypeFlags & 0x1000) { + MSFT_GuidEntry foo; + int guidoffset; + int fileoffset; + MSFT_ImpInfo impinfo; + static const WCHAR stdole2tlb[] = { 's','t','d','o','l','e','2','.','t','l','b',0 }; + + foo.guid = IID_StdOle; + foo.hreftype = 2; + foo.next_hash = -1; + guidoffset = ctl2_alloc_guid(This->typelib, &foo); + if (guidoffset == -1) return E_OUTOFMEMORY; + + fileoffset = ctl2_alloc_importfile(This->typelib, guidoffset, 2, 0, stdole2tlb); + if (fileoffset == -1) return E_OUTOFMEMORY; + + foo.guid = IID_IDispatch; + foo.hreftype = 1; + foo.next_hash = -1; + guidoffset = ctl2_alloc_guid(This->typelib, &foo); + if (guidoffset == -1) return E_OUTOFMEMORY; + + impinfo.res0 = 0x03010000; + impinfo.oImpFile = fileoffset; + impinfo.oGuid = guidoffset; + ctl2_alloc_importinfo(This->typelib, &impinfo); + + This->typelib->typelib_header.dispatchpos = 1; + This->typelib->typelib_header.res50 = 1; + + This->typeinfo->typekind |= 0x10; + This->typeinfo->typekind &= ~0x0f; + This->typeinfo->typekind |= TKIND_DISPATCH; + } + + return S_OK; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetDocString {OLEAUT32} + * + * See ICreateTypeInfo_SetDocString. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetDocString( + ICreateTypeInfo2* iface, + LPOLESTR pStrDoc) +{ + ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; + + int offset; + + TRACE("(%p,%s)\n", iface, debugstr_w(pStrDoc)); + + offset = ctl2_alloc_string(This->typelib, pStrDoc); + if (offset == -1) return E_OUTOFMEMORY; + This->typeinfo->docstringoffs = offset; + return S_OK; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetHelpContext {OLEAUT32} + * + * See ICreateTypeInfo_SetHelpContext. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetHelpContext( + ICreateTypeInfo2* iface, + DWORD dwHelpContext) +{ + ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; + + TRACE("(%p,%ld)\n", iface, dwHelpContext); + + This->typeinfo->helpcontext = dwHelpContext; + + return S_OK; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetVersion {OLEAUT32} + * + * See ICreateTypeInfo_SetVersion. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetVersion( + ICreateTypeInfo2* iface, + WORD wMajorVerNum, + WORD wMinorVerNum) +{ + ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; + + TRACE("(%p,%d,%d)\n", iface, wMajorVerNum, wMinorVerNum); + + This->typeinfo->version = wMajorVerNum | (wMinorVerNum << 16); + return S_OK; +} + +/****************************************************************************** + * ICreateTypeInfo2_AddRefTypeInfo {OLEAUT32} + * + * See ICreateTypeInfo_AddRefTypeInfo. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnAddRefTypeInfo( + ICreateTypeInfo2* iface, + ITypeInfo* pTInfo, + HREFTYPE* phRefType) +{ + ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; + + ITypeLib *container; + int index; + HRESULT res; + + TRACE("(%p,%p,%p)\n", iface, pTInfo, phRefType); + + /* + * If this is one of ours, we set *phRefType to the TYPEINFO offset of + * the referred TypeInfo. Otherwise, we presumably have more magic to do. + * + * Unfortunately, we can't rely on the passed-in TypeInfo even having the + * same internal structure as one of ours. It could be from another + * implementation of ITypeInfo. So we need to do the following... + */ + res = ITypeInfo_GetContainingTypeLib(pTInfo, &container, &index); + if (!SUCCEEDED(res)) { + TRACE("failed to find containing typelib.\n"); + return res; + } + + if (container == (ITypeLib *)&This->typelib->lpVtblTypeLib2) { + *phRefType = This->typelib->typelib_typeinfo_offsets[index]; + } else { + FIXME("(%p,%p,%p), pTInfo from different typelib.\n", iface, pTInfo, phRefType); + } + + ITypeLib_Release(container); + return S_OK; +} + +/****************************************************************************** + * ICreateTypeInfo2_AddFuncDesc {OLEAUT32} + * + * See ICreateTypeInfo_AddFuncDesc. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnAddFuncDesc( + ICreateTypeInfo2* iface, + UINT index, + FUNCDESC* pFuncDesc) +{ + ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; + + int offset; + int *typedata; + int i; + int decoded_size; + + FIXME("(%p,%d,%p), stub!\n", iface, index, pFuncDesc); + FIXME("{%ld,%p,%p,%d,%d,%d,%d,%d,%d,%d,{%d},%d}\n", pFuncDesc->memid, pFuncDesc->lprgscode, pFuncDesc->lprgelemdescParam, pFuncDesc->funckind, pFuncDesc->invkind, pFuncDesc->callconv, pFuncDesc->cParams, pFuncDesc->cParamsOpt, pFuncDesc->oVft, pFuncDesc->cScodes, pFuncDesc->elemdescFunc.tdesc.vt, pFuncDesc->wFuncFlags); +/* FIXME("{%d, %d}\n", pFuncDesc->lprgelemdescParam[0].tdesc.vt, pFuncDesc->lprgelemdescParam[1].tdesc.vt); */ +/* return E_OUTOFMEMORY; */ + + if (!This->typedata) { + This->typedata = HeapAlloc(GetProcessHeap(), 0, 0x2000); + This->typedata[0] = 0; + } + + /* allocate type data space for us */ + offset = This->typedata[0]; + This->typedata[0] += 0x18 + (pFuncDesc->cParams * 12); + typedata = This->typedata + (offset >> 2) + 1; + + /* fill out the basic type information */ + typedata[0] = (0x18 + (pFuncDesc->cParams * 12)) | (index << 16); + ctl2_encode_typedesc(This->typelib, &pFuncDesc->elemdescFunc.tdesc, &typedata[1], NULL, NULL, &decoded_size); + typedata[2] = pFuncDesc->wFuncFlags; + typedata[3] = ((sizeof(FUNCDESC) + decoded_size) << 16) | This->typeinfo->cbSizeVft; + typedata[4] = (index << 16) | (pFuncDesc->callconv << 8) | 9; + typedata[5] = pFuncDesc->cParams; + + /* NOTE: High word of typedata[3] is total size of FUNCDESC + size of all ELEMDESCs for params + TYPEDESCs for pointer params and return types. */ + /* That is, total memory allocation required to reconstitute the FUNCDESC in its entirety. */ + typedata[3] += (sizeof(ELEMDESC) * pFuncDesc->cParams) << 16; + + for (i = 0; i < pFuncDesc->cParams; i++) { + ctl2_encode_typedesc(This->typelib, &pFuncDesc->lprgelemdescParam[i].tdesc, &typedata[6+(i*3)], NULL, NULL, &decoded_size); + typedata[7+(i*3)] = -1; + typedata[8+(i*3)] = pFuncDesc->lprgelemdescParam[i].u.paramdesc.wParamFlags; + typedata[3] += decoded_size << 16; + +#if 0 + /* FIXME: Doesn't work. Doesn't even come up with usable VTs for varDefaultValue. */ + if (pFuncDesc->lprgelemdescParam[i].u.paramdesc.wParamFlags & PARAMFLAG_FHASDEFAULT) { + ctl2_alloc_custdata(This->typelib, &pFuncDesc->lprgelemdescParam[i].u.paramdesc.pparamdescex->varDefaultValue); + } +#endif + } + + /* update the index data */ + This->indices[index] = ((0x6000 | This->typeinfo->cImplTypes) << 16) | index; + This->names[index] = -1; + This->offsets[index] = offset; + + /* ??? */ + if (!This->typeinfo->res2) This->typeinfo->res2 = 0x20; + This->typeinfo->res2 <<= 1; + + /* ??? */ + if (This->typeinfo->res3 == -1) This->typeinfo->res3 = 0; + This->typeinfo->res3 += 0x38; + + /* ??? */ + if (index < 2) This->typeinfo->res2 += pFuncDesc->cParams << 4; + This->typeinfo->res3 += pFuncDesc->cParams << 4; + + /* adjust size of VTBL */ + This->typeinfo->cbSizeVft += 4; + + /* Increment the number of function elements */ + This->typeinfo->cElement += 1; + + return S_OK; +} + +/****************************************************************************** + * ICreateTypeInfo2_AddImplType {OLEAUT32} + * + * See ICreateTypeInfo_AddImplType. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnAddImplType( + ICreateTypeInfo2* iface, + UINT index, + HREFTYPE hRefType) +{ + ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; + + TRACE("(%p,%d,%ld)\n", iface, index, hRefType); + + if ((This->typeinfo->typekind & 15) == TKIND_COCLASS) { + int offset; + MSFT_RefRecord *ref; + + if (index == 0) { + if (This->typeinfo->datatype1 != -1) return TYPE_E_ELEMENTNOTFOUND; + + offset = ctl2_alloc_segment(This->typelib, MSFT_SEG_REFERENCES, sizeof(MSFT_RefRecord), 0); + if (offset == -1) return E_OUTOFMEMORY; + + This->typeinfo->datatype1 = offset; + } else { + int lastoffset; + + lastoffset = ctl2_find_nth_reference(This->typelib, This->typeinfo->datatype1, index - 1); + if (lastoffset == -1) return TYPE_E_ELEMENTNOTFOUND; + + ref = (MSFT_RefRecord *)&This->typelib->typelib_segment_data[MSFT_SEG_REFERENCES][lastoffset]; + if (ref->onext != -1) return TYPE_E_ELEMENTNOTFOUND; + + offset = ctl2_alloc_segment(This->typelib, MSFT_SEG_REFERENCES, sizeof(MSFT_RefRecord), 0); + if (offset == -1) return E_OUTOFMEMORY; + + ref->onext = offset; + } + + ref = (MSFT_RefRecord *)&This->typelib->typelib_segment_data[MSFT_SEG_REFERENCES][offset]; + + ref->reftype = hRefType; + ref->flags = 0; + ref->oCustData = -1; + ref->onext = -1; + } else if ((This->typeinfo->typekind & 15) == TKIND_DISPATCH) { + FIXME("dispatch case unhandled.\n"); + } else if ((This->typeinfo->typekind & 15) == TKIND_INTERFACE) { + if (This->typeinfo->cImplTypes) { + return (index == 1)? TYPE_E_BADMODULEKIND: TYPE_E_ELEMENTNOTFOUND; + } + + if (index != 0) return TYPE_E_ELEMENTNOTFOUND; + + This->typeinfo->cImplTypes++; + + /* hacked values for IDispatch only, and maybe only for stdole. */ + This->typeinfo->cbSizeVft += 0x0c; /* hack */ + This->typeinfo->datatype1 = hRefType; + This->typeinfo->datatype2 = (3 << 16) | 1; /* ? */ + } else { + FIXME("AddImplType unsupported on typekind %d\n", This->typeinfo->typekind & 15); + return E_OUTOFMEMORY; + } + + return S_OK; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetImplTypeFlags {OLEAUT32} + * + * See ICreateTypeInfo_SetImplTypeFlags. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetImplTypeFlags( + ICreateTypeInfo2* iface, + UINT index, + INT implTypeFlags) +{ + ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; + int offset; + MSFT_RefRecord *ref; + + TRACE("(%p,%d,0x%x)\n", iface, index, implTypeFlags); + + if ((This->typeinfo->typekind & 15) != TKIND_COCLASS) { + return TYPE_E_BADMODULEKIND; + } + + offset = ctl2_find_nth_reference(This->typelib, This->typeinfo->datatype1, index); + if (offset == -1) return TYPE_E_ELEMENTNOTFOUND; + + ref = (MSFT_RefRecord *)&This->typelib->typelib_segment_data[MSFT_SEG_REFERENCES][offset]; + ref->flags = implTypeFlags; + + return S_OK; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetAlignment {OLEAUT32} + * + * See ICreateTypeInfo_SetAlignment. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetAlignment( + ICreateTypeInfo2* iface, + WORD cbAlignment) +{ + ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; + + TRACE("(%p,%d)\n", iface, cbAlignment); + + if (!cbAlignment) return E_INVALIDARG; + if (cbAlignment > 16) return E_INVALIDARG; + + This->typeinfo->typekind &= ~0xffc0; + This->typeinfo->typekind |= cbAlignment << 6; + + /* FIXME: There's probably some way to simplify this. */ + switch (This->typeinfo->typekind & 15) { + case TKIND_ALIAS: + default: + break; + + case TKIND_ENUM: + case TKIND_INTERFACE: + case TKIND_DISPATCH: + case TKIND_COCLASS: + if (cbAlignment > 4) cbAlignment = 4; + break; + + case TKIND_RECORD: + case TKIND_MODULE: + case TKIND_UNION: + cbAlignment = 1; + break; + } + + This->typeinfo->typekind |= cbAlignment << 11; + + return S_OK; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetSchema {OLEAUT32} + * + * See ICreateTypeInfo_SetSchema. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetSchema( + ICreateTypeInfo2* iface, + LPOLESTR pStrSchema) +{ + FIXME("(%p,%s), stub!\n", iface, debugstr_w(pStrSchema)); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_AddVarDesc {OLEAUT32} + * + * See ICreateTypeInfo_AddVarDesc. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnAddVarDesc( + ICreateTypeInfo2* iface, + UINT index, + VARDESC* pVarDesc) +{ + ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; + int offset; + INT *typedata; + int var_datawidth; + int var_alignment; + int var_type_size; + int alignment; + + TRACE("(%p,%d,%p), stub!\n", iface, index, pVarDesc); + TRACE("%ld, %p, %ld, {{%lx, %d}, {%p, %x}}, 0x%x, %d\n", pVarDesc->memid, pVarDesc->lpstrSchema, pVarDesc->u.oInst, + pVarDesc->elemdescVar.tdesc.u.hreftype, pVarDesc->elemdescVar.tdesc.vt, + pVarDesc->elemdescVar.u.paramdesc.pparamdescex, pVarDesc->elemdescVar.u.paramdesc.wParamFlags, + pVarDesc->wVarFlags, pVarDesc->varkind); + + if ((This->typeinfo->cElement >> 16) != index) { + TRACE("Out-of-order element.\n"); + return TYPE_E_ELEMENTNOTFOUND; + } + + if (!This->typedata) { + This->typedata = HeapAlloc(GetProcessHeap(), 0, 0x2000); + This->typedata[0] = 0; + } + + /* allocate type data space for us */ + offset = This->typedata[0]; + This->typedata[0] += 0x14; + typedata = This->typedata + (offset >> 2) + 1; + + /* fill out the basic type information */ + typedata[0] = 0x14 | (index << 16); + typedata[2] = pVarDesc->wVarFlags; + typedata[3] = (sizeof(VARDESC) << 16) | 0; + + /* update the index data */ + This->indices[index] = 0x40000000 + index; + This->names[index] = -1; + This->offsets[index] = offset; + + /* figure out type widths and whatnot */ + ctl2_encode_typedesc(This->typelib, &pVarDesc->elemdescVar.tdesc, + &typedata[1], &var_datawidth, &var_alignment, + &var_type_size); + + /* pad out starting position to data width */ + This->datawidth += var_alignment - 1; + This->datawidth &= ~(var_alignment - 1); + typedata[4] = This->datawidth; + + /* add the new variable to the total data width */ + This->datawidth += var_datawidth; + + /* add type description size to total required allocation */ + typedata[3] += var_type_size << 16; + + /* fix type alignment */ + alignment = (This->typeinfo->typekind >> 11) & 0x1f; + if (alignment < var_alignment) { + alignment = var_alignment; + This->typeinfo->typekind &= ~0xf800; + This->typeinfo->typekind |= alignment << 11; + } + + /* ??? */ + if (!This->typeinfo->res2) This->typeinfo->res2 = 0x1a; + if ((index == 0) || (index == 1) || (index == 2) || (index == 4) || (index == 9)) { + This->typeinfo->res2 <<= 1; + } + + /* ??? */ + if (This->typeinfo->res3 == -1) This->typeinfo->res3 = 0; + This->typeinfo->res3 += 0x2c; + + /* increment the number of variable elements */ + This->typeinfo->cElement += 0x10000; + + /* pad data width to alignment */ + This->typeinfo->size = (This->datawidth + (alignment - 1)) & ~(alignment - 1); + + return S_OK; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetFuncAndParamNames {OLEAUT32} + * + * See ICreateTypeInfo_SetFuncAndParamNames. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncAndParamNames( + ICreateTypeInfo2* iface, + UINT index, + LPOLESTR* rgszNames, + UINT cNames) +{ + ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; + + int i; + int offset; + char *namedata; + + FIXME("(%p,%d,%s,%d), stub!\n", iface, index, debugstr_w(*rgszNames), cNames); + + offset = ctl2_alloc_name(This->typelib, rgszNames[0]); + This->names[index] = offset; + + namedata = This->typelib->typelib_segment_data[MSFT_SEG_NAME] + offset; + namedata[9] &= ~0x10; + if (*((INT *)namedata) == -1) { + *((INT *)namedata) = This->typelib->typelib_typeinfo_offsets[This->typeinfo->typekind >> 16]; + } + + for (i = 1; i < cNames; i++) { + /* FIXME: Almost certainly easy to break */ + int *paramdata = &This->typedata[This->offsets[index] >> 2]; + + offset = ctl2_alloc_name(This->typelib, rgszNames[i]); + paramdata[(i * 3) + 5] = offset; + } + + return S_OK; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetVarName {OLEAUT32} + * + * See ICreateTypeInfo_SetVarName. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetVarName( + ICreateTypeInfo2* iface, + UINT index, + LPOLESTR szName) +{ + ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; + int offset; + char *namedata; + + TRACE("(%p,%d,%s), stub!\n", iface, index, debugstr_w(szName)); + + if ((This->typeinfo->cElement >> 16) <= index) { + TRACE("Out-of-order element.\n"); + return TYPE_E_ELEMENTNOTFOUND; + } + + offset = ctl2_alloc_name(This->typelib, szName); + if (offset == -1) return E_OUTOFMEMORY; + + namedata = This->typelib->typelib_segment_data[MSFT_SEG_NAME] + offset; + if (*((INT *)namedata) == -1) { + *((INT *)namedata) = This->typelib->typelib_typeinfo_offsets[This->typeinfo->typekind >> 16]; + namedata[9] |= 0x10; + } + if ((This->typeinfo->typekind & 15) == TKIND_ENUM) { + namedata[9] |= 0x20; + } + This->names[index] = offset; + + return S_OK; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetTypeDescAlias {OLEAUT32} + * + * See ICreateTypeInfo_SetTypeDescAlias. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetTypeDescAlias( + ICreateTypeInfo2* iface, + TYPEDESC* pTDescAlias) +{ + ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; + + int encoded_typedesc; + int width; + + if ((This->typeinfo->typekind & 15) != TKIND_ALIAS) { + return TYPE_E_WRONGTYPEKIND; + } + + FIXME("(%p,%p), hack!\n", iface, pTDescAlias); + + if (ctl2_encode_typedesc(This->typelib, pTDescAlias, &encoded_typedesc, &width, NULL, NULL) == -1) { + return E_OUTOFMEMORY; + } + + This->typeinfo->size = width; + This->typeinfo->datatype1 = encoded_typedesc; + + return S_OK; +} + +/****************************************************************************** + * ICreateTypeInfo2_DefineFuncAsDllEntry {OLEAUT32} + * + * See ICreateTypeInfo_DefineFuncAsDllEntry. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnDefineFuncAsDllEntry( + ICreateTypeInfo2* iface, + UINT index, + LPOLESTR szDllName, + LPOLESTR szProcName) +{ + FIXME("(%p,%d,%s,%s), stub!\n", iface, index, debugstr_w(szDllName), debugstr_w(szProcName)); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetFuncDocString {OLEAUT32} + * + * See ICreateTypeInfo_SetFuncDocString. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncDocString( + ICreateTypeInfo2* iface, + UINT index, + LPOLESTR szDocString) +{ + FIXME("(%p,%d,%s), stub!\n", iface, index, debugstr_w(szDocString)); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetVarDocString {OLEAUT32} + * + * See ICreateTypeInfo_SetVarDocString. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetVarDocString( + ICreateTypeInfo2* iface, + UINT index, + LPOLESTR szDocString) +{ + ICreateTypeInfo2Impl *This = (ICreateTypeInfo2Impl *)iface; + + FIXME("(%p,%d,%s), stub!\n", iface, index, debugstr_w(szDocString)); + + ctl2_alloc_string(This->typelib, szDocString); + + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetFuncHelpContext {OLEAUT32} + * + * See ICreateTypeInfo_SetFuncHelpContext. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncHelpContext( + ICreateTypeInfo2* iface, + UINT index, + DWORD dwHelpContext) +{ + FIXME("(%p,%d,%ld), stub!\n", iface, index, dwHelpContext); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetVarHelpContext {OLEAUT32} + * + * See ICreateTypeInfo_SetVarHelpContext. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetVarHelpContext( + ICreateTypeInfo2* iface, + UINT index, + DWORD dwHelpContext) +{ + FIXME("(%p,%d,%ld), stub!\n", iface, index, dwHelpContext); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetMops {OLEAUT32} + * + * See ICreateTypeInfo_SetMops. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetMops( + ICreateTypeInfo2* iface, + UINT index, + BSTR bstrMops) +{ + FIXME("(%p,%d,%p), stub!\n", iface, index, bstrMops); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetTypeIdldesc {OLEAUT32} + * + * See ICreateTypeInfo_SetTypeIdldesc. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetTypeIdldesc( + ICreateTypeInfo2* iface, + IDLDESC* pIdlDesc) +{ + FIXME("(%p,%p), stub!\n", iface, pIdlDesc); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_LayOut {OLEAUT32} + * + * See ICreateTypeInfo_LayOut. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnLayOut( + ICreateTypeInfo2* iface) +{ + TRACE("(%p), stub!\n", iface); +/* return E_OUTOFMEMORY; */ + return S_OK; +} + +/****************************************************************************** + * ICreateTypeInfo2_DeleteFuncDesc {OLEAUT32} + * + * Delete a function description from a type. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnDeleteFuncDesc( + ICreateTypeInfo2* iface, /* [I] The typeinfo from which to delete a function. */ + UINT index) /* [I] The index of the function to delete. */ +{ + FIXME("(%p,%d), stub!\n", iface, index); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_DeleteFuncDescByMemId {OLEAUT32} + * + * Delete a function description from a type. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnDeleteFuncDescByMemId( + ICreateTypeInfo2* iface, /* [I] The typeinfo from which to delete a function. */ + MEMBERID memid, /* [I] The member id of the function to delete. */ + INVOKEKIND invKind) /* [I] The invocation type of the function to delete. (?) */ +{ + FIXME("(%p,%ld,%d), stub!\n", iface, memid, invKind); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_DeleteVarDesc {OLEAUT32} + * + * Delete a variable description from a type. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY, E_INVALIDARG, TYPE_E_IOERROR, + * TYPE_E_INVDATAREAD, TYPE_E_UNSUPFORMAT or TYPE_E_INVALIDSTATE. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnDeleteVarDesc( + ICreateTypeInfo2* iface, /* [I] The typeinfo from which to delete the variable description. */ + UINT index) /* [I] The index of the variable description to delete. */ +{ + FIXME("(%p,%d), stub!\n", iface, index); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_DeleteVarDescByMemId {OLEAUT32} + * + * Delete a variable description from a type. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY, E_INVALIDARG, TYPE_E_IOERROR, + * TYPE_E_INVDATAREAD, TYPE_E_UNSUPFORMAT or TYPE_E_INVALIDSTATE. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnDeleteVarDescByMemId( + ICreateTypeInfo2* iface, /* [I] The typeinfo from which to delete the variable description. */ + MEMBERID memid) /* [I] The member id of the variable description to delete. */ +{ + FIXME("(%p,%ld), stub!\n", iface, memid); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_DeleteImplType {OLEAUT32} + * + * Delete an interface implementation from a type. (?) + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnDeleteImplType( + ICreateTypeInfo2* iface, /* [I] The typeinfo from which to delete. */ + UINT index) /* [I] The index of the interface to delete. */ +{ + FIXME("(%p,%d), stub!\n", iface, index); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetCustData {OLEAUT32} + * + * Set the custom data for a type. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetCustData( + ICreateTypeInfo2* iface, /* [I] The typeinfo in which to set the custom data. */ + REFGUID guid, /* [I] The GUID used as a key to retrieve the custom data. */ + VARIANT* pVarVal) /* [I] The custom data. */ +{ + FIXME("(%p,%s,%p), stub!\n", iface, debugstr_guid(guid), pVarVal); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetFuncCustData {OLEAUT32} + * + * Set the custom data for a function. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncCustData( + ICreateTypeInfo2* iface, /* [I] The typeinfo in which to set the custom data. */ + UINT index, /* [I] The index of the function for which to set the custom data. */ + REFGUID guid, /* [I] The GUID used as a key to retrieve the custom data. */ + VARIANT* pVarVal) /* [I] The custom data. */ +{ + FIXME("(%p,%d,%s,%p), stub!\n", iface, index, debugstr_guid(guid), pVarVal); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetParamCustData {OLEAUT32} + * + * Set the custom data for a function parameter. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetParamCustData( + ICreateTypeInfo2* iface, /* [I] The typeinfo in which to set the custom data. */ + UINT indexFunc, /* [I] The index of the function on which the parameter resides. */ + UINT indexParam, /* [I] The index of the parameter on which to set the custom data. */ + REFGUID guid, /* [I] The GUID used as a key to retrieve the custom data. */ + VARIANT* pVarVal) /* [I] The custom data. */ +{ + FIXME("(%p,%d,%d,%s,%p), stub!\n", iface, indexFunc, indexParam, debugstr_guid(guid), pVarVal); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetVarCustData {OLEAUT32} + * + * Set the custom data for a variable. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetVarCustData( + ICreateTypeInfo2* iface, /* [I] The typeinfo in which to set the custom data. */ + UINT index, /* [I] The index of the variable on which to set the custom data. */ + REFGUID guid, /* [I] The GUID used as a key to retrieve the custom data. */ + VARIANT* pVarVal) /* [I] The custom data. */ +{ + FIXME("(%p,%d,%s,%p), stub!\n", iface, index, debugstr_guid(guid), pVarVal); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetImplTypeCustData {OLEAUT32} + * + * Set the custom data for an implemented interface. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetImplTypeCustData( + ICreateTypeInfo2* iface, /* [I] The typeinfo on which to set the custom data. */ + UINT index, /* [I] The index of the implemented interface on which to set the custom data. */ + REFGUID guid, /* [I] The GUID used as a key to retrieve the custom data. */ + VARIANT* pVarVal) /* [I] The custom data. */ +{ + FIXME("(%p,%d,%s,%p), stub!\n", iface, index, debugstr_guid(guid), pVarVal); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetHelpStringContext {OLEAUT32} + * + * Set the help string context for the typeinfo. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetHelpStringContext( + ICreateTypeInfo2* iface, /* [I] The typeinfo on which to set the help string context. */ + ULONG dwHelpStringContext) /* [I] The help string context. */ +{ + FIXME("(%p,%ld), stub!\n", iface, dwHelpStringContext); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetFuncHelpStringContext {OLEAUT32} + * + * Set the help string context for a function. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetFuncHelpStringContext( + ICreateTypeInfo2* iface, /* [I] The typeinfo on which to set the help string context. */ + UINT index, /* [I] The index for the function on which to set the help string context. */ + ULONG dwHelpStringContext) /* [I] The help string context. */ +{ + FIXME("(%p,%d,%ld), stub!\n", iface, index, dwHelpStringContext); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetVarHelpStringContext {OLEAUT32} + * + * Set the help string context for a variable. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetVarHelpStringContext( + ICreateTypeInfo2* iface, /* [I] The typeinfo on which to set the help string context. */ + UINT index, /* [I] The index of the variable on which to set the help string context. */ + ULONG dwHelpStringContext) /* [I] The help string context */ +{ + FIXME("(%p,%d,%ld), stub!\n", iface, index, dwHelpStringContext); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_Invalidate {OLEAUT32} + * + * Undocumented function. (!) + */ +static HRESULT WINAPI ICreateTypeInfo2_fnInvalidate( + ICreateTypeInfo2* iface) +{ + FIXME("(%p), stub!\n", iface); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeInfo2_SetName {OLEAUT32} + * + * Set the name for a typeinfo. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of STG_E_INSUFFICIENTMEMORY, E_OUTOFMEMORY, E_INVALIDARG or TYPE_E_INVALIDSTATE. + */ +static HRESULT WINAPI ICreateTypeInfo2_fnSetName( + ICreateTypeInfo2* iface, + LPOLESTR szName) +{ + FIXME("(%p,%s), stub!\n", iface, debugstr_w(szName)); + return E_OUTOFMEMORY; +} + +/*================== ITypeInfo2 Implementation ===================================*/ + +/****************************************************************************** + * ITypeInfo2_QueryInterface {OLEAUT32} + * + * See IUnknown_QueryInterface. + */ +static HRESULT WINAPI ITypeInfo2_fnQueryInterface(ITypeInfo2 * iface, REFIID riid, LPVOID * ppv) +{ + ICOM_THIS_From_ITypeInfo2(ICreateTypeInfo2Impl, iface); + + return ICreateTypeInfo2_QueryInterface((ICreateTypeInfo2 *)This, riid, ppv); +} + +/****************************************************************************** + * ITypeInfo2_AddRef {OLEAUT32} + * + * See IUnknown_AddRef. + */ +static ULONG WINAPI ITypeInfo2_fnAddRef(ITypeInfo2 * iface) +{ + ICOM_THIS_From_ITypeInfo2(ICreateTypeInfo2Impl, iface); + + return ICreateTypeInfo2_AddRef((ICreateTypeInfo2 *)This); +} + +/****************************************************************************** + * ITypeInfo2_Release {OLEAUT32} + * + * See IUnknown_Release. + */ +static ULONG WINAPI ITypeInfo2_fnRelease(ITypeInfo2 * iface) +{ + ICOM_THIS_From_ITypeInfo2(ICreateTypeInfo2Impl, iface); + + return ICreateTypeInfo2_Release((ICreateTypeInfo2 *)This); +} + +/****************************************************************************** + * ITypeInfo2_GetTypeAttr {OLEAUT32} + * + * See ITypeInfo_GetTypeAttr. + */ +static HRESULT WINAPI ITypeInfo2_fnGetTypeAttr( + ITypeInfo2* iface, + TYPEATTR** ppTypeAttr) +{ + FIXME("(%p,%p), stub!\n", iface, ppTypeAttr); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetTypeComp {OLEAUT32} + * + * See ITypeInfo_GetTypeComp. + */ +static HRESULT WINAPI ITypeInfo2_fnGetTypeComp( + ITypeInfo2* iface, + ITypeComp** ppTComp) +{ + FIXME("(%p,%p), stub!\n", iface, ppTComp); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetFuncDesc {OLEAUT32} + * + * See ITypeInfo_GetFuncDesc. + */ +static HRESULT WINAPI ITypeInfo2_fnGetFuncDesc( + ITypeInfo2* iface, + UINT index, + FUNCDESC** ppFuncDesc) +{ + FIXME("(%p,%d,%p), stub!\n", iface, index, ppFuncDesc); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetVarDesc {OLEAUT32} + * + * See ITypeInfo_GetVarDesc. + */ +static HRESULT WINAPI ITypeInfo2_fnGetVarDesc( + ITypeInfo2* iface, + UINT index, + VARDESC** ppVarDesc) +{ + FIXME("(%p,%d,%p), stub!\n", iface, index, ppVarDesc); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetNames {OLEAUT32} + * + * See ITypeInfo_GetNames. + */ +static HRESULT WINAPI ITypeInfo2_fnGetNames( + ITypeInfo2* iface, + MEMBERID memid, + BSTR* rgBstrNames, + UINT cMaxNames, + UINT* pcNames) +{ + FIXME("(%p,%ld,%p,%d,%p), stub!\n", iface, memid, rgBstrNames, cMaxNames, pcNames); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetRefTypeOfImplType {OLEAUT32} + * + * See ITypeInfo_GetRefTypeOfImplType. + */ +static HRESULT WINAPI ITypeInfo2_fnGetRefTypeOfImplType( + ITypeInfo2* iface, + UINT index, + HREFTYPE* pRefType) +{ + FIXME("(%p,%d,%p), stub!\n", iface, index, pRefType); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetImplTypeFlags {OLEAUT32} + * + * See ITypeInfo_GetImplTypeFlags. + */ +static HRESULT WINAPI ITypeInfo2_fnGetImplTypeFlags( + ITypeInfo2* iface, + UINT index, + INT* pImplTypeFlags) +{ + FIXME("(%p,%d,%p), stub!\n", iface, index, pImplTypeFlags); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetIDsOfNames {OLEAUT32} + * + * See ITypeInfo_GetIDsOfNames. + */ +static HRESULT WINAPI ITypeInfo2_fnGetIDsOfNames( + ITypeInfo2* iface, + LPOLESTR* rgszNames, + UINT cNames, + MEMBERID* pMemId) +{ + FIXME("(%p,%p,%d,%p), stub!\n", iface, rgszNames, cNames, pMemId); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_Invoke {OLEAUT32} + * + * See ITypeInfo_Invoke. + */ +static HRESULT WINAPI ITypeInfo2_fnInvoke( + ITypeInfo2* iface, + PVOID pvInstance, + MEMBERID memid, + WORD wFlags, + DISPPARAMS* pDispParams, + VARIANT* pVarResult, + EXCEPINFO* pExcepInfo, + UINT* puArgErr) +{ + FIXME("(%p,%p,%ld,%x,%p,%p,%p,%p), stub!\n", iface, pvInstance, memid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetDocumentation {OLEAUT32} + * + * See ITypeInfo_GetDocumentation. + */ +static HRESULT WINAPI ITypeInfo2_fnGetDocumentation( + ITypeInfo2* iface, + MEMBERID memid, + BSTR* pBstrName, + BSTR* pBstrDocString, + DWORD* pdwHelpContext, + BSTR* pBstrHelpFile) +{ + FIXME("(%p,%ld,%p,%p,%p,%p), stub!\n", iface, memid, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetDllEntry {OLEAUT32} + * + * See ITypeInfo_GetDllEntry. + */ +static HRESULT WINAPI ITypeInfo2_fnGetDllEntry( + ITypeInfo2* iface, + MEMBERID memid, + INVOKEKIND invKind, + BSTR* pBstrDllName, + BSTR* pBstrName, + WORD* pwOrdinal) +{ + FIXME("(%p,%ld,%d,%p,%p,%p), stub!\n", iface, memid, invKind, pBstrDllName, pBstrName, pwOrdinal); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetRefTypeInfo {OLEAUT32} + * + * See ITypeInfo_GetRefTypeInfo. + */ +static HRESULT WINAPI ITypeInfo2_fnGetRefTypeInfo( + ITypeInfo2* iface, + HREFTYPE hRefType, + ITypeInfo** ppTInfo) +{ + FIXME("(%p,%ld,%p), stub!\n", iface, hRefType, ppTInfo); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_AddressOfMember {OLEAUT32} + * + * See ITypeInfo_AddressOfMember. + */ +static HRESULT WINAPI ITypeInfo2_fnAddressOfMember( + ITypeInfo2* iface, + MEMBERID memid, + INVOKEKIND invKind, + PVOID* ppv) +{ + FIXME("(%p,%ld,%d,%p), stub!\n", iface, memid, invKind, ppv); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_CreateInstance {OLEAUT32} + * + * See ITypeInfo_CreateInstance. + */ +static HRESULT WINAPI ITypeInfo2_fnCreateInstance( + ITypeInfo2* iface, + IUnknown* pUnkOuter, + REFIID riid, + PVOID* ppvObj) +{ + FIXME("(%p,%p,%s,%p), stub!\n", iface, pUnkOuter, debugstr_guid(riid), ppvObj); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetMops {OLEAUT32} + * + * See ITypeInfo_GetMops. + */ +static HRESULT WINAPI ITypeInfo2_fnGetMops( + ITypeInfo2* iface, + MEMBERID memid, + BSTR* pBstrMops) +{ + FIXME("(%p,%ld,%p), stub!\n", iface, memid, pBstrMops); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetContainingTypeLib {OLEAUT32} + * + * See ITypeInfo_GetContainingTypeLib. + */ +static HRESULT WINAPI ITypeInfo2_fnGetContainingTypeLib( + ITypeInfo2* iface, + ITypeLib** ppTLib, + UINT* pIndex) +{ + ICOM_THIS_From_ITypeInfo2(ICreateTypeInfo2Impl, iface); + + TRACE("(%p,%p,%p)\n", iface, ppTLib, pIndex); + + *ppTLib = (ITypeLib *)&This->typelib->lpVtblTypeLib2; + This->typelib->ref++; + *pIndex = This->typeinfo->typekind >> 16; + + return S_OK; +} + +/****************************************************************************** + * ITypeInfo2_ReleaseTypeAttr {OLEAUT32} + * + * See ITypeInfo_ReleaseTypeAttr. + */ +static void WINAPI ITypeInfo2_fnReleaseTypeAttr( + ITypeInfo2* iface, + TYPEATTR* pTypeAttr) +{ + FIXME("(%p,%p), stub!\n", iface, pTypeAttr); +} + +/****************************************************************************** + * ITypeInfo2_ReleaseFuncDesc {OLEAUT32} + * + * See ITypeInfo_ReleaseFuncDesc. + */ +static void WINAPI ITypeInfo2_fnReleaseFuncDesc( + ITypeInfo2* iface, + FUNCDESC* pFuncDesc) +{ + FIXME("(%p,%p), stub!\n", iface, pFuncDesc); +} + +/****************************************************************************** + * ITypeInfo2_ReleaseVarDesc {OLEAUT32} + * + * See ITypeInfo_ReleaseVarDesc. + */ +static void WINAPI ITypeInfo2_fnReleaseVarDesc( + ITypeInfo2* iface, + VARDESC* pVarDesc) +{ + FIXME("(%p,%p), stub!\n", iface, pVarDesc); +} + +/****************************************************************************** + * ITypeInfo2_GetTypeKind {OLEAUT32} + * + * Get the TYPEKIND value for a TypeInfo. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ITypeInfo2_fnGetTypeKind( + ITypeInfo2* iface, /* [I] The TypeInfo to obtain the typekind for. */ + TYPEKIND* pTypeKind) /* [O] The typekind for this TypeInfo. */ +{ + FIXME("(%p,%p), stub!\n", iface, pTypeKind); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetTypeFlags {OLEAUT32} + * + * Get the Type Flags for a TypeInfo. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ITypeInfo2_fnGetTypeFlags( + ITypeInfo2* iface, /* [I] The TypeInfo to obtain the typeflags for. */ + ULONG* pTypeFlags) /* [O] The type flags for this TypeInfo. */ +{ + FIXME("(%p,%p), stub!\n", iface, pTypeFlags); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetFuncIndexOfMemId {OLEAUT32} + * + * Gets the index of a function given its member id. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ITypeInfo2_fnGetFuncIndexOfMemId( + ITypeInfo2* iface, /* [I] The TypeInfo in which to find the function. */ + MEMBERID memid, /* [I] The member id for the function. */ + INVOKEKIND invKind, /* [I] The invocation kind for the function. */ + UINT* pFuncIndex) /* [O] The index of the function. */ +{ + FIXME("(%p,%ld,%d,%p), stub!\n", iface, memid, invKind, pFuncIndex); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetVarIndexOfMemId {OLEAUT32} + * + * Gets the index of a variable given its member id. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ITypeInfo2_fnGetVarIndexOfMemId( + ITypeInfo2* iface, /* [I] The TypeInfo in which to find the variable. */ + MEMBERID memid, /* [I] The member id for the variable. */ + UINT* pVarIndex) /* [O] The index of the variable. */ +{ + FIXME("(%p,%ld,%p), stub!\n", iface, memid, pVarIndex); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetCustData {OLEAUT32} + * + * Gets a custom data element from a TypeInfo. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ITypeInfo2_fnGetCustData( + ITypeInfo2* iface, /* [I] The TypeInfo in which to find the custom data. */ + REFGUID guid, /* [I] The GUID under which the custom data is stored. */ + VARIANT* pVarVal) /* [O] The custom data. */ +{ + FIXME("(%p,%s,%p), stub!\n", iface, debugstr_guid(guid), pVarVal); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetFuncCustData {OLEAUT32} + * + * Gets a custom data element from a function. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ITypeInfo2_fnGetFuncCustData( + ITypeInfo2* iface, /* [I] The TypeInfo in which to find the custom data. */ + UINT index, /* [I] The index of the function for which to retrieve the custom data. */ + REFGUID guid, /* [I] The GUID under which the custom data is stored. */ + VARIANT* pVarVal) /* [O] The custom data. */ +{ + FIXME("(%p,%d,%s,%p), stub!\n", iface, index, debugstr_guid(guid), pVarVal); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetParamCustData {OLEAUT32} + * + * Gets a custom data element from a parameter. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ITypeInfo2_fnGetParamCustData( + ITypeInfo2* iface, /* [I] The TypeInfo in which to find the custom data. */ + UINT indexFunc, /* [I] The index of the function for which to retrieve the custom data. */ + UINT indexParam, /* [I] The index of the parameter for which to retrieve the custom data. */ + REFGUID guid, /* [I] The GUID under which the custom data is stored. */ + VARIANT* pVarVal) /* [O] The custom data. */ +{ + FIXME("(%p,%d,%d,%s,%p), stub!\n", iface, indexFunc, indexParam, debugstr_guid(guid), pVarVal); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetVarCustData {OLEAUT32} + * + * Gets a custom data element from a variable. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ITypeInfo2_fnGetVarCustData( + ITypeInfo2* iface, /* [I] The TypeInfo in which to find the custom data. */ + UINT index, /* [I] The index of the variable for which to retrieve the custom data. */ + REFGUID guid, /* [I] The GUID under which the custom data is stored. */ + VARIANT* pVarVal) /* [O] The custom data. */ +{ + FIXME("(%p,%d,%s,%p), stub!\n", iface, index, debugstr_guid(guid), pVarVal); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetImplTypeCustData {OLEAUT32} + * + * Gets a custom data element from an implemented type of a TypeInfo. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ITypeInfo2_fnGetImplTypeCustData( + ITypeInfo2* iface, /* [I] The TypeInfo in which to find the custom data. */ + UINT index, /* [I] The index of the implemented type for which to retrieve the custom data. */ + REFGUID guid, /* [I] The GUID under which the custom data is stored. */ + VARIANT* pVarVal) /* [O] The custom data. */ +{ + FIXME("(%p,%d,%s,%p), stub!\n", iface, index, debugstr_guid(guid), pVarVal); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetDocumentation2 {OLEAUT32} + * + * Gets some documentation from a TypeInfo in a locale-aware fashion. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of STG_E_INSUFFICIENTMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ITypeInfo2_fnGetDocumentation2( + ITypeInfo2* iface, /* [I] The TypeInfo to retrieve the documentation from. */ + MEMBERID memid, /* [I] The member id (why?). */ + LCID lcid, /* [I] The locale (why?). */ + BSTR* pbstrHelpString, /* [O] The help string. */ + DWORD* pdwHelpStringContext, /* [O] The help string context. */ + BSTR* pbstrHelpStringDll) /* [O] The help file name. */ +{ + FIXME("(%p,%ld,%ld,%p,%p,%p), stub!\n", iface, memid, lcid, pbstrHelpString, pdwHelpStringContext, pbstrHelpStringDll); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetAllCustData {OLEAUT32} + * + * Gets all of the custom data associated with a TypeInfo. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ITypeInfo2_fnGetAllCustData( + ITypeInfo2* iface, /* [I] The TypeInfo in which to find the custom data. */ + CUSTDATA* pCustData) /* [O] A pointer to the custom data. */ +{ + FIXME("(%p,%p), stub!\n", iface, pCustData); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetAllFuncCustData {OLEAUT32} + * + * Gets all of the custom data associated with a function. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ITypeInfo2_fnGetAllFuncCustData( + ITypeInfo2* iface, /* [I] The TypeInfo in which to find the custom data. */ + UINT index, /* [I] The index of the function for which to retrieve the custom data. */ + CUSTDATA* pCustData) /* [O] A pointer to the custom data. */ +{ + FIXME("(%p,%d,%p), stub!\n", iface, index, pCustData); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetAllParamCustData {OLEAUT32} + * + * Gets all of the custom data associated with a parameter. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ITypeInfo2_fnGetAllParamCustData( + ITypeInfo2* iface, /* [I] The TypeInfo in which to find the custom data. */ + UINT indexFunc, /* [I] The index of the function for which to retrieve the custom data. */ + UINT indexParam, /* [I] The index of the parameter for which to retrieve the custom data. */ + CUSTDATA* pCustData) /* [O] A pointer to the custom data. */ +{ + FIXME("(%p,%d,%d,%p), stub!\n", iface, indexFunc, indexParam, pCustData); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetAllVarCustData {OLEAUT32} + * + * Gets all of the custom data associated with a variable. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ITypeInfo2_fnGetAllVarCustData( + ITypeInfo2* iface, /* [I] The TypeInfo in which to find the custom data. */ + UINT index, /* [I] The index of the variable for which to retrieve the custom data. */ + CUSTDATA* pCustData) /* [O] A pointer to the custom data. */ +{ + FIXME("(%p,%d,%p), stub!\n", iface, index, pCustData); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeInfo2_GetAllImplTypeCustData {OLEAUT32} + * + * Gets all of the custom data associated with an implemented type. + * + * RETURNS + * + * Success: S_OK. + * Failure: One of E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ITypeInfo2_fnGetAllImplTypeCustData( + ITypeInfo2* iface, /* [I] The TypeInfo in which to find the custom data. */ + UINT index, /* [I] The index of the implemented type for which to retrieve the custom data. */ + CUSTDATA* pCustData) /* [O] A pointer to the custom data. */ +{ + FIXME("(%p,%d,%p), stub!\n", iface, index, pCustData); + return E_OUTOFMEMORY; +} + + +/*================== ICreateTypeInfo2 & ITypeInfo2 VTABLEs And Creation ===================================*/ + +static ICreateTypeInfo2Vtbl ctypeinfo2vt = +{ + + ICreateTypeInfo2_fnQueryInterface, + ICreateTypeInfo2_fnAddRef, + ICreateTypeInfo2_fnRelease, + + ICreateTypeInfo2_fnSetGuid, + ICreateTypeInfo2_fnSetTypeFlags, + ICreateTypeInfo2_fnSetDocString, + ICreateTypeInfo2_fnSetHelpContext, + ICreateTypeInfo2_fnSetVersion, + ICreateTypeInfo2_fnAddRefTypeInfo, + ICreateTypeInfo2_fnAddFuncDesc, + ICreateTypeInfo2_fnAddImplType, + ICreateTypeInfo2_fnSetImplTypeFlags, + ICreateTypeInfo2_fnSetAlignment, + ICreateTypeInfo2_fnSetSchema, + ICreateTypeInfo2_fnAddVarDesc, + ICreateTypeInfo2_fnSetFuncAndParamNames, + ICreateTypeInfo2_fnSetVarName, + ICreateTypeInfo2_fnSetTypeDescAlias, + ICreateTypeInfo2_fnDefineFuncAsDllEntry, + ICreateTypeInfo2_fnSetFuncDocString, + ICreateTypeInfo2_fnSetVarDocString, + ICreateTypeInfo2_fnSetFuncHelpContext, + ICreateTypeInfo2_fnSetVarHelpContext, + ICreateTypeInfo2_fnSetMops, + ICreateTypeInfo2_fnSetTypeIdldesc, + ICreateTypeInfo2_fnLayOut, + + ICreateTypeInfo2_fnDeleteFuncDesc, + ICreateTypeInfo2_fnDeleteFuncDescByMemId, + ICreateTypeInfo2_fnDeleteVarDesc, + ICreateTypeInfo2_fnDeleteVarDescByMemId, + ICreateTypeInfo2_fnDeleteImplType, + ICreateTypeInfo2_fnSetCustData, + ICreateTypeInfo2_fnSetFuncCustData, + ICreateTypeInfo2_fnSetParamCustData, + ICreateTypeInfo2_fnSetVarCustData, + ICreateTypeInfo2_fnSetImplTypeCustData, + ICreateTypeInfo2_fnSetHelpStringContext, + ICreateTypeInfo2_fnSetFuncHelpStringContext, + ICreateTypeInfo2_fnSetVarHelpStringContext, + ICreateTypeInfo2_fnInvalidate, + ICreateTypeInfo2_fnSetName +}; + +static ITypeInfo2Vtbl typeinfo2vt = +{ + + ITypeInfo2_fnQueryInterface, + ITypeInfo2_fnAddRef, + ITypeInfo2_fnRelease, + + ITypeInfo2_fnGetTypeAttr, + ITypeInfo2_fnGetTypeComp, + ITypeInfo2_fnGetFuncDesc, + ITypeInfo2_fnGetVarDesc, + ITypeInfo2_fnGetNames, + ITypeInfo2_fnGetRefTypeOfImplType, + ITypeInfo2_fnGetImplTypeFlags, + ITypeInfo2_fnGetIDsOfNames, + ITypeInfo2_fnInvoke, + ITypeInfo2_fnGetDocumentation, + ITypeInfo2_fnGetDllEntry, + ITypeInfo2_fnGetRefTypeInfo, + ITypeInfo2_fnAddressOfMember, + ITypeInfo2_fnCreateInstance, + ITypeInfo2_fnGetMops, + ITypeInfo2_fnGetContainingTypeLib, + ITypeInfo2_fnReleaseTypeAttr, + ITypeInfo2_fnReleaseFuncDesc, + ITypeInfo2_fnReleaseVarDesc, + + ITypeInfo2_fnGetTypeKind, + ITypeInfo2_fnGetTypeFlags, + ITypeInfo2_fnGetFuncIndexOfMemId, + ITypeInfo2_fnGetVarIndexOfMemId, + ITypeInfo2_fnGetCustData, + ITypeInfo2_fnGetFuncCustData, + ITypeInfo2_fnGetParamCustData, + ITypeInfo2_fnGetVarCustData, + ITypeInfo2_fnGetImplTypeCustData, + ITypeInfo2_fnGetDocumentation2, + ITypeInfo2_fnGetAllCustData, + ITypeInfo2_fnGetAllFuncCustData, + ITypeInfo2_fnGetAllParamCustData, + ITypeInfo2_fnGetAllVarCustData, + ITypeInfo2_fnGetAllImplTypeCustData, +}; + +static ICreateTypeInfo2 *ICreateTypeInfo2_Constructor(ICreateTypeLib2Impl *typelib, WCHAR *szName, TYPEKIND tkind) +{ + ICreateTypeInfo2Impl *pCreateTypeInfo2Impl; + + int nameoffset; + int typeinfo_offset; + MSFT_TypeInfoBase *typeinfo; + + TRACE("Constructing ICreateTypeInfo2 for %s with tkind %d\n", debugstr_w(szName), tkind); + + pCreateTypeInfo2Impl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ICreateTypeInfo2Impl)); + if (!pCreateTypeInfo2Impl) return NULL; + + pCreateTypeInfo2Impl->lpVtbl = &ctypeinfo2vt; + pCreateTypeInfo2Impl->lpVtblTypeInfo2 = &typeinfo2vt; + pCreateTypeInfo2Impl->ref = 1; + + pCreateTypeInfo2Impl->typelib = typelib; + typelib->ref++; + + nameoffset = ctl2_alloc_name(typelib, szName); + typeinfo_offset = ctl2_alloc_typeinfo(typelib, nameoffset); + typeinfo = (MSFT_TypeInfoBase *)&typelib->typelib_segment_data[MSFT_SEG_TYPEINFO][typeinfo_offset]; + + typelib->typelib_segment_data[MSFT_SEG_NAME][nameoffset + 9] = 0x38; + *((int *)&typelib->typelib_segment_data[MSFT_SEG_NAME][nameoffset]) = typeinfo_offset; + + pCreateTypeInfo2Impl->typeinfo = typeinfo; + + typeinfo->typekind |= tkind | 0x20; + ICreateTypeInfo2_SetAlignment((ICreateTypeInfo2 *)pCreateTypeInfo2Impl, 4); + + switch (tkind) { + case TKIND_ENUM: + case TKIND_INTERFACE: + case TKIND_DISPATCH: + case TKIND_COCLASS: + typeinfo->size = 4; + break; + + case TKIND_RECORD: + case TKIND_UNION: + typeinfo->size = 0; + break; + + case TKIND_MODULE: + typeinfo->size = 2; + break; + + case TKIND_ALIAS: + typeinfo->size = -0x75; + break; + + default: + FIXME("(%s,%d), unrecognized typekind %d\n", debugstr_w(szName), tkind, tkind); + typeinfo->size = 0xdeadbeef; + break; + } + + if (typelib->last_typeinfo) typelib->last_typeinfo->next_typeinfo = pCreateTypeInfo2Impl; + typelib->last_typeinfo = pCreateTypeInfo2Impl; + if (!typelib->typeinfos) typelib->typeinfos = pCreateTypeInfo2Impl; + + TRACE(" -- %p\n", pCreateTypeInfo2Impl); + + return (ICreateTypeInfo2 *)pCreateTypeInfo2Impl; +} + + +/*================== ICreateTypeLib2 Implementation ===================================*/ + +/****************************************************************************** + * ICreateTypeLib2_QueryInterface {OLEAUT32} + * + * See IUnknown_QueryInterface. + */ +static HRESULT WINAPI ICreateTypeLib2_fnQueryInterface( + ICreateTypeLib2 * iface, + REFIID riid, + VOID **ppvObject) +{ + ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; + + TRACE("(%p)->(IID: %s)\n",This,debugstr_guid(riid)); + + *ppvObject=NULL; + if(IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid,&IID_ICreateTypeLib)|| + IsEqualIID(riid,&IID_ICreateTypeLib2)) + { + *ppvObject = This; + } else if (IsEqualIID(riid, &IID_ITypeLib) || + IsEqualIID(riid, &IID_ITypeLib2)) { + *ppvObject = &This->lpVtblTypeLib2; + } + + if(*ppvObject) + { + ICreateTypeLib2_AddRef(iface); + TRACE("-- Interface: (%p)->(%p)\n",ppvObject,*ppvObject); + return S_OK; + } + TRACE("-- Interface: E_NOINTERFACE\n"); + return E_NOINTERFACE; +} + +/****************************************************************************** + * ICreateTypeLib2_AddRef {OLEAUT32} + * + * See IUnknown_AddRef. + */ +static ULONG WINAPI ICreateTypeLib2_fnAddRef(ICreateTypeLib2 *iface) +{ + ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p)->ref was %lu\n",This, ref - 1); + + return ref; +} + +/****************************************************************************** + * ICreateTypeLib2_Release {OLEAUT32} + * + * See IUnknown_Release. + */ +static ULONG WINAPI ICreateTypeLib2_fnRelease(ICreateTypeLib2 *iface) +{ + ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(%lu)\n",This, ref); + + if (!ref) { + int i; + + for (i = 0; i < MSFT_SEG_MAX; i++) { + HeapFree(GetProcessHeap(), 0, This->typelib_segment_data[i]); + This->typelib_segment_data[i] = NULL; + } + + HeapFree(GetProcessHeap(), 0, This->filename); + This->filename = NULL; + + while (This->typeinfos) { + ICreateTypeInfo2Impl *typeinfo = This->typeinfos; + This->typeinfos = typeinfo->next_typeinfo; + HeapFree(GetProcessHeap(), 0, typeinfo->typedata); + HeapFree(GetProcessHeap(), 0, typeinfo); + } + + HeapFree(GetProcessHeap(),0,This); + return 0; + } + + return ref; +} + + +/****************************************************************************** + * ICreateTypeLib2_CreateTypeInfo {OLEAUT32} + * + * See ICreateTypeLib_CreateTypeInfo. + */ +static HRESULT WINAPI ICreateTypeLib2_fnCreateTypeInfo( + ICreateTypeLib2 * iface, + LPOLESTR szName, + TYPEKIND tkind, + ICreateTypeInfo **ppCTInfo) +{ + ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; + + TRACE("(%p,%s,%d,%p)\n", iface, debugstr_w(szName), tkind, ppCTInfo); + + *ppCTInfo = (ICreateTypeInfo *)ICreateTypeInfo2_Constructor(This, szName, tkind); + + if (!*ppCTInfo) return E_OUTOFMEMORY; + + return S_OK; +} + +/****************************************************************************** + * ICreateTypeLib2_SetName {OLEAUT32} + * + * See ICreateTypeLib_SetName. + */ +static HRESULT WINAPI ICreateTypeLib2_fnSetName( + ICreateTypeLib2 * iface, + LPOLESTR szName) +{ + ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; + + int offset; + + TRACE("(%p,%s)\n", iface, debugstr_w(szName)); + + offset = ctl2_alloc_name(This, szName); + if (offset == -1) return E_OUTOFMEMORY; + This->typelib_header.NameOffset = offset; + return S_OK; +} + +/****************************************************************************** + * ICreateTypeLib2_SetVersion {OLEAUT32} + * + * See ICreateTypeLib_SetVersion. + */ +static HRESULT WINAPI ICreateTypeLib2_fnSetVersion(ICreateTypeLib2 * iface, WORD wMajorVerNum, WORD wMinorVerNum) +{ + ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; + + TRACE("(%p,%d,%d)\n", iface, wMajorVerNum, wMinorVerNum); + + This->typelib_header.version = wMajorVerNum | (wMinorVerNum << 16); + return S_OK; +} + +/****************************************************************************** + * ICreateTypeLib2_SetGuid {OLEAUT32} + * + * See ICreateTypeLib_SetGuid. + */ +static HRESULT WINAPI ICreateTypeLib2_fnSetGuid(ICreateTypeLib2 * iface, REFGUID guid) +{ + ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; + + MSFT_GuidEntry guidentry; + int offset; + + TRACE("(%p,%s)\n", iface, debugstr_guid(guid)); + + guidentry.guid = *guid; + guidentry.hreftype = -2; + guidentry.next_hash = -1; + + offset = ctl2_alloc_guid(This, &guidentry); + + if (offset == -1) return E_OUTOFMEMORY; + + This->typelib_header.posguid = offset; + + return S_OK; +} + +/****************************************************************************** + * ICreateTypeLib2_SetDocString {OLEAUT32} + * + * See ICreateTypeLib_SetDocString. + */ +static HRESULT WINAPI ICreateTypeLib2_fnSetDocString(ICreateTypeLib2 * iface, LPOLESTR szDoc) +{ + ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; + + int offset; + + TRACE("(%p,%s)\n", iface, debugstr_w(szDoc)); + + offset = ctl2_alloc_string(This, szDoc); + if (offset == -1) return E_OUTOFMEMORY; + This->typelib_header.helpstring = offset; + return S_OK; +} + +/****************************************************************************** + * ICreateTypeLib2_SetHelpFileName {OLEAUT32} + * + * See ICreateTypeLib_SetHelpFileName. + */ +static HRESULT WINAPI ICreateTypeLib2_fnSetHelpFileName(ICreateTypeLib2 * iface, LPOLESTR szHelpFileName) +{ + ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; + + int offset; + + TRACE("(%p,%s)\n", iface, debugstr_w(szHelpFileName)); + + offset = ctl2_alloc_string(This, szHelpFileName); + if (offset == -1) return E_OUTOFMEMORY; + This->typelib_header.helpfile = offset; + This->typelib_header.varflags |= 0x10; + return S_OK; +} + +/****************************************************************************** + * ICreateTypeLib2_SetHelpContext {OLEAUT32} + * + * See ICreateTypeLib_SetHelpContext. + */ +static HRESULT WINAPI ICreateTypeLib2_fnSetHelpContext(ICreateTypeLib2 * iface, DWORD dwHelpContext) +{ + FIXME("(%p,%ld), stub!\n", iface, dwHelpContext); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeLib2_SetLcid {OLEAUT32} + * + * See ICreateTypeLib_SetLcid. + */ +static HRESULT WINAPI ICreateTypeLib2_fnSetLcid(ICreateTypeLib2 * iface, LCID lcid) +{ + ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; + + TRACE("(%p,%ld)\n", iface, lcid); + + This->typelib_header.lcid2 = lcid; + + return S_OK; +} + +/****************************************************************************** + * ICreateTypeLib2_SetLibFlags {OLEAUT32} + * + * See ICreateTypeLib_SetLibFlags. + */ +static HRESULT WINAPI ICreateTypeLib2_fnSetLibFlags(ICreateTypeLib2 * iface, UINT uLibFlags) +{ + ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; + + TRACE("(%p,0x%x)\n", iface, uLibFlags); + + This->typelib_header.flags = uLibFlags; + + return S_OK; +} + +static int ctl2_write_chunk(HANDLE hFile, void *segment, int length) +{ + DWORD dwWritten; + if (!WriteFile(hFile, segment, length, &dwWritten, 0)) { + CloseHandle(hFile); + return 0; + } + return -1; +} + +static int ctl2_write_segment(ICreateTypeLib2Impl *This, HANDLE hFile, int segment) +{ + DWORD dwWritten; + if (!WriteFile(hFile, This->typelib_segment_data[segment], + This->typelib_segdir[segment].length, &dwWritten, 0)) { + CloseHandle(hFile); + return 0; + } + + return -1; +} + +static void ctl2_finalize_typeinfos(ICreateTypeLib2Impl *This, int filesize) +{ + ICreateTypeInfo2Impl *typeinfo; + + for (typeinfo = This->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) { + typeinfo->typeinfo->memoffset = filesize; + if (typeinfo->typedata) { + ICreateTypeInfo2_fnLayOut((ICreateTypeInfo2 *)typeinfo); + filesize += typeinfo->typedata[0] + ((typeinfo->typeinfo->cElement >> 16) * 12) + ((typeinfo->typeinfo->cElement & 0xffff) * 12) + 4; + } + } +} + +static int ctl2_finalize_segment(ICreateTypeLib2Impl *This, int filepos, int segment) +{ + if (This->typelib_segdir[segment].length) { + This->typelib_segdir[segment].offset = filepos; + } else { + This->typelib_segdir[segment].offset = -1; + } + + return This->typelib_segdir[segment].length; +} + +static void ctl2_write_typeinfos(ICreateTypeLib2Impl *This, HANDLE hFile) +{ + ICreateTypeInfo2Impl *typeinfo; + + for (typeinfo = This->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) { + if (!typeinfo->typedata) continue; + + ctl2_write_chunk(hFile, typeinfo->typedata, typeinfo->typedata[0] + 4); + ctl2_write_chunk(hFile, typeinfo->indices, ((typeinfo->typeinfo->cElement & 0xffff) + (typeinfo->typeinfo->cElement >> 16)) * 4); + ctl2_write_chunk(hFile, typeinfo->names, ((typeinfo->typeinfo->cElement & 0xffff) + (typeinfo->typeinfo->cElement >> 16)) * 4); + ctl2_write_chunk(hFile, typeinfo->offsets, ((typeinfo->typeinfo->cElement & 0xffff) + (typeinfo->typeinfo->cElement >> 16)) * 4); + } +} + +/****************************************************************************** + * ICreateTypeLib2_SaveAllChanges {OLEAUT32} + * + * See ICreateTypeLib_SaveAllChanges. + */ +static HRESULT WINAPI ICreateTypeLib2_fnSaveAllChanges(ICreateTypeLib2 * iface) +{ + ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; + + int retval; + int filepos; + HANDLE hFile; + + TRACE("(%p)\n", iface); + + retval = TYPE_E_IOERROR; + + hFile = CreateFileW(This->filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (hFile == INVALID_HANDLE_VALUE) return retval; + + filepos = sizeof(MSFT_Header) + sizeof(MSFT_SegDir); + filepos += This->typelib_header.nrtypeinfos * 4; + + filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_TYPEINFO); + filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_GUIDHASH); + filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_GUID); + filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_IMPORTINFO); + filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_IMPORTFILES); + filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_REFERENCES); + filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_NAMEHASH); + filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_NAME); + filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_STRING); + filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_TYPEDESC); + filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_ARRAYDESC); + filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_CUSTDATA); + filepos += ctl2_finalize_segment(This, filepos, MSFT_SEG_CUSTDATAGUID); + + ctl2_finalize_typeinfos(This, filepos); + + if (!ctl2_write_chunk(hFile, &This->typelib_header, sizeof(This->typelib_header))) return retval; + if (!ctl2_write_chunk(hFile, This->typelib_typeinfo_offsets, This->typelib_header.nrtypeinfos * 4)) return retval; + if (!ctl2_write_chunk(hFile, &This->typelib_segdir, sizeof(This->typelib_segdir))) return retval; + if (!ctl2_write_segment(This, hFile, MSFT_SEG_TYPEINFO )) return retval; + if (!ctl2_write_segment(This, hFile, MSFT_SEG_GUIDHASH )) return retval; + if (!ctl2_write_segment(This, hFile, MSFT_SEG_GUID )) return retval; + if (!ctl2_write_segment(This, hFile, MSFT_SEG_IMPORTINFO )) return retval; + if (!ctl2_write_segment(This, hFile, MSFT_SEG_IMPORTFILES )) return retval; + if (!ctl2_write_segment(This, hFile, MSFT_SEG_REFERENCES )) return retval; + if (!ctl2_write_segment(This, hFile, MSFT_SEG_NAMEHASH )) return retval; + if (!ctl2_write_segment(This, hFile, MSFT_SEG_NAME )) return retval; + if (!ctl2_write_segment(This, hFile, MSFT_SEG_STRING )) return retval; + if (!ctl2_write_segment(This, hFile, MSFT_SEG_TYPEDESC )) return retval; + if (!ctl2_write_segment(This, hFile, MSFT_SEG_ARRAYDESC )) return retval; + if (!ctl2_write_segment(This, hFile, MSFT_SEG_CUSTDATA )) return retval; + if (!ctl2_write_segment(This, hFile, MSFT_SEG_CUSTDATAGUID)) return retval; + + ctl2_write_typeinfos(This, hFile); + + if (!CloseHandle(hFile)) return retval; + + retval = S_OK; + return retval; +} + + +/****************************************************************************** + * ICreateTypeLib2_DeleteTypeInfo {OLEAUT32} + * + * Deletes a named TypeInfo from a type library. + * + * RETURNS + * + * Success: S_OK + * Failure: E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ICreateTypeLib2_fnDeleteTypeInfo( + ICreateTypeLib2 * iface, /* [I] The type library to delete from. */ + LPOLESTR szName) /* [I] The name of the typeinfo to delete. */ +{ + FIXME("(%p,%s), stub!\n", iface, debugstr_w(szName)); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeLib2_SetCustData {OLEAUT32} + * + * Sets custom data for a type library. + * + * RETURNS + * + * Success: S_OK + * Failure: E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ICreateTypeLib2_fnSetCustData( + ICreateTypeLib2 * iface, /* [I] The type library to store the custom data in. */ + REFGUID guid, /* [I] The GUID used as a key to retrieve the custom data. */ + VARIANT *pVarVal) /* [I] The custom data itself. */ +{ + ICreateTypeLib2Impl *This = (ICreateTypeLib2Impl *)iface; + + TRACE("(%p,%s,%p)\n", iface, debugstr_guid(guid), pVarVal); + + return ctl2_set_custdata(This, guid, pVarVal, &This->typelib_header.CustomDataOffset); +} + +/****************************************************************************** + * ICreateTypeLib2_SetHelpStringContext {OLEAUT32} + * + * Sets a context number for the library help string. + * + * RETURNS + * + * Success: S_OK + * Failure: E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ICreateTypeLib2_fnSetHelpStringContext( + ICreateTypeLib2 * iface, /* [I] The type library to set the help string context for. */ + ULONG dwHelpStringContext) /* [I] The help string context. */ +{ + FIXME("(%p,%ld), stub!\n", iface, dwHelpStringContext); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeLib2_SetHelpStringDll {OLEAUT32} + * + * Sets the DLL used to look up localized help strings. + * + * RETURNS + * + * Success: S_OK + * Failure: E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ICreateTypeLib2_fnSetHelpStringDll( + ICreateTypeLib2 * iface, /* [I] The type library to set the help DLL for. */ + LPOLESTR szFileName) /* [I] The name of the help DLL. */ +{ + FIXME("(%p,%s), stub!\n", iface, debugstr_w(szFileName)); + return E_OUTOFMEMORY; +} + +/*================== ITypeLib2 Implementation ===================================*/ + +/****************************************************************************** + * ITypeLib2_QueryInterface {OLEAUT32} + * + * See IUnknown_QueryInterface. + */ +static HRESULT WINAPI ITypeLib2_fnQueryInterface(ITypeLib2 * iface, REFIID riid, LPVOID * ppv) +{ + ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); + + return ICreateTypeLib2_QueryInterface((ICreateTypeLib2 *)This, riid, ppv); +} + +/****************************************************************************** + * ITypeLib2_AddRef {OLEAUT32} + * + * See IUnknown_AddRef. + */ +static ULONG WINAPI ITypeLib2_fnAddRef(ITypeLib2 * iface) +{ + ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); + + return ICreateTypeLib2_AddRef((ICreateTypeLib2 *)This); +} + +/****************************************************************************** + * ITypeLib2_Release {OLEAUT32} + * + * See IUnknown_Release. + */ +static ULONG WINAPI ITypeLib2_fnRelease(ITypeLib2 * iface) +{ + ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); + + return ICreateTypeLib2_Release((ICreateTypeLib2 *)This); +} + +/****************************************************************************** + * ITypeLib2_GetTypeInfoCount {OLEAUT32} + * + * See ITypeLib_GetTypeInfoCount. + */ +static UINT WINAPI ITypeLib2_fnGetTypeInfoCount( + ITypeLib2 * iface) +{ + ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); + + TRACE("(%p)\n", iface); + + return This->typelib_header.nrtypeinfos; +} + +/****************************************************************************** + * ITypeLib2_GetTypeInfo {OLEAUT32} + * + * See ITypeLib_GetTypeInfo. + */ +static HRESULT WINAPI ITypeLib2_fnGetTypeInfo( + ITypeLib2 * iface, + UINT index, + ITypeInfo** ppTInfo) +{ + ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); + + TRACE("(%p,%d,%p)\n", iface, index, ppTInfo); + + if ((index < 0) || (index >= This->typelib_header.nrtypeinfos)) { + return TYPE_E_ELEMENTNOTFOUND; + } + + return ctl2_find_typeinfo_from_offset(This, This->typelib_typeinfo_offsets[index], ppTInfo); +} + +/****************************************************************************** + * ITypeLib2_GetTypeInfoType {OLEAUT32} + * + * See ITypeLib_GetTypeInfoType. + */ +static HRESULT WINAPI ITypeLib2_fnGetTypeInfoType( + ITypeLib2 * iface, + UINT index, + TYPEKIND* pTKind) +{ + ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); + + TRACE("(%p,%d,%p)\n", iface, index, pTKind); + + if ((index < 0) || (index >= This->typelib_header.nrtypeinfos)) { + return TYPE_E_ELEMENTNOTFOUND; + } + + *pTKind = (This->typelib_segment_data[MSFT_SEG_TYPEINFO][This->typelib_typeinfo_offsets[index]]) & 15; + + return S_OK; +} + +/****************************************************************************** + * ITypeLib2_GetTypeInfoOfGuid {OLEAUT32} + * + * See ITypeLib_GetTypeInfoOfGuid. + */ +static HRESULT WINAPI ITypeLib2_fnGetTypeInfoOfGuid( + ITypeLib2 * iface, + REFGUID guid, + ITypeInfo** ppTinfo) +{ + ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); + + int guidoffset; + int typeinfo; + + TRACE("(%p,%s,%p)\n", iface, debugstr_guid(guid), ppTinfo); + + guidoffset = ctl2_find_guid(This, ctl2_hash_guid(guid), guid); + if (guidoffset == -1) return TYPE_E_ELEMENTNOTFOUND; + + typeinfo = ((MSFT_GuidEntry *)&This->typelib_segment_data[MSFT_SEG_GUID][guidoffset])->hreftype; + if (typeinfo < 0) return TYPE_E_ELEMENTNOTFOUND; + + return ctl2_find_typeinfo_from_offset(This, typeinfo, ppTinfo); +} + +/****************************************************************************** + * ITypeLib2_GetLibAttr {OLEAUT32} + * + * See ITypeLib_GetLibAttr. + */ +static HRESULT WINAPI ITypeLib2_fnGetLibAttr( + ITypeLib2 * iface, + TLIBATTR** ppTLibAttr) +{ +/* ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); */ + + FIXME("(%p,%p), stub!\n", iface, ppTLibAttr); + + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeLib2_GetTypeComp {OLEAUT32} + * + * See ITypeLib_GetTypeComp. + */ +static HRESULT WINAPI ITypeLib2_fnGetTypeComp( + ITypeLib2 * iface, + ITypeComp** ppTComp) +{ +/* ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); */ + + FIXME("(%p,%p), stub!\n", iface, ppTComp); + + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeLib2_GetDocumentation {OLEAUT32} + * + * See ITypeLib_GetDocumentation. + */ +static HRESULT WINAPI ITypeLib2_fnGetDocumentation( + ITypeLib2 * iface, + INT index, + BSTR* pBstrName, + BSTR* pBstrDocString, + DWORD* pdwHelpContext, + BSTR* pBstrHelpFile) +{ +/* ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); */ + + FIXME("(%p,%d,%p,%p,%p,%p), stub!\n", iface, index, pBstrName, pBstrDocString, pdwHelpContext, pBstrHelpFile); + + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeLib2_IsName {OLEAUT32} + * + * See ITypeLib_IsName. + */ +static HRESULT WINAPI ITypeLib2_fnIsName( + ITypeLib2 * iface, + LPOLESTR szNameBuf, + ULONG lHashVal, + BOOL* pfName) +{ + ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); + + char *encoded_name; + int nameoffset; + MSFT_NameIntro *nameintro; + + TRACE("(%p,%s,%lx,%p)\n", iface, debugstr_w(szNameBuf), lHashVal, pfName); + + ctl2_encode_name(This, szNameBuf, &encoded_name); + nameoffset = ctl2_find_name(This, encoded_name); + + *pfName = 0; + + if (nameoffset == -1) return S_OK; + + nameintro = (MSFT_NameIntro *)(&This->typelib_segment_data[MSFT_SEG_NAME][nameoffset]); + if (nameintro->hreftype == -1) return S_OK; + + *pfName = 1; + + FIXME("Should be decoding our copy of the name over szNameBuf.\n"); + + return S_OK; +} + +/****************************************************************************** + * ITypeLib2_FindName {OLEAUT32} + * + * See ITypeLib_FindName. + */ +static HRESULT WINAPI ITypeLib2_fnFindName( + ITypeLib2 * iface, + LPOLESTR szNameBuf, + ULONG lHashVal, + ITypeInfo** ppTInfo, + MEMBERID* rgMemId, + USHORT* pcFound) +{ +/* ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); */ + + FIXME("(%p,%s,%lx,%p,%p,%p), stub!\n", iface, debugstr_w(szNameBuf), lHashVal, ppTInfo, rgMemId, pcFound); + + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ITypeLib2_ReleaseTLibAttr {OLEAUT32} + * + * See ITypeLib_ReleaseTLibAttr. + */ +static void WINAPI ITypeLib2_fnReleaseTLibAttr( + ITypeLib2 * iface, + TLIBATTR* pTLibAttr) +{ +/* ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); */ + + FIXME("(%p,%p), stub!\n", iface, pTLibAttr); +} + +/****************************************************************************** + * ICreateTypeLib2_GetCustData {OLEAUT32} + * + * Retrieves a custom data value stored on a type library. + * + * RETURNS + * + * Success: S_OK + * Failure: E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ITypeLib2_fnGetCustData( + ITypeLib2 * iface, /* [I] The type library in which to find the custom data. */ + REFGUID guid, /* [I] The GUID under which the custom data is stored. */ + VARIANT* pVarVal) /* [O] The custom data. */ +{ +/* ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); */ + + FIXME("(%p,%s,%p), stub!\n", iface, debugstr_guid(guid), pVarVal); + + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeLib2_GetLibStatistics {OLEAUT32} + * + * Retrieves some statistics about names in a type library, supposedly for + * hash table optimization purposes. + * + * RETURNS + * + * Success: S_OK + * Failure: E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ITypeLib2_fnGetLibStatistics( + ITypeLib2 * iface, /* [I] The type library to get statistics about. */ + ULONG* pcUniqueNames, /* [O] The number of unique names in the type library. */ + ULONG* pcchUniqueNames) /* [O] The number of changed (?) characters in names in the type library. */ +{ +/* ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); */ + + FIXME("(%p,%p,%p), stub!\n", iface, pcUniqueNames, pcchUniqueNames); + + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeLib2_GetDocumentation2 {OLEAUT32} + * + * Obtain locale-aware help string information. + * + * RETURNS + * + * Success: S_OK + * Failure: STG_E_INSUFFICIENTMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ITypeLib2_fnGetDocumentation2( + ITypeLib2 * iface, + INT index, + LCID lcid, + BSTR* pbstrHelpString, + DWORD* pdwHelpStringContext, + BSTR* pbstrHelpStringDll) +{ +/* ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); */ + + FIXME("(%p,%d,%ld,%p,%p,%p), stub!\n", iface, index, lcid, pbstrHelpString, pdwHelpStringContext, pbstrHelpStringDll); + + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * ICreateTypeLib2_GetAllCustData {OLEAUT32} + * + * Retrieve all of the custom data for a type library. + * + * RETURNS + * + * Success: S_OK + * Failure: E_OUTOFMEMORY or E_INVALIDARG. + */ +static HRESULT WINAPI ITypeLib2_fnGetAllCustData( + ITypeLib2 * iface, /* [I] The type library in which to find the custom data. */ + CUSTDATA* pCustData) /* [O] The structure in which to place the custom data. */ +{ +/* ICOM_THIS_From_ITypeLib2(ICreateTypeLib2Impl, iface); */ + + FIXME("(%p,%p), stub!\n", iface, pCustData); + + return E_OUTOFMEMORY; +} + + +/*================== ICreateTypeLib2 & ITypeLib2 VTABLEs And Creation ===================================*/ + +static ICreateTypeLib2Vtbl ctypelib2vt = +{ + + ICreateTypeLib2_fnQueryInterface, + ICreateTypeLib2_fnAddRef, + ICreateTypeLib2_fnRelease, + + ICreateTypeLib2_fnCreateTypeInfo, + ICreateTypeLib2_fnSetName, + ICreateTypeLib2_fnSetVersion, + ICreateTypeLib2_fnSetGuid, + ICreateTypeLib2_fnSetDocString, + ICreateTypeLib2_fnSetHelpFileName, + ICreateTypeLib2_fnSetHelpContext, + ICreateTypeLib2_fnSetLcid, + ICreateTypeLib2_fnSetLibFlags, + ICreateTypeLib2_fnSaveAllChanges, + + ICreateTypeLib2_fnDeleteTypeInfo, + ICreateTypeLib2_fnSetCustData, + ICreateTypeLib2_fnSetHelpStringContext, + ICreateTypeLib2_fnSetHelpStringDll +}; + +static ITypeLib2Vtbl typelib2vt = +{ + + ITypeLib2_fnQueryInterface, + ITypeLib2_fnAddRef, + ITypeLib2_fnRelease, + + ITypeLib2_fnGetTypeInfoCount, + ITypeLib2_fnGetTypeInfo, + ITypeLib2_fnGetTypeInfoType, + ITypeLib2_fnGetTypeInfoOfGuid, + ITypeLib2_fnGetLibAttr, + ITypeLib2_fnGetTypeComp, + ITypeLib2_fnGetDocumentation, + ITypeLib2_fnIsName, + ITypeLib2_fnFindName, + ITypeLib2_fnReleaseTLibAttr, + + ITypeLib2_fnGetCustData, + ITypeLib2_fnGetLibStatistics, + ITypeLib2_fnGetDocumentation2, + ITypeLib2_fnGetAllCustData, +}; + +static ICreateTypeLib2 *ICreateTypeLib2_Constructor(SYSKIND syskind, LPCOLESTR szFile) +{ + ICreateTypeLib2Impl *pCreateTypeLib2Impl; + int failed = 0; + + TRACE("Constructing ICreateTypeLib2 (%d, %s)\n", syskind, debugstr_w(szFile)); + + pCreateTypeLib2Impl = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ICreateTypeLib2Impl)); + if (!pCreateTypeLib2Impl) return NULL; + + pCreateTypeLib2Impl->filename = HeapAlloc(GetProcessHeap(), 0, (strlenW(szFile) + 1) * sizeof(WCHAR)); + if (!pCreateTypeLib2Impl->filename) { + HeapFree(GetProcessHeap(), 0, pCreateTypeLib2Impl); + return NULL; + } + strcpyW(pCreateTypeLib2Impl->filename, szFile); + + ctl2_init_header(pCreateTypeLib2Impl); + ctl2_init_segdir(pCreateTypeLib2Impl); + + pCreateTypeLib2Impl->typelib_header.varflags |= syskind; + + /* + * The following two calls return an offset or -1 if out of memory. We + * specifically need an offset of 0, however, so... + */ + if (ctl2_alloc_segment(pCreateTypeLib2Impl, MSFT_SEG_GUIDHASH, 0x80, 0x80)) { failed = 1; } + if (ctl2_alloc_segment(pCreateTypeLib2Impl, MSFT_SEG_NAMEHASH, 0x200, 0x200)) { failed = 1; } + + pCreateTypeLib2Impl->typelib_guidhash_segment = (int *)pCreateTypeLib2Impl->typelib_segment_data[MSFT_SEG_GUIDHASH]; + pCreateTypeLib2Impl->typelib_namehash_segment = (int *)pCreateTypeLib2Impl->typelib_segment_data[MSFT_SEG_NAMEHASH]; + + memset(pCreateTypeLib2Impl->typelib_guidhash_segment, 0xff, 0x80); + memset(pCreateTypeLib2Impl->typelib_namehash_segment, 0xff, 0x200); + + pCreateTypeLib2Impl->lpVtbl = &ctypelib2vt; + pCreateTypeLib2Impl->lpVtblTypeLib2 = &typelib2vt; + pCreateTypeLib2Impl->ref = 1; + + if (failed) { + ICreateTypeLib2_fnRelease((ICreateTypeLib2 *)pCreateTypeLib2Impl); + return 0; + } + + return (ICreateTypeLib2 *)pCreateTypeLib2Impl; +} + +/****************************************************************************** + * CreateTypeLib2 [OLEAUT32.180] + * + * Obtains an ICreateTypeLib2 object for creating a new-style (MSFT) type + * library. + * + * NOTES + * + * See also CreateTypeLib. + * + * RETURNS + * Success: S_OK + * Failure: Status + */ +HRESULT WINAPI CreateTypeLib2( + SYSKIND syskind, /* [I] System type library is for */ + LPCOLESTR szFile, /* [I] Type library file name */ + ICreateTypeLib2** ppctlib) /* [O] Storage for object returned */ +{ + TRACE("(%d,%s,%p)\n", syskind, debugstr_w(szFile), ppctlib); + + if (!szFile) return E_INVALIDARG; + *ppctlib = ICreateTypeLib2_Constructor(syskind, szFile); + return (*ppctlib)? S_OK: E_OUTOFMEMORY; +} + +/****************************************************************************** + * ClearCustData (OLEAUT32.171) + * + * Clear a custom data types' data. + * + * PARAMS + * lpCust [I] The custom data type instance + * + * RETURNS + * Nothing. + */ +void WINAPI ClearCustData(LPCUSTDATA lpCust) +{ + if (lpCust && lpCust->cCustData) + { + if (lpCust->prgCustData) + { + DWORD i; + + for (i = 0; i < lpCust->cCustData; i++) + VariantClear(&lpCust->prgCustData[i].varValue); + + /* FIXME - Should be using a per-thread IMalloc */ + HeapFree(GetProcessHeap(), 0, lpCust->prgCustData); + lpCust->prgCustData = NULL; + } + lpCust->cCustData = 0; + } +} diff --git a/reactos/lib/oleaut32/usrmarshal.c b/reactos/lib/oleaut32/usrmarshal.c index 6eb87334c3a..eaddecc7550 100644 --- a/reactos/lib/oleaut32/usrmarshal.c +++ b/reactos/lib/oleaut32/usrmarshal.c @@ -1,1181 +1,1181 @@ -/* - * Misc marshalling routines - * - * Copyright 2002 Ove Kaaven - * Copyright 2003 Mike Hearn - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> -#include <string.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winerror.h" - -#include "ole2.h" -#include "oleauto.h" -#include "rpcproxy.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/* FIXME: not supposed to be here */ - -const CLSID CLSID_PSDispatch = { - 0x20420, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46} -}; - -static CStdPSFactoryBuffer PSFactoryBuffer; - -CSTDSTUBBUFFERRELEASE(&PSFactoryBuffer) - -extern const ExtendedProxyFileInfo oaidl_ProxyFileInfo; - -const ProxyFileInfo* OLEAUT32_ProxyFileList[] = { - &oaidl_ProxyFileInfo, - NULL -}; - -HRESULT OLEAUTPS_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) -{ - return NdrDllGetClassObject(rclsid, riid, ppv, OLEAUT32_ProxyFileList, - &CLSID_PSDispatch, &PSFactoryBuffer); -} - -/* CLEANLOCALSTORAGE */ -/* I'm not sure how this is supposed to work yet */ - -unsigned long WINAPI CLEANLOCALSTORAGE_UserSize(unsigned long *pFlags, unsigned long Start, CLEANLOCALSTORAGE *pstg) -{ - return Start + sizeof(DWORD); -} - -unsigned char * WINAPI CLEANLOCALSTORAGE_UserMarshal(unsigned long *pFlags, unsigned char *Buffer, CLEANLOCALSTORAGE *pstg) -{ - *(DWORD*)Buffer = 0; - return Buffer + sizeof(DWORD); -} - -unsigned char * WINAPI CLEANLOCALSTORAGE_UserUnmarshal(unsigned long *pFlags, unsigned char *Buffer, CLEANLOCALSTORAGE *pstr) -{ - return Buffer + sizeof(DWORD); -} - -void WINAPI CLEANLOCALSTORAGE_UserFree(unsigned long *pFlags, CLEANLOCALSTORAGE *pstr) -{ -} - -/* BSTR */ - -unsigned long WINAPI BSTR_UserSize(unsigned long *pFlags, unsigned long Start, BSTR *pstr) -{ - TRACE("(%lx,%ld,%p) => %p\n", *pFlags, Start, pstr, *pstr); - if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr)); - Start += sizeof(FLAGGED_WORD_BLOB) + sizeof(OLECHAR) * (SysStringLen(*pstr) - 1); - TRACE("returning %ld\n", Start); - return Start; -} - -unsigned char * WINAPI BSTR_UserMarshal(unsigned long *pFlags, unsigned char *Buffer, BSTR *pstr) -{ - wireBSTR str = (wireBSTR)Buffer; - - TRACE("(%lx,%p,%p) => %p\n", *pFlags, Buffer, pstr, *pstr); - if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr)); - str->fFlags = 0; - str->clSize = SysStringLen(*pstr); - if (str->clSize) - memcpy(&str->asData, *pstr, sizeof(OLECHAR) * str->clSize); - return Buffer + sizeof(FLAGGED_WORD_BLOB) + sizeof(OLECHAR) * (str->clSize - 1); -} - -unsigned char * WINAPI BSTR_UserUnmarshal(unsigned long *pFlags, unsigned char *Buffer, BSTR *pstr) -{ - wireBSTR str = (wireBSTR)Buffer; - TRACE("(%lx,%p,%p) => %p\n", *pFlags, Buffer, pstr, *pstr); - if (str->clSize) { - SysReAllocStringLen(pstr, (OLECHAR*)&str->asData, str->clSize); - } - else if (*pstr) { - SysFreeString(*pstr); - *pstr = NULL; - } - if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr)); - return Buffer + sizeof(FLAGGED_WORD_BLOB) + sizeof(OLECHAR) * (str->clSize - 1); -} - -void WINAPI BSTR_UserFree(unsigned long *pFlags, BSTR *pstr) -{ - TRACE("(%lx,%p) => %p\n", *pFlags, pstr, *pstr); - if (*pstr) { - SysFreeString(*pstr); - *pstr = NULL; - } -} - -/* VARIANT */ -/* I'm not too sure how to do this yet */ - -#define VARIANT_wiresize sizeof(struct _wireVARIANT) - -static unsigned wire_size(VARTYPE vt) -{ - if (vt & VT_ARRAY) return 0; - - switch (vt & ~VT_BYREF) { - case VT_EMPTY: - case VT_NULL: - return 0; - case VT_I1: - case VT_UI1: - return sizeof(CHAR); - case VT_I2: - case VT_UI2: - return sizeof(SHORT); - case VT_I4: - case VT_UI4: - return sizeof(LONG); - case VT_INT: - case VT_UINT: - return sizeof(INT); - case VT_R4: - return sizeof(FLOAT); - case VT_R8: - return sizeof(DOUBLE); - case VT_BOOL: - return sizeof(VARIANT_BOOL); - case VT_ERROR: - return sizeof(SCODE); - case VT_DATE: - return sizeof(DATE); - case VT_CY: - return sizeof(CY); - case VT_DECIMAL: - return sizeof(DECIMAL); - case VT_BSTR: - case VT_VARIANT: - case VT_UNKNOWN: - case VT_DISPATCH: - case VT_SAFEARRAY: - case VT_RECORD: - return 0; - default: - FIXME("unhandled VT %d\n", vt); - return 0; - } -} - -static unsigned wire_extra(unsigned long *pFlags, VARIANT *pvar) -{ - ULONG size; - HRESULT hr; - - if (V_ISARRAY(pvar)) { - FIXME("wire-size safearray\n"); - return 0; - } - switch (V_VT(pvar)) { - case VT_BSTR: - return BSTR_UserSize(pFlags, 0, &V_BSTR(pvar)); - case VT_BSTR | VT_BYREF: - return BSTR_UserSize(pFlags, 0, V_BSTRREF(pvar)); - case VT_SAFEARRAY: - case VT_SAFEARRAY | VT_BYREF: - FIXME("wire-size safearray\n"); - return 0; - case VT_VARIANT | VT_BYREF: - return VARIANT_UserSize(pFlags, 0, V_VARIANTREF(pvar)); - case VT_UNKNOWN: - case VT_DISPATCH: - /* find the buffer size of the marshalled dispatch interface */ - hr = CoGetMarshalSizeMax(&size, &IID_IDispatch, (IUnknown*)V_DISPATCH(pvar), LOWORD(*pFlags), NULL, MSHLFLAGS_NORMAL); - if (FAILED(hr)) { - ERR("Dispatch variant buffer size calculation failed, HRESULT=0x%lx\n", hr); - return 0; - } - size += sizeof(ULONG); /* we have to store the buffersize in the stream */ - TRACE("wire-size extra of dispatch variant is %ld\n", size); - return size; - case VT_RECORD: - FIXME("wire-size record\n"); - return 0; - default: - return 0; - } -} - -/* helper: called for VT_DISPATCH variants to marshal the IDispatch* into the buffer. returns Buffer on failure, new position otherwise */ -static unsigned char* dispatch_variant_marshal(unsigned long *pFlags, unsigned char *Buffer, VARIANT *pvar) { - IStream *working; - HGLOBAL working_mem; - void *working_memlocked; - unsigned char *oldpos; - ULONG size; - HRESULT hr; - - TRACE("pFlags=%ld, Buffer=%p, pvar=%p\n", *pFlags, Buffer, pvar); - - oldpos = Buffer; - - /* CoMarshalInterface needs a stream, whereas at this level we are operating in terms of buffers. - * We create a stream on an HGLOBAL, so we can simply do a memcpy to move it to the buffer. - * in rpcrt4/ndr_ole.c, a simple IStream implementation is wrapped around the buffer object, - * but that would be overkill here, hence this implementation. We save the size because the unmarshal - * code has no way to know how long the marshalled buffer is. */ - - size = wire_extra(pFlags, pvar); - - working_mem = GlobalAlloc(0, size); - if (!working_mem) return oldpos; - - hr = CreateStreamOnHGlobal(working_mem, TRUE, &working); - if (hr != S_OK) { - GlobalFree(working_mem); - return oldpos; - } - - hr = CoMarshalInterface(working, &IID_IDispatch, (IUnknown*)V_DISPATCH(pvar), LOWORD(*pFlags), NULL, MSHLFLAGS_NORMAL); - if (hr != S_OK) { - IStream_Release(working); /* this also releases the hglobal */ - return oldpos; - } - - working_memlocked = GlobalLock(working_mem); - memcpy(Buffer, &size, sizeof(ULONG)); /* copy the buffersize */ - Buffer += sizeof(ULONG); - memcpy(Buffer, working_memlocked, size); - GlobalUnlock(working_mem); - - IStream_Release(working); - - TRACE("done, size=%ld\n", sizeof(ULONG) + size); - return Buffer + sizeof(ULONG) + size; -} - -/* helper: called for VT_DISPATCH variants to unmarshal the buffer back into a dispatch variant. returns Buffer on failure, new position otherwise */ -static unsigned char *dispatch_variant_unmarshal(unsigned long *pFlags, unsigned char *Buffer, VARIANT *pvar) { - IStream *working; - HGLOBAL working_mem; - void *working_memlocked; - unsigned char *oldpos; - ULONG size; - HRESULT hr; - - TRACE("pFlags=%ld, Buffer=%p, pvar=%p\n", *pFlags, Buffer, pvar); - - oldpos = Buffer; - - /* get the buffersize */ - memcpy(&size, Buffer, sizeof(ULONG)); - TRACE("buffersize=%ld\n", size); - Buffer += sizeof(ULONG); - - working_mem = GlobalAlloc(0, size); - if (!working_mem) return oldpos; - - hr = CreateStreamOnHGlobal(working_mem, TRUE, &working); - if (hr != S_OK) { - GlobalFree(working_mem); - return oldpos; - } - - working_memlocked = GlobalLock(working_mem); - - /* now we copy the contents of the marshalling buffer to working_memlocked, unlock it, and demarshal the stream */ - memcpy(working_memlocked, Buffer, size); - GlobalUnlock(working_mem); - - hr = CoUnmarshalInterface(working, &IID_IDispatch, (void**)&V_DISPATCH(pvar)); - if (hr != S_OK) { - IStream_Release(working); - return oldpos; - } - - IStream_Release(working); /* this also frees the underlying hglobal */ - - TRACE("done, processed=%ld bytes\n", sizeof(ULONG) + size); - return Buffer + sizeof(ULONG) + size; -} - - -unsigned long WINAPI VARIANT_UserSize(unsigned long *pFlags, unsigned long Start, VARIANT *pvar) -{ - TRACE("(%lx,%ld,%p)\n", *pFlags, Start, pvar); - TRACE("vt=%04x\n", V_VT(pvar)); - Start += VARIANT_wiresize + wire_extra(pFlags, pvar); - TRACE("returning %ld\n", Start); - return Start; -} - -unsigned char * WINAPI VARIANT_UserMarshal(unsigned long *pFlags, unsigned char *Buffer, VARIANT *pvar) -{ - wireVARIANT var = (wireVARIANT)Buffer; - unsigned size, extra; - unsigned char *Pos = Buffer + VARIANT_wiresize; - - TRACE("(%lx,%p,%p)\n", *pFlags, Buffer, pvar); - TRACE("vt=%04x\n", V_VT(pvar)); - - memset(var, 0, sizeof(*var)); - var->clSize = sizeof(*var); - var->vt = pvar->n1.n2.vt; - - var->rpcReserved = var->vt; - if ((var->vt & VT_ARRAY) || - ((var->vt & VT_TYPEMASK) == VT_SAFEARRAY)) - var->vt = VT_ARRAY | (var->vt & VT_BYREF); - - if (var->vt == VT_DECIMAL) { - /* special case because decVal is on a different level */ - var->u.decVal = pvar->n1.decVal; - return Pos; - } - - size = wire_size(V_VT(pvar)); - extra = wire_extra(pFlags, pvar); - var->wReserved1 = pvar->n1.n2.wReserved1; - var->wReserved2 = pvar->n1.n2.wReserved2; - var->wReserved3 = pvar->n1.n2.wReserved3; - if (size) { - if (var->vt & VT_BYREF) - memcpy(&var->u.cVal, pvar->n1.n2.n3.byref, size); - else - memcpy(&var->u.cVal, &pvar->n1.n2.n3, size); - } - if (!extra) return Pos; - - switch (var->vt) { - case VT_BSTR: - Pos = BSTR_UserMarshal(pFlags, Pos, &V_BSTR(pvar)); - break; - case VT_BSTR | VT_BYREF: - Pos = BSTR_UserMarshal(pFlags, Pos, V_BSTRREF(pvar)); - break; - case VT_VARIANT | VT_BYREF: - Pos = VARIANT_UserMarshal(pFlags, Pos, V_VARIANTREF(pvar)); - break; - case VT_DISPATCH | VT_BYREF: - FIXME("handle DISPATCH by ref\n"); - break; - case VT_DISPATCH: - /* this should probably call WdtpInterfacePointer_UserMarshal in ole32.dll */ - Pos = dispatch_variant_marshal(pFlags, Pos, pvar); - break; - case VT_RECORD: - FIXME("handle BRECORD by val\n"); - break; - case VT_RECORD | VT_BYREF: - FIXME("handle BRECORD by ref\n"); - break; - default: - FIXME("handle unknown complex type\n"); - break; - } - var->clSize = Pos - Buffer; - TRACE("marshalled size=%ld\n", var->clSize); - return Pos; -} - -unsigned char * WINAPI VARIANT_UserUnmarshal(unsigned long *pFlags, unsigned char *Buffer, VARIANT *pvar) -{ - wireVARIANT var = (wireVARIANT)Buffer; - unsigned size; - unsigned char *Pos = Buffer + VARIANT_wiresize; - - TRACE("(%lx,%p,%p)\n", *pFlags, Buffer, pvar); - VariantInit(pvar); - pvar->n1.n2.vt = var->rpcReserved; - TRACE("marshalled: clSize=%ld, vt=%04x\n", var->clSize, var->vt); - TRACE("vt=%04x\n", V_VT(pvar)); - TRACE("reserved: %d, %d, %d\n", var->wReserved1, var->wReserved2, var->wReserved3); - TRACE("val: %ld\n", var->u.lVal); - - if (var->vt == VT_DECIMAL) { - /* special case because decVal is on a different level */ - pvar->n1.decVal = var->u.decVal; - return Pos; - } - - size = wire_size(V_VT(pvar)); - pvar->n1.n2.wReserved1 = var->wReserved1; - pvar->n1.n2.wReserved2 = var->wReserved2; - pvar->n1.n2.wReserved3 = var->wReserved3; - if (size) { - if (var->vt & VT_BYREF) { - pvar->n1.n2.n3.byref = CoTaskMemAlloc(size); - memcpy(pvar->n1.n2.n3.byref, &var->u.cVal, size); - } - else - memcpy(&pvar->n1.n2.n3, &var->u.cVal, size); - } - if (var->clSize <= VARIANT_wiresize) return Pos; - - switch (var->vt) { - case VT_BSTR: - Pos = BSTR_UserUnmarshal(pFlags, Pos, &V_BSTR(pvar)); - break; - case VT_BSTR | VT_BYREF: - pvar->n1.n2.n3.byref = CoTaskMemAlloc(sizeof(BSTR)); - *(BSTR*)pvar->n1.n2.n3.byref = NULL; - Pos = BSTR_UserUnmarshal(pFlags, Pos, V_BSTRREF(pvar)); - break; - case VT_VARIANT | VT_BYREF: - pvar->n1.n2.n3.byref = CoTaskMemAlloc(sizeof(VARIANT)); - Pos = VARIANT_UserUnmarshal(pFlags, Pos, V_VARIANTREF(pvar)); - break; - case VT_RECORD: - FIXME("handle BRECORD by val\n"); - break; - case VT_RECORD | VT_BYREF: - FIXME("handle BRECORD by ref\n"); - break; - case VT_DISPATCH: - Pos = dispatch_variant_unmarshal(pFlags, Pos, pvar); - break; - case VT_DISPATCH | VT_BYREF: - FIXME("handle DISPATCH by ref\n"); - default: - FIXME("handle unknown complex type\n"); - break; - } - if (Pos != Buffer + var->clSize) { - ERR("size difference during unmarshal\n"); - } - return Buffer + var->clSize; -} - -void WINAPI VARIANT_UserFree(unsigned long *pFlags, VARIANT *pvar) -{ - VARTYPE vt = V_VT(pvar); - PVOID ref = NULL; - - TRACE("(%lx,%p)\n", *pFlags, pvar); - TRACE("vt=%04x\n", V_VT(pvar)); - - if (vt & VT_BYREF) ref = pvar->n1.n2.n3.byref; - - VariantClear(pvar); - if (!ref) return; - - switch (vt) { - case VT_BSTR | VT_BYREF: - BSTR_UserFree(pFlags, ref); - break; - case VT_VARIANT | VT_BYREF: - VARIANT_UserFree(pFlags, ref); - break; - case VT_RECORD | VT_BYREF: - FIXME("handle BRECORD by ref\n"); - break; - default: - FIXME("handle unknown complex type\n"); - break; - } - - CoTaskMemFree(ref); -} - -/* IDispatch */ -/* exactly how Invoke is marshalled is not very clear to me yet, - * but the way I've done it seems to work for me */ - -HRESULT CALLBACK IDispatch_Invoke_Proxy( - IDispatch* This, - DISPID dispIdMember, - REFIID riid, - LCID lcid, - WORD wFlags, - DISPPARAMS* pDispParams, - VARIANT* pVarResult, - EXCEPINFO* pExcepInfo, - UINT* puArgErr) -{ - HRESULT hr; - VARIANT VarResult; - UINT* rgVarRefIdx = NULL; - VARIANTARG* rgVarRef = NULL; - UINT u, cVarRef; - - TRACE("(%p)->(%ld,%s,%lx,%x,%p,%p,%p,%p)\n", This, - dispIdMember, debugstr_guid(riid), - lcid, wFlags, pDispParams, pVarResult, - pExcepInfo, puArgErr); - - /* [out] args can't be null, use dummy vars if needed */ - if (!pVarResult) pVarResult = &VarResult; - - /* count by-ref args */ - for (cVarRef=0,u=0; u<pDispParams->cArgs; u++) { - VARIANTARG* arg = &pDispParams->rgvarg[u]; - if (V_ISBYREF(arg)) { - cVarRef++; - } - } - if (cVarRef) { - rgVarRefIdx = CoTaskMemAlloc(sizeof(UINT)*cVarRef); - rgVarRef = CoTaskMemAlloc(sizeof(VARIANTARG)*cVarRef); - /* make list of by-ref args */ - for (cVarRef=0,u=0; u<pDispParams->cArgs; u++) { - VARIANTARG* arg = &pDispParams->rgvarg[u]; - if (V_ISBYREF(arg)) { - rgVarRefIdx[cVarRef] = u; - VariantInit(&rgVarRef[cVarRef]); - cVarRef++; - } - } - } else { - /* [out] args still can't be null, - * but we can point these anywhere in this case, - * since they won't be written to when cVarRef is 0 */ - rgVarRefIdx = puArgErr; - rgVarRef = pVarResult; - } - TRACE("passed by ref: %d args\n", cVarRef); - hr = IDispatch_RemoteInvoke_Proxy(This, - dispIdMember, - riid, - lcid, - wFlags, - pDispParams, - pVarResult, - pExcepInfo, - puArgErr, - cVarRef, - rgVarRefIdx, - rgVarRef); - if (cVarRef) { - for (u=0; u<cVarRef; u++) { - unsigned i = rgVarRefIdx[u]; - VariantCopy(&pDispParams->rgvarg[i], - &rgVarRef[u]); - VariantClear(&rgVarRef[u]); - } - CoTaskMemFree(rgVarRef); - CoTaskMemFree(rgVarRefIdx); - } - return hr; -} - -HRESULT __RPC_STUB IDispatch_Invoke_Stub( - IDispatch* This, - DISPID dispIdMember, - REFIID riid, - LCID lcid, - DWORD dwFlags, - DISPPARAMS* pDispParams, - VARIANT* pVarResult, - EXCEPINFO* pExcepInfo, - UINT* pArgErr, - UINT cVarRef, - UINT* rgVarRefIdx, - VARIANTARG* rgVarRef) -{ - HRESULT hr; - VARIANTARG *rgvarg, *arg; - UINT u; - - /* let the real Invoke operate on a copy of the in parameters, - * so we don't risk losing pointers to allocated memory */ - rgvarg = pDispParams->rgvarg; - arg = CoTaskMemAlloc(sizeof(VARIANTARG)*pDispParams->cArgs); - for (u=0; u<pDispParams->cArgs; u++) { - VariantInit(&arg[u]); - VariantCopy(&arg[u], &rgvarg[u]); - } - pDispParams->rgvarg = arg; - - /* initialize out parameters, so that they can be marshalled - * in case the real Invoke doesn't initialize them */ - VariantInit(pVarResult); - memset(pExcepInfo, 0, sizeof(*pExcepInfo)); - *pArgErr = 0; - - hr = IDispatch_Invoke(This, - dispIdMember, - riid, - lcid, - dwFlags, - pDispParams, - pVarResult, - pExcepInfo, - pArgErr); - - /* copy ref args to out list */ - for (u=0; u<cVarRef; u++) { - unsigned i = rgVarRefIdx[u]; - VariantInit(&rgVarRef[u]); - VariantCopy(&rgVarRef[u], &arg[i]); - /* clear original if equal, to avoid double-free */ - if (V_BYREF(&rgVarRef[u]) == V_BYREF(&rgvarg[i])) - VariantClear(&rgvarg[i]); - } - /* clear the duplicate argument list */ - for (u=0; u<pDispParams->cArgs; u++) { - VariantClear(&arg[u]); - } - pDispParams->rgvarg = rgvarg; - CoTaskMemFree(arg); - - return hr; -} - -/* IEnumVARIANT */ - -HRESULT CALLBACK IEnumVARIANT_Next_Proxy( - IEnumVARIANT* This, - ULONG celt, - VARIANT* rgVar, - ULONG* pCeltFetched) -{ - ULONG fetched; - if (!pCeltFetched) - pCeltFetched = &fetched; - return IEnumVARIANT_RemoteNext_Proxy(This, - celt, - rgVar, - pCeltFetched); -} - -HRESULT __RPC_STUB IEnumVARIANT_Next_Stub( - IEnumVARIANT* This, - ULONG celt, - VARIANT* rgVar, - ULONG* pCeltFetched) -{ - HRESULT hr; - *pCeltFetched = 0; - hr = IEnumVARIANT_Next(This, - celt, - rgVar, - pCeltFetched); - if (hr == S_OK) *pCeltFetched = celt; - return hr; -} - -/* ITypeComp */ - -HRESULT CALLBACK ITypeComp_Bind_Proxy( - ITypeComp* This, - LPOLESTR szName, - ULONG lHashVal, - WORD wFlags, - ITypeInfo** ppTInfo, - DESCKIND* pDescKind, - BINDPTR* pBindPtr) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT __RPC_STUB ITypeComp_Bind_Stub( - ITypeComp* This, - LPOLESTR szName, - ULONG lHashVal, - WORD wFlags, - ITypeInfo** ppTInfo, - DESCKIND* pDescKind, - LPFUNCDESC* ppFuncDesc, - LPVARDESC* ppVarDesc, - ITypeComp** ppTypeComp, - CLEANLOCALSTORAGE* pDummy) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT CALLBACK ITypeComp_BindType_Proxy( - ITypeComp* This, - LPOLESTR szName, - ULONG lHashVal, - ITypeInfo** ppTInfo, - ITypeComp** ppTComp) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT __RPC_STUB ITypeComp_BindType_Stub( - ITypeComp* This, - LPOLESTR szName, - ULONG lHashVal, - ITypeInfo** ppTInfo) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -/* ITypeInfo */ - -HRESULT CALLBACK ITypeInfo_GetTypeAttr_Proxy( - ITypeInfo* This, - TYPEATTR** ppTypeAttr) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT __RPC_STUB ITypeInfo_GetTypeAttr_Stub( - ITypeInfo* This, - LPTYPEATTR* ppTypeAttr, - CLEANLOCALSTORAGE* pDummy) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT CALLBACK ITypeInfo_GetFuncDesc_Proxy( - ITypeInfo* This, - UINT index, - FUNCDESC** ppFuncDesc) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT __RPC_STUB ITypeInfo_GetFuncDesc_Stub( - ITypeInfo* This, - UINT index, - LPFUNCDESC* ppFuncDesc, - CLEANLOCALSTORAGE* pDummy) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT CALLBACK ITypeInfo_GetVarDesc_Proxy( - ITypeInfo* This, - UINT index, - VARDESC** ppVarDesc) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT __RPC_STUB ITypeInfo_GetVarDesc_Stub( - ITypeInfo* This, - UINT index, - LPVARDESC* ppVarDesc, - CLEANLOCALSTORAGE* pDummy) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT CALLBACK ITypeInfo_GetNames_Proxy( - ITypeInfo* This, - MEMBERID memid, - BSTR* rgBstrNames, - UINT cMaxNames, - UINT* pcNames) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT __RPC_STUB ITypeInfo_GetNames_Stub( - ITypeInfo* This, - MEMBERID memid, - BSTR* rgBstrNames, - UINT cMaxNames, - UINT* pcNames) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT CALLBACK ITypeInfo_GetIDsOfNames_Proxy( - ITypeInfo* This, - LPOLESTR* rgszNames, - UINT cNames, - MEMBERID* pMemId) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT __RPC_STUB ITypeInfo_GetIDsOfNames_Stub( - ITypeInfo* This) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT CALLBACK ITypeInfo_Invoke_Proxy( - ITypeInfo* This, - PVOID pvInstance, - MEMBERID memid, - WORD wFlags, - DISPPARAMS* pDispParams, - VARIANT* pVarResult, - EXCEPINFO* pExcepInfo, - UINT* puArgErr) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT __RPC_STUB ITypeInfo_Invoke_Stub( - ITypeInfo* This) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT CALLBACK ITypeInfo_GetDocumentation_Proxy( - ITypeInfo* This, - MEMBERID memid, - BSTR* pBstrName, - BSTR* pBstrDocString, - DWORD* pdwHelpContext, - BSTR* pBstrHelpFile) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT __RPC_STUB ITypeInfo_GetDocumentation_Stub( - ITypeInfo* This, - MEMBERID memid, - DWORD refPtrFlags, - BSTR* pBstrName, - BSTR* pBstrDocString, - DWORD* pdwHelpContext, - BSTR* pBstrHelpFile) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT CALLBACK ITypeInfo_GetDllEntry_Proxy( - ITypeInfo* This, - MEMBERID memid, - INVOKEKIND invKind, - BSTR* pBstrDllName, - BSTR* pBstrName, - WORD* pwOrdinal) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT __RPC_STUB ITypeInfo_GetDllEntry_Stub( - ITypeInfo* This, - MEMBERID memid, - INVOKEKIND invKind, - DWORD refPtrFlags, - BSTR* pBstrDllName, - BSTR* pBstrName, - WORD* pwOrdinal) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT CALLBACK ITypeInfo_AddressOfMember_Proxy( - ITypeInfo* This, - MEMBERID memid, - INVOKEKIND invKind, - PVOID* ppv) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT __RPC_STUB ITypeInfo_AddressOfMember_Stub( - ITypeInfo* This) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT CALLBACK ITypeInfo_CreateInstance_Proxy( - ITypeInfo* This, - IUnknown* pUnkOuter, - REFIID riid, - PVOID* ppvObj) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT __RPC_STUB ITypeInfo_CreateInstance_Stub( - ITypeInfo* This, - REFIID riid, - IUnknown** ppvObj) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT CALLBACK ITypeInfo_GetContainingTypeLib_Proxy( - ITypeInfo* This, - ITypeLib** ppTLib, - UINT* pIndex) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT __RPC_STUB ITypeInfo_GetContainingTypeLib_Stub( - ITypeInfo* This, - ITypeLib** ppTLib, - UINT* pIndex) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -void CALLBACK ITypeInfo_ReleaseTypeAttr_Proxy( - ITypeInfo* This, - TYPEATTR* pTypeAttr) -{ - FIXME("not implemented\n"); -} - -HRESULT __RPC_STUB ITypeInfo_ReleaseTypeAttr_Stub( - ITypeInfo* This) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -void CALLBACK ITypeInfo_ReleaseFuncDesc_Proxy( - ITypeInfo* This, - FUNCDESC* pFuncDesc) -{ - FIXME("not implemented\n"); -} - -HRESULT __RPC_STUB ITypeInfo_ReleaseFuncDesc_Stub( - ITypeInfo* This) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -void CALLBACK ITypeInfo_ReleaseVarDesc_Proxy( - ITypeInfo* This, - VARDESC* pVarDesc) -{ - FIXME("not implemented\n"); -} - -HRESULT __RPC_STUB ITypeInfo_ReleaseVarDesc_Stub( - ITypeInfo* This) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - - -/* ITypeInfo2 */ - -HRESULT CALLBACK ITypeInfo2_GetDocumentation2_Proxy( - ITypeInfo2* This, - MEMBERID memid, - LCID lcid, - BSTR* pbstrHelpString, - DWORD* pdwHelpStringContext, - BSTR* pbstrHelpStringDll) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT __RPC_STUB ITypeInfo2_GetDocumentation2_Stub( - ITypeInfo2* This, - MEMBERID memid, - LCID lcid, - DWORD refPtrFlags, - BSTR* pbstrHelpString, - DWORD* pdwHelpStringContext, - BSTR* pbstrHelpStringDll) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -/* ITypeLib */ - -UINT CALLBACK ITypeLib_GetTypeInfoCount_Proxy( - ITypeLib* This) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT __RPC_STUB ITypeLib_GetTypeInfoCount_Stub( - ITypeLib* This, - UINT* pcTInfo) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT CALLBACK ITypeLib_GetLibAttr_Proxy( - ITypeLib* This, - TLIBATTR** ppTLibAttr) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT __RPC_STUB ITypeLib_GetLibAttr_Stub( - ITypeLib* This, - LPTLIBATTR* ppTLibAttr, - CLEANLOCALSTORAGE* pDummy) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT CALLBACK ITypeLib_GetDocumentation_Proxy( - ITypeLib* This, - INT index, - BSTR* pBstrName, - BSTR* pBstrDocString, - DWORD* pdwHelpContext, - BSTR* pBstrHelpFile) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT __RPC_STUB ITypeLib_GetDocumentation_Stub( - ITypeLib* This, - INT index, - DWORD refPtrFlags, - BSTR* pBstrName, - BSTR* pBstrDocString, - DWORD* pdwHelpContext, - BSTR* pBstrHelpFile) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT CALLBACK ITypeLib_IsName_Proxy( - ITypeLib* This, - LPOLESTR szNameBuf, - ULONG lHashVal, - BOOL* pfName) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT __RPC_STUB ITypeLib_IsName_Stub( - ITypeLib* This, - LPOLESTR szNameBuf, - ULONG lHashVal, - BOOL* pfName, - BSTR* pBstrLibName) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT CALLBACK ITypeLib_FindName_Proxy( - ITypeLib* This, - LPOLESTR szNameBuf, - ULONG lHashVal, - ITypeInfo** ppTInfo, - MEMBERID* rgMemId, - USHORT* pcFound) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT __RPC_STUB ITypeLib_FindName_Stub( - ITypeLib* This, - LPOLESTR szNameBuf, - ULONG lHashVal, - ITypeInfo** ppTInfo, - MEMBERID* rgMemId, - USHORT* pcFound, - BSTR* pBstrLibName) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -void CALLBACK ITypeLib_ReleaseTLibAttr_Proxy( - ITypeLib* This, - TLIBATTR* pTLibAttr) -{ - FIXME("not implemented\n"); -} - -HRESULT __RPC_STUB ITypeLib_ReleaseTLibAttr_Stub( - ITypeLib* This) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - - -/* ITypeLib2 */ - -HRESULT CALLBACK ITypeLib2_GetLibStatistics_Proxy( - ITypeLib2* This, - ULONG* pcUniqueNames, - ULONG* pcchUniqueNames) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT __RPC_STUB ITypeLib2_GetLibStatistics_Stub( - ITypeLib2* This, - ULONG* pcUniqueNames, - ULONG* pcchUniqueNames) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT CALLBACK ITypeLib2_GetDocumentation2_Proxy( - ITypeLib2* This, - INT index, - LCID lcid, - BSTR* pbstrHelpString, - DWORD* pdwHelpStringContext, - BSTR* pbstrHelpStringDll) -{ - FIXME("not implemented\n"); - return E_FAIL; -} - -HRESULT __RPC_STUB ITypeLib2_GetDocumentation2_Stub( - ITypeLib2* This, - INT index, - LCID lcid, - DWORD refPtrFlags, - BSTR* pbstrHelpString, - DWORD* pdwHelpStringContext, - BSTR* pbstrHelpStringDll) -{ - FIXME("not implemented\n"); - return E_FAIL; -} +/* + * Misc marshalling routines + * + * Copyright 2002 Ove Kaaven + * Copyright 2003 Mike Hearn + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> +#include <string.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winerror.h" + +#include "ole2.h" +#include "oleauto.h" +#include "rpcproxy.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/* FIXME: not supposed to be here */ + +const CLSID CLSID_PSDispatch = { + 0x20420, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46} +}; + +static CStdPSFactoryBuffer PSFactoryBuffer; + +CSTDSTUBBUFFERRELEASE(&PSFactoryBuffer) + +extern const ExtendedProxyFileInfo oaidl_ProxyFileInfo; + +const ProxyFileInfo* OLEAUT32_ProxyFileList[] = { + &oaidl_ProxyFileInfo, + NULL +}; + +HRESULT OLEAUTPS_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) +{ + return NdrDllGetClassObject(rclsid, riid, ppv, OLEAUT32_ProxyFileList, + &CLSID_PSDispatch, &PSFactoryBuffer); +} + +/* CLEANLOCALSTORAGE */ +/* I'm not sure how this is supposed to work yet */ + +unsigned long WINAPI CLEANLOCALSTORAGE_UserSize(unsigned long *pFlags, unsigned long Start, CLEANLOCALSTORAGE *pstg) +{ + return Start + sizeof(DWORD); +} + +unsigned char * WINAPI CLEANLOCALSTORAGE_UserMarshal(unsigned long *pFlags, unsigned char *Buffer, CLEANLOCALSTORAGE *pstg) +{ + *(DWORD*)Buffer = 0; + return Buffer + sizeof(DWORD); +} + +unsigned char * WINAPI CLEANLOCALSTORAGE_UserUnmarshal(unsigned long *pFlags, unsigned char *Buffer, CLEANLOCALSTORAGE *pstr) +{ + return Buffer + sizeof(DWORD); +} + +void WINAPI CLEANLOCALSTORAGE_UserFree(unsigned long *pFlags, CLEANLOCALSTORAGE *pstr) +{ +} + +/* BSTR */ + +unsigned long WINAPI BSTR_UserSize(unsigned long *pFlags, unsigned long Start, BSTR *pstr) +{ + TRACE("(%lx,%ld,%p) => %p\n", *pFlags, Start, pstr, *pstr); + if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr)); + Start += sizeof(FLAGGED_WORD_BLOB) + sizeof(OLECHAR) * (SysStringLen(*pstr) - 1); + TRACE("returning %ld\n", Start); + return Start; +} + +unsigned char * WINAPI BSTR_UserMarshal(unsigned long *pFlags, unsigned char *Buffer, BSTR *pstr) +{ + wireBSTR str = (wireBSTR)Buffer; + + TRACE("(%lx,%p,%p) => %p\n", *pFlags, Buffer, pstr, *pstr); + if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr)); + str->fFlags = 0; + str->clSize = SysStringLen(*pstr); + if (str->clSize) + memcpy(&str->asData, *pstr, sizeof(OLECHAR) * str->clSize); + return Buffer + sizeof(FLAGGED_WORD_BLOB) + sizeof(OLECHAR) * (str->clSize - 1); +} + +unsigned char * WINAPI BSTR_UserUnmarshal(unsigned long *pFlags, unsigned char *Buffer, BSTR *pstr) +{ + wireBSTR str = (wireBSTR)Buffer; + TRACE("(%lx,%p,%p) => %p\n", *pFlags, Buffer, pstr, *pstr); + if (str->clSize) { + SysReAllocStringLen(pstr, (OLECHAR*)&str->asData, str->clSize); + } + else if (*pstr) { + SysFreeString(*pstr); + *pstr = NULL; + } + if (*pstr) TRACE("string=%s\n", debugstr_w(*pstr)); + return Buffer + sizeof(FLAGGED_WORD_BLOB) + sizeof(OLECHAR) * (str->clSize - 1); +} + +void WINAPI BSTR_UserFree(unsigned long *pFlags, BSTR *pstr) +{ + TRACE("(%lx,%p) => %p\n", *pFlags, pstr, *pstr); + if (*pstr) { + SysFreeString(*pstr); + *pstr = NULL; + } +} + +/* VARIANT */ +/* I'm not too sure how to do this yet */ + +#define VARIANT_wiresize sizeof(struct _wireVARIANT) + +static unsigned wire_size(VARTYPE vt) +{ + if (vt & VT_ARRAY) return 0; + + switch (vt & ~VT_BYREF) { + case VT_EMPTY: + case VT_NULL: + return 0; + case VT_I1: + case VT_UI1: + return sizeof(CHAR); + case VT_I2: + case VT_UI2: + return sizeof(SHORT); + case VT_I4: + case VT_UI4: + return sizeof(LONG); + case VT_INT: + case VT_UINT: + return sizeof(INT); + case VT_R4: + return sizeof(FLOAT); + case VT_R8: + return sizeof(DOUBLE); + case VT_BOOL: + return sizeof(VARIANT_BOOL); + case VT_ERROR: + return sizeof(SCODE); + case VT_DATE: + return sizeof(DATE); + case VT_CY: + return sizeof(CY); + case VT_DECIMAL: + return sizeof(DECIMAL); + case VT_BSTR: + case VT_VARIANT: + case VT_UNKNOWN: + case VT_DISPATCH: + case VT_SAFEARRAY: + case VT_RECORD: + return 0; + default: + FIXME("unhandled VT %d\n", vt); + return 0; + } +} + +static unsigned wire_extra(unsigned long *pFlags, VARIANT *pvar) +{ + ULONG size; + HRESULT hr; + + if (V_ISARRAY(pvar)) { + FIXME("wire-size safearray\n"); + return 0; + } + switch (V_VT(pvar)) { + case VT_BSTR: + return BSTR_UserSize(pFlags, 0, &V_BSTR(pvar)); + case VT_BSTR | VT_BYREF: + return BSTR_UserSize(pFlags, 0, V_BSTRREF(pvar)); + case VT_SAFEARRAY: + case VT_SAFEARRAY | VT_BYREF: + FIXME("wire-size safearray\n"); + return 0; + case VT_VARIANT | VT_BYREF: + return VARIANT_UserSize(pFlags, 0, V_VARIANTREF(pvar)); + case VT_UNKNOWN: + case VT_DISPATCH: + /* find the buffer size of the marshalled dispatch interface */ + hr = CoGetMarshalSizeMax(&size, &IID_IDispatch, (IUnknown*)V_DISPATCH(pvar), LOWORD(*pFlags), NULL, MSHLFLAGS_NORMAL); + if (FAILED(hr)) { + ERR("Dispatch variant buffer size calculation failed, HRESULT=0x%lx\n", hr); + return 0; + } + size += sizeof(ULONG); /* we have to store the buffersize in the stream */ + TRACE("wire-size extra of dispatch variant is %ld\n", size); + return size; + case VT_RECORD: + FIXME("wire-size record\n"); + return 0; + default: + return 0; + } +} + +/* helper: called for VT_DISPATCH variants to marshal the IDispatch* into the buffer. returns Buffer on failure, new position otherwise */ +static unsigned char* dispatch_variant_marshal(unsigned long *pFlags, unsigned char *Buffer, VARIANT *pvar) { + IStream *working; + HGLOBAL working_mem; + void *working_memlocked; + unsigned char *oldpos; + ULONG size; + HRESULT hr; + + TRACE("pFlags=%ld, Buffer=%p, pvar=%p\n", *pFlags, Buffer, pvar); + + oldpos = Buffer; + + /* CoMarshalInterface needs a stream, whereas at this level we are operating in terms of buffers. + * We create a stream on an HGLOBAL, so we can simply do a memcpy to move it to the buffer. + * in rpcrt4/ndr_ole.c, a simple IStream implementation is wrapped around the buffer object, + * but that would be overkill here, hence this implementation. We save the size because the unmarshal + * code has no way to know how long the marshalled buffer is. */ + + size = wire_extra(pFlags, pvar); + + working_mem = GlobalAlloc(0, size); + if (!working_mem) return oldpos; + + hr = CreateStreamOnHGlobal(working_mem, TRUE, &working); + if (hr != S_OK) { + GlobalFree(working_mem); + return oldpos; + } + + hr = CoMarshalInterface(working, &IID_IDispatch, (IUnknown*)V_DISPATCH(pvar), LOWORD(*pFlags), NULL, MSHLFLAGS_NORMAL); + if (hr != S_OK) { + IStream_Release(working); /* this also releases the hglobal */ + return oldpos; + } + + working_memlocked = GlobalLock(working_mem); + memcpy(Buffer, &size, sizeof(ULONG)); /* copy the buffersize */ + Buffer += sizeof(ULONG); + memcpy(Buffer, working_memlocked, size); + GlobalUnlock(working_mem); + + IStream_Release(working); + + TRACE("done, size=%ld\n", sizeof(ULONG) + size); + return Buffer + sizeof(ULONG) + size; +} + +/* helper: called for VT_DISPATCH variants to unmarshal the buffer back into a dispatch variant. returns Buffer on failure, new position otherwise */ +static unsigned char *dispatch_variant_unmarshal(unsigned long *pFlags, unsigned char *Buffer, VARIANT *pvar) { + IStream *working; + HGLOBAL working_mem; + void *working_memlocked; + unsigned char *oldpos; + ULONG size; + HRESULT hr; + + TRACE("pFlags=%ld, Buffer=%p, pvar=%p\n", *pFlags, Buffer, pvar); + + oldpos = Buffer; + + /* get the buffersize */ + memcpy(&size, Buffer, sizeof(ULONG)); + TRACE("buffersize=%ld\n", size); + Buffer += sizeof(ULONG); + + working_mem = GlobalAlloc(0, size); + if (!working_mem) return oldpos; + + hr = CreateStreamOnHGlobal(working_mem, TRUE, &working); + if (hr != S_OK) { + GlobalFree(working_mem); + return oldpos; + } + + working_memlocked = GlobalLock(working_mem); + + /* now we copy the contents of the marshalling buffer to working_memlocked, unlock it, and demarshal the stream */ + memcpy(working_memlocked, Buffer, size); + GlobalUnlock(working_mem); + + hr = CoUnmarshalInterface(working, &IID_IDispatch, (void**)&V_DISPATCH(pvar)); + if (hr != S_OK) { + IStream_Release(working); + return oldpos; + } + + IStream_Release(working); /* this also frees the underlying hglobal */ + + TRACE("done, processed=%ld bytes\n", sizeof(ULONG) + size); + return Buffer + sizeof(ULONG) + size; +} + + +unsigned long WINAPI VARIANT_UserSize(unsigned long *pFlags, unsigned long Start, VARIANT *pvar) +{ + TRACE("(%lx,%ld,%p)\n", *pFlags, Start, pvar); + TRACE("vt=%04x\n", V_VT(pvar)); + Start += VARIANT_wiresize + wire_extra(pFlags, pvar); + TRACE("returning %ld\n", Start); + return Start; +} + +unsigned char * WINAPI VARIANT_UserMarshal(unsigned long *pFlags, unsigned char *Buffer, VARIANT *pvar) +{ + wireVARIANT var = (wireVARIANT)Buffer; + unsigned size, extra; + unsigned char *Pos = Buffer + VARIANT_wiresize; + + TRACE("(%lx,%p,%p)\n", *pFlags, Buffer, pvar); + TRACE("vt=%04x\n", V_VT(pvar)); + + memset(var, 0, sizeof(*var)); + var->clSize = sizeof(*var); + var->vt = pvar->n1.n2.vt; + + var->rpcReserved = var->vt; + if ((var->vt & VT_ARRAY) || + ((var->vt & VT_TYPEMASK) == VT_SAFEARRAY)) + var->vt = VT_ARRAY | (var->vt & VT_BYREF); + + if (var->vt == VT_DECIMAL) { + /* special case because decVal is on a different level */ + var->u.decVal = pvar->n1.decVal; + return Pos; + } + + size = wire_size(V_VT(pvar)); + extra = wire_extra(pFlags, pvar); + var->wReserved1 = pvar->n1.n2.wReserved1; + var->wReserved2 = pvar->n1.n2.wReserved2; + var->wReserved3 = pvar->n1.n2.wReserved3; + if (size) { + if (var->vt & VT_BYREF) + memcpy(&var->u.cVal, pvar->n1.n2.n3.byref, size); + else + memcpy(&var->u.cVal, &pvar->n1.n2.n3, size); + } + if (!extra) return Pos; + + switch (var->vt) { + case VT_BSTR: + Pos = BSTR_UserMarshal(pFlags, Pos, &V_BSTR(pvar)); + break; + case VT_BSTR | VT_BYREF: + Pos = BSTR_UserMarshal(pFlags, Pos, V_BSTRREF(pvar)); + break; + case VT_VARIANT | VT_BYREF: + Pos = VARIANT_UserMarshal(pFlags, Pos, V_VARIANTREF(pvar)); + break; + case VT_DISPATCH | VT_BYREF: + FIXME("handle DISPATCH by ref\n"); + break; + case VT_DISPATCH: + /* this should probably call WdtpInterfacePointer_UserMarshal in ole32.dll */ + Pos = dispatch_variant_marshal(pFlags, Pos, pvar); + break; + case VT_RECORD: + FIXME("handle BRECORD by val\n"); + break; + case VT_RECORD | VT_BYREF: + FIXME("handle BRECORD by ref\n"); + break; + default: + FIXME("handle unknown complex type\n"); + break; + } + var->clSize = Pos - Buffer; + TRACE("marshalled size=%ld\n", var->clSize); + return Pos; +} + +unsigned char * WINAPI VARIANT_UserUnmarshal(unsigned long *pFlags, unsigned char *Buffer, VARIANT *pvar) +{ + wireVARIANT var = (wireVARIANT)Buffer; + unsigned size; + unsigned char *Pos = Buffer + VARIANT_wiresize; + + TRACE("(%lx,%p,%p)\n", *pFlags, Buffer, pvar); + VariantInit(pvar); + pvar->n1.n2.vt = var->rpcReserved; + TRACE("marshalled: clSize=%ld, vt=%04x\n", var->clSize, var->vt); + TRACE("vt=%04x\n", V_VT(pvar)); + TRACE("reserved: %d, %d, %d\n", var->wReserved1, var->wReserved2, var->wReserved3); + TRACE("val: %ld\n", var->u.lVal); + + if (var->vt == VT_DECIMAL) { + /* special case because decVal is on a different level */ + pvar->n1.decVal = var->u.decVal; + return Pos; + } + + size = wire_size(V_VT(pvar)); + pvar->n1.n2.wReserved1 = var->wReserved1; + pvar->n1.n2.wReserved2 = var->wReserved2; + pvar->n1.n2.wReserved3 = var->wReserved3; + if (size) { + if (var->vt & VT_BYREF) { + pvar->n1.n2.n3.byref = CoTaskMemAlloc(size); + memcpy(pvar->n1.n2.n3.byref, &var->u.cVal, size); + } + else + memcpy(&pvar->n1.n2.n3, &var->u.cVal, size); + } + if (var->clSize <= VARIANT_wiresize) return Pos; + + switch (var->vt) { + case VT_BSTR: + Pos = BSTR_UserUnmarshal(pFlags, Pos, &V_BSTR(pvar)); + break; + case VT_BSTR | VT_BYREF: + pvar->n1.n2.n3.byref = CoTaskMemAlloc(sizeof(BSTR)); + *(BSTR*)pvar->n1.n2.n3.byref = NULL; + Pos = BSTR_UserUnmarshal(pFlags, Pos, V_BSTRREF(pvar)); + break; + case VT_VARIANT | VT_BYREF: + pvar->n1.n2.n3.byref = CoTaskMemAlloc(sizeof(VARIANT)); + Pos = VARIANT_UserUnmarshal(pFlags, Pos, V_VARIANTREF(pvar)); + break; + case VT_RECORD: + FIXME("handle BRECORD by val\n"); + break; + case VT_RECORD | VT_BYREF: + FIXME("handle BRECORD by ref\n"); + break; + case VT_DISPATCH: + Pos = dispatch_variant_unmarshal(pFlags, Pos, pvar); + break; + case VT_DISPATCH | VT_BYREF: + FIXME("handle DISPATCH by ref\n"); + default: + FIXME("handle unknown complex type\n"); + break; + } + if (Pos != Buffer + var->clSize) { + ERR("size difference during unmarshal\n"); + } + return Buffer + var->clSize; +} + +void WINAPI VARIANT_UserFree(unsigned long *pFlags, VARIANT *pvar) +{ + VARTYPE vt = V_VT(pvar); + PVOID ref = NULL; + + TRACE("(%lx,%p)\n", *pFlags, pvar); + TRACE("vt=%04x\n", V_VT(pvar)); + + if (vt & VT_BYREF) ref = pvar->n1.n2.n3.byref; + + VariantClear(pvar); + if (!ref) return; + + switch (vt) { + case VT_BSTR | VT_BYREF: + BSTR_UserFree(pFlags, ref); + break; + case VT_VARIANT | VT_BYREF: + VARIANT_UserFree(pFlags, ref); + break; + case VT_RECORD | VT_BYREF: + FIXME("handle BRECORD by ref\n"); + break; + default: + FIXME("handle unknown complex type\n"); + break; + } + + CoTaskMemFree(ref); +} + +/* IDispatch */ +/* exactly how Invoke is marshalled is not very clear to me yet, + * but the way I've done it seems to work for me */ + +HRESULT CALLBACK IDispatch_Invoke_Proxy( + IDispatch* This, + DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS* pDispParams, + VARIANT* pVarResult, + EXCEPINFO* pExcepInfo, + UINT* puArgErr) +{ + HRESULT hr; + VARIANT VarResult; + UINT* rgVarRefIdx = NULL; + VARIANTARG* rgVarRef = NULL; + UINT u, cVarRef; + + TRACE("(%p)->(%ld,%s,%lx,%x,%p,%p,%p,%p)\n", This, + dispIdMember, debugstr_guid(riid), + lcid, wFlags, pDispParams, pVarResult, + pExcepInfo, puArgErr); + + /* [out] args can't be null, use dummy vars if needed */ + if (!pVarResult) pVarResult = &VarResult; + + /* count by-ref args */ + for (cVarRef=0,u=0; u<pDispParams->cArgs; u++) { + VARIANTARG* arg = &pDispParams->rgvarg[u]; + if (V_ISBYREF(arg)) { + cVarRef++; + } + } + if (cVarRef) { + rgVarRefIdx = CoTaskMemAlloc(sizeof(UINT)*cVarRef); + rgVarRef = CoTaskMemAlloc(sizeof(VARIANTARG)*cVarRef); + /* make list of by-ref args */ + for (cVarRef=0,u=0; u<pDispParams->cArgs; u++) { + VARIANTARG* arg = &pDispParams->rgvarg[u]; + if (V_ISBYREF(arg)) { + rgVarRefIdx[cVarRef] = u; + VariantInit(&rgVarRef[cVarRef]); + cVarRef++; + } + } + } else { + /* [out] args still can't be null, + * but we can point these anywhere in this case, + * since they won't be written to when cVarRef is 0 */ + rgVarRefIdx = puArgErr; + rgVarRef = pVarResult; + } + TRACE("passed by ref: %d args\n", cVarRef); + hr = IDispatch_RemoteInvoke_Proxy(This, + dispIdMember, + riid, + lcid, + wFlags, + pDispParams, + pVarResult, + pExcepInfo, + puArgErr, + cVarRef, + rgVarRefIdx, + rgVarRef); + if (cVarRef) { + for (u=0; u<cVarRef; u++) { + unsigned i = rgVarRefIdx[u]; + VariantCopy(&pDispParams->rgvarg[i], + &rgVarRef[u]); + VariantClear(&rgVarRef[u]); + } + CoTaskMemFree(rgVarRef); + CoTaskMemFree(rgVarRefIdx); + } + return hr; +} + +HRESULT __RPC_STUB IDispatch_Invoke_Stub( + IDispatch* This, + DISPID dispIdMember, + REFIID riid, + LCID lcid, + DWORD dwFlags, + DISPPARAMS* pDispParams, + VARIANT* pVarResult, + EXCEPINFO* pExcepInfo, + UINT* pArgErr, + UINT cVarRef, + UINT* rgVarRefIdx, + VARIANTARG* rgVarRef) +{ + HRESULT hr; + VARIANTARG *rgvarg, *arg; + UINT u; + + /* let the real Invoke operate on a copy of the in parameters, + * so we don't risk losing pointers to allocated memory */ + rgvarg = pDispParams->rgvarg; + arg = CoTaskMemAlloc(sizeof(VARIANTARG)*pDispParams->cArgs); + for (u=0; u<pDispParams->cArgs; u++) { + VariantInit(&arg[u]); + VariantCopy(&arg[u], &rgvarg[u]); + } + pDispParams->rgvarg = arg; + + /* initialize out parameters, so that they can be marshalled + * in case the real Invoke doesn't initialize them */ + VariantInit(pVarResult); + memset(pExcepInfo, 0, sizeof(*pExcepInfo)); + *pArgErr = 0; + + hr = IDispatch_Invoke(This, + dispIdMember, + riid, + lcid, + dwFlags, + pDispParams, + pVarResult, + pExcepInfo, + pArgErr); + + /* copy ref args to out list */ + for (u=0; u<cVarRef; u++) { + unsigned i = rgVarRefIdx[u]; + VariantInit(&rgVarRef[u]); + VariantCopy(&rgVarRef[u], &arg[i]); + /* clear original if equal, to avoid double-free */ + if (V_BYREF(&rgVarRef[u]) == V_BYREF(&rgvarg[i])) + VariantClear(&rgvarg[i]); + } + /* clear the duplicate argument list */ + for (u=0; u<pDispParams->cArgs; u++) { + VariantClear(&arg[u]); + } + pDispParams->rgvarg = rgvarg; + CoTaskMemFree(arg); + + return hr; +} + +/* IEnumVARIANT */ + +HRESULT CALLBACK IEnumVARIANT_Next_Proxy( + IEnumVARIANT* This, + ULONG celt, + VARIANT* rgVar, + ULONG* pCeltFetched) +{ + ULONG fetched; + if (!pCeltFetched) + pCeltFetched = &fetched; + return IEnumVARIANT_RemoteNext_Proxy(This, + celt, + rgVar, + pCeltFetched); +} + +HRESULT __RPC_STUB IEnumVARIANT_Next_Stub( + IEnumVARIANT* This, + ULONG celt, + VARIANT* rgVar, + ULONG* pCeltFetched) +{ + HRESULT hr; + *pCeltFetched = 0; + hr = IEnumVARIANT_Next(This, + celt, + rgVar, + pCeltFetched); + if (hr == S_OK) *pCeltFetched = celt; + return hr; +} + +/* ITypeComp */ + +HRESULT CALLBACK ITypeComp_Bind_Proxy( + ITypeComp* This, + LPOLESTR szName, + ULONG lHashVal, + WORD wFlags, + ITypeInfo** ppTInfo, + DESCKIND* pDescKind, + BINDPTR* pBindPtr) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB ITypeComp_Bind_Stub( + ITypeComp* This, + LPOLESTR szName, + ULONG lHashVal, + WORD wFlags, + ITypeInfo** ppTInfo, + DESCKIND* pDescKind, + LPFUNCDESC* ppFuncDesc, + LPVARDESC* ppVarDesc, + ITypeComp** ppTypeComp, + CLEANLOCALSTORAGE* pDummy) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK ITypeComp_BindType_Proxy( + ITypeComp* This, + LPOLESTR szName, + ULONG lHashVal, + ITypeInfo** ppTInfo, + ITypeComp** ppTComp) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB ITypeComp_BindType_Stub( + ITypeComp* This, + LPOLESTR szName, + ULONG lHashVal, + ITypeInfo** ppTInfo) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +/* ITypeInfo */ + +HRESULT CALLBACK ITypeInfo_GetTypeAttr_Proxy( + ITypeInfo* This, + TYPEATTR** ppTypeAttr) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB ITypeInfo_GetTypeAttr_Stub( + ITypeInfo* This, + LPTYPEATTR* ppTypeAttr, + CLEANLOCALSTORAGE* pDummy) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK ITypeInfo_GetFuncDesc_Proxy( + ITypeInfo* This, + UINT index, + FUNCDESC** ppFuncDesc) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB ITypeInfo_GetFuncDesc_Stub( + ITypeInfo* This, + UINT index, + LPFUNCDESC* ppFuncDesc, + CLEANLOCALSTORAGE* pDummy) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK ITypeInfo_GetVarDesc_Proxy( + ITypeInfo* This, + UINT index, + VARDESC** ppVarDesc) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB ITypeInfo_GetVarDesc_Stub( + ITypeInfo* This, + UINT index, + LPVARDESC* ppVarDesc, + CLEANLOCALSTORAGE* pDummy) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK ITypeInfo_GetNames_Proxy( + ITypeInfo* This, + MEMBERID memid, + BSTR* rgBstrNames, + UINT cMaxNames, + UINT* pcNames) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB ITypeInfo_GetNames_Stub( + ITypeInfo* This, + MEMBERID memid, + BSTR* rgBstrNames, + UINT cMaxNames, + UINT* pcNames) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK ITypeInfo_GetIDsOfNames_Proxy( + ITypeInfo* This, + LPOLESTR* rgszNames, + UINT cNames, + MEMBERID* pMemId) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB ITypeInfo_GetIDsOfNames_Stub( + ITypeInfo* This) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK ITypeInfo_Invoke_Proxy( + ITypeInfo* This, + PVOID pvInstance, + MEMBERID memid, + WORD wFlags, + DISPPARAMS* pDispParams, + VARIANT* pVarResult, + EXCEPINFO* pExcepInfo, + UINT* puArgErr) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB ITypeInfo_Invoke_Stub( + ITypeInfo* This) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK ITypeInfo_GetDocumentation_Proxy( + ITypeInfo* This, + MEMBERID memid, + BSTR* pBstrName, + BSTR* pBstrDocString, + DWORD* pdwHelpContext, + BSTR* pBstrHelpFile) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB ITypeInfo_GetDocumentation_Stub( + ITypeInfo* This, + MEMBERID memid, + DWORD refPtrFlags, + BSTR* pBstrName, + BSTR* pBstrDocString, + DWORD* pdwHelpContext, + BSTR* pBstrHelpFile) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK ITypeInfo_GetDllEntry_Proxy( + ITypeInfo* This, + MEMBERID memid, + INVOKEKIND invKind, + BSTR* pBstrDllName, + BSTR* pBstrName, + WORD* pwOrdinal) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB ITypeInfo_GetDllEntry_Stub( + ITypeInfo* This, + MEMBERID memid, + INVOKEKIND invKind, + DWORD refPtrFlags, + BSTR* pBstrDllName, + BSTR* pBstrName, + WORD* pwOrdinal) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK ITypeInfo_AddressOfMember_Proxy( + ITypeInfo* This, + MEMBERID memid, + INVOKEKIND invKind, + PVOID* ppv) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB ITypeInfo_AddressOfMember_Stub( + ITypeInfo* This) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK ITypeInfo_CreateInstance_Proxy( + ITypeInfo* This, + IUnknown* pUnkOuter, + REFIID riid, + PVOID* ppvObj) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB ITypeInfo_CreateInstance_Stub( + ITypeInfo* This, + REFIID riid, + IUnknown** ppvObj) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK ITypeInfo_GetContainingTypeLib_Proxy( + ITypeInfo* This, + ITypeLib** ppTLib, + UINT* pIndex) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB ITypeInfo_GetContainingTypeLib_Stub( + ITypeInfo* This, + ITypeLib** ppTLib, + UINT* pIndex) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +void CALLBACK ITypeInfo_ReleaseTypeAttr_Proxy( + ITypeInfo* This, + TYPEATTR* pTypeAttr) +{ + FIXME("not implemented\n"); +} + +HRESULT __RPC_STUB ITypeInfo_ReleaseTypeAttr_Stub( + ITypeInfo* This) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +void CALLBACK ITypeInfo_ReleaseFuncDesc_Proxy( + ITypeInfo* This, + FUNCDESC* pFuncDesc) +{ + FIXME("not implemented\n"); +} + +HRESULT __RPC_STUB ITypeInfo_ReleaseFuncDesc_Stub( + ITypeInfo* This) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +void CALLBACK ITypeInfo_ReleaseVarDesc_Proxy( + ITypeInfo* This, + VARDESC* pVarDesc) +{ + FIXME("not implemented\n"); +} + +HRESULT __RPC_STUB ITypeInfo_ReleaseVarDesc_Stub( + ITypeInfo* This) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + + +/* ITypeInfo2 */ + +HRESULT CALLBACK ITypeInfo2_GetDocumentation2_Proxy( + ITypeInfo2* This, + MEMBERID memid, + LCID lcid, + BSTR* pbstrHelpString, + DWORD* pdwHelpStringContext, + BSTR* pbstrHelpStringDll) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB ITypeInfo2_GetDocumentation2_Stub( + ITypeInfo2* This, + MEMBERID memid, + LCID lcid, + DWORD refPtrFlags, + BSTR* pbstrHelpString, + DWORD* pdwHelpStringContext, + BSTR* pbstrHelpStringDll) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +/* ITypeLib */ + +UINT CALLBACK ITypeLib_GetTypeInfoCount_Proxy( + ITypeLib* This) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB ITypeLib_GetTypeInfoCount_Stub( + ITypeLib* This, + UINT* pcTInfo) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK ITypeLib_GetLibAttr_Proxy( + ITypeLib* This, + TLIBATTR** ppTLibAttr) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB ITypeLib_GetLibAttr_Stub( + ITypeLib* This, + LPTLIBATTR* ppTLibAttr, + CLEANLOCALSTORAGE* pDummy) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK ITypeLib_GetDocumentation_Proxy( + ITypeLib* This, + INT index, + BSTR* pBstrName, + BSTR* pBstrDocString, + DWORD* pdwHelpContext, + BSTR* pBstrHelpFile) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB ITypeLib_GetDocumentation_Stub( + ITypeLib* This, + INT index, + DWORD refPtrFlags, + BSTR* pBstrName, + BSTR* pBstrDocString, + DWORD* pdwHelpContext, + BSTR* pBstrHelpFile) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK ITypeLib_IsName_Proxy( + ITypeLib* This, + LPOLESTR szNameBuf, + ULONG lHashVal, + BOOL* pfName) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB ITypeLib_IsName_Stub( + ITypeLib* This, + LPOLESTR szNameBuf, + ULONG lHashVal, + BOOL* pfName, + BSTR* pBstrLibName) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK ITypeLib_FindName_Proxy( + ITypeLib* This, + LPOLESTR szNameBuf, + ULONG lHashVal, + ITypeInfo** ppTInfo, + MEMBERID* rgMemId, + USHORT* pcFound) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB ITypeLib_FindName_Stub( + ITypeLib* This, + LPOLESTR szNameBuf, + ULONG lHashVal, + ITypeInfo** ppTInfo, + MEMBERID* rgMemId, + USHORT* pcFound, + BSTR* pBstrLibName) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +void CALLBACK ITypeLib_ReleaseTLibAttr_Proxy( + ITypeLib* This, + TLIBATTR* pTLibAttr) +{ + FIXME("not implemented\n"); +} + +HRESULT __RPC_STUB ITypeLib_ReleaseTLibAttr_Stub( + ITypeLib* This) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + + +/* ITypeLib2 */ + +HRESULT CALLBACK ITypeLib2_GetLibStatistics_Proxy( + ITypeLib2* This, + ULONG* pcUniqueNames, + ULONG* pcchUniqueNames) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB ITypeLib2_GetLibStatistics_Stub( + ITypeLib2* This, + ULONG* pcUniqueNames, + ULONG* pcchUniqueNames) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT CALLBACK ITypeLib2_GetDocumentation2_Proxy( + ITypeLib2* This, + INT index, + LCID lcid, + BSTR* pbstrHelpString, + DWORD* pdwHelpStringContext, + BSTR* pbstrHelpStringDll) +{ + FIXME("not implemented\n"); + return E_FAIL; +} + +HRESULT __RPC_STUB ITypeLib2_GetDocumentation2_Stub( + ITypeLib2* This, + INT index, + LCID lcid, + DWORD refPtrFlags, + BSTR* pbstrHelpString, + DWORD* pdwHelpStringContext, + BSTR* pbstrHelpStringDll) +{ + FIXME("not implemented\n"); + return E_FAIL; +} diff --git a/reactos/lib/oleaut32/varformat.c b/reactos/lib/oleaut32/varformat.c index ef2c06e326b..32770f8e5cf 100644 --- a/reactos/lib/oleaut32/varformat.c +++ b/reactos/lib/oleaut32/varformat.c @@ -1,2407 +1,2407 @@ -/* - * Variant formatting functions - * - * Copyright 2003 Jon Griffiths - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTES - * Since the formatting functions aren't properly documented, I used the - * Visual Basic documentation as a guide to implementing these functions. This - * means that some named or user-defined formats may work slightly differently. - * Please submit a test case if you find a difference. - */ - -#include "config.h" - -#include <string.h> -#include <stdlib.h> -#include <stdarg.h> -#include <stdio.h> - -#define NONAMELESSUNION -#define NONAMELESSSTRUCT -#include "windef.h" -#include "winbase.h" -#include "wine/unicode.h" -#include "winerror.h" -#include "variant.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(variant); - -/* Make sure internal conversions to strings use the '.','+'/'-' and ',' - * format chars from the US locale. This enables us to parse the created - * strings to determine the number of decimal places, exponent, etc. - */ -#define LCID_US MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT) - -static const WCHAR szPercent_d[] = { '%','d','\0' }; -static const WCHAR szPercentZeroTwo_d[] = { '%','0','2','d','\0' }; -static const WCHAR szPercentZeroFour_d[] = { '%','0','4','d','\0' }; -static const WCHAR szPercentZeroStar_d[] = { '%','0','*','d','\0' }; - -#if 0 -#define dump_tokens(rgb) do { \ - int i_; TRACE("Tokens->{ \n"); \ - for (i_ = 0; i_ < rgb[0]; i_++) \ - TRACE("%s0x%02x", i_?",":"",rgb[i_]); \ - TRACE(" }\n"); \ - } while(0) -#endif - -/****************************************************************************** - * Variant-Formats {OLEAUT32} - * - * NOTES - * When formatting a variant a variety of format strings may be used to generate - * different kinds of formatted output. A format string consists of either a named - * format, or a user-defined format. - * - * The following named formats are defined: - *| Name Description - *| ---- ----------- - *| General Date Display Date, and time for non-integer values - *| Short Date Short date format as defined by locale settings - *| Medium Date Medium date format as defined by locale settings - *| Long Date Long date format as defined by locale settings - *| Short Time Short Time format as defined by locale settings - *| Medium Time Medium time format as defined by locale settings - *| Long Time Long time format as defined by locale settings - *| True/False Localised text of "True" or "False" - *| Yes/No Localised text of "Yes" or "No" - *| On/Off Localised text of "On" or "Off" - *| General Number No thousands separator. No decimal points for integers - *| Currency General currency format using localised characters - *| Fixed At least one whole and two fractional digits - *| Standard Same as 'Fixed', but including decimal separators - *| Percent Multiply by 100 and display a trailing '%' character - *| Scientific Display with exponent - * - * User-defined formats consist of a combination of tokens and literal - * characters. Literal characters are copied unmodified to the formatted - * output at the position they occupy in the format string. Any character - * that is not recognised as a token is treated as a literal. A literal can - * also be specified by preceding it with a backslash character - * (e.g. "\L\i\t\e\r\a\l") or enclosing it in double quotes. - * - * A user-defined format can have up to 4 sections, depending on the type of - * format. The following table lists sections and their meaning: - *| Format Type Sections Meaning - *| ----------- -------- ------- - *| Number 1 Use the same format for all numbers - *| Number 2 Use format 1 for positive and 2 for negative numbers - *| Number 3 Use format 1 for positive, 2 for zero, and 3 - *| for negative numbers. - *| Number 4 Use format 1 for positive, 2 for zero, 3 for - *| negative, and 4 for null numbers. - *| String 1 Use the same format for all strings - *| String 2 Use format 2 for null and empty strings, otherwise - *| use format 1. - *| Date 1 Use the same format for all dates - * - * The formatting tokens fall into several categories depending on the type - * of formatted output. For more information on each type, see - * VarFormat-Dates(), VarFormat-Strings() and VarFormat-Numbers(). - * - * SEE ALSO - * VarTokenizeFormatString(), VarFormatFromTokens(), VarFormat(), - * VarFormatDateTime(), VarFormatNumber(), VarFormatCurrency(). - */ - -/****************************************************************************** - * VarFormat-Strings {OLEAUT32} - * - * NOTES - * When formatting a variant as a string, it is first converted to a VT_BSTR. - * The user-format string defines which characters are copied into which - * positions in the output string. Literals may be inserted in the format - * string. When creating the formatted string, excess characters in the string - * (those not consumed by a token) are appended to the end of the output. If - * there are more tokens than characters in the string to format, spaces will - * be inserted at the start of the string if the '@' token was used. - * - * By default strings are converted to lowercase, or uppercase if the '>' token - * is encountered. This applies to the whole string: it is not possible to - * generate a mixed-case output string. - * - * In user-defined string formats, the following tokens are recognised: - *| Token Description - *| ----- ----------- - *| '@' Copy a char from the source, or a space if no chars are left. - *| '&' Copy a char from the source, or write nothing if no chars are left. - *| '<' Output the whole string as lower-case (the default). - *| '>' Output the whole string as upper-case. - *| '!' MSDN indicates that this character should cause right-to-left - *| copying, however tests show that it is tokenised but not processed. - */ - -/* - * Common format definitions - */ - - /* Fomat types */ -#define FMT_TYPE_UNKNOWN 0x0 -#define FMT_TYPE_GENERAL 0x1 -#define FMT_TYPE_NUMBER 0x2 -#define FMT_TYPE_DATE 0x3 -#define FMT_TYPE_STRING 0x4 - -#define FMT_TO_STRING 0x0 /* If header->size == this, act like VB's Str() fn */ - -typedef struct tagFMT_SHORT_HEADER -{ - BYTE size; /* Size of tokenised block (including header), or FMT_TO_STRING */ - BYTE type; /* Allowable types (FMT_TYPE_*) */ - BYTE offset[1]; /* Offset of the first (and only) format section */ -} FMT_SHORT_HEADER; - -typedef struct tagFMT_HEADER -{ - BYTE size; /* Total size of the whole tokenised block (including header) */ - BYTE type; /* Allowable types (FMT_TYPE_*) */ - BYTE starts[4]; /* Offset of each of the 4 format sections, or 0 if none */ -} FMT_HEADER; - -#define FmtGetPositive(x) (x->starts[0]) -#define FmtGetNegative(x) (x->starts[1] ? x->starts[1] : x->starts[0]) -#define FmtGetZero(x) (x->starts[2] ? x->starts[2] : x->starts[0]) -#define FmtGetNull(x) (x->starts[3] ? x->starts[3] : x->starts[0]) - -/* - * String formats - */ - -#define FMT_FLAG_LT 0x1 /* Has '<' (lower case) */ -#define FMT_FLAG_GT 0x2 /* Has '>' (upper case) */ -#define FMT_FLAG_RTL 0x4 /* Has '!' (Copy right to left) */ - -typedef struct tagFMT_STRING_HEADER -{ - BYTE flags; /* LT, GT, RTL */ - BYTE unknown1; - BYTE unknown2; - BYTE copy_chars; /* Number of chars to be copied */ - BYTE unknown3; -} FMT_STRING_HEADER; - -/* - * Number formats - */ - -#define FMT_FLAG_PERCENT 0x1 /* Has '%' (Percentage) */ -#define FMT_FLAG_EXPONENT 0x2 /* Has 'e' (Exponent/Scientific notation) */ -#define FMT_FLAG_THOUSANDS 0x4 /* Has ',' (Standard use of the thousands separator) */ -#define FMT_FLAG_BOOL 0x20 /* Boolean format */ - -typedef struct tagFMT_NUMBER_HEADER -{ - BYTE flags; /* PERCENT, EXPONENT, THOUSANDS, BOOL */ - BYTE multiplier; /* Multiplier, 100 for percentages */ - BYTE divisor; /* Divisor, 1000 if '%%' was used */ - BYTE whole; /* Number of digits before the decimal point */ - BYTE fractional; /* Number of digits after the decimal point */ -} FMT_NUMBER_HEADER; - -/* - * Date Formats - */ -typedef struct tagFMT_DATE_HEADER -{ - BYTE flags; - BYTE unknown1; - BYTE unknown2; - BYTE unknown3; - BYTE unknown4; -} FMT_DATE_HEADER; - -/* - * Format token values - */ -#define FMT_GEN_COPY 0x00 /* \n, "lit" => 0,pos,len: Copy len chars from input+pos */ -#define FMT_GEN_INLINE 0x01 /* => 1,len,[chars]: Copy len chars from token stream */ -#define FMT_GEN_END 0x02 /* \0,; => 2: End of the tokenised format */ -#define FMT_DATE_TIME_SEP 0x03 /* Time separator char */ -#define FMT_DATE_DATE_SEP 0x04 /* Date separator char */ -#define FMT_DATE_GENERAL 0x05 /* General format date */ -#define FMT_DATE_QUARTER 0x06 /* Quarter of the year from 1-4 */ -#define FMT_DATE_TIME_SYS 0x07 /* System long time format */ -#define FMT_DATE_DAY 0x08 /* Day with no leading 0 */ -#define FMT_DATE_DAY_0 0x09 /* Day with leading 0 */ -#define FMT_DATE_DAY_SHORT 0x0A /* Short day name */ -#define FMT_DATE_DAY_LONG 0x0B /* Long day name */ -#define FMT_DATE_SHORT 0x0C /* Short date format */ -#define FMT_DATE_LONG 0x0D /* Long date format */ -#define FMT_DATE_MEDIUM 0x0E /* Medium date format */ -#define FMT_DATE_DAY_WEEK 0x0F /* First day of the week */ -#define FMT_DATE_WEEK_YEAR 0x10 /* First week of the year */ -#define FMT_DATE_MON 0x11 /* Month with no leading 0 */ -#define FMT_DATE_MON_0 0x12 /* Month with leading 0 */ -#define FMT_DATE_MON_SHORT 0x13 /* Short month name */ -#define FMT_DATE_MON_LONG 0x14 /* Long month name */ -#define FMT_DATE_YEAR_DOY 0x15 /* Day of the year with no leading 0 */ -#define FMT_DATE_YEAR_0 0x16 /* 2 digit year with leading 0 */ -/* NOTE: token 0x17 is not defined, 'yyy' is not valid */ -#define FMT_DATE_YEAR_LONG 0x18 /* 4 digit year */ -#define FMT_DATE_MIN 0x1A /* Minutes with no leading 0 */ -#define FMT_DATE_MIN_0 0x1B /* Minutes with leading 0 */ -#define FMT_DATE_SEC 0x1C /* Seconds with no leading 0 */ -#define FMT_DATE_SEC_0 0x1D /* Seconds with leading 0 */ -#define FMT_DATE_HOUR 0x1E /* Hours with no leading 0 */ -#define FMT_DATE_HOUR_0 0x1F /* Hours with leading 0 */ -#define FMT_DATE_HOUR_12 0x20 /* Hours with no leading 0, 12 hour clock */ -#define FMT_DATE_HOUR_12_0 0x21 /* Hours with leading 0, 12 hour clock */ -#define FMT_DATE_TIME_UNK2 0x23 -/* FIXME: probably missing some here */ -#define FMT_DATE_AMPM_SYS1 0x2E /* AM/PM as defined by system settings */ -#define FMT_DATE_AMPM_UPPER 0x2F /* Upper-case AM or PM */ -#define FMT_DATE_A_UPPER 0x30 /* Upper-case A or P */ -#define FMT_DATE_AMPM_SYS2 0x31 /* AM/PM as defined by system settings */ -#define FMT_DATE_AMPM_LOWER 0x32 /* Lower-case AM or PM */ -#define FMT_DATE_A_LOWER 0x33 /* Lower-case A or P */ -#define FMT_NUM_COPY_ZERO 0x34 /* Copy 1 digit or 0 if no digit */ -#define FMT_NUM_COPY_SKIP 0x35 /* Copy 1 digit or skip if no digit */ -#define FMT_NUM_DECIMAL 0x36 /* Decimal separator */ -#define FMT_NUM_EXP_POS_U 0x37 /* Scientific notation, uppercase, + sign */ -#define FMT_NUM_EXP_NEG_U 0x38 /* Scientific notation, lowercase, - sign */ -#define FMT_NUM_EXP_POS_L 0x39 /* Scientific notation, uppercase, + sign */ -#define FMT_NUM_EXP_NEG_L 0x3A /* Scientific notation, lowercase, - sign */ -#define FMT_NUM_CURRENCY 0x3B /* Currency symbol */ -#define FMT_NUM_TRUE_FALSE 0x3D /* Convert to "True" or "False" */ -#define FMT_NUM_YES_NO 0x3E /* Convert to "Yes" or "No" */ -#define FMT_NUM_ON_OFF 0x3F /* Convert to "On" or "Off" */ -#define FMT_STR_COPY_SPACE 0x40 /* Copy len chars with space if no char */ -#define FMT_STR_COPY_SKIP 0x41 /* Copy len chars or skip if no char */ -/* Wine additions */ -#define FMT_WINE_HOURS_12 0x81 /* Hours using 12 hour clockhourCopy len chars or skip if no char */ - -/* Named Formats and their tokenised values */ -static const WCHAR szGeneralDate[] = { 'G','e','n','e','r','a','l',' ','D','a','t','e','\0' }; -static const BYTE fmtGeneralDate[0x0a] = -{ - 0x0a,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER), - 0x0,0x0,0x0,0x0,0x0, - FMT_DATE_GENERAL,FMT_GEN_END -}; - -static const WCHAR szShortDate[] = { 'S','h','o','r','t',' ','D','a','t','e','\0' }; -static const BYTE fmtShortDate[0x0a] = -{ - 0x0a,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER), - 0x0,0x0,0x0,0x0,0x0, - FMT_DATE_SHORT,FMT_GEN_END -}; - -static const WCHAR szMediumDate[] = { 'M','e','d','i','u','m',' ','D','a','t','e','\0' }; -static const BYTE fmtMediumDate[0x0a] = -{ - 0x0a,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER), - 0x0,0x0,0x0,0x0,0x0, - FMT_DATE_MEDIUM,FMT_GEN_END -}; - -static const WCHAR szLongDate[] = { 'L','o','n','g',' ','D','a','t','e','\0' }; -static const BYTE fmtLongDate[0x0a] = -{ - 0x0a,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER), - 0x0,0x0,0x0,0x0,0x0, - FMT_DATE_LONG,FMT_GEN_END -}; - -static const WCHAR szShortTime[] = { 'S','h','o','r','t',' ','T','i','m','e','\0' }; -static const BYTE fmtShortTime[0x0c] = -{ - 0x0c,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER), - 0x0,0x0,0x0,0x0,0x0, - FMT_DATE_TIME_UNK2,FMT_DATE_TIME_SEP,FMT_DATE_MIN_0,FMT_GEN_END -}; - -static const WCHAR szMediumTime[] = { 'M','e','d','i','u','m',' ','T','i','m','e','\0' }; -static const BYTE fmtMediumTime[0x11] = -{ - 0x11,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER), - 0x0,0x0,0x0,0x0,0x0, - FMT_DATE_HOUR_12_0,FMT_DATE_TIME_SEP,FMT_DATE_MIN_0, - FMT_GEN_INLINE,0x01,' ','\0',FMT_DATE_AMPM_SYS1,FMT_GEN_END -}; - -static const WCHAR szLongTime[] = { 'L','o','n','g',' ','T','i','m','e','\0' }; -static const BYTE fmtLongTime[0x0d] = -{ - 0x0a,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER), - 0x0,0x0,0x0,0x0,0x0, - FMT_DATE_TIME_SYS,FMT_GEN_END -}; - -static const WCHAR szTrueFalse[] = { 'T','r','u','e','/','F','a','l','s','e','\0' }; -static const BYTE fmtTrueFalse[0x0d] = -{ - 0x0d,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0, - FMT_FLAG_BOOL,0x0,0x0,0x0,0x0, - FMT_NUM_TRUE_FALSE,FMT_GEN_END -}; - -static const WCHAR szYesNo[] = { 'Y','e','s','/','N','o','\0' }; -static const BYTE fmtYesNo[0x0d] = -{ - 0x0d,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0, - FMT_FLAG_BOOL,0x0,0x0,0x0,0x0, - FMT_NUM_YES_NO,FMT_GEN_END -}; - -static const WCHAR szOnOff[] = { 'O','n','/','O','f','f','\0' }; -static const BYTE fmtOnOff[0x0d] = -{ - 0x0d,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0, - FMT_FLAG_BOOL,0x0,0x0,0x0,0x0, - FMT_NUM_ON_OFF,FMT_GEN_END -}; - -static const WCHAR szGeneralNumber[] = { 'G','e','n','e','r','a','l',' ','N','u','m','b','e','r','\0' }; -static const BYTE fmtGeneralNumber[sizeof(FMT_HEADER)] = -{ - sizeof(FMT_HEADER),FMT_TYPE_GENERAL,sizeof(FMT_HEADER),0x0,0x0,0x0 -}; - -static const WCHAR szCurrency[] = { 'C','u','r','r','e','n','c','y','\0' }; -static const BYTE fmtCurrency[0x26] = -{ - 0x26,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x12,0x0,0x0, - /* Positive numbers */ - FMT_FLAG_THOUSANDS,0xcc,0x0,0x1,0x2, - FMT_NUM_CURRENCY,FMT_NUM_COPY_ZERO,0x1,FMT_NUM_DECIMAL,FMT_NUM_COPY_ZERO,0x2, - FMT_GEN_END, - /* Negative numbers */ - FMT_FLAG_THOUSANDS,0xcc,0x0,0x1,0x2, - FMT_GEN_INLINE,0x1,'(','\0',FMT_NUM_CURRENCY,FMT_NUM_COPY_ZERO,0x1, - FMT_NUM_DECIMAL,FMT_NUM_COPY_ZERO,0x2,FMT_GEN_INLINE,0x1,')','\0', - FMT_GEN_END -}; - -static const WCHAR szFixed[] = { 'F','i','x','e','d','\0' }; -static const BYTE fmtFixed[0x11] = -{ - 0x11,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0, - 0x0,0x0,0x0,0x1,0x2, - FMT_NUM_COPY_ZERO,0x1,FMT_NUM_DECIMAL,FMT_NUM_COPY_ZERO,0x2,FMT_GEN_END -}; - -static const WCHAR szStandard[] = { 'S','t','a','n','d','a','r','d','\0' }; -static const BYTE fmtStandard[0x11] = -{ - 0x11,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0, - FMT_FLAG_THOUSANDS,0x0,0x0,0x1,0x2, - FMT_NUM_COPY_ZERO,0x1,FMT_NUM_DECIMAL,FMT_NUM_COPY_ZERO,0x2,FMT_GEN_END -}; - -static const WCHAR szPercent[] = { 'P','e','r','c','e','n','t','\0' }; -static const BYTE fmtPercent[0x15] = -{ - 0x15,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0, - FMT_FLAG_PERCENT,0x1,0x0,0x1,0x2, - FMT_NUM_COPY_ZERO,0x1,FMT_NUM_DECIMAL,FMT_NUM_COPY_ZERO,0x2, - FMT_GEN_INLINE,0x1,'%','\0',FMT_GEN_END -}; - -static const WCHAR szScientific[] = { 'S','c','i','e','n','t','i','f','i','c','\0' }; -static const BYTE fmtScientific[0x13] = -{ - 0x13,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0, - FMT_FLAG_EXPONENT,0x0,0x0,0x1,0x2, - FMT_NUM_COPY_ZERO,0x1,FMT_NUM_DECIMAL,FMT_NUM_COPY_ZERO,0x2,FMT_NUM_EXP_POS_U,0x2,FMT_GEN_END -}; - -typedef struct tagNAMED_FORMAT -{ - LPCWSTR name; - const BYTE* format; -} NAMED_FORMAT; - -/* Format name to tokenised format. Must be kept sorted by name */ -static const NAMED_FORMAT VARIANT_NamedFormats[] = -{ - { szCurrency, fmtCurrency }, - { szFixed, fmtFixed }, - { szGeneralDate, fmtGeneralDate }, - { szGeneralNumber, fmtGeneralNumber }, - { szLongDate, fmtLongDate }, - { szLongTime, fmtLongTime }, - { szMediumDate, fmtMediumDate }, - { szMediumTime, fmtMediumTime }, - { szOnOff, fmtOnOff }, - { szPercent, fmtPercent }, - { szScientific, fmtScientific }, - { szShortDate, fmtShortDate }, - { szShortTime, fmtShortTime }, - { szStandard, fmtStandard }, - { szTrueFalse, fmtTrueFalse }, - { szYesNo, fmtYesNo } -}; -typedef const NAMED_FORMAT *LPCNAMED_FORMAT; - -static int FormatCompareFn(const void *l, const void *r) -{ - return strcmpiW(((LPCNAMED_FORMAT)l)->name, ((LPCNAMED_FORMAT)r)->name); -} - -static inline const BYTE *VARIANT_GetNamedFormat(LPCWSTR lpszFormat) -{ - NAMED_FORMAT key; - LPCNAMED_FORMAT fmt; - - key.name = lpszFormat; - fmt = (LPCNAMED_FORMAT)bsearch(&key, VARIANT_NamedFormats, - sizeof(VARIANT_NamedFormats)/sizeof(NAMED_FORMAT), - sizeof(NAMED_FORMAT), FormatCompareFn); - return fmt ? fmt->format : NULL; -} - -/* Return an error if the token for the value will not fit in the destination */ -#define NEED_SPACE(x) if (cbTok < (int)(x)) return TYPE_E_BUFFERTOOSMALL; cbTok -= (x) - -/* Non-zero if the format is unknown or a given type */ -#define COULD_BE(typ) ((!fmt_number && header->type==FMT_TYPE_UNKNOWN)||header->type==typ) - -/* State during tokenising */ -#define FMT_STATE_OPEN_COPY 0x1 /* Last token written was a copy */ -#define FMT_STATE_WROTE_DECIMAL 0x2 /* Already wrote a decimal separator */ -#define FMT_STATE_SEEN_HOURS 0x4 /* See the hh specifier */ -#define FMT_STATE_WROTE_MINUTES 0x8 /* Wrote minutes */ - -/********************************************************************** - * VarTokenizeFormatString [OLEAUT32.140] - * - * Convert a format string into tokenised form. - * - * PARAMS - * lpszFormat [I] Format string to tokenise - * rgbTok [O] Destination for tokenised format - * cbTok [I] Size of rgbTok in bytes - * nFirstDay [I] First day of the week (1-7, or 0 for current system default) - * nFirstWeek [I] How to treat the first week (see notes) - * lcid [I] Locale Id of the format string - * pcbActual [O] If non-NULL, filled with the first token generated - * - * RETURNS - * Success: S_OK. rgbTok contains the tokenised format. - * Failure: E_INVALIDARG, if any argument is invalid. - * TYPE_E_BUFFERTOOSMALL, if rgbTok is not large enough. - * - * NOTES - * Valid values for the nFirstWeek parameter are: - *| Value Meaning - *| ----- ------- - *| 0 Use the current system default - *| 1 The first week is that containing Jan 1 - *| 2 Four or more days of the first week are in the current year - *| 3 The first week is 7 days long - * See Variant-Formats(), VarFormatFromTokens(). - */ -HRESULT WINAPI VarTokenizeFormatString(LPOLESTR lpszFormat, LPBYTE rgbTok, - int cbTok, int nFirstDay, int nFirstWeek, - LCID lcid, int *pcbActual) -{ - /* Note: none of these strings should be NUL terminated */ - static const WCHAR szTTTTT[] = { 't','t','t','t','t' }; - static const WCHAR szAMPM[] = { 'A','M','P','M' }; - static const WCHAR szampm[] = { 'a','m','p','m' }; - static const WCHAR szAMSlashPM[] = { 'A','M','/','P','M' }; - static const WCHAR szamSlashpm[] = { 'a','m','/','p','m' }; - const BYTE *namedFmt; - FMT_HEADER *header = (FMT_HEADER*)rgbTok; - FMT_STRING_HEADER *str_header = (FMT_STRING_HEADER*)(rgbTok + sizeof(FMT_HEADER)); - FMT_NUMBER_HEADER *num_header = (FMT_NUMBER_HEADER*)str_header; - FMT_DATE_HEADER *date_header = (FMT_DATE_HEADER*)str_header; - BYTE* pOut = rgbTok + sizeof(FMT_HEADER) + sizeof(FMT_STRING_HEADER); - BYTE* pLastHours = NULL; - BYTE fmt_number = 0; - DWORD fmt_state = 0; - LPCWSTR pFormat = lpszFormat; - - TRACE("(%s,%p,%d,%d,%d,0x%08lx,%p)\n", debugstr_w(lpszFormat), rgbTok, cbTok, - nFirstDay, nFirstWeek, lcid, pcbActual); - - if (!rgbTok || - nFirstDay < 0 || nFirstDay > 7 || nFirstWeek < 0 || nFirstWeek > 3) - return E_INVALIDARG; - - if (!lpszFormat || !*lpszFormat) - { - /* An empty string means 'general format' */ - NEED_SPACE(sizeof(BYTE)); - *rgbTok = FMT_TO_STRING; - if (pcbActual) - *pcbActual = FMT_TO_STRING; - return S_OK; - } - - if (cbTok > 255) - cbTok = 255; /* Ensure we error instead of wrapping */ - - /* Named formats */ - namedFmt = VARIANT_GetNamedFormat(lpszFormat); - if (namedFmt) - { - NEED_SPACE(namedFmt[0]); - memcpy(rgbTok, namedFmt, namedFmt[0]); - TRACE("Using pre-tokenised named format %s\n", debugstr_w(lpszFormat)); - /* FIXME: pcbActual */ - return S_OK; - } - - /* Insert header */ - NEED_SPACE(sizeof(FMT_HEADER) + sizeof(FMT_STRING_HEADER)); - memset(header, 0, sizeof(FMT_HEADER)); - memset(str_header, 0, sizeof(FMT_STRING_HEADER)); - - header->starts[fmt_number] = sizeof(FMT_HEADER); - - while (*pFormat) - { - /* -------------- - * General tokens - * -------------- - */ - if (*pFormat == ';') - { - while (*pFormat == ';') - { - TRACE(";\n"); - if (++fmt_number > 3) - return E_INVALIDARG; /* too many formats */ - pFormat++; - } - if (*pFormat) - { - TRACE("New header\n"); - NEED_SPACE(sizeof(BYTE) + sizeof(FMT_STRING_HEADER)); - *pOut++ = FMT_GEN_END; - - header->starts[fmt_number] = pOut - rgbTok; - str_header = (FMT_STRING_HEADER*)pOut; - num_header = (FMT_NUMBER_HEADER*)pOut; - date_header = (FMT_DATE_HEADER*)pOut; - memset(str_header, 0, sizeof(FMT_STRING_HEADER)); - pOut += sizeof(FMT_STRING_HEADER); - fmt_state = 0; - pLastHours = NULL; - } - } - else if (*pFormat == '\\') - { - /* Escaped character */ - if (pFormat[1]) - { - NEED_SPACE(3 * sizeof(BYTE)); - pFormat++; - *pOut++ = FMT_GEN_COPY; - *pOut++ = pFormat - lpszFormat; - *pOut++ = 0x1; - fmt_state |= FMT_STATE_OPEN_COPY; - TRACE("'\\'\n"); - } - else - fmt_state &= ~FMT_STATE_OPEN_COPY; - pFormat++; - } - else if (*pFormat == '"') - { - /* Escaped string - * Note: Native encodes "" as a copy of length zero. That's just dumb, so - * here we avoid encoding anything in this case. - */ - if (!pFormat[1]) - pFormat++; - else if (pFormat[1] == '"') - { - pFormat += 2; - } - else - { - LPCWSTR start = ++pFormat; - while (*pFormat && *pFormat != '"') - pFormat++; - NEED_SPACE(3 * sizeof(BYTE)); - *pOut++ = FMT_GEN_COPY; - *pOut++ = start - lpszFormat; - *pOut++ = pFormat - start; - if (*pFormat == '"') - pFormat++; - TRACE("Quoted string pos %d, len %d\n", pOut[-2], pOut[-1]); - } - fmt_state &= ~FMT_STATE_OPEN_COPY; - } - /* ------------- - * Number tokens - * ------------- - */ - else if (*pFormat == '0' && COULD_BE(FMT_TYPE_NUMBER)) - { - /* Number formats: Digit from number or '0' if no digits - * Other formats: Literal - * Types the format if found - */ - header->type = FMT_TYPE_NUMBER; - NEED_SPACE(2 * sizeof(BYTE)); - *pOut++ = FMT_NUM_COPY_ZERO; - *pOut = 0x0; - while (*pFormat == '0') - { - *pOut = *pOut + 1; - pFormat++; - } - if (fmt_state & FMT_STATE_WROTE_DECIMAL) - num_header->fractional += *pOut; - else - num_header->whole += *pOut; - TRACE("%d 0's\n", *pOut); - pOut++; - fmt_state &= ~FMT_STATE_OPEN_COPY; - } - else if (*pFormat == '#' && COULD_BE(FMT_TYPE_NUMBER)) - { - /* Number formats: Digit from number or blank if no digits - * Other formats: Literal - * Types the format if found - */ - header->type = FMT_TYPE_NUMBER; - NEED_SPACE(2 * sizeof(BYTE)); - *pOut++ = FMT_NUM_COPY_SKIP; - *pOut = 0x0; - while (*pFormat == '#') - { - *pOut = *pOut + 1; - pFormat++; - } - if (fmt_state & FMT_STATE_WROTE_DECIMAL) - num_header->fractional += *pOut; - else - num_header->whole += *pOut; - TRACE("%d #'s\n", *pOut); - pOut++; - fmt_state &= ~FMT_STATE_OPEN_COPY; - } - else if (*pFormat == '.' && COULD_BE(FMT_TYPE_NUMBER) && - !(fmt_state & FMT_STATE_WROTE_DECIMAL)) - { - /* Number formats: Decimal separator when 1st seen, literal thereafter - * Other formats: Literal - * Types the format if found - */ - header->type = FMT_TYPE_NUMBER; - NEED_SPACE(sizeof(BYTE)); - *pOut++ = FMT_NUM_DECIMAL; - fmt_state |= FMT_STATE_WROTE_DECIMAL; - fmt_state &= ~FMT_STATE_OPEN_COPY; - pFormat++; - TRACE("decimal sep\n"); - } - /* FIXME: E+ E- e+ e- => Exponent */ - /* FIXME: %% => Divide by 1000 */ - else if (*pFormat == ',' && header->type == FMT_TYPE_NUMBER) - { - /* Number formats: Use the thousands separator - * Other formats: Literal - */ - num_header->flags |= FMT_FLAG_THOUSANDS; - pFormat++; - fmt_state &= ~FMT_STATE_OPEN_COPY; - TRACE("thousands sep\n"); - } - /* ----------- - * Date tokens - * ----------- - */ - else if (*pFormat == '/' && COULD_BE(FMT_TYPE_DATE)) - { - /* Date formats: Date separator - * Other formats: Literal - * Types the format if found - */ - header->type = FMT_TYPE_DATE; - NEED_SPACE(sizeof(BYTE)); - *pOut++ = FMT_DATE_DATE_SEP; - pFormat++; - fmt_state &= ~FMT_STATE_OPEN_COPY; - TRACE("date sep\n"); - } - else if (*pFormat == ':' && COULD_BE(FMT_TYPE_DATE)) - { - /* Date formats: Time separator - * Other formats: Literal - * Types the format if found - */ - header->type = FMT_TYPE_DATE; - NEED_SPACE(sizeof(BYTE)); - *pOut++ = FMT_DATE_TIME_SEP; - pFormat++; - fmt_state &= ~FMT_STATE_OPEN_COPY; - TRACE("time sep\n"); - } - else if ((*pFormat == 'a' || *pFormat == 'A') && - !strncmpiW(pFormat, szAMPM, sizeof(szAMPM)/sizeof(WCHAR))) - { - /* Date formats: System AM/PM designation - * Other formats: Literal - * Types the format if found - */ - header->type = FMT_TYPE_DATE; - NEED_SPACE(sizeof(BYTE)); - pFormat += sizeof(szAMPM)/sizeof(WCHAR); - if (!strncmpW(pFormat, szampm, sizeof(szampm)/sizeof(WCHAR))) - *pOut++ = FMT_DATE_AMPM_SYS2; - else - *pOut++ = FMT_DATE_AMPM_SYS1; - if (pLastHours) - *pLastHours = *pLastHours + 2; - TRACE("ampm\n"); - } - else if (*pFormat == 'a' && pFormat[1] == '/' && - (pFormat[2] == 'p' || pFormat[2] == 'P')) - { - /* Date formats: lowercase a or p designation - * Other formats: Literal - * Types the format if found - */ - header->type = FMT_TYPE_DATE; - NEED_SPACE(sizeof(BYTE)); - pFormat += 3; - *pOut++ = FMT_DATE_A_LOWER; - if (pLastHours) - *pLastHours = *pLastHours + 2; - TRACE("a/p\n"); - } - else if (*pFormat == 'A' && pFormat[1] == '/' && - (pFormat[2] == 'p' || pFormat[2] == 'P')) - { - /* Date formats: Uppercase a or p designation - * Other formats: Literal - * Types the format if found - */ - header->type = FMT_TYPE_DATE; - NEED_SPACE(sizeof(BYTE)); - pFormat += 3; - *pOut++ = FMT_DATE_A_UPPER; - if (pLastHours) - *pLastHours = *pLastHours + 2; - TRACE("A/P\n"); - } - else if (*pFormat == 'a' && - !strncmpW(pFormat, szamSlashpm, sizeof(szamSlashpm)/sizeof(WCHAR))) - { - /* Date formats: lowercase AM or PM designation - * Other formats: Literal - * Types the format if found - */ - header->type = FMT_TYPE_DATE; - NEED_SPACE(sizeof(BYTE)); - pFormat += sizeof(szamSlashpm)/sizeof(WCHAR); - *pOut++ = FMT_DATE_AMPM_LOWER; - if (pLastHours) - *pLastHours = *pLastHours + 2; - TRACE("AM/PM\n"); - } - else if (*pFormat == 'A' && - !strncmpW(pFormat, szAMSlashPM, sizeof(szAMSlashPM)/sizeof(WCHAR))) - { - /* Date formats: Uppercase AM or PM designation - * Other formats: Literal - * Types the format if found - */ - header->type = FMT_TYPE_DATE; - NEED_SPACE(sizeof(BYTE)); - pFormat += sizeof(szAMSlashPM)/sizeof(WCHAR); - *pOut++ = FMT_DATE_AMPM_UPPER; - TRACE("AM/PM\n"); - } - else if (*pFormat == 'c' || *pFormat == 'C') - { - /* Date formats: General date format - * Other formats: Literal - * Types the format if found - */ - header->type = FMT_TYPE_DATE; - NEED_SPACE(sizeof(BYTE)); - pFormat += sizeof(szAMSlashPM)/sizeof(WCHAR); - *pOut++ = FMT_DATE_GENERAL; - TRACE("gen date\n"); - } - else if ((*pFormat == 'd' || *pFormat == 'D') && COULD_BE(FMT_TYPE_DATE)) - { - /* Date formats: Day specifier - * Other formats: Literal - * Types the format if found - */ - int count = -1; - header->type = FMT_TYPE_DATE; - while ((*pFormat == 'd' || *pFormat == 'D') && count < 6) - { - pFormat++; - count++; - } - NEED_SPACE(sizeof(BYTE)); - *pOut++ = FMT_DATE_DAY + count; - fmt_state &= ~FMT_STATE_OPEN_COPY; - /* When we find the days token, reset the seen hours state so that - * 'mm' is again written as month when encountered. - */ - fmt_state &= ~FMT_STATE_SEEN_HOURS; - TRACE("%d d's\n", count + 1); - } - else if ((*pFormat == 'h' || *pFormat == 'H') && COULD_BE(FMT_TYPE_DATE)) - { - /* Date formats: Hour specifier - * Other formats: Literal - * Types the format if found - */ - header->type = FMT_TYPE_DATE; - NEED_SPACE(sizeof(BYTE)); - pFormat++; - /* Record the position of the hours specifier - if we encounter - * an am/pm specifier we will change the hours from 24 to 12. - */ - pLastHours = pOut; - if (*pFormat == 'h' || *pFormat == 'H') - { - pFormat++; - *pOut++ = FMT_DATE_HOUR_0; - TRACE("hh\n"); - } - else - { - *pOut++ = FMT_DATE_HOUR; - TRACE("h\n"); - } - fmt_state &= ~FMT_STATE_OPEN_COPY; - /* Note that now we have seen an hours token, the next occurrence of - * 'mm' indicates minutes, not months. - */ - fmt_state |= FMT_STATE_SEEN_HOURS; - } - else if ((*pFormat == 'm' || *pFormat == 'M') && COULD_BE(FMT_TYPE_DATE)) - { - /* Date formats: Month specifier (or Minute specifier, after hour specifier) - * Other formats: Literal - * Types the format if found - */ - int count = -1; - header->type = FMT_TYPE_DATE; - while ((*pFormat == 'm' || *pFormat == 'M') && count < 4) - { - pFormat++; - count++; - } - NEED_SPACE(sizeof(BYTE)); - if (count <= 1 && fmt_state & FMT_STATE_SEEN_HOURS && - !(fmt_state & FMT_STATE_WROTE_MINUTES)) - { - /* We have seen an hours specifier and not yet written a minutes - * specifier. Write this as minutes and thereafter as months. - */ - *pOut++ = count == 1 ? FMT_DATE_MIN_0 : FMT_DATE_MIN; - fmt_state |= FMT_STATE_WROTE_MINUTES; /* Hereafter write months */ - } - else - *pOut++ = FMT_DATE_MON + count; /* Months */ - fmt_state &= ~FMT_STATE_OPEN_COPY; - TRACE("%d m's\n", count + 1); - } - else if ((*pFormat == 'n' || *pFormat == 'N') && COULD_BE(FMT_TYPE_DATE)) - { - /* Date formats: Minute specifier - * Other formats: Literal - * Types the format if found - */ - header->type = FMT_TYPE_DATE; - NEED_SPACE(sizeof(BYTE)); - pFormat++; - if (*pFormat == 'n' || *pFormat == 'N') - { - pFormat++; - *pOut++ = FMT_DATE_MIN_0; - TRACE("nn\n"); - } - else - { - *pOut++ = FMT_DATE_MIN; - TRACE("n\n"); - } - fmt_state &= ~FMT_STATE_OPEN_COPY; - } - else if ((*pFormat == 'q' || *pFormat == 'q') && COULD_BE(FMT_TYPE_DATE)) - { - /* Date formats: Quarter specifier - * Other formats: Literal - * Types the format if found - */ - header->type = FMT_TYPE_DATE; - NEED_SPACE(sizeof(BYTE)); - *pOut++ = FMT_DATE_QUARTER; - pFormat++; - fmt_state &= ~FMT_STATE_OPEN_COPY; - TRACE("quarter\n"); - } - else if ((*pFormat == 's' || *pFormat == 'S') && COULD_BE(FMT_TYPE_DATE)) - { - /* Date formats: Second specifier - * Other formats: Literal - * Types the format if found - */ - header->type = FMT_TYPE_DATE; - NEED_SPACE(sizeof(BYTE)); - pFormat++; - if (*pFormat == 's' || *pFormat == 'S') - { - pFormat++; - *pOut++ = FMT_DATE_SEC_0; - TRACE("ss\n"); - } - else - { - *pOut++ = FMT_DATE_SEC; - TRACE("s\n"); - } - fmt_state &= ~FMT_STATE_OPEN_COPY; - } - else if ((*pFormat == 't' || *pFormat == 'T') && - !strncmpiW(pFormat, szTTTTT, sizeof(szTTTTT)/sizeof(WCHAR))) - { - /* Date formats: System time specifier - * Other formats: Literal - * Types the format if found - */ - header->type = FMT_TYPE_DATE; - pFormat += sizeof(szTTTTT)/sizeof(WCHAR); - NEED_SPACE(sizeof(BYTE)); - *pOut++ = FMT_DATE_TIME_SYS; - fmt_state &= ~FMT_STATE_OPEN_COPY; - } - else if ((*pFormat == 'w' || *pFormat == 'W') && COULD_BE(FMT_TYPE_DATE)) - { - /* Date formats: Week of the year/Day of the week - * Other formats: Literal - * Types the format if found - */ - header->type = FMT_TYPE_DATE; - pFormat++; - if (*pFormat == 'w' || *pFormat == 'W') - { - NEED_SPACE(3 * sizeof(BYTE)); - pFormat++; - *pOut++ = FMT_DATE_WEEK_YEAR; - *pOut++ = nFirstDay; - *pOut++ = nFirstWeek; - TRACE("ww\n"); - } - else - { - NEED_SPACE(2 * sizeof(BYTE)); - *pOut++ = FMT_DATE_DAY_WEEK; - *pOut++ = nFirstDay; - TRACE("w\n"); - } - - fmt_state &= ~FMT_STATE_OPEN_COPY; - } - else if ((*pFormat == 'y' || *pFormat == 'Y') && COULD_BE(FMT_TYPE_DATE)) - { - /* Date formats: Day of year/Year specifier - * Other formats: Literal - * Types the format if found - */ - int count = -1; - header->type = FMT_TYPE_DATE; - while ((*pFormat == 'y' || *pFormat == 'Y') && count < 4) - { - pFormat++; - count++; - } - if (count == 2) - { - count--; /* 'yyy' has no meaning, despite what MSDN says */ - pFormat--; - } - NEED_SPACE(sizeof(BYTE)); - *pOut++ = FMT_DATE_YEAR_DOY + count; - fmt_state &= ~FMT_STATE_OPEN_COPY; - TRACE("%d y's\n", count + 1); - } - /* ------------- - * String tokens - * ------------- - */ - else if (*pFormat == '@' && COULD_BE(FMT_TYPE_STRING)) - { - /* String formats: Character from string or space if no char - * Other formats: Literal - * Types the format if found - */ - header->type = FMT_TYPE_STRING; - NEED_SPACE(2 * sizeof(BYTE)); - *pOut++ = FMT_STR_COPY_SPACE; - *pOut = 0x0; - while (*pFormat == '@') - { - *pOut = *pOut + 1; - str_header->copy_chars++; - pFormat++; - } - TRACE("%d @'s\n", *pOut); - pOut++; - fmt_state &= ~FMT_STATE_OPEN_COPY; - } - else if (*pFormat == '&' && COULD_BE(FMT_TYPE_STRING)) - { - /* String formats: Character from string or skip if no char - * Other formats: Literal - * Types the format if found - */ - header->type = FMT_TYPE_STRING; - NEED_SPACE(2 * sizeof(BYTE)); - *pOut++ = FMT_STR_COPY_SKIP; - *pOut = 0x0; - while (*pFormat == '&') - { - *pOut = *pOut + 1; - str_header->copy_chars++; - pFormat++; - } - TRACE("%d &'s\n", *pOut); - pOut++; - fmt_state &= ~FMT_STATE_OPEN_COPY; - } - else if ((*pFormat == '<' || *pFormat == '>') && COULD_BE(FMT_TYPE_STRING)) - { - /* String formats: Use upper/lower case - * Other formats: Literal - * Types the format if found - */ - header->type = FMT_TYPE_STRING; - if (*pFormat == '<') - str_header->flags |= FMT_FLAG_LT; - else - str_header->flags |= FMT_FLAG_GT; - TRACE("to %s case\n", *pFormat == '<' ? "lower" : "upper"); - pFormat++; - fmt_state &= ~FMT_STATE_OPEN_COPY; - } - else if (*pFormat == '!' && COULD_BE(FMT_TYPE_STRING)) - { - /* String formats: Copy right to left - * Other formats: Literal - * Types the format if found - */ - header->type = FMT_TYPE_STRING; - str_header->flags |= FMT_FLAG_RTL; - pFormat++; - fmt_state &= ~FMT_STATE_OPEN_COPY; - TRACE("copy right-to-left\n"); - } - /* -------- - * Literals - * -------- - */ - /* FIXME: [ seems to be ignored */ - else - { - if (*pFormat == '%' && header->type == FMT_TYPE_NUMBER) - { - /* Number formats: Percentage indicator, also a literal - * Other formats: Literal - * Doesn't type the format - */ - num_header->flags |= FMT_FLAG_PERCENT; - } - - if (fmt_state & FMT_STATE_OPEN_COPY) - { - pOut[-1] = pOut[-1] + 1; /* Increase the length of the open copy */ - TRACE("extend copy (char '%c'), length now %d\n", *pFormat, pOut[-1]); - } - else - { - /* Create a new open copy */ - TRACE("New copy (char '%c')\n", *pFormat); - NEED_SPACE(3 * sizeof(BYTE)); - *pOut++ = FMT_GEN_COPY; - *pOut++ = pFormat - lpszFormat; - *pOut++ = 0x1; - fmt_state |= FMT_STATE_OPEN_COPY; - } - pFormat++; - } - } - - *pOut++ = FMT_GEN_END; - - header->size = pOut - rgbTok; - if (pcbActual) - *pcbActual = header->size; - - return S_OK; -} - -/* Number formatting state flags */ -#define NUM_WROTE_DEC 0x01 /* Written the decimal separator */ - -/* Format a variant using a number format */ -static HRESULT VARIANT_FormatNumber(LPVARIANT pVarIn, LPOLESTR lpszFormat, - LPBYTE rgbTok, ULONG dwFlags, - BSTR *pbstrOut, LCID lcid) -{ - BYTE rgbDig[256]; - NUMPARSE np; - int wholeNumberDigits, fractionalDigits, divisor10 = 0, multiplier10 = 0; - WCHAR buff[256], *pBuff = buff; - VARIANT vString, vBool; - DWORD dwState = 0; - FMT_HEADER *header = (FMT_HEADER*)rgbTok; - FMT_NUMBER_HEADER *numHeader; - const BYTE* pToken = NULL; - HRESULT hRes = S_OK; - - TRACE("(%p->(%s%s),%s,%p,0x%08lx,%p,0x%08lx)\n", pVarIn, debugstr_VT(pVarIn), - debugstr_VF(pVarIn), debugstr_w(lpszFormat), rgbTok, dwFlags, pbstrOut, - lcid); - - V_VT(&vString) = VT_EMPTY; - V_VT(&vBool) = VT_BOOL; - - if (V_TYPE(pVarIn) == VT_EMPTY || V_TYPE(pVarIn) == VT_NULL) - { - wholeNumberDigits = fractionalDigits = 0; - numHeader = (FMT_NUMBER_HEADER*)(rgbTok + FmtGetNull(header)); - V_BOOL(&vBool) = VARIANT_FALSE; - } - else - { - /* Get a number string from pVarIn, and parse it */ - hRes = VariantChangeTypeEx(&vString, pVarIn, LCID_US, VARIANT_NOUSEROVERRIDE, VT_BSTR); - if (FAILED(hRes)) - return hRes; - - np.cDig = sizeof(rgbDig); - np.dwInFlags = NUMPRS_STD; - hRes = VarParseNumFromStr(V_BSTR(&vString), LCID_US, 0, &np, rgbDig); - if (FAILED(hRes)) - return hRes; - - if (np.nPwr10 < 0) - { - if (-np.nPwr10 >= np.cDig) - { - /* A real number < +/- 1.0 e.g. 0.1024 or 0.01024 */ - wholeNumberDigits = 0; - fractionalDigits = np.cDig; - divisor10 = -np.nPwr10; - } - else - { - /* An exactly represented real number e.g. 1.024 */ - wholeNumberDigits = np.cDig + np.nPwr10; - fractionalDigits = np.cDig - wholeNumberDigits; - divisor10 = np.cDig - wholeNumberDigits; - } - } - else if (np.nPwr10 == 0) - { - /* An exactly represented whole number e.g. 1024 */ - wholeNumberDigits = np.cDig; - fractionalDigits = 0; - } - else /* np.nPwr10 > 0 */ - { - /* A whole number followed by nPwr10 0's e.g. 102400 */ - wholeNumberDigits = np.cDig; - fractionalDigits = 0; - multiplier10 = np.nPwr10; - } - - /* Figure out which format to use */ - if (np.dwOutFlags & NUMPRS_NEG) - { - numHeader = (FMT_NUMBER_HEADER*)(rgbTok + FmtGetNegative(header)); - V_BOOL(&vBool) = VARIANT_TRUE; - } - else if (wholeNumberDigits == 1 && !fractionalDigits && !multiplier10 && - !divisor10 && rgbDig[0] == 0) - { - numHeader = (FMT_NUMBER_HEADER*)(rgbTok + FmtGetZero(header)); - V_BOOL(&vBool) = VARIANT_FALSE; - } - else - { - numHeader = (FMT_NUMBER_HEADER*)(rgbTok + FmtGetPositive(header)); - V_BOOL(&vBool) = VARIANT_TRUE; - } - - TRACE("num header: flags = 0x%x, mult=%d, div=%d, whole=%d, fract=%d\n", - numHeader->flags, numHeader->multiplier, numHeader->divisor, - numHeader->whole, numHeader->fractional); - - if (numHeader->flags & FMT_FLAG_PERCENT && - !(wholeNumberDigits == 1 && !fractionalDigits && !multiplier10 && - !divisor10 && rgbDig[0] == 0)) - { - /* *100 for %'s. Try to 'steal' fractional digits if we can */ - TRACE("Fraction - multiply by 100\n"); - if (!fractionalDigits) - multiplier10 += 2; - else - { - fractionalDigits--; - wholeNumberDigits++; - if (!fractionalDigits) - multiplier10++; - else - { - fractionalDigits--; - wholeNumberDigits++; - } - } - } - TRACE("cDig %d; nPwr10 %d, whole %d, frac %d ", np.cDig, - np.nPwr10, wholeNumberDigits, fractionalDigits); - TRACE("mult %d; div %d\n", multiplier10, divisor10); - - } - pToken = (const BYTE*)numHeader + sizeof(FMT_NUMBER_HEADER); - - while (SUCCEEDED(hRes) && *pToken != FMT_GEN_END) - { - WCHAR defaultChar = '?'; - DWORD boolFlag, localeValue = 0; - - if (pToken - rgbTok > header->size) - { - ERR("Ran off the end of the format!\n"); - hRes = E_INVALIDARG; - goto VARIANT_FormatNumber_Exit; - } - - switch (*pToken) - { - case FMT_GEN_COPY: - TRACE("copy %s\n", debugstr_wn(lpszFormat + pToken[1], pToken[2])); - memcpy(pBuff, lpszFormat + pToken[1], pToken[2] * sizeof(WCHAR)); - pBuff += pToken[2]; - pToken += 2; - break; - - case FMT_GEN_INLINE: - pToken += 2; - TRACE("copy %s\n", debugstr_a(pToken)); - while (*pToken) - *pBuff++ = *pToken++; - break; - - case FMT_NUM_YES_NO: - boolFlag = VAR_BOOLYESNO; - goto VARIANT_FormatNumber_Bool; - - case FMT_NUM_ON_OFF: - boolFlag = VAR_BOOLONOFF; - goto VARIANT_FormatNumber_Bool; - - case FMT_NUM_TRUE_FALSE: - boolFlag = VAR_LOCALBOOL; - -VARIANT_FormatNumber_Bool: - { - BSTR boolStr = NULL; - - if (pToken[1] != FMT_GEN_END) - { - ERR("Boolean token not at end of format!\n"); - hRes = E_INVALIDARG; - goto VARIANT_FormatNumber_Exit; - } - hRes = VarBstrFromBool(V_BOOL(&vBool), lcid, boolFlag, &boolStr); - if (SUCCEEDED(hRes)) - { - strcpyW(pBuff, boolStr); - SysFreeString(boolStr); - while (*pBuff) - pBuff++; - } - } - break; - - case FMT_NUM_DECIMAL: - TRACE("write decimal separator\n"); - localeValue = LOCALE_SDECIMAL; - defaultChar = '.'; - dwState |= NUM_WROTE_DEC; - break; - - case FMT_NUM_CURRENCY: - TRACE("write currency symbol\n"); - localeValue = LOCALE_SCURRENCY; - defaultChar = '$'; - break; - - case FMT_NUM_EXP_POS_U: - case FMT_NUM_EXP_POS_L: - case FMT_NUM_EXP_NEG_U: - case FMT_NUM_EXP_NEG_L: - if (*pToken == FMT_NUM_EXP_POS_L || *pToken == FMT_NUM_EXP_NEG_L) - *pBuff++ = 'e'; - else - *pBuff++ = 'E'; - if (divisor10) - { - *pBuff++ = '-'; - sprintfW(pBuff, szPercentZeroStar_d, pToken[1], divisor10); - } - else - { - if (*pToken == FMT_NUM_EXP_POS_L || *pToken == FMT_NUM_EXP_POS_U) - *pBuff++ = '+'; - sprintfW(pBuff, szPercentZeroStar_d, pToken[1], multiplier10); - } - while (*pBuff) - pBuff++; - pToken++; - break; - - case FMT_NUM_COPY_SKIP: - if (dwState & NUM_WROTE_DEC) - { - int count; - - TRACE("write %d fractional digits or skip\n", pToken[1]); - - for (count = 0; count < fractionalDigits; count++) - pBuff[count] = '0' + rgbDig[wholeNumberDigits + count]; - pBuff += fractionalDigits; - } - else - { - int count; - - TRACE("write %d digits or skip\n", pToken[1]); - - if (wholeNumberDigits > 1 || rgbDig[0] > 0) - { - TRACE("write %d whole number digits\n", wholeNumberDigits); - for (count = 0; count < wholeNumberDigits; count++) - *pBuff++ = '0' + rgbDig[count]; - TRACE("write %d whole trailing 0's\n", multiplier10); - for (count = 0; count < multiplier10; count++) - *pBuff++ = '0'; /* Write trailing zeros for multiplied values */ - } - } - pToken++; - break; - - case FMT_NUM_COPY_ZERO: - if (dwState & NUM_WROTE_DEC) - { - int count; - - TRACE("write %d fractional digits or 0's\n", pToken[1]); - - for (count = 0; count < fractionalDigits; count++) - pBuff[count] = '0' + rgbDig[wholeNumberDigits + count]; - pBuff += fractionalDigits; - if (pToken[1] > fractionalDigits) - { - count = pToken[1] - fractionalDigits; - while (count--) - *pBuff++ = '0'; /* Write trailing zeros for missing digits */ - } - } - else - { - int count; - - TRACE("write %d digits or 0's\n", pToken[1]); - - if (pToken[1] > (wholeNumberDigits + multiplier10)) - { - count = pToken[1] - (wholeNumberDigits + multiplier10); - TRACE("write %d leading zeros\n", count); - while(count--) - *pBuff++ = '0'; /* Write leading zeros for missing digits */ - } - TRACE("write %d whole number digits\n", wholeNumberDigits); - for (count = 0; count < wholeNumberDigits; count++) - *pBuff++ = '0' + rgbDig[count]; - TRACE("write %d whole trailing 0's\n", multiplier10); - for (count = 0; count < multiplier10; count++) - *pBuff++ = '0'; /* Write trailing zeros for multiplied values */ - } - pToken++; - break; - - default: - ERR("Unknown token 0x%02x!\n", *pToken); - hRes = E_INVALIDARG; - goto VARIANT_FormatNumber_Exit; - } - if (localeValue) - { - if (GetLocaleInfoW(lcid, localeValue, pBuff, - sizeof(buff)/sizeof(WCHAR)-(pBuff-buff))) - { - TRACE("added %s\n", debugstr_w(pBuff)); - while (*pBuff) - pBuff++; - } - else - { - TRACE("added %d '%c'\n", defaultChar, defaultChar); - *pBuff++ = defaultChar; - } - } - pToken++; - } - -VARIANT_FormatNumber_Exit: - VariantClear(&vString); - *pBuff = '\0'; - TRACE("buff is %s\n", debugstr_w(buff)); - if (SUCCEEDED(hRes)) - { - *pbstrOut = SysAllocString(buff); - if (!*pbstrOut) - hRes = E_OUTOFMEMORY; - } - return hRes; -} - -/* Format a variant using a date format */ -static HRESULT VARIANT_FormatDate(LPVARIANT pVarIn, LPOLESTR lpszFormat, - LPBYTE rgbTok, ULONG dwFlags, - BSTR *pbstrOut, LCID lcid) -{ - WCHAR buff[256], *pBuff = buff; - VARIANT vDate; - UDATE udate; - FMT_HEADER *header = (FMT_HEADER*)rgbTok; - FMT_DATE_HEADER *dateHeader; - const BYTE* pToken = NULL; - HRESULT hRes; - - TRACE("(%p->(%s%s),%s,%p,0x%08lx,%p,0x%08lx)\n", pVarIn, debugstr_VT(pVarIn), - debugstr_VF(pVarIn), debugstr_w(lpszFormat), rgbTok, dwFlags, pbstrOut, - lcid); - - V_VT(&vDate) = VT_EMPTY; - - if (V_TYPE(pVarIn) == VT_EMPTY || V_TYPE(pVarIn) == VT_NULL) - { - dateHeader = (FMT_DATE_HEADER*)(rgbTok + FmtGetNegative(header)); - V_DATE(&vDate) = 0; - } - else - { - USHORT usFlags = dwFlags & VARIANT_CALENDAR_HIJRI ? VAR_CALENDAR_HIJRI : 0; - - hRes = VariantChangeTypeEx(&vDate, pVarIn, LCID_US, usFlags, VT_DATE); - if (FAILED(hRes)) - return hRes; - dateHeader = (FMT_DATE_HEADER*)(rgbTok + FmtGetPositive(header)); - } - - hRes = VarUdateFromDate(V_DATE(&vDate), 0 /* FIXME: flags? */, &udate); - if (FAILED(hRes)) - return hRes; - pToken = (const BYTE*)dateHeader + sizeof(FMT_DATE_HEADER); - - while (*pToken != FMT_GEN_END) - { - DWORD dwVal = 0, localeValue = 0, dwFmt = 0; - LPCWSTR szPrintFmt = NULL; - WCHAR defaultChar = '?'; - - if (pToken - rgbTok > header->size) - { - ERR("Ran off the end of the format!\n"); - hRes = E_INVALIDARG; - goto VARIANT_FormatDate_Exit; - } - - switch (*pToken) - { - case FMT_GEN_COPY: - TRACE("copy %s\n", debugstr_wn(lpszFormat + pToken[1], pToken[2])); - memcpy(pBuff, lpszFormat + pToken[1], pToken[2] * sizeof(WCHAR)); - pBuff += pToken[2]; - pToken += 2; - break; - - case FMT_DATE_TIME_SEP: - TRACE("time separator\n"); - localeValue = LOCALE_STIME; - defaultChar = ':'; - break; - - case FMT_DATE_DATE_SEP: - TRACE("date separator\n"); - localeValue = LOCALE_SDATE; - defaultChar = '/'; - break; - - case FMT_DATE_GENERAL: - { - BSTR date = NULL; - WCHAR *pDate = date; - hRes = VarBstrFromDate(V_DATE(&vDate), lcid, 0, pbstrOut); - if (FAILED(hRes)) - goto VARIANT_FormatDate_Exit; - while (*pDate) - *pBuff++ = *pDate++; - SysFreeString(date); - } - break; - - case FMT_DATE_QUARTER: - if (udate.st.wMonth <= 3) - *pBuff++ = '1'; - else if (udate.st.wMonth <= 6) - *pBuff++ = '2'; - else if (udate.st.wMonth <= 9) - *pBuff++ = '3'; - else - *pBuff++ = '4'; - break; - - case FMT_DATE_TIME_SYS: - { - /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */ - BSTR date = NULL; - WCHAR *pDate = date; - hRes = VarBstrFromDate(V_DATE(&vDate), lcid, VAR_TIMEVALUEONLY, pbstrOut); - if (FAILED(hRes)) - goto VARIANT_FormatDate_Exit; - while (*pDate) - *pBuff++ = *pDate++; - SysFreeString(date); - } - break; - - case FMT_DATE_DAY: - szPrintFmt = szPercent_d; - dwVal = udate.st.wDay; - break; - - case FMT_DATE_DAY_0: - szPrintFmt = szPercentZeroTwo_d; - dwVal = udate.st.wDay; - break; - - case FMT_DATE_DAY_SHORT: - /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */ - TRACE("short day\n"); - localeValue = LOCALE_SABBREVDAYNAME1 + udate.st.wMonth - 1; - defaultChar = '?'; - break; - - case FMT_DATE_DAY_LONG: - /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */ - TRACE("long day\n"); - localeValue = LOCALE_SDAYNAME1 + udate.st.wMonth - 1; - defaultChar = '?'; - break; - - case FMT_DATE_SHORT: - /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */ - dwFmt = LOCALE_SSHORTDATE; - break; - - case FMT_DATE_LONG: - /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */ - dwFmt = LOCALE_SLONGDATE; - break; - - case FMT_DATE_MEDIUM: - FIXME("Medium date treated as long date\n"); - dwFmt = LOCALE_SLONGDATE; - break; - - case FMT_DATE_DAY_WEEK: - szPrintFmt = szPercent_d; - if (pToken[1]) - dwVal = udate.st.wDayOfWeek + 2 - pToken[1]; - else - { - GetLocaleInfoW(lcid,LOCALE_RETURN_NUMBER|LOCALE_IFIRSTDAYOFWEEK, - (LPWSTR)&dwVal, sizeof(dwVal)/sizeof(WCHAR)); - dwVal = udate.st.wDayOfWeek + 1 - dwVal; - } - pToken++; - break; - - case FMT_DATE_WEEK_YEAR: - szPrintFmt = szPercent_d; - dwVal = udate.wDayOfYear / 7 + 1; - pToken += 2; - FIXME("Ignoring nFirstDay of %d, nFirstWeek of %d\n", pToken[0], pToken[1]); - break; - - case FMT_DATE_MON: - szPrintFmt = szPercent_d; - dwVal = udate.st.wMonth; - break; - - case FMT_DATE_MON_0: - szPrintFmt = szPercentZeroTwo_d; - dwVal = udate.st.wMonth; - break; - - case FMT_DATE_MON_SHORT: - /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */ - TRACE("short month\n"); - localeValue = LOCALE_SABBREVMONTHNAME1 + udate.st.wMonth - 1; - defaultChar = '?'; - break; - - case FMT_DATE_MON_LONG: - /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */ - TRACE("long month\n"); - localeValue = LOCALE_SMONTHNAME1 + udate.st.wMonth - 1; - defaultChar = '?'; - break; - - case FMT_DATE_YEAR_DOY: - szPrintFmt = szPercent_d; - dwVal = udate.wDayOfYear; - break; - - case FMT_DATE_YEAR_0: - szPrintFmt = szPercentZeroTwo_d; - dwVal = udate.st.wYear % 100; - break; - - case FMT_DATE_YEAR_LONG: - szPrintFmt = szPercent_d; - dwVal = udate.st.wYear; - break; - - case FMT_DATE_MIN: - szPrintFmt = szPercent_d; - dwVal = udate.st.wMinute; - break; - - case FMT_DATE_MIN_0: - szPrintFmt = szPercentZeroTwo_d; - dwVal = udate.st.wMinute; - break; - - case FMT_DATE_SEC: - szPrintFmt = szPercent_d; - dwVal = udate.st.wSecond; - break; - - case FMT_DATE_SEC_0: - szPrintFmt = szPercentZeroTwo_d; - dwVal = udate.st.wSecond; - break; - - case FMT_DATE_HOUR: - szPrintFmt = szPercent_d; - dwVal = udate.st.wHour; - break; - - case FMT_DATE_HOUR_0: - szPrintFmt = szPercentZeroTwo_d; - dwVal = udate.st.wHour; - break; - - case FMT_DATE_HOUR_12: - szPrintFmt = szPercent_d; - dwVal = udate.st.wHour ? udate.st.wHour > 12 ? udate.st.wHour - 12 : udate.st.wHour : 12; - break; - - case FMT_DATE_HOUR_12_0: - szPrintFmt = szPercentZeroTwo_d; - dwVal = udate.st.wHour ? udate.st.wHour > 12 ? udate.st.wHour - 12 : udate.st.wHour : 12; - break; - - case FMT_DATE_AMPM_SYS1: - case FMT_DATE_AMPM_SYS2: - localeValue = udate.st.wHour < 12 ? LOCALE_S1159 : LOCALE_S2359; - defaultChar = '?'; - break; - - case FMT_DATE_AMPM_UPPER: - *pBuff++ = udate.st.wHour < 12 ? 'A' : 'P'; - *pBuff++ = 'M'; - break; - - case FMT_DATE_A_UPPER: - *pBuff++ = udate.st.wHour < 12 ? 'A' : 'P'; - break; - - case FMT_DATE_AMPM_LOWER: - *pBuff++ = udate.st.wHour < 12 ? 'a' : 'p'; - *pBuff++ = 'm'; - break; - - case FMT_DATE_A_LOWER: - *pBuff++ = udate.st.wHour < 12 ? 'a' : 'p'; - break; - - default: - ERR("Unknown token 0x%02x!\n", *pToken); - hRes = E_INVALIDARG; - goto VARIANT_FormatDate_Exit; - } - if (localeValue) - { - *pBuff = '\0'; - if (GetLocaleInfoW(lcid, localeValue, pBuff, - sizeof(buff)/sizeof(WCHAR)-(pBuff-buff))) - { - TRACE("added %s\n", debugstr_w(pBuff)); - while (*pBuff) - pBuff++; - } - else - { - TRACE("added %d %c\n", defaultChar, defaultChar); - *pBuff++ = defaultChar; - } - } - else if (dwFmt) - { - WCHAR fmt_buff[80]; - - if (!GetLocaleInfoW(lcid, dwFmt, fmt_buff, sizeof(fmt_buff)/sizeof(WCHAR)) || - !GetDateFormatW(lcid, 0, &udate.st, fmt_buff, pBuff, - sizeof(buff)/sizeof(WCHAR)-(pBuff-buff))) - { - hRes = E_INVALIDARG; - goto VARIANT_FormatDate_Exit; - } - while (*pBuff) - pBuff++; - } - else if (szPrintFmt) - { - sprintfW(pBuff, szPrintFmt, dwVal); - while (*pBuff) - pBuff++; - } - pToken++; - } - -VARIANT_FormatDate_Exit: - *pBuff = '\0'; - TRACE("buff is %s\n", debugstr_w(buff)); - if (SUCCEEDED(hRes)) - { - *pbstrOut = SysAllocString(buff); - if (!*pbstrOut) - hRes = E_OUTOFMEMORY; - } - return hRes; -} - -/* Format a variant using a string format */ -static HRESULT VARIANT_FormatString(LPVARIANT pVarIn, LPOLESTR lpszFormat, - LPBYTE rgbTok, ULONG dwFlags, - BSTR *pbstrOut, LCID lcid) -{ - static const WCHAR szEmpty[] = { '\0' }; - WCHAR buff[256], *pBuff = buff; - WCHAR *pSrc; - FMT_HEADER *header = (FMT_HEADER*)rgbTok; - FMT_STRING_HEADER *strHeader; - const BYTE* pToken = NULL; - VARIANT vStr; - int blanks_first; - BOOL bUpper = FALSE; - HRESULT hRes = S_OK; - - TRACE("(%p->(%s%s),%s,%p,0x%08lx,%p,0x%08lx)\n", pVarIn, debugstr_VT(pVarIn), - debugstr_VF(pVarIn), debugstr_w(lpszFormat), rgbTok, dwFlags, pbstrOut, - lcid); - - V_VT(&vStr) = VT_EMPTY; - - if (V_TYPE(pVarIn) == VT_EMPTY || V_TYPE(pVarIn) == VT_NULL) - { - strHeader = (FMT_STRING_HEADER*)(rgbTok + FmtGetNegative(header)); - V_BSTR(&vStr) = (WCHAR*)szEmpty; - } - else - { - hRes = VariantChangeTypeEx(&vStr, pVarIn, LCID_US, VARIANT_NOUSEROVERRIDE, VT_BSTR); - if (FAILED(hRes)) - return hRes; - - if (V_BSTR(pVarIn)[0] == '\0') - strHeader = (FMT_STRING_HEADER*)(rgbTok + FmtGetNegative(header)); - else - strHeader = (FMT_STRING_HEADER*)(rgbTok + FmtGetPositive(header)); - } - pSrc = V_BSTR(&vStr); - if ((strHeader->flags & (FMT_FLAG_LT|FMT_FLAG_GT)) == FMT_FLAG_GT) - bUpper = TRUE; - blanks_first = strHeader->copy_chars - strlenW(pSrc); - pToken = (const BYTE*)strHeader + sizeof(FMT_DATE_HEADER); - - while (*pToken != FMT_GEN_END) - { - int dwCount = 0; - - if (pToken - rgbTok > header->size) - { - ERR("Ran off the end of the format!\n"); - hRes = E_INVALIDARG; - goto VARIANT_FormatString_Exit; - } - - switch (*pToken) - { - case FMT_GEN_COPY: - TRACE("copy %s\n", debugstr_wn(lpszFormat + pToken[1], pToken[2])); - memcpy(pBuff, lpszFormat + pToken[1], pToken[2] * sizeof(WCHAR)); - pBuff += pToken[2]; - pToken += 2; - break; - - case FMT_STR_COPY_SPACE: - case FMT_STR_COPY_SKIP: - dwCount = pToken[1]; - if (*pToken == FMT_STR_COPY_SPACE && blanks_first > 0) - { - TRACE("insert %d initial spaces\n", blanks_first); - while (dwCount > 0 && blanks_first > 0) - { - *pBuff++ = ' '; - dwCount--; - blanks_first--; - } - } - TRACE("copy %d chars%s\n", dwCount, - *pToken == FMT_STR_COPY_SPACE ? " with space" :""); - while (dwCount > 0 && *pSrc) - { - if (bUpper) - *pBuff++ = toupperW(*pSrc); - else - *pBuff++ = tolowerW(*pSrc); - dwCount--; - pSrc++; - } - if (*pToken == FMT_STR_COPY_SPACE && dwCount > 0) - { - TRACE("insert %d spaces\n", dwCount); - while (dwCount-- > 0) - *pBuff++ = ' '; - } - pToken++; - break; - - default: - ERR("Unknown token 0x%02x!\n", *pToken); - hRes = E_INVALIDARG; - goto VARIANT_FormatString_Exit; - } - pToken++; - } - -VARIANT_FormatString_Exit: - /* Copy out any remaining chars */ - while (*pSrc) - { - if (bUpper) - *pBuff++ = toupperW(*pSrc); - else - *pBuff++ = tolowerW(*pSrc); - pSrc++; - } - VariantClear(&vStr); - *pBuff = '\0'; - TRACE("buff is %s\n", debugstr_w(buff)); - if (SUCCEEDED(hRes)) - { - *pbstrOut = SysAllocString(buff); - if (!*pbstrOut) - hRes = E_OUTOFMEMORY; - } - return hRes; -} - -#define NUMBER_VTBITS (VTBIT_I1|VTBIT_UI1|VTBIT_I2|VTBIT_UI2| \ - VTBIT_I4|VTBIT_UI4|VTBIT_I8|VTBIT_UI8| \ - VTBIT_R4|VTBIT_R8|VTBIT_CY|VTBIT_DECIMAL| \ - (1<<VT_BOOL)|(1<<VT_INT)|(1<<VT_UINT)) - -/********************************************************************** - * VarFormatFromTokens [OLEAUT32.139] - */ -HRESULT WINAPI VarFormatFromTokens(LPVARIANT pVarIn, LPOLESTR lpszFormat, - LPBYTE rgbTok, ULONG dwFlags, - BSTR *pbstrOut, LCID lcid) -{ - FMT_SHORT_HEADER *header = (FMT_SHORT_HEADER *)rgbTok; - VARIANT vTmp; - HRESULT hres; - - TRACE("(%p,%s,%p,%lx,%p,0x%08lx)\n", pVarIn, debugstr_w(lpszFormat), - rgbTok, dwFlags, pbstrOut, lcid); - - if (!pbstrOut) - return E_INVALIDARG; - - *pbstrOut = NULL; - - if (!pVarIn || !rgbTok) - return E_INVALIDARG; - - if (*rgbTok == FMT_TO_STRING || header->type == FMT_TYPE_GENERAL) - { - /* According to MSDN, general format acts somewhat like the 'Str' - * function in Visual Basic. - */ -VarFormatFromTokens_AsStr: - V_VT(&vTmp) = VT_EMPTY; - hres = VariantChangeTypeEx(&vTmp, pVarIn, lcid, dwFlags, VT_BSTR); - *pbstrOut = V_BSTR(&vTmp); - } - else - { - if (header->type == FMT_TYPE_NUMBER || - (header->type == FMT_TYPE_UNKNOWN && ((1 << V_TYPE(pVarIn)) & NUMBER_VTBITS))) - { - hres = VARIANT_FormatNumber(pVarIn, lpszFormat, rgbTok, dwFlags, pbstrOut, lcid); - } - else if (header->type == FMT_TYPE_DATE || - (header->type == FMT_TYPE_UNKNOWN && V_TYPE(pVarIn) == VT_DATE)) - { - hres = VARIANT_FormatDate(pVarIn, lpszFormat, rgbTok, dwFlags, pbstrOut, lcid); - } - else if (header->type == FMT_TYPE_STRING || V_TYPE(pVarIn) == VT_BSTR) - { - hres = VARIANT_FormatString(pVarIn, lpszFormat, rgbTok, dwFlags, pbstrOut, lcid); - } - else - { - ERR("unrecognised format type 0x%02x\n", header->type); - return E_INVALIDARG; - } - /* If the coercion failed, still try to create output, unless the - * VAR_FORMAT_NOSUBSTITUTE flag is set. - */ - if ((hres == DISP_E_OVERFLOW || hres == DISP_E_TYPEMISMATCH) && - !(dwFlags & VAR_FORMAT_NOSUBSTITUTE)) - goto VarFormatFromTokens_AsStr; - } - - return hres; -} - -/********************************************************************** - * VarFormat [OLEAUT32.87] - * - * Format a variant from a format string. - * - * PARAMS - * pVarIn [I] Variant to format - * lpszFormat [I] Format string (see notes) - * nFirstDay [I] First day of the week, (See VarTokenizeFormatString() for details) - * nFirstWeek [I] First week of the year (See VarTokenizeFormatString() for details) - * dwFlags [I] Flags for the format (VAR_ flags from "oleauto.h") - * pbstrOut [O] Destination for formatted string. - * - * RETURNS - * Success: S_OK. pbstrOut contains the formatted value. - * Failure: E_INVALIDARG, if any parameter is invalid. - * E_OUTOFMEMORY, if enough memory cannot be allocated. - * DISP_E_TYPEMISMATCH, if the variant cannot be formatted. - * - * NOTES - * - See Variant-Formats for details concerning creating format strings. - * - This function uses LOCALE_USER_DEFAULT when calling VarTokenizeFormatString() - * and VarFormatFromTokens(). - */ -HRESULT WINAPI VarFormat(LPVARIANT pVarIn, LPOLESTR lpszFormat, - int nFirstDay, int nFirstWeek, ULONG dwFlags, - BSTR *pbstrOut) -{ - BYTE buff[256]; - HRESULT hres; - - TRACE("(%p->(%s%s),%s,%d,%d,0x%08lx,%p)\n", pVarIn, debugstr_VT(pVarIn), - debugstr_VF(pVarIn), debugstr_w(lpszFormat), nFirstDay, nFirstWeek, - dwFlags, pbstrOut); - - if (!pbstrOut) - return E_INVALIDARG; - *pbstrOut = NULL; - - hres = VarTokenizeFormatString(lpszFormat, buff, sizeof(buff), nFirstDay, - nFirstWeek, LOCALE_USER_DEFAULT, NULL); - if (SUCCEEDED(hres)) - hres = VarFormatFromTokens(pVarIn, lpszFormat, buff, dwFlags, - pbstrOut, LOCALE_USER_DEFAULT); - TRACE("returning 0x%08lx, %s\n", hres, debugstr_w(*pbstrOut)); - return hres; -} - -/********************************************************************** - * VarFormatDateTime [OLEAUT32.97] - * - * Format a variant value as a date and/or time. - * - * PARAMS - * pVarIn [I] Variant to format - * nFormat [I] Format type (see notes) - * dwFlags [I] Flags for the format (VAR_ flags from "oleauto.h") - * pbstrOut [O] Destination for formatted string. - * - * RETURNS - * Success: S_OK. pbstrOut contains the formatted value. - * Failure: E_INVALIDARG, if any parameter is invalid. - * E_OUTOFMEMORY, if enough memory cannot be allocated. - * DISP_E_TYPEMISMATCH, if the variant cannot be formatted. - * - * NOTES - * This function uses LOCALE_USER_DEFAULT when determining the date format - * characters to use. - * Possible values for the nFormat parameter are: - *| Value Meaning - *| ----- ------- - *| 0 General date format - *| 1 Long date format - *| 2 Short date format - *| 3 Long time format - *| 4 Short time format - */ -HRESULT WINAPI VarFormatDateTime(LPVARIANT pVarIn, INT nFormat, ULONG dwFlags, BSTR *pbstrOut) -{ - static const WCHAR szEmpty[] = { '\0' }; - const BYTE* lpFmt = NULL; - - TRACE("(%p->(%s%s),%d,0x%08lx,%p)\n", pVarIn, debugstr_VT(pVarIn), - debugstr_VF(pVarIn), nFormat, dwFlags, pbstrOut); - - if (!pVarIn || !pbstrOut || nFormat < 0 || nFormat > 4) - return E_INVALIDARG; - - switch (nFormat) - { - case 0: lpFmt = fmtGeneralDate; break; - case 1: lpFmt = fmtLongDate; break; - case 2: lpFmt = fmtShortDate; break; - case 3: lpFmt = fmtLongTime; break; - case 4: lpFmt = fmtShortTime; break; - } - return VarFormatFromTokens(pVarIn, (LPWSTR)szEmpty, (BYTE*)lpFmt, dwFlags, - pbstrOut, LOCALE_USER_DEFAULT); -} - -#define GETLOCALENUMBER(type,field) GetLocaleInfoW(LOCALE_USER_DEFAULT, \ - type|LOCALE_RETURN_NUMBER, \ - (LPWSTR)&numfmt.field, \ - sizeof(numfmt.field)/sizeof(WCHAR)) - -/********************************************************************** - * VarFormatNumber [OLEAUT32.107] - * - * Format a variant value as a number. - * - * PARAMS - * pVarIn [I] Variant to format - * nDigits [I] Number of digits following the decimal point (-1 = user default) - * nLeading [I] Use a leading zero (-2 = user default, -1 = yes, 0 = no) - * nParens [I] Use brackets for values < 0 (-2 = user default, -1 = yes, 0 = no) - * nGrouping [I] Use grouping characters (-2 = user default, -1 = yes, 0 = no) - * dwFlags [I] Currently unused, set to zero - * pbstrOut [O] Destination for formatted string. - * - * RETURNS - * Success: S_OK. pbstrOut contains the formatted value. - * Failure: E_INVALIDARG, if any parameter is invalid. - * E_OUTOFMEMORY, if enough memory cannot be allocated. - * DISP_E_TYPEMISMATCH, if the variant cannot be formatted. - * - * NOTES - * This function uses LOCALE_USER_DEFAULT when determining the number format - * characters to use. - */ -HRESULT WINAPI VarFormatNumber(LPVARIANT pVarIn, INT nDigits, INT nLeading, INT nParens, - INT nGrouping, ULONG dwFlags, BSTR *pbstrOut) -{ - HRESULT hRet; - VARIANT vStr; - - TRACE("(%p->(%s%s),%d,%d,%d,%d,0x%08lx,%p)\n", pVarIn, debugstr_VT(pVarIn), - debugstr_VF(pVarIn), nDigits, nLeading, nParens, nGrouping, dwFlags, pbstrOut); - - if (!pVarIn || !pbstrOut || nDigits > 9) - return E_INVALIDARG; - - *pbstrOut = NULL; - - V_VT(&vStr) = VT_EMPTY; - hRet = VariantCopyInd(&vStr, pVarIn); - - if (SUCCEEDED(hRet)) - hRet = VariantChangeTypeEx(&vStr, &vStr, LOCALE_USER_DEFAULT, 0, VT_BSTR); - - if (SUCCEEDED(hRet)) - { - WCHAR buff[256], decimal[8], thousands[8]; - NUMBERFMTW numfmt; - - /* Although MSDN makes it clear that the native versions of these functions - * are implemented using VarTokenizeFormatString()/VarFormatFromTokens(), - * using NLS gives us the same result. - */ - if (nDigits < 0) - GETLOCALENUMBER(LOCALE_IDIGITS, NumDigits); - else - numfmt.NumDigits = nDigits; - - if (nLeading == -2) - GETLOCALENUMBER(LOCALE_ILZERO, LeadingZero); - else if (nLeading == -1) - numfmt.LeadingZero = 1; - else - numfmt.LeadingZero = 0; - - if (nGrouping == -2) - { - WCHAR grouping[16]; - grouping[2] = '\0'; - GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, grouping, - sizeof(grouping)/sizeof(WCHAR)); - numfmt.Grouping = grouping[2] == '2' ? 32 : grouping[0] - '0'; - } - else if (nGrouping == -1) - numfmt.Grouping = 3; /* 3 = "n,nnn.nn" */ - else - numfmt.Grouping = 0; /* 0 = No grouping */ - - if (nParens == -2) - GETLOCALENUMBER(LOCALE_INEGNUMBER, NegativeOrder); - else if (nParens == -1) - numfmt.NegativeOrder = 0; /* 0 = "(xxx)" */ - else - numfmt.NegativeOrder = 1; /* 1 = "-xxx" */ - - numfmt.lpDecimalSep = decimal; - GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimal, - sizeof(decimal)/sizeof(WCHAR)); - numfmt.lpThousandSep = thousands; - GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, thousands, - sizeof(thousands)/sizeof(WCHAR)); - - if (GetNumberFormatW(LOCALE_USER_DEFAULT, 0, V_BSTR(&vStr), &numfmt, - buff, sizeof(buff)/sizeof(WCHAR))) - { - *pbstrOut = SysAllocString(buff); - if (!*pbstrOut) - hRet = E_OUTOFMEMORY; - } - else - hRet = DISP_E_TYPEMISMATCH; - - SysFreeString(V_BSTR(&vStr)); - } - return hRet; -} - -/********************************************************************** - * VarFormatPercent [OLEAUT32.117] - * - * Format a variant value as a percentage. - * - * PARAMS - * pVarIn [I] Variant to format - * nDigits [I] Number of digits following the decimal point (-1 = user default) - * nLeading [I] Use a leading zero (-2 = user default, -1 = yes, 0 = no) - * nParens [I] Use brackets for values < 0 (-2 = user default, -1 = yes, 0 = no) - * nGrouping [I] Use grouping characters (-2 = user default, -1 = yes, 0 = no) - * dwFlags [I] Currently unused, set to zero - * pbstrOut [O] Destination for formatted string. - * - * RETURNS - * Success: S_OK. pbstrOut contains the formatted value. - * Failure: E_INVALIDARG, if any parameter is invalid. - * E_OUTOFMEMORY, if enough memory cannot be allocated. - * DISP_E_OVERFLOW, if overflow occurs during the conversion. - * DISP_E_TYPEMISMATCH, if the variant cannot be formatted. - * - * NOTES - * This function uses LOCALE_USER_DEFAULT when determining the number format - * characters to use. - */ -HRESULT WINAPI VarFormatPercent(LPVARIANT pVarIn, INT nDigits, INT nLeading, INT nParens, - INT nGrouping, ULONG dwFlags, BSTR *pbstrOut) -{ - static const WCHAR szPercent[] = { '%','\0' }; - static const WCHAR szPercentBracket[] = { '%',')','\0' }; - WCHAR buff[256]; - HRESULT hRet; - VARIANT vDbl; - - TRACE("(%p->(%s%s),%d,%d,%d,%d,0x%08lx,%p)\n", pVarIn, debugstr_VT(pVarIn), - debugstr_VF(pVarIn), nDigits, nLeading, nParens, nGrouping, - dwFlags, pbstrOut); - - if (!pVarIn || !pbstrOut || nDigits > 9) - return E_INVALIDARG; - - *pbstrOut = NULL; - - V_VT(&vDbl) = VT_EMPTY; - hRet = VariantCopyInd(&vDbl, pVarIn); - - if (SUCCEEDED(hRet)) - { - hRet = VariantChangeTypeEx(&vDbl, &vDbl, LOCALE_USER_DEFAULT, 0, VT_R8); - - if (SUCCEEDED(hRet)) - { - if (V_R8(&vDbl) > (R8_MAX / 100.0)) - return DISP_E_OVERFLOW; - - V_R8(&vDbl) *= 100.0; - hRet = VarFormatNumber(&vDbl, nDigits, nLeading, nParens, - nGrouping, dwFlags, pbstrOut); - - if (SUCCEEDED(hRet)) - { - DWORD dwLen = strlenW(*pbstrOut); - BOOL bBracket = (*pbstrOut)[dwLen] == ')' ? TRUE : FALSE; - - dwLen -= bBracket; - memcpy(buff, *pbstrOut, dwLen * sizeof(WCHAR)); - strcpyW(buff + dwLen, bBracket ? szPercentBracket : szPercent); - SysFreeString(*pbstrOut); - *pbstrOut = SysAllocString(buff); - if (!*pbstrOut) - hRet = E_OUTOFMEMORY; - } - } - } - return hRet; -} - -/********************************************************************** - * VarFormatCurrency [OLEAUT32.127] - * - * Format a variant value as a currency. - * - * PARAMS - * pVarIn [I] Variant to format - * nDigits [I] Number of digits following the decimal point (-1 = user default) - * nLeading [I] Use a leading zero (-2 = user default, -1 = yes, 0 = no) - * nParens [I] Use brackets for values < 0 (-2 = user default, -1 = yes, 0 = no) - * nGrouping [I] Use grouping characters (-2 = user default, -1 = yes, 0 = no) - * dwFlags [I] Currently unused, set to zero - * pbstrOut [O] Destination for formatted string. - * - * RETURNS - * Success: S_OK. pbstrOut contains the formatted value. - * Failure: E_INVALIDARG, if any parameter is invalid. - * E_OUTOFMEMORY, if enough memory cannot be allocated. - * DISP_E_TYPEMISMATCH, if the variant cannot be formatted. - * - * NOTES - * This function uses LOCALE_USER_DEFAULT when determining the currency format - * characters to use. - */ -HRESULT WINAPI VarFormatCurrency(LPVARIANT pVarIn, INT nDigits, INT nLeading, - INT nParens, INT nGrouping, ULONG dwFlags, - BSTR *pbstrOut) -{ - HRESULT hRet; - VARIANT vStr; - - TRACE("(%p->(%s%s),%d,%d,%d,%d,0x%08lx,%p)\n", pVarIn, debugstr_VT(pVarIn), - debugstr_VF(pVarIn), nDigits, nLeading, nParens, nGrouping, dwFlags, pbstrOut); - - if (!pVarIn || !pbstrOut || nDigits > 9) - return E_INVALIDARG; - - *pbstrOut = NULL; - - V_VT(&vStr) = VT_EMPTY; - hRet = VariantCopyInd(&vStr, pVarIn); - - if (SUCCEEDED(hRet)) - hRet = VariantChangeTypeEx(&vStr, &vStr, LOCALE_USER_DEFAULT, 0, VT_BSTR); - - if (SUCCEEDED(hRet)) - { - WCHAR buff[256], decimal[8], thousands[8], currency[8]; - CURRENCYFMTW numfmt; - - if (nDigits < 0) - GETLOCALENUMBER(LOCALE_IDIGITS, NumDigits); - else - numfmt.NumDigits = nDigits; - - if (nLeading == -2) - GETLOCALENUMBER(LOCALE_ILZERO, LeadingZero); - else if (nLeading == -1) - numfmt.LeadingZero = 1; - else - numfmt.LeadingZero = 0; - - if (nGrouping == -2) - { - WCHAR nGrouping[16]; - nGrouping[2] = '\0'; - GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, nGrouping, - sizeof(nGrouping)/sizeof(WCHAR)); - numfmt.Grouping = nGrouping[2] == '2' ? 32 : nGrouping[0] - '0'; - } - else if (nGrouping == -1) - numfmt.Grouping = 3; /* 3 = "n,nnn.nn" */ - else - numfmt.Grouping = 0; /* 0 = No grouping */ - - if (nParens == -2) - GETLOCALENUMBER(LOCALE_INEGCURR, NegativeOrder); - else if (nParens == -1) - numfmt.NegativeOrder = 0; /* 0 = "(xxx)" */ - else - numfmt.NegativeOrder = 1; /* 1 = "-xxx" */ - - GETLOCALENUMBER(LOCALE_ICURRENCY, PositiveOrder); - - numfmt.lpDecimalSep = decimal; - GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimal, - sizeof(decimal)/sizeof(WCHAR)); - numfmt.lpThousandSep = thousands; - GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, thousands, - sizeof(thousands)/sizeof(WCHAR)); - numfmt.lpCurrencySymbol = currency; - GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, currency, - sizeof(currency)/sizeof(WCHAR)); - - /* use NLS as per VarFormatNumber() */ - if (GetCurrencyFormatW(LOCALE_USER_DEFAULT, 0, V_BSTR(&vStr), &numfmt, - buff, sizeof(buff)/sizeof(WCHAR))) - { - *pbstrOut = SysAllocString(buff); - if (!*pbstrOut) - hRet = E_OUTOFMEMORY; - } - else - hRet = DISP_E_TYPEMISMATCH; - - SysFreeString(V_BSTR(&vStr)); - } - return hRet; -} +/* + * Variant formatting functions + * + * Copyright 2003 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES + * Since the formatting functions aren't properly documented, I used the + * Visual Basic documentation as a guide to implementing these functions. This + * means that some named or user-defined formats may work slightly differently. + * Please submit a test case if you find a difference. + */ + +#include "config.h" + +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winbase.h" +#include "wine/unicode.h" +#include "winerror.h" +#include "variant.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(variant); + +/* Make sure internal conversions to strings use the '.','+'/'-' and ',' + * format chars from the US locale. This enables us to parse the created + * strings to determine the number of decimal places, exponent, etc. + */ +#define LCID_US MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT) + +static const WCHAR szPercent_d[] = { '%','d','\0' }; +static const WCHAR szPercentZeroTwo_d[] = { '%','0','2','d','\0' }; +static const WCHAR szPercentZeroFour_d[] = { '%','0','4','d','\0' }; +static const WCHAR szPercentZeroStar_d[] = { '%','0','*','d','\0' }; + +#if 0 +#define dump_tokens(rgb) do { \ + int i_; TRACE("Tokens->{ \n"); \ + for (i_ = 0; i_ < rgb[0]; i_++) \ + TRACE("%s0x%02x", i_?",":"",rgb[i_]); \ + TRACE(" }\n"); \ + } while(0) +#endif + +/****************************************************************************** + * Variant-Formats {OLEAUT32} + * + * NOTES + * When formatting a variant a variety of format strings may be used to generate + * different kinds of formatted output. A format string consists of either a named + * format, or a user-defined format. + * + * The following named formats are defined: + *| Name Description + *| ---- ----------- + *| General Date Display Date, and time for non-integer values + *| Short Date Short date format as defined by locale settings + *| Medium Date Medium date format as defined by locale settings + *| Long Date Long date format as defined by locale settings + *| Short Time Short Time format as defined by locale settings + *| Medium Time Medium time format as defined by locale settings + *| Long Time Long time format as defined by locale settings + *| True/False Localised text of "True" or "False" + *| Yes/No Localised text of "Yes" or "No" + *| On/Off Localised text of "On" or "Off" + *| General Number No thousands separator. No decimal points for integers + *| Currency General currency format using localised characters + *| Fixed At least one whole and two fractional digits + *| Standard Same as 'Fixed', but including decimal separators + *| Percent Multiply by 100 and display a trailing '%' character + *| Scientific Display with exponent + * + * User-defined formats consist of a combination of tokens and literal + * characters. Literal characters are copied unmodified to the formatted + * output at the position they occupy in the format string. Any character + * that is not recognised as a token is treated as a literal. A literal can + * also be specified by preceding it with a backslash character + * (e.g. "\L\i\t\e\r\a\l") or enclosing it in double quotes. + * + * A user-defined format can have up to 4 sections, depending on the type of + * format. The following table lists sections and their meaning: + *| Format Type Sections Meaning + *| ----------- -------- ------- + *| Number 1 Use the same format for all numbers + *| Number 2 Use format 1 for positive and 2 for negative numbers + *| Number 3 Use format 1 for positive, 2 for zero, and 3 + *| for negative numbers. + *| Number 4 Use format 1 for positive, 2 for zero, 3 for + *| negative, and 4 for null numbers. + *| String 1 Use the same format for all strings + *| String 2 Use format 2 for null and empty strings, otherwise + *| use format 1. + *| Date 1 Use the same format for all dates + * + * The formatting tokens fall into several categories depending on the type + * of formatted output. For more information on each type, see + * VarFormat-Dates(), VarFormat-Strings() and VarFormat-Numbers(). + * + * SEE ALSO + * VarTokenizeFormatString(), VarFormatFromTokens(), VarFormat(), + * VarFormatDateTime(), VarFormatNumber(), VarFormatCurrency(). + */ + +/****************************************************************************** + * VarFormat-Strings {OLEAUT32} + * + * NOTES + * When formatting a variant as a string, it is first converted to a VT_BSTR. + * The user-format string defines which characters are copied into which + * positions in the output string. Literals may be inserted in the format + * string. When creating the formatted string, excess characters in the string + * (those not consumed by a token) are appended to the end of the output. If + * there are more tokens than characters in the string to format, spaces will + * be inserted at the start of the string if the '@' token was used. + * + * By default strings are converted to lowercase, or uppercase if the '>' token + * is encountered. This applies to the whole string: it is not possible to + * generate a mixed-case output string. + * + * In user-defined string formats, the following tokens are recognised: + *| Token Description + *| ----- ----------- + *| '@' Copy a char from the source, or a space if no chars are left. + *| '&' Copy a char from the source, or write nothing if no chars are left. + *| '<' Output the whole string as lower-case (the default). + *| '>' Output the whole string as upper-case. + *| '!' MSDN indicates that this character should cause right-to-left + *| copying, however tests show that it is tokenised but not processed. + */ + +/* + * Common format definitions + */ + + /* Fomat types */ +#define FMT_TYPE_UNKNOWN 0x0 +#define FMT_TYPE_GENERAL 0x1 +#define FMT_TYPE_NUMBER 0x2 +#define FMT_TYPE_DATE 0x3 +#define FMT_TYPE_STRING 0x4 + +#define FMT_TO_STRING 0x0 /* If header->size == this, act like VB's Str() fn */ + +typedef struct tagFMT_SHORT_HEADER +{ + BYTE size; /* Size of tokenised block (including header), or FMT_TO_STRING */ + BYTE type; /* Allowable types (FMT_TYPE_*) */ + BYTE offset[1]; /* Offset of the first (and only) format section */ +} FMT_SHORT_HEADER; + +typedef struct tagFMT_HEADER +{ + BYTE size; /* Total size of the whole tokenised block (including header) */ + BYTE type; /* Allowable types (FMT_TYPE_*) */ + BYTE starts[4]; /* Offset of each of the 4 format sections, or 0 if none */ +} FMT_HEADER; + +#define FmtGetPositive(x) (x->starts[0]) +#define FmtGetNegative(x) (x->starts[1] ? x->starts[1] : x->starts[0]) +#define FmtGetZero(x) (x->starts[2] ? x->starts[2] : x->starts[0]) +#define FmtGetNull(x) (x->starts[3] ? x->starts[3] : x->starts[0]) + +/* + * String formats + */ + +#define FMT_FLAG_LT 0x1 /* Has '<' (lower case) */ +#define FMT_FLAG_GT 0x2 /* Has '>' (upper case) */ +#define FMT_FLAG_RTL 0x4 /* Has '!' (Copy right to left) */ + +typedef struct tagFMT_STRING_HEADER +{ + BYTE flags; /* LT, GT, RTL */ + BYTE unknown1; + BYTE unknown2; + BYTE copy_chars; /* Number of chars to be copied */ + BYTE unknown3; +} FMT_STRING_HEADER; + +/* + * Number formats + */ + +#define FMT_FLAG_PERCENT 0x1 /* Has '%' (Percentage) */ +#define FMT_FLAG_EXPONENT 0x2 /* Has 'e' (Exponent/Scientific notation) */ +#define FMT_FLAG_THOUSANDS 0x4 /* Has ',' (Standard use of the thousands separator) */ +#define FMT_FLAG_BOOL 0x20 /* Boolean format */ + +typedef struct tagFMT_NUMBER_HEADER +{ + BYTE flags; /* PERCENT, EXPONENT, THOUSANDS, BOOL */ + BYTE multiplier; /* Multiplier, 100 for percentages */ + BYTE divisor; /* Divisor, 1000 if '%%' was used */ + BYTE whole; /* Number of digits before the decimal point */ + BYTE fractional; /* Number of digits after the decimal point */ +} FMT_NUMBER_HEADER; + +/* + * Date Formats + */ +typedef struct tagFMT_DATE_HEADER +{ + BYTE flags; + BYTE unknown1; + BYTE unknown2; + BYTE unknown3; + BYTE unknown4; +} FMT_DATE_HEADER; + +/* + * Format token values + */ +#define FMT_GEN_COPY 0x00 /* \n, "lit" => 0,pos,len: Copy len chars from input+pos */ +#define FMT_GEN_INLINE 0x01 /* => 1,len,[chars]: Copy len chars from token stream */ +#define FMT_GEN_END 0x02 /* \0,; => 2: End of the tokenised format */ +#define FMT_DATE_TIME_SEP 0x03 /* Time separator char */ +#define FMT_DATE_DATE_SEP 0x04 /* Date separator char */ +#define FMT_DATE_GENERAL 0x05 /* General format date */ +#define FMT_DATE_QUARTER 0x06 /* Quarter of the year from 1-4 */ +#define FMT_DATE_TIME_SYS 0x07 /* System long time format */ +#define FMT_DATE_DAY 0x08 /* Day with no leading 0 */ +#define FMT_DATE_DAY_0 0x09 /* Day with leading 0 */ +#define FMT_DATE_DAY_SHORT 0x0A /* Short day name */ +#define FMT_DATE_DAY_LONG 0x0B /* Long day name */ +#define FMT_DATE_SHORT 0x0C /* Short date format */ +#define FMT_DATE_LONG 0x0D /* Long date format */ +#define FMT_DATE_MEDIUM 0x0E /* Medium date format */ +#define FMT_DATE_DAY_WEEK 0x0F /* First day of the week */ +#define FMT_DATE_WEEK_YEAR 0x10 /* First week of the year */ +#define FMT_DATE_MON 0x11 /* Month with no leading 0 */ +#define FMT_DATE_MON_0 0x12 /* Month with leading 0 */ +#define FMT_DATE_MON_SHORT 0x13 /* Short month name */ +#define FMT_DATE_MON_LONG 0x14 /* Long month name */ +#define FMT_DATE_YEAR_DOY 0x15 /* Day of the year with no leading 0 */ +#define FMT_DATE_YEAR_0 0x16 /* 2 digit year with leading 0 */ +/* NOTE: token 0x17 is not defined, 'yyy' is not valid */ +#define FMT_DATE_YEAR_LONG 0x18 /* 4 digit year */ +#define FMT_DATE_MIN 0x1A /* Minutes with no leading 0 */ +#define FMT_DATE_MIN_0 0x1B /* Minutes with leading 0 */ +#define FMT_DATE_SEC 0x1C /* Seconds with no leading 0 */ +#define FMT_DATE_SEC_0 0x1D /* Seconds with leading 0 */ +#define FMT_DATE_HOUR 0x1E /* Hours with no leading 0 */ +#define FMT_DATE_HOUR_0 0x1F /* Hours with leading 0 */ +#define FMT_DATE_HOUR_12 0x20 /* Hours with no leading 0, 12 hour clock */ +#define FMT_DATE_HOUR_12_0 0x21 /* Hours with leading 0, 12 hour clock */ +#define FMT_DATE_TIME_UNK2 0x23 +/* FIXME: probably missing some here */ +#define FMT_DATE_AMPM_SYS1 0x2E /* AM/PM as defined by system settings */ +#define FMT_DATE_AMPM_UPPER 0x2F /* Upper-case AM or PM */ +#define FMT_DATE_A_UPPER 0x30 /* Upper-case A or P */ +#define FMT_DATE_AMPM_SYS2 0x31 /* AM/PM as defined by system settings */ +#define FMT_DATE_AMPM_LOWER 0x32 /* Lower-case AM or PM */ +#define FMT_DATE_A_LOWER 0x33 /* Lower-case A or P */ +#define FMT_NUM_COPY_ZERO 0x34 /* Copy 1 digit or 0 if no digit */ +#define FMT_NUM_COPY_SKIP 0x35 /* Copy 1 digit or skip if no digit */ +#define FMT_NUM_DECIMAL 0x36 /* Decimal separator */ +#define FMT_NUM_EXP_POS_U 0x37 /* Scientific notation, uppercase, + sign */ +#define FMT_NUM_EXP_NEG_U 0x38 /* Scientific notation, lowercase, - sign */ +#define FMT_NUM_EXP_POS_L 0x39 /* Scientific notation, uppercase, + sign */ +#define FMT_NUM_EXP_NEG_L 0x3A /* Scientific notation, lowercase, - sign */ +#define FMT_NUM_CURRENCY 0x3B /* Currency symbol */ +#define FMT_NUM_TRUE_FALSE 0x3D /* Convert to "True" or "False" */ +#define FMT_NUM_YES_NO 0x3E /* Convert to "Yes" or "No" */ +#define FMT_NUM_ON_OFF 0x3F /* Convert to "On" or "Off" */ +#define FMT_STR_COPY_SPACE 0x40 /* Copy len chars with space if no char */ +#define FMT_STR_COPY_SKIP 0x41 /* Copy len chars or skip if no char */ +/* Wine additions */ +#define FMT_WINE_HOURS_12 0x81 /* Hours using 12 hour clockhourCopy len chars or skip if no char */ + +/* Named Formats and their tokenised values */ +static const WCHAR szGeneralDate[] = { 'G','e','n','e','r','a','l',' ','D','a','t','e','\0' }; +static const BYTE fmtGeneralDate[0x0a] = +{ + 0x0a,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER), + 0x0,0x0,0x0,0x0,0x0, + FMT_DATE_GENERAL,FMT_GEN_END +}; + +static const WCHAR szShortDate[] = { 'S','h','o','r','t',' ','D','a','t','e','\0' }; +static const BYTE fmtShortDate[0x0a] = +{ + 0x0a,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER), + 0x0,0x0,0x0,0x0,0x0, + FMT_DATE_SHORT,FMT_GEN_END +}; + +static const WCHAR szMediumDate[] = { 'M','e','d','i','u','m',' ','D','a','t','e','\0' }; +static const BYTE fmtMediumDate[0x0a] = +{ + 0x0a,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER), + 0x0,0x0,0x0,0x0,0x0, + FMT_DATE_MEDIUM,FMT_GEN_END +}; + +static const WCHAR szLongDate[] = { 'L','o','n','g',' ','D','a','t','e','\0' }; +static const BYTE fmtLongDate[0x0a] = +{ + 0x0a,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER), + 0x0,0x0,0x0,0x0,0x0, + FMT_DATE_LONG,FMT_GEN_END +}; + +static const WCHAR szShortTime[] = { 'S','h','o','r','t',' ','T','i','m','e','\0' }; +static const BYTE fmtShortTime[0x0c] = +{ + 0x0c,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER), + 0x0,0x0,0x0,0x0,0x0, + FMT_DATE_TIME_UNK2,FMT_DATE_TIME_SEP,FMT_DATE_MIN_0,FMT_GEN_END +}; + +static const WCHAR szMediumTime[] = { 'M','e','d','i','u','m',' ','T','i','m','e','\0' }; +static const BYTE fmtMediumTime[0x11] = +{ + 0x11,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER), + 0x0,0x0,0x0,0x0,0x0, + FMT_DATE_HOUR_12_0,FMT_DATE_TIME_SEP,FMT_DATE_MIN_0, + FMT_GEN_INLINE,0x01,' ','\0',FMT_DATE_AMPM_SYS1,FMT_GEN_END +}; + +static const WCHAR szLongTime[] = { 'L','o','n','g',' ','T','i','m','e','\0' }; +static const BYTE fmtLongTime[0x0d] = +{ + 0x0a,FMT_TYPE_DATE,sizeof(FMT_SHORT_HEADER), + 0x0,0x0,0x0,0x0,0x0, + FMT_DATE_TIME_SYS,FMT_GEN_END +}; + +static const WCHAR szTrueFalse[] = { 'T','r','u','e','/','F','a','l','s','e','\0' }; +static const BYTE fmtTrueFalse[0x0d] = +{ + 0x0d,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0, + FMT_FLAG_BOOL,0x0,0x0,0x0,0x0, + FMT_NUM_TRUE_FALSE,FMT_GEN_END +}; + +static const WCHAR szYesNo[] = { 'Y','e','s','/','N','o','\0' }; +static const BYTE fmtYesNo[0x0d] = +{ + 0x0d,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0, + FMT_FLAG_BOOL,0x0,0x0,0x0,0x0, + FMT_NUM_YES_NO,FMT_GEN_END +}; + +static const WCHAR szOnOff[] = { 'O','n','/','O','f','f','\0' }; +static const BYTE fmtOnOff[0x0d] = +{ + 0x0d,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0, + FMT_FLAG_BOOL,0x0,0x0,0x0,0x0, + FMT_NUM_ON_OFF,FMT_GEN_END +}; + +static const WCHAR szGeneralNumber[] = { 'G','e','n','e','r','a','l',' ','N','u','m','b','e','r','\0' }; +static const BYTE fmtGeneralNumber[sizeof(FMT_HEADER)] = +{ + sizeof(FMT_HEADER),FMT_TYPE_GENERAL,sizeof(FMT_HEADER),0x0,0x0,0x0 +}; + +static const WCHAR szCurrency[] = { 'C','u','r','r','e','n','c','y','\0' }; +static const BYTE fmtCurrency[0x26] = +{ + 0x26,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x12,0x0,0x0, + /* Positive numbers */ + FMT_FLAG_THOUSANDS,0xcc,0x0,0x1,0x2, + FMT_NUM_CURRENCY,FMT_NUM_COPY_ZERO,0x1,FMT_NUM_DECIMAL,FMT_NUM_COPY_ZERO,0x2, + FMT_GEN_END, + /* Negative numbers */ + FMT_FLAG_THOUSANDS,0xcc,0x0,0x1,0x2, + FMT_GEN_INLINE,0x1,'(','\0',FMT_NUM_CURRENCY,FMT_NUM_COPY_ZERO,0x1, + FMT_NUM_DECIMAL,FMT_NUM_COPY_ZERO,0x2,FMT_GEN_INLINE,0x1,')','\0', + FMT_GEN_END +}; + +static const WCHAR szFixed[] = { 'F','i','x','e','d','\0' }; +static const BYTE fmtFixed[0x11] = +{ + 0x11,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0, + 0x0,0x0,0x0,0x1,0x2, + FMT_NUM_COPY_ZERO,0x1,FMT_NUM_DECIMAL,FMT_NUM_COPY_ZERO,0x2,FMT_GEN_END +}; + +static const WCHAR szStandard[] = { 'S','t','a','n','d','a','r','d','\0' }; +static const BYTE fmtStandard[0x11] = +{ + 0x11,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0, + FMT_FLAG_THOUSANDS,0x0,0x0,0x1,0x2, + FMT_NUM_COPY_ZERO,0x1,FMT_NUM_DECIMAL,FMT_NUM_COPY_ZERO,0x2,FMT_GEN_END +}; + +static const WCHAR szPercent[] = { 'P','e','r','c','e','n','t','\0' }; +static const BYTE fmtPercent[0x15] = +{ + 0x15,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0, + FMT_FLAG_PERCENT,0x1,0x0,0x1,0x2, + FMT_NUM_COPY_ZERO,0x1,FMT_NUM_DECIMAL,FMT_NUM_COPY_ZERO,0x2, + FMT_GEN_INLINE,0x1,'%','\0',FMT_GEN_END +}; + +static const WCHAR szScientific[] = { 'S','c','i','e','n','t','i','f','i','c','\0' }; +static const BYTE fmtScientific[0x13] = +{ + 0x13,FMT_TYPE_NUMBER,sizeof(FMT_HEADER),0x0,0x0,0x0, + FMT_FLAG_EXPONENT,0x0,0x0,0x1,0x2, + FMT_NUM_COPY_ZERO,0x1,FMT_NUM_DECIMAL,FMT_NUM_COPY_ZERO,0x2,FMT_NUM_EXP_POS_U,0x2,FMT_GEN_END +}; + +typedef struct tagNAMED_FORMAT +{ + LPCWSTR name; + const BYTE* format; +} NAMED_FORMAT; + +/* Format name to tokenised format. Must be kept sorted by name */ +static const NAMED_FORMAT VARIANT_NamedFormats[] = +{ + { szCurrency, fmtCurrency }, + { szFixed, fmtFixed }, + { szGeneralDate, fmtGeneralDate }, + { szGeneralNumber, fmtGeneralNumber }, + { szLongDate, fmtLongDate }, + { szLongTime, fmtLongTime }, + { szMediumDate, fmtMediumDate }, + { szMediumTime, fmtMediumTime }, + { szOnOff, fmtOnOff }, + { szPercent, fmtPercent }, + { szScientific, fmtScientific }, + { szShortDate, fmtShortDate }, + { szShortTime, fmtShortTime }, + { szStandard, fmtStandard }, + { szTrueFalse, fmtTrueFalse }, + { szYesNo, fmtYesNo } +}; +typedef const NAMED_FORMAT *LPCNAMED_FORMAT; + +static int FormatCompareFn(const void *l, const void *r) +{ + return strcmpiW(((LPCNAMED_FORMAT)l)->name, ((LPCNAMED_FORMAT)r)->name); +} + +static inline const BYTE *VARIANT_GetNamedFormat(LPCWSTR lpszFormat) +{ + NAMED_FORMAT key; + LPCNAMED_FORMAT fmt; + + key.name = lpszFormat; + fmt = (LPCNAMED_FORMAT)bsearch(&key, VARIANT_NamedFormats, + sizeof(VARIANT_NamedFormats)/sizeof(NAMED_FORMAT), + sizeof(NAMED_FORMAT), FormatCompareFn); + return fmt ? fmt->format : NULL; +} + +/* Return an error if the token for the value will not fit in the destination */ +#define NEED_SPACE(x) if (cbTok < (int)(x)) return TYPE_E_BUFFERTOOSMALL; cbTok -= (x) + +/* Non-zero if the format is unknown or a given type */ +#define COULD_BE(typ) ((!fmt_number && header->type==FMT_TYPE_UNKNOWN)||header->type==typ) + +/* State during tokenising */ +#define FMT_STATE_OPEN_COPY 0x1 /* Last token written was a copy */ +#define FMT_STATE_WROTE_DECIMAL 0x2 /* Already wrote a decimal separator */ +#define FMT_STATE_SEEN_HOURS 0x4 /* See the hh specifier */ +#define FMT_STATE_WROTE_MINUTES 0x8 /* Wrote minutes */ + +/********************************************************************** + * VarTokenizeFormatString [OLEAUT32.140] + * + * Convert a format string into tokenised form. + * + * PARAMS + * lpszFormat [I] Format string to tokenise + * rgbTok [O] Destination for tokenised format + * cbTok [I] Size of rgbTok in bytes + * nFirstDay [I] First day of the week (1-7, or 0 for current system default) + * nFirstWeek [I] How to treat the first week (see notes) + * lcid [I] Locale Id of the format string + * pcbActual [O] If non-NULL, filled with the first token generated + * + * RETURNS + * Success: S_OK. rgbTok contains the tokenised format. + * Failure: E_INVALIDARG, if any argument is invalid. + * TYPE_E_BUFFERTOOSMALL, if rgbTok is not large enough. + * + * NOTES + * Valid values for the nFirstWeek parameter are: + *| Value Meaning + *| ----- ------- + *| 0 Use the current system default + *| 1 The first week is that containing Jan 1 + *| 2 Four or more days of the first week are in the current year + *| 3 The first week is 7 days long + * See Variant-Formats(), VarFormatFromTokens(). + */ +HRESULT WINAPI VarTokenizeFormatString(LPOLESTR lpszFormat, LPBYTE rgbTok, + int cbTok, int nFirstDay, int nFirstWeek, + LCID lcid, int *pcbActual) +{ + /* Note: none of these strings should be NUL terminated */ + static const WCHAR szTTTTT[] = { 't','t','t','t','t' }; + static const WCHAR szAMPM[] = { 'A','M','P','M' }; + static const WCHAR szampm[] = { 'a','m','p','m' }; + static const WCHAR szAMSlashPM[] = { 'A','M','/','P','M' }; + static const WCHAR szamSlashpm[] = { 'a','m','/','p','m' }; + const BYTE *namedFmt; + FMT_HEADER *header = (FMT_HEADER*)rgbTok; + FMT_STRING_HEADER *str_header = (FMT_STRING_HEADER*)(rgbTok + sizeof(FMT_HEADER)); + FMT_NUMBER_HEADER *num_header = (FMT_NUMBER_HEADER*)str_header; + FMT_DATE_HEADER *date_header = (FMT_DATE_HEADER*)str_header; + BYTE* pOut = rgbTok + sizeof(FMT_HEADER) + sizeof(FMT_STRING_HEADER); + BYTE* pLastHours = NULL; + BYTE fmt_number = 0; + DWORD fmt_state = 0; + LPCWSTR pFormat = lpszFormat; + + TRACE("(%s,%p,%d,%d,%d,0x%08lx,%p)\n", debugstr_w(lpszFormat), rgbTok, cbTok, + nFirstDay, nFirstWeek, lcid, pcbActual); + + if (!rgbTok || + nFirstDay < 0 || nFirstDay > 7 || nFirstWeek < 0 || nFirstWeek > 3) + return E_INVALIDARG; + + if (!lpszFormat || !*lpszFormat) + { + /* An empty string means 'general format' */ + NEED_SPACE(sizeof(BYTE)); + *rgbTok = FMT_TO_STRING; + if (pcbActual) + *pcbActual = FMT_TO_STRING; + return S_OK; + } + + if (cbTok > 255) + cbTok = 255; /* Ensure we error instead of wrapping */ + + /* Named formats */ + namedFmt = VARIANT_GetNamedFormat(lpszFormat); + if (namedFmt) + { + NEED_SPACE(namedFmt[0]); + memcpy(rgbTok, namedFmt, namedFmt[0]); + TRACE("Using pre-tokenised named format %s\n", debugstr_w(lpszFormat)); + /* FIXME: pcbActual */ + return S_OK; + } + + /* Insert header */ + NEED_SPACE(sizeof(FMT_HEADER) + sizeof(FMT_STRING_HEADER)); + memset(header, 0, sizeof(FMT_HEADER)); + memset(str_header, 0, sizeof(FMT_STRING_HEADER)); + + header->starts[fmt_number] = sizeof(FMT_HEADER); + + while (*pFormat) + { + /* -------------- + * General tokens + * -------------- + */ + if (*pFormat == ';') + { + while (*pFormat == ';') + { + TRACE(";\n"); + if (++fmt_number > 3) + return E_INVALIDARG; /* too many formats */ + pFormat++; + } + if (*pFormat) + { + TRACE("New header\n"); + NEED_SPACE(sizeof(BYTE) + sizeof(FMT_STRING_HEADER)); + *pOut++ = FMT_GEN_END; + + header->starts[fmt_number] = pOut - rgbTok; + str_header = (FMT_STRING_HEADER*)pOut; + num_header = (FMT_NUMBER_HEADER*)pOut; + date_header = (FMT_DATE_HEADER*)pOut; + memset(str_header, 0, sizeof(FMT_STRING_HEADER)); + pOut += sizeof(FMT_STRING_HEADER); + fmt_state = 0; + pLastHours = NULL; + } + } + else if (*pFormat == '\\') + { + /* Escaped character */ + if (pFormat[1]) + { + NEED_SPACE(3 * sizeof(BYTE)); + pFormat++; + *pOut++ = FMT_GEN_COPY; + *pOut++ = pFormat - lpszFormat; + *pOut++ = 0x1; + fmt_state |= FMT_STATE_OPEN_COPY; + TRACE("'\\'\n"); + } + else + fmt_state &= ~FMT_STATE_OPEN_COPY; + pFormat++; + } + else if (*pFormat == '"') + { + /* Escaped string + * Note: Native encodes "" as a copy of length zero. That's just dumb, so + * here we avoid encoding anything in this case. + */ + if (!pFormat[1]) + pFormat++; + else if (pFormat[1] == '"') + { + pFormat += 2; + } + else + { + LPCWSTR start = ++pFormat; + while (*pFormat && *pFormat != '"') + pFormat++; + NEED_SPACE(3 * sizeof(BYTE)); + *pOut++ = FMT_GEN_COPY; + *pOut++ = start - lpszFormat; + *pOut++ = pFormat - start; + if (*pFormat == '"') + pFormat++; + TRACE("Quoted string pos %d, len %d\n", pOut[-2], pOut[-1]); + } + fmt_state &= ~FMT_STATE_OPEN_COPY; + } + /* ------------- + * Number tokens + * ------------- + */ + else if (*pFormat == '0' && COULD_BE(FMT_TYPE_NUMBER)) + { + /* Number formats: Digit from number or '0' if no digits + * Other formats: Literal + * Types the format if found + */ + header->type = FMT_TYPE_NUMBER; + NEED_SPACE(2 * sizeof(BYTE)); + *pOut++ = FMT_NUM_COPY_ZERO; + *pOut = 0x0; + while (*pFormat == '0') + { + *pOut = *pOut + 1; + pFormat++; + } + if (fmt_state & FMT_STATE_WROTE_DECIMAL) + num_header->fractional += *pOut; + else + num_header->whole += *pOut; + TRACE("%d 0's\n", *pOut); + pOut++; + fmt_state &= ~FMT_STATE_OPEN_COPY; + } + else if (*pFormat == '#' && COULD_BE(FMT_TYPE_NUMBER)) + { + /* Number formats: Digit from number or blank if no digits + * Other formats: Literal + * Types the format if found + */ + header->type = FMT_TYPE_NUMBER; + NEED_SPACE(2 * sizeof(BYTE)); + *pOut++ = FMT_NUM_COPY_SKIP; + *pOut = 0x0; + while (*pFormat == '#') + { + *pOut = *pOut + 1; + pFormat++; + } + if (fmt_state & FMT_STATE_WROTE_DECIMAL) + num_header->fractional += *pOut; + else + num_header->whole += *pOut; + TRACE("%d #'s\n", *pOut); + pOut++; + fmt_state &= ~FMT_STATE_OPEN_COPY; + } + else if (*pFormat == '.' && COULD_BE(FMT_TYPE_NUMBER) && + !(fmt_state & FMT_STATE_WROTE_DECIMAL)) + { + /* Number formats: Decimal separator when 1st seen, literal thereafter + * Other formats: Literal + * Types the format if found + */ + header->type = FMT_TYPE_NUMBER; + NEED_SPACE(sizeof(BYTE)); + *pOut++ = FMT_NUM_DECIMAL; + fmt_state |= FMT_STATE_WROTE_DECIMAL; + fmt_state &= ~FMT_STATE_OPEN_COPY; + pFormat++; + TRACE("decimal sep\n"); + } + /* FIXME: E+ E- e+ e- => Exponent */ + /* FIXME: %% => Divide by 1000 */ + else if (*pFormat == ',' && header->type == FMT_TYPE_NUMBER) + { + /* Number formats: Use the thousands separator + * Other formats: Literal + */ + num_header->flags |= FMT_FLAG_THOUSANDS; + pFormat++; + fmt_state &= ~FMT_STATE_OPEN_COPY; + TRACE("thousands sep\n"); + } + /* ----------- + * Date tokens + * ----------- + */ + else if (*pFormat == '/' && COULD_BE(FMT_TYPE_DATE)) + { + /* Date formats: Date separator + * Other formats: Literal + * Types the format if found + */ + header->type = FMT_TYPE_DATE; + NEED_SPACE(sizeof(BYTE)); + *pOut++ = FMT_DATE_DATE_SEP; + pFormat++; + fmt_state &= ~FMT_STATE_OPEN_COPY; + TRACE("date sep\n"); + } + else if (*pFormat == ':' && COULD_BE(FMT_TYPE_DATE)) + { + /* Date formats: Time separator + * Other formats: Literal + * Types the format if found + */ + header->type = FMT_TYPE_DATE; + NEED_SPACE(sizeof(BYTE)); + *pOut++ = FMT_DATE_TIME_SEP; + pFormat++; + fmt_state &= ~FMT_STATE_OPEN_COPY; + TRACE("time sep\n"); + } + else if ((*pFormat == 'a' || *pFormat == 'A') && + !strncmpiW(pFormat, szAMPM, sizeof(szAMPM)/sizeof(WCHAR))) + { + /* Date formats: System AM/PM designation + * Other formats: Literal + * Types the format if found + */ + header->type = FMT_TYPE_DATE; + NEED_SPACE(sizeof(BYTE)); + pFormat += sizeof(szAMPM)/sizeof(WCHAR); + if (!strncmpW(pFormat, szampm, sizeof(szampm)/sizeof(WCHAR))) + *pOut++ = FMT_DATE_AMPM_SYS2; + else + *pOut++ = FMT_DATE_AMPM_SYS1; + if (pLastHours) + *pLastHours = *pLastHours + 2; + TRACE("ampm\n"); + } + else if (*pFormat == 'a' && pFormat[1] == '/' && + (pFormat[2] == 'p' || pFormat[2] == 'P')) + { + /* Date formats: lowercase a or p designation + * Other formats: Literal + * Types the format if found + */ + header->type = FMT_TYPE_DATE; + NEED_SPACE(sizeof(BYTE)); + pFormat += 3; + *pOut++ = FMT_DATE_A_LOWER; + if (pLastHours) + *pLastHours = *pLastHours + 2; + TRACE("a/p\n"); + } + else if (*pFormat == 'A' && pFormat[1] == '/' && + (pFormat[2] == 'p' || pFormat[2] == 'P')) + { + /* Date formats: Uppercase a or p designation + * Other formats: Literal + * Types the format if found + */ + header->type = FMT_TYPE_DATE; + NEED_SPACE(sizeof(BYTE)); + pFormat += 3; + *pOut++ = FMT_DATE_A_UPPER; + if (pLastHours) + *pLastHours = *pLastHours + 2; + TRACE("A/P\n"); + } + else if (*pFormat == 'a' && + !strncmpW(pFormat, szamSlashpm, sizeof(szamSlashpm)/sizeof(WCHAR))) + { + /* Date formats: lowercase AM or PM designation + * Other formats: Literal + * Types the format if found + */ + header->type = FMT_TYPE_DATE; + NEED_SPACE(sizeof(BYTE)); + pFormat += sizeof(szamSlashpm)/sizeof(WCHAR); + *pOut++ = FMT_DATE_AMPM_LOWER; + if (pLastHours) + *pLastHours = *pLastHours + 2; + TRACE("AM/PM\n"); + } + else if (*pFormat == 'A' && + !strncmpW(pFormat, szAMSlashPM, sizeof(szAMSlashPM)/sizeof(WCHAR))) + { + /* Date formats: Uppercase AM or PM designation + * Other formats: Literal + * Types the format if found + */ + header->type = FMT_TYPE_DATE; + NEED_SPACE(sizeof(BYTE)); + pFormat += sizeof(szAMSlashPM)/sizeof(WCHAR); + *pOut++ = FMT_DATE_AMPM_UPPER; + TRACE("AM/PM\n"); + } + else if (*pFormat == 'c' || *pFormat == 'C') + { + /* Date formats: General date format + * Other formats: Literal + * Types the format if found + */ + header->type = FMT_TYPE_DATE; + NEED_SPACE(sizeof(BYTE)); + pFormat += sizeof(szAMSlashPM)/sizeof(WCHAR); + *pOut++ = FMT_DATE_GENERAL; + TRACE("gen date\n"); + } + else if ((*pFormat == 'd' || *pFormat == 'D') && COULD_BE(FMT_TYPE_DATE)) + { + /* Date formats: Day specifier + * Other formats: Literal + * Types the format if found + */ + int count = -1; + header->type = FMT_TYPE_DATE; + while ((*pFormat == 'd' || *pFormat == 'D') && count < 6) + { + pFormat++; + count++; + } + NEED_SPACE(sizeof(BYTE)); + *pOut++ = FMT_DATE_DAY + count; + fmt_state &= ~FMT_STATE_OPEN_COPY; + /* When we find the days token, reset the seen hours state so that + * 'mm' is again written as month when encountered. + */ + fmt_state &= ~FMT_STATE_SEEN_HOURS; + TRACE("%d d's\n", count + 1); + } + else if ((*pFormat == 'h' || *pFormat == 'H') && COULD_BE(FMT_TYPE_DATE)) + { + /* Date formats: Hour specifier + * Other formats: Literal + * Types the format if found + */ + header->type = FMT_TYPE_DATE; + NEED_SPACE(sizeof(BYTE)); + pFormat++; + /* Record the position of the hours specifier - if we encounter + * an am/pm specifier we will change the hours from 24 to 12. + */ + pLastHours = pOut; + if (*pFormat == 'h' || *pFormat == 'H') + { + pFormat++; + *pOut++ = FMT_DATE_HOUR_0; + TRACE("hh\n"); + } + else + { + *pOut++ = FMT_DATE_HOUR; + TRACE("h\n"); + } + fmt_state &= ~FMT_STATE_OPEN_COPY; + /* Note that now we have seen an hours token, the next occurrence of + * 'mm' indicates minutes, not months. + */ + fmt_state |= FMT_STATE_SEEN_HOURS; + } + else if ((*pFormat == 'm' || *pFormat == 'M') && COULD_BE(FMT_TYPE_DATE)) + { + /* Date formats: Month specifier (or Minute specifier, after hour specifier) + * Other formats: Literal + * Types the format if found + */ + int count = -1; + header->type = FMT_TYPE_DATE; + while ((*pFormat == 'm' || *pFormat == 'M') && count < 4) + { + pFormat++; + count++; + } + NEED_SPACE(sizeof(BYTE)); + if (count <= 1 && fmt_state & FMT_STATE_SEEN_HOURS && + !(fmt_state & FMT_STATE_WROTE_MINUTES)) + { + /* We have seen an hours specifier and not yet written a minutes + * specifier. Write this as minutes and thereafter as months. + */ + *pOut++ = count == 1 ? FMT_DATE_MIN_0 : FMT_DATE_MIN; + fmt_state |= FMT_STATE_WROTE_MINUTES; /* Hereafter write months */ + } + else + *pOut++ = FMT_DATE_MON + count; /* Months */ + fmt_state &= ~FMT_STATE_OPEN_COPY; + TRACE("%d m's\n", count + 1); + } + else if ((*pFormat == 'n' || *pFormat == 'N') && COULD_BE(FMT_TYPE_DATE)) + { + /* Date formats: Minute specifier + * Other formats: Literal + * Types the format if found + */ + header->type = FMT_TYPE_DATE; + NEED_SPACE(sizeof(BYTE)); + pFormat++; + if (*pFormat == 'n' || *pFormat == 'N') + { + pFormat++; + *pOut++ = FMT_DATE_MIN_0; + TRACE("nn\n"); + } + else + { + *pOut++ = FMT_DATE_MIN; + TRACE("n\n"); + } + fmt_state &= ~FMT_STATE_OPEN_COPY; + } + else if ((*pFormat == 'q' || *pFormat == 'q') && COULD_BE(FMT_TYPE_DATE)) + { + /* Date formats: Quarter specifier + * Other formats: Literal + * Types the format if found + */ + header->type = FMT_TYPE_DATE; + NEED_SPACE(sizeof(BYTE)); + *pOut++ = FMT_DATE_QUARTER; + pFormat++; + fmt_state &= ~FMT_STATE_OPEN_COPY; + TRACE("quarter\n"); + } + else if ((*pFormat == 's' || *pFormat == 'S') && COULD_BE(FMT_TYPE_DATE)) + { + /* Date formats: Second specifier + * Other formats: Literal + * Types the format if found + */ + header->type = FMT_TYPE_DATE; + NEED_SPACE(sizeof(BYTE)); + pFormat++; + if (*pFormat == 's' || *pFormat == 'S') + { + pFormat++; + *pOut++ = FMT_DATE_SEC_0; + TRACE("ss\n"); + } + else + { + *pOut++ = FMT_DATE_SEC; + TRACE("s\n"); + } + fmt_state &= ~FMT_STATE_OPEN_COPY; + } + else if ((*pFormat == 't' || *pFormat == 'T') && + !strncmpiW(pFormat, szTTTTT, sizeof(szTTTTT)/sizeof(WCHAR))) + { + /* Date formats: System time specifier + * Other formats: Literal + * Types the format if found + */ + header->type = FMT_TYPE_DATE; + pFormat += sizeof(szTTTTT)/sizeof(WCHAR); + NEED_SPACE(sizeof(BYTE)); + *pOut++ = FMT_DATE_TIME_SYS; + fmt_state &= ~FMT_STATE_OPEN_COPY; + } + else if ((*pFormat == 'w' || *pFormat == 'W') && COULD_BE(FMT_TYPE_DATE)) + { + /* Date formats: Week of the year/Day of the week + * Other formats: Literal + * Types the format if found + */ + header->type = FMT_TYPE_DATE; + pFormat++; + if (*pFormat == 'w' || *pFormat == 'W') + { + NEED_SPACE(3 * sizeof(BYTE)); + pFormat++; + *pOut++ = FMT_DATE_WEEK_YEAR; + *pOut++ = nFirstDay; + *pOut++ = nFirstWeek; + TRACE("ww\n"); + } + else + { + NEED_SPACE(2 * sizeof(BYTE)); + *pOut++ = FMT_DATE_DAY_WEEK; + *pOut++ = nFirstDay; + TRACE("w\n"); + } + + fmt_state &= ~FMT_STATE_OPEN_COPY; + } + else if ((*pFormat == 'y' || *pFormat == 'Y') && COULD_BE(FMT_TYPE_DATE)) + { + /* Date formats: Day of year/Year specifier + * Other formats: Literal + * Types the format if found + */ + int count = -1; + header->type = FMT_TYPE_DATE; + while ((*pFormat == 'y' || *pFormat == 'Y') && count < 4) + { + pFormat++; + count++; + } + if (count == 2) + { + count--; /* 'yyy' has no meaning, despite what MSDN says */ + pFormat--; + } + NEED_SPACE(sizeof(BYTE)); + *pOut++ = FMT_DATE_YEAR_DOY + count; + fmt_state &= ~FMT_STATE_OPEN_COPY; + TRACE("%d y's\n", count + 1); + } + /* ------------- + * String tokens + * ------------- + */ + else if (*pFormat == '@' && COULD_BE(FMT_TYPE_STRING)) + { + /* String formats: Character from string or space if no char + * Other formats: Literal + * Types the format if found + */ + header->type = FMT_TYPE_STRING; + NEED_SPACE(2 * sizeof(BYTE)); + *pOut++ = FMT_STR_COPY_SPACE; + *pOut = 0x0; + while (*pFormat == '@') + { + *pOut = *pOut + 1; + str_header->copy_chars++; + pFormat++; + } + TRACE("%d @'s\n", *pOut); + pOut++; + fmt_state &= ~FMT_STATE_OPEN_COPY; + } + else if (*pFormat == '&' && COULD_BE(FMT_TYPE_STRING)) + { + /* String formats: Character from string or skip if no char + * Other formats: Literal + * Types the format if found + */ + header->type = FMT_TYPE_STRING; + NEED_SPACE(2 * sizeof(BYTE)); + *pOut++ = FMT_STR_COPY_SKIP; + *pOut = 0x0; + while (*pFormat == '&') + { + *pOut = *pOut + 1; + str_header->copy_chars++; + pFormat++; + } + TRACE("%d &'s\n", *pOut); + pOut++; + fmt_state &= ~FMT_STATE_OPEN_COPY; + } + else if ((*pFormat == '<' || *pFormat == '>') && COULD_BE(FMT_TYPE_STRING)) + { + /* String formats: Use upper/lower case + * Other formats: Literal + * Types the format if found + */ + header->type = FMT_TYPE_STRING; + if (*pFormat == '<') + str_header->flags |= FMT_FLAG_LT; + else + str_header->flags |= FMT_FLAG_GT; + TRACE("to %s case\n", *pFormat == '<' ? "lower" : "upper"); + pFormat++; + fmt_state &= ~FMT_STATE_OPEN_COPY; + } + else if (*pFormat == '!' && COULD_BE(FMT_TYPE_STRING)) + { + /* String formats: Copy right to left + * Other formats: Literal + * Types the format if found + */ + header->type = FMT_TYPE_STRING; + str_header->flags |= FMT_FLAG_RTL; + pFormat++; + fmt_state &= ~FMT_STATE_OPEN_COPY; + TRACE("copy right-to-left\n"); + } + /* -------- + * Literals + * -------- + */ + /* FIXME: [ seems to be ignored */ + else + { + if (*pFormat == '%' && header->type == FMT_TYPE_NUMBER) + { + /* Number formats: Percentage indicator, also a literal + * Other formats: Literal + * Doesn't type the format + */ + num_header->flags |= FMT_FLAG_PERCENT; + } + + if (fmt_state & FMT_STATE_OPEN_COPY) + { + pOut[-1] = pOut[-1] + 1; /* Increase the length of the open copy */ + TRACE("extend copy (char '%c'), length now %d\n", *pFormat, pOut[-1]); + } + else + { + /* Create a new open copy */ + TRACE("New copy (char '%c')\n", *pFormat); + NEED_SPACE(3 * sizeof(BYTE)); + *pOut++ = FMT_GEN_COPY; + *pOut++ = pFormat - lpszFormat; + *pOut++ = 0x1; + fmt_state |= FMT_STATE_OPEN_COPY; + } + pFormat++; + } + } + + *pOut++ = FMT_GEN_END; + + header->size = pOut - rgbTok; + if (pcbActual) + *pcbActual = header->size; + + return S_OK; +} + +/* Number formatting state flags */ +#define NUM_WROTE_DEC 0x01 /* Written the decimal separator */ + +/* Format a variant using a number format */ +static HRESULT VARIANT_FormatNumber(LPVARIANT pVarIn, LPOLESTR lpszFormat, + LPBYTE rgbTok, ULONG dwFlags, + BSTR *pbstrOut, LCID lcid) +{ + BYTE rgbDig[256]; + NUMPARSE np; + int wholeNumberDigits, fractionalDigits, divisor10 = 0, multiplier10 = 0; + WCHAR buff[256], *pBuff = buff; + VARIANT vString, vBool; + DWORD dwState = 0; + FMT_HEADER *header = (FMT_HEADER*)rgbTok; + FMT_NUMBER_HEADER *numHeader; + const BYTE* pToken = NULL; + HRESULT hRes = S_OK; + + TRACE("(%p->(%s%s),%s,%p,0x%08lx,%p,0x%08lx)\n", pVarIn, debugstr_VT(pVarIn), + debugstr_VF(pVarIn), debugstr_w(lpszFormat), rgbTok, dwFlags, pbstrOut, + lcid); + + V_VT(&vString) = VT_EMPTY; + V_VT(&vBool) = VT_BOOL; + + if (V_TYPE(pVarIn) == VT_EMPTY || V_TYPE(pVarIn) == VT_NULL) + { + wholeNumberDigits = fractionalDigits = 0; + numHeader = (FMT_NUMBER_HEADER*)(rgbTok + FmtGetNull(header)); + V_BOOL(&vBool) = VARIANT_FALSE; + } + else + { + /* Get a number string from pVarIn, and parse it */ + hRes = VariantChangeTypeEx(&vString, pVarIn, LCID_US, VARIANT_NOUSEROVERRIDE, VT_BSTR); + if (FAILED(hRes)) + return hRes; + + np.cDig = sizeof(rgbDig); + np.dwInFlags = NUMPRS_STD; + hRes = VarParseNumFromStr(V_BSTR(&vString), LCID_US, 0, &np, rgbDig); + if (FAILED(hRes)) + return hRes; + + if (np.nPwr10 < 0) + { + if (-np.nPwr10 >= np.cDig) + { + /* A real number < +/- 1.0 e.g. 0.1024 or 0.01024 */ + wholeNumberDigits = 0; + fractionalDigits = np.cDig; + divisor10 = -np.nPwr10; + } + else + { + /* An exactly represented real number e.g. 1.024 */ + wholeNumberDigits = np.cDig + np.nPwr10; + fractionalDigits = np.cDig - wholeNumberDigits; + divisor10 = np.cDig - wholeNumberDigits; + } + } + else if (np.nPwr10 == 0) + { + /* An exactly represented whole number e.g. 1024 */ + wholeNumberDigits = np.cDig; + fractionalDigits = 0; + } + else /* np.nPwr10 > 0 */ + { + /* A whole number followed by nPwr10 0's e.g. 102400 */ + wholeNumberDigits = np.cDig; + fractionalDigits = 0; + multiplier10 = np.nPwr10; + } + + /* Figure out which format to use */ + if (np.dwOutFlags & NUMPRS_NEG) + { + numHeader = (FMT_NUMBER_HEADER*)(rgbTok + FmtGetNegative(header)); + V_BOOL(&vBool) = VARIANT_TRUE; + } + else if (wholeNumberDigits == 1 && !fractionalDigits && !multiplier10 && + !divisor10 && rgbDig[0] == 0) + { + numHeader = (FMT_NUMBER_HEADER*)(rgbTok + FmtGetZero(header)); + V_BOOL(&vBool) = VARIANT_FALSE; + } + else + { + numHeader = (FMT_NUMBER_HEADER*)(rgbTok + FmtGetPositive(header)); + V_BOOL(&vBool) = VARIANT_TRUE; + } + + TRACE("num header: flags = 0x%x, mult=%d, div=%d, whole=%d, fract=%d\n", + numHeader->flags, numHeader->multiplier, numHeader->divisor, + numHeader->whole, numHeader->fractional); + + if (numHeader->flags & FMT_FLAG_PERCENT && + !(wholeNumberDigits == 1 && !fractionalDigits && !multiplier10 && + !divisor10 && rgbDig[0] == 0)) + { + /* *100 for %'s. Try to 'steal' fractional digits if we can */ + TRACE("Fraction - multiply by 100\n"); + if (!fractionalDigits) + multiplier10 += 2; + else + { + fractionalDigits--; + wholeNumberDigits++; + if (!fractionalDigits) + multiplier10++; + else + { + fractionalDigits--; + wholeNumberDigits++; + } + } + } + TRACE("cDig %d; nPwr10 %d, whole %d, frac %d ", np.cDig, + np.nPwr10, wholeNumberDigits, fractionalDigits); + TRACE("mult %d; div %d\n", multiplier10, divisor10); + + } + pToken = (const BYTE*)numHeader + sizeof(FMT_NUMBER_HEADER); + + while (SUCCEEDED(hRes) && *pToken != FMT_GEN_END) + { + WCHAR defaultChar = '?'; + DWORD boolFlag, localeValue = 0; + + if (pToken - rgbTok > header->size) + { + ERR("Ran off the end of the format!\n"); + hRes = E_INVALIDARG; + goto VARIANT_FormatNumber_Exit; + } + + switch (*pToken) + { + case FMT_GEN_COPY: + TRACE("copy %s\n", debugstr_wn(lpszFormat + pToken[1], pToken[2])); + memcpy(pBuff, lpszFormat + pToken[1], pToken[2] * sizeof(WCHAR)); + pBuff += pToken[2]; + pToken += 2; + break; + + case FMT_GEN_INLINE: + pToken += 2; + TRACE("copy %s\n", debugstr_a(pToken)); + while (*pToken) + *pBuff++ = *pToken++; + break; + + case FMT_NUM_YES_NO: + boolFlag = VAR_BOOLYESNO; + goto VARIANT_FormatNumber_Bool; + + case FMT_NUM_ON_OFF: + boolFlag = VAR_BOOLONOFF; + goto VARIANT_FormatNumber_Bool; + + case FMT_NUM_TRUE_FALSE: + boolFlag = VAR_LOCALBOOL; + +VARIANT_FormatNumber_Bool: + { + BSTR boolStr = NULL; + + if (pToken[1] != FMT_GEN_END) + { + ERR("Boolean token not at end of format!\n"); + hRes = E_INVALIDARG; + goto VARIANT_FormatNumber_Exit; + } + hRes = VarBstrFromBool(V_BOOL(&vBool), lcid, boolFlag, &boolStr); + if (SUCCEEDED(hRes)) + { + strcpyW(pBuff, boolStr); + SysFreeString(boolStr); + while (*pBuff) + pBuff++; + } + } + break; + + case FMT_NUM_DECIMAL: + TRACE("write decimal separator\n"); + localeValue = LOCALE_SDECIMAL; + defaultChar = '.'; + dwState |= NUM_WROTE_DEC; + break; + + case FMT_NUM_CURRENCY: + TRACE("write currency symbol\n"); + localeValue = LOCALE_SCURRENCY; + defaultChar = '$'; + break; + + case FMT_NUM_EXP_POS_U: + case FMT_NUM_EXP_POS_L: + case FMT_NUM_EXP_NEG_U: + case FMT_NUM_EXP_NEG_L: + if (*pToken == FMT_NUM_EXP_POS_L || *pToken == FMT_NUM_EXP_NEG_L) + *pBuff++ = 'e'; + else + *pBuff++ = 'E'; + if (divisor10) + { + *pBuff++ = '-'; + sprintfW(pBuff, szPercentZeroStar_d, pToken[1], divisor10); + } + else + { + if (*pToken == FMT_NUM_EXP_POS_L || *pToken == FMT_NUM_EXP_POS_U) + *pBuff++ = '+'; + sprintfW(pBuff, szPercentZeroStar_d, pToken[1], multiplier10); + } + while (*pBuff) + pBuff++; + pToken++; + break; + + case FMT_NUM_COPY_SKIP: + if (dwState & NUM_WROTE_DEC) + { + int count; + + TRACE("write %d fractional digits or skip\n", pToken[1]); + + for (count = 0; count < fractionalDigits; count++) + pBuff[count] = '0' + rgbDig[wholeNumberDigits + count]; + pBuff += fractionalDigits; + } + else + { + int count; + + TRACE("write %d digits or skip\n", pToken[1]); + + if (wholeNumberDigits > 1 || rgbDig[0] > 0) + { + TRACE("write %d whole number digits\n", wholeNumberDigits); + for (count = 0; count < wholeNumberDigits; count++) + *pBuff++ = '0' + rgbDig[count]; + TRACE("write %d whole trailing 0's\n", multiplier10); + for (count = 0; count < multiplier10; count++) + *pBuff++ = '0'; /* Write trailing zeros for multiplied values */ + } + } + pToken++; + break; + + case FMT_NUM_COPY_ZERO: + if (dwState & NUM_WROTE_DEC) + { + int count; + + TRACE("write %d fractional digits or 0's\n", pToken[1]); + + for (count = 0; count < fractionalDigits; count++) + pBuff[count] = '0' + rgbDig[wholeNumberDigits + count]; + pBuff += fractionalDigits; + if (pToken[1] > fractionalDigits) + { + count = pToken[1] - fractionalDigits; + while (count--) + *pBuff++ = '0'; /* Write trailing zeros for missing digits */ + } + } + else + { + int count; + + TRACE("write %d digits or 0's\n", pToken[1]); + + if (pToken[1] > (wholeNumberDigits + multiplier10)) + { + count = pToken[1] - (wholeNumberDigits + multiplier10); + TRACE("write %d leading zeros\n", count); + while(count--) + *pBuff++ = '0'; /* Write leading zeros for missing digits */ + } + TRACE("write %d whole number digits\n", wholeNumberDigits); + for (count = 0; count < wholeNumberDigits; count++) + *pBuff++ = '0' + rgbDig[count]; + TRACE("write %d whole trailing 0's\n", multiplier10); + for (count = 0; count < multiplier10; count++) + *pBuff++ = '0'; /* Write trailing zeros for multiplied values */ + } + pToken++; + break; + + default: + ERR("Unknown token 0x%02x!\n", *pToken); + hRes = E_INVALIDARG; + goto VARIANT_FormatNumber_Exit; + } + if (localeValue) + { + if (GetLocaleInfoW(lcid, localeValue, pBuff, + sizeof(buff)/sizeof(WCHAR)-(pBuff-buff))) + { + TRACE("added %s\n", debugstr_w(pBuff)); + while (*pBuff) + pBuff++; + } + else + { + TRACE("added %d '%c'\n", defaultChar, defaultChar); + *pBuff++ = defaultChar; + } + } + pToken++; + } + +VARIANT_FormatNumber_Exit: + VariantClear(&vString); + *pBuff = '\0'; + TRACE("buff is %s\n", debugstr_w(buff)); + if (SUCCEEDED(hRes)) + { + *pbstrOut = SysAllocString(buff); + if (!*pbstrOut) + hRes = E_OUTOFMEMORY; + } + return hRes; +} + +/* Format a variant using a date format */ +static HRESULT VARIANT_FormatDate(LPVARIANT pVarIn, LPOLESTR lpszFormat, + LPBYTE rgbTok, ULONG dwFlags, + BSTR *pbstrOut, LCID lcid) +{ + WCHAR buff[256], *pBuff = buff; + VARIANT vDate; + UDATE udate; + FMT_HEADER *header = (FMT_HEADER*)rgbTok; + FMT_DATE_HEADER *dateHeader; + const BYTE* pToken = NULL; + HRESULT hRes; + + TRACE("(%p->(%s%s),%s,%p,0x%08lx,%p,0x%08lx)\n", pVarIn, debugstr_VT(pVarIn), + debugstr_VF(pVarIn), debugstr_w(lpszFormat), rgbTok, dwFlags, pbstrOut, + lcid); + + V_VT(&vDate) = VT_EMPTY; + + if (V_TYPE(pVarIn) == VT_EMPTY || V_TYPE(pVarIn) == VT_NULL) + { + dateHeader = (FMT_DATE_HEADER*)(rgbTok + FmtGetNegative(header)); + V_DATE(&vDate) = 0; + } + else + { + USHORT usFlags = dwFlags & VARIANT_CALENDAR_HIJRI ? VAR_CALENDAR_HIJRI : 0; + + hRes = VariantChangeTypeEx(&vDate, pVarIn, LCID_US, usFlags, VT_DATE); + if (FAILED(hRes)) + return hRes; + dateHeader = (FMT_DATE_HEADER*)(rgbTok + FmtGetPositive(header)); + } + + hRes = VarUdateFromDate(V_DATE(&vDate), 0 /* FIXME: flags? */, &udate); + if (FAILED(hRes)) + return hRes; + pToken = (const BYTE*)dateHeader + sizeof(FMT_DATE_HEADER); + + while (*pToken != FMT_GEN_END) + { + DWORD dwVal = 0, localeValue = 0, dwFmt = 0; + LPCWSTR szPrintFmt = NULL; + WCHAR defaultChar = '?'; + + if (pToken - rgbTok > header->size) + { + ERR("Ran off the end of the format!\n"); + hRes = E_INVALIDARG; + goto VARIANT_FormatDate_Exit; + } + + switch (*pToken) + { + case FMT_GEN_COPY: + TRACE("copy %s\n", debugstr_wn(lpszFormat + pToken[1], pToken[2])); + memcpy(pBuff, lpszFormat + pToken[1], pToken[2] * sizeof(WCHAR)); + pBuff += pToken[2]; + pToken += 2; + break; + + case FMT_DATE_TIME_SEP: + TRACE("time separator\n"); + localeValue = LOCALE_STIME; + defaultChar = ':'; + break; + + case FMT_DATE_DATE_SEP: + TRACE("date separator\n"); + localeValue = LOCALE_SDATE; + defaultChar = '/'; + break; + + case FMT_DATE_GENERAL: + { + BSTR date = NULL; + WCHAR *pDate = date; + hRes = VarBstrFromDate(V_DATE(&vDate), lcid, 0, pbstrOut); + if (FAILED(hRes)) + goto VARIANT_FormatDate_Exit; + while (*pDate) + *pBuff++ = *pDate++; + SysFreeString(date); + } + break; + + case FMT_DATE_QUARTER: + if (udate.st.wMonth <= 3) + *pBuff++ = '1'; + else if (udate.st.wMonth <= 6) + *pBuff++ = '2'; + else if (udate.st.wMonth <= 9) + *pBuff++ = '3'; + else + *pBuff++ = '4'; + break; + + case FMT_DATE_TIME_SYS: + { + /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */ + BSTR date = NULL; + WCHAR *pDate = date; + hRes = VarBstrFromDate(V_DATE(&vDate), lcid, VAR_TIMEVALUEONLY, pbstrOut); + if (FAILED(hRes)) + goto VARIANT_FormatDate_Exit; + while (*pDate) + *pBuff++ = *pDate++; + SysFreeString(date); + } + break; + + case FMT_DATE_DAY: + szPrintFmt = szPercent_d; + dwVal = udate.st.wDay; + break; + + case FMT_DATE_DAY_0: + szPrintFmt = szPercentZeroTwo_d; + dwVal = udate.st.wDay; + break; + + case FMT_DATE_DAY_SHORT: + /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */ + TRACE("short day\n"); + localeValue = LOCALE_SABBREVDAYNAME1 + udate.st.wMonth - 1; + defaultChar = '?'; + break; + + case FMT_DATE_DAY_LONG: + /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */ + TRACE("long day\n"); + localeValue = LOCALE_SDAYNAME1 + udate.st.wMonth - 1; + defaultChar = '?'; + break; + + case FMT_DATE_SHORT: + /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */ + dwFmt = LOCALE_SSHORTDATE; + break; + + case FMT_DATE_LONG: + /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */ + dwFmt = LOCALE_SLONGDATE; + break; + + case FMT_DATE_MEDIUM: + FIXME("Medium date treated as long date\n"); + dwFmt = LOCALE_SLONGDATE; + break; + + case FMT_DATE_DAY_WEEK: + szPrintFmt = szPercent_d; + if (pToken[1]) + dwVal = udate.st.wDayOfWeek + 2 - pToken[1]; + else + { + GetLocaleInfoW(lcid,LOCALE_RETURN_NUMBER|LOCALE_IFIRSTDAYOFWEEK, + (LPWSTR)&dwVal, sizeof(dwVal)/sizeof(WCHAR)); + dwVal = udate.st.wDayOfWeek + 1 - dwVal; + } + pToken++; + break; + + case FMT_DATE_WEEK_YEAR: + szPrintFmt = szPercent_d; + dwVal = udate.wDayOfYear / 7 + 1; + pToken += 2; + FIXME("Ignoring nFirstDay of %d, nFirstWeek of %d\n", pToken[0], pToken[1]); + break; + + case FMT_DATE_MON: + szPrintFmt = szPercent_d; + dwVal = udate.st.wMonth; + break; + + case FMT_DATE_MON_0: + szPrintFmt = szPercentZeroTwo_d; + dwVal = udate.st.wMonth; + break; + + case FMT_DATE_MON_SHORT: + /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */ + TRACE("short month\n"); + localeValue = LOCALE_SABBREVMONTHNAME1 + udate.st.wMonth - 1; + defaultChar = '?'; + break; + + case FMT_DATE_MON_LONG: + /* FIXME: VARIANT_CALENDAR HIJRI should cause Hijri output */ + TRACE("long month\n"); + localeValue = LOCALE_SMONTHNAME1 + udate.st.wMonth - 1; + defaultChar = '?'; + break; + + case FMT_DATE_YEAR_DOY: + szPrintFmt = szPercent_d; + dwVal = udate.wDayOfYear; + break; + + case FMT_DATE_YEAR_0: + szPrintFmt = szPercentZeroTwo_d; + dwVal = udate.st.wYear % 100; + break; + + case FMT_DATE_YEAR_LONG: + szPrintFmt = szPercent_d; + dwVal = udate.st.wYear; + break; + + case FMT_DATE_MIN: + szPrintFmt = szPercent_d; + dwVal = udate.st.wMinute; + break; + + case FMT_DATE_MIN_0: + szPrintFmt = szPercentZeroTwo_d; + dwVal = udate.st.wMinute; + break; + + case FMT_DATE_SEC: + szPrintFmt = szPercent_d; + dwVal = udate.st.wSecond; + break; + + case FMT_DATE_SEC_0: + szPrintFmt = szPercentZeroTwo_d; + dwVal = udate.st.wSecond; + break; + + case FMT_DATE_HOUR: + szPrintFmt = szPercent_d; + dwVal = udate.st.wHour; + break; + + case FMT_DATE_HOUR_0: + szPrintFmt = szPercentZeroTwo_d; + dwVal = udate.st.wHour; + break; + + case FMT_DATE_HOUR_12: + szPrintFmt = szPercent_d; + dwVal = udate.st.wHour ? udate.st.wHour > 12 ? udate.st.wHour - 12 : udate.st.wHour : 12; + break; + + case FMT_DATE_HOUR_12_0: + szPrintFmt = szPercentZeroTwo_d; + dwVal = udate.st.wHour ? udate.st.wHour > 12 ? udate.st.wHour - 12 : udate.st.wHour : 12; + break; + + case FMT_DATE_AMPM_SYS1: + case FMT_DATE_AMPM_SYS2: + localeValue = udate.st.wHour < 12 ? LOCALE_S1159 : LOCALE_S2359; + defaultChar = '?'; + break; + + case FMT_DATE_AMPM_UPPER: + *pBuff++ = udate.st.wHour < 12 ? 'A' : 'P'; + *pBuff++ = 'M'; + break; + + case FMT_DATE_A_UPPER: + *pBuff++ = udate.st.wHour < 12 ? 'A' : 'P'; + break; + + case FMT_DATE_AMPM_LOWER: + *pBuff++ = udate.st.wHour < 12 ? 'a' : 'p'; + *pBuff++ = 'm'; + break; + + case FMT_DATE_A_LOWER: + *pBuff++ = udate.st.wHour < 12 ? 'a' : 'p'; + break; + + default: + ERR("Unknown token 0x%02x!\n", *pToken); + hRes = E_INVALIDARG; + goto VARIANT_FormatDate_Exit; + } + if (localeValue) + { + *pBuff = '\0'; + if (GetLocaleInfoW(lcid, localeValue, pBuff, + sizeof(buff)/sizeof(WCHAR)-(pBuff-buff))) + { + TRACE("added %s\n", debugstr_w(pBuff)); + while (*pBuff) + pBuff++; + } + else + { + TRACE("added %d %c\n", defaultChar, defaultChar); + *pBuff++ = defaultChar; + } + } + else if (dwFmt) + { + WCHAR fmt_buff[80]; + + if (!GetLocaleInfoW(lcid, dwFmt, fmt_buff, sizeof(fmt_buff)/sizeof(WCHAR)) || + !GetDateFormatW(lcid, 0, &udate.st, fmt_buff, pBuff, + sizeof(buff)/sizeof(WCHAR)-(pBuff-buff))) + { + hRes = E_INVALIDARG; + goto VARIANT_FormatDate_Exit; + } + while (*pBuff) + pBuff++; + } + else if (szPrintFmt) + { + sprintfW(pBuff, szPrintFmt, dwVal); + while (*pBuff) + pBuff++; + } + pToken++; + } + +VARIANT_FormatDate_Exit: + *pBuff = '\0'; + TRACE("buff is %s\n", debugstr_w(buff)); + if (SUCCEEDED(hRes)) + { + *pbstrOut = SysAllocString(buff); + if (!*pbstrOut) + hRes = E_OUTOFMEMORY; + } + return hRes; +} + +/* Format a variant using a string format */ +static HRESULT VARIANT_FormatString(LPVARIANT pVarIn, LPOLESTR lpszFormat, + LPBYTE rgbTok, ULONG dwFlags, + BSTR *pbstrOut, LCID lcid) +{ + static const WCHAR szEmpty[] = { '\0' }; + WCHAR buff[256], *pBuff = buff; + WCHAR *pSrc; + FMT_HEADER *header = (FMT_HEADER*)rgbTok; + FMT_STRING_HEADER *strHeader; + const BYTE* pToken = NULL; + VARIANT vStr; + int blanks_first; + BOOL bUpper = FALSE; + HRESULT hRes = S_OK; + + TRACE("(%p->(%s%s),%s,%p,0x%08lx,%p,0x%08lx)\n", pVarIn, debugstr_VT(pVarIn), + debugstr_VF(pVarIn), debugstr_w(lpszFormat), rgbTok, dwFlags, pbstrOut, + lcid); + + V_VT(&vStr) = VT_EMPTY; + + if (V_TYPE(pVarIn) == VT_EMPTY || V_TYPE(pVarIn) == VT_NULL) + { + strHeader = (FMT_STRING_HEADER*)(rgbTok + FmtGetNegative(header)); + V_BSTR(&vStr) = (WCHAR*)szEmpty; + } + else + { + hRes = VariantChangeTypeEx(&vStr, pVarIn, LCID_US, VARIANT_NOUSEROVERRIDE, VT_BSTR); + if (FAILED(hRes)) + return hRes; + + if (V_BSTR(pVarIn)[0] == '\0') + strHeader = (FMT_STRING_HEADER*)(rgbTok + FmtGetNegative(header)); + else + strHeader = (FMT_STRING_HEADER*)(rgbTok + FmtGetPositive(header)); + } + pSrc = V_BSTR(&vStr); + if ((strHeader->flags & (FMT_FLAG_LT|FMT_FLAG_GT)) == FMT_FLAG_GT) + bUpper = TRUE; + blanks_first = strHeader->copy_chars - strlenW(pSrc); + pToken = (const BYTE*)strHeader + sizeof(FMT_DATE_HEADER); + + while (*pToken != FMT_GEN_END) + { + int dwCount = 0; + + if (pToken - rgbTok > header->size) + { + ERR("Ran off the end of the format!\n"); + hRes = E_INVALIDARG; + goto VARIANT_FormatString_Exit; + } + + switch (*pToken) + { + case FMT_GEN_COPY: + TRACE("copy %s\n", debugstr_wn(lpszFormat + pToken[1], pToken[2])); + memcpy(pBuff, lpszFormat + pToken[1], pToken[2] * sizeof(WCHAR)); + pBuff += pToken[2]; + pToken += 2; + break; + + case FMT_STR_COPY_SPACE: + case FMT_STR_COPY_SKIP: + dwCount = pToken[1]; + if (*pToken == FMT_STR_COPY_SPACE && blanks_first > 0) + { + TRACE("insert %d initial spaces\n", blanks_first); + while (dwCount > 0 && blanks_first > 0) + { + *pBuff++ = ' '; + dwCount--; + blanks_first--; + } + } + TRACE("copy %d chars%s\n", dwCount, + *pToken == FMT_STR_COPY_SPACE ? " with space" :""); + while (dwCount > 0 && *pSrc) + { + if (bUpper) + *pBuff++ = toupperW(*pSrc); + else + *pBuff++ = tolowerW(*pSrc); + dwCount--; + pSrc++; + } + if (*pToken == FMT_STR_COPY_SPACE && dwCount > 0) + { + TRACE("insert %d spaces\n", dwCount); + while (dwCount-- > 0) + *pBuff++ = ' '; + } + pToken++; + break; + + default: + ERR("Unknown token 0x%02x!\n", *pToken); + hRes = E_INVALIDARG; + goto VARIANT_FormatString_Exit; + } + pToken++; + } + +VARIANT_FormatString_Exit: + /* Copy out any remaining chars */ + while (*pSrc) + { + if (bUpper) + *pBuff++ = toupperW(*pSrc); + else + *pBuff++ = tolowerW(*pSrc); + pSrc++; + } + VariantClear(&vStr); + *pBuff = '\0'; + TRACE("buff is %s\n", debugstr_w(buff)); + if (SUCCEEDED(hRes)) + { + *pbstrOut = SysAllocString(buff); + if (!*pbstrOut) + hRes = E_OUTOFMEMORY; + } + return hRes; +} + +#define NUMBER_VTBITS (VTBIT_I1|VTBIT_UI1|VTBIT_I2|VTBIT_UI2| \ + VTBIT_I4|VTBIT_UI4|VTBIT_I8|VTBIT_UI8| \ + VTBIT_R4|VTBIT_R8|VTBIT_CY|VTBIT_DECIMAL| \ + (1<<VT_BOOL)|(1<<VT_INT)|(1<<VT_UINT)) + +/********************************************************************** + * VarFormatFromTokens [OLEAUT32.139] + */ +HRESULT WINAPI VarFormatFromTokens(LPVARIANT pVarIn, LPOLESTR lpszFormat, + LPBYTE rgbTok, ULONG dwFlags, + BSTR *pbstrOut, LCID lcid) +{ + FMT_SHORT_HEADER *header = (FMT_SHORT_HEADER *)rgbTok; + VARIANT vTmp; + HRESULT hres; + + TRACE("(%p,%s,%p,%lx,%p,0x%08lx)\n", pVarIn, debugstr_w(lpszFormat), + rgbTok, dwFlags, pbstrOut, lcid); + + if (!pbstrOut) + return E_INVALIDARG; + + *pbstrOut = NULL; + + if (!pVarIn || !rgbTok) + return E_INVALIDARG; + + if (*rgbTok == FMT_TO_STRING || header->type == FMT_TYPE_GENERAL) + { + /* According to MSDN, general format acts somewhat like the 'Str' + * function in Visual Basic. + */ +VarFormatFromTokens_AsStr: + V_VT(&vTmp) = VT_EMPTY; + hres = VariantChangeTypeEx(&vTmp, pVarIn, lcid, dwFlags, VT_BSTR); + *pbstrOut = V_BSTR(&vTmp); + } + else + { + if (header->type == FMT_TYPE_NUMBER || + (header->type == FMT_TYPE_UNKNOWN && ((1 << V_TYPE(pVarIn)) & NUMBER_VTBITS))) + { + hres = VARIANT_FormatNumber(pVarIn, lpszFormat, rgbTok, dwFlags, pbstrOut, lcid); + } + else if (header->type == FMT_TYPE_DATE || + (header->type == FMT_TYPE_UNKNOWN && V_TYPE(pVarIn) == VT_DATE)) + { + hres = VARIANT_FormatDate(pVarIn, lpszFormat, rgbTok, dwFlags, pbstrOut, lcid); + } + else if (header->type == FMT_TYPE_STRING || V_TYPE(pVarIn) == VT_BSTR) + { + hres = VARIANT_FormatString(pVarIn, lpszFormat, rgbTok, dwFlags, pbstrOut, lcid); + } + else + { + ERR("unrecognised format type 0x%02x\n", header->type); + return E_INVALIDARG; + } + /* If the coercion failed, still try to create output, unless the + * VAR_FORMAT_NOSUBSTITUTE flag is set. + */ + if ((hres == DISP_E_OVERFLOW || hres == DISP_E_TYPEMISMATCH) && + !(dwFlags & VAR_FORMAT_NOSUBSTITUTE)) + goto VarFormatFromTokens_AsStr; + } + + return hres; +} + +/********************************************************************** + * VarFormat [OLEAUT32.87] + * + * Format a variant from a format string. + * + * PARAMS + * pVarIn [I] Variant to format + * lpszFormat [I] Format string (see notes) + * nFirstDay [I] First day of the week, (See VarTokenizeFormatString() for details) + * nFirstWeek [I] First week of the year (See VarTokenizeFormatString() for details) + * dwFlags [I] Flags for the format (VAR_ flags from "oleauto.h") + * pbstrOut [O] Destination for formatted string. + * + * RETURNS + * Success: S_OK. pbstrOut contains the formatted value. + * Failure: E_INVALIDARG, if any parameter is invalid. + * E_OUTOFMEMORY, if enough memory cannot be allocated. + * DISP_E_TYPEMISMATCH, if the variant cannot be formatted. + * + * NOTES + * - See Variant-Formats for details concerning creating format strings. + * - This function uses LOCALE_USER_DEFAULT when calling VarTokenizeFormatString() + * and VarFormatFromTokens(). + */ +HRESULT WINAPI VarFormat(LPVARIANT pVarIn, LPOLESTR lpszFormat, + int nFirstDay, int nFirstWeek, ULONG dwFlags, + BSTR *pbstrOut) +{ + BYTE buff[256]; + HRESULT hres; + + TRACE("(%p->(%s%s),%s,%d,%d,0x%08lx,%p)\n", pVarIn, debugstr_VT(pVarIn), + debugstr_VF(pVarIn), debugstr_w(lpszFormat), nFirstDay, nFirstWeek, + dwFlags, pbstrOut); + + if (!pbstrOut) + return E_INVALIDARG; + *pbstrOut = NULL; + + hres = VarTokenizeFormatString(lpszFormat, buff, sizeof(buff), nFirstDay, + nFirstWeek, LOCALE_USER_DEFAULT, NULL); + if (SUCCEEDED(hres)) + hres = VarFormatFromTokens(pVarIn, lpszFormat, buff, dwFlags, + pbstrOut, LOCALE_USER_DEFAULT); + TRACE("returning 0x%08lx, %s\n", hres, debugstr_w(*pbstrOut)); + return hres; +} + +/********************************************************************** + * VarFormatDateTime [OLEAUT32.97] + * + * Format a variant value as a date and/or time. + * + * PARAMS + * pVarIn [I] Variant to format + * nFormat [I] Format type (see notes) + * dwFlags [I] Flags for the format (VAR_ flags from "oleauto.h") + * pbstrOut [O] Destination for formatted string. + * + * RETURNS + * Success: S_OK. pbstrOut contains the formatted value. + * Failure: E_INVALIDARG, if any parameter is invalid. + * E_OUTOFMEMORY, if enough memory cannot be allocated. + * DISP_E_TYPEMISMATCH, if the variant cannot be formatted. + * + * NOTES + * This function uses LOCALE_USER_DEFAULT when determining the date format + * characters to use. + * Possible values for the nFormat parameter are: + *| Value Meaning + *| ----- ------- + *| 0 General date format + *| 1 Long date format + *| 2 Short date format + *| 3 Long time format + *| 4 Short time format + */ +HRESULT WINAPI VarFormatDateTime(LPVARIANT pVarIn, INT nFormat, ULONG dwFlags, BSTR *pbstrOut) +{ + static const WCHAR szEmpty[] = { '\0' }; + const BYTE* lpFmt = NULL; + + TRACE("(%p->(%s%s),%d,0x%08lx,%p)\n", pVarIn, debugstr_VT(pVarIn), + debugstr_VF(pVarIn), nFormat, dwFlags, pbstrOut); + + if (!pVarIn || !pbstrOut || nFormat < 0 || nFormat > 4) + return E_INVALIDARG; + + switch (nFormat) + { + case 0: lpFmt = fmtGeneralDate; break; + case 1: lpFmt = fmtLongDate; break; + case 2: lpFmt = fmtShortDate; break; + case 3: lpFmt = fmtLongTime; break; + case 4: lpFmt = fmtShortTime; break; + } + return VarFormatFromTokens(pVarIn, (LPWSTR)szEmpty, (BYTE*)lpFmt, dwFlags, + pbstrOut, LOCALE_USER_DEFAULT); +} + +#define GETLOCALENUMBER(type,field) GetLocaleInfoW(LOCALE_USER_DEFAULT, \ + type|LOCALE_RETURN_NUMBER, \ + (LPWSTR)&numfmt.field, \ + sizeof(numfmt.field)/sizeof(WCHAR)) + +/********************************************************************** + * VarFormatNumber [OLEAUT32.107] + * + * Format a variant value as a number. + * + * PARAMS + * pVarIn [I] Variant to format + * nDigits [I] Number of digits following the decimal point (-1 = user default) + * nLeading [I] Use a leading zero (-2 = user default, -1 = yes, 0 = no) + * nParens [I] Use brackets for values < 0 (-2 = user default, -1 = yes, 0 = no) + * nGrouping [I] Use grouping characters (-2 = user default, -1 = yes, 0 = no) + * dwFlags [I] Currently unused, set to zero + * pbstrOut [O] Destination for formatted string. + * + * RETURNS + * Success: S_OK. pbstrOut contains the formatted value. + * Failure: E_INVALIDARG, if any parameter is invalid. + * E_OUTOFMEMORY, if enough memory cannot be allocated. + * DISP_E_TYPEMISMATCH, if the variant cannot be formatted. + * + * NOTES + * This function uses LOCALE_USER_DEFAULT when determining the number format + * characters to use. + */ +HRESULT WINAPI VarFormatNumber(LPVARIANT pVarIn, INT nDigits, INT nLeading, INT nParens, + INT nGrouping, ULONG dwFlags, BSTR *pbstrOut) +{ + HRESULT hRet; + VARIANT vStr; + + TRACE("(%p->(%s%s),%d,%d,%d,%d,0x%08lx,%p)\n", pVarIn, debugstr_VT(pVarIn), + debugstr_VF(pVarIn), nDigits, nLeading, nParens, nGrouping, dwFlags, pbstrOut); + + if (!pVarIn || !pbstrOut || nDigits > 9) + return E_INVALIDARG; + + *pbstrOut = NULL; + + V_VT(&vStr) = VT_EMPTY; + hRet = VariantCopyInd(&vStr, pVarIn); + + if (SUCCEEDED(hRet)) + hRet = VariantChangeTypeEx(&vStr, &vStr, LOCALE_USER_DEFAULT, 0, VT_BSTR); + + if (SUCCEEDED(hRet)) + { + WCHAR buff[256], decimal[8], thousands[8]; + NUMBERFMTW numfmt; + + /* Although MSDN makes it clear that the native versions of these functions + * are implemented using VarTokenizeFormatString()/VarFormatFromTokens(), + * using NLS gives us the same result. + */ + if (nDigits < 0) + GETLOCALENUMBER(LOCALE_IDIGITS, NumDigits); + else + numfmt.NumDigits = nDigits; + + if (nLeading == -2) + GETLOCALENUMBER(LOCALE_ILZERO, LeadingZero); + else if (nLeading == -1) + numfmt.LeadingZero = 1; + else + numfmt.LeadingZero = 0; + + if (nGrouping == -2) + { + WCHAR grouping[16]; + grouping[2] = '\0'; + GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, grouping, + sizeof(grouping)/sizeof(WCHAR)); + numfmt.Grouping = grouping[2] == '2' ? 32 : grouping[0] - '0'; + } + else if (nGrouping == -1) + numfmt.Grouping = 3; /* 3 = "n,nnn.nn" */ + else + numfmt.Grouping = 0; /* 0 = No grouping */ + + if (nParens == -2) + GETLOCALENUMBER(LOCALE_INEGNUMBER, NegativeOrder); + else if (nParens == -1) + numfmt.NegativeOrder = 0; /* 0 = "(xxx)" */ + else + numfmt.NegativeOrder = 1; /* 1 = "-xxx" */ + + numfmt.lpDecimalSep = decimal; + GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimal, + sizeof(decimal)/sizeof(WCHAR)); + numfmt.lpThousandSep = thousands; + GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, thousands, + sizeof(thousands)/sizeof(WCHAR)); + + if (GetNumberFormatW(LOCALE_USER_DEFAULT, 0, V_BSTR(&vStr), &numfmt, + buff, sizeof(buff)/sizeof(WCHAR))) + { + *pbstrOut = SysAllocString(buff); + if (!*pbstrOut) + hRet = E_OUTOFMEMORY; + } + else + hRet = DISP_E_TYPEMISMATCH; + + SysFreeString(V_BSTR(&vStr)); + } + return hRet; +} + +/********************************************************************** + * VarFormatPercent [OLEAUT32.117] + * + * Format a variant value as a percentage. + * + * PARAMS + * pVarIn [I] Variant to format + * nDigits [I] Number of digits following the decimal point (-1 = user default) + * nLeading [I] Use a leading zero (-2 = user default, -1 = yes, 0 = no) + * nParens [I] Use brackets for values < 0 (-2 = user default, -1 = yes, 0 = no) + * nGrouping [I] Use grouping characters (-2 = user default, -1 = yes, 0 = no) + * dwFlags [I] Currently unused, set to zero + * pbstrOut [O] Destination for formatted string. + * + * RETURNS + * Success: S_OK. pbstrOut contains the formatted value. + * Failure: E_INVALIDARG, if any parameter is invalid. + * E_OUTOFMEMORY, if enough memory cannot be allocated. + * DISP_E_OVERFLOW, if overflow occurs during the conversion. + * DISP_E_TYPEMISMATCH, if the variant cannot be formatted. + * + * NOTES + * This function uses LOCALE_USER_DEFAULT when determining the number format + * characters to use. + */ +HRESULT WINAPI VarFormatPercent(LPVARIANT pVarIn, INT nDigits, INT nLeading, INT nParens, + INT nGrouping, ULONG dwFlags, BSTR *pbstrOut) +{ + static const WCHAR szPercent[] = { '%','\0' }; + static const WCHAR szPercentBracket[] = { '%',')','\0' }; + WCHAR buff[256]; + HRESULT hRet; + VARIANT vDbl; + + TRACE("(%p->(%s%s),%d,%d,%d,%d,0x%08lx,%p)\n", pVarIn, debugstr_VT(pVarIn), + debugstr_VF(pVarIn), nDigits, nLeading, nParens, nGrouping, + dwFlags, pbstrOut); + + if (!pVarIn || !pbstrOut || nDigits > 9) + return E_INVALIDARG; + + *pbstrOut = NULL; + + V_VT(&vDbl) = VT_EMPTY; + hRet = VariantCopyInd(&vDbl, pVarIn); + + if (SUCCEEDED(hRet)) + { + hRet = VariantChangeTypeEx(&vDbl, &vDbl, LOCALE_USER_DEFAULT, 0, VT_R8); + + if (SUCCEEDED(hRet)) + { + if (V_R8(&vDbl) > (R8_MAX / 100.0)) + return DISP_E_OVERFLOW; + + V_R8(&vDbl) *= 100.0; + hRet = VarFormatNumber(&vDbl, nDigits, nLeading, nParens, + nGrouping, dwFlags, pbstrOut); + + if (SUCCEEDED(hRet)) + { + DWORD dwLen = strlenW(*pbstrOut); + BOOL bBracket = (*pbstrOut)[dwLen] == ')' ? TRUE : FALSE; + + dwLen -= bBracket; + memcpy(buff, *pbstrOut, dwLen * sizeof(WCHAR)); + strcpyW(buff + dwLen, bBracket ? szPercentBracket : szPercent); + SysFreeString(*pbstrOut); + *pbstrOut = SysAllocString(buff); + if (!*pbstrOut) + hRet = E_OUTOFMEMORY; + } + } + } + return hRet; +} + +/********************************************************************** + * VarFormatCurrency [OLEAUT32.127] + * + * Format a variant value as a currency. + * + * PARAMS + * pVarIn [I] Variant to format + * nDigits [I] Number of digits following the decimal point (-1 = user default) + * nLeading [I] Use a leading zero (-2 = user default, -1 = yes, 0 = no) + * nParens [I] Use brackets for values < 0 (-2 = user default, -1 = yes, 0 = no) + * nGrouping [I] Use grouping characters (-2 = user default, -1 = yes, 0 = no) + * dwFlags [I] Currently unused, set to zero + * pbstrOut [O] Destination for formatted string. + * + * RETURNS + * Success: S_OK. pbstrOut contains the formatted value. + * Failure: E_INVALIDARG, if any parameter is invalid. + * E_OUTOFMEMORY, if enough memory cannot be allocated. + * DISP_E_TYPEMISMATCH, if the variant cannot be formatted. + * + * NOTES + * This function uses LOCALE_USER_DEFAULT when determining the currency format + * characters to use. + */ +HRESULT WINAPI VarFormatCurrency(LPVARIANT pVarIn, INT nDigits, INT nLeading, + INT nParens, INT nGrouping, ULONG dwFlags, + BSTR *pbstrOut) +{ + HRESULT hRet; + VARIANT vStr; + + TRACE("(%p->(%s%s),%d,%d,%d,%d,0x%08lx,%p)\n", pVarIn, debugstr_VT(pVarIn), + debugstr_VF(pVarIn), nDigits, nLeading, nParens, nGrouping, dwFlags, pbstrOut); + + if (!pVarIn || !pbstrOut || nDigits > 9) + return E_INVALIDARG; + + *pbstrOut = NULL; + + V_VT(&vStr) = VT_EMPTY; + hRet = VariantCopyInd(&vStr, pVarIn); + + if (SUCCEEDED(hRet)) + hRet = VariantChangeTypeEx(&vStr, &vStr, LOCALE_USER_DEFAULT, 0, VT_BSTR); + + if (SUCCEEDED(hRet)) + { + WCHAR buff[256], decimal[8], thousands[8], currency[8]; + CURRENCYFMTW numfmt; + + if (nDigits < 0) + GETLOCALENUMBER(LOCALE_IDIGITS, NumDigits); + else + numfmt.NumDigits = nDigits; + + if (nLeading == -2) + GETLOCALENUMBER(LOCALE_ILZERO, LeadingZero); + else if (nLeading == -1) + numfmt.LeadingZero = 1; + else + numfmt.LeadingZero = 0; + + if (nGrouping == -2) + { + WCHAR nGrouping[16]; + nGrouping[2] = '\0'; + GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, nGrouping, + sizeof(nGrouping)/sizeof(WCHAR)); + numfmt.Grouping = nGrouping[2] == '2' ? 32 : nGrouping[0] - '0'; + } + else if (nGrouping == -1) + numfmt.Grouping = 3; /* 3 = "n,nnn.nn" */ + else + numfmt.Grouping = 0; /* 0 = No grouping */ + + if (nParens == -2) + GETLOCALENUMBER(LOCALE_INEGCURR, NegativeOrder); + else if (nParens == -1) + numfmt.NegativeOrder = 0; /* 0 = "(xxx)" */ + else + numfmt.NegativeOrder = 1; /* 1 = "-xxx" */ + + GETLOCALENUMBER(LOCALE_ICURRENCY, PositiveOrder); + + numfmt.lpDecimalSep = decimal; + GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, decimal, + sizeof(decimal)/sizeof(WCHAR)); + numfmt.lpThousandSep = thousands; + GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, thousands, + sizeof(thousands)/sizeof(WCHAR)); + numfmt.lpCurrencySymbol = currency; + GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, currency, + sizeof(currency)/sizeof(WCHAR)); + + /* use NLS as per VarFormatNumber() */ + if (GetCurrencyFormatW(LOCALE_USER_DEFAULT, 0, V_BSTR(&vStr), &numfmt, + buff, sizeof(buff)/sizeof(WCHAR))) + { + *pbstrOut = SysAllocString(buff); + if (!*pbstrOut) + hRet = E_OUTOFMEMORY; + } + else + hRet = DISP_E_TYPEMISMATCH; + + SysFreeString(V_BSTR(&vStr)); + } + return hRet; +} diff --git a/reactos/lib/oleaut32/variant.c b/reactos/lib/oleaut32/variant.c index 80b2e394175..f57f0df77b2 100644 --- a/reactos/lib/oleaut32/variant.c +++ b/reactos/lib/oleaut32/variant.c @@ -1,4561 +1,4561 @@ -/* - * VARIANT - * - * Copyright 1998 Jean-Claude Cote - * Copyright 2003 Jon Griffiths - * Copyright 2005 Daniel Remenak - * - * The alorithm for conversion from Julian days to day/month/year is based on - * that devised by Henry Fliegel, as implemented in PostgreSQL, which is - * Copyright 1994-7 Regents of the University of California - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <string.h> -#include <stdlib.h> -#include <stdarg.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "wine/unicode.h" -#include "winerror.h" -#include "variant.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(variant); - -const char* wine_vtypes[VT_CLSID] = -{ - "VT_EMPTY","VT_NULL","VT_I2","VT_I4","VT_R4","VT_R8","VT_CY","VT_DATE", - "VT_BSTR","VT_DISPATCH","VT_ERROR","VT_BOOL","VT_VARIANT","VT_UNKNOWN", - "VT_DECIMAL","15","VT_I1","VT_UI1","VT_UI2","VT_UI4","VT_I8","VT_UI8", - "VT_INT","VT_UINT","VT_VOID","VT_HRESULT","VT_PTR","VT_SAFEARRAY", - "VT_CARRAY","VT_USERDEFINED","VT_LPSTR","VT_LPWSTR""32","33","34","35", - "VT_RECORD","VT_INT_PTR","VT_UINT_PTR","39","40","41","42","43","44","45", - "46","47","48","49","50","51","52","53","54","55","56","57","58","59","60", - "61","62","63","VT_FILETIME","VT_BLOB","VT_STREAM","VT_STORAGE", - "VT_STREAMED_OBJECT","VT_STORED_OBJECT","VT_BLOB_OBJECT","VT_CF","VT_CLSID" -}; - -const char* wine_vflags[16] = -{ - "", - "|VT_VECTOR", - "|VT_ARRAY", - "|VT_VECTOR|VT_ARRAY", - "|VT_BYREF", - "|VT_VECTOR|VT_ARRAY", - "|VT_ARRAY|VT_BYREF", - "|VT_VECTOR|VT_ARRAY|VT_BYREF", - "|VT_HARDTYPE", - "|VT_VECTOR|VT_HARDTYPE", - "|VT_ARRAY|VT_HARDTYPE", - "|VT_VECTOR|VT_ARRAY|VT_HARDTYPE", - "|VT_BYREF|VT_HARDTYPE", - "|VT_VECTOR|VT_ARRAY|VT_HARDTYPE", - "|VT_ARRAY|VT_BYREF|VT_HARDTYPE", - "|VT_VECTOR|VT_ARRAY|VT_BYREF|VT_HARDTYPE", -}; - -/* Convert a variant from one type to another */ -static inline HRESULT VARIANT_Coerce(VARIANTARG* pd, LCID lcid, USHORT wFlags, - VARIANTARG* ps, VARTYPE vt) -{ - HRESULT res = DISP_E_TYPEMISMATCH; - VARTYPE vtFrom = V_TYPE(ps); - BOOL bIgnoreOverflow = FALSE; - DWORD dwFlags = 0; - - TRACE("(%p->(%s%s),0x%08lx,0x%04x,%p->(%s%s),%s%s)\n", pd, debugstr_VT(pd), - debugstr_VF(pd), lcid, wFlags, ps, debugstr_VT(ps), debugstr_VF(ps), - debugstr_vt(vt), debugstr_vf(vt)); - - if (vt == VT_BSTR || vtFrom == VT_BSTR) - { - /* All flags passed to low level function are only used for - * changing to or from strings. Map these here. - */ - if (wFlags & VARIANT_LOCALBOOL) - dwFlags |= VAR_LOCALBOOL; - if (wFlags & VARIANT_CALENDAR_HIJRI) - dwFlags |= VAR_CALENDAR_HIJRI; - if (wFlags & VARIANT_CALENDAR_THAI) - dwFlags |= VAR_CALENDAR_THAI; - if (wFlags & VARIANT_CALENDAR_GREGORIAN) - dwFlags |= VAR_CALENDAR_GREGORIAN; - if (wFlags & VARIANT_NOUSEROVERRIDE) - dwFlags |= LOCALE_NOUSEROVERRIDE; - if (wFlags & VARIANT_USE_NLS) - dwFlags |= LOCALE_USE_NLS; - } - - /* Map int/uint to i4/ui4 */ - if (vt == VT_INT) - vt = VT_I4; - else if (vt == VT_UINT) - vt = VT_UI4; - - if (vtFrom == VT_INT) - vtFrom = VT_I4; - else if (vtFrom == VT_UINT) - { - vtFrom = VT_UI4; - if (vt == VT_I4) - bIgnoreOverflow = TRUE; - } - - if (vt == vtFrom) - return VariantCopy(pd, ps); - - if (wFlags & VARIANT_NOVALUEPROP && vtFrom == VT_DISPATCH && vt != VT_UNKNOWN) - { - /* VARIANT_NOVALUEPROP prevents IDispatch objects from being coerced by - * accessing the default object property. - */ - return DISP_E_TYPEMISMATCH; - } - - switch (vt) - { - case VT_EMPTY: - if (vtFrom == VT_NULL) - return DISP_E_TYPEMISMATCH; - /* ... Fall through */ - case VT_NULL: - if (vtFrom <= VT_UINT && vtFrom != (VARTYPE)15 && vtFrom != VT_ERROR) - { - res = VariantClear( pd ); - if (vt == VT_NULL && SUCCEEDED(res)) - V_VT(pd) = VT_NULL; - } - return res; - - case VT_I1: - switch (vtFrom) - { - case VT_EMPTY: V_I1(pd) = 0; return S_OK; - case VT_I2: return VarI1FromI2(V_I2(ps), &V_I1(pd)); - case VT_I4: return VarI1FromI4(V_I4(ps), &V_I1(pd)); - case VT_UI1: return VarI1FromUI1(V_UI1(ps), &V_I1(pd)); - case VT_UI2: return VarI1FromUI2(V_UI2(ps), &V_I1(pd)); - case VT_UI4: return VarI1FromUI4(V_UI4(ps), &V_I1(pd)); - case VT_I8: return VarI1FromI8(V_I8(ps), &V_I1(pd)); - case VT_UI8: return VarI1FromUI8(V_UI8(ps), &V_I1(pd)); - case VT_R4: return VarI1FromR4(V_R4(ps), &V_I1(pd)); - case VT_R8: return VarI1FromR8(V_R8(ps), &V_I1(pd)); - case VT_DATE: return VarI1FromDate(V_DATE(ps), &V_I1(pd)); - case VT_BOOL: return VarI1FromBool(V_BOOL(ps), &V_I1(pd)); - case VT_CY: return VarI1FromCy(V_CY(ps), &V_I1(pd)); - case VT_DECIMAL: return VarI1FromDec(&V_DECIMAL(ps), &V_I1(pd) ); - case VT_DISPATCH: return VarI1FromDisp(V_DISPATCH(ps), lcid, &V_I1(pd) ); - case VT_BSTR: return VarI1FromStr(V_BSTR(ps), lcid, dwFlags, &V_I1(pd) ); - } - break; - - case VT_I2: - switch (vtFrom) - { - case VT_EMPTY: V_I2(pd) = 0; return S_OK; - case VT_I1: return VarI2FromI1(V_I1(ps), &V_I2(pd)); - case VT_I4: return VarI2FromI4(V_I4(ps), &V_I2(pd)); - case VT_UI1: return VarI2FromUI1(V_UI1(ps), &V_I2(pd)); - case VT_UI2: return VarI2FromUI2(V_UI2(ps), &V_I2(pd)); - case VT_UI4: return VarI2FromUI4(V_UI4(ps), &V_I2(pd)); - case VT_I8: return VarI2FromI8(V_I8(ps), &V_I2(pd)); - case VT_UI8: return VarI2FromUI8(V_UI8(ps), &V_I2(pd)); - case VT_R4: return VarI2FromR4(V_R4(ps), &V_I2(pd)); - case VT_R8: return VarI2FromR8(V_R8(ps), &V_I2(pd)); - case VT_DATE: return VarI2FromDate(V_DATE(ps), &V_I2(pd)); - case VT_BOOL: return VarI2FromBool(V_BOOL(ps), &V_I2(pd)); - case VT_CY: return VarI2FromCy(V_CY(ps), &V_I2(pd)); - case VT_DECIMAL: return VarI2FromDec(&V_DECIMAL(ps), &V_I2(pd)); - case VT_DISPATCH: return VarI2FromDisp(V_DISPATCH(ps), lcid, &V_I2(pd)); - case VT_BSTR: return VarI2FromStr(V_BSTR(ps), lcid, dwFlags, &V_I2(pd)); - } - break; - - case VT_I4: - switch (vtFrom) - { - case VT_EMPTY: V_I4(pd) = 0; return S_OK; - case VT_I1: return VarI4FromI1(V_I1(ps), &V_I4(pd)); - case VT_I2: return VarI4FromI2(V_I2(ps), &V_I4(pd)); - case VT_UI1: return VarI4FromUI1(V_UI1(ps), &V_I4(pd)); - case VT_UI2: return VarI4FromUI2(V_UI2(ps), &V_I4(pd)); - case VT_UI4: - if (bIgnoreOverflow) - { - V_VT(pd) = VT_I4; - V_I4(pd) = V_I4(ps); - return S_OK; - } - return VarI4FromUI4(V_UI4(ps), &V_I4(pd)); - case VT_I8: return VarI4FromI8(V_I8(ps), &V_I4(pd)); - case VT_UI8: return VarI4FromUI8(V_UI8(ps), &V_I4(pd)); - case VT_R4: return VarI4FromR4(V_R4(ps), &V_I4(pd)); - case VT_R8: return VarI4FromR8(V_R8(ps), &V_I4(pd)); - case VT_DATE: return VarI4FromDate(V_DATE(ps), &V_I4(pd)); - case VT_BOOL: return VarI4FromBool(V_BOOL(ps), &V_I4(pd)); - case VT_CY: return VarI4FromCy(V_CY(ps), &V_I4(pd)); - case VT_DECIMAL: return VarI4FromDec(&V_DECIMAL(ps), &V_I4(pd)); - case VT_DISPATCH: return VarI4FromDisp(V_DISPATCH(ps), lcid, &V_I4(pd)); - case VT_BSTR: return VarI4FromStr(V_BSTR(ps), lcid, dwFlags, &V_I4(pd)); - } - break; - - case VT_UI1: - switch (vtFrom) - { - case VT_EMPTY: V_UI1(pd) = 0; return S_OK; - case VT_I1: return VarUI1FromI1(V_I1(ps), &V_UI1(pd)); - case VT_I2: return VarUI1FromI2(V_I2(ps), &V_UI1(pd)); - case VT_I4: return VarUI1FromI4(V_I4(ps), &V_UI1(pd)); - case VT_UI2: return VarUI1FromUI2(V_UI2(ps), &V_UI1(pd)); - case VT_UI4: return VarUI1FromUI4(V_UI4(ps), &V_UI1(pd)); - case VT_I8: return VarUI1FromI8(V_I8(ps), &V_UI1(pd)); - case VT_UI8: return VarUI1FromUI8(V_UI8(ps), &V_UI1(pd)); - case VT_R4: return VarUI1FromR4(V_R4(ps), &V_UI1(pd)); - case VT_R8: return VarUI1FromR8(V_R8(ps), &V_UI1(pd)); - case VT_DATE: return VarUI1FromDate(V_DATE(ps), &V_UI1(pd)); - case VT_BOOL: return VarUI1FromBool(V_BOOL(ps), &V_UI1(pd)); - case VT_CY: return VarUI1FromCy(V_CY(ps), &V_UI1(pd)); - case VT_DECIMAL: return VarUI1FromDec(&V_DECIMAL(ps), &V_UI1(pd)); - case VT_DISPATCH: return VarUI1FromDisp(V_DISPATCH(ps), lcid, &V_UI1(pd)); - case VT_BSTR: return VarUI1FromStr(V_BSTR(ps), lcid, dwFlags, &V_UI1(pd)); - } - break; - - case VT_UI2: - switch (vtFrom) - { - case VT_EMPTY: V_UI2(pd) = 0; return S_OK; - case VT_I1: return VarUI2FromI1(V_I1(ps), &V_UI2(pd)); - case VT_I2: return VarUI2FromI2(V_I2(ps), &V_UI2(pd)); - case VT_I4: return VarUI2FromI4(V_I4(ps), &V_UI2(pd)); - case VT_UI1: return VarUI2FromUI1(V_UI1(ps), &V_UI2(pd)); - case VT_UI4: return VarUI2FromUI4(V_UI4(ps), &V_UI2(pd)); - case VT_I8: return VarUI4FromI8(V_I8(ps), &V_UI4(pd)); - case VT_UI8: return VarUI4FromUI8(V_UI8(ps), &V_UI4(pd)); - case VT_R4: return VarUI2FromR4(V_R4(ps), &V_UI2(pd)); - case VT_R8: return VarUI2FromR8(V_R8(ps), &V_UI2(pd)); - case VT_DATE: return VarUI2FromDate(V_DATE(ps), &V_UI2(pd)); - case VT_BOOL: return VarUI2FromBool(V_BOOL(ps), &V_UI2(pd)); - case VT_CY: return VarUI2FromCy(V_CY(ps), &V_UI2(pd)); - case VT_DECIMAL: return VarUI2FromDec(&V_DECIMAL(ps), &V_UI2(pd)); - case VT_DISPATCH: return VarUI2FromDisp(V_DISPATCH(ps), lcid, &V_UI2(pd)); - case VT_BSTR: return VarUI2FromStr(V_BSTR(ps), lcid, dwFlags, &V_UI2(pd)); - } - break; - - case VT_UI4: - switch (vtFrom) - { - case VT_EMPTY: V_UI4(pd) = 0; return S_OK; - case VT_I1: return VarUI4FromI1(V_I1(ps), &V_UI4(pd)); - case VT_I2: return VarUI4FromI2(V_I2(ps), &V_UI4(pd)); - case VT_I4: return VarUI4FromI4(V_I4(ps), &V_UI4(pd)); - case VT_UI1: return VarUI4FromUI1(V_UI1(ps), &V_UI4(pd)); - case VT_UI2: return VarUI4FromUI2(V_UI2(ps), &V_UI4(pd)); - case VT_I8: return VarUI4FromI8(V_I8(ps), &V_UI4(pd)); - case VT_UI8: return VarUI4FromUI8(V_UI8(ps), &V_UI4(pd)); - case VT_R4: return VarUI4FromR4(V_R4(ps), &V_UI4(pd)); - case VT_R8: return VarUI4FromR8(V_R8(ps), &V_UI4(pd)); - case VT_DATE: return VarUI4FromDate(V_DATE(ps), &V_UI4(pd)); - case VT_BOOL: return VarUI4FromBool(V_BOOL(ps), &V_UI4(pd)); - case VT_CY: return VarUI4FromCy(V_CY(ps), &V_UI4(pd)); - case VT_DECIMAL: return VarUI4FromDec(&V_DECIMAL(ps), &V_UI4(pd)); - case VT_DISPATCH: return VarUI4FromDisp(V_DISPATCH(ps), lcid, &V_UI4(pd)); - case VT_BSTR: return VarUI4FromStr(V_BSTR(ps), lcid, dwFlags, &V_UI4(pd)); - } - break; - - case VT_UI8: - switch (vtFrom) - { - case VT_EMPTY: V_UI8(pd) = 0; return S_OK; - case VT_I4: if (V_I4(ps) < 0) return DISP_E_OVERFLOW; V_UI8(pd) = V_I4(ps); return S_OK; - case VT_I1: return VarUI8FromI1(V_I1(ps), &V_UI8(pd)); - case VT_I2: return VarUI8FromI2(V_I2(ps), &V_UI8(pd)); - case VT_UI1: return VarUI8FromUI1(V_UI1(ps), &V_UI8(pd)); - case VT_UI2: return VarUI8FromUI2(V_UI2(ps), &V_UI8(pd)); - case VT_UI4: return VarUI8FromUI4(V_UI4(ps), &V_UI8(pd)); - case VT_I8: return VarUI8FromI8(V_I8(ps), &V_UI8(pd)); - case VT_R4: return VarUI8FromR4(V_R4(ps), &V_UI8(pd)); - case VT_R8: return VarUI8FromR8(V_R8(ps), &V_UI8(pd)); - case VT_DATE: return VarUI8FromDate(V_DATE(ps), &V_UI8(pd)); - case VT_BOOL: return VarUI8FromBool(V_BOOL(ps), &V_UI8(pd)); - case VT_CY: return VarUI8FromCy(V_CY(ps), &V_UI8(pd)); - case VT_DECIMAL: return VarUI8FromDec(&V_DECIMAL(ps), &V_UI8(pd)); - case VT_DISPATCH: return VarUI8FromDisp(V_DISPATCH(ps), lcid, &V_UI8(pd)); - case VT_BSTR: return VarUI8FromStr(V_BSTR(ps), lcid, dwFlags, &V_UI8(pd)); - } - break; - - case VT_I8: - switch (vtFrom) - { - case VT_EMPTY: V_I8(pd) = 0; return S_OK; - case VT_I4: V_I8(pd) = V_I4(ps); return S_OK; - case VT_I1: return VarI8FromI1(V_I1(ps), &V_I8(pd)); - case VT_I2: return VarI8FromI2(V_I2(ps), &V_I8(pd)); - case VT_UI1: return VarI8FromUI1(V_UI1(ps), &V_I8(pd)); - case VT_UI2: return VarI8FromUI2(V_UI2(ps), &V_I8(pd)); - case VT_UI4: return VarI8FromUI4(V_UI4(ps), &V_I8(pd)); - case VT_UI8: return VarI8FromUI8(V_I8(ps), &V_I8(pd)); - case VT_R4: return VarI8FromR4(V_R4(ps), &V_I8(pd)); - case VT_R8: return VarI8FromR8(V_R8(ps), &V_I8(pd)); - case VT_DATE: return VarI8FromDate(V_DATE(ps), &V_I8(pd)); - case VT_BOOL: return VarI8FromBool(V_BOOL(ps), &V_I8(pd)); - case VT_CY: return VarI8FromCy(V_CY(ps), &V_I8(pd)); - case VT_DECIMAL: return VarI8FromDec(&V_DECIMAL(ps), &V_I8(pd)); - case VT_DISPATCH: return VarI8FromDisp(V_DISPATCH(ps), lcid, &V_I8(pd)); - case VT_BSTR: return VarI8FromStr(V_BSTR(ps), lcid, dwFlags, &V_I8(pd)); - } - break; - - case VT_R4: - switch (vtFrom) - { - case VT_EMPTY: V_R4(pd) = 0.0f; return S_OK; - case VT_I1: return VarR4FromI1(V_I1(ps), &V_R4(pd)); - case VT_I2: return VarR4FromI2(V_I2(ps), &V_R4(pd)); - case VT_I4: return VarR4FromI4(V_I4(ps), &V_R4(pd)); - case VT_UI1: return VarR4FromUI1(V_UI1(ps), &V_R4(pd)); - case VT_UI2: return VarR4FromUI2(V_UI2(ps), &V_R4(pd)); - case VT_UI4: return VarR4FromUI4(V_UI4(ps), &V_R4(pd)); - case VT_I8: return VarR4FromI8(V_I8(ps), &V_R4(pd)); - case VT_UI8: return VarR4FromUI8(V_UI8(ps), &V_R4(pd)); - case VT_R8: return VarR4FromR8(V_R8(ps), &V_R4(pd)); - case VT_DATE: return VarR4FromDate(V_DATE(ps), &V_R4(pd)); - case VT_BOOL: return VarR4FromBool(V_BOOL(ps), &V_R4(pd)); - case VT_CY: return VarR4FromCy(V_CY(ps), &V_R4(pd)); - case VT_DECIMAL: return VarR4FromDec(&V_DECIMAL(ps), &V_R4(pd)); - case VT_DISPATCH: return VarR4FromDisp(V_DISPATCH(ps), lcid, &V_R4(pd)); - case VT_BSTR: return VarR4FromStr(V_BSTR(ps), lcid, dwFlags, &V_R4(pd)); - } - break; - - case VT_R8: - switch (vtFrom) - { - case VT_EMPTY: V_R8(pd) = 0.0; return S_OK; - case VT_I1: return VarR8FromI1(V_I1(ps), &V_R8(pd)); - case VT_I2: return VarR8FromI2(V_I2(ps), &V_R8(pd)); - case VT_I4: return VarR8FromI4(V_I4(ps), &V_R8(pd)); - case VT_UI1: return VarR8FromUI1(V_UI1(ps), &V_R8(pd)); - case VT_UI2: return VarR8FromUI2(V_UI2(ps), &V_R8(pd)); - case VT_UI4: return VarR8FromUI4(V_UI4(ps), &V_R8(pd)); - case VT_I8: return VarR8FromI8(V_I8(ps), &V_R8(pd)); - case VT_UI8: return VarR8FromUI8(V_UI8(ps), &V_R8(pd)); - case VT_R4: return VarR8FromR4(V_R4(ps), &V_R8(pd)); - case VT_DATE: return VarR8FromDate(V_DATE(ps), &V_R8(pd)); - case VT_BOOL: return VarR8FromBool(V_BOOL(ps), &V_R8(pd)); - case VT_CY: return VarR8FromCy(V_CY(ps), &V_R8(pd)); - case VT_DECIMAL: return VarR8FromDec(&V_DECIMAL(ps), &V_R8(pd)); - case VT_DISPATCH: return VarR8FromDisp(V_DISPATCH(ps), lcid, &V_R8(pd)); - case VT_BSTR: return VarR8FromStr(V_BSTR(ps), lcid, dwFlags, &V_R8(pd)); - } - break; - - case VT_DATE: - switch (vtFrom) - { - case VT_EMPTY: V_DATE(pd) = 0.0; return S_OK; - case VT_I1: return VarDateFromI1(V_I1(ps), &V_DATE(pd)); - case VT_I2: return VarDateFromI2(V_I2(ps), &V_DATE(pd)); - case VT_I4: return VarDateFromI4(V_I4(ps), &V_DATE(pd)); - case VT_UI1: return VarDateFromUI1(V_UI1(ps), &V_DATE(pd)); - case VT_UI2: return VarDateFromUI2(V_UI2(ps), &V_DATE(pd)); - case VT_UI4: return VarDateFromUI4(V_UI4(ps), &V_DATE(pd)); - case VT_I8: return VarDateFromI8(V_I8(ps), &V_DATE(pd)); - case VT_UI8: return VarDateFromUI8(V_UI8(ps), &V_DATE(pd)); - case VT_R4: return VarDateFromR4(V_R4(ps), &V_DATE(pd)); - case VT_R8: return VarDateFromR8(V_R8(ps), &V_DATE(pd)); - case VT_BOOL: return VarDateFromBool(V_BOOL(ps), &V_DATE(pd)); - case VT_CY: return VarDateFromCy(V_CY(ps), &V_DATE(pd)); - case VT_DECIMAL: return VarDateFromDec(&V_DECIMAL(ps), &V_DATE(pd)); - case VT_DISPATCH: return VarDateFromDisp(V_DISPATCH(ps), lcid, &V_DATE(pd)); - case VT_BSTR: return VarDateFromStr(V_BSTR(ps), lcid, dwFlags, &V_DATE(pd)); - } - break; - - case VT_BOOL: - switch (vtFrom) - { - case VT_EMPTY: V_BOOL(pd) = 0; return S_OK; - case VT_I1: return VarBoolFromI1(V_I1(ps), &V_BOOL(pd)); - case VT_I2: return VarBoolFromI2(V_I2(ps), &V_BOOL(pd)); - case VT_I4: return VarBoolFromI4(V_I4(ps), &V_BOOL(pd)); - case VT_UI1: return VarBoolFromUI1(V_UI1(ps), &V_BOOL(pd)); - case VT_UI2: return VarBoolFromUI2(V_UI2(ps), &V_BOOL(pd)); - case VT_UI4: return VarBoolFromUI4(V_UI4(ps), &V_BOOL(pd)); - case VT_I8: return VarBoolFromI8(V_I8(ps), &V_BOOL(pd)); - case VT_UI8: return VarBoolFromUI8(V_UI8(ps), &V_BOOL(pd)); - case VT_R4: return VarBoolFromR4(V_R4(ps), &V_BOOL(pd)); - case VT_R8: return VarBoolFromR8(V_R8(ps), &V_BOOL(pd)); - case VT_DATE: return VarBoolFromDate(V_DATE(ps), &V_BOOL(pd)); - case VT_CY: return VarBoolFromCy(V_CY(ps), &V_BOOL(pd)); - case VT_DECIMAL: return VarBoolFromDec(&V_DECIMAL(ps), &V_BOOL(pd)); - case VT_DISPATCH: return VarBoolFromDisp(V_DISPATCH(ps), lcid, &V_BOOL(pd)); - case VT_BSTR: return VarBoolFromStr(V_BSTR(ps), lcid, dwFlags, &V_BOOL(pd)); - } - break; - - case VT_BSTR: - switch (vtFrom) - { - case VT_EMPTY: - V_BSTR(pd) = SysAllocStringLen(NULL, 0); - return V_BSTR(pd) ? S_OK : E_OUTOFMEMORY; - case VT_BOOL: - if (wFlags & (VARIANT_ALPHABOOL|VARIANT_LOCALBOOL)) - return VarBstrFromBool(V_BOOL(ps), lcid, dwFlags, &V_BSTR(pd)); - return VarBstrFromI2(V_BOOL(ps), lcid, dwFlags, &V_BSTR(pd)); - case VT_I1: return VarBstrFromI1(V_I1(ps), lcid, dwFlags, &V_BSTR(pd)); - case VT_I2: return VarBstrFromI2(V_I2(ps), lcid, dwFlags, &V_BSTR(pd)); - case VT_I4: return VarBstrFromI4(V_I4(ps), lcid, dwFlags, &V_BSTR(pd)); - case VT_UI1: return VarBstrFromUI1(V_UI1(ps), lcid, dwFlags, &V_BSTR(pd)); - case VT_UI2: return VarBstrFromUI2(V_UI2(ps), lcid, dwFlags, &V_BSTR(pd)); - case VT_UI4: return VarBstrFromUI4(V_UI4(ps), lcid, dwFlags, &V_BSTR(pd)); - case VT_I8: return VarBstrFromI8(V_I8(ps), lcid, dwFlags, &V_BSTR(pd)); - case VT_UI8: return VarBstrFromUI8(V_UI8(ps), lcid, dwFlags, &V_BSTR(pd)); - case VT_R4: return VarBstrFromR4(V_R4(ps), lcid, dwFlags, &V_BSTR(pd)); - case VT_R8: return VarBstrFromR8(V_R8(ps), lcid, dwFlags, &V_BSTR(pd)); - case VT_DATE: return VarBstrFromDate(V_DATE(ps), lcid, dwFlags, &V_BSTR(pd)); - case VT_CY: return VarBstrFromCy(V_CY(ps), lcid, dwFlags, &V_BSTR(pd)); - case VT_DECIMAL: return VarBstrFromDec(&V_DECIMAL(ps), lcid, dwFlags, &V_BSTR(pd)); -/* case VT_DISPATCH: return VarBstrFromDisp(V_DISPATCH(ps), lcid, dwFlags, &V_BSTR(pd)); */ - } - break; - - case VT_CY: - switch (vtFrom) - { - case VT_EMPTY: V_CY(pd).int64 = 0; return S_OK; - case VT_I1: return VarCyFromI1(V_I1(ps), &V_CY(pd)); - case VT_I2: return VarCyFromI2(V_I2(ps), &V_CY(pd)); - case VT_I4: return VarCyFromI4(V_I4(ps), &V_CY(pd)); - case VT_UI1: return VarCyFromUI1(V_UI1(ps), &V_CY(pd)); - case VT_UI2: return VarCyFromUI2(V_UI2(ps), &V_CY(pd)); - case VT_UI4: return VarCyFromUI4(V_UI4(ps), &V_CY(pd)); - case VT_I8: return VarCyFromI8(V_I8(ps), &V_CY(pd)); - case VT_UI8: return VarCyFromUI8(V_UI8(ps), &V_CY(pd)); - case VT_R4: return VarCyFromR4(V_R4(ps), &V_CY(pd)); - case VT_R8: return VarCyFromR8(V_R8(ps), &V_CY(pd)); - case VT_DATE: return VarCyFromDate(V_DATE(ps), &V_CY(pd)); - case VT_BOOL: return VarCyFromBool(V_BOOL(ps), &V_CY(pd)); - case VT_DECIMAL: return VarCyFromDec(&V_DECIMAL(ps), &V_CY(pd)); - case VT_DISPATCH: return VarCyFromDisp(V_DISPATCH(ps), lcid, &V_CY(pd)); - case VT_BSTR: return VarCyFromStr(V_BSTR(ps), lcid, dwFlags, &V_CY(pd)); - } - break; - - case VT_DECIMAL: - switch (vtFrom) - { - case VT_EMPTY: - case VT_BOOL: - DEC_SIGNSCALE(&V_DECIMAL(pd)) = SIGNSCALE(DECIMAL_POS,0); - DEC_HI32(&V_DECIMAL(pd)) = 0; - DEC_MID32(&V_DECIMAL(pd)) = 0; - /* VarDecFromBool() coerces to -1/0, ChangeTypeEx() coerces to 1/0. - * VT_NULL and VT_EMPTY always give a 0 value. - */ - DEC_LO32(&V_DECIMAL(pd)) = vtFrom == VT_BOOL && V_BOOL(ps) ? 1 : 0; - return S_OK; - case VT_I1: return VarDecFromI1(V_I1(ps), &V_DECIMAL(pd)); - case VT_I2: return VarDecFromI2(V_I2(ps), &V_DECIMAL(pd)); - case VT_I4: return VarDecFromI4(V_I4(ps), &V_DECIMAL(pd)); - case VT_UI1: return VarDecFromUI1(V_UI1(ps), &V_DECIMAL(pd)); - case VT_UI2: return VarDecFromUI2(V_UI2(ps), &V_DECIMAL(pd)); - case VT_UI4: return VarDecFromUI4(V_UI4(ps), &V_DECIMAL(pd)); - case VT_I8: return VarDecFromI8(V_I8(ps), &V_DECIMAL(pd)); - case VT_UI8: return VarDecFromUI8(V_UI8(ps), &V_DECIMAL(pd)); - case VT_R4: return VarDecFromR4(V_R4(ps), &V_DECIMAL(pd)); - case VT_R8: return VarDecFromR8(V_R8(ps), &V_DECIMAL(pd)); - case VT_DATE: return VarDecFromDate(V_DATE(ps), &V_DECIMAL(pd)); - case VT_CY: return VarDecFromCy(V_CY(ps), &V_DECIMAL(pd)); - case VT_DISPATCH: return VarDecFromDisp(V_DISPATCH(ps), lcid, &V_DECIMAL(pd)); - case VT_BSTR: return VarDecFromStr(V_BSTR(ps), lcid, dwFlags, &V_DECIMAL(pd)); - } - break; - - case VT_UNKNOWN: - switch (vtFrom) - { - case VT_DISPATCH: - if (V_DISPATCH(ps) == NULL) - V_UNKNOWN(pd) = NULL; - else - res = IDispatch_QueryInterface(V_DISPATCH(ps), &IID_IUnknown, (LPVOID*)&V_UNKNOWN(pd)); - break; - } - break; - - case VT_DISPATCH: - switch (vtFrom) - { - case VT_UNKNOWN: - if (V_UNKNOWN(ps) == NULL) - V_DISPATCH(pd) = NULL; - else - res = IUnknown_QueryInterface(V_UNKNOWN(ps), &IID_IDispatch, (LPVOID*)&V_DISPATCH(pd)); - break; - } - break; - - case VT_RECORD: - break; - } - return res; -} - -/* Coerce to/from an array */ -static inline HRESULT VARIANT_CoerceArray(VARIANTARG* pd, VARIANTARG* ps, VARTYPE vt) -{ - if (vt == VT_BSTR && V_VT(ps) == (VT_ARRAY|VT_UI1)) - return BstrFromVector(V_ARRAY(ps), &V_BSTR(pd)); - - if (V_VT(ps) == VT_BSTR && vt == (VT_ARRAY|VT_UI1)) - return VectorFromBstr(V_BSTR(ps), &V_ARRAY(ps)); - - if (V_VT(ps) == vt) - return SafeArrayCopy(V_ARRAY(ps), &V_ARRAY(pd)); - - return DISP_E_TYPEMISMATCH; -} - -/****************************************************************************** - * Check if a variants type is valid. - */ -static inline HRESULT VARIANT_ValidateType(VARTYPE vt) -{ - VARTYPE vtExtra = vt & VT_EXTRA_TYPE; - - vt &= VT_TYPEMASK; - - if (!(vtExtra & (VT_VECTOR|VT_RESERVED))) - { - if (vt < VT_VOID || vt == VT_RECORD || vt == VT_CLSID) - { - if ((vtExtra & (VT_BYREF|VT_ARRAY)) && vt <= VT_NULL) - return DISP_E_BADVARTYPE; - if (vt != (VARTYPE)15) - return S_OK; - } - } - return DISP_E_BADVARTYPE; -} - -/****************************************************************************** - * VariantInit [OLEAUT32.8] - * - * Initialise a variant. - * - * PARAMS - * pVarg [O] Variant to initialise - * - * RETURNS - * Nothing. - * - * NOTES - * This function simply sets the type of the variant to VT_EMPTY. It does not - * free any existing value, use VariantClear() for that. - */ -void WINAPI VariantInit(VARIANTARG* pVarg) -{ - TRACE("(%p)\n", pVarg); - - V_VT(pVarg) = VT_EMPTY; /* Native doesn't set any other fields */ -} - -/****************************************************************************** - * VariantClear [OLEAUT32.9] - * - * Clear a variant. - * - * PARAMS - * pVarg [I/O] Variant to clear - * - * RETURNS - * Success: S_OK. Any previous value in pVarg is freed and its type is set to VT_EMPTY. - * Failure: DISP_E_BADVARTYPE, if the variant is a not a valid variant type. - */ -HRESULT WINAPI VariantClear(VARIANTARG* pVarg) -{ - HRESULT hres = S_OK; - - TRACE("(%p->(%s%s))\n", pVarg, debugstr_VT(pVarg), debugstr_VF(pVarg)); - - hres = VARIANT_ValidateType(V_VT(pVarg)); - - if (SUCCEEDED(hres)) - { - if (!V_ISBYREF(pVarg)) - { - if (V_ISARRAY(pVarg) || V_VT(pVarg) == VT_SAFEARRAY) - { - if (V_ARRAY(pVarg)) - hres = SafeArrayDestroy(V_ARRAY(pVarg)); - } - else if (V_VT(pVarg) == VT_BSTR) - { - if (V_BSTR(pVarg)) - SysFreeString(V_BSTR(pVarg)); - } - else if (V_VT(pVarg) == VT_RECORD) - { - struct __tagBRECORD* pBr = &V_UNION(pVarg,brecVal); - if (pBr->pRecInfo) - { - IRecordInfo_RecordClear(pBr->pRecInfo, pBr->pvRecord); - IRecordInfo_Release(pBr->pRecInfo); - } - } - else if (V_VT(pVarg) == VT_DISPATCH || - V_VT(pVarg) == VT_UNKNOWN) - { - if (V_UNKNOWN(pVarg)) - IUnknown_Release(V_UNKNOWN(pVarg)); - } - else if (V_VT(pVarg) == VT_VARIANT) - { - if (V_VARIANTREF(pVarg)) - VariantClear(V_VARIANTREF(pVarg)); - } - } - V_VT(pVarg) = VT_EMPTY; - } - return hres; -} - -/****************************************************************************** - * Copy an IRecordInfo object contained in a variant. - */ -static HRESULT VARIANT_CopyIRecordInfo(struct __tagBRECORD* pBr) -{ - HRESULT hres = S_OK; - - if (pBr->pRecInfo) - { - ULONG ulSize; - - hres = IRecordInfo_GetSize(pBr->pRecInfo, &ulSize); - if (SUCCEEDED(hres)) - { - PVOID pvRecord = HeapAlloc(GetProcessHeap(), 0, ulSize); - if (!pvRecord) - hres = E_OUTOFMEMORY; - else - { - memcpy(pvRecord, pBr->pvRecord, ulSize); - pBr->pvRecord = pvRecord; - - hres = IRecordInfo_RecordCopy(pBr->pRecInfo, pvRecord, pvRecord); - if (SUCCEEDED(hres)) - IRecordInfo_AddRef(pBr->pRecInfo); - } - } - } - else if (pBr->pvRecord) - hres = E_INVALIDARG; - return hres; -} - -/****************************************************************************** - * VariantCopy [OLEAUT32.10] - * - * Copy a variant. - * - * PARAMS - * pvargDest [O] Destination for copy - * pvargSrc [I] Source variant to copy - * - * RETURNS - * Success: S_OK. pvargDest contains a copy of pvargSrc. - * Failure: DISP_E_BADVARTYPE, if either variant has an invalid type. - * E_OUTOFMEMORY, if memory cannot be allocated. Otherwise an - * HRESULT error code from SafeArrayCopy(), IRecordInfo_GetSize(), - * or IRecordInfo_RecordCopy(), depending on the type of pvargSrc. - * - * NOTES - * - If pvargSrc == pvargDest, this function does nothing, and succeeds if - * pvargSrc is valid. Otherwise, pvargDest is always cleared using - * VariantClear() before pvargSrc is copied to it. If clearing pvargDest - * fails, so does this function. - * - VT_CLSID is a valid type type for pvargSrc, but not for pvargDest. - * - For by-value non-intrinsic types, a deep copy is made, i.e. The whole value - * is copied rather than just any pointers to it. - * - For by-value object types the object pointer is copied and the objects - * reference count increased using IUnknown_AddRef(). - * - For all by-reference types, only the referencing pointer is copied. - */ -HRESULT WINAPI VariantCopy(VARIANTARG* pvargDest, VARIANTARG* pvargSrc) -{ - HRESULT hres = S_OK; - - TRACE("(%p->(%s%s),%p->(%s%s))\n", pvargDest, debugstr_VT(pvargDest), - debugstr_VF(pvargDest), pvargSrc, debugstr_VT(pvargSrc), - debugstr_VF(pvargSrc)); - - if (V_TYPE(pvargSrc) == VT_CLSID || /* VT_CLSID is a special case */ - FAILED(VARIANT_ValidateType(V_VT(pvargSrc)))) - return DISP_E_BADVARTYPE; - - if (pvargSrc != pvargDest && - SUCCEEDED(hres = VariantClear(pvargDest))) - { - *pvargDest = *pvargSrc; /* Shallow copy the value */ - - if (!V_ISBYREF(pvargSrc)) - { - if (V_ISARRAY(pvargSrc)) - { - if (V_ARRAY(pvargSrc)) - hres = SafeArrayCopy(V_ARRAY(pvargSrc), &V_ARRAY(pvargDest)); - } - else if (V_VT(pvargSrc) == VT_BSTR) - { - if (V_BSTR(pvargSrc)) - { - V_BSTR(pvargDest) = SysAllocStringByteLen((char*)V_BSTR(pvargSrc), SysStringByteLen(V_BSTR(pvargSrc))); - if (!V_BSTR(pvargDest)) - { - TRACE("!V_BSTR(pvargDest), SysAllocStringByteLen() failed to allocate %d bytes\n", SysStringByteLen(V_BSTR(pvargSrc))); - hres = E_OUTOFMEMORY; - } - } - } - else if (V_VT(pvargSrc) == VT_RECORD) - { - hres = VARIANT_CopyIRecordInfo(&V_UNION(pvargDest,brecVal)); - } - else if (V_VT(pvargSrc) == VT_DISPATCH || - V_VT(pvargSrc) == VT_UNKNOWN) - { - if (V_UNKNOWN(pvargSrc)) - IUnknown_AddRef(V_UNKNOWN(pvargSrc)); - } - } - } - return hres; -} - -/* Return the byte size of a variants data */ -static inline size_t VARIANT_DataSize(const VARIANT* pv) -{ - switch (V_TYPE(pv)) - { - case VT_I1: - case VT_UI1: return sizeof(BYTE); - case VT_I2: - case VT_UI2: return sizeof(SHORT); - case VT_INT: - case VT_UINT: - case VT_I4: - case VT_UI4: return sizeof(LONG); - case VT_I8: - case VT_UI8: return sizeof(LONGLONG); - case VT_R4: return sizeof(float); - case VT_R8: return sizeof(double); - case VT_DATE: return sizeof(DATE); - case VT_BOOL: return sizeof(VARIANT_BOOL); - case VT_DISPATCH: - case VT_UNKNOWN: - case VT_BSTR: return sizeof(void*); - case VT_CY: return sizeof(CY); - case VT_ERROR: return sizeof(SCODE); - } - TRACE("Shouldn't be called for vt %s%s!\n", debugstr_VT(pv), debugstr_VF(pv)); - return 0; -} - -/****************************************************************************** - * VariantCopyInd [OLEAUT32.11] - * - * Copy a variant, dereferencing it it is by-reference. - * - * PARAMS - * pvargDest [O] Destination for copy - * pvargSrc [I] Source variant to copy - * - * RETURNS - * Success: S_OK. pvargDest contains a copy of pvargSrc. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * Failure: DISP_E_BADVARTYPE, if either variant has an invalid by-value type. - * E_INVALIDARG, if pvargSrc is an invalid by-reference type. - * E_OUTOFMEMORY, if memory cannot be allocated. Otherwise an - * HRESULT error code from SafeArrayCopy(), IRecordInfo_GetSize(), - * or IRecordInfo_RecordCopy(), depending on the type of pvargSrc. - * - * NOTES - * - If pvargSrc is by-value, this function behaves exactly as VariantCopy(). - * - If pvargSrc is by-reference, the value copied to pvargDest is the pointed-to - * value. - * - if pvargSrc == pvargDest, this function dereferences in place. Otherwise, - * pvargDest is always cleared using VariantClear() before pvargSrc is copied - * to it. If clearing pvargDest fails, so does this function. - */ -HRESULT WINAPI VariantCopyInd(VARIANT* pvargDest, VARIANTARG* pvargSrc) -{ - VARIANTARG vTmp, *pSrc = pvargSrc; - VARTYPE vt; - HRESULT hres = S_OK; - - TRACE("(%p->(%s%s),%p->(%s%s))\n", pvargDest, debugstr_VT(pvargDest), - debugstr_VF(pvargDest), pvargSrc, debugstr_VT(pvargSrc), - debugstr_VF(pvargSrc)); - - if (!V_ISBYREF(pvargSrc)) - return VariantCopy(pvargDest, pvargSrc); - - /* Argument checking is more lax than VariantCopy()... */ - vt = V_TYPE(pvargSrc); - if (V_ISARRAY(pvargSrc) || - (vt > VT_NULL && vt != (VARTYPE)15 && vt < VT_VOID && - !(V_VT(pvargSrc) & (VT_VECTOR|VT_RESERVED)))) - { - /* OK */ - } - else - return E_INVALIDARG; /* ...And the return value for invalid types differs too */ - - if (pvargSrc == pvargDest) - { - /* In place copy. Use a shallow copy of pvargSrc & init pvargDest. - * This avoids an expensive VariantCopy() call - e.g. SafeArrayCopy(). - */ - vTmp = *pvargSrc; - pSrc = &vTmp; - V_VT(pvargDest) = VT_EMPTY; - } - else - { - /* Copy into another variant. Free the variant in pvargDest */ - if (FAILED(hres = VariantClear(pvargDest))) - { - TRACE("VariantClear() of destination failed\n"); - return hres; - } - } - - if (V_ISARRAY(pSrc)) - { - /* Native doesn't check that *V_ARRAYREF(pSrc) is valid */ - hres = SafeArrayCopy(*V_ARRAYREF(pSrc), &V_ARRAY(pvargDest)); - } - else if (V_VT(pSrc) == (VT_BSTR|VT_BYREF)) - { - /* Native doesn't check that *V_BSTRREF(pSrc) is valid */ - V_BSTR(pvargDest) = SysAllocStringByteLen((char*)*V_BSTRREF(pSrc), SysStringByteLen(*V_BSTRREF(pSrc))); - } - else if (V_VT(pSrc) == (VT_RECORD|VT_BYREF)) - { - V_UNION(pvargDest,brecVal) = V_UNION(pvargSrc,brecVal); - hres = VARIANT_CopyIRecordInfo(&V_UNION(pvargDest,brecVal)); - } - else if (V_VT(pSrc) == (VT_DISPATCH|VT_BYREF) || - V_VT(pSrc) == (VT_UNKNOWN|VT_BYREF)) - { - /* Native doesn't check that *V_UNKNOWNREF(pSrc) is valid */ - V_UNKNOWN(pvargDest) = *V_UNKNOWNREF(pSrc); - if (*V_UNKNOWNREF(pSrc)) - IUnknown_AddRef(*V_UNKNOWNREF(pSrc)); - } - else if (V_VT(pSrc) == (VT_VARIANT|VT_BYREF)) - { - /* Native doesn't check that *V_VARIANTREF(pSrc) is valid */ - if (V_VT(V_VARIANTREF(pSrc)) == (VT_VARIANT|VT_BYREF)) - hres = E_INVALIDARG; /* Don't dereference more than one level */ - else - hres = VariantCopyInd(pvargDest, V_VARIANTREF(pSrc)); - - /* Use the dereferenced variants type value, not VT_VARIANT */ - goto VariantCopyInd_Return; - } - else if (V_VT(pSrc) == (VT_DECIMAL|VT_BYREF)) - { - memcpy(&DEC_SCALE(&V_DECIMAL(pvargDest)), &DEC_SCALE(V_DECIMALREF(pSrc)), - sizeof(DECIMAL) - sizeof(USHORT)); - } - else - { - /* Copy the pointed to data into this variant */ - memcpy(&V_BYREF(pvargDest), V_BYREF(pSrc), VARIANT_DataSize(pSrc)); - } - - V_VT(pvargDest) = V_VT(pSrc) & ~VT_BYREF; - -VariantCopyInd_Return: - - if (pSrc != pvargSrc) - VariantClear(pSrc); - - TRACE("returning 0x%08lx, %p->(%s%s)\n", hres, pvargDest, - debugstr_VT(pvargDest), debugstr_VF(pvargDest)); - return hres; -} - -/****************************************************************************** - * VariantChangeType [OLEAUT32.12] - * - * Change the type of a variant. - * - * PARAMS - * pvargDest [O] Destination for the converted variant - * pvargSrc [O] Source variant to change the type of - * wFlags [I] VARIANT_ flags from "oleauto.h" - * vt [I] Variant type to change pvargSrc into - * - * RETURNS - * Success: S_OK. pvargDest contains the converted value. - * Failure: An HRESULT error code describing the failure. - * - * NOTES - * The LCID used for the conversion is LOCALE_USER_DEFAULT. - * See VariantChangeTypeEx. - */ -HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc, - USHORT wFlags, VARTYPE vt) -{ - return VariantChangeTypeEx( pvargDest, pvargSrc, LOCALE_USER_DEFAULT, wFlags, vt ); -} - -/****************************************************************************** - * VariantChangeTypeEx [OLEAUT32.147] - * - * Change the type of a variant. - * - * PARAMS - * pvargDest [O] Destination for the converted variant - * pvargSrc [O] Source variant to change the type of - * lcid [I] LCID for the conversion - * wFlags [I] VARIANT_ flags from "oleauto.h" - * vt [I] Variant type to change pvargSrc into - * - * RETURNS - * Success: S_OK. pvargDest contains the converted value. - * Failure: An HRESULT error code describing the failure. - * - * NOTES - * pvargDest and pvargSrc can point to the same variant to perform an in-place - * conversion. If the conversion is successful, pvargSrc will be freed. - */ -HRESULT WINAPI VariantChangeTypeEx(VARIANTARG* pvargDest, VARIANTARG* pvargSrc, - LCID lcid, USHORT wFlags, VARTYPE vt) -{ - HRESULT res = S_OK; - - TRACE("(%p->(%s%s),%p->(%s%s),0x%08lx,0x%04x,%s%s)\n", pvargDest, - debugstr_VT(pvargDest), debugstr_VF(pvargDest), pvargSrc, - debugstr_VT(pvargSrc), debugstr_VF(pvargSrc), lcid, wFlags, - debugstr_vt(vt), debugstr_vf(vt)); - - if (vt == VT_CLSID) - res = DISP_E_BADVARTYPE; - else - { - res = VARIANT_ValidateType(V_VT(pvargSrc)); - - if (SUCCEEDED(res)) - { - res = VARIANT_ValidateType(vt); - - if (SUCCEEDED(res)) - { - VARIANTARG vTmp, vSrcDeref; - - if(V_ISBYREF(pvargSrc) && !V_BYREF(pvargSrc)) - res = DISP_E_TYPEMISMATCH; - else - { - V_VT(&vTmp) = VT_EMPTY; - V_VT(&vSrcDeref) = VT_EMPTY; - VariantClear(&vTmp); - VariantClear(&vSrcDeref); - } - - if (SUCCEEDED(res)) - { - res = VariantCopyInd(&vSrcDeref, pvargSrc); - if (SUCCEEDED(res)) - { - if (V_ISARRAY(&vSrcDeref) || (vt & VT_ARRAY)) - res = VARIANT_CoerceArray(&vTmp, &vSrcDeref, vt); - else - res = VARIANT_Coerce(&vTmp, lcid, wFlags, &vSrcDeref, vt); - - if (SUCCEEDED(res)) { - V_VT(&vTmp) = vt; - VariantCopy(pvargDest, &vTmp); - } - VariantClear(&vTmp); - VariantClear(&vSrcDeref); - } - } - } - } - } - - TRACE("returning 0x%08lx, %p->(%s%s)\n", res, pvargDest, - debugstr_VT(pvargDest), debugstr_VF(pvargDest)); - return res; -} - -/* Date Conversions */ - -#define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0))) - -/* Convert a VT_DATE value to a Julian Date */ -static inline int VARIANT_JulianFromDate(int dateIn) -{ - int julianDays = dateIn; - - julianDays -= DATE_MIN; /* Convert to + days from 1 Jan 100 AD */ - julianDays += 1757585; /* Convert to + days from 23 Nov 4713 BC (Julian) */ - return julianDays; -} - -/* Convert a Julian Date to a VT_DATE value */ -static inline int VARIANT_DateFromJulian(int dateIn) -{ - int julianDays = dateIn; - - julianDays -= 1757585; /* Convert to + days from 1 Jan 100 AD */ - julianDays += DATE_MIN; /* Convert to +/- days from 1 Jan 1899 AD */ - return julianDays; -} - -/* Convert a Julian date to Day/Month/Year - from PostgreSQL */ -static inline void VARIANT_DMYFromJulian(int jd, USHORT *year, USHORT *month, USHORT *day) -{ - int j, i, l, n; - - l = jd + 68569; - n = l * 4 / 146097; - l -= (n * 146097 + 3) / 4; - i = (4000 * (l + 1)) / 1461001; - l += 31 - (i * 1461) / 4; - j = (l * 80) / 2447; - *day = l - (j * 2447) / 80; - l = j / 11; - *month = (j + 2) - (12 * l); - *year = 100 * (n - 49) + i + l; -} - -/* Convert Day/Month/Year to a Julian date - from PostgreSQL */ -static inline double VARIANT_JulianFromDMY(USHORT year, USHORT month, USHORT day) -{ - int m12 = (month - 14) / 12; - - return ((1461 * (year + 4800 + m12)) / 4 + (367 * (month - 2 - 12 * m12)) / 12 - - (3 * ((year + 4900 + m12) / 100)) / 4 + day - 32075); -} - -/* Macros for accessing DOS format date/time fields */ -#define DOS_YEAR(x) (1980 + (x >> 9)) -#define DOS_MONTH(x) ((x >> 5) & 0xf) -#define DOS_DAY(x) (x & 0x1f) -#define DOS_HOUR(x) (x >> 11) -#define DOS_MINUTE(x) ((x >> 5) & 0x3f) -#define DOS_SECOND(x) ((x & 0x1f) << 1) -/* Create a DOS format date/time */ -#define DOS_DATE(d,m,y) (d | (m << 5) | ((y-1980) << 9)) -#define DOS_TIME(h,m,s) ((s >> 1) | (m << 5) | (h << 11)) - -/* Roll a date forwards or backwards to correct it */ -static HRESULT VARIANT_RollUdate(UDATE *lpUd) -{ - static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - - TRACE("Raw date: %d/%d/%d %d:%d:%d\n", lpUd->st.wDay, lpUd->st.wMonth, - lpUd->st.wYear, lpUd->st.wHour, lpUd->st.wMinute, lpUd->st.wSecond); - - /* Years < 100 are treated as 1900 + year */ - if (lpUd->st.wYear < 100) - lpUd->st.wYear += 1900; - - if (!lpUd->st.wMonth) - { - /* Roll back to December of the previous year */ - lpUd->st.wMonth = 12; - lpUd->st.wYear--; - } - else while (lpUd->st.wMonth > 12) - { - /* Roll forward the correct number of months */ - lpUd->st.wYear++; - lpUd->st.wMonth -= 12; - } - - if (lpUd->st.wYear > 9999 || lpUd->st.wHour > 23 || - lpUd->st.wMinute > 59 || lpUd->st.wSecond > 59) - return E_INVALIDARG; /* Invalid values */ - - if (!lpUd->st.wDay) - { - /* Roll back the date one day */ - if (lpUd->st.wMonth == 1) - { - /* Roll back to December 31 of the previous year */ - lpUd->st.wDay = 31; - lpUd->st.wMonth = 12; - lpUd->st.wYear--; - } - else - { - lpUd->st.wMonth--; /* Previous month */ - if (lpUd->st.wMonth == 2 && IsLeapYear(lpUd->st.wYear)) - lpUd->st.wDay = 29; /* Februaury has 29 days on leap years */ - else - lpUd->st.wDay = days[lpUd->st.wMonth]; /* Last day of the month */ - } - } - else if (lpUd->st.wDay > 28) - { - int rollForward = 0; - - /* Possibly need to roll the date forward */ - if (lpUd->st.wMonth == 2 && IsLeapYear(lpUd->st.wYear)) - rollForward = lpUd->st.wDay - 29; /* Februaury has 29 days on leap years */ - else - rollForward = lpUd->st.wDay - days[lpUd->st.wMonth]; - - if (rollForward > 0) - { - lpUd->st.wDay = rollForward; - lpUd->st.wMonth++; - if (lpUd->st.wMonth > 12) - { - lpUd->st.wMonth = 1; /* Roll forward into January of the next year */ - lpUd->st.wYear++; - } - } - } - TRACE("Rolled date: %d/%d/%d %d:%d:%d\n", lpUd->st.wDay, lpUd->st.wMonth, - lpUd->st.wYear, lpUd->st.wHour, lpUd->st.wMinute, lpUd->st.wSecond); - return S_OK; -} - -/********************************************************************** - * DosDateTimeToVariantTime [OLEAUT32.14] - * - * Convert a Dos format date and time into variant VT_DATE format. - * - * PARAMS - * wDosDate [I] Dos format date - * wDosTime [I] Dos format time - * pDateOut [O] Destination for VT_DATE format - * - * RETURNS - * Success: TRUE. pDateOut contains the converted time. - * Failure: FALSE, if wDosDate or wDosTime are invalid (see notes). - * - * NOTES - * - Dos format dates can only hold dates from 1-Jan-1980 to 31-Dec-2099. - * - Dos format times are accurate to only 2 second precision. - * - The format of a Dos Date is: - *| Bits Values Meaning - *| ---- ------ ------- - *| 0-4 1-31 Day of the week. 0 rolls back one day. A value greater than - *| the days in the month rolls forward the extra days. - *| 5-8 1-12 Month of the year. 0 rolls back to December of the previous - *| year. 13-15 are invalid. - *| 9-15 0-119 Year based from 1980 (Max 2099). 120-127 are invalid. - * - The format of a Dos Time is: - *| Bits Values Meaning - *| ---- ------ ------- - *| 0-4 0-29 Seconds/2. 30 and 31 are invalid. - *| 5-10 0-59 Minutes. 60-63 are invalid. - *| 11-15 0-23 Hours (24 hour clock). 24-32 are invalid. - */ -INT WINAPI DosDateTimeToVariantTime(USHORT wDosDate, USHORT wDosTime, - double *pDateOut) -{ - UDATE ud; - - TRACE("(0x%x(%d/%d/%d),0x%x(%d:%d:%d),%p)\n", - wDosDate, DOS_YEAR(wDosDate), DOS_MONTH(wDosDate), DOS_DAY(wDosDate), - wDosTime, DOS_HOUR(wDosTime), DOS_MINUTE(wDosTime), DOS_SECOND(wDosTime), - pDateOut); - - ud.st.wYear = DOS_YEAR(wDosDate); - ud.st.wMonth = DOS_MONTH(wDosDate); - if (ud.st.wYear > 2099 || ud.st.wMonth > 12) - return FALSE; - ud.st.wDay = DOS_DAY(wDosDate); - ud.st.wHour = DOS_HOUR(wDosTime); - ud.st.wMinute = DOS_MINUTE(wDosTime); - ud.st.wSecond = DOS_SECOND(wDosTime); - ud.st.wDayOfWeek = ud.st.wMilliseconds = 0; - - return !VarDateFromUdate(&ud, 0, pDateOut); -} - -/********************************************************************** - * VariantTimeToDosDateTime [OLEAUT32.13] - * - * Convert a variant format date into a Dos format date and time. - * - * dateIn [I] VT_DATE time format - * pwDosDate [O] Destination for Dos format date - * pwDosTime [O] Destination for Dos format time - * - * RETURNS - * Success: TRUE. pwDosDate and pwDosTime contains the converted values. - * Failure: FALSE, if dateIn cannot be represented in Dos format. - * - * NOTES - * See DosDateTimeToVariantTime() for Dos format details and bugs. - */ -INT WINAPI VariantTimeToDosDateTime(double dateIn, USHORT *pwDosDate, USHORT *pwDosTime) -{ - UDATE ud; - - TRACE("(%g,%p,%p)\n", dateIn, pwDosDate, pwDosTime); - - if (FAILED(VarUdateFromDate(dateIn, 0, &ud))) - return FALSE; - - if (ud.st.wYear < 1980 || ud.st.wYear > 2099) - return FALSE; - - *pwDosDate = DOS_DATE(ud.st.wDay, ud.st.wMonth, ud.st.wYear); - *pwDosTime = DOS_TIME(ud.st.wHour, ud.st.wMinute, ud.st.wSecond); - - TRACE("Returning 0x%x(%d/%d/%d), 0x%x(%d:%d:%d)\n", - *pwDosDate, DOS_YEAR(*pwDosDate), DOS_MONTH(*pwDosDate), DOS_DAY(*pwDosDate), - *pwDosTime, DOS_HOUR(*pwDosTime), DOS_MINUTE(*pwDosTime), DOS_SECOND(*pwDosTime)); - return TRUE; -} - -/*********************************************************************** - * SystemTimeToVariantTime [OLEAUT32.184] - * - * Convert a System format date and time into variant VT_DATE format. - * - * PARAMS - * lpSt [I] System format date and time - * pDateOut [O] Destination for VT_DATE format date - * - * RETURNS - * Success: TRUE. *pDateOut contains the converted value. - * Failure: FALSE, if lpSt cannot be represented in VT_DATE format. - */ -INT WINAPI SystemTimeToVariantTime(LPSYSTEMTIME lpSt, double *pDateOut) -{ - UDATE ud; - - TRACE("(%p->%d/%d/%d %d:%d:%d,%p)\n", lpSt, lpSt->wDay, lpSt->wMonth, - lpSt->wYear, lpSt->wHour, lpSt->wMinute, lpSt->wSecond, pDateOut); - - if (lpSt->wMonth > 12) - return FALSE; - - memcpy(&ud.st, lpSt, sizeof(ud.st)); - return !VarDateFromUdate(&ud, 0, pDateOut); -} - -/*********************************************************************** - * VariantTimeToSystemTime [OLEAUT32.185] - * - * Convert a variant VT_DATE into a System format date and time. - * - * PARAMS - * datein [I] Variant VT_DATE format date - * lpSt [O] Destination for System format date and time - * - * RETURNS - * Success: TRUE. *lpSt contains the converted value. - * Failure: FALSE, if dateIn is too large or small. - */ -INT WINAPI VariantTimeToSystemTime(double dateIn, LPSYSTEMTIME lpSt) -{ - UDATE ud; - - TRACE("(%g,%p)\n", dateIn, lpSt); - - if (FAILED(VarUdateFromDate(dateIn, 0, &ud))) - return FALSE; - - memcpy(lpSt, &ud.st, sizeof(ud.st)); - return TRUE; -} - -/*********************************************************************** - * VarDateFromUdateEx [OLEAUT32.319] - * - * Convert an unpacked format date and time to a variant VT_DATE. - * - * PARAMS - * pUdateIn [I] Unpacked format date and time to convert - * lcid [I] Locale identifier for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pDateOut [O] Destination for variant VT_DATE. - * - * RETURNS - * Success: S_OK. *pDateOut contains the converted value. - * Failure: E_INVALIDARG, if pUdateIn cannot be represented in VT_DATE format. - */ -HRESULT WINAPI VarDateFromUdateEx(UDATE *pUdateIn, LCID lcid, ULONG dwFlags, DATE *pDateOut) -{ - UDATE ud; - double dateVal; - - TRACE("(%p->%d/%d/%d %d:%d:%d:%d %d %d,0x%08lx,0x%08lx,%p)\n", pUdateIn, - pUdateIn->st.wMonth, pUdateIn->st.wDay, pUdateIn->st.wYear, - pUdateIn->st.wHour, pUdateIn->st.wMinute, pUdateIn->st.wSecond, - pUdateIn->st.wMilliseconds, pUdateIn->st.wDayOfWeek, - pUdateIn->wDayOfYear, lcid, dwFlags, pDateOut); - - if (lcid != MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT)) - FIXME("lcid possibly not handled, treating as en-us\n"); - - memcpy(&ud, pUdateIn, sizeof(ud)); - - if (dwFlags & VAR_VALIDDATE) - WARN("Ignoring VAR_VALIDDATE\n"); - - if (FAILED(VARIANT_RollUdate(&ud))) - return E_INVALIDARG; - - /* Date */ - dateVal = VARIANT_DateFromJulian(VARIANT_JulianFromDMY(ud.st.wYear, ud.st.wMonth, ud.st.wDay)); - - /* Time */ - dateVal += ud.st.wHour / 24.0; - dateVal += ud.st.wMinute / 1440.0; - dateVal += ud.st.wSecond / 86400.0; - dateVal += ud.st.wMilliseconds / 86400000.0; - - TRACE("Returning %g\n", dateVal); - *pDateOut = dateVal; - return S_OK; -} - -/*********************************************************************** - * VarDateFromUdate [OLEAUT32.330] - * - * Convert an unpacked format date and time to a variant VT_DATE. - * - * PARAMS - * pUdateIn [I] Unpacked format date and time to convert - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pDateOut [O] Destination for variant VT_DATE. - * - * RETURNS - * Success: S_OK. *pDateOut contains the converted value. - * Failure: E_INVALIDARG, if pUdateIn cannot be represented in VT_DATE format. - * - * NOTES - * This function uses the United States English locale for the conversion. Use - * VarDateFromUdateEx() for alternate locales. - */ -HRESULT WINAPI VarDateFromUdate(UDATE *pUdateIn, ULONG dwFlags, DATE *pDateOut) -{ - LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); - - return VarDateFromUdateEx(pUdateIn, lcid, dwFlags, pDateOut); -} - -/*********************************************************************** - * VarUdateFromDate [OLEAUT32.331] - * - * Convert a variant VT_DATE into an unpacked format date and time. - * - * PARAMS - * datein [I] Variant VT_DATE format date - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * lpUdate [O] Destination for unpacked format date and time - * - * RETURNS - * Success: S_OK. *lpUdate contains the converted value. - * Failure: E_INVALIDARG, if dateIn is too large or small. - */ -HRESULT WINAPI VarUdateFromDate(DATE dateIn, ULONG dwFlags, UDATE *lpUdate) -{ - /* Cumulative totals of days per month */ - static const USHORT cumulativeDays[] = - { - 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 - }; - double datePart, timePart; - int julianDays; - - TRACE("(%g,0x%08lx,%p)\n", dateIn, dwFlags, lpUdate); - - if (dateIn <= (DATE_MIN - 1.0) || dateIn >= (DATE_MAX + 1.0)) - return E_INVALIDARG; - - datePart = dateIn < 0.0 ? ceil(dateIn) : floor(dateIn); - /* Compensate for int truncation (always downwards) */ - timePart = dateIn - datePart + 0.00000000001; - if (timePart >= 1.0) - timePart -= 0.00000000001; - - /* Date */ - julianDays = VARIANT_JulianFromDate(dateIn); - VARIANT_DMYFromJulian(julianDays, &lpUdate->st.wYear, &lpUdate->st.wMonth, - &lpUdate->st.wDay); - - datePart = (datePart + 1.5) / 7.0; - lpUdate->st.wDayOfWeek = (datePart - floor(datePart)) * 7; - if (lpUdate->st.wDayOfWeek == 0) - lpUdate->st.wDayOfWeek = 5; - else if (lpUdate->st.wDayOfWeek == 1) - lpUdate->st.wDayOfWeek = 6; - else - lpUdate->st.wDayOfWeek -= 2; - - if (lpUdate->st.wMonth > 2 && IsLeapYear(lpUdate->st.wYear)) - lpUdate->wDayOfYear = 1; /* After February, in a leap year */ - else - lpUdate->wDayOfYear = 0; - - lpUdate->wDayOfYear += cumulativeDays[lpUdate->st.wMonth]; - lpUdate->wDayOfYear += lpUdate->st.wDay; - - /* Time */ - timePart *= 24.0; - lpUdate->st.wHour = timePart; - timePart -= lpUdate->st.wHour; - timePart *= 60.0; - lpUdate->st.wMinute = timePart; - timePart -= lpUdate->st.wMinute; - timePart *= 60.0; - lpUdate->st.wSecond = timePart; - timePart -= lpUdate->st.wSecond; - lpUdate->st.wMilliseconds = 0; - if (timePart > 0.5) - { - /* Round the milliseconds, adjusting the time/date forward if needed */ - if (lpUdate->st.wSecond < 59) - lpUdate->st.wSecond++; - else - { - lpUdate->st.wSecond = 0; - if (lpUdate->st.wMinute < 59) - lpUdate->st.wMinute++; - else - { - lpUdate->st.wMinute = 0; - if (lpUdate->st.wHour < 23) - lpUdate->st.wHour++; - else - { - lpUdate->st.wHour = 0; - /* Roll over a whole day */ - if (++lpUdate->st.wDay > 28) - VARIANT_RollUdate(lpUdate); - } - } - } - } - return S_OK; -} - -#define GET_NUMBER_TEXT(fld,name) \ - buff[0] = 0; \ - if (!GetLocaleInfoW(lcid, lctype|fld, buff, 2)) \ - WARN("buffer too small for " #fld "\n"); \ - else \ - if (buff[0]) lpChars->name = buff[0]; \ - TRACE("lcid 0x%lx, " #name "=%d '%c'\n", lcid, lpChars->name, lpChars->name) - -/* Get the valid number characters for an lcid */ -void VARIANT_GetLocalisedNumberChars(VARIANT_NUMBER_CHARS *lpChars, LCID lcid, DWORD dwFlags) -{ - static const VARIANT_NUMBER_CHARS defaultChars = { '-','+','.',',','$',0,'.',',' }; - LCTYPE lctype = dwFlags & LOCALE_NOUSEROVERRIDE; - WCHAR buff[4]; - - memcpy(lpChars, &defaultChars, sizeof(defaultChars)); - GET_NUMBER_TEXT(LOCALE_SNEGATIVESIGN, cNegativeSymbol); - GET_NUMBER_TEXT(LOCALE_SPOSITIVESIGN, cPositiveSymbol); - GET_NUMBER_TEXT(LOCALE_SDECIMAL, cDecimalPoint); - GET_NUMBER_TEXT(LOCALE_STHOUSAND, cDigitSeperator); - GET_NUMBER_TEXT(LOCALE_SMONDECIMALSEP, cCurrencyDecimalPoint); - GET_NUMBER_TEXT(LOCALE_SMONTHOUSANDSEP, cCurrencyDigitSeperator); - - /* Local currency symbols are often 2 characters */ - lpChars->cCurrencyLocal2 = '\0'; - switch(GetLocaleInfoW(lcid, lctype|LOCALE_SCURRENCY, buff, sizeof(buff)/sizeof(WCHAR))) - { - case 3: lpChars->cCurrencyLocal2 = buff[1]; /* Fall through */ - case 2: lpChars->cCurrencyLocal = buff[0]; - break; - default: WARN("buffer too small for LOCALE_SCURRENCY\n"); - } - TRACE("lcid 0x%lx, cCurrencyLocal =%d,%d '%c','%c'\n", lcid, lpChars->cCurrencyLocal, - lpChars->cCurrencyLocal2, lpChars->cCurrencyLocal, lpChars->cCurrencyLocal2); -} - -/* Number Parsing States */ -#define B_PROCESSING_EXPONENT 0x1 -#define B_NEGATIVE_EXPONENT 0x2 -#define B_EXPONENT_START 0x4 -#define B_INEXACT_ZEROS 0x8 -#define B_LEADING_ZERO 0x10 -#define B_PROCESSING_HEX 0x20 -#define B_PROCESSING_OCT 0x40 - -/********************************************************************** - * VarParseNumFromStr [OLEAUT32.46] - * - * Parse a string containing a number into a NUMPARSE structure. - * - * PARAMS - * lpszStr [I] String to parse number from - * lcid [I] Locale Id for the conversion - * dwFlags [I] 0, or LOCALE_NOUSEROVERRIDE to use system default number chars - * pNumprs [I/O] Destination for parsed number - * rgbDig [O] Destination for digits read in - * - * RETURNS - * Success: S_OK. pNumprs and rgbDig contain the parsed representation of - * the number. - * Failure: E_INVALIDARG, if any parameter is invalid. - * DISP_E_TYPEMISMATCH, if the string is not a number or is formatted - * incorrectly. - * DISP_E_OVERFLOW, if rgbDig is too small to hold the number. - * - * NOTES - * pNumprs must have the following fields set: - * cDig: Set to the size of rgbDig. - * dwInFlags: Set to the allowable syntax of the number using NUMPRS_ flags - * from "oleauto.h". - * - * FIXME - * - I am unsure if this function should parse non-arabic (e.g. Thai) - * numerals, so this has not been implemented. - */ -HRESULT WINAPI VarParseNumFromStr(OLECHAR *lpszStr, LCID lcid, ULONG dwFlags, - NUMPARSE *pNumprs, BYTE *rgbDig) -{ - VARIANT_NUMBER_CHARS chars; - BYTE rgbTmp[1024]; - DWORD dwState = B_EXPONENT_START|B_INEXACT_ZEROS; - int iMaxDigits = sizeof(rgbTmp) / sizeof(BYTE); - int cchUsed = 0; - - TRACE("(%s,%ld,0x%08lx,%p,%p)\n", debugstr_w(lpszStr), lcid, dwFlags, pNumprs, rgbDig); - - if (!pNumprs || !rgbDig) - return E_INVALIDARG; - - if (pNumprs->cDig < iMaxDigits) - iMaxDigits = pNumprs->cDig; - - pNumprs->cDig = 0; - pNumprs->dwOutFlags = 0; - pNumprs->cchUsed = 0; - pNumprs->nBaseShift = 0; - pNumprs->nPwr10 = 0; - - if (!lpszStr) - return DISP_E_TYPEMISMATCH; - - VARIANT_GetLocalisedNumberChars(&chars, lcid, dwFlags); - - /* First consume all the leading symbols and space from the string */ - while (1) - { - if (pNumprs->dwInFlags & NUMPRS_LEADING_WHITE && isspaceW(*lpszStr)) - { - pNumprs->dwOutFlags |= NUMPRS_LEADING_WHITE; - do - { - cchUsed++; - lpszStr++; - } while (isspaceW(*lpszStr)); - } - else if (pNumprs->dwInFlags & NUMPRS_LEADING_PLUS && - *lpszStr == chars.cPositiveSymbol && - !(pNumprs->dwOutFlags & NUMPRS_LEADING_PLUS)) - { - pNumprs->dwOutFlags |= NUMPRS_LEADING_PLUS; - cchUsed++; - lpszStr++; - } - else if (pNumprs->dwInFlags & NUMPRS_LEADING_MINUS && - *lpszStr == chars.cNegativeSymbol && - !(pNumprs->dwOutFlags & NUMPRS_LEADING_MINUS)) - { - pNumprs->dwOutFlags |= (NUMPRS_LEADING_MINUS|NUMPRS_NEG); - cchUsed++; - lpszStr++; - } - else if (pNumprs->dwInFlags & NUMPRS_CURRENCY && - !(pNumprs->dwOutFlags & NUMPRS_CURRENCY) && - *lpszStr == chars.cCurrencyLocal && - (!chars.cCurrencyLocal2 || lpszStr[1] == chars.cCurrencyLocal2)) - { - pNumprs->dwOutFlags |= NUMPRS_CURRENCY; - cchUsed++; - lpszStr++; - /* Only accept currency characters */ - chars.cDecimalPoint = chars.cCurrencyDecimalPoint; - chars.cDigitSeperator = chars.cCurrencyDigitSeperator; - } - else if (pNumprs->dwInFlags & NUMPRS_PARENS && *lpszStr == '(' && - !(pNumprs->dwOutFlags & NUMPRS_PARENS)) - { - pNumprs->dwOutFlags |= NUMPRS_PARENS; - cchUsed++; - lpszStr++; - } - else - break; - } - - if (!(pNumprs->dwOutFlags & NUMPRS_CURRENCY)) - { - /* Only accept non-currency characters */ - chars.cCurrencyDecimalPoint = chars.cDecimalPoint; - chars.cCurrencyDigitSeperator = chars.cDigitSeperator; - } - - if ((*lpszStr == '&' && (*(lpszStr+1) == 'H' || *(lpszStr+1) == 'h')) && - pNumprs->dwInFlags & NUMPRS_HEX_OCT) - { - dwState |= B_PROCESSING_HEX; - pNumprs->dwOutFlags |= NUMPRS_HEX_OCT; - cchUsed=cchUsed+2; - lpszStr=lpszStr+2; - } - else if ((*lpszStr == '&' && (*(lpszStr+1) == 'O' || *(lpszStr+1) == 'o')) && - pNumprs->dwInFlags & NUMPRS_HEX_OCT) - { - dwState |= B_PROCESSING_OCT; - pNumprs->dwOutFlags |= NUMPRS_HEX_OCT; - cchUsed=cchUsed+2; - lpszStr=lpszStr+2; - } - - /* Strip Leading zeros */ - while (*lpszStr == '0') - { - dwState |= B_LEADING_ZERO; - cchUsed++; - lpszStr++; - } - - while (*lpszStr) - { - if (isdigitW(*lpszStr)) - { - if (dwState & B_PROCESSING_EXPONENT) - { - int exponentSize = 0; - if (dwState & B_EXPONENT_START) - { - if (!isdigitW(*lpszStr)) - break; /* No exponent digits - invalid */ - while (*lpszStr == '0') - { - /* Skip leading zero's in the exponent */ - cchUsed++; - lpszStr++; - } - } - - while (isdigitW(*lpszStr)) - { - exponentSize *= 10; - exponentSize += *lpszStr - '0'; - cchUsed++; - lpszStr++; - } - if (dwState & B_NEGATIVE_EXPONENT) - exponentSize = -exponentSize; - /* Add the exponent into the powers of 10 */ - pNumprs->nPwr10 += exponentSize; - dwState &= ~(B_PROCESSING_EXPONENT|B_EXPONENT_START); - lpszStr--; /* back up to allow processing of next char */ - } - else - { - if ((pNumprs->cDig >= iMaxDigits) && !(dwState & B_PROCESSING_HEX) - && !(dwState & B_PROCESSING_OCT)) - { - pNumprs->dwOutFlags |= NUMPRS_INEXACT; - - if (*lpszStr != '0') - dwState &= ~B_INEXACT_ZEROS; /* Inexact number with non-trailing zeros */ - - /* This digit can't be represented, but count it in nPwr10 */ - if (pNumprs->dwOutFlags & NUMPRS_DECIMAL) - pNumprs->nPwr10--; - else - pNumprs->nPwr10++; - } - else - { - if ((dwState & B_PROCESSING_OCT) && ((*lpszStr == '8') || (*lpszStr == '9'))) { - return DISP_E_TYPEMISMATCH; - } - - if (pNumprs->dwOutFlags & NUMPRS_DECIMAL) - pNumprs->nPwr10--; /* Count decimal points in nPwr10 */ - - rgbTmp[pNumprs->cDig] = *lpszStr - '0'; - } - pNumprs->cDig++; - cchUsed++; - } - } - else if (*lpszStr == chars.cDigitSeperator && pNumprs->dwInFlags & NUMPRS_THOUSANDS) - { - pNumprs->dwOutFlags |= NUMPRS_THOUSANDS; - cchUsed++; - } - else if (*lpszStr == chars.cDecimalPoint && - pNumprs->dwInFlags & NUMPRS_DECIMAL && - !(pNumprs->dwOutFlags & (NUMPRS_DECIMAL|NUMPRS_EXPONENT))) - { - pNumprs->dwOutFlags |= NUMPRS_DECIMAL; - cchUsed++; - - /* If we have no digits so far, skip leading zeros */ - if (!pNumprs->cDig) - { - while (lpszStr[1] == '0') - { - dwState |= B_LEADING_ZERO; - cchUsed++; - lpszStr++; - pNumprs->nPwr10--; - } - } - } - else if ((*lpszStr == 'e' || *lpszStr == 'E') && - pNumprs->dwInFlags & NUMPRS_EXPONENT && - !(pNumprs->dwOutFlags & NUMPRS_EXPONENT)) - { - dwState |= B_PROCESSING_EXPONENT; - pNumprs->dwOutFlags |= NUMPRS_EXPONENT; - cchUsed++; - } - else if (dwState & B_PROCESSING_EXPONENT && *lpszStr == chars.cPositiveSymbol) - { - cchUsed++; /* Ignore positive exponent */ - } - else if (dwState & B_PROCESSING_EXPONENT && *lpszStr == chars.cNegativeSymbol) - { - dwState |= B_NEGATIVE_EXPONENT; - cchUsed++; - } - else if (((*lpszStr >= 'a' && *lpszStr <= 'f') || - (*lpszStr >= 'A' && *lpszStr <= 'F')) && - dwState & B_PROCESSING_HEX) - { - if (pNumprs->cDig >= iMaxDigits) - { - return DISP_E_OVERFLOW; - } - else - { - if (*lpszStr >= 'a') - rgbTmp[pNumprs->cDig] = *lpszStr - 'a' + 10; - else - rgbTmp[pNumprs->cDig] = *lpszStr - 'A' + 10; - } - pNumprs->cDig++; - cchUsed++; - } - else - break; /* Stop at an unrecognised character */ - - lpszStr++; - } - - if (!pNumprs->cDig && dwState & B_LEADING_ZERO) - { - /* Ensure a 0 on its own gets stored */ - pNumprs->cDig = 1; - rgbTmp[0] = 0; - } - - if (pNumprs->dwOutFlags & NUMPRS_EXPONENT && dwState & B_PROCESSING_EXPONENT) - { - pNumprs->cchUsed = cchUsed; - return DISP_E_TYPEMISMATCH; /* Failed to completely parse the exponent */ - } - - if (pNumprs->dwOutFlags & NUMPRS_INEXACT) - { - if (dwState & B_INEXACT_ZEROS) - pNumprs->dwOutFlags &= ~NUMPRS_INEXACT; /* All zeros doesn't set NUMPRS_INEXACT */ - } else if(pNumprs->dwInFlags & NUMPRS_HEX_OCT) - { - /* copy all of the digits into the output digit buffer */ - /* this is exactly what windows does although it also returns */ - /* cDig of X and writes X+Y where Y>=0 number of digits to rgbDig */ - memcpy(rgbDig, rgbTmp, pNumprs->cDig * sizeof(BYTE)); - - if (dwState & B_PROCESSING_HEX) { - /* hex numbers have always the same format */ - pNumprs->nPwr10=0; - pNumprs->nBaseShift=4; - } else { - if (dwState & B_PROCESSING_OCT) { - /* oct numbers have always the same format */ - pNumprs->nPwr10=0; - pNumprs->nBaseShift=3; - } else { - while (pNumprs->cDig > 1 && !rgbTmp[pNumprs->cDig - 1]) - { - pNumprs->nPwr10++; - pNumprs->cDig--; - } - } - } - } else - { - /* Remove trailing zeros from the last (whole number or decimal) part */ - while (pNumprs->cDig > 1 && !rgbTmp[pNumprs->cDig - 1]) - { - pNumprs->nPwr10++; - pNumprs->cDig--; - } - } - - if (pNumprs->cDig <= iMaxDigits) - pNumprs->dwOutFlags &= ~NUMPRS_INEXACT; /* Ignore stripped zeros for NUMPRS_INEXACT */ - else - pNumprs->cDig = iMaxDigits; /* Only return iMaxDigits worth of digits */ - - /* Copy the digits we processed into rgbDig */ - memcpy(rgbDig, rgbTmp, pNumprs->cDig * sizeof(BYTE)); - - /* Consume any trailing symbols and space */ - while (1) - { - if ((pNumprs->dwInFlags & NUMPRS_TRAILING_WHITE) && isspaceW(*lpszStr)) - { - pNumprs->dwOutFlags |= NUMPRS_TRAILING_WHITE; - do - { - cchUsed++; - lpszStr++; - } while (isspaceW(*lpszStr)); - } - else if (pNumprs->dwInFlags & NUMPRS_TRAILING_PLUS && - !(pNumprs->dwOutFlags & NUMPRS_LEADING_PLUS) && - *lpszStr == chars.cPositiveSymbol) - { - pNumprs->dwOutFlags |= NUMPRS_TRAILING_PLUS; - cchUsed++; - lpszStr++; - } - else if (pNumprs->dwInFlags & NUMPRS_TRAILING_MINUS && - !(pNumprs->dwOutFlags & NUMPRS_LEADING_MINUS) && - *lpszStr == chars.cNegativeSymbol) - { - pNumprs->dwOutFlags |= (NUMPRS_TRAILING_MINUS|NUMPRS_NEG); - cchUsed++; - lpszStr++; - } - else if (pNumprs->dwInFlags & NUMPRS_PARENS && *lpszStr == ')' && - pNumprs->dwOutFlags & NUMPRS_PARENS) - { - cchUsed++; - lpszStr++; - pNumprs->dwOutFlags |= NUMPRS_NEG; - } - else - break; - } - - if (pNumprs->dwOutFlags & NUMPRS_PARENS && !(pNumprs->dwOutFlags & NUMPRS_NEG)) - { - pNumprs->cchUsed = cchUsed; - return DISP_E_TYPEMISMATCH; /* Opening parenthesis not matched */ - } - - if (pNumprs->dwInFlags & NUMPRS_USE_ALL && *lpszStr != '\0') - return DISP_E_TYPEMISMATCH; /* Not all chars were consumed */ - - if (!pNumprs->cDig) - return DISP_E_TYPEMISMATCH; /* No Number found */ - - pNumprs->cchUsed = cchUsed; - return S_OK; -} - -/* VTBIT flags indicating an integer value */ -#define INTEGER_VTBITS (VTBIT_I1|VTBIT_UI1|VTBIT_I2|VTBIT_UI2|VTBIT_I4|VTBIT_UI4|VTBIT_I8|VTBIT_UI8) -/* VTBIT flags indicating a real number value */ -#define REAL_VTBITS (VTBIT_R4|VTBIT_R8|VTBIT_CY) - -/* Helper macros to check whether bit pattern fits in VARIANT (x is a ULONG64 ) */ -#define FITS_AS_I1(x) ((x) >> 8 == 0) -#define FITS_AS_I2(x) ((x) >> 16 == 0) -#define FITS_AS_I4(x) ((x) >> 32 == 0) - -/********************************************************************** - * VarNumFromParseNum [OLEAUT32.47] - * - * Convert a NUMPARSE structure into a numeric Variant type. - * - * PARAMS - * pNumprs [I] Source for parsed number. cDig must be set to the size of rgbDig - * rgbDig [I] Source for the numbers digits - * dwVtBits [I] VTBIT_ flags from "oleauto.h" indicating the acceptable dest types - * pVarDst [O] Destination for the converted Variant value. - * - * RETURNS - * Success: S_OK. pVarDst contains the converted value. - * Failure: E_INVALIDARG, if any parameter is invalid. - * DISP_E_OVERFLOW, if the number is too big for the types set in dwVtBits. - * - * NOTES - * - The smallest favoured type present in dwVtBits that can represent the - * number in pNumprs without losing precision is used. - * - Signed types are preferrred over unsigned types of the same size. - * - Preferred types in order are: integer, float, double, currency then decimal. - * - Rounding (dropping of decimal points) occurs without error. See VarI8FromR8() - * for details of the rounding method. - * - pVarDst is not cleared before the result is stored in it. - */ -HRESULT WINAPI VarNumFromParseNum(NUMPARSE *pNumprs, BYTE *rgbDig, - ULONG dwVtBits, VARIANT *pVarDst) -{ - /* Scale factors and limits for double arithmetic */ - static const double dblMultipliers[11] = { - 1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0, - 1000000.0, 10000000.0, 100000000.0, 1000000000.0, 10000000000.0 - }; - static const double dblMinimums[11] = { - R8_MIN, R8_MIN*10.0, R8_MIN*100.0, R8_MIN*1000.0, R8_MIN*10000.0, - R8_MIN*100000.0, R8_MIN*1000000.0, R8_MIN*10000000.0, - R8_MIN*100000000.0, R8_MIN*1000000000.0, R8_MIN*10000000000.0 - }; - static const double dblMaximums[11] = { - R8_MAX, R8_MAX/10.0, R8_MAX/100.0, R8_MAX/1000.0, R8_MAX/10000.0, - R8_MAX/100000.0, R8_MAX/1000000.0, R8_MAX/10000000.0, - R8_MAX/100000000.0, R8_MAX/1000000000.0, R8_MAX/10000000000.0 - }; - - int wholeNumberDigits, fractionalDigits, divisor10 = 0, multiplier10 = 0; - - TRACE("(%p,%p,0x%lx,%p)\n", pNumprs, rgbDig, dwVtBits, pVarDst); - - if (pNumprs->nBaseShift) - { - /* nBaseShift indicates a hex or octal number */ - ULONG64 ul64 = 0; - LONG64 l64; - int i; - - /* Convert the hex or octal number string into a UI64 */ - for (i = 0; i < pNumprs->cDig; i++) - { - if (ul64 > ((UI8_MAX>>pNumprs->nBaseShift) - rgbDig[i])) - { - TRACE("Overflow multiplying digits\n"); - return DISP_E_OVERFLOW; - } - ul64 = (ul64<<pNumprs->nBaseShift) + rgbDig[i]; - } - - /* also make a negative representation */ - l64=-ul64; - - /* Try signed and unsigned types in size order */ - if (dwVtBits & VTBIT_I1 && FITS_AS_I1(ul64)) - { - V_VT(pVarDst) = VT_I1; - V_I1(pVarDst) = ul64; - return S_OK; - } - else if (dwVtBits & VTBIT_UI1 && FITS_AS_I1(ul64)) - { - V_VT(pVarDst) = VT_UI1; - V_UI1(pVarDst) = ul64; - return S_OK; - } - else if (dwVtBits & VTBIT_I2 && FITS_AS_I2(ul64)) - { - V_VT(pVarDst) = VT_I2; - V_I2(pVarDst) = ul64; - return S_OK; - } - else if (dwVtBits & VTBIT_UI2 && FITS_AS_I2(ul64)) - { - V_VT(pVarDst) = VT_UI2; - V_UI2(pVarDst) = ul64; - return S_OK; - } - else if (dwVtBits & VTBIT_I4 && FITS_AS_I4(ul64)) - { - V_VT(pVarDst) = VT_I4; - V_I4(pVarDst) = ul64; - return S_OK; - } - else if (dwVtBits & VTBIT_UI4 && FITS_AS_I4(ul64)) - { - V_VT(pVarDst) = VT_UI4; - V_UI4(pVarDst) = ul64; - return S_OK; - } - else if (dwVtBits & VTBIT_I8 && ((ul64 <= I8_MAX)||(l64>=I8_MIN))) - { - V_VT(pVarDst) = VT_I8; - V_I8(pVarDst) = ul64; - return S_OK; - } - else if (dwVtBits & VTBIT_UI8) - { - V_VT(pVarDst) = VT_UI8; - V_UI8(pVarDst) = ul64; - return S_OK; - } - else if ((dwVtBits & REAL_VTBITS) == VTBIT_DECIMAL) - { - V_VT(pVarDst) = VT_DECIMAL; - DEC_SIGNSCALE(&V_DECIMAL(pVarDst)) = SIGNSCALE(DECIMAL_POS,0); - DEC_HI32(&V_DECIMAL(pVarDst)) = 0; - DEC_LO64(&V_DECIMAL(pVarDst)) = ul64; - return S_OK; - } - else if (dwVtBits & VTBIT_R4 && ((ul64 <= I4_MAX)||(l64 >= I4_MIN))) - { - V_VT(pVarDst) = VT_R4; - if (ul64 <= I4_MAX) - V_R4(pVarDst) = ul64; - else - V_R4(pVarDst) = l64; - return S_OK; - } - else if (dwVtBits & VTBIT_R8 && ((ul64 <= I4_MAX)||(l64 >= I4_MIN))) - { - V_VT(pVarDst) = VT_R8; - if (ul64 <= I4_MAX) - V_R8(pVarDst) = ul64; - else - V_R8(pVarDst) = l64; - return S_OK; - } - - TRACE("Overflow: possible return types: 0x%lx, value: %s\n", dwVtBits, wine_dbgstr_longlong(ul64)); - return DISP_E_OVERFLOW; - } - - /* Count the number of relevant fractional and whole digits stored, - * And compute the divisor/multiplier to scale the number by. - */ - if (pNumprs->nPwr10 < 0) - { - if (-pNumprs->nPwr10 >= pNumprs->cDig) - { - /* A real number < +/- 1.0 e.g. 0.1024 or 0.01024 */ - wholeNumberDigits = 0; - fractionalDigits = pNumprs->cDig; - divisor10 = -pNumprs->nPwr10; - } - else - { - /* An exactly represented real number e.g. 1.024 */ - wholeNumberDigits = pNumprs->cDig + pNumprs->nPwr10; - fractionalDigits = pNumprs->cDig - wholeNumberDigits; - divisor10 = pNumprs->cDig - wholeNumberDigits; - } - } - else if (pNumprs->nPwr10 == 0) - { - /* An exactly represented whole number e.g. 1024 */ - wholeNumberDigits = pNumprs->cDig; - fractionalDigits = 0; - } - else /* pNumprs->nPwr10 > 0 */ - { - /* A whole number followed by nPwr10 0's e.g. 102400 */ - wholeNumberDigits = pNumprs->cDig; - fractionalDigits = 0; - multiplier10 = pNumprs->nPwr10; - } - - TRACE("cDig %d; nPwr10 %d, whole %d, frac %d ", pNumprs->cDig, - pNumprs->nPwr10, wholeNumberDigits, fractionalDigits); - TRACE("mult %d; div %d\n", multiplier10, divisor10); - - if (dwVtBits & (INTEGER_VTBITS|VTBIT_DECIMAL) && - (!fractionalDigits || !(dwVtBits & (REAL_VTBITS|VTBIT_CY|VTBIT_DECIMAL)))) - { - /* We have one or more integer output choices, and either: - * 1) An integer input value, or - * 2) A real number input value but no floating output choices. - * Alternately, we have a DECIMAL output available and an integer input. - * - * So, place the integer value into pVarDst, using the smallest type - * possible and preferring signed over unsigned types. - */ - BOOL bOverflow = FALSE, bNegative; - ULONG64 ul64 = 0; - int i; - - /* Convert the integer part of the number into a UI8 */ - for (i = 0; i < wholeNumberDigits; i++) - { - if (ul64 > (UI8_MAX / 10 - rgbDig[i])) - { - TRACE("Overflow multiplying digits\n"); - bOverflow = TRUE; - break; - } - ul64 = ul64 * 10 + rgbDig[i]; - } - - /* Account for the scale of the number */ - if (!bOverflow && multiplier10) - { - for (i = 0; i < multiplier10; i++) - { - if (ul64 > (UI8_MAX / 10)) - { - TRACE("Overflow scaling number\n"); - bOverflow = TRUE; - break; - } - ul64 = ul64 * 10; - } - } - - /* If we have any fractional digits, round the value. - * Note we don't have to do this if divisor10 is < 1, - * because this means the fractional part must be < 0.5 - */ - if (!bOverflow && fractionalDigits && divisor10 > 0) - { - const BYTE* fracDig = rgbDig + wholeNumberDigits; - BOOL bAdjust = FALSE; - - TRACE("first decimal value is %d\n", *fracDig); - - if (*fracDig > 5) - bAdjust = TRUE; /* > 0.5 */ - else if (*fracDig == 5) - { - for (i = 1; i < fractionalDigits; i++) - { - if (fracDig[i]) - { - bAdjust = TRUE; /* > 0.5 */ - break; - } - } - /* If exactly 0.5, round only odd values */ - if (i == fractionalDigits && (ul64 & 1)) - bAdjust = TRUE; - } - - if (bAdjust) - { - if (ul64 == UI8_MAX) - { - TRACE("Overflow after rounding\n"); - bOverflow = TRUE; - } - ul64++; - } - } - - /* Zero is not a negative number */ - bNegative = pNumprs->dwOutFlags & NUMPRS_NEG && ul64 ? TRUE : FALSE; - - TRACE("Integer value is %lld, bNeg %d\n", ul64, bNegative); - - /* For negative integers, try the signed types in size order */ - if (!bOverflow && bNegative) - { - if (dwVtBits & (VTBIT_I1|VTBIT_I2|VTBIT_I4|VTBIT_I8)) - { - if (dwVtBits & VTBIT_I1 && ul64 <= -I1_MIN) - { - V_VT(pVarDst) = VT_I1; - V_I1(pVarDst) = -ul64; - return S_OK; - } - else if (dwVtBits & VTBIT_I2 && ul64 <= -I2_MIN) - { - V_VT(pVarDst) = VT_I2; - V_I2(pVarDst) = -ul64; - return S_OK; - } - else if (dwVtBits & VTBIT_I4 && ul64 <= -((LONGLONG)I4_MIN)) - { - V_VT(pVarDst) = VT_I4; - V_I4(pVarDst) = -ul64; - return S_OK; - } - else if (dwVtBits & VTBIT_I8 && ul64 <= (ULONGLONG)I8_MAX + 1) - { - V_VT(pVarDst) = VT_I8; - V_I8(pVarDst) = -ul64; - return S_OK; - } - else if ((dwVtBits & REAL_VTBITS) == VTBIT_DECIMAL) - { - /* Decimal is only output choice left - fast path */ - V_VT(pVarDst) = VT_DECIMAL; - DEC_SIGNSCALE(&V_DECIMAL(pVarDst)) = SIGNSCALE(DECIMAL_NEG,0); - DEC_HI32(&V_DECIMAL(pVarDst)) = 0; - DEC_LO64(&V_DECIMAL(pVarDst)) = -ul64; - return S_OK; - } - } - } - else if (!bOverflow) - { - /* For positive integers, try signed then unsigned types in size order */ - if (dwVtBits & VTBIT_I1 && ul64 <= I1_MAX) - { - V_VT(pVarDst) = VT_I1; - V_I1(pVarDst) = ul64; - return S_OK; - } - else if (dwVtBits & VTBIT_UI1 && ul64 <= UI1_MAX) - { - V_VT(pVarDst) = VT_UI1; - V_UI1(pVarDst) = ul64; - return S_OK; - } - else if (dwVtBits & VTBIT_I2 && ul64 <= I2_MAX) - { - V_VT(pVarDst) = VT_I2; - V_I2(pVarDst) = ul64; - return S_OK; - } - else if (dwVtBits & VTBIT_UI2 && ul64 <= UI2_MAX) - { - V_VT(pVarDst) = VT_UI2; - V_UI2(pVarDst) = ul64; - return S_OK; - } - else if (dwVtBits & VTBIT_I4 && ul64 <= I4_MAX) - { - V_VT(pVarDst) = VT_I4; - V_I4(pVarDst) = ul64; - return S_OK; - } - else if (dwVtBits & VTBIT_UI4 && ul64 <= UI4_MAX) - { - V_VT(pVarDst) = VT_UI4; - V_UI4(pVarDst) = ul64; - return S_OK; - } - else if (dwVtBits & VTBIT_I8 && ul64 <= I8_MAX) - { - V_VT(pVarDst) = VT_I8; - V_I8(pVarDst) = ul64; - return S_OK; - } - else if (dwVtBits & VTBIT_UI8) - { - V_VT(pVarDst) = VT_UI8; - V_UI8(pVarDst) = ul64; - return S_OK; - } - else if ((dwVtBits & REAL_VTBITS) == VTBIT_DECIMAL) - { - /* Decimal is only output choice left - fast path */ - V_VT(pVarDst) = VT_DECIMAL; - DEC_SIGNSCALE(&V_DECIMAL(pVarDst)) = SIGNSCALE(DECIMAL_POS,0); - DEC_HI32(&V_DECIMAL(pVarDst)) = 0; - DEC_LO64(&V_DECIMAL(pVarDst)) = ul64; - return S_OK; - } - } - } - - if (dwVtBits & REAL_VTBITS) - { - /* Try to put the number into a float or real */ - BOOL bOverflow = FALSE, bNegative = pNumprs->dwOutFlags & NUMPRS_NEG; - double whole = 0.0; - int i; - - /* Convert the number into a double */ - for (i = 0; i < pNumprs->cDig; i++) - whole = whole * 10.0 + rgbDig[i]; - - TRACE("Whole double value is %16.16g\n", whole); - - /* Account for the scale */ - while (multiplier10 > 10) - { - if (whole > dblMaximums[10]) - { - dwVtBits &= ~(VTBIT_R4|VTBIT_R8|VTBIT_CY); - bOverflow = TRUE; - break; - } - whole = whole * dblMultipliers[10]; - multiplier10 -= 10; - } - if (multiplier10) - { - if (whole > dblMaximums[multiplier10]) - { - dwVtBits &= ~(VTBIT_R4|VTBIT_R8|VTBIT_CY); - bOverflow = TRUE; - } - else - whole = whole * dblMultipliers[multiplier10]; - } - - TRACE("Scaled double value is %16.16g\n", whole); - - while (divisor10 > 10) - { - if (whole < dblMinimums[10] && whole != 0) - { - dwVtBits &= ~(VTBIT_R4|VTBIT_R8|VTBIT_CY); /* Underflow */ - bOverflow = TRUE; - break; - } - whole = whole / dblMultipliers[10]; - divisor10 -= 10; - } - if (divisor10) - { - if (whole < dblMinimums[divisor10] && whole != 0) - { - dwVtBits &= ~(VTBIT_R4|VTBIT_R8|VTBIT_CY); /* Underflow */ - bOverflow = TRUE; - } - else - whole = whole / dblMultipliers[divisor10]; - } - if (!bOverflow) - TRACE("Final double value is %16.16g\n", whole); - - if (dwVtBits & VTBIT_R4 && - ((whole <= R4_MAX && whole >= R4_MIN) || whole == 0.0)) - { - TRACE("Set R4 to final value\n"); - V_VT(pVarDst) = VT_R4; /* Fits into a float */ - V_R4(pVarDst) = pNumprs->dwOutFlags & NUMPRS_NEG ? -whole : whole; - return S_OK; - } - - if (dwVtBits & VTBIT_R8) - { - TRACE("Set R8 to final value\n"); - V_VT(pVarDst) = VT_R8; /* Fits into a double */ - V_R8(pVarDst) = pNumprs->dwOutFlags & NUMPRS_NEG ? -whole : whole; - return S_OK; - } - - if (dwVtBits & VTBIT_CY) - { - if (SUCCEEDED(VarCyFromR8(bNegative ? -whole : whole, &V_CY(pVarDst)))) - { - V_VT(pVarDst) = VT_CY; /* Fits into a currency */ - TRACE("Set CY to final value\n"); - return S_OK; - } - TRACE("Value Overflows CY\n"); - } - } - - if (dwVtBits & VTBIT_DECIMAL) - { - int i; - ULONG carry; - ULONG64 tmp; - DECIMAL* pDec = &V_DECIMAL(pVarDst); - - DECIMAL_SETZERO(*pDec); - DEC_LO32(pDec) = 0; - - if (pNumprs->dwOutFlags & NUMPRS_NEG) - DEC_SIGN(pDec) = DECIMAL_NEG; - else - DEC_SIGN(pDec) = DECIMAL_POS; - - /* Factor the significant digits */ - for (i = 0; i < pNumprs->cDig; i++) - { - tmp = (ULONG64)DEC_LO32(pDec) * 10 + rgbDig[i]; - carry = (ULONG)(tmp >> 32); - DEC_LO32(pDec) = (ULONG)(tmp & UI4_MAX); - tmp = (ULONG64)DEC_MID32(pDec) * 10 + carry; - carry = (ULONG)(tmp >> 32); - DEC_MID32(pDec) = (ULONG)(tmp & UI4_MAX); - tmp = (ULONG64)DEC_HI32(pDec) * 10 + carry; - DEC_HI32(pDec) = (ULONG)(tmp & UI4_MAX); - - if (tmp >> 32 & UI4_MAX) - { -VarNumFromParseNum_DecOverflow: - TRACE("Overflow\n"); - DEC_LO32(pDec) = DEC_MID32(pDec) = DEC_HI32(pDec) = UI4_MAX; - return DISP_E_OVERFLOW; - } - } - - /* Account for the scale of the number */ - while (multiplier10 > 0) - { - tmp = (ULONG64)DEC_LO32(pDec) * 10; - carry = (ULONG)(tmp >> 32); - DEC_LO32(pDec) = (ULONG)(tmp & UI4_MAX); - tmp = (ULONG64)DEC_MID32(pDec) * 10 + carry; - carry = (ULONG)(tmp >> 32); - DEC_MID32(pDec) = (ULONG)(tmp & UI4_MAX); - tmp = (ULONG64)DEC_HI32(pDec) * 10 + carry; - DEC_HI32(pDec) = (ULONG)(tmp & UI4_MAX); - - if (tmp >> 32 & UI4_MAX) - goto VarNumFromParseNum_DecOverflow; - multiplier10--; - } - DEC_SCALE(pDec) = divisor10; - - V_VT(pVarDst) = VT_DECIMAL; - return S_OK; - } - return DISP_E_OVERFLOW; /* No more output choices */ -} - -/********************************************************************** - * VarCat [OLEAUT32.318] - */ -HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out) -{ - TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left), - debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), out); - - /* Should we VariantClear out? */ - /* Can we handle array, vector, by ref etc. */ - if ((V_VT(left)&VT_TYPEMASK) == VT_NULL && - (V_VT(right)&VT_TYPEMASK) == VT_NULL) - { - V_VT(out) = VT_NULL; - return S_OK; - } - - if (V_VT(left) == VT_BSTR && V_VT(right) == VT_BSTR) - { - V_VT(out) = VT_BSTR; - VarBstrCat (V_BSTR(left), V_BSTR(right), &V_BSTR(out)); - return S_OK; - } - if (V_VT(left) == VT_BSTR) { - VARIANT bstrvar; - HRESULT hres; - - V_VT(out) = VT_BSTR; - VariantInit(&bstrvar); - hres = VariantChangeTypeEx(&bstrvar,right,0,0,VT_BSTR); - if (hres) { - FIXME("Failed to convert right side from vt %d to VT_BSTR?\n",V_VT(right)); - return hres; - } - VarBstrCat (V_BSTR(left), V_BSTR(&bstrvar), &V_BSTR(out)); - return S_OK; - } - if (V_VT(right) == VT_BSTR) { - VARIANT bstrvar; - HRESULT hres; - - V_VT(out) = VT_BSTR; - VariantInit(&bstrvar); - hres = VariantChangeTypeEx(&bstrvar,left,0,0,VT_BSTR); - if (hres) { - FIXME("Failed to convert right side from vt %d to VT_BSTR?\n",V_VT(right)); - return hres; - } - VarBstrCat (V_BSTR(&bstrvar), V_BSTR(right), &V_BSTR(out)); - return S_OK; - } - FIXME ("types %d / %d not supported\n",V_VT(left)&VT_TYPEMASK, V_VT(right)&VT_TYPEMASK); - return S_OK; -} - -/********************************************************************** - * VarCmp [OLEAUT32.176] - * - * flags can be: - * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS - * NORM_IGNOREWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA - * - */ -HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags) -{ - BOOL lOk = TRUE; - BOOL rOk = TRUE; - LONGLONG lVal = -1; - LONGLONG rVal = -1; - VARIANT rv,lv; - DWORD xmask; - HRESULT rc; - - TRACE("(%p->(%s%s),%p->(%s%s),0x%08lx,0x%08lx)\n", left, debugstr_VT(left), - debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), lcid, flags); - - VariantInit(&lv);VariantInit(&rv); - V_VT(right) &= ~0x8000; /* hack since we sometime get this flag. */ - V_VT(left) &= ~0x8000; /* hack since we sometime get this flag. */ - - /* If either are null, then return VARCMP_NULL */ - if ((V_VT(left)&VT_TYPEMASK) == VT_NULL || - (V_VT(right)&VT_TYPEMASK) == VT_NULL) - return VARCMP_NULL; - - /* Strings - use VarBstrCmp */ - if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR && - (V_VT(right)&VT_TYPEMASK) == VT_BSTR) { - return VarBstrCmp(V_BSTR(left), V_BSTR(right), lcid, flags); - } - - xmask = (1<<(V_VT(left)&VT_TYPEMASK))|(1<<(V_VT(right)&VT_TYPEMASK)); - if (xmask & VTBIT_R8) { - rc = VariantChangeType(&lv,left,0,VT_R8); - if (FAILED(rc)) return rc; - rc = VariantChangeType(&rv,right,0,VT_R8); - if (FAILED(rc)) return rc; - - if (V_R8(&lv) == V_R8(&rv)) return VARCMP_EQ; - if (V_R8(&lv) < V_R8(&rv)) return VARCMP_LT; - if (V_R8(&lv) > V_R8(&rv)) return VARCMP_GT; - return E_FAIL; /* can't get here */ - } - if (xmask & VTBIT_R4) { - rc = VariantChangeType(&lv,left,0,VT_R4); - if (FAILED(rc)) return rc; - rc = VariantChangeType(&rv,right,0,VT_R4); - if (FAILED(rc)) return rc; - - if (V_R4(&lv) == V_R4(&rv)) return VARCMP_EQ; - if (V_R4(&lv) < V_R4(&rv)) return VARCMP_LT; - if (V_R4(&lv) > V_R4(&rv)) return VARCMP_GT; - return E_FAIL; /* can't get here */ - } - - /* Integers - Ideally like to use VarDecCmp, but no Dec support yet - Use LONGLONG to maximize ranges */ - lOk = TRUE; - switch (V_VT(left)&VT_TYPEMASK) { - case VT_I1 : lVal = V_I1(left); break; - case VT_I2 : lVal = V_I2(left); break; - case VT_I4 : - case VT_INT : lVal = V_I4(left); break; - case VT_UI1 : lVal = V_UI1(left); break; - case VT_UI2 : lVal = V_UI2(left); break; - case VT_UI4 : - case VT_UINT : lVal = V_UI4(left); break; - case VT_BOOL : lVal = V_BOOL(left); break; - default: lOk = FALSE; - } - - rOk = TRUE; - switch (V_VT(right)&VT_TYPEMASK) { - case VT_I1 : rVal = V_I1(right); break; - case VT_I2 : rVal = V_I2(right); break; - case VT_I4 : - case VT_INT : rVal = V_I4(right); break; - case VT_UI1 : rVal = V_UI1(right); break; - case VT_UI2 : rVal = V_UI2(right); break; - case VT_UI4 : - case VT_UINT : rVal = V_UI4(right); break; - case VT_BOOL : rVal = V_BOOL(right); break; - default: rOk = FALSE; - } - - if (lOk && rOk) { - if (lVal < rVal) { - return VARCMP_LT; - } else if (lVal > rVal) { - return VARCMP_GT; - } else { - return VARCMP_EQ; - } - } - - /* Strings - use VarBstrCmp */ - if ((V_VT(left)&VT_TYPEMASK) == VT_DATE && - (V_VT(right)&VT_TYPEMASK) == VT_DATE) { - - if (floor(V_DATE(left)) == floor(V_DATE(right))) { - /* Due to floating point rounding errors, calculate varDate in whole numbers) */ - double wholePart = 0.0; - double leftR; - double rightR; - - /* Get the fraction * 24*60*60 to make it into whole seconds */ - wholePart = (double) floor( V_DATE(left) ); - if (wholePart == 0) wholePart = 1; - leftR = floor(fmod( V_DATE(left), wholePart ) * (24*60*60)); - - wholePart = (double) floor( V_DATE(right) ); - if (wholePart == 0) wholePart = 1; - rightR = floor(fmod( V_DATE(right), wholePart ) * (24*60*60)); - - if (leftR < rightR) { - return VARCMP_LT; - } else if (leftR > rightR) { - return VARCMP_GT; - } else { - return VARCMP_EQ; - } - - } else if (V_DATE(left) < V_DATE(right)) { - return VARCMP_LT; - } else if (V_DATE(left) > V_DATE(right)) { - return VARCMP_GT; - } - } - FIXME("VarCmp partial implementation, doesn't support vt 0x%x / 0x%x\n",V_VT(left), V_VT(right)); - return E_FAIL; -} - -/********************************************************************** - * VarAnd [OLEAUT32.142] - * - */ -HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result) -{ - HRESULT rc = E_FAIL; - - TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left), - debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), result); - - if ((V_VT(left)&VT_TYPEMASK) == VT_BOOL && - (V_VT(right)&VT_TYPEMASK) == VT_BOOL) { - - V_VT(result) = VT_BOOL; - if (V_BOOL(left) && V_BOOL(right)) { - V_BOOL(result) = VARIANT_TRUE; - } else { - V_BOOL(result) = VARIANT_FALSE; - } - rc = S_OK; - - } else { - /* Integers */ - BOOL lOk = TRUE; - BOOL rOk = TRUE; - LONGLONG lVal = -1; - LONGLONG rVal = -1; - LONGLONG res = -1; - int resT = 0; /* Testing has shown I2 & I2 == I2, all else - becomes I4, even unsigned ints (incl. UI2) */ - - lOk = TRUE; - switch (V_VT(left)&VT_TYPEMASK) { - case VT_I1 : lVal = V_I1(left); resT=VT_I4; break; - case VT_I2 : lVal = V_I2(left); resT=VT_I2; break; - case VT_I4 : - case VT_INT : lVal = V_I4(left); resT=VT_I4; break; - case VT_UI1 : lVal = V_UI1(left); resT=VT_I4; break; - case VT_UI2 : lVal = V_UI2(left); resT=VT_I4; break; - case VT_UI4 : - case VT_UINT : lVal = V_UI4(left); resT=VT_I4; break; - case VT_BOOL : rVal = V_BOOL(left); resT=VT_I4; break; - default: lOk = FALSE; - } - - rOk = TRUE; - switch (V_VT(right)&VT_TYPEMASK) { - case VT_I1 : rVal = V_I1(right); resT=VT_I4; break; - case VT_I2 : rVal = V_I2(right); resT=max(VT_I2, resT); break; - case VT_I4 : - case VT_INT : rVal = V_I4(right); resT=VT_I4; break; - case VT_UI1 : rVal = V_UI1(right); resT=VT_I4; break; - case VT_UI2 : rVal = V_UI2(right); resT=VT_I4; break; - case VT_UI4 : - case VT_UINT : rVal = V_UI4(right); resT=VT_I4; break; - case VT_BOOL : rVal = V_BOOL(right); resT=VT_I4; break; - default: rOk = FALSE; - } - - if (lOk && rOk) { - res = (lVal & rVal); - V_VT(result) = resT; - switch (resT) { - case VT_I2 : V_I2(result) = res; break; - case VT_I4 : V_I4(result) = res; break; - default: - FIXME("Unexpected result variant type %x\n", resT); - V_I4(result) = res; - } - rc = S_OK; - - } else { - FIXME("VarAnd stub\n"); - } - } - - TRACE("returning 0x%8lx (%s%s),%ld\n", rc, debugstr_VT(result), - debugstr_VF(result), V_VT(result) == VT_I4 ? V_I4(result) : V_I2(result)); - return rc; -} - -/********************************************************************** - * VarAdd [OLEAUT32.141] - * FIXME: From MSDN: If ... Then - * Both expressions are of the string type Concatenated. - * One expression is a string type and the other a character Addition. - * One expression is numeric and the other is a string Addition. - * Both expressions are numeric Addition. - * Either expression is NULL NULL is returned. - * Both expressions are empty Integer subtype is returned. - * - */ -HRESULT WINAPI VarAdd(LPVARIANT left, LPVARIANT right, LPVARIANT result) -{ - HRESULT rc = E_FAIL; - - TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left), - debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), result); - - if ((V_VT(left)&VT_TYPEMASK) == VT_EMPTY) - return VariantCopy(result,right); - - if ((V_VT(right)&VT_TYPEMASK) == VT_EMPTY) - return VariantCopy(result,left); - - /* check if we add doubles */ - if (((V_VT(left)&VT_TYPEMASK) == VT_R8) || ((V_VT(right)&VT_TYPEMASK) == VT_R8)) { - BOOL lOk = TRUE; - BOOL rOk = TRUE; - double lVal = -1; - double rVal = -1; - double res = -1; - - lOk = TRUE; - switch (V_VT(left)&VT_TYPEMASK) { - case VT_I1 : lVal = V_I1(left); break; - case VT_I2 : lVal = V_I2(left); break; - case VT_I4 : - case VT_INT : lVal = V_I4(left); break; - case VT_UI1 : lVal = V_UI1(left); break; - case VT_UI2 : lVal = V_UI2(left); break; - case VT_UI4 : - case VT_UINT : lVal = V_UI4(left); break; - case VT_R4 : lVal = V_R4(left); break; - case VT_R8 : lVal = V_R8(left); break; - case VT_NULL : lVal = 0.0; break; - default: lOk = FALSE; - } - - rOk = TRUE; - switch (V_VT(right)&VT_TYPEMASK) { - case VT_I1 : rVal = V_I1(right); break; - case VT_I2 : rVal = V_I2(right); break; - case VT_I4 : - case VT_INT : rVal = V_I4(right); break; - case VT_UI1 : rVal = V_UI1(right); break; - case VT_UI2 : rVal = V_UI2(right); break; - case VT_UI4 : - case VT_UINT : rVal = V_UI4(right); break; - case VT_R4 : rVal = V_R4(right);break; - case VT_R8 : rVal = V_R8(right);break; - case VT_NULL : rVal = 0.0; break; - default: rOk = FALSE; - } - - if (lOk && rOk) { - res = (lVal + rVal); - V_VT(result) = VT_R8; - V_R8(result) = res; - rc = S_OK; - } else { - FIXME("Unhandled type pair %d / %d in double addition.\n", - (V_VT(left)&VT_TYPEMASK), - (V_VT(right)&VT_TYPEMASK) - ); - } - return rc; - } - - /* now check if we add floats. VT_R8 can no longer happen here! */ - if (((V_VT(left)&VT_TYPEMASK) == VT_R4) || ((V_VT(right)&VT_TYPEMASK) == VT_R4)) { - BOOL lOk = TRUE; - BOOL rOk = TRUE; - float lVal = -1; - float rVal = -1; - float res = -1; - - lOk = TRUE; - switch (V_VT(left)&VT_TYPEMASK) { - case VT_I1 : lVal = V_I1(left); break; - case VT_I2 : lVal = V_I2(left); break; - case VT_I4 : - case VT_INT : lVal = V_I4(left); break; - case VT_UI1 : lVal = V_UI1(left); break; - case VT_UI2 : lVal = V_UI2(left); break; - case VT_UI4 : - case VT_UINT : lVal = V_UI4(left); break; - case VT_R4 : lVal = V_R4(left); break; - case VT_NULL : lVal = 0.0; break; - default: lOk = FALSE; - } - - rOk = TRUE; - switch (V_VT(right)&VT_TYPEMASK) { - case VT_I1 : rVal = V_I1(right); break; - case VT_I2 : rVal = V_I2(right); break; - case VT_I4 : - case VT_INT : rVal = V_I4(right); break; - case VT_UI1 : rVal = V_UI1(right); break; - case VT_UI2 : rVal = V_UI2(right); break; - case VT_UI4 : - case VT_UINT : rVal = V_UI4(right); break; - case VT_R4 : rVal = V_R4(right);break; - case VT_NULL : rVal = 0.0; break; - default: rOk = FALSE; - } - - if (lOk && rOk) { - res = (lVal + rVal); - V_VT(result) = VT_R4; - V_R4(result) = res; - rc = S_OK; - } else { - FIXME("Unhandled type pair %d / %d in float addition.\n", - (V_VT(left)&VT_TYPEMASK), - (V_VT(right)&VT_TYPEMASK) - ); - } - return rc; - } - - /* Handle strings as concat */ - if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR && - (V_VT(right)&VT_TYPEMASK) == VT_BSTR) { - V_VT(result) = VT_BSTR; - return VarBstrCat(V_BSTR(left), V_BSTR(right), &V_BSTR(result)); - } else { - - /* Integers */ - BOOL lOk = TRUE; - BOOL rOk = TRUE; - LONGLONG lVal = -1; - LONGLONG rVal = -1; - LONGLONG res = -1; - int resT = 0; /* Testing has shown I2 + I2 == I2, all else - becomes I4 */ - - lOk = TRUE; - switch (V_VT(left)&VT_TYPEMASK) { - case VT_I1 : lVal = V_I1(left); resT=VT_I4; break; - case VT_I2 : lVal = V_I2(left); resT=VT_I2; break; - case VT_I4 : - case VT_INT : lVal = V_I4(left); resT=VT_I4; break; - case VT_UI1 : lVal = V_UI1(left); resT=VT_I4; break; - case VT_UI2 : lVal = V_UI2(left); resT=VT_I4; break; - case VT_UI4 : - case VT_UINT : lVal = V_UI4(left); resT=VT_I4; break; - case VT_NULL : lVal = 0; resT = VT_I4; break; - default: lOk = FALSE; - } - - rOk = TRUE; - switch (V_VT(right)&VT_TYPEMASK) { - case VT_I1 : rVal = V_I1(right); resT=VT_I4; break; - case VT_I2 : rVal = V_I2(right); resT=max(VT_I2, resT); break; - case VT_I4 : - case VT_INT : rVal = V_I4(right); resT=VT_I4; break; - case VT_UI1 : rVal = V_UI1(right); resT=VT_I4; break; - case VT_UI2 : rVal = V_UI2(right); resT=VT_I4; break; - case VT_UI4 : - case VT_UINT : rVal = V_UI4(right); resT=VT_I4; break; - case VT_NULL : rVal = 0; resT=VT_I4; break; - default: rOk = FALSE; - } - - if (lOk && rOk) { - res = (lVal + rVal); - V_VT(result) = resT; - switch (resT) { - case VT_I2 : V_I2(result) = res; break; - case VT_I4 : V_I4(result) = res; break; - default: - FIXME("Unexpected result variant type %x\n", resT); - V_I4(result) = res; - } - rc = S_OK; - - } else { - FIXME("unimplemented part (0x%x + 0x%x)\n",V_VT(left), V_VT(right)); - } - } - - TRACE("returning 0x%8lx (%s%s),%ld\n", rc, debugstr_VT(result), - debugstr_VF(result), V_VT(result) == VT_I4 ? V_I4(result) : V_I2(result)); - return rc; -} - -/********************************************************************** - * VarMul [OLEAUT32.156] - * - * Multiply two variants. - * - * PARAMS - * left [I] First variant - * right [I] Second variant - * result [O] Result variant - * - * RETURNS - * Success: S_OK. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * Native VarMul up to and including WinXP dosn't like as input variants - * I1, UI2, UI4, UI8, INT and UINT. But it can multiply apples with oranges. - * - * Native VarMul dosn't check for NULL in/out pointers and crashes. We do the - * same here. - * - * FIXME - * Overflow checking for R8 (double) overflow. Return DISP_E_OVERFLOW in that - * case. - */ -HRESULT WINAPI VarMul(LPVARIANT left, LPVARIANT right, LPVARIANT result) -{ - HRESULT hres; - VARTYPE lvt, rvt, resvt, tvt; - VARIANT lv, rv, tv; - double r8res; - - /* Variant priority for coercion. Sorted from lowest to highest. - VT_ERROR shows an invalid input variant type. */ - enum coerceprio { vt_UI1 = 0, vt_I2, vt_I4, vt_I8, vt_CY, vt_R4, vt_R8, - vt_DECIMAL, vt_NULL, vt_ERROR }; - /* Mapping from priority to variant type. Keep in sync with coerceprio! */ - VARTYPE prio2vt[] = { VT_UI1, VT_I2, VT_I4, VT_I8, VT_CY, VT_R4, VT_R8, - VT_DECIMAL, VT_NULL, VT_ERROR }; - - /* Mapping for coercion from input variant to priority of result variant. */ - static VARTYPE coerce[] = { - /* VT_EMPTY, VT_NULL, VT_I2, VT_I4, VT_R4 */ - vt_UI1, vt_NULL, vt_I2, vt_I4, vt_R4, - /* VT_R8, VT_CY, VT_DATE, VT_BSTR, VT_DISPATCH */ - vt_R8, vt_CY, vt_R8, vt_R8, vt_ERROR, - /* VT_ERROR, VT_BOOL, VT_VARIANT, VT_UNKNOWN, VT_DECIMAL */ - vt_ERROR, vt_I2, vt_ERROR, vt_ERROR, vt_DECIMAL, - /* 15, VT_I1, VT_UI1, VT_UI2, VT_UI4 VT_I8 */ - vt_ERROR, vt_ERROR, vt_UI1, vt_ERROR, vt_ERROR, vt_I8 - }; - - TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left), - debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), - result); - - VariantInit(&lv); - VariantInit(&rv); - VariantInit(&tv); - lvt = V_VT(left)&VT_TYPEMASK; - rvt = V_VT(right)&VT_TYPEMASK; - - /* If we have any flag set (VT_ARRAY, VT_VECTOR, etc.) bail out. - Same for any input variant type > VT_I8 */ - if (V_VT(left) & ~VT_TYPEMASK || V_VT(right) & ~VT_TYPEMASK || - lvt > VT_I8 || rvt > VT_I8) { - hres = DISP_E_BADVARTYPE; - goto end; - } - - /* Determine the variant type to coerce to. */ - if (coerce[lvt] > coerce[rvt]) { - resvt = prio2vt[coerce[lvt]]; - tvt = prio2vt[coerce[rvt]]; - } else { - resvt = prio2vt[coerce[rvt]]; - tvt = prio2vt[coerce[lvt]]; - } - - /* Special cases where the result variant type is defined by both - input variants and not only that with the highest priority */ - if (resvt == VT_R4 && (tvt == VT_CY || tvt == VT_I8 || tvt == VT_I4)) - resvt = VT_R8; - if (lvt == VT_EMPTY && rvt == VT_EMPTY) - resvt = VT_I2; - - /* For overflow detection use the biggest compatible type for the - multiplication */ - switch (resvt) { - case VT_ERROR: - hres = DISP_E_BADVARTYPE; - goto end; - case VT_NULL: - hres = S_OK; - V_VT(result) = VT_NULL; - goto end; - case VT_UI1: - case VT_I2: - case VT_I4: - case VT_I8: - tvt = VT_I8; - break; - case VT_R4: - tvt = VT_R8; - break; - default: - tvt = resvt; - } - - /* Now coerce the variants */ - hres = VariantChangeType(&lv, left, 0, tvt); - if (FAILED(hres)) - goto end; - hres = VariantChangeType(&rv, right, 0, tvt); - if (FAILED(hres)) - goto end; - - /* Do the math */ - hres = S_OK; - V_VT(&tv) = tvt; - V_VT(result) = resvt; - switch (tvt) { - case VT_DECIMAL: - hres = VarDecMul(&V_DECIMAL(&lv), &V_DECIMAL(&rv), - &V_DECIMAL(result)); - goto end; - case VT_CY: - hres = VarCyMul(V_CY(&lv), V_CY(&rv), &V_CY(result)); - goto end; - case VT_I8: - /* Overflow detection */ - r8res = (double)V_I8(&lv) * (double)V_I8(&rv); - if (r8res > (double)I8_MAX || r8res < (double)I8_MIN) { - V_VT(result) = VT_R8; - V_R8(result) = r8res; - goto end; - } else - V_I8(&tv) = V_I8(&lv) * V_I8(&rv); - break; - case VT_R8: - /* FIXME: overflow detection */ - V_R8(&tv) = V_R8(&lv) * V_R8(&rv); - break; - default: - ERR("We shouldn't get here! tvt = %d!\n", tvt); - break; - } - if (rvt != tvt) { - while ((hres = VariantChangeType(result, &tv, 0, resvt)) != S_OK) { - /* Overflow! Change to the vartype with the next higher priority */ - resvt = prio2vt[coerce[resvt] + 1]; - } - } else - hres = VariantCopy(result, &tv); - -end: - if (hres != S_OK) { - V_VT(result) = VT_EMPTY; - V_I4(result) = 0; /* No V_EMPTY */ - } - VariantClear(&lv); - VariantClear(&rv); - VariantClear(&tv); - TRACE("returning 0x%8lx (variant type %s)\n", hres, debugstr_VT(result)); - return hres; -} - -/********************************************************************** - * VarDiv [OLEAUT32.143] - * - */ -HRESULT WINAPI VarDiv(LPVARIANT left, LPVARIANT right, LPVARIANT result) -{ - HRESULT rc = E_FAIL; - VARTYPE lvt,rvt,resvt; - VARIANT lv,rv; - BOOL found; - - TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left), - debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), result); - - VariantInit(&lv);VariantInit(&rv); - lvt = V_VT(left)&VT_TYPEMASK; - rvt = V_VT(right)&VT_TYPEMASK; - found = FALSE;resvt = VT_VOID; - if (((1<<lvt) | (1<<rvt)) & (VTBIT_R4|VTBIT_R8)) { - found = TRUE; - resvt = VT_R8; - } - if (!found && (((1<<lvt) | (1<<rvt)) & (VTBIT_I1|VTBIT_I2|VTBIT_UI1|VTBIT_UI2|VTBIT_I4|VTBIT_UI4|(1<<VT_INT)|(1<<VT_UINT)))) { - found = TRUE; - resvt = VT_I4; - } - if (!found) { - FIXME("can't expand vt %d vs %d to a target type.\n",lvt,rvt); - return E_FAIL; - } - rc = VariantChangeType(&lv, left, 0, resvt); - if (FAILED(rc)) { - FIXME("Could not convert 0x%x to %d?\n",V_VT(left),resvt); - return rc; - } - rc = VariantChangeType(&rv, right, 0, resvt); - if (FAILED(rc)) { - FIXME("Could not convert 0x%x to %d?\n",V_VT(right),resvt); - return rc; - } - switch (resvt) { - case VT_R8: - if (V_R8(&rv) == 0) return DISP_E_DIVBYZERO; - V_VT(result) = resvt; - V_R8(result) = V_R8(&lv) / V_R8(&rv); - rc = S_OK; - break; - case VT_I4: - if (V_I4(&rv) == 0) return DISP_E_DIVBYZERO; - V_VT(result) = resvt; - V_I4(result) = V_I4(&lv) / V_I4(&rv); - rc = S_OK; - break; - } - TRACE("returning 0x%8lx (%s%s),%g\n", rc, debugstr_VT(result), - debugstr_VF(result), V_VT(result) == VT_R8 ? V_R8(result) : (double)V_I4(result)); - return rc; -} - -/********************************************************************** - * VarSub [OLEAUT32.159] - * - */ -HRESULT WINAPI VarSub(LPVARIANT left, LPVARIANT right, LPVARIANT result) -{ - HRESULT rc = E_FAIL; - VARTYPE lvt,rvt,resvt; - VARIANT lv,rv; - BOOL found; - - TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left), - debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), result); - - VariantInit(&lv);VariantInit(&rv); - lvt = V_VT(left)&VT_TYPEMASK; - rvt = V_VT(right)&VT_TYPEMASK; - found = FALSE;resvt = VT_VOID; - if (((1<<lvt) | (1<<rvt)) & ((1<<VT_DATE)|(1<<VT_R4)|(1<<VT_R8))) { - found = TRUE; - resvt = VT_R8; - } - if (!found && (((1<<lvt) | (1<<rvt)) & (VTBIT_I1|VTBIT_I2|VTBIT_UI1|VTBIT_UI2|VTBIT_I4|VTBIT_UI4|(1<<VT_INT)|(1<<VT_UINT)))) { - found = TRUE; - resvt = VT_I4; - } - if (!found) { - FIXME("can't expand vt %d vs %d to a target type.\n",lvt,rvt); - return E_FAIL; - } - rc = VariantChangeType(&lv, left, 0, resvt); - if (FAILED(rc)) { - FIXME("Could not convert 0x%x to %d?\n",V_VT(left),resvt); - return rc; - } - rc = VariantChangeType(&rv, right, 0, resvt); - if (FAILED(rc)) { - FIXME("Could not convert 0x%x to %d?\n",V_VT(right),resvt); - return rc; - } - switch (resvt) { - case VT_R8: - V_VT(result) = resvt; - V_R8(result) = V_R8(&lv) - V_R8(&rv); - rc = S_OK; - break; - case VT_I4: - V_VT(result) = resvt; - V_I4(result) = V_I4(&lv) - V_I4(&rv); - rc = S_OK; - break; - } - TRACE("returning 0x%8lx (%s%s),%g\n", rc, debugstr_VT(result), - debugstr_VF(result), V_VT(result) == VT_R8 ? V_R8(result) : (double)V_I4(result)); - return rc; -} - -/********************************************************************** - * VarOr [OLEAUT32.157] - * - * Perform a logical or (OR) operation on two variants. - * - * PARAMS - * pVarLeft [I] First variant - * pVarRight [I] Variant to OR with pVarLeft - * pVarOut [O] Destination for OR result - * - * RETURNS - * Success: S_OK. pVarOut contains the result of the operation with its type - * taken from the table listed under VarXor(). - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * See the Notes section of VarXor() for further information. - */ -HRESULT WINAPI VarOr(LPVARIANT pVarLeft, LPVARIANT pVarRight, LPVARIANT pVarOut) -{ - VARTYPE vt = VT_I4; - VARIANT varLeft, varRight, varStr; - HRESULT hRet; - - TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", pVarLeft, debugstr_VT(pVarLeft), - debugstr_VF(pVarLeft), pVarRight, debugstr_VT(pVarRight), - debugstr_VF(pVarRight), pVarOut); - - if (V_EXTRA_TYPE(pVarLeft) || V_EXTRA_TYPE(pVarRight) || - V_VT(pVarLeft) == VT_UNKNOWN || V_VT(pVarRight) == VT_UNKNOWN || - V_VT(pVarLeft) == VT_DISPATCH || V_VT(pVarRight) == VT_DISPATCH || - V_VT(pVarLeft) == VT_RECORD || V_VT(pVarRight) == VT_RECORD) - return DISP_E_BADVARTYPE; - - V_VT(&varLeft) = V_VT(&varRight) = V_VT(&varStr) = VT_EMPTY; - - if (V_VT(pVarLeft) == VT_NULL || V_VT(pVarRight) == VT_NULL) - { - /* NULL OR Zero is NULL, NULL OR value is value */ - if (V_VT(pVarLeft) == VT_NULL) - pVarLeft = pVarRight; /* point to the non-NULL var */ - - V_VT(pVarOut) = VT_NULL; - V_I4(pVarOut) = 0; - - switch (V_VT(pVarLeft)) - { - case VT_DATE: case VT_R8: - if (V_R8(pVarLeft)) - goto VarOr_AsEmpty; - return S_OK; - case VT_BOOL: - if (V_BOOL(pVarLeft)) - *pVarOut = *pVarLeft; - return S_OK; - case VT_I2: case VT_UI2: - if (V_I2(pVarLeft)) - goto VarOr_AsEmpty; - return S_OK; - case VT_I1: - if (V_I1(pVarLeft)) - goto VarOr_AsEmpty; - return S_OK; - case VT_UI1: - if (V_UI1(pVarLeft)) - *pVarOut = *pVarLeft; - return S_OK; - case VT_R4: - if (V_R4(pVarLeft)) - goto VarOr_AsEmpty; - return S_OK; - case VT_I4: case VT_UI4: case VT_INT: case VT_UINT: - if (V_I4(pVarLeft)) - goto VarOr_AsEmpty; - return S_OK; - case VT_CY: - if (V_CY(pVarLeft).int64) - goto VarOr_AsEmpty; - return S_OK; - case VT_I8: case VT_UI8: - if (V_I8(pVarLeft)) - goto VarOr_AsEmpty; - return S_OK; - case VT_DECIMAL: - if (DEC_HI32(&V_DECIMAL(pVarLeft)) || DEC_LO64(&V_DECIMAL(pVarLeft))) - goto VarOr_AsEmpty; - return S_OK; - case VT_BSTR: - { - VARIANT_BOOL b; - - if (!V_BSTR(pVarLeft)) - return DISP_E_BADVARTYPE; - - hRet = VarBoolFromStr(V_BSTR(pVarLeft), LOCALE_USER_DEFAULT, VAR_LOCALBOOL, &b); - if (SUCCEEDED(hRet) && b) - { - V_VT(pVarOut) = VT_BOOL; - V_BOOL(pVarOut) = b; - } - return hRet; - } - case VT_NULL: case VT_EMPTY: - V_VT(pVarOut) = VT_NULL; - return S_OK; - default: - return DISP_E_BADVARTYPE; - } - } - - if (V_VT(pVarLeft) == VT_EMPTY || V_VT(pVarRight) == VT_EMPTY) - { - if (V_VT(pVarLeft) == VT_EMPTY) - pVarLeft = pVarRight; /* point to the non-EMPTY var */ - -VarOr_AsEmpty: - /* Since one argument is empty (0), OR'ing it with the other simply - * gives the others value (as 0|x => x). So just convert the other - * argument to the required result type. - */ - switch (V_VT(pVarLeft)) - { - case VT_BSTR: - if (!V_BSTR(pVarLeft)) - return DISP_E_BADVARTYPE; - - hRet = VariantCopy(&varStr, pVarLeft); - if (FAILED(hRet)) - goto VarOr_Exit; - pVarLeft = &varStr; - hRet = VariantChangeType(pVarLeft, pVarLeft, 0, VT_BOOL); - if (FAILED(hRet)) - goto VarOr_Exit; - /* Fall Through ... */ - case VT_EMPTY: case VT_UI1: case VT_BOOL: case VT_I2: - V_VT(pVarOut) = VT_I2; - break; - case VT_DATE: case VT_CY: case VT_DECIMAL: case VT_R4: case VT_R8: - case VT_I1: case VT_UI2: case VT_I4: case VT_UI4: - case VT_INT: case VT_UINT: case VT_UI8: - V_VT(pVarOut) = VT_I4; - break; - case VT_I8: - V_VT(pVarOut) = VT_I8; - break; - default: - return DISP_E_BADVARTYPE; - } - hRet = VariantCopy(&varLeft, pVarLeft); - if (FAILED(hRet)) - goto VarOr_Exit; - pVarLeft = &varLeft; - hRet = VariantChangeType(pVarOut, pVarLeft, 0, V_VT(pVarOut)); - goto VarOr_Exit; - } - - if (V_VT(pVarLeft) == VT_BOOL && V_VT(pVarRight) == VT_BOOL) - { - V_VT(pVarOut) = VT_BOOL; - V_BOOL(pVarOut) = V_BOOL(pVarLeft) | V_BOOL(pVarRight); - return S_OK; - } - - if (V_VT(pVarLeft) == VT_UI1 && V_VT(pVarRight) == VT_UI1) - { - V_VT(pVarOut) = VT_UI1; - V_UI1(pVarOut) = V_UI1(pVarLeft) | V_UI1(pVarRight); - return S_OK; - } - - if (V_VT(pVarLeft) == VT_BSTR) - { - hRet = VariantCopy(&varStr, pVarLeft); - if (FAILED(hRet)) - goto VarOr_Exit; - pVarLeft = &varStr; - hRet = VariantChangeType(pVarLeft, pVarLeft, 0, VT_BOOL); - if (FAILED(hRet)) - goto VarOr_Exit; - } - - if (V_VT(pVarLeft) == VT_BOOL && - (V_VT(pVarRight) == VT_BOOL || V_VT(pVarRight) == VT_BSTR)) - { - vt = VT_BOOL; - } - else if ((V_VT(pVarLeft) == VT_BOOL || V_VT(pVarLeft) == VT_UI1 || - V_VT(pVarLeft) == VT_I2 || V_VT(pVarLeft) == VT_BSTR) && - (V_VT(pVarRight) == VT_BOOL || V_VT(pVarRight) == VT_UI1 || - V_VT(pVarRight) == VT_I2 || V_VT(pVarRight) == VT_BSTR)) - { - vt = VT_I2; - } - else if (V_VT(pVarLeft) == VT_I8 || V_VT(pVarRight) == VT_I8) - { - if (V_VT(pVarLeft) == VT_INT || V_VT(pVarRight) == VT_INT) - return DISP_E_TYPEMISMATCH; - vt = VT_I8; - } - - hRet = VariantCopy(&varLeft, pVarLeft); - if (FAILED(hRet)) - goto VarOr_Exit; - - hRet = VariantCopy(&varRight, pVarRight); - if (FAILED(hRet)) - goto VarOr_Exit; - - if (vt == VT_I4 && V_VT(&varLeft) == VT_UI4) - V_VT(&varLeft) = VT_I4; /* Don't overflow */ - else - { - double d; - - if (V_VT(&varLeft) == VT_BSTR && - FAILED(VarR8FromStr(V_BSTR(&varLeft), LOCALE_USER_DEFAULT, 0, &d))) - hRet = VariantChangeType(&varLeft, &varLeft, VARIANT_LOCALBOOL, VT_BOOL); - if (SUCCEEDED(hRet) && V_VT(&varLeft) != vt) - hRet = VariantChangeType(&varLeft, &varLeft, 0, vt); - if (FAILED(hRet)) - goto VarOr_Exit; - } - - if (vt == VT_I4 && V_VT(&varRight) == VT_UI4) - V_VT(&varRight) = VT_I4; /* Don't overflow */ - else - { - double d; - - if (V_VT(&varRight) == VT_BSTR && - FAILED(VarR8FromStr(V_BSTR(&varRight), LOCALE_USER_DEFAULT, 0, &d))) - hRet = VariantChangeType(&varRight, &varRight, VARIANT_LOCALBOOL, VT_BOOL); - if (SUCCEEDED(hRet) && V_VT(&varRight) != vt) - hRet = VariantChangeType(&varRight, &varRight, 0, vt); - if (FAILED(hRet)) - goto VarOr_Exit; - } - - V_VT(pVarOut) = vt; - if (vt == VT_I8) - { - V_I8(pVarOut) = V_I8(&varLeft) | V_I8(&varRight); - } - else if (vt == VT_I4) - { - V_I4(pVarOut) = V_I4(&varLeft) | V_I4(&varRight); - } - else - { - V_I2(pVarOut) = V_I2(&varLeft) | V_I2(&varRight); - } - -VarOr_Exit: - VariantClear(&varStr); - VariantClear(&varLeft); - VariantClear(&varRight); - return hRet; -} - -/********************************************************************** - * VarAbs [OLEAUT32.168] - * - * Convert a variant to its absolute value. - * - * PARAMS - * pVarIn [I] Source variant - * pVarOut [O] Destination for converted value - * - * RETURNS - * Success: S_OK. pVarOut contains the absolute value of pVarIn. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * - This function does not process by-reference variants. - * - The type of the value stored in pVarOut depends on the type of pVarIn, - * according to the following table: - *| Input Type Output Type - *| ---------- ----------- - *| VT_BOOL VT_I2 - *| VT_BSTR VT_R8 - *| (All others) Unchanged - */ -HRESULT WINAPI VarAbs(LPVARIANT pVarIn, LPVARIANT pVarOut) -{ - VARIANT varIn; - HRESULT hRet = S_OK; - - TRACE("(%p->(%s%s),%p)\n", pVarIn, debugstr_VT(pVarIn), - debugstr_VF(pVarIn), pVarOut); - - if (V_ISARRAY(pVarIn) || V_VT(pVarIn) == VT_UNKNOWN || - V_VT(pVarIn) == VT_DISPATCH || V_VT(pVarIn) == VT_RECORD || - V_VT(pVarIn) == VT_ERROR) - return DISP_E_TYPEMISMATCH; - - *pVarOut = *pVarIn; /* Shallow copy the value, and invert it if needed */ - -#define ABS_CASE(typ,min) \ - case VT_##typ: if (V_##typ(pVarIn) == min) hRet = DISP_E_OVERFLOW; \ - else if (V_##typ(pVarIn) < 0) V_##typ(pVarOut) = -V_##typ(pVarIn); \ - break - - switch (V_VT(pVarIn)) - { - ABS_CASE(I1,I1_MIN); - case VT_BOOL: - V_VT(pVarOut) = VT_I2; - /* BOOL->I2, Fall through ... */ - ABS_CASE(I2,I2_MIN); - case VT_INT: - ABS_CASE(I4,I4_MIN); - ABS_CASE(I8,I8_MIN); - ABS_CASE(R4,R4_MIN); - case VT_BSTR: - hRet = VarR8FromStr(V_BSTR(pVarIn), LOCALE_USER_DEFAULT, 0, &V_R8(&varIn)); - if (FAILED(hRet)) - break; - V_VT(pVarOut) = VT_R8; - pVarIn = &varIn; - /* Fall through ... */ - case VT_DATE: - ABS_CASE(R8,R8_MIN); - case VT_CY: - hRet = VarCyAbs(V_CY(pVarIn), & V_CY(pVarOut)); - break; - case VT_DECIMAL: - DEC_SIGN(&V_DECIMAL(pVarOut)) &= ~DECIMAL_NEG; - break; - case VT_UI1: - case VT_UI2: - case VT_UINT: - case VT_UI4: - case VT_UI8: - /* No-Op */ - break; - case VT_EMPTY: - V_VT(pVarOut) = VT_I2; - case VT_NULL: - V_I2(pVarOut) = 0; - break; - default: - hRet = DISP_E_BADVARTYPE; - } - - return hRet; -} - -/********************************************************************** - * VarFix [OLEAUT32.169] - * - * Truncate a variants value to a whole number. - * - * PARAMS - * pVarIn [I] Source variant - * pVarOut [O] Destination for converted value - * - * RETURNS - * Success: S_OK. pVarOut contains the converted value. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * - The type of the value stored in pVarOut depends on the type of pVarIn, - * according to the following table: - *| Input Type Output Type - *| ---------- ----------- - *| VT_BOOL VT_I2 - *| VT_EMPTY VT_I2 - *| VT_BSTR VT_R8 - *| All Others Unchanged - * - The difference between this function and VarInt() is that VarInt() rounds - * negative numbers away from 0, while this function rounds them towards zero. - */ -HRESULT WINAPI VarFix(LPVARIANT pVarIn, LPVARIANT pVarOut) -{ - HRESULT hRet = S_OK; - - TRACE("(%p->(%s%s),%p)\n", pVarIn, debugstr_VT(pVarIn), - debugstr_VF(pVarIn), pVarOut); - - V_VT(pVarOut) = V_VT(pVarIn); - - switch (V_VT(pVarIn)) - { - case VT_UI1: - V_UI1(pVarOut) = V_UI1(pVarIn); - break; - case VT_BOOL: - V_VT(pVarOut) = VT_I2; - /* Fall through */ - case VT_I2: - V_I2(pVarOut) = V_I2(pVarIn); - break; - case VT_I4: - V_I4(pVarOut) = V_I4(pVarIn); - break; - case VT_I8: - V_I8(pVarOut) = V_I8(pVarIn); - break; - case VT_R4: - if (V_R4(pVarIn) < 0.0f) - V_R4(pVarOut) = (float)ceil(V_R4(pVarIn)); - else - V_R4(pVarOut) = (float)floor(V_R4(pVarIn)); - break; - case VT_BSTR: - V_VT(pVarOut) = VT_R8; - hRet = VarR8FromStr(V_BSTR(pVarIn), LOCALE_USER_DEFAULT, 0, &V_R8(pVarOut)); - pVarIn = pVarOut; - /* Fall through */ - case VT_DATE: - case VT_R8: - if (V_R8(pVarIn) < 0.0) - V_R8(pVarOut) = ceil(V_R8(pVarIn)); - else - V_R8(pVarOut) = floor(V_R8(pVarIn)); - break; - case VT_CY: - hRet = VarCyFix(V_CY(pVarIn), &V_CY(pVarOut)); - break; - case VT_DECIMAL: - hRet = VarDecFix(&V_DECIMAL(pVarIn), &V_DECIMAL(pVarOut)); - break; - case VT_EMPTY: - V_VT(pVarOut) = VT_I2; - V_I2(pVarOut) = 0; - break; - case VT_NULL: - /* No-Op */ - break; - default: - if (V_TYPE(pVarIn) == VT_CLSID || /* VT_CLSID is a special case */ - FAILED(VARIANT_ValidateType(V_VT(pVarIn)))) - hRet = DISP_E_BADVARTYPE; - else - hRet = DISP_E_TYPEMISMATCH; - } - if (FAILED(hRet)) - V_VT(pVarOut) = VT_EMPTY; - - return hRet; -} - -/********************************************************************** - * VarInt [OLEAUT32.172] - * - * Truncate a variants value to a whole number. - * - * PARAMS - * pVarIn [I] Source variant - * pVarOut [O] Destination for converted value - * - * RETURNS - * Success: S_OK. pVarOut contains the converted value. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * - The type of the value stored in pVarOut depends on the type of pVarIn, - * according to the following table: - *| Input Type Output Type - *| ---------- ----------- - *| VT_BOOL VT_I2 - *| VT_EMPTY VT_I2 - *| VT_BSTR VT_R8 - *| All Others Unchanged - * - The difference between this function and VarFix() is that VarFix() rounds - * negative numbers towards 0, while this function rounds them away from zero. - */ -HRESULT WINAPI VarInt(LPVARIANT pVarIn, LPVARIANT pVarOut) -{ - HRESULT hRet = S_OK; - - TRACE("(%p->(%s%s),%p)\n", pVarIn, debugstr_VT(pVarIn), - debugstr_VF(pVarIn), pVarOut); - - V_VT(pVarOut) = V_VT(pVarIn); - - switch (V_VT(pVarIn)) - { - case VT_R4: - V_R4(pVarOut) = (float)floor(V_R4(pVarIn)); - break; - case VT_BSTR: - V_VT(pVarOut) = VT_R8; - hRet = VarR8FromStr(V_BSTR(pVarIn), LOCALE_USER_DEFAULT, 0, &V_R8(pVarOut)); - pVarIn = pVarOut; - /* Fall through */ - case VT_DATE: - case VT_R8: - V_R8(pVarOut) = floor(V_R8(pVarIn)); - break; - case VT_CY: - hRet = VarCyInt(V_CY(pVarIn), &V_CY(pVarOut)); - break; - case VT_DECIMAL: - hRet = VarDecInt(&V_DECIMAL(pVarIn), &V_DECIMAL(pVarOut)); - break; - default: - return VarFix(pVarIn, pVarOut); - } - - return hRet; -} - -/********************************************************************** - * VarXor [OLEAUT32.167] - * - * Perform a logical exclusive-or (XOR) operation on two variants. - * - * PARAMS - * pVarLeft [I] First variant - * pVarRight [I] Variant to XOR with pVarLeft - * pVarOut [O] Destination for XOR result - * - * RETURNS - * Success: S_OK. pVarOut contains the result of the operation with its type - * taken from the table below). - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * - Neither pVarLeft or pVarRight are modified by this function. - * - This function does not process by-reference variants. - * - Input types of VT_BSTR may be numeric strings or boolean text. - * - The type of result stored in pVarOut depends on the types of pVarLeft - * and pVarRight, and will be one of VT_UI1, VT_I2, VT_I4, VT_I8, VT_BOOL, - * or VT_NULL if the function succeeds. - * - Type promotion is inconsistent and as a result certain combinations of - * values will return DISP_E_OVERFLOW even when they could be represented. - * This matches the behaviour of native oleaut32. - */ -HRESULT WINAPI VarXor(LPVARIANT pVarLeft, LPVARIANT pVarRight, LPVARIANT pVarOut) -{ - VARTYPE vt; - VARIANT varLeft, varRight; - double d; - HRESULT hRet; - - TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", pVarLeft, debugstr_VT(pVarLeft), - debugstr_VF(pVarLeft), pVarRight, debugstr_VT(pVarRight), - debugstr_VF(pVarRight), pVarOut); - - if (V_EXTRA_TYPE(pVarLeft) || V_EXTRA_TYPE(pVarRight) || - V_VT(pVarLeft) > VT_UINT || V_VT(pVarRight) > VT_UINT || - V_VT(pVarLeft) == VT_VARIANT || V_VT(pVarRight) == VT_VARIANT || - V_VT(pVarLeft) == VT_UNKNOWN || V_VT(pVarRight) == VT_UNKNOWN || - V_VT(pVarLeft) == (VARTYPE)15 || V_VT(pVarRight) == (VARTYPE)15 || - V_VT(pVarLeft) == VT_ERROR || V_VT(pVarRight) == VT_ERROR) - return DISP_E_BADVARTYPE; - - if (V_VT(pVarLeft) == VT_NULL || V_VT(pVarRight) == VT_NULL) - { - /* NULL XOR anything valid is NULL */ - V_VT(pVarOut) = VT_NULL; - return S_OK; - } - - /* Copy our inputs so we don't disturb anything */ - V_VT(&varLeft) = V_VT(&varRight) = VT_EMPTY; - - hRet = VariantCopy(&varLeft, pVarLeft); - if (FAILED(hRet)) - goto VarXor_Exit; - - hRet = VariantCopy(&varRight, pVarRight); - if (FAILED(hRet)) - goto VarXor_Exit; - - /* Try any strings first as numbers, then as VT_BOOL */ - if (V_VT(&varLeft) == VT_BSTR) - { - hRet = VarR8FromStr(V_BSTR(&varLeft), LOCALE_USER_DEFAULT, 0, &d); - hRet = VariantChangeType(&varLeft, &varLeft, VARIANT_LOCALBOOL, - FAILED(hRet) ? VT_BOOL : VT_I4); - if (FAILED(hRet)) - goto VarXor_Exit; - } - - if (V_VT(&varRight) == VT_BSTR) - { - hRet = VarR8FromStr(V_BSTR(&varRight), LOCALE_USER_DEFAULT, 0, &d); - hRet = VariantChangeType(&varRight, &varRight, VARIANT_LOCALBOOL, - FAILED(hRet) ? VT_BOOL : VT_I4); - if (FAILED(hRet)) - goto VarXor_Exit; - } - - /* Determine the result type */ - if (V_VT(&varLeft) == VT_I8 || V_VT(&varRight) == VT_I8) - { - if (V_VT(pVarLeft) == VT_INT || V_VT(pVarRight) == VT_INT) - return DISP_E_TYPEMISMATCH; - vt = VT_I8; - } - else - { - switch ((V_VT(&varLeft) << 16) | V_VT(&varRight)) - { - case (VT_BOOL << 16) | VT_BOOL: - vt = VT_BOOL; - break; - case (VT_UI1 << 16) | VT_UI1: - vt = VT_UI1; - break; - case (VT_EMPTY << 16) | VT_EMPTY: - case (VT_EMPTY << 16) | VT_UI1: - case (VT_EMPTY << 16) | VT_I2: - case (VT_EMPTY << 16) | VT_BOOL: - case (VT_UI1 << 16) | VT_EMPTY: - case (VT_UI1 << 16) | VT_I2: - case (VT_UI1 << 16) | VT_BOOL: - case (VT_I2 << 16) | VT_EMPTY: - case (VT_I2 << 16) | VT_UI1: - case (VT_I2 << 16) | VT_I2: - case (VT_I2 << 16) | VT_BOOL: - case (VT_BOOL << 16) | VT_EMPTY: - case (VT_BOOL << 16) | VT_UI1: - case (VT_BOOL << 16) | VT_I2: - vt = VT_I2; - break; - default: - vt = VT_I4; - break; - } - } - - /* VT_UI4 does not overflow */ - if (vt != VT_I8) - { - if (V_VT(&varLeft) == VT_UI4) - V_VT(&varLeft) = VT_I4; - if (V_VT(&varRight) == VT_UI4) - V_VT(&varRight) = VT_I4; - } - - /* Convert our input copies to the result type */ - if (V_VT(&varLeft) != vt) - hRet = VariantChangeType(&varLeft, &varLeft, 0, vt); - if (FAILED(hRet)) - goto VarXor_Exit; - - if (V_VT(&varRight) != vt) - hRet = VariantChangeType(&varRight, &varRight, 0, vt); - if (FAILED(hRet)) - goto VarXor_Exit; - - V_VT(pVarOut) = vt; - - /* Calculate the result */ - switch (vt) - { - case VT_I8: - V_I8(pVarOut) = V_I8(&varLeft) ^ V_I8(&varRight); - break; - case VT_I4: - V_I4(pVarOut) = V_I4(&varLeft) ^ V_I4(&varRight); - break; - case VT_BOOL: - case VT_I2: - V_I2(pVarOut) = V_I2(&varLeft) ^ V_I2(&varRight); - break; - case VT_UI1: - V_UI1(pVarOut) = V_UI1(&varLeft) ^ V_UI1(&varRight); - break; - } - -VarXor_Exit: - VariantClear(&varLeft); - VariantClear(&varRight); - return hRet; -} - -/********************************************************************** - * VarEqv [OLEAUT32.172] - * - * Determine if two variants contain the same value. - * - * PARAMS - * pVarLeft [I] First variant to compare - * pVarRight [I] Variant to compare to pVarLeft - * pVarOut [O] Destination for comparison result - * - * RETURNS - * Success: S_OK. pVarOut contains the result of the comparison (VARIANT_TRUE - * if equivalent or non-zero otherwise. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * - This function simply calls VarXor() on pVarLeft and pVarRight and inverts - * the result. - */ -HRESULT WINAPI VarEqv(LPVARIANT pVarLeft, LPVARIANT pVarRight, LPVARIANT pVarOut) -{ - HRESULT hRet; - - TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", pVarLeft, debugstr_VT(pVarLeft), - debugstr_VF(pVarLeft), pVarRight, debugstr_VT(pVarRight), - debugstr_VF(pVarRight), pVarOut); - - hRet = VarXor(pVarLeft, pVarRight, pVarOut); - if (SUCCEEDED(hRet)) - { - if (V_VT(pVarOut) == VT_I8) - V_I8(pVarOut) = ~V_I8(pVarOut); - else - V_UI4(pVarOut) = ~V_UI4(pVarOut); - } - return hRet; -} - -/********************************************************************** - * VarNeg [OLEAUT32.173] - * - * Negate the value of a variant. - * - * PARAMS - * pVarIn [I] Source variant - * pVarOut [O] Destination for converted value - * - * RETURNS - * Success: S_OK. pVarOut contains the converted value. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * - The type of the value stored in pVarOut depends on the type of pVarIn, - * according to the following table: - *| Input Type Output Type - *| ---------- ----------- - *| VT_EMPTY VT_I2 - *| VT_UI1 VT_I2 - *| VT_BOOL VT_I2 - *| VT_BSTR VT_R8 - *| All Others Unchanged (unless promoted) - * - Where the negated value of a variant does not fit in its base type, the type - * is promoted according to the following table: - *| Input Type Promoted To - *| ---------- ----------- - *| VT_I2 VT_I4 - *| VT_I4 VT_R8 - *| VT_I8 VT_R8 - * - The native version of this function returns DISP_E_BADVARTYPE for valid - * variant types that cannot be negated, and returns DISP_E_TYPEMISMATCH - * for types which are not valid. Since this is in contravention of the - * meaning of those error codes and unlikely to be relied on by applications, - * this implementation returns errors consistent with the other high level - * variant math functions. - */ -HRESULT WINAPI VarNeg(LPVARIANT pVarIn, LPVARIANT pVarOut) -{ - HRESULT hRet = S_OK; - - TRACE("(%p->(%s%s),%p)\n", pVarIn, debugstr_VT(pVarIn), - debugstr_VF(pVarIn), pVarOut); - - V_VT(pVarOut) = V_VT(pVarIn); - - switch (V_VT(pVarIn)) - { - case VT_UI1: - V_VT(pVarOut) = VT_I2; - V_I2(pVarOut) = -V_UI1(pVarIn); - break; - case VT_BOOL: - V_VT(pVarOut) = VT_I2; - /* Fall through */ - case VT_I2: - if (V_I2(pVarIn) == I2_MIN) - { - V_VT(pVarOut) = VT_I4; - V_I4(pVarOut) = -(int)V_I2(pVarIn); - } - else - V_I2(pVarOut) = -V_I2(pVarIn); - break; - case VT_I4: - if (V_I4(pVarIn) == I4_MIN) - { - V_VT(pVarOut) = VT_R8; - V_R8(pVarOut) = -(double)V_I4(pVarIn); - } - else - V_I4(pVarOut) = -V_I4(pVarIn); - break; - case VT_I8: - if (V_I8(pVarIn) == I8_MIN) - { - V_VT(pVarOut) = VT_R8; - hRet = VarR8FromI8(V_I8(pVarIn), &V_R8(pVarOut)); - V_R8(pVarOut) *= -1.0; - } - else - V_I8(pVarOut) = -V_I8(pVarIn); - break; - case VT_R4: - V_R4(pVarOut) = -V_R4(pVarIn); - break; - case VT_DATE: - case VT_R8: - V_R8(pVarOut) = -V_R8(pVarIn); - break; - case VT_CY: - hRet = VarCyNeg(V_CY(pVarIn), &V_CY(pVarOut)); - break; - case VT_DECIMAL: - hRet = VarDecNeg(&V_DECIMAL(pVarIn), &V_DECIMAL(pVarOut)); - break; - case VT_BSTR: - V_VT(pVarOut) = VT_R8; - hRet = VarR8FromStr(V_BSTR(pVarIn), LOCALE_USER_DEFAULT, 0, &V_R8(pVarOut)); - V_R8(pVarOut) = -V_R8(pVarOut); - break; - case VT_EMPTY: - V_VT(pVarOut) = VT_I2; - V_I2(pVarOut) = 0; - break; - case VT_NULL: - /* No-Op */ - break; - default: - if (V_TYPE(pVarIn) == VT_CLSID || /* VT_CLSID is a special case */ - FAILED(VARIANT_ValidateType(V_VT(pVarIn)))) - hRet = DISP_E_BADVARTYPE; - else - hRet = DISP_E_TYPEMISMATCH; - } - if (FAILED(hRet)) - V_VT(pVarOut) = VT_EMPTY; - - return hRet; -} - -/********************************************************************** - * VarNot [OLEAUT32.174] - * - * Perform a not operation on a variant. - * - * PARAMS - * pVarIn [I] Source variant - * pVarOut [O] Destination for converted value - * - * RETURNS - * Success: S_OK. pVarOut contains the converted value. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * - Strictly speaking, this function performs a bitwise ones complement - * on the variants value (after possibly converting to VT_I4, see below). - * This only behaves like a boolean not operation if the value in - * pVarIn is either VARIANT_TRUE or VARIANT_FALSE and the type is signed. - * - To perform a genuine not operation, convert the variant to a VT_BOOL - * before calling this function. - * - This function does not process by-reference variants. - * - The type of the value stored in pVarOut depends on the type of pVarIn, - * according to the following table: - *| Input Type Output Type - *| ---------- ----------- - *| VT_EMPTY VT_I2 - *| VT_R4 VT_I4 - *| VT_R8 VT_I4 - *| VT_BSTR VT_I4 - *| VT_DECIMAL VT_I4 - *| VT_CY VT_I4 - *| (All others) Unchanged - */ -HRESULT WINAPI VarNot(LPVARIANT pVarIn, LPVARIANT pVarOut) -{ - VARIANT varIn; - HRESULT hRet = S_OK; - - TRACE("(%p->(%s%s),%p)\n", pVarIn, debugstr_VT(pVarIn), - debugstr_VF(pVarIn), pVarOut); - - V_VT(pVarOut) = V_VT(pVarIn); - - switch (V_VT(pVarIn)) - { - case VT_I1: - V_I4(pVarOut) = ~V_I1(pVarIn); - V_VT(pVarOut) = VT_I4; - break; - case VT_UI1: V_UI1(pVarOut) = ~V_UI1(pVarIn); break; - case VT_BOOL: - case VT_I2: V_I2(pVarOut) = ~V_I2(pVarIn); break; - case VT_UI2: - V_I4(pVarOut) = ~V_UI2(pVarIn); - V_VT(pVarOut) = VT_I4; - break; - case VT_DECIMAL: - hRet = VarI4FromDec(&V_DECIMAL(pVarIn), &V_I4(&varIn)); - if (FAILED(hRet)) - break; - pVarIn = &varIn; - /* Fall through ... */ - case VT_INT: - V_VT(pVarOut) = VT_I4; - /* Fall through ... */ - case VT_I4: V_I4(pVarOut) = ~V_I4(pVarIn); break; - case VT_UINT: - case VT_UI4: - V_I4(pVarOut) = ~V_UI4(pVarIn); - V_VT(pVarOut) = VT_I4; - break; - case VT_I8: V_I8(pVarOut) = ~V_I8(pVarIn); break; - case VT_UI8: - V_I4(pVarOut) = ~V_UI8(pVarIn); - V_VT(pVarOut) = VT_I4; - break; - case VT_R4: - hRet = VarI4FromR4(V_R4(pVarIn), &V_I4(pVarOut)); - V_I4(pVarOut) = ~V_I4(pVarOut); - V_VT(pVarOut) = VT_I4; - break; - case VT_BSTR: - hRet = VarR8FromStr(V_BSTR(pVarIn), LOCALE_USER_DEFAULT, 0, &V_R8(&varIn)); - if (FAILED(hRet)) - break; - pVarIn = &varIn; - /* Fall through ... */ - case VT_DATE: - case VT_R8: - hRet = VarI4FromR8(V_R8(pVarIn), &V_I4(pVarOut)); - V_I4(pVarOut) = ~V_I4(pVarOut); - V_VT(pVarOut) = VT_I4; - break; - case VT_CY: - hRet = VarI4FromCy(V_CY(pVarIn), &V_I4(pVarOut)); - V_I4(pVarOut) = ~V_I4(pVarOut); - V_VT(pVarOut) = VT_I4; - break; - case VT_EMPTY: - V_I2(pVarOut) = ~0; - V_VT(pVarOut) = VT_I2; - break; - case VT_NULL: - /* No-Op */ - break; - default: - if (V_TYPE(pVarIn) == VT_CLSID || /* VT_CLSID is a special case */ - FAILED(VARIANT_ValidateType(V_VT(pVarIn)))) - hRet = DISP_E_BADVARTYPE; - else - hRet = DISP_E_TYPEMISMATCH; - } - if (FAILED(hRet)) - V_VT(pVarOut) = VT_EMPTY; - - return hRet; -} - -/********************************************************************** - * VarRound [OLEAUT32.175] - * - * Perform a round operation on a variant. - * - * PARAMS - * pVarIn [I] Source variant - * deci [I] Number of decimals to round to - * pVarOut [O] Destination for converted value - * - * RETURNS - * Success: S_OK. pVarOut contains the converted value. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * - Floating point values are rounded to the desired number of decimals. - * - Some integer types are just copied to the return variable. - * - Some other integer types are not handled and fail. - */ -HRESULT WINAPI VarRound(LPVARIANT pVarIn, int deci, LPVARIANT pVarOut) -{ - VARIANT varIn; - HRESULT hRet = S_OK; - float factor; - - TRACE("(%p->(%s%s),%d)\n", pVarIn, debugstr_VT(pVarIn), debugstr_VF(pVarIn), deci); - - switch (V_VT(pVarIn)) - { - /* cases that fail on windows */ - case VT_I1: - case VT_I8: - case VT_UI2: - case VT_UI4: - hRet = DISP_E_BADVARTYPE; - break; - - /* cases just copying in to out */ - case VT_UI1: - V_VT(pVarOut) = V_VT(pVarIn); - V_UI1(pVarOut) = V_UI1(pVarIn); - break; - case VT_I2: - V_VT(pVarOut) = V_VT(pVarIn); - V_I2(pVarOut) = V_I2(pVarIn); - break; - case VT_I4: - V_VT(pVarOut) = V_VT(pVarIn); - V_I4(pVarOut) = V_I4(pVarIn); - break; - case VT_NULL: - V_VT(pVarOut) = V_VT(pVarIn); - /* value unchanged */ - break; - - /* cases that change type */ - case VT_EMPTY: - V_VT(pVarOut) = VT_I2; - V_I2(pVarOut) = 0; - break; - case VT_BOOL: - V_VT(pVarOut) = VT_I2; - V_I2(pVarOut) = V_BOOL(pVarIn); - break; - case VT_BSTR: - hRet = VarR8FromStr(V_BSTR(pVarIn), LOCALE_USER_DEFAULT, 0, &V_R8(&varIn)); - if (FAILED(hRet)) - break; - V_VT(&varIn)=VT_R8; - pVarIn = &varIn; - /* Fall through ... */ - - /* cases we need to do math */ - case VT_R8: - if (V_R8(pVarIn)>0) { - V_R8(pVarOut)=floor(V_R8(pVarIn)*pow(10, deci)+0.5)/pow(10, deci); - } else { - V_R8(pVarOut)=ceil(V_R8(pVarIn)*pow(10, deci)-0.5)/pow(10, deci); - } - V_VT(pVarOut) = V_VT(pVarIn); - break; - case VT_R4: - if (V_R4(pVarIn)>0) { - V_R4(pVarOut)=floor(V_R4(pVarIn)*pow(10, deci)+0.5)/pow(10, deci); - } else { - V_R4(pVarOut)=ceil(V_R4(pVarIn)*pow(10, deci)-0.5)/pow(10, deci); - } - V_VT(pVarOut) = V_VT(pVarIn); - break; - case VT_DATE: - if (V_DATE(pVarIn)>0) { - V_DATE(pVarOut)=floor(V_DATE(pVarIn)*pow(10, deci)+0.5)/pow(10, deci); - } else { - V_DATE(pVarOut)=ceil(V_DATE(pVarIn)*pow(10, deci)-0.5)/pow(10, deci); - } - V_VT(pVarOut) = V_VT(pVarIn); - break; - case VT_CY: - if (deci>3) - factor=1; - else - factor=pow(10, 4-deci); - - if (V_CY(pVarIn).int64>0) { - V_CY(pVarOut).int64=floor(V_CY(pVarIn).int64/factor)*factor; - } else { - V_CY(pVarOut).int64=ceil(V_CY(pVarIn).int64/factor)*factor; - } - V_VT(pVarOut) = V_VT(pVarIn); - break; - - /* cases we don't know yet */ - default: - FIXME("unimplemented part, V_VT(pVarIn) == 0x%X, deci == %d\n", - V_VT(pVarIn) & VT_TYPEMASK, deci); - hRet = DISP_E_BADVARTYPE; - } - - if (FAILED(hRet)) - V_VT(pVarOut) = VT_EMPTY; - - TRACE("returning 0x%08lx (%s%s),%f\n", hRet, debugstr_VT(pVarOut), - debugstr_VF(pVarOut), (V_VT(pVarOut) == VT_R4) ? V_R4(pVarOut) : - (V_VT(pVarOut) == VT_R8) ? V_R8(pVarOut) : 0); - - return hRet; -} - -/********************************************************************** - * VarIdiv [OLEAUT32.153] - * - * Converts input variants to integers and divides them. - * - * PARAMS - * left [I] Left hand variant - * right [I] Right hand variant - * result [O] Destination for quotient - * - * RETURNS - * Success: S_OK. result contains the quotient. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * If either expression is null, null is returned, as per MSDN - */ -HRESULT WINAPI VarIdiv(LPVARIANT left, LPVARIANT right, LPVARIANT result) -{ - VARIANT lv, rv; - HRESULT hr; - - VariantInit(&lv); - VariantInit(&rv); - - if ((V_VT(left) == VT_NULL) || (V_VT(right) == VT_NULL)) { - hr = VariantChangeType(result, result, 0, VT_NULL); - if (FAILED(hr)) { - /* This should never happen */ - FIXME("Failed to convert return value to VT_NULL.\n"); - return hr; - } - return S_OK; - } - - hr = VariantChangeType(&lv, left, 0, VT_I4); - if (FAILED(hr)) { - return hr; - } - hr = VariantChangeType(&rv, right, 0, VT_I4); - if (FAILED(hr)) { - return hr; - } - - hr = VarDiv(&lv, &rv, result); - return hr; -} - - -/********************************************************************** - * VarMod [OLEAUT32.155] - * - * Perform the modulus operation of the right hand variant on the left - * - * PARAMS - * left [I] Left hand variant - * right [I] Right hand variant - * result [O] Destination for converted value - * - * RETURNS - * Success: S_OK. result contains the remainder. - * Failure: An HRESULT error code indicating the error. - * - * NOTE: - * If an error occurs the type of result will be modified but the value will not be. - * Doesn't support arrays or any special flags yet. - */ -HRESULT WINAPI VarMod(LPVARIANT left, LPVARIANT right, LPVARIANT result) -{ - BOOL lOk = TRUE; - BOOL rOk = TRUE; - HRESULT rc = E_FAIL; - int resT = 0; - VARIANT lv,rv; - - VariantInit(&lv); - VariantInit(&rv); - - TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left), - debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), result); - - /* check for invalid inputs */ - lOk = TRUE; - switch (V_VT(left) & VT_TYPEMASK) { - case VT_BOOL : - case VT_I1 : - case VT_I2 : - case VT_I4 : - case VT_I8 : - case VT_INT : - case VT_UI1 : - case VT_UI2 : - case VT_UI4 : - case VT_UI8 : - case VT_UINT : - case VT_R4 : - case VT_R8 : - case VT_CY : - case VT_EMPTY: - case VT_DATE : - case VT_BSTR : - break; - case VT_VARIANT: - case VT_UNKNOWN: - V_VT(result) = VT_EMPTY; - return DISP_E_TYPEMISMATCH; - case VT_DECIMAL: - V_VT(result) = VT_EMPTY; - return DISP_E_OVERFLOW; - case VT_ERROR: - return DISP_E_TYPEMISMATCH; - case VT_RECORD: - V_VT(result) = VT_EMPTY; - return DISP_E_TYPEMISMATCH; - case VT_NULL: - break; - default: - V_VT(result) = VT_EMPTY; - return DISP_E_BADVARTYPE; - } - - - rOk = TRUE; - switch (V_VT(right) & VT_TYPEMASK) { - case VT_BOOL : - case VT_I1 : - case VT_I2 : - case VT_I4 : - case VT_I8 : - if((V_VT(left) == VT_INT) && (V_VT(right) == VT_I8)) - { - V_VT(result) = VT_EMPTY; - return DISP_E_TYPEMISMATCH; - } - case VT_INT : - if((V_VT(right) == VT_INT) && (V_VT(left) == VT_I8)) - { - V_VT(result) = VT_EMPTY; - return DISP_E_TYPEMISMATCH; - } - case VT_UI1 : - case VT_UI2 : - case VT_UI4 : - case VT_UI8 : - case VT_UINT : - case VT_R4 : - case VT_R8 : - case VT_CY : - if(V_VT(left) == VT_EMPTY) - { - V_VT(result) = VT_I4; - return S_OK; - } - case VT_EMPTY: - case VT_DATE : - case VT_BSTR: - if(V_VT(left) == VT_NULL) - { - V_VT(result) = VT_NULL; - return S_OK; - } - break; - - case VT_VOID: - V_VT(result) = VT_EMPTY; - return DISP_E_BADVARTYPE; - case VT_NULL: - if(V_VT(left) == VT_VOID) - { - V_VT(result) = VT_EMPTY; - return DISP_E_BADVARTYPE; - } else if((V_VT(left) == VT_NULL) || (V_VT(left) == VT_EMPTY) || (V_VT(left) == VT_ERROR) || - lOk) - { - V_VT(result) = VT_NULL; - return S_OK; - } else - { - V_VT(result) = VT_NULL; - return DISP_E_BADVARTYPE; - } - case VT_VARIANT: - case VT_UNKNOWN: - V_VT(result) = VT_EMPTY; - return DISP_E_TYPEMISMATCH; - case VT_DECIMAL: - if(V_VT(left) == VT_ERROR) - { - V_VT(result) = VT_EMPTY; - return DISP_E_TYPEMISMATCH; - } else - { - V_VT(result) = VT_EMPTY; - return DISP_E_OVERFLOW; - } - case VT_ERROR: - return DISP_E_TYPEMISMATCH; - case VT_RECORD: - if((V_VT(left) == 15) || ((V_VT(left) >= 24) && (V_VT(left) <= 35)) || !lOk) - { - V_VT(result) = VT_EMPTY; - return DISP_E_BADVARTYPE; - } else - { - V_VT(result) = VT_EMPTY; - return DISP_E_TYPEMISMATCH; - } - default: - V_VT(result) = VT_EMPTY; - return DISP_E_BADVARTYPE; - } - - /* determine the result type */ - if((V_VT(left) == VT_I8) || (V_VT(right) == VT_I8)) resT = VT_I8; - else if((V_VT(left) == VT_UI1) && (V_VT(right) == VT_BOOL)) resT = VT_I2; - else if((V_VT(left) == VT_UI1) && (V_VT(right) == VT_UI1)) resT = VT_UI1; - else if((V_VT(left) == VT_UI1) && (V_VT(right) == VT_I2)) resT = VT_I2; - else if((V_VT(left) == VT_I2) && (V_VT(right) == VT_BOOL)) resT = VT_I2; - else if((V_VT(left) == VT_I2) && (V_VT(right) == VT_UI1)) resT = VT_I2; - else if((V_VT(left) == VT_I2) && (V_VT(right) == VT_I2)) resT = VT_I2; - else if((V_VT(left) == VT_BOOL) && (V_VT(right) == VT_BOOL)) resT = VT_I2; - else if((V_VT(left) == VT_BOOL) && (V_VT(right) == VT_UI1)) resT = VT_I2; - else if((V_VT(left) == VT_BOOL) && (V_VT(right) == VT_I2)) resT = VT_I2; - else resT = VT_I4; /* most outputs are I4 */ - - /* convert to I8 for the modulo */ - rc = VariantChangeType(&lv, left, 0, VT_I8); - if(FAILED(rc)) - { - FIXME("Could not convert left type %d to %d? rc == 0x%lX\n", V_VT(left), VT_I8, rc); - return rc; - } - - rc = VariantChangeType(&rv, right, 0, VT_I8); - if(FAILED(rc)) - { - FIXME("Could not convert right type %d to %d? rc == 0x%lX\n", V_VT(right), VT_I8, rc); - return rc; - } - - /* if right is zero set VT_EMPTY and return divide by zero */ - if(V_I8(&rv) == 0) - { - V_VT(result) = VT_EMPTY; - return DISP_E_DIVBYZERO; - } - - /* perform the modulo operation */ - V_VT(result) = VT_I8; - V_I8(result) = V_I8(&lv) % V_I8(&rv); - - TRACE("V_I8(left) == %ld, V_I8(right) == %ld, V_I8(result) == %ld\n", (long)V_I8(&lv), (long)V_I8(&rv), (long)V_I8(result)); - - /* convert left and right to the destination type */ - rc = VariantChangeType(result, result, 0, resT); - if(FAILED(rc)) - { - FIXME("Could not convert 0x%x to %d?\n", V_VT(result), resT); - return rc; - } - - return S_OK; -} - -/********************************************************************** - * VarPow [OLEAUT32.158] - * - */ -HRESULT WINAPI VarPow(LPVARIANT left, LPVARIANT right, LPVARIANT result) -{ - HRESULT hr; - VARIANT dl,dr; - - TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left), debugstr_VF(left), - right, debugstr_VT(right), debugstr_VF(right), result); - - hr = VariantChangeType(&dl,left,0,VT_R8); - if (!SUCCEEDED(hr)) { - ERR("Could not change passed left argument to VT_R8, handle it differently.\n"); - return E_FAIL; - } - hr = VariantChangeType(&dr,right,0,VT_R8); - if (!SUCCEEDED(hr)) { - ERR("Could not change passed right argument to VT_R8, handle it differently.\n"); - return E_FAIL; - } - V_VT(result) = VT_R8; - V_R8(result) = pow(V_R8(&dl),V_R8(&dr)); - return S_OK; -} +/* + * VARIANT + * + * Copyright 1998 Jean-Claude Cote + * Copyright 2003 Jon Griffiths + * Copyright 2005 Daniel Remenak + * + * The alorithm for conversion from Julian days to day/month/year is based on + * that devised by Henry Fliegel, as implemented in PostgreSQL, which is + * Copyright 1994-7 Regents of the University of California + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "wine/unicode.h" +#include "winerror.h" +#include "variant.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(variant); + +const char* wine_vtypes[VT_CLSID] = +{ + "VT_EMPTY","VT_NULL","VT_I2","VT_I4","VT_R4","VT_R8","VT_CY","VT_DATE", + "VT_BSTR","VT_DISPATCH","VT_ERROR","VT_BOOL","VT_VARIANT","VT_UNKNOWN", + "VT_DECIMAL","15","VT_I1","VT_UI1","VT_UI2","VT_UI4","VT_I8","VT_UI8", + "VT_INT","VT_UINT","VT_VOID","VT_HRESULT","VT_PTR","VT_SAFEARRAY", + "VT_CARRAY","VT_USERDEFINED","VT_LPSTR","VT_LPWSTR""32","33","34","35", + "VT_RECORD","VT_INT_PTR","VT_UINT_PTR","39","40","41","42","43","44","45", + "46","47","48","49","50","51","52","53","54","55","56","57","58","59","60", + "61","62","63","VT_FILETIME","VT_BLOB","VT_STREAM","VT_STORAGE", + "VT_STREAMED_OBJECT","VT_STORED_OBJECT","VT_BLOB_OBJECT","VT_CF","VT_CLSID" +}; + +const char* wine_vflags[16] = +{ + "", + "|VT_VECTOR", + "|VT_ARRAY", + "|VT_VECTOR|VT_ARRAY", + "|VT_BYREF", + "|VT_VECTOR|VT_ARRAY", + "|VT_ARRAY|VT_BYREF", + "|VT_VECTOR|VT_ARRAY|VT_BYREF", + "|VT_HARDTYPE", + "|VT_VECTOR|VT_HARDTYPE", + "|VT_ARRAY|VT_HARDTYPE", + "|VT_VECTOR|VT_ARRAY|VT_HARDTYPE", + "|VT_BYREF|VT_HARDTYPE", + "|VT_VECTOR|VT_ARRAY|VT_HARDTYPE", + "|VT_ARRAY|VT_BYREF|VT_HARDTYPE", + "|VT_VECTOR|VT_ARRAY|VT_BYREF|VT_HARDTYPE", +}; + +/* Convert a variant from one type to another */ +static inline HRESULT VARIANT_Coerce(VARIANTARG* pd, LCID lcid, USHORT wFlags, + VARIANTARG* ps, VARTYPE vt) +{ + HRESULT res = DISP_E_TYPEMISMATCH; + VARTYPE vtFrom = V_TYPE(ps); + BOOL bIgnoreOverflow = FALSE; + DWORD dwFlags = 0; + + TRACE("(%p->(%s%s),0x%08lx,0x%04x,%p->(%s%s),%s%s)\n", pd, debugstr_VT(pd), + debugstr_VF(pd), lcid, wFlags, ps, debugstr_VT(ps), debugstr_VF(ps), + debugstr_vt(vt), debugstr_vf(vt)); + + if (vt == VT_BSTR || vtFrom == VT_BSTR) + { + /* All flags passed to low level function are only used for + * changing to or from strings. Map these here. + */ + if (wFlags & VARIANT_LOCALBOOL) + dwFlags |= VAR_LOCALBOOL; + if (wFlags & VARIANT_CALENDAR_HIJRI) + dwFlags |= VAR_CALENDAR_HIJRI; + if (wFlags & VARIANT_CALENDAR_THAI) + dwFlags |= VAR_CALENDAR_THAI; + if (wFlags & VARIANT_CALENDAR_GREGORIAN) + dwFlags |= VAR_CALENDAR_GREGORIAN; + if (wFlags & VARIANT_NOUSEROVERRIDE) + dwFlags |= LOCALE_NOUSEROVERRIDE; + if (wFlags & VARIANT_USE_NLS) + dwFlags |= LOCALE_USE_NLS; + } + + /* Map int/uint to i4/ui4 */ + if (vt == VT_INT) + vt = VT_I4; + else if (vt == VT_UINT) + vt = VT_UI4; + + if (vtFrom == VT_INT) + vtFrom = VT_I4; + else if (vtFrom == VT_UINT) + { + vtFrom = VT_UI4; + if (vt == VT_I4) + bIgnoreOverflow = TRUE; + } + + if (vt == vtFrom) + return VariantCopy(pd, ps); + + if (wFlags & VARIANT_NOVALUEPROP && vtFrom == VT_DISPATCH && vt != VT_UNKNOWN) + { + /* VARIANT_NOVALUEPROP prevents IDispatch objects from being coerced by + * accessing the default object property. + */ + return DISP_E_TYPEMISMATCH; + } + + switch (vt) + { + case VT_EMPTY: + if (vtFrom == VT_NULL) + return DISP_E_TYPEMISMATCH; + /* ... Fall through */ + case VT_NULL: + if (vtFrom <= VT_UINT && vtFrom != (VARTYPE)15 && vtFrom != VT_ERROR) + { + res = VariantClear( pd ); + if (vt == VT_NULL && SUCCEEDED(res)) + V_VT(pd) = VT_NULL; + } + return res; + + case VT_I1: + switch (vtFrom) + { + case VT_EMPTY: V_I1(pd) = 0; return S_OK; + case VT_I2: return VarI1FromI2(V_I2(ps), &V_I1(pd)); + case VT_I4: return VarI1FromI4(V_I4(ps), &V_I1(pd)); + case VT_UI1: return VarI1FromUI1(V_UI1(ps), &V_I1(pd)); + case VT_UI2: return VarI1FromUI2(V_UI2(ps), &V_I1(pd)); + case VT_UI4: return VarI1FromUI4(V_UI4(ps), &V_I1(pd)); + case VT_I8: return VarI1FromI8(V_I8(ps), &V_I1(pd)); + case VT_UI8: return VarI1FromUI8(V_UI8(ps), &V_I1(pd)); + case VT_R4: return VarI1FromR4(V_R4(ps), &V_I1(pd)); + case VT_R8: return VarI1FromR8(V_R8(ps), &V_I1(pd)); + case VT_DATE: return VarI1FromDate(V_DATE(ps), &V_I1(pd)); + case VT_BOOL: return VarI1FromBool(V_BOOL(ps), &V_I1(pd)); + case VT_CY: return VarI1FromCy(V_CY(ps), &V_I1(pd)); + case VT_DECIMAL: return VarI1FromDec(&V_DECIMAL(ps), &V_I1(pd) ); + case VT_DISPATCH: return VarI1FromDisp(V_DISPATCH(ps), lcid, &V_I1(pd) ); + case VT_BSTR: return VarI1FromStr(V_BSTR(ps), lcid, dwFlags, &V_I1(pd) ); + } + break; + + case VT_I2: + switch (vtFrom) + { + case VT_EMPTY: V_I2(pd) = 0; return S_OK; + case VT_I1: return VarI2FromI1(V_I1(ps), &V_I2(pd)); + case VT_I4: return VarI2FromI4(V_I4(ps), &V_I2(pd)); + case VT_UI1: return VarI2FromUI1(V_UI1(ps), &V_I2(pd)); + case VT_UI2: return VarI2FromUI2(V_UI2(ps), &V_I2(pd)); + case VT_UI4: return VarI2FromUI4(V_UI4(ps), &V_I2(pd)); + case VT_I8: return VarI2FromI8(V_I8(ps), &V_I2(pd)); + case VT_UI8: return VarI2FromUI8(V_UI8(ps), &V_I2(pd)); + case VT_R4: return VarI2FromR4(V_R4(ps), &V_I2(pd)); + case VT_R8: return VarI2FromR8(V_R8(ps), &V_I2(pd)); + case VT_DATE: return VarI2FromDate(V_DATE(ps), &V_I2(pd)); + case VT_BOOL: return VarI2FromBool(V_BOOL(ps), &V_I2(pd)); + case VT_CY: return VarI2FromCy(V_CY(ps), &V_I2(pd)); + case VT_DECIMAL: return VarI2FromDec(&V_DECIMAL(ps), &V_I2(pd)); + case VT_DISPATCH: return VarI2FromDisp(V_DISPATCH(ps), lcid, &V_I2(pd)); + case VT_BSTR: return VarI2FromStr(V_BSTR(ps), lcid, dwFlags, &V_I2(pd)); + } + break; + + case VT_I4: + switch (vtFrom) + { + case VT_EMPTY: V_I4(pd) = 0; return S_OK; + case VT_I1: return VarI4FromI1(V_I1(ps), &V_I4(pd)); + case VT_I2: return VarI4FromI2(V_I2(ps), &V_I4(pd)); + case VT_UI1: return VarI4FromUI1(V_UI1(ps), &V_I4(pd)); + case VT_UI2: return VarI4FromUI2(V_UI2(ps), &V_I4(pd)); + case VT_UI4: + if (bIgnoreOverflow) + { + V_VT(pd) = VT_I4; + V_I4(pd) = V_I4(ps); + return S_OK; + } + return VarI4FromUI4(V_UI4(ps), &V_I4(pd)); + case VT_I8: return VarI4FromI8(V_I8(ps), &V_I4(pd)); + case VT_UI8: return VarI4FromUI8(V_UI8(ps), &V_I4(pd)); + case VT_R4: return VarI4FromR4(V_R4(ps), &V_I4(pd)); + case VT_R8: return VarI4FromR8(V_R8(ps), &V_I4(pd)); + case VT_DATE: return VarI4FromDate(V_DATE(ps), &V_I4(pd)); + case VT_BOOL: return VarI4FromBool(V_BOOL(ps), &V_I4(pd)); + case VT_CY: return VarI4FromCy(V_CY(ps), &V_I4(pd)); + case VT_DECIMAL: return VarI4FromDec(&V_DECIMAL(ps), &V_I4(pd)); + case VT_DISPATCH: return VarI4FromDisp(V_DISPATCH(ps), lcid, &V_I4(pd)); + case VT_BSTR: return VarI4FromStr(V_BSTR(ps), lcid, dwFlags, &V_I4(pd)); + } + break; + + case VT_UI1: + switch (vtFrom) + { + case VT_EMPTY: V_UI1(pd) = 0; return S_OK; + case VT_I1: return VarUI1FromI1(V_I1(ps), &V_UI1(pd)); + case VT_I2: return VarUI1FromI2(V_I2(ps), &V_UI1(pd)); + case VT_I4: return VarUI1FromI4(V_I4(ps), &V_UI1(pd)); + case VT_UI2: return VarUI1FromUI2(V_UI2(ps), &V_UI1(pd)); + case VT_UI4: return VarUI1FromUI4(V_UI4(ps), &V_UI1(pd)); + case VT_I8: return VarUI1FromI8(V_I8(ps), &V_UI1(pd)); + case VT_UI8: return VarUI1FromUI8(V_UI8(ps), &V_UI1(pd)); + case VT_R4: return VarUI1FromR4(V_R4(ps), &V_UI1(pd)); + case VT_R8: return VarUI1FromR8(V_R8(ps), &V_UI1(pd)); + case VT_DATE: return VarUI1FromDate(V_DATE(ps), &V_UI1(pd)); + case VT_BOOL: return VarUI1FromBool(V_BOOL(ps), &V_UI1(pd)); + case VT_CY: return VarUI1FromCy(V_CY(ps), &V_UI1(pd)); + case VT_DECIMAL: return VarUI1FromDec(&V_DECIMAL(ps), &V_UI1(pd)); + case VT_DISPATCH: return VarUI1FromDisp(V_DISPATCH(ps), lcid, &V_UI1(pd)); + case VT_BSTR: return VarUI1FromStr(V_BSTR(ps), lcid, dwFlags, &V_UI1(pd)); + } + break; + + case VT_UI2: + switch (vtFrom) + { + case VT_EMPTY: V_UI2(pd) = 0; return S_OK; + case VT_I1: return VarUI2FromI1(V_I1(ps), &V_UI2(pd)); + case VT_I2: return VarUI2FromI2(V_I2(ps), &V_UI2(pd)); + case VT_I4: return VarUI2FromI4(V_I4(ps), &V_UI2(pd)); + case VT_UI1: return VarUI2FromUI1(V_UI1(ps), &V_UI2(pd)); + case VT_UI4: return VarUI2FromUI4(V_UI4(ps), &V_UI2(pd)); + case VT_I8: return VarUI4FromI8(V_I8(ps), &V_UI4(pd)); + case VT_UI8: return VarUI4FromUI8(V_UI8(ps), &V_UI4(pd)); + case VT_R4: return VarUI2FromR4(V_R4(ps), &V_UI2(pd)); + case VT_R8: return VarUI2FromR8(V_R8(ps), &V_UI2(pd)); + case VT_DATE: return VarUI2FromDate(V_DATE(ps), &V_UI2(pd)); + case VT_BOOL: return VarUI2FromBool(V_BOOL(ps), &V_UI2(pd)); + case VT_CY: return VarUI2FromCy(V_CY(ps), &V_UI2(pd)); + case VT_DECIMAL: return VarUI2FromDec(&V_DECIMAL(ps), &V_UI2(pd)); + case VT_DISPATCH: return VarUI2FromDisp(V_DISPATCH(ps), lcid, &V_UI2(pd)); + case VT_BSTR: return VarUI2FromStr(V_BSTR(ps), lcid, dwFlags, &V_UI2(pd)); + } + break; + + case VT_UI4: + switch (vtFrom) + { + case VT_EMPTY: V_UI4(pd) = 0; return S_OK; + case VT_I1: return VarUI4FromI1(V_I1(ps), &V_UI4(pd)); + case VT_I2: return VarUI4FromI2(V_I2(ps), &V_UI4(pd)); + case VT_I4: return VarUI4FromI4(V_I4(ps), &V_UI4(pd)); + case VT_UI1: return VarUI4FromUI1(V_UI1(ps), &V_UI4(pd)); + case VT_UI2: return VarUI4FromUI2(V_UI2(ps), &V_UI4(pd)); + case VT_I8: return VarUI4FromI8(V_I8(ps), &V_UI4(pd)); + case VT_UI8: return VarUI4FromUI8(V_UI8(ps), &V_UI4(pd)); + case VT_R4: return VarUI4FromR4(V_R4(ps), &V_UI4(pd)); + case VT_R8: return VarUI4FromR8(V_R8(ps), &V_UI4(pd)); + case VT_DATE: return VarUI4FromDate(V_DATE(ps), &V_UI4(pd)); + case VT_BOOL: return VarUI4FromBool(V_BOOL(ps), &V_UI4(pd)); + case VT_CY: return VarUI4FromCy(V_CY(ps), &V_UI4(pd)); + case VT_DECIMAL: return VarUI4FromDec(&V_DECIMAL(ps), &V_UI4(pd)); + case VT_DISPATCH: return VarUI4FromDisp(V_DISPATCH(ps), lcid, &V_UI4(pd)); + case VT_BSTR: return VarUI4FromStr(V_BSTR(ps), lcid, dwFlags, &V_UI4(pd)); + } + break; + + case VT_UI8: + switch (vtFrom) + { + case VT_EMPTY: V_UI8(pd) = 0; return S_OK; + case VT_I4: if (V_I4(ps) < 0) return DISP_E_OVERFLOW; V_UI8(pd) = V_I4(ps); return S_OK; + case VT_I1: return VarUI8FromI1(V_I1(ps), &V_UI8(pd)); + case VT_I2: return VarUI8FromI2(V_I2(ps), &V_UI8(pd)); + case VT_UI1: return VarUI8FromUI1(V_UI1(ps), &V_UI8(pd)); + case VT_UI2: return VarUI8FromUI2(V_UI2(ps), &V_UI8(pd)); + case VT_UI4: return VarUI8FromUI4(V_UI4(ps), &V_UI8(pd)); + case VT_I8: return VarUI8FromI8(V_I8(ps), &V_UI8(pd)); + case VT_R4: return VarUI8FromR4(V_R4(ps), &V_UI8(pd)); + case VT_R8: return VarUI8FromR8(V_R8(ps), &V_UI8(pd)); + case VT_DATE: return VarUI8FromDate(V_DATE(ps), &V_UI8(pd)); + case VT_BOOL: return VarUI8FromBool(V_BOOL(ps), &V_UI8(pd)); + case VT_CY: return VarUI8FromCy(V_CY(ps), &V_UI8(pd)); + case VT_DECIMAL: return VarUI8FromDec(&V_DECIMAL(ps), &V_UI8(pd)); + case VT_DISPATCH: return VarUI8FromDisp(V_DISPATCH(ps), lcid, &V_UI8(pd)); + case VT_BSTR: return VarUI8FromStr(V_BSTR(ps), lcid, dwFlags, &V_UI8(pd)); + } + break; + + case VT_I8: + switch (vtFrom) + { + case VT_EMPTY: V_I8(pd) = 0; return S_OK; + case VT_I4: V_I8(pd) = V_I4(ps); return S_OK; + case VT_I1: return VarI8FromI1(V_I1(ps), &V_I8(pd)); + case VT_I2: return VarI8FromI2(V_I2(ps), &V_I8(pd)); + case VT_UI1: return VarI8FromUI1(V_UI1(ps), &V_I8(pd)); + case VT_UI2: return VarI8FromUI2(V_UI2(ps), &V_I8(pd)); + case VT_UI4: return VarI8FromUI4(V_UI4(ps), &V_I8(pd)); + case VT_UI8: return VarI8FromUI8(V_I8(ps), &V_I8(pd)); + case VT_R4: return VarI8FromR4(V_R4(ps), &V_I8(pd)); + case VT_R8: return VarI8FromR8(V_R8(ps), &V_I8(pd)); + case VT_DATE: return VarI8FromDate(V_DATE(ps), &V_I8(pd)); + case VT_BOOL: return VarI8FromBool(V_BOOL(ps), &V_I8(pd)); + case VT_CY: return VarI8FromCy(V_CY(ps), &V_I8(pd)); + case VT_DECIMAL: return VarI8FromDec(&V_DECIMAL(ps), &V_I8(pd)); + case VT_DISPATCH: return VarI8FromDisp(V_DISPATCH(ps), lcid, &V_I8(pd)); + case VT_BSTR: return VarI8FromStr(V_BSTR(ps), lcid, dwFlags, &V_I8(pd)); + } + break; + + case VT_R4: + switch (vtFrom) + { + case VT_EMPTY: V_R4(pd) = 0.0f; return S_OK; + case VT_I1: return VarR4FromI1(V_I1(ps), &V_R4(pd)); + case VT_I2: return VarR4FromI2(V_I2(ps), &V_R4(pd)); + case VT_I4: return VarR4FromI4(V_I4(ps), &V_R4(pd)); + case VT_UI1: return VarR4FromUI1(V_UI1(ps), &V_R4(pd)); + case VT_UI2: return VarR4FromUI2(V_UI2(ps), &V_R4(pd)); + case VT_UI4: return VarR4FromUI4(V_UI4(ps), &V_R4(pd)); + case VT_I8: return VarR4FromI8(V_I8(ps), &V_R4(pd)); + case VT_UI8: return VarR4FromUI8(V_UI8(ps), &V_R4(pd)); + case VT_R8: return VarR4FromR8(V_R8(ps), &V_R4(pd)); + case VT_DATE: return VarR4FromDate(V_DATE(ps), &V_R4(pd)); + case VT_BOOL: return VarR4FromBool(V_BOOL(ps), &V_R4(pd)); + case VT_CY: return VarR4FromCy(V_CY(ps), &V_R4(pd)); + case VT_DECIMAL: return VarR4FromDec(&V_DECIMAL(ps), &V_R4(pd)); + case VT_DISPATCH: return VarR4FromDisp(V_DISPATCH(ps), lcid, &V_R4(pd)); + case VT_BSTR: return VarR4FromStr(V_BSTR(ps), lcid, dwFlags, &V_R4(pd)); + } + break; + + case VT_R8: + switch (vtFrom) + { + case VT_EMPTY: V_R8(pd) = 0.0; return S_OK; + case VT_I1: return VarR8FromI1(V_I1(ps), &V_R8(pd)); + case VT_I2: return VarR8FromI2(V_I2(ps), &V_R8(pd)); + case VT_I4: return VarR8FromI4(V_I4(ps), &V_R8(pd)); + case VT_UI1: return VarR8FromUI1(V_UI1(ps), &V_R8(pd)); + case VT_UI2: return VarR8FromUI2(V_UI2(ps), &V_R8(pd)); + case VT_UI4: return VarR8FromUI4(V_UI4(ps), &V_R8(pd)); + case VT_I8: return VarR8FromI8(V_I8(ps), &V_R8(pd)); + case VT_UI8: return VarR8FromUI8(V_UI8(ps), &V_R8(pd)); + case VT_R4: return VarR8FromR4(V_R4(ps), &V_R8(pd)); + case VT_DATE: return VarR8FromDate(V_DATE(ps), &V_R8(pd)); + case VT_BOOL: return VarR8FromBool(V_BOOL(ps), &V_R8(pd)); + case VT_CY: return VarR8FromCy(V_CY(ps), &V_R8(pd)); + case VT_DECIMAL: return VarR8FromDec(&V_DECIMAL(ps), &V_R8(pd)); + case VT_DISPATCH: return VarR8FromDisp(V_DISPATCH(ps), lcid, &V_R8(pd)); + case VT_BSTR: return VarR8FromStr(V_BSTR(ps), lcid, dwFlags, &V_R8(pd)); + } + break; + + case VT_DATE: + switch (vtFrom) + { + case VT_EMPTY: V_DATE(pd) = 0.0; return S_OK; + case VT_I1: return VarDateFromI1(V_I1(ps), &V_DATE(pd)); + case VT_I2: return VarDateFromI2(V_I2(ps), &V_DATE(pd)); + case VT_I4: return VarDateFromI4(V_I4(ps), &V_DATE(pd)); + case VT_UI1: return VarDateFromUI1(V_UI1(ps), &V_DATE(pd)); + case VT_UI2: return VarDateFromUI2(V_UI2(ps), &V_DATE(pd)); + case VT_UI4: return VarDateFromUI4(V_UI4(ps), &V_DATE(pd)); + case VT_I8: return VarDateFromI8(V_I8(ps), &V_DATE(pd)); + case VT_UI8: return VarDateFromUI8(V_UI8(ps), &V_DATE(pd)); + case VT_R4: return VarDateFromR4(V_R4(ps), &V_DATE(pd)); + case VT_R8: return VarDateFromR8(V_R8(ps), &V_DATE(pd)); + case VT_BOOL: return VarDateFromBool(V_BOOL(ps), &V_DATE(pd)); + case VT_CY: return VarDateFromCy(V_CY(ps), &V_DATE(pd)); + case VT_DECIMAL: return VarDateFromDec(&V_DECIMAL(ps), &V_DATE(pd)); + case VT_DISPATCH: return VarDateFromDisp(V_DISPATCH(ps), lcid, &V_DATE(pd)); + case VT_BSTR: return VarDateFromStr(V_BSTR(ps), lcid, dwFlags, &V_DATE(pd)); + } + break; + + case VT_BOOL: + switch (vtFrom) + { + case VT_EMPTY: V_BOOL(pd) = 0; return S_OK; + case VT_I1: return VarBoolFromI1(V_I1(ps), &V_BOOL(pd)); + case VT_I2: return VarBoolFromI2(V_I2(ps), &V_BOOL(pd)); + case VT_I4: return VarBoolFromI4(V_I4(ps), &V_BOOL(pd)); + case VT_UI1: return VarBoolFromUI1(V_UI1(ps), &V_BOOL(pd)); + case VT_UI2: return VarBoolFromUI2(V_UI2(ps), &V_BOOL(pd)); + case VT_UI4: return VarBoolFromUI4(V_UI4(ps), &V_BOOL(pd)); + case VT_I8: return VarBoolFromI8(V_I8(ps), &V_BOOL(pd)); + case VT_UI8: return VarBoolFromUI8(V_UI8(ps), &V_BOOL(pd)); + case VT_R4: return VarBoolFromR4(V_R4(ps), &V_BOOL(pd)); + case VT_R8: return VarBoolFromR8(V_R8(ps), &V_BOOL(pd)); + case VT_DATE: return VarBoolFromDate(V_DATE(ps), &V_BOOL(pd)); + case VT_CY: return VarBoolFromCy(V_CY(ps), &V_BOOL(pd)); + case VT_DECIMAL: return VarBoolFromDec(&V_DECIMAL(ps), &V_BOOL(pd)); + case VT_DISPATCH: return VarBoolFromDisp(V_DISPATCH(ps), lcid, &V_BOOL(pd)); + case VT_BSTR: return VarBoolFromStr(V_BSTR(ps), lcid, dwFlags, &V_BOOL(pd)); + } + break; + + case VT_BSTR: + switch (vtFrom) + { + case VT_EMPTY: + V_BSTR(pd) = SysAllocStringLen(NULL, 0); + return V_BSTR(pd) ? S_OK : E_OUTOFMEMORY; + case VT_BOOL: + if (wFlags & (VARIANT_ALPHABOOL|VARIANT_LOCALBOOL)) + return VarBstrFromBool(V_BOOL(ps), lcid, dwFlags, &V_BSTR(pd)); + return VarBstrFromI2(V_BOOL(ps), lcid, dwFlags, &V_BSTR(pd)); + case VT_I1: return VarBstrFromI1(V_I1(ps), lcid, dwFlags, &V_BSTR(pd)); + case VT_I2: return VarBstrFromI2(V_I2(ps), lcid, dwFlags, &V_BSTR(pd)); + case VT_I4: return VarBstrFromI4(V_I4(ps), lcid, dwFlags, &V_BSTR(pd)); + case VT_UI1: return VarBstrFromUI1(V_UI1(ps), lcid, dwFlags, &V_BSTR(pd)); + case VT_UI2: return VarBstrFromUI2(V_UI2(ps), lcid, dwFlags, &V_BSTR(pd)); + case VT_UI4: return VarBstrFromUI4(V_UI4(ps), lcid, dwFlags, &V_BSTR(pd)); + case VT_I8: return VarBstrFromI8(V_I8(ps), lcid, dwFlags, &V_BSTR(pd)); + case VT_UI8: return VarBstrFromUI8(V_UI8(ps), lcid, dwFlags, &V_BSTR(pd)); + case VT_R4: return VarBstrFromR4(V_R4(ps), lcid, dwFlags, &V_BSTR(pd)); + case VT_R8: return VarBstrFromR8(V_R8(ps), lcid, dwFlags, &V_BSTR(pd)); + case VT_DATE: return VarBstrFromDate(V_DATE(ps), lcid, dwFlags, &V_BSTR(pd)); + case VT_CY: return VarBstrFromCy(V_CY(ps), lcid, dwFlags, &V_BSTR(pd)); + case VT_DECIMAL: return VarBstrFromDec(&V_DECIMAL(ps), lcid, dwFlags, &V_BSTR(pd)); +/* case VT_DISPATCH: return VarBstrFromDisp(V_DISPATCH(ps), lcid, dwFlags, &V_BSTR(pd)); */ + } + break; + + case VT_CY: + switch (vtFrom) + { + case VT_EMPTY: V_CY(pd).int64 = 0; return S_OK; + case VT_I1: return VarCyFromI1(V_I1(ps), &V_CY(pd)); + case VT_I2: return VarCyFromI2(V_I2(ps), &V_CY(pd)); + case VT_I4: return VarCyFromI4(V_I4(ps), &V_CY(pd)); + case VT_UI1: return VarCyFromUI1(V_UI1(ps), &V_CY(pd)); + case VT_UI2: return VarCyFromUI2(V_UI2(ps), &V_CY(pd)); + case VT_UI4: return VarCyFromUI4(V_UI4(ps), &V_CY(pd)); + case VT_I8: return VarCyFromI8(V_I8(ps), &V_CY(pd)); + case VT_UI8: return VarCyFromUI8(V_UI8(ps), &V_CY(pd)); + case VT_R4: return VarCyFromR4(V_R4(ps), &V_CY(pd)); + case VT_R8: return VarCyFromR8(V_R8(ps), &V_CY(pd)); + case VT_DATE: return VarCyFromDate(V_DATE(ps), &V_CY(pd)); + case VT_BOOL: return VarCyFromBool(V_BOOL(ps), &V_CY(pd)); + case VT_DECIMAL: return VarCyFromDec(&V_DECIMAL(ps), &V_CY(pd)); + case VT_DISPATCH: return VarCyFromDisp(V_DISPATCH(ps), lcid, &V_CY(pd)); + case VT_BSTR: return VarCyFromStr(V_BSTR(ps), lcid, dwFlags, &V_CY(pd)); + } + break; + + case VT_DECIMAL: + switch (vtFrom) + { + case VT_EMPTY: + case VT_BOOL: + DEC_SIGNSCALE(&V_DECIMAL(pd)) = SIGNSCALE(DECIMAL_POS,0); + DEC_HI32(&V_DECIMAL(pd)) = 0; + DEC_MID32(&V_DECIMAL(pd)) = 0; + /* VarDecFromBool() coerces to -1/0, ChangeTypeEx() coerces to 1/0. + * VT_NULL and VT_EMPTY always give a 0 value. + */ + DEC_LO32(&V_DECIMAL(pd)) = vtFrom == VT_BOOL && V_BOOL(ps) ? 1 : 0; + return S_OK; + case VT_I1: return VarDecFromI1(V_I1(ps), &V_DECIMAL(pd)); + case VT_I2: return VarDecFromI2(V_I2(ps), &V_DECIMAL(pd)); + case VT_I4: return VarDecFromI4(V_I4(ps), &V_DECIMAL(pd)); + case VT_UI1: return VarDecFromUI1(V_UI1(ps), &V_DECIMAL(pd)); + case VT_UI2: return VarDecFromUI2(V_UI2(ps), &V_DECIMAL(pd)); + case VT_UI4: return VarDecFromUI4(V_UI4(ps), &V_DECIMAL(pd)); + case VT_I8: return VarDecFromI8(V_I8(ps), &V_DECIMAL(pd)); + case VT_UI8: return VarDecFromUI8(V_UI8(ps), &V_DECIMAL(pd)); + case VT_R4: return VarDecFromR4(V_R4(ps), &V_DECIMAL(pd)); + case VT_R8: return VarDecFromR8(V_R8(ps), &V_DECIMAL(pd)); + case VT_DATE: return VarDecFromDate(V_DATE(ps), &V_DECIMAL(pd)); + case VT_CY: return VarDecFromCy(V_CY(ps), &V_DECIMAL(pd)); + case VT_DISPATCH: return VarDecFromDisp(V_DISPATCH(ps), lcid, &V_DECIMAL(pd)); + case VT_BSTR: return VarDecFromStr(V_BSTR(ps), lcid, dwFlags, &V_DECIMAL(pd)); + } + break; + + case VT_UNKNOWN: + switch (vtFrom) + { + case VT_DISPATCH: + if (V_DISPATCH(ps) == NULL) + V_UNKNOWN(pd) = NULL; + else + res = IDispatch_QueryInterface(V_DISPATCH(ps), &IID_IUnknown, (LPVOID*)&V_UNKNOWN(pd)); + break; + } + break; + + case VT_DISPATCH: + switch (vtFrom) + { + case VT_UNKNOWN: + if (V_UNKNOWN(ps) == NULL) + V_DISPATCH(pd) = NULL; + else + res = IUnknown_QueryInterface(V_UNKNOWN(ps), &IID_IDispatch, (LPVOID*)&V_DISPATCH(pd)); + break; + } + break; + + case VT_RECORD: + break; + } + return res; +} + +/* Coerce to/from an array */ +static inline HRESULT VARIANT_CoerceArray(VARIANTARG* pd, VARIANTARG* ps, VARTYPE vt) +{ + if (vt == VT_BSTR && V_VT(ps) == (VT_ARRAY|VT_UI1)) + return BstrFromVector(V_ARRAY(ps), &V_BSTR(pd)); + + if (V_VT(ps) == VT_BSTR && vt == (VT_ARRAY|VT_UI1)) + return VectorFromBstr(V_BSTR(ps), &V_ARRAY(ps)); + + if (V_VT(ps) == vt) + return SafeArrayCopy(V_ARRAY(ps), &V_ARRAY(pd)); + + return DISP_E_TYPEMISMATCH; +} + +/****************************************************************************** + * Check if a variants type is valid. + */ +static inline HRESULT VARIANT_ValidateType(VARTYPE vt) +{ + VARTYPE vtExtra = vt & VT_EXTRA_TYPE; + + vt &= VT_TYPEMASK; + + if (!(vtExtra & (VT_VECTOR|VT_RESERVED))) + { + if (vt < VT_VOID || vt == VT_RECORD || vt == VT_CLSID) + { + if ((vtExtra & (VT_BYREF|VT_ARRAY)) && vt <= VT_NULL) + return DISP_E_BADVARTYPE; + if (vt != (VARTYPE)15) + return S_OK; + } + } + return DISP_E_BADVARTYPE; +} + +/****************************************************************************** + * VariantInit [OLEAUT32.8] + * + * Initialise a variant. + * + * PARAMS + * pVarg [O] Variant to initialise + * + * RETURNS + * Nothing. + * + * NOTES + * This function simply sets the type of the variant to VT_EMPTY. It does not + * free any existing value, use VariantClear() for that. + */ +void WINAPI VariantInit(VARIANTARG* pVarg) +{ + TRACE("(%p)\n", pVarg); + + V_VT(pVarg) = VT_EMPTY; /* Native doesn't set any other fields */ +} + +/****************************************************************************** + * VariantClear [OLEAUT32.9] + * + * Clear a variant. + * + * PARAMS + * pVarg [I/O] Variant to clear + * + * RETURNS + * Success: S_OK. Any previous value in pVarg is freed and its type is set to VT_EMPTY. + * Failure: DISP_E_BADVARTYPE, if the variant is a not a valid variant type. + */ +HRESULT WINAPI VariantClear(VARIANTARG* pVarg) +{ + HRESULT hres = S_OK; + + TRACE("(%p->(%s%s))\n", pVarg, debugstr_VT(pVarg), debugstr_VF(pVarg)); + + hres = VARIANT_ValidateType(V_VT(pVarg)); + + if (SUCCEEDED(hres)) + { + if (!V_ISBYREF(pVarg)) + { + if (V_ISARRAY(pVarg) || V_VT(pVarg) == VT_SAFEARRAY) + { + if (V_ARRAY(pVarg)) + hres = SafeArrayDestroy(V_ARRAY(pVarg)); + } + else if (V_VT(pVarg) == VT_BSTR) + { + if (V_BSTR(pVarg)) + SysFreeString(V_BSTR(pVarg)); + } + else if (V_VT(pVarg) == VT_RECORD) + { + struct __tagBRECORD* pBr = &V_UNION(pVarg,brecVal); + if (pBr->pRecInfo) + { + IRecordInfo_RecordClear(pBr->pRecInfo, pBr->pvRecord); + IRecordInfo_Release(pBr->pRecInfo); + } + } + else if (V_VT(pVarg) == VT_DISPATCH || + V_VT(pVarg) == VT_UNKNOWN) + { + if (V_UNKNOWN(pVarg)) + IUnknown_Release(V_UNKNOWN(pVarg)); + } + else if (V_VT(pVarg) == VT_VARIANT) + { + if (V_VARIANTREF(pVarg)) + VariantClear(V_VARIANTREF(pVarg)); + } + } + V_VT(pVarg) = VT_EMPTY; + } + return hres; +} + +/****************************************************************************** + * Copy an IRecordInfo object contained in a variant. + */ +static HRESULT VARIANT_CopyIRecordInfo(struct __tagBRECORD* pBr) +{ + HRESULT hres = S_OK; + + if (pBr->pRecInfo) + { + ULONG ulSize; + + hres = IRecordInfo_GetSize(pBr->pRecInfo, &ulSize); + if (SUCCEEDED(hres)) + { + PVOID pvRecord = HeapAlloc(GetProcessHeap(), 0, ulSize); + if (!pvRecord) + hres = E_OUTOFMEMORY; + else + { + memcpy(pvRecord, pBr->pvRecord, ulSize); + pBr->pvRecord = pvRecord; + + hres = IRecordInfo_RecordCopy(pBr->pRecInfo, pvRecord, pvRecord); + if (SUCCEEDED(hres)) + IRecordInfo_AddRef(pBr->pRecInfo); + } + } + } + else if (pBr->pvRecord) + hres = E_INVALIDARG; + return hres; +} + +/****************************************************************************** + * VariantCopy [OLEAUT32.10] + * + * Copy a variant. + * + * PARAMS + * pvargDest [O] Destination for copy + * pvargSrc [I] Source variant to copy + * + * RETURNS + * Success: S_OK. pvargDest contains a copy of pvargSrc. + * Failure: DISP_E_BADVARTYPE, if either variant has an invalid type. + * E_OUTOFMEMORY, if memory cannot be allocated. Otherwise an + * HRESULT error code from SafeArrayCopy(), IRecordInfo_GetSize(), + * or IRecordInfo_RecordCopy(), depending on the type of pvargSrc. + * + * NOTES + * - If pvargSrc == pvargDest, this function does nothing, and succeeds if + * pvargSrc is valid. Otherwise, pvargDest is always cleared using + * VariantClear() before pvargSrc is copied to it. If clearing pvargDest + * fails, so does this function. + * - VT_CLSID is a valid type type for pvargSrc, but not for pvargDest. + * - For by-value non-intrinsic types, a deep copy is made, i.e. The whole value + * is copied rather than just any pointers to it. + * - For by-value object types the object pointer is copied and the objects + * reference count increased using IUnknown_AddRef(). + * - For all by-reference types, only the referencing pointer is copied. + */ +HRESULT WINAPI VariantCopy(VARIANTARG* pvargDest, VARIANTARG* pvargSrc) +{ + HRESULT hres = S_OK; + + TRACE("(%p->(%s%s),%p->(%s%s))\n", pvargDest, debugstr_VT(pvargDest), + debugstr_VF(pvargDest), pvargSrc, debugstr_VT(pvargSrc), + debugstr_VF(pvargSrc)); + + if (V_TYPE(pvargSrc) == VT_CLSID || /* VT_CLSID is a special case */ + FAILED(VARIANT_ValidateType(V_VT(pvargSrc)))) + return DISP_E_BADVARTYPE; + + if (pvargSrc != pvargDest && + SUCCEEDED(hres = VariantClear(pvargDest))) + { + *pvargDest = *pvargSrc; /* Shallow copy the value */ + + if (!V_ISBYREF(pvargSrc)) + { + if (V_ISARRAY(pvargSrc)) + { + if (V_ARRAY(pvargSrc)) + hres = SafeArrayCopy(V_ARRAY(pvargSrc), &V_ARRAY(pvargDest)); + } + else if (V_VT(pvargSrc) == VT_BSTR) + { + if (V_BSTR(pvargSrc)) + { + V_BSTR(pvargDest) = SysAllocStringByteLen((char*)V_BSTR(pvargSrc), SysStringByteLen(V_BSTR(pvargSrc))); + if (!V_BSTR(pvargDest)) + { + TRACE("!V_BSTR(pvargDest), SysAllocStringByteLen() failed to allocate %d bytes\n", SysStringByteLen(V_BSTR(pvargSrc))); + hres = E_OUTOFMEMORY; + } + } + } + else if (V_VT(pvargSrc) == VT_RECORD) + { + hres = VARIANT_CopyIRecordInfo(&V_UNION(pvargDest,brecVal)); + } + else if (V_VT(pvargSrc) == VT_DISPATCH || + V_VT(pvargSrc) == VT_UNKNOWN) + { + if (V_UNKNOWN(pvargSrc)) + IUnknown_AddRef(V_UNKNOWN(pvargSrc)); + } + } + } + return hres; +} + +/* Return the byte size of a variants data */ +static inline size_t VARIANT_DataSize(const VARIANT* pv) +{ + switch (V_TYPE(pv)) + { + case VT_I1: + case VT_UI1: return sizeof(BYTE); + case VT_I2: + case VT_UI2: return sizeof(SHORT); + case VT_INT: + case VT_UINT: + case VT_I4: + case VT_UI4: return sizeof(LONG); + case VT_I8: + case VT_UI8: return sizeof(LONGLONG); + case VT_R4: return sizeof(float); + case VT_R8: return sizeof(double); + case VT_DATE: return sizeof(DATE); + case VT_BOOL: return sizeof(VARIANT_BOOL); + case VT_DISPATCH: + case VT_UNKNOWN: + case VT_BSTR: return sizeof(void*); + case VT_CY: return sizeof(CY); + case VT_ERROR: return sizeof(SCODE); + } + TRACE("Shouldn't be called for vt %s%s!\n", debugstr_VT(pv), debugstr_VF(pv)); + return 0; +} + +/****************************************************************************** + * VariantCopyInd [OLEAUT32.11] + * + * Copy a variant, dereferencing it it is by-reference. + * + * PARAMS + * pvargDest [O] Destination for copy + * pvargSrc [I] Source variant to copy + * + * RETURNS + * Success: S_OK. pvargDest contains a copy of pvargSrc. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * Failure: DISP_E_BADVARTYPE, if either variant has an invalid by-value type. + * E_INVALIDARG, if pvargSrc is an invalid by-reference type. + * E_OUTOFMEMORY, if memory cannot be allocated. Otherwise an + * HRESULT error code from SafeArrayCopy(), IRecordInfo_GetSize(), + * or IRecordInfo_RecordCopy(), depending on the type of pvargSrc. + * + * NOTES + * - If pvargSrc is by-value, this function behaves exactly as VariantCopy(). + * - If pvargSrc is by-reference, the value copied to pvargDest is the pointed-to + * value. + * - if pvargSrc == pvargDest, this function dereferences in place. Otherwise, + * pvargDest is always cleared using VariantClear() before pvargSrc is copied + * to it. If clearing pvargDest fails, so does this function. + */ +HRESULT WINAPI VariantCopyInd(VARIANT* pvargDest, VARIANTARG* pvargSrc) +{ + VARIANTARG vTmp, *pSrc = pvargSrc; + VARTYPE vt; + HRESULT hres = S_OK; + + TRACE("(%p->(%s%s),%p->(%s%s))\n", pvargDest, debugstr_VT(pvargDest), + debugstr_VF(pvargDest), pvargSrc, debugstr_VT(pvargSrc), + debugstr_VF(pvargSrc)); + + if (!V_ISBYREF(pvargSrc)) + return VariantCopy(pvargDest, pvargSrc); + + /* Argument checking is more lax than VariantCopy()... */ + vt = V_TYPE(pvargSrc); + if (V_ISARRAY(pvargSrc) || + (vt > VT_NULL && vt != (VARTYPE)15 && vt < VT_VOID && + !(V_VT(pvargSrc) & (VT_VECTOR|VT_RESERVED)))) + { + /* OK */ + } + else + return E_INVALIDARG; /* ...And the return value for invalid types differs too */ + + if (pvargSrc == pvargDest) + { + /* In place copy. Use a shallow copy of pvargSrc & init pvargDest. + * This avoids an expensive VariantCopy() call - e.g. SafeArrayCopy(). + */ + vTmp = *pvargSrc; + pSrc = &vTmp; + V_VT(pvargDest) = VT_EMPTY; + } + else + { + /* Copy into another variant. Free the variant in pvargDest */ + if (FAILED(hres = VariantClear(pvargDest))) + { + TRACE("VariantClear() of destination failed\n"); + return hres; + } + } + + if (V_ISARRAY(pSrc)) + { + /* Native doesn't check that *V_ARRAYREF(pSrc) is valid */ + hres = SafeArrayCopy(*V_ARRAYREF(pSrc), &V_ARRAY(pvargDest)); + } + else if (V_VT(pSrc) == (VT_BSTR|VT_BYREF)) + { + /* Native doesn't check that *V_BSTRREF(pSrc) is valid */ + V_BSTR(pvargDest) = SysAllocStringByteLen((char*)*V_BSTRREF(pSrc), SysStringByteLen(*V_BSTRREF(pSrc))); + } + else if (V_VT(pSrc) == (VT_RECORD|VT_BYREF)) + { + V_UNION(pvargDest,brecVal) = V_UNION(pvargSrc,brecVal); + hres = VARIANT_CopyIRecordInfo(&V_UNION(pvargDest,brecVal)); + } + else if (V_VT(pSrc) == (VT_DISPATCH|VT_BYREF) || + V_VT(pSrc) == (VT_UNKNOWN|VT_BYREF)) + { + /* Native doesn't check that *V_UNKNOWNREF(pSrc) is valid */ + V_UNKNOWN(pvargDest) = *V_UNKNOWNREF(pSrc); + if (*V_UNKNOWNREF(pSrc)) + IUnknown_AddRef(*V_UNKNOWNREF(pSrc)); + } + else if (V_VT(pSrc) == (VT_VARIANT|VT_BYREF)) + { + /* Native doesn't check that *V_VARIANTREF(pSrc) is valid */ + if (V_VT(V_VARIANTREF(pSrc)) == (VT_VARIANT|VT_BYREF)) + hres = E_INVALIDARG; /* Don't dereference more than one level */ + else + hres = VariantCopyInd(pvargDest, V_VARIANTREF(pSrc)); + + /* Use the dereferenced variants type value, not VT_VARIANT */ + goto VariantCopyInd_Return; + } + else if (V_VT(pSrc) == (VT_DECIMAL|VT_BYREF)) + { + memcpy(&DEC_SCALE(&V_DECIMAL(pvargDest)), &DEC_SCALE(V_DECIMALREF(pSrc)), + sizeof(DECIMAL) - sizeof(USHORT)); + } + else + { + /* Copy the pointed to data into this variant */ + memcpy(&V_BYREF(pvargDest), V_BYREF(pSrc), VARIANT_DataSize(pSrc)); + } + + V_VT(pvargDest) = V_VT(pSrc) & ~VT_BYREF; + +VariantCopyInd_Return: + + if (pSrc != pvargSrc) + VariantClear(pSrc); + + TRACE("returning 0x%08lx, %p->(%s%s)\n", hres, pvargDest, + debugstr_VT(pvargDest), debugstr_VF(pvargDest)); + return hres; +} + +/****************************************************************************** + * VariantChangeType [OLEAUT32.12] + * + * Change the type of a variant. + * + * PARAMS + * pvargDest [O] Destination for the converted variant + * pvargSrc [O] Source variant to change the type of + * wFlags [I] VARIANT_ flags from "oleauto.h" + * vt [I] Variant type to change pvargSrc into + * + * RETURNS + * Success: S_OK. pvargDest contains the converted value. + * Failure: An HRESULT error code describing the failure. + * + * NOTES + * The LCID used for the conversion is LOCALE_USER_DEFAULT. + * See VariantChangeTypeEx. + */ +HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc, + USHORT wFlags, VARTYPE vt) +{ + return VariantChangeTypeEx( pvargDest, pvargSrc, LOCALE_USER_DEFAULT, wFlags, vt ); +} + +/****************************************************************************** + * VariantChangeTypeEx [OLEAUT32.147] + * + * Change the type of a variant. + * + * PARAMS + * pvargDest [O] Destination for the converted variant + * pvargSrc [O] Source variant to change the type of + * lcid [I] LCID for the conversion + * wFlags [I] VARIANT_ flags from "oleauto.h" + * vt [I] Variant type to change pvargSrc into + * + * RETURNS + * Success: S_OK. pvargDest contains the converted value. + * Failure: An HRESULT error code describing the failure. + * + * NOTES + * pvargDest and pvargSrc can point to the same variant to perform an in-place + * conversion. If the conversion is successful, pvargSrc will be freed. + */ +HRESULT WINAPI VariantChangeTypeEx(VARIANTARG* pvargDest, VARIANTARG* pvargSrc, + LCID lcid, USHORT wFlags, VARTYPE vt) +{ + HRESULT res = S_OK; + + TRACE("(%p->(%s%s),%p->(%s%s),0x%08lx,0x%04x,%s%s)\n", pvargDest, + debugstr_VT(pvargDest), debugstr_VF(pvargDest), pvargSrc, + debugstr_VT(pvargSrc), debugstr_VF(pvargSrc), lcid, wFlags, + debugstr_vt(vt), debugstr_vf(vt)); + + if (vt == VT_CLSID) + res = DISP_E_BADVARTYPE; + else + { + res = VARIANT_ValidateType(V_VT(pvargSrc)); + + if (SUCCEEDED(res)) + { + res = VARIANT_ValidateType(vt); + + if (SUCCEEDED(res)) + { + VARIANTARG vTmp, vSrcDeref; + + if(V_ISBYREF(pvargSrc) && !V_BYREF(pvargSrc)) + res = DISP_E_TYPEMISMATCH; + else + { + V_VT(&vTmp) = VT_EMPTY; + V_VT(&vSrcDeref) = VT_EMPTY; + VariantClear(&vTmp); + VariantClear(&vSrcDeref); + } + + if (SUCCEEDED(res)) + { + res = VariantCopyInd(&vSrcDeref, pvargSrc); + if (SUCCEEDED(res)) + { + if (V_ISARRAY(&vSrcDeref) || (vt & VT_ARRAY)) + res = VARIANT_CoerceArray(&vTmp, &vSrcDeref, vt); + else + res = VARIANT_Coerce(&vTmp, lcid, wFlags, &vSrcDeref, vt); + + if (SUCCEEDED(res)) { + V_VT(&vTmp) = vt; + VariantCopy(pvargDest, &vTmp); + } + VariantClear(&vTmp); + VariantClear(&vSrcDeref); + } + } + } + } + } + + TRACE("returning 0x%08lx, %p->(%s%s)\n", res, pvargDest, + debugstr_VT(pvargDest), debugstr_VF(pvargDest)); + return res; +} + +/* Date Conversions */ + +#define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0))) + +/* Convert a VT_DATE value to a Julian Date */ +static inline int VARIANT_JulianFromDate(int dateIn) +{ + int julianDays = dateIn; + + julianDays -= DATE_MIN; /* Convert to + days from 1 Jan 100 AD */ + julianDays += 1757585; /* Convert to + days from 23 Nov 4713 BC (Julian) */ + return julianDays; +} + +/* Convert a Julian Date to a VT_DATE value */ +static inline int VARIANT_DateFromJulian(int dateIn) +{ + int julianDays = dateIn; + + julianDays -= 1757585; /* Convert to + days from 1 Jan 100 AD */ + julianDays += DATE_MIN; /* Convert to +/- days from 1 Jan 1899 AD */ + return julianDays; +} + +/* Convert a Julian date to Day/Month/Year - from PostgreSQL */ +static inline void VARIANT_DMYFromJulian(int jd, USHORT *year, USHORT *month, USHORT *day) +{ + int j, i, l, n; + + l = jd + 68569; + n = l * 4 / 146097; + l -= (n * 146097 + 3) / 4; + i = (4000 * (l + 1)) / 1461001; + l += 31 - (i * 1461) / 4; + j = (l * 80) / 2447; + *day = l - (j * 2447) / 80; + l = j / 11; + *month = (j + 2) - (12 * l); + *year = 100 * (n - 49) + i + l; +} + +/* Convert Day/Month/Year to a Julian date - from PostgreSQL */ +static inline double VARIANT_JulianFromDMY(USHORT year, USHORT month, USHORT day) +{ + int m12 = (month - 14) / 12; + + return ((1461 * (year + 4800 + m12)) / 4 + (367 * (month - 2 - 12 * m12)) / 12 - + (3 * ((year + 4900 + m12) / 100)) / 4 + day - 32075); +} + +/* Macros for accessing DOS format date/time fields */ +#define DOS_YEAR(x) (1980 + (x >> 9)) +#define DOS_MONTH(x) ((x >> 5) & 0xf) +#define DOS_DAY(x) (x & 0x1f) +#define DOS_HOUR(x) (x >> 11) +#define DOS_MINUTE(x) ((x >> 5) & 0x3f) +#define DOS_SECOND(x) ((x & 0x1f) << 1) +/* Create a DOS format date/time */ +#define DOS_DATE(d,m,y) (d | (m << 5) | ((y-1980) << 9)) +#define DOS_TIME(h,m,s) ((s >> 1) | (m << 5) | (h << 11)) + +/* Roll a date forwards or backwards to correct it */ +static HRESULT VARIANT_RollUdate(UDATE *lpUd) +{ + static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + + TRACE("Raw date: %d/%d/%d %d:%d:%d\n", lpUd->st.wDay, lpUd->st.wMonth, + lpUd->st.wYear, lpUd->st.wHour, lpUd->st.wMinute, lpUd->st.wSecond); + + /* Years < 100 are treated as 1900 + year */ + if (lpUd->st.wYear < 100) + lpUd->st.wYear += 1900; + + if (!lpUd->st.wMonth) + { + /* Roll back to December of the previous year */ + lpUd->st.wMonth = 12; + lpUd->st.wYear--; + } + else while (lpUd->st.wMonth > 12) + { + /* Roll forward the correct number of months */ + lpUd->st.wYear++; + lpUd->st.wMonth -= 12; + } + + if (lpUd->st.wYear > 9999 || lpUd->st.wHour > 23 || + lpUd->st.wMinute > 59 || lpUd->st.wSecond > 59) + return E_INVALIDARG; /* Invalid values */ + + if (!lpUd->st.wDay) + { + /* Roll back the date one day */ + if (lpUd->st.wMonth == 1) + { + /* Roll back to December 31 of the previous year */ + lpUd->st.wDay = 31; + lpUd->st.wMonth = 12; + lpUd->st.wYear--; + } + else + { + lpUd->st.wMonth--; /* Previous month */ + if (lpUd->st.wMonth == 2 && IsLeapYear(lpUd->st.wYear)) + lpUd->st.wDay = 29; /* Februaury has 29 days on leap years */ + else + lpUd->st.wDay = days[lpUd->st.wMonth]; /* Last day of the month */ + } + } + else if (lpUd->st.wDay > 28) + { + int rollForward = 0; + + /* Possibly need to roll the date forward */ + if (lpUd->st.wMonth == 2 && IsLeapYear(lpUd->st.wYear)) + rollForward = lpUd->st.wDay - 29; /* Februaury has 29 days on leap years */ + else + rollForward = lpUd->st.wDay - days[lpUd->st.wMonth]; + + if (rollForward > 0) + { + lpUd->st.wDay = rollForward; + lpUd->st.wMonth++; + if (lpUd->st.wMonth > 12) + { + lpUd->st.wMonth = 1; /* Roll forward into January of the next year */ + lpUd->st.wYear++; + } + } + } + TRACE("Rolled date: %d/%d/%d %d:%d:%d\n", lpUd->st.wDay, lpUd->st.wMonth, + lpUd->st.wYear, lpUd->st.wHour, lpUd->st.wMinute, lpUd->st.wSecond); + return S_OK; +} + +/********************************************************************** + * DosDateTimeToVariantTime [OLEAUT32.14] + * + * Convert a Dos format date and time into variant VT_DATE format. + * + * PARAMS + * wDosDate [I] Dos format date + * wDosTime [I] Dos format time + * pDateOut [O] Destination for VT_DATE format + * + * RETURNS + * Success: TRUE. pDateOut contains the converted time. + * Failure: FALSE, if wDosDate or wDosTime are invalid (see notes). + * + * NOTES + * - Dos format dates can only hold dates from 1-Jan-1980 to 31-Dec-2099. + * - Dos format times are accurate to only 2 second precision. + * - The format of a Dos Date is: + *| Bits Values Meaning + *| ---- ------ ------- + *| 0-4 1-31 Day of the week. 0 rolls back one day. A value greater than + *| the days in the month rolls forward the extra days. + *| 5-8 1-12 Month of the year. 0 rolls back to December of the previous + *| year. 13-15 are invalid. + *| 9-15 0-119 Year based from 1980 (Max 2099). 120-127 are invalid. + * - The format of a Dos Time is: + *| Bits Values Meaning + *| ---- ------ ------- + *| 0-4 0-29 Seconds/2. 30 and 31 are invalid. + *| 5-10 0-59 Minutes. 60-63 are invalid. + *| 11-15 0-23 Hours (24 hour clock). 24-32 are invalid. + */ +INT WINAPI DosDateTimeToVariantTime(USHORT wDosDate, USHORT wDosTime, + double *pDateOut) +{ + UDATE ud; + + TRACE("(0x%x(%d/%d/%d),0x%x(%d:%d:%d),%p)\n", + wDosDate, DOS_YEAR(wDosDate), DOS_MONTH(wDosDate), DOS_DAY(wDosDate), + wDosTime, DOS_HOUR(wDosTime), DOS_MINUTE(wDosTime), DOS_SECOND(wDosTime), + pDateOut); + + ud.st.wYear = DOS_YEAR(wDosDate); + ud.st.wMonth = DOS_MONTH(wDosDate); + if (ud.st.wYear > 2099 || ud.st.wMonth > 12) + return FALSE; + ud.st.wDay = DOS_DAY(wDosDate); + ud.st.wHour = DOS_HOUR(wDosTime); + ud.st.wMinute = DOS_MINUTE(wDosTime); + ud.st.wSecond = DOS_SECOND(wDosTime); + ud.st.wDayOfWeek = ud.st.wMilliseconds = 0; + + return !VarDateFromUdate(&ud, 0, pDateOut); +} + +/********************************************************************** + * VariantTimeToDosDateTime [OLEAUT32.13] + * + * Convert a variant format date into a Dos format date and time. + * + * dateIn [I] VT_DATE time format + * pwDosDate [O] Destination for Dos format date + * pwDosTime [O] Destination for Dos format time + * + * RETURNS + * Success: TRUE. pwDosDate and pwDosTime contains the converted values. + * Failure: FALSE, if dateIn cannot be represented in Dos format. + * + * NOTES + * See DosDateTimeToVariantTime() for Dos format details and bugs. + */ +INT WINAPI VariantTimeToDosDateTime(double dateIn, USHORT *pwDosDate, USHORT *pwDosTime) +{ + UDATE ud; + + TRACE("(%g,%p,%p)\n", dateIn, pwDosDate, pwDosTime); + + if (FAILED(VarUdateFromDate(dateIn, 0, &ud))) + return FALSE; + + if (ud.st.wYear < 1980 || ud.st.wYear > 2099) + return FALSE; + + *pwDosDate = DOS_DATE(ud.st.wDay, ud.st.wMonth, ud.st.wYear); + *pwDosTime = DOS_TIME(ud.st.wHour, ud.st.wMinute, ud.st.wSecond); + + TRACE("Returning 0x%x(%d/%d/%d), 0x%x(%d:%d:%d)\n", + *pwDosDate, DOS_YEAR(*pwDosDate), DOS_MONTH(*pwDosDate), DOS_DAY(*pwDosDate), + *pwDosTime, DOS_HOUR(*pwDosTime), DOS_MINUTE(*pwDosTime), DOS_SECOND(*pwDosTime)); + return TRUE; +} + +/*********************************************************************** + * SystemTimeToVariantTime [OLEAUT32.184] + * + * Convert a System format date and time into variant VT_DATE format. + * + * PARAMS + * lpSt [I] System format date and time + * pDateOut [O] Destination for VT_DATE format date + * + * RETURNS + * Success: TRUE. *pDateOut contains the converted value. + * Failure: FALSE, if lpSt cannot be represented in VT_DATE format. + */ +INT WINAPI SystemTimeToVariantTime(LPSYSTEMTIME lpSt, double *pDateOut) +{ + UDATE ud; + + TRACE("(%p->%d/%d/%d %d:%d:%d,%p)\n", lpSt, lpSt->wDay, lpSt->wMonth, + lpSt->wYear, lpSt->wHour, lpSt->wMinute, lpSt->wSecond, pDateOut); + + if (lpSt->wMonth > 12) + return FALSE; + + memcpy(&ud.st, lpSt, sizeof(ud.st)); + return !VarDateFromUdate(&ud, 0, pDateOut); +} + +/*********************************************************************** + * VariantTimeToSystemTime [OLEAUT32.185] + * + * Convert a variant VT_DATE into a System format date and time. + * + * PARAMS + * datein [I] Variant VT_DATE format date + * lpSt [O] Destination for System format date and time + * + * RETURNS + * Success: TRUE. *lpSt contains the converted value. + * Failure: FALSE, if dateIn is too large or small. + */ +INT WINAPI VariantTimeToSystemTime(double dateIn, LPSYSTEMTIME lpSt) +{ + UDATE ud; + + TRACE("(%g,%p)\n", dateIn, lpSt); + + if (FAILED(VarUdateFromDate(dateIn, 0, &ud))) + return FALSE; + + memcpy(lpSt, &ud.st, sizeof(ud.st)); + return TRUE; +} + +/*********************************************************************** + * VarDateFromUdateEx [OLEAUT32.319] + * + * Convert an unpacked format date and time to a variant VT_DATE. + * + * PARAMS + * pUdateIn [I] Unpacked format date and time to convert + * lcid [I] Locale identifier for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pDateOut [O] Destination for variant VT_DATE. + * + * RETURNS + * Success: S_OK. *pDateOut contains the converted value. + * Failure: E_INVALIDARG, if pUdateIn cannot be represented in VT_DATE format. + */ +HRESULT WINAPI VarDateFromUdateEx(UDATE *pUdateIn, LCID lcid, ULONG dwFlags, DATE *pDateOut) +{ + UDATE ud; + double dateVal; + + TRACE("(%p->%d/%d/%d %d:%d:%d:%d %d %d,0x%08lx,0x%08lx,%p)\n", pUdateIn, + pUdateIn->st.wMonth, pUdateIn->st.wDay, pUdateIn->st.wYear, + pUdateIn->st.wHour, pUdateIn->st.wMinute, pUdateIn->st.wSecond, + pUdateIn->st.wMilliseconds, pUdateIn->st.wDayOfWeek, + pUdateIn->wDayOfYear, lcid, dwFlags, pDateOut); + + if (lcid != MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT)) + FIXME("lcid possibly not handled, treating as en-us\n"); + + memcpy(&ud, pUdateIn, sizeof(ud)); + + if (dwFlags & VAR_VALIDDATE) + WARN("Ignoring VAR_VALIDDATE\n"); + + if (FAILED(VARIANT_RollUdate(&ud))) + return E_INVALIDARG; + + /* Date */ + dateVal = VARIANT_DateFromJulian(VARIANT_JulianFromDMY(ud.st.wYear, ud.st.wMonth, ud.st.wDay)); + + /* Time */ + dateVal += ud.st.wHour / 24.0; + dateVal += ud.st.wMinute / 1440.0; + dateVal += ud.st.wSecond / 86400.0; + dateVal += ud.st.wMilliseconds / 86400000.0; + + TRACE("Returning %g\n", dateVal); + *pDateOut = dateVal; + return S_OK; +} + +/*********************************************************************** + * VarDateFromUdate [OLEAUT32.330] + * + * Convert an unpacked format date and time to a variant VT_DATE. + * + * PARAMS + * pUdateIn [I] Unpacked format date and time to convert + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pDateOut [O] Destination for variant VT_DATE. + * + * RETURNS + * Success: S_OK. *pDateOut contains the converted value. + * Failure: E_INVALIDARG, if pUdateIn cannot be represented in VT_DATE format. + * + * NOTES + * This function uses the United States English locale for the conversion. Use + * VarDateFromUdateEx() for alternate locales. + */ +HRESULT WINAPI VarDateFromUdate(UDATE *pUdateIn, ULONG dwFlags, DATE *pDateOut) +{ + LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); + + return VarDateFromUdateEx(pUdateIn, lcid, dwFlags, pDateOut); +} + +/*********************************************************************** + * VarUdateFromDate [OLEAUT32.331] + * + * Convert a variant VT_DATE into an unpacked format date and time. + * + * PARAMS + * datein [I] Variant VT_DATE format date + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * lpUdate [O] Destination for unpacked format date and time + * + * RETURNS + * Success: S_OK. *lpUdate contains the converted value. + * Failure: E_INVALIDARG, if dateIn is too large or small. + */ +HRESULT WINAPI VarUdateFromDate(DATE dateIn, ULONG dwFlags, UDATE *lpUdate) +{ + /* Cumulative totals of days per month */ + static const USHORT cumulativeDays[] = + { + 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 + }; + double datePart, timePart; + int julianDays; + + TRACE("(%g,0x%08lx,%p)\n", dateIn, dwFlags, lpUdate); + + if (dateIn <= (DATE_MIN - 1.0) || dateIn >= (DATE_MAX + 1.0)) + return E_INVALIDARG; + + datePart = dateIn < 0.0 ? ceil(dateIn) : floor(dateIn); + /* Compensate for int truncation (always downwards) */ + timePart = dateIn - datePart + 0.00000000001; + if (timePart >= 1.0) + timePart -= 0.00000000001; + + /* Date */ + julianDays = VARIANT_JulianFromDate(dateIn); + VARIANT_DMYFromJulian(julianDays, &lpUdate->st.wYear, &lpUdate->st.wMonth, + &lpUdate->st.wDay); + + datePart = (datePart + 1.5) / 7.0; + lpUdate->st.wDayOfWeek = (datePart - floor(datePart)) * 7; + if (lpUdate->st.wDayOfWeek == 0) + lpUdate->st.wDayOfWeek = 5; + else if (lpUdate->st.wDayOfWeek == 1) + lpUdate->st.wDayOfWeek = 6; + else + lpUdate->st.wDayOfWeek -= 2; + + if (lpUdate->st.wMonth > 2 && IsLeapYear(lpUdate->st.wYear)) + lpUdate->wDayOfYear = 1; /* After February, in a leap year */ + else + lpUdate->wDayOfYear = 0; + + lpUdate->wDayOfYear += cumulativeDays[lpUdate->st.wMonth]; + lpUdate->wDayOfYear += lpUdate->st.wDay; + + /* Time */ + timePart *= 24.0; + lpUdate->st.wHour = timePart; + timePart -= lpUdate->st.wHour; + timePart *= 60.0; + lpUdate->st.wMinute = timePart; + timePart -= lpUdate->st.wMinute; + timePart *= 60.0; + lpUdate->st.wSecond = timePart; + timePart -= lpUdate->st.wSecond; + lpUdate->st.wMilliseconds = 0; + if (timePart > 0.5) + { + /* Round the milliseconds, adjusting the time/date forward if needed */ + if (lpUdate->st.wSecond < 59) + lpUdate->st.wSecond++; + else + { + lpUdate->st.wSecond = 0; + if (lpUdate->st.wMinute < 59) + lpUdate->st.wMinute++; + else + { + lpUdate->st.wMinute = 0; + if (lpUdate->st.wHour < 23) + lpUdate->st.wHour++; + else + { + lpUdate->st.wHour = 0; + /* Roll over a whole day */ + if (++lpUdate->st.wDay > 28) + VARIANT_RollUdate(lpUdate); + } + } + } + } + return S_OK; +} + +#define GET_NUMBER_TEXT(fld,name) \ + buff[0] = 0; \ + if (!GetLocaleInfoW(lcid, lctype|fld, buff, 2)) \ + WARN("buffer too small for " #fld "\n"); \ + else \ + if (buff[0]) lpChars->name = buff[0]; \ + TRACE("lcid 0x%lx, " #name "=%d '%c'\n", lcid, lpChars->name, lpChars->name) + +/* Get the valid number characters for an lcid */ +void VARIANT_GetLocalisedNumberChars(VARIANT_NUMBER_CHARS *lpChars, LCID lcid, DWORD dwFlags) +{ + static const VARIANT_NUMBER_CHARS defaultChars = { '-','+','.',',','$',0,'.',',' }; + LCTYPE lctype = dwFlags & LOCALE_NOUSEROVERRIDE; + WCHAR buff[4]; + + memcpy(lpChars, &defaultChars, sizeof(defaultChars)); + GET_NUMBER_TEXT(LOCALE_SNEGATIVESIGN, cNegativeSymbol); + GET_NUMBER_TEXT(LOCALE_SPOSITIVESIGN, cPositiveSymbol); + GET_NUMBER_TEXT(LOCALE_SDECIMAL, cDecimalPoint); + GET_NUMBER_TEXT(LOCALE_STHOUSAND, cDigitSeperator); + GET_NUMBER_TEXT(LOCALE_SMONDECIMALSEP, cCurrencyDecimalPoint); + GET_NUMBER_TEXT(LOCALE_SMONTHOUSANDSEP, cCurrencyDigitSeperator); + + /* Local currency symbols are often 2 characters */ + lpChars->cCurrencyLocal2 = '\0'; + switch(GetLocaleInfoW(lcid, lctype|LOCALE_SCURRENCY, buff, sizeof(buff)/sizeof(WCHAR))) + { + case 3: lpChars->cCurrencyLocal2 = buff[1]; /* Fall through */ + case 2: lpChars->cCurrencyLocal = buff[0]; + break; + default: WARN("buffer too small for LOCALE_SCURRENCY\n"); + } + TRACE("lcid 0x%lx, cCurrencyLocal =%d,%d '%c','%c'\n", lcid, lpChars->cCurrencyLocal, + lpChars->cCurrencyLocal2, lpChars->cCurrencyLocal, lpChars->cCurrencyLocal2); +} + +/* Number Parsing States */ +#define B_PROCESSING_EXPONENT 0x1 +#define B_NEGATIVE_EXPONENT 0x2 +#define B_EXPONENT_START 0x4 +#define B_INEXACT_ZEROS 0x8 +#define B_LEADING_ZERO 0x10 +#define B_PROCESSING_HEX 0x20 +#define B_PROCESSING_OCT 0x40 + +/********************************************************************** + * VarParseNumFromStr [OLEAUT32.46] + * + * Parse a string containing a number into a NUMPARSE structure. + * + * PARAMS + * lpszStr [I] String to parse number from + * lcid [I] Locale Id for the conversion + * dwFlags [I] 0, or LOCALE_NOUSEROVERRIDE to use system default number chars + * pNumprs [I/O] Destination for parsed number + * rgbDig [O] Destination for digits read in + * + * RETURNS + * Success: S_OK. pNumprs and rgbDig contain the parsed representation of + * the number. + * Failure: E_INVALIDARG, if any parameter is invalid. + * DISP_E_TYPEMISMATCH, if the string is not a number or is formatted + * incorrectly. + * DISP_E_OVERFLOW, if rgbDig is too small to hold the number. + * + * NOTES + * pNumprs must have the following fields set: + * cDig: Set to the size of rgbDig. + * dwInFlags: Set to the allowable syntax of the number using NUMPRS_ flags + * from "oleauto.h". + * + * FIXME + * - I am unsure if this function should parse non-arabic (e.g. Thai) + * numerals, so this has not been implemented. + */ +HRESULT WINAPI VarParseNumFromStr(OLECHAR *lpszStr, LCID lcid, ULONG dwFlags, + NUMPARSE *pNumprs, BYTE *rgbDig) +{ + VARIANT_NUMBER_CHARS chars; + BYTE rgbTmp[1024]; + DWORD dwState = B_EXPONENT_START|B_INEXACT_ZEROS; + int iMaxDigits = sizeof(rgbTmp) / sizeof(BYTE); + int cchUsed = 0; + + TRACE("(%s,%ld,0x%08lx,%p,%p)\n", debugstr_w(lpszStr), lcid, dwFlags, pNumprs, rgbDig); + + if (!pNumprs || !rgbDig) + return E_INVALIDARG; + + if (pNumprs->cDig < iMaxDigits) + iMaxDigits = pNumprs->cDig; + + pNumprs->cDig = 0; + pNumprs->dwOutFlags = 0; + pNumprs->cchUsed = 0; + pNumprs->nBaseShift = 0; + pNumprs->nPwr10 = 0; + + if (!lpszStr) + return DISP_E_TYPEMISMATCH; + + VARIANT_GetLocalisedNumberChars(&chars, lcid, dwFlags); + + /* First consume all the leading symbols and space from the string */ + while (1) + { + if (pNumprs->dwInFlags & NUMPRS_LEADING_WHITE && isspaceW(*lpszStr)) + { + pNumprs->dwOutFlags |= NUMPRS_LEADING_WHITE; + do + { + cchUsed++; + lpszStr++; + } while (isspaceW(*lpszStr)); + } + else if (pNumprs->dwInFlags & NUMPRS_LEADING_PLUS && + *lpszStr == chars.cPositiveSymbol && + !(pNumprs->dwOutFlags & NUMPRS_LEADING_PLUS)) + { + pNumprs->dwOutFlags |= NUMPRS_LEADING_PLUS; + cchUsed++; + lpszStr++; + } + else if (pNumprs->dwInFlags & NUMPRS_LEADING_MINUS && + *lpszStr == chars.cNegativeSymbol && + !(pNumprs->dwOutFlags & NUMPRS_LEADING_MINUS)) + { + pNumprs->dwOutFlags |= (NUMPRS_LEADING_MINUS|NUMPRS_NEG); + cchUsed++; + lpszStr++; + } + else if (pNumprs->dwInFlags & NUMPRS_CURRENCY && + !(pNumprs->dwOutFlags & NUMPRS_CURRENCY) && + *lpszStr == chars.cCurrencyLocal && + (!chars.cCurrencyLocal2 || lpszStr[1] == chars.cCurrencyLocal2)) + { + pNumprs->dwOutFlags |= NUMPRS_CURRENCY; + cchUsed++; + lpszStr++; + /* Only accept currency characters */ + chars.cDecimalPoint = chars.cCurrencyDecimalPoint; + chars.cDigitSeperator = chars.cCurrencyDigitSeperator; + } + else if (pNumprs->dwInFlags & NUMPRS_PARENS && *lpszStr == '(' && + !(pNumprs->dwOutFlags & NUMPRS_PARENS)) + { + pNumprs->dwOutFlags |= NUMPRS_PARENS; + cchUsed++; + lpszStr++; + } + else + break; + } + + if (!(pNumprs->dwOutFlags & NUMPRS_CURRENCY)) + { + /* Only accept non-currency characters */ + chars.cCurrencyDecimalPoint = chars.cDecimalPoint; + chars.cCurrencyDigitSeperator = chars.cDigitSeperator; + } + + if ((*lpszStr == '&' && (*(lpszStr+1) == 'H' || *(lpszStr+1) == 'h')) && + pNumprs->dwInFlags & NUMPRS_HEX_OCT) + { + dwState |= B_PROCESSING_HEX; + pNumprs->dwOutFlags |= NUMPRS_HEX_OCT; + cchUsed=cchUsed+2; + lpszStr=lpszStr+2; + } + else if ((*lpszStr == '&' && (*(lpszStr+1) == 'O' || *(lpszStr+1) == 'o')) && + pNumprs->dwInFlags & NUMPRS_HEX_OCT) + { + dwState |= B_PROCESSING_OCT; + pNumprs->dwOutFlags |= NUMPRS_HEX_OCT; + cchUsed=cchUsed+2; + lpszStr=lpszStr+2; + } + + /* Strip Leading zeros */ + while (*lpszStr == '0') + { + dwState |= B_LEADING_ZERO; + cchUsed++; + lpszStr++; + } + + while (*lpszStr) + { + if (isdigitW(*lpszStr)) + { + if (dwState & B_PROCESSING_EXPONENT) + { + int exponentSize = 0; + if (dwState & B_EXPONENT_START) + { + if (!isdigitW(*lpszStr)) + break; /* No exponent digits - invalid */ + while (*lpszStr == '0') + { + /* Skip leading zero's in the exponent */ + cchUsed++; + lpszStr++; + } + } + + while (isdigitW(*lpszStr)) + { + exponentSize *= 10; + exponentSize += *lpszStr - '0'; + cchUsed++; + lpszStr++; + } + if (dwState & B_NEGATIVE_EXPONENT) + exponentSize = -exponentSize; + /* Add the exponent into the powers of 10 */ + pNumprs->nPwr10 += exponentSize; + dwState &= ~(B_PROCESSING_EXPONENT|B_EXPONENT_START); + lpszStr--; /* back up to allow processing of next char */ + } + else + { + if ((pNumprs->cDig >= iMaxDigits) && !(dwState & B_PROCESSING_HEX) + && !(dwState & B_PROCESSING_OCT)) + { + pNumprs->dwOutFlags |= NUMPRS_INEXACT; + + if (*lpszStr != '0') + dwState &= ~B_INEXACT_ZEROS; /* Inexact number with non-trailing zeros */ + + /* This digit can't be represented, but count it in nPwr10 */ + if (pNumprs->dwOutFlags & NUMPRS_DECIMAL) + pNumprs->nPwr10--; + else + pNumprs->nPwr10++; + } + else + { + if ((dwState & B_PROCESSING_OCT) && ((*lpszStr == '8') || (*lpszStr == '9'))) { + return DISP_E_TYPEMISMATCH; + } + + if (pNumprs->dwOutFlags & NUMPRS_DECIMAL) + pNumprs->nPwr10--; /* Count decimal points in nPwr10 */ + + rgbTmp[pNumprs->cDig] = *lpszStr - '0'; + } + pNumprs->cDig++; + cchUsed++; + } + } + else if (*lpszStr == chars.cDigitSeperator && pNumprs->dwInFlags & NUMPRS_THOUSANDS) + { + pNumprs->dwOutFlags |= NUMPRS_THOUSANDS; + cchUsed++; + } + else if (*lpszStr == chars.cDecimalPoint && + pNumprs->dwInFlags & NUMPRS_DECIMAL && + !(pNumprs->dwOutFlags & (NUMPRS_DECIMAL|NUMPRS_EXPONENT))) + { + pNumprs->dwOutFlags |= NUMPRS_DECIMAL; + cchUsed++; + + /* If we have no digits so far, skip leading zeros */ + if (!pNumprs->cDig) + { + while (lpszStr[1] == '0') + { + dwState |= B_LEADING_ZERO; + cchUsed++; + lpszStr++; + pNumprs->nPwr10--; + } + } + } + else if ((*lpszStr == 'e' || *lpszStr == 'E') && + pNumprs->dwInFlags & NUMPRS_EXPONENT && + !(pNumprs->dwOutFlags & NUMPRS_EXPONENT)) + { + dwState |= B_PROCESSING_EXPONENT; + pNumprs->dwOutFlags |= NUMPRS_EXPONENT; + cchUsed++; + } + else if (dwState & B_PROCESSING_EXPONENT && *lpszStr == chars.cPositiveSymbol) + { + cchUsed++; /* Ignore positive exponent */ + } + else if (dwState & B_PROCESSING_EXPONENT && *lpszStr == chars.cNegativeSymbol) + { + dwState |= B_NEGATIVE_EXPONENT; + cchUsed++; + } + else if (((*lpszStr >= 'a' && *lpszStr <= 'f') || + (*lpszStr >= 'A' && *lpszStr <= 'F')) && + dwState & B_PROCESSING_HEX) + { + if (pNumprs->cDig >= iMaxDigits) + { + return DISP_E_OVERFLOW; + } + else + { + if (*lpszStr >= 'a') + rgbTmp[pNumprs->cDig] = *lpszStr - 'a' + 10; + else + rgbTmp[pNumprs->cDig] = *lpszStr - 'A' + 10; + } + pNumprs->cDig++; + cchUsed++; + } + else + break; /* Stop at an unrecognised character */ + + lpszStr++; + } + + if (!pNumprs->cDig && dwState & B_LEADING_ZERO) + { + /* Ensure a 0 on its own gets stored */ + pNumprs->cDig = 1; + rgbTmp[0] = 0; + } + + if (pNumprs->dwOutFlags & NUMPRS_EXPONENT && dwState & B_PROCESSING_EXPONENT) + { + pNumprs->cchUsed = cchUsed; + return DISP_E_TYPEMISMATCH; /* Failed to completely parse the exponent */ + } + + if (pNumprs->dwOutFlags & NUMPRS_INEXACT) + { + if (dwState & B_INEXACT_ZEROS) + pNumprs->dwOutFlags &= ~NUMPRS_INEXACT; /* All zeros doesn't set NUMPRS_INEXACT */ + } else if(pNumprs->dwInFlags & NUMPRS_HEX_OCT) + { + /* copy all of the digits into the output digit buffer */ + /* this is exactly what windows does although it also returns */ + /* cDig of X and writes X+Y where Y>=0 number of digits to rgbDig */ + memcpy(rgbDig, rgbTmp, pNumprs->cDig * sizeof(BYTE)); + + if (dwState & B_PROCESSING_HEX) { + /* hex numbers have always the same format */ + pNumprs->nPwr10=0; + pNumprs->nBaseShift=4; + } else { + if (dwState & B_PROCESSING_OCT) { + /* oct numbers have always the same format */ + pNumprs->nPwr10=0; + pNumprs->nBaseShift=3; + } else { + while (pNumprs->cDig > 1 && !rgbTmp[pNumprs->cDig - 1]) + { + pNumprs->nPwr10++; + pNumprs->cDig--; + } + } + } + } else + { + /* Remove trailing zeros from the last (whole number or decimal) part */ + while (pNumprs->cDig > 1 && !rgbTmp[pNumprs->cDig - 1]) + { + pNumprs->nPwr10++; + pNumprs->cDig--; + } + } + + if (pNumprs->cDig <= iMaxDigits) + pNumprs->dwOutFlags &= ~NUMPRS_INEXACT; /* Ignore stripped zeros for NUMPRS_INEXACT */ + else + pNumprs->cDig = iMaxDigits; /* Only return iMaxDigits worth of digits */ + + /* Copy the digits we processed into rgbDig */ + memcpy(rgbDig, rgbTmp, pNumprs->cDig * sizeof(BYTE)); + + /* Consume any trailing symbols and space */ + while (1) + { + if ((pNumprs->dwInFlags & NUMPRS_TRAILING_WHITE) && isspaceW(*lpszStr)) + { + pNumprs->dwOutFlags |= NUMPRS_TRAILING_WHITE; + do + { + cchUsed++; + lpszStr++; + } while (isspaceW(*lpszStr)); + } + else if (pNumprs->dwInFlags & NUMPRS_TRAILING_PLUS && + !(pNumprs->dwOutFlags & NUMPRS_LEADING_PLUS) && + *lpszStr == chars.cPositiveSymbol) + { + pNumprs->dwOutFlags |= NUMPRS_TRAILING_PLUS; + cchUsed++; + lpszStr++; + } + else if (pNumprs->dwInFlags & NUMPRS_TRAILING_MINUS && + !(pNumprs->dwOutFlags & NUMPRS_LEADING_MINUS) && + *lpszStr == chars.cNegativeSymbol) + { + pNumprs->dwOutFlags |= (NUMPRS_TRAILING_MINUS|NUMPRS_NEG); + cchUsed++; + lpszStr++; + } + else if (pNumprs->dwInFlags & NUMPRS_PARENS && *lpszStr == ')' && + pNumprs->dwOutFlags & NUMPRS_PARENS) + { + cchUsed++; + lpszStr++; + pNumprs->dwOutFlags |= NUMPRS_NEG; + } + else + break; + } + + if (pNumprs->dwOutFlags & NUMPRS_PARENS && !(pNumprs->dwOutFlags & NUMPRS_NEG)) + { + pNumprs->cchUsed = cchUsed; + return DISP_E_TYPEMISMATCH; /* Opening parenthesis not matched */ + } + + if (pNumprs->dwInFlags & NUMPRS_USE_ALL && *lpszStr != '\0') + return DISP_E_TYPEMISMATCH; /* Not all chars were consumed */ + + if (!pNumprs->cDig) + return DISP_E_TYPEMISMATCH; /* No Number found */ + + pNumprs->cchUsed = cchUsed; + return S_OK; +} + +/* VTBIT flags indicating an integer value */ +#define INTEGER_VTBITS (VTBIT_I1|VTBIT_UI1|VTBIT_I2|VTBIT_UI2|VTBIT_I4|VTBIT_UI4|VTBIT_I8|VTBIT_UI8) +/* VTBIT flags indicating a real number value */ +#define REAL_VTBITS (VTBIT_R4|VTBIT_R8|VTBIT_CY) + +/* Helper macros to check whether bit pattern fits in VARIANT (x is a ULONG64 ) */ +#define FITS_AS_I1(x) ((x) >> 8 == 0) +#define FITS_AS_I2(x) ((x) >> 16 == 0) +#define FITS_AS_I4(x) ((x) >> 32 == 0) + +/********************************************************************** + * VarNumFromParseNum [OLEAUT32.47] + * + * Convert a NUMPARSE structure into a numeric Variant type. + * + * PARAMS + * pNumprs [I] Source for parsed number. cDig must be set to the size of rgbDig + * rgbDig [I] Source for the numbers digits + * dwVtBits [I] VTBIT_ flags from "oleauto.h" indicating the acceptable dest types + * pVarDst [O] Destination for the converted Variant value. + * + * RETURNS + * Success: S_OK. pVarDst contains the converted value. + * Failure: E_INVALIDARG, if any parameter is invalid. + * DISP_E_OVERFLOW, if the number is too big for the types set in dwVtBits. + * + * NOTES + * - The smallest favoured type present in dwVtBits that can represent the + * number in pNumprs without losing precision is used. + * - Signed types are preferrred over unsigned types of the same size. + * - Preferred types in order are: integer, float, double, currency then decimal. + * - Rounding (dropping of decimal points) occurs without error. See VarI8FromR8() + * for details of the rounding method. + * - pVarDst is not cleared before the result is stored in it. + */ +HRESULT WINAPI VarNumFromParseNum(NUMPARSE *pNumprs, BYTE *rgbDig, + ULONG dwVtBits, VARIANT *pVarDst) +{ + /* Scale factors and limits for double arithmetic */ + static const double dblMultipliers[11] = { + 1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0, + 1000000.0, 10000000.0, 100000000.0, 1000000000.0, 10000000000.0 + }; + static const double dblMinimums[11] = { + R8_MIN, R8_MIN*10.0, R8_MIN*100.0, R8_MIN*1000.0, R8_MIN*10000.0, + R8_MIN*100000.0, R8_MIN*1000000.0, R8_MIN*10000000.0, + R8_MIN*100000000.0, R8_MIN*1000000000.0, R8_MIN*10000000000.0 + }; + static const double dblMaximums[11] = { + R8_MAX, R8_MAX/10.0, R8_MAX/100.0, R8_MAX/1000.0, R8_MAX/10000.0, + R8_MAX/100000.0, R8_MAX/1000000.0, R8_MAX/10000000.0, + R8_MAX/100000000.0, R8_MAX/1000000000.0, R8_MAX/10000000000.0 + }; + + int wholeNumberDigits, fractionalDigits, divisor10 = 0, multiplier10 = 0; + + TRACE("(%p,%p,0x%lx,%p)\n", pNumprs, rgbDig, dwVtBits, pVarDst); + + if (pNumprs->nBaseShift) + { + /* nBaseShift indicates a hex or octal number */ + ULONG64 ul64 = 0; + LONG64 l64; + int i; + + /* Convert the hex or octal number string into a UI64 */ + for (i = 0; i < pNumprs->cDig; i++) + { + if (ul64 > ((UI8_MAX>>pNumprs->nBaseShift) - rgbDig[i])) + { + TRACE("Overflow multiplying digits\n"); + return DISP_E_OVERFLOW; + } + ul64 = (ul64<<pNumprs->nBaseShift) + rgbDig[i]; + } + + /* also make a negative representation */ + l64=-ul64; + + /* Try signed and unsigned types in size order */ + if (dwVtBits & VTBIT_I1 && FITS_AS_I1(ul64)) + { + V_VT(pVarDst) = VT_I1; + V_I1(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_UI1 && FITS_AS_I1(ul64)) + { + V_VT(pVarDst) = VT_UI1; + V_UI1(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_I2 && FITS_AS_I2(ul64)) + { + V_VT(pVarDst) = VT_I2; + V_I2(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_UI2 && FITS_AS_I2(ul64)) + { + V_VT(pVarDst) = VT_UI2; + V_UI2(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_I4 && FITS_AS_I4(ul64)) + { + V_VT(pVarDst) = VT_I4; + V_I4(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_UI4 && FITS_AS_I4(ul64)) + { + V_VT(pVarDst) = VT_UI4; + V_UI4(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_I8 && ((ul64 <= I8_MAX)||(l64>=I8_MIN))) + { + V_VT(pVarDst) = VT_I8; + V_I8(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_UI8) + { + V_VT(pVarDst) = VT_UI8; + V_UI8(pVarDst) = ul64; + return S_OK; + } + else if ((dwVtBits & REAL_VTBITS) == VTBIT_DECIMAL) + { + V_VT(pVarDst) = VT_DECIMAL; + DEC_SIGNSCALE(&V_DECIMAL(pVarDst)) = SIGNSCALE(DECIMAL_POS,0); + DEC_HI32(&V_DECIMAL(pVarDst)) = 0; + DEC_LO64(&V_DECIMAL(pVarDst)) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_R4 && ((ul64 <= I4_MAX)||(l64 >= I4_MIN))) + { + V_VT(pVarDst) = VT_R4; + if (ul64 <= I4_MAX) + V_R4(pVarDst) = ul64; + else + V_R4(pVarDst) = l64; + return S_OK; + } + else if (dwVtBits & VTBIT_R8 && ((ul64 <= I4_MAX)||(l64 >= I4_MIN))) + { + V_VT(pVarDst) = VT_R8; + if (ul64 <= I4_MAX) + V_R8(pVarDst) = ul64; + else + V_R8(pVarDst) = l64; + return S_OK; + } + + TRACE("Overflow: possible return types: 0x%lx, value: %s\n", dwVtBits, wine_dbgstr_longlong(ul64)); + return DISP_E_OVERFLOW; + } + + /* Count the number of relevant fractional and whole digits stored, + * And compute the divisor/multiplier to scale the number by. + */ + if (pNumprs->nPwr10 < 0) + { + if (-pNumprs->nPwr10 >= pNumprs->cDig) + { + /* A real number < +/- 1.0 e.g. 0.1024 or 0.01024 */ + wholeNumberDigits = 0; + fractionalDigits = pNumprs->cDig; + divisor10 = -pNumprs->nPwr10; + } + else + { + /* An exactly represented real number e.g. 1.024 */ + wholeNumberDigits = pNumprs->cDig + pNumprs->nPwr10; + fractionalDigits = pNumprs->cDig - wholeNumberDigits; + divisor10 = pNumprs->cDig - wholeNumberDigits; + } + } + else if (pNumprs->nPwr10 == 0) + { + /* An exactly represented whole number e.g. 1024 */ + wholeNumberDigits = pNumprs->cDig; + fractionalDigits = 0; + } + else /* pNumprs->nPwr10 > 0 */ + { + /* A whole number followed by nPwr10 0's e.g. 102400 */ + wholeNumberDigits = pNumprs->cDig; + fractionalDigits = 0; + multiplier10 = pNumprs->nPwr10; + } + + TRACE("cDig %d; nPwr10 %d, whole %d, frac %d ", pNumprs->cDig, + pNumprs->nPwr10, wholeNumberDigits, fractionalDigits); + TRACE("mult %d; div %d\n", multiplier10, divisor10); + + if (dwVtBits & (INTEGER_VTBITS|VTBIT_DECIMAL) && + (!fractionalDigits || !(dwVtBits & (REAL_VTBITS|VTBIT_CY|VTBIT_DECIMAL)))) + { + /* We have one or more integer output choices, and either: + * 1) An integer input value, or + * 2) A real number input value but no floating output choices. + * Alternately, we have a DECIMAL output available and an integer input. + * + * So, place the integer value into pVarDst, using the smallest type + * possible and preferring signed over unsigned types. + */ + BOOL bOverflow = FALSE, bNegative; + ULONG64 ul64 = 0; + int i; + + /* Convert the integer part of the number into a UI8 */ + for (i = 0; i < wholeNumberDigits; i++) + { + if (ul64 > (UI8_MAX / 10 - rgbDig[i])) + { + TRACE("Overflow multiplying digits\n"); + bOverflow = TRUE; + break; + } + ul64 = ul64 * 10 + rgbDig[i]; + } + + /* Account for the scale of the number */ + if (!bOverflow && multiplier10) + { + for (i = 0; i < multiplier10; i++) + { + if (ul64 > (UI8_MAX / 10)) + { + TRACE("Overflow scaling number\n"); + bOverflow = TRUE; + break; + } + ul64 = ul64 * 10; + } + } + + /* If we have any fractional digits, round the value. + * Note we don't have to do this if divisor10 is < 1, + * because this means the fractional part must be < 0.5 + */ + if (!bOverflow && fractionalDigits && divisor10 > 0) + { + const BYTE* fracDig = rgbDig + wholeNumberDigits; + BOOL bAdjust = FALSE; + + TRACE("first decimal value is %d\n", *fracDig); + + if (*fracDig > 5) + bAdjust = TRUE; /* > 0.5 */ + else if (*fracDig == 5) + { + for (i = 1; i < fractionalDigits; i++) + { + if (fracDig[i]) + { + bAdjust = TRUE; /* > 0.5 */ + break; + } + } + /* If exactly 0.5, round only odd values */ + if (i == fractionalDigits && (ul64 & 1)) + bAdjust = TRUE; + } + + if (bAdjust) + { + if (ul64 == UI8_MAX) + { + TRACE("Overflow after rounding\n"); + bOverflow = TRUE; + } + ul64++; + } + } + + /* Zero is not a negative number */ + bNegative = pNumprs->dwOutFlags & NUMPRS_NEG && ul64 ? TRUE : FALSE; + + TRACE("Integer value is %lld, bNeg %d\n", ul64, bNegative); + + /* For negative integers, try the signed types in size order */ + if (!bOverflow && bNegative) + { + if (dwVtBits & (VTBIT_I1|VTBIT_I2|VTBIT_I4|VTBIT_I8)) + { + if (dwVtBits & VTBIT_I1 && ul64 <= -I1_MIN) + { + V_VT(pVarDst) = VT_I1; + V_I1(pVarDst) = -ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_I2 && ul64 <= -I2_MIN) + { + V_VT(pVarDst) = VT_I2; + V_I2(pVarDst) = -ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_I4 && ul64 <= -((LONGLONG)I4_MIN)) + { + V_VT(pVarDst) = VT_I4; + V_I4(pVarDst) = -ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_I8 && ul64 <= (ULONGLONG)I8_MAX + 1) + { + V_VT(pVarDst) = VT_I8; + V_I8(pVarDst) = -ul64; + return S_OK; + } + else if ((dwVtBits & REAL_VTBITS) == VTBIT_DECIMAL) + { + /* Decimal is only output choice left - fast path */ + V_VT(pVarDst) = VT_DECIMAL; + DEC_SIGNSCALE(&V_DECIMAL(pVarDst)) = SIGNSCALE(DECIMAL_NEG,0); + DEC_HI32(&V_DECIMAL(pVarDst)) = 0; + DEC_LO64(&V_DECIMAL(pVarDst)) = -ul64; + return S_OK; + } + } + } + else if (!bOverflow) + { + /* For positive integers, try signed then unsigned types in size order */ + if (dwVtBits & VTBIT_I1 && ul64 <= I1_MAX) + { + V_VT(pVarDst) = VT_I1; + V_I1(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_UI1 && ul64 <= UI1_MAX) + { + V_VT(pVarDst) = VT_UI1; + V_UI1(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_I2 && ul64 <= I2_MAX) + { + V_VT(pVarDst) = VT_I2; + V_I2(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_UI2 && ul64 <= UI2_MAX) + { + V_VT(pVarDst) = VT_UI2; + V_UI2(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_I4 && ul64 <= I4_MAX) + { + V_VT(pVarDst) = VT_I4; + V_I4(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_UI4 && ul64 <= UI4_MAX) + { + V_VT(pVarDst) = VT_UI4; + V_UI4(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_I8 && ul64 <= I8_MAX) + { + V_VT(pVarDst) = VT_I8; + V_I8(pVarDst) = ul64; + return S_OK; + } + else if (dwVtBits & VTBIT_UI8) + { + V_VT(pVarDst) = VT_UI8; + V_UI8(pVarDst) = ul64; + return S_OK; + } + else if ((dwVtBits & REAL_VTBITS) == VTBIT_DECIMAL) + { + /* Decimal is only output choice left - fast path */ + V_VT(pVarDst) = VT_DECIMAL; + DEC_SIGNSCALE(&V_DECIMAL(pVarDst)) = SIGNSCALE(DECIMAL_POS,0); + DEC_HI32(&V_DECIMAL(pVarDst)) = 0; + DEC_LO64(&V_DECIMAL(pVarDst)) = ul64; + return S_OK; + } + } + } + + if (dwVtBits & REAL_VTBITS) + { + /* Try to put the number into a float or real */ + BOOL bOverflow = FALSE, bNegative = pNumprs->dwOutFlags & NUMPRS_NEG; + double whole = 0.0; + int i; + + /* Convert the number into a double */ + for (i = 0; i < pNumprs->cDig; i++) + whole = whole * 10.0 + rgbDig[i]; + + TRACE("Whole double value is %16.16g\n", whole); + + /* Account for the scale */ + while (multiplier10 > 10) + { + if (whole > dblMaximums[10]) + { + dwVtBits &= ~(VTBIT_R4|VTBIT_R8|VTBIT_CY); + bOverflow = TRUE; + break; + } + whole = whole * dblMultipliers[10]; + multiplier10 -= 10; + } + if (multiplier10) + { + if (whole > dblMaximums[multiplier10]) + { + dwVtBits &= ~(VTBIT_R4|VTBIT_R8|VTBIT_CY); + bOverflow = TRUE; + } + else + whole = whole * dblMultipliers[multiplier10]; + } + + TRACE("Scaled double value is %16.16g\n", whole); + + while (divisor10 > 10) + { + if (whole < dblMinimums[10] && whole != 0) + { + dwVtBits &= ~(VTBIT_R4|VTBIT_R8|VTBIT_CY); /* Underflow */ + bOverflow = TRUE; + break; + } + whole = whole / dblMultipliers[10]; + divisor10 -= 10; + } + if (divisor10) + { + if (whole < dblMinimums[divisor10] && whole != 0) + { + dwVtBits &= ~(VTBIT_R4|VTBIT_R8|VTBIT_CY); /* Underflow */ + bOverflow = TRUE; + } + else + whole = whole / dblMultipliers[divisor10]; + } + if (!bOverflow) + TRACE("Final double value is %16.16g\n", whole); + + if (dwVtBits & VTBIT_R4 && + ((whole <= R4_MAX && whole >= R4_MIN) || whole == 0.0)) + { + TRACE("Set R4 to final value\n"); + V_VT(pVarDst) = VT_R4; /* Fits into a float */ + V_R4(pVarDst) = pNumprs->dwOutFlags & NUMPRS_NEG ? -whole : whole; + return S_OK; + } + + if (dwVtBits & VTBIT_R8) + { + TRACE("Set R8 to final value\n"); + V_VT(pVarDst) = VT_R8; /* Fits into a double */ + V_R8(pVarDst) = pNumprs->dwOutFlags & NUMPRS_NEG ? -whole : whole; + return S_OK; + } + + if (dwVtBits & VTBIT_CY) + { + if (SUCCEEDED(VarCyFromR8(bNegative ? -whole : whole, &V_CY(pVarDst)))) + { + V_VT(pVarDst) = VT_CY; /* Fits into a currency */ + TRACE("Set CY to final value\n"); + return S_OK; + } + TRACE("Value Overflows CY\n"); + } + } + + if (dwVtBits & VTBIT_DECIMAL) + { + int i; + ULONG carry; + ULONG64 tmp; + DECIMAL* pDec = &V_DECIMAL(pVarDst); + + DECIMAL_SETZERO(*pDec); + DEC_LO32(pDec) = 0; + + if (pNumprs->dwOutFlags & NUMPRS_NEG) + DEC_SIGN(pDec) = DECIMAL_NEG; + else + DEC_SIGN(pDec) = DECIMAL_POS; + + /* Factor the significant digits */ + for (i = 0; i < pNumprs->cDig; i++) + { + tmp = (ULONG64)DEC_LO32(pDec) * 10 + rgbDig[i]; + carry = (ULONG)(tmp >> 32); + DEC_LO32(pDec) = (ULONG)(tmp & UI4_MAX); + tmp = (ULONG64)DEC_MID32(pDec) * 10 + carry; + carry = (ULONG)(tmp >> 32); + DEC_MID32(pDec) = (ULONG)(tmp & UI4_MAX); + tmp = (ULONG64)DEC_HI32(pDec) * 10 + carry; + DEC_HI32(pDec) = (ULONG)(tmp & UI4_MAX); + + if (tmp >> 32 & UI4_MAX) + { +VarNumFromParseNum_DecOverflow: + TRACE("Overflow\n"); + DEC_LO32(pDec) = DEC_MID32(pDec) = DEC_HI32(pDec) = UI4_MAX; + return DISP_E_OVERFLOW; + } + } + + /* Account for the scale of the number */ + while (multiplier10 > 0) + { + tmp = (ULONG64)DEC_LO32(pDec) * 10; + carry = (ULONG)(tmp >> 32); + DEC_LO32(pDec) = (ULONG)(tmp & UI4_MAX); + tmp = (ULONG64)DEC_MID32(pDec) * 10 + carry; + carry = (ULONG)(tmp >> 32); + DEC_MID32(pDec) = (ULONG)(tmp & UI4_MAX); + tmp = (ULONG64)DEC_HI32(pDec) * 10 + carry; + DEC_HI32(pDec) = (ULONG)(tmp & UI4_MAX); + + if (tmp >> 32 & UI4_MAX) + goto VarNumFromParseNum_DecOverflow; + multiplier10--; + } + DEC_SCALE(pDec) = divisor10; + + V_VT(pVarDst) = VT_DECIMAL; + return S_OK; + } + return DISP_E_OVERFLOW; /* No more output choices */ +} + +/********************************************************************** + * VarCat [OLEAUT32.318] + */ +HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out) +{ + TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left), + debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), out); + + /* Should we VariantClear out? */ + /* Can we handle array, vector, by ref etc. */ + if ((V_VT(left)&VT_TYPEMASK) == VT_NULL && + (V_VT(right)&VT_TYPEMASK) == VT_NULL) + { + V_VT(out) = VT_NULL; + return S_OK; + } + + if (V_VT(left) == VT_BSTR && V_VT(right) == VT_BSTR) + { + V_VT(out) = VT_BSTR; + VarBstrCat (V_BSTR(left), V_BSTR(right), &V_BSTR(out)); + return S_OK; + } + if (V_VT(left) == VT_BSTR) { + VARIANT bstrvar; + HRESULT hres; + + V_VT(out) = VT_BSTR; + VariantInit(&bstrvar); + hres = VariantChangeTypeEx(&bstrvar,right,0,0,VT_BSTR); + if (hres) { + FIXME("Failed to convert right side from vt %d to VT_BSTR?\n",V_VT(right)); + return hres; + } + VarBstrCat (V_BSTR(left), V_BSTR(&bstrvar), &V_BSTR(out)); + return S_OK; + } + if (V_VT(right) == VT_BSTR) { + VARIANT bstrvar; + HRESULT hres; + + V_VT(out) = VT_BSTR; + VariantInit(&bstrvar); + hres = VariantChangeTypeEx(&bstrvar,left,0,0,VT_BSTR); + if (hres) { + FIXME("Failed to convert right side from vt %d to VT_BSTR?\n",V_VT(right)); + return hres; + } + VarBstrCat (V_BSTR(&bstrvar), V_BSTR(right), &V_BSTR(out)); + return S_OK; + } + FIXME ("types %d / %d not supported\n",V_VT(left)&VT_TYPEMASK, V_VT(right)&VT_TYPEMASK); + return S_OK; +} + +/********************************************************************** + * VarCmp [OLEAUT32.176] + * + * flags can be: + * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS + * NORM_IGNOREWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA + * + */ +HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags) +{ + BOOL lOk = TRUE; + BOOL rOk = TRUE; + LONGLONG lVal = -1; + LONGLONG rVal = -1; + VARIANT rv,lv; + DWORD xmask; + HRESULT rc; + + TRACE("(%p->(%s%s),%p->(%s%s),0x%08lx,0x%08lx)\n", left, debugstr_VT(left), + debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), lcid, flags); + + VariantInit(&lv);VariantInit(&rv); + V_VT(right) &= ~0x8000; /* hack since we sometime get this flag. */ + V_VT(left) &= ~0x8000; /* hack since we sometime get this flag. */ + + /* If either are null, then return VARCMP_NULL */ + if ((V_VT(left)&VT_TYPEMASK) == VT_NULL || + (V_VT(right)&VT_TYPEMASK) == VT_NULL) + return VARCMP_NULL; + + /* Strings - use VarBstrCmp */ + if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR && + (V_VT(right)&VT_TYPEMASK) == VT_BSTR) { + return VarBstrCmp(V_BSTR(left), V_BSTR(right), lcid, flags); + } + + xmask = (1<<(V_VT(left)&VT_TYPEMASK))|(1<<(V_VT(right)&VT_TYPEMASK)); + if (xmask & VTBIT_R8) { + rc = VariantChangeType(&lv,left,0,VT_R8); + if (FAILED(rc)) return rc; + rc = VariantChangeType(&rv,right,0,VT_R8); + if (FAILED(rc)) return rc; + + if (V_R8(&lv) == V_R8(&rv)) return VARCMP_EQ; + if (V_R8(&lv) < V_R8(&rv)) return VARCMP_LT; + if (V_R8(&lv) > V_R8(&rv)) return VARCMP_GT; + return E_FAIL; /* can't get here */ + } + if (xmask & VTBIT_R4) { + rc = VariantChangeType(&lv,left,0,VT_R4); + if (FAILED(rc)) return rc; + rc = VariantChangeType(&rv,right,0,VT_R4); + if (FAILED(rc)) return rc; + + if (V_R4(&lv) == V_R4(&rv)) return VARCMP_EQ; + if (V_R4(&lv) < V_R4(&rv)) return VARCMP_LT; + if (V_R4(&lv) > V_R4(&rv)) return VARCMP_GT; + return E_FAIL; /* can't get here */ + } + + /* Integers - Ideally like to use VarDecCmp, but no Dec support yet + Use LONGLONG to maximize ranges */ + lOk = TRUE; + switch (V_VT(left)&VT_TYPEMASK) { + case VT_I1 : lVal = V_I1(left); break; + case VT_I2 : lVal = V_I2(left); break; + case VT_I4 : + case VT_INT : lVal = V_I4(left); break; + case VT_UI1 : lVal = V_UI1(left); break; + case VT_UI2 : lVal = V_UI2(left); break; + case VT_UI4 : + case VT_UINT : lVal = V_UI4(left); break; + case VT_BOOL : lVal = V_BOOL(left); break; + default: lOk = FALSE; + } + + rOk = TRUE; + switch (V_VT(right)&VT_TYPEMASK) { + case VT_I1 : rVal = V_I1(right); break; + case VT_I2 : rVal = V_I2(right); break; + case VT_I4 : + case VT_INT : rVal = V_I4(right); break; + case VT_UI1 : rVal = V_UI1(right); break; + case VT_UI2 : rVal = V_UI2(right); break; + case VT_UI4 : + case VT_UINT : rVal = V_UI4(right); break; + case VT_BOOL : rVal = V_BOOL(right); break; + default: rOk = FALSE; + } + + if (lOk && rOk) { + if (lVal < rVal) { + return VARCMP_LT; + } else if (lVal > rVal) { + return VARCMP_GT; + } else { + return VARCMP_EQ; + } + } + + /* Strings - use VarBstrCmp */ + if ((V_VT(left)&VT_TYPEMASK) == VT_DATE && + (V_VT(right)&VT_TYPEMASK) == VT_DATE) { + + if (floor(V_DATE(left)) == floor(V_DATE(right))) { + /* Due to floating point rounding errors, calculate varDate in whole numbers) */ + double wholePart = 0.0; + double leftR; + double rightR; + + /* Get the fraction * 24*60*60 to make it into whole seconds */ + wholePart = (double) floor( V_DATE(left) ); + if (wholePart == 0) wholePart = 1; + leftR = floor(fmod( V_DATE(left), wholePart ) * (24*60*60)); + + wholePart = (double) floor( V_DATE(right) ); + if (wholePart == 0) wholePart = 1; + rightR = floor(fmod( V_DATE(right), wholePart ) * (24*60*60)); + + if (leftR < rightR) { + return VARCMP_LT; + } else if (leftR > rightR) { + return VARCMP_GT; + } else { + return VARCMP_EQ; + } + + } else if (V_DATE(left) < V_DATE(right)) { + return VARCMP_LT; + } else if (V_DATE(left) > V_DATE(right)) { + return VARCMP_GT; + } + } + FIXME("VarCmp partial implementation, doesn't support vt 0x%x / 0x%x\n",V_VT(left), V_VT(right)); + return E_FAIL; +} + +/********************************************************************** + * VarAnd [OLEAUT32.142] + * + */ +HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result) +{ + HRESULT rc = E_FAIL; + + TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left), + debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), result); + + if ((V_VT(left)&VT_TYPEMASK) == VT_BOOL && + (V_VT(right)&VT_TYPEMASK) == VT_BOOL) { + + V_VT(result) = VT_BOOL; + if (V_BOOL(left) && V_BOOL(right)) { + V_BOOL(result) = VARIANT_TRUE; + } else { + V_BOOL(result) = VARIANT_FALSE; + } + rc = S_OK; + + } else { + /* Integers */ + BOOL lOk = TRUE; + BOOL rOk = TRUE; + LONGLONG lVal = -1; + LONGLONG rVal = -1; + LONGLONG res = -1; + int resT = 0; /* Testing has shown I2 & I2 == I2, all else + becomes I4, even unsigned ints (incl. UI2) */ + + lOk = TRUE; + switch (V_VT(left)&VT_TYPEMASK) { + case VT_I1 : lVal = V_I1(left); resT=VT_I4; break; + case VT_I2 : lVal = V_I2(left); resT=VT_I2; break; + case VT_I4 : + case VT_INT : lVal = V_I4(left); resT=VT_I4; break; + case VT_UI1 : lVal = V_UI1(left); resT=VT_I4; break; + case VT_UI2 : lVal = V_UI2(left); resT=VT_I4; break; + case VT_UI4 : + case VT_UINT : lVal = V_UI4(left); resT=VT_I4; break; + case VT_BOOL : rVal = V_BOOL(left); resT=VT_I4; break; + default: lOk = FALSE; + } + + rOk = TRUE; + switch (V_VT(right)&VT_TYPEMASK) { + case VT_I1 : rVal = V_I1(right); resT=VT_I4; break; + case VT_I2 : rVal = V_I2(right); resT=max(VT_I2, resT); break; + case VT_I4 : + case VT_INT : rVal = V_I4(right); resT=VT_I4; break; + case VT_UI1 : rVal = V_UI1(right); resT=VT_I4; break; + case VT_UI2 : rVal = V_UI2(right); resT=VT_I4; break; + case VT_UI4 : + case VT_UINT : rVal = V_UI4(right); resT=VT_I4; break; + case VT_BOOL : rVal = V_BOOL(right); resT=VT_I4; break; + default: rOk = FALSE; + } + + if (lOk && rOk) { + res = (lVal & rVal); + V_VT(result) = resT; + switch (resT) { + case VT_I2 : V_I2(result) = res; break; + case VT_I4 : V_I4(result) = res; break; + default: + FIXME("Unexpected result variant type %x\n", resT); + V_I4(result) = res; + } + rc = S_OK; + + } else { + FIXME("VarAnd stub\n"); + } + } + + TRACE("returning 0x%8lx (%s%s),%ld\n", rc, debugstr_VT(result), + debugstr_VF(result), V_VT(result) == VT_I4 ? V_I4(result) : V_I2(result)); + return rc; +} + +/********************************************************************** + * VarAdd [OLEAUT32.141] + * FIXME: From MSDN: If ... Then + * Both expressions are of the string type Concatenated. + * One expression is a string type and the other a character Addition. + * One expression is numeric and the other is a string Addition. + * Both expressions are numeric Addition. + * Either expression is NULL NULL is returned. + * Both expressions are empty Integer subtype is returned. + * + */ +HRESULT WINAPI VarAdd(LPVARIANT left, LPVARIANT right, LPVARIANT result) +{ + HRESULT rc = E_FAIL; + + TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left), + debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), result); + + if ((V_VT(left)&VT_TYPEMASK) == VT_EMPTY) + return VariantCopy(result,right); + + if ((V_VT(right)&VT_TYPEMASK) == VT_EMPTY) + return VariantCopy(result,left); + + /* check if we add doubles */ + if (((V_VT(left)&VT_TYPEMASK) == VT_R8) || ((V_VT(right)&VT_TYPEMASK) == VT_R8)) { + BOOL lOk = TRUE; + BOOL rOk = TRUE; + double lVal = -1; + double rVal = -1; + double res = -1; + + lOk = TRUE; + switch (V_VT(left)&VT_TYPEMASK) { + case VT_I1 : lVal = V_I1(left); break; + case VT_I2 : lVal = V_I2(left); break; + case VT_I4 : + case VT_INT : lVal = V_I4(left); break; + case VT_UI1 : lVal = V_UI1(left); break; + case VT_UI2 : lVal = V_UI2(left); break; + case VT_UI4 : + case VT_UINT : lVal = V_UI4(left); break; + case VT_R4 : lVal = V_R4(left); break; + case VT_R8 : lVal = V_R8(left); break; + case VT_NULL : lVal = 0.0; break; + default: lOk = FALSE; + } + + rOk = TRUE; + switch (V_VT(right)&VT_TYPEMASK) { + case VT_I1 : rVal = V_I1(right); break; + case VT_I2 : rVal = V_I2(right); break; + case VT_I4 : + case VT_INT : rVal = V_I4(right); break; + case VT_UI1 : rVal = V_UI1(right); break; + case VT_UI2 : rVal = V_UI2(right); break; + case VT_UI4 : + case VT_UINT : rVal = V_UI4(right); break; + case VT_R4 : rVal = V_R4(right);break; + case VT_R8 : rVal = V_R8(right);break; + case VT_NULL : rVal = 0.0; break; + default: rOk = FALSE; + } + + if (lOk && rOk) { + res = (lVal + rVal); + V_VT(result) = VT_R8; + V_R8(result) = res; + rc = S_OK; + } else { + FIXME("Unhandled type pair %d / %d in double addition.\n", + (V_VT(left)&VT_TYPEMASK), + (V_VT(right)&VT_TYPEMASK) + ); + } + return rc; + } + + /* now check if we add floats. VT_R8 can no longer happen here! */ + if (((V_VT(left)&VT_TYPEMASK) == VT_R4) || ((V_VT(right)&VT_TYPEMASK) == VT_R4)) { + BOOL lOk = TRUE; + BOOL rOk = TRUE; + float lVal = -1; + float rVal = -1; + float res = -1; + + lOk = TRUE; + switch (V_VT(left)&VT_TYPEMASK) { + case VT_I1 : lVal = V_I1(left); break; + case VT_I2 : lVal = V_I2(left); break; + case VT_I4 : + case VT_INT : lVal = V_I4(left); break; + case VT_UI1 : lVal = V_UI1(left); break; + case VT_UI2 : lVal = V_UI2(left); break; + case VT_UI4 : + case VT_UINT : lVal = V_UI4(left); break; + case VT_R4 : lVal = V_R4(left); break; + case VT_NULL : lVal = 0.0; break; + default: lOk = FALSE; + } + + rOk = TRUE; + switch (V_VT(right)&VT_TYPEMASK) { + case VT_I1 : rVal = V_I1(right); break; + case VT_I2 : rVal = V_I2(right); break; + case VT_I4 : + case VT_INT : rVal = V_I4(right); break; + case VT_UI1 : rVal = V_UI1(right); break; + case VT_UI2 : rVal = V_UI2(right); break; + case VT_UI4 : + case VT_UINT : rVal = V_UI4(right); break; + case VT_R4 : rVal = V_R4(right);break; + case VT_NULL : rVal = 0.0; break; + default: rOk = FALSE; + } + + if (lOk && rOk) { + res = (lVal + rVal); + V_VT(result) = VT_R4; + V_R4(result) = res; + rc = S_OK; + } else { + FIXME("Unhandled type pair %d / %d in float addition.\n", + (V_VT(left)&VT_TYPEMASK), + (V_VT(right)&VT_TYPEMASK) + ); + } + return rc; + } + + /* Handle strings as concat */ + if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR && + (V_VT(right)&VT_TYPEMASK) == VT_BSTR) { + V_VT(result) = VT_BSTR; + return VarBstrCat(V_BSTR(left), V_BSTR(right), &V_BSTR(result)); + } else { + + /* Integers */ + BOOL lOk = TRUE; + BOOL rOk = TRUE; + LONGLONG lVal = -1; + LONGLONG rVal = -1; + LONGLONG res = -1; + int resT = 0; /* Testing has shown I2 + I2 == I2, all else + becomes I4 */ + + lOk = TRUE; + switch (V_VT(left)&VT_TYPEMASK) { + case VT_I1 : lVal = V_I1(left); resT=VT_I4; break; + case VT_I2 : lVal = V_I2(left); resT=VT_I2; break; + case VT_I4 : + case VT_INT : lVal = V_I4(left); resT=VT_I4; break; + case VT_UI1 : lVal = V_UI1(left); resT=VT_I4; break; + case VT_UI2 : lVal = V_UI2(left); resT=VT_I4; break; + case VT_UI4 : + case VT_UINT : lVal = V_UI4(left); resT=VT_I4; break; + case VT_NULL : lVal = 0; resT = VT_I4; break; + default: lOk = FALSE; + } + + rOk = TRUE; + switch (V_VT(right)&VT_TYPEMASK) { + case VT_I1 : rVal = V_I1(right); resT=VT_I4; break; + case VT_I2 : rVal = V_I2(right); resT=max(VT_I2, resT); break; + case VT_I4 : + case VT_INT : rVal = V_I4(right); resT=VT_I4; break; + case VT_UI1 : rVal = V_UI1(right); resT=VT_I4; break; + case VT_UI2 : rVal = V_UI2(right); resT=VT_I4; break; + case VT_UI4 : + case VT_UINT : rVal = V_UI4(right); resT=VT_I4; break; + case VT_NULL : rVal = 0; resT=VT_I4; break; + default: rOk = FALSE; + } + + if (lOk && rOk) { + res = (lVal + rVal); + V_VT(result) = resT; + switch (resT) { + case VT_I2 : V_I2(result) = res; break; + case VT_I4 : V_I4(result) = res; break; + default: + FIXME("Unexpected result variant type %x\n", resT); + V_I4(result) = res; + } + rc = S_OK; + + } else { + FIXME("unimplemented part (0x%x + 0x%x)\n",V_VT(left), V_VT(right)); + } + } + + TRACE("returning 0x%8lx (%s%s),%ld\n", rc, debugstr_VT(result), + debugstr_VF(result), V_VT(result) == VT_I4 ? V_I4(result) : V_I2(result)); + return rc; +} + +/********************************************************************** + * VarMul [OLEAUT32.156] + * + * Multiply two variants. + * + * PARAMS + * left [I] First variant + * right [I] Second variant + * result [O] Result variant + * + * RETURNS + * Success: S_OK. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * Native VarMul up to and including WinXP dosn't like as input variants + * I1, UI2, UI4, UI8, INT and UINT. But it can multiply apples with oranges. + * + * Native VarMul dosn't check for NULL in/out pointers and crashes. We do the + * same here. + * + * FIXME + * Overflow checking for R8 (double) overflow. Return DISP_E_OVERFLOW in that + * case. + */ +HRESULT WINAPI VarMul(LPVARIANT left, LPVARIANT right, LPVARIANT result) +{ + HRESULT hres; + VARTYPE lvt, rvt, resvt, tvt; + VARIANT lv, rv, tv; + double r8res; + + /* Variant priority for coercion. Sorted from lowest to highest. + VT_ERROR shows an invalid input variant type. */ + enum coerceprio { vt_UI1 = 0, vt_I2, vt_I4, vt_I8, vt_CY, vt_R4, vt_R8, + vt_DECIMAL, vt_NULL, vt_ERROR }; + /* Mapping from priority to variant type. Keep in sync with coerceprio! */ + VARTYPE prio2vt[] = { VT_UI1, VT_I2, VT_I4, VT_I8, VT_CY, VT_R4, VT_R8, + VT_DECIMAL, VT_NULL, VT_ERROR }; + + /* Mapping for coercion from input variant to priority of result variant. */ + static VARTYPE coerce[] = { + /* VT_EMPTY, VT_NULL, VT_I2, VT_I4, VT_R4 */ + vt_UI1, vt_NULL, vt_I2, vt_I4, vt_R4, + /* VT_R8, VT_CY, VT_DATE, VT_BSTR, VT_DISPATCH */ + vt_R8, vt_CY, vt_R8, vt_R8, vt_ERROR, + /* VT_ERROR, VT_BOOL, VT_VARIANT, VT_UNKNOWN, VT_DECIMAL */ + vt_ERROR, vt_I2, vt_ERROR, vt_ERROR, vt_DECIMAL, + /* 15, VT_I1, VT_UI1, VT_UI2, VT_UI4 VT_I8 */ + vt_ERROR, vt_ERROR, vt_UI1, vt_ERROR, vt_ERROR, vt_I8 + }; + + TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left), + debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), + result); + + VariantInit(&lv); + VariantInit(&rv); + VariantInit(&tv); + lvt = V_VT(left)&VT_TYPEMASK; + rvt = V_VT(right)&VT_TYPEMASK; + + /* If we have any flag set (VT_ARRAY, VT_VECTOR, etc.) bail out. + Same for any input variant type > VT_I8 */ + if (V_VT(left) & ~VT_TYPEMASK || V_VT(right) & ~VT_TYPEMASK || + lvt > VT_I8 || rvt > VT_I8) { + hres = DISP_E_BADVARTYPE; + goto end; + } + + /* Determine the variant type to coerce to. */ + if (coerce[lvt] > coerce[rvt]) { + resvt = prio2vt[coerce[lvt]]; + tvt = prio2vt[coerce[rvt]]; + } else { + resvt = prio2vt[coerce[rvt]]; + tvt = prio2vt[coerce[lvt]]; + } + + /* Special cases where the result variant type is defined by both + input variants and not only that with the highest priority */ + if (resvt == VT_R4 && (tvt == VT_CY || tvt == VT_I8 || tvt == VT_I4)) + resvt = VT_R8; + if (lvt == VT_EMPTY && rvt == VT_EMPTY) + resvt = VT_I2; + + /* For overflow detection use the biggest compatible type for the + multiplication */ + switch (resvt) { + case VT_ERROR: + hres = DISP_E_BADVARTYPE; + goto end; + case VT_NULL: + hres = S_OK; + V_VT(result) = VT_NULL; + goto end; + case VT_UI1: + case VT_I2: + case VT_I4: + case VT_I8: + tvt = VT_I8; + break; + case VT_R4: + tvt = VT_R8; + break; + default: + tvt = resvt; + } + + /* Now coerce the variants */ + hres = VariantChangeType(&lv, left, 0, tvt); + if (FAILED(hres)) + goto end; + hres = VariantChangeType(&rv, right, 0, tvt); + if (FAILED(hres)) + goto end; + + /* Do the math */ + hres = S_OK; + V_VT(&tv) = tvt; + V_VT(result) = resvt; + switch (tvt) { + case VT_DECIMAL: + hres = VarDecMul(&V_DECIMAL(&lv), &V_DECIMAL(&rv), + &V_DECIMAL(result)); + goto end; + case VT_CY: + hres = VarCyMul(V_CY(&lv), V_CY(&rv), &V_CY(result)); + goto end; + case VT_I8: + /* Overflow detection */ + r8res = (double)V_I8(&lv) * (double)V_I8(&rv); + if (r8res > (double)I8_MAX || r8res < (double)I8_MIN) { + V_VT(result) = VT_R8; + V_R8(result) = r8res; + goto end; + } else + V_I8(&tv) = V_I8(&lv) * V_I8(&rv); + break; + case VT_R8: + /* FIXME: overflow detection */ + V_R8(&tv) = V_R8(&lv) * V_R8(&rv); + break; + default: + ERR("We shouldn't get here! tvt = %d!\n", tvt); + break; + } + if (rvt != tvt) { + while ((hres = VariantChangeType(result, &tv, 0, resvt)) != S_OK) { + /* Overflow! Change to the vartype with the next higher priority */ + resvt = prio2vt[coerce[resvt] + 1]; + } + } else + hres = VariantCopy(result, &tv); + +end: + if (hres != S_OK) { + V_VT(result) = VT_EMPTY; + V_I4(result) = 0; /* No V_EMPTY */ + } + VariantClear(&lv); + VariantClear(&rv); + VariantClear(&tv); + TRACE("returning 0x%8lx (variant type %s)\n", hres, debugstr_VT(result)); + return hres; +} + +/********************************************************************** + * VarDiv [OLEAUT32.143] + * + */ +HRESULT WINAPI VarDiv(LPVARIANT left, LPVARIANT right, LPVARIANT result) +{ + HRESULT rc = E_FAIL; + VARTYPE lvt,rvt,resvt; + VARIANT lv,rv; + BOOL found; + + TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left), + debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), result); + + VariantInit(&lv);VariantInit(&rv); + lvt = V_VT(left)&VT_TYPEMASK; + rvt = V_VT(right)&VT_TYPEMASK; + found = FALSE;resvt = VT_VOID; + if (((1<<lvt) | (1<<rvt)) & (VTBIT_R4|VTBIT_R8)) { + found = TRUE; + resvt = VT_R8; + } + if (!found && (((1<<lvt) | (1<<rvt)) & (VTBIT_I1|VTBIT_I2|VTBIT_UI1|VTBIT_UI2|VTBIT_I4|VTBIT_UI4|(1<<VT_INT)|(1<<VT_UINT)))) { + found = TRUE; + resvt = VT_I4; + } + if (!found) { + FIXME("can't expand vt %d vs %d to a target type.\n",lvt,rvt); + return E_FAIL; + } + rc = VariantChangeType(&lv, left, 0, resvt); + if (FAILED(rc)) { + FIXME("Could not convert 0x%x to %d?\n",V_VT(left),resvt); + return rc; + } + rc = VariantChangeType(&rv, right, 0, resvt); + if (FAILED(rc)) { + FIXME("Could not convert 0x%x to %d?\n",V_VT(right),resvt); + return rc; + } + switch (resvt) { + case VT_R8: + if (V_R8(&rv) == 0) return DISP_E_DIVBYZERO; + V_VT(result) = resvt; + V_R8(result) = V_R8(&lv) / V_R8(&rv); + rc = S_OK; + break; + case VT_I4: + if (V_I4(&rv) == 0) return DISP_E_DIVBYZERO; + V_VT(result) = resvt; + V_I4(result) = V_I4(&lv) / V_I4(&rv); + rc = S_OK; + break; + } + TRACE("returning 0x%8lx (%s%s),%g\n", rc, debugstr_VT(result), + debugstr_VF(result), V_VT(result) == VT_R8 ? V_R8(result) : (double)V_I4(result)); + return rc; +} + +/********************************************************************** + * VarSub [OLEAUT32.159] + * + */ +HRESULT WINAPI VarSub(LPVARIANT left, LPVARIANT right, LPVARIANT result) +{ + HRESULT rc = E_FAIL; + VARTYPE lvt,rvt,resvt; + VARIANT lv,rv; + BOOL found; + + TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left), + debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), result); + + VariantInit(&lv);VariantInit(&rv); + lvt = V_VT(left)&VT_TYPEMASK; + rvt = V_VT(right)&VT_TYPEMASK; + found = FALSE;resvt = VT_VOID; + if (((1<<lvt) | (1<<rvt)) & ((1<<VT_DATE)|(1<<VT_R4)|(1<<VT_R8))) { + found = TRUE; + resvt = VT_R8; + } + if (!found && (((1<<lvt) | (1<<rvt)) & (VTBIT_I1|VTBIT_I2|VTBIT_UI1|VTBIT_UI2|VTBIT_I4|VTBIT_UI4|(1<<VT_INT)|(1<<VT_UINT)))) { + found = TRUE; + resvt = VT_I4; + } + if (!found) { + FIXME("can't expand vt %d vs %d to a target type.\n",lvt,rvt); + return E_FAIL; + } + rc = VariantChangeType(&lv, left, 0, resvt); + if (FAILED(rc)) { + FIXME("Could not convert 0x%x to %d?\n",V_VT(left),resvt); + return rc; + } + rc = VariantChangeType(&rv, right, 0, resvt); + if (FAILED(rc)) { + FIXME("Could not convert 0x%x to %d?\n",V_VT(right),resvt); + return rc; + } + switch (resvt) { + case VT_R8: + V_VT(result) = resvt; + V_R8(result) = V_R8(&lv) - V_R8(&rv); + rc = S_OK; + break; + case VT_I4: + V_VT(result) = resvt; + V_I4(result) = V_I4(&lv) - V_I4(&rv); + rc = S_OK; + break; + } + TRACE("returning 0x%8lx (%s%s),%g\n", rc, debugstr_VT(result), + debugstr_VF(result), V_VT(result) == VT_R8 ? V_R8(result) : (double)V_I4(result)); + return rc; +} + +/********************************************************************** + * VarOr [OLEAUT32.157] + * + * Perform a logical or (OR) operation on two variants. + * + * PARAMS + * pVarLeft [I] First variant + * pVarRight [I] Variant to OR with pVarLeft + * pVarOut [O] Destination for OR result + * + * RETURNS + * Success: S_OK. pVarOut contains the result of the operation with its type + * taken from the table listed under VarXor(). + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * See the Notes section of VarXor() for further information. + */ +HRESULT WINAPI VarOr(LPVARIANT pVarLeft, LPVARIANT pVarRight, LPVARIANT pVarOut) +{ + VARTYPE vt = VT_I4; + VARIANT varLeft, varRight, varStr; + HRESULT hRet; + + TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", pVarLeft, debugstr_VT(pVarLeft), + debugstr_VF(pVarLeft), pVarRight, debugstr_VT(pVarRight), + debugstr_VF(pVarRight), pVarOut); + + if (V_EXTRA_TYPE(pVarLeft) || V_EXTRA_TYPE(pVarRight) || + V_VT(pVarLeft) == VT_UNKNOWN || V_VT(pVarRight) == VT_UNKNOWN || + V_VT(pVarLeft) == VT_DISPATCH || V_VT(pVarRight) == VT_DISPATCH || + V_VT(pVarLeft) == VT_RECORD || V_VT(pVarRight) == VT_RECORD) + return DISP_E_BADVARTYPE; + + V_VT(&varLeft) = V_VT(&varRight) = V_VT(&varStr) = VT_EMPTY; + + if (V_VT(pVarLeft) == VT_NULL || V_VT(pVarRight) == VT_NULL) + { + /* NULL OR Zero is NULL, NULL OR value is value */ + if (V_VT(pVarLeft) == VT_NULL) + pVarLeft = pVarRight; /* point to the non-NULL var */ + + V_VT(pVarOut) = VT_NULL; + V_I4(pVarOut) = 0; + + switch (V_VT(pVarLeft)) + { + case VT_DATE: case VT_R8: + if (V_R8(pVarLeft)) + goto VarOr_AsEmpty; + return S_OK; + case VT_BOOL: + if (V_BOOL(pVarLeft)) + *pVarOut = *pVarLeft; + return S_OK; + case VT_I2: case VT_UI2: + if (V_I2(pVarLeft)) + goto VarOr_AsEmpty; + return S_OK; + case VT_I1: + if (V_I1(pVarLeft)) + goto VarOr_AsEmpty; + return S_OK; + case VT_UI1: + if (V_UI1(pVarLeft)) + *pVarOut = *pVarLeft; + return S_OK; + case VT_R4: + if (V_R4(pVarLeft)) + goto VarOr_AsEmpty; + return S_OK; + case VT_I4: case VT_UI4: case VT_INT: case VT_UINT: + if (V_I4(pVarLeft)) + goto VarOr_AsEmpty; + return S_OK; + case VT_CY: + if (V_CY(pVarLeft).int64) + goto VarOr_AsEmpty; + return S_OK; + case VT_I8: case VT_UI8: + if (V_I8(pVarLeft)) + goto VarOr_AsEmpty; + return S_OK; + case VT_DECIMAL: + if (DEC_HI32(&V_DECIMAL(pVarLeft)) || DEC_LO64(&V_DECIMAL(pVarLeft))) + goto VarOr_AsEmpty; + return S_OK; + case VT_BSTR: + { + VARIANT_BOOL b; + + if (!V_BSTR(pVarLeft)) + return DISP_E_BADVARTYPE; + + hRet = VarBoolFromStr(V_BSTR(pVarLeft), LOCALE_USER_DEFAULT, VAR_LOCALBOOL, &b); + if (SUCCEEDED(hRet) && b) + { + V_VT(pVarOut) = VT_BOOL; + V_BOOL(pVarOut) = b; + } + return hRet; + } + case VT_NULL: case VT_EMPTY: + V_VT(pVarOut) = VT_NULL; + return S_OK; + default: + return DISP_E_BADVARTYPE; + } + } + + if (V_VT(pVarLeft) == VT_EMPTY || V_VT(pVarRight) == VT_EMPTY) + { + if (V_VT(pVarLeft) == VT_EMPTY) + pVarLeft = pVarRight; /* point to the non-EMPTY var */ + +VarOr_AsEmpty: + /* Since one argument is empty (0), OR'ing it with the other simply + * gives the others value (as 0|x => x). So just convert the other + * argument to the required result type. + */ + switch (V_VT(pVarLeft)) + { + case VT_BSTR: + if (!V_BSTR(pVarLeft)) + return DISP_E_BADVARTYPE; + + hRet = VariantCopy(&varStr, pVarLeft); + if (FAILED(hRet)) + goto VarOr_Exit; + pVarLeft = &varStr; + hRet = VariantChangeType(pVarLeft, pVarLeft, 0, VT_BOOL); + if (FAILED(hRet)) + goto VarOr_Exit; + /* Fall Through ... */ + case VT_EMPTY: case VT_UI1: case VT_BOOL: case VT_I2: + V_VT(pVarOut) = VT_I2; + break; + case VT_DATE: case VT_CY: case VT_DECIMAL: case VT_R4: case VT_R8: + case VT_I1: case VT_UI2: case VT_I4: case VT_UI4: + case VT_INT: case VT_UINT: case VT_UI8: + V_VT(pVarOut) = VT_I4; + break; + case VT_I8: + V_VT(pVarOut) = VT_I8; + break; + default: + return DISP_E_BADVARTYPE; + } + hRet = VariantCopy(&varLeft, pVarLeft); + if (FAILED(hRet)) + goto VarOr_Exit; + pVarLeft = &varLeft; + hRet = VariantChangeType(pVarOut, pVarLeft, 0, V_VT(pVarOut)); + goto VarOr_Exit; + } + + if (V_VT(pVarLeft) == VT_BOOL && V_VT(pVarRight) == VT_BOOL) + { + V_VT(pVarOut) = VT_BOOL; + V_BOOL(pVarOut) = V_BOOL(pVarLeft) | V_BOOL(pVarRight); + return S_OK; + } + + if (V_VT(pVarLeft) == VT_UI1 && V_VT(pVarRight) == VT_UI1) + { + V_VT(pVarOut) = VT_UI1; + V_UI1(pVarOut) = V_UI1(pVarLeft) | V_UI1(pVarRight); + return S_OK; + } + + if (V_VT(pVarLeft) == VT_BSTR) + { + hRet = VariantCopy(&varStr, pVarLeft); + if (FAILED(hRet)) + goto VarOr_Exit; + pVarLeft = &varStr; + hRet = VariantChangeType(pVarLeft, pVarLeft, 0, VT_BOOL); + if (FAILED(hRet)) + goto VarOr_Exit; + } + + if (V_VT(pVarLeft) == VT_BOOL && + (V_VT(pVarRight) == VT_BOOL || V_VT(pVarRight) == VT_BSTR)) + { + vt = VT_BOOL; + } + else if ((V_VT(pVarLeft) == VT_BOOL || V_VT(pVarLeft) == VT_UI1 || + V_VT(pVarLeft) == VT_I2 || V_VT(pVarLeft) == VT_BSTR) && + (V_VT(pVarRight) == VT_BOOL || V_VT(pVarRight) == VT_UI1 || + V_VT(pVarRight) == VT_I2 || V_VT(pVarRight) == VT_BSTR)) + { + vt = VT_I2; + } + else if (V_VT(pVarLeft) == VT_I8 || V_VT(pVarRight) == VT_I8) + { + if (V_VT(pVarLeft) == VT_INT || V_VT(pVarRight) == VT_INT) + return DISP_E_TYPEMISMATCH; + vt = VT_I8; + } + + hRet = VariantCopy(&varLeft, pVarLeft); + if (FAILED(hRet)) + goto VarOr_Exit; + + hRet = VariantCopy(&varRight, pVarRight); + if (FAILED(hRet)) + goto VarOr_Exit; + + if (vt == VT_I4 && V_VT(&varLeft) == VT_UI4) + V_VT(&varLeft) = VT_I4; /* Don't overflow */ + else + { + double d; + + if (V_VT(&varLeft) == VT_BSTR && + FAILED(VarR8FromStr(V_BSTR(&varLeft), LOCALE_USER_DEFAULT, 0, &d))) + hRet = VariantChangeType(&varLeft, &varLeft, VARIANT_LOCALBOOL, VT_BOOL); + if (SUCCEEDED(hRet) && V_VT(&varLeft) != vt) + hRet = VariantChangeType(&varLeft, &varLeft, 0, vt); + if (FAILED(hRet)) + goto VarOr_Exit; + } + + if (vt == VT_I4 && V_VT(&varRight) == VT_UI4) + V_VT(&varRight) = VT_I4; /* Don't overflow */ + else + { + double d; + + if (V_VT(&varRight) == VT_BSTR && + FAILED(VarR8FromStr(V_BSTR(&varRight), LOCALE_USER_DEFAULT, 0, &d))) + hRet = VariantChangeType(&varRight, &varRight, VARIANT_LOCALBOOL, VT_BOOL); + if (SUCCEEDED(hRet) && V_VT(&varRight) != vt) + hRet = VariantChangeType(&varRight, &varRight, 0, vt); + if (FAILED(hRet)) + goto VarOr_Exit; + } + + V_VT(pVarOut) = vt; + if (vt == VT_I8) + { + V_I8(pVarOut) = V_I8(&varLeft) | V_I8(&varRight); + } + else if (vt == VT_I4) + { + V_I4(pVarOut) = V_I4(&varLeft) | V_I4(&varRight); + } + else + { + V_I2(pVarOut) = V_I2(&varLeft) | V_I2(&varRight); + } + +VarOr_Exit: + VariantClear(&varStr); + VariantClear(&varLeft); + VariantClear(&varRight); + return hRet; +} + +/********************************************************************** + * VarAbs [OLEAUT32.168] + * + * Convert a variant to its absolute value. + * + * PARAMS + * pVarIn [I] Source variant + * pVarOut [O] Destination for converted value + * + * RETURNS + * Success: S_OK. pVarOut contains the absolute value of pVarIn. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * - This function does not process by-reference variants. + * - The type of the value stored in pVarOut depends on the type of pVarIn, + * according to the following table: + *| Input Type Output Type + *| ---------- ----------- + *| VT_BOOL VT_I2 + *| VT_BSTR VT_R8 + *| (All others) Unchanged + */ +HRESULT WINAPI VarAbs(LPVARIANT pVarIn, LPVARIANT pVarOut) +{ + VARIANT varIn; + HRESULT hRet = S_OK; + + TRACE("(%p->(%s%s),%p)\n", pVarIn, debugstr_VT(pVarIn), + debugstr_VF(pVarIn), pVarOut); + + if (V_ISARRAY(pVarIn) || V_VT(pVarIn) == VT_UNKNOWN || + V_VT(pVarIn) == VT_DISPATCH || V_VT(pVarIn) == VT_RECORD || + V_VT(pVarIn) == VT_ERROR) + return DISP_E_TYPEMISMATCH; + + *pVarOut = *pVarIn; /* Shallow copy the value, and invert it if needed */ + +#define ABS_CASE(typ,min) \ + case VT_##typ: if (V_##typ(pVarIn) == min) hRet = DISP_E_OVERFLOW; \ + else if (V_##typ(pVarIn) < 0) V_##typ(pVarOut) = -V_##typ(pVarIn); \ + break + + switch (V_VT(pVarIn)) + { + ABS_CASE(I1,I1_MIN); + case VT_BOOL: + V_VT(pVarOut) = VT_I2; + /* BOOL->I2, Fall through ... */ + ABS_CASE(I2,I2_MIN); + case VT_INT: + ABS_CASE(I4,I4_MIN); + ABS_CASE(I8,I8_MIN); + ABS_CASE(R4,R4_MIN); + case VT_BSTR: + hRet = VarR8FromStr(V_BSTR(pVarIn), LOCALE_USER_DEFAULT, 0, &V_R8(&varIn)); + if (FAILED(hRet)) + break; + V_VT(pVarOut) = VT_R8; + pVarIn = &varIn; + /* Fall through ... */ + case VT_DATE: + ABS_CASE(R8,R8_MIN); + case VT_CY: + hRet = VarCyAbs(V_CY(pVarIn), & V_CY(pVarOut)); + break; + case VT_DECIMAL: + DEC_SIGN(&V_DECIMAL(pVarOut)) &= ~DECIMAL_NEG; + break; + case VT_UI1: + case VT_UI2: + case VT_UINT: + case VT_UI4: + case VT_UI8: + /* No-Op */ + break; + case VT_EMPTY: + V_VT(pVarOut) = VT_I2; + case VT_NULL: + V_I2(pVarOut) = 0; + break; + default: + hRet = DISP_E_BADVARTYPE; + } + + return hRet; +} + +/********************************************************************** + * VarFix [OLEAUT32.169] + * + * Truncate a variants value to a whole number. + * + * PARAMS + * pVarIn [I] Source variant + * pVarOut [O] Destination for converted value + * + * RETURNS + * Success: S_OK. pVarOut contains the converted value. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * - The type of the value stored in pVarOut depends on the type of pVarIn, + * according to the following table: + *| Input Type Output Type + *| ---------- ----------- + *| VT_BOOL VT_I2 + *| VT_EMPTY VT_I2 + *| VT_BSTR VT_R8 + *| All Others Unchanged + * - The difference between this function and VarInt() is that VarInt() rounds + * negative numbers away from 0, while this function rounds them towards zero. + */ +HRESULT WINAPI VarFix(LPVARIANT pVarIn, LPVARIANT pVarOut) +{ + HRESULT hRet = S_OK; + + TRACE("(%p->(%s%s),%p)\n", pVarIn, debugstr_VT(pVarIn), + debugstr_VF(pVarIn), pVarOut); + + V_VT(pVarOut) = V_VT(pVarIn); + + switch (V_VT(pVarIn)) + { + case VT_UI1: + V_UI1(pVarOut) = V_UI1(pVarIn); + break; + case VT_BOOL: + V_VT(pVarOut) = VT_I2; + /* Fall through */ + case VT_I2: + V_I2(pVarOut) = V_I2(pVarIn); + break; + case VT_I4: + V_I4(pVarOut) = V_I4(pVarIn); + break; + case VT_I8: + V_I8(pVarOut) = V_I8(pVarIn); + break; + case VT_R4: + if (V_R4(pVarIn) < 0.0f) + V_R4(pVarOut) = (float)ceil(V_R4(pVarIn)); + else + V_R4(pVarOut) = (float)floor(V_R4(pVarIn)); + break; + case VT_BSTR: + V_VT(pVarOut) = VT_R8; + hRet = VarR8FromStr(V_BSTR(pVarIn), LOCALE_USER_DEFAULT, 0, &V_R8(pVarOut)); + pVarIn = pVarOut; + /* Fall through */ + case VT_DATE: + case VT_R8: + if (V_R8(pVarIn) < 0.0) + V_R8(pVarOut) = ceil(V_R8(pVarIn)); + else + V_R8(pVarOut) = floor(V_R8(pVarIn)); + break; + case VT_CY: + hRet = VarCyFix(V_CY(pVarIn), &V_CY(pVarOut)); + break; + case VT_DECIMAL: + hRet = VarDecFix(&V_DECIMAL(pVarIn), &V_DECIMAL(pVarOut)); + break; + case VT_EMPTY: + V_VT(pVarOut) = VT_I2; + V_I2(pVarOut) = 0; + break; + case VT_NULL: + /* No-Op */ + break; + default: + if (V_TYPE(pVarIn) == VT_CLSID || /* VT_CLSID is a special case */ + FAILED(VARIANT_ValidateType(V_VT(pVarIn)))) + hRet = DISP_E_BADVARTYPE; + else + hRet = DISP_E_TYPEMISMATCH; + } + if (FAILED(hRet)) + V_VT(pVarOut) = VT_EMPTY; + + return hRet; +} + +/********************************************************************** + * VarInt [OLEAUT32.172] + * + * Truncate a variants value to a whole number. + * + * PARAMS + * pVarIn [I] Source variant + * pVarOut [O] Destination for converted value + * + * RETURNS + * Success: S_OK. pVarOut contains the converted value. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * - The type of the value stored in pVarOut depends on the type of pVarIn, + * according to the following table: + *| Input Type Output Type + *| ---------- ----------- + *| VT_BOOL VT_I2 + *| VT_EMPTY VT_I2 + *| VT_BSTR VT_R8 + *| All Others Unchanged + * - The difference between this function and VarFix() is that VarFix() rounds + * negative numbers towards 0, while this function rounds them away from zero. + */ +HRESULT WINAPI VarInt(LPVARIANT pVarIn, LPVARIANT pVarOut) +{ + HRESULT hRet = S_OK; + + TRACE("(%p->(%s%s),%p)\n", pVarIn, debugstr_VT(pVarIn), + debugstr_VF(pVarIn), pVarOut); + + V_VT(pVarOut) = V_VT(pVarIn); + + switch (V_VT(pVarIn)) + { + case VT_R4: + V_R4(pVarOut) = (float)floor(V_R4(pVarIn)); + break; + case VT_BSTR: + V_VT(pVarOut) = VT_R8; + hRet = VarR8FromStr(V_BSTR(pVarIn), LOCALE_USER_DEFAULT, 0, &V_R8(pVarOut)); + pVarIn = pVarOut; + /* Fall through */ + case VT_DATE: + case VT_R8: + V_R8(pVarOut) = floor(V_R8(pVarIn)); + break; + case VT_CY: + hRet = VarCyInt(V_CY(pVarIn), &V_CY(pVarOut)); + break; + case VT_DECIMAL: + hRet = VarDecInt(&V_DECIMAL(pVarIn), &V_DECIMAL(pVarOut)); + break; + default: + return VarFix(pVarIn, pVarOut); + } + + return hRet; +} + +/********************************************************************** + * VarXor [OLEAUT32.167] + * + * Perform a logical exclusive-or (XOR) operation on two variants. + * + * PARAMS + * pVarLeft [I] First variant + * pVarRight [I] Variant to XOR with pVarLeft + * pVarOut [O] Destination for XOR result + * + * RETURNS + * Success: S_OK. pVarOut contains the result of the operation with its type + * taken from the table below). + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * - Neither pVarLeft or pVarRight are modified by this function. + * - This function does not process by-reference variants. + * - Input types of VT_BSTR may be numeric strings or boolean text. + * - The type of result stored in pVarOut depends on the types of pVarLeft + * and pVarRight, and will be one of VT_UI1, VT_I2, VT_I4, VT_I8, VT_BOOL, + * or VT_NULL if the function succeeds. + * - Type promotion is inconsistent and as a result certain combinations of + * values will return DISP_E_OVERFLOW even when they could be represented. + * This matches the behaviour of native oleaut32. + */ +HRESULT WINAPI VarXor(LPVARIANT pVarLeft, LPVARIANT pVarRight, LPVARIANT pVarOut) +{ + VARTYPE vt; + VARIANT varLeft, varRight; + double d; + HRESULT hRet; + + TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", pVarLeft, debugstr_VT(pVarLeft), + debugstr_VF(pVarLeft), pVarRight, debugstr_VT(pVarRight), + debugstr_VF(pVarRight), pVarOut); + + if (V_EXTRA_TYPE(pVarLeft) || V_EXTRA_TYPE(pVarRight) || + V_VT(pVarLeft) > VT_UINT || V_VT(pVarRight) > VT_UINT || + V_VT(pVarLeft) == VT_VARIANT || V_VT(pVarRight) == VT_VARIANT || + V_VT(pVarLeft) == VT_UNKNOWN || V_VT(pVarRight) == VT_UNKNOWN || + V_VT(pVarLeft) == (VARTYPE)15 || V_VT(pVarRight) == (VARTYPE)15 || + V_VT(pVarLeft) == VT_ERROR || V_VT(pVarRight) == VT_ERROR) + return DISP_E_BADVARTYPE; + + if (V_VT(pVarLeft) == VT_NULL || V_VT(pVarRight) == VT_NULL) + { + /* NULL XOR anything valid is NULL */ + V_VT(pVarOut) = VT_NULL; + return S_OK; + } + + /* Copy our inputs so we don't disturb anything */ + V_VT(&varLeft) = V_VT(&varRight) = VT_EMPTY; + + hRet = VariantCopy(&varLeft, pVarLeft); + if (FAILED(hRet)) + goto VarXor_Exit; + + hRet = VariantCopy(&varRight, pVarRight); + if (FAILED(hRet)) + goto VarXor_Exit; + + /* Try any strings first as numbers, then as VT_BOOL */ + if (V_VT(&varLeft) == VT_BSTR) + { + hRet = VarR8FromStr(V_BSTR(&varLeft), LOCALE_USER_DEFAULT, 0, &d); + hRet = VariantChangeType(&varLeft, &varLeft, VARIANT_LOCALBOOL, + FAILED(hRet) ? VT_BOOL : VT_I4); + if (FAILED(hRet)) + goto VarXor_Exit; + } + + if (V_VT(&varRight) == VT_BSTR) + { + hRet = VarR8FromStr(V_BSTR(&varRight), LOCALE_USER_DEFAULT, 0, &d); + hRet = VariantChangeType(&varRight, &varRight, VARIANT_LOCALBOOL, + FAILED(hRet) ? VT_BOOL : VT_I4); + if (FAILED(hRet)) + goto VarXor_Exit; + } + + /* Determine the result type */ + if (V_VT(&varLeft) == VT_I8 || V_VT(&varRight) == VT_I8) + { + if (V_VT(pVarLeft) == VT_INT || V_VT(pVarRight) == VT_INT) + return DISP_E_TYPEMISMATCH; + vt = VT_I8; + } + else + { + switch ((V_VT(&varLeft) << 16) | V_VT(&varRight)) + { + case (VT_BOOL << 16) | VT_BOOL: + vt = VT_BOOL; + break; + case (VT_UI1 << 16) | VT_UI1: + vt = VT_UI1; + break; + case (VT_EMPTY << 16) | VT_EMPTY: + case (VT_EMPTY << 16) | VT_UI1: + case (VT_EMPTY << 16) | VT_I2: + case (VT_EMPTY << 16) | VT_BOOL: + case (VT_UI1 << 16) | VT_EMPTY: + case (VT_UI1 << 16) | VT_I2: + case (VT_UI1 << 16) | VT_BOOL: + case (VT_I2 << 16) | VT_EMPTY: + case (VT_I2 << 16) | VT_UI1: + case (VT_I2 << 16) | VT_I2: + case (VT_I2 << 16) | VT_BOOL: + case (VT_BOOL << 16) | VT_EMPTY: + case (VT_BOOL << 16) | VT_UI1: + case (VT_BOOL << 16) | VT_I2: + vt = VT_I2; + break; + default: + vt = VT_I4; + break; + } + } + + /* VT_UI4 does not overflow */ + if (vt != VT_I8) + { + if (V_VT(&varLeft) == VT_UI4) + V_VT(&varLeft) = VT_I4; + if (V_VT(&varRight) == VT_UI4) + V_VT(&varRight) = VT_I4; + } + + /* Convert our input copies to the result type */ + if (V_VT(&varLeft) != vt) + hRet = VariantChangeType(&varLeft, &varLeft, 0, vt); + if (FAILED(hRet)) + goto VarXor_Exit; + + if (V_VT(&varRight) != vt) + hRet = VariantChangeType(&varRight, &varRight, 0, vt); + if (FAILED(hRet)) + goto VarXor_Exit; + + V_VT(pVarOut) = vt; + + /* Calculate the result */ + switch (vt) + { + case VT_I8: + V_I8(pVarOut) = V_I8(&varLeft) ^ V_I8(&varRight); + break; + case VT_I4: + V_I4(pVarOut) = V_I4(&varLeft) ^ V_I4(&varRight); + break; + case VT_BOOL: + case VT_I2: + V_I2(pVarOut) = V_I2(&varLeft) ^ V_I2(&varRight); + break; + case VT_UI1: + V_UI1(pVarOut) = V_UI1(&varLeft) ^ V_UI1(&varRight); + break; + } + +VarXor_Exit: + VariantClear(&varLeft); + VariantClear(&varRight); + return hRet; +} + +/********************************************************************** + * VarEqv [OLEAUT32.172] + * + * Determine if two variants contain the same value. + * + * PARAMS + * pVarLeft [I] First variant to compare + * pVarRight [I] Variant to compare to pVarLeft + * pVarOut [O] Destination for comparison result + * + * RETURNS + * Success: S_OK. pVarOut contains the result of the comparison (VARIANT_TRUE + * if equivalent or non-zero otherwise. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * - This function simply calls VarXor() on pVarLeft and pVarRight and inverts + * the result. + */ +HRESULT WINAPI VarEqv(LPVARIANT pVarLeft, LPVARIANT pVarRight, LPVARIANT pVarOut) +{ + HRESULT hRet; + + TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", pVarLeft, debugstr_VT(pVarLeft), + debugstr_VF(pVarLeft), pVarRight, debugstr_VT(pVarRight), + debugstr_VF(pVarRight), pVarOut); + + hRet = VarXor(pVarLeft, pVarRight, pVarOut); + if (SUCCEEDED(hRet)) + { + if (V_VT(pVarOut) == VT_I8) + V_I8(pVarOut) = ~V_I8(pVarOut); + else + V_UI4(pVarOut) = ~V_UI4(pVarOut); + } + return hRet; +} + +/********************************************************************** + * VarNeg [OLEAUT32.173] + * + * Negate the value of a variant. + * + * PARAMS + * pVarIn [I] Source variant + * pVarOut [O] Destination for converted value + * + * RETURNS + * Success: S_OK. pVarOut contains the converted value. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * - The type of the value stored in pVarOut depends on the type of pVarIn, + * according to the following table: + *| Input Type Output Type + *| ---------- ----------- + *| VT_EMPTY VT_I2 + *| VT_UI1 VT_I2 + *| VT_BOOL VT_I2 + *| VT_BSTR VT_R8 + *| All Others Unchanged (unless promoted) + * - Where the negated value of a variant does not fit in its base type, the type + * is promoted according to the following table: + *| Input Type Promoted To + *| ---------- ----------- + *| VT_I2 VT_I4 + *| VT_I4 VT_R8 + *| VT_I8 VT_R8 + * - The native version of this function returns DISP_E_BADVARTYPE for valid + * variant types that cannot be negated, and returns DISP_E_TYPEMISMATCH + * for types which are not valid. Since this is in contravention of the + * meaning of those error codes and unlikely to be relied on by applications, + * this implementation returns errors consistent with the other high level + * variant math functions. + */ +HRESULT WINAPI VarNeg(LPVARIANT pVarIn, LPVARIANT pVarOut) +{ + HRESULT hRet = S_OK; + + TRACE("(%p->(%s%s),%p)\n", pVarIn, debugstr_VT(pVarIn), + debugstr_VF(pVarIn), pVarOut); + + V_VT(pVarOut) = V_VT(pVarIn); + + switch (V_VT(pVarIn)) + { + case VT_UI1: + V_VT(pVarOut) = VT_I2; + V_I2(pVarOut) = -V_UI1(pVarIn); + break; + case VT_BOOL: + V_VT(pVarOut) = VT_I2; + /* Fall through */ + case VT_I2: + if (V_I2(pVarIn) == I2_MIN) + { + V_VT(pVarOut) = VT_I4; + V_I4(pVarOut) = -(int)V_I2(pVarIn); + } + else + V_I2(pVarOut) = -V_I2(pVarIn); + break; + case VT_I4: + if (V_I4(pVarIn) == I4_MIN) + { + V_VT(pVarOut) = VT_R8; + V_R8(pVarOut) = -(double)V_I4(pVarIn); + } + else + V_I4(pVarOut) = -V_I4(pVarIn); + break; + case VT_I8: + if (V_I8(pVarIn) == I8_MIN) + { + V_VT(pVarOut) = VT_R8; + hRet = VarR8FromI8(V_I8(pVarIn), &V_R8(pVarOut)); + V_R8(pVarOut) *= -1.0; + } + else + V_I8(pVarOut) = -V_I8(pVarIn); + break; + case VT_R4: + V_R4(pVarOut) = -V_R4(pVarIn); + break; + case VT_DATE: + case VT_R8: + V_R8(pVarOut) = -V_R8(pVarIn); + break; + case VT_CY: + hRet = VarCyNeg(V_CY(pVarIn), &V_CY(pVarOut)); + break; + case VT_DECIMAL: + hRet = VarDecNeg(&V_DECIMAL(pVarIn), &V_DECIMAL(pVarOut)); + break; + case VT_BSTR: + V_VT(pVarOut) = VT_R8; + hRet = VarR8FromStr(V_BSTR(pVarIn), LOCALE_USER_DEFAULT, 0, &V_R8(pVarOut)); + V_R8(pVarOut) = -V_R8(pVarOut); + break; + case VT_EMPTY: + V_VT(pVarOut) = VT_I2; + V_I2(pVarOut) = 0; + break; + case VT_NULL: + /* No-Op */ + break; + default: + if (V_TYPE(pVarIn) == VT_CLSID || /* VT_CLSID is a special case */ + FAILED(VARIANT_ValidateType(V_VT(pVarIn)))) + hRet = DISP_E_BADVARTYPE; + else + hRet = DISP_E_TYPEMISMATCH; + } + if (FAILED(hRet)) + V_VT(pVarOut) = VT_EMPTY; + + return hRet; +} + +/********************************************************************** + * VarNot [OLEAUT32.174] + * + * Perform a not operation on a variant. + * + * PARAMS + * pVarIn [I] Source variant + * pVarOut [O] Destination for converted value + * + * RETURNS + * Success: S_OK. pVarOut contains the converted value. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * - Strictly speaking, this function performs a bitwise ones complement + * on the variants value (after possibly converting to VT_I4, see below). + * This only behaves like a boolean not operation if the value in + * pVarIn is either VARIANT_TRUE or VARIANT_FALSE and the type is signed. + * - To perform a genuine not operation, convert the variant to a VT_BOOL + * before calling this function. + * - This function does not process by-reference variants. + * - The type of the value stored in pVarOut depends on the type of pVarIn, + * according to the following table: + *| Input Type Output Type + *| ---------- ----------- + *| VT_EMPTY VT_I2 + *| VT_R4 VT_I4 + *| VT_R8 VT_I4 + *| VT_BSTR VT_I4 + *| VT_DECIMAL VT_I4 + *| VT_CY VT_I4 + *| (All others) Unchanged + */ +HRESULT WINAPI VarNot(LPVARIANT pVarIn, LPVARIANT pVarOut) +{ + VARIANT varIn; + HRESULT hRet = S_OK; + + TRACE("(%p->(%s%s),%p)\n", pVarIn, debugstr_VT(pVarIn), + debugstr_VF(pVarIn), pVarOut); + + V_VT(pVarOut) = V_VT(pVarIn); + + switch (V_VT(pVarIn)) + { + case VT_I1: + V_I4(pVarOut) = ~V_I1(pVarIn); + V_VT(pVarOut) = VT_I4; + break; + case VT_UI1: V_UI1(pVarOut) = ~V_UI1(pVarIn); break; + case VT_BOOL: + case VT_I2: V_I2(pVarOut) = ~V_I2(pVarIn); break; + case VT_UI2: + V_I4(pVarOut) = ~V_UI2(pVarIn); + V_VT(pVarOut) = VT_I4; + break; + case VT_DECIMAL: + hRet = VarI4FromDec(&V_DECIMAL(pVarIn), &V_I4(&varIn)); + if (FAILED(hRet)) + break; + pVarIn = &varIn; + /* Fall through ... */ + case VT_INT: + V_VT(pVarOut) = VT_I4; + /* Fall through ... */ + case VT_I4: V_I4(pVarOut) = ~V_I4(pVarIn); break; + case VT_UINT: + case VT_UI4: + V_I4(pVarOut) = ~V_UI4(pVarIn); + V_VT(pVarOut) = VT_I4; + break; + case VT_I8: V_I8(pVarOut) = ~V_I8(pVarIn); break; + case VT_UI8: + V_I4(pVarOut) = ~V_UI8(pVarIn); + V_VT(pVarOut) = VT_I4; + break; + case VT_R4: + hRet = VarI4FromR4(V_R4(pVarIn), &V_I4(pVarOut)); + V_I4(pVarOut) = ~V_I4(pVarOut); + V_VT(pVarOut) = VT_I4; + break; + case VT_BSTR: + hRet = VarR8FromStr(V_BSTR(pVarIn), LOCALE_USER_DEFAULT, 0, &V_R8(&varIn)); + if (FAILED(hRet)) + break; + pVarIn = &varIn; + /* Fall through ... */ + case VT_DATE: + case VT_R8: + hRet = VarI4FromR8(V_R8(pVarIn), &V_I4(pVarOut)); + V_I4(pVarOut) = ~V_I4(pVarOut); + V_VT(pVarOut) = VT_I4; + break; + case VT_CY: + hRet = VarI4FromCy(V_CY(pVarIn), &V_I4(pVarOut)); + V_I4(pVarOut) = ~V_I4(pVarOut); + V_VT(pVarOut) = VT_I4; + break; + case VT_EMPTY: + V_I2(pVarOut) = ~0; + V_VT(pVarOut) = VT_I2; + break; + case VT_NULL: + /* No-Op */ + break; + default: + if (V_TYPE(pVarIn) == VT_CLSID || /* VT_CLSID is a special case */ + FAILED(VARIANT_ValidateType(V_VT(pVarIn)))) + hRet = DISP_E_BADVARTYPE; + else + hRet = DISP_E_TYPEMISMATCH; + } + if (FAILED(hRet)) + V_VT(pVarOut) = VT_EMPTY; + + return hRet; +} + +/********************************************************************** + * VarRound [OLEAUT32.175] + * + * Perform a round operation on a variant. + * + * PARAMS + * pVarIn [I] Source variant + * deci [I] Number of decimals to round to + * pVarOut [O] Destination for converted value + * + * RETURNS + * Success: S_OK. pVarOut contains the converted value. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * - Floating point values are rounded to the desired number of decimals. + * - Some integer types are just copied to the return variable. + * - Some other integer types are not handled and fail. + */ +HRESULT WINAPI VarRound(LPVARIANT pVarIn, int deci, LPVARIANT pVarOut) +{ + VARIANT varIn; + HRESULT hRet = S_OK; + float factor; + + TRACE("(%p->(%s%s),%d)\n", pVarIn, debugstr_VT(pVarIn), debugstr_VF(pVarIn), deci); + + switch (V_VT(pVarIn)) + { + /* cases that fail on windows */ + case VT_I1: + case VT_I8: + case VT_UI2: + case VT_UI4: + hRet = DISP_E_BADVARTYPE; + break; + + /* cases just copying in to out */ + case VT_UI1: + V_VT(pVarOut) = V_VT(pVarIn); + V_UI1(pVarOut) = V_UI1(pVarIn); + break; + case VT_I2: + V_VT(pVarOut) = V_VT(pVarIn); + V_I2(pVarOut) = V_I2(pVarIn); + break; + case VT_I4: + V_VT(pVarOut) = V_VT(pVarIn); + V_I4(pVarOut) = V_I4(pVarIn); + break; + case VT_NULL: + V_VT(pVarOut) = V_VT(pVarIn); + /* value unchanged */ + break; + + /* cases that change type */ + case VT_EMPTY: + V_VT(pVarOut) = VT_I2; + V_I2(pVarOut) = 0; + break; + case VT_BOOL: + V_VT(pVarOut) = VT_I2; + V_I2(pVarOut) = V_BOOL(pVarIn); + break; + case VT_BSTR: + hRet = VarR8FromStr(V_BSTR(pVarIn), LOCALE_USER_DEFAULT, 0, &V_R8(&varIn)); + if (FAILED(hRet)) + break; + V_VT(&varIn)=VT_R8; + pVarIn = &varIn; + /* Fall through ... */ + + /* cases we need to do math */ + case VT_R8: + if (V_R8(pVarIn)>0) { + V_R8(pVarOut)=floor(V_R8(pVarIn)*pow(10, deci)+0.5)/pow(10, deci); + } else { + V_R8(pVarOut)=ceil(V_R8(pVarIn)*pow(10, deci)-0.5)/pow(10, deci); + } + V_VT(pVarOut) = V_VT(pVarIn); + break; + case VT_R4: + if (V_R4(pVarIn)>0) { + V_R4(pVarOut)=floor(V_R4(pVarIn)*pow(10, deci)+0.5)/pow(10, deci); + } else { + V_R4(pVarOut)=ceil(V_R4(pVarIn)*pow(10, deci)-0.5)/pow(10, deci); + } + V_VT(pVarOut) = V_VT(pVarIn); + break; + case VT_DATE: + if (V_DATE(pVarIn)>0) { + V_DATE(pVarOut)=floor(V_DATE(pVarIn)*pow(10, deci)+0.5)/pow(10, deci); + } else { + V_DATE(pVarOut)=ceil(V_DATE(pVarIn)*pow(10, deci)-0.5)/pow(10, deci); + } + V_VT(pVarOut) = V_VT(pVarIn); + break; + case VT_CY: + if (deci>3) + factor=1; + else + factor=pow(10, 4-deci); + + if (V_CY(pVarIn).int64>0) { + V_CY(pVarOut).int64=floor(V_CY(pVarIn).int64/factor)*factor; + } else { + V_CY(pVarOut).int64=ceil(V_CY(pVarIn).int64/factor)*factor; + } + V_VT(pVarOut) = V_VT(pVarIn); + break; + + /* cases we don't know yet */ + default: + FIXME("unimplemented part, V_VT(pVarIn) == 0x%X, deci == %d\n", + V_VT(pVarIn) & VT_TYPEMASK, deci); + hRet = DISP_E_BADVARTYPE; + } + + if (FAILED(hRet)) + V_VT(pVarOut) = VT_EMPTY; + + TRACE("returning 0x%08lx (%s%s),%f\n", hRet, debugstr_VT(pVarOut), + debugstr_VF(pVarOut), (V_VT(pVarOut) == VT_R4) ? V_R4(pVarOut) : + (V_VT(pVarOut) == VT_R8) ? V_R8(pVarOut) : 0); + + return hRet; +} + +/********************************************************************** + * VarIdiv [OLEAUT32.153] + * + * Converts input variants to integers and divides them. + * + * PARAMS + * left [I] Left hand variant + * right [I] Right hand variant + * result [O] Destination for quotient + * + * RETURNS + * Success: S_OK. result contains the quotient. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * If either expression is null, null is returned, as per MSDN + */ +HRESULT WINAPI VarIdiv(LPVARIANT left, LPVARIANT right, LPVARIANT result) +{ + VARIANT lv, rv; + HRESULT hr; + + VariantInit(&lv); + VariantInit(&rv); + + if ((V_VT(left) == VT_NULL) || (V_VT(right) == VT_NULL)) { + hr = VariantChangeType(result, result, 0, VT_NULL); + if (FAILED(hr)) { + /* This should never happen */ + FIXME("Failed to convert return value to VT_NULL.\n"); + return hr; + } + return S_OK; + } + + hr = VariantChangeType(&lv, left, 0, VT_I4); + if (FAILED(hr)) { + return hr; + } + hr = VariantChangeType(&rv, right, 0, VT_I4); + if (FAILED(hr)) { + return hr; + } + + hr = VarDiv(&lv, &rv, result); + return hr; +} + + +/********************************************************************** + * VarMod [OLEAUT32.155] + * + * Perform the modulus operation of the right hand variant on the left + * + * PARAMS + * left [I] Left hand variant + * right [I] Right hand variant + * result [O] Destination for converted value + * + * RETURNS + * Success: S_OK. result contains the remainder. + * Failure: An HRESULT error code indicating the error. + * + * NOTE: + * If an error occurs the type of result will be modified but the value will not be. + * Doesn't support arrays or any special flags yet. + */ +HRESULT WINAPI VarMod(LPVARIANT left, LPVARIANT right, LPVARIANT result) +{ + BOOL lOk = TRUE; + BOOL rOk = TRUE; + HRESULT rc = E_FAIL; + int resT = 0; + VARIANT lv,rv; + + VariantInit(&lv); + VariantInit(&rv); + + TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left), + debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), result); + + /* check for invalid inputs */ + lOk = TRUE; + switch (V_VT(left) & VT_TYPEMASK) { + case VT_BOOL : + case VT_I1 : + case VT_I2 : + case VT_I4 : + case VT_I8 : + case VT_INT : + case VT_UI1 : + case VT_UI2 : + case VT_UI4 : + case VT_UI8 : + case VT_UINT : + case VT_R4 : + case VT_R8 : + case VT_CY : + case VT_EMPTY: + case VT_DATE : + case VT_BSTR : + break; + case VT_VARIANT: + case VT_UNKNOWN: + V_VT(result) = VT_EMPTY; + return DISP_E_TYPEMISMATCH; + case VT_DECIMAL: + V_VT(result) = VT_EMPTY; + return DISP_E_OVERFLOW; + case VT_ERROR: + return DISP_E_TYPEMISMATCH; + case VT_RECORD: + V_VT(result) = VT_EMPTY; + return DISP_E_TYPEMISMATCH; + case VT_NULL: + break; + default: + V_VT(result) = VT_EMPTY; + return DISP_E_BADVARTYPE; + } + + + rOk = TRUE; + switch (V_VT(right) & VT_TYPEMASK) { + case VT_BOOL : + case VT_I1 : + case VT_I2 : + case VT_I4 : + case VT_I8 : + if((V_VT(left) == VT_INT) && (V_VT(right) == VT_I8)) + { + V_VT(result) = VT_EMPTY; + return DISP_E_TYPEMISMATCH; + } + case VT_INT : + if((V_VT(right) == VT_INT) && (V_VT(left) == VT_I8)) + { + V_VT(result) = VT_EMPTY; + return DISP_E_TYPEMISMATCH; + } + case VT_UI1 : + case VT_UI2 : + case VT_UI4 : + case VT_UI8 : + case VT_UINT : + case VT_R4 : + case VT_R8 : + case VT_CY : + if(V_VT(left) == VT_EMPTY) + { + V_VT(result) = VT_I4; + return S_OK; + } + case VT_EMPTY: + case VT_DATE : + case VT_BSTR: + if(V_VT(left) == VT_NULL) + { + V_VT(result) = VT_NULL; + return S_OK; + } + break; + + case VT_VOID: + V_VT(result) = VT_EMPTY; + return DISP_E_BADVARTYPE; + case VT_NULL: + if(V_VT(left) == VT_VOID) + { + V_VT(result) = VT_EMPTY; + return DISP_E_BADVARTYPE; + } else if((V_VT(left) == VT_NULL) || (V_VT(left) == VT_EMPTY) || (V_VT(left) == VT_ERROR) || + lOk) + { + V_VT(result) = VT_NULL; + return S_OK; + } else + { + V_VT(result) = VT_NULL; + return DISP_E_BADVARTYPE; + } + case VT_VARIANT: + case VT_UNKNOWN: + V_VT(result) = VT_EMPTY; + return DISP_E_TYPEMISMATCH; + case VT_DECIMAL: + if(V_VT(left) == VT_ERROR) + { + V_VT(result) = VT_EMPTY; + return DISP_E_TYPEMISMATCH; + } else + { + V_VT(result) = VT_EMPTY; + return DISP_E_OVERFLOW; + } + case VT_ERROR: + return DISP_E_TYPEMISMATCH; + case VT_RECORD: + if((V_VT(left) == 15) || ((V_VT(left) >= 24) && (V_VT(left) <= 35)) || !lOk) + { + V_VT(result) = VT_EMPTY; + return DISP_E_BADVARTYPE; + } else + { + V_VT(result) = VT_EMPTY; + return DISP_E_TYPEMISMATCH; + } + default: + V_VT(result) = VT_EMPTY; + return DISP_E_BADVARTYPE; + } + + /* determine the result type */ + if((V_VT(left) == VT_I8) || (V_VT(right) == VT_I8)) resT = VT_I8; + else if((V_VT(left) == VT_UI1) && (V_VT(right) == VT_BOOL)) resT = VT_I2; + else if((V_VT(left) == VT_UI1) && (V_VT(right) == VT_UI1)) resT = VT_UI1; + else if((V_VT(left) == VT_UI1) && (V_VT(right) == VT_I2)) resT = VT_I2; + else if((V_VT(left) == VT_I2) && (V_VT(right) == VT_BOOL)) resT = VT_I2; + else if((V_VT(left) == VT_I2) && (V_VT(right) == VT_UI1)) resT = VT_I2; + else if((V_VT(left) == VT_I2) && (V_VT(right) == VT_I2)) resT = VT_I2; + else if((V_VT(left) == VT_BOOL) && (V_VT(right) == VT_BOOL)) resT = VT_I2; + else if((V_VT(left) == VT_BOOL) && (V_VT(right) == VT_UI1)) resT = VT_I2; + else if((V_VT(left) == VT_BOOL) && (V_VT(right) == VT_I2)) resT = VT_I2; + else resT = VT_I4; /* most outputs are I4 */ + + /* convert to I8 for the modulo */ + rc = VariantChangeType(&lv, left, 0, VT_I8); + if(FAILED(rc)) + { + FIXME("Could not convert left type %d to %d? rc == 0x%lX\n", V_VT(left), VT_I8, rc); + return rc; + } + + rc = VariantChangeType(&rv, right, 0, VT_I8); + if(FAILED(rc)) + { + FIXME("Could not convert right type %d to %d? rc == 0x%lX\n", V_VT(right), VT_I8, rc); + return rc; + } + + /* if right is zero set VT_EMPTY and return divide by zero */ + if(V_I8(&rv) == 0) + { + V_VT(result) = VT_EMPTY; + return DISP_E_DIVBYZERO; + } + + /* perform the modulo operation */ + V_VT(result) = VT_I8; + V_I8(result) = V_I8(&lv) % V_I8(&rv); + + TRACE("V_I8(left) == %ld, V_I8(right) == %ld, V_I8(result) == %ld\n", (long)V_I8(&lv), (long)V_I8(&rv), (long)V_I8(result)); + + /* convert left and right to the destination type */ + rc = VariantChangeType(result, result, 0, resT); + if(FAILED(rc)) + { + FIXME("Could not convert 0x%x to %d?\n", V_VT(result), resT); + return rc; + } + + return S_OK; +} + +/********************************************************************** + * VarPow [OLEAUT32.158] + * + */ +HRESULT WINAPI VarPow(LPVARIANT left, LPVARIANT right, LPVARIANT result) +{ + HRESULT hr; + VARIANT dl,dr; + + TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left), debugstr_VF(left), + right, debugstr_VT(right), debugstr_VF(right), result); + + hr = VariantChangeType(&dl,left,0,VT_R8); + if (!SUCCEEDED(hr)) { + ERR("Could not change passed left argument to VT_R8, handle it differently.\n"); + return E_FAIL; + } + hr = VariantChangeType(&dr,right,0,VT_R8); + if (!SUCCEEDED(hr)) { + ERR("Could not change passed right argument to VT_R8, handle it differently.\n"); + return E_FAIL; + } + V_VT(result) = VT_R8; + V_R8(result) = pow(V_R8(&dl),V_R8(&dr)); + return S_OK; +} diff --git a/reactos/lib/oleaut32/variant.h b/reactos/lib/oleaut32/variant.h index a0a4fbe1d2e..7bf6a510ecf 100644 --- a/reactos/lib/oleaut32/variant.h +++ b/reactos/lib/oleaut32/variant.h @@ -1,435 +1,435 @@ -/* - * Variant Inlines - * - * Copyright 2003 Jon Griffiths - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#define NONAMELESSUNION -#define NONAMELESSSTRUCT -#include "windef.h" -#include "winerror.h" -#include "objbase.h" -#include "oleauto.h" -#include <math.h> - -/* Get just the type from a variant pointer */ -#define V_TYPE(v) (V_VT((v)) & VT_TYPEMASK) - -/* Flags set in V_VT, other than the actual type value */ -#define VT_EXTRA_TYPE (VT_VECTOR|VT_ARRAY|VT_BYREF|VT_RESERVED) - -/* Get the extra flags from a variant pointer */ -#define V_EXTRA_TYPE(v) (V_VT((v)) & VT_EXTRA_TYPE) - -extern const char* wine_vtypes[]; -#define debugstr_vt(v) (((v)&VT_TYPEMASK) <= VT_CLSID ? wine_vtypes[((v)&VT_TYPEMASK)] : \ - ((v)&VT_TYPEMASK) == VT_BSTR_BLOB ? "VT_BSTR_BLOB": "Invalid") -#define debugstr_VT(v) (!(v) ? "(null)" : debugstr_vt(V_TYPE((v)))) - -extern const char* wine_vflags[]; -#define debugstr_vf(v) (wine_vflags[((v)&VT_EXTRA_TYPE)>>12]) -#define debugstr_VF(v) (!(v) ? "(null)" : debugstr_vf(V_EXTRA_TYPE(v))) - -/* Size constraints */ -#define I1_MAX 0x7f -#define I1_MIN ((-I1_MAX)-1) -#define UI1_MAX 0xff -#define UI1_MIN 0 -#define I2_MAX 0x7fff -#define I2_MIN ((-I2_MAX)-1) -#define UI2_MAX 0xffff -#define UI2_MIN 0 -#define I4_MAX 0x7fffffff -#define I4_MIN ((-I4_MAX)-1) -#define UI4_MAX 0xffffffff -#define UI4_MIN 0 -#define I8_MAX (((LONGLONG)I4_MAX << 32) | UI4_MAX) -#define I8_MIN ((-I8_MAX)-1) -#define UI8_MAX (((ULONGLONG)UI4_MAX << 32) | UI4_MAX) -#define UI8_MIN 0 -#define DATE_MAX 2958465 -#define DATE_MIN -657434 -#define R4_MAX 3.402823567797336e38 -#define R4_MIN 1.40129846432481707e-45 -#define R8_MAX 1.79769313486231470e+308 -#define R8_MIN 4.94065645841246544e-324 - -/* Value of sign for a positive decimal number */ -#define DECIMAL_POS 0 - -/* Native headers don't change the union ordering for DECIMAL sign/scale (duh). - * This means that the signscale member is only useful for setting both members to 0. - * SIGNSCALE creates endian-correct values so that we can properly set both at once - * to values other than 0. - */ -#ifdef WORDS_BIGENDIAN -#define SIGNSCALE(sign,scale) (((scale) << 8) | sign) -#else -#define SIGNSCALE(sign,scale) (((sign) << 8) | scale) -#endif - -/* Macros for getting at a DECIMAL's parts */ -#define DEC_SIGN(d) ((d)->sign) -#define DEC_SCALE(d) ((d)->scale) -#define DEC_SIGNSCALE(d) ((d)->signscale) -#define DEC_HI32(d) ((d)->Hi32) -#define DEC_MID32(d) ((d)->Mid32) -#define DEC_LO32(d) ((d)->Lo32) -#define DEC_LO64(d) ((d)->Lo64) - -#define DEC_MAX_SCALE 28 /* Maximum scale for a decimal */ - -/* Inline return type */ -#define RETTYP inline static HRESULT - -/* Simple compiler cast from one type to another */ -#define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \ - *out = in; return S_OK; } - -/* Compiler cast where input cannot be negative */ -#define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \ - if (in < (src)0) return DISP_E_OVERFLOW; *out = in; return S_OK; } - -/* Compiler cast where input cannot be > some number */ -#define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \ - if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; } - -/* Compiler cast where input cannot be < some number or >= some other number */ -#define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \ - if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; } - -/* Conversions from IDispatch use the same code */ -HRESULT VARIANT_FromDisp(IDispatch*,LCID,void*,VARTYPE); -/* As do conversions from BSTR to numeric types */ -HRESULT VARIANT_NumberFromBstr(OLECHAR*,LCID,ULONG,void*,VARTYPE); - -#define CY_MULTIPLIER 10000 /* 4 dp of precision */ -#define CY_MULTIPLIER_F 10000.0 -#define CY_HALF (CY_MULTIPLIER/2) /* 0.5 */ -#define CY_HALF_F (CY_MULTIPLIER_F/2.0) - -/* I1 */ -POSTST(signed char, BYTE, VarI1FromUI1, I1_MAX); -BOTHTST(signed char, SHORT, VarI1FromI2, I1_MIN, I1_MAX); -BOTHTST(signed char, LONG, VarI1FromI4, I1_MIN, I1_MAX); -#define _VarI1FromR4(flt,out) VarI1FromR8((double)flt,out) -#define _VarI1FromR8 VarI1FromR8 -#define _VarI1FromCy VarI1FromCy -#define _VarI1FromDate(dt,out) VarI1FromR8((double)dt,out) -#define _VarI1FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_I1) -#define _VarI1FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, (BYTE*)out, VT_I1) -SIMPLE(signed char, VARIANT_BOOL, VarI1FromBool); -POSTST(signed char, USHORT, VarI1FromUI2, I1_MAX); -POSTST(signed char, ULONG, VarI1FromUI4, I1_MAX); -#define _VarI1FromDec VarI1FromDec -BOTHTST(signed char, LONG64, VarI1FromI8, I1_MIN, I1_MAX); -POSTST(signed char, ULONG64, VarI1FromUI8, I1_MAX); - -/* UI1 */ -BOTHTST(BYTE, SHORT, VarUI1FromI2, UI1_MIN, UI1_MAX); -#define _VarUI1FromR4(flt,out) VarUI1FromR8((double)flt,out) -#define _VarUI1FromR8 VarUI1FromR8 -#define _VarUI1FromCy VarUI1FromCy -#define _VarUI1FromDate(dt,out) VarUI1FromR8((double)dt,out) -#define _VarUI1FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_UI1) -#define _VarUI1FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_UI1) -SIMPLE(BYTE, VARIANT_BOOL, VarUI1FromBool); -NEGTST(BYTE, signed char, VarUI1FromI1); -POSTST(BYTE, USHORT, VarUI1FromUI2, UI1_MAX); -BOTHTST(BYTE, LONG, VarUI1FromI4, UI1_MIN, UI1_MAX); -POSTST(BYTE, ULONG, VarUI1FromUI4, UI1_MAX); -#define _VarUI1FromDec VarUI1FromDec -BOTHTST(BYTE, LONG64, VarUI1FromI8, UI1_MIN, UI1_MAX); -POSTST(BYTE, ULONG64, VarUI1FromUI8, UI1_MAX); - -/* I2 */ -SIMPLE(SHORT, BYTE, VarI2FromUI1); -BOTHTST(SHORT, LONG, VarI2FromI4, I2_MIN, I2_MAX); -#define _VarI2FromR4(flt,out) VarI2FromR8((double)flt,out) -#define _VarI2FromR8 VarI2FromR8 -#define _VarI2FromCy VarI2FromCy -#define _VarI2FromDate(dt,out) VarI2FromR8((double)dt,out) -#define _VarI2FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_I2) -#define _VarI2FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, (BYTE*)out, VT_I2) -SIMPLE(SHORT, VARIANT_BOOL, VarI2FromBool); -SIMPLE(SHORT, signed char, VarI2FromI1); -POSTST(SHORT, USHORT, VarI2FromUI2, I2_MAX); -POSTST(SHORT, ULONG, VarI2FromUI4, I2_MAX); -#define _VarI2FromDec VarI2FromDec -BOTHTST(SHORT, LONG64, VarI2FromI8, I2_MIN, I2_MAX); -POSTST(SHORT, ULONG64, VarI2FromUI8, I2_MAX); - -/* UI2 */ -SIMPLE(USHORT, BYTE, VarUI2FromUI1); -NEGTST(USHORT, SHORT, VarUI2FromI2); -BOTHTST(USHORT, LONG, VarUI2FromI4, UI2_MIN, UI2_MAX); -#define _VarUI2FromR4(flt,out) VarUI2FromR8((double)flt,out) -#define _VarUI2FromR8 VarUI2FromR8 -#define _VarUI2FromCy VarUI2FromCy -#define _VarUI2FromDate(dt,out) VarUI2FromR8((double)dt,out) -#define _VarUI2FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_UI2) -#define _VarUI2FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_UI2) -SIMPLE(USHORT, VARIANT_BOOL, VarUI2FromBool); -NEGTST(USHORT, signed char, VarUI2FromI1); -POSTST(USHORT, ULONG, VarUI2FromUI4, UI2_MAX); -#define _VarUI2FromDec VarUI2FromDec -BOTHTST(USHORT, LONG64, VarUI2FromI8, UI2_MIN, UI2_MAX); -POSTST(USHORT, ULONG64, VarUI2FromUI8, UI2_MAX); - -/* I4 */ -SIMPLE(LONG, BYTE, VarI4FromUI1); -SIMPLE(LONG, SHORT, VarI4FromI2); -#define _VarI4FromR4(flt,out) VarI4FromR8((double)flt,out) -#define _VarI4FromR8 VarI4FromR8 -#define _VarI4FromCy VarI4FromCy -#define _VarI4FromDate(dt,out) VarI4FromR8((double)dt,out) -#define _VarI4FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_I4) -#define _VarI4FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, (BYTE*)out, VT_I4) -SIMPLE(LONG, VARIANT_BOOL, VarI4FromBool); -SIMPLE(LONG, signed char, VarI4FromI1); -SIMPLE(LONG, USHORT, VarI4FromUI2); -POSTST(LONG, ULONG, VarI4FromUI4, I4_MAX); -#define _VarI4FromDec VarI4FromDec -BOTHTST(LONG, LONG64, VarI4FromI8, I4_MIN, I4_MAX); -POSTST(LONG, ULONG64, VarI4FromUI8, I4_MAX); - -/* UI4 */ -SIMPLE(ULONG, BYTE, VarUI4FromUI1); -NEGTST(ULONG, SHORT, VarUI4FromI2); -NEGTST(ULONG, LONG, VarUI4FromI4); -#define _VarUI4FromR4(flt,out) VarUI4FromR8((double)flt,out) -#define _VarUI4FromR8 VarUI4FromR8 -#define _VarUI4FromCy VarUI4FromCy -#define _VarUI4FromDate(dt,out) VarUI4FromR8((double)dt,out) -#define _VarUI4FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_UI4) -#define _VarUI4FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_UI4) -SIMPLE(ULONG, VARIANT_BOOL, VarUI4FromBool); -NEGTST(ULONG, signed char, VarUI4FromI1); -SIMPLE(ULONG, USHORT, VarUI4FromUI2); -#define _VarUI4FromDec VarUI4FromDec -BOTHTST(ULONG, LONG64, VarUI4FromI8, UI4_MIN, UI4_MAX); -POSTST(ULONG, ULONG64, VarUI4FromUI8, UI4_MAX); - -/* I8 */ -SIMPLE(LONG64, BYTE, VarI8FromUI1); -SIMPLE(LONG64, SHORT, VarI8FromI2); -#define _VarI8FromR4 VarI8FromR8 -#define _VarI8FromR8 VarI8FromR8 -#define _VarI8FromCy VarI8FromCy -#define _VarI8FromDate(dt,out) VarI8FromR8((double)dt,out) -#define _VarI8FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_I8) -#define _VarI8FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_I8) -#define _VarI8FromBool _VarI8FromI2 -SIMPLE(LONG64, signed char, VarI8FromI1); -SIMPLE(LONG64, USHORT, VarI8FromUI2); -SIMPLE(LONG64, LONG, VarI8FromI4); -SIMPLE(LONG64, ULONG, VarI8FromUI4); -#define _VarI8FromDec VarI8FromDec -POSTST(LONG64, ULONG64, VarI8FromUI8, I8_MAX); - -/* UI8 */ -SIMPLE(ULONG64, BYTE, VarUI8FromUI1); -NEGTST(ULONG64, SHORT, VarUI8FromI2); -#define _VarUI8FromR4 VarUI8FromR8 -#define _VarUI8FromR8 VarUI8FromR8 -#define _VarUI8FromCy VarUI8FromCy -#define _VarUI8FromDate(dt,out) VarUI8FromR8((double)dt,out) -#define _VarUI8FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_UI8) -#define _VarUI8FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_UI8) -#define _VarUI8FromBool _VarI8FromI2 -NEGTST(ULONG64, signed char, VarUI8FromI1); -SIMPLE(ULONG64, USHORT, VarUI8FromUI2); -NEGTST(ULONG64, LONG, VarUI8FromI4); -SIMPLE(ULONG64, ULONG, VarUI8FromUI4); -#define _VarUI8FromDec VarUI8FromDec -NEGTST(ULONG64, LONG64, VarUI8FromI8); - -/* R4 (float) */ -SIMPLE(float, BYTE, VarR4FromUI1); -SIMPLE(float, SHORT, VarR4FromI2); -RETTYP _VarR4FromR8(double i, float* o) { - double d = i < 0.0 ? -i : i; - if (d > R4_MAX) return DISP_E_OVERFLOW; - *o = i; - return S_OK; -} -RETTYP _VarR4FromCy(CY i, float* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; } -#define _VarR4FromDate(dt,out) _VarR4FromR8((double)dt,out) -#define _VarR4FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_R4) -#define _VarR4FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_R4) -#define _VarR4FromBool _VarR4FromI2 -SIMPLE(float, signed char, VarR4FromI1); -SIMPLE(float, USHORT, VarR4FromUI2); -SIMPLE(float, LONG, VarR4FromI4); -SIMPLE(float, ULONG, VarR4FromUI4); -#define _VarR4FromDec VarR4FromDec -SIMPLE(float, LONG64, VarR4FromI8); -SIMPLE(float, ULONG64, VarR4FromUI8); - -/* R8 (double) */ -SIMPLE(double, BYTE, VarR8FromUI1); -SIMPLE(double, SHORT, VarR8FromI2); -SIMPLE(double, float, VarR8FromR4); -RETTYP _VarR8FromCy(CY i, double* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; } -SIMPLE(double, DATE, VarR8FromDate); -#define _VarR8FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_R8) -#define _VarR8FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_R8) -#define _VarR8FromBool _VarR8FromI2 -SIMPLE(double, signed char, VarR8FromI1); -SIMPLE(double, USHORT, VarR8FromUI2); -SIMPLE(double, LONG, VarR8FromI4); -SIMPLE(double, ULONG, VarR8FromUI4); -#define _VarR8FromDec VarR8FromDec -SIMPLE(double, LONG64, VarR8FromI8); -SIMPLE(double, ULONG64, VarR8FromUI8); - -/* BOOL */ -#define BOOLFUNC(src, func) RETTYP _##func(src in, VARIANT_BOOL* out) { \ - *out = in ? VARIANT_TRUE : VARIANT_FALSE; return S_OK; } - -BOOLFUNC(signed char,VarBoolFromI1); -BOOLFUNC(BYTE,VarBoolFromUI1); -BOOLFUNC(SHORT,VarBoolFromI2); -BOOLFUNC(USHORT,VarBoolFromUI2); -BOOLFUNC(LONG,VarBoolFromI4); -BOOLFUNC(ULONG,VarBoolFromUI4); -BOOLFUNC(LONG64,VarBoolFromI8); -BOOLFUNC(ULONG64,VarBoolFromUI8); -#define _VarBoolFromR4(flt,out) _VarBoolFromR8((double)flt,out) -BOOLFUNC(double,VarBoolFromR8); -#define _VarBoolFromCy(i,o) _VarBoolFromI8(i.int64,o) -#define _VarBoolFromDate(dt,out) _VarBoolFromR8((double)dt,out) -#define _VarBoolFromStr VarBoolFromStr -#define _VarBoolFromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, (BYTE*)out, VT_BOOL) -#define _VarBoolFromDec VarBoolFromDec - -/* Internal flags for low level conversion functions */ -#define VAR_BOOLONOFF 0x0400 /* Convert bool to "On"/"Off" */ -#define VAR_BOOLYESNO 0x0800 /* Convert bool to "Yes"/"No" */ -#define VAR_NEGATIVE 0x1000 /* Number is negative */ - -/* DECIMAL */ -#define _VarDecFromUI1 VarDecFromUI4 -#define _VarDecFromI2 VarDecFromI4 -#define _VarDecFromR4 VarDecFromR4 -#define _VarDecFromR8 VarDecFromR8 -#define _VarDecFromCy VarDecFromCy -#define _VarDecFromDate(dt,out) VarDecFromR8((double)dt,out) -#define _VarDecFromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_DECIMAL) -#define _VarDecFromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_DECIMAL) -#define _VarDecFromBool VarDecFromBool -#define _VarDecFromI1 VarDecFromI4 -#define _VarDecFromUI2 VarDecFromUI4 -#define _VarDecFromI4 VarDecFromI4 -#define _VarDecFromUI4 VarDecFromUI4 -#define _VarDecFromI8 VarDecFromI8 -#define _VarDecFromUI8 VarDecFromUI8 - -/* CY (Currency) */ -#define _VarCyFromUI1 VarCyFromR8 -#define _VarCyFromI2 VarCyFromR8 -#define _VarCyFromR4 VarCyFromR8 -#define _VarCyFromR8 VarCyFromR8 -#define _VarCyFromDate VarCyFromR8 -#define _VarCyFromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_CY) -#define _VarCyFromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_CY) -#define _VarCyFromBool VarCyFromR8 -#define _VarCyFromI1 VarCyFromR8 -#define _VarCyFromUI2 VarCyFromR8 -#define _VarCyFromI4 VarCyFromR8 -#define _VarCyFromUI4 VarCyFromR8 -#define _VarCyFromDec VarCyFromDec -RETTYP _VarCyFromI8(LONG64 i, CY* o) { - if (i <= (I8_MIN/CY_MULTIPLIER) || i >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW; - o->int64 = i * CY_MULTIPLIER; - return S_OK; -} -#define _VarCyFromUI8 VarCyFromR8 - -/* DATE */ -#define _VarDateFromUI1 _VarR8FromUI1 -#define _VarDateFromI2 _VarR8FromI2 -#define _VarDateFromR4 _VarDateFromR8 -RETTYP _VarDateFromR8(double i, DATE* o) { - if (i <= (DATE_MIN - 1.0) || i >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW; - *o = (DATE)i; - return S_OK; -} -#define _VarDateFromCy _VarR8FromCy -#define _VarDateFromStr VarDateFromStr -#define _VarDateFromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_DATE) -#define _VarDateFromBool _VarR8FromBool -#define _VarDateFromI1 _VarR8FromI1 -#define _VarDateFromUI2 _VarR8FromUI2 -#define _VarDateFromI4 _VarDateFromR8 -#define _VarDateFromUI4 _VarDateFromR8 -#define _VarDateFromDec _VarR8FromDec -RETTYP _VarDateFromI8(LONG64 i, DATE* o) { - if (i < DATE_MIN || i > DATE_MAX) return DISP_E_OVERFLOW; - *o = (DATE)i; - return S_OK; -} -RETTYP _VarDateFromUI8(ULONG64 i, DATE* o) { - if (i > DATE_MAX) return DISP_E_OVERFLOW; - *o = (DATE)i; - return S_OK; -} - -/* BSTR */ -#define _VarBstrFromUI1 VarBstrFromUI4 -#define _VarBstrFromI2 VarBstrFromI4 -#define _VarBstrFromR4 VarBstrFromR8 -#define _VarBstrFromR8 VarBstrFromR8 -#define _VarBstrFromCy VarBstrFromCy -#define _VarBstrFromDate VarBstrFromDate -#define _VarBstrFromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_BSTR) -#define _VarBstrFromBool VarBstrFromBool -#define _VarBstrFromI1 VarBstrFromI4 -#define _VarBstrFromUI2 VarBstrFromUI4 -#define _VarBstrFromI4 VarBstrFromI4 -#define _VarBstrFromUI4 VarBstrFromUI4 -#define _VarBstrFromDec VarBstrFromDec -#define _VarBstrFromI8 VarBstrFromI8 -#define _VarBstrFromUI8 VarBstrFromUI8 - -/* Macro to inline conversion from a float or double to any integer type, - * rounding according to the 'dutch' convention. - */ -#define OLEAUT32_DutchRound(typ, value, res) do { \ - double whole = (double)value < 0 ? ceil((double)value) : floor((double)value); \ - double fract = (double)value - whole; \ - if (fract > 0.5) res = (typ)whole + (typ)1; \ - else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \ - else if (fract >= 0.0) res = (typ)whole; \ - else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \ - else if (fract > -0.5) res = (typ)whole; \ - else res = (typ)whole - (typ)1; \ -} while(0); - -/* The localised characters that make up a valid number */ -typedef struct tagVARIANT_NUMBER_CHARS -{ - WCHAR cNegativeSymbol; - WCHAR cPositiveSymbol; - WCHAR cDecimalPoint; - WCHAR cDigitSeperator; - WCHAR cCurrencyLocal; - WCHAR cCurrencyLocal2; - WCHAR cCurrencyDecimalPoint; - WCHAR cCurrencyDigitSeperator; -} VARIANT_NUMBER_CHARS; - -void VARIANT_GetLocalisedNumberChars(VARIANT_NUMBER_CHARS*,LCID,DWORD); +/* + * Variant Inlines + * + * Copyright 2003 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winerror.h" +#include "objbase.h" +#include "oleauto.h" +#include <math.h> + +/* Get just the type from a variant pointer */ +#define V_TYPE(v) (V_VT((v)) & VT_TYPEMASK) + +/* Flags set in V_VT, other than the actual type value */ +#define VT_EXTRA_TYPE (VT_VECTOR|VT_ARRAY|VT_BYREF|VT_RESERVED) + +/* Get the extra flags from a variant pointer */ +#define V_EXTRA_TYPE(v) (V_VT((v)) & VT_EXTRA_TYPE) + +extern const char* wine_vtypes[]; +#define debugstr_vt(v) (((v)&VT_TYPEMASK) <= VT_CLSID ? wine_vtypes[((v)&VT_TYPEMASK)] : \ + ((v)&VT_TYPEMASK) == VT_BSTR_BLOB ? "VT_BSTR_BLOB": "Invalid") +#define debugstr_VT(v) (!(v) ? "(null)" : debugstr_vt(V_TYPE((v)))) + +extern const char* wine_vflags[]; +#define debugstr_vf(v) (wine_vflags[((v)&VT_EXTRA_TYPE)>>12]) +#define debugstr_VF(v) (!(v) ? "(null)" : debugstr_vf(V_EXTRA_TYPE(v))) + +/* Size constraints */ +#define I1_MAX 0x7f +#define I1_MIN ((-I1_MAX)-1) +#define UI1_MAX 0xff +#define UI1_MIN 0 +#define I2_MAX 0x7fff +#define I2_MIN ((-I2_MAX)-1) +#define UI2_MAX 0xffff +#define UI2_MIN 0 +#define I4_MAX 0x7fffffff +#define I4_MIN ((-I4_MAX)-1) +#define UI4_MAX 0xffffffff +#define UI4_MIN 0 +#define I8_MAX (((LONGLONG)I4_MAX << 32) | UI4_MAX) +#define I8_MIN ((-I8_MAX)-1) +#define UI8_MAX (((ULONGLONG)UI4_MAX << 32) | UI4_MAX) +#define UI8_MIN 0 +#define DATE_MAX 2958465 +#define DATE_MIN -657434 +#define R4_MAX 3.402823567797336e38 +#define R4_MIN 1.40129846432481707e-45 +#define R8_MAX 1.79769313486231470e+308 +#define R8_MIN 4.94065645841246544e-324 + +/* Value of sign for a positive decimal number */ +#define DECIMAL_POS 0 + +/* Native headers don't change the union ordering for DECIMAL sign/scale (duh). + * This means that the signscale member is only useful for setting both members to 0. + * SIGNSCALE creates endian-correct values so that we can properly set both at once + * to values other than 0. + */ +#ifdef WORDS_BIGENDIAN +#define SIGNSCALE(sign,scale) (((scale) << 8) | sign) +#else +#define SIGNSCALE(sign,scale) (((sign) << 8) | scale) +#endif + +/* Macros for getting at a DECIMAL's parts */ +#define DEC_SIGN(d) ((d)->sign) +#define DEC_SCALE(d) ((d)->scale) +#define DEC_SIGNSCALE(d) ((d)->signscale) +#define DEC_HI32(d) ((d)->Hi32) +#define DEC_MID32(d) ((d)->Mid32) +#define DEC_LO32(d) ((d)->Lo32) +#define DEC_LO64(d) ((d)->Lo64) + +#define DEC_MAX_SCALE 28 /* Maximum scale for a decimal */ + +/* Inline return type */ +#define RETTYP inline static HRESULT + +/* Simple compiler cast from one type to another */ +#define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \ + *out = in; return S_OK; } + +/* Compiler cast where input cannot be negative */ +#define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \ + if (in < (src)0) return DISP_E_OVERFLOW; *out = in; return S_OK; } + +/* Compiler cast where input cannot be > some number */ +#define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \ + if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; } + +/* Compiler cast where input cannot be < some number or >= some other number */ +#define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \ + if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; } + +/* Conversions from IDispatch use the same code */ +HRESULT VARIANT_FromDisp(IDispatch*,LCID,void*,VARTYPE); +/* As do conversions from BSTR to numeric types */ +HRESULT VARIANT_NumberFromBstr(OLECHAR*,LCID,ULONG,void*,VARTYPE); + +#define CY_MULTIPLIER 10000 /* 4 dp of precision */ +#define CY_MULTIPLIER_F 10000.0 +#define CY_HALF (CY_MULTIPLIER/2) /* 0.5 */ +#define CY_HALF_F (CY_MULTIPLIER_F/2.0) + +/* I1 */ +POSTST(signed char, BYTE, VarI1FromUI1, I1_MAX); +BOTHTST(signed char, SHORT, VarI1FromI2, I1_MIN, I1_MAX); +BOTHTST(signed char, LONG, VarI1FromI4, I1_MIN, I1_MAX); +#define _VarI1FromR4(flt,out) VarI1FromR8((double)flt,out) +#define _VarI1FromR8 VarI1FromR8 +#define _VarI1FromCy VarI1FromCy +#define _VarI1FromDate(dt,out) VarI1FromR8((double)dt,out) +#define _VarI1FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_I1) +#define _VarI1FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, (BYTE*)out, VT_I1) +SIMPLE(signed char, VARIANT_BOOL, VarI1FromBool); +POSTST(signed char, USHORT, VarI1FromUI2, I1_MAX); +POSTST(signed char, ULONG, VarI1FromUI4, I1_MAX); +#define _VarI1FromDec VarI1FromDec +BOTHTST(signed char, LONG64, VarI1FromI8, I1_MIN, I1_MAX); +POSTST(signed char, ULONG64, VarI1FromUI8, I1_MAX); + +/* UI1 */ +BOTHTST(BYTE, SHORT, VarUI1FromI2, UI1_MIN, UI1_MAX); +#define _VarUI1FromR4(flt,out) VarUI1FromR8((double)flt,out) +#define _VarUI1FromR8 VarUI1FromR8 +#define _VarUI1FromCy VarUI1FromCy +#define _VarUI1FromDate(dt,out) VarUI1FromR8((double)dt,out) +#define _VarUI1FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_UI1) +#define _VarUI1FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_UI1) +SIMPLE(BYTE, VARIANT_BOOL, VarUI1FromBool); +NEGTST(BYTE, signed char, VarUI1FromI1); +POSTST(BYTE, USHORT, VarUI1FromUI2, UI1_MAX); +BOTHTST(BYTE, LONG, VarUI1FromI4, UI1_MIN, UI1_MAX); +POSTST(BYTE, ULONG, VarUI1FromUI4, UI1_MAX); +#define _VarUI1FromDec VarUI1FromDec +BOTHTST(BYTE, LONG64, VarUI1FromI8, UI1_MIN, UI1_MAX); +POSTST(BYTE, ULONG64, VarUI1FromUI8, UI1_MAX); + +/* I2 */ +SIMPLE(SHORT, BYTE, VarI2FromUI1); +BOTHTST(SHORT, LONG, VarI2FromI4, I2_MIN, I2_MAX); +#define _VarI2FromR4(flt,out) VarI2FromR8((double)flt,out) +#define _VarI2FromR8 VarI2FromR8 +#define _VarI2FromCy VarI2FromCy +#define _VarI2FromDate(dt,out) VarI2FromR8((double)dt,out) +#define _VarI2FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_I2) +#define _VarI2FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, (BYTE*)out, VT_I2) +SIMPLE(SHORT, VARIANT_BOOL, VarI2FromBool); +SIMPLE(SHORT, signed char, VarI2FromI1); +POSTST(SHORT, USHORT, VarI2FromUI2, I2_MAX); +POSTST(SHORT, ULONG, VarI2FromUI4, I2_MAX); +#define _VarI2FromDec VarI2FromDec +BOTHTST(SHORT, LONG64, VarI2FromI8, I2_MIN, I2_MAX); +POSTST(SHORT, ULONG64, VarI2FromUI8, I2_MAX); + +/* UI2 */ +SIMPLE(USHORT, BYTE, VarUI2FromUI1); +NEGTST(USHORT, SHORT, VarUI2FromI2); +BOTHTST(USHORT, LONG, VarUI2FromI4, UI2_MIN, UI2_MAX); +#define _VarUI2FromR4(flt,out) VarUI2FromR8((double)flt,out) +#define _VarUI2FromR8 VarUI2FromR8 +#define _VarUI2FromCy VarUI2FromCy +#define _VarUI2FromDate(dt,out) VarUI2FromR8((double)dt,out) +#define _VarUI2FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_UI2) +#define _VarUI2FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_UI2) +SIMPLE(USHORT, VARIANT_BOOL, VarUI2FromBool); +NEGTST(USHORT, signed char, VarUI2FromI1); +POSTST(USHORT, ULONG, VarUI2FromUI4, UI2_MAX); +#define _VarUI2FromDec VarUI2FromDec +BOTHTST(USHORT, LONG64, VarUI2FromI8, UI2_MIN, UI2_MAX); +POSTST(USHORT, ULONG64, VarUI2FromUI8, UI2_MAX); + +/* I4 */ +SIMPLE(LONG, BYTE, VarI4FromUI1); +SIMPLE(LONG, SHORT, VarI4FromI2); +#define _VarI4FromR4(flt,out) VarI4FromR8((double)flt,out) +#define _VarI4FromR8 VarI4FromR8 +#define _VarI4FromCy VarI4FromCy +#define _VarI4FromDate(dt,out) VarI4FromR8((double)dt,out) +#define _VarI4FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_I4) +#define _VarI4FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, (BYTE*)out, VT_I4) +SIMPLE(LONG, VARIANT_BOOL, VarI4FromBool); +SIMPLE(LONG, signed char, VarI4FromI1); +SIMPLE(LONG, USHORT, VarI4FromUI2); +POSTST(LONG, ULONG, VarI4FromUI4, I4_MAX); +#define _VarI4FromDec VarI4FromDec +BOTHTST(LONG, LONG64, VarI4FromI8, I4_MIN, I4_MAX); +POSTST(LONG, ULONG64, VarI4FromUI8, I4_MAX); + +/* UI4 */ +SIMPLE(ULONG, BYTE, VarUI4FromUI1); +NEGTST(ULONG, SHORT, VarUI4FromI2); +NEGTST(ULONG, LONG, VarUI4FromI4); +#define _VarUI4FromR4(flt,out) VarUI4FromR8((double)flt,out) +#define _VarUI4FromR8 VarUI4FromR8 +#define _VarUI4FromCy VarUI4FromCy +#define _VarUI4FromDate(dt,out) VarUI4FromR8((double)dt,out) +#define _VarUI4FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_UI4) +#define _VarUI4FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_UI4) +SIMPLE(ULONG, VARIANT_BOOL, VarUI4FromBool); +NEGTST(ULONG, signed char, VarUI4FromI1); +SIMPLE(ULONG, USHORT, VarUI4FromUI2); +#define _VarUI4FromDec VarUI4FromDec +BOTHTST(ULONG, LONG64, VarUI4FromI8, UI4_MIN, UI4_MAX); +POSTST(ULONG, ULONG64, VarUI4FromUI8, UI4_MAX); + +/* I8 */ +SIMPLE(LONG64, BYTE, VarI8FromUI1); +SIMPLE(LONG64, SHORT, VarI8FromI2); +#define _VarI8FromR4 VarI8FromR8 +#define _VarI8FromR8 VarI8FromR8 +#define _VarI8FromCy VarI8FromCy +#define _VarI8FromDate(dt,out) VarI8FromR8((double)dt,out) +#define _VarI8FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_I8) +#define _VarI8FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_I8) +#define _VarI8FromBool _VarI8FromI2 +SIMPLE(LONG64, signed char, VarI8FromI1); +SIMPLE(LONG64, USHORT, VarI8FromUI2); +SIMPLE(LONG64, LONG, VarI8FromI4); +SIMPLE(LONG64, ULONG, VarI8FromUI4); +#define _VarI8FromDec VarI8FromDec +POSTST(LONG64, ULONG64, VarI8FromUI8, I8_MAX); + +/* UI8 */ +SIMPLE(ULONG64, BYTE, VarUI8FromUI1); +NEGTST(ULONG64, SHORT, VarUI8FromI2); +#define _VarUI8FromR4 VarUI8FromR8 +#define _VarUI8FromR8 VarUI8FromR8 +#define _VarUI8FromCy VarUI8FromCy +#define _VarUI8FromDate(dt,out) VarUI8FromR8((double)dt,out) +#define _VarUI8FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_UI8) +#define _VarUI8FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_UI8) +#define _VarUI8FromBool _VarI8FromI2 +NEGTST(ULONG64, signed char, VarUI8FromI1); +SIMPLE(ULONG64, USHORT, VarUI8FromUI2); +NEGTST(ULONG64, LONG, VarUI8FromI4); +SIMPLE(ULONG64, ULONG, VarUI8FromUI4); +#define _VarUI8FromDec VarUI8FromDec +NEGTST(ULONG64, LONG64, VarUI8FromI8); + +/* R4 (float) */ +SIMPLE(float, BYTE, VarR4FromUI1); +SIMPLE(float, SHORT, VarR4FromI2); +RETTYP _VarR4FromR8(double i, float* o) { + double d = i < 0.0 ? -i : i; + if (d > R4_MAX) return DISP_E_OVERFLOW; + *o = i; + return S_OK; +} +RETTYP _VarR4FromCy(CY i, float* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; } +#define _VarR4FromDate(dt,out) _VarR4FromR8((double)dt,out) +#define _VarR4FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_R4) +#define _VarR4FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_R4) +#define _VarR4FromBool _VarR4FromI2 +SIMPLE(float, signed char, VarR4FromI1); +SIMPLE(float, USHORT, VarR4FromUI2); +SIMPLE(float, LONG, VarR4FromI4); +SIMPLE(float, ULONG, VarR4FromUI4); +#define _VarR4FromDec VarR4FromDec +SIMPLE(float, LONG64, VarR4FromI8); +SIMPLE(float, ULONG64, VarR4FromUI8); + +/* R8 (double) */ +SIMPLE(double, BYTE, VarR8FromUI1); +SIMPLE(double, SHORT, VarR8FromI2); +SIMPLE(double, float, VarR8FromR4); +RETTYP _VarR8FromCy(CY i, double* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; } +SIMPLE(double, DATE, VarR8FromDate); +#define _VarR8FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_R8) +#define _VarR8FromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_R8) +#define _VarR8FromBool _VarR8FromI2 +SIMPLE(double, signed char, VarR8FromI1); +SIMPLE(double, USHORT, VarR8FromUI2); +SIMPLE(double, LONG, VarR8FromI4); +SIMPLE(double, ULONG, VarR8FromUI4); +#define _VarR8FromDec VarR8FromDec +SIMPLE(double, LONG64, VarR8FromI8); +SIMPLE(double, ULONG64, VarR8FromUI8); + +/* BOOL */ +#define BOOLFUNC(src, func) RETTYP _##func(src in, VARIANT_BOOL* out) { \ + *out = in ? VARIANT_TRUE : VARIANT_FALSE; return S_OK; } + +BOOLFUNC(signed char,VarBoolFromI1); +BOOLFUNC(BYTE,VarBoolFromUI1); +BOOLFUNC(SHORT,VarBoolFromI2); +BOOLFUNC(USHORT,VarBoolFromUI2); +BOOLFUNC(LONG,VarBoolFromI4); +BOOLFUNC(ULONG,VarBoolFromUI4); +BOOLFUNC(LONG64,VarBoolFromI8); +BOOLFUNC(ULONG64,VarBoolFromUI8); +#define _VarBoolFromR4(flt,out) _VarBoolFromR8((double)flt,out) +BOOLFUNC(double,VarBoolFromR8); +#define _VarBoolFromCy(i,o) _VarBoolFromI8(i.int64,o) +#define _VarBoolFromDate(dt,out) _VarBoolFromR8((double)dt,out) +#define _VarBoolFromStr VarBoolFromStr +#define _VarBoolFromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, (BYTE*)out, VT_BOOL) +#define _VarBoolFromDec VarBoolFromDec + +/* Internal flags for low level conversion functions */ +#define VAR_BOOLONOFF 0x0400 /* Convert bool to "On"/"Off" */ +#define VAR_BOOLYESNO 0x0800 /* Convert bool to "Yes"/"No" */ +#define VAR_NEGATIVE 0x1000 /* Number is negative */ + +/* DECIMAL */ +#define _VarDecFromUI1 VarDecFromUI4 +#define _VarDecFromI2 VarDecFromI4 +#define _VarDecFromR4 VarDecFromR4 +#define _VarDecFromR8 VarDecFromR8 +#define _VarDecFromCy VarDecFromCy +#define _VarDecFromDate(dt,out) VarDecFromR8((double)dt,out) +#define _VarDecFromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_DECIMAL) +#define _VarDecFromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_DECIMAL) +#define _VarDecFromBool VarDecFromBool +#define _VarDecFromI1 VarDecFromI4 +#define _VarDecFromUI2 VarDecFromUI4 +#define _VarDecFromI4 VarDecFromI4 +#define _VarDecFromUI4 VarDecFromUI4 +#define _VarDecFromI8 VarDecFromI8 +#define _VarDecFromUI8 VarDecFromUI8 + +/* CY (Currency) */ +#define _VarCyFromUI1 VarCyFromR8 +#define _VarCyFromI2 VarCyFromR8 +#define _VarCyFromR4 VarCyFromR8 +#define _VarCyFromR8 VarCyFromR8 +#define _VarCyFromDate VarCyFromR8 +#define _VarCyFromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_CY) +#define _VarCyFromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_CY) +#define _VarCyFromBool VarCyFromR8 +#define _VarCyFromI1 VarCyFromR8 +#define _VarCyFromUI2 VarCyFromR8 +#define _VarCyFromI4 VarCyFromR8 +#define _VarCyFromUI4 VarCyFromR8 +#define _VarCyFromDec VarCyFromDec +RETTYP _VarCyFromI8(LONG64 i, CY* o) { + if (i <= (I8_MIN/CY_MULTIPLIER) || i >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW; + o->int64 = i * CY_MULTIPLIER; + return S_OK; +} +#define _VarCyFromUI8 VarCyFromR8 + +/* DATE */ +#define _VarDateFromUI1 _VarR8FromUI1 +#define _VarDateFromI2 _VarR8FromI2 +#define _VarDateFromR4 _VarDateFromR8 +RETTYP _VarDateFromR8(double i, DATE* o) { + if (i <= (DATE_MIN - 1.0) || i >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW; + *o = (DATE)i; + return S_OK; +} +#define _VarDateFromCy _VarR8FromCy +#define _VarDateFromStr VarDateFromStr +#define _VarDateFromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_DATE) +#define _VarDateFromBool _VarR8FromBool +#define _VarDateFromI1 _VarR8FromI1 +#define _VarDateFromUI2 _VarR8FromUI2 +#define _VarDateFromI4 _VarDateFromR8 +#define _VarDateFromUI4 _VarDateFromR8 +#define _VarDateFromDec _VarR8FromDec +RETTYP _VarDateFromI8(LONG64 i, DATE* o) { + if (i < DATE_MIN || i > DATE_MAX) return DISP_E_OVERFLOW; + *o = (DATE)i; + return S_OK; +} +RETTYP _VarDateFromUI8(ULONG64 i, DATE* o) { + if (i > DATE_MAX) return DISP_E_OVERFLOW; + *o = (DATE)i; + return S_OK; +} + +/* BSTR */ +#define _VarBstrFromUI1 VarBstrFromUI4 +#define _VarBstrFromI2 VarBstrFromI4 +#define _VarBstrFromR4 VarBstrFromR8 +#define _VarBstrFromR8 VarBstrFromR8 +#define _VarBstrFromCy VarBstrFromCy +#define _VarBstrFromDate VarBstrFromDate +#define _VarBstrFromDisp(disp,lcid,out) VARIANT_FromDisp(disp, lcid, out, VT_BSTR) +#define _VarBstrFromBool VarBstrFromBool +#define _VarBstrFromI1 VarBstrFromI4 +#define _VarBstrFromUI2 VarBstrFromUI4 +#define _VarBstrFromI4 VarBstrFromI4 +#define _VarBstrFromUI4 VarBstrFromUI4 +#define _VarBstrFromDec VarBstrFromDec +#define _VarBstrFromI8 VarBstrFromI8 +#define _VarBstrFromUI8 VarBstrFromUI8 + +/* Macro to inline conversion from a float or double to any integer type, + * rounding according to the 'dutch' convention. + */ +#define OLEAUT32_DutchRound(typ, value, res) do { \ + double whole = (double)value < 0 ? ceil((double)value) : floor((double)value); \ + double fract = (double)value - whole; \ + if (fract > 0.5) res = (typ)whole + (typ)1; \ + else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \ + else if (fract >= 0.0) res = (typ)whole; \ + else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \ + else if (fract > -0.5) res = (typ)whole; \ + else res = (typ)whole - (typ)1; \ +} while(0); + +/* The localised characters that make up a valid number */ +typedef struct tagVARIANT_NUMBER_CHARS +{ + WCHAR cNegativeSymbol; + WCHAR cPositiveSymbol; + WCHAR cDecimalPoint; + WCHAR cDigitSeperator; + WCHAR cCurrencyLocal; + WCHAR cCurrencyLocal2; + WCHAR cCurrencyDecimalPoint; + WCHAR cCurrencyDigitSeperator; +} VARIANT_NUMBER_CHARS; + +void VARIANT_GetLocalisedNumberChars(VARIANT_NUMBER_CHARS*,LCID,DWORD); diff --git a/reactos/lib/oleaut32/vartype.c b/reactos/lib/oleaut32/vartype.c index 2e771e8ce75..a82b6922992 100644 --- a/reactos/lib/oleaut32/vartype.c +++ b/reactos/lib/oleaut32/vartype.c @@ -1,6558 +1,6558 @@ -/* - * Low level variant functions - * - * Copyright 2003 Jon Griffiths - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "wine/debug.h" -#include "wine/unicode.h" -#include "winbase.h" -#include "winuser.h" -#include "winnt.h" -#include "variant.h" -#include "resource.h" - -WINE_DEFAULT_DEBUG_CHANNEL(variant); - -extern HMODULE OLEAUT32_hModule; - -static const WCHAR szFloatFormatW[] = { '%','.','7','G','\0' }; -static const WCHAR szDoubleFormatW[] = { '%','.','1','5','G','\0' }; - -/* Copy data from one variant to another. */ -static inline void VARIANT_CopyData(const VARIANT *srcVar, VARTYPE vt, void *pOut) -{ - switch (vt) - { - case VT_I1: - case VT_UI1: memcpy(pOut, &V_UI1(srcVar), sizeof(BYTE)); break; - case VT_BOOL: - case VT_I2: - case VT_UI2: memcpy(pOut, &V_UI2(srcVar), sizeof(SHORT)); break; - case VT_R4: - case VT_INT: - case VT_I4: - case VT_UINT: - case VT_UI4: memcpy(pOut, &V_UI4(srcVar), sizeof (LONG)); break; - case VT_R8: - case VT_DATE: - case VT_CY: - case VT_I8: - case VT_UI8: memcpy(pOut, &V_UI8(srcVar), sizeof (LONG64)); break; - case VT_INT_PTR: memcpy(pOut, &V_INT_PTR(srcVar), sizeof (INT_PTR)); break; - case VT_DECIMAL: memcpy(pOut, &V_DECIMAL(srcVar), sizeof (DECIMAL)); break; - default: - FIXME("VT_ type %d unhandled, please report!\n", vt); - } -} - - -/* Coerce VT_BSTR to a numeric type */ -HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags, - void* pOut, VARTYPE vt) -{ - VARIANTARG dstVar; - HRESULT hRet; - NUMPARSE np; - BYTE rgb[1024]; - - /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */ - np.cDig = sizeof(rgb) / sizeof(BYTE); - np.dwInFlags = NUMPRS_STD; - - hRet = VarParseNumFromStr(pStrIn, lcid, ulFlags, &np, rgb); - - if (SUCCEEDED(hRet)) - { - /* 1 << vt gives us the VTBIT constant for the destination number type */ - hRet = VarNumFromParseNum(&np, rgb, 1 << vt, &dstVar); - if (SUCCEEDED(hRet)) - VARIANT_CopyData(&dstVar, vt, pOut); - } - return hRet; -} - -/* Coerce VT_DISPATCH to another type */ -HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut, VARTYPE vt) -{ - static const DISPPARAMS emptyParams = { NULL, NULL, 0, 0 }; - VARIANTARG srcVar, dstVar; - HRESULT hRet; - - if (!pdispIn) - return DISP_E_BADVARTYPE; - - /* Get the default 'value' property from the IDispatch */ - hRet = IDispatch_Invoke(pdispIn, DISPID_VALUE, &IID_NULL, lcid, DISPATCH_PROPERTYGET, - (DISPPARAMS*)&emptyParams, &srcVar, NULL, NULL); - - if (SUCCEEDED(hRet)) - { - /* Convert the property to the requested type */ - V_VT(&dstVar) = VT_EMPTY; - hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, 0, vt); - VariantClear(&srcVar); - - if (SUCCEEDED(hRet)) - { - VARIANT_CopyData(&dstVar, vt, pOut); - VariantClear(&srcVar); - } - } - else - hRet = DISP_E_TYPEMISMATCH; - return hRet; -} - -/* I1 - */ - -/************************************************************************ - * VarI1FromUI1 (OLEAUT32.244) - * - * Convert a VT_UI1 to a VT_I1. - * - * PARAMS - * bIn [I] Source - * pcOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char* pcOut) -{ - return _VarI1FromUI1(bIn, pcOut); -} - -/************************************************************************ - * VarI1FromI2 (OLEAUT32.245) - * - * Convert a VT_I2 to a VT_I1. - * - * PARAMS - * sIn [I] Source - * pcOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI1FromI2(SHORT sIn, signed char* pcOut) -{ - return _VarI1FromI2(sIn, pcOut); -} - -/************************************************************************ - * VarI1FromI4 (OLEAUT32.246) - * - * Convert a VT_I4 to a VT_I1. - * - * PARAMS - * iIn [I] Source - * pcOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI1FromI4(LONG iIn, signed char* pcOut) -{ - return _VarI1FromI4(iIn, pcOut); -} - -/************************************************************************ - * VarI1FromR4 (OLEAUT32.247) - * - * Convert a VT_R4 to a VT_I1. - * - * PARAMS - * fltIn [I] Source - * pcOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char* pcOut) -{ - return _VarI1FromR4(fltIn, pcOut); -} - -/************************************************************************ - * VarI1FromR8 (OLEAUT32.248) - * - * Convert a VT_R8 to a VT_I1. - * - * PARAMS - * dblIn [I] Source - * pcOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * - * NOTES - * See VarI8FromR8() for details concerning rounding. - */ -HRESULT WINAPI VarI1FromR8(double dblIn, signed char* pcOut) -{ - if (dblIn < (double)I1_MIN || dblIn > (double)I1_MAX) - return DISP_E_OVERFLOW; - OLEAUT32_DutchRound(CHAR, dblIn, *pcOut); - return S_OK; -} - -/************************************************************************ - * VarI1FromDate (OLEAUT32.249) - * - * Convert a VT_DATE to a VT_I1. - * - * PARAMS - * dateIn [I] Source - * pcOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char* pcOut) -{ - return _VarI1FromDate(dateIn, pcOut); -} - -/************************************************************************ - * VarI1FromCy (OLEAUT32.250) - * - * Convert a VT_CY to a VT_I1. - * - * PARAMS - * cyIn [I] Source - * pcOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI1FromCy(CY cyIn, signed char* pcOut) -{ - LONG i = I1_MAX + 1; - - _VarI4FromCy(cyIn, &i); - return _VarI1FromI4(i, pcOut); -} - -/************************************************************************ - * VarI1FromStr (OLEAUT32.251) - * - * Convert a VT_BSTR to a VT_I1. - * - * PARAMS - * strIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pcOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char* pcOut) -{ - return _VarI1FromStr(strIn, lcid, dwFlags, pcOut); -} - -/************************************************************************ - * VarI1FromDisp (OLEAUT32.252) - * - * Convert a VT_DISPATCH to a VT_I1. - * - * PARAMS - * pdispIn [I] Source - * lcid [I] LCID for conversion - * pcOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarI1FromDisp(IDispatch* pdispIn, LCID lcid, signed char* pcOut) -{ - return _VarI1FromDisp(pdispIn, lcid, pcOut); -} - -/************************************************************************ - * VarI1FromBool (OLEAUT32.253) - * - * Convert a VT_BOOL to a VT_I1. - * - * PARAMS - * boolIn [I] Source - * pcOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char* pcOut) -{ - return _VarI1FromBool(boolIn, pcOut); -} - -/************************************************************************ - * VarI1FromUI2 (OLEAUT32.254) - * - * Convert a VT_UI2 to a VT_I1. - * - * PARAMS - * usIn [I] Source - * pcOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI1FromUI2(USHORT usIn, signed char* pcOut) -{ - return _VarI1FromUI2(usIn, pcOut); -} - -/************************************************************************ - * VarI1FromUI4 (OLEAUT32.255) - * - * Convert a VT_UI4 to a VT_I1. - * - * PARAMS - * ulIn [I] Source - * pcOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char* pcOut) -{ - return _VarI1FromUI4(ulIn, pcOut); -} - -/************************************************************************ - * VarI1FromDec (OLEAUT32.256) - * - * Convert a VT_DECIMAL to a VT_I1. - * - * PARAMS - * pDecIn [I] Source - * pcOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI1FromDec(DECIMAL *pdecIn, signed char* pcOut) -{ - LONG64 i64; - HRESULT hRet; - - hRet = _VarI8FromDec(pdecIn, &i64); - - if (SUCCEEDED(hRet)) - hRet = _VarI1FromI8(i64, pcOut); - return hRet; -} - -/************************************************************************ - * VarI1FromI8 (OLEAUT32.376) - * - * Convert a VT_I8 to a VT_I1. - * - * PARAMS - * llIn [I] Source - * pcOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI1FromI8(LONG64 llIn, signed char* pcOut) -{ - return _VarI1FromI8(llIn, pcOut); -} - -/************************************************************************ - * VarI1FromUI8 (OLEAUT32.377) - * - * Convert a VT_UI8 to a VT_I1. - * - * PARAMS - * ullIn [I] Source - * pcOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI1FromUI8(ULONG64 ullIn, signed char* pcOut) -{ - return _VarI1FromUI8(ullIn, pcOut); -} - -/* UI1 - */ - -/************************************************************************ - * VarUI1FromI2 (OLEAUT32.130) - * - * Convert a VT_I2 to a VT_UI1. - * - * PARAMS - * sIn [I] Source - * pbOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI1FromI2(SHORT sIn, BYTE* pbOut) -{ - return _VarUI1FromI2(sIn, pbOut); -} - -/************************************************************************ - * VarUI1FromI4 (OLEAUT32.131) - * - * Convert a VT_I4 to a VT_UI1. - * - * PARAMS - * iIn [I] Source - * pbOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI1FromI4(LONG iIn, BYTE* pbOut) -{ - return _VarUI1FromI4(iIn, pbOut); -} - -/************************************************************************ - * VarUI1FromR4 (OLEAUT32.132) - * - * Convert a VT_R4 to a VT_UI1. - * - * PARAMS - * fltIn [I] Source - * pbOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut) -{ - return _VarUI1FromR4(fltIn, pbOut); -} - -/************************************************************************ - * VarUI1FromR8 (OLEAUT32.133) - * - * Convert a VT_R8 to a VT_UI1. - * - * PARAMS - * dblIn [I] Source - * pbOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * - * NOTES - * See VarI8FromR8() for details concerning rounding. - */ -HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut) -{ - if (dblIn < -0.5 || dblIn > (double)UI1_MAX) - return DISP_E_OVERFLOW; - OLEAUT32_DutchRound(BYTE, dblIn, *pbOut); - return S_OK; -} - -/************************************************************************ - * VarUI1FromCy (OLEAUT32.134) - * - * Convert a VT_CY to a VT_UI1. - * - * PARAMS - * cyIn [I] Source - * pbOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * - * NOTES - * Negative values >= -5000 will be converted to 0. - */ -HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) -{ - ULONG i = UI1_MAX + 1; - - _VarUI4FromCy(cyIn, &i); - return _VarUI1FromUI4(i, pbOut); -} - -/************************************************************************ - * VarUI1FromDate (OLEAUT32.135) - * - * Convert a VT_DATE to a VT_UI1. - * - * PARAMS - * dateIn [I] Source - * pbOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut) -{ - return _VarUI1FromDate(dateIn, pbOut); -} - -/************************************************************************ - * VarUI1FromStr (OLEAUT32.136) - * - * Convert a VT_BSTR to a VT_UI1. - * - * PARAMS - * strIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pbOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut) -{ - return _VarUI1FromStr(strIn, lcid, dwFlags, pbOut); -} - -/************************************************************************ - * VarUI1FromDisp (OLEAUT32.137) - * - * Convert a VT_DISPATCH to a VT_UI1. - * - * PARAMS - * pdispIn [I] Source - * lcid [I] LCID for conversion - * pbOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarUI1FromDisp(IDispatch* pdispIn, LCID lcid, BYTE* pbOut) -{ - return _VarUI1FromDisp(pdispIn, lcid, pbOut); -} - -/************************************************************************ - * VarUI1FromBool (OLEAUT32.138) - * - * Convert a VT_BOOL to a VT_UI1. - * - * PARAMS - * boolIn [I] Source - * pbOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut) -{ - return _VarUI1FromBool(boolIn, pbOut); -} - -/************************************************************************ - * VarUI1FromI1 (OLEAUT32.237) - * - * Convert a VT_I1 to a VT_UI1. - * - * PARAMS - * cIn [I] Source - * pbOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut) -{ - return _VarUI1FromI1(cIn, pbOut); -} - -/************************************************************************ - * VarUI1FromUI2 (OLEAUT32.238) - * - * Convert a VT_UI2 to a VT_UI1. - * - * PARAMS - * usIn [I] Source - * pbOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI1FromUI2(USHORT usIn, BYTE* pbOut) -{ - return _VarUI1FromUI2(usIn, pbOut); -} - -/************************************************************************ - * VarUI1FromUI4 (OLEAUT32.239) - * - * Convert a VT_UI4 to a VT_UI1. - * - * PARAMS - * ulIn [I] Source - * pbOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut) -{ - return _VarUI1FromUI4(ulIn, pbOut); -} - -/************************************************************************ - * VarUI1FromDec (OLEAUT32.240) - * - * Convert a VT_DECIMAL to a VT_UI1. - * - * PARAMS - * pDecIn [I] Source - * pbOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI1FromDec(DECIMAL *pdecIn, BYTE* pbOut) -{ - LONG64 i64; - HRESULT hRet; - - hRet = _VarI8FromDec(pdecIn, &i64); - - if (SUCCEEDED(hRet)) - hRet = _VarUI1FromI8(i64, pbOut); - return hRet; -} - -/************************************************************************ - * VarUI1FromI8 (OLEAUT32.372) - * - * Convert a VT_I8 to a VT_UI1. - * - * PARAMS - * llIn [I] Source - * pbOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI1FromI8(LONG64 llIn, BYTE* pbOut) -{ - return _VarUI1FromI8(llIn, pbOut); -} - -/************************************************************************ - * VarUI1FromUI8 (OLEAUT32.373) - * - * Convert a VT_UI8 to a VT_UI1. - * - * PARAMS - * ullIn [I] Source - * pbOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI1FromUI8(ULONG64 ullIn, BYTE* pbOut) -{ - return _VarUI1FromUI8(ullIn, pbOut); -} - - -/* I2 - */ - -/************************************************************************ - * VarI2FromUI1 (OLEAUT32.48) - * - * Convert a VT_UI2 to a VT_I2. - * - * PARAMS - * bIn [I] Source - * psOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarI2FromUI1(BYTE bIn, SHORT* psOut) -{ - return _VarI2FromUI1(bIn, psOut); -} - -/************************************************************************ - * VarI2FromI4 (OLEAUT32.49) - * - * Convert a VT_I4 to a VT_I2. - * - * PARAMS - * iIn [I] Source - * psOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI2FromI4(LONG iIn, SHORT* psOut) -{ - return _VarI2FromI4(iIn, psOut); -} - -/************************************************************************ - * VarI2FromR4 (OLEAUT32.50) - * - * Convert a VT_R4 to a VT_I2. - * - * PARAMS - * fltIn [I] Source - * psOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI2FromR4(FLOAT fltIn, SHORT* psOut) -{ - return _VarI2FromR4(fltIn, psOut); -} - -/************************************************************************ - * VarI2FromR8 (OLEAUT32.51) - * - * Convert a VT_R8 to a VT_I2. - * - * PARAMS - * dblIn [I] Source - * psOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - * - * NOTES - * See VarI8FromR8() for details concerning rounding. - */ -HRESULT WINAPI VarI2FromR8(double dblIn, SHORT* psOut) -{ - if (dblIn < (double)I2_MIN || dblIn > (double)I2_MAX) - return DISP_E_OVERFLOW; - OLEAUT32_DutchRound(SHORT, dblIn, *psOut); - return S_OK; -} - -/************************************************************************ - * VarI2FromCy (OLEAUT32.52) - * - * Convert a VT_CY to a VT_I2. - * - * PARAMS - * cyIn [I] Source - * psOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI2FromCy(CY cyIn, SHORT* psOut) -{ - LONG i = I2_MAX + 1; - - _VarI4FromCy(cyIn, &i); - return _VarI2FromI4(i, psOut); -} - -/************************************************************************ - * VarI2FromDate (OLEAUT32.53) - * - * Convert a VT_DATE to a VT_I2. - * - * PARAMS - * dateIn [I] Source - * psOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI2FromDate(DATE dateIn, SHORT* psOut) -{ - return _VarI2FromDate(dateIn, psOut); -} - -/************************************************************************ - * VarI2FromStr (OLEAUT32.54) - * - * Convert a VT_BSTR to a VT_I2. - * - * PARAMS - * strIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * psOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if any parameter is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psOut) -{ - return _VarI2FromStr(strIn, lcid, dwFlags, psOut); -} - -/************************************************************************ - * VarI2FromDisp (OLEAUT32.55) - * - * Convert a VT_DISPATCH to a VT_I2. - * - * PARAMS - * pdispIn [I] Source - * lcid [I] LCID for conversion - * psOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if pdispIn is invalid, - * DISP_E_OVERFLOW, if the value will not fit in the destination, - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarI2FromDisp(IDispatch* pdispIn, LCID lcid, SHORT* psOut) -{ - return _VarI2FromDisp(pdispIn, lcid, psOut); -} - -/************************************************************************ - * VarI2FromBool (OLEAUT32.56) - * - * Convert a VT_BOOL to a VT_I2. - * - * PARAMS - * boolIn [I] Source - * psOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, SHORT* psOut) -{ - return _VarI2FromBool(boolIn, psOut); -} - -/************************************************************************ - * VarI2FromI1 (OLEAUT32.205) - * - * Convert a VT_I1 to a VT_I2. - * - * PARAMS - * cIn [I] Source - * psOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarI2FromI1(signed char cIn, SHORT* psOut) -{ - return _VarI2FromI1(cIn, psOut); -} - -/************************************************************************ - * VarI2FromUI2 (OLEAUT32.206) - * - * Convert a VT_UI2 to a VT_I2. - * - * PARAMS - * usIn [I] Source - * psOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI2FromUI2(USHORT usIn, SHORT* psOut) -{ - return _VarI2FromUI2(usIn, psOut); -} - -/************************************************************************ - * VarI2FromUI4 (OLEAUT32.207) - * - * Convert a VT_UI4 to a VT_I2. - * - * PARAMS - * ulIn [I] Source - * psOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI2FromUI4(ULONG ulIn, SHORT* psOut) -{ - return _VarI2FromUI4(ulIn, psOut); -} - -/************************************************************************ - * VarI2FromDec (OLEAUT32.208) - * - * Convert a VT_DECIMAL to a VT_I2. - * - * PARAMS - * pDecIn [I] Source - * psOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI2FromDec(DECIMAL *pdecIn, SHORT* psOut) -{ - LONG64 i64; - HRESULT hRet; - - hRet = _VarI8FromDec(pdecIn, &i64); - - if (SUCCEEDED(hRet)) - hRet = _VarI2FromI8(i64, psOut); - return hRet; -} - -/************************************************************************ - * VarI2FromI8 (OLEAUT32.346) - * - * Convert a VT_I8 to a VT_I2. - * - * PARAMS - * llIn [I] Source - * psOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI2FromI8(LONG64 llIn, SHORT* psOut) -{ - return _VarI2FromI8(llIn, psOut); -} - -/************************************************************************ - * VarI2FromUI8 (OLEAUT32.347) - * - * Convert a VT_UI8 to a VT_I2. - * - * PARAMS - * ullIn [I] Source - * psOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI2FromUI8(ULONG64 ullIn, SHORT* psOut) -{ - return _VarI2FromUI8(ullIn, psOut); -} - -/* UI2 - */ - -/************************************************************************ - * VarUI2FromUI1 (OLEAUT32.257) - * - * Convert a VT_UI1 to a VT_UI2. - * - * PARAMS - * bIn [I] Source - * pusOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* pusOut) -{ - return _VarUI2FromUI1(bIn, pusOut); -} - -/************************************************************************ - * VarUI2FromI2 (OLEAUT32.258) - * - * Convert a VT_I2 to a VT_UI2. - * - * PARAMS - * sIn [I] Source - * pusOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI2FromI2(SHORT sIn, USHORT* pusOut) -{ - return _VarUI2FromI2(sIn, pusOut); -} - -/************************************************************************ - * VarUI2FromI4 (OLEAUT32.259) - * - * Convert a VT_I4 to a VT_UI2. - * - * PARAMS - * iIn [I] Source - * pusOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI2FromI4(LONG iIn, USHORT* pusOut) -{ - return _VarUI2FromI4(iIn, pusOut); -} - -/************************************************************************ - * VarUI2FromR4 (OLEAUT32.260) - * - * Convert a VT_R4 to a VT_UI2. - * - * PARAMS - * fltIn [I] Source - * pusOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* pusOut) -{ - return _VarUI2FromR4(fltIn, pusOut); -} - -/************************************************************************ - * VarUI2FromR8 (OLEAUT32.261) - * - * Convert a VT_R8 to a VT_UI2. - * - * PARAMS - * dblIn [I] Source - * pusOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - * - * NOTES - * See VarI8FromR8() for details concerning rounding. - */ -HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* pusOut) -{ - if (dblIn < -0.5 || dblIn > (double)UI2_MAX) - return DISP_E_OVERFLOW; - OLEAUT32_DutchRound(USHORT, dblIn, *pusOut); - return S_OK; -} - -/************************************************************************ - * VarUI2FromDate (OLEAUT32.262) - * - * Convert a VT_DATE to a VT_UI2. - * - * PARAMS - * dateIn [I] Source - * pusOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* pusOut) -{ - return _VarUI2FromDate(dateIn, pusOut); -} - -/************************************************************************ - * VarUI2FromCy (OLEAUT32.263) - * - * Convert a VT_CY to a VT_UI2. - * - * PARAMS - * cyIn [I] Source - * pusOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - * - * NOTES - * Negative values >= -5000 will be converted to 0. - */ -HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) -{ - ULONG i = UI2_MAX + 1; - - _VarUI4FromCy(cyIn, &i); - return _VarUI2FromUI4(i, pusOut); -} - -/************************************************************************ - * VarUI2FromStr (OLEAUT32.264) - * - * Convert a VT_BSTR to a VT_UI2. - * - * PARAMS - * strIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pusOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* pusOut) -{ - return _VarUI2FromStr(strIn, lcid, dwFlags, pusOut); -} - -/************************************************************************ - * VarUI2FromDisp (OLEAUT32.265) - * - * Convert a VT_DISPATCH to a VT_UI2. - * - * PARAMS - * pdispIn [I] Source - * lcid [I] LCID for conversion - * pusOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarUI2FromDisp(IDispatch* pdispIn, LCID lcid, USHORT* pusOut) -{ - return _VarUI2FromDisp(pdispIn, lcid, pusOut); -} - -/************************************************************************ - * VarUI2FromBool (OLEAUT32.266) - * - * Convert a VT_BOOL to a VT_UI2. - * - * PARAMS - * boolIn [I] Source - * pusOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* pusOut) -{ - return _VarUI2FromBool(boolIn, pusOut); -} - -/************************************************************************ - * VarUI2FromI1 (OLEAUT32.267) - * - * Convert a VT_I1 to a VT_UI2. - * - * PARAMS - * cIn [I] Source - * pusOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* pusOut) -{ - return _VarUI2FromI1(cIn, pusOut); -} - -/************************************************************************ - * VarUI2FromUI4 (OLEAUT32.268) - * - * Convert a VT_UI4 to a VT_UI2. - * - * PARAMS - * ulIn [I] Source - * pusOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* pusOut) -{ - return _VarUI2FromUI4(ulIn, pusOut); -} - -/************************************************************************ - * VarUI2FromDec (OLEAUT32.269) - * - * Convert a VT_DECIMAL to a VT_UI2. - * - * PARAMS - * pDecIn [I] Source - * pusOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI2FromDec(DECIMAL *pdecIn, USHORT* pusOut) -{ - LONG64 i64; - HRESULT hRet; - - hRet = _VarI8FromDec(pdecIn, &i64); - - if (SUCCEEDED(hRet)) - hRet = _VarUI2FromI8(i64, pusOut); - return hRet; -} - -/************************************************************************ - * VarUI2FromI8 (OLEAUT32.378) - * - * Convert a VT_I8 to a VT_UI2. - * - * PARAMS - * llIn [I] Source - * pusOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI2FromI8(LONG64 llIn, USHORT* pusOut) -{ - return _VarUI2FromI8(llIn, pusOut); -} - -/************************************************************************ - * VarUI2FromUI8 (OLEAUT32.379) - * - * Convert a VT_UI8 to a VT_UI2. - * - * PARAMS - * ullIn [I] Source - * pusOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI2FromUI8(ULONG64 ullIn, USHORT* pusOut) -{ - return _VarUI2FromUI8(ullIn, pusOut); -} - -/* I4 - */ - -/************************************************************************ - * VarI4FromUI1 (OLEAUT32.58) - * - * Convert a VT_UI1 to a VT_I4. - * - * PARAMS - * bIn [I] Source - * piOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG *piOut) -{ - return _VarI4FromUI1(bIn, piOut); -} - -/************************************************************************ - * VarI4FromI2 (OLEAUT32.59) - * - * Convert a VT_I2 to a VT_I4. - * - * PARAMS - * sIn [I] Source - * piOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI4FromI2(SHORT sIn, LONG *piOut) -{ - return _VarI4FromI2(sIn, piOut); -} - -/************************************************************************ - * VarI4FromR4 (OLEAUT32.60) - * - * Convert a VT_R4 to a VT_I4. - * - * PARAMS - * fltIn [I] Source - * piOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG *piOut) -{ - return _VarI4FromR4(fltIn, piOut); -} - -/************************************************************************ - * VarI4FromR8 (OLEAUT32.61) - * - * Convert a VT_R8 to a VT_I4. - * - * PARAMS - * dblIn [I] Source - * piOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - * - * NOTES - * See VarI8FromR8() for details concerning rounding. - */ -HRESULT WINAPI VarI4FromR8(double dblIn, LONG *piOut) -{ - if (dblIn < (double)I4_MIN || dblIn > (double)I4_MAX) - return DISP_E_OVERFLOW; - OLEAUT32_DutchRound(LONG, dblIn, *piOut); - return S_OK; -} - -/************************************************************************ - * VarI4FromCy (OLEAUT32.62) - * - * Convert a VT_CY to a VT_I4. - * - * PARAMS - * cyIn [I] Source - * piOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI4FromCy(CY cyIn, LONG *piOut) -{ - double d = cyIn.int64 / CY_MULTIPLIER_F; - return _VarI4FromR8(d, piOut); -} - -/************************************************************************ - * VarI4FromDate (OLEAUT32.63) - * - * Convert a VT_DATE to a VT_I4. - * - * PARAMS - * dateIn [I] Source - * piOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG *piOut) -{ - return _VarI4FromDate(dateIn, piOut); -} - -/************************************************************************ - * VarI4FromStr (OLEAUT32.64) - * - * Convert a VT_BSTR to a VT_I4. - * - * PARAMS - * strIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * piOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if any parameter is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if strIn cannot be converted - */ -HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOut) -{ - return _VarI4FromStr(strIn, lcid, dwFlags, piOut); -} - -/************************************************************************ - * VarI4FromDisp (OLEAUT32.65) - * - * Convert a VT_DISPATCH to a VT_I4. - * - * PARAMS - * pdispIn [I] Source - * lcid [I] LCID for conversion - * piOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarI4FromDisp(IDispatch* pdispIn, LCID lcid, LONG *piOut) -{ - return _VarI4FromDisp(pdispIn, lcid, piOut); -} - -/************************************************************************ - * VarI4FromBool (OLEAUT32.66) - * - * Convert a VT_BOOL to a VT_I4. - * - * PARAMS - * boolIn [I] Source - * piOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG *piOut) -{ - return _VarI4FromBool(boolIn, piOut); -} - -/************************************************************************ - * VarI4FromI1 (OLEAUT32.209) - * - * Convert a VT_I4 to a VT_I4. - * - * PARAMS - * cIn [I] Source - * piOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarI4FromI1(signed char cIn, LONG *piOut) -{ - return _VarI4FromI1(cIn, piOut); -} - -/************************************************************************ - * VarI4FromUI2 (OLEAUT32.210) - * - * Convert a VT_UI2 to a VT_I4. - * - * PARAMS - * usIn [I] Source - * piOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarI4FromUI2(USHORT usIn, LONG *piOut) -{ - return _VarI4FromUI2(usIn, piOut); -} - -/************************************************************************ - * VarI4FromUI4 (OLEAUT32.211) - * - * Convert a VT_UI4 to a VT_I4. - * - * PARAMS - * ulIn [I] Source - * piOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG *piOut) -{ - return _VarI4FromUI4(ulIn, piOut); -} - -/************************************************************************ - * VarI4FromDec (OLEAUT32.212) - * - * Convert a VT_DECIMAL to a VT_I4. - * - * PARAMS - * pDecIn [I] Source - * piOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if pdecIn is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI4FromDec(DECIMAL *pdecIn, LONG *piOut) -{ - LONG64 i64; - HRESULT hRet; - - hRet = _VarI8FromDec(pdecIn, &i64); - - if (SUCCEEDED(hRet)) - hRet = _VarI4FromI8(i64, piOut); - return hRet; -} - -/************************************************************************ - * VarI4FromI8 (OLEAUT32.348) - * - * Convert a VT_I8 to a VT_I4. - * - * PARAMS - * llIn [I] Source - * piOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI4FromI8(LONG64 llIn, LONG *piOut) -{ - return _VarI4FromI8(llIn, piOut); -} - -/************************************************************************ - * VarI4FromUI8 (OLEAUT32.349) - * - * Convert a VT_UI8 to a VT_I4. - * - * PARAMS - * ullIn [I] Source - * piOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI4FromUI8(ULONG64 ullIn, LONG *piOut) -{ - return _VarI4FromUI8(ullIn, piOut); -} - -/* UI4 - */ - -/************************************************************************ - * VarUI4FromUI1 (OLEAUT32.270) - * - * Convert a VT_UI1 to a VT_UI4. - * - * PARAMS - * bIn [I] Source - * pulOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG *pulOut) -{ - return _VarUI4FromUI1(bIn, pulOut); -} - -/************************************************************************ - * VarUI4FromI2 (OLEAUT32.271) - * - * Convert a VT_I2 to a VT_UI4. - * - * PARAMS - * sIn [I] Source - * pulOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI4FromI2(SHORT sIn, ULONG *pulOut) -{ - return _VarUI4FromI2(sIn, pulOut); -} - -/************************************************************************ - * VarUI4FromI4 (OLEAUT32.272) - * - * Convert a VT_I4 to a VT_UI4. - * - * PARAMS - * iIn [I] Source - * pulOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI4FromI4(LONG iIn, ULONG *pulOut) -{ - return _VarUI4FromI4(iIn, pulOut); -} - -/************************************************************************ - * VarUI4FromR4 (OLEAUT32.273) - * - * Convert a VT_R4 to a VT_UI4. - * - * PARAMS - * fltIn [I] Source - * pulOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG *pulOut) -{ - return _VarUI4FromR4(fltIn, pulOut); -} - -/************************************************************************ - * VarUI4FromR8 (OLEAUT32.274) - * - * Convert a VT_R8 to a VT_UI4. - * - * PARAMS - * dblIn [I] Source - * pulOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - * - * NOTES - * See VarI8FromR8() for details concerning rounding. - */ -HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG *pulOut) -{ - if (dblIn < -0.5 || dblIn > (double)UI4_MAX) - return DISP_E_OVERFLOW; - OLEAUT32_DutchRound(ULONG, dblIn, *pulOut); - return S_OK; -} - -/************************************************************************ - * VarUI4FromDate (OLEAUT32.275) - * - * Convert a VT_DATE to a VT_UI4. - * - * PARAMS - * dateIn [I] Source - * pulOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG *pulOut) -{ - return _VarUI4FromDate(dateIn, pulOut); -} - -/************************************************************************ - * VarUI4FromCy (OLEAUT32.276) - * - * Convert a VT_CY to a VT_UI4. - * - * PARAMS - * cyIn [I] Source - * pulOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG *pulOut) -{ - double d = cyIn.int64 / CY_MULTIPLIER_F; - return _VarUI4FromR8(d, pulOut); -} - -/************************************************************************ - * VarUI4FromStr (OLEAUT32.277) - * - * Convert a VT_BSTR to a VT_UI4. - * - * PARAMS - * strIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pulOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if any parameter is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if strIn cannot be converted - */ -HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pulOut) -{ - return _VarUI4FromStr(strIn, lcid, dwFlags, pulOut); -} - -/************************************************************************ - * VarUI4FromDisp (OLEAUT32.278) - * - * Convert a VT_DISPATCH to a VT_UI4. - * - * PARAMS - * pdispIn [I] Source - * lcid [I] LCID for conversion - * pulOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarUI4FromDisp(IDispatch* pdispIn, LCID lcid, ULONG *pulOut) -{ - return _VarUI4FromDisp(pdispIn, lcid, pulOut); -} - -/************************************************************************ - * VarUI4FromBool (OLEAUT32.279) - * - * Convert a VT_BOOL to a VT_UI4. - * - * PARAMS - * boolIn [I] Source - * pulOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG *pulOut) -{ - return _VarUI4FromBool(boolIn, pulOut); -} - -/************************************************************************ - * VarUI4FromI1 (OLEAUT32.280) - * - * Convert a VT_I1 to a VT_UI4. - * - * PARAMS - * cIn [I] Source - * pulOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG *pulOut) -{ - return _VarUI4FromI1(cIn, pulOut); -} - -/************************************************************************ - * VarUI4FromUI2 (OLEAUT32.281) - * - * Convert a VT_UI2 to a VT_UI4. - * - * PARAMS - * usIn [I] Source - * pulOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarUI4FromUI2(USHORT usIn, ULONG *pulOut) -{ - return _VarUI4FromUI2(usIn, pulOut); -} - -/************************************************************************ - * VarUI4FromDec (OLEAUT32.282) - * - * Convert a VT_DECIMAL to a VT_UI4. - * - * PARAMS - * pDecIn [I] Source - * pulOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if pdecIn is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI4FromDec(DECIMAL *pdecIn, ULONG *pulOut) -{ - LONG64 i64; - HRESULT hRet; - - hRet = _VarI8FromDec(pdecIn, &i64); - - if (SUCCEEDED(hRet)) - hRet = _VarUI4FromI8(i64, pulOut); - return hRet; -} - -/************************************************************************ - * VarUI4FromI8 (OLEAUT32.425) - * - * Convert a VT_I8 to a VT_UI4. - * - * PARAMS - * llIn [I] Source - * pulOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI4FromI8(LONG64 llIn, ULONG *pulOut) -{ - return _VarUI4FromI8(llIn, pulOut); -} - -/************************************************************************ - * VarUI4FromUI8 (OLEAUT32.426) - * - * Convert a VT_UI8 to a VT_UI4. - * - * PARAMS - * ullIn [I] Source - * pulOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI4FromUI8(ULONG64 ullIn, ULONG *pulOut) -{ - return _VarUI4FromUI8(ullIn, pulOut); -} - -/* I8 - */ - -/************************************************************************ - * VarI8FromUI1 (OLEAUT32.333) - * - * Convert a VT_UI1 to a VT_I8. - * - * PARAMS - * bIn [I] Source - * pi64Out [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarI8FromUI1(BYTE bIn, LONG64* pi64Out) -{ - return _VarI8FromUI1(bIn, pi64Out); -} - - -/************************************************************************ - * VarI8FromI2 (OLEAUT32.334) - * - * Convert a VT_I2 to a VT_I8. - * - * PARAMS - * sIn [I] Source - * pi64Out [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarI8FromI2(SHORT sIn, LONG64* pi64Out) -{ - return _VarI8FromI2(sIn, pi64Out); -} - -/************************************************************************ - * VarI8FromR4 (OLEAUT32.335) - * - * Convert a VT_R4 to a VT_I8. - * - * PARAMS - * fltIn [I] Source - * pi64Out [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI8FromR4(FLOAT fltIn, LONG64* pi64Out) -{ - return _VarI8FromR4(fltIn, pi64Out); -} - -/************************************************************************ - * VarI8FromR8 (OLEAUT32.336) - * - * Convert a VT_R8 to a VT_I8. - * - * PARAMS - * dblIn [I] Source - * pi64Out [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * - * NOTES - * Only values that fit into 63 bits are accepted. Due to rounding issues, - * very high or low values will not be accurately converted. - * - * Numbers are rounded using Dutch rounding, as follows: - * - *| Fractional Part Sign Direction Example - *| --------------- ---- --------- ------- - *| < 0.5 + Down 0.4 -> 0.0 - *| < 0.5 - Up -0.4 -> 0.0 - *| > 0.5 + Up 0.6 -> 1.0 - *| < 0.5 - Up -0.6 -> -1.0 - *| = 0.5 + Up/Down Down if even, Up if odd - *| = 0.5 - Up/Down Up if even, Down if odd - * - * This system is often used in supermarkets. - */ -HRESULT WINAPI VarI8FromR8(double dblIn, LONG64* pi64Out) -{ - if ( dblIn < -4611686018427387904.0 || dblIn >= 4611686018427387904.0) - return DISP_E_OVERFLOW; - OLEAUT32_DutchRound(LONG64, dblIn, *pi64Out); - return S_OK; -} - -/************************************************************************ - * VarI8FromCy (OLEAUT32.337) - * - * Convert a VT_CY to a VT_I8. - * - * PARAMS - * cyIn [I] Source - * pi64Out [O] Destination - * - * RETURNS - * S_OK. - * - * NOTES - * All negative numbers are rounded down by 1, including those that are - * evenly divisible by 10000 (this is a Win32 bug that Wine mimics). - * Positive numbers are rounded using Dutch rounding: See VarI8FromR8() - * for details. - */ -HRESULT WINAPI VarI8FromCy(CY cyIn, LONG64* pi64Out) -{ - *pi64Out = cyIn.int64 / CY_MULTIPLIER; - - if (cyIn.int64 < 0) - (*pi64Out)--; /* Mimic Win32 bug */ - else - { - cyIn.int64 -= *pi64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */ - - if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pi64Out & 0x1))) - (*pi64Out)++; - } - return S_OK; -} - -/************************************************************************ - * VarI8FromDate (OLEAUT32.338) - * - * Convert a VT_DATE to a VT_I8. - * - * PARAMS - * dateIn [I] Source - * pi64Out [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarI8FromDate(DATE dateIn, LONG64* pi64Out) -{ - return _VarI8FromDate(dateIn, pi64Out); -} - -/************************************************************************ - * VarI8FromStr (OLEAUT32.339) - * - * Convert a VT_BSTR to a VT_I8. - * - * PARAMS - * strIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pi64Out [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi64Out) -{ - return _VarI8FromStr(strIn, lcid, dwFlags, pi64Out); -} - -/************************************************************************ - * VarI8FromDisp (OLEAUT32.340) - * - * Convert a VT_DISPATCH to a VT_I8. - * - * PARAMS - * pdispIn [I] Source - * lcid [I] LCID for conversion - * pi64Out [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out) -{ - return _VarI8FromDisp(pdispIn, lcid, pi64Out); -} - -/************************************************************************ - * VarI8FromBool (OLEAUT32.341) - * - * Convert a VT_BOOL to a VT_I8. - * - * PARAMS - * boolIn [I] Source - * pi64Out [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarI8FromBool(VARIANT_BOOL boolIn, LONG64* pi64Out) -{ - return _VarI8FromBool(boolIn, pi64Out); -} - -/************************************************************************ - * VarI8FromI1 (OLEAUT32.342) - * - * Convert a VT_I1 to a VT_I8. - * - * PARAMS - * cIn [I] Source - * pi64Out [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarI8FromI1(signed char cIn, LONG64* pi64Out) -{ - return _VarI8FromI1(cIn, pi64Out); -} - -/************************************************************************ - * VarI8FromUI2 (OLEAUT32.343) - * - * Convert a VT_UI2 to a VT_I8. - * - * PARAMS - * usIn [I] Source - * pi64Out [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarI8FromUI2(USHORT usIn, LONG64* pi64Out) -{ - return _VarI8FromUI2(usIn, pi64Out); -} - -/************************************************************************ - * VarI8FromUI4 (OLEAUT32.344) - * - * Convert a VT_UI4 to a VT_I8. - * - * PARAMS - * ulIn [I] Source - * pi64Out [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarI8FromUI4(ULONG ulIn, LONG64* pi64Out) -{ - return _VarI8FromUI4(ulIn, pi64Out); -} - -/************************************************************************ - * VarI8FromDec (OLEAUT32.345) - * - * Convert a VT_DECIMAL to a VT_I8. - * - * PARAMS - * pDecIn [I] Source - * pi64Out [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI8FromDec(DECIMAL *pdecIn, LONG64* pi64Out) -{ - if (!DEC_SCALE(pdecIn)) - { - /* This decimal is just a 96 bit integer */ - if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG) - return E_INVALIDARG; - - if (DEC_HI32(pdecIn) || DEC_MID32(pdecIn) & 0x80000000) - return DISP_E_OVERFLOW; - - if (DEC_SIGN(pdecIn)) - *pi64Out = -DEC_LO64(pdecIn); - else - *pi64Out = DEC_LO64(pdecIn); - return S_OK; - } - else - { - /* Decimal contains a floating point number */ - HRESULT hRet; - double dbl; - - hRet = _VarR8FromDec(pdecIn, &dbl); - if (SUCCEEDED(hRet)) - hRet = VarI8FromR8(dbl, pi64Out); - return hRet; - } -} - -/************************************************************************ - * VarI8FromUI8 (OLEAUT32.427) - * - * Convert a VT_UI8 to a VT_I8. - * - * PARAMS - * ullIn [I] Source - * pi64Out [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarI8FromUI8(ULONG64 ullIn, LONG64* pi64Out) -{ - return _VarI8FromUI8(ullIn, pi64Out); -} - -/* UI8 - */ - -/************************************************************************ - * VarUI8FromI8 (OLEAUT32.428) - * - * Convert a VT_I8 to a VT_UI8. - * - * PARAMS - * ulIn [I] Source - * pui64Out [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI8FromI8(LONG64 llIn, ULONG64* pui64Out) -{ - return _VarUI8FromI8(llIn, pui64Out); -} - -/************************************************************************ - * VarUI8FromUI1 (OLEAUT32.429) - * - * Convert a VT_UI1 to a VT_UI8. - * - * PARAMS - * bIn [I] Source - * pui64Out [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarUI8FromUI1(BYTE bIn, ULONG64* pui64Out) -{ - return _VarUI8FromUI1(bIn, pui64Out); -} - -/************************************************************************ - * VarUI8FromI2 (OLEAUT32.430) - * - * Convert a VT_I2 to a VT_UI8. - * - * PARAMS - * sIn [I] Source - * pui64Out [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarUI8FromI2(SHORT sIn, ULONG64* pui64Out) -{ - return _VarUI8FromI2(sIn, pui64Out); -} - -/************************************************************************ - * VarUI8FromR4 (OLEAUT32.431) - * - * Convert a VT_R4 to a VT_UI8. - * - * PARAMS - * fltIn [I] Source - * pui64Out [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI8FromR4(FLOAT fltIn, ULONG64* pui64Out) -{ - return _VarUI8FromR4(fltIn, pui64Out); -} - -/************************************************************************ - * VarUI8FromR8 (OLEAUT32.432) - * - * Convert a VT_R8 to a VT_UI8. - * - * PARAMS - * dblIn [I] Source - * pui64Out [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * - * NOTES - * See VarI8FromR8() for details concerning rounding. - */ -HRESULT WINAPI VarUI8FromR8(double dblIn, ULONG64* pui64Out) -{ - if (dblIn < -0.5 || dblIn > 1.844674407370955e19) - return DISP_E_OVERFLOW; - OLEAUT32_DutchRound(ULONG64, dblIn, *pui64Out); - return S_OK; -} - -/************************************************************************ - * VarUI8FromCy (OLEAUT32.433) - * - * Convert a VT_CY to a VT_UI8. - * - * PARAMS - * cyIn [I] Source - * pui64Out [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * - * NOTES - * Negative values >= -5000 will be converted to 0. - */ -HRESULT WINAPI VarUI8FromCy(CY cyIn, ULONG64* pui64Out) -{ - if (cyIn.int64 < 0) - { - if (cyIn.int64 < -CY_HALF) - return DISP_E_OVERFLOW; - *pui64Out = 0; - } - else - { - *pui64Out = cyIn.int64 / CY_MULTIPLIER; - - cyIn.int64 -= *pui64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */ - - if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pui64Out & 0x1))) - (*pui64Out)++; - } - return S_OK; -} - -/************************************************************************ - * VarUI8FromDate (OLEAUT32.434) - * - * Convert a VT_DATE to a VT_UI8. - * - * PARAMS - * dateIn [I] Source - * pui64Out [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarUI8FromDate(DATE dateIn, ULONG64* pui64Out) -{ - return _VarUI8FromDate(dateIn, pui64Out); -} - -/************************************************************************ - * VarUI8FromStr (OLEAUT32.435) - * - * Convert a VT_BSTR to a VT_UI8. - * - * PARAMS - * strIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pui64Out [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarUI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64* pui64Out) -{ - return _VarUI8FromStr(strIn, lcid, dwFlags, pui64Out); -} - -/************************************************************************ - * VarUI8FromDisp (OLEAUT32.436) - * - * Convert a VT_DISPATCH to a VT_UI8. - * - * PARAMS - * pdispIn [I] Source - * lcid [I] LCID for conversion - * pui64Out [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out) -{ - return _VarUI8FromDisp(pdispIn, lcid, pui64Out); -} - -/************************************************************************ - * VarUI8FromBool (OLEAUT32.437) - * - * Convert a VT_BOOL to a VT_UI8. - * - * PARAMS - * boolIn [I] Source - * pui64Out [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI8FromBool(VARIANT_BOOL boolIn, ULONG64* pui64Out) -{ - return _VarUI8FromBool(boolIn, pui64Out); -} -/************************************************************************ - * VarUI8FromI1 (OLEAUT32.438) - * - * Convert a VT_I1 to a VT_UI8. - * - * PARAMS - * cIn [I] Source - * pui64Out [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarUI8FromI1(signed char cIn, ULONG64* pui64Out) -{ - return _VarUI8FromI1(cIn, pui64Out); -} - -/************************************************************************ - * VarUI8FromUI2 (OLEAUT32.439) - * - * Convert a VT_UI2 to a VT_UI8. - * - * PARAMS - * usIn [I] Source - * pui64Out [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarUI8FromUI2(USHORT usIn, ULONG64* pui64Out) -{ - return _VarUI8FromUI2(usIn, pui64Out); -} - -/************************************************************************ - * VarUI8FromUI4 (OLEAUT32.440) - * - * Convert a VT_UI4 to a VT_UI8. - * - * PARAMS - * ulIn [I] Source - * pui64Out [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarUI8FromUI4(ULONG ulIn, ULONG64* pui64Out) -{ - return _VarUI8FromUI4(ulIn, pui64Out); -} - -/************************************************************************ - * VarUI8FromDec (OLEAUT32.441) - * - * Convert a VT_DECIMAL to a VT_UI8. - * - * PARAMS - * pDecIn [I] Source - * pui64Out [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * - * NOTES - * Under native Win32, if the source value has a scale of 0, its sign is - * ignored, i.e. this function takes the absolute value rather than fail - * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation - * (use VarAbs() on pDecIn first if you really want this behaviour). - */ -HRESULT WINAPI VarUI8FromDec(DECIMAL *pdecIn, ULONG64* pui64Out) -{ - if (!DEC_SCALE(pdecIn)) - { - /* This decimal is just a 96 bit integer */ - if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG) - return E_INVALIDARG; - - if (DEC_HI32(pdecIn)) - return DISP_E_OVERFLOW; - - if (DEC_SIGN(pdecIn)) - { - WARN("Sign would be ignored under Win32!\n"); - return DISP_E_OVERFLOW; - } - - *pui64Out = DEC_LO64(pdecIn); - return S_OK; - } - else - { - /* Decimal contains a floating point number */ - HRESULT hRet; - double dbl; - - hRet = _VarR8FromDec(pdecIn, &dbl); - if (SUCCEEDED(hRet)) - hRet = VarUI8FromR8(dbl, pui64Out); - return hRet; - } -} - -/* R4 - */ - -/************************************************************************ - * VarR4FromUI1 (OLEAUT32.68) - * - * Convert a VT_UI1 to a VT_R4. - * - * PARAMS - * bIn [I] Source - * pFltOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarR4FromUI1(BYTE bIn, float *pFltOut) -{ - return _VarR4FromUI1(bIn, pFltOut); -} - -/************************************************************************ - * VarR4FromI2 (OLEAUT32.69) - * - * Convert a VT_I2 to a VT_R4. - * - * PARAMS - * sIn [I] Source - * pFltOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarR4FromI2(SHORT sIn, float *pFltOut) -{ - return _VarR4FromI2(sIn, pFltOut); -} - -/************************************************************************ - * VarR4FromI4 (OLEAUT32.70) - * - * Convert a VT_I4 to a VT_R4. - * - * PARAMS - * sIn [I] Source - * pFltOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarR4FromI4(LONG lIn, float *pFltOut) -{ - return _VarR4FromI4(lIn, pFltOut); -} - -/************************************************************************ - * VarR4FromR8 (OLEAUT32.71) - * - * Convert a VT_R8 to a VT_R4. - * - * PARAMS - * dblIn [I] Source - * pFltOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination. - */ -HRESULT WINAPI VarR4FromR8(double dblIn, float *pFltOut) -{ - return _VarR4FromR8(dblIn, pFltOut); -} - -/************************************************************************ - * VarR4FromCy (OLEAUT32.72) - * - * Convert a VT_CY to a VT_R4. - * - * PARAMS - * cyIn [I] Source - * pFltOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarR4FromCy(CY cyIn, float *pFltOut) -{ - return _VarR4FromCy(cyIn, pFltOut); -} - -/************************************************************************ - * VarR4FromDate (OLEAUT32.73) - * - * Convert a VT_DATE to a VT_R4. - * - * PARAMS - * dateIn [I] Source - * pFltOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination. - */ -HRESULT WINAPI VarR4FromDate(DATE dateIn, float *pFltOut) -{ - return _VarR4FromDate(dateIn, pFltOut); -} - -/************************************************************************ - * VarR4FromStr (OLEAUT32.74) - * - * Convert a VT_BSTR to a VT_R4. - * - * PARAMS - * strIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pFltOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if strIn or pFltOut is invalid. - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFltOut) -{ - return _VarR4FromStr(strIn, lcid, dwFlags, pFltOut); -} - -/************************************************************************ - * VarR4FromDisp (OLEAUT32.75) - * - * Convert a VT_DISPATCH to a VT_R4. - * - * PARAMS - * pdispIn [I] Source - * lcid [I] LCID for conversion - * pFltOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut) -{ - return _VarR4FromDisp(pdispIn, lcid, pFltOut); -} - -/************************************************************************ - * VarR4FromBool (OLEAUT32.76) - * - * Convert a VT_BOOL to a VT_R4. - * - * PARAMS - * boolIn [I] Source - * pFltOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut) -{ - return _VarR4FromBool(boolIn, pFltOut); -} - -/************************************************************************ - * VarR4FromI1 (OLEAUT32.213) - * - * Convert a VT_I1 to a VT_R4. - * - * PARAMS - * cIn [I] Source - * pFltOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarR4FromI1(signed char cIn, float *pFltOut) -{ - return _VarR4FromI1(cIn, pFltOut); -} - -/************************************************************************ - * VarR4FromUI2 (OLEAUT32.214) - * - * Convert a VT_UI2 to a VT_R4. - * - * PARAMS - * usIn [I] Source - * pFltOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarR4FromUI2(USHORT usIn, float *pFltOut) -{ - return _VarR4FromUI2(usIn, pFltOut); -} - -/************************************************************************ - * VarR4FromUI4 (OLEAUT32.215) - * - * Convert a VT_UI4 to a VT_R4. - * - * PARAMS - * ulIn [I] Source - * pFltOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarR4FromUI4(ULONG ulIn, float *pFltOut) -{ - return _VarR4FromUI4(ulIn, pFltOut); -} - -/************************************************************************ - * VarR4FromDec (OLEAUT32.216) - * - * Convert a VT_DECIMAL to a VT_R4. - * - * PARAMS - * pDecIn [I] Source - * pFltOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid. - */ -HRESULT WINAPI VarR4FromDec(DECIMAL* pDecIn, float *pFltOut) -{ - BYTE scale = DEC_SCALE(pDecIn); - int divisor = 1; - double highPart; - - if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG) - return E_INVALIDARG; - - while (scale--) - divisor *= 10; - - if (DEC_SIGN(pDecIn)) - divisor = -divisor; - - if (DEC_HI32(pDecIn)) - { - highPart = (double)DEC_HI32(pDecIn) / (double)divisor; - highPart *= 1.0e64; - } - else - highPart = 0.0; - - *pFltOut = (double)DEC_LO64(pDecIn) / (double)divisor + highPart; - return S_OK; -} - -/************************************************************************ - * VarR4FromI8 (OLEAUT32.360) - * - * Convert a VT_I8 to a VT_R4. - * - * PARAMS - * ullIn [I] Source - * pFltOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarR4FromI8(LONG64 llIn, float *pFltOut) -{ - return _VarR4FromI8(llIn, pFltOut); -} - -/************************************************************************ - * VarR4FromUI8 (OLEAUT32.361) - * - * Convert a VT_UI8 to a VT_R4. - * - * PARAMS - * ullIn [I] Source - * pFltOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarR4FromUI8(ULONG64 ullIn, float *pFltOut) -{ - return _VarR4FromUI8(ullIn, pFltOut); -} - -/************************************************************************ - * VarR4CmpR8 (OLEAUT32.316) - * - * Compare a VT_R4 to a VT_R8. - * - * PARAMS - * fltLeft [I] Source - * dblRight [I] Value to compare - * - * RETURNS - * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than, - * equal to or greater than dblRight respectively. - */ -HRESULT WINAPI VarR4CmpR8(float fltLeft, double dblRight) -{ - if (fltLeft < dblRight) - return VARCMP_LT; - else if (fltLeft > dblRight) - return VARCMP_GT; - return VARCMP_EQ; -} - -/* R8 - */ - -/************************************************************************ - * VarR8FromUI1 (OLEAUT32.78) - * - * Convert a VT_UI1 to a VT_R8. - * - * PARAMS - * bIn [I] Source - * pDblOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarR8FromUI1(BYTE bIn, double *pDblOut) -{ - return _VarR8FromUI1(bIn, pDblOut); -} - -/************************************************************************ - * VarR8FromI2 (OLEAUT32.79) - * - * Convert a VT_I2 to a VT_R8. - * - * PARAMS - * sIn [I] Source - * pDblOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarR8FromI2(SHORT sIn, double *pDblOut) -{ - return _VarR8FromI2(sIn, pDblOut); -} - -/************************************************************************ - * VarR8FromI4 (OLEAUT32.80) - * - * Convert a VT_I4 to a VT_R8. - * - * PARAMS - * sIn [I] Source - * pDblOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarR8FromI4(LONG lIn, double *pDblOut) -{ - return _VarR8FromI4(lIn, pDblOut); -} - -/************************************************************************ - * VarR8FromR4 (OLEAUT32.81) - * - * Convert a VT_R4 to a VT_R8. - * - * PARAMS - * fltIn [I] Source - * pDblOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double *pDblOut) -{ - return _VarR8FromR4(fltIn, pDblOut); -} - -/************************************************************************ - * VarR8FromCy (OLEAUT32.82) - * - * Convert a VT_CY to a VT_R8. - * - * PARAMS - * cyIn [I] Source - * pDblOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarR8FromCy(CY cyIn, double *pDblOut) -{ - return _VarR8FromCy(cyIn, pDblOut); -} - -/************************************************************************ - * VarR8FromDate (OLEAUT32.83) - * - * Convert a VT_DATE to a VT_R8. - * - * PARAMS - * dateIn [I] Source - * pDblOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut) -{ - return _VarR8FromDate(dateIn, pDblOut); -} - -/************************************************************************ - * VarR8FromStr (OLEAUT32.84) - * - * Convert a VT_BSTR to a VT_R8. - * - * PARAMS - * strIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pDblOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if strIn or pDblOut is invalid. - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut) -{ - return _VarR8FromStr(strIn, lcid, dwFlags, pDblOut); -} - -/************************************************************************ - * VarR8FromDisp (OLEAUT32.85) - * - * Convert a VT_DISPATCH to a VT_R8. - * - * PARAMS - * pdispIn [I] Source - * lcid [I] LCID for conversion - * pDblOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut) -{ - return _VarR8FromDisp(pdispIn, lcid, pDblOut); -} - -/************************************************************************ - * VarR8FromBool (OLEAUT32.86) - * - * Convert a VT_BOOL to a VT_R8. - * - * PARAMS - * boolIn [I] Source - * pDblOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut) -{ - return _VarR8FromBool(boolIn, pDblOut); -} - -/************************************************************************ - * VarR8FromI1 (OLEAUT32.217) - * - * Convert a VT_I1 to a VT_R8. - * - * PARAMS - * cIn [I] Source - * pDblOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut) -{ - return _VarR8FromI1(cIn, pDblOut); -} - -/************************************************************************ - * VarR8FromUI2 (OLEAUT32.218) - * - * Convert a VT_UI2 to a VT_R8. - * - * PARAMS - * usIn [I] Source - * pDblOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut) -{ - return _VarR8FromUI2(usIn, pDblOut); -} - -/************************************************************************ - * VarR8FromUI4 (OLEAUT32.219) - * - * Convert a VT_UI4 to a VT_R8. - * - * PARAMS - * ulIn [I] Source - * pDblOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut) -{ - return _VarR8FromUI4(ulIn, pDblOut); -} - -/************************************************************************ - * VarR8FromDec (OLEAUT32.220) - * - * Convert a VT_DECIMAL to a VT_R8. - * - * PARAMS - * pDecIn [I] Source - * pDblOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid. - */ -HRESULT WINAPI VarR8FromDec(DECIMAL* pDecIn, double *pDblOut) -{ - BYTE scale = DEC_SCALE(pDecIn); - double divisor = 1.0, highPart; - - if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG) - return E_INVALIDARG; - - while (scale--) - divisor *= 10; - - if (DEC_SIGN(pDecIn)) - divisor = -divisor; - - if (DEC_HI32(pDecIn)) - { - highPart = (double)DEC_HI32(pDecIn) / divisor; - highPart *= 1.0e64; - } - else - highPart = 0.0; - - *pDblOut = (double)DEC_LO64(pDecIn) / divisor + highPart; - return S_OK; -} - -/************************************************************************ - * VarR8FromI8 (OLEAUT32.362) - * - * Convert a VT_I8 to a VT_R8. - * - * PARAMS - * ullIn [I] Source - * pDblOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut) -{ - return _VarR8FromI8(llIn, pDblOut); -} - -/************************************************************************ - * VarR8FromUI8 (OLEAUT32.363) - * - * Convert a VT_UI8 to a VT_R8. - * - * PARAMS - * ullIn [I] Source - * pDblOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut) -{ - return _VarR8FromUI8(ullIn, pDblOut); -} - -/************************************************************************ - * VarR8Pow (OLEAUT32.315) - * - * Raise a VT_R8 to a power. - * - * PARAMS - * dblLeft [I] Source - * dblPow [I] Power to raise dblLeft by - * pDblOut [O] Destination - * - * RETURNS - * S_OK. pDblOut contains dblLeft to the power of dblRight. - */ -HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut) -{ - *pDblOut = pow(dblLeft, dblPow); - return S_OK; -} - -/************************************************************************ - * VarR8Round (OLEAUT32.317) - * - * Round a VT_R8 to a given number of decimal points. - * - * PARAMS - * dblIn [I] Source - * nDig [I] Number of decimal points to round to - * pDblOut [O] Destination for rounded number - * - * RETURNS - * Success: S_OK. pDblOut is rounded to nDig digits. - * Failure: E_INVALIDARG, if cDecimals is less than 0. - * - * NOTES - * The native version of this function rounds using the internal - * binary representation of the number. Wine uses the dutch rounding - * convention, so therefore small differences can occur in the value returned. - * MSDN says that you should use your own rounding function if you want - * rounding to be predictable in your application. - */ -HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut) -{ - double scale, whole, fract; - - if (nDig < 0) - return E_INVALIDARG; - - scale = pow(10.0, nDig); - - dblIn *= scale; - whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn); - fract = dblIn - whole; - - if (fract > 0.5) - dblIn = whole + 1.0; - else if (fract == 0.5) - dblIn = whole + fmod(whole, 2.0); - else if (fract >= 0.0) - dblIn = whole; - else if (fract == -0.5) - dblIn = whole - fmod(whole, 2.0); - else if (fract > -0.5) - dblIn = whole; - else - dblIn = whole - 1.0; - - *pDblOut = dblIn / scale; - return S_OK; -} - -/* CY - */ - -/* Powers of 10 from 0..4 D.P. */ -static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000, - CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER }; - -/************************************************************************ - * VarCyFromUI1 (OLEAUT32.98) - * - * Convert a VT_UI1 to a VT_CY. - * - * PARAMS - * bIn [I] Source - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut) -{ - return _VarCyFromUI1(bIn, pCyOut); -} - -/************************************************************************ - * VarCyFromI2 (OLEAUT32.99) - * - * Convert a VT_I2 to a VT_CY. - * - * PARAMS - * sIn [I] Source - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut) -{ - return _VarCyFromI2(sIn, pCyOut); -} - -/************************************************************************ - * VarCyFromI4 (OLEAUT32.100) - * - * Convert a VT_I4 to a VT_CY. - * - * PARAMS - * sIn [I] Source - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut) -{ - return _VarCyFromI4(lIn, pCyOut); -} - -/************************************************************************ - * VarCyFromR4 (OLEAUT32.101) - * - * Convert a VT_R4 to a VT_CY. - * - * PARAMS - * fltIn [I] Source - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut) -{ - return _VarCyFromR4(fltIn, pCyOut); -} - -/************************************************************************ - * VarCyFromR8 (OLEAUT32.102) - * - * Convert a VT_R8 to a VT_CY. - * - * PARAMS - * dblIn [I] Source - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut) -{ -#if defined(__GNUC__) && defined(__i386__) - /* This code gives identical results to Win32 on Intel. - * Here we use fp exceptions to catch overflows when storing the value. - */ - static const unsigned short r8_fpcontrol = 0x137f; - static const double r8_multiplier = CY_MULTIPLIER_F; - unsigned short old_fpcontrol, result_fpstatus; - - /* Clear exceptions, save the old fp state and load the new state */ - __asm__ __volatile__( "fnclex" ); - __asm__ __volatile__( "fstcw %0" : "=m" (old_fpcontrol) : ); - __asm__ __volatile__( "fldcw %0" : : "m" (r8_fpcontrol) ); - /* Perform the conversion. */ - __asm__ __volatile__( "fldl %0" : : "m" (dblIn) ); - __asm__ __volatile__( "fmull %0" : : "m" (r8_multiplier) ); - __asm__ __volatile__( "fistpll %0" : : "m" (*pCyOut) ); - /* Save the resulting fp state, load the old state and clear exceptions */ - __asm__ __volatile__( "fstsw %0" : "=m" (result_fpstatus) : ); - __asm__ __volatile__( "fnclex" ); - __asm__ __volatile__( "fldcw %0" : : "m" (old_fpcontrol) ); - - if (result_fpstatus & 0x9) /* Overflow | Invalid */ - return DISP_E_OVERFLOW; - return S_OK; -#else - /* This version produces slightly different results for boundary cases */ - if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807) - return DISP_E_OVERFLOW; - dblIn *= CY_MULTIPLIER_F; - OLEAUT32_DutchRound(LONG64, dblIn, pCyOut->int64); -#endif - return S_OK; -} - -/************************************************************************ - * VarCyFromDate (OLEAUT32.103) - * - * Convert a VT_DATE to a VT_CY. - * - * PARAMS - * dateIn [I] Source - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut) -{ - return _VarCyFromDate(dateIn, pCyOut); -} - -/************************************************************************ - * VarCyFromStr (OLEAUT32.104) - * - * Convert a VT_BSTR to a VT_CY. - * - * PARAMS - * strIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarCyFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut) -{ - return _VarCyFromStr(strIn, lcid, dwFlags, pCyOut); -} - -/************************************************************************ - * VarCyFromDisp (OLEAUT32.105) - * - * Convert a VT_DISPATCH to a VT_CY. - * - * PARAMS - * pdispIn [I] Source - * lcid [I] LCID for conversion - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut) -{ - return _VarCyFromDisp(pdispIn, lcid, pCyOut); -} - -/************************************************************************ - * VarCyFromBool (OLEAUT32.106) - * - * Convert a VT_BOOL to a VT_CY. - * - * PARAMS - * boolIn [I] Source - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - * - * NOTES - * While the sign of the boolean is stored in the currency, the value is - * converted to either 0 or 1. - */ -HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut) -{ - return _VarCyFromBool(boolIn, pCyOut); -} - -/************************************************************************ - * VarCyFromI1 (OLEAUT32.225) - * - * Convert a VT_I1 to a VT_CY. - * - * PARAMS - * cIn [I] Source - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut) -{ - return _VarCyFromI1(cIn, pCyOut); -} - -/************************************************************************ - * VarCyFromUI2 (OLEAUT32.226) - * - * Convert a VT_UI2 to a VT_CY. - * - * PARAMS - * usIn [I] Source - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut) -{ - return _VarCyFromUI2(usIn, pCyOut); -} - -/************************************************************************ - * VarCyFromUI4 (OLEAUT32.227) - * - * Convert a VT_UI4 to a VT_CY. - * - * PARAMS - * ulIn [I] Source - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut) -{ - return _VarCyFromUI4(ulIn, pCyOut); -} - -/************************************************************************ - * VarCyFromDec (OLEAUT32.228) - * - * Convert a VT_DECIMAL to a VT_CY. - * - * PARAMS - * pdecIn [I] Source - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarCyFromDec(DECIMAL* pdecIn, CY* pCyOut) -{ - DECIMAL rounded; - HRESULT hRet; - - hRet = VarDecRound(pdecIn, 4, &rounded); - - if (SUCCEEDED(hRet)) - { - double d; - - if (DEC_HI32(&rounded)) - return DISP_E_OVERFLOW; - - /* Note: Without the casts this promotes to int64 which loses precision */ - d = (double)DEC_LO64(&rounded) / (double)CY_Divisors[DEC_SCALE(&rounded)]; - if (DEC_SIGN(&rounded)) - d = -d; - return _VarCyFromR8(d, pCyOut); - } - return hRet; -} - -/************************************************************************ - * VarCyFromI8 (OLEAUT32.366) - * - * Convert a VT_I8 to a VT_CY. - * - * PARAMS - * ullIn [I] Source - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut) -{ - return _VarCyFromI8(llIn, pCyOut); -} - -/************************************************************************ - * VarCyFromUI8 (OLEAUT32.375) - * - * Convert a VT_UI8 to a VT_CY. - * - * PARAMS - * ullIn [I] Source - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut) -{ - return _VarCyFromUI8(ullIn, pCyOut); -} - -/************************************************************************ - * VarCyAdd (OLEAUT32.299) - * - * Add one CY to another. - * - * PARAMS - * cyLeft [I] Source - * cyRight [I] Value to add - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarCyAdd(const CY cyLeft, const CY cyRight, CY* pCyOut) -{ - double l,r; - _VarR8FromCy(cyLeft, &l); - _VarR8FromCy(cyRight, &r); - l = l + r; - return _VarCyFromR8(l, pCyOut); -} - -/************************************************************************ - * VarCyMul (OLEAUT32.303) - * - * Multiply one CY by another. - * - * PARAMS - * cyLeft [I] Source - * cyRight [I] Value to multiply by - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarCyMul(const CY cyLeft, const CY cyRight, CY* pCyOut) -{ - double l,r; - _VarR8FromCy(cyLeft, &l); - _VarR8FromCy(cyRight, &r); - l = l * r; - return _VarCyFromR8(l, pCyOut); -} - -/************************************************************************ - * VarCyMulI4 (OLEAUT32.304) - * - * Multiply one CY by a VT_I4. - * - * PARAMS - * cyLeft [I] Source - * lRight [I] Value to multiply by - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarCyMulI4(const CY cyLeft, LONG lRight, CY* pCyOut) -{ - double d; - - _VarR8FromCy(cyLeft, &d); - d = d * lRight; - return _VarCyFromR8(d, pCyOut); -} - -/************************************************************************ - * VarCySub (OLEAUT32.305) - * - * Subtract one CY from another. - * - * PARAMS - * cyLeft [I] Source - * cyRight [I] Value to subtract - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarCySub(const CY cyLeft, const CY cyRight, CY* pCyOut) -{ - double l,r; - _VarR8FromCy(cyLeft, &l); - _VarR8FromCy(cyRight, &r); - l = l - r; - return _VarCyFromR8(l, pCyOut); -} - -/************************************************************************ - * VarCyAbs (OLEAUT32.306) - * - * Convert a VT_CY into its absolute value. - * - * PARAMS - * cyIn [I] Source - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. pCyOut contains the absolute value. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarCyAbs(const CY cyIn, CY* pCyOut) -{ - if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo) - return DISP_E_OVERFLOW; - - pCyOut->int64 = cyIn.int64 < 0 ? -cyIn.int64 : cyIn.int64; - return S_OK; -} - -/************************************************************************ - * VarCyFix (OLEAUT32.307) - * - * Return the integer part of a VT_CY. - * - * PARAMS - * cyIn [I] Source - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - * - * NOTES - * - The difference between this function and VarCyInt() is that VarCyInt() rounds - * negative numbers away from 0, while this function rounds them towards zero. - */ -HRESULT WINAPI VarCyFix(const CY cyIn, CY* pCyOut) -{ - pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER; - pCyOut->int64 *= CY_MULTIPLIER; - return S_OK; -} - -/************************************************************************ - * VarCyInt (OLEAUT32.308) - * - * Return the integer part of a VT_CY. - * - * PARAMS - * cyIn [I] Source - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - * - * NOTES - * - The difference between this function and VarCyFix() is that VarCyFix() rounds - * negative numbers towards 0, while this function rounds them away from zero. - */ -HRESULT WINAPI VarCyInt(const CY cyIn, CY* pCyOut) -{ - pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER; - pCyOut->int64 *= CY_MULTIPLIER; - - if (cyIn.int64 < 0 && cyIn.int64 % CY_MULTIPLIER != 0) - { - pCyOut->int64 -= CY_MULTIPLIER; - } - return S_OK; -} - -/************************************************************************ - * VarCyNeg (OLEAUT32.309) - * - * Change the sign of a VT_CY. - * - * PARAMS - * cyIn [I] Source - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarCyNeg(const CY cyIn, CY* pCyOut) -{ - if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo) - return DISP_E_OVERFLOW; - - pCyOut->int64 = -cyIn.int64; - return S_OK; -} - -/************************************************************************ - * VarCyRound (OLEAUT32.310) - * - * Change the precision of a VT_CY. - * - * PARAMS - * cyIn [I] Source - * cDecimals [I] New number of decimals to keep - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if cDecimals is less than 0. - */ -HRESULT WINAPI VarCyRound(const CY cyIn, int cDecimals, CY* pCyOut) -{ - if (cDecimals < 0) - return E_INVALIDARG; - - if (cDecimals > 3) - { - /* Rounding to more precision than we have */ - *pCyOut = cyIn; - return S_OK; - } - else - { - double d, div = CY_Divisors[cDecimals]; - - _VarR8FromCy(cyIn, &d); - d = d * div; - OLEAUT32_DutchRound(LONGLONG, d, pCyOut->int64) - d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F; - OLEAUT32_DutchRound(LONGLONG, d, pCyOut->int64) - return S_OK; - } -} - -/************************************************************************ - * VarCyCmp (OLEAUT32.311) - * - * Compare two VT_CY values. - * - * PARAMS - * cyLeft [I] Source - * cyRight [I] Value to compare - * - * RETURNS - * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to - * compare is less, equal or greater than source respectively. - * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison - */ -HRESULT WINAPI VarCyCmp(const CY cyLeft, const CY cyRight) -{ - HRESULT hRet; - CY result; - - /* Subtract right from left, and compare the result to 0 */ - hRet = VarCySub(cyLeft, cyRight, &result); - - if (SUCCEEDED(hRet)) - { - if (result.int64 < 0) - hRet = (HRESULT)VARCMP_LT; - else if (result.int64 > 0) - hRet = (HRESULT)VARCMP_GT; - else - hRet = (HRESULT)VARCMP_EQ; - } - return hRet; -} - -/************************************************************************ - * VarCyCmpR8 (OLEAUT32.312) - * - * Compare a VT_CY to a double - * - * PARAMS - * cyLeft [I] Currency Source - * dblRight [I] double to compare to cyLeft - * - * RETURNS - * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is - * less than, equal to or greater than cyLeft respectively. - * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison - */ -HRESULT WINAPI VarCyCmpR8(const CY cyLeft, double dblRight) -{ - HRESULT hRet; - CY cyRight; - - hRet = _VarCyFromR8(dblRight, &cyRight); - - if (SUCCEEDED(hRet)) - hRet = VarCyCmp(cyLeft, cyRight); - - return hRet; -} - -/************************************************************************ - * VarCyMulI8 (OLEAUT32.329) - * - * Multiply a VT_CY by a VT_I8. - * - * PARAMS - * cyLeft [I] Source - * llRight [I] Value to multiply by - * pCyOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarCyMulI8(const CY cyLeft, LONG64 llRight, CY* pCyOut) -{ - double d; - - _VarR8FromCy(cyLeft, &d); - d = d * (double)llRight; - return _VarCyFromR8(d, pCyOut); -} - -/* DECIMAL - */ - -/************************************************************************ - * VarDecFromUI1 (OLEAUT32.190) - * - * Convert a VT_UI1 to a DECIMAL. - * - * PARAMS - * bIn [I] Source - * pDecOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut) -{ - return _VarDecFromUI1(bIn, pDecOut); -} - -/************************************************************************ - * VarDecFromI2 (OLEAUT32.191) - * - * Convert a VT_I2 to a DECIMAL. - * - * PARAMS - * sIn [I] Source - * pDecOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut) -{ - return _VarDecFromI2(sIn, pDecOut); -} - -/************************************************************************ - * VarDecFromI4 (OLEAUT32.192) - * - * Convert a VT_I4 to a DECIMAL. - * - * PARAMS - * sIn [I] Source - * pDecOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut) -{ - DEC_HI32(pDecOut) = 0; - DEC_MID32(pDecOut) = 0; - - if (lIn < 0) - { - DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0); - DEC_LO32(pDecOut) = -lIn; - } - else - { - DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); - DEC_LO32(pDecOut) = lIn; - } - return S_OK; -} - -#define LOCALE_EN_US (MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT)) - -/************************************************************************ - * VarDecFromR4 (OLEAUT32.193) - * - * Convert a VT_R4 to a DECIMAL. - * - * PARAMS - * fltIn [I] Source - * pDecOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut) -{ - WCHAR buff[256]; - - sprintfW( buff, szFloatFormatW, fltIn ); - return _VarDecFromStr(buff, LOCALE_EN_US, 0, pDecOut); -} - -/************************************************************************ - * VarDecFromR8 (OLEAUT32.194) - * - * Convert a VT_R8 to a DECIMAL. - * - * PARAMS - * dblIn [I] Source - * pDecOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut) -{ - WCHAR buff[256]; - - sprintfW( buff, szDoubleFormatW, dblIn ); - return _VarDecFromStr(buff, LOCALE_EN_US, 0, pDecOut); -} - -/************************************************************************ - * VarDecFromDate (OLEAUT32.195) - * - * Convert a VT_DATE to a DECIMAL. - * - * PARAMS - * dateIn [I] Source - * pDecOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut) -{ - return _VarDecFromDate(dateIn, pDecOut); -} - -/************************************************************************ - * VarDecFromCy (OLEAUT32.196) - * - * Convert a VT_CY to a DECIMAL. - * - * PARAMS - * cyIn [I] Source - * pDecOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut) -{ - DEC_HI32(pDecOut) = 0; - - /* Note: This assumes 2s complement integer representation */ - if (cyIn.s.Hi & 0x80000000) - { - DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,4); - DEC_LO64(pDecOut) = -cyIn.int64; - } - else - { - DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,4); - DEC_MID32(pDecOut) = cyIn.s.Hi; - DEC_LO32(pDecOut) = cyIn.s.Lo; - } - return S_OK; -} - -/************************************************************************ - * VarDecFromStr (OLEAUT32.197) - * - * Convert a VT_BSTR to a DECIMAL. - * - * PARAMS - * strIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pDecOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut) -{ - return _VarDecFromStr(strIn, lcid, dwFlags, pDecOut); -} - -/************************************************************************ - * VarDecFromDisp (OLEAUT32.198) - * - * Convert a VT_DISPATCH to a DECIMAL. - * - * PARAMS - * pdispIn [I] Source - * lcid [I] LCID for conversion - * pDecOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut) -{ - return _VarDecFromDisp(pdispIn, lcid, pDecOut); -} - -/************************************************************************ - * VarDecFromBool (OLEAUT32.199) - * - * Convert a VT_BOOL to a DECIMAL. - * - * PARAMS - * bIn [I] Source - * pDecOut [O] Destination - * - * RETURNS - * S_OK. - * - * NOTES - * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE). - */ -HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut) -{ - DEC_HI32(pDecOut) = 0; - DEC_MID32(pDecOut) = 0; - if (bIn) - { - DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0); - DEC_LO32(pDecOut) = 1; - } - else - { - DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); - DEC_LO32(pDecOut) = 0; - } - return S_OK; -} - -/************************************************************************ - * VarDecFromI1 (OLEAUT32.241) - * - * Convert a VT_I1 to a DECIMAL. - * - * PARAMS - * cIn [I] Source - * pDecOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut) -{ - return _VarDecFromI1(cIn, pDecOut); -} - -/************************************************************************ - * VarDecFromUI2 (OLEAUT32.242) - * - * Convert a VT_UI2 to a DECIMAL. - * - * PARAMS - * usIn [I] Source - * pDecOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut) -{ - return _VarDecFromUI2(usIn, pDecOut); -} - -/************************************************************************ - * VarDecFromUI4 (OLEAUT32.243) - * - * Convert a VT_UI4 to a DECIMAL. - * - * PARAMS - * ulIn [I] Source - * pDecOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut) -{ - DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); - DEC_HI32(pDecOut) = 0; - DEC_MID32(pDecOut) = 0; - DEC_LO32(pDecOut) = ulIn; - return S_OK; -} - -/************************************************************************ - * VarDecFromI8 (OLEAUT32.374) - * - * Convert a VT_I8 to a DECIMAL. - * - * PARAMS - * llIn [I] Source - * pDecOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut) -{ - PULARGE_INTEGER pLi = (PULARGE_INTEGER)&llIn; - - DEC_HI32(pDecOut) = 0; - - /* Note: This assumes 2s complement integer representation */ - if (pLi->u.HighPart & 0x80000000) - { - DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0); - DEC_LO64(pDecOut) = -pLi->QuadPart; - } - else - { - DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); - DEC_MID32(pDecOut) = pLi->u.HighPart; - DEC_LO32(pDecOut) = pLi->u.LowPart; - } - return S_OK; -} - -/************************************************************************ - * VarDecFromUI8 (OLEAUT32.375) - * - * Convert a VT_UI8 to a DECIMAL. - * - * PARAMS - * ullIn [I] Source - * pDecOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut) -{ - DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); - DEC_HI32(pDecOut) = 0; - DEC_LO64(pDecOut) = ullIn; - return S_OK; -} - -/* Make two DECIMALS the same scale; used by math functions below */ -static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft, - const DECIMAL** ppDecRight, - DECIMAL* pDecOut) -{ - static DECIMAL scaleFactor; - DECIMAL decTemp; - int scaleAmount, i; - HRESULT hRet = S_OK; - - if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG) - return E_INVALIDARG; - - DEC_LO32(&scaleFactor) = 10; - - i = scaleAmount = DEC_SCALE(*ppDecLeft) - DEC_SCALE(*ppDecRight); - - if (!scaleAmount) - return S_OK; /* Same scale */ - - if (scaleAmount > 0) - { - decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */ - *ppDecRight = pDecOut; - } - else - { - decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */ - *ppDecLeft = pDecOut; - i = scaleAmount = -scaleAmount; - } - - if (DEC_SCALE(&decTemp) + scaleAmount > DEC_MAX_SCALE) - return DISP_E_OVERFLOW; /* Can't scale up */ - - /* Multiply up the value to be scaled by the correct amount */ - while (SUCCEEDED(hRet) && i--) - { - /* Note we are multiplying by a value with a scale of 0, so we don't recurse */ - hRet = VarDecMul(&decTemp, &scaleFactor, pDecOut); - decTemp = *pDecOut; - } - DEC_SCALE(pDecOut) += scaleAmount; /* Set the new scale */ - return hRet; -} - -/* Add two unsigned 32 bit values with overflow */ -static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh) -{ - ULARGE_INTEGER ul64; - - ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh; - *pulHigh = ul64.u.HighPart; - return ul64.u.LowPart; -} - -/* Subtract two unsigned 32 bit values with underflow */ -static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh) -{ - int invert = 0; - ULARGE_INTEGER ul64; - - ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight; - if (ulLeft < ulRight) - invert = 1; - - if (ul64.QuadPart > (ULONG64)*pulHigh) - ul64.QuadPart -= (ULONG64)*pulHigh; - else - { - ul64.QuadPart -= (ULONG64)*pulHigh; - invert = 1; - } - if (invert) - ul64.u.HighPart = -ul64.u.HighPart ; - - *pulHigh = ul64.u.HighPart; - return ul64.u.LowPart; -} - -/* Multiply two unsigned 32 bit values with overflow */ -static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh) -{ - ULARGE_INTEGER ul64; - - ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh; - *pulHigh = ul64.u.HighPart; - return ul64.u.LowPart; -} - -/* Compare two decimals that have the same scale */ -static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight) -{ - if ( DEC_HI32(pDecLeft) < DEC_HI32(pDecRight) || - (DEC_HI32(pDecLeft) <= DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) < DEC_LO64(pDecRight))) - return -1; - else if (DEC_HI32(pDecLeft) == DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) == DEC_LO64(pDecRight)) - return 0; - return 1; -} - -/************************************************************************ - * VarDecAdd (OLEAUT32.177) - * - * Add one DECIMAL to another. - * - * PARAMS - * pDecLeft [I] Source - * pDecRight [I] Value to add - * pDecOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) -{ - HRESULT hRet; - DECIMAL scaled; - - hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, &scaled); - - if (SUCCEEDED(hRet)) - { - /* Our decimals now have the same scale, we can add them as 96 bit integers */ - ULONG overflow = 0; - BYTE sign = DECIMAL_POS; - - /* Correct for the sign of the result */ - if (DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight)) - { - /* -x + -y : Negative */ - sign = DECIMAL_NEG; - goto VarDecAdd_AsPositive; - } - else if (DEC_SIGN(pDecLeft) && !DEC_SIGN(pDecRight)) - { - int cmp = VARIANT_DecCmp(pDecLeft, pDecRight); - - /* -x + y : Negative if x > y */ - if (cmp > 0) - { - sign = DECIMAL_NEG; -VarDecAdd_AsNegative: - DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow); - DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow); - DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow); - } - else - { -VarDecAdd_AsInvertedNegative: - DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecRight), DEC_LO32(pDecLeft), &overflow); - DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecRight), DEC_MID32(pDecLeft), &overflow); - DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecRight), DEC_HI32(pDecLeft), &overflow); - } - } - else if (!DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight)) - { - int cmp = VARIANT_DecCmp(pDecLeft, pDecRight); - - /* x + -y : Negative if x <= y */ - if (cmp <= 0) - { - sign = DECIMAL_NEG; - goto VarDecAdd_AsInvertedNegative; - } - goto VarDecAdd_AsNegative; - } - else - { - /* x + y : Positive */ -VarDecAdd_AsPositive: - DEC_LO32(pDecOut) = VARIANT_Add(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow); - DEC_MID32(pDecOut) = VARIANT_Add(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow); - DEC_HI32(pDecOut) = VARIANT_Add(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow); - } - - if (overflow) - return DISP_E_OVERFLOW; /* overflowed */ - - DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft); - DEC_SIGN(pDecOut) = sign; - } - return hRet; -} - -/************************************************************************ - * VarDecDiv (OLEAUT32.178) - * - * Divide one DECIMAL by another. - * - * PARAMS - * pDecLeft [I] Source - * pDecRight [I] Value to divide by - * pDecOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) -{ - FIXME("(%p,%p,%p)-stub!\n",pDecLeft,pDecRight,pDecOut); - return DISP_E_OVERFLOW; -} - -/************************************************************************ - * VarDecMul (OLEAUT32.179) - * - * Multiply one DECIMAL by another. - * - * PARAMS - * pDecLeft [I] Source - * pDecRight [I] Value to multiply by - * pDecOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) -{ - /* FIXME: This only allows multiplying by a fixed integer <= 0xffffffff */ - - if (!DEC_SCALE(pDecLeft) || !DEC_SCALE(pDecRight)) - { - /* At least one term is an integer */ - const DECIMAL* pDecInteger = DEC_SCALE(pDecLeft) ? pDecRight : pDecLeft; - const DECIMAL* pDecOperand = DEC_SCALE(pDecLeft) ? pDecLeft : pDecRight; - HRESULT hRet = S_OK; - unsigned int multiplier = DEC_LO32(pDecInteger); - ULONG overflow = 0; - - if (DEC_HI32(pDecInteger) || DEC_MID32(pDecInteger)) - { - FIXME("(%p,%p,%p) semi-stub!\n",pDecLeft,pDecRight,pDecOut); - return DISP_E_OVERFLOW; - } - - DEC_LO32(pDecOut) = VARIANT_Mul(DEC_LO32(pDecOperand), multiplier, &overflow); - DEC_MID32(pDecOut) = VARIANT_Mul(DEC_MID32(pDecOperand), multiplier, &overflow); - DEC_HI32(pDecOut) = VARIANT_Mul(DEC_HI32(pDecOperand), multiplier, &overflow); - - if (overflow) - hRet = DISP_E_OVERFLOW; - else - { - BYTE sign = DECIMAL_POS; - - if (DEC_SIGN(pDecLeft) != DEC_SIGN(pDecRight)) - sign = DECIMAL_NEG; /* pos * neg => negative */ - DEC_SIGN(pDecOut) = sign; - DEC_SCALE(pDecOut) = DEC_SCALE(pDecOperand); - } - return hRet; - } - FIXME("(%p,%p,%p) semi-stub!\n",pDecLeft,pDecRight,pDecOut); - return DISP_E_OVERFLOW; -} - -/************************************************************************ - * VarDecSub (OLEAUT32.181) - * - * Subtract one DECIMAL from another. - * - * PARAMS - * pDecLeft [I] Source - * pDecRight [I] DECIMAL to subtract from pDecLeft - * pDecOut [O] Destination - * - * RETURNS - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) -{ - DECIMAL decRight; - - /* Implement as addition of the negative */ - VarDecNeg(pDecRight, &decRight); - return VarDecAdd(pDecLeft, &decRight, pDecOut); -} - -/************************************************************************ - * VarDecAbs (OLEAUT32.182) - * - * Convert a DECIMAL into its absolute value. - * - * PARAMS - * pDecIn [I] Source - * pDecOut [O] Destination - * - * RETURNS - * S_OK. This function does not fail. - */ -HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut) -{ - *pDecOut = *pDecIn; - DEC_SIGN(pDecOut) &= ~DECIMAL_NEG; - return S_OK; -} - -/************************************************************************ - * VarDecFix (OLEAUT32.187) - * - * Return the integer portion of a DECIMAL. - * - * PARAMS - * pDecIn [I] Source - * pDecOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - * - * NOTES - * - The difference between this function and VarDecInt() is that VarDecInt() rounds - * negative numbers away from 0, while this function rounds them towards zero. - */ -HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut) -{ - if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) - return E_INVALIDARG; - - if (!DEC_SCALE(pDecIn)) - { - *pDecOut = *pDecIn; /* Already an integer */ - return S_OK; - } - - FIXME("semi-stub!\n"); - return DISP_E_OVERFLOW; -} - -/************************************************************************ - * VarDecInt (OLEAUT32.188) - * - * Return the integer portion of a DECIMAL. - * - * PARAMS - * pDecIn [I] Source - * pDecOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - * - * NOTES - * - The difference between this function and VarDecFix() is that VarDecFix() rounds - * negative numbers towards 0, while this function rounds them away from zero. - */ -HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut) -{ - if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) - return E_INVALIDARG; - - if (!(DEC_SIGN(pDecIn) & DECIMAL_NEG) || !DEC_SCALE(pDecIn)) - return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */ - - FIXME("semi-stub!\n"); - return DISP_E_OVERFLOW; -} - -/************************************************************************ - * VarDecNeg (OLEAUT32.189) - * - * Change the sign of a DECIMAL. - * - * PARAMS - * pDecIn [I] Source - * pDecOut [O] Destination - * - * RETURNS - * S_OK. This function does not fail. - */ -HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut) -{ - *pDecOut = *pDecIn; - DEC_SIGN(pDecOut) ^= DECIMAL_NEG; - return S_OK; -} - -/************************************************************************ - * VarDecRound (OLEAUT32.203) - * - * Change the precision of a DECIMAL. - * - * PARAMS - * pDecIn [I] Source - * cDecimals [I] New number of decimals to keep - * pDecOut [O] Destination - * - * RETURNS - * Success: S_OK. pDecOut contains the rounded value. - * Failure: E_INVALIDARG if any argument is invalid. - */ -HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut) -{ - if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE) - return E_INVALIDARG; - - if (cDecimals >= DEC_SCALE(pDecIn)) - { - *pDecOut = *pDecIn; /* More precision than we have */ - return S_OK; - } - - FIXME("semi-stub!\n"); - - return DISP_E_OVERFLOW; -} - -/************************************************************************ - * VarDecCmp (OLEAUT32.204) - * - * Compare two DECIMAL values. - * - * PARAMS - * pDecLeft [I] Source - * pDecRight [I] Value to compare - * - * RETURNS - * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft - * is less than, equal to or greater than pDecRight respectively. - * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison - */ -HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight) -{ - HRESULT hRet; - DECIMAL result; - - /* Subtract right from left, and compare the result to 0 */ - hRet = VarDecSub(pDecLeft, pDecRight, &result); - - if (SUCCEEDED(hRet)) - { - int non_zero = DEC_HI32(&result) | DEC_MID32(&result) | DEC_LO32(&result); - - if ((DEC_SIGN(&result) & DECIMAL_NEG) && non_zero) - hRet = (HRESULT)VARCMP_LT; - else if (non_zero) - hRet = (HRESULT)VARCMP_GT; - else - hRet = (HRESULT)VARCMP_EQ; - } - return hRet; -} - -/************************************************************************ - * VarDecCmpR8 (OLEAUT32.298) - * - * Compare a DECIMAL to a double - * - * PARAMS - * pDecLeft [I] DECIMAL Source - * dblRight [I] double to compare to pDecLeft - * - * RETURNS - * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight - * is less than, equal to or greater than pDecLeft respectively. - * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison - */ -HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight) -{ - HRESULT hRet; - DECIMAL decRight; - - hRet = VarDecFromR8(dblRight, &decRight); - - if (SUCCEEDED(hRet)) - hRet = VarDecCmp(pDecLeft, &decRight); - - return hRet; -} - -/* BOOL - */ - -/************************************************************************ - * VarBoolFromUI1 (OLEAUT32.118) - * - * Convert a VT_UI1 to a VT_BOOL. - * - * PARAMS - * bIn [I] Source - * pBoolOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut) -{ - return _VarBoolFromUI1(bIn, pBoolOut); -} - -/************************************************************************ - * VarBoolFromI2 (OLEAUT32.119) - * - * Convert a VT_I2 to a VT_BOOL. - * - * PARAMS - * sIn [I] Source - * pBoolOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut) -{ - return _VarBoolFromI2(sIn, pBoolOut); -} - -/************************************************************************ - * VarBoolFromI4 (OLEAUT32.120) - * - * Convert a VT_I4 to a VT_BOOL. - * - * PARAMS - * sIn [I] Source - * pBoolOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut) -{ - return _VarBoolFromI4(lIn, pBoolOut); -} - -/************************************************************************ - * VarBoolFromR4 (OLEAUT32.121) - * - * Convert a VT_R4 to a VT_BOOL. - * - * PARAMS - * fltIn [I] Source - * pBoolOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut) -{ - return _VarBoolFromR4(fltIn, pBoolOut); -} - -/************************************************************************ - * VarBoolFromR8 (OLEAUT32.122) - * - * Convert a VT_R8 to a VT_BOOL. - * - * PARAMS - * dblIn [I] Source - * pBoolOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut) -{ - return _VarBoolFromR8(dblIn, pBoolOut); -} - -/************************************************************************ - * VarBoolFromDate (OLEAUT32.123) - * - * Convert a VT_DATE to a VT_BOOL. - * - * PARAMS - * dateIn [I] Source - * pBoolOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut) -{ - return _VarBoolFromDate(dateIn, pBoolOut); -} - -/************************************************************************ - * VarBoolFromCy (OLEAUT32.124) - * - * Convert a VT_CY to a VT_BOOL. - * - * PARAMS - * cyIn [I] Source - * pBoolOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut) -{ - return _VarBoolFromCy(cyIn, pBoolOut); -} - -static BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest) -{ - HRSRC hrsrc; - - hrsrc = FindResourceExW( OLEAUT32_hModule, (LPWSTR)RT_STRING, - (LPCWSTR)((dwId >> 4) + 1), langId ); - if (hrsrc) - { - HGLOBAL hmem = LoadResource( OLEAUT32_hModule, hrsrc ); - - if (hmem) - { - const WCHAR *p; - unsigned int i; - - p = LockResource( hmem ); - for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1; - - memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) ); - lpszDest[*p] = '\0'; - TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId); - return TRUE; - } - } - return FALSE; -} - -/************************************************************************ - * VarBoolFromStr (OLEAUT32.125) - * - * Convert a VT_BSTR to a VT_BOOL. - * - * PARAMS - * strIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pBoolOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if pBoolOut is invalid. - * DISP_E_TYPEMISMATCH, if the type cannot be converted - * - * NOTES - * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally, - * it may contain (in any case mapping) the text "true" or "false". - * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the - * localised text of "True" or "False" in the language specified by lcid. - * - If none of these matches occur, the string is treated as a numeric string - * and the boolean pBoolOut will be set according to whether the number is zero - * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion. - * - If the text is not numeric and does not match any of the above, then - * DISP_E_TYPEMISMATCH is returned. - */ -HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut) -{ - /* Any VB/VBA programmers out there should recognise these strings... */ - static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' }; - static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' }; - WCHAR szBuff[64]; - LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); - HRESULT hRes = S_OK; - - if (!strIn || !pBoolOut) - return DISP_E_TYPEMISMATCH; - - /* Check if we should be comparing against localised text */ - if (dwFlags & VAR_LOCALBOOL) - { - /* Convert our LCID into a usable value */ - lcid = ConvertDefaultLocale(lcid); - - langId = LANGIDFROMLCID(lcid); - - if (PRIMARYLANGID(langId) == LANG_NEUTRAL) - langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); - - /* Note: Native oleaut32 always copies strIn and maps halfwidth characters. - * I don't think this is needed unless any of the localised text strings - * contain characters that can be so mapped. In the event that this is - * true for a given language (possibly some Asian languages), then strIn - * should be mapped here _only_ if langId is an Id for which this can occur. - */ - } - - /* Note that if we are not comparing against localised strings, langId - * will have its default value of LANG_ENGLISH. This allows us to mimic - * the native behaviour of always checking against English strings even - * after we've checked for localised ones. - */ -VarBoolFromStr_CheckLocalised: - if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff)) - { - /* Compare against localised strings, ignoring case */ - if (!strcmpiW(strIn, szBuff)) - { - *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */ - return hRes; - } - VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff); - if (!strcmpiW(strIn, szBuff)) - { - *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */ - return hRes; - } - } - - if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT)) - { - /* We have checked the localised text, now check English */ - langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); - goto VarBoolFromStr_CheckLocalised; - } - - /* All checks against localised text have failed, try #TRUE#/#FALSE# */ - if (!strcmpW(strIn, szFalse)) - *pBoolOut = VARIANT_FALSE; - else if (!strcmpW(strIn, szTrue)) - *pBoolOut = VARIANT_TRUE; - else - { - double d; - - /* If this string is a number, convert it as one */ - hRes = _VarR8FromStr(strIn, lcid, dwFlags, &d); - if (SUCCEEDED(hRes)) - hRes = _VarBoolFromR8(d, pBoolOut); - } - return hRes; -} - -/************************************************************************ - * VarBoolFromDisp (OLEAUT32.126) - * - * Convert a VT_DISPATCH to a VT_BOOL. - * - * PARAMS - * pdispIn [I] Source - * lcid [I] LCID for conversion - * pBoolOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut) -{ - return _VarBoolFromDisp(pdispIn, lcid, pBoolOut); -} - -/************************************************************************ - * VarBoolFromI1 (OLEAUT32.233) - * - * Convert a VT_I1 to a VT_BOOL. - * - * PARAMS - * cIn [I] Source - * pBoolOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut) -{ - return _VarBoolFromI1(cIn, pBoolOut); -} - -/************************************************************************ - * VarBoolFromUI2 (OLEAUT32.234) - * - * Convert a VT_UI2 to a VT_BOOL. - * - * PARAMS - * usIn [I] Source - * pBoolOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut) -{ - return _VarBoolFromUI2(usIn, pBoolOut); -} - -/************************************************************************ - * VarBoolFromUI4 (OLEAUT32.235) - * - * Convert a VT_UI4 to a VT_BOOL. - * - * PARAMS - * ulIn [I] Source - * pBoolOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut) -{ - return _VarBoolFromUI4(ulIn, pBoolOut); -} - -/************************************************************************ - * VarBoolFromDec (OLEAUT32.236) - * - * Convert a VT_DECIMAL to a VT_BOOL. - * - * PARAMS - * pDecIn [I] Source - * pBoolOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if pDecIn is invalid. - */ -HRESULT WINAPI VarBoolFromDec(DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut) -{ - if (DEC_SCALE(pDecIn) > DEC_MAX_SCALE || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)) - return E_INVALIDARG; - - if (DEC_HI32(pDecIn) || DEC_MID32(pDecIn) || DEC_LO32(pDecIn)) - *pBoolOut = VARIANT_TRUE; - else - *pBoolOut = VARIANT_FALSE; - return S_OK; -} - -/************************************************************************ - * VarBoolFromI8 (OLEAUT32.370) - * - * Convert a VT_I8 to a VT_BOOL. - * - * PARAMS - * ullIn [I] Source - * pBoolOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut) -{ - return _VarBoolFromI8(llIn, pBoolOut); -} - -/************************************************************************ - * VarBoolFromUI8 (OLEAUT32.371) - * - * Convert a VT_UI8 to a VT_BOOL. - * - * PARAMS - * ullIn [I] Source - * pBoolOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut) -{ - return _VarBoolFromUI8(ullIn, pBoolOut); -} - -/* BSTR - */ - -/* Write a number from a UI8 and sign */ -static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut) -{ - do - { - WCHAR ulNextDigit = ulVal % 10; - - *szOut-- = '0' + ulNextDigit; - ulVal = (ulVal - ulNextDigit) / 10; - } while (ulVal); - - szOut++; - return szOut; -} - -/* Create a (possibly localised) BSTR from a UI8 and sign */ -static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut) -{ - WCHAR szConverted[256]; - - if (dwFlags & VAR_NEGATIVE) - *--szOut = '-'; - - if (dwFlags & LOCALE_USE_NLS) - { - /* Format the number for the locale */ - szConverted[0] = '\0'; - GetNumberFormatW(lcid, - dwFlags & LOCALE_NOUSEROVERRIDE, - szOut, NULL, szConverted, sizeof(szConverted)/sizeof(WCHAR)); - szOut = szConverted; - } - return SysAllocStringByteLen((LPCSTR)szOut, strlenW(szOut) * sizeof(WCHAR)); -} - -/* Create a (possibly localised) BSTR from a UI8 and sign */ -static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut) -{ - WCHAR szBuff[64], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1; - - if (!pbstrOut) - return E_INVALIDARG; - - /* Create the basic number string */ - *szOut-- = '\0'; - szOut = VARIANT_WriteNumber(ulVal, szOut); - - *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut); - TRACE("returning %s\n", debugstr_w(*pbstrOut)); - return *pbstrOut ? S_OK : E_OUTOFMEMORY; -} - -/****************************************************************************** - * VarBstrFromUI1 (OLEAUT32.108) - * - * Convert a VT_UI1 to a VT_BSTR. - * - * PARAMS - * bIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pbstrOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if pbstrOut is invalid. - * E_OUTOFMEMORY, if memory allocation fails. - */ -HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) -{ - return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut); -} - -/****************************************************************************** - * VarBstrFromI2 (OLEAUT32.109) - * - * Convert a VT_I2 to a VT_BSTR. - * - * PARAMS - * sIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pbstrOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if pbstrOut is invalid. - * E_OUTOFMEMORY, if memory allocation fails. - */ -HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) -{ - ULONG64 ul64 = sIn; - - if (sIn < 0) - { - ul64 = -sIn; - dwFlags |= VAR_NEGATIVE; - } - return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut); -} - -/****************************************************************************** - * VarBstrFromI4 (OLEAUT32.110) - * - * Convert a VT_I4 to a VT_BSTR. - * - * PARAMS - * lIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pbstrOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if pbstrOut is invalid. - * E_OUTOFMEMORY, if memory allocation fails. - */ -HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) -{ - ULONG64 ul64 = lIn; - - if (lIn < 0) - { - ul64 = (ULONG)-lIn; - dwFlags |= VAR_NEGATIVE; - } - return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut); -} - -static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags, - BSTR* pbstrOut, LPCWSTR lpszFormat) -{ - WCHAR buff[256]; - - if (!pbstrOut) - return E_INVALIDARG; - - sprintfW( buff, lpszFormat, dblIn ); - TRACE("created string %s\n", debugstr_w(buff)); - if (dwFlags & LOCALE_USE_NLS) - { - WCHAR numbuff[256]; - - /* Format the number for the locale */ - numbuff[0] = '\0'; - GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE, - buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR)); - TRACE("created NLS string %s\n", debugstr_w(numbuff)); - *pbstrOut = SysAllocString(numbuff); - } - else - *pbstrOut = SysAllocString(buff); - return *pbstrOut ? S_OK : E_OUTOFMEMORY; -} - -/****************************************************************************** - * VarBstrFromR4 (OLEAUT32.111) - * - * Convert a VT_R4 to a VT_BSTR. - * - * PARAMS - * fltIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pbstrOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if pbstrOut is invalid. - * E_OUTOFMEMORY, if memory allocation fails. - */ -HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) -{ - return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, szFloatFormatW); -} - -/****************************************************************************** - * VarBstrFromR8 (OLEAUT32.112) - * - * Convert a VT_R8 to a VT_BSTR. - * - * PARAMS - * dblIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pbstrOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if pbstrOut is invalid. - * E_OUTOFMEMORY, if memory allocation fails. - */ -HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) -{ - return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, szDoubleFormatW); -} - -/****************************************************************************** - * VarBstrFromCy [OLEAUT32.113] - * - * Convert a VT_CY to a VT_BSTR. - * - * PARAMS - * cyIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pbstrOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if pbstrOut is invalid. - * E_OUTOFMEMORY, if memory allocation fails. - */ -HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) -{ - WCHAR buff[256]; - double dblVal; - - if (!pbstrOut) - return E_INVALIDARG; - - VarR8FromCy(cyIn, &dblVal); - sprintfW(buff, szDoubleFormatW, dblVal); - - if (dwFlags & LOCALE_USE_NLS) - { - WCHAR cybuff[256]; - - /* Format the currency for the locale */ - cybuff[0] = '\0'; - GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE, - buff, NULL, cybuff, sizeof(cybuff) / sizeof(WCHAR)); - *pbstrOut = SysAllocString(cybuff); - } - else - *pbstrOut = SysAllocString(buff); - - return *pbstrOut ? S_OK : E_OUTOFMEMORY; -} - -/****************************************************************************** - * VarBstrFromDate [OLEAUT32.114] - * - * Convert a VT_DATE to a VT_BSTR. - * - * PARAMS - * dateIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pbstrOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid. - * E_OUTOFMEMORY, if memory allocation fails. - */ -HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) -{ - SYSTEMTIME st; - DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE; - WCHAR date[128], *time; - - TRACE("(%g,0x%08lx,0x%08lx,%p)\n", dateIn, lcid, dwFlags, pbstrOut); - - if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st)) - return E_INVALIDARG; - - *pbstrOut = NULL; - - if (dwFlags & VAR_CALENDAR_THAI) - st.wYear += 553; /* Use the Thai buddhist calendar year */ - else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN)) - FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n"); - - if (dwFlags & LOCALE_USE_NLS) - dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY); - else - { - double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn); - double partial = dateIn - whole; - - if (whole == 0.0) - dwFlags |= VAR_TIMEVALUEONLY; - else if (partial < 1e-12) - dwFlags |= VAR_DATEVALUEONLY; - } - - if (dwFlags & VAR_TIMEVALUEONLY) - date[0] = '\0'; - else - if (!GetDateFormatW(lcid, dwFormatFlags|DATE_SHORTDATE, &st, NULL, date, - sizeof(date)/sizeof(WCHAR))) - return E_INVALIDARG; - - if (!(dwFlags & VAR_DATEVALUEONLY)) - { - time = date + strlenW(date); - if (time != date) - *time++ = ' '; - if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time, - sizeof(date)/sizeof(WCHAR)-(time-date))) - return E_INVALIDARG; - } - - *pbstrOut = SysAllocString(date); - if (*pbstrOut) - TRACE("returning %s\n", debugstr_w(*pbstrOut)); - return *pbstrOut ? S_OK : E_OUTOFMEMORY; -} - -/****************************************************************************** - * VarBstrFromBool (OLEAUT32.116) - * - * Convert a VT_BOOL to a VT_BSTR. - * - * PARAMS - * boolIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pbstrOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if pbstrOut is invalid. - * E_OUTOFMEMORY, if memory allocation fails. - * - * NOTES - * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the - * localised text of "True" or "False". To convert a bool into a - * numeric string of "0" or "-1", use VariantChangeTypeTypeEx(). - */ -HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) -{ - WCHAR szBuff[64]; - DWORD dwResId = IDS_TRUE; - LANGID langId; - - TRACE("%d,0x%08lx,0x%08lx,%p\n", boolIn, lcid, dwFlags, pbstrOut); - - if (!pbstrOut) - return E_INVALIDARG; - - /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used - * for variant formatting */ - switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO)) - { - case VAR_BOOLONOFF: - dwResId = IDS_ON; - break; - case VAR_BOOLYESNO: - dwResId = IDS_YES; - break; - case VAR_LOCALBOOL: - break; - default: - lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT); - } - - lcid = ConvertDefaultLocale(lcid); - langId = LANGIDFROMLCID(lcid); - if (PRIMARYLANGID(langId) == LANG_NEUTRAL) - langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); - - if (boolIn == VARIANT_FALSE) - dwResId++; /* Use negative form */ - -VarBstrFromBool_GetLocalised: - if (VARIANT_GetLocalisedText(langId, dwResId, szBuff)) - { - *pbstrOut = SysAllocString(szBuff); - return *pbstrOut ? S_OK : E_OUTOFMEMORY; - } - - if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT)) - { - langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); - goto VarBstrFromBool_GetLocalised; - } - - /* Should never get here */ - WARN("Failed to load bool text!\n"); - return E_OUTOFMEMORY; -} - -/****************************************************************************** - * VarBstrFromI1 (OLEAUT32.229) - * - * Convert a VT_I1 to a VT_BSTR. - * - * PARAMS - * cIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pbstrOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if pbstrOut is invalid. - * E_OUTOFMEMORY, if memory allocation fails. - */ -HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) -{ - ULONG64 ul64 = cIn; - - if (cIn < 0) - { - ul64 = -cIn; - dwFlags |= VAR_NEGATIVE; - } - return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut); -} - -/****************************************************************************** - * VarBstrFromUI2 (OLEAUT32.230) - * - * Convert a VT_UI2 to a VT_BSTR. - * - * PARAMS - * usIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pbstrOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if pbstrOut is invalid. - * E_OUTOFMEMORY, if memory allocation fails. - */ -HRESULT WINAPI VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) -{ - return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut); -} - -/****************************************************************************** - * VarBstrFromUI4 (OLEAUT32.231) - * - * Convert a VT_UI4 to a VT_BSTR. - * - * PARAMS - * ulIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pbstrOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if pbstrOut is invalid. - * E_OUTOFMEMORY, if memory allocation fails. - */ -HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) -{ - return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut); -} - -/****************************************************************************** - * VarBstrFromDec (OLEAUT32.232) - * - * Convert a VT_DECIMAL to a VT_BSTR. - * - * PARAMS - * pDecIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pbstrOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if pbstrOut is invalid. - * E_OUTOFMEMORY, if memory allocation fails. - */ -HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) -{ - if (!pbstrOut) - return E_INVALIDARG; - - if (!DEC_SCALE(pDecIn) && !DEC_HI32(pDecIn)) - { - WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1; - - /* Create the basic number string */ - *szOut-- = '\0'; - szOut = VARIANT_WriteNumber(DEC_LO64(pDecIn), szOut); - if (DEC_SIGN(pDecIn)) - dwFlags |= VAR_NEGATIVE; - - *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut); - TRACE("returning %s\n", debugstr_w(*pbstrOut)); - return *pbstrOut ? S_OK : E_OUTOFMEMORY; - } - FIXME("semi-stub\n"); - return E_INVALIDARG; -} - -/************************************************************************ - * VarBstrFromI8 (OLEAUT32.370) - * - * Convert a VT_I8 to a VT_BSTR. - * - * PARAMS - * llIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pbstrOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if pbstrOut is invalid. - * E_OUTOFMEMORY, if memory allocation fails. - */ -HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) -{ - ULONG64 ul64 = llIn; - - if (llIn < 0) - { - ul64 = -llIn; - dwFlags |= VAR_NEGATIVE; - } - return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut); -} - -/************************************************************************ - * VarBstrFromUI8 (OLEAUT32.371) - * - * Convert a VT_UI8 to a VT_BSTR. - * - * PARAMS - * ullIn [I] Source - * lcid [I] LCID for the conversion - * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") - * pbstrOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if pbstrOut is invalid. - * E_OUTOFMEMORY, if memory allocation fails. - */ -HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) -{ - return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut); -} - -/********************************************************************** - * VarBstrCat (OLEAUT32.313) - * - * Concatenate two BSTR values. - * - * PARAMS - * pbstrLeft [I] Source - * pbstrRight [I] Value to concatenate - * pbstrOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if pbstrOut is invalid. - * E_OUTOFMEMORY, if memory allocation fails. - */ -HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut) -{ - unsigned int len; - - if (!pbstrOut) - return E_INVALIDARG; - - len = pbstrLeft ? strlenW(pbstrLeft) : 0; - if (pbstrRight) - len += strlenW(pbstrRight); - - *pbstrOut = SysAllocStringLen(NULL, len); - if (!*pbstrOut) - return E_OUTOFMEMORY; - - (*pbstrOut)[0] = '\0'; - - if (pbstrLeft) - strcpyW(*pbstrOut, pbstrLeft); - - if (pbstrRight) - strcatW(*pbstrOut, pbstrRight); - - return S_OK; -} - -/********************************************************************** - * VarBstrCmp (OLEAUT32.314) - * - * Compare two BSTR values. - * - * PARAMS - * pbstrLeft [I] Source - * pbstrRight [I] Value to compare - * lcid [I] LCID for the comparison - * dwFlags [I] Flags to pass directly to CompareStringW(). - * - * RETURNS - * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less - * than, equal to or greater than pbstrRight respectively. - * VARCMP_NULL is returned if either string is NULL, unless both are NULL - * in which case VARCMP_EQ is returned. - */ -HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags) -{ - if (!pbstrLeft) - { - if (!pbstrRight || !*pbstrRight) - return VARCMP_EQ; - return VARCMP_NULL; - } - else if (!pbstrRight) - { - if (!*pbstrLeft) - return VARCMP_EQ; - return VARCMP_NULL; - } - - return CompareStringW(lcid, dwFlags, pbstrLeft, -1, pbstrRight, -1) - 1; -} - -/* - * DATE - */ - -/****************************************************************************** - * VarDateFromUI1 (OLEAUT32.88) - * - * Convert a VT_UI1 to a VT_DATE. - * - * PARAMS - * bIn [I] Source - * pdateOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut) -{ - return _VarDateFromUI1(bIn, pdateOut); -} - -/****************************************************************************** - * VarDateFromI2 (OLEAUT32.89) - * - * Convert a VT_I2 to a VT_DATE. - * - * PARAMS - * sIn [I] Source - * pdateOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut) -{ - return _VarDateFromI2(sIn, pdateOut); -} - -/****************************************************************************** - * VarDateFromI4 (OLEAUT32.90) - * - * Convert a VT_I4 to a VT_DATE. - * - * PARAMS - * lIn [I] Source - * pdateOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut) -{ - return _VarDateFromI4(lIn, pdateOut); -} - -/****************************************************************************** - * VarDateFromR4 (OLEAUT32.91) - * - * Convert a VT_R4 to a VT_DATE. - * - * PARAMS - * fltIn [I] Source - * pdateOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut) -{ - return _VarDateFromR4(fltIn, pdateOut); -} - -/****************************************************************************** - * VarDateFromR8 (OLEAUT32.92) - * - * Convert a VT_R8 to a VT_DATE. - * - * PARAMS - * dblIn [I] Source - * pdateOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut) -{ - return _VarDateFromR8(dblIn, pdateOut); -} - -/********************************************************************** - * VarDateFromDisp (OLEAUT32.95) - * - * Convert a VT_DISPATCH to a VT_DATE. - * - * PARAMS - * pdispIn [I] Source - * lcid [I] LCID for conversion - * pdateOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if the source value is invalid - * DISP_E_OVERFLOW, if the value will not fit in the destination - * DISP_E_TYPEMISMATCH, if the type cannot be converted - */ -HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut) -{ - return _VarDateFromDisp(pdispIn, lcid, pdateOut); -} - -/****************************************************************************** - * VarDateFromBool (OLEAUT32.96) - * - * Convert a VT_BOOL to a VT_DATE. - * - * PARAMS - * boolIn [I] Source - * pdateOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut) -{ - return _VarDateFromBool(boolIn, pdateOut); -} - -/********************************************************************** - * VarDateFromCy (OLEAUT32.93) - * - * Convert a VT_CY to a VT_DATE. - * - * PARAMS - * lIn [I] Source - * pdateOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) -{ - return _VarDateFromCy(cyIn, pdateOut); -} - -/* Date string parsing */ -#define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */ -#define DP_DATESEP 0x02 /* Date separator */ -#define DP_MONTH 0x04 /* Month name */ -#define DP_AM 0x08 /* AM */ -#define DP_PM 0x10 /* PM */ - -typedef struct tagDATEPARSE -{ - DWORD dwCount; /* Number of fields found so far (maximum 6) */ - DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */ - DWORD dwFlags[6]; /* Flags for each field */ - DWORD dwValues[6]; /* Value of each field */ -} DATEPARSE; - -#define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i) - -#define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0))) - -/* Determine if a day is valid in a given month of a given year */ -static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year) -{ - static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - - if (day && month && month < 13) - { - if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year))) - return TRUE; - } - return FALSE; -} - -/* Possible orders for 3 numbers making up a date */ -#define ORDER_MDY 0x01 -#define ORDER_YMD 0x02 -#define ORDER_YDM 0x04 -#define ORDER_DMY 0x08 -#define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */ - -/* Determine a date for a particular locale, from 3 numbers */ -static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate, - DWORD offset, SYSTEMTIME *st) -{ - DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3; - - if (!dp->dwCount) - { - v1 = 30; /* Default to (Variant) 0 date part */ - v2 = 12; - v3 = 1899; - goto VARIANT_MakeDate_OK; - } - - v1 = dp->dwValues[offset + 0]; - v2 = dp->dwValues[offset + 1]; - if (dp->dwCount == 2) - { - SYSTEMTIME current; - GetSystemTime(¤t); - v3 = current.wYear; - } - else - v3 = dp->dwValues[offset + 2]; - - TRACE("(%ld,%ld,%ld,%ld,%ld)\n", v1, v2, v3, iDate, offset); - - /* If one number must be a month (Because a month name was given), then only - * consider orders with the month in that position. - * If we took the current year as 'v3', then only allow a year in that position. - */ - if (dp->dwFlags[offset + 0] & DP_MONTH) - { - dwAllOrders = ORDER_MDY; - } - else if (dp->dwFlags[offset + 1] & DP_MONTH) - { - dwAllOrders = ORDER_DMY; - if (dp->dwCount > 2) - dwAllOrders |= ORDER_YMD; - } - else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH) - { - dwAllOrders = ORDER_YDM; - } - else - { - dwAllOrders = ORDER_MDY|ORDER_DMY; - if (dp->dwCount > 2) - dwAllOrders |= (ORDER_YMD|ORDER_YDM); - } - -VARIANT_MakeDate_Start: - TRACE("dwAllOrders is 0x%08lx\n", dwAllOrders); - - while (dwAllOrders) - { - DWORD dwTemp; - - if (dwCount == 0) - { - /* First: Try the order given by iDate */ - switch (iDate) - { - case 0: dwTry = dwAllOrders & ORDER_MDY; break; - case 1: dwTry = dwAllOrders & ORDER_DMY; break; - default: dwTry = dwAllOrders & ORDER_YMD; break; - } - } - else if (dwCount == 1) - { - /* Second: Try all the orders compatible with iDate */ - switch (iDate) - { - case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break; - case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YMD|ORDER_MYD); break; - default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break; - } - } - else - { - /* Finally: Try any remaining orders */ - dwTry = dwAllOrders; - } - - TRACE("Attempt %ld, dwTry is 0x%08lx\n", dwCount, dwTry); - - dwCount++; - if (!dwTry) - continue; - -#define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0) - - if (dwTry & ORDER_MDY) - { - if (VARIANT_IsValidMonthDay(v2,v1,v3)) - { - DATE_SWAP(v1,v2); - goto VARIANT_MakeDate_OK; - } - dwAllOrders &= ~ORDER_MDY; - } - if (dwTry & ORDER_YMD) - { - if (VARIANT_IsValidMonthDay(v3,v2,v1)) - { - DATE_SWAP(v1,v3); - goto VARIANT_MakeDate_OK; - } - dwAllOrders &= ~ORDER_YMD; - } - if (dwTry & ORDER_YDM) - { - if (VARIANT_IsValidMonthDay(v2,v3,v1)) - { - DATE_SWAP(v1,v2); - DATE_SWAP(v2,v3); - goto VARIANT_MakeDate_OK; - } - dwAllOrders &= ~ORDER_YDM; - } - if (dwTry & ORDER_DMY) - { - if (VARIANT_IsValidMonthDay(v1,v2,v3)) - goto VARIANT_MakeDate_OK; - dwAllOrders &= ~ORDER_DMY; - } - if (dwTry & ORDER_MYD) - { - /* Only occurs if we are trying a 2 year date as M/Y not D/M */ - if (VARIANT_IsValidMonthDay(v3,v1,v2)) - { - DATE_SWAP(v1,v3); - DATE_SWAP(v2,v3); - goto VARIANT_MakeDate_OK; - } - dwAllOrders &= ~ORDER_MYD; - } - } - - if (dp->dwCount == 2) - { - /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */ - v3 = 1; /* 1st of the month */ - dwAllOrders = ORDER_YMD|ORDER_MYD; - dp->dwCount = 0; /* Don't return to this code path again */ - dwCount = 0; - goto VARIANT_MakeDate_Start; - } - - /* No valid dates were able to be constructed */ - return DISP_E_TYPEMISMATCH; - -VARIANT_MakeDate_OK: - - /* Check that the time part is ok */ - if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59) - return DISP_E_TYPEMISMATCH; - - TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond); - if (st->wHour < 12 && (dp->dwParseFlags & DP_PM)) - st->wHour += 12; - else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM)) - st->wHour = 0; - TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond); - - st->wDay = v1; - st->wMonth = v2; - /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may - * be retrieved from: - * HKCU\Control Panel\International\Calendars\TwoDigitYearMax - * But Wine doesn't have/use that key as at the time of writing. - */ - st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3; - TRACE("Returning date %ld/%ld/%d\n", v1, v2, st->wYear); - return S_OK; -} - -/****************************************************************************** - * VarDateFromStr [OLEAUT32.94] - * - * Convert a VT_BSTR to at VT_DATE. - * - * PARAMS - * strIn [I] String to convert - * lcid [I] Locale identifier for the conversion - * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h") - * pdateOut [O] Destination for the converted value - * - * RETURNS - * Success: S_OK. pdateOut contains the converted value. - * FAILURE: An HRESULT error code indicating the prolem. - * - * NOTES - * Any date format that can be created using the date formats from lcid - * (Either from kernel Nls functions, variant conversion or formatting) is a - * valid input to this function. In addition, a few more esoteric formats are - * also supported for compatibility with the native version. The date is - * interpreted according to the date settings in the control panel, unless - * the date is invalid in that format, in which the most compatible format - * that produces a valid date will be used. - */ -HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut) -{ - static const USHORT ParseDateTokens[] = - { - LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4, - LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, - LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12, - LOCALE_SMONTHNAME13, - LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3, - LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6, - LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9, - LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12, - LOCALE_SABBREVMONTHNAME13, - LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4, - LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7, - LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, - LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6, - LOCALE_SABBREVDAYNAME7, - LOCALE_S1159, LOCALE_S2359 - }; - static const BYTE ParseDateMonths[] = - { - 1,2,3,4,5,6,7,8,9,10,11,12,13, - 1,2,3,4,5,6,7,8,9,10,11,12,13 - }; - size_t i; - BSTR tokens[sizeof(ParseDateTokens)/sizeof(ParseDateTokens[0])]; - DATEPARSE dp; - DWORD dwDateSeps = 0, iDate = 0; - HRESULT hRet = S_OK; - - if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) == - (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) - return E_INVALIDARG; - - if (!strIn) - return DISP_E_TYPEMISMATCH; - - *pdateOut = 0.0; - - TRACE("(%s,0x%08lx,0x%08lx,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut); - - memset(&dp, 0, sizeof(dp)); - - GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE), - (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR)); - TRACE("iDate is %ld\n", iDate); - - /* Get the month/day/am/pm tokens for this locale */ - for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++) - { - WCHAR buff[128]; - LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE); - - /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or - * GetAltMonthNames(). We should really cache these strings too. - */ - buff[0] = '\0'; - GetLocaleInfoW(lcid, lctype, buff, sizeof(buff)/sizeof(WCHAR)); - tokens[i] = SysAllocString(buff); - TRACE("token %d is %s\n", i, debugstr_w(tokens[i])); - } - - /* Parse the string into our structure */ - while (*strIn) - { - if (dp.dwCount > 6) - break; - - if (isdigitW(*strIn)) - { - dp.dwValues[dp.dwCount] = strtoulW(strIn, &strIn, 10); - dp.dwCount++; - strIn--; - } - else if (isalpha(*strIn)) - { - BOOL bFound = FALSE; - - for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++) - { - DWORD dwLen = strlenW(tokens[i]); - if (dwLen && !strncmpiW(strIn, tokens[i], dwLen)) - { - if (i <= 25) - { - dp.dwValues[dp.dwCount] = ParseDateMonths[i]; - dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP); - dp.dwCount++; - } - else if (i > 39) - { - if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM)) - hRet = DISP_E_TYPEMISMATCH; - else - { - dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM); - dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM); - } - } - strIn += (dwLen - 1); - bFound = TRUE; - break; - } - } - - if (!bFound) - { - if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') && - (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM)))) - { - /* Special case - 'a' and 'p' are recognised as short for am/pm */ - if (*strIn == 'a' || *strIn == 'A') - { - dp.dwFlags[dp.dwCount - 1] |= DP_AM; - dp.dwParseFlags |= DP_AM; - } - else - { - dp.dwFlags[dp.dwCount - 1] |= DP_PM; - dp.dwParseFlags |= DP_PM; - } - strIn++; - } - else - { - TRACE("No matching token for %s\n", debugstr_w(strIn)); - hRet = DISP_E_TYPEMISMATCH; - break; - } - } - } - else if (*strIn == ':' || *strIn == '.') - { - if (!dp.dwCount || !strIn[1]) - hRet = DISP_E_TYPEMISMATCH; - else - dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP; - } - else if (*strIn == '-' || *strIn == '/') - { - dwDateSeps++; - if (dwDateSeps > 2 || !dp.dwCount || !strIn[1]) - hRet = DISP_E_TYPEMISMATCH; - else - dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP; - } - else if (*strIn == ',' || isspaceW(*strIn)) - { - if (*strIn == ',' && !strIn[1]) - hRet = DISP_E_TYPEMISMATCH; - } - else - { - hRet = DISP_E_TYPEMISMATCH; - } - strIn++; - } - - if (!dp.dwCount || dp.dwCount > 6 || - (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM)))) - hRet = DISP_E_TYPEMISMATCH; - - if (SUCCEEDED(hRet)) - { - SYSTEMTIME st; - DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */ - - st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0; - - /* Figure out which numbers correspond to which fields. - * - * This switch statement works based on the fact that native interprets any - * fields that are not joined with a time separator ('.' or ':') as date - * fields. Thus we construct a value from 0-32 where each set bit indicates - * a time field. This encapsulates the hundreds of permutations of 2-6 fields. - * For valid permutations, we set dwOffset to point to the first date field - * and shorten dp.dwCount by the number of time fields found. The real - * magic here occurs in VARIANT_MakeDate() above, where we determine what - * each date number must represent in the context of iDate. - */ - TRACE("0x%08lx\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4)); - - switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4)) - { - case 0x1: /* TT TTDD TTDDD */ - if (dp.dwCount > 3 && - ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) || - (dp.dwFlags[4] & (DP_AM|DP_PM)))) - hRet = DISP_E_TYPEMISMATCH; - else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5) - hRet = DISP_E_TYPEMISMATCH; - st.wHour = dp.dwValues[0]; - st.wMinute = dp.dwValues[1]; - dp.dwCount -= 2; - dwOffset = 2; - break; - - case 0x3: /* TTT TTTDD TTTDDD */ - if (dp.dwCount > 4 && - ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) || - (dp.dwFlags[5] & (DP_AM|DP_PM)))) - hRet = DISP_E_TYPEMISMATCH; - else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6) - hRet = DISP_E_TYPEMISMATCH; - st.wHour = dp.dwValues[0]; - st.wMinute = dp.dwValues[1]; - st.wSecond = dp.dwValues[2]; - dwOffset = 3; - dp.dwCount -= 3; - break; - - case 0x4: /* DDTT */ - if (dp.dwCount != 4 || - (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM))) - hRet = DISP_E_TYPEMISMATCH; - - st.wHour = dp.dwValues[2]; - st.wMinute = dp.dwValues[3]; - dp.dwCount -= 2; - break; - - case 0x0: /* T DD DDD TDDD TDDD */ - if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM))) - { - st.wHour = dp.dwValues[0]; /* T */ - dp.dwCount = 0; - break; - } - else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM))) - { - hRet = DISP_E_TYPEMISMATCH; - } - else if (dp.dwCount == 3) - { - if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */ - { - dp.dwCount = 2; - st.wHour = dp.dwValues[0]; - dwOffset = 1; - break; - } - if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */ - { - dp.dwCount = 2; - st.wHour = dp.dwValues[2]; - break; - } - else if (dp.dwParseFlags & (DP_AM|DP_PM)) - hRet = DISP_E_TYPEMISMATCH; - } - else if (dp.dwCount == 4) - { - dp.dwCount = 3; - if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */ - { - st.wHour = dp.dwValues[0]; - dwOffset = 1; - } - else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */ - { - st.wHour = dp.dwValues[3]; - } - else - hRet = DISP_E_TYPEMISMATCH; - break; - } - /* .. fall through .. */ - - case 0x8: /* DDDTT */ - if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) || - (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) || - (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) || - dp.dwCount == 4 || dp.dwCount == 6) - hRet = DISP_E_TYPEMISMATCH; - st.wHour = dp.dwValues[3]; - st.wMinute = dp.dwValues[4]; - if (dp.dwCount == 5) - dp.dwCount -= 2; - break; - - case 0xC: /* DDTTT */ - if (dp.dwCount != 5 || - (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM))) - hRet = DISP_E_TYPEMISMATCH; - st.wHour = dp.dwValues[2]; - st.wMinute = dp.dwValues[3]; - st.wSecond = dp.dwValues[4]; - dp.dwCount -= 3; - break; - - case 0x18: /* DDDTTT */ - if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) || - (dp.dwFlags[2] & (DP_AM|DP_PM))) - hRet = DISP_E_TYPEMISMATCH; - st.wHour = dp.dwValues[3]; - st.wMinute = dp.dwValues[4]; - st.wSecond = dp.dwValues[5]; - dp.dwCount -= 3; - break; - - default: - hRet = DISP_E_TYPEMISMATCH; - break; - } - - if (SUCCEEDED(hRet)) - { - hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st); - - if (dwFlags & VAR_TIMEVALUEONLY) - { - st.wYear = 1899; - st.wMonth = 12; - st.wDay = 30; - } - else if (dwFlags & VAR_DATEVALUEONLY) - st.wHour = st.wMinute = st.wSecond = 0; - - /* Finally, convert the value to a VT_DATE */ - if (SUCCEEDED(hRet)) - hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH; - } - } - - for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++) - SysFreeString(tokens[i]); - return hRet; -} - -/****************************************************************************** - * VarDateFromI1 (OLEAUT32.221) - * - * Convert a VT_I1 to a VT_DATE. - * - * PARAMS - * cIn [I] Source - * pdateOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut) -{ - return _VarDateFromI1(cIn, pdateOut); -} - -/****************************************************************************** - * VarDateFromUI2 (OLEAUT32.222) - * - * Convert a VT_UI2 to a VT_DATE. - * - * PARAMS - * uiIn [I] Source - * pdateOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut) -{ - return _VarDateFromUI2(uiIn, pdateOut); -} - -/****************************************************************************** - * VarDateFromUI4 (OLEAUT32.223) - * - * Convert a VT_UI4 to a VT_DATE. - * - * PARAMS - * ulIn [I] Source - * pdateOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut) -{ - return _VarDateFromUI4(ulIn, pdateOut); -} - -/********************************************************************** - * VarDateFromDec (OLEAUT32.224) - * - * Convert a VT_DECIMAL to a VT_DATE. - * - * PARAMS - * pdecIn [I] Source - * pdateOut [O] Destination - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut) -{ - return _VarDateFromDec(pdecIn, pdateOut); -} - -/****************************************************************************** - * VarDateFromI8 (OLEAUT32.364) - * - * Convert a VT_I8 to a VT_DATE. - * - * PARAMS - * llIn [I] Source - * pdateOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut) -{ - return _VarDateFromI8(llIn, pdateOut); -} - -/****************************************************************************** - * VarDateFromUI8 (OLEAUT32.365) - * - * Convert a VT_UI8 to a VT_DATE. - * - * PARAMS - * ullIn [I] Source - * pdateOut [O] Destination - * - * RETURNS - * Success: S_OK. - * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination - */ -HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut) -{ - return _VarDateFromUI8(ullIn, pdateOut); -} +/* + * Low level variant functions + * + * Copyright 2003 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "wine/debug.h" +#include "wine/unicode.h" +#include "winbase.h" +#include "winuser.h" +#include "winnt.h" +#include "variant.h" +#include "resource.h" + +WINE_DEFAULT_DEBUG_CHANNEL(variant); + +extern HMODULE OLEAUT32_hModule; + +static const WCHAR szFloatFormatW[] = { '%','.','7','G','\0' }; +static const WCHAR szDoubleFormatW[] = { '%','.','1','5','G','\0' }; + +/* Copy data from one variant to another. */ +static inline void VARIANT_CopyData(const VARIANT *srcVar, VARTYPE vt, void *pOut) +{ + switch (vt) + { + case VT_I1: + case VT_UI1: memcpy(pOut, &V_UI1(srcVar), sizeof(BYTE)); break; + case VT_BOOL: + case VT_I2: + case VT_UI2: memcpy(pOut, &V_UI2(srcVar), sizeof(SHORT)); break; + case VT_R4: + case VT_INT: + case VT_I4: + case VT_UINT: + case VT_UI4: memcpy(pOut, &V_UI4(srcVar), sizeof (LONG)); break; + case VT_R8: + case VT_DATE: + case VT_CY: + case VT_I8: + case VT_UI8: memcpy(pOut, &V_UI8(srcVar), sizeof (LONG64)); break; + case VT_INT_PTR: memcpy(pOut, &V_INT_PTR(srcVar), sizeof (INT_PTR)); break; + case VT_DECIMAL: memcpy(pOut, &V_DECIMAL(srcVar), sizeof (DECIMAL)); break; + default: + FIXME("VT_ type %d unhandled, please report!\n", vt); + } +} + + +/* Coerce VT_BSTR to a numeric type */ +HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags, + void* pOut, VARTYPE vt) +{ + VARIANTARG dstVar; + HRESULT hRet; + NUMPARSE np; + BYTE rgb[1024]; + + /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */ + np.cDig = sizeof(rgb) / sizeof(BYTE); + np.dwInFlags = NUMPRS_STD; + + hRet = VarParseNumFromStr(pStrIn, lcid, ulFlags, &np, rgb); + + if (SUCCEEDED(hRet)) + { + /* 1 << vt gives us the VTBIT constant for the destination number type */ + hRet = VarNumFromParseNum(&np, rgb, 1 << vt, &dstVar); + if (SUCCEEDED(hRet)) + VARIANT_CopyData(&dstVar, vt, pOut); + } + return hRet; +} + +/* Coerce VT_DISPATCH to another type */ +HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut, VARTYPE vt) +{ + static const DISPPARAMS emptyParams = { NULL, NULL, 0, 0 }; + VARIANTARG srcVar, dstVar; + HRESULT hRet; + + if (!pdispIn) + return DISP_E_BADVARTYPE; + + /* Get the default 'value' property from the IDispatch */ + hRet = IDispatch_Invoke(pdispIn, DISPID_VALUE, &IID_NULL, lcid, DISPATCH_PROPERTYGET, + (DISPPARAMS*)&emptyParams, &srcVar, NULL, NULL); + + if (SUCCEEDED(hRet)) + { + /* Convert the property to the requested type */ + V_VT(&dstVar) = VT_EMPTY; + hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, 0, vt); + VariantClear(&srcVar); + + if (SUCCEEDED(hRet)) + { + VARIANT_CopyData(&dstVar, vt, pOut); + VariantClear(&srcVar); + } + } + else + hRet = DISP_E_TYPEMISMATCH; + return hRet; +} + +/* I1 + */ + +/************************************************************************ + * VarI1FromUI1 (OLEAUT32.244) + * + * Convert a VT_UI1 to a VT_I1. + * + * PARAMS + * bIn [I] Source + * pcOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char* pcOut) +{ + return _VarI1FromUI1(bIn, pcOut); +} + +/************************************************************************ + * VarI1FromI2 (OLEAUT32.245) + * + * Convert a VT_I2 to a VT_I1. + * + * PARAMS + * sIn [I] Source + * pcOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI1FromI2(SHORT sIn, signed char* pcOut) +{ + return _VarI1FromI2(sIn, pcOut); +} + +/************************************************************************ + * VarI1FromI4 (OLEAUT32.246) + * + * Convert a VT_I4 to a VT_I1. + * + * PARAMS + * iIn [I] Source + * pcOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI1FromI4(LONG iIn, signed char* pcOut) +{ + return _VarI1FromI4(iIn, pcOut); +} + +/************************************************************************ + * VarI1FromR4 (OLEAUT32.247) + * + * Convert a VT_R4 to a VT_I1. + * + * PARAMS + * fltIn [I] Source + * pcOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char* pcOut) +{ + return _VarI1FromR4(fltIn, pcOut); +} + +/************************************************************************ + * VarI1FromR8 (OLEAUT32.248) + * + * Convert a VT_R8 to a VT_I1. + * + * PARAMS + * dblIn [I] Source + * pcOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * + * NOTES + * See VarI8FromR8() for details concerning rounding. + */ +HRESULT WINAPI VarI1FromR8(double dblIn, signed char* pcOut) +{ + if (dblIn < (double)I1_MIN || dblIn > (double)I1_MAX) + return DISP_E_OVERFLOW; + OLEAUT32_DutchRound(CHAR, dblIn, *pcOut); + return S_OK; +} + +/************************************************************************ + * VarI1FromDate (OLEAUT32.249) + * + * Convert a VT_DATE to a VT_I1. + * + * PARAMS + * dateIn [I] Source + * pcOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char* pcOut) +{ + return _VarI1FromDate(dateIn, pcOut); +} + +/************************************************************************ + * VarI1FromCy (OLEAUT32.250) + * + * Convert a VT_CY to a VT_I1. + * + * PARAMS + * cyIn [I] Source + * pcOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI1FromCy(CY cyIn, signed char* pcOut) +{ + LONG i = I1_MAX + 1; + + _VarI4FromCy(cyIn, &i); + return _VarI1FromI4(i, pcOut); +} + +/************************************************************************ + * VarI1FromStr (OLEAUT32.251) + * + * Convert a VT_BSTR to a VT_I1. + * + * PARAMS + * strIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pcOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char* pcOut) +{ + return _VarI1FromStr(strIn, lcid, dwFlags, pcOut); +} + +/************************************************************************ + * VarI1FromDisp (OLEAUT32.252) + * + * Convert a VT_DISPATCH to a VT_I1. + * + * PARAMS + * pdispIn [I] Source + * lcid [I] LCID for conversion + * pcOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarI1FromDisp(IDispatch* pdispIn, LCID lcid, signed char* pcOut) +{ + return _VarI1FromDisp(pdispIn, lcid, pcOut); +} + +/************************************************************************ + * VarI1FromBool (OLEAUT32.253) + * + * Convert a VT_BOOL to a VT_I1. + * + * PARAMS + * boolIn [I] Source + * pcOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char* pcOut) +{ + return _VarI1FromBool(boolIn, pcOut); +} + +/************************************************************************ + * VarI1FromUI2 (OLEAUT32.254) + * + * Convert a VT_UI2 to a VT_I1. + * + * PARAMS + * usIn [I] Source + * pcOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI1FromUI2(USHORT usIn, signed char* pcOut) +{ + return _VarI1FromUI2(usIn, pcOut); +} + +/************************************************************************ + * VarI1FromUI4 (OLEAUT32.255) + * + * Convert a VT_UI4 to a VT_I1. + * + * PARAMS + * ulIn [I] Source + * pcOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char* pcOut) +{ + return _VarI1FromUI4(ulIn, pcOut); +} + +/************************************************************************ + * VarI1FromDec (OLEAUT32.256) + * + * Convert a VT_DECIMAL to a VT_I1. + * + * PARAMS + * pDecIn [I] Source + * pcOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI1FromDec(DECIMAL *pdecIn, signed char* pcOut) +{ + LONG64 i64; + HRESULT hRet; + + hRet = _VarI8FromDec(pdecIn, &i64); + + if (SUCCEEDED(hRet)) + hRet = _VarI1FromI8(i64, pcOut); + return hRet; +} + +/************************************************************************ + * VarI1FromI8 (OLEAUT32.376) + * + * Convert a VT_I8 to a VT_I1. + * + * PARAMS + * llIn [I] Source + * pcOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI1FromI8(LONG64 llIn, signed char* pcOut) +{ + return _VarI1FromI8(llIn, pcOut); +} + +/************************************************************************ + * VarI1FromUI8 (OLEAUT32.377) + * + * Convert a VT_UI8 to a VT_I1. + * + * PARAMS + * ullIn [I] Source + * pcOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI1FromUI8(ULONG64 ullIn, signed char* pcOut) +{ + return _VarI1FromUI8(ullIn, pcOut); +} + +/* UI1 + */ + +/************************************************************************ + * VarUI1FromI2 (OLEAUT32.130) + * + * Convert a VT_I2 to a VT_UI1. + * + * PARAMS + * sIn [I] Source + * pbOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI1FromI2(SHORT sIn, BYTE* pbOut) +{ + return _VarUI1FromI2(sIn, pbOut); +} + +/************************************************************************ + * VarUI1FromI4 (OLEAUT32.131) + * + * Convert a VT_I4 to a VT_UI1. + * + * PARAMS + * iIn [I] Source + * pbOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI1FromI4(LONG iIn, BYTE* pbOut) +{ + return _VarUI1FromI4(iIn, pbOut); +} + +/************************************************************************ + * VarUI1FromR4 (OLEAUT32.132) + * + * Convert a VT_R4 to a VT_UI1. + * + * PARAMS + * fltIn [I] Source + * pbOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut) +{ + return _VarUI1FromR4(fltIn, pbOut); +} + +/************************************************************************ + * VarUI1FromR8 (OLEAUT32.133) + * + * Convert a VT_R8 to a VT_UI1. + * + * PARAMS + * dblIn [I] Source + * pbOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * + * NOTES + * See VarI8FromR8() for details concerning rounding. + */ +HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut) +{ + if (dblIn < -0.5 || dblIn > (double)UI1_MAX) + return DISP_E_OVERFLOW; + OLEAUT32_DutchRound(BYTE, dblIn, *pbOut); + return S_OK; +} + +/************************************************************************ + * VarUI1FromCy (OLEAUT32.134) + * + * Convert a VT_CY to a VT_UI1. + * + * PARAMS + * cyIn [I] Source + * pbOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * + * NOTES + * Negative values >= -5000 will be converted to 0. + */ +HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) +{ + ULONG i = UI1_MAX + 1; + + _VarUI4FromCy(cyIn, &i); + return _VarUI1FromUI4(i, pbOut); +} + +/************************************************************************ + * VarUI1FromDate (OLEAUT32.135) + * + * Convert a VT_DATE to a VT_UI1. + * + * PARAMS + * dateIn [I] Source + * pbOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut) +{ + return _VarUI1FromDate(dateIn, pbOut); +} + +/************************************************************************ + * VarUI1FromStr (OLEAUT32.136) + * + * Convert a VT_BSTR to a VT_UI1. + * + * PARAMS + * strIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pbOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut) +{ + return _VarUI1FromStr(strIn, lcid, dwFlags, pbOut); +} + +/************************************************************************ + * VarUI1FromDisp (OLEAUT32.137) + * + * Convert a VT_DISPATCH to a VT_UI1. + * + * PARAMS + * pdispIn [I] Source + * lcid [I] LCID for conversion + * pbOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarUI1FromDisp(IDispatch* pdispIn, LCID lcid, BYTE* pbOut) +{ + return _VarUI1FromDisp(pdispIn, lcid, pbOut); +} + +/************************************************************************ + * VarUI1FromBool (OLEAUT32.138) + * + * Convert a VT_BOOL to a VT_UI1. + * + * PARAMS + * boolIn [I] Source + * pbOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut) +{ + return _VarUI1FromBool(boolIn, pbOut); +} + +/************************************************************************ + * VarUI1FromI1 (OLEAUT32.237) + * + * Convert a VT_I1 to a VT_UI1. + * + * PARAMS + * cIn [I] Source + * pbOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut) +{ + return _VarUI1FromI1(cIn, pbOut); +} + +/************************************************************************ + * VarUI1FromUI2 (OLEAUT32.238) + * + * Convert a VT_UI2 to a VT_UI1. + * + * PARAMS + * usIn [I] Source + * pbOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI1FromUI2(USHORT usIn, BYTE* pbOut) +{ + return _VarUI1FromUI2(usIn, pbOut); +} + +/************************************************************************ + * VarUI1FromUI4 (OLEAUT32.239) + * + * Convert a VT_UI4 to a VT_UI1. + * + * PARAMS + * ulIn [I] Source + * pbOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut) +{ + return _VarUI1FromUI4(ulIn, pbOut); +} + +/************************************************************************ + * VarUI1FromDec (OLEAUT32.240) + * + * Convert a VT_DECIMAL to a VT_UI1. + * + * PARAMS + * pDecIn [I] Source + * pbOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI1FromDec(DECIMAL *pdecIn, BYTE* pbOut) +{ + LONG64 i64; + HRESULT hRet; + + hRet = _VarI8FromDec(pdecIn, &i64); + + if (SUCCEEDED(hRet)) + hRet = _VarUI1FromI8(i64, pbOut); + return hRet; +} + +/************************************************************************ + * VarUI1FromI8 (OLEAUT32.372) + * + * Convert a VT_I8 to a VT_UI1. + * + * PARAMS + * llIn [I] Source + * pbOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI1FromI8(LONG64 llIn, BYTE* pbOut) +{ + return _VarUI1FromI8(llIn, pbOut); +} + +/************************************************************************ + * VarUI1FromUI8 (OLEAUT32.373) + * + * Convert a VT_UI8 to a VT_UI1. + * + * PARAMS + * ullIn [I] Source + * pbOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI1FromUI8(ULONG64 ullIn, BYTE* pbOut) +{ + return _VarUI1FromUI8(ullIn, pbOut); +} + + +/* I2 + */ + +/************************************************************************ + * VarI2FromUI1 (OLEAUT32.48) + * + * Convert a VT_UI2 to a VT_I2. + * + * PARAMS + * bIn [I] Source + * psOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarI2FromUI1(BYTE bIn, SHORT* psOut) +{ + return _VarI2FromUI1(bIn, psOut); +} + +/************************************************************************ + * VarI2FromI4 (OLEAUT32.49) + * + * Convert a VT_I4 to a VT_I2. + * + * PARAMS + * iIn [I] Source + * psOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI2FromI4(LONG iIn, SHORT* psOut) +{ + return _VarI2FromI4(iIn, psOut); +} + +/************************************************************************ + * VarI2FromR4 (OLEAUT32.50) + * + * Convert a VT_R4 to a VT_I2. + * + * PARAMS + * fltIn [I] Source + * psOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI2FromR4(FLOAT fltIn, SHORT* psOut) +{ + return _VarI2FromR4(fltIn, psOut); +} + +/************************************************************************ + * VarI2FromR8 (OLEAUT32.51) + * + * Convert a VT_R8 to a VT_I2. + * + * PARAMS + * dblIn [I] Source + * psOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + * + * NOTES + * See VarI8FromR8() for details concerning rounding. + */ +HRESULT WINAPI VarI2FromR8(double dblIn, SHORT* psOut) +{ + if (dblIn < (double)I2_MIN || dblIn > (double)I2_MAX) + return DISP_E_OVERFLOW; + OLEAUT32_DutchRound(SHORT, dblIn, *psOut); + return S_OK; +} + +/************************************************************************ + * VarI2FromCy (OLEAUT32.52) + * + * Convert a VT_CY to a VT_I2. + * + * PARAMS + * cyIn [I] Source + * psOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI2FromCy(CY cyIn, SHORT* psOut) +{ + LONG i = I2_MAX + 1; + + _VarI4FromCy(cyIn, &i); + return _VarI2FromI4(i, psOut); +} + +/************************************************************************ + * VarI2FromDate (OLEAUT32.53) + * + * Convert a VT_DATE to a VT_I2. + * + * PARAMS + * dateIn [I] Source + * psOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI2FromDate(DATE dateIn, SHORT* psOut) +{ + return _VarI2FromDate(dateIn, psOut); +} + +/************************************************************************ + * VarI2FromStr (OLEAUT32.54) + * + * Convert a VT_BSTR to a VT_I2. + * + * PARAMS + * strIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * psOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if any parameter is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psOut) +{ + return _VarI2FromStr(strIn, lcid, dwFlags, psOut); +} + +/************************************************************************ + * VarI2FromDisp (OLEAUT32.55) + * + * Convert a VT_DISPATCH to a VT_I2. + * + * PARAMS + * pdispIn [I] Source + * lcid [I] LCID for conversion + * psOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if pdispIn is invalid, + * DISP_E_OVERFLOW, if the value will not fit in the destination, + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarI2FromDisp(IDispatch* pdispIn, LCID lcid, SHORT* psOut) +{ + return _VarI2FromDisp(pdispIn, lcid, psOut); +} + +/************************************************************************ + * VarI2FromBool (OLEAUT32.56) + * + * Convert a VT_BOOL to a VT_I2. + * + * PARAMS + * boolIn [I] Source + * psOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, SHORT* psOut) +{ + return _VarI2FromBool(boolIn, psOut); +} + +/************************************************************************ + * VarI2FromI1 (OLEAUT32.205) + * + * Convert a VT_I1 to a VT_I2. + * + * PARAMS + * cIn [I] Source + * psOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarI2FromI1(signed char cIn, SHORT* psOut) +{ + return _VarI2FromI1(cIn, psOut); +} + +/************************************************************************ + * VarI2FromUI2 (OLEAUT32.206) + * + * Convert a VT_UI2 to a VT_I2. + * + * PARAMS + * usIn [I] Source + * psOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI2FromUI2(USHORT usIn, SHORT* psOut) +{ + return _VarI2FromUI2(usIn, psOut); +} + +/************************************************************************ + * VarI2FromUI4 (OLEAUT32.207) + * + * Convert a VT_UI4 to a VT_I2. + * + * PARAMS + * ulIn [I] Source + * psOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI2FromUI4(ULONG ulIn, SHORT* psOut) +{ + return _VarI2FromUI4(ulIn, psOut); +} + +/************************************************************************ + * VarI2FromDec (OLEAUT32.208) + * + * Convert a VT_DECIMAL to a VT_I2. + * + * PARAMS + * pDecIn [I] Source + * psOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI2FromDec(DECIMAL *pdecIn, SHORT* psOut) +{ + LONG64 i64; + HRESULT hRet; + + hRet = _VarI8FromDec(pdecIn, &i64); + + if (SUCCEEDED(hRet)) + hRet = _VarI2FromI8(i64, psOut); + return hRet; +} + +/************************************************************************ + * VarI2FromI8 (OLEAUT32.346) + * + * Convert a VT_I8 to a VT_I2. + * + * PARAMS + * llIn [I] Source + * psOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI2FromI8(LONG64 llIn, SHORT* psOut) +{ + return _VarI2FromI8(llIn, psOut); +} + +/************************************************************************ + * VarI2FromUI8 (OLEAUT32.347) + * + * Convert a VT_UI8 to a VT_I2. + * + * PARAMS + * ullIn [I] Source + * psOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI2FromUI8(ULONG64 ullIn, SHORT* psOut) +{ + return _VarI2FromUI8(ullIn, psOut); +} + +/* UI2 + */ + +/************************************************************************ + * VarUI2FromUI1 (OLEAUT32.257) + * + * Convert a VT_UI1 to a VT_UI2. + * + * PARAMS + * bIn [I] Source + * pusOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* pusOut) +{ + return _VarUI2FromUI1(bIn, pusOut); +} + +/************************************************************************ + * VarUI2FromI2 (OLEAUT32.258) + * + * Convert a VT_I2 to a VT_UI2. + * + * PARAMS + * sIn [I] Source + * pusOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI2FromI2(SHORT sIn, USHORT* pusOut) +{ + return _VarUI2FromI2(sIn, pusOut); +} + +/************************************************************************ + * VarUI2FromI4 (OLEAUT32.259) + * + * Convert a VT_I4 to a VT_UI2. + * + * PARAMS + * iIn [I] Source + * pusOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI2FromI4(LONG iIn, USHORT* pusOut) +{ + return _VarUI2FromI4(iIn, pusOut); +} + +/************************************************************************ + * VarUI2FromR4 (OLEAUT32.260) + * + * Convert a VT_R4 to a VT_UI2. + * + * PARAMS + * fltIn [I] Source + * pusOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* pusOut) +{ + return _VarUI2FromR4(fltIn, pusOut); +} + +/************************************************************************ + * VarUI2FromR8 (OLEAUT32.261) + * + * Convert a VT_R8 to a VT_UI2. + * + * PARAMS + * dblIn [I] Source + * pusOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + * + * NOTES + * See VarI8FromR8() for details concerning rounding. + */ +HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* pusOut) +{ + if (dblIn < -0.5 || dblIn > (double)UI2_MAX) + return DISP_E_OVERFLOW; + OLEAUT32_DutchRound(USHORT, dblIn, *pusOut); + return S_OK; +} + +/************************************************************************ + * VarUI2FromDate (OLEAUT32.262) + * + * Convert a VT_DATE to a VT_UI2. + * + * PARAMS + * dateIn [I] Source + * pusOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* pusOut) +{ + return _VarUI2FromDate(dateIn, pusOut); +} + +/************************************************************************ + * VarUI2FromCy (OLEAUT32.263) + * + * Convert a VT_CY to a VT_UI2. + * + * PARAMS + * cyIn [I] Source + * pusOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + * + * NOTES + * Negative values >= -5000 will be converted to 0. + */ +HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) +{ + ULONG i = UI2_MAX + 1; + + _VarUI4FromCy(cyIn, &i); + return _VarUI2FromUI4(i, pusOut); +} + +/************************************************************************ + * VarUI2FromStr (OLEAUT32.264) + * + * Convert a VT_BSTR to a VT_UI2. + * + * PARAMS + * strIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pusOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* pusOut) +{ + return _VarUI2FromStr(strIn, lcid, dwFlags, pusOut); +} + +/************************************************************************ + * VarUI2FromDisp (OLEAUT32.265) + * + * Convert a VT_DISPATCH to a VT_UI2. + * + * PARAMS + * pdispIn [I] Source + * lcid [I] LCID for conversion + * pusOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarUI2FromDisp(IDispatch* pdispIn, LCID lcid, USHORT* pusOut) +{ + return _VarUI2FromDisp(pdispIn, lcid, pusOut); +} + +/************************************************************************ + * VarUI2FromBool (OLEAUT32.266) + * + * Convert a VT_BOOL to a VT_UI2. + * + * PARAMS + * boolIn [I] Source + * pusOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* pusOut) +{ + return _VarUI2FromBool(boolIn, pusOut); +} + +/************************************************************************ + * VarUI2FromI1 (OLEAUT32.267) + * + * Convert a VT_I1 to a VT_UI2. + * + * PARAMS + * cIn [I] Source + * pusOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* pusOut) +{ + return _VarUI2FromI1(cIn, pusOut); +} + +/************************************************************************ + * VarUI2FromUI4 (OLEAUT32.268) + * + * Convert a VT_UI4 to a VT_UI2. + * + * PARAMS + * ulIn [I] Source + * pusOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* pusOut) +{ + return _VarUI2FromUI4(ulIn, pusOut); +} + +/************************************************************************ + * VarUI2FromDec (OLEAUT32.269) + * + * Convert a VT_DECIMAL to a VT_UI2. + * + * PARAMS + * pDecIn [I] Source + * pusOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI2FromDec(DECIMAL *pdecIn, USHORT* pusOut) +{ + LONG64 i64; + HRESULT hRet; + + hRet = _VarI8FromDec(pdecIn, &i64); + + if (SUCCEEDED(hRet)) + hRet = _VarUI2FromI8(i64, pusOut); + return hRet; +} + +/************************************************************************ + * VarUI2FromI8 (OLEAUT32.378) + * + * Convert a VT_I8 to a VT_UI2. + * + * PARAMS + * llIn [I] Source + * pusOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI2FromI8(LONG64 llIn, USHORT* pusOut) +{ + return _VarUI2FromI8(llIn, pusOut); +} + +/************************************************************************ + * VarUI2FromUI8 (OLEAUT32.379) + * + * Convert a VT_UI8 to a VT_UI2. + * + * PARAMS + * ullIn [I] Source + * pusOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI2FromUI8(ULONG64 ullIn, USHORT* pusOut) +{ + return _VarUI2FromUI8(ullIn, pusOut); +} + +/* I4 + */ + +/************************************************************************ + * VarI4FromUI1 (OLEAUT32.58) + * + * Convert a VT_UI1 to a VT_I4. + * + * PARAMS + * bIn [I] Source + * piOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG *piOut) +{ + return _VarI4FromUI1(bIn, piOut); +} + +/************************************************************************ + * VarI4FromI2 (OLEAUT32.59) + * + * Convert a VT_I2 to a VT_I4. + * + * PARAMS + * sIn [I] Source + * piOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI4FromI2(SHORT sIn, LONG *piOut) +{ + return _VarI4FromI2(sIn, piOut); +} + +/************************************************************************ + * VarI4FromR4 (OLEAUT32.60) + * + * Convert a VT_R4 to a VT_I4. + * + * PARAMS + * fltIn [I] Source + * piOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG *piOut) +{ + return _VarI4FromR4(fltIn, piOut); +} + +/************************************************************************ + * VarI4FromR8 (OLEAUT32.61) + * + * Convert a VT_R8 to a VT_I4. + * + * PARAMS + * dblIn [I] Source + * piOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + * + * NOTES + * See VarI8FromR8() for details concerning rounding. + */ +HRESULT WINAPI VarI4FromR8(double dblIn, LONG *piOut) +{ + if (dblIn < (double)I4_MIN || dblIn > (double)I4_MAX) + return DISP_E_OVERFLOW; + OLEAUT32_DutchRound(LONG, dblIn, *piOut); + return S_OK; +} + +/************************************************************************ + * VarI4FromCy (OLEAUT32.62) + * + * Convert a VT_CY to a VT_I4. + * + * PARAMS + * cyIn [I] Source + * piOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI4FromCy(CY cyIn, LONG *piOut) +{ + double d = cyIn.int64 / CY_MULTIPLIER_F; + return _VarI4FromR8(d, piOut); +} + +/************************************************************************ + * VarI4FromDate (OLEAUT32.63) + * + * Convert a VT_DATE to a VT_I4. + * + * PARAMS + * dateIn [I] Source + * piOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG *piOut) +{ + return _VarI4FromDate(dateIn, piOut); +} + +/************************************************************************ + * VarI4FromStr (OLEAUT32.64) + * + * Convert a VT_BSTR to a VT_I4. + * + * PARAMS + * strIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * piOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if any parameter is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if strIn cannot be converted + */ +HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOut) +{ + return _VarI4FromStr(strIn, lcid, dwFlags, piOut); +} + +/************************************************************************ + * VarI4FromDisp (OLEAUT32.65) + * + * Convert a VT_DISPATCH to a VT_I4. + * + * PARAMS + * pdispIn [I] Source + * lcid [I] LCID for conversion + * piOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarI4FromDisp(IDispatch* pdispIn, LCID lcid, LONG *piOut) +{ + return _VarI4FromDisp(pdispIn, lcid, piOut); +} + +/************************************************************************ + * VarI4FromBool (OLEAUT32.66) + * + * Convert a VT_BOOL to a VT_I4. + * + * PARAMS + * boolIn [I] Source + * piOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG *piOut) +{ + return _VarI4FromBool(boolIn, piOut); +} + +/************************************************************************ + * VarI4FromI1 (OLEAUT32.209) + * + * Convert a VT_I4 to a VT_I4. + * + * PARAMS + * cIn [I] Source + * piOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarI4FromI1(signed char cIn, LONG *piOut) +{ + return _VarI4FromI1(cIn, piOut); +} + +/************************************************************************ + * VarI4FromUI2 (OLEAUT32.210) + * + * Convert a VT_UI2 to a VT_I4. + * + * PARAMS + * usIn [I] Source + * piOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarI4FromUI2(USHORT usIn, LONG *piOut) +{ + return _VarI4FromUI2(usIn, piOut); +} + +/************************************************************************ + * VarI4FromUI4 (OLEAUT32.211) + * + * Convert a VT_UI4 to a VT_I4. + * + * PARAMS + * ulIn [I] Source + * piOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG *piOut) +{ + return _VarI4FromUI4(ulIn, piOut); +} + +/************************************************************************ + * VarI4FromDec (OLEAUT32.212) + * + * Convert a VT_DECIMAL to a VT_I4. + * + * PARAMS + * pDecIn [I] Source + * piOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if pdecIn is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI4FromDec(DECIMAL *pdecIn, LONG *piOut) +{ + LONG64 i64; + HRESULT hRet; + + hRet = _VarI8FromDec(pdecIn, &i64); + + if (SUCCEEDED(hRet)) + hRet = _VarI4FromI8(i64, piOut); + return hRet; +} + +/************************************************************************ + * VarI4FromI8 (OLEAUT32.348) + * + * Convert a VT_I8 to a VT_I4. + * + * PARAMS + * llIn [I] Source + * piOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI4FromI8(LONG64 llIn, LONG *piOut) +{ + return _VarI4FromI8(llIn, piOut); +} + +/************************************************************************ + * VarI4FromUI8 (OLEAUT32.349) + * + * Convert a VT_UI8 to a VT_I4. + * + * PARAMS + * ullIn [I] Source + * piOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI4FromUI8(ULONG64 ullIn, LONG *piOut) +{ + return _VarI4FromUI8(ullIn, piOut); +} + +/* UI4 + */ + +/************************************************************************ + * VarUI4FromUI1 (OLEAUT32.270) + * + * Convert a VT_UI1 to a VT_UI4. + * + * PARAMS + * bIn [I] Source + * pulOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG *pulOut) +{ + return _VarUI4FromUI1(bIn, pulOut); +} + +/************************************************************************ + * VarUI4FromI2 (OLEAUT32.271) + * + * Convert a VT_I2 to a VT_UI4. + * + * PARAMS + * sIn [I] Source + * pulOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI4FromI2(SHORT sIn, ULONG *pulOut) +{ + return _VarUI4FromI2(sIn, pulOut); +} + +/************************************************************************ + * VarUI4FromI4 (OLEAUT32.272) + * + * Convert a VT_I4 to a VT_UI4. + * + * PARAMS + * iIn [I] Source + * pulOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI4FromI4(LONG iIn, ULONG *pulOut) +{ + return _VarUI4FromI4(iIn, pulOut); +} + +/************************************************************************ + * VarUI4FromR4 (OLEAUT32.273) + * + * Convert a VT_R4 to a VT_UI4. + * + * PARAMS + * fltIn [I] Source + * pulOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG *pulOut) +{ + return _VarUI4FromR4(fltIn, pulOut); +} + +/************************************************************************ + * VarUI4FromR8 (OLEAUT32.274) + * + * Convert a VT_R8 to a VT_UI4. + * + * PARAMS + * dblIn [I] Source + * pulOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + * + * NOTES + * See VarI8FromR8() for details concerning rounding. + */ +HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG *pulOut) +{ + if (dblIn < -0.5 || dblIn > (double)UI4_MAX) + return DISP_E_OVERFLOW; + OLEAUT32_DutchRound(ULONG, dblIn, *pulOut); + return S_OK; +} + +/************************************************************************ + * VarUI4FromDate (OLEAUT32.275) + * + * Convert a VT_DATE to a VT_UI4. + * + * PARAMS + * dateIn [I] Source + * pulOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG *pulOut) +{ + return _VarUI4FromDate(dateIn, pulOut); +} + +/************************************************************************ + * VarUI4FromCy (OLEAUT32.276) + * + * Convert a VT_CY to a VT_UI4. + * + * PARAMS + * cyIn [I] Source + * pulOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG *pulOut) +{ + double d = cyIn.int64 / CY_MULTIPLIER_F; + return _VarUI4FromR8(d, pulOut); +} + +/************************************************************************ + * VarUI4FromStr (OLEAUT32.277) + * + * Convert a VT_BSTR to a VT_UI4. + * + * PARAMS + * strIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pulOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if any parameter is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if strIn cannot be converted + */ +HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pulOut) +{ + return _VarUI4FromStr(strIn, lcid, dwFlags, pulOut); +} + +/************************************************************************ + * VarUI4FromDisp (OLEAUT32.278) + * + * Convert a VT_DISPATCH to a VT_UI4. + * + * PARAMS + * pdispIn [I] Source + * lcid [I] LCID for conversion + * pulOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarUI4FromDisp(IDispatch* pdispIn, LCID lcid, ULONG *pulOut) +{ + return _VarUI4FromDisp(pdispIn, lcid, pulOut); +} + +/************************************************************************ + * VarUI4FromBool (OLEAUT32.279) + * + * Convert a VT_BOOL to a VT_UI4. + * + * PARAMS + * boolIn [I] Source + * pulOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG *pulOut) +{ + return _VarUI4FromBool(boolIn, pulOut); +} + +/************************************************************************ + * VarUI4FromI1 (OLEAUT32.280) + * + * Convert a VT_I1 to a VT_UI4. + * + * PARAMS + * cIn [I] Source + * pulOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG *pulOut) +{ + return _VarUI4FromI1(cIn, pulOut); +} + +/************************************************************************ + * VarUI4FromUI2 (OLEAUT32.281) + * + * Convert a VT_UI2 to a VT_UI4. + * + * PARAMS + * usIn [I] Source + * pulOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarUI4FromUI2(USHORT usIn, ULONG *pulOut) +{ + return _VarUI4FromUI2(usIn, pulOut); +} + +/************************************************************************ + * VarUI4FromDec (OLEAUT32.282) + * + * Convert a VT_DECIMAL to a VT_UI4. + * + * PARAMS + * pDecIn [I] Source + * pulOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if pdecIn is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI4FromDec(DECIMAL *pdecIn, ULONG *pulOut) +{ + LONG64 i64; + HRESULT hRet; + + hRet = _VarI8FromDec(pdecIn, &i64); + + if (SUCCEEDED(hRet)) + hRet = _VarUI4FromI8(i64, pulOut); + return hRet; +} + +/************************************************************************ + * VarUI4FromI8 (OLEAUT32.425) + * + * Convert a VT_I8 to a VT_UI4. + * + * PARAMS + * llIn [I] Source + * pulOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI4FromI8(LONG64 llIn, ULONG *pulOut) +{ + return _VarUI4FromI8(llIn, pulOut); +} + +/************************************************************************ + * VarUI4FromUI8 (OLEAUT32.426) + * + * Convert a VT_UI8 to a VT_UI4. + * + * PARAMS + * ullIn [I] Source + * pulOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI4FromUI8(ULONG64 ullIn, ULONG *pulOut) +{ + return _VarUI4FromUI8(ullIn, pulOut); +} + +/* I8 + */ + +/************************************************************************ + * VarI8FromUI1 (OLEAUT32.333) + * + * Convert a VT_UI1 to a VT_I8. + * + * PARAMS + * bIn [I] Source + * pi64Out [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarI8FromUI1(BYTE bIn, LONG64* pi64Out) +{ + return _VarI8FromUI1(bIn, pi64Out); +} + + +/************************************************************************ + * VarI8FromI2 (OLEAUT32.334) + * + * Convert a VT_I2 to a VT_I8. + * + * PARAMS + * sIn [I] Source + * pi64Out [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarI8FromI2(SHORT sIn, LONG64* pi64Out) +{ + return _VarI8FromI2(sIn, pi64Out); +} + +/************************************************************************ + * VarI8FromR4 (OLEAUT32.335) + * + * Convert a VT_R4 to a VT_I8. + * + * PARAMS + * fltIn [I] Source + * pi64Out [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI8FromR4(FLOAT fltIn, LONG64* pi64Out) +{ + return _VarI8FromR4(fltIn, pi64Out); +} + +/************************************************************************ + * VarI8FromR8 (OLEAUT32.336) + * + * Convert a VT_R8 to a VT_I8. + * + * PARAMS + * dblIn [I] Source + * pi64Out [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * + * NOTES + * Only values that fit into 63 bits are accepted. Due to rounding issues, + * very high or low values will not be accurately converted. + * + * Numbers are rounded using Dutch rounding, as follows: + * + *| Fractional Part Sign Direction Example + *| --------------- ---- --------- ------- + *| < 0.5 + Down 0.4 -> 0.0 + *| < 0.5 - Up -0.4 -> 0.0 + *| > 0.5 + Up 0.6 -> 1.0 + *| < 0.5 - Up -0.6 -> -1.0 + *| = 0.5 + Up/Down Down if even, Up if odd + *| = 0.5 - Up/Down Up if even, Down if odd + * + * This system is often used in supermarkets. + */ +HRESULT WINAPI VarI8FromR8(double dblIn, LONG64* pi64Out) +{ + if ( dblIn < -4611686018427387904.0 || dblIn >= 4611686018427387904.0) + return DISP_E_OVERFLOW; + OLEAUT32_DutchRound(LONG64, dblIn, *pi64Out); + return S_OK; +} + +/************************************************************************ + * VarI8FromCy (OLEAUT32.337) + * + * Convert a VT_CY to a VT_I8. + * + * PARAMS + * cyIn [I] Source + * pi64Out [O] Destination + * + * RETURNS + * S_OK. + * + * NOTES + * All negative numbers are rounded down by 1, including those that are + * evenly divisible by 10000 (this is a Win32 bug that Wine mimics). + * Positive numbers are rounded using Dutch rounding: See VarI8FromR8() + * for details. + */ +HRESULT WINAPI VarI8FromCy(CY cyIn, LONG64* pi64Out) +{ + *pi64Out = cyIn.int64 / CY_MULTIPLIER; + + if (cyIn.int64 < 0) + (*pi64Out)--; /* Mimic Win32 bug */ + else + { + cyIn.int64 -= *pi64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */ + + if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pi64Out & 0x1))) + (*pi64Out)++; + } + return S_OK; +} + +/************************************************************************ + * VarI8FromDate (OLEAUT32.338) + * + * Convert a VT_DATE to a VT_I8. + * + * PARAMS + * dateIn [I] Source + * pi64Out [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarI8FromDate(DATE dateIn, LONG64* pi64Out) +{ + return _VarI8FromDate(dateIn, pi64Out); +} + +/************************************************************************ + * VarI8FromStr (OLEAUT32.339) + * + * Convert a VT_BSTR to a VT_I8. + * + * PARAMS + * strIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pi64Out [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi64Out) +{ + return _VarI8FromStr(strIn, lcid, dwFlags, pi64Out); +} + +/************************************************************************ + * VarI8FromDisp (OLEAUT32.340) + * + * Convert a VT_DISPATCH to a VT_I8. + * + * PARAMS + * pdispIn [I] Source + * lcid [I] LCID for conversion + * pi64Out [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out) +{ + return _VarI8FromDisp(pdispIn, lcid, pi64Out); +} + +/************************************************************************ + * VarI8FromBool (OLEAUT32.341) + * + * Convert a VT_BOOL to a VT_I8. + * + * PARAMS + * boolIn [I] Source + * pi64Out [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarI8FromBool(VARIANT_BOOL boolIn, LONG64* pi64Out) +{ + return _VarI8FromBool(boolIn, pi64Out); +} + +/************************************************************************ + * VarI8FromI1 (OLEAUT32.342) + * + * Convert a VT_I1 to a VT_I8. + * + * PARAMS + * cIn [I] Source + * pi64Out [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarI8FromI1(signed char cIn, LONG64* pi64Out) +{ + return _VarI8FromI1(cIn, pi64Out); +} + +/************************************************************************ + * VarI8FromUI2 (OLEAUT32.343) + * + * Convert a VT_UI2 to a VT_I8. + * + * PARAMS + * usIn [I] Source + * pi64Out [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarI8FromUI2(USHORT usIn, LONG64* pi64Out) +{ + return _VarI8FromUI2(usIn, pi64Out); +} + +/************************************************************************ + * VarI8FromUI4 (OLEAUT32.344) + * + * Convert a VT_UI4 to a VT_I8. + * + * PARAMS + * ulIn [I] Source + * pi64Out [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarI8FromUI4(ULONG ulIn, LONG64* pi64Out) +{ + return _VarI8FromUI4(ulIn, pi64Out); +} + +/************************************************************************ + * VarI8FromDec (OLEAUT32.345) + * + * Convert a VT_DECIMAL to a VT_I8. + * + * PARAMS + * pDecIn [I] Source + * pi64Out [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI8FromDec(DECIMAL *pdecIn, LONG64* pi64Out) +{ + if (!DEC_SCALE(pdecIn)) + { + /* This decimal is just a 96 bit integer */ + if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG) + return E_INVALIDARG; + + if (DEC_HI32(pdecIn) || DEC_MID32(pdecIn) & 0x80000000) + return DISP_E_OVERFLOW; + + if (DEC_SIGN(pdecIn)) + *pi64Out = -DEC_LO64(pdecIn); + else + *pi64Out = DEC_LO64(pdecIn); + return S_OK; + } + else + { + /* Decimal contains a floating point number */ + HRESULT hRet; + double dbl; + + hRet = _VarR8FromDec(pdecIn, &dbl); + if (SUCCEEDED(hRet)) + hRet = VarI8FromR8(dbl, pi64Out); + return hRet; + } +} + +/************************************************************************ + * VarI8FromUI8 (OLEAUT32.427) + * + * Convert a VT_UI8 to a VT_I8. + * + * PARAMS + * ullIn [I] Source + * pi64Out [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarI8FromUI8(ULONG64 ullIn, LONG64* pi64Out) +{ + return _VarI8FromUI8(ullIn, pi64Out); +} + +/* UI8 + */ + +/************************************************************************ + * VarUI8FromI8 (OLEAUT32.428) + * + * Convert a VT_I8 to a VT_UI8. + * + * PARAMS + * ulIn [I] Source + * pui64Out [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI8FromI8(LONG64 llIn, ULONG64* pui64Out) +{ + return _VarUI8FromI8(llIn, pui64Out); +} + +/************************************************************************ + * VarUI8FromUI1 (OLEAUT32.429) + * + * Convert a VT_UI1 to a VT_UI8. + * + * PARAMS + * bIn [I] Source + * pui64Out [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarUI8FromUI1(BYTE bIn, ULONG64* pui64Out) +{ + return _VarUI8FromUI1(bIn, pui64Out); +} + +/************************************************************************ + * VarUI8FromI2 (OLEAUT32.430) + * + * Convert a VT_I2 to a VT_UI8. + * + * PARAMS + * sIn [I] Source + * pui64Out [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarUI8FromI2(SHORT sIn, ULONG64* pui64Out) +{ + return _VarUI8FromI2(sIn, pui64Out); +} + +/************************************************************************ + * VarUI8FromR4 (OLEAUT32.431) + * + * Convert a VT_R4 to a VT_UI8. + * + * PARAMS + * fltIn [I] Source + * pui64Out [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI8FromR4(FLOAT fltIn, ULONG64* pui64Out) +{ + return _VarUI8FromR4(fltIn, pui64Out); +} + +/************************************************************************ + * VarUI8FromR8 (OLEAUT32.432) + * + * Convert a VT_R8 to a VT_UI8. + * + * PARAMS + * dblIn [I] Source + * pui64Out [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * + * NOTES + * See VarI8FromR8() for details concerning rounding. + */ +HRESULT WINAPI VarUI8FromR8(double dblIn, ULONG64* pui64Out) +{ + if (dblIn < -0.5 || dblIn > 1.844674407370955e19) + return DISP_E_OVERFLOW; + OLEAUT32_DutchRound(ULONG64, dblIn, *pui64Out); + return S_OK; +} + +/************************************************************************ + * VarUI8FromCy (OLEAUT32.433) + * + * Convert a VT_CY to a VT_UI8. + * + * PARAMS + * cyIn [I] Source + * pui64Out [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * + * NOTES + * Negative values >= -5000 will be converted to 0. + */ +HRESULT WINAPI VarUI8FromCy(CY cyIn, ULONG64* pui64Out) +{ + if (cyIn.int64 < 0) + { + if (cyIn.int64 < -CY_HALF) + return DISP_E_OVERFLOW; + *pui64Out = 0; + } + else + { + *pui64Out = cyIn.int64 / CY_MULTIPLIER; + + cyIn.int64 -= *pui64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */ + + if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pui64Out & 0x1))) + (*pui64Out)++; + } + return S_OK; +} + +/************************************************************************ + * VarUI8FromDate (OLEAUT32.434) + * + * Convert a VT_DATE to a VT_UI8. + * + * PARAMS + * dateIn [I] Source + * pui64Out [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarUI8FromDate(DATE dateIn, ULONG64* pui64Out) +{ + return _VarUI8FromDate(dateIn, pui64Out); +} + +/************************************************************************ + * VarUI8FromStr (OLEAUT32.435) + * + * Convert a VT_BSTR to a VT_UI8. + * + * PARAMS + * strIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pui64Out [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarUI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64* pui64Out) +{ + return _VarUI8FromStr(strIn, lcid, dwFlags, pui64Out); +} + +/************************************************************************ + * VarUI8FromDisp (OLEAUT32.436) + * + * Convert a VT_DISPATCH to a VT_UI8. + * + * PARAMS + * pdispIn [I] Source + * lcid [I] LCID for conversion + * pui64Out [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out) +{ + return _VarUI8FromDisp(pdispIn, lcid, pui64Out); +} + +/************************************************************************ + * VarUI8FromBool (OLEAUT32.437) + * + * Convert a VT_BOOL to a VT_UI8. + * + * PARAMS + * boolIn [I] Source + * pui64Out [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI8FromBool(VARIANT_BOOL boolIn, ULONG64* pui64Out) +{ + return _VarUI8FromBool(boolIn, pui64Out); +} +/************************************************************************ + * VarUI8FromI1 (OLEAUT32.438) + * + * Convert a VT_I1 to a VT_UI8. + * + * PARAMS + * cIn [I] Source + * pui64Out [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarUI8FromI1(signed char cIn, ULONG64* pui64Out) +{ + return _VarUI8FromI1(cIn, pui64Out); +} + +/************************************************************************ + * VarUI8FromUI2 (OLEAUT32.439) + * + * Convert a VT_UI2 to a VT_UI8. + * + * PARAMS + * usIn [I] Source + * pui64Out [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarUI8FromUI2(USHORT usIn, ULONG64* pui64Out) +{ + return _VarUI8FromUI2(usIn, pui64Out); +} + +/************************************************************************ + * VarUI8FromUI4 (OLEAUT32.440) + * + * Convert a VT_UI4 to a VT_UI8. + * + * PARAMS + * ulIn [I] Source + * pui64Out [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarUI8FromUI4(ULONG ulIn, ULONG64* pui64Out) +{ + return _VarUI8FromUI4(ulIn, pui64Out); +} + +/************************************************************************ + * VarUI8FromDec (OLEAUT32.441) + * + * Convert a VT_DECIMAL to a VT_UI8. + * + * PARAMS + * pDecIn [I] Source + * pui64Out [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * + * NOTES + * Under native Win32, if the source value has a scale of 0, its sign is + * ignored, i.e. this function takes the absolute value rather than fail + * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation + * (use VarAbs() on pDecIn first if you really want this behaviour). + */ +HRESULT WINAPI VarUI8FromDec(DECIMAL *pdecIn, ULONG64* pui64Out) +{ + if (!DEC_SCALE(pdecIn)) + { + /* This decimal is just a 96 bit integer */ + if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG) + return E_INVALIDARG; + + if (DEC_HI32(pdecIn)) + return DISP_E_OVERFLOW; + + if (DEC_SIGN(pdecIn)) + { + WARN("Sign would be ignored under Win32!\n"); + return DISP_E_OVERFLOW; + } + + *pui64Out = DEC_LO64(pdecIn); + return S_OK; + } + else + { + /* Decimal contains a floating point number */ + HRESULT hRet; + double dbl; + + hRet = _VarR8FromDec(pdecIn, &dbl); + if (SUCCEEDED(hRet)) + hRet = VarUI8FromR8(dbl, pui64Out); + return hRet; + } +} + +/* R4 + */ + +/************************************************************************ + * VarR4FromUI1 (OLEAUT32.68) + * + * Convert a VT_UI1 to a VT_R4. + * + * PARAMS + * bIn [I] Source + * pFltOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarR4FromUI1(BYTE bIn, float *pFltOut) +{ + return _VarR4FromUI1(bIn, pFltOut); +} + +/************************************************************************ + * VarR4FromI2 (OLEAUT32.69) + * + * Convert a VT_I2 to a VT_R4. + * + * PARAMS + * sIn [I] Source + * pFltOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarR4FromI2(SHORT sIn, float *pFltOut) +{ + return _VarR4FromI2(sIn, pFltOut); +} + +/************************************************************************ + * VarR4FromI4 (OLEAUT32.70) + * + * Convert a VT_I4 to a VT_R4. + * + * PARAMS + * sIn [I] Source + * pFltOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarR4FromI4(LONG lIn, float *pFltOut) +{ + return _VarR4FromI4(lIn, pFltOut); +} + +/************************************************************************ + * VarR4FromR8 (OLEAUT32.71) + * + * Convert a VT_R8 to a VT_R4. + * + * PARAMS + * dblIn [I] Source + * pFltOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination. + */ +HRESULT WINAPI VarR4FromR8(double dblIn, float *pFltOut) +{ + return _VarR4FromR8(dblIn, pFltOut); +} + +/************************************************************************ + * VarR4FromCy (OLEAUT32.72) + * + * Convert a VT_CY to a VT_R4. + * + * PARAMS + * cyIn [I] Source + * pFltOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarR4FromCy(CY cyIn, float *pFltOut) +{ + return _VarR4FromCy(cyIn, pFltOut); +} + +/************************************************************************ + * VarR4FromDate (OLEAUT32.73) + * + * Convert a VT_DATE to a VT_R4. + * + * PARAMS + * dateIn [I] Source + * pFltOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination. + */ +HRESULT WINAPI VarR4FromDate(DATE dateIn, float *pFltOut) +{ + return _VarR4FromDate(dateIn, pFltOut); +} + +/************************************************************************ + * VarR4FromStr (OLEAUT32.74) + * + * Convert a VT_BSTR to a VT_R4. + * + * PARAMS + * strIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pFltOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if strIn or pFltOut is invalid. + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFltOut) +{ + return _VarR4FromStr(strIn, lcid, dwFlags, pFltOut); +} + +/************************************************************************ + * VarR4FromDisp (OLEAUT32.75) + * + * Convert a VT_DISPATCH to a VT_R4. + * + * PARAMS + * pdispIn [I] Source + * lcid [I] LCID for conversion + * pFltOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut) +{ + return _VarR4FromDisp(pdispIn, lcid, pFltOut); +} + +/************************************************************************ + * VarR4FromBool (OLEAUT32.76) + * + * Convert a VT_BOOL to a VT_R4. + * + * PARAMS + * boolIn [I] Source + * pFltOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut) +{ + return _VarR4FromBool(boolIn, pFltOut); +} + +/************************************************************************ + * VarR4FromI1 (OLEAUT32.213) + * + * Convert a VT_I1 to a VT_R4. + * + * PARAMS + * cIn [I] Source + * pFltOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarR4FromI1(signed char cIn, float *pFltOut) +{ + return _VarR4FromI1(cIn, pFltOut); +} + +/************************************************************************ + * VarR4FromUI2 (OLEAUT32.214) + * + * Convert a VT_UI2 to a VT_R4. + * + * PARAMS + * usIn [I] Source + * pFltOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarR4FromUI2(USHORT usIn, float *pFltOut) +{ + return _VarR4FromUI2(usIn, pFltOut); +} + +/************************************************************************ + * VarR4FromUI4 (OLEAUT32.215) + * + * Convert a VT_UI4 to a VT_R4. + * + * PARAMS + * ulIn [I] Source + * pFltOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarR4FromUI4(ULONG ulIn, float *pFltOut) +{ + return _VarR4FromUI4(ulIn, pFltOut); +} + +/************************************************************************ + * VarR4FromDec (OLEAUT32.216) + * + * Convert a VT_DECIMAL to a VT_R4. + * + * PARAMS + * pDecIn [I] Source + * pFltOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid. + */ +HRESULT WINAPI VarR4FromDec(DECIMAL* pDecIn, float *pFltOut) +{ + BYTE scale = DEC_SCALE(pDecIn); + int divisor = 1; + double highPart; + + if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG) + return E_INVALIDARG; + + while (scale--) + divisor *= 10; + + if (DEC_SIGN(pDecIn)) + divisor = -divisor; + + if (DEC_HI32(pDecIn)) + { + highPart = (double)DEC_HI32(pDecIn) / (double)divisor; + highPart *= 1.0e64; + } + else + highPart = 0.0; + + *pFltOut = (double)DEC_LO64(pDecIn) / (double)divisor + highPart; + return S_OK; +} + +/************************************************************************ + * VarR4FromI8 (OLEAUT32.360) + * + * Convert a VT_I8 to a VT_R4. + * + * PARAMS + * ullIn [I] Source + * pFltOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarR4FromI8(LONG64 llIn, float *pFltOut) +{ + return _VarR4FromI8(llIn, pFltOut); +} + +/************************************************************************ + * VarR4FromUI8 (OLEAUT32.361) + * + * Convert a VT_UI8 to a VT_R4. + * + * PARAMS + * ullIn [I] Source + * pFltOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarR4FromUI8(ULONG64 ullIn, float *pFltOut) +{ + return _VarR4FromUI8(ullIn, pFltOut); +} + +/************************************************************************ + * VarR4CmpR8 (OLEAUT32.316) + * + * Compare a VT_R4 to a VT_R8. + * + * PARAMS + * fltLeft [I] Source + * dblRight [I] Value to compare + * + * RETURNS + * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than, + * equal to or greater than dblRight respectively. + */ +HRESULT WINAPI VarR4CmpR8(float fltLeft, double dblRight) +{ + if (fltLeft < dblRight) + return VARCMP_LT; + else if (fltLeft > dblRight) + return VARCMP_GT; + return VARCMP_EQ; +} + +/* R8 + */ + +/************************************************************************ + * VarR8FromUI1 (OLEAUT32.78) + * + * Convert a VT_UI1 to a VT_R8. + * + * PARAMS + * bIn [I] Source + * pDblOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarR8FromUI1(BYTE bIn, double *pDblOut) +{ + return _VarR8FromUI1(bIn, pDblOut); +} + +/************************************************************************ + * VarR8FromI2 (OLEAUT32.79) + * + * Convert a VT_I2 to a VT_R8. + * + * PARAMS + * sIn [I] Source + * pDblOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarR8FromI2(SHORT sIn, double *pDblOut) +{ + return _VarR8FromI2(sIn, pDblOut); +} + +/************************************************************************ + * VarR8FromI4 (OLEAUT32.80) + * + * Convert a VT_I4 to a VT_R8. + * + * PARAMS + * sIn [I] Source + * pDblOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarR8FromI4(LONG lIn, double *pDblOut) +{ + return _VarR8FromI4(lIn, pDblOut); +} + +/************************************************************************ + * VarR8FromR4 (OLEAUT32.81) + * + * Convert a VT_R4 to a VT_R8. + * + * PARAMS + * fltIn [I] Source + * pDblOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double *pDblOut) +{ + return _VarR8FromR4(fltIn, pDblOut); +} + +/************************************************************************ + * VarR8FromCy (OLEAUT32.82) + * + * Convert a VT_CY to a VT_R8. + * + * PARAMS + * cyIn [I] Source + * pDblOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarR8FromCy(CY cyIn, double *pDblOut) +{ + return _VarR8FromCy(cyIn, pDblOut); +} + +/************************************************************************ + * VarR8FromDate (OLEAUT32.83) + * + * Convert a VT_DATE to a VT_R8. + * + * PARAMS + * dateIn [I] Source + * pDblOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut) +{ + return _VarR8FromDate(dateIn, pDblOut); +} + +/************************************************************************ + * VarR8FromStr (OLEAUT32.84) + * + * Convert a VT_BSTR to a VT_R8. + * + * PARAMS + * strIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pDblOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if strIn or pDblOut is invalid. + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut) +{ + return _VarR8FromStr(strIn, lcid, dwFlags, pDblOut); +} + +/************************************************************************ + * VarR8FromDisp (OLEAUT32.85) + * + * Convert a VT_DISPATCH to a VT_R8. + * + * PARAMS + * pdispIn [I] Source + * lcid [I] LCID for conversion + * pDblOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut) +{ + return _VarR8FromDisp(pdispIn, lcid, pDblOut); +} + +/************************************************************************ + * VarR8FromBool (OLEAUT32.86) + * + * Convert a VT_BOOL to a VT_R8. + * + * PARAMS + * boolIn [I] Source + * pDblOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut) +{ + return _VarR8FromBool(boolIn, pDblOut); +} + +/************************************************************************ + * VarR8FromI1 (OLEAUT32.217) + * + * Convert a VT_I1 to a VT_R8. + * + * PARAMS + * cIn [I] Source + * pDblOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut) +{ + return _VarR8FromI1(cIn, pDblOut); +} + +/************************************************************************ + * VarR8FromUI2 (OLEAUT32.218) + * + * Convert a VT_UI2 to a VT_R8. + * + * PARAMS + * usIn [I] Source + * pDblOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut) +{ + return _VarR8FromUI2(usIn, pDblOut); +} + +/************************************************************************ + * VarR8FromUI4 (OLEAUT32.219) + * + * Convert a VT_UI4 to a VT_R8. + * + * PARAMS + * ulIn [I] Source + * pDblOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut) +{ + return _VarR8FromUI4(ulIn, pDblOut); +} + +/************************************************************************ + * VarR8FromDec (OLEAUT32.220) + * + * Convert a VT_DECIMAL to a VT_R8. + * + * PARAMS + * pDecIn [I] Source + * pDblOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid. + */ +HRESULT WINAPI VarR8FromDec(DECIMAL* pDecIn, double *pDblOut) +{ + BYTE scale = DEC_SCALE(pDecIn); + double divisor = 1.0, highPart; + + if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG) + return E_INVALIDARG; + + while (scale--) + divisor *= 10; + + if (DEC_SIGN(pDecIn)) + divisor = -divisor; + + if (DEC_HI32(pDecIn)) + { + highPart = (double)DEC_HI32(pDecIn) / divisor; + highPart *= 1.0e64; + } + else + highPart = 0.0; + + *pDblOut = (double)DEC_LO64(pDecIn) / divisor + highPart; + return S_OK; +} + +/************************************************************************ + * VarR8FromI8 (OLEAUT32.362) + * + * Convert a VT_I8 to a VT_R8. + * + * PARAMS + * ullIn [I] Source + * pDblOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut) +{ + return _VarR8FromI8(llIn, pDblOut); +} + +/************************************************************************ + * VarR8FromUI8 (OLEAUT32.363) + * + * Convert a VT_UI8 to a VT_R8. + * + * PARAMS + * ullIn [I] Source + * pDblOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut) +{ + return _VarR8FromUI8(ullIn, pDblOut); +} + +/************************************************************************ + * VarR8Pow (OLEAUT32.315) + * + * Raise a VT_R8 to a power. + * + * PARAMS + * dblLeft [I] Source + * dblPow [I] Power to raise dblLeft by + * pDblOut [O] Destination + * + * RETURNS + * S_OK. pDblOut contains dblLeft to the power of dblRight. + */ +HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut) +{ + *pDblOut = pow(dblLeft, dblPow); + return S_OK; +} + +/************************************************************************ + * VarR8Round (OLEAUT32.317) + * + * Round a VT_R8 to a given number of decimal points. + * + * PARAMS + * dblIn [I] Source + * nDig [I] Number of decimal points to round to + * pDblOut [O] Destination for rounded number + * + * RETURNS + * Success: S_OK. pDblOut is rounded to nDig digits. + * Failure: E_INVALIDARG, if cDecimals is less than 0. + * + * NOTES + * The native version of this function rounds using the internal + * binary representation of the number. Wine uses the dutch rounding + * convention, so therefore small differences can occur in the value returned. + * MSDN says that you should use your own rounding function if you want + * rounding to be predictable in your application. + */ +HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut) +{ + double scale, whole, fract; + + if (nDig < 0) + return E_INVALIDARG; + + scale = pow(10.0, nDig); + + dblIn *= scale; + whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn); + fract = dblIn - whole; + + if (fract > 0.5) + dblIn = whole + 1.0; + else if (fract == 0.5) + dblIn = whole + fmod(whole, 2.0); + else if (fract >= 0.0) + dblIn = whole; + else if (fract == -0.5) + dblIn = whole - fmod(whole, 2.0); + else if (fract > -0.5) + dblIn = whole; + else + dblIn = whole - 1.0; + + *pDblOut = dblIn / scale; + return S_OK; +} + +/* CY + */ + +/* Powers of 10 from 0..4 D.P. */ +static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000, + CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER }; + +/************************************************************************ + * VarCyFromUI1 (OLEAUT32.98) + * + * Convert a VT_UI1 to a VT_CY. + * + * PARAMS + * bIn [I] Source + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut) +{ + return _VarCyFromUI1(bIn, pCyOut); +} + +/************************************************************************ + * VarCyFromI2 (OLEAUT32.99) + * + * Convert a VT_I2 to a VT_CY. + * + * PARAMS + * sIn [I] Source + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut) +{ + return _VarCyFromI2(sIn, pCyOut); +} + +/************************************************************************ + * VarCyFromI4 (OLEAUT32.100) + * + * Convert a VT_I4 to a VT_CY. + * + * PARAMS + * sIn [I] Source + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut) +{ + return _VarCyFromI4(lIn, pCyOut); +} + +/************************************************************************ + * VarCyFromR4 (OLEAUT32.101) + * + * Convert a VT_R4 to a VT_CY. + * + * PARAMS + * fltIn [I] Source + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut) +{ + return _VarCyFromR4(fltIn, pCyOut); +} + +/************************************************************************ + * VarCyFromR8 (OLEAUT32.102) + * + * Convert a VT_R8 to a VT_CY. + * + * PARAMS + * dblIn [I] Source + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut) +{ +#if defined(__GNUC__) && defined(__i386__) + /* This code gives identical results to Win32 on Intel. + * Here we use fp exceptions to catch overflows when storing the value. + */ + static const unsigned short r8_fpcontrol = 0x137f; + static const double r8_multiplier = CY_MULTIPLIER_F; + unsigned short old_fpcontrol, result_fpstatus; + + /* Clear exceptions, save the old fp state and load the new state */ + __asm__ __volatile__( "fnclex" ); + __asm__ __volatile__( "fstcw %0" : "=m" (old_fpcontrol) : ); + __asm__ __volatile__( "fldcw %0" : : "m" (r8_fpcontrol) ); + /* Perform the conversion. */ + __asm__ __volatile__( "fldl %0" : : "m" (dblIn) ); + __asm__ __volatile__( "fmull %0" : : "m" (r8_multiplier) ); + __asm__ __volatile__( "fistpll %0" : : "m" (*pCyOut) ); + /* Save the resulting fp state, load the old state and clear exceptions */ + __asm__ __volatile__( "fstsw %0" : "=m" (result_fpstatus) : ); + __asm__ __volatile__( "fnclex" ); + __asm__ __volatile__( "fldcw %0" : : "m" (old_fpcontrol) ); + + if (result_fpstatus & 0x9) /* Overflow | Invalid */ + return DISP_E_OVERFLOW; + return S_OK; +#else + /* This version produces slightly different results for boundary cases */ + if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807) + return DISP_E_OVERFLOW; + dblIn *= CY_MULTIPLIER_F; + OLEAUT32_DutchRound(LONG64, dblIn, pCyOut->int64); +#endif + return S_OK; +} + +/************************************************************************ + * VarCyFromDate (OLEAUT32.103) + * + * Convert a VT_DATE to a VT_CY. + * + * PARAMS + * dateIn [I] Source + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut) +{ + return _VarCyFromDate(dateIn, pCyOut); +} + +/************************************************************************ + * VarCyFromStr (OLEAUT32.104) + * + * Convert a VT_BSTR to a VT_CY. + * + * PARAMS + * strIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarCyFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut) +{ + return _VarCyFromStr(strIn, lcid, dwFlags, pCyOut); +} + +/************************************************************************ + * VarCyFromDisp (OLEAUT32.105) + * + * Convert a VT_DISPATCH to a VT_CY. + * + * PARAMS + * pdispIn [I] Source + * lcid [I] LCID for conversion + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut) +{ + return _VarCyFromDisp(pdispIn, lcid, pCyOut); +} + +/************************************************************************ + * VarCyFromBool (OLEAUT32.106) + * + * Convert a VT_BOOL to a VT_CY. + * + * PARAMS + * boolIn [I] Source + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + * + * NOTES + * While the sign of the boolean is stored in the currency, the value is + * converted to either 0 or 1. + */ +HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut) +{ + return _VarCyFromBool(boolIn, pCyOut); +} + +/************************************************************************ + * VarCyFromI1 (OLEAUT32.225) + * + * Convert a VT_I1 to a VT_CY. + * + * PARAMS + * cIn [I] Source + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut) +{ + return _VarCyFromI1(cIn, pCyOut); +} + +/************************************************************************ + * VarCyFromUI2 (OLEAUT32.226) + * + * Convert a VT_UI2 to a VT_CY. + * + * PARAMS + * usIn [I] Source + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut) +{ + return _VarCyFromUI2(usIn, pCyOut); +} + +/************************************************************************ + * VarCyFromUI4 (OLEAUT32.227) + * + * Convert a VT_UI4 to a VT_CY. + * + * PARAMS + * ulIn [I] Source + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut) +{ + return _VarCyFromUI4(ulIn, pCyOut); +} + +/************************************************************************ + * VarCyFromDec (OLEAUT32.228) + * + * Convert a VT_DECIMAL to a VT_CY. + * + * PARAMS + * pdecIn [I] Source + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarCyFromDec(DECIMAL* pdecIn, CY* pCyOut) +{ + DECIMAL rounded; + HRESULT hRet; + + hRet = VarDecRound(pdecIn, 4, &rounded); + + if (SUCCEEDED(hRet)) + { + double d; + + if (DEC_HI32(&rounded)) + return DISP_E_OVERFLOW; + + /* Note: Without the casts this promotes to int64 which loses precision */ + d = (double)DEC_LO64(&rounded) / (double)CY_Divisors[DEC_SCALE(&rounded)]; + if (DEC_SIGN(&rounded)) + d = -d; + return _VarCyFromR8(d, pCyOut); + } + return hRet; +} + +/************************************************************************ + * VarCyFromI8 (OLEAUT32.366) + * + * Convert a VT_I8 to a VT_CY. + * + * PARAMS + * ullIn [I] Source + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut) +{ + return _VarCyFromI8(llIn, pCyOut); +} + +/************************************************************************ + * VarCyFromUI8 (OLEAUT32.375) + * + * Convert a VT_UI8 to a VT_CY. + * + * PARAMS + * ullIn [I] Source + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut) +{ + return _VarCyFromUI8(ullIn, pCyOut); +} + +/************************************************************************ + * VarCyAdd (OLEAUT32.299) + * + * Add one CY to another. + * + * PARAMS + * cyLeft [I] Source + * cyRight [I] Value to add + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarCyAdd(const CY cyLeft, const CY cyRight, CY* pCyOut) +{ + double l,r; + _VarR8FromCy(cyLeft, &l); + _VarR8FromCy(cyRight, &r); + l = l + r; + return _VarCyFromR8(l, pCyOut); +} + +/************************************************************************ + * VarCyMul (OLEAUT32.303) + * + * Multiply one CY by another. + * + * PARAMS + * cyLeft [I] Source + * cyRight [I] Value to multiply by + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarCyMul(const CY cyLeft, const CY cyRight, CY* pCyOut) +{ + double l,r; + _VarR8FromCy(cyLeft, &l); + _VarR8FromCy(cyRight, &r); + l = l * r; + return _VarCyFromR8(l, pCyOut); +} + +/************************************************************************ + * VarCyMulI4 (OLEAUT32.304) + * + * Multiply one CY by a VT_I4. + * + * PARAMS + * cyLeft [I] Source + * lRight [I] Value to multiply by + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarCyMulI4(const CY cyLeft, LONG lRight, CY* pCyOut) +{ + double d; + + _VarR8FromCy(cyLeft, &d); + d = d * lRight; + return _VarCyFromR8(d, pCyOut); +} + +/************************************************************************ + * VarCySub (OLEAUT32.305) + * + * Subtract one CY from another. + * + * PARAMS + * cyLeft [I] Source + * cyRight [I] Value to subtract + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarCySub(const CY cyLeft, const CY cyRight, CY* pCyOut) +{ + double l,r; + _VarR8FromCy(cyLeft, &l); + _VarR8FromCy(cyRight, &r); + l = l - r; + return _VarCyFromR8(l, pCyOut); +} + +/************************************************************************ + * VarCyAbs (OLEAUT32.306) + * + * Convert a VT_CY into its absolute value. + * + * PARAMS + * cyIn [I] Source + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. pCyOut contains the absolute value. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarCyAbs(const CY cyIn, CY* pCyOut) +{ + if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo) + return DISP_E_OVERFLOW; + + pCyOut->int64 = cyIn.int64 < 0 ? -cyIn.int64 : cyIn.int64; + return S_OK; +} + +/************************************************************************ + * VarCyFix (OLEAUT32.307) + * + * Return the integer part of a VT_CY. + * + * PARAMS + * cyIn [I] Source + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + * + * NOTES + * - The difference between this function and VarCyInt() is that VarCyInt() rounds + * negative numbers away from 0, while this function rounds them towards zero. + */ +HRESULT WINAPI VarCyFix(const CY cyIn, CY* pCyOut) +{ + pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER; + pCyOut->int64 *= CY_MULTIPLIER; + return S_OK; +} + +/************************************************************************ + * VarCyInt (OLEAUT32.308) + * + * Return the integer part of a VT_CY. + * + * PARAMS + * cyIn [I] Source + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + * + * NOTES + * - The difference between this function and VarCyFix() is that VarCyFix() rounds + * negative numbers towards 0, while this function rounds them away from zero. + */ +HRESULT WINAPI VarCyInt(const CY cyIn, CY* pCyOut) +{ + pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER; + pCyOut->int64 *= CY_MULTIPLIER; + + if (cyIn.int64 < 0 && cyIn.int64 % CY_MULTIPLIER != 0) + { + pCyOut->int64 -= CY_MULTIPLIER; + } + return S_OK; +} + +/************************************************************************ + * VarCyNeg (OLEAUT32.309) + * + * Change the sign of a VT_CY. + * + * PARAMS + * cyIn [I] Source + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarCyNeg(const CY cyIn, CY* pCyOut) +{ + if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo) + return DISP_E_OVERFLOW; + + pCyOut->int64 = -cyIn.int64; + return S_OK; +} + +/************************************************************************ + * VarCyRound (OLEAUT32.310) + * + * Change the precision of a VT_CY. + * + * PARAMS + * cyIn [I] Source + * cDecimals [I] New number of decimals to keep + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if cDecimals is less than 0. + */ +HRESULT WINAPI VarCyRound(const CY cyIn, int cDecimals, CY* pCyOut) +{ + if (cDecimals < 0) + return E_INVALIDARG; + + if (cDecimals > 3) + { + /* Rounding to more precision than we have */ + *pCyOut = cyIn; + return S_OK; + } + else + { + double d, div = CY_Divisors[cDecimals]; + + _VarR8FromCy(cyIn, &d); + d = d * div; + OLEAUT32_DutchRound(LONGLONG, d, pCyOut->int64) + d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F; + OLEAUT32_DutchRound(LONGLONG, d, pCyOut->int64) + return S_OK; + } +} + +/************************************************************************ + * VarCyCmp (OLEAUT32.311) + * + * Compare two VT_CY values. + * + * PARAMS + * cyLeft [I] Source + * cyRight [I] Value to compare + * + * RETURNS + * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to + * compare is less, equal or greater than source respectively. + * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison + */ +HRESULT WINAPI VarCyCmp(const CY cyLeft, const CY cyRight) +{ + HRESULT hRet; + CY result; + + /* Subtract right from left, and compare the result to 0 */ + hRet = VarCySub(cyLeft, cyRight, &result); + + if (SUCCEEDED(hRet)) + { + if (result.int64 < 0) + hRet = (HRESULT)VARCMP_LT; + else if (result.int64 > 0) + hRet = (HRESULT)VARCMP_GT; + else + hRet = (HRESULT)VARCMP_EQ; + } + return hRet; +} + +/************************************************************************ + * VarCyCmpR8 (OLEAUT32.312) + * + * Compare a VT_CY to a double + * + * PARAMS + * cyLeft [I] Currency Source + * dblRight [I] double to compare to cyLeft + * + * RETURNS + * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is + * less than, equal to or greater than cyLeft respectively. + * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison + */ +HRESULT WINAPI VarCyCmpR8(const CY cyLeft, double dblRight) +{ + HRESULT hRet; + CY cyRight; + + hRet = _VarCyFromR8(dblRight, &cyRight); + + if (SUCCEEDED(hRet)) + hRet = VarCyCmp(cyLeft, cyRight); + + return hRet; +} + +/************************************************************************ + * VarCyMulI8 (OLEAUT32.329) + * + * Multiply a VT_CY by a VT_I8. + * + * PARAMS + * cyLeft [I] Source + * llRight [I] Value to multiply by + * pCyOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarCyMulI8(const CY cyLeft, LONG64 llRight, CY* pCyOut) +{ + double d; + + _VarR8FromCy(cyLeft, &d); + d = d * (double)llRight; + return _VarCyFromR8(d, pCyOut); +} + +/* DECIMAL + */ + +/************************************************************************ + * VarDecFromUI1 (OLEAUT32.190) + * + * Convert a VT_UI1 to a DECIMAL. + * + * PARAMS + * bIn [I] Source + * pDecOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut) +{ + return _VarDecFromUI1(bIn, pDecOut); +} + +/************************************************************************ + * VarDecFromI2 (OLEAUT32.191) + * + * Convert a VT_I2 to a DECIMAL. + * + * PARAMS + * sIn [I] Source + * pDecOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut) +{ + return _VarDecFromI2(sIn, pDecOut); +} + +/************************************************************************ + * VarDecFromI4 (OLEAUT32.192) + * + * Convert a VT_I4 to a DECIMAL. + * + * PARAMS + * sIn [I] Source + * pDecOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut) +{ + DEC_HI32(pDecOut) = 0; + DEC_MID32(pDecOut) = 0; + + if (lIn < 0) + { + DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0); + DEC_LO32(pDecOut) = -lIn; + } + else + { + DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); + DEC_LO32(pDecOut) = lIn; + } + return S_OK; +} + +#define LOCALE_EN_US (MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT)) + +/************************************************************************ + * VarDecFromR4 (OLEAUT32.193) + * + * Convert a VT_R4 to a DECIMAL. + * + * PARAMS + * fltIn [I] Source + * pDecOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut) +{ + WCHAR buff[256]; + + sprintfW( buff, szFloatFormatW, fltIn ); + return _VarDecFromStr(buff, LOCALE_EN_US, 0, pDecOut); +} + +/************************************************************************ + * VarDecFromR8 (OLEAUT32.194) + * + * Convert a VT_R8 to a DECIMAL. + * + * PARAMS + * dblIn [I] Source + * pDecOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut) +{ + WCHAR buff[256]; + + sprintfW( buff, szDoubleFormatW, dblIn ); + return _VarDecFromStr(buff, LOCALE_EN_US, 0, pDecOut); +} + +/************************************************************************ + * VarDecFromDate (OLEAUT32.195) + * + * Convert a VT_DATE to a DECIMAL. + * + * PARAMS + * dateIn [I] Source + * pDecOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut) +{ + return _VarDecFromDate(dateIn, pDecOut); +} + +/************************************************************************ + * VarDecFromCy (OLEAUT32.196) + * + * Convert a VT_CY to a DECIMAL. + * + * PARAMS + * cyIn [I] Source + * pDecOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut) +{ + DEC_HI32(pDecOut) = 0; + + /* Note: This assumes 2s complement integer representation */ + if (cyIn.s.Hi & 0x80000000) + { + DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,4); + DEC_LO64(pDecOut) = -cyIn.int64; + } + else + { + DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,4); + DEC_MID32(pDecOut) = cyIn.s.Hi; + DEC_LO32(pDecOut) = cyIn.s.Lo; + } + return S_OK; +} + +/************************************************************************ + * VarDecFromStr (OLEAUT32.197) + * + * Convert a VT_BSTR to a DECIMAL. + * + * PARAMS + * strIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pDecOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut) +{ + return _VarDecFromStr(strIn, lcid, dwFlags, pDecOut); +} + +/************************************************************************ + * VarDecFromDisp (OLEAUT32.198) + * + * Convert a VT_DISPATCH to a DECIMAL. + * + * PARAMS + * pdispIn [I] Source + * lcid [I] LCID for conversion + * pDecOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut) +{ + return _VarDecFromDisp(pdispIn, lcid, pDecOut); +} + +/************************************************************************ + * VarDecFromBool (OLEAUT32.199) + * + * Convert a VT_BOOL to a DECIMAL. + * + * PARAMS + * bIn [I] Source + * pDecOut [O] Destination + * + * RETURNS + * S_OK. + * + * NOTES + * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE). + */ +HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut) +{ + DEC_HI32(pDecOut) = 0; + DEC_MID32(pDecOut) = 0; + if (bIn) + { + DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0); + DEC_LO32(pDecOut) = 1; + } + else + { + DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); + DEC_LO32(pDecOut) = 0; + } + return S_OK; +} + +/************************************************************************ + * VarDecFromI1 (OLEAUT32.241) + * + * Convert a VT_I1 to a DECIMAL. + * + * PARAMS + * cIn [I] Source + * pDecOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut) +{ + return _VarDecFromI1(cIn, pDecOut); +} + +/************************************************************************ + * VarDecFromUI2 (OLEAUT32.242) + * + * Convert a VT_UI2 to a DECIMAL. + * + * PARAMS + * usIn [I] Source + * pDecOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut) +{ + return _VarDecFromUI2(usIn, pDecOut); +} + +/************************************************************************ + * VarDecFromUI4 (OLEAUT32.243) + * + * Convert a VT_UI4 to a DECIMAL. + * + * PARAMS + * ulIn [I] Source + * pDecOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut) +{ + DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); + DEC_HI32(pDecOut) = 0; + DEC_MID32(pDecOut) = 0; + DEC_LO32(pDecOut) = ulIn; + return S_OK; +} + +/************************************************************************ + * VarDecFromI8 (OLEAUT32.374) + * + * Convert a VT_I8 to a DECIMAL. + * + * PARAMS + * llIn [I] Source + * pDecOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut) +{ + PULARGE_INTEGER pLi = (PULARGE_INTEGER)&llIn; + + DEC_HI32(pDecOut) = 0; + + /* Note: This assumes 2s complement integer representation */ + if (pLi->u.HighPart & 0x80000000) + { + DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0); + DEC_LO64(pDecOut) = -pLi->QuadPart; + } + else + { + DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); + DEC_MID32(pDecOut) = pLi->u.HighPart; + DEC_LO32(pDecOut) = pLi->u.LowPart; + } + return S_OK; +} + +/************************************************************************ + * VarDecFromUI8 (OLEAUT32.375) + * + * Convert a VT_UI8 to a DECIMAL. + * + * PARAMS + * ullIn [I] Source + * pDecOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut) +{ + DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0); + DEC_HI32(pDecOut) = 0; + DEC_LO64(pDecOut) = ullIn; + return S_OK; +} + +/* Make two DECIMALS the same scale; used by math functions below */ +static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft, + const DECIMAL** ppDecRight, + DECIMAL* pDecOut) +{ + static DECIMAL scaleFactor; + DECIMAL decTemp; + int scaleAmount, i; + HRESULT hRet = S_OK; + + if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG) + return E_INVALIDARG; + + DEC_LO32(&scaleFactor) = 10; + + i = scaleAmount = DEC_SCALE(*ppDecLeft) - DEC_SCALE(*ppDecRight); + + if (!scaleAmount) + return S_OK; /* Same scale */ + + if (scaleAmount > 0) + { + decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */ + *ppDecRight = pDecOut; + } + else + { + decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */ + *ppDecLeft = pDecOut; + i = scaleAmount = -scaleAmount; + } + + if (DEC_SCALE(&decTemp) + scaleAmount > DEC_MAX_SCALE) + return DISP_E_OVERFLOW; /* Can't scale up */ + + /* Multiply up the value to be scaled by the correct amount */ + while (SUCCEEDED(hRet) && i--) + { + /* Note we are multiplying by a value with a scale of 0, so we don't recurse */ + hRet = VarDecMul(&decTemp, &scaleFactor, pDecOut); + decTemp = *pDecOut; + } + DEC_SCALE(pDecOut) += scaleAmount; /* Set the new scale */ + return hRet; +} + +/* Add two unsigned 32 bit values with overflow */ +static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh) +{ + ULARGE_INTEGER ul64; + + ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh; + *pulHigh = ul64.u.HighPart; + return ul64.u.LowPart; +} + +/* Subtract two unsigned 32 bit values with underflow */ +static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh) +{ + int invert = 0; + ULARGE_INTEGER ul64; + + ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight; + if (ulLeft < ulRight) + invert = 1; + + if (ul64.QuadPart > (ULONG64)*pulHigh) + ul64.QuadPart -= (ULONG64)*pulHigh; + else + { + ul64.QuadPart -= (ULONG64)*pulHigh; + invert = 1; + } + if (invert) + ul64.u.HighPart = -ul64.u.HighPart ; + + *pulHigh = ul64.u.HighPart; + return ul64.u.LowPart; +} + +/* Multiply two unsigned 32 bit values with overflow */ +static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh) +{ + ULARGE_INTEGER ul64; + + ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh; + *pulHigh = ul64.u.HighPart; + return ul64.u.LowPart; +} + +/* Compare two decimals that have the same scale */ +static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight) +{ + if ( DEC_HI32(pDecLeft) < DEC_HI32(pDecRight) || + (DEC_HI32(pDecLeft) <= DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) < DEC_LO64(pDecRight))) + return -1; + else if (DEC_HI32(pDecLeft) == DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) == DEC_LO64(pDecRight)) + return 0; + return 1; +} + +/************************************************************************ + * VarDecAdd (OLEAUT32.177) + * + * Add one DECIMAL to another. + * + * PARAMS + * pDecLeft [I] Source + * pDecRight [I] Value to add + * pDecOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) +{ + HRESULT hRet; + DECIMAL scaled; + + hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, &scaled); + + if (SUCCEEDED(hRet)) + { + /* Our decimals now have the same scale, we can add them as 96 bit integers */ + ULONG overflow = 0; + BYTE sign = DECIMAL_POS; + + /* Correct for the sign of the result */ + if (DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight)) + { + /* -x + -y : Negative */ + sign = DECIMAL_NEG; + goto VarDecAdd_AsPositive; + } + else if (DEC_SIGN(pDecLeft) && !DEC_SIGN(pDecRight)) + { + int cmp = VARIANT_DecCmp(pDecLeft, pDecRight); + + /* -x + y : Negative if x > y */ + if (cmp > 0) + { + sign = DECIMAL_NEG; +VarDecAdd_AsNegative: + DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow); + DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow); + DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow); + } + else + { +VarDecAdd_AsInvertedNegative: + DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecRight), DEC_LO32(pDecLeft), &overflow); + DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecRight), DEC_MID32(pDecLeft), &overflow); + DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecRight), DEC_HI32(pDecLeft), &overflow); + } + } + else if (!DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight)) + { + int cmp = VARIANT_DecCmp(pDecLeft, pDecRight); + + /* x + -y : Negative if x <= y */ + if (cmp <= 0) + { + sign = DECIMAL_NEG; + goto VarDecAdd_AsInvertedNegative; + } + goto VarDecAdd_AsNegative; + } + else + { + /* x + y : Positive */ +VarDecAdd_AsPositive: + DEC_LO32(pDecOut) = VARIANT_Add(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow); + DEC_MID32(pDecOut) = VARIANT_Add(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow); + DEC_HI32(pDecOut) = VARIANT_Add(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow); + } + + if (overflow) + return DISP_E_OVERFLOW; /* overflowed */ + + DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft); + DEC_SIGN(pDecOut) = sign; + } + return hRet; +} + +/************************************************************************ + * VarDecDiv (OLEAUT32.178) + * + * Divide one DECIMAL by another. + * + * PARAMS + * pDecLeft [I] Source + * pDecRight [I] Value to divide by + * pDecOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) +{ + FIXME("(%p,%p,%p)-stub!\n",pDecLeft,pDecRight,pDecOut); + return DISP_E_OVERFLOW; +} + +/************************************************************************ + * VarDecMul (OLEAUT32.179) + * + * Multiply one DECIMAL by another. + * + * PARAMS + * pDecLeft [I] Source + * pDecRight [I] Value to multiply by + * pDecOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) +{ + /* FIXME: This only allows multiplying by a fixed integer <= 0xffffffff */ + + if (!DEC_SCALE(pDecLeft) || !DEC_SCALE(pDecRight)) + { + /* At least one term is an integer */ + const DECIMAL* pDecInteger = DEC_SCALE(pDecLeft) ? pDecRight : pDecLeft; + const DECIMAL* pDecOperand = DEC_SCALE(pDecLeft) ? pDecLeft : pDecRight; + HRESULT hRet = S_OK; + unsigned int multiplier = DEC_LO32(pDecInteger); + ULONG overflow = 0; + + if (DEC_HI32(pDecInteger) || DEC_MID32(pDecInteger)) + { + FIXME("(%p,%p,%p) semi-stub!\n",pDecLeft,pDecRight,pDecOut); + return DISP_E_OVERFLOW; + } + + DEC_LO32(pDecOut) = VARIANT_Mul(DEC_LO32(pDecOperand), multiplier, &overflow); + DEC_MID32(pDecOut) = VARIANT_Mul(DEC_MID32(pDecOperand), multiplier, &overflow); + DEC_HI32(pDecOut) = VARIANT_Mul(DEC_HI32(pDecOperand), multiplier, &overflow); + + if (overflow) + hRet = DISP_E_OVERFLOW; + else + { + BYTE sign = DECIMAL_POS; + + if (DEC_SIGN(pDecLeft) != DEC_SIGN(pDecRight)) + sign = DECIMAL_NEG; /* pos * neg => negative */ + DEC_SIGN(pDecOut) = sign; + DEC_SCALE(pDecOut) = DEC_SCALE(pDecOperand); + } + return hRet; + } + FIXME("(%p,%p,%p) semi-stub!\n",pDecLeft,pDecRight,pDecOut); + return DISP_E_OVERFLOW; +} + +/************************************************************************ + * VarDecSub (OLEAUT32.181) + * + * Subtract one DECIMAL from another. + * + * PARAMS + * pDecLeft [I] Source + * pDecRight [I] DECIMAL to subtract from pDecLeft + * pDecOut [O] Destination + * + * RETURNS + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut) +{ + DECIMAL decRight; + + /* Implement as addition of the negative */ + VarDecNeg(pDecRight, &decRight); + return VarDecAdd(pDecLeft, &decRight, pDecOut); +} + +/************************************************************************ + * VarDecAbs (OLEAUT32.182) + * + * Convert a DECIMAL into its absolute value. + * + * PARAMS + * pDecIn [I] Source + * pDecOut [O] Destination + * + * RETURNS + * S_OK. This function does not fail. + */ +HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut) +{ + *pDecOut = *pDecIn; + DEC_SIGN(pDecOut) &= ~DECIMAL_NEG; + return S_OK; +} + +/************************************************************************ + * VarDecFix (OLEAUT32.187) + * + * Return the integer portion of a DECIMAL. + * + * PARAMS + * pDecIn [I] Source + * pDecOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + * + * NOTES + * - The difference between this function and VarDecInt() is that VarDecInt() rounds + * negative numbers away from 0, while this function rounds them towards zero. + */ +HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut) +{ + if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) + return E_INVALIDARG; + + if (!DEC_SCALE(pDecIn)) + { + *pDecOut = *pDecIn; /* Already an integer */ + return S_OK; + } + + FIXME("semi-stub!\n"); + return DISP_E_OVERFLOW; +} + +/************************************************************************ + * VarDecInt (OLEAUT32.188) + * + * Return the integer portion of a DECIMAL. + * + * PARAMS + * pDecIn [I] Source + * pDecOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + * + * NOTES + * - The difference between this function and VarDecFix() is that VarDecFix() rounds + * negative numbers towards 0, while this function rounds them away from zero. + */ +HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut) +{ + if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) + return E_INVALIDARG; + + if (!(DEC_SIGN(pDecIn) & DECIMAL_NEG) || !DEC_SCALE(pDecIn)) + return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */ + + FIXME("semi-stub!\n"); + return DISP_E_OVERFLOW; +} + +/************************************************************************ + * VarDecNeg (OLEAUT32.189) + * + * Change the sign of a DECIMAL. + * + * PARAMS + * pDecIn [I] Source + * pDecOut [O] Destination + * + * RETURNS + * S_OK. This function does not fail. + */ +HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut) +{ + *pDecOut = *pDecIn; + DEC_SIGN(pDecOut) ^= DECIMAL_NEG; + return S_OK; +} + +/************************************************************************ + * VarDecRound (OLEAUT32.203) + * + * Change the precision of a DECIMAL. + * + * PARAMS + * pDecIn [I] Source + * cDecimals [I] New number of decimals to keep + * pDecOut [O] Destination + * + * RETURNS + * Success: S_OK. pDecOut contains the rounded value. + * Failure: E_INVALIDARG if any argument is invalid. + */ +HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut) +{ + if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE) + return E_INVALIDARG; + + if (cDecimals >= DEC_SCALE(pDecIn)) + { + *pDecOut = *pDecIn; /* More precision than we have */ + return S_OK; + } + + FIXME("semi-stub!\n"); + + return DISP_E_OVERFLOW; +} + +/************************************************************************ + * VarDecCmp (OLEAUT32.204) + * + * Compare two DECIMAL values. + * + * PARAMS + * pDecLeft [I] Source + * pDecRight [I] Value to compare + * + * RETURNS + * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft + * is less than, equal to or greater than pDecRight respectively. + * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison + */ +HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight) +{ + HRESULT hRet; + DECIMAL result; + + /* Subtract right from left, and compare the result to 0 */ + hRet = VarDecSub(pDecLeft, pDecRight, &result); + + if (SUCCEEDED(hRet)) + { + int non_zero = DEC_HI32(&result) | DEC_MID32(&result) | DEC_LO32(&result); + + if ((DEC_SIGN(&result) & DECIMAL_NEG) && non_zero) + hRet = (HRESULT)VARCMP_LT; + else if (non_zero) + hRet = (HRESULT)VARCMP_GT; + else + hRet = (HRESULT)VARCMP_EQ; + } + return hRet; +} + +/************************************************************************ + * VarDecCmpR8 (OLEAUT32.298) + * + * Compare a DECIMAL to a double + * + * PARAMS + * pDecLeft [I] DECIMAL Source + * dblRight [I] double to compare to pDecLeft + * + * RETURNS + * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight + * is less than, equal to or greater than pDecLeft respectively. + * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison + */ +HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight) +{ + HRESULT hRet; + DECIMAL decRight; + + hRet = VarDecFromR8(dblRight, &decRight); + + if (SUCCEEDED(hRet)) + hRet = VarDecCmp(pDecLeft, &decRight); + + return hRet; +} + +/* BOOL + */ + +/************************************************************************ + * VarBoolFromUI1 (OLEAUT32.118) + * + * Convert a VT_UI1 to a VT_BOOL. + * + * PARAMS + * bIn [I] Source + * pBoolOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut) +{ + return _VarBoolFromUI1(bIn, pBoolOut); +} + +/************************************************************************ + * VarBoolFromI2 (OLEAUT32.119) + * + * Convert a VT_I2 to a VT_BOOL. + * + * PARAMS + * sIn [I] Source + * pBoolOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut) +{ + return _VarBoolFromI2(sIn, pBoolOut); +} + +/************************************************************************ + * VarBoolFromI4 (OLEAUT32.120) + * + * Convert a VT_I4 to a VT_BOOL. + * + * PARAMS + * sIn [I] Source + * pBoolOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut) +{ + return _VarBoolFromI4(lIn, pBoolOut); +} + +/************************************************************************ + * VarBoolFromR4 (OLEAUT32.121) + * + * Convert a VT_R4 to a VT_BOOL. + * + * PARAMS + * fltIn [I] Source + * pBoolOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut) +{ + return _VarBoolFromR4(fltIn, pBoolOut); +} + +/************************************************************************ + * VarBoolFromR8 (OLEAUT32.122) + * + * Convert a VT_R8 to a VT_BOOL. + * + * PARAMS + * dblIn [I] Source + * pBoolOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut) +{ + return _VarBoolFromR8(dblIn, pBoolOut); +} + +/************************************************************************ + * VarBoolFromDate (OLEAUT32.123) + * + * Convert a VT_DATE to a VT_BOOL. + * + * PARAMS + * dateIn [I] Source + * pBoolOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut) +{ + return _VarBoolFromDate(dateIn, pBoolOut); +} + +/************************************************************************ + * VarBoolFromCy (OLEAUT32.124) + * + * Convert a VT_CY to a VT_BOOL. + * + * PARAMS + * cyIn [I] Source + * pBoolOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut) +{ + return _VarBoolFromCy(cyIn, pBoolOut); +} + +static BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest) +{ + HRSRC hrsrc; + + hrsrc = FindResourceExW( OLEAUT32_hModule, (LPWSTR)RT_STRING, + (LPCWSTR)((dwId >> 4) + 1), langId ); + if (hrsrc) + { + HGLOBAL hmem = LoadResource( OLEAUT32_hModule, hrsrc ); + + if (hmem) + { + const WCHAR *p; + unsigned int i; + + p = LockResource( hmem ); + for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1; + + memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) ); + lpszDest[*p] = '\0'; + TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId); + return TRUE; + } + } + return FALSE; +} + +/************************************************************************ + * VarBoolFromStr (OLEAUT32.125) + * + * Convert a VT_BSTR to a VT_BOOL. + * + * PARAMS + * strIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pBoolOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if pBoolOut is invalid. + * DISP_E_TYPEMISMATCH, if the type cannot be converted + * + * NOTES + * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally, + * it may contain (in any case mapping) the text "true" or "false". + * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the + * localised text of "True" or "False" in the language specified by lcid. + * - If none of these matches occur, the string is treated as a numeric string + * and the boolean pBoolOut will be set according to whether the number is zero + * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion. + * - If the text is not numeric and does not match any of the above, then + * DISP_E_TYPEMISMATCH is returned. + */ +HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut) +{ + /* Any VB/VBA programmers out there should recognise these strings... */ + static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' }; + static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' }; + WCHAR szBuff[64]; + LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); + HRESULT hRes = S_OK; + + if (!strIn || !pBoolOut) + return DISP_E_TYPEMISMATCH; + + /* Check if we should be comparing against localised text */ + if (dwFlags & VAR_LOCALBOOL) + { + /* Convert our LCID into a usable value */ + lcid = ConvertDefaultLocale(lcid); + + langId = LANGIDFROMLCID(lcid); + + if (PRIMARYLANGID(langId) == LANG_NEUTRAL) + langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); + + /* Note: Native oleaut32 always copies strIn and maps halfwidth characters. + * I don't think this is needed unless any of the localised text strings + * contain characters that can be so mapped. In the event that this is + * true for a given language (possibly some Asian languages), then strIn + * should be mapped here _only_ if langId is an Id for which this can occur. + */ + } + + /* Note that if we are not comparing against localised strings, langId + * will have its default value of LANG_ENGLISH. This allows us to mimic + * the native behaviour of always checking against English strings even + * after we've checked for localised ones. + */ +VarBoolFromStr_CheckLocalised: + if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff)) + { + /* Compare against localised strings, ignoring case */ + if (!strcmpiW(strIn, szBuff)) + { + *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */ + return hRes; + } + VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff); + if (!strcmpiW(strIn, szBuff)) + { + *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */ + return hRes; + } + } + + if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT)) + { + /* We have checked the localised text, now check English */ + langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); + goto VarBoolFromStr_CheckLocalised; + } + + /* All checks against localised text have failed, try #TRUE#/#FALSE# */ + if (!strcmpW(strIn, szFalse)) + *pBoolOut = VARIANT_FALSE; + else if (!strcmpW(strIn, szTrue)) + *pBoolOut = VARIANT_TRUE; + else + { + double d; + + /* If this string is a number, convert it as one */ + hRes = _VarR8FromStr(strIn, lcid, dwFlags, &d); + if (SUCCEEDED(hRes)) + hRes = _VarBoolFromR8(d, pBoolOut); + } + return hRes; +} + +/************************************************************************ + * VarBoolFromDisp (OLEAUT32.126) + * + * Convert a VT_DISPATCH to a VT_BOOL. + * + * PARAMS + * pdispIn [I] Source + * lcid [I] LCID for conversion + * pBoolOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut) +{ + return _VarBoolFromDisp(pdispIn, lcid, pBoolOut); +} + +/************************************************************************ + * VarBoolFromI1 (OLEAUT32.233) + * + * Convert a VT_I1 to a VT_BOOL. + * + * PARAMS + * cIn [I] Source + * pBoolOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut) +{ + return _VarBoolFromI1(cIn, pBoolOut); +} + +/************************************************************************ + * VarBoolFromUI2 (OLEAUT32.234) + * + * Convert a VT_UI2 to a VT_BOOL. + * + * PARAMS + * usIn [I] Source + * pBoolOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut) +{ + return _VarBoolFromUI2(usIn, pBoolOut); +} + +/************************************************************************ + * VarBoolFromUI4 (OLEAUT32.235) + * + * Convert a VT_UI4 to a VT_BOOL. + * + * PARAMS + * ulIn [I] Source + * pBoolOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut) +{ + return _VarBoolFromUI4(ulIn, pBoolOut); +} + +/************************************************************************ + * VarBoolFromDec (OLEAUT32.236) + * + * Convert a VT_DECIMAL to a VT_BOOL. + * + * PARAMS + * pDecIn [I] Source + * pBoolOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if pDecIn is invalid. + */ +HRESULT WINAPI VarBoolFromDec(DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut) +{ + if (DEC_SCALE(pDecIn) > DEC_MAX_SCALE || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)) + return E_INVALIDARG; + + if (DEC_HI32(pDecIn) || DEC_MID32(pDecIn) || DEC_LO32(pDecIn)) + *pBoolOut = VARIANT_TRUE; + else + *pBoolOut = VARIANT_FALSE; + return S_OK; +} + +/************************************************************************ + * VarBoolFromI8 (OLEAUT32.370) + * + * Convert a VT_I8 to a VT_BOOL. + * + * PARAMS + * ullIn [I] Source + * pBoolOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut) +{ + return _VarBoolFromI8(llIn, pBoolOut); +} + +/************************************************************************ + * VarBoolFromUI8 (OLEAUT32.371) + * + * Convert a VT_UI8 to a VT_BOOL. + * + * PARAMS + * ullIn [I] Source + * pBoolOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut) +{ + return _VarBoolFromUI8(ullIn, pBoolOut); +} + +/* BSTR + */ + +/* Write a number from a UI8 and sign */ +static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut) +{ + do + { + WCHAR ulNextDigit = ulVal % 10; + + *szOut-- = '0' + ulNextDigit; + ulVal = (ulVal - ulNextDigit) / 10; + } while (ulVal); + + szOut++; + return szOut; +} + +/* Create a (possibly localised) BSTR from a UI8 and sign */ +static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut) +{ + WCHAR szConverted[256]; + + if (dwFlags & VAR_NEGATIVE) + *--szOut = '-'; + + if (dwFlags & LOCALE_USE_NLS) + { + /* Format the number for the locale */ + szConverted[0] = '\0'; + GetNumberFormatW(lcid, + dwFlags & LOCALE_NOUSEROVERRIDE, + szOut, NULL, szConverted, sizeof(szConverted)/sizeof(WCHAR)); + szOut = szConverted; + } + return SysAllocStringByteLen((LPCSTR)szOut, strlenW(szOut) * sizeof(WCHAR)); +} + +/* Create a (possibly localised) BSTR from a UI8 and sign */ +static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut) +{ + WCHAR szBuff[64], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1; + + if (!pbstrOut) + return E_INVALIDARG; + + /* Create the basic number string */ + *szOut-- = '\0'; + szOut = VARIANT_WriteNumber(ulVal, szOut); + + *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut); + TRACE("returning %s\n", debugstr_w(*pbstrOut)); + return *pbstrOut ? S_OK : E_OUTOFMEMORY; +} + +/****************************************************************************** + * VarBstrFromUI1 (OLEAUT32.108) + * + * Convert a VT_UI1 to a VT_BSTR. + * + * PARAMS + * bIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pbstrOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if pbstrOut is invalid. + * E_OUTOFMEMORY, if memory allocation fails. + */ +HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) +{ + return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut); +} + +/****************************************************************************** + * VarBstrFromI2 (OLEAUT32.109) + * + * Convert a VT_I2 to a VT_BSTR. + * + * PARAMS + * sIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pbstrOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if pbstrOut is invalid. + * E_OUTOFMEMORY, if memory allocation fails. + */ +HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) +{ + ULONG64 ul64 = sIn; + + if (sIn < 0) + { + ul64 = -sIn; + dwFlags |= VAR_NEGATIVE; + } + return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut); +} + +/****************************************************************************** + * VarBstrFromI4 (OLEAUT32.110) + * + * Convert a VT_I4 to a VT_BSTR. + * + * PARAMS + * lIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pbstrOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if pbstrOut is invalid. + * E_OUTOFMEMORY, if memory allocation fails. + */ +HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) +{ + ULONG64 ul64 = lIn; + + if (lIn < 0) + { + ul64 = (ULONG)-lIn; + dwFlags |= VAR_NEGATIVE; + } + return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut); +} + +static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags, + BSTR* pbstrOut, LPCWSTR lpszFormat) +{ + WCHAR buff[256]; + + if (!pbstrOut) + return E_INVALIDARG; + + sprintfW( buff, lpszFormat, dblIn ); + TRACE("created string %s\n", debugstr_w(buff)); + if (dwFlags & LOCALE_USE_NLS) + { + WCHAR numbuff[256]; + + /* Format the number for the locale */ + numbuff[0] = '\0'; + GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE, + buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR)); + TRACE("created NLS string %s\n", debugstr_w(numbuff)); + *pbstrOut = SysAllocString(numbuff); + } + else + *pbstrOut = SysAllocString(buff); + return *pbstrOut ? S_OK : E_OUTOFMEMORY; +} + +/****************************************************************************** + * VarBstrFromR4 (OLEAUT32.111) + * + * Convert a VT_R4 to a VT_BSTR. + * + * PARAMS + * fltIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pbstrOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if pbstrOut is invalid. + * E_OUTOFMEMORY, if memory allocation fails. + */ +HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) +{ + return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, szFloatFormatW); +} + +/****************************************************************************** + * VarBstrFromR8 (OLEAUT32.112) + * + * Convert a VT_R8 to a VT_BSTR. + * + * PARAMS + * dblIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pbstrOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if pbstrOut is invalid. + * E_OUTOFMEMORY, if memory allocation fails. + */ +HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) +{ + return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, szDoubleFormatW); +} + +/****************************************************************************** + * VarBstrFromCy [OLEAUT32.113] + * + * Convert a VT_CY to a VT_BSTR. + * + * PARAMS + * cyIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pbstrOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if pbstrOut is invalid. + * E_OUTOFMEMORY, if memory allocation fails. + */ +HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) +{ + WCHAR buff[256]; + double dblVal; + + if (!pbstrOut) + return E_INVALIDARG; + + VarR8FromCy(cyIn, &dblVal); + sprintfW(buff, szDoubleFormatW, dblVal); + + if (dwFlags & LOCALE_USE_NLS) + { + WCHAR cybuff[256]; + + /* Format the currency for the locale */ + cybuff[0] = '\0'; + GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE, + buff, NULL, cybuff, sizeof(cybuff) / sizeof(WCHAR)); + *pbstrOut = SysAllocString(cybuff); + } + else + *pbstrOut = SysAllocString(buff); + + return *pbstrOut ? S_OK : E_OUTOFMEMORY; +} + +/****************************************************************************** + * VarBstrFromDate [OLEAUT32.114] + * + * Convert a VT_DATE to a VT_BSTR. + * + * PARAMS + * dateIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pbstrOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid. + * E_OUTOFMEMORY, if memory allocation fails. + */ +HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) +{ + SYSTEMTIME st; + DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE; + WCHAR date[128], *time; + + TRACE("(%g,0x%08lx,0x%08lx,%p)\n", dateIn, lcid, dwFlags, pbstrOut); + + if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st)) + return E_INVALIDARG; + + *pbstrOut = NULL; + + if (dwFlags & VAR_CALENDAR_THAI) + st.wYear += 553; /* Use the Thai buddhist calendar year */ + else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN)) + FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n"); + + if (dwFlags & LOCALE_USE_NLS) + dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY); + else + { + double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn); + double partial = dateIn - whole; + + if (whole == 0.0) + dwFlags |= VAR_TIMEVALUEONLY; + else if (partial < 1e-12) + dwFlags |= VAR_DATEVALUEONLY; + } + + if (dwFlags & VAR_TIMEVALUEONLY) + date[0] = '\0'; + else + if (!GetDateFormatW(lcid, dwFormatFlags|DATE_SHORTDATE, &st, NULL, date, + sizeof(date)/sizeof(WCHAR))) + return E_INVALIDARG; + + if (!(dwFlags & VAR_DATEVALUEONLY)) + { + time = date + strlenW(date); + if (time != date) + *time++ = ' '; + if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time, + sizeof(date)/sizeof(WCHAR)-(time-date))) + return E_INVALIDARG; + } + + *pbstrOut = SysAllocString(date); + if (*pbstrOut) + TRACE("returning %s\n", debugstr_w(*pbstrOut)); + return *pbstrOut ? S_OK : E_OUTOFMEMORY; +} + +/****************************************************************************** + * VarBstrFromBool (OLEAUT32.116) + * + * Convert a VT_BOOL to a VT_BSTR. + * + * PARAMS + * boolIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pbstrOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if pbstrOut is invalid. + * E_OUTOFMEMORY, if memory allocation fails. + * + * NOTES + * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the + * localised text of "True" or "False". To convert a bool into a + * numeric string of "0" or "-1", use VariantChangeTypeTypeEx(). + */ +HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) +{ + WCHAR szBuff[64]; + DWORD dwResId = IDS_TRUE; + LANGID langId; + + TRACE("%d,0x%08lx,0x%08lx,%p\n", boolIn, lcid, dwFlags, pbstrOut); + + if (!pbstrOut) + return E_INVALIDARG; + + /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used + * for variant formatting */ + switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO)) + { + case VAR_BOOLONOFF: + dwResId = IDS_ON; + break; + case VAR_BOOLYESNO: + dwResId = IDS_YES; + break; + case VAR_LOCALBOOL: + break; + default: + lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT); + } + + lcid = ConvertDefaultLocale(lcid); + langId = LANGIDFROMLCID(lcid); + if (PRIMARYLANGID(langId) == LANG_NEUTRAL) + langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); + + if (boolIn == VARIANT_FALSE) + dwResId++; /* Use negative form */ + +VarBstrFromBool_GetLocalised: + if (VARIANT_GetLocalisedText(langId, dwResId, szBuff)) + { + *pbstrOut = SysAllocString(szBuff); + return *pbstrOut ? S_OK : E_OUTOFMEMORY; + } + + if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT)) + { + langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT); + goto VarBstrFromBool_GetLocalised; + } + + /* Should never get here */ + WARN("Failed to load bool text!\n"); + return E_OUTOFMEMORY; +} + +/****************************************************************************** + * VarBstrFromI1 (OLEAUT32.229) + * + * Convert a VT_I1 to a VT_BSTR. + * + * PARAMS + * cIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pbstrOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if pbstrOut is invalid. + * E_OUTOFMEMORY, if memory allocation fails. + */ +HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) +{ + ULONG64 ul64 = cIn; + + if (cIn < 0) + { + ul64 = -cIn; + dwFlags |= VAR_NEGATIVE; + } + return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut); +} + +/****************************************************************************** + * VarBstrFromUI2 (OLEAUT32.230) + * + * Convert a VT_UI2 to a VT_BSTR. + * + * PARAMS + * usIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pbstrOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if pbstrOut is invalid. + * E_OUTOFMEMORY, if memory allocation fails. + */ +HRESULT WINAPI VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) +{ + return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut); +} + +/****************************************************************************** + * VarBstrFromUI4 (OLEAUT32.231) + * + * Convert a VT_UI4 to a VT_BSTR. + * + * PARAMS + * ulIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pbstrOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if pbstrOut is invalid. + * E_OUTOFMEMORY, if memory allocation fails. + */ +HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) +{ + return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut); +} + +/****************************************************************************** + * VarBstrFromDec (OLEAUT32.232) + * + * Convert a VT_DECIMAL to a VT_BSTR. + * + * PARAMS + * pDecIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pbstrOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if pbstrOut is invalid. + * E_OUTOFMEMORY, if memory allocation fails. + */ +HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) +{ + if (!pbstrOut) + return E_INVALIDARG; + + if (!DEC_SCALE(pDecIn) && !DEC_HI32(pDecIn)) + { + WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1; + + /* Create the basic number string */ + *szOut-- = '\0'; + szOut = VARIANT_WriteNumber(DEC_LO64(pDecIn), szOut); + if (DEC_SIGN(pDecIn)) + dwFlags |= VAR_NEGATIVE; + + *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut); + TRACE("returning %s\n", debugstr_w(*pbstrOut)); + return *pbstrOut ? S_OK : E_OUTOFMEMORY; + } + FIXME("semi-stub\n"); + return E_INVALIDARG; +} + +/************************************************************************ + * VarBstrFromI8 (OLEAUT32.370) + * + * Convert a VT_I8 to a VT_BSTR. + * + * PARAMS + * llIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pbstrOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if pbstrOut is invalid. + * E_OUTOFMEMORY, if memory allocation fails. + */ +HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) +{ + ULONG64 ul64 = llIn; + + if (llIn < 0) + { + ul64 = -llIn; + dwFlags |= VAR_NEGATIVE; + } + return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut); +} + +/************************************************************************ + * VarBstrFromUI8 (OLEAUT32.371) + * + * Convert a VT_UI8 to a VT_BSTR. + * + * PARAMS + * ullIn [I] Source + * lcid [I] LCID for the conversion + * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h") + * pbstrOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if pbstrOut is invalid. + * E_OUTOFMEMORY, if memory allocation fails. + */ +HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut) +{ + return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut); +} + +/********************************************************************** + * VarBstrCat (OLEAUT32.313) + * + * Concatenate two BSTR values. + * + * PARAMS + * pbstrLeft [I] Source + * pbstrRight [I] Value to concatenate + * pbstrOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if pbstrOut is invalid. + * E_OUTOFMEMORY, if memory allocation fails. + */ +HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut) +{ + unsigned int len; + + if (!pbstrOut) + return E_INVALIDARG; + + len = pbstrLeft ? strlenW(pbstrLeft) : 0; + if (pbstrRight) + len += strlenW(pbstrRight); + + *pbstrOut = SysAllocStringLen(NULL, len); + if (!*pbstrOut) + return E_OUTOFMEMORY; + + (*pbstrOut)[0] = '\0'; + + if (pbstrLeft) + strcpyW(*pbstrOut, pbstrLeft); + + if (pbstrRight) + strcatW(*pbstrOut, pbstrRight); + + return S_OK; +} + +/********************************************************************** + * VarBstrCmp (OLEAUT32.314) + * + * Compare two BSTR values. + * + * PARAMS + * pbstrLeft [I] Source + * pbstrRight [I] Value to compare + * lcid [I] LCID for the comparison + * dwFlags [I] Flags to pass directly to CompareStringW(). + * + * RETURNS + * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less + * than, equal to or greater than pbstrRight respectively. + * VARCMP_NULL is returned if either string is NULL, unless both are NULL + * in which case VARCMP_EQ is returned. + */ +HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags) +{ + if (!pbstrLeft) + { + if (!pbstrRight || !*pbstrRight) + return VARCMP_EQ; + return VARCMP_NULL; + } + else if (!pbstrRight) + { + if (!*pbstrLeft) + return VARCMP_EQ; + return VARCMP_NULL; + } + + return CompareStringW(lcid, dwFlags, pbstrLeft, -1, pbstrRight, -1) - 1; +} + +/* + * DATE + */ + +/****************************************************************************** + * VarDateFromUI1 (OLEAUT32.88) + * + * Convert a VT_UI1 to a VT_DATE. + * + * PARAMS + * bIn [I] Source + * pdateOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut) +{ + return _VarDateFromUI1(bIn, pdateOut); +} + +/****************************************************************************** + * VarDateFromI2 (OLEAUT32.89) + * + * Convert a VT_I2 to a VT_DATE. + * + * PARAMS + * sIn [I] Source + * pdateOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut) +{ + return _VarDateFromI2(sIn, pdateOut); +} + +/****************************************************************************** + * VarDateFromI4 (OLEAUT32.90) + * + * Convert a VT_I4 to a VT_DATE. + * + * PARAMS + * lIn [I] Source + * pdateOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut) +{ + return _VarDateFromI4(lIn, pdateOut); +} + +/****************************************************************************** + * VarDateFromR4 (OLEAUT32.91) + * + * Convert a VT_R4 to a VT_DATE. + * + * PARAMS + * fltIn [I] Source + * pdateOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut) +{ + return _VarDateFromR4(fltIn, pdateOut); +} + +/****************************************************************************** + * VarDateFromR8 (OLEAUT32.92) + * + * Convert a VT_R8 to a VT_DATE. + * + * PARAMS + * dblIn [I] Source + * pdateOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut) +{ + return _VarDateFromR8(dblIn, pdateOut); +} + +/********************************************************************** + * VarDateFromDisp (OLEAUT32.95) + * + * Convert a VT_DISPATCH to a VT_DATE. + * + * PARAMS + * pdispIn [I] Source + * lcid [I] LCID for conversion + * pdateOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if the source value is invalid + * DISP_E_OVERFLOW, if the value will not fit in the destination + * DISP_E_TYPEMISMATCH, if the type cannot be converted + */ +HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut) +{ + return _VarDateFromDisp(pdispIn, lcid, pdateOut); +} + +/****************************************************************************** + * VarDateFromBool (OLEAUT32.96) + * + * Convert a VT_BOOL to a VT_DATE. + * + * PARAMS + * boolIn [I] Source + * pdateOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut) +{ + return _VarDateFromBool(boolIn, pdateOut); +} + +/********************************************************************** + * VarDateFromCy (OLEAUT32.93) + * + * Convert a VT_CY to a VT_DATE. + * + * PARAMS + * lIn [I] Source + * pdateOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) +{ + return _VarDateFromCy(cyIn, pdateOut); +} + +/* Date string parsing */ +#define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */ +#define DP_DATESEP 0x02 /* Date separator */ +#define DP_MONTH 0x04 /* Month name */ +#define DP_AM 0x08 /* AM */ +#define DP_PM 0x10 /* PM */ + +typedef struct tagDATEPARSE +{ + DWORD dwCount; /* Number of fields found so far (maximum 6) */ + DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */ + DWORD dwFlags[6]; /* Flags for each field */ + DWORD dwValues[6]; /* Value of each field */ +} DATEPARSE; + +#define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i) + +#define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0))) + +/* Determine if a day is valid in a given month of a given year */ +static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year) +{ + static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + + if (day && month && month < 13) + { + if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year))) + return TRUE; + } + return FALSE; +} + +/* Possible orders for 3 numbers making up a date */ +#define ORDER_MDY 0x01 +#define ORDER_YMD 0x02 +#define ORDER_YDM 0x04 +#define ORDER_DMY 0x08 +#define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */ + +/* Determine a date for a particular locale, from 3 numbers */ +static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate, + DWORD offset, SYSTEMTIME *st) +{ + DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3; + + if (!dp->dwCount) + { + v1 = 30; /* Default to (Variant) 0 date part */ + v2 = 12; + v3 = 1899; + goto VARIANT_MakeDate_OK; + } + + v1 = dp->dwValues[offset + 0]; + v2 = dp->dwValues[offset + 1]; + if (dp->dwCount == 2) + { + SYSTEMTIME current; + GetSystemTime(¤t); + v3 = current.wYear; + } + else + v3 = dp->dwValues[offset + 2]; + + TRACE("(%ld,%ld,%ld,%ld,%ld)\n", v1, v2, v3, iDate, offset); + + /* If one number must be a month (Because a month name was given), then only + * consider orders with the month in that position. + * If we took the current year as 'v3', then only allow a year in that position. + */ + if (dp->dwFlags[offset + 0] & DP_MONTH) + { + dwAllOrders = ORDER_MDY; + } + else if (dp->dwFlags[offset + 1] & DP_MONTH) + { + dwAllOrders = ORDER_DMY; + if (dp->dwCount > 2) + dwAllOrders |= ORDER_YMD; + } + else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH) + { + dwAllOrders = ORDER_YDM; + } + else + { + dwAllOrders = ORDER_MDY|ORDER_DMY; + if (dp->dwCount > 2) + dwAllOrders |= (ORDER_YMD|ORDER_YDM); + } + +VARIANT_MakeDate_Start: + TRACE("dwAllOrders is 0x%08lx\n", dwAllOrders); + + while (dwAllOrders) + { + DWORD dwTemp; + + if (dwCount == 0) + { + /* First: Try the order given by iDate */ + switch (iDate) + { + case 0: dwTry = dwAllOrders & ORDER_MDY; break; + case 1: dwTry = dwAllOrders & ORDER_DMY; break; + default: dwTry = dwAllOrders & ORDER_YMD; break; + } + } + else if (dwCount == 1) + { + /* Second: Try all the orders compatible with iDate */ + switch (iDate) + { + case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break; + case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YMD|ORDER_MYD); break; + default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break; + } + } + else + { + /* Finally: Try any remaining orders */ + dwTry = dwAllOrders; + } + + TRACE("Attempt %ld, dwTry is 0x%08lx\n", dwCount, dwTry); + + dwCount++; + if (!dwTry) + continue; + +#define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0) + + if (dwTry & ORDER_MDY) + { + if (VARIANT_IsValidMonthDay(v2,v1,v3)) + { + DATE_SWAP(v1,v2); + goto VARIANT_MakeDate_OK; + } + dwAllOrders &= ~ORDER_MDY; + } + if (dwTry & ORDER_YMD) + { + if (VARIANT_IsValidMonthDay(v3,v2,v1)) + { + DATE_SWAP(v1,v3); + goto VARIANT_MakeDate_OK; + } + dwAllOrders &= ~ORDER_YMD; + } + if (dwTry & ORDER_YDM) + { + if (VARIANT_IsValidMonthDay(v2,v3,v1)) + { + DATE_SWAP(v1,v2); + DATE_SWAP(v2,v3); + goto VARIANT_MakeDate_OK; + } + dwAllOrders &= ~ORDER_YDM; + } + if (dwTry & ORDER_DMY) + { + if (VARIANT_IsValidMonthDay(v1,v2,v3)) + goto VARIANT_MakeDate_OK; + dwAllOrders &= ~ORDER_DMY; + } + if (dwTry & ORDER_MYD) + { + /* Only occurs if we are trying a 2 year date as M/Y not D/M */ + if (VARIANT_IsValidMonthDay(v3,v1,v2)) + { + DATE_SWAP(v1,v3); + DATE_SWAP(v2,v3); + goto VARIANT_MakeDate_OK; + } + dwAllOrders &= ~ORDER_MYD; + } + } + + if (dp->dwCount == 2) + { + /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */ + v3 = 1; /* 1st of the month */ + dwAllOrders = ORDER_YMD|ORDER_MYD; + dp->dwCount = 0; /* Don't return to this code path again */ + dwCount = 0; + goto VARIANT_MakeDate_Start; + } + + /* No valid dates were able to be constructed */ + return DISP_E_TYPEMISMATCH; + +VARIANT_MakeDate_OK: + + /* Check that the time part is ok */ + if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59) + return DISP_E_TYPEMISMATCH; + + TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond); + if (st->wHour < 12 && (dp->dwParseFlags & DP_PM)) + st->wHour += 12; + else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM)) + st->wHour = 0; + TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond); + + st->wDay = v1; + st->wMonth = v2; + /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may + * be retrieved from: + * HKCU\Control Panel\International\Calendars\TwoDigitYearMax + * But Wine doesn't have/use that key as at the time of writing. + */ + st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3; + TRACE("Returning date %ld/%ld/%d\n", v1, v2, st->wYear); + return S_OK; +} + +/****************************************************************************** + * VarDateFromStr [OLEAUT32.94] + * + * Convert a VT_BSTR to at VT_DATE. + * + * PARAMS + * strIn [I] String to convert + * lcid [I] Locale identifier for the conversion + * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h") + * pdateOut [O] Destination for the converted value + * + * RETURNS + * Success: S_OK. pdateOut contains the converted value. + * FAILURE: An HRESULT error code indicating the prolem. + * + * NOTES + * Any date format that can be created using the date formats from lcid + * (Either from kernel Nls functions, variant conversion or formatting) is a + * valid input to this function. In addition, a few more esoteric formats are + * also supported for compatibility with the native version. The date is + * interpreted according to the date settings in the control panel, unless + * the date is invalid in that format, in which the most compatible format + * that produces a valid date will be used. + */ +HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut) +{ + static const USHORT ParseDateTokens[] = + { + LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4, + LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, + LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12, + LOCALE_SMONTHNAME13, + LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3, + LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6, + LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9, + LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12, + LOCALE_SABBREVMONTHNAME13, + LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4, + LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7, + LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, + LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6, + LOCALE_SABBREVDAYNAME7, + LOCALE_S1159, LOCALE_S2359 + }; + static const BYTE ParseDateMonths[] = + { + 1,2,3,4,5,6,7,8,9,10,11,12,13, + 1,2,3,4,5,6,7,8,9,10,11,12,13 + }; + size_t i; + BSTR tokens[sizeof(ParseDateTokens)/sizeof(ParseDateTokens[0])]; + DATEPARSE dp; + DWORD dwDateSeps = 0, iDate = 0; + HRESULT hRet = S_OK; + + if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) == + (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) + return E_INVALIDARG; + + if (!strIn) + return DISP_E_TYPEMISMATCH; + + *pdateOut = 0.0; + + TRACE("(%s,0x%08lx,0x%08lx,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut); + + memset(&dp, 0, sizeof(dp)); + + GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE), + (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR)); + TRACE("iDate is %ld\n", iDate); + + /* Get the month/day/am/pm tokens for this locale */ + for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++) + { + WCHAR buff[128]; + LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE); + + /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or + * GetAltMonthNames(). We should really cache these strings too. + */ + buff[0] = '\0'; + GetLocaleInfoW(lcid, lctype, buff, sizeof(buff)/sizeof(WCHAR)); + tokens[i] = SysAllocString(buff); + TRACE("token %d is %s\n", i, debugstr_w(tokens[i])); + } + + /* Parse the string into our structure */ + while (*strIn) + { + if (dp.dwCount > 6) + break; + + if (isdigitW(*strIn)) + { + dp.dwValues[dp.dwCount] = strtoulW(strIn, &strIn, 10); + dp.dwCount++; + strIn--; + } + else if (isalpha(*strIn)) + { + BOOL bFound = FALSE; + + for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++) + { + DWORD dwLen = strlenW(tokens[i]); + if (dwLen && !strncmpiW(strIn, tokens[i], dwLen)) + { + if (i <= 25) + { + dp.dwValues[dp.dwCount] = ParseDateMonths[i]; + dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP); + dp.dwCount++; + } + else if (i > 39) + { + if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM)) + hRet = DISP_E_TYPEMISMATCH; + else + { + dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM); + dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM); + } + } + strIn += (dwLen - 1); + bFound = TRUE; + break; + } + } + + if (!bFound) + { + if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') && + (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM)))) + { + /* Special case - 'a' and 'p' are recognised as short for am/pm */ + if (*strIn == 'a' || *strIn == 'A') + { + dp.dwFlags[dp.dwCount - 1] |= DP_AM; + dp.dwParseFlags |= DP_AM; + } + else + { + dp.dwFlags[dp.dwCount - 1] |= DP_PM; + dp.dwParseFlags |= DP_PM; + } + strIn++; + } + else + { + TRACE("No matching token for %s\n", debugstr_w(strIn)); + hRet = DISP_E_TYPEMISMATCH; + break; + } + } + } + else if (*strIn == ':' || *strIn == '.') + { + if (!dp.dwCount || !strIn[1]) + hRet = DISP_E_TYPEMISMATCH; + else + dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP; + } + else if (*strIn == '-' || *strIn == '/') + { + dwDateSeps++; + if (dwDateSeps > 2 || !dp.dwCount || !strIn[1]) + hRet = DISP_E_TYPEMISMATCH; + else + dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP; + } + else if (*strIn == ',' || isspaceW(*strIn)) + { + if (*strIn == ',' && !strIn[1]) + hRet = DISP_E_TYPEMISMATCH; + } + else + { + hRet = DISP_E_TYPEMISMATCH; + } + strIn++; + } + + if (!dp.dwCount || dp.dwCount > 6 || + (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM)))) + hRet = DISP_E_TYPEMISMATCH; + + if (SUCCEEDED(hRet)) + { + SYSTEMTIME st; + DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */ + + st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0; + + /* Figure out which numbers correspond to which fields. + * + * This switch statement works based on the fact that native interprets any + * fields that are not joined with a time separator ('.' or ':') as date + * fields. Thus we construct a value from 0-32 where each set bit indicates + * a time field. This encapsulates the hundreds of permutations of 2-6 fields. + * For valid permutations, we set dwOffset to point to the first date field + * and shorten dp.dwCount by the number of time fields found. The real + * magic here occurs in VARIANT_MakeDate() above, where we determine what + * each date number must represent in the context of iDate. + */ + TRACE("0x%08lx\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4)); + + switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4)) + { + case 0x1: /* TT TTDD TTDDD */ + if (dp.dwCount > 3 && + ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) || + (dp.dwFlags[4] & (DP_AM|DP_PM)))) + hRet = DISP_E_TYPEMISMATCH; + else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5) + hRet = DISP_E_TYPEMISMATCH; + st.wHour = dp.dwValues[0]; + st.wMinute = dp.dwValues[1]; + dp.dwCount -= 2; + dwOffset = 2; + break; + + case 0x3: /* TTT TTTDD TTTDDD */ + if (dp.dwCount > 4 && + ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) || + (dp.dwFlags[5] & (DP_AM|DP_PM)))) + hRet = DISP_E_TYPEMISMATCH; + else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6) + hRet = DISP_E_TYPEMISMATCH; + st.wHour = dp.dwValues[0]; + st.wMinute = dp.dwValues[1]; + st.wSecond = dp.dwValues[2]; + dwOffset = 3; + dp.dwCount -= 3; + break; + + case 0x4: /* DDTT */ + if (dp.dwCount != 4 || + (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM))) + hRet = DISP_E_TYPEMISMATCH; + + st.wHour = dp.dwValues[2]; + st.wMinute = dp.dwValues[3]; + dp.dwCount -= 2; + break; + + case 0x0: /* T DD DDD TDDD TDDD */ + if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM))) + { + st.wHour = dp.dwValues[0]; /* T */ + dp.dwCount = 0; + break; + } + else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM))) + { + hRet = DISP_E_TYPEMISMATCH; + } + else if (dp.dwCount == 3) + { + if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */ + { + dp.dwCount = 2; + st.wHour = dp.dwValues[0]; + dwOffset = 1; + break; + } + if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */ + { + dp.dwCount = 2; + st.wHour = dp.dwValues[2]; + break; + } + else if (dp.dwParseFlags & (DP_AM|DP_PM)) + hRet = DISP_E_TYPEMISMATCH; + } + else if (dp.dwCount == 4) + { + dp.dwCount = 3; + if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */ + { + st.wHour = dp.dwValues[0]; + dwOffset = 1; + } + else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */ + { + st.wHour = dp.dwValues[3]; + } + else + hRet = DISP_E_TYPEMISMATCH; + break; + } + /* .. fall through .. */ + + case 0x8: /* DDDTT */ + if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) || + (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) || + (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) || + dp.dwCount == 4 || dp.dwCount == 6) + hRet = DISP_E_TYPEMISMATCH; + st.wHour = dp.dwValues[3]; + st.wMinute = dp.dwValues[4]; + if (dp.dwCount == 5) + dp.dwCount -= 2; + break; + + case 0xC: /* DDTTT */ + if (dp.dwCount != 5 || + (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM))) + hRet = DISP_E_TYPEMISMATCH; + st.wHour = dp.dwValues[2]; + st.wMinute = dp.dwValues[3]; + st.wSecond = dp.dwValues[4]; + dp.dwCount -= 3; + break; + + case 0x18: /* DDDTTT */ + if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) || + (dp.dwFlags[2] & (DP_AM|DP_PM))) + hRet = DISP_E_TYPEMISMATCH; + st.wHour = dp.dwValues[3]; + st.wMinute = dp.dwValues[4]; + st.wSecond = dp.dwValues[5]; + dp.dwCount -= 3; + break; + + default: + hRet = DISP_E_TYPEMISMATCH; + break; + } + + if (SUCCEEDED(hRet)) + { + hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st); + + if (dwFlags & VAR_TIMEVALUEONLY) + { + st.wYear = 1899; + st.wMonth = 12; + st.wDay = 30; + } + else if (dwFlags & VAR_DATEVALUEONLY) + st.wHour = st.wMinute = st.wSecond = 0; + + /* Finally, convert the value to a VT_DATE */ + if (SUCCEEDED(hRet)) + hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH; + } + } + + for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++) + SysFreeString(tokens[i]); + return hRet; +} + +/****************************************************************************** + * VarDateFromI1 (OLEAUT32.221) + * + * Convert a VT_I1 to a VT_DATE. + * + * PARAMS + * cIn [I] Source + * pdateOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut) +{ + return _VarDateFromI1(cIn, pdateOut); +} + +/****************************************************************************** + * VarDateFromUI2 (OLEAUT32.222) + * + * Convert a VT_UI2 to a VT_DATE. + * + * PARAMS + * uiIn [I] Source + * pdateOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut) +{ + return _VarDateFromUI2(uiIn, pdateOut); +} + +/****************************************************************************** + * VarDateFromUI4 (OLEAUT32.223) + * + * Convert a VT_UI4 to a VT_DATE. + * + * PARAMS + * ulIn [I] Source + * pdateOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut) +{ + return _VarDateFromUI4(ulIn, pdateOut); +} + +/********************************************************************** + * VarDateFromDec (OLEAUT32.224) + * + * Convert a VT_DECIMAL to a VT_DATE. + * + * PARAMS + * pdecIn [I] Source + * pdateOut [O] Destination + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut) +{ + return _VarDateFromDec(pdecIn, pdateOut); +} + +/****************************************************************************** + * VarDateFromI8 (OLEAUT32.364) + * + * Convert a VT_I8 to a VT_DATE. + * + * PARAMS + * llIn [I] Source + * pdateOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut) +{ + return _VarDateFromI8(llIn, pdateOut); +} + +/****************************************************************************** + * VarDateFromUI8 (OLEAUT32.365) + * + * Convert a VT_UI8 to a VT_DATE. + * + * PARAMS + * ullIn [I] Source + * pdateOut [O] Destination + * + * RETURNS + * Success: S_OK. + * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination + */ +HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut) +{ + return _VarDateFromUI8(ullIn, pdateOut); +} diff --git a/reactos/lib/oledlg/insobjdlg.c b/reactos/lib/oledlg/insobjdlg.c index 0d4a2cd41e7..88259264ea1 100644 --- a/reactos/lib/oledlg/insobjdlg.c +++ b/reactos/lib/oledlg/insobjdlg.c @@ -1,628 +1,628 @@ -/* - * OLEDLG library - * - * Copyright 2003 Ulrich Czekalla for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> -#include <stdio.h> - -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "winternl.h" -#include "winnls.h" -#include "winerror.h" -#include "wingdi.h" -#include "winuser.h" -#include "wine/debug.h" -#include "wine/unicode.h" - -#include "oledlg.h" -#include "resource.h" - -WINE_DEFAULT_DEBUG_CHANNEL(oledlg); - -typedef struct -{ - HWND hwndSelf; - BOOL bObjListInit; /* Object list has been initialized */ - LPOLEUIINSERTOBJECTA lpOleUIInsertObject; - - HWND hwndObjTypeLBL; - HWND hwndObjTypeLB; - HWND hwndFileLBL; - HWND hwndFileTB; - HWND hwndCreateCtrlCB; - HWND hwndCreateNewCB; - HWND hwndCreateFromFileCB; - HWND hwndDisplayIconCB; - HWND hwndAddCtrlBTN; - HWND hwndBrowseBTN; - HWND hwndResultDesc; - -} InsertObjectDlgInfo; - -INT_PTR CALLBACK UIInsertObjectDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); -static LRESULT UIINSOBJDLG_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam); -static void UIINSERTOBJECTDLG_InitDialog(InsertObjectDlgInfo* pdlgInfo); -static void UIINSERTOBJECTDLG_SelectCreateCtrl(InsertObjectDlgInfo* pdlgInfo); -static void UIINSERTOBJECTDLG_SelectCreateFromFile(InsertObjectDlgInfo* pdlgInfo); -static void UIINSERTOBJECTDLG_SelectCreateNew(InsertObjectDlgInfo* pdlgInfo); -static BOOL UIINSERTOBJECTDLG_PopulateObjectTypes(InsertObjectDlgInfo* pdlgInfo); -static void UIINSERTOBJECTDLG_FreeObjectTypes(InsertObjectDlgInfo* pdlgInfo); -static void UIINSERTOBJECTDLG_SelChange(InsertObjectDlgInfo* pdlgInfo); -static BOOL UIINSERTOBJECTDLG_OnOpen(InsertObjectDlgInfo* pdlgInfo); -static void UIINSERTOBJECTDLG_BrowseFile(InsertObjectDlgInfo* pdlgInfo); -static void UIINSERTOBJECTDLG_AddControl(InsertObjectDlgInfo* pdlgInfo); - -typedef HRESULT (*DLLREGISTER) (void); - -extern HINSTANCE OLEDLG_hInstance; -const char *OleUIInsertObjectInfoStr = "OleUIInsertObjectInfoStr"; - -/*********************************************************************** - * OleUIInsertObjectA (OLEDLG.3) - */ -UINT WINAPI OleUIInsertObjectA(LPOLEUIINSERTOBJECTA lpOleUIInsertObject) -{ - LRESULT lRes; - LPCVOID template; - HRSRC hRes; - InsertObjectDlgInfo dlgInfo; - HANDLE hDlgTmpl = 0; - - if (lpOleUIInsertObject->lpszTemplate || lpOleUIInsertObject->hResource) - FIXME("Customized template not supported\n"); - - /* Create the dialog from a template */ - if(!(hRes = FindResourceA(OLEDLG_hInstance,MAKEINTRESOURCEA(UIINSERTOBJECT), - (LPSTR)RT_DIALOG))) - { - return OLEUI_ERR_FINDTEMPLATEFAILURE; - } - - if (!(hDlgTmpl = LoadResource(OLEDLG_hInstance, hRes )) || - !(template = LockResource( hDlgTmpl ))) - { - return OLEUI_ERR_LOADTEMPLATEFAILURE; - } - - /* Initialize InsertObjectDlgInfo structure */ - dlgInfo.lpOleUIInsertObject = lpOleUIInsertObject; - dlgInfo.bObjListInit = FALSE; - - lRes = DialogBoxIndirectParamA(OLEDLG_hInstance, (const DLGTEMPLATE*) template, - lpOleUIInsertObject->hWndOwner, UIInsertObjectDlgProc, - (LPARAM) &dlgInfo); - - /* Unable to create the dialog */ - if( lRes == -1) - return OLEUI_ERR_DIALOGFAILURE; - - return lRes; -} - - -/*********************************************************************** - * UIInsertObjectDlgProc - * - * OLE UI Insert Object dialog procedure - */ -INT_PTR CALLBACK UIInsertObjectDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - InsertObjectDlgInfo* pdlgInfo = (InsertObjectDlgInfo*) GetPropA(hwnd,OleUIInsertObjectInfoStr); - - switch(uMsg) - { - case WM_INITDIALOG: - { - InsertObjectDlgInfo* pdlgInfo = (InsertObjectDlgInfo*)lParam; - - pdlgInfo->hwndSelf = hwnd; - - SetPropA(hwnd, OleUIInsertObjectInfoStr, (HANDLE) pdlgInfo); - - UIINSERTOBJECTDLG_InitDialog(pdlgInfo); - - return 0; - } - - case WM_COMMAND: - return UIINSOBJDLG_OnWMCommand(hwnd, wParam, lParam); - - case WM_DESTROY: - if (pdlgInfo) - UIINSERTOBJECTDLG_FreeObjectTypes(pdlgInfo); - RemovePropA(hwnd, OleUIInsertObjectInfoStr); - return FALSE; - - default : - return FALSE; - } -} - - -/*********************************************************************** - * UIINSOBJDLG_OnWMCommand - * - * WM_COMMAND message handler - */ -static LRESULT UIINSOBJDLG_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam) -{ - WORD wNotifyCode = HIWORD(wParam); - WORD wID = LOWORD(wParam); - InsertObjectDlgInfo* pdlgInfo = (InsertObjectDlgInfo*) GetPropA(hwnd,OleUIInsertObjectInfoStr); - - switch(wID) - { - case IDOK: - EndDialog(hwnd, UIINSERTOBJECTDLG_OnOpen(pdlgInfo)); - break; - - case IDCANCEL: - EndDialog(hwnd, FALSE); - break; - - case IDC_CREATECONTROL: - UIINSERTOBJECTDLG_SelectCreateCtrl(pdlgInfo); - break; - - case IDC_CREATENEW: - UIINSERTOBJECTDLG_SelectCreateNew(pdlgInfo); - break; - - case IDC_CREATEFROMFILE: - UIINSERTOBJECTDLG_SelectCreateFromFile(pdlgInfo); - break; - - case IDC_BROWSE: - UIINSERTOBJECTDLG_BrowseFile(pdlgInfo); - break; - - case IDC_ADDCONTROL: - UIINSERTOBJECTDLG_AddControl(pdlgInfo); - - case IDC_OBJTYPELIST: - { - if (wNotifyCode == LBN_SELCHANGE) - UIINSERTOBJECTDLG_SelChange(pdlgInfo); - break; - } - } - return 0; -} - - -/*********************************************************************** - * UIINSERTOBJECTDLG_InitDialog - * - * Initialize dialog display - */ -static void UIINSERTOBJECTDLG_InitDialog(InsertObjectDlgInfo* pdlgInfo) -{ - /* Initialize InsertObjectDlgInfo data structure */ - pdlgInfo->hwndObjTypeLB = GetDlgItem(pdlgInfo->hwndSelf, IDC_OBJTYPELIST); - pdlgInfo->hwndObjTypeLBL = GetDlgItem(pdlgInfo->hwndSelf, IDC_OBJTYPELBL); - pdlgInfo->hwndFileLBL = GetDlgItem(pdlgInfo->hwndSelf, IDC_FILELBL); - pdlgInfo->hwndFileTB = GetDlgItem(pdlgInfo->hwndSelf, IDC_FILE); - pdlgInfo->hwndCreateCtrlCB = GetDlgItem(pdlgInfo->hwndSelf, IDC_CREATECONTROL); - pdlgInfo->hwndCreateNewCB = GetDlgItem(pdlgInfo->hwndSelf, IDC_CREATENEW); - pdlgInfo->hwndCreateFromFileCB = GetDlgItem(pdlgInfo->hwndSelf, IDC_CREATEFROMFILE); - pdlgInfo->hwndDisplayIconCB = GetDlgItem(pdlgInfo->hwndSelf, IDC_ASICON); - pdlgInfo->hwndAddCtrlBTN = GetDlgItem(pdlgInfo->hwndSelf, IDC_ADDCONTROL); - pdlgInfo->hwndBrowseBTN = GetDlgItem(pdlgInfo->hwndSelf, IDC_BROWSE); - pdlgInfo->hwndResultDesc = GetDlgItem(pdlgInfo->hwndSelf, IDC_RESULTDESC); - - /* Setup dialog controls based on flags */ - if (pdlgInfo->lpOleUIInsertObject->lpszCaption) - SetWindowTextA(pdlgInfo->hwndSelf, pdlgInfo->lpOleUIInsertObject->lpszCaption); - - ShowWindow(pdlgInfo->hwndCreateCtrlCB, (pdlgInfo->lpOleUIInsertObject->dwFlags & - IOF_SHOWINSERTCONTROL) ? SW_SHOW : SW_HIDE); - ShowWindow(pdlgInfo->hwndDisplayIconCB, (pdlgInfo->lpOleUIInsertObject->dwFlags & - IOF_CHECKDISPLAYASICON) ? SW_SHOW : SW_HIDE); - EnableWindow(pdlgInfo->hwndDisplayIconCB, (pdlgInfo->lpOleUIInsertObject->dwFlags & - IOF_DISABLEDISPLAYASICON) ? FALSE : TRUE); - - if (pdlgInfo->lpOleUIInsertObject->dwFlags & IOF_SELECTCREATECONTROL) - UIINSERTOBJECTDLG_SelectCreateCtrl(pdlgInfo); - else if (pdlgInfo->lpOleUIInsertObject->dwFlags & IOF_SELECTCREATEFROMFILE) - UIINSERTOBJECTDLG_SelectCreateFromFile(pdlgInfo); - else /* (pdlgInfo->lpOleUIInsertObject->dwFlags & IOF_SELECTCREATENEW) */ - UIINSERTOBJECTDLG_SelectCreateNew(pdlgInfo); -} - - -/*********************************************************************** - * UIINSERTOBJECTDLG_SelectCreateCtrl - * - * Select Create Control Radio Button - */ -static void UIINSERTOBJECTDLG_SelectCreateCtrl(InsertObjectDlgInfo* pdlgInfo) -{ - ShowWindow(pdlgInfo->hwndDisplayIconCB, SW_HIDE); - ShowWindow(pdlgInfo->hwndFileLBL, SW_HIDE); - ShowWindow(pdlgInfo->hwndFileTB, SW_HIDE); - ShowWindow(pdlgInfo->hwndBrowseBTN, SW_HIDE); - - ShowWindow(pdlgInfo->hwndObjTypeLBL, SW_SHOW); - ShowWindow(pdlgInfo->hwndObjTypeLB, SW_SHOW); - ShowWindow(pdlgInfo->hwndAddCtrlBTN, SW_SHOW); - - SendMessageA(pdlgInfo->hwndCreateCtrlCB, BM_SETCHECK, BST_CHECKED, 0); - - /* Populate object type listbox */ - if (!pdlgInfo->bObjListInit) - UIINSERTOBJECTDLG_PopulateObjectTypes(pdlgInfo); -} - - -/*********************************************************************** - * UIINSERTOBJECTDLG_SelectCreateNew - * - * Select Create New Radio Button - */ -static void UIINSERTOBJECTDLG_SelectCreateNew(InsertObjectDlgInfo* pdlgInfo) -{ - ShowWindow(pdlgInfo->hwndFileLBL, SW_HIDE); - ShowWindow(pdlgInfo->hwndFileTB, SW_HIDE); - ShowWindow(pdlgInfo->hwndAddCtrlBTN, SW_HIDE); - ShowWindow(pdlgInfo->hwndBrowseBTN, SW_HIDE); - - if (pdlgInfo->lpOleUIInsertObject->dwFlags & IOF_CHECKDISPLAYASICON) - ShowWindow(pdlgInfo->hwndDisplayIconCB, SW_SHOW); - - ShowWindow(pdlgInfo->hwndObjTypeLBL, SW_SHOW); - ShowWindow(pdlgInfo->hwndObjTypeLB, SW_SHOW); - - SendMessageA(pdlgInfo->hwndCreateNewCB, BM_SETCHECK, BST_CHECKED, 0); - - if (!pdlgInfo->bObjListInit) - UIINSERTOBJECTDLG_PopulateObjectTypes(pdlgInfo); - - UIINSERTOBJECTDLG_SelChange(pdlgInfo); -} - - -/*********************************************************************** - * UIINSERTOBJECTDLG_SelectCreateFromFile - * - * Select Create From File Radio Button - */ -static void UIINSERTOBJECTDLG_SelectCreateFromFile(InsertObjectDlgInfo* pdlgInfo) -{ - char resstr[MAX_PATH]; - - ShowWindow(pdlgInfo->hwndAddCtrlBTN, SW_HIDE); - ShowWindow(pdlgInfo->hwndObjTypeLBL, SW_HIDE); - ShowWindow(pdlgInfo->hwndObjTypeLB, SW_HIDE); - - if (pdlgInfo->lpOleUIInsertObject->dwFlags & IOF_CHECKDISPLAYASICON) - ShowWindow(pdlgInfo->hwndDisplayIconCB, SW_SHOW); - - ShowWindow(pdlgInfo->hwndFileLBL, SW_SHOW); - ShowWindow(pdlgInfo->hwndFileTB, SW_SHOW); - ShowWindow(pdlgInfo->hwndBrowseBTN, SW_SHOW); - - SendMessageA(pdlgInfo->hwndCreateFromFileCB, BM_SETCHECK, BST_CHECKED, 0); - - if (LoadStringA(OLEDLG_hInstance, IDS_RESULTFILEOBJDESC, resstr, MAX_PATH)) - SendMessageA(pdlgInfo->hwndResultDesc, WM_SETTEXT, 0, (LPARAM)resstr); -} - - -/*********************************************************************** - * UIINSERTOBJECTDLG_PopulateObjectTypes - * - * Populate Object Type listbox - */ -static BOOL UIINSERTOBJECTDLG_PopulateObjectTypes(InsertObjectDlgInfo* pdlgInfo) -{ - DWORD i, len; - HKEY hkclsids; - HKEY hkey; - CLSID clsid; - HRESULT ret; - CHAR szclsid[128]; - CHAR keydesc[MAX_PATH]; - CHAR keyname[MAX_PATH]; - WCHAR wszclsid[128]; - DWORD index = 0; - - UIINSERTOBJECTDLG_FreeObjectTypes(pdlgInfo); - - RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_READ, &hkclsids); - - while (ERROR_SUCCESS == (ret = RegEnumKeyA(hkclsids, index, szclsid, MAX_PATH))) - { - index++; - - RegOpenKeyExA(hkclsids, szclsid, 0, KEY_READ, &hkey); - - len = MAX_PATH; - if (ERROR_SUCCESS != RegQueryValueA(hkey, "Insertable", keyname, &len)) - continue; - - len = MAX_PATH; - if (ERROR_SUCCESS == RegQueryValueA(hkey, "NotInsertable", keyname, &len)) - continue; - - RtlMultiByteToUnicodeN(wszclsid, MAX_PATH, NULL, szclsid, MAX_PATH); - CLSIDFromString(wszclsid, &clsid); - - for (i = 0; i < pdlgInfo->lpOleUIInsertObject->cClsidExclude; i++) - if (IsEqualGUID(&pdlgInfo->lpOleUIInsertObject->lpClsidExclude[i], &clsid)) - break; - - if (i < pdlgInfo->lpOleUIInsertObject->cClsidExclude) - continue; - - len = MAX_PATH; - if (ERROR_SUCCESS == RegQueryValueA(hkey, NULL, keydesc, &len)) - { - CLSID* lpclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(CLSID)); - memcpy(lpclsid, &clsid, sizeof(CLSID)); - - len = SendMessageA(pdlgInfo->hwndObjTypeLB, LB_ADDSTRING, 0, (LPARAM)keydesc); - SendMessageA(pdlgInfo->hwndObjTypeLB, LB_SETITEMDATA, (WPARAM)len, (LPARAM)lpclsid); - } - } - - pdlgInfo->bObjListInit = (ret == ERROR_NO_MORE_ITEMS); - - return pdlgInfo->bObjListInit; -} - - -/*********************************************************************** - * UIINSERTOBJECTDLG_FreeObjectTypes - * - * Free Object Types listbox - */ -static void UIINSERTOBJECTDLG_FreeObjectTypes(InsertObjectDlgInfo* pdlgInfo) -{ - UINT i, count; - - count = SendMessageA(pdlgInfo->hwndObjTypeLB, LB_GETCOUNT, (WPARAM)0, (LPARAM)0); - - for (i = 0; i < count; i++) - { - CLSID* lpclsid = (CLSID*) SendMessageA(pdlgInfo->hwndObjTypeLB, - LB_GETITEMDATA, (WPARAM)i, (LPARAM)0); - HeapFree(GetProcessHeap(), 0, lpclsid); - } -} - - -/*********************************************************************** - * UIINSERTOBJECTDLG_SelChange - * - * Handle object type selection change - */ -static void UIINSERTOBJECTDLG_SelChange(InsertObjectDlgInfo* pdlgInfo) -{ - INT index; - CHAR objname[MAX_PATH]; - CHAR objdesc[MAX_PATH]; - CHAR resstr[MAX_PATH]; - - TRACE("\n"); - - if (LoadStringA(OLEDLG_hInstance, IDS_RESULTOBJDESC, resstr, MAX_PATH) && - ((index = SendMessageA(pdlgInfo->hwndObjTypeLB, LB_GETCURSEL, 0, 0)) >= 0) && - SendMessageA(pdlgInfo->hwndObjTypeLB, LB_GETTEXT, (WPARAM)index, (LPARAM)objname)) - sprintf(objdesc, resstr, objname); - else - objdesc[0] = 0; - - SendMessageA(pdlgInfo->hwndResultDesc, WM_SETTEXT, 0, (LPARAM)objdesc); -} - - -/*********************************************************************** - * UIINSERTOBJECTDLG_SelChange - * - * Handle OK Button - */ -static BOOL UIINSERTOBJECTDLG_OnOpen(InsertObjectDlgInfo* pdlgInfo) -{ - BOOL bret = FALSE; - - if (BST_CHECKED == SendMessageA(pdlgInfo->hwndCreateCtrlCB, BM_GETCHECK, 0, 0) || - BST_CHECKED == SendMessageA(pdlgInfo->hwndCreateNewCB, BM_GETCHECK, 0, 0)) - { - INT index = SendMessageA(pdlgInfo->hwndObjTypeLB, LB_GETCURSEL, 0, 0); - - if (index >= 0) - { - CLSID* clsid = (CLSID*) SendMessageA(pdlgInfo->hwndObjTypeLB, - LB_GETITEMDATA, (WPARAM)index, 0); - memcpy(&pdlgInfo->lpOleUIInsertObject->clsid, clsid, sizeof(CLSID)); - - if (pdlgInfo->lpOleUIInsertObject->dwFlags & IOF_CREATENEWOBJECT) - { - pdlgInfo->lpOleUIInsertObject->sc= OleCreate( - &pdlgInfo->lpOleUIInsertObject->clsid, - &pdlgInfo->lpOleUIInsertObject->iid, - pdlgInfo->lpOleUIInsertObject->oleRender, - pdlgInfo->lpOleUIInsertObject->lpFormatEtc, - pdlgInfo->lpOleUIInsertObject->lpIOleClientSite, - pdlgInfo->lpOleUIInsertObject->lpIStorage, - pdlgInfo->lpOleUIInsertObject->ppvObj); - } - - bret = TRUE; - } - } - else if (BST_CHECKED == SendMessageA(pdlgInfo->hwndCreateFromFileCB, BM_GETCHECK, 0, 0)) - { - char fname[MAX_PATH]; - - if (pdlgInfo->lpOleUIInsertObject->lpszFile) - { - HRESULT hres; - WCHAR wcsFile[MAX_PATH]; - - SendMessageA(pdlgInfo->hwndFileTB, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)fname); - lstrcpynA(pdlgInfo->lpOleUIInsertObject->lpszFile, fname, pdlgInfo->lpOleUIInsertObject->cchFile); - - RtlMultiByteToUnicodeN(wcsFile, MAX_PATH, NULL, fname, MAX_PATH); - if (ERROR_SUCCESS == (hres = GetClassFile(wcsFile, &pdlgInfo->lpOleUIInsertObject->clsid))) - { - if (pdlgInfo->lpOleUIInsertObject->dwFlags & IOF_CREATEFILEOBJECT) - { - hres = OleCreateFromFile( - &pdlgInfo->lpOleUIInsertObject->clsid, - wcsFile, - &pdlgInfo->lpOleUIInsertObject->iid, - pdlgInfo->lpOleUIInsertObject->oleRender, - pdlgInfo->lpOleUIInsertObject->lpFormatEtc, - pdlgInfo->lpOleUIInsertObject->lpIOleClientSite, - pdlgInfo->lpOleUIInsertObject->lpIStorage, - pdlgInfo->lpOleUIInsertObject->ppvObj); - } - - bret = TRUE; - } - pdlgInfo->lpOleUIInsertObject->sc = hres; - } - } - - return bret; -} - - -/*********************************************************************** - * UIINSERTOBJECTDLG_BrowseFile - * - * Browse for the file - */ -static void UIINSERTOBJECTDLG_BrowseFile(InsertObjectDlgInfo* pdlgInfo) -{ - OPENFILENAMEA fn; - char fname[MAX_PATH]; - char title[32]; - - fn.lStructSize = sizeof(OPENFILENAMEA); - fn.hwndOwner = pdlgInfo->hwndSelf; - fn.hInstance = 0; - fn.lpstrFilter = "All Files\0*.*\0\0"; - fn.lpstrCustomFilter = NULL; - fn.nMaxCustFilter = 0; - fn.nFilterIndex = 0; - - SendMessageA(pdlgInfo->hwndFileTB, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)fname); - fn.lpstrFile = fname; - fn.nMaxFile = MAX_PATH; - - fn.lpstrFileTitle = NULL; - fn.nMaxFileTitle = 0; - fn.lpstrInitialDir = NULL; - - LoadStringA(OLEDLG_hInstance, IDS_BROWSE, title, 32); - fn.lpstrTitle = title; - - fn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | - OFN_HIDEREADONLY | OFN_LONGNAMES; - fn.nFileOffset = 0; - fn.nFileExtension = 0; - fn.lpstrDefExt = NULL; - fn.lCustData = 0; - fn.lpfnHook = NULL; - fn.lpTemplateName = NULL; - - if (GetOpenFileNameA(&fn)) - SendMessageA(pdlgInfo->hwndFileTB, WM_SETTEXT, (WPARAM)0, (LPARAM)fn.lpstrFile); -} - - -/*********************************************************************** - * UIINSERTOBJECTDLG_AddControl - * - * Add control to Object Type - */ -static void UIINSERTOBJECTDLG_AddControl(InsertObjectDlgInfo* pdlgInfo) -{ - OPENFILENAMEA fn; - char fname[MAX_PATH]; - char title[32]; - - fn.lStructSize = sizeof(OPENFILENAMEA); - fn.hwndOwner = pdlgInfo->hwndSelf; - fn.hInstance = 0; - fn.lpstrFilter = "OLE Controls\0*.ocx\0Libraries\0*.dll\0All Files\0*.*\0\0"; - fn.lpstrCustomFilter = NULL; - fn.nMaxCustFilter = 0; - fn.nFilterIndex = 0; - - fname[0] = 0; - fn.lpstrFile = fname; - fn.nMaxFile = MAX_PATH; - - fn.lpstrFileTitle = NULL; - fn.nMaxFileTitle = 0; - fn.lpstrInitialDir = NULL; - - LoadStringA(OLEDLG_hInstance, IDS_BROWSE, title, 32); - fn.lpstrTitle = title; - - fn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | - OFN_HIDEREADONLY | OFN_LONGNAMES; - fn.nFileOffset = 0; - fn.nFileExtension = 0; - fn.lpstrDefExt = NULL; - fn.lCustData = 0; - fn.lpfnHook = NULL; - fn.lpTemplateName = NULL; - - if (GetOpenFileNameA(&fn)) - { - HMODULE hMod; - BOOL bValid = FALSE; - - hMod = LoadLibraryA(fn.lpstrFile); - - if (hMod) - { - DLLREGISTER regproc; - - regproc = (DLLREGISTER) GetProcAddress(hMod, "DllRegisterServer"); - if (regproc) - { - if (S_OK == regproc()) - { - UIINSERTOBJECTDLG_PopulateObjectTypes(pdlgInfo); - bValid = TRUE; - } - } - - FreeLibrary(hMod); - } - - if (!bValid) - { - char title[32]; - char msg[256]; - - LoadStringA(OLEDLG_hInstance, IDS_NOTOLEMODCAPTION, title, 32); - LoadStringA(OLEDLG_hInstance, IDS_NOTOLEMOD, msg, 256); - - MessageBoxA(pdlgInfo->hwndSelf, msg, title, MB_ICONEXCLAMATION); - } - } -} +/* + * OLEDLG library + * + * Copyright 2003 Ulrich Czekalla for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> +#include <stdio.h> + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winternl.h" +#include "winnls.h" +#include "winerror.h" +#include "wingdi.h" +#include "winuser.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +#include "oledlg.h" +#include "resource.h" + +WINE_DEFAULT_DEBUG_CHANNEL(oledlg); + +typedef struct +{ + HWND hwndSelf; + BOOL bObjListInit; /* Object list has been initialized */ + LPOLEUIINSERTOBJECTA lpOleUIInsertObject; + + HWND hwndObjTypeLBL; + HWND hwndObjTypeLB; + HWND hwndFileLBL; + HWND hwndFileTB; + HWND hwndCreateCtrlCB; + HWND hwndCreateNewCB; + HWND hwndCreateFromFileCB; + HWND hwndDisplayIconCB; + HWND hwndAddCtrlBTN; + HWND hwndBrowseBTN; + HWND hwndResultDesc; + +} InsertObjectDlgInfo; + +INT_PTR CALLBACK UIInsertObjectDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +static LRESULT UIINSOBJDLG_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam); +static void UIINSERTOBJECTDLG_InitDialog(InsertObjectDlgInfo* pdlgInfo); +static void UIINSERTOBJECTDLG_SelectCreateCtrl(InsertObjectDlgInfo* pdlgInfo); +static void UIINSERTOBJECTDLG_SelectCreateFromFile(InsertObjectDlgInfo* pdlgInfo); +static void UIINSERTOBJECTDLG_SelectCreateNew(InsertObjectDlgInfo* pdlgInfo); +static BOOL UIINSERTOBJECTDLG_PopulateObjectTypes(InsertObjectDlgInfo* pdlgInfo); +static void UIINSERTOBJECTDLG_FreeObjectTypes(InsertObjectDlgInfo* pdlgInfo); +static void UIINSERTOBJECTDLG_SelChange(InsertObjectDlgInfo* pdlgInfo); +static BOOL UIINSERTOBJECTDLG_OnOpen(InsertObjectDlgInfo* pdlgInfo); +static void UIINSERTOBJECTDLG_BrowseFile(InsertObjectDlgInfo* pdlgInfo); +static void UIINSERTOBJECTDLG_AddControl(InsertObjectDlgInfo* pdlgInfo); + +typedef HRESULT (*DLLREGISTER) (void); + +extern HINSTANCE OLEDLG_hInstance; +const char *OleUIInsertObjectInfoStr = "OleUIInsertObjectInfoStr"; + +/*********************************************************************** + * OleUIInsertObjectA (OLEDLG.3) + */ +UINT WINAPI OleUIInsertObjectA(LPOLEUIINSERTOBJECTA lpOleUIInsertObject) +{ + LRESULT lRes; + LPCVOID template; + HRSRC hRes; + InsertObjectDlgInfo dlgInfo; + HANDLE hDlgTmpl = 0; + + if (lpOleUIInsertObject->lpszTemplate || lpOleUIInsertObject->hResource) + FIXME("Customized template not supported\n"); + + /* Create the dialog from a template */ + if(!(hRes = FindResourceA(OLEDLG_hInstance,MAKEINTRESOURCEA(UIINSERTOBJECT), + (LPSTR)RT_DIALOG))) + { + return OLEUI_ERR_FINDTEMPLATEFAILURE; + } + + if (!(hDlgTmpl = LoadResource(OLEDLG_hInstance, hRes )) || + !(template = LockResource( hDlgTmpl ))) + { + return OLEUI_ERR_LOADTEMPLATEFAILURE; + } + + /* Initialize InsertObjectDlgInfo structure */ + dlgInfo.lpOleUIInsertObject = lpOleUIInsertObject; + dlgInfo.bObjListInit = FALSE; + + lRes = DialogBoxIndirectParamA(OLEDLG_hInstance, (const DLGTEMPLATE*) template, + lpOleUIInsertObject->hWndOwner, UIInsertObjectDlgProc, + (LPARAM) &dlgInfo); + + /* Unable to create the dialog */ + if( lRes == -1) + return OLEUI_ERR_DIALOGFAILURE; + + return lRes; +} + + +/*********************************************************************** + * UIInsertObjectDlgProc + * + * OLE UI Insert Object dialog procedure + */ +INT_PTR CALLBACK UIInsertObjectDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + InsertObjectDlgInfo* pdlgInfo = (InsertObjectDlgInfo*) GetPropA(hwnd,OleUIInsertObjectInfoStr); + + switch(uMsg) + { + case WM_INITDIALOG: + { + InsertObjectDlgInfo* pdlgInfo = (InsertObjectDlgInfo*)lParam; + + pdlgInfo->hwndSelf = hwnd; + + SetPropA(hwnd, OleUIInsertObjectInfoStr, (HANDLE) pdlgInfo); + + UIINSERTOBJECTDLG_InitDialog(pdlgInfo); + + return 0; + } + + case WM_COMMAND: + return UIINSOBJDLG_OnWMCommand(hwnd, wParam, lParam); + + case WM_DESTROY: + if (pdlgInfo) + UIINSERTOBJECTDLG_FreeObjectTypes(pdlgInfo); + RemovePropA(hwnd, OleUIInsertObjectInfoStr); + return FALSE; + + default : + return FALSE; + } +} + + +/*********************************************************************** + * UIINSOBJDLG_OnWMCommand + * + * WM_COMMAND message handler + */ +static LRESULT UIINSOBJDLG_OnWMCommand(HWND hwnd, WPARAM wParam, LPARAM lParam) +{ + WORD wNotifyCode = HIWORD(wParam); + WORD wID = LOWORD(wParam); + InsertObjectDlgInfo* pdlgInfo = (InsertObjectDlgInfo*) GetPropA(hwnd,OleUIInsertObjectInfoStr); + + switch(wID) + { + case IDOK: + EndDialog(hwnd, UIINSERTOBJECTDLG_OnOpen(pdlgInfo)); + break; + + case IDCANCEL: + EndDialog(hwnd, FALSE); + break; + + case IDC_CREATECONTROL: + UIINSERTOBJECTDLG_SelectCreateCtrl(pdlgInfo); + break; + + case IDC_CREATENEW: + UIINSERTOBJECTDLG_SelectCreateNew(pdlgInfo); + break; + + case IDC_CREATEFROMFILE: + UIINSERTOBJECTDLG_SelectCreateFromFile(pdlgInfo); + break; + + case IDC_BROWSE: + UIINSERTOBJECTDLG_BrowseFile(pdlgInfo); + break; + + case IDC_ADDCONTROL: + UIINSERTOBJECTDLG_AddControl(pdlgInfo); + + case IDC_OBJTYPELIST: + { + if (wNotifyCode == LBN_SELCHANGE) + UIINSERTOBJECTDLG_SelChange(pdlgInfo); + break; + } + } + return 0; +} + + +/*********************************************************************** + * UIINSERTOBJECTDLG_InitDialog + * + * Initialize dialog display + */ +static void UIINSERTOBJECTDLG_InitDialog(InsertObjectDlgInfo* pdlgInfo) +{ + /* Initialize InsertObjectDlgInfo data structure */ + pdlgInfo->hwndObjTypeLB = GetDlgItem(pdlgInfo->hwndSelf, IDC_OBJTYPELIST); + pdlgInfo->hwndObjTypeLBL = GetDlgItem(pdlgInfo->hwndSelf, IDC_OBJTYPELBL); + pdlgInfo->hwndFileLBL = GetDlgItem(pdlgInfo->hwndSelf, IDC_FILELBL); + pdlgInfo->hwndFileTB = GetDlgItem(pdlgInfo->hwndSelf, IDC_FILE); + pdlgInfo->hwndCreateCtrlCB = GetDlgItem(pdlgInfo->hwndSelf, IDC_CREATECONTROL); + pdlgInfo->hwndCreateNewCB = GetDlgItem(pdlgInfo->hwndSelf, IDC_CREATENEW); + pdlgInfo->hwndCreateFromFileCB = GetDlgItem(pdlgInfo->hwndSelf, IDC_CREATEFROMFILE); + pdlgInfo->hwndDisplayIconCB = GetDlgItem(pdlgInfo->hwndSelf, IDC_ASICON); + pdlgInfo->hwndAddCtrlBTN = GetDlgItem(pdlgInfo->hwndSelf, IDC_ADDCONTROL); + pdlgInfo->hwndBrowseBTN = GetDlgItem(pdlgInfo->hwndSelf, IDC_BROWSE); + pdlgInfo->hwndResultDesc = GetDlgItem(pdlgInfo->hwndSelf, IDC_RESULTDESC); + + /* Setup dialog controls based on flags */ + if (pdlgInfo->lpOleUIInsertObject->lpszCaption) + SetWindowTextA(pdlgInfo->hwndSelf, pdlgInfo->lpOleUIInsertObject->lpszCaption); + + ShowWindow(pdlgInfo->hwndCreateCtrlCB, (pdlgInfo->lpOleUIInsertObject->dwFlags & + IOF_SHOWINSERTCONTROL) ? SW_SHOW : SW_HIDE); + ShowWindow(pdlgInfo->hwndDisplayIconCB, (pdlgInfo->lpOleUIInsertObject->dwFlags & + IOF_CHECKDISPLAYASICON) ? SW_SHOW : SW_HIDE); + EnableWindow(pdlgInfo->hwndDisplayIconCB, (pdlgInfo->lpOleUIInsertObject->dwFlags & + IOF_DISABLEDISPLAYASICON) ? FALSE : TRUE); + + if (pdlgInfo->lpOleUIInsertObject->dwFlags & IOF_SELECTCREATECONTROL) + UIINSERTOBJECTDLG_SelectCreateCtrl(pdlgInfo); + else if (pdlgInfo->lpOleUIInsertObject->dwFlags & IOF_SELECTCREATEFROMFILE) + UIINSERTOBJECTDLG_SelectCreateFromFile(pdlgInfo); + else /* (pdlgInfo->lpOleUIInsertObject->dwFlags & IOF_SELECTCREATENEW) */ + UIINSERTOBJECTDLG_SelectCreateNew(pdlgInfo); +} + + +/*********************************************************************** + * UIINSERTOBJECTDLG_SelectCreateCtrl + * + * Select Create Control Radio Button + */ +static void UIINSERTOBJECTDLG_SelectCreateCtrl(InsertObjectDlgInfo* pdlgInfo) +{ + ShowWindow(pdlgInfo->hwndDisplayIconCB, SW_HIDE); + ShowWindow(pdlgInfo->hwndFileLBL, SW_HIDE); + ShowWindow(pdlgInfo->hwndFileTB, SW_HIDE); + ShowWindow(pdlgInfo->hwndBrowseBTN, SW_HIDE); + + ShowWindow(pdlgInfo->hwndObjTypeLBL, SW_SHOW); + ShowWindow(pdlgInfo->hwndObjTypeLB, SW_SHOW); + ShowWindow(pdlgInfo->hwndAddCtrlBTN, SW_SHOW); + + SendMessageA(pdlgInfo->hwndCreateCtrlCB, BM_SETCHECK, BST_CHECKED, 0); + + /* Populate object type listbox */ + if (!pdlgInfo->bObjListInit) + UIINSERTOBJECTDLG_PopulateObjectTypes(pdlgInfo); +} + + +/*********************************************************************** + * UIINSERTOBJECTDLG_SelectCreateNew + * + * Select Create New Radio Button + */ +static void UIINSERTOBJECTDLG_SelectCreateNew(InsertObjectDlgInfo* pdlgInfo) +{ + ShowWindow(pdlgInfo->hwndFileLBL, SW_HIDE); + ShowWindow(pdlgInfo->hwndFileTB, SW_HIDE); + ShowWindow(pdlgInfo->hwndAddCtrlBTN, SW_HIDE); + ShowWindow(pdlgInfo->hwndBrowseBTN, SW_HIDE); + + if (pdlgInfo->lpOleUIInsertObject->dwFlags & IOF_CHECKDISPLAYASICON) + ShowWindow(pdlgInfo->hwndDisplayIconCB, SW_SHOW); + + ShowWindow(pdlgInfo->hwndObjTypeLBL, SW_SHOW); + ShowWindow(pdlgInfo->hwndObjTypeLB, SW_SHOW); + + SendMessageA(pdlgInfo->hwndCreateNewCB, BM_SETCHECK, BST_CHECKED, 0); + + if (!pdlgInfo->bObjListInit) + UIINSERTOBJECTDLG_PopulateObjectTypes(pdlgInfo); + + UIINSERTOBJECTDLG_SelChange(pdlgInfo); +} + + +/*********************************************************************** + * UIINSERTOBJECTDLG_SelectCreateFromFile + * + * Select Create From File Radio Button + */ +static void UIINSERTOBJECTDLG_SelectCreateFromFile(InsertObjectDlgInfo* pdlgInfo) +{ + char resstr[MAX_PATH]; + + ShowWindow(pdlgInfo->hwndAddCtrlBTN, SW_HIDE); + ShowWindow(pdlgInfo->hwndObjTypeLBL, SW_HIDE); + ShowWindow(pdlgInfo->hwndObjTypeLB, SW_HIDE); + + if (pdlgInfo->lpOleUIInsertObject->dwFlags & IOF_CHECKDISPLAYASICON) + ShowWindow(pdlgInfo->hwndDisplayIconCB, SW_SHOW); + + ShowWindow(pdlgInfo->hwndFileLBL, SW_SHOW); + ShowWindow(pdlgInfo->hwndFileTB, SW_SHOW); + ShowWindow(pdlgInfo->hwndBrowseBTN, SW_SHOW); + + SendMessageA(pdlgInfo->hwndCreateFromFileCB, BM_SETCHECK, BST_CHECKED, 0); + + if (LoadStringA(OLEDLG_hInstance, IDS_RESULTFILEOBJDESC, resstr, MAX_PATH)) + SendMessageA(pdlgInfo->hwndResultDesc, WM_SETTEXT, 0, (LPARAM)resstr); +} + + +/*********************************************************************** + * UIINSERTOBJECTDLG_PopulateObjectTypes + * + * Populate Object Type listbox + */ +static BOOL UIINSERTOBJECTDLG_PopulateObjectTypes(InsertObjectDlgInfo* pdlgInfo) +{ + DWORD i, len; + HKEY hkclsids; + HKEY hkey; + CLSID clsid; + HRESULT ret; + CHAR szclsid[128]; + CHAR keydesc[MAX_PATH]; + CHAR keyname[MAX_PATH]; + WCHAR wszclsid[128]; + DWORD index = 0; + + UIINSERTOBJECTDLG_FreeObjectTypes(pdlgInfo); + + RegOpenKeyExA(HKEY_CLASSES_ROOT, "CLSID", 0, KEY_READ, &hkclsids); + + while (ERROR_SUCCESS == (ret = RegEnumKeyA(hkclsids, index, szclsid, MAX_PATH))) + { + index++; + + RegOpenKeyExA(hkclsids, szclsid, 0, KEY_READ, &hkey); + + len = MAX_PATH; + if (ERROR_SUCCESS != RegQueryValueA(hkey, "Insertable", keyname, &len)) + continue; + + len = MAX_PATH; + if (ERROR_SUCCESS == RegQueryValueA(hkey, "NotInsertable", keyname, &len)) + continue; + + RtlMultiByteToUnicodeN(wszclsid, MAX_PATH, NULL, szclsid, MAX_PATH); + CLSIDFromString(wszclsid, &clsid); + + for (i = 0; i < pdlgInfo->lpOleUIInsertObject->cClsidExclude; i++) + if (IsEqualGUID(&pdlgInfo->lpOleUIInsertObject->lpClsidExclude[i], &clsid)) + break; + + if (i < pdlgInfo->lpOleUIInsertObject->cClsidExclude) + continue; + + len = MAX_PATH; + if (ERROR_SUCCESS == RegQueryValueA(hkey, NULL, keydesc, &len)) + { + CLSID* lpclsid = HeapAlloc(GetProcessHeap(), 0, sizeof(CLSID)); + memcpy(lpclsid, &clsid, sizeof(CLSID)); + + len = SendMessageA(pdlgInfo->hwndObjTypeLB, LB_ADDSTRING, 0, (LPARAM)keydesc); + SendMessageA(pdlgInfo->hwndObjTypeLB, LB_SETITEMDATA, (WPARAM)len, (LPARAM)lpclsid); + } + } + + pdlgInfo->bObjListInit = (ret == ERROR_NO_MORE_ITEMS); + + return pdlgInfo->bObjListInit; +} + + +/*********************************************************************** + * UIINSERTOBJECTDLG_FreeObjectTypes + * + * Free Object Types listbox + */ +static void UIINSERTOBJECTDLG_FreeObjectTypes(InsertObjectDlgInfo* pdlgInfo) +{ + UINT i, count; + + count = SendMessageA(pdlgInfo->hwndObjTypeLB, LB_GETCOUNT, (WPARAM)0, (LPARAM)0); + + for (i = 0; i < count; i++) + { + CLSID* lpclsid = (CLSID*) SendMessageA(pdlgInfo->hwndObjTypeLB, + LB_GETITEMDATA, (WPARAM)i, (LPARAM)0); + HeapFree(GetProcessHeap(), 0, lpclsid); + } +} + + +/*********************************************************************** + * UIINSERTOBJECTDLG_SelChange + * + * Handle object type selection change + */ +static void UIINSERTOBJECTDLG_SelChange(InsertObjectDlgInfo* pdlgInfo) +{ + INT index; + CHAR objname[MAX_PATH]; + CHAR objdesc[MAX_PATH]; + CHAR resstr[MAX_PATH]; + + TRACE("\n"); + + if (LoadStringA(OLEDLG_hInstance, IDS_RESULTOBJDESC, resstr, MAX_PATH) && + ((index = SendMessageA(pdlgInfo->hwndObjTypeLB, LB_GETCURSEL, 0, 0)) >= 0) && + SendMessageA(pdlgInfo->hwndObjTypeLB, LB_GETTEXT, (WPARAM)index, (LPARAM)objname)) + sprintf(objdesc, resstr, objname); + else + objdesc[0] = 0; + + SendMessageA(pdlgInfo->hwndResultDesc, WM_SETTEXT, 0, (LPARAM)objdesc); +} + + +/*********************************************************************** + * UIINSERTOBJECTDLG_SelChange + * + * Handle OK Button + */ +static BOOL UIINSERTOBJECTDLG_OnOpen(InsertObjectDlgInfo* pdlgInfo) +{ + BOOL bret = FALSE; + + if (BST_CHECKED == SendMessageA(pdlgInfo->hwndCreateCtrlCB, BM_GETCHECK, 0, 0) || + BST_CHECKED == SendMessageA(pdlgInfo->hwndCreateNewCB, BM_GETCHECK, 0, 0)) + { + INT index = SendMessageA(pdlgInfo->hwndObjTypeLB, LB_GETCURSEL, 0, 0); + + if (index >= 0) + { + CLSID* clsid = (CLSID*) SendMessageA(pdlgInfo->hwndObjTypeLB, + LB_GETITEMDATA, (WPARAM)index, 0); + memcpy(&pdlgInfo->lpOleUIInsertObject->clsid, clsid, sizeof(CLSID)); + + if (pdlgInfo->lpOleUIInsertObject->dwFlags & IOF_CREATENEWOBJECT) + { + pdlgInfo->lpOleUIInsertObject->sc= OleCreate( + &pdlgInfo->lpOleUIInsertObject->clsid, + &pdlgInfo->lpOleUIInsertObject->iid, + pdlgInfo->lpOleUIInsertObject->oleRender, + pdlgInfo->lpOleUIInsertObject->lpFormatEtc, + pdlgInfo->lpOleUIInsertObject->lpIOleClientSite, + pdlgInfo->lpOleUIInsertObject->lpIStorage, + pdlgInfo->lpOleUIInsertObject->ppvObj); + } + + bret = TRUE; + } + } + else if (BST_CHECKED == SendMessageA(pdlgInfo->hwndCreateFromFileCB, BM_GETCHECK, 0, 0)) + { + char fname[MAX_PATH]; + + if (pdlgInfo->lpOleUIInsertObject->lpszFile) + { + HRESULT hres; + WCHAR wcsFile[MAX_PATH]; + + SendMessageA(pdlgInfo->hwndFileTB, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)fname); + lstrcpynA(pdlgInfo->lpOleUIInsertObject->lpszFile, fname, pdlgInfo->lpOleUIInsertObject->cchFile); + + RtlMultiByteToUnicodeN(wcsFile, MAX_PATH, NULL, fname, MAX_PATH); + if (ERROR_SUCCESS == (hres = GetClassFile(wcsFile, &pdlgInfo->lpOleUIInsertObject->clsid))) + { + if (pdlgInfo->lpOleUIInsertObject->dwFlags & IOF_CREATEFILEOBJECT) + { + hres = OleCreateFromFile( + &pdlgInfo->lpOleUIInsertObject->clsid, + wcsFile, + &pdlgInfo->lpOleUIInsertObject->iid, + pdlgInfo->lpOleUIInsertObject->oleRender, + pdlgInfo->lpOleUIInsertObject->lpFormatEtc, + pdlgInfo->lpOleUIInsertObject->lpIOleClientSite, + pdlgInfo->lpOleUIInsertObject->lpIStorage, + pdlgInfo->lpOleUIInsertObject->ppvObj); + } + + bret = TRUE; + } + pdlgInfo->lpOleUIInsertObject->sc = hres; + } + } + + return bret; +} + + +/*********************************************************************** + * UIINSERTOBJECTDLG_BrowseFile + * + * Browse for the file + */ +static void UIINSERTOBJECTDLG_BrowseFile(InsertObjectDlgInfo* pdlgInfo) +{ + OPENFILENAMEA fn; + char fname[MAX_PATH]; + char title[32]; + + fn.lStructSize = sizeof(OPENFILENAMEA); + fn.hwndOwner = pdlgInfo->hwndSelf; + fn.hInstance = 0; + fn.lpstrFilter = "All Files\0*.*\0\0"; + fn.lpstrCustomFilter = NULL; + fn.nMaxCustFilter = 0; + fn.nFilterIndex = 0; + + SendMessageA(pdlgInfo->hwndFileTB, WM_GETTEXT, (WPARAM)MAX_PATH, (LPARAM)fname); + fn.lpstrFile = fname; + fn.nMaxFile = MAX_PATH; + + fn.lpstrFileTitle = NULL; + fn.nMaxFileTitle = 0; + fn.lpstrInitialDir = NULL; + + LoadStringA(OLEDLG_hInstance, IDS_BROWSE, title, 32); + fn.lpstrTitle = title; + + fn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | + OFN_HIDEREADONLY | OFN_LONGNAMES; + fn.nFileOffset = 0; + fn.nFileExtension = 0; + fn.lpstrDefExt = NULL; + fn.lCustData = 0; + fn.lpfnHook = NULL; + fn.lpTemplateName = NULL; + + if (GetOpenFileNameA(&fn)) + SendMessageA(pdlgInfo->hwndFileTB, WM_SETTEXT, (WPARAM)0, (LPARAM)fn.lpstrFile); +} + + +/*********************************************************************** + * UIINSERTOBJECTDLG_AddControl + * + * Add control to Object Type + */ +static void UIINSERTOBJECTDLG_AddControl(InsertObjectDlgInfo* pdlgInfo) +{ + OPENFILENAMEA fn; + char fname[MAX_PATH]; + char title[32]; + + fn.lStructSize = sizeof(OPENFILENAMEA); + fn.hwndOwner = pdlgInfo->hwndSelf; + fn.hInstance = 0; + fn.lpstrFilter = "OLE Controls\0*.ocx\0Libraries\0*.dll\0All Files\0*.*\0\0"; + fn.lpstrCustomFilter = NULL; + fn.nMaxCustFilter = 0; + fn.nFilterIndex = 0; + + fname[0] = 0; + fn.lpstrFile = fname; + fn.nMaxFile = MAX_PATH; + + fn.lpstrFileTitle = NULL; + fn.nMaxFileTitle = 0; + fn.lpstrInitialDir = NULL; + + LoadStringA(OLEDLG_hInstance, IDS_BROWSE, title, 32); + fn.lpstrTitle = title; + + fn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | + OFN_HIDEREADONLY | OFN_LONGNAMES; + fn.nFileOffset = 0; + fn.nFileExtension = 0; + fn.lpstrDefExt = NULL; + fn.lCustData = 0; + fn.lpfnHook = NULL; + fn.lpTemplateName = NULL; + + if (GetOpenFileNameA(&fn)) + { + HMODULE hMod; + BOOL bValid = FALSE; + + hMod = LoadLibraryA(fn.lpstrFile); + + if (hMod) + { + DLLREGISTER regproc; + + regproc = (DLLREGISTER) GetProcAddress(hMod, "DllRegisterServer"); + if (regproc) + { + if (S_OK == regproc()) + { + UIINSERTOBJECTDLG_PopulateObjectTypes(pdlgInfo); + bValid = TRUE; + } + } + + FreeLibrary(hMod); + } + + if (!bValid) + { + char title[32]; + char msg[256]; + + LoadStringA(OLEDLG_hInstance, IDS_NOTOLEMODCAPTION, title, 32); + LoadStringA(OLEDLG_hInstance, IDS_NOTOLEMOD, msg, 256); + + MessageBoxA(pdlgInfo->hwndSelf, msg, title, MB_ICONEXCLAMATION); + } + } +} diff --git a/reactos/lib/oledlg/oledlg_main.c b/reactos/lib/oledlg/oledlg_main.c index ea0459a392c..1157459d396 100644 --- a/reactos/lib/oledlg/oledlg_main.c +++ b/reactos/lib/oledlg/oledlg_main.c @@ -1,309 +1,309 @@ -/* - * OLEDLG library - * - * Copyright 1998 Patrik Stridvall - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define COM_NO_WINDOWS_H -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "wingdi.h" -#include "winuser.h" -#include "oledlg.h" -#include "wine/debug.h" -#include "ole2.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -HINSTANCE OLEDLG_hInstance = 0; - -/*********************************************************************** - * DllMain - */ -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad) -{ - TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad); - - switch(fdwReason) { - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(hinstDLL); - OLEDLG_hInstance = hinstDLL; - break; - - case DLL_PROCESS_DETACH: - OLEDLG_hInstance = 0; - break; - } - return TRUE; -} - - -/*********************************************************************** - * OleUIAddVerbMenuA (OLEDLG.1) - */ -BOOL WINAPI OleUIAddVerbMenuA( - LPOLEOBJECT lpOleObj, LPCSTR lpszShortType, - HMENU hMenu, UINT uPos, UINT uIDVerbMin, UINT uIDVerbMax, - BOOL bAddConvert, UINT idConvert, HMENU *lphMenu) -{ - FIXME("(%p, %s, %p, %d, %d, %d, %d, %d, %p): stub\n", - lpOleObj, debugstr_a(lpszShortType), - hMenu, uPos, uIDVerbMin, uIDVerbMax, - bAddConvert, idConvert, lphMenu - ); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - -/*********************************************************************** - * OleUIAddVerbMenuW (OLEDLG.14) - */ -BOOL WINAPI OleUIAddVerbMenuW( - LPOLEOBJECT lpOleObj, LPCWSTR lpszShortType, - HMENU hMenu, UINT uPos, UINT uIDVerbMin, UINT uIDVerbMax, - BOOL bAddConvert, UINT idConvert, HMENU *lphMenu) -{ - FIXME("(%p, %s, %p, %d, %d, %d, %d, %d, %p): stub\n", - lpOleObj, debugstr_w(lpszShortType), - hMenu, uPos, uIDVerbMin, uIDVerbMax, - bAddConvert, idConvert, lphMenu - ); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - -/*********************************************************************** - * OleUICanConvertOrActivateAs (OLEDLG.2) - */ -BOOL WINAPI OleUICanConvertOrActivateAs( - REFCLSID rClsid, BOOL fIsLinkedObject, WORD wFormat) -{ - FIXME("(%p, %d, %hd): stub\n", - rClsid, fIsLinkedObject, wFormat - ); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - -/*********************************************************************** - * OleUIInsertObjectW (OLEDLG.20) - */ -UINT WINAPI OleUIInsertObjectW(LPOLEUIINSERTOBJECTW lpOleUIInsertObject) -{ - FIXME("(%p): stub\n", lpOleUIInsertObject); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return OLEUI_FALSE; -} - -/*********************************************************************** - * OleUIPasteSpecialA (OLEDLG.4) - */ -UINT WINAPI OleUIPasteSpecialA(LPOLEUIPASTESPECIALA lpOleUIPasteSpecial) -{ - FIXME("(%p): stub\n", lpOleUIPasteSpecial); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return OLEUI_FALSE; -} - -/*********************************************************************** - * OleUIPasteSpecialW (OLEDLG.22) - */ -UINT WINAPI OleUIPasteSpecialW(LPOLEUIPASTESPECIALW lpOleUIPasteSpecial) -{ - FIXME("(%p): stub\n", lpOleUIPasteSpecial); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return OLEUI_FALSE; -} - -/*********************************************************************** - * OleUIEditLinksA (OLEDLG.5) - */ -UINT WINAPI OleUIEditLinksA(LPOLEUIEDITLINKSA lpOleUIEditLinks) -{ - FIXME("(%p): stub\n", lpOleUIEditLinks); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return OLEUI_FALSE; -} - -/*********************************************************************** - * OleUIEditLinksW (OLEDLG.19) - */ -UINT WINAPI OleUIEditLinksW(LPOLEUIEDITLINKSW lpOleUIEditLinks) -{ - FIXME("(%p): stub\n", lpOleUIEditLinks); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return OLEUI_FALSE; -} - -/*********************************************************************** - * OleUIChangeIconA (OLEDLG.6) - */ -UINT WINAPI OleUIChangeIconA( - LPOLEUICHANGEICONA lpOleUIChangeIcon) -{ - FIXME("(%p): stub\n", lpOleUIChangeIcon); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return OLEUI_FALSE; -} - -/*********************************************************************** - * OleUIChangeIconW (OLEDLG.16) - */ -UINT WINAPI OleUIChangeIconW( - LPOLEUICHANGEICONW lpOleUIChangeIcon) -{ - FIXME("(%p): stub\n", lpOleUIChangeIcon); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return OLEUI_FALSE; -} - -/*********************************************************************** - * OleUIConvertA (OLEDLG.7) - */ -UINT WINAPI OleUIConvertA(LPOLEUICONVERTA lpOleUIConvert) -{ - FIXME("(%p): stub\n", lpOleUIConvert); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return OLEUI_FALSE; -} - -/*********************************************************************** - * OleUIConvertW (OLEDLG.18) - */ -UINT WINAPI OleUIConvertW(LPOLEUICONVERTW lpOleUIConvert) -{ - FIXME("(%p): stub\n", lpOleUIConvert); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return OLEUI_FALSE; -} - -/*********************************************************************** - * OleUIBusyA (OLEDLG.8) - */ -UINT WINAPI OleUIBusyA(LPOLEUIBUSYA lpOleUIBusy) -{ - FIXME("(%p): stub\n", lpOleUIBusy); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return OLEUI_FALSE; -} - -/*********************************************************************** - * OleUIBusyW (OLEDLG.15) - */ -UINT WINAPI OleUIBusyW(LPOLEUIBUSYW lpOleUIBusy) -{ - FIXME("(%p): stub\n", lpOleUIBusy); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return OLEUI_FALSE; -} - -/*********************************************************************** - * OleUIUpdateLinksA (OLEDLG.9) - */ -BOOL WINAPI OleUIUpdateLinksA( - LPOLEUILINKCONTAINERA lpOleUILinkCntr, - HWND hwndParent, LPSTR lpszTitle, INT cLinks) -{ - FIXME("(%p, %p, %s, %d): stub\n", - lpOleUILinkCntr, hwndParent, debugstr_a(lpszTitle), cLinks - ); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - -/*********************************************************************** - * OleUIUpdateLinksW (OLEDLG.23) - */ -BOOL WINAPI OleUIUpdateLinksW( - LPOLEUILINKCONTAINERW lpOleUILinkCntr, - HWND hwndParent, LPWSTR lpszTitle, INT cLinks) -{ - FIXME("(%p, %p, %s, %d): stub\n", - lpOleUILinkCntr, hwndParent, debugstr_w(lpszTitle), cLinks - ); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; -} - -/*********************************************************************** - * OleUIPromptUserA (OLEDLG.10) - */ -INT __cdecl OleUIPromptUserA( - INT nTemplate, HWND hwndParent, ...) -{ - FIXME("(%d, %p, ...): stub\n", nTemplate, hwndParent); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return OLEUI_FALSE; -} - -/*********************************************************************** - * OleUIPromptUserW (OLEDLG.13) - */ -INT __cdecl OleUIPromptUserW( - INT nTemplate, HWND hwndParent, ...) -{ - FIXME("(%d, %p, ...): stub\n", nTemplate, hwndParent); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return OLEUI_FALSE; -} - -/*********************************************************************** - * OleUIObjectPropertiesA (OLEDLG.11) - */ -UINT WINAPI OleUIObjectPropertiesA( - LPOLEUIOBJECTPROPSA lpOleUIObjectProps) -{ - FIXME("(%p): stub\n", lpOleUIObjectProps); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return OLEUI_FALSE; -} - -/*********************************************************************** - * OleUIObjectPropertiesW (OLEDLG.21) - */ -UINT WINAPI OleUIObjectPropertiesW( - LPOLEUIOBJECTPROPSW lpOleUIObjectProps) -{ - FIXME("(%p): stub\n", lpOleUIObjectProps); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return OLEUI_FALSE; -} - -/*********************************************************************** - * OleUIChangeSourceA (OLEDLG.12) - */ -UINT WINAPI OleUIChangeSourceA( - LPOLEUICHANGESOURCEA lpOleUIChangeSource) -{ - FIXME("(%p): stub\n", lpOleUIChangeSource); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return OLEUI_FALSE; -} - -/*********************************************************************** - * OleUIChangeSourceW (OLEDLG.17) - */ -UINT WINAPI OleUIChangeSourceW( - LPOLEUICHANGESOURCEW lpOleUIChangeSource) -{ - FIXME("(%p): stub\n", lpOleUIChangeSource); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return OLEUI_FALSE; -} +/* + * OLEDLG library + * + * Copyright 1998 Patrik Stridvall + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define COM_NO_WINDOWS_H +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wingdi.h" +#include "winuser.h" +#include "oledlg.h" +#include "wine/debug.h" +#include "ole2.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +HINSTANCE OLEDLG_hInstance = 0; + +/*********************************************************************** + * DllMain + */ +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad) +{ + TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad); + + switch(fdwReason) { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDLL); + OLEDLG_hInstance = hinstDLL; + break; + + case DLL_PROCESS_DETACH: + OLEDLG_hInstance = 0; + break; + } + return TRUE; +} + + +/*********************************************************************** + * OleUIAddVerbMenuA (OLEDLG.1) + */ +BOOL WINAPI OleUIAddVerbMenuA( + LPOLEOBJECT lpOleObj, LPCSTR lpszShortType, + HMENU hMenu, UINT uPos, UINT uIDVerbMin, UINT uIDVerbMax, + BOOL bAddConvert, UINT idConvert, HMENU *lphMenu) +{ + FIXME("(%p, %s, %p, %d, %d, %d, %d, %d, %p): stub\n", + lpOleObj, debugstr_a(lpszShortType), + hMenu, uPos, uIDVerbMin, uIDVerbMax, + bAddConvert, idConvert, lphMenu + ); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +/*********************************************************************** + * OleUIAddVerbMenuW (OLEDLG.14) + */ +BOOL WINAPI OleUIAddVerbMenuW( + LPOLEOBJECT lpOleObj, LPCWSTR lpszShortType, + HMENU hMenu, UINT uPos, UINT uIDVerbMin, UINT uIDVerbMax, + BOOL bAddConvert, UINT idConvert, HMENU *lphMenu) +{ + FIXME("(%p, %s, %p, %d, %d, %d, %d, %d, %p): stub\n", + lpOleObj, debugstr_w(lpszShortType), + hMenu, uPos, uIDVerbMin, uIDVerbMax, + bAddConvert, idConvert, lphMenu + ); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +/*********************************************************************** + * OleUICanConvertOrActivateAs (OLEDLG.2) + */ +BOOL WINAPI OleUICanConvertOrActivateAs( + REFCLSID rClsid, BOOL fIsLinkedObject, WORD wFormat) +{ + FIXME("(%p, %d, %hd): stub\n", + rClsid, fIsLinkedObject, wFormat + ); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +/*********************************************************************** + * OleUIInsertObjectW (OLEDLG.20) + */ +UINT WINAPI OleUIInsertObjectW(LPOLEUIINSERTOBJECTW lpOleUIInsertObject) +{ + FIXME("(%p): stub\n", lpOleUIInsertObject); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return OLEUI_FALSE; +} + +/*********************************************************************** + * OleUIPasteSpecialA (OLEDLG.4) + */ +UINT WINAPI OleUIPasteSpecialA(LPOLEUIPASTESPECIALA lpOleUIPasteSpecial) +{ + FIXME("(%p): stub\n", lpOleUIPasteSpecial); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return OLEUI_FALSE; +} + +/*********************************************************************** + * OleUIPasteSpecialW (OLEDLG.22) + */ +UINT WINAPI OleUIPasteSpecialW(LPOLEUIPASTESPECIALW lpOleUIPasteSpecial) +{ + FIXME("(%p): stub\n", lpOleUIPasteSpecial); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return OLEUI_FALSE; +} + +/*********************************************************************** + * OleUIEditLinksA (OLEDLG.5) + */ +UINT WINAPI OleUIEditLinksA(LPOLEUIEDITLINKSA lpOleUIEditLinks) +{ + FIXME("(%p): stub\n", lpOleUIEditLinks); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return OLEUI_FALSE; +} + +/*********************************************************************** + * OleUIEditLinksW (OLEDLG.19) + */ +UINT WINAPI OleUIEditLinksW(LPOLEUIEDITLINKSW lpOleUIEditLinks) +{ + FIXME("(%p): stub\n", lpOleUIEditLinks); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return OLEUI_FALSE; +} + +/*********************************************************************** + * OleUIChangeIconA (OLEDLG.6) + */ +UINT WINAPI OleUIChangeIconA( + LPOLEUICHANGEICONA lpOleUIChangeIcon) +{ + FIXME("(%p): stub\n", lpOleUIChangeIcon); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return OLEUI_FALSE; +} + +/*********************************************************************** + * OleUIChangeIconW (OLEDLG.16) + */ +UINT WINAPI OleUIChangeIconW( + LPOLEUICHANGEICONW lpOleUIChangeIcon) +{ + FIXME("(%p): stub\n", lpOleUIChangeIcon); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return OLEUI_FALSE; +} + +/*********************************************************************** + * OleUIConvertA (OLEDLG.7) + */ +UINT WINAPI OleUIConvertA(LPOLEUICONVERTA lpOleUIConvert) +{ + FIXME("(%p): stub\n", lpOleUIConvert); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return OLEUI_FALSE; +} + +/*********************************************************************** + * OleUIConvertW (OLEDLG.18) + */ +UINT WINAPI OleUIConvertW(LPOLEUICONVERTW lpOleUIConvert) +{ + FIXME("(%p): stub\n", lpOleUIConvert); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return OLEUI_FALSE; +} + +/*********************************************************************** + * OleUIBusyA (OLEDLG.8) + */ +UINT WINAPI OleUIBusyA(LPOLEUIBUSYA lpOleUIBusy) +{ + FIXME("(%p): stub\n", lpOleUIBusy); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return OLEUI_FALSE; +} + +/*********************************************************************** + * OleUIBusyW (OLEDLG.15) + */ +UINT WINAPI OleUIBusyW(LPOLEUIBUSYW lpOleUIBusy) +{ + FIXME("(%p): stub\n", lpOleUIBusy); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return OLEUI_FALSE; +} + +/*********************************************************************** + * OleUIUpdateLinksA (OLEDLG.9) + */ +BOOL WINAPI OleUIUpdateLinksA( + LPOLEUILINKCONTAINERA lpOleUILinkCntr, + HWND hwndParent, LPSTR lpszTitle, INT cLinks) +{ + FIXME("(%p, %p, %s, %d): stub\n", + lpOleUILinkCntr, hwndParent, debugstr_a(lpszTitle), cLinks + ); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +/*********************************************************************** + * OleUIUpdateLinksW (OLEDLG.23) + */ +BOOL WINAPI OleUIUpdateLinksW( + LPOLEUILINKCONTAINERW lpOleUILinkCntr, + HWND hwndParent, LPWSTR lpszTitle, INT cLinks) +{ + FIXME("(%p, %p, %s, %d): stub\n", + lpOleUILinkCntr, hwndParent, debugstr_w(lpszTitle), cLinks + ); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +/*********************************************************************** + * OleUIPromptUserA (OLEDLG.10) + */ +INT __cdecl OleUIPromptUserA( + INT nTemplate, HWND hwndParent, ...) +{ + FIXME("(%d, %p, ...): stub\n", nTemplate, hwndParent); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return OLEUI_FALSE; +} + +/*********************************************************************** + * OleUIPromptUserW (OLEDLG.13) + */ +INT __cdecl OleUIPromptUserW( + INT nTemplate, HWND hwndParent, ...) +{ + FIXME("(%d, %p, ...): stub\n", nTemplate, hwndParent); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return OLEUI_FALSE; +} + +/*********************************************************************** + * OleUIObjectPropertiesA (OLEDLG.11) + */ +UINT WINAPI OleUIObjectPropertiesA( + LPOLEUIOBJECTPROPSA lpOleUIObjectProps) +{ + FIXME("(%p): stub\n", lpOleUIObjectProps); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return OLEUI_FALSE; +} + +/*********************************************************************** + * OleUIObjectPropertiesW (OLEDLG.21) + */ +UINT WINAPI OleUIObjectPropertiesW( + LPOLEUIOBJECTPROPSW lpOleUIObjectProps) +{ + FIXME("(%p): stub\n", lpOleUIObjectProps); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return OLEUI_FALSE; +} + +/*********************************************************************** + * OleUIChangeSourceA (OLEDLG.12) + */ +UINT WINAPI OleUIChangeSourceA( + LPOLEUICHANGESOURCEA lpOleUIChangeSource) +{ + FIXME("(%p): stub\n", lpOleUIChangeSource); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return OLEUI_FALSE; +} + +/*********************************************************************** + * OleUIChangeSourceW (OLEDLG.17) + */ +UINT WINAPI OleUIChangeSourceW( + LPOLEUICHANGESOURCEW lpOleUIChangeSource) +{ + FIXME("(%p): stub\n", lpOleUIChangeSource); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return OLEUI_FALSE; +} diff --git a/reactos/lib/oledlg/resource.h b/reactos/lib/oledlg/resource.h index 83e4cfe33cb..a14f18534e3 100644 --- a/reactos/lib/oledlg/resource.h +++ b/reactos/lib/oledlg/resource.h @@ -1,40 +1,40 @@ -/* - * Definitions for OLE dialog resources - * - * Copyright 2003 Ulrich Czekalla for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define IDS_RESULTOBJDESC 101 -#define IDS_RESULTFILEOBJDESC 102 -#define IDS_BROWSE 103 -#define IDS_NOTOLEMOD 104 -#define IDS_NOTOLEMODCAPTION 105 - -#define UIINSERTOBJECT 129 - -#define IDC_OBJTYPELIST 1000 -#define IDC_RESULT 1001 -#define IDC_CREATENEW 1002 -#define IDC_CREATECONTROL 1003 -#define IDC_CREATEFROMFILE 1004 -#define IDC_OBJTYPELBL 1005 -#define IDC_RESULTDESC 1006 -#define IDC_ADDCONTROL 1007 -#define IDC_ASICON 1008 -#define IDC_BROWSE 1009 -#define IDC_FILELBL 1010 -#define IDC_FILE 1011 +/* + * Definitions for OLE dialog resources + * + * Copyright 2003 Ulrich Czekalla for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define IDS_RESULTOBJDESC 101 +#define IDS_RESULTFILEOBJDESC 102 +#define IDS_BROWSE 103 +#define IDS_NOTOLEMOD 104 +#define IDS_NOTOLEMODCAPTION 105 + +#define UIINSERTOBJECT 129 + +#define IDC_OBJTYPELIST 1000 +#define IDC_RESULT 1001 +#define IDC_CREATENEW 1002 +#define IDC_CREATECONTROL 1003 +#define IDC_CREATEFROMFILE 1004 +#define IDC_OBJTYPELBL 1005 +#define IDC_RESULTDESC 1006 +#define IDC_ADDCONTROL 1007 +#define IDC_ASICON 1008 +#define IDC_BROWSE 1009 +#define IDC_FILELBL 1010 +#define IDC_FILE 1011 diff --git a/reactos/lib/olepro32/olepro32stubs.c b/reactos/lib/olepro32/olepro32stubs.c index 20b90842a99..38ccbbfacb3 100644 --- a/reactos/lib/olepro32/olepro32stubs.c +++ b/reactos/lib/olepro32/olepro32stubs.c @@ -1,68 +1,68 @@ -/* - * OlePro32 Stubs - * - * Copyright 1999 Corel Corporation - * - * Sean Langley - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define COM_NO_WINDOWS_H -#include <stdarg.h> - -#include "wine/debug.h" -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "ole2.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/*********************************************************************** - * DllUnregisterServer (OLEPRO32.258) - */ -HRESULT WINAPI DllUnregisterServer() -{ - FIXME("not implemented (olepro32.dll) \n"); - return S_OK; -} - -/*********************************************************************** - * DllRegisterServer (OLEPRO32.257) - */ -HRESULT WINAPI DllRegisterServer() -{ - FIXME("not implemented (olepro32.dll) \n"); - return S_OK; -} - -/*********************************************************************** - * DllCanUnloadNow (OLEPRO32.255) - */ -HRESULT WINAPI DllCanUnloadNow(void) -{ - FIXME("not implemented (olepro32.dll) \n"); - return S_OK; -} - -/*********************************************************************** - * DllGetClassObject (OLEPRO32.256) - */ -HRESULT WINAPI DllGetClassObject( REFCLSID rclsid, REFIID riid, LPVOID* ppv ) -{ - FIXME("not implemented (olepro32.dll) \n"); - return S_OK; -} +/* + * OlePro32 Stubs + * + * Copyright 1999 Corel Corporation + * + * Sean Langley + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define COM_NO_WINDOWS_H +#include <stdarg.h> + +#include "wine/debug.h" +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "ole2.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/*********************************************************************** + * DllUnregisterServer (OLEPRO32.258) + */ +HRESULT WINAPI DllUnregisterServer() +{ + FIXME("not implemented (olepro32.dll) \n"); + return S_OK; +} + +/*********************************************************************** + * DllRegisterServer (OLEPRO32.257) + */ +HRESULT WINAPI DllRegisterServer() +{ + FIXME("not implemented (olepro32.dll) \n"); + return S_OK; +} + +/*********************************************************************** + * DllCanUnloadNow (OLEPRO32.255) + */ +HRESULT WINAPI DllCanUnloadNow(void) +{ + FIXME("not implemented (olepro32.dll) \n"); + return S_OK; +} + +/*********************************************************************** + * DllGetClassObject (OLEPRO32.256) + */ +HRESULT WINAPI DllGetClassObject( REFCLSID rclsid, REFIID riid, LPVOID* ppv ) +{ + FIXME("not implemented (olepro32.dll) \n"); + return S_OK; +} diff --git a/reactos/lib/richedit/richedit.c b/reactos/lib/richedit/richedit.c index 93dfec4bd89..d059b0791cd 100644 --- a/reactos/lib/richedit/richedit.c +++ b/reactos/lib/richedit/richedit.c @@ -1,106 +1,106 @@ -/* - * RichEdit32 functions - * - * This module is a simple wrapper for the RichEdit 2.0 control - * - * Copyright 2000 by Jean-Claude Batista - * Copyright 2005 Mike McCormack - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> -#include <string.h> -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winreg.h" -#include "winerror.h" -#include "winuser.h" -#include "richedit.h" -#include "shlwapi.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(richedit); - -/* Window procedure of the RichEdit 1.0 control in riched20.dll */ -extern LRESULT WINAPI RichEdit10ANSIWndProc(HWND, UINT, WPARAM, LPARAM); - - -/* Unregisters the window class. */ -static BOOL RICHED32_Unregister(void) -{ - TRACE("\n"); - - UnregisterClassA(RICHEDIT_CLASS10A, NULL); - return TRUE; -} - - -/* Registers the window class. */ -static BOOL RICHED32_Register(void) -{ - WNDCLASSA wndClass; - - ZeroMemory(&wndClass, sizeof(WNDCLASSA)); - wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS; - wndClass.lpfnWndProc = RichEdit10ANSIWndProc; - wndClass.cbClsExtra = 0; - wndClass.cbWndExtra = 4; - wndClass.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); - wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wndClass.lpszClassName = RICHEDIT_CLASS10A; /* WC_RICHED32A; */ - - RegisterClassA(&wndClass); - - return TRUE; -} - -/* Initialization function */ -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - TRACE("\n"); - switch (fdwReason) - { - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(hinstDLL); - return RICHED32_Register(); - - case DLL_PROCESS_DETACH: - return RICHED32_Unregister(); - } - return TRUE; -} - -/*********************************************************************** - * DllGetVersion [RICHED32.2] - * - * Retrieves version information - */ -HRESULT WINAPI RICHED32_DllGetVersion (DLLVERSIONINFO *pdvi) -{ - TRACE("\n"); - - if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) - return E_INVALIDARG; - - pdvi->dwMajorVersion = 4; - pdvi->dwMinorVersion = 0; - pdvi->dwBuildNumber = 0; - pdvi->dwPlatformID = 0; - - return S_OK; -} +/* + * RichEdit32 functions + * + * This module is a simple wrapper for the RichEdit 2.0 control + * + * Copyright 2000 by Jean-Claude Batista + * Copyright 2005 Mike McCormack + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> +#include <string.h> +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winreg.h" +#include "winerror.h" +#include "winuser.h" +#include "richedit.h" +#include "shlwapi.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(richedit); + +/* Window procedure of the RichEdit 1.0 control in riched20.dll */ +extern LRESULT WINAPI RichEdit10ANSIWndProc(HWND, UINT, WPARAM, LPARAM); + + +/* Unregisters the window class. */ +static BOOL RICHED32_Unregister(void) +{ + TRACE("\n"); + + UnregisterClassA(RICHEDIT_CLASS10A, NULL); + return TRUE; +} + + +/* Registers the window class. */ +static BOOL RICHED32_Register(void) +{ + WNDCLASSA wndClass; + + ZeroMemory(&wndClass, sizeof(WNDCLASSA)); + wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS; + wndClass.lpfnWndProc = RichEdit10ANSIWndProc; + wndClass.cbClsExtra = 0; + wndClass.cbWndExtra = 4; + wndClass.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wndClass.lpszClassName = RICHEDIT_CLASS10A; /* WC_RICHED32A; */ + + RegisterClassA(&wndClass); + + return TRUE; +} + +/* Initialization function */ +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + TRACE("\n"); + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDLL); + return RICHED32_Register(); + + case DLL_PROCESS_DETACH: + return RICHED32_Unregister(); + } + return TRUE; +} + +/*********************************************************************** + * DllGetVersion [RICHED32.2] + * + * Retrieves version information + */ +HRESULT WINAPI RICHED32_DllGetVersion (DLLVERSIONINFO *pdvi) +{ + TRACE("\n"); + + if (pdvi->cbSize != sizeof(DLLVERSIONINFO)) + return E_INVALIDARG; + + pdvi->dwMajorVersion = 4; + pdvi->dwMinorVersion = 0; + pdvi->dwBuildNumber = 0; + pdvi->dwPlatformID = 0; + + return S_OK; +} diff --git a/reactos/lib/rpcrt4/cproxy.c b/reactos/lib/rpcrt4/cproxy.c index f5645ab79df..af8709a22c5 100644 --- a/reactos/lib/rpcrt4/cproxy.c +++ b/reactos/lib/rpcrt4/cproxy.c @@ -1,342 +1,342 @@ -/* - * COM proxy implementation - * - * Copyright 2001 Ove KÃ¥ven, TransGaming Technologies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * TODO: Handle non-i386 architectures - * Get rid of #if 0'ed code. - */ - -#include <stdarg.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" - -#include "objbase.h" -#include "rpcproxy.h" - -#include "cpsf.h" -#include "ndr_misc.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -struct StublessThunk; - -/* I don't know what MS's std proxy structure looks like, - so this probably doesn't match, but that shouldn't matter */ -typedef struct { - IRpcProxyBufferVtbl *lpVtbl; - LPVOID *PVtbl; - DWORD RefCount; - const MIDL_STUBLESS_PROXY_INFO *stubless; - const IID* piid; - LPUNKNOWN pUnkOuter; - PCInterfaceName name; - LPPSFACTORYBUFFER pPSFactory; - LPRPCCHANNELBUFFER pChannel; - struct StublessThunk *thunks; -} StdProxyImpl; - -static IRpcProxyBufferVtbl StdProxy_Vtbl; - -#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) - -/* How the Windows stubless proxy thunks work is explained at - * http://msdn.microsoft.com/library/en-us/dnmsj99/html/com0199.asp, - * but I'll use a slightly different method, to make life easier */ - -#if defined(__i386__) - -#include "pshpack1.h" - -struct StublessThunk { - BYTE push; - DWORD index; - BYTE call; - LONG handler; - BYTE ret; - WORD bytes; - BYTE pad[3]; -}; - -#include "poppack.h" - -/* adjust the stack size since we don't use Windows's method */ -#define STACK_ADJUST sizeof(DWORD) - -#define FILL_STUBLESS(x,idx,stk) \ - x->push = 0x68; /* pushl [immediate] */ \ - x->index = (idx); \ - x->call = 0xe8; /* call [near] */ \ - x->handler = (char*)ObjectStubless - (char*)&x->ret; \ - x->ret = 0xc2; /* ret [immediate] */ \ - x->bytes = stk; \ - x->pad[0] = 0x8d; /* leal (%esi),%esi */ \ - x->pad[1] = 0x76; \ - x->pad[2] = 0x00; - -static HRESULT WINAPI ObjectStubless(DWORD index) -{ - char *args = (char*)(&index + 2); - LPVOID iface = *(LPVOID*)args; - - ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); - - PFORMAT_STRING fs = This->stubless->ProcFormatString + This->stubless->FormatStringOffset[index]; - unsigned bytes = *(const WORD*)(fs+8) - STACK_ADJUST; - TRACE("(%p)->(%ld)([%d bytes]) ret=%08lx\n", iface, index, bytes, *(DWORD*)(args+bytes)); - - return RPCRT4_NdrClientCall2(This->stubless->pStubDesc, fs, args); -} - -#else /* __i386__ */ - -/* can't do that on this arch */ -struct StublessThunk { int dummy; }; -#define FILL_STUBLESS(x,idx,stk) \ - ERR("stubless proxies are not supported on this architecture\n"); -#define STACK_ADJUST 0 - -#endif /* __i386__ */ - -HRESULT WINAPI StdProxy_Construct(REFIID riid, - LPUNKNOWN pUnkOuter, - PCInterfaceName name, - CInterfaceProxyVtbl *vtbl, - CInterfaceStubVtbl *svtbl, - LPPSFACTORYBUFFER pPSFactory, - LPRPCPROXYBUFFER *ppProxy, - LPVOID *ppvObj) -{ - StdProxyImpl *This; - const MIDL_STUBLESS_PROXY_INFO *stubless = NULL; - - TRACE("(%p,%p,%p,%p,%p) %s\n", pUnkOuter, vtbl, pPSFactory, ppProxy, ppvObj, name); - - /* I can't find any other way to detect stubless proxies than this hack */ - if (!IsEqualGUID(vtbl->header.piid, riid)) { - stubless = *(const void **)vtbl; - vtbl = (CInterfaceProxyVtbl *)((const void **)vtbl + 1); - TRACE("stubless=%p\n", stubless); - } - - TRACE("iid=%s\n", debugstr_guid(vtbl->header.piid)); - TRACE("vtbl=%p\n", vtbl->Vtbl); - - if (!IsEqualGUID(vtbl->header.piid, riid)) { - ERR("IID mismatch during proxy creation\n"); - return RPC_E_UNEXPECTED; - } - - This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(StdProxyImpl)); - if (!This) return E_OUTOFMEMORY; - - if (stubless) { - unsigned i, count = svtbl->header.DispatchTableCount; - /* Maybe the original vtbl is just modified directly to point at - * ObjectStublessClientXXX thunks in real Windows, but I don't like it - */ - TRACE("stubless thunks: count=%d\n", count); - This->thunks = HeapAlloc(GetProcessHeap(),0,sizeof(struct StublessThunk)*count); - This->PVtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPVOID)*count); - for (i=0; i<count; i++) { - struct StublessThunk *thunk = &This->thunks[i]; - if (vtbl->Vtbl[i] == (LPVOID)-1) { - PFORMAT_STRING fs = stubless->ProcFormatString + stubless->FormatStringOffset[i]; - unsigned bytes = *(const WORD*)(fs+8) - STACK_ADJUST; - TRACE("method %d: stacksize=%d\n", i, bytes); - FILL_STUBLESS(thunk, i, bytes) - This->PVtbl[i] = thunk; - } - else { - memset(thunk, 0, sizeof(struct StublessThunk)); - This->PVtbl[i] = vtbl->Vtbl[i]; - } - } - } - else - This->PVtbl = vtbl->Vtbl; - - This->lpVtbl = &StdProxy_Vtbl; - /* 1 reference for the proxy and 1 for the object */ - This->RefCount = 2; - This->stubless = stubless; - This->piid = vtbl->header.piid; - This->pUnkOuter = pUnkOuter; - This->name = name; - This->pPSFactory = pPSFactory; - This->pChannel = NULL; - *ppProxy = (LPRPCPROXYBUFFER)&This->lpVtbl; - *ppvObj = &This->PVtbl; - IPSFactoryBuffer_AddRef(pPSFactory); - - return S_OK; -} - -static void WINAPI StdProxy_Destruct(LPRPCPROXYBUFFER iface) -{ - ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); - - if (This->pChannel) - IRpcProxyBuffer_Disconnect(iface); - - IPSFactoryBuffer_Release(This->pPSFactory); - if (This->thunks) { - HeapFree(GetProcessHeap(),0,This->PVtbl); - HeapFree(GetProcessHeap(),0,This->thunks); - } - HeapFree(GetProcessHeap(),0,This); -} - -static HRESULT WINAPI StdProxy_QueryInterface(LPRPCPROXYBUFFER iface, - REFIID riid, - LPVOID *obj) -{ - ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); - TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(riid),obj); - - if (IsEqualGUID(&IID_IUnknown,riid) || - IsEqualGUID(This->piid,riid)) { - *obj = &This->PVtbl; - This->RefCount++; - return S_OK; - } - - if (IsEqualGUID(&IID_IRpcProxyBuffer,riid)) { - *obj = &This->lpVtbl; - This->RefCount++; - return S_OK; - } - - return E_NOINTERFACE; -} - -static ULONG WINAPI StdProxy_AddRef(LPRPCPROXYBUFFER iface) -{ - ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); - TRACE("(%p)->AddRef()\n",This); - - return ++(This->RefCount); -} - -static ULONG WINAPI StdProxy_Release(LPRPCPROXYBUFFER iface) -{ - ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); - TRACE("(%p)->Release()\n",This); - - if (!--(This->RefCount)) { - StdProxy_Destruct((LPRPCPROXYBUFFER)&This->lpVtbl); - return 0; - } - return This->RefCount; -} - -static HRESULT WINAPI StdProxy_Connect(LPRPCPROXYBUFFER iface, - LPRPCCHANNELBUFFER pChannel) -{ - ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); - TRACE("(%p)->Connect(%p)\n",This,pChannel); - - This->pChannel = pChannel; - IRpcChannelBuffer_AddRef(pChannel); - return S_OK; -} - -static VOID WINAPI StdProxy_Disconnect(LPRPCPROXYBUFFER iface) -{ - ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); - TRACE("(%p)->Disconnect()\n",This); - - IRpcChannelBuffer_Release(This->pChannel); - This->pChannel = NULL; -} - -static IRpcProxyBufferVtbl StdProxy_Vtbl = -{ - StdProxy_QueryInterface, - StdProxy_AddRef, - StdProxy_Release, - StdProxy_Connect, - StdProxy_Disconnect -}; - -HRESULT WINAPI StdProxy_GetChannel(LPVOID iface, - LPRPCCHANNELBUFFER *ppChannel) -{ - ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); - TRACE("(%p)->GetChannel(%p) %s\n",This,ppChannel,This->name); - - *ppChannel = This->pChannel; - return S_OK; -} - -HRESULT WINAPI StdProxy_GetIID(LPVOID iface, - const IID **ppiid) -{ - ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); - TRACE("(%p)->GetIID(%p) %s\n",This,ppiid,This->name); - - *ppiid = This->piid; - return S_OK; -} - -HRESULT WINAPI IUnknown_QueryInterface_Proxy(LPUNKNOWN iface, - REFIID riid, - LPVOID *ppvObj) -{ - ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); - TRACE("(%p)->QueryInterface(%s,%p) %s\n",This,debugstr_guid(riid),ppvObj,This->name); - return IUnknown_QueryInterface(This->pUnkOuter,riid,ppvObj); -} - -ULONG WINAPI IUnknown_AddRef_Proxy(LPUNKNOWN iface) -{ - ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); - TRACE("(%p)->AddRef() %s\n",This,This->name); -#if 0 /* interface refcounting */ - return ++(This->RefCount); -#else /* object refcounting */ - return IUnknown_AddRef(This->pUnkOuter); -#endif -} - -ULONG WINAPI IUnknown_Release_Proxy(LPUNKNOWN iface) -{ - ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); - TRACE("(%p)->Release() %s\n",This,This->name); -#if 0 /* interface refcounting */ - if (!--(This->RefCount)) { - StdProxy_Destruct((LPRPCPROXYBUFFER)&This->lpVtbl); - return 0; - } - return This->RefCount; -#else /* object refcounting */ - return IUnknown_Release(This->pUnkOuter); -#endif -} - -HRESULT WINAPI -CreateProxyFromTypeInfo( LPTYPEINFO pTypeInfo, LPUNKNOWN pUnkOuter, REFIID riid, - LPRPCPROXYBUFFER *ppProxy, LPVOID *ppv ) -{ - FIXME("%p %p %s %p %p\n", pTypeInfo, pUnkOuter, debugstr_guid(riid), ppProxy, ppv); - return E_NOTIMPL; -} +/* + * COM proxy implementation + * + * Copyright 2001 Ove KÃ¥ven, TransGaming Technologies + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * TODO: Handle non-i386 architectures + * Get rid of #if 0'ed code. + */ + +#include <stdarg.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" + +#include "objbase.h" +#include "rpcproxy.h" + +#include "cpsf.h" +#include "ndr_misc.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +struct StublessThunk; + +/* I don't know what MS's std proxy structure looks like, + so this probably doesn't match, but that shouldn't matter */ +typedef struct { + IRpcProxyBufferVtbl *lpVtbl; + LPVOID *PVtbl; + DWORD RefCount; + const MIDL_STUBLESS_PROXY_INFO *stubless; + const IID* piid; + LPUNKNOWN pUnkOuter; + PCInterfaceName name; + LPPSFACTORYBUFFER pPSFactory; + LPRPCCHANNELBUFFER pChannel; + struct StublessThunk *thunks; +} StdProxyImpl; + +static IRpcProxyBufferVtbl StdProxy_Vtbl; + +#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) + +/* How the Windows stubless proxy thunks work is explained at + * http://msdn.microsoft.com/library/en-us/dnmsj99/html/com0199.asp, + * but I'll use a slightly different method, to make life easier */ + +#if defined(__i386__) + +#include "pshpack1.h" + +struct StublessThunk { + BYTE push; + DWORD index; + BYTE call; + LONG handler; + BYTE ret; + WORD bytes; + BYTE pad[3]; +}; + +#include "poppack.h" + +/* adjust the stack size since we don't use Windows's method */ +#define STACK_ADJUST sizeof(DWORD) + +#define FILL_STUBLESS(x,idx,stk) \ + x->push = 0x68; /* pushl [immediate] */ \ + x->index = (idx); \ + x->call = 0xe8; /* call [near] */ \ + x->handler = (char*)ObjectStubless - (char*)&x->ret; \ + x->ret = 0xc2; /* ret [immediate] */ \ + x->bytes = stk; \ + x->pad[0] = 0x8d; /* leal (%esi),%esi */ \ + x->pad[1] = 0x76; \ + x->pad[2] = 0x00; + +static HRESULT WINAPI ObjectStubless(DWORD index) +{ + char *args = (char*)(&index + 2); + LPVOID iface = *(LPVOID*)args; + + ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); + + PFORMAT_STRING fs = This->stubless->ProcFormatString + This->stubless->FormatStringOffset[index]; + unsigned bytes = *(const WORD*)(fs+8) - STACK_ADJUST; + TRACE("(%p)->(%ld)([%d bytes]) ret=%08lx\n", iface, index, bytes, *(DWORD*)(args+bytes)); + + return RPCRT4_NdrClientCall2(This->stubless->pStubDesc, fs, args); +} + +#else /* __i386__ */ + +/* can't do that on this arch */ +struct StublessThunk { int dummy; }; +#define FILL_STUBLESS(x,idx,stk) \ + ERR("stubless proxies are not supported on this architecture\n"); +#define STACK_ADJUST 0 + +#endif /* __i386__ */ + +HRESULT WINAPI StdProxy_Construct(REFIID riid, + LPUNKNOWN pUnkOuter, + PCInterfaceName name, + CInterfaceProxyVtbl *vtbl, + CInterfaceStubVtbl *svtbl, + LPPSFACTORYBUFFER pPSFactory, + LPRPCPROXYBUFFER *ppProxy, + LPVOID *ppvObj) +{ + StdProxyImpl *This; + const MIDL_STUBLESS_PROXY_INFO *stubless = NULL; + + TRACE("(%p,%p,%p,%p,%p) %s\n", pUnkOuter, vtbl, pPSFactory, ppProxy, ppvObj, name); + + /* I can't find any other way to detect stubless proxies than this hack */ + if (!IsEqualGUID(vtbl->header.piid, riid)) { + stubless = *(const void **)vtbl; + vtbl = (CInterfaceProxyVtbl *)((const void **)vtbl + 1); + TRACE("stubless=%p\n", stubless); + } + + TRACE("iid=%s\n", debugstr_guid(vtbl->header.piid)); + TRACE("vtbl=%p\n", vtbl->Vtbl); + + if (!IsEqualGUID(vtbl->header.piid, riid)) { + ERR("IID mismatch during proxy creation\n"); + return RPC_E_UNEXPECTED; + } + + This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(StdProxyImpl)); + if (!This) return E_OUTOFMEMORY; + + if (stubless) { + unsigned i, count = svtbl->header.DispatchTableCount; + /* Maybe the original vtbl is just modified directly to point at + * ObjectStublessClientXXX thunks in real Windows, but I don't like it + */ + TRACE("stubless thunks: count=%d\n", count); + This->thunks = HeapAlloc(GetProcessHeap(),0,sizeof(struct StublessThunk)*count); + This->PVtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPVOID)*count); + for (i=0; i<count; i++) { + struct StublessThunk *thunk = &This->thunks[i]; + if (vtbl->Vtbl[i] == (LPVOID)-1) { + PFORMAT_STRING fs = stubless->ProcFormatString + stubless->FormatStringOffset[i]; + unsigned bytes = *(const WORD*)(fs+8) - STACK_ADJUST; + TRACE("method %d: stacksize=%d\n", i, bytes); + FILL_STUBLESS(thunk, i, bytes) + This->PVtbl[i] = thunk; + } + else { + memset(thunk, 0, sizeof(struct StublessThunk)); + This->PVtbl[i] = vtbl->Vtbl[i]; + } + } + } + else + This->PVtbl = vtbl->Vtbl; + + This->lpVtbl = &StdProxy_Vtbl; + /* 1 reference for the proxy and 1 for the object */ + This->RefCount = 2; + This->stubless = stubless; + This->piid = vtbl->header.piid; + This->pUnkOuter = pUnkOuter; + This->name = name; + This->pPSFactory = pPSFactory; + This->pChannel = NULL; + *ppProxy = (LPRPCPROXYBUFFER)&This->lpVtbl; + *ppvObj = &This->PVtbl; + IPSFactoryBuffer_AddRef(pPSFactory); + + return S_OK; +} + +static void WINAPI StdProxy_Destruct(LPRPCPROXYBUFFER iface) +{ + ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); + + if (This->pChannel) + IRpcProxyBuffer_Disconnect(iface); + + IPSFactoryBuffer_Release(This->pPSFactory); + if (This->thunks) { + HeapFree(GetProcessHeap(),0,This->PVtbl); + HeapFree(GetProcessHeap(),0,This->thunks); + } + HeapFree(GetProcessHeap(),0,This); +} + +static HRESULT WINAPI StdProxy_QueryInterface(LPRPCPROXYBUFFER iface, + REFIID riid, + LPVOID *obj) +{ + ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); + TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(riid),obj); + + if (IsEqualGUID(&IID_IUnknown,riid) || + IsEqualGUID(This->piid,riid)) { + *obj = &This->PVtbl; + This->RefCount++; + return S_OK; + } + + if (IsEqualGUID(&IID_IRpcProxyBuffer,riid)) { + *obj = &This->lpVtbl; + This->RefCount++; + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG WINAPI StdProxy_AddRef(LPRPCPROXYBUFFER iface) +{ + ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); + TRACE("(%p)->AddRef()\n",This); + + return ++(This->RefCount); +} + +static ULONG WINAPI StdProxy_Release(LPRPCPROXYBUFFER iface) +{ + ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); + TRACE("(%p)->Release()\n",This); + + if (!--(This->RefCount)) { + StdProxy_Destruct((LPRPCPROXYBUFFER)&This->lpVtbl); + return 0; + } + return This->RefCount; +} + +static HRESULT WINAPI StdProxy_Connect(LPRPCPROXYBUFFER iface, + LPRPCCHANNELBUFFER pChannel) +{ + ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); + TRACE("(%p)->Connect(%p)\n",This,pChannel); + + This->pChannel = pChannel; + IRpcChannelBuffer_AddRef(pChannel); + return S_OK; +} + +static VOID WINAPI StdProxy_Disconnect(LPRPCPROXYBUFFER iface) +{ + ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); + TRACE("(%p)->Disconnect()\n",This); + + IRpcChannelBuffer_Release(This->pChannel); + This->pChannel = NULL; +} + +static IRpcProxyBufferVtbl StdProxy_Vtbl = +{ + StdProxy_QueryInterface, + StdProxy_AddRef, + StdProxy_Release, + StdProxy_Connect, + StdProxy_Disconnect +}; + +HRESULT WINAPI StdProxy_GetChannel(LPVOID iface, + LPRPCCHANNELBUFFER *ppChannel) +{ + ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); + TRACE("(%p)->GetChannel(%p) %s\n",This,ppChannel,This->name); + + *ppChannel = This->pChannel; + return S_OK; +} + +HRESULT WINAPI StdProxy_GetIID(LPVOID iface, + const IID **ppiid) +{ + ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); + TRACE("(%p)->GetIID(%p) %s\n",This,ppiid,This->name); + + *ppiid = This->piid; + return S_OK; +} + +HRESULT WINAPI IUnknown_QueryInterface_Proxy(LPUNKNOWN iface, + REFIID riid, + LPVOID *ppvObj) +{ + ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); + TRACE("(%p)->QueryInterface(%s,%p) %s\n",This,debugstr_guid(riid),ppvObj,This->name); + return IUnknown_QueryInterface(This->pUnkOuter,riid,ppvObj); +} + +ULONG WINAPI IUnknown_AddRef_Proxy(LPUNKNOWN iface) +{ + ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); + TRACE("(%p)->AddRef() %s\n",This,This->name); +#if 0 /* interface refcounting */ + return ++(This->RefCount); +#else /* object refcounting */ + return IUnknown_AddRef(This->pUnkOuter); +#endif +} + +ULONG WINAPI IUnknown_Release_Proxy(LPUNKNOWN iface) +{ + ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); + TRACE("(%p)->Release() %s\n",This,This->name); +#if 0 /* interface refcounting */ + if (!--(This->RefCount)) { + StdProxy_Destruct((LPRPCPROXYBUFFER)&This->lpVtbl); + return 0; + } + return This->RefCount; +#else /* object refcounting */ + return IUnknown_Release(This->pUnkOuter); +#endif +} + +HRESULT WINAPI +CreateProxyFromTypeInfo( LPTYPEINFO pTypeInfo, LPUNKNOWN pUnkOuter, REFIID riid, + LPRPCPROXYBUFFER *ppProxy, LPVOID *ppv ) +{ + FIXME("%p %p %s %p %p\n", pTypeInfo, pUnkOuter, debugstr_guid(riid), ppProxy, ppv); + return E_NOTIMPL; +} diff --git a/reactos/lib/rpcrt4/cpsf.c b/reactos/lib/rpcrt4/cpsf.c index 0bd8eca326c..55af27c5790 100644 --- a/reactos/lib/rpcrt4/cpsf.c +++ b/reactos/lib/rpcrt4/cpsf.c @@ -1,263 +1,263 @@ -/* - * COM proxy/stub factory (CStdPSFactory) implementation - * - * Copyright 2001 Ove KÃ¥ven, TransGaming Technologies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> -#include <stdio.h> -#include <string.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "winreg.h" - -#include "objbase.h" - -#include "rpcproxy.h" - -#include "wine/debug.h" - -#include "cpsf.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -static BOOL FindProxyInfo(const ProxyFileInfo **pProxyFileList, REFIID riid, const ProxyFileInfo **pProxyInfo, int *pIndex) -{ - while (*pProxyFileList) { - if ((*pProxyFileList)->pIIDLookupRtn(riid, pIndex)) { - *pProxyInfo = *pProxyFileList; - TRACE("found: ProxyInfo %p Index %d\n", *pProxyInfo, *pIndex); - return TRUE; - } - pProxyFileList++; - } - TRACE("not found\n"); - return FALSE; -} - -static HRESULT WINAPI CStdPSFactory_QueryInterface(LPPSFACTORYBUFFER iface, - REFIID riid, - LPVOID *obj) -{ - CStdPSFactoryBuffer *This = (CStdPSFactoryBuffer *)iface; - TRACE("(%p)->QueryInterface(%s,%p)\n",iface,debugstr_guid(riid),obj); - if (IsEqualGUID(&IID_IUnknown,riid) || - IsEqualGUID(&IID_IPSFactoryBuffer,riid)) { - *obj = This; - This->RefCount++; - return S_OK; - } - return E_NOINTERFACE; -} - -static ULONG WINAPI CStdPSFactory_AddRef(LPPSFACTORYBUFFER iface) -{ - CStdPSFactoryBuffer *This = (CStdPSFactoryBuffer *)iface; - TRACE("(%p)->AddRef()\n",iface); - return ++(This->RefCount); -} - -static ULONG WINAPI CStdPSFactory_Release(LPPSFACTORYBUFFER iface) -{ - CStdPSFactoryBuffer *This = (CStdPSFactoryBuffer *)iface; - TRACE("(%p)->Release()\n",iface); - return --(This->RefCount); -} - -static HRESULT WINAPI CStdPSFactory_CreateProxy(LPPSFACTORYBUFFER iface, - LPUNKNOWN pUnkOuter, - REFIID riid, - LPRPCPROXYBUFFER *ppProxy, - LPVOID *ppv) -{ - CStdPSFactoryBuffer *This = (CStdPSFactoryBuffer *)iface; - const ProxyFileInfo *ProxyInfo; - int Index; - TRACE("(%p)->CreateProxy(%p,%s,%p,%p)\n",iface,pUnkOuter, - debugstr_guid(riid),ppProxy,ppv); - if (!FindProxyInfo(This->pProxyFileList,riid,&ProxyInfo,&Index)) - return E_NOINTERFACE; - return StdProxy_Construct(riid, pUnkOuter, ProxyInfo->pNamesArray[Index], - ProxyInfo->pProxyVtblList[Index], - ProxyInfo->pStubVtblList[Index], iface, ppProxy, ppv); -} - -static HRESULT WINAPI CStdPSFactory_CreateStub(LPPSFACTORYBUFFER iface, - REFIID riid, - LPUNKNOWN pUnkServer, - LPRPCSTUBBUFFER *ppStub) -{ - CStdPSFactoryBuffer *This = (CStdPSFactoryBuffer *)iface; - const ProxyFileInfo *ProxyInfo; - int Index; - TRACE("(%p)->CreateStub(%s,%p,%p)\n",iface,debugstr_guid(riid), - pUnkServer,ppStub); - if (!FindProxyInfo(This->pProxyFileList,riid,&ProxyInfo,&Index)) - return E_NOINTERFACE; - return CStdStubBuffer_Construct(riid, pUnkServer, ProxyInfo->pNamesArray[Index], - ProxyInfo->pStubVtblList[Index], iface, ppStub); -} - -static IPSFactoryBufferVtbl CStdPSFactory_Vtbl = -{ - CStdPSFactory_QueryInterface, - CStdPSFactory_AddRef, - CStdPSFactory_Release, - CStdPSFactory_CreateProxy, - CStdPSFactory_CreateStub -}; - -/*********************************************************************** - * NdrDllGetClassObject [RPCRT4.@] - */ -HRESULT WINAPI NdrDllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv, - const ProxyFileInfo **pProxyFileList, - const CLSID *pclsid, - CStdPSFactoryBuffer *pPSFactoryBuffer) -{ - *ppv = NULL; - if (!pPSFactoryBuffer->lpVtbl) { - pPSFactoryBuffer->lpVtbl = &CStdPSFactory_Vtbl; - pPSFactoryBuffer->RefCount = 0; - pPSFactoryBuffer->pProxyFileList = pProxyFileList; - } - if (IsEqualGUID(rclsid, pclsid)) - return IPSFactoryBuffer_QueryInterface((LPPSFACTORYBUFFER)pPSFactoryBuffer, iid, ppv); - return CLASS_E_CLASSNOTAVAILABLE; -} - -/*********************************************************************** - * NdrDllCanUnloadNow [RPCRT4.@] - */ -HRESULT WINAPI NdrDllCanUnloadNow(CStdPSFactoryBuffer *pPSFactoryBuffer) -{ - return !(pPSFactoryBuffer->RefCount); -} - -/*********************************************************************** - * NdrDllRegisterProxy [RPCRT4.@] - */ -HRESULT WINAPI NdrDllRegisterProxy(HMODULE hDll, - const ProxyFileInfo **pProxyFileList, - const CLSID *pclsid) -{ - LPSTR clsid; - char keyname[120], module[MAX_PATH]; - HKEY key, subkey; - DWORD len; - - TRACE("(%p,%p,%s)\n", hDll, pProxyFileList, debugstr_guid(pclsid)); - UuidToStringA((UUID*)pclsid, (unsigned char**)&clsid); - - /* register interfaces to point to clsid */ - while (*pProxyFileList) { - unsigned u; - for (u=0; u<(*pProxyFileList)->TableSize; u++) { - CInterfaceStubVtbl *proxy = (*pProxyFileList)->pStubVtblList[u]; - PCInterfaceName name = (*pProxyFileList)->pNamesArray[u]; - LPSTR iid; - - TRACE("registering %s %s => %s\n", name, debugstr_guid(proxy->header.piid), clsid); - - UuidToStringA((UUID*)proxy->header.piid, (unsigned char**)&iid); - snprintf(keyname, sizeof(keyname), "Interface\\{%s}", iid); - RpcStringFreeA((unsigned char**)&iid); - if (RegCreateKeyExA(HKEY_CLASSES_ROOT, keyname, 0, NULL, 0, - KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS) { - if (name) - RegSetValueExA(key, NULL, 0, REG_SZ, name, strlen(name)); - if (RegCreateKeyExA(key, "ProxyStubClsid32", 0, NULL, 0, - KEY_WRITE, NULL, &subkey, NULL) == ERROR_SUCCESS) { - snprintf(module, sizeof(module), "{%s}", clsid); - RegSetValueExA(subkey, NULL, 0, REG_SZ, module, strlen(module)); - RegCloseKey(subkey); - } - RegCloseKey(key); - } - } - pProxyFileList++; - } - - /* register clsid to point to module */ - snprintf(keyname, sizeof(keyname), "CLSID\\{%s}", clsid); - len = GetModuleFileNameA(hDll, module, sizeof(module)); - if (len && len < sizeof(module)) { - TRACE("registering CLSID %s => %s\n", clsid, module); - if (RegCreateKeyExA(HKEY_CLASSES_ROOT, keyname, 0, NULL, 0, - KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS) { - if (RegCreateKeyExA(key, "InProcServer32", 0, NULL, 0, - KEY_WRITE, NULL, &subkey, NULL) == ERROR_SUCCESS) { - RegSetValueExA(subkey, NULL, 0, REG_SZ, module, strlen(module)); - RegCloseKey(subkey); - } - RegCloseKey(key); - } - } - - /* done */ - RpcStringFreeA((unsigned char**)&clsid); - return S_OK; -} - -/*********************************************************************** - * NdrDllUnregisterProxy [RPCRT4.@] - */ -HRESULT WINAPI NdrDllUnregisterProxy(HMODULE hDll, - const ProxyFileInfo **pProxyFileList, - const CLSID *pclsid) -{ - LPSTR clsid; - char keyname[120], module[MAX_PATH]; - DWORD len; - - TRACE("(%p,%p,%s)\n", hDll, pProxyFileList, debugstr_guid(pclsid)); - UuidToStringA((UUID*)pclsid, (unsigned char**)&clsid); - - /* unregister interfaces */ - while (*pProxyFileList) { - unsigned u; - for (u=0; u<(*pProxyFileList)->TableSize; u++) { - CInterfaceStubVtbl *proxy = (*pProxyFileList)->pStubVtblList[u]; - PCInterfaceName name = (*pProxyFileList)->pNamesArray[u]; - LPSTR iid; - - TRACE("unregistering %s %s <= %s\n", name, debugstr_guid(proxy->header.piid), clsid); - - UuidToStringA((UUID*)proxy->header.piid, (unsigned char**)&iid); - snprintf(keyname, sizeof(keyname), "Interface\\{%s}", iid); - RpcStringFreeA((unsigned char**)&iid); - RegDeleteKeyA(HKEY_CLASSES_ROOT, keyname); - } - pProxyFileList++; - } - - /* unregister clsid */ - snprintf(keyname, sizeof(keyname), "CLSID\\{%s}", clsid); - len = GetModuleFileNameA(hDll, module, sizeof(module)); - if (len && len < sizeof(module)) { - TRACE("unregistering CLSID %s <= %s\n", clsid, module); - RegDeleteKeyA(HKEY_CLASSES_ROOT, keyname); - } - - /* done */ - RpcStringFreeA((unsigned char**)&clsid); - return S_OK; -} +/* + * COM proxy/stub factory (CStdPSFactory) implementation + * + * Copyright 2001 Ove KÃ¥ven, TransGaming Technologies + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" + +#include "objbase.h" + +#include "rpcproxy.h" + +#include "wine/debug.h" + +#include "cpsf.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +static BOOL FindProxyInfo(const ProxyFileInfo **pProxyFileList, REFIID riid, const ProxyFileInfo **pProxyInfo, int *pIndex) +{ + while (*pProxyFileList) { + if ((*pProxyFileList)->pIIDLookupRtn(riid, pIndex)) { + *pProxyInfo = *pProxyFileList; + TRACE("found: ProxyInfo %p Index %d\n", *pProxyInfo, *pIndex); + return TRUE; + } + pProxyFileList++; + } + TRACE("not found\n"); + return FALSE; +} + +static HRESULT WINAPI CStdPSFactory_QueryInterface(LPPSFACTORYBUFFER iface, + REFIID riid, + LPVOID *obj) +{ + CStdPSFactoryBuffer *This = (CStdPSFactoryBuffer *)iface; + TRACE("(%p)->QueryInterface(%s,%p)\n",iface,debugstr_guid(riid),obj); + if (IsEqualGUID(&IID_IUnknown,riid) || + IsEqualGUID(&IID_IPSFactoryBuffer,riid)) { + *obj = This; + This->RefCount++; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI CStdPSFactory_AddRef(LPPSFACTORYBUFFER iface) +{ + CStdPSFactoryBuffer *This = (CStdPSFactoryBuffer *)iface; + TRACE("(%p)->AddRef()\n",iface); + return ++(This->RefCount); +} + +static ULONG WINAPI CStdPSFactory_Release(LPPSFACTORYBUFFER iface) +{ + CStdPSFactoryBuffer *This = (CStdPSFactoryBuffer *)iface; + TRACE("(%p)->Release()\n",iface); + return --(This->RefCount); +} + +static HRESULT WINAPI CStdPSFactory_CreateProxy(LPPSFACTORYBUFFER iface, + LPUNKNOWN pUnkOuter, + REFIID riid, + LPRPCPROXYBUFFER *ppProxy, + LPVOID *ppv) +{ + CStdPSFactoryBuffer *This = (CStdPSFactoryBuffer *)iface; + const ProxyFileInfo *ProxyInfo; + int Index; + TRACE("(%p)->CreateProxy(%p,%s,%p,%p)\n",iface,pUnkOuter, + debugstr_guid(riid),ppProxy,ppv); + if (!FindProxyInfo(This->pProxyFileList,riid,&ProxyInfo,&Index)) + return E_NOINTERFACE; + return StdProxy_Construct(riid, pUnkOuter, ProxyInfo->pNamesArray[Index], + ProxyInfo->pProxyVtblList[Index], + ProxyInfo->pStubVtblList[Index], iface, ppProxy, ppv); +} + +static HRESULT WINAPI CStdPSFactory_CreateStub(LPPSFACTORYBUFFER iface, + REFIID riid, + LPUNKNOWN pUnkServer, + LPRPCSTUBBUFFER *ppStub) +{ + CStdPSFactoryBuffer *This = (CStdPSFactoryBuffer *)iface; + const ProxyFileInfo *ProxyInfo; + int Index; + TRACE("(%p)->CreateStub(%s,%p,%p)\n",iface,debugstr_guid(riid), + pUnkServer,ppStub); + if (!FindProxyInfo(This->pProxyFileList,riid,&ProxyInfo,&Index)) + return E_NOINTERFACE; + return CStdStubBuffer_Construct(riid, pUnkServer, ProxyInfo->pNamesArray[Index], + ProxyInfo->pStubVtblList[Index], iface, ppStub); +} + +static IPSFactoryBufferVtbl CStdPSFactory_Vtbl = +{ + CStdPSFactory_QueryInterface, + CStdPSFactory_AddRef, + CStdPSFactory_Release, + CStdPSFactory_CreateProxy, + CStdPSFactory_CreateStub +}; + +/*********************************************************************** + * NdrDllGetClassObject [RPCRT4.@] + */ +HRESULT WINAPI NdrDllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv, + const ProxyFileInfo **pProxyFileList, + const CLSID *pclsid, + CStdPSFactoryBuffer *pPSFactoryBuffer) +{ + *ppv = NULL; + if (!pPSFactoryBuffer->lpVtbl) { + pPSFactoryBuffer->lpVtbl = &CStdPSFactory_Vtbl; + pPSFactoryBuffer->RefCount = 0; + pPSFactoryBuffer->pProxyFileList = pProxyFileList; + } + if (IsEqualGUID(rclsid, pclsid)) + return IPSFactoryBuffer_QueryInterface((LPPSFACTORYBUFFER)pPSFactoryBuffer, iid, ppv); + return CLASS_E_CLASSNOTAVAILABLE; +} + +/*********************************************************************** + * NdrDllCanUnloadNow [RPCRT4.@] + */ +HRESULT WINAPI NdrDllCanUnloadNow(CStdPSFactoryBuffer *pPSFactoryBuffer) +{ + return !(pPSFactoryBuffer->RefCount); +} + +/*********************************************************************** + * NdrDllRegisterProxy [RPCRT4.@] + */ +HRESULT WINAPI NdrDllRegisterProxy(HMODULE hDll, + const ProxyFileInfo **pProxyFileList, + const CLSID *pclsid) +{ + LPSTR clsid; + char keyname[120], module[MAX_PATH]; + HKEY key, subkey; + DWORD len; + + TRACE("(%p,%p,%s)\n", hDll, pProxyFileList, debugstr_guid(pclsid)); + UuidToStringA((UUID*)pclsid, (unsigned char**)&clsid); + + /* register interfaces to point to clsid */ + while (*pProxyFileList) { + unsigned u; + for (u=0; u<(*pProxyFileList)->TableSize; u++) { + CInterfaceStubVtbl *proxy = (*pProxyFileList)->pStubVtblList[u]; + PCInterfaceName name = (*pProxyFileList)->pNamesArray[u]; + LPSTR iid; + + TRACE("registering %s %s => %s\n", name, debugstr_guid(proxy->header.piid), clsid); + + UuidToStringA((UUID*)proxy->header.piid, (unsigned char**)&iid); + snprintf(keyname, sizeof(keyname), "Interface\\{%s}", iid); + RpcStringFreeA((unsigned char**)&iid); + if (RegCreateKeyExA(HKEY_CLASSES_ROOT, keyname, 0, NULL, 0, + KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS) { + if (name) + RegSetValueExA(key, NULL, 0, REG_SZ, name, strlen(name)); + if (RegCreateKeyExA(key, "ProxyStubClsid32", 0, NULL, 0, + KEY_WRITE, NULL, &subkey, NULL) == ERROR_SUCCESS) { + snprintf(module, sizeof(module), "{%s}", clsid); + RegSetValueExA(subkey, NULL, 0, REG_SZ, module, strlen(module)); + RegCloseKey(subkey); + } + RegCloseKey(key); + } + } + pProxyFileList++; + } + + /* register clsid to point to module */ + snprintf(keyname, sizeof(keyname), "CLSID\\{%s}", clsid); + len = GetModuleFileNameA(hDll, module, sizeof(module)); + if (len && len < sizeof(module)) { + TRACE("registering CLSID %s => %s\n", clsid, module); + if (RegCreateKeyExA(HKEY_CLASSES_ROOT, keyname, 0, NULL, 0, + KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS) { + if (RegCreateKeyExA(key, "InProcServer32", 0, NULL, 0, + KEY_WRITE, NULL, &subkey, NULL) == ERROR_SUCCESS) { + RegSetValueExA(subkey, NULL, 0, REG_SZ, module, strlen(module)); + RegCloseKey(subkey); + } + RegCloseKey(key); + } + } + + /* done */ + RpcStringFreeA((unsigned char**)&clsid); + return S_OK; +} + +/*********************************************************************** + * NdrDllUnregisterProxy [RPCRT4.@] + */ +HRESULT WINAPI NdrDllUnregisterProxy(HMODULE hDll, + const ProxyFileInfo **pProxyFileList, + const CLSID *pclsid) +{ + LPSTR clsid; + char keyname[120], module[MAX_PATH]; + DWORD len; + + TRACE("(%p,%p,%s)\n", hDll, pProxyFileList, debugstr_guid(pclsid)); + UuidToStringA((UUID*)pclsid, (unsigned char**)&clsid); + + /* unregister interfaces */ + while (*pProxyFileList) { + unsigned u; + for (u=0; u<(*pProxyFileList)->TableSize; u++) { + CInterfaceStubVtbl *proxy = (*pProxyFileList)->pStubVtblList[u]; + PCInterfaceName name = (*pProxyFileList)->pNamesArray[u]; + LPSTR iid; + + TRACE("unregistering %s %s <= %s\n", name, debugstr_guid(proxy->header.piid), clsid); + + UuidToStringA((UUID*)proxy->header.piid, (unsigned char**)&iid); + snprintf(keyname, sizeof(keyname), "Interface\\{%s}", iid); + RpcStringFreeA((unsigned char**)&iid); + RegDeleteKeyA(HKEY_CLASSES_ROOT, keyname); + } + pProxyFileList++; + } + + /* unregister clsid */ + snprintf(keyname, sizeof(keyname), "CLSID\\{%s}", clsid); + len = GetModuleFileNameA(hDll, module, sizeof(module)); + if (len && len < sizeof(module)) { + TRACE("unregistering CLSID %s <= %s\n", clsid, module); + RegDeleteKeyA(HKEY_CLASSES_ROOT, keyname); + } + + /* done */ + RpcStringFreeA((unsigned char**)&clsid); + return S_OK; +} diff --git a/reactos/lib/rpcrt4/cpsf.h b/reactos/lib/rpcrt4/cpsf.h index 12f33757f64..bdb6503ea63 100644 --- a/reactos/lib/rpcrt4/cpsf.h +++ b/reactos/lib/rpcrt4/cpsf.h @@ -1,44 +1,44 @@ -/* - * COM proxy definitions - * - * Copyright 2001 Ove KÃ¥ven, TransGaming Technologies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_CPSF_H -#define __WINE_CPSF_H - -HRESULT WINAPI StdProxy_Construct(REFIID riid, - LPUNKNOWN pUnkOuter, - PCInterfaceName name, - CInterfaceProxyVtbl *vtbl, - CInterfaceStubVtbl *svtbl, - LPPSFACTORYBUFFER pPSFactory, - LPRPCPROXYBUFFER *ppProxy, - LPVOID *ppvObj); -HRESULT WINAPI StdProxy_GetChannel(LPVOID iface, - LPRPCCHANNELBUFFER *ppChannel); -HRESULT WINAPI StdProxy_GetIID(LPVOID iface, - const IID **piid); - -HRESULT WINAPI CStdStubBuffer_Construct(REFIID riid, - LPUNKNOWN pUnkServer, - PCInterfaceName name, - CInterfaceStubVtbl *vtbl, - LPPSFACTORYBUFFER pPSFactory, - LPRPCSTUBBUFFER *ppStub); - -#endif /* __WINE_CPSF_H */ +/* + * COM proxy definitions + * + * Copyright 2001 Ove KÃ¥ven, TransGaming Technologies + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_CPSF_H +#define __WINE_CPSF_H + +HRESULT WINAPI StdProxy_Construct(REFIID riid, + LPUNKNOWN pUnkOuter, + PCInterfaceName name, + CInterfaceProxyVtbl *vtbl, + CInterfaceStubVtbl *svtbl, + LPPSFACTORYBUFFER pPSFactory, + LPRPCPROXYBUFFER *ppProxy, + LPVOID *ppvObj); +HRESULT WINAPI StdProxy_GetChannel(LPVOID iface, + LPRPCCHANNELBUFFER *ppChannel); +HRESULT WINAPI StdProxy_GetIID(LPVOID iface, + const IID **piid); + +HRESULT WINAPI CStdStubBuffer_Construct(REFIID riid, + LPUNKNOWN pUnkServer, + PCInterfaceName name, + CInterfaceStubVtbl *vtbl, + LPPSFACTORYBUFFER pPSFactory, + LPRPCSTUBBUFFER *ppStub); + +#endif /* __WINE_CPSF_H */ diff --git a/reactos/lib/rpcrt4/cstub.c b/reactos/lib/rpcrt4/cstub.c index bf590d8ea17..574f63b3e35 100644 --- a/reactos/lib/rpcrt4/cstub.c +++ b/reactos/lib/rpcrt4/cstub.c @@ -1,169 +1,169 @@ -/* - * COM stub (CStdStubBuffer) implementation - * - * Copyright 2001 Ove KÃ¥ven, TransGaming Technologies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" - -#include "objbase.h" - -#include "rpcproxy.h" - -#include "wine/debug.h" - -#include "cpsf.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -#define STUB_HEADER(This) (((CInterfaceStubHeader*)((This)->lpVtbl))[-1]) - -HRESULT WINAPI CStdStubBuffer_Construct(REFIID riid, - LPUNKNOWN pUnkServer, - PCInterfaceName name, - CInterfaceStubVtbl *vtbl, - LPPSFACTORYBUFFER pPSFactory, - LPRPCSTUBBUFFER *ppStub) -{ - CStdStubBuffer *This; - - TRACE("(%p,%p,%p,%p) %s\n", pUnkServer, vtbl, pPSFactory, ppStub, name); - TRACE("iid=%s\n", debugstr_guid(vtbl->header.piid)); - TRACE("vtbl=%p\n", &vtbl->Vtbl); - - if (!IsEqualGUID(vtbl->header.piid, riid)) { - ERR("IID mismatch during stub creation\n"); - return RPC_E_UNEXPECTED; - } - - This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CStdStubBuffer)); - if (!This) return E_OUTOFMEMORY; - - This->lpVtbl = &vtbl->Vtbl; - This->RefCount = 1; - This->pvServerObject = pUnkServer; - This->pPSFactory = pPSFactory; - *ppStub = (LPRPCSTUBBUFFER)This; - - IUnknown_AddRef(This->pvServerObject); - IPSFactoryBuffer_AddRef(pPSFactory); - return S_OK; -} - -HRESULT WINAPI CStdStubBuffer_QueryInterface(LPRPCSTUBBUFFER iface, - REFIID riid, - LPVOID *obj) -{ - CStdStubBuffer *This = (CStdStubBuffer *)iface; - TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(riid),obj); - - if (IsEqualGUID(&IID_IUnknown,riid) || - IsEqualGUID(&IID_IRpcStubBuffer,riid)) { - *obj = This; - This->RefCount++; - return S_OK; - } - return E_NOINTERFACE; -} - -ULONG WINAPI CStdStubBuffer_AddRef(LPRPCSTUBBUFFER iface) -{ - CStdStubBuffer *This = (CStdStubBuffer *)iface; - TRACE("(%p)->AddRef()\n",This); - return ++(This->RefCount); -} - -ULONG WINAPI NdrCStdStubBuffer_Release(LPRPCSTUBBUFFER iface, - LPPSFACTORYBUFFER pPSF) -{ - CStdStubBuffer *This = (CStdStubBuffer *)iface; - TRACE("(%p)->Release()\n",This); - - if (!--(This->RefCount)) { - if(This->pvServerObject) - IUnknown_Release(This->pvServerObject); - if(This->pPSFactory) - IPSFactoryBuffer_Release(This->pPSFactory); - HeapFree(GetProcessHeap(),0,This); - return 0; - } - return This->RefCount; -} - -HRESULT WINAPI CStdStubBuffer_Connect(LPRPCSTUBBUFFER iface, - LPUNKNOWN lpUnkServer) -{ - CStdStubBuffer *This = (CStdStubBuffer *)iface; - TRACE("(%p)->Connect(%p)\n",This,lpUnkServer); - This->pvServerObject = lpUnkServer; - return S_OK; -} - -void WINAPI CStdStubBuffer_Disconnect(LPRPCSTUBBUFFER iface) -{ - CStdStubBuffer *This = (CStdStubBuffer *)iface; - TRACE("(%p)->Disconnect()\n",This); - This->pvServerObject = NULL; -} - -HRESULT WINAPI CStdStubBuffer_Invoke(LPRPCSTUBBUFFER iface, - PRPCOLEMESSAGE pMsg, - LPRPCCHANNELBUFFER pChannel) -{ - CStdStubBuffer *This = (CStdStubBuffer *)iface; - DWORD dwPhase = STUB_UNMARSHAL; - TRACE("(%p)->Invoke(%p,%p)\n",This,pMsg,pChannel); - - STUB_HEADER(This).pDispatchTable[pMsg->iMethod](iface, pChannel, (PRPC_MESSAGE)pMsg, &dwPhase); - return S_OK; -} - -LPRPCSTUBBUFFER WINAPI CStdStubBuffer_IsIIDSupported(LPRPCSTUBBUFFER iface, - REFIID riid) -{ - CStdStubBuffer *This = (CStdStubBuffer *)iface; - TRACE("(%p)->IsIIDSupported(%s)\n",This,debugstr_guid(riid)); - return IsEqualGUID(STUB_HEADER(This).piid, riid) ? iface : NULL; -} - -ULONG WINAPI CStdStubBuffer_CountRefs(LPRPCSTUBBUFFER iface) -{ - CStdStubBuffer *This = (CStdStubBuffer *)iface; - TRACE("(%p)->CountRefs()\n",This); - return This->RefCount; -} - -HRESULT WINAPI CStdStubBuffer_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, - LPVOID *ppv) -{ - CStdStubBuffer *This = (CStdStubBuffer *)iface; - TRACE("(%p)->DebugServerQueryInterface(%p)\n",This,ppv); - return S_OK; -} - -void WINAPI CStdStubBuffer_DebugServerRelease(LPRPCSTUBBUFFER iface, - LPVOID pv) -{ - CStdStubBuffer *This = (CStdStubBuffer *)iface; - TRACE("(%p)->DebugServerRelease(%p)\n",This,pv); -} +/* + * COM stub (CStdStubBuffer) implementation + * + * Copyright 2001 Ove KÃ¥ven, TransGaming Technologies + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" + +#include "objbase.h" + +#include "rpcproxy.h" + +#include "wine/debug.h" + +#include "cpsf.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +#define STUB_HEADER(This) (((CInterfaceStubHeader*)((This)->lpVtbl))[-1]) + +HRESULT WINAPI CStdStubBuffer_Construct(REFIID riid, + LPUNKNOWN pUnkServer, + PCInterfaceName name, + CInterfaceStubVtbl *vtbl, + LPPSFACTORYBUFFER pPSFactory, + LPRPCSTUBBUFFER *ppStub) +{ + CStdStubBuffer *This; + + TRACE("(%p,%p,%p,%p) %s\n", pUnkServer, vtbl, pPSFactory, ppStub, name); + TRACE("iid=%s\n", debugstr_guid(vtbl->header.piid)); + TRACE("vtbl=%p\n", &vtbl->Vtbl); + + if (!IsEqualGUID(vtbl->header.piid, riid)) { + ERR("IID mismatch during stub creation\n"); + return RPC_E_UNEXPECTED; + } + + This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CStdStubBuffer)); + if (!This) return E_OUTOFMEMORY; + + This->lpVtbl = &vtbl->Vtbl; + This->RefCount = 1; + This->pvServerObject = pUnkServer; + This->pPSFactory = pPSFactory; + *ppStub = (LPRPCSTUBBUFFER)This; + + IUnknown_AddRef(This->pvServerObject); + IPSFactoryBuffer_AddRef(pPSFactory); + return S_OK; +} + +HRESULT WINAPI CStdStubBuffer_QueryInterface(LPRPCSTUBBUFFER iface, + REFIID riid, + LPVOID *obj) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(riid),obj); + + if (IsEqualGUID(&IID_IUnknown,riid) || + IsEqualGUID(&IID_IRpcStubBuffer,riid)) { + *obj = This; + This->RefCount++; + return S_OK; + } + return E_NOINTERFACE; +} + +ULONG WINAPI CStdStubBuffer_AddRef(LPRPCSTUBBUFFER iface) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->AddRef()\n",This); + return ++(This->RefCount); +} + +ULONG WINAPI NdrCStdStubBuffer_Release(LPRPCSTUBBUFFER iface, + LPPSFACTORYBUFFER pPSF) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->Release()\n",This); + + if (!--(This->RefCount)) { + if(This->pvServerObject) + IUnknown_Release(This->pvServerObject); + if(This->pPSFactory) + IPSFactoryBuffer_Release(This->pPSFactory); + HeapFree(GetProcessHeap(),0,This); + return 0; + } + return This->RefCount; +} + +HRESULT WINAPI CStdStubBuffer_Connect(LPRPCSTUBBUFFER iface, + LPUNKNOWN lpUnkServer) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->Connect(%p)\n",This,lpUnkServer); + This->pvServerObject = lpUnkServer; + return S_OK; +} + +void WINAPI CStdStubBuffer_Disconnect(LPRPCSTUBBUFFER iface) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->Disconnect()\n",This); + This->pvServerObject = NULL; +} + +HRESULT WINAPI CStdStubBuffer_Invoke(LPRPCSTUBBUFFER iface, + PRPCOLEMESSAGE pMsg, + LPRPCCHANNELBUFFER pChannel) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + DWORD dwPhase = STUB_UNMARSHAL; + TRACE("(%p)->Invoke(%p,%p)\n",This,pMsg,pChannel); + + STUB_HEADER(This).pDispatchTable[pMsg->iMethod](iface, pChannel, (PRPC_MESSAGE)pMsg, &dwPhase); + return S_OK; +} + +LPRPCSTUBBUFFER WINAPI CStdStubBuffer_IsIIDSupported(LPRPCSTUBBUFFER iface, + REFIID riid) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->IsIIDSupported(%s)\n",This,debugstr_guid(riid)); + return IsEqualGUID(STUB_HEADER(This).piid, riid) ? iface : NULL; +} + +ULONG WINAPI CStdStubBuffer_CountRefs(LPRPCSTUBBUFFER iface) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->CountRefs()\n",This); + return This->RefCount; +} + +HRESULT WINAPI CStdStubBuffer_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, + LPVOID *ppv) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->DebugServerQueryInterface(%p)\n",This,ppv); + return S_OK; +} + +void WINAPI CStdStubBuffer_DebugServerRelease(LPRPCSTUBBUFFER iface, + LPVOID pv) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->DebugServerRelease(%p)\n",This,pv); +} diff --git a/reactos/lib/rpcrt4/ndr_marshall.c b/reactos/lib/rpcrt4/ndr_marshall.c index 36bd4c3034c..5354b428515 100644 --- a/reactos/lib/rpcrt4/ndr_marshall.c +++ b/reactos/lib/rpcrt4/ndr_marshall.c @@ -1,2151 +1,2151 @@ -/* - * NDR data marshalling - * - * Copyright 2002 Greg Turner - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * TODO: - * - figure out whether we *really* got this right - * - check for errors and throw exceptions - */ - -#include <stdarg.h> -#include <stdio.h> -#include <string.h> -#include <assert.h> - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "winreg.h" - -#include "ndr_misc.h" -#include "rpcndr.h" - -#include "wine/unicode.h" -#include "wine/rpcfc.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -#define BUFFER_PARANOIA 20 - -#if defined(__i386__) -# define LITTLE_ENDIAN_UINT32_WRITE(pchar, uint32) \ - (*((UINT32 *)(pchar)) = (uint32)) - -# define LITTLE_ENDIAN_UINT32_READ(pchar) \ - (*((UINT32 *)(pchar))) -#else - /* these would work for i386 too, but less efficient */ -# define LITTLE_ENDIAN_UINT32_WRITE(pchar, uint32) \ - (*(pchar) = LOBYTE(LOWORD(uint32)), \ - *((pchar)+1) = HIBYTE(LOWORD(uint32)), \ - *((pchar)+2) = LOBYTE(HIWORD(uint32)), \ - *((pchar)+3) = HIBYTE(HIWORD(uint32)), \ - (uint32)) /* allow as r-value */ - -# define LITTLE_ENDIAN_UINT32_READ(pchar) \ - (MAKELONG( \ - MAKEWORD(*(pchar), *((pchar)+1)), \ - MAKEWORD(*((pchar)+2), *((pchar)+3)))) -#endif - -#define BIG_ENDIAN_UINT32_WRITE(pchar, uint32) \ - (*((pchar)+3) = LOBYTE(LOWORD(uint32)), \ - *((pchar)+2) = HIBYTE(LOWORD(uint32)), \ - *((pchar)+1) = LOBYTE(HIWORD(uint32)), \ - *(pchar) = HIBYTE(HIWORD(uint32)), \ - (uint32)) /* allow as r-value */ - -#define BIG_ENDIAN_UINT32_READ(pchar) \ - (MAKELONG( \ - MAKEWORD(*((pchar)+3), *((pchar)+2)), \ - MAKEWORD(*((pchar)+1), *(pchar)))) - -#ifdef NDR_LOCAL_IS_BIG_ENDIAN -# define NDR_LOCAL_UINT32_WRITE(pchar, uint32) \ - BIG_ENDIAN_UINT32_WRITE(pchar, uint32) -# define NDR_LOCAL_UINT32_READ(pchar) \ - BIG_ENDIAN_UINT32_READ(pchar) -#else -# define NDR_LOCAL_UINT32_WRITE(pchar, uint32) \ - LITTLE_ENDIAN_UINT32_WRITE(pchar, uint32) -# define NDR_LOCAL_UINT32_READ(pchar) \ - LITTLE_ENDIAN_UINT32_READ(pchar) -#endif - -/* _Align must be the desired alignment minus 1, - * e.g. ALIGN_LENGTH(len, 3) to align on a dword boundary. */ -#define ALIGNED_LENGTH(_Len, _Align) (((_Len)+(_Align))&~(_Align)) -#define ALIGNED_POINTER(_Ptr, _Align) ((LPVOID)ALIGNED_LENGTH((ULONG_PTR)(_Ptr), _Align)) -#define ALIGN_LENGTH(_Len, _Align) _Len = ALIGNED_LENGTH(_Len, _Align) -#define ALIGN_POINTER(_Ptr, _Align) _Ptr = ALIGNED_POINTER(_Ptr, _Align) - -#define STD_OVERFLOW_CHECK(_Msg) do { \ - TRACE("buffer=%d/%ld\n", _Msg->Buffer - _Msg->BufferStart, _Msg->BufferLength); \ - if (_Msg->Buffer > _Msg->BufferEnd) ERR("buffer overflow %d bytes\n", _Msg->Buffer - _Msg->BufferEnd); \ - } while (0) - -#define NDR_TABLE_SIZE 128 -#define NDR_TABLE_MASK 127 - -NDR_MARSHALL NdrMarshaller[NDR_TABLE_SIZE] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x10 */ - 0, - /* 0x11 */ - NdrPointerMarshall, NdrPointerMarshall, - NdrPointerMarshall, NdrPointerMarshall, - /* 0x15 */ - NdrSimpleStructMarshall, NdrSimpleStructMarshall, - 0, 0, 0, - NdrComplexStructMarshall, - /* 0x1b */ - NdrConformantArrayMarshall, 0, 0, 0, 0, 0, - NdrComplexArrayMarshall, - /* 0x22 */ - NdrConformantStringMarshall, 0, 0, - NdrConformantStringMarshall, 0, 0, 0, 0, - /* 0x2a */ - 0, 0, 0, 0, 0, - /* 0x2f */ - NdrInterfacePointerMarshall, - /* 0xb0 */ - 0, 0, 0, 0, - NdrUserMarshalMarshall -}; -NDR_UNMARSHALL NdrUnmarshaller[NDR_TABLE_SIZE] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x10 */ - 0, - /* 0x11 */ - NdrPointerUnmarshall, NdrPointerUnmarshall, - NdrPointerUnmarshall, NdrPointerUnmarshall, - /* 0x15 */ - NdrSimpleStructUnmarshall, NdrSimpleStructUnmarshall, - 0, 0, 0, - NdrComplexStructUnmarshall, - /* 0x1b */ - NdrConformantArrayUnmarshall, 0, 0, 0, 0, 0, - NdrComplexArrayUnmarshall, - /* 0x22 */ - NdrConformantStringUnmarshall, 0, 0, - NdrConformantStringUnmarshall, 0, 0, 0, 0, - /* 0x2a */ - 0, 0, 0, 0, 0, - /* 0x2f */ - NdrInterfacePointerUnmarshall, - /* 0xb0 */ - 0, 0, 0, 0, - NdrUserMarshalUnmarshall -}; -NDR_BUFFERSIZE NdrBufferSizer[NDR_TABLE_SIZE] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x10 */ - 0, - /* 0x11 */ - NdrPointerBufferSize, NdrPointerBufferSize, - NdrPointerBufferSize, NdrPointerBufferSize, - /* 0x15 */ - NdrSimpleStructBufferSize, NdrSimpleStructBufferSize, - 0, 0, 0, - NdrComplexStructBufferSize, - /* 0x1b */ - NdrConformantArrayBufferSize, 0, 0, 0, 0, 0, - NdrComplexArrayBufferSize, - /* 0x22 */ - NdrConformantStringBufferSize, 0, 0, - NdrConformantStringBufferSize, 0, 0, 0, 0, - /* 0x2a */ - 0, 0, 0, 0, 0, - /* 0x2f */ - NdrInterfacePointerBufferSize, - /* 0xb0 */ - 0, 0, 0, 0, - NdrUserMarshalBufferSize -}; -NDR_MEMORYSIZE NdrMemorySizer[NDR_TABLE_SIZE] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x10 */ - 0, - /* 0x11 */ - NdrPointerMemorySize, NdrPointerMemorySize, - NdrPointerMemorySize, NdrPointerMemorySize, - /* 0x15 */ - NdrSimpleStructMemorySize, NdrSimpleStructMemorySize, - 0, 0, 0, - NdrComplexStructMemorySize, - /* 0x1b */ - NdrConformantArrayMemorySize, 0, 0, 0, 0, 0, - NdrComplexArrayMemorySize, - /* 0x22 */ - NdrConformantStringMemorySize, 0, 0, - NdrConformantStringMemorySize, 0, 0, 0, 0, - /* 0x2a */ - 0, 0, 0, 0, 0, - /* 0x2f */ - NdrInterfacePointerMemorySize, - /* 0xb0 */ - 0, 0, 0, 0, - NdrUserMarshalMemorySize -}; -NDR_FREE NdrFreer[NDR_TABLE_SIZE] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x10 */ - 0, - /* 0x11 */ - NdrPointerFree, NdrPointerFree, - NdrPointerFree, NdrPointerFree, - /* 0x15 */ - NdrSimpleStructFree, NdrSimpleStructFree, - 0, 0, 0, - NdrComplexStructFree, - /* 0x1b */ - NdrConformantArrayFree, 0, 0, 0, 0, 0, - NdrComplexArrayFree, - /* 0x22 */ - 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x2a */ - 0, 0, 0, 0, 0, - /* 0x2f */ - NdrInterfacePointerFree, - /* 0xb0 */ - 0, 0, 0, 0, - NdrUserMarshalFree -}; - -void * WINAPI NdrAllocate(MIDL_STUB_MESSAGE *pStubMsg, size_t len) -{ - /* hmm, this is probably supposed to do more? */ - return pStubMsg->pfnAllocate(len); -} - -static void WINAPI NdrFree(MIDL_STUB_MESSAGE *pStubMsg, unsigned char *Pointer) -{ - pStubMsg->pfnFree(Pointer); -} - -PFORMAT_STRING ReadConformance(MIDL_STUB_MESSAGE *pStubMsg, PFORMAT_STRING pFormat) -{ - pStubMsg->MaxCount = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); - pStubMsg->Buffer += 4; - TRACE("unmarshalled conformance is %ld\n", pStubMsg->MaxCount); - return pFormat+4; -} - -PFORMAT_STRING ComputeConformance(MIDL_STUB_MESSAGE *pStubMsg, unsigned char *pMemory, - PFORMAT_STRING pFormat, ULONG_PTR def) -{ - BYTE dtype = pFormat[0] & 0xf; - DWORD ofs = (DWORD)pFormat[2] | ((DWORD)pFormat[3] << 8); - LPVOID ptr = NULL; - DWORD data = 0; - - if (pFormat[0] == 0xff) { - /* null descriptor */ - pStubMsg->MaxCount = def; - goto finish_conf; - } - - switch (pFormat[0] & 0xf0) { - case RPC_FC_NORMAL_CONFORMANCE: - TRACE("normal conformance, ofs=%ld\n", ofs); - ptr = pMemory + ofs; - break; - case RPC_FC_POINTER_CONFORMANCE: - TRACE("pointer conformance, ofs=%ld\n", ofs); - ptr = pStubMsg->Memory + ofs; - break; - case RPC_FC_TOP_LEVEL_CONFORMANCE: - TRACE("toplevel conformance, ofs=%ld\n", ofs); - if (pStubMsg->StackTop) { - ptr = pStubMsg->StackTop + ofs; - } - else { - /* -Os mode, MaxCount is already set */ - goto finish_conf; - } - break; - case RPC_FC_CONSTANT_CONFORMANCE: - data = ofs | ((DWORD)pFormat[1] << 16); - TRACE("constant conformance, val=%ld\n", data); - pStubMsg->MaxCount = data; - goto finish_conf; - case RPC_FC_TOP_LEVEL_MULTID_CONFORMANCE: - FIXME("toplevel multidimensional conformance, ofs=%ld\n", ofs); - if (pStubMsg->StackTop) { - ptr = pStubMsg->StackTop + ofs; - } - else { - /* ? */ - goto done_conf_grab; - } - break; - default: - FIXME("unknown conformance type %x\n", pFormat[0] & 0xf0); - } - - switch (pFormat[1]) { - case RPC_FC_DEREFERENCE: - ptr = *(LPVOID*)ptr; - break; - case RPC_FC_CALLBACK: - /* ofs is index into StubDesc->apfnExprEval */ - FIXME("handle callback\n"); - goto finish_conf; - default: - break; - } - - switch (dtype) { - case RPC_FC_LONG: - case RPC_FC_ULONG: - data = *(DWORD*)ptr; - break; - case RPC_FC_SHORT: - data = *(SHORT*)ptr; - break; - case RPC_FC_USHORT: - data = *(USHORT*)ptr; - break; - case RPC_FC_SMALL: - data = *(CHAR*)ptr; - break; - case RPC_FC_USMALL: - data = *(UCHAR*)ptr; - break; - default: - FIXME("unknown conformance data type %x\n", dtype); - goto done_conf_grab; - } - TRACE("dereferenced data type %x at %p, got %ld\n", dtype, ptr, data); - -done_conf_grab: - switch (pFormat[1]) { - case 0: /* no op */ - pStubMsg->MaxCount = data; - break; - case RPC_FC_DEREFERENCE: - /* already handled */ - break; - default: - FIXME("unknown conformance op %d\n", pFormat[1]); - goto finish_conf; - } - -finish_conf: - TRACE("resulting conformance is %ld\n", pStubMsg->MaxCount); - return pFormat+4; -} - - -/* - * NdrConformantString: - * - * What MS calls a ConformantString is, in DCE terminology, - * a Varying-Conformant String. - * [ - * maxlen: DWORD (max # of CHARTYPE characters, inclusive of '\0') - * offset: DWORD (actual string data begins at (offset) CHARTYPE's - * into unmarshalled string) - * length: DWORD (# of CHARTYPE characters, inclusive of '\0') - * [ - * data: CHARTYPE[maxlen] - * ] - * ], where CHARTYPE is the appropriate character type (specified externally) - * - */ - -/*********************************************************************** - * NdrConformantStringMarshall [RPCRT4.@] - */ -unsigned char *WINAPI NdrConformantStringMarshall(MIDL_STUB_MESSAGE *pStubMsg, - unsigned char *pszMessage, PFORMAT_STRING pFormat) -{ - unsigned long len, esize; - unsigned char *c; - - TRACE("(pStubMsg == ^%p, pszMessage == ^%p, pFormat == ^%p)\n", pStubMsg, pszMessage, pFormat); - - assert(pFormat); - if (pszMessage == NULL) { - TRACE("string=%s\n", debugstr_a(pszMessage)); - len = 0; - esize = 0; - } - else if (*pFormat == RPC_FC_C_CSTRING) { - TRACE("string=%s\n", debugstr_a(pszMessage)); - len = strlen(pszMessage)+1; - esize = 1; - } - else if (*pFormat == RPC_FC_C_WSTRING) { - TRACE("string=%s\n", debugstr_w((LPWSTR)pszMessage)); - len = strlenW((LPWSTR)pszMessage)+1; - esize = 2; - } - else { - ERR("Unhandled string type: %#x\n", *pFormat); - /* FIXME: raise an exception. */ - return NULL; - } - - if (pFormat[1] != RPC_FC_PAD) { - FIXME("sized string format=%d\n", pFormat[1]); - } - - assert( (pStubMsg->BufferLength >= (len*esize + 13)) && (pStubMsg->Buffer != NULL) ); - - c = pStubMsg->Buffer; - memset(c, 0, 12); - NDR_LOCAL_UINT32_WRITE(c, len); /* max length: strlen + 1 (for '\0') */ - c += 8; /* offset: 0 */ - NDR_LOCAL_UINT32_WRITE(c, len); /* actual length: (same) */ - c += 4; - if (len != 0) { - memcpy(c, pszMessage, len*esize); /* the string itself */ - c += len*esize; - } - pStubMsg->Buffer = c; - - STD_OVERFLOW_CHECK(pStubMsg); - - /* success */ - return NULL; /* is this always right? */ -} - -/*********************************************************************** - * NdrConformantStringBufferSize [RPCRT4.@] - */ -void WINAPI NdrConformantStringBufferSize(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char* pMemory, PFORMAT_STRING pFormat) -{ - TRACE("(pStubMsg == ^%p, pMemory == ^%p, pFormat == ^%p)\n", pStubMsg, pMemory, pFormat); - - assert(pFormat); - if (pMemory == NULL) { - /* we need 12 octets for the [maxlen, offset, len] DWORDS */ - TRACE("string=NULL\n"); - pStubMsg->BufferLength += 12 + BUFFER_PARANOIA; - } - else if (*pFormat == RPC_FC_C_CSTRING) { - /* we need 12 octets for the [maxlen, offset, len] DWORDS, + 1 octet for '\0' */ - TRACE("string=%s\n", debugstr_a(pMemory)); - pStubMsg->BufferLength += strlen(pMemory) + 13 + BUFFER_PARANOIA; - } - else if (*pFormat == RPC_FC_C_WSTRING) { - /* we need 12 octets for the [maxlen, offset, len] DWORDS, + 2 octets for L'\0' */ - TRACE("string=%s\n", debugstr_w((LPWSTR)pMemory)); - pStubMsg->BufferLength += strlenW((LPWSTR)pMemory)*2 + 14 + BUFFER_PARANOIA; - } - else { - ERR("Unhandled string type: %#x\n", *pFormat); - /* FIXME: raise an exception */ - } - - if (pFormat[1] != RPC_FC_PAD) { - FIXME("sized string format=%d\n", pFormat[1]); - } -} - -/************************************************************************ - * NdrConformantStringMemorySize [RPCRT4.@] - */ -unsigned long WINAPI NdrConformantStringMemorySize( PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat ) -{ - unsigned long rslt = 0; - - TRACE("(pStubMsg == ^%p, pFormat == ^%p)\n", pStubMsg, pFormat); - - assert(pStubMsg && pFormat); - - if (*pFormat == RPC_FC_C_CSTRING) { - rslt = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); /* maxlen */ - } - else if (*pFormat == RPC_FC_C_WSTRING) { - rslt = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer)*2; /* maxlen */ - } - else { - ERR("Unhandled string type: %#x\n", *pFormat); - /* FIXME: raise an exception */ - } - - if (pFormat[1] != RPC_FC_PAD) { - FIXME("sized string format=%d\n", pFormat[1]); - } - - TRACE(" --> %lu\n", rslt); - return rslt; -} - -/************************************************************************ - * NdrConformantStringUnmarshall [RPCRT4.@] - */ -unsigned char *WINAPI NdrConformantStringUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, - unsigned char** ppMemory, PFORMAT_STRING pFormat, unsigned char fMustAlloc ) -{ - unsigned long len, esize, ofs; - unsigned char *pMem; - - TRACE("(pStubMsg == ^%p, *pMemory == ^%p, pFormat == ^%p, fMustAlloc == %u)\n", - pStubMsg, *ppMemory, pFormat, fMustAlloc); - - assert(pFormat && ppMemory && pStubMsg); - - pStubMsg->Buffer += 4; - ofs = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); - pStubMsg->Buffer += 4; - len = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); - pStubMsg->Buffer += 4; - - if (*pFormat == RPC_FC_C_CSTRING) esize = 1; - else if (*pFormat == RPC_FC_C_WSTRING) esize = 2; - else { - ERR("Unhandled string type: %#x\n", *pFormat); - /* FIXME: raise an exception */ - esize = 0; - } - - if (pFormat[1] != RPC_FC_PAD) { - FIXME("sized string format=%d\n", pFormat[1]); - } - - if (fMustAlloc) { - *ppMemory = NdrAllocate(pStubMsg, len*esize + BUFFER_PARANOIA); - } else { - if (pStubMsg->ReuseBuffer && !*ppMemory) - /* for servers, we may just point straight into the RPC buffer, I think - * (I guess that's what MS does since MIDL code doesn't try to free) */ - *ppMemory = pStubMsg->Buffer - ofs*esize; - /* for clients, memory should be provided by caller */ - } - - if (len == 0) { - *ppMemory = NULL; - return NULL; - } - - pMem = *ppMemory + ofs*esize; - - if (pMem != pStubMsg->Buffer) - memcpy(pMem, pStubMsg->Buffer, len*esize); - - pStubMsg->Buffer += len*esize; - - if (*pFormat == RPC_FC_C_CSTRING) { - TRACE("string=%s\n", debugstr_a(pMem)); - } - else if (*pFormat == RPC_FC_C_WSTRING) { - TRACE("string=%s\n", debugstr_w((LPWSTR)pMem)); - } - - return NULL; /* FIXME: is this always right? */ -} - -/*********************************************************************** - * PointerMarshall - */ -void WINAPI PointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *Buffer, - unsigned char *Pointer, - PFORMAT_STRING pFormat) -{ - unsigned type = pFormat[0], attr = pFormat[1]; - PFORMAT_STRING desc; - NDR_MARSHALL m; - - TRACE("(%p,%p,%p,%p)\n", pStubMsg, Buffer, Pointer, pFormat); - TRACE("type=%d, attr=%d\n", type, attr); - pFormat += 2; - if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; - else desc = pFormat + *(const SHORT*)pFormat; - if (attr & RPC_FC_P_DEREF) { - Pointer = *(unsigned char**)Pointer; - TRACE("deref => %p\n", Pointer); - } - - *(LPVOID*)Buffer = 0; - - switch (type) { - case RPC_FC_RP: /* ref pointer (always non-null) */ - break; - case RPC_FC_UP: /* unique pointer */ - break; - default: - FIXME("unhandled ptr type=%02x\n", type); - } - - m = NdrMarshaller[*desc & NDR_TABLE_MASK]; - if (m) m(pStubMsg, Pointer, desc); - else FIXME("no marshaller for data type=%02x\n", *desc); - - STD_OVERFLOW_CHECK(pStubMsg); -} - -/*********************************************************************** - * PointerUnmarshall - */ -void WINAPI PointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *Buffer, - unsigned char **pPointer, - PFORMAT_STRING pFormat, - unsigned char fMustAlloc) -{ - unsigned type = pFormat[0], attr = pFormat[1]; - PFORMAT_STRING desc; - NDR_UNMARSHALL m; - - TRACE("(%p,%p,%p,%p,%d)\n", pStubMsg, Buffer, pPointer, pFormat, fMustAlloc); - TRACE("type=%d, attr=%d\n", type, attr); - pFormat += 2; - if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; - else desc = pFormat + *(const SHORT*)pFormat; - if (attr & RPC_FC_P_DEREF) { - pPointer = *(unsigned char***)pPointer; - TRACE("deref => %p\n", pPointer); - } - - switch (type) { - case RPC_FC_RP: /* ref pointer (always non-null) */ - break; - case RPC_FC_UP: /* unique pointer */ - break; - default: - FIXME("unhandled ptr type=%02x\n", type); - } - - *pPointer = NULL; - - m = NdrUnmarshaller[*desc & NDR_TABLE_MASK]; - if (m) m(pStubMsg, pPointer, desc, fMustAlloc); - else FIXME("no unmarshaller for data type=%02x\n", *desc); - TRACE("pointer=%p\n", *pPointer); -} - -/*********************************************************************** - * PointerBufferSize - */ -void WINAPI PointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *Pointer, - PFORMAT_STRING pFormat) -{ - unsigned type = pFormat[0], attr = pFormat[1]; - PFORMAT_STRING desc; - NDR_BUFFERSIZE m; - - TRACE("(%p,%p,%p)\n", pStubMsg, Pointer, pFormat); - TRACE("type=%d, attr=%d\n", type, attr); - pFormat += 2; - if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; - else desc = pFormat + *(const SHORT*)pFormat; - if (attr & RPC_FC_P_DEREF) { - Pointer = *(unsigned char**)Pointer; - TRACE("deref => %p\n", Pointer); - } - - switch (type) { - case RPC_FC_RP: /* ref pointer (always non-null) */ - break; - case RPC_FC_UP: /* unique pointer */ - break; - default: - FIXME("unhandled ptr type=%02x\n", type); - } - - m = NdrBufferSizer[*desc & NDR_TABLE_MASK]; - if (m) m(pStubMsg, Pointer, desc); - else FIXME("no buffersizer for data type=%02x\n", *desc); -} - -/*********************************************************************** - * PointerMemorySize [RPCRT4.@] - */ -unsigned long WINAPI PointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *Buffer, - PFORMAT_STRING pFormat) -{ - unsigned type = pFormat[0], attr = pFormat[1]; - PFORMAT_STRING desc; - NDR_MEMORYSIZE m; - - FIXME("(%p,%p,%p): stub\n", pStubMsg, Buffer, pFormat); - TRACE("type=%d, attr=%d\n", type, attr); - pFormat += 2; - if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; - else desc = pFormat + *(const SHORT*)pFormat; - if (attr & RPC_FC_P_DEREF) { - TRACE("deref\n"); - } - - switch (type) { - case RPC_FC_RP: /* ref pointer (always non-null) */ - break; - default: - FIXME("unhandled ptr type=%02x\n", type); - } - - m = NdrMemorySizer[*desc & NDR_TABLE_MASK]; - if (m) m(pStubMsg, desc); - else FIXME("no memorysizer for data type=%02x\n", *desc); - - return 0; -} - -/*********************************************************************** - * PointerFree [RPCRT4.@] - */ -void WINAPI PointerFree(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *Pointer, - PFORMAT_STRING pFormat) -{ - unsigned type = pFormat[0], attr = pFormat[1]; - PFORMAT_STRING desc; - NDR_FREE m; - - TRACE("(%p,%p,%p)\n", pStubMsg, Pointer, pFormat); - TRACE("type=%d, attr=%d\n", type, attr); - if (attr & RPC_FC_P_DONTFREE) return; - pFormat += 2; - if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; - else desc = pFormat + *(const SHORT*)pFormat; - if (attr & RPC_FC_P_DEREF) { - Pointer = *(unsigned char**)Pointer; - TRACE("deref => %p\n", Pointer); - } - - if (!Pointer) return; - - m = NdrFreer[*desc & NDR_TABLE_MASK]; - if (m) m(pStubMsg, Pointer, desc); - - /* hmm... is this sensible? - * perhaps we should check if the memory comes from NdrAllocate, - * and deallocate only if so - checking if the pointer is between - * BufferStart and BufferEnd is probably no good since the buffer - * may be reallocated when the server wants to marshal the reply */ - switch (*desc) { - case RPC_FC_BOGUS_STRUCT: - case RPC_FC_BOGUS_ARRAY: - case RPC_FC_USER_MARSHAL: - break; - default: - FIXME("unhandled data type=%02x\n", *desc); - case RPC_FC_CARRAY: - case RPC_FC_C_CSTRING: - case RPC_FC_C_WSTRING: - if (pStubMsg->ReuseBuffer) goto notfree; - break; - case RPC_FC_IP: - goto notfree; - } - - if (attr & RPC_FC_P_ONSTACK) { - TRACE("not freeing stack ptr %p\n", Pointer); - return; - } - TRACE("freeing %p\n", Pointer); - NdrFree(pStubMsg, Pointer); - return; -notfree: - TRACE("not freeing %p\n", Pointer); -} - -/*********************************************************************** - * EmbeddedPointerMarshall - */ -unsigned char * WINAPI EmbeddedPointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ - unsigned char *Mark = pStubMsg->BufferMark; - unsigned long Offset = pStubMsg->Offset; - unsigned ofs, rep, count, stride, xofs; - - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - - if (*pFormat != RPC_FC_PP) return NULL; - pFormat += 2; - - while (pFormat[0] != RPC_FC_END) { - switch (pFormat[0]) { - default: - FIXME("unknown repeat type %d\n", pFormat[0]); - case RPC_FC_NO_REPEAT: - rep = 1; - stride = 0; - ofs = 0; - count = 1; - xofs = 0; - pFormat += 2; - break; - case RPC_FC_FIXED_REPEAT: - rep = *(const WORD*)&pFormat[2]; - stride = *(const WORD*)&pFormat[4]; - ofs = *(const WORD*)&pFormat[6]; - count = *(const WORD*)&pFormat[8]; - xofs = 0; - pFormat += 10; - break; - case RPC_FC_VARIABLE_REPEAT: - rep = pStubMsg->MaxCount; - stride = *(const WORD*)&pFormat[2]; - ofs = *(const WORD*)&pFormat[4]; - count = *(const WORD*)&pFormat[6]; - xofs = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? Offset * stride : 0; - pFormat += 8; - break; - } - /* ofs doesn't seem to matter in this context */ - while (rep) { - PFORMAT_STRING info = pFormat; - unsigned char *membase = pMemory + xofs; - unsigned u; - for (u=0; u<count; u++,info+=8) { - unsigned char *memptr = membase + *(const SHORT*)&info[0]; - unsigned char *bufptr = Mark + *(const SHORT*)&info[2]; - PointerMarshall(pStubMsg, bufptr, *(unsigned char**)memptr, info+4); - } - rep--; - } - pFormat += 8 * count; - } - - STD_OVERFLOW_CHECK(pStubMsg); - - return NULL; -} - -/*********************************************************************** - * EmbeddedPointerUnmarshall - */ -unsigned char * WINAPI EmbeddedPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char **ppMemory, - PFORMAT_STRING pFormat, - unsigned char fMustAlloc) -{ - unsigned char *Mark = pStubMsg->BufferMark; - unsigned long Offset = pStubMsg->Offset; - unsigned ofs, rep, count, stride, xofs; - - TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); - - if (*pFormat != RPC_FC_PP) return NULL; - pFormat += 2; - - while (pFormat[0] != RPC_FC_END) { - switch (pFormat[0]) { - default: - FIXME("unknown repeat type %d\n", pFormat[0]); - case RPC_FC_NO_REPEAT: - rep = 1; - stride = 0; - ofs = 0; - count = 1; - xofs = 0; - pFormat += 2; - break; - case RPC_FC_FIXED_REPEAT: - rep = *(const WORD*)&pFormat[2]; - stride = *(const WORD*)&pFormat[4]; - ofs = *(const WORD*)&pFormat[6]; - count = *(const WORD*)&pFormat[8]; - xofs = 0; - pFormat += 10; - break; - case RPC_FC_VARIABLE_REPEAT: - rep = pStubMsg->MaxCount; - stride = *(const WORD*)&pFormat[2]; - ofs = *(const WORD*)&pFormat[4]; - count = *(const WORD*)&pFormat[6]; - xofs = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? Offset * stride : 0; - pFormat += 8; - break; - } - /* ofs doesn't seem to matter in this context */ - while (rep) { - PFORMAT_STRING info = pFormat; - unsigned char *membase = *ppMemory + xofs; - unsigned u; - for (u=0; u<count; u++,info+=8) { - unsigned char *memptr = membase + *(const SHORT*)&info[0]; - unsigned char *bufptr = Mark + *(const SHORT*)&info[2]; - PointerUnmarshall(pStubMsg, bufptr, (unsigned char**)memptr, info+4, fMustAlloc); - } - rep--; - } - pFormat += 8 * count; - } - - return NULL; -} - -/*********************************************************************** - * EmbeddedPointerBufferSize - */ -void WINAPI EmbeddedPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ - unsigned long Offset = pStubMsg->Offset; - unsigned ofs, rep, count, stride, xofs; - - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - if (*pFormat != RPC_FC_PP) return; - pFormat += 2; - - while (pFormat[0] != RPC_FC_END) { - switch (pFormat[0]) { - default: - FIXME("unknown repeat type %d\n", pFormat[0]); - case RPC_FC_NO_REPEAT: - rep = 1; - stride = 0; - ofs = 0; - count = 1; - xofs = 0; - pFormat += 2; - break; - case RPC_FC_FIXED_REPEAT: - rep = *(const WORD*)&pFormat[2]; - stride = *(const WORD*)&pFormat[4]; - ofs = *(const WORD*)&pFormat[6]; - count = *(const WORD*)&pFormat[8]; - xofs = 0; - pFormat += 10; - break; - case RPC_FC_VARIABLE_REPEAT: - rep = pStubMsg->MaxCount; - stride = *(const WORD*)&pFormat[2]; - ofs = *(const WORD*)&pFormat[4]; - count = *(const WORD*)&pFormat[6]; - xofs = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? Offset * stride : 0; - pFormat += 8; - break; - } - /* ofs doesn't seem to matter in this context */ - while (rep) { - PFORMAT_STRING info = pFormat; - unsigned char *membase = pMemory + xofs; - unsigned u; - for (u=0; u<count; u++,info+=8) { - unsigned char *memptr = membase + *(const SHORT*)&info[0]; - PointerBufferSize(pStubMsg, *(unsigned char**)memptr, info+4); - } - rep--; - } - pFormat += 8 * count; - } -} - -/*********************************************************************** - * EmbeddedPointerMemorySize - */ -unsigned long WINAPI EmbeddedPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat) -{ - unsigned long Offset = pStubMsg->Offset; - unsigned char *Mark = pStubMsg->BufferMark; - unsigned ofs, rep, count, stride, xofs; - - FIXME("(%p,%p): stub\n", pStubMsg, pFormat); - if (*pFormat != RPC_FC_PP) return 0; - pFormat += 2; - - while (pFormat[0] != RPC_FC_END) { - switch (pFormat[0]) { - default: - FIXME("unknown repeat type %d\n", pFormat[0]); - case RPC_FC_NO_REPEAT: - rep = 1; - stride = 0; - ofs = 0; - count = 1; - xofs = 0; - pFormat += 2; - break; - case RPC_FC_FIXED_REPEAT: - rep = *(const WORD*)&pFormat[2]; - stride = *(const WORD*)&pFormat[4]; - ofs = *(const WORD*)&pFormat[6]; - count = *(const WORD*)&pFormat[8]; - xofs = 0; - pFormat += 10; - break; - case RPC_FC_VARIABLE_REPEAT: - rep = pStubMsg->MaxCount; - stride = *(const WORD*)&pFormat[2]; - ofs = *(const WORD*)&pFormat[4]; - count = *(const WORD*)&pFormat[6]; - xofs = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? Offset * stride : 0; - pFormat += 8; - break; - } - /* ofs doesn't seem to matter in this context */ - while (rep) { - PFORMAT_STRING info = pFormat; - unsigned u; - for (u=0; u<count; u++,info+=8) { - unsigned char *bufptr = Mark + *(const SHORT*)&info[2]; - PointerMemorySize(pStubMsg, bufptr, info+4); - } - rep--; - } - pFormat += 8 * count; - } - - return 0; -} - -/*********************************************************************** - * EmbeddedPointerFree - */ -void WINAPI EmbeddedPointerFree(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ - unsigned long Offset = pStubMsg->Offset; - unsigned ofs, rep, count, stride, xofs; - - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - if (*pFormat != RPC_FC_PP) return; - pFormat += 2; - - while (pFormat[0] != RPC_FC_END) { - switch (pFormat[0]) { - default: - FIXME("unknown repeat type %d\n", pFormat[0]); - case RPC_FC_NO_REPEAT: - rep = 1; - stride = 0; - ofs = 0; - count = 1; - xofs = 0; - pFormat += 2; - break; - case RPC_FC_FIXED_REPEAT: - rep = *(const WORD*)&pFormat[2]; - stride = *(const WORD*)&pFormat[4]; - ofs = *(const WORD*)&pFormat[6]; - count = *(const WORD*)&pFormat[8]; - xofs = 0; - pFormat += 10; - break; - case RPC_FC_VARIABLE_REPEAT: - rep = pStubMsg->MaxCount; - stride = *(const WORD*)&pFormat[2]; - ofs = *(const WORD*)&pFormat[4]; - count = *(const WORD*)&pFormat[6]; - xofs = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? Offset * stride : 0; - pFormat += 8; - break; - } - /* ofs doesn't seem to matter in this context */ - while (rep) { - PFORMAT_STRING info = pFormat; - unsigned char *membase = pMemory + xofs; - unsigned u; - for (u=0; u<count; u++,info+=8) { - unsigned char *memptr = membase + *(const SHORT*)&info[0]; - PointerFree(pStubMsg, *(unsigned char**)memptr, info+4); - } - rep--; - } - pFormat += 8 * count; - } -} - -/*********************************************************************** - * NdrPointerMarshall [RPCRT4.@] - */ -unsigned char * WINAPI NdrPointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - - pStubMsg->BufferMark = pStubMsg->Buffer; - PointerMarshall(pStubMsg, pStubMsg->Buffer, pMemory, pFormat); - pStubMsg->Buffer += 4; - - STD_OVERFLOW_CHECK(pStubMsg); - - return NULL; -} - -/*********************************************************************** - * NdrPointerUnmarshall [RPCRT4.@] - */ -unsigned char * WINAPI NdrPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char **ppMemory, - PFORMAT_STRING pFormat, - unsigned char fMustAlloc) -{ - TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); - - pStubMsg->BufferMark = pStubMsg->Buffer; - PointerUnmarshall(pStubMsg, pStubMsg->Buffer, ppMemory, pFormat, fMustAlloc); - pStubMsg->Buffer += 4; - - return NULL; -} - -/*********************************************************************** - * NdrPointerBufferSize [RPCRT4.@] - */ -void WINAPI NdrPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - pStubMsg->BufferLength += 4; - PointerBufferSize(pStubMsg, pMemory, pFormat); -} - -/*********************************************************************** - * NdrPointerMemorySize [RPCRT4.@] - */ -unsigned long WINAPI NdrPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat) -{ - /* unsigned size = *(LPWORD)(pFormat+2); */ - FIXME("(%p,%p): stub\n", pStubMsg, pFormat); - PointerMemorySize(pStubMsg, pStubMsg->Buffer, pFormat); - return 0; -} - -/*********************************************************************** - * NdrPointerFree [RPCRT4.@] - */ -void WINAPI NdrPointerFree(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - PointerFree(pStubMsg, pMemory, pFormat); -} - -/*********************************************************************** - * NdrSimpleStructMarshall [RPCRT4.@] - */ -unsigned char * WINAPI NdrSimpleStructMarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ - unsigned size = *(const WORD*)(pFormat+2); - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - - memcpy(pStubMsg->Buffer, pMemory, size); - pStubMsg->BufferMark = pStubMsg->Buffer; - pStubMsg->Buffer += size; - - if (pFormat[0] != RPC_FC_STRUCT) - EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat+4); - - /* - * This test does not work when NdrSimpleStructMarshall is called - * by an rpc-server to marshall data to return to the client because - * BufferStart and BufferEnd are bogus. MIDL does not update them - * when a new buffer is allocated in order to return data to the caller. - */ -#if 0 - STD_OVERFLOW_CHECK(pStubMsg); -#endif - - return NULL; -} - -/*********************************************************************** - * NdrSimpleStructUnmarshall [RPCRT4.@] - */ -unsigned char * WINAPI NdrSimpleStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char **ppMemory, - PFORMAT_STRING pFormat, - unsigned char fMustAlloc) -{ - unsigned size = *(const WORD*)(pFormat+2); - TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); - - if (fMustAlloc) { - *ppMemory = NdrAllocate(pStubMsg, size); - memcpy(*ppMemory, pStubMsg->Buffer, size); - } else { - if (pStubMsg->ReuseBuffer && !*ppMemory) - /* for servers, we may just point straight into the RPC buffer, I think - * (I guess that's what MS does since MIDL code doesn't try to free) */ - *ppMemory = pStubMsg->Buffer; - else - /* for clients, memory should be provided by caller */ - memcpy(*ppMemory, pStubMsg->Buffer, size); - } - - pStubMsg->BufferMark = pStubMsg->Buffer; - pStubMsg->Buffer += size; - - if (pFormat[0] != RPC_FC_STRUCT) - EmbeddedPointerUnmarshall(pStubMsg, ppMemory, pFormat+4, fMustAlloc); - - return NULL; -} - - -/*********************************************************************** - * NdrSimpleTypeUnmarshall [RPCRT4.@] - */ -void WINAPI NdrSimpleTypeMarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - unsigned char FormatChar) -{ - FIXME("stub\n"); -} - - -/*********************************************************************** - * NdrSimpleTypeUnmarshall [RPCRT4.@] - */ -void WINAPI NdrSimpleTypeUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - unsigned char FormatChar) -{ - FIXME("stub\n"); -} - - -/*********************************************************************** - * NdrSimpleStructBufferSize [RPCRT4.@] - */ -void WINAPI NdrSimpleStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ - unsigned size = *(const WORD*)(pFormat+2); - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - pStubMsg->BufferLength += size; - if (pFormat[0] != RPC_FC_STRUCT) - EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat+4); -} - -/*********************************************************************** - * NdrSimpleStructMemorySize [RPCRT4.@] - */ -unsigned long WINAPI NdrSimpleStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat) -{ - /* unsigned size = *(LPWORD)(pFormat+2); */ - FIXME("(%p,%p): stub\n", pStubMsg, pFormat); - if (pFormat[0] != RPC_FC_STRUCT) - EmbeddedPointerMemorySize(pStubMsg, pFormat+4); - return 0; -} - -/*********************************************************************** - * NdrSimpleStructFree [RPCRT4.@] - */ -void WINAPI NdrSimpleStructFree(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - if (pFormat[0] != RPC_FC_STRUCT) - EmbeddedPointerFree(pStubMsg, pMemory, pFormat+4); -} - - -unsigned long WINAPI EmbeddedComplexSize(PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat) -{ - switch (*pFormat) { - case RPC_FC_STRUCT: - case RPC_FC_PSTRUCT: - case RPC_FC_CSTRUCT: - case RPC_FC_BOGUS_STRUCT: - return *(const WORD*)&pFormat[2]; - case RPC_FC_USER_MARSHAL: - return *(const WORD*)&pFormat[4]; - default: - FIXME("unhandled embedded type %02x\n", *pFormat); - } - return 0; -} - - -unsigned char * WINAPI ComplexMarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat, - PFORMAT_STRING pPointer) -{ - PFORMAT_STRING desc; - NDR_MARSHALL m; - unsigned long size; - - while (*pFormat != RPC_FC_END) { - switch (*pFormat) { - case RPC_FC_SHORT: - case RPC_FC_USHORT: - TRACE("short=%d <= %p\n", *(WORD*)pMemory, pMemory); - memcpy(pStubMsg->Buffer, pMemory, 2); - pStubMsg->Buffer += 2; - pMemory += 2; - break; - case RPC_FC_LONG: - case RPC_FC_ULONG: - TRACE("long=%ld <= %p\n", *(DWORD*)pMemory, pMemory); - memcpy(pStubMsg->Buffer, pMemory, 4); - pStubMsg->Buffer += 4; - pMemory += 4; - break; - case RPC_FC_POINTER: - TRACE("pointer=%p <= %p\n", *(unsigned char**)pMemory, pMemory); - NdrPointerMarshall(pStubMsg, *(unsigned char**)pMemory, pPointer); - pPointer += 4; - pMemory += 4; - break; - case RPC_FC_ALIGNM4: - ALIGN_POINTER(pMemory, 3); - break; - case RPC_FC_ALIGNM8: - ALIGN_POINTER(pMemory, 7); - break; - case RPC_FC_EMBEDDED_COMPLEX: - pMemory += pFormat[1]; - pFormat += 2; - desc = pFormat + *(const SHORT*)pFormat; - size = EmbeddedComplexSize(pStubMsg, desc); - TRACE("embedded complex (size=%ld) <= %p\n", size, pMemory); - m = NdrMarshaller[*desc & NDR_TABLE_MASK]; - if (m) m(pStubMsg, pMemory, desc); - else FIXME("no marshaller for embedded type %02x\n", *desc); - pMemory += size; - pFormat += 2; - continue; - case RPC_FC_PAD: - break; - default: - FIXME("unhandled format %02x\n", *pFormat); - } - pFormat++; - } - - return pMemory; -} - -unsigned char * WINAPI ComplexUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat, - PFORMAT_STRING pPointer, - unsigned char fMustAlloc) -{ - PFORMAT_STRING desc; - NDR_UNMARSHALL m; - unsigned long size; - - while (*pFormat != RPC_FC_END) { - switch (*pFormat) { - case RPC_FC_SHORT: - case RPC_FC_USHORT: - memcpy(pMemory, pStubMsg->Buffer, 2); - TRACE("short=%d => %p\n", *(WORD*)pMemory, pMemory); - pStubMsg->Buffer += 2; - pMemory += 2; - break; - case RPC_FC_LONG: - case RPC_FC_ULONG: - memcpy(pMemory, pStubMsg->Buffer, 4); - TRACE("long=%ld => %p\n", *(DWORD*)pMemory, pMemory); - pStubMsg->Buffer += 4; - pMemory += 4; - break; - case RPC_FC_POINTER: - *(unsigned char**)pMemory = NULL; - TRACE("pointer => %p\n", pMemory); - NdrPointerUnmarshall(pStubMsg, (unsigned char**)pMemory, pPointer, fMustAlloc); - pPointer += 4; - pMemory += 4; - break; - case RPC_FC_ALIGNM4: - ALIGN_POINTER(pMemory, 3); - break; - case RPC_FC_ALIGNM8: - ALIGN_POINTER(pMemory, 7); - break; - case RPC_FC_EMBEDDED_COMPLEX: - pMemory += pFormat[1]; - pFormat += 2; - desc = pFormat + *(const SHORT*)pFormat; - size = EmbeddedComplexSize(pStubMsg, desc); - TRACE("embedded complex (size=%ld) => %p\n", size, pMemory); - m = NdrUnmarshaller[*desc & NDR_TABLE_MASK]; - memset(pMemory, 0, size); /* just in case */ - if (m) m(pStubMsg, &pMemory, desc, fMustAlloc); - else FIXME("no unmarshaller for embedded type %02x\n", *desc); - pMemory += size; - pFormat += 2; - continue; - case RPC_FC_PAD: - break; - default: - FIXME("unhandled format %d\n", *pFormat); - } - pFormat++; - } - - return pMemory; -} - -unsigned char * WINAPI ComplexBufferSize(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat, - PFORMAT_STRING pPointer) -{ - PFORMAT_STRING desc; - NDR_BUFFERSIZE m; - unsigned long size; - - while (*pFormat != RPC_FC_END) { - switch (*pFormat) { - case RPC_FC_SHORT: - case RPC_FC_USHORT: - pStubMsg->BufferLength += 2; - pMemory += 2; - break; - case RPC_FC_LONG: - case RPC_FC_ULONG: - pStubMsg->BufferLength += 4; - pMemory += 4; - break; - case RPC_FC_POINTER: - NdrPointerBufferSize(pStubMsg, *(unsigned char**)pMemory, pPointer); - pPointer += 4; - pMemory += 4; - break; - case RPC_FC_ALIGNM4: - ALIGN_POINTER(pMemory, 3); - break; - case RPC_FC_ALIGNM8: - ALIGN_POINTER(pMemory, 7); - break; - case RPC_FC_EMBEDDED_COMPLEX: - pMemory += pFormat[1]; - pFormat += 2; - desc = pFormat + *(const SHORT*)pFormat; - size = EmbeddedComplexSize(pStubMsg, desc); - m = NdrBufferSizer[*desc & NDR_TABLE_MASK]; - if (m) m(pStubMsg, pMemory, desc); - else FIXME("no buffersizer for embedded type %02x\n", *desc); - pMemory += size; - pFormat += 2; - continue; - case RPC_FC_PAD: - break; - default: - FIXME("unhandled format %d\n", *pFormat); - } - pFormat++; - } - - return pMemory; -} - -unsigned char * WINAPI ComplexFree(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat, - PFORMAT_STRING pPointer) -{ - PFORMAT_STRING desc; - NDR_FREE m; - unsigned long size; - - while (*pFormat != RPC_FC_END) { - switch (*pFormat) { - case RPC_FC_SHORT: - case RPC_FC_USHORT: - pMemory += 2; - break; - case RPC_FC_LONG: - case RPC_FC_ULONG: - pMemory += 4; - break; - case RPC_FC_POINTER: - NdrPointerFree(pStubMsg, *(unsigned char**)pMemory, pPointer); - pPointer += 4; - pMemory += 4; - break; - case RPC_FC_ALIGNM4: - ALIGN_POINTER(pMemory, 3); - break; - case RPC_FC_ALIGNM8: - ALIGN_POINTER(pMemory, 7); - break; - case RPC_FC_EMBEDDED_COMPLEX: - pMemory += pFormat[1]; - pFormat += 2; - desc = pFormat + *(const SHORT*)pFormat; - size = EmbeddedComplexSize(pStubMsg, desc); - m = NdrFreer[*desc & NDR_TABLE_MASK]; - if (m) m(pStubMsg, pMemory, desc); - else FIXME("no freer for embedded type %02x\n", *desc); - pMemory += size; - pFormat += 2; - continue; - case RPC_FC_PAD: - break; - default: - FIXME("unhandled format %d\n", *pFormat); - } - pFormat++; - } - - return pMemory; -} - -unsigned long WINAPI ComplexStructSize(PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat) -{ - PFORMAT_STRING desc; - unsigned long size = 0; - - while (*pFormat != RPC_FC_END) { - switch (*pFormat) { - case RPC_FC_SHORT: - case RPC_FC_USHORT: - size += 2; - break; - case RPC_FC_LONG: - case RPC_FC_ULONG: - size += 4; - break; - case RPC_FC_POINTER: - size += 4; - break; - case RPC_FC_ALIGNM4: - ALIGN_LENGTH(size, 3); - break; - case RPC_FC_ALIGNM8: - ALIGN_LENGTH(size, 7); - break; - case RPC_FC_EMBEDDED_COMPLEX: - size += pFormat[1]; - pFormat += 2; - desc = pFormat + *(const SHORT*)pFormat; - size += EmbeddedComplexSize(pStubMsg, desc); - pFormat += 2; - continue; - case RPC_FC_PAD: - break; - default: - FIXME("unhandled format %d\n", *pFormat); - } - pFormat++; - } - - return size; -} - -/*********************************************************************** - * NdrComplexStructMarshall [RPCRT4.@] - */ -unsigned char * WINAPI NdrComplexStructMarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ - PFORMAT_STRING conf_array = NULL; - PFORMAT_STRING pointer_desc = NULL; - unsigned char *OldMemory = pStubMsg->Memory; - - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - - pFormat += 4; - if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; - pFormat += 2; - if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; - pFormat += 2; - - pStubMsg->Memory = pMemory; - - ComplexMarshall(pStubMsg, pMemory, pFormat, pointer_desc); - - if (conf_array) - NdrConformantArrayMarshall(pStubMsg, pMemory, conf_array); - - pStubMsg->Memory = OldMemory; - - STD_OVERFLOW_CHECK(pStubMsg); - - return NULL; -} - -/*********************************************************************** - * NdrComplexStructUnmarshall [RPCRT4.@] - */ -unsigned char * WINAPI NdrComplexStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char **ppMemory, - PFORMAT_STRING pFormat, - unsigned char fMustAlloc) -{ - unsigned size = *(const WORD*)(pFormat+2); - PFORMAT_STRING conf_array = NULL; - PFORMAT_STRING pointer_desc = NULL; - unsigned char *pMemory; - - TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); - - if (fMustAlloc || !*ppMemory) - *ppMemory = NdrAllocate(pStubMsg, size); - - pFormat += 4; - if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; - pFormat += 2; - if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; - pFormat += 2; - - pMemory = ComplexUnmarshall(pStubMsg, *ppMemory, pFormat, pointer_desc, fMustAlloc); - - if (conf_array) - NdrConformantArrayUnmarshall(pStubMsg, &pMemory, conf_array, fMustAlloc); - - return NULL; -} - -/*********************************************************************** - * NdrComplexStructBufferSize [RPCRT4.@] - */ -void WINAPI NdrComplexStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ - PFORMAT_STRING conf_array = NULL; - PFORMAT_STRING pointer_desc = NULL; - unsigned char *OldMemory = pStubMsg->Memory; - - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - - pFormat += 4; - if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; - pFormat += 2; - if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; - pFormat += 2; - - pStubMsg->Memory = pMemory; - - pMemory = ComplexBufferSize(pStubMsg, pMemory, pFormat, pointer_desc); - - if (conf_array) - NdrConformantArrayBufferSize(pStubMsg, pMemory, conf_array); - - pStubMsg->Memory = OldMemory; -} - -/*********************************************************************** - * NdrComplexStructMemorySize [RPCRT4.@] - */ -unsigned long WINAPI NdrComplexStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat) -{ - /* unsigned size = *(LPWORD)(pFormat+2); */ - PFORMAT_STRING conf_array = NULL; - PFORMAT_STRING pointer_desc = NULL; - - FIXME("(%p,%p): stub\n", pStubMsg, pFormat); - - pFormat += 4; - if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; - pFormat += 2; - if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; - pFormat += 2; - - return 0; -} - -/*********************************************************************** - * NdrComplexStructFree [RPCRT4.@] - */ -void WINAPI NdrComplexStructFree(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ - PFORMAT_STRING conf_array = NULL; - PFORMAT_STRING pointer_desc = NULL; - unsigned char *OldMemory = pStubMsg->Memory; - - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - - pFormat += 4; - if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; - pFormat += 2; - if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; - pFormat += 2; - - pStubMsg->Memory = pMemory; - - pMemory = ComplexFree(pStubMsg, pMemory, pFormat, pointer_desc); - - if (conf_array) - NdrConformantArrayFree(pStubMsg, pMemory, conf_array); - - pStubMsg->Memory = OldMemory; -} - -/*********************************************************************** - * NdrConformantArrayMarshall [RPCRT4.@] - */ -unsigned char * WINAPI NdrConformantArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ - DWORD size = 0, esize = *(const WORD*)(pFormat+2); - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); - - pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); - size = pStubMsg->MaxCount; - - NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, size); - pStubMsg->Buffer += 4; - - memcpy(pStubMsg->Buffer, pMemory, size*esize); - pStubMsg->BufferMark = pStubMsg->Buffer; - pStubMsg->Buffer += size*esize; - - EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat); - - STD_OVERFLOW_CHECK(pStubMsg); - - return NULL; -} - -/*********************************************************************** - * NdrConformantArrayUnmarshall [RPCRT4.@] - */ -unsigned char * WINAPI NdrConformantArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char **ppMemory, - PFORMAT_STRING pFormat, - unsigned char fMustAlloc) -{ - DWORD size = 0, esize = *(const WORD*)(pFormat+2); - TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); - if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); - - pFormat = ReadConformance(pStubMsg, pFormat+4); - size = pStubMsg->MaxCount; - - if (fMustAlloc) { - *ppMemory = NdrAllocate(pStubMsg, size*esize); - memcpy(*ppMemory, pStubMsg->Buffer, size*esize); - } else { - if (pStubMsg->ReuseBuffer && !*ppMemory) - /* for servers, we may just point straight into the RPC buffer, I think - * (I guess that's what MS does since MIDL code doesn't try to free) */ - *ppMemory = pStubMsg->Buffer; - else - /* for clients, memory should be provided by caller */ - memcpy(*ppMemory, pStubMsg->Buffer, size*esize); - } - - pStubMsg->BufferMark = pStubMsg->Buffer; - pStubMsg->Buffer += size*esize; - - EmbeddedPointerUnmarshall(pStubMsg, ppMemory, pFormat, fMustAlloc); - - return NULL; -} - -/*********************************************************************** - * NdrConformantArrayBufferSize [RPCRT4.@] - */ -void WINAPI NdrConformantArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ - DWORD size = 0, esize = *(const WORD*)(pFormat+2); - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); - - pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); - size = pStubMsg->MaxCount; - - pStubMsg->BufferLength += size*esize; - - EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat); -} - -/*********************************************************************** - * NdrConformantArrayMemorySize [RPCRT4.@] - */ -unsigned long WINAPI NdrConformantArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat) -{ - DWORD size = 0; - FIXME("(%p,%p): stub\n", pStubMsg, pFormat); - if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); - - pFormat = ReadConformance(pStubMsg, pFormat+4); - size = pStubMsg->MaxCount; - - EmbeddedPointerMemorySize(pStubMsg, pFormat); - - return 0; -} - -/*********************************************************************** - * NdrConformantArrayFree [RPCRT4.@] - */ -void WINAPI NdrConformantArrayFree(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); - - EmbeddedPointerFree(pStubMsg, pMemory, pFormat); -} - - -/*********************************************************************** - * NdrConformantVaryingArrayMarshall [RPCRT4.@] - */ -unsigned char* WINAPI NdrConformantVaryingArrayMarshall( PMIDL_STUB_MESSAGE pStubMsg, - unsigned char* pMemory, - PFORMAT_STRING pFormat ) -{ - FIXME( "stub\n" ); - return NULL; -} - - -/*********************************************************************** - * NdrConformantVaryingArrayUnmarshall [RPCRT4.@] - */ -unsigned char* WINAPI NdrConformantVaryingArrayUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, - unsigned char** ppMemory, - PFORMAT_STRING pFormat, - unsigned char fMustAlloc ) -{ - FIXME( "stub\n" ); - return NULL; -} - - -/*********************************************************************** - * NdrConformantVaryingArrayFree [RPCRT4.@] - */ -void WINAPI NdrConformantVaryingArrayFree( PMIDL_STUB_MESSAGE pStubMsg, - unsigned char* pMemory, - PFORMAT_STRING pFormat ) -{ - FIXME( "stub\n" ); -} - - -/*********************************************************************** - * NdrConformantVaryingArrayBufferSize [RPCRT4.@] - */ -void WINAPI NdrConformantVaryingArrayBufferSize( PMIDL_STUB_MESSAGE pStubMsg, - unsigned char* pMemory, PFORMAT_STRING pFormat ) -{ - FIXME( "stub\n" ); -} - - -/*********************************************************************** - * NdrConformantVaryingArrayMemorySize [RPCRT4.@] - */ -unsigned long WINAPI NdrConformantVaryingArrayMemorySize( PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat ) -{ - FIXME( "stub\n" ); - return 0; -} - - -/*********************************************************************** - * NdrComplexArrayMarshall [RPCRT4.@] - */ -unsigned char * WINAPI NdrComplexArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ - DWORD size = 0, count, def; - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - - def = *(const WORD*)&pFormat[2]; - pFormat += 4; - - pFormat = ComputeConformance(pStubMsg, pMemory, pFormat, def); - size = pStubMsg->MaxCount; - TRACE("conformance=%ld\n", size); - - if (*(const DWORD*)pFormat != 0xffffffff) - FIXME("compute variance\n"); - pFormat += 4; - - NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, size); - pStubMsg->Buffer += 4; - - for (count=0; count<size; count++) - pMemory = ComplexMarshall(pStubMsg, pMemory, pFormat, NULL); - - STD_OVERFLOW_CHECK(pStubMsg); - - return NULL; -} - -/*********************************************************************** - * NdrComplexArrayUnmarshall [RPCRT4.@] - */ -unsigned char * WINAPI NdrComplexArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char **ppMemory, - PFORMAT_STRING pFormat, - unsigned char fMustAlloc) -{ - DWORD size = 0, count, esize; - unsigned char *pMemory; - TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); - - pFormat += 4; - - pFormat = ReadConformance(pStubMsg, pFormat); - size = pStubMsg->MaxCount; - TRACE("conformance=%ld\n", size); - - pFormat += 4; - - esize = ComplexStructSize(pStubMsg, pFormat); - - if (fMustAlloc || !*ppMemory) - *ppMemory = NdrAllocate(pStubMsg, size*esize); - - pMemory = *ppMemory; - for (count=0; count<size; count++) - pMemory = ComplexUnmarshall(pStubMsg, pMemory, pFormat, NULL, fMustAlloc); - - return NULL; -} - -/*********************************************************************** - * NdrComplexArrayBufferSize [RPCRT4.@] - */ -void WINAPI NdrComplexArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ - DWORD size = 0, count, def; - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - - def = *(const WORD*)&pFormat[2]; - pFormat += 4; - - pFormat = ComputeConformance(pStubMsg, pMemory, pFormat, def); - size = pStubMsg->MaxCount; - TRACE("conformance=%ld\n", size); - - if (*(const DWORD*)pFormat != 0xffffffff) - FIXME("compute variance\n"); - pFormat += 4; - - for (count=0; count<size; count++) - pMemory = ComplexBufferSize(pStubMsg, pMemory, pFormat, NULL); -} - -/*********************************************************************** - * NdrComplexArrayMemorySize [RPCRT4.@] - */ -unsigned long WINAPI NdrComplexArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat) -{ - DWORD size = 0; - FIXME("(%p,%p): stub\n", pStubMsg, pFormat); - - pFormat += 4; - - pFormat = ReadConformance(pStubMsg, pFormat); - size = pStubMsg->MaxCount; - TRACE("conformance=%ld\n", size); - - pFormat += 4; - - return 0; -} - -/*********************************************************************** - * NdrComplexArrayFree [RPCRT4.@] - */ -void WINAPI NdrComplexArrayFree(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ - DWORD size = 0, count, def; - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - - def = *(const WORD*)&pFormat[2]; - pFormat += 4; - - pFormat = ComputeConformance(pStubMsg, pMemory, pFormat, def); - size = pStubMsg->MaxCount; - TRACE("conformance=%ld\n", size); - - if (*(const DWORD*)pFormat != 0xffffffff) - FIXME("compute variance\n"); - pFormat += 4; - - for (count=0; count<size; count++) - pMemory = ComplexFree(pStubMsg, pMemory, pFormat, NULL); -} - -unsigned long UserMarshalFlags(PMIDL_STUB_MESSAGE pStubMsg) -{ - return MAKELONG(pStubMsg->dwDestContext, - pStubMsg->RpcMsg->DataRepresentation); -} - -/*********************************************************************** - * NdrUserMarshalMarshall [RPCRT4.@] - */ -unsigned char * WINAPI NdrUserMarshalMarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ -/* unsigned flags = pFormat[1]; */ - unsigned index = *(const WORD*)&pFormat[2]; - unsigned long uflag = UserMarshalFlags(pStubMsg); - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - TRACE("index=%d\n", index); - - pStubMsg->Buffer = - pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnMarshall( - &uflag, pStubMsg->Buffer, pMemory); - - STD_OVERFLOW_CHECK(pStubMsg); - - return NULL; -} - -/*********************************************************************** - * NdrUserMarshalUnmarshall [RPCRT4.@] - */ -unsigned char * WINAPI NdrUserMarshalUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char **ppMemory, - PFORMAT_STRING pFormat, - unsigned char fMustAlloc) -{ -/* unsigned flags = pFormat[1];*/ - unsigned index = *(const WORD*)&pFormat[2]; - DWORD memsize = *(const WORD*)&pFormat[4]; - unsigned long uflag = UserMarshalFlags(pStubMsg); - TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); - TRACE("index=%d\n", index); - - if (fMustAlloc || !*ppMemory) - *ppMemory = NdrAllocate(pStubMsg, memsize); - - pStubMsg->Buffer = - pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnUnmarshall( - &uflag, pStubMsg->Buffer, *ppMemory); - - return NULL; -} - -/*********************************************************************** - * NdrUserMarshalBufferSize [RPCRT4.@] - */ -void WINAPI NdrUserMarshalBufferSize(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ -/* unsigned flags = pFormat[1];*/ - unsigned index = *(const WORD*)&pFormat[2]; - DWORD bufsize = *(const WORD*)&pFormat[6]; - unsigned long uflag = UserMarshalFlags(pStubMsg); - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - TRACE("index=%d\n", index); - - if (bufsize) { - TRACE("size=%ld\n", bufsize); - pStubMsg->BufferLength += bufsize; - return; - } - - pStubMsg->BufferLength = - pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnBufferSize( - &uflag, pStubMsg->BufferLength, pMemory); -} - -/*********************************************************************** - * NdrUserMarshalMemorySize [RPCRT4.@] - */ -unsigned long WINAPI NdrUserMarshalMemorySize(PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat) -{ - unsigned index = *(const WORD*)&pFormat[2]; -/* DWORD memsize = *(const WORD*)&pFormat[4]; */ - FIXME("(%p,%p): stub\n", pStubMsg, pFormat); - TRACE("index=%d\n", index); - - return 0; -} - -/*********************************************************************** - * NdrUserMarshalFree [RPCRT4.@] - */ -void WINAPI NdrUserMarshalFree(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ -/* unsigned flags = pFormat[1]; */ - unsigned index = *(const WORD*)&pFormat[2]; - unsigned long uflag = UserMarshalFlags(pStubMsg); - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - TRACE("index=%d\n", index); - - pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnFree( - &uflag, pMemory); -} - -/*********************************************************************** - * NdrClearOutParameters [RPCRT4.@] - */ -void WINAPI NdrClearOutParameters(PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat, - void *ArgAddr) -{ - FIXME("(%p,%p,%p): stub\n", pStubMsg, pFormat, ArgAddr); -} - -/*********************************************************************** - * NdrConvert [RPCRT4.@] - */ -void WINAPI NdrConvert( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) -{ - FIXME("(pStubMsg == ^%p, pFormat == ^%p): stub.\n", pStubMsg, pFormat); - /* FIXME: since this stub doesn't do any converting, the proper behavior - is to raise an exception */ -} - -/*********************************************************************** - * NdrConvert2 [RPCRT4.@] - */ -void WINAPI NdrConvert2( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, long NumberParams ) -{ - FIXME("(pStubMsg == ^%p, pFormat == ^%p, NumberParams == %ld): stub.\n", - pStubMsg, pFormat, NumberParams); - /* FIXME: since this stub doesn't do any converting, the proper behavior - is to raise an exception */ -} +/* + * NDR data marshalling + * + * Copyright 2002 Greg Turner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * TODO: + * - figure out whether we *really* got this right + * - check for errors and throw exceptions + */ + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" + +#include "ndr_misc.h" +#include "rpcndr.h" + +#include "wine/unicode.h" +#include "wine/rpcfc.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +#define BUFFER_PARANOIA 20 + +#if defined(__i386__) +# define LITTLE_ENDIAN_UINT32_WRITE(pchar, uint32) \ + (*((UINT32 *)(pchar)) = (uint32)) + +# define LITTLE_ENDIAN_UINT32_READ(pchar) \ + (*((UINT32 *)(pchar))) +#else + /* these would work for i386 too, but less efficient */ +# define LITTLE_ENDIAN_UINT32_WRITE(pchar, uint32) \ + (*(pchar) = LOBYTE(LOWORD(uint32)), \ + *((pchar)+1) = HIBYTE(LOWORD(uint32)), \ + *((pchar)+2) = LOBYTE(HIWORD(uint32)), \ + *((pchar)+3) = HIBYTE(HIWORD(uint32)), \ + (uint32)) /* allow as r-value */ + +# define LITTLE_ENDIAN_UINT32_READ(pchar) \ + (MAKELONG( \ + MAKEWORD(*(pchar), *((pchar)+1)), \ + MAKEWORD(*((pchar)+2), *((pchar)+3)))) +#endif + +#define BIG_ENDIAN_UINT32_WRITE(pchar, uint32) \ + (*((pchar)+3) = LOBYTE(LOWORD(uint32)), \ + *((pchar)+2) = HIBYTE(LOWORD(uint32)), \ + *((pchar)+1) = LOBYTE(HIWORD(uint32)), \ + *(pchar) = HIBYTE(HIWORD(uint32)), \ + (uint32)) /* allow as r-value */ + +#define BIG_ENDIAN_UINT32_READ(pchar) \ + (MAKELONG( \ + MAKEWORD(*((pchar)+3), *((pchar)+2)), \ + MAKEWORD(*((pchar)+1), *(pchar)))) + +#ifdef NDR_LOCAL_IS_BIG_ENDIAN +# define NDR_LOCAL_UINT32_WRITE(pchar, uint32) \ + BIG_ENDIAN_UINT32_WRITE(pchar, uint32) +# define NDR_LOCAL_UINT32_READ(pchar) \ + BIG_ENDIAN_UINT32_READ(pchar) +#else +# define NDR_LOCAL_UINT32_WRITE(pchar, uint32) \ + LITTLE_ENDIAN_UINT32_WRITE(pchar, uint32) +# define NDR_LOCAL_UINT32_READ(pchar) \ + LITTLE_ENDIAN_UINT32_READ(pchar) +#endif + +/* _Align must be the desired alignment minus 1, + * e.g. ALIGN_LENGTH(len, 3) to align on a dword boundary. */ +#define ALIGNED_LENGTH(_Len, _Align) (((_Len)+(_Align))&~(_Align)) +#define ALIGNED_POINTER(_Ptr, _Align) ((LPVOID)ALIGNED_LENGTH((ULONG_PTR)(_Ptr), _Align)) +#define ALIGN_LENGTH(_Len, _Align) _Len = ALIGNED_LENGTH(_Len, _Align) +#define ALIGN_POINTER(_Ptr, _Align) _Ptr = ALIGNED_POINTER(_Ptr, _Align) + +#define STD_OVERFLOW_CHECK(_Msg) do { \ + TRACE("buffer=%d/%ld\n", _Msg->Buffer - _Msg->BufferStart, _Msg->BufferLength); \ + if (_Msg->Buffer > _Msg->BufferEnd) ERR("buffer overflow %d bytes\n", _Msg->Buffer - _Msg->BufferEnd); \ + } while (0) + +#define NDR_TABLE_SIZE 128 +#define NDR_TABLE_MASK 127 + +NDR_MARSHALL NdrMarshaller[NDR_TABLE_SIZE] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x10 */ + 0, + /* 0x11 */ + NdrPointerMarshall, NdrPointerMarshall, + NdrPointerMarshall, NdrPointerMarshall, + /* 0x15 */ + NdrSimpleStructMarshall, NdrSimpleStructMarshall, + 0, 0, 0, + NdrComplexStructMarshall, + /* 0x1b */ + NdrConformantArrayMarshall, 0, 0, 0, 0, 0, + NdrComplexArrayMarshall, + /* 0x22 */ + NdrConformantStringMarshall, 0, 0, + NdrConformantStringMarshall, 0, 0, 0, 0, + /* 0x2a */ + 0, 0, 0, 0, 0, + /* 0x2f */ + NdrInterfacePointerMarshall, + /* 0xb0 */ + 0, 0, 0, 0, + NdrUserMarshalMarshall +}; +NDR_UNMARSHALL NdrUnmarshaller[NDR_TABLE_SIZE] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x10 */ + 0, + /* 0x11 */ + NdrPointerUnmarshall, NdrPointerUnmarshall, + NdrPointerUnmarshall, NdrPointerUnmarshall, + /* 0x15 */ + NdrSimpleStructUnmarshall, NdrSimpleStructUnmarshall, + 0, 0, 0, + NdrComplexStructUnmarshall, + /* 0x1b */ + NdrConformantArrayUnmarshall, 0, 0, 0, 0, 0, + NdrComplexArrayUnmarshall, + /* 0x22 */ + NdrConformantStringUnmarshall, 0, 0, + NdrConformantStringUnmarshall, 0, 0, 0, 0, + /* 0x2a */ + 0, 0, 0, 0, 0, + /* 0x2f */ + NdrInterfacePointerUnmarshall, + /* 0xb0 */ + 0, 0, 0, 0, + NdrUserMarshalUnmarshall +}; +NDR_BUFFERSIZE NdrBufferSizer[NDR_TABLE_SIZE] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x10 */ + 0, + /* 0x11 */ + NdrPointerBufferSize, NdrPointerBufferSize, + NdrPointerBufferSize, NdrPointerBufferSize, + /* 0x15 */ + NdrSimpleStructBufferSize, NdrSimpleStructBufferSize, + 0, 0, 0, + NdrComplexStructBufferSize, + /* 0x1b */ + NdrConformantArrayBufferSize, 0, 0, 0, 0, 0, + NdrComplexArrayBufferSize, + /* 0x22 */ + NdrConformantStringBufferSize, 0, 0, + NdrConformantStringBufferSize, 0, 0, 0, 0, + /* 0x2a */ + 0, 0, 0, 0, 0, + /* 0x2f */ + NdrInterfacePointerBufferSize, + /* 0xb0 */ + 0, 0, 0, 0, + NdrUserMarshalBufferSize +}; +NDR_MEMORYSIZE NdrMemorySizer[NDR_TABLE_SIZE] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x10 */ + 0, + /* 0x11 */ + NdrPointerMemorySize, NdrPointerMemorySize, + NdrPointerMemorySize, NdrPointerMemorySize, + /* 0x15 */ + NdrSimpleStructMemorySize, NdrSimpleStructMemorySize, + 0, 0, 0, + NdrComplexStructMemorySize, + /* 0x1b */ + NdrConformantArrayMemorySize, 0, 0, 0, 0, 0, + NdrComplexArrayMemorySize, + /* 0x22 */ + NdrConformantStringMemorySize, 0, 0, + NdrConformantStringMemorySize, 0, 0, 0, 0, + /* 0x2a */ + 0, 0, 0, 0, 0, + /* 0x2f */ + NdrInterfacePointerMemorySize, + /* 0xb0 */ + 0, 0, 0, 0, + NdrUserMarshalMemorySize +}; +NDR_FREE NdrFreer[NDR_TABLE_SIZE] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x10 */ + 0, + /* 0x11 */ + NdrPointerFree, NdrPointerFree, + NdrPointerFree, NdrPointerFree, + /* 0x15 */ + NdrSimpleStructFree, NdrSimpleStructFree, + 0, 0, 0, + NdrComplexStructFree, + /* 0x1b */ + NdrConformantArrayFree, 0, 0, 0, 0, 0, + NdrComplexArrayFree, + /* 0x22 */ + 0, 0, 0, 0, 0, 0, 0, 0, + /* 0x2a */ + 0, 0, 0, 0, 0, + /* 0x2f */ + NdrInterfacePointerFree, + /* 0xb0 */ + 0, 0, 0, 0, + NdrUserMarshalFree +}; + +void * WINAPI NdrAllocate(MIDL_STUB_MESSAGE *pStubMsg, size_t len) +{ + /* hmm, this is probably supposed to do more? */ + return pStubMsg->pfnAllocate(len); +} + +static void WINAPI NdrFree(MIDL_STUB_MESSAGE *pStubMsg, unsigned char *Pointer) +{ + pStubMsg->pfnFree(Pointer); +} + +PFORMAT_STRING ReadConformance(MIDL_STUB_MESSAGE *pStubMsg, PFORMAT_STRING pFormat) +{ + pStubMsg->MaxCount = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); + pStubMsg->Buffer += 4; + TRACE("unmarshalled conformance is %ld\n", pStubMsg->MaxCount); + return pFormat+4; +} + +PFORMAT_STRING ComputeConformance(MIDL_STUB_MESSAGE *pStubMsg, unsigned char *pMemory, + PFORMAT_STRING pFormat, ULONG_PTR def) +{ + BYTE dtype = pFormat[0] & 0xf; + DWORD ofs = (DWORD)pFormat[2] | ((DWORD)pFormat[3] << 8); + LPVOID ptr = NULL; + DWORD data = 0; + + if (pFormat[0] == 0xff) { + /* null descriptor */ + pStubMsg->MaxCount = def; + goto finish_conf; + } + + switch (pFormat[0] & 0xf0) { + case RPC_FC_NORMAL_CONFORMANCE: + TRACE("normal conformance, ofs=%ld\n", ofs); + ptr = pMemory + ofs; + break; + case RPC_FC_POINTER_CONFORMANCE: + TRACE("pointer conformance, ofs=%ld\n", ofs); + ptr = pStubMsg->Memory + ofs; + break; + case RPC_FC_TOP_LEVEL_CONFORMANCE: + TRACE("toplevel conformance, ofs=%ld\n", ofs); + if (pStubMsg->StackTop) { + ptr = pStubMsg->StackTop + ofs; + } + else { + /* -Os mode, MaxCount is already set */ + goto finish_conf; + } + break; + case RPC_FC_CONSTANT_CONFORMANCE: + data = ofs | ((DWORD)pFormat[1] << 16); + TRACE("constant conformance, val=%ld\n", data); + pStubMsg->MaxCount = data; + goto finish_conf; + case RPC_FC_TOP_LEVEL_MULTID_CONFORMANCE: + FIXME("toplevel multidimensional conformance, ofs=%ld\n", ofs); + if (pStubMsg->StackTop) { + ptr = pStubMsg->StackTop + ofs; + } + else { + /* ? */ + goto done_conf_grab; + } + break; + default: + FIXME("unknown conformance type %x\n", pFormat[0] & 0xf0); + } + + switch (pFormat[1]) { + case RPC_FC_DEREFERENCE: + ptr = *(LPVOID*)ptr; + break; + case RPC_FC_CALLBACK: + /* ofs is index into StubDesc->apfnExprEval */ + FIXME("handle callback\n"); + goto finish_conf; + default: + break; + } + + switch (dtype) { + case RPC_FC_LONG: + case RPC_FC_ULONG: + data = *(DWORD*)ptr; + break; + case RPC_FC_SHORT: + data = *(SHORT*)ptr; + break; + case RPC_FC_USHORT: + data = *(USHORT*)ptr; + break; + case RPC_FC_SMALL: + data = *(CHAR*)ptr; + break; + case RPC_FC_USMALL: + data = *(UCHAR*)ptr; + break; + default: + FIXME("unknown conformance data type %x\n", dtype); + goto done_conf_grab; + } + TRACE("dereferenced data type %x at %p, got %ld\n", dtype, ptr, data); + +done_conf_grab: + switch (pFormat[1]) { + case 0: /* no op */ + pStubMsg->MaxCount = data; + break; + case RPC_FC_DEREFERENCE: + /* already handled */ + break; + default: + FIXME("unknown conformance op %d\n", pFormat[1]); + goto finish_conf; + } + +finish_conf: + TRACE("resulting conformance is %ld\n", pStubMsg->MaxCount); + return pFormat+4; +} + + +/* + * NdrConformantString: + * + * What MS calls a ConformantString is, in DCE terminology, + * a Varying-Conformant String. + * [ + * maxlen: DWORD (max # of CHARTYPE characters, inclusive of '\0') + * offset: DWORD (actual string data begins at (offset) CHARTYPE's + * into unmarshalled string) + * length: DWORD (# of CHARTYPE characters, inclusive of '\0') + * [ + * data: CHARTYPE[maxlen] + * ] + * ], where CHARTYPE is the appropriate character type (specified externally) + * + */ + +/*********************************************************************** + * NdrConformantStringMarshall [RPCRT4.@] + */ +unsigned char *WINAPI NdrConformantStringMarshall(MIDL_STUB_MESSAGE *pStubMsg, + unsigned char *pszMessage, PFORMAT_STRING pFormat) +{ + unsigned long len, esize; + unsigned char *c; + + TRACE("(pStubMsg == ^%p, pszMessage == ^%p, pFormat == ^%p)\n", pStubMsg, pszMessage, pFormat); + + assert(pFormat); + if (pszMessage == NULL) { + TRACE("string=%s\n", debugstr_a(pszMessage)); + len = 0; + esize = 0; + } + else if (*pFormat == RPC_FC_C_CSTRING) { + TRACE("string=%s\n", debugstr_a(pszMessage)); + len = strlen(pszMessage)+1; + esize = 1; + } + else if (*pFormat == RPC_FC_C_WSTRING) { + TRACE("string=%s\n", debugstr_w((LPWSTR)pszMessage)); + len = strlenW((LPWSTR)pszMessage)+1; + esize = 2; + } + else { + ERR("Unhandled string type: %#x\n", *pFormat); + /* FIXME: raise an exception. */ + return NULL; + } + + if (pFormat[1] != RPC_FC_PAD) { + FIXME("sized string format=%d\n", pFormat[1]); + } + + assert( (pStubMsg->BufferLength >= (len*esize + 13)) && (pStubMsg->Buffer != NULL) ); + + c = pStubMsg->Buffer; + memset(c, 0, 12); + NDR_LOCAL_UINT32_WRITE(c, len); /* max length: strlen + 1 (for '\0') */ + c += 8; /* offset: 0 */ + NDR_LOCAL_UINT32_WRITE(c, len); /* actual length: (same) */ + c += 4; + if (len != 0) { + memcpy(c, pszMessage, len*esize); /* the string itself */ + c += len*esize; + } + pStubMsg->Buffer = c; + + STD_OVERFLOW_CHECK(pStubMsg); + + /* success */ + return NULL; /* is this always right? */ +} + +/*********************************************************************** + * NdrConformantStringBufferSize [RPCRT4.@] + */ +void WINAPI NdrConformantStringBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char* pMemory, PFORMAT_STRING pFormat) +{ + TRACE("(pStubMsg == ^%p, pMemory == ^%p, pFormat == ^%p)\n", pStubMsg, pMemory, pFormat); + + assert(pFormat); + if (pMemory == NULL) { + /* we need 12 octets for the [maxlen, offset, len] DWORDS */ + TRACE("string=NULL\n"); + pStubMsg->BufferLength += 12 + BUFFER_PARANOIA; + } + else if (*pFormat == RPC_FC_C_CSTRING) { + /* we need 12 octets for the [maxlen, offset, len] DWORDS, + 1 octet for '\0' */ + TRACE("string=%s\n", debugstr_a(pMemory)); + pStubMsg->BufferLength += strlen(pMemory) + 13 + BUFFER_PARANOIA; + } + else if (*pFormat == RPC_FC_C_WSTRING) { + /* we need 12 octets for the [maxlen, offset, len] DWORDS, + 2 octets for L'\0' */ + TRACE("string=%s\n", debugstr_w((LPWSTR)pMemory)); + pStubMsg->BufferLength += strlenW((LPWSTR)pMemory)*2 + 14 + BUFFER_PARANOIA; + } + else { + ERR("Unhandled string type: %#x\n", *pFormat); + /* FIXME: raise an exception */ + } + + if (pFormat[1] != RPC_FC_PAD) { + FIXME("sized string format=%d\n", pFormat[1]); + } +} + +/************************************************************************ + * NdrConformantStringMemorySize [RPCRT4.@] + */ +unsigned long WINAPI NdrConformantStringMemorySize( PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat ) +{ + unsigned long rslt = 0; + + TRACE("(pStubMsg == ^%p, pFormat == ^%p)\n", pStubMsg, pFormat); + + assert(pStubMsg && pFormat); + + if (*pFormat == RPC_FC_C_CSTRING) { + rslt = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); /* maxlen */ + } + else if (*pFormat == RPC_FC_C_WSTRING) { + rslt = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer)*2; /* maxlen */ + } + else { + ERR("Unhandled string type: %#x\n", *pFormat); + /* FIXME: raise an exception */ + } + + if (pFormat[1] != RPC_FC_PAD) { + FIXME("sized string format=%d\n", pFormat[1]); + } + + TRACE(" --> %lu\n", rslt); + return rslt; +} + +/************************************************************************ + * NdrConformantStringUnmarshall [RPCRT4.@] + */ +unsigned char *WINAPI NdrConformantStringUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, + unsigned char** ppMemory, PFORMAT_STRING pFormat, unsigned char fMustAlloc ) +{ + unsigned long len, esize, ofs; + unsigned char *pMem; + + TRACE("(pStubMsg == ^%p, *pMemory == ^%p, pFormat == ^%p, fMustAlloc == %u)\n", + pStubMsg, *ppMemory, pFormat, fMustAlloc); + + assert(pFormat && ppMemory && pStubMsg); + + pStubMsg->Buffer += 4; + ofs = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); + pStubMsg->Buffer += 4; + len = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); + pStubMsg->Buffer += 4; + + if (*pFormat == RPC_FC_C_CSTRING) esize = 1; + else if (*pFormat == RPC_FC_C_WSTRING) esize = 2; + else { + ERR("Unhandled string type: %#x\n", *pFormat); + /* FIXME: raise an exception */ + esize = 0; + } + + if (pFormat[1] != RPC_FC_PAD) { + FIXME("sized string format=%d\n", pFormat[1]); + } + + if (fMustAlloc) { + *ppMemory = NdrAllocate(pStubMsg, len*esize + BUFFER_PARANOIA); + } else { + if (pStubMsg->ReuseBuffer && !*ppMemory) + /* for servers, we may just point straight into the RPC buffer, I think + * (I guess that's what MS does since MIDL code doesn't try to free) */ + *ppMemory = pStubMsg->Buffer - ofs*esize; + /* for clients, memory should be provided by caller */ + } + + if (len == 0) { + *ppMemory = NULL; + return NULL; + } + + pMem = *ppMemory + ofs*esize; + + if (pMem != pStubMsg->Buffer) + memcpy(pMem, pStubMsg->Buffer, len*esize); + + pStubMsg->Buffer += len*esize; + + if (*pFormat == RPC_FC_C_CSTRING) { + TRACE("string=%s\n", debugstr_a(pMem)); + } + else if (*pFormat == RPC_FC_C_WSTRING) { + TRACE("string=%s\n", debugstr_w((LPWSTR)pMem)); + } + + return NULL; /* FIXME: is this always right? */ +} + +/*********************************************************************** + * PointerMarshall + */ +void WINAPI PointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *Buffer, + unsigned char *Pointer, + PFORMAT_STRING pFormat) +{ + unsigned type = pFormat[0], attr = pFormat[1]; + PFORMAT_STRING desc; + NDR_MARSHALL m; + + TRACE("(%p,%p,%p,%p)\n", pStubMsg, Buffer, Pointer, pFormat); + TRACE("type=%d, attr=%d\n", type, attr); + pFormat += 2; + if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; + else desc = pFormat + *(const SHORT*)pFormat; + if (attr & RPC_FC_P_DEREF) { + Pointer = *(unsigned char**)Pointer; + TRACE("deref => %p\n", Pointer); + } + + *(LPVOID*)Buffer = 0; + + switch (type) { + case RPC_FC_RP: /* ref pointer (always non-null) */ + break; + case RPC_FC_UP: /* unique pointer */ + break; + default: + FIXME("unhandled ptr type=%02x\n", type); + } + + m = NdrMarshaller[*desc & NDR_TABLE_MASK]; + if (m) m(pStubMsg, Pointer, desc); + else FIXME("no marshaller for data type=%02x\n", *desc); + + STD_OVERFLOW_CHECK(pStubMsg); +} + +/*********************************************************************** + * PointerUnmarshall + */ +void WINAPI PointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *Buffer, + unsigned char **pPointer, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + unsigned type = pFormat[0], attr = pFormat[1]; + PFORMAT_STRING desc; + NDR_UNMARSHALL m; + + TRACE("(%p,%p,%p,%p,%d)\n", pStubMsg, Buffer, pPointer, pFormat, fMustAlloc); + TRACE("type=%d, attr=%d\n", type, attr); + pFormat += 2; + if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; + else desc = pFormat + *(const SHORT*)pFormat; + if (attr & RPC_FC_P_DEREF) { + pPointer = *(unsigned char***)pPointer; + TRACE("deref => %p\n", pPointer); + } + + switch (type) { + case RPC_FC_RP: /* ref pointer (always non-null) */ + break; + case RPC_FC_UP: /* unique pointer */ + break; + default: + FIXME("unhandled ptr type=%02x\n", type); + } + + *pPointer = NULL; + + m = NdrUnmarshaller[*desc & NDR_TABLE_MASK]; + if (m) m(pStubMsg, pPointer, desc, fMustAlloc); + else FIXME("no unmarshaller for data type=%02x\n", *desc); + TRACE("pointer=%p\n", *pPointer); +} + +/*********************************************************************** + * PointerBufferSize + */ +void WINAPI PointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *Pointer, + PFORMAT_STRING pFormat) +{ + unsigned type = pFormat[0], attr = pFormat[1]; + PFORMAT_STRING desc; + NDR_BUFFERSIZE m; + + TRACE("(%p,%p,%p)\n", pStubMsg, Pointer, pFormat); + TRACE("type=%d, attr=%d\n", type, attr); + pFormat += 2; + if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; + else desc = pFormat + *(const SHORT*)pFormat; + if (attr & RPC_FC_P_DEREF) { + Pointer = *(unsigned char**)Pointer; + TRACE("deref => %p\n", Pointer); + } + + switch (type) { + case RPC_FC_RP: /* ref pointer (always non-null) */ + break; + case RPC_FC_UP: /* unique pointer */ + break; + default: + FIXME("unhandled ptr type=%02x\n", type); + } + + m = NdrBufferSizer[*desc & NDR_TABLE_MASK]; + if (m) m(pStubMsg, Pointer, desc); + else FIXME("no buffersizer for data type=%02x\n", *desc); +} + +/*********************************************************************** + * PointerMemorySize [RPCRT4.@] + */ +unsigned long WINAPI PointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *Buffer, + PFORMAT_STRING pFormat) +{ + unsigned type = pFormat[0], attr = pFormat[1]; + PFORMAT_STRING desc; + NDR_MEMORYSIZE m; + + FIXME("(%p,%p,%p): stub\n", pStubMsg, Buffer, pFormat); + TRACE("type=%d, attr=%d\n", type, attr); + pFormat += 2; + if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; + else desc = pFormat + *(const SHORT*)pFormat; + if (attr & RPC_FC_P_DEREF) { + TRACE("deref\n"); + } + + switch (type) { + case RPC_FC_RP: /* ref pointer (always non-null) */ + break; + default: + FIXME("unhandled ptr type=%02x\n", type); + } + + m = NdrMemorySizer[*desc & NDR_TABLE_MASK]; + if (m) m(pStubMsg, desc); + else FIXME("no memorysizer for data type=%02x\n", *desc); + + return 0; +} + +/*********************************************************************** + * PointerFree [RPCRT4.@] + */ +void WINAPI PointerFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *Pointer, + PFORMAT_STRING pFormat) +{ + unsigned type = pFormat[0], attr = pFormat[1]; + PFORMAT_STRING desc; + NDR_FREE m; + + TRACE("(%p,%p,%p)\n", pStubMsg, Pointer, pFormat); + TRACE("type=%d, attr=%d\n", type, attr); + if (attr & RPC_FC_P_DONTFREE) return; + pFormat += 2; + if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; + else desc = pFormat + *(const SHORT*)pFormat; + if (attr & RPC_FC_P_DEREF) { + Pointer = *(unsigned char**)Pointer; + TRACE("deref => %p\n", Pointer); + } + + if (!Pointer) return; + + m = NdrFreer[*desc & NDR_TABLE_MASK]; + if (m) m(pStubMsg, Pointer, desc); + + /* hmm... is this sensible? + * perhaps we should check if the memory comes from NdrAllocate, + * and deallocate only if so - checking if the pointer is between + * BufferStart and BufferEnd is probably no good since the buffer + * may be reallocated when the server wants to marshal the reply */ + switch (*desc) { + case RPC_FC_BOGUS_STRUCT: + case RPC_FC_BOGUS_ARRAY: + case RPC_FC_USER_MARSHAL: + break; + default: + FIXME("unhandled data type=%02x\n", *desc); + case RPC_FC_CARRAY: + case RPC_FC_C_CSTRING: + case RPC_FC_C_WSTRING: + if (pStubMsg->ReuseBuffer) goto notfree; + break; + case RPC_FC_IP: + goto notfree; + } + + if (attr & RPC_FC_P_ONSTACK) { + TRACE("not freeing stack ptr %p\n", Pointer); + return; + } + TRACE("freeing %p\n", Pointer); + NdrFree(pStubMsg, Pointer); + return; +notfree: + TRACE("not freeing %p\n", Pointer); +} + +/*********************************************************************** + * EmbeddedPointerMarshall + */ +unsigned char * WINAPI EmbeddedPointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned char *Mark = pStubMsg->BufferMark; + unsigned long Offset = pStubMsg->Offset; + unsigned ofs, rep, count, stride, xofs; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + if (*pFormat != RPC_FC_PP) return NULL; + pFormat += 2; + + while (pFormat[0] != RPC_FC_END) { + switch (pFormat[0]) { + default: + FIXME("unknown repeat type %d\n", pFormat[0]); + case RPC_FC_NO_REPEAT: + rep = 1; + stride = 0; + ofs = 0; + count = 1; + xofs = 0; + pFormat += 2; + break; + case RPC_FC_FIXED_REPEAT: + rep = *(const WORD*)&pFormat[2]; + stride = *(const WORD*)&pFormat[4]; + ofs = *(const WORD*)&pFormat[6]; + count = *(const WORD*)&pFormat[8]; + xofs = 0; + pFormat += 10; + break; + case RPC_FC_VARIABLE_REPEAT: + rep = pStubMsg->MaxCount; + stride = *(const WORD*)&pFormat[2]; + ofs = *(const WORD*)&pFormat[4]; + count = *(const WORD*)&pFormat[6]; + xofs = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? Offset * stride : 0; + pFormat += 8; + break; + } + /* ofs doesn't seem to matter in this context */ + while (rep) { + PFORMAT_STRING info = pFormat; + unsigned char *membase = pMemory + xofs; + unsigned u; + for (u=0; u<count; u++,info+=8) { + unsigned char *memptr = membase + *(const SHORT*)&info[0]; + unsigned char *bufptr = Mark + *(const SHORT*)&info[2]; + PointerMarshall(pStubMsg, bufptr, *(unsigned char**)memptr, info+4); + } + rep--; + } + pFormat += 8 * count; + } + + STD_OVERFLOW_CHECK(pStubMsg); + + return NULL; +} + +/*********************************************************************** + * EmbeddedPointerUnmarshall + */ +unsigned char * WINAPI EmbeddedPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + unsigned char *Mark = pStubMsg->BufferMark; + unsigned long Offset = pStubMsg->Offset; + unsigned ofs, rep, count, stride, xofs; + + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + if (*pFormat != RPC_FC_PP) return NULL; + pFormat += 2; + + while (pFormat[0] != RPC_FC_END) { + switch (pFormat[0]) { + default: + FIXME("unknown repeat type %d\n", pFormat[0]); + case RPC_FC_NO_REPEAT: + rep = 1; + stride = 0; + ofs = 0; + count = 1; + xofs = 0; + pFormat += 2; + break; + case RPC_FC_FIXED_REPEAT: + rep = *(const WORD*)&pFormat[2]; + stride = *(const WORD*)&pFormat[4]; + ofs = *(const WORD*)&pFormat[6]; + count = *(const WORD*)&pFormat[8]; + xofs = 0; + pFormat += 10; + break; + case RPC_FC_VARIABLE_REPEAT: + rep = pStubMsg->MaxCount; + stride = *(const WORD*)&pFormat[2]; + ofs = *(const WORD*)&pFormat[4]; + count = *(const WORD*)&pFormat[6]; + xofs = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? Offset * stride : 0; + pFormat += 8; + break; + } + /* ofs doesn't seem to matter in this context */ + while (rep) { + PFORMAT_STRING info = pFormat; + unsigned char *membase = *ppMemory + xofs; + unsigned u; + for (u=0; u<count; u++,info+=8) { + unsigned char *memptr = membase + *(const SHORT*)&info[0]; + unsigned char *bufptr = Mark + *(const SHORT*)&info[2]; + PointerUnmarshall(pStubMsg, bufptr, (unsigned char**)memptr, info+4, fMustAlloc); + } + rep--; + } + pFormat += 8 * count; + } + + return NULL; +} + +/*********************************************************************** + * EmbeddedPointerBufferSize + */ +void WINAPI EmbeddedPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned long Offset = pStubMsg->Offset; + unsigned ofs, rep, count, stride, xofs; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (*pFormat != RPC_FC_PP) return; + pFormat += 2; + + while (pFormat[0] != RPC_FC_END) { + switch (pFormat[0]) { + default: + FIXME("unknown repeat type %d\n", pFormat[0]); + case RPC_FC_NO_REPEAT: + rep = 1; + stride = 0; + ofs = 0; + count = 1; + xofs = 0; + pFormat += 2; + break; + case RPC_FC_FIXED_REPEAT: + rep = *(const WORD*)&pFormat[2]; + stride = *(const WORD*)&pFormat[4]; + ofs = *(const WORD*)&pFormat[6]; + count = *(const WORD*)&pFormat[8]; + xofs = 0; + pFormat += 10; + break; + case RPC_FC_VARIABLE_REPEAT: + rep = pStubMsg->MaxCount; + stride = *(const WORD*)&pFormat[2]; + ofs = *(const WORD*)&pFormat[4]; + count = *(const WORD*)&pFormat[6]; + xofs = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? Offset * stride : 0; + pFormat += 8; + break; + } + /* ofs doesn't seem to matter in this context */ + while (rep) { + PFORMAT_STRING info = pFormat; + unsigned char *membase = pMemory + xofs; + unsigned u; + for (u=0; u<count; u++,info+=8) { + unsigned char *memptr = membase + *(const SHORT*)&info[0]; + PointerBufferSize(pStubMsg, *(unsigned char**)memptr, info+4); + } + rep--; + } + pFormat += 8 * count; + } +} + +/*********************************************************************** + * EmbeddedPointerMemorySize + */ +unsigned long WINAPI EmbeddedPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + unsigned long Offset = pStubMsg->Offset; + unsigned char *Mark = pStubMsg->BufferMark; + unsigned ofs, rep, count, stride, xofs; + + FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + if (*pFormat != RPC_FC_PP) return 0; + pFormat += 2; + + while (pFormat[0] != RPC_FC_END) { + switch (pFormat[0]) { + default: + FIXME("unknown repeat type %d\n", pFormat[0]); + case RPC_FC_NO_REPEAT: + rep = 1; + stride = 0; + ofs = 0; + count = 1; + xofs = 0; + pFormat += 2; + break; + case RPC_FC_FIXED_REPEAT: + rep = *(const WORD*)&pFormat[2]; + stride = *(const WORD*)&pFormat[4]; + ofs = *(const WORD*)&pFormat[6]; + count = *(const WORD*)&pFormat[8]; + xofs = 0; + pFormat += 10; + break; + case RPC_FC_VARIABLE_REPEAT: + rep = pStubMsg->MaxCount; + stride = *(const WORD*)&pFormat[2]; + ofs = *(const WORD*)&pFormat[4]; + count = *(const WORD*)&pFormat[6]; + xofs = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? Offset * stride : 0; + pFormat += 8; + break; + } + /* ofs doesn't seem to matter in this context */ + while (rep) { + PFORMAT_STRING info = pFormat; + unsigned u; + for (u=0; u<count; u++,info+=8) { + unsigned char *bufptr = Mark + *(const SHORT*)&info[2]; + PointerMemorySize(pStubMsg, bufptr, info+4); + } + rep--; + } + pFormat += 8 * count; + } + + return 0; +} + +/*********************************************************************** + * EmbeddedPointerFree + */ +void WINAPI EmbeddedPointerFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned long Offset = pStubMsg->Offset; + unsigned ofs, rep, count, stride, xofs; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (*pFormat != RPC_FC_PP) return; + pFormat += 2; + + while (pFormat[0] != RPC_FC_END) { + switch (pFormat[0]) { + default: + FIXME("unknown repeat type %d\n", pFormat[0]); + case RPC_FC_NO_REPEAT: + rep = 1; + stride = 0; + ofs = 0; + count = 1; + xofs = 0; + pFormat += 2; + break; + case RPC_FC_FIXED_REPEAT: + rep = *(const WORD*)&pFormat[2]; + stride = *(const WORD*)&pFormat[4]; + ofs = *(const WORD*)&pFormat[6]; + count = *(const WORD*)&pFormat[8]; + xofs = 0; + pFormat += 10; + break; + case RPC_FC_VARIABLE_REPEAT: + rep = pStubMsg->MaxCount; + stride = *(const WORD*)&pFormat[2]; + ofs = *(const WORD*)&pFormat[4]; + count = *(const WORD*)&pFormat[6]; + xofs = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? Offset * stride : 0; + pFormat += 8; + break; + } + /* ofs doesn't seem to matter in this context */ + while (rep) { + PFORMAT_STRING info = pFormat; + unsigned char *membase = pMemory + xofs; + unsigned u; + for (u=0; u<count; u++,info+=8) { + unsigned char *memptr = membase + *(const SHORT*)&info[0]; + PointerFree(pStubMsg, *(unsigned char**)memptr, info+4); + } + rep--; + } + pFormat += 8 * count; + } +} + +/*********************************************************************** + * NdrPointerMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrPointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + pStubMsg->BufferMark = pStubMsg->Buffer; + PointerMarshall(pStubMsg, pStubMsg->Buffer, pMemory, pFormat); + pStubMsg->Buffer += 4; + + STD_OVERFLOW_CHECK(pStubMsg); + + return NULL; +} + +/*********************************************************************** + * NdrPointerUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + pStubMsg->BufferMark = pStubMsg->Buffer; + PointerUnmarshall(pStubMsg, pStubMsg->Buffer, ppMemory, pFormat, fMustAlloc); + pStubMsg->Buffer += 4; + + return NULL; +} + +/*********************************************************************** + * NdrPointerBufferSize [RPCRT4.@] + */ +void WINAPI NdrPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + pStubMsg->BufferLength += 4; + PointerBufferSize(pStubMsg, pMemory, pFormat); +} + +/*********************************************************************** + * NdrPointerMemorySize [RPCRT4.@] + */ +unsigned long WINAPI NdrPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + /* unsigned size = *(LPWORD)(pFormat+2); */ + FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + PointerMemorySize(pStubMsg, pStubMsg->Buffer, pFormat); + return 0; +} + +/*********************************************************************** + * NdrPointerFree [RPCRT4.@] + */ +void WINAPI NdrPointerFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + PointerFree(pStubMsg, pMemory, pFormat); +} + +/*********************************************************************** + * NdrSimpleStructMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrSimpleStructMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned size = *(const WORD*)(pFormat+2); + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + memcpy(pStubMsg->Buffer, pMemory, size); + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += size; + + if (pFormat[0] != RPC_FC_STRUCT) + EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat+4); + + /* + * This test does not work when NdrSimpleStructMarshall is called + * by an rpc-server to marshall data to return to the client because + * BufferStart and BufferEnd are bogus. MIDL does not update them + * when a new buffer is allocated in order to return data to the caller. + */ +#if 0 + STD_OVERFLOW_CHECK(pStubMsg); +#endif + + return NULL; +} + +/*********************************************************************** + * NdrSimpleStructUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrSimpleStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + unsigned size = *(const WORD*)(pFormat+2); + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + if (fMustAlloc) { + *ppMemory = NdrAllocate(pStubMsg, size); + memcpy(*ppMemory, pStubMsg->Buffer, size); + } else { + if (pStubMsg->ReuseBuffer && !*ppMemory) + /* for servers, we may just point straight into the RPC buffer, I think + * (I guess that's what MS does since MIDL code doesn't try to free) */ + *ppMemory = pStubMsg->Buffer; + else + /* for clients, memory should be provided by caller */ + memcpy(*ppMemory, pStubMsg->Buffer, size); + } + + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += size; + + if (pFormat[0] != RPC_FC_STRUCT) + EmbeddedPointerUnmarshall(pStubMsg, ppMemory, pFormat+4, fMustAlloc); + + return NULL; +} + + +/*********************************************************************** + * NdrSimpleTypeUnmarshall [RPCRT4.@] + */ +void WINAPI NdrSimpleTypeMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + unsigned char FormatChar) +{ + FIXME("stub\n"); +} + + +/*********************************************************************** + * NdrSimpleTypeUnmarshall [RPCRT4.@] + */ +void WINAPI NdrSimpleTypeUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + unsigned char FormatChar) +{ + FIXME("stub\n"); +} + + +/*********************************************************************** + * NdrSimpleStructBufferSize [RPCRT4.@] + */ +void WINAPI NdrSimpleStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned size = *(const WORD*)(pFormat+2); + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + pStubMsg->BufferLength += size; + if (pFormat[0] != RPC_FC_STRUCT) + EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat+4); +} + +/*********************************************************************** + * NdrSimpleStructMemorySize [RPCRT4.@] + */ +unsigned long WINAPI NdrSimpleStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + /* unsigned size = *(LPWORD)(pFormat+2); */ + FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + if (pFormat[0] != RPC_FC_STRUCT) + EmbeddedPointerMemorySize(pStubMsg, pFormat+4); + return 0; +} + +/*********************************************************************** + * NdrSimpleStructFree [RPCRT4.@] + */ +void WINAPI NdrSimpleStructFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (pFormat[0] != RPC_FC_STRUCT) + EmbeddedPointerFree(pStubMsg, pMemory, pFormat+4); +} + + +unsigned long WINAPI EmbeddedComplexSize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + switch (*pFormat) { + case RPC_FC_STRUCT: + case RPC_FC_PSTRUCT: + case RPC_FC_CSTRUCT: + case RPC_FC_BOGUS_STRUCT: + return *(const WORD*)&pFormat[2]; + case RPC_FC_USER_MARSHAL: + return *(const WORD*)&pFormat[4]; + default: + FIXME("unhandled embedded type %02x\n", *pFormat); + } + return 0; +} + + +unsigned char * WINAPI ComplexMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat, + PFORMAT_STRING pPointer) +{ + PFORMAT_STRING desc; + NDR_MARSHALL m; + unsigned long size; + + while (*pFormat != RPC_FC_END) { + switch (*pFormat) { + case RPC_FC_SHORT: + case RPC_FC_USHORT: + TRACE("short=%d <= %p\n", *(WORD*)pMemory, pMemory); + memcpy(pStubMsg->Buffer, pMemory, 2); + pStubMsg->Buffer += 2; + pMemory += 2; + break; + case RPC_FC_LONG: + case RPC_FC_ULONG: + TRACE("long=%ld <= %p\n", *(DWORD*)pMemory, pMemory); + memcpy(pStubMsg->Buffer, pMemory, 4); + pStubMsg->Buffer += 4; + pMemory += 4; + break; + case RPC_FC_POINTER: + TRACE("pointer=%p <= %p\n", *(unsigned char**)pMemory, pMemory); + NdrPointerMarshall(pStubMsg, *(unsigned char**)pMemory, pPointer); + pPointer += 4; + pMemory += 4; + break; + case RPC_FC_ALIGNM4: + ALIGN_POINTER(pMemory, 3); + break; + case RPC_FC_ALIGNM8: + ALIGN_POINTER(pMemory, 7); + break; + case RPC_FC_EMBEDDED_COMPLEX: + pMemory += pFormat[1]; + pFormat += 2; + desc = pFormat + *(const SHORT*)pFormat; + size = EmbeddedComplexSize(pStubMsg, desc); + TRACE("embedded complex (size=%ld) <= %p\n", size, pMemory); + m = NdrMarshaller[*desc & NDR_TABLE_MASK]; + if (m) m(pStubMsg, pMemory, desc); + else FIXME("no marshaller for embedded type %02x\n", *desc); + pMemory += size; + pFormat += 2; + continue; + case RPC_FC_PAD: + break; + default: + FIXME("unhandled format %02x\n", *pFormat); + } + pFormat++; + } + + return pMemory; +} + +unsigned char * WINAPI ComplexUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat, + PFORMAT_STRING pPointer, + unsigned char fMustAlloc) +{ + PFORMAT_STRING desc; + NDR_UNMARSHALL m; + unsigned long size; + + while (*pFormat != RPC_FC_END) { + switch (*pFormat) { + case RPC_FC_SHORT: + case RPC_FC_USHORT: + memcpy(pMemory, pStubMsg->Buffer, 2); + TRACE("short=%d => %p\n", *(WORD*)pMemory, pMemory); + pStubMsg->Buffer += 2; + pMemory += 2; + break; + case RPC_FC_LONG: + case RPC_FC_ULONG: + memcpy(pMemory, pStubMsg->Buffer, 4); + TRACE("long=%ld => %p\n", *(DWORD*)pMemory, pMemory); + pStubMsg->Buffer += 4; + pMemory += 4; + break; + case RPC_FC_POINTER: + *(unsigned char**)pMemory = NULL; + TRACE("pointer => %p\n", pMemory); + NdrPointerUnmarshall(pStubMsg, (unsigned char**)pMemory, pPointer, fMustAlloc); + pPointer += 4; + pMemory += 4; + break; + case RPC_FC_ALIGNM4: + ALIGN_POINTER(pMemory, 3); + break; + case RPC_FC_ALIGNM8: + ALIGN_POINTER(pMemory, 7); + break; + case RPC_FC_EMBEDDED_COMPLEX: + pMemory += pFormat[1]; + pFormat += 2; + desc = pFormat + *(const SHORT*)pFormat; + size = EmbeddedComplexSize(pStubMsg, desc); + TRACE("embedded complex (size=%ld) => %p\n", size, pMemory); + m = NdrUnmarshaller[*desc & NDR_TABLE_MASK]; + memset(pMemory, 0, size); /* just in case */ + if (m) m(pStubMsg, &pMemory, desc, fMustAlloc); + else FIXME("no unmarshaller for embedded type %02x\n", *desc); + pMemory += size; + pFormat += 2; + continue; + case RPC_FC_PAD: + break; + default: + FIXME("unhandled format %d\n", *pFormat); + } + pFormat++; + } + + return pMemory; +} + +unsigned char * WINAPI ComplexBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat, + PFORMAT_STRING pPointer) +{ + PFORMAT_STRING desc; + NDR_BUFFERSIZE m; + unsigned long size; + + while (*pFormat != RPC_FC_END) { + switch (*pFormat) { + case RPC_FC_SHORT: + case RPC_FC_USHORT: + pStubMsg->BufferLength += 2; + pMemory += 2; + break; + case RPC_FC_LONG: + case RPC_FC_ULONG: + pStubMsg->BufferLength += 4; + pMemory += 4; + break; + case RPC_FC_POINTER: + NdrPointerBufferSize(pStubMsg, *(unsigned char**)pMemory, pPointer); + pPointer += 4; + pMemory += 4; + break; + case RPC_FC_ALIGNM4: + ALIGN_POINTER(pMemory, 3); + break; + case RPC_FC_ALIGNM8: + ALIGN_POINTER(pMemory, 7); + break; + case RPC_FC_EMBEDDED_COMPLEX: + pMemory += pFormat[1]; + pFormat += 2; + desc = pFormat + *(const SHORT*)pFormat; + size = EmbeddedComplexSize(pStubMsg, desc); + m = NdrBufferSizer[*desc & NDR_TABLE_MASK]; + if (m) m(pStubMsg, pMemory, desc); + else FIXME("no buffersizer for embedded type %02x\n", *desc); + pMemory += size; + pFormat += 2; + continue; + case RPC_FC_PAD: + break; + default: + FIXME("unhandled format %d\n", *pFormat); + } + pFormat++; + } + + return pMemory; +} + +unsigned char * WINAPI ComplexFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat, + PFORMAT_STRING pPointer) +{ + PFORMAT_STRING desc; + NDR_FREE m; + unsigned long size; + + while (*pFormat != RPC_FC_END) { + switch (*pFormat) { + case RPC_FC_SHORT: + case RPC_FC_USHORT: + pMemory += 2; + break; + case RPC_FC_LONG: + case RPC_FC_ULONG: + pMemory += 4; + break; + case RPC_FC_POINTER: + NdrPointerFree(pStubMsg, *(unsigned char**)pMemory, pPointer); + pPointer += 4; + pMemory += 4; + break; + case RPC_FC_ALIGNM4: + ALIGN_POINTER(pMemory, 3); + break; + case RPC_FC_ALIGNM8: + ALIGN_POINTER(pMemory, 7); + break; + case RPC_FC_EMBEDDED_COMPLEX: + pMemory += pFormat[1]; + pFormat += 2; + desc = pFormat + *(const SHORT*)pFormat; + size = EmbeddedComplexSize(pStubMsg, desc); + m = NdrFreer[*desc & NDR_TABLE_MASK]; + if (m) m(pStubMsg, pMemory, desc); + else FIXME("no freer for embedded type %02x\n", *desc); + pMemory += size; + pFormat += 2; + continue; + case RPC_FC_PAD: + break; + default: + FIXME("unhandled format %d\n", *pFormat); + } + pFormat++; + } + + return pMemory; +} + +unsigned long WINAPI ComplexStructSize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + PFORMAT_STRING desc; + unsigned long size = 0; + + while (*pFormat != RPC_FC_END) { + switch (*pFormat) { + case RPC_FC_SHORT: + case RPC_FC_USHORT: + size += 2; + break; + case RPC_FC_LONG: + case RPC_FC_ULONG: + size += 4; + break; + case RPC_FC_POINTER: + size += 4; + break; + case RPC_FC_ALIGNM4: + ALIGN_LENGTH(size, 3); + break; + case RPC_FC_ALIGNM8: + ALIGN_LENGTH(size, 7); + break; + case RPC_FC_EMBEDDED_COMPLEX: + size += pFormat[1]; + pFormat += 2; + desc = pFormat + *(const SHORT*)pFormat; + size += EmbeddedComplexSize(pStubMsg, desc); + pFormat += 2; + continue; + case RPC_FC_PAD: + break; + default: + FIXME("unhandled format %d\n", *pFormat); + } + pFormat++; + } + + return size; +} + +/*********************************************************************** + * NdrComplexStructMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrComplexStructMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + PFORMAT_STRING conf_array = NULL; + PFORMAT_STRING pointer_desc = NULL; + unsigned char *OldMemory = pStubMsg->Memory; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + pFormat += 4; + if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; + pFormat += 2; + if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; + pFormat += 2; + + pStubMsg->Memory = pMemory; + + ComplexMarshall(pStubMsg, pMemory, pFormat, pointer_desc); + + if (conf_array) + NdrConformantArrayMarshall(pStubMsg, pMemory, conf_array); + + pStubMsg->Memory = OldMemory; + + STD_OVERFLOW_CHECK(pStubMsg); + + return NULL; +} + +/*********************************************************************** + * NdrComplexStructUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrComplexStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + unsigned size = *(const WORD*)(pFormat+2); + PFORMAT_STRING conf_array = NULL; + PFORMAT_STRING pointer_desc = NULL; + unsigned char *pMemory; + + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + if (fMustAlloc || !*ppMemory) + *ppMemory = NdrAllocate(pStubMsg, size); + + pFormat += 4; + if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; + pFormat += 2; + if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; + pFormat += 2; + + pMemory = ComplexUnmarshall(pStubMsg, *ppMemory, pFormat, pointer_desc, fMustAlloc); + + if (conf_array) + NdrConformantArrayUnmarshall(pStubMsg, &pMemory, conf_array, fMustAlloc); + + return NULL; +} + +/*********************************************************************** + * NdrComplexStructBufferSize [RPCRT4.@] + */ +void WINAPI NdrComplexStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + PFORMAT_STRING conf_array = NULL; + PFORMAT_STRING pointer_desc = NULL; + unsigned char *OldMemory = pStubMsg->Memory; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + pFormat += 4; + if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; + pFormat += 2; + if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; + pFormat += 2; + + pStubMsg->Memory = pMemory; + + pMemory = ComplexBufferSize(pStubMsg, pMemory, pFormat, pointer_desc); + + if (conf_array) + NdrConformantArrayBufferSize(pStubMsg, pMemory, conf_array); + + pStubMsg->Memory = OldMemory; +} + +/*********************************************************************** + * NdrComplexStructMemorySize [RPCRT4.@] + */ +unsigned long WINAPI NdrComplexStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + /* unsigned size = *(LPWORD)(pFormat+2); */ + PFORMAT_STRING conf_array = NULL; + PFORMAT_STRING pointer_desc = NULL; + + FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + + pFormat += 4; + if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; + pFormat += 2; + if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; + pFormat += 2; + + return 0; +} + +/*********************************************************************** + * NdrComplexStructFree [RPCRT4.@] + */ +void WINAPI NdrComplexStructFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + PFORMAT_STRING conf_array = NULL; + PFORMAT_STRING pointer_desc = NULL; + unsigned char *OldMemory = pStubMsg->Memory; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + pFormat += 4; + if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; + pFormat += 2; + if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; + pFormat += 2; + + pStubMsg->Memory = pMemory; + + pMemory = ComplexFree(pStubMsg, pMemory, pFormat, pointer_desc); + + if (conf_array) + NdrConformantArrayFree(pStubMsg, pMemory, conf_array); + + pStubMsg->Memory = OldMemory; +} + +/*********************************************************************** + * NdrConformantArrayMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrConformantArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + DWORD size = 0, esize = *(const WORD*)(pFormat+2); + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); + size = pStubMsg->MaxCount; + + NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, size); + pStubMsg->Buffer += 4; + + memcpy(pStubMsg->Buffer, pMemory, size*esize); + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += size*esize; + + EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat); + + STD_OVERFLOW_CHECK(pStubMsg); + + return NULL; +} + +/*********************************************************************** + * NdrConformantArrayUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrConformantArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + DWORD size = 0, esize = *(const WORD*)(pFormat+2); + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); + + pFormat = ReadConformance(pStubMsg, pFormat+4); + size = pStubMsg->MaxCount; + + if (fMustAlloc) { + *ppMemory = NdrAllocate(pStubMsg, size*esize); + memcpy(*ppMemory, pStubMsg->Buffer, size*esize); + } else { + if (pStubMsg->ReuseBuffer && !*ppMemory) + /* for servers, we may just point straight into the RPC buffer, I think + * (I guess that's what MS does since MIDL code doesn't try to free) */ + *ppMemory = pStubMsg->Buffer; + else + /* for clients, memory should be provided by caller */ + memcpy(*ppMemory, pStubMsg->Buffer, size*esize); + } + + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += size*esize; + + EmbeddedPointerUnmarshall(pStubMsg, ppMemory, pFormat, fMustAlloc); + + return NULL; +} + +/*********************************************************************** + * NdrConformantArrayBufferSize [RPCRT4.@] + */ +void WINAPI NdrConformantArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + DWORD size = 0, esize = *(const WORD*)(pFormat+2); + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); + size = pStubMsg->MaxCount; + + pStubMsg->BufferLength += size*esize; + + EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat); +} + +/*********************************************************************** + * NdrConformantArrayMemorySize [RPCRT4.@] + */ +unsigned long WINAPI NdrConformantArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + DWORD size = 0; + FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); + + pFormat = ReadConformance(pStubMsg, pFormat+4); + size = pStubMsg->MaxCount; + + EmbeddedPointerMemorySize(pStubMsg, pFormat); + + return 0; +} + +/*********************************************************************** + * NdrConformantArrayFree [RPCRT4.@] + */ +void WINAPI NdrConformantArrayFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); + + EmbeddedPointerFree(pStubMsg, pMemory, pFormat); +} + + +/*********************************************************************** + * NdrConformantVaryingArrayMarshall [RPCRT4.@] + */ +unsigned char* WINAPI NdrConformantVaryingArrayMarshall( PMIDL_STUB_MESSAGE pStubMsg, + unsigned char* pMemory, + PFORMAT_STRING pFormat ) +{ + FIXME( "stub\n" ); + return NULL; +} + + +/*********************************************************************** + * NdrConformantVaryingArrayUnmarshall [RPCRT4.@] + */ +unsigned char* WINAPI NdrConformantVaryingArrayUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, + unsigned char** ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc ) +{ + FIXME( "stub\n" ); + return NULL; +} + + +/*********************************************************************** + * NdrConformantVaryingArrayFree [RPCRT4.@] + */ +void WINAPI NdrConformantVaryingArrayFree( PMIDL_STUB_MESSAGE pStubMsg, + unsigned char* pMemory, + PFORMAT_STRING pFormat ) +{ + FIXME( "stub\n" ); +} + + +/*********************************************************************** + * NdrConformantVaryingArrayBufferSize [RPCRT4.@] + */ +void WINAPI NdrConformantVaryingArrayBufferSize( PMIDL_STUB_MESSAGE pStubMsg, + unsigned char* pMemory, PFORMAT_STRING pFormat ) +{ + FIXME( "stub\n" ); +} + + +/*********************************************************************** + * NdrConformantVaryingArrayMemorySize [RPCRT4.@] + */ +unsigned long WINAPI NdrConformantVaryingArrayMemorySize( PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat ) +{ + FIXME( "stub\n" ); + return 0; +} + + +/*********************************************************************** + * NdrComplexArrayMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrComplexArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + DWORD size = 0, count, def; + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + def = *(const WORD*)&pFormat[2]; + pFormat += 4; + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat, def); + size = pStubMsg->MaxCount; + TRACE("conformance=%ld\n", size); + + if (*(const DWORD*)pFormat != 0xffffffff) + FIXME("compute variance\n"); + pFormat += 4; + + NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, size); + pStubMsg->Buffer += 4; + + for (count=0; count<size; count++) + pMemory = ComplexMarshall(pStubMsg, pMemory, pFormat, NULL); + + STD_OVERFLOW_CHECK(pStubMsg); + + return NULL; +} + +/*********************************************************************** + * NdrComplexArrayUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrComplexArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + DWORD size = 0, count, esize; + unsigned char *pMemory; + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + pFormat += 4; + + pFormat = ReadConformance(pStubMsg, pFormat); + size = pStubMsg->MaxCount; + TRACE("conformance=%ld\n", size); + + pFormat += 4; + + esize = ComplexStructSize(pStubMsg, pFormat); + + if (fMustAlloc || !*ppMemory) + *ppMemory = NdrAllocate(pStubMsg, size*esize); + + pMemory = *ppMemory; + for (count=0; count<size; count++) + pMemory = ComplexUnmarshall(pStubMsg, pMemory, pFormat, NULL, fMustAlloc); + + return NULL; +} + +/*********************************************************************** + * NdrComplexArrayBufferSize [RPCRT4.@] + */ +void WINAPI NdrComplexArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + DWORD size = 0, count, def; + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + def = *(const WORD*)&pFormat[2]; + pFormat += 4; + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat, def); + size = pStubMsg->MaxCount; + TRACE("conformance=%ld\n", size); + + if (*(const DWORD*)pFormat != 0xffffffff) + FIXME("compute variance\n"); + pFormat += 4; + + for (count=0; count<size; count++) + pMemory = ComplexBufferSize(pStubMsg, pMemory, pFormat, NULL); +} + +/*********************************************************************** + * NdrComplexArrayMemorySize [RPCRT4.@] + */ +unsigned long WINAPI NdrComplexArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + DWORD size = 0; + FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + + pFormat += 4; + + pFormat = ReadConformance(pStubMsg, pFormat); + size = pStubMsg->MaxCount; + TRACE("conformance=%ld\n", size); + + pFormat += 4; + + return 0; +} + +/*********************************************************************** + * NdrComplexArrayFree [RPCRT4.@] + */ +void WINAPI NdrComplexArrayFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + DWORD size = 0, count, def; + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + def = *(const WORD*)&pFormat[2]; + pFormat += 4; + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat, def); + size = pStubMsg->MaxCount; + TRACE("conformance=%ld\n", size); + + if (*(const DWORD*)pFormat != 0xffffffff) + FIXME("compute variance\n"); + pFormat += 4; + + for (count=0; count<size; count++) + pMemory = ComplexFree(pStubMsg, pMemory, pFormat, NULL); +} + +unsigned long UserMarshalFlags(PMIDL_STUB_MESSAGE pStubMsg) +{ + return MAKELONG(pStubMsg->dwDestContext, + pStubMsg->RpcMsg->DataRepresentation); +} + +/*********************************************************************** + * NdrUserMarshalMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrUserMarshalMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ +/* unsigned flags = pFormat[1]; */ + unsigned index = *(const WORD*)&pFormat[2]; + unsigned long uflag = UserMarshalFlags(pStubMsg); + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + TRACE("index=%d\n", index); + + pStubMsg->Buffer = + pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnMarshall( + &uflag, pStubMsg->Buffer, pMemory); + + STD_OVERFLOW_CHECK(pStubMsg); + + return NULL; +} + +/*********************************************************************** + * NdrUserMarshalUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrUserMarshalUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ +/* unsigned flags = pFormat[1];*/ + unsigned index = *(const WORD*)&pFormat[2]; + DWORD memsize = *(const WORD*)&pFormat[4]; + unsigned long uflag = UserMarshalFlags(pStubMsg); + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + TRACE("index=%d\n", index); + + if (fMustAlloc || !*ppMemory) + *ppMemory = NdrAllocate(pStubMsg, memsize); + + pStubMsg->Buffer = + pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnUnmarshall( + &uflag, pStubMsg->Buffer, *ppMemory); + + return NULL; +} + +/*********************************************************************** + * NdrUserMarshalBufferSize [RPCRT4.@] + */ +void WINAPI NdrUserMarshalBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ +/* unsigned flags = pFormat[1];*/ + unsigned index = *(const WORD*)&pFormat[2]; + DWORD bufsize = *(const WORD*)&pFormat[6]; + unsigned long uflag = UserMarshalFlags(pStubMsg); + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + TRACE("index=%d\n", index); + + if (bufsize) { + TRACE("size=%ld\n", bufsize); + pStubMsg->BufferLength += bufsize; + return; + } + + pStubMsg->BufferLength = + pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnBufferSize( + &uflag, pStubMsg->BufferLength, pMemory); +} + +/*********************************************************************** + * NdrUserMarshalMemorySize [RPCRT4.@] + */ +unsigned long WINAPI NdrUserMarshalMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + unsigned index = *(const WORD*)&pFormat[2]; +/* DWORD memsize = *(const WORD*)&pFormat[4]; */ + FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + TRACE("index=%d\n", index); + + return 0; +} + +/*********************************************************************** + * NdrUserMarshalFree [RPCRT4.@] + */ +void WINAPI NdrUserMarshalFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ +/* unsigned flags = pFormat[1]; */ + unsigned index = *(const WORD*)&pFormat[2]; + unsigned long uflag = UserMarshalFlags(pStubMsg); + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + TRACE("index=%d\n", index); + + pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnFree( + &uflag, pMemory); +} + +/*********************************************************************** + * NdrClearOutParameters [RPCRT4.@] + */ +void WINAPI NdrClearOutParameters(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat, + void *ArgAddr) +{ + FIXME("(%p,%p,%p): stub\n", pStubMsg, pFormat, ArgAddr); +} + +/*********************************************************************** + * NdrConvert [RPCRT4.@] + */ +void WINAPI NdrConvert( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) +{ + FIXME("(pStubMsg == ^%p, pFormat == ^%p): stub.\n", pStubMsg, pFormat); + /* FIXME: since this stub doesn't do any converting, the proper behavior + is to raise an exception */ +} + +/*********************************************************************** + * NdrConvert2 [RPCRT4.@] + */ +void WINAPI NdrConvert2( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, long NumberParams ) +{ + FIXME("(pStubMsg == ^%p, pFormat == ^%p, NumberParams == %ld): stub.\n", + pStubMsg, pFormat, NumberParams); + /* FIXME: since this stub doesn't do any converting, the proper behavior + is to raise an exception */ +} diff --git a/reactos/lib/rpcrt4/ndr_midl.c b/reactos/lib/rpcrt4/ndr_midl.c index f1d6b71c3c2..ba95835d197 100644 --- a/reactos/lib/rpcrt4/ndr_midl.c +++ b/reactos/lib/rpcrt4/ndr_midl.c @@ -1,296 +1,296 @@ -/* - * MIDL proxy/stub stuff - * - * Copyright 2002 Ove KÃ¥ven, TransGaming Technologies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * TODO: - * - figure out whether we *really* got this right - * - check for errors and throw exceptions - */ - -#include <stdarg.h> -#include <stdio.h> -#include <string.h> -#include <assert.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "winreg.h" - -#include "objbase.h" - -#include "rpcproxy.h" - -#include "wine/debug.h" - -#include "cpsf.h" -#include "ndr_misc.h" -#include "rpcndr.h" - -WINE_DEFAULT_DEBUG_CHANNEL(rpc); - -/*********************************************************************** - * NdrProxyInitialize [RPCRT4.@] - */ -void WINAPI NdrProxyInitialize(void *This, - PRPC_MESSAGE pRpcMsg, - PMIDL_STUB_MESSAGE pStubMsg, - PMIDL_STUB_DESC pStubDescriptor, - unsigned int ProcNum) -{ - HRESULT hr; - - TRACE("(%p,%p,%p,%p,%d)\n", This, pRpcMsg, pStubMsg, pStubDescriptor, ProcNum); - NdrClientInitializeNew(pRpcMsg, pStubMsg, pStubDescriptor, ProcNum); - if (This) StdProxy_GetChannel(This, &pStubMsg->pRpcChannelBuffer); - if (pStubMsg->pRpcChannelBuffer) { - hr = IRpcChannelBuffer_GetDestCtx(pStubMsg->pRpcChannelBuffer, - &pStubMsg->dwDestContext, - &pStubMsg->pvDestContext); - } - TRACE("channel=%p\n", pStubMsg->pRpcChannelBuffer); -} - -/*********************************************************************** - * NdrProxyGetBuffer [RPCRT4.@] - */ -void WINAPI NdrProxyGetBuffer(void *This, - PMIDL_STUB_MESSAGE pStubMsg) -{ - HRESULT hr; - const IID *riid = NULL; - - TRACE("(%p,%p)\n", This, pStubMsg); - pStubMsg->RpcMsg->BufferLength = pStubMsg->BufferLength; - pStubMsg->dwStubPhase = PROXY_GETBUFFER; - hr = StdProxy_GetIID(This, &riid); - hr = IRpcChannelBuffer_GetBuffer(pStubMsg->pRpcChannelBuffer, - (RPCOLEMESSAGE*)pStubMsg->RpcMsg, - riid); - pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; - pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; - pStubMsg->Buffer = pStubMsg->BufferStart; - pStubMsg->dwStubPhase = PROXY_MARSHAL; -} - -/*********************************************************************** - * NdrProxySendReceive [RPCRT4.@] - */ -void WINAPI NdrProxySendReceive(void *This, - PMIDL_STUB_MESSAGE pStubMsg) -{ - ULONG Status = 0; - HRESULT hr; - - TRACE("(%p,%p)\n", This, pStubMsg); - - if (!pStubMsg->pRpcChannelBuffer) - { - WARN("Trying to use disconnected proxy %p\n", This); - RpcRaiseException(RPC_E_DISCONNECTED); - } - - pStubMsg->dwStubPhase = PROXY_SENDRECEIVE; - hr = IRpcChannelBuffer_SendReceive(pStubMsg->pRpcChannelBuffer, - (RPCOLEMESSAGE*)pStubMsg->RpcMsg, - &Status); - pStubMsg->dwStubPhase = PROXY_UNMARSHAL; - pStubMsg->BufferLength = pStubMsg->RpcMsg->BufferLength; - pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; - pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; - pStubMsg->Buffer = pStubMsg->BufferStart; - - /* raise exception if call failed */ - if (hr == RPC_S_CALL_FAILED) RpcRaiseException(*(DWORD*)pStubMsg->Buffer); - else if (FAILED(hr)) RpcRaiseException(hr); -} - -/*********************************************************************** - * NdrProxyFreeBuffer [RPCRT4.@] - */ -void WINAPI NdrProxyFreeBuffer(void *This, - PMIDL_STUB_MESSAGE pStubMsg) -{ - HRESULT hr; - - TRACE("(%p,%p)\n", This, pStubMsg); - hr = IRpcChannelBuffer_FreeBuffer(pStubMsg->pRpcChannelBuffer, - (RPCOLEMESSAGE*)pStubMsg->RpcMsg); -} - -/*********************************************************************** - * NdrProxyErrorHandler [RPCRT4.@] - */ -HRESULT WINAPI NdrProxyErrorHandler(DWORD dwExceptionCode) -{ - FIXME("(0x%08lx): semi-stub\n", dwExceptionCode); - return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_RPC, RPC_S_CALL_FAILED); -} - -/*********************************************************************** - * NdrStubInitialize [RPCRT4.@] - */ -void WINAPI NdrStubInitialize(PRPC_MESSAGE pRpcMsg, - PMIDL_STUB_MESSAGE pStubMsg, - PMIDL_STUB_DESC pStubDescriptor, - LPRPCCHANNELBUFFER pRpcChannelBuffer) -{ - TRACE("(%p,%p,%p,%p)\n", pRpcMsg, pStubMsg, pStubDescriptor, pRpcChannelBuffer); - NdrServerInitializeNew(pRpcMsg, pStubMsg, pStubDescriptor); - pStubMsg->pRpcChannelBuffer = pRpcChannelBuffer; -} - -/*********************************************************************** - * NdrStubGetBuffer [RPCRT4.@] - */ -void WINAPI NdrStubGetBuffer(LPRPCSTUBBUFFER This, - LPRPCCHANNELBUFFER pRpcChannelBuffer, - PMIDL_STUB_MESSAGE pStubMsg) -{ - TRACE("(%p,%p)\n", This, pStubMsg); - pStubMsg->pRpcChannelBuffer = pRpcChannelBuffer; - pStubMsg->RpcMsg->BufferLength = pStubMsg->BufferLength; - I_RpcGetBuffer(pStubMsg->RpcMsg); /* ? */ - pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; - pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; - pStubMsg->Buffer = pStubMsg->BufferStart; -} - -/************************************************************************ - * NdrClientInitializeNew [RPCRT4.@] - */ -void WINAPI NdrClientInitializeNew( PRPC_MESSAGE pRpcMessage, PMIDL_STUB_MESSAGE pStubMsg, - PMIDL_STUB_DESC pStubDesc, unsigned int ProcNum ) -{ - TRACE("(pRpcMessage == ^%p, pStubMsg == ^%p, pStubDesc == ^%p, ProcNum == %d)\n", - pRpcMessage, pStubMsg, pStubDesc, ProcNum); - - assert( pRpcMessage && pStubMsg && pStubDesc ); - - memset(pRpcMessage, 0, sizeof(RPC_MESSAGE)); - - /* not everyone allocates stack space for w2kReserved */ - memset(pStubMsg, 0, FIELD_OFFSET(MIDL_STUB_MESSAGE,pCSInfo)); - - pStubMsg->ReuseBuffer = FALSE; - pStubMsg->IsClient = TRUE; - pStubMsg->StubDesc = pStubDesc; - pStubMsg->pfnAllocate = pStubDesc->pfnAllocate; - pStubMsg->pfnFree = pStubDesc->pfnFree; - pStubMsg->RpcMsg = pRpcMessage; - - pRpcMessage->ProcNum = ProcNum; - pRpcMessage->RpcInterfaceInformation = pStubDesc->RpcInterfaceInformation; -} - -/*********************************************************************** - * NdrServerInitializeNew [RPCRT4.@] - */ -unsigned char* WINAPI NdrServerInitializeNew( PRPC_MESSAGE pRpcMsg, PMIDL_STUB_MESSAGE pStubMsg, - PMIDL_STUB_DESC pStubDesc ) -{ - TRACE("(pRpcMsg == ^%p, pStubMsg == ^%p, pStubDesc == ^%p)\n", pRpcMsg, pStubMsg, pStubDesc); - - assert( pRpcMsg && pStubMsg && pStubDesc ); - - /* not everyone allocates stack space for w2kReserved */ - memset(pStubMsg, 0, FIELD_OFFSET(MIDL_STUB_MESSAGE,pCSInfo)); - - pStubMsg->ReuseBuffer = TRUE; - pStubMsg->IsClient = FALSE; - pStubMsg->StubDesc = pStubDesc; - pStubMsg->pfnAllocate = pStubDesc->pfnAllocate; - pStubMsg->pfnFree = pStubDesc->pfnFree; - pStubMsg->RpcMsg = pRpcMsg; - pStubMsg->Buffer = pStubMsg->BufferStart = pRpcMsg->Buffer; - pStubMsg->BufferLength = pRpcMsg->BufferLength; - pStubMsg->BufferEnd = pStubMsg->Buffer + pStubMsg->BufferLength; - - /* FIXME: determine the proper return value */ - return NULL; -} - -/*********************************************************************** - * NdrGetBuffer [RPCRT4.@] - */ -unsigned char *WINAPI NdrGetBuffer(MIDL_STUB_MESSAGE *stubmsg, unsigned long buflen, RPC_BINDING_HANDLE handle) -{ - TRACE("(stubmsg == ^%p, buflen == %lu, handle == %p): wild guess.\n", stubmsg, buflen, handle); - - assert( stubmsg && stubmsg->RpcMsg ); - - /* I guess this is our chance to put the binding handle into the RPC_MESSAGE */ - stubmsg->RpcMsg->Handle = handle; - - stubmsg->RpcMsg->BufferLength = buflen; - if (I_RpcGetBuffer(stubmsg->RpcMsg) != S_OK) - return NULL; - - stubmsg->Buffer = stubmsg->BufferStart = stubmsg->RpcMsg->Buffer; - stubmsg->BufferLength = stubmsg->RpcMsg->BufferLength; - stubmsg->BufferEnd = stubmsg->Buffer + stubmsg->BufferLength; - return (stubmsg->Buffer = (unsigned char *)stubmsg->RpcMsg->Buffer); -} - -/*********************************************************************** - * NdrFreeBuffer [RPCRT4.@] - */ -void WINAPI NdrFreeBuffer(MIDL_STUB_MESSAGE *pStubMsg) -{ - TRACE("(pStubMsg == ^%p): wild guess.\n", pStubMsg); - I_RpcFreeBuffer(pStubMsg->RpcMsg); - pStubMsg->BufferLength = 0; - pStubMsg->Buffer = pStubMsg->BufferEnd = (unsigned char *)(pStubMsg->RpcMsg->Buffer = NULL); -} - -/************************************************************************ - * NdrSendReceive [RPCRT4.@] - */ -unsigned char *WINAPI NdrSendReceive( MIDL_STUB_MESSAGE *pStubMsg, unsigned char *buffer ) -{ - TRACE("(pStubMsg == ^%p, buffer == ^%p)\n", pStubMsg, buffer); - - /* FIXME: how to handle errors? (raise exception?) */ - if (!pStubMsg) { - ERR("NULL stub message. No action taken.\n"); - return NULL; - } - if (!pStubMsg->RpcMsg) { - ERR("RPC Message not present in stub message. No action taken.\n"); - return NULL; - } - - /* FIXME: Seems wrong. Where should this really come from, and when? */ - pStubMsg->RpcMsg->DataRepresentation = NDR_LOCAL_DATA_REPRESENTATION; - - if (I_RpcSendReceive(pStubMsg->RpcMsg) != RPC_S_OK) { - WARN("I_RpcSendReceive did not return success.\n"); - /* FIXME: raise exception? */ - return NULL; - } - - pStubMsg->BufferLength = pStubMsg->RpcMsg->BufferLength; - pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; - pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; - pStubMsg->Buffer = pStubMsg->BufferStart; - - /* FIXME: is this the right return value? */ - return NULL; -} +/* + * MIDL proxy/stub stuff + * + * Copyright 2002 Ove KÃ¥ven, TransGaming Technologies + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * TODO: + * - figure out whether we *really* got this right + * - check for errors and throw exceptions + */ + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" + +#include "objbase.h" + +#include "rpcproxy.h" + +#include "wine/debug.h" + +#include "cpsf.h" +#include "ndr_misc.h" +#include "rpcndr.h" + +WINE_DEFAULT_DEBUG_CHANNEL(rpc); + +/*********************************************************************** + * NdrProxyInitialize [RPCRT4.@] + */ +void WINAPI NdrProxyInitialize(void *This, + PRPC_MESSAGE pRpcMsg, + PMIDL_STUB_MESSAGE pStubMsg, + PMIDL_STUB_DESC pStubDescriptor, + unsigned int ProcNum) +{ + HRESULT hr; + + TRACE("(%p,%p,%p,%p,%d)\n", This, pRpcMsg, pStubMsg, pStubDescriptor, ProcNum); + NdrClientInitializeNew(pRpcMsg, pStubMsg, pStubDescriptor, ProcNum); + if (This) StdProxy_GetChannel(This, &pStubMsg->pRpcChannelBuffer); + if (pStubMsg->pRpcChannelBuffer) { + hr = IRpcChannelBuffer_GetDestCtx(pStubMsg->pRpcChannelBuffer, + &pStubMsg->dwDestContext, + &pStubMsg->pvDestContext); + } + TRACE("channel=%p\n", pStubMsg->pRpcChannelBuffer); +} + +/*********************************************************************** + * NdrProxyGetBuffer [RPCRT4.@] + */ +void WINAPI NdrProxyGetBuffer(void *This, + PMIDL_STUB_MESSAGE pStubMsg) +{ + HRESULT hr; + const IID *riid = NULL; + + TRACE("(%p,%p)\n", This, pStubMsg); + pStubMsg->RpcMsg->BufferLength = pStubMsg->BufferLength; + pStubMsg->dwStubPhase = PROXY_GETBUFFER; + hr = StdProxy_GetIID(This, &riid); + hr = IRpcChannelBuffer_GetBuffer(pStubMsg->pRpcChannelBuffer, + (RPCOLEMESSAGE*)pStubMsg->RpcMsg, + riid); + pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; + pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; + pStubMsg->Buffer = pStubMsg->BufferStart; + pStubMsg->dwStubPhase = PROXY_MARSHAL; +} + +/*********************************************************************** + * NdrProxySendReceive [RPCRT4.@] + */ +void WINAPI NdrProxySendReceive(void *This, + PMIDL_STUB_MESSAGE pStubMsg) +{ + ULONG Status = 0; + HRESULT hr; + + TRACE("(%p,%p)\n", This, pStubMsg); + + if (!pStubMsg->pRpcChannelBuffer) + { + WARN("Trying to use disconnected proxy %p\n", This); + RpcRaiseException(RPC_E_DISCONNECTED); + } + + pStubMsg->dwStubPhase = PROXY_SENDRECEIVE; + hr = IRpcChannelBuffer_SendReceive(pStubMsg->pRpcChannelBuffer, + (RPCOLEMESSAGE*)pStubMsg->RpcMsg, + &Status); + pStubMsg->dwStubPhase = PROXY_UNMARSHAL; + pStubMsg->BufferLength = pStubMsg->RpcMsg->BufferLength; + pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; + pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; + pStubMsg->Buffer = pStubMsg->BufferStart; + + /* raise exception if call failed */ + if (hr == RPC_S_CALL_FAILED) RpcRaiseException(*(DWORD*)pStubMsg->Buffer); + else if (FAILED(hr)) RpcRaiseException(hr); +} + +/*********************************************************************** + * NdrProxyFreeBuffer [RPCRT4.@] + */ +void WINAPI NdrProxyFreeBuffer(void *This, + PMIDL_STUB_MESSAGE pStubMsg) +{ + HRESULT hr; + + TRACE("(%p,%p)\n", This, pStubMsg); + hr = IRpcChannelBuffer_FreeBuffer(pStubMsg->pRpcChannelBuffer, + (RPCOLEMESSAGE*)pStubMsg->RpcMsg); +} + +/*********************************************************************** + * NdrProxyErrorHandler [RPCRT4.@] + */ +HRESULT WINAPI NdrProxyErrorHandler(DWORD dwExceptionCode) +{ + FIXME("(0x%08lx): semi-stub\n", dwExceptionCode); + return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_RPC, RPC_S_CALL_FAILED); +} + +/*********************************************************************** + * NdrStubInitialize [RPCRT4.@] + */ +void WINAPI NdrStubInitialize(PRPC_MESSAGE pRpcMsg, + PMIDL_STUB_MESSAGE pStubMsg, + PMIDL_STUB_DESC pStubDescriptor, + LPRPCCHANNELBUFFER pRpcChannelBuffer) +{ + TRACE("(%p,%p,%p,%p)\n", pRpcMsg, pStubMsg, pStubDescriptor, pRpcChannelBuffer); + NdrServerInitializeNew(pRpcMsg, pStubMsg, pStubDescriptor); + pStubMsg->pRpcChannelBuffer = pRpcChannelBuffer; +} + +/*********************************************************************** + * NdrStubGetBuffer [RPCRT4.@] + */ +void WINAPI NdrStubGetBuffer(LPRPCSTUBBUFFER This, + LPRPCCHANNELBUFFER pRpcChannelBuffer, + PMIDL_STUB_MESSAGE pStubMsg) +{ + TRACE("(%p,%p)\n", This, pStubMsg); + pStubMsg->pRpcChannelBuffer = pRpcChannelBuffer; + pStubMsg->RpcMsg->BufferLength = pStubMsg->BufferLength; + I_RpcGetBuffer(pStubMsg->RpcMsg); /* ? */ + pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; + pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; + pStubMsg->Buffer = pStubMsg->BufferStart; +} + +/************************************************************************ + * NdrClientInitializeNew [RPCRT4.@] + */ +void WINAPI NdrClientInitializeNew( PRPC_MESSAGE pRpcMessage, PMIDL_STUB_MESSAGE pStubMsg, + PMIDL_STUB_DESC pStubDesc, unsigned int ProcNum ) +{ + TRACE("(pRpcMessage == ^%p, pStubMsg == ^%p, pStubDesc == ^%p, ProcNum == %d)\n", + pRpcMessage, pStubMsg, pStubDesc, ProcNum); + + assert( pRpcMessage && pStubMsg && pStubDesc ); + + memset(pRpcMessage, 0, sizeof(RPC_MESSAGE)); + + /* not everyone allocates stack space for w2kReserved */ + memset(pStubMsg, 0, FIELD_OFFSET(MIDL_STUB_MESSAGE,pCSInfo)); + + pStubMsg->ReuseBuffer = FALSE; + pStubMsg->IsClient = TRUE; + pStubMsg->StubDesc = pStubDesc; + pStubMsg->pfnAllocate = pStubDesc->pfnAllocate; + pStubMsg->pfnFree = pStubDesc->pfnFree; + pStubMsg->RpcMsg = pRpcMessage; + + pRpcMessage->ProcNum = ProcNum; + pRpcMessage->RpcInterfaceInformation = pStubDesc->RpcInterfaceInformation; +} + +/*********************************************************************** + * NdrServerInitializeNew [RPCRT4.@] + */ +unsigned char* WINAPI NdrServerInitializeNew( PRPC_MESSAGE pRpcMsg, PMIDL_STUB_MESSAGE pStubMsg, + PMIDL_STUB_DESC pStubDesc ) +{ + TRACE("(pRpcMsg == ^%p, pStubMsg == ^%p, pStubDesc == ^%p)\n", pRpcMsg, pStubMsg, pStubDesc); + + assert( pRpcMsg && pStubMsg && pStubDesc ); + + /* not everyone allocates stack space for w2kReserved */ + memset(pStubMsg, 0, FIELD_OFFSET(MIDL_STUB_MESSAGE,pCSInfo)); + + pStubMsg->ReuseBuffer = TRUE; + pStubMsg->IsClient = FALSE; + pStubMsg->StubDesc = pStubDesc; + pStubMsg->pfnAllocate = pStubDesc->pfnAllocate; + pStubMsg->pfnFree = pStubDesc->pfnFree; + pStubMsg->RpcMsg = pRpcMsg; + pStubMsg->Buffer = pStubMsg->BufferStart = pRpcMsg->Buffer; + pStubMsg->BufferLength = pRpcMsg->BufferLength; + pStubMsg->BufferEnd = pStubMsg->Buffer + pStubMsg->BufferLength; + + /* FIXME: determine the proper return value */ + return NULL; +} + +/*********************************************************************** + * NdrGetBuffer [RPCRT4.@] + */ +unsigned char *WINAPI NdrGetBuffer(MIDL_STUB_MESSAGE *stubmsg, unsigned long buflen, RPC_BINDING_HANDLE handle) +{ + TRACE("(stubmsg == ^%p, buflen == %lu, handle == %p): wild guess.\n", stubmsg, buflen, handle); + + assert( stubmsg && stubmsg->RpcMsg ); + + /* I guess this is our chance to put the binding handle into the RPC_MESSAGE */ + stubmsg->RpcMsg->Handle = handle; + + stubmsg->RpcMsg->BufferLength = buflen; + if (I_RpcGetBuffer(stubmsg->RpcMsg) != S_OK) + return NULL; + + stubmsg->Buffer = stubmsg->BufferStart = stubmsg->RpcMsg->Buffer; + stubmsg->BufferLength = stubmsg->RpcMsg->BufferLength; + stubmsg->BufferEnd = stubmsg->Buffer + stubmsg->BufferLength; + return (stubmsg->Buffer = (unsigned char *)stubmsg->RpcMsg->Buffer); +} + +/*********************************************************************** + * NdrFreeBuffer [RPCRT4.@] + */ +void WINAPI NdrFreeBuffer(MIDL_STUB_MESSAGE *pStubMsg) +{ + TRACE("(pStubMsg == ^%p): wild guess.\n", pStubMsg); + I_RpcFreeBuffer(pStubMsg->RpcMsg); + pStubMsg->BufferLength = 0; + pStubMsg->Buffer = pStubMsg->BufferEnd = (unsigned char *)(pStubMsg->RpcMsg->Buffer = NULL); +} + +/************************************************************************ + * NdrSendReceive [RPCRT4.@] + */ +unsigned char *WINAPI NdrSendReceive( MIDL_STUB_MESSAGE *pStubMsg, unsigned char *buffer ) +{ + TRACE("(pStubMsg == ^%p, buffer == ^%p)\n", pStubMsg, buffer); + + /* FIXME: how to handle errors? (raise exception?) */ + if (!pStubMsg) { + ERR("NULL stub message. No action taken.\n"); + return NULL; + } + if (!pStubMsg->RpcMsg) { + ERR("RPC Message not present in stub message. No action taken.\n"); + return NULL; + } + + /* FIXME: Seems wrong. Where should this really come from, and when? */ + pStubMsg->RpcMsg->DataRepresentation = NDR_LOCAL_DATA_REPRESENTATION; + + if (I_RpcSendReceive(pStubMsg->RpcMsg) != RPC_S_OK) { + WARN("I_RpcSendReceive did not return success.\n"); + /* FIXME: raise exception? */ + return NULL; + } + + pStubMsg->BufferLength = pStubMsg->RpcMsg->BufferLength; + pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; + pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; + pStubMsg->Buffer = pStubMsg->BufferStart; + + /* FIXME: is this the right return value? */ + return NULL; +} diff --git a/reactos/lib/rpcrt4/ndr_misc.h b/reactos/lib/rpcrt4/ndr_misc.h index 9ffeed2448e..b246b44d991 100644 --- a/reactos/lib/rpcrt4/ndr_misc.h +++ b/reactos/lib/rpcrt4/ndr_misc.h @@ -1,53 +1,53 @@ -/* - * NDR definitions - * - * Copyright 2001 Ove KÃ¥ven, TransGaming Technologies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_NDR_MISC_H -#define __WINE_NDR_MISC_H - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "rpc.h" -#include "rpcndr.h" - -struct IPSFactoryBuffer; - -LONG_PTR RPCRT4_NdrClientCall2(PMIDL_STUB_DESC pStubDesc, - PFORMAT_STRING pFormat, va_list args ); - -HRESULT RPCRT4_GetPSFactory(REFIID riid, struct IPSFactoryBuffer **ppPS); - -PFORMAT_STRING ComputeConformance(MIDL_STUB_MESSAGE *pStubMsg, unsigned char *pMemory, - PFORMAT_STRING pFormat, ULONG_PTR def); - -typedef unsigned char* (WINAPI *NDR_MARSHALL) (PMIDL_STUB_MESSAGE, unsigned char*, PFORMAT_STRING); -typedef unsigned char* (WINAPI *NDR_UNMARSHALL)(PMIDL_STUB_MESSAGE, unsigned char**,PFORMAT_STRING, unsigned char); -typedef void (WINAPI *NDR_BUFFERSIZE)(PMIDL_STUB_MESSAGE, unsigned char*, PFORMAT_STRING); -typedef unsigned long (WINAPI *NDR_MEMORYSIZE)(PMIDL_STUB_MESSAGE, PFORMAT_STRING); -typedef void (WINAPI *NDR_FREE) (PMIDL_STUB_MESSAGE, unsigned char*, PFORMAT_STRING); - -extern NDR_MARSHALL NdrMarshaller[]; -extern NDR_UNMARSHALL NdrUnmarshaller[]; -extern NDR_BUFFERSIZE NdrBufferSizer[]; -extern NDR_MEMORYSIZE NdrMemorySizer[]; -extern NDR_FREE NdrFreer[]; - -#endif /* __WINE_NDR_MISC_H */ +/* + * NDR definitions + * + * Copyright 2001 Ove KÃ¥ven, TransGaming Technologies + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_NDR_MISC_H +#define __WINE_NDR_MISC_H + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "rpc.h" +#include "rpcndr.h" + +struct IPSFactoryBuffer; + +LONG_PTR RPCRT4_NdrClientCall2(PMIDL_STUB_DESC pStubDesc, + PFORMAT_STRING pFormat, va_list args ); + +HRESULT RPCRT4_GetPSFactory(REFIID riid, struct IPSFactoryBuffer **ppPS); + +PFORMAT_STRING ComputeConformance(MIDL_STUB_MESSAGE *pStubMsg, unsigned char *pMemory, + PFORMAT_STRING pFormat, ULONG_PTR def); + +typedef unsigned char* (WINAPI *NDR_MARSHALL) (PMIDL_STUB_MESSAGE, unsigned char*, PFORMAT_STRING); +typedef unsigned char* (WINAPI *NDR_UNMARSHALL)(PMIDL_STUB_MESSAGE, unsigned char**,PFORMAT_STRING, unsigned char); +typedef void (WINAPI *NDR_BUFFERSIZE)(PMIDL_STUB_MESSAGE, unsigned char*, PFORMAT_STRING); +typedef unsigned long (WINAPI *NDR_MEMORYSIZE)(PMIDL_STUB_MESSAGE, PFORMAT_STRING); +typedef void (WINAPI *NDR_FREE) (PMIDL_STUB_MESSAGE, unsigned char*, PFORMAT_STRING); + +extern NDR_MARSHALL NdrMarshaller[]; +extern NDR_UNMARSHALL NdrUnmarshaller[]; +extern NDR_BUFFERSIZE NdrBufferSizer[]; +extern NDR_MEMORYSIZE NdrMemorySizer[]; +extern NDR_FREE NdrFreer[]; + +#endif /* __WINE_NDR_MISC_H */ diff --git a/reactos/lib/rpcrt4/ndr_ole.c b/reactos/lib/rpcrt4/ndr_ole.c index aef1c9485d3..cda3dc163c7 100644 --- a/reactos/lib/rpcrt4/ndr_ole.c +++ b/reactos/lib/rpcrt4/ndr_ole.c @@ -1,350 +1,350 @@ -/* - * OLE32 callouts, COM interface marshalling - * - * Copyright 2001 Ove KÃ¥ven, TransGaming Technologies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * TODO: - * - figure out whether we *really* got this right - * - check for errors and throw exceptions - * - what are the marshalling functions supposed to return? - * - finish RpcStream_Vtbl - */ - -#include <stdarg.h> -#include <stdio.h> -#include <string.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "winreg.h" - -#include "objbase.h" - -#include "ndr_misc.h" -#include "rpcndr.h" -#include "wine/rpcfc.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -static HMODULE hOLE; - -static HRESULT (WINAPI *COM_GetMarshalSizeMax)(ULONG *,REFIID,LPUNKNOWN,DWORD,LPVOID,DWORD); -static HRESULT (WINAPI *COM_MarshalInterface)(LPSTREAM,REFIID,LPUNKNOWN,DWORD,LPVOID,DWORD); -static HRESULT (WINAPI *COM_UnmarshalInterface)(LPSTREAM,REFIID,LPVOID*); -static HRESULT (WINAPI *COM_ReleaseMarshalData)(LPSTREAM); -static HRESULT (WINAPI *COM_GetClassObject)(REFCLSID,DWORD,COSERVERINFO *,REFIID,LPVOID *); -static HRESULT (WINAPI *COM_GetPSClsid)(REFIID,CLSID *); -static LPVOID (WINAPI *COM_MemAlloc)(ULONG); -static void (WINAPI *COM_MemFree)(LPVOID); - -static HMODULE LoadCOM(void) -{ - if (hOLE) return hOLE; - hOLE = LoadLibraryA("OLE32.DLL"); - if (!hOLE) return 0; - COM_GetMarshalSizeMax = (LPVOID)GetProcAddress(hOLE, "CoGetMarshalSizeMax"); - COM_MarshalInterface = (LPVOID)GetProcAddress(hOLE, "CoMarshalInterface"); - COM_UnmarshalInterface = (LPVOID)GetProcAddress(hOLE, "CoUnmarshalInterface"); - COM_ReleaseMarshalData = (LPVOID)GetProcAddress(hOLE, "CoReleaseMarshalData"); - COM_GetClassObject = (LPVOID)GetProcAddress(hOLE, "CoGetClassObject"); - COM_GetPSClsid = (LPVOID)GetProcAddress(hOLE, "CoGetPSClsid"); - COM_MemAlloc = (LPVOID)GetProcAddress(hOLE, "CoTaskMemAlloc"); - COM_MemFree = (LPVOID)GetProcAddress(hOLE, "CoTaskMemFree"); - return hOLE; -} - -/* CoMarshalInterface/CoUnmarshalInterface works on streams, - * so implement a simple stream on top of the RPC buffer - * (which also implements the MInterfacePointer structure) */ -typedef struct RpcStreamImpl -{ - IStreamVtbl *lpVtbl; - DWORD RefCount; - PMIDL_STUB_MESSAGE pMsg; - LPDWORD size; - char *data; - DWORD pos; -} RpcStreamImpl; - -static HRESULT WINAPI RpcStream_QueryInterface(LPSTREAM iface, - REFIID riid, - LPVOID *obj) -{ - RpcStreamImpl *This = (RpcStreamImpl *)iface; - if (IsEqualGUID(&IID_IUnknown, riid) || - IsEqualGUID(&IID_ISequentialStream, riid) || - IsEqualGUID(&IID_IStream, riid)) { - *obj = This; - This->RefCount++; - return S_OK; - } - return E_NOINTERFACE; -} - -static ULONG WINAPI RpcStream_AddRef(LPSTREAM iface) -{ - RpcStreamImpl *This = (RpcStreamImpl *)iface; - return ++(This->RefCount); -} - -static ULONG WINAPI RpcStream_Release(LPSTREAM iface) -{ - RpcStreamImpl *This = (RpcStreamImpl *)iface; - if (!--(This->RefCount)) { - TRACE("size=%ld\n", *This->size); - This->pMsg->Buffer = This->data + *This->size; - HeapFree(GetProcessHeap(),0,This); - return 0; - } - return This->RefCount; -} - -static HRESULT WINAPI RpcStream_Read(LPSTREAM iface, - void *pv, - ULONG cb, - ULONG *pcbRead) -{ - RpcStreamImpl *This = (RpcStreamImpl *)iface; - if (This->pos + cb > *This->size) cb = *This->size - This->pos; - if (cb) { - memcpy(pv, This->data + This->pos, cb); - This->pos += cb; - } - if (pcbRead) *pcbRead = cb; - return S_OK; -} - -static HRESULT WINAPI RpcStream_Write(LPSTREAM iface, - const void *pv, - ULONG cb, - ULONG *pcbWritten) -{ - RpcStreamImpl *This = (RpcStreamImpl *)iface; - memcpy(This->data + This->pos, pv, cb); - This->pos += cb; - if (This->pos > *This->size) *This->size = This->pos; - if (pcbWritten) *pcbWritten = cb; - return S_OK; -} - -static HRESULT WINAPI RpcStream_Seek(LPSTREAM iface, - LARGE_INTEGER move, - DWORD origin, - ULARGE_INTEGER *newPos) -{ - RpcStreamImpl *This = (RpcStreamImpl *)iface; - switch (origin) { - case STREAM_SEEK_SET: - This->pos = move.u.LowPart; - break; - case STREAM_SEEK_CUR: - This->pos = This->pos + move.u.LowPart; - break; - case STREAM_SEEK_END: - This->pos = *This->size + move.u.LowPart; - break; - default: - return STG_E_INVALIDFUNCTION; - } - if (newPos) { - newPos->u.LowPart = This->pos; - newPos->u.HighPart = 0; - } - return S_OK; -} - -static HRESULT WINAPI RpcStream_SetSize(LPSTREAM iface, - ULARGE_INTEGER newSize) -{ - RpcStreamImpl *This = (RpcStreamImpl *)iface; - *This->size = newSize.u.LowPart; - return S_OK; -} - -static IStreamVtbl RpcStream_Vtbl = -{ - RpcStream_QueryInterface, - RpcStream_AddRef, - RpcStream_Release, - RpcStream_Read, - RpcStream_Write, - RpcStream_Seek, - RpcStream_SetSize, - NULL, /* CopyTo */ - NULL, /* Commit */ - NULL, /* Revert */ - NULL, /* LockRegion */ - NULL, /* UnlockRegion */ - NULL, /* Stat */ - NULL /* Clone */ -}; - -static LPSTREAM RpcStream_Create(PMIDL_STUB_MESSAGE pStubMsg, BOOL init) -{ - RpcStreamImpl *This; - This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(RpcStreamImpl)); - if (!This) return NULL; - This->lpVtbl = &RpcStream_Vtbl; - This->RefCount = 1; - This->pMsg = pStubMsg; - This->size = (LPDWORD)pStubMsg->Buffer; - This->data = (char*)(This->size + 1); - This->pos = 0; - if (init) *This->size = 0; - TRACE("init size=%ld\n", *This->size); - return (LPSTREAM)This; -} - -const IID* get_ip_iid(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) -{ - const IID *riid; - if (!pFormat) return &IID_IUnknown; - TRACE("format=%02x %02x\n", pFormat[0], pFormat[1]); - if (pFormat[0] != RPC_FC_IP) FIXME("format=%d\n", pFormat[0]); - if (pFormat[1] == RPC_FC_CONSTANT_IID) { - riid = (const IID *)&pFormat[2]; - } else { - ComputeConformance(pStubMsg, pMemory, pFormat+2, 0); - riid = (const IID *)pStubMsg->MaxCount; - } - if (!riid) riid = &IID_IUnknown; - TRACE("got %s\n", debugstr_guid(riid)); - return riid; -} - -/*********************************************************************** - * NdrInterfacePointerMarshall [RPCRT4.@] - */ -unsigned char * WINAPI NdrInterfacePointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ - const IID *riid = get_ip_iid(pStubMsg, pMemory, pFormat); - LPSTREAM stream; - HRESULT hr; - - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - pStubMsg->MaxCount = 0; - if (!LoadCOM()) return NULL; - stream = RpcStream_Create(pStubMsg, TRUE); - hr = COM_MarshalInterface(stream, riid, (LPUNKNOWN)pMemory, - pStubMsg->dwDestContext, pStubMsg->pvDestContext, - MSHLFLAGS_NORMAL); - IStream_Release(stream); - return NULL; -} - -/*********************************************************************** - * NdrInterfacePointerUnmarshall [RPCRT4.@] - */ -unsigned char * WINAPI NdrInterfacePointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char **ppMemory, - PFORMAT_STRING pFormat, - unsigned char fMustAlloc) -{ - LPSTREAM stream; - HRESULT hr; - - TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); - if (!LoadCOM()) return NULL; - *(LPVOID*)ppMemory = NULL; - stream = RpcStream_Create(pStubMsg, FALSE); - hr = COM_UnmarshalInterface(stream, &IID_NULL, (LPVOID*)ppMemory); - IStream_Release(stream); - return NULL; -} - -/*********************************************************************** - * NdrInterfacePointerBufferSize [RPCRT4.@] - */ -void WINAPI NdrInterfacePointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ - const IID *riid = get_ip_iid(pStubMsg, pMemory, pFormat); - ULONG size = 0; - HRESULT hr; - - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - if (!LoadCOM()) return; - hr = COM_GetMarshalSizeMax(&size, riid, (LPUNKNOWN)pMemory, - pStubMsg->dwDestContext, pStubMsg->pvDestContext, - MSHLFLAGS_NORMAL); - TRACE("size=%ld\n", size); - pStubMsg->BufferLength += sizeof(DWORD) + size; -} - -/*********************************************************************** - * NdrInterfacePointerMemorySize [RPCRT4.@] - */ -unsigned long WINAPI NdrInterfacePointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, - PFORMAT_STRING pFormat) -{ - FIXME("(%p,%p): stub\n", pStubMsg, pFormat); - return 0; -} - -/*********************************************************************** - * NdrInterfacePointerFree [RPCRT4.@] - */ -void WINAPI NdrInterfacePointerFree(PMIDL_STUB_MESSAGE pStubMsg, - unsigned char *pMemory, - PFORMAT_STRING pFormat) -{ - LPUNKNOWN pUnk = (LPUNKNOWN)pMemory; - TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); - if (pUnk) IUnknown_Release(pUnk); -} - -/*********************************************************************** - * NdrOleAllocate [RPCRT4.@] - */ -void * WINAPI NdrOleAllocate(size_t Size) -{ - if (!LoadCOM()) return NULL; - return COM_MemAlloc(Size); -} - -/*********************************************************************** - * NdrOleFree [RPCRT4.@] - */ -void WINAPI NdrOleFree(void *NodeToFree) -{ - if (!LoadCOM()) return; - COM_MemFree(NodeToFree); -} - -/* internal */ -HRESULT RPCRT4_GetPSFactory(REFIID riid, LPPSFACTORYBUFFER *pPS) -{ - HRESULT hr; - CLSID clsid; - - if (!LoadCOM()) return RPC_E_UNEXPECTED; - hr = COM_GetPSClsid(riid, &clsid); - if (FAILED(hr)) return hr; - hr = COM_GetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, - &IID_IPSFactoryBuffer, (LPVOID *)pPS); - return hr; -} +/* + * OLE32 callouts, COM interface marshalling + * + * Copyright 2001 Ove KÃ¥ven, TransGaming Technologies + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * TODO: + * - figure out whether we *really* got this right + * - check for errors and throw exceptions + * - what are the marshalling functions supposed to return? + * - finish RpcStream_Vtbl + */ + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" + +#include "objbase.h" + +#include "ndr_misc.h" +#include "rpcndr.h" +#include "wine/rpcfc.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +static HMODULE hOLE; + +static HRESULT (WINAPI *COM_GetMarshalSizeMax)(ULONG *,REFIID,LPUNKNOWN,DWORD,LPVOID,DWORD); +static HRESULT (WINAPI *COM_MarshalInterface)(LPSTREAM,REFIID,LPUNKNOWN,DWORD,LPVOID,DWORD); +static HRESULT (WINAPI *COM_UnmarshalInterface)(LPSTREAM,REFIID,LPVOID*); +static HRESULT (WINAPI *COM_ReleaseMarshalData)(LPSTREAM); +static HRESULT (WINAPI *COM_GetClassObject)(REFCLSID,DWORD,COSERVERINFO *,REFIID,LPVOID *); +static HRESULT (WINAPI *COM_GetPSClsid)(REFIID,CLSID *); +static LPVOID (WINAPI *COM_MemAlloc)(ULONG); +static void (WINAPI *COM_MemFree)(LPVOID); + +static HMODULE LoadCOM(void) +{ + if (hOLE) return hOLE; + hOLE = LoadLibraryA("OLE32.DLL"); + if (!hOLE) return 0; + COM_GetMarshalSizeMax = (LPVOID)GetProcAddress(hOLE, "CoGetMarshalSizeMax"); + COM_MarshalInterface = (LPVOID)GetProcAddress(hOLE, "CoMarshalInterface"); + COM_UnmarshalInterface = (LPVOID)GetProcAddress(hOLE, "CoUnmarshalInterface"); + COM_ReleaseMarshalData = (LPVOID)GetProcAddress(hOLE, "CoReleaseMarshalData"); + COM_GetClassObject = (LPVOID)GetProcAddress(hOLE, "CoGetClassObject"); + COM_GetPSClsid = (LPVOID)GetProcAddress(hOLE, "CoGetPSClsid"); + COM_MemAlloc = (LPVOID)GetProcAddress(hOLE, "CoTaskMemAlloc"); + COM_MemFree = (LPVOID)GetProcAddress(hOLE, "CoTaskMemFree"); + return hOLE; +} + +/* CoMarshalInterface/CoUnmarshalInterface works on streams, + * so implement a simple stream on top of the RPC buffer + * (which also implements the MInterfacePointer structure) */ +typedef struct RpcStreamImpl +{ + IStreamVtbl *lpVtbl; + DWORD RefCount; + PMIDL_STUB_MESSAGE pMsg; + LPDWORD size; + char *data; + DWORD pos; +} RpcStreamImpl; + +static HRESULT WINAPI RpcStream_QueryInterface(LPSTREAM iface, + REFIID riid, + LPVOID *obj) +{ + RpcStreamImpl *This = (RpcStreamImpl *)iface; + if (IsEqualGUID(&IID_IUnknown, riid) || + IsEqualGUID(&IID_ISequentialStream, riid) || + IsEqualGUID(&IID_IStream, riid)) { + *obj = This; + This->RefCount++; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI RpcStream_AddRef(LPSTREAM iface) +{ + RpcStreamImpl *This = (RpcStreamImpl *)iface; + return ++(This->RefCount); +} + +static ULONG WINAPI RpcStream_Release(LPSTREAM iface) +{ + RpcStreamImpl *This = (RpcStreamImpl *)iface; + if (!--(This->RefCount)) { + TRACE("size=%ld\n", *This->size); + This->pMsg->Buffer = This->data + *This->size; + HeapFree(GetProcessHeap(),0,This); + return 0; + } + return This->RefCount; +} + +static HRESULT WINAPI RpcStream_Read(LPSTREAM iface, + void *pv, + ULONG cb, + ULONG *pcbRead) +{ + RpcStreamImpl *This = (RpcStreamImpl *)iface; + if (This->pos + cb > *This->size) cb = *This->size - This->pos; + if (cb) { + memcpy(pv, This->data + This->pos, cb); + This->pos += cb; + } + if (pcbRead) *pcbRead = cb; + return S_OK; +} + +static HRESULT WINAPI RpcStream_Write(LPSTREAM iface, + const void *pv, + ULONG cb, + ULONG *pcbWritten) +{ + RpcStreamImpl *This = (RpcStreamImpl *)iface; + memcpy(This->data + This->pos, pv, cb); + This->pos += cb; + if (This->pos > *This->size) *This->size = This->pos; + if (pcbWritten) *pcbWritten = cb; + return S_OK; +} + +static HRESULT WINAPI RpcStream_Seek(LPSTREAM iface, + LARGE_INTEGER move, + DWORD origin, + ULARGE_INTEGER *newPos) +{ + RpcStreamImpl *This = (RpcStreamImpl *)iface; + switch (origin) { + case STREAM_SEEK_SET: + This->pos = move.u.LowPart; + break; + case STREAM_SEEK_CUR: + This->pos = This->pos + move.u.LowPart; + break; + case STREAM_SEEK_END: + This->pos = *This->size + move.u.LowPart; + break; + default: + return STG_E_INVALIDFUNCTION; + } + if (newPos) { + newPos->u.LowPart = This->pos; + newPos->u.HighPart = 0; + } + return S_OK; +} + +static HRESULT WINAPI RpcStream_SetSize(LPSTREAM iface, + ULARGE_INTEGER newSize) +{ + RpcStreamImpl *This = (RpcStreamImpl *)iface; + *This->size = newSize.u.LowPart; + return S_OK; +} + +static IStreamVtbl RpcStream_Vtbl = +{ + RpcStream_QueryInterface, + RpcStream_AddRef, + RpcStream_Release, + RpcStream_Read, + RpcStream_Write, + RpcStream_Seek, + RpcStream_SetSize, + NULL, /* CopyTo */ + NULL, /* Commit */ + NULL, /* Revert */ + NULL, /* LockRegion */ + NULL, /* UnlockRegion */ + NULL, /* Stat */ + NULL /* Clone */ +}; + +static LPSTREAM RpcStream_Create(PMIDL_STUB_MESSAGE pStubMsg, BOOL init) +{ + RpcStreamImpl *This; + This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(RpcStreamImpl)); + if (!This) return NULL; + This->lpVtbl = &RpcStream_Vtbl; + This->RefCount = 1; + This->pMsg = pStubMsg; + This->size = (LPDWORD)pStubMsg->Buffer; + This->data = (char*)(This->size + 1); + This->pos = 0; + if (init) *This->size = 0; + TRACE("init size=%ld\n", *This->size); + return (LPSTREAM)This; +} + +const IID* get_ip_iid(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) +{ + const IID *riid; + if (!pFormat) return &IID_IUnknown; + TRACE("format=%02x %02x\n", pFormat[0], pFormat[1]); + if (pFormat[0] != RPC_FC_IP) FIXME("format=%d\n", pFormat[0]); + if (pFormat[1] == RPC_FC_CONSTANT_IID) { + riid = (const IID *)&pFormat[2]; + } else { + ComputeConformance(pStubMsg, pMemory, pFormat+2, 0); + riid = (const IID *)pStubMsg->MaxCount; + } + if (!riid) riid = &IID_IUnknown; + TRACE("got %s\n", debugstr_guid(riid)); + return riid; +} + +/*********************************************************************** + * NdrInterfacePointerMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrInterfacePointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + const IID *riid = get_ip_iid(pStubMsg, pMemory, pFormat); + LPSTREAM stream; + HRESULT hr; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + pStubMsg->MaxCount = 0; + if (!LoadCOM()) return NULL; + stream = RpcStream_Create(pStubMsg, TRUE); + hr = COM_MarshalInterface(stream, riid, (LPUNKNOWN)pMemory, + pStubMsg->dwDestContext, pStubMsg->pvDestContext, + MSHLFLAGS_NORMAL); + IStream_Release(stream); + return NULL; +} + +/*********************************************************************** + * NdrInterfacePointerUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrInterfacePointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + LPSTREAM stream; + HRESULT hr; + + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + if (!LoadCOM()) return NULL; + *(LPVOID*)ppMemory = NULL; + stream = RpcStream_Create(pStubMsg, FALSE); + hr = COM_UnmarshalInterface(stream, &IID_NULL, (LPVOID*)ppMemory); + IStream_Release(stream); + return NULL; +} + +/*********************************************************************** + * NdrInterfacePointerBufferSize [RPCRT4.@] + */ +void WINAPI NdrInterfacePointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + const IID *riid = get_ip_iid(pStubMsg, pMemory, pFormat); + ULONG size = 0; + HRESULT hr; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (!LoadCOM()) return; + hr = COM_GetMarshalSizeMax(&size, riid, (LPUNKNOWN)pMemory, + pStubMsg->dwDestContext, pStubMsg->pvDestContext, + MSHLFLAGS_NORMAL); + TRACE("size=%ld\n", size); + pStubMsg->BufferLength += sizeof(DWORD) + size; +} + +/*********************************************************************** + * NdrInterfacePointerMemorySize [RPCRT4.@] + */ +unsigned long WINAPI NdrInterfacePointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + return 0; +} + +/*********************************************************************** + * NdrInterfacePointerFree [RPCRT4.@] + */ +void WINAPI NdrInterfacePointerFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + LPUNKNOWN pUnk = (LPUNKNOWN)pMemory; + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (pUnk) IUnknown_Release(pUnk); +} + +/*********************************************************************** + * NdrOleAllocate [RPCRT4.@] + */ +void * WINAPI NdrOleAllocate(size_t Size) +{ + if (!LoadCOM()) return NULL; + return COM_MemAlloc(Size); +} + +/*********************************************************************** + * NdrOleFree [RPCRT4.@] + */ +void WINAPI NdrOleFree(void *NodeToFree) +{ + if (!LoadCOM()) return; + COM_MemFree(NodeToFree); +} + +/* internal */ +HRESULT RPCRT4_GetPSFactory(REFIID riid, LPPSFACTORYBUFFER *pPS) +{ + HRESULT hr; + CLSID clsid; + + if (!LoadCOM()) return RPC_E_UNEXPECTED; + hr = COM_GetPSClsid(riid, &clsid); + if (FAILED(hr)) return hr; + hr = COM_GetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL, + &IID_IPSFactoryBuffer, (LPVOID *)pPS); + return hr; +} diff --git a/reactos/lib/rpcrt4/ndr_stubless.c b/reactos/lib/rpcrt4/ndr_stubless.c index f4c6a7a12e7..40f8dcc6d30 100644 --- a/reactos/lib/rpcrt4/ndr_stubless.c +++ b/reactos/lib/rpcrt4/ndr_stubless.c @@ -1,106 +1,106 @@ -/* - * NDR client stuff - * - * Copyright 2001 Ove KÃ¥ven, TransGaming Technologies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * TODO: - * - Exception handling - * - Context stuff - * - Who knows - */ - -#include <stdarg.h> -#include <stdio.h> -#include <string.h> - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "winreg.h" - -#include "rpc.h" -#include "rpcndr.h" - -#include "wine/debug.h" - -#include "ndr_misc.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/*********************************************************************** - * Note: this should return a CLIENT_CALL_RETURN, but calling convention for - * returning structures/unions is different between Windows and gcc on i386. - */ -LONG_PTR RPCRT4_NdrClientCall2(PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pFormat, va_list args) -{ - - RPC_CLIENT_INTERFACE *rpc_cli_if = (RPC_CLIENT_INTERFACE *)(pStubDesc->RpcInterfaceInformation); - LONG_PTR ret = 0; -/* - RPC_BINDING_HANDLE handle = 0; - RPC_MESSAGE rpcmsg; - MIDL_STUB_MESSAGE stubmsg; -*/ - - FIXME("(pStubDec == ^%p,pFormat = ^%p,...): stub\n", pStubDesc, pFormat); - if (rpc_cli_if) /* NULL for objects */ { - TRACE(" *rpc_cli_if (== ^%p) == (RPC_CLIENT_INTERFACE):\n", pStubDesc); - TRACE(" Length == %d\n", rpc_cli_if->Length); - TRACE(" InterfaceID == %s (%d.%d)\n", debugstr_guid(&rpc_cli_if->InterfaceId.SyntaxGUID), - rpc_cli_if->InterfaceId.SyntaxVersion.MajorVersion, rpc_cli_if->InterfaceId.SyntaxVersion.MinorVersion); - TRACE(" TransferSyntax == %s (%d.%d)\n", debugstr_guid(&rpc_cli_if->TransferSyntax.SyntaxGUID), - rpc_cli_if->TransferSyntax.SyntaxVersion.MajorVersion, rpc_cli_if->TransferSyntax.SyntaxVersion.MinorVersion); - TRACE(" DispatchTable == ^%p\n", rpc_cli_if->DispatchTable); - TRACE(" RpcProtseqEndpointCount == ^%d\n", rpc_cli_if->RpcProtseqEndpointCount); - TRACE(" RpcProtseqEndpoint == ^%p\n", rpc_cli_if->RpcProtseqEndpoint); - TRACE(" Flags == ^%d\n", rpc_cli_if->Flags); - } - - /* for now, while these functons are under development, this is too sketchy. commented out. */ - /* - NdrClientInitializeNew( &rpcmsg, &stubmsg, pStubDesc, 0 ); - - handle = (RPC_BINDING_HANDLE)0xdeadbeef; */ /* FIXME */ - - /* stubmsg.BufferLength = 0;*/ /* FIXME */ - /* - NdrGetBuffer( &stubmsg, stubmsg.BufferLength, handle ); - NdrSendReceive( &stubmsg, stubmsg.Buffer ); - NdrFreeBuffer( &stubmsg ); - */ - return ret; -} - -/*********************************************************************** - * NdrClientCall2 [RPCRT4.@] - * - * Note: this should return a CLIENT_CALL_RETURN, but calling convention for - * returning structures/unions is different between Windows and gcc on i386. - */ -LONG_PTR WINAPIV NdrClientCall2(PMIDL_STUB_DESC pStubDesc, - PFORMAT_STRING pFormat, ...) -{ - LONG_PTR ret; - va_list args; - - TRACE("(%p,%p,...)\n", pStubDesc, pFormat); - - va_start(args, pFormat); - ret = RPCRT4_NdrClientCall2(pStubDesc, pFormat, args); - va_end(args); - return ret; -} +/* + * NDR client stuff + * + * Copyright 2001 Ove KÃ¥ven, TransGaming Technologies + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * TODO: + * - Exception handling + * - Context stuff + * - Who knows + */ + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" + +#include "rpc.h" +#include "rpcndr.h" + +#include "wine/debug.h" + +#include "ndr_misc.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/*********************************************************************** + * Note: this should return a CLIENT_CALL_RETURN, but calling convention for + * returning structures/unions is different between Windows and gcc on i386. + */ +LONG_PTR RPCRT4_NdrClientCall2(PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pFormat, va_list args) +{ + + RPC_CLIENT_INTERFACE *rpc_cli_if = (RPC_CLIENT_INTERFACE *)(pStubDesc->RpcInterfaceInformation); + LONG_PTR ret = 0; +/* + RPC_BINDING_HANDLE handle = 0; + RPC_MESSAGE rpcmsg; + MIDL_STUB_MESSAGE stubmsg; +*/ + + FIXME("(pStubDec == ^%p,pFormat = ^%p,...): stub\n", pStubDesc, pFormat); + if (rpc_cli_if) /* NULL for objects */ { + TRACE(" *rpc_cli_if (== ^%p) == (RPC_CLIENT_INTERFACE):\n", pStubDesc); + TRACE(" Length == %d\n", rpc_cli_if->Length); + TRACE(" InterfaceID == %s (%d.%d)\n", debugstr_guid(&rpc_cli_if->InterfaceId.SyntaxGUID), + rpc_cli_if->InterfaceId.SyntaxVersion.MajorVersion, rpc_cli_if->InterfaceId.SyntaxVersion.MinorVersion); + TRACE(" TransferSyntax == %s (%d.%d)\n", debugstr_guid(&rpc_cli_if->TransferSyntax.SyntaxGUID), + rpc_cli_if->TransferSyntax.SyntaxVersion.MajorVersion, rpc_cli_if->TransferSyntax.SyntaxVersion.MinorVersion); + TRACE(" DispatchTable == ^%p\n", rpc_cli_if->DispatchTable); + TRACE(" RpcProtseqEndpointCount == ^%d\n", rpc_cli_if->RpcProtseqEndpointCount); + TRACE(" RpcProtseqEndpoint == ^%p\n", rpc_cli_if->RpcProtseqEndpoint); + TRACE(" Flags == ^%d\n", rpc_cli_if->Flags); + } + + /* for now, while these functons are under development, this is too sketchy. commented out. */ + /* + NdrClientInitializeNew( &rpcmsg, &stubmsg, pStubDesc, 0 ); + + handle = (RPC_BINDING_HANDLE)0xdeadbeef; */ /* FIXME */ + + /* stubmsg.BufferLength = 0;*/ /* FIXME */ + /* + NdrGetBuffer( &stubmsg, stubmsg.BufferLength, handle ); + NdrSendReceive( &stubmsg, stubmsg.Buffer ); + NdrFreeBuffer( &stubmsg ); + */ + return ret; +} + +/*********************************************************************** + * NdrClientCall2 [RPCRT4.@] + * + * Note: this should return a CLIENT_CALL_RETURN, but calling convention for + * returning structures/unions is different between Windows and gcc on i386. + */ +LONG_PTR WINAPIV NdrClientCall2(PMIDL_STUB_DESC pStubDesc, + PFORMAT_STRING pFormat, ...) +{ + LONG_PTR ret; + va_list args; + + TRACE("(%p,%p,...)\n", pStubDesc, pFormat); + + va_start(args, pFormat); + ret = RPCRT4_NdrClientCall2(pStubDesc, pFormat, args); + va_end(args); + return ret; +} diff --git a/reactos/lib/rpcrt4/rpc_binding.c b/reactos/lib/rpcrt4/rpc_binding.c index 326086ad359..02b7d9779d3 100644 --- a/reactos/lib/rpcrt4/rpc_binding.c +++ b/reactos/lib/rpcrt4/rpc_binding.c @@ -1,1155 +1,1155 @@ -/* - * RPC binding API - * - * Copyright 2001 Ove KÃ¥ven, TransGaming Technologies - * Copyright 2003 Mike Hearn - * Copyright 2004 Filip Navara - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * TODO: - * - a whole lot - */ - -#include <stdarg.h> -#include <stdio.h> -#include <string.h> -#include <assert.h> - -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "winerror.h" -#include "winreg.h" -#include "winternl.h" -#include "wine/unicode.h" - -#include "rpc.h" -#include "rpcndr.h" - -#include "wine/debug.h" - -#include "rpc_binding.h" -#include "rpc_message.h" - -WINE_DEFAULT_DEBUG_CHANNEL(rpc); - -LPSTR RPCRT4_strndupA(LPCSTR src, INT slen) -{ - DWORD len; - LPSTR s; - if (!src) return NULL; - if (slen == -1) slen = strlen(src); - len = slen; - s = HeapAlloc(GetProcessHeap(), 0, len+1); - memcpy(s, src, len); - s[len] = 0; - return s; -} - -LPSTR RPCRT4_strdupWtoA(LPWSTR src) -{ - DWORD len; - LPSTR s; - if (!src) return NULL; - len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL); - s = HeapAlloc(GetProcessHeap(), 0, len); - WideCharToMultiByte(CP_ACP, 0, src, -1, s, len, NULL, NULL); - return s; -} - -LPWSTR RPCRT4_strdupAtoW(LPSTR src) -{ - DWORD len; - LPWSTR s; - if (!src) return NULL; - len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0); - s = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, src, -1, s, len); - return s; -} - -LPWSTR RPCRT4_strndupW(LPWSTR src, INT slen) -{ - DWORD len; - LPWSTR s; - if (!src) return NULL; - if (slen == -1) slen = strlenW(src); - len = slen; - s = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR)); - memcpy(s, src, len*sizeof(WCHAR)); - s[len] = 0; - return s; -} - -void RPCRT4_strfree(LPSTR src) -{ - HeapFree(GetProcessHeap(), 0, src); -} - -RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPSTR Protseq, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions, RpcBinding* Binding) -{ - RpcConnection* NewConnection; - - NewConnection = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection)); - NewConnection->server = server; - NewConnection->Protseq = RPCRT4_strdupA(Protseq); - NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr); - NewConnection->Endpoint = RPCRT4_strdupA(Endpoint); - NewConnection->Used = Binding; - NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE; - - TRACE("connection: %p\n", NewConnection); - *Connection = NewConnection; - - return RPC_S_OK; -} - -RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection) -{ - TRACE("connection: %p\n", Connection); - - RPCRT4_CloseConnection(Connection); - RPCRT4_strfree(Connection->Endpoint); - RPCRT4_strfree(Connection->NetworkAddr); - RPCRT4_strfree(Connection->Protseq); - HeapFree(GetProcessHeap(), 0, Connection); - return RPC_S_OK; -} - -RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection) -{ - TRACE("(Connection == ^%p)\n", Connection); - if (!Connection->conn) { - if (Connection->server) { /* server */ - /* protseq=ncalrpc: supposed to use NT LPC ports, - * but we'll implement it with named pipes for now */ - if (strcmp(Connection->Protseq, "ncalrpc") == 0) { - static LPCSTR prefix = "\\\\.\\pipe\\lrpc\\"; - LPSTR pname; - pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1); - strcat(strcpy(pname, prefix), Connection->Endpoint); - TRACE("listening on %s\n", pname); - Connection->conn = CreateNamedPipeA(pname, PROFILE_SERVER | PIPE_ACCESS_DUPLEX, - PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, - RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL); - HeapFree(GetProcessHeap(), 0, pname); - memset(&Connection->ovl, 0, sizeof(Connection->ovl)); - Connection->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - Connection->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - if (!ConnectNamedPipe(Connection->conn, &Connection->ovl[0])) { - WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError()); - if (GetLastError() == ERROR_PIPE_CONNECTED) { - SetEvent(Connection->ovl[0].hEvent); - return RPC_S_OK; - } else if (GetLastError() == ERROR_IO_PENDING) { - return RPC_S_OK; - } - return RPC_S_SERVER_UNAVAILABLE; - } - } - /* protseq=ncacn_np: named pipes */ - else if (strcmp(Connection->Protseq, "ncacn_np") == 0) { - static LPCSTR prefix = "\\\\."; - LPSTR pname; - pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1); - strcat(strcpy(pname, prefix), Connection->Endpoint); - TRACE("listening on %s\n", pname); - Connection->conn = CreateNamedPipeA(pname, PROFILE_SERVER | PIPE_ACCESS_DUPLEX, - PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, - RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL); - HeapFree(GetProcessHeap(), 0, pname); - memset(&Connection->ovl, 0, sizeof(Connection->ovl)); - Connection->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - Connection->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - if (!ConnectNamedPipe(Connection->conn, &Connection->ovl[0])) { - if (GetLastError() == ERROR_PIPE_CONNECTED) { - SetEvent(Connection->ovl[0].hEvent); - return RPC_S_OK; - } else if (GetLastError() == ERROR_IO_PENDING) { - return RPC_S_OK; - } - WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError()); - return RPC_S_SERVER_UNAVAILABLE; - } - } - else { - ERR("protseq %s not supported\n", Connection->Protseq); - return RPC_S_PROTSEQ_NOT_SUPPORTED; - } - } - else { /* client */ - /* protseq=ncalrpc: supposed to use NT LPC ports, - * but we'll implement it with named pipes for now */ - if (strcmp(Connection->Protseq, "ncalrpc") == 0) { - static LPCSTR prefix = "\\\\.\\pipe\\lrpc\\"; - LPSTR pname; - HANDLE conn; - DWORD err; - DWORD dwMode; - - pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1); - strcat(strcpy(pname, prefix), Connection->Endpoint); - TRACE("connecting to %s\n", pname); - while (TRUE) { - if (WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) { - conn = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL, - OPEN_EXISTING, 0, 0); - if (conn != INVALID_HANDLE_VALUE) break; - err = GetLastError(); - if (err == ERROR_PIPE_BUSY) continue; - TRACE("connection failed, error=%lx\n", err); - HeapFree(GetProcessHeap(), 0, pname); - return RPC_S_SERVER_TOO_BUSY; - } else { - err = GetLastError(); - WARN("connection failed, error=%lx\n", err); - HeapFree(GetProcessHeap(), 0, pname); - return RPC_S_SERVER_UNAVAILABLE; - } - } - - /* success */ - HeapFree(GetProcessHeap(), 0, pname); - memset(&Connection->ovl, 0, sizeof(Connection->ovl)); - /* pipe is connected; change to message-read mode. */ - dwMode = PIPE_READMODE_MESSAGE; - SetNamedPipeHandleState(conn, &dwMode, NULL, NULL); - Connection->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - Connection->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - Connection->conn = conn; - } - /* protseq=ncacn_np: named pipes */ - else if (strcmp(Connection->Protseq, "ncacn_np") == 0) { - static LPCSTR prefix = "\\\\."; - LPSTR pname; - HANDLE conn; - DWORD err; - DWORD dwMode; - - pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1); - strcat(strcpy(pname, prefix), Connection->Endpoint); - TRACE("connecting to %s\n", pname); - conn = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL, - OPEN_EXISTING, 0, 0); - if (conn == INVALID_HANDLE_VALUE) { - err = GetLastError(); - /* we don't need to handle ERROR_PIPE_BUSY here, - * the doc says that it is returned to the app */ - WARN("connection failed, error=%lx\n", err); - HeapFree(GetProcessHeap(), 0, pname); - if (err == ERROR_PIPE_BUSY) - return RPC_S_SERVER_TOO_BUSY; - else - return RPC_S_SERVER_UNAVAILABLE; - } - - /* success */ - HeapFree(GetProcessHeap(), 0, pname); - memset(&Connection->ovl, 0, sizeof(Connection->ovl)); - /* pipe is connected; change to message-read mode. */ - dwMode = PIPE_READMODE_MESSAGE; - SetNamedPipeHandleState(conn, &dwMode, NULL, NULL); - Connection->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - Connection->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - Connection->conn = conn; - } else { - ERR("protseq %s not supported\n", Connection->Protseq); - return RPC_S_PROTSEQ_NOT_SUPPORTED; - } - } - } - return RPC_S_OK; -} - -RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection) -{ - TRACE("(Connection == ^%p)\n", Connection); - if (Connection->conn) { - CancelIo(Connection->conn); - CloseHandle(Connection->conn); - Connection->conn = 0; - } - if (Connection->ovl[0].hEvent) { - CloseHandle(Connection->ovl[0].hEvent); - Connection->ovl[0].hEvent = 0; - } - if (Connection->ovl[1].hEvent) { - CloseHandle(Connection->ovl[1].hEvent); - Connection->ovl[1].hEvent = 0; - } - return RPC_S_OK; -} - -RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection) -{ - RpcConnection* NewConnection; - RPC_STATUS err = RPCRT4_CreateConnection(&NewConnection, OldConnection->server, OldConnection->Protseq, - OldConnection->NetworkAddr, OldConnection->Endpoint, NULL, NULL); - if (err == RPC_S_OK) { - /* because of the way named pipes work, we'll transfer the connected pipe - * to the child, then reopen the server binding to continue listening */ - NewConnection->conn = OldConnection->conn; - NewConnection->ovl[0] = OldConnection->ovl[0]; - NewConnection->ovl[1] = OldConnection->ovl[1]; - OldConnection->conn = 0; - memset(&OldConnection->ovl, 0, sizeof(OldConnection->ovl)); - *Connection = NewConnection; - RPCRT4_OpenConnection(OldConnection); - } - return err; -} - -RPC_STATUS RPCRT4_AllocBinding(RpcBinding** Binding, BOOL server) -{ - RpcBinding* NewBinding; - - NewBinding = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcBinding)); - NewBinding->refs = 1; - NewBinding->server = server; - - *Binding = NewBinding; - - return RPC_S_OK; -} - -RPC_STATUS RPCRT4_CreateBindingA(RpcBinding** Binding, BOOL server, LPSTR Protseq) -{ - RpcBinding* NewBinding; - - RPCRT4_AllocBinding(&NewBinding, server); - NewBinding->Protseq = RPCRT4_strdupA(Protseq); - - TRACE("binding: %p\n", NewBinding); - *Binding = NewBinding; - - return RPC_S_OK; -} - -RPC_STATUS RPCRT4_CreateBindingW(RpcBinding** Binding, BOOL server, LPWSTR Protseq) -{ - RpcBinding* NewBinding; - - RPCRT4_AllocBinding(&NewBinding, server); - NewBinding->Protseq = RPCRT4_strdupWtoA(Protseq); - - TRACE("binding: %p\n", NewBinding); - *Binding = NewBinding; - - return RPC_S_OK; -} - -RPC_STATUS RPCRT4_CompleteBindingA(RpcBinding* Binding, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions) -{ - TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding, - debugstr_a(NetworkAddr), debugstr_a(Endpoint), debugstr_a(NetworkOptions)); - - RPCRT4_strfree(Binding->NetworkAddr); - Binding->NetworkAddr = RPCRT4_strdupA(NetworkAddr); - RPCRT4_strfree(Binding->Endpoint); - if (Endpoint) { - Binding->Endpoint = RPCRT4_strdupA(Endpoint); - } else { - Binding->Endpoint = RPCRT4_strdupA(""); - } - if (!Binding->Endpoint) ERR("out of memory?\n"); - - return RPC_S_OK; -} - -RPC_STATUS RPCRT4_CompleteBindingW(RpcBinding* Binding, LPWSTR NetworkAddr, LPWSTR Endpoint, LPWSTR NetworkOptions) -{ - TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding, - debugstr_w(NetworkAddr), debugstr_w(Endpoint), debugstr_w(NetworkOptions)); - - RPCRT4_strfree(Binding->NetworkAddr); - Binding->NetworkAddr = RPCRT4_strdupWtoA(NetworkAddr); - RPCRT4_strfree(Binding->Endpoint); - if (Endpoint) { - Binding->Endpoint = RPCRT4_strdupWtoA(Endpoint); - } else { - Binding->Endpoint = RPCRT4_strdupA(""); - } - if (!Binding->Endpoint) ERR("out of memory?\n"); - - return RPC_S_OK; -} - -RPC_STATUS RPCRT4_ResolveBinding(RpcBinding* Binding, LPSTR Endpoint) -{ - TRACE("(RpcBinding == ^%p, EndPoint == \"%s\"\n", Binding, Endpoint); - - RPCRT4_strfree(Binding->Endpoint); - Binding->Endpoint = RPCRT4_strdupA(Endpoint); - - return RPC_S_OK; -} - -RPC_STATUS RPCRT4_SetBindingObject(RpcBinding* Binding, UUID* ObjectUuid) -{ - TRACE("(*RpcBinding == ^%p, UUID == %s)\n", Binding, debugstr_guid(ObjectUuid)); - if (ObjectUuid) memcpy(&Binding->ObjectUuid, ObjectUuid, sizeof(UUID)); - else UuidCreateNil(&Binding->ObjectUuid); - return RPC_S_OK; -} - -RPC_STATUS RPCRT4_MakeBinding(RpcBinding** Binding, RpcConnection* Connection) -{ - RpcBinding* NewBinding; - TRACE("(RpcBinding == ^%p, Connection == ^%p)\n", Binding, Connection); - - RPCRT4_AllocBinding(&NewBinding, Connection->server); - NewBinding->Protseq = RPCRT4_strdupA(Connection->Protseq); - NewBinding->NetworkAddr = RPCRT4_strdupA(Connection->NetworkAddr); - NewBinding->Endpoint = RPCRT4_strdupA(Connection->Endpoint); - NewBinding->FromConn = Connection; - - TRACE("binding: %p\n", NewBinding); - *Binding = NewBinding; - - return RPC_S_OK; -} - -RPC_STATUS RPCRT4_ExportBinding(RpcBinding** Binding, RpcBinding* OldBinding) -{ - InterlockedIncrement(&OldBinding->refs); - *Binding = OldBinding; - return RPC_S_OK; -} - -RPC_STATUS RPCRT4_DestroyBinding(RpcBinding* Binding) -{ - if (InterlockedDecrement(&Binding->refs)) - return RPC_S_OK; - - TRACE("binding: %p\n", Binding); - /* FIXME: release connections */ - RPCRT4_strfree(Binding->Endpoint); - RPCRT4_strfree(Binding->NetworkAddr); - RPCRT4_strfree(Binding->Protseq); - HeapFree(GetProcessHeap(), 0, Binding); - return RPC_S_OK; -} - -RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection, - PRPC_SYNTAX_IDENTIFIER TransferSyntax, - PRPC_SYNTAX_IDENTIFIER InterfaceId) -{ - RpcConnection* NewConnection; - RPC_STATUS status; - - TRACE("(Binding == ^%p)\n", Binding); - - /* if we try to bind a new interface and the connection is already opened, - * close the current connection and create a new with the new binding. */ - if (!Binding->server && Binding->FromConn && - memcmp(&Binding->FromConn->ActiveInterface, InterfaceId, - sizeof(RPC_SYNTAX_IDENTIFIER))) { - - TRACE("releasing pre-existing connection\n"); - RPCRT4_DestroyConnection(Binding->FromConn); - Binding->FromConn = NULL; - } else { - /* we already have a connection with acceptable binding, so use it */ - if (Binding->FromConn) { - *Connection = Binding->FromConn; - return RPC_S_OK; - } - } - - /* create a new connection */ - RPCRT4_CreateConnection(&NewConnection, Binding->server, Binding->Protseq, Binding->NetworkAddr, Binding->Endpoint, NULL, Binding); - *Connection = NewConnection; - status = RPCRT4_OpenConnection(NewConnection); - if (status != RPC_S_OK) { - return status; - } - - /* we need to send a binding packet if we are client. */ - if (!(*Connection)->server) { - RpcPktHdr *hdr; - DWORD count; - BYTE *response; - RpcPktHdr *response_hdr; - - TRACE("sending bind request to server\n"); - - hdr = RPCRT4_BuildBindHeader(NDR_LOCAL_DATA_REPRESENTATION, - RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, - InterfaceId, TransferSyntax); - - status = RPCRT4_Send(*Connection, hdr, NULL, 0); - if (status != RPC_S_OK) { - RPCRT4_DestroyConnection(*Connection); - return status; - } - - response = HeapAlloc(GetProcessHeap(), 0, RPC_MAX_PACKET_SIZE); - if (response == NULL) { - WARN("Can't allocate memory for binding response\n"); - RPCRT4_DestroyConnection(*Connection); - return E_OUTOFMEMORY; - } - - /* get a reply */ - if (!ReadFile(NewConnection->conn, response, RPC_MAX_PACKET_SIZE, &count, NULL)) { - WARN("ReadFile failed with error %ld\n", GetLastError()); - RPCRT4_DestroyConnection(*Connection); - return RPC_S_PROTOCOL_ERROR; - } - - if (count < sizeof(response_hdr->common)) { - WARN("received invalid header\n"); - RPCRT4_DestroyConnection(*Connection); - return RPC_S_PROTOCOL_ERROR; - } - - response_hdr = (RpcPktHdr*)response; - - if (response_hdr->common.rpc_ver != RPC_VER_MAJOR || - response_hdr->common.rpc_ver_minor != RPC_VER_MINOR || - response_hdr->common.ptype != PKT_BIND_ACK) { - WARN("invalid protocol version or rejection packet\n"); - RPCRT4_DestroyConnection(*Connection); - return RPC_S_PROTOCOL_ERROR; - } - - if (response_hdr->bind_ack.max_tsize < RPC_MIN_PACKET_SIZE) { - WARN("server doesn't allow large enough packets\n"); - RPCRT4_DestroyConnection(*Connection); - return RPC_S_PROTOCOL_ERROR; - } - - /* FIXME: do more checks? */ - - (*Connection)->MaxTransmissionSize = response_hdr->bind_ack.max_tsize; - (*Connection)->ActiveInterface = *InterfaceId; - } - - return RPC_S_OK; -} - -RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding, RpcConnection* Connection) -{ - TRACE("(Binding == ^%p)\n", Binding); - if (!Connection) return RPC_S_OK; - if (Binding->FromConn == Connection) return RPC_S_OK; - return RPCRT4_DestroyConnection(Connection); -} - -/* utility functions for string composing and parsing */ -static unsigned RPCRT4_strcopyA(LPSTR data, LPCSTR src) -{ - unsigned len = strlen(src); - memcpy(data, src, len*sizeof(CHAR)); - return len; -} - -static unsigned RPCRT4_strcopyW(LPWSTR data, LPCWSTR src) -{ - unsigned len = strlenW(src); - memcpy(data, src, len*sizeof(WCHAR)); - return len; -} - -static LPSTR RPCRT4_strconcatA(LPSTR dst, LPCSTR src) -{ - DWORD len = strlen(dst), slen = strlen(src); - LPSTR ndst = HeapReAlloc(GetProcessHeap(), 0, dst, (len+slen+2)*sizeof(CHAR)); - if (!ndst) - { - HeapFree(GetProcessHeap(), 0, dst); - return NULL; - } - ndst[len] = ','; - memcpy(ndst+len+1, src, slen+1); - return ndst; -} - -static LPWSTR RPCRT4_strconcatW(LPWSTR dst, LPCWSTR src) -{ - DWORD len = strlenW(dst), slen = strlenW(src); - LPWSTR ndst = HeapReAlloc(GetProcessHeap(), 0, dst, (len+slen+2)*sizeof(WCHAR)); - if (!ndst) - { - HeapFree(GetProcessHeap(), 0, dst); - return NULL; - } - ndst[len] = ','; - memcpy(ndst+len+1, src, (slen+1)*sizeof(WCHAR)); - return ndst; -} - - -/*********************************************************************** - * RpcStringBindingComposeA (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcStringBindingComposeA(unsigned char *ObjUuid, unsigned char *Protseq, - unsigned char *NetworkAddr, unsigned char *Endpoint, - unsigned char *Options, unsigned char** StringBinding ) -{ - DWORD len = 1; - LPSTR data; - - TRACE( "(%s,%s,%s,%s,%s,%p)\n", - debugstr_a( ObjUuid ), debugstr_a( Protseq ), - debugstr_a( NetworkAddr ), debugstr_a( Endpoint ), - debugstr_a( Options ), StringBinding ); - - if (ObjUuid && *ObjUuid) len += strlen(ObjUuid) + 1; - if (Protseq && *Protseq) len += strlen(Protseq) + 1; - if (NetworkAddr && *NetworkAddr) len += strlen(NetworkAddr); - if (Endpoint && *Endpoint) len += strlen(Endpoint) + 2; - if (Options && *Options) len += strlen(Options) + 2; - - data = HeapAlloc(GetProcessHeap(), 0, len); - *StringBinding = data; - - if (ObjUuid && *ObjUuid) { - data += RPCRT4_strcopyA(data, ObjUuid); - *data++ = '@'; - } - if (Protseq && *Protseq) { - data += RPCRT4_strcopyA(data, Protseq); - *data++ = ':'; - } - if (NetworkAddr && *NetworkAddr) - data += RPCRT4_strcopyA(data, NetworkAddr); - - if ((Endpoint && *Endpoint) || - (Options && *Options)) { - *data++ = '['; - if (Endpoint && *Endpoint) { - data += RPCRT4_strcopyA(data, Endpoint); - if (Options && *Options) *data++ = ','; - } - if (Options && *Options) { - data += RPCRT4_strcopyA(data, Options); - } - *data++ = ']'; - } - *data = 0; - - return RPC_S_OK; -} - -/*********************************************************************** - * RpcStringBindingComposeW (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcStringBindingComposeW( LPWSTR ObjUuid, LPWSTR Protseq, - LPWSTR NetworkAddr, LPWSTR Endpoint, - LPWSTR Options, LPWSTR* StringBinding ) -{ - DWORD len = 1; - LPWSTR data; - - TRACE("(%s,%s,%s,%s,%s,%p)\n", - debugstr_w( ObjUuid ), debugstr_w( Protseq ), - debugstr_w( NetworkAddr ), debugstr_w( Endpoint ), - debugstr_w( Options ), StringBinding); - - if (ObjUuid && *ObjUuid) len += strlenW(ObjUuid) + 1; - if (Protseq && *Protseq) len += strlenW(Protseq) + 1; - if (NetworkAddr && *NetworkAddr) len += strlenW(NetworkAddr); - if (Endpoint && *Endpoint) len += strlenW(Endpoint) + 2; - if (Options && *Options) len += strlenW(Options) + 2; - - data = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - *StringBinding = data; - - if (ObjUuid && *ObjUuid) { - data += RPCRT4_strcopyW(data, ObjUuid); - *data++ = '@'; - } - if (Protseq && *Protseq) { - data += RPCRT4_strcopyW(data, Protseq); - *data++ = ':'; - } - if (NetworkAddr && *NetworkAddr) { - data += RPCRT4_strcopyW(data, NetworkAddr); - } - if ((Endpoint && *Endpoint) || - (Options && *Options)) { - *data++ = '['; - if (Endpoint && *Endpoint) { - data += RPCRT4_strcopyW(data, Endpoint); - if (Options && *Options) *data++ = ','; - } - if (Options && *Options) { - data += RPCRT4_strcopyW(data, Options); - } - *data++ = ']'; - } - *data = 0; - - return RPC_S_OK; -} - - -/*********************************************************************** - * RpcStringBindingParseA (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcStringBindingParseA( unsigned char *StringBinding, unsigned char **ObjUuid, - unsigned char **Protseq, unsigned char **NetworkAddr, - unsigned char **Endpoint, unsigned char **Options) -{ - CHAR *data, *next; - static const char ep_opt[] = "endpoint="; - - TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_a(StringBinding), - ObjUuid, Protseq, NetworkAddr, Endpoint, Options); - - if (ObjUuid) *ObjUuid = NULL; - if (Protseq) *Protseq = NULL; - if (NetworkAddr) *NetworkAddr = NULL; - if (Endpoint) *Endpoint = NULL; - if (Options) *Options = NULL; - - data = StringBinding; - - next = strchr(data, '@'); - if (next) { - if (ObjUuid) *ObjUuid = RPCRT4_strndupA(data, next - data); - data = next+1; - } - - next = strchr(data, ':'); - if (next) { - if (Protseq) *Protseq = RPCRT4_strndupA(data, next - data); - data = next+1; - } - - next = strchr(data, '['); - if (next) { - CHAR *close, *opt; - - if (NetworkAddr) *NetworkAddr = RPCRT4_strndupA(data, next - data); - data = next+1; - close = strchr(data, ']'); - if (!close) goto fail; - - /* tokenize options */ - while (data < close) { - next = strchr(data, ','); - if (!next || next > close) next = close; - /* FIXME: this is kind of inefficient */ - opt = RPCRT4_strndupA(data, next - data); - data = next+1; - - /* parse option */ - next = strchr(opt, '='); - if (!next) { - /* not an option, must be an endpoint */ - if (*Endpoint) goto fail; - *Endpoint = opt; - } else { - if (strncmp(opt, ep_opt, strlen(ep_opt)) == 0) { - /* endpoint option */ - if (*Endpoint) goto fail; - *Endpoint = RPCRT4_strdupA(next+1); - HeapFree(GetProcessHeap(), 0, opt); - } else { - /* network option */ - if (*Options) { - /* FIXME: this is kind of inefficient */ - *Options = RPCRT4_strconcatA(*Options, opt); - HeapFree(GetProcessHeap(), 0, opt); - } else - *Options = opt; - } - } - } - - data = close+1; - if (*data) goto fail; - } - else if (NetworkAddr) - *NetworkAddr = RPCRT4_strdupA(data); - - return RPC_S_OK; - -fail: - if (ObjUuid) RpcStringFreeA((unsigned char**)ObjUuid); - if (Protseq) RpcStringFreeA((unsigned char**)Protseq); - if (NetworkAddr) RpcStringFreeA((unsigned char**)NetworkAddr); - if (Endpoint) RpcStringFreeA((unsigned char**)Endpoint); - if (Options) RpcStringFreeA((unsigned char**)Options); - return RPC_S_INVALID_STRING_BINDING; -} - -/*********************************************************************** - * RpcStringBindingParseW (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcStringBindingParseW( LPWSTR StringBinding, LPWSTR *ObjUuid, - LPWSTR *Protseq, LPWSTR *NetworkAddr, - LPWSTR *Endpoint, LPWSTR *Options) -{ - WCHAR *data, *next; - static const WCHAR ep_opt[] = {'e','n','d','p','o','i','n','t','=',0}; - - TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_w(StringBinding), - ObjUuid, Protseq, NetworkAddr, Endpoint, Options); - - if (ObjUuid) *ObjUuid = NULL; - if (Protseq) *Protseq = NULL; - if (NetworkAddr) *NetworkAddr = NULL; - if (Endpoint) *Endpoint = NULL; - if (Options) *Options = NULL; - - data = StringBinding; - - next = strchrW(data, '@'); - if (next) { - if (ObjUuid) *ObjUuid = RPCRT4_strndupW(data, next - data); - data = next+1; - } - - next = strchrW(data, ':'); - if (next) { - if (Protseq) *Protseq = RPCRT4_strndupW(data, next - data); - data = next+1; - } - - next = strchrW(data, '['); - if (next) { - WCHAR *close, *opt; - - if (NetworkAddr) *NetworkAddr = RPCRT4_strndupW(data, next - data); - data = next+1; - close = strchrW(data, ']'); - if (!close) goto fail; - - /* tokenize options */ - while (data < close) { - next = strchrW(data, ','); - if (!next || next > close) next = close; - /* FIXME: this is kind of inefficient */ - opt = RPCRT4_strndupW(data, next - data); - data = next+1; - - /* parse option */ - next = strchrW(opt, '='); - if (!next) { - /* not an option, must be an endpoint */ - if (*Endpoint) goto fail; - *Endpoint = opt; - } else { - if (strncmpW(opt, ep_opt, strlenW(ep_opt)) == 0) { - /* endpoint option */ - if (*Endpoint) goto fail; - *Endpoint = RPCRT4_strdupW(next+1); - HeapFree(GetProcessHeap(), 0, opt); - } else { - /* network option */ - if (*Options) { - /* FIXME: this is kind of inefficient */ - *Options = RPCRT4_strconcatW(*Options, opt); - HeapFree(GetProcessHeap(), 0, opt); - } else - *Options = opt; - } - } - } - - data = close+1; - if (*data) goto fail; - } else if (NetworkAddr) - *NetworkAddr = RPCRT4_strdupW(data); - - return RPC_S_OK; - -fail: - if (ObjUuid) RpcStringFreeW(ObjUuid); - if (Protseq) RpcStringFreeW(Protseq); - if (NetworkAddr) RpcStringFreeW(NetworkAddr); - if (Endpoint) RpcStringFreeW(Endpoint); - if (Options) RpcStringFreeW(Options); - return RPC_S_INVALID_STRING_BINDING; -} - -/*********************************************************************** - * RpcBindingFree (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcBindingFree( RPC_BINDING_HANDLE* Binding ) -{ - RPC_STATUS status; - TRACE("(%p) = %p\n", Binding, *Binding); - status = RPCRT4_DestroyBinding(*Binding); - if (status == RPC_S_OK) *Binding = 0; - return status; -} - -/*********************************************************************** - * RpcBindingVectorFree (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcBindingVectorFree( RPC_BINDING_VECTOR** BindingVector ) -{ - RPC_STATUS status; - unsigned long c; - - TRACE("(%p)\n", BindingVector); - for (c=0; c<(*BindingVector)->Count; c++) { - status = RpcBindingFree(&(*BindingVector)->BindingH[c]); - } - HeapFree(GetProcessHeap(), 0, *BindingVector); - *BindingVector = NULL; - return RPC_S_OK; -} - -/*********************************************************************** - * RpcBindingInqObject (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcBindingInqObject( RPC_BINDING_HANDLE Binding, UUID* ObjectUuid ) -{ - RpcBinding* bind = (RpcBinding*)Binding; - - TRACE("(%p,%p) = %s\n", Binding, ObjectUuid, debugstr_guid(&bind->ObjectUuid)); - memcpy(ObjectUuid, &bind->ObjectUuid, sizeof(UUID)); - return RPC_S_OK; -} - -/*********************************************************************** - * RpcBindingSetObject (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcBindingSetObject( RPC_BINDING_HANDLE Binding, UUID* ObjectUuid ) -{ - RpcBinding* bind = (RpcBinding*)Binding; - - TRACE("(%p,%s)\n", Binding, debugstr_guid(ObjectUuid)); - if (bind->server) return RPC_S_WRONG_KIND_OF_BINDING; - return RPCRT4_SetBindingObject(Binding, ObjectUuid); -} - -/*********************************************************************** - * RpcBindingFromStringBindingA (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcBindingFromStringBindingA( unsigned char *StringBinding, RPC_BINDING_HANDLE* Binding ) -{ - RPC_STATUS ret; - RpcBinding* bind = NULL; - unsigned char *ObjectUuid, *Protseq, *NetworkAddr, *Endpoint, *Options; - UUID Uuid; - - TRACE("(%s,%p)\n", debugstr_a(StringBinding), Binding); - - ret = RpcStringBindingParseA(StringBinding, &ObjectUuid, &Protseq, - &NetworkAddr, &Endpoint, &Options); - if (ret != RPC_S_OK) return ret; - - ret = UuidFromStringA(ObjectUuid, &Uuid); - - if (ret == RPC_S_OK) - ret = RPCRT4_CreateBindingA(&bind, FALSE, Protseq); - if (ret == RPC_S_OK) - ret = RPCRT4_SetBindingObject(bind, &Uuid); - if (ret == RPC_S_OK) - ret = RPCRT4_CompleteBindingA(bind, NetworkAddr, Endpoint, Options); - - RpcStringFreeA((unsigned char**)&Options); - RpcStringFreeA((unsigned char**)&Endpoint); - RpcStringFreeA((unsigned char**)&NetworkAddr); - RpcStringFreeA((unsigned char**)&Protseq); - RpcStringFreeA((unsigned char**)&ObjectUuid); - - if (ret == RPC_S_OK) - *Binding = (RPC_BINDING_HANDLE)bind; - else - RPCRT4_DestroyBinding(bind); - - return ret; -} - -/*********************************************************************** - * RpcBindingFromStringBindingW (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcBindingFromStringBindingW( LPWSTR StringBinding, RPC_BINDING_HANDLE* Binding ) -{ - RPC_STATUS ret; - RpcBinding* bind = NULL; - LPWSTR ObjectUuid, Protseq, NetworkAddr, Endpoint, Options; - UUID Uuid; - - TRACE("(%s,%p)\n", debugstr_w(StringBinding), Binding); - - ret = RpcStringBindingParseW(StringBinding, &ObjectUuid, &Protseq, - &NetworkAddr, &Endpoint, &Options); - if (ret != RPC_S_OK) return ret; - - ret = UuidFromStringW(ObjectUuid, &Uuid); - - if (ret == RPC_S_OK) - ret = RPCRT4_CreateBindingW(&bind, FALSE, Protseq); - if (ret == RPC_S_OK) - ret = RPCRT4_SetBindingObject(bind, &Uuid); - if (ret == RPC_S_OK) - ret = RPCRT4_CompleteBindingW(bind, NetworkAddr, Endpoint, Options); - - RpcStringFreeW(&Options); - RpcStringFreeW(&Endpoint); - RpcStringFreeW(&NetworkAddr); - RpcStringFreeW(&Protseq); - RpcStringFreeW(&ObjectUuid); - - if (ret == RPC_S_OK) - *Binding = (RPC_BINDING_HANDLE)bind; - else - RPCRT4_DestroyBinding(bind); - - return ret; -} - -/*********************************************************************** - * RpcBindingToStringBindingA (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcBindingToStringBindingA( RPC_BINDING_HANDLE Binding, unsigned char** StringBinding ) -{ - RPC_STATUS ret; - RpcBinding* bind = (RpcBinding*)Binding; - LPSTR ObjectUuid; - - TRACE("(%p,%p)\n", Binding, StringBinding); - - ret = UuidToStringA(&bind->ObjectUuid, (unsigned char**)&ObjectUuid); - if (ret != RPC_S_OK) return ret; - - ret = RpcStringBindingComposeA(ObjectUuid, bind->Protseq, bind->NetworkAddr, - bind->Endpoint, NULL, StringBinding); - - RpcStringFreeA((unsigned char**)&ObjectUuid); - - return ret; -} - -/*********************************************************************** - * RpcBindingToStringBindingW (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcBindingToStringBindingW( RPC_BINDING_HANDLE Binding, unsigned short** StringBinding ) -{ - RPC_STATUS ret; - unsigned char *str = NULL; - TRACE("(%p,%p)\n", Binding, StringBinding); - ret = RpcBindingToStringBindingA(Binding, &str); - *StringBinding = RPCRT4_strdupAtoW(str); - RpcStringFreeA((unsigned char**)&str); - return ret; -} - -/*********************************************************************** - * I_RpcBindingSetAsync (RPCRT4.@) - * NOTES - * Exists in win9x and winNT, but with different number of arguments - * (9x version has 3 arguments, NT has 2). - */ -RPC_STATUS WINAPI I_RpcBindingSetAsync( RPC_BINDING_HANDLE Binding, RPC_BLOCKING_FN BlockingFn) -{ - RpcBinding* bind = (RpcBinding*)Binding; - - TRACE( "(%p,%p): stub\n", Binding, BlockingFn ); - - bind->BlockingFn = BlockingFn; - - return RPC_S_OK; -} - -/*********************************************************************** - * RpcNetworkIsProtseqValidA (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(unsigned char *protseq) { - UNICODE_STRING protseqW; - - if (!protseq) return RPC_S_INVALID_RPC_PROTSEQ; /* ? */ - - if (RtlCreateUnicodeStringFromAsciiz(&protseqW, protseq)) { - RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer); - RtlFreeUnicodeString(&protseqW); - return ret; - } else return RPC_S_OUT_OF_MEMORY; -} - -/*********************************************************************** - * RpcNetworkIsProtseqValidW (RPCRT4.@) - * - * Checks if the given protocol sequence is known by the RPC system. - * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED. - * - * We currently support: - * ncalrpc local-only rpc over LPC (LPC is not really used) - * ncacn_np rpc over named pipes - */ -RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(LPWSTR protseq) { - static const WCHAR protseqsW[][15] = { - {'n','c','a','l','r','p','c',0}, - {'n','c','a','c','n','_','n','p',0} - }; - static const int count = sizeof(protseqsW) / sizeof(protseqsW[0]); - int i; - - if (!protseq) return RPC_S_INVALID_RPC_PROTSEQ; /* ? */ - - for (i = 0; i < count; i++) { - if (!strcmpW(protseq, protseqsW[i])) return RPC_S_OK; - } - - FIXME("Unknown protseq %s - we probably need to implement it one day\n", debugstr_w(protseq)); - return RPC_S_PROTSEQ_NOT_SUPPORTED; -} - -/*********************************************************************** - * RpcImpersonateClient (RPCRT4.@) - * - * Impersonates the client connected via a binding handle so that security - * checks are done in the context of the client. - * - * PARAMS - * BindingHandle [I] Handle to the binding to the client. - * - * RETURNS - * Success: RPS_S_OK. - * Failure: RPC_STATUS value. - * - * NOTES - * - * If BindingHandle is NULL then the function impersonates the client - * connected to the binding handle of the current thread. - */ -RPC_STATUS WINAPI RpcImpersonateClient(RPC_BINDING_HANDLE BindingHandle) -{ - FIXME("(%p): stub\n", BindingHandle); - return RPC_S_OK; -} - -/*********************************************************************** - * RpcRevertToSelfEx (RPCRT4.@) - * - * Stops impersonating the client connected to the binding handle so that security - * checks are no longer done in the context of the client. - * - * PARAMS - * BindingHandle [I] Handle to the binding to the client. - * - * RETURNS - * Success: RPS_S_OK. - * Failure: RPC_STATUS value. - * - * NOTES - * - * If BindingHandle is NULL then the function stops impersonating the client - * connected to the binding handle of the current thread. - */ -RPC_STATUS WINAPI RpcRevertToSelfEx(RPC_BINDING_HANDLE BindingHandle) -{ - FIXME("(%p): stub\n", BindingHandle); - return RPC_S_OK; -} +/* + * RPC binding API + * + * Copyright 2001 Ove KÃ¥ven, TransGaming Technologies + * Copyright 2003 Mike Hearn + * Copyright 2004 Filip Navara + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * TODO: + * - a whole lot + */ + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winerror.h" +#include "winreg.h" +#include "winternl.h" +#include "wine/unicode.h" + +#include "rpc.h" +#include "rpcndr.h" + +#include "wine/debug.h" + +#include "rpc_binding.h" +#include "rpc_message.h" + +WINE_DEFAULT_DEBUG_CHANNEL(rpc); + +LPSTR RPCRT4_strndupA(LPCSTR src, INT slen) +{ + DWORD len; + LPSTR s; + if (!src) return NULL; + if (slen == -1) slen = strlen(src); + len = slen; + s = HeapAlloc(GetProcessHeap(), 0, len+1); + memcpy(s, src, len); + s[len] = 0; + return s; +} + +LPSTR RPCRT4_strdupWtoA(LPWSTR src) +{ + DWORD len; + LPSTR s; + if (!src) return NULL; + len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL); + s = HeapAlloc(GetProcessHeap(), 0, len); + WideCharToMultiByte(CP_ACP, 0, src, -1, s, len, NULL, NULL); + return s; +} + +LPWSTR RPCRT4_strdupAtoW(LPSTR src) +{ + DWORD len; + LPWSTR s; + if (!src) return NULL; + len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0); + s = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, src, -1, s, len); + return s; +} + +LPWSTR RPCRT4_strndupW(LPWSTR src, INT slen) +{ + DWORD len; + LPWSTR s; + if (!src) return NULL; + if (slen == -1) slen = strlenW(src); + len = slen; + s = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR)); + memcpy(s, src, len*sizeof(WCHAR)); + s[len] = 0; + return s; +} + +void RPCRT4_strfree(LPSTR src) +{ + HeapFree(GetProcessHeap(), 0, src); +} + +RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPSTR Protseq, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions, RpcBinding* Binding) +{ + RpcConnection* NewConnection; + + NewConnection = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection)); + NewConnection->server = server; + NewConnection->Protseq = RPCRT4_strdupA(Protseq); + NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr); + NewConnection->Endpoint = RPCRT4_strdupA(Endpoint); + NewConnection->Used = Binding; + NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE; + + TRACE("connection: %p\n", NewConnection); + *Connection = NewConnection; + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection) +{ + TRACE("connection: %p\n", Connection); + + RPCRT4_CloseConnection(Connection); + RPCRT4_strfree(Connection->Endpoint); + RPCRT4_strfree(Connection->NetworkAddr); + RPCRT4_strfree(Connection->Protseq); + HeapFree(GetProcessHeap(), 0, Connection); + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection) +{ + TRACE("(Connection == ^%p)\n", Connection); + if (!Connection->conn) { + if (Connection->server) { /* server */ + /* protseq=ncalrpc: supposed to use NT LPC ports, + * but we'll implement it with named pipes for now */ + if (strcmp(Connection->Protseq, "ncalrpc") == 0) { + static LPCSTR prefix = "\\\\.\\pipe\\lrpc\\"; + LPSTR pname; + pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1); + strcat(strcpy(pname, prefix), Connection->Endpoint); + TRACE("listening on %s\n", pname); + Connection->conn = CreateNamedPipeA(pname, PROFILE_SERVER | PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES, + RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL); + HeapFree(GetProcessHeap(), 0, pname); + memset(&Connection->ovl, 0, sizeof(Connection->ovl)); + Connection->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + Connection->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + if (!ConnectNamedPipe(Connection->conn, &Connection->ovl[0])) { + WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError()); + if (GetLastError() == ERROR_PIPE_CONNECTED) { + SetEvent(Connection->ovl[0].hEvent); + return RPC_S_OK; + } else if (GetLastError() == ERROR_IO_PENDING) { + return RPC_S_OK; + } + return RPC_S_SERVER_UNAVAILABLE; + } + } + /* protseq=ncacn_np: named pipes */ + else if (strcmp(Connection->Protseq, "ncacn_np") == 0) { + static LPCSTR prefix = "\\\\."; + LPSTR pname; + pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1); + strcat(strcpy(pname, prefix), Connection->Endpoint); + TRACE("listening on %s\n", pname); + Connection->conn = CreateNamedPipeA(pname, PROFILE_SERVER | PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, + RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL); + HeapFree(GetProcessHeap(), 0, pname); + memset(&Connection->ovl, 0, sizeof(Connection->ovl)); + Connection->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + Connection->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + if (!ConnectNamedPipe(Connection->conn, &Connection->ovl[0])) { + if (GetLastError() == ERROR_PIPE_CONNECTED) { + SetEvent(Connection->ovl[0].hEvent); + return RPC_S_OK; + } else if (GetLastError() == ERROR_IO_PENDING) { + return RPC_S_OK; + } + WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError()); + return RPC_S_SERVER_UNAVAILABLE; + } + } + else { + ERR("protseq %s not supported\n", Connection->Protseq); + return RPC_S_PROTSEQ_NOT_SUPPORTED; + } + } + else { /* client */ + /* protseq=ncalrpc: supposed to use NT LPC ports, + * but we'll implement it with named pipes for now */ + if (strcmp(Connection->Protseq, "ncalrpc") == 0) { + static LPCSTR prefix = "\\\\.\\pipe\\lrpc\\"; + LPSTR pname; + HANDLE conn; + DWORD err; + DWORD dwMode; + + pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1); + strcat(strcpy(pname, prefix), Connection->Endpoint); + TRACE("connecting to %s\n", pname); + while (TRUE) { + if (WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) { + conn = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, 0, 0); + if (conn != INVALID_HANDLE_VALUE) break; + err = GetLastError(); + if (err == ERROR_PIPE_BUSY) continue; + TRACE("connection failed, error=%lx\n", err); + HeapFree(GetProcessHeap(), 0, pname); + return RPC_S_SERVER_TOO_BUSY; + } else { + err = GetLastError(); + WARN("connection failed, error=%lx\n", err); + HeapFree(GetProcessHeap(), 0, pname); + return RPC_S_SERVER_UNAVAILABLE; + } + } + + /* success */ + HeapFree(GetProcessHeap(), 0, pname); + memset(&Connection->ovl, 0, sizeof(Connection->ovl)); + /* pipe is connected; change to message-read mode. */ + dwMode = PIPE_READMODE_MESSAGE; + SetNamedPipeHandleState(conn, &dwMode, NULL, NULL); + Connection->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + Connection->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + Connection->conn = conn; + } + /* protseq=ncacn_np: named pipes */ + else if (strcmp(Connection->Protseq, "ncacn_np") == 0) { + static LPCSTR prefix = "\\\\."; + LPSTR pname; + HANDLE conn; + DWORD err; + DWORD dwMode; + + pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1); + strcat(strcpy(pname, prefix), Connection->Endpoint); + TRACE("connecting to %s\n", pname); + conn = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, 0, 0); + if (conn == INVALID_HANDLE_VALUE) { + err = GetLastError(); + /* we don't need to handle ERROR_PIPE_BUSY here, + * the doc says that it is returned to the app */ + WARN("connection failed, error=%lx\n", err); + HeapFree(GetProcessHeap(), 0, pname); + if (err == ERROR_PIPE_BUSY) + return RPC_S_SERVER_TOO_BUSY; + else + return RPC_S_SERVER_UNAVAILABLE; + } + + /* success */ + HeapFree(GetProcessHeap(), 0, pname); + memset(&Connection->ovl, 0, sizeof(Connection->ovl)); + /* pipe is connected; change to message-read mode. */ + dwMode = PIPE_READMODE_MESSAGE; + SetNamedPipeHandleState(conn, &dwMode, NULL, NULL); + Connection->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + Connection->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + Connection->conn = conn; + } else { + ERR("protseq %s not supported\n", Connection->Protseq); + return RPC_S_PROTSEQ_NOT_SUPPORTED; + } + } + } + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection) +{ + TRACE("(Connection == ^%p)\n", Connection); + if (Connection->conn) { + CancelIo(Connection->conn); + CloseHandle(Connection->conn); + Connection->conn = 0; + } + if (Connection->ovl[0].hEvent) { + CloseHandle(Connection->ovl[0].hEvent); + Connection->ovl[0].hEvent = 0; + } + if (Connection->ovl[1].hEvent) { + CloseHandle(Connection->ovl[1].hEvent); + Connection->ovl[1].hEvent = 0; + } + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection) +{ + RpcConnection* NewConnection; + RPC_STATUS err = RPCRT4_CreateConnection(&NewConnection, OldConnection->server, OldConnection->Protseq, + OldConnection->NetworkAddr, OldConnection->Endpoint, NULL, NULL); + if (err == RPC_S_OK) { + /* because of the way named pipes work, we'll transfer the connected pipe + * to the child, then reopen the server binding to continue listening */ + NewConnection->conn = OldConnection->conn; + NewConnection->ovl[0] = OldConnection->ovl[0]; + NewConnection->ovl[1] = OldConnection->ovl[1]; + OldConnection->conn = 0; + memset(&OldConnection->ovl, 0, sizeof(OldConnection->ovl)); + *Connection = NewConnection; + RPCRT4_OpenConnection(OldConnection); + } + return err; +} + +RPC_STATUS RPCRT4_AllocBinding(RpcBinding** Binding, BOOL server) +{ + RpcBinding* NewBinding; + + NewBinding = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcBinding)); + NewBinding->refs = 1; + NewBinding->server = server; + + *Binding = NewBinding; + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_CreateBindingA(RpcBinding** Binding, BOOL server, LPSTR Protseq) +{ + RpcBinding* NewBinding; + + RPCRT4_AllocBinding(&NewBinding, server); + NewBinding->Protseq = RPCRT4_strdupA(Protseq); + + TRACE("binding: %p\n", NewBinding); + *Binding = NewBinding; + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_CreateBindingW(RpcBinding** Binding, BOOL server, LPWSTR Protseq) +{ + RpcBinding* NewBinding; + + RPCRT4_AllocBinding(&NewBinding, server); + NewBinding->Protseq = RPCRT4_strdupWtoA(Protseq); + + TRACE("binding: %p\n", NewBinding); + *Binding = NewBinding; + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_CompleteBindingA(RpcBinding* Binding, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions) +{ + TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding, + debugstr_a(NetworkAddr), debugstr_a(Endpoint), debugstr_a(NetworkOptions)); + + RPCRT4_strfree(Binding->NetworkAddr); + Binding->NetworkAddr = RPCRT4_strdupA(NetworkAddr); + RPCRT4_strfree(Binding->Endpoint); + if (Endpoint) { + Binding->Endpoint = RPCRT4_strdupA(Endpoint); + } else { + Binding->Endpoint = RPCRT4_strdupA(""); + } + if (!Binding->Endpoint) ERR("out of memory?\n"); + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_CompleteBindingW(RpcBinding* Binding, LPWSTR NetworkAddr, LPWSTR Endpoint, LPWSTR NetworkOptions) +{ + TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding, + debugstr_w(NetworkAddr), debugstr_w(Endpoint), debugstr_w(NetworkOptions)); + + RPCRT4_strfree(Binding->NetworkAddr); + Binding->NetworkAddr = RPCRT4_strdupWtoA(NetworkAddr); + RPCRT4_strfree(Binding->Endpoint); + if (Endpoint) { + Binding->Endpoint = RPCRT4_strdupWtoA(Endpoint); + } else { + Binding->Endpoint = RPCRT4_strdupA(""); + } + if (!Binding->Endpoint) ERR("out of memory?\n"); + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_ResolveBinding(RpcBinding* Binding, LPSTR Endpoint) +{ + TRACE("(RpcBinding == ^%p, EndPoint == \"%s\"\n", Binding, Endpoint); + + RPCRT4_strfree(Binding->Endpoint); + Binding->Endpoint = RPCRT4_strdupA(Endpoint); + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_SetBindingObject(RpcBinding* Binding, UUID* ObjectUuid) +{ + TRACE("(*RpcBinding == ^%p, UUID == %s)\n", Binding, debugstr_guid(ObjectUuid)); + if (ObjectUuid) memcpy(&Binding->ObjectUuid, ObjectUuid, sizeof(UUID)); + else UuidCreateNil(&Binding->ObjectUuid); + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_MakeBinding(RpcBinding** Binding, RpcConnection* Connection) +{ + RpcBinding* NewBinding; + TRACE("(RpcBinding == ^%p, Connection == ^%p)\n", Binding, Connection); + + RPCRT4_AllocBinding(&NewBinding, Connection->server); + NewBinding->Protseq = RPCRT4_strdupA(Connection->Protseq); + NewBinding->NetworkAddr = RPCRT4_strdupA(Connection->NetworkAddr); + NewBinding->Endpoint = RPCRT4_strdupA(Connection->Endpoint); + NewBinding->FromConn = Connection; + + TRACE("binding: %p\n", NewBinding); + *Binding = NewBinding; + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_ExportBinding(RpcBinding** Binding, RpcBinding* OldBinding) +{ + InterlockedIncrement(&OldBinding->refs); + *Binding = OldBinding; + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_DestroyBinding(RpcBinding* Binding) +{ + if (InterlockedDecrement(&Binding->refs)) + return RPC_S_OK; + + TRACE("binding: %p\n", Binding); + /* FIXME: release connections */ + RPCRT4_strfree(Binding->Endpoint); + RPCRT4_strfree(Binding->NetworkAddr); + RPCRT4_strfree(Binding->Protseq); + HeapFree(GetProcessHeap(), 0, Binding); + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection, + PRPC_SYNTAX_IDENTIFIER TransferSyntax, + PRPC_SYNTAX_IDENTIFIER InterfaceId) +{ + RpcConnection* NewConnection; + RPC_STATUS status; + + TRACE("(Binding == ^%p)\n", Binding); + + /* if we try to bind a new interface and the connection is already opened, + * close the current connection and create a new with the new binding. */ + if (!Binding->server && Binding->FromConn && + memcmp(&Binding->FromConn->ActiveInterface, InterfaceId, + sizeof(RPC_SYNTAX_IDENTIFIER))) { + + TRACE("releasing pre-existing connection\n"); + RPCRT4_DestroyConnection(Binding->FromConn); + Binding->FromConn = NULL; + } else { + /* we already have a connection with acceptable binding, so use it */ + if (Binding->FromConn) { + *Connection = Binding->FromConn; + return RPC_S_OK; + } + } + + /* create a new connection */ + RPCRT4_CreateConnection(&NewConnection, Binding->server, Binding->Protseq, Binding->NetworkAddr, Binding->Endpoint, NULL, Binding); + *Connection = NewConnection; + status = RPCRT4_OpenConnection(NewConnection); + if (status != RPC_S_OK) { + return status; + } + + /* we need to send a binding packet if we are client. */ + if (!(*Connection)->server) { + RpcPktHdr *hdr; + DWORD count; + BYTE *response; + RpcPktHdr *response_hdr; + + TRACE("sending bind request to server\n"); + + hdr = RPCRT4_BuildBindHeader(NDR_LOCAL_DATA_REPRESENTATION, + RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, + InterfaceId, TransferSyntax); + + status = RPCRT4_Send(*Connection, hdr, NULL, 0); + if (status != RPC_S_OK) { + RPCRT4_DestroyConnection(*Connection); + return status; + } + + response = HeapAlloc(GetProcessHeap(), 0, RPC_MAX_PACKET_SIZE); + if (response == NULL) { + WARN("Can't allocate memory for binding response\n"); + RPCRT4_DestroyConnection(*Connection); + return E_OUTOFMEMORY; + } + + /* get a reply */ + if (!ReadFile(NewConnection->conn, response, RPC_MAX_PACKET_SIZE, &count, NULL)) { + WARN("ReadFile failed with error %ld\n", GetLastError()); + RPCRT4_DestroyConnection(*Connection); + return RPC_S_PROTOCOL_ERROR; + } + + if (count < sizeof(response_hdr->common)) { + WARN("received invalid header\n"); + RPCRT4_DestroyConnection(*Connection); + return RPC_S_PROTOCOL_ERROR; + } + + response_hdr = (RpcPktHdr*)response; + + if (response_hdr->common.rpc_ver != RPC_VER_MAJOR || + response_hdr->common.rpc_ver_minor != RPC_VER_MINOR || + response_hdr->common.ptype != PKT_BIND_ACK) { + WARN("invalid protocol version or rejection packet\n"); + RPCRT4_DestroyConnection(*Connection); + return RPC_S_PROTOCOL_ERROR; + } + + if (response_hdr->bind_ack.max_tsize < RPC_MIN_PACKET_SIZE) { + WARN("server doesn't allow large enough packets\n"); + RPCRT4_DestroyConnection(*Connection); + return RPC_S_PROTOCOL_ERROR; + } + + /* FIXME: do more checks? */ + + (*Connection)->MaxTransmissionSize = response_hdr->bind_ack.max_tsize; + (*Connection)->ActiveInterface = *InterfaceId; + } + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding, RpcConnection* Connection) +{ + TRACE("(Binding == ^%p)\n", Binding); + if (!Connection) return RPC_S_OK; + if (Binding->FromConn == Connection) return RPC_S_OK; + return RPCRT4_DestroyConnection(Connection); +} + +/* utility functions for string composing and parsing */ +static unsigned RPCRT4_strcopyA(LPSTR data, LPCSTR src) +{ + unsigned len = strlen(src); + memcpy(data, src, len*sizeof(CHAR)); + return len; +} + +static unsigned RPCRT4_strcopyW(LPWSTR data, LPCWSTR src) +{ + unsigned len = strlenW(src); + memcpy(data, src, len*sizeof(WCHAR)); + return len; +} + +static LPSTR RPCRT4_strconcatA(LPSTR dst, LPCSTR src) +{ + DWORD len = strlen(dst), slen = strlen(src); + LPSTR ndst = HeapReAlloc(GetProcessHeap(), 0, dst, (len+slen+2)*sizeof(CHAR)); + if (!ndst) + { + HeapFree(GetProcessHeap(), 0, dst); + return NULL; + } + ndst[len] = ','; + memcpy(ndst+len+1, src, slen+1); + return ndst; +} + +static LPWSTR RPCRT4_strconcatW(LPWSTR dst, LPCWSTR src) +{ + DWORD len = strlenW(dst), slen = strlenW(src); + LPWSTR ndst = HeapReAlloc(GetProcessHeap(), 0, dst, (len+slen+2)*sizeof(WCHAR)); + if (!ndst) + { + HeapFree(GetProcessHeap(), 0, dst); + return NULL; + } + ndst[len] = ','; + memcpy(ndst+len+1, src, (slen+1)*sizeof(WCHAR)); + return ndst; +} + + +/*********************************************************************** + * RpcStringBindingComposeA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcStringBindingComposeA(unsigned char *ObjUuid, unsigned char *Protseq, + unsigned char *NetworkAddr, unsigned char *Endpoint, + unsigned char *Options, unsigned char** StringBinding ) +{ + DWORD len = 1; + LPSTR data; + + TRACE( "(%s,%s,%s,%s,%s,%p)\n", + debugstr_a( ObjUuid ), debugstr_a( Protseq ), + debugstr_a( NetworkAddr ), debugstr_a( Endpoint ), + debugstr_a( Options ), StringBinding ); + + if (ObjUuid && *ObjUuid) len += strlen(ObjUuid) + 1; + if (Protseq && *Protseq) len += strlen(Protseq) + 1; + if (NetworkAddr && *NetworkAddr) len += strlen(NetworkAddr); + if (Endpoint && *Endpoint) len += strlen(Endpoint) + 2; + if (Options && *Options) len += strlen(Options) + 2; + + data = HeapAlloc(GetProcessHeap(), 0, len); + *StringBinding = data; + + if (ObjUuid && *ObjUuid) { + data += RPCRT4_strcopyA(data, ObjUuid); + *data++ = '@'; + } + if (Protseq && *Protseq) { + data += RPCRT4_strcopyA(data, Protseq); + *data++ = ':'; + } + if (NetworkAddr && *NetworkAddr) + data += RPCRT4_strcopyA(data, NetworkAddr); + + if ((Endpoint && *Endpoint) || + (Options && *Options)) { + *data++ = '['; + if (Endpoint && *Endpoint) { + data += RPCRT4_strcopyA(data, Endpoint); + if (Options && *Options) *data++ = ','; + } + if (Options && *Options) { + data += RPCRT4_strcopyA(data, Options); + } + *data++ = ']'; + } + *data = 0; + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcStringBindingComposeW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcStringBindingComposeW( LPWSTR ObjUuid, LPWSTR Protseq, + LPWSTR NetworkAddr, LPWSTR Endpoint, + LPWSTR Options, LPWSTR* StringBinding ) +{ + DWORD len = 1; + LPWSTR data; + + TRACE("(%s,%s,%s,%s,%s,%p)\n", + debugstr_w( ObjUuid ), debugstr_w( Protseq ), + debugstr_w( NetworkAddr ), debugstr_w( Endpoint ), + debugstr_w( Options ), StringBinding); + + if (ObjUuid && *ObjUuid) len += strlenW(ObjUuid) + 1; + if (Protseq && *Protseq) len += strlenW(Protseq) + 1; + if (NetworkAddr && *NetworkAddr) len += strlenW(NetworkAddr); + if (Endpoint && *Endpoint) len += strlenW(Endpoint) + 2; + if (Options && *Options) len += strlenW(Options) + 2; + + data = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); + *StringBinding = data; + + if (ObjUuid && *ObjUuid) { + data += RPCRT4_strcopyW(data, ObjUuid); + *data++ = '@'; + } + if (Protseq && *Protseq) { + data += RPCRT4_strcopyW(data, Protseq); + *data++ = ':'; + } + if (NetworkAddr && *NetworkAddr) { + data += RPCRT4_strcopyW(data, NetworkAddr); + } + if ((Endpoint && *Endpoint) || + (Options && *Options)) { + *data++ = '['; + if (Endpoint && *Endpoint) { + data += RPCRT4_strcopyW(data, Endpoint); + if (Options && *Options) *data++ = ','; + } + if (Options && *Options) { + data += RPCRT4_strcopyW(data, Options); + } + *data++ = ']'; + } + *data = 0; + + return RPC_S_OK; +} + + +/*********************************************************************** + * RpcStringBindingParseA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcStringBindingParseA( unsigned char *StringBinding, unsigned char **ObjUuid, + unsigned char **Protseq, unsigned char **NetworkAddr, + unsigned char **Endpoint, unsigned char **Options) +{ + CHAR *data, *next; + static const char ep_opt[] = "endpoint="; + + TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_a(StringBinding), + ObjUuid, Protseq, NetworkAddr, Endpoint, Options); + + if (ObjUuid) *ObjUuid = NULL; + if (Protseq) *Protseq = NULL; + if (NetworkAddr) *NetworkAddr = NULL; + if (Endpoint) *Endpoint = NULL; + if (Options) *Options = NULL; + + data = StringBinding; + + next = strchr(data, '@'); + if (next) { + if (ObjUuid) *ObjUuid = RPCRT4_strndupA(data, next - data); + data = next+1; + } + + next = strchr(data, ':'); + if (next) { + if (Protseq) *Protseq = RPCRT4_strndupA(data, next - data); + data = next+1; + } + + next = strchr(data, '['); + if (next) { + CHAR *close, *opt; + + if (NetworkAddr) *NetworkAddr = RPCRT4_strndupA(data, next - data); + data = next+1; + close = strchr(data, ']'); + if (!close) goto fail; + + /* tokenize options */ + while (data < close) { + next = strchr(data, ','); + if (!next || next > close) next = close; + /* FIXME: this is kind of inefficient */ + opt = RPCRT4_strndupA(data, next - data); + data = next+1; + + /* parse option */ + next = strchr(opt, '='); + if (!next) { + /* not an option, must be an endpoint */ + if (*Endpoint) goto fail; + *Endpoint = opt; + } else { + if (strncmp(opt, ep_opt, strlen(ep_opt)) == 0) { + /* endpoint option */ + if (*Endpoint) goto fail; + *Endpoint = RPCRT4_strdupA(next+1); + HeapFree(GetProcessHeap(), 0, opt); + } else { + /* network option */ + if (*Options) { + /* FIXME: this is kind of inefficient */ + *Options = RPCRT4_strconcatA(*Options, opt); + HeapFree(GetProcessHeap(), 0, opt); + } else + *Options = opt; + } + } + } + + data = close+1; + if (*data) goto fail; + } + else if (NetworkAddr) + *NetworkAddr = RPCRT4_strdupA(data); + + return RPC_S_OK; + +fail: + if (ObjUuid) RpcStringFreeA((unsigned char**)ObjUuid); + if (Protseq) RpcStringFreeA((unsigned char**)Protseq); + if (NetworkAddr) RpcStringFreeA((unsigned char**)NetworkAddr); + if (Endpoint) RpcStringFreeA((unsigned char**)Endpoint); + if (Options) RpcStringFreeA((unsigned char**)Options); + return RPC_S_INVALID_STRING_BINDING; +} + +/*********************************************************************** + * RpcStringBindingParseW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcStringBindingParseW( LPWSTR StringBinding, LPWSTR *ObjUuid, + LPWSTR *Protseq, LPWSTR *NetworkAddr, + LPWSTR *Endpoint, LPWSTR *Options) +{ + WCHAR *data, *next; + static const WCHAR ep_opt[] = {'e','n','d','p','o','i','n','t','=',0}; + + TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_w(StringBinding), + ObjUuid, Protseq, NetworkAddr, Endpoint, Options); + + if (ObjUuid) *ObjUuid = NULL; + if (Protseq) *Protseq = NULL; + if (NetworkAddr) *NetworkAddr = NULL; + if (Endpoint) *Endpoint = NULL; + if (Options) *Options = NULL; + + data = StringBinding; + + next = strchrW(data, '@'); + if (next) { + if (ObjUuid) *ObjUuid = RPCRT4_strndupW(data, next - data); + data = next+1; + } + + next = strchrW(data, ':'); + if (next) { + if (Protseq) *Protseq = RPCRT4_strndupW(data, next - data); + data = next+1; + } + + next = strchrW(data, '['); + if (next) { + WCHAR *close, *opt; + + if (NetworkAddr) *NetworkAddr = RPCRT4_strndupW(data, next - data); + data = next+1; + close = strchrW(data, ']'); + if (!close) goto fail; + + /* tokenize options */ + while (data < close) { + next = strchrW(data, ','); + if (!next || next > close) next = close; + /* FIXME: this is kind of inefficient */ + opt = RPCRT4_strndupW(data, next - data); + data = next+1; + + /* parse option */ + next = strchrW(opt, '='); + if (!next) { + /* not an option, must be an endpoint */ + if (*Endpoint) goto fail; + *Endpoint = opt; + } else { + if (strncmpW(opt, ep_opt, strlenW(ep_opt)) == 0) { + /* endpoint option */ + if (*Endpoint) goto fail; + *Endpoint = RPCRT4_strdupW(next+1); + HeapFree(GetProcessHeap(), 0, opt); + } else { + /* network option */ + if (*Options) { + /* FIXME: this is kind of inefficient */ + *Options = RPCRT4_strconcatW(*Options, opt); + HeapFree(GetProcessHeap(), 0, opt); + } else + *Options = opt; + } + } + } + + data = close+1; + if (*data) goto fail; + } else if (NetworkAddr) + *NetworkAddr = RPCRT4_strdupW(data); + + return RPC_S_OK; + +fail: + if (ObjUuid) RpcStringFreeW(ObjUuid); + if (Protseq) RpcStringFreeW(Protseq); + if (NetworkAddr) RpcStringFreeW(NetworkAddr); + if (Endpoint) RpcStringFreeW(Endpoint); + if (Options) RpcStringFreeW(Options); + return RPC_S_INVALID_STRING_BINDING; +} + +/*********************************************************************** + * RpcBindingFree (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingFree( RPC_BINDING_HANDLE* Binding ) +{ + RPC_STATUS status; + TRACE("(%p) = %p\n", Binding, *Binding); + status = RPCRT4_DestroyBinding(*Binding); + if (status == RPC_S_OK) *Binding = 0; + return status; +} + +/*********************************************************************** + * RpcBindingVectorFree (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingVectorFree( RPC_BINDING_VECTOR** BindingVector ) +{ + RPC_STATUS status; + unsigned long c; + + TRACE("(%p)\n", BindingVector); + for (c=0; c<(*BindingVector)->Count; c++) { + status = RpcBindingFree(&(*BindingVector)->BindingH[c]); + } + HeapFree(GetProcessHeap(), 0, *BindingVector); + *BindingVector = NULL; + return RPC_S_OK; +} + +/*********************************************************************** + * RpcBindingInqObject (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingInqObject( RPC_BINDING_HANDLE Binding, UUID* ObjectUuid ) +{ + RpcBinding* bind = (RpcBinding*)Binding; + + TRACE("(%p,%p) = %s\n", Binding, ObjectUuid, debugstr_guid(&bind->ObjectUuid)); + memcpy(ObjectUuid, &bind->ObjectUuid, sizeof(UUID)); + return RPC_S_OK; +} + +/*********************************************************************** + * RpcBindingSetObject (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingSetObject( RPC_BINDING_HANDLE Binding, UUID* ObjectUuid ) +{ + RpcBinding* bind = (RpcBinding*)Binding; + + TRACE("(%p,%s)\n", Binding, debugstr_guid(ObjectUuid)); + if (bind->server) return RPC_S_WRONG_KIND_OF_BINDING; + return RPCRT4_SetBindingObject(Binding, ObjectUuid); +} + +/*********************************************************************** + * RpcBindingFromStringBindingA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingFromStringBindingA( unsigned char *StringBinding, RPC_BINDING_HANDLE* Binding ) +{ + RPC_STATUS ret; + RpcBinding* bind = NULL; + unsigned char *ObjectUuid, *Protseq, *NetworkAddr, *Endpoint, *Options; + UUID Uuid; + + TRACE("(%s,%p)\n", debugstr_a(StringBinding), Binding); + + ret = RpcStringBindingParseA(StringBinding, &ObjectUuid, &Protseq, + &NetworkAddr, &Endpoint, &Options); + if (ret != RPC_S_OK) return ret; + + ret = UuidFromStringA(ObjectUuid, &Uuid); + + if (ret == RPC_S_OK) + ret = RPCRT4_CreateBindingA(&bind, FALSE, Protseq); + if (ret == RPC_S_OK) + ret = RPCRT4_SetBindingObject(bind, &Uuid); + if (ret == RPC_S_OK) + ret = RPCRT4_CompleteBindingA(bind, NetworkAddr, Endpoint, Options); + + RpcStringFreeA((unsigned char**)&Options); + RpcStringFreeA((unsigned char**)&Endpoint); + RpcStringFreeA((unsigned char**)&NetworkAddr); + RpcStringFreeA((unsigned char**)&Protseq); + RpcStringFreeA((unsigned char**)&ObjectUuid); + + if (ret == RPC_S_OK) + *Binding = (RPC_BINDING_HANDLE)bind; + else + RPCRT4_DestroyBinding(bind); + + return ret; +} + +/*********************************************************************** + * RpcBindingFromStringBindingW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingFromStringBindingW( LPWSTR StringBinding, RPC_BINDING_HANDLE* Binding ) +{ + RPC_STATUS ret; + RpcBinding* bind = NULL; + LPWSTR ObjectUuid, Protseq, NetworkAddr, Endpoint, Options; + UUID Uuid; + + TRACE("(%s,%p)\n", debugstr_w(StringBinding), Binding); + + ret = RpcStringBindingParseW(StringBinding, &ObjectUuid, &Protseq, + &NetworkAddr, &Endpoint, &Options); + if (ret != RPC_S_OK) return ret; + + ret = UuidFromStringW(ObjectUuid, &Uuid); + + if (ret == RPC_S_OK) + ret = RPCRT4_CreateBindingW(&bind, FALSE, Protseq); + if (ret == RPC_S_OK) + ret = RPCRT4_SetBindingObject(bind, &Uuid); + if (ret == RPC_S_OK) + ret = RPCRT4_CompleteBindingW(bind, NetworkAddr, Endpoint, Options); + + RpcStringFreeW(&Options); + RpcStringFreeW(&Endpoint); + RpcStringFreeW(&NetworkAddr); + RpcStringFreeW(&Protseq); + RpcStringFreeW(&ObjectUuid); + + if (ret == RPC_S_OK) + *Binding = (RPC_BINDING_HANDLE)bind; + else + RPCRT4_DestroyBinding(bind); + + return ret; +} + +/*********************************************************************** + * RpcBindingToStringBindingA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingToStringBindingA( RPC_BINDING_HANDLE Binding, unsigned char** StringBinding ) +{ + RPC_STATUS ret; + RpcBinding* bind = (RpcBinding*)Binding; + LPSTR ObjectUuid; + + TRACE("(%p,%p)\n", Binding, StringBinding); + + ret = UuidToStringA(&bind->ObjectUuid, (unsigned char**)&ObjectUuid); + if (ret != RPC_S_OK) return ret; + + ret = RpcStringBindingComposeA(ObjectUuid, bind->Protseq, bind->NetworkAddr, + bind->Endpoint, NULL, StringBinding); + + RpcStringFreeA((unsigned char**)&ObjectUuid); + + return ret; +} + +/*********************************************************************** + * RpcBindingToStringBindingW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingToStringBindingW( RPC_BINDING_HANDLE Binding, unsigned short** StringBinding ) +{ + RPC_STATUS ret; + unsigned char *str = NULL; + TRACE("(%p,%p)\n", Binding, StringBinding); + ret = RpcBindingToStringBindingA(Binding, &str); + *StringBinding = RPCRT4_strdupAtoW(str); + RpcStringFreeA((unsigned char**)&str); + return ret; +} + +/*********************************************************************** + * I_RpcBindingSetAsync (RPCRT4.@) + * NOTES + * Exists in win9x and winNT, but with different number of arguments + * (9x version has 3 arguments, NT has 2). + */ +RPC_STATUS WINAPI I_RpcBindingSetAsync( RPC_BINDING_HANDLE Binding, RPC_BLOCKING_FN BlockingFn) +{ + RpcBinding* bind = (RpcBinding*)Binding; + + TRACE( "(%p,%p): stub\n", Binding, BlockingFn ); + + bind->BlockingFn = BlockingFn; + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcNetworkIsProtseqValidA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(unsigned char *protseq) { + UNICODE_STRING protseqW; + + if (!protseq) return RPC_S_INVALID_RPC_PROTSEQ; /* ? */ + + if (RtlCreateUnicodeStringFromAsciiz(&protseqW, protseq)) { + RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer); + RtlFreeUnicodeString(&protseqW); + return ret; + } else return RPC_S_OUT_OF_MEMORY; +} + +/*********************************************************************** + * RpcNetworkIsProtseqValidW (RPCRT4.@) + * + * Checks if the given protocol sequence is known by the RPC system. + * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED. + * + * We currently support: + * ncalrpc local-only rpc over LPC (LPC is not really used) + * ncacn_np rpc over named pipes + */ +RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(LPWSTR protseq) { + static const WCHAR protseqsW[][15] = { + {'n','c','a','l','r','p','c',0}, + {'n','c','a','c','n','_','n','p',0} + }; + static const int count = sizeof(protseqsW) / sizeof(protseqsW[0]); + int i; + + if (!protseq) return RPC_S_INVALID_RPC_PROTSEQ; /* ? */ + + for (i = 0; i < count; i++) { + if (!strcmpW(protseq, protseqsW[i])) return RPC_S_OK; + } + + FIXME("Unknown protseq %s - we probably need to implement it one day\n", debugstr_w(protseq)); + return RPC_S_PROTSEQ_NOT_SUPPORTED; +} + +/*********************************************************************** + * RpcImpersonateClient (RPCRT4.@) + * + * Impersonates the client connected via a binding handle so that security + * checks are done in the context of the client. + * + * PARAMS + * BindingHandle [I] Handle to the binding to the client. + * + * RETURNS + * Success: RPS_S_OK. + * Failure: RPC_STATUS value. + * + * NOTES + * + * If BindingHandle is NULL then the function impersonates the client + * connected to the binding handle of the current thread. + */ +RPC_STATUS WINAPI RpcImpersonateClient(RPC_BINDING_HANDLE BindingHandle) +{ + FIXME("(%p): stub\n", BindingHandle); + return RPC_S_OK; +} + +/*********************************************************************** + * RpcRevertToSelfEx (RPCRT4.@) + * + * Stops impersonating the client connected to the binding handle so that security + * checks are no longer done in the context of the client. + * + * PARAMS + * BindingHandle [I] Handle to the binding to the client. + * + * RETURNS + * Success: RPS_S_OK. + * Failure: RPC_STATUS value. + * + * NOTES + * + * If BindingHandle is NULL then the function stops impersonating the client + * connected to the binding handle of the current thread. + */ +RPC_STATUS WINAPI RpcRevertToSelfEx(RPC_BINDING_HANDLE BindingHandle) +{ + FIXME("(%p): stub\n", BindingHandle); + return RPC_S_OK; +} diff --git a/reactos/lib/rpcrt4/rpc_binding.h b/reactos/lib/rpcrt4/rpc_binding.h index 61f796b41ff..242492daa9b 100644 --- a/reactos/lib/rpcrt4/rpc_binding.h +++ b/reactos/lib/rpcrt4/rpc_binding.h @@ -1,86 +1,86 @@ -/* - * RPC binding API - * - * Copyright 2001 Ove KÃ¥ven, TransGaming Technologies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_RPC_BINDING_H -#define __WINE_RPC_BINDING_H - -#include "wine/rpcss_shared.h" - -typedef struct _RpcConnection -{ - struct _RpcConnection* Next; - struct _RpcBinding* Used; - BOOL server; - LPSTR Protseq; - LPSTR NetworkAddr; - LPSTR Endpoint; - HANDLE conn, thread; - OVERLAPPED ovl[2]; - USHORT MaxTransmissionSize; - /* The active interface bound to server. */ - RPC_SYNTAX_IDENTIFIER ActiveInterface; -} RpcConnection; - -/* don't know what MS's structure looks like */ -typedef struct _RpcBinding -{ - DWORD refs; - struct _RpcBinding* Next; - BOOL server; - UUID ObjectUuid; - LPSTR Protseq; - LPSTR NetworkAddr; - LPSTR Endpoint; - RPC_BLOCKING_FN BlockingFn; - ULONG ServerTid; - RpcConnection* FromConn; -} RpcBinding; - -LPSTR RPCRT4_strndupA(LPCSTR src, INT len); -LPWSTR RPCRT4_strndupW(LPWSTR src, INT len); -LPSTR RPCRT4_strdupWtoA(LPWSTR src); -LPWSTR RPCRT4_strdupAtoW(LPSTR src); -void RPCRT4_strfree(LPSTR src); - -#define RPCRT4_strdupA(x) RPCRT4_strndupA((x),-1) -#define RPCRT4_strdupW(x) RPCRT4_strndupW((x),-1) - -RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPSTR Protseq, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions, RpcBinding* Binding); -RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection); -RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection); -RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection); -RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection); - -RPC_STATUS RPCRT4_CreateBindingA(RpcBinding** Binding, BOOL server, LPSTR Protseq); -RPC_STATUS RPCRT4_CreateBindingW(RpcBinding** Binding, BOOL server, LPWSTR Protseq); -RPC_STATUS RPCRT4_CompleteBindingA(RpcBinding* Binding, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions); -RPC_STATUS RPCRT4_CompleteBindingW(RpcBinding* Binding, LPWSTR NetworkAddr, LPWSTR Endpoint, LPWSTR NetworkOptions); -RPC_STATUS RPCRT4_ResolveBinding(RpcBinding* Binding, LPSTR Endpoint); -RPC_STATUS RPCRT4_SetBindingObject(RpcBinding* Binding, UUID* ObjectUuid); -RPC_STATUS RPCRT4_MakeBinding(RpcBinding** Binding, RpcConnection* Connection); -RPC_STATUS RPCRT4_ExportBinding(RpcBinding** Binding, RpcBinding* OldBinding); -RPC_STATUS RPCRT4_DestroyBinding(RpcBinding* Binding); -RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection, PRPC_SYNTAX_IDENTIFIER TransferSyntax, PRPC_SYNTAX_IDENTIFIER InterfaceId); -RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding, RpcConnection* Connection); -BOOL RPCRT4_RPCSSOnDemandCall(PRPCSS_NP_MESSAGE msg, char *vardata_payload, PRPCSS_NP_REPLY reply); -HANDLE RPCRT4_GetMasterMutex(void); -HANDLE RPCRT4_RpcssNPConnect(void); - -#endif +/* + * RPC binding API + * + * Copyright 2001 Ove KÃ¥ven, TransGaming Technologies + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_RPC_BINDING_H +#define __WINE_RPC_BINDING_H + +#include "wine/rpcss_shared.h" + +typedef struct _RpcConnection +{ + struct _RpcConnection* Next; + struct _RpcBinding* Used; + BOOL server; + LPSTR Protseq; + LPSTR NetworkAddr; + LPSTR Endpoint; + HANDLE conn, thread; + OVERLAPPED ovl[2]; + USHORT MaxTransmissionSize; + /* The active interface bound to server. */ + RPC_SYNTAX_IDENTIFIER ActiveInterface; +} RpcConnection; + +/* don't know what MS's structure looks like */ +typedef struct _RpcBinding +{ + DWORD refs; + struct _RpcBinding* Next; + BOOL server; + UUID ObjectUuid; + LPSTR Protseq; + LPSTR NetworkAddr; + LPSTR Endpoint; + RPC_BLOCKING_FN BlockingFn; + ULONG ServerTid; + RpcConnection* FromConn; +} RpcBinding; + +LPSTR RPCRT4_strndupA(LPCSTR src, INT len); +LPWSTR RPCRT4_strndupW(LPWSTR src, INT len); +LPSTR RPCRT4_strdupWtoA(LPWSTR src); +LPWSTR RPCRT4_strdupAtoW(LPSTR src); +void RPCRT4_strfree(LPSTR src); + +#define RPCRT4_strdupA(x) RPCRT4_strndupA((x),-1) +#define RPCRT4_strdupW(x) RPCRT4_strndupW((x),-1) + +RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPSTR Protseq, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions, RpcBinding* Binding); +RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection); +RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection); +RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection); +RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection); + +RPC_STATUS RPCRT4_CreateBindingA(RpcBinding** Binding, BOOL server, LPSTR Protseq); +RPC_STATUS RPCRT4_CreateBindingW(RpcBinding** Binding, BOOL server, LPWSTR Protseq); +RPC_STATUS RPCRT4_CompleteBindingA(RpcBinding* Binding, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions); +RPC_STATUS RPCRT4_CompleteBindingW(RpcBinding* Binding, LPWSTR NetworkAddr, LPWSTR Endpoint, LPWSTR NetworkOptions); +RPC_STATUS RPCRT4_ResolveBinding(RpcBinding* Binding, LPSTR Endpoint); +RPC_STATUS RPCRT4_SetBindingObject(RpcBinding* Binding, UUID* ObjectUuid); +RPC_STATUS RPCRT4_MakeBinding(RpcBinding** Binding, RpcConnection* Connection); +RPC_STATUS RPCRT4_ExportBinding(RpcBinding** Binding, RpcBinding* OldBinding); +RPC_STATUS RPCRT4_DestroyBinding(RpcBinding* Binding); +RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection, PRPC_SYNTAX_IDENTIFIER TransferSyntax, PRPC_SYNTAX_IDENTIFIER InterfaceId); +RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding, RpcConnection* Connection); +BOOL RPCRT4_RPCSSOnDemandCall(PRPCSS_NP_MESSAGE msg, char *vardata_payload, PRPCSS_NP_REPLY reply); +HANDLE RPCRT4_GetMasterMutex(void); +HANDLE RPCRT4_RpcssNPConnect(void); + +#endif diff --git a/reactos/lib/rpcrt4/rpc_defs.h b/reactos/lib/rpcrt4/rpc_defs.h index f2fc382ac10..9e9a7359b10 100644 --- a/reactos/lib/rpcrt4/rpc_defs.h +++ b/reactos/lib/rpcrt4/rpc_defs.h @@ -1,183 +1,183 @@ -/* - * RPC definitions - * - * Copyright 2001-2002 Ove Kåven, TransGaming Technologies - * Copyright 2004 Filip Navara - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_RPC_DEFS_H -#define __WINE_RPC_DEFS_H - -/* info from http://www.microsoft.com/msj/0398/dcomtextfigs.htm */ - -typedef struct -{ - unsigned char rpc_ver; /* RPC major version (5) */ - unsigned char rpc_ver_minor; /* RPC minor version (0) */ - unsigned char ptype; /* Packet type (PKT_*) */ - unsigned char flags; - unsigned char drep[4]; /* Data representation */ - unsigned short frag_len; /* Data size in bytes including header and tail. */ - unsigned short auth_len; /* Authentication length */ - unsigned long call_id; /* Call identifier. */ -} RpcPktCommonHdr; - -typedef struct -{ - RpcPktCommonHdr common; - unsigned long alloc_hint; /* Data size in bytes excluding header and tail. */ - unsigned short context_id; /* Presentation context identifier */ - unsigned short opnum; -} RpcPktRequestHdr; - -typedef struct -{ - RpcPktCommonHdr common; - unsigned long alloc_hint; /* Data size in bytes excluding header and tail. */ - unsigned short context_id; /* Presentation context identifier */ - unsigned char cancel_count; - unsigned char reserved; -} RpcPktResponseHdr; - -typedef struct -{ - RpcPktCommonHdr common; - unsigned long alloc_hint; /* Data size in bytes excluding header and tail. */ - unsigned short context_id; /* Presentation context identifier */ - unsigned char alert_count; /* Pending alert count */ - unsigned char padding[3]; /* Force alignment! */ - unsigned long status; /* Runtime fault code (RPC_STATUS) */ - unsigned long reserved; -} RpcPktFaultHdr; - -typedef struct -{ - RpcPktCommonHdr common; - unsigned short max_tsize; /* Maximum transmission fragment size */ - unsigned short max_rsize; /* Maximum receive fragment size */ - unsigned long assoc_gid; /* Associated group id */ - unsigned char num_elements; /* Number of elements */ - unsigned char padding[3]; /* Force alignment! */ - unsigned short context_id; /* Presentation context identifier */ - unsigned char num_syntaxes; /* Number of syntaxes */ - RPC_SYNTAX_IDENTIFIER abstract; - RPC_SYNTAX_IDENTIFIER transfer; -} RpcPktBindHdr; - -#include "pshpack1.h" -typedef struct -{ - unsigned short length; /* Length of the string including null terminator */ - char string[1]; /* String data in single byte, null terminated form */ -} RpcAddressString; -#include "poppack.h" - -typedef struct -{ - unsigned char padding1[2]; /* Force alignment! */ - unsigned char num_results; /* Number of results */ - unsigned char padding2[3]; /* Force alignment! */ - struct { - unsigned short result; - unsigned short reason; - } results[1]; -} RpcResults; - -typedef struct -{ - RpcPktCommonHdr common; - unsigned short max_tsize; /* Maximum transmission fragment size */ - unsigned short max_rsize; /* Maximum receive fragment size */ - unsigned long assoc_gid; /* Associated group id */ - /* - * Following this header are these fields: - * RpcAddressString server_address; - * RpcResults results; - * RPC_SYNTAX_IDENTIFIER transfer; - */ -} RpcPktBindAckHdr; - -typedef struct -{ - RpcPktCommonHdr common; - unsigned short reject_reason; - unsigned char protocols_count; - struct { - unsigned char rpc_ver; - unsigned char rpc_ver_minor; - } protocols[1]; -} RpcPktBindNAckHdr; - -/* Union representing all possible packet headers */ -typedef union -{ - RpcPktCommonHdr common; - RpcPktRequestHdr request; - RpcPktResponseHdr response; - RpcPktFaultHdr fault; - RpcPktBindHdr bind; - RpcPktBindAckHdr bind_ack; - RpcPktBindNAckHdr bind_nack; -} RpcPktHdr; - -#define RPC_VER_MAJOR 5 -#define RPC_VER_MINOR 0 - -#define RPC_FLG_FIRST 1 -#define RPC_FLG_LAST 2 -#define RPC_FLG_OBJECT_UUID 0x80 - -#define RPC_MIN_PACKET_SIZE 0x1000 -#define RPC_MAX_PACKET_SIZE 0x16D0 - -#define PKT_REQUEST 0 -#define PKT_PING 1 -#define PKT_RESPONSE 2 -#define PKT_FAULT 3 -#define PKT_WORKING 4 -#define PKT_NOCALL 5 -#define PKT_REJECT 6 -#define PKT_ACK 7 -#define PKT_CL_CANCEL 8 -#define PKT_FACK 9 -#define PKT_CANCEL_ACK 10 -#define PKT_BIND 11 -#define PKT_BIND_ACK 12 -#define PKT_BIND_NACK 13 -#define PKT_ALTER_CONTEXT 14 -#define PKT_ALTER_CONTEXT_RESP 15 -#define PKT_SHUTDOWN 17 -#define PKT_CO_CANCEL 18 -#define PKT_ORPHANED 19 - -#define RESULT_ACCEPT 0 - -#define NO_REASON 0 - -#define NCADG_IP_UDP 0x08 -#define NCACN_IP_TCP 0x07 -#define NCADG_IPX 0x0E -#define NCACN_SPX 0x0C -#define NCACN_NB_NB 0x12 -#define NCACN_NB_IPX 0x0D -#define NCACN_DNET_NSP 0x04 -#define NCACN_HTTP 0x1F - -/* FreeDCE: TWR_C_FLR_PROT_ID_IP */ -#define TWR_IP 0x09 - -#endif /* __WINE_RPC_DEFS_H */ +/* + * RPC definitions + * + * Copyright 2001-2002 Ove Kåven, TransGaming Technologies + * Copyright 2004 Filip Navara + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_RPC_DEFS_H +#define __WINE_RPC_DEFS_H + +/* info from http://www.microsoft.com/msj/0398/dcomtextfigs.htm */ + +typedef struct +{ + unsigned char rpc_ver; /* RPC major version (5) */ + unsigned char rpc_ver_minor; /* RPC minor version (0) */ + unsigned char ptype; /* Packet type (PKT_*) */ + unsigned char flags; + unsigned char drep[4]; /* Data representation */ + unsigned short frag_len; /* Data size in bytes including header and tail. */ + unsigned short auth_len; /* Authentication length */ + unsigned long call_id; /* Call identifier. */ +} RpcPktCommonHdr; + +typedef struct +{ + RpcPktCommonHdr common; + unsigned long alloc_hint; /* Data size in bytes excluding header and tail. */ + unsigned short context_id; /* Presentation context identifier */ + unsigned short opnum; +} RpcPktRequestHdr; + +typedef struct +{ + RpcPktCommonHdr common; + unsigned long alloc_hint; /* Data size in bytes excluding header and tail. */ + unsigned short context_id; /* Presentation context identifier */ + unsigned char cancel_count; + unsigned char reserved; +} RpcPktResponseHdr; + +typedef struct +{ + RpcPktCommonHdr common; + unsigned long alloc_hint; /* Data size in bytes excluding header and tail. */ + unsigned short context_id; /* Presentation context identifier */ + unsigned char alert_count; /* Pending alert count */ + unsigned char padding[3]; /* Force alignment! */ + unsigned long status; /* Runtime fault code (RPC_STATUS) */ + unsigned long reserved; +} RpcPktFaultHdr; + +typedef struct +{ + RpcPktCommonHdr common; + unsigned short max_tsize; /* Maximum transmission fragment size */ + unsigned short max_rsize; /* Maximum receive fragment size */ + unsigned long assoc_gid; /* Associated group id */ + unsigned char num_elements; /* Number of elements */ + unsigned char padding[3]; /* Force alignment! */ + unsigned short context_id; /* Presentation context identifier */ + unsigned char num_syntaxes; /* Number of syntaxes */ + RPC_SYNTAX_IDENTIFIER abstract; + RPC_SYNTAX_IDENTIFIER transfer; +} RpcPktBindHdr; + +#include "pshpack1.h" +typedef struct +{ + unsigned short length; /* Length of the string including null terminator */ + char string[1]; /* String data in single byte, null terminated form */ +} RpcAddressString; +#include "poppack.h" + +typedef struct +{ + unsigned char padding1[2]; /* Force alignment! */ + unsigned char num_results; /* Number of results */ + unsigned char padding2[3]; /* Force alignment! */ + struct { + unsigned short result; + unsigned short reason; + } results[1]; +} RpcResults; + +typedef struct +{ + RpcPktCommonHdr common; + unsigned short max_tsize; /* Maximum transmission fragment size */ + unsigned short max_rsize; /* Maximum receive fragment size */ + unsigned long assoc_gid; /* Associated group id */ + /* + * Following this header are these fields: + * RpcAddressString server_address; + * RpcResults results; + * RPC_SYNTAX_IDENTIFIER transfer; + */ +} RpcPktBindAckHdr; + +typedef struct +{ + RpcPktCommonHdr common; + unsigned short reject_reason; + unsigned char protocols_count; + struct { + unsigned char rpc_ver; + unsigned char rpc_ver_minor; + } protocols[1]; +} RpcPktBindNAckHdr; + +/* Union representing all possible packet headers */ +typedef union +{ + RpcPktCommonHdr common; + RpcPktRequestHdr request; + RpcPktResponseHdr response; + RpcPktFaultHdr fault; + RpcPktBindHdr bind; + RpcPktBindAckHdr bind_ack; + RpcPktBindNAckHdr bind_nack; +} RpcPktHdr; + +#define RPC_VER_MAJOR 5 +#define RPC_VER_MINOR 0 + +#define RPC_FLG_FIRST 1 +#define RPC_FLG_LAST 2 +#define RPC_FLG_OBJECT_UUID 0x80 + +#define RPC_MIN_PACKET_SIZE 0x1000 +#define RPC_MAX_PACKET_SIZE 0x16D0 + +#define PKT_REQUEST 0 +#define PKT_PING 1 +#define PKT_RESPONSE 2 +#define PKT_FAULT 3 +#define PKT_WORKING 4 +#define PKT_NOCALL 5 +#define PKT_REJECT 6 +#define PKT_ACK 7 +#define PKT_CL_CANCEL 8 +#define PKT_FACK 9 +#define PKT_CANCEL_ACK 10 +#define PKT_BIND 11 +#define PKT_BIND_ACK 12 +#define PKT_BIND_NACK 13 +#define PKT_ALTER_CONTEXT 14 +#define PKT_ALTER_CONTEXT_RESP 15 +#define PKT_SHUTDOWN 17 +#define PKT_CO_CANCEL 18 +#define PKT_ORPHANED 19 + +#define RESULT_ACCEPT 0 + +#define NO_REASON 0 + +#define NCADG_IP_UDP 0x08 +#define NCACN_IP_TCP 0x07 +#define NCADG_IPX 0x0E +#define NCACN_SPX 0x0C +#define NCACN_NB_NB 0x12 +#define NCACN_NB_IPX 0x0D +#define NCACN_DNET_NSP 0x04 +#define NCACN_HTTP 0x1F + +/* FreeDCE: TWR_C_FLR_PROT_ID_IP */ +#define TWR_IP 0x09 + +#endif /* __WINE_RPC_DEFS_H */ diff --git a/reactos/lib/rpcrt4/rpc_epmap.c b/reactos/lib/rpcrt4/rpc_epmap.c index 1986ec65eb4..1d8eeb2b00a 100644 --- a/reactos/lib/rpcrt4/rpc_epmap.c +++ b/reactos/lib/rpcrt4/rpc_epmap.c @@ -1,247 +1,247 @@ -/* - * RPC endpoint mapper - * - * Copyright 2002 Greg Turner - * Copyright 2001 Ove Kåven, TransGaming Technologies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * TODO: - * - actually do things right - */ - -#include <stdarg.h> -#include <stdio.h> -#include <string.h> - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "winreg.h" - -#include "rpc.h" - -#include "wine/debug.h" - -#include "rpc_binding.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -/* The "real" RPC portmapper endpoints that I know of are: - * - * ncadg_ip_udp: 135 - * ncacn_ip_tcp: 135 - * ncacn_np: \\pipe\epmapper (?) - * ncalrpc: epmapper - * - * If the user's machine ran a DCE RPC daemon, it would - * probably be possible to connect to it, but there are many - * reasons not to, like: - * - the user probably does *not* run one, and probably - * shouldn't be forced to run one just for local COM - * - very few Unix systems use DCE RPC... if they run a RPC - * daemon at all, it's usually Sun RPC - * - DCE RPC registrations are persistent and saved on disk, - * while MS-RPC registrations are documented as non-persistent - * and stored only in RAM, and auto-destroyed when the process - * dies (something DCE RPC can't do) - * - * Of course, if the user *did* want to run a DCE RPC daemon anyway, - * there would be interoperability advantages, like the possibility - * of running a fully functional DCOM server using Wine... - */ - -/*********************************************************************** - * RpcEpRegisterA (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcEpRegisterA( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, - UUID_VECTOR *UuidVector, unsigned char *Annotation ) -{ - RPCSS_NP_MESSAGE msg; - RPCSS_NP_REPLY reply; - char *vardata_payload, *vp; - PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec; - unsigned long c; - RPC_STATUS rslt = RPC_S_OK; - - TRACE("(%p,%p,%p,%s)\n", IfSpec, BindingVector, UuidVector, debugstr_a(Annotation)); - TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID)); - for (c=0; c<BindingVector->Count; c++) { - RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[c]); - TRACE(" protseq[%ld]=%s\n", c, debugstr_a(bind->Protseq)); - TRACE(" endpoint[%ld]=%s\n", c, debugstr_a(bind->Endpoint)); - } - if (UuidVector) { - for (c=0; c<UuidVector->Count; c++) - TRACE(" obj[%ld]=%s\n", c, debugstr_guid(UuidVector->Uuid[c])); - } - - /* FIXME: Do something with annotation. */ - - /* construct the message to rpcss */ - msg.message_type = RPCSS_NP_MESSAGE_TYPEID_REGISTEREPMSG; - msg.message.registerepmsg.iface = If->InterfaceId; - msg.message.registerepmsg.no_replace = 0; - - msg.message.registerepmsg.object_count = (UuidVector) ? UuidVector->Count : 0; - msg.message.registerepmsg.binding_count = BindingVector->Count; - - /* calculate vardata payload size */ - msg.vardata_payload_size = msg.message.registerepmsg.object_count * sizeof(UUID); - for (c=0; c < msg.message.registerepmsg.binding_count; c++) { - RpcBinding *bind = (RpcBinding *)(BindingVector->BindingH[c]); - msg.vardata_payload_size += strlen(bind->Protseq) + 1; - msg.vardata_payload_size += strlen(bind->Endpoint) + 1; - } - - /* allocate the payload buffer */ - vp = vardata_payload = LocalAlloc(LPTR, msg.vardata_payload_size); - if (!vardata_payload) - return RPC_S_OUT_OF_MEMORY; - - /* populate the payload data */ - for (c=0; c < msg.message.registerepmsg.object_count; c++) { - CopyMemory(vp, UuidVector->Uuid[c], sizeof(UUID)); - vp += sizeof(UUID); - } - - for (c=0; c < msg.message.registerepmsg.binding_count; c++) { - RpcBinding *bind = (RpcBinding*)(BindingVector->BindingH[c]); - unsigned long pslen = strlen(bind->Protseq) + 1, eplen = strlen(bind->Endpoint) + 1; - CopyMemory(vp, bind->Protseq, pslen); - vp += pslen; - CopyMemory(vp, bind->Endpoint, eplen); - vp += eplen; - } - - /* send our request */ - if (!RPCRT4_RPCSSOnDemandCall(&msg, vardata_payload, &reply)) - rslt = RPC_S_OUT_OF_MEMORY; - - /* free the payload buffer */ - LocalFree(vardata_payload); - - return rslt; -} - -/*********************************************************************** - * RpcEpUnregister (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcEpUnregister( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, - UUID_VECTOR *UuidVector ) -{ - RPCSS_NP_MESSAGE msg; - RPCSS_NP_REPLY reply; - char *vardata_payload, *vp; - PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec; - unsigned long c; - RPC_STATUS rslt = RPC_S_OK; - - TRACE("(%p,%p,%p)\n", IfSpec, BindingVector, UuidVector); - TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID)); - for (c=0; c<BindingVector->Count; c++) { - RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[c]); - TRACE(" protseq[%ld]=%s\n", c, debugstr_a(bind->Protseq)); - TRACE(" endpoint[%ld]=%s\n", c, debugstr_a(bind->Endpoint)); - } - if (UuidVector) { - for (c=0; c<UuidVector->Count; c++) - TRACE(" obj[%ld]=%s\n", c, debugstr_guid(UuidVector->Uuid[c])); - } - - /* construct the message to rpcss */ - msg.message_type = RPCSS_NP_MESSAGE_TYPEID_UNREGISTEREPMSG; - msg.message.unregisterepmsg.iface = If->InterfaceId; - - msg.message.unregisterepmsg.object_count = (UuidVector) ? UuidVector->Count : 0; - msg.message.unregisterepmsg.binding_count = BindingVector->Count; - - /* calculate vardata payload size */ - msg.vardata_payload_size = msg.message.unregisterepmsg.object_count * sizeof(UUID); - for (c=0; c < msg.message.unregisterepmsg.binding_count; c++) { - RpcBinding *bind = (RpcBinding *)(BindingVector->BindingH[c]); - msg.vardata_payload_size += strlen(bind->Protseq) + 1; - msg.vardata_payload_size += strlen(bind->Endpoint) + 1; - } - - /* allocate the payload buffer */ - vp = vardata_payload = LocalAlloc(LPTR, msg.vardata_payload_size); - if (!vardata_payload) - return RPC_S_OUT_OF_MEMORY; - - /* populate the payload data */ - for (c=0; c < msg.message.unregisterepmsg.object_count; c++) { - CopyMemory(vp, UuidVector->Uuid[c], sizeof(UUID)); - vp += sizeof(UUID); - } - - for (c=0; c < msg.message.unregisterepmsg.binding_count; c++) { - RpcBinding *bind = (RpcBinding*)(BindingVector->BindingH[c]); - unsigned long pslen = strlen(bind->Protseq) + 1, eplen = strlen(bind->Endpoint) + 1; - CopyMemory(vp, bind->Protseq, pslen); - vp += pslen; - CopyMemory(vp, bind->Endpoint, eplen); - vp += eplen; - } - - /* send our request */ - if (!RPCRT4_RPCSSOnDemandCall(&msg, vardata_payload, &reply)) - rslt = RPC_S_OUT_OF_MEMORY; - - /* free the payload buffer */ - LocalFree(vardata_payload); - - return rslt; -} - -/*********************************************************************** - * RpcEpResolveBinding (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcEpResolveBinding( RPC_BINDING_HANDLE Binding, RPC_IF_HANDLE IfSpec ) -{ - RPCSS_NP_MESSAGE msg; - RPCSS_NP_REPLY reply; - PRPC_CLIENT_INTERFACE If = (PRPC_CLIENT_INTERFACE)IfSpec; - RpcBinding* bind = (RpcBinding*)Binding; - - TRACE("(%p,%p)\n", Binding, IfSpec); - TRACE(" protseq=%s\n", debugstr_a(bind->Protseq)); - TRACE(" obj=%s\n", debugstr_guid(&bind->ObjectUuid)); - TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID)); - - /* FIXME: totally untested */ - - /* just return for fully bound handles */ - if (bind->Endpoint && (bind->Endpoint[0] != '\0')) - return RPC_S_OK; - - /* construct the message to rpcss */ - msg.message_type = RPCSS_NP_MESSAGE_TYPEID_RESOLVEEPMSG; - msg.message.resolveepmsg.iface = If->InterfaceId; - msg.message.resolveepmsg.object = bind->ObjectUuid; - - msg.vardata_payload_size = strlen(bind->Protseq) + 1; - - /* send the message */ - if (!RPCRT4_RPCSSOnDemandCall(&msg, bind->Protseq, &reply)) - return RPC_S_OUT_OF_MEMORY; - - /* empty-string result means not registered */ - if (reply.as_string[0] == '\0') - return EPT_S_NOT_REGISTERED; - - /* otherwise we fully bind the handle & return RPC_S_OK */ - return RPCRT4_ResolveBinding(Binding, reply.as_string); -} +/* + * RPC endpoint mapper + * + * Copyright 2002 Greg Turner + * Copyright 2001 Ove Kåven, TransGaming Technologies + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * TODO: + * - actually do things right + */ + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" + +#include "rpc.h" + +#include "wine/debug.h" + +#include "rpc_binding.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/* The "real" RPC portmapper endpoints that I know of are: + * + * ncadg_ip_udp: 135 + * ncacn_ip_tcp: 135 + * ncacn_np: \\pipe\epmapper (?) + * ncalrpc: epmapper + * + * If the user's machine ran a DCE RPC daemon, it would + * probably be possible to connect to it, but there are many + * reasons not to, like: + * - the user probably does *not* run one, and probably + * shouldn't be forced to run one just for local COM + * - very few Unix systems use DCE RPC... if they run a RPC + * daemon at all, it's usually Sun RPC + * - DCE RPC registrations are persistent and saved on disk, + * while MS-RPC registrations are documented as non-persistent + * and stored only in RAM, and auto-destroyed when the process + * dies (something DCE RPC can't do) + * + * Of course, if the user *did* want to run a DCE RPC daemon anyway, + * there would be interoperability advantages, like the possibility + * of running a fully functional DCOM server using Wine... + */ + +/*********************************************************************** + * RpcEpRegisterA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcEpRegisterA( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, + UUID_VECTOR *UuidVector, unsigned char *Annotation ) +{ + RPCSS_NP_MESSAGE msg; + RPCSS_NP_REPLY reply; + char *vardata_payload, *vp; + PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec; + unsigned long c; + RPC_STATUS rslt = RPC_S_OK; + + TRACE("(%p,%p,%p,%s)\n", IfSpec, BindingVector, UuidVector, debugstr_a(Annotation)); + TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID)); + for (c=0; c<BindingVector->Count; c++) { + RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[c]); + TRACE(" protseq[%ld]=%s\n", c, debugstr_a(bind->Protseq)); + TRACE(" endpoint[%ld]=%s\n", c, debugstr_a(bind->Endpoint)); + } + if (UuidVector) { + for (c=0; c<UuidVector->Count; c++) + TRACE(" obj[%ld]=%s\n", c, debugstr_guid(UuidVector->Uuid[c])); + } + + /* FIXME: Do something with annotation. */ + + /* construct the message to rpcss */ + msg.message_type = RPCSS_NP_MESSAGE_TYPEID_REGISTEREPMSG; + msg.message.registerepmsg.iface = If->InterfaceId; + msg.message.registerepmsg.no_replace = 0; + + msg.message.registerepmsg.object_count = (UuidVector) ? UuidVector->Count : 0; + msg.message.registerepmsg.binding_count = BindingVector->Count; + + /* calculate vardata payload size */ + msg.vardata_payload_size = msg.message.registerepmsg.object_count * sizeof(UUID); + for (c=0; c < msg.message.registerepmsg.binding_count; c++) { + RpcBinding *bind = (RpcBinding *)(BindingVector->BindingH[c]); + msg.vardata_payload_size += strlen(bind->Protseq) + 1; + msg.vardata_payload_size += strlen(bind->Endpoint) + 1; + } + + /* allocate the payload buffer */ + vp = vardata_payload = LocalAlloc(LPTR, msg.vardata_payload_size); + if (!vardata_payload) + return RPC_S_OUT_OF_MEMORY; + + /* populate the payload data */ + for (c=0; c < msg.message.registerepmsg.object_count; c++) { + CopyMemory(vp, UuidVector->Uuid[c], sizeof(UUID)); + vp += sizeof(UUID); + } + + for (c=0; c < msg.message.registerepmsg.binding_count; c++) { + RpcBinding *bind = (RpcBinding*)(BindingVector->BindingH[c]); + unsigned long pslen = strlen(bind->Protseq) + 1, eplen = strlen(bind->Endpoint) + 1; + CopyMemory(vp, bind->Protseq, pslen); + vp += pslen; + CopyMemory(vp, bind->Endpoint, eplen); + vp += eplen; + } + + /* send our request */ + if (!RPCRT4_RPCSSOnDemandCall(&msg, vardata_payload, &reply)) + rslt = RPC_S_OUT_OF_MEMORY; + + /* free the payload buffer */ + LocalFree(vardata_payload); + + return rslt; +} + +/*********************************************************************** + * RpcEpUnregister (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcEpUnregister( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, + UUID_VECTOR *UuidVector ) +{ + RPCSS_NP_MESSAGE msg; + RPCSS_NP_REPLY reply; + char *vardata_payload, *vp; + PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec; + unsigned long c; + RPC_STATUS rslt = RPC_S_OK; + + TRACE("(%p,%p,%p)\n", IfSpec, BindingVector, UuidVector); + TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID)); + for (c=0; c<BindingVector->Count; c++) { + RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[c]); + TRACE(" protseq[%ld]=%s\n", c, debugstr_a(bind->Protseq)); + TRACE(" endpoint[%ld]=%s\n", c, debugstr_a(bind->Endpoint)); + } + if (UuidVector) { + for (c=0; c<UuidVector->Count; c++) + TRACE(" obj[%ld]=%s\n", c, debugstr_guid(UuidVector->Uuid[c])); + } + + /* construct the message to rpcss */ + msg.message_type = RPCSS_NP_MESSAGE_TYPEID_UNREGISTEREPMSG; + msg.message.unregisterepmsg.iface = If->InterfaceId; + + msg.message.unregisterepmsg.object_count = (UuidVector) ? UuidVector->Count : 0; + msg.message.unregisterepmsg.binding_count = BindingVector->Count; + + /* calculate vardata payload size */ + msg.vardata_payload_size = msg.message.unregisterepmsg.object_count * sizeof(UUID); + for (c=0; c < msg.message.unregisterepmsg.binding_count; c++) { + RpcBinding *bind = (RpcBinding *)(BindingVector->BindingH[c]); + msg.vardata_payload_size += strlen(bind->Protseq) + 1; + msg.vardata_payload_size += strlen(bind->Endpoint) + 1; + } + + /* allocate the payload buffer */ + vp = vardata_payload = LocalAlloc(LPTR, msg.vardata_payload_size); + if (!vardata_payload) + return RPC_S_OUT_OF_MEMORY; + + /* populate the payload data */ + for (c=0; c < msg.message.unregisterepmsg.object_count; c++) { + CopyMemory(vp, UuidVector->Uuid[c], sizeof(UUID)); + vp += sizeof(UUID); + } + + for (c=0; c < msg.message.unregisterepmsg.binding_count; c++) { + RpcBinding *bind = (RpcBinding*)(BindingVector->BindingH[c]); + unsigned long pslen = strlen(bind->Protseq) + 1, eplen = strlen(bind->Endpoint) + 1; + CopyMemory(vp, bind->Protseq, pslen); + vp += pslen; + CopyMemory(vp, bind->Endpoint, eplen); + vp += eplen; + } + + /* send our request */ + if (!RPCRT4_RPCSSOnDemandCall(&msg, vardata_payload, &reply)) + rslt = RPC_S_OUT_OF_MEMORY; + + /* free the payload buffer */ + LocalFree(vardata_payload); + + return rslt; +} + +/*********************************************************************** + * RpcEpResolveBinding (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcEpResolveBinding( RPC_BINDING_HANDLE Binding, RPC_IF_HANDLE IfSpec ) +{ + RPCSS_NP_MESSAGE msg; + RPCSS_NP_REPLY reply; + PRPC_CLIENT_INTERFACE If = (PRPC_CLIENT_INTERFACE)IfSpec; + RpcBinding* bind = (RpcBinding*)Binding; + + TRACE("(%p,%p)\n", Binding, IfSpec); + TRACE(" protseq=%s\n", debugstr_a(bind->Protseq)); + TRACE(" obj=%s\n", debugstr_guid(&bind->ObjectUuid)); + TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID)); + + /* FIXME: totally untested */ + + /* just return for fully bound handles */ + if (bind->Endpoint && (bind->Endpoint[0] != '\0')) + return RPC_S_OK; + + /* construct the message to rpcss */ + msg.message_type = RPCSS_NP_MESSAGE_TYPEID_RESOLVEEPMSG; + msg.message.resolveepmsg.iface = If->InterfaceId; + msg.message.resolveepmsg.object = bind->ObjectUuid; + + msg.vardata_payload_size = strlen(bind->Protseq) + 1; + + /* send the message */ + if (!RPCRT4_RPCSSOnDemandCall(&msg, bind->Protseq, &reply)) + return RPC_S_OUT_OF_MEMORY; + + /* empty-string result means not registered */ + if (reply.as_string[0] == '\0') + return EPT_S_NOT_REGISTERED; + + /* otherwise we fully bind the handle & return RPC_S_OK */ + return RPCRT4_ResolveBinding(Binding, reply.as_string); +} diff --git a/reactos/lib/rpcrt4/rpc_message.c b/reactos/lib/rpcrt4/rpc_message.c index ebc50171556..00c39efa901 100644 --- a/reactos/lib/rpcrt4/rpc_message.c +++ b/reactos/lib/rpcrt4/rpc_message.c @@ -1,655 +1,655 @@ -/* - * RPC messages - * - * Copyright 2001-2002 Ove Kåven, TransGaming Technologies - * Copyright 2004 Filip Navara - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * TODO: - * - figure out whether we *really* got this right - * - check for errors and throw exceptions - */ - -#include <stdarg.h> -#include <stdio.h> -#include <string.h> - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "winreg.h" - -#include "rpc.h" -#include "rpcndr.h" -#include "rpcdcep.h" - -#include "wine/debug.h" - -#include "rpc_binding.h" -#include "rpc_misc.h" -#include "rpc_defs.h" - -WINE_DEFAULT_DEBUG_CHANNEL(rpc); - -DWORD RPCRT4_GetHeaderSize(RpcPktHdr *Header) -{ - static const DWORD header_sizes[] = { - sizeof(Header->request), 0, sizeof(Header->response), - sizeof(Header->fault), 0, 0, 0, 0, 0, 0, 0, sizeof(Header->bind), - sizeof(Header->bind_ack), sizeof(Header->bind_nack), - 0, 0, 0, 0, 0 - }; - ULONG ret = 0; - - if (Header->common.ptype < sizeof(header_sizes) / sizeof(header_sizes[0])) { - ret = header_sizes[Header->common.ptype]; - if (ret == 0) - FIXME("unhandled packet type\n"); - if (Header->common.flags & RPC_FLG_OBJECT_UUID) - ret += sizeof(UUID); - } else { - TRACE("invalid packet type\n"); - } - - return ret; -} - -VOID RPCRT4_BuildCommonHeader(RpcPktHdr *Header, unsigned char PacketType, - unsigned long DataRepresentation) -{ - Header->common.rpc_ver = RPC_VER_MAJOR; - Header->common.rpc_ver_minor = RPC_VER_MINOR; - Header->common.ptype = PacketType; - Header->common.drep[0] = LOBYTE(LOWORD(DataRepresentation)); - Header->common.drep[1] = HIBYTE(LOWORD(DataRepresentation)); - Header->common.drep[2] = LOBYTE(HIWORD(DataRepresentation)); - Header->common.drep[3] = HIBYTE(HIWORD(DataRepresentation)); - Header->common.auth_len = 0; - Header->common.call_id = 1; - Header->common.flags = 0; - /* Flags and fragment length are computed in RPCRT4_Send. */ -} - -RpcPktHdr *RPCRT4_BuildRequestHeader(unsigned long DataRepresentation, - unsigned long BufferLength, - unsigned short ProcNum, - UUID *ObjectUuid) -{ - RpcPktHdr *header; - BOOL has_object; - RPC_STATUS status; - - has_object = (ObjectUuid != NULL && !UuidIsNil(ObjectUuid, &status)); - header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(header->request) + (has_object ? sizeof(UUID) : 0)); - if (header == NULL) { - return NULL; - } - - RPCRT4_BuildCommonHeader(header, PKT_REQUEST, DataRepresentation); - header->common.frag_len = sizeof(header->request); - header->request.alloc_hint = BufferLength; - header->request.context_id = 0; - header->request.opnum = ProcNum; - if (has_object) { - header->common.flags |= RPC_FLG_OBJECT_UUID; - header->common.frag_len += sizeof(UUID); - memcpy(&header->request + 1, ObjectUuid, sizeof(UUID)); - } - - return header; -} - -RpcPktHdr *RPCRT4_BuildResponseHeader(unsigned long DataRepresentation, - unsigned long BufferLength) -{ - RpcPktHdr *header; - - header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->response)); - if (header == NULL) { - return NULL; - } - - RPCRT4_BuildCommonHeader(header, PKT_RESPONSE, DataRepresentation); - header->common.frag_len = sizeof(header->response); - header->response.alloc_hint = BufferLength; - - return header; -} - -RpcPktHdr *RPCRT4_BuildFaultHeader(unsigned long DataRepresentation, - RPC_STATUS Status) -{ - RpcPktHdr *header; - - header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->fault)); - if (header == NULL) { - return NULL; - } - - RPCRT4_BuildCommonHeader(header, PKT_FAULT, DataRepresentation); - header->common.frag_len = sizeof(header->fault); - header->fault.status = Status; - - return header; -} - -RpcPktHdr *RPCRT4_BuildBindHeader(unsigned long DataRepresentation, - unsigned short MaxTransmissionSize, - unsigned short MaxReceiveSize, - RPC_SYNTAX_IDENTIFIER *AbstractId, - RPC_SYNTAX_IDENTIFIER *TransferId) -{ - RpcPktHdr *header; - - header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->bind)); - if (header == NULL) { - return NULL; - } - - RPCRT4_BuildCommonHeader(header, PKT_BIND, DataRepresentation); - header->common.frag_len = sizeof(header->bind); - header->bind.max_tsize = MaxTransmissionSize; - header->bind.max_rsize = MaxReceiveSize; - header->bind.num_elements = 1; - header->bind.num_syntaxes = 1; - memcpy(&header->bind.abstract, AbstractId, sizeof(RPC_SYNTAX_IDENTIFIER)); - memcpy(&header->bind.transfer, TransferId, sizeof(RPC_SYNTAX_IDENTIFIER)); - - return header; -} - -RpcPktHdr *RPCRT4_BuildBindNackHeader(unsigned long DataRepresentation, - unsigned char RpcVersion, - unsigned char RpcVersionMinor) -{ - RpcPktHdr *header; - - header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->bind_nack)); - if (header == NULL) { - return NULL; - } - - RPCRT4_BuildCommonHeader(header, PKT_BIND_NACK, DataRepresentation); - header->common.frag_len = sizeof(header->bind_nack); - header->bind_nack.protocols_count = 1; - header->bind_nack.protocols[0].rpc_ver = RpcVersion; - header->bind_nack.protocols[0].rpc_ver_minor = RpcVersionMinor; - - return header; -} - -RpcPktHdr *RPCRT4_BuildBindAckHeader(unsigned long DataRepresentation, - unsigned short MaxTransmissionSize, - unsigned short MaxReceiveSize, - LPSTR ServerAddress, - unsigned long Result, - unsigned long Reason, - RPC_SYNTAX_IDENTIFIER *TransferId) -{ - RpcPktHdr *header; - unsigned long header_size; - RpcAddressString *server_address; - RpcResults *results; - RPC_SYNTAX_IDENTIFIER *transfer_id; - - header_size = sizeof(header->bind_ack) + sizeof(RpcResults) + - sizeof(RPC_SYNTAX_IDENTIFIER) + sizeof(RpcAddressString) + - strlen(ServerAddress); - - header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, header_size); - if (header == NULL) { - return NULL; - } - - RPCRT4_BuildCommonHeader(header, PKT_BIND_ACK, DataRepresentation); - header->common.frag_len = header_size; - header->bind_ack.max_tsize = MaxTransmissionSize; - header->bind_ack.max_rsize = MaxReceiveSize; - server_address = (RpcAddressString*)(&header->bind_ack + 1); - server_address->length = strlen(ServerAddress) + 1; - strcpy(server_address->string, ServerAddress); - results = (RpcResults*)((ULONG_PTR)server_address + sizeof(RpcAddressString) + server_address->length - 1); - results->num_results = 1; - results->results[0].result = Result; - results->results[0].reason = Reason; - transfer_id = (RPC_SYNTAX_IDENTIFIER*)(results + 1); - memcpy(transfer_id, TransferId, sizeof(RPC_SYNTAX_IDENTIFIER)); - - return header; -} - -VOID RPCRT4_FreeHeader(RpcPktHdr *Header) -{ - HeapFree(GetProcessHeap(), 0, Header); -} - -/*********************************************************************** - * RPCRT4_Send (internal) - * - * Transmit a packet over connection in acceptable fragments. - */ -RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header, - void *Buffer, unsigned int BufferLength) -{ - PUCHAR buffer_pos; - DWORD hdr_size, count; - - buffer_pos = Buffer; - /* The packet building functions save the packet header size, so we can use it. */ - hdr_size = Header->common.frag_len; - Header->common.flags |= RPC_FLG_FIRST; - Header->common.flags &= ~RPC_FLG_LAST; - while (!(Header->common.flags & RPC_FLG_LAST)) { - /* decide if we need to split the packet into fragments */ - if ((BufferLength + hdr_size) <= Connection->MaxTransmissionSize) { - Header->common.flags |= RPC_FLG_LAST; - Header->common.frag_len = BufferLength + hdr_size; - } else { - Header->common.frag_len = Connection->MaxTransmissionSize; - buffer_pos += Header->common.frag_len - hdr_size; - BufferLength -= Header->common.frag_len - hdr_size; - } - - /* transmit packet header */ - if (!WriteFile(Connection->conn, Header, hdr_size, &count, &Connection->ovl[1]) && - ERROR_IO_PENDING != GetLastError()) { - WARN("WriteFile failed with error %ld\n", GetLastError()); - return GetLastError(); - } - if (!GetOverlappedResult(Connection->conn, &Connection->ovl[1], &count, TRUE)) { - WARN("GetOverlappedResult failed with error %ld\n", GetLastError()); - return GetLastError(); - } - - /* fragment consisted of header only and is the last one */ - if (hdr_size == Header->common.frag_len && - Header->common.flags & RPC_FLG_LAST) { - return RPC_S_OK; - } - - /* send the fragment data */ - if (!WriteFile(Connection->conn, buffer_pos, Header->common.frag_len - hdr_size, &count, &Connection->ovl[1]) && - ERROR_IO_PENDING != GetLastError()) { - WARN("WriteFile failed with error %ld\n", GetLastError()); - return GetLastError(); - } - if (!GetOverlappedResult(Connection->conn, &Connection->ovl[1], &count, TRUE)) { - WARN("GetOverlappedResult failed with error %ld\n", GetLastError()); - return GetLastError(); - } - - Header->common.flags &= ~RPC_FLG_FIRST; - } - - return RPC_S_OK; -} - -/*********************************************************************** - * RPCRT4_Receive (internal) - * - * Receive a packet from connection and merge the fragments. - */ -RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header, - PRPC_MESSAGE pMsg) -{ - RPC_STATUS status; - DWORD dwRead, hdr_length; - unsigned short first_flag; - unsigned long data_length; - unsigned long buffer_length; - unsigned char *buffer_ptr; - RpcPktCommonHdr common_hdr; - - *Header = NULL; - - TRACE("(%p, %p, %p)\n", Connection, Header, pMsg); - - /* read packet common header */ - if (!ReadFile(Connection->conn, &common_hdr, sizeof(common_hdr), &dwRead, &Connection->ovl[0]) && - ERROR_IO_PENDING != GetLastError()) { - WARN("ReadFile failed with error %ld\n", GetLastError()); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - if (!GetOverlappedResult(Connection->conn, &Connection->ovl[0], &dwRead, TRUE)) { - if (GetLastError() != ERROR_MORE_DATA) { - WARN("GetOverlappedResult failed with error %ld\n", GetLastError()); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - } - if (dwRead != sizeof(common_hdr)) { - WARN("Short read of header, %ld/%d bytes\n", dwRead, sizeof(common_hdr)); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - - /* verify if the header really makes sense */ - if (common_hdr.rpc_ver != RPC_VER_MAJOR || - common_hdr.rpc_ver_minor != RPC_VER_MINOR) { - WARN("unhandled packet version\n"); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - - hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr); - if (hdr_length == 0) { - WARN("header length == 0\n"); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - - *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length); - memcpy(*Header, &common_hdr, sizeof(common_hdr)); - - /* read the rest of packet header */ - if (!ReadFile(Connection->conn, &(*Header)->common + 1, - hdr_length - sizeof(common_hdr), &dwRead, &Connection->ovl[0]) && - ERROR_IO_PENDING != GetLastError()) { - WARN("ReadFile failed with error %ld\n", GetLastError()); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - if (!GetOverlappedResult(Connection->conn, &Connection->ovl[0], &dwRead, TRUE)) { - if (GetLastError() != ERROR_MORE_DATA) { - WARN("GetOverlappedResult failed with error %ld\n", GetLastError()); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - } - if (dwRead != hdr_length - sizeof(common_hdr)) { - WARN("bad header length, %ld/%ld bytes\n", dwRead, hdr_length - sizeof(common_hdr)); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - - - /* read packet body */ - switch (common_hdr.ptype) { - case PKT_RESPONSE: - pMsg->BufferLength = (*Header)->response.alloc_hint; - break; - case PKT_REQUEST: - pMsg->BufferLength = (*Header)->request.alloc_hint; - break; - default: - pMsg->BufferLength = common_hdr.frag_len - hdr_length; - } - - TRACE("buffer length = %u\n", pMsg->BufferLength); - - status = I_RpcGetBuffer(pMsg); - if (status != RPC_S_OK) goto fail; - - first_flag = RPC_FLG_FIRST; - buffer_length = 0; - buffer_ptr = pMsg->Buffer; - while (buffer_length < pMsg->BufferLength) - { - data_length = (*Header)->common.frag_len - hdr_length; - if (((*Header)->common.flags & RPC_FLG_FIRST) != first_flag || - data_length + buffer_length > pMsg->BufferLength) { - TRACE("invalid packet flags or buffer length\n"); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - - if (data_length == 0) dwRead = 0; else { - if (!ReadFile(Connection->conn, buffer_ptr, data_length, &dwRead, &Connection->ovl[0]) && - ERROR_IO_PENDING != GetLastError()) { - WARN("ReadFile failed with error %ld\n", GetLastError()); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - if (!GetOverlappedResult(Connection->conn, &Connection->ovl[0], &dwRead, TRUE)) { - if (GetLastError() != ERROR_MORE_DATA) { - WARN("GetOverlappedResult failed with error %ld\n", GetLastError()); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - } - } - if (dwRead != data_length) { - WARN("bad data length, %ld/%ld\n", dwRead, data_length); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - - /* when there is no more data left, it should be the last packet */ - if (buffer_length == pMsg->BufferLength && - ((*Header)->common.flags & RPC_FLG_LAST) == 0) { - WARN("no more data left, but not last packet\n"); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - - buffer_length += data_length; - if (buffer_length < pMsg->BufferLength) { - TRACE("next header\n"); - - /* read the header of next packet */ - if (!ReadFile(Connection->conn, *Header, hdr_length, &dwRead, &Connection->ovl[0]) && - ERROR_IO_PENDING != GetLastError()) { - WARN("ReadFile failed with error %ld\n", GetLastError()); - status = GetLastError(); - goto fail; - } - if (!GetOverlappedResult(Connection->conn, &Connection->ovl[0], &dwRead, TRUE)) { - if (GetLastError() != ERROR_MORE_DATA) { - WARN("GetOverlappedResult failed with error %ld\n", GetLastError()); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - } - if (dwRead != hdr_length) { - WARN("invalid packet header size (%ld)\n", dwRead); - status = RPC_S_PROTOCOL_ERROR; - goto fail; - } - - buffer_ptr += data_length; - first_flag = 0; - } - } - - /* success */ - status = RPC_S_OK; - -fail: - if (status != RPC_S_OK && *Header) { - RPCRT4_FreeHeader(*Header); - *Header = NULL; - } - return status; -} - -/*********************************************************************** - * I_RpcGetBuffer [RPCRT4.@] - */ -RPC_STATUS WINAPI I_RpcGetBuffer(PRPC_MESSAGE pMsg) -{ - RpcBinding* bind = (RpcBinding*)pMsg->Handle; - - TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength); - /* FIXME: pfnAllocate? */ - if (bind->server) { - /* it turns out that the original buffer data must still be available - * while the RPC server is marshalling a reply, so we should not deallocate - * it, we'll leave deallocating the original buffer to the RPC server */ - pMsg->Buffer = HeapAlloc(GetProcessHeap(), 0, pMsg->BufferLength); - } else { - HeapFree(GetProcessHeap(), 0, pMsg->Buffer); - pMsg->Buffer = HeapAlloc(GetProcessHeap(), 0, pMsg->BufferLength); - } - TRACE("Buffer=%p\n", pMsg->Buffer); - /* FIXME: which errors to return? */ - return pMsg->Buffer ? S_OK : E_OUTOFMEMORY; -} - -/*********************************************************************** - * I_RpcFreeBuffer [RPCRT4.@] - */ -RPC_STATUS WINAPI I_RpcFreeBuffer(PRPC_MESSAGE pMsg) -{ - TRACE("(%p) Buffer=%p\n", pMsg, pMsg->Buffer); - /* FIXME: pfnFree? */ - HeapFree(GetProcessHeap(), 0, pMsg->Buffer); - pMsg->Buffer = NULL; - return S_OK; -} - -/*********************************************************************** - * I_RpcSend [RPCRT4.@] - */ -RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg) -{ - RpcBinding* bind = (RpcBinding*)pMsg->Handle; - RpcConnection* conn; - RPC_CLIENT_INTERFACE* cif = NULL; - RPC_SERVER_INTERFACE* sif = NULL; - RPC_STATUS status; - RpcPktHdr *hdr; - - TRACE("(%p)\n", pMsg); - if (!bind) return RPC_S_INVALID_BINDING; - - if (bind->server) { - sif = pMsg->RpcInterfaceInformation; - if (!sif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ - status = RPCRT4_OpenBinding(bind, &conn, &sif->TransferSyntax, - &sif->InterfaceId); - } else { - cif = pMsg->RpcInterfaceInformation; - if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ - status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax, - &cif->InterfaceId); - } - - if (status != RPC_S_OK) return status; - - if (bind->server) { - if (pMsg->RpcFlags & WINE_RPCFLAG_EXCEPTION) { - hdr = RPCRT4_BuildFaultHeader(pMsg->DataRepresentation, - RPC_S_CALL_FAILED); - } else { - hdr = RPCRT4_BuildResponseHeader(pMsg->DataRepresentation, - pMsg->BufferLength); - } - } else { - hdr = RPCRT4_BuildRequestHeader(pMsg->DataRepresentation, - pMsg->BufferLength, pMsg->ProcNum, - &bind->ObjectUuid); - } - - status = RPCRT4_Send(conn, hdr, pMsg->Buffer, pMsg->BufferLength); - - RPCRT4_FreeHeader(hdr); - - /* success */ - if (!bind->server) { - /* save the connection, so the response can be read from it */ - pMsg->ReservedForRuntime = conn; - return RPC_S_OK; - } - RPCRT4_CloseBinding(bind, conn); - status = RPC_S_OK; - - return status; -} - -/*********************************************************************** - * I_RpcReceive [RPCRT4.@] - */ -RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg) -{ - RpcBinding* bind = (RpcBinding*)pMsg->Handle; - RpcConnection* conn; - RPC_CLIENT_INTERFACE* cif = NULL; - RPC_SERVER_INTERFACE* sif = NULL; - RPC_STATUS status; - RpcPktHdr *hdr = NULL; - - TRACE("(%p)\n", pMsg); - if (!bind) return RPC_S_INVALID_BINDING; - - if (pMsg->ReservedForRuntime) { - conn = pMsg->ReservedForRuntime; - pMsg->ReservedForRuntime = NULL; - } else { - if (bind->server) { - sif = pMsg->RpcInterfaceInformation; - if (!sif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ - status = RPCRT4_OpenBinding(bind, &conn, &sif->TransferSyntax, - &sif->InterfaceId); - } else { - cif = pMsg->RpcInterfaceInformation; - if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ - status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax, - &cif->InterfaceId); - } - if (status != RPC_S_OK) return status; - } - - status = RPCRT4_Receive(conn, &hdr, pMsg); - if (status != RPC_S_OK) { - WARN("receive failed with error %lx\n", status); - goto fail; - } - - status = RPC_S_PROTOCOL_ERROR; - - switch (hdr->common.ptype) { - case PKT_RESPONSE: - if (bind->server) goto fail; - break; - case PKT_REQUEST: - if (!bind->server) goto fail; - break; - case PKT_FAULT: - pMsg->RpcFlags |= WINE_RPCFLAG_EXCEPTION; - ERR ("we got fault packet with status %lx\n", hdr->fault.status); - status = RPC_S_CALL_FAILED; /* ? */ - goto fail; - default: - WARN("bad packet type %d\n", hdr->common.ptype); - goto fail; - } - - /* success */ - status = RPC_S_OK; - -fail: - if (hdr) { - RPCRT4_FreeHeader(hdr); - } - RPCRT4_CloseBinding(bind, conn); - return status; -} - -/*********************************************************************** - * I_RpcSendReceive [RPCRT4.@] - */ -RPC_STATUS WINAPI I_RpcSendReceive(PRPC_MESSAGE pMsg) -{ - RPC_STATUS status; - - TRACE("(%p)\n", pMsg); - status = I_RpcSend(pMsg); - if (status == RPC_S_OK) - status = I_RpcReceive(pMsg); - return status; -} +/* + * RPC messages + * + * Copyright 2001-2002 Ove Kåven, TransGaming Technologies + * Copyright 2004 Filip Navara + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * TODO: + * - figure out whether we *really* got this right + * - check for errors and throw exceptions + */ + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" + +#include "rpc.h" +#include "rpcndr.h" +#include "rpcdcep.h" + +#include "wine/debug.h" + +#include "rpc_binding.h" +#include "rpc_misc.h" +#include "rpc_defs.h" + +WINE_DEFAULT_DEBUG_CHANNEL(rpc); + +DWORD RPCRT4_GetHeaderSize(RpcPktHdr *Header) +{ + static const DWORD header_sizes[] = { + sizeof(Header->request), 0, sizeof(Header->response), + sizeof(Header->fault), 0, 0, 0, 0, 0, 0, 0, sizeof(Header->bind), + sizeof(Header->bind_ack), sizeof(Header->bind_nack), + 0, 0, 0, 0, 0 + }; + ULONG ret = 0; + + if (Header->common.ptype < sizeof(header_sizes) / sizeof(header_sizes[0])) { + ret = header_sizes[Header->common.ptype]; + if (ret == 0) + FIXME("unhandled packet type\n"); + if (Header->common.flags & RPC_FLG_OBJECT_UUID) + ret += sizeof(UUID); + } else { + TRACE("invalid packet type\n"); + } + + return ret; +} + +VOID RPCRT4_BuildCommonHeader(RpcPktHdr *Header, unsigned char PacketType, + unsigned long DataRepresentation) +{ + Header->common.rpc_ver = RPC_VER_MAJOR; + Header->common.rpc_ver_minor = RPC_VER_MINOR; + Header->common.ptype = PacketType; + Header->common.drep[0] = LOBYTE(LOWORD(DataRepresentation)); + Header->common.drep[1] = HIBYTE(LOWORD(DataRepresentation)); + Header->common.drep[2] = LOBYTE(HIWORD(DataRepresentation)); + Header->common.drep[3] = HIBYTE(HIWORD(DataRepresentation)); + Header->common.auth_len = 0; + Header->common.call_id = 1; + Header->common.flags = 0; + /* Flags and fragment length are computed in RPCRT4_Send. */ +} + +RpcPktHdr *RPCRT4_BuildRequestHeader(unsigned long DataRepresentation, + unsigned long BufferLength, + unsigned short ProcNum, + UUID *ObjectUuid) +{ + RpcPktHdr *header; + BOOL has_object; + RPC_STATUS status; + + has_object = (ObjectUuid != NULL && !UuidIsNil(ObjectUuid, &status)); + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(header->request) + (has_object ? sizeof(UUID) : 0)); + if (header == NULL) { + return NULL; + } + + RPCRT4_BuildCommonHeader(header, PKT_REQUEST, DataRepresentation); + header->common.frag_len = sizeof(header->request); + header->request.alloc_hint = BufferLength; + header->request.context_id = 0; + header->request.opnum = ProcNum; + if (has_object) { + header->common.flags |= RPC_FLG_OBJECT_UUID; + header->common.frag_len += sizeof(UUID); + memcpy(&header->request + 1, ObjectUuid, sizeof(UUID)); + } + + return header; +} + +RpcPktHdr *RPCRT4_BuildResponseHeader(unsigned long DataRepresentation, + unsigned long BufferLength) +{ + RpcPktHdr *header; + + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->response)); + if (header == NULL) { + return NULL; + } + + RPCRT4_BuildCommonHeader(header, PKT_RESPONSE, DataRepresentation); + header->common.frag_len = sizeof(header->response); + header->response.alloc_hint = BufferLength; + + return header; +} + +RpcPktHdr *RPCRT4_BuildFaultHeader(unsigned long DataRepresentation, + RPC_STATUS Status) +{ + RpcPktHdr *header; + + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->fault)); + if (header == NULL) { + return NULL; + } + + RPCRT4_BuildCommonHeader(header, PKT_FAULT, DataRepresentation); + header->common.frag_len = sizeof(header->fault); + header->fault.status = Status; + + return header; +} + +RpcPktHdr *RPCRT4_BuildBindHeader(unsigned long DataRepresentation, + unsigned short MaxTransmissionSize, + unsigned short MaxReceiveSize, + RPC_SYNTAX_IDENTIFIER *AbstractId, + RPC_SYNTAX_IDENTIFIER *TransferId) +{ + RpcPktHdr *header; + + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->bind)); + if (header == NULL) { + return NULL; + } + + RPCRT4_BuildCommonHeader(header, PKT_BIND, DataRepresentation); + header->common.frag_len = sizeof(header->bind); + header->bind.max_tsize = MaxTransmissionSize; + header->bind.max_rsize = MaxReceiveSize; + header->bind.num_elements = 1; + header->bind.num_syntaxes = 1; + memcpy(&header->bind.abstract, AbstractId, sizeof(RPC_SYNTAX_IDENTIFIER)); + memcpy(&header->bind.transfer, TransferId, sizeof(RPC_SYNTAX_IDENTIFIER)); + + return header; +} + +RpcPktHdr *RPCRT4_BuildBindNackHeader(unsigned long DataRepresentation, + unsigned char RpcVersion, + unsigned char RpcVersionMinor) +{ + RpcPktHdr *header; + + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->bind_nack)); + if (header == NULL) { + return NULL; + } + + RPCRT4_BuildCommonHeader(header, PKT_BIND_NACK, DataRepresentation); + header->common.frag_len = sizeof(header->bind_nack); + header->bind_nack.protocols_count = 1; + header->bind_nack.protocols[0].rpc_ver = RpcVersion; + header->bind_nack.protocols[0].rpc_ver_minor = RpcVersionMinor; + + return header; +} + +RpcPktHdr *RPCRT4_BuildBindAckHeader(unsigned long DataRepresentation, + unsigned short MaxTransmissionSize, + unsigned short MaxReceiveSize, + LPSTR ServerAddress, + unsigned long Result, + unsigned long Reason, + RPC_SYNTAX_IDENTIFIER *TransferId) +{ + RpcPktHdr *header; + unsigned long header_size; + RpcAddressString *server_address; + RpcResults *results; + RPC_SYNTAX_IDENTIFIER *transfer_id; + + header_size = sizeof(header->bind_ack) + sizeof(RpcResults) + + sizeof(RPC_SYNTAX_IDENTIFIER) + sizeof(RpcAddressString) + + strlen(ServerAddress); + + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, header_size); + if (header == NULL) { + return NULL; + } + + RPCRT4_BuildCommonHeader(header, PKT_BIND_ACK, DataRepresentation); + header->common.frag_len = header_size; + header->bind_ack.max_tsize = MaxTransmissionSize; + header->bind_ack.max_rsize = MaxReceiveSize; + server_address = (RpcAddressString*)(&header->bind_ack + 1); + server_address->length = strlen(ServerAddress) + 1; + strcpy(server_address->string, ServerAddress); + results = (RpcResults*)((ULONG_PTR)server_address + sizeof(RpcAddressString) + server_address->length - 1); + results->num_results = 1; + results->results[0].result = Result; + results->results[0].reason = Reason; + transfer_id = (RPC_SYNTAX_IDENTIFIER*)(results + 1); + memcpy(transfer_id, TransferId, sizeof(RPC_SYNTAX_IDENTIFIER)); + + return header; +} + +VOID RPCRT4_FreeHeader(RpcPktHdr *Header) +{ + HeapFree(GetProcessHeap(), 0, Header); +} + +/*********************************************************************** + * RPCRT4_Send (internal) + * + * Transmit a packet over connection in acceptable fragments. + */ +RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header, + void *Buffer, unsigned int BufferLength) +{ + PUCHAR buffer_pos; + DWORD hdr_size, count; + + buffer_pos = Buffer; + /* The packet building functions save the packet header size, so we can use it. */ + hdr_size = Header->common.frag_len; + Header->common.flags |= RPC_FLG_FIRST; + Header->common.flags &= ~RPC_FLG_LAST; + while (!(Header->common.flags & RPC_FLG_LAST)) { + /* decide if we need to split the packet into fragments */ + if ((BufferLength + hdr_size) <= Connection->MaxTransmissionSize) { + Header->common.flags |= RPC_FLG_LAST; + Header->common.frag_len = BufferLength + hdr_size; + } else { + Header->common.frag_len = Connection->MaxTransmissionSize; + buffer_pos += Header->common.frag_len - hdr_size; + BufferLength -= Header->common.frag_len - hdr_size; + } + + /* transmit packet header */ + if (!WriteFile(Connection->conn, Header, hdr_size, &count, &Connection->ovl[1]) && + ERROR_IO_PENDING != GetLastError()) { + WARN("WriteFile failed with error %ld\n", GetLastError()); + return GetLastError(); + } + if (!GetOverlappedResult(Connection->conn, &Connection->ovl[1], &count, TRUE)) { + WARN("GetOverlappedResult failed with error %ld\n", GetLastError()); + return GetLastError(); + } + + /* fragment consisted of header only and is the last one */ + if (hdr_size == Header->common.frag_len && + Header->common.flags & RPC_FLG_LAST) { + return RPC_S_OK; + } + + /* send the fragment data */ + if (!WriteFile(Connection->conn, buffer_pos, Header->common.frag_len - hdr_size, &count, &Connection->ovl[1]) && + ERROR_IO_PENDING != GetLastError()) { + WARN("WriteFile failed with error %ld\n", GetLastError()); + return GetLastError(); + } + if (!GetOverlappedResult(Connection->conn, &Connection->ovl[1], &count, TRUE)) { + WARN("GetOverlappedResult failed with error %ld\n", GetLastError()); + return GetLastError(); + } + + Header->common.flags &= ~RPC_FLG_FIRST; + } + + return RPC_S_OK; +} + +/*********************************************************************** + * RPCRT4_Receive (internal) + * + * Receive a packet from connection and merge the fragments. + */ +RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header, + PRPC_MESSAGE pMsg) +{ + RPC_STATUS status; + DWORD dwRead, hdr_length; + unsigned short first_flag; + unsigned long data_length; + unsigned long buffer_length; + unsigned char *buffer_ptr; + RpcPktCommonHdr common_hdr; + + *Header = NULL; + + TRACE("(%p, %p, %p)\n", Connection, Header, pMsg); + + /* read packet common header */ + if (!ReadFile(Connection->conn, &common_hdr, sizeof(common_hdr), &dwRead, &Connection->ovl[0]) && + ERROR_IO_PENDING != GetLastError()) { + WARN("ReadFile failed with error %ld\n", GetLastError()); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + if (!GetOverlappedResult(Connection->conn, &Connection->ovl[0], &dwRead, TRUE)) { + if (GetLastError() != ERROR_MORE_DATA) { + WARN("GetOverlappedResult failed with error %ld\n", GetLastError()); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + } + if (dwRead != sizeof(common_hdr)) { + WARN("Short read of header, %ld/%d bytes\n", dwRead, sizeof(common_hdr)); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + /* verify if the header really makes sense */ + if (common_hdr.rpc_ver != RPC_VER_MAJOR || + common_hdr.rpc_ver_minor != RPC_VER_MINOR) { + WARN("unhandled packet version\n"); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr); + if (hdr_length == 0) { + WARN("header length == 0\n"); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length); + memcpy(*Header, &common_hdr, sizeof(common_hdr)); + + /* read the rest of packet header */ + if (!ReadFile(Connection->conn, &(*Header)->common + 1, + hdr_length - sizeof(common_hdr), &dwRead, &Connection->ovl[0]) && + ERROR_IO_PENDING != GetLastError()) { + WARN("ReadFile failed with error %ld\n", GetLastError()); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + if (!GetOverlappedResult(Connection->conn, &Connection->ovl[0], &dwRead, TRUE)) { + if (GetLastError() != ERROR_MORE_DATA) { + WARN("GetOverlappedResult failed with error %ld\n", GetLastError()); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + } + if (dwRead != hdr_length - sizeof(common_hdr)) { + WARN("bad header length, %ld/%ld bytes\n", dwRead, hdr_length - sizeof(common_hdr)); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + + /* read packet body */ + switch (common_hdr.ptype) { + case PKT_RESPONSE: + pMsg->BufferLength = (*Header)->response.alloc_hint; + break; + case PKT_REQUEST: + pMsg->BufferLength = (*Header)->request.alloc_hint; + break; + default: + pMsg->BufferLength = common_hdr.frag_len - hdr_length; + } + + TRACE("buffer length = %u\n", pMsg->BufferLength); + + status = I_RpcGetBuffer(pMsg); + if (status != RPC_S_OK) goto fail; + + first_flag = RPC_FLG_FIRST; + buffer_length = 0; + buffer_ptr = pMsg->Buffer; + while (buffer_length < pMsg->BufferLength) + { + data_length = (*Header)->common.frag_len - hdr_length; + if (((*Header)->common.flags & RPC_FLG_FIRST) != first_flag || + data_length + buffer_length > pMsg->BufferLength) { + TRACE("invalid packet flags or buffer length\n"); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + if (data_length == 0) dwRead = 0; else { + if (!ReadFile(Connection->conn, buffer_ptr, data_length, &dwRead, &Connection->ovl[0]) && + ERROR_IO_PENDING != GetLastError()) { + WARN("ReadFile failed with error %ld\n", GetLastError()); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + if (!GetOverlappedResult(Connection->conn, &Connection->ovl[0], &dwRead, TRUE)) { + if (GetLastError() != ERROR_MORE_DATA) { + WARN("GetOverlappedResult failed with error %ld\n", GetLastError()); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + } + } + if (dwRead != data_length) { + WARN("bad data length, %ld/%ld\n", dwRead, data_length); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + /* when there is no more data left, it should be the last packet */ + if (buffer_length == pMsg->BufferLength && + ((*Header)->common.flags & RPC_FLG_LAST) == 0) { + WARN("no more data left, but not last packet\n"); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + buffer_length += data_length; + if (buffer_length < pMsg->BufferLength) { + TRACE("next header\n"); + + /* read the header of next packet */ + if (!ReadFile(Connection->conn, *Header, hdr_length, &dwRead, &Connection->ovl[0]) && + ERROR_IO_PENDING != GetLastError()) { + WARN("ReadFile failed with error %ld\n", GetLastError()); + status = GetLastError(); + goto fail; + } + if (!GetOverlappedResult(Connection->conn, &Connection->ovl[0], &dwRead, TRUE)) { + if (GetLastError() != ERROR_MORE_DATA) { + WARN("GetOverlappedResult failed with error %ld\n", GetLastError()); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + } + if (dwRead != hdr_length) { + WARN("invalid packet header size (%ld)\n", dwRead); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + buffer_ptr += data_length; + first_flag = 0; + } + } + + /* success */ + status = RPC_S_OK; + +fail: + if (status != RPC_S_OK && *Header) { + RPCRT4_FreeHeader(*Header); + *Header = NULL; + } + return status; +} + +/*********************************************************************** + * I_RpcGetBuffer [RPCRT4.@] + */ +RPC_STATUS WINAPI I_RpcGetBuffer(PRPC_MESSAGE pMsg) +{ + RpcBinding* bind = (RpcBinding*)pMsg->Handle; + + TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength); + /* FIXME: pfnAllocate? */ + if (bind->server) { + /* it turns out that the original buffer data must still be available + * while the RPC server is marshalling a reply, so we should not deallocate + * it, we'll leave deallocating the original buffer to the RPC server */ + pMsg->Buffer = HeapAlloc(GetProcessHeap(), 0, pMsg->BufferLength); + } else { + HeapFree(GetProcessHeap(), 0, pMsg->Buffer); + pMsg->Buffer = HeapAlloc(GetProcessHeap(), 0, pMsg->BufferLength); + } + TRACE("Buffer=%p\n", pMsg->Buffer); + /* FIXME: which errors to return? */ + return pMsg->Buffer ? S_OK : E_OUTOFMEMORY; +} + +/*********************************************************************** + * I_RpcFreeBuffer [RPCRT4.@] + */ +RPC_STATUS WINAPI I_RpcFreeBuffer(PRPC_MESSAGE pMsg) +{ + TRACE("(%p) Buffer=%p\n", pMsg, pMsg->Buffer); + /* FIXME: pfnFree? */ + HeapFree(GetProcessHeap(), 0, pMsg->Buffer); + pMsg->Buffer = NULL; + return S_OK; +} + +/*********************************************************************** + * I_RpcSend [RPCRT4.@] + */ +RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg) +{ + RpcBinding* bind = (RpcBinding*)pMsg->Handle; + RpcConnection* conn; + RPC_CLIENT_INTERFACE* cif = NULL; + RPC_SERVER_INTERFACE* sif = NULL; + RPC_STATUS status; + RpcPktHdr *hdr; + + TRACE("(%p)\n", pMsg); + if (!bind) return RPC_S_INVALID_BINDING; + + if (bind->server) { + sif = pMsg->RpcInterfaceInformation; + if (!sif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ + status = RPCRT4_OpenBinding(bind, &conn, &sif->TransferSyntax, + &sif->InterfaceId); + } else { + cif = pMsg->RpcInterfaceInformation; + if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ + status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax, + &cif->InterfaceId); + } + + if (status != RPC_S_OK) return status; + + if (bind->server) { + if (pMsg->RpcFlags & WINE_RPCFLAG_EXCEPTION) { + hdr = RPCRT4_BuildFaultHeader(pMsg->DataRepresentation, + RPC_S_CALL_FAILED); + } else { + hdr = RPCRT4_BuildResponseHeader(pMsg->DataRepresentation, + pMsg->BufferLength); + } + } else { + hdr = RPCRT4_BuildRequestHeader(pMsg->DataRepresentation, + pMsg->BufferLength, pMsg->ProcNum, + &bind->ObjectUuid); + } + + status = RPCRT4_Send(conn, hdr, pMsg->Buffer, pMsg->BufferLength); + + RPCRT4_FreeHeader(hdr); + + /* success */ + if (!bind->server) { + /* save the connection, so the response can be read from it */ + pMsg->ReservedForRuntime = conn; + return RPC_S_OK; + } + RPCRT4_CloseBinding(bind, conn); + status = RPC_S_OK; + + return status; +} + +/*********************************************************************** + * I_RpcReceive [RPCRT4.@] + */ +RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg) +{ + RpcBinding* bind = (RpcBinding*)pMsg->Handle; + RpcConnection* conn; + RPC_CLIENT_INTERFACE* cif = NULL; + RPC_SERVER_INTERFACE* sif = NULL; + RPC_STATUS status; + RpcPktHdr *hdr = NULL; + + TRACE("(%p)\n", pMsg); + if (!bind) return RPC_S_INVALID_BINDING; + + if (pMsg->ReservedForRuntime) { + conn = pMsg->ReservedForRuntime; + pMsg->ReservedForRuntime = NULL; + } else { + if (bind->server) { + sif = pMsg->RpcInterfaceInformation; + if (!sif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ + status = RPCRT4_OpenBinding(bind, &conn, &sif->TransferSyntax, + &sif->InterfaceId); + } else { + cif = pMsg->RpcInterfaceInformation; + if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ + status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax, + &cif->InterfaceId); + } + if (status != RPC_S_OK) return status; + } + + status = RPCRT4_Receive(conn, &hdr, pMsg); + if (status != RPC_S_OK) { + WARN("receive failed with error %lx\n", status); + goto fail; + } + + status = RPC_S_PROTOCOL_ERROR; + + switch (hdr->common.ptype) { + case PKT_RESPONSE: + if (bind->server) goto fail; + break; + case PKT_REQUEST: + if (!bind->server) goto fail; + break; + case PKT_FAULT: + pMsg->RpcFlags |= WINE_RPCFLAG_EXCEPTION; + ERR ("we got fault packet with status %lx\n", hdr->fault.status); + status = RPC_S_CALL_FAILED; /* ? */ + goto fail; + default: + WARN("bad packet type %d\n", hdr->common.ptype); + goto fail; + } + + /* success */ + status = RPC_S_OK; + +fail: + if (hdr) { + RPCRT4_FreeHeader(hdr); + } + RPCRT4_CloseBinding(bind, conn); + return status; +} + +/*********************************************************************** + * I_RpcSendReceive [RPCRT4.@] + */ +RPC_STATUS WINAPI I_RpcSendReceive(PRPC_MESSAGE pMsg) +{ + RPC_STATUS status; + + TRACE("(%p)\n", pMsg); + status = I_RpcSend(pMsg); + if (status == RPC_S_OK) + status = I_RpcReceive(pMsg); + return status; +} diff --git a/reactos/lib/rpcrt4/rpc_message.h b/reactos/lib/rpcrt4/rpc_message.h index 9b463992105..18a73a9fb0a 100644 --- a/reactos/lib/rpcrt4/rpc_message.h +++ b/reactos/lib/rpcrt4/rpc_message.h @@ -1,38 +1,38 @@ -/* - * RPC message API - * - * Copyright 2004 Filip Navara - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_RPC_MESSAGE_H -#define __WINE_RPC_MESSAGE_H - -#include "wine/rpcss_shared.h" -#include "rpc_defs.h" - -VOID RPCRT4_BuildCommonHeader(RpcPktHdr *Header, unsigned char PacketType, unsigned long DataRepresentation); -RpcPktHdr *RPCRT4_BuildRequestHeader(unsigned long DataRepresentation, unsigned long BufferLength, unsigned short ProcNum, UUID *ObjectUuid); -RpcPktHdr *RPCRT4_BuildResponseHeader(unsigned long DataRepresentation, unsigned long BufferLength); -RpcPktHdr *RPCRT4_BuildFaultHeader(unsigned long DataRepresentation, RPC_STATUS Status); -RpcPktHdr *RPCRT4_BuildBindHeader(unsigned long DataRepresentation, unsigned short MaxTransmissionSize, unsigned short MaxReceiveSize, RPC_SYNTAX_IDENTIFIER *AbstractId, RPC_SYNTAX_IDENTIFIER *TransferId); -RpcPktHdr *RPCRT4_BuildBindNackHeader(unsigned long DataRepresentation, unsigned char RpcVersion, unsigned char RpcVersionMinor); -RpcPktHdr *RPCRT4_BuildBindAckHeader(unsigned long DataRepresentation, unsigned short MaxTransmissionSize, unsigned short MaxReceiveSize, LPSTR ServerAddress, unsigned long Result, unsigned long Reason, RPC_SYNTAX_IDENTIFIER *TransferId); -VOID RPCRT4_FreeHeader(RpcPktHdr *Header); -RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header, void *Buffer, unsigned int BufferLength); -RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header, PRPC_MESSAGE pMsg); - -#endif +/* + * RPC message API + * + * Copyright 2004 Filip Navara + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_RPC_MESSAGE_H +#define __WINE_RPC_MESSAGE_H + +#include "wine/rpcss_shared.h" +#include "rpc_defs.h" + +VOID RPCRT4_BuildCommonHeader(RpcPktHdr *Header, unsigned char PacketType, unsigned long DataRepresentation); +RpcPktHdr *RPCRT4_BuildRequestHeader(unsigned long DataRepresentation, unsigned long BufferLength, unsigned short ProcNum, UUID *ObjectUuid); +RpcPktHdr *RPCRT4_BuildResponseHeader(unsigned long DataRepresentation, unsigned long BufferLength); +RpcPktHdr *RPCRT4_BuildFaultHeader(unsigned long DataRepresentation, RPC_STATUS Status); +RpcPktHdr *RPCRT4_BuildBindHeader(unsigned long DataRepresentation, unsigned short MaxTransmissionSize, unsigned short MaxReceiveSize, RPC_SYNTAX_IDENTIFIER *AbstractId, RPC_SYNTAX_IDENTIFIER *TransferId); +RpcPktHdr *RPCRT4_BuildBindNackHeader(unsigned long DataRepresentation, unsigned char RpcVersion, unsigned char RpcVersionMinor); +RpcPktHdr *RPCRT4_BuildBindAckHeader(unsigned long DataRepresentation, unsigned short MaxTransmissionSize, unsigned short MaxReceiveSize, LPSTR ServerAddress, unsigned long Result, unsigned long Reason, RPC_SYNTAX_IDENTIFIER *TransferId); +VOID RPCRT4_FreeHeader(RpcPktHdr *Header); +RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header, void *Buffer, unsigned int BufferLength); +RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header, PRPC_MESSAGE pMsg); + +#endif diff --git a/reactos/lib/rpcrt4/rpc_misc.h b/reactos/lib/rpcrt4/rpc_misc.h index c94d72a6ea4..49c483e5c4b 100644 --- a/reactos/lib/rpcrt4/rpc_misc.h +++ b/reactos/lib/rpcrt4/rpc_misc.h @@ -1,28 +1,28 @@ -/* - * RPC definitions - * - * Copyright 2003 Ove Kåven, TransGaming Technologies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef __WINE_RPC_MISC_H -#define __WINE_RPC_MISC_H - -/* flags for RPC_MESSAGE.RpcFlags */ -#define WINE_RPCFLAG_EXCEPTION 0x0001 - -#endif /* __WINE_RPC_MISC_H */ +/* + * RPC definitions + * + * Copyright 2003 Ove Kåven, TransGaming Technologies + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __WINE_RPC_MISC_H +#define __WINE_RPC_MISC_H + +/* flags for RPC_MESSAGE.RpcFlags */ +#define WINE_RPCFLAG_EXCEPTION 0x0001 + +#endif /* __WINE_RPC_MISC_H */ diff --git a/reactos/lib/rpcrt4/rpc_server.c b/reactos/lib/rpcrt4/rpc_server.c index 507e3f39159..20f6ca67301 100644 --- a/reactos/lib/rpcrt4/rpc_server.c +++ b/reactos/lib/rpcrt4/rpc_server.c @@ -1,1061 +1,1061 @@ -/* - * RPC server API - * - * Copyright 2001 Ove Kåven, TransGaming Technologies - * Copyright 2004 Filip Navara - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * TODO: - * - a whole lot - */ - -#include "config.h" -#include "wine/port.h" - -#include <stdarg.h> -#include <stdio.h> -#include <string.h> -#include <assert.h> - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "winreg.h" -#include "ntstatus.h" - -#include "rpc.h" -#include "rpcndr.h" -#include "excpt.h" - -#include "wine/debug.h" -#include "wine/exception.h" - -#include "rpc_server.h" -#include "rpc_misc.h" -#include "rpc_message.h" -#include "rpc_defs.h" - -#define MAX_THREADS 128 - -WINE_DEFAULT_DEBUG_CHANNEL(rpc); - -typedef struct _RpcPacket -{ - struct _RpcPacket* next; - struct _RpcConnection* conn; - RpcPktHdr* hdr; - RPC_MESSAGE* msg; -} RpcPacket; - -typedef struct _RpcObjTypeMap -{ - /* FIXME: a hash table would be better. */ - struct _RpcObjTypeMap *next; - UUID Object; - UUID Type; -} RpcObjTypeMap; - -static RpcObjTypeMap *RpcObjTypeMaps; - -static RpcServerProtseq* protseqs; -static RpcServerInterface* ifs; - -static CRITICAL_SECTION server_cs; -static CRITICAL_SECTION_DEBUG server_cs_debug = -{ - 0, 0, &server_cs, - { &server_cs_debug.ProcessLocksList, &server_cs_debug.ProcessLocksList }, - 0, 0, { 0, (DWORD)(__FILE__ ": server_cs") } -}; -static CRITICAL_SECTION server_cs = { &server_cs_debug, -1, 0, 0, 0, 0 }; - -static CRITICAL_SECTION listen_cs; -static CRITICAL_SECTION_DEBUG listen_cs_debug = -{ - 0, 0, &listen_cs, - { &listen_cs_debug.ProcessLocksList, &listen_cs_debug.ProcessLocksList }, - 0, 0, { 0, (DWORD)(__FILE__ ": listen_cs") } -}; -static CRITICAL_SECTION listen_cs = { &listen_cs_debug, -1, 0, 0, 0, 0 }; - -/* whether the server is currently listening */ -static BOOL std_listen; -/* number of manual listeners (calls to RpcServerListen) */ -static LONG manual_listen_count; -/* total listeners including auto listeners */ -static LONG listen_count; -/* set on change of configuration (e.g. listening on new protseq) */ -static HANDLE mgr_event; -/* mutex for ensuring only one thread can change state at a time */ -static HANDLE mgr_mutex; -/* set when server thread has finished opening connections */ -static HANDLE server_ready_event; - -static CRITICAL_SECTION spacket_cs; -static CRITICAL_SECTION_DEBUG spacket_cs_debug = -{ - 0, 0, &spacket_cs, - { &spacket_cs_debug.ProcessLocksList, &spacket_cs_debug.ProcessLocksList }, - 0, 0, { 0, (DWORD)(__FILE__ ": spacket_cs") } -}; -static CRITICAL_SECTION spacket_cs = { &spacket_cs_debug, -1, 0, 0, 0, 0 }; - -static RpcPacket* spacket_head; -static RpcPacket* spacket_tail; -static HANDLE server_sem; - -static DWORD worker_count, worker_free, worker_tls; - -static UUID uuid_nil; - -inline static RpcObjTypeMap *LookupObjTypeMap(UUID *ObjUuid) -{ - RpcObjTypeMap *rslt = RpcObjTypeMaps; - RPC_STATUS dummy; - - while (rslt) { - if (! UuidCompare(ObjUuid, &rslt->Object, &dummy)) break; - rslt = rslt->next; - } - - return rslt; -} - -inline static UUID *LookupObjType(UUID *ObjUuid) -{ - RpcObjTypeMap *map = LookupObjTypeMap(ObjUuid); - if (map) - return &map->Type; - else - return &uuid_nil; -} - -static RpcServerInterface* RPCRT4_find_interface(UUID* object, - RPC_SYNTAX_IDENTIFIER* if_id, - BOOL check_object) -{ - UUID* MgrType = NULL; - RpcServerInterface* cif = NULL; - RPC_STATUS status; - - if (check_object) - MgrType = LookupObjType(object); - EnterCriticalSection(&server_cs); - cif = ifs; - while (cif) { - if (!memcmp(if_id, &cif->If->InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER)) && - (check_object == FALSE || UuidEqual(MgrType, &cif->MgrTypeUuid, &status)) && - std_listen) break; - cif = cif->Next; - } - LeaveCriticalSection(&server_cs); - TRACE("returning %p for %s\n", cif, debugstr_guid(object)); - return cif; -} - -static void RPCRT4_push_packet(RpcPacket* packet) -{ - packet->next = NULL; - EnterCriticalSection(&spacket_cs); - if (spacket_tail) { - spacket_tail->next = packet; - spacket_tail = packet; - } else { - spacket_head = packet; - spacket_tail = packet; - } - LeaveCriticalSection(&spacket_cs); -} - -static RpcPacket* RPCRT4_pop_packet(void) -{ - RpcPacket* packet; - EnterCriticalSection(&spacket_cs); - packet = spacket_head; - if (packet) { - spacket_head = packet->next; - if (!spacket_head) spacket_tail = NULL; - } - LeaveCriticalSection(&spacket_cs); - if (packet) packet->next = NULL; - return packet; -} - -#ifndef __REACTOS__ -typedef struct { - PRPC_MESSAGE msg; - void* buf; -} packet_state; - -static WINE_EXCEPTION_FILTER(rpc_filter) -{ - packet_state* state; - PRPC_MESSAGE msg; - state = TlsGetValue(worker_tls); - msg = state->msg; - if (msg->Buffer != state->buf) I_RpcFreeBuffer(msg); - msg->RpcFlags |= WINE_RPCFLAG_EXCEPTION; - msg->BufferLength = sizeof(DWORD); - I_RpcGetBuffer(msg); - *(DWORD*)msg->Buffer = GetExceptionCode(); - WARN("exception caught with code 0x%08lx = %ld\n", *(DWORD*)msg->Buffer, *(DWORD*)msg->Buffer); - TRACE("returning failure packet\n"); - return EXCEPTION_EXECUTE_HANDLER; -} -#endif - -static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSAGE* msg) -{ - RpcServerInterface* sif; - RPC_DISPATCH_FUNCTION func; -#ifndef __REACTOS__ - packet_state state; -#endif - UUID *object_uuid; - RpcPktHdr *response; - void *buf = msg->Buffer; - RPC_STATUS status; - -#ifndef __REACTOS__ - state.msg = msg; - state.buf = buf; - TlsSetValue(worker_tls, &state); -#endif - - switch (hdr->common.ptype) { - case PKT_BIND: - TRACE("got bind packet\n"); - - /* FIXME: do more checks! */ - if (hdr->bind.max_tsize < RPC_MIN_PACKET_SIZE || - !UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) { - TRACE("packet size less than min size, or active interface syntax guid non-null\n"); - sif = NULL; - } else { - sif = RPCRT4_find_interface(NULL, &hdr->bind.abstract, FALSE); - } - if (sif == NULL) { - TRACE("rejecting bind request on connection %p\n", conn); - /* Report failure to client. */ - response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION, - RPC_VER_MAJOR, RPC_VER_MINOR); - } else { - TRACE("accepting bind request on connection %p\n", conn); - - /* accept. */ - response = RPCRT4_BuildBindAckHeader(NDR_LOCAL_DATA_REPRESENTATION, - RPC_MAX_PACKET_SIZE, - RPC_MAX_PACKET_SIZE, - conn->Endpoint, - RESULT_ACCEPT, NO_REASON, - &sif->If->TransferSyntax); - - /* save the interface for later use */ - conn->ActiveInterface = hdr->bind.abstract; - conn->MaxTransmissionSize = hdr->bind.max_tsize; - } - - if (RPCRT4_Send(conn, response, NULL, 0) != RPC_S_OK) - goto fail; - - break; - - case PKT_REQUEST: - TRACE("got request packet\n"); - - /* fail if the connection isn't bound with an interface */ - if (UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) { - response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION, - status); - - RPCRT4_Send(conn, response, NULL, 0); - break; - } - - if (hdr->common.flags & RPC_FLG_OBJECT_UUID) { - object_uuid = (UUID*)(&hdr->request + 1); - } else { - object_uuid = NULL; - } - - sif = RPCRT4_find_interface(object_uuid, &conn->ActiveInterface, TRUE); - msg->RpcInterfaceInformation = sif->If; - /* copy the endpoint vector from sif to msg so that midl-generated code will use it */ - msg->ManagerEpv = sif->MgrEpv; - if (object_uuid != NULL) { - RPCRT4_SetBindingObject(msg->Handle, object_uuid); - } - - /* find dispatch function */ - msg->ProcNum = hdr->request.opnum; - if (sif->Flags & RPC_IF_OLE) { - /* native ole32 always gives us a dispatch table with a single entry - * (I assume that's a wrapper for IRpcStubBuffer::Invoke) */ - func = *sif->If->DispatchTable->DispatchTable; - } else { - if (msg->ProcNum >= sif->If->DispatchTable->DispatchTableCount) { - ERR("invalid procnum\n"); - func = NULL; - } - func = sif->If->DispatchTable->DispatchTable[msg->ProcNum]; - } - - /* put in the drep. FIXME: is this more universally applicable? - perhaps we should move this outward... */ - msg->DataRepresentation = - MAKELONG( MAKEWORD(hdr->common.drep[0], hdr->common.drep[1]), - MAKEWORD(hdr->common.drep[2], hdr->common.drep[3])); - - /* dispatch */ -#ifndef __REACTOS__ - __TRY { - if (func) func(msg); - } __EXCEPT(rpc_filter) { - /* failure packet was created in rpc_filter */ - } __ENDTRY -#else - if (func) func(msg); -#endif - - /* send response packet */ - I_RpcSend(msg); - - msg->RpcInterfaceInformation = NULL; - - break; - - default: - FIXME("unhandled packet type\n"); - break; - } - -fail: - /* clean up */ - if (msg->Buffer == buf) msg->Buffer = NULL; - TRACE("freeing Buffer=%p\n", buf); - HeapFree(GetProcessHeap(), 0, buf); - RPCRT4_DestroyBinding(msg->Handle); - msg->Handle = 0; - I_RpcFreeBuffer(msg); - msg->Buffer = NULL; - RPCRT4_FreeHeader(hdr); -#ifndef __REACTOS__ - TlsSetValue(worker_tls, NULL); -#endif -} - -static DWORD CALLBACK RPCRT4_worker_thread(LPVOID the_arg) -{ - DWORD obj; - RpcPacket* pkt; - - for (;;) { - /* idle timeout after 5s */ - obj = WaitForSingleObject(server_sem, 5000); - if (obj == WAIT_TIMEOUT) { - /* if another idle thread exist, self-destruct */ - if (worker_free > 1) break; - continue; - } - pkt = RPCRT4_pop_packet(); - if (!pkt) continue; - InterlockedDecrement(&worker_free); - for (;;) { - RPCRT4_process_packet(pkt->conn, pkt->hdr, pkt->msg); - HeapFree(GetProcessHeap(), 0, pkt); - /* try to grab another packet here without waiting - * on the semaphore, in case it hits max */ - pkt = RPCRT4_pop_packet(); - if (!pkt) break; - /* decrement semaphore */ - WaitForSingleObject(server_sem, 0); - } - InterlockedIncrement(&worker_free); - } - InterlockedDecrement(&worker_free); - InterlockedDecrement(&worker_count); - return 0; -} - -static void RPCRT4_create_worker_if_needed(void) -{ - if (!worker_free && worker_count < MAX_THREADS) { - HANDLE thread; - InterlockedIncrement(&worker_count); - InterlockedIncrement(&worker_free); - thread = CreateThread(NULL, 0, RPCRT4_worker_thread, NULL, 0, NULL); - if (thread) CloseHandle(thread); - else { - InterlockedDecrement(&worker_free); - InterlockedDecrement(&worker_count); - } - } -} - -static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg) -{ - RpcConnection* conn = (RpcConnection*)the_arg; - RpcPktHdr *hdr; - RpcBinding *pbind; - RPC_MESSAGE *msg; - RPC_STATUS status; - RpcPacket *packet; - - TRACE("(%p)\n", conn); - - for (;;) { - msg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_MESSAGE)); - - /* create temporary binding for dispatch, it will be freed in - * RPCRT4_process_packet */ - RPCRT4_MakeBinding(&pbind, conn); - msg->Handle = (RPC_BINDING_HANDLE)pbind; - - status = RPCRT4_Receive(conn, &hdr, msg); - if (status != RPC_S_OK) { - WARN("receive failed with error %lx\n", status); - break; - } - -#if 0 - RPCRT4_process_packet(conn, hdr, msg); -#else - packet = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcPacket)); - packet->conn = conn; - packet->hdr = hdr; - packet->msg = msg; - RPCRT4_create_worker_if_needed(); - RPCRT4_push_packet(packet); - ReleaseSemaphore(server_sem, 1, NULL); -#endif - msg = NULL; - } - HeapFree(GetProcessHeap(), 0, msg); - RPCRT4_DestroyConnection(conn); - return 0; -} - -static void RPCRT4_new_client(RpcConnection* conn) -{ - HANDLE thread = CreateThread(NULL, 0, RPCRT4_io_thread, conn, 0, NULL); - if (!thread) { - DWORD err = GetLastError(); - ERR("failed to create thread, error=%08lx\n", err); - RPCRT4_DestroyConnection(conn); - } - /* we could set conn->thread, but then we'd have to make the io_thread wait - * for that, otherwise the thread might finish, destroy the connection, and - * free the memory we'd write to before we did, causing crashes and stuff - - * so let's implement that later, when we really need conn->thread */ - - CloseHandle( thread ); -} - -static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg) -{ - HANDLE m_event = mgr_event, b_handle; - HANDLE *objs = NULL; - DWORD count, res; - RpcServerProtseq* cps; - RpcConnection* conn; - RpcConnection* cconn; - BOOL set_ready_event = FALSE; - - TRACE("(the_arg == ^%p)\n", the_arg); - - for (;;) { - EnterCriticalSection(&server_cs); - /* open and count connections */ - count = 1; - cps = protseqs; - while (cps) { - conn = cps->conn; - while (conn) { - RPCRT4_OpenConnection(conn); - if (conn->ovl[0].hEvent) count++; - conn = conn->Next; - } - cps = cps->Next; - } - /* make array of connections */ - if (objs) - objs = HeapReAlloc(GetProcessHeap(), 0, objs, count*sizeof(HANDLE)); - else - objs = HeapAlloc(GetProcessHeap(), 0, count*sizeof(HANDLE)); - - objs[0] = m_event; - count = 1; - cps = protseqs; - while (cps) { - conn = cps->conn; - while (conn) { - if (conn->ovl[0].hEvent) objs[count++] = conn->ovl[0].hEvent; - conn = conn->Next; - } - cps = cps->Next; - } - LeaveCriticalSection(&server_cs); - - if (set_ready_event) - { - /* signal to function that changed state that we are now sync'ed */ - SetEvent(server_ready_event); - set_ready_event = FALSE; - } - - /* start waiting */ - res = WaitForMultipleObjects(count, objs, FALSE, INFINITE); - if (res == WAIT_OBJECT_0) { - if (!std_listen) - { - SetEvent(server_ready_event); - break; - } - set_ready_event = TRUE; - } - else if (res == WAIT_FAILED) { - ERR("wait failed\n"); - } - else { - b_handle = objs[res - WAIT_OBJECT_0]; - /* find which connection got a RPC */ - EnterCriticalSection(&server_cs); - conn = NULL; - cps = protseqs; - while (cps) { - conn = cps->conn; - while (conn) { - if (conn->ovl[0].hEvent == b_handle) break; - conn = conn->Next; - } - if (conn) break; - cps = cps->Next; - } - cconn = NULL; - if (conn) RPCRT4_SpawnConnection(&cconn, conn); - LeaveCriticalSection(&server_cs); - if (!conn) { - ERR("failed to locate connection for handle %p\n", b_handle); - } - if (cconn) RPCRT4_new_client(cconn); - } - } - HeapFree(GetProcessHeap(), 0, objs); - EnterCriticalSection(&server_cs); - /* close connections */ - cps = protseqs; - while (cps) { - conn = cps->conn; - while (conn) { - RPCRT4_CloseConnection(conn); - conn = conn->Next; - } - cps = cps->Next; - } - LeaveCriticalSection(&server_cs); - return 0; -} - -/* tells the server thread that the state has changed and waits for it to - * make the changes */ -static void RPCRT4_sync_with_server_thread(void) -{ - /* make sure we are the only thread sync'ing the server state, otherwise - * there is a race with the server thread setting an older state and setting - * the server_ready_event when the new state hasn't yet been applied */ - WaitForSingleObject(mgr_mutex, INFINITE); - - SetEvent(mgr_event); - /* wait for server thread to make the requested changes before returning */ - WaitForSingleObject(server_ready_event, INFINITE); - - ReleaseMutex(mgr_mutex); -} - -static RPC_STATUS RPCRT4_start_listen(BOOL auto_listen) -{ - RPC_STATUS status = RPC_S_ALREADY_LISTENING; - - TRACE("\n"); - - EnterCriticalSection(&listen_cs); - if (auto_listen || (manual_listen_count++ == 0)) - { - status = RPC_S_OK; - if (++listen_count == 1) { - HANDLE server_thread; - /* first listener creates server thread */ - if (!mgr_mutex) mgr_mutex = CreateMutexW(NULL, FALSE, NULL); - if (!mgr_event) mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL); - if (!server_ready_event) server_ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); - if (!server_sem) server_sem = CreateSemaphoreW(NULL, 0, MAX_THREADS, NULL); - if (!worker_tls) worker_tls = TlsAlloc(); - std_listen = TRUE; - server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, NULL, 0, NULL); - CloseHandle(server_thread); - } - } - LeaveCriticalSection(&listen_cs); - - return status; -} - -static void RPCRT4_stop_listen(BOOL auto_listen) -{ - EnterCriticalSection(&listen_cs); - if (auto_listen || (--manual_listen_count == 0)) - { - if (listen_count != 0 && --listen_count == 0) { - std_listen = FALSE; - LeaveCriticalSection(&listen_cs); - RPCRT4_sync_with_server_thread(); - return; - } - assert(listen_count >= 0); - } - LeaveCriticalSection(&listen_cs); -} - -static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps) -{ - RPCRT4_CreateConnection(&ps->conn, TRUE, ps->Protseq, NULL, ps->Endpoint, NULL, NULL); - - EnterCriticalSection(&server_cs); - ps->Next = protseqs; - protseqs = ps; - LeaveCriticalSection(&server_cs); - - if (std_listen) RPCRT4_sync_with_server_thread(); - - return RPC_S_OK; -} - -/*********************************************************************** - * RpcServerInqBindings (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector ) -{ - RPC_STATUS status; - DWORD count; - RpcServerProtseq* ps; - RpcConnection* conn; - - if (BindingVector) - TRACE("(*BindingVector == ^%p)\n", *BindingVector); - else - ERR("(BindingVector == NULL!!?)\n"); - - EnterCriticalSection(&server_cs); - /* count connections */ - count = 0; - ps = protseqs; - while (ps) { - conn = ps->conn; - while (conn) { - count++; - conn = conn->Next; - } - ps = ps->Next; - } - if (count) { - /* export bindings */ - *BindingVector = HeapAlloc(GetProcessHeap(), 0, - sizeof(RPC_BINDING_VECTOR) + - sizeof(RPC_BINDING_HANDLE)*(count-1)); - (*BindingVector)->Count = count; - count = 0; - ps = protseqs; - while (ps) { - conn = ps->conn; - while (conn) { - RPCRT4_MakeBinding((RpcBinding**)&(*BindingVector)->BindingH[count], - conn); - count++; - conn = conn->Next; - } - ps = ps->Next; - } - status = RPC_S_OK; - } else { - *BindingVector = NULL; - status = RPC_S_NO_BINDINGS; - } - LeaveCriticalSection(&server_cs); - return status; -} - -/*********************************************************************** - * RpcServerUseProtseqEpA (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcServerUseProtseqEpA( unsigned char *Protseq, UINT MaxCalls, unsigned char *Endpoint, LPVOID SecurityDescriptor ) -{ - RPC_POLICY policy; - - TRACE( "(%s,%u,%s,%p)\n", Protseq, MaxCalls, Endpoint, SecurityDescriptor ); - - /* This should provide the default behaviour */ - policy.Length = sizeof( policy ); - policy.EndpointFlags = 0; - policy.NICFlags = 0; - - return RpcServerUseProtseqEpExA( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy ); -} - -/*********************************************************************** - * RpcServerUseProtseqEpW (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcServerUseProtseqEpW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor ) -{ - RPC_POLICY policy; - - TRACE( "(%s,%u,%s,%p)\n", debugstr_w( Protseq ), MaxCalls, debugstr_w( Endpoint ), SecurityDescriptor ); - - /* This should provide the default behaviour */ - policy.Length = sizeof( policy ); - policy.EndpointFlags = 0; - policy.NICFlags = 0; - - return RpcServerUseProtseqEpExW( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy ); -} - -/*********************************************************************** - * RpcServerUseProtseqEpExA (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcServerUseProtseqEpExA( unsigned char *Protseq, UINT MaxCalls, unsigned char *Endpoint, LPVOID SecurityDescriptor, - PRPC_POLICY lpPolicy ) -{ - RpcServerProtseq* ps; - - TRACE("(%s,%u,%s,%p,{%u,%lu,%lu})\n", debugstr_a( Protseq ), MaxCalls, - debugstr_a( Endpoint ), SecurityDescriptor, - lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags ); - - ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerProtseq)); - ps->MaxCalls = MaxCalls; - ps->Protseq = RPCRT4_strdupA(Protseq); - ps->Endpoint = RPCRT4_strdupA(Endpoint); - - return RPCRT4_use_protseq(ps); -} - -/*********************************************************************** - * RpcServerUseProtseqEpExW (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcServerUseProtseqEpExW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor, - PRPC_POLICY lpPolicy ) -{ - RpcServerProtseq* ps; - - TRACE("(%s,%u,%s,%p,{%u,%lu,%lu})\n", debugstr_w( Protseq ), MaxCalls, - debugstr_w( Endpoint ), SecurityDescriptor, - lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags ); - - ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerProtseq)); - ps->MaxCalls = MaxCalls; - ps->Protseq = RPCRT4_strdupWtoA(Protseq); - ps->Endpoint = RPCRT4_strdupWtoA(Endpoint); - - return RPCRT4_use_protseq(ps); -} - -/*********************************************************************** - * RpcServerUseProtseqA (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcServerUseProtseqA(unsigned char *Protseq, unsigned int MaxCalls, void *SecurityDescriptor) -{ - TRACE("(Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_a(Protseq), MaxCalls, SecurityDescriptor); - return RpcServerUseProtseqEpA(Protseq, MaxCalls, NULL, SecurityDescriptor); -} - -/*********************************************************************** - * RpcServerUseProtseqW (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcServerUseProtseqW(LPWSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor) -{ - TRACE("Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_w(Protseq), MaxCalls, SecurityDescriptor); - return RpcServerUseProtseqEpW(Protseq, MaxCalls, NULL, SecurityDescriptor); -} - -/*********************************************************************** - * RpcServerRegisterIf (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcServerRegisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv ) -{ - TRACE("(%p,%s,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv); - return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, 0, RPC_C_LISTEN_MAX_CALLS_DEFAULT, (UINT)-1, NULL ); -} - -/*********************************************************************** - * RpcServerRegisterIfEx (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcServerRegisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv, - UINT Flags, UINT MaxCalls, RPC_IF_CALLBACK_FN* IfCallbackFn ) -{ - TRACE("(%p,%s,%p,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls, IfCallbackFn); - return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, Flags, MaxCalls, (UINT)-1, IfCallbackFn ); -} - -/*********************************************************************** - * RpcServerRegisterIf2 (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcServerRegisterIf2( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv, - UINT Flags, UINT MaxCalls, UINT MaxRpcSize, RPC_IF_CALLBACK_FN* IfCallbackFn ) -{ - PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec; - RpcServerInterface* sif; - unsigned int i; - - TRACE("(%p,%s,%p,%u,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls, - MaxRpcSize, IfCallbackFn); - TRACE(" interface id: %s %d.%d\n", debugstr_guid(&If->InterfaceId.SyntaxGUID), - If->InterfaceId.SyntaxVersion.MajorVersion, - If->InterfaceId.SyntaxVersion.MinorVersion); - TRACE(" transfer syntax: %s %d.%d\n", debugstr_guid(&If->TransferSyntax.SyntaxGUID), - If->TransferSyntax.SyntaxVersion.MajorVersion, - If->TransferSyntax.SyntaxVersion.MinorVersion); - TRACE(" dispatch table: %p\n", If->DispatchTable); - if (If->DispatchTable) { - TRACE(" dispatch table count: %d\n", If->DispatchTable->DispatchTableCount); - for (i=0; i<If->DispatchTable->DispatchTableCount; i++) { - TRACE(" entry %d: %p\n", i, If->DispatchTable->DispatchTable[i]); - } - TRACE(" reserved: %ld\n", If->DispatchTable->Reserved); - } - TRACE(" protseq endpoint count: %d\n", If->RpcProtseqEndpointCount); - TRACE(" default manager epv: %p\n", If->DefaultManagerEpv); - TRACE(" interpreter info: %p\n", If->InterpreterInfo); - - sif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerInterface)); - sif->If = If; - if (MgrTypeUuid) { - memcpy(&sif->MgrTypeUuid, MgrTypeUuid, sizeof(UUID)); - sif->MgrEpv = MgrEpv; - } else { - memset(&sif->MgrTypeUuid, 0, sizeof(UUID)); - sif->MgrEpv = If->DefaultManagerEpv; - } - sif->Flags = Flags; - sif->MaxCalls = MaxCalls; - sif->MaxRpcSize = MaxRpcSize; - sif->IfCallbackFn = IfCallbackFn; - - EnterCriticalSection(&server_cs); - sif->Next = ifs; - ifs = sif; - LeaveCriticalSection(&server_cs); - - if (sif->Flags & RPC_IF_AUTOLISTEN) { - /* well, start listening, I think... */ - RPCRT4_start_listen(TRUE); - } - - return RPC_S_OK; -} - -/*********************************************************************** - * RpcServerUnregisterIf (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcServerUnregisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, UINT WaitForCallsToComplete ) -{ - FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, WaitForCallsToComplete == %u): stub\n", - IfSpec, debugstr_guid(MgrTypeUuid), WaitForCallsToComplete); - - return RPC_S_OK; -} - -/*********************************************************************** - * RpcServerUnregisterIfEx (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcServerUnregisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, int RundownContextHandles ) -{ - FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, RundownContextHandles == %d): stub\n", - IfSpec, debugstr_guid(MgrTypeUuid), RundownContextHandles); - - return RPC_S_OK; -} - -/*********************************************************************** - * RpcObjectSetType (RPCRT4.@) - * - * PARAMS - * ObjUuid [I] "Object" UUID - * TypeUuid [I] "Type" UUID - * - * RETURNS - * RPC_S_OK The call succeeded - * RPC_S_INVALID_OBJECT The provided object (nil) is not valid - * RPC_S_ALREADY_REGISTERED The provided object is already registered - * - * Maps "Object" UUIDs to "Type" UUID's. Passing the nil UUID as the type - * resets the mapping for the specified object UUID to nil (the default). - * The nil object is always associated with the nil type and cannot be - * reassigned. Servers can support multiple implementations on the same - * interface by registering different end-point vectors for the different - * types. There's no need to call this if a server only supports the nil - * type, as is typical. - */ -RPC_STATUS WINAPI RpcObjectSetType( UUID* ObjUuid, UUID* TypeUuid ) -{ - RpcObjTypeMap *map = RpcObjTypeMaps, *prev = NULL; - RPC_STATUS dummy; - - TRACE("(ObjUUID == %s, TypeUuid == %s).\n", debugstr_guid(ObjUuid), debugstr_guid(TypeUuid)); - if ((! ObjUuid) || UuidIsNil(ObjUuid, &dummy)) { - /* nil uuid cannot be remapped */ - return RPC_S_INVALID_OBJECT; - } - - /* find the mapping for this object if there is one ... */ - while (map) { - if (! UuidCompare(ObjUuid, &map->Object, &dummy)) break; - prev = map; - map = map->next; - } - if ((! TypeUuid) || UuidIsNil(TypeUuid, &dummy)) { - /* ... and drop it from the list */ - if (map) { - if (prev) - prev->next = map->next; - else - RpcObjTypeMaps = map->next; - HeapFree(GetProcessHeap(), 0, map); - } - } else { - /* ... , fail if we found it ... */ - if (map) - return RPC_S_ALREADY_REGISTERED; - /* ... otherwise create a new one and add it in. */ - map = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcObjTypeMap)); - memcpy(&map->Object, ObjUuid, sizeof(UUID)); - memcpy(&map->Type, TypeUuid, sizeof(UUID)); - map->next = NULL; - if (prev) - prev->next = map; /* prev is the last map in the linklist */ - else - RpcObjTypeMaps = map; - } - - return RPC_S_OK; -} - -/*********************************************************************** - * RpcServerRegisterAuthInfoA (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcServerRegisterAuthInfoA( unsigned char *ServerPrincName, unsigned long AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn, - LPVOID Arg ) -{ - FIXME( "(%s,%lu,%p,%p): stub\n", ServerPrincName, AuthnSvc, GetKeyFn, Arg ); - - return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */ -} - -/*********************************************************************** - * RpcServerRegisterAuthInfoW (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcServerRegisterAuthInfoW( LPWSTR ServerPrincName, unsigned long AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn, - LPVOID Arg ) -{ - FIXME( "(%s,%lu,%p,%p): stub\n", debugstr_w( ServerPrincName ), AuthnSvc, GetKeyFn, Arg ); - - return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */ -} - -/*********************************************************************** - * RpcServerListen (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcServerListen( UINT MinimumCallThreads, UINT MaxCalls, UINT DontWait ) -{ - RPC_STATUS status; - - TRACE("(%u,%u,%u)\n", MinimumCallThreads, MaxCalls, DontWait); - - if (!protseqs) - return RPC_S_NO_PROTSEQS_REGISTERED; - - status = RPCRT4_start_listen(FALSE); - - if (DontWait || (status != RPC_S_OK)) return status; - - return RpcMgmtWaitServerListen(); -} - -/*********************************************************************** - * RpcMgmtServerWaitListen (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcMgmtWaitServerListen( void ) -{ - TRACE("()\n"); - - EnterCriticalSection(&listen_cs); - - if (!std_listen) { - LeaveCriticalSection(&listen_cs); - return RPC_S_NOT_LISTENING; - } - - LeaveCriticalSection(&listen_cs); - - RPCRT4_sync_with_server_thread(); - - return RPC_S_OK; -} - -/*********************************************************************** - * RpcMgmtStopServerListening (RPCRT4.@) - */ -RPC_STATUS WINAPI RpcMgmtStopServerListening ( RPC_BINDING_HANDLE Binding ) -{ - TRACE("(Binding == (RPC_BINDING_HANDLE)^%p)\n", Binding); - - if (Binding) { - FIXME("client-side invocation not implemented.\n"); - return RPC_S_WRONG_KIND_OF_BINDING; - } - - RPCRT4_stop_listen(FALSE); - - return RPC_S_OK; -} - -/*********************************************************************** - * I_RpcServerStartListening (RPCRT4.@) - */ -RPC_STATUS WINAPI I_RpcServerStartListening( HWND hWnd ) -{ - FIXME( "(%p): stub\n", hWnd ); - - return RPC_S_OK; -} - -/*********************************************************************** - * I_RpcServerStopListening (RPCRT4.@) - */ -RPC_STATUS WINAPI I_RpcServerStopListening( void ) -{ - FIXME( "(): stub\n" ); - - return RPC_S_OK; -} - -/*********************************************************************** - * I_RpcWindowProc (RPCRT4.@) - */ -UINT WINAPI I_RpcWindowProc( void *hWnd, UINT Message, UINT wParam, ULONG lParam ) -{ - FIXME( "(%p,%08x,%08x,%08lx): stub\n", hWnd, Message, wParam, lParam ); - - return 0; -} +/* + * RPC server API + * + * Copyright 2001 Ove Kåven, TransGaming Technologies + * Copyright 2004 Filip Navara + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * TODO: + * - a whole lot + */ + +#include "config.h" +#include "wine/port.h" + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" +#include "ntstatus.h" + +#include "rpc.h" +#include "rpcndr.h" +#include "excpt.h" + +#include "wine/debug.h" +#include "wine/exception.h" + +#include "rpc_server.h" +#include "rpc_misc.h" +#include "rpc_message.h" +#include "rpc_defs.h" + +#define MAX_THREADS 128 + +WINE_DEFAULT_DEBUG_CHANNEL(rpc); + +typedef struct _RpcPacket +{ + struct _RpcPacket* next; + struct _RpcConnection* conn; + RpcPktHdr* hdr; + RPC_MESSAGE* msg; +} RpcPacket; + +typedef struct _RpcObjTypeMap +{ + /* FIXME: a hash table would be better. */ + struct _RpcObjTypeMap *next; + UUID Object; + UUID Type; +} RpcObjTypeMap; + +static RpcObjTypeMap *RpcObjTypeMaps; + +static RpcServerProtseq* protseqs; +static RpcServerInterface* ifs; + +static CRITICAL_SECTION server_cs; +static CRITICAL_SECTION_DEBUG server_cs_debug = +{ + 0, 0, &server_cs, + { &server_cs_debug.ProcessLocksList, &server_cs_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": server_cs") } +}; +static CRITICAL_SECTION server_cs = { &server_cs_debug, -1, 0, 0, 0, 0 }; + +static CRITICAL_SECTION listen_cs; +static CRITICAL_SECTION_DEBUG listen_cs_debug = +{ + 0, 0, &listen_cs, + { &listen_cs_debug.ProcessLocksList, &listen_cs_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": listen_cs") } +}; +static CRITICAL_SECTION listen_cs = { &listen_cs_debug, -1, 0, 0, 0, 0 }; + +/* whether the server is currently listening */ +static BOOL std_listen; +/* number of manual listeners (calls to RpcServerListen) */ +static LONG manual_listen_count; +/* total listeners including auto listeners */ +static LONG listen_count; +/* set on change of configuration (e.g. listening on new protseq) */ +static HANDLE mgr_event; +/* mutex for ensuring only one thread can change state at a time */ +static HANDLE mgr_mutex; +/* set when server thread has finished opening connections */ +static HANDLE server_ready_event; + +static CRITICAL_SECTION spacket_cs; +static CRITICAL_SECTION_DEBUG spacket_cs_debug = +{ + 0, 0, &spacket_cs, + { &spacket_cs_debug.ProcessLocksList, &spacket_cs_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": spacket_cs") } +}; +static CRITICAL_SECTION spacket_cs = { &spacket_cs_debug, -1, 0, 0, 0, 0 }; + +static RpcPacket* spacket_head; +static RpcPacket* spacket_tail; +static HANDLE server_sem; + +static DWORD worker_count, worker_free, worker_tls; + +static UUID uuid_nil; + +inline static RpcObjTypeMap *LookupObjTypeMap(UUID *ObjUuid) +{ + RpcObjTypeMap *rslt = RpcObjTypeMaps; + RPC_STATUS dummy; + + while (rslt) { + if (! UuidCompare(ObjUuid, &rslt->Object, &dummy)) break; + rslt = rslt->next; + } + + return rslt; +} + +inline static UUID *LookupObjType(UUID *ObjUuid) +{ + RpcObjTypeMap *map = LookupObjTypeMap(ObjUuid); + if (map) + return &map->Type; + else + return &uuid_nil; +} + +static RpcServerInterface* RPCRT4_find_interface(UUID* object, + RPC_SYNTAX_IDENTIFIER* if_id, + BOOL check_object) +{ + UUID* MgrType = NULL; + RpcServerInterface* cif = NULL; + RPC_STATUS status; + + if (check_object) + MgrType = LookupObjType(object); + EnterCriticalSection(&server_cs); + cif = ifs; + while (cif) { + if (!memcmp(if_id, &cif->If->InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER)) && + (check_object == FALSE || UuidEqual(MgrType, &cif->MgrTypeUuid, &status)) && + std_listen) break; + cif = cif->Next; + } + LeaveCriticalSection(&server_cs); + TRACE("returning %p for %s\n", cif, debugstr_guid(object)); + return cif; +} + +static void RPCRT4_push_packet(RpcPacket* packet) +{ + packet->next = NULL; + EnterCriticalSection(&spacket_cs); + if (spacket_tail) { + spacket_tail->next = packet; + spacket_tail = packet; + } else { + spacket_head = packet; + spacket_tail = packet; + } + LeaveCriticalSection(&spacket_cs); +} + +static RpcPacket* RPCRT4_pop_packet(void) +{ + RpcPacket* packet; + EnterCriticalSection(&spacket_cs); + packet = spacket_head; + if (packet) { + spacket_head = packet->next; + if (!spacket_head) spacket_tail = NULL; + } + LeaveCriticalSection(&spacket_cs); + if (packet) packet->next = NULL; + return packet; +} + +#ifndef __REACTOS__ +typedef struct { + PRPC_MESSAGE msg; + void* buf; +} packet_state; + +static WINE_EXCEPTION_FILTER(rpc_filter) +{ + packet_state* state; + PRPC_MESSAGE msg; + state = TlsGetValue(worker_tls); + msg = state->msg; + if (msg->Buffer != state->buf) I_RpcFreeBuffer(msg); + msg->RpcFlags |= WINE_RPCFLAG_EXCEPTION; + msg->BufferLength = sizeof(DWORD); + I_RpcGetBuffer(msg); + *(DWORD*)msg->Buffer = GetExceptionCode(); + WARN("exception caught with code 0x%08lx = %ld\n", *(DWORD*)msg->Buffer, *(DWORD*)msg->Buffer); + TRACE("returning failure packet\n"); + return EXCEPTION_EXECUTE_HANDLER; +} +#endif + +static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSAGE* msg) +{ + RpcServerInterface* sif; + RPC_DISPATCH_FUNCTION func; +#ifndef __REACTOS__ + packet_state state; +#endif + UUID *object_uuid; + RpcPktHdr *response; + void *buf = msg->Buffer; + RPC_STATUS status; + +#ifndef __REACTOS__ + state.msg = msg; + state.buf = buf; + TlsSetValue(worker_tls, &state); +#endif + + switch (hdr->common.ptype) { + case PKT_BIND: + TRACE("got bind packet\n"); + + /* FIXME: do more checks! */ + if (hdr->bind.max_tsize < RPC_MIN_PACKET_SIZE || + !UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) { + TRACE("packet size less than min size, or active interface syntax guid non-null\n"); + sif = NULL; + } else { + sif = RPCRT4_find_interface(NULL, &hdr->bind.abstract, FALSE); + } + if (sif == NULL) { + TRACE("rejecting bind request on connection %p\n", conn); + /* Report failure to client. */ + response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION, + RPC_VER_MAJOR, RPC_VER_MINOR); + } else { + TRACE("accepting bind request on connection %p\n", conn); + + /* accept. */ + response = RPCRT4_BuildBindAckHeader(NDR_LOCAL_DATA_REPRESENTATION, + RPC_MAX_PACKET_SIZE, + RPC_MAX_PACKET_SIZE, + conn->Endpoint, + RESULT_ACCEPT, NO_REASON, + &sif->If->TransferSyntax); + + /* save the interface for later use */ + conn->ActiveInterface = hdr->bind.abstract; + conn->MaxTransmissionSize = hdr->bind.max_tsize; + } + + if (RPCRT4_Send(conn, response, NULL, 0) != RPC_S_OK) + goto fail; + + break; + + case PKT_REQUEST: + TRACE("got request packet\n"); + + /* fail if the connection isn't bound with an interface */ + if (UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) { + response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION, + status); + + RPCRT4_Send(conn, response, NULL, 0); + break; + } + + if (hdr->common.flags & RPC_FLG_OBJECT_UUID) { + object_uuid = (UUID*)(&hdr->request + 1); + } else { + object_uuid = NULL; + } + + sif = RPCRT4_find_interface(object_uuid, &conn->ActiveInterface, TRUE); + msg->RpcInterfaceInformation = sif->If; + /* copy the endpoint vector from sif to msg so that midl-generated code will use it */ + msg->ManagerEpv = sif->MgrEpv; + if (object_uuid != NULL) { + RPCRT4_SetBindingObject(msg->Handle, object_uuid); + } + + /* find dispatch function */ + msg->ProcNum = hdr->request.opnum; + if (sif->Flags & RPC_IF_OLE) { + /* native ole32 always gives us a dispatch table with a single entry + * (I assume that's a wrapper for IRpcStubBuffer::Invoke) */ + func = *sif->If->DispatchTable->DispatchTable; + } else { + if (msg->ProcNum >= sif->If->DispatchTable->DispatchTableCount) { + ERR("invalid procnum\n"); + func = NULL; + } + func = sif->If->DispatchTable->DispatchTable[msg->ProcNum]; + } + + /* put in the drep. FIXME: is this more universally applicable? + perhaps we should move this outward... */ + msg->DataRepresentation = + MAKELONG( MAKEWORD(hdr->common.drep[0], hdr->common.drep[1]), + MAKEWORD(hdr->common.drep[2], hdr->common.drep[3])); + + /* dispatch */ +#ifndef __REACTOS__ + __TRY { + if (func) func(msg); + } __EXCEPT(rpc_filter) { + /* failure packet was created in rpc_filter */ + } __ENDTRY +#else + if (func) func(msg); +#endif + + /* send response packet */ + I_RpcSend(msg); + + msg->RpcInterfaceInformation = NULL; + + break; + + default: + FIXME("unhandled packet type\n"); + break; + } + +fail: + /* clean up */ + if (msg->Buffer == buf) msg->Buffer = NULL; + TRACE("freeing Buffer=%p\n", buf); + HeapFree(GetProcessHeap(), 0, buf); + RPCRT4_DestroyBinding(msg->Handle); + msg->Handle = 0; + I_RpcFreeBuffer(msg); + msg->Buffer = NULL; + RPCRT4_FreeHeader(hdr); +#ifndef __REACTOS__ + TlsSetValue(worker_tls, NULL); +#endif +} + +static DWORD CALLBACK RPCRT4_worker_thread(LPVOID the_arg) +{ + DWORD obj; + RpcPacket* pkt; + + for (;;) { + /* idle timeout after 5s */ + obj = WaitForSingleObject(server_sem, 5000); + if (obj == WAIT_TIMEOUT) { + /* if another idle thread exist, self-destruct */ + if (worker_free > 1) break; + continue; + } + pkt = RPCRT4_pop_packet(); + if (!pkt) continue; + InterlockedDecrement(&worker_free); + for (;;) { + RPCRT4_process_packet(pkt->conn, pkt->hdr, pkt->msg); + HeapFree(GetProcessHeap(), 0, pkt); + /* try to grab another packet here without waiting + * on the semaphore, in case it hits max */ + pkt = RPCRT4_pop_packet(); + if (!pkt) break; + /* decrement semaphore */ + WaitForSingleObject(server_sem, 0); + } + InterlockedIncrement(&worker_free); + } + InterlockedDecrement(&worker_free); + InterlockedDecrement(&worker_count); + return 0; +} + +static void RPCRT4_create_worker_if_needed(void) +{ + if (!worker_free && worker_count < MAX_THREADS) { + HANDLE thread; + InterlockedIncrement(&worker_count); + InterlockedIncrement(&worker_free); + thread = CreateThread(NULL, 0, RPCRT4_worker_thread, NULL, 0, NULL); + if (thread) CloseHandle(thread); + else { + InterlockedDecrement(&worker_free); + InterlockedDecrement(&worker_count); + } + } +} + +static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg) +{ + RpcConnection* conn = (RpcConnection*)the_arg; + RpcPktHdr *hdr; + RpcBinding *pbind; + RPC_MESSAGE *msg; + RPC_STATUS status; + RpcPacket *packet; + + TRACE("(%p)\n", conn); + + for (;;) { + msg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_MESSAGE)); + + /* create temporary binding for dispatch, it will be freed in + * RPCRT4_process_packet */ + RPCRT4_MakeBinding(&pbind, conn); + msg->Handle = (RPC_BINDING_HANDLE)pbind; + + status = RPCRT4_Receive(conn, &hdr, msg); + if (status != RPC_S_OK) { + WARN("receive failed with error %lx\n", status); + break; + } + +#if 0 + RPCRT4_process_packet(conn, hdr, msg); +#else + packet = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcPacket)); + packet->conn = conn; + packet->hdr = hdr; + packet->msg = msg; + RPCRT4_create_worker_if_needed(); + RPCRT4_push_packet(packet); + ReleaseSemaphore(server_sem, 1, NULL); +#endif + msg = NULL; + } + HeapFree(GetProcessHeap(), 0, msg); + RPCRT4_DestroyConnection(conn); + return 0; +} + +static void RPCRT4_new_client(RpcConnection* conn) +{ + HANDLE thread = CreateThread(NULL, 0, RPCRT4_io_thread, conn, 0, NULL); + if (!thread) { + DWORD err = GetLastError(); + ERR("failed to create thread, error=%08lx\n", err); + RPCRT4_DestroyConnection(conn); + } + /* we could set conn->thread, but then we'd have to make the io_thread wait + * for that, otherwise the thread might finish, destroy the connection, and + * free the memory we'd write to before we did, causing crashes and stuff - + * so let's implement that later, when we really need conn->thread */ + + CloseHandle( thread ); +} + +static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg) +{ + HANDLE m_event = mgr_event, b_handle; + HANDLE *objs = NULL; + DWORD count, res; + RpcServerProtseq* cps; + RpcConnection* conn; + RpcConnection* cconn; + BOOL set_ready_event = FALSE; + + TRACE("(the_arg == ^%p)\n", the_arg); + + for (;;) { + EnterCriticalSection(&server_cs); + /* open and count connections */ + count = 1; + cps = protseqs; + while (cps) { + conn = cps->conn; + while (conn) { + RPCRT4_OpenConnection(conn); + if (conn->ovl[0].hEvent) count++; + conn = conn->Next; + } + cps = cps->Next; + } + /* make array of connections */ + if (objs) + objs = HeapReAlloc(GetProcessHeap(), 0, objs, count*sizeof(HANDLE)); + else + objs = HeapAlloc(GetProcessHeap(), 0, count*sizeof(HANDLE)); + + objs[0] = m_event; + count = 1; + cps = protseqs; + while (cps) { + conn = cps->conn; + while (conn) { + if (conn->ovl[0].hEvent) objs[count++] = conn->ovl[0].hEvent; + conn = conn->Next; + } + cps = cps->Next; + } + LeaveCriticalSection(&server_cs); + + if (set_ready_event) + { + /* signal to function that changed state that we are now sync'ed */ + SetEvent(server_ready_event); + set_ready_event = FALSE; + } + + /* start waiting */ + res = WaitForMultipleObjects(count, objs, FALSE, INFINITE); + if (res == WAIT_OBJECT_0) { + if (!std_listen) + { + SetEvent(server_ready_event); + break; + } + set_ready_event = TRUE; + } + else if (res == WAIT_FAILED) { + ERR("wait failed\n"); + } + else { + b_handle = objs[res - WAIT_OBJECT_0]; + /* find which connection got a RPC */ + EnterCriticalSection(&server_cs); + conn = NULL; + cps = protseqs; + while (cps) { + conn = cps->conn; + while (conn) { + if (conn->ovl[0].hEvent == b_handle) break; + conn = conn->Next; + } + if (conn) break; + cps = cps->Next; + } + cconn = NULL; + if (conn) RPCRT4_SpawnConnection(&cconn, conn); + LeaveCriticalSection(&server_cs); + if (!conn) { + ERR("failed to locate connection for handle %p\n", b_handle); + } + if (cconn) RPCRT4_new_client(cconn); + } + } + HeapFree(GetProcessHeap(), 0, objs); + EnterCriticalSection(&server_cs); + /* close connections */ + cps = protseqs; + while (cps) { + conn = cps->conn; + while (conn) { + RPCRT4_CloseConnection(conn); + conn = conn->Next; + } + cps = cps->Next; + } + LeaveCriticalSection(&server_cs); + return 0; +} + +/* tells the server thread that the state has changed and waits for it to + * make the changes */ +static void RPCRT4_sync_with_server_thread(void) +{ + /* make sure we are the only thread sync'ing the server state, otherwise + * there is a race with the server thread setting an older state and setting + * the server_ready_event when the new state hasn't yet been applied */ + WaitForSingleObject(mgr_mutex, INFINITE); + + SetEvent(mgr_event); + /* wait for server thread to make the requested changes before returning */ + WaitForSingleObject(server_ready_event, INFINITE); + + ReleaseMutex(mgr_mutex); +} + +static RPC_STATUS RPCRT4_start_listen(BOOL auto_listen) +{ + RPC_STATUS status = RPC_S_ALREADY_LISTENING; + + TRACE("\n"); + + EnterCriticalSection(&listen_cs); + if (auto_listen || (manual_listen_count++ == 0)) + { + status = RPC_S_OK; + if (++listen_count == 1) { + HANDLE server_thread; + /* first listener creates server thread */ + if (!mgr_mutex) mgr_mutex = CreateMutexW(NULL, FALSE, NULL); + if (!mgr_event) mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL); + if (!server_ready_event) server_ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); + if (!server_sem) server_sem = CreateSemaphoreW(NULL, 0, MAX_THREADS, NULL); + if (!worker_tls) worker_tls = TlsAlloc(); + std_listen = TRUE; + server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, NULL, 0, NULL); + CloseHandle(server_thread); + } + } + LeaveCriticalSection(&listen_cs); + + return status; +} + +static void RPCRT4_stop_listen(BOOL auto_listen) +{ + EnterCriticalSection(&listen_cs); + if (auto_listen || (--manual_listen_count == 0)) + { + if (listen_count != 0 && --listen_count == 0) { + std_listen = FALSE; + LeaveCriticalSection(&listen_cs); + RPCRT4_sync_with_server_thread(); + return; + } + assert(listen_count >= 0); + } + LeaveCriticalSection(&listen_cs); +} + +static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps) +{ + RPCRT4_CreateConnection(&ps->conn, TRUE, ps->Protseq, NULL, ps->Endpoint, NULL, NULL); + + EnterCriticalSection(&server_cs); + ps->Next = protseqs; + protseqs = ps; + LeaveCriticalSection(&server_cs); + + if (std_listen) RPCRT4_sync_with_server_thread(); + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcServerInqBindings (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector ) +{ + RPC_STATUS status; + DWORD count; + RpcServerProtseq* ps; + RpcConnection* conn; + + if (BindingVector) + TRACE("(*BindingVector == ^%p)\n", *BindingVector); + else + ERR("(BindingVector == NULL!!?)\n"); + + EnterCriticalSection(&server_cs); + /* count connections */ + count = 0; + ps = protseqs; + while (ps) { + conn = ps->conn; + while (conn) { + count++; + conn = conn->Next; + } + ps = ps->Next; + } + if (count) { + /* export bindings */ + *BindingVector = HeapAlloc(GetProcessHeap(), 0, + sizeof(RPC_BINDING_VECTOR) + + sizeof(RPC_BINDING_HANDLE)*(count-1)); + (*BindingVector)->Count = count; + count = 0; + ps = protseqs; + while (ps) { + conn = ps->conn; + while (conn) { + RPCRT4_MakeBinding((RpcBinding**)&(*BindingVector)->BindingH[count], + conn); + count++; + conn = conn->Next; + } + ps = ps->Next; + } + status = RPC_S_OK; + } else { + *BindingVector = NULL; + status = RPC_S_NO_BINDINGS; + } + LeaveCriticalSection(&server_cs); + return status; +} + +/*********************************************************************** + * RpcServerUseProtseqEpA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUseProtseqEpA( unsigned char *Protseq, UINT MaxCalls, unsigned char *Endpoint, LPVOID SecurityDescriptor ) +{ + RPC_POLICY policy; + + TRACE( "(%s,%u,%s,%p)\n", Protseq, MaxCalls, Endpoint, SecurityDescriptor ); + + /* This should provide the default behaviour */ + policy.Length = sizeof( policy ); + policy.EndpointFlags = 0; + policy.NICFlags = 0; + + return RpcServerUseProtseqEpExA( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy ); +} + +/*********************************************************************** + * RpcServerUseProtseqEpW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUseProtseqEpW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor ) +{ + RPC_POLICY policy; + + TRACE( "(%s,%u,%s,%p)\n", debugstr_w( Protseq ), MaxCalls, debugstr_w( Endpoint ), SecurityDescriptor ); + + /* This should provide the default behaviour */ + policy.Length = sizeof( policy ); + policy.EndpointFlags = 0; + policy.NICFlags = 0; + + return RpcServerUseProtseqEpExW( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy ); +} + +/*********************************************************************** + * RpcServerUseProtseqEpExA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUseProtseqEpExA( unsigned char *Protseq, UINT MaxCalls, unsigned char *Endpoint, LPVOID SecurityDescriptor, + PRPC_POLICY lpPolicy ) +{ + RpcServerProtseq* ps; + + TRACE("(%s,%u,%s,%p,{%u,%lu,%lu})\n", debugstr_a( Protseq ), MaxCalls, + debugstr_a( Endpoint ), SecurityDescriptor, + lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags ); + + ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerProtseq)); + ps->MaxCalls = MaxCalls; + ps->Protseq = RPCRT4_strdupA(Protseq); + ps->Endpoint = RPCRT4_strdupA(Endpoint); + + return RPCRT4_use_protseq(ps); +} + +/*********************************************************************** + * RpcServerUseProtseqEpExW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUseProtseqEpExW( LPWSTR Protseq, UINT MaxCalls, LPWSTR Endpoint, LPVOID SecurityDescriptor, + PRPC_POLICY lpPolicy ) +{ + RpcServerProtseq* ps; + + TRACE("(%s,%u,%s,%p,{%u,%lu,%lu})\n", debugstr_w( Protseq ), MaxCalls, + debugstr_w( Endpoint ), SecurityDescriptor, + lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags ); + + ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerProtseq)); + ps->MaxCalls = MaxCalls; + ps->Protseq = RPCRT4_strdupWtoA(Protseq); + ps->Endpoint = RPCRT4_strdupWtoA(Endpoint); + + return RPCRT4_use_protseq(ps); +} + +/*********************************************************************** + * RpcServerUseProtseqA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUseProtseqA(unsigned char *Protseq, unsigned int MaxCalls, void *SecurityDescriptor) +{ + TRACE("(Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_a(Protseq), MaxCalls, SecurityDescriptor); + return RpcServerUseProtseqEpA(Protseq, MaxCalls, NULL, SecurityDescriptor); +} + +/*********************************************************************** + * RpcServerUseProtseqW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUseProtseqW(LPWSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor) +{ + TRACE("Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_w(Protseq), MaxCalls, SecurityDescriptor); + return RpcServerUseProtseqEpW(Protseq, MaxCalls, NULL, SecurityDescriptor); +} + +/*********************************************************************** + * RpcServerRegisterIf (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerRegisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv ) +{ + TRACE("(%p,%s,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv); + return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, 0, RPC_C_LISTEN_MAX_CALLS_DEFAULT, (UINT)-1, NULL ); +} + +/*********************************************************************** + * RpcServerRegisterIfEx (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerRegisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv, + UINT Flags, UINT MaxCalls, RPC_IF_CALLBACK_FN* IfCallbackFn ) +{ + TRACE("(%p,%s,%p,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls, IfCallbackFn); + return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, Flags, MaxCalls, (UINT)-1, IfCallbackFn ); +} + +/*********************************************************************** + * RpcServerRegisterIf2 (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerRegisterIf2( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv, + UINT Flags, UINT MaxCalls, UINT MaxRpcSize, RPC_IF_CALLBACK_FN* IfCallbackFn ) +{ + PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec; + RpcServerInterface* sif; + unsigned int i; + + TRACE("(%p,%s,%p,%u,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls, + MaxRpcSize, IfCallbackFn); + TRACE(" interface id: %s %d.%d\n", debugstr_guid(&If->InterfaceId.SyntaxGUID), + If->InterfaceId.SyntaxVersion.MajorVersion, + If->InterfaceId.SyntaxVersion.MinorVersion); + TRACE(" transfer syntax: %s %d.%d\n", debugstr_guid(&If->TransferSyntax.SyntaxGUID), + If->TransferSyntax.SyntaxVersion.MajorVersion, + If->TransferSyntax.SyntaxVersion.MinorVersion); + TRACE(" dispatch table: %p\n", If->DispatchTable); + if (If->DispatchTable) { + TRACE(" dispatch table count: %d\n", If->DispatchTable->DispatchTableCount); + for (i=0; i<If->DispatchTable->DispatchTableCount; i++) { + TRACE(" entry %d: %p\n", i, If->DispatchTable->DispatchTable[i]); + } + TRACE(" reserved: %ld\n", If->DispatchTable->Reserved); + } + TRACE(" protseq endpoint count: %d\n", If->RpcProtseqEndpointCount); + TRACE(" default manager epv: %p\n", If->DefaultManagerEpv); + TRACE(" interpreter info: %p\n", If->InterpreterInfo); + + sif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerInterface)); + sif->If = If; + if (MgrTypeUuid) { + memcpy(&sif->MgrTypeUuid, MgrTypeUuid, sizeof(UUID)); + sif->MgrEpv = MgrEpv; + } else { + memset(&sif->MgrTypeUuid, 0, sizeof(UUID)); + sif->MgrEpv = If->DefaultManagerEpv; + } + sif->Flags = Flags; + sif->MaxCalls = MaxCalls; + sif->MaxRpcSize = MaxRpcSize; + sif->IfCallbackFn = IfCallbackFn; + + EnterCriticalSection(&server_cs); + sif->Next = ifs; + ifs = sif; + LeaveCriticalSection(&server_cs); + + if (sif->Flags & RPC_IF_AUTOLISTEN) { + /* well, start listening, I think... */ + RPCRT4_start_listen(TRUE); + } + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcServerUnregisterIf (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUnregisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, UINT WaitForCallsToComplete ) +{ + FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, WaitForCallsToComplete == %u): stub\n", + IfSpec, debugstr_guid(MgrTypeUuid), WaitForCallsToComplete); + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcServerUnregisterIfEx (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUnregisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, int RundownContextHandles ) +{ + FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, RundownContextHandles == %d): stub\n", + IfSpec, debugstr_guid(MgrTypeUuid), RundownContextHandles); + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcObjectSetType (RPCRT4.@) + * + * PARAMS + * ObjUuid [I] "Object" UUID + * TypeUuid [I] "Type" UUID + * + * RETURNS + * RPC_S_OK The call succeeded + * RPC_S_INVALID_OBJECT The provided object (nil) is not valid + * RPC_S_ALREADY_REGISTERED The provided object is already registered + * + * Maps "Object" UUIDs to "Type" UUID's. Passing the nil UUID as the type + * resets the mapping for the specified object UUID to nil (the default). + * The nil object is always associated with the nil type and cannot be + * reassigned. Servers can support multiple implementations on the same + * interface by registering different end-point vectors for the different + * types. There's no need to call this if a server only supports the nil + * type, as is typical. + */ +RPC_STATUS WINAPI RpcObjectSetType( UUID* ObjUuid, UUID* TypeUuid ) +{ + RpcObjTypeMap *map = RpcObjTypeMaps, *prev = NULL; + RPC_STATUS dummy; + + TRACE("(ObjUUID == %s, TypeUuid == %s).\n", debugstr_guid(ObjUuid), debugstr_guid(TypeUuid)); + if ((! ObjUuid) || UuidIsNil(ObjUuid, &dummy)) { + /* nil uuid cannot be remapped */ + return RPC_S_INVALID_OBJECT; + } + + /* find the mapping for this object if there is one ... */ + while (map) { + if (! UuidCompare(ObjUuid, &map->Object, &dummy)) break; + prev = map; + map = map->next; + } + if ((! TypeUuid) || UuidIsNil(TypeUuid, &dummy)) { + /* ... and drop it from the list */ + if (map) { + if (prev) + prev->next = map->next; + else + RpcObjTypeMaps = map->next; + HeapFree(GetProcessHeap(), 0, map); + } + } else { + /* ... , fail if we found it ... */ + if (map) + return RPC_S_ALREADY_REGISTERED; + /* ... otherwise create a new one and add it in. */ + map = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcObjTypeMap)); + memcpy(&map->Object, ObjUuid, sizeof(UUID)); + memcpy(&map->Type, TypeUuid, sizeof(UUID)); + map->next = NULL; + if (prev) + prev->next = map; /* prev is the last map in the linklist */ + else + RpcObjTypeMaps = map; + } + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcServerRegisterAuthInfoA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerRegisterAuthInfoA( unsigned char *ServerPrincName, unsigned long AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn, + LPVOID Arg ) +{ + FIXME( "(%s,%lu,%p,%p): stub\n", ServerPrincName, AuthnSvc, GetKeyFn, Arg ); + + return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */ +} + +/*********************************************************************** + * RpcServerRegisterAuthInfoW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerRegisterAuthInfoW( LPWSTR ServerPrincName, unsigned long AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn, + LPVOID Arg ) +{ + FIXME( "(%s,%lu,%p,%p): stub\n", debugstr_w( ServerPrincName ), AuthnSvc, GetKeyFn, Arg ); + + return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */ +} + +/*********************************************************************** + * RpcServerListen (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerListen( UINT MinimumCallThreads, UINT MaxCalls, UINT DontWait ) +{ + RPC_STATUS status; + + TRACE("(%u,%u,%u)\n", MinimumCallThreads, MaxCalls, DontWait); + + if (!protseqs) + return RPC_S_NO_PROTSEQS_REGISTERED; + + status = RPCRT4_start_listen(FALSE); + + if (DontWait || (status != RPC_S_OK)) return status; + + return RpcMgmtWaitServerListen(); +} + +/*********************************************************************** + * RpcMgmtServerWaitListen (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcMgmtWaitServerListen( void ) +{ + TRACE("()\n"); + + EnterCriticalSection(&listen_cs); + + if (!std_listen) { + LeaveCriticalSection(&listen_cs); + return RPC_S_NOT_LISTENING; + } + + LeaveCriticalSection(&listen_cs); + + RPCRT4_sync_with_server_thread(); + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcMgmtStopServerListening (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcMgmtStopServerListening ( RPC_BINDING_HANDLE Binding ) +{ + TRACE("(Binding == (RPC_BINDING_HANDLE)^%p)\n", Binding); + + if (Binding) { + FIXME("client-side invocation not implemented.\n"); + return RPC_S_WRONG_KIND_OF_BINDING; + } + + RPCRT4_stop_listen(FALSE); + + return RPC_S_OK; +} + +/*********************************************************************** + * I_RpcServerStartListening (RPCRT4.@) + */ +RPC_STATUS WINAPI I_RpcServerStartListening( HWND hWnd ) +{ + FIXME( "(%p): stub\n", hWnd ); + + return RPC_S_OK; +} + +/*********************************************************************** + * I_RpcServerStopListening (RPCRT4.@) + */ +RPC_STATUS WINAPI I_RpcServerStopListening( void ) +{ + FIXME( "(): stub\n" ); + + return RPC_S_OK; +} + +/*********************************************************************** + * I_RpcWindowProc (RPCRT4.@) + */ +UINT WINAPI I_RpcWindowProc( void *hWnd, UINT Message, UINT wParam, ULONG lParam ) +{ + FIXME( "(%p,%08x,%08x,%08lx): stub\n", hWnd, Message, wParam, lParam ); + + return 0; +} diff --git a/reactos/lib/rpcrt4/rpc_server.h b/reactos/lib/rpcrt4/rpc_server.h index df950bb0599..1f43de8d024 100644 --- a/reactos/lib/rpcrt4/rpc_server.h +++ b/reactos/lib/rpcrt4/rpc_server.h @@ -1,47 +1,47 @@ -/* - * RPC server API - * - * Copyright 2001 Ove Kåven, TransGaming Technologies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_RPC_SERVER_H -#define __WINE_RPC_SERVER_H - -#include "rpc_binding.h" - -typedef struct _RpcServerProtseq -{ - struct _RpcServerProtseq* Next; - LPSTR Protseq; - LPSTR Endpoint; - UINT MaxCalls; - RpcConnection* conn; -} RpcServerProtseq; - -typedef struct _RpcServerInterface -{ - struct _RpcServerInterface* Next; - RPC_SERVER_INTERFACE* If; - UUID MgrTypeUuid; - RPC_MGR_EPV* MgrEpv; - UINT Flags; - UINT MaxCalls; - UINT MaxRpcSize; - RPC_IF_CALLBACK_FN* IfCallbackFn; -} RpcServerInterface; - -#endif /* __WINE_RPC_SERVER_H */ +/* + * RPC server API + * + * Copyright 2001 Ove Kåven, TransGaming Technologies + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_RPC_SERVER_H +#define __WINE_RPC_SERVER_H + +#include "rpc_binding.h" + +typedef struct _RpcServerProtseq +{ + struct _RpcServerProtseq* Next; + LPSTR Protseq; + LPSTR Endpoint; + UINT MaxCalls; + RpcConnection* conn; +} RpcServerProtseq; + +typedef struct _RpcServerInterface +{ + struct _RpcServerInterface* Next; + RPC_SERVER_INTERFACE* If; + UUID MgrTypeUuid; + RPC_MGR_EPV* MgrEpv; + UINT Flags; + UINT MaxCalls; + UINT MaxRpcSize; + RPC_IF_CALLBACK_FN* IfCallbackFn; +} RpcServerInterface; + +#endif /* __WINE_RPC_SERVER_H */ diff --git a/reactos/lib/rpcrt4/rpcrt4_main.c b/reactos/lib/rpcrt4/rpcrt4_main.c index 81f09eaf4b4..8a3411344f1 100644 --- a/reactos/lib/rpcrt4/rpcrt4_main.c +++ b/reactos/lib/rpcrt4/rpcrt4_main.c @@ -1,821 +1,821 @@ -/* - * RPCRT4 - * - * Copyright 2000 Huw D M Davies for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * WINE RPC TODO's (and a few TODONT's) - * - * - Ove's decreasingly incomplete widl is an IDL compiler for wine. For widl - * to be wine's only IDL compiler, a fair bit of work remains to be done. - * until then we have used some midl-generated stuff. (What?) - * widl currently doesn't generate stub/proxy files required by wine's (O)RPC - * capabilities -- nor does it make those lovely format strings :( - * The MS MIDL compiler does some really esoteric stuff. Of course Ove has - * started with the less esoteric stuff. There are also lots of nice - * comments in there if you want to flex your bison and help build this monster. - * - * - RPC has a quite featureful error handling mechanism; basically none of this is - * implemented right now. We also have deficiencies on the compiler side, where - * wine's __TRY / __EXCEPT / __FINALLY macros are not even used for RpcTryExcept & co, - * due to syntactic differences! (we can fix it with widl by using __TRY) - * - * - There are several different memory allocation schemes for MSRPC. - * I don't even understand what they all are yet, much less have them - * properly implemented. Surely we are supposed to be doing something with - * the user-provided allocation/deallocation functions, but so far, - * I don't think we are doing this... - * - * - MSRPC provides impersonation capabilities which currently are not possible - * to implement in wine. At the very least we should implement the authorization - * API's & gracefully ignore the irrelevant stuff (to an extent we already do). - * - * - Some transports are not yet implemented. The existing transport implementations - * are incomplete and may be bug-infested. - * - * - The various transports that we do support ought to be supported in a more - * object-oriented manner, as in DCE's RPC implementation, instead of cluttering - * up the code with conditionals like we do now. - * - * - Data marshalling: So far, only the beginnings of a full implementation - * exist in wine. NDR protocol itself is documented, but the MS API's to - * convert data-types in memory into NDR are not. This is challenging work, - * and has supposedly been "at the top of Greg's queue" for several months now. - * - * - ORPC is RPC for OLE; once we have a working RPC framework, we can - * use it to implement out-of-process OLE client/server communications. - * ATM there is maybe a disconnect between the marshalling in the OLE DLL's - * and the marshalling going on here [TODO: well, is there or not?] - * - * - In-source API Documentation, at least for those functions which we have - * implemented, but preferably for everything we can document, would be nice, - * since some of this stuff is quite obscure. - * - * - Name services... [TODO: what about them] - * - * - Protocol Towers: Totally unimplemented.... I think. - * - * - Context Handle Rundown: whatever that is. - * - * - Nested RPC's: Totally unimplemented. - * - * - Statistics: we are supposed to be keeping various counters. we aren't. - * - * - Async RPC: Unimplemented. - * - * - XML/http RPC: Somewhere there's an XML fiend that wants to do this! Betcha - * we could use these as a transport for RPC's across computers without a - * permissions and/or licensing crisis. - * - * - The NT "ports" API, aka LPC. Greg claims this is on his radar. Might (or - * might not) enable users to get some kind of meaningful result out of - * NT-based native rpcrt4's. Commonly-used transport for self-to-self RPC's. - * - * - ...? More stuff I haven't thought of. If you think of more RPC todo's - * drop me an e-mail <gmturner007@ameritech.net> or send a patch to the - * wine-patches mailing list. - */ - -#include "config.h" - -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "windef.h" -#include "winerror.h" -#include "winbase.h" -#include "winuser.h" -#include "iptypes.h" -#include "iphlpapi.h" -#include "wine/unicode.h" -#include "rpc.h" - -#include "ole2.h" -#include "rpcndr.h" -#include "rpcproxy.h" - -#include "rpc_binding.h" -#include "rpcss_np_client.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(rpc); - -static UUID uuid_nil; -static HANDLE master_mutex; - -HANDLE RPCRT4_GetMasterMutex(void) -{ - return master_mutex; -} - -static CRITICAL_SECTION uuid_cs; -static CRITICAL_SECTION_DEBUG critsect_debug = -{ - 0, 0, &uuid_cs, - { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, - 0, 0, { 0, (DWORD)(__FILE__ ": uuid_cs") } -}; -static CRITICAL_SECTION uuid_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; - -/*********************************************************************** - * DllMain - * - * PARAMS - * hinstDLL [I] handle to the DLL's instance - * fdwReason [I] - * lpvReserved [I] reserved, must be NULL - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ - -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - switch (fdwReason) { - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(hinstDLL); - master_mutex = CreateMutexA( NULL, FALSE, RPCSS_MASTER_MUTEX_NAME); - break; - - case DLL_PROCESS_DETACH: - CloseHandle(master_mutex); - master_mutex = NULL; - break; - } - - return TRUE; -} - -/************************************************************************* - * RpcStringFreeA [RPCRT4.@] - * - * Frees a character string allocated by the RPC run-time library. - * - * RETURNS - * - * S_OK if successful. - */ -RPC_STATUS WINAPI RpcStringFreeA(unsigned char** String) -{ - HeapFree( GetProcessHeap(), 0, *String); - - return RPC_S_OK; -} - -/************************************************************************* - * RpcStringFreeW [RPCRT4.@] - * - * Frees a character string allocated by the RPC run-time library. - * - * RETURNS - * - * S_OK if successful. - */ -RPC_STATUS WINAPI RpcStringFreeW(unsigned short** String) -{ - HeapFree( GetProcessHeap(), 0, *String); - - return RPC_S_OK; -} - -/************************************************************************* - * RpcRaiseException [RPCRT4.@] - * - * Raises an exception. - */ -void WINAPI RpcRaiseException(RPC_STATUS exception) -{ - /* FIXME: translate exception? */ - RaiseException(exception, 0, 0, NULL); -} - -/************************************************************************* - * UuidCompare [RPCRT4.@] - * - * PARAMS - * UUID *Uuid1 [I] Uuid to compare - * UUID *Uuid2 [I] Uuid to compare - * RPC_STATUS *Status [O] returns RPC_S_OK - * - * RETURNS - * -1 if Uuid1 is less than Uuid2 - * 0 if Uuid1 and Uuid2 are equal - * 1 if Uuid1 is greater than Uuid2 - */ -int WINAPI UuidCompare(UUID *Uuid1, UUID *Uuid2, RPC_STATUS *Status) -{ - int i; - - TRACE("(%s,%s)\n", debugstr_guid(Uuid1), debugstr_guid(Uuid2)); - - *Status = RPC_S_OK; - - if (!Uuid1) Uuid1 = &uuid_nil; - if (!Uuid2) Uuid2 = &uuid_nil; - - if (Uuid1 == Uuid2) return 0; - - if (Uuid1->Data1 != Uuid2->Data1) - return Uuid1->Data1 < Uuid2->Data1 ? -1 : 1; - - if (Uuid1->Data2 != Uuid2->Data2) - return Uuid1->Data2 < Uuid2->Data2 ? -1 : 1; - - if (Uuid1->Data3 != Uuid2->Data3) - return Uuid1->Data3 < Uuid2->Data3 ? -1 : 1; - - for (i = 0; i < 8; i++) { - if (Uuid1->Data4[i] < Uuid2->Data4[i]) - return -1; - if (Uuid1->Data4[i] > Uuid2->Data4[i]) - return 1; - } - - return 0; -} - -/************************************************************************* - * UuidEqual [RPCRT4.@] - * - * PARAMS - * UUID *Uuid1 [I] Uuid to compare - * UUID *Uuid2 [I] Uuid to compare - * RPC_STATUS *Status [O] returns RPC_S_OK - * - * RETURNS - * TRUE/FALSE - */ -int WINAPI UuidEqual(UUID *Uuid1, UUID *Uuid2, RPC_STATUS *Status) -{ - TRACE("(%s,%s)\n", debugstr_guid(Uuid1), debugstr_guid(Uuid2)); - return !UuidCompare(Uuid1, Uuid2, Status); -} - -/************************************************************************* - * UuidIsNil [RPCRT4.@] - * - * PARAMS - * UUID *Uuid [I] Uuid to compare - * RPC_STATUS *Status [O] retuns RPC_S_OK - * - * RETURNS - * TRUE/FALSE - */ -int WINAPI UuidIsNil(UUID *Uuid, RPC_STATUS *Status) -{ - TRACE("(%s)\n", debugstr_guid(Uuid)); - if (!Uuid) return TRUE; - return !UuidCompare(Uuid, &uuid_nil, Status); -} - - /************************************************************************* - * UuidCreateNil [RPCRT4.@] - * - * PARAMS - * UUID *Uuid [O] returns a nil UUID - * - * RETURNS - * RPC_S_OK - */ -RPC_STATUS WINAPI UuidCreateNil(UUID *Uuid) -{ - *Uuid = uuid_nil; - return RPC_S_OK; -} - -/* Number of 100ns ticks per clock tick. To be safe, assume that the clock - resolution is at least 1000 * 100 * (1/1000000) = 1/10 of a second */ -#define TICKS_PER_CLOCK_TICK 1000 -#define SECSPERDAY 86400 -#define TICKSPERSEC 10000000 -/* UUID system time starts at October 15, 1582 */ -#define SECS_15_OCT_1582_TO_1601 ((17 + 30 + 31 + 365 * 18 + 5) * SECSPERDAY) -#define TICKS_15_OCT_1582_TO_1601 ((ULONGLONG)SECS_15_OCT_1582_TO_1601 * TICKSPERSEC) - -static void RPC_UuidGetSystemTime(ULONGLONG *time) -{ - FILETIME ft; - - GetSystemTimeAsFileTime(&ft); - - *time = ((ULONGLONG)ft.dwHighDateTime << 32) | ft.dwLowDateTime; - *time += TICKS_15_OCT_1582_TO_1601; -} - -typedef DWORD WINAPI (*LPGETADAPTERSINFO)(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen); - -/* Assume that a hardware address is at least 6 bytes long */ -#define ADDRESS_BYTES_NEEDED 6 - -static RPC_STATUS RPC_UuidGetNodeAddress(BYTE *address) -{ - int i; - DWORD status = RPC_S_OK; - - ULONG buflen = sizeof(IP_ADAPTER_INFO); - PIP_ADAPTER_INFO adapter = HeapAlloc(GetProcessHeap(), 0, buflen); - HANDLE hIpHlpApi; - LPGETADAPTERSINFO pGetAdaptersInfo; - - hIpHlpApi = LoadLibrary("iphlpapi.dll"); - if (hIpHlpApi) - { - pGetAdaptersInfo = (LPGETADAPTERSINFO)GetProcAddress(hIpHlpApi, "GetAdaptersInfo"); - if (pGetAdaptersInfo) - { - if (pGetAdaptersInfo(adapter, &buflen) == ERROR_BUFFER_OVERFLOW) { - HeapFree(GetProcessHeap(), 0, adapter); - adapter = HeapAlloc(GetProcessHeap(), 0, buflen); - } - - if (pGetAdaptersInfo(adapter, &buflen) == NO_ERROR) { - for (i = 0; i < ADDRESS_BYTES_NEEDED; i++) { - address[i] = adapter->Address[i]; - } - } - else - { - goto local; - } - } - - /* Free the Library */ - FreeLibrary(hIpHlpApi); - goto exit; - } - -local: - /* We can't get a hardware address, just use random numbers. - Set the multicast bit to prevent conflicts with real cards. */ - for (i = 0; i < ADDRESS_BYTES_NEEDED; i++) { - address[i] = rand() & 0xff; - } - address[0] |= 0x01; - status = RPC_S_UUID_LOCAL_ONLY; - -exit: - HeapFree(GetProcessHeap(), 0, adapter); - return status; -} - -/************************************************************************* - * UuidCreate [RPCRT4.@] - * - * Creates a 128bit UUID. - * - * RETURNS - * - * RPC_S_OK if successful. - * RPC_S_UUID_LOCAL_ONLY if UUID is only locally unique. - * - * FIXME: No compensation for changes across reloading - * this dll or across reboots (e.g. clock going - * backwards and swapped network cards). The RFC - * suggests using NVRAM for storing persistent - * values. - */ -RPC_STATUS WINAPI UuidCreate(UUID *Uuid) -{ - static int initialised, count; - - ULONGLONG time; - static ULONGLONG timelast; - static WORD sequence; - - static DWORD status; - static BYTE address[MAX_ADAPTER_ADDRESS_LENGTH]; - - EnterCriticalSection(&uuid_cs); - - if (!initialised) { - RPC_UuidGetSystemTime(&timelast); - count = TICKS_PER_CLOCK_TICK; - - sequence = ((rand() & 0xff) << 8) + (rand() & 0xff); - sequence &= 0x1fff; - - status = RPC_UuidGetNodeAddress(address); - initialised = 1; - } - - /* Generate time element of the UUID. Account for going faster - than our clock as well as the clock going backwards. */ - while (1) { - RPC_UuidGetSystemTime(&time); - if (time > timelast) { - count = 0; - break; - } - if (time < timelast) { - sequence = (sequence + 1) & 0x1fff; - count = 0; - break; - } - if (count < TICKS_PER_CLOCK_TICK) { - count++; - break; - } - } - - timelast = time; - time += count; - - /* Pack the information into the UUID structure. */ - - Uuid->Data1 = (unsigned long)(time & 0xffffffff); - Uuid->Data2 = (unsigned short)((time >> 32) & 0xffff); - Uuid->Data3 = (unsigned short)((time >> 48) & 0x0fff); - - /* This is a version 1 UUID */ - Uuid->Data3 |= (1 << 12); - - Uuid->Data4[0] = sequence & 0xff; - Uuid->Data4[1] = (sequence & 0x3f00) >> 8; - Uuid->Data4[1] |= 0x80; - - Uuid->Data4[2] = address[0]; - Uuid->Data4[3] = address[1]; - Uuid->Data4[4] = address[2]; - Uuid->Data4[5] = address[3]; - Uuid->Data4[6] = address[4]; - Uuid->Data4[7] = address[5]; - - LeaveCriticalSection(&uuid_cs); - - TRACE("%s\n", debugstr_guid(Uuid)); - - return status; -} - -/************************************************************************* - * UuidCreateSequential [RPCRT4.@] - * - * Creates a 128bit UUID. - * - * RETURNS - * - * RPC_S_OK if successful. - * RPC_S_UUID_LOCAL_ONLY if UUID is only locally unique. - * - */ -RPC_STATUS WINAPI UuidCreateSequential(UUID *Uuid) -{ - return UuidCreate(Uuid); -} - - -/************************************************************************* - * UuidHash [RPCRT4.@] - * - * Generates a hash value for a given UUID - * - * Code based on FreeDCE implementation - * - */ -unsigned short WINAPI UuidHash(UUID *uuid, RPC_STATUS *Status) -{ - BYTE *data = (BYTE*)uuid; - short c0 = 0, c1 = 0, x, y; - unsigned int i; - - if (!uuid) data = (BYTE*)(uuid = &uuid_nil); - - TRACE("(%s)\n", debugstr_guid(uuid)); - - for (i=0; i<sizeof(UUID); i++) { - c0 += data[i]; - c1 += c0; - } - - x = -c1 % 255; - if (x < 0) x += 255; - - y = (c1 - c0) % 255; - if (y < 0) y += 255; - - *Status = RPC_S_OK; - return y*256 + x; -} - -/************************************************************************* - * UuidToStringA [RPCRT4.@] - * - * Converts a UUID to a string. - * - * UUID format is 8 hex digits, followed by a hyphen then three groups of - * 4 hex digits each followed by a hyphen and then 12 hex digits - * - * RETURNS - * - * S_OK if successful. - * S_OUT_OF_MEMORY if unsucessful. - */ -RPC_STATUS WINAPI UuidToStringA(UUID *Uuid, unsigned char** StringUuid) -{ - *StringUuid = HeapAlloc( GetProcessHeap(), 0, sizeof(char) * 37); - - if(!(*StringUuid)) - return RPC_S_OUT_OF_MEMORY; - - if (!Uuid) Uuid = &uuid_nil; - - sprintf(*StringUuid, "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - Uuid->Data1, Uuid->Data2, Uuid->Data3, - Uuid->Data4[0], Uuid->Data4[1], Uuid->Data4[2], - Uuid->Data4[3], Uuid->Data4[4], Uuid->Data4[5], - Uuid->Data4[6], Uuid->Data4[7] ); - - return RPC_S_OK; -} - -/************************************************************************* - * UuidToStringW [RPCRT4.@] - * - * Converts a UUID to a string. - * - * S_OK if successful. - * S_OUT_OF_MEMORY if unsucessful. - */ -RPC_STATUS WINAPI UuidToStringW(UUID *Uuid, unsigned short** StringUuid) -{ - char buf[37]; - - if (!Uuid) Uuid = &uuid_nil; - - sprintf(buf, "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - Uuid->Data1, Uuid->Data2, Uuid->Data3, - Uuid->Data4[0], Uuid->Data4[1], Uuid->Data4[2], - Uuid->Data4[3], Uuid->Data4[4], Uuid->Data4[5], - Uuid->Data4[6], Uuid->Data4[7] ); - - *StringUuid = RPCRT4_strdupAtoW(buf); - - if(!(*StringUuid)) - return RPC_S_OUT_OF_MEMORY; - - return RPC_S_OK; -} - -static const BYTE hex2bin[] = -{ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */ - 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */ - 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */ - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */ - 0,10,11,12,13,14,15 /* 0x60 */ -}; - -/*********************************************************************** - * UuidFromStringA (RPCRT4.@) - */ -RPC_STATUS WINAPI UuidFromStringA(unsigned char* str, UUID *uuid) -{ - BYTE *s = (BYTE *)str; - int i; - - if (!s) return UuidCreateNil( uuid ); - - if (strlen(s) != 36) return RPC_S_INVALID_STRING_UUID; - - if ((s[8]!='-') || (s[13]!='-') || (s[18]!='-') || (s[23]!='-')) - return RPC_S_INVALID_STRING_UUID; - - for (i=0; i<36; i++) - { - if ((i == 8)||(i == 13)||(i == 18)||(i == 23)) continue; - if (s[i] > 'f' || (!hex2bin[s[i]] && s[i] != '0')) return RPC_S_INVALID_STRING_UUID; - } - - /* in form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */ - - uuid->Data1 = (hex2bin[s[0]] << 28 | hex2bin[s[1]] << 24 | hex2bin[s[2]] << 20 | hex2bin[s[3]] << 16 | - hex2bin[s[4]] << 12 | hex2bin[s[5]] << 8 | hex2bin[s[6]] << 4 | hex2bin[s[7]]); - uuid->Data2 = hex2bin[s[9]] << 12 | hex2bin[s[10]] << 8 | hex2bin[s[11]] << 4 | hex2bin[s[12]]; - uuid->Data3 = hex2bin[s[14]] << 12 | hex2bin[s[15]] << 8 | hex2bin[s[16]] << 4 | hex2bin[s[17]]; - - /* these are just sequential bytes */ - uuid->Data4[0] = hex2bin[s[19]] << 4 | hex2bin[s[20]]; - uuid->Data4[1] = hex2bin[s[21]] << 4 | hex2bin[s[22]]; - uuid->Data4[2] = hex2bin[s[24]] << 4 | hex2bin[s[25]]; - uuid->Data4[3] = hex2bin[s[26]] << 4 | hex2bin[s[27]]; - uuid->Data4[4] = hex2bin[s[28]] << 4 | hex2bin[s[29]]; - uuid->Data4[5] = hex2bin[s[30]] << 4 | hex2bin[s[31]]; - uuid->Data4[6] = hex2bin[s[32]] << 4 | hex2bin[s[33]]; - uuid->Data4[7] = hex2bin[s[34]] << 4 | hex2bin[s[35]]; - return RPC_S_OK; -} - - -/*********************************************************************** - * UuidFromStringW (RPCRT4.@) - */ -RPC_STATUS WINAPI UuidFromStringW(unsigned short* s, UUID *uuid) -{ - int i; - - if (!s) return UuidCreateNil( uuid ); - - if (strlenW(s) != 36) return RPC_S_INVALID_STRING_UUID; - - if ((s[8]!='-') || (s[13]!='-') || (s[18]!='-') || (s[23]!='-')) - return RPC_S_INVALID_STRING_UUID; - - for (i=0; i<36; i++) - { - if ((i == 8)||(i == 13)||(i == 18)||(i == 23)) continue; - if (s[i] > 'f' || (!hex2bin[s[i]] && s[i] != '0')) return RPC_S_INVALID_STRING_UUID; - } - - /* in form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */ - - uuid->Data1 = (hex2bin[s[0]] << 28 | hex2bin[s[1]] << 24 | hex2bin[s[2]] << 20 | hex2bin[s[3]] << 16 | - hex2bin[s[4]] << 12 | hex2bin[s[5]] << 8 | hex2bin[s[6]] << 4 | hex2bin[s[7]]); - uuid->Data2 = hex2bin[s[9]] << 12 | hex2bin[s[10]] << 8 | hex2bin[s[11]] << 4 | hex2bin[s[12]]; - uuid->Data3 = hex2bin[s[14]] << 12 | hex2bin[s[15]] << 8 | hex2bin[s[16]] << 4 | hex2bin[s[17]]; - - /* these are just sequential bytes */ - uuid->Data4[0] = hex2bin[s[19]] << 4 | hex2bin[s[20]]; - uuid->Data4[1] = hex2bin[s[21]] << 4 | hex2bin[s[22]]; - uuid->Data4[2] = hex2bin[s[24]] << 4 | hex2bin[s[25]]; - uuid->Data4[3] = hex2bin[s[26]] << 4 | hex2bin[s[27]]; - uuid->Data4[4] = hex2bin[s[28]] << 4 | hex2bin[s[29]]; - uuid->Data4[5] = hex2bin[s[30]] << 4 | hex2bin[s[31]]; - uuid->Data4[6] = hex2bin[s[32]] << 4 | hex2bin[s[33]]; - uuid->Data4[7] = hex2bin[s[34]] << 4 | hex2bin[s[35]]; - return RPC_S_OK; -} - -/*********************************************************************** - * DllRegisterServer (RPCRT4.@) - */ - -HRESULT WINAPI RPCRT4_DllRegisterServer( void ) -{ - FIXME( "(): stub\n" ); - return S_OK; -} - -BOOL RPCRT4_StartRPCSS(void) -{ - PROCESS_INFORMATION pi; - STARTUPINFOA si; - static char cmd[6]; - BOOL rslt; - - ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); - ZeroMemory(&si, sizeof(STARTUPINFOA)); - si.cb = sizeof(STARTUPINFOA); - - /* apparently it's not OK to use a constant string below */ - CopyMemory(cmd, "rpcss", 6); - - /* FIXME: will this do the right thing when run as a test? */ - rslt = CreateProcessA( - NULL, /* executable */ - cmd, /* command line */ - NULL, /* process security attributes */ - NULL, /* primary thread security attributes */ - FALSE, /* inherit handles */ - 0, /* creation flags */ - NULL, /* use parent's environment */ - NULL, /* use parent's current directory */ - &si, /* STARTUPINFO pointer */ - &pi /* PROCESS_INFORMATION */ - ); - - if (rslt) { - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - } - - return rslt; -} - -/*********************************************************************** - * RPCRT4_RPCSSOnDemandCall (internal) - * - * Attempts to send a message to the RPCSS process - * on the local machine, invoking it if necessary. - * For remote RPCSS calls, use.... your imagination. - * - * PARAMS - * msg [I] pointer to the RPCSS message - * vardata_payload [I] pointer vardata portion of the RPCSS message - * reply [O] pointer to reply structure - * - * RETURNS - * TRUE if successful - * FALSE otherwise - */ -BOOL RPCRT4_RPCSSOnDemandCall(PRPCSS_NP_MESSAGE msg, char *vardata_payload, PRPCSS_NP_REPLY reply) -{ - HANDLE client_handle; - int i, j = 0; - - TRACE("(msg == %p, vardata_payload == %p, reply == %p)\n", msg, vardata_payload, reply); - - client_handle = RPCRT4_RpcssNPConnect(); - - while (!client_handle) { - /* start the RPCSS process */ - if (!RPCRT4_StartRPCSS()) { - ERR("Unable to start RPCSS process.\n"); - return FALSE; - } - /* wait for a connection (w/ periodic polling) */ - for (i = 0; i < 60; i++) { - Sleep(200); - client_handle = RPCRT4_RpcssNPConnect(); - if (client_handle) break; - } - /* we are only willing to try twice */ - if (j++ >= 1) break; - } - - if (!client_handle) { - /* no dice! */ - ERR("Unable to connect to RPCSS process!\n"); - SetLastError(RPC_E_SERVER_DIED_DNE); - return FALSE; - } - - /* great, we're connected. now send the message */ - if (!RPCRT4_SendReceiveNPMsg(client_handle, msg, vardata_payload, reply)) { - ERR("Something is amiss: RPC_SendReceive failed.\n"); - return FALSE; - } - - return TRUE; -} - -#define MAX_RPC_ERROR_TEXT 256 - -/****************************************************************************** - * DceErrorInqTextW (rpcrt4.@) - * - * Notes - * 1. On passing a NULL pointer the code does bomb out. - * 2. The size of the required buffer is not defined in the documentation. - * It appears to be 256. - * 3. The function is defined to return RPC_S_INVALID_ARG but I don't know - * of any value for which it does. - * 4. The MSDN documentation currently declares that the second argument is - * unsigned char *, even for the W version. I don't believe it. - */ -RPC_STATUS RPC_ENTRY DceErrorInqTextW (RPC_STATUS e, unsigned short *buffer) -{ - DWORD count; - count = FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, e, 0, buffer, MAX_RPC_ERROR_TEXT, NULL); - if (!count) - { - count = FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, RPC_S_NOT_RPC_ERROR, 0, buffer, MAX_RPC_ERROR_TEXT, NULL); - if (!count) - { - ERR ("Failed to translate error"); - return RPC_S_INVALID_ARG; - } - } - return RPC_S_OK; -} - -/****************************************************************************** - * DceErrorInqTextA (rpcrt4.@) - */ -RPC_STATUS RPC_ENTRY DceErrorInqTextA (RPC_STATUS e, unsigned char *buffer) -{ - RPC_STATUS status; - WCHAR bufferW [MAX_RPC_ERROR_TEXT]; - if ((status = DceErrorInqTextW (e, bufferW)) == RPC_S_OK) - { - if (!WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_RPC_ERROR_TEXT, - NULL, NULL)) - { - ERR ("Failed to translate error"); - status = RPC_S_INVALID_ARG; - } - } - return status; -} +/* + * RPCRT4 + * + * Copyright 2000 Huw D M Davies for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * WINE RPC TODO's (and a few TODONT's) + * + * - Ove's decreasingly incomplete widl is an IDL compiler for wine. For widl + * to be wine's only IDL compiler, a fair bit of work remains to be done. + * until then we have used some midl-generated stuff. (What?) + * widl currently doesn't generate stub/proxy files required by wine's (O)RPC + * capabilities -- nor does it make those lovely format strings :( + * The MS MIDL compiler does some really esoteric stuff. Of course Ove has + * started with the less esoteric stuff. There are also lots of nice + * comments in there if you want to flex your bison and help build this monster. + * + * - RPC has a quite featureful error handling mechanism; basically none of this is + * implemented right now. We also have deficiencies on the compiler side, where + * wine's __TRY / __EXCEPT / __FINALLY macros are not even used for RpcTryExcept & co, + * due to syntactic differences! (we can fix it with widl by using __TRY) + * + * - There are several different memory allocation schemes for MSRPC. + * I don't even understand what they all are yet, much less have them + * properly implemented. Surely we are supposed to be doing something with + * the user-provided allocation/deallocation functions, but so far, + * I don't think we are doing this... + * + * - MSRPC provides impersonation capabilities which currently are not possible + * to implement in wine. At the very least we should implement the authorization + * API's & gracefully ignore the irrelevant stuff (to an extent we already do). + * + * - Some transports are not yet implemented. The existing transport implementations + * are incomplete and may be bug-infested. + * + * - The various transports that we do support ought to be supported in a more + * object-oriented manner, as in DCE's RPC implementation, instead of cluttering + * up the code with conditionals like we do now. + * + * - Data marshalling: So far, only the beginnings of a full implementation + * exist in wine. NDR protocol itself is documented, but the MS API's to + * convert data-types in memory into NDR are not. This is challenging work, + * and has supposedly been "at the top of Greg's queue" for several months now. + * + * - ORPC is RPC for OLE; once we have a working RPC framework, we can + * use it to implement out-of-process OLE client/server communications. + * ATM there is maybe a disconnect between the marshalling in the OLE DLL's + * and the marshalling going on here [TODO: well, is there or not?] + * + * - In-source API Documentation, at least for those functions which we have + * implemented, but preferably for everything we can document, would be nice, + * since some of this stuff is quite obscure. + * + * - Name services... [TODO: what about them] + * + * - Protocol Towers: Totally unimplemented.... I think. + * + * - Context Handle Rundown: whatever that is. + * + * - Nested RPC's: Totally unimplemented. + * + * - Statistics: we are supposed to be keeping various counters. we aren't. + * + * - Async RPC: Unimplemented. + * + * - XML/http RPC: Somewhere there's an XML fiend that wants to do this! Betcha + * we could use these as a transport for RPC's across computers without a + * permissions and/or licensing crisis. + * + * - The NT "ports" API, aka LPC. Greg claims this is on his radar. Might (or + * might not) enable users to get some kind of meaningful result out of + * NT-based native rpcrt4's. Commonly-used transport for self-to-self RPC's. + * + * - ...? More stuff I haven't thought of. If you think of more RPC todo's + * drop me an e-mail <gmturner007@ameritech.net> or send a patch to the + * wine-patches mailing list. + */ + +#include "config.h" + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "windef.h" +#include "winerror.h" +#include "winbase.h" +#include "winuser.h" +#include "iptypes.h" +#include "iphlpapi.h" +#include "wine/unicode.h" +#include "rpc.h" + +#include "ole2.h" +#include "rpcndr.h" +#include "rpcproxy.h" + +#include "rpc_binding.h" +#include "rpcss_np_client.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(rpc); + +static UUID uuid_nil; +static HANDLE master_mutex; + +HANDLE RPCRT4_GetMasterMutex(void) +{ + return master_mutex; +} + +static CRITICAL_SECTION uuid_cs; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &uuid_cs, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": uuid_cs") } +}; +static CRITICAL_SECTION uuid_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; + +/*********************************************************************** + * DllMain + * + * PARAMS + * hinstDLL [I] handle to the DLL's instance + * fdwReason [I] + * lpvReserved [I] reserved, must be NULL + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDLL); + master_mutex = CreateMutexA( NULL, FALSE, RPCSS_MASTER_MUTEX_NAME); + break; + + case DLL_PROCESS_DETACH: + CloseHandle(master_mutex); + master_mutex = NULL; + break; + } + + return TRUE; +} + +/************************************************************************* + * RpcStringFreeA [RPCRT4.@] + * + * Frees a character string allocated by the RPC run-time library. + * + * RETURNS + * + * S_OK if successful. + */ +RPC_STATUS WINAPI RpcStringFreeA(unsigned char** String) +{ + HeapFree( GetProcessHeap(), 0, *String); + + return RPC_S_OK; +} + +/************************************************************************* + * RpcStringFreeW [RPCRT4.@] + * + * Frees a character string allocated by the RPC run-time library. + * + * RETURNS + * + * S_OK if successful. + */ +RPC_STATUS WINAPI RpcStringFreeW(unsigned short** String) +{ + HeapFree( GetProcessHeap(), 0, *String); + + return RPC_S_OK; +} + +/************************************************************************* + * RpcRaiseException [RPCRT4.@] + * + * Raises an exception. + */ +void WINAPI RpcRaiseException(RPC_STATUS exception) +{ + /* FIXME: translate exception? */ + RaiseException(exception, 0, 0, NULL); +} + +/************************************************************************* + * UuidCompare [RPCRT4.@] + * + * PARAMS + * UUID *Uuid1 [I] Uuid to compare + * UUID *Uuid2 [I] Uuid to compare + * RPC_STATUS *Status [O] returns RPC_S_OK + * + * RETURNS + * -1 if Uuid1 is less than Uuid2 + * 0 if Uuid1 and Uuid2 are equal + * 1 if Uuid1 is greater than Uuid2 + */ +int WINAPI UuidCompare(UUID *Uuid1, UUID *Uuid2, RPC_STATUS *Status) +{ + int i; + + TRACE("(%s,%s)\n", debugstr_guid(Uuid1), debugstr_guid(Uuid2)); + + *Status = RPC_S_OK; + + if (!Uuid1) Uuid1 = &uuid_nil; + if (!Uuid2) Uuid2 = &uuid_nil; + + if (Uuid1 == Uuid2) return 0; + + if (Uuid1->Data1 != Uuid2->Data1) + return Uuid1->Data1 < Uuid2->Data1 ? -1 : 1; + + if (Uuid1->Data2 != Uuid2->Data2) + return Uuid1->Data2 < Uuid2->Data2 ? -1 : 1; + + if (Uuid1->Data3 != Uuid2->Data3) + return Uuid1->Data3 < Uuid2->Data3 ? -1 : 1; + + for (i = 0; i < 8; i++) { + if (Uuid1->Data4[i] < Uuid2->Data4[i]) + return -1; + if (Uuid1->Data4[i] > Uuid2->Data4[i]) + return 1; + } + + return 0; +} + +/************************************************************************* + * UuidEqual [RPCRT4.@] + * + * PARAMS + * UUID *Uuid1 [I] Uuid to compare + * UUID *Uuid2 [I] Uuid to compare + * RPC_STATUS *Status [O] returns RPC_S_OK + * + * RETURNS + * TRUE/FALSE + */ +int WINAPI UuidEqual(UUID *Uuid1, UUID *Uuid2, RPC_STATUS *Status) +{ + TRACE("(%s,%s)\n", debugstr_guid(Uuid1), debugstr_guid(Uuid2)); + return !UuidCompare(Uuid1, Uuid2, Status); +} + +/************************************************************************* + * UuidIsNil [RPCRT4.@] + * + * PARAMS + * UUID *Uuid [I] Uuid to compare + * RPC_STATUS *Status [O] retuns RPC_S_OK + * + * RETURNS + * TRUE/FALSE + */ +int WINAPI UuidIsNil(UUID *Uuid, RPC_STATUS *Status) +{ + TRACE("(%s)\n", debugstr_guid(Uuid)); + if (!Uuid) return TRUE; + return !UuidCompare(Uuid, &uuid_nil, Status); +} + + /************************************************************************* + * UuidCreateNil [RPCRT4.@] + * + * PARAMS + * UUID *Uuid [O] returns a nil UUID + * + * RETURNS + * RPC_S_OK + */ +RPC_STATUS WINAPI UuidCreateNil(UUID *Uuid) +{ + *Uuid = uuid_nil; + return RPC_S_OK; +} + +/* Number of 100ns ticks per clock tick. To be safe, assume that the clock + resolution is at least 1000 * 100 * (1/1000000) = 1/10 of a second */ +#define TICKS_PER_CLOCK_TICK 1000 +#define SECSPERDAY 86400 +#define TICKSPERSEC 10000000 +/* UUID system time starts at October 15, 1582 */ +#define SECS_15_OCT_1582_TO_1601 ((17 + 30 + 31 + 365 * 18 + 5) * SECSPERDAY) +#define TICKS_15_OCT_1582_TO_1601 ((ULONGLONG)SECS_15_OCT_1582_TO_1601 * TICKSPERSEC) + +static void RPC_UuidGetSystemTime(ULONGLONG *time) +{ + FILETIME ft; + + GetSystemTimeAsFileTime(&ft); + + *time = ((ULONGLONG)ft.dwHighDateTime << 32) | ft.dwLowDateTime; + *time += TICKS_15_OCT_1582_TO_1601; +} + +typedef DWORD WINAPI (*LPGETADAPTERSINFO)(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen); + +/* Assume that a hardware address is at least 6 bytes long */ +#define ADDRESS_BYTES_NEEDED 6 + +static RPC_STATUS RPC_UuidGetNodeAddress(BYTE *address) +{ + int i; + DWORD status = RPC_S_OK; + + ULONG buflen = sizeof(IP_ADAPTER_INFO); + PIP_ADAPTER_INFO adapter = HeapAlloc(GetProcessHeap(), 0, buflen); + HANDLE hIpHlpApi; + LPGETADAPTERSINFO pGetAdaptersInfo; + + hIpHlpApi = LoadLibrary("iphlpapi.dll"); + if (hIpHlpApi) + { + pGetAdaptersInfo = (LPGETADAPTERSINFO)GetProcAddress(hIpHlpApi, "GetAdaptersInfo"); + if (pGetAdaptersInfo) + { + if (pGetAdaptersInfo(adapter, &buflen) == ERROR_BUFFER_OVERFLOW) { + HeapFree(GetProcessHeap(), 0, adapter); + adapter = HeapAlloc(GetProcessHeap(), 0, buflen); + } + + if (pGetAdaptersInfo(adapter, &buflen) == NO_ERROR) { + for (i = 0; i < ADDRESS_BYTES_NEEDED; i++) { + address[i] = adapter->Address[i]; + } + } + else + { + goto local; + } + } + + /* Free the Library */ + FreeLibrary(hIpHlpApi); + goto exit; + } + +local: + /* We can't get a hardware address, just use random numbers. + Set the multicast bit to prevent conflicts with real cards. */ + for (i = 0; i < ADDRESS_BYTES_NEEDED; i++) { + address[i] = rand() & 0xff; + } + address[0] |= 0x01; + status = RPC_S_UUID_LOCAL_ONLY; + +exit: + HeapFree(GetProcessHeap(), 0, adapter); + return status; +} + +/************************************************************************* + * UuidCreate [RPCRT4.@] + * + * Creates a 128bit UUID. + * + * RETURNS + * + * RPC_S_OK if successful. + * RPC_S_UUID_LOCAL_ONLY if UUID is only locally unique. + * + * FIXME: No compensation for changes across reloading + * this dll or across reboots (e.g. clock going + * backwards and swapped network cards). The RFC + * suggests using NVRAM for storing persistent + * values. + */ +RPC_STATUS WINAPI UuidCreate(UUID *Uuid) +{ + static int initialised, count; + + ULONGLONG time; + static ULONGLONG timelast; + static WORD sequence; + + static DWORD status; + static BYTE address[MAX_ADAPTER_ADDRESS_LENGTH]; + + EnterCriticalSection(&uuid_cs); + + if (!initialised) { + RPC_UuidGetSystemTime(&timelast); + count = TICKS_PER_CLOCK_TICK; + + sequence = ((rand() & 0xff) << 8) + (rand() & 0xff); + sequence &= 0x1fff; + + status = RPC_UuidGetNodeAddress(address); + initialised = 1; + } + + /* Generate time element of the UUID. Account for going faster + than our clock as well as the clock going backwards. */ + while (1) { + RPC_UuidGetSystemTime(&time); + if (time > timelast) { + count = 0; + break; + } + if (time < timelast) { + sequence = (sequence + 1) & 0x1fff; + count = 0; + break; + } + if (count < TICKS_PER_CLOCK_TICK) { + count++; + break; + } + } + + timelast = time; + time += count; + + /* Pack the information into the UUID structure. */ + + Uuid->Data1 = (unsigned long)(time & 0xffffffff); + Uuid->Data2 = (unsigned short)((time >> 32) & 0xffff); + Uuid->Data3 = (unsigned short)((time >> 48) & 0x0fff); + + /* This is a version 1 UUID */ + Uuid->Data3 |= (1 << 12); + + Uuid->Data4[0] = sequence & 0xff; + Uuid->Data4[1] = (sequence & 0x3f00) >> 8; + Uuid->Data4[1] |= 0x80; + + Uuid->Data4[2] = address[0]; + Uuid->Data4[3] = address[1]; + Uuid->Data4[4] = address[2]; + Uuid->Data4[5] = address[3]; + Uuid->Data4[6] = address[4]; + Uuid->Data4[7] = address[5]; + + LeaveCriticalSection(&uuid_cs); + + TRACE("%s\n", debugstr_guid(Uuid)); + + return status; +} + +/************************************************************************* + * UuidCreateSequential [RPCRT4.@] + * + * Creates a 128bit UUID. + * + * RETURNS + * + * RPC_S_OK if successful. + * RPC_S_UUID_LOCAL_ONLY if UUID is only locally unique. + * + */ +RPC_STATUS WINAPI UuidCreateSequential(UUID *Uuid) +{ + return UuidCreate(Uuid); +} + + +/************************************************************************* + * UuidHash [RPCRT4.@] + * + * Generates a hash value for a given UUID + * + * Code based on FreeDCE implementation + * + */ +unsigned short WINAPI UuidHash(UUID *uuid, RPC_STATUS *Status) +{ + BYTE *data = (BYTE*)uuid; + short c0 = 0, c1 = 0, x, y; + unsigned int i; + + if (!uuid) data = (BYTE*)(uuid = &uuid_nil); + + TRACE("(%s)\n", debugstr_guid(uuid)); + + for (i=0; i<sizeof(UUID); i++) { + c0 += data[i]; + c1 += c0; + } + + x = -c1 % 255; + if (x < 0) x += 255; + + y = (c1 - c0) % 255; + if (y < 0) y += 255; + + *Status = RPC_S_OK; + return y*256 + x; +} + +/************************************************************************* + * UuidToStringA [RPCRT4.@] + * + * Converts a UUID to a string. + * + * UUID format is 8 hex digits, followed by a hyphen then three groups of + * 4 hex digits each followed by a hyphen and then 12 hex digits + * + * RETURNS + * + * S_OK if successful. + * S_OUT_OF_MEMORY if unsucessful. + */ +RPC_STATUS WINAPI UuidToStringA(UUID *Uuid, unsigned char** StringUuid) +{ + *StringUuid = HeapAlloc( GetProcessHeap(), 0, sizeof(char) * 37); + + if(!(*StringUuid)) + return RPC_S_OUT_OF_MEMORY; + + if (!Uuid) Uuid = &uuid_nil; + + sprintf(*StringUuid, "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + Uuid->Data1, Uuid->Data2, Uuid->Data3, + Uuid->Data4[0], Uuid->Data4[1], Uuid->Data4[2], + Uuid->Data4[3], Uuid->Data4[4], Uuid->Data4[5], + Uuid->Data4[6], Uuid->Data4[7] ); + + return RPC_S_OK; +} + +/************************************************************************* + * UuidToStringW [RPCRT4.@] + * + * Converts a UUID to a string. + * + * S_OK if successful. + * S_OUT_OF_MEMORY if unsucessful. + */ +RPC_STATUS WINAPI UuidToStringW(UUID *Uuid, unsigned short** StringUuid) +{ + char buf[37]; + + if (!Uuid) Uuid = &uuid_nil; + + sprintf(buf, "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + Uuid->Data1, Uuid->Data2, Uuid->Data3, + Uuid->Data4[0], Uuid->Data4[1], Uuid->Data4[2], + Uuid->Data4[3], Uuid->Data4[4], Uuid->Data4[5], + Uuid->Data4[6], Uuid->Data4[7] ); + + *StringUuid = RPCRT4_strdupAtoW(buf); + + if(!(*StringUuid)) + return RPC_S_OUT_OF_MEMORY; + + return RPC_S_OK; +} + +static const BYTE hex2bin[] = +{ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */ + 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */ + 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */ + 0,10,11,12,13,14,15 /* 0x60 */ +}; + +/*********************************************************************** + * UuidFromStringA (RPCRT4.@) + */ +RPC_STATUS WINAPI UuidFromStringA(unsigned char* str, UUID *uuid) +{ + BYTE *s = (BYTE *)str; + int i; + + if (!s) return UuidCreateNil( uuid ); + + if (strlen(s) != 36) return RPC_S_INVALID_STRING_UUID; + + if ((s[8]!='-') || (s[13]!='-') || (s[18]!='-') || (s[23]!='-')) + return RPC_S_INVALID_STRING_UUID; + + for (i=0; i<36; i++) + { + if ((i == 8)||(i == 13)||(i == 18)||(i == 23)) continue; + if (s[i] > 'f' || (!hex2bin[s[i]] && s[i] != '0')) return RPC_S_INVALID_STRING_UUID; + } + + /* in form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */ + + uuid->Data1 = (hex2bin[s[0]] << 28 | hex2bin[s[1]] << 24 | hex2bin[s[2]] << 20 | hex2bin[s[3]] << 16 | + hex2bin[s[4]] << 12 | hex2bin[s[5]] << 8 | hex2bin[s[6]] << 4 | hex2bin[s[7]]); + uuid->Data2 = hex2bin[s[9]] << 12 | hex2bin[s[10]] << 8 | hex2bin[s[11]] << 4 | hex2bin[s[12]]; + uuid->Data3 = hex2bin[s[14]] << 12 | hex2bin[s[15]] << 8 | hex2bin[s[16]] << 4 | hex2bin[s[17]]; + + /* these are just sequential bytes */ + uuid->Data4[0] = hex2bin[s[19]] << 4 | hex2bin[s[20]]; + uuid->Data4[1] = hex2bin[s[21]] << 4 | hex2bin[s[22]]; + uuid->Data4[2] = hex2bin[s[24]] << 4 | hex2bin[s[25]]; + uuid->Data4[3] = hex2bin[s[26]] << 4 | hex2bin[s[27]]; + uuid->Data4[4] = hex2bin[s[28]] << 4 | hex2bin[s[29]]; + uuid->Data4[5] = hex2bin[s[30]] << 4 | hex2bin[s[31]]; + uuid->Data4[6] = hex2bin[s[32]] << 4 | hex2bin[s[33]]; + uuid->Data4[7] = hex2bin[s[34]] << 4 | hex2bin[s[35]]; + return RPC_S_OK; +} + + +/*********************************************************************** + * UuidFromStringW (RPCRT4.@) + */ +RPC_STATUS WINAPI UuidFromStringW(unsigned short* s, UUID *uuid) +{ + int i; + + if (!s) return UuidCreateNil( uuid ); + + if (strlenW(s) != 36) return RPC_S_INVALID_STRING_UUID; + + if ((s[8]!='-') || (s[13]!='-') || (s[18]!='-') || (s[23]!='-')) + return RPC_S_INVALID_STRING_UUID; + + for (i=0; i<36; i++) + { + if ((i == 8)||(i == 13)||(i == 18)||(i == 23)) continue; + if (s[i] > 'f' || (!hex2bin[s[i]] && s[i] != '0')) return RPC_S_INVALID_STRING_UUID; + } + + /* in form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */ + + uuid->Data1 = (hex2bin[s[0]] << 28 | hex2bin[s[1]] << 24 | hex2bin[s[2]] << 20 | hex2bin[s[3]] << 16 | + hex2bin[s[4]] << 12 | hex2bin[s[5]] << 8 | hex2bin[s[6]] << 4 | hex2bin[s[7]]); + uuid->Data2 = hex2bin[s[9]] << 12 | hex2bin[s[10]] << 8 | hex2bin[s[11]] << 4 | hex2bin[s[12]]; + uuid->Data3 = hex2bin[s[14]] << 12 | hex2bin[s[15]] << 8 | hex2bin[s[16]] << 4 | hex2bin[s[17]]; + + /* these are just sequential bytes */ + uuid->Data4[0] = hex2bin[s[19]] << 4 | hex2bin[s[20]]; + uuid->Data4[1] = hex2bin[s[21]] << 4 | hex2bin[s[22]]; + uuid->Data4[2] = hex2bin[s[24]] << 4 | hex2bin[s[25]]; + uuid->Data4[3] = hex2bin[s[26]] << 4 | hex2bin[s[27]]; + uuid->Data4[4] = hex2bin[s[28]] << 4 | hex2bin[s[29]]; + uuid->Data4[5] = hex2bin[s[30]] << 4 | hex2bin[s[31]]; + uuid->Data4[6] = hex2bin[s[32]] << 4 | hex2bin[s[33]]; + uuid->Data4[7] = hex2bin[s[34]] << 4 | hex2bin[s[35]]; + return RPC_S_OK; +} + +/*********************************************************************** + * DllRegisterServer (RPCRT4.@) + */ + +HRESULT WINAPI RPCRT4_DllRegisterServer( void ) +{ + FIXME( "(): stub\n" ); + return S_OK; +} + +BOOL RPCRT4_StartRPCSS(void) +{ + PROCESS_INFORMATION pi; + STARTUPINFOA si; + static char cmd[6]; + BOOL rslt; + + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + ZeroMemory(&si, sizeof(STARTUPINFOA)); + si.cb = sizeof(STARTUPINFOA); + + /* apparently it's not OK to use a constant string below */ + CopyMemory(cmd, "rpcss", 6); + + /* FIXME: will this do the right thing when run as a test? */ + rslt = CreateProcessA( + NULL, /* executable */ + cmd, /* command line */ + NULL, /* process security attributes */ + NULL, /* primary thread security attributes */ + FALSE, /* inherit handles */ + 0, /* creation flags */ + NULL, /* use parent's environment */ + NULL, /* use parent's current directory */ + &si, /* STARTUPINFO pointer */ + &pi /* PROCESS_INFORMATION */ + ); + + if (rslt) { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + + return rslt; +} + +/*********************************************************************** + * RPCRT4_RPCSSOnDemandCall (internal) + * + * Attempts to send a message to the RPCSS process + * on the local machine, invoking it if necessary. + * For remote RPCSS calls, use.... your imagination. + * + * PARAMS + * msg [I] pointer to the RPCSS message + * vardata_payload [I] pointer vardata portion of the RPCSS message + * reply [O] pointer to reply structure + * + * RETURNS + * TRUE if successful + * FALSE otherwise + */ +BOOL RPCRT4_RPCSSOnDemandCall(PRPCSS_NP_MESSAGE msg, char *vardata_payload, PRPCSS_NP_REPLY reply) +{ + HANDLE client_handle; + int i, j = 0; + + TRACE("(msg == %p, vardata_payload == %p, reply == %p)\n", msg, vardata_payload, reply); + + client_handle = RPCRT4_RpcssNPConnect(); + + while (!client_handle) { + /* start the RPCSS process */ + if (!RPCRT4_StartRPCSS()) { + ERR("Unable to start RPCSS process.\n"); + return FALSE; + } + /* wait for a connection (w/ periodic polling) */ + for (i = 0; i < 60; i++) { + Sleep(200); + client_handle = RPCRT4_RpcssNPConnect(); + if (client_handle) break; + } + /* we are only willing to try twice */ + if (j++ >= 1) break; + } + + if (!client_handle) { + /* no dice! */ + ERR("Unable to connect to RPCSS process!\n"); + SetLastError(RPC_E_SERVER_DIED_DNE); + return FALSE; + } + + /* great, we're connected. now send the message */ + if (!RPCRT4_SendReceiveNPMsg(client_handle, msg, vardata_payload, reply)) { + ERR("Something is amiss: RPC_SendReceive failed.\n"); + return FALSE; + } + + return TRUE; +} + +#define MAX_RPC_ERROR_TEXT 256 + +/****************************************************************************** + * DceErrorInqTextW (rpcrt4.@) + * + * Notes + * 1. On passing a NULL pointer the code does bomb out. + * 2. The size of the required buffer is not defined in the documentation. + * It appears to be 256. + * 3. The function is defined to return RPC_S_INVALID_ARG but I don't know + * of any value for which it does. + * 4. The MSDN documentation currently declares that the second argument is + * unsigned char *, even for the W version. I don't believe it. + */ +RPC_STATUS RPC_ENTRY DceErrorInqTextW (RPC_STATUS e, unsigned short *buffer) +{ + DWORD count; + count = FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, e, 0, buffer, MAX_RPC_ERROR_TEXT, NULL); + if (!count) + { + count = FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, RPC_S_NOT_RPC_ERROR, 0, buffer, MAX_RPC_ERROR_TEXT, NULL); + if (!count) + { + ERR ("Failed to translate error"); + return RPC_S_INVALID_ARG; + } + } + return RPC_S_OK; +} + +/****************************************************************************** + * DceErrorInqTextA (rpcrt4.@) + */ +RPC_STATUS RPC_ENTRY DceErrorInqTextA (RPC_STATUS e, unsigned char *buffer) +{ + RPC_STATUS status; + WCHAR bufferW [MAX_RPC_ERROR_TEXT]; + if ((status = DceErrorInqTextW (e, bufferW)) == RPC_S_OK) + { + if (!WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_RPC_ERROR_TEXT, + NULL, NULL)) + { + ERR ("Failed to translate error"); + status = RPC_S_INVALID_ARG; + } + } + return status; +} diff --git a/reactos/lib/rpcrt4/rpcss_np_client.c b/reactos/lib/rpcrt4/rpcss_np_client.c index 67b42d70fc8..78d675e3c26 100644 --- a/reactos/lib/rpcrt4/rpcss_np_client.c +++ b/reactos/lib/rpcrt4/rpcss_np_client.c @@ -1,155 +1,155 @@ -/* - * RPCSS named pipe client implementation - * - * Copyright (C) 2002 Greg Turner - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <assert.h> -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "ntstatus.h" -#include "wine/rpcss_shared.h" -#include "wine/debug.h" - -#include "rpc_binding.h" - -WINE_DEFAULT_DEBUG_CHANNEL(ole); - -HANDLE RPCRT4_RpcssNPConnect(void) -{ - HANDLE the_pipe = NULL; - DWORD dwmode, wait_result; - HANDLE master_mutex = RPCRT4_GetMasterMutex(); - - TRACE("\n"); - - while (TRUE) { - - wait_result = WaitForSingleObject(master_mutex, MASTER_MUTEX_TIMEOUT); - switch (wait_result) { - case WAIT_ABANDONED: - case WAIT_OBJECT_0: - break; - case WAIT_FAILED: - case WAIT_TIMEOUT: - default: - ERR("This should never happen: couldn't enter mutex.\n"); - return NULL; - } - - /* try to open the client side of the named pipe. */ - the_pipe = CreateFileA( - NAME_RPCSS_NAMED_PIPE, /* pipe name */ - GENERIC_READ | GENERIC_WRITE, /* r/w access */ - 0, /* no sharing */ - NULL, /* no security attributes */ - OPEN_EXISTING, /* open an existing pipe */ - 0, /* default attributes */ - NULL /* no template file */ - ); - - if (the_pipe != INVALID_HANDLE_VALUE) - break; - - if (GetLastError() != ERROR_PIPE_BUSY) { - WARN("Unable to open named pipe %s (assuming unavailable).\n", - debugstr_a(NAME_RPCSS_NAMED_PIPE)); - the_pipe = NULL; - break; - } - - WARN("Named pipe busy (will wait)\n"); - - if (!ReleaseMutex(master_mutex)) - ERR("Failed to release master mutex. Expect deadlock.\n"); - - /* wait for the named pipe. We are only - willing to wait only 5 seconds. It should be available /very/ soon. */ - if (! WaitNamedPipeA(NAME_RPCSS_NAMED_PIPE, MASTER_MUTEX_WAITNAMEDPIPE_TIMEOUT)) - { - ERR("Named pipe unavailable after waiting. Something is probably wrong.\n"); - the_pipe = NULL; - break; - } - - } - - if (the_pipe) { - dwmode = PIPE_READMODE_MESSAGE; - /* SetNamedPipeHandleState not implemented ATM, but still seems to work somehow. */ - if (! SetNamedPipeHandleState(the_pipe, &dwmode, NULL, NULL)) - WARN("Failed to set pipe handle state\n"); - } - - if (!ReleaseMutex(master_mutex)) - ERR("Uh oh, failed to leave the RPC Master Mutex!\n"); - - return the_pipe; -} - -BOOL RPCRT4_SendReceiveNPMsg(HANDLE np, PRPCSS_NP_MESSAGE msg, char *vardata, PRPCSS_NP_REPLY reply) -{ - DWORD count; - UINT32 payload_offset; - RPCSS_NP_MESSAGE vardata_payload_msg; - - TRACE("(np == %p, msg == %p, vardata == %p, reply == %p)\n", - np, msg, vardata, reply); - - if (! WriteFile(np, msg, sizeof(RPCSS_NP_MESSAGE), &count, NULL)) { - ERR("write failed.\n"); - return FALSE; - } - - if (count != sizeof(RPCSS_NP_MESSAGE)) { - ERR("write count mismatch.\n"); - return FALSE; - } - - /* process the vardata payload if necessary */ - vardata_payload_msg.message_type = RPCSS_NP_MESSAGE_TYPEID_VARDATAPAYLOADMSG; - vardata_payload_msg.vardata_payload_size = 0; /* meaningless */ - for ( payload_offset = 0; payload_offset < msg->vardata_payload_size; - payload_offset += VARDATA_PAYLOAD_BYTES ) { - TRACE("sending vardata payload. vd=%p, po=%d, ps=%d\n", vardata, - payload_offset, msg->vardata_payload_size); - ZeroMemory(vardata_payload_msg.message.vardatapayloadmsg.payload, VARDATA_PAYLOAD_BYTES); - CopyMemory(vardata_payload_msg.message.vardatapayloadmsg.payload, - vardata, - min( VARDATA_PAYLOAD_BYTES, msg->vardata_payload_size - payload_offset )); - vardata += VARDATA_PAYLOAD_BYTES; - if (! WriteFile(np, &vardata_payload_msg, sizeof(RPCSS_NP_MESSAGE), &count, NULL)) { - ERR("vardata write failed at %u bytes.\n", payload_offset); - return FALSE; - } - } - - if (! ReadFile(np, reply, sizeof(RPCSS_NP_REPLY), &count, NULL)) { - ERR("read failed.\n"); - return FALSE; - } - - if (count != sizeof(RPCSS_NP_REPLY)) { - ERR("read count mismatch. got %ld, expected %u.\n", count, sizeof(RPCSS_NP_REPLY)); - return FALSE; - } - - /* message execution was successful */ - return TRUE; -} +/* + * RPCSS named pipe client implementation + * + * Copyright (C) 2002 Greg Turner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <assert.h> +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "ntstatus.h" +#include "wine/rpcss_shared.h" +#include "wine/debug.h" + +#include "rpc_binding.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +HANDLE RPCRT4_RpcssNPConnect(void) +{ + HANDLE the_pipe = NULL; + DWORD dwmode, wait_result; + HANDLE master_mutex = RPCRT4_GetMasterMutex(); + + TRACE("\n"); + + while (TRUE) { + + wait_result = WaitForSingleObject(master_mutex, MASTER_MUTEX_TIMEOUT); + switch (wait_result) { + case WAIT_ABANDONED: + case WAIT_OBJECT_0: + break; + case WAIT_FAILED: + case WAIT_TIMEOUT: + default: + ERR("This should never happen: couldn't enter mutex.\n"); + return NULL; + } + + /* try to open the client side of the named pipe. */ + the_pipe = CreateFileA( + NAME_RPCSS_NAMED_PIPE, /* pipe name */ + GENERIC_READ | GENERIC_WRITE, /* r/w access */ + 0, /* no sharing */ + NULL, /* no security attributes */ + OPEN_EXISTING, /* open an existing pipe */ + 0, /* default attributes */ + NULL /* no template file */ + ); + + if (the_pipe != INVALID_HANDLE_VALUE) + break; + + if (GetLastError() != ERROR_PIPE_BUSY) { + WARN("Unable to open named pipe %s (assuming unavailable).\n", + debugstr_a(NAME_RPCSS_NAMED_PIPE)); + the_pipe = NULL; + break; + } + + WARN("Named pipe busy (will wait)\n"); + + if (!ReleaseMutex(master_mutex)) + ERR("Failed to release master mutex. Expect deadlock.\n"); + + /* wait for the named pipe. We are only + willing to wait only 5 seconds. It should be available /very/ soon. */ + if (! WaitNamedPipeA(NAME_RPCSS_NAMED_PIPE, MASTER_MUTEX_WAITNAMEDPIPE_TIMEOUT)) + { + ERR("Named pipe unavailable after waiting. Something is probably wrong.\n"); + the_pipe = NULL; + break; + } + + } + + if (the_pipe) { + dwmode = PIPE_READMODE_MESSAGE; + /* SetNamedPipeHandleState not implemented ATM, but still seems to work somehow. */ + if (! SetNamedPipeHandleState(the_pipe, &dwmode, NULL, NULL)) + WARN("Failed to set pipe handle state\n"); + } + + if (!ReleaseMutex(master_mutex)) + ERR("Uh oh, failed to leave the RPC Master Mutex!\n"); + + return the_pipe; +} + +BOOL RPCRT4_SendReceiveNPMsg(HANDLE np, PRPCSS_NP_MESSAGE msg, char *vardata, PRPCSS_NP_REPLY reply) +{ + DWORD count; + UINT32 payload_offset; + RPCSS_NP_MESSAGE vardata_payload_msg; + + TRACE("(np == %p, msg == %p, vardata == %p, reply == %p)\n", + np, msg, vardata, reply); + + if (! WriteFile(np, msg, sizeof(RPCSS_NP_MESSAGE), &count, NULL)) { + ERR("write failed.\n"); + return FALSE; + } + + if (count != sizeof(RPCSS_NP_MESSAGE)) { + ERR("write count mismatch.\n"); + return FALSE; + } + + /* process the vardata payload if necessary */ + vardata_payload_msg.message_type = RPCSS_NP_MESSAGE_TYPEID_VARDATAPAYLOADMSG; + vardata_payload_msg.vardata_payload_size = 0; /* meaningless */ + for ( payload_offset = 0; payload_offset < msg->vardata_payload_size; + payload_offset += VARDATA_PAYLOAD_BYTES ) { + TRACE("sending vardata payload. vd=%p, po=%d, ps=%d\n", vardata, + payload_offset, msg->vardata_payload_size); + ZeroMemory(vardata_payload_msg.message.vardatapayloadmsg.payload, VARDATA_PAYLOAD_BYTES); + CopyMemory(vardata_payload_msg.message.vardatapayloadmsg.payload, + vardata, + min( VARDATA_PAYLOAD_BYTES, msg->vardata_payload_size - payload_offset )); + vardata += VARDATA_PAYLOAD_BYTES; + if (! WriteFile(np, &vardata_payload_msg, sizeof(RPCSS_NP_MESSAGE), &count, NULL)) { + ERR("vardata write failed at %u bytes.\n", payload_offset); + return FALSE; + } + } + + if (! ReadFile(np, reply, sizeof(RPCSS_NP_REPLY), &count, NULL)) { + ERR("read failed.\n"); + return FALSE; + } + + if (count != sizeof(RPCSS_NP_REPLY)) { + ERR("read count mismatch. got %ld, expected %u.\n", count, sizeof(RPCSS_NP_REPLY)); + return FALSE; + } + + /* message execution was successful */ + return TRUE; +} diff --git a/reactos/lib/rpcrt4/rpcss_np_client.h b/reactos/lib/rpcrt4/rpcss_np_client.h index 54793151353..c50e8ada80f 100644 --- a/reactos/lib/rpcrt4/rpcss_np_client.h +++ b/reactos/lib/rpcrt4/rpcss_np_client.h @@ -1,26 +1,26 @@ -/* - * Copyright (C) 2002 Greg Turner - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_RPCSS_NP_CLIENT_H -#define __WINE_RPCSS_NP_CLIENT_H - -/* rpcss_np_client.c */ -HANDLE RPC_RpcssNPConnect(void); -BOOL RPCRT4_SendReceiveNPMsg(HANDLE, PRPCSS_NP_MESSAGE, char *, PRPCSS_NP_REPLY); - -#endif /* __RPCSS_NP_CLINET_H */ +/* + * Copyright (C) 2002 Greg Turner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_RPCSS_NP_CLIENT_H +#define __WINE_RPCSS_NP_CLIENT_H + +/* rpcss_np_client.c */ +HANDLE RPC_RpcssNPConnect(void); +BOOL RPCRT4_SendReceiveNPMsg(HANDLE, PRPCSS_NP_MESSAGE, char *, PRPCSS_NP_REPLY); + +#endif /* __RPCSS_NP_CLINET_H */ diff --git a/reactos/lib/rtl/qsort.c b/reactos/lib/rtl/qsort.c index 7846708dfe6..77549202abf 100644 --- a/reactos/lib/rtl/qsort.c +++ b/reactos/lib/rtl/qsort.c @@ -1,266 +1,266 @@ -/* $Id: qsort.c 12852 2005-01-06 13:58:04Z mf $ - * - * FILE: ntoskrnl/rtl/qsort.c - * NOTE: Adapted from CygWin newlib 2000-03-12. - */ -/* -FUNCTION -<<qsort>>---sort an array - -INDEX - qsort - -ANSI_SYNOPSIS - #include <stdlib.h> - void qsort(void *<[base]>, size_t <[nmemb]>, size_t <[size]>, - int (*<[compar]>)(const void *, const void *) ); - -TRAD_SYNOPSIS - #include <stdlib.h> - qsort(<[base]>, <[nmemb]>, <[size]>, <[compar]> ) - char *<[base]>; - size_t <[nmemb]>; - size_t <[size]>; - int (*<[compar]>)(); - -DESCRIPTION -<<qsort>> sorts an array (beginning at <[base]>) of <[nmemb]> objects. -<[size]> describes the size of each element of the array. - -You must supply a pointer to a comparison function, using the argument -shown as <[compar]>. (This permits sorting objects of unknown -properties.) Define the comparison function to accept two arguments, -each a pointer to an element of the array starting at <[base]>. The -result of <<(*<[compar]>)>> must be negative if the first argument is -less than the second, zero if the two arguments match, and positive if -the first argument is greater than the second (where ``less than'' and -``greater than'' refer to whatever arbitrary ordering is appropriate). - -The array is sorted in place; that is, when <<qsort>> returns, the -array elements beginning at <[base]> have been reordered. - -RETURNS -<<qsort>> does not return a result. - -PORTABILITY -<<qsort>> is required by ANSI (without specifying the sorting algorithm). -*/ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef __GNUC__ -#define inline -#endif - -/* FIXME: these types should be from the default includes */ - -typedef int (* _pfunccmp_t) (char *, char *); -typedef int size_t; - -#define min(a,b) ((a)<(b)?(a):(b)) - -/* - * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". - */ -#define swapcode(TYPE, parmi, parmj, n) { \ - long i = (n) / sizeof (TYPE); \ - register TYPE *pi = (TYPE *) (parmi); \ - register TYPE *pj = (TYPE *) (parmj); \ - do { \ - register TYPE t = *pi; \ - *pi++ = *pj; \ - *pj++ = t; \ - } while (--i > 0); \ -} - -#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ - es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; - -static inline void -swapfunc ( - char * a, - char * b, - int n, - int swaptype - ) -{ - if(swaptype <= 1) - swapcode(long, a, b, n) - else - swapcode(char, a, b, n) -} - -#define swap(a, b) \ - if (swaptype == 0) { \ - long t = *(long *)(a); \ - *(long *)(a) = *(long *)(b); \ - *(long *)(b) = t; \ - } else \ - swapfunc(a, b, es, swaptype) - -#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) - -static inline char * -med3 ( - char * a, - char * b, - char * c, - _pfunccmp_t cmp - ) -{ - return cmp(a, b) < 0 ? - (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a )) - :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); -} - - -/* EXPORTED */ -void -qsort ( - void * a, - size_t n, - size_t es, - _pfunccmp_t cmp - ) -{ - char *pa, *pb, *pc, *pd, *pl, *pm, *pn; - int d, r, swaptype, swap_cnt; - -loop: SWAPINIT(a, es); - swap_cnt = 0; - if (n < 7) - { - for ( pm = (char *) a + es; - pm < (char *) a + n * es; - pm += es - ) - { - for ( pl = pm; - pl > (char *) a && cmp(pl - es, pl) > 0; - pl -= es - ) - { - swap(pl, pl - es); - } - } - return; - } - pm = (char *) a + (n / 2) * es; - if (n > 7) - { - pl = (char *) a; - pn = (char *) a + (n - 1) * es; - if (n > 40) - { - d = (n / 8) * es; - pl = med3(pl, pl + d, pl + 2 * d, cmp); - pm = med3(pm - d, pm, pm + d, cmp); - pn = med3(pn - 2 * d, pn - d, pn, cmp); - } - pm = med3(pl, pm, pn, cmp); - } - swap(a, pm); - pa = pb = (char *) a + es; - - pc = pd = (char *) a + (n - 1) * es; - for (;;) - { - while (pb <= pc && (r = cmp(pb, a)) <= 0) - { - if (r == 0) - { - swap_cnt = 1; - swap(pa, pb); - pa += es; - } - pb += es; - } - while (pb <= pc && (r = cmp(pc, a)) >= 0) - { - if (r == 0) - { - swap_cnt = 1; - swap(pc, pd); - pd -= es; - } - pc -= es; - } - if (pb > pc) - { - break; - } - swap(pb, pc); - swap_cnt = 1; - pb += es; - pc -= es; - } - if (swap_cnt == 0) /* Switch to insertion sort */ - { - for ( pm = (char *) a + es; - pm < (char *) a + n * es; - pm += es - ) - { - for ( pl = pm; - pl > (char *) a && cmp(pl - es, pl) > 0; - pl -= es - ) - { - swap(pl, pl - es); - } - } - return; - } - - pn = (char *) a + n * es; - r = min(pa - (char *)a, pb - pa); - vecswap(a, pb - r, r); - r = min(pd - pc, pn - pd - es); - vecswap(pb, pn - r, r); - if ((r = pb - pa) > es) - { - qsort(a, r / es, es, cmp); - } - if ((r = pd - pc) > es) - { - /* Iterate rather than recurse to save stack space */ - a = pn - r; - n = r / es; - goto loop; - } -/* qsort(pn - r, r / es, es, cmp);*/ -} - - -/* EOF */ +/* $Id: qsort.c 12852 2005-01-06 13:58:04Z mf $ + * + * FILE: ntoskrnl/rtl/qsort.c + * NOTE: Adapted from CygWin newlib 2000-03-12. + */ +/* +FUNCTION +<<qsort>>---sort an array + +INDEX + qsort + +ANSI_SYNOPSIS + #include <stdlib.h> + void qsort(void *<[base]>, size_t <[nmemb]>, size_t <[size]>, + int (*<[compar]>)(const void *, const void *) ); + +TRAD_SYNOPSIS + #include <stdlib.h> + qsort(<[base]>, <[nmemb]>, <[size]>, <[compar]> ) + char *<[base]>; + size_t <[nmemb]>; + size_t <[size]>; + int (*<[compar]>)(); + +DESCRIPTION +<<qsort>> sorts an array (beginning at <[base]>) of <[nmemb]> objects. +<[size]> describes the size of each element of the array. + +You must supply a pointer to a comparison function, using the argument +shown as <[compar]>. (This permits sorting objects of unknown +properties.) Define the comparison function to accept two arguments, +each a pointer to an element of the array starting at <[base]>. The +result of <<(*<[compar]>)>> must be negative if the first argument is +less than the second, zero if the two arguments match, and positive if +the first argument is greater than the second (where ``less than'' and +``greater than'' refer to whatever arbitrary ordering is appropriate). + +The array is sorted in place; that is, when <<qsort>> returns, the +array elements beginning at <[base]> have been reordered. + +RETURNS +<<qsort>> does not return a result. + +PORTABILITY +<<qsort>> is required by ANSI (without specifying the sorting algorithm). +*/ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __GNUC__ +#define inline +#endif + +/* FIXME: these types should be from the default includes */ + +typedef int (* _pfunccmp_t) (char *, char *); +typedef int size_t; + +#define min(a,b) ((a)<(b)?(a):(b)) + +/* + * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". + */ +#define swapcode(TYPE, parmi, parmj, n) { \ + long i = (n) / sizeof (TYPE); \ + register TYPE *pi = (TYPE *) (parmi); \ + register TYPE *pj = (TYPE *) (parmj); \ + do { \ + register TYPE t = *pi; \ + *pi++ = *pj; \ + *pj++ = t; \ + } while (--i > 0); \ +} + +#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ + es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; + +static inline void +swapfunc ( + char * a, + char * b, + int n, + int swaptype + ) +{ + if(swaptype <= 1) + swapcode(long, a, b, n) + else + swapcode(char, a, b, n) +} + +#define swap(a, b) \ + if (swaptype == 0) { \ + long t = *(long *)(a); \ + *(long *)(a) = *(long *)(b); \ + *(long *)(b) = t; \ + } else \ + swapfunc(a, b, es, swaptype) + +#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) + +static inline char * +med3 ( + char * a, + char * b, + char * c, + _pfunccmp_t cmp + ) +{ + return cmp(a, b) < 0 ? + (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a )) + :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); +} + + +/* EXPORTED */ +void +qsort ( + void * a, + size_t n, + size_t es, + _pfunccmp_t cmp + ) +{ + char *pa, *pb, *pc, *pd, *pl, *pm, *pn; + int d, r, swaptype, swap_cnt; + +loop: SWAPINIT(a, es); + swap_cnt = 0; + if (n < 7) + { + for ( pm = (char *) a + es; + pm < (char *) a + n * es; + pm += es + ) + { + for ( pl = pm; + pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es + ) + { + swap(pl, pl - es); + } + } + return; + } + pm = (char *) a + (n / 2) * es; + if (n > 7) + { + pl = (char *) a; + pn = (char *) a + (n - 1) * es; + if (n > 40) + { + d = (n / 8) * es; + pl = med3(pl, pl + d, pl + 2 * d, cmp); + pm = med3(pm - d, pm, pm + d, cmp); + pn = med3(pn - 2 * d, pn - d, pn, cmp); + } + pm = med3(pl, pm, pn, cmp); + } + swap(a, pm); + pa = pb = (char *) a + es; + + pc = pd = (char *) a + (n - 1) * es; + for (;;) + { + while (pb <= pc && (r = cmp(pb, a)) <= 0) + { + if (r == 0) + { + swap_cnt = 1; + swap(pa, pb); + pa += es; + } + pb += es; + } + while (pb <= pc && (r = cmp(pc, a)) >= 0) + { + if (r == 0) + { + swap_cnt = 1; + swap(pc, pd); + pd -= es; + } + pc -= es; + } + if (pb > pc) + { + break; + } + swap(pb, pc); + swap_cnt = 1; + pb += es; + pc -= es; + } + if (swap_cnt == 0) /* Switch to insertion sort */ + { + for ( pm = (char *) a + es; + pm < (char *) a + n * es; + pm += es + ) + { + for ( pl = pm; + pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es + ) + { + swap(pl, pl - es); + } + } + return; + } + + pn = (char *) a + n * es; + r = min(pa - (char *)a, pb - pa); + vecswap(a, pb - r, r); + r = min(pd - pc, pn - pd - es); + vecswap(pb, pn - r, r); + if ((r = pb - pa) > es) + { + qsort(a, r / es, es, cmp); + } + if ((r = pd - pc) > es) + { + /* Iterate rather than recurse to save stack space */ + a = pn - r; + n = r / es; + goto loop; + } +/* qsort(pn - r, r / es, es, cmp);*/ +} + + +/* EOF */ diff --git a/reactos/lib/setupapi/rpc_private.h b/reactos/lib/setupapi/rpc_private.h index cfd3f9e7271..04ab2839a97 100644 --- a/reactos/lib/setupapi/rpc_private.h +++ b/reactos/lib/setupapi/rpc_private.h @@ -1,31 +1,31 @@ -/* - * Copyright 2005 Eric Kohl - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __RPC_PRIVATE_H -#define __RPC_PRIVATE_H - -RPC_STATUS PnpBindRpc(LPCWSTR pszMachine, - RPC_BINDING_HANDLE* BindingHandle); -RPC_STATUS PnpUnbindRpc(RPC_BINDING_HANDLE *BindingHandle); - -BOOL -PnpGetLocalHandles(RPC_BINDING_HANDLE *BindingHandle, - HSTRING_TABLE *StringTable); -RPC_STATUS PnpUnbindLocalHandles(VOID); - -#endif /* __RPC_PRIVATE_H */ +/* + * Copyright 2005 Eric Kohl + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __RPC_PRIVATE_H +#define __RPC_PRIVATE_H + +RPC_STATUS PnpBindRpc(LPCWSTR pszMachine, + RPC_BINDING_HANDLE* BindingHandle); +RPC_STATUS PnpUnbindRpc(RPC_BINDING_HANDLE *BindingHandle); + +BOOL +PnpGetLocalHandles(RPC_BINDING_HANDLE *BindingHandle, + HSTRING_TABLE *StringTable); +RPC_STATUS PnpUnbindLocalHandles(VOID); + +#endif /* __RPC_PRIVATE_H */ diff --git a/reactos/lib/shdocvw/classinfo.c b/reactos/lib/shdocvw/classinfo.c index 11f888e867c..13c954e1617 100644 --- a/reactos/lib/shdocvw/classinfo.c +++ b/reactos/lib/shdocvw/classinfo.c @@ -1,166 +1,166 @@ -/* - * Implementation of IProvideClassInfo interfaces for IE Web Browser control - * - * Copyright 2001 John R. Sheets (for CodeWeavers) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> -#include <string.h> - -#include "windef.h" -#include "winbase.h" -#include "shdocvw.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(shdocvw); - -/********************************************************************** - * Implement the IProvideClassInfo interface - * - * FIXME: Should we just pass in the IProvideClassInfo2 methods rather - * reimplementing them here? - */ - -static HRESULT WINAPI WBPCI_QueryInterface(LPPROVIDECLASSINFO iface, - REFIID riid, LPVOID *ppobj) -{ - FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); - - if (ppobj == NULL) return E_POINTER; - - return E_NOINTERFACE; -} - -static ULONG WINAPI WBPCI_AddRef(LPPROVIDECLASSINFO iface) -{ - SHDOCVW_LockModule(); - - return 2; /* non-heap based object */ -} - -static ULONG WINAPI WBPCI_Release(LPPROVIDECLASSINFO iface) -{ - SHDOCVW_UnlockModule(); - - return 1; /* non-heap based object */ -} - -/* Return an ITypeInfo interface to retrieve type library info about - * this control. - */ -static HRESULT WINAPI WBPCI_GetClassInfo(LPPROVIDECLASSINFO iface, LPTYPEINFO *ppTI) -{ - FIXME("stub: LPTYPEINFO = %p\n", *ppTI); - return S_OK; -} - -/********************************************************************** - * IProvideClassInfo virtual function table for IE Web Browser component - */ - -static IProvideClassInfoVtbl WBPCI_Vtbl = -{ - WBPCI_QueryInterface, - WBPCI_AddRef, - WBPCI_Release, - WBPCI_GetClassInfo -}; - -IProvideClassInfoImpl SHDOCVW_ProvideClassInfo = { &WBPCI_Vtbl}; - - -/********************************************************************** - * Implement the IProvideClassInfo2 interface (inherits from - * IProvideClassInfo). - */ - -static HRESULT WINAPI WBPCI2_QueryInterface(LPPROVIDECLASSINFO2 iface, - REFIID riid, LPVOID *ppobj) -{ - FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); - - if (ppobj == NULL) return E_POINTER; - - return E_NOINTERFACE; -} - -static ULONG WINAPI WBPCI2_AddRef(LPPROVIDECLASSINFO2 iface) -{ - SHDOCVW_LockModule(); - - return 2; /* non-heap based object */ -} - -static ULONG WINAPI WBPCI2_Release(LPPROVIDECLASSINFO2 iface) -{ - SHDOCVW_UnlockModule(); - - return 1; /* non-heap based object */ -} - -/* Return an ITypeInfo interface to retrieve type library info about - * this control. - */ -static HRESULT WINAPI WBPCI2_GetClassInfo(LPPROVIDECLASSINFO2 iface, LPTYPEINFO *ppTI) -{ - FIXME("stub: LPTYPEINFO = %p\n", *ppTI); - return S_OK; -} - -/* Get the IID for generic default event callbacks. This IID will - * in theory be used to later query for an IConnectionPoint to connect - * an event sink (callback implementation in the OLE control site) - * to this control. -*/ -static HRESULT WINAPI WBPCI2_GetGUID(LPPROVIDECLASSINFO2 iface, - DWORD dwGuidKind, GUID *pGUID) -{ - FIXME("stub: dwGuidKind = %ld, pGUID = %s\n", dwGuidKind, debugstr_guid(pGUID)); - - if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID) - { - FIXME ("Requested unsupported GUID type: %ld\n", dwGuidKind); - return E_FAIL; /* Is there a better return type here? */ - } - - /* FIXME: Returning IPropertyNotifySink interface, but should really - * return a more generic event set (???) dispinterface. - * However, this hack, allows a control site to return with success - * (MFC's COleControlSite falls back to older IProvideClassInfo interface - * if GetGUID() fails to return a non-NULL GUID). - */ - memcpy(pGUID, &IID_IPropertyNotifySink, sizeof(GUID)); - FIXME("Wrongly returning IPropertyNotifySink interface %s\n", - debugstr_guid(pGUID)); - - return S_OK; -} - -/********************************************************************** - * IProvideClassInfo virtual function table for IE Web Browser component - */ - -static IProvideClassInfo2Vtbl WBPCI2_Vtbl = -{ - WBPCI2_QueryInterface, - WBPCI2_AddRef, - WBPCI2_Release, - WBPCI2_GetClassInfo, - WBPCI2_GetGUID -}; - -IProvideClassInfo2Impl SHDOCVW_ProvideClassInfo2 = { &WBPCI2_Vtbl}; +/* + * Implementation of IProvideClassInfo interfaces for IE Web Browser control + * + * Copyright 2001 John R. Sheets (for CodeWeavers) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> +#include <string.h> + +#include "windef.h" +#include "winbase.h" +#include "shdocvw.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shdocvw); + +/********************************************************************** + * Implement the IProvideClassInfo interface + * + * FIXME: Should we just pass in the IProvideClassInfo2 methods rather + * reimplementing them here? + */ + +static HRESULT WINAPI WBPCI_QueryInterface(LPPROVIDECLASSINFO iface, + REFIID riid, LPVOID *ppobj) +{ + FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); + + if (ppobj == NULL) return E_POINTER; + + return E_NOINTERFACE; +} + +static ULONG WINAPI WBPCI_AddRef(LPPROVIDECLASSINFO iface) +{ + SHDOCVW_LockModule(); + + return 2; /* non-heap based object */ +} + +static ULONG WINAPI WBPCI_Release(LPPROVIDECLASSINFO iface) +{ + SHDOCVW_UnlockModule(); + + return 1; /* non-heap based object */ +} + +/* Return an ITypeInfo interface to retrieve type library info about + * this control. + */ +static HRESULT WINAPI WBPCI_GetClassInfo(LPPROVIDECLASSINFO iface, LPTYPEINFO *ppTI) +{ + FIXME("stub: LPTYPEINFO = %p\n", *ppTI); + return S_OK; +} + +/********************************************************************** + * IProvideClassInfo virtual function table for IE Web Browser component + */ + +static IProvideClassInfoVtbl WBPCI_Vtbl = +{ + WBPCI_QueryInterface, + WBPCI_AddRef, + WBPCI_Release, + WBPCI_GetClassInfo +}; + +IProvideClassInfoImpl SHDOCVW_ProvideClassInfo = { &WBPCI_Vtbl}; + + +/********************************************************************** + * Implement the IProvideClassInfo2 interface (inherits from + * IProvideClassInfo). + */ + +static HRESULT WINAPI WBPCI2_QueryInterface(LPPROVIDECLASSINFO2 iface, + REFIID riid, LPVOID *ppobj) +{ + FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); + + if (ppobj == NULL) return E_POINTER; + + return E_NOINTERFACE; +} + +static ULONG WINAPI WBPCI2_AddRef(LPPROVIDECLASSINFO2 iface) +{ + SHDOCVW_LockModule(); + + return 2; /* non-heap based object */ +} + +static ULONG WINAPI WBPCI2_Release(LPPROVIDECLASSINFO2 iface) +{ + SHDOCVW_UnlockModule(); + + return 1; /* non-heap based object */ +} + +/* Return an ITypeInfo interface to retrieve type library info about + * this control. + */ +static HRESULT WINAPI WBPCI2_GetClassInfo(LPPROVIDECLASSINFO2 iface, LPTYPEINFO *ppTI) +{ + FIXME("stub: LPTYPEINFO = %p\n", *ppTI); + return S_OK; +} + +/* Get the IID for generic default event callbacks. This IID will + * in theory be used to later query for an IConnectionPoint to connect + * an event sink (callback implementation in the OLE control site) + * to this control. +*/ +static HRESULT WINAPI WBPCI2_GetGUID(LPPROVIDECLASSINFO2 iface, + DWORD dwGuidKind, GUID *pGUID) +{ + FIXME("stub: dwGuidKind = %ld, pGUID = %s\n", dwGuidKind, debugstr_guid(pGUID)); + + if (dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID) + { + FIXME ("Requested unsupported GUID type: %ld\n", dwGuidKind); + return E_FAIL; /* Is there a better return type here? */ + } + + /* FIXME: Returning IPropertyNotifySink interface, but should really + * return a more generic event set (???) dispinterface. + * However, this hack, allows a control site to return with success + * (MFC's COleControlSite falls back to older IProvideClassInfo interface + * if GetGUID() fails to return a non-NULL GUID). + */ + memcpy(pGUID, &IID_IPropertyNotifySink, sizeof(GUID)); + FIXME("Wrongly returning IPropertyNotifySink interface %s\n", + debugstr_guid(pGUID)); + + return S_OK; +} + +/********************************************************************** + * IProvideClassInfo virtual function table for IE Web Browser component + */ + +static IProvideClassInfo2Vtbl WBPCI2_Vtbl = +{ + WBPCI2_QueryInterface, + WBPCI2_AddRef, + WBPCI2_Release, + WBPCI2_GetClassInfo, + WBPCI2_GetGUID +}; + +IProvideClassInfo2Impl SHDOCVW_ProvideClassInfo2 = { &WBPCI2_Vtbl}; diff --git a/reactos/lib/shdocvw/events.c b/reactos/lib/shdocvw/events.c index df611246e18..96ef64bb34d 100644 --- a/reactos/lib/shdocvw/events.c +++ b/reactos/lib/shdocvw/events.c @@ -1,208 +1,208 @@ -/* - * Implementation of event-related interfaces for IE Web Browser control: - * - * - IConnectionPointContainer - * - IConnectionPoint - * - * Copyright 2001 John R. Sheets (for CodeWeavers) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <string.h> -#include "wine/debug.h" -#include "shdocvw.h" - -WINE_DEFAULT_DEBUG_CHANNEL(shdocvw); - - -static const GUID IID_INotifyDBEvents = - { 0xdb526cc0, 0xd188, 0x11cd, { 0xad, 0x48, 0x00, 0xaa, 0x00, 0x3c, 0x9c, 0xb6 } }; - -/********************************************************************** - * Implement the IConnectionPointContainer interface - */ - -static HRESULT WINAPI WBCPC_QueryInterface(LPCONNECTIONPOINTCONTAINER iface, - REFIID riid, LPVOID *ppobj) -{ - FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); - - if (ppobj == NULL) return E_POINTER; - - return E_NOINTERFACE; -} - -static ULONG WINAPI WBCPC_AddRef(LPCONNECTIONPOINTCONTAINER iface) -{ - SHDOCVW_LockModule(); - - return 2; /* non-heap based object */ -} - -static ULONG WINAPI WBCPC_Release(LPCONNECTIONPOINTCONTAINER iface) -{ - SHDOCVW_UnlockModule(); - - return 1; /* non-heap based object */ -} - -/* Get a list of connection points inside this container. */ -static HRESULT WINAPI WBCPC_EnumConnectionPoints(LPCONNECTIONPOINTCONTAINER iface, - LPENUMCONNECTIONPOINTS *ppEnum) -{ - FIXME("stub: IEnumConnectionPoints = %p\n", *ppEnum); - return S_OK; -} - -/* Retrieve the connection point in this container associated with the - * riid interface. When events occur in the control, the control can - * call backwards into its embedding site, through these interfaces. - */ -static HRESULT WINAPI WBCPC_FindConnectionPoint(LPCONNECTIONPOINTCONTAINER iface, - REFIID riid, LPCONNECTIONPOINT *ppCP) -{ - TRACE(": IID = %s, IConnectionPoint = %p\n", debugstr_guid(riid), *ppCP); - - /* For now, return the same IConnectionPoint object for both - * event interface requests. - */ - if (IsEqualGUID (&IID_INotifyDBEvents, riid)) - { - TRACE("Returning connection point %p for IID_INotifyDBEvents\n", - &SHDOCVW_ConnectionPoint); - *ppCP = (LPCONNECTIONPOINT)&SHDOCVW_ConnectionPoint; - return S_OK; - } - else if (IsEqualGUID (&IID_IPropertyNotifySink, riid)) - { - TRACE("Returning connection point %p for IID_IPropertyNotifySink\n", - &SHDOCVW_ConnectionPoint); - *ppCP = (LPCONNECTIONPOINT)&SHDOCVW_ConnectionPoint; - return S_OK; - } - - return E_FAIL; -} - -/********************************************************************** - * IConnectionPointContainer virtual function table for IE Web Browser component - */ - -static IConnectionPointContainerVtbl WBCPC_Vtbl = -{ - WBCPC_QueryInterface, - WBCPC_AddRef, - WBCPC_Release, - WBCPC_EnumConnectionPoints, - WBCPC_FindConnectionPoint -}; - -IConnectionPointContainerImpl SHDOCVW_ConnectionPointContainer = {&WBCPC_Vtbl}; - - -/********************************************************************** - * Implement the IConnectionPoint interface - */ - -static HRESULT WINAPI WBCP_QueryInterface(LPCONNECTIONPOINT iface, - REFIID riid, LPVOID *ppobj) -{ - FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); - - if (ppobj == NULL) return E_POINTER; - - return E_NOINTERFACE; -} - -static ULONG WINAPI WBCP_AddRef(LPCONNECTIONPOINT iface) -{ - SHDOCVW_LockModule(); - - return 2; /* non-heap based object */ -} - -static ULONG WINAPI WBCP_Release(LPCONNECTIONPOINT iface) -{ - SHDOCVW_UnlockModule(); - - return 1; /* non-heap based object */ -} - -static HRESULT WINAPI WBCP_GetConnectionInterface(LPCONNECTIONPOINT iface, IID* pIId) -{ - FIXME("stub: %s\n", debugstr_guid(pIId)); - return S_OK; -} - -/* Get this connection point's owning container */ -static HRESULT WINAPI -WBCP_GetConnectionPointContainer(LPCONNECTIONPOINT iface, - LPCONNECTIONPOINTCONTAINER *ppCPC) -{ - FIXME("stub: IConnectionPointContainer = %p\n", *ppCPC); - return S_OK; -} - -/* Connect the pUnkSink event-handling implementation (in the control site) - * to this connection point. Return a handle to this connection in - * pdwCookie (for later use in Unadvise()). - */ -static HRESULT WINAPI WBCP_Advise(LPCONNECTIONPOINT iface, - LPUNKNOWN pUnkSink, DWORD *pdwCookie) -{ - static int new_cookie; - - FIXME("stub: IUnknown = %p, connection cookie = %ld\n", pUnkSink, *pdwCookie); - - *pdwCookie = ++new_cookie; - TRACE ("Returning cookie = %ld\n", *pdwCookie); - - return S_OK; -} - -/* Disconnect this implementation from the connection point. */ -static HRESULT WINAPI WBCP_Unadvise(LPCONNECTIONPOINT iface, - DWORD dwCookie) -{ - FIXME("stub: cookie to disconnect = %lx\n", dwCookie); - return S_OK; -} - -/* Get a list of connections in this connection point. */ -static HRESULT WINAPI WBCP_EnumConnections(LPCONNECTIONPOINT iface, - LPENUMCONNECTIONS *ppEnum) -{ - FIXME("stub: IEnumConnections = %p\n", *ppEnum); - return S_OK; -} - -/********************************************************************** - * IConnectionPoint virtual function table for IE Web Browser component - */ - -static IConnectionPointVtbl WBCP_Vtbl = -{ - WBCP_QueryInterface, - WBCP_AddRef, - WBCP_Release, - WBCP_GetConnectionInterface, - WBCP_GetConnectionPointContainer, - WBCP_Advise, - WBCP_Unadvise, - WBCP_EnumConnections -}; - -IConnectionPointImpl SHDOCVW_ConnectionPoint = {&WBCP_Vtbl}; +/* + * Implementation of event-related interfaces for IE Web Browser control: + * + * - IConnectionPointContainer + * - IConnectionPoint + * + * Copyright 2001 John R. Sheets (for CodeWeavers) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <string.h> +#include "wine/debug.h" +#include "shdocvw.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shdocvw); + + +static const GUID IID_INotifyDBEvents = + { 0xdb526cc0, 0xd188, 0x11cd, { 0xad, 0x48, 0x00, 0xaa, 0x00, 0x3c, 0x9c, 0xb6 } }; + +/********************************************************************** + * Implement the IConnectionPointContainer interface + */ + +static HRESULT WINAPI WBCPC_QueryInterface(LPCONNECTIONPOINTCONTAINER iface, + REFIID riid, LPVOID *ppobj) +{ + FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); + + if (ppobj == NULL) return E_POINTER; + + return E_NOINTERFACE; +} + +static ULONG WINAPI WBCPC_AddRef(LPCONNECTIONPOINTCONTAINER iface) +{ + SHDOCVW_LockModule(); + + return 2; /* non-heap based object */ +} + +static ULONG WINAPI WBCPC_Release(LPCONNECTIONPOINTCONTAINER iface) +{ + SHDOCVW_UnlockModule(); + + return 1; /* non-heap based object */ +} + +/* Get a list of connection points inside this container. */ +static HRESULT WINAPI WBCPC_EnumConnectionPoints(LPCONNECTIONPOINTCONTAINER iface, + LPENUMCONNECTIONPOINTS *ppEnum) +{ + FIXME("stub: IEnumConnectionPoints = %p\n", *ppEnum); + return S_OK; +} + +/* Retrieve the connection point in this container associated with the + * riid interface. When events occur in the control, the control can + * call backwards into its embedding site, through these interfaces. + */ +static HRESULT WINAPI WBCPC_FindConnectionPoint(LPCONNECTIONPOINTCONTAINER iface, + REFIID riid, LPCONNECTIONPOINT *ppCP) +{ + TRACE(": IID = %s, IConnectionPoint = %p\n", debugstr_guid(riid), *ppCP); + + /* For now, return the same IConnectionPoint object for both + * event interface requests. + */ + if (IsEqualGUID (&IID_INotifyDBEvents, riid)) + { + TRACE("Returning connection point %p for IID_INotifyDBEvents\n", + &SHDOCVW_ConnectionPoint); + *ppCP = (LPCONNECTIONPOINT)&SHDOCVW_ConnectionPoint; + return S_OK; + } + else if (IsEqualGUID (&IID_IPropertyNotifySink, riid)) + { + TRACE("Returning connection point %p for IID_IPropertyNotifySink\n", + &SHDOCVW_ConnectionPoint); + *ppCP = (LPCONNECTIONPOINT)&SHDOCVW_ConnectionPoint; + return S_OK; + } + + return E_FAIL; +} + +/********************************************************************** + * IConnectionPointContainer virtual function table for IE Web Browser component + */ + +static IConnectionPointContainerVtbl WBCPC_Vtbl = +{ + WBCPC_QueryInterface, + WBCPC_AddRef, + WBCPC_Release, + WBCPC_EnumConnectionPoints, + WBCPC_FindConnectionPoint +}; + +IConnectionPointContainerImpl SHDOCVW_ConnectionPointContainer = {&WBCPC_Vtbl}; + + +/********************************************************************** + * Implement the IConnectionPoint interface + */ + +static HRESULT WINAPI WBCP_QueryInterface(LPCONNECTIONPOINT iface, + REFIID riid, LPVOID *ppobj) +{ + FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); + + if (ppobj == NULL) return E_POINTER; + + return E_NOINTERFACE; +} + +static ULONG WINAPI WBCP_AddRef(LPCONNECTIONPOINT iface) +{ + SHDOCVW_LockModule(); + + return 2; /* non-heap based object */ +} + +static ULONG WINAPI WBCP_Release(LPCONNECTIONPOINT iface) +{ + SHDOCVW_UnlockModule(); + + return 1; /* non-heap based object */ +} + +static HRESULT WINAPI WBCP_GetConnectionInterface(LPCONNECTIONPOINT iface, IID* pIId) +{ + FIXME("stub: %s\n", debugstr_guid(pIId)); + return S_OK; +} + +/* Get this connection point's owning container */ +static HRESULT WINAPI +WBCP_GetConnectionPointContainer(LPCONNECTIONPOINT iface, + LPCONNECTIONPOINTCONTAINER *ppCPC) +{ + FIXME("stub: IConnectionPointContainer = %p\n", *ppCPC); + return S_OK; +} + +/* Connect the pUnkSink event-handling implementation (in the control site) + * to this connection point. Return a handle to this connection in + * pdwCookie (for later use in Unadvise()). + */ +static HRESULT WINAPI WBCP_Advise(LPCONNECTIONPOINT iface, + LPUNKNOWN pUnkSink, DWORD *pdwCookie) +{ + static int new_cookie; + + FIXME("stub: IUnknown = %p, connection cookie = %ld\n", pUnkSink, *pdwCookie); + + *pdwCookie = ++new_cookie; + TRACE ("Returning cookie = %ld\n", *pdwCookie); + + return S_OK; +} + +/* Disconnect this implementation from the connection point. */ +static HRESULT WINAPI WBCP_Unadvise(LPCONNECTIONPOINT iface, + DWORD dwCookie) +{ + FIXME("stub: cookie to disconnect = %lx\n", dwCookie); + return S_OK; +} + +/* Get a list of connections in this connection point. */ +static HRESULT WINAPI WBCP_EnumConnections(LPCONNECTIONPOINT iface, + LPENUMCONNECTIONS *ppEnum) +{ + FIXME("stub: IEnumConnections = %p\n", *ppEnum); + return S_OK; +} + +/********************************************************************** + * IConnectionPoint virtual function table for IE Web Browser component + */ + +static IConnectionPointVtbl WBCP_Vtbl = +{ + WBCP_QueryInterface, + WBCP_AddRef, + WBCP_Release, + WBCP_GetConnectionInterface, + WBCP_GetConnectionPointContainer, + WBCP_Advise, + WBCP_Unadvise, + WBCP_EnumConnections +}; + +IConnectionPointImpl SHDOCVW_ConnectionPoint = {&WBCP_Vtbl}; diff --git a/reactos/lib/shdocvw/factory.c b/reactos/lib/shdocvw/factory.c index df00714d93a..afdf63f665f 100644 --- a/reactos/lib/shdocvw/factory.c +++ b/reactos/lib/shdocvw/factory.c @@ -1,117 +1,117 @@ -/* - * Implementation of class factory for IE Web Browser - * - * Copyright 2001 John R. Sheets (for CodeWeavers) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <string.h> -#include "wine/debug.h" -#include "shdocvw.h" - -WINE_DEFAULT_DEBUG_CHANNEL(shdocvw); - -/********************************************************************** - * Implement the IWebBrowser class factory - * - * (Based on implementation in ddraw/main.c) - */ - -/********************************************************************** - * WBCF_QueryInterface (IUnknown) - */ -static HRESULT WINAPI WBCF_QueryInterface(LPCLASSFACTORY iface, - REFIID riid, LPVOID *ppobj) -{ - FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); - - if (ppobj == NULL) return E_POINTER; - - return E_NOINTERFACE; -} - -/************************************************************************ - * WBCF_AddRef (IUnknown) - */ -static ULONG WINAPI WBCF_AddRef(LPCLASSFACTORY iface) -{ - SHDOCVW_LockModule(); - - return 2; /* non-heap based object */ -} - -/************************************************************************ - * WBCF_Release (IUnknown) - */ -static ULONG WINAPI WBCF_Release(LPCLASSFACTORY iface) -{ - SHDOCVW_UnlockModule(); - - return 1; /* non-heap based object */ -} - -/************************************************************************ - * WBCF_CreateInstance (IClassFactory) - */ -static HRESULT WINAPI WBCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter, - REFIID riid, LPVOID *ppobj) -{ - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - - /* Don't support aggregation (yet?) */ - if (pOuter) - { - TRACE ("Failed attempt to aggregate IWebBrowser\n"); - return CLASS_E_NOAGGREGATION; - } - - TRACE("(%p)->(%p,%s,%p)\n", This, pOuter, debugstr_guid(riid), ppobj); - - if ((IsEqualGUID (&IID_IOleObject, riid))) - { - TRACE ("Instantiating IOleObject component\n"); - *ppobj = (LPVOID)&SHDOCVW_OleObject; - - return S_OK; - } - return CLASS_E_CLASSNOTAVAILABLE; -} - -/************************************************************************ - * WBCF_LockServer (IClassFactory) - */ -static HRESULT WINAPI WBCF_LockServer(LPCLASSFACTORY iface, BOOL dolock) -{ - TRACE("(%d)\n", dolock); - - if (dolock) - SHDOCVW_LockModule(); - else - SHDOCVW_UnlockModule(); - - return S_OK; -} - -static IClassFactoryVtbl WBCF_Vtbl = -{ - WBCF_QueryInterface, - WBCF_AddRef, - WBCF_Release, - WBCF_CreateInstance, - WBCF_LockServer -}; - -IClassFactoryImpl SHDOCVW_ClassFactory = {&WBCF_Vtbl}; +/* + * Implementation of class factory for IE Web Browser + * + * Copyright 2001 John R. Sheets (for CodeWeavers) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <string.h> +#include "wine/debug.h" +#include "shdocvw.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shdocvw); + +/********************************************************************** + * Implement the IWebBrowser class factory + * + * (Based on implementation in ddraw/main.c) + */ + +/********************************************************************** + * WBCF_QueryInterface (IUnknown) + */ +static HRESULT WINAPI WBCF_QueryInterface(LPCLASSFACTORY iface, + REFIID riid, LPVOID *ppobj) +{ + FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); + + if (ppobj == NULL) return E_POINTER; + + return E_NOINTERFACE; +} + +/************************************************************************ + * WBCF_AddRef (IUnknown) + */ +static ULONG WINAPI WBCF_AddRef(LPCLASSFACTORY iface) +{ + SHDOCVW_LockModule(); + + return 2; /* non-heap based object */ +} + +/************************************************************************ + * WBCF_Release (IUnknown) + */ +static ULONG WINAPI WBCF_Release(LPCLASSFACTORY iface) +{ + SHDOCVW_UnlockModule(); + + return 1; /* non-heap based object */ +} + +/************************************************************************ + * WBCF_CreateInstance (IClassFactory) + */ +static HRESULT WINAPI WBCF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter, + REFIID riid, LPVOID *ppobj) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + + /* Don't support aggregation (yet?) */ + if (pOuter) + { + TRACE ("Failed attempt to aggregate IWebBrowser\n"); + return CLASS_E_NOAGGREGATION; + } + + TRACE("(%p)->(%p,%s,%p)\n", This, pOuter, debugstr_guid(riid), ppobj); + + if ((IsEqualGUID (&IID_IOleObject, riid))) + { + TRACE ("Instantiating IOleObject component\n"); + *ppobj = (LPVOID)&SHDOCVW_OleObject; + + return S_OK; + } + return CLASS_E_CLASSNOTAVAILABLE; +} + +/************************************************************************ + * WBCF_LockServer (IClassFactory) + */ +static HRESULT WINAPI WBCF_LockServer(LPCLASSFACTORY iface, BOOL dolock) +{ + TRACE("(%d)\n", dolock); + + if (dolock) + SHDOCVW_LockModule(); + else + SHDOCVW_UnlockModule(); + + return S_OK; +} + +static IClassFactoryVtbl WBCF_Vtbl = +{ + WBCF_QueryInterface, + WBCF_AddRef, + WBCF_Release, + WBCF_CreateInstance, + WBCF_LockServer +}; + +IClassFactoryImpl SHDOCVW_ClassFactory = {&WBCF_Vtbl}; diff --git a/reactos/lib/shdocvw/misc.c b/reactos/lib/shdocvw/misc.c index 928f2a34def..398a466c7de 100644 --- a/reactos/lib/shdocvw/misc.c +++ b/reactos/lib/shdocvw/misc.c @@ -1,99 +1,99 @@ -/* - * Implementation of miscellaneous interfaces for IE Web Browser control: - * - * - IQuickActivate - * - * Copyright 2001 John R. Sheets (for CodeWeavers) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "wine/debug.h" -#include "shdocvw.h" - -WINE_DEFAULT_DEBUG_CHANNEL(shdocvw); - -/********************************************************************** - * Implement the IQuickActivate interface - */ - -static HRESULT WINAPI WBQA_QueryInterface(LPQUICKACTIVATE iface, - REFIID riid, LPVOID *ppobj) -{ - FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); - - if (ppobj == NULL) return E_POINTER; - - return E_NOINTERFACE; -} - -static ULONG WINAPI WBQA_AddRef(LPQUICKACTIVATE iface) -{ - SHDOCVW_LockModule(); - - return 2; /* non-heap based object */ -} - -static ULONG WINAPI WBQA_Release(LPQUICKACTIVATE iface) -{ - SHDOCVW_UnlockModule(); - - return 1; /* non-heap based object */ -} - -/* Alternative interface for quicker, easier activation of a control. */ -static HRESULT WINAPI WBQA_QuickActivate(LPQUICKACTIVATE iface, - QACONTAINER *pQaContainer, - QACONTROL *pQaControl) -{ - FIXME("stub: QACONTAINER = %p, QACONTROL = %p\n", pQaContainer, pQaControl); - return S_OK; -} - -static HRESULT WINAPI WBQA_SetContentExtent(LPQUICKACTIVATE iface, LPSIZEL pSizel) -{ - FIXME("stub: LPSIZEL = %p\n", pSizel); - return E_NOINTERFACE; -} - -static HRESULT WINAPI WBQA_GetContentExtent(LPQUICKACTIVATE iface, LPSIZEL pSizel) -{ - FIXME("stub: LPSIZEL = %p\n", pSizel); - return E_NOINTERFACE; -} - -/********************************************************************** - * IQuickActivate virtual function table for IE Web Browser component - */ - -static IQuickActivateVtbl WBQA_Vtbl = -{ - WBQA_QueryInterface, - WBQA_AddRef, - WBQA_Release, - WBQA_QuickActivate, - WBQA_SetContentExtent, - WBQA_GetContentExtent -}; - -IQuickActivateImpl SHDOCVW_QuickActivate = {&WBQA_Vtbl}; - -/********************************************************************** - * OpenURL (SHDOCVW.@) - */ -void WINAPI OpenURL(HWND hWnd, HINSTANCE hInst, LPCSTR lpcstrUrl, int nShowCmd) -{ - FIXME("%p %p %s %d\n", hWnd, hInst, debugstr_a(lpcstrUrl), nShowCmd); -} +/* + * Implementation of miscellaneous interfaces for IE Web Browser control: + * + * - IQuickActivate + * + * Copyright 2001 John R. Sheets (for CodeWeavers) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "wine/debug.h" +#include "shdocvw.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shdocvw); + +/********************************************************************** + * Implement the IQuickActivate interface + */ + +static HRESULT WINAPI WBQA_QueryInterface(LPQUICKACTIVATE iface, + REFIID riid, LPVOID *ppobj) +{ + FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); + + if (ppobj == NULL) return E_POINTER; + + return E_NOINTERFACE; +} + +static ULONG WINAPI WBQA_AddRef(LPQUICKACTIVATE iface) +{ + SHDOCVW_LockModule(); + + return 2; /* non-heap based object */ +} + +static ULONG WINAPI WBQA_Release(LPQUICKACTIVATE iface) +{ + SHDOCVW_UnlockModule(); + + return 1; /* non-heap based object */ +} + +/* Alternative interface for quicker, easier activation of a control. */ +static HRESULT WINAPI WBQA_QuickActivate(LPQUICKACTIVATE iface, + QACONTAINER *pQaContainer, + QACONTROL *pQaControl) +{ + FIXME("stub: QACONTAINER = %p, QACONTROL = %p\n", pQaContainer, pQaControl); + return S_OK; +} + +static HRESULT WINAPI WBQA_SetContentExtent(LPQUICKACTIVATE iface, LPSIZEL pSizel) +{ + FIXME("stub: LPSIZEL = %p\n", pSizel); + return E_NOINTERFACE; +} + +static HRESULT WINAPI WBQA_GetContentExtent(LPQUICKACTIVATE iface, LPSIZEL pSizel) +{ + FIXME("stub: LPSIZEL = %p\n", pSizel); + return E_NOINTERFACE; +} + +/********************************************************************** + * IQuickActivate virtual function table for IE Web Browser component + */ + +static IQuickActivateVtbl WBQA_Vtbl = +{ + WBQA_QueryInterface, + WBQA_AddRef, + WBQA_Release, + WBQA_QuickActivate, + WBQA_SetContentExtent, + WBQA_GetContentExtent +}; + +IQuickActivateImpl SHDOCVW_QuickActivate = {&WBQA_Vtbl}; + +/********************************************************************** + * OpenURL (SHDOCVW.@) + */ +void WINAPI OpenURL(HWND hWnd, HINSTANCE hInst, LPCSTR lpcstrUrl, int nShowCmd) +{ + FIXME("%p %p %s %d\n", hWnd, hInst, debugstr_a(lpcstrUrl), nShowCmd); +} diff --git a/reactos/lib/shdocvw/oleobject.c b/reactos/lib/shdocvw/oleobject.c index 6652b875da6..8845b5ce277 100644 --- a/reactos/lib/shdocvw/oleobject.c +++ b/reactos/lib/shdocvw/oleobject.c @@ -1,608 +1,608 @@ -/* - * Implementation of IOleObject interfaces for IE Web Browser - * - * - IOleObject - * - IOleInPlaceObject - * - IOleControl - * - * Copyright 2001 John R. Sheets (for CodeWeavers) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <string.h> -#include "wine/debug.h" -#include "shdocvw.h" -#include "ole2.h" - -WINE_DEFAULT_DEBUG_CHANNEL(shdocvw); - -/********************************************************************** - * Implement the IOleObject interface for the web browser component - * - * Based on DefaultHandler code in dlls/ole32/defaulthandler.c. - */ - -static ULONG WINAPI WBOOBJ_AddRef(LPOLEOBJECT iface); -static ULONG WINAPI WBOOBJ_Release(LPOLEOBJECT iface); - -/************************************************************************ - * WBOOBJ_QueryInterface (IUnknown) - * - * Interfaces we need to (at least pretend to) retrieve: - * - * a6bc3ac0-dbaa-11ce-9de3-00aa004bb851 IID_IProvideClassInfo2 - * b196b283-bab4-101a-b69c-00aa00341d07 IID_IProvideClassInfo - * cf51ed10-62fe-11cf-bf86-00a0c9034836 IID_IQuickActivate - * 7fd52380-4e07-101b-ae2d-08002b2ec713 IID_IPersistStreamInit - * 0000010a-0000-0000-c000-000000000046 IID_IPersistStorage - * b196b284-bab4-101a-b69c-00aa00341d07 IID_IConnectionPointContainer - */ -static HRESULT WINAPI WBOOBJ_QueryInterface(LPOLEOBJECT iface, - REFIID riid, void** ppobj) -{ - IOleObjectImpl *This = (IOleObjectImpl *)iface; - - /* - * Perform a sanity check on the parameters. - */ - if ((This == NULL) || (ppobj == NULL) ) - return E_INVALIDARG; - - if (IsEqualGUID (&IID_IPersistStorage, riid)) - { - TRACE("Returning IID_IPersistStorage interface\n"); - *ppobj = (LPVOID)&SHDOCVW_PersistStorage; - WBOOBJ_AddRef (iface); - return S_OK; - } - else if (IsEqualGUID (&IID_IPersistStreamInit, riid)) - { - TRACE("Returning IID_IPersistStreamInit interface\n"); - *ppobj = (LPVOID)&SHDOCVW_PersistStreamInit; - WBOOBJ_AddRef (iface); - return S_OK; - } - else if (IsEqualGUID (&IID_IProvideClassInfo, riid)) - { - TRACE("Returning IID_IProvideClassInfo interface\n"); - *ppobj = (LPVOID)&SHDOCVW_ProvideClassInfo; - WBOOBJ_AddRef (iface); - return S_OK; - } - else if (IsEqualGUID (&IID_IProvideClassInfo2, riid)) - { - TRACE("Returning IID_IProvideClassInfo2 interface %p\n", - &SHDOCVW_ProvideClassInfo2); - *ppobj = (LPVOID)&SHDOCVW_ProvideClassInfo2; - WBOOBJ_AddRef (iface); - return S_OK; - } - else if (IsEqualGUID (&IID_IQuickActivate, riid)) - { - TRACE("Returning IID_IQuickActivate interface\n"); - *ppobj = (LPVOID)&SHDOCVW_QuickActivate; - WBOOBJ_AddRef (iface); - return S_OK; - } - else if (IsEqualGUID (&IID_IConnectionPointContainer, riid)) - { - TRACE("Returning IID_IConnectionPointContainer interface\n"); - *ppobj = (LPVOID)&SHDOCVW_ConnectionPointContainer; - WBOOBJ_AddRef (iface); - return S_OK; - } - else if (IsEqualGUID (&IID_IOleInPlaceObject, riid)) - { - TRACE("Returning IID_IOleInPlaceObject interface\n"); - *ppobj = (LPVOID)&SHDOCVW_OleInPlaceObject; - WBOOBJ_AddRef (iface); - return S_OK; - } - else if (IsEqualGUID (&IID_IOleControl, riid)) - { - TRACE("Returning IID_IOleControl interface\n"); - *ppobj = (LPVOID)&SHDOCVW_OleControl; - WBOOBJ_AddRef (iface); - return S_OK; - } - else if (IsEqualGUID (&IID_IWebBrowser, riid)) - { - TRACE("Returning IID_IWebBrowser interface\n"); - *ppobj = (LPVOID)&SHDOCVW_WebBrowser; - WBOOBJ_AddRef (iface); - return S_OK; - } - else if (IsEqualGUID (&IID_IDispatch, riid)) - { - TRACE("Returning IID_IDispatch interface\n"); - *ppobj = (LPVOID)&SHDOCVW_WebBrowser; - WBOOBJ_AddRef (iface); - return S_OK; - } - - TRACE ("Failed to find iid = %s\n", debugstr_guid(riid)); - - return E_NOINTERFACE; -} - -/************************************************************************ - * WBOOBJ_AddRef (IUnknown) - */ -static ULONG WINAPI WBOOBJ_AddRef(LPOLEOBJECT iface) -{ - SHDOCVW_LockModule(); - - return 2; /* non-heap based object */ -} - -/************************************************************************ - * WBOOBJ_Release (IUnknown) - */ -static ULONG WINAPI WBOOBJ_Release(LPOLEOBJECT iface) -{ - SHDOCVW_UnlockModule(); - - return 1; /* non-heap based object */ -} - -/************************************************************************ - * WBOOBJ_SetClientSite (IOleObject) - */ -static HRESULT WINAPI WBOOBJ_SetClientSite(LPOLEOBJECT iface, - LPOLECLIENTSITE pClientSite) -{ - FIXME("stub: (%p, %p)\n", iface, pClientSite); - return S_OK; -} - -/************************************************************************ - * WBOOBJ_GetClientSite (IOleObject) - */ -static HRESULT WINAPI WBOOBJ_GetClientSite(LPOLEOBJECT iface, - LPOLECLIENTSITE* ppClientSite) -{ - FIXME("stub: (%p)\n", *ppClientSite); - return S_OK; -} - -/************************************************************************ - * WBOOBJ_SetHostNames (IOleObject) - */ -static HRESULT WINAPI WBOOBJ_SetHostNames(LPOLEOBJECT iface, LPCOLESTR szContainerApp, - LPCOLESTR szContainerObj) -{ - FIXME("stub: (%p, %s, %s)\n", iface, debugstr_w(szContainerApp), - debugstr_w(szContainerObj)); - return S_OK; -} - -/************************************************************************ - * WBOOBJ_Close (IOleObject) - */ -static HRESULT WINAPI WBOOBJ_Close(LPOLEOBJECT iface, DWORD dwSaveOption) -{ - FIXME("stub: ()\n"); - return S_OK; -} - -/************************************************************************ - * WBOOBJ_SetMoniker (IOleObject) - */ -static HRESULT WINAPI WBOOBJ_SetMoniker(LPOLEOBJECT iface, - DWORD dwWhichMoniker, IMoniker* pmk) -{ - FIXME("stub: (%p, %ld, %p)\n", iface, dwWhichMoniker, pmk); - return S_OK; -} - -/************************************************************************ - * WBOOBJ_GetMoniker (IOleObject) - * - * Delegate this request to the client site if we have one. - */ -static HRESULT WINAPI WBOOBJ_GetMoniker(LPOLEOBJECT iface, DWORD dwAssign, - DWORD dwWhichMoniker, LPMONIKER *ppmk) -{ - FIXME("stub (%p, %ld, %ld, %p)\n", iface, dwAssign, dwWhichMoniker, ppmk); - return E_FAIL; -} - -/************************************************************************ - * WBOOBJ_InitFromData (IOleObject) - * - * This method is meaningless if the server is not running - */ -static HRESULT WINAPI WBOOBJ_InitFromData(LPOLEOBJECT iface, LPDATAOBJECT pDataObject, - BOOL fCreation, DWORD dwReserved) -{ - FIXME("stub: (%p, %p, %d, %ld)\n", iface, pDataObject, fCreation, dwReserved); - return OLE_E_NOTRUNNING; -} - -/************************************************************************ - * WBOOBJ_GetClipboardData (IOleObject) - * - * This method is meaningless if the server is not running - */ -static HRESULT WINAPI WBOOBJ_GetClipboardData(LPOLEOBJECT iface, DWORD dwReserved, - LPDATAOBJECT *ppDataObject) -{ - FIXME("stub: (%p, %ld, %p)\n", iface, dwReserved, ppDataObject); - return OLE_E_NOTRUNNING; -} - -/************************************************************************ - * WBOOBJ_DoVerb (IOleObject) - */ -static HRESULT WINAPI WBOOBJ_DoVerb(LPOLEOBJECT iface, LONG iVerb, struct tagMSG* lpmsg, - LPOLECLIENTSITE pActiveSite, LONG lindex, - HWND hwndParent, LPCRECT lprcPosRect) -{ - FIXME(": stub iVerb = %ld\n", iVerb); - switch (iVerb) - { - case OLEIVERB_INPLACEACTIVATE: - FIXME ("stub for OLEIVERB_INPLACEACTIVATE\n"); - break; - case OLEIVERB_HIDE: - FIXME ("stub for OLEIVERB_HIDE\n"); - break; - } - - return S_OK; -} - -/************************************************************************ - * WBOOBJ_EnumVerbs (IOleObject) - * - * Delegate to OleRegEnumVerbs. - */ -static HRESULT WINAPI WBOOBJ_EnumVerbs(LPOLEOBJECT iface, - IEnumOLEVERB** ppEnumOleVerb) -{ - TRACE("(%p, %p)\n", iface, ppEnumOleVerb); - - return OleRegEnumVerbs(&CLSID_WebBrowser, ppEnumOleVerb); -} - -/************************************************************************ - * WBOOBJ_EnumVerbs (IOleObject) - */ -static HRESULT WINAPI WBOOBJ_Update(LPOLEOBJECT iface) -{ - FIXME(": Stub\n"); - return E_NOTIMPL; -} - -/************************************************************************ - * WBOOBJ_IsUpToDate (IOleObject) - * - * This method is meaningless if the server is not running - */ -static HRESULT WINAPI WBOOBJ_IsUpToDate(LPOLEOBJECT iface) -{ - FIXME("(%p)\n", iface); - return OLE_E_NOTRUNNING; -} - -/************************************************************************ - * WBOOBJ_GetUserClassID (IOleObject) - */ -static HRESULT WINAPI WBOOBJ_GetUserClassID(LPOLEOBJECT iface, CLSID* pClsid) -{ - FIXME("stub: (%p, %p)\n", iface, pClsid); - return S_OK; -} - -/************************************************************************ - * WBOOBJ_GetUserType (IOleObject) - * - * Delegate to OleRegGetUserType. - */ -static HRESULT WINAPI WBOOBJ_GetUserType(LPOLEOBJECT iface, DWORD dwFormOfType, - LPOLESTR* pszUserType) -{ - TRACE("(%p, %ld, %p)\n", iface, dwFormOfType, pszUserType); - - return OleRegGetUserType(&CLSID_WebBrowser, dwFormOfType, pszUserType); -} - -/************************************************************************ - * WBOOBJ_SetExtent (IOleObject) - * - * This method is meaningless if the server is not running - */ -static HRESULT WINAPI WBOOBJ_SetExtent(LPOLEOBJECT iface, DWORD dwDrawAspect, - SIZEL* psizel) -{ - FIXME("stub: (%p, %lx, (%ld x %ld))\n", iface, dwDrawAspect, - psizel->cx, psizel->cy); - return OLE_E_NOTRUNNING; -} - -/************************************************************************ - * WBOOBJ_GetExtent (IOleObject) - */ -static HRESULT WINAPI WBOOBJ_GetExtent(LPOLEOBJECT iface, DWORD dwDrawAspect, - SIZEL* psizel) -{ - FIXME("stub: (%p, %lx, %p)\n", iface, dwDrawAspect, psizel); - return S_OK; -} - -/************************************************************************ - * WBOOBJ_Advise (IOleObject) - */ -static HRESULT WINAPI WBOOBJ_Advise(LPOLEOBJECT iface, IAdviseSink* pAdvSink, - DWORD* pdwConnection) -{ - FIXME("stub: (%p, %p, %p)\n", iface, pAdvSink, pdwConnection); - return S_OK; -} - -/************************************************************************ - * WBOOBJ_Unadvise (IOleObject) - */ -static HRESULT WINAPI WBOOBJ_Unadvise(LPOLEOBJECT iface, DWORD dwConnection) -{ - FIXME("stub: (%p, %ld)\n", iface, dwConnection); - return S_OK; -} - -/************************************************************************ - * WBOOBJ_EnumAdvise (IOleObject) - */ -static HRESULT WINAPI WBOOBJ_EnumAdvise(LPOLEOBJECT iface, IEnumSTATDATA** ppenumAdvise) -{ - FIXME("stub: (%p, %p)\n", iface, ppenumAdvise); - return S_OK; -} - -/************************************************************************ - * WBOOBJ_GetMiscStatus (IOleObject) - * - * Delegate to OleRegGetMiscStatus. - */ -static HRESULT WINAPI WBOOBJ_GetMiscStatus(LPOLEOBJECT iface, DWORD dwAspect, - DWORD* pdwStatus) -{ - HRESULT hres; - - TRACE("(%p, %lx, %p)\n", iface, dwAspect, pdwStatus); - - hres = OleRegGetMiscStatus(&CLSID_WebBrowser, dwAspect, pdwStatus); - - if (FAILED(hres)) - *pdwStatus = 0; - - return S_OK; -} - -/************************************************************************ - * WBOOBJ_SetColorScheme (IOleObject) - * - * This method is meaningless if the server is not running - */ -static HRESULT WINAPI WBOOBJ_SetColorScheme(LPOLEOBJECT iface, - struct tagLOGPALETTE* pLogpal) -{ - FIXME("stub: (%p, %p))\n", iface, pLogpal); - return OLE_E_NOTRUNNING; -} - -/********************************************************************** - * IOleObject virtual function table for IE Web Browser component - */ - -static IOleObjectVtbl WBOOBJ_Vtbl = -{ - WBOOBJ_QueryInterface, - WBOOBJ_AddRef, - WBOOBJ_Release, - WBOOBJ_SetClientSite, - WBOOBJ_GetClientSite, - WBOOBJ_SetHostNames, - WBOOBJ_Close, - WBOOBJ_SetMoniker, - WBOOBJ_GetMoniker, - WBOOBJ_InitFromData, - WBOOBJ_GetClipboardData, - WBOOBJ_DoVerb, - WBOOBJ_EnumVerbs, - WBOOBJ_Update, - WBOOBJ_IsUpToDate, - WBOOBJ_GetUserClassID, - WBOOBJ_GetUserType, - WBOOBJ_SetExtent, - WBOOBJ_GetExtent, - WBOOBJ_Advise, - WBOOBJ_Unadvise, - WBOOBJ_EnumAdvise, - WBOOBJ_GetMiscStatus, - WBOOBJ_SetColorScheme -}; - -IOleObjectImpl SHDOCVW_OleObject = {&WBOOBJ_Vtbl}; - - -/********************************************************************** - * Implement the IOleInPlaceObject interface - */ - -static HRESULT WINAPI WBOIPO_QueryInterface(LPOLEINPLACEOBJECT iface, - REFIID riid, LPVOID *ppobj) -{ - FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); - - if (ppobj == NULL) return E_POINTER; - - return E_NOINTERFACE; -} - -static ULONG WINAPI WBOIPO_AddRef(LPOLEINPLACEOBJECT iface) -{ - SHDOCVW_LockModule(); - - return 2; /* non-heap based object */ -} - -static ULONG WINAPI WBOIPO_Release(LPOLEINPLACEOBJECT iface) -{ - SHDOCVW_UnlockModule(); - - return 1; /* non-heap based object */ -} - -static HRESULT WINAPI WBOIPO_GetWindow(LPOLEINPLACEOBJECT iface, HWND* phwnd) -{ -#if 0 - /* Create a fake window to fool MFC into believing that we actually - * have an implemented browser control. Avoids the assertion. - */ - HWND hwnd; - hwnd = CreateWindowA("BUTTON", "Web Control", - WS_HSCROLL | WS_VSCROLL | WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, 600, - 400, NULL, NULL, NULL, NULL); - - *phwnd = hwnd; - TRACE ("Returning hwnd = %d\n", hwnd); -#endif - - FIXME("stub HWND* = %p\n", phwnd); - return S_OK; -} - -static HRESULT WINAPI WBOIPO_ContextSensitiveHelp(LPOLEINPLACEOBJECT iface, - BOOL fEnterMode) -{ - FIXME("stub fEnterMode = %d\n", fEnterMode); - return S_OK; -} - -static HRESULT WINAPI WBOIPO_InPlaceDeactivate(LPOLEINPLACEOBJECT iface) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WBOIPO_UIDeactivate(LPOLEINPLACEOBJECT iface) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WBOIPO_SetObjectRects(LPOLEINPLACEOBJECT iface, - LPCRECT lprcPosRect, LPCRECT lprcClipRect) -{ - FIXME("stub PosRect = %p, ClipRect = %p\n", lprcPosRect, lprcClipRect); - return S_OK; -} - -static HRESULT WINAPI WBOIPO_ReactivateAndUndo(LPOLEINPLACEOBJECT iface) -{ - FIXME("stub \n"); - return S_OK; -} - -/********************************************************************** - * IOleInPlaceObject virtual function table for IE Web Browser component - */ - -static IOleInPlaceObjectVtbl WBOIPO_Vtbl = -{ - WBOIPO_QueryInterface, - WBOIPO_AddRef, - WBOIPO_Release, - WBOIPO_GetWindow, - WBOIPO_ContextSensitiveHelp, - WBOIPO_InPlaceDeactivate, - WBOIPO_UIDeactivate, - WBOIPO_SetObjectRects, - WBOIPO_ReactivateAndUndo -}; - -IOleInPlaceObjectImpl SHDOCVW_OleInPlaceObject = {&WBOIPO_Vtbl}; - - -/********************************************************************** - * Implement the IOleControl interface - */ - -static HRESULT WINAPI WBOC_QueryInterface(LPOLECONTROL iface, - REFIID riid, LPVOID *ppobj) -{ - FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); - - if (ppobj == NULL) return E_POINTER; - - return E_NOINTERFACE; -} - -static ULONG WINAPI WBOC_AddRef(LPOLECONTROL iface) -{ - SHDOCVW_LockModule(); - - return 2; /* non-heap based object */ -} - -static ULONG WINAPI WBOC_Release(LPOLECONTROL iface) -{ - SHDOCVW_UnlockModule(); - - return 1; /* non-heap based object */ -} - -static HRESULT WINAPI WBOC_GetControlInfo(LPOLECONTROL iface, LPCONTROLINFO pCI) -{ - FIXME("stub: LPCONTROLINFO = %p\n", pCI); - return S_OK; -} - -static HRESULT WINAPI WBOC_OnMnemonic(LPOLECONTROL iface, struct tagMSG *pMsg) -{ - FIXME("stub: MSG* = %p\n", pMsg); - return S_OK; -} - -static HRESULT WINAPI WBOC_OnAmbientPropertyChange(LPOLECONTROL iface, DISPID dispID) -{ - FIXME("stub: DISPID = %ld\n", dispID); - return S_OK; -} - -static HRESULT WINAPI WBOC_FreezeEvents(LPOLECONTROL iface, BOOL bFreeze) -{ - FIXME("stub: bFreeze = %d\n", bFreeze); - return S_OK; -} - -/********************************************************************** - * IOleControl virtual function table for IE Web Browser component - */ - -static IOleControlVtbl WBOC_Vtbl = -{ - WBOC_QueryInterface, - WBOC_AddRef, - WBOC_Release, - WBOC_GetControlInfo, - WBOC_OnMnemonic, - WBOC_OnAmbientPropertyChange, - WBOC_FreezeEvents -}; - -IOleControlImpl SHDOCVW_OleControl = {&WBOC_Vtbl}; +/* + * Implementation of IOleObject interfaces for IE Web Browser + * + * - IOleObject + * - IOleInPlaceObject + * - IOleControl + * + * Copyright 2001 John R. Sheets (for CodeWeavers) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <string.h> +#include "wine/debug.h" +#include "shdocvw.h" +#include "ole2.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shdocvw); + +/********************************************************************** + * Implement the IOleObject interface for the web browser component + * + * Based on DefaultHandler code in dlls/ole32/defaulthandler.c. + */ + +static ULONG WINAPI WBOOBJ_AddRef(LPOLEOBJECT iface); +static ULONG WINAPI WBOOBJ_Release(LPOLEOBJECT iface); + +/************************************************************************ + * WBOOBJ_QueryInterface (IUnknown) + * + * Interfaces we need to (at least pretend to) retrieve: + * + * a6bc3ac0-dbaa-11ce-9de3-00aa004bb851 IID_IProvideClassInfo2 + * b196b283-bab4-101a-b69c-00aa00341d07 IID_IProvideClassInfo + * cf51ed10-62fe-11cf-bf86-00a0c9034836 IID_IQuickActivate + * 7fd52380-4e07-101b-ae2d-08002b2ec713 IID_IPersistStreamInit + * 0000010a-0000-0000-c000-000000000046 IID_IPersistStorage + * b196b284-bab4-101a-b69c-00aa00341d07 IID_IConnectionPointContainer + */ +static HRESULT WINAPI WBOOBJ_QueryInterface(LPOLEOBJECT iface, + REFIID riid, void** ppobj) +{ + IOleObjectImpl *This = (IOleObjectImpl *)iface; + + /* + * Perform a sanity check on the parameters. + */ + if ((This == NULL) || (ppobj == NULL) ) + return E_INVALIDARG; + + if (IsEqualGUID (&IID_IPersistStorage, riid)) + { + TRACE("Returning IID_IPersistStorage interface\n"); + *ppobj = (LPVOID)&SHDOCVW_PersistStorage; + WBOOBJ_AddRef (iface); + return S_OK; + } + else if (IsEqualGUID (&IID_IPersistStreamInit, riid)) + { + TRACE("Returning IID_IPersistStreamInit interface\n"); + *ppobj = (LPVOID)&SHDOCVW_PersistStreamInit; + WBOOBJ_AddRef (iface); + return S_OK; + } + else if (IsEqualGUID (&IID_IProvideClassInfo, riid)) + { + TRACE("Returning IID_IProvideClassInfo interface\n"); + *ppobj = (LPVOID)&SHDOCVW_ProvideClassInfo; + WBOOBJ_AddRef (iface); + return S_OK; + } + else if (IsEqualGUID (&IID_IProvideClassInfo2, riid)) + { + TRACE("Returning IID_IProvideClassInfo2 interface %p\n", + &SHDOCVW_ProvideClassInfo2); + *ppobj = (LPVOID)&SHDOCVW_ProvideClassInfo2; + WBOOBJ_AddRef (iface); + return S_OK; + } + else if (IsEqualGUID (&IID_IQuickActivate, riid)) + { + TRACE("Returning IID_IQuickActivate interface\n"); + *ppobj = (LPVOID)&SHDOCVW_QuickActivate; + WBOOBJ_AddRef (iface); + return S_OK; + } + else if (IsEqualGUID (&IID_IConnectionPointContainer, riid)) + { + TRACE("Returning IID_IConnectionPointContainer interface\n"); + *ppobj = (LPVOID)&SHDOCVW_ConnectionPointContainer; + WBOOBJ_AddRef (iface); + return S_OK; + } + else if (IsEqualGUID (&IID_IOleInPlaceObject, riid)) + { + TRACE("Returning IID_IOleInPlaceObject interface\n"); + *ppobj = (LPVOID)&SHDOCVW_OleInPlaceObject; + WBOOBJ_AddRef (iface); + return S_OK; + } + else if (IsEqualGUID (&IID_IOleControl, riid)) + { + TRACE("Returning IID_IOleControl interface\n"); + *ppobj = (LPVOID)&SHDOCVW_OleControl; + WBOOBJ_AddRef (iface); + return S_OK; + } + else if (IsEqualGUID (&IID_IWebBrowser, riid)) + { + TRACE("Returning IID_IWebBrowser interface\n"); + *ppobj = (LPVOID)&SHDOCVW_WebBrowser; + WBOOBJ_AddRef (iface); + return S_OK; + } + else if (IsEqualGUID (&IID_IDispatch, riid)) + { + TRACE("Returning IID_IDispatch interface\n"); + *ppobj = (LPVOID)&SHDOCVW_WebBrowser; + WBOOBJ_AddRef (iface); + return S_OK; + } + + TRACE ("Failed to find iid = %s\n", debugstr_guid(riid)); + + return E_NOINTERFACE; +} + +/************************************************************************ + * WBOOBJ_AddRef (IUnknown) + */ +static ULONG WINAPI WBOOBJ_AddRef(LPOLEOBJECT iface) +{ + SHDOCVW_LockModule(); + + return 2; /* non-heap based object */ +} + +/************************************************************************ + * WBOOBJ_Release (IUnknown) + */ +static ULONG WINAPI WBOOBJ_Release(LPOLEOBJECT iface) +{ + SHDOCVW_UnlockModule(); + + return 1; /* non-heap based object */ +} + +/************************************************************************ + * WBOOBJ_SetClientSite (IOleObject) + */ +static HRESULT WINAPI WBOOBJ_SetClientSite(LPOLEOBJECT iface, + LPOLECLIENTSITE pClientSite) +{ + FIXME("stub: (%p, %p)\n", iface, pClientSite); + return S_OK; +} + +/************************************************************************ + * WBOOBJ_GetClientSite (IOleObject) + */ +static HRESULT WINAPI WBOOBJ_GetClientSite(LPOLEOBJECT iface, + LPOLECLIENTSITE* ppClientSite) +{ + FIXME("stub: (%p)\n", *ppClientSite); + return S_OK; +} + +/************************************************************************ + * WBOOBJ_SetHostNames (IOleObject) + */ +static HRESULT WINAPI WBOOBJ_SetHostNames(LPOLEOBJECT iface, LPCOLESTR szContainerApp, + LPCOLESTR szContainerObj) +{ + FIXME("stub: (%p, %s, %s)\n", iface, debugstr_w(szContainerApp), + debugstr_w(szContainerObj)); + return S_OK; +} + +/************************************************************************ + * WBOOBJ_Close (IOleObject) + */ +static HRESULT WINAPI WBOOBJ_Close(LPOLEOBJECT iface, DWORD dwSaveOption) +{ + FIXME("stub: ()\n"); + return S_OK; +} + +/************************************************************************ + * WBOOBJ_SetMoniker (IOleObject) + */ +static HRESULT WINAPI WBOOBJ_SetMoniker(LPOLEOBJECT iface, + DWORD dwWhichMoniker, IMoniker* pmk) +{ + FIXME("stub: (%p, %ld, %p)\n", iface, dwWhichMoniker, pmk); + return S_OK; +} + +/************************************************************************ + * WBOOBJ_GetMoniker (IOleObject) + * + * Delegate this request to the client site if we have one. + */ +static HRESULT WINAPI WBOOBJ_GetMoniker(LPOLEOBJECT iface, DWORD dwAssign, + DWORD dwWhichMoniker, LPMONIKER *ppmk) +{ + FIXME("stub (%p, %ld, %ld, %p)\n", iface, dwAssign, dwWhichMoniker, ppmk); + return E_FAIL; +} + +/************************************************************************ + * WBOOBJ_InitFromData (IOleObject) + * + * This method is meaningless if the server is not running + */ +static HRESULT WINAPI WBOOBJ_InitFromData(LPOLEOBJECT iface, LPDATAOBJECT pDataObject, + BOOL fCreation, DWORD dwReserved) +{ + FIXME("stub: (%p, %p, %d, %ld)\n", iface, pDataObject, fCreation, dwReserved); + return OLE_E_NOTRUNNING; +} + +/************************************************************************ + * WBOOBJ_GetClipboardData (IOleObject) + * + * This method is meaningless if the server is not running + */ +static HRESULT WINAPI WBOOBJ_GetClipboardData(LPOLEOBJECT iface, DWORD dwReserved, + LPDATAOBJECT *ppDataObject) +{ + FIXME("stub: (%p, %ld, %p)\n", iface, dwReserved, ppDataObject); + return OLE_E_NOTRUNNING; +} + +/************************************************************************ + * WBOOBJ_DoVerb (IOleObject) + */ +static HRESULT WINAPI WBOOBJ_DoVerb(LPOLEOBJECT iface, LONG iVerb, struct tagMSG* lpmsg, + LPOLECLIENTSITE pActiveSite, LONG lindex, + HWND hwndParent, LPCRECT lprcPosRect) +{ + FIXME(": stub iVerb = %ld\n", iVerb); + switch (iVerb) + { + case OLEIVERB_INPLACEACTIVATE: + FIXME ("stub for OLEIVERB_INPLACEACTIVATE\n"); + break; + case OLEIVERB_HIDE: + FIXME ("stub for OLEIVERB_HIDE\n"); + break; + } + + return S_OK; +} + +/************************************************************************ + * WBOOBJ_EnumVerbs (IOleObject) + * + * Delegate to OleRegEnumVerbs. + */ +static HRESULT WINAPI WBOOBJ_EnumVerbs(LPOLEOBJECT iface, + IEnumOLEVERB** ppEnumOleVerb) +{ + TRACE("(%p, %p)\n", iface, ppEnumOleVerb); + + return OleRegEnumVerbs(&CLSID_WebBrowser, ppEnumOleVerb); +} + +/************************************************************************ + * WBOOBJ_EnumVerbs (IOleObject) + */ +static HRESULT WINAPI WBOOBJ_Update(LPOLEOBJECT iface) +{ + FIXME(": Stub\n"); + return E_NOTIMPL; +} + +/************************************************************************ + * WBOOBJ_IsUpToDate (IOleObject) + * + * This method is meaningless if the server is not running + */ +static HRESULT WINAPI WBOOBJ_IsUpToDate(LPOLEOBJECT iface) +{ + FIXME("(%p)\n", iface); + return OLE_E_NOTRUNNING; +} + +/************************************************************************ + * WBOOBJ_GetUserClassID (IOleObject) + */ +static HRESULT WINAPI WBOOBJ_GetUserClassID(LPOLEOBJECT iface, CLSID* pClsid) +{ + FIXME("stub: (%p, %p)\n", iface, pClsid); + return S_OK; +} + +/************************************************************************ + * WBOOBJ_GetUserType (IOleObject) + * + * Delegate to OleRegGetUserType. + */ +static HRESULT WINAPI WBOOBJ_GetUserType(LPOLEOBJECT iface, DWORD dwFormOfType, + LPOLESTR* pszUserType) +{ + TRACE("(%p, %ld, %p)\n", iface, dwFormOfType, pszUserType); + + return OleRegGetUserType(&CLSID_WebBrowser, dwFormOfType, pszUserType); +} + +/************************************************************************ + * WBOOBJ_SetExtent (IOleObject) + * + * This method is meaningless if the server is not running + */ +static HRESULT WINAPI WBOOBJ_SetExtent(LPOLEOBJECT iface, DWORD dwDrawAspect, + SIZEL* psizel) +{ + FIXME("stub: (%p, %lx, (%ld x %ld))\n", iface, dwDrawAspect, + psizel->cx, psizel->cy); + return OLE_E_NOTRUNNING; +} + +/************************************************************************ + * WBOOBJ_GetExtent (IOleObject) + */ +static HRESULT WINAPI WBOOBJ_GetExtent(LPOLEOBJECT iface, DWORD dwDrawAspect, + SIZEL* psizel) +{ + FIXME("stub: (%p, %lx, %p)\n", iface, dwDrawAspect, psizel); + return S_OK; +} + +/************************************************************************ + * WBOOBJ_Advise (IOleObject) + */ +static HRESULT WINAPI WBOOBJ_Advise(LPOLEOBJECT iface, IAdviseSink* pAdvSink, + DWORD* pdwConnection) +{ + FIXME("stub: (%p, %p, %p)\n", iface, pAdvSink, pdwConnection); + return S_OK; +} + +/************************************************************************ + * WBOOBJ_Unadvise (IOleObject) + */ +static HRESULT WINAPI WBOOBJ_Unadvise(LPOLEOBJECT iface, DWORD dwConnection) +{ + FIXME("stub: (%p, %ld)\n", iface, dwConnection); + return S_OK; +} + +/************************************************************************ + * WBOOBJ_EnumAdvise (IOleObject) + */ +static HRESULT WINAPI WBOOBJ_EnumAdvise(LPOLEOBJECT iface, IEnumSTATDATA** ppenumAdvise) +{ + FIXME("stub: (%p, %p)\n", iface, ppenumAdvise); + return S_OK; +} + +/************************************************************************ + * WBOOBJ_GetMiscStatus (IOleObject) + * + * Delegate to OleRegGetMiscStatus. + */ +static HRESULT WINAPI WBOOBJ_GetMiscStatus(LPOLEOBJECT iface, DWORD dwAspect, + DWORD* pdwStatus) +{ + HRESULT hres; + + TRACE("(%p, %lx, %p)\n", iface, dwAspect, pdwStatus); + + hres = OleRegGetMiscStatus(&CLSID_WebBrowser, dwAspect, pdwStatus); + + if (FAILED(hres)) + *pdwStatus = 0; + + return S_OK; +} + +/************************************************************************ + * WBOOBJ_SetColorScheme (IOleObject) + * + * This method is meaningless if the server is not running + */ +static HRESULT WINAPI WBOOBJ_SetColorScheme(LPOLEOBJECT iface, + struct tagLOGPALETTE* pLogpal) +{ + FIXME("stub: (%p, %p))\n", iface, pLogpal); + return OLE_E_NOTRUNNING; +} + +/********************************************************************** + * IOleObject virtual function table for IE Web Browser component + */ + +static IOleObjectVtbl WBOOBJ_Vtbl = +{ + WBOOBJ_QueryInterface, + WBOOBJ_AddRef, + WBOOBJ_Release, + WBOOBJ_SetClientSite, + WBOOBJ_GetClientSite, + WBOOBJ_SetHostNames, + WBOOBJ_Close, + WBOOBJ_SetMoniker, + WBOOBJ_GetMoniker, + WBOOBJ_InitFromData, + WBOOBJ_GetClipboardData, + WBOOBJ_DoVerb, + WBOOBJ_EnumVerbs, + WBOOBJ_Update, + WBOOBJ_IsUpToDate, + WBOOBJ_GetUserClassID, + WBOOBJ_GetUserType, + WBOOBJ_SetExtent, + WBOOBJ_GetExtent, + WBOOBJ_Advise, + WBOOBJ_Unadvise, + WBOOBJ_EnumAdvise, + WBOOBJ_GetMiscStatus, + WBOOBJ_SetColorScheme +}; + +IOleObjectImpl SHDOCVW_OleObject = {&WBOOBJ_Vtbl}; + + +/********************************************************************** + * Implement the IOleInPlaceObject interface + */ + +static HRESULT WINAPI WBOIPO_QueryInterface(LPOLEINPLACEOBJECT iface, + REFIID riid, LPVOID *ppobj) +{ + FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); + + if (ppobj == NULL) return E_POINTER; + + return E_NOINTERFACE; +} + +static ULONG WINAPI WBOIPO_AddRef(LPOLEINPLACEOBJECT iface) +{ + SHDOCVW_LockModule(); + + return 2; /* non-heap based object */ +} + +static ULONG WINAPI WBOIPO_Release(LPOLEINPLACEOBJECT iface) +{ + SHDOCVW_UnlockModule(); + + return 1; /* non-heap based object */ +} + +static HRESULT WINAPI WBOIPO_GetWindow(LPOLEINPLACEOBJECT iface, HWND* phwnd) +{ +#if 0 + /* Create a fake window to fool MFC into believing that we actually + * have an implemented browser control. Avoids the assertion. + */ + HWND hwnd; + hwnd = CreateWindowA("BUTTON", "Web Control", + WS_HSCROLL | WS_VSCROLL | WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, 600, + 400, NULL, NULL, NULL, NULL); + + *phwnd = hwnd; + TRACE ("Returning hwnd = %d\n", hwnd); +#endif + + FIXME("stub HWND* = %p\n", phwnd); + return S_OK; +} + +static HRESULT WINAPI WBOIPO_ContextSensitiveHelp(LPOLEINPLACEOBJECT iface, + BOOL fEnterMode) +{ + FIXME("stub fEnterMode = %d\n", fEnterMode); + return S_OK; +} + +static HRESULT WINAPI WBOIPO_InPlaceDeactivate(LPOLEINPLACEOBJECT iface) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WBOIPO_UIDeactivate(LPOLEINPLACEOBJECT iface) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WBOIPO_SetObjectRects(LPOLEINPLACEOBJECT iface, + LPCRECT lprcPosRect, LPCRECT lprcClipRect) +{ + FIXME("stub PosRect = %p, ClipRect = %p\n", lprcPosRect, lprcClipRect); + return S_OK; +} + +static HRESULT WINAPI WBOIPO_ReactivateAndUndo(LPOLEINPLACEOBJECT iface) +{ + FIXME("stub \n"); + return S_OK; +} + +/********************************************************************** + * IOleInPlaceObject virtual function table for IE Web Browser component + */ + +static IOleInPlaceObjectVtbl WBOIPO_Vtbl = +{ + WBOIPO_QueryInterface, + WBOIPO_AddRef, + WBOIPO_Release, + WBOIPO_GetWindow, + WBOIPO_ContextSensitiveHelp, + WBOIPO_InPlaceDeactivate, + WBOIPO_UIDeactivate, + WBOIPO_SetObjectRects, + WBOIPO_ReactivateAndUndo +}; + +IOleInPlaceObjectImpl SHDOCVW_OleInPlaceObject = {&WBOIPO_Vtbl}; + + +/********************************************************************** + * Implement the IOleControl interface + */ + +static HRESULT WINAPI WBOC_QueryInterface(LPOLECONTROL iface, + REFIID riid, LPVOID *ppobj) +{ + FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); + + if (ppobj == NULL) return E_POINTER; + + return E_NOINTERFACE; +} + +static ULONG WINAPI WBOC_AddRef(LPOLECONTROL iface) +{ + SHDOCVW_LockModule(); + + return 2; /* non-heap based object */ +} + +static ULONG WINAPI WBOC_Release(LPOLECONTROL iface) +{ + SHDOCVW_UnlockModule(); + + return 1; /* non-heap based object */ +} + +static HRESULT WINAPI WBOC_GetControlInfo(LPOLECONTROL iface, LPCONTROLINFO pCI) +{ + FIXME("stub: LPCONTROLINFO = %p\n", pCI); + return S_OK; +} + +static HRESULT WINAPI WBOC_OnMnemonic(LPOLECONTROL iface, struct tagMSG *pMsg) +{ + FIXME("stub: MSG* = %p\n", pMsg); + return S_OK; +} + +static HRESULT WINAPI WBOC_OnAmbientPropertyChange(LPOLECONTROL iface, DISPID dispID) +{ + FIXME("stub: DISPID = %ld\n", dispID); + return S_OK; +} + +static HRESULT WINAPI WBOC_FreezeEvents(LPOLECONTROL iface, BOOL bFreeze) +{ + FIXME("stub: bFreeze = %d\n", bFreeze); + return S_OK; +} + +/********************************************************************** + * IOleControl virtual function table for IE Web Browser component + */ + +static IOleControlVtbl WBOC_Vtbl = +{ + WBOC_QueryInterface, + WBOC_AddRef, + WBOC_Release, + WBOC_GetControlInfo, + WBOC_OnMnemonic, + WBOC_OnAmbientPropertyChange, + WBOC_FreezeEvents +}; + +IOleControlImpl SHDOCVW_OleControl = {&WBOC_Vtbl}; diff --git a/reactos/lib/shdocvw/persist.c b/reactos/lib/shdocvw/persist.c index 53533e5617f..c07a914aed0 100644 --- a/reactos/lib/shdocvw/persist.c +++ b/reactos/lib/shdocvw/persist.c @@ -1,194 +1,194 @@ -/* - * Implementation of IPersist interfaces for IE Web Browser control - * - * Copyright 2001 John R. Sheets (for CodeWeavers) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "wine/debug.h" -#include "shdocvw.h" - -WINE_DEFAULT_DEBUG_CHANNEL(shdocvw); - -/********************************************************************** - * Implement the IPersistStorage interface - */ - -static HRESULT WINAPI WBPS_QueryInterface(LPPERSISTSTORAGE iface, - REFIID riid, LPVOID *ppobj) -{ - FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); - - if (ppobj == NULL) return E_POINTER; - - return E_NOINTERFACE; -} - -static ULONG WINAPI WBPS_AddRef(LPPERSISTSTORAGE iface) -{ - SHDOCVW_LockModule(); - - return 2; /* non-heap based object */ -} - -static ULONG WINAPI WBPS_Release(LPPERSISTSTORAGE iface) -{ - SHDOCVW_UnlockModule(); - - return 1; /* non-heap based object */ -} - -static HRESULT WINAPI WBPS_GetClassID(LPPERSISTSTORAGE iface, CLSID *pClassID) -{ - FIXME("stub: CLSID = %s\n", debugstr_guid(pClassID)); - return S_OK; -} - -static HRESULT WINAPI WBPS_IsDirty(LPPERSISTSTORAGE iface) -{ - FIXME("stub\n"); - return S_OK; -} - -static HRESULT WINAPI WBPS_InitNew(LPPERSISTSTORAGE iface, LPSTORAGE pStg) -{ - FIXME("stub: LPSTORAGE = %p\n", pStg); - return S_OK; -} - -static HRESULT WINAPI WBPS_Load(LPPERSISTSTORAGE iface, LPSTORAGE pStg) -{ - FIXME("stub: LPSTORAGE = %p\n", pStg); - return S_OK; -} - -static HRESULT WINAPI WBPS_Save(LPPERSISTSTORAGE iface, LPSTORAGE pStg, - BOOL fSameAsLoad) -{ - FIXME("stub: LPSTORAGE = %p, fSameAsLoad = %d\n", pStg, fSameAsLoad); - return S_OK; -} - -static HRESULT WINAPI WBPS_SaveCompleted(LPPERSISTSTORAGE iface, LPSTORAGE pStgNew) -{ - FIXME("stub: LPSTORAGE = %p\n", pStgNew); - return S_OK; -} - -/********************************************************************** - * IPersistStorage virtual function table for IE Web Browser component - */ - -static IPersistStorageVtbl WBPS_Vtbl = -{ - WBPS_QueryInterface, - WBPS_AddRef, - WBPS_Release, - WBPS_GetClassID, - WBPS_IsDirty, - WBPS_InitNew, - WBPS_Load, - WBPS_Save, - WBPS_SaveCompleted -}; - -IPersistStorageImpl SHDOCVW_PersistStorage = {&WBPS_Vtbl}; - - -/********************************************************************** - * Implement the IPersistStreamInit interface - */ - -static HRESULT WINAPI WBPSI_QueryInterface(LPPERSISTSTREAMINIT iface, - REFIID riid, LPVOID *ppobj) -{ - FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); - - if (ppobj == NULL) return E_POINTER; - - return E_NOINTERFACE; -} - -static ULONG WINAPI WBPSI_AddRef(LPPERSISTSTREAMINIT iface) -{ - SHDOCVW_LockModule(); - - return 2; /* non-heap based object */ -} - -static ULONG WINAPI WBPSI_Release(LPPERSISTSTREAMINIT iface) -{ - SHDOCVW_UnlockModule(); - - return 1; /* non-heap based object */ -} - -static HRESULT WINAPI WBPSI_GetClassID(LPPERSISTSTREAMINIT iface, CLSID *pClassID) -{ - FIXME("stub: CLSID = %s\n", debugstr_guid(pClassID)); - return S_OK; -} - -static HRESULT WINAPI WBPSI_IsDirty(LPPERSISTSTREAMINIT iface) -{ - FIXME("stub\n"); - return S_OK; -} - -static HRESULT WINAPI WBPSI_Load(LPPERSISTSTREAMINIT iface, LPSTREAM pStg) -{ - FIXME("stub: LPSTORAGE = %p\n", pStg); - return S_OK; -} - -static HRESULT WINAPI WBPSI_Save(LPPERSISTSTREAMINIT iface, LPSTREAM pStg, - BOOL fSameAsLoad) -{ - FIXME("stub: LPSTORAGE = %p, fSameAsLoad = %d\n", pStg, fSameAsLoad); - return S_OK; -} - -static HRESULT WINAPI WBPSI_GetSizeMax(LPPERSISTSTREAMINIT iface, - ULARGE_INTEGER *pcbSize) -{ - FIXME("stub: ULARGE_INTEGER = %p\n", pcbSize); - return S_OK; -} - -static HRESULT WINAPI WBPSI_InitNew(LPPERSISTSTREAMINIT iface) -{ - FIXME("stub\n"); - return S_OK; -} - -/********************************************************************** - * IPersistStreamInit virtual function table for IE Web Browser component - */ - -static IPersistStreamInitVtbl WBPSI_Vtbl = -{ - WBPSI_QueryInterface, - WBPSI_AddRef, - WBPSI_Release, - WBPSI_GetClassID, - WBPSI_IsDirty, - WBPSI_Load, - WBPSI_Save, - WBPSI_GetSizeMax, - WBPSI_InitNew -}; - -IPersistStreamInitImpl SHDOCVW_PersistStreamInit = {&WBPSI_Vtbl}; +/* + * Implementation of IPersist interfaces for IE Web Browser control + * + * Copyright 2001 John R. Sheets (for CodeWeavers) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "wine/debug.h" +#include "shdocvw.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shdocvw); + +/********************************************************************** + * Implement the IPersistStorage interface + */ + +static HRESULT WINAPI WBPS_QueryInterface(LPPERSISTSTORAGE iface, + REFIID riid, LPVOID *ppobj) +{ + FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); + + if (ppobj == NULL) return E_POINTER; + + return E_NOINTERFACE; +} + +static ULONG WINAPI WBPS_AddRef(LPPERSISTSTORAGE iface) +{ + SHDOCVW_LockModule(); + + return 2; /* non-heap based object */ +} + +static ULONG WINAPI WBPS_Release(LPPERSISTSTORAGE iface) +{ + SHDOCVW_UnlockModule(); + + return 1; /* non-heap based object */ +} + +static HRESULT WINAPI WBPS_GetClassID(LPPERSISTSTORAGE iface, CLSID *pClassID) +{ + FIXME("stub: CLSID = %s\n", debugstr_guid(pClassID)); + return S_OK; +} + +static HRESULT WINAPI WBPS_IsDirty(LPPERSISTSTORAGE iface) +{ + FIXME("stub\n"); + return S_OK; +} + +static HRESULT WINAPI WBPS_InitNew(LPPERSISTSTORAGE iface, LPSTORAGE pStg) +{ + FIXME("stub: LPSTORAGE = %p\n", pStg); + return S_OK; +} + +static HRESULT WINAPI WBPS_Load(LPPERSISTSTORAGE iface, LPSTORAGE pStg) +{ + FIXME("stub: LPSTORAGE = %p\n", pStg); + return S_OK; +} + +static HRESULT WINAPI WBPS_Save(LPPERSISTSTORAGE iface, LPSTORAGE pStg, + BOOL fSameAsLoad) +{ + FIXME("stub: LPSTORAGE = %p, fSameAsLoad = %d\n", pStg, fSameAsLoad); + return S_OK; +} + +static HRESULT WINAPI WBPS_SaveCompleted(LPPERSISTSTORAGE iface, LPSTORAGE pStgNew) +{ + FIXME("stub: LPSTORAGE = %p\n", pStgNew); + return S_OK; +} + +/********************************************************************** + * IPersistStorage virtual function table for IE Web Browser component + */ + +static IPersistStorageVtbl WBPS_Vtbl = +{ + WBPS_QueryInterface, + WBPS_AddRef, + WBPS_Release, + WBPS_GetClassID, + WBPS_IsDirty, + WBPS_InitNew, + WBPS_Load, + WBPS_Save, + WBPS_SaveCompleted +}; + +IPersistStorageImpl SHDOCVW_PersistStorage = {&WBPS_Vtbl}; + + +/********************************************************************** + * Implement the IPersistStreamInit interface + */ + +static HRESULT WINAPI WBPSI_QueryInterface(LPPERSISTSTREAMINIT iface, + REFIID riid, LPVOID *ppobj) +{ + FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); + + if (ppobj == NULL) return E_POINTER; + + return E_NOINTERFACE; +} + +static ULONG WINAPI WBPSI_AddRef(LPPERSISTSTREAMINIT iface) +{ + SHDOCVW_LockModule(); + + return 2; /* non-heap based object */ +} + +static ULONG WINAPI WBPSI_Release(LPPERSISTSTREAMINIT iface) +{ + SHDOCVW_UnlockModule(); + + return 1; /* non-heap based object */ +} + +static HRESULT WINAPI WBPSI_GetClassID(LPPERSISTSTREAMINIT iface, CLSID *pClassID) +{ + FIXME("stub: CLSID = %s\n", debugstr_guid(pClassID)); + return S_OK; +} + +static HRESULT WINAPI WBPSI_IsDirty(LPPERSISTSTREAMINIT iface) +{ + FIXME("stub\n"); + return S_OK; +} + +static HRESULT WINAPI WBPSI_Load(LPPERSISTSTREAMINIT iface, LPSTREAM pStg) +{ + FIXME("stub: LPSTORAGE = %p\n", pStg); + return S_OK; +} + +static HRESULT WINAPI WBPSI_Save(LPPERSISTSTREAMINIT iface, LPSTREAM pStg, + BOOL fSameAsLoad) +{ + FIXME("stub: LPSTORAGE = %p, fSameAsLoad = %d\n", pStg, fSameAsLoad); + return S_OK; +} + +static HRESULT WINAPI WBPSI_GetSizeMax(LPPERSISTSTREAMINIT iface, + ULARGE_INTEGER *pcbSize) +{ + FIXME("stub: ULARGE_INTEGER = %p\n", pcbSize); + return S_OK; +} + +static HRESULT WINAPI WBPSI_InitNew(LPPERSISTSTREAMINIT iface) +{ + FIXME("stub\n"); + return S_OK; +} + +/********************************************************************** + * IPersistStreamInit virtual function table for IE Web Browser component + */ + +static IPersistStreamInitVtbl WBPSI_Vtbl = +{ + WBPSI_QueryInterface, + WBPSI_AddRef, + WBPSI_Release, + WBPSI_GetClassID, + WBPSI_IsDirty, + WBPSI_Load, + WBPSI_Save, + WBPSI_GetSizeMax, + WBPSI_InitNew +}; + +IPersistStreamInitImpl SHDOCVW_PersistStreamInit = {&WBPSI_Vtbl}; diff --git a/reactos/lib/shdocvw/regsvr.c b/reactos/lib/shdocvw/regsvr.c index 405a856ba8d..5c282dfc1cd 100644 --- a/reactos/lib/shdocvw/regsvr.c +++ b/reactos/lib/shdocvw/regsvr.c @@ -1,551 +1,551 @@ -/* - * self-registerable dll functions for shdocvw.dll - * - * Copyright (C) 2003 John K. Hohm - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> -#include <string.h> - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "winreg.h" -#include "winerror.h" - -#include "shdocvw.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(shdocvw); - -/* - * Near the bottom of this file are the exported DllRegisterServer and - * DllUnregisterServer, which make all this worthwhile. - */ - -/*********************************************************************** - * interface for self-registering - */ -struct regsvr_interface -{ - IID const *iid; /* NULL for end of list */ - LPCSTR name; /* can be NULL to omit */ - IID const *base_iid; /* can be NULL to omit */ - int num_methods; /* can be <0 to omit */ - CLSID const *ps_clsid; /* can be NULL to omit */ - CLSID const *ps_clsid32; /* can be NULL to omit */ -}; - -static HRESULT register_interfaces(struct regsvr_interface const *list); -static HRESULT unregister_interfaces(struct regsvr_interface const *list); - -struct regsvr_coclass -{ - CLSID const *clsid; /* NULL for end of list */ - LPCSTR name; /* can be NULL to omit */ - LPCSTR ips; /* can be NULL to omit */ - LPCSTR ips32; /* can be NULL to omit */ - LPCSTR ips32_tmodel; /* can be NULL to omit */ - LPCSTR progid; /* can be NULL to omit */ - LPCSTR viprogid; /* can be NULL to omit */ - LPCSTR progid_extra; /* can be NULL to omit */ -}; - -static HRESULT register_coclasses(struct regsvr_coclass const *list); -static HRESULT unregister_coclasses(struct regsvr_coclass const *list); - -/*********************************************************************** - * static string constants - */ -static WCHAR const interface_keyname[10] = { - 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 }; -static WCHAR const base_ifa_keyname[14] = { - 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', - 'e', 0 }; -static WCHAR const num_methods_keyname[11] = { - 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 }; -static WCHAR const ps_clsid_keyname[15] = { - 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', - 'i', 'd', 0 }; -static WCHAR const ps_clsid32_keyname[17] = { - 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', - 'i', 'd', '3', '2', 0 }; -static WCHAR const clsid_keyname[6] = { - 'C', 'L', 'S', 'I', 'D', 0 }; -static WCHAR const curver_keyname[7] = { - 'C', 'u', 'r', 'V', 'e', 'r', 0 }; -static WCHAR const ips_keyname[13] = { - 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', - 0 }; -static WCHAR const ips32_keyname[15] = { - 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', - '3', '2', 0 }; -static WCHAR const progid_keyname[7] = { - 'P', 'r', 'o', 'g', 'I', 'D', 0 }; -static WCHAR const viprogid_keyname[25] = { - 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p', - 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D', - 0 }; -static char const tmodel_valuename[] = "ThreadingModel"; - -/*********************************************************************** - * static helper functions - */ -static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid); -static LONG register_key_defvalueW(HKEY base, WCHAR const *name, - WCHAR const *value); -static LONG register_key_defvalueA(HKEY base, WCHAR const *name, - char const *value); -static LONG register_progid(WCHAR const *clsid, - char const *progid, char const *curver_progid, - char const *name, char const *extra); -static LONG recursive_delete_key(HKEY key); -static LONG recursive_delete_keyA(HKEY base, char const *name); -static LONG recursive_delete_keyW(HKEY base, WCHAR const *name); - -/*********************************************************************** - * register_interfaces - */ -static HRESULT register_interfaces(struct regsvr_interface const *list) -{ - LONG res = ERROR_SUCCESS; - HKEY interface_key; - - res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &interface_key, NULL); - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->iid; ++list) { - WCHAR buf[39]; - HKEY iid_key; - - StringFromGUID2(list->iid, buf, 39); - res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &iid_key, NULL); - if (res != ERROR_SUCCESS) goto error_close_interface_key; - - if (list->name) { - res = RegSetValueExA(iid_key, NULL, 0, REG_SZ, - (CONST BYTE*)(list->name), - strlen(list->name) + 1); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (list->base_iid) { - register_key_guid(iid_key, base_ifa_keyname, list->base_iid); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (0 <= list->num_methods) { - static WCHAR const fmt[3] = { '%', 'd', 0 }; - HKEY key; - - res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &key, NULL); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - - wsprintfW(buf, fmt, list->num_methods); - res = RegSetValueExW(key, NULL, 0, REG_SZ, - (CONST BYTE*)buf, - (lstrlenW(buf) + 1) * sizeof(WCHAR)); - RegCloseKey(key); - - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (list->ps_clsid) { - register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (list->ps_clsid32) { - register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - error_close_iid_key: - RegCloseKey(iid_key); - } - -error_close_interface_key: - RegCloseKey(interface_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * unregister_interfaces - */ -static HRESULT unregister_interfaces(struct regsvr_interface const *list) -{ - LONG res = ERROR_SUCCESS; - HKEY interface_key; - - res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, - KEY_READ | KEY_WRITE, &interface_key); - if (res == ERROR_FILE_NOT_FOUND) return S_OK; - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->iid; ++list) { - WCHAR buf[39]; - - StringFromGUID2(list->iid, buf, 39); - res = recursive_delete_keyW(interface_key, buf); - } - - RegCloseKey(interface_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * register_coclasses - */ -static HRESULT register_coclasses(struct regsvr_coclass const *list) -{ - LONG res = ERROR_SUCCESS; - HKEY coclass_key; - - res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL); - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->clsid; ++list) { - WCHAR buf[39]; - HKEY clsid_key; - - StringFromGUID2(list->clsid, buf, 39); - res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL); - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - - if (list->name) { - res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ, - (CONST BYTE*)(list->name), - strlen(list->name) + 1); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->ips) { - res = register_key_defvalueA(clsid_key, ips_keyname, list->ips); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->ips32) { - HKEY ips32_key; - - res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, - &ips32_key, NULL); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - - res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ, - (CONST BYTE*)list->ips32, - lstrlenA(list->ips32) + 1); - if (res == ERROR_SUCCESS && list->ips32_tmodel) - res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ, - (CONST BYTE*)list->ips32_tmodel, - strlen(list->ips32_tmodel) + 1); - RegCloseKey(ips32_key); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->progid) { - res = register_key_defvalueA(clsid_key, progid_keyname, - list->progid); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - - res = register_progid(buf, list->progid, NULL, - list->name, list->progid_extra); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->viprogid) { - res = register_key_defvalueA(clsid_key, viprogid_keyname, - list->viprogid); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - - res = register_progid(buf, list->viprogid, list->progid, - list->name, list->progid_extra); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - error_close_clsid_key: - RegCloseKey(clsid_key); - } - -error_close_coclass_key: - RegCloseKey(coclass_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * unregister_coclasses - */ -static HRESULT unregister_coclasses(struct regsvr_coclass const *list) -{ - LONG res = ERROR_SUCCESS; - HKEY coclass_key; - - res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, - KEY_READ | KEY_WRITE, &coclass_key); - if (res == ERROR_FILE_NOT_FOUND) return S_OK; - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->clsid; ++list) { - WCHAR buf[39]; - - StringFromGUID2(list->clsid, buf, 39); - res = recursive_delete_keyW(coclass_key, buf); - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - - if (list->progid) { - res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid); - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - } - - if (list->viprogid) { - res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid); - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - } - } - -error_close_coclass_key: - RegCloseKey(coclass_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * regsvr_key_guid - */ -static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) -{ - WCHAR buf[39]; - - StringFromGUID2(guid, buf, 39); - return register_key_defvalueW(base, name, buf); -} - -/*********************************************************************** - * regsvr_key_defvalueW - */ -static LONG register_key_defvalueW( - HKEY base, - WCHAR const *name, - WCHAR const *value) -{ - LONG res; - HKEY key; - - res = RegCreateKeyExW(base, name, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &key, NULL); - if (res != ERROR_SUCCESS) return res; - res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value, - (lstrlenW(value) + 1) * sizeof(WCHAR)); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * regsvr_key_defvalueA - */ -static LONG register_key_defvalueA( - HKEY base, - WCHAR const *name, - char const *value) -{ - LONG res; - HKEY key; - - res = RegCreateKeyExW(base, name, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &key, NULL); - if (res != ERROR_SUCCESS) return res; - res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value, - lstrlenA(value) + 1); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * regsvr_progid - */ -static LONG register_progid( - WCHAR const *clsid, - char const *progid, - char const *curver_progid, - char const *name, - char const *extra) -{ - LONG res; - HKEY progid_key; - - res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0, - NULL, 0, KEY_READ | KEY_WRITE, NULL, - &progid_key, NULL); - if (res != ERROR_SUCCESS) return res; - - if (name) { - res = RegSetValueExA(progid_key, NULL, 0, REG_SZ, - (CONST BYTE*)name, strlen(name) + 1); - if (res != ERROR_SUCCESS) goto error_close_progid_key; - } - - if (clsid) { - res = register_key_defvalueW(progid_key, clsid_keyname, clsid); - if (res != ERROR_SUCCESS) goto error_close_progid_key; - } - - if (curver_progid) { - res = register_key_defvalueA(progid_key, curver_keyname, - curver_progid); - if (res != ERROR_SUCCESS) goto error_close_progid_key; - } - - if (extra) { - HKEY extra_key; - - res = RegCreateKeyExA(progid_key, extra, 0, - NULL, 0, KEY_READ | KEY_WRITE, NULL, - &extra_key, NULL); - if (res == ERROR_SUCCESS) - RegCloseKey(extra_key); - } - -error_close_progid_key: - RegCloseKey(progid_key); - return res; -} - -/*********************************************************************** - * recursive_delete_key - */ -static LONG recursive_delete_key(HKEY key) -{ - LONG res; - WCHAR subkey_name[MAX_PATH]; - DWORD cName; - HKEY subkey; - - for (;;) { - cName = sizeof(subkey_name) / sizeof(WCHAR); - res = RegEnumKeyExW(key, 0, subkey_name, &cName, - NULL, NULL, NULL, NULL); - if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) { - res = ERROR_SUCCESS; /* presumably we're done enumerating */ - break; - } - res = RegOpenKeyExW(key, subkey_name, 0, - KEY_READ | KEY_WRITE, &subkey); - if (res == ERROR_FILE_NOT_FOUND) continue; - if (res != ERROR_SUCCESS) break; - - res = recursive_delete_key(subkey); - RegCloseKey(subkey); - if (res != ERROR_SUCCESS) break; - } - - if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0); - return res; -} - -/*********************************************************************** - * recursive_delete_keyA - */ -static LONG recursive_delete_keyA(HKEY base, char const *name) -{ - LONG res; - HKEY key; - - res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key); - if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; - if (res != ERROR_SUCCESS) return res; - res = recursive_delete_key(key); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * recursive_delete_keyW - */ -static LONG recursive_delete_keyW(HKEY base, WCHAR const *name) -{ - LONG res; - HKEY key; - - res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key); - if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; - if (res != ERROR_SUCCESS) return res; - res = recursive_delete_key(key); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * coclass list - */ -static struct regsvr_coclass const coclass_list[] = { - { &CLSID_WebBrowser, - "Microsoft Web Browser", - NULL, - "shdocvw.dll", - "Apartment", - "Shell.Explorer.2", - "Shell.Explorer" - }, - { NULL } /* list terminator */ -}; - -/*********************************************************************** - * interface list - */ - -static struct regsvr_interface const interface_list[] = { - { NULL } /* list terminator */ -}; - -/*********************************************************************** - * DllRegisterServer (SHDOCVW.@) - */ -HRESULT WINAPI DllRegisterServer(void) -{ - HRESULT hr; - - TRACE("\n"); - - hr = register_coclasses(coclass_list); - if (SUCCEEDED(hr)) - hr = register_interfaces(interface_list); - return hr; -} - -/*********************************************************************** - * DllUnregisterServer (SHDOCVW.@) - */ -HRESULT WINAPI DllUnregisterServer(void) -{ - HRESULT hr; - - TRACE("\n"); - - hr = unregister_coclasses(coclass_list); - if (SUCCEEDED(hr)) - hr = unregister_interfaces(interface_list); - return hr; -} +/* + * self-registerable dll functions for shdocvw.dll + * + * Copyright (C) 2003 John K. Hohm + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> +#include <string.h> + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "winerror.h" + +#include "shdocvw.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shdocvw); + +/* + * Near the bottom of this file are the exported DllRegisterServer and + * DllUnregisterServer, which make all this worthwhile. + */ + +/*********************************************************************** + * interface for self-registering + */ +struct regsvr_interface +{ + IID const *iid; /* NULL for end of list */ + LPCSTR name; /* can be NULL to omit */ + IID const *base_iid; /* can be NULL to omit */ + int num_methods; /* can be <0 to omit */ + CLSID const *ps_clsid; /* can be NULL to omit */ + CLSID const *ps_clsid32; /* can be NULL to omit */ +}; + +static HRESULT register_interfaces(struct regsvr_interface const *list); +static HRESULT unregister_interfaces(struct regsvr_interface const *list); + +struct regsvr_coclass +{ + CLSID const *clsid; /* NULL for end of list */ + LPCSTR name; /* can be NULL to omit */ + LPCSTR ips; /* can be NULL to omit */ + LPCSTR ips32; /* can be NULL to omit */ + LPCSTR ips32_tmodel; /* can be NULL to omit */ + LPCSTR progid; /* can be NULL to omit */ + LPCSTR viprogid; /* can be NULL to omit */ + LPCSTR progid_extra; /* can be NULL to omit */ +}; + +static HRESULT register_coclasses(struct regsvr_coclass const *list); +static HRESULT unregister_coclasses(struct regsvr_coclass const *list); + +/*********************************************************************** + * static string constants + */ +static WCHAR const interface_keyname[10] = { + 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 }; +static WCHAR const base_ifa_keyname[14] = { + 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', + 'e', 0 }; +static WCHAR const num_methods_keyname[11] = { + 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 }; +static WCHAR const ps_clsid_keyname[15] = { + 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', + 'i', 'd', 0 }; +static WCHAR const ps_clsid32_keyname[17] = { + 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', + 'i', 'd', '3', '2', 0 }; +static WCHAR const clsid_keyname[6] = { + 'C', 'L', 'S', 'I', 'D', 0 }; +static WCHAR const curver_keyname[7] = { + 'C', 'u', 'r', 'V', 'e', 'r', 0 }; +static WCHAR const ips_keyname[13] = { + 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', + 0 }; +static WCHAR const ips32_keyname[15] = { + 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', + '3', '2', 0 }; +static WCHAR const progid_keyname[7] = { + 'P', 'r', 'o', 'g', 'I', 'D', 0 }; +static WCHAR const viprogid_keyname[25] = { + 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p', + 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D', + 0 }; +static char const tmodel_valuename[] = "ThreadingModel"; + +/*********************************************************************** + * static helper functions + */ +static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid); +static LONG register_key_defvalueW(HKEY base, WCHAR const *name, + WCHAR const *value); +static LONG register_key_defvalueA(HKEY base, WCHAR const *name, + char const *value); +static LONG register_progid(WCHAR const *clsid, + char const *progid, char const *curver_progid, + char const *name, char const *extra); +static LONG recursive_delete_key(HKEY key); +static LONG recursive_delete_keyA(HKEY base, char const *name); +static LONG recursive_delete_keyW(HKEY base, WCHAR const *name); + +/*********************************************************************** + * register_interfaces + */ +static HRESULT register_interfaces(struct regsvr_interface const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY interface_key; + + res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &interface_key, NULL); + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->iid; ++list) { + WCHAR buf[39]; + HKEY iid_key; + + StringFromGUID2(list->iid, buf, 39); + res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &iid_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_interface_key; + + if (list->name) { + res = RegSetValueExA(iid_key, NULL, 0, REG_SZ, + (CONST BYTE*)(list->name), + strlen(list->name) + 1); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->base_iid) { + register_key_guid(iid_key, base_ifa_keyname, list->base_iid); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (0 <= list->num_methods) { + static WCHAR const fmt[3] = { '%', 'd', 0 }; + HKEY key; + + res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + + wsprintfW(buf, fmt, list->num_methods); + res = RegSetValueExW(key, NULL, 0, REG_SZ, + (CONST BYTE*)buf, + (lstrlenW(buf) + 1) * sizeof(WCHAR)); + RegCloseKey(key); + + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->ps_clsid) { + register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->ps_clsid32) { + register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + error_close_iid_key: + RegCloseKey(iid_key); + } + +error_close_interface_key: + RegCloseKey(interface_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * unregister_interfaces + */ +static HRESULT unregister_interfaces(struct regsvr_interface const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY interface_key; + + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, + KEY_READ | KEY_WRITE, &interface_key); + if (res == ERROR_FILE_NOT_FOUND) return S_OK; + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->iid; ++list) { + WCHAR buf[39]; + + StringFromGUID2(list->iid, buf, 39); + res = recursive_delete_keyW(interface_key, buf); + } + + RegCloseKey(interface_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * register_coclasses + */ +static HRESULT register_coclasses(struct regsvr_coclass const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY coclass_key; + + res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL); + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->clsid; ++list) { + WCHAR buf[39]; + HKEY clsid_key; + + StringFromGUID2(list->clsid, buf, 39); + res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + + if (list->name) { + res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ, + (CONST BYTE*)(list->name), + strlen(list->name) + 1); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->ips) { + res = register_key_defvalueA(clsid_key, ips_keyname, list->ips); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->ips32) { + HKEY ips32_key; + + res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, + &ips32_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ, + (CONST BYTE*)list->ips32, + lstrlenA(list->ips32) + 1); + if (res == ERROR_SUCCESS && list->ips32_tmodel) + res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ, + (CONST BYTE*)list->ips32_tmodel, + strlen(list->ips32_tmodel) + 1); + RegCloseKey(ips32_key); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->progid) { + res = register_key_defvalueA(clsid_key, progid_keyname, + list->progid); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = register_progid(buf, list->progid, NULL, + list->name, list->progid_extra); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->viprogid) { + res = register_key_defvalueA(clsid_key, viprogid_keyname, + list->viprogid); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = register_progid(buf, list->viprogid, list->progid, + list->name, list->progid_extra); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + error_close_clsid_key: + RegCloseKey(clsid_key); + } + +error_close_coclass_key: + RegCloseKey(coclass_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * unregister_coclasses + */ +static HRESULT unregister_coclasses(struct regsvr_coclass const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY coclass_key; + + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, + KEY_READ | KEY_WRITE, &coclass_key); + if (res == ERROR_FILE_NOT_FOUND) return S_OK; + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->clsid; ++list) { + WCHAR buf[39]; + + StringFromGUID2(list->clsid, buf, 39); + res = recursive_delete_keyW(coclass_key, buf); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + + if (list->progid) { + res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + } + + if (list->viprogid) { + res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + } + } + +error_close_coclass_key: + RegCloseKey(coclass_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * regsvr_key_guid + */ +static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) +{ + WCHAR buf[39]; + + StringFromGUID2(guid, buf, 39); + return register_key_defvalueW(base, name, buf); +} + +/*********************************************************************** + * regsvr_key_defvalueW + */ +static LONG register_key_defvalueW( + HKEY base, + WCHAR const *name, + WCHAR const *value) +{ + LONG res; + HKEY key; + + res = RegCreateKeyExW(base, name, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) return res; + res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value, + (lstrlenW(value) + 1) * sizeof(WCHAR)); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * regsvr_key_defvalueA + */ +static LONG register_key_defvalueA( + HKEY base, + WCHAR const *name, + char const *value) +{ + LONG res; + HKEY key; + + res = RegCreateKeyExW(base, name, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) return res; + res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value, + lstrlenA(value) + 1); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * regsvr_progid + */ +static LONG register_progid( + WCHAR const *clsid, + char const *progid, + char const *curver_progid, + char const *name, + char const *extra) +{ + LONG res; + HKEY progid_key; + + res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0, + NULL, 0, KEY_READ | KEY_WRITE, NULL, + &progid_key, NULL); + if (res != ERROR_SUCCESS) return res; + + if (name) { + res = RegSetValueExA(progid_key, NULL, 0, REG_SZ, + (CONST BYTE*)name, strlen(name) + 1); + if (res != ERROR_SUCCESS) goto error_close_progid_key; + } + + if (clsid) { + res = register_key_defvalueW(progid_key, clsid_keyname, clsid); + if (res != ERROR_SUCCESS) goto error_close_progid_key; + } + + if (curver_progid) { + res = register_key_defvalueA(progid_key, curver_keyname, + curver_progid); + if (res != ERROR_SUCCESS) goto error_close_progid_key; + } + + if (extra) { + HKEY extra_key; + + res = RegCreateKeyExA(progid_key, extra, 0, + NULL, 0, KEY_READ | KEY_WRITE, NULL, + &extra_key, NULL); + if (res == ERROR_SUCCESS) + RegCloseKey(extra_key); + } + +error_close_progid_key: + RegCloseKey(progid_key); + return res; +} + +/*********************************************************************** + * recursive_delete_key + */ +static LONG recursive_delete_key(HKEY key) +{ + LONG res; + WCHAR subkey_name[MAX_PATH]; + DWORD cName; + HKEY subkey; + + for (;;) { + cName = sizeof(subkey_name) / sizeof(WCHAR); + res = RegEnumKeyExW(key, 0, subkey_name, &cName, + NULL, NULL, NULL, NULL); + if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) { + res = ERROR_SUCCESS; /* presumably we're done enumerating */ + break; + } + res = RegOpenKeyExW(key, subkey_name, 0, + KEY_READ | KEY_WRITE, &subkey); + if (res == ERROR_FILE_NOT_FOUND) continue; + if (res != ERROR_SUCCESS) break; + + res = recursive_delete_key(subkey); + RegCloseKey(subkey); + if (res != ERROR_SUCCESS) break; + } + + if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0); + return res; +} + +/*********************************************************************** + * recursive_delete_keyA + */ +static LONG recursive_delete_keyA(HKEY base, char const *name) +{ + LONG res; + HKEY key; + + res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key); + if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; + if (res != ERROR_SUCCESS) return res; + res = recursive_delete_key(key); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * recursive_delete_keyW + */ +static LONG recursive_delete_keyW(HKEY base, WCHAR const *name) +{ + LONG res; + HKEY key; + + res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key); + if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; + if (res != ERROR_SUCCESS) return res; + res = recursive_delete_key(key); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * coclass list + */ +static struct regsvr_coclass const coclass_list[] = { + { &CLSID_WebBrowser, + "Microsoft Web Browser", + NULL, + "shdocvw.dll", + "Apartment", + "Shell.Explorer.2", + "Shell.Explorer" + }, + { NULL } /* list terminator */ +}; + +/*********************************************************************** + * interface list + */ + +static struct regsvr_interface const interface_list[] = { + { NULL } /* list terminator */ +}; + +/*********************************************************************** + * DllRegisterServer (SHDOCVW.@) + */ +HRESULT WINAPI DllRegisterServer(void) +{ + HRESULT hr; + + TRACE("\n"); + + hr = register_coclasses(coclass_list); + if (SUCCEEDED(hr)) + hr = register_interfaces(interface_list); + return hr; +} + +/*********************************************************************** + * DllUnregisterServer (SHDOCVW.@) + */ +HRESULT WINAPI DllUnregisterServer(void) +{ + HRESULT hr; + + TRACE("\n"); + + hr = unregister_coclasses(coclass_list); + if (SUCCEEDED(hr)) + hr = unregister_interfaces(interface_list); + return hr; +} diff --git a/reactos/lib/shdocvw/shdocvw.h b/reactos/lib/shdocvw/shdocvw.h index 44ea589bdea..0c8ff470d43 100644 --- a/reactos/lib/shdocvw/shdocvw.h +++ b/reactos/lib/shdocvw/shdocvw.h @@ -1,200 +1,200 @@ -/* - * Header includes for shdocvw.dll - * - * Copyright 2001 John R. Sheets (for CodeWeavers) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_SHDOCVW_H -#define __WINE_SHDOCVW_H - -#define COM_NO_WINDOWS_H -/* FIXME: Is there a better way to deal with all these includes? */ -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" - -#include "ole2.h" -#include "olectl.h" -#include "shlobj.h" -#include "exdisp.h" - -/********************************************************************** - * IClassFactory declaration for SHDOCVW.DLL - */ -typedef struct -{ - /* IUnknown fields */ - IClassFactoryVtbl *lpVtbl; - DWORD ref; -} IClassFactoryImpl; - -extern IClassFactoryImpl SHDOCVW_ClassFactory; - - -/********************************************************************** - * IOleObject declaration for SHDOCVW.DLL - */ -typedef struct -{ - /* IUnknown fields */ - IOleObjectVtbl *lpVtbl; - DWORD ref; -} IOleObjectImpl; - -extern IOleObjectImpl SHDOCVW_OleObject; - - -/********************************************************************** - * IOleInPlaceObject declaration for SHDOCVW.DLL - */ -typedef struct -{ - /* IUnknown fields */ - IOleInPlaceObjectVtbl *lpVtbl; - DWORD ref; -} IOleInPlaceObjectImpl; - -extern IOleInPlaceObjectImpl SHDOCVW_OleInPlaceObject; - - -/********************************************************************** - * IOleControl declaration for SHDOCVW.DLL - */ -typedef struct -{ - /* IUnknown fields */ - IOleControlVtbl *lpVtbl; - DWORD ref; -} IOleControlImpl; - -extern IOleControlImpl SHDOCVW_OleControl; - - -/********************************************************************** - * IWebBrowser declaration for SHDOCVW.DLL - */ -typedef struct -{ - /* IUnknown fields */ - IWebBrowserVtbl *lpVtbl; - DWORD ref; -} IWebBrowserImpl; - -extern IWebBrowserImpl SHDOCVW_WebBrowser; - - -/********************************************************************** - * IProvideClassInfo declaration for SHDOCVW.DLL - */ -typedef struct -{ - /* IUnknown fields */ - IProvideClassInfoVtbl *lpVtbl; - DWORD ref; -} IProvideClassInfoImpl; - -extern IProvideClassInfoImpl SHDOCVW_ProvideClassInfo; - - -/********************************************************************** - * IProvideClassInfo2 declaration for SHDOCVW.DLL - */ -typedef struct -{ - /* IUnknown fields */ - IProvideClassInfo2Vtbl *lpVtbl; - DWORD ref; -} IProvideClassInfo2Impl; - -extern IProvideClassInfo2Impl SHDOCVW_ProvideClassInfo2; - - -/********************************************************************** - * IPersistStorage declaration for SHDOCVW.DLL - */ -typedef struct -{ - /* IUnknown fields */ - IPersistStorageVtbl *lpVtbl; - DWORD ref; -} IPersistStorageImpl; - -extern IPersistStorageImpl SHDOCVW_PersistStorage; - - -/********************************************************************** - * IPersistStreamInit declaration for SHDOCVW.DLL - */ -typedef struct -{ - /* IUnknown fields */ - IPersistStreamInitVtbl *lpVtbl; - DWORD ref; -} IPersistStreamInitImpl; - -extern IPersistStreamInitImpl SHDOCVW_PersistStreamInit; - - -/********************************************************************** - * IQuickActivate declaration for SHDOCVW.DLL - */ -typedef struct -{ - /* IUnknown fields */ - IQuickActivateVtbl *lpVtbl; - DWORD ref; -} IQuickActivateImpl; - -extern IQuickActivateImpl SHDOCVW_QuickActivate; - - -/********************************************************************** - * IConnectionPointContainer declaration for SHDOCVW.DLL - */ -typedef struct -{ - /* IUnknown fields */ - IConnectionPointContainerVtbl *lpVtbl; - DWORD ref; -} IConnectionPointContainerImpl; - -extern IConnectionPointContainerImpl SHDOCVW_ConnectionPointContainer; - - -/********************************************************************** - * IConnectionPoint declaration for SHDOCVW.DLL - */ -typedef struct -{ - /* IUnknown fields */ - IConnectionPointVtbl *lpVtbl; - DWORD ref; -} IConnectionPointImpl; - -extern IConnectionPointImpl SHDOCVW_ConnectionPoint; - -/********************************************************************** - * Dll lifetime tracking declaration for shdocvw.dll - */ -extern LONG SHDOCVW_refCount; -static inline void SHDOCVW_LockModule() { InterlockedIncrement( &SHDOCVW_refCount ); } -static inline void SHDOCVW_UnlockModule() { InterlockedDecrement( &SHDOCVW_refCount ); } - -#endif /* __WINE_SHDOCVW_H */ +/* + * Header includes for shdocvw.dll + * + * Copyright 2001 John R. Sheets (for CodeWeavers) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_SHDOCVW_H +#define __WINE_SHDOCVW_H + +#define COM_NO_WINDOWS_H +/* FIXME: Is there a better way to deal with all these includes? */ +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" + +#include "ole2.h" +#include "olectl.h" +#include "shlobj.h" +#include "exdisp.h" + +/********************************************************************** + * IClassFactory declaration for SHDOCVW.DLL + */ +typedef struct +{ + /* IUnknown fields */ + IClassFactoryVtbl *lpVtbl; + DWORD ref; +} IClassFactoryImpl; + +extern IClassFactoryImpl SHDOCVW_ClassFactory; + + +/********************************************************************** + * IOleObject declaration for SHDOCVW.DLL + */ +typedef struct +{ + /* IUnknown fields */ + IOleObjectVtbl *lpVtbl; + DWORD ref; +} IOleObjectImpl; + +extern IOleObjectImpl SHDOCVW_OleObject; + + +/********************************************************************** + * IOleInPlaceObject declaration for SHDOCVW.DLL + */ +typedef struct +{ + /* IUnknown fields */ + IOleInPlaceObjectVtbl *lpVtbl; + DWORD ref; +} IOleInPlaceObjectImpl; + +extern IOleInPlaceObjectImpl SHDOCVW_OleInPlaceObject; + + +/********************************************************************** + * IOleControl declaration for SHDOCVW.DLL + */ +typedef struct +{ + /* IUnknown fields */ + IOleControlVtbl *lpVtbl; + DWORD ref; +} IOleControlImpl; + +extern IOleControlImpl SHDOCVW_OleControl; + + +/********************************************************************** + * IWebBrowser declaration for SHDOCVW.DLL + */ +typedef struct +{ + /* IUnknown fields */ + IWebBrowserVtbl *lpVtbl; + DWORD ref; +} IWebBrowserImpl; + +extern IWebBrowserImpl SHDOCVW_WebBrowser; + + +/********************************************************************** + * IProvideClassInfo declaration for SHDOCVW.DLL + */ +typedef struct +{ + /* IUnknown fields */ + IProvideClassInfoVtbl *lpVtbl; + DWORD ref; +} IProvideClassInfoImpl; + +extern IProvideClassInfoImpl SHDOCVW_ProvideClassInfo; + + +/********************************************************************** + * IProvideClassInfo2 declaration for SHDOCVW.DLL + */ +typedef struct +{ + /* IUnknown fields */ + IProvideClassInfo2Vtbl *lpVtbl; + DWORD ref; +} IProvideClassInfo2Impl; + +extern IProvideClassInfo2Impl SHDOCVW_ProvideClassInfo2; + + +/********************************************************************** + * IPersistStorage declaration for SHDOCVW.DLL + */ +typedef struct +{ + /* IUnknown fields */ + IPersistStorageVtbl *lpVtbl; + DWORD ref; +} IPersistStorageImpl; + +extern IPersistStorageImpl SHDOCVW_PersistStorage; + + +/********************************************************************** + * IPersistStreamInit declaration for SHDOCVW.DLL + */ +typedef struct +{ + /* IUnknown fields */ + IPersistStreamInitVtbl *lpVtbl; + DWORD ref; +} IPersistStreamInitImpl; + +extern IPersistStreamInitImpl SHDOCVW_PersistStreamInit; + + +/********************************************************************** + * IQuickActivate declaration for SHDOCVW.DLL + */ +typedef struct +{ + /* IUnknown fields */ + IQuickActivateVtbl *lpVtbl; + DWORD ref; +} IQuickActivateImpl; + +extern IQuickActivateImpl SHDOCVW_QuickActivate; + + +/********************************************************************** + * IConnectionPointContainer declaration for SHDOCVW.DLL + */ +typedef struct +{ + /* IUnknown fields */ + IConnectionPointContainerVtbl *lpVtbl; + DWORD ref; +} IConnectionPointContainerImpl; + +extern IConnectionPointContainerImpl SHDOCVW_ConnectionPointContainer; + + +/********************************************************************** + * IConnectionPoint declaration for SHDOCVW.DLL + */ +typedef struct +{ + /* IUnknown fields */ + IConnectionPointVtbl *lpVtbl; + DWORD ref; +} IConnectionPointImpl; + +extern IConnectionPointImpl SHDOCVW_ConnectionPoint; + +/********************************************************************** + * Dll lifetime tracking declaration for shdocvw.dll + */ +extern LONG SHDOCVW_refCount; +static inline void SHDOCVW_LockModule() { InterlockedIncrement( &SHDOCVW_refCount ); } +static inline void SHDOCVW_UnlockModule() { InterlockedDecrement( &SHDOCVW_refCount ); } + +#endif /* __WINE_SHDOCVW_H */ diff --git a/reactos/lib/shdocvw/shdocvw_main.c b/reactos/lib/shdocvw/shdocvw_main.c index 5f94189d9e0..03c4470e354 100644 --- a/reactos/lib/shdocvw/shdocvw_main.c +++ b/reactos/lib/shdocvw/shdocvw_main.c @@ -1,576 +1,576 @@ -/* - * SHDOCVW - Internet Explorer Web Control - * - * Copyright 2001 John R. Sheets (for CodeWeavers) - * Copyright 2004 Mike McCormack (for CodeWeavers) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <stdarg.h> -#include <stdio.h> -#include <string.h> - -#define COBJMACROS -#define COM_NO_WINDOWS_H - -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "winuser.h" -#include "winnls.h" -#include "ole2.h" -#include "shlwapi.h" - -#include "shdocvw.h" -#include "uuids.h" -#include "urlmon.h" - -#include "wine/unicode.h" -#include "wine/debug.h" - -#include "initguid.h" - -WINE_DEFAULT_DEBUG_CHANNEL(shdocvw); - -LONG SHDOCVW_refCount = 0; - -static const WCHAR szMozDlPath[] = { - 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\', - 's','h','d','o','c','v','w',0 -}; - -DEFINE_GUID( CLSID_MozillaBrowser, 0x1339B54C,0x3453,0x11D2,0x93,0xB9,0x00,0x00,0x00,0x00,0x00,0x00); - -typedef HRESULT (WINAPI *fnGetClassObject)(REFCLSID rclsid, REFIID iid, LPVOID *ppv); -typedef HRESULT (WINAPI *fnCanUnloadNow)(void); - -HINSTANCE shdocvw_hinstance = 0; -static HMODULE SHDOCVW_hshell32 = 0; -static HMODULE hMozCtl = (HMODULE)~0UL; - - -/* convert a guid to a wide character string */ -static void SHDOCVW_guid2wstr( const GUID *guid, LPWSTR wstr ) -{ - char str[40]; - - sprintf(str, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", - guid->Data1, guid->Data2, guid->Data3, - guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], - guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] ); - MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, 40 ); -} - -static BOOL SHDOCVW_GetMozctlPath( LPWSTR szPath, DWORD sz ) -{ - DWORD r, type; - BOOL ret = FALSE; - HKEY hkey; - static const WCHAR szPre[] = { - 'S','o','f','t','w','a','r','e','\\', - 'C','l','a','s','s','e','s','\\', - 'C','L','S','I','D','\\',0 }; - static const WCHAR szPost[] = { - '\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2',0 }; - WCHAR szRegPath[(sizeof(szPre)+sizeof(szPost))/sizeof(WCHAR)+40]; - - strcpyW( szRegPath, szPre ); - SHDOCVW_guid2wstr( &CLSID_MozillaBrowser, &szRegPath[strlenW(szRegPath)] ); - strcatW( szRegPath, szPost ); - - TRACE("key = %s\n", debugstr_w( szRegPath ) ); - - r = RegOpenKeyW( HKEY_LOCAL_MACHINE, szRegPath, &hkey ); - if( r != ERROR_SUCCESS ) - return FALSE; - - r = RegQueryValueExW( hkey, NULL, NULL, &type, (LPBYTE)szPath, &sz ); - ret = ( r == ERROR_SUCCESS ) && ( type == REG_SZ ); - RegCloseKey( hkey ); - - return ret; -} - -/************************************************************************* - * SHDOCVW DllMain - */ -BOOL WINAPI DllMain(HINSTANCE hinst, DWORD fdwReason, LPVOID fImpLoad) -{ - TRACE("%p 0x%lx %p\n", hinst, fdwReason, fImpLoad); - switch (fdwReason) - { - case DLL_PROCESS_ATTACH: - shdocvw_hinstance = hinst; - break; - case DLL_PROCESS_DETACH: - if (SHDOCVW_hshell32) FreeLibrary(SHDOCVW_hshell32); - if (hMozCtl && hMozCtl != (HMODULE)~0UL) FreeLibrary(hMozCtl); - break; - } - return TRUE; -} - -/************************************************************************* - * DllCanUnloadNow (SHDOCVW.@) - */ -HRESULT WINAPI DllCanUnloadNow(void) -{ - HRESULT moz_can_unload = S_OK; - fnCanUnloadNow pCanUnloadNow; - - if (hMozCtl) - { - pCanUnloadNow = (fnCanUnloadNow) - GetProcAddress(hMozCtl, "DllCanUnloadNow"); - if (pCanUnloadNow) - moz_can_unload = pCanUnloadNow(); - } - - if (moz_can_unload == S_OK && SHDOCVW_refCount == 0) - return S_OK; - - return S_FALSE; -} - -/************************************************************************* - * SHDOCVW_TryDownloadMozillaControl - */ -typedef struct _IBindStatusCallbackImpl { - IBindStatusCallbackVtbl *vtbl; - DWORD ref; - HWND hDialog; - BOOL *pbCancelled; -} IBindStatusCallbackImpl; - -static HRESULT WINAPI -dlQueryInterface( IBindStatusCallback* This, REFIID riid, void** ppvObject ) -{ - if (ppvObject == NULL) return E_POINTER; - - if( IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IBindStatusCallback)) - { - IBindStatusCallback_AddRef( This ); - *ppvObject = This; - return S_OK; - } - return E_NOINTERFACE; -} - -static ULONG WINAPI dlAddRef( IBindStatusCallback* iface ) -{ - IBindStatusCallbackImpl *This = (IBindStatusCallbackImpl *) iface; - - SHDOCVW_LockModule(); - - return InterlockedIncrement( &This->ref ); -} - -static ULONG WINAPI dlRelease( IBindStatusCallback* iface ) -{ - IBindStatusCallbackImpl *This = (IBindStatusCallbackImpl *) iface; - DWORD ref = InterlockedDecrement( &This->ref ); - - if( !ref ) - { - DestroyWindow( This->hDialog ); - HeapFree( GetProcessHeap(), 0, This ); - } - - SHDOCVW_UnlockModule(); - - return ref; -} - -static HRESULT WINAPI -dlOnStartBinding( IBindStatusCallback* iface, DWORD dwReserved, IBinding* pib) -{ - ERR("\n"); - return S_OK; -} - -static HRESULT WINAPI -dlGetPriority( IBindStatusCallback* iface, LONG* pnPriority) -{ - ERR("\n"); - return S_OK; -} - -static HRESULT WINAPI -dlOnLowResource( IBindStatusCallback* iface, DWORD reserved) -{ - ERR("\n"); - return S_OK; -} - -static HRESULT WINAPI -dlOnProgress( IBindStatusCallback* iface, ULONG ulProgress, - ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText) -{ - IBindStatusCallbackImpl *This = (IBindStatusCallbackImpl *) iface; - HWND hItem; - LONG r; - - hItem = GetDlgItem( This->hDialog, 1000 ); - if( hItem && ulProgressMax ) - SendMessageW(hItem,PBM_SETPOS,(ulProgress*100)/ulProgressMax,0); - - hItem = GetDlgItem(This->hDialog, 104); - if( hItem ) - SendMessageW(hItem,WM_SETTEXT, 0, (LPARAM) szStatusText); - - SetLastError(0); - r = GetWindowLongPtrW( This->hDialog, GWLP_USERDATA ); - if( r || GetLastError() ) - { - *This->pbCancelled = TRUE; - ERR("Cancelled\n"); - return E_ABORT; - } - - return S_OK; -} - -static HRESULT WINAPI -dlOnStopBinding( IBindStatusCallback* iface, HRESULT hresult, LPCWSTR szError) -{ - ERR("\n"); - return S_OK; -} - -static HRESULT WINAPI -dlGetBindInfo( IBindStatusCallback* iface, DWORD* grfBINDF, BINDINFO* pbindinfo) -{ - ERR("\n"); - return S_OK; -} - -static HRESULT WINAPI -dlOnDataAvailable( IBindStatusCallback* iface, DWORD grfBSCF, - DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed) -{ - ERR("\n"); - return S_OK; -} - -static HRESULT WINAPI -dlOnObjectAvailable( IBindStatusCallback* iface, REFIID riid, IUnknown* punk) -{ - ERR("\n"); - return S_OK; -} - -struct IBindStatusCallbackVtbl dlVtbl = -{ - dlQueryInterface, - dlAddRef, - dlRelease, - dlOnStartBinding, - dlGetPriority, - dlOnLowResource, - dlOnProgress, - dlOnStopBinding, - dlGetBindInfo, - dlOnDataAvailable, - dlOnObjectAvailable -}; - -static IBindStatusCallback* create_dl(HWND dlg, BOOL *pbCancelled) -{ - IBindStatusCallbackImpl *This; - - This = HeapAlloc( GetProcessHeap(), 0, sizeof *This ); - This->vtbl = &dlVtbl; - This->ref = 1; - This->hDialog = dlg; - This->pbCancelled = pbCancelled; - - return (IBindStatusCallback*) This; -} - -static DWORD WINAPI ThreadFunc( LPVOID info ) -{ - IBindStatusCallback *dl; - static const WCHAR szUrlVal[] = {'M','o','z','i','l','l','a','U','r','l',0}; - WCHAR path[MAX_PATH], szUrl[MAX_PATH]; - LPWSTR p; - STARTUPINFOW si; - PROCESS_INFORMATION pi; - HWND hDlg = info; - DWORD r, sz, type; - HKEY hkey; - BOOL bCancelled = FALSE; - - /* find the name of the thing to download */ - szUrl[0] = 0; - r = RegOpenKeyW( HKEY_LOCAL_MACHINE, szMozDlPath, &hkey ); - if( r == ERROR_SUCCESS ) - { - sz = MAX_PATH; - r = RegQueryValueExW( hkey, szUrlVal, NULL, &type, (LPBYTE)szUrl, &sz ); - RegCloseKey( hkey ); - } - if( r != ERROR_SUCCESS ) - goto end; - - /* built the path for the download */ - p = strrchrW( szUrl, '/' ); - if (!p) - goto end; - if (!GetTempPathW( MAX_PATH, path )) - goto end; - strcatW( path, p+1 ); - - /* download it */ - dl = create_dl(info, &bCancelled); - r = URLDownloadToFileW( NULL, szUrl, path, 0, dl ); - if( dl ) - IBindStatusCallback_Release( dl ); - if( (r != S_OK) || bCancelled ) - goto end; - - /* run it */ - memset( &si, 0, sizeof si ); - si.cb = sizeof si; - r = CreateProcessW( path, NULL, NULL, NULL, 0, 0, NULL, NULL, &si, &pi ); - if( !r ) - goto end; - WaitForSingleObject( pi.hProcess, INFINITE ); - -end: - EndDialog( hDlg, 0 ); - return 0; -} - -static INT_PTR CALLBACK -dlProc ( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - HANDLE hThread; - DWORD ThreadId; - HWND hItem; - - switch (uMsg) - { - case WM_INITDIALOG: - SetWindowLongPtrW( hwndDlg, GWLP_USERDATA, 0 ); - hItem = GetDlgItem(hwndDlg, 1000); - if( hItem ) - { - SendMessageW(hItem,PBM_SETRANGE,0,MAKELPARAM(0,100)); - SendMessageW(hItem,PBM_SETPOS,0,0); - } - hThread = CreateThread(NULL,0,ThreadFunc,hwndDlg,0,&ThreadId); - if (!hThread) - return FALSE; - return TRUE; - case WM_COMMAND: - if( wParam == IDCANCEL ) - SetWindowLongPtrW( hwndDlg, GWLP_USERDATA, 1 ); - return FALSE; - default: - return FALSE; - } -} - -static BOOL SHDOCVW_TryDownloadMozillaControl() -{ - DWORD r; - WCHAR buf[0x100]; - static const WCHAR szWine[] = { 'W','i','n','e',0 }; - HANDLE hsem; - - SetLastError( ERROR_SUCCESS ); - hsem = CreateSemaphoreA( NULL, 0, 1, "mozctl_install_semaphore"); - if( GetLastError() != ERROR_ALREADY_EXISTS ) - { - LoadStringW( shdocvw_hinstance, 1001, buf, sizeof buf/sizeof(WCHAR) ); - r = MessageBoxW(NULL, buf, szWine, MB_YESNO | MB_ICONQUESTION); - if( r != IDYES ) - return FALSE; - - DialogBoxW(shdocvw_hinstance, MAKEINTRESOURCEW(100), 0, dlProc); - } - else - WaitForSingleObject( hsem, INFINITE ); - ReleaseSemaphore( hsem, 1, NULL ); - CloseHandle( hsem ); - - return TRUE; -} - -static BOOL SHDOCVW_TryLoadMozillaControl() -{ - WCHAR szPath[MAX_PATH]; - BOOL bTried = FALSE; - - if( hMozCtl != (HMODULE)~0UL ) - return hMozCtl ? TRUE : FALSE; - - while( 1 ) - { - if( SHDOCVW_GetMozctlPath( szPath, sizeof szPath ) ) - { - hMozCtl = LoadLibraryExW(szPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); - if( hMozCtl ) - return TRUE; - } - if( bTried ) - { - MESSAGE("You need to install the Mozilla ActiveX control to\n"); - MESSAGE("use Wine's builtin CLSID_WebBrowser from SHDOCVW.DLL\n"); - return FALSE; - } - SHDOCVW_TryDownloadMozillaControl(); - bTried = TRUE; - } -} - -/************************************************************************* - * DllGetClassObject (SHDOCVW.@) - */ -HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) -{ - TRACE("\n"); - - if( IsEqualGUID( &CLSID_WebBrowser, rclsid ) && - SHDOCVW_TryLoadMozillaControl() ) - { - HRESULT r; - fnGetClassObject pGetClassObject; - - TRACE("WebBrowser class %s\n", debugstr_guid(rclsid) ); - - pGetClassObject = (fnGetClassObject) - GetProcAddress( hMozCtl, "DllGetClassObject" ); - - if( !pGetClassObject ) - return CLASS_E_CLASSNOTAVAILABLE; - r = pGetClassObject( &CLSID_MozillaBrowser, riid, ppv ); - - TRACE("r = %08lx *ppv = %p\n", r, *ppv ); - - return r; - } - - if (IsEqualGUID(&IID_IClassFactory, riid)) - { - /* Pass back our shdocvw class factory */ - *ppv = (LPVOID)&SHDOCVW_ClassFactory; - IClassFactory_AddRef((IClassFactory*)&SHDOCVW_ClassFactory); - - return S_OK; - } - - return CLASS_E_CLASSNOTAVAILABLE; -} - -/*********************************************************************** - * DllGetVersion (SHDOCVW.@) - */ -HRESULT WINAPI DllGetVersion(DLLVERSIONINFO *info) -{ - if (info->cbSize != sizeof(DLLVERSIONINFO)) FIXME("support DLLVERSIONINFO2\n"); - - /* this is what IE6 on Windows 98 reports */ - info->dwMajorVersion = 6; - info->dwMinorVersion = 0; - info->dwBuildNumber = 2600; - info->dwPlatformID = DLLVER_PLATFORM_WINDOWS; - - return NOERROR; -} - -/************************************************************************* - * DllInstall (SHDOCVW.@) - */ -HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline) -{ - FIXME("(%s, %s): stub!\n", bInstall ? "TRUE":"FALSE", debugstr_w(cmdline)); - - return S_OK; -} - -/************************************************************************* - * SHDOCVW_LoadShell32 - * - * makes sure the handle to shell32 is valid - */ - BOOL SHDOCVW_LoadShell32(void) -{ - if (SHDOCVW_hshell32) - return TRUE; - return ((SHDOCVW_hshell32 = LoadLibraryA("shell32.dll")) != NULL); -} - -/*********************************************************************** - * @ (SHDOCVW.110) - * - * Called by Win98 explorer.exe main binary, definitely has 0 - * parameters. - */ -DWORD WINAPI WinList_Init(void) -{ - FIXME("(), stub!\n"); - return 0x0deadfeed; -} - -/*********************************************************************** - * @ (SHDOCVW.118) - * - * Called by Win98 explorer.exe main binary, definitely has only one - * parameter. - */ -static BOOL (WINAPI *pShellDDEInit)(BOOL start) = NULL; - -BOOL WINAPI ShellDDEInit(BOOL start) -{ - TRACE("(%d)\n", start); - - if (!pShellDDEInit) - { - if (!SHDOCVW_LoadShell32()) - return FALSE; - pShellDDEInit = GetProcAddress(SHDOCVW_hshell32, (LPCSTR)188); - } - - if (pShellDDEInit) - return pShellDDEInit(start); - else - return FALSE; -} - -/*********************************************************************** - * @ (SHDOCVW.125) - * - * Called by Win98 explorer.exe main binary, definitely has 0 - * parameters. - */ -DWORD WINAPI RunInstallUninstallStubs(void) -{ - FIXME("(), stub!\n"); - return 0x0deadbee; -} - -/*********************************************************************** - * SetQueryNetSessionCount (SHDOCVW.@) - */ -DWORD WINAPI SetQueryNetSessionCount(DWORD arg) -{ - FIXME("(%lu), stub!\n", arg); - return 0; -} +/* + * SHDOCVW - Internet Explorer Web Control + * + * Copyright 2001 John R. Sheets (for CodeWeavers) + * Copyright 2004 Mike McCormack (for CodeWeavers) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#define COBJMACROS +#define COM_NO_WINDOWS_H + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winuser.h" +#include "winnls.h" +#include "ole2.h" +#include "shlwapi.h" + +#include "shdocvw.h" +#include "uuids.h" +#include "urlmon.h" + +#include "wine/unicode.h" +#include "wine/debug.h" + +#include "initguid.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shdocvw); + +LONG SHDOCVW_refCount = 0; + +static const WCHAR szMozDlPath[] = { + 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\', + 's','h','d','o','c','v','w',0 +}; + +DEFINE_GUID( CLSID_MozillaBrowser, 0x1339B54C,0x3453,0x11D2,0x93,0xB9,0x00,0x00,0x00,0x00,0x00,0x00); + +typedef HRESULT (WINAPI *fnGetClassObject)(REFCLSID rclsid, REFIID iid, LPVOID *ppv); +typedef HRESULT (WINAPI *fnCanUnloadNow)(void); + +HINSTANCE shdocvw_hinstance = 0; +static HMODULE SHDOCVW_hshell32 = 0; +static HMODULE hMozCtl = (HMODULE)~0UL; + + +/* convert a guid to a wide character string */ +static void SHDOCVW_guid2wstr( const GUID *guid, LPWSTR wstr ) +{ + char str[40]; + + sprintf(str, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", + guid->Data1, guid->Data2, guid->Data3, + guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], + guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] ); + MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, 40 ); +} + +static BOOL SHDOCVW_GetMozctlPath( LPWSTR szPath, DWORD sz ) +{ + DWORD r, type; + BOOL ret = FALSE; + HKEY hkey; + static const WCHAR szPre[] = { + 'S','o','f','t','w','a','r','e','\\', + 'C','l','a','s','s','e','s','\\', + 'C','L','S','I','D','\\',0 }; + static const WCHAR szPost[] = { + '\\','I','n','p','r','o','c','S','e','r','v','e','r','3','2',0 }; + WCHAR szRegPath[(sizeof(szPre)+sizeof(szPost))/sizeof(WCHAR)+40]; + + strcpyW( szRegPath, szPre ); + SHDOCVW_guid2wstr( &CLSID_MozillaBrowser, &szRegPath[strlenW(szRegPath)] ); + strcatW( szRegPath, szPost ); + + TRACE("key = %s\n", debugstr_w( szRegPath ) ); + + r = RegOpenKeyW( HKEY_LOCAL_MACHINE, szRegPath, &hkey ); + if( r != ERROR_SUCCESS ) + return FALSE; + + r = RegQueryValueExW( hkey, NULL, NULL, &type, (LPBYTE)szPath, &sz ); + ret = ( r == ERROR_SUCCESS ) && ( type == REG_SZ ); + RegCloseKey( hkey ); + + return ret; +} + +/************************************************************************* + * SHDOCVW DllMain + */ +BOOL WINAPI DllMain(HINSTANCE hinst, DWORD fdwReason, LPVOID fImpLoad) +{ + TRACE("%p 0x%lx %p\n", hinst, fdwReason, fImpLoad); + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + shdocvw_hinstance = hinst; + break; + case DLL_PROCESS_DETACH: + if (SHDOCVW_hshell32) FreeLibrary(SHDOCVW_hshell32); + if (hMozCtl && hMozCtl != (HMODULE)~0UL) FreeLibrary(hMozCtl); + break; + } + return TRUE; +} + +/************************************************************************* + * DllCanUnloadNow (SHDOCVW.@) + */ +HRESULT WINAPI DllCanUnloadNow(void) +{ + HRESULT moz_can_unload = S_OK; + fnCanUnloadNow pCanUnloadNow; + + if (hMozCtl) + { + pCanUnloadNow = (fnCanUnloadNow) + GetProcAddress(hMozCtl, "DllCanUnloadNow"); + if (pCanUnloadNow) + moz_can_unload = pCanUnloadNow(); + } + + if (moz_can_unload == S_OK && SHDOCVW_refCount == 0) + return S_OK; + + return S_FALSE; +} + +/************************************************************************* + * SHDOCVW_TryDownloadMozillaControl + */ +typedef struct _IBindStatusCallbackImpl { + IBindStatusCallbackVtbl *vtbl; + DWORD ref; + HWND hDialog; + BOOL *pbCancelled; +} IBindStatusCallbackImpl; + +static HRESULT WINAPI +dlQueryInterface( IBindStatusCallback* This, REFIID riid, void** ppvObject ) +{ + if (ppvObject == NULL) return E_POINTER; + + if( IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IBindStatusCallback)) + { + IBindStatusCallback_AddRef( This ); + *ppvObject = This; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI dlAddRef( IBindStatusCallback* iface ) +{ + IBindStatusCallbackImpl *This = (IBindStatusCallbackImpl *) iface; + + SHDOCVW_LockModule(); + + return InterlockedIncrement( &This->ref ); +} + +static ULONG WINAPI dlRelease( IBindStatusCallback* iface ) +{ + IBindStatusCallbackImpl *This = (IBindStatusCallbackImpl *) iface; + DWORD ref = InterlockedDecrement( &This->ref ); + + if( !ref ) + { + DestroyWindow( This->hDialog ); + HeapFree( GetProcessHeap(), 0, This ); + } + + SHDOCVW_UnlockModule(); + + return ref; +} + +static HRESULT WINAPI +dlOnStartBinding( IBindStatusCallback* iface, DWORD dwReserved, IBinding* pib) +{ + ERR("\n"); + return S_OK; +} + +static HRESULT WINAPI +dlGetPriority( IBindStatusCallback* iface, LONG* pnPriority) +{ + ERR("\n"); + return S_OK; +} + +static HRESULT WINAPI +dlOnLowResource( IBindStatusCallback* iface, DWORD reserved) +{ + ERR("\n"); + return S_OK; +} + +static HRESULT WINAPI +dlOnProgress( IBindStatusCallback* iface, ULONG ulProgress, + ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText) +{ + IBindStatusCallbackImpl *This = (IBindStatusCallbackImpl *) iface; + HWND hItem; + LONG r; + + hItem = GetDlgItem( This->hDialog, 1000 ); + if( hItem && ulProgressMax ) + SendMessageW(hItem,PBM_SETPOS,(ulProgress*100)/ulProgressMax,0); + + hItem = GetDlgItem(This->hDialog, 104); + if( hItem ) + SendMessageW(hItem,WM_SETTEXT, 0, (LPARAM) szStatusText); + + SetLastError(0); + r = GetWindowLongPtrW( This->hDialog, GWLP_USERDATA ); + if( r || GetLastError() ) + { + *This->pbCancelled = TRUE; + ERR("Cancelled\n"); + return E_ABORT; + } + + return S_OK; +} + +static HRESULT WINAPI +dlOnStopBinding( IBindStatusCallback* iface, HRESULT hresult, LPCWSTR szError) +{ + ERR("\n"); + return S_OK; +} + +static HRESULT WINAPI +dlGetBindInfo( IBindStatusCallback* iface, DWORD* grfBINDF, BINDINFO* pbindinfo) +{ + ERR("\n"); + return S_OK; +} + +static HRESULT WINAPI +dlOnDataAvailable( IBindStatusCallback* iface, DWORD grfBSCF, + DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed) +{ + ERR("\n"); + return S_OK; +} + +static HRESULT WINAPI +dlOnObjectAvailable( IBindStatusCallback* iface, REFIID riid, IUnknown* punk) +{ + ERR("\n"); + return S_OK; +} + +struct IBindStatusCallbackVtbl dlVtbl = +{ + dlQueryInterface, + dlAddRef, + dlRelease, + dlOnStartBinding, + dlGetPriority, + dlOnLowResource, + dlOnProgress, + dlOnStopBinding, + dlGetBindInfo, + dlOnDataAvailable, + dlOnObjectAvailable +}; + +static IBindStatusCallback* create_dl(HWND dlg, BOOL *pbCancelled) +{ + IBindStatusCallbackImpl *This; + + This = HeapAlloc( GetProcessHeap(), 0, sizeof *This ); + This->vtbl = &dlVtbl; + This->ref = 1; + This->hDialog = dlg; + This->pbCancelled = pbCancelled; + + return (IBindStatusCallback*) This; +} + +static DWORD WINAPI ThreadFunc( LPVOID info ) +{ + IBindStatusCallback *dl; + static const WCHAR szUrlVal[] = {'M','o','z','i','l','l','a','U','r','l',0}; + WCHAR path[MAX_PATH], szUrl[MAX_PATH]; + LPWSTR p; + STARTUPINFOW si; + PROCESS_INFORMATION pi; + HWND hDlg = info; + DWORD r, sz, type; + HKEY hkey; + BOOL bCancelled = FALSE; + + /* find the name of the thing to download */ + szUrl[0] = 0; + r = RegOpenKeyW( HKEY_LOCAL_MACHINE, szMozDlPath, &hkey ); + if( r == ERROR_SUCCESS ) + { + sz = MAX_PATH; + r = RegQueryValueExW( hkey, szUrlVal, NULL, &type, (LPBYTE)szUrl, &sz ); + RegCloseKey( hkey ); + } + if( r != ERROR_SUCCESS ) + goto end; + + /* built the path for the download */ + p = strrchrW( szUrl, '/' ); + if (!p) + goto end; + if (!GetTempPathW( MAX_PATH, path )) + goto end; + strcatW( path, p+1 ); + + /* download it */ + dl = create_dl(info, &bCancelled); + r = URLDownloadToFileW( NULL, szUrl, path, 0, dl ); + if( dl ) + IBindStatusCallback_Release( dl ); + if( (r != S_OK) || bCancelled ) + goto end; + + /* run it */ + memset( &si, 0, sizeof si ); + si.cb = sizeof si; + r = CreateProcessW( path, NULL, NULL, NULL, 0, 0, NULL, NULL, &si, &pi ); + if( !r ) + goto end; + WaitForSingleObject( pi.hProcess, INFINITE ); + +end: + EndDialog( hDlg, 0 ); + return 0; +} + +static INT_PTR CALLBACK +dlProc ( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + HANDLE hThread; + DWORD ThreadId; + HWND hItem; + + switch (uMsg) + { + case WM_INITDIALOG: + SetWindowLongPtrW( hwndDlg, GWLP_USERDATA, 0 ); + hItem = GetDlgItem(hwndDlg, 1000); + if( hItem ) + { + SendMessageW(hItem,PBM_SETRANGE,0,MAKELPARAM(0,100)); + SendMessageW(hItem,PBM_SETPOS,0,0); + } + hThread = CreateThread(NULL,0,ThreadFunc,hwndDlg,0,&ThreadId); + if (!hThread) + return FALSE; + return TRUE; + case WM_COMMAND: + if( wParam == IDCANCEL ) + SetWindowLongPtrW( hwndDlg, GWLP_USERDATA, 1 ); + return FALSE; + default: + return FALSE; + } +} + +static BOOL SHDOCVW_TryDownloadMozillaControl() +{ + DWORD r; + WCHAR buf[0x100]; + static const WCHAR szWine[] = { 'W','i','n','e',0 }; + HANDLE hsem; + + SetLastError( ERROR_SUCCESS ); + hsem = CreateSemaphoreA( NULL, 0, 1, "mozctl_install_semaphore"); + if( GetLastError() != ERROR_ALREADY_EXISTS ) + { + LoadStringW( shdocvw_hinstance, 1001, buf, sizeof buf/sizeof(WCHAR) ); + r = MessageBoxW(NULL, buf, szWine, MB_YESNO | MB_ICONQUESTION); + if( r != IDYES ) + return FALSE; + + DialogBoxW(shdocvw_hinstance, MAKEINTRESOURCEW(100), 0, dlProc); + } + else + WaitForSingleObject( hsem, INFINITE ); + ReleaseSemaphore( hsem, 1, NULL ); + CloseHandle( hsem ); + + return TRUE; +} + +static BOOL SHDOCVW_TryLoadMozillaControl() +{ + WCHAR szPath[MAX_PATH]; + BOOL bTried = FALSE; + + if( hMozCtl != (HMODULE)~0UL ) + return hMozCtl ? TRUE : FALSE; + + while( 1 ) + { + if( SHDOCVW_GetMozctlPath( szPath, sizeof szPath ) ) + { + hMozCtl = LoadLibraryExW(szPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if( hMozCtl ) + return TRUE; + } + if( bTried ) + { + MESSAGE("You need to install the Mozilla ActiveX control to\n"); + MESSAGE("use Wine's builtin CLSID_WebBrowser from SHDOCVW.DLL\n"); + return FALSE; + } + SHDOCVW_TryDownloadMozillaControl(); + bTried = TRUE; + } +} + +/************************************************************************* + * DllGetClassObject (SHDOCVW.@) + */ +HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) +{ + TRACE("\n"); + + if( IsEqualGUID( &CLSID_WebBrowser, rclsid ) && + SHDOCVW_TryLoadMozillaControl() ) + { + HRESULT r; + fnGetClassObject pGetClassObject; + + TRACE("WebBrowser class %s\n", debugstr_guid(rclsid) ); + + pGetClassObject = (fnGetClassObject) + GetProcAddress( hMozCtl, "DllGetClassObject" ); + + if( !pGetClassObject ) + return CLASS_E_CLASSNOTAVAILABLE; + r = pGetClassObject( &CLSID_MozillaBrowser, riid, ppv ); + + TRACE("r = %08lx *ppv = %p\n", r, *ppv ); + + return r; + } + + if (IsEqualGUID(&IID_IClassFactory, riid)) + { + /* Pass back our shdocvw class factory */ + *ppv = (LPVOID)&SHDOCVW_ClassFactory; + IClassFactory_AddRef((IClassFactory*)&SHDOCVW_ClassFactory); + + return S_OK; + } + + return CLASS_E_CLASSNOTAVAILABLE; +} + +/*********************************************************************** + * DllGetVersion (SHDOCVW.@) + */ +HRESULT WINAPI DllGetVersion(DLLVERSIONINFO *info) +{ + if (info->cbSize != sizeof(DLLVERSIONINFO)) FIXME("support DLLVERSIONINFO2\n"); + + /* this is what IE6 on Windows 98 reports */ + info->dwMajorVersion = 6; + info->dwMinorVersion = 0; + info->dwBuildNumber = 2600; + info->dwPlatformID = DLLVER_PLATFORM_WINDOWS; + + return NOERROR; +} + +/************************************************************************* + * DllInstall (SHDOCVW.@) + */ +HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline) +{ + FIXME("(%s, %s): stub!\n", bInstall ? "TRUE":"FALSE", debugstr_w(cmdline)); + + return S_OK; +} + +/************************************************************************* + * SHDOCVW_LoadShell32 + * + * makes sure the handle to shell32 is valid + */ + BOOL SHDOCVW_LoadShell32(void) +{ + if (SHDOCVW_hshell32) + return TRUE; + return ((SHDOCVW_hshell32 = LoadLibraryA("shell32.dll")) != NULL); +} + +/*********************************************************************** + * @ (SHDOCVW.110) + * + * Called by Win98 explorer.exe main binary, definitely has 0 + * parameters. + */ +DWORD WINAPI WinList_Init(void) +{ + FIXME("(), stub!\n"); + return 0x0deadfeed; +} + +/*********************************************************************** + * @ (SHDOCVW.118) + * + * Called by Win98 explorer.exe main binary, definitely has only one + * parameter. + */ +static BOOL (WINAPI *pShellDDEInit)(BOOL start) = NULL; + +BOOL WINAPI ShellDDEInit(BOOL start) +{ + TRACE("(%d)\n", start); + + if (!pShellDDEInit) + { + if (!SHDOCVW_LoadShell32()) + return FALSE; + pShellDDEInit = GetProcAddress(SHDOCVW_hshell32, (LPCSTR)188); + } + + if (pShellDDEInit) + return pShellDDEInit(start); + else + return FALSE; +} + +/*********************************************************************** + * @ (SHDOCVW.125) + * + * Called by Win98 explorer.exe main binary, definitely has 0 + * parameters. + */ +DWORD WINAPI RunInstallUninstallStubs(void) +{ + FIXME("(), stub!\n"); + return 0x0deadbee; +} + +/*********************************************************************** + * SetQueryNetSessionCount (SHDOCVW.@) + */ +DWORD WINAPI SetQueryNetSessionCount(DWORD arg) +{ + FIXME("(%lu), stub!\n", arg); + return 0; +} diff --git a/reactos/lib/shdocvw/webbrowser.c b/reactos/lib/shdocvw/webbrowser.c index 21bd351b649..bcc8d84efd4 100644 --- a/reactos/lib/shdocvw/webbrowser.c +++ b/reactos/lib/shdocvw/webbrowser.c @@ -1,278 +1,278 @@ -/* - * Implementation of IWebBrowser interface for IE Web Browser control - * - * Copyright 2001 John R. Sheets (for CodeWeavers) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "wine/debug.h" -#include "shdocvw.h" - -WINE_DEFAULT_DEBUG_CHANNEL(shdocvw); - -/********************************************************************** - * Implement the IWebBrowser interface - */ - -static HRESULT WINAPI WB_QueryInterface(IWebBrowser *iface, REFIID riid, LPVOID *ppobj) -{ - FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); - - if (ppobj == NULL) return E_POINTER; - - return E_NOINTERFACE; -} - -static ULONG WINAPI WB_AddRef(IWebBrowser *iface) -{ - SHDOCVW_LockModule(); - - return 2; /* non-heap based object */ -} - -static ULONG WINAPI WB_Release(IWebBrowser *iface) -{ - SHDOCVW_UnlockModule(); - - return 1; /* non-heap based object */ -} - -/* IDispatch methods */ -static HRESULT WINAPI WB_GetTypeInfoCount(IWebBrowser *iface, UINT *pctinfo) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_GetTypeInfo(IWebBrowser *iface, UINT iTInfo, LCID lcid, - LPTYPEINFO *ppTInfo) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_GetIDsOfNames(IWebBrowser *iface, REFIID riid, - LPOLESTR *rgszNames, UINT cNames, - LCID lcid, DISPID *rgDispId) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_Invoke(IWebBrowser *iface, DISPID dispIdMember, - REFIID riid, LCID lcid, WORD wFlags, - DISPPARAMS *pDispParams, VARIANT *pVarResult, - EXCEPINFO *pExepInfo, UINT *puArgErr) -{ - FIXME("stub dispIdMember = %d, IID = %s\n", (int)dispIdMember, debugstr_guid(riid)); - return S_OK; -} - -/* IWebBrowser methods */ -static HRESULT WINAPI WB_GoBack(IWebBrowser *iface) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_GoForward(IWebBrowser *iface) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_GoHome(IWebBrowser *iface) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_GoSearch(IWebBrowser *iface) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_Navigate(IWebBrowser *iface, BSTR URL, - VARIANT *Flags, VARIANT *TargetFrameName, - VARIANT *PostData, VARIANT *Headers) -{ - FIXME("stub: URL = %p (%p, %p, %p, %p)\n", URL, Flags, TargetFrameName, - PostData, Headers); - return S_OK; -} - -static HRESULT WINAPI WB_Refresh(IWebBrowser *iface) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_Refresh2(IWebBrowser *iface, VARIANT *Level) -{ - FIXME("stub: %p\n", Level); - return S_OK; -} - -static HRESULT WINAPI WB_Stop(IWebBrowser *iface) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_get_Application(IWebBrowser *iface, IDispatch **ppDisp) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_get_Parent(IWebBrowser *iface, IDispatch **ppDisp) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_get_Container(IWebBrowser *iface, IDispatch **ppDisp) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_get_Document(IWebBrowser *iface, IDispatch **ppDisp) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_get_TopLevelContainer(IWebBrowser *iface, VARIANT_BOOL *pBool) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_get_Type(IWebBrowser *iface, BSTR *Type) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_get_Left(IWebBrowser *iface, long *pl) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_put_Left(IWebBrowser *iface, long Left) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_get_Top(IWebBrowser *iface, long *pl) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_put_Top(IWebBrowser *iface, long Top) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_get_Width(IWebBrowser *iface, long *pl) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_put_Width(IWebBrowser *iface, long Width) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_get_Height(IWebBrowser *iface, long *pl) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_put_Height(IWebBrowser *iface, long Height) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_get_LocationName(IWebBrowser *iface, BSTR *LocationName) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_get_LocationURL(IWebBrowser *iface, BSTR *LocationURL) -{ - FIXME("stub \n"); - return S_OK; -} - -static HRESULT WINAPI WB_get_Busy(IWebBrowser *iface, VARIANT_BOOL *pBool) -{ - FIXME("stub \n"); - return S_OK; -} - -/********************************************************************** - * IWebBrowser virtual function table for IE Web Browser component - */ - -static IWebBrowserVtbl WB_Vtbl = -{ - WB_QueryInterface, - WB_AddRef, - WB_Release, - WB_GetTypeInfoCount, - WB_GetTypeInfo, - WB_GetIDsOfNames, - WB_Invoke, - WB_GoBack, - WB_GoForward, - WB_GoHome, - WB_GoSearch, - WB_Navigate, - WB_Refresh, - WB_Refresh2, - WB_Stop, - WB_get_Application, - WB_get_Parent, - WB_get_Container, - WB_get_Document, - WB_get_TopLevelContainer, - WB_get_Type, - WB_get_Left, - WB_put_Left, - WB_get_Top, - WB_put_Top, - WB_get_Width, - WB_put_Width, - WB_get_Height, - WB_put_Height, - WB_get_LocationName, - WB_get_LocationURL, - WB_get_Busy -}; - -IWebBrowserImpl SHDOCVW_WebBrowser = {&WB_Vtbl}; +/* + * Implementation of IWebBrowser interface for IE Web Browser control + * + * Copyright 2001 John R. Sheets (for CodeWeavers) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "wine/debug.h" +#include "shdocvw.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shdocvw); + +/********************************************************************** + * Implement the IWebBrowser interface + */ + +static HRESULT WINAPI WB_QueryInterface(IWebBrowser *iface, REFIID riid, LPVOID *ppobj) +{ + FIXME("- no interface\n\tIID:\t%s\n", debugstr_guid(riid)); + + if (ppobj == NULL) return E_POINTER; + + return E_NOINTERFACE; +} + +static ULONG WINAPI WB_AddRef(IWebBrowser *iface) +{ + SHDOCVW_LockModule(); + + return 2; /* non-heap based object */ +} + +static ULONG WINAPI WB_Release(IWebBrowser *iface) +{ + SHDOCVW_UnlockModule(); + + return 1; /* non-heap based object */ +} + +/* IDispatch methods */ +static HRESULT WINAPI WB_GetTypeInfoCount(IWebBrowser *iface, UINT *pctinfo) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_GetTypeInfo(IWebBrowser *iface, UINT iTInfo, LCID lcid, + LPTYPEINFO *ppTInfo) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_GetIDsOfNames(IWebBrowser *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_Invoke(IWebBrowser *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, + DISPPARAMS *pDispParams, VARIANT *pVarResult, + EXCEPINFO *pExepInfo, UINT *puArgErr) +{ + FIXME("stub dispIdMember = %d, IID = %s\n", (int)dispIdMember, debugstr_guid(riid)); + return S_OK; +} + +/* IWebBrowser methods */ +static HRESULT WINAPI WB_GoBack(IWebBrowser *iface) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_GoForward(IWebBrowser *iface) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_GoHome(IWebBrowser *iface) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_GoSearch(IWebBrowser *iface) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_Navigate(IWebBrowser *iface, BSTR URL, + VARIANT *Flags, VARIANT *TargetFrameName, + VARIANT *PostData, VARIANT *Headers) +{ + FIXME("stub: URL = %p (%p, %p, %p, %p)\n", URL, Flags, TargetFrameName, + PostData, Headers); + return S_OK; +} + +static HRESULT WINAPI WB_Refresh(IWebBrowser *iface) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_Refresh2(IWebBrowser *iface, VARIANT *Level) +{ + FIXME("stub: %p\n", Level); + return S_OK; +} + +static HRESULT WINAPI WB_Stop(IWebBrowser *iface) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_get_Application(IWebBrowser *iface, IDispatch **ppDisp) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_get_Parent(IWebBrowser *iface, IDispatch **ppDisp) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_get_Container(IWebBrowser *iface, IDispatch **ppDisp) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_get_Document(IWebBrowser *iface, IDispatch **ppDisp) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_get_TopLevelContainer(IWebBrowser *iface, VARIANT_BOOL *pBool) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_get_Type(IWebBrowser *iface, BSTR *Type) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_get_Left(IWebBrowser *iface, long *pl) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_put_Left(IWebBrowser *iface, long Left) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_get_Top(IWebBrowser *iface, long *pl) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_put_Top(IWebBrowser *iface, long Top) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_get_Width(IWebBrowser *iface, long *pl) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_put_Width(IWebBrowser *iface, long Width) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_get_Height(IWebBrowser *iface, long *pl) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_put_Height(IWebBrowser *iface, long Height) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_get_LocationName(IWebBrowser *iface, BSTR *LocationName) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_get_LocationURL(IWebBrowser *iface, BSTR *LocationURL) +{ + FIXME("stub \n"); + return S_OK; +} + +static HRESULT WINAPI WB_get_Busy(IWebBrowser *iface, VARIANT_BOOL *pBool) +{ + FIXME("stub \n"); + return S_OK; +} + +/********************************************************************** + * IWebBrowser virtual function table for IE Web Browser component + */ + +static IWebBrowserVtbl WB_Vtbl = +{ + WB_QueryInterface, + WB_AddRef, + WB_Release, + WB_GetTypeInfoCount, + WB_GetTypeInfo, + WB_GetIDsOfNames, + WB_Invoke, + WB_GoBack, + WB_GoForward, + WB_GoHome, + WB_GoSearch, + WB_Navigate, + WB_Refresh, + WB_Refresh2, + WB_Stop, + WB_get_Application, + WB_get_Parent, + WB_get_Container, + WB_get_Document, + WB_get_TopLevelContainer, + WB_get_Type, + WB_get_Left, + WB_put_Left, + WB_get_Top, + WB_put_Top, + WB_get_Width, + WB_put_Width, + WB_get_Height, + WB_put_Height, + WB_get_LocationName, + WB_get_LocationURL, + WB_get_Busy +}; + +IWebBrowserImpl SHDOCVW_WebBrowser = {&WB_Vtbl}; diff --git a/reactos/lib/shell32/authors.c b/reactos/lib/shell32/authors.c index 36ed8a39c25..ae4b28f00ae 100644 --- a/reactos/lib/shell32/authors.c +++ b/reactos/lib/shell32/authors.c @@ -1 +1 @@ -const char * const SHELL_Authors[] = { "Copyright 1993-2005 WINE team", "Copyright 1998-2005 ReactOS Team", 0 }; +const char * const SHELL_Authors[] = { "Copyright 1993-2005 WINE team", "Copyright 1998-2005 ReactOS Team", 0 }; diff --git a/reactos/lib/shlwapi/assoc.c b/reactos/lib/shlwapi/assoc.c index 81109b96ecf..153f1d43e27 100644 --- a/reactos/lib/shlwapi/assoc.c +++ b/reactos/lib/shlwapi/assoc.c @@ -1,706 +1,706 @@ -/* - * IQueryAssociations object and helper functions - * - * Copyright 2002 Jon Griffiths - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "winreg.h" -#include "objbase.h" -#include "shlguid.h" -#include "shlwapi.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(shell); - -/************************************************************************** - * IQueryAssociations {SHLWAPI} - * - * DESCRIPTION - * This object provides a layer of abstraction over the system registry in - * order to simplify the process of parsing associations between files. - * Associations in this context means the registry entries that link (for - * example) the extension of a file with its description, list of - * applications to open the file with, and actions that can be performed on it - * (the shell displays such information in the context menu of explorer - * when you right-click on a file). - * - * HELPERS - * You can use this object transparently by calling the helper functions - * AssocQueryKeyA(), AssocQueryStringA() and AssocQueryStringByKeyA(). These - * create an IQueryAssociations object, perform the requested actions - * and then dispose of the object. Alternatively, you can create an instance - * of the object using AssocCreate() and call the following methods on it: - * - * METHODS - */ - -/* Default IQueryAssociations::Init() flags */ -#define SHLWAPI_DEF_ASSOCF (ASSOCF_INIT_BYEXENAME|ASSOCF_INIT_DEFAULTTOSTAR| \ - ASSOCF_INIT_DEFAULTTOFOLDER) - -typedef struct -{ - IQueryAssociationsVtbl *lpVtbl; - LONG ref; - HKEY hkeySource; - HKEY hkeyProgID; -} IQueryAssociationsImpl; - -static struct IQueryAssociationsVtbl IQueryAssociations_vtbl; - -/************************************************************************** - * IQueryAssociations_Constructor [internal] - * - * Construct a new IQueryAssociations object. - */ -static IQueryAssociations* IQueryAssociations_Constructor(void) -{ - IQueryAssociationsImpl* iface; - - iface = HeapAlloc(GetProcessHeap(),0,sizeof(IQueryAssociationsImpl)); - iface->lpVtbl = &IQueryAssociations_vtbl; - iface->ref = 1; - iface->hkeySource = NULL; - iface->hkeyProgID = NULL; - - TRACE("Returning IQueryAssociations* %p\n", iface); - return (IQueryAssociations*)iface; -} - -/************************************************************************* - * SHLWAPI_ParamAToW - * - * Internal helper function: Convert ASCII parameter to Unicode. - */ -static BOOL SHLWAPI_ParamAToW(LPCSTR lpszParam, LPWSTR lpszBuff, DWORD dwLen, - LPWSTR* lpszOut) -{ - if (lpszParam) - { - DWORD dwStrLen = MultiByteToWideChar(CP_ACP, 0, lpszParam, -1, NULL, 0); - - if (dwStrLen < dwLen) - { - *lpszOut = lpszBuff; /* Use Buffer, it is big enough */ - } - else - { - /* Create a new buffer big enough for the string */ - *lpszOut = HeapAlloc(GetProcessHeap(), 0, - dwStrLen * sizeof(WCHAR)); - if (!*lpszOut) - return FALSE; - } - MultiByteToWideChar(CP_ACP, 0, lpszParam, -1, *lpszOut, dwStrLen); - } - else - *lpszOut = NULL; - return TRUE; -} - -/************************************************************************* - * AssocCreate [SHLWAPI.@] - * - * Create a new IQueryAssociations object. - * - * PARAMS - * clsid [I] CLSID of object - * refiid [I] REFIID of interface - * lpInterface [O] Destination for the created IQueryAssociations object - * - * RETURNS - * Success: S_OK. lpInterface contains the new object. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * refiid must be equal to IID_IQueryAssociations, or this function will fail. - */ -HRESULT WINAPI AssocCreate(CLSID clsid, REFIID refiid, void **lpInterface) -{ - HRESULT hRet; - IQueryAssociations* lpAssoc; - - TRACE("(%s,%s,%p)\n", debugstr_guid(&clsid), debugstr_guid(refiid), - lpInterface); - - if (!lpInterface) - return E_INVALIDARG; - - *(DWORD*)lpInterface = 0; - - if (!IsEqualGUID(&clsid, &IID_IQueryAssociations)) - return E_NOTIMPL; - - lpAssoc = IQueryAssociations_Constructor(); - - if (!lpAssoc) - return E_OUTOFMEMORY; - - hRet = IQueryAssociations_QueryInterface(lpAssoc, refiid, lpInterface); - IQueryAssociations_Release(lpAssoc); - return hRet; -} - -/************************************************************************* - * AssocQueryKeyW [SHLWAPI.@] - * - * See AssocQueryKeyA. - */ -HRESULT WINAPI AssocQueryKeyW(ASSOCF cfFlags, ASSOCKEY assockey, LPCWSTR pszAssoc, - LPCWSTR pszExtra, HKEY *phkeyOut) -{ - HRESULT hRet; - IQueryAssociations* lpAssoc; - - TRACE("(0x%8lx,0x%8x,%s,%s,%p)\n", cfFlags, assockey, debugstr_w(pszAssoc), - debugstr_w(pszExtra), phkeyOut); - - lpAssoc = IQueryAssociations_Constructor(); - - if (!lpAssoc) - return E_OUTOFMEMORY; - - cfFlags &= SHLWAPI_DEF_ASSOCF; - hRet = IQueryAssociations_Init(lpAssoc, cfFlags, pszAssoc, NULL, NULL); - - if (SUCCEEDED(hRet)) - hRet = IQueryAssociations_GetKey(lpAssoc, cfFlags, assockey, pszExtra, phkeyOut); - - IQueryAssociations_Release(lpAssoc); - return hRet; -} - -/************************************************************************* - * AssocQueryKeyA [SHLWAPI.@] - * - * Get a file association key from the registry. - * - * PARAMS - * cfFlags [I] ASSOCF_ flags from "shlwapi.h" - * assockey [I] Type of key to get - * pszAssoc [I] Key name to search below - * pszExtra [I] Extra information about the key location - * phkeyOut [O] Destination for the association key - * - * RETURNS - * Success: S_OK. phkeyOut contains the key. - * Failure: An HRESULT error code indicating the error. - */ -HRESULT WINAPI AssocQueryKeyA(ASSOCF cfFlags, ASSOCKEY assockey, LPCSTR pszAssoc, - LPCSTR pszExtra, HKEY *phkeyOut) -{ - WCHAR szAssocW[MAX_PATH], *lpszAssocW = NULL; - WCHAR szExtraW[MAX_PATH], *lpszExtraW = NULL; - HRESULT hRet = E_OUTOFMEMORY; - - TRACE("(0x%8lx,0x%8x,%s,%s,%p)\n", cfFlags, assockey, debugstr_a(pszAssoc), - debugstr_a(pszExtra), phkeyOut); - - if (SHLWAPI_ParamAToW(pszAssoc, szAssocW, MAX_PATH, &lpszAssocW) && - SHLWAPI_ParamAToW(pszExtra, szExtraW, MAX_PATH, &lpszExtraW)) - { - hRet = AssocQueryKeyW(cfFlags, assockey, lpszAssocW, lpszExtraW, phkeyOut); - } - - if (lpszAssocW && lpszAssocW != szAssocW) - HeapFree(GetProcessHeap(), 0, lpszAssocW); - - if (lpszExtraW && lpszExtraW != szExtraW) - HeapFree(GetProcessHeap(), 0, lpszExtraW); - - return hRet; -} - -/************************************************************************* - * AssocQueryStringW [SHLWAPI.@] - * - * See AssocQueryStringA. - */ -HRESULT WINAPI AssocQueryStringW(ASSOCF cfFlags, ASSOCSTR str, LPCWSTR pszAssoc, - LPCWSTR pszExtra, LPWSTR pszOut, DWORD *pcchOut) -{ - HRESULT hRet; - IQueryAssociations* lpAssoc; - - TRACE("(0x%8lx,0x%8x,%s,%s,%p,%p)\n", cfFlags, str, debugstr_w(pszAssoc), - debugstr_w(pszExtra), pszOut, pcchOut); - - if (!pcchOut) - return E_INVALIDARG; - - lpAssoc = IQueryAssociations_Constructor(); - - if (!lpAssoc) - return E_OUTOFMEMORY; - - hRet = IQueryAssociations_Init(lpAssoc, cfFlags & SHLWAPI_DEF_ASSOCF, - pszAssoc, NULL, NULL); - - if (SUCCEEDED(hRet)) - hRet = IQueryAssociations_GetString(lpAssoc, cfFlags, str, pszExtra, - pszOut, pcchOut); - - IQueryAssociations_Release(lpAssoc); - return hRet; -} - -/************************************************************************* - * AssocQueryStringA [SHLWAPI.@] - * - * Get a file association string from the registry. - * - * PARAMS - * cfFlags [I] ASSOCF_ flags from "shlwapi.h" - * str [I] Type of string to get (ASSOCSTR enum from "shlwapi.h") - * pszAssoc [I] Key name to search below - * pszExtra [I] Extra information about the string location - * pszOut [O] Destination for the association string - * pcchOut [O] Length of pszOut - * - * RETURNS - * Success: S_OK. pszOut contains the string, pcchOut contains its length. - * Failure: An HRESULT error code indicating the error. - */ -HRESULT WINAPI AssocQueryStringA(ASSOCF cfFlags, ASSOCSTR str, LPCSTR pszAssoc, - LPCSTR pszExtra, LPSTR pszOut, DWORD *pcchOut) -{ - WCHAR szAssocW[MAX_PATH], *lpszAssocW = NULL; - WCHAR szExtraW[MAX_PATH], *lpszExtraW = NULL; - HRESULT hRet = E_OUTOFMEMORY; - - TRACE("(0x%8lx,0x%8x,%s,%s,%p,%p)\n", cfFlags, str, debugstr_a(pszAssoc), - debugstr_a(pszExtra), pszOut, pcchOut); - - if (!pcchOut) - hRet = E_INVALIDARG; - else if (SHLWAPI_ParamAToW(pszAssoc, szAssocW, MAX_PATH, &lpszAssocW) && - SHLWAPI_ParamAToW(pszExtra, szExtraW, MAX_PATH, &lpszExtraW)) - { - WCHAR szReturnW[MAX_PATH], *lpszReturnW = szReturnW; - DWORD dwLenOut = *pcchOut; - - if (dwLenOut >= MAX_PATH) - lpszReturnW = HeapAlloc(GetProcessHeap(), 0, - (dwLenOut + 1) * sizeof(WCHAR)); - - if (!lpszReturnW) - hRet = E_OUTOFMEMORY; - else - { - hRet = AssocQueryStringW(cfFlags, str, lpszAssocW, lpszExtraW, - lpszReturnW, &dwLenOut); - - if (SUCCEEDED(hRet)) - WideCharToMultiByte(CP_ACP,0,szReturnW,-1,pszOut,dwLenOut,0,0); - *pcchOut = dwLenOut; - - if (lpszReturnW && lpszReturnW != szReturnW) - HeapFree(GetProcessHeap(), 0, lpszReturnW); - } - } - - if (lpszAssocW && lpszAssocW != szAssocW) - HeapFree(GetProcessHeap(), 0, lpszAssocW); - if (lpszExtraW && lpszExtraW != szExtraW) - HeapFree(GetProcessHeap(), 0, lpszExtraW); - return hRet; -} - -/************************************************************************* - * AssocQueryStringByKeyW [SHLWAPI.@] - * - * See AssocQueryStringByKeyA. - */ -HRESULT WINAPI AssocQueryStringByKeyW(ASSOCF cfFlags, ASSOCSTR str, HKEY hkAssoc, - LPCWSTR pszExtra, LPWSTR pszOut, - DWORD *pcchOut) -{ - HRESULT hRet; - IQueryAssociations* lpAssoc; - - TRACE("(0x%8lx,0x%8x,%p,%s,%p,%p)\n", cfFlags, str, hkAssoc, - debugstr_w(pszExtra), pszOut, pcchOut); - - lpAssoc = IQueryAssociations_Constructor(); - - if (!lpAssoc) - return E_OUTOFMEMORY; - - cfFlags &= SHLWAPI_DEF_ASSOCF; - hRet = IQueryAssociations_Init(lpAssoc, cfFlags, 0, hkAssoc, NULL); - - if (SUCCEEDED(hRet)) - hRet = IQueryAssociations_GetString(lpAssoc, cfFlags, str, pszExtra, - pszOut, pcchOut); - - IQueryAssociations_Release(lpAssoc); - return hRet; -} - -/************************************************************************* - * AssocQueryStringByKeyA [SHLWAPI.@] - * - * Get a file association string from the registry, given a starting key. - * - * PARAMS - * cfFlags [I] ASSOCF_ flags from "shlwapi.h" - * str [I] Type of string to get - * hkAssoc [I] Key to search below - * pszExtra [I] Extra information about the string location - * pszOut [O] Destination for the association string - * pcchOut [O] Length of pszOut - * - * RETURNS - * Success: S_OK. pszOut contains the string, pcchOut contains its length. - * Failure: An HRESULT error code indicating the error. - */ -HRESULT WINAPI AssocQueryStringByKeyA(ASSOCF cfFlags, ASSOCSTR str, HKEY hkAssoc, - LPCSTR pszExtra, LPSTR pszOut, - DWORD *pcchOut) -{ - WCHAR szExtraW[MAX_PATH], *lpszExtraW; - WCHAR szReturnW[MAX_PATH], *lpszReturnW = szReturnW; - HRESULT hRet = E_OUTOFMEMORY; - - TRACE("(0x%8lx,0x%8x,%p,%s,%p,%p)\n", cfFlags, str, hkAssoc, - debugstr_a(pszExtra), pszOut, pcchOut); - - if (!pcchOut) - hRet = E_INVALIDARG; - else if (SHLWAPI_ParamAToW(pszExtra, szExtraW, MAX_PATH, &lpszExtraW)) - { - DWORD dwLenOut = *pcchOut; - if (dwLenOut >= MAX_PATH) - lpszReturnW = HeapAlloc(GetProcessHeap(), 0, - (dwLenOut + 1) * sizeof(WCHAR)); - - if (lpszReturnW) - { - hRet = AssocQueryStringByKeyW(cfFlags, str, hkAssoc, lpszExtraW, - lpszReturnW, &dwLenOut); - - if (SUCCEEDED(hRet)) - WideCharToMultiByte(CP_ACP,0,szReturnW,-1,pszOut,dwLenOut,0,0); - *pcchOut = dwLenOut; - - if (lpszReturnW != szReturnW) - HeapFree(GetProcessHeap(), 0, lpszReturnW); - } - } - - if (lpszExtraW && lpszExtraW != szExtraW) - HeapFree(GetProcessHeap(), 0, lpszExtraW); - return hRet; -} - - -/************************************************************************** - * AssocIsDangerous (SHLWAPI.@) - * - * Determine if a file association is dangerous (potentially malware). - * - * PARAMS - * lpszAssoc [I] Name of file or file extension to check. - * - * RETURNS - * TRUE, if lpszAssoc may potentially be malware (executable), - * FALSE, Otherwise. - */ -BOOL WINAPI AssocIsDangerous(LPCWSTR lpszAssoc) -{ - FIXME("%s\n", debugstr_w(lpszAssoc)); - return FALSE; -} - -/************************************************************************** - * IQueryAssociations_QueryInterface {SHLWAPI} - * - * See IUnknown_QueryInterface. - */ -static HRESULT WINAPI IQueryAssociations_fnQueryInterface( - IQueryAssociations* iface, - REFIID riid, - LPVOID *ppvObj) -{ - IQueryAssociationsImpl *This = (IQueryAssociationsImpl *)iface; - - TRACE("(%p,%s,%p)\n",This, debugstr_guid(riid), ppvObj); - - *ppvObj = NULL; - - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IQueryAssociations)) - { - *ppvObj = (IQueryAssociations*)This; - - IQueryAssociations_AddRef((IQueryAssociations*)*ppvObj); - TRACE("Returning IQueryAssociations (%p)\n", *ppvObj); - return S_OK; - } - TRACE("Returning E_NOINTERFACE\n"); - return E_NOINTERFACE; -} - -/************************************************************************** - * IQueryAssociations_AddRef {SHLWAPI} - * - * See IUnknown_AddRef. - */ -static ULONG WINAPI IQueryAssociations_fnAddRef(IQueryAssociations *iface) -{ - IQueryAssociationsImpl *This = (IQueryAssociationsImpl *)iface; - ULONG refCount = InterlockedIncrement(&This->ref); - - TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1); - - return refCount; -} - -/************************************************************************** - * IQueryAssociations_Release {SHLWAPI} - * - * See IUnknown_Release. - */ -static ULONG WINAPI IQueryAssociations_fnRelease(IQueryAssociations *iface) -{ - IQueryAssociationsImpl *This = (IQueryAssociationsImpl *)iface; - ULONG refCount = InterlockedDecrement(&This->ref); - - TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1); - - if (!refCount) - { - TRACE("Destroying IQueryAssociations (%p)\n", This); - HeapFree(GetProcessHeap(), 0, This); - } - - return refCount; -} - -/************************************************************************** - * IQueryAssociations_Init {SHLWAPI} - * - * Initialise an IQueryAssociations object. - * - * PARAMS - * iface [I] IQueryAssociations interface to initialise - * cfFlags [I] ASSOCF_ flags from "shlwapi.h" - * pszAssoc [I] String for the root key name, or NULL if hkProgid is given - * hkeyProgid [I] Handle for the root key, or NULL if pszAssoc is given - * hWnd [I] Reserved, must be NULL. - * - * RETURNS - * Success: S_OK. iface is initialised with the parameters given. - * Failure: An HRESULT error code indicating the error. - */ -static HRESULT WINAPI IQueryAssociations_fnInit( - IQueryAssociations *iface, - ASSOCF cfFlags, - LPCWSTR pszAssoc, - HKEY hkeyProgid, - HWND hWnd) -{ - static const WCHAR szProgID[] = {'P','r','o','g','I','D',0}; - IQueryAssociationsImpl *This = (IQueryAssociationsImpl *)iface; - HRESULT hr; - - TRACE("(%p)->(%ld,%s,%p,%p)\n", iface, - cfFlags, - debugstr_w(pszAssoc), - hkeyProgid, - hWnd); - if (hWnd != NULL) - FIXME("hwnd != NULL not supported\n"); - if (cfFlags != 0) - FIXME("unsupported flags: %lx\n", cfFlags); - if (pszAssoc != NULL) - { - hr = RegOpenKeyExW(HKEY_CLASSES_ROOT, - pszAssoc, - 0, - KEY_READ, - &This->hkeySource); - if (FAILED(hr)) - return HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION); - /* if this is not a prog id */ - if ((*pszAssoc == '.') || (*pszAssoc == '{')) - { - hr = RegOpenKeyExW(This->hkeySource, - szProgID, - 0, - KEY_READ, - &This->hkeyProgID); - if (FAILED(hr)) - FIXME("Don't know what to return\n"); - } - else - This->hkeyProgID = This->hkeySource; - return S_OK; - } - else if (hkeyProgid != NULL) - { - This->hkeyProgID = hkeyProgid; - return S_OK; - } - else - return E_FAIL; -} - -/************************************************************************** - * IQueryAssociations_GetString {SHLWAPI} - * - * Get a file association string from the registry. - * - * PARAMS - * iface [I] IQueryAssociations interface to query - * cfFlags [I] ASSOCF_ flags from "shlwapi.h" - * str [I] Type of string to get (ASSOCSTR enum from "shlwapi.h") - * pszExtra [I] Extra information about the string location - * pszOut [O] Destination for the association string - * pcchOut [I/O] Length of pszOut - * - * RETURNS - * Success: S_OK. pszOut contains the string, pcchOut contains its length. - * Failure: An HRESULT error code indicating the error. - */ -static HRESULT WINAPI IQueryAssociations_fnGetString( - IQueryAssociations *iface, - ASSOCF cfFlags, - ASSOCSTR str, - LPCWSTR pszExtra, - LPWSTR pszOut, - DWORD *pcchOut) -{ - IQueryAssociationsImpl *This = (IQueryAssociationsImpl *)iface; - - FIXME("(%p,0x%8lx,0x%8x,%s,%p,%p)-stub!\n", This, cfFlags, str, - debugstr_w(pszExtra), pszOut, pcchOut); - return E_NOTIMPL; -} - -/************************************************************************** - * IQueryAssociations_GetKey {SHLWAPI} - * - * Get a file association key from the registry. - * - * PARAMS - * iface [I] IQueryAssociations interface to query - * cfFlags [I] ASSOCF_ flags from "shlwapi.h" - * assockey [I] Type of key to get (ASSOCKEY enum from "shlwapi.h") - * pszExtra [I] Extra information about the key location - * phkeyOut [O] Destination for the association key - * - * RETURNS - * Success: S_OK. phkeyOut contains a handle to the key. - * Failure: An HRESULT error code indicating the error. - */ -static HRESULT WINAPI IQueryAssociations_fnGetKey( - IQueryAssociations *iface, - ASSOCF cfFlags, - ASSOCKEY assockey, - LPCWSTR pszExtra, - HKEY *phkeyOut) -{ - IQueryAssociationsImpl *This = (IQueryAssociationsImpl *)iface; - - FIXME("(%p,0x%8lx,0x%8x,%s,%p)-stub!\n", This, cfFlags, assockey, - debugstr_w(pszExtra), phkeyOut); - return E_NOTIMPL; -} - -/************************************************************************** - * IQueryAssociations_GetData {SHLWAPI} - * - * Get the data for a file association key from the registry. - * - * PARAMS - * iface [I] IQueryAssociations interface to query - * cfFlags [I] ASSOCF_ flags from "shlwapi.h" - * assocdata [I] Type of data to get (ASSOCDATA enum from "shlwapi.h") - * pszExtra [I] Extra information about the data location - * pvOut [O] Destination for the association key - * pcbOut [I/O] Size of pvOut - * - * RETURNS - * Success: S_OK. pszOut contains the data, pcbOut contains its length. - * Failure: An HRESULT error code indicating the error. - */ -static HRESULT WINAPI IQueryAssociations_fnGetData( - IQueryAssociations *iface, - ASSOCF cfFlags, - ASSOCDATA assocdata, - LPCWSTR pszExtra, - LPVOID pvOut, - DWORD *pcbOut) -{ - IQueryAssociationsImpl *This = (IQueryAssociationsImpl *)iface; - - FIXME("(%p,0x%8lx,0x%8x,%s,%p,%p)-stub!\n", This, cfFlags, assocdata, - debugstr_w(pszExtra), pvOut, pcbOut); - return E_NOTIMPL; -} - -/************************************************************************** - * IQueryAssociations_GetEnum {SHLWAPI} - * - * Not yet implemented in native Win32. - * - * PARAMS - * iface [I] IQueryAssociations interface to query - * cfFlags [I] ASSOCF_ flags from "shlwapi.h" - * assocenum [I] Type of enum to get (ASSOCENUM enum from "shlwapi.h") - * pszExtra [I] Extra information about the enum location - * riid [I] REFIID to look for - * ppvOut [O] Destination for the interface. - * - * RETURNS - * Success: S_OK. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * Presumably this function returns an enumerator object. - */ -static HRESULT WINAPI IQueryAssociations_fnGetEnum( - IQueryAssociations *iface, - ASSOCF cfFlags, - ASSOCENUM assocenum, - LPCWSTR pszExtra, - REFIID riid, - LPVOID *ppvOut) -{ - IQueryAssociationsImpl *This = (IQueryAssociationsImpl *)iface; - - FIXME("(%p,0x%8lx,0x%8x,%s,%s,%p)-stub!\n", This, cfFlags, assocenum, - debugstr_w(pszExtra), debugstr_guid(riid), ppvOut); - return E_NOTIMPL; -} - -static struct IQueryAssociationsVtbl IQueryAssociations_vtbl = -{ - IQueryAssociations_fnQueryInterface, - IQueryAssociations_fnAddRef, - IQueryAssociations_fnRelease, - IQueryAssociations_fnInit, - IQueryAssociations_fnGetString, - IQueryAssociations_fnGetKey, - IQueryAssociations_fnGetData, - IQueryAssociations_fnGetEnum -}; +/* + * IQueryAssociations object and helper functions + * + * Copyright 2002 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winreg.h" +#include "objbase.h" +#include "shlguid.h" +#include "shlwapi.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/************************************************************************** + * IQueryAssociations {SHLWAPI} + * + * DESCRIPTION + * This object provides a layer of abstraction over the system registry in + * order to simplify the process of parsing associations between files. + * Associations in this context means the registry entries that link (for + * example) the extension of a file with its description, list of + * applications to open the file with, and actions that can be performed on it + * (the shell displays such information in the context menu of explorer + * when you right-click on a file). + * + * HELPERS + * You can use this object transparently by calling the helper functions + * AssocQueryKeyA(), AssocQueryStringA() and AssocQueryStringByKeyA(). These + * create an IQueryAssociations object, perform the requested actions + * and then dispose of the object. Alternatively, you can create an instance + * of the object using AssocCreate() and call the following methods on it: + * + * METHODS + */ + +/* Default IQueryAssociations::Init() flags */ +#define SHLWAPI_DEF_ASSOCF (ASSOCF_INIT_BYEXENAME|ASSOCF_INIT_DEFAULTTOSTAR| \ + ASSOCF_INIT_DEFAULTTOFOLDER) + +typedef struct +{ + IQueryAssociationsVtbl *lpVtbl; + LONG ref; + HKEY hkeySource; + HKEY hkeyProgID; +} IQueryAssociationsImpl; + +static struct IQueryAssociationsVtbl IQueryAssociations_vtbl; + +/************************************************************************** + * IQueryAssociations_Constructor [internal] + * + * Construct a new IQueryAssociations object. + */ +static IQueryAssociations* IQueryAssociations_Constructor(void) +{ + IQueryAssociationsImpl* iface; + + iface = HeapAlloc(GetProcessHeap(),0,sizeof(IQueryAssociationsImpl)); + iface->lpVtbl = &IQueryAssociations_vtbl; + iface->ref = 1; + iface->hkeySource = NULL; + iface->hkeyProgID = NULL; + + TRACE("Returning IQueryAssociations* %p\n", iface); + return (IQueryAssociations*)iface; +} + +/************************************************************************* + * SHLWAPI_ParamAToW + * + * Internal helper function: Convert ASCII parameter to Unicode. + */ +static BOOL SHLWAPI_ParamAToW(LPCSTR lpszParam, LPWSTR lpszBuff, DWORD dwLen, + LPWSTR* lpszOut) +{ + if (lpszParam) + { + DWORD dwStrLen = MultiByteToWideChar(CP_ACP, 0, lpszParam, -1, NULL, 0); + + if (dwStrLen < dwLen) + { + *lpszOut = lpszBuff; /* Use Buffer, it is big enough */ + } + else + { + /* Create a new buffer big enough for the string */ + *lpszOut = HeapAlloc(GetProcessHeap(), 0, + dwStrLen * sizeof(WCHAR)); + if (!*lpszOut) + return FALSE; + } + MultiByteToWideChar(CP_ACP, 0, lpszParam, -1, *lpszOut, dwStrLen); + } + else + *lpszOut = NULL; + return TRUE; +} + +/************************************************************************* + * AssocCreate [SHLWAPI.@] + * + * Create a new IQueryAssociations object. + * + * PARAMS + * clsid [I] CLSID of object + * refiid [I] REFIID of interface + * lpInterface [O] Destination for the created IQueryAssociations object + * + * RETURNS + * Success: S_OK. lpInterface contains the new object. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * refiid must be equal to IID_IQueryAssociations, or this function will fail. + */ +HRESULT WINAPI AssocCreate(CLSID clsid, REFIID refiid, void **lpInterface) +{ + HRESULT hRet; + IQueryAssociations* lpAssoc; + + TRACE("(%s,%s,%p)\n", debugstr_guid(&clsid), debugstr_guid(refiid), + lpInterface); + + if (!lpInterface) + return E_INVALIDARG; + + *(DWORD*)lpInterface = 0; + + if (!IsEqualGUID(&clsid, &IID_IQueryAssociations)) + return E_NOTIMPL; + + lpAssoc = IQueryAssociations_Constructor(); + + if (!lpAssoc) + return E_OUTOFMEMORY; + + hRet = IQueryAssociations_QueryInterface(lpAssoc, refiid, lpInterface); + IQueryAssociations_Release(lpAssoc); + return hRet; +} + +/************************************************************************* + * AssocQueryKeyW [SHLWAPI.@] + * + * See AssocQueryKeyA. + */ +HRESULT WINAPI AssocQueryKeyW(ASSOCF cfFlags, ASSOCKEY assockey, LPCWSTR pszAssoc, + LPCWSTR pszExtra, HKEY *phkeyOut) +{ + HRESULT hRet; + IQueryAssociations* lpAssoc; + + TRACE("(0x%8lx,0x%8x,%s,%s,%p)\n", cfFlags, assockey, debugstr_w(pszAssoc), + debugstr_w(pszExtra), phkeyOut); + + lpAssoc = IQueryAssociations_Constructor(); + + if (!lpAssoc) + return E_OUTOFMEMORY; + + cfFlags &= SHLWAPI_DEF_ASSOCF; + hRet = IQueryAssociations_Init(lpAssoc, cfFlags, pszAssoc, NULL, NULL); + + if (SUCCEEDED(hRet)) + hRet = IQueryAssociations_GetKey(lpAssoc, cfFlags, assockey, pszExtra, phkeyOut); + + IQueryAssociations_Release(lpAssoc); + return hRet; +} + +/************************************************************************* + * AssocQueryKeyA [SHLWAPI.@] + * + * Get a file association key from the registry. + * + * PARAMS + * cfFlags [I] ASSOCF_ flags from "shlwapi.h" + * assockey [I] Type of key to get + * pszAssoc [I] Key name to search below + * pszExtra [I] Extra information about the key location + * phkeyOut [O] Destination for the association key + * + * RETURNS + * Success: S_OK. phkeyOut contains the key. + * Failure: An HRESULT error code indicating the error. + */ +HRESULT WINAPI AssocQueryKeyA(ASSOCF cfFlags, ASSOCKEY assockey, LPCSTR pszAssoc, + LPCSTR pszExtra, HKEY *phkeyOut) +{ + WCHAR szAssocW[MAX_PATH], *lpszAssocW = NULL; + WCHAR szExtraW[MAX_PATH], *lpszExtraW = NULL; + HRESULT hRet = E_OUTOFMEMORY; + + TRACE("(0x%8lx,0x%8x,%s,%s,%p)\n", cfFlags, assockey, debugstr_a(pszAssoc), + debugstr_a(pszExtra), phkeyOut); + + if (SHLWAPI_ParamAToW(pszAssoc, szAssocW, MAX_PATH, &lpszAssocW) && + SHLWAPI_ParamAToW(pszExtra, szExtraW, MAX_PATH, &lpszExtraW)) + { + hRet = AssocQueryKeyW(cfFlags, assockey, lpszAssocW, lpszExtraW, phkeyOut); + } + + if (lpszAssocW && lpszAssocW != szAssocW) + HeapFree(GetProcessHeap(), 0, lpszAssocW); + + if (lpszExtraW && lpszExtraW != szExtraW) + HeapFree(GetProcessHeap(), 0, lpszExtraW); + + return hRet; +} + +/************************************************************************* + * AssocQueryStringW [SHLWAPI.@] + * + * See AssocQueryStringA. + */ +HRESULT WINAPI AssocQueryStringW(ASSOCF cfFlags, ASSOCSTR str, LPCWSTR pszAssoc, + LPCWSTR pszExtra, LPWSTR pszOut, DWORD *pcchOut) +{ + HRESULT hRet; + IQueryAssociations* lpAssoc; + + TRACE("(0x%8lx,0x%8x,%s,%s,%p,%p)\n", cfFlags, str, debugstr_w(pszAssoc), + debugstr_w(pszExtra), pszOut, pcchOut); + + if (!pcchOut) + return E_INVALIDARG; + + lpAssoc = IQueryAssociations_Constructor(); + + if (!lpAssoc) + return E_OUTOFMEMORY; + + hRet = IQueryAssociations_Init(lpAssoc, cfFlags & SHLWAPI_DEF_ASSOCF, + pszAssoc, NULL, NULL); + + if (SUCCEEDED(hRet)) + hRet = IQueryAssociations_GetString(lpAssoc, cfFlags, str, pszExtra, + pszOut, pcchOut); + + IQueryAssociations_Release(lpAssoc); + return hRet; +} + +/************************************************************************* + * AssocQueryStringA [SHLWAPI.@] + * + * Get a file association string from the registry. + * + * PARAMS + * cfFlags [I] ASSOCF_ flags from "shlwapi.h" + * str [I] Type of string to get (ASSOCSTR enum from "shlwapi.h") + * pszAssoc [I] Key name to search below + * pszExtra [I] Extra information about the string location + * pszOut [O] Destination for the association string + * pcchOut [O] Length of pszOut + * + * RETURNS + * Success: S_OK. pszOut contains the string, pcchOut contains its length. + * Failure: An HRESULT error code indicating the error. + */ +HRESULT WINAPI AssocQueryStringA(ASSOCF cfFlags, ASSOCSTR str, LPCSTR pszAssoc, + LPCSTR pszExtra, LPSTR pszOut, DWORD *pcchOut) +{ + WCHAR szAssocW[MAX_PATH], *lpszAssocW = NULL; + WCHAR szExtraW[MAX_PATH], *lpszExtraW = NULL; + HRESULT hRet = E_OUTOFMEMORY; + + TRACE("(0x%8lx,0x%8x,%s,%s,%p,%p)\n", cfFlags, str, debugstr_a(pszAssoc), + debugstr_a(pszExtra), pszOut, pcchOut); + + if (!pcchOut) + hRet = E_INVALIDARG; + else if (SHLWAPI_ParamAToW(pszAssoc, szAssocW, MAX_PATH, &lpszAssocW) && + SHLWAPI_ParamAToW(pszExtra, szExtraW, MAX_PATH, &lpszExtraW)) + { + WCHAR szReturnW[MAX_PATH], *lpszReturnW = szReturnW; + DWORD dwLenOut = *pcchOut; + + if (dwLenOut >= MAX_PATH) + lpszReturnW = HeapAlloc(GetProcessHeap(), 0, + (dwLenOut + 1) * sizeof(WCHAR)); + + if (!lpszReturnW) + hRet = E_OUTOFMEMORY; + else + { + hRet = AssocQueryStringW(cfFlags, str, lpszAssocW, lpszExtraW, + lpszReturnW, &dwLenOut); + + if (SUCCEEDED(hRet)) + WideCharToMultiByte(CP_ACP,0,szReturnW,-1,pszOut,dwLenOut,0,0); + *pcchOut = dwLenOut; + + if (lpszReturnW && lpszReturnW != szReturnW) + HeapFree(GetProcessHeap(), 0, lpszReturnW); + } + } + + if (lpszAssocW && lpszAssocW != szAssocW) + HeapFree(GetProcessHeap(), 0, lpszAssocW); + if (lpszExtraW && lpszExtraW != szExtraW) + HeapFree(GetProcessHeap(), 0, lpszExtraW); + return hRet; +} + +/************************************************************************* + * AssocQueryStringByKeyW [SHLWAPI.@] + * + * See AssocQueryStringByKeyA. + */ +HRESULT WINAPI AssocQueryStringByKeyW(ASSOCF cfFlags, ASSOCSTR str, HKEY hkAssoc, + LPCWSTR pszExtra, LPWSTR pszOut, + DWORD *pcchOut) +{ + HRESULT hRet; + IQueryAssociations* lpAssoc; + + TRACE("(0x%8lx,0x%8x,%p,%s,%p,%p)\n", cfFlags, str, hkAssoc, + debugstr_w(pszExtra), pszOut, pcchOut); + + lpAssoc = IQueryAssociations_Constructor(); + + if (!lpAssoc) + return E_OUTOFMEMORY; + + cfFlags &= SHLWAPI_DEF_ASSOCF; + hRet = IQueryAssociations_Init(lpAssoc, cfFlags, 0, hkAssoc, NULL); + + if (SUCCEEDED(hRet)) + hRet = IQueryAssociations_GetString(lpAssoc, cfFlags, str, pszExtra, + pszOut, pcchOut); + + IQueryAssociations_Release(lpAssoc); + return hRet; +} + +/************************************************************************* + * AssocQueryStringByKeyA [SHLWAPI.@] + * + * Get a file association string from the registry, given a starting key. + * + * PARAMS + * cfFlags [I] ASSOCF_ flags from "shlwapi.h" + * str [I] Type of string to get + * hkAssoc [I] Key to search below + * pszExtra [I] Extra information about the string location + * pszOut [O] Destination for the association string + * pcchOut [O] Length of pszOut + * + * RETURNS + * Success: S_OK. pszOut contains the string, pcchOut contains its length. + * Failure: An HRESULT error code indicating the error. + */ +HRESULT WINAPI AssocQueryStringByKeyA(ASSOCF cfFlags, ASSOCSTR str, HKEY hkAssoc, + LPCSTR pszExtra, LPSTR pszOut, + DWORD *pcchOut) +{ + WCHAR szExtraW[MAX_PATH], *lpszExtraW; + WCHAR szReturnW[MAX_PATH], *lpszReturnW = szReturnW; + HRESULT hRet = E_OUTOFMEMORY; + + TRACE("(0x%8lx,0x%8x,%p,%s,%p,%p)\n", cfFlags, str, hkAssoc, + debugstr_a(pszExtra), pszOut, pcchOut); + + if (!pcchOut) + hRet = E_INVALIDARG; + else if (SHLWAPI_ParamAToW(pszExtra, szExtraW, MAX_PATH, &lpszExtraW)) + { + DWORD dwLenOut = *pcchOut; + if (dwLenOut >= MAX_PATH) + lpszReturnW = HeapAlloc(GetProcessHeap(), 0, + (dwLenOut + 1) * sizeof(WCHAR)); + + if (lpszReturnW) + { + hRet = AssocQueryStringByKeyW(cfFlags, str, hkAssoc, lpszExtraW, + lpszReturnW, &dwLenOut); + + if (SUCCEEDED(hRet)) + WideCharToMultiByte(CP_ACP,0,szReturnW,-1,pszOut,dwLenOut,0,0); + *pcchOut = dwLenOut; + + if (lpszReturnW != szReturnW) + HeapFree(GetProcessHeap(), 0, lpszReturnW); + } + } + + if (lpszExtraW && lpszExtraW != szExtraW) + HeapFree(GetProcessHeap(), 0, lpszExtraW); + return hRet; +} + + +/************************************************************************** + * AssocIsDangerous (SHLWAPI.@) + * + * Determine if a file association is dangerous (potentially malware). + * + * PARAMS + * lpszAssoc [I] Name of file or file extension to check. + * + * RETURNS + * TRUE, if lpszAssoc may potentially be malware (executable), + * FALSE, Otherwise. + */ +BOOL WINAPI AssocIsDangerous(LPCWSTR lpszAssoc) +{ + FIXME("%s\n", debugstr_w(lpszAssoc)); + return FALSE; +} + +/************************************************************************** + * IQueryAssociations_QueryInterface {SHLWAPI} + * + * See IUnknown_QueryInterface. + */ +static HRESULT WINAPI IQueryAssociations_fnQueryInterface( + IQueryAssociations* iface, + REFIID riid, + LPVOID *ppvObj) +{ + IQueryAssociationsImpl *This = (IQueryAssociationsImpl *)iface; + + TRACE("(%p,%s,%p)\n",This, debugstr_guid(riid), ppvObj); + + *ppvObj = NULL; + + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IQueryAssociations)) + { + *ppvObj = (IQueryAssociations*)This; + + IQueryAssociations_AddRef((IQueryAssociations*)*ppvObj); + TRACE("Returning IQueryAssociations (%p)\n", *ppvObj); + return S_OK; + } + TRACE("Returning E_NOINTERFACE\n"); + return E_NOINTERFACE; +} + +/************************************************************************** + * IQueryAssociations_AddRef {SHLWAPI} + * + * See IUnknown_AddRef. + */ +static ULONG WINAPI IQueryAssociations_fnAddRef(IQueryAssociations *iface) +{ + IQueryAssociationsImpl *This = (IQueryAssociationsImpl *)iface; + ULONG refCount = InterlockedIncrement(&This->ref); + + TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1); + + return refCount; +} + +/************************************************************************** + * IQueryAssociations_Release {SHLWAPI} + * + * See IUnknown_Release. + */ +static ULONG WINAPI IQueryAssociations_fnRelease(IQueryAssociations *iface) +{ + IQueryAssociationsImpl *This = (IQueryAssociationsImpl *)iface; + ULONG refCount = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1); + + if (!refCount) + { + TRACE("Destroying IQueryAssociations (%p)\n", This); + HeapFree(GetProcessHeap(), 0, This); + } + + return refCount; +} + +/************************************************************************** + * IQueryAssociations_Init {SHLWAPI} + * + * Initialise an IQueryAssociations object. + * + * PARAMS + * iface [I] IQueryAssociations interface to initialise + * cfFlags [I] ASSOCF_ flags from "shlwapi.h" + * pszAssoc [I] String for the root key name, or NULL if hkProgid is given + * hkeyProgid [I] Handle for the root key, or NULL if pszAssoc is given + * hWnd [I] Reserved, must be NULL. + * + * RETURNS + * Success: S_OK. iface is initialised with the parameters given. + * Failure: An HRESULT error code indicating the error. + */ +static HRESULT WINAPI IQueryAssociations_fnInit( + IQueryAssociations *iface, + ASSOCF cfFlags, + LPCWSTR pszAssoc, + HKEY hkeyProgid, + HWND hWnd) +{ + static const WCHAR szProgID[] = {'P','r','o','g','I','D',0}; + IQueryAssociationsImpl *This = (IQueryAssociationsImpl *)iface; + HRESULT hr; + + TRACE("(%p)->(%ld,%s,%p,%p)\n", iface, + cfFlags, + debugstr_w(pszAssoc), + hkeyProgid, + hWnd); + if (hWnd != NULL) + FIXME("hwnd != NULL not supported\n"); + if (cfFlags != 0) + FIXME("unsupported flags: %lx\n", cfFlags); + if (pszAssoc != NULL) + { + hr = RegOpenKeyExW(HKEY_CLASSES_ROOT, + pszAssoc, + 0, + KEY_READ, + &This->hkeySource); + if (FAILED(hr)) + return HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION); + /* if this is not a prog id */ + if ((*pszAssoc == '.') || (*pszAssoc == '{')) + { + hr = RegOpenKeyExW(This->hkeySource, + szProgID, + 0, + KEY_READ, + &This->hkeyProgID); + if (FAILED(hr)) + FIXME("Don't know what to return\n"); + } + else + This->hkeyProgID = This->hkeySource; + return S_OK; + } + else if (hkeyProgid != NULL) + { + This->hkeyProgID = hkeyProgid; + return S_OK; + } + else + return E_FAIL; +} + +/************************************************************************** + * IQueryAssociations_GetString {SHLWAPI} + * + * Get a file association string from the registry. + * + * PARAMS + * iface [I] IQueryAssociations interface to query + * cfFlags [I] ASSOCF_ flags from "shlwapi.h" + * str [I] Type of string to get (ASSOCSTR enum from "shlwapi.h") + * pszExtra [I] Extra information about the string location + * pszOut [O] Destination for the association string + * pcchOut [I/O] Length of pszOut + * + * RETURNS + * Success: S_OK. pszOut contains the string, pcchOut contains its length. + * Failure: An HRESULT error code indicating the error. + */ +static HRESULT WINAPI IQueryAssociations_fnGetString( + IQueryAssociations *iface, + ASSOCF cfFlags, + ASSOCSTR str, + LPCWSTR pszExtra, + LPWSTR pszOut, + DWORD *pcchOut) +{ + IQueryAssociationsImpl *This = (IQueryAssociationsImpl *)iface; + + FIXME("(%p,0x%8lx,0x%8x,%s,%p,%p)-stub!\n", This, cfFlags, str, + debugstr_w(pszExtra), pszOut, pcchOut); + return E_NOTIMPL; +} + +/************************************************************************** + * IQueryAssociations_GetKey {SHLWAPI} + * + * Get a file association key from the registry. + * + * PARAMS + * iface [I] IQueryAssociations interface to query + * cfFlags [I] ASSOCF_ flags from "shlwapi.h" + * assockey [I] Type of key to get (ASSOCKEY enum from "shlwapi.h") + * pszExtra [I] Extra information about the key location + * phkeyOut [O] Destination for the association key + * + * RETURNS + * Success: S_OK. phkeyOut contains a handle to the key. + * Failure: An HRESULT error code indicating the error. + */ +static HRESULT WINAPI IQueryAssociations_fnGetKey( + IQueryAssociations *iface, + ASSOCF cfFlags, + ASSOCKEY assockey, + LPCWSTR pszExtra, + HKEY *phkeyOut) +{ + IQueryAssociationsImpl *This = (IQueryAssociationsImpl *)iface; + + FIXME("(%p,0x%8lx,0x%8x,%s,%p)-stub!\n", This, cfFlags, assockey, + debugstr_w(pszExtra), phkeyOut); + return E_NOTIMPL; +} + +/************************************************************************** + * IQueryAssociations_GetData {SHLWAPI} + * + * Get the data for a file association key from the registry. + * + * PARAMS + * iface [I] IQueryAssociations interface to query + * cfFlags [I] ASSOCF_ flags from "shlwapi.h" + * assocdata [I] Type of data to get (ASSOCDATA enum from "shlwapi.h") + * pszExtra [I] Extra information about the data location + * pvOut [O] Destination for the association key + * pcbOut [I/O] Size of pvOut + * + * RETURNS + * Success: S_OK. pszOut contains the data, pcbOut contains its length. + * Failure: An HRESULT error code indicating the error. + */ +static HRESULT WINAPI IQueryAssociations_fnGetData( + IQueryAssociations *iface, + ASSOCF cfFlags, + ASSOCDATA assocdata, + LPCWSTR pszExtra, + LPVOID pvOut, + DWORD *pcbOut) +{ + IQueryAssociationsImpl *This = (IQueryAssociationsImpl *)iface; + + FIXME("(%p,0x%8lx,0x%8x,%s,%p,%p)-stub!\n", This, cfFlags, assocdata, + debugstr_w(pszExtra), pvOut, pcbOut); + return E_NOTIMPL; +} + +/************************************************************************** + * IQueryAssociations_GetEnum {SHLWAPI} + * + * Not yet implemented in native Win32. + * + * PARAMS + * iface [I] IQueryAssociations interface to query + * cfFlags [I] ASSOCF_ flags from "shlwapi.h" + * assocenum [I] Type of enum to get (ASSOCENUM enum from "shlwapi.h") + * pszExtra [I] Extra information about the enum location + * riid [I] REFIID to look for + * ppvOut [O] Destination for the interface. + * + * RETURNS + * Success: S_OK. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * Presumably this function returns an enumerator object. + */ +static HRESULT WINAPI IQueryAssociations_fnGetEnum( + IQueryAssociations *iface, + ASSOCF cfFlags, + ASSOCENUM assocenum, + LPCWSTR pszExtra, + REFIID riid, + LPVOID *ppvOut) +{ + IQueryAssociationsImpl *This = (IQueryAssociationsImpl *)iface; + + FIXME("(%p,0x%8lx,0x%8x,%s,%s,%p)-stub!\n", This, cfFlags, assocenum, + debugstr_w(pszExtra), debugstr_guid(riid), ppvOut); + return E_NOTIMPL; +} + +static struct IQueryAssociationsVtbl IQueryAssociations_vtbl = +{ + IQueryAssociations_fnQueryInterface, + IQueryAssociations_fnAddRef, + IQueryAssociations_fnRelease, + IQueryAssociations_fnInit, + IQueryAssociations_fnGetString, + IQueryAssociations_fnGetKey, + IQueryAssociations_fnGetData, + IQueryAssociations_fnGetEnum +}; diff --git a/reactos/lib/shlwapi/clist.c b/reactos/lib/shlwapi/clist.c index 566c10fb9ee..c5312de2348 100644 --- a/reactos/lib/shlwapi/clist.c +++ b/reactos/lib/shlwapi/clist.c @@ -1,455 +1,455 @@ -/* - * SHLWAPI DataBlock List functions - * - * Copyright 2002 Jon Griffiths - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include <stdarg.h> -#include <string.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "objbase.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(shell); - -/* DataBlock list element (ordinals 17-22) */ -typedef struct tagSHLWAPI_CLIST -{ - ULONG ulSize; /* Size of this list element and its data */ - ULONG ulId; /* If 0xFFFFFFFF, The real element follows */ - /* Item data (or a contained SHLWAPI_CLIST) follows... */ -} SHLWAPI_CLIST, *LPSHLWAPI_CLIST; - -typedef const SHLWAPI_CLIST* LPCSHLWAPI_CLIST; - -/* ulId for contained SHLWAPI_CLIST items */ -#define CLIST_ID_CONTAINER (~0UL) - -HRESULT WINAPI SHAddDataBlock(LPSHLWAPI_CLIST*,LPCSHLWAPI_CLIST); - -/************************************************************************* - * NextItem - * - * Internal helper: move a DataBlock pointer to the next item. - */ -inline static LPSHLWAPI_CLIST NextItem(LPCSHLWAPI_CLIST lpList) -{ - const char* address = (const char*)lpList; - address += lpList->ulSize; - return (LPSHLWAPI_CLIST)address; -} - -/************************************************************************* - * @ [SHLWAPI.17] - * - * Write a DataBlock list to an IStream object. - * - * PARAMS - * lpStream [I] IStream object to write the list to - * lpList [I] List of items to write - * - * RETURNS - * Success: S_OK. The object is written to the stream. - * Failure: An HRESULT error code - * - * NOTES - * Ordinals 17,18,19,20,21 and 22 are related and together provide a compact - * list structure (a "DataBlock List"), which may be stored and retrieved from - * an IStream object. - * - * The exposed API consists of: - * - * - SHWriteDataBlockList() - Write a DataBlock list to a stream, - * - SHReadDataBlockList() - Read and create a list from a stream, - * - SHFreeDataBlockList() - Free a list, - * - SHAddDataBlock() - Insert a new item into a list, - * - SHRemoveDataBlock() - Remove an item from a list, - * - SHFindDataBlock() - Find an item in a list. - * - * The DataBlock list is stored packed into a memory array. Each element has a - * size and an associated ID. Elements must be less than 64k if the list is - * to be subsequently read from a stream. - * - * Elements are aligned on DWORD boundaries. If an elements data size is not - * a DWORD size multiple, the element is wrapped by inserting a surrounding - * element with an Id of 0xFFFFFFFF, and size sufficient to pad to a DWORD boundary. - * - * These functions are slow for large objects and long lists. - */ -HRESULT WINAPI SHWriteDataBlockList(IStream* lpStream, LPSHLWAPI_CLIST lpList) -{ - ULONG ulSize; - HRESULT hRet = E_FAIL; - - TRACE("(%p,%p)\n", lpStream, lpList); - - if(lpList) - { - while (lpList->ulSize) - { - LPSHLWAPI_CLIST lpItem = lpList; - - if(lpList->ulId == CLIST_ID_CONTAINER) - lpItem++; - - hRet = IStream_Write(lpStream,lpItem,lpItem->ulSize,&ulSize); - if (FAILED(hRet)) - return hRet; - - if(lpItem->ulSize != ulSize) - return STG_E_MEDIUMFULL; - - lpList = NextItem(lpList); - } - } - - if(SUCCEEDED(hRet)) - { - ULONG ulDummy; - ulSize = 0; - - /* Write a terminating list entry with zero size */ - hRet = IStream_Write(lpStream, &ulSize,sizeof(ulSize),&ulDummy); - } - - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.18] - * - * Read and create a DataBlock list from an IStream object. - * - * PARAMS - * lpStream [I] Stream to read the list from - * lppList [0] Pointer to receive the new List - * - * RETURNS - * Success: S_OK - * Failure: An HRESULT error code - * - * NOTES - * When read from a file, list objects are limited in size to 64k. - * See SHWriteDataBlockList. - */ -HRESULT WINAPI SHReadDataBlockList(IStream* lpStream, LPSHLWAPI_CLIST* lppList) -{ - SHLWAPI_CLIST bBuff[128]; /* Temporary storage for new list item */ - ULONG ulBuffSize = sizeof(bBuff); - LPSHLWAPI_CLIST pItem = bBuff; - ULONG ulRead, ulSize; - HRESULT hRet = S_OK; - - TRACE("(%p,%p)\n", lpStream, lppList); - - if(*lppList) - { - /* Free any existing list */ - LocalFree((HLOCAL)*lppList); - *lppList = NULL; - } - - do - { - /* Read the size of the next item */ - hRet = IStream_Read(lpStream, &ulSize,sizeof(ulSize),&ulRead); - - if(FAILED(hRet) || ulRead != sizeof(ulSize) || !ulSize) - break; /* Read failed or read zero size (the end of the list) */ - - if(ulSize > 0xFFFF) - { - LARGE_INTEGER liZero; - ULARGE_INTEGER ulPos; - - liZero.QuadPart = 0; - - /* Back the stream up; this object is too big for the list */ - if(SUCCEEDED(IStream_Seek(lpStream, liZero, STREAM_SEEK_CUR, &ulPos))) - { - liZero.QuadPart = ulPos.QuadPart - sizeof(ULONG); - IStream_Seek(lpStream, liZero, STREAM_SEEK_SET, NULL); - } - break; - } - else if (ulSize >= sizeof(SHLWAPI_CLIST)) - { - /* Add this new item to the list */ - if(ulSize > ulBuffSize) - { - /* We need more buffer space, allocate it */ - LPSHLWAPI_CLIST lpTemp; - - if (pItem == bBuff) - lpTemp = (LPSHLWAPI_CLIST)LocalAlloc(LMEM_ZEROINIT, ulSize); - else - lpTemp = (LPSHLWAPI_CLIST)LocalReAlloc((HLOCAL)pItem, ulSize, - LMEM_ZEROINIT|LMEM_MOVEABLE); - - if(!lpTemp) - { - hRet = E_OUTOFMEMORY; - break; - } - ulBuffSize = ulSize; - pItem = lpTemp; - } - - pItem->ulSize = ulSize; - ulSize -= sizeof(pItem->ulSize); /* already read this member */ - - /* Read the item Id and data */ - hRet = IStream_Read(lpStream, &pItem->ulId, ulSize, &ulRead); - - if(FAILED(hRet) || ulRead != ulSize) - break; - - SHAddDataBlock(lppList, pItem); /* Insert Item */ - } - } while(1); - - /* If we allocated space, free it */ - if(pItem != bBuff) - LocalFree((HLOCAL)pItem); - - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.19] - * - * Free a DataBlock list. - * - * PARAMS - * lpList [I] List to free - * - * RETURNS - * Nothing. - * - * NOTES - * See SHWriteDataBlockList. - */ -VOID WINAPI SHFreeDataBlockList(LPSHLWAPI_CLIST lpList) -{ - TRACE("(%p)\n", lpList); - - if (lpList) - LocalFree((HLOCAL)lpList); -} - -/************************************************************************* - * @ [SHLWAPI.20] - * - * Insert a new item into a DataBlock list. - * - * PARAMS - * lppList [0] Pointer to the List - * lpNewItem [I] The new item to add to the list - * - * RETURNS - * Success: S_OK. The item is added to the list. - * Failure: An HRESULT error code. - * - * NOTES - * If the size of the element to be inserted is less than the size of a - * SHLWAPI_CLIST node, or the Id for the item is CLIST_ID_CONTAINER, - * the call returns S_OK but does not actually add the element. - * See SHWriteDataBlockList. - */ -HRESULT WINAPI SHAddDataBlock(LPSHLWAPI_CLIST* lppList, LPCSHLWAPI_CLIST lpNewItem) -{ - LPSHLWAPI_CLIST lpInsertAt = NULL; - ULONG ulSize; - - TRACE("(%p,%p)\n", lppList, lpNewItem); - - if(!lppList || !lpNewItem ) - return E_INVALIDARG; - - if (lpNewItem->ulSize < sizeof(SHLWAPI_CLIST) || - lpNewItem->ulId == CLIST_ID_CONTAINER) - return S_OK; - - ulSize = lpNewItem->ulSize; - - if(ulSize & 0x3) - { - /* Tune size to a ULONG boundary, add space for container element */ - ulSize = ((ulSize + 0x3) & 0xFFFFFFFC) + sizeof(SHLWAPI_CLIST); - TRACE("Creating container item, new size = %ld\n", ulSize); - } - - if(!*lppList) - { - /* An empty list. Allocate space for terminal ulSize also */ - *lppList = (LPSHLWAPI_CLIST)LocalAlloc(LMEM_ZEROINIT, - ulSize + sizeof(ULONG)); - lpInsertAt = *lppList; - } - else - { - /* Append to the end of the list */ - ULONG ulTotalSize = 0; - LPSHLWAPI_CLIST lpIter = *lppList; - - /* Iterate to the end of the list, calculating the total size */ - while (lpIter->ulSize) - { - ulTotalSize += lpIter->ulSize; - lpIter = NextItem(lpIter); - } - - /* Increase the size of the list */ - lpIter = (LPSHLWAPI_CLIST)LocalReAlloc((HLOCAL)*lppList, - ulTotalSize + ulSize+sizeof(ULONG), - LMEM_ZEROINIT | LMEM_MOVEABLE); - if(lpIter) - { - *lppList = lpIter; - lpInsertAt = (LPSHLWAPI_CLIST)((char*)lpIter + ulTotalSize); /* At end */ - } - } - - if(lpInsertAt) - { - /* Copy in the new item */ - LPSHLWAPI_CLIST lpDest = lpInsertAt; - - if(ulSize != lpNewItem->ulSize) - { - lpInsertAt->ulSize = ulSize; - lpInsertAt->ulId = CLIST_ID_CONTAINER; - lpDest++; - } - memcpy(lpDest, lpNewItem, lpNewItem->ulSize); - - /* Terminate the list */ - lpInsertAt = NextItem(lpInsertAt); - lpInsertAt->ulSize = 0; - - return lpNewItem->ulSize; - } - return S_OK; -} - -/************************************************************************* - * @ [SHLWAPI.21] - * - * Remove an item from a DataBlock list. - * - * PARAMS - * lppList [O] List to remove the item from - * ulId [I] Id of item to remove - * - * RETURNS - * Success: TRUE. - * Failure: FALSE, If any parameters are invalid, or the item was not found. - * - * NOTES - * See SHWriteDataBlockList. - */ -BOOL WINAPI SHRemoveDataBlock(LPSHLWAPI_CLIST* lppList, ULONG ulId) -{ - LPSHLWAPI_CLIST lpList = 0; - LPSHLWAPI_CLIST lpItem = NULL; - LPSHLWAPI_CLIST lpNext; - ULONG ulNewSize; - - TRACE("(%p,%ld)\n", lppList, ulId); - - if(lppList && (lpList = *lppList)) - { - /* Search for item in list */ - while (lpList->ulSize) - { - if(lpList->ulId == ulId || - (lpList->ulId == CLIST_ID_CONTAINER && lpList[1].ulId == ulId)) - { - lpItem = lpList; /* Found */ - break; - } - lpList = NextItem(lpList); - } - } - - if(!lpItem) - return FALSE; - - lpList = lpNext = NextItem(lpItem); - - /* Locate the end of the list */ - while (lpList->ulSize) - lpList = NextItem(lpList); - - /* Resize the list */ - ulNewSize = LocalSize((HLOCAL)*lppList) - lpItem->ulSize; - - /* Copy following elements over lpItem */ - memmove(lpItem, lpNext, (char *)lpList - (char *)lpNext + sizeof(ULONG)); - - if(ulNewSize <= sizeof(ULONG)) - { - LocalFree((HLOCAL)*lppList); - *lppList = NULL; /* Removed the last element */ - } - else - { - lpList = (LPSHLWAPI_CLIST)LocalReAlloc((HLOCAL)*lppList, ulNewSize, - LMEM_ZEROINIT|LMEM_MOVEABLE); - if(lpList) - *lppList = lpList; - } - return TRUE; -} - -/************************************************************************* - * @ [SHLWAPI.22] - * - * Find an item in a DataBlock list. - * - * PARAMS - * lpList [I] List to search - * ulId [I] Id of item to find - * - * RETURNS - * Success: A pointer to the list item found - * Failure: NULL - * - * NOTES - * See SHWriteDataBlockList. - */ -LPSHLWAPI_CLIST WINAPI SHFindDataBlock(LPSHLWAPI_CLIST lpList, ULONG ulId) -{ - TRACE("(%p,%ld)\n", lpList, ulId); - - if(lpList) - { - while(lpList->ulSize) - { - if(lpList->ulId == ulId) - return lpList; /* Matched */ - else if(lpList->ulId == CLIST_ID_CONTAINER && lpList[1].ulId == ulId) - return lpList + 1; /* Contained item matches */ - - lpList = NextItem(lpList); - } - } - return NULL; -} +/* + * SHLWAPI DataBlock List functions + * + * Copyright 2002 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <stdarg.h> +#include <string.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/* DataBlock list element (ordinals 17-22) */ +typedef struct tagSHLWAPI_CLIST +{ + ULONG ulSize; /* Size of this list element and its data */ + ULONG ulId; /* If 0xFFFFFFFF, The real element follows */ + /* Item data (or a contained SHLWAPI_CLIST) follows... */ +} SHLWAPI_CLIST, *LPSHLWAPI_CLIST; + +typedef const SHLWAPI_CLIST* LPCSHLWAPI_CLIST; + +/* ulId for contained SHLWAPI_CLIST items */ +#define CLIST_ID_CONTAINER (~0UL) + +HRESULT WINAPI SHAddDataBlock(LPSHLWAPI_CLIST*,LPCSHLWAPI_CLIST); + +/************************************************************************* + * NextItem + * + * Internal helper: move a DataBlock pointer to the next item. + */ +inline static LPSHLWAPI_CLIST NextItem(LPCSHLWAPI_CLIST lpList) +{ + const char* address = (const char*)lpList; + address += lpList->ulSize; + return (LPSHLWAPI_CLIST)address; +} + +/************************************************************************* + * @ [SHLWAPI.17] + * + * Write a DataBlock list to an IStream object. + * + * PARAMS + * lpStream [I] IStream object to write the list to + * lpList [I] List of items to write + * + * RETURNS + * Success: S_OK. The object is written to the stream. + * Failure: An HRESULT error code + * + * NOTES + * Ordinals 17,18,19,20,21 and 22 are related and together provide a compact + * list structure (a "DataBlock List"), which may be stored and retrieved from + * an IStream object. + * + * The exposed API consists of: + * + * - SHWriteDataBlockList() - Write a DataBlock list to a stream, + * - SHReadDataBlockList() - Read and create a list from a stream, + * - SHFreeDataBlockList() - Free a list, + * - SHAddDataBlock() - Insert a new item into a list, + * - SHRemoveDataBlock() - Remove an item from a list, + * - SHFindDataBlock() - Find an item in a list. + * + * The DataBlock list is stored packed into a memory array. Each element has a + * size and an associated ID. Elements must be less than 64k if the list is + * to be subsequently read from a stream. + * + * Elements are aligned on DWORD boundaries. If an elements data size is not + * a DWORD size multiple, the element is wrapped by inserting a surrounding + * element with an Id of 0xFFFFFFFF, and size sufficient to pad to a DWORD boundary. + * + * These functions are slow for large objects and long lists. + */ +HRESULT WINAPI SHWriteDataBlockList(IStream* lpStream, LPSHLWAPI_CLIST lpList) +{ + ULONG ulSize; + HRESULT hRet = E_FAIL; + + TRACE("(%p,%p)\n", lpStream, lpList); + + if(lpList) + { + while (lpList->ulSize) + { + LPSHLWAPI_CLIST lpItem = lpList; + + if(lpList->ulId == CLIST_ID_CONTAINER) + lpItem++; + + hRet = IStream_Write(lpStream,lpItem,lpItem->ulSize,&ulSize); + if (FAILED(hRet)) + return hRet; + + if(lpItem->ulSize != ulSize) + return STG_E_MEDIUMFULL; + + lpList = NextItem(lpList); + } + } + + if(SUCCEEDED(hRet)) + { + ULONG ulDummy; + ulSize = 0; + + /* Write a terminating list entry with zero size */ + hRet = IStream_Write(lpStream, &ulSize,sizeof(ulSize),&ulDummy); + } + + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.18] + * + * Read and create a DataBlock list from an IStream object. + * + * PARAMS + * lpStream [I] Stream to read the list from + * lppList [0] Pointer to receive the new List + * + * RETURNS + * Success: S_OK + * Failure: An HRESULT error code + * + * NOTES + * When read from a file, list objects are limited in size to 64k. + * See SHWriteDataBlockList. + */ +HRESULT WINAPI SHReadDataBlockList(IStream* lpStream, LPSHLWAPI_CLIST* lppList) +{ + SHLWAPI_CLIST bBuff[128]; /* Temporary storage for new list item */ + ULONG ulBuffSize = sizeof(bBuff); + LPSHLWAPI_CLIST pItem = bBuff; + ULONG ulRead, ulSize; + HRESULT hRet = S_OK; + + TRACE("(%p,%p)\n", lpStream, lppList); + + if(*lppList) + { + /* Free any existing list */ + LocalFree((HLOCAL)*lppList); + *lppList = NULL; + } + + do + { + /* Read the size of the next item */ + hRet = IStream_Read(lpStream, &ulSize,sizeof(ulSize),&ulRead); + + if(FAILED(hRet) || ulRead != sizeof(ulSize) || !ulSize) + break; /* Read failed or read zero size (the end of the list) */ + + if(ulSize > 0xFFFF) + { + LARGE_INTEGER liZero; + ULARGE_INTEGER ulPos; + + liZero.QuadPart = 0; + + /* Back the stream up; this object is too big for the list */ + if(SUCCEEDED(IStream_Seek(lpStream, liZero, STREAM_SEEK_CUR, &ulPos))) + { + liZero.QuadPart = ulPos.QuadPart - sizeof(ULONG); + IStream_Seek(lpStream, liZero, STREAM_SEEK_SET, NULL); + } + break; + } + else if (ulSize >= sizeof(SHLWAPI_CLIST)) + { + /* Add this new item to the list */ + if(ulSize > ulBuffSize) + { + /* We need more buffer space, allocate it */ + LPSHLWAPI_CLIST lpTemp; + + if (pItem == bBuff) + lpTemp = (LPSHLWAPI_CLIST)LocalAlloc(LMEM_ZEROINIT, ulSize); + else + lpTemp = (LPSHLWAPI_CLIST)LocalReAlloc((HLOCAL)pItem, ulSize, + LMEM_ZEROINIT|LMEM_MOVEABLE); + + if(!lpTemp) + { + hRet = E_OUTOFMEMORY; + break; + } + ulBuffSize = ulSize; + pItem = lpTemp; + } + + pItem->ulSize = ulSize; + ulSize -= sizeof(pItem->ulSize); /* already read this member */ + + /* Read the item Id and data */ + hRet = IStream_Read(lpStream, &pItem->ulId, ulSize, &ulRead); + + if(FAILED(hRet) || ulRead != ulSize) + break; + + SHAddDataBlock(lppList, pItem); /* Insert Item */ + } + } while(1); + + /* If we allocated space, free it */ + if(pItem != bBuff) + LocalFree((HLOCAL)pItem); + + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.19] + * + * Free a DataBlock list. + * + * PARAMS + * lpList [I] List to free + * + * RETURNS + * Nothing. + * + * NOTES + * See SHWriteDataBlockList. + */ +VOID WINAPI SHFreeDataBlockList(LPSHLWAPI_CLIST lpList) +{ + TRACE("(%p)\n", lpList); + + if (lpList) + LocalFree((HLOCAL)lpList); +} + +/************************************************************************* + * @ [SHLWAPI.20] + * + * Insert a new item into a DataBlock list. + * + * PARAMS + * lppList [0] Pointer to the List + * lpNewItem [I] The new item to add to the list + * + * RETURNS + * Success: S_OK. The item is added to the list. + * Failure: An HRESULT error code. + * + * NOTES + * If the size of the element to be inserted is less than the size of a + * SHLWAPI_CLIST node, or the Id for the item is CLIST_ID_CONTAINER, + * the call returns S_OK but does not actually add the element. + * See SHWriteDataBlockList. + */ +HRESULT WINAPI SHAddDataBlock(LPSHLWAPI_CLIST* lppList, LPCSHLWAPI_CLIST lpNewItem) +{ + LPSHLWAPI_CLIST lpInsertAt = NULL; + ULONG ulSize; + + TRACE("(%p,%p)\n", lppList, lpNewItem); + + if(!lppList || !lpNewItem ) + return E_INVALIDARG; + + if (lpNewItem->ulSize < sizeof(SHLWAPI_CLIST) || + lpNewItem->ulId == CLIST_ID_CONTAINER) + return S_OK; + + ulSize = lpNewItem->ulSize; + + if(ulSize & 0x3) + { + /* Tune size to a ULONG boundary, add space for container element */ + ulSize = ((ulSize + 0x3) & 0xFFFFFFFC) + sizeof(SHLWAPI_CLIST); + TRACE("Creating container item, new size = %ld\n", ulSize); + } + + if(!*lppList) + { + /* An empty list. Allocate space for terminal ulSize also */ + *lppList = (LPSHLWAPI_CLIST)LocalAlloc(LMEM_ZEROINIT, + ulSize + sizeof(ULONG)); + lpInsertAt = *lppList; + } + else + { + /* Append to the end of the list */ + ULONG ulTotalSize = 0; + LPSHLWAPI_CLIST lpIter = *lppList; + + /* Iterate to the end of the list, calculating the total size */ + while (lpIter->ulSize) + { + ulTotalSize += lpIter->ulSize; + lpIter = NextItem(lpIter); + } + + /* Increase the size of the list */ + lpIter = (LPSHLWAPI_CLIST)LocalReAlloc((HLOCAL)*lppList, + ulTotalSize + ulSize+sizeof(ULONG), + LMEM_ZEROINIT | LMEM_MOVEABLE); + if(lpIter) + { + *lppList = lpIter; + lpInsertAt = (LPSHLWAPI_CLIST)((char*)lpIter + ulTotalSize); /* At end */ + } + } + + if(lpInsertAt) + { + /* Copy in the new item */ + LPSHLWAPI_CLIST lpDest = lpInsertAt; + + if(ulSize != lpNewItem->ulSize) + { + lpInsertAt->ulSize = ulSize; + lpInsertAt->ulId = CLIST_ID_CONTAINER; + lpDest++; + } + memcpy(lpDest, lpNewItem, lpNewItem->ulSize); + + /* Terminate the list */ + lpInsertAt = NextItem(lpInsertAt); + lpInsertAt->ulSize = 0; + + return lpNewItem->ulSize; + } + return S_OK; +} + +/************************************************************************* + * @ [SHLWAPI.21] + * + * Remove an item from a DataBlock list. + * + * PARAMS + * lppList [O] List to remove the item from + * ulId [I] Id of item to remove + * + * RETURNS + * Success: TRUE. + * Failure: FALSE, If any parameters are invalid, or the item was not found. + * + * NOTES + * See SHWriteDataBlockList. + */ +BOOL WINAPI SHRemoveDataBlock(LPSHLWAPI_CLIST* lppList, ULONG ulId) +{ + LPSHLWAPI_CLIST lpList = 0; + LPSHLWAPI_CLIST lpItem = NULL; + LPSHLWAPI_CLIST lpNext; + ULONG ulNewSize; + + TRACE("(%p,%ld)\n", lppList, ulId); + + if(lppList && (lpList = *lppList)) + { + /* Search for item in list */ + while (lpList->ulSize) + { + if(lpList->ulId == ulId || + (lpList->ulId == CLIST_ID_CONTAINER && lpList[1].ulId == ulId)) + { + lpItem = lpList; /* Found */ + break; + } + lpList = NextItem(lpList); + } + } + + if(!lpItem) + return FALSE; + + lpList = lpNext = NextItem(lpItem); + + /* Locate the end of the list */ + while (lpList->ulSize) + lpList = NextItem(lpList); + + /* Resize the list */ + ulNewSize = LocalSize((HLOCAL)*lppList) - lpItem->ulSize; + + /* Copy following elements over lpItem */ + memmove(lpItem, lpNext, (char *)lpList - (char *)lpNext + sizeof(ULONG)); + + if(ulNewSize <= sizeof(ULONG)) + { + LocalFree((HLOCAL)*lppList); + *lppList = NULL; /* Removed the last element */ + } + else + { + lpList = (LPSHLWAPI_CLIST)LocalReAlloc((HLOCAL)*lppList, ulNewSize, + LMEM_ZEROINIT|LMEM_MOVEABLE); + if(lpList) + *lppList = lpList; + } + return TRUE; +} + +/************************************************************************* + * @ [SHLWAPI.22] + * + * Find an item in a DataBlock list. + * + * PARAMS + * lpList [I] List to search + * ulId [I] Id of item to find + * + * RETURNS + * Success: A pointer to the list item found + * Failure: NULL + * + * NOTES + * See SHWriteDataBlockList. + */ +LPSHLWAPI_CLIST WINAPI SHFindDataBlock(LPSHLWAPI_CLIST lpList, ULONG ulId) +{ + TRACE("(%p,%ld)\n", lpList, ulId); + + if(lpList) + { + while(lpList->ulSize) + { + if(lpList->ulId == ulId) + return lpList; /* Matched */ + else if(lpList->ulId == CLIST_ID_CONTAINER && lpList[1].ulId == ulId) + return lpList + 1; /* Contained item matches */ + + lpList = NextItem(lpList); + } + } + return NULL; +} diff --git a/reactos/lib/shlwapi/istream.c b/reactos/lib/shlwapi/istream.c index 46967fe52a8..ff7114c57dc 100644 --- a/reactos/lib/shlwapi/istream.c +++ b/reactos/lib/shlwapi/istream.c @@ -1,672 +1,672 @@ -/* - * SHLWAPI IStream functions - * - * Copyright 2002 Jon Griffiths - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include <stdarg.h> -#include <string.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "winnls.h" -#define NO_SHLWAPI_REG -#define NO_SHLWAPI_PATH -#include "shlwapi.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(shell); - -/* Layout of ISHFileStream object */ -typedef struct -{ - IStreamVtbl *lpVtbl; - ULONG ref; - HANDLE hFile; - DWORD dwMode; - LPOLESTR lpszPath; - DWORD type; - DWORD grfStateBits; -} ISHFileStream; - -static HRESULT WINAPI IStream_fnCommit(IStream*,DWORD); - - -/************************************************************************** -* IStream_fnQueryInterface -*/ -static HRESULT WINAPI IStream_fnQueryInterface(IStream *iface, REFIID riid, LPVOID *ppvObj) -{ - ISHFileStream *This = (ISHFileStream *)iface; - - TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppvObj); - - *ppvObj = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IStream)) - { - *ppvObj = This; - - IStream_AddRef((IStream*)*ppvObj); - return S_OK; - } - return E_NOINTERFACE; -} - -/************************************************************************** -* IStream_fnAddRef -*/ -static ULONG WINAPI IStream_fnAddRef(IStream *iface) -{ - ISHFileStream *This = (ISHFileStream *)iface; - ULONG refCount = InterlockedIncrement(&This->ref); - - TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1); - - return refCount; -} - -/************************************************************************** -* IStream_fnRelease -*/ -static ULONG WINAPI IStream_fnRelease(IStream *iface) -{ - ISHFileStream *This = (ISHFileStream *)iface; - ULONG refCount = InterlockedDecrement(&This->ref); - - TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1); - - if (!refCount) - { - IStream_fnCommit(iface, 0); /* If ever buffered, this will be needed */ - LocalFree((HLOCAL)This->lpszPath); - CloseHandle(This->hFile); - HeapFree(GetProcessHeap(), 0, This); - } - - return refCount; -} - -/************************************************************************** - * IStream_fnRead - */ -static HRESULT WINAPI IStream_fnRead(IStream *iface, void* pv, ULONG cb, ULONG* pcbRead) -{ - ISHFileStream *This = (ISHFileStream *)iface; - HRESULT hRet = S_OK; - DWORD dwRead = 0; - - TRACE("(%p,%p,0x%08lx,%p)\n", This, pv, cb, pcbRead); - - if (!pv) - hRet = STG_E_INVALIDPOINTER; - else if (!ReadFile(This->hFile, pv, cb, &dwRead, NULL)) - { - hRet = (HRESULT)GetLastError(); - if(hRet > 0) - hRet = HRESULT_FROM_WIN32(hRet); - } - if (pcbRead) - *pcbRead = dwRead; - return hRet; -} - -/************************************************************************** - * IStream_fnWrite - */ -static HRESULT WINAPI IStream_fnWrite(IStream *iface, const void* pv, ULONG cb, ULONG* pcbWritten) -{ - ISHFileStream *This = (ISHFileStream *)iface; - HRESULT hRet = S_OK; - DWORD dwWritten = 0; - - TRACE("(%p,%p,0x%08lx,%p)\n", This, pv, cb, pcbWritten); - - if (!pv) - hRet = STG_E_INVALIDPOINTER; - else if (!(This->dwMode & STGM_WRITE)) - hRet = E_FAIL; - else if (!WriteFile(This->hFile, pv, cb, &dwWritten, NULL)) - { - hRet = (HRESULT)GetLastError(); - if(hRet > 0) - hRet = HRESULT_FROM_WIN32(hRet); - } - if (pcbWritten) - *pcbWritten = dwWritten; - return hRet; -} - -/************************************************************************** - * IStream_fnSeek - */ -static HRESULT WINAPI IStream_fnSeek(IStream *iface, LARGE_INTEGER dlibMove, - DWORD dwOrigin, ULARGE_INTEGER* pNewPos) -{ - ISHFileStream *This = (ISHFileStream *)iface; - DWORD dwPos; - - TRACE("(%p,%ld,%ld,%p)\n", This, dlibMove.u.LowPart, dwOrigin, pNewPos); - - IStream_fnCommit(iface, 0); /* If ever buffered, this will be needed */ - dwPos = SetFilePointer(This->hFile, dlibMove.u.LowPart, NULL, dwOrigin); - - if (pNewPos) - { - pNewPos->u.HighPart = 0; - pNewPos->u.LowPart = dwPos; - } - return S_OK; -} - -/************************************************************************** - * IStream_fnSetSize - */ -static HRESULT WINAPI IStream_fnSetSize(IStream *iface, ULARGE_INTEGER libNewSize) -{ - ISHFileStream *This = (ISHFileStream *)iface; - - TRACE("(%p,%ld)\n", This, libNewSize.u.LowPart); - IStream_fnCommit(iface, 0); /* If ever buffered, this will be needed */ - return E_NOTIMPL; -} - -/************************************************************************** - * IStream_fnCopyTo - */ -static HRESULT WINAPI IStream_fnCopyTo(IStream *iface, IStream* pstm, ULARGE_INTEGER cb, - ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) -{ - ISHFileStream *This = (ISHFileStream *)iface; - char copyBuff[1024]; - ULONGLONG ulSize; - HRESULT hRet = S_OK; - - TRACE("(%p,%p,%ld,%p,%p)\n", This, pstm, cb.u.LowPart, pcbRead, pcbWritten); - - if (pcbRead) - pcbRead->QuadPart = 0; - if (pcbWritten) - pcbWritten->QuadPart = 0; - - if (!pstm) - return STG_E_INVALIDPOINTER; - - IStream_fnCommit(iface, 0); /* If ever buffered, this will be needed */ - - /* Copy data */ - ulSize = cb.QuadPart; - while (ulSize) - { - ULONG ulLeft, ulAmt; - - ulLeft = ulSize > sizeof(copyBuff) ? sizeof(copyBuff) : ulSize; - - /* Read */ - hRet = IStream_fnRead(iface, copyBuff, ulLeft, &ulAmt); - if (pcbRead) - pcbRead->QuadPart += ulAmt; - if (FAILED(hRet) || ulAmt != ulLeft) - break; - - /* Write */ - hRet = IStream_fnWrite(pstm, copyBuff, ulLeft, &ulAmt); - if (pcbWritten) - pcbWritten->QuadPart += ulAmt; - if (FAILED(hRet) || ulAmt != ulLeft) - break; - - ulSize -= ulLeft; - } - return hRet; -} - -/************************************************************************** - * IStream_fnCommit - */ -static HRESULT WINAPI IStream_fnCommit(IStream *iface, DWORD grfCommitFlags) -{ - ISHFileStream *This = (ISHFileStream *)iface; - - TRACE("(%p,%ld)\n", This, grfCommitFlags); - /* Currently unbuffered: This function is not needed */ - return S_OK; -} - -/************************************************************************** - * IStream_fnRevert - */ -static HRESULT WINAPI IStream_fnRevert(IStream *iface) -{ - ISHFileStream *This = (ISHFileStream *)iface; - - TRACE("(%p)\n", This); - return E_NOTIMPL; -} - -/************************************************************************** - * IStream_fnLockUnlockRegion - */ -static HRESULT WINAPI IStream_fnLockUnlockRegion(IStream *iface, ULARGE_INTEGER libOffset, - ULARGE_INTEGER cb, DWORD dwLockType) -{ - ISHFileStream *This = (ISHFileStream *)iface; - TRACE("(%p,%ld,%ld,%ld)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType); - return E_NOTIMPL; -} - -/************************************************************************* - * IStream_fnStat - */ -static HRESULT WINAPI IStream_fnStat(IStream *iface, STATSTG* lpStat, - DWORD grfStatFlag) -{ - ISHFileStream *This = (ISHFileStream *)iface; - BY_HANDLE_FILE_INFORMATION fi; - HRESULT hRet = S_OK; - - TRACE("(%p,%p,%ld)\n", This, lpStat, grfStatFlag); - - if (!grfStatFlag) - hRet = STG_E_INVALIDPOINTER; - else - { - memset(&fi, 0, sizeof(fi)); - GetFileInformationByHandle(This->hFile, &fi); - - if (grfStatFlag & STATFLAG_NONAME) - lpStat->pwcsName = NULL; - else - lpStat->pwcsName = StrDupW(This->lpszPath); - lpStat->type = This->type; - lpStat->cbSize.u.LowPart = fi.nFileSizeLow; - lpStat->cbSize.u.HighPart = fi.nFileSizeHigh; - lpStat->mtime = fi.ftLastWriteTime; - lpStat->ctime = fi.ftCreationTime; - lpStat->atime = fi.ftLastAccessTime; - lpStat->grfMode = This->dwMode; - lpStat->grfLocksSupported = 0; - memcpy(&lpStat->clsid, &IID_IStream, sizeof(CLSID)); - lpStat->grfStateBits = This->grfStateBits; - lpStat->reserved = 0; - } - return hRet; -} - -/************************************************************************* - * IStream_fnClone - */ -static HRESULT WINAPI IStream_fnClone(IStream *iface, IStream** ppstm) -{ - ISHFileStream *This = (ISHFileStream *)iface; - - TRACE("(%p)\n",This); - if (ppstm) - *ppstm = NULL; - return E_NOTIMPL; -} - -static struct IStreamVtbl SHLWAPI_fsVTable = -{ - IStream_fnQueryInterface, - IStream_fnAddRef, - IStream_fnRelease, - IStream_fnRead, - IStream_fnWrite, - IStream_fnSeek, - IStream_fnSetSize, - IStream_fnCopyTo, - IStream_fnCommit, - IStream_fnRevert, - IStream_fnLockUnlockRegion, - IStream_fnLockUnlockRegion, - IStream_fnStat, - IStream_fnClone -}; - -/************************************************************************** - * IStream_Create - * - * Internal helper: Create and initialise a new file stream object. - */ -static IStream *IStream_Create(LPCWSTR lpszPath, HANDLE hFile, DWORD dwMode) -{ - ISHFileStream* fileStream; - - fileStream = HeapAlloc(GetProcessHeap(), 0, sizeof(ISHFileStream)); - - if (fileStream) - { - fileStream->lpVtbl = &SHLWAPI_fsVTable; - fileStream->ref = 1; - fileStream->hFile = hFile; - fileStream->dwMode = dwMode; - fileStream->lpszPath = StrDupW(lpszPath); - fileStream->type = 0; /* FIXME */ - fileStream->grfStateBits = 0; /* FIXME */ - } - TRACE ("Returning %p\n", fileStream); - return (IStream *)fileStream; -} - -/************************************************************************* - * SHCreateStreamOnFileEx [SHLWAPI.@] - * - * Create a stream on a file. - * - * PARAMS - * lpszPath [I] Path of file to create stream on - * dwMode [I] Mode to create stream in - * dwAttributes [I] Attributes of the file - * bCreate [I] Whether to create the file if it doesn't exist - * lpTemplate [I] Reserved, must be NULL - * lppStream [O] Destination for created stream - * - * RETURNS - * Success: S_OK. lppStream contains the new stream object - * Failure: E_INVALIDARG if any parameter is invalid, or an HRESULT error code - * - * NOTES - * This function is available in Unicode only. - */ -HRESULT WINAPI SHCreateStreamOnFileEx(LPCWSTR lpszPath, DWORD dwMode, - DWORD dwAttributes, BOOL bCreate, - IStream *lpTemplate, IStream **lppStream) -{ - DWORD dwAccess, dwShare, dwCreate; - HANDLE hFile; - - TRACE("(%s,%ld,0x%08lX,%d,%p,%p)\n", debugstr_w(lpszPath), dwMode, - dwAttributes, bCreate, lpTemplate, lppStream); - - if (!lpszPath || !lppStream || lpTemplate) - return E_INVALIDARG; - - *lppStream = NULL; - - if (dwMode & ~(STGM_WRITE|STGM_READWRITE|STGM_SHARE_DENY_NONE|STGM_SHARE_DENY_READ|STGM_CREATE)) - { - WARN("Invalid mode 0x%08lX\n", dwMode); - return E_INVALIDARG; - } - - /* Access */ - switch (dwMode & (STGM_WRITE|STGM_READWRITE)) - { - case STGM_READWRITE|STGM_WRITE: - case STGM_READWRITE: - dwAccess = GENERIC_READ|GENERIC_WRITE; - break; - case STGM_WRITE: - dwAccess = GENERIC_WRITE; - break; - default: - dwAccess = GENERIC_READ; - break; - } - - /* Sharing */ - switch (dwMode & STGM_SHARE_DENY_READ) - { - case STGM_SHARE_DENY_READ: - dwShare = FILE_SHARE_WRITE; - break; - case STGM_SHARE_DENY_WRITE: - dwShare = FILE_SHARE_READ; - break; - case STGM_SHARE_EXCLUSIVE: - dwShare = 0; - break; - default: - dwShare = FILE_SHARE_READ|FILE_SHARE_WRITE; - } - - /* FIXME: Creation Flags, MSDN is fuzzy on the mapping... */ - if (dwMode == STGM_FAILIFTHERE) - dwCreate = bCreate ? CREATE_NEW : OPEN_EXISTING; - else if (dwMode & STGM_CREATE) - dwCreate = CREATE_ALWAYS; - else - dwCreate = OPEN_ALWAYS; - - /* Open HANDLE to file */ - hFile = CreateFileW(lpszPath, dwAccess, dwShare, NULL, dwCreate, - dwAttributes, 0); - - if(hFile == INVALID_HANDLE_VALUE) - { - HRESULT hRet = (HRESULT)GetLastError(); - if(hRet > 0) - hRet = HRESULT_FROM_WIN32(hRet); - return hRet; - } - - *lppStream = IStream_Create(lpszPath, hFile, dwMode); - - if(!*lppStream) - { - CloseHandle(hFile); - return E_OUTOFMEMORY; - } - return S_OK; -} - -/************************************************************************* - * SHCreateStreamOnFileW [SHLWAPI.@] - * - * See SHCreateStreamOnFileA. - */ -HRESULT WINAPI SHCreateStreamOnFileW(LPCWSTR lpszPath, DWORD dwMode, - IStream **lppStream) -{ - DWORD dwAttr; - - TRACE("(%s,%ld,%p)\n", debugstr_w(lpszPath), dwMode, lppStream); - - if (!lpszPath || !lppStream) - return E_INVALIDARG; - - dwAttr = GetFileAttributesW(lpszPath); - if (dwAttr == INVALID_FILE_ATTRIBUTES) - dwAttr = 0; - - return SHCreateStreamOnFileEx(lpszPath, dwMode|STGM_WRITE, dwAttr, - TRUE, NULL, lppStream); -} - -/************************************************************************* - * SHCreateStreamOnFileA [SHLWAPI.@] - * - * Create a stream on a file. - * - * PARAMS - * lpszPath [I] Path of file to create stream on - * dwMode [I] Mode to create stream in - * lppStream [O] Destination for created IStream object - * - * RETURNS - * Success: S_OK. lppStream contains the new IStream object - * Failure: E_INVALIDARG if any parameter is invalid, or an HRESULT error code - */ -HRESULT WINAPI SHCreateStreamOnFileA(LPCSTR lpszPath, DWORD dwMode, - IStream **lppStream) -{ - WCHAR szPath[MAX_PATH]; - - TRACE("(%s,%ld,%p)\n", debugstr_a(lpszPath), dwMode, lppStream); - - if (!lpszPath) - return E_INVALIDARG; - MultiByteToWideChar(0, 0, lpszPath, -1, szPath, MAX_PATH); - return SHCreateStreamOnFileW(szPath, dwMode, lppStream); -} - -/************************************************************************* - * @ [SHLWAPI.184] - * - * Call IStream_Read() on a stream. - * - * PARAMS - * lpStream [I] IStream object - * lpvDest [O] Destination for data read - * ulSize [I] Size of data to read - * - * RETURNS - * Success: S_OK. ulSize bytes have been read from the stream into lpvDest. - * Failure: An HRESULT error code, or E_FAIL if the read succeeded but the - * number of bytes read does not match. - */ -HRESULT WINAPI SHLWAPI_184(IStream *lpStream, LPVOID lpvDest, ULONG ulSize) -{ - ULONG ulRead; - HRESULT hRet; - - TRACE("(%p,%p,%ld)\n", lpStream, lpvDest, ulSize); - - hRet = IStream_Read(lpStream, lpvDest, ulSize, &ulRead); - - if (SUCCEEDED(hRet) && ulRead != ulSize) - hRet = E_FAIL; - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.166] - * - * Determine if a stream has 0 length. - * - * PARAMS - * lpStream [I] IStream object - * - * RETURNS - * TRUE: If the stream has 0 length - * FALSE: Otherwise. - */ -BOOL WINAPI SHIsEmptyStream(IStream *lpStream) -{ - STATSTG statstg; - BOOL bRet = TRUE; - - TRACE("(%p)\n", lpStream); - - memset(&statstg, 0, sizeof(statstg)); - - if(SUCCEEDED(IStream_Stat(lpStream, &statstg, 1))) - { - if(statstg.cbSize.QuadPart) - bRet = FALSE; /* Non-Zero */ - } - else - { - DWORD dwDummy; - - /* Try to read from the stream */ - if(SUCCEEDED(SHLWAPI_184(lpStream, &dwDummy, sizeof(dwDummy)))) - { - LARGE_INTEGER zero; - zero.QuadPart = 0; - - IStream_Seek(lpStream, zero, 0, NULL); - bRet = FALSE; /* Non-Zero */ - } - } - return bRet; -} - -/************************************************************************* - * @ [SHLWAPI.212] - * - * Call IStream_Write() on a stream. - * - * PARAMS - * lpStream [I] IStream object - * lpvSrc [I] Source for data to write - * ulSize [I] Size of data - * - * RETURNS - * Success: S_OK. ulSize bytes have been written to the stream from lpvSrc. - * Failure: An HRESULT error code, or E_FAIL if the write succeeded but the - * number of bytes written does not match. - */ -HRESULT WINAPI SHLWAPI_212(IStream *lpStream, LPCVOID lpvSrc, ULONG ulSize) -{ - ULONG ulWritten; - HRESULT hRet; - - TRACE("(%p,%p,%ld)\n", lpStream, lpvSrc, ulSize); - - hRet = IStream_Write(lpStream, lpvSrc, ulSize, &ulWritten); - - if (SUCCEEDED(hRet) && ulWritten != ulSize) - hRet = E_FAIL; - - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.213] - * - * Seek to the start of a stream. - * - * PARAMS - * lpStream [I] IStream object - * - * RETURNS - * Success: S_OK. The current position within the stream is updated - * Failure: An HRESULT error code. - */ -HRESULT WINAPI IStream_Reset(IStream *lpStream) -{ - LARGE_INTEGER zero; - TRACE("(%p)\n", lpStream); - zero.QuadPart = 0; - return IStream_Seek(lpStream, zero, 0, NULL); -} - -/************************************************************************* - * @ [SHLWAPI.214] - * - * Get the size of a stream. - * - * PARAMS - * lpStream [I] IStream object - * lpulSize [O] Destination for size - * - * RETURNS - * Success: S_OK. lpulSize contains the size of the stream. - * Failure: An HRESULT error code. - */ -HRESULT WINAPI IStream_Size(IStream *lpStream, ULARGE_INTEGER* lpulSize) -{ - STATSTG statstg; - HRESULT hRet; - - TRACE("(%p,%p)\n", lpStream, lpulSize); - - memset(&statstg, 0, sizeof(statstg)); - - hRet = IStream_Stat(lpStream, &statstg, 1); - - if (SUCCEEDED(hRet) && lpulSize) - *lpulSize = statstg.cbSize; - return hRet; -} +/* + * SHLWAPI IStream functions + * + * Copyright 2002 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <stdarg.h> +#include <string.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winnls.h" +#define NO_SHLWAPI_REG +#define NO_SHLWAPI_PATH +#include "shlwapi.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/* Layout of ISHFileStream object */ +typedef struct +{ + IStreamVtbl *lpVtbl; + ULONG ref; + HANDLE hFile; + DWORD dwMode; + LPOLESTR lpszPath; + DWORD type; + DWORD grfStateBits; +} ISHFileStream; + +static HRESULT WINAPI IStream_fnCommit(IStream*,DWORD); + + +/************************************************************************** +* IStream_fnQueryInterface +*/ +static HRESULT WINAPI IStream_fnQueryInterface(IStream *iface, REFIID riid, LPVOID *ppvObj) +{ + ISHFileStream *This = (ISHFileStream *)iface; + + TRACE("(%p,%s,%p)\n", This, debugstr_guid(riid), ppvObj); + + *ppvObj = NULL; + + if(IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IStream)) + { + *ppvObj = This; + + IStream_AddRef((IStream*)*ppvObj); + return S_OK; + } + return E_NOINTERFACE; +} + +/************************************************************************** +* IStream_fnAddRef +*/ +static ULONG WINAPI IStream_fnAddRef(IStream *iface) +{ + ISHFileStream *This = (ISHFileStream *)iface; + ULONG refCount = InterlockedIncrement(&This->ref); + + TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1); + + return refCount; +} + +/************************************************************************** +* IStream_fnRelease +*/ +static ULONG WINAPI IStream_fnRelease(IStream *iface) +{ + ISHFileStream *This = (ISHFileStream *)iface; + ULONG refCount = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1); + + if (!refCount) + { + IStream_fnCommit(iface, 0); /* If ever buffered, this will be needed */ + LocalFree((HLOCAL)This->lpszPath); + CloseHandle(This->hFile); + HeapFree(GetProcessHeap(), 0, This); + } + + return refCount; +} + +/************************************************************************** + * IStream_fnRead + */ +static HRESULT WINAPI IStream_fnRead(IStream *iface, void* pv, ULONG cb, ULONG* pcbRead) +{ + ISHFileStream *This = (ISHFileStream *)iface; + HRESULT hRet = S_OK; + DWORD dwRead = 0; + + TRACE("(%p,%p,0x%08lx,%p)\n", This, pv, cb, pcbRead); + + if (!pv) + hRet = STG_E_INVALIDPOINTER; + else if (!ReadFile(This->hFile, pv, cb, &dwRead, NULL)) + { + hRet = (HRESULT)GetLastError(); + if(hRet > 0) + hRet = HRESULT_FROM_WIN32(hRet); + } + if (pcbRead) + *pcbRead = dwRead; + return hRet; +} + +/************************************************************************** + * IStream_fnWrite + */ +static HRESULT WINAPI IStream_fnWrite(IStream *iface, const void* pv, ULONG cb, ULONG* pcbWritten) +{ + ISHFileStream *This = (ISHFileStream *)iface; + HRESULT hRet = S_OK; + DWORD dwWritten = 0; + + TRACE("(%p,%p,0x%08lx,%p)\n", This, pv, cb, pcbWritten); + + if (!pv) + hRet = STG_E_INVALIDPOINTER; + else if (!(This->dwMode & STGM_WRITE)) + hRet = E_FAIL; + else if (!WriteFile(This->hFile, pv, cb, &dwWritten, NULL)) + { + hRet = (HRESULT)GetLastError(); + if(hRet > 0) + hRet = HRESULT_FROM_WIN32(hRet); + } + if (pcbWritten) + *pcbWritten = dwWritten; + return hRet; +} + +/************************************************************************** + * IStream_fnSeek + */ +static HRESULT WINAPI IStream_fnSeek(IStream *iface, LARGE_INTEGER dlibMove, + DWORD dwOrigin, ULARGE_INTEGER* pNewPos) +{ + ISHFileStream *This = (ISHFileStream *)iface; + DWORD dwPos; + + TRACE("(%p,%ld,%ld,%p)\n", This, dlibMove.u.LowPart, dwOrigin, pNewPos); + + IStream_fnCommit(iface, 0); /* If ever buffered, this will be needed */ + dwPos = SetFilePointer(This->hFile, dlibMove.u.LowPart, NULL, dwOrigin); + + if (pNewPos) + { + pNewPos->u.HighPart = 0; + pNewPos->u.LowPart = dwPos; + } + return S_OK; +} + +/************************************************************************** + * IStream_fnSetSize + */ +static HRESULT WINAPI IStream_fnSetSize(IStream *iface, ULARGE_INTEGER libNewSize) +{ + ISHFileStream *This = (ISHFileStream *)iface; + + TRACE("(%p,%ld)\n", This, libNewSize.u.LowPart); + IStream_fnCommit(iface, 0); /* If ever buffered, this will be needed */ + return E_NOTIMPL; +} + +/************************************************************************** + * IStream_fnCopyTo + */ +static HRESULT WINAPI IStream_fnCopyTo(IStream *iface, IStream* pstm, ULARGE_INTEGER cb, + ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) +{ + ISHFileStream *This = (ISHFileStream *)iface; + char copyBuff[1024]; + ULONGLONG ulSize; + HRESULT hRet = S_OK; + + TRACE("(%p,%p,%ld,%p,%p)\n", This, pstm, cb.u.LowPart, pcbRead, pcbWritten); + + if (pcbRead) + pcbRead->QuadPart = 0; + if (pcbWritten) + pcbWritten->QuadPart = 0; + + if (!pstm) + return STG_E_INVALIDPOINTER; + + IStream_fnCommit(iface, 0); /* If ever buffered, this will be needed */ + + /* Copy data */ + ulSize = cb.QuadPart; + while (ulSize) + { + ULONG ulLeft, ulAmt; + + ulLeft = ulSize > sizeof(copyBuff) ? sizeof(copyBuff) : ulSize; + + /* Read */ + hRet = IStream_fnRead(iface, copyBuff, ulLeft, &ulAmt); + if (pcbRead) + pcbRead->QuadPart += ulAmt; + if (FAILED(hRet) || ulAmt != ulLeft) + break; + + /* Write */ + hRet = IStream_fnWrite(pstm, copyBuff, ulLeft, &ulAmt); + if (pcbWritten) + pcbWritten->QuadPart += ulAmt; + if (FAILED(hRet) || ulAmt != ulLeft) + break; + + ulSize -= ulLeft; + } + return hRet; +} + +/************************************************************************** + * IStream_fnCommit + */ +static HRESULT WINAPI IStream_fnCommit(IStream *iface, DWORD grfCommitFlags) +{ + ISHFileStream *This = (ISHFileStream *)iface; + + TRACE("(%p,%ld)\n", This, grfCommitFlags); + /* Currently unbuffered: This function is not needed */ + return S_OK; +} + +/************************************************************************** + * IStream_fnRevert + */ +static HRESULT WINAPI IStream_fnRevert(IStream *iface) +{ + ISHFileStream *This = (ISHFileStream *)iface; + + TRACE("(%p)\n", This); + return E_NOTIMPL; +} + +/************************************************************************** + * IStream_fnLockUnlockRegion + */ +static HRESULT WINAPI IStream_fnLockUnlockRegion(IStream *iface, ULARGE_INTEGER libOffset, + ULARGE_INTEGER cb, DWORD dwLockType) +{ + ISHFileStream *This = (ISHFileStream *)iface; + TRACE("(%p,%ld,%ld,%ld)\n", This, libOffset.u.LowPart, cb.u.LowPart, dwLockType); + return E_NOTIMPL; +} + +/************************************************************************* + * IStream_fnStat + */ +static HRESULT WINAPI IStream_fnStat(IStream *iface, STATSTG* lpStat, + DWORD grfStatFlag) +{ + ISHFileStream *This = (ISHFileStream *)iface; + BY_HANDLE_FILE_INFORMATION fi; + HRESULT hRet = S_OK; + + TRACE("(%p,%p,%ld)\n", This, lpStat, grfStatFlag); + + if (!grfStatFlag) + hRet = STG_E_INVALIDPOINTER; + else + { + memset(&fi, 0, sizeof(fi)); + GetFileInformationByHandle(This->hFile, &fi); + + if (grfStatFlag & STATFLAG_NONAME) + lpStat->pwcsName = NULL; + else + lpStat->pwcsName = StrDupW(This->lpszPath); + lpStat->type = This->type; + lpStat->cbSize.u.LowPart = fi.nFileSizeLow; + lpStat->cbSize.u.HighPart = fi.nFileSizeHigh; + lpStat->mtime = fi.ftLastWriteTime; + lpStat->ctime = fi.ftCreationTime; + lpStat->atime = fi.ftLastAccessTime; + lpStat->grfMode = This->dwMode; + lpStat->grfLocksSupported = 0; + memcpy(&lpStat->clsid, &IID_IStream, sizeof(CLSID)); + lpStat->grfStateBits = This->grfStateBits; + lpStat->reserved = 0; + } + return hRet; +} + +/************************************************************************* + * IStream_fnClone + */ +static HRESULT WINAPI IStream_fnClone(IStream *iface, IStream** ppstm) +{ + ISHFileStream *This = (ISHFileStream *)iface; + + TRACE("(%p)\n",This); + if (ppstm) + *ppstm = NULL; + return E_NOTIMPL; +} + +static struct IStreamVtbl SHLWAPI_fsVTable = +{ + IStream_fnQueryInterface, + IStream_fnAddRef, + IStream_fnRelease, + IStream_fnRead, + IStream_fnWrite, + IStream_fnSeek, + IStream_fnSetSize, + IStream_fnCopyTo, + IStream_fnCommit, + IStream_fnRevert, + IStream_fnLockUnlockRegion, + IStream_fnLockUnlockRegion, + IStream_fnStat, + IStream_fnClone +}; + +/************************************************************************** + * IStream_Create + * + * Internal helper: Create and initialise a new file stream object. + */ +static IStream *IStream_Create(LPCWSTR lpszPath, HANDLE hFile, DWORD dwMode) +{ + ISHFileStream* fileStream; + + fileStream = HeapAlloc(GetProcessHeap(), 0, sizeof(ISHFileStream)); + + if (fileStream) + { + fileStream->lpVtbl = &SHLWAPI_fsVTable; + fileStream->ref = 1; + fileStream->hFile = hFile; + fileStream->dwMode = dwMode; + fileStream->lpszPath = StrDupW(lpszPath); + fileStream->type = 0; /* FIXME */ + fileStream->grfStateBits = 0; /* FIXME */ + } + TRACE ("Returning %p\n", fileStream); + return (IStream *)fileStream; +} + +/************************************************************************* + * SHCreateStreamOnFileEx [SHLWAPI.@] + * + * Create a stream on a file. + * + * PARAMS + * lpszPath [I] Path of file to create stream on + * dwMode [I] Mode to create stream in + * dwAttributes [I] Attributes of the file + * bCreate [I] Whether to create the file if it doesn't exist + * lpTemplate [I] Reserved, must be NULL + * lppStream [O] Destination for created stream + * + * RETURNS + * Success: S_OK. lppStream contains the new stream object + * Failure: E_INVALIDARG if any parameter is invalid, or an HRESULT error code + * + * NOTES + * This function is available in Unicode only. + */ +HRESULT WINAPI SHCreateStreamOnFileEx(LPCWSTR lpszPath, DWORD dwMode, + DWORD dwAttributes, BOOL bCreate, + IStream *lpTemplate, IStream **lppStream) +{ + DWORD dwAccess, dwShare, dwCreate; + HANDLE hFile; + + TRACE("(%s,%ld,0x%08lX,%d,%p,%p)\n", debugstr_w(lpszPath), dwMode, + dwAttributes, bCreate, lpTemplate, lppStream); + + if (!lpszPath || !lppStream || lpTemplate) + return E_INVALIDARG; + + *lppStream = NULL; + + if (dwMode & ~(STGM_WRITE|STGM_READWRITE|STGM_SHARE_DENY_NONE|STGM_SHARE_DENY_READ|STGM_CREATE)) + { + WARN("Invalid mode 0x%08lX\n", dwMode); + return E_INVALIDARG; + } + + /* Access */ + switch (dwMode & (STGM_WRITE|STGM_READWRITE)) + { + case STGM_READWRITE|STGM_WRITE: + case STGM_READWRITE: + dwAccess = GENERIC_READ|GENERIC_WRITE; + break; + case STGM_WRITE: + dwAccess = GENERIC_WRITE; + break; + default: + dwAccess = GENERIC_READ; + break; + } + + /* Sharing */ + switch (dwMode & STGM_SHARE_DENY_READ) + { + case STGM_SHARE_DENY_READ: + dwShare = FILE_SHARE_WRITE; + break; + case STGM_SHARE_DENY_WRITE: + dwShare = FILE_SHARE_READ; + break; + case STGM_SHARE_EXCLUSIVE: + dwShare = 0; + break; + default: + dwShare = FILE_SHARE_READ|FILE_SHARE_WRITE; + } + + /* FIXME: Creation Flags, MSDN is fuzzy on the mapping... */ + if (dwMode == STGM_FAILIFTHERE) + dwCreate = bCreate ? CREATE_NEW : OPEN_EXISTING; + else if (dwMode & STGM_CREATE) + dwCreate = CREATE_ALWAYS; + else + dwCreate = OPEN_ALWAYS; + + /* Open HANDLE to file */ + hFile = CreateFileW(lpszPath, dwAccess, dwShare, NULL, dwCreate, + dwAttributes, 0); + + if(hFile == INVALID_HANDLE_VALUE) + { + HRESULT hRet = (HRESULT)GetLastError(); + if(hRet > 0) + hRet = HRESULT_FROM_WIN32(hRet); + return hRet; + } + + *lppStream = IStream_Create(lpszPath, hFile, dwMode); + + if(!*lppStream) + { + CloseHandle(hFile); + return E_OUTOFMEMORY; + } + return S_OK; +} + +/************************************************************************* + * SHCreateStreamOnFileW [SHLWAPI.@] + * + * See SHCreateStreamOnFileA. + */ +HRESULT WINAPI SHCreateStreamOnFileW(LPCWSTR lpszPath, DWORD dwMode, + IStream **lppStream) +{ + DWORD dwAttr; + + TRACE("(%s,%ld,%p)\n", debugstr_w(lpszPath), dwMode, lppStream); + + if (!lpszPath || !lppStream) + return E_INVALIDARG; + + dwAttr = GetFileAttributesW(lpszPath); + if (dwAttr == INVALID_FILE_ATTRIBUTES) + dwAttr = 0; + + return SHCreateStreamOnFileEx(lpszPath, dwMode|STGM_WRITE, dwAttr, + TRUE, NULL, lppStream); +} + +/************************************************************************* + * SHCreateStreamOnFileA [SHLWAPI.@] + * + * Create a stream on a file. + * + * PARAMS + * lpszPath [I] Path of file to create stream on + * dwMode [I] Mode to create stream in + * lppStream [O] Destination for created IStream object + * + * RETURNS + * Success: S_OK. lppStream contains the new IStream object + * Failure: E_INVALIDARG if any parameter is invalid, or an HRESULT error code + */ +HRESULT WINAPI SHCreateStreamOnFileA(LPCSTR lpszPath, DWORD dwMode, + IStream **lppStream) +{ + WCHAR szPath[MAX_PATH]; + + TRACE("(%s,%ld,%p)\n", debugstr_a(lpszPath), dwMode, lppStream); + + if (!lpszPath) + return E_INVALIDARG; + MultiByteToWideChar(0, 0, lpszPath, -1, szPath, MAX_PATH); + return SHCreateStreamOnFileW(szPath, dwMode, lppStream); +} + +/************************************************************************* + * @ [SHLWAPI.184] + * + * Call IStream_Read() on a stream. + * + * PARAMS + * lpStream [I] IStream object + * lpvDest [O] Destination for data read + * ulSize [I] Size of data to read + * + * RETURNS + * Success: S_OK. ulSize bytes have been read from the stream into lpvDest. + * Failure: An HRESULT error code, or E_FAIL if the read succeeded but the + * number of bytes read does not match. + */ +HRESULT WINAPI SHLWAPI_184(IStream *lpStream, LPVOID lpvDest, ULONG ulSize) +{ + ULONG ulRead; + HRESULT hRet; + + TRACE("(%p,%p,%ld)\n", lpStream, lpvDest, ulSize); + + hRet = IStream_Read(lpStream, lpvDest, ulSize, &ulRead); + + if (SUCCEEDED(hRet) && ulRead != ulSize) + hRet = E_FAIL; + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.166] + * + * Determine if a stream has 0 length. + * + * PARAMS + * lpStream [I] IStream object + * + * RETURNS + * TRUE: If the stream has 0 length + * FALSE: Otherwise. + */ +BOOL WINAPI SHIsEmptyStream(IStream *lpStream) +{ + STATSTG statstg; + BOOL bRet = TRUE; + + TRACE("(%p)\n", lpStream); + + memset(&statstg, 0, sizeof(statstg)); + + if(SUCCEEDED(IStream_Stat(lpStream, &statstg, 1))) + { + if(statstg.cbSize.QuadPart) + bRet = FALSE; /* Non-Zero */ + } + else + { + DWORD dwDummy; + + /* Try to read from the stream */ + if(SUCCEEDED(SHLWAPI_184(lpStream, &dwDummy, sizeof(dwDummy)))) + { + LARGE_INTEGER zero; + zero.QuadPart = 0; + + IStream_Seek(lpStream, zero, 0, NULL); + bRet = FALSE; /* Non-Zero */ + } + } + return bRet; +} + +/************************************************************************* + * @ [SHLWAPI.212] + * + * Call IStream_Write() on a stream. + * + * PARAMS + * lpStream [I] IStream object + * lpvSrc [I] Source for data to write + * ulSize [I] Size of data + * + * RETURNS + * Success: S_OK. ulSize bytes have been written to the stream from lpvSrc. + * Failure: An HRESULT error code, or E_FAIL if the write succeeded but the + * number of bytes written does not match. + */ +HRESULT WINAPI SHLWAPI_212(IStream *lpStream, LPCVOID lpvSrc, ULONG ulSize) +{ + ULONG ulWritten; + HRESULT hRet; + + TRACE("(%p,%p,%ld)\n", lpStream, lpvSrc, ulSize); + + hRet = IStream_Write(lpStream, lpvSrc, ulSize, &ulWritten); + + if (SUCCEEDED(hRet) && ulWritten != ulSize) + hRet = E_FAIL; + + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.213] + * + * Seek to the start of a stream. + * + * PARAMS + * lpStream [I] IStream object + * + * RETURNS + * Success: S_OK. The current position within the stream is updated + * Failure: An HRESULT error code. + */ +HRESULT WINAPI IStream_Reset(IStream *lpStream) +{ + LARGE_INTEGER zero; + TRACE("(%p)\n", lpStream); + zero.QuadPart = 0; + return IStream_Seek(lpStream, zero, 0, NULL); +} + +/************************************************************************* + * @ [SHLWAPI.214] + * + * Get the size of a stream. + * + * PARAMS + * lpStream [I] IStream object + * lpulSize [O] Destination for size + * + * RETURNS + * Success: S_OK. lpulSize contains the size of the stream. + * Failure: An HRESULT error code. + */ +HRESULT WINAPI IStream_Size(IStream *lpStream, ULARGE_INTEGER* lpulSize) +{ + STATSTG statstg; + HRESULT hRet; + + TRACE("(%p,%p)\n", lpStream, lpulSize); + + memset(&statstg, 0, sizeof(statstg)); + + hRet = IStream_Stat(lpStream, &statstg, 1); + + if (SUCCEEDED(hRet) && lpulSize) + *lpulSize = statstg.cbSize; + return hRet; +} diff --git a/reactos/lib/shlwapi/msgbox.c b/reactos/lib/shlwapi/msgbox.c index ec9a4a3c02c..dbf3f70d1da 100644 --- a/reactos/lib/shlwapi/msgbox.c +++ b/reactos/lib/shlwapi/msgbox.c @@ -1,296 +1,296 @@ -/* - * SHLWAPI message box functions - * - * Copyright 2004 Jon Griffiths - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define COM_NO_WINDOWS_H -#include "config.h" -#include "wine/port.h" - -#include <stdarg.h> -#include <string.h> - -#define NONAMELESSUNION -#define NONAMELESSSTRUCT -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "winreg.h" -#include "shlwapi.h" -#include "wine/unicode.h" -#include "wine/debug.h" -#include "resource.h" - - -WINE_DEFAULT_DEBUG_CHANNEL(shell); - -extern HINSTANCE shlwapi_hInstance; /* in shlwapi_main.c */ - -static const WCHAR szDontShowKey[] = { 'S','o','f','t','w','a','r','e','\\', - 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\', - 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', - 'E','x','p','l','o','r','e','r','\\','D','o','n','t','S','h','o','w', - 'M','e','T','h','i','s','D','i','a','l','o','g','A','g','a','i','n','\0' -}; - -INT_PTR WINAPI SHMessageBoxCheckExW(HWND,HINSTANCE,LPCWSTR,DLGPROC,LPARAM,INT_PTR,LPCWSTR); -INT_PTR WINAPI SHMessageBoxCheckW(HWND,LPCWSTR,LPCWSTR,DWORD,INT_PTR,LPCWSTR); - -/* Data held by each general message boxes */ -typedef struct tagDLGDATAEX -{ - DLGPROC dlgProc; /* User supplied DlgProc */ - LPARAM lParam; /* User supplied LPARAM for dlgProc */ - LPCWSTR lpszId; /* Name of reg key holding whether to skip */ -} DLGDATAEX; - -/* Dialogue procedure for general message boxes */ -static INT_PTR CALLBACK SHDlgProcEx(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - DLGDATAEX *d = (DLGDATAEX *)GetWindowLongPtrW(hDlg, DWLP_USER); - - TRACE("(%p,%u,%d,%ld) data %p\n", hDlg, uMsg, wParam, lParam, d); - - switch (uMsg) - { - case WM_INITDIALOG: - { - /* FIXME: Not sure where native stores its lParam */ - SetWindowLongPtrW(hDlg, DWLP_USER, lParam); - d = (DLGDATAEX *)lParam; - TRACE("WM_INITDIALOG: %p, %s,%p,%p\n", hDlg, debugstr_w(d->lpszId), - d->dlgProc, (void*)d->lParam); - if (d->dlgProc) - return d->dlgProc(hDlg, uMsg, wParam, d->lParam); - return TRUE; - } - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDYES: - wParam = MAKELONG(IDOK, HIWORD(wParam)); - /* Fall through ... */ - case IDNO: - if (LOWORD(wParam) == IDNO) - wParam = MAKELONG(IDCANCEL, HIWORD(wParam)); - /* Fall through ... */ - case IDOK: - case IDCANCEL: - - TRACE("WM_COMMAND: id=%s data=%p\n", - LOWORD(wParam) == IDOK ? "IDOK" : "IDCANCEL", d); - - if (SendMessageW(GetDlgItem(hDlg, IDC_ERR_DONT_SHOW), BM_GETCHECK, 0L, 0L)) - { - DWORD dwZero = 0; - - /* The user clicked 'don't show again', so set the key */ - SHRegSetUSValueW(szDontShowKey, d->lpszId, REG_DWORD, &dwZero, - sizeof(dwZero), SHREGSET_DEFAULT); - } - if (!d->dlgProc || !d->dlgProc(hDlg, uMsg, wParam, lParam)) - EndDialog(hDlg, wParam); - return TRUE; - } - break; - - default: - break; - } - - if (d && d->dlgProc) - return d->dlgProc(hDlg, uMsg, wParam, lParam); - return FALSE; -} - -/************************************************************************* - * @ [SHLWAPI.291] - * - * Pop up a 'Don't show this message again' dialogue box. - * - * PARAMS - * hWnd [I] Window to be the dialogues' parent - * hInst [I] Instance of the module holding the dialogue resource - * lpszName [I] Resource Id of the dialogue resource - * dlgProc [I] Dialog procedure, or NULL for default handling - * lParam [I] LPARAM to pass to dlgProc - * iRet [I] Value to return if dialogue is not shown - * lpszId [I] Name of registry subkey which determines whether to show the dialog - * - * RETURNS - * Success: The value returned from the dialogue procedure. - * Failure: iRet, if the dialogue resource could not be loaded or the dialogue - * should not be shown. - * - * NOTES - * Both lpszName and lpszId must be less than MAX_PATH in length. - */ -INT_PTR WINAPI SHMessageBoxCheckExA(HWND hWnd, HINSTANCE hInst, LPCSTR lpszName, - DLGPROC dlgProc, LPARAM lParam, INT_PTR iRet, - LPCSTR lpszId) -{ - WCHAR szNameBuff[MAX_PATH], szIdBuff[MAX_PATH]; - LPCWSTR szName = szNameBuff; - - if (HIWORD(lpszName)) - MultiByteToWideChar(CP_ACP, 0, lpszName, -1, szNameBuff, MAX_PATH); - else - szName = (LPCWSTR)lpszName; /* Resource Id or NULL */ - - MultiByteToWideChar(CP_ACP, 0, lpszId, -1, szIdBuff, MAX_PATH); - - return SHMessageBoxCheckExW(hWnd, hInst, szName, dlgProc, lParam, iRet, szIdBuff); -} - -/************************************************************************* - * @ [SHLWAPI.292] - * - * Unicode version of SHMessageBoxCheckExW. - */ -INT_PTR WINAPI SHMessageBoxCheckExW(HWND hWnd, HINSTANCE hInst, LPCWSTR lpszName, - DLGPROC dlgProc, LPARAM lParam, INT_PTR iRet, LPCWSTR lpszId) -{ - DLGDATAEX d; - - if (!SHRegGetBoolUSValueW(szDontShowKey, lpszId, FALSE, TRUE)) - return iRet; - - d.dlgProc = dlgProc; - d.lParam = lParam; - d.lpszId = lpszId; - return DialogBoxParamW(hInst, (LPCWSTR)lpszName, hWnd, SHDlgProcEx, (LPARAM)&d); -} - -/* Data held by each shlwapi message box */ -typedef struct tagDLGDATA -{ - LPCWSTR lpszTitle; /* User supplied message title */ - LPCWSTR lpszText; /* User supplied message text */ - DWORD dwType; /* Message box type */ -} DLGDATA; - -/* Dialogue procedure for shlwapi message boxes */ -static INT_PTR CALLBACK SHDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - TRACE("(%p,%u,%d,%ld)\n", hDlg, uMsg, wParam, lParam); - - switch (uMsg) - { - case WM_INITDIALOG: - { - DLGDATA *d = (DLGDATA *)lParam; - TRACE("WM_INITDIALOG: %p, %s,%s,%ld\n", hDlg, debugstr_w(d->lpszTitle), - debugstr_w(d->lpszText), d->dwType); - - SetWindowTextW(hDlg, d->lpszTitle); - SetWindowTextW(GetDlgItem(hDlg, IDS_ERR_USER_MSG), d->lpszText); - - /* Set buttons according to dwType */ - switch (d->dwType) - { - case 0: - ShowWindow(GetDlgItem(hDlg, IDCANCEL), FALSE); - /* FIXME: Move OK button to position of the Cancel button (cosmetic) */ - case 1: - ShowWindow(GetDlgItem(hDlg, IDYES), FALSE); - ShowWindow(GetDlgItem(hDlg, IDNO), FALSE); - break; - default: - ShowWindow(GetDlgItem(hDlg, IDOK), FALSE); - ShowWindow(GetDlgItem(hDlg, IDCANCEL), FALSE); - break; - } - return TRUE; - } - default: - break; - } - return FALSE; -} - -/************************************************************************* - * @ [SHLWAPI.185] - * - * Pop up a 'Don't show this message again' dialogue box. - * - * PARAMS - * hWnd [I] Window to be the dialogues' parent - * lpszText [I] Text of the message to show - * lpszTitle [I] Title of the dialogue box - * dwType [I] Type of dialogue buttons (See below) - * iRet [I] Value to return if dialogue is not shown - * lpszId [I] Name of registry subkey which determines whether to show the dialog - * - * RETURNS - * Success: The value returned from the dialogue procedure (e.g. IDOK). - * Failure: iRet, if the default dialogue resource could not be loaded or the - * dialogue should not be shown. - * - * NOTES - * - Both lpszTitle and lpszId must be less than MAX_PATH in length. - * - Possible values for dwType are: - *| Value Buttons - *| ----- ------- - *| 0 OK - *| 1 OK/Cancel - *| 2 Yes/No - */ -INT_PTR WINAPI SHMessageBoxCheckA(HWND hWnd, LPCSTR lpszText, LPCSTR lpszTitle, - DWORD dwType, INT_PTR iRet, LPCSTR lpszId) -{ - WCHAR szTitleBuff[MAX_PATH], szIdBuff[MAX_PATH]; - WCHAR *szTextBuff = NULL; - int iLen; - INT_PTR iRetVal; - - if (lpszTitle) - MultiByteToWideChar(CP_ACP, 0, lpszTitle, -1, szTitleBuff, MAX_PATH); - - if (lpszText) - { - iLen = MultiByteToWideChar(CP_ACP, 0, lpszText, -1, NULL, 0); - szTextBuff = HeapAlloc(GetProcessHeap(), 0, iLen * sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, lpszText, -1, szTextBuff, iLen); - } - - MultiByteToWideChar(CP_ACP, 0, lpszId, -1, szIdBuff, MAX_PATH); - - iRetVal = SHMessageBoxCheckW(hWnd, szTextBuff, lpszTitle ? szTitleBuff : NULL, - dwType, iRet, szIdBuff); - HeapFree(GetProcessHeap(), 0, szTextBuff); - return iRetVal; -} - -/************************************************************************* - * @ [SHLWAPI.191] - * - * Unicode version of SHMessageBoxCheckA. - */ -INT_PTR WINAPI SHMessageBoxCheckW(HWND hWnd, LPCWSTR lpszText, LPCWSTR lpszTitle, - DWORD dwType, INT_PTR iRet, LPCWSTR lpszId) -{ - DLGDATA d; - - d.lpszTitle = lpszTitle; - d.lpszText = lpszText; - d.dwType = dwType; - - return SHMessageBoxCheckExW(hWnd, shlwapi_hInstance, (LPCWSTR)IDD_ERR_DIALOG, - SHDlgProc, (LPARAM)&d, iRet, lpszId); -} +/* + * SHLWAPI message box functions + * + * Copyright 2004 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define COM_NO_WINDOWS_H +#include "config.h" +#include "wine/port.h" + +#include <stdarg.h> +#include <string.h> + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "shlwapi.h" +#include "wine/unicode.h" +#include "wine/debug.h" +#include "resource.h" + + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +extern HINSTANCE shlwapi_hInstance; /* in shlwapi_main.c */ + +static const WCHAR szDontShowKey[] = { 'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\', + 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'E','x','p','l','o','r','e','r','\\','D','o','n','t','S','h','o','w', + 'M','e','T','h','i','s','D','i','a','l','o','g','A','g','a','i','n','\0' +}; + +INT_PTR WINAPI SHMessageBoxCheckExW(HWND,HINSTANCE,LPCWSTR,DLGPROC,LPARAM,INT_PTR,LPCWSTR); +INT_PTR WINAPI SHMessageBoxCheckW(HWND,LPCWSTR,LPCWSTR,DWORD,INT_PTR,LPCWSTR); + +/* Data held by each general message boxes */ +typedef struct tagDLGDATAEX +{ + DLGPROC dlgProc; /* User supplied DlgProc */ + LPARAM lParam; /* User supplied LPARAM for dlgProc */ + LPCWSTR lpszId; /* Name of reg key holding whether to skip */ +} DLGDATAEX; + +/* Dialogue procedure for general message boxes */ +static INT_PTR CALLBACK SHDlgProcEx(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + DLGDATAEX *d = (DLGDATAEX *)GetWindowLongPtrW(hDlg, DWLP_USER); + + TRACE("(%p,%u,%d,%ld) data %p\n", hDlg, uMsg, wParam, lParam, d); + + switch (uMsg) + { + case WM_INITDIALOG: + { + /* FIXME: Not sure where native stores its lParam */ + SetWindowLongPtrW(hDlg, DWLP_USER, lParam); + d = (DLGDATAEX *)lParam; + TRACE("WM_INITDIALOG: %p, %s,%p,%p\n", hDlg, debugstr_w(d->lpszId), + d->dlgProc, (void*)d->lParam); + if (d->dlgProc) + return d->dlgProc(hDlg, uMsg, wParam, d->lParam); + return TRUE; + } + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDYES: + wParam = MAKELONG(IDOK, HIWORD(wParam)); + /* Fall through ... */ + case IDNO: + if (LOWORD(wParam) == IDNO) + wParam = MAKELONG(IDCANCEL, HIWORD(wParam)); + /* Fall through ... */ + case IDOK: + case IDCANCEL: + + TRACE("WM_COMMAND: id=%s data=%p\n", + LOWORD(wParam) == IDOK ? "IDOK" : "IDCANCEL", d); + + if (SendMessageW(GetDlgItem(hDlg, IDC_ERR_DONT_SHOW), BM_GETCHECK, 0L, 0L)) + { + DWORD dwZero = 0; + + /* The user clicked 'don't show again', so set the key */ + SHRegSetUSValueW(szDontShowKey, d->lpszId, REG_DWORD, &dwZero, + sizeof(dwZero), SHREGSET_DEFAULT); + } + if (!d->dlgProc || !d->dlgProc(hDlg, uMsg, wParam, lParam)) + EndDialog(hDlg, wParam); + return TRUE; + } + break; + + default: + break; + } + + if (d && d->dlgProc) + return d->dlgProc(hDlg, uMsg, wParam, lParam); + return FALSE; +} + +/************************************************************************* + * @ [SHLWAPI.291] + * + * Pop up a 'Don't show this message again' dialogue box. + * + * PARAMS + * hWnd [I] Window to be the dialogues' parent + * hInst [I] Instance of the module holding the dialogue resource + * lpszName [I] Resource Id of the dialogue resource + * dlgProc [I] Dialog procedure, or NULL for default handling + * lParam [I] LPARAM to pass to dlgProc + * iRet [I] Value to return if dialogue is not shown + * lpszId [I] Name of registry subkey which determines whether to show the dialog + * + * RETURNS + * Success: The value returned from the dialogue procedure. + * Failure: iRet, if the dialogue resource could not be loaded or the dialogue + * should not be shown. + * + * NOTES + * Both lpszName and lpszId must be less than MAX_PATH in length. + */ +INT_PTR WINAPI SHMessageBoxCheckExA(HWND hWnd, HINSTANCE hInst, LPCSTR lpszName, + DLGPROC dlgProc, LPARAM lParam, INT_PTR iRet, + LPCSTR lpszId) +{ + WCHAR szNameBuff[MAX_PATH], szIdBuff[MAX_PATH]; + LPCWSTR szName = szNameBuff; + + if (HIWORD(lpszName)) + MultiByteToWideChar(CP_ACP, 0, lpszName, -1, szNameBuff, MAX_PATH); + else + szName = (LPCWSTR)lpszName; /* Resource Id or NULL */ + + MultiByteToWideChar(CP_ACP, 0, lpszId, -1, szIdBuff, MAX_PATH); + + return SHMessageBoxCheckExW(hWnd, hInst, szName, dlgProc, lParam, iRet, szIdBuff); +} + +/************************************************************************* + * @ [SHLWAPI.292] + * + * Unicode version of SHMessageBoxCheckExW. + */ +INT_PTR WINAPI SHMessageBoxCheckExW(HWND hWnd, HINSTANCE hInst, LPCWSTR lpszName, + DLGPROC dlgProc, LPARAM lParam, INT_PTR iRet, LPCWSTR lpszId) +{ + DLGDATAEX d; + + if (!SHRegGetBoolUSValueW(szDontShowKey, lpszId, FALSE, TRUE)) + return iRet; + + d.dlgProc = dlgProc; + d.lParam = lParam; + d.lpszId = lpszId; + return DialogBoxParamW(hInst, (LPCWSTR)lpszName, hWnd, SHDlgProcEx, (LPARAM)&d); +} + +/* Data held by each shlwapi message box */ +typedef struct tagDLGDATA +{ + LPCWSTR lpszTitle; /* User supplied message title */ + LPCWSTR lpszText; /* User supplied message text */ + DWORD dwType; /* Message box type */ +} DLGDATA; + +/* Dialogue procedure for shlwapi message boxes */ +static INT_PTR CALLBACK SHDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + TRACE("(%p,%u,%d,%ld)\n", hDlg, uMsg, wParam, lParam); + + switch (uMsg) + { + case WM_INITDIALOG: + { + DLGDATA *d = (DLGDATA *)lParam; + TRACE("WM_INITDIALOG: %p, %s,%s,%ld\n", hDlg, debugstr_w(d->lpszTitle), + debugstr_w(d->lpszText), d->dwType); + + SetWindowTextW(hDlg, d->lpszTitle); + SetWindowTextW(GetDlgItem(hDlg, IDS_ERR_USER_MSG), d->lpszText); + + /* Set buttons according to dwType */ + switch (d->dwType) + { + case 0: + ShowWindow(GetDlgItem(hDlg, IDCANCEL), FALSE); + /* FIXME: Move OK button to position of the Cancel button (cosmetic) */ + case 1: + ShowWindow(GetDlgItem(hDlg, IDYES), FALSE); + ShowWindow(GetDlgItem(hDlg, IDNO), FALSE); + break; + default: + ShowWindow(GetDlgItem(hDlg, IDOK), FALSE); + ShowWindow(GetDlgItem(hDlg, IDCANCEL), FALSE); + break; + } + return TRUE; + } + default: + break; + } + return FALSE; +} + +/************************************************************************* + * @ [SHLWAPI.185] + * + * Pop up a 'Don't show this message again' dialogue box. + * + * PARAMS + * hWnd [I] Window to be the dialogues' parent + * lpszText [I] Text of the message to show + * lpszTitle [I] Title of the dialogue box + * dwType [I] Type of dialogue buttons (See below) + * iRet [I] Value to return if dialogue is not shown + * lpszId [I] Name of registry subkey which determines whether to show the dialog + * + * RETURNS + * Success: The value returned from the dialogue procedure (e.g. IDOK). + * Failure: iRet, if the default dialogue resource could not be loaded or the + * dialogue should not be shown. + * + * NOTES + * - Both lpszTitle and lpszId must be less than MAX_PATH in length. + * - Possible values for dwType are: + *| Value Buttons + *| ----- ------- + *| 0 OK + *| 1 OK/Cancel + *| 2 Yes/No + */ +INT_PTR WINAPI SHMessageBoxCheckA(HWND hWnd, LPCSTR lpszText, LPCSTR lpszTitle, + DWORD dwType, INT_PTR iRet, LPCSTR lpszId) +{ + WCHAR szTitleBuff[MAX_PATH], szIdBuff[MAX_PATH]; + WCHAR *szTextBuff = NULL; + int iLen; + INT_PTR iRetVal; + + if (lpszTitle) + MultiByteToWideChar(CP_ACP, 0, lpszTitle, -1, szTitleBuff, MAX_PATH); + + if (lpszText) + { + iLen = MultiByteToWideChar(CP_ACP, 0, lpszText, -1, NULL, 0); + szTextBuff = HeapAlloc(GetProcessHeap(), 0, iLen * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, lpszText, -1, szTextBuff, iLen); + } + + MultiByteToWideChar(CP_ACP, 0, lpszId, -1, szIdBuff, MAX_PATH); + + iRetVal = SHMessageBoxCheckW(hWnd, szTextBuff, lpszTitle ? szTitleBuff : NULL, + dwType, iRet, szIdBuff); + HeapFree(GetProcessHeap(), 0, szTextBuff); + return iRetVal; +} + +/************************************************************************* + * @ [SHLWAPI.191] + * + * Unicode version of SHMessageBoxCheckA. + */ +INT_PTR WINAPI SHMessageBoxCheckW(HWND hWnd, LPCWSTR lpszText, LPCWSTR lpszTitle, + DWORD dwType, INT_PTR iRet, LPCWSTR lpszId) +{ + DLGDATA d; + + d.lpszTitle = lpszTitle; + d.lpszText = lpszText; + d.dwType = dwType; + + return SHMessageBoxCheckExW(hWnd, shlwapi_hInstance, (LPCWSTR)IDD_ERR_DIALOG, + SHDlgProc, (LPARAM)&d, iRet, lpszId); +} diff --git a/reactos/lib/shlwapi/ordinal.c b/reactos/lib/shlwapi/ordinal.c index 6fafe1dbb06..ccc95b63482 100644 --- a/reactos/lib/shlwapi/ordinal.c +++ b/reactos/lib/shlwapi/ordinal.c @@ -1,4296 +1,4296 @@ -/* - * SHLWAPI ordinal functions - * - * Copyright 1997 Marcus Meissner - * 1998 Jürgen Schmied - * 2001-2003 Jon Griffiths - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define COM_NO_WINDOWS_H -#include "config.h" -#include "wine/port.h" - -#include <stdarg.h> -#include <stdio.h> -#include <string.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "winnls.h" -#include "objbase.h" -#include "docobj.h" -#include "exdisp.h" -#include "shlguid.h" -#include "wingdi.h" -#include "shlobj.h" -#include "shellapi.h" -#include "commdlg.h" -#include "wine/unicode.h" -#include "winreg.h" -#include "wine/debug.h" -#include "shlwapi.h" - - -WINE_DEFAULT_DEBUG_CHANNEL(shell); - -/* Get a function pointer from a DLL handle */ -#define GET_FUNC(func, module, name, fail) \ - do { \ - if (!func) { \ - if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \ - func = (fn##func)GetProcAddress(SHLWAPI_h##module, name); \ - if (!func) return fail; \ - } \ - } while (0) - -/* DLL handles for late bound calls */ -extern HINSTANCE shlwapi_hInstance; -extern HMODULE SHLWAPI_hshell32; -extern HMODULE SHLWAPI_hwinmm; -extern HMODULE SHLWAPI_hcomdlg32; -extern HMODULE SHLWAPI_hcomctl32; -extern HMODULE SHLWAPI_hmpr; -extern HMODULE SHLWAPI_hurlmon; -extern HMODULE SHLWAPI_hversion; - -extern DWORD SHLWAPI_ThreadRef_index; - -/* following is GUID for IObjectWithSite::SetSite -- see _174 */ -static DWORD id1[4] = {0xfc4801a3, 0x11cf2ba9, 0xaa0029a2, 0x52733d00}; -/* following is GUID for IPersistMoniker::GetClassID -- see _174 */ -static DWORD id2[4] = {0x79eac9ee, 0x11cebaf9, 0xaa00828c, 0x0ba94b00}; - -/* Function pointers for GET_FUNC macro; these need to be global because of gcc bug */ -typedef LPITEMIDLIST (WINAPI *fnpSHBrowseForFolderW)(LPBROWSEINFOW); -static fnpSHBrowseForFolderW pSHBrowseForFolderW; -typedef BOOL (WINAPI *fnpPlaySoundW)(LPCWSTR, HMODULE, DWORD); -static fnpPlaySoundW pPlaySoundW; -typedef DWORD (WINAPI *fnpSHGetFileInfoW)(LPCWSTR,DWORD,SHFILEINFOW*,UINT,UINT); -static fnpSHGetFileInfoW pSHGetFileInfoW; -typedef UINT (WINAPI *fnpDragQueryFileW)(HDROP, UINT, LPWSTR, UINT); -static fnpDragQueryFileW pDragQueryFileW; -typedef BOOL (WINAPI *fnpSHGetPathFromIDListW)(LPCITEMIDLIST, LPWSTR); -static fnpSHGetPathFromIDListW pSHGetPathFromIDListW; -typedef BOOL (WINAPI *fnpShellExecuteExW)(LPSHELLEXECUTEINFOW); -static fnpShellExecuteExW pShellExecuteExW; -typedef HICON (WINAPI *fnpSHFileOperationW)(LPSHFILEOPSTRUCTW); -static fnpSHFileOperationW pSHFileOperationW; -typedef UINT (WINAPI *fnpExtractIconExW)(LPCWSTR, INT,HICON *,HICON *, UINT); -static fnpExtractIconExW pExtractIconExW; -typedef BOOL (WINAPI *fnpSHGetNewLinkInfoW)(LPCWSTR, LPCWSTR, LPCWSTR, BOOL*, UINT); -static fnpSHGetNewLinkInfoW pSHGetNewLinkInfoW; -typedef HRESULT (WINAPI *fnpSHDefExtractIconW)(LPCWSTR, int, UINT, HICON*, HICON*, UINT); -static fnpSHDefExtractIconW pSHDefExtractIconW; -typedef HICON (WINAPI *fnpExtractIconW)(HINSTANCE, LPCWSTR, UINT); -static fnpExtractIconW pExtractIconW; -typedef BOOL (WINAPI *fnpGetSaveFileNameW)(LPOPENFILENAMEW); -static fnpGetSaveFileNameW pGetSaveFileNameW; -typedef DWORD (WINAPI *fnpWNetRestoreConnectionW)(HWND, LPWSTR); -static fnpWNetRestoreConnectionW pWNetRestoreConnectionW; -typedef DWORD (WINAPI *fnpWNetGetLastErrorW)(LPDWORD, LPWSTR, DWORD, LPWSTR, DWORD); -static fnpWNetGetLastErrorW pWNetGetLastErrorW; -typedef BOOL (WINAPI *fnpPageSetupDlgW)(LPPAGESETUPDLGW); -static fnpPageSetupDlgW pPageSetupDlgW; -typedef BOOL (WINAPI *fnpPrintDlgW)(LPPRINTDLGW); -static fnpPrintDlgW pPrintDlgW; -typedef BOOL (WINAPI *fnpGetOpenFileNameW)(LPOPENFILENAMEW); -static fnpGetOpenFileNameW pGetOpenFileNameW; -typedef DWORD (WINAPI *fnpGetFileVersionInfoSizeW)(LPCWSTR,LPDWORD); -static fnpGetFileVersionInfoSizeW pGetFileVersionInfoSizeW; -typedef BOOL (WINAPI *fnpGetFileVersionInfoW)(LPCWSTR,DWORD,DWORD,LPVOID); -static fnpGetFileVersionInfoW pGetFileVersionInfoW; -typedef WORD (WINAPI *fnpVerQueryValueW)(LPVOID,LPCWSTR,LPVOID*,UINT*); -static fnpVerQueryValueW pVerQueryValueW; -typedef BOOL (WINAPI *fnpCOMCTL32_417)(HDC,INT,INT,UINT,const RECT*,LPCWSTR,UINT,const INT*); -static fnpCOMCTL32_417 pCOMCTL32_417; -typedef HRESULT (WINAPI *fnpDllGetVersion)(DLLVERSIONINFO*); -static fnpDllGetVersion pDllGetVersion; -typedef HRESULT (WINAPI *fnpCreateFormatEnumerator)(UINT,FORMATETC*,IEnumFORMATETC**); -static fnpCreateFormatEnumerator pCreateFormatEnumerator; -typedef HRESULT (WINAPI *fnpRegisterFormatEnumerator)(LPBC,IEnumFORMATETC*,DWORD); -static fnpRegisterFormatEnumerator pRegisterFormatEnumerator; - -HRESULT WINAPI IUnknown_QueryService(IUnknown*,REFGUID,REFIID,LPVOID*); -HRESULT WINAPI SHInvokeCommand(HWND,IShellFolder*,LPCITEMIDLIST,BOOL); -HRESULT WINAPI CLSIDFromStringWrap(LPCWSTR,CLSID*); -BOOL WINAPI SHAboutInfoW(LPWSTR,DWORD); - -/* - NOTES: Most functions exported by ordinal seem to be superflous. - The reason for these functions to be there is to provide a wrapper - for unicode functions to provide these functions on systems without - unicode functions eg. win95/win98. Since we have such functions we just - call these. If running Wine with native DLL's, some late bound calls may - fail. However, it is better to implement the functions in the forward DLL - and recommend the builtin rather than reimplementing the calls here! -*/ - -/************************************************************************* - * SHLWAPI_DupSharedHandle - * - * Internal implemetation of SHLWAPI_11. - */ -static -HANDLE WINAPI SHLWAPI_DupSharedHandle(HANDLE hShared, DWORD dwDstProcId, - DWORD dwSrcProcId, DWORD dwAccess, - DWORD dwOptions) -{ - HANDLE hDst, hSrc; - DWORD dwMyProcId = GetCurrentProcessId(); - HANDLE hRet = NULL; - - TRACE("(%p,%ld,%ld,%08lx,%08lx)\n", hShared, dwDstProcId, dwSrcProcId, - dwAccess, dwOptions); - - /* Get dest process handle */ - if (dwDstProcId == dwMyProcId) - hDst = GetCurrentProcess(); - else - hDst = OpenProcess(PROCESS_DUP_HANDLE, 0, dwDstProcId); - - if (hDst) - { - /* Get src process handle */ - if (dwSrcProcId == dwMyProcId) - hSrc = GetCurrentProcess(); - else - hSrc = OpenProcess(PROCESS_DUP_HANDLE, 0, dwSrcProcId); - - if (hSrc) - { - /* Make handle available to dest process */ - if (!DuplicateHandle(hDst, hShared, hSrc, &hRet, - dwAccess, 0, dwOptions | DUPLICATE_SAME_ACCESS)) - hRet = NULL; - - if (dwSrcProcId != dwMyProcId) - CloseHandle(hSrc); - } - - if (dwDstProcId != dwMyProcId) - CloseHandle(hDst); - } - - TRACE("Returning handle %p\n", hRet); - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.7] - * - * Create a block of sharable memory and initialise it with data. - * - * PARAMS - * lpvData [I] Pointer to data to write - * dwSize [I] Size of data - * dwProcId [I] ID of process owning data - * - * RETURNS - * Success: A shared memory handle - * Failure: NULL - * - * NOTES - * Ordinals 7-11 provide a set of calls to create shared memory between a - * group of processes. The shared memory is treated opaquely in that its size - * is not exposed to clients who map it. This is accomplished by storing - * the size of the map as the first DWORD of mapped data, and then offsetting - * the view pointer returned by this size. - * - */ -HANDLE WINAPI SHAllocShared(LPCVOID lpvData, DWORD dwSize, DWORD dwProcId) -{ - HANDLE hMap; - LPVOID pMapped; - HANDLE hRet = NULL; - - TRACE("(%p,%ld,%ld)\n", lpvData, dwSize, dwProcId); - - /* Create file mapping of the correct length */ - hMap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, FILE_MAP_READ, 0, - dwSize + sizeof(dwSize), NULL); - if (!hMap) - return hRet; - - /* Get a view in our process address space */ - pMapped = MapViewOfFile(hMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); - - if (pMapped) - { - /* Write size of data, followed by the data, to the view */ - *((DWORD*)pMapped) = dwSize; - if (lpvData) - memcpy((char *) pMapped + sizeof(dwSize), lpvData, dwSize); - - /* Release view. All further views mapped will be opaque */ - UnmapViewOfFile(pMapped); - hRet = SHLWAPI_DupSharedHandle(hMap, dwProcId, - GetCurrentProcessId(), FILE_MAP_ALL_ACCESS, - DUPLICATE_SAME_ACCESS); - } - - CloseHandle(hMap); - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.8] - * - * Get a pointer to a block of shared memory from a shared memory handle. - * - * PARAMS - * hShared [I] Shared memory handle - * dwProcId [I] ID of process owning hShared - * - * RETURNS - * Success: A pointer to the shared memory - * Failure: NULL - * - */ -PVOID WINAPI SHLockShared(HANDLE hShared, DWORD dwProcId) -{ - HANDLE hDup; - LPVOID pMapped; - - TRACE("(%p %ld)\n", hShared, dwProcId); - - /* Get handle to shared memory for current process */ - hDup = SHLWAPI_DupSharedHandle(hShared, dwProcId, GetCurrentProcessId(), - FILE_MAP_ALL_ACCESS, 0); - /* Get View */ - pMapped = MapViewOfFile(hDup, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); - CloseHandle(hDup); - - if (pMapped) - return (char *) pMapped + sizeof(DWORD); /* Hide size */ - return NULL; -} - -/************************************************************************* - * @ [SHLWAPI.9] - * - * Release a pointer to a block of shared memory. - * - * PARAMS - * lpView [I] Shared memory pointer - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - */ -BOOL WINAPI SHUnlockShared(LPVOID lpView) -{ - TRACE("(%p)\n", lpView); - return UnmapViewOfFile((char *) lpView - sizeof(DWORD)); /* Include size */ -} - -/************************************************************************* - * @ [SHLWAPI.10] - * - * Destroy a block of sharable memory. - * - * PARAMS - * hShared [I] Shared memory handle - * dwProcId [I] ID of process owning hShared - * - * RETURNS - * Success: TRUE - * Failure: FALSE - * - */ -BOOL WINAPI SHFreeShared(HANDLE hShared, DWORD dwProcId) -{ - HANDLE hClose; - - TRACE("(%p %ld)\n", hShared, dwProcId); - - /* Get a copy of the handle for our process, closing the source handle */ - hClose = SHLWAPI_DupSharedHandle(hShared, dwProcId, GetCurrentProcessId(), - FILE_MAP_ALL_ACCESS,DUPLICATE_CLOSE_SOURCE); - /* Close local copy */ - return CloseHandle(hClose); -} - -/************************************************************************* - * @ [SHLWAPI.11] - * - * Copy a sharable memory handle from one process to another. - * - * PARAMS - * hShared [I] Shared memory handle to duplicate - * dwDstProcId [I] ID of the process wanting the duplicated handle - * dwSrcProcId [I] ID of the process owning hShared - * dwAccess [I] Desired DuplicateHandle() access - * dwOptions [I] Desired DuplicateHandle() options - * - * RETURNS - * Success: A handle suitable for use by the dwDstProcId process. - * Failure: A NULL handle. - * - */ -HANDLE WINAPI SHMapHandle(HANDLE hShared, DWORD dwDstProcId, DWORD dwSrcProcId, - DWORD dwAccess, DWORD dwOptions) -{ - HANDLE hRet; - - hRet = SHLWAPI_DupSharedHandle(hShared, dwDstProcId, dwSrcProcId, - dwAccess, dwOptions); - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.13] - * - * Create and register a clipboard enumerator for a web browser. - * - * PARAMS - * lpBC [I] Binding context - * lpUnknown [I] An object exposing the IWebBrowserApp interface - * - * RETURNS - * Success: S_OK. - * Failure: An HRESULT error code. - * - * NOTES - * The enumerator is stored as a property of the web browser. If it does not - * yet exist, it is created and set before being registered. - */ -HRESULT WINAPI RegisterDefaultAcceptHeaders(LPBC lpBC, IUnknown *lpUnknown) -{ - static const WCHAR szProperty[] = { '{','D','0','F','C','A','4','2','0', - '-','D','3','F','5','-','1','1','C','F', '-','B','2','1','1','-','0', - '0','A','A','0','0','4','A','E','8','3','7','}','\0' }; - IEnumFORMATETC* pIEnumFormatEtc = NULL; - VARIANTARG var; - HRESULT hRet; - IWebBrowserApp* pBrowser = NULL; - - TRACE("(%p, %p)\n", lpBC, lpUnknown); - - /* Get An IWebBrowserApp interface from lpUnknown */ - hRet = IUnknown_QueryService(lpUnknown, &IID_IWebBrowserApp, &IID_IWebBrowserApp, (PVOID)&pBrowser); - if (FAILED(hRet) || !pBrowser) - return E_NOINTERFACE; - - V_VT(&var) = VT_EMPTY; - - /* The property we get is the browsers clipboard enumerator */ - hRet = IWebBrowserApp_GetProperty(pBrowser, (BSTR)szProperty, &var); - if (FAILED(hRet)) - return hRet; - - if (V_VT(&var) == VT_EMPTY) - { - /* Iterate through accepted documents and RegisterClipBoardFormatA() them */ - char szKeyBuff[128], szValueBuff[128]; - DWORD dwKeySize, dwValueSize, dwRet = 0, dwCount = 0, dwNumValues, dwType; - FORMATETC* formatList, *format; - HKEY hDocs; - - TRACE("Registering formats and creating IEnumFORMATETC instance\n"); - - if (!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\Current" - "Version\\Internet Settings\\Accepted Documents", &hDocs)) - return E_FAIL; - - /* Get count of values in key */ - while (!dwRet) - { - dwKeySize = sizeof(szKeyBuff); - dwRet = RegEnumValueA(hDocs,dwCount,szKeyBuff,&dwKeySize,0,&dwType,0,0); - dwCount++; - } - - dwNumValues = dwCount; - - /* Note: dwCount = number of items + 1; The extra item is the end node */ - format = formatList = HeapAlloc(GetProcessHeap(), 0, dwCount * sizeof(FORMATETC)); - if (!formatList) - return E_OUTOFMEMORY; - - if (dwNumValues > 1) - { - dwRet = 0; - dwCount = 0; - - dwNumValues--; - - /* Register clipboard formats for the values and populate format list */ - while(!dwRet && dwCount < dwNumValues) - { - dwKeySize = sizeof(szKeyBuff); - dwValueSize = sizeof(szValueBuff); - dwRet = RegEnumValueA(hDocs, dwCount, szKeyBuff, &dwKeySize, 0, &dwType, - (PBYTE)szValueBuff, &dwValueSize); - if (!dwRet) - return E_FAIL; - - format->cfFormat = RegisterClipboardFormatA(szValueBuff); - format->ptd = NULL; - format->dwAspect = 1; - format->lindex = 4; - format->tymed = -1; - - format++; - dwCount++; - } - } - - /* Terminate the (maybe empty) list, last entry has a cfFormat of 0 */ - format->cfFormat = 0; - format->ptd = NULL; - format->dwAspect = 1; - format->lindex = 4; - format->tymed = -1; - - /* Create a clipboard enumerator */ - GET_FUNC(pCreateFormatEnumerator, urlmon, "CreateFormatEnumerator", E_FAIL); - hRet = pCreateFormatEnumerator(dwNumValues, formatList, &pIEnumFormatEtc); - - if (FAILED(hRet) || !pIEnumFormatEtc) - return hRet; - - /* Set our enumerator as the browsers property */ - V_VT(&var) = VT_UNKNOWN; - V_UNKNOWN(&var) = (IUnknown*)pIEnumFormatEtc; - - hRet = IWebBrowserApp_PutProperty(pBrowser, (BSTR)szProperty, var); - if (FAILED(hRet)) - { - IEnumFORMATETC_Release(pIEnumFormatEtc); - goto RegisterDefaultAcceptHeaders_Exit; - } - } - - if (V_VT(&var) == VT_UNKNOWN) - { - /* Our variant is holding the clipboard enumerator */ - IUnknown* pIUnknown = V_UNKNOWN(&var); - IEnumFORMATETC* pClone = NULL; - - TRACE("Retrieved IEnumFORMATETC property\n"); - - /* Get an IEnumFormatEtc interface from the variants value */ - pIEnumFormatEtc = NULL; - hRet = IUnknown_QueryInterface(pIUnknown, &IID_IEnumFORMATETC, - (PVOID)&pIEnumFormatEtc); - if (!hRet && pIEnumFormatEtc) - { - /* Clone and register the enumerator */ - hRet = IEnumFORMATETC_Clone(pIEnumFormatEtc, &pClone); - if (!hRet && pClone) - { - GET_FUNC(pRegisterFormatEnumerator, urlmon, "RegisterFormatEnumerator", E_FAIL); - pRegisterFormatEnumerator(lpBC, pClone, 0); - - IEnumFORMATETC_Release(pClone); - } - - /* Release the IEnumFormatEtc interface */ - IEnumFORMATETC_Release(pIUnknown); - } - IUnknown_Release(V_UNKNOWN(&var)); - } - -RegisterDefaultAcceptHeaders_Exit: - IWebBrowserApp_Release(pBrowser); - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.15] - * - * Get Explorers "AcceptLanguage" setting. - * - * PARAMS - * langbuf [O] Destination for language string - * buflen [I] Length of langbuf - * [0] Success: used length of langbuf - * - * RETURNS - * Success: S_OK. langbuf is set to the language string found. - * Failure: E_FAIL, If any arguments are invalid, error occurred, or Explorer - * does not contain the setting. - * E_INVALIDARG, If the buffer is not big enough - */ -HRESULT WINAPI GetAcceptLanguagesW( LPWSTR langbuf, LPDWORD buflen) -{ - static const WCHAR szkeyW[] = { - 'S','o','f','t','w','a','r','e','\\', - 'M','i','c','r','o','s','o','f','t','\\', - 'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\', - 'I','n','t','e','r','n','a','t','i','o','n','a','l',0}; - static const WCHAR valueW[] = { - 'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0}; - static const WCHAR enusW[] = {'e','n','-','u','s',0}; - DWORD mystrlen, mytype; - HKEY mykey; - HRESULT retval; - LCID mylcid; - WCHAR *mystr; - - if(!langbuf || !buflen || !*buflen) - return E_FAIL; - - mystrlen = (*buflen > 20) ? *buflen : 20 ; - mystr = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * mystrlen); - RegOpenKeyW(HKEY_CURRENT_USER, szkeyW, &mykey); - if(RegQueryValueExW(mykey, valueW, 0, &mytype, (PBYTE)mystr, &mystrlen)) { - /* Did not find value */ - mylcid = GetUserDefaultLCID(); - /* somehow the mylcid translates into "en-us" - * this is similar to "LOCALE_SABBREVLANGNAME" - * which could be gotten via GetLocaleInfo. - * The only problem is LOCALE_SABBREVLANGUAGE" is - * a 3 char string (first 2 are country code and third is - * letter for "sublanguage", which does not come close to - * "en-us" - */ - lstrcpyW(mystr, enusW); - mystrlen = lstrlenW(mystr); - } else { - /* handle returned string */ - FIXME("missing code\n"); - } - memcpy( langbuf, mystr, min(*buflen,strlenW(mystr)+1)*sizeof(WCHAR) ); - - if(*buflen > strlenW(mystr)) { - *buflen = strlenW(mystr); - retval = S_OK; - } else { - *buflen = 0; - retval = E_INVALIDARG; - SetLastError(ERROR_INSUFFICIENT_BUFFER); - } - RegCloseKey(mykey); - HeapFree(GetProcessHeap(), 0, mystr); - return retval; -} - -/************************************************************************* - * @ [SHLWAPI.14] - * - * Ascii version of GetAcceptLanguagesW. - */ -HRESULT WINAPI GetAcceptLanguagesA( LPSTR langbuf, LPDWORD buflen) -{ - WCHAR *langbufW; - DWORD buflenW, convlen; - HRESULT retval; - - if(!langbuf || !buflen || !*buflen) return E_FAIL; - - buflenW = *buflen; - langbufW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * buflenW); - retval = GetAcceptLanguagesW(langbufW, &buflenW); - - /* FIXME: this is wrong, the string may not be null-terminated */ - convlen = WideCharToMultiByte(CP_ACP, 0, langbufW, -1, langbuf, - *buflen, NULL, NULL); - *buflen = buflenW ? convlen : 0; - - HeapFree(GetProcessHeap(), 0, langbufW); - return retval; -} - -/************************************************************************* - * @ [SHLWAPI.23] - * - * Convert a GUID to a string. - * - * PARAMS - * guid [I] GUID to convert - * lpszDest [O] Destination for string - * cchMax [I] Length of output buffer - * - * RETURNS - * The length of the string created. - */ -INT WINAPI SHStringFromGUIDA(REFGUID guid, LPSTR lpszDest, INT cchMax) -{ - char xguid[40]; - INT iLen; - - TRACE("(%s,%p,%d)\n", debugstr_guid(guid), lpszDest, cchMax); - - sprintf(xguid, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", - guid->Data1, guid->Data2, guid->Data3, - guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], - guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); - - iLen = strlen(xguid) + 1; - - if (iLen > cchMax) - return 0; - memcpy(lpszDest, xguid, iLen); - return iLen; -} - -/************************************************************************* - * @ [SHLWAPI.24] - * - * Convert a GUID to a string. - * - * PARAMS - * guid [I] GUID to convert - * str [O] Destination for string - * cmax [I] Length of output buffer - * - * RETURNS - * The length of the string created. - */ -INT WINAPI SHStringFromGUIDW(REFGUID guid, LPWSTR lpszDest, INT cchMax) -{ - WCHAR xguid[40]; - INT iLen; - static const WCHAR wszFormat[] = {'{','%','0','8','l','X','-','%','0','4','X','-','%','0','4','X','-', - '%','0','2','X','%','0','2','X','-','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2', - 'X','%','0','2','X','%','0','2','X','}',0}; - - TRACE("(%s,%p,%d)\n", debugstr_guid(guid), lpszDest, cchMax); - - sprintfW(xguid, wszFormat, guid->Data1, guid->Data2, guid->Data3, - guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], - guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); - - iLen = strlenW(xguid) + 1; - - if (iLen > cchMax) - return 0; - memcpy(lpszDest, xguid, iLen*sizeof(WCHAR)); - return iLen; -} - -/************************************************************************* - * @ [SHLWAPI.29] - * - * Determine if a Unicode character is a space. - * - * PARAMS - * wc [I] Character to check. - * - * RETURNS - * TRUE, if wc is a space, - * FALSE otherwise. - */ -BOOL WINAPI IsCharSpaceW(WCHAR wc) -{ - WORD CharType; - - return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_SPACE); -} - -/************************************************************************* - * @ [SHLWAPI.30] - * - * Determine if a Unicode character is a blank. - * - * PARAMS - * wc [I] Character to check. - * - * RETURNS - * TRUE, if wc is a blank, - * FALSE otherwise. - * - */ -BOOL WINAPI IsCharBlankW(WCHAR wc) -{ - WORD CharType; - - return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_BLANK); -} - -/************************************************************************* - * @ [SHLWAPI.31] - * - * Determine if a Unicode character is punctuation. - * - * PARAMS - * wc [I] Character to check. - * - * RETURNS - * TRUE, if wc is punctuation, - * FALSE otherwise. - */ -BOOL WINAPI IsCharPunctW(WCHAR wc) -{ - WORD CharType; - - return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_PUNCT); -} - -/************************************************************************* - * @ [SHLWAPI.32] - * - * Determine if a Unicode character is a control character. - * - * PARAMS - * wc [I] Character to check. - * - * RETURNS - * TRUE, if wc is a control character, - * FALSE otherwise. - */ -BOOL WINAPI IsCharCntrlW(WCHAR wc) -{ - WORD CharType; - - return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_CNTRL); -} - -/************************************************************************* - * @ [SHLWAPI.33] - * - * Determine if a Unicode character is a digit. - * - * PARAMS - * wc [I] Character to check. - * - * RETURNS - * TRUE, if wc is a digit, - * FALSE otherwise. - */ -BOOL WINAPI IsCharDigitW(WCHAR wc) -{ - WORD CharType; - - return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_DIGIT); -} - -/************************************************************************* - * @ [SHLWAPI.34] - * - * Determine if a Unicode character is a hex digit. - * - * PARAMS - * wc [I] Character to check. - * - * RETURNS - * TRUE, if wc is a hex digit, - * FALSE otherwise. - */ -BOOL WINAPI IsCharXDigitW(WCHAR wc) -{ - WORD CharType; - - return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_XDIGIT); -} - -/************************************************************************* - * @ [SHLWAPI.35] - * - */ -BOOL WINAPI GetStringType3ExW(LPWSTR lpszStr, DWORD dwLen, LPVOID p3) -{ - FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(lpszStr), dwLen, p3); - return TRUE; -} - -/************************************************************************* - * @ [SHLWAPI.36] - * - * Insert a bitmap menu item at the bottom of a menu. - * - * PARAMS - * hMenu [I] Menu to insert into - * flags [I] Flags for insertion - * id [I] Menu ID of the item - * str [I] Menu text for the item - * - * RETURNS - * Success: TRUE, the item is inserted into the menu - * Failure: FALSE, if any parameter is invalid - */ -BOOL WINAPI AppendMenuWrapW(HMENU hMenu, UINT flags, UINT id, LPCWSTR str) -{ - TRACE("(%p,0x%08x,0x%08x,%s)\n",hMenu, flags, id, debugstr_w(str)); - return InsertMenuW(hMenu, -1, flags | MF_BITMAP, id, str); -} - -/************************************************************************* - * @ [SHLWAPI.74] - * - * Get the text from a given dialog item. - * - * PARAMS - * hWnd [I] Handle of dialog - * nItem [I] Index of item - * lpsDest [O] Buffer for receiving window text - * nDestLen [I] Length of buffer. - * - * RETURNS - * Success: The length of the returned text. - * Failure: 0. - */ -INT WINAPI GetDlgItemTextWrapW(HWND hWnd, INT nItem, LPWSTR lpsDest,INT nDestLen) -{ - HWND hItem = GetDlgItem(hWnd, nItem); - - if (hItem) - return GetWindowTextW(hItem, lpsDest, nDestLen); - if (nDestLen) - *lpsDest = (WCHAR)'\0'; - return 0; -} - -/************************************************************************* - * @ [SHLWAPI.138] - * - * Set the text of a given dialog item. - * - * PARAMS - * hWnd [I] Handle of dialog - * iItem [I] Index of item - * lpszText [O] Text to set - * - * RETURNS - * Success: TRUE. The text of the dialog is set to lpszText. - * Failure: FALSE, Otherwise. - */ -BOOL WINAPI SetDlgItemTextWrapW(HWND hWnd, INT iItem, LPCWSTR lpszText) -{ - HWND hWndItem = GetDlgItem(hWnd, iItem); - if (hWndItem) - return SetWindowTextW(hWndItem, lpszText); - return FALSE; -} - -/************************************************************************* - * @ [SHLWAPI.151] - * - * Compare two Ascii strings up to a given length. - * - * PARAMS - * lpszSrc [I] Source string - * lpszCmp [I] String to compare to lpszSrc - * len [I] Maximum length - * - * RETURNS - * A number greater than, less than or equal to 0 depending on whether - * lpszSrc is greater than, less than or equal to lpszCmp. - */ -DWORD WINAPI StrCmpNCA(LPCSTR lpszSrc, LPCSTR lpszCmp, INT len) -{ - return strncmp(lpszSrc, lpszCmp, len); -} - -/************************************************************************* - * @ [SHLWAPI.152] - * - * Unicode version of StrCmpNCA. - */ -DWORD WINAPI StrCmpNCW(LPCWSTR lpszSrc, LPCWSTR lpszCmp, INT len) -{ - return strncmpW(lpszSrc, lpszCmp, len); -} - -/************************************************************************* - * @ [SHLWAPI.153] - * - * Compare two Ascii strings up to a given length, ignoring case. - * - * PARAMS - * lpszSrc [I] Source string - * lpszCmp [I] String to compare to lpszSrc - * len [I] Maximum length - * - * RETURNS - * A number greater than, less than or equal to 0 depending on whether - * lpszSrc is greater than, less than or equal to lpszCmp. - */ -DWORD WINAPI StrCmpNICA(LPCSTR lpszSrc, LPCSTR lpszCmp, DWORD len) -{ - return strncasecmp(lpszSrc, lpszCmp, len); -} - -/************************************************************************* - * @ [SHLWAPI.154] - * - * Unicode version of StrCmpNICA. - */ -DWORD WINAPI StrCmpNICW(LPCWSTR lpszSrc, LPCWSTR lpszCmp, DWORD len) -{ - return strncmpiW(lpszSrc, lpszCmp, len); -} - -/************************************************************************* - * @ [SHLWAPI.155] - * - * Compare two Ascii strings. - * - * PARAMS - * lpszSrc [I] Source string - * lpszCmp [I] String to compare to lpszSrc - * - * RETURNS - * A number greater than, less than or equal to 0 depending on whether - * lpszSrc is greater than, less than or equal to lpszCmp. - */ -DWORD WINAPI StrCmpCA(LPCSTR lpszSrc, LPCSTR lpszCmp) -{ - return strcmp(lpszSrc, lpszCmp); -} - -/************************************************************************* - * @ [SHLWAPI.156] - * - * Unicode version of StrCmpCA. - */ -DWORD WINAPI StrCmpCW(LPCWSTR lpszSrc, LPCWSTR lpszCmp) -{ - return strcmpW(lpszSrc, lpszCmp); -} - -/************************************************************************* - * @ [SHLWAPI.157] - * - * Compare two Ascii strings, ignoring case. - * - * PARAMS - * lpszSrc [I] Source string - * lpszCmp [I] String to compare to lpszSrc - * - * RETURNS - * A number greater than, less than or equal to 0 depending on whether - * lpszSrc is greater than, less than or equal to lpszCmp. - */ -DWORD WINAPI StrCmpICA(LPCSTR lpszSrc, LPCSTR lpszCmp) -{ - return strcasecmp(lpszSrc, lpszCmp); -} - -/************************************************************************* - * @ [SHLWAPI.158] - * - * Unicode version of StrCmpICA. - */ -DWORD WINAPI StrCmpICW(LPCWSTR lpszSrc, LPCWSTR lpszCmp) -{ - return strcmpiW(lpszSrc, lpszCmp); -} - -/************************************************************************* - * @ [SHLWAPI.160] - * - * Get an identification string for the OS and explorer. - * - * PARAMS - * lpszDest [O] Destination for Id string - * dwDestLen [I] Length of lpszDest - * - * RETURNS - * TRUE, If the string was created successfully - * FALSE, Otherwise - */ -BOOL WINAPI SHAboutInfoA(LPSTR lpszDest, DWORD dwDestLen) -{ - WCHAR buff[2084]; - - TRACE("(%p,%ld)\n", lpszDest, dwDestLen); - - if (lpszDest && SHAboutInfoW(buff, dwDestLen)) - { - WideCharToMultiByte(CP_ACP, 0, buff, -1, lpszDest, dwDestLen, NULL, NULL); - return TRUE; - } - return FALSE; -} - -/************************************************************************* - * @ [SHLWAPI.161] - * - * Unicode version of SHAboutInfoA. - */ -BOOL WINAPI SHAboutInfoW(LPWSTR lpszDest, DWORD dwDestLen) -{ - static const WCHAR szIEKey[] = { 'S','O','F','T','W','A','R','E','\\', - 'M','i','c','r','o','s','o','f','t','\\','I','n','t','e','r','n','e','t', - ' ','E','x','p','l','o','r','e','r','\0' }; - static const WCHAR szWinNtKey[] = { 'S','O','F','T','W','A','R','E','\\', - 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s',' ', - 'N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\0' }; - static const WCHAR szWinKey[] = { 'S','O','F','T','W','A','R','E','\\', - 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\', - 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\0' }; - static const WCHAR szRegKey[] = { 'S','O','F','T','W','A','R','E','\\', - 'M','i','c','r','o','s','o','f','t','\\','I','n','t','e','r','n','e','t', - ' ','E','x','p','l','o','r','e','r','\\', - 'R','e','g','i','s','t','r','a','t','i','o','n','\0' }; - static const WCHAR szVersion[] = { 'V','e','r','s','i','o','n','\0' }; - static const WCHAR szCustomized[] = { 'C','u','s','t','o','m','i','z','e','d', - 'V','e','r','s','i','o','n','\0' }; - static const WCHAR szOwner[] = { 'R','e','g','i','s','t','e','r','e','d', - 'O','w','n','e','r','\0' }; - static const WCHAR szOrg[] = { 'R','e','g','i','s','t','e','r','e','d', - 'O','r','g','a','n','i','z','a','t','i','o','n','\0' }; - static const WCHAR szProduct[] = { 'P','r','o','d','u','c','t','I','d','\0' }; - static const WCHAR szUpdate[] = { 'I','E','A','K', - 'U','p','d','a','t','e','U','r','l','\0' }; - static const WCHAR szHelp[] = { 'I','E','A','K', - 'H','e','l','p','S','t','r','i','n','g','\0' }; - WCHAR buff[2084]; - HKEY hReg; - DWORD dwType, dwLen; - - TRACE("(%p,%ld)\n", lpszDest, dwDestLen); - - if (!lpszDest) - return FALSE; - - *lpszDest = '\0'; - - /* Try the NT key first, followed by 95/98 key */ - if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szWinNtKey, 0, KEY_READ, &hReg) && - RegOpenKeyExW(HKEY_LOCAL_MACHINE, szWinKey, 0, KEY_READ, &hReg)) - return FALSE; - - /* OS Version */ - buff[0] = '\0'; - dwLen = 30; - if (!SHGetValueW(HKEY_LOCAL_MACHINE, szIEKey, szVersion, &dwType, buff, &dwLen)) - { - DWORD dwStrLen = strlenW(buff); - dwLen = 30 - dwStrLen; - SHGetValueW(HKEY_LOCAL_MACHINE, szIEKey, - szCustomized, &dwType, buff+dwStrLen, &dwLen); - } - StrCatBuffW(lpszDest, buff, dwDestLen); - - /* ~Registered Owner */ - buff[0] = '~'; - dwLen = 256; - if (SHGetValueW(hReg, szOwner, 0, &dwType, buff+1, &dwLen)) - buff[1] = '\0'; - StrCatBuffW(lpszDest, buff, dwDestLen); - - /* ~Registered Organization */ - dwLen = 256; - if (SHGetValueW(hReg, szOrg, 0, &dwType, buff+1, &dwLen)) - buff[1] = '\0'; - StrCatBuffW(lpszDest, buff, dwDestLen); - - /* FIXME: Not sure where this number comes from */ - buff[0] = '~'; - buff[1] = '0'; - buff[2] = '\0'; - StrCatBuffW(lpszDest, buff, dwDestLen); - - /* ~Product Id */ - dwLen = 256; - if (SHGetValueW(HKEY_LOCAL_MACHINE, szRegKey, szProduct, &dwType, buff+1, &dwLen)) - buff[1] = '\0'; - StrCatBuffW(lpszDest, buff, dwDestLen); - - /* ~IE Update Url */ - dwLen = 2048; - if(SHGetValueW(HKEY_LOCAL_MACHINE, szWinKey, szUpdate, &dwType, buff+1, &dwLen)) - buff[1] = '\0'; - StrCatBuffW(lpszDest, buff, dwDestLen); - - /* ~IE Help String */ - dwLen = 256; - if(SHGetValueW(hReg, szHelp, 0, &dwType, buff+1, &dwLen)) - buff[1] = '\0'; - StrCatBuffW(lpszDest, buff, dwDestLen); - - RegCloseKey(hReg); - return TRUE; -} - -/************************************************************************* - * @ [SHLWAPI.163] - * - * Call IOleCommandTarget_QueryStatus() on an object. - * - * PARAMS - * lpUnknown [I] Object supporting the IOleCommandTarget interface - * pguidCmdGroup [I] GUID for the command group - * cCmds [I] - * prgCmds [O] Commands - * pCmdText [O] Command text - * - * RETURNS - * Success: S_OK. - * Failure: E_FAIL, if lpUnknown is NULL. - * E_NOINTERFACE, if lpUnknown does not support IOleCommandTarget. - * Otherwise, an error code from IOleCommandTarget_QueryStatus(). - */ -HRESULT WINAPI IUnknown_QueryStatus(IUnknown* lpUnknown, REFGUID pguidCmdGroup, - ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT* pCmdText) -{ - HRESULT hRet = E_FAIL; - - TRACE("(%p,%p,%ld,%p,%p)\n",lpUnknown, pguidCmdGroup, cCmds, prgCmds, pCmdText); - - if (lpUnknown) - { - IOleCommandTarget* lpOle; - - hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleCommandTarget, - (void**)&lpOle); - - if (SUCCEEDED(hRet) && lpOle) - { - hRet = IOleCommandTarget_QueryStatus(lpOle, pguidCmdGroup, cCmds, - prgCmds, pCmdText); - IOleCommandTarget_Release(lpOle); - } - } - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.164] - * - * Call IOleCommandTarget_Exec() on an object. - * - * PARAMS - * lpUnknown [I] Object supporting the IOleCommandTarget interface - * pguidCmdGroup [I] GUID for the command group - * - * RETURNS - * Success: S_OK. - * Failure: E_FAIL, if lpUnknown is NULL. - * E_NOINTERFACE, if lpUnknown does not support IOleCommandTarget. - * Otherwise, an error code from IOleCommandTarget_Exec(). - */ -HRESULT WINAPI IUnknown_Exec(IUnknown* lpUnknown, REFGUID pguidCmdGroup, - DWORD nCmdID, DWORD nCmdexecopt, VARIANT* pvaIn, - VARIANT* pvaOut) -{ - HRESULT hRet = E_FAIL; - - TRACE("(%p,%p,%ld,%ld,%p,%p)\n",lpUnknown, pguidCmdGroup, nCmdID, - nCmdexecopt, pvaIn, pvaOut); - - if (lpUnknown) - { - IOleCommandTarget* lpOle; - - hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleCommandTarget, - (void**)&lpOle); - if (SUCCEEDED(hRet) && lpOle) - { - hRet = IOleCommandTarget_Exec(lpOle, pguidCmdGroup, nCmdID, - nCmdexecopt, pvaIn, pvaOut); - IOleCommandTarget_Release(lpOle); - } - } - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.165] - * - * Retrieve, modify, and re-set a value from a window. - * - * PARAMS - * hWnd [I] Window to get value from - * offset [I] Offset of value - * wMask [I] Mask for uiFlags - * wFlags [I] Bits to set in window value - * - * RETURNS - * The new value as it was set, or 0 if any parameter is invalid. - * - * NOTES - * Any bits set in uiMask are cleared from the value, then any bits set in - * uiFlags are set in the value. - */ -LONG WINAPI SHSetWindowBits(HWND hwnd, INT offset, UINT wMask, UINT wFlags) -{ - LONG ret = GetWindowLongA(hwnd, offset); - LONG newFlags = (wFlags & wMask) | (ret & ~wFlags); - - if (newFlags != ret) - ret = SetWindowLongA(hwnd, offset, newFlags); - return ret; -} - -/************************************************************************* - * @ [SHLWAPI.167] - * - * Change a window's parent. - * - * PARAMS - * hWnd [I] Window to change parent of - * hWndParent [I] New parent window - * - * RETURNS - * The old parent of hWnd. - * - * NOTES - * If hWndParent is NULL (desktop), the window style is changed to WS_POPUP. - * If hWndParent is NOT NULL then we set the WS_CHILD style. - */ -HWND WINAPI SHSetParentHwnd(HWND hWnd, HWND hWndParent) -{ - TRACE("%p, %p\n", hWnd, hWndParent); - - if(GetParent(hWnd) == hWndParent) - return 0; - - if(hWndParent) - SHSetWindowBits(hWnd, GWL_STYLE, WS_CHILD, WS_CHILD); - else - SHSetWindowBits(hWnd, GWL_STYLE, WS_POPUP, WS_POPUP); - - return SetParent(hWnd, hWndParent); -} - -/************************************************************************* - * @ [SHLWAPI.168] - * - * Locate and advise a connection point in an IConnectionPointContainer object. - * - * PARAMS - * lpUnkSink [I] Sink for the connection point advise call - * riid [I] REFIID of connection point to advise - * bAdviseOnly [I] TRUE = Advise only, FALSE = Unadvise first - * lpUnknown [I] Object supporting the IConnectionPointContainer interface - * lpCookie [O] Pointer to connection point cookie - * lppCP [O] Destination for the IConnectionPoint found - * - * RETURNS - * Success: S_OK. If lppCP is non-NULL, it is filled with the IConnectionPoint - * that was advised. The caller is responsable for releasing it. - * Failure: E_FAIL, if any arguments are invalid. - * E_NOINTERFACE, if lpUnknown isn't an IConnectionPointContainer, - * Or an HRESULT error code if any call fails. - */ -HRESULT WINAPI ConnectToConnectionPoint(IUnknown* lpUnkSink, REFIID riid, BOOL bAdviseOnly, - IUnknown* lpUnknown, LPDWORD lpCookie, - IConnectionPoint **lppCP) -{ - HRESULT hRet; - IConnectionPointContainer* lpContainer; - IConnectionPoint *lpCP; - - if(!lpUnknown || (bAdviseOnly && !lpUnkSink)) - return E_FAIL; - - if(lppCP) - *lppCP = NULL; - - hRet = IUnknown_QueryInterface(lpUnknown, &IID_IConnectionPointContainer, - (void**)&lpContainer); - if (SUCCEEDED(hRet)) - { - hRet = IConnectionPointContainer_FindConnectionPoint(lpContainer, riid, &lpCP); - - if (SUCCEEDED(hRet)) - { - if(!bAdviseOnly) - hRet = IConnectionPoint_Unadvise(lpCP, *lpCookie); - hRet = IConnectionPoint_Advise(lpCP, lpUnkSink, lpCookie); - - if (FAILED(hRet)) - *lpCookie = 0; - - if (lppCP && SUCCEEDED(hRet)) - *lppCP = lpCP; /* Caller keeps the interface */ - else - IConnectionPoint_Release(lpCP); /* Release it */ - } - - IUnknown_Release(lpContainer); - } - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.169] - * - * Release an interface. - * - * PARAMS - * lpUnknown [I] Object to release - * - * RETURNS - * Nothing. - */ -DWORD WINAPI IUnknown_AtomicRelease(IUnknown ** lpUnknown) -{ - IUnknown *temp; - - TRACE("(%p)\n",lpUnknown); - - if(!lpUnknown || !*((LPDWORD)lpUnknown)) return 0; - temp = *lpUnknown; - *lpUnknown = NULL; - - TRACE("doing Release\n"); - - return IUnknown_Release(temp); -} - -/************************************************************************* - * @ [SHLWAPI.170] - * - * Skip '//' if present in a string. - * - * PARAMS - * lpszSrc [I] String to check for '//' - * - * RETURNS - * Success: The next character after the '//' or the string if not present - * Failure: NULL, if lpszStr is NULL. - */ -LPCSTR WINAPI PathSkipLeadingSlashesA(LPCSTR lpszSrc) -{ - if (lpszSrc && lpszSrc[0] == '/' && lpszSrc[1] == '/') - lpszSrc += 2; - return lpszSrc; -} - -/************************************************************************* - * @ [SHLWAPI.171] - * - * Check if two interfaces come from the same object. - * - * PARAMS - * lpInt1 [I] Interface to check against lpInt2. - * lpInt2 [I] Interface to check against lpInt1. - * - * RETURNS - * TRUE, If the interfaces come from the same object. - * FALSE Otherwise. - */ -BOOL WINAPI SHIsSameObject(IUnknown* lpInt1, IUnknown* lpInt2) -{ - LPVOID lpUnknown1, lpUnknown2; - - TRACE("%p %p\n", lpInt1, lpInt2); - - if (!lpInt1 || !lpInt2) - return FALSE; - - if (lpInt1 == lpInt2) - return TRUE; - - if (!SUCCEEDED(IUnknown_QueryInterface(lpInt1, &IID_IUnknown, - (LPVOID *)&lpUnknown1))) - return FALSE; - - if (!SUCCEEDED(IUnknown_QueryInterface(lpInt2, &IID_IUnknown, - (LPVOID *)&lpUnknown2))) - return FALSE; - - if (lpUnknown1 == lpUnknown2) - return TRUE; - - return FALSE; -} - -/************************************************************************* - * @ [SHLWAPI.172] - * - * Get the window handle of an object. - * - * PARAMS - * lpUnknown [I] Object to get the window handle of - * lphWnd [O] Destination for window handle - * - * RETURNS - * Success: S_OK. lphWnd contains the objects window handle. - * Failure: An HRESULT error code. - * - * NOTES - * lpUnknown is expected to support one of the following interfaces: - * IOleWindow(), IInternetSecurityMgrSite(), or IShellView(). - */ -HRESULT WINAPI IUnknown_GetWindow(IUnknown *lpUnknown, HWND *lphWnd) -{ - /* FIXME: Wine has no header for this object */ - static const GUID IID_IInternetSecurityMgrSite = { 0x79eac9ed, - 0xbaf9, 0x11ce, { 0x8c, 0x82, 0x00, 0xaa, 0x00, 0x4b, 0xa9, 0x0b }}; - IUnknown *lpOle; - HRESULT hRet = E_FAIL; - - TRACE("(%p,%p)\n", lpUnknown, lphWnd); - - if (!lpUnknown) - return hRet; - - hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleWindow, (void**)&lpOle); - - if (FAILED(hRet)) - { - hRet = IUnknown_QueryInterface(lpUnknown,&IID_IShellView, (void**)&lpOle); - - if (FAILED(hRet)) - { - hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInternetSecurityMgrSite, - (void**)&lpOle); - } - } - - if (SUCCEEDED(hRet)) - { - /* Lazyness here - Since GetWindow() is the first method for the above 3 - * interfaces, we use the same call for them all. - */ - hRet = IOleWindow_GetWindow((IOleWindow*)lpOle, lphWnd); - IUnknown_Release(lpOle); - if (lphWnd) - TRACE("Returning HWND=%p\n", *lphWnd); - } - - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.173] - * - * Call a method on as as yet unidentified object. - * - * PARAMS - * pUnk [I] Object supporting the unidentified interface, - * arg [I] Argument for the call on the object. - * - * RETURNS - * S_OK. - */ -HRESULT WINAPI IUnknown_SetOwner(IUnknown *pUnk, ULONG arg) -{ - static const GUID guid_173 = { - 0x5836fb00, 0x8187, 0x11cf, { 0xa1,0x2b,0x00,0xaa,0x00,0x4a,0xe8,0x37 } - }; - IMalloc *pUnk2; - - TRACE("(%p,%ld)\n", pUnk, arg); - - /* Note: arg may not be a ULONG and pUnk2 is for sure not an IMalloc - - * We use this interface as its vtable entry is compatible with the - * object in question. - * FIXME: Find out what this object is and where it should be defined. - */ - if (pUnk && - SUCCEEDED(IUnknown_QueryInterface(pUnk, &guid_173, (void**)&pUnk2))) - { - IMalloc_Alloc(pUnk2, arg); /* Faked call!! */ - IMalloc_Release(pUnk2); - } - return S_OK; -} - -/************************************************************************* - * @ [SHLWAPI.174] - * - * Call either IObjectWithSite_SetSite() or IPersistMoniker_GetClassID() on - * an interface. - * - * RETURNS - * Success: S_OK. - * Failure: E_FAIL, if p1 is NULL. - * E_NOINTERFACE If p1 does not support the IPersist interface, - * Or an HRESULT error code. - */ -DWORD WINAPI IUnknown_SetSite( - IUnknown *p1, /* [in] OLE object */ - LPVOID *p2) /* [out] ptr for call results */ -{ - DWORD ret, aa; - IUnknown *iobjectwithsite; - - if (!p1) return E_FAIL; - - /* see if SetSite interface exists for IObjectWithSite object */ - ret = IUnknown_QueryInterface((IUnknown *)p1, (REFIID)id1, (LPVOID *)&iobjectwithsite); - TRACE("first IU_QI ret=%08lx, iobjectwithsite=%p\n", ret, iobjectwithsite); - if (ret) { - - /* see if GetClassId interface exists for IPersistMoniker object */ - ret = IUnknown_QueryInterface(p1, (REFIID)id2, (LPVOID *)&aa); - TRACE("second IU_QI ret=%08lx, aa=%08lx\n", ret, aa); - if (ret) return ret; - - /* fake a GetClassId call */ - ret = IOleWindow_GetWindow((IOleWindow *)aa, (HWND*)p2); - TRACE("second IU_QI doing 0x0c ret=%08lx, *p2=%08lx\n", ret, - *(LPDWORD)p2); - IUnknown_Release((IUnknown *)aa); - } - else { - /* fake a SetSite call */ - ret = IOleWindow_GetWindow((IOleWindow *)iobjectwithsite, (HWND*)p2); - TRACE("first IU_QI doing 0x0c ret=%08lx, *p2=%08lx\n", ret, - *(LPDWORD)p2); - IUnknown_Release((IUnknown *)iobjectwithsite); - } - return ret; -} - -/************************************************************************* - * @ [SHLWAPI.175] - * - * Call IPersist_GetClassID() on an object. - * - * PARAMS - * lpUnknown [I] Object supporting the IPersist interface - * lpClassId [O] Destination for Class Id - * - * RETURNS - * Success: S_OK. lpClassId contains the Class Id requested. - * Failure: E_FAIL, If lpUnknown is NULL, - * E_NOINTERFACE If lpUnknown does not support IPersist, - * Or an HRESULT error code. - */ -HRESULT WINAPI IUnknown_GetClassID(IUnknown *lpUnknown, CLSID* lpClassId) -{ - IPersist* lpPersist; - HRESULT hRet = E_FAIL; - - TRACE("(%p,%p)\n", lpUnknown, debugstr_guid(lpClassId)); - - if (lpUnknown) - { - hRet = IUnknown_QueryInterface(lpUnknown,&IID_IPersist,(void**)&lpPersist); - if (SUCCEEDED(hRet)) - { - IPersist_GetClassID(lpPersist, lpClassId); - IPersist_Release(lpPersist); - } - } - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.176] - * - * Retrieve a Service Interface from an object. - * - * PARAMS - * lpUnknown [I] Object to get an IServiceProvider interface from - * sid [I] Service ID for IServiceProvider_QueryService() call - * riid [I] Function requested for QueryService call - * lppOut [O] Destination for the service interface pointer - * - * RETURNS - * Success: S_OK. lppOut contains an object providing the requested service - * Failure: An HRESULT error code - * - * NOTES - * lpUnknown is expected to support the IServiceProvider interface. - */ -HRESULT WINAPI IUnknown_QueryService(IUnknown* lpUnknown, REFGUID sid, REFIID riid, - LPVOID *lppOut) -{ - IServiceProvider* pService = NULL; - HRESULT hRet; - - if (!lppOut) - return E_FAIL; - - *lppOut = NULL; - - if (!lpUnknown) - return E_FAIL; - - /* Get an IServiceProvider interface from the object */ - hRet = IUnknown_QueryInterface(lpUnknown, &IID_IServiceProvider, - (LPVOID*)&pService); - - if (!hRet && pService) - { - TRACE("QueryInterface returned (IServiceProvider*)%p\n", pService); - - /* Get a Service interface from the object */ - hRet = IServiceProvider_QueryService(pService, sid, riid, lppOut); - - TRACE("(IServiceProvider*)%p returned (IUnknown*)%p\n", pService, *lppOut); - - /* Release the IServiceProvider interface */ - IUnknown_Release(pService); - } - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.177] - * - * Loads a popup menu. - * - * PARAMS - * hInst [I] Instance handle - * szName [I] Menu name - * - * RETURNS - * Success: TRUE. - * Failure: FALSE. - */ -BOOL WINAPI SHLoadMenuPopup(HINSTANCE hInst, LPCWSTR szName) -{ - HMENU hMenu, hSubMenu; - - if ((hMenu = LoadMenuW(hInst, szName))) - { - if ((hSubMenu = GetSubMenu(hMenu, 0))) - RemoveMenu(hMenu, 0, MF_BYPOSITION); - - DestroyMenu(hMenu); - return TRUE; - } - return FALSE; -} - -typedef struct _enumWndData -{ - UINT uiMsgId; - WPARAM wParam; - LPARAM lParam; - LRESULT (WINAPI *pfnPost)(HWND,UINT,WPARAM,LPARAM); -} enumWndData; - -/* Callback for SHLWAPI_178 */ -static BOOL CALLBACK SHLWAPI_EnumChildProc(HWND hWnd, LPARAM lParam) -{ - enumWndData *data = (enumWndData *)lParam; - - TRACE("(%p,%p)\n", hWnd, data); - data->pfnPost(hWnd, data->uiMsgId, data->wParam, data->lParam); - return TRUE; -} - -/************************************************************************* - * @ [SHLWAPI.178] - * - * Send or post a message to every child of a window. - * - * PARAMS - * hWnd [I] Window whose children will get the messages - * uiMsgId [I] Message Id - * wParam [I] WPARAM of message - * lParam [I] LPARAM of message - * bSend [I] TRUE = Use SendMessageA(), FALSE = Use PostMessageA() - * - * RETURNS - * Nothing. - * - * NOTES - * The appropriate ASCII or Unicode function is called for the window. - */ -void WINAPI SHPropagateMessage(HWND hWnd, UINT uiMsgId, WPARAM wParam, LPARAM lParam, BOOL bSend) -{ - enumWndData data; - - TRACE("(%p,%u,%d,%ld,%d)\n", hWnd, uiMsgId, wParam, lParam, bSend); - - if(hWnd) - { - data.uiMsgId = uiMsgId; - data.wParam = wParam; - data.lParam = lParam; - - if (bSend) - data.pfnPost = IsWindowUnicode(hWnd) ? (void*)SendMessageW : (void*)SendMessageA; - else - data.pfnPost = IsWindowUnicode(hWnd) ? (void*)PostMessageW : (void*)PostMessageA; - - EnumChildWindows(hWnd, SHLWAPI_EnumChildProc, (LPARAM)&data); - } -} - -/************************************************************************* - * @ [SHLWAPI.180] - * - * Remove all sub-menus from a menu. - * - * PARAMS - * hMenu [I] Menu to remove sub-menus from - * - * RETURNS - * Success: 0. All sub-menus under hMenu are removed - * Failure: -1, if any parameter is invalid - */ -DWORD WINAPI SHRemoveAllSubMenus(HMENU hMenu) -{ - int iItemCount = GetMenuItemCount(hMenu) - 1; - while (iItemCount >= 0) - { - HMENU hSubMenu = GetSubMenu(hMenu, iItemCount); - if (hSubMenu) - RemoveMenu(hMenu, iItemCount, MF_BYPOSITION); - iItemCount--; - } - return iItemCount; -} - -/************************************************************************* - * @ [SHLWAPI.181] - * - * Enable or disable a menu item. - * - * PARAMS - * hMenu [I] Menu holding menu item - * uID [I] ID of menu item to enable/disable - * bEnable [I] Whether to enable (TRUE) or disable (FALSE) the item. - * - * RETURNS - * The return code from EnableMenuItem. - */ -UINT WINAPI SHEnableMenuItem(HMENU hMenu, UINT wItemID, BOOL bEnable) -{ - return EnableMenuItem(hMenu, wItemID, bEnable ? MF_ENABLED : MF_GRAYED); -} - -/************************************************************************* - * @ [SHLWAPI.182] - * - * Check or uncheck a menu item. - * - * PARAMS - * hMenu [I] Menu holding menu item - * uID [I] ID of menu item to check/uncheck - * bCheck [I] Whether to check (TRUE) or uncheck (FALSE) the item. - * - * RETURNS - * The return code from CheckMenuItem. - */ -DWORD WINAPI SHCheckMenuItem(HMENU hMenu, UINT uID, BOOL bCheck) -{ - return CheckMenuItem(hMenu, uID, bCheck ? MF_CHECKED : MF_UNCHECKED); -} - -/************************************************************************* - * @ [SHLWAPI.183] - * - * Register a window class if it isn't already. - * - * PARAMS - * lpWndClass [I] Window class to register - * - * RETURNS - * The result of the RegisterClassA call. - */ -DWORD WINAPI SHRegisterClassA(WNDCLASSA *wndclass) -{ - WNDCLASSA wca; - if (GetClassInfoA(wndclass->hInstance, wndclass->lpszClassName, &wca)) - return TRUE; - return (DWORD)RegisterClassA(wndclass); -} - -/************************************************************************* - * @ [SHLWAPI.186] - */ -BOOL WINAPI SHSimulateDrop(IDropTarget *pDrop, IDataObject *pDataObj, - DWORD grfKeyState, PPOINTL lpPt, DWORD* pdwEffect) -{ - DWORD dwEffect = DROPEFFECT_LINK | DROPEFFECT_MOVE | DROPEFFECT_COPY; - POINTL pt = { 0, 0 }; - - if (!lpPt) - lpPt = &pt; - - if (!pdwEffect) - pdwEffect = &dwEffect; - - IDropTarget_DragEnter(pDrop, pDataObj, grfKeyState, *lpPt, pdwEffect); - - if (*pdwEffect) - return IDropTarget_Drop(pDrop, pDataObj, grfKeyState, *lpPt, pdwEffect); - - IDropTarget_DragLeave(pDrop); - return TRUE; -} - -/************************************************************************* - * @ [SHLWAPI.187] - * - * Call IPersistPropertyBag_Load() on an object. - * - * PARAMS - * lpUnknown [I] Object supporting the IPersistPropertyBag interface - * lpPropBag [O] Destination for loaded IPropertyBag - * - * RETURNS - * Success: S_OK. - * Failure: An HRESULT error code, or E_FAIL if lpUnknown is NULL. - */ -DWORD WINAPI SHLoadFromPropertyBag(IUnknown *lpUnknown, IPropertyBag* lpPropBag) -{ - IPersistPropertyBag* lpPPBag; - HRESULT hRet = E_FAIL; - - TRACE("(%p,%p)\n", lpUnknown, lpPropBag); - - if (lpUnknown) - { - hRet = IUnknown_QueryInterface(lpUnknown, &IID_IPersistPropertyBag, - (void**)&lpPPBag); - if (SUCCEEDED(hRet) && lpPPBag) - { - hRet = IPersistPropertyBag_Load(lpPPBag, lpPropBag, NULL); - IPersistPropertyBag_Release(lpPPBag); - } - } - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.188] - * - * Call IOleControlSite_TranslateAccelerator() on an object. - * - * PARAMS - * lpUnknown [I] Object supporting the IOleControlSite interface. - * lpMsg [I] Key message to be processed. - * dwModifiers [I] Flags containing the state of the modifier keys. - * - * RETURNS - * Success: S_OK. - * Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL. - */ -HRESULT WINAPI IUnknown_TranslateAcceleratorOCS(IUnknown *lpUnknown, LPMSG lpMsg, DWORD dwModifiers) -{ - IOleControlSite* lpCSite = NULL; - HRESULT hRet = E_INVALIDARG; - - TRACE("(%p,%p,0x%08lx)\n", lpUnknown, lpMsg, dwModifiers); - if (lpUnknown) - { - hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleControlSite, - (void**)&lpCSite); - if (SUCCEEDED(hRet) && lpCSite) - { - hRet = IOleControlSite_TranslateAccelerator(lpCSite, lpMsg, dwModifiers); - IOleControlSite_Release(lpCSite); - } - } - return hRet; -} - - -/************************************************************************* - * @ [SHLWAPI.189] - * - * Call IOleControlSite_GetExtendedControl() on an object. - * - * PARAMS - * lpUnknown [I] Object supporting the IOleControlSite interface. - * lppDisp [O] Destination for resulting IDispatch. - * - * RETURNS - * Success: S_OK. - * Failure: An HRESULT error code, or E_FAIL if lpUnknown is NULL. - */ -DWORD WINAPI IUnknown_OnFocusOCS(IUnknown *lpUnknown, IDispatch** lppDisp) -{ - IOleControlSite* lpCSite = NULL; - HRESULT hRet = E_FAIL; - - TRACE("(%p,%p)\n", lpUnknown, lppDisp); - if (lpUnknown) - { - hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleControlSite, - (void**)&lpCSite); - if (SUCCEEDED(hRet) && lpCSite) - { - hRet = IOleControlSite_GetExtendedControl(lpCSite, lppDisp); - IOleControlSite_Release(lpCSite); - } - } - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.190] - */ -HRESULT WINAPI IUnknown_HandleIRestrict(LPUNKNOWN lpUnknown, PVOID lpArg1, - PVOID lpArg2, PVOID lpArg3, PVOID lpArg4) -{ - /* FIXME: {D12F26B2-D90A-11D0-830D-00AA005B4383} - What object does this represent? */ - static const DWORD service_id[] = { 0xd12f26b2, 0x11d0d90a, 0xaa000d83, 0x83435b00 }; - /* FIXME: {D12F26B1-D90A-11D0-830D-00AA005B4383} - Also Unknown/undocumented */ - static const DWORD function_id[] = { 0xd12f26b1, 0x11d0d90a, 0xaa000d83, 0x83435b00 }; - HRESULT hRet = E_INVALIDARG; - LPUNKNOWN lpUnkInner = NULL; /* FIXME: Real type is unknown */ - - TRACE("(%p,%p,%p,%p,%p)\n", lpUnknown, lpArg1, lpArg2, lpArg3, lpArg4); - - if (lpUnknown && lpArg4) - { - hRet = IUnknown_QueryService(lpUnknown, (REFGUID)service_id, - (REFGUID)function_id, (void**)&lpUnkInner); - - if (SUCCEEDED(hRet) && lpUnkInner) - { - /* FIXME: The type of service object requested is unknown, however - * testing shows that its first method is called with 4 parameters. - * Fake this by using IParseDisplayName_ParseDisplayName since the - * signature and position in the vtable matches our unknown object type. - */ - hRet = IParseDisplayName_ParseDisplayName((LPPARSEDISPLAYNAME)lpUnkInner, - lpArg1, lpArg2, lpArg3, lpArg4); - IUnknown_Release(lpUnkInner); - } - } - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.192] - * - * Get a sub-menu from a menu item. - * - * PARAMS - * hMenu [I] Menu to get sub-menu from - * uID [I] ID of menu item containing sub-menu - * - * RETURNS - * The sub-menu of the item, or a NULL handle if any parameters are invalid. - */ -HMENU WINAPI SHGetMenuFromID(HMENU hMenu, UINT uID) -{ - MENUITEMINFOA mi; - - TRACE("(%p,%uld)\n", hMenu, uID); - - mi.cbSize = sizeof(MENUITEMINFOA); - mi.fMask = MIIM_SUBMENU; - - if (!GetMenuItemInfoA(hMenu, uID, 0, &mi)) - return NULL; - - return mi.hSubMenu; -} - -/************************************************************************* - * @ [SHLWAPI.193] - * - * Get the color depth of the primary display. - * - * PARAMS - * None. - * - * RETURNS - * The color depth of the primary display. - */ -DWORD WINAPI SHGetCurColorRes() -{ - HDC hdc; - DWORD ret; - - TRACE("()\n"); - - hdc = GetDC(0); - ret = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES); - ReleaseDC(0, hdc); - return ret; -} - -/************************************************************************* - * @ [SHLWAPI.194] - * - * Wait for a message to arrive, with a timeout. - * - * PARAMS - * hand [I] Handle to query - * dwTimeout [I] Timeout in ticks or INFINITE to never timeout - * - * RETURNS - * STATUS_TIMEOUT if no message is received before dwTimeout ticks passes. - * Otherwise returns the value from MsgWaitForMultipleObjectsEx when a - * message is available. - */ -DWORD WINAPI SHWaitForSendMessageThread(HANDLE hand, DWORD dwTimeout) -{ - DWORD dwEndTicks = GetTickCount() + dwTimeout; - DWORD dwRet; - - while ((dwRet = MsgWaitForMultipleObjectsEx(1, &hand, dwTimeout, QS_SENDMESSAGE, 0)) == 1) - { - MSG msg; - - PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE); - - if (dwTimeout != INFINITE) - { - if ((int)(dwTimeout = dwEndTicks - GetTickCount()) <= 0) - return WAIT_TIMEOUT; - } - } - - return dwRet; -} - -/************************************************************************* - * @ [SHLWAPI.195] - * - * Determine if a shell folder can be expanded. - * - * PARAMS - * lpFolder [I] Parent folder containing the object to test. - * pidl [I] Id of the object to test. - * - * RETURNS - * Success: S_OK, if the object is expandable, S_FALSE otherwise. - * Failure: E_INVALIDARG, if any argument is invalid. - * - * NOTES - * If the object to be tested does not expose the IQueryInfo() interface it - * will not be identified as an expandable folder. - */ -HRESULT WINAPI SHIsExpandableFolder(LPSHELLFOLDER lpFolder, LPCITEMIDLIST pidl) -{ - HRESULT hRet = E_INVALIDARG; - IQueryInfo *lpInfo; - - if (lpFolder && pidl) - { - hRet = IShellFolder_GetUIObjectOf(lpFolder, NULL, 1, &pidl, &IID_IQueryInfo, - NULL, (void**)&lpInfo); - if (FAILED(hRet)) - hRet = S_FALSE; /* Doesn't expose IQueryInfo */ - else - { - DWORD dwFlags = 0; - - /* MSDN states of IQueryInfo_GetInfoFlags() that "This method is not - * currently used". Really? You wouldn't be holding out on me would you? - */ - hRet = IQueryInfo_GetInfoFlags(lpInfo, &dwFlags); - - if (SUCCEEDED(hRet)) - { - /* 0x2 is an undocumented flag apparently indicating expandability */ - hRet = dwFlags & 0x2 ? S_OK : S_FALSE; - } - - IQueryInfo_Release(lpInfo); - } - } - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.197] - * - * Blank out a region of text by drawing the background only. - * - * PARAMS - * hDC [I] Device context to draw in - * pRect [I] Area to draw in - * cRef [I] Color to draw in - * - * RETURNS - * Nothing. - */ -DWORD WINAPI SHFillRectClr(HDC hDC, LPCRECT pRect, COLORREF cRef) -{ - COLORREF cOldColor = SetBkColor(hDC, cRef); - ExtTextOutA(hDC, 0, 0, ETO_OPAQUE, pRect, 0, 0, 0); - SetBkColor(hDC, cOldColor); - return 0; -} - -/************************************************************************* - * @ [SHLWAPI.198] - * - * Return the value asociated with a key in a map. - * - * PARAMS - * lpKeys [I] A list of keys of length iLen - * lpValues [I] A list of values associated with lpKeys, of length iLen - * iLen [I] Length of both lpKeys and lpValues - * iKey [I] The key value to look up in lpKeys - * - * RETURNS - * The value in lpValues associated with iKey, or -1 if iKey is not - * found in lpKeys. - * - * NOTES - * - If two elements in the map share the same key, this function returns - * the value closest to the start of the map - * - The native version of this function crashes if lpKeys or lpValues is NULL. - */ -int WINAPI SHSearchMapInt(const int *lpKeys, const int *lpValues, int iLen, int iKey) -{ - if (lpKeys && lpValues) - { - int i = 0; - - while (i < iLen) - { - if (lpKeys[i] == iKey) - return lpValues[i]; /* Found */ - i++; - } - } - return -1; /* Not found */ -} - - -/************************************************************************* - * @ [SHLWAPI.199] - * - * Copy an interface pointer - * - * PARAMS - * lppDest [O] Destination for copy - * lpUnknown [I] Source for copy - * - * RETURNS - * Nothing. - */ -VOID WINAPI IUnknown_Set(IUnknown **lppDest, IUnknown *lpUnknown) -{ - TRACE("(%p,%p)\n", lppDest, lpUnknown); - - if (lppDest) - IUnknown_AtomicRelease(lppDest); /* Release existing interface */ - - if (lpUnknown) - { - /* Copy */ - IUnknown_AddRef(lpUnknown); - *lppDest = lpUnknown; - } -} - -/************************************************************************* - * @ [SHLWAPI.200] - * - */ -HRESULT WINAPI MayQSForward(IUnknown* lpUnknown, PVOID lpReserved, - REFGUID riidCmdGrp, ULONG cCmds, - OLECMD *prgCmds, OLECMDTEXT* pCmdText) -{ - FIXME("(%p,%p,%p,%ld,%p,%p) - stub\n", - lpUnknown, lpReserved, riidCmdGrp, cCmds, prgCmds, pCmdText); - - /* FIXME: Calls IsQSForward & IUnknown_QueryStatus */ - return DRAGDROP_E_NOTREGISTERED; -} - -/************************************************************************* - * @ [SHLWAPI.201] - * - */ -HRESULT WINAPI MayExecForward(IUnknown* lpUnknown, INT iUnk, REFGUID pguidCmdGroup, - DWORD nCmdID, DWORD nCmdexecopt, VARIANT* pvaIn, - VARIANT* pvaOut) -{ - FIXME("(%p,%d,%p,%ld,%ld,%p,%p) - stub!\n", lpUnknown, iUnk, pguidCmdGroup, - nCmdID, nCmdexecopt, pvaIn, pvaOut); - return DRAGDROP_E_NOTREGISTERED; -} - -/************************************************************************* - * @ [SHLWAPI.202] - * - */ -HRESULT WINAPI IsQSForward(REFGUID pguidCmdGroup,ULONG cCmds, OLECMD *prgCmds) -{ - FIXME("(%p,%ld,%p) - stub!\n", pguidCmdGroup, cCmds, prgCmds); - return DRAGDROP_E_NOTREGISTERED; -} - -/************************************************************************* - * @ [SHLWAPI.204] - * - * Determine if a window is not a child of another window. - * - * PARAMS - * hParent [I] Suspected parent window - * hChild [I] Suspected child window - * - * RETURNS - * TRUE: If hChild is a child window of hParent - * FALSE: If hChild is not a child window of hParent, or they are equal - */ -BOOL WINAPI SHIsChildOrSelf(HWND hParent, HWND hChild) -{ - TRACE("(%p,%p)\n", hParent, hChild); - - if (!hParent || !hChild) - return TRUE; - else if(hParent == hChild) - return FALSE; - return !IsChild(hParent, hChild); -} - -/************************************************************************* - * @ [SHLWAPI.208] - * - * Some sort of memory management process. - */ -DWORD WINAPI FDSA_Initialize( - DWORD a, - DWORD b, - LPVOID c, - LPVOID d, - DWORD e) -{ - FIXME("(0x%08lx 0x%08lx %p %p 0x%08lx) stub\n", - a, b, c, d, e); - return 1; -} - -/************************************************************************* - * @ [SHLWAPI.209] - * - * Some sort of memory management process. - */ -DWORD WINAPI FDSA_Destroy( - LPVOID a) -{ - FIXME("(%p) stub\n", - a); - return 1; -} - -/************************************************************************* - * @ [SHLWAPI.210] - * - * Some sort of memory management process. - */ -DWORD WINAPI FDSA_InsertItem( - LPVOID a, - DWORD b, - LPVOID c) -{ - FIXME("(%p 0x%08lx %p) stub\n", - a, b, c); - return 0; -} - -/************************************************************************* - * @ [SHLWAPI.211] - */ -DWORD WINAPI FDSA_DeleteItem( - LPVOID a, - DWORD b) -{ - FIXME("(%p 0x%08lx) stub\n", - a, b); - return 1; -} - -typedef struct { - REFIID refid; - DWORD indx; -} IFACE_INDEX_TBL; - -/************************************************************************* - * @ [SHLWAPI.219] - * - * Call IUnknown_QueryInterface() on a table of objects. - * - * RETURNS - * Success: S_OK. - * Failure: E_POINTER or E_NOINTERFACE. - */ -HRESULT WINAPI QISearch( - LPVOID w, /* [in] Table of interfaces */ - IFACE_INDEX_TBL *x, /* [in] Array of REFIIDs and indexes into the table */ - REFIID riid, /* [in] REFIID to get interface for */ - LPVOID *ppv) /* [out] Destination for interface pointer */ -{ - HRESULT ret; - IUnknown *a_vtbl; - IFACE_INDEX_TBL *xmove; - - TRACE("(%p %p %s %p)\n", w,x,debugstr_guid(riid),ppv); - if (ppv) { - xmove = x; - while (xmove->refid) { - TRACE("trying (indx %ld) %s\n", xmove->indx, debugstr_guid(xmove->refid)); - if (IsEqualIID(riid, xmove->refid)) { - a_vtbl = (IUnknown*)(xmove->indx + (LPBYTE)w); - TRACE("matched, returning (%p)\n", a_vtbl); - *ppv = (LPVOID)a_vtbl; - IUnknown_AddRef(a_vtbl); - return S_OK; - } - xmove++; - } - - if (IsEqualIID(riid, &IID_IUnknown)) { - a_vtbl = (IUnknown*)(x->indx + (LPBYTE)w); - TRACE("returning first for IUnknown (%p)\n", a_vtbl); - *ppv = (LPVOID)a_vtbl; - IUnknown_AddRef(a_vtbl); - return S_OK; - } - *ppv = 0; - ret = E_NOINTERFACE; - } else - ret = E_POINTER; - - TRACE("-- 0x%08lx\n", ret); - return ret; -} - -/************************************************************************* - * @ [SHLWAPI.221] - * - * Remove the "PropDlgFont" property from a window. - * - * PARAMS - * hWnd [I] Window to remove the property from - * - * RETURNS - * A handle to the removed property, or NULL if it did not exist. - */ -HANDLE WINAPI SHRemoveDefaultDialogFont(HWND hWnd) -{ - HANDLE hProp; - - TRACE("(%p)\n", hWnd); - - hProp = GetPropA(hWnd, "PropDlgFont"); - - if(hProp) - { - DeleteObject(hProp); - hProp = RemovePropA(hWnd, "PropDlgFont"); - } - return hProp; -} - -/************************************************************************* - * @ [SHLWAPI.236] - * - * Load the in-process server of a given GUID. - * - * PARAMS - * refiid [I] GUID of the server to load. - * - * RETURNS - * Success: A handle to the loaded server dll. - * Failure: A NULL handle. - */ -HMODULE WINAPI SHPinDllOfCLSID(REFIID refiid) -{ - HKEY newkey; - DWORD type, count; - CHAR value[MAX_PATH], string[MAX_PATH]; - - strcpy(string, "CLSID\\"); - SHStringFromGUIDA(refiid, string + 6, sizeof(string)/sizeof(char) - 6); - strcat(string, "\\InProcServer32"); - - count = MAX_PATH; - RegOpenKeyExA(HKEY_CLASSES_ROOT, string, 0, 1, &newkey); - RegQueryValueExA(newkey, 0, 0, &type, (PBYTE)value, &count); - RegCloseKey(newkey); - return LoadLibraryExA(value, 0, 0); -} - -/************************************************************************* - * @ [SHLWAPI.237] - * - * Unicode version of SHLWAPI_183. - */ -DWORD WINAPI SHRegisterClassW(WNDCLASSW * lpWndClass) -{ - WNDCLASSW WndClass; - - TRACE("(%p %s)\n",lpWndClass->hInstance, debugstr_w(lpWndClass->lpszClassName)); - - if (GetClassInfoW(lpWndClass->hInstance, lpWndClass->lpszClassName, &WndClass)) - return TRUE; - return RegisterClassW(lpWndClass); -} - -/************************************************************************* - * @ [SHLWAPI.238] - * - * Unregister a list of classes. - * - * PARAMS - * hInst [I] Application instance that registered the classes - * lppClasses [I] List of class names - * iCount [I] Number of names in lppClasses - * - * RETURNS - * Nothing. - */ -void WINAPI SHUnregisterClassesA(HINSTANCE hInst, LPCSTR *lppClasses, INT iCount) -{ - WNDCLASSA WndClass; - - TRACE("(%p,%p,%d)\n", hInst, lppClasses, iCount); - - while (iCount > 0) - { - if (GetClassInfoA(hInst, *lppClasses, &WndClass)) - UnregisterClassA(*lppClasses, hInst); - lppClasses++; - iCount--; - } -} - -/************************************************************************* - * @ [SHLWAPI.239] - * - * Unicode version of SHUnregisterClassesA. - */ -void WINAPI SHUnregisterClassesW(HINSTANCE hInst, LPCWSTR *lppClasses, INT iCount) -{ - WNDCLASSW WndClass; - - TRACE("(%p,%p,%d)\n", hInst, lppClasses, iCount); - - while (iCount > 0) - { - if (GetClassInfoW(hInst, *lppClasses, &WndClass)) - UnregisterClassW(*lppClasses, hInst); - lppClasses++; - iCount--; - } -} - -/************************************************************************* - * @ [SHLWAPI.240] - * - * Call The correct (Ascii/Unicode) default window procedure for a window. - * - * PARAMS - * hWnd [I] Window to call the default procedure for - * uMessage [I] Message ID - * wParam [I] WPARAM of message - * lParam [I] LPARAM of message - * - * RETURNS - * The result of calling DefWindowProcA() or DefWindowProcW(). - */ -LRESULT CALLBACK SHDefWindowProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam) -{ - if (IsWindowUnicode(hWnd)) - return DefWindowProcW(hWnd, uMessage, wParam, lParam); - return DefWindowProcA(hWnd, uMessage, wParam, lParam); -} - -/************************************************************************* - * @ [SHLWAPI.256] - */ -HRESULT WINAPI IUnknown_GetSite(LPUNKNOWN lpUnknown, REFIID iid, PVOID *lppSite) -{ - HRESULT hRet = E_INVALIDARG; - LPOBJECTWITHSITE lpSite = NULL; - - TRACE("(%p,%s,%p)\n", lpUnknown, debugstr_guid(iid), lppSite); - - if (lpUnknown && iid && lppSite) - { - hRet = IUnknown_QueryInterface(lpUnknown, &IID_IObjectWithSite, - (void**)&lpSite); - if (SUCCEEDED(hRet) && lpSite) - { - hRet = IObjectWithSite_GetSite(lpSite, iid, lppSite); - IObjectWithSite_Release(lpSite); - } - } - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.257] - * - * Create a worker window using CreateWindowExA(). - * - * PARAMS - * wndProc [I] Window procedure - * hWndParent [I] Parent window - * dwExStyle [I] Extra style flags - * dwStyle [I] Style flags - * hMenu [I] Window menu - * z [I] Unknown - * - * RETURNS - * Success: The window handle of the newly created window. - * Failure: 0. - */ -HWND WINAPI SHCreateWorkerWindowA(LONG wndProc, HWND hWndParent, DWORD dwExStyle, - DWORD dwStyle, HMENU hMenu, LONG z) -{ - static const char* szClass = "WorkerA"; - WNDCLASSA wc; - HWND hWnd; - - TRACE("(0x%08lx,%p,0x%08lx,0x%08lx,%p,0x%08lx)\n", - wndProc, hWndParent, dwExStyle, dwStyle, hMenu, z); - - /* Create Window class */ - wc.style = 0; - wc.lpfnWndProc = DefWindowProcA; - wc.cbClsExtra = 0; - wc.cbWndExtra = 4; - wc.hInstance = shlwapi_hInstance; - wc.hIcon = NULL; - wc.hCursor = LoadCursorA(NULL, (LPSTR)IDC_ARROW); - wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW; - wc.lpszMenuName = NULL; - wc.lpszClassName = szClass; - - SHRegisterClassA(&wc); /* Register class */ - - /* FIXME: Set extra bits in dwExStyle */ - - hWnd = CreateWindowExA(dwExStyle, szClass, 0, dwStyle, 0, 0, 0, 0, - hWndParent, hMenu, shlwapi_hInstance, 0); - if (hWnd) - { - SetWindowLongPtrW(hWnd, DWLP_MSGRESULT, z); - - if (wndProc) - SetWindowLongPtrA(hWnd, GWLP_WNDPROC, wndProc); - } - return hWnd; -} - -typedef struct tagPOLICYDATA -{ - DWORD policy; /* flags value passed to SHRestricted */ - LPCWSTR appstr; /* application str such as "Explorer" */ - LPCWSTR keystr; /* name of the actual registry key / policy */ -} POLICYDATA, *LPPOLICYDATA; - -#define SHELL_NO_POLICY 0xffffffff - -/* default shell policy registry key */ -static const WCHAR strRegistryPolicyW[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o', - 's','o','f','t','\\','W','i','n','d','o','w','s','\\', - 'C','u','r','r','e','n','t','V','e','r','s','i','o','n', - '\\','P','o','l','i','c','i','e','s',0}; - -/************************************************************************* - * @ [SHLWAPI.271] - * - * Retrieve a policy value from the registry. - * - * PARAMS - * lpSubKey [I] registry key name - * lpSubName [I] subname of registry key - * lpValue [I] value name of registry value - * - * RETURNS - * the value associated with the registry key or 0 if not found - */ -DWORD WINAPI SHGetRestriction(LPCWSTR lpSubKey, LPCWSTR lpSubName, LPCWSTR lpValue) -{ - DWORD retval, datsize = sizeof(retval); - HKEY hKey; - - if (!lpSubKey) - lpSubKey = strRegistryPolicyW; - - retval = RegOpenKeyW(HKEY_LOCAL_MACHINE, lpSubKey, &hKey); - if (retval != ERROR_SUCCESS) - retval = RegOpenKeyW(HKEY_CURRENT_USER, lpSubKey, &hKey); - if (retval != ERROR_SUCCESS) - return 0; - - SHGetValueW(hKey, lpSubName, lpValue, NULL, (LPBYTE)&retval, &datsize); - RegCloseKey(hKey); - return retval; -} - -/************************************************************************* - * @ [SHLWAPI.266] - * - * Helper function to retrieve the possibly cached value for a specific policy - * - * PARAMS - * policy [I] The policy to look for - * initial [I] Main registry key to open, if NULL use default - * polTable [I] Table of known policies, 0 terminated - * polArr [I] Cache array of policy values - * - * RETURNS - * The retrieved policy value or 0 if not successful - * - * NOTES - * This function is used by the native SHRestricted function to search for the - * policy and cache it once retrieved. The current Wine implementation uses a - * different POLICYDATA structure and implements a similar algorithme adapted to - * that structure. - */ -DWORD WINAPI SHRestrictionLookup( - DWORD policy, - LPCWSTR initial, - LPPOLICYDATA polTable, - LPDWORD polArr) -{ - TRACE("(0x%08lx %s %p %p)\n", policy, debugstr_w(initial), polTable, polArr); - - if (!polTable || !polArr) - return 0; - - for (;polTable->policy; polTable++, polArr++) - { - if (policy == polTable->policy) - { - /* we have a known policy */ - - /* check if this policy has been cached */ - if (*polArr == SHELL_NO_POLICY) - *polArr = SHGetRestriction(initial, polTable->appstr, polTable->keystr); - return *polArr; - } - } - /* we don't know this policy, return 0 */ - TRACE("unknown policy: (%08lx)\n", policy); - return 0; -} - -/************************************************************************* - * @ [SHLWAPI.267] - * - * Get an interface from an object. - * - * RETURNS - * Success: S_OK. ppv contains the requested interface. - * Failure: An HRESULT error code. - * - * NOTES - * This QueryInterface asks the inner object for an interface. In case - * of aggregation this request would be forwarded by the inner to the - * outer object. This function asks the inner object directly for the - * interface circumventing the forwarding to the outer object. - */ -HRESULT WINAPI SHWeakQueryInterface( - IUnknown * pUnk, /* [in] Outer object */ - IUnknown * pInner, /* [in] Inner object */ - IID * riid, /* [in] Interface GUID to query for */ - LPVOID* ppv) /* [out] Destination for queried interface */ -{ - HRESULT hret = E_NOINTERFACE; - TRACE("(pUnk=%p pInner=%p\n\tIID: %s %p)\n",pUnk,pInner,debugstr_guid(riid), ppv); - - *ppv = NULL; - if(pUnk && pInner) { - hret = IUnknown_QueryInterface(pInner, riid, (LPVOID*)ppv); - if (SUCCEEDED(hret)) IUnknown_Release(pUnk); - } - TRACE("-- 0x%08lx\n", hret); - return hret; -} - -/************************************************************************* - * @ [SHLWAPI.268] - * - * Move a reference from one interface to another. - * - * PARAMS - * lpDest [O] Destination to receive the reference - * lppUnknown [O] Source to give up the reference to lpDest - * - * RETURNS - * Nothing. - */ -VOID WINAPI SHWeakReleaseInterface(IUnknown *lpDest, IUnknown **lppUnknown) -{ - TRACE("(%p,%p)\n", lpDest, lppUnknown); - - if (*lppUnknown) - { - /* Copy Reference*/ - IUnknown_AddRef(lpDest); - IUnknown_AtomicRelease(lppUnknown); /* Release existing interface */ - } -} - -/************************************************************************* - * @ [SHLWAPI.269] - * - * Convert an ASCII string of a CLSID into a CLSID. - * - * PARAMS - * idstr [I] String representing a CLSID in registry format - * id [O] Destination for the converted CLSID - * - * RETURNS - * Success: TRUE. id contains the converted CLSID. - * Failure: FALSE. - */ -BOOL WINAPI GUIDFromStringA(LPCSTR idstr, CLSID *id) -{ - WCHAR wClsid[40]; - MultiByteToWideChar(CP_ACP, 0, idstr, -1, wClsid, sizeof(wClsid)/sizeof(WCHAR)); - return SUCCEEDED(CLSIDFromStringWrap(wClsid, id)); -} - -/************************************************************************* - * @ [SHLWAPI.270] - * - * Unicode version of GUIDFromStringA. - */ -BOOL WINAPI GUIDFromStringW(LPCWSTR idstr, CLSID *id) -{ - return SUCCEEDED(CLSIDFromStringWrap(idstr, id)); -} - -/************************************************************************* - * @ [SHLWAPI.276] - * - * Determine if the browser is integrated into the shell, and set a registry - * key accordingly. - * - * PARAMS - * None. - * - * RETURNS - * 1, If the browser is not integrated. - * 2, If the browser is integrated. - * - * NOTES - * The key "HKLM\Software\Microsoft\Internet Explorer\IntegratedBrowser" is - * either set to TRUE, or removed depending on whether the browser is deemed - * to be integrated. - */ -DWORD WINAPI WhichPlatform() -{ - static LPCSTR szIntegratedBrowser = "IntegratedBrowser"; - static DWORD dwState = 0; - HKEY hKey; - DWORD dwRet, dwData, dwSize; - - if (dwState) - return dwState; - - /* If shell32 exports DllGetVersion(), the browser is integrated */ - GET_FUNC(pDllGetVersion, shell32, "DllGetVersion", 1); - dwState = pDllGetVersion ? 2 : 1; - - /* Set or delete the key accordingly */ - dwRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE, - "Software\\Microsoft\\Internet Explorer", 0, - KEY_ALL_ACCESS, &hKey); - if (!dwRet) - { - dwRet = RegQueryValueExA(hKey, szIntegratedBrowser, 0, 0, - (LPBYTE)&dwData, &dwSize); - - if (!dwRet && dwState == 1) - { - /* Value exists but browser is not integrated */ - RegDeleteValueA(hKey, szIntegratedBrowser); - } - else if (dwRet && dwState == 2) - { - /* Browser is integrated but value does not exist */ - dwData = TRUE; - RegSetValueExA(hKey, szIntegratedBrowser, 0, REG_DWORD, - (LPBYTE)&dwData, sizeof(dwData)); - } - RegCloseKey(hKey); - } - return dwState; -} - -/************************************************************************* - * @ [SHLWAPI.278] - * - * Unicode version of SHCreateWorkerWindowA. - */ -HWND WINAPI SHCreateWorkerWindowW(LONG wndProc, HWND hWndParent, DWORD dwExStyle, - DWORD dwStyle, HMENU hMenu, LONG z) -{ - static const WCHAR szClass[] = { 'W', 'o', 'r', 'k', 'e', 'r', 'W', '\0' }; - WNDCLASSW wc; - HWND hWnd; - - TRACE("(0x%08lx,%p,0x%08lx,0x%08lx,%p,0x%08lx)\n", - wndProc, hWndParent, dwExStyle, dwStyle, hMenu, z); - - /* If our OS is natively ASCII, use the ASCII version */ - if (!(GetVersion() & 0x80000000)) /* NT */ - return SHCreateWorkerWindowA(wndProc, hWndParent, dwExStyle, dwStyle, hMenu, z); - - /* Create Window class */ - wc.style = 0; - wc.lpfnWndProc = DefWindowProcW; - wc.cbClsExtra = 0; - wc.cbWndExtra = 4; - wc.hInstance = shlwapi_hInstance; - wc.hIcon = NULL; - wc.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW); - wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW; - wc.lpszMenuName = NULL; - wc.lpszClassName = szClass; - - SHRegisterClassW(&wc); /* Register class */ - - /* FIXME: Set extra bits in dwExStyle */ - - hWnd = CreateWindowExW(dwExStyle, szClass, 0, dwStyle, 0, 0, 0, 0, - hWndParent, hMenu, shlwapi_hInstance, 0); - if (hWnd) - { - SetWindowLongPtrW(hWnd, DWLP_MSGRESULT, z); - - if (wndProc) - SetWindowLongPtrW(hWnd, GWLP_WNDPROC, wndProc); - } - return hWnd; -} - -/************************************************************************* - * @ [SHLWAPI.279] - * - * Get and show a context menu from a shell folder. - * - * PARAMS - * hWnd [I] Window displaying the shell folder - * lpFolder [I] IShellFolder interface - * lpApidl [I] Id for the particular folder desired - * - * RETURNS - * Success: S_OK. - * Failure: An HRESULT error code indicating the error. - */ -HRESULT WINAPI SHInvokeDefaultCommand(HWND hWnd, IShellFolder* lpFolder, LPCITEMIDLIST lpApidl) -{ - return SHInvokeCommand(hWnd, lpFolder, lpApidl, FALSE); -} - -/************************************************************************* - * @ [SHLWAPI.281] - * - * _SHPackDispParamsV - */ -HRESULT WINAPI SHPackDispParamsV(LPVOID w, LPVOID x, LPVOID y, LPVOID z) -{ - FIXME("%p %p %p %p\n",w,x,y,z); - return E_FAIL; -} - -/************************************************************************* - * @ [SHLWAPI.282] - * - * This function seems to be a forward to SHPackDispParamsV (whatever THAT - * function does...). - */ -HRESULT WINAPI SHPackDispParams(LPVOID w, LPVOID x, LPVOID y, LPVOID z) -{ - FIXME("%p %p %p %p\n", w, x, y, z); - return E_FAIL; -} - -/************************************************************************* - * @ [SHLWAPI.284] - * - * _IConnectionPoint_SimpleInvoke - */ -DWORD WINAPI IConnectionPoint_SimpleInvoke( - LPVOID x, - LPVOID y, - LPVOID z) -{ - FIXME("(%p %p %p) stub\n",x,y,z); - return 0; -} - -/************************************************************************* - * @ [SHLWAPI.285] - * - * Notify an IConnectionPoint object of changes. - * - * PARAMS - * lpCP [I] Object to notify - * dispID [I] - * - * RETURNS - * Success: S_OK. - * Failure: E_NOINTERFACE, if lpCP is NULL or does not support the - * IConnectionPoint interface. - */ -HRESULT WINAPI IConnectionPoint_OnChanged(IConnectionPoint* lpCP, DISPID dispID) -{ - IEnumConnections *lpEnum; - HRESULT hRet = E_NOINTERFACE; - - TRACE("(%p,0x%8lX)\n", lpCP, dispID); - - /* Get an enumerator for the connections */ - if (lpCP) - hRet = IConnectionPoint_EnumConnections(lpCP, &lpEnum); - - if (SUCCEEDED(hRet)) - { - IPropertyNotifySink *lpSink; - CONNECTDATA connData; - ULONG ulFetched; - - /* Call OnChanged() for every notify sink in the connection point */ - while (IEnumConnections_Next(lpEnum, 1, &connData, &ulFetched) == S_OK) - { - if (SUCCEEDED(IUnknown_QueryInterface(connData.pUnk, &IID_IPropertyNotifySink, (void**)&lpSink)) && - lpSink) - { - IPropertyNotifySink_OnChanged(lpSink, dispID); - IPropertyNotifySink_Release(lpSink); - } - IUnknown_Release(connData.pUnk); - } - - IEnumConnections_Release(lpEnum); - } - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.287] - * - * Notify an IConnectionPointContainer object of changes. - * - * PARAMS - * lpUnknown [I] Object to notify - * dispID [I] - * - * RETURNS - * Success: S_OK. - * Failure: E_NOINTERFACE, if lpUnknown is NULL or does not support the - * IConnectionPointContainer interface. - */ -HRESULT WINAPI IUnknown_CPContainerOnChanged(IUnknown *lpUnknown, DISPID dispID) -{ - IConnectionPointContainer* lpCPC = NULL; - HRESULT hRet = E_NOINTERFACE; - - TRACE("(%p,0x%8lX)\n", lpUnknown, dispID); - - if (lpUnknown) - hRet = IUnknown_QueryInterface(lpUnknown, &IID_IConnectionPointContainer, (void**)&lpCPC); - - if (SUCCEEDED(hRet)) - { - IConnectionPoint* lpCP; - - hRet = IConnectionPointContainer_FindConnectionPoint(lpCPC, &IID_IPropertyNotifySink, &lpCP); - IConnectionPointContainer_Release(lpCPC); - - hRet = IConnectionPoint_OnChanged(lpCP, dispID); - IConnectionPoint_Release(lpCP); - } - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.289] - * - * See PlaySoundW. - */ -BOOL WINAPI PlaySoundWrapW(LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound) -{ - GET_FUNC(pPlaySoundW, winmm, "PlaySoundW", FALSE); - return pPlaySoundW(pszSound, hmod, fdwSound); -} - -/************************************************************************* - * @ [SHLWAPI.294] - */ -BOOL WINAPI SHGetIniStringW(LPSTR str1, LPSTR str2, LPSTR pStr, DWORD some_len, LPCSTR lpStr2) -{ - /* - * str1: "I" "I" pushl esp+0x20 - * str2: "U" "I" pushl 0x77c93810 - * (is "I" and "U" "integer" and "unsigned" ??) - * - * pStr: "" "" pushl eax - * some_len: 0x824 0x104 pushl 0x824 - * lpStr2: "%l" "%l" pushl esp+0xc - * - * shlwapi. StrCpyNW(lpStr2, irrelevant_var, 0x104); - * LocalAlloc(0x00, some_len) -> irrelevant_var - * LocalAlloc(0x40, irrelevant_len) -> pStr - * shlwapi.294(str1, str2, pStr, some_len, lpStr2); - * shlwapi.PathRemoveBlanksW(pStr); - */ - FIXME("('%s', '%s', '%s', %08lx, '%s'): stub!\n", str1, str2, pStr, some_len, lpStr2); - return TRUE; -} - -/************************************************************************* - * @ [SHLWAPI.295] - * - * Called by ICQ2000b install via SHDOCVW: - * str1: "InternetShortcut" - * x: some unknown pointer - * str2: "http://free.aol.com/tryaolfree/index.adp?139269" - * str3: "C:\\WINDOWS\\Desktop.new2\\Free AOL & Unlimited Internet.url" - * - * In short: this one maybe creates a desktop link :-) - */ -BOOL WINAPI SHSetIniStringW(LPWSTR str1, LPVOID x, LPWSTR str2, LPWSTR str3) -{ - FIXME("('%s', %p, '%s', '%s'), stub.\n", debugstr_w(str1), x, debugstr_w(str2), debugstr_w(str3)); - return TRUE; -} - -/************************************************************************* - * @ [SHLWAPI.299] - * - * See COMCTL32_417. - */ -BOOL WINAPI ExtTextOutWrapW(HDC hdc, INT x, INT y, UINT flags, const RECT *lprect, - LPCWSTR str, UINT count, const INT *lpDx) -{ - GET_FUNC(pCOMCTL32_417, comctl32, (LPCSTR)417, FALSE); - return pCOMCTL32_417(hdc, x, y, flags, lprect, str, count, lpDx); -} - -/************************************************************************* - * @ [SHLWAPI.313] - * - * See SHGetFileInfoW. - */ -DWORD WINAPI SHGetFileInfoWrapW(LPCWSTR path, DWORD dwFileAttributes, - SHFILEINFOW *psfi, UINT sizeofpsfi, UINT flags) -{ - GET_FUNC(pSHGetFileInfoW, shell32, "SHGetFileInfoW", 0); - return pSHGetFileInfoW(path, dwFileAttributes, psfi, sizeofpsfi, flags); -} - -/************************************************************************* - * @ [SHLWAPI.318] - * - * See DragQueryFileW. - */ -UINT WINAPI DragQueryFileWrapW(HDROP hDrop, UINT lFile, LPWSTR lpszFile, UINT lLength) -{ - GET_FUNC(pDragQueryFileW, shell32, "DragQueryFileW", 0); - return pDragQueryFileW(hDrop, lFile, lpszFile, lLength); -} - -/************************************************************************* - * @ [SHLWAPI.333] - * - * See SHBrowseForFolderW. - */ -LPITEMIDLIST WINAPI SHBrowseForFolderWrapW(LPBROWSEINFOW lpBi) -{ - GET_FUNC(pSHBrowseForFolderW, shell32, "SHBrowseForFolderW", NULL); - return pSHBrowseForFolderW(lpBi); -} - -/************************************************************************* - * @ [SHLWAPI.334] - * - * See SHGetPathFromIDListW. - */ -BOOL WINAPI SHGetPathFromIDListWrapW(LPCITEMIDLIST pidl,LPWSTR pszPath) -{ - GET_FUNC(pSHGetPathFromIDListW, shell32, "SHGetPathFromIDListW", 0); - return pSHGetPathFromIDListW(pidl, pszPath); -} - -/************************************************************************* - * @ [SHLWAPI.335] - * - * See ShellExecuteExW. - */ -BOOL WINAPI ShellExecuteExWrapW(LPSHELLEXECUTEINFOW lpExecInfo) -{ - GET_FUNC(pShellExecuteExW, shell32, "ShellExecuteExW", FALSE); - return pShellExecuteExW(lpExecInfo); -} - -/************************************************************************* - * @ [SHLWAPI.336] - * - * See SHFileOperationW. - */ -HICON WINAPI SHFileOperationWrapW(LPSHFILEOPSTRUCTW lpFileOp) -{ - GET_FUNC(pSHFileOperationW, shell32, "SHFileOperationW", 0); - return pSHFileOperationW(lpFileOp); -} - -/************************************************************************* - * @ [SHLWAPI.337] - * - * See ExtractIconExW. - */ -UINT WINAPI ExtractIconExWrapW(LPCWSTR lpszFile, INT nIconIndex, HICON *phiconLarge, - HICON *phiconSmall, UINT nIcons) -{ - GET_FUNC(pExtractIconExW, shell32, "ExtractIconExW", 0); - return pExtractIconExW(lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons); -} - -/************************************************************************* - * @ [SHLWAPI.342] - * - */ -LONG WINAPI SHInterlockedCompareExchange( PLONG dest, LONG xchg, LONG compare) -{ - return InterlockedCompareExchange(dest, xchg, compare); -} - -/************************************************************************* - * @ [SHLWAPI.350] - * - * See GetFileVersionInfoSizeW. - */ -DWORD WINAPI GetFileVersionInfoSizeWrapW( - LPWSTR x, - LPVOID y) -{ - DWORD ret; - - GET_FUNC(pGetFileVersionInfoSizeW, version, "GetFileVersionInfoSizeW", 0); - ret = pGetFileVersionInfoSizeW(x, y); - return 0x208 + ret; -} - -/************************************************************************* - * @ [SHLWAPI.351] - * - * See GetFileVersionInfoW. - */ -BOOL WINAPI GetFileVersionInfoWrapW( - LPWSTR w, /* [in] path to dll */ - DWORD x, /* [in] parm 2 to GetFileVersionInfoA */ - DWORD y, /* [in] return value from SHLWAPI_350() - assume length */ - LPVOID z) /* [in/out] buffer (+0x208 sent to GetFileVersionInfoA()) */ -{ - GET_FUNC(pGetFileVersionInfoW, version, "GetFileVersionInfoW", 0); - return pGetFileVersionInfoW(w, x, y-0x208, (char*)z+0x208); -} - -/************************************************************************* - * @ [SHLWAPI.352] - * - * See VerQueryValueW. - */ -WORD WINAPI VerQueryValueWrapW( - LPVOID w, /* [in] Buffer from SHLWAPI_351() */ - LPWSTR x, /* [in] Value to retrieve - converted and passed to VerQueryValueA() as #2 */ - LPVOID y, /* [out] Ver buffer - passed to VerQueryValueA as #3 */ - UINT* z) /* [in] Ver length - passed to VerQueryValueA as #4 */ -{ - GET_FUNC(pVerQueryValueW, version, "VerQueryValueW", 0); - return pVerQueryValueW((char*)w+0x208, x, y, z); -} - -#define IsIface(type) SUCCEEDED((hRet = IUnknown_QueryInterface(lpUnknown, &IID_##type, (void**)&lpObj))) -#define IShellBrowser_EnableModeless IShellBrowser_EnableModelessSB -#define EnableModeless(type) type##_EnableModeless((type*)lpObj, bModeless) - -/************************************************************************* - * @ [SHLWAPI.355] - * - * Change the modality of a shell object. - * - * PARAMS - * lpUnknown [I] Object to make modeless - * bModeless [I] TRUE=Make modeless, FALSE=Make modal - * - * RETURNS - * Success: S_OK. The modality lpUnknown is changed. - * Failure: An HRESULT error code indicating the error. - * - * NOTES - * lpUnknown must support the IOleInPlaceFrame interface, the - * IInternetSecurityMgrSite interface, the IShellBrowser interface - * the IDocHostUIHandler interface, or the IOleInPlaceActiveObject interface, - * or this call will fail. - */ -HRESULT WINAPI IUnknown_EnableModeless(IUnknown *lpUnknown, BOOL bModeless) -{ - IUnknown *lpObj; - HRESULT hRet; - - TRACE("(%p,%d)\n", lpUnknown, bModeless); - - if (!lpUnknown) - return E_FAIL; - - if (IsIface(IOleInPlaceActiveObject)) - EnableModeless(IOleInPlaceActiveObject); - else if (IsIface(IOleInPlaceFrame)) - EnableModeless(IOleInPlaceFrame); - else if (IsIface(IShellBrowser)) - EnableModeless(IShellBrowser); -#if 0 - /* FIXME: Wine has no headers for these objects yet */ - else if (IsIface(IInternetSecurityMgrSite)) - EnableModeless(IInternetSecurityMgrSite); - else if (IsIface(IDocHostUIHandler)) - EnableModeless(IDocHostUIHandler); -#endif - else - return hRet; - - IUnknown_Release(lpObj); - return S_OK; -} - -/************************************************************************* - * @ [SHLWAPI.357] - * - * See SHGetNewLinkInfoW. - */ -BOOL WINAPI SHGetNewLinkInfoWrapW(LPCWSTR pszLinkTo, LPCWSTR pszDir, LPWSTR pszName, - BOOL *pfMustCopy, UINT uFlags) -{ - GET_FUNC(pSHGetNewLinkInfoW, shell32, "SHGetNewLinkInfoW", FALSE); - return pSHGetNewLinkInfoW(pszLinkTo, pszDir, pszName, pfMustCopy, uFlags); -} - -/************************************************************************* - * @ [SHLWAPI.358] - * - * See SHDefExtractIconW. - */ -UINT WINAPI SHDefExtractIconWrapW(LPCWSTR pszIconFile, int iIndex, UINT uFlags, HICON* phiconLarge, - HICON* phiconSmall, UINT nIconSize) -{ - GET_FUNC(pSHDefExtractIconW, shell32, "SHDefExtractIconW", 0); - return pSHDefExtractIconW(pszIconFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize); -} - -/************************************************************************* - * @ [SHLWAPI.363] - * - * Get and show a context menu from a shell folder. - * - * PARAMS - * hWnd [I] Window displaying the shell folder - * lpFolder [I] IShellFolder interface - * lpApidl [I] Id for the particular folder desired - * bInvokeDefault [I] Whether to invoke the default menu item - * - * RETURNS - * Success: S_OK. If bInvokeDefault is TRUE, the default menu action was - * executed. - * Failure: An HRESULT error code indicating the error. - */ -HRESULT WINAPI SHInvokeCommand(HWND hWnd, IShellFolder* lpFolder, LPCITEMIDLIST lpApidl, BOOL bInvokeDefault) -{ - IContextMenu *iContext; - HRESULT hRet = E_FAIL; - - TRACE("(%p,%p,%p,%d)\n", hWnd, lpFolder, lpApidl, bInvokeDefault); - - if (!lpFolder) - return hRet; - - /* Get the context menu from the shell folder */ - hRet = IShellFolder_GetUIObjectOf(lpFolder, hWnd, 1, &lpApidl, - &IID_IContextMenu, 0, (void**)&iContext); - if (SUCCEEDED(hRet)) - { - HMENU hMenu; - if ((hMenu = CreatePopupMenu())) - { - HRESULT hQuery; - DWORD dwDefaultId = 0; - - /* Add the context menu entries to the popup */ - hQuery = IContextMenu_QueryContextMenu(iContext, hMenu, 0, 1, 0x7FFF, - bInvokeDefault ? CMF_NORMAL : CMF_DEFAULTONLY); - - if (SUCCEEDED(hQuery)) - { - if (bInvokeDefault && - (dwDefaultId = GetMenuDefaultItem(hMenu, 0, 0)) != 0xFFFFFFFF) - { - CMINVOKECOMMANDINFO cmIci; - /* Invoke the default item */ - memset(&cmIci,0,sizeof(cmIci)); - cmIci.cbSize = sizeof(cmIci); - cmIci.fMask = CMIC_MASK_ASYNCOK; - cmIci.hwnd = hWnd; - cmIci.lpVerb = MAKEINTRESOURCEA(dwDefaultId); - cmIci.nShow = SW_SCROLLCHILDREN; - - hRet = IContextMenu_InvokeCommand(iContext, &cmIci); - } - } - DestroyMenu(hMenu); - } - IContextMenu_Release(iContext); - } - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.370] - * - * See ExtractIconW. - */ -HICON WINAPI ExtractIconWrapW(HINSTANCE hInstance, LPCWSTR lpszExeFileName, - UINT nIconIndex) -{ - GET_FUNC(pExtractIconW, shell32, "ExtractIconW", NULL); - return pExtractIconW(hInstance, lpszExeFileName, nIconIndex); -} - -/************************************************************************* - * @ [SHLWAPI.376] - */ -LANGID WINAPI MLGetUILanguage() -{ - FIXME("() stub\n"); - /* FIXME: This should be a forward in the .spec file to the win2k function - * kernel32.GetUserDefaultUILanguage, however that function isn't there yet. - */ - return GetUserDefaultLangID(); -} - -/************************************************************************* - * @ [SHLWAPI.377] - * - * Load a library from the directory of a particular process. - * - * PARAMS - * new_mod [I] Library name - * inst_hwnd [I] Module whose directory is to be used - * dwFlags [I] Flags controlling the load - * - * RETURNS - * Success: A handle to the loaded module - * Failure: A NULL handle. - */ -HMODULE WINAPI MLLoadLibraryA(LPCSTR new_mod, HMODULE inst_hwnd, DWORD dwFlags) -{ - /* FIXME: Native appears to do DPA_Create and a DPA_InsertPtr for - * each call here. - * FIXME: Native shows calls to: - * SHRegGetUSValue for "Software\Microsoft\Internet Explorer\International" - * CheckVersion - * RegOpenKeyExA for "HKLM\Software\Microsoft\Internet Explorer" - * RegQueryValueExA for "LPKInstalled" - * RegCloseKey - * RegOpenKeyExA for "HKCU\Software\Microsoft\Internet Explorer\International" - * RegQueryValueExA for "ResourceLocale" - * RegCloseKey - * RegOpenKeyExA for "HKLM\Software\Microsoft\Active Setup\Installed Components\{guid}" - * RegQueryValueExA for "Locale" - * RegCloseKey - * and then tests the Locale ("en" for me). - * code below - * after the code then a DPA_Create (first time) and DPA_InsertPtr are done. - */ - CHAR mod_path[2*MAX_PATH]; - LPSTR ptr; - DWORD len; - - FIXME("(%s,%p,0x%08lx) semi-stub!\n", debugstr_a(new_mod), inst_hwnd, dwFlags); - len = GetModuleFileNameA(inst_hwnd, mod_path, sizeof(mod_path)); - if (!len || len >= sizeof(mod_path)) return NULL; - - ptr = strrchr(mod_path, '\\'); - if (ptr) { - strcpy(ptr+1, new_mod); - TRACE("loading %s\n", debugstr_a(mod_path)); - return LoadLibraryA(mod_path); - } - return NULL; -} - -/************************************************************************* - * @ [SHLWAPI.378] - * - * Unicode version of MLLoadLibraryA. - */ -HMODULE WINAPI MLLoadLibraryW(LPCWSTR new_mod, HMODULE inst_hwnd, DWORD dwFlags) -{ - WCHAR mod_path[2*MAX_PATH]; - LPWSTR ptr; - DWORD len; - - FIXME("(%s,%p,0x%08lx) semi-stub!\n", debugstr_w(new_mod), inst_hwnd, dwFlags); - len = GetModuleFileNameW(inst_hwnd, mod_path, sizeof(mod_path) / sizeof(WCHAR)); - if (!len || len >= sizeof(mod_path) / sizeof(WCHAR)) return NULL; - - ptr = strrchrW(mod_path, '\\'); - if (ptr) { - strcpyW(ptr+1, new_mod); - TRACE("loading %s\n", debugstr_w(mod_path)); - return LoadLibraryW(mod_path); - } - return NULL; -} - -/************************************************************************* - * ColorAdjustLuma [SHLWAPI.@] - * - * Adjust the luminosity of a color - * - * PARAMS - * cRGB [I] RGB value to convert - * dwLuma [I] Luma adjustment - * bUnknown [I] Unknown - * - * RETURNS - * The adjusted RGB color. - */ -COLORREF WINAPI ColorAdjustLuma(COLORREF cRGB, int dwLuma, BOOL bUnknown) -{ - TRACE("(0x%8lx,%d,%d)\n", cRGB, dwLuma, bUnknown); - - if (dwLuma) - { - WORD wH, wL, wS; - - ColorRGBToHLS(cRGB, &wH, &wL, &wS); - - FIXME("Ignoring luma adjustment\n"); - - /* FIXME: The ajdustment is not linear */ - - cRGB = ColorHLSToRGB(wH, wL, wS); - } - return cRGB; -} - -/************************************************************************* - * @ [SHLWAPI.389] - * - * See GetSaveFileNameW. - */ -BOOL WINAPI GetSaveFileNameWrapW(LPOPENFILENAMEW ofn) -{ - GET_FUNC(pGetSaveFileNameW, comdlg32, "GetSaveFileNameW", FALSE); - return pGetSaveFileNameW(ofn); -} - -/************************************************************************* - * @ [SHLWAPI.390] - * - * See WNetRestoreConnectionW. - */ -DWORD WINAPI WNetRestoreConnectionWrapW(HWND hwndOwner, LPWSTR lpszDevice) -{ - GET_FUNC(pWNetRestoreConnectionW, mpr, "WNetRestoreConnectionW", 0); - return pWNetRestoreConnectionW(hwndOwner, lpszDevice); -} - -/************************************************************************* - * @ [SHLWAPI.391] - * - * See WNetGetLastErrorW. - */ -DWORD WINAPI WNetGetLastErrorWrapW(LPDWORD lpError, LPWSTR lpErrorBuf, DWORD nErrorBufSize, - LPWSTR lpNameBuf, DWORD nNameBufSize) -{ - GET_FUNC(pWNetGetLastErrorW, mpr, "WNetGetLastErrorW", 0); - return pWNetGetLastErrorW(lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize); -} - -/************************************************************************* - * @ [SHLWAPI.401] - * - * See PageSetupDlgW. - */ -BOOL WINAPI PageSetupDlgWrapW(LPPAGESETUPDLGW pagedlg) -{ - GET_FUNC(pPageSetupDlgW, comdlg32, "PageSetupDlgW", FALSE); - return pPageSetupDlgW(pagedlg); -} - -/************************************************************************* - * @ [SHLWAPI.402] - * - * See PrintDlgW. - */ -BOOL WINAPI PrintDlgWrapW(LPPRINTDLGW printdlg) -{ - GET_FUNC(pPrintDlgW, comdlg32, "PrintDlgW", FALSE); - return pPrintDlgW(printdlg); -} - -/************************************************************************* - * @ [SHLWAPI.403] - * - * See GetOpenFileNameW. - */ -BOOL WINAPI GetOpenFileNameWrapW(LPOPENFILENAMEW ofn) -{ - GET_FUNC(pGetOpenFileNameW, comdlg32, "GetOpenFileNameW", FALSE); - return pGetOpenFileNameW(ofn); -} - -/* INTERNAL: Map from HLS color space to RGB */ -static WORD WINAPI ConvertHue(int wHue, WORD wMid1, WORD wMid2) -{ - wHue = wHue > 240 ? wHue - 240 : wHue < 0 ? wHue + 240 : wHue; - - if (wHue > 160) - return wMid1; - else if (wHue > 120) - wHue = 160 - wHue; - else if (wHue > 40) - return wMid2; - - return ((wHue * (wMid2 - wMid1) + 20) / 40) + wMid1; -} - -/* Convert to RGB and scale into RGB range (0..255) */ -#define GET_RGB(h) (ConvertHue(h, wMid1, wMid2) * 255 + 120) / 240 - -/************************************************************************* - * ColorHLSToRGB [SHLWAPI.@] - * - * Convert from hls color space into an rgb COLORREF. - * - * PARAMS - * wHue [I] Hue amount - * wLuminosity [I] Luminosity amount - * wSaturation [I] Saturation amount - * - * RETURNS - * A COLORREF representing the converted color. - * - * NOTES - * Input hls values are constrained to the range (0..240). - */ -COLORREF WINAPI ColorHLSToRGB(WORD wHue, WORD wLuminosity, WORD wSaturation) -{ - WORD wRed; - - if (wSaturation) - { - WORD wGreen, wBlue, wMid1, wMid2; - - if (wLuminosity > 120) - wMid2 = wSaturation + wLuminosity - (wSaturation * wLuminosity + 120) / 240; - else - wMid2 = ((wSaturation + 240) * wLuminosity + 120) / 240; - - wMid1 = wLuminosity * 2 - wMid2; - - wRed = GET_RGB(wHue + 80); - wGreen = GET_RGB(wHue); - wBlue = GET_RGB(wHue - 80); - - return RGB(wRed, wGreen, wBlue); - } - - wRed = wLuminosity * 255 / 240; - return RGB(wRed, wRed, wRed); -} - -/************************************************************************* - * @ [SHLWAPI.413] - * - * Get the current docking status of the system. - * - * PARAMS - * dwFlags [I] DOCKINFO_ flags from "winbase.h", unused - * - * RETURNS - * One of DOCKINFO_UNDOCKED, DOCKINFO_UNDOCKED, or 0 if the system is not - * a notebook. - */ -DWORD WINAPI SHGetMachineInfo(DWORD dwFlags) -{ - HW_PROFILE_INFOA hwInfo; - - TRACE("(0x%08lx)\n", dwFlags); - - GetCurrentHwProfileA(&hwInfo); - switch (hwInfo.dwDockInfo & (DOCKINFO_DOCKED|DOCKINFO_UNDOCKED)) - { - case DOCKINFO_DOCKED: - case DOCKINFO_UNDOCKED: - return hwInfo.dwDockInfo & (DOCKINFO_DOCKED|DOCKINFO_UNDOCKED); - default: - return 0; - } -} - -/************************************************************************* - * @ [SHLWAPI.418] - * - * Function seems to do FreeLibrary plus other things. - * - * FIXME native shows the following calls: - * RtlEnterCriticalSection - * LocalFree - * GetProcAddress(Comctl32??, 150L) - * DPA_DeletePtr - * RtlLeaveCriticalSection - * followed by the FreeLibrary. - * The above code may be related to .377 above. - */ -BOOL WINAPI MLFreeLibrary(HMODULE hModule) -{ - FIXME("(%p) semi-stub\n", hModule); - return FreeLibrary(hModule); -} - -/************************************************************************* - * @ [SHLWAPI.419] - */ -BOOL WINAPI SHFlushSFCacheWrap(void) { - FIXME(": stub\n"); - return TRUE; -} - -/************************************************************************* - * @ [SHLWAPI.429] - * FIXME I have no idea what this function does or what its arguments are. - */ -BOOL WINAPI MLIsMLHInstance(HINSTANCE hInst) -{ - FIXME("(%p) stub\n", hInst); - return FALSE; -} - - -/************************************************************************* - * @ [SHLWAPI.430] - */ -DWORD WINAPI MLSetMLHInstance(HINSTANCE hInst, HANDLE hHeap) -{ - FIXME("(%p,%p) stub\n", hInst, hHeap); - return E_FAIL; /* This is what is used if shlwapi not loaded */ -} - -/************************************************************************* - * @ [SHLWAPI.431] - */ -DWORD WINAPI MLClearMLHInstance(DWORD x) -{ - FIXME("(0x%08lx)stub\n", x); - return 0xabba1247; -} - -/************************************************************************* - * @ [SHLWAPI.436] - * - * Convert an Unicode string CLSID into a CLSID. - * - * PARAMS - * idstr [I] string containing a CLSID in text form - * id [O] CLSID extracted from the string - * - * RETURNS - * S_OK on success or E_INVALIDARG on failure - * - * NOTES - * This is really CLSIDFromString() which is exported by ole32.dll, - * however the native shlwapi.dll does *not* import ole32. Nor does - * ole32.dll import this ordinal from shlwapi. Therefore we must conclude - * that MS duplicated the code for CLSIDFromString(), and yes they did, only - * it returns an E_INVALIDARG error code on failure. - * This is a duplicate (with changes for Unicode) of CLSIDFromString16() - * in "dlls/ole32/compobj.c". - */ -HRESULT WINAPI CLSIDFromStringWrap(LPCWSTR idstr, CLSID *id) -{ - LPCWSTR s = idstr; - BYTE *p; - INT i; - WCHAR table[256]; - - if (!s) { - memset(id, 0, sizeof(CLSID)); - return S_OK; - } - else { /* validate the CLSID string */ - - if (strlenW(s) != 38) - return E_INVALIDARG; - - if ((s[0]!=L'{') || (s[9]!=L'-') || (s[14]!=L'-') || (s[19]!=L'-') || (s[24]!=L'-') || (s[37]!=L'}')) - return E_INVALIDARG; - - for (i=1; i<37; i++) - { - if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) - continue; - if (!(((s[i] >= L'0') && (s[i] <= L'9')) || - ((s[i] >= L'a') && (s[i] <= L'f')) || - ((s[i] >= L'A') && (s[i] <= L'F'))) - ) - return E_INVALIDARG; - } - } - - TRACE("%s -> %p\n", debugstr_w(s), id); - - /* quick lookup table */ - memset(table, 0, 256*sizeof(WCHAR)); - - 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} */ - - p = (BYTE *) id; - - s++; /* skip leading brace */ - for (i = 0; i < 4; i++) { - p[3 - i] = table[*s]<<4 | table[*(s+1)]; - s += 2; - } - p += 4; - s++; /* skip - */ - - for (i = 0; i < 2; i++) { - p[1-i] = table[*s]<<4 | table[*(s+1)]; - s += 2; - } - p += 2; - s++; /* skip - */ - - for (i = 0; i < 2; i++) { - p[1-i] = table[*s]<<4 | table[*(s+1)]; - s += 2; - } - p += 2; - s++; /* skip - */ - - /* these are just sequential bytes */ - for (i = 0; i < 2; i++) { - *p++ = table[*s]<<4 | table[*(s+1)]; - s += 2; - } - s++; /* skip - */ - - for (i = 0; i < 6; i++) { - *p++ = table[*s]<<4 | table[*(s+1)]; - s += 2; - } - - return S_OK; -} - -/************************************************************************* - * @ [SHLWAPI.437] - * - * Determine if the OS supports a given feature. - * - * PARAMS - * dwFeature [I] Feature requested (undocumented) - * - * RETURNS - * TRUE If the feature is available. - * FALSE If the feature is not available. - */ -BOOL WINAPI IsOS(DWORD feature) -{ - OSVERSIONINFOA osvi; - DWORD platform, majorv, minorv; - - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); - if(!GetVersionExA(&osvi)) { - ERR("GetVersionEx failed"); - return FALSE; - } - - majorv = osvi.dwMajorVersion; - minorv = osvi.dwMinorVersion; - platform = osvi.dwPlatformId; - -#define ISOS_RETURN(x) \ - TRACE("(0x%lx) ret=%d\n",feature,(x)); \ - return (x); - - switch(feature) { - case OS_WIN32SORGREATER: - ISOS_RETURN(platform == VER_PLATFORM_WIN32s - || platform == VER_PLATFORM_WIN32_WINDOWS) - case OS_NT: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT) - case OS_WIN95ORGREATER: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS) - case OS_NT4ORGREATER: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 4) - case OS_WIN2000ORGREATER_ALT: - case OS_WIN2000ORGREATER: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5) - case OS_WIN98ORGREATER: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 10) - case OS_WIN98_GOLD: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 10) - case OS_WIN2000PRO: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5) - case OS_WIN2000SERVER: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1)) - case OS_WIN2000ADVSERVER: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1)) - case OS_WIN2000DATACENTER: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1)) - case OS_WIN2000TERMINAL: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1)) - case OS_EMBEDDED: - FIXME("(OS_EMBEDDED) What should we return here?\n"); - return FALSE; - case OS_TERMINALCLIENT: - FIXME("(OS_TERMINALCLIENT) What should we return here?\n"); - return FALSE; - case OS_TERMINALREMOTEADMIN: - FIXME("(OS_TERMINALREMOTEADMIN) What should we return here?\n"); - return FALSE; - case OS_WIN95_GOLD: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 0) - case OS_MEORGREATER: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 90) - case OS_XPORGREATER: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1) - case OS_HOME: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1) - case OS_PROFESSIONAL: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT) - case OS_DATACENTER: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT) - case OS_ADVSERVER: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5) - case OS_SERVER: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT) - case OS_TERMINALSERVER: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT) - case OS_PERSONALTERMINALSERVER: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && minorv >= 1 && majorv >= 5) - case OS_FASTUSERSWITCHING: - FIXME("(OS_FASTUSERSWITCHING) What should we return here?\n"); - return TRUE; - case OS_WELCOMELOGONUI: - FIXME("(OS_WELCOMELOGONUI) What should we return here?\n"); - return FALSE; - case OS_DOMAINMEMBER: - FIXME("(OS_DOMAINMEMBER) What should we return here?\n"); - return TRUE; - case OS_ANYSERVER: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT) - case OS_WOW6432: - FIXME("(OS_WOW6432) Should we check this?\n"); - return FALSE; - case OS_WEBSERVER: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT) - case OS_SMALLBUSINESSSERVER: - ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT) - case OS_TABLETPC: - FIXME("(OS_TABLEPC) What should we return here?\n"); - return FALSE; - case OS_SERVERADMINUI: - FIXME("(OS_SERVERADMINUI) What should we return here?\n"); - return FALSE; - case OS_MEDIACENTER: - FIXME("(OS_MEDIACENTER) What should we return here?\n"); - return FALSE; - case OS_APPLIANCE: - FIXME("(OS_APPLIANCE) What should we return here?\n"); - return FALSE; - } - -#undef ISOS_RETURN - - WARN("(0x%lx) unknown parameter\n",feature); - - return FALSE; -} - -/************************************************************************* - * @ [SHLWAPI.478] - * - * Call IInputObject_TranslateAcceleratorIO() on an object. - * - * PARAMS - * lpUnknown [I] Object supporting the IInputObject interface. - * lpMsg [I] Key message to be processed. - * - * RETURNS - * Success: S_OK. - * Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL. - */ -HRESULT WINAPI IUnknown_TranslateAcceleratorIO(IUnknown *lpUnknown, LPMSG lpMsg) -{ - IInputObject* lpInput = NULL; - HRESULT hRet = E_INVALIDARG; - - TRACE("(%p,%p)\n", lpUnknown, lpMsg); - if (lpUnknown) - { - hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInputObject, - (void**)&lpInput); - if (SUCCEEDED(hRet) && lpInput) - { - hRet = IInputObject_TranslateAcceleratorIO(lpInput, lpMsg); - IInputObject_Release(lpInput); - } - } - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.481] - * - * Call IInputObject_HasFocusIO() on an object. - * - * PARAMS - * lpUnknown [I] Object supporting the IInputObject interface. - * - * RETURNS - * Success: S_OK, if lpUnknown is an IInputObject object and has the focus, - * or S_FALSE otherwise. - * Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL. - */ -HRESULT WINAPI IUnknown_HasFocusIO(IUnknown *lpUnknown) -{ - IInputObject* lpInput = NULL; - HRESULT hRet = E_INVALIDARG; - - TRACE("(%p)\n", lpUnknown); - if (lpUnknown) - { - hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInputObject, - (void**)&lpInput); - if (SUCCEEDED(hRet) && lpInput) - { - hRet = IInputObject_HasFocusIO(lpInput); - IInputObject_Release(lpInput); - } - } - return hRet; -} - -/************************************************************************* - * ColorRGBToHLS [SHLWAPI.@] - * - * Convert an rgb COLORREF into the hls color space. - * - * PARAMS - * cRGB [I] Source rgb value - * pwHue [O] Destination for converted hue - * pwLuminance [O] Destination for converted luminance - * pwSaturation [O] Destination for converted saturation - * - * RETURNS - * Nothing. pwHue, pwLuminance and pwSaturation are set to the converted - * values. - * - * NOTES - * Output HLS values are constrained to the range (0..240). - * For Achromatic conversions, Hue is set to 160. - */ -VOID WINAPI ColorRGBToHLS(COLORREF cRGB, LPWORD pwHue, - LPWORD pwLuminance, LPWORD pwSaturation) -{ - int wR, wG, wB, wMax, wMin, wHue, wLuminosity, wSaturation; - - TRACE("(%08lx,%p,%p,%p)\n", cRGB, pwHue, pwLuminance, pwSaturation); - - wR = GetRValue(cRGB); - wG = GetGValue(cRGB); - wB = GetBValue(cRGB); - - wMax = max(wR, max(wG, wB)); - wMin = min(wR, min(wG, wB)); - - /* Luminosity */ - wLuminosity = ((wMax + wMin) * 240 + 255) / 510; - - if (wMax == wMin) - { - /* Achromatic case */ - wSaturation = 0; - /* Hue is now unrepresentable, but this is what native returns... */ - wHue = 160; - } - else - { - /* Chromatic case */ - int wDelta = wMax - wMin, wRNorm, wGNorm, wBNorm; - - /* Saturation */ - if (wLuminosity <= 120) - wSaturation = ((wMax + wMin)/2 + wDelta * 240) / (wMax + wMin); - else - wSaturation = ((510 - wMax - wMin)/2 + wDelta * 240) / (510 - wMax - wMin); - - /* Hue */ - wRNorm = (wDelta/2 + wMax * 40 - wR * 40) / wDelta; - wGNorm = (wDelta/2 + wMax * 40 - wG * 40) / wDelta; - wBNorm = (wDelta/2 + wMax * 40 - wB * 40) / wDelta; - - if (wR == wMax) - wHue = wBNorm - wGNorm; - else if (wG == wMax) - wHue = 80 + wRNorm - wBNorm; - else - wHue = 160 + wGNorm - wRNorm; - if (wHue < 0) - wHue += 240; - else if (wHue > 240) - wHue -= 240; - } - if (pwHue) - *pwHue = wHue; - if (pwLuminance) - *pwLuminance = wLuminosity; - if (pwSaturation) - *pwSaturation = wSaturation; -} - -/************************************************************************* - * SHCreateShellPalette [SHLWAPI.@] - */ -HPALETTE WINAPI SHCreateShellPalette(HDC hdc) -{ - FIXME("stub\n"); - return CreateHalftonePalette(hdc); -} - -/************************************************************************* - * SHGetInverseCMAP (SHLWAPI.@) - * - * Get an inverse color map table. - * - * PARAMS - * lpCmap [O] Destination for color map - * dwSize [I] Size of memory pointed to by lpCmap - * - * RETURNS - * Success: S_OK. - * Failure: E_POINTER, If lpCmap is invalid. - * E_INVALIDARG, If dwFlags is invalid - * E_OUTOFMEMORY, If there is no memory available - * - * NOTES - * dwSize may only be CMAP_PTR_SIZE (4) or CMAP_SIZE (8192). - * If dwSize = CMAP_PTR_SIZE, *lpCmap is set to the address of this DLL's - * internal CMap. - * If dwSize = CMAP_SIZE, lpCmap is filled with a copy of the data from - * this DLL's internal CMap. - */ -HRESULT WINAPI SHGetInverseCMAP(LPDWORD dest, DWORD dwSize) -{ - if (dwSize == 4) { - FIXME(" - returning bogus address for SHGetInverseCMAP\n"); - *dest = (DWORD)0xabba1249; - return 0; - } - FIXME("(%p, %#lx) stub\n", dest, dwSize); - return 0; -} - -/************************************************************************* - * SHIsLowMemoryMachine [SHLWAPI.@] - * - * Determine if the current computer has low memory. - * - * PARAMS - * x [I] FIXME - * - * RETURNS - * TRUE if the users machine has 16 Megabytes of memory or less, - * FALSE otherwise. - */ -BOOL WINAPI SHIsLowMemoryMachine (DWORD x) -{ - FIXME("(0x%08lx) stub\n", x); - return FALSE; -} - -/************************************************************************* - * GetMenuPosFromID [SHLWAPI.@] - * - * Return the position of a menu item from its Id. - * - * PARAMS - * hMenu [I] Menu containing the item - * wID [I] Id of the menu item - * - * RETURNS - * Success: The index of the menu item in hMenu. - * Failure: -1, If the item is not found. - */ -INT WINAPI GetMenuPosFromID(HMENU hMenu, UINT wID) -{ - MENUITEMINFOA mi; - INT nCount = GetMenuItemCount(hMenu), nIter = 0; - - while (nIter < nCount) - { - mi.wID = 0; - if (!GetMenuItemInfoA(hMenu, nIter, TRUE, &mi) && mi.wID == wID) - return nIter; - nIter++; - } - return -1; -} - -/************************************************************************* - * @ [SHLWAPI.179] - * - * Same as SHLWAPI.GetMenuPosFromID - */ -DWORD WINAPI SHMenuIndexFromID(HMENU hMenu, UINT uID) -{ - return GetMenuPosFromID(hMenu, uID); -} - - -/************************************************************************* - * @ [SHLWAPI.448] - */ -VOID WINAPI FixSlashesAndColonW(LPWSTR lpwstr) -{ - while (*lpwstr) - { - if (*lpwstr == '/') - *lpwstr = '\\'; - lpwstr++; - } -} - - -/************************************************************************* - * @ [SHLWAPI.461] - */ -DWORD WINAPI SHGetAppCompatFlags(DWORD dwUnknown) -{ - FIXME("(0x%08lx) stub\n", dwUnknown); - return 0; -} - - -/************************************************************************* - * @ [SHLWAPI.549] - */ -HRESULT WINAPI SHCoCreateInstanceAC(REFCLSID rclsid, LPUNKNOWN pUnkOuter, - DWORD dwClsContext, REFIID iid, LPVOID *ppv) -{ - return CoCreateInstance(rclsid, pUnkOuter, dwClsContext, iid, ppv); -} - -/************************************************************************* - * SHSkipJunction [SHLWAPI.@] - * - * Determine if a bind context can be bound to an object - * - * PARAMS - * pbc [I] Bind context to check - * pclsid [I] CLSID of object to be bound to - * - * RETURNS - * TRUE: If it is safe to bind - * FALSE: If pbc is invalid or binding would not be safe - * - */ -BOOL WINAPI SHSkipJunction(IBindCtx *pbc, const CLSID *pclsid) -{ - static const WCHAR szSkipBinding[] = { 'S','k','i','p',' ', - 'B','i','n','d','i','n','g',' ','C','L','S','I','D','\0' }; - BOOL bRet = FALSE; - - if (pbc) - { - IUnknown* lpUnk; - - if (SUCCEEDED(IBindCtx_GetObjectParam(pbc, (LPOLESTR)szSkipBinding, &lpUnk))) - { - CLSID clsid; - - if (SUCCEEDED(IUnknown_GetClassID(lpUnk, &clsid)) && - IsEqualGUID(pclsid, &clsid)) - bRet = TRUE; - - IUnknown_Release(lpUnk); - } - } - return bRet; -} - -/*********************************************************************** - * SHGetShellKey (SHLWAPI.@) - */ -DWORD WINAPI SHGetShellKey(DWORD a, DWORD b, DWORD c) -{ - FIXME("(%lx, %lx, %lx): stub\n", a, b, c); - return 0x50; -} - -/*********************************************************************** - * SHQueueUserWorkItem (SHLWAPI.@) - */ -HRESULT WINAPI SHQueueUserWorkItem(DWORD a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f, DWORD g) -{ - FIXME("(%lx, %lx, %lx, %lx, %lx, %lx, %lx): stub\n", a, b, c, d, e, f, g); - return E_FAIL; -} - -/*********************************************************************** - * IUnknown_OnFocusChangeIS (SHLWAPI.@) - */ -HRESULT WINAPI IUnknown_OnFocusChangeIS(LPUNKNOWN lpUnknown, LPUNKNOWN pFocusObject, BOOL bFocus) -{ - IInputObjectSite *pIOS = NULL; - HRESULT hRet = E_INVALIDARG; - - TRACE("(%p, %p, %s)\n", lpUnknown, pFocusObject, bFocus ? "TRUE" : "FALSE"); - - if (lpUnknown) - { - hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInputObjectSite, - (void **)&pIOS); - if (SUCCEEDED(hRet) && pIOS) - { - hRet = IInputObjectSite_OnFocusChangeIS(pIOS, pFocusObject, bFocus); - IInputObjectSite_Release(pIOS); - } - } - return hRet; -} - -/*********************************************************************** - * SHGetValueW (SHLWAPI.@) - */ -HRESULT WINAPI SKGetValueW(DWORD a, LPWSTR b, LPWSTR c, DWORD d, DWORD e, DWORD f) -{ - FIXME("(%lx, %s, %s, %lx, %lx, %lx): stub\n", a, debugstr_w(b), debugstr_w(c), d, e, f); - return E_FAIL; -} - -typedef HRESULT (WINAPI *DllGetVersion_func)(DLLVERSIONINFO *); - -/*********************************************************************** - * GetUIVersion (SHLWAPI.452) - */ -DWORD WINAPI GetUIVersion(void) -{ - static DWORD version; - - if (!version) - { - DllGetVersion_func pDllGetVersion; - HMODULE dll = LoadLibraryA("shell32.dll"); - if (!dll) return 0; - - pDllGetVersion = (DllGetVersion_func)GetProcAddress(dll, "DllGetVersion"); - if (pDllGetVersion) - { - DLLVERSIONINFO dvi; - dvi.cbSize = sizeof(DLLVERSIONINFO); - if (pDllGetVersion(&dvi) == S_OK) version = dvi.dwMajorVersion; - } - FreeLibrary( dll ); - if (!version) version = 3; /* old shell dlls don't have DllGetVersion */ - } - return version; -} +/* + * SHLWAPI ordinal functions + * + * Copyright 1997 Marcus Meissner + * 1998 Jürgen Schmied + * 2001-2003 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define COM_NO_WINDOWS_H +#include "config.h" +#include "wine/port.h" + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winnls.h" +#include "objbase.h" +#include "docobj.h" +#include "exdisp.h" +#include "shlguid.h" +#include "wingdi.h" +#include "shlobj.h" +#include "shellapi.h" +#include "commdlg.h" +#include "wine/unicode.h" +#include "winreg.h" +#include "wine/debug.h" +#include "shlwapi.h" + + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/* Get a function pointer from a DLL handle */ +#define GET_FUNC(func, module, name, fail) \ + do { \ + if (!func) { \ + if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \ + func = (fn##func)GetProcAddress(SHLWAPI_h##module, name); \ + if (!func) return fail; \ + } \ + } while (0) + +/* DLL handles for late bound calls */ +extern HINSTANCE shlwapi_hInstance; +extern HMODULE SHLWAPI_hshell32; +extern HMODULE SHLWAPI_hwinmm; +extern HMODULE SHLWAPI_hcomdlg32; +extern HMODULE SHLWAPI_hcomctl32; +extern HMODULE SHLWAPI_hmpr; +extern HMODULE SHLWAPI_hurlmon; +extern HMODULE SHLWAPI_hversion; + +extern DWORD SHLWAPI_ThreadRef_index; + +/* following is GUID for IObjectWithSite::SetSite -- see _174 */ +static DWORD id1[4] = {0xfc4801a3, 0x11cf2ba9, 0xaa0029a2, 0x52733d00}; +/* following is GUID for IPersistMoniker::GetClassID -- see _174 */ +static DWORD id2[4] = {0x79eac9ee, 0x11cebaf9, 0xaa00828c, 0x0ba94b00}; + +/* Function pointers for GET_FUNC macro; these need to be global because of gcc bug */ +typedef LPITEMIDLIST (WINAPI *fnpSHBrowseForFolderW)(LPBROWSEINFOW); +static fnpSHBrowseForFolderW pSHBrowseForFolderW; +typedef BOOL (WINAPI *fnpPlaySoundW)(LPCWSTR, HMODULE, DWORD); +static fnpPlaySoundW pPlaySoundW; +typedef DWORD (WINAPI *fnpSHGetFileInfoW)(LPCWSTR,DWORD,SHFILEINFOW*,UINT,UINT); +static fnpSHGetFileInfoW pSHGetFileInfoW; +typedef UINT (WINAPI *fnpDragQueryFileW)(HDROP, UINT, LPWSTR, UINT); +static fnpDragQueryFileW pDragQueryFileW; +typedef BOOL (WINAPI *fnpSHGetPathFromIDListW)(LPCITEMIDLIST, LPWSTR); +static fnpSHGetPathFromIDListW pSHGetPathFromIDListW; +typedef BOOL (WINAPI *fnpShellExecuteExW)(LPSHELLEXECUTEINFOW); +static fnpShellExecuteExW pShellExecuteExW; +typedef HICON (WINAPI *fnpSHFileOperationW)(LPSHFILEOPSTRUCTW); +static fnpSHFileOperationW pSHFileOperationW; +typedef UINT (WINAPI *fnpExtractIconExW)(LPCWSTR, INT,HICON *,HICON *, UINT); +static fnpExtractIconExW pExtractIconExW; +typedef BOOL (WINAPI *fnpSHGetNewLinkInfoW)(LPCWSTR, LPCWSTR, LPCWSTR, BOOL*, UINT); +static fnpSHGetNewLinkInfoW pSHGetNewLinkInfoW; +typedef HRESULT (WINAPI *fnpSHDefExtractIconW)(LPCWSTR, int, UINT, HICON*, HICON*, UINT); +static fnpSHDefExtractIconW pSHDefExtractIconW; +typedef HICON (WINAPI *fnpExtractIconW)(HINSTANCE, LPCWSTR, UINT); +static fnpExtractIconW pExtractIconW; +typedef BOOL (WINAPI *fnpGetSaveFileNameW)(LPOPENFILENAMEW); +static fnpGetSaveFileNameW pGetSaveFileNameW; +typedef DWORD (WINAPI *fnpWNetRestoreConnectionW)(HWND, LPWSTR); +static fnpWNetRestoreConnectionW pWNetRestoreConnectionW; +typedef DWORD (WINAPI *fnpWNetGetLastErrorW)(LPDWORD, LPWSTR, DWORD, LPWSTR, DWORD); +static fnpWNetGetLastErrorW pWNetGetLastErrorW; +typedef BOOL (WINAPI *fnpPageSetupDlgW)(LPPAGESETUPDLGW); +static fnpPageSetupDlgW pPageSetupDlgW; +typedef BOOL (WINAPI *fnpPrintDlgW)(LPPRINTDLGW); +static fnpPrintDlgW pPrintDlgW; +typedef BOOL (WINAPI *fnpGetOpenFileNameW)(LPOPENFILENAMEW); +static fnpGetOpenFileNameW pGetOpenFileNameW; +typedef DWORD (WINAPI *fnpGetFileVersionInfoSizeW)(LPCWSTR,LPDWORD); +static fnpGetFileVersionInfoSizeW pGetFileVersionInfoSizeW; +typedef BOOL (WINAPI *fnpGetFileVersionInfoW)(LPCWSTR,DWORD,DWORD,LPVOID); +static fnpGetFileVersionInfoW pGetFileVersionInfoW; +typedef WORD (WINAPI *fnpVerQueryValueW)(LPVOID,LPCWSTR,LPVOID*,UINT*); +static fnpVerQueryValueW pVerQueryValueW; +typedef BOOL (WINAPI *fnpCOMCTL32_417)(HDC,INT,INT,UINT,const RECT*,LPCWSTR,UINT,const INT*); +static fnpCOMCTL32_417 pCOMCTL32_417; +typedef HRESULT (WINAPI *fnpDllGetVersion)(DLLVERSIONINFO*); +static fnpDllGetVersion pDllGetVersion; +typedef HRESULT (WINAPI *fnpCreateFormatEnumerator)(UINT,FORMATETC*,IEnumFORMATETC**); +static fnpCreateFormatEnumerator pCreateFormatEnumerator; +typedef HRESULT (WINAPI *fnpRegisterFormatEnumerator)(LPBC,IEnumFORMATETC*,DWORD); +static fnpRegisterFormatEnumerator pRegisterFormatEnumerator; + +HRESULT WINAPI IUnknown_QueryService(IUnknown*,REFGUID,REFIID,LPVOID*); +HRESULT WINAPI SHInvokeCommand(HWND,IShellFolder*,LPCITEMIDLIST,BOOL); +HRESULT WINAPI CLSIDFromStringWrap(LPCWSTR,CLSID*); +BOOL WINAPI SHAboutInfoW(LPWSTR,DWORD); + +/* + NOTES: Most functions exported by ordinal seem to be superflous. + The reason for these functions to be there is to provide a wrapper + for unicode functions to provide these functions on systems without + unicode functions eg. win95/win98. Since we have such functions we just + call these. If running Wine with native DLL's, some late bound calls may + fail. However, it is better to implement the functions in the forward DLL + and recommend the builtin rather than reimplementing the calls here! +*/ + +/************************************************************************* + * SHLWAPI_DupSharedHandle + * + * Internal implemetation of SHLWAPI_11. + */ +static +HANDLE WINAPI SHLWAPI_DupSharedHandle(HANDLE hShared, DWORD dwDstProcId, + DWORD dwSrcProcId, DWORD dwAccess, + DWORD dwOptions) +{ + HANDLE hDst, hSrc; + DWORD dwMyProcId = GetCurrentProcessId(); + HANDLE hRet = NULL; + + TRACE("(%p,%ld,%ld,%08lx,%08lx)\n", hShared, dwDstProcId, dwSrcProcId, + dwAccess, dwOptions); + + /* Get dest process handle */ + if (dwDstProcId == dwMyProcId) + hDst = GetCurrentProcess(); + else + hDst = OpenProcess(PROCESS_DUP_HANDLE, 0, dwDstProcId); + + if (hDst) + { + /* Get src process handle */ + if (dwSrcProcId == dwMyProcId) + hSrc = GetCurrentProcess(); + else + hSrc = OpenProcess(PROCESS_DUP_HANDLE, 0, dwSrcProcId); + + if (hSrc) + { + /* Make handle available to dest process */ + if (!DuplicateHandle(hDst, hShared, hSrc, &hRet, + dwAccess, 0, dwOptions | DUPLICATE_SAME_ACCESS)) + hRet = NULL; + + if (dwSrcProcId != dwMyProcId) + CloseHandle(hSrc); + } + + if (dwDstProcId != dwMyProcId) + CloseHandle(hDst); + } + + TRACE("Returning handle %p\n", hRet); + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.7] + * + * Create a block of sharable memory and initialise it with data. + * + * PARAMS + * lpvData [I] Pointer to data to write + * dwSize [I] Size of data + * dwProcId [I] ID of process owning data + * + * RETURNS + * Success: A shared memory handle + * Failure: NULL + * + * NOTES + * Ordinals 7-11 provide a set of calls to create shared memory between a + * group of processes. The shared memory is treated opaquely in that its size + * is not exposed to clients who map it. This is accomplished by storing + * the size of the map as the first DWORD of mapped data, and then offsetting + * the view pointer returned by this size. + * + */ +HANDLE WINAPI SHAllocShared(LPCVOID lpvData, DWORD dwSize, DWORD dwProcId) +{ + HANDLE hMap; + LPVOID pMapped; + HANDLE hRet = NULL; + + TRACE("(%p,%ld,%ld)\n", lpvData, dwSize, dwProcId); + + /* Create file mapping of the correct length */ + hMap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, FILE_MAP_READ, 0, + dwSize + sizeof(dwSize), NULL); + if (!hMap) + return hRet; + + /* Get a view in our process address space */ + pMapped = MapViewOfFile(hMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); + + if (pMapped) + { + /* Write size of data, followed by the data, to the view */ + *((DWORD*)pMapped) = dwSize; + if (lpvData) + memcpy((char *) pMapped + sizeof(dwSize), lpvData, dwSize); + + /* Release view. All further views mapped will be opaque */ + UnmapViewOfFile(pMapped); + hRet = SHLWAPI_DupSharedHandle(hMap, dwProcId, + GetCurrentProcessId(), FILE_MAP_ALL_ACCESS, + DUPLICATE_SAME_ACCESS); + } + + CloseHandle(hMap); + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.8] + * + * Get a pointer to a block of shared memory from a shared memory handle. + * + * PARAMS + * hShared [I] Shared memory handle + * dwProcId [I] ID of process owning hShared + * + * RETURNS + * Success: A pointer to the shared memory + * Failure: NULL + * + */ +PVOID WINAPI SHLockShared(HANDLE hShared, DWORD dwProcId) +{ + HANDLE hDup; + LPVOID pMapped; + + TRACE("(%p %ld)\n", hShared, dwProcId); + + /* Get handle to shared memory for current process */ + hDup = SHLWAPI_DupSharedHandle(hShared, dwProcId, GetCurrentProcessId(), + FILE_MAP_ALL_ACCESS, 0); + /* Get View */ + pMapped = MapViewOfFile(hDup, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); + CloseHandle(hDup); + + if (pMapped) + return (char *) pMapped + sizeof(DWORD); /* Hide size */ + return NULL; +} + +/************************************************************************* + * @ [SHLWAPI.9] + * + * Release a pointer to a block of shared memory. + * + * PARAMS + * lpView [I] Shared memory pointer + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + */ +BOOL WINAPI SHUnlockShared(LPVOID lpView) +{ + TRACE("(%p)\n", lpView); + return UnmapViewOfFile((char *) lpView - sizeof(DWORD)); /* Include size */ +} + +/************************************************************************* + * @ [SHLWAPI.10] + * + * Destroy a block of sharable memory. + * + * PARAMS + * hShared [I] Shared memory handle + * dwProcId [I] ID of process owning hShared + * + * RETURNS + * Success: TRUE + * Failure: FALSE + * + */ +BOOL WINAPI SHFreeShared(HANDLE hShared, DWORD dwProcId) +{ + HANDLE hClose; + + TRACE("(%p %ld)\n", hShared, dwProcId); + + /* Get a copy of the handle for our process, closing the source handle */ + hClose = SHLWAPI_DupSharedHandle(hShared, dwProcId, GetCurrentProcessId(), + FILE_MAP_ALL_ACCESS,DUPLICATE_CLOSE_SOURCE); + /* Close local copy */ + return CloseHandle(hClose); +} + +/************************************************************************* + * @ [SHLWAPI.11] + * + * Copy a sharable memory handle from one process to another. + * + * PARAMS + * hShared [I] Shared memory handle to duplicate + * dwDstProcId [I] ID of the process wanting the duplicated handle + * dwSrcProcId [I] ID of the process owning hShared + * dwAccess [I] Desired DuplicateHandle() access + * dwOptions [I] Desired DuplicateHandle() options + * + * RETURNS + * Success: A handle suitable for use by the dwDstProcId process. + * Failure: A NULL handle. + * + */ +HANDLE WINAPI SHMapHandle(HANDLE hShared, DWORD dwDstProcId, DWORD dwSrcProcId, + DWORD dwAccess, DWORD dwOptions) +{ + HANDLE hRet; + + hRet = SHLWAPI_DupSharedHandle(hShared, dwDstProcId, dwSrcProcId, + dwAccess, dwOptions); + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.13] + * + * Create and register a clipboard enumerator for a web browser. + * + * PARAMS + * lpBC [I] Binding context + * lpUnknown [I] An object exposing the IWebBrowserApp interface + * + * RETURNS + * Success: S_OK. + * Failure: An HRESULT error code. + * + * NOTES + * The enumerator is stored as a property of the web browser. If it does not + * yet exist, it is created and set before being registered. + */ +HRESULT WINAPI RegisterDefaultAcceptHeaders(LPBC lpBC, IUnknown *lpUnknown) +{ + static const WCHAR szProperty[] = { '{','D','0','F','C','A','4','2','0', + '-','D','3','F','5','-','1','1','C','F', '-','B','2','1','1','-','0', + '0','A','A','0','0','4','A','E','8','3','7','}','\0' }; + IEnumFORMATETC* pIEnumFormatEtc = NULL; + VARIANTARG var; + HRESULT hRet; + IWebBrowserApp* pBrowser = NULL; + + TRACE("(%p, %p)\n", lpBC, lpUnknown); + + /* Get An IWebBrowserApp interface from lpUnknown */ + hRet = IUnknown_QueryService(lpUnknown, &IID_IWebBrowserApp, &IID_IWebBrowserApp, (PVOID)&pBrowser); + if (FAILED(hRet) || !pBrowser) + return E_NOINTERFACE; + + V_VT(&var) = VT_EMPTY; + + /* The property we get is the browsers clipboard enumerator */ + hRet = IWebBrowserApp_GetProperty(pBrowser, (BSTR)szProperty, &var); + if (FAILED(hRet)) + return hRet; + + if (V_VT(&var) == VT_EMPTY) + { + /* Iterate through accepted documents and RegisterClipBoardFormatA() them */ + char szKeyBuff[128], szValueBuff[128]; + DWORD dwKeySize, dwValueSize, dwRet = 0, dwCount = 0, dwNumValues, dwType; + FORMATETC* formatList, *format; + HKEY hDocs; + + TRACE("Registering formats and creating IEnumFORMATETC instance\n"); + + if (!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\Current" + "Version\\Internet Settings\\Accepted Documents", &hDocs)) + return E_FAIL; + + /* Get count of values in key */ + while (!dwRet) + { + dwKeySize = sizeof(szKeyBuff); + dwRet = RegEnumValueA(hDocs,dwCount,szKeyBuff,&dwKeySize,0,&dwType,0,0); + dwCount++; + } + + dwNumValues = dwCount; + + /* Note: dwCount = number of items + 1; The extra item is the end node */ + format = formatList = HeapAlloc(GetProcessHeap(), 0, dwCount * sizeof(FORMATETC)); + if (!formatList) + return E_OUTOFMEMORY; + + if (dwNumValues > 1) + { + dwRet = 0; + dwCount = 0; + + dwNumValues--; + + /* Register clipboard formats for the values and populate format list */ + while(!dwRet && dwCount < dwNumValues) + { + dwKeySize = sizeof(szKeyBuff); + dwValueSize = sizeof(szValueBuff); + dwRet = RegEnumValueA(hDocs, dwCount, szKeyBuff, &dwKeySize, 0, &dwType, + (PBYTE)szValueBuff, &dwValueSize); + if (!dwRet) + return E_FAIL; + + format->cfFormat = RegisterClipboardFormatA(szValueBuff); + format->ptd = NULL; + format->dwAspect = 1; + format->lindex = 4; + format->tymed = -1; + + format++; + dwCount++; + } + } + + /* Terminate the (maybe empty) list, last entry has a cfFormat of 0 */ + format->cfFormat = 0; + format->ptd = NULL; + format->dwAspect = 1; + format->lindex = 4; + format->tymed = -1; + + /* Create a clipboard enumerator */ + GET_FUNC(pCreateFormatEnumerator, urlmon, "CreateFormatEnumerator", E_FAIL); + hRet = pCreateFormatEnumerator(dwNumValues, formatList, &pIEnumFormatEtc); + + if (FAILED(hRet) || !pIEnumFormatEtc) + return hRet; + + /* Set our enumerator as the browsers property */ + V_VT(&var) = VT_UNKNOWN; + V_UNKNOWN(&var) = (IUnknown*)pIEnumFormatEtc; + + hRet = IWebBrowserApp_PutProperty(pBrowser, (BSTR)szProperty, var); + if (FAILED(hRet)) + { + IEnumFORMATETC_Release(pIEnumFormatEtc); + goto RegisterDefaultAcceptHeaders_Exit; + } + } + + if (V_VT(&var) == VT_UNKNOWN) + { + /* Our variant is holding the clipboard enumerator */ + IUnknown* pIUnknown = V_UNKNOWN(&var); + IEnumFORMATETC* pClone = NULL; + + TRACE("Retrieved IEnumFORMATETC property\n"); + + /* Get an IEnumFormatEtc interface from the variants value */ + pIEnumFormatEtc = NULL; + hRet = IUnknown_QueryInterface(pIUnknown, &IID_IEnumFORMATETC, + (PVOID)&pIEnumFormatEtc); + if (!hRet && pIEnumFormatEtc) + { + /* Clone and register the enumerator */ + hRet = IEnumFORMATETC_Clone(pIEnumFormatEtc, &pClone); + if (!hRet && pClone) + { + GET_FUNC(pRegisterFormatEnumerator, urlmon, "RegisterFormatEnumerator", E_FAIL); + pRegisterFormatEnumerator(lpBC, pClone, 0); + + IEnumFORMATETC_Release(pClone); + } + + /* Release the IEnumFormatEtc interface */ + IEnumFORMATETC_Release(pIUnknown); + } + IUnknown_Release(V_UNKNOWN(&var)); + } + +RegisterDefaultAcceptHeaders_Exit: + IWebBrowserApp_Release(pBrowser); + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.15] + * + * Get Explorers "AcceptLanguage" setting. + * + * PARAMS + * langbuf [O] Destination for language string + * buflen [I] Length of langbuf + * [0] Success: used length of langbuf + * + * RETURNS + * Success: S_OK. langbuf is set to the language string found. + * Failure: E_FAIL, If any arguments are invalid, error occurred, or Explorer + * does not contain the setting. + * E_INVALIDARG, If the buffer is not big enough + */ +HRESULT WINAPI GetAcceptLanguagesW( LPWSTR langbuf, LPDWORD buflen) +{ + static const WCHAR szkeyW[] = { + 'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\', + 'I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r','\\', + 'I','n','t','e','r','n','a','t','i','o','n','a','l',0}; + static const WCHAR valueW[] = { + 'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0}; + static const WCHAR enusW[] = {'e','n','-','u','s',0}; + DWORD mystrlen, mytype; + HKEY mykey; + HRESULT retval; + LCID mylcid; + WCHAR *mystr; + + if(!langbuf || !buflen || !*buflen) + return E_FAIL; + + mystrlen = (*buflen > 20) ? *buflen : 20 ; + mystr = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * mystrlen); + RegOpenKeyW(HKEY_CURRENT_USER, szkeyW, &mykey); + if(RegQueryValueExW(mykey, valueW, 0, &mytype, (PBYTE)mystr, &mystrlen)) { + /* Did not find value */ + mylcid = GetUserDefaultLCID(); + /* somehow the mylcid translates into "en-us" + * this is similar to "LOCALE_SABBREVLANGNAME" + * which could be gotten via GetLocaleInfo. + * The only problem is LOCALE_SABBREVLANGUAGE" is + * a 3 char string (first 2 are country code and third is + * letter for "sublanguage", which does not come close to + * "en-us" + */ + lstrcpyW(mystr, enusW); + mystrlen = lstrlenW(mystr); + } else { + /* handle returned string */ + FIXME("missing code\n"); + } + memcpy( langbuf, mystr, min(*buflen,strlenW(mystr)+1)*sizeof(WCHAR) ); + + if(*buflen > strlenW(mystr)) { + *buflen = strlenW(mystr); + retval = S_OK; + } else { + *buflen = 0; + retval = E_INVALIDARG; + SetLastError(ERROR_INSUFFICIENT_BUFFER); + } + RegCloseKey(mykey); + HeapFree(GetProcessHeap(), 0, mystr); + return retval; +} + +/************************************************************************* + * @ [SHLWAPI.14] + * + * Ascii version of GetAcceptLanguagesW. + */ +HRESULT WINAPI GetAcceptLanguagesA( LPSTR langbuf, LPDWORD buflen) +{ + WCHAR *langbufW; + DWORD buflenW, convlen; + HRESULT retval; + + if(!langbuf || !buflen || !*buflen) return E_FAIL; + + buflenW = *buflen; + langbufW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * buflenW); + retval = GetAcceptLanguagesW(langbufW, &buflenW); + + /* FIXME: this is wrong, the string may not be null-terminated */ + convlen = WideCharToMultiByte(CP_ACP, 0, langbufW, -1, langbuf, + *buflen, NULL, NULL); + *buflen = buflenW ? convlen : 0; + + HeapFree(GetProcessHeap(), 0, langbufW); + return retval; +} + +/************************************************************************* + * @ [SHLWAPI.23] + * + * Convert a GUID to a string. + * + * PARAMS + * guid [I] GUID to convert + * lpszDest [O] Destination for string + * cchMax [I] Length of output buffer + * + * RETURNS + * The length of the string created. + */ +INT WINAPI SHStringFromGUIDA(REFGUID guid, LPSTR lpszDest, INT cchMax) +{ + char xguid[40]; + INT iLen; + + TRACE("(%s,%p,%d)\n", debugstr_guid(guid), lpszDest, cchMax); + + sprintf(xguid, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", + guid->Data1, guid->Data2, guid->Data3, + guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], + guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); + + iLen = strlen(xguid) + 1; + + if (iLen > cchMax) + return 0; + memcpy(lpszDest, xguid, iLen); + return iLen; +} + +/************************************************************************* + * @ [SHLWAPI.24] + * + * Convert a GUID to a string. + * + * PARAMS + * guid [I] GUID to convert + * str [O] Destination for string + * cmax [I] Length of output buffer + * + * RETURNS + * The length of the string created. + */ +INT WINAPI SHStringFromGUIDW(REFGUID guid, LPWSTR lpszDest, INT cchMax) +{ + WCHAR xguid[40]; + INT iLen; + static const WCHAR wszFormat[] = {'{','%','0','8','l','X','-','%','0','4','X','-','%','0','4','X','-', + '%','0','2','X','%','0','2','X','-','%','0','2','X','%','0','2','X','%','0','2','X','%','0','2', + 'X','%','0','2','X','%','0','2','X','}',0}; + + TRACE("(%s,%p,%d)\n", debugstr_guid(guid), lpszDest, cchMax); + + sprintfW(xguid, wszFormat, guid->Data1, guid->Data2, guid->Data3, + guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], + guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]); + + iLen = strlenW(xguid) + 1; + + if (iLen > cchMax) + return 0; + memcpy(lpszDest, xguid, iLen*sizeof(WCHAR)); + return iLen; +} + +/************************************************************************* + * @ [SHLWAPI.29] + * + * Determine if a Unicode character is a space. + * + * PARAMS + * wc [I] Character to check. + * + * RETURNS + * TRUE, if wc is a space, + * FALSE otherwise. + */ +BOOL WINAPI IsCharSpaceW(WCHAR wc) +{ + WORD CharType; + + return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_SPACE); +} + +/************************************************************************* + * @ [SHLWAPI.30] + * + * Determine if a Unicode character is a blank. + * + * PARAMS + * wc [I] Character to check. + * + * RETURNS + * TRUE, if wc is a blank, + * FALSE otherwise. + * + */ +BOOL WINAPI IsCharBlankW(WCHAR wc) +{ + WORD CharType; + + return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_BLANK); +} + +/************************************************************************* + * @ [SHLWAPI.31] + * + * Determine if a Unicode character is punctuation. + * + * PARAMS + * wc [I] Character to check. + * + * RETURNS + * TRUE, if wc is punctuation, + * FALSE otherwise. + */ +BOOL WINAPI IsCharPunctW(WCHAR wc) +{ + WORD CharType; + + return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_PUNCT); +} + +/************************************************************************* + * @ [SHLWAPI.32] + * + * Determine if a Unicode character is a control character. + * + * PARAMS + * wc [I] Character to check. + * + * RETURNS + * TRUE, if wc is a control character, + * FALSE otherwise. + */ +BOOL WINAPI IsCharCntrlW(WCHAR wc) +{ + WORD CharType; + + return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_CNTRL); +} + +/************************************************************************* + * @ [SHLWAPI.33] + * + * Determine if a Unicode character is a digit. + * + * PARAMS + * wc [I] Character to check. + * + * RETURNS + * TRUE, if wc is a digit, + * FALSE otherwise. + */ +BOOL WINAPI IsCharDigitW(WCHAR wc) +{ + WORD CharType; + + return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_DIGIT); +} + +/************************************************************************* + * @ [SHLWAPI.34] + * + * Determine if a Unicode character is a hex digit. + * + * PARAMS + * wc [I] Character to check. + * + * RETURNS + * TRUE, if wc is a hex digit, + * FALSE otherwise. + */ +BOOL WINAPI IsCharXDigitW(WCHAR wc) +{ + WORD CharType; + + return GetStringTypeW(CT_CTYPE1, &wc, 1, &CharType) && (CharType & C1_XDIGIT); +} + +/************************************************************************* + * @ [SHLWAPI.35] + * + */ +BOOL WINAPI GetStringType3ExW(LPWSTR lpszStr, DWORD dwLen, LPVOID p3) +{ + FIXME("(%s,0x%08lx,%p): stub\n", debugstr_w(lpszStr), dwLen, p3); + return TRUE; +} + +/************************************************************************* + * @ [SHLWAPI.36] + * + * Insert a bitmap menu item at the bottom of a menu. + * + * PARAMS + * hMenu [I] Menu to insert into + * flags [I] Flags for insertion + * id [I] Menu ID of the item + * str [I] Menu text for the item + * + * RETURNS + * Success: TRUE, the item is inserted into the menu + * Failure: FALSE, if any parameter is invalid + */ +BOOL WINAPI AppendMenuWrapW(HMENU hMenu, UINT flags, UINT id, LPCWSTR str) +{ + TRACE("(%p,0x%08x,0x%08x,%s)\n",hMenu, flags, id, debugstr_w(str)); + return InsertMenuW(hMenu, -1, flags | MF_BITMAP, id, str); +} + +/************************************************************************* + * @ [SHLWAPI.74] + * + * Get the text from a given dialog item. + * + * PARAMS + * hWnd [I] Handle of dialog + * nItem [I] Index of item + * lpsDest [O] Buffer for receiving window text + * nDestLen [I] Length of buffer. + * + * RETURNS + * Success: The length of the returned text. + * Failure: 0. + */ +INT WINAPI GetDlgItemTextWrapW(HWND hWnd, INT nItem, LPWSTR lpsDest,INT nDestLen) +{ + HWND hItem = GetDlgItem(hWnd, nItem); + + if (hItem) + return GetWindowTextW(hItem, lpsDest, nDestLen); + if (nDestLen) + *lpsDest = (WCHAR)'\0'; + return 0; +} + +/************************************************************************* + * @ [SHLWAPI.138] + * + * Set the text of a given dialog item. + * + * PARAMS + * hWnd [I] Handle of dialog + * iItem [I] Index of item + * lpszText [O] Text to set + * + * RETURNS + * Success: TRUE. The text of the dialog is set to lpszText. + * Failure: FALSE, Otherwise. + */ +BOOL WINAPI SetDlgItemTextWrapW(HWND hWnd, INT iItem, LPCWSTR lpszText) +{ + HWND hWndItem = GetDlgItem(hWnd, iItem); + if (hWndItem) + return SetWindowTextW(hWndItem, lpszText); + return FALSE; +} + +/************************************************************************* + * @ [SHLWAPI.151] + * + * Compare two Ascii strings up to a given length. + * + * PARAMS + * lpszSrc [I] Source string + * lpszCmp [I] String to compare to lpszSrc + * len [I] Maximum length + * + * RETURNS + * A number greater than, less than or equal to 0 depending on whether + * lpszSrc is greater than, less than or equal to lpszCmp. + */ +DWORD WINAPI StrCmpNCA(LPCSTR lpszSrc, LPCSTR lpszCmp, INT len) +{ + return strncmp(lpszSrc, lpszCmp, len); +} + +/************************************************************************* + * @ [SHLWAPI.152] + * + * Unicode version of StrCmpNCA. + */ +DWORD WINAPI StrCmpNCW(LPCWSTR lpszSrc, LPCWSTR lpszCmp, INT len) +{ + return strncmpW(lpszSrc, lpszCmp, len); +} + +/************************************************************************* + * @ [SHLWAPI.153] + * + * Compare two Ascii strings up to a given length, ignoring case. + * + * PARAMS + * lpszSrc [I] Source string + * lpszCmp [I] String to compare to lpszSrc + * len [I] Maximum length + * + * RETURNS + * A number greater than, less than or equal to 0 depending on whether + * lpszSrc is greater than, less than or equal to lpszCmp. + */ +DWORD WINAPI StrCmpNICA(LPCSTR lpszSrc, LPCSTR lpszCmp, DWORD len) +{ + return strncasecmp(lpszSrc, lpszCmp, len); +} + +/************************************************************************* + * @ [SHLWAPI.154] + * + * Unicode version of StrCmpNICA. + */ +DWORD WINAPI StrCmpNICW(LPCWSTR lpszSrc, LPCWSTR lpszCmp, DWORD len) +{ + return strncmpiW(lpszSrc, lpszCmp, len); +} + +/************************************************************************* + * @ [SHLWAPI.155] + * + * Compare two Ascii strings. + * + * PARAMS + * lpszSrc [I] Source string + * lpszCmp [I] String to compare to lpszSrc + * + * RETURNS + * A number greater than, less than or equal to 0 depending on whether + * lpszSrc is greater than, less than or equal to lpszCmp. + */ +DWORD WINAPI StrCmpCA(LPCSTR lpszSrc, LPCSTR lpszCmp) +{ + return strcmp(lpszSrc, lpszCmp); +} + +/************************************************************************* + * @ [SHLWAPI.156] + * + * Unicode version of StrCmpCA. + */ +DWORD WINAPI StrCmpCW(LPCWSTR lpszSrc, LPCWSTR lpszCmp) +{ + return strcmpW(lpszSrc, lpszCmp); +} + +/************************************************************************* + * @ [SHLWAPI.157] + * + * Compare two Ascii strings, ignoring case. + * + * PARAMS + * lpszSrc [I] Source string + * lpszCmp [I] String to compare to lpszSrc + * + * RETURNS + * A number greater than, less than or equal to 0 depending on whether + * lpszSrc is greater than, less than or equal to lpszCmp. + */ +DWORD WINAPI StrCmpICA(LPCSTR lpszSrc, LPCSTR lpszCmp) +{ + return strcasecmp(lpszSrc, lpszCmp); +} + +/************************************************************************* + * @ [SHLWAPI.158] + * + * Unicode version of StrCmpICA. + */ +DWORD WINAPI StrCmpICW(LPCWSTR lpszSrc, LPCWSTR lpszCmp) +{ + return strcmpiW(lpszSrc, lpszCmp); +} + +/************************************************************************* + * @ [SHLWAPI.160] + * + * Get an identification string for the OS and explorer. + * + * PARAMS + * lpszDest [O] Destination for Id string + * dwDestLen [I] Length of lpszDest + * + * RETURNS + * TRUE, If the string was created successfully + * FALSE, Otherwise + */ +BOOL WINAPI SHAboutInfoA(LPSTR lpszDest, DWORD dwDestLen) +{ + WCHAR buff[2084]; + + TRACE("(%p,%ld)\n", lpszDest, dwDestLen); + + if (lpszDest && SHAboutInfoW(buff, dwDestLen)) + { + WideCharToMultiByte(CP_ACP, 0, buff, -1, lpszDest, dwDestLen, NULL, NULL); + return TRUE; + } + return FALSE; +} + +/************************************************************************* + * @ [SHLWAPI.161] + * + * Unicode version of SHAboutInfoA. + */ +BOOL WINAPI SHAboutInfoW(LPWSTR lpszDest, DWORD dwDestLen) +{ + static const WCHAR szIEKey[] = { 'S','O','F','T','W','A','R','E','\\', + 'M','i','c','r','o','s','o','f','t','\\','I','n','t','e','r','n','e','t', + ' ','E','x','p','l','o','r','e','r','\0' }; + static const WCHAR szWinNtKey[] = { 'S','O','F','T','W','A','R','E','\\', + 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s',' ', + 'N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\0' }; + static const WCHAR szWinKey[] = { 'S','O','F','T','W','A','R','E','\\', + 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\', + 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\0' }; + static const WCHAR szRegKey[] = { 'S','O','F','T','W','A','R','E','\\', + 'M','i','c','r','o','s','o','f','t','\\','I','n','t','e','r','n','e','t', + ' ','E','x','p','l','o','r','e','r','\\', + 'R','e','g','i','s','t','r','a','t','i','o','n','\0' }; + static const WCHAR szVersion[] = { 'V','e','r','s','i','o','n','\0' }; + static const WCHAR szCustomized[] = { 'C','u','s','t','o','m','i','z','e','d', + 'V','e','r','s','i','o','n','\0' }; + static const WCHAR szOwner[] = { 'R','e','g','i','s','t','e','r','e','d', + 'O','w','n','e','r','\0' }; + static const WCHAR szOrg[] = { 'R','e','g','i','s','t','e','r','e','d', + 'O','r','g','a','n','i','z','a','t','i','o','n','\0' }; + static const WCHAR szProduct[] = { 'P','r','o','d','u','c','t','I','d','\0' }; + static const WCHAR szUpdate[] = { 'I','E','A','K', + 'U','p','d','a','t','e','U','r','l','\0' }; + static const WCHAR szHelp[] = { 'I','E','A','K', + 'H','e','l','p','S','t','r','i','n','g','\0' }; + WCHAR buff[2084]; + HKEY hReg; + DWORD dwType, dwLen; + + TRACE("(%p,%ld)\n", lpszDest, dwDestLen); + + if (!lpszDest) + return FALSE; + + *lpszDest = '\0'; + + /* Try the NT key first, followed by 95/98 key */ + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szWinNtKey, 0, KEY_READ, &hReg) && + RegOpenKeyExW(HKEY_LOCAL_MACHINE, szWinKey, 0, KEY_READ, &hReg)) + return FALSE; + + /* OS Version */ + buff[0] = '\0'; + dwLen = 30; + if (!SHGetValueW(HKEY_LOCAL_MACHINE, szIEKey, szVersion, &dwType, buff, &dwLen)) + { + DWORD dwStrLen = strlenW(buff); + dwLen = 30 - dwStrLen; + SHGetValueW(HKEY_LOCAL_MACHINE, szIEKey, + szCustomized, &dwType, buff+dwStrLen, &dwLen); + } + StrCatBuffW(lpszDest, buff, dwDestLen); + + /* ~Registered Owner */ + buff[0] = '~'; + dwLen = 256; + if (SHGetValueW(hReg, szOwner, 0, &dwType, buff+1, &dwLen)) + buff[1] = '\0'; + StrCatBuffW(lpszDest, buff, dwDestLen); + + /* ~Registered Organization */ + dwLen = 256; + if (SHGetValueW(hReg, szOrg, 0, &dwType, buff+1, &dwLen)) + buff[1] = '\0'; + StrCatBuffW(lpszDest, buff, dwDestLen); + + /* FIXME: Not sure where this number comes from */ + buff[0] = '~'; + buff[1] = '0'; + buff[2] = '\0'; + StrCatBuffW(lpszDest, buff, dwDestLen); + + /* ~Product Id */ + dwLen = 256; + if (SHGetValueW(HKEY_LOCAL_MACHINE, szRegKey, szProduct, &dwType, buff+1, &dwLen)) + buff[1] = '\0'; + StrCatBuffW(lpszDest, buff, dwDestLen); + + /* ~IE Update Url */ + dwLen = 2048; + if(SHGetValueW(HKEY_LOCAL_MACHINE, szWinKey, szUpdate, &dwType, buff+1, &dwLen)) + buff[1] = '\0'; + StrCatBuffW(lpszDest, buff, dwDestLen); + + /* ~IE Help String */ + dwLen = 256; + if(SHGetValueW(hReg, szHelp, 0, &dwType, buff+1, &dwLen)) + buff[1] = '\0'; + StrCatBuffW(lpszDest, buff, dwDestLen); + + RegCloseKey(hReg); + return TRUE; +} + +/************************************************************************* + * @ [SHLWAPI.163] + * + * Call IOleCommandTarget_QueryStatus() on an object. + * + * PARAMS + * lpUnknown [I] Object supporting the IOleCommandTarget interface + * pguidCmdGroup [I] GUID for the command group + * cCmds [I] + * prgCmds [O] Commands + * pCmdText [O] Command text + * + * RETURNS + * Success: S_OK. + * Failure: E_FAIL, if lpUnknown is NULL. + * E_NOINTERFACE, if lpUnknown does not support IOleCommandTarget. + * Otherwise, an error code from IOleCommandTarget_QueryStatus(). + */ +HRESULT WINAPI IUnknown_QueryStatus(IUnknown* lpUnknown, REFGUID pguidCmdGroup, + ULONG cCmds, OLECMD *prgCmds, OLECMDTEXT* pCmdText) +{ + HRESULT hRet = E_FAIL; + + TRACE("(%p,%p,%ld,%p,%p)\n",lpUnknown, pguidCmdGroup, cCmds, prgCmds, pCmdText); + + if (lpUnknown) + { + IOleCommandTarget* lpOle; + + hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleCommandTarget, + (void**)&lpOle); + + if (SUCCEEDED(hRet) && lpOle) + { + hRet = IOleCommandTarget_QueryStatus(lpOle, pguidCmdGroup, cCmds, + prgCmds, pCmdText); + IOleCommandTarget_Release(lpOle); + } + } + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.164] + * + * Call IOleCommandTarget_Exec() on an object. + * + * PARAMS + * lpUnknown [I] Object supporting the IOleCommandTarget interface + * pguidCmdGroup [I] GUID for the command group + * + * RETURNS + * Success: S_OK. + * Failure: E_FAIL, if lpUnknown is NULL. + * E_NOINTERFACE, if lpUnknown does not support IOleCommandTarget. + * Otherwise, an error code from IOleCommandTarget_Exec(). + */ +HRESULT WINAPI IUnknown_Exec(IUnknown* lpUnknown, REFGUID pguidCmdGroup, + DWORD nCmdID, DWORD nCmdexecopt, VARIANT* pvaIn, + VARIANT* pvaOut) +{ + HRESULT hRet = E_FAIL; + + TRACE("(%p,%p,%ld,%ld,%p,%p)\n",lpUnknown, pguidCmdGroup, nCmdID, + nCmdexecopt, pvaIn, pvaOut); + + if (lpUnknown) + { + IOleCommandTarget* lpOle; + + hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleCommandTarget, + (void**)&lpOle); + if (SUCCEEDED(hRet) && lpOle) + { + hRet = IOleCommandTarget_Exec(lpOle, pguidCmdGroup, nCmdID, + nCmdexecopt, pvaIn, pvaOut); + IOleCommandTarget_Release(lpOle); + } + } + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.165] + * + * Retrieve, modify, and re-set a value from a window. + * + * PARAMS + * hWnd [I] Window to get value from + * offset [I] Offset of value + * wMask [I] Mask for uiFlags + * wFlags [I] Bits to set in window value + * + * RETURNS + * The new value as it was set, or 0 if any parameter is invalid. + * + * NOTES + * Any bits set in uiMask are cleared from the value, then any bits set in + * uiFlags are set in the value. + */ +LONG WINAPI SHSetWindowBits(HWND hwnd, INT offset, UINT wMask, UINT wFlags) +{ + LONG ret = GetWindowLongA(hwnd, offset); + LONG newFlags = (wFlags & wMask) | (ret & ~wFlags); + + if (newFlags != ret) + ret = SetWindowLongA(hwnd, offset, newFlags); + return ret; +} + +/************************************************************************* + * @ [SHLWAPI.167] + * + * Change a window's parent. + * + * PARAMS + * hWnd [I] Window to change parent of + * hWndParent [I] New parent window + * + * RETURNS + * The old parent of hWnd. + * + * NOTES + * If hWndParent is NULL (desktop), the window style is changed to WS_POPUP. + * If hWndParent is NOT NULL then we set the WS_CHILD style. + */ +HWND WINAPI SHSetParentHwnd(HWND hWnd, HWND hWndParent) +{ + TRACE("%p, %p\n", hWnd, hWndParent); + + if(GetParent(hWnd) == hWndParent) + return 0; + + if(hWndParent) + SHSetWindowBits(hWnd, GWL_STYLE, WS_CHILD, WS_CHILD); + else + SHSetWindowBits(hWnd, GWL_STYLE, WS_POPUP, WS_POPUP); + + return SetParent(hWnd, hWndParent); +} + +/************************************************************************* + * @ [SHLWAPI.168] + * + * Locate and advise a connection point in an IConnectionPointContainer object. + * + * PARAMS + * lpUnkSink [I] Sink for the connection point advise call + * riid [I] REFIID of connection point to advise + * bAdviseOnly [I] TRUE = Advise only, FALSE = Unadvise first + * lpUnknown [I] Object supporting the IConnectionPointContainer interface + * lpCookie [O] Pointer to connection point cookie + * lppCP [O] Destination for the IConnectionPoint found + * + * RETURNS + * Success: S_OK. If lppCP is non-NULL, it is filled with the IConnectionPoint + * that was advised. The caller is responsable for releasing it. + * Failure: E_FAIL, if any arguments are invalid. + * E_NOINTERFACE, if lpUnknown isn't an IConnectionPointContainer, + * Or an HRESULT error code if any call fails. + */ +HRESULT WINAPI ConnectToConnectionPoint(IUnknown* lpUnkSink, REFIID riid, BOOL bAdviseOnly, + IUnknown* lpUnknown, LPDWORD lpCookie, + IConnectionPoint **lppCP) +{ + HRESULT hRet; + IConnectionPointContainer* lpContainer; + IConnectionPoint *lpCP; + + if(!lpUnknown || (bAdviseOnly && !lpUnkSink)) + return E_FAIL; + + if(lppCP) + *lppCP = NULL; + + hRet = IUnknown_QueryInterface(lpUnknown, &IID_IConnectionPointContainer, + (void**)&lpContainer); + if (SUCCEEDED(hRet)) + { + hRet = IConnectionPointContainer_FindConnectionPoint(lpContainer, riid, &lpCP); + + if (SUCCEEDED(hRet)) + { + if(!bAdviseOnly) + hRet = IConnectionPoint_Unadvise(lpCP, *lpCookie); + hRet = IConnectionPoint_Advise(lpCP, lpUnkSink, lpCookie); + + if (FAILED(hRet)) + *lpCookie = 0; + + if (lppCP && SUCCEEDED(hRet)) + *lppCP = lpCP; /* Caller keeps the interface */ + else + IConnectionPoint_Release(lpCP); /* Release it */ + } + + IUnknown_Release(lpContainer); + } + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.169] + * + * Release an interface. + * + * PARAMS + * lpUnknown [I] Object to release + * + * RETURNS + * Nothing. + */ +DWORD WINAPI IUnknown_AtomicRelease(IUnknown ** lpUnknown) +{ + IUnknown *temp; + + TRACE("(%p)\n",lpUnknown); + + if(!lpUnknown || !*((LPDWORD)lpUnknown)) return 0; + temp = *lpUnknown; + *lpUnknown = NULL; + + TRACE("doing Release\n"); + + return IUnknown_Release(temp); +} + +/************************************************************************* + * @ [SHLWAPI.170] + * + * Skip '//' if present in a string. + * + * PARAMS + * lpszSrc [I] String to check for '//' + * + * RETURNS + * Success: The next character after the '//' or the string if not present + * Failure: NULL, if lpszStr is NULL. + */ +LPCSTR WINAPI PathSkipLeadingSlashesA(LPCSTR lpszSrc) +{ + if (lpszSrc && lpszSrc[0] == '/' && lpszSrc[1] == '/') + lpszSrc += 2; + return lpszSrc; +} + +/************************************************************************* + * @ [SHLWAPI.171] + * + * Check if two interfaces come from the same object. + * + * PARAMS + * lpInt1 [I] Interface to check against lpInt2. + * lpInt2 [I] Interface to check against lpInt1. + * + * RETURNS + * TRUE, If the interfaces come from the same object. + * FALSE Otherwise. + */ +BOOL WINAPI SHIsSameObject(IUnknown* lpInt1, IUnknown* lpInt2) +{ + LPVOID lpUnknown1, lpUnknown2; + + TRACE("%p %p\n", lpInt1, lpInt2); + + if (!lpInt1 || !lpInt2) + return FALSE; + + if (lpInt1 == lpInt2) + return TRUE; + + if (!SUCCEEDED(IUnknown_QueryInterface(lpInt1, &IID_IUnknown, + (LPVOID *)&lpUnknown1))) + return FALSE; + + if (!SUCCEEDED(IUnknown_QueryInterface(lpInt2, &IID_IUnknown, + (LPVOID *)&lpUnknown2))) + return FALSE; + + if (lpUnknown1 == lpUnknown2) + return TRUE; + + return FALSE; +} + +/************************************************************************* + * @ [SHLWAPI.172] + * + * Get the window handle of an object. + * + * PARAMS + * lpUnknown [I] Object to get the window handle of + * lphWnd [O] Destination for window handle + * + * RETURNS + * Success: S_OK. lphWnd contains the objects window handle. + * Failure: An HRESULT error code. + * + * NOTES + * lpUnknown is expected to support one of the following interfaces: + * IOleWindow(), IInternetSecurityMgrSite(), or IShellView(). + */ +HRESULT WINAPI IUnknown_GetWindow(IUnknown *lpUnknown, HWND *lphWnd) +{ + /* FIXME: Wine has no header for this object */ + static const GUID IID_IInternetSecurityMgrSite = { 0x79eac9ed, + 0xbaf9, 0x11ce, { 0x8c, 0x82, 0x00, 0xaa, 0x00, 0x4b, 0xa9, 0x0b }}; + IUnknown *lpOle; + HRESULT hRet = E_FAIL; + + TRACE("(%p,%p)\n", lpUnknown, lphWnd); + + if (!lpUnknown) + return hRet; + + hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleWindow, (void**)&lpOle); + + if (FAILED(hRet)) + { + hRet = IUnknown_QueryInterface(lpUnknown,&IID_IShellView, (void**)&lpOle); + + if (FAILED(hRet)) + { + hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInternetSecurityMgrSite, + (void**)&lpOle); + } + } + + if (SUCCEEDED(hRet)) + { + /* Lazyness here - Since GetWindow() is the first method for the above 3 + * interfaces, we use the same call for them all. + */ + hRet = IOleWindow_GetWindow((IOleWindow*)lpOle, lphWnd); + IUnknown_Release(lpOle); + if (lphWnd) + TRACE("Returning HWND=%p\n", *lphWnd); + } + + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.173] + * + * Call a method on as as yet unidentified object. + * + * PARAMS + * pUnk [I] Object supporting the unidentified interface, + * arg [I] Argument for the call on the object. + * + * RETURNS + * S_OK. + */ +HRESULT WINAPI IUnknown_SetOwner(IUnknown *pUnk, ULONG arg) +{ + static const GUID guid_173 = { + 0x5836fb00, 0x8187, 0x11cf, { 0xa1,0x2b,0x00,0xaa,0x00,0x4a,0xe8,0x37 } + }; + IMalloc *pUnk2; + + TRACE("(%p,%ld)\n", pUnk, arg); + + /* Note: arg may not be a ULONG and pUnk2 is for sure not an IMalloc - + * We use this interface as its vtable entry is compatible with the + * object in question. + * FIXME: Find out what this object is and where it should be defined. + */ + if (pUnk && + SUCCEEDED(IUnknown_QueryInterface(pUnk, &guid_173, (void**)&pUnk2))) + { + IMalloc_Alloc(pUnk2, arg); /* Faked call!! */ + IMalloc_Release(pUnk2); + } + return S_OK; +} + +/************************************************************************* + * @ [SHLWAPI.174] + * + * Call either IObjectWithSite_SetSite() or IPersistMoniker_GetClassID() on + * an interface. + * + * RETURNS + * Success: S_OK. + * Failure: E_FAIL, if p1 is NULL. + * E_NOINTERFACE If p1 does not support the IPersist interface, + * Or an HRESULT error code. + */ +DWORD WINAPI IUnknown_SetSite( + IUnknown *p1, /* [in] OLE object */ + LPVOID *p2) /* [out] ptr for call results */ +{ + DWORD ret, aa; + IUnknown *iobjectwithsite; + + if (!p1) return E_FAIL; + + /* see if SetSite interface exists for IObjectWithSite object */ + ret = IUnknown_QueryInterface((IUnknown *)p1, (REFIID)id1, (LPVOID *)&iobjectwithsite); + TRACE("first IU_QI ret=%08lx, iobjectwithsite=%p\n", ret, iobjectwithsite); + if (ret) { + + /* see if GetClassId interface exists for IPersistMoniker object */ + ret = IUnknown_QueryInterface(p1, (REFIID)id2, (LPVOID *)&aa); + TRACE("second IU_QI ret=%08lx, aa=%08lx\n", ret, aa); + if (ret) return ret; + + /* fake a GetClassId call */ + ret = IOleWindow_GetWindow((IOleWindow *)aa, (HWND*)p2); + TRACE("second IU_QI doing 0x0c ret=%08lx, *p2=%08lx\n", ret, + *(LPDWORD)p2); + IUnknown_Release((IUnknown *)aa); + } + else { + /* fake a SetSite call */ + ret = IOleWindow_GetWindow((IOleWindow *)iobjectwithsite, (HWND*)p2); + TRACE("first IU_QI doing 0x0c ret=%08lx, *p2=%08lx\n", ret, + *(LPDWORD)p2); + IUnknown_Release((IUnknown *)iobjectwithsite); + } + return ret; +} + +/************************************************************************* + * @ [SHLWAPI.175] + * + * Call IPersist_GetClassID() on an object. + * + * PARAMS + * lpUnknown [I] Object supporting the IPersist interface + * lpClassId [O] Destination for Class Id + * + * RETURNS + * Success: S_OK. lpClassId contains the Class Id requested. + * Failure: E_FAIL, If lpUnknown is NULL, + * E_NOINTERFACE If lpUnknown does not support IPersist, + * Or an HRESULT error code. + */ +HRESULT WINAPI IUnknown_GetClassID(IUnknown *lpUnknown, CLSID* lpClassId) +{ + IPersist* lpPersist; + HRESULT hRet = E_FAIL; + + TRACE("(%p,%p)\n", lpUnknown, debugstr_guid(lpClassId)); + + if (lpUnknown) + { + hRet = IUnknown_QueryInterface(lpUnknown,&IID_IPersist,(void**)&lpPersist); + if (SUCCEEDED(hRet)) + { + IPersist_GetClassID(lpPersist, lpClassId); + IPersist_Release(lpPersist); + } + } + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.176] + * + * Retrieve a Service Interface from an object. + * + * PARAMS + * lpUnknown [I] Object to get an IServiceProvider interface from + * sid [I] Service ID for IServiceProvider_QueryService() call + * riid [I] Function requested for QueryService call + * lppOut [O] Destination for the service interface pointer + * + * RETURNS + * Success: S_OK. lppOut contains an object providing the requested service + * Failure: An HRESULT error code + * + * NOTES + * lpUnknown is expected to support the IServiceProvider interface. + */ +HRESULT WINAPI IUnknown_QueryService(IUnknown* lpUnknown, REFGUID sid, REFIID riid, + LPVOID *lppOut) +{ + IServiceProvider* pService = NULL; + HRESULT hRet; + + if (!lppOut) + return E_FAIL; + + *lppOut = NULL; + + if (!lpUnknown) + return E_FAIL; + + /* Get an IServiceProvider interface from the object */ + hRet = IUnknown_QueryInterface(lpUnknown, &IID_IServiceProvider, + (LPVOID*)&pService); + + if (!hRet && pService) + { + TRACE("QueryInterface returned (IServiceProvider*)%p\n", pService); + + /* Get a Service interface from the object */ + hRet = IServiceProvider_QueryService(pService, sid, riid, lppOut); + + TRACE("(IServiceProvider*)%p returned (IUnknown*)%p\n", pService, *lppOut); + + /* Release the IServiceProvider interface */ + IUnknown_Release(pService); + } + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.177] + * + * Loads a popup menu. + * + * PARAMS + * hInst [I] Instance handle + * szName [I] Menu name + * + * RETURNS + * Success: TRUE. + * Failure: FALSE. + */ +BOOL WINAPI SHLoadMenuPopup(HINSTANCE hInst, LPCWSTR szName) +{ + HMENU hMenu, hSubMenu; + + if ((hMenu = LoadMenuW(hInst, szName))) + { + if ((hSubMenu = GetSubMenu(hMenu, 0))) + RemoveMenu(hMenu, 0, MF_BYPOSITION); + + DestroyMenu(hMenu); + return TRUE; + } + return FALSE; +} + +typedef struct _enumWndData +{ + UINT uiMsgId; + WPARAM wParam; + LPARAM lParam; + LRESULT (WINAPI *pfnPost)(HWND,UINT,WPARAM,LPARAM); +} enumWndData; + +/* Callback for SHLWAPI_178 */ +static BOOL CALLBACK SHLWAPI_EnumChildProc(HWND hWnd, LPARAM lParam) +{ + enumWndData *data = (enumWndData *)lParam; + + TRACE("(%p,%p)\n", hWnd, data); + data->pfnPost(hWnd, data->uiMsgId, data->wParam, data->lParam); + return TRUE; +} + +/************************************************************************* + * @ [SHLWAPI.178] + * + * Send or post a message to every child of a window. + * + * PARAMS + * hWnd [I] Window whose children will get the messages + * uiMsgId [I] Message Id + * wParam [I] WPARAM of message + * lParam [I] LPARAM of message + * bSend [I] TRUE = Use SendMessageA(), FALSE = Use PostMessageA() + * + * RETURNS + * Nothing. + * + * NOTES + * The appropriate ASCII or Unicode function is called for the window. + */ +void WINAPI SHPropagateMessage(HWND hWnd, UINT uiMsgId, WPARAM wParam, LPARAM lParam, BOOL bSend) +{ + enumWndData data; + + TRACE("(%p,%u,%d,%ld,%d)\n", hWnd, uiMsgId, wParam, lParam, bSend); + + if(hWnd) + { + data.uiMsgId = uiMsgId; + data.wParam = wParam; + data.lParam = lParam; + + if (bSend) + data.pfnPost = IsWindowUnicode(hWnd) ? (void*)SendMessageW : (void*)SendMessageA; + else + data.pfnPost = IsWindowUnicode(hWnd) ? (void*)PostMessageW : (void*)PostMessageA; + + EnumChildWindows(hWnd, SHLWAPI_EnumChildProc, (LPARAM)&data); + } +} + +/************************************************************************* + * @ [SHLWAPI.180] + * + * Remove all sub-menus from a menu. + * + * PARAMS + * hMenu [I] Menu to remove sub-menus from + * + * RETURNS + * Success: 0. All sub-menus under hMenu are removed + * Failure: -1, if any parameter is invalid + */ +DWORD WINAPI SHRemoveAllSubMenus(HMENU hMenu) +{ + int iItemCount = GetMenuItemCount(hMenu) - 1; + while (iItemCount >= 0) + { + HMENU hSubMenu = GetSubMenu(hMenu, iItemCount); + if (hSubMenu) + RemoveMenu(hMenu, iItemCount, MF_BYPOSITION); + iItemCount--; + } + return iItemCount; +} + +/************************************************************************* + * @ [SHLWAPI.181] + * + * Enable or disable a menu item. + * + * PARAMS + * hMenu [I] Menu holding menu item + * uID [I] ID of menu item to enable/disable + * bEnable [I] Whether to enable (TRUE) or disable (FALSE) the item. + * + * RETURNS + * The return code from EnableMenuItem. + */ +UINT WINAPI SHEnableMenuItem(HMENU hMenu, UINT wItemID, BOOL bEnable) +{ + return EnableMenuItem(hMenu, wItemID, bEnable ? MF_ENABLED : MF_GRAYED); +} + +/************************************************************************* + * @ [SHLWAPI.182] + * + * Check or uncheck a menu item. + * + * PARAMS + * hMenu [I] Menu holding menu item + * uID [I] ID of menu item to check/uncheck + * bCheck [I] Whether to check (TRUE) or uncheck (FALSE) the item. + * + * RETURNS + * The return code from CheckMenuItem. + */ +DWORD WINAPI SHCheckMenuItem(HMENU hMenu, UINT uID, BOOL bCheck) +{ + return CheckMenuItem(hMenu, uID, bCheck ? MF_CHECKED : MF_UNCHECKED); +} + +/************************************************************************* + * @ [SHLWAPI.183] + * + * Register a window class if it isn't already. + * + * PARAMS + * lpWndClass [I] Window class to register + * + * RETURNS + * The result of the RegisterClassA call. + */ +DWORD WINAPI SHRegisterClassA(WNDCLASSA *wndclass) +{ + WNDCLASSA wca; + if (GetClassInfoA(wndclass->hInstance, wndclass->lpszClassName, &wca)) + return TRUE; + return (DWORD)RegisterClassA(wndclass); +} + +/************************************************************************* + * @ [SHLWAPI.186] + */ +BOOL WINAPI SHSimulateDrop(IDropTarget *pDrop, IDataObject *pDataObj, + DWORD grfKeyState, PPOINTL lpPt, DWORD* pdwEffect) +{ + DWORD dwEffect = DROPEFFECT_LINK | DROPEFFECT_MOVE | DROPEFFECT_COPY; + POINTL pt = { 0, 0 }; + + if (!lpPt) + lpPt = &pt; + + if (!pdwEffect) + pdwEffect = &dwEffect; + + IDropTarget_DragEnter(pDrop, pDataObj, grfKeyState, *lpPt, pdwEffect); + + if (*pdwEffect) + return IDropTarget_Drop(pDrop, pDataObj, grfKeyState, *lpPt, pdwEffect); + + IDropTarget_DragLeave(pDrop); + return TRUE; +} + +/************************************************************************* + * @ [SHLWAPI.187] + * + * Call IPersistPropertyBag_Load() on an object. + * + * PARAMS + * lpUnknown [I] Object supporting the IPersistPropertyBag interface + * lpPropBag [O] Destination for loaded IPropertyBag + * + * RETURNS + * Success: S_OK. + * Failure: An HRESULT error code, or E_FAIL if lpUnknown is NULL. + */ +DWORD WINAPI SHLoadFromPropertyBag(IUnknown *lpUnknown, IPropertyBag* lpPropBag) +{ + IPersistPropertyBag* lpPPBag; + HRESULT hRet = E_FAIL; + + TRACE("(%p,%p)\n", lpUnknown, lpPropBag); + + if (lpUnknown) + { + hRet = IUnknown_QueryInterface(lpUnknown, &IID_IPersistPropertyBag, + (void**)&lpPPBag); + if (SUCCEEDED(hRet) && lpPPBag) + { + hRet = IPersistPropertyBag_Load(lpPPBag, lpPropBag, NULL); + IPersistPropertyBag_Release(lpPPBag); + } + } + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.188] + * + * Call IOleControlSite_TranslateAccelerator() on an object. + * + * PARAMS + * lpUnknown [I] Object supporting the IOleControlSite interface. + * lpMsg [I] Key message to be processed. + * dwModifiers [I] Flags containing the state of the modifier keys. + * + * RETURNS + * Success: S_OK. + * Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL. + */ +HRESULT WINAPI IUnknown_TranslateAcceleratorOCS(IUnknown *lpUnknown, LPMSG lpMsg, DWORD dwModifiers) +{ + IOleControlSite* lpCSite = NULL; + HRESULT hRet = E_INVALIDARG; + + TRACE("(%p,%p,0x%08lx)\n", lpUnknown, lpMsg, dwModifiers); + if (lpUnknown) + { + hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleControlSite, + (void**)&lpCSite); + if (SUCCEEDED(hRet) && lpCSite) + { + hRet = IOleControlSite_TranslateAccelerator(lpCSite, lpMsg, dwModifiers); + IOleControlSite_Release(lpCSite); + } + } + return hRet; +} + + +/************************************************************************* + * @ [SHLWAPI.189] + * + * Call IOleControlSite_GetExtendedControl() on an object. + * + * PARAMS + * lpUnknown [I] Object supporting the IOleControlSite interface. + * lppDisp [O] Destination for resulting IDispatch. + * + * RETURNS + * Success: S_OK. + * Failure: An HRESULT error code, or E_FAIL if lpUnknown is NULL. + */ +DWORD WINAPI IUnknown_OnFocusOCS(IUnknown *lpUnknown, IDispatch** lppDisp) +{ + IOleControlSite* lpCSite = NULL; + HRESULT hRet = E_FAIL; + + TRACE("(%p,%p)\n", lpUnknown, lppDisp); + if (lpUnknown) + { + hRet = IUnknown_QueryInterface(lpUnknown, &IID_IOleControlSite, + (void**)&lpCSite); + if (SUCCEEDED(hRet) && lpCSite) + { + hRet = IOleControlSite_GetExtendedControl(lpCSite, lppDisp); + IOleControlSite_Release(lpCSite); + } + } + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.190] + */ +HRESULT WINAPI IUnknown_HandleIRestrict(LPUNKNOWN lpUnknown, PVOID lpArg1, + PVOID lpArg2, PVOID lpArg3, PVOID lpArg4) +{ + /* FIXME: {D12F26B2-D90A-11D0-830D-00AA005B4383} - What object does this represent? */ + static const DWORD service_id[] = { 0xd12f26b2, 0x11d0d90a, 0xaa000d83, 0x83435b00 }; + /* FIXME: {D12F26B1-D90A-11D0-830D-00AA005B4383} - Also Unknown/undocumented */ + static const DWORD function_id[] = { 0xd12f26b1, 0x11d0d90a, 0xaa000d83, 0x83435b00 }; + HRESULT hRet = E_INVALIDARG; + LPUNKNOWN lpUnkInner = NULL; /* FIXME: Real type is unknown */ + + TRACE("(%p,%p,%p,%p,%p)\n", lpUnknown, lpArg1, lpArg2, lpArg3, lpArg4); + + if (lpUnknown && lpArg4) + { + hRet = IUnknown_QueryService(lpUnknown, (REFGUID)service_id, + (REFGUID)function_id, (void**)&lpUnkInner); + + if (SUCCEEDED(hRet) && lpUnkInner) + { + /* FIXME: The type of service object requested is unknown, however + * testing shows that its first method is called with 4 parameters. + * Fake this by using IParseDisplayName_ParseDisplayName since the + * signature and position in the vtable matches our unknown object type. + */ + hRet = IParseDisplayName_ParseDisplayName((LPPARSEDISPLAYNAME)lpUnkInner, + lpArg1, lpArg2, lpArg3, lpArg4); + IUnknown_Release(lpUnkInner); + } + } + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.192] + * + * Get a sub-menu from a menu item. + * + * PARAMS + * hMenu [I] Menu to get sub-menu from + * uID [I] ID of menu item containing sub-menu + * + * RETURNS + * The sub-menu of the item, or a NULL handle if any parameters are invalid. + */ +HMENU WINAPI SHGetMenuFromID(HMENU hMenu, UINT uID) +{ + MENUITEMINFOA mi; + + TRACE("(%p,%uld)\n", hMenu, uID); + + mi.cbSize = sizeof(MENUITEMINFOA); + mi.fMask = MIIM_SUBMENU; + + if (!GetMenuItemInfoA(hMenu, uID, 0, &mi)) + return NULL; + + return mi.hSubMenu; +} + +/************************************************************************* + * @ [SHLWAPI.193] + * + * Get the color depth of the primary display. + * + * PARAMS + * None. + * + * RETURNS + * The color depth of the primary display. + */ +DWORD WINAPI SHGetCurColorRes() +{ + HDC hdc; + DWORD ret; + + TRACE("()\n"); + + hdc = GetDC(0); + ret = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES); + ReleaseDC(0, hdc); + return ret; +} + +/************************************************************************* + * @ [SHLWAPI.194] + * + * Wait for a message to arrive, with a timeout. + * + * PARAMS + * hand [I] Handle to query + * dwTimeout [I] Timeout in ticks or INFINITE to never timeout + * + * RETURNS + * STATUS_TIMEOUT if no message is received before dwTimeout ticks passes. + * Otherwise returns the value from MsgWaitForMultipleObjectsEx when a + * message is available. + */ +DWORD WINAPI SHWaitForSendMessageThread(HANDLE hand, DWORD dwTimeout) +{ + DWORD dwEndTicks = GetTickCount() + dwTimeout; + DWORD dwRet; + + while ((dwRet = MsgWaitForMultipleObjectsEx(1, &hand, dwTimeout, QS_SENDMESSAGE, 0)) == 1) + { + MSG msg; + + PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE); + + if (dwTimeout != INFINITE) + { + if ((int)(dwTimeout = dwEndTicks - GetTickCount()) <= 0) + return WAIT_TIMEOUT; + } + } + + return dwRet; +} + +/************************************************************************* + * @ [SHLWAPI.195] + * + * Determine if a shell folder can be expanded. + * + * PARAMS + * lpFolder [I] Parent folder containing the object to test. + * pidl [I] Id of the object to test. + * + * RETURNS + * Success: S_OK, if the object is expandable, S_FALSE otherwise. + * Failure: E_INVALIDARG, if any argument is invalid. + * + * NOTES + * If the object to be tested does not expose the IQueryInfo() interface it + * will not be identified as an expandable folder. + */ +HRESULT WINAPI SHIsExpandableFolder(LPSHELLFOLDER lpFolder, LPCITEMIDLIST pidl) +{ + HRESULT hRet = E_INVALIDARG; + IQueryInfo *lpInfo; + + if (lpFolder && pidl) + { + hRet = IShellFolder_GetUIObjectOf(lpFolder, NULL, 1, &pidl, &IID_IQueryInfo, + NULL, (void**)&lpInfo); + if (FAILED(hRet)) + hRet = S_FALSE; /* Doesn't expose IQueryInfo */ + else + { + DWORD dwFlags = 0; + + /* MSDN states of IQueryInfo_GetInfoFlags() that "This method is not + * currently used". Really? You wouldn't be holding out on me would you? + */ + hRet = IQueryInfo_GetInfoFlags(lpInfo, &dwFlags); + + if (SUCCEEDED(hRet)) + { + /* 0x2 is an undocumented flag apparently indicating expandability */ + hRet = dwFlags & 0x2 ? S_OK : S_FALSE; + } + + IQueryInfo_Release(lpInfo); + } + } + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.197] + * + * Blank out a region of text by drawing the background only. + * + * PARAMS + * hDC [I] Device context to draw in + * pRect [I] Area to draw in + * cRef [I] Color to draw in + * + * RETURNS + * Nothing. + */ +DWORD WINAPI SHFillRectClr(HDC hDC, LPCRECT pRect, COLORREF cRef) +{ + COLORREF cOldColor = SetBkColor(hDC, cRef); + ExtTextOutA(hDC, 0, 0, ETO_OPAQUE, pRect, 0, 0, 0); + SetBkColor(hDC, cOldColor); + return 0; +} + +/************************************************************************* + * @ [SHLWAPI.198] + * + * Return the value asociated with a key in a map. + * + * PARAMS + * lpKeys [I] A list of keys of length iLen + * lpValues [I] A list of values associated with lpKeys, of length iLen + * iLen [I] Length of both lpKeys and lpValues + * iKey [I] The key value to look up in lpKeys + * + * RETURNS + * The value in lpValues associated with iKey, or -1 if iKey is not + * found in lpKeys. + * + * NOTES + * - If two elements in the map share the same key, this function returns + * the value closest to the start of the map + * - The native version of this function crashes if lpKeys or lpValues is NULL. + */ +int WINAPI SHSearchMapInt(const int *lpKeys, const int *lpValues, int iLen, int iKey) +{ + if (lpKeys && lpValues) + { + int i = 0; + + while (i < iLen) + { + if (lpKeys[i] == iKey) + return lpValues[i]; /* Found */ + i++; + } + } + return -1; /* Not found */ +} + + +/************************************************************************* + * @ [SHLWAPI.199] + * + * Copy an interface pointer + * + * PARAMS + * lppDest [O] Destination for copy + * lpUnknown [I] Source for copy + * + * RETURNS + * Nothing. + */ +VOID WINAPI IUnknown_Set(IUnknown **lppDest, IUnknown *lpUnknown) +{ + TRACE("(%p,%p)\n", lppDest, lpUnknown); + + if (lppDest) + IUnknown_AtomicRelease(lppDest); /* Release existing interface */ + + if (lpUnknown) + { + /* Copy */ + IUnknown_AddRef(lpUnknown); + *lppDest = lpUnknown; + } +} + +/************************************************************************* + * @ [SHLWAPI.200] + * + */ +HRESULT WINAPI MayQSForward(IUnknown* lpUnknown, PVOID lpReserved, + REFGUID riidCmdGrp, ULONG cCmds, + OLECMD *prgCmds, OLECMDTEXT* pCmdText) +{ + FIXME("(%p,%p,%p,%ld,%p,%p) - stub\n", + lpUnknown, lpReserved, riidCmdGrp, cCmds, prgCmds, pCmdText); + + /* FIXME: Calls IsQSForward & IUnknown_QueryStatus */ + return DRAGDROP_E_NOTREGISTERED; +} + +/************************************************************************* + * @ [SHLWAPI.201] + * + */ +HRESULT WINAPI MayExecForward(IUnknown* lpUnknown, INT iUnk, REFGUID pguidCmdGroup, + DWORD nCmdID, DWORD nCmdexecopt, VARIANT* pvaIn, + VARIANT* pvaOut) +{ + FIXME("(%p,%d,%p,%ld,%ld,%p,%p) - stub!\n", lpUnknown, iUnk, pguidCmdGroup, + nCmdID, nCmdexecopt, pvaIn, pvaOut); + return DRAGDROP_E_NOTREGISTERED; +} + +/************************************************************************* + * @ [SHLWAPI.202] + * + */ +HRESULT WINAPI IsQSForward(REFGUID pguidCmdGroup,ULONG cCmds, OLECMD *prgCmds) +{ + FIXME("(%p,%ld,%p) - stub!\n", pguidCmdGroup, cCmds, prgCmds); + return DRAGDROP_E_NOTREGISTERED; +} + +/************************************************************************* + * @ [SHLWAPI.204] + * + * Determine if a window is not a child of another window. + * + * PARAMS + * hParent [I] Suspected parent window + * hChild [I] Suspected child window + * + * RETURNS + * TRUE: If hChild is a child window of hParent + * FALSE: If hChild is not a child window of hParent, or they are equal + */ +BOOL WINAPI SHIsChildOrSelf(HWND hParent, HWND hChild) +{ + TRACE("(%p,%p)\n", hParent, hChild); + + if (!hParent || !hChild) + return TRUE; + else if(hParent == hChild) + return FALSE; + return !IsChild(hParent, hChild); +} + +/************************************************************************* + * @ [SHLWAPI.208] + * + * Some sort of memory management process. + */ +DWORD WINAPI FDSA_Initialize( + DWORD a, + DWORD b, + LPVOID c, + LPVOID d, + DWORD e) +{ + FIXME("(0x%08lx 0x%08lx %p %p 0x%08lx) stub\n", + a, b, c, d, e); + return 1; +} + +/************************************************************************* + * @ [SHLWAPI.209] + * + * Some sort of memory management process. + */ +DWORD WINAPI FDSA_Destroy( + LPVOID a) +{ + FIXME("(%p) stub\n", + a); + return 1; +} + +/************************************************************************* + * @ [SHLWAPI.210] + * + * Some sort of memory management process. + */ +DWORD WINAPI FDSA_InsertItem( + LPVOID a, + DWORD b, + LPVOID c) +{ + FIXME("(%p 0x%08lx %p) stub\n", + a, b, c); + return 0; +} + +/************************************************************************* + * @ [SHLWAPI.211] + */ +DWORD WINAPI FDSA_DeleteItem( + LPVOID a, + DWORD b) +{ + FIXME("(%p 0x%08lx) stub\n", + a, b); + return 1; +} + +typedef struct { + REFIID refid; + DWORD indx; +} IFACE_INDEX_TBL; + +/************************************************************************* + * @ [SHLWAPI.219] + * + * Call IUnknown_QueryInterface() on a table of objects. + * + * RETURNS + * Success: S_OK. + * Failure: E_POINTER or E_NOINTERFACE. + */ +HRESULT WINAPI QISearch( + LPVOID w, /* [in] Table of interfaces */ + IFACE_INDEX_TBL *x, /* [in] Array of REFIIDs and indexes into the table */ + REFIID riid, /* [in] REFIID to get interface for */ + LPVOID *ppv) /* [out] Destination for interface pointer */ +{ + HRESULT ret; + IUnknown *a_vtbl; + IFACE_INDEX_TBL *xmove; + + TRACE("(%p %p %s %p)\n", w,x,debugstr_guid(riid),ppv); + if (ppv) { + xmove = x; + while (xmove->refid) { + TRACE("trying (indx %ld) %s\n", xmove->indx, debugstr_guid(xmove->refid)); + if (IsEqualIID(riid, xmove->refid)) { + a_vtbl = (IUnknown*)(xmove->indx + (LPBYTE)w); + TRACE("matched, returning (%p)\n", a_vtbl); + *ppv = (LPVOID)a_vtbl; + IUnknown_AddRef(a_vtbl); + return S_OK; + } + xmove++; + } + + if (IsEqualIID(riid, &IID_IUnknown)) { + a_vtbl = (IUnknown*)(x->indx + (LPBYTE)w); + TRACE("returning first for IUnknown (%p)\n", a_vtbl); + *ppv = (LPVOID)a_vtbl; + IUnknown_AddRef(a_vtbl); + return S_OK; + } + *ppv = 0; + ret = E_NOINTERFACE; + } else + ret = E_POINTER; + + TRACE("-- 0x%08lx\n", ret); + return ret; +} + +/************************************************************************* + * @ [SHLWAPI.221] + * + * Remove the "PropDlgFont" property from a window. + * + * PARAMS + * hWnd [I] Window to remove the property from + * + * RETURNS + * A handle to the removed property, or NULL if it did not exist. + */ +HANDLE WINAPI SHRemoveDefaultDialogFont(HWND hWnd) +{ + HANDLE hProp; + + TRACE("(%p)\n", hWnd); + + hProp = GetPropA(hWnd, "PropDlgFont"); + + if(hProp) + { + DeleteObject(hProp); + hProp = RemovePropA(hWnd, "PropDlgFont"); + } + return hProp; +} + +/************************************************************************* + * @ [SHLWAPI.236] + * + * Load the in-process server of a given GUID. + * + * PARAMS + * refiid [I] GUID of the server to load. + * + * RETURNS + * Success: A handle to the loaded server dll. + * Failure: A NULL handle. + */ +HMODULE WINAPI SHPinDllOfCLSID(REFIID refiid) +{ + HKEY newkey; + DWORD type, count; + CHAR value[MAX_PATH], string[MAX_PATH]; + + strcpy(string, "CLSID\\"); + SHStringFromGUIDA(refiid, string + 6, sizeof(string)/sizeof(char) - 6); + strcat(string, "\\InProcServer32"); + + count = MAX_PATH; + RegOpenKeyExA(HKEY_CLASSES_ROOT, string, 0, 1, &newkey); + RegQueryValueExA(newkey, 0, 0, &type, (PBYTE)value, &count); + RegCloseKey(newkey); + return LoadLibraryExA(value, 0, 0); +} + +/************************************************************************* + * @ [SHLWAPI.237] + * + * Unicode version of SHLWAPI_183. + */ +DWORD WINAPI SHRegisterClassW(WNDCLASSW * lpWndClass) +{ + WNDCLASSW WndClass; + + TRACE("(%p %s)\n",lpWndClass->hInstance, debugstr_w(lpWndClass->lpszClassName)); + + if (GetClassInfoW(lpWndClass->hInstance, lpWndClass->lpszClassName, &WndClass)) + return TRUE; + return RegisterClassW(lpWndClass); +} + +/************************************************************************* + * @ [SHLWAPI.238] + * + * Unregister a list of classes. + * + * PARAMS + * hInst [I] Application instance that registered the classes + * lppClasses [I] List of class names + * iCount [I] Number of names in lppClasses + * + * RETURNS + * Nothing. + */ +void WINAPI SHUnregisterClassesA(HINSTANCE hInst, LPCSTR *lppClasses, INT iCount) +{ + WNDCLASSA WndClass; + + TRACE("(%p,%p,%d)\n", hInst, lppClasses, iCount); + + while (iCount > 0) + { + if (GetClassInfoA(hInst, *lppClasses, &WndClass)) + UnregisterClassA(*lppClasses, hInst); + lppClasses++; + iCount--; + } +} + +/************************************************************************* + * @ [SHLWAPI.239] + * + * Unicode version of SHUnregisterClassesA. + */ +void WINAPI SHUnregisterClassesW(HINSTANCE hInst, LPCWSTR *lppClasses, INT iCount) +{ + WNDCLASSW WndClass; + + TRACE("(%p,%p,%d)\n", hInst, lppClasses, iCount); + + while (iCount > 0) + { + if (GetClassInfoW(hInst, *lppClasses, &WndClass)) + UnregisterClassW(*lppClasses, hInst); + lppClasses++; + iCount--; + } +} + +/************************************************************************* + * @ [SHLWAPI.240] + * + * Call The correct (Ascii/Unicode) default window procedure for a window. + * + * PARAMS + * hWnd [I] Window to call the default procedure for + * uMessage [I] Message ID + * wParam [I] WPARAM of message + * lParam [I] LPARAM of message + * + * RETURNS + * The result of calling DefWindowProcA() or DefWindowProcW(). + */ +LRESULT CALLBACK SHDefWindowProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam) +{ + if (IsWindowUnicode(hWnd)) + return DefWindowProcW(hWnd, uMessage, wParam, lParam); + return DefWindowProcA(hWnd, uMessage, wParam, lParam); +} + +/************************************************************************* + * @ [SHLWAPI.256] + */ +HRESULT WINAPI IUnknown_GetSite(LPUNKNOWN lpUnknown, REFIID iid, PVOID *lppSite) +{ + HRESULT hRet = E_INVALIDARG; + LPOBJECTWITHSITE lpSite = NULL; + + TRACE("(%p,%s,%p)\n", lpUnknown, debugstr_guid(iid), lppSite); + + if (lpUnknown && iid && lppSite) + { + hRet = IUnknown_QueryInterface(lpUnknown, &IID_IObjectWithSite, + (void**)&lpSite); + if (SUCCEEDED(hRet) && lpSite) + { + hRet = IObjectWithSite_GetSite(lpSite, iid, lppSite); + IObjectWithSite_Release(lpSite); + } + } + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.257] + * + * Create a worker window using CreateWindowExA(). + * + * PARAMS + * wndProc [I] Window procedure + * hWndParent [I] Parent window + * dwExStyle [I] Extra style flags + * dwStyle [I] Style flags + * hMenu [I] Window menu + * z [I] Unknown + * + * RETURNS + * Success: The window handle of the newly created window. + * Failure: 0. + */ +HWND WINAPI SHCreateWorkerWindowA(LONG wndProc, HWND hWndParent, DWORD dwExStyle, + DWORD dwStyle, HMENU hMenu, LONG z) +{ + static const char* szClass = "WorkerA"; + WNDCLASSA wc; + HWND hWnd; + + TRACE("(0x%08lx,%p,0x%08lx,0x%08lx,%p,0x%08lx)\n", + wndProc, hWndParent, dwExStyle, dwStyle, hMenu, z); + + /* Create Window class */ + wc.style = 0; + wc.lpfnWndProc = DefWindowProcA; + wc.cbClsExtra = 0; + wc.cbWndExtra = 4; + wc.hInstance = shlwapi_hInstance; + wc.hIcon = NULL; + wc.hCursor = LoadCursorA(NULL, (LPSTR)IDC_ARROW); + wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW; + wc.lpszMenuName = NULL; + wc.lpszClassName = szClass; + + SHRegisterClassA(&wc); /* Register class */ + + /* FIXME: Set extra bits in dwExStyle */ + + hWnd = CreateWindowExA(dwExStyle, szClass, 0, dwStyle, 0, 0, 0, 0, + hWndParent, hMenu, shlwapi_hInstance, 0); + if (hWnd) + { + SetWindowLongPtrW(hWnd, DWLP_MSGRESULT, z); + + if (wndProc) + SetWindowLongPtrA(hWnd, GWLP_WNDPROC, wndProc); + } + return hWnd; +} + +typedef struct tagPOLICYDATA +{ + DWORD policy; /* flags value passed to SHRestricted */ + LPCWSTR appstr; /* application str such as "Explorer" */ + LPCWSTR keystr; /* name of the actual registry key / policy */ +} POLICYDATA, *LPPOLICYDATA; + +#define SHELL_NO_POLICY 0xffffffff + +/* default shell policy registry key */ +static const WCHAR strRegistryPolicyW[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o', + 's','o','f','t','\\','W','i','n','d','o','w','s','\\', + 'C','u','r','r','e','n','t','V','e','r','s','i','o','n', + '\\','P','o','l','i','c','i','e','s',0}; + +/************************************************************************* + * @ [SHLWAPI.271] + * + * Retrieve a policy value from the registry. + * + * PARAMS + * lpSubKey [I] registry key name + * lpSubName [I] subname of registry key + * lpValue [I] value name of registry value + * + * RETURNS + * the value associated with the registry key or 0 if not found + */ +DWORD WINAPI SHGetRestriction(LPCWSTR lpSubKey, LPCWSTR lpSubName, LPCWSTR lpValue) +{ + DWORD retval, datsize = sizeof(retval); + HKEY hKey; + + if (!lpSubKey) + lpSubKey = strRegistryPolicyW; + + retval = RegOpenKeyW(HKEY_LOCAL_MACHINE, lpSubKey, &hKey); + if (retval != ERROR_SUCCESS) + retval = RegOpenKeyW(HKEY_CURRENT_USER, lpSubKey, &hKey); + if (retval != ERROR_SUCCESS) + return 0; + + SHGetValueW(hKey, lpSubName, lpValue, NULL, (LPBYTE)&retval, &datsize); + RegCloseKey(hKey); + return retval; +} + +/************************************************************************* + * @ [SHLWAPI.266] + * + * Helper function to retrieve the possibly cached value for a specific policy + * + * PARAMS + * policy [I] The policy to look for + * initial [I] Main registry key to open, if NULL use default + * polTable [I] Table of known policies, 0 terminated + * polArr [I] Cache array of policy values + * + * RETURNS + * The retrieved policy value or 0 if not successful + * + * NOTES + * This function is used by the native SHRestricted function to search for the + * policy and cache it once retrieved. The current Wine implementation uses a + * different POLICYDATA structure and implements a similar algorithme adapted to + * that structure. + */ +DWORD WINAPI SHRestrictionLookup( + DWORD policy, + LPCWSTR initial, + LPPOLICYDATA polTable, + LPDWORD polArr) +{ + TRACE("(0x%08lx %s %p %p)\n", policy, debugstr_w(initial), polTable, polArr); + + if (!polTable || !polArr) + return 0; + + for (;polTable->policy; polTable++, polArr++) + { + if (policy == polTable->policy) + { + /* we have a known policy */ + + /* check if this policy has been cached */ + if (*polArr == SHELL_NO_POLICY) + *polArr = SHGetRestriction(initial, polTable->appstr, polTable->keystr); + return *polArr; + } + } + /* we don't know this policy, return 0 */ + TRACE("unknown policy: (%08lx)\n", policy); + return 0; +} + +/************************************************************************* + * @ [SHLWAPI.267] + * + * Get an interface from an object. + * + * RETURNS + * Success: S_OK. ppv contains the requested interface. + * Failure: An HRESULT error code. + * + * NOTES + * This QueryInterface asks the inner object for an interface. In case + * of aggregation this request would be forwarded by the inner to the + * outer object. This function asks the inner object directly for the + * interface circumventing the forwarding to the outer object. + */ +HRESULT WINAPI SHWeakQueryInterface( + IUnknown * pUnk, /* [in] Outer object */ + IUnknown * pInner, /* [in] Inner object */ + IID * riid, /* [in] Interface GUID to query for */ + LPVOID* ppv) /* [out] Destination for queried interface */ +{ + HRESULT hret = E_NOINTERFACE; + TRACE("(pUnk=%p pInner=%p\n\tIID: %s %p)\n",pUnk,pInner,debugstr_guid(riid), ppv); + + *ppv = NULL; + if(pUnk && pInner) { + hret = IUnknown_QueryInterface(pInner, riid, (LPVOID*)ppv); + if (SUCCEEDED(hret)) IUnknown_Release(pUnk); + } + TRACE("-- 0x%08lx\n", hret); + return hret; +} + +/************************************************************************* + * @ [SHLWAPI.268] + * + * Move a reference from one interface to another. + * + * PARAMS + * lpDest [O] Destination to receive the reference + * lppUnknown [O] Source to give up the reference to lpDest + * + * RETURNS + * Nothing. + */ +VOID WINAPI SHWeakReleaseInterface(IUnknown *lpDest, IUnknown **lppUnknown) +{ + TRACE("(%p,%p)\n", lpDest, lppUnknown); + + if (*lppUnknown) + { + /* Copy Reference*/ + IUnknown_AddRef(lpDest); + IUnknown_AtomicRelease(lppUnknown); /* Release existing interface */ + } +} + +/************************************************************************* + * @ [SHLWAPI.269] + * + * Convert an ASCII string of a CLSID into a CLSID. + * + * PARAMS + * idstr [I] String representing a CLSID in registry format + * id [O] Destination for the converted CLSID + * + * RETURNS + * Success: TRUE. id contains the converted CLSID. + * Failure: FALSE. + */ +BOOL WINAPI GUIDFromStringA(LPCSTR idstr, CLSID *id) +{ + WCHAR wClsid[40]; + MultiByteToWideChar(CP_ACP, 0, idstr, -1, wClsid, sizeof(wClsid)/sizeof(WCHAR)); + return SUCCEEDED(CLSIDFromStringWrap(wClsid, id)); +} + +/************************************************************************* + * @ [SHLWAPI.270] + * + * Unicode version of GUIDFromStringA. + */ +BOOL WINAPI GUIDFromStringW(LPCWSTR idstr, CLSID *id) +{ + return SUCCEEDED(CLSIDFromStringWrap(idstr, id)); +} + +/************************************************************************* + * @ [SHLWAPI.276] + * + * Determine if the browser is integrated into the shell, and set a registry + * key accordingly. + * + * PARAMS + * None. + * + * RETURNS + * 1, If the browser is not integrated. + * 2, If the browser is integrated. + * + * NOTES + * The key "HKLM\Software\Microsoft\Internet Explorer\IntegratedBrowser" is + * either set to TRUE, or removed depending on whether the browser is deemed + * to be integrated. + */ +DWORD WINAPI WhichPlatform() +{ + static LPCSTR szIntegratedBrowser = "IntegratedBrowser"; + static DWORD dwState = 0; + HKEY hKey; + DWORD dwRet, dwData, dwSize; + + if (dwState) + return dwState; + + /* If shell32 exports DllGetVersion(), the browser is integrated */ + GET_FUNC(pDllGetVersion, shell32, "DllGetVersion", 1); + dwState = pDllGetVersion ? 2 : 1; + + /* Set or delete the key accordingly */ + dwRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE, + "Software\\Microsoft\\Internet Explorer", 0, + KEY_ALL_ACCESS, &hKey); + if (!dwRet) + { + dwRet = RegQueryValueExA(hKey, szIntegratedBrowser, 0, 0, + (LPBYTE)&dwData, &dwSize); + + if (!dwRet && dwState == 1) + { + /* Value exists but browser is not integrated */ + RegDeleteValueA(hKey, szIntegratedBrowser); + } + else if (dwRet && dwState == 2) + { + /* Browser is integrated but value does not exist */ + dwData = TRUE; + RegSetValueExA(hKey, szIntegratedBrowser, 0, REG_DWORD, + (LPBYTE)&dwData, sizeof(dwData)); + } + RegCloseKey(hKey); + } + return dwState; +} + +/************************************************************************* + * @ [SHLWAPI.278] + * + * Unicode version of SHCreateWorkerWindowA. + */ +HWND WINAPI SHCreateWorkerWindowW(LONG wndProc, HWND hWndParent, DWORD dwExStyle, + DWORD dwStyle, HMENU hMenu, LONG z) +{ + static const WCHAR szClass[] = { 'W', 'o', 'r', 'k', 'e', 'r', 'W', '\0' }; + WNDCLASSW wc; + HWND hWnd; + + TRACE("(0x%08lx,%p,0x%08lx,0x%08lx,%p,0x%08lx)\n", + wndProc, hWndParent, dwExStyle, dwStyle, hMenu, z); + + /* If our OS is natively ASCII, use the ASCII version */ + if (!(GetVersion() & 0x80000000)) /* NT */ + return SHCreateWorkerWindowA(wndProc, hWndParent, dwExStyle, dwStyle, hMenu, z); + + /* Create Window class */ + wc.style = 0; + wc.lpfnWndProc = DefWindowProcW; + wc.cbClsExtra = 0; + wc.cbWndExtra = 4; + wc.hInstance = shlwapi_hInstance; + wc.hIcon = NULL; + wc.hCursor = LoadCursorW(NULL, (LPWSTR)IDC_ARROW); + wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW; + wc.lpszMenuName = NULL; + wc.lpszClassName = szClass; + + SHRegisterClassW(&wc); /* Register class */ + + /* FIXME: Set extra bits in dwExStyle */ + + hWnd = CreateWindowExW(dwExStyle, szClass, 0, dwStyle, 0, 0, 0, 0, + hWndParent, hMenu, shlwapi_hInstance, 0); + if (hWnd) + { + SetWindowLongPtrW(hWnd, DWLP_MSGRESULT, z); + + if (wndProc) + SetWindowLongPtrW(hWnd, GWLP_WNDPROC, wndProc); + } + return hWnd; +} + +/************************************************************************* + * @ [SHLWAPI.279] + * + * Get and show a context menu from a shell folder. + * + * PARAMS + * hWnd [I] Window displaying the shell folder + * lpFolder [I] IShellFolder interface + * lpApidl [I] Id for the particular folder desired + * + * RETURNS + * Success: S_OK. + * Failure: An HRESULT error code indicating the error. + */ +HRESULT WINAPI SHInvokeDefaultCommand(HWND hWnd, IShellFolder* lpFolder, LPCITEMIDLIST lpApidl) +{ + return SHInvokeCommand(hWnd, lpFolder, lpApidl, FALSE); +} + +/************************************************************************* + * @ [SHLWAPI.281] + * + * _SHPackDispParamsV + */ +HRESULT WINAPI SHPackDispParamsV(LPVOID w, LPVOID x, LPVOID y, LPVOID z) +{ + FIXME("%p %p %p %p\n",w,x,y,z); + return E_FAIL; +} + +/************************************************************************* + * @ [SHLWAPI.282] + * + * This function seems to be a forward to SHPackDispParamsV (whatever THAT + * function does...). + */ +HRESULT WINAPI SHPackDispParams(LPVOID w, LPVOID x, LPVOID y, LPVOID z) +{ + FIXME("%p %p %p %p\n", w, x, y, z); + return E_FAIL; +} + +/************************************************************************* + * @ [SHLWAPI.284] + * + * _IConnectionPoint_SimpleInvoke + */ +DWORD WINAPI IConnectionPoint_SimpleInvoke( + LPVOID x, + LPVOID y, + LPVOID z) +{ + FIXME("(%p %p %p) stub\n",x,y,z); + return 0; +} + +/************************************************************************* + * @ [SHLWAPI.285] + * + * Notify an IConnectionPoint object of changes. + * + * PARAMS + * lpCP [I] Object to notify + * dispID [I] + * + * RETURNS + * Success: S_OK. + * Failure: E_NOINTERFACE, if lpCP is NULL or does not support the + * IConnectionPoint interface. + */ +HRESULT WINAPI IConnectionPoint_OnChanged(IConnectionPoint* lpCP, DISPID dispID) +{ + IEnumConnections *lpEnum; + HRESULT hRet = E_NOINTERFACE; + + TRACE("(%p,0x%8lX)\n", lpCP, dispID); + + /* Get an enumerator for the connections */ + if (lpCP) + hRet = IConnectionPoint_EnumConnections(lpCP, &lpEnum); + + if (SUCCEEDED(hRet)) + { + IPropertyNotifySink *lpSink; + CONNECTDATA connData; + ULONG ulFetched; + + /* Call OnChanged() for every notify sink in the connection point */ + while (IEnumConnections_Next(lpEnum, 1, &connData, &ulFetched) == S_OK) + { + if (SUCCEEDED(IUnknown_QueryInterface(connData.pUnk, &IID_IPropertyNotifySink, (void**)&lpSink)) && + lpSink) + { + IPropertyNotifySink_OnChanged(lpSink, dispID); + IPropertyNotifySink_Release(lpSink); + } + IUnknown_Release(connData.pUnk); + } + + IEnumConnections_Release(lpEnum); + } + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.287] + * + * Notify an IConnectionPointContainer object of changes. + * + * PARAMS + * lpUnknown [I] Object to notify + * dispID [I] + * + * RETURNS + * Success: S_OK. + * Failure: E_NOINTERFACE, if lpUnknown is NULL or does not support the + * IConnectionPointContainer interface. + */ +HRESULT WINAPI IUnknown_CPContainerOnChanged(IUnknown *lpUnknown, DISPID dispID) +{ + IConnectionPointContainer* lpCPC = NULL; + HRESULT hRet = E_NOINTERFACE; + + TRACE("(%p,0x%8lX)\n", lpUnknown, dispID); + + if (lpUnknown) + hRet = IUnknown_QueryInterface(lpUnknown, &IID_IConnectionPointContainer, (void**)&lpCPC); + + if (SUCCEEDED(hRet)) + { + IConnectionPoint* lpCP; + + hRet = IConnectionPointContainer_FindConnectionPoint(lpCPC, &IID_IPropertyNotifySink, &lpCP); + IConnectionPointContainer_Release(lpCPC); + + hRet = IConnectionPoint_OnChanged(lpCP, dispID); + IConnectionPoint_Release(lpCP); + } + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.289] + * + * See PlaySoundW. + */ +BOOL WINAPI PlaySoundWrapW(LPCWSTR pszSound, HMODULE hmod, DWORD fdwSound) +{ + GET_FUNC(pPlaySoundW, winmm, "PlaySoundW", FALSE); + return pPlaySoundW(pszSound, hmod, fdwSound); +} + +/************************************************************************* + * @ [SHLWAPI.294] + */ +BOOL WINAPI SHGetIniStringW(LPSTR str1, LPSTR str2, LPSTR pStr, DWORD some_len, LPCSTR lpStr2) +{ + /* + * str1: "I" "I" pushl esp+0x20 + * str2: "U" "I" pushl 0x77c93810 + * (is "I" and "U" "integer" and "unsigned" ??) + * + * pStr: "" "" pushl eax + * some_len: 0x824 0x104 pushl 0x824 + * lpStr2: "%l" "%l" pushl esp+0xc + * + * shlwapi. StrCpyNW(lpStr2, irrelevant_var, 0x104); + * LocalAlloc(0x00, some_len) -> irrelevant_var + * LocalAlloc(0x40, irrelevant_len) -> pStr + * shlwapi.294(str1, str2, pStr, some_len, lpStr2); + * shlwapi.PathRemoveBlanksW(pStr); + */ + FIXME("('%s', '%s', '%s', %08lx, '%s'): stub!\n", str1, str2, pStr, some_len, lpStr2); + return TRUE; +} + +/************************************************************************* + * @ [SHLWAPI.295] + * + * Called by ICQ2000b install via SHDOCVW: + * str1: "InternetShortcut" + * x: some unknown pointer + * str2: "http://free.aol.com/tryaolfree/index.adp?139269" + * str3: "C:\\WINDOWS\\Desktop.new2\\Free AOL & Unlimited Internet.url" + * + * In short: this one maybe creates a desktop link :-) + */ +BOOL WINAPI SHSetIniStringW(LPWSTR str1, LPVOID x, LPWSTR str2, LPWSTR str3) +{ + FIXME("('%s', %p, '%s', '%s'), stub.\n", debugstr_w(str1), x, debugstr_w(str2), debugstr_w(str3)); + return TRUE; +} + +/************************************************************************* + * @ [SHLWAPI.299] + * + * See COMCTL32_417. + */ +BOOL WINAPI ExtTextOutWrapW(HDC hdc, INT x, INT y, UINT flags, const RECT *lprect, + LPCWSTR str, UINT count, const INT *lpDx) +{ + GET_FUNC(pCOMCTL32_417, comctl32, (LPCSTR)417, FALSE); + return pCOMCTL32_417(hdc, x, y, flags, lprect, str, count, lpDx); +} + +/************************************************************************* + * @ [SHLWAPI.313] + * + * See SHGetFileInfoW. + */ +DWORD WINAPI SHGetFileInfoWrapW(LPCWSTR path, DWORD dwFileAttributes, + SHFILEINFOW *psfi, UINT sizeofpsfi, UINT flags) +{ + GET_FUNC(pSHGetFileInfoW, shell32, "SHGetFileInfoW", 0); + return pSHGetFileInfoW(path, dwFileAttributes, psfi, sizeofpsfi, flags); +} + +/************************************************************************* + * @ [SHLWAPI.318] + * + * See DragQueryFileW. + */ +UINT WINAPI DragQueryFileWrapW(HDROP hDrop, UINT lFile, LPWSTR lpszFile, UINT lLength) +{ + GET_FUNC(pDragQueryFileW, shell32, "DragQueryFileW", 0); + return pDragQueryFileW(hDrop, lFile, lpszFile, lLength); +} + +/************************************************************************* + * @ [SHLWAPI.333] + * + * See SHBrowseForFolderW. + */ +LPITEMIDLIST WINAPI SHBrowseForFolderWrapW(LPBROWSEINFOW lpBi) +{ + GET_FUNC(pSHBrowseForFolderW, shell32, "SHBrowseForFolderW", NULL); + return pSHBrowseForFolderW(lpBi); +} + +/************************************************************************* + * @ [SHLWAPI.334] + * + * See SHGetPathFromIDListW. + */ +BOOL WINAPI SHGetPathFromIDListWrapW(LPCITEMIDLIST pidl,LPWSTR pszPath) +{ + GET_FUNC(pSHGetPathFromIDListW, shell32, "SHGetPathFromIDListW", 0); + return pSHGetPathFromIDListW(pidl, pszPath); +} + +/************************************************************************* + * @ [SHLWAPI.335] + * + * See ShellExecuteExW. + */ +BOOL WINAPI ShellExecuteExWrapW(LPSHELLEXECUTEINFOW lpExecInfo) +{ + GET_FUNC(pShellExecuteExW, shell32, "ShellExecuteExW", FALSE); + return pShellExecuteExW(lpExecInfo); +} + +/************************************************************************* + * @ [SHLWAPI.336] + * + * See SHFileOperationW. + */ +HICON WINAPI SHFileOperationWrapW(LPSHFILEOPSTRUCTW lpFileOp) +{ + GET_FUNC(pSHFileOperationW, shell32, "SHFileOperationW", 0); + return pSHFileOperationW(lpFileOp); +} + +/************************************************************************* + * @ [SHLWAPI.337] + * + * See ExtractIconExW. + */ +UINT WINAPI ExtractIconExWrapW(LPCWSTR lpszFile, INT nIconIndex, HICON *phiconLarge, + HICON *phiconSmall, UINT nIcons) +{ + GET_FUNC(pExtractIconExW, shell32, "ExtractIconExW", 0); + return pExtractIconExW(lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons); +} + +/************************************************************************* + * @ [SHLWAPI.342] + * + */ +LONG WINAPI SHInterlockedCompareExchange( PLONG dest, LONG xchg, LONG compare) +{ + return InterlockedCompareExchange(dest, xchg, compare); +} + +/************************************************************************* + * @ [SHLWAPI.350] + * + * See GetFileVersionInfoSizeW. + */ +DWORD WINAPI GetFileVersionInfoSizeWrapW( + LPWSTR x, + LPVOID y) +{ + DWORD ret; + + GET_FUNC(pGetFileVersionInfoSizeW, version, "GetFileVersionInfoSizeW", 0); + ret = pGetFileVersionInfoSizeW(x, y); + return 0x208 + ret; +} + +/************************************************************************* + * @ [SHLWAPI.351] + * + * See GetFileVersionInfoW. + */ +BOOL WINAPI GetFileVersionInfoWrapW( + LPWSTR w, /* [in] path to dll */ + DWORD x, /* [in] parm 2 to GetFileVersionInfoA */ + DWORD y, /* [in] return value from SHLWAPI_350() - assume length */ + LPVOID z) /* [in/out] buffer (+0x208 sent to GetFileVersionInfoA()) */ +{ + GET_FUNC(pGetFileVersionInfoW, version, "GetFileVersionInfoW", 0); + return pGetFileVersionInfoW(w, x, y-0x208, (char*)z+0x208); +} + +/************************************************************************* + * @ [SHLWAPI.352] + * + * See VerQueryValueW. + */ +WORD WINAPI VerQueryValueWrapW( + LPVOID w, /* [in] Buffer from SHLWAPI_351() */ + LPWSTR x, /* [in] Value to retrieve - converted and passed to VerQueryValueA() as #2 */ + LPVOID y, /* [out] Ver buffer - passed to VerQueryValueA as #3 */ + UINT* z) /* [in] Ver length - passed to VerQueryValueA as #4 */ +{ + GET_FUNC(pVerQueryValueW, version, "VerQueryValueW", 0); + return pVerQueryValueW((char*)w+0x208, x, y, z); +} + +#define IsIface(type) SUCCEEDED((hRet = IUnknown_QueryInterface(lpUnknown, &IID_##type, (void**)&lpObj))) +#define IShellBrowser_EnableModeless IShellBrowser_EnableModelessSB +#define EnableModeless(type) type##_EnableModeless((type*)lpObj, bModeless) + +/************************************************************************* + * @ [SHLWAPI.355] + * + * Change the modality of a shell object. + * + * PARAMS + * lpUnknown [I] Object to make modeless + * bModeless [I] TRUE=Make modeless, FALSE=Make modal + * + * RETURNS + * Success: S_OK. The modality lpUnknown is changed. + * Failure: An HRESULT error code indicating the error. + * + * NOTES + * lpUnknown must support the IOleInPlaceFrame interface, the + * IInternetSecurityMgrSite interface, the IShellBrowser interface + * the IDocHostUIHandler interface, or the IOleInPlaceActiveObject interface, + * or this call will fail. + */ +HRESULT WINAPI IUnknown_EnableModeless(IUnknown *lpUnknown, BOOL bModeless) +{ + IUnknown *lpObj; + HRESULT hRet; + + TRACE("(%p,%d)\n", lpUnknown, bModeless); + + if (!lpUnknown) + return E_FAIL; + + if (IsIface(IOleInPlaceActiveObject)) + EnableModeless(IOleInPlaceActiveObject); + else if (IsIface(IOleInPlaceFrame)) + EnableModeless(IOleInPlaceFrame); + else if (IsIface(IShellBrowser)) + EnableModeless(IShellBrowser); +#if 0 + /* FIXME: Wine has no headers for these objects yet */ + else if (IsIface(IInternetSecurityMgrSite)) + EnableModeless(IInternetSecurityMgrSite); + else if (IsIface(IDocHostUIHandler)) + EnableModeless(IDocHostUIHandler); +#endif + else + return hRet; + + IUnknown_Release(lpObj); + return S_OK; +} + +/************************************************************************* + * @ [SHLWAPI.357] + * + * See SHGetNewLinkInfoW. + */ +BOOL WINAPI SHGetNewLinkInfoWrapW(LPCWSTR pszLinkTo, LPCWSTR pszDir, LPWSTR pszName, + BOOL *pfMustCopy, UINT uFlags) +{ + GET_FUNC(pSHGetNewLinkInfoW, shell32, "SHGetNewLinkInfoW", FALSE); + return pSHGetNewLinkInfoW(pszLinkTo, pszDir, pszName, pfMustCopy, uFlags); +} + +/************************************************************************* + * @ [SHLWAPI.358] + * + * See SHDefExtractIconW. + */ +UINT WINAPI SHDefExtractIconWrapW(LPCWSTR pszIconFile, int iIndex, UINT uFlags, HICON* phiconLarge, + HICON* phiconSmall, UINT nIconSize) +{ + GET_FUNC(pSHDefExtractIconW, shell32, "SHDefExtractIconW", 0); + return pSHDefExtractIconW(pszIconFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize); +} + +/************************************************************************* + * @ [SHLWAPI.363] + * + * Get and show a context menu from a shell folder. + * + * PARAMS + * hWnd [I] Window displaying the shell folder + * lpFolder [I] IShellFolder interface + * lpApidl [I] Id for the particular folder desired + * bInvokeDefault [I] Whether to invoke the default menu item + * + * RETURNS + * Success: S_OK. If bInvokeDefault is TRUE, the default menu action was + * executed. + * Failure: An HRESULT error code indicating the error. + */ +HRESULT WINAPI SHInvokeCommand(HWND hWnd, IShellFolder* lpFolder, LPCITEMIDLIST lpApidl, BOOL bInvokeDefault) +{ + IContextMenu *iContext; + HRESULT hRet = E_FAIL; + + TRACE("(%p,%p,%p,%d)\n", hWnd, lpFolder, lpApidl, bInvokeDefault); + + if (!lpFolder) + return hRet; + + /* Get the context menu from the shell folder */ + hRet = IShellFolder_GetUIObjectOf(lpFolder, hWnd, 1, &lpApidl, + &IID_IContextMenu, 0, (void**)&iContext); + if (SUCCEEDED(hRet)) + { + HMENU hMenu; + if ((hMenu = CreatePopupMenu())) + { + HRESULT hQuery; + DWORD dwDefaultId = 0; + + /* Add the context menu entries to the popup */ + hQuery = IContextMenu_QueryContextMenu(iContext, hMenu, 0, 1, 0x7FFF, + bInvokeDefault ? CMF_NORMAL : CMF_DEFAULTONLY); + + if (SUCCEEDED(hQuery)) + { + if (bInvokeDefault && + (dwDefaultId = GetMenuDefaultItem(hMenu, 0, 0)) != 0xFFFFFFFF) + { + CMINVOKECOMMANDINFO cmIci; + /* Invoke the default item */ + memset(&cmIci,0,sizeof(cmIci)); + cmIci.cbSize = sizeof(cmIci); + cmIci.fMask = CMIC_MASK_ASYNCOK; + cmIci.hwnd = hWnd; + cmIci.lpVerb = MAKEINTRESOURCEA(dwDefaultId); + cmIci.nShow = SW_SCROLLCHILDREN; + + hRet = IContextMenu_InvokeCommand(iContext, &cmIci); + } + } + DestroyMenu(hMenu); + } + IContextMenu_Release(iContext); + } + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.370] + * + * See ExtractIconW. + */ +HICON WINAPI ExtractIconWrapW(HINSTANCE hInstance, LPCWSTR lpszExeFileName, + UINT nIconIndex) +{ + GET_FUNC(pExtractIconW, shell32, "ExtractIconW", NULL); + return pExtractIconW(hInstance, lpszExeFileName, nIconIndex); +} + +/************************************************************************* + * @ [SHLWAPI.376] + */ +LANGID WINAPI MLGetUILanguage() +{ + FIXME("() stub\n"); + /* FIXME: This should be a forward in the .spec file to the win2k function + * kernel32.GetUserDefaultUILanguage, however that function isn't there yet. + */ + return GetUserDefaultLangID(); +} + +/************************************************************************* + * @ [SHLWAPI.377] + * + * Load a library from the directory of a particular process. + * + * PARAMS + * new_mod [I] Library name + * inst_hwnd [I] Module whose directory is to be used + * dwFlags [I] Flags controlling the load + * + * RETURNS + * Success: A handle to the loaded module + * Failure: A NULL handle. + */ +HMODULE WINAPI MLLoadLibraryA(LPCSTR new_mod, HMODULE inst_hwnd, DWORD dwFlags) +{ + /* FIXME: Native appears to do DPA_Create and a DPA_InsertPtr for + * each call here. + * FIXME: Native shows calls to: + * SHRegGetUSValue for "Software\Microsoft\Internet Explorer\International" + * CheckVersion + * RegOpenKeyExA for "HKLM\Software\Microsoft\Internet Explorer" + * RegQueryValueExA for "LPKInstalled" + * RegCloseKey + * RegOpenKeyExA for "HKCU\Software\Microsoft\Internet Explorer\International" + * RegQueryValueExA for "ResourceLocale" + * RegCloseKey + * RegOpenKeyExA for "HKLM\Software\Microsoft\Active Setup\Installed Components\{guid}" + * RegQueryValueExA for "Locale" + * RegCloseKey + * and then tests the Locale ("en" for me). + * code below + * after the code then a DPA_Create (first time) and DPA_InsertPtr are done. + */ + CHAR mod_path[2*MAX_PATH]; + LPSTR ptr; + DWORD len; + + FIXME("(%s,%p,0x%08lx) semi-stub!\n", debugstr_a(new_mod), inst_hwnd, dwFlags); + len = GetModuleFileNameA(inst_hwnd, mod_path, sizeof(mod_path)); + if (!len || len >= sizeof(mod_path)) return NULL; + + ptr = strrchr(mod_path, '\\'); + if (ptr) { + strcpy(ptr+1, new_mod); + TRACE("loading %s\n", debugstr_a(mod_path)); + return LoadLibraryA(mod_path); + } + return NULL; +} + +/************************************************************************* + * @ [SHLWAPI.378] + * + * Unicode version of MLLoadLibraryA. + */ +HMODULE WINAPI MLLoadLibraryW(LPCWSTR new_mod, HMODULE inst_hwnd, DWORD dwFlags) +{ + WCHAR mod_path[2*MAX_PATH]; + LPWSTR ptr; + DWORD len; + + FIXME("(%s,%p,0x%08lx) semi-stub!\n", debugstr_w(new_mod), inst_hwnd, dwFlags); + len = GetModuleFileNameW(inst_hwnd, mod_path, sizeof(mod_path) / sizeof(WCHAR)); + if (!len || len >= sizeof(mod_path) / sizeof(WCHAR)) return NULL; + + ptr = strrchrW(mod_path, '\\'); + if (ptr) { + strcpyW(ptr+1, new_mod); + TRACE("loading %s\n", debugstr_w(mod_path)); + return LoadLibraryW(mod_path); + } + return NULL; +} + +/************************************************************************* + * ColorAdjustLuma [SHLWAPI.@] + * + * Adjust the luminosity of a color + * + * PARAMS + * cRGB [I] RGB value to convert + * dwLuma [I] Luma adjustment + * bUnknown [I] Unknown + * + * RETURNS + * The adjusted RGB color. + */ +COLORREF WINAPI ColorAdjustLuma(COLORREF cRGB, int dwLuma, BOOL bUnknown) +{ + TRACE("(0x%8lx,%d,%d)\n", cRGB, dwLuma, bUnknown); + + if (dwLuma) + { + WORD wH, wL, wS; + + ColorRGBToHLS(cRGB, &wH, &wL, &wS); + + FIXME("Ignoring luma adjustment\n"); + + /* FIXME: The ajdustment is not linear */ + + cRGB = ColorHLSToRGB(wH, wL, wS); + } + return cRGB; +} + +/************************************************************************* + * @ [SHLWAPI.389] + * + * See GetSaveFileNameW. + */ +BOOL WINAPI GetSaveFileNameWrapW(LPOPENFILENAMEW ofn) +{ + GET_FUNC(pGetSaveFileNameW, comdlg32, "GetSaveFileNameW", FALSE); + return pGetSaveFileNameW(ofn); +} + +/************************************************************************* + * @ [SHLWAPI.390] + * + * See WNetRestoreConnectionW. + */ +DWORD WINAPI WNetRestoreConnectionWrapW(HWND hwndOwner, LPWSTR lpszDevice) +{ + GET_FUNC(pWNetRestoreConnectionW, mpr, "WNetRestoreConnectionW", 0); + return pWNetRestoreConnectionW(hwndOwner, lpszDevice); +} + +/************************************************************************* + * @ [SHLWAPI.391] + * + * See WNetGetLastErrorW. + */ +DWORD WINAPI WNetGetLastErrorWrapW(LPDWORD lpError, LPWSTR lpErrorBuf, DWORD nErrorBufSize, + LPWSTR lpNameBuf, DWORD nNameBufSize) +{ + GET_FUNC(pWNetGetLastErrorW, mpr, "WNetGetLastErrorW", 0); + return pWNetGetLastErrorW(lpError, lpErrorBuf, nErrorBufSize, lpNameBuf, nNameBufSize); +} + +/************************************************************************* + * @ [SHLWAPI.401] + * + * See PageSetupDlgW. + */ +BOOL WINAPI PageSetupDlgWrapW(LPPAGESETUPDLGW pagedlg) +{ + GET_FUNC(pPageSetupDlgW, comdlg32, "PageSetupDlgW", FALSE); + return pPageSetupDlgW(pagedlg); +} + +/************************************************************************* + * @ [SHLWAPI.402] + * + * See PrintDlgW. + */ +BOOL WINAPI PrintDlgWrapW(LPPRINTDLGW printdlg) +{ + GET_FUNC(pPrintDlgW, comdlg32, "PrintDlgW", FALSE); + return pPrintDlgW(printdlg); +} + +/************************************************************************* + * @ [SHLWAPI.403] + * + * See GetOpenFileNameW. + */ +BOOL WINAPI GetOpenFileNameWrapW(LPOPENFILENAMEW ofn) +{ + GET_FUNC(pGetOpenFileNameW, comdlg32, "GetOpenFileNameW", FALSE); + return pGetOpenFileNameW(ofn); +} + +/* INTERNAL: Map from HLS color space to RGB */ +static WORD WINAPI ConvertHue(int wHue, WORD wMid1, WORD wMid2) +{ + wHue = wHue > 240 ? wHue - 240 : wHue < 0 ? wHue + 240 : wHue; + + if (wHue > 160) + return wMid1; + else if (wHue > 120) + wHue = 160 - wHue; + else if (wHue > 40) + return wMid2; + + return ((wHue * (wMid2 - wMid1) + 20) / 40) + wMid1; +} + +/* Convert to RGB and scale into RGB range (0..255) */ +#define GET_RGB(h) (ConvertHue(h, wMid1, wMid2) * 255 + 120) / 240 + +/************************************************************************* + * ColorHLSToRGB [SHLWAPI.@] + * + * Convert from hls color space into an rgb COLORREF. + * + * PARAMS + * wHue [I] Hue amount + * wLuminosity [I] Luminosity amount + * wSaturation [I] Saturation amount + * + * RETURNS + * A COLORREF representing the converted color. + * + * NOTES + * Input hls values are constrained to the range (0..240). + */ +COLORREF WINAPI ColorHLSToRGB(WORD wHue, WORD wLuminosity, WORD wSaturation) +{ + WORD wRed; + + if (wSaturation) + { + WORD wGreen, wBlue, wMid1, wMid2; + + if (wLuminosity > 120) + wMid2 = wSaturation + wLuminosity - (wSaturation * wLuminosity + 120) / 240; + else + wMid2 = ((wSaturation + 240) * wLuminosity + 120) / 240; + + wMid1 = wLuminosity * 2 - wMid2; + + wRed = GET_RGB(wHue + 80); + wGreen = GET_RGB(wHue); + wBlue = GET_RGB(wHue - 80); + + return RGB(wRed, wGreen, wBlue); + } + + wRed = wLuminosity * 255 / 240; + return RGB(wRed, wRed, wRed); +} + +/************************************************************************* + * @ [SHLWAPI.413] + * + * Get the current docking status of the system. + * + * PARAMS + * dwFlags [I] DOCKINFO_ flags from "winbase.h", unused + * + * RETURNS + * One of DOCKINFO_UNDOCKED, DOCKINFO_UNDOCKED, or 0 if the system is not + * a notebook. + */ +DWORD WINAPI SHGetMachineInfo(DWORD dwFlags) +{ + HW_PROFILE_INFOA hwInfo; + + TRACE("(0x%08lx)\n", dwFlags); + + GetCurrentHwProfileA(&hwInfo); + switch (hwInfo.dwDockInfo & (DOCKINFO_DOCKED|DOCKINFO_UNDOCKED)) + { + case DOCKINFO_DOCKED: + case DOCKINFO_UNDOCKED: + return hwInfo.dwDockInfo & (DOCKINFO_DOCKED|DOCKINFO_UNDOCKED); + default: + return 0; + } +} + +/************************************************************************* + * @ [SHLWAPI.418] + * + * Function seems to do FreeLibrary plus other things. + * + * FIXME native shows the following calls: + * RtlEnterCriticalSection + * LocalFree + * GetProcAddress(Comctl32??, 150L) + * DPA_DeletePtr + * RtlLeaveCriticalSection + * followed by the FreeLibrary. + * The above code may be related to .377 above. + */ +BOOL WINAPI MLFreeLibrary(HMODULE hModule) +{ + FIXME("(%p) semi-stub\n", hModule); + return FreeLibrary(hModule); +} + +/************************************************************************* + * @ [SHLWAPI.419] + */ +BOOL WINAPI SHFlushSFCacheWrap(void) { + FIXME(": stub\n"); + return TRUE; +} + +/************************************************************************* + * @ [SHLWAPI.429] + * FIXME I have no idea what this function does or what its arguments are. + */ +BOOL WINAPI MLIsMLHInstance(HINSTANCE hInst) +{ + FIXME("(%p) stub\n", hInst); + return FALSE; +} + + +/************************************************************************* + * @ [SHLWAPI.430] + */ +DWORD WINAPI MLSetMLHInstance(HINSTANCE hInst, HANDLE hHeap) +{ + FIXME("(%p,%p) stub\n", hInst, hHeap); + return E_FAIL; /* This is what is used if shlwapi not loaded */ +} + +/************************************************************************* + * @ [SHLWAPI.431] + */ +DWORD WINAPI MLClearMLHInstance(DWORD x) +{ + FIXME("(0x%08lx)stub\n", x); + return 0xabba1247; +} + +/************************************************************************* + * @ [SHLWAPI.436] + * + * Convert an Unicode string CLSID into a CLSID. + * + * PARAMS + * idstr [I] string containing a CLSID in text form + * id [O] CLSID extracted from the string + * + * RETURNS + * S_OK on success or E_INVALIDARG on failure + * + * NOTES + * This is really CLSIDFromString() which is exported by ole32.dll, + * however the native shlwapi.dll does *not* import ole32. Nor does + * ole32.dll import this ordinal from shlwapi. Therefore we must conclude + * that MS duplicated the code for CLSIDFromString(), and yes they did, only + * it returns an E_INVALIDARG error code on failure. + * This is a duplicate (with changes for Unicode) of CLSIDFromString16() + * in "dlls/ole32/compobj.c". + */ +HRESULT WINAPI CLSIDFromStringWrap(LPCWSTR idstr, CLSID *id) +{ + LPCWSTR s = idstr; + BYTE *p; + INT i; + WCHAR table[256]; + + if (!s) { + memset(id, 0, sizeof(CLSID)); + return S_OK; + } + else { /* validate the CLSID string */ + + if (strlenW(s) != 38) + return E_INVALIDARG; + + if ((s[0]!=L'{') || (s[9]!=L'-') || (s[14]!=L'-') || (s[19]!=L'-') || (s[24]!=L'-') || (s[37]!=L'}')) + return E_INVALIDARG; + + for (i=1; i<37; i++) + { + if ((i == 9)||(i == 14)||(i == 19)||(i == 24)) + continue; + if (!(((s[i] >= L'0') && (s[i] <= L'9')) || + ((s[i] >= L'a') && (s[i] <= L'f')) || + ((s[i] >= L'A') && (s[i] <= L'F'))) + ) + return E_INVALIDARG; + } + } + + TRACE("%s -> %p\n", debugstr_w(s), id); + + /* quick lookup table */ + memset(table, 0, 256*sizeof(WCHAR)); + + 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} */ + + p = (BYTE *) id; + + s++; /* skip leading brace */ + for (i = 0; i < 4; i++) { + p[3 - i] = table[*s]<<4 | table[*(s+1)]; + s += 2; + } + p += 4; + s++; /* skip - */ + + for (i = 0; i < 2; i++) { + p[1-i] = table[*s]<<4 | table[*(s+1)]; + s += 2; + } + p += 2; + s++; /* skip - */ + + for (i = 0; i < 2; i++) { + p[1-i] = table[*s]<<4 | table[*(s+1)]; + s += 2; + } + p += 2; + s++; /* skip - */ + + /* these are just sequential bytes */ + for (i = 0; i < 2; i++) { + *p++ = table[*s]<<4 | table[*(s+1)]; + s += 2; + } + s++; /* skip - */ + + for (i = 0; i < 6; i++) { + *p++ = table[*s]<<4 | table[*(s+1)]; + s += 2; + } + + return S_OK; +} + +/************************************************************************* + * @ [SHLWAPI.437] + * + * Determine if the OS supports a given feature. + * + * PARAMS + * dwFeature [I] Feature requested (undocumented) + * + * RETURNS + * TRUE If the feature is available. + * FALSE If the feature is not available. + */ +BOOL WINAPI IsOS(DWORD feature) +{ + OSVERSIONINFOA osvi; + DWORD platform, majorv, minorv; + + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); + if(!GetVersionExA(&osvi)) { + ERR("GetVersionEx failed"); + return FALSE; + } + + majorv = osvi.dwMajorVersion; + minorv = osvi.dwMinorVersion; + platform = osvi.dwPlatformId; + +#define ISOS_RETURN(x) \ + TRACE("(0x%lx) ret=%d\n",feature,(x)); \ + return (x); + + switch(feature) { + case OS_WIN32SORGREATER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32s + || platform == VER_PLATFORM_WIN32_WINDOWS) + case OS_NT: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT) + case OS_WIN95ORGREATER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS) + case OS_NT4ORGREATER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 4) + case OS_WIN2000ORGREATER_ALT: + case OS_WIN2000ORGREATER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5) + case OS_WIN98ORGREATER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 10) + case OS_WIN98_GOLD: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 10) + case OS_WIN2000PRO: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5) + case OS_WIN2000SERVER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1)) + case OS_WIN2000ADVSERVER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1)) + case OS_WIN2000DATACENTER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1)) + case OS_WIN2000TERMINAL: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && (minorv == 0 || minorv == 1)) + case OS_EMBEDDED: + FIXME("(OS_EMBEDDED) What should we return here?\n"); + return FALSE; + case OS_TERMINALCLIENT: + FIXME("(OS_TERMINALCLIENT) What should we return here?\n"); + return FALSE; + case OS_TERMINALREMOTEADMIN: + FIXME("(OS_TERMINALREMOTEADMIN) What should we return here?\n"); + return FALSE; + case OS_WIN95_GOLD: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv == 0) + case OS_MEORGREATER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_WINDOWS && minorv >= 90) + case OS_XPORGREATER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1) + case OS_HOME: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5 && minorv >= 1) + case OS_PROFESSIONAL: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT) + case OS_DATACENTER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT) + case OS_ADVSERVER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && majorv >= 5) + case OS_SERVER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT) + case OS_TERMINALSERVER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT) + case OS_PERSONALTERMINALSERVER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT && minorv >= 1 && majorv >= 5) + case OS_FASTUSERSWITCHING: + FIXME("(OS_FASTUSERSWITCHING) What should we return here?\n"); + return TRUE; + case OS_WELCOMELOGONUI: + FIXME("(OS_WELCOMELOGONUI) What should we return here?\n"); + return FALSE; + case OS_DOMAINMEMBER: + FIXME("(OS_DOMAINMEMBER) What should we return here?\n"); + return TRUE; + case OS_ANYSERVER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT) + case OS_WOW6432: + FIXME("(OS_WOW6432) Should we check this?\n"); + return FALSE; + case OS_WEBSERVER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT) + case OS_SMALLBUSINESSSERVER: + ISOS_RETURN(platform == VER_PLATFORM_WIN32_NT) + case OS_TABLETPC: + FIXME("(OS_TABLEPC) What should we return here?\n"); + return FALSE; + case OS_SERVERADMINUI: + FIXME("(OS_SERVERADMINUI) What should we return here?\n"); + return FALSE; + case OS_MEDIACENTER: + FIXME("(OS_MEDIACENTER) What should we return here?\n"); + return FALSE; + case OS_APPLIANCE: + FIXME("(OS_APPLIANCE) What should we return here?\n"); + return FALSE; + } + +#undef ISOS_RETURN + + WARN("(0x%lx) unknown parameter\n",feature); + + return FALSE; +} + +/************************************************************************* + * @ [SHLWAPI.478] + * + * Call IInputObject_TranslateAcceleratorIO() on an object. + * + * PARAMS + * lpUnknown [I] Object supporting the IInputObject interface. + * lpMsg [I] Key message to be processed. + * + * RETURNS + * Success: S_OK. + * Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL. + */ +HRESULT WINAPI IUnknown_TranslateAcceleratorIO(IUnknown *lpUnknown, LPMSG lpMsg) +{ + IInputObject* lpInput = NULL; + HRESULT hRet = E_INVALIDARG; + + TRACE("(%p,%p)\n", lpUnknown, lpMsg); + if (lpUnknown) + { + hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInputObject, + (void**)&lpInput); + if (SUCCEEDED(hRet) && lpInput) + { + hRet = IInputObject_TranslateAcceleratorIO(lpInput, lpMsg); + IInputObject_Release(lpInput); + } + } + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.481] + * + * Call IInputObject_HasFocusIO() on an object. + * + * PARAMS + * lpUnknown [I] Object supporting the IInputObject interface. + * + * RETURNS + * Success: S_OK, if lpUnknown is an IInputObject object and has the focus, + * or S_FALSE otherwise. + * Failure: An HRESULT error code, or E_INVALIDARG if lpUnknown is NULL. + */ +HRESULT WINAPI IUnknown_HasFocusIO(IUnknown *lpUnknown) +{ + IInputObject* lpInput = NULL; + HRESULT hRet = E_INVALIDARG; + + TRACE("(%p)\n", lpUnknown); + if (lpUnknown) + { + hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInputObject, + (void**)&lpInput); + if (SUCCEEDED(hRet) && lpInput) + { + hRet = IInputObject_HasFocusIO(lpInput); + IInputObject_Release(lpInput); + } + } + return hRet; +} + +/************************************************************************* + * ColorRGBToHLS [SHLWAPI.@] + * + * Convert an rgb COLORREF into the hls color space. + * + * PARAMS + * cRGB [I] Source rgb value + * pwHue [O] Destination for converted hue + * pwLuminance [O] Destination for converted luminance + * pwSaturation [O] Destination for converted saturation + * + * RETURNS + * Nothing. pwHue, pwLuminance and pwSaturation are set to the converted + * values. + * + * NOTES + * Output HLS values are constrained to the range (0..240). + * For Achromatic conversions, Hue is set to 160. + */ +VOID WINAPI ColorRGBToHLS(COLORREF cRGB, LPWORD pwHue, + LPWORD pwLuminance, LPWORD pwSaturation) +{ + int wR, wG, wB, wMax, wMin, wHue, wLuminosity, wSaturation; + + TRACE("(%08lx,%p,%p,%p)\n", cRGB, pwHue, pwLuminance, pwSaturation); + + wR = GetRValue(cRGB); + wG = GetGValue(cRGB); + wB = GetBValue(cRGB); + + wMax = max(wR, max(wG, wB)); + wMin = min(wR, min(wG, wB)); + + /* Luminosity */ + wLuminosity = ((wMax + wMin) * 240 + 255) / 510; + + if (wMax == wMin) + { + /* Achromatic case */ + wSaturation = 0; + /* Hue is now unrepresentable, but this is what native returns... */ + wHue = 160; + } + else + { + /* Chromatic case */ + int wDelta = wMax - wMin, wRNorm, wGNorm, wBNorm; + + /* Saturation */ + if (wLuminosity <= 120) + wSaturation = ((wMax + wMin)/2 + wDelta * 240) / (wMax + wMin); + else + wSaturation = ((510 - wMax - wMin)/2 + wDelta * 240) / (510 - wMax - wMin); + + /* Hue */ + wRNorm = (wDelta/2 + wMax * 40 - wR * 40) / wDelta; + wGNorm = (wDelta/2 + wMax * 40 - wG * 40) / wDelta; + wBNorm = (wDelta/2 + wMax * 40 - wB * 40) / wDelta; + + if (wR == wMax) + wHue = wBNorm - wGNorm; + else if (wG == wMax) + wHue = 80 + wRNorm - wBNorm; + else + wHue = 160 + wGNorm - wRNorm; + if (wHue < 0) + wHue += 240; + else if (wHue > 240) + wHue -= 240; + } + if (pwHue) + *pwHue = wHue; + if (pwLuminance) + *pwLuminance = wLuminosity; + if (pwSaturation) + *pwSaturation = wSaturation; +} + +/************************************************************************* + * SHCreateShellPalette [SHLWAPI.@] + */ +HPALETTE WINAPI SHCreateShellPalette(HDC hdc) +{ + FIXME("stub\n"); + return CreateHalftonePalette(hdc); +} + +/************************************************************************* + * SHGetInverseCMAP (SHLWAPI.@) + * + * Get an inverse color map table. + * + * PARAMS + * lpCmap [O] Destination for color map + * dwSize [I] Size of memory pointed to by lpCmap + * + * RETURNS + * Success: S_OK. + * Failure: E_POINTER, If lpCmap is invalid. + * E_INVALIDARG, If dwFlags is invalid + * E_OUTOFMEMORY, If there is no memory available + * + * NOTES + * dwSize may only be CMAP_PTR_SIZE (4) or CMAP_SIZE (8192). + * If dwSize = CMAP_PTR_SIZE, *lpCmap is set to the address of this DLL's + * internal CMap. + * If dwSize = CMAP_SIZE, lpCmap is filled with a copy of the data from + * this DLL's internal CMap. + */ +HRESULT WINAPI SHGetInverseCMAP(LPDWORD dest, DWORD dwSize) +{ + if (dwSize == 4) { + FIXME(" - returning bogus address for SHGetInverseCMAP\n"); + *dest = (DWORD)0xabba1249; + return 0; + } + FIXME("(%p, %#lx) stub\n", dest, dwSize); + return 0; +} + +/************************************************************************* + * SHIsLowMemoryMachine [SHLWAPI.@] + * + * Determine if the current computer has low memory. + * + * PARAMS + * x [I] FIXME + * + * RETURNS + * TRUE if the users machine has 16 Megabytes of memory or less, + * FALSE otherwise. + */ +BOOL WINAPI SHIsLowMemoryMachine (DWORD x) +{ + FIXME("(0x%08lx) stub\n", x); + return FALSE; +} + +/************************************************************************* + * GetMenuPosFromID [SHLWAPI.@] + * + * Return the position of a menu item from its Id. + * + * PARAMS + * hMenu [I] Menu containing the item + * wID [I] Id of the menu item + * + * RETURNS + * Success: The index of the menu item in hMenu. + * Failure: -1, If the item is not found. + */ +INT WINAPI GetMenuPosFromID(HMENU hMenu, UINT wID) +{ + MENUITEMINFOA mi; + INT nCount = GetMenuItemCount(hMenu), nIter = 0; + + while (nIter < nCount) + { + mi.wID = 0; + if (!GetMenuItemInfoA(hMenu, nIter, TRUE, &mi) && mi.wID == wID) + return nIter; + nIter++; + } + return -1; +} + +/************************************************************************* + * @ [SHLWAPI.179] + * + * Same as SHLWAPI.GetMenuPosFromID + */ +DWORD WINAPI SHMenuIndexFromID(HMENU hMenu, UINT uID) +{ + return GetMenuPosFromID(hMenu, uID); +} + + +/************************************************************************* + * @ [SHLWAPI.448] + */ +VOID WINAPI FixSlashesAndColonW(LPWSTR lpwstr) +{ + while (*lpwstr) + { + if (*lpwstr == '/') + *lpwstr = '\\'; + lpwstr++; + } +} + + +/************************************************************************* + * @ [SHLWAPI.461] + */ +DWORD WINAPI SHGetAppCompatFlags(DWORD dwUnknown) +{ + FIXME("(0x%08lx) stub\n", dwUnknown); + return 0; +} + + +/************************************************************************* + * @ [SHLWAPI.549] + */ +HRESULT WINAPI SHCoCreateInstanceAC(REFCLSID rclsid, LPUNKNOWN pUnkOuter, + DWORD dwClsContext, REFIID iid, LPVOID *ppv) +{ + return CoCreateInstance(rclsid, pUnkOuter, dwClsContext, iid, ppv); +} + +/************************************************************************* + * SHSkipJunction [SHLWAPI.@] + * + * Determine if a bind context can be bound to an object + * + * PARAMS + * pbc [I] Bind context to check + * pclsid [I] CLSID of object to be bound to + * + * RETURNS + * TRUE: If it is safe to bind + * FALSE: If pbc is invalid or binding would not be safe + * + */ +BOOL WINAPI SHSkipJunction(IBindCtx *pbc, const CLSID *pclsid) +{ + static const WCHAR szSkipBinding[] = { 'S','k','i','p',' ', + 'B','i','n','d','i','n','g',' ','C','L','S','I','D','\0' }; + BOOL bRet = FALSE; + + if (pbc) + { + IUnknown* lpUnk; + + if (SUCCEEDED(IBindCtx_GetObjectParam(pbc, (LPOLESTR)szSkipBinding, &lpUnk))) + { + CLSID clsid; + + if (SUCCEEDED(IUnknown_GetClassID(lpUnk, &clsid)) && + IsEqualGUID(pclsid, &clsid)) + bRet = TRUE; + + IUnknown_Release(lpUnk); + } + } + return bRet; +} + +/*********************************************************************** + * SHGetShellKey (SHLWAPI.@) + */ +DWORD WINAPI SHGetShellKey(DWORD a, DWORD b, DWORD c) +{ + FIXME("(%lx, %lx, %lx): stub\n", a, b, c); + return 0x50; +} + +/*********************************************************************** + * SHQueueUserWorkItem (SHLWAPI.@) + */ +HRESULT WINAPI SHQueueUserWorkItem(DWORD a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f, DWORD g) +{ + FIXME("(%lx, %lx, %lx, %lx, %lx, %lx, %lx): stub\n", a, b, c, d, e, f, g); + return E_FAIL; +} + +/*********************************************************************** + * IUnknown_OnFocusChangeIS (SHLWAPI.@) + */ +HRESULT WINAPI IUnknown_OnFocusChangeIS(LPUNKNOWN lpUnknown, LPUNKNOWN pFocusObject, BOOL bFocus) +{ + IInputObjectSite *pIOS = NULL; + HRESULT hRet = E_INVALIDARG; + + TRACE("(%p, %p, %s)\n", lpUnknown, pFocusObject, bFocus ? "TRUE" : "FALSE"); + + if (lpUnknown) + { + hRet = IUnknown_QueryInterface(lpUnknown, &IID_IInputObjectSite, + (void **)&pIOS); + if (SUCCEEDED(hRet) && pIOS) + { + hRet = IInputObjectSite_OnFocusChangeIS(pIOS, pFocusObject, bFocus); + IInputObjectSite_Release(pIOS); + } + } + return hRet; +} + +/*********************************************************************** + * SHGetValueW (SHLWAPI.@) + */ +HRESULT WINAPI SKGetValueW(DWORD a, LPWSTR b, LPWSTR c, DWORD d, DWORD e, DWORD f) +{ + FIXME("(%lx, %s, %s, %lx, %lx, %lx): stub\n", a, debugstr_w(b), debugstr_w(c), d, e, f); + return E_FAIL; +} + +typedef HRESULT (WINAPI *DllGetVersion_func)(DLLVERSIONINFO *); + +/*********************************************************************** + * GetUIVersion (SHLWAPI.452) + */ +DWORD WINAPI GetUIVersion(void) +{ + static DWORD version; + + if (!version) + { + DllGetVersion_func pDllGetVersion; + HMODULE dll = LoadLibraryA("shell32.dll"); + if (!dll) return 0; + + pDllGetVersion = (DllGetVersion_func)GetProcAddress(dll, "DllGetVersion"); + if (pDllGetVersion) + { + DLLVERSIONINFO dvi; + dvi.cbSize = sizeof(DLLVERSIONINFO); + if (pDllGetVersion(&dvi) == S_OK) version = dvi.dwMajorVersion; + } + FreeLibrary( dll ); + if (!version) version = 3; /* old shell dlls don't have DllGetVersion */ + } + return version; +} diff --git a/reactos/lib/shlwapi/path.c b/reactos/lib/shlwapi/path.c index bb1c3f21e03..1f9ac973e9d 100644 --- a/reactos/lib/shlwapi/path.c +++ b/reactos/lib/shlwapi/path.c @@ -1,4138 +1,4138 @@ -/* - * Path Functions - * - * Copyright 1999, 2000 Juergen Schmied - * Copyright 2001, 2002 Jon Griffiths - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" -#include "wine/port.h" - -#include <stdarg.h> -#include <string.h> -#include <stdlib.h> - -#include "wine/unicode.h" -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winreg.h" -#include "winternl.h" -#define NO_SHLWAPI_STREAM -#include "shlwapi.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(shell); - -/* Get a function pointer from a DLL handle */ -#define GET_FUNC(func, module, name, fail) \ - do { \ - if (!func) { \ - if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \ - func = (fn##func)GetProcAddress(SHLWAPI_h##module, name); \ - if (!func) return fail; \ - } \ - } while (0) - -/* DLL handles for late bound calls */ -extern HMODULE SHLWAPI_hshell32; - -/* Function pointers for GET_FUNC macro; these need to be global because of gcc bug */ -typedef BOOL (WINAPI *fnpIsNetDrive)(int); -static fnpIsNetDrive pIsNetDrive; - -HRESULT WINAPI SHGetWebFolderFilePathW(LPCWSTR,LPWSTR,DWORD); - -/************************************************************************* - * PathAppendA [SHLWAPI.@] - * - * Append one path to another. - * - * PARAMS - * lpszPath [I/O] Initial part of path, and destination for output - * lpszAppend [I] Path to append - * - * RETURNS - * Success: TRUE. lpszPath contains the newly created path. - * Failure: FALSE, if either path is NULL, or PathCombineA() fails. - * - * NOTES - * lpszAppend must contain at least one backslash ('\') if not NULL. - * Because PathCombineA() is used to join the paths, the resulting - * path is also canonicalized. - */ -BOOL WINAPI PathAppendA (LPSTR lpszPath, LPCSTR lpszAppend) -{ - TRACE("(%s,%s)\n",debugstr_a(lpszPath), debugstr_a(lpszAppend)); - - if (lpszPath && lpszAppend) - { - if (!PathIsUNCA(lpszAppend)) - while (*lpszAppend == '\\') - lpszAppend++; - if (PathCombineA(lpszPath, lpszPath, lpszAppend)) - return TRUE; - } - return FALSE; -} - -/************************************************************************* - * PathAppendW [SHLWAPI.@] - * - * See PathAppendA. - */ -BOOL WINAPI PathAppendW(LPWSTR lpszPath, LPCWSTR lpszAppend) -{ - TRACE("(%s,%s)\n",debugstr_w(lpszPath), debugstr_w(lpszAppend)); - - if (lpszPath && lpszAppend) - { - if (!PathIsUNCW(lpszAppend)) - while (*lpszAppend == '\\') - lpszAppend++; - if (PathCombineW(lpszPath, lpszPath, lpszAppend)) - return TRUE; - } - return FALSE; -} - -/************************************************************************* - * PathCombineA [SHLWAPI.@] - * - * Combine two paths together. - * - * PARAMS - * lpszDest [O] Destination for combined path - * lpszDir [I] Directory path - * lpszFile [I] File path - * - * RETURNS - * Success: The output path - * Failure: NULL, if inputs are invalid. - * - * NOTES - * lpszDest should be at least MAX_PATH in size, and may point to the same - * memory location as lpszDir. The combined path is canonicalised. - */ -LPSTR WINAPI PathCombineA(LPSTR lpszDest, LPCSTR lpszDir, LPCSTR lpszFile) -{ - TRACE("(%p,%s,%s)\n", lpszDest, debugstr_a(lpszDir), debugstr_a(lpszFile)); - - if (!lpszDest || (!lpszDir && !lpszFile)) - return NULL; /* Invalid parameters */ - else - { - WCHAR szDest[MAX_PATH]; - WCHAR szDir[MAX_PATH]; - WCHAR szFile[MAX_PATH]; - if (lpszDir) - MultiByteToWideChar(CP_ACP,0,lpszDir,-1,szDir,MAX_PATH); - if (lpszFile) - MultiByteToWideChar(CP_ACP,0,lpszFile,-1,szFile,MAX_PATH); - PathCombineW(szDest, lpszDir ? szDir : NULL, lpszFile ? szFile : NULL); - WideCharToMultiByte(CP_ACP,0,szDest,-1,lpszDest,MAX_PATH,0,0); - } - return lpszDest; -} - -/************************************************************************* - * PathCombineW [SHLWAPI.@] - * - * See PathCombineA. - */ -LPWSTR WINAPI PathCombineW(LPWSTR lpszDest, LPCWSTR lpszDir, LPCWSTR lpszFile) -{ - WCHAR szTemp[MAX_PATH]; - BOOL bUseBoth = FALSE, bStrip = FALSE; - - TRACE("(%p,%s,%s)\n", lpszDest, debugstr_w(lpszDir), debugstr_w(lpszFile)); - - if (!lpszDest || (!lpszDir && !lpszFile)) - return lpszDest; /* Invalid parameters */ - - if (!lpszFile || !*lpszFile) - { - /* Use dir only */ - lstrcpynW(szTemp, lpszDir, MAX_PATH); - } - else if (!lpszDir || !*lpszDir || !PathIsRelativeW(lpszFile)) - { - if (!lpszDir || !*lpszDir || *lpszFile != '\\' || PathIsUNCW(lpszFile)) - { - /* Use file only */ - lstrcpynW(szTemp, lpszFile, MAX_PATH); - } - else - { - bUseBoth = TRUE; - bStrip = TRUE; - } - } - else - bUseBoth = TRUE; - - if (bUseBoth) - { - lstrcpynW(szTemp, lpszDir, MAX_PATH); - if (bStrip) - { - PathStripToRootW(szTemp); - lpszFile++; /* Skip '\' */ - } - if (!PathAddBackslashW(szTemp)) - return NULL; - if (strlenW(szTemp) + strlenW(lpszFile) >= MAX_PATH) - return NULL; - strcatW(szTemp, lpszFile); - } - - PathCanonicalizeW(lpszDest, szTemp); - return lpszDest; -} - -/************************************************************************* - * PathAddBackslashA [SHLWAPI.@] - * - * Append a backslash ('\') to a path if one doesn't exist. - * - * PARAMS - * lpszPath [I/O] The path to append a backslash to. - * - * RETURNS - * Success: The position of the last backslash in the path. - * Failure: NULL, if lpszPath is NULL or the path is too large. - */ -LPSTR WINAPI PathAddBackslashA(LPSTR lpszPath) -{ - size_t iLen; - - TRACE("(%s)\n",debugstr_a(lpszPath)); - - if (!lpszPath || (iLen = strlen(lpszPath)) >= MAX_PATH) - return NULL; - - if (iLen) - { - lpszPath += iLen; - if (lpszPath[-1] != '\\') - { - *lpszPath++ = '\\'; - *lpszPath = '\0'; - } - } - return lpszPath; -} - -/************************************************************************* - * PathAddBackslashW [SHLWAPI.@] - * - * See PathAddBackslashA. - */ -LPWSTR WINAPI PathAddBackslashW( LPWSTR lpszPath ) -{ - size_t iLen; - - TRACE("(%s)\n",debugstr_w(lpszPath)); - - if (!lpszPath || (iLen = strlenW(lpszPath)) >= MAX_PATH) - return NULL; - - if (iLen) - { - lpszPath += iLen; - if (lpszPath[-1] != '\\') - { - *lpszPath++ = '\\'; - *lpszPath = '\0'; - } - } - return lpszPath; -} - -/************************************************************************* - * PathBuildRootA [SHLWAPI.@] - * - * Create a root drive string (e.g. "A:\") from a drive number. - * - * PARAMS - * lpszPath [O] Destination for the drive string - * - * RETURNS - * lpszPath - * - * NOTES - * If lpszPath is NULL or drive is invalid, nothing is written to lpszPath. - */ -LPSTR WINAPI PathBuildRootA(LPSTR lpszPath, int drive) -{ - TRACE("(%p,%d)\n", lpszPath, drive); - - if (lpszPath && drive >= 0 && drive < 26) - { - lpszPath[0] = 'A' + drive; - lpszPath[1] = ':'; - lpszPath[2] = '\\'; - lpszPath[3] = '\0'; - } - return lpszPath; -} - -/************************************************************************* - * PathBuildRootW [SHLWAPI.@] - * - * See PathBuildRootA. - */ -LPWSTR WINAPI PathBuildRootW(LPWSTR lpszPath, int drive) -{ - TRACE("(%p,%d)\n", lpszPath, drive); - - if (lpszPath && drive >= 0 && drive < 26) - { - lpszPath[0] = 'A' + drive; - lpszPath[1] = ':'; - lpszPath[2] = '\\'; - lpszPath[3] = '\0'; - } - return lpszPath; -} - -/************************************************************************* - * PathFindFileNameA [SHLWAPI.@] - * - * Locate the start of the file name in a path - * - * PARAMS - * lpszPath [I] Path to search - * - * RETURNS - * A pointer to the first character of the file name - */ -LPSTR WINAPI PathFindFileNameA(LPCSTR lpszPath) -{ - LPCSTR lastSlash = lpszPath; - - TRACE("(%s)\n",debugstr_a(lpszPath)); - - while (lpszPath && *lpszPath) - { - if ((*lpszPath == '\\' || *lpszPath == '/' || *lpszPath == ':') && - lpszPath[1] && lpszPath[1] != '\\' && lpszPath[1] != '/') - lastSlash = lpszPath + 1; - lpszPath = CharNextA(lpszPath); - } - return (LPSTR)lastSlash; -} - -/************************************************************************* - * PathFindFileNameW [SHLWAPI.@] - * - * See PathFindFileNameA. - */ -LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath) -{ - LPCWSTR lastSlash = lpszPath; - - TRACE("(%s)\n",debugstr_w(lpszPath)); - - while (lpszPath && *lpszPath) - { - if ((*lpszPath == '\\' || *lpszPath == '/' || *lpszPath == ':') && - lpszPath[1] && lpszPath[1] != '\\' && lpszPath[1] != '/') - lastSlash = lpszPath + 1; - lpszPath = CharNextW(lpszPath); - } - return (LPWSTR)lastSlash; -} - -/************************************************************************* - * PathFindExtensionA [SHLWAPI.@] - * - * Locate the start of the file extension in a path - * - * PARAMS - * lpszPath [I] The path to search - * - * RETURNS - * A pointer to the first character of the extension, the end of - * the string if the path has no extension, or NULL If lpszPath is NULL - */ -LPSTR WINAPI PathFindExtensionA( LPCSTR lpszPath ) -{ - LPCSTR lastpoint = NULL; - - TRACE("(%s)\n", debugstr_a(lpszPath)); - - if (lpszPath) - { - while (*lpszPath) - { - if (*lpszPath == '\\' || *lpszPath==' ') - lastpoint = NULL; - else if (*lpszPath == '.') - lastpoint = lpszPath; - lpszPath = CharNextA(lpszPath); - } - } - return (LPSTR)(lastpoint ? lastpoint : lpszPath); -} - -/************************************************************************* - * PathFindExtensionW [SHLWAPI.@] - * - * See PathFindExtensionA. - */ -LPWSTR WINAPI PathFindExtensionW( LPCWSTR lpszPath ) -{ - LPCWSTR lastpoint = NULL; - - TRACE("(%s)\n", debugstr_w(lpszPath)); - - if (lpszPath) - { - while (*lpszPath) - { - if (*lpszPath == '\\' || *lpszPath==' ') - lastpoint = NULL; - else if (*lpszPath == '.') - lastpoint = lpszPath; - lpszPath = CharNextW(lpszPath); - } - } - return (LPWSTR)(lastpoint ? lastpoint : lpszPath); -} - -/************************************************************************* - * PathGetArgsA [SHLWAPI.@] - * - * Find the next argument in a string delimited by spaces. - * - * PARAMS - * lpszPath [I] The string to search for arguments in - * - * RETURNS - * The start of the next argument in lpszPath, or NULL if lpszPath is NULL - * - * NOTES - * Spaces in quoted strings are ignored as delimiters. - */ -LPSTR WINAPI PathGetArgsA(LPCSTR lpszPath) -{ - BOOL bSeenQuote = FALSE; - - TRACE("(%s)\n",debugstr_a(lpszPath)); - - if (lpszPath) - { - while (*lpszPath) - { - if ((*lpszPath==' ') && !bSeenQuote) - return (LPSTR)lpszPath + 1; - if (*lpszPath == '"') - bSeenQuote = !bSeenQuote; - lpszPath = CharNextA(lpszPath); - } - } - return (LPSTR)lpszPath; -} - -/************************************************************************* - * PathGetArgsW [SHLWAPI.@] - * - * See PathGetArgsA. - */ -LPWSTR WINAPI PathGetArgsW(LPCWSTR lpszPath) -{ - BOOL bSeenQuote = FALSE; - - TRACE("(%s)\n",debugstr_w(lpszPath)); - - if (lpszPath) - { - while (*lpszPath) - { - if ((*lpszPath==' ') && !bSeenQuote) - return (LPWSTR)lpszPath + 1; - if (*lpszPath == '"') - bSeenQuote = !bSeenQuote; - lpszPath = CharNextW(lpszPath); - } - } - return (LPWSTR)lpszPath; -} - -/************************************************************************* - * PathGetDriveNumberA [SHLWAPI.@] - * - * Return the drive number from a path - * - * PARAMS - * lpszPath [I] Path to get the drive number from - * - * RETURNS - * Success: The drive number corresponding to the drive in the path - * Failure: -1, if lpszPath contains no valid drive - */ -int WINAPI PathGetDriveNumberA(LPCSTR lpszPath) -{ - TRACE ("(%s)\n",debugstr_a(lpszPath)); - - if (lpszPath && !IsDBCSLeadByte(*lpszPath) && lpszPath[1] == ':' && - tolower(*lpszPath) >= 'a' && tolower(*lpszPath) <= 'z') - return tolower(*lpszPath) - 'a'; - return -1; -} - -/************************************************************************* - * PathGetDriveNumberW [SHLWAPI.@] - * - * See PathGetDriveNumberA. - */ -int WINAPI PathGetDriveNumberW(LPCWSTR lpszPath) -{ - TRACE ("(%s)\n",debugstr_w(lpszPath)); - - if (lpszPath && lpszPath[1] == ':' && - tolowerW(*lpszPath) >= 'a' && tolowerW(*lpszPath) <= 'z') - return tolowerW(*lpszPath) - 'a'; - return -1; -} - -/************************************************************************* - * PathRemoveFileSpecA [SHLWAPI.@] - * - * Remove the file specification from a path. - * - * PARAMS - * lpszPath [I/O] Path to remove the file spec from - * - * RETURNS - * TRUE If the path was valid and modified - * FALSE Otherwise - */ -BOOL WINAPI PathRemoveFileSpecA(LPSTR lpszPath) -{ - LPSTR lpszFileSpec = lpszPath; - BOOL bModified = FALSE; - - TRACE("(%s)\n",debugstr_a(lpszPath)); - - if(lpszPath) - { - /* Skip directory or UNC path */ - if (*lpszPath == '\\') - lpszFileSpec = ++lpszPath; - if (*lpszPath == '\\') - lpszFileSpec = ++lpszPath; - - while (*lpszPath) - { - if(*lpszPath == '\\') - lpszFileSpec = lpszPath; /* Skip dir */ - else if(*lpszPath == ':') - { - lpszFileSpec = ++lpszPath; /* Skip drive */ - if (*lpszPath == '\\') - lpszFileSpec++; - } - if (!(lpszPath = CharNextA(lpszPath))) - break; - } - - if (*lpszFileSpec) - { - *lpszFileSpec = '\0'; - bModified = TRUE; - } - } - return bModified; -} - -/************************************************************************* - * PathRemoveFileSpecW [SHLWAPI.@] - * - * See PathRemoveFileSpecA. - */ -BOOL WINAPI PathRemoveFileSpecW(LPWSTR lpszPath) -{ - LPWSTR lpszFileSpec = lpszPath; - BOOL bModified = FALSE; - - TRACE("(%s)\n",debugstr_w(lpszPath)); - - if(lpszPath) - { - /* Skip directory or UNC path */ - if (*lpszPath == '\\') - lpszFileSpec = ++lpszPath; - if (*lpszPath == '\\') - lpszFileSpec = ++lpszPath; - - while (*lpszPath) - { - if(*lpszPath == '\\') - lpszFileSpec = lpszPath; /* Skip dir */ - else if(*lpszPath == ':') - { - lpszFileSpec = ++lpszPath; /* Skip drive */ - if (*lpszPath == '\\') - lpszFileSpec++; - } - if (!(lpszPath = CharNextW(lpszPath))) - break; - } - - if (*lpszFileSpec) - { - *lpszFileSpec = '\0'; - bModified = TRUE; - } - } - return bModified; -} - -/************************************************************************* - * PathStripPathA [SHLWAPI.@] - * - * Remove the initial path from the beginning of a filename - * - * PARAMS - * lpszPath [I/O] Path to remove the initial path from - * - * RETURNS - * Nothing. - */ -void WINAPI PathStripPathA(LPSTR lpszPath) -{ - TRACE("(%s)\n", debugstr_a(lpszPath)); - - if (lpszPath) - { - LPSTR lpszFileName = PathFindFileNameA(lpszPath); - if(lpszFileName) - RtlMoveMemory(lpszPath, lpszFileName, strlen(lpszFileName)+1); - } -} - -/************************************************************************* - * PathStripPathW [SHLWAPI.@] - * - * See PathStripPathA. - */ -void WINAPI PathStripPathW(LPWSTR lpszPath) -{ - LPWSTR lpszFileName; - - TRACE("(%s)\n", debugstr_w(lpszPath)); - lpszFileName = PathFindFileNameW(lpszPath); - if(lpszFileName) - RtlMoveMemory(lpszPath, lpszFileName, (strlenW(lpszFileName)+1)*sizeof(WCHAR)); -} - -/************************************************************************* - * PathStripToRootA [SHLWAPI.@] - * - * Reduce a path to its root. - * - * PARAMS - * lpszPath [I/O] the path to reduce - * - * RETURNS - * Success: TRUE if the stripped path is a root path - * Failure: FALSE if the path cannot be stripped or is NULL - */ -BOOL WINAPI PathStripToRootA(LPSTR lpszPath) -{ - TRACE("(%s)\n", debugstr_a(lpszPath)); - - if (!lpszPath) - return FALSE; - while(!PathIsRootA(lpszPath)) - if (!PathRemoveFileSpecA(lpszPath)) - return FALSE; - return TRUE; -} - -/************************************************************************* - * PathStripToRootW [SHLWAPI.@] - * - * See PathStripToRootA. - */ -BOOL WINAPI PathStripToRootW(LPWSTR lpszPath) -{ - TRACE("(%s)\n", debugstr_w(lpszPath)); - - if (!lpszPath) - return FALSE; - while(!PathIsRootW(lpszPath)) - if (!PathRemoveFileSpecW(lpszPath)) - return FALSE; - return TRUE; -} - -/************************************************************************* - * PathRemoveArgsA [SHLWAPI.@] - * - * Strip space separated arguments from a path. - * - * PARAMS - * lpszPath [I/O] Path to remove arguments from - * - * RETURNS - * Nothing. - */ -void WINAPI PathRemoveArgsA(LPSTR lpszPath) -{ - TRACE("(%s)\n",debugstr_a(lpszPath)); - - if(lpszPath) - { - LPSTR lpszArgs = PathGetArgsA(lpszPath); - if (*lpszArgs) - lpszArgs[-1] = '\0'; - else - { - LPSTR lpszLastChar = CharPrevA(lpszPath, lpszArgs); - if(*lpszLastChar == ' ') - *lpszLastChar = '\0'; - } - } -} - -/************************************************************************* - * PathRemoveArgsW [SHLWAPI.@] - * - * See PathRemoveArgsA. - */ -void WINAPI PathRemoveArgsW(LPWSTR lpszPath) -{ - TRACE("(%s)\n",debugstr_w(lpszPath)); - - if(lpszPath) - { - LPWSTR lpszArgs = PathGetArgsW(lpszPath); - if (*lpszArgs) - lpszArgs[-1] = '\0'; - else - { - LPWSTR lpszLastChar = CharPrevW(lpszPath, lpszArgs); - if(*lpszLastChar == ' ') - *lpszLastChar = '\0'; - } - } -} - -/************************************************************************* - * PathRemoveExtensionA [SHLWAPI.@] - * - * Remove the file extension from a path - * - * PARAMS - * lpszPath [I/O] Path to remove the extension from - * - * RETURNS - * Nothing. - */ -void WINAPI PathRemoveExtensionA(LPSTR lpszPath) -{ - TRACE("(%s)\n", debugstr_a(lpszPath)); - - if (lpszPath) - { - lpszPath = PathFindExtensionA(lpszPath); - *lpszPath = '\0'; - } -} - -/************************************************************************* - * PathRemoveExtensionW [SHLWAPI.@] - * - * See PathRemoveExtensionA. -*/ -void WINAPI PathRemoveExtensionW(LPWSTR lpszPath) -{ - TRACE("(%s)\n", debugstr_w(lpszPath)); - - if (lpszPath) - { - lpszPath = PathFindExtensionW(lpszPath); - *lpszPath = '\0'; - } -} - -/************************************************************************* - * PathRemoveBackslashA [SHLWAPI.@] - * - * Remove a trailing backslash from a path. - * - * PARAMS - * lpszPath [I/O] Path to remove backslash from - * - * RETURNS - * Success: A pointer to the end of the path - * Failure: NULL, if lpszPath is NULL - */ -LPSTR WINAPI PathRemoveBackslashA( LPSTR lpszPath ) -{ - LPSTR szTemp = NULL; - - TRACE("(%s)\n", debugstr_a(lpszPath)); - - if(lpszPath) - { - szTemp = CharPrevA(lpszPath, lpszPath + strlen(lpszPath)); - if (!PathIsRootA(lpszPath) && *szTemp == '\\') - *szTemp = '\0'; - } - return szTemp; -} - -/************************************************************************* - * PathRemoveBackslashW [SHLWAPI.@] - * - * See PathRemoveBackslashA. - */ -LPWSTR WINAPI PathRemoveBackslashW( LPWSTR lpszPath ) -{ - LPWSTR szTemp = NULL; - - TRACE("(%s)\n", debugstr_w(lpszPath)); - - if(lpszPath) - { - szTemp = CharPrevW(lpszPath, lpszPath + strlenW(lpszPath)); - if (!PathIsRootW(lpszPath) && *szTemp == '\\') - *szTemp = '\0'; - } - return szTemp; -} - -/************************************************************************* - * PathRemoveBlanksA [SHLWAPI.@] - * - * Remove Spaces from the start and end of a path. - * - * PARAMS - * lpszPath [I/O] Path to strip blanks from - * - * RETURNS - * Nothing. - */ -VOID WINAPI PathRemoveBlanksA(LPSTR lpszPath) -{ - TRACE("(%s)\n", debugstr_a(lpszPath)); - - if(lpszPath && *lpszPath) - { - LPSTR start = lpszPath; - - while (*lpszPath == ' ') - lpszPath = CharNextA(lpszPath); - - while(*lpszPath) - *start++ = *lpszPath++; - - if (start != lpszPath) - while (start[-1] == ' ') - start--; - *start = '\0'; - } -} - -/************************************************************************* - * PathRemoveBlanksW [SHLWAPI.@] - * - * See PathRemoveBlanksA. - */ -VOID WINAPI PathRemoveBlanksW(LPWSTR lpszPath) -{ - TRACE("(%s)\n", debugstr_w(lpszPath)); - - if(lpszPath && *lpszPath) - { - LPWSTR start = lpszPath; - - while (*lpszPath == ' ') - lpszPath++; - - while(*lpszPath) - *start++ = *lpszPath++; - - if (start != lpszPath) - while (start[-1] == ' ') - start--; - *start = '\0'; - } -} - -/************************************************************************* - * PathQuoteSpacesA [SHLWAPI.@] - * - * Surround a path containg spaces in quotes. - * - * PARAMS - * lpszPath [I/O] Path to quote - * - * RETURNS - * Nothing. - * - * NOTES - * The path is not changed if it is invalid or has no spaces. - */ -VOID WINAPI PathQuoteSpacesA(LPSTR lpszPath) -{ - TRACE("(%s)\n", debugstr_a(lpszPath)); - - if(lpszPath && StrChrA(lpszPath,' ')) - { - size_t iLen = strlen(lpszPath) + 1; - - if (iLen + 2 < MAX_PATH) - { - memmove(lpszPath + 1, lpszPath, iLen); - lpszPath[0] = '"'; - lpszPath[iLen] = '"'; - lpszPath[iLen + 1] = '\0'; - } - } -} - -/************************************************************************* - * PathQuoteSpacesW [SHLWAPI.@] - * - * See PathQuoteSpacesA. - */ -VOID WINAPI PathQuoteSpacesW(LPWSTR lpszPath) -{ - TRACE("(%s)\n", debugstr_w(lpszPath)); - - if(lpszPath && StrChrW(lpszPath,' ')) - { - int iLen = strlenW(lpszPath) + 1; - - if (iLen + 2 < MAX_PATH) - { - memmove(lpszPath + 1, lpszPath, iLen * sizeof(WCHAR)); - lpszPath[0] = '"'; - lpszPath[iLen] = '"'; - lpszPath[iLen + 1] = '\0'; - } - } -} - -/************************************************************************* - * PathUnquoteSpacesA [SHLWAPI.@] - * - * Remove quotes ("") from around a path, if present. - * - * PARAMS - * lpszPath [I/O] Path to strip quotes from - * - * RETURNS - * Nothing - * - * NOTES - * If the path contains a single quote only, an empty string will result. - * Otherwise quotes are only removed if they appear at the start and end - * of the path. - */ -VOID WINAPI PathUnquoteSpacesA(LPSTR lpszPath) -{ - TRACE("(%s)\n", debugstr_a(lpszPath)); - - if (lpszPath && *lpszPath == '"') - { - DWORD dwLen = strlen(lpszPath) - 1; - - if (lpszPath[dwLen] == '"') - { - lpszPath[dwLen] = '\0'; - for (; *lpszPath; lpszPath++) - *lpszPath = lpszPath[1]; - } - } -} - -/************************************************************************* - * PathUnquoteSpacesW [SHLWAPI.@] - * - * See PathUnquoteSpacesA. - */ -VOID WINAPI PathUnquoteSpacesW(LPWSTR lpszPath) -{ - TRACE("(%s)\n", debugstr_w(lpszPath)); - - if (lpszPath && *lpszPath == '"') - { - DWORD dwLen = strlenW(lpszPath) - 1; - - if (lpszPath[dwLen] == '"') - { - lpszPath[dwLen] = '\0'; - for (; *lpszPath; lpszPath++) - *lpszPath = lpszPath[1]; - } - } -} - -/************************************************************************* - * PathParseIconLocationA [SHLWAPI.@] - * - * Parse the location of an icon from a path. - * - * PARAMS - * lpszPath [I/O] The path to parse the icon location from. - * - * RETURNS - * Success: The number of the icon - * Failure: 0 if the path does not contain an icon location or is NULL - * - * NOTES - * The path has surrounding quotes and spaces removed regardless - * of whether the call succeeds or not. - */ -int WINAPI PathParseIconLocationA(LPSTR lpszPath) -{ - int iRet = 0; - LPSTR lpszComma; - - TRACE("(%s)\n", debugstr_a(lpszPath)); - - if (lpszPath) - { - if ((lpszComma = strchr(lpszPath, ','))) - { - *lpszComma++ = '\0'; - iRet = StrToIntA(lpszComma); - } - PathUnquoteSpacesA(lpszPath); - PathRemoveBlanksA(lpszPath); - } - return iRet; -} - -/************************************************************************* - * PathParseIconLocationW [SHLWAPI.@] - * - * See PathParseIconLocationA. - */ -int WINAPI PathParseIconLocationW(LPWSTR lpszPath) -{ - int iRet = 0; - LPWSTR lpszComma; - - TRACE("(%s)\n", debugstr_w(lpszPath)); - - if (lpszPath) - { - if ((lpszComma = StrChrW(lpszPath, ','))) - { - *lpszComma++ = '\0'; - iRet = StrToIntW(lpszComma); - } - PathUnquoteSpacesW(lpszPath); - PathRemoveBlanksW(lpszPath); - } - return iRet; -} - -/************************************************************************* - * @ [SHLWAPI.4] - * - * Unicode version of PathFileExistsDefExtA. - */ -BOOL WINAPI PathFileExistsDefExtW(LPWSTR lpszPath,DWORD dwWhich) -{ - static const WCHAR pszExts[7][5] = { { '.', 'p', 'i', 'f', 0}, - { '.', 'c', 'o', 'm', 0}, - { '.', 'e', 'x', 'e', 0}, - { '.', 'b', 'a', 't', 0}, - { '.', 'l', 'n', 'k', 0}, - { '.', 'c', 'm', 'd', 0}, - { 0, 0, 0, 0, 0} }; - - TRACE("(%s,%ld)\n", debugstr_w(lpszPath), dwWhich); - - if (!lpszPath || PathIsUNCServerW(lpszPath) || PathIsUNCServerShareW(lpszPath)) - return FALSE; - - if (dwWhich) - { - LPCWSTR szExt = PathFindExtensionW(lpszPath); - if (!*szExt || dwWhich & 0x40) - { - size_t iChoose = 0; - int iLen = lstrlenW(lpszPath); - if (iLen > (MAX_PATH - 5)) - return FALSE; - while ( (dwWhich & 0x1) && pszExts[iChoose][0] ) - { - lstrcpyW(lpszPath + iLen, pszExts[iChoose]); - if (PathFileExistsW(lpszPath)) - return TRUE; - iChoose++; - dwWhich >>= 1; - } - *(lpszPath + iLen) = (WCHAR)'\0'; - return FALSE; - } - } - return PathFileExistsW(lpszPath); -} - -/************************************************************************* - * @ [SHLWAPI.3] - * - * Determine if a file exists locally and is of an executable type. - * - * PARAMS - * lpszPath [I/O] File to search for - * dwWhich [I] Type of executable to search for - * - * RETURNS - * TRUE If the file was found. lpszPath contains the file name. - * FALSE Otherwise. - * - * NOTES - * lpszPath is modified in place and must be at least MAX_PATH in length. - * If the function returns FALSE, the path is modified to its orginal state. - * If the given path contains an extension or dwWhich is 0, executable - * extensions are not checked. - * - * Ordinals 3-6 are a classic case of MS exposing limited functionality to - * users (here through PathFindOnPathA()) and keeping advanced functionality for - * their own developers exclusive use. Monopoly, anyone? - */ -BOOL WINAPI PathFileExistsDefExtA(LPSTR lpszPath,DWORD dwWhich) -{ - BOOL bRet = FALSE; - - TRACE("(%s,%ld)\n", debugstr_a(lpszPath), dwWhich); - - if (lpszPath) - { - WCHAR szPath[MAX_PATH]; - MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH); - bRet = PathFileExistsDefExtW(szPath, dwWhich); - if (bRet) - WideCharToMultiByte(CP_ACP,0,szPath,-1,lpszPath,MAX_PATH,0,0); - } - return bRet; -} - -/************************************************************************* - * SHLWAPI_PathFindInOtherDirs - * - * Internal helper for SHLWAPI_PathFindOnPathExA/W. - */ -static BOOL WINAPI SHLWAPI_PathFindInOtherDirs(LPWSTR lpszFile, DWORD dwWhich) -{ - static const WCHAR szSystem[] = { 'S','y','s','t','e','m','\0'}; - static const WCHAR szPath[] = { 'P','A','T','H','\0'}; - DWORD dwLenPATH; - LPCWSTR lpszCurr; - WCHAR *lpszPATH; - WCHAR buff[MAX_PATH]; - - TRACE("(%s,%08lx)\n", debugstr_w(lpszFile), dwWhich); - - /* Try system directories */ - GetSystemDirectoryW(buff, MAX_PATH); - if (!PathAppendW(buff, lpszFile)) - return FALSE; - if (PathFileExistsDefExtW(buff, dwWhich)) - { - strcpyW(lpszFile, buff); - return TRUE; - } - GetWindowsDirectoryW(buff, MAX_PATH); - if (!PathAppendW(buff, szSystem ) || !PathAppendW(buff, lpszFile)) - return FALSE; - if (PathFileExistsDefExtW(buff, dwWhich)) - { - strcpyW(lpszFile, buff); - return TRUE; - } - GetWindowsDirectoryW(buff, MAX_PATH); - if (!PathAppendW(buff, lpszFile)) - return FALSE; - if (PathFileExistsDefExtW(buff, dwWhich)) - { - strcpyW(lpszFile, buff); - return TRUE; - } - /* Try dirs listed in %PATH% */ - dwLenPATH = GetEnvironmentVariableW(szPath, buff, MAX_PATH); - - if (!dwLenPATH || !(lpszPATH = malloc((dwLenPATH + 1) * sizeof (WCHAR)))) - return FALSE; - - GetEnvironmentVariableW(szPath, lpszPATH, dwLenPATH + 1); - lpszCurr = lpszPATH; - while (lpszCurr) - { - LPCWSTR lpszEnd = lpszCurr; - LPWSTR pBuff = buff; - - while (*lpszEnd == ' ') - lpszEnd++; - while (*lpszEnd && *lpszEnd != ';') - *pBuff++ = *lpszEnd++; - *pBuff = '\0'; - - if (*lpszEnd) - lpszCurr = lpszEnd + 1; - else - lpszCurr = NULL; /* Last Path, terminate after this */ - - if (!PathAppendW(buff, lpszFile)) - { - free(lpszPATH); - return FALSE; - } - if (PathFileExistsDefExtW(buff, dwWhich)) - { - strcpyW(lpszFile, buff); - free(lpszPATH); - return TRUE; - } - } - free(lpszPATH); - return FALSE; -} - -/************************************************************************* - * @ [SHLWAPI.5] - * - * Search a range of paths for a specific type of executable. - * - * PARAMS - * lpszFile [I/O] File to search for - * lppszOtherDirs [I] Other directories to look in - * dwWhich [I] Type of executable to search for - * - * RETURNS - * Success: TRUE. The path to the executable is stored in lpszFile. - * Failure: FALSE. The path to the executable is unchanged. - */ -BOOL WINAPI PathFindOnPathExA(LPSTR lpszFile,LPCSTR *lppszOtherDirs,DWORD dwWhich) -{ - WCHAR szFile[MAX_PATH]; - WCHAR buff[MAX_PATH]; - - TRACE("(%s,%p,%08lx)\n", debugstr_a(lpszFile), lppszOtherDirs, dwWhich); - - if (!lpszFile || !PathIsFileSpecA(lpszFile)) - return FALSE; - - MultiByteToWideChar(CP_ACP,0,lpszFile,-1,szFile,MAX_PATH); - - /* Search provided directories first */ - if (lppszOtherDirs && *lppszOtherDirs) - { - WCHAR szOther[MAX_PATH]; - LPCSTR *lpszOtherPath = lppszOtherDirs; - - while (lpszOtherPath && *lpszOtherPath && (*lpszOtherPath)[0]) - { - MultiByteToWideChar(CP_ACP,0,*lpszOtherPath,-1,szOther,MAX_PATH); - PathCombineW(buff, szOther, szFile); - if (PathFileExistsDefExtW(buff, dwWhich)) - { - WideCharToMultiByte(CP_ACP,0,buff,-1,lpszFile,MAX_PATH,0,0); - return TRUE; - } - lpszOtherPath++; - } - } - /* Not found, try system and path dirs */ - if (SHLWAPI_PathFindInOtherDirs(szFile, dwWhich)) - { - WideCharToMultiByte(CP_ACP,0,szFile,-1,lpszFile,MAX_PATH,0,0); - return TRUE; - } - return FALSE; -} - -/************************************************************************* - * @ [SHLWAPI.6] - * - * Unicode version of PathFindOnPathExA. - */ -BOOL WINAPI PathFindOnPathExW(LPWSTR lpszFile,LPCWSTR *lppszOtherDirs,DWORD dwWhich) -{ - WCHAR buff[MAX_PATH]; - - TRACE("(%s,%p,%08lx)\n", debugstr_w(lpszFile), lppszOtherDirs, dwWhich); - - if (!lpszFile || !PathIsFileSpecW(lpszFile)) - return FALSE; - - /* Search provided directories first */ - if (lppszOtherDirs && *lppszOtherDirs) - { - LPCWSTR *lpszOtherPath = lppszOtherDirs; - while (lpszOtherPath && *lpszOtherPath && (*lpszOtherPath)[0]) - { - PathCombineW(buff, *lpszOtherPath, lpszFile); - if (PathFileExistsDefExtW(buff, dwWhich)) - { - strcpyW(lpszFile, buff); - return TRUE; - } - lpszOtherPath++; - } - } - /* Not found, try system and path dirs */ - return SHLWAPI_PathFindInOtherDirs(lpszFile, dwWhich); -} - -/************************************************************************* - * PathFindOnPathA [SHLWAPI.@] - * - * Search a range of paths for an executable. - * - * PARAMS - * lpszFile [I/O] File to search for - * lppszOtherDirs [I] Other directories to look in - * - * RETURNS - * Success: TRUE. The path to the executable is stored in lpszFile. - * Failure: FALSE. The path to the executable is unchanged. - */ -BOOL WINAPI PathFindOnPathA(LPSTR lpszFile, LPCSTR *lppszOtherDirs) -{ - TRACE("(%s,%p)\n", debugstr_a(lpszFile), lppszOtherDirs); - return PathFindOnPathExA(lpszFile, lppszOtherDirs, 0); - } - -/************************************************************************* - * PathFindOnPathW [SHLWAPI.@] - * - * See PathFindOnPathA. - */ -BOOL WINAPI PathFindOnPathW(LPWSTR lpszFile, LPCWSTR *lppszOtherDirs) -{ - TRACE("(%s,%p)\n", debugstr_w(lpszFile), lppszOtherDirs); - return PathFindOnPathExW(lpszFile,lppszOtherDirs, 0); -} - -/************************************************************************* - * PathCompactPathExA [SHLWAPI.@] - * - * Compact a path into a given number of characters. - * - * PARAMS - * lpszDest [O] Destination for compacted path - * lpszPath [I] Source path - * cchMax [I] Maximum size of compacted path - * dwFlags [I] Reserved - * - * RETURNS - * Success: TRUE. The compacted path is written to lpszDest. - * Failure: FALSE. lpszPath is undefined. - * - * NOTES - * If cchMax is given as 0, lpszDest will still be NUL terminated. - * - * The Win32 version of this function contains a bug: When cchMax == 7, - * 8 bytes will be written to lpszDest. This bug is fixed in the Wine - * implementation. - * - * Some relative paths will be different when cchMax == 5 or 6. This occurs - * because Win32 will insert a "\" in lpszDest, even if one is - * not present in the original path. - */ -BOOL WINAPI PathCompactPathExA(LPSTR lpszDest, LPCSTR lpszPath, - UINT cchMax, DWORD dwFlags) -{ - BOOL bRet = FALSE; - - TRACE("(%p,%s,%d,0x%08lx)\n", lpszDest, debugstr_a(lpszPath), cchMax, dwFlags); - - if (lpszPath && lpszDest) - { - WCHAR szPath[MAX_PATH]; - WCHAR szDest[MAX_PATH]; - - MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH); - szDest[0] = '\0'; - bRet = PathCompactPathExW(szDest, szPath, cchMax, dwFlags); - WideCharToMultiByte(CP_ACP,0,szDest,-1,lpszDest,MAX_PATH,0,0); - } - return bRet; -} - -/************************************************************************* - * PathCompactPathExW [SHLWAPI.@] - * - * See PathCompactPathExA. - */ -BOOL WINAPI PathCompactPathExW(LPWSTR lpszDest, LPCWSTR lpszPath, - UINT cchMax, DWORD dwFlags) -{ - static const WCHAR szEllipses[] = { '.', '.', '.', '\0' }; - LPCWSTR lpszFile; - DWORD dwLen, dwFileLen = 0; - - TRACE("(%p,%s,%d,0x%08lx)\n", lpszDest, debugstr_w(lpszPath), cchMax, dwFlags); - - if (!lpszPath) - return FALSE; - - if (!lpszDest) - { - WARN("Invalid lpszDest would crash under Win32!\n"); - return FALSE; - } - - *lpszDest = '\0'; - - if (cchMax < 2) - return TRUE; - - dwLen = strlenW(lpszPath) + 1; - - if (dwLen < cchMax) - { - /* Don't need to compact */ - memcpy(lpszDest, lpszPath, dwLen * sizeof(WCHAR)); - return TRUE; - } - - /* Path must be compacted to fit into lpszDest */ - lpszFile = PathFindFileNameW(lpszPath); - dwFileLen = lpszPath + dwLen - lpszFile; - - if (dwFileLen == dwLen) - { - /* No root in psth */ - if (cchMax <= 4) - { - while (--cchMax > 0) /* No room left for anything but ellipses */ - *lpszDest++ = '.'; - *lpszDest = '\0'; - return TRUE; - } - /* Compact the file name with ellipses at the end */ - cchMax -= 4; - memcpy(lpszDest, lpszFile, cchMax * sizeof(WCHAR)); - strcpyW(lpszDest + cchMax, szEllipses); - return TRUE; - } - /* We have a root in the path */ - lpszFile--; /* Start compacted filename with the path separator */ - dwFileLen++; - - if (dwFileLen + 3 > cchMax) - { - /* Compact the file name */ - if (cchMax <= 4) - { - while (--cchMax > 0) /* No room left for anything but ellipses */ - *lpszDest++ = '.'; - *lpszDest = '\0'; - return TRUE; - } - strcpyW(lpszDest, szEllipses); - lpszDest += 3; - cchMax -= 4; - *lpszDest++ = *lpszFile++; - if (cchMax <= 4) - { - while (--cchMax > 0) /* No room left for anything but ellipses */ - *lpszDest++ = '.'; - *lpszDest = '\0'; - return TRUE; - } - cchMax -= 4; - memcpy(lpszDest, lpszFile, cchMax * sizeof(WCHAR)); - strcpyW(lpszDest + cchMax, szEllipses); - return TRUE; - } - - /* Only the root needs to be Compacted */ - dwLen = cchMax - dwFileLen - 3; - memcpy(lpszDest, lpszPath, dwLen * sizeof(WCHAR)); - strcpyW(lpszDest + dwLen, szEllipses); - strcpyW(lpszDest + dwLen + 3, lpszFile); - return TRUE; -} - -/************************************************************************* - * PathIsRelativeA [SHLWAPI.@] - * - * Determine if a path is a relative path. - * - * PARAMS - * lpszPath [I] Path to check - * - * RETURNS - * TRUE: The path is relative, or is invalid. - * FALSE: The path is not relative. - */ -BOOL WINAPI PathIsRelativeA (LPCSTR lpszPath) -{ - TRACE("(%s)\n",debugstr_a(lpszPath)); - - if (!lpszPath || !*lpszPath || IsDBCSLeadByte(*lpszPath)) - return TRUE; - if (*lpszPath == '\\' || (*lpszPath && lpszPath[1] == ':')) - return FALSE; - return TRUE; -} - -/************************************************************************* - * PathIsRelativeW [SHLWAPI.@] - * - * See PathIsRelativeA. - */ -BOOL WINAPI PathIsRelativeW (LPCWSTR lpszPath) -{ - TRACE("(%s)\n",debugstr_w(lpszPath)); - - if (!lpszPath || !*lpszPath) - return TRUE; - if (*lpszPath == '\\' || (*lpszPath && lpszPath[1] == ':')) - return FALSE; - return TRUE; -} - -/************************************************************************* - * PathIsRootA [SHLWAPI.@] - * - * Determine if a path is a root path. - * - * PARAMS - * lpszPath [I] Path to check - * - * RETURNS - * TRUE If lpszPath is valid and a root path, - * FALSE Otherwise - */ -BOOL WINAPI PathIsRootA(LPCSTR lpszPath) -{ - TRACE("(%s)\n", debugstr_a(lpszPath)); - - if (lpszPath && *lpszPath) - { - if (*lpszPath == '\\') - { - if (!lpszPath[1]) - return TRUE; /* \ */ - else if (lpszPath[1]=='\\') - { - BOOL bSeenSlash = FALSE; - lpszPath += 2; - - /* Check for UNC root path */ - while (*lpszPath) - { - if (*lpszPath == '\\') - { - if (bSeenSlash) - return FALSE; - bSeenSlash = TRUE; - } - lpszPath = CharNextA(lpszPath); - } - return TRUE; - } - } - else if (lpszPath[1] == ':' && lpszPath[2] == '\\' && lpszPath[3] == '\0') - return TRUE; /* X:\ */ - } - return FALSE; -} - -/************************************************************************* - * PathIsRootW [SHLWAPI.@] - * - * See PathIsRootA. - */ -BOOL WINAPI PathIsRootW(LPCWSTR lpszPath) -{ - TRACE("(%s)\n", debugstr_w(lpszPath)); - - if (lpszPath && *lpszPath) - { - if (*lpszPath == '\\') - { - if (!lpszPath[1]) - return TRUE; /* \ */ - else if (lpszPath[1]=='\\') - { - BOOL bSeenSlash = FALSE; - lpszPath += 2; - - /* Check for UNC root path */ - while (*lpszPath) - { - if (*lpszPath == '\\') - { - if (bSeenSlash) - return FALSE; - bSeenSlash = TRUE; - } - lpszPath = CharNextW(lpszPath); - } - return TRUE; - } - } - else if (lpszPath[1] == ':' && lpszPath[2] == '\\' && lpszPath[3] == '\0') - return TRUE; /* X:\ */ - } - return FALSE; -} - -/************************************************************************* - * PathIsDirectoryA [SHLWAPI.@] - * - * Determine if a path is a valid directory - * - * PARAMS - * lpszPath [I] Path to check. - * - * RETURNS - * FILE_ATTRIBUTE_DIRECTORY if lpszPath exists and can be read (See Notes) - * FALSE if lpszPath is invalid or not a directory. - * - * NOTES - * Although this function is prototyped as returning a BOOL, it returns - * FILE_ATTRIBUTE_DIRECTORY for success. This means that code such as: - * - *| if (PathIsDirectoryA("c:\\windows\\") == TRUE) - *| ... - * - * will always fail. - */ -BOOL WINAPI PathIsDirectoryA(LPCSTR lpszPath) -{ - DWORD dwAttr; - - TRACE("(%s)\n", debugstr_a(lpszPath)); - - if (!lpszPath || PathIsUNCServerA(lpszPath)) - return FALSE; - - if (PathIsUNCServerShareA(lpszPath)) - { - FIXME("UNC Server Share not yet supported - FAILING\n"); - return FALSE; - } - - if ((dwAttr = GetFileAttributesA(lpszPath)) == INVALID_FILE_ATTRIBUTES) - return FALSE; - return dwAttr & FILE_ATTRIBUTE_DIRECTORY; -} - -/************************************************************************* - * PathIsDirectoryW [SHLWAPI.@] - * - * See PathIsDirectoryA. - */ -BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath) -{ - DWORD dwAttr; - - TRACE("(%s)\n", debugstr_w(lpszPath)); - - if (!lpszPath || PathIsUNCServerW(lpszPath)) - return FALSE; - - if (PathIsUNCServerShareW(lpszPath)) - { - FIXME("UNC Server Share not yet supported - FAILING\n"); - return FALSE; - } - - if ((dwAttr = GetFileAttributesW(lpszPath)) == INVALID_FILE_ATTRIBUTES) - return FALSE; - return dwAttr & FILE_ATTRIBUTE_DIRECTORY; -} - -/************************************************************************* - * PathFileExistsA [SHLWAPI.@] - * - * Determine if a file exists. - * - * PARAMS - * lpszPath [I] Path to check - * - * RETURNS - * TRUE If the file exists and is readable - * FALSE Otherwise - */ -BOOL WINAPI PathFileExistsA(LPCSTR lpszPath) -{ - UINT iPrevErrMode; - DWORD dwAttr; - - TRACE("(%s)\n",debugstr_a(lpszPath)); - - if (!lpszPath) - return FALSE; - - /* Prevent a dialog box if path is on a disk that has been ejected. */ - iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS); - dwAttr = GetFileAttributesA(lpszPath); - SetErrorMode(iPrevErrMode); - return dwAttr == INVALID_FILE_ATTRIBUTES ? FALSE : TRUE; -} - -/************************************************************************* - * PathFileExistsW [SHLWAPI.@] - * - * See PathFileExistsA. - */ -BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath) -{ - UINT iPrevErrMode; - DWORD dwAttr; - - TRACE("(%s)\n",debugstr_w(lpszPath)); - - if (!lpszPath) - return FALSE; - - iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS); - dwAttr = GetFileAttributesW(lpszPath); - SetErrorMode(iPrevErrMode); - return dwAttr == INVALID_FILE_ATTRIBUTES ? FALSE : TRUE; -} - -/************************************************************************* - * PathFileExistsAndAttributesA [SHLWAPI.445] - * - * Determine if a file exists. - * - * PARAMS - * lpszPath [I] Path to check - * dwAttr [O] attributes of file - * - * RETURNS - * TRUE If the file exists and is readable - * FALSE Otherwise - */ -BOOL WINAPI PathFileExistsAndAttributesA(LPCSTR lpszPath, DWORD *dwAttr) -{ - UINT iPrevErrMode; - DWORD dwVal = 0; - - TRACE("(%s %p)\n", debugstr_a(lpszPath), dwAttr); - - if (dwAttr) - *dwAttr = INVALID_FILE_ATTRIBUTES; - - if (!lpszPath) - return FALSE; - - iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS); - dwVal = GetFileAttributesA(lpszPath); - SetErrorMode(iPrevErrMode); - if (dwAttr) - *dwAttr = dwVal; - return (dwVal != INVALID_FILE_ATTRIBUTES); -} - -/************************************************************************* - * PathFileExistsAndAttributesW [SHLWAPI.446] - * - * See PathFileExistsA. - */ -BOOL WINAPI PathFileExistsAndAttributesW(LPCWSTR lpszPath, DWORD *dwAttr) -{ - UINT iPrevErrMode; - DWORD dwVal; - - TRACE("(%s %p)\n", debugstr_w(lpszPath), dwAttr); - - if (!lpszPath) - return FALSE; - - iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS); - dwVal = GetFileAttributesW(lpszPath); - SetErrorMode(iPrevErrMode); - if (dwAttr) - *dwAttr = dwVal; - return (dwVal != INVALID_FILE_ATTRIBUTES); -} - -/************************************************************************* - * PathMatchSingleMaskA [internal] - */ -static BOOL WINAPI PathMatchSingleMaskA(LPCSTR name, LPCSTR mask) -{ - while (*name && *mask && *mask!=';') - { - if (*mask == '*') - { - do - { - if (PathMatchSingleMaskA(name,mask+1)) - return TRUE; /* try substrings */ - } while (*name++); - return FALSE; - } - - if (toupper(*mask) != toupper(*name) && *mask != '?') - return FALSE; - - name = CharNextA(name); - mask = CharNextA(mask); - } - - if (!*name) - { - while (*mask == '*') - mask++; - if (!*mask || *mask == ';') - return TRUE; - } - return FALSE; -} - -/************************************************************************* - * PathMatchSingleMaskW [internal] - */ -static BOOL WINAPI PathMatchSingleMaskW(LPCWSTR name, LPCWSTR mask) -{ - while (*name && *mask && *mask != ';') - { - if (*mask == '*') - { - do - { - if (PathMatchSingleMaskW(name,mask+1)) - return TRUE; /* try substrings */ - } while (*name++); - return FALSE; - } - - if (toupperW(*mask) != toupperW(*name) && *mask != '?') - return FALSE; - - name = CharNextW(name); - mask = CharNextW(mask); - } - if (!*name) - { - while (*mask == '*') - mask++; - if (!*mask || *mask == ';') - return TRUE; - } - return FALSE; -} - -/************************************************************************* - * PathMatchSpecA [SHLWAPI.@] - * - * Determine if a path matches one or more search masks. - * - * PARAMS - * lpszPath [I] Path to check - * lpszMask [I] Search mask(s) - * - * RETURNS - * TRUE If lpszPath is valid and is matched - * FALSE Otherwise - * - * NOTES - * Multiple search masks may be given if they are separated by ";". The - * pattern "*.*" is treated specially in that it matches all paths (for - * backwards compatibility with DOS). - */ -BOOL WINAPI PathMatchSpecA(LPCSTR lpszPath, LPCSTR lpszMask) -{ - TRACE("(%s,%s)\n", lpszPath, lpszMask); - - if (!lstrcmpA(lpszMask, "*.*")) - return TRUE; /* Matches every path */ - - while (*lpszMask) - { - if (PathMatchSingleMaskA(lpszPath, lpszMask)) - return TRUE; /* Matches the current mask */ - - while (*lpszMask && *lpszMask != ';') - lpszMask = CharNextA(lpszMask); - - if (*lpszMask == ';') - { - lpszMask++; - while (*lpszMask == ' ') - lpszMask++; /* masks may be separated by "; " */ - } - } - return FALSE; -} - -/************************************************************************* - * PathMatchSpecW [SHLWAPI.@] - * - * See PathMatchSpecA. - */ -BOOL WINAPI PathMatchSpecW(LPCWSTR lpszPath, LPCWSTR lpszMask) -{ - static const WCHAR szStarDotStar[] = { '*', '.', '*', '\0' }; - - TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszMask)); - - if (!lstrcmpW(lpszMask, szStarDotStar)) - return TRUE; /* Matches every path */ - - while (*lpszMask) - { - if (PathMatchSingleMaskW(lpszPath, lpszMask)) - return TRUE; /* Matches the current path */ - - while (*lpszMask && *lpszMask != ';') - lpszMask++; - - if (*lpszMask == ';') - { - lpszMask++; - while (*lpszMask == ' ') - lpszMask++; /* Masks may be separated by "; " */ - } - } - return FALSE; -} - -/************************************************************************* - * PathIsSameRootA [SHLWAPI.@] - * - * Determine if two paths share the same root. - * - * PARAMS - * lpszPath1 [I] Source path - * lpszPath2 [I] Path to compare with - * - * RETURNS - * TRUE If both paths are valid and share the same root. - * FALSE If either path is invalid or the paths do not share the same root. - */ -BOOL WINAPI PathIsSameRootA(LPCSTR lpszPath1, LPCSTR lpszPath2) -{ - LPCSTR lpszStart; - int dwLen; - - TRACE("(%s,%s)\n", debugstr_a(lpszPath1), debugstr_a(lpszPath2)); - - if (!lpszPath1 || !lpszPath2 || !(lpszStart = PathSkipRootA(lpszPath1))) - return FALSE; - - dwLen = PathCommonPrefixA(lpszPath1, lpszPath2, NULL) + 1; - if (lpszStart - lpszPath1 > dwLen) - return FALSE; /* Paths not common up to length of the root */ - return TRUE; -} - -/************************************************************************* - * PathIsSameRootW [SHLWAPI.@] - * - * See PathIsSameRootA. - */ -BOOL WINAPI PathIsSameRootW(LPCWSTR lpszPath1, LPCWSTR lpszPath2) -{ - LPCWSTR lpszStart; - int dwLen; - - TRACE("(%s,%s)\n", debugstr_w(lpszPath1), debugstr_w(lpszPath2)); - - if (!lpszPath1 || !lpszPath2 || !(lpszStart = PathSkipRootW(lpszPath1))) - return FALSE; - - dwLen = PathCommonPrefixW(lpszPath1, lpszPath2, NULL) + 1; - if (lpszStart - lpszPath1 > dwLen) - return FALSE; /* Paths not common up to length of the root */ - return TRUE; -} - -/************************************************************************* - * PathIsContentTypeA [SHLWAPI.@] - * - * Determine if a file is of a given registered content type. - * - * PARAMS - * lpszPath [I] File to check - * lpszContentType [I] Content type to check for - * - * RETURNS - * TRUE If lpszPath is a given registered content type, - * FALSE Otherwise. - * - * NOTES - * This function looks up the registered content type for lpszPath. If - * a content type is registered, it is compared (case insensitively) to - * lpszContentType. Only if this matches does the function succeed. - */ -BOOL WINAPI PathIsContentTypeA(LPCSTR lpszPath, LPCSTR lpszContentType) -{ - LPCSTR szExt; - DWORD dwDummy; - char szBuff[MAX_PATH]; - - TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszContentType)); - - if (lpszPath && (szExt = PathFindExtensionA(lpszPath)) && *szExt && - !SHGetValueA(HKEY_CLASSES_ROOT, szExt, "Content Type", - REG_NONE, szBuff, &dwDummy) && - !strcasecmp(lpszContentType, szBuff)) - { - return TRUE; - } - return FALSE; -} - -/************************************************************************* - * PathIsContentTypeW [SHLWAPI.@] - * - * See PathIsContentTypeA. - */ -BOOL WINAPI PathIsContentTypeW(LPCWSTR lpszPath, LPCWSTR lpszContentType) -{ - static const WCHAR szContentType[] = { 'C','o','n','t','e','n','t',' ','T','y','p','e','\0' }; - LPCWSTR szExt; - DWORD dwDummy; - WCHAR szBuff[MAX_PATH]; - - TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszContentType)); - - if (lpszPath && (szExt = PathFindExtensionW(lpszPath)) && *szExt && - !SHGetValueW(HKEY_CLASSES_ROOT, szExt, szContentType, - REG_NONE, szBuff, &dwDummy) && - !strcmpiW(lpszContentType, szBuff)) - { - return TRUE; - } - return FALSE; -} - -/************************************************************************* - * PathIsFileSpecA [SHLWAPI.@] - * - * Determine if a path is a file specification. - * - * PARAMS - * lpszPath [I] Path to chack - * - * RETURNS - * TRUE If lpszPath is a file specification (i.e. Contains no directories). - * FALSE Otherwise. - */ -BOOL WINAPI PathIsFileSpecA(LPCSTR lpszPath) -{ - TRACE("(%s)\n", debugstr_a(lpszPath)); - - if (!lpszPath) - return FALSE; - - while (*lpszPath) - { - if (*lpszPath == '\\' || *lpszPath == ':') - return FALSE; - lpszPath = CharNextA(lpszPath); - } - return TRUE; -} - -/************************************************************************* - * PathIsFileSpecW [SHLWAPI.@] - * - * See PathIsFileSpecA. - */ -BOOL WINAPI PathIsFileSpecW(LPCWSTR lpszPath) -{ - TRACE("(%s)\n", debugstr_w(lpszPath)); - - if (!lpszPath) - return FALSE; - - while (*lpszPath) - { - if (*lpszPath == '\\' || *lpszPath == ':') - return FALSE; - lpszPath = CharNextW(lpszPath); - } - return TRUE; -} - -/************************************************************************* - * PathIsPrefixA [SHLWAPI.@] - * - * Determine if a path is a prefix of another. - * - * PARAMS - * lpszPrefix [I] Prefix - * lpszPath [I] Path to check - * - * RETURNS - * TRUE If lpszPath has lpszPrefix as its prefix, - * FALSE If either path is NULL or lpszPrefix is not a prefix - */ -BOOL WINAPI PathIsPrefixA (LPCSTR lpszPrefix, LPCSTR lpszPath) -{ - TRACE("(%s,%s)\n", debugstr_a(lpszPrefix), debugstr_a(lpszPath)); - - if (lpszPrefix && lpszPath && - PathCommonPrefixA(lpszPath, lpszPrefix, NULL) == (int)strlen(lpszPrefix)) - return TRUE; - return FALSE; -} - -/************************************************************************* - * PathIsPrefixW [SHLWAPI.@] - * - * See PathIsPrefixA. - */ -BOOL WINAPI PathIsPrefixW(LPCWSTR lpszPrefix, LPCWSTR lpszPath) -{ - TRACE("(%s,%s)\n", debugstr_w(lpszPrefix), debugstr_w(lpszPath)); - - if (lpszPrefix && lpszPath && - PathCommonPrefixW(lpszPath, lpszPrefix, NULL) == (int)strlenW(lpszPrefix)) - return TRUE; - return FALSE; -} - -/************************************************************************* - * PathIsSystemFolderA [SHLWAPI.@] - * - * Determine if a path or file attributes are a system folder. - * - * PARAMS - * lpszPath [I] Path to check. - * dwAttrib [I] Attributes to check, if lpszPath is NULL. - * - * RETURNS - * TRUE If lpszPath or dwAttrib are a system folder. - * FALSE If GetFileAttributesA() fails or neither parameter is a system folder. - */ -BOOL WINAPI PathIsSystemFolderA(LPCSTR lpszPath, DWORD dwAttrib) -{ - TRACE("(%s,0x%08lx)\n", debugstr_a(lpszPath), dwAttrib); - - if (lpszPath && *lpszPath) - dwAttrib = GetFileAttributesA(lpszPath); - - if (dwAttrib == INVALID_FILE_ATTRIBUTES || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY) || - !(dwAttrib & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY))) - return FALSE; - return TRUE; -} - -/************************************************************************* - * PathIsSystemFolderW [SHLWAPI.@] - * - * See PathIsSystemFolderA. - */ -BOOL WINAPI PathIsSystemFolderW(LPCWSTR lpszPath, DWORD dwAttrib) -{ - TRACE("(%s,0x%08lx)\n", debugstr_w(lpszPath), dwAttrib); - - if (lpszPath && *lpszPath) - dwAttrib = GetFileAttributesW(lpszPath); - - if (dwAttrib == INVALID_FILE_ATTRIBUTES || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY) || - !(dwAttrib & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY))) - return FALSE; - return TRUE; -} - -/************************************************************************* - * PathIsUNCA [SHLWAPI.@] - * - * Determine if a path is in UNC format. - * - * PARAMS - * lpszPath [I] Path to check - * - * RETURNS - * TRUE: The path is UNC. - * FALSE: The path is not UNC or is NULL. - */ -BOOL WINAPI PathIsUNCA(LPCSTR lpszPath) -{ - TRACE("(%s)\n",debugstr_a(lpszPath)); - - if (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\')) - return TRUE; - return FALSE; -} - -/************************************************************************* - * PathIsUNCW [SHLWAPI.@] - * - * See PathIsUNCA. - */ -BOOL WINAPI PathIsUNCW(LPCWSTR lpszPath) -{ - TRACE("(%s)\n",debugstr_w(lpszPath)); - - if (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\')) - return TRUE; - return FALSE; -} - -/************************************************************************* - * PathIsUNCServerA [SHLWAPI.@] - * - * Determine if a path is a UNC server name ("\\SHARENAME"). - * - * PARAMS - * lpszPath [I] Path to check. - * - * RETURNS - * TRUE If lpszPath is a valid UNC server name. - * FALSE Otherwise. - * - * NOTES - * This routine is bug compatible with Win32: Server names with a - * trailing backslash (e.g. "\\FOO\"), return FALSE incorrectly. - * Fixing this bug may break other shlwapi functions! - */ -BOOL WINAPI PathIsUNCServerA(LPCSTR lpszPath) -{ - TRACE("(%s)\n", debugstr_a(lpszPath)); - - if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\') - { - while (*lpszPath) - { - if (*lpszPath == '\\') - return FALSE; - lpszPath = CharNextA(lpszPath); - } - return TRUE; - } - return FALSE; -} - -/************************************************************************* - * PathIsUNCServerW [SHLWAPI.@] - * - * See PathIsUNCServerA. - */ -BOOL WINAPI PathIsUNCServerW(LPCWSTR lpszPath) -{ - TRACE("(%s)\n", debugstr_w(lpszPath)); - - if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\') - { - while (*lpszPath) - { - if (*lpszPath == '\\') - return FALSE; - lpszPath = CharNextW(lpszPath); - } - return TRUE; - } - return FALSE; -} - -/************************************************************************* - * PathIsUNCServerShareA [SHLWAPI.@] - * - * Determine if a path is a UNC server share ("\\SHARENAME\SHARE"). - * - * PARAMS - * lpszPath [I] Path to check. - * - * RETURNS - * TRUE If lpszPath is a valid UNC server share. - * FALSE Otherwise. - * - * NOTES - * This routine is bug compatible with Win32: Server shares with a - * trailing backslash (e.g. "\\FOO\BAR\"), return FALSE incorrectly. - * Fixing this bug may break other shlwapi functions! - */ -BOOL WINAPI PathIsUNCServerShareA(LPCSTR lpszPath) -{ - TRACE("(%s)\n", debugstr_a(lpszPath)); - - if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\') - { - BOOL bSeenSlash = FALSE; - while (*lpszPath) - { - if (*lpszPath == '\\') - { - if (bSeenSlash) - return FALSE; - bSeenSlash = TRUE; - } - lpszPath = CharNextA(lpszPath); - } - return bSeenSlash; - } - return FALSE; -} - -/************************************************************************* - * PathIsUNCServerShareW [SHLWAPI.@] - * - * See PathIsUNCServerShareA. - */ -BOOL WINAPI PathIsUNCServerShareW(LPCWSTR lpszPath) -{ - TRACE("(%s)\n", debugstr_w(lpszPath)); - - if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\') - { - BOOL bSeenSlash = FALSE; - while (*lpszPath) - { - if (*lpszPath == '\\') - { - if (bSeenSlash) - return FALSE; - bSeenSlash = TRUE; - } - lpszPath = CharNextW(lpszPath); - } - return bSeenSlash; - } - return FALSE; -} - -/************************************************************************* - * PathCanonicalizeA [SHLWAPI.@] - * - * Convert a path to its canonical form. - * - * PARAMS - * lpszBuf [O] Output path - * lpszPath [I] Path to cnonicalize - * - * RETURNS - * Success: TRUE. lpszBuf contains the output path, - * Failure: FALSE, If input path is invalid. lpszBuf is undefined - */ -BOOL WINAPI PathCanonicalizeA(LPSTR lpszBuf, LPCSTR lpszPath) -{ - BOOL bRet = FALSE; - - TRACE("(%p,%s)\n", lpszBuf, debugstr_a(lpszPath)); - - if (lpszBuf) - *lpszBuf = '\0'; - - if (!lpszBuf || !lpszPath) - SetLastError(ERROR_INVALID_PARAMETER); - else - { - WCHAR szPath[MAX_PATH]; - WCHAR szBuff[MAX_PATH]; - MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH); - bRet = PathCanonicalizeW(szBuff, szPath); - WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszBuf,MAX_PATH,0,0); - } - return bRet; -} - - -/************************************************************************* - * PathCanonicalizeW [SHLWAPI.@] - * - * See PathCanonicalizeA. - */ -BOOL WINAPI PathCanonicalizeW(LPWSTR lpszBuf, LPCWSTR lpszPath) -{ - LPWSTR lpszDst = lpszBuf; - LPCWSTR lpszSrc = lpszPath; - - TRACE("(%p,%s)\n", lpszBuf, debugstr_w(lpszPath)); - - if (lpszBuf) - *lpszDst = '\0'; - - if (!lpszBuf || !lpszPath) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - if (!*lpszPath) - { - *lpszBuf++ = '\\'; - *lpszBuf = '\0'; - return TRUE; - } - - /* Copy path root */ - if (*lpszSrc == '\\') - { - *lpszDst++ = *lpszSrc++; - } - else if (*lpszSrc && lpszSrc[1] == ':') - { - /* X:\ */ - *lpszDst++ = *lpszSrc++; - *lpszDst++ = *lpszSrc++; - if (*lpszSrc == '\\') - *lpszDst++ = *lpszSrc++; - } - - /* Canonicalize the rest of the path */ - while (*lpszSrc) - { - if (*lpszSrc == '.') - { - if (lpszSrc[1] == '\\' && (lpszSrc == lpszPath || lpszSrc[-1] == '\\' || lpszSrc[-1] == ':')) - { - lpszSrc += 2; /* Skip .\ */ - } - else if (lpszSrc[1] == '.' && (lpszDst == lpszBuf || lpszDst[-1] == '\\')) - { - /* \.. backs up a directory, over the root if it has no \ following X:. - * .. is ignored if it would remove a UNC server name or inital \\ - */ - if (lpszDst != lpszBuf) - { - *lpszDst = '\0'; /* Allow PathIsUNCServerShareA test on lpszBuf */ - if (lpszDst > lpszBuf+1 && lpszDst[-1] == '\\' && - (lpszDst[-2] != '\\' || lpszDst > lpszBuf+2)) - { - if (lpszDst[-2] == ':' && (lpszDst > lpszBuf+3 || lpszDst[-3] == ':')) - { - lpszDst -= 2; - while (lpszDst > lpszBuf && *lpszDst != '\\') - lpszDst--; - if (*lpszDst == '\\') - lpszDst++; /* Reset to last '\' */ - else - lpszDst = lpszBuf; /* Start path again from new root */ - } - else if (lpszDst[-2] != ':' && !PathIsUNCServerShareW(lpszBuf)) - lpszDst -= 2; - } - while (lpszDst > lpszBuf && *lpszDst != '\\') - lpszDst--; - if (lpszDst == lpszBuf) - { - *lpszDst++ = '\\'; - lpszSrc++; - } - } - lpszSrc += 2; /* Skip .. in src path */ - } - else - *lpszDst++ = *lpszSrc++; - } - else - *lpszDst++ = *lpszSrc++; - } - /* Append \ to naked drive specs */ - if (lpszDst - lpszBuf == 2 && lpszDst[-1] == ':') - *lpszDst++ = '\\'; - *lpszDst++ = '\0'; - return TRUE; -} - -/************************************************************************* - * PathFindNextComponentA [SHLWAPI.@] - * - * Find the next component in a path. - * - * PARAMS - * lpszPath [I] Path to find next component in - * - * RETURNS - * Success: A pointer to the next component, or the end of the string. - * Failure: NULL, If lpszPath is invalid - * - * NOTES - * A 'component' is either a backslash character (\) or UNC marker (\\). - * Because of this, relative paths (e.g "c:foo") are regarded as having - * only one component. - */ -LPSTR WINAPI PathFindNextComponentA(LPCSTR lpszPath) -{ - LPSTR lpszSlash; - - TRACE("(%s)\n", debugstr_a(lpszPath)); - - if(!lpszPath || !*lpszPath) - return NULL; - - if ((lpszSlash = StrChrA(lpszPath, '\\'))) - { - if (lpszSlash[1] == '\\') - lpszSlash++; - return lpszSlash + 1; - } - return (LPSTR)lpszPath + strlen(lpszPath); -} - -/************************************************************************* - * PathFindNextComponentW [SHLWAPI.@] - * - * See PathFindNextComponentA. - */ -LPWSTR WINAPI PathFindNextComponentW(LPCWSTR lpszPath) -{ - LPWSTR lpszSlash; - - TRACE("(%s)\n", debugstr_w(lpszPath)); - - if(!lpszPath || !*lpszPath) - return NULL; - - if ((lpszSlash = StrChrW(lpszPath, '\\'))) - { - if (lpszSlash[1] == '\\') - lpszSlash++; - return lpszSlash + 1; - } - return (LPWSTR)lpszPath + strlenW(lpszPath); -} - -/************************************************************************* - * PathAddExtensionA [SHLWAPI.@] - * - * Add a file extension to a path - * - * PARAMS - * lpszPath [I/O] Path to add extension to - * lpszExtension [I] Extension to add to lpszPath - * - * RETURNS - * TRUE If the path was modified, - * FALSE If lpszPath or lpszExtension are invalid, lpszPath has an - * extension allready, or the new path length is too big. - * - * FIXME - * What version of shlwapi.dll adds "exe" if lpszExtension is NULL? Win2k - * does not do this, so the behaviour was removed. - */ -BOOL WINAPI PathAddExtensionA(LPSTR lpszPath, LPCSTR lpszExtension) -{ - size_t dwLen; - - TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszExtension)); - - if (!lpszPath || !lpszExtension || *(PathFindExtensionA(lpszPath))) - return FALSE; - - dwLen = strlen(lpszPath); - - if (dwLen + strlen(lpszExtension) >= MAX_PATH) - return FALSE; - - strcpy(lpszPath + dwLen, lpszExtension); - return TRUE; -} - -/************************************************************************* - * PathAddExtensionW [SHLWAPI.@] - * - * See PathAddExtensionA. - */ -BOOL WINAPI PathAddExtensionW(LPWSTR lpszPath, LPCWSTR lpszExtension) -{ - size_t dwLen; - - TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszExtension)); - - if (!lpszPath || !lpszExtension || *(PathFindExtensionW(lpszPath))) - return FALSE; - - dwLen = strlenW(lpszPath); - - if (dwLen + strlenW(lpszExtension) >= MAX_PATH) - return FALSE; - - strcpyW(lpszPath + dwLen, lpszExtension); - return TRUE; -} - -/************************************************************************* - * PathMakePrettyA [SHLWAPI.@] - * - * Convert an uppercase DOS filename into lowercase. - * - * PARAMS - * lpszPath [I/O] Path to convert. - * - * RETURNS - * TRUE If the path was an uppercase DOS path and was converted, - * FALSE Otherwise. - */ -BOOL WINAPI PathMakePrettyA(LPSTR lpszPath) -{ - LPSTR pszIter = lpszPath; - - TRACE("(%s)\n", debugstr_a(lpszPath)); - - if (!pszIter) - return FALSE; - - if (*pszIter) - { - do - { - if (islower(*pszIter) || IsDBCSLeadByte(*pszIter)) - return FALSE; /* Not DOS path */ - pszIter++; - } while (*pszIter); - pszIter = lpszPath + 1; - while (*pszIter) - { - *pszIter = tolower(*pszIter); - pszIter++; - } - } - return TRUE; -} - -/************************************************************************* - * PathMakePrettyW [SHLWAPI.@] - * - * See PathMakePrettyA. - */ -BOOL WINAPI PathMakePrettyW(LPWSTR lpszPath) -{ - LPWSTR pszIter = lpszPath; - - TRACE("(%s)\n", debugstr_w(lpszPath)); - - if (!pszIter) - return FALSE; - - if (*pszIter) - { - do - { - if (islowerW(*pszIter)) - return FALSE; /* Not DOS path */ - pszIter++; - } while (*pszIter); - pszIter = lpszPath + 1; - while (*pszIter) - { - *pszIter = tolowerW(*pszIter); - pszIter++; - } - } - return TRUE; -} - -/************************************************************************* - * PathCommonPrefixA [SHLWAPI.@] - * - * Determine the length of the common prefix between two paths. - * - * PARAMS - * lpszFile1 [I] First path for comparison - * lpszFile2 [I] Second path for comparison - * achPath [O] Destination for common prefix string - * - * RETURNS - * The length of the common prefix. This is 0 if there is no common - * prefix between the paths or if any parameters are invalid. If the prefix - * is non-zero and achPath is not NULL, achPath is filled with the common - * part of the prefix and NUL terminated. - * - * NOTES - * A common prefix of 2 is always returned as 3. It is thus possible for - * the length returned to be invalid (i.e. Longer than one or both of the - * strings given as parameters). This Win32 behaviour has been implemented - * here, and cannot be changed (fixed?) without breaking other SHLWAPI calls. - * To work around this when using this function, always check that the byte - * at [common_prefix_len-1] is not a NUL. If it is, deduct 1 from the prefix. - */ -int WINAPI PathCommonPrefixA(LPCSTR lpszFile1, LPCSTR lpszFile2, LPSTR achPath) -{ - size_t iLen = 0; - LPCSTR lpszIter1 = lpszFile1; - LPCSTR lpszIter2 = lpszFile2; - - TRACE("(%s,%s,%p)\n", debugstr_a(lpszFile1), debugstr_a(lpszFile2), achPath); - - if (achPath) - *achPath = '\0'; - - if (!lpszFile1 || !lpszFile2) - return 0; - - /* Handle roots first */ - if (PathIsUNCA(lpszFile1)) - { - if (!PathIsUNCA(lpszFile2)) - return 0; - lpszIter1 += 2; - lpszIter2 += 2; - } - else if (PathIsUNCA(lpszFile2)) - return 0; /* Know already lpszFile1 is not UNC */ - - do - { - /* Update len */ - if ((!*lpszIter1 || *lpszIter1 == '\\') && - (!*lpszIter2 || *lpszIter2 == '\\')) - iLen = lpszIter1 - lpszFile1; /* Common to this point */ - - if (!*lpszIter1 || (tolower(*lpszIter1) != tolower(*lpszIter2))) - break; /* Strings differ at this point */ - - lpszIter1++; - lpszIter2++; - } while (1); - - if (iLen == 2) - iLen++; /* Feature/Bug compatible with Win32 */ - - if (iLen && achPath) - { - memcpy(achPath,lpszFile1,iLen); - achPath[iLen] = '\0'; - } - return iLen; -} - -/************************************************************************* - * PathCommonPrefixW [SHLWAPI.@] - * - * See PathCommonPrefixA. - */ -int WINAPI PathCommonPrefixW(LPCWSTR lpszFile1, LPCWSTR lpszFile2, LPWSTR achPath) -{ - size_t iLen = 0; - LPCWSTR lpszIter1 = lpszFile1; - LPCWSTR lpszIter2 = lpszFile2; - - TRACE("(%s,%s,%p)\n", debugstr_w(lpszFile1), debugstr_w(lpszFile2), achPath); - - if (achPath) - *achPath = '\0'; - - if (!lpszFile1 || !lpszFile2) - return 0; - - /* Handle roots first */ - if (PathIsUNCW(lpszFile1)) - { - if (!PathIsUNCW(lpszFile2)) - return 0; - lpszIter1 += 2; - lpszIter2 += 2; - } - else if (PathIsUNCW(lpszFile2)) - return 0; /* Know already lpszFile1 is not UNC */ - - do - { - /* Update len */ - if ((!*lpszIter1 || *lpszIter1 == '\\') && - (!*lpszIter2 || *lpszIter2 == '\\')) - iLen = lpszIter1 - lpszFile1; /* Common to this point */ - - if (!*lpszIter1 || (tolowerW(*lpszIter1) != tolowerW(*lpszIter2))) - break; /* Strings differ at this point */ - - lpszIter1++; - lpszIter2++; - } while (1); - - if (iLen == 2) - iLen++; /* Feature/Bug compatible with Win32 */ - - if (iLen && achPath) - { - memcpy(achPath,lpszFile1,iLen * sizeof(WCHAR)); - achPath[iLen] = '\0'; - } - return iLen; -} - -/************************************************************************* - * PathCompactPathA [SHLWAPI.@] - * - * Make a path fit into a given width when printed to a DC. - * - * PARAMS - * hDc [I] Destination DC - * lpszPath [I/O] Path to be printed to hDc - * dx [I] Desired width - * - * RETURNS - * TRUE If the path was modified/went well. - * FALSE Otherwise. - */ -BOOL WINAPI PathCompactPathA(HDC hDC, LPSTR lpszPath, UINT dx) -{ - BOOL bRet = FALSE; - - TRACE("(%p,%s,%d)\n", hDC, debugstr_a(lpszPath), dx); - - if (lpszPath) - { - WCHAR szPath[MAX_PATH]; - MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH); - bRet = PathCompactPathW(hDC, szPath, dx); - WideCharToMultiByte(CP_ACP,0,szPath,-1,lpszPath,MAX_PATH,0,0); - } - return bRet; -} - -/************************************************************************* - * PathCompactPathW [SHLWAPI.@] - * - * See PathCompactPathA. - */ -BOOL WINAPI PathCompactPathW(HDC hDC, LPWSTR lpszPath, UINT dx) -{ - static const WCHAR szEllipses[] = { '.', '.', '.', '\0' }; - BOOL bRet = TRUE; - HDC hdc = 0; - WCHAR buff[MAX_PATH]; - SIZE size; - DWORD dwLen; - - TRACE("(%p,%s,%d)\n", hDC, debugstr_w(lpszPath), dx); - - if (!lpszPath) - return FALSE; - - if (!hDC) - hdc = hDC = GetDC(0); - - /* Get the length of the whole path */ - dwLen = strlenW(lpszPath); - GetTextExtentPointW(hDC, lpszPath, dwLen, &size); - - if ((UINT)size.cx > dx) - { - /* Path too big, must reduce it */ - LPWSTR sFile; - DWORD dwEllipsesLen = 0, dwPathLen = 0; - - sFile = PathFindFileNameW(lpszPath); - if (sFile != lpszPath) - sFile = CharPrevW(lpszPath, sFile); - - /* Get the size of ellipses */ - GetTextExtentPointW(hDC, szEllipses, 3, &size); - dwEllipsesLen = size.cx; - /* Get the size of the file name */ - GetTextExtentPointW(hDC, sFile, strlenW(sFile), &size); - dwPathLen = size.cx; - - if (sFile != lpszPath) - { - LPWSTR sPath = sFile; - BOOL bEllipses = FALSE; - - /* The path includes a file name. Include as much of the path prior to - * the file name as possible, allowing for the ellipses, e.g: - * c:\some very long path\filename ==> c:\some v...\filename - */ - lstrcpynW(buff, sFile, MAX_PATH); - - do - { - DWORD dwTotalLen = bEllipses? dwPathLen + dwEllipsesLen : dwPathLen; - - GetTextExtentPointW(hDC, lpszPath, sPath - lpszPath, &size); - dwTotalLen += size.cx; - if (dwTotalLen <= dx) - break; - sPath = CharPrevW(lpszPath, sPath); - if (!bEllipses) - { - bEllipses = TRUE; - sPath = CharPrevW(lpszPath, sPath); - sPath = CharPrevW(lpszPath, sPath); - } - } while (sPath > lpszPath); - - if (sPath > lpszPath) - { - if (bEllipses) - { - strcpyW(sPath, szEllipses); - strcpyW(sPath+3, buff); - } - bRet = TRUE; - goto end; - } - strcpyW(lpszPath, szEllipses); - strcpyW(lpszPath+3, buff); - bRet = FALSE; - goto end; - } - - /* Trim the path by adding ellipses to the end, e.g: - * A very long file name.txt ==> A very... - */ - dwLen = strlenW(lpszPath); - - if (dwLen > MAX_PATH - 3) - dwLen = MAX_PATH - 3; - lstrcpynW(buff, sFile, dwLen); - - do { - dwLen--; - GetTextExtentPointW(hDC, buff, dwLen, &size); - } while (dwLen && size.cx + dwEllipsesLen > dx); - - if (!dwLen) - { - DWORD dwWritten = 0; - - dwEllipsesLen /= 3; /* Size of a single '.' */ - - /* Write as much of the Ellipses string as possible */ - while (dwWritten + dwEllipsesLen < dx && dwLen < 3) - { - *lpszPath++ = '.'; - dwWritten += dwEllipsesLen; - dwLen++; - } - *lpszPath = '\0'; - bRet = FALSE; - } - else - { - strcpyW(buff + dwLen, szEllipses); - strcpyW(lpszPath, buff); - } - } - -end: - if (hdc) - ReleaseDC(0, hdc); - - return bRet; -} - -/************************************************************************* - * PathGetCharTypeA [SHLWAPI.@] - * - * Categorise a character from a file path. - * - * PARAMS - * ch [I] Character to get the type of - * - * RETURNS - * A set of GCT_ bit flags (from "shlwapi.h") indicating the character type. - */ -UINT WINAPI PathGetCharTypeA(UCHAR ch) -{ - return PathGetCharTypeW(ch); -} - -/************************************************************************* - * PathGetCharTypeW [SHLWAPI.@] - * - * See PathGetCharTypeA. - */ -UINT WINAPI PathGetCharTypeW(WCHAR ch) -{ - UINT flags = 0; - - TRACE("(%d)\n", ch); - - if (!ch || ch < ' ' || ch == '<' || ch == '>' || - ch == '"' || ch == '|' || ch == '/') - flags = GCT_INVALID; /* Invalid */ - else if (ch == '*' || ch=='?') - flags = GCT_WILD; /* Wildchars */ - else if ((ch == '\\') || (ch == ':')) - return GCT_SEPARATOR; /* Path separators */ - else - { - if (ch < 126) - { - if ((ch & 0x1 && ch != ';') || !ch || isalnum(ch) || ch == '$' || ch == '&' || ch == '(' || - ch == '.' || ch == '@' || ch == '^' || - ch == '\'' || ch == 130 || ch == '`') - flags |= GCT_SHORTCHAR; /* All these are valid for DOS */ - } - else - flags |= GCT_SHORTCHAR; /* Bug compatible with win32 */ - flags |= GCT_LFNCHAR; /* Valid for long file names */ - } - return flags; -} - -/************************************************************************* - * SHLWAPI_UseSystemForSystemFolders - * - * Internal helper for PathMakeSystemFolderW. - */ -static BOOL WINAPI SHLWAPI_UseSystemForSystemFolders() -{ - static BOOL bCheckedReg = FALSE; - static BOOL bUseSystemForSystemFolders = FALSE; - - if (!bCheckedReg) - { - bCheckedReg = TRUE; - - /* Key tells Win what file attributes to use on system folders */ - if (SHGetValueA(HKEY_LOCAL_MACHINE, - "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer", - "UseSystemForSystemFolders", 0, 0, 0)) - bUseSystemForSystemFolders = TRUE; - } - return bUseSystemForSystemFolders; -} - -/************************************************************************* - * PathMakeSystemFolderA [SHLWAPI.@] - * - * Set system folder attribute for a path. - * - * PARAMS - * lpszPath [I] The path to turn into a system folder - * - * RETURNS - * TRUE If the path was changed to/already was a system folder - * FALSE If the path is invalid or SetFileAttributesA() fails - */ -BOOL WINAPI PathMakeSystemFolderA(LPCSTR lpszPath) -{ - BOOL bRet = FALSE; - - TRACE("(%s)\n", debugstr_a(lpszPath)); - - if (lpszPath && *lpszPath) - { - WCHAR szPath[MAX_PATH]; - MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH); - bRet = PathMakeSystemFolderW(szPath); - } - return bRet; -} - -/************************************************************************* - * PathMakeSystemFolderW [SHLWAPI.@] - * - * See PathMakeSystemFolderA. - */ -BOOL WINAPI PathMakeSystemFolderW(LPCWSTR lpszPath) -{ - DWORD dwDefaultAttr = FILE_ATTRIBUTE_READONLY, dwAttr; - WCHAR buff[MAX_PATH]; - - TRACE("(%s)\n", debugstr_w(lpszPath)); - - if (!lpszPath || !*lpszPath) - return FALSE; - - /* If the directory is already a system directory, don't do anything */ - GetSystemDirectoryW(buff, MAX_PATH); - if (!strcmpW(buff, lpszPath)) - return TRUE; - - GetWindowsDirectoryW(buff, MAX_PATH); - if (!strcmpW(buff, lpszPath)) - return TRUE; - - /* "UseSystemForSystemFolders" Tells Win what attributes to use */ - if (SHLWAPI_UseSystemForSystemFolders()) - dwDefaultAttr = FILE_ATTRIBUTE_SYSTEM; - - if ((dwAttr = GetFileAttributesW(lpszPath)) == INVALID_FILE_ATTRIBUTES) - return FALSE; - - /* Change file attributes to system attributes */ - dwAttr &= ~(FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_READONLY); - return SetFileAttributesW(lpszPath, dwAttr | dwDefaultAttr); -} - -/************************************************************************* - * PathRenameExtensionA [SHLWAPI.@] - * - * Swap the file extension in a path with another extension. - * - * PARAMS - * lpszPath [I/O] Path to swap the extension in - * lpszExt [I] The new extension - * - * RETURNS - * TRUE if lpszPath was modified, - * FALSE if lpszPath or lpszExt is NULL, or the new path is too long - */ -BOOL WINAPI PathRenameExtensionA(LPSTR lpszPath, LPCSTR lpszExt) -{ - LPSTR lpszExtension; - - TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszExt)); - - lpszExtension = PathFindExtensionA(lpszPath); - - if (!lpszExtension || (lpszExtension - lpszPath + strlen(lpszExt) >= MAX_PATH)) - return FALSE; - - strcpy(lpszExtension, lpszExt); - return TRUE; -} - -/************************************************************************* - * PathRenameExtensionW [SHLWAPI.@] - * - * See PathRenameExtensionA. - */ -BOOL WINAPI PathRenameExtensionW(LPWSTR lpszPath, LPCWSTR lpszExt) -{ - LPWSTR lpszExtension; - - TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszExt)); - - lpszExtension = PathFindExtensionW(lpszPath); - - if (!lpszExtension || (lpszExtension - lpszPath + strlenW(lpszExt) >= MAX_PATH)) - return FALSE; - - strcpyW(lpszExtension, lpszExt); - return TRUE; -} - -/************************************************************************* - * PathSearchAndQualifyA [SHLWAPI.@] - * - * Determine if a given path is correct and fully qualified. - * - * PARAMS - * lpszPath [I] Path to check - * lpszBuf [O] Output for correct path - * cchBuf [I] Size of lpszBuf - * - * RETURNS - * Unknown. - */ -BOOL WINAPI PathSearchAndQualifyA(LPCSTR lpszPath, LPSTR lpszBuf, UINT cchBuf) -{ - TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszPath), lpszBuf, cchBuf); - - if(SearchPathA(NULL, lpszPath, NULL, cchBuf, lpszBuf, NULL)) - return TRUE; - return !!GetFullPathNameA(lpszPath, cchBuf, lpszBuf, NULL); -} - -/************************************************************************* - * PathSearchAndQualifyW [SHLWAPI.@] - * - * See PathSearchAndQualifyA. - */ -BOOL WINAPI PathSearchAndQualifyW(LPCWSTR lpszPath, LPWSTR lpszBuf, UINT cchBuf) -{ - TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszPath), lpszBuf, cchBuf); - - if(SearchPathW(NULL, lpszPath, NULL, cchBuf, lpszBuf, NULL)) - return TRUE; - return !!GetFullPathNameW(lpszPath, cchBuf, lpszBuf, NULL); -} - -/************************************************************************* - * PathSkipRootA [SHLWAPI.@] - * - * Return the portion of a path following the drive letter or mount point. - * - * PARAMS - * lpszPath [I] The path to skip on - * - * RETURNS - * Success: A pointer to the next character after the root. - * Failure: NULL, if lpszPath is invalid, has no root or is a multibyte string. - */ -LPSTR WINAPI PathSkipRootA(LPCSTR lpszPath) -{ - TRACE("(%s)\n", debugstr_a(lpszPath)); - - if (!lpszPath || !*lpszPath) - return NULL; - - if (*lpszPath == '\\' && lpszPath[1] == '\\') - { - /* Network share: skip share server and mount point */ - lpszPath += 2; - if ((lpszPath = StrChrA(lpszPath, '\\')) && - (lpszPath = StrChrA(lpszPath + 1, '\\'))) - lpszPath++; - return (LPSTR)lpszPath; - } - - if (IsDBCSLeadByte(*lpszPath)) - return NULL; - - /* Check x:\ */ - if (lpszPath[0] && lpszPath[1] == ':' && lpszPath[2] == '\\') - return (LPSTR)lpszPath + 3; - return NULL; -} - -/************************************************************************* - * PathSkipRootW [SHLWAPI.@] - * - * See PathSkipRootA. - */ -LPWSTR WINAPI PathSkipRootW(LPCWSTR lpszPath) -{ - TRACE("(%s)\n", debugstr_w(lpszPath)); - - if (!lpszPath || !*lpszPath) - return NULL; - - if (*lpszPath == '\\' && lpszPath[1] == '\\') - { - /* Network share: skip share server and mount point */ - lpszPath += 2; - if ((lpszPath = StrChrW(lpszPath, '\\')) && - (lpszPath = StrChrW(lpszPath + 1, '\\'))) - lpszPath++; - return (LPWSTR)lpszPath; - } - - /* Check x:\ */ - if (lpszPath[0] && lpszPath[1] == ':' && lpszPath[2] == '\\') - return (LPWSTR)lpszPath + 3; - return NULL; -} - -/************************************************************************* - * PathCreateFromUrlA [SHLWAPI.@] - * - * See PathCreateFromUrlW - */ -HRESULT WINAPI PathCreateFromUrlA(LPCSTR pszUrl, LPSTR pszPath, - LPDWORD pcchPath, DWORD dwReserved) -{ - WCHAR bufW[MAX_PATH]; - WCHAR *pathW = bufW; - UNICODE_STRING urlW; - HRESULT ret; - DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA; - - if(!RtlCreateUnicodeStringFromAsciiz(&urlW, pszUrl)) - return E_INVALIDARG; - if((ret = PathCreateFromUrlW(urlW.Buffer, pathW, &lenW, dwReserved)) == E_POINTER) { - pathW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR)); - ret = PathCreateFromUrlW(urlW.Buffer, pathW, &lenW, dwReserved); - } - if(ret == S_OK) { - RtlUnicodeToMultiByteSize(&lenA, pathW, lenW * sizeof(WCHAR)); - if(*pcchPath > lenA) { - RtlUnicodeToMultiByteN(pszPath, *pcchPath - 1, &lenA, pathW, lenW * sizeof(WCHAR)); - pszPath[lenA] = 0; - *pcchPath = lenA; - } else { - *pcchPath = lenA + 1; - ret = E_POINTER; - } - } - if(pathW != bufW) HeapFree(GetProcessHeap(), 0, pathW); - RtlFreeUnicodeString(&urlW); - return ret; -} - -/************************************************************************* - * PathCreateFromUrlW [SHLWAPI.@] - * - * Create a path from a URL - * - * PARAMS - * lpszUrl [I] URL to convert into a path - * lpszPath [O] Output buffer for the resulting Path - * pcchPath [I] Length of lpszPath - * dwFlags [I] Flags controlling the conversion - * - * RETURNS - * Success: S_OK. lpszPath contains the URL in path format, - * Failure: An HRESULT error code such as E_INVALIDARG. - */ -HRESULT WINAPI PathCreateFromUrlW(LPCWSTR pszUrl, LPWSTR pszPath, - LPDWORD pcchPath, DWORD dwReserved) -{ - static const WCHAR file_colon[] = { 'f','i','l','e',':',0 }; - HRESULT hr; - DWORD nslashes = 0; - WCHAR *ptr; - - TRACE("(%s,%p,%p,0x%08lx)\n", debugstr_w(pszUrl), pszPath, pcchPath, dwReserved); - - if (!pszUrl || !pszPath || !pcchPath || !*pcchPath) - return E_INVALIDARG; - - - if (strncmpW(pszUrl, file_colon, 5)) - return E_INVALIDARG; - pszUrl += 5; - - while(*pszUrl == '/' || *pszUrl == '\\') { - nslashes++; - pszUrl++; - } - - if(isalphaW(*pszUrl) && (pszUrl[1] == ':' || pszUrl[1] == '|') && (pszUrl[2] == '/' || pszUrl[2] == '\\')) - nslashes = 0; - - switch(nslashes) { - case 2: - pszUrl -= 2; - break; - case 0: - break; - default: - pszUrl -= 1; - break; - } - - hr = UrlUnescapeW((LPWSTR)pszUrl, pszPath, pcchPath, 0); - if(hr != S_OK) return hr; - - for(ptr = pszPath; *ptr; ptr++) - if(*ptr == '/') *ptr = '\\'; - - while(*pszPath == '\\') - pszPath++; - - if(isalphaW(*pszPath) && pszPath[1] == '|' && pszPath[2] == '\\') /* c|\ -> c:\ */ - pszPath[1] = ':'; - - if(nslashes == 2 && (ptr = strchrW(pszPath, '\\'))) { /* \\host\c:\ -> \\hostc:\ */ - ptr++; - if(isalphaW(*ptr) && (ptr[1] == ':' || ptr[1] == '|') && ptr[2] == '\\') { - memmove(ptr - 1, ptr, (strlenW(ptr) + 1) * sizeof(WCHAR)); - (*pcchPath)--; - } - } - - TRACE("Returning %s\n",debugstr_w(pszPath)); - - return hr; -} - -/************************************************************************* - * PathRelativePathToA [SHLWAPI.@] - * - * Create a relative path from one path to another. - * - * PARAMS - * lpszPath [O] Destination for relative path - * lpszFrom [I] Source path - * dwAttrFrom [I] File attribute of source path - * lpszTo [I] Destination path - * dwAttrTo [I] File attributes of destination path - * - * RETURNS - * TRUE If a relative path can be formed. lpszPath contains the new path - * FALSE If the paths are not relavtive or any parameters are invalid - * - * NOTES - * lpszTo should be at least MAX_PATH in length. - * - * Calling this function with relative paths for lpszFrom or lpszTo may - * give erroneous results. - * - * The Win32 version of this function contains a bug where the lpszTo string - * may be referenced 1 byte beyond the end of the string. As a result random - * garbage may be written to the output path, depending on what lies beyond - * the last byte of the string. This bug occurs because of the behaviour of - * PathCommonPrefix() (see notes for that function), and no workaround seems - * possible with Win32. - * - * This bug has been fixed here, so for example the relative path from "\\" - * to "\\" is correctly determined as "." in this implementation. - */ -BOOL WINAPI PathRelativePathToA(LPSTR lpszPath, LPCSTR lpszFrom, DWORD dwAttrFrom, - LPCSTR lpszTo, DWORD dwAttrTo) -{ - BOOL bRet = FALSE; - - TRACE("(%p,%s,0x%08lx,%s,0x%08lx)\n", lpszPath, debugstr_a(lpszFrom), - dwAttrFrom, debugstr_a(lpszTo), dwAttrTo); - - if(lpszPath && lpszFrom && lpszTo) - { - WCHAR szPath[MAX_PATH]; - WCHAR szFrom[MAX_PATH]; - WCHAR szTo[MAX_PATH]; - MultiByteToWideChar(CP_ACP,0,lpszFrom,-1,szFrom,MAX_PATH); - MultiByteToWideChar(CP_ACP,0,lpszTo,-1,szTo,MAX_PATH); - bRet = PathRelativePathToW(szPath,szFrom,dwAttrFrom,szTo,dwAttrTo); - WideCharToMultiByte(CP_ACP,0,szPath,-1,lpszPath,MAX_PATH,0,0); - } - return bRet; -} - -/************************************************************************* - * PathRelativePathToW [SHLWAPI.@] - * - * See PathRelativePathToA. - */ -BOOL WINAPI PathRelativePathToW(LPWSTR lpszPath, LPCWSTR lpszFrom, DWORD dwAttrFrom, - LPCWSTR lpszTo, DWORD dwAttrTo) -{ - static const WCHAR szPrevDirSlash[] = { '.', '.', '\\', '\0' }; - static const WCHAR szPrevDir[] = { '.', '.', '\0' }; - WCHAR szFrom[MAX_PATH]; - WCHAR szTo[MAX_PATH]; - DWORD dwLen; - - TRACE("(%p,%s,0x%08lx,%s,0x%08lx)\n", lpszPath, debugstr_w(lpszFrom), - dwAttrFrom, debugstr_w(lpszTo), dwAttrTo); - - if(!lpszPath || !lpszFrom || !lpszTo) - return FALSE; - - *lpszPath = '\0'; - lstrcpynW(szFrom, lpszFrom, MAX_PATH); - lstrcpynW(szTo, lpszTo, MAX_PATH); - - if(!(dwAttrFrom & FILE_ATTRIBUTE_DIRECTORY)) - PathRemoveFileSpecW(szFrom); - if(!(dwAttrFrom & FILE_ATTRIBUTE_DIRECTORY)) - PathRemoveFileSpecW(szTo); - - /* Paths can only be relative if they have a common root */ - if(!(dwLen = PathCommonPrefixW(szFrom, szTo, 0))) - return FALSE; - - /* Strip off lpszFrom components to the root, by adding "..\" */ - lpszFrom = szFrom + dwLen; - if (!*lpszFrom) - { - lpszPath[0] = '.'; - lpszPath[1] = '\0'; - } - if (*lpszFrom == '\\') - lpszFrom++; - - while (*lpszFrom) - { - lpszFrom = PathFindNextComponentW(lpszFrom); - strcatW(lpszPath, *lpszFrom ? szPrevDirSlash : szPrevDir); - } - - /* From the root add the components of lpszTo */ - lpszTo += dwLen; - /* We check lpszTo[-1] to avoid skipping end of string. See the notes for - * this function. - */ - if (*lpszTo && lpszTo[-1]) - { - if (*lpszTo != '\\') - lpszTo--; - dwLen = strlenW(lpszPath); - if (dwLen + strlenW(lpszTo) >= MAX_PATH) - { - *lpszPath = '\0'; - return FALSE; - } - strcpyW(lpszPath + dwLen, lpszTo); - } - return TRUE; -} - -/************************************************************************* - * PathUnmakeSystemFolderA [SHLWAPI.@] - * - * Remove the system folder attributes from a path. - * - * PARAMS - * lpszPath [I] The path to remove attributes from - * - * RETURNS - * Success: TRUE. - * Failure: FALSE, if lpszPath is NULL, empty, not a directory, or calling - * SetFileAttributesA() fails. - */ -BOOL WINAPI PathUnmakeSystemFolderA(LPCSTR lpszPath) -{ - DWORD dwAttr; - - TRACE("(%s)\n", debugstr_a(lpszPath)); - - if (!lpszPath || !*lpszPath || (dwAttr = GetFileAttributesA(lpszPath)) == INVALID_FILE_ATTRIBUTES || - !(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) - return FALSE; - - dwAttr &= ~(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM); - return SetFileAttributesA(lpszPath, dwAttr); -} - -/************************************************************************* - * PathUnmakeSystemFolderW [SHLWAPI.@] - * - * See PathUnmakeSystemFolderA. - */ -BOOL WINAPI PathUnmakeSystemFolderW(LPCWSTR lpszPath) -{ - DWORD dwAttr; - - TRACE("(%s)\n", debugstr_w(lpszPath)); - - if (!lpszPath || !*lpszPath || (dwAttr = GetFileAttributesW(lpszPath)) == INVALID_FILE_ATTRIBUTES || - !(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) - return FALSE; - - dwAttr &= ~(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM); - return SetFileAttributesW(lpszPath, dwAttr); -} - - -/************************************************************************* - * PathSetDlgItemPathA [SHLWAPI.@] - * - * Set the text of a dialog item to a path, shrinking the path to fit - * if it is too big for the item. - * - * PARAMS - * hDlg [I] Dialog handle - * id [I] ID of item in the dialog - * lpszPath [I] Path to set as the items text - * - * RETURNS - * Nothing. - * - * NOTES - * If lpszPath is NULL, a blank string ("") is set (i.e. The previous - * window text is erased). - */ -VOID WINAPI PathSetDlgItemPathA(HWND hDlg, int id, LPCSTR lpszPath) -{ - WCHAR szPath[MAX_PATH]; - - TRACE("(%p,%8x,%s)\n",hDlg, id, debugstr_a(lpszPath)); - - if (lpszPath) - MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH); - else - szPath[0] = '\0'; - PathSetDlgItemPathW(hDlg, id, szPath); -} - -/************************************************************************* - * PathSetDlgItemPathW [SHLWAPI.@] - * - * See PathSetDlgItemPathA. - */ -VOID WINAPI PathSetDlgItemPathW(HWND hDlg, int id, LPCWSTR lpszPath) -{ - WCHAR path[MAX_PATH + 1]; - HWND hwItem; - RECT rect; - HDC hdc; - HGDIOBJ hPrevObj; - - TRACE("(%p,%8x,%s)\n",hDlg, id, debugstr_w(lpszPath)); - - if (!(hwItem = GetDlgItem(hDlg, id))) - return; - - if (lpszPath) - lstrcpynW(path, lpszPath, sizeof(path) / sizeof(WCHAR)); - else - path[0] = '\0'; - - GetClientRect(hwItem, &rect); - hdc = GetDC(hDlg); - hPrevObj = SelectObject(hdc, (HGDIOBJ)SendMessageW(hwItem,WM_GETFONT,0,0)); - - if (hPrevObj) - { - PathCompactPathW(hdc, path, rect.right); - SelectObject(hdc, hPrevObj); - } - - ReleaseDC(hDlg, hdc); - SetWindowTextW(hwItem, path); -} - -/************************************************************************* - * PathIsNetworkPathA [SHLWAPI.@] - * - * Determine if the given path is a network path. - * - * PARAMS - * lpszPath [I] Path to check - * - * RETURNS - * TRUE If lpszPath is a UNC share or mapped network drive, or - * FALSE If lpszPath is a local drive or cannot be determined - */ -BOOL WINAPI PathIsNetworkPathA(LPCSTR lpszPath) -{ - int dwDriveNum; - - TRACE("(%s)\n",debugstr_a(lpszPath)); - - if (!lpszPath) - return FALSE; - if (*lpszPath == '\\' && lpszPath[1] == '\\') - return TRUE; - dwDriveNum = PathGetDriveNumberA(lpszPath); - if (dwDriveNum == -1) - return FALSE; - GET_FUNC(pIsNetDrive, shell32, (LPCSTR)66, FALSE); /* ord 66 = shell32.IsNetDrive */ - return pIsNetDrive(dwDriveNum); -} - -/************************************************************************* - * PathIsNetworkPathW [SHLWAPI.@] - * - * See PathIsNetworkPathA. - */ -BOOL WINAPI PathIsNetworkPathW(LPCWSTR lpszPath) -{ - int dwDriveNum; - - TRACE("(%s)\n", debugstr_w(lpszPath)); - - if (!lpszPath) - return FALSE; - if (*lpszPath == '\\' && lpszPath[1] == '\\') - return TRUE; - dwDriveNum = PathGetDriveNumberW(lpszPath); - if (dwDriveNum == -1) - return FALSE; - GET_FUNC(pIsNetDrive, shell32, (LPCSTR)66, FALSE); /* ord 66 = shell32.IsNetDrive */ - return pIsNetDrive(dwDriveNum); -} - -/************************************************************************* - * PathIsLFNFileSpecA [SHLWAPI.@] - * - * Determine if the given path is a long file name - * - * PARAMS - * lpszPath [I] Path to check - * - * RETURNS - * TRUE If path is a long file name, - * FALSE If path is a valid DOS short file name - */ -BOOL WINAPI PathIsLFNFileSpecA(LPCSTR lpszPath) -{ - DWORD dwNameLen = 0, dwExtLen = 0; - - TRACE("(%s)\n",debugstr_a(lpszPath)); - - if (!lpszPath) - return FALSE; - - while (*lpszPath) - { - if (*lpszPath == ' ') - return TRUE; /* DOS names cannot have spaces */ - if (*lpszPath == '.') - { - if (dwExtLen) - return TRUE; /* DOS names have only one dot */ - dwExtLen = 1; - } - else if (dwExtLen) - { - dwExtLen++; - if (dwExtLen > 4) - return TRUE; /* DOS extensions are <= 3 chars*/ - } - else - { - dwNameLen++; - if (dwNameLen > 8) - return TRUE; /* DOS names are <= 8 chars */ - } - lpszPath += IsDBCSLeadByte(*lpszPath) ? 2 : 1; - } - return FALSE; /* Valid DOS path */ -} - -/************************************************************************* - * PathIsLFNFileSpecW [SHLWAPI.@] - * - * See PathIsLFNFileSpecA. - */ -BOOL WINAPI PathIsLFNFileSpecW(LPCWSTR lpszPath) -{ - DWORD dwNameLen = 0, dwExtLen = 0; - - TRACE("(%s)\n",debugstr_w(lpszPath)); - - if (!lpszPath) - return FALSE; - - while (*lpszPath) - { - if (*lpszPath == ' ') - return TRUE; /* DOS names cannot have spaces */ - if (*lpszPath == '.') - { - if (dwExtLen) - return TRUE; /* DOS names have only one dot */ - dwExtLen = 1; - } - else if (dwExtLen) - { - dwExtLen++; - if (dwExtLen > 4) - return TRUE; /* DOS extensions are <= 3 chars*/ - } - else - { - dwNameLen++; - if (dwNameLen > 8) - return TRUE; /* DOS names are <= 8 chars */ - } - lpszPath++; - } - return FALSE; /* Valid DOS path */ -} - -/************************************************************************* - * PathIsDirectoryEmptyA [SHLWAPI.@] - * - * Determine if a given directory is empty. - * - * PARAMS - * lpszPath [I] Directory to check - * - * RETURNS - * TRUE If the directory exists and contains no files, - * FALSE Otherwise - */ -BOOL WINAPI PathIsDirectoryEmptyA(LPCSTR lpszPath) -{ - BOOL bRet = FALSE; - - TRACE("(%s)\n",debugstr_a(lpszPath)); - - if (lpszPath) - { - WCHAR szPath[MAX_PATH]; - MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH); - bRet = PathIsDirectoryEmptyW(szPath); - } - return bRet; -} - -/************************************************************************* - * PathIsDirectoryEmptyW [SHLWAPI.@] - * - * See PathIsDirectoryEmptyA. - */ -BOOL WINAPI PathIsDirectoryEmptyW(LPCWSTR lpszPath) -{ - static const WCHAR szAllFiles[] = { '*', '.', '*', '\0' }; - WCHAR szSearch[MAX_PATH]; - DWORD dwLen; - HANDLE hfind; - BOOL retVal = FALSE; - WIN32_FIND_DATAW find_data; - - TRACE("(%s)\n",debugstr_w(lpszPath)); - - if (!lpszPath || !PathIsDirectoryW(lpszPath)) - return FALSE; - - lstrcpynW(szSearch, lpszPath, MAX_PATH); - PathAddBackslashW(szSearch); - dwLen = strlenW(szSearch); - if (dwLen > MAX_PATH - 4) - return FALSE; - - strcpyW(szSearch + dwLen, szAllFiles); - hfind = FindFirstFileW(szSearch, &find_data); - - if (hfind != INVALID_HANDLE_VALUE && - find_data.cFileName[0] == '.' && - find_data.cFileName[1] == '.') - { - /* The only directory entry should be the parent */ - if (!FindNextFileW(hfind, &find_data)) - retVal = TRUE; - FindClose(hfind); - } - return retVal; -} - - -/************************************************************************* - * PathFindSuffixArrayA [SHLWAPI.@] - * - * Find a suffix string in an array of suffix strings - * - * PARAMS - * lpszSuffix [I] Suffix string to search for - * lppszArray [I] Array of suffix strings to search - * dwCount [I] Number of elements in lppszArray - * - * RETURNS - * Success: The index of the position of lpszSuffix in lppszArray - * Failure: 0, if any parameters are invalid or lpszSuffix is not found - * - * NOTES - * The search is case sensitive. - * The match is made against the end of the suffix string, so for example: - * lpszSuffix="fooBAR" matches "BAR", but lpszSuffix="fooBARfoo" does not. - */ -LPCSTR WINAPI PathFindSuffixArrayA(LPCSTR lpszSuffix, LPCSTR *lppszArray, int dwCount) -{ - size_t dwLen; - int dwRet = 0; - - TRACE("(%s,%p,%d)\n",debugstr_a(lpszSuffix), lppszArray, dwCount); - - if (lpszSuffix && lppszArray && dwCount > 0) - { - dwLen = strlen(lpszSuffix); - - while (dwRet < dwCount) - { - size_t dwCompareLen = strlen(*lppszArray); - if (dwCompareLen < dwLen) - { - if (!strcmp(lpszSuffix + dwLen - dwCompareLen, *lppszArray)) - return *lppszArray; /* Found */ - } - dwRet++; - lppszArray++; - } - } - return NULL; -} - -/************************************************************************* - * PathFindSuffixArrayW [SHLWAPI.@] - * - * See PathFindSuffixArrayA. - */ -LPCWSTR WINAPI PathFindSuffixArrayW(LPCWSTR lpszSuffix, LPCWSTR *lppszArray, int dwCount) -{ - size_t dwLen; - int dwRet = 0; - - TRACE("(%s,%p,%d)\n",debugstr_w(lpszSuffix), lppszArray, dwCount); - - if (lpszSuffix && lppszArray && dwCount > 0) - { - dwLen = strlenW(lpszSuffix); - - while (dwRet < dwCount) - { - size_t dwCompareLen = strlenW(*lppszArray); - if (dwCompareLen < dwLen) - { - if (!strcmpW(lpszSuffix + dwLen - dwCompareLen, *lppszArray)) - return *lppszArray; /* Found */ - } - dwRet++; - lppszArray++; - } - } - return NULL; -} - -/************************************************************************* - * PathUndecorateA [SHLWAPI.@] - * - * Undecorate a file path - * - * PARAMS - * lpszPath [I/O] Path to remove any decoration from - * - * RETURNS - * Nothing - * - * NOTES - * A decorations form is "path[n].ext" where "n" is an optional decimal number. - */ -VOID WINAPI PathUndecorateA(LPSTR lpszPath) -{ - TRACE("(%s)\n",debugstr_a(lpszPath)); - - if (lpszPath) - { - LPSTR lpszExt = PathFindExtensionA(lpszPath); - if (lpszExt > lpszPath && lpszExt[-1] == ']') - { - LPSTR lpszSkip = lpszExt - 2; - if (*lpszSkip == '[') - lpszSkip++; /* [] (no number) */ - else - while (lpszSkip > lpszPath && isdigit(lpszSkip[-1])) - lpszSkip--; - if (lpszSkip > lpszPath && lpszSkip[-1] == '[' && lpszSkip[-2] != '\\') - { - /* remove the [n] */ - lpszSkip--; - while (*lpszExt) - *lpszSkip++ = *lpszExt++; - *lpszSkip = '\0'; - } - } - } -} - -/************************************************************************* - * PathUndecorateW [SHLWAPI.@] - * - * See PathUndecorateA. - */ -VOID WINAPI PathUndecorateW(LPWSTR lpszPath) -{ - TRACE("(%s)\n",debugstr_w(lpszPath)); - - if (lpszPath) - { - LPWSTR lpszExt = PathFindExtensionW(lpszPath); - if (lpszExt > lpszPath && lpszExt[-1] == ']') - { - LPWSTR lpszSkip = lpszExt - 2; - if (*lpszSkip == '[') - lpszSkip++; /* [] (no number) */ - else - while (lpszSkip > lpszPath && isdigitW(lpszSkip[-1])) - lpszSkip--; - if (lpszSkip > lpszPath && lpszSkip[-1] == '[' && lpszSkip[-2] != '\\') - { - /* remove the [n] */ - lpszSkip--; - while (*lpszExt) - *lpszSkip++ = *lpszExt++; - *lpszSkip = '\0'; - } - } - } -} - -/************************************************************************* - * PathUnExpandEnvStringsA [SHLWAPI.@] - * - * Substitute folder names in a path with their corresponding environment - * strings. - * - * PARAMS - * pszPath [I] Buffer containing the path to unexpand. - * pszBuf [O] Buffer to receive the unexpanded path. - * cchBuf [I] Size of pszBuf in characters. - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI PathUnExpandEnvStringsA(LPCSTR pszPath, LPSTR pszBuf, UINT cchBuf) -{ - FIXME("(%s,%s,0x%08x)\n", debugstr_a(pszPath), debugstr_a(pszBuf), cchBuf); - return FALSE; -} - -/************************************************************************* - * PathUnExpandEnvStringsW [SHLWAPI.@] - * - * Unicode version of PathUnExpandEnvStringsA. - */ -BOOL WINAPI PathUnExpandEnvStringsW(LPCWSTR pszPath, LPWSTR pszBuf, UINT cchBuf) -{ - FIXME("(%s,%s,0x%08x)\n", debugstr_w(pszPath), debugstr_w(pszBuf), cchBuf); - return FALSE; -} - -/************************************************************************* - * @ [SHLWAPI.440] - * - * Find localised or default web content in "%WINDOWS%\web\". - * - * PARAMS - * lpszFile [I] File name containing content to look for - * lpszPath [O] Buffer to contain the full path to the file - * dwPathLen [I] Length of lpszPath - * - * RETURNS - * Success: S_OK. lpszPath contains the full path to the content. - * Failure: E_FAIL. The content does not exist or lpszPath is too short. - */ -HRESULT WINAPI SHGetWebFolderFilePathA(LPCSTR lpszFile, LPSTR lpszPath, DWORD dwPathLen) -{ - WCHAR szFile[MAX_PATH], szPath[MAX_PATH]; - HRESULT hRet; - - TRACE("(%s,%p,%ld)\n", lpszFile, lpszPath, dwPathLen); - - MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, szFile, MAX_PATH); - szPath[0] = '\0'; - hRet = SHGetWebFolderFilePathW(szFile, szPath, dwPathLen); - WideCharToMultiByte(CP_ACP, 0, szPath, -1, lpszPath, dwPathLen, 0, 0); - return hRet; -} - -/************************************************************************* - * @ [SHLWAPI.441] - * - * Unicode version of SHGetWebFolderFilePathA. - */ -HRESULT WINAPI SHGetWebFolderFilePathW(LPCWSTR lpszFile, LPWSTR lpszPath, DWORD dwPathLen) -{ - static const WCHAR szWeb[] = {'\\','W','e','b','\\','\0'}; - static const WCHAR szWebMui[] = {'m','u','i','\\','%','0','4','x','\\','\0'}; -#define szWebLen (sizeof(szWeb)/sizeof(WCHAR)) -#define szWebMuiLen ((sizeof(szWebMui)+1)/sizeof(WCHAR)) - DWORD dwLen, dwFileLen; - LANGID lidSystem, lidUser; - - TRACE("(%s,%p,%ld)\n", debugstr_w(lpszFile), lpszPath, dwPathLen); - - /* Get base directory for web content */ - dwLen = GetSystemWindowsDirectoryW(lpszPath, dwPathLen); - if (dwLen > 0 && lpszPath[dwLen-1] == '\\') - dwLen--; - - dwFileLen = strlenW(lpszFile); - - if (dwLen + dwFileLen + szWebLen >= dwPathLen) - return E_FAIL; /* lpszPath too short */ - - strcpyW(lpszPath+dwLen, szWeb); - dwLen += szWebLen; - dwPathLen = dwPathLen - dwLen; /* Remaining space */ - - lidSystem = GetSystemDefaultUILanguage(); - lidUser = GetUserDefaultUILanguage(); - - if (lidSystem != lidUser) - { - if (dwFileLen + szWebMuiLen < dwPathLen) - { - /* Use localised content in the users UI language if present */ - wsprintfW(lpszPath + dwLen, szWebMui, lidUser); - strcpyW(lpszPath + dwLen + szWebMuiLen, lpszFile); - if (PathFileExistsW(lpszPath)) - return S_OK; - } - } - - /* Fall back to OS default installed content */ - strcpyW(lpszPath + dwLen, lpszFile); - if (PathFileExistsW(lpszPath)) - return S_OK; - return E_FAIL; -} - -#define PATH_CHAR_CLASS_LETTER 0x00000001 -#define PATH_CHAR_CLASS_ASTERIX 0x00000002 -#define PATH_CHAR_CLASS_DOT 0x00000004 -#define PATH_CHAR_CLASS_BACKSLASH 0x00000008 -#define PATH_CHAR_CLASS_COLON 0x00000010 -#define PATH_CHAR_CLASS_SEMICOLON 0x00000020 -#define PATH_CHAR_CLASS_COMMA 0x00000040 -#define PATH_CHAR_CLASS_SPACE 0x00000080 -#define PATH_CHAR_CLASS_OTHER_VALID 0x00000100 -#define PATH_CHAR_CLASS_DOUBLEQUOTE 0x00000200 - -#define PATH_CHAR_CLASS_INVALID 0x00000000 -#define PATH_CHAR_CLASS_ANY 0xffffffff - -static const DWORD SHELL_charclass[] = -{ - /* 0x00 */ PATH_CHAR_CLASS_INVALID, /* 0x01 */ PATH_CHAR_CLASS_INVALID, - /* 0x02 */ PATH_CHAR_CLASS_INVALID, /* 0x03 */ PATH_CHAR_CLASS_INVALID, - /* 0x04 */ PATH_CHAR_CLASS_INVALID, /* 0x05 */ PATH_CHAR_CLASS_INVALID, - /* 0x06 */ PATH_CHAR_CLASS_INVALID, /* 0x07 */ PATH_CHAR_CLASS_INVALID, - /* 0x08 */ PATH_CHAR_CLASS_INVALID, /* 0x09 */ PATH_CHAR_CLASS_INVALID, - /* 0x0a */ PATH_CHAR_CLASS_INVALID, /* 0x0b */ PATH_CHAR_CLASS_INVALID, - /* 0x0c */ PATH_CHAR_CLASS_INVALID, /* 0x0d */ PATH_CHAR_CLASS_INVALID, - /* 0x0e */ PATH_CHAR_CLASS_INVALID, /* 0x0f */ PATH_CHAR_CLASS_INVALID, - /* 0x10 */ PATH_CHAR_CLASS_INVALID, /* 0x11 */ PATH_CHAR_CLASS_INVALID, - /* 0x12 */ PATH_CHAR_CLASS_INVALID, /* 0x13 */ PATH_CHAR_CLASS_INVALID, - /* 0x14 */ PATH_CHAR_CLASS_INVALID, /* 0x15 */ PATH_CHAR_CLASS_INVALID, - /* 0x16 */ PATH_CHAR_CLASS_INVALID, /* 0x17 */ PATH_CHAR_CLASS_INVALID, - /* 0x18 */ PATH_CHAR_CLASS_INVALID, /* 0x19 */ PATH_CHAR_CLASS_INVALID, - /* 0x1a */ PATH_CHAR_CLASS_INVALID, /* 0x1b */ PATH_CHAR_CLASS_INVALID, - /* 0x1c */ PATH_CHAR_CLASS_INVALID, /* 0x1d */ PATH_CHAR_CLASS_INVALID, - /* 0x1e */ PATH_CHAR_CLASS_INVALID, /* 0x1f */ PATH_CHAR_CLASS_INVALID, - /* ' ' */ PATH_CHAR_CLASS_SPACE, /* '!' */ PATH_CHAR_CLASS_OTHER_VALID, - /* '"' */ PATH_CHAR_CLASS_DOUBLEQUOTE, /* '#' */ PATH_CHAR_CLASS_OTHER_VALID, - /* '$' */ PATH_CHAR_CLASS_OTHER_VALID, /* '%' */ PATH_CHAR_CLASS_OTHER_VALID, - /* '&' */ PATH_CHAR_CLASS_OTHER_VALID, /* '\'' */ PATH_CHAR_CLASS_OTHER_VALID, - /* '(' */ PATH_CHAR_CLASS_OTHER_VALID, /* ')' */ PATH_CHAR_CLASS_OTHER_VALID, - /* '*' */ PATH_CHAR_CLASS_ASTERIX, /* '+' */ PATH_CHAR_CLASS_OTHER_VALID, - /* ',' */ PATH_CHAR_CLASS_COMMA, /* '-' */ PATH_CHAR_CLASS_OTHER_VALID, - /* '.' */ PATH_CHAR_CLASS_DOT, /* '/' */ PATH_CHAR_CLASS_INVALID, - /* '0' */ PATH_CHAR_CLASS_OTHER_VALID, /* '1' */ PATH_CHAR_CLASS_OTHER_VALID, - /* '2' */ PATH_CHAR_CLASS_OTHER_VALID, /* '3' */ PATH_CHAR_CLASS_OTHER_VALID, - /* '4' */ PATH_CHAR_CLASS_OTHER_VALID, /* '5' */ PATH_CHAR_CLASS_OTHER_VALID, - /* '6' */ PATH_CHAR_CLASS_OTHER_VALID, /* '7' */ PATH_CHAR_CLASS_OTHER_VALID, - /* '8' */ PATH_CHAR_CLASS_OTHER_VALID, /* '9' */ PATH_CHAR_CLASS_OTHER_VALID, - /* ':' */ PATH_CHAR_CLASS_COLON, /* ';' */ PATH_CHAR_CLASS_SEMICOLON, - /* '<' */ PATH_CHAR_CLASS_INVALID, /* '=' */ PATH_CHAR_CLASS_OTHER_VALID, - /* '>' */ PATH_CHAR_CLASS_INVALID, /* '?' */ PATH_CHAR_CLASS_LETTER, - /* '@' */ PATH_CHAR_CLASS_OTHER_VALID, /* 'A' */ PATH_CHAR_CLASS_ANY, - /* 'B' */ PATH_CHAR_CLASS_ANY, /* 'C' */ PATH_CHAR_CLASS_ANY, - /* 'D' */ PATH_CHAR_CLASS_ANY, /* 'E' */ PATH_CHAR_CLASS_ANY, - /* 'F' */ PATH_CHAR_CLASS_ANY, /* 'G' */ PATH_CHAR_CLASS_ANY, - /* 'H' */ PATH_CHAR_CLASS_ANY, /* 'I' */ PATH_CHAR_CLASS_ANY, - /* 'J' */ PATH_CHAR_CLASS_ANY, /* 'K' */ PATH_CHAR_CLASS_ANY, - /* 'L' */ PATH_CHAR_CLASS_ANY, /* 'M' */ PATH_CHAR_CLASS_ANY, - /* 'N' */ PATH_CHAR_CLASS_ANY, /* 'O' */ PATH_CHAR_CLASS_ANY, - /* 'P' */ PATH_CHAR_CLASS_ANY, /* 'Q' */ PATH_CHAR_CLASS_ANY, - /* 'R' */ PATH_CHAR_CLASS_ANY, /* 'S' */ PATH_CHAR_CLASS_ANY, - /* 'T' */ PATH_CHAR_CLASS_ANY, /* 'U' */ PATH_CHAR_CLASS_ANY, - /* 'V' */ PATH_CHAR_CLASS_ANY, /* 'W' */ PATH_CHAR_CLASS_ANY, - /* 'X' */ PATH_CHAR_CLASS_ANY, /* 'Y' */ PATH_CHAR_CLASS_ANY, - /* 'Z' */ PATH_CHAR_CLASS_ANY, /* '[' */ PATH_CHAR_CLASS_OTHER_VALID, - /* '\\' */ PATH_CHAR_CLASS_BACKSLASH, /* ']' */ PATH_CHAR_CLASS_OTHER_VALID, - /* '^' */ PATH_CHAR_CLASS_OTHER_VALID, /* '_' */ PATH_CHAR_CLASS_OTHER_VALID, - /* '`' */ PATH_CHAR_CLASS_OTHER_VALID, /* 'a' */ PATH_CHAR_CLASS_ANY, - /* 'b' */ PATH_CHAR_CLASS_ANY, /* 'c' */ PATH_CHAR_CLASS_ANY, - /* 'd' */ PATH_CHAR_CLASS_ANY, /* 'e' */ PATH_CHAR_CLASS_ANY, - /* 'f' */ PATH_CHAR_CLASS_ANY, /* 'g' */ PATH_CHAR_CLASS_ANY, - /* 'h' */ PATH_CHAR_CLASS_ANY, /* 'i' */ PATH_CHAR_CLASS_ANY, - /* 'j' */ PATH_CHAR_CLASS_ANY, /* 'k' */ PATH_CHAR_CLASS_ANY, - /* 'l' */ PATH_CHAR_CLASS_ANY, /* 'm' */ PATH_CHAR_CLASS_ANY, - /* 'n' */ PATH_CHAR_CLASS_ANY, /* 'o' */ PATH_CHAR_CLASS_ANY, - /* 'p' */ PATH_CHAR_CLASS_ANY, /* 'q' */ PATH_CHAR_CLASS_ANY, - /* 'r' */ PATH_CHAR_CLASS_ANY, /* 's' */ PATH_CHAR_CLASS_ANY, - /* 't' */ PATH_CHAR_CLASS_ANY, /* 'u' */ PATH_CHAR_CLASS_ANY, - /* 'v' */ PATH_CHAR_CLASS_ANY, /* 'w' */ PATH_CHAR_CLASS_ANY, - /* 'x' */ PATH_CHAR_CLASS_ANY, /* 'y' */ PATH_CHAR_CLASS_ANY, - /* 'z' */ PATH_CHAR_CLASS_ANY, /* '{' */ PATH_CHAR_CLASS_OTHER_VALID, - /* '|' */ PATH_CHAR_CLASS_INVALID, /* '}' */ PATH_CHAR_CLASS_OTHER_VALID, - /* '~' */ PATH_CHAR_CLASS_OTHER_VALID -}; - -/************************************************************************* - * @ [SHLWAPI.455] - * - * Check if an ASCII char is of a certain class - */ -BOOL WINAPI PathIsValidCharA( char c, DWORD class ) -{ - if ((unsigned)c > 0x7e) - return class & PATH_CHAR_CLASS_OTHER_VALID; - - return class & SHELL_charclass[(unsigned)c]; -} - -/************************************************************************* - * @ [SHLWAPI.456] - * - * Check if a Unicode char is of a certain class - */ -BOOL WINAPI PathIsValidCharW( WCHAR c, DWORD class ) -{ - if (c > 0x7e) - return class & PATH_CHAR_CLASS_OTHER_VALID; - - return class & SHELL_charclass[c]; -} +/* + * Path Functions + * + * Copyright 1999, 2000 Juergen Schmied + * Copyright 2001, 2002 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "wine/port.h" + +#include <stdarg.h> +#include <string.h> +#include <stdlib.h> + +#include "wine/unicode.h" +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winreg.h" +#include "winternl.h" +#define NO_SHLWAPI_STREAM +#include "shlwapi.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/* Get a function pointer from a DLL handle */ +#define GET_FUNC(func, module, name, fail) \ + do { \ + if (!func) { \ + if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \ + func = (fn##func)GetProcAddress(SHLWAPI_h##module, name); \ + if (!func) return fail; \ + } \ + } while (0) + +/* DLL handles for late bound calls */ +extern HMODULE SHLWAPI_hshell32; + +/* Function pointers for GET_FUNC macro; these need to be global because of gcc bug */ +typedef BOOL (WINAPI *fnpIsNetDrive)(int); +static fnpIsNetDrive pIsNetDrive; + +HRESULT WINAPI SHGetWebFolderFilePathW(LPCWSTR,LPWSTR,DWORD); + +/************************************************************************* + * PathAppendA [SHLWAPI.@] + * + * Append one path to another. + * + * PARAMS + * lpszPath [I/O] Initial part of path, and destination for output + * lpszAppend [I] Path to append + * + * RETURNS + * Success: TRUE. lpszPath contains the newly created path. + * Failure: FALSE, if either path is NULL, or PathCombineA() fails. + * + * NOTES + * lpszAppend must contain at least one backslash ('\') if not NULL. + * Because PathCombineA() is used to join the paths, the resulting + * path is also canonicalized. + */ +BOOL WINAPI PathAppendA (LPSTR lpszPath, LPCSTR lpszAppend) +{ + TRACE("(%s,%s)\n",debugstr_a(lpszPath), debugstr_a(lpszAppend)); + + if (lpszPath && lpszAppend) + { + if (!PathIsUNCA(lpszAppend)) + while (*lpszAppend == '\\') + lpszAppend++; + if (PathCombineA(lpszPath, lpszPath, lpszAppend)) + return TRUE; + } + return FALSE; +} + +/************************************************************************* + * PathAppendW [SHLWAPI.@] + * + * See PathAppendA. + */ +BOOL WINAPI PathAppendW(LPWSTR lpszPath, LPCWSTR lpszAppend) +{ + TRACE("(%s,%s)\n",debugstr_w(lpszPath), debugstr_w(lpszAppend)); + + if (lpszPath && lpszAppend) + { + if (!PathIsUNCW(lpszAppend)) + while (*lpszAppend == '\\') + lpszAppend++; + if (PathCombineW(lpszPath, lpszPath, lpszAppend)) + return TRUE; + } + return FALSE; +} + +/************************************************************************* + * PathCombineA [SHLWAPI.@] + * + * Combine two paths together. + * + * PARAMS + * lpszDest [O] Destination for combined path + * lpszDir [I] Directory path + * lpszFile [I] File path + * + * RETURNS + * Success: The output path + * Failure: NULL, if inputs are invalid. + * + * NOTES + * lpszDest should be at least MAX_PATH in size, and may point to the same + * memory location as lpszDir. The combined path is canonicalised. + */ +LPSTR WINAPI PathCombineA(LPSTR lpszDest, LPCSTR lpszDir, LPCSTR lpszFile) +{ + TRACE("(%p,%s,%s)\n", lpszDest, debugstr_a(lpszDir), debugstr_a(lpszFile)); + + if (!lpszDest || (!lpszDir && !lpszFile)) + return NULL; /* Invalid parameters */ + else + { + WCHAR szDest[MAX_PATH]; + WCHAR szDir[MAX_PATH]; + WCHAR szFile[MAX_PATH]; + if (lpszDir) + MultiByteToWideChar(CP_ACP,0,lpszDir,-1,szDir,MAX_PATH); + if (lpszFile) + MultiByteToWideChar(CP_ACP,0,lpszFile,-1,szFile,MAX_PATH); + PathCombineW(szDest, lpszDir ? szDir : NULL, lpszFile ? szFile : NULL); + WideCharToMultiByte(CP_ACP,0,szDest,-1,lpszDest,MAX_PATH,0,0); + } + return lpszDest; +} + +/************************************************************************* + * PathCombineW [SHLWAPI.@] + * + * See PathCombineA. + */ +LPWSTR WINAPI PathCombineW(LPWSTR lpszDest, LPCWSTR lpszDir, LPCWSTR lpszFile) +{ + WCHAR szTemp[MAX_PATH]; + BOOL bUseBoth = FALSE, bStrip = FALSE; + + TRACE("(%p,%s,%s)\n", lpszDest, debugstr_w(lpszDir), debugstr_w(lpszFile)); + + if (!lpszDest || (!lpszDir && !lpszFile)) + return lpszDest; /* Invalid parameters */ + + if (!lpszFile || !*lpszFile) + { + /* Use dir only */ + lstrcpynW(szTemp, lpszDir, MAX_PATH); + } + else if (!lpszDir || !*lpszDir || !PathIsRelativeW(lpszFile)) + { + if (!lpszDir || !*lpszDir || *lpszFile != '\\' || PathIsUNCW(lpszFile)) + { + /* Use file only */ + lstrcpynW(szTemp, lpszFile, MAX_PATH); + } + else + { + bUseBoth = TRUE; + bStrip = TRUE; + } + } + else + bUseBoth = TRUE; + + if (bUseBoth) + { + lstrcpynW(szTemp, lpszDir, MAX_PATH); + if (bStrip) + { + PathStripToRootW(szTemp); + lpszFile++; /* Skip '\' */ + } + if (!PathAddBackslashW(szTemp)) + return NULL; + if (strlenW(szTemp) + strlenW(lpszFile) >= MAX_PATH) + return NULL; + strcatW(szTemp, lpszFile); + } + + PathCanonicalizeW(lpszDest, szTemp); + return lpszDest; +} + +/************************************************************************* + * PathAddBackslashA [SHLWAPI.@] + * + * Append a backslash ('\') to a path if one doesn't exist. + * + * PARAMS + * lpszPath [I/O] The path to append a backslash to. + * + * RETURNS + * Success: The position of the last backslash in the path. + * Failure: NULL, if lpszPath is NULL or the path is too large. + */ +LPSTR WINAPI PathAddBackslashA(LPSTR lpszPath) +{ + size_t iLen; + + TRACE("(%s)\n",debugstr_a(lpszPath)); + + if (!lpszPath || (iLen = strlen(lpszPath)) >= MAX_PATH) + return NULL; + + if (iLen) + { + lpszPath += iLen; + if (lpszPath[-1] != '\\') + { + *lpszPath++ = '\\'; + *lpszPath = '\0'; + } + } + return lpszPath; +} + +/************************************************************************* + * PathAddBackslashW [SHLWAPI.@] + * + * See PathAddBackslashA. + */ +LPWSTR WINAPI PathAddBackslashW( LPWSTR lpszPath ) +{ + size_t iLen; + + TRACE("(%s)\n",debugstr_w(lpszPath)); + + if (!lpszPath || (iLen = strlenW(lpszPath)) >= MAX_PATH) + return NULL; + + if (iLen) + { + lpszPath += iLen; + if (lpszPath[-1] != '\\') + { + *lpszPath++ = '\\'; + *lpszPath = '\0'; + } + } + return lpszPath; +} + +/************************************************************************* + * PathBuildRootA [SHLWAPI.@] + * + * Create a root drive string (e.g. "A:\") from a drive number. + * + * PARAMS + * lpszPath [O] Destination for the drive string + * + * RETURNS + * lpszPath + * + * NOTES + * If lpszPath is NULL or drive is invalid, nothing is written to lpszPath. + */ +LPSTR WINAPI PathBuildRootA(LPSTR lpszPath, int drive) +{ + TRACE("(%p,%d)\n", lpszPath, drive); + + if (lpszPath && drive >= 0 && drive < 26) + { + lpszPath[0] = 'A' + drive; + lpszPath[1] = ':'; + lpszPath[2] = '\\'; + lpszPath[3] = '\0'; + } + return lpszPath; +} + +/************************************************************************* + * PathBuildRootW [SHLWAPI.@] + * + * See PathBuildRootA. + */ +LPWSTR WINAPI PathBuildRootW(LPWSTR lpszPath, int drive) +{ + TRACE("(%p,%d)\n", lpszPath, drive); + + if (lpszPath && drive >= 0 && drive < 26) + { + lpszPath[0] = 'A' + drive; + lpszPath[1] = ':'; + lpszPath[2] = '\\'; + lpszPath[3] = '\0'; + } + return lpszPath; +} + +/************************************************************************* + * PathFindFileNameA [SHLWAPI.@] + * + * Locate the start of the file name in a path + * + * PARAMS + * lpszPath [I] Path to search + * + * RETURNS + * A pointer to the first character of the file name + */ +LPSTR WINAPI PathFindFileNameA(LPCSTR lpszPath) +{ + LPCSTR lastSlash = lpszPath; + + TRACE("(%s)\n",debugstr_a(lpszPath)); + + while (lpszPath && *lpszPath) + { + if ((*lpszPath == '\\' || *lpszPath == '/' || *lpszPath == ':') && + lpszPath[1] && lpszPath[1] != '\\' && lpszPath[1] != '/') + lastSlash = lpszPath + 1; + lpszPath = CharNextA(lpszPath); + } + return (LPSTR)lastSlash; +} + +/************************************************************************* + * PathFindFileNameW [SHLWAPI.@] + * + * See PathFindFileNameA. + */ +LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath) +{ + LPCWSTR lastSlash = lpszPath; + + TRACE("(%s)\n",debugstr_w(lpszPath)); + + while (lpszPath && *lpszPath) + { + if ((*lpszPath == '\\' || *lpszPath == '/' || *lpszPath == ':') && + lpszPath[1] && lpszPath[1] != '\\' && lpszPath[1] != '/') + lastSlash = lpszPath + 1; + lpszPath = CharNextW(lpszPath); + } + return (LPWSTR)lastSlash; +} + +/************************************************************************* + * PathFindExtensionA [SHLWAPI.@] + * + * Locate the start of the file extension in a path + * + * PARAMS + * lpszPath [I] The path to search + * + * RETURNS + * A pointer to the first character of the extension, the end of + * the string if the path has no extension, or NULL If lpszPath is NULL + */ +LPSTR WINAPI PathFindExtensionA( LPCSTR lpszPath ) +{ + LPCSTR lastpoint = NULL; + + TRACE("(%s)\n", debugstr_a(lpszPath)); + + if (lpszPath) + { + while (*lpszPath) + { + if (*lpszPath == '\\' || *lpszPath==' ') + lastpoint = NULL; + else if (*lpszPath == '.') + lastpoint = lpszPath; + lpszPath = CharNextA(lpszPath); + } + } + return (LPSTR)(lastpoint ? lastpoint : lpszPath); +} + +/************************************************************************* + * PathFindExtensionW [SHLWAPI.@] + * + * See PathFindExtensionA. + */ +LPWSTR WINAPI PathFindExtensionW( LPCWSTR lpszPath ) +{ + LPCWSTR lastpoint = NULL; + + TRACE("(%s)\n", debugstr_w(lpszPath)); + + if (lpszPath) + { + while (*lpszPath) + { + if (*lpszPath == '\\' || *lpszPath==' ') + lastpoint = NULL; + else if (*lpszPath == '.') + lastpoint = lpszPath; + lpszPath = CharNextW(lpszPath); + } + } + return (LPWSTR)(lastpoint ? lastpoint : lpszPath); +} + +/************************************************************************* + * PathGetArgsA [SHLWAPI.@] + * + * Find the next argument in a string delimited by spaces. + * + * PARAMS + * lpszPath [I] The string to search for arguments in + * + * RETURNS + * The start of the next argument in lpszPath, or NULL if lpszPath is NULL + * + * NOTES + * Spaces in quoted strings are ignored as delimiters. + */ +LPSTR WINAPI PathGetArgsA(LPCSTR lpszPath) +{ + BOOL bSeenQuote = FALSE; + + TRACE("(%s)\n",debugstr_a(lpszPath)); + + if (lpszPath) + { + while (*lpszPath) + { + if ((*lpszPath==' ') && !bSeenQuote) + return (LPSTR)lpszPath + 1; + if (*lpszPath == '"') + bSeenQuote = !bSeenQuote; + lpszPath = CharNextA(lpszPath); + } + } + return (LPSTR)lpszPath; +} + +/************************************************************************* + * PathGetArgsW [SHLWAPI.@] + * + * See PathGetArgsA. + */ +LPWSTR WINAPI PathGetArgsW(LPCWSTR lpszPath) +{ + BOOL bSeenQuote = FALSE; + + TRACE("(%s)\n",debugstr_w(lpszPath)); + + if (lpszPath) + { + while (*lpszPath) + { + if ((*lpszPath==' ') && !bSeenQuote) + return (LPWSTR)lpszPath + 1; + if (*lpszPath == '"') + bSeenQuote = !bSeenQuote; + lpszPath = CharNextW(lpszPath); + } + } + return (LPWSTR)lpszPath; +} + +/************************************************************************* + * PathGetDriveNumberA [SHLWAPI.@] + * + * Return the drive number from a path + * + * PARAMS + * lpszPath [I] Path to get the drive number from + * + * RETURNS + * Success: The drive number corresponding to the drive in the path + * Failure: -1, if lpszPath contains no valid drive + */ +int WINAPI PathGetDriveNumberA(LPCSTR lpszPath) +{ + TRACE ("(%s)\n",debugstr_a(lpszPath)); + + if (lpszPath && !IsDBCSLeadByte(*lpszPath) && lpszPath[1] == ':' && + tolower(*lpszPath) >= 'a' && tolower(*lpszPath) <= 'z') + return tolower(*lpszPath) - 'a'; + return -1; +} + +/************************************************************************* + * PathGetDriveNumberW [SHLWAPI.@] + * + * See PathGetDriveNumberA. + */ +int WINAPI PathGetDriveNumberW(LPCWSTR lpszPath) +{ + TRACE ("(%s)\n",debugstr_w(lpszPath)); + + if (lpszPath && lpszPath[1] == ':' && + tolowerW(*lpszPath) >= 'a' && tolowerW(*lpszPath) <= 'z') + return tolowerW(*lpszPath) - 'a'; + return -1; +} + +/************************************************************************* + * PathRemoveFileSpecA [SHLWAPI.@] + * + * Remove the file specification from a path. + * + * PARAMS + * lpszPath [I/O] Path to remove the file spec from + * + * RETURNS + * TRUE If the path was valid and modified + * FALSE Otherwise + */ +BOOL WINAPI PathRemoveFileSpecA(LPSTR lpszPath) +{ + LPSTR lpszFileSpec = lpszPath; + BOOL bModified = FALSE; + + TRACE("(%s)\n",debugstr_a(lpszPath)); + + if(lpszPath) + { + /* Skip directory or UNC path */ + if (*lpszPath == '\\') + lpszFileSpec = ++lpszPath; + if (*lpszPath == '\\') + lpszFileSpec = ++lpszPath; + + while (*lpszPath) + { + if(*lpszPath == '\\') + lpszFileSpec = lpszPath; /* Skip dir */ + else if(*lpszPath == ':') + { + lpszFileSpec = ++lpszPath; /* Skip drive */ + if (*lpszPath == '\\') + lpszFileSpec++; + } + if (!(lpszPath = CharNextA(lpszPath))) + break; + } + + if (*lpszFileSpec) + { + *lpszFileSpec = '\0'; + bModified = TRUE; + } + } + return bModified; +} + +/************************************************************************* + * PathRemoveFileSpecW [SHLWAPI.@] + * + * See PathRemoveFileSpecA. + */ +BOOL WINAPI PathRemoveFileSpecW(LPWSTR lpszPath) +{ + LPWSTR lpszFileSpec = lpszPath; + BOOL bModified = FALSE; + + TRACE("(%s)\n",debugstr_w(lpszPath)); + + if(lpszPath) + { + /* Skip directory or UNC path */ + if (*lpszPath == '\\') + lpszFileSpec = ++lpszPath; + if (*lpszPath == '\\') + lpszFileSpec = ++lpszPath; + + while (*lpszPath) + { + if(*lpszPath == '\\') + lpszFileSpec = lpszPath; /* Skip dir */ + else if(*lpszPath == ':') + { + lpszFileSpec = ++lpszPath; /* Skip drive */ + if (*lpszPath == '\\') + lpszFileSpec++; + } + if (!(lpszPath = CharNextW(lpszPath))) + break; + } + + if (*lpszFileSpec) + { + *lpszFileSpec = '\0'; + bModified = TRUE; + } + } + return bModified; +} + +/************************************************************************* + * PathStripPathA [SHLWAPI.@] + * + * Remove the initial path from the beginning of a filename + * + * PARAMS + * lpszPath [I/O] Path to remove the initial path from + * + * RETURNS + * Nothing. + */ +void WINAPI PathStripPathA(LPSTR lpszPath) +{ + TRACE("(%s)\n", debugstr_a(lpszPath)); + + if (lpszPath) + { + LPSTR lpszFileName = PathFindFileNameA(lpszPath); + if(lpszFileName) + RtlMoveMemory(lpszPath, lpszFileName, strlen(lpszFileName)+1); + } +} + +/************************************************************************* + * PathStripPathW [SHLWAPI.@] + * + * See PathStripPathA. + */ +void WINAPI PathStripPathW(LPWSTR lpszPath) +{ + LPWSTR lpszFileName; + + TRACE("(%s)\n", debugstr_w(lpszPath)); + lpszFileName = PathFindFileNameW(lpszPath); + if(lpszFileName) + RtlMoveMemory(lpszPath, lpszFileName, (strlenW(lpszFileName)+1)*sizeof(WCHAR)); +} + +/************************************************************************* + * PathStripToRootA [SHLWAPI.@] + * + * Reduce a path to its root. + * + * PARAMS + * lpszPath [I/O] the path to reduce + * + * RETURNS + * Success: TRUE if the stripped path is a root path + * Failure: FALSE if the path cannot be stripped or is NULL + */ +BOOL WINAPI PathStripToRootA(LPSTR lpszPath) +{ + TRACE("(%s)\n", debugstr_a(lpszPath)); + + if (!lpszPath) + return FALSE; + while(!PathIsRootA(lpszPath)) + if (!PathRemoveFileSpecA(lpszPath)) + return FALSE; + return TRUE; +} + +/************************************************************************* + * PathStripToRootW [SHLWAPI.@] + * + * See PathStripToRootA. + */ +BOOL WINAPI PathStripToRootW(LPWSTR lpszPath) +{ + TRACE("(%s)\n", debugstr_w(lpszPath)); + + if (!lpszPath) + return FALSE; + while(!PathIsRootW(lpszPath)) + if (!PathRemoveFileSpecW(lpszPath)) + return FALSE; + return TRUE; +} + +/************************************************************************* + * PathRemoveArgsA [SHLWAPI.@] + * + * Strip space separated arguments from a path. + * + * PARAMS + * lpszPath [I/O] Path to remove arguments from + * + * RETURNS + * Nothing. + */ +void WINAPI PathRemoveArgsA(LPSTR lpszPath) +{ + TRACE("(%s)\n",debugstr_a(lpszPath)); + + if(lpszPath) + { + LPSTR lpszArgs = PathGetArgsA(lpszPath); + if (*lpszArgs) + lpszArgs[-1] = '\0'; + else + { + LPSTR lpszLastChar = CharPrevA(lpszPath, lpszArgs); + if(*lpszLastChar == ' ') + *lpszLastChar = '\0'; + } + } +} + +/************************************************************************* + * PathRemoveArgsW [SHLWAPI.@] + * + * See PathRemoveArgsA. + */ +void WINAPI PathRemoveArgsW(LPWSTR lpszPath) +{ + TRACE("(%s)\n",debugstr_w(lpszPath)); + + if(lpszPath) + { + LPWSTR lpszArgs = PathGetArgsW(lpszPath); + if (*lpszArgs) + lpszArgs[-1] = '\0'; + else + { + LPWSTR lpszLastChar = CharPrevW(lpszPath, lpszArgs); + if(*lpszLastChar == ' ') + *lpszLastChar = '\0'; + } + } +} + +/************************************************************************* + * PathRemoveExtensionA [SHLWAPI.@] + * + * Remove the file extension from a path + * + * PARAMS + * lpszPath [I/O] Path to remove the extension from + * + * RETURNS + * Nothing. + */ +void WINAPI PathRemoveExtensionA(LPSTR lpszPath) +{ + TRACE("(%s)\n", debugstr_a(lpszPath)); + + if (lpszPath) + { + lpszPath = PathFindExtensionA(lpszPath); + *lpszPath = '\0'; + } +} + +/************************************************************************* + * PathRemoveExtensionW [SHLWAPI.@] + * + * See PathRemoveExtensionA. +*/ +void WINAPI PathRemoveExtensionW(LPWSTR lpszPath) +{ + TRACE("(%s)\n", debugstr_w(lpszPath)); + + if (lpszPath) + { + lpszPath = PathFindExtensionW(lpszPath); + *lpszPath = '\0'; + } +} + +/************************************************************************* + * PathRemoveBackslashA [SHLWAPI.@] + * + * Remove a trailing backslash from a path. + * + * PARAMS + * lpszPath [I/O] Path to remove backslash from + * + * RETURNS + * Success: A pointer to the end of the path + * Failure: NULL, if lpszPath is NULL + */ +LPSTR WINAPI PathRemoveBackslashA( LPSTR lpszPath ) +{ + LPSTR szTemp = NULL; + + TRACE("(%s)\n", debugstr_a(lpszPath)); + + if(lpszPath) + { + szTemp = CharPrevA(lpszPath, lpszPath + strlen(lpszPath)); + if (!PathIsRootA(lpszPath) && *szTemp == '\\') + *szTemp = '\0'; + } + return szTemp; +} + +/************************************************************************* + * PathRemoveBackslashW [SHLWAPI.@] + * + * See PathRemoveBackslashA. + */ +LPWSTR WINAPI PathRemoveBackslashW( LPWSTR lpszPath ) +{ + LPWSTR szTemp = NULL; + + TRACE("(%s)\n", debugstr_w(lpszPath)); + + if(lpszPath) + { + szTemp = CharPrevW(lpszPath, lpszPath + strlenW(lpszPath)); + if (!PathIsRootW(lpszPath) && *szTemp == '\\') + *szTemp = '\0'; + } + return szTemp; +} + +/************************************************************************* + * PathRemoveBlanksA [SHLWAPI.@] + * + * Remove Spaces from the start and end of a path. + * + * PARAMS + * lpszPath [I/O] Path to strip blanks from + * + * RETURNS + * Nothing. + */ +VOID WINAPI PathRemoveBlanksA(LPSTR lpszPath) +{ + TRACE("(%s)\n", debugstr_a(lpszPath)); + + if(lpszPath && *lpszPath) + { + LPSTR start = lpszPath; + + while (*lpszPath == ' ') + lpszPath = CharNextA(lpszPath); + + while(*lpszPath) + *start++ = *lpszPath++; + + if (start != lpszPath) + while (start[-1] == ' ') + start--; + *start = '\0'; + } +} + +/************************************************************************* + * PathRemoveBlanksW [SHLWAPI.@] + * + * See PathRemoveBlanksA. + */ +VOID WINAPI PathRemoveBlanksW(LPWSTR lpszPath) +{ + TRACE("(%s)\n", debugstr_w(lpszPath)); + + if(lpszPath && *lpszPath) + { + LPWSTR start = lpszPath; + + while (*lpszPath == ' ') + lpszPath++; + + while(*lpszPath) + *start++ = *lpszPath++; + + if (start != lpszPath) + while (start[-1] == ' ') + start--; + *start = '\0'; + } +} + +/************************************************************************* + * PathQuoteSpacesA [SHLWAPI.@] + * + * Surround a path containg spaces in quotes. + * + * PARAMS + * lpszPath [I/O] Path to quote + * + * RETURNS + * Nothing. + * + * NOTES + * The path is not changed if it is invalid or has no spaces. + */ +VOID WINAPI PathQuoteSpacesA(LPSTR lpszPath) +{ + TRACE("(%s)\n", debugstr_a(lpszPath)); + + if(lpszPath && StrChrA(lpszPath,' ')) + { + size_t iLen = strlen(lpszPath) + 1; + + if (iLen + 2 < MAX_PATH) + { + memmove(lpszPath + 1, lpszPath, iLen); + lpszPath[0] = '"'; + lpszPath[iLen] = '"'; + lpszPath[iLen + 1] = '\0'; + } + } +} + +/************************************************************************* + * PathQuoteSpacesW [SHLWAPI.@] + * + * See PathQuoteSpacesA. + */ +VOID WINAPI PathQuoteSpacesW(LPWSTR lpszPath) +{ + TRACE("(%s)\n", debugstr_w(lpszPath)); + + if(lpszPath && StrChrW(lpszPath,' ')) + { + int iLen = strlenW(lpszPath) + 1; + + if (iLen + 2 < MAX_PATH) + { + memmove(lpszPath + 1, lpszPath, iLen * sizeof(WCHAR)); + lpszPath[0] = '"'; + lpszPath[iLen] = '"'; + lpszPath[iLen + 1] = '\0'; + } + } +} + +/************************************************************************* + * PathUnquoteSpacesA [SHLWAPI.@] + * + * Remove quotes ("") from around a path, if present. + * + * PARAMS + * lpszPath [I/O] Path to strip quotes from + * + * RETURNS + * Nothing + * + * NOTES + * If the path contains a single quote only, an empty string will result. + * Otherwise quotes are only removed if they appear at the start and end + * of the path. + */ +VOID WINAPI PathUnquoteSpacesA(LPSTR lpszPath) +{ + TRACE("(%s)\n", debugstr_a(lpszPath)); + + if (lpszPath && *lpszPath == '"') + { + DWORD dwLen = strlen(lpszPath) - 1; + + if (lpszPath[dwLen] == '"') + { + lpszPath[dwLen] = '\0'; + for (; *lpszPath; lpszPath++) + *lpszPath = lpszPath[1]; + } + } +} + +/************************************************************************* + * PathUnquoteSpacesW [SHLWAPI.@] + * + * See PathUnquoteSpacesA. + */ +VOID WINAPI PathUnquoteSpacesW(LPWSTR lpszPath) +{ + TRACE("(%s)\n", debugstr_w(lpszPath)); + + if (lpszPath && *lpszPath == '"') + { + DWORD dwLen = strlenW(lpszPath) - 1; + + if (lpszPath[dwLen] == '"') + { + lpszPath[dwLen] = '\0'; + for (; *lpszPath; lpszPath++) + *lpszPath = lpszPath[1]; + } + } +} + +/************************************************************************* + * PathParseIconLocationA [SHLWAPI.@] + * + * Parse the location of an icon from a path. + * + * PARAMS + * lpszPath [I/O] The path to parse the icon location from. + * + * RETURNS + * Success: The number of the icon + * Failure: 0 if the path does not contain an icon location or is NULL + * + * NOTES + * The path has surrounding quotes and spaces removed regardless + * of whether the call succeeds or not. + */ +int WINAPI PathParseIconLocationA(LPSTR lpszPath) +{ + int iRet = 0; + LPSTR lpszComma; + + TRACE("(%s)\n", debugstr_a(lpszPath)); + + if (lpszPath) + { + if ((lpszComma = strchr(lpszPath, ','))) + { + *lpszComma++ = '\0'; + iRet = StrToIntA(lpszComma); + } + PathUnquoteSpacesA(lpszPath); + PathRemoveBlanksA(lpszPath); + } + return iRet; +} + +/************************************************************************* + * PathParseIconLocationW [SHLWAPI.@] + * + * See PathParseIconLocationA. + */ +int WINAPI PathParseIconLocationW(LPWSTR lpszPath) +{ + int iRet = 0; + LPWSTR lpszComma; + + TRACE("(%s)\n", debugstr_w(lpszPath)); + + if (lpszPath) + { + if ((lpszComma = StrChrW(lpszPath, ','))) + { + *lpszComma++ = '\0'; + iRet = StrToIntW(lpszComma); + } + PathUnquoteSpacesW(lpszPath); + PathRemoveBlanksW(lpszPath); + } + return iRet; +} + +/************************************************************************* + * @ [SHLWAPI.4] + * + * Unicode version of PathFileExistsDefExtA. + */ +BOOL WINAPI PathFileExistsDefExtW(LPWSTR lpszPath,DWORD dwWhich) +{ + static const WCHAR pszExts[7][5] = { { '.', 'p', 'i', 'f', 0}, + { '.', 'c', 'o', 'm', 0}, + { '.', 'e', 'x', 'e', 0}, + { '.', 'b', 'a', 't', 0}, + { '.', 'l', 'n', 'k', 0}, + { '.', 'c', 'm', 'd', 0}, + { 0, 0, 0, 0, 0} }; + + TRACE("(%s,%ld)\n", debugstr_w(lpszPath), dwWhich); + + if (!lpszPath || PathIsUNCServerW(lpszPath) || PathIsUNCServerShareW(lpszPath)) + return FALSE; + + if (dwWhich) + { + LPCWSTR szExt = PathFindExtensionW(lpszPath); + if (!*szExt || dwWhich & 0x40) + { + size_t iChoose = 0; + int iLen = lstrlenW(lpszPath); + if (iLen > (MAX_PATH - 5)) + return FALSE; + while ( (dwWhich & 0x1) && pszExts[iChoose][0] ) + { + lstrcpyW(lpszPath + iLen, pszExts[iChoose]); + if (PathFileExistsW(lpszPath)) + return TRUE; + iChoose++; + dwWhich >>= 1; + } + *(lpszPath + iLen) = (WCHAR)'\0'; + return FALSE; + } + } + return PathFileExistsW(lpszPath); +} + +/************************************************************************* + * @ [SHLWAPI.3] + * + * Determine if a file exists locally and is of an executable type. + * + * PARAMS + * lpszPath [I/O] File to search for + * dwWhich [I] Type of executable to search for + * + * RETURNS + * TRUE If the file was found. lpszPath contains the file name. + * FALSE Otherwise. + * + * NOTES + * lpszPath is modified in place and must be at least MAX_PATH in length. + * If the function returns FALSE, the path is modified to its orginal state. + * If the given path contains an extension or dwWhich is 0, executable + * extensions are not checked. + * + * Ordinals 3-6 are a classic case of MS exposing limited functionality to + * users (here through PathFindOnPathA()) and keeping advanced functionality for + * their own developers exclusive use. Monopoly, anyone? + */ +BOOL WINAPI PathFileExistsDefExtA(LPSTR lpszPath,DWORD dwWhich) +{ + BOOL bRet = FALSE; + + TRACE("(%s,%ld)\n", debugstr_a(lpszPath), dwWhich); + + if (lpszPath) + { + WCHAR szPath[MAX_PATH]; + MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH); + bRet = PathFileExistsDefExtW(szPath, dwWhich); + if (bRet) + WideCharToMultiByte(CP_ACP,0,szPath,-1,lpszPath,MAX_PATH,0,0); + } + return bRet; +} + +/************************************************************************* + * SHLWAPI_PathFindInOtherDirs + * + * Internal helper for SHLWAPI_PathFindOnPathExA/W. + */ +static BOOL WINAPI SHLWAPI_PathFindInOtherDirs(LPWSTR lpszFile, DWORD dwWhich) +{ + static const WCHAR szSystem[] = { 'S','y','s','t','e','m','\0'}; + static const WCHAR szPath[] = { 'P','A','T','H','\0'}; + DWORD dwLenPATH; + LPCWSTR lpszCurr; + WCHAR *lpszPATH; + WCHAR buff[MAX_PATH]; + + TRACE("(%s,%08lx)\n", debugstr_w(lpszFile), dwWhich); + + /* Try system directories */ + GetSystemDirectoryW(buff, MAX_PATH); + if (!PathAppendW(buff, lpszFile)) + return FALSE; + if (PathFileExistsDefExtW(buff, dwWhich)) + { + strcpyW(lpszFile, buff); + return TRUE; + } + GetWindowsDirectoryW(buff, MAX_PATH); + if (!PathAppendW(buff, szSystem ) || !PathAppendW(buff, lpszFile)) + return FALSE; + if (PathFileExistsDefExtW(buff, dwWhich)) + { + strcpyW(lpszFile, buff); + return TRUE; + } + GetWindowsDirectoryW(buff, MAX_PATH); + if (!PathAppendW(buff, lpszFile)) + return FALSE; + if (PathFileExistsDefExtW(buff, dwWhich)) + { + strcpyW(lpszFile, buff); + return TRUE; + } + /* Try dirs listed in %PATH% */ + dwLenPATH = GetEnvironmentVariableW(szPath, buff, MAX_PATH); + + if (!dwLenPATH || !(lpszPATH = malloc((dwLenPATH + 1) * sizeof (WCHAR)))) + return FALSE; + + GetEnvironmentVariableW(szPath, lpszPATH, dwLenPATH + 1); + lpszCurr = lpszPATH; + while (lpszCurr) + { + LPCWSTR lpszEnd = lpszCurr; + LPWSTR pBuff = buff; + + while (*lpszEnd == ' ') + lpszEnd++; + while (*lpszEnd && *lpszEnd != ';') + *pBuff++ = *lpszEnd++; + *pBuff = '\0'; + + if (*lpszEnd) + lpszCurr = lpszEnd + 1; + else + lpszCurr = NULL; /* Last Path, terminate after this */ + + if (!PathAppendW(buff, lpszFile)) + { + free(lpszPATH); + return FALSE; + } + if (PathFileExistsDefExtW(buff, dwWhich)) + { + strcpyW(lpszFile, buff); + free(lpszPATH); + return TRUE; + } + } + free(lpszPATH); + return FALSE; +} + +/************************************************************************* + * @ [SHLWAPI.5] + * + * Search a range of paths for a specific type of executable. + * + * PARAMS + * lpszFile [I/O] File to search for + * lppszOtherDirs [I] Other directories to look in + * dwWhich [I] Type of executable to search for + * + * RETURNS + * Success: TRUE. The path to the executable is stored in lpszFile. + * Failure: FALSE. The path to the executable is unchanged. + */ +BOOL WINAPI PathFindOnPathExA(LPSTR lpszFile,LPCSTR *lppszOtherDirs,DWORD dwWhich) +{ + WCHAR szFile[MAX_PATH]; + WCHAR buff[MAX_PATH]; + + TRACE("(%s,%p,%08lx)\n", debugstr_a(lpszFile), lppszOtherDirs, dwWhich); + + if (!lpszFile || !PathIsFileSpecA(lpszFile)) + return FALSE; + + MultiByteToWideChar(CP_ACP,0,lpszFile,-1,szFile,MAX_PATH); + + /* Search provided directories first */ + if (lppszOtherDirs && *lppszOtherDirs) + { + WCHAR szOther[MAX_PATH]; + LPCSTR *lpszOtherPath = lppszOtherDirs; + + while (lpszOtherPath && *lpszOtherPath && (*lpszOtherPath)[0]) + { + MultiByteToWideChar(CP_ACP,0,*lpszOtherPath,-1,szOther,MAX_PATH); + PathCombineW(buff, szOther, szFile); + if (PathFileExistsDefExtW(buff, dwWhich)) + { + WideCharToMultiByte(CP_ACP,0,buff,-1,lpszFile,MAX_PATH,0,0); + return TRUE; + } + lpszOtherPath++; + } + } + /* Not found, try system and path dirs */ + if (SHLWAPI_PathFindInOtherDirs(szFile, dwWhich)) + { + WideCharToMultiByte(CP_ACP,0,szFile,-1,lpszFile,MAX_PATH,0,0); + return TRUE; + } + return FALSE; +} + +/************************************************************************* + * @ [SHLWAPI.6] + * + * Unicode version of PathFindOnPathExA. + */ +BOOL WINAPI PathFindOnPathExW(LPWSTR lpszFile,LPCWSTR *lppszOtherDirs,DWORD dwWhich) +{ + WCHAR buff[MAX_PATH]; + + TRACE("(%s,%p,%08lx)\n", debugstr_w(lpszFile), lppszOtherDirs, dwWhich); + + if (!lpszFile || !PathIsFileSpecW(lpszFile)) + return FALSE; + + /* Search provided directories first */ + if (lppszOtherDirs && *lppszOtherDirs) + { + LPCWSTR *lpszOtherPath = lppszOtherDirs; + while (lpszOtherPath && *lpszOtherPath && (*lpszOtherPath)[0]) + { + PathCombineW(buff, *lpszOtherPath, lpszFile); + if (PathFileExistsDefExtW(buff, dwWhich)) + { + strcpyW(lpszFile, buff); + return TRUE; + } + lpszOtherPath++; + } + } + /* Not found, try system and path dirs */ + return SHLWAPI_PathFindInOtherDirs(lpszFile, dwWhich); +} + +/************************************************************************* + * PathFindOnPathA [SHLWAPI.@] + * + * Search a range of paths for an executable. + * + * PARAMS + * lpszFile [I/O] File to search for + * lppszOtherDirs [I] Other directories to look in + * + * RETURNS + * Success: TRUE. The path to the executable is stored in lpszFile. + * Failure: FALSE. The path to the executable is unchanged. + */ +BOOL WINAPI PathFindOnPathA(LPSTR lpszFile, LPCSTR *lppszOtherDirs) +{ + TRACE("(%s,%p)\n", debugstr_a(lpszFile), lppszOtherDirs); + return PathFindOnPathExA(lpszFile, lppszOtherDirs, 0); + } + +/************************************************************************* + * PathFindOnPathW [SHLWAPI.@] + * + * See PathFindOnPathA. + */ +BOOL WINAPI PathFindOnPathW(LPWSTR lpszFile, LPCWSTR *lppszOtherDirs) +{ + TRACE("(%s,%p)\n", debugstr_w(lpszFile), lppszOtherDirs); + return PathFindOnPathExW(lpszFile,lppszOtherDirs, 0); +} + +/************************************************************************* + * PathCompactPathExA [SHLWAPI.@] + * + * Compact a path into a given number of characters. + * + * PARAMS + * lpszDest [O] Destination for compacted path + * lpszPath [I] Source path + * cchMax [I] Maximum size of compacted path + * dwFlags [I] Reserved + * + * RETURNS + * Success: TRUE. The compacted path is written to lpszDest. + * Failure: FALSE. lpszPath is undefined. + * + * NOTES + * If cchMax is given as 0, lpszDest will still be NUL terminated. + * + * The Win32 version of this function contains a bug: When cchMax == 7, + * 8 bytes will be written to lpszDest. This bug is fixed in the Wine + * implementation. + * + * Some relative paths will be different when cchMax == 5 or 6. This occurs + * because Win32 will insert a "\" in lpszDest, even if one is + * not present in the original path. + */ +BOOL WINAPI PathCompactPathExA(LPSTR lpszDest, LPCSTR lpszPath, + UINT cchMax, DWORD dwFlags) +{ + BOOL bRet = FALSE; + + TRACE("(%p,%s,%d,0x%08lx)\n", lpszDest, debugstr_a(lpszPath), cchMax, dwFlags); + + if (lpszPath && lpszDest) + { + WCHAR szPath[MAX_PATH]; + WCHAR szDest[MAX_PATH]; + + MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH); + szDest[0] = '\0'; + bRet = PathCompactPathExW(szDest, szPath, cchMax, dwFlags); + WideCharToMultiByte(CP_ACP,0,szDest,-1,lpszDest,MAX_PATH,0,0); + } + return bRet; +} + +/************************************************************************* + * PathCompactPathExW [SHLWAPI.@] + * + * See PathCompactPathExA. + */ +BOOL WINAPI PathCompactPathExW(LPWSTR lpszDest, LPCWSTR lpszPath, + UINT cchMax, DWORD dwFlags) +{ + static const WCHAR szEllipses[] = { '.', '.', '.', '\0' }; + LPCWSTR lpszFile; + DWORD dwLen, dwFileLen = 0; + + TRACE("(%p,%s,%d,0x%08lx)\n", lpszDest, debugstr_w(lpszPath), cchMax, dwFlags); + + if (!lpszPath) + return FALSE; + + if (!lpszDest) + { + WARN("Invalid lpszDest would crash under Win32!\n"); + return FALSE; + } + + *lpszDest = '\0'; + + if (cchMax < 2) + return TRUE; + + dwLen = strlenW(lpszPath) + 1; + + if (dwLen < cchMax) + { + /* Don't need to compact */ + memcpy(lpszDest, lpszPath, dwLen * sizeof(WCHAR)); + return TRUE; + } + + /* Path must be compacted to fit into lpszDest */ + lpszFile = PathFindFileNameW(lpszPath); + dwFileLen = lpszPath + dwLen - lpszFile; + + if (dwFileLen == dwLen) + { + /* No root in psth */ + if (cchMax <= 4) + { + while (--cchMax > 0) /* No room left for anything but ellipses */ + *lpszDest++ = '.'; + *lpszDest = '\0'; + return TRUE; + } + /* Compact the file name with ellipses at the end */ + cchMax -= 4; + memcpy(lpszDest, lpszFile, cchMax * sizeof(WCHAR)); + strcpyW(lpszDest + cchMax, szEllipses); + return TRUE; + } + /* We have a root in the path */ + lpszFile--; /* Start compacted filename with the path separator */ + dwFileLen++; + + if (dwFileLen + 3 > cchMax) + { + /* Compact the file name */ + if (cchMax <= 4) + { + while (--cchMax > 0) /* No room left for anything but ellipses */ + *lpszDest++ = '.'; + *lpszDest = '\0'; + return TRUE; + } + strcpyW(lpszDest, szEllipses); + lpszDest += 3; + cchMax -= 4; + *lpszDest++ = *lpszFile++; + if (cchMax <= 4) + { + while (--cchMax > 0) /* No room left for anything but ellipses */ + *lpszDest++ = '.'; + *lpszDest = '\0'; + return TRUE; + } + cchMax -= 4; + memcpy(lpszDest, lpszFile, cchMax * sizeof(WCHAR)); + strcpyW(lpszDest + cchMax, szEllipses); + return TRUE; + } + + /* Only the root needs to be Compacted */ + dwLen = cchMax - dwFileLen - 3; + memcpy(lpszDest, lpszPath, dwLen * sizeof(WCHAR)); + strcpyW(lpszDest + dwLen, szEllipses); + strcpyW(lpszDest + dwLen + 3, lpszFile); + return TRUE; +} + +/************************************************************************* + * PathIsRelativeA [SHLWAPI.@] + * + * Determine if a path is a relative path. + * + * PARAMS + * lpszPath [I] Path to check + * + * RETURNS + * TRUE: The path is relative, or is invalid. + * FALSE: The path is not relative. + */ +BOOL WINAPI PathIsRelativeA (LPCSTR lpszPath) +{ + TRACE("(%s)\n",debugstr_a(lpszPath)); + + if (!lpszPath || !*lpszPath || IsDBCSLeadByte(*lpszPath)) + return TRUE; + if (*lpszPath == '\\' || (*lpszPath && lpszPath[1] == ':')) + return FALSE; + return TRUE; +} + +/************************************************************************* + * PathIsRelativeW [SHLWAPI.@] + * + * See PathIsRelativeA. + */ +BOOL WINAPI PathIsRelativeW (LPCWSTR lpszPath) +{ + TRACE("(%s)\n",debugstr_w(lpszPath)); + + if (!lpszPath || !*lpszPath) + return TRUE; + if (*lpszPath == '\\' || (*lpszPath && lpszPath[1] == ':')) + return FALSE; + return TRUE; +} + +/************************************************************************* + * PathIsRootA [SHLWAPI.@] + * + * Determine if a path is a root path. + * + * PARAMS + * lpszPath [I] Path to check + * + * RETURNS + * TRUE If lpszPath is valid and a root path, + * FALSE Otherwise + */ +BOOL WINAPI PathIsRootA(LPCSTR lpszPath) +{ + TRACE("(%s)\n", debugstr_a(lpszPath)); + + if (lpszPath && *lpszPath) + { + if (*lpszPath == '\\') + { + if (!lpszPath[1]) + return TRUE; /* \ */ + else if (lpszPath[1]=='\\') + { + BOOL bSeenSlash = FALSE; + lpszPath += 2; + + /* Check for UNC root path */ + while (*lpszPath) + { + if (*lpszPath == '\\') + { + if (bSeenSlash) + return FALSE; + bSeenSlash = TRUE; + } + lpszPath = CharNextA(lpszPath); + } + return TRUE; + } + } + else if (lpszPath[1] == ':' && lpszPath[2] == '\\' && lpszPath[3] == '\0') + return TRUE; /* X:\ */ + } + return FALSE; +} + +/************************************************************************* + * PathIsRootW [SHLWAPI.@] + * + * See PathIsRootA. + */ +BOOL WINAPI PathIsRootW(LPCWSTR lpszPath) +{ + TRACE("(%s)\n", debugstr_w(lpszPath)); + + if (lpszPath && *lpszPath) + { + if (*lpszPath == '\\') + { + if (!lpszPath[1]) + return TRUE; /* \ */ + else if (lpszPath[1]=='\\') + { + BOOL bSeenSlash = FALSE; + lpszPath += 2; + + /* Check for UNC root path */ + while (*lpszPath) + { + if (*lpszPath == '\\') + { + if (bSeenSlash) + return FALSE; + bSeenSlash = TRUE; + } + lpszPath = CharNextW(lpszPath); + } + return TRUE; + } + } + else if (lpszPath[1] == ':' && lpszPath[2] == '\\' && lpszPath[3] == '\0') + return TRUE; /* X:\ */ + } + return FALSE; +} + +/************************************************************************* + * PathIsDirectoryA [SHLWAPI.@] + * + * Determine if a path is a valid directory + * + * PARAMS + * lpszPath [I] Path to check. + * + * RETURNS + * FILE_ATTRIBUTE_DIRECTORY if lpszPath exists and can be read (See Notes) + * FALSE if lpszPath is invalid or not a directory. + * + * NOTES + * Although this function is prototyped as returning a BOOL, it returns + * FILE_ATTRIBUTE_DIRECTORY for success. This means that code such as: + * + *| if (PathIsDirectoryA("c:\\windows\\") == TRUE) + *| ... + * + * will always fail. + */ +BOOL WINAPI PathIsDirectoryA(LPCSTR lpszPath) +{ + DWORD dwAttr; + + TRACE("(%s)\n", debugstr_a(lpszPath)); + + if (!lpszPath || PathIsUNCServerA(lpszPath)) + return FALSE; + + if (PathIsUNCServerShareA(lpszPath)) + { + FIXME("UNC Server Share not yet supported - FAILING\n"); + return FALSE; + } + + if ((dwAttr = GetFileAttributesA(lpszPath)) == INVALID_FILE_ATTRIBUTES) + return FALSE; + return dwAttr & FILE_ATTRIBUTE_DIRECTORY; +} + +/************************************************************************* + * PathIsDirectoryW [SHLWAPI.@] + * + * See PathIsDirectoryA. + */ +BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath) +{ + DWORD dwAttr; + + TRACE("(%s)\n", debugstr_w(lpszPath)); + + if (!lpszPath || PathIsUNCServerW(lpszPath)) + return FALSE; + + if (PathIsUNCServerShareW(lpszPath)) + { + FIXME("UNC Server Share not yet supported - FAILING\n"); + return FALSE; + } + + if ((dwAttr = GetFileAttributesW(lpszPath)) == INVALID_FILE_ATTRIBUTES) + return FALSE; + return dwAttr & FILE_ATTRIBUTE_DIRECTORY; +} + +/************************************************************************* + * PathFileExistsA [SHLWAPI.@] + * + * Determine if a file exists. + * + * PARAMS + * lpszPath [I] Path to check + * + * RETURNS + * TRUE If the file exists and is readable + * FALSE Otherwise + */ +BOOL WINAPI PathFileExistsA(LPCSTR lpszPath) +{ + UINT iPrevErrMode; + DWORD dwAttr; + + TRACE("(%s)\n",debugstr_a(lpszPath)); + + if (!lpszPath) + return FALSE; + + /* Prevent a dialog box if path is on a disk that has been ejected. */ + iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS); + dwAttr = GetFileAttributesA(lpszPath); + SetErrorMode(iPrevErrMode); + return dwAttr == INVALID_FILE_ATTRIBUTES ? FALSE : TRUE; +} + +/************************************************************************* + * PathFileExistsW [SHLWAPI.@] + * + * See PathFileExistsA. + */ +BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath) +{ + UINT iPrevErrMode; + DWORD dwAttr; + + TRACE("(%s)\n",debugstr_w(lpszPath)); + + if (!lpszPath) + return FALSE; + + iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS); + dwAttr = GetFileAttributesW(lpszPath); + SetErrorMode(iPrevErrMode); + return dwAttr == INVALID_FILE_ATTRIBUTES ? FALSE : TRUE; +} + +/************************************************************************* + * PathFileExistsAndAttributesA [SHLWAPI.445] + * + * Determine if a file exists. + * + * PARAMS + * lpszPath [I] Path to check + * dwAttr [O] attributes of file + * + * RETURNS + * TRUE If the file exists and is readable + * FALSE Otherwise + */ +BOOL WINAPI PathFileExistsAndAttributesA(LPCSTR lpszPath, DWORD *dwAttr) +{ + UINT iPrevErrMode; + DWORD dwVal = 0; + + TRACE("(%s %p)\n", debugstr_a(lpszPath), dwAttr); + + if (dwAttr) + *dwAttr = INVALID_FILE_ATTRIBUTES; + + if (!lpszPath) + return FALSE; + + iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS); + dwVal = GetFileAttributesA(lpszPath); + SetErrorMode(iPrevErrMode); + if (dwAttr) + *dwAttr = dwVal; + return (dwVal != INVALID_FILE_ATTRIBUTES); +} + +/************************************************************************* + * PathFileExistsAndAttributesW [SHLWAPI.446] + * + * See PathFileExistsA. + */ +BOOL WINAPI PathFileExistsAndAttributesW(LPCWSTR lpszPath, DWORD *dwAttr) +{ + UINT iPrevErrMode; + DWORD dwVal; + + TRACE("(%s %p)\n", debugstr_w(lpszPath), dwAttr); + + if (!lpszPath) + return FALSE; + + iPrevErrMode = SetErrorMode(SEM_FAILCRITICALERRORS); + dwVal = GetFileAttributesW(lpszPath); + SetErrorMode(iPrevErrMode); + if (dwAttr) + *dwAttr = dwVal; + return (dwVal != INVALID_FILE_ATTRIBUTES); +} + +/************************************************************************* + * PathMatchSingleMaskA [internal] + */ +static BOOL WINAPI PathMatchSingleMaskA(LPCSTR name, LPCSTR mask) +{ + while (*name && *mask && *mask!=';') + { + if (*mask == '*') + { + do + { + if (PathMatchSingleMaskA(name,mask+1)) + return TRUE; /* try substrings */ + } while (*name++); + return FALSE; + } + + if (toupper(*mask) != toupper(*name) && *mask != '?') + return FALSE; + + name = CharNextA(name); + mask = CharNextA(mask); + } + + if (!*name) + { + while (*mask == '*') + mask++; + if (!*mask || *mask == ';') + return TRUE; + } + return FALSE; +} + +/************************************************************************* + * PathMatchSingleMaskW [internal] + */ +static BOOL WINAPI PathMatchSingleMaskW(LPCWSTR name, LPCWSTR mask) +{ + while (*name && *mask && *mask != ';') + { + if (*mask == '*') + { + do + { + if (PathMatchSingleMaskW(name,mask+1)) + return TRUE; /* try substrings */ + } while (*name++); + return FALSE; + } + + if (toupperW(*mask) != toupperW(*name) && *mask != '?') + return FALSE; + + name = CharNextW(name); + mask = CharNextW(mask); + } + if (!*name) + { + while (*mask == '*') + mask++; + if (!*mask || *mask == ';') + return TRUE; + } + return FALSE; +} + +/************************************************************************* + * PathMatchSpecA [SHLWAPI.@] + * + * Determine if a path matches one or more search masks. + * + * PARAMS + * lpszPath [I] Path to check + * lpszMask [I] Search mask(s) + * + * RETURNS + * TRUE If lpszPath is valid and is matched + * FALSE Otherwise + * + * NOTES + * Multiple search masks may be given if they are separated by ";". The + * pattern "*.*" is treated specially in that it matches all paths (for + * backwards compatibility with DOS). + */ +BOOL WINAPI PathMatchSpecA(LPCSTR lpszPath, LPCSTR lpszMask) +{ + TRACE("(%s,%s)\n", lpszPath, lpszMask); + + if (!lstrcmpA(lpszMask, "*.*")) + return TRUE; /* Matches every path */ + + while (*lpszMask) + { + if (PathMatchSingleMaskA(lpszPath, lpszMask)) + return TRUE; /* Matches the current mask */ + + while (*lpszMask && *lpszMask != ';') + lpszMask = CharNextA(lpszMask); + + if (*lpszMask == ';') + { + lpszMask++; + while (*lpszMask == ' ') + lpszMask++; /* masks may be separated by "; " */ + } + } + return FALSE; +} + +/************************************************************************* + * PathMatchSpecW [SHLWAPI.@] + * + * See PathMatchSpecA. + */ +BOOL WINAPI PathMatchSpecW(LPCWSTR lpszPath, LPCWSTR lpszMask) +{ + static const WCHAR szStarDotStar[] = { '*', '.', '*', '\0' }; + + TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszMask)); + + if (!lstrcmpW(lpszMask, szStarDotStar)) + return TRUE; /* Matches every path */ + + while (*lpszMask) + { + if (PathMatchSingleMaskW(lpszPath, lpszMask)) + return TRUE; /* Matches the current path */ + + while (*lpszMask && *lpszMask != ';') + lpszMask++; + + if (*lpszMask == ';') + { + lpszMask++; + while (*lpszMask == ' ') + lpszMask++; /* Masks may be separated by "; " */ + } + } + return FALSE; +} + +/************************************************************************* + * PathIsSameRootA [SHLWAPI.@] + * + * Determine if two paths share the same root. + * + * PARAMS + * lpszPath1 [I] Source path + * lpszPath2 [I] Path to compare with + * + * RETURNS + * TRUE If both paths are valid and share the same root. + * FALSE If either path is invalid or the paths do not share the same root. + */ +BOOL WINAPI PathIsSameRootA(LPCSTR lpszPath1, LPCSTR lpszPath2) +{ + LPCSTR lpszStart; + int dwLen; + + TRACE("(%s,%s)\n", debugstr_a(lpszPath1), debugstr_a(lpszPath2)); + + if (!lpszPath1 || !lpszPath2 || !(lpszStart = PathSkipRootA(lpszPath1))) + return FALSE; + + dwLen = PathCommonPrefixA(lpszPath1, lpszPath2, NULL) + 1; + if (lpszStart - lpszPath1 > dwLen) + return FALSE; /* Paths not common up to length of the root */ + return TRUE; +} + +/************************************************************************* + * PathIsSameRootW [SHLWAPI.@] + * + * See PathIsSameRootA. + */ +BOOL WINAPI PathIsSameRootW(LPCWSTR lpszPath1, LPCWSTR lpszPath2) +{ + LPCWSTR lpszStart; + int dwLen; + + TRACE("(%s,%s)\n", debugstr_w(lpszPath1), debugstr_w(lpszPath2)); + + if (!lpszPath1 || !lpszPath2 || !(lpszStart = PathSkipRootW(lpszPath1))) + return FALSE; + + dwLen = PathCommonPrefixW(lpszPath1, lpszPath2, NULL) + 1; + if (lpszStart - lpszPath1 > dwLen) + return FALSE; /* Paths not common up to length of the root */ + return TRUE; +} + +/************************************************************************* + * PathIsContentTypeA [SHLWAPI.@] + * + * Determine if a file is of a given registered content type. + * + * PARAMS + * lpszPath [I] File to check + * lpszContentType [I] Content type to check for + * + * RETURNS + * TRUE If lpszPath is a given registered content type, + * FALSE Otherwise. + * + * NOTES + * This function looks up the registered content type for lpszPath. If + * a content type is registered, it is compared (case insensitively) to + * lpszContentType. Only if this matches does the function succeed. + */ +BOOL WINAPI PathIsContentTypeA(LPCSTR lpszPath, LPCSTR lpszContentType) +{ + LPCSTR szExt; + DWORD dwDummy; + char szBuff[MAX_PATH]; + + TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszContentType)); + + if (lpszPath && (szExt = PathFindExtensionA(lpszPath)) && *szExt && + !SHGetValueA(HKEY_CLASSES_ROOT, szExt, "Content Type", + REG_NONE, szBuff, &dwDummy) && + !strcasecmp(lpszContentType, szBuff)) + { + return TRUE; + } + return FALSE; +} + +/************************************************************************* + * PathIsContentTypeW [SHLWAPI.@] + * + * See PathIsContentTypeA. + */ +BOOL WINAPI PathIsContentTypeW(LPCWSTR lpszPath, LPCWSTR lpszContentType) +{ + static const WCHAR szContentType[] = { 'C','o','n','t','e','n','t',' ','T','y','p','e','\0' }; + LPCWSTR szExt; + DWORD dwDummy; + WCHAR szBuff[MAX_PATH]; + + TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszContentType)); + + if (lpszPath && (szExt = PathFindExtensionW(lpszPath)) && *szExt && + !SHGetValueW(HKEY_CLASSES_ROOT, szExt, szContentType, + REG_NONE, szBuff, &dwDummy) && + !strcmpiW(lpszContentType, szBuff)) + { + return TRUE; + } + return FALSE; +} + +/************************************************************************* + * PathIsFileSpecA [SHLWAPI.@] + * + * Determine if a path is a file specification. + * + * PARAMS + * lpszPath [I] Path to chack + * + * RETURNS + * TRUE If lpszPath is a file specification (i.e. Contains no directories). + * FALSE Otherwise. + */ +BOOL WINAPI PathIsFileSpecA(LPCSTR lpszPath) +{ + TRACE("(%s)\n", debugstr_a(lpszPath)); + + if (!lpszPath) + return FALSE; + + while (*lpszPath) + { + if (*lpszPath == '\\' || *lpszPath == ':') + return FALSE; + lpszPath = CharNextA(lpszPath); + } + return TRUE; +} + +/************************************************************************* + * PathIsFileSpecW [SHLWAPI.@] + * + * See PathIsFileSpecA. + */ +BOOL WINAPI PathIsFileSpecW(LPCWSTR lpszPath) +{ + TRACE("(%s)\n", debugstr_w(lpszPath)); + + if (!lpszPath) + return FALSE; + + while (*lpszPath) + { + if (*lpszPath == '\\' || *lpszPath == ':') + return FALSE; + lpszPath = CharNextW(lpszPath); + } + return TRUE; +} + +/************************************************************************* + * PathIsPrefixA [SHLWAPI.@] + * + * Determine if a path is a prefix of another. + * + * PARAMS + * lpszPrefix [I] Prefix + * lpszPath [I] Path to check + * + * RETURNS + * TRUE If lpszPath has lpszPrefix as its prefix, + * FALSE If either path is NULL or lpszPrefix is not a prefix + */ +BOOL WINAPI PathIsPrefixA (LPCSTR lpszPrefix, LPCSTR lpszPath) +{ + TRACE("(%s,%s)\n", debugstr_a(lpszPrefix), debugstr_a(lpszPath)); + + if (lpszPrefix && lpszPath && + PathCommonPrefixA(lpszPath, lpszPrefix, NULL) == (int)strlen(lpszPrefix)) + return TRUE; + return FALSE; +} + +/************************************************************************* + * PathIsPrefixW [SHLWAPI.@] + * + * See PathIsPrefixA. + */ +BOOL WINAPI PathIsPrefixW(LPCWSTR lpszPrefix, LPCWSTR lpszPath) +{ + TRACE("(%s,%s)\n", debugstr_w(lpszPrefix), debugstr_w(lpszPath)); + + if (lpszPrefix && lpszPath && + PathCommonPrefixW(lpszPath, lpszPrefix, NULL) == (int)strlenW(lpszPrefix)) + return TRUE; + return FALSE; +} + +/************************************************************************* + * PathIsSystemFolderA [SHLWAPI.@] + * + * Determine if a path or file attributes are a system folder. + * + * PARAMS + * lpszPath [I] Path to check. + * dwAttrib [I] Attributes to check, if lpszPath is NULL. + * + * RETURNS + * TRUE If lpszPath or dwAttrib are a system folder. + * FALSE If GetFileAttributesA() fails or neither parameter is a system folder. + */ +BOOL WINAPI PathIsSystemFolderA(LPCSTR lpszPath, DWORD dwAttrib) +{ + TRACE("(%s,0x%08lx)\n", debugstr_a(lpszPath), dwAttrib); + + if (lpszPath && *lpszPath) + dwAttrib = GetFileAttributesA(lpszPath); + + if (dwAttrib == INVALID_FILE_ATTRIBUTES || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY) || + !(dwAttrib & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY))) + return FALSE; + return TRUE; +} + +/************************************************************************* + * PathIsSystemFolderW [SHLWAPI.@] + * + * See PathIsSystemFolderA. + */ +BOOL WINAPI PathIsSystemFolderW(LPCWSTR lpszPath, DWORD dwAttrib) +{ + TRACE("(%s,0x%08lx)\n", debugstr_w(lpszPath), dwAttrib); + + if (lpszPath && *lpszPath) + dwAttrib = GetFileAttributesW(lpszPath); + + if (dwAttrib == INVALID_FILE_ATTRIBUTES || !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY) || + !(dwAttrib & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY))) + return FALSE; + return TRUE; +} + +/************************************************************************* + * PathIsUNCA [SHLWAPI.@] + * + * Determine if a path is in UNC format. + * + * PARAMS + * lpszPath [I] Path to check + * + * RETURNS + * TRUE: The path is UNC. + * FALSE: The path is not UNC or is NULL. + */ +BOOL WINAPI PathIsUNCA(LPCSTR lpszPath) +{ + TRACE("(%s)\n",debugstr_a(lpszPath)); + + if (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\')) + return TRUE; + return FALSE; +} + +/************************************************************************* + * PathIsUNCW [SHLWAPI.@] + * + * See PathIsUNCA. + */ +BOOL WINAPI PathIsUNCW(LPCWSTR lpszPath) +{ + TRACE("(%s)\n",debugstr_w(lpszPath)); + + if (lpszPath && (lpszPath[0]=='\\') && (lpszPath[1]=='\\')) + return TRUE; + return FALSE; +} + +/************************************************************************* + * PathIsUNCServerA [SHLWAPI.@] + * + * Determine if a path is a UNC server name ("\\SHARENAME"). + * + * PARAMS + * lpszPath [I] Path to check. + * + * RETURNS + * TRUE If lpszPath is a valid UNC server name. + * FALSE Otherwise. + * + * NOTES + * This routine is bug compatible with Win32: Server names with a + * trailing backslash (e.g. "\\FOO\"), return FALSE incorrectly. + * Fixing this bug may break other shlwapi functions! + */ +BOOL WINAPI PathIsUNCServerA(LPCSTR lpszPath) +{ + TRACE("(%s)\n", debugstr_a(lpszPath)); + + if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\') + { + while (*lpszPath) + { + if (*lpszPath == '\\') + return FALSE; + lpszPath = CharNextA(lpszPath); + } + return TRUE; + } + return FALSE; +} + +/************************************************************************* + * PathIsUNCServerW [SHLWAPI.@] + * + * See PathIsUNCServerA. + */ +BOOL WINAPI PathIsUNCServerW(LPCWSTR lpszPath) +{ + TRACE("(%s)\n", debugstr_w(lpszPath)); + + if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\') + { + while (*lpszPath) + { + if (*lpszPath == '\\') + return FALSE; + lpszPath = CharNextW(lpszPath); + } + return TRUE; + } + return FALSE; +} + +/************************************************************************* + * PathIsUNCServerShareA [SHLWAPI.@] + * + * Determine if a path is a UNC server share ("\\SHARENAME\SHARE"). + * + * PARAMS + * lpszPath [I] Path to check. + * + * RETURNS + * TRUE If lpszPath is a valid UNC server share. + * FALSE Otherwise. + * + * NOTES + * This routine is bug compatible with Win32: Server shares with a + * trailing backslash (e.g. "\\FOO\BAR\"), return FALSE incorrectly. + * Fixing this bug may break other shlwapi functions! + */ +BOOL WINAPI PathIsUNCServerShareA(LPCSTR lpszPath) +{ + TRACE("(%s)\n", debugstr_a(lpszPath)); + + if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\') + { + BOOL bSeenSlash = FALSE; + while (*lpszPath) + { + if (*lpszPath == '\\') + { + if (bSeenSlash) + return FALSE; + bSeenSlash = TRUE; + } + lpszPath = CharNextA(lpszPath); + } + return bSeenSlash; + } + return FALSE; +} + +/************************************************************************* + * PathIsUNCServerShareW [SHLWAPI.@] + * + * See PathIsUNCServerShareA. + */ +BOOL WINAPI PathIsUNCServerShareW(LPCWSTR lpszPath) +{ + TRACE("(%s)\n", debugstr_w(lpszPath)); + + if (lpszPath && *lpszPath++ == '\\' && *lpszPath++ == '\\') + { + BOOL bSeenSlash = FALSE; + while (*lpszPath) + { + if (*lpszPath == '\\') + { + if (bSeenSlash) + return FALSE; + bSeenSlash = TRUE; + } + lpszPath = CharNextW(lpszPath); + } + return bSeenSlash; + } + return FALSE; +} + +/************************************************************************* + * PathCanonicalizeA [SHLWAPI.@] + * + * Convert a path to its canonical form. + * + * PARAMS + * lpszBuf [O] Output path + * lpszPath [I] Path to cnonicalize + * + * RETURNS + * Success: TRUE. lpszBuf contains the output path, + * Failure: FALSE, If input path is invalid. lpszBuf is undefined + */ +BOOL WINAPI PathCanonicalizeA(LPSTR lpszBuf, LPCSTR lpszPath) +{ + BOOL bRet = FALSE; + + TRACE("(%p,%s)\n", lpszBuf, debugstr_a(lpszPath)); + + if (lpszBuf) + *lpszBuf = '\0'; + + if (!lpszBuf || !lpszPath) + SetLastError(ERROR_INVALID_PARAMETER); + else + { + WCHAR szPath[MAX_PATH]; + WCHAR szBuff[MAX_PATH]; + MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH); + bRet = PathCanonicalizeW(szBuff, szPath); + WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszBuf,MAX_PATH,0,0); + } + return bRet; +} + + +/************************************************************************* + * PathCanonicalizeW [SHLWAPI.@] + * + * See PathCanonicalizeA. + */ +BOOL WINAPI PathCanonicalizeW(LPWSTR lpszBuf, LPCWSTR lpszPath) +{ + LPWSTR lpszDst = lpszBuf; + LPCWSTR lpszSrc = lpszPath; + + TRACE("(%p,%s)\n", lpszBuf, debugstr_w(lpszPath)); + + if (lpszBuf) + *lpszDst = '\0'; + + if (!lpszBuf || !lpszPath) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (!*lpszPath) + { + *lpszBuf++ = '\\'; + *lpszBuf = '\0'; + return TRUE; + } + + /* Copy path root */ + if (*lpszSrc == '\\') + { + *lpszDst++ = *lpszSrc++; + } + else if (*lpszSrc && lpszSrc[1] == ':') + { + /* X:\ */ + *lpszDst++ = *lpszSrc++; + *lpszDst++ = *lpszSrc++; + if (*lpszSrc == '\\') + *lpszDst++ = *lpszSrc++; + } + + /* Canonicalize the rest of the path */ + while (*lpszSrc) + { + if (*lpszSrc == '.') + { + if (lpszSrc[1] == '\\' && (lpszSrc == lpszPath || lpszSrc[-1] == '\\' || lpszSrc[-1] == ':')) + { + lpszSrc += 2; /* Skip .\ */ + } + else if (lpszSrc[1] == '.' && (lpszDst == lpszBuf || lpszDst[-1] == '\\')) + { + /* \.. backs up a directory, over the root if it has no \ following X:. + * .. is ignored if it would remove a UNC server name or inital \\ + */ + if (lpszDst != lpszBuf) + { + *lpszDst = '\0'; /* Allow PathIsUNCServerShareA test on lpszBuf */ + if (lpszDst > lpszBuf+1 && lpszDst[-1] == '\\' && + (lpszDst[-2] != '\\' || lpszDst > lpszBuf+2)) + { + if (lpszDst[-2] == ':' && (lpszDst > lpszBuf+3 || lpszDst[-3] == ':')) + { + lpszDst -= 2; + while (lpszDst > lpszBuf && *lpszDst != '\\') + lpszDst--; + if (*lpszDst == '\\') + lpszDst++; /* Reset to last '\' */ + else + lpszDst = lpszBuf; /* Start path again from new root */ + } + else if (lpszDst[-2] != ':' && !PathIsUNCServerShareW(lpszBuf)) + lpszDst -= 2; + } + while (lpszDst > lpszBuf && *lpszDst != '\\') + lpszDst--; + if (lpszDst == lpszBuf) + { + *lpszDst++ = '\\'; + lpszSrc++; + } + } + lpszSrc += 2; /* Skip .. in src path */ + } + else + *lpszDst++ = *lpszSrc++; + } + else + *lpszDst++ = *lpszSrc++; + } + /* Append \ to naked drive specs */ + if (lpszDst - lpszBuf == 2 && lpszDst[-1] == ':') + *lpszDst++ = '\\'; + *lpszDst++ = '\0'; + return TRUE; +} + +/************************************************************************* + * PathFindNextComponentA [SHLWAPI.@] + * + * Find the next component in a path. + * + * PARAMS + * lpszPath [I] Path to find next component in + * + * RETURNS + * Success: A pointer to the next component, or the end of the string. + * Failure: NULL, If lpszPath is invalid + * + * NOTES + * A 'component' is either a backslash character (\) or UNC marker (\\). + * Because of this, relative paths (e.g "c:foo") are regarded as having + * only one component. + */ +LPSTR WINAPI PathFindNextComponentA(LPCSTR lpszPath) +{ + LPSTR lpszSlash; + + TRACE("(%s)\n", debugstr_a(lpszPath)); + + if(!lpszPath || !*lpszPath) + return NULL; + + if ((lpszSlash = StrChrA(lpszPath, '\\'))) + { + if (lpszSlash[1] == '\\') + lpszSlash++; + return lpszSlash + 1; + } + return (LPSTR)lpszPath + strlen(lpszPath); +} + +/************************************************************************* + * PathFindNextComponentW [SHLWAPI.@] + * + * See PathFindNextComponentA. + */ +LPWSTR WINAPI PathFindNextComponentW(LPCWSTR lpszPath) +{ + LPWSTR lpszSlash; + + TRACE("(%s)\n", debugstr_w(lpszPath)); + + if(!lpszPath || !*lpszPath) + return NULL; + + if ((lpszSlash = StrChrW(lpszPath, '\\'))) + { + if (lpszSlash[1] == '\\') + lpszSlash++; + return lpszSlash + 1; + } + return (LPWSTR)lpszPath + strlenW(lpszPath); +} + +/************************************************************************* + * PathAddExtensionA [SHLWAPI.@] + * + * Add a file extension to a path + * + * PARAMS + * lpszPath [I/O] Path to add extension to + * lpszExtension [I] Extension to add to lpszPath + * + * RETURNS + * TRUE If the path was modified, + * FALSE If lpszPath or lpszExtension are invalid, lpszPath has an + * extension allready, or the new path length is too big. + * + * FIXME + * What version of shlwapi.dll adds "exe" if lpszExtension is NULL? Win2k + * does not do this, so the behaviour was removed. + */ +BOOL WINAPI PathAddExtensionA(LPSTR lpszPath, LPCSTR lpszExtension) +{ + size_t dwLen; + + TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszExtension)); + + if (!lpszPath || !lpszExtension || *(PathFindExtensionA(lpszPath))) + return FALSE; + + dwLen = strlen(lpszPath); + + if (dwLen + strlen(lpszExtension) >= MAX_PATH) + return FALSE; + + strcpy(lpszPath + dwLen, lpszExtension); + return TRUE; +} + +/************************************************************************* + * PathAddExtensionW [SHLWAPI.@] + * + * See PathAddExtensionA. + */ +BOOL WINAPI PathAddExtensionW(LPWSTR lpszPath, LPCWSTR lpszExtension) +{ + size_t dwLen; + + TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszExtension)); + + if (!lpszPath || !lpszExtension || *(PathFindExtensionW(lpszPath))) + return FALSE; + + dwLen = strlenW(lpszPath); + + if (dwLen + strlenW(lpszExtension) >= MAX_PATH) + return FALSE; + + strcpyW(lpszPath + dwLen, lpszExtension); + return TRUE; +} + +/************************************************************************* + * PathMakePrettyA [SHLWAPI.@] + * + * Convert an uppercase DOS filename into lowercase. + * + * PARAMS + * lpszPath [I/O] Path to convert. + * + * RETURNS + * TRUE If the path was an uppercase DOS path and was converted, + * FALSE Otherwise. + */ +BOOL WINAPI PathMakePrettyA(LPSTR lpszPath) +{ + LPSTR pszIter = lpszPath; + + TRACE("(%s)\n", debugstr_a(lpszPath)); + + if (!pszIter) + return FALSE; + + if (*pszIter) + { + do + { + if (islower(*pszIter) || IsDBCSLeadByte(*pszIter)) + return FALSE; /* Not DOS path */ + pszIter++; + } while (*pszIter); + pszIter = lpszPath + 1; + while (*pszIter) + { + *pszIter = tolower(*pszIter); + pszIter++; + } + } + return TRUE; +} + +/************************************************************************* + * PathMakePrettyW [SHLWAPI.@] + * + * See PathMakePrettyA. + */ +BOOL WINAPI PathMakePrettyW(LPWSTR lpszPath) +{ + LPWSTR pszIter = lpszPath; + + TRACE("(%s)\n", debugstr_w(lpszPath)); + + if (!pszIter) + return FALSE; + + if (*pszIter) + { + do + { + if (islowerW(*pszIter)) + return FALSE; /* Not DOS path */ + pszIter++; + } while (*pszIter); + pszIter = lpszPath + 1; + while (*pszIter) + { + *pszIter = tolowerW(*pszIter); + pszIter++; + } + } + return TRUE; +} + +/************************************************************************* + * PathCommonPrefixA [SHLWAPI.@] + * + * Determine the length of the common prefix between two paths. + * + * PARAMS + * lpszFile1 [I] First path for comparison + * lpszFile2 [I] Second path for comparison + * achPath [O] Destination for common prefix string + * + * RETURNS + * The length of the common prefix. This is 0 if there is no common + * prefix between the paths or if any parameters are invalid. If the prefix + * is non-zero and achPath is not NULL, achPath is filled with the common + * part of the prefix and NUL terminated. + * + * NOTES + * A common prefix of 2 is always returned as 3. It is thus possible for + * the length returned to be invalid (i.e. Longer than one or both of the + * strings given as parameters). This Win32 behaviour has been implemented + * here, and cannot be changed (fixed?) without breaking other SHLWAPI calls. + * To work around this when using this function, always check that the byte + * at [common_prefix_len-1] is not a NUL. If it is, deduct 1 from the prefix. + */ +int WINAPI PathCommonPrefixA(LPCSTR lpszFile1, LPCSTR lpszFile2, LPSTR achPath) +{ + size_t iLen = 0; + LPCSTR lpszIter1 = lpszFile1; + LPCSTR lpszIter2 = lpszFile2; + + TRACE("(%s,%s,%p)\n", debugstr_a(lpszFile1), debugstr_a(lpszFile2), achPath); + + if (achPath) + *achPath = '\0'; + + if (!lpszFile1 || !lpszFile2) + return 0; + + /* Handle roots first */ + if (PathIsUNCA(lpszFile1)) + { + if (!PathIsUNCA(lpszFile2)) + return 0; + lpszIter1 += 2; + lpszIter2 += 2; + } + else if (PathIsUNCA(lpszFile2)) + return 0; /* Know already lpszFile1 is not UNC */ + + do + { + /* Update len */ + if ((!*lpszIter1 || *lpszIter1 == '\\') && + (!*lpszIter2 || *lpszIter2 == '\\')) + iLen = lpszIter1 - lpszFile1; /* Common to this point */ + + if (!*lpszIter1 || (tolower(*lpszIter1) != tolower(*lpszIter2))) + break; /* Strings differ at this point */ + + lpszIter1++; + lpszIter2++; + } while (1); + + if (iLen == 2) + iLen++; /* Feature/Bug compatible with Win32 */ + + if (iLen && achPath) + { + memcpy(achPath,lpszFile1,iLen); + achPath[iLen] = '\0'; + } + return iLen; +} + +/************************************************************************* + * PathCommonPrefixW [SHLWAPI.@] + * + * See PathCommonPrefixA. + */ +int WINAPI PathCommonPrefixW(LPCWSTR lpszFile1, LPCWSTR lpszFile2, LPWSTR achPath) +{ + size_t iLen = 0; + LPCWSTR lpszIter1 = lpszFile1; + LPCWSTR lpszIter2 = lpszFile2; + + TRACE("(%s,%s,%p)\n", debugstr_w(lpszFile1), debugstr_w(lpszFile2), achPath); + + if (achPath) + *achPath = '\0'; + + if (!lpszFile1 || !lpszFile2) + return 0; + + /* Handle roots first */ + if (PathIsUNCW(lpszFile1)) + { + if (!PathIsUNCW(lpszFile2)) + return 0; + lpszIter1 += 2; + lpszIter2 += 2; + } + else if (PathIsUNCW(lpszFile2)) + return 0; /* Know already lpszFile1 is not UNC */ + + do + { + /* Update len */ + if ((!*lpszIter1 || *lpszIter1 == '\\') && + (!*lpszIter2 || *lpszIter2 == '\\')) + iLen = lpszIter1 - lpszFile1; /* Common to this point */ + + if (!*lpszIter1 || (tolowerW(*lpszIter1) != tolowerW(*lpszIter2))) + break; /* Strings differ at this point */ + + lpszIter1++; + lpszIter2++; + } while (1); + + if (iLen == 2) + iLen++; /* Feature/Bug compatible with Win32 */ + + if (iLen && achPath) + { + memcpy(achPath,lpszFile1,iLen * sizeof(WCHAR)); + achPath[iLen] = '\0'; + } + return iLen; +} + +/************************************************************************* + * PathCompactPathA [SHLWAPI.@] + * + * Make a path fit into a given width when printed to a DC. + * + * PARAMS + * hDc [I] Destination DC + * lpszPath [I/O] Path to be printed to hDc + * dx [I] Desired width + * + * RETURNS + * TRUE If the path was modified/went well. + * FALSE Otherwise. + */ +BOOL WINAPI PathCompactPathA(HDC hDC, LPSTR lpszPath, UINT dx) +{ + BOOL bRet = FALSE; + + TRACE("(%p,%s,%d)\n", hDC, debugstr_a(lpszPath), dx); + + if (lpszPath) + { + WCHAR szPath[MAX_PATH]; + MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH); + bRet = PathCompactPathW(hDC, szPath, dx); + WideCharToMultiByte(CP_ACP,0,szPath,-1,lpszPath,MAX_PATH,0,0); + } + return bRet; +} + +/************************************************************************* + * PathCompactPathW [SHLWAPI.@] + * + * See PathCompactPathA. + */ +BOOL WINAPI PathCompactPathW(HDC hDC, LPWSTR lpszPath, UINT dx) +{ + static const WCHAR szEllipses[] = { '.', '.', '.', '\0' }; + BOOL bRet = TRUE; + HDC hdc = 0; + WCHAR buff[MAX_PATH]; + SIZE size; + DWORD dwLen; + + TRACE("(%p,%s,%d)\n", hDC, debugstr_w(lpszPath), dx); + + if (!lpszPath) + return FALSE; + + if (!hDC) + hdc = hDC = GetDC(0); + + /* Get the length of the whole path */ + dwLen = strlenW(lpszPath); + GetTextExtentPointW(hDC, lpszPath, dwLen, &size); + + if ((UINT)size.cx > dx) + { + /* Path too big, must reduce it */ + LPWSTR sFile; + DWORD dwEllipsesLen = 0, dwPathLen = 0; + + sFile = PathFindFileNameW(lpszPath); + if (sFile != lpszPath) + sFile = CharPrevW(lpszPath, sFile); + + /* Get the size of ellipses */ + GetTextExtentPointW(hDC, szEllipses, 3, &size); + dwEllipsesLen = size.cx; + /* Get the size of the file name */ + GetTextExtentPointW(hDC, sFile, strlenW(sFile), &size); + dwPathLen = size.cx; + + if (sFile != lpszPath) + { + LPWSTR sPath = sFile; + BOOL bEllipses = FALSE; + + /* The path includes a file name. Include as much of the path prior to + * the file name as possible, allowing for the ellipses, e.g: + * c:\some very long path\filename ==> c:\some v...\filename + */ + lstrcpynW(buff, sFile, MAX_PATH); + + do + { + DWORD dwTotalLen = bEllipses? dwPathLen + dwEllipsesLen : dwPathLen; + + GetTextExtentPointW(hDC, lpszPath, sPath - lpszPath, &size); + dwTotalLen += size.cx; + if (dwTotalLen <= dx) + break; + sPath = CharPrevW(lpszPath, sPath); + if (!bEllipses) + { + bEllipses = TRUE; + sPath = CharPrevW(lpszPath, sPath); + sPath = CharPrevW(lpszPath, sPath); + } + } while (sPath > lpszPath); + + if (sPath > lpszPath) + { + if (bEllipses) + { + strcpyW(sPath, szEllipses); + strcpyW(sPath+3, buff); + } + bRet = TRUE; + goto end; + } + strcpyW(lpszPath, szEllipses); + strcpyW(lpszPath+3, buff); + bRet = FALSE; + goto end; + } + + /* Trim the path by adding ellipses to the end, e.g: + * A very long file name.txt ==> A very... + */ + dwLen = strlenW(lpszPath); + + if (dwLen > MAX_PATH - 3) + dwLen = MAX_PATH - 3; + lstrcpynW(buff, sFile, dwLen); + + do { + dwLen--; + GetTextExtentPointW(hDC, buff, dwLen, &size); + } while (dwLen && size.cx + dwEllipsesLen > dx); + + if (!dwLen) + { + DWORD dwWritten = 0; + + dwEllipsesLen /= 3; /* Size of a single '.' */ + + /* Write as much of the Ellipses string as possible */ + while (dwWritten + dwEllipsesLen < dx && dwLen < 3) + { + *lpszPath++ = '.'; + dwWritten += dwEllipsesLen; + dwLen++; + } + *lpszPath = '\0'; + bRet = FALSE; + } + else + { + strcpyW(buff + dwLen, szEllipses); + strcpyW(lpszPath, buff); + } + } + +end: + if (hdc) + ReleaseDC(0, hdc); + + return bRet; +} + +/************************************************************************* + * PathGetCharTypeA [SHLWAPI.@] + * + * Categorise a character from a file path. + * + * PARAMS + * ch [I] Character to get the type of + * + * RETURNS + * A set of GCT_ bit flags (from "shlwapi.h") indicating the character type. + */ +UINT WINAPI PathGetCharTypeA(UCHAR ch) +{ + return PathGetCharTypeW(ch); +} + +/************************************************************************* + * PathGetCharTypeW [SHLWAPI.@] + * + * See PathGetCharTypeA. + */ +UINT WINAPI PathGetCharTypeW(WCHAR ch) +{ + UINT flags = 0; + + TRACE("(%d)\n", ch); + + if (!ch || ch < ' ' || ch == '<' || ch == '>' || + ch == '"' || ch == '|' || ch == '/') + flags = GCT_INVALID; /* Invalid */ + else if (ch == '*' || ch=='?') + flags = GCT_WILD; /* Wildchars */ + else if ((ch == '\\') || (ch == ':')) + return GCT_SEPARATOR; /* Path separators */ + else + { + if (ch < 126) + { + if ((ch & 0x1 && ch != ';') || !ch || isalnum(ch) || ch == '$' || ch == '&' || ch == '(' || + ch == '.' || ch == '@' || ch == '^' || + ch == '\'' || ch == 130 || ch == '`') + flags |= GCT_SHORTCHAR; /* All these are valid for DOS */ + } + else + flags |= GCT_SHORTCHAR; /* Bug compatible with win32 */ + flags |= GCT_LFNCHAR; /* Valid for long file names */ + } + return flags; +} + +/************************************************************************* + * SHLWAPI_UseSystemForSystemFolders + * + * Internal helper for PathMakeSystemFolderW. + */ +static BOOL WINAPI SHLWAPI_UseSystemForSystemFolders() +{ + static BOOL bCheckedReg = FALSE; + static BOOL bUseSystemForSystemFolders = FALSE; + + if (!bCheckedReg) + { + bCheckedReg = TRUE; + + /* Key tells Win what file attributes to use on system folders */ + if (SHGetValueA(HKEY_LOCAL_MACHINE, + "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer", + "UseSystemForSystemFolders", 0, 0, 0)) + bUseSystemForSystemFolders = TRUE; + } + return bUseSystemForSystemFolders; +} + +/************************************************************************* + * PathMakeSystemFolderA [SHLWAPI.@] + * + * Set system folder attribute for a path. + * + * PARAMS + * lpszPath [I] The path to turn into a system folder + * + * RETURNS + * TRUE If the path was changed to/already was a system folder + * FALSE If the path is invalid or SetFileAttributesA() fails + */ +BOOL WINAPI PathMakeSystemFolderA(LPCSTR lpszPath) +{ + BOOL bRet = FALSE; + + TRACE("(%s)\n", debugstr_a(lpszPath)); + + if (lpszPath && *lpszPath) + { + WCHAR szPath[MAX_PATH]; + MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH); + bRet = PathMakeSystemFolderW(szPath); + } + return bRet; +} + +/************************************************************************* + * PathMakeSystemFolderW [SHLWAPI.@] + * + * See PathMakeSystemFolderA. + */ +BOOL WINAPI PathMakeSystemFolderW(LPCWSTR lpszPath) +{ + DWORD dwDefaultAttr = FILE_ATTRIBUTE_READONLY, dwAttr; + WCHAR buff[MAX_PATH]; + + TRACE("(%s)\n", debugstr_w(lpszPath)); + + if (!lpszPath || !*lpszPath) + return FALSE; + + /* If the directory is already a system directory, don't do anything */ + GetSystemDirectoryW(buff, MAX_PATH); + if (!strcmpW(buff, lpszPath)) + return TRUE; + + GetWindowsDirectoryW(buff, MAX_PATH); + if (!strcmpW(buff, lpszPath)) + return TRUE; + + /* "UseSystemForSystemFolders" Tells Win what attributes to use */ + if (SHLWAPI_UseSystemForSystemFolders()) + dwDefaultAttr = FILE_ATTRIBUTE_SYSTEM; + + if ((dwAttr = GetFileAttributesW(lpszPath)) == INVALID_FILE_ATTRIBUTES) + return FALSE; + + /* Change file attributes to system attributes */ + dwAttr &= ~(FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_READONLY); + return SetFileAttributesW(lpszPath, dwAttr | dwDefaultAttr); +} + +/************************************************************************* + * PathRenameExtensionA [SHLWAPI.@] + * + * Swap the file extension in a path with another extension. + * + * PARAMS + * lpszPath [I/O] Path to swap the extension in + * lpszExt [I] The new extension + * + * RETURNS + * TRUE if lpszPath was modified, + * FALSE if lpszPath or lpszExt is NULL, or the new path is too long + */ +BOOL WINAPI PathRenameExtensionA(LPSTR lpszPath, LPCSTR lpszExt) +{ + LPSTR lpszExtension; + + TRACE("(%s,%s)\n", debugstr_a(lpszPath), debugstr_a(lpszExt)); + + lpszExtension = PathFindExtensionA(lpszPath); + + if (!lpszExtension || (lpszExtension - lpszPath + strlen(lpszExt) >= MAX_PATH)) + return FALSE; + + strcpy(lpszExtension, lpszExt); + return TRUE; +} + +/************************************************************************* + * PathRenameExtensionW [SHLWAPI.@] + * + * See PathRenameExtensionA. + */ +BOOL WINAPI PathRenameExtensionW(LPWSTR lpszPath, LPCWSTR lpszExt) +{ + LPWSTR lpszExtension; + + TRACE("(%s,%s)\n", debugstr_w(lpszPath), debugstr_w(lpszExt)); + + lpszExtension = PathFindExtensionW(lpszPath); + + if (!lpszExtension || (lpszExtension - lpszPath + strlenW(lpszExt) >= MAX_PATH)) + return FALSE; + + strcpyW(lpszExtension, lpszExt); + return TRUE; +} + +/************************************************************************* + * PathSearchAndQualifyA [SHLWAPI.@] + * + * Determine if a given path is correct and fully qualified. + * + * PARAMS + * lpszPath [I] Path to check + * lpszBuf [O] Output for correct path + * cchBuf [I] Size of lpszBuf + * + * RETURNS + * Unknown. + */ +BOOL WINAPI PathSearchAndQualifyA(LPCSTR lpszPath, LPSTR lpszBuf, UINT cchBuf) +{ + TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszPath), lpszBuf, cchBuf); + + if(SearchPathA(NULL, lpszPath, NULL, cchBuf, lpszBuf, NULL)) + return TRUE; + return !!GetFullPathNameA(lpszPath, cchBuf, lpszBuf, NULL); +} + +/************************************************************************* + * PathSearchAndQualifyW [SHLWAPI.@] + * + * See PathSearchAndQualifyA. + */ +BOOL WINAPI PathSearchAndQualifyW(LPCWSTR lpszPath, LPWSTR lpszBuf, UINT cchBuf) +{ + TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszPath), lpszBuf, cchBuf); + + if(SearchPathW(NULL, lpszPath, NULL, cchBuf, lpszBuf, NULL)) + return TRUE; + return !!GetFullPathNameW(lpszPath, cchBuf, lpszBuf, NULL); +} + +/************************************************************************* + * PathSkipRootA [SHLWAPI.@] + * + * Return the portion of a path following the drive letter or mount point. + * + * PARAMS + * lpszPath [I] The path to skip on + * + * RETURNS + * Success: A pointer to the next character after the root. + * Failure: NULL, if lpszPath is invalid, has no root or is a multibyte string. + */ +LPSTR WINAPI PathSkipRootA(LPCSTR lpszPath) +{ + TRACE("(%s)\n", debugstr_a(lpszPath)); + + if (!lpszPath || !*lpszPath) + return NULL; + + if (*lpszPath == '\\' && lpszPath[1] == '\\') + { + /* Network share: skip share server and mount point */ + lpszPath += 2; + if ((lpszPath = StrChrA(lpszPath, '\\')) && + (lpszPath = StrChrA(lpszPath + 1, '\\'))) + lpszPath++; + return (LPSTR)lpszPath; + } + + if (IsDBCSLeadByte(*lpszPath)) + return NULL; + + /* Check x:\ */ + if (lpszPath[0] && lpszPath[1] == ':' && lpszPath[2] == '\\') + return (LPSTR)lpszPath + 3; + return NULL; +} + +/************************************************************************* + * PathSkipRootW [SHLWAPI.@] + * + * See PathSkipRootA. + */ +LPWSTR WINAPI PathSkipRootW(LPCWSTR lpszPath) +{ + TRACE("(%s)\n", debugstr_w(lpszPath)); + + if (!lpszPath || !*lpszPath) + return NULL; + + if (*lpszPath == '\\' && lpszPath[1] == '\\') + { + /* Network share: skip share server and mount point */ + lpszPath += 2; + if ((lpszPath = StrChrW(lpszPath, '\\')) && + (lpszPath = StrChrW(lpszPath + 1, '\\'))) + lpszPath++; + return (LPWSTR)lpszPath; + } + + /* Check x:\ */ + if (lpszPath[0] && lpszPath[1] == ':' && lpszPath[2] == '\\') + return (LPWSTR)lpszPath + 3; + return NULL; +} + +/************************************************************************* + * PathCreateFromUrlA [SHLWAPI.@] + * + * See PathCreateFromUrlW + */ +HRESULT WINAPI PathCreateFromUrlA(LPCSTR pszUrl, LPSTR pszPath, + LPDWORD pcchPath, DWORD dwReserved) +{ + WCHAR bufW[MAX_PATH]; + WCHAR *pathW = bufW; + UNICODE_STRING urlW; + HRESULT ret; + DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA; + + if(!RtlCreateUnicodeStringFromAsciiz(&urlW, pszUrl)) + return E_INVALIDARG; + if((ret = PathCreateFromUrlW(urlW.Buffer, pathW, &lenW, dwReserved)) == E_POINTER) { + pathW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR)); + ret = PathCreateFromUrlW(urlW.Buffer, pathW, &lenW, dwReserved); + } + if(ret == S_OK) { + RtlUnicodeToMultiByteSize(&lenA, pathW, lenW * sizeof(WCHAR)); + if(*pcchPath > lenA) { + RtlUnicodeToMultiByteN(pszPath, *pcchPath - 1, &lenA, pathW, lenW * sizeof(WCHAR)); + pszPath[lenA] = 0; + *pcchPath = lenA; + } else { + *pcchPath = lenA + 1; + ret = E_POINTER; + } + } + if(pathW != bufW) HeapFree(GetProcessHeap(), 0, pathW); + RtlFreeUnicodeString(&urlW); + return ret; +} + +/************************************************************************* + * PathCreateFromUrlW [SHLWAPI.@] + * + * Create a path from a URL + * + * PARAMS + * lpszUrl [I] URL to convert into a path + * lpszPath [O] Output buffer for the resulting Path + * pcchPath [I] Length of lpszPath + * dwFlags [I] Flags controlling the conversion + * + * RETURNS + * Success: S_OK. lpszPath contains the URL in path format, + * Failure: An HRESULT error code such as E_INVALIDARG. + */ +HRESULT WINAPI PathCreateFromUrlW(LPCWSTR pszUrl, LPWSTR pszPath, + LPDWORD pcchPath, DWORD dwReserved) +{ + static const WCHAR file_colon[] = { 'f','i','l','e',':',0 }; + HRESULT hr; + DWORD nslashes = 0; + WCHAR *ptr; + + TRACE("(%s,%p,%p,0x%08lx)\n", debugstr_w(pszUrl), pszPath, pcchPath, dwReserved); + + if (!pszUrl || !pszPath || !pcchPath || !*pcchPath) + return E_INVALIDARG; + + + if (strncmpW(pszUrl, file_colon, 5)) + return E_INVALIDARG; + pszUrl += 5; + + while(*pszUrl == '/' || *pszUrl == '\\') { + nslashes++; + pszUrl++; + } + + if(isalphaW(*pszUrl) && (pszUrl[1] == ':' || pszUrl[1] == '|') && (pszUrl[2] == '/' || pszUrl[2] == '\\')) + nslashes = 0; + + switch(nslashes) { + case 2: + pszUrl -= 2; + break; + case 0: + break; + default: + pszUrl -= 1; + break; + } + + hr = UrlUnescapeW((LPWSTR)pszUrl, pszPath, pcchPath, 0); + if(hr != S_OK) return hr; + + for(ptr = pszPath; *ptr; ptr++) + if(*ptr == '/') *ptr = '\\'; + + while(*pszPath == '\\') + pszPath++; + + if(isalphaW(*pszPath) && pszPath[1] == '|' && pszPath[2] == '\\') /* c|\ -> c:\ */ + pszPath[1] = ':'; + + if(nslashes == 2 && (ptr = strchrW(pszPath, '\\'))) { /* \\host\c:\ -> \\hostc:\ */ + ptr++; + if(isalphaW(*ptr) && (ptr[1] == ':' || ptr[1] == '|') && ptr[2] == '\\') { + memmove(ptr - 1, ptr, (strlenW(ptr) + 1) * sizeof(WCHAR)); + (*pcchPath)--; + } + } + + TRACE("Returning %s\n",debugstr_w(pszPath)); + + return hr; +} + +/************************************************************************* + * PathRelativePathToA [SHLWAPI.@] + * + * Create a relative path from one path to another. + * + * PARAMS + * lpszPath [O] Destination for relative path + * lpszFrom [I] Source path + * dwAttrFrom [I] File attribute of source path + * lpszTo [I] Destination path + * dwAttrTo [I] File attributes of destination path + * + * RETURNS + * TRUE If a relative path can be formed. lpszPath contains the new path + * FALSE If the paths are not relavtive or any parameters are invalid + * + * NOTES + * lpszTo should be at least MAX_PATH in length. + * + * Calling this function with relative paths for lpszFrom or lpszTo may + * give erroneous results. + * + * The Win32 version of this function contains a bug where the lpszTo string + * may be referenced 1 byte beyond the end of the string. As a result random + * garbage may be written to the output path, depending on what lies beyond + * the last byte of the string. This bug occurs because of the behaviour of + * PathCommonPrefix() (see notes for that function), and no workaround seems + * possible with Win32. + * + * This bug has been fixed here, so for example the relative path from "\\" + * to "\\" is correctly determined as "." in this implementation. + */ +BOOL WINAPI PathRelativePathToA(LPSTR lpszPath, LPCSTR lpszFrom, DWORD dwAttrFrom, + LPCSTR lpszTo, DWORD dwAttrTo) +{ + BOOL bRet = FALSE; + + TRACE("(%p,%s,0x%08lx,%s,0x%08lx)\n", lpszPath, debugstr_a(lpszFrom), + dwAttrFrom, debugstr_a(lpszTo), dwAttrTo); + + if(lpszPath && lpszFrom && lpszTo) + { + WCHAR szPath[MAX_PATH]; + WCHAR szFrom[MAX_PATH]; + WCHAR szTo[MAX_PATH]; + MultiByteToWideChar(CP_ACP,0,lpszFrom,-1,szFrom,MAX_PATH); + MultiByteToWideChar(CP_ACP,0,lpszTo,-1,szTo,MAX_PATH); + bRet = PathRelativePathToW(szPath,szFrom,dwAttrFrom,szTo,dwAttrTo); + WideCharToMultiByte(CP_ACP,0,szPath,-1,lpszPath,MAX_PATH,0,0); + } + return bRet; +} + +/************************************************************************* + * PathRelativePathToW [SHLWAPI.@] + * + * See PathRelativePathToA. + */ +BOOL WINAPI PathRelativePathToW(LPWSTR lpszPath, LPCWSTR lpszFrom, DWORD dwAttrFrom, + LPCWSTR lpszTo, DWORD dwAttrTo) +{ + static const WCHAR szPrevDirSlash[] = { '.', '.', '\\', '\0' }; + static const WCHAR szPrevDir[] = { '.', '.', '\0' }; + WCHAR szFrom[MAX_PATH]; + WCHAR szTo[MAX_PATH]; + DWORD dwLen; + + TRACE("(%p,%s,0x%08lx,%s,0x%08lx)\n", lpszPath, debugstr_w(lpszFrom), + dwAttrFrom, debugstr_w(lpszTo), dwAttrTo); + + if(!lpszPath || !lpszFrom || !lpszTo) + return FALSE; + + *lpszPath = '\0'; + lstrcpynW(szFrom, lpszFrom, MAX_PATH); + lstrcpynW(szTo, lpszTo, MAX_PATH); + + if(!(dwAttrFrom & FILE_ATTRIBUTE_DIRECTORY)) + PathRemoveFileSpecW(szFrom); + if(!(dwAttrFrom & FILE_ATTRIBUTE_DIRECTORY)) + PathRemoveFileSpecW(szTo); + + /* Paths can only be relative if they have a common root */ + if(!(dwLen = PathCommonPrefixW(szFrom, szTo, 0))) + return FALSE; + + /* Strip off lpszFrom components to the root, by adding "..\" */ + lpszFrom = szFrom + dwLen; + if (!*lpszFrom) + { + lpszPath[0] = '.'; + lpszPath[1] = '\0'; + } + if (*lpszFrom == '\\') + lpszFrom++; + + while (*lpszFrom) + { + lpszFrom = PathFindNextComponentW(lpszFrom); + strcatW(lpszPath, *lpszFrom ? szPrevDirSlash : szPrevDir); + } + + /* From the root add the components of lpszTo */ + lpszTo += dwLen; + /* We check lpszTo[-1] to avoid skipping end of string. See the notes for + * this function. + */ + if (*lpszTo && lpszTo[-1]) + { + if (*lpszTo != '\\') + lpszTo--; + dwLen = strlenW(lpszPath); + if (dwLen + strlenW(lpszTo) >= MAX_PATH) + { + *lpszPath = '\0'; + return FALSE; + } + strcpyW(lpszPath + dwLen, lpszTo); + } + return TRUE; +} + +/************************************************************************* + * PathUnmakeSystemFolderA [SHLWAPI.@] + * + * Remove the system folder attributes from a path. + * + * PARAMS + * lpszPath [I] The path to remove attributes from + * + * RETURNS + * Success: TRUE. + * Failure: FALSE, if lpszPath is NULL, empty, not a directory, or calling + * SetFileAttributesA() fails. + */ +BOOL WINAPI PathUnmakeSystemFolderA(LPCSTR lpszPath) +{ + DWORD dwAttr; + + TRACE("(%s)\n", debugstr_a(lpszPath)); + + if (!lpszPath || !*lpszPath || (dwAttr = GetFileAttributesA(lpszPath)) == INVALID_FILE_ATTRIBUTES || + !(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) + return FALSE; + + dwAttr &= ~(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM); + return SetFileAttributesA(lpszPath, dwAttr); +} + +/************************************************************************* + * PathUnmakeSystemFolderW [SHLWAPI.@] + * + * See PathUnmakeSystemFolderA. + */ +BOOL WINAPI PathUnmakeSystemFolderW(LPCWSTR lpszPath) +{ + DWORD dwAttr; + + TRACE("(%s)\n", debugstr_w(lpszPath)); + + if (!lpszPath || !*lpszPath || (dwAttr = GetFileAttributesW(lpszPath)) == INVALID_FILE_ATTRIBUTES || + !(dwAttr & FILE_ATTRIBUTE_DIRECTORY)) + return FALSE; + + dwAttr &= ~(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM); + return SetFileAttributesW(lpszPath, dwAttr); +} + + +/************************************************************************* + * PathSetDlgItemPathA [SHLWAPI.@] + * + * Set the text of a dialog item to a path, shrinking the path to fit + * if it is too big for the item. + * + * PARAMS + * hDlg [I] Dialog handle + * id [I] ID of item in the dialog + * lpszPath [I] Path to set as the items text + * + * RETURNS + * Nothing. + * + * NOTES + * If lpszPath is NULL, a blank string ("") is set (i.e. The previous + * window text is erased). + */ +VOID WINAPI PathSetDlgItemPathA(HWND hDlg, int id, LPCSTR lpszPath) +{ + WCHAR szPath[MAX_PATH]; + + TRACE("(%p,%8x,%s)\n",hDlg, id, debugstr_a(lpszPath)); + + if (lpszPath) + MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH); + else + szPath[0] = '\0'; + PathSetDlgItemPathW(hDlg, id, szPath); +} + +/************************************************************************* + * PathSetDlgItemPathW [SHLWAPI.@] + * + * See PathSetDlgItemPathA. + */ +VOID WINAPI PathSetDlgItemPathW(HWND hDlg, int id, LPCWSTR lpszPath) +{ + WCHAR path[MAX_PATH + 1]; + HWND hwItem; + RECT rect; + HDC hdc; + HGDIOBJ hPrevObj; + + TRACE("(%p,%8x,%s)\n",hDlg, id, debugstr_w(lpszPath)); + + if (!(hwItem = GetDlgItem(hDlg, id))) + return; + + if (lpszPath) + lstrcpynW(path, lpszPath, sizeof(path) / sizeof(WCHAR)); + else + path[0] = '\0'; + + GetClientRect(hwItem, &rect); + hdc = GetDC(hDlg); + hPrevObj = SelectObject(hdc, (HGDIOBJ)SendMessageW(hwItem,WM_GETFONT,0,0)); + + if (hPrevObj) + { + PathCompactPathW(hdc, path, rect.right); + SelectObject(hdc, hPrevObj); + } + + ReleaseDC(hDlg, hdc); + SetWindowTextW(hwItem, path); +} + +/************************************************************************* + * PathIsNetworkPathA [SHLWAPI.@] + * + * Determine if the given path is a network path. + * + * PARAMS + * lpszPath [I] Path to check + * + * RETURNS + * TRUE If lpszPath is a UNC share or mapped network drive, or + * FALSE If lpszPath is a local drive or cannot be determined + */ +BOOL WINAPI PathIsNetworkPathA(LPCSTR lpszPath) +{ + int dwDriveNum; + + TRACE("(%s)\n",debugstr_a(lpszPath)); + + if (!lpszPath) + return FALSE; + if (*lpszPath == '\\' && lpszPath[1] == '\\') + return TRUE; + dwDriveNum = PathGetDriveNumberA(lpszPath); + if (dwDriveNum == -1) + return FALSE; + GET_FUNC(pIsNetDrive, shell32, (LPCSTR)66, FALSE); /* ord 66 = shell32.IsNetDrive */ + return pIsNetDrive(dwDriveNum); +} + +/************************************************************************* + * PathIsNetworkPathW [SHLWAPI.@] + * + * See PathIsNetworkPathA. + */ +BOOL WINAPI PathIsNetworkPathW(LPCWSTR lpszPath) +{ + int dwDriveNum; + + TRACE("(%s)\n", debugstr_w(lpszPath)); + + if (!lpszPath) + return FALSE; + if (*lpszPath == '\\' && lpszPath[1] == '\\') + return TRUE; + dwDriveNum = PathGetDriveNumberW(lpszPath); + if (dwDriveNum == -1) + return FALSE; + GET_FUNC(pIsNetDrive, shell32, (LPCSTR)66, FALSE); /* ord 66 = shell32.IsNetDrive */ + return pIsNetDrive(dwDriveNum); +} + +/************************************************************************* + * PathIsLFNFileSpecA [SHLWAPI.@] + * + * Determine if the given path is a long file name + * + * PARAMS + * lpszPath [I] Path to check + * + * RETURNS + * TRUE If path is a long file name, + * FALSE If path is a valid DOS short file name + */ +BOOL WINAPI PathIsLFNFileSpecA(LPCSTR lpszPath) +{ + DWORD dwNameLen = 0, dwExtLen = 0; + + TRACE("(%s)\n",debugstr_a(lpszPath)); + + if (!lpszPath) + return FALSE; + + while (*lpszPath) + { + if (*lpszPath == ' ') + return TRUE; /* DOS names cannot have spaces */ + if (*lpszPath == '.') + { + if (dwExtLen) + return TRUE; /* DOS names have only one dot */ + dwExtLen = 1; + } + else if (dwExtLen) + { + dwExtLen++; + if (dwExtLen > 4) + return TRUE; /* DOS extensions are <= 3 chars*/ + } + else + { + dwNameLen++; + if (dwNameLen > 8) + return TRUE; /* DOS names are <= 8 chars */ + } + lpszPath += IsDBCSLeadByte(*lpszPath) ? 2 : 1; + } + return FALSE; /* Valid DOS path */ +} + +/************************************************************************* + * PathIsLFNFileSpecW [SHLWAPI.@] + * + * See PathIsLFNFileSpecA. + */ +BOOL WINAPI PathIsLFNFileSpecW(LPCWSTR lpszPath) +{ + DWORD dwNameLen = 0, dwExtLen = 0; + + TRACE("(%s)\n",debugstr_w(lpszPath)); + + if (!lpszPath) + return FALSE; + + while (*lpszPath) + { + if (*lpszPath == ' ') + return TRUE; /* DOS names cannot have spaces */ + if (*lpszPath == '.') + { + if (dwExtLen) + return TRUE; /* DOS names have only one dot */ + dwExtLen = 1; + } + else if (dwExtLen) + { + dwExtLen++; + if (dwExtLen > 4) + return TRUE; /* DOS extensions are <= 3 chars*/ + } + else + { + dwNameLen++; + if (dwNameLen > 8) + return TRUE; /* DOS names are <= 8 chars */ + } + lpszPath++; + } + return FALSE; /* Valid DOS path */ +} + +/************************************************************************* + * PathIsDirectoryEmptyA [SHLWAPI.@] + * + * Determine if a given directory is empty. + * + * PARAMS + * lpszPath [I] Directory to check + * + * RETURNS + * TRUE If the directory exists and contains no files, + * FALSE Otherwise + */ +BOOL WINAPI PathIsDirectoryEmptyA(LPCSTR lpszPath) +{ + BOOL bRet = FALSE; + + TRACE("(%s)\n",debugstr_a(lpszPath)); + + if (lpszPath) + { + WCHAR szPath[MAX_PATH]; + MultiByteToWideChar(CP_ACP,0,lpszPath,-1,szPath,MAX_PATH); + bRet = PathIsDirectoryEmptyW(szPath); + } + return bRet; +} + +/************************************************************************* + * PathIsDirectoryEmptyW [SHLWAPI.@] + * + * See PathIsDirectoryEmptyA. + */ +BOOL WINAPI PathIsDirectoryEmptyW(LPCWSTR lpszPath) +{ + static const WCHAR szAllFiles[] = { '*', '.', '*', '\0' }; + WCHAR szSearch[MAX_PATH]; + DWORD dwLen; + HANDLE hfind; + BOOL retVal = FALSE; + WIN32_FIND_DATAW find_data; + + TRACE("(%s)\n",debugstr_w(lpszPath)); + + if (!lpszPath || !PathIsDirectoryW(lpszPath)) + return FALSE; + + lstrcpynW(szSearch, lpszPath, MAX_PATH); + PathAddBackslashW(szSearch); + dwLen = strlenW(szSearch); + if (dwLen > MAX_PATH - 4) + return FALSE; + + strcpyW(szSearch + dwLen, szAllFiles); + hfind = FindFirstFileW(szSearch, &find_data); + + if (hfind != INVALID_HANDLE_VALUE && + find_data.cFileName[0] == '.' && + find_data.cFileName[1] == '.') + { + /* The only directory entry should be the parent */ + if (!FindNextFileW(hfind, &find_data)) + retVal = TRUE; + FindClose(hfind); + } + return retVal; +} + + +/************************************************************************* + * PathFindSuffixArrayA [SHLWAPI.@] + * + * Find a suffix string in an array of suffix strings + * + * PARAMS + * lpszSuffix [I] Suffix string to search for + * lppszArray [I] Array of suffix strings to search + * dwCount [I] Number of elements in lppszArray + * + * RETURNS + * Success: The index of the position of lpszSuffix in lppszArray + * Failure: 0, if any parameters are invalid or lpszSuffix is not found + * + * NOTES + * The search is case sensitive. + * The match is made against the end of the suffix string, so for example: + * lpszSuffix="fooBAR" matches "BAR", but lpszSuffix="fooBARfoo" does not. + */ +LPCSTR WINAPI PathFindSuffixArrayA(LPCSTR lpszSuffix, LPCSTR *lppszArray, int dwCount) +{ + size_t dwLen; + int dwRet = 0; + + TRACE("(%s,%p,%d)\n",debugstr_a(lpszSuffix), lppszArray, dwCount); + + if (lpszSuffix && lppszArray && dwCount > 0) + { + dwLen = strlen(lpszSuffix); + + while (dwRet < dwCount) + { + size_t dwCompareLen = strlen(*lppszArray); + if (dwCompareLen < dwLen) + { + if (!strcmp(lpszSuffix + dwLen - dwCompareLen, *lppszArray)) + return *lppszArray; /* Found */ + } + dwRet++; + lppszArray++; + } + } + return NULL; +} + +/************************************************************************* + * PathFindSuffixArrayW [SHLWAPI.@] + * + * See PathFindSuffixArrayA. + */ +LPCWSTR WINAPI PathFindSuffixArrayW(LPCWSTR lpszSuffix, LPCWSTR *lppszArray, int dwCount) +{ + size_t dwLen; + int dwRet = 0; + + TRACE("(%s,%p,%d)\n",debugstr_w(lpszSuffix), lppszArray, dwCount); + + if (lpszSuffix && lppszArray && dwCount > 0) + { + dwLen = strlenW(lpszSuffix); + + while (dwRet < dwCount) + { + size_t dwCompareLen = strlenW(*lppszArray); + if (dwCompareLen < dwLen) + { + if (!strcmpW(lpszSuffix + dwLen - dwCompareLen, *lppszArray)) + return *lppszArray; /* Found */ + } + dwRet++; + lppszArray++; + } + } + return NULL; +} + +/************************************************************************* + * PathUndecorateA [SHLWAPI.@] + * + * Undecorate a file path + * + * PARAMS + * lpszPath [I/O] Path to remove any decoration from + * + * RETURNS + * Nothing + * + * NOTES + * A decorations form is "path[n].ext" where "n" is an optional decimal number. + */ +VOID WINAPI PathUndecorateA(LPSTR lpszPath) +{ + TRACE("(%s)\n",debugstr_a(lpszPath)); + + if (lpszPath) + { + LPSTR lpszExt = PathFindExtensionA(lpszPath); + if (lpszExt > lpszPath && lpszExt[-1] == ']') + { + LPSTR lpszSkip = lpszExt - 2; + if (*lpszSkip == '[') + lpszSkip++; /* [] (no number) */ + else + while (lpszSkip > lpszPath && isdigit(lpszSkip[-1])) + lpszSkip--; + if (lpszSkip > lpszPath && lpszSkip[-1] == '[' && lpszSkip[-2] != '\\') + { + /* remove the [n] */ + lpszSkip--; + while (*lpszExt) + *lpszSkip++ = *lpszExt++; + *lpszSkip = '\0'; + } + } + } +} + +/************************************************************************* + * PathUndecorateW [SHLWAPI.@] + * + * See PathUndecorateA. + */ +VOID WINAPI PathUndecorateW(LPWSTR lpszPath) +{ + TRACE("(%s)\n",debugstr_w(lpszPath)); + + if (lpszPath) + { + LPWSTR lpszExt = PathFindExtensionW(lpszPath); + if (lpszExt > lpszPath && lpszExt[-1] == ']') + { + LPWSTR lpszSkip = lpszExt - 2; + if (*lpszSkip == '[') + lpszSkip++; /* [] (no number) */ + else + while (lpszSkip > lpszPath && isdigitW(lpszSkip[-1])) + lpszSkip--; + if (lpszSkip > lpszPath && lpszSkip[-1] == '[' && lpszSkip[-2] != '\\') + { + /* remove the [n] */ + lpszSkip--; + while (*lpszExt) + *lpszSkip++ = *lpszExt++; + *lpszSkip = '\0'; + } + } + } +} + +/************************************************************************* + * PathUnExpandEnvStringsA [SHLWAPI.@] + * + * Substitute folder names in a path with their corresponding environment + * strings. + * + * PARAMS + * pszPath [I] Buffer containing the path to unexpand. + * pszBuf [O] Buffer to receive the unexpanded path. + * cchBuf [I] Size of pszBuf in characters. + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI PathUnExpandEnvStringsA(LPCSTR pszPath, LPSTR pszBuf, UINT cchBuf) +{ + FIXME("(%s,%s,0x%08x)\n", debugstr_a(pszPath), debugstr_a(pszBuf), cchBuf); + return FALSE; +} + +/************************************************************************* + * PathUnExpandEnvStringsW [SHLWAPI.@] + * + * Unicode version of PathUnExpandEnvStringsA. + */ +BOOL WINAPI PathUnExpandEnvStringsW(LPCWSTR pszPath, LPWSTR pszBuf, UINT cchBuf) +{ + FIXME("(%s,%s,0x%08x)\n", debugstr_w(pszPath), debugstr_w(pszBuf), cchBuf); + return FALSE; +} + +/************************************************************************* + * @ [SHLWAPI.440] + * + * Find localised or default web content in "%WINDOWS%\web\". + * + * PARAMS + * lpszFile [I] File name containing content to look for + * lpszPath [O] Buffer to contain the full path to the file + * dwPathLen [I] Length of lpszPath + * + * RETURNS + * Success: S_OK. lpszPath contains the full path to the content. + * Failure: E_FAIL. The content does not exist or lpszPath is too short. + */ +HRESULT WINAPI SHGetWebFolderFilePathA(LPCSTR lpszFile, LPSTR lpszPath, DWORD dwPathLen) +{ + WCHAR szFile[MAX_PATH], szPath[MAX_PATH]; + HRESULT hRet; + + TRACE("(%s,%p,%ld)\n", lpszFile, lpszPath, dwPathLen); + + MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, szFile, MAX_PATH); + szPath[0] = '\0'; + hRet = SHGetWebFolderFilePathW(szFile, szPath, dwPathLen); + WideCharToMultiByte(CP_ACP, 0, szPath, -1, lpszPath, dwPathLen, 0, 0); + return hRet; +} + +/************************************************************************* + * @ [SHLWAPI.441] + * + * Unicode version of SHGetWebFolderFilePathA. + */ +HRESULT WINAPI SHGetWebFolderFilePathW(LPCWSTR lpszFile, LPWSTR lpszPath, DWORD dwPathLen) +{ + static const WCHAR szWeb[] = {'\\','W','e','b','\\','\0'}; + static const WCHAR szWebMui[] = {'m','u','i','\\','%','0','4','x','\\','\0'}; +#define szWebLen (sizeof(szWeb)/sizeof(WCHAR)) +#define szWebMuiLen ((sizeof(szWebMui)+1)/sizeof(WCHAR)) + DWORD dwLen, dwFileLen; + LANGID lidSystem, lidUser; + + TRACE("(%s,%p,%ld)\n", debugstr_w(lpszFile), lpszPath, dwPathLen); + + /* Get base directory for web content */ + dwLen = GetSystemWindowsDirectoryW(lpszPath, dwPathLen); + if (dwLen > 0 && lpszPath[dwLen-1] == '\\') + dwLen--; + + dwFileLen = strlenW(lpszFile); + + if (dwLen + dwFileLen + szWebLen >= dwPathLen) + return E_FAIL; /* lpszPath too short */ + + strcpyW(lpszPath+dwLen, szWeb); + dwLen += szWebLen; + dwPathLen = dwPathLen - dwLen; /* Remaining space */ + + lidSystem = GetSystemDefaultUILanguage(); + lidUser = GetUserDefaultUILanguage(); + + if (lidSystem != lidUser) + { + if (dwFileLen + szWebMuiLen < dwPathLen) + { + /* Use localised content in the users UI language if present */ + wsprintfW(lpszPath + dwLen, szWebMui, lidUser); + strcpyW(lpszPath + dwLen + szWebMuiLen, lpszFile); + if (PathFileExistsW(lpszPath)) + return S_OK; + } + } + + /* Fall back to OS default installed content */ + strcpyW(lpszPath + dwLen, lpszFile); + if (PathFileExistsW(lpszPath)) + return S_OK; + return E_FAIL; +} + +#define PATH_CHAR_CLASS_LETTER 0x00000001 +#define PATH_CHAR_CLASS_ASTERIX 0x00000002 +#define PATH_CHAR_CLASS_DOT 0x00000004 +#define PATH_CHAR_CLASS_BACKSLASH 0x00000008 +#define PATH_CHAR_CLASS_COLON 0x00000010 +#define PATH_CHAR_CLASS_SEMICOLON 0x00000020 +#define PATH_CHAR_CLASS_COMMA 0x00000040 +#define PATH_CHAR_CLASS_SPACE 0x00000080 +#define PATH_CHAR_CLASS_OTHER_VALID 0x00000100 +#define PATH_CHAR_CLASS_DOUBLEQUOTE 0x00000200 + +#define PATH_CHAR_CLASS_INVALID 0x00000000 +#define PATH_CHAR_CLASS_ANY 0xffffffff + +static const DWORD SHELL_charclass[] = +{ + /* 0x00 */ PATH_CHAR_CLASS_INVALID, /* 0x01 */ PATH_CHAR_CLASS_INVALID, + /* 0x02 */ PATH_CHAR_CLASS_INVALID, /* 0x03 */ PATH_CHAR_CLASS_INVALID, + /* 0x04 */ PATH_CHAR_CLASS_INVALID, /* 0x05 */ PATH_CHAR_CLASS_INVALID, + /* 0x06 */ PATH_CHAR_CLASS_INVALID, /* 0x07 */ PATH_CHAR_CLASS_INVALID, + /* 0x08 */ PATH_CHAR_CLASS_INVALID, /* 0x09 */ PATH_CHAR_CLASS_INVALID, + /* 0x0a */ PATH_CHAR_CLASS_INVALID, /* 0x0b */ PATH_CHAR_CLASS_INVALID, + /* 0x0c */ PATH_CHAR_CLASS_INVALID, /* 0x0d */ PATH_CHAR_CLASS_INVALID, + /* 0x0e */ PATH_CHAR_CLASS_INVALID, /* 0x0f */ PATH_CHAR_CLASS_INVALID, + /* 0x10 */ PATH_CHAR_CLASS_INVALID, /* 0x11 */ PATH_CHAR_CLASS_INVALID, + /* 0x12 */ PATH_CHAR_CLASS_INVALID, /* 0x13 */ PATH_CHAR_CLASS_INVALID, + /* 0x14 */ PATH_CHAR_CLASS_INVALID, /* 0x15 */ PATH_CHAR_CLASS_INVALID, + /* 0x16 */ PATH_CHAR_CLASS_INVALID, /* 0x17 */ PATH_CHAR_CLASS_INVALID, + /* 0x18 */ PATH_CHAR_CLASS_INVALID, /* 0x19 */ PATH_CHAR_CLASS_INVALID, + /* 0x1a */ PATH_CHAR_CLASS_INVALID, /* 0x1b */ PATH_CHAR_CLASS_INVALID, + /* 0x1c */ PATH_CHAR_CLASS_INVALID, /* 0x1d */ PATH_CHAR_CLASS_INVALID, + /* 0x1e */ PATH_CHAR_CLASS_INVALID, /* 0x1f */ PATH_CHAR_CLASS_INVALID, + /* ' ' */ PATH_CHAR_CLASS_SPACE, /* '!' */ PATH_CHAR_CLASS_OTHER_VALID, + /* '"' */ PATH_CHAR_CLASS_DOUBLEQUOTE, /* '#' */ PATH_CHAR_CLASS_OTHER_VALID, + /* '$' */ PATH_CHAR_CLASS_OTHER_VALID, /* '%' */ PATH_CHAR_CLASS_OTHER_VALID, + /* '&' */ PATH_CHAR_CLASS_OTHER_VALID, /* '\'' */ PATH_CHAR_CLASS_OTHER_VALID, + /* '(' */ PATH_CHAR_CLASS_OTHER_VALID, /* ')' */ PATH_CHAR_CLASS_OTHER_VALID, + /* '*' */ PATH_CHAR_CLASS_ASTERIX, /* '+' */ PATH_CHAR_CLASS_OTHER_VALID, + /* ',' */ PATH_CHAR_CLASS_COMMA, /* '-' */ PATH_CHAR_CLASS_OTHER_VALID, + /* '.' */ PATH_CHAR_CLASS_DOT, /* '/' */ PATH_CHAR_CLASS_INVALID, + /* '0' */ PATH_CHAR_CLASS_OTHER_VALID, /* '1' */ PATH_CHAR_CLASS_OTHER_VALID, + /* '2' */ PATH_CHAR_CLASS_OTHER_VALID, /* '3' */ PATH_CHAR_CLASS_OTHER_VALID, + /* '4' */ PATH_CHAR_CLASS_OTHER_VALID, /* '5' */ PATH_CHAR_CLASS_OTHER_VALID, + /* '6' */ PATH_CHAR_CLASS_OTHER_VALID, /* '7' */ PATH_CHAR_CLASS_OTHER_VALID, + /* '8' */ PATH_CHAR_CLASS_OTHER_VALID, /* '9' */ PATH_CHAR_CLASS_OTHER_VALID, + /* ':' */ PATH_CHAR_CLASS_COLON, /* ';' */ PATH_CHAR_CLASS_SEMICOLON, + /* '<' */ PATH_CHAR_CLASS_INVALID, /* '=' */ PATH_CHAR_CLASS_OTHER_VALID, + /* '>' */ PATH_CHAR_CLASS_INVALID, /* '?' */ PATH_CHAR_CLASS_LETTER, + /* '@' */ PATH_CHAR_CLASS_OTHER_VALID, /* 'A' */ PATH_CHAR_CLASS_ANY, + /* 'B' */ PATH_CHAR_CLASS_ANY, /* 'C' */ PATH_CHAR_CLASS_ANY, + /* 'D' */ PATH_CHAR_CLASS_ANY, /* 'E' */ PATH_CHAR_CLASS_ANY, + /* 'F' */ PATH_CHAR_CLASS_ANY, /* 'G' */ PATH_CHAR_CLASS_ANY, + /* 'H' */ PATH_CHAR_CLASS_ANY, /* 'I' */ PATH_CHAR_CLASS_ANY, + /* 'J' */ PATH_CHAR_CLASS_ANY, /* 'K' */ PATH_CHAR_CLASS_ANY, + /* 'L' */ PATH_CHAR_CLASS_ANY, /* 'M' */ PATH_CHAR_CLASS_ANY, + /* 'N' */ PATH_CHAR_CLASS_ANY, /* 'O' */ PATH_CHAR_CLASS_ANY, + /* 'P' */ PATH_CHAR_CLASS_ANY, /* 'Q' */ PATH_CHAR_CLASS_ANY, + /* 'R' */ PATH_CHAR_CLASS_ANY, /* 'S' */ PATH_CHAR_CLASS_ANY, + /* 'T' */ PATH_CHAR_CLASS_ANY, /* 'U' */ PATH_CHAR_CLASS_ANY, + /* 'V' */ PATH_CHAR_CLASS_ANY, /* 'W' */ PATH_CHAR_CLASS_ANY, + /* 'X' */ PATH_CHAR_CLASS_ANY, /* 'Y' */ PATH_CHAR_CLASS_ANY, + /* 'Z' */ PATH_CHAR_CLASS_ANY, /* '[' */ PATH_CHAR_CLASS_OTHER_VALID, + /* '\\' */ PATH_CHAR_CLASS_BACKSLASH, /* ']' */ PATH_CHAR_CLASS_OTHER_VALID, + /* '^' */ PATH_CHAR_CLASS_OTHER_VALID, /* '_' */ PATH_CHAR_CLASS_OTHER_VALID, + /* '`' */ PATH_CHAR_CLASS_OTHER_VALID, /* 'a' */ PATH_CHAR_CLASS_ANY, + /* 'b' */ PATH_CHAR_CLASS_ANY, /* 'c' */ PATH_CHAR_CLASS_ANY, + /* 'd' */ PATH_CHAR_CLASS_ANY, /* 'e' */ PATH_CHAR_CLASS_ANY, + /* 'f' */ PATH_CHAR_CLASS_ANY, /* 'g' */ PATH_CHAR_CLASS_ANY, + /* 'h' */ PATH_CHAR_CLASS_ANY, /* 'i' */ PATH_CHAR_CLASS_ANY, + /* 'j' */ PATH_CHAR_CLASS_ANY, /* 'k' */ PATH_CHAR_CLASS_ANY, + /* 'l' */ PATH_CHAR_CLASS_ANY, /* 'm' */ PATH_CHAR_CLASS_ANY, + /* 'n' */ PATH_CHAR_CLASS_ANY, /* 'o' */ PATH_CHAR_CLASS_ANY, + /* 'p' */ PATH_CHAR_CLASS_ANY, /* 'q' */ PATH_CHAR_CLASS_ANY, + /* 'r' */ PATH_CHAR_CLASS_ANY, /* 's' */ PATH_CHAR_CLASS_ANY, + /* 't' */ PATH_CHAR_CLASS_ANY, /* 'u' */ PATH_CHAR_CLASS_ANY, + /* 'v' */ PATH_CHAR_CLASS_ANY, /* 'w' */ PATH_CHAR_CLASS_ANY, + /* 'x' */ PATH_CHAR_CLASS_ANY, /* 'y' */ PATH_CHAR_CLASS_ANY, + /* 'z' */ PATH_CHAR_CLASS_ANY, /* '{' */ PATH_CHAR_CLASS_OTHER_VALID, + /* '|' */ PATH_CHAR_CLASS_INVALID, /* '}' */ PATH_CHAR_CLASS_OTHER_VALID, + /* '~' */ PATH_CHAR_CLASS_OTHER_VALID +}; + +/************************************************************************* + * @ [SHLWAPI.455] + * + * Check if an ASCII char is of a certain class + */ +BOOL WINAPI PathIsValidCharA( char c, DWORD class ) +{ + if ((unsigned)c > 0x7e) + return class & PATH_CHAR_CLASS_OTHER_VALID; + + return class & SHELL_charclass[(unsigned)c]; +} + +/************************************************************************* + * @ [SHLWAPI.456] + * + * Check if a Unicode char is of a certain class + */ +BOOL WINAPI PathIsValidCharW( WCHAR c, DWORD class ) +{ + if (c > 0x7e) + return class & PATH_CHAR_CLASS_OTHER_VALID; + + return class & SHELL_charclass[c]; +} diff --git a/reactos/lib/shlwapi/reg.c b/reactos/lib/shlwapi/reg.c index 6df3689ef19..d0cb52d467c 100644 --- a/reactos/lib/shlwapi/reg.c +++ b/reactos/lib/shlwapi/reg.c @@ -1,2438 +1,2438 @@ -/* - * SHLWAPI registry functions - * - * Copyright 1998 Juergen Schmied - * Copyright 2001 Guy Albertelli - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> -#include <string.h> -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "winreg.h" -#include "wine/debug.h" -#define NO_SHLWAPI_STREAM -#include "shlwapi.h" -#include "wine/unicode.h" - -WINE_DEFAULT_DEBUG_CHANNEL(shell); - -/* Key/Value names for MIME content types */ -static const char *lpszContentTypeA = "Content Type"; -static const WCHAR lpszContentTypeW[] = { 'C','o','n','t','e','n','t',' ','T','y','p','e','\0'}; - -static const char *szMimeDbContentA = "MIME\\Database\\Content Type\\"; -static const WCHAR szMimeDbContentW[] = { 'M', 'I', 'M','E','\\', - 'D','a','t','a','b','a','s','e','\\','C','o','n','t','e','n','t', - ' ','T','y','p','e','\\', 0 }; -static const DWORD dwLenMimeDbContent = 27; /* strlen of szMimeDbContentA/W */ - -static const char *szExtensionA = "Extension"; -static const WCHAR szExtensionW[] = { 'E', 'x', 't','e','n','s','i','o','n','\0' }; - -/* internal structure of what the HUSKEY points to */ -typedef struct { - HKEY HKCUstart; /* Start key in CU hive */ - HKEY HKCUkey; /* Opened key in CU hive */ - HKEY HKLMstart; /* Start key in LM hive */ - HKEY HKLMkey; /* Opened key in LM hive */ - WCHAR lpszPath[MAX_PATH]; -} SHUSKEY, *LPSHUSKEY; - -DWORD WINAPI SHStringFromGUIDW(REFGUID,LPWSTR,INT); -HRESULT WINAPI SHRegGetCLSIDKeyW(REFGUID,LPCWSTR,BOOL,BOOL,PHKEY); - - -#define REG_HKCU TRUE -#define REG_HKLM FALSE -/************************************************************************* - * REG_GetHKEYFromHUSKEY - * - * Function: Return the proper registry key from the HUSKEY structure - * also allow special predefined values. - */ -static HKEY WINAPI REG_GetHKEYFromHUSKEY(HUSKEY hUSKey, BOOL which) -{ - HKEY test = (HKEY) hUSKey; - LPSHUSKEY mihk = (LPSHUSKEY) hUSKey; - - if ((test == HKEY_CLASSES_ROOT) || - (test == HKEY_CURRENT_CONFIG) || - (test == HKEY_CURRENT_USER) || - (test == HKEY_DYN_DATA) || - (test == HKEY_LOCAL_MACHINE) || - (test == HKEY_PERFORMANCE_DATA) || -/* FIXME: need to define for Win2k, ME, XP - * (test == HKEY_PERFORMANCE_TEXT) || - * (test == HKEY_PERFORMANCE_NLSTEXT) || - */ - (test == HKEY_USERS)) return test; - if (which == REG_HKCU) return mihk->HKCUkey; - return mihk->HKLMkey; -} - - -/************************************************************************* - * SHRegOpenUSKeyA [SHLWAPI.@] - * - * Open a user-specific registry key. - * - * PARAMS - * Path [I] Key name to open - * AccessType [I] Access type - * hRelativeUSKey [I] Relative user key - * phNewUSKey [O] Destination for created key - * fIgnoreHKCU [I] TRUE=Don't check HKEY_CURRENT_USER - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: An error code from RegOpenKeyExA(). - */ -LONG WINAPI SHRegOpenUSKeyA(LPCSTR Path, REGSAM AccessType, HUSKEY hRelativeUSKey, - PHUSKEY phNewUSKey, BOOL fIgnoreHKCU) -{ - WCHAR szPath[MAX_PATH]; - - if (Path) - MultiByteToWideChar(CP_ACP, 0, Path, -1, szPath, MAX_PATH); - - return SHRegOpenUSKeyW(Path ? szPath : NULL, AccessType, hRelativeUSKey, - phNewUSKey, fIgnoreHKCU); -} - -/************************************************************************* - * SHRegOpenUSKeyW [SHLWAPI.@] - * - * See SHRegOpenUSKeyA. - */ -LONG WINAPI SHRegOpenUSKeyW(LPCWSTR Path, REGSAM AccessType, HUSKEY hRelativeUSKey, - PHUSKEY phNewUSKey, BOOL fIgnoreHKCU) -{ - LONG ret2, ret1 = ~ERROR_SUCCESS; - LPSHUSKEY hKey; - - TRACE("(%s,0x%lx,%p,%p,%d)\n", debugstr_w(Path),(LONG)AccessType, - hRelativeUSKey, phNewUSKey, fIgnoreHKCU); - - if (phNewUSKey) - *phNewUSKey = NULL; - - /* Create internal HUSKEY */ - hKey = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*hKey)); - lstrcpynW(hKey->lpszPath, Path, sizeof(hKey->lpszPath)); - - if (hRelativeUSKey) - { - hKey->HKCUstart = SHRegDuplicateHKey(REG_GetHKEYFromHUSKEY(hRelativeUSKey, REG_HKCU)); - hKey->HKLMstart = SHRegDuplicateHKey(REG_GetHKEYFromHUSKEY(hRelativeUSKey, REG_HKLM)); - - /* FIXME: if either of these keys is NULL, create the start key from - * the relative keys start+path - */ - } - else - { - hKey->HKCUstart = HKEY_CURRENT_USER; - hKey->HKLMstart = HKEY_LOCAL_MACHINE; - } - - if (!fIgnoreHKCU) - { - ret1 = RegOpenKeyExW(hKey->HKCUstart, hKey->lpszPath, 0, AccessType, &hKey->HKCUkey); - if (ret1) - hKey->HKCUkey = 0; - } - - ret2 = RegOpenKeyExW(hKey->HKLMstart, hKey->lpszPath, 0, AccessType, &hKey->HKLMkey); - if (ret2) - hKey->HKLMkey = 0; - - if (ret1 || ret2) - TRACE("one or more opens failed: HKCU=%ld HKLM=%ld\n", ret1, ret2); - - if (ret1 && ret2) - { - /* Neither open succeeded: fail */ - SHRegCloseUSKey(hKey); - return ret2; - } - - TRACE("HUSKEY=%p\n", hKey); - if (phNewUSKey) - *phNewUSKey = (HUSKEY)hKey; - return ERROR_SUCCESS; -} - -/************************************************************************* - * SHRegCloseUSKey [SHLWAPI.@] - * - * Close a user-specific registry key - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: An error code from RegCloseKey(). - */ -LONG WINAPI SHRegCloseUSKey( - HUSKEY hUSKey) /* [I] Key to close */ -{ - LPSHUSKEY hKey = (LPSHUSKEY)hUSKey; - LONG ret = ERROR_SUCCESS; - - if (hKey->HKCUkey) - ret = RegCloseKey(hKey->HKCUkey); - if (hKey->HKCUstart && hKey->HKCUstart != HKEY_CURRENT_USER) - ret = RegCloseKey(hKey->HKCUstart); - if (hKey->HKLMkey) - ret = RegCloseKey(hKey->HKLMkey); - if (hKey->HKLMstart && hKey->HKLMstart != HKEY_LOCAL_MACHINE) - ret = RegCloseKey(hKey->HKCUstart); - - HeapFree(GetProcessHeap(), 0, hKey); - return ret; -} - -/************************************************************************* - * SHRegCreateUSKeyA [SHLWAPI.@] - * - * Create or open a user-specific registry key. - * - * PARAMS - * pszPath [I] Key name to create or open. - * samDesired [I] Wanted security access. - * hRelativeUSKey [I] Base path if pszPath is relative. NULL otherwise. - * phNewUSKey [O] Receives a handle to the new or openened key. - * dwFlags [I] Base key under which the key should be opened. - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: Nonzero error code from winerror.h - */ -LONG WINAPI SHRegCreateUSKeyA(LPCSTR pszPath, REGSAM samDesired, HUSKEY hRelativeUSKey, - PHUSKEY phNewUSKey, DWORD dwFlags) -{ - FIXME("(%s, 0x%08lx, %p, %p, 0x%08lx) stub\n", debugstr_a(pszPath), samDesired, - hRelativeUSKey, phNewUSKey, dwFlags); - return ERROR_SUCCESS; -} - -/************************************************************************* - * SHRegCreateUSKeyW [SHLWAPI.@] - * - * See SHRegCreateUSKeyA. - */ -LONG WINAPI SHRegCreateUSKeyW(LPCWSTR pszPath, REGSAM samDesired, HUSKEY hRelativeUSKey, - PHUSKEY phNewUSKey, DWORD dwFlags) -{ - FIXME("(%s, 0x%08lx, %p, %p, 0x%08lx) stub\n", debugstr_w(pszPath), samDesired, - hRelativeUSKey, phNewUSKey, dwFlags); - return ERROR_SUCCESS; -} - -/************************************************************************* - * SHRegDeleteEmptyUSKeyA [SHLWAPI.@] - * - * Delete an empty user-specific registry key. - * - * PARAMS - * hUSKey [I] Handle to an open registry key. - * pszValue [I] Empty key name. - * delRegFlags [I] Flag that specifies the base from which to delete - * the key. - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: Nonzero error code from winerror.h - */ -LONG WINAPI SHRegDeleteEmptyUSKeyA(HUSKEY hUSKey, LPCSTR pszValue, SHREGDEL_FLAGS delRegFlags) -{ - FIXME("(%p, %s, 0x%08x) stub\n", hUSKey, debugstr_a(pszValue), delRegFlags); - return ERROR_SUCCESS; -} - -/************************************************************************* - * SHRegDeleteEmptyUSKeyW [SHLWAPI.@] - * - * See SHRegDeleteEmptyUSKeyA. - */ -LONG WINAPI SHRegDeleteEmptyUSKeyW(HUSKEY hUSKey, LPCWSTR pszValue, SHREGDEL_FLAGS delRegFlags) -{ - FIXME("(%p, %s, 0x%08x) stub\n", hUSKey, debugstr_w(pszValue), delRegFlags); - return ERROR_SUCCESS; -} - -/************************************************************************* - * SHRegDeleteUSValueA [SHLWAPI.@] - * - * Delete a user-specific registry value. - * - * PARAMS - * hUSKey [I] Handle to an open registry key. - * pszValue [I] Specifies the value to delete. - * delRegFlags [I] Flag that specifies the base of the key from which to - * delete the value. - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: Nonzero error code from winerror.h - */ -LONG WINAPI SHRegDeleteUSValueA(HUSKEY hUSKey, LPCSTR pszValue, SHREGDEL_FLAGS delRegFlags) -{ - FIXME("(%p, %s, 0x%08x) stub\n", hUSKey, debugstr_a(pszValue), delRegFlags); - return ERROR_SUCCESS; -} - -/************************************************************************* - * SHRegDeleteUSValueW [SHLWAPI.@] - * - * See SHRegDeleteUSValueA. - */ -LONG WINAPI SHRegDeleteUSValueW(HUSKEY hUSKey, LPCWSTR pszValue, SHREGDEL_FLAGS delRegFlags) -{ - FIXME("(%p, %s, 0x%08x) stub\n", hUSKey, debugstr_w(pszValue), delRegFlags); - return ERROR_SUCCESS; -} - -/************************************************************************* - * SHRegEnumUSValueA [SHLWAPI.@] - * - * Enumerate values of a specified registry key. - * - * PARAMS - * hUSKey [I] Handle to an open registry key. - * dwIndex [I] Index of the value to be retrieved. - * pszValueName [O] Buffer to receive the value name. - * pcchValueNameLen [I] Size of pszValueName in characters. - * pdwType [O] Receives data type of the value. - * pvData [O] Receives value data. May be NULL. - * pcbData [I/O] Size of pvData in bytes. - * enumRegFlags [I] Flag that specifies the base key under which to - * enumerate values. - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: Nonzero error code from winerror.h - */ -LONG WINAPI SHRegEnumUSValueA(HUSKEY hUSKey, DWORD dwIndex, LPSTR pszValueName, - LPDWORD pcchValueNameLen, LPDWORD pdwType, LPVOID pvData, - LPDWORD pcbData, SHREGENUM_FLAGS enumRegFlags) -{ - FIXME("(%p, 0x%08lx, %s, %p, %p, %p, %p, 0x%08x) stub\n", hUSKey, dwIndex, - debugstr_a(pszValueName), pcchValueNameLen, pdwType, pvData, pcbData, enumRegFlags); - return ERROR_INVALID_FUNCTION; -} - -/************************************************************************* - * SHRegEnumUSValueW [SHLWAPI.@] - * - * See SHRegEnumUSValueA. - */ -LONG WINAPI SHRegEnumUSValueW(HUSKEY hUSKey, DWORD dwIndex, LPWSTR pszValueName, - LPDWORD pcchValueNameLen, LPDWORD pdwType, LPVOID pvData, - LPDWORD pcbData, SHREGENUM_FLAGS enumRegFlags) -{ - FIXME("(%p, 0x%08lx, %s, %p, %p, %p, %p, 0x%08x) stub\n", hUSKey, dwIndex, - debugstr_w(pszValueName), pcchValueNameLen, pdwType, pvData, pcbData, enumRegFlags); - return ERROR_INVALID_FUNCTION; -} - -/************************************************************************* - * SHRegQueryUSValueA [SHLWAPI.@] - * - * Query a user-specific registry value. - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: An error code from RegQueryValueExA(). - */ -LONG WINAPI SHRegQueryUSValueA( - HUSKEY hUSKey, /* [I] Key to query */ - LPCSTR pszValue, /* [I] Value name under hUSKey */ - LPDWORD pdwType, /* [O] Destination for value type */ - LPVOID pvData, /* [O] Destination for value data */ - LPDWORD pcbData, /* [O] Destination for value length */ - BOOL fIgnoreHKCU, /* [I] TRUE=Don't check HKEY_CURRENT_USER */ - LPVOID pvDefaultData, /* [I] Default data if pszValue does not exist */ - DWORD dwDefaultDataSize) /* [I] Length of pvDefaultData */ -{ - LONG ret = ~ERROR_SUCCESS; - LONG i, maxmove; - HKEY dokey; - CHAR *src, *dst; - - /* if user wants HKCU, and it exists, then try it */ - if (!fIgnoreHKCU && (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) { - ret = RegQueryValueExA(dokey, - pszValue, 0, pdwType, pvData, pcbData); - TRACE("HKCU RegQueryValue returned %08lx\n", ret); - } - - /* if HKCU did not work and HKLM exists, then try it */ - if ((ret != ERROR_SUCCESS) && - (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) { - ret = RegQueryValueExA(dokey, - pszValue, 0, pdwType, pvData, pcbData); - TRACE("HKLM RegQueryValue returned %08lx\n", ret); - } - - /* if neither worked, and default data exists, then use it */ - if (ret != ERROR_SUCCESS) { - if (pvDefaultData && (dwDefaultDataSize != 0)) { - maxmove = (dwDefaultDataSize >= *pcbData) ? *pcbData : dwDefaultDataSize; - src = (CHAR*)pvDefaultData; - dst = (CHAR*)pvData; - for(i=0; i<maxmove; i++) *dst++ = *src++; - *pcbData = maxmove; - TRACE("setting default data\n"); - ret = ERROR_SUCCESS; - } - } - return ret; -} - - -/************************************************************************* - * SHRegQueryUSValueW [SHLWAPI.@] - * - * See SHRegQueryUSValueA. - */ -LONG WINAPI SHRegQueryUSValueW( - HUSKEY hUSKey, - LPCWSTR pszValue, - LPDWORD pdwType, - LPVOID pvData, - LPDWORD pcbData, - BOOL fIgnoreHKCU, - LPVOID pvDefaultData, - DWORD dwDefaultDataSize) -{ - LONG ret = ~ERROR_SUCCESS; - LONG i, maxmove; - HKEY dokey; - CHAR *src, *dst; - - /* if user wants HKCU, and it exists, then try it */ - if (!fIgnoreHKCU && (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) { - ret = RegQueryValueExW(dokey, - pszValue, 0, pdwType, pvData, pcbData); - TRACE("HKCU RegQueryValue returned %08lx\n", ret); - } - - /* if HKCU did not work and HKLM exists, then try it */ - if ((ret != ERROR_SUCCESS) && - (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) { - ret = RegQueryValueExW(dokey, - pszValue, 0, pdwType, pvData, pcbData); - TRACE("HKLM RegQueryValue returned %08lx\n", ret); - } - - /* if neither worked, and default data exists, then use it */ - if (ret != ERROR_SUCCESS) { - if (pvDefaultData && (dwDefaultDataSize != 0)) { - maxmove = (dwDefaultDataSize >= *pcbData) ? *pcbData : dwDefaultDataSize; - src = (CHAR*)pvDefaultData; - dst = (CHAR*)pvData; - for(i=0; i<maxmove; i++) *dst++ = *src++; - *pcbData = maxmove; - TRACE("setting default data\n"); - ret = ERROR_SUCCESS; - } - } - return ret; -} - -/************************************************************************* - * SHRegGetUSValueA [SHLWAPI.@] - * - * Get a user-specific registry value. - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: An error code from SHRegOpenUSKeyA() or SHRegQueryUSValueA(). - * - * NOTES - * This function opens pSubKey, queries the value, and then closes the key. - */ -LONG WINAPI SHRegGetUSValueA( - LPCSTR pSubKey, /* [I] Key name to open */ - LPCSTR pValue, /* [I] Value name to open */ - LPDWORD pwType, /* [O] Destination for the type of the value */ - LPVOID pvData, /* [O] Destination for the value */ - LPDWORD pcbData, /* [I] Destination for the length of the value **/ - BOOL flagIgnoreHKCU, /* [I] TRUE=Don't check HKEY_CURRENT_USER */ - LPVOID pDefaultData, /* [I] Default value if it doesn't exist */ - DWORD wDefaultDataSize) /* [I] Length of pDefaultData */ -{ - HUSKEY myhuskey; - LONG ret; - - if (!pvData || !pcbData) return ERROR_INVALID_FUNCTION; /* FIXME:wrong*/ - TRACE("key '%s', value '%s', datalen %ld, %s\n", - debugstr_a(pSubKey), debugstr_a(pValue), *pcbData, - (flagIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM"); - - ret = SHRegOpenUSKeyA(pSubKey, 0x1, 0, &myhuskey, flagIgnoreHKCU); - if (ret == ERROR_SUCCESS) { - ret = SHRegQueryUSValueA(myhuskey, pValue, pwType, pvData, - pcbData, flagIgnoreHKCU, pDefaultData, - wDefaultDataSize); - SHRegCloseUSKey(myhuskey); - } - return ret; -} - -/************************************************************************* - * SHRegGetUSValueW [SHLWAPI.@] - * - * See SHRegGetUSValueA. - */ -LONG WINAPI SHRegGetUSValueW( - LPCWSTR pSubKey, - LPCWSTR pValue, - LPDWORD pwType, - LPVOID pvData, - LPDWORD pcbData, - BOOL flagIgnoreHKCU, - LPVOID pDefaultData, - DWORD wDefaultDataSize) -{ - HUSKEY myhuskey; - LONG ret; - - if (!pvData || !pcbData) return ERROR_INVALID_FUNCTION; /* FIXME:wrong*/ - TRACE("key '%s', value '%s', datalen %ld, %s\n", - debugstr_w(pSubKey), debugstr_w(pValue), *pcbData, - (flagIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM"); - - ret = SHRegOpenUSKeyW(pSubKey, 0x1, 0, &myhuskey, flagIgnoreHKCU); - if (ret == ERROR_SUCCESS) { - ret = SHRegQueryUSValueW(myhuskey, pValue, pwType, pvData, - pcbData, flagIgnoreHKCU, pDefaultData, - wDefaultDataSize); - SHRegCloseUSKey(myhuskey); - } - return ret; -} - -/************************************************************************* - * SHRegSetUSValueA [SHLWAPI.@] - * - * Set a user-specific registry value. - * - * PARAMS - * pszSubKey [I] Name of key to set the value in - * pszValue [I] Name of value under pszSubKey to set the value in - * dwType [I] Type of the value - * pvData [I] Data to set as the value - * cbData [I] length of pvData - * dwFlags [I] SHREGSET_ flags from "shlwapi.h" - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: An error code from SHRegOpenUSKeyA() or SHRegWriteUSValueA(), or - * ERROR_INVALID_FUNCTION if pvData is NULL. - * - * NOTES - * This function opens pszSubKey, sets the value, and then closes the key. - */ -LONG WINAPI SHRegSetUSValueA(LPCSTR pszSubKey, LPCSTR pszValue, DWORD dwType, - LPVOID pvData, DWORD cbData, DWORD dwFlags) -{ - BOOL ignoreHKCU = TRUE; - HUSKEY hkey; - LONG ret; - - TRACE("(%s,%s,%ld,%p,%ld,0x%08lx\n", debugstr_a(pszSubKey), debugstr_a(pszValue), - dwType, pvData, cbData, dwFlags); - - if (!pvData) - return ERROR_INVALID_FUNCTION; - - if (dwFlags & SHREGSET_HKCU || dwFlags & SHREGSET_FORCE_HKCU) - ignoreHKCU = FALSE; - - ret = SHRegOpenUSKeyA(pszSubKey, KEY_ALL_ACCESS, 0, &hkey, ignoreHKCU); - if (ret == ERROR_SUCCESS) - { - ret = SHRegWriteUSValueA(hkey, pszValue, dwType, pvData, cbData, dwFlags); - SHRegCloseUSKey(hkey); - } - return ret; -} - -/************************************************************************* - * SHRegSetUSValueW [SHLWAPI.@] - * - * See SHRegSetUSValueA. - */ -LONG WINAPI SHRegSetUSValueW(LPCWSTR pszSubKey, LPCWSTR pszValue, DWORD dwType, - LPVOID pvData, DWORD cbData, DWORD dwFlags) -{ - BOOL ignoreHKCU = TRUE; - HUSKEY hkey; - LONG ret; - - TRACE("(%s,%s,%ld,%p,%ld,0x%08lx\n", debugstr_w(pszSubKey), debugstr_w(pszValue), - dwType, pvData, cbData, dwFlags); - - if (!pvData) - return ERROR_INVALID_FUNCTION; - - if (dwFlags & SHREGSET_HKCU || dwFlags & SHREGSET_FORCE_HKCU) - ignoreHKCU = FALSE; - - ret = SHRegOpenUSKeyW(pszSubKey, KEY_ALL_ACCESS, 0, &hkey, ignoreHKCU); - if (ret == ERROR_SUCCESS) - { - ret = SHRegWriteUSValueW(hkey, pszValue, dwType, pvData, cbData, dwFlags); - SHRegCloseUSKey(hkey); - } - return ret; -} - -/************************************************************************* - * SHRegGetBoolUSValueA [SHLWAPI.@] - * - * Get a user-specific registry boolean value. - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: An error code from SHRegOpenUSKeyA() or SHRegQueryUSValueA(). - * - * NOTES - * This function opens pszSubKey, queries the value, and then closes the key. - * - * Boolean values are one of the following: - * True: YES,TRUE,non-zero - * False: NO,FALSE,0 - */ -BOOL WINAPI SHRegGetBoolUSValueA( - LPCSTR pszSubKey, /* [I] Key name to open */ - LPCSTR pszValue, /* [I] Value name to open */ - BOOL fIgnoreHKCU, /* [I] TRUE=Don't check HKEY_CURRENT_USER */ - BOOL fDefault) /* [I] Default value to use if pszValue is not present */ -{ - LONG retvalue; - DWORD type, datalen, work; - BOOL ret = fDefault; - CHAR data[10]; - - TRACE("key '%s', value '%s', %s\n", - debugstr_a(pszSubKey), debugstr_a(pszValue), - (fIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM"); - - datalen = sizeof(data)-1; - if (!(retvalue = SHRegGetUSValueA( pszSubKey, pszValue, &type, - data, &datalen, - fIgnoreHKCU, 0, 0))) { - /* process returned data via type into bool */ - switch (type) { - case REG_SZ: - data[9] = '\0'; /* set end of string */ - if (lstrcmpiA(data, "YES") == 0) ret = TRUE; - if (lstrcmpiA(data, "TRUE") == 0) ret = TRUE; - if (lstrcmpiA(data, "NO") == 0) ret = FALSE; - if (lstrcmpiA(data, "FALSE") == 0) ret = FALSE; - break; - case REG_DWORD: - work = *(LPDWORD)data; - ret = (work != 0); - break; - case REG_BINARY: - if (datalen == 1) { - ret = (data[0] != '\0'); - break; - } - default: - FIXME("Unsupported registry data type %ld\n", type); - ret = FALSE; - } - TRACE("got value (type=%ld), returing <%s>\n", type, - (ret) ? "TRUE" : "FALSE"); - } - else { - ret = fDefault; - TRACE("returning default data <%s>\n", - (ret) ? "TRUE" : "FALSE"); - } - return ret; -} - -/************************************************************************* - * SHRegGetBoolUSValueW [SHLWAPI.@] - * - * See SHRegGetBoolUSValueA. - */ -BOOL WINAPI SHRegGetBoolUSValueW( - LPCWSTR pszSubKey, - LPCWSTR pszValue, - BOOL fIgnoreHKCU, - BOOL fDefault) -{ - static const WCHAR wYES[]= {'Y','E','S','\0'}; - static const WCHAR wTRUE[]= {'T','R','U','E','\0'}; - static const WCHAR wNO[]= {'N','O','\0'}; - static const WCHAR wFALSE[]={'F','A','L','S','E','\0'}; - LONG retvalue; - DWORD type, datalen, work; - BOOL ret = fDefault; - WCHAR data[10]; - - TRACE("key '%s', value '%s', %s\n", - debugstr_w(pszSubKey), debugstr_w(pszValue), - (fIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM"); - - datalen = (sizeof(data)-1) * sizeof(WCHAR); - if (!(retvalue = SHRegGetUSValueW( pszSubKey, pszValue, &type, - data, &datalen, - fIgnoreHKCU, 0, 0))) { - /* process returned data via type into bool */ - switch (type) { - case REG_SZ: - data[9] = L'\0'; /* set end of string */ - if (lstrcmpiW(data, wYES)==0 || lstrcmpiW(data, wTRUE)==0) - ret = TRUE; - else if (lstrcmpiW(data, wNO)==0 || lstrcmpiW(data, wFALSE)==0) - ret = FALSE; - break; - case REG_DWORD: - work = *(LPDWORD)data; - ret = (work != 0); - break; - case REG_BINARY: - if (datalen == 1) { - ret = (data[0] != L'\0'); - break; - } - default: - FIXME("Unsupported registry data type %ld\n", type); - ret = FALSE; - } - TRACE("got value (type=%ld), returing <%s>\n", type, - (ret) ? "TRUE" : "FALSE"); - } - else { - ret = fDefault; - TRACE("returning default data <%s>\n", - (ret) ? "TRUE" : "FALSE"); - } - return ret; -} - -/************************************************************************* - * SHRegQueryInfoUSKeyA [SHLWAPI.@] - * - * Get information about a user-specific registry key. - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: An error code from RegQueryInfoKeyA(). - */ -LONG WINAPI SHRegQueryInfoUSKeyA( - HUSKEY hUSKey, /* [I] Key to query */ - LPDWORD pcSubKeys, /* [O] Destination for number of sub keys */ - LPDWORD pcchMaxSubKeyLen, /* [O] Destination for the length of the biggest sub key name */ - LPDWORD pcValues, /* [O] Destination for number of values */ - LPDWORD pcchMaxValueNameLen,/* [O] Destination for the length of the biggest value */ - SHREGENUM_FLAGS enumRegFlags) /* [in] SHREGENUM_ flags from "shlwapi.h" */ -{ - HKEY dokey; - LONG ret; - - TRACE("(%p,%p,%p,%p,%p,%d)\n", - hUSKey,pcSubKeys,pcchMaxSubKeyLen,pcValues, - pcchMaxValueNameLen,enumRegFlags); - - /* if user wants HKCU, and it exists, then try it */ - if (((enumRegFlags == SHREGENUM_HKCU) || - (enumRegFlags == SHREGENUM_DEFAULT)) && - (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) { - ret = RegQueryInfoKeyA(dokey, 0, 0, 0, - pcSubKeys, pcchMaxSubKeyLen, 0, - pcValues, pcchMaxValueNameLen, 0, 0, 0); - if ((ret == ERROR_SUCCESS) || - (enumRegFlags == SHREGENUM_HKCU)) - return ret; - } - if (((enumRegFlags == SHREGENUM_HKLM) || - (enumRegFlags == SHREGENUM_DEFAULT)) && - (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) { - return RegQueryInfoKeyA(dokey, 0, 0, 0, - pcSubKeys, pcchMaxSubKeyLen, 0, - pcValues, pcchMaxValueNameLen, 0, 0, 0); - } - return ERROR_INVALID_FUNCTION; -} - -/************************************************************************* - * SHRegQueryInfoUSKeyW [SHLWAPI.@] - * - * See SHRegQueryInfoUSKeyA. - */ -LONG WINAPI SHRegQueryInfoUSKeyW( - HUSKEY hUSKey, - LPDWORD pcSubKeys, - LPDWORD pcchMaxSubKeyLen, - LPDWORD pcValues, - LPDWORD pcchMaxValueNameLen, - SHREGENUM_FLAGS enumRegFlags) -{ - HKEY dokey; - LONG ret; - - TRACE("(%p,%p,%p,%p,%p,%d)\n", - hUSKey,pcSubKeys,pcchMaxSubKeyLen,pcValues, - pcchMaxValueNameLen,enumRegFlags); - - /* if user wants HKCU, and it exists, then try it */ - if (((enumRegFlags == SHREGENUM_HKCU) || - (enumRegFlags == SHREGENUM_DEFAULT)) && - (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) { - ret = RegQueryInfoKeyW(dokey, 0, 0, 0, - pcSubKeys, pcchMaxSubKeyLen, 0, - pcValues, pcchMaxValueNameLen, 0, 0, 0); - if ((ret == ERROR_SUCCESS) || - (enumRegFlags == SHREGENUM_HKCU)) - return ret; - } - if (((enumRegFlags == SHREGENUM_HKLM) || - (enumRegFlags == SHREGENUM_DEFAULT)) && - (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) { - return RegQueryInfoKeyW(dokey, 0, 0, 0, - pcSubKeys, pcchMaxSubKeyLen, 0, - pcValues, pcchMaxValueNameLen, 0, 0, 0); - } - return ERROR_INVALID_FUNCTION; -} - -/************************************************************************* - * SHRegEnumUSKeyA [SHLWAPI.@] - * - * Enumerate a user-specific registry key. - * - * RETURNS - * Success: ERROR_SUCCESS - * Failure: An error code from RegEnumKeyExA(). - */ -LONG WINAPI SHRegEnumUSKeyA( - HUSKEY hUSKey, /* [in] Key to enumerate */ - DWORD dwIndex, /* [in] Index within hUSKey */ - LPSTR pszName, /* [out] Name of the enumerated value */ - LPDWORD pcchValueNameLen, /* [in/out] Length of pszName */ - SHREGENUM_FLAGS enumRegFlags) /* [in] SHREGENUM_ flags from "shlwapi.h" */ -{ - HKEY dokey; - - TRACE("(%p,%ld,%p,%p(%ld),%d)\n", - hUSKey, dwIndex, pszName, pcchValueNameLen, - *pcchValueNameLen, enumRegFlags); - - if (((enumRegFlags == SHREGENUM_HKCU) || - (enumRegFlags == SHREGENUM_DEFAULT)) && - (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) { - return RegEnumKeyExA(dokey, dwIndex, pszName, pcchValueNameLen, - 0, 0, 0, 0); - } - - if (((enumRegFlags == SHREGENUM_HKLM) || - (enumRegFlags == SHREGENUM_DEFAULT)) && - (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) { - return RegEnumKeyExA(dokey, dwIndex, pszName, pcchValueNameLen, - 0, 0, 0, 0); - } - FIXME("no support for SHREGENUM_BOTH\n"); - return ERROR_INVALID_FUNCTION; -} - -/************************************************************************* - * SHRegEnumUSKeyW [SHLWAPI.@] - * - * See SHRegEnumUSKeyA. - */ -LONG WINAPI SHRegEnumUSKeyW( - HUSKEY hUSKey, - DWORD dwIndex, - LPWSTR pszName, - LPDWORD pcchValueNameLen, - SHREGENUM_FLAGS enumRegFlags) -{ - HKEY dokey; - - TRACE("(%p,%ld,%p,%p(%ld),%d)\n", - hUSKey, dwIndex, pszName, pcchValueNameLen, - *pcchValueNameLen, enumRegFlags); - - if (((enumRegFlags == SHREGENUM_HKCU) || - (enumRegFlags == SHREGENUM_DEFAULT)) && - (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) { - return RegEnumKeyExW(dokey, dwIndex, pszName, pcchValueNameLen, - 0, 0, 0, 0); - } - - if (((enumRegFlags == SHREGENUM_HKLM) || - (enumRegFlags == SHREGENUM_DEFAULT)) && - (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) { - return RegEnumKeyExW(dokey, dwIndex, pszName, pcchValueNameLen, - 0, 0, 0, 0); - } - FIXME("no support for SHREGENUM_BOTH\n"); - return ERROR_INVALID_FUNCTION; -} - - -/************************************************************************* - * SHRegWriteUSValueA [SHLWAPI.@] - * - * Write a user-specific registry value. - * - * PARAMS - * hUSKey [I] Key to write the value to - * pszValue [I] Name of value under hUSKey to write the value as - * dwType [I] Type of the value - * pvData [I] Data to set as the value - * cbData [I] length of pvData - * dwFlags [I] SHREGSET_ flags from "shlwapi.h" - * - * RETURNS - * Success: ERROR_SUCCESS. - * Failure: ERROR_INVALID_PARAMETER, if any parameter is invalid, otherwise - * an error code from RegSetValueExA(). - * - * NOTES - * dwFlags must have at least SHREGSET_FORCE_HKCU or SHREGSET_FORCE_HKLM set. - */ -LONG WINAPI SHRegWriteUSValueA(HUSKEY hUSKey, LPCSTR pszValue, DWORD dwType, - LPVOID pvData, DWORD cbData, DWORD dwFlags) -{ - WCHAR szValue[MAX_PATH]; - - if (pszValue) - MultiByteToWideChar(CP_ACP, 0, pszValue, -1, szValue, MAX_PATH); - - return SHRegWriteUSValueW(hUSKey, pszValue ? szValue : NULL, dwType, - pvData, cbData, dwFlags); -} - -/************************************************************************* - * SHRegWriteUSValueW [SHLWAPI.@] - * - * See SHRegWriteUSValueA. - */ -LONG WINAPI SHRegWriteUSValueW(HUSKEY hUSKey, LPCWSTR pszValue, DWORD dwType, - LPVOID pvData, DWORD cbData, DWORD dwFlags) -{ - LONG dummy; - LPSHUSKEY hKey = (LPSHUSKEY)hUSKey; - LONG ret = ERROR_SUCCESS; - - TRACE("(%p,%s,%ld,%p,%ld,%ld)\n", hUSKey, debugstr_w(pszValue), - dwType, pvData, cbData, dwFlags); - - if (!hUSKey || IsBadWritePtr(hUSKey, sizeof(SHUSKEY)) || - !(dwFlags & (SHREGSET_FORCE_HKCU|SHREGSET_FORCE_HKLM))) - return ERROR_INVALID_PARAMETER; - - if (dwFlags & (SHREGSET_FORCE_HKCU|SHREGSET_HKCU)) - { - if (!hKey->HKCUkey) - { - /* Create the key */ - ret = RegCreateKeyW(hKey->HKCUstart, hKey->lpszPath, &hKey->HKCUkey); - TRACE("Creating HKCU key, ret = %ld\n", ret); - if (ret && (dwFlags & (SHREGSET_FORCE_HKCU))) - { - hKey->HKCUkey = 0; - return ret; - } - } - - if (!ret) - { - if ((dwFlags & SHREGSET_FORCE_HKCU) || - RegQueryValueExW(hKey->HKCUkey, pszValue, NULL, NULL, NULL, &dummy)) - { - /* Doesn't exist or we are forcing: Write value */ - ret = RegSetValueExW(hKey->HKCUkey, pszValue, 0, dwType, pvData, cbData); - TRACE("Writing HKCU value, ret = %ld\n", ret); - } - } - } - - if (dwFlags & (SHREGSET_FORCE_HKLM|SHREGSET_HKLM)) - { - if (!hKey->HKLMkey) - { - /* Create the key */ - ret = RegCreateKeyW(hKey->HKLMstart, hKey->lpszPath, &hKey->HKLMkey); - TRACE("Creating HKLM key, ret = %ld\n", ret); - if (ret && (dwFlags & (SHREGSET_FORCE_HKLM))) - { - hKey->HKLMkey = 0; - return ret; - } - } - - if (!ret) - { - if ((dwFlags & SHREGSET_FORCE_HKLM) || - RegQueryValueExW(hKey->HKLMkey, pszValue, NULL, NULL, NULL, &dummy)) - { - /* Doesn't exist or we are forcing: Write value */ - ret = RegSetValueExW(hKey->HKLMkey, pszValue, 0, dwType, pvData, cbData); - TRACE("Writing HKLM value, ret = %ld\n", ret); - } - } - } - - return ret; -} - -/************************************************************************* - * SHRegGetPathA [SHLWAPI.@] - * - * Get a path from the registry. - * - * PARAMS - * hKey [I] Handle to registry key - * lpszSubKey [I] Name of sub key containing path to get - * lpszValue [I] Name of value containing path to get - * lpszPath [O] Buffer for returned path - * dwFlags [I] Reserved - * - * RETURNS - * Success: ERROR_SUCCESS. lpszPath contains the path. - * Failure: An error code from RegOpenKeyExA() or SHQueryValueExA(). - */ -DWORD WINAPI SHRegGetPathA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue, - LPSTR lpszPath, DWORD dwFlags) -{ - DWORD dwSize = MAX_PATH; - - TRACE("(hkey=%p,%s,%s,%p,%ld)\n", hKey, debugstr_a(lpszSubKey), - debugstr_a(lpszValue), lpszPath, dwFlags); - - return SHGetValueA(hKey, lpszSubKey, lpszValue, 0, lpszPath, &dwSize); -} - -/************************************************************************* - * SHRegGetPathW [SHLWAPI.@] - * - * See SHRegGetPathA. - */ -DWORD WINAPI SHRegGetPathW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue, - LPWSTR lpszPath, DWORD dwFlags) -{ - DWORD dwSize = MAX_PATH; - - TRACE("(hkey=%p,%s,%s,%p,%ld)\n", hKey, debugstr_w(lpszSubKey), - debugstr_w(lpszValue), lpszPath, dwFlags); - - return SHGetValueW(hKey, lpszSubKey, lpszValue, 0, lpszPath, &dwSize); -} - - -/************************************************************************* - * SHRegSetPathA [SHLWAPI.@] - * - * Write a path to the registry. - * - * PARAMS - * hKey [I] Handle to registry key - * lpszSubKey [I] Name of sub key containing path to set - * lpszValue [I] Name of value containing path to set - * lpszPath [O] Path to write - * dwFlags [I] Reserved, must be 0. - * - * RETURNS - * Success: ERROR_SUCCESS. - * Failure: An error code from SHSetValueA(). - */ -DWORD WINAPI SHRegSetPathA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue, - LPCSTR lpszPath, DWORD dwFlags) -{ - char szBuff[MAX_PATH]; - - FIXME("(hkey=%p,%s,%s,%p,%ld) - semi-stub\n",hKey, debugstr_a(lpszSubKey), - debugstr_a(lpszValue), lpszPath, dwFlags); - - lstrcpyA(szBuff, lpszPath); - - /* FIXME: PathUnExpandEnvStringsA(szBuff); */ - - return SHSetValueA(hKey,lpszSubKey, lpszValue, REG_SZ, szBuff, - lstrlenA(szBuff)); -} - -/************************************************************************* - * SHRegSetPathW [SHLWAPI.@] - * - * See SHRegSetPathA. - */ -DWORD WINAPI SHRegSetPathW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue, - LPCWSTR lpszPath, DWORD dwFlags) -{ - WCHAR szBuff[MAX_PATH]; - - FIXME("(hkey=%p,%s,%s,%p,%ld) - semi-stub\n",hKey, debugstr_w(lpszSubKey), - debugstr_w(lpszValue), lpszPath, dwFlags); - - lstrcpyW(szBuff, lpszPath); - - /* FIXME: PathUnExpandEnvStringsW(szBuff); */ - - return SHSetValueW(hKey,lpszSubKey, lpszValue, REG_SZ, szBuff, - lstrlenW(szBuff)); -} - -/************************************************************************* - * SHGetValueA [SHLWAPI.@] - * - * Get a value from the registry. - * - * PARAMS - * hKey [I] Handle to registry key - * lpszSubKey [I] Name of sub key containing value to get - * lpszValue [I] Name of value to get - * pwType [O] Pointer to the values type - * pvData [O] Pointer to the values data - * pcbData [O] Pointer to the values size - * - * RETURNS - * Success: ERROR_SUCCESS. Output parameters contain the details read. - * Failure: An error code from RegOpenKeyExA() or SHQueryValueExA(). - */ -DWORD WINAPI SHGetValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue, - LPDWORD pwType, LPVOID pvData, LPDWORD pcbData) -{ - DWORD dwRet = 0; - HKEY hSubKey = 0; - - TRACE("(hkey=%p,%s,%s,%p,%p,%p)\n", hKey, debugstr_a(lpszSubKey), - debugstr_a(lpszValue), pwType, pvData, pcbData); - - /* lpszSubKey can be 0. In this case the value is taken from the - * current key. - */ - if(lpszSubKey) - dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_QUERY_VALUE, &hSubKey); - - if (! dwRet) - { - /* SHQueryValueEx expands Environment strings */ - dwRet = SHQueryValueExA(hSubKey ? hSubKey : hKey, lpszValue, 0, pwType, pvData, pcbData); - if (hSubKey) RegCloseKey(hSubKey); - } - return dwRet; -} - -/************************************************************************* - * SHGetValueW [SHLWAPI.@] - * - * See SHGetValueA. - */ -DWORD WINAPI SHGetValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue, - LPDWORD pwType, LPVOID pvData, LPDWORD pcbData) -{ - DWORD dwRet = 0; - HKEY hSubKey = 0; - - TRACE("(hkey=%p,%s,%s,%p,%p,%p)\n", hKey, debugstr_w(lpszSubKey), - debugstr_w(lpszValue), pwType, pvData, pcbData); - - if(lpszSubKey) - dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_QUERY_VALUE, &hSubKey); - - if (! dwRet) - { - dwRet = SHQueryValueExW(hSubKey ? hSubKey : hKey, lpszValue, 0, pwType, pvData, pcbData); - if (hSubKey) RegCloseKey(hSubKey); - } - return dwRet; -} - -/************************************************************************* - * SHSetValueA [SHLWAPI.@] - * - * Set a value in the registry. - * - * PARAMS - * hKey [I] Handle to registry key - * lpszSubKey [I] Name of sub key under hKey - * lpszValue [I] Name of value to set - * dwType [I] Type of the value - * pvData [I] Data of the value - * cbData [I] Size of the value - * - * RETURNS - * Success: ERROR_SUCCESS. The value is set with the data given. - * Failure: An error code from RegCreateKeyExA() or RegSetValueExA() - * - * NOTES - * If lpszSubKey does not exist, it is created before the value is set. If - * lpszSubKey is NULL or an empty string, then the value is added directly - * to hKey instead. - */ -DWORD WINAPI SHSetValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue, - DWORD dwType, LPCVOID pvData, DWORD cbData) -{ - DWORD dwRet = ERROR_SUCCESS, dwDummy; - HKEY hSubKey; - static const char szEmpty[] = { '\0' }; - - TRACE("(hkey=%p,%s,%s,%ld,%p,%ld)\n", hKey, debugstr_a(lpszSubKey), - debugstr_a(lpszValue), dwType, pvData, cbData); - - if (lpszSubKey && *lpszSubKey) - dwRet = RegCreateKeyExA(hKey, lpszSubKey, 0, (LPSTR)szEmpty, - 0, KEY_SET_VALUE, NULL, &hSubKey, &dwDummy); - else - hSubKey = hKey; - if (!dwRet) - { - dwRet = RegSetValueExA(hSubKey, lpszValue, 0, dwType, pvData, cbData); - if (hSubKey != hKey) - RegCloseKey(hSubKey); - } - return dwRet; -} - -/************************************************************************* - * SHSetValueW [SHLWAPI.@] - * - * See SHSetValueA. - */ -DWORD WINAPI SHSetValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue, - DWORD dwType, LPCVOID pvData, DWORD cbData) -{ - DWORD dwRet = ERROR_SUCCESS, dwDummy; - HKEY hSubKey; - static const WCHAR szEmpty[] = { '\0' }; - - TRACE("(hkey=%p,%s,%s,%ld,%p,%ld)\n", hKey, debugstr_w(lpszSubKey), - debugstr_w(lpszValue), dwType, pvData, cbData); - - if (lpszSubKey && *lpszSubKey) - dwRet = RegCreateKeyExW(hKey, lpszSubKey, 0, (LPWSTR)szEmpty, - 0, KEY_SET_VALUE, NULL, &hSubKey, &dwDummy); - else - hSubKey = hKey; - if (!dwRet) - { - dwRet = RegSetValueExW(hSubKey, lpszValue, 0, dwType, pvData, cbData); - if (hSubKey != hKey) - RegCloseKey(hSubKey); - } - return dwRet; -} - -/************************************************************************* - * SHQueryInfoKeyA [SHLWAPI.@] - * - * Get information about a registry key. See RegQueryInfoKeyA(). - * - * RETURNS - * The result of calling RegQueryInfoKeyA(). - */ -LONG WINAPI SHQueryInfoKeyA(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax, - LPDWORD pwValues, LPDWORD pwValueMax) -{ - TRACE("(hkey=%p,%p,%p,%p,%p)\n", hKey, pwSubKeys, pwSubKeyMax, - pwValues, pwValueMax); - return RegQueryInfoKeyA(hKey, NULL, NULL, NULL, pwSubKeys, pwSubKeyMax, - NULL, pwValues, pwValueMax, NULL, NULL, NULL); -} - -/************************************************************************* - * SHQueryInfoKeyW [SHLWAPI.@] - * - * See SHQueryInfoKeyA. - */ -LONG WINAPI SHQueryInfoKeyW(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax, - LPDWORD pwValues, LPDWORD pwValueMax) -{ - TRACE("(hkey=%p,%p,%p,%p,%p)\n", hKey, pwSubKeys, pwSubKeyMax, - pwValues, pwValueMax); - return RegQueryInfoKeyW(hKey, NULL, NULL, NULL, pwSubKeys, pwSubKeyMax, - NULL, pwValues, pwValueMax, NULL, NULL, NULL); -} - -/************************************************************************* - * SHQueryValueExA [SHLWAPI.@] - * - * Get a value from the registry, expanding environment variable strings. - * - * PARAMS - * hKey [I] Handle to registry key - * lpszValue [I] Name of value to query - * lpReserved [O] Reserved for future use; must be NULL - * pwType [O] Optional pointer updated with the values type - * pvData [O] Optional pointer updated with the values data - * pcbData [O] Optional pointer updated with the values size - * - * RETURNS - * Success: ERROR_SUCCESS. Any non NULL output parameters are updated with - * information about the value. - * Failure: ERROR_OUTOFMEMORY if memory allocation fails, or the type of the - * data is REG_EXPAND_SZ and pcbData is NULL. Otherwise an error - * code from RegQueryValueExA() or ExpandEnvironmentStringsA(). - * - * NOTES - * Either pwType, pvData or pcbData may be NULL if the caller doesn't want - * the type, data or size information for the value. - * - * If the type of the data is REG_EXPAND_SZ, it is expanded to REG_SZ. The - * value returned will be truncated if it is of type REG_SZ and bigger than - * the buffer given to store it. - * - * REG_EXPAND_SZ: - * case-1: the unexpanded string is smaller than the expanded one - * subcase-1: the buffer is too small to hold the unexpanded string: - * function fails and returns the size of the unexpanded string. - * - * subcase-2: buffer is too small to hold the expanded string: - * the function return success (!!) and the result is truncated - * *** This is clearly an error in the native implementation. *** - * - * case-2: the unexpanded string is bigger than the expanded one - * The buffer must have enough space to hold the unexpanded - * string even if the result is smaller. - * - */ -DWORD WINAPI SHQueryValueExA( HKEY hKey, LPCSTR lpszValue, - LPDWORD lpReserved, LPDWORD pwType, - LPVOID pvData, LPDWORD pcbData) -{ - DWORD dwRet, dwType, dwUnExpDataLen = 0, dwExpDataLen; - - TRACE("(hkey=%p,%s,%p,%p,%p,%p=%ld)\n", hKey, debugstr_a(lpszValue), - lpReserved, pwType, pvData, pcbData, pcbData ? *pcbData : 0); - - if (pcbData) dwUnExpDataLen = *pcbData; - - dwRet = RegQueryValueExA(hKey, lpszValue, lpReserved, &dwType, pvData, &dwUnExpDataLen); - - if (pcbData && (dwType == REG_EXPAND_SZ)) - { - DWORD nBytesToAlloc; - - /* Expand type REG_EXPAND_SZ into REG_SZ */ - LPSTR szData; - - /* If the caller didn't supply a buffer or the buffer is too small we have - * to allocate our own - */ - if ((!pvData) || (dwRet == ERROR_MORE_DATA) ) - { - char cNull = '\0'; - nBytesToAlloc = (!pvData || (dwRet == ERROR_MORE_DATA)) ? dwUnExpDataLen : *pcbData; - - szData = (LPSTR) LocalAlloc(LMEM_ZEROINIT, nBytesToAlloc); - RegQueryValueExA (hKey, lpszValue, lpReserved, NULL, (LPBYTE)szData, &nBytesToAlloc); - dwExpDataLen = ExpandEnvironmentStringsA(szData, &cNull, 1); - dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen); - LocalFree((HLOCAL) szData); - } - else - { - nBytesToAlloc = (lstrlenA(pvData)+1) * sizeof (CHAR); - szData = (LPSTR) LocalAlloc(LMEM_ZEROINIT, nBytesToAlloc ); - lstrcpyA(szData, pvData); - dwExpDataLen = ExpandEnvironmentStringsA(szData, pvData, *pcbData / sizeof(CHAR)); - if (dwExpDataLen > *pcbData) dwRet = ERROR_MORE_DATA; - dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen); - LocalFree((HLOCAL) szData); - } - } - - /* Update the type and data size if the caller wanted them */ - if ( dwType == REG_EXPAND_SZ ) dwType = REG_SZ; - if ( pwType ) *pwType = dwType; - if ( pcbData ) *pcbData = dwUnExpDataLen; - return dwRet; -} - - -/************************************************************************* - * SHQueryValueExW [SHLWAPI.@] - * - * See SHQueryValueExA. - */ -DWORD WINAPI SHQueryValueExW(HKEY hKey, LPCWSTR lpszValue, - LPDWORD lpReserved, LPDWORD pwType, - LPVOID pvData, LPDWORD pcbData) -{ - DWORD dwRet, dwType, dwUnExpDataLen = 0, dwExpDataLen; - - TRACE("(hkey=%p,%s,%p,%p,%p,%p=%ld)\n", hKey, debugstr_w(lpszValue), - lpReserved, pwType, pvData, pcbData, pcbData ? *pcbData : 0); - - if (pcbData) dwUnExpDataLen = *pcbData; - - dwRet = RegQueryValueExW(hKey, lpszValue, lpReserved, &dwType, pvData, &dwUnExpDataLen); - if (dwRet!=ERROR_SUCCESS && dwRet!=ERROR_MORE_DATA) - return dwRet; - - if (pcbData && (dwType == REG_EXPAND_SZ)) - { - DWORD nBytesToAlloc; - - /* Expand type REG_EXPAND_SZ into REG_SZ */ - LPWSTR szData; - - /* If the caller didn't supply a buffer or the buffer is too small we have - * to allocate our own - */ - if ((!pvData) || (dwRet == ERROR_MORE_DATA) ) - { - WCHAR cNull = '\0'; - nBytesToAlloc = (!pvData || (dwRet == ERROR_MORE_DATA)) ? dwUnExpDataLen : *pcbData; - - szData = (LPWSTR) LocalAlloc(LMEM_ZEROINIT, nBytesToAlloc); - RegQueryValueExW (hKey, lpszValue, lpReserved, NULL, (LPBYTE)szData, &nBytesToAlloc); - dwExpDataLen = ExpandEnvironmentStringsW(szData, &cNull, 1); - dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen); - LocalFree((HLOCAL) szData); - } - else - { - nBytesToAlloc = (lstrlenW(pvData) + 1) * sizeof(WCHAR); - szData = (LPWSTR) LocalAlloc(LMEM_ZEROINIT, nBytesToAlloc ); - lstrcpyW(szData, pvData); - dwExpDataLen = ExpandEnvironmentStringsW(szData, pvData, *pcbData/sizeof(WCHAR) ); - if (dwExpDataLen > *pcbData) dwRet = ERROR_MORE_DATA; - dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen); - LocalFree((HLOCAL) szData); - } - } - - /* Update the type and data size if the caller wanted them */ - if ( dwType == REG_EXPAND_SZ ) dwType = REG_SZ; - if ( pwType ) *pwType = dwType; - if ( pcbData ) *pcbData = dwUnExpDataLen; - return dwRet; -} - -/************************************************************************* - * SHDeleteKeyA [SHLWAPI.@] - * - * Delete a registry key and any sub keys/values present - * - * PARAMS - * hKey [I] Handle to registry key - * lpszSubKey [I] Name of sub key to delete - * - * RETURNS - * Success: ERROR_SUCCESS. The key is deleted. - * Failure: An error code from RegOpenKeyExA(), RegQueryInfoKeyA(), - * RegEnumKeyExA() or RegDeleteKeyA(). - */ -DWORD WINAPI SHDeleteKeyA(HKEY hKey, LPCSTR lpszSubKey) -{ - DWORD dwRet, dwMaxSubkeyLen = 0, dwSize; - CHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf; - HKEY hSubKey = 0; - - TRACE("(hkey=%p,%s)\n", hKey, debugstr_a(lpszSubKey)); - - dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); - if(!dwRet) - { - /* Find the maximum subkey length so that we can allocate a buffer */ - dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, NULL, - &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL); - if(!dwRet) - { - dwMaxSubkeyLen++; - if (dwMaxSubkeyLen > sizeof(szNameBuf)) - /* Name too big: alloc a buffer for it */ - lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(CHAR)); - - if(!lpszName) - dwRet = ERROR_NOT_ENOUGH_MEMORY; - else - { - while (dwRet == ERROR_SUCCESS) - { - dwSize = dwMaxSubkeyLen; - dwRet = RegEnumKeyExA(hSubKey, 0, lpszName, &dwSize, NULL, NULL, NULL, NULL); - if (dwRet == ERROR_SUCCESS || dwRet == ERROR_MORE_DATA) - dwRet = SHDeleteKeyA(hSubKey, lpszName); - } - if (dwRet == ERROR_NO_MORE_ITEMS) - dwRet = ERROR_SUCCESS; - if (lpszName != szNameBuf) - HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */ - } - } - - RegCloseKey(hSubKey); - if(!dwRet) - dwRet = RegDeleteKeyA(hKey, lpszSubKey); - } - return dwRet; -} - -/************************************************************************* - * SHDeleteKeyW [SHLWAPI.@] - * - * See SHDeleteKeyA. - */ -DWORD WINAPI SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey) -{ - DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i; - WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf; - HKEY hSubKey = 0; - - TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey)); - - dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); - if(!dwRet) - { - /* Find how many subkeys there are */ - dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount, - &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL); - if(!dwRet) - { - dwMaxSubkeyLen++; - if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR)) - /* Name too big: alloc a buffer for it */ - lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR)); - - if(!lpszName) - dwRet = ERROR_NOT_ENOUGH_MEMORY; - else - { - /* Recursively delete all the subkeys */ - for(i = 0; i < dwKeyCount && !dwRet; i++) - { - dwSize = dwMaxSubkeyLen; - dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL); - if(!dwRet) - dwRet = SHDeleteKeyW(hSubKey, lpszName); - } - - if (lpszName != szNameBuf) - HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */ - } - } - - RegCloseKey(hSubKey); - if(!dwRet) - dwRet = RegDeleteKeyW(hKey, lpszSubKey); - } - return dwRet; -} - -/************************************************************************* - * SHDeleteEmptyKeyA [SHLWAPI.@] - * - * Delete a registry key with no sub keys. - * - * PARAMS - * hKey [I] Handle to registry key - * lpszSubKey [I] Name of sub key to delete - * - * RETURNS - * Success: ERROR_SUCCESS. The key is deleted. - * Failure: If the key is not empty, returns ERROR_KEY_HAS_CHILDREN. Otherwise - * returns an error code from RegOpenKeyExA(), RegQueryInfoKeyA() or - * RegDeleteKeyA(). - */ -DWORD WINAPI SHDeleteEmptyKeyA(HKEY hKey, LPCSTR lpszSubKey) -{ - DWORD dwRet, dwKeyCount = 0; - HKEY hSubKey = 0; - - TRACE("(hkey=%p,%s)\n", hKey, debugstr_a(lpszSubKey)); - - dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); - if(!dwRet) - { - dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount, - NULL, NULL, NULL, NULL, NULL, NULL, NULL); - RegCloseKey(hSubKey); - if(!dwRet) - { - if (!dwKeyCount) - dwRet = RegDeleteKeyA(hKey, lpszSubKey); - else - dwRet = ERROR_KEY_HAS_CHILDREN; - } - } - return dwRet; -} - -/************************************************************************* - * SHDeleteEmptyKeyW [SHLWAPI.@] - * - * See SHDeleteEmptyKeyA. - */ -DWORD WINAPI SHDeleteEmptyKeyW(HKEY hKey, LPCWSTR lpszSubKey) -{ - DWORD dwRet, dwKeyCount = 0; - HKEY hSubKey = 0; - - TRACE("(hkey=%p, %s)\n", hKey, debugstr_w(lpszSubKey)); - - dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); - if(!dwRet) - { - dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount, - NULL, NULL, NULL, NULL, NULL, NULL, NULL); - RegCloseKey(hSubKey); - if(!dwRet) - { - if (!dwKeyCount) - dwRet = RegDeleteKeyW(hKey, lpszSubKey); - else - dwRet = ERROR_KEY_HAS_CHILDREN; - } - } - return dwRet; -} - -/************************************************************************* - * SHDeleteOrphanKeyA [SHLWAPI.@] - * - * Delete a registry key with no sub keys or values. - * - * PARAMS - * hKey [I] Handle to registry key - * lpszSubKey [I] Name of sub key to possibly delete - * - * RETURNS - * Success: ERROR_SUCCESS. The key has been deleted if it was an orphan. - * Failure: An error from RegOpenKeyExA(), RegQueryValueExA(), or RegDeleteKeyA(). - */ -DWORD WINAPI SHDeleteOrphanKeyA(HKEY hKey, LPCSTR lpszSubKey) -{ - HKEY hSubKey; - DWORD dwKeyCount = 0, dwValueCount = 0, dwRet; - - TRACE("(hkey=%p,%s)\n", hKey, debugstr_a(lpszSubKey)); - - dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); - - if(!dwRet) - { - /* Get subkey and value count */ - dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount, - NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL); - - if(!dwRet && !dwKeyCount && !dwValueCount) - { - dwRet = RegDeleteKeyA(hKey, lpszSubKey); - } - RegCloseKey(hSubKey); - } - return dwRet; -} - -/************************************************************************* - * SHDeleteOrphanKeyW [SHLWAPI.@] - * - * See SHDeleteOrphanKeyA. - */ -DWORD WINAPI SHDeleteOrphanKeyW(HKEY hKey, LPCWSTR lpszSubKey) -{ - HKEY hSubKey; - DWORD dwKeyCount = 0, dwValueCount = 0, dwRet; - - TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey)); - - dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); - - if(!dwRet) - { - /* Get subkey and value count */ - dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount, - NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL); - - if(!dwRet && !dwKeyCount && !dwValueCount) - { - dwRet = RegDeleteKeyW(hKey, lpszSubKey); - } - RegCloseKey(hSubKey); - } - return dwRet; -} - -/************************************************************************* - * SHDeleteValueA [SHLWAPI.@] - * - * Delete a value from the registry. - * - * PARAMS - * hKey [I] Handle to registry key - * lpszSubKey [I] Name of sub key containing value to delete - * lpszValue [I] Name of value to delete - * - * RETURNS - * Success: ERROR_SUCCESS. The value is deleted. - * Failure: An error code from RegOpenKeyExA() or RegDeleteValueA(). - */ -DWORD WINAPI SHDeleteValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue) -{ - DWORD dwRet; - HKEY hSubKey; - - TRACE("(hkey=%p,%s,%s)\n", hKey, debugstr_a(lpszSubKey), debugstr_a(lpszValue)); - - dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_SET_VALUE, &hSubKey); - if (!dwRet) - { - dwRet = RegDeleteValueA(hSubKey, lpszValue); - RegCloseKey(hSubKey); - } - return dwRet; -} - -/************************************************************************* - * SHDeleteValueW [SHLWAPI.@] - * - * See SHDeleteValueA. - */ -DWORD WINAPI SHDeleteValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue) -{ - DWORD dwRet; - HKEY hSubKey; - - TRACE("(hkey=%p,%s,%s)\n", hKey, debugstr_w(lpszSubKey), debugstr_w(lpszValue)); - - dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_SET_VALUE, &hSubKey); - if (!dwRet) - { - dwRet = RegDeleteValueW(hSubKey, lpszValue); - RegCloseKey(hSubKey); - } - return dwRet; -} - -/************************************************************************* - * SHEnumKeyExA [SHLWAPI.@] - * - * Enumerate sub keys in a registry key. - * - * PARAMS - * hKey [I] Handle to registry key - * dwIndex [I] Index of key to enumerate - * lpszSubKey [O] Pointer updated with the subkey name - * pwLen [O] Pointer updated with the subkey length - * - * RETURNS - * Success: ERROR_SUCCESS. lpszSubKey and pwLen are updated. - * Failure: An error code from RegEnumKeyExA(). - */ -LONG WINAPI SHEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpszSubKey, - LPDWORD pwLen) -{ - TRACE("(hkey=%p,%ld,%s,%p)\n", hKey, dwIndex, debugstr_a(lpszSubKey), pwLen); - - return RegEnumKeyExA(hKey, dwIndex, lpszSubKey, pwLen, NULL, NULL, NULL, NULL); -} - -/************************************************************************* - * SHEnumKeyExW [SHLWAPI.@] - * - * See SHEnumKeyExA. - */ -LONG WINAPI SHEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpszSubKey, - LPDWORD pwLen) -{ - TRACE("(hkey=%p,%ld,%s,%p)\n", hKey, dwIndex, debugstr_w(lpszSubKey), pwLen); - - return RegEnumKeyExW(hKey, dwIndex, lpszSubKey, pwLen, NULL, NULL, NULL, NULL); -} - -/************************************************************************* - * SHEnumValueA [SHLWAPI.@] - * - * Enumerate values in a registry key. - * - * PARAMS - * hKey [I] Handle to registry key - * dwIndex [I] Index of key to enumerate - * lpszValue [O] Pointer updated with the values name - * pwLen [O] Pointer updated with the values length - * pwType [O] Pointer updated with the values type - * pvData [O] Pointer updated with the values data - * pcbData [O] Pointer updated with the values size - * - * RETURNS - * Success: ERROR_SUCCESS. Output parameters are updated. - * Failure: An error code from RegEnumValueA(). - */ -LONG WINAPI SHEnumValueA(HKEY hKey, DWORD dwIndex, LPSTR lpszValue, - LPDWORD pwLen, LPDWORD pwType, - LPVOID pvData, LPDWORD pcbData) -{ - TRACE("(hkey=%p,%ld,%s,%p,%p,%p,%p)\n", hKey, dwIndex, - debugstr_a(lpszValue), pwLen, pwType, pvData, pcbData); - - return RegEnumValueA(hKey, dwIndex, lpszValue, pwLen, NULL, - pwType, pvData, pcbData); -} - -/************************************************************************* - * SHEnumValueW [SHLWAPI.@] - * - * See SHEnumValueA. - */ -LONG WINAPI SHEnumValueW(HKEY hKey, DWORD dwIndex, LPWSTR lpszValue, - LPDWORD pwLen, LPDWORD pwType, - LPVOID pvData, LPDWORD pcbData) -{ - TRACE("(hkey=%p,%ld,%s,%p,%p,%p,%p)\n", hKey, dwIndex, - debugstr_w(lpszValue), pwLen, pwType, pvData, pcbData); - - return RegEnumValueW(hKey, dwIndex, lpszValue, pwLen, NULL, - pwType, pvData, pcbData); -} - -/************************************************************************* - * @ [SHLWAPI.205] - * - * Get a value from the registry. - * - * PARAMS - * hKey [I] Handle to registry key - * pSubKey [I] Name of sub key containing value to get - * pValue [I] Name of value to get - * pwType [O] Destination for the values type - * pvData [O] Destination for the values data - * pbData [O] Destination for the values size - * - * RETURNS - * Success: ERROR_SUCCESS. Output parameters contain the details read. - * Failure: An error code from RegOpenKeyExA() or SHQueryValueExA(), - * or ERROR_INVALID_FUNCTION in the machine is in safe mode. - */ -DWORD WINAPI SHGetValueGoodBootA(HKEY hkey, LPCSTR pSubKey, LPCSTR pValue, - LPDWORD pwType, LPVOID pvData, LPDWORD pbData) -{ - if (GetSystemMetrics(SM_CLEANBOOT)) - return ERROR_INVALID_FUNCTION; - return SHGetValueA(hkey, pSubKey, pValue, pwType, pvData, pbData); -} - -/************************************************************************* - * @ [SHLWAPI.206] - * - * Unicode version of SHGetValueGoodBootW. - */ -DWORD WINAPI SHGetValueGoodBootW(HKEY hkey, LPCWSTR pSubKey, LPCWSTR pValue, - LPDWORD pwType, LPVOID pvData, LPDWORD pbData) -{ - if (GetSystemMetrics(SM_CLEANBOOT)) - return ERROR_INVALID_FUNCTION; - return SHGetValueW(hkey, pSubKey, pValue, pwType, pvData, pbData); -} - -/************************************************************************* - * @ [SHLWAPI.320] - * - * Set a MIME content type in the registry. - * - * PARAMS - * lpszSubKey [I] Name of key under HKEY_CLASSES_ROOT. - * lpszValue [I] Value to set - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI RegisterMIMETypeForExtensionA(LPCSTR lpszSubKey, LPCSTR lpszValue) -{ - DWORD dwRet; - - if (!lpszValue) - { - WARN("Invalid lpszValue would crash under Win32!\n"); - return FALSE; - } - - dwRet = SHSetValueA(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeA, - REG_SZ, lpszValue, strlen(lpszValue)); - return dwRet ? FALSE : TRUE; -} - -/************************************************************************* - * @ [SHLWAPI.321] - * - * Unicode version of RegisterMIMETypeForExtensionA. - */ -BOOL WINAPI RegisterMIMETypeForExtensionW(LPCWSTR lpszSubKey, LPCWSTR lpszValue) -{ - DWORD dwRet; - - if (!lpszValue) - { - WARN("Invalid lpszValue would crash under Win32!\n"); - return FALSE; - } - - dwRet = SHSetValueW(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeW, - REG_SZ, lpszValue, strlenW(lpszValue)); - return dwRet ? FALSE : TRUE; -} - -/************************************************************************* - * @ [SHLWAPI.322] - * - * Delete a MIME content type from the registry. - * - * PARAMS - * lpszSubKey [I] Name of sub key - * - * RETURNS - * Success: TRUE - * Failure: FALSE - */ -BOOL WINAPI UnregisterMIMETypeForExtensionA(LPCSTR lpszSubKey) -{ - HRESULT ret = SHDeleteValueA(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeA); - return ret ? FALSE : TRUE; -} - -/************************************************************************* - * @ [SHLWAPI.323] - * - * Unicode version of UnregisterMIMETypeForExtensionA. - */ -BOOL WINAPI UnregisterMIMETypeForExtensionW(LPCWSTR lpszSubKey) -{ - HRESULT ret = SHDeleteValueW(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeW); - return ret ? FALSE : TRUE; -} - -/************************************************************************* - * @ [SHLWAPI.328] - * - * Get the registry path to a MIME content key. - * - * PARAMS - * lpszType [I] Content type to get the path for - * lpszBuffer [O] Destination for path - * dwLen [I] Length of lpszBuffer - * - * RETURNS - * Success: TRUE. lpszBuffer contains the full path. - * Failure: FALSE. - * - * NOTES - * The base path for the key is "MIME\Database\Content Type\" - */ -BOOL WINAPI GetMIMETypeSubKeyA(LPCSTR lpszType, LPSTR lpszBuffer, DWORD dwLen) -{ - TRACE("(%s,%p,%ld)\n", debugstr_a(lpszType), lpszBuffer, dwLen); - - if (dwLen > dwLenMimeDbContent && lpszType && lpszBuffer) - { - size_t dwStrLen = strlen(lpszType); - - if (dwStrLen < dwLen - dwLenMimeDbContent) - { - memcpy(lpszBuffer, szMimeDbContentA, dwLenMimeDbContent); - memcpy(lpszBuffer + dwLenMimeDbContent, lpszType, dwStrLen + 1); - return TRUE; - } - } - return FALSE; -} - -/************************************************************************* - * @ [SHLWAPI.329] - * - * Unicode version of GetMIMETypeSubKeyA. - */ -BOOL WINAPI GetMIMETypeSubKeyW(LPCWSTR lpszType, LPWSTR lpszBuffer, DWORD dwLen) -{ - TRACE("(%s,%p,%ld)\n", debugstr_w(lpszType), lpszBuffer, dwLen); - - if (dwLen > dwLenMimeDbContent && lpszType && lpszBuffer) - { - DWORD dwStrLen = strlenW(lpszType); - - if (dwStrLen < dwLen - dwLenMimeDbContent) - { - memcpy(lpszBuffer, szMimeDbContentW, dwLenMimeDbContent * sizeof(WCHAR)); - memcpy(lpszBuffer + dwLenMimeDbContent, lpszType, (dwStrLen + 1) * sizeof(WCHAR)); - return TRUE; - } - } - return FALSE; -} - -/************************************************************************* - * @ [SHLWAPI.330] - * - * Get the file extension for a given Mime type. - * - * PARAMS - * lpszType [I] Mime type to get the file extension for - * lpExt [O] Destination for the resulting extension - * iLen [I] Length of lpExt in characters - * - * RETURNS - * Success: TRUE. lpExt contains the file extension. - * Failure: FALSE, if any parameter is invalid or the extension cannot be - * retrieved. If iLen > 0, lpExt is set to an empty string. - * - * NOTES - * - The extension returned in lpExt always has a leading '.' character, even - * if the registry Mime database entry does not. - * - iLen must be long enough for the file extension for this function to succeed. - */ -BOOL WINAPI MIME_GetExtensionA(LPCSTR lpszType, LPSTR lpExt, INT iLen) -{ - char szSubKey[MAX_PATH]; - DWORD dwlen = iLen - 1, dwType; - BOOL bRet = FALSE; - - if (iLen > 0 && lpExt) - *lpExt = '\0'; - - if (lpszType && lpExt && iLen > 2 && - GetMIMETypeSubKeyA(lpszType, szSubKey, MAX_PATH) && - !SHGetValueA(HKEY_CLASSES_ROOT, szSubKey, szExtensionA, &dwType, lpExt + 1, &dwlen) && - lpExt[1]) - { - if (lpExt[1] == '.') - memmove(lpExt, lpExt + 1, strlen(lpExt + 1) + 1); - else - *lpExt = '.'; /* Supply a '.' */ - bRet = TRUE; - } - return bRet; -} - -/************************************************************************* - * @ [SHLWAPI.331] - * - * Unicode version of MIME_GetExtensionA. - */ -BOOL WINAPI MIME_GetExtensionW(LPCWSTR lpszType, LPWSTR lpExt, INT iLen) -{ - WCHAR szSubKey[MAX_PATH]; - DWORD dwlen = iLen - 1, dwType; - BOOL bRet = FALSE; - - if (iLen > 0 && lpExt) - *lpExt = '\0'; - - if (lpszType && lpExt && iLen > 2 && - GetMIMETypeSubKeyW(lpszType, szSubKey, MAX_PATH) && - !SHGetValueW(HKEY_CLASSES_ROOT, szSubKey, szExtensionW, &dwType, lpExt + 1, &dwlen) && - lpExt[1]) - { - if (lpExt[1] == '.') - memmove(lpExt, lpExt + 1, (strlenW(lpExt + 1) + 1) * sizeof(WCHAR)); - else - *lpExt = '.'; /* Supply a '.' */ - bRet = TRUE; - } - return bRet; -} - -/************************************************************************* - * @ [SHLWAPI.324] - * - * Set the file extension for a MIME content key. - * - * PARAMS - * lpszExt [I] File extension to set - * lpszType [I] Content type to set the extension for - * - * RETURNS - * Success: TRUE. The file extension is set in the registry. - * Failure: FALSE. - */ -BOOL WINAPI RegisterExtensionForMIMETypeA(LPCSTR lpszExt, LPCSTR lpszType) -{ - DWORD dwLen; - char szKey[MAX_PATH]; - - TRACE("(%s,%s)\n", debugstr_a(lpszExt), debugstr_a(lpszType)); - - if (!GetMIMETypeSubKeyA(lpszType, szKey, MAX_PATH)) /* Get full path to the key */ - return FALSE; - - dwLen = strlen(lpszExt) + 1; - - if (SHSetValueA(HKEY_CLASSES_ROOT, szKey, szExtensionA, REG_SZ, lpszExt, dwLen)) - return FALSE; - return TRUE; -} - -/************************************************************************* - * @ [SHLWAPI.325] - * - * Unicode version of RegisterExtensionForMIMETypeA. - */ -BOOL WINAPI RegisterExtensionForMIMETypeW(LPCWSTR lpszExt, LPCWSTR lpszType) -{ - DWORD dwLen; - WCHAR szKey[MAX_PATH]; - - TRACE("(%s,%s)\n", debugstr_w(lpszExt), debugstr_w(lpszType)); - - /* Get the full path to the key */ - if (!GetMIMETypeSubKeyW(lpszType, szKey, MAX_PATH)) /* Get full path to the key */ - return FALSE; - - dwLen = (lstrlenW(lpszExt) + 1) * sizeof(WCHAR); - - if (SHSetValueW(HKEY_CLASSES_ROOT, szKey, szExtensionW, REG_SZ, lpszExt, dwLen)) - return FALSE; - return TRUE; -} - -/************************************************************************* - * @ [SHLWAPI.326] - * - * Delete a file extension from a MIME content type. - * - * PARAMS - * lpszType [I] Content type to delete the extension for - * - * RETURNS - * Success: TRUE. The file extension is deleted from the registry. - * Failure: FALSE. The extension may have been removed but the key remains. - * - * NOTES - * If deleting the extension leaves an orphan key, the key is removed also. - */ -BOOL WINAPI UnregisterExtensionForMIMETypeA(LPCSTR lpszType) -{ - char szKey[MAX_PATH]; - - TRACE("(%s)\n", debugstr_a(lpszType)); - - if (!GetMIMETypeSubKeyA(lpszType, szKey, MAX_PATH)) /* Get full path to the key */ - return FALSE; - - if (!SHDeleteValueA(HKEY_CLASSES_ROOT, szKey, szExtensionA)) - return FALSE; - - if (!SHDeleteOrphanKeyA(HKEY_CLASSES_ROOT, szKey)) - return FALSE; - return TRUE; -} - -/************************************************************************* - * @ [SHLWAPI.327] - * - * Unicode version of UnregisterExtensionForMIMETypeA. - */ -BOOL WINAPI UnregisterExtensionForMIMETypeW(LPCWSTR lpszType) -{ - WCHAR szKey[MAX_PATH]; - - TRACE("(%s)\n", debugstr_w(lpszType)); - - if (!GetMIMETypeSubKeyW(lpszType, szKey, MAX_PATH)) /* Get full path to the key */ - return FALSE; - - if (!SHDeleteValueW(HKEY_CLASSES_ROOT, szKey, szExtensionW)) - return FALSE; - - if (!SHDeleteOrphanKeyW(HKEY_CLASSES_ROOT, szKey)) - return FALSE; - return TRUE; -} - -/************************************************************************* - * SHRegDuplicateHKey [SHLWAPI.@] - * - * Create a duplicate of a registry handle. - * - * PARAMS - * hKey [I] key to duplicate. - * - * RETURNS - * A new handle pointing to the same key as hKey. - */ -HKEY WINAPI SHRegDuplicateHKey(HKEY hKey) -{ - HKEY newKey = 0; - - RegOpenKeyExA(hKey, 0, 0, MAXIMUM_ALLOWED, &newKey); - TRACE("new key is %p\n", newKey); - return newKey; -} - - -/************************************************************************* - * SHCopyKeyA [SHLWAPI.@] - * - * Copy a key and its values/sub keys to another location. - * - * PARAMS - * hKeySrc [I] Source key to copy from - * lpszSrcSubKey [I] Sub key under hKeySrc, or NULL to use hKeySrc directly - * hKeyDst [I] Destination key - * dwReserved [I] Reserved, must be 0 - * - * RETURNS - * Success: ERROR_SUCCESS. The key is copied to the destination key. - * Failure: A standard windows error code. - * - * NOTES - * If hKeyDst is a key under hKeySrc, this function will misbehave - * (It will loop until out of stack, or the registry is full). This - * bug is present in Win32 also. - */ -DWORD WINAPI SHCopyKeyA(HKEY hKeySrc, LPCSTR lpszSrcSubKey, HKEY hKeyDst, DWORD dwReserved) -{ - WCHAR szSubKeyW[MAX_PATH]; - - TRACE("(hkey=%p,%s,%p08x,%ld)\n", hKeySrc, debugstr_a(lpszSrcSubKey), hKeyDst, dwReserved); - - if (lpszSrcSubKey) - MultiByteToWideChar(0, 0, lpszSrcSubKey, -1, szSubKeyW, MAX_PATH); - - return SHCopyKeyW(hKeySrc, lpszSrcSubKey ? szSubKeyW : NULL, hKeyDst, dwReserved); -} - -/************************************************************************* - * SHCopyKeyW [SHLWAPI.@] - * - * See SHCopyKeyA. - */ -DWORD WINAPI SHCopyKeyW(HKEY hKeySrc, LPCWSTR lpszSrcSubKey, HKEY hKeyDst, DWORD dwReserved) -{ - DWORD dwKeyCount = 0, dwValueCount = 0, dwMaxKeyLen = 0; - DWORD dwMaxValueLen = 0, dwMaxDataLen = 0, i; - BYTE buff[1024]; - LPVOID lpBuff = (LPVOID)buff; - WCHAR szName[MAX_PATH], *lpszName = szName; - DWORD dwRet = S_OK; - - TRACE("hkey=%p,%s,%p08x,%ld)\n", hKeySrc, debugstr_w(lpszSrcSubKey), hKeyDst, dwReserved); - - if(!hKeyDst || !hKeySrc) - dwRet = ERROR_INVALID_PARAMETER; - else - { - /* Open source key */ - if(lpszSrcSubKey) - dwRet = RegOpenKeyExW(hKeySrc, lpszSrcSubKey, 0, KEY_ALL_ACCESS, &hKeySrc); - - if(dwRet) - hKeyDst = NULL; /* Don't close this key since we didn't open it */ - else - { - /* Get details about sub keys and values */ - dwRet = RegQueryInfoKeyW(hKeySrc, NULL, NULL, NULL, &dwKeyCount, &dwMaxKeyLen, - NULL, &dwValueCount, &dwMaxValueLen, &dwMaxDataLen, - NULL, NULL); - if(!dwRet) - { - if (dwMaxValueLen > dwMaxKeyLen) - dwMaxKeyLen = dwMaxValueLen; /* Get max size for key/value names */ - - if (dwMaxKeyLen++ > MAX_PATH - 1) - lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxKeyLen * sizeof(WCHAR)); - - if (dwMaxDataLen > sizeof(buff)) - lpBuff = HeapAlloc(GetProcessHeap(), 0, dwMaxDataLen); - - if (!lpszName || !lpBuff) - dwRet = ERROR_NOT_ENOUGH_MEMORY; - } - } - } - - /* Copy all the sub keys */ - for(i = 0; i < dwKeyCount && !dwRet; i++) - { - HKEY hSubKeySrc, hSubKeyDst; - DWORD dwSize = dwMaxKeyLen; - - dwRet = RegEnumKeyExW(hKeySrc, i, lpszName, &dwSize, NULL, NULL, NULL, NULL); - - if(!dwRet) - { - /* Open source sub key */ - dwRet = RegOpenKeyExW(hKeySrc, lpszName, 0, KEY_READ, &hSubKeySrc); - - if(!dwRet) - { - /* Create destination sub key */ - dwRet = RegCreateKeyW(hKeyDst, lpszName, &hSubKeyDst); - - if(!dwRet) - { - /* Recursively copy keys and values from the sub key */ - dwRet = SHCopyKeyW(hSubKeySrc, NULL, hSubKeyDst, 0); - RegCloseKey(hSubKeyDst); - } - } - RegCloseKey(hSubKeySrc); - } - } - - /* Copy all the values in this key */ - for (i = 0; i < dwValueCount && !dwRet; i++) - { - DWORD dwNameSize = dwMaxKeyLen, dwType, dwLen = dwMaxDataLen; - - dwRet = RegEnumValueW(hKeySrc, i, lpszName, &dwNameSize, NULL, &dwType, buff, &dwLen); - - if (!dwRet) - dwRet = SHSetValueW(hKeyDst, NULL, lpszName, dwType, lpBuff, dwLen); - } - - /* Free buffers if allocated */ - if (lpszName != szName) - HeapFree(GetProcessHeap(), 0, lpszName); - if (lpBuff != buff) - HeapFree(GetProcessHeap(), 0, lpBuff); - - if (lpszSrcSubKey && hKeyDst) - RegCloseKey(hKeyDst); - return dwRet; -} - -/* - * The following functions are ORDINAL ONLY: - */ - -/************************************************************************* - * @ [SHLWAPI.280] - * - * Read an integer value from the registry, falling back to a default. - * - * PARAMS - * hKey [I] Registry key to read from - * lpszValue [I] Value name to read - * iDefault [I] Default value to return - * - * RETURNS - * The value contained in the given registry value if present, otherwise - * iDefault. - */ -int WINAPI SHRegGetIntW(HKEY hKey, LPCWSTR lpszValue, int iDefault) -{ - TRACE("(%p,%s,%d)\n", hKey, debugstr_w(lpszValue), iDefault); - - if (hKey) - { - WCHAR szBuff[32]; - DWORD dwSize = sizeof(szBuff); - szBuff[0] = '\0'; - SHQueryValueExW(hKey, lpszValue, 0, 0, szBuff, &dwSize); - - if(*szBuff >= '0' && *szBuff <= '9') - return StrToIntW(szBuff); - } - return iDefault; -} - -/************************************************************************* - * @ [SHLWAPI.343] - * - * Create or open an explorer ClassId Key. - * - * PARAMS - * guid [I] Explorer ClassId key to open - * lpszValue [I] Value name under the ClassId Key - * bUseHKCU [I] TRUE=Use HKEY_CURRENT_USER, FALSE=Use HKEY_CLASSES_ROOT - * bCreate [I] TRUE=Create the key if it doesn't exist, FALSE=Don't - * phKey [O] Destination for the resulting key handle - * - * RETURNS - * Success: S_OK. phKey contains the resulting registry handle. - * Failure: An HRESULT error code indicating the problem. - */ -HRESULT WINAPI SHRegGetCLSIDKeyA(REFGUID guid, LPCSTR lpszValue, BOOL bUseHKCU, BOOL bCreate, PHKEY phKey) -{ - WCHAR szValue[MAX_PATH]; - - if (lpszValue) - MultiByteToWideChar(CP_ACP, 0, lpszValue, -1, szValue, sizeof(szValue)/sizeof(WCHAR)); - - return SHRegGetCLSIDKeyW(guid, lpszValue ? szValue : NULL, bUseHKCU, bCreate, phKey); -} - -/************************************************************************* - * @ [SHLWAPI.344] - * - * Unicode version of SHRegGetCLSIDKeyA. - */ -HRESULT WINAPI SHRegGetCLSIDKeyW(REFGUID guid, LPCWSTR lpszValue, BOOL bUseHKCU, - BOOL bCreate, PHKEY phKey) -{ - static const WCHAR szClassIdKey[] = { 'S','o','f','t','w','a','r','e','\\', - 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\', - 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', - 'E','x','p','l','o','r','e','r','\\','C','L','S','I','D','\\' }; -#define szClassIdKeyLen (sizeof(szClassIdKey)/sizeof(WCHAR)) - WCHAR szKey[MAX_PATH]; - DWORD dwRet; - HKEY hkey; - - /* Create the key string */ - memcpy(szKey, szClassIdKey, sizeof(szClassIdKey)); - SHStringFromGUIDW(guid, szKey + szClassIdKeyLen, 39); /* Append guid */ - - if(lpszValue) - { - szKey[szClassIdKeyLen + 39] = '\\'; - strcpyW(szKey + szClassIdKeyLen + 40, lpszValue); /* Append value name */ - } - - hkey = bUseHKCU ? HKEY_CURRENT_USER : HKEY_CLASSES_ROOT; - - if(bCreate) - dwRet = RegCreateKeyW(hkey, szKey, phKey); - else - dwRet = RegOpenKeyExW(hkey, szKey, 0, KEY_READ, phKey); - - return dwRet ? HRESULT_FROM_WIN32(dwRet) : S_OK; -} - -/************************************************************************* - * SHRegisterValidateTemplate [SHLWAPI.@] - * - * observed from the ie 5.5 installer: - * - allocates a buffer with the size of the given file - * - read the file content into the buffer - * - creates the key szTemplateKey - * - sets "205523652929647911071668590831910975402"=dword:00002e37 at - * the key - * - * PARAMS - * filename [I] An existing file its content is read into an allocated - * buffer - * unknown [I] - * - * RETURNS - * Success: ERROR_SUCCESS. - */ -HRESULT WINAPI SHRegisterValidateTemplate(LPCWSTR filename, BOOL unknown) -{ -/* static const WCHAR szTemplateKey[] = { 'S','o','f','t','w','a','r','e','\\', - * 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\', - * 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', - * 'E','x','p','l','o','r','e','r','\\', - * 'T','e','m','p','l','a','t','e','R','e','g','i','s','t','r','y',0 }; - */ - FIXME("stub: %s, %08x\n", debugstr_w(filename), unknown); - - return S_OK; -} +/* + * SHLWAPI registry functions + * + * Copyright 1998 Juergen Schmied + * Copyright 2001 Guy Albertelli + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> +#include <string.h> +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "winreg.h" +#include "wine/debug.h" +#define NO_SHLWAPI_STREAM +#include "shlwapi.h" +#include "wine/unicode.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/* Key/Value names for MIME content types */ +static const char *lpszContentTypeA = "Content Type"; +static const WCHAR lpszContentTypeW[] = { 'C','o','n','t','e','n','t',' ','T','y','p','e','\0'}; + +static const char *szMimeDbContentA = "MIME\\Database\\Content Type\\"; +static const WCHAR szMimeDbContentW[] = { 'M', 'I', 'M','E','\\', + 'D','a','t','a','b','a','s','e','\\','C','o','n','t','e','n','t', + ' ','T','y','p','e','\\', 0 }; +static const DWORD dwLenMimeDbContent = 27; /* strlen of szMimeDbContentA/W */ + +static const char *szExtensionA = "Extension"; +static const WCHAR szExtensionW[] = { 'E', 'x', 't','e','n','s','i','o','n','\0' }; + +/* internal structure of what the HUSKEY points to */ +typedef struct { + HKEY HKCUstart; /* Start key in CU hive */ + HKEY HKCUkey; /* Opened key in CU hive */ + HKEY HKLMstart; /* Start key in LM hive */ + HKEY HKLMkey; /* Opened key in LM hive */ + WCHAR lpszPath[MAX_PATH]; +} SHUSKEY, *LPSHUSKEY; + +DWORD WINAPI SHStringFromGUIDW(REFGUID,LPWSTR,INT); +HRESULT WINAPI SHRegGetCLSIDKeyW(REFGUID,LPCWSTR,BOOL,BOOL,PHKEY); + + +#define REG_HKCU TRUE +#define REG_HKLM FALSE +/************************************************************************* + * REG_GetHKEYFromHUSKEY + * + * Function: Return the proper registry key from the HUSKEY structure + * also allow special predefined values. + */ +static HKEY WINAPI REG_GetHKEYFromHUSKEY(HUSKEY hUSKey, BOOL which) +{ + HKEY test = (HKEY) hUSKey; + LPSHUSKEY mihk = (LPSHUSKEY) hUSKey; + + if ((test == HKEY_CLASSES_ROOT) || + (test == HKEY_CURRENT_CONFIG) || + (test == HKEY_CURRENT_USER) || + (test == HKEY_DYN_DATA) || + (test == HKEY_LOCAL_MACHINE) || + (test == HKEY_PERFORMANCE_DATA) || +/* FIXME: need to define for Win2k, ME, XP + * (test == HKEY_PERFORMANCE_TEXT) || + * (test == HKEY_PERFORMANCE_NLSTEXT) || + */ + (test == HKEY_USERS)) return test; + if (which == REG_HKCU) return mihk->HKCUkey; + return mihk->HKLMkey; +} + + +/************************************************************************* + * SHRegOpenUSKeyA [SHLWAPI.@] + * + * Open a user-specific registry key. + * + * PARAMS + * Path [I] Key name to open + * AccessType [I] Access type + * hRelativeUSKey [I] Relative user key + * phNewUSKey [O] Destination for created key + * fIgnoreHKCU [I] TRUE=Don't check HKEY_CURRENT_USER + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: An error code from RegOpenKeyExA(). + */ +LONG WINAPI SHRegOpenUSKeyA(LPCSTR Path, REGSAM AccessType, HUSKEY hRelativeUSKey, + PHUSKEY phNewUSKey, BOOL fIgnoreHKCU) +{ + WCHAR szPath[MAX_PATH]; + + if (Path) + MultiByteToWideChar(CP_ACP, 0, Path, -1, szPath, MAX_PATH); + + return SHRegOpenUSKeyW(Path ? szPath : NULL, AccessType, hRelativeUSKey, + phNewUSKey, fIgnoreHKCU); +} + +/************************************************************************* + * SHRegOpenUSKeyW [SHLWAPI.@] + * + * See SHRegOpenUSKeyA. + */ +LONG WINAPI SHRegOpenUSKeyW(LPCWSTR Path, REGSAM AccessType, HUSKEY hRelativeUSKey, + PHUSKEY phNewUSKey, BOOL fIgnoreHKCU) +{ + LONG ret2, ret1 = ~ERROR_SUCCESS; + LPSHUSKEY hKey; + + TRACE("(%s,0x%lx,%p,%p,%d)\n", debugstr_w(Path),(LONG)AccessType, + hRelativeUSKey, phNewUSKey, fIgnoreHKCU); + + if (phNewUSKey) + *phNewUSKey = NULL; + + /* Create internal HUSKEY */ + hKey = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*hKey)); + lstrcpynW(hKey->lpszPath, Path, sizeof(hKey->lpszPath)); + + if (hRelativeUSKey) + { + hKey->HKCUstart = SHRegDuplicateHKey(REG_GetHKEYFromHUSKEY(hRelativeUSKey, REG_HKCU)); + hKey->HKLMstart = SHRegDuplicateHKey(REG_GetHKEYFromHUSKEY(hRelativeUSKey, REG_HKLM)); + + /* FIXME: if either of these keys is NULL, create the start key from + * the relative keys start+path + */ + } + else + { + hKey->HKCUstart = HKEY_CURRENT_USER; + hKey->HKLMstart = HKEY_LOCAL_MACHINE; + } + + if (!fIgnoreHKCU) + { + ret1 = RegOpenKeyExW(hKey->HKCUstart, hKey->lpszPath, 0, AccessType, &hKey->HKCUkey); + if (ret1) + hKey->HKCUkey = 0; + } + + ret2 = RegOpenKeyExW(hKey->HKLMstart, hKey->lpszPath, 0, AccessType, &hKey->HKLMkey); + if (ret2) + hKey->HKLMkey = 0; + + if (ret1 || ret2) + TRACE("one or more opens failed: HKCU=%ld HKLM=%ld\n", ret1, ret2); + + if (ret1 && ret2) + { + /* Neither open succeeded: fail */ + SHRegCloseUSKey(hKey); + return ret2; + } + + TRACE("HUSKEY=%p\n", hKey); + if (phNewUSKey) + *phNewUSKey = (HUSKEY)hKey; + return ERROR_SUCCESS; +} + +/************************************************************************* + * SHRegCloseUSKey [SHLWAPI.@] + * + * Close a user-specific registry key + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: An error code from RegCloseKey(). + */ +LONG WINAPI SHRegCloseUSKey( + HUSKEY hUSKey) /* [I] Key to close */ +{ + LPSHUSKEY hKey = (LPSHUSKEY)hUSKey; + LONG ret = ERROR_SUCCESS; + + if (hKey->HKCUkey) + ret = RegCloseKey(hKey->HKCUkey); + if (hKey->HKCUstart && hKey->HKCUstart != HKEY_CURRENT_USER) + ret = RegCloseKey(hKey->HKCUstart); + if (hKey->HKLMkey) + ret = RegCloseKey(hKey->HKLMkey); + if (hKey->HKLMstart && hKey->HKLMstart != HKEY_LOCAL_MACHINE) + ret = RegCloseKey(hKey->HKCUstart); + + HeapFree(GetProcessHeap(), 0, hKey); + return ret; +} + +/************************************************************************* + * SHRegCreateUSKeyA [SHLWAPI.@] + * + * Create or open a user-specific registry key. + * + * PARAMS + * pszPath [I] Key name to create or open. + * samDesired [I] Wanted security access. + * hRelativeUSKey [I] Base path if pszPath is relative. NULL otherwise. + * phNewUSKey [O] Receives a handle to the new or openened key. + * dwFlags [I] Base key under which the key should be opened. + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: Nonzero error code from winerror.h + */ +LONG WINAPI SHRegCreateUSKeyA(LPCSTR pszPath, REGSAM samDesired, HUSKEY hRelativeUSKey, + PHUSKEY phNewUSKey, DWORD dwFlags) +{ + FIXME("(%s, 0x%08lx, %p, %p, 0x%08lx) stub\n", debugstr_a(pszPath), samDesired, + hRelativeUSKey, phNewUSKey, dwFlags); + return ERROR_SUCCESS; +} + +/************************************************************************* + * SHRegCreateUSKeyW [SHLWAPI.@] + * + * See SHRegCreateUSKeyA. + */ +LONG WINAPI SHRegCreateUSKeyW(LPCWSTR pszPath, REGSAM samDesired, HUSKEY hRelativeUSKey, + PHUSKEY phNewUSKey, DWORD dwFlags) +{ + FIXME("(%s, 0x%08lx, %p, %p, 0x%08lx) stub\n", debugstr_w(pszPath), samDesired, + hRelativeUSKey, phNewUSKey, dwFlags); + return ERROR_SUCCESS; +} + +/************************************************************************* + * SHRegDeleteEmptyUSKeyA [SHLWAPI.@] + * + * Delete an empty user-specific registry key. + * + * PARAMS + * hUSKey [I] Handle to an open registry key. + * pszValue [I] Empty key name. + * delRegFlags [I] Flag that specifies the base from which to delete + * the key. + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: Nonzero error code from winerror.h + */ +LONG WINAPI SHRegDeleteEmptyUSKeyA(HUSKEY hUSKey, LPCSTR pszValue, SHREGDEL_FLAGS delRegFlags) +{ + FIXME("(%p, %s, 0x%08x) stub\n", hUSKey, debugstr_a(pszValue), delRegFlags); + return ERROR_SUCCESS; +} + +/************************************************************************* + * SHRegDeleteEmptyUSKeyW [SHLWAPI.@] + * + * See SHRegDeleteEmptyUSKeyA. + */ +LONG WINAPI SHRegDeleteEmptyUSKeyW(HUSKEY hUSKey, LPCWSTR pszValue, SHREGDEL_FLAGS delRegFlags) +{ + FIXME("(%p, %s, 0x%08x) stub\n", hUSKey, debugstr_w(pszValue), delRegFlags); + return ERROR_SUCCESS; +} + +/************************************************************************* + * SHRegDeleteUSValueA [SHLWAPI.@] + * + * Delete a user-specific registry value. + * + * PARAMS + * hUSKey [I] Handle to an open registry key. + * pszValue [I] Specifies the value to delete. + * delRegFlags [I] Flag that specifies the base of the key from which to + * delete the value. + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: Nonzero error code from winerror.h + */ +LONG WINAPI SHRegDeleteUSValueA(HUSKEY hUSKey, LPCSTR pszValue, SHREGDEL_FLAGS delRegFlags) +{ + FIXME("(%p, %s, 0x%08x) stub\n", hUSKey, debugstr_a(pszValue), delRegFlags); + return ERROR_SUCCESS; +} + +/************************************************************************* + * SHRegDeleteUSValueW [SHLWAPI.@] + * + * See SHRegDeleteUSValueA. + */ +LONG WINAPI SHRegDeleteUSValueW(HUSKEY hUSKey, LPCWSTR pszValue, SHREGDEL_FLAGS delRegFlags) +{ + FIXME("(%p, %s, 0x%08x) stub\n", hUSKey, debugstr_w(pszValue), delRegFlags); + return ERROR_SUCCESS; +} + +/************************************************************************* + * SHRegEnumUSValueA [SHLWAPI.@] + * + * Enumerate values of a specified registry key. + * + * PARAMS + * hUSKey [I] Handle to an open registry key. + * dwIndex [I] Index of the value to be retrieved. + * pszValueName [O] Buffer to receive the value name. + * pcchValueNameLen [I] Size of pszValueName in characters. + * pdwType [O] Receives data type of the value. + * pvData [O] Receives value data. May be NULL. + * pcbData [I/O] Size of pvData in bytes. + * enumRegFlags [I] Flag that specifies the base key under which to + * enumerate values. + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: Nonzero error code from winerror.h + */ +LONG WINAPI SHRegEnumUSValueA(HUSKEY hUSKey, DWORD dwIndex, LPSTR pszValueName, + LPDWORD pcchValueNameLen, LPDWORD pdwType, LPVOID pvData, + LPDWORD pcbData, SHREGENUM_FLAGS enumRegFlags) +{ + FIXME("(%p, 0x%08lx, %s, %p, %p, %p, %p, 0x%08x) stub\n", hUSKey, dwIndex, + debugstr_a(pszValueName), pcchValueNameLen, pdwType, pvData, pcbData, enumRegFlags); + return ERROR_INVALID_FUNCTION; +} + +/************************************************************************* + * SHRegEnumUSValueW [SHLWAPI.@] + * + * See SHRegEnumUSValueA. + */ +LONG WINAPI SHRegEnumUSValueW(HUSKEY hUSKey, DWORD dwIndex, LPWSTR pszValueName, + LPDWORD pcchValueNameLen, LPDWORD pdwType, LPVOID pvData, + LPDWORD pcbData, SHREGENUM_FLAGS enumRegFlags) +{ + FIXME("(%p, 0x%08lx, %s, %p, %p, %p, %p, 0x%08x) stub\n", hUSKey, dwIndex, + debugstr_w(pszValueName), pcchValueNameLen, pdwType, pvData, pcbData, enumRegFlags); + return ERROR_INVALID_FUNCTION; +} + +/************************************************************************* + * SHRegQueryUSValueA [SHLWAPI.@] + * + * Query a user-specific registry value. + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: An error code from RegQueryValueExA(). + */ +LONG WINAPI SHRegQueryUSValueA( + HUSKEY hUSKey, /* [I] Key to query */ + LPCSTR pszValue, /* [I] Value name under hUSKey */ + LPDWORD pdwType, /* [O] Destination for value type */ + LPVOID pvData, /* [O] Destination for value data */ + LPDWORD pcbData, /* [O] Destination for value length */ + BOOL fIgnoreHKCU, /* [I] TRUE=Don't check HKEY_CURRENT_USER */ + LPVOID pvDefaultData, /* [I] Default data if pszValue does not exist */ + DWORD dwDefaultDataSize) /* [I] Length of pvDefaultData */ +{ + LONG ret = ~ERROR_SUCCESS; + LONG i, maxmove; + HKEY dokey; + CHAR *src, *dst; + + /* if user wants HKCU, and it exists, then try it */ + if (!fIgnoreHKCU && (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) { + ret = RegQueryValueExA(dokey, + pszValue, 0, pdwType, pvData, pcbData); + TRACE("HKCU RegQueryValue returned %08lx\n", ret); + } + + /* if HKCU did not work and HKLM exists, then try it */ + if ((ret != ERROR_SUCCESS) && + (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) { + ret = RegQueryValueExA(dokey, + pszValue, 0, pdwType, pvData, pcbData); + TRACE("HKLM RegQueryValue returned %08lx\n", ret); + } + + /* if neither worked, and default data exists, then use it */ + if (ret != ERROR_SUCCESS) { + if (pvDefaultData && (dwDefaultDataSize != 0)) { + maxmove = (dwDefaultDataSize >= *pcbData) ? *pcbData : dwDefaultDataSize; + src = (CHAR*)pvDefaultData; + dst = (CHAR*)pvData; + for(i=0; i<maxmove; i++) *dst++ = *src++; + *pcbData = maxmove; + TRACE("setting default data\n"); + ret = ERROR_SUCCESS; + } + } + return ret; +} + + +/************************************************************************* + * SHRegQueryUSValueW [SHLWAPI.@] + * + * See SHRegQueryUSValueA. + */ +LONG WINAPI SHRegQueryUSValueW( + HUSKEY hUSKey, + LPCWSTR pszValue, + LPDWORD pdwType, + LPVOID pvData, + LPDWORD pcbData, + BOOL fIgnoreHKCU, + LPVOID pvDefaultData, + DWORD dwDefaultDataSize) +{ + LONG ret = ~ERROR_SUCCESS; + LONG i, maxmove; + HKEY dokey; + CHAR *src, *dst; + + /* if user wants HKCU, and it exists, then try it */ + if (!fIgnoreHKCU && (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) { + ret = RegQueryValueExW(dokey, + pszValue, 0, pdwType, pvData, pcbData); + TRACE("HKCU RegQueryValue returned %08lx\n", ret); + } + + /* if HKCU did not work and HKLM exists, then try it */ + if ((ret != ERROR_SUCCESS) && + (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) { + ret = RegQueryValueExW(dokey, + pszValue, 0, pdwType, pvData, pcbData); + TRACE("HKLM RegQueryValue returned %08lx\n", ret); + } + + /* if neither worked, and default data exists, then use it */ + if (ret != ERROR_SUCCESS) { + if (pvDefaultData && (dwDefaultDataSize != 0)) { + maxmove = (dwDefaultDataSize >= *pcbData) ? *pcbData : dwDefaultDataSize; + src = (CHAR*)pvDefaultData; + dst = (CHAR*)pvData; + for(i=0; i<maxmove; i++) *dst++ = *src++; + *pcbData = maxmove; + TRACE("setting default data\n"); + ret = ERROR_SUCCESS; + } + } + return ret; +} + +/************************************************************************* + * SHRegGetUSValueA [SHLWAPI.@] + * + * Get a user-specific registry value. + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: An error code from SHRegOpenUSKeyA() or SHRegQueryUSValueA(). + * + * NOTES + * This function opens pSubKey, queries the value, and then closes the key. + */ +LONG WINAPI SHRegGetUSValueA( + LPCSTR pSubKey, /* [I] Key name to open */ + LPCSTR pValue, /* [I] Value name to open */ + LPDWORD pwType, /* [O] Destination for the type of the value */ + LPVOID pvData, /* [O] Destination for the value */ + LPDWORD pcbData, /* [I] Destination for the length of the value **/ + BOOL flagIgnoreHKCU, /* [I] TRUE=Don't check HKEY_CURRENT_USER */ + LPVOID pDefaultData, /* [I] Default value if it doesn't exist */ + DWORD wDefaultDataSize) /* [I] Length of pDefaultData */ +{ + HUSKEY myhuskey; + LONG ret; + + if (!pvData || !pcbData) return ERROR_INVALID_FUNCTION; /* FIXME:wrong*/ + TRACE("key '%s', value '%s', datalen %ld, %s\n", + debugstr_a(pSubKey), debugstr_a(pValue), *pcbData, + (flagIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM"); + + ret = SHRegOpenUSKeyA(pSubKey, 0x1, 0, &myhuskey, flagIgnoreHKCU); + if (ret == ERROR_SUCCESS) { + ret = SHRegQueryUSValueA(myhuskey, pValue, pwType, pvData, + pcbData, flagIgnoreHKCU, pDefaultData, + wDefaultDataSize); + SHRegCloseUSKey(myhuskey); + } + return ret; +} + +/************************************************************************* + * SHRegGetUSValueW [SHLWAPI.@] + * + * See SHRegGetUSValueA. + */ +LONG WINAPI SHRegGetUSValueW( + LPCWSTR pSubKey, + LPCWSTR pValue, + LPDWORD pwType, + LPVOID pvData, + LPDWORD pcbData, + BOOL flagIgnoreHKCU, + LPVOID pDefaultData, + DWORD wDefaultDataSize) +{ + HUSKEY myhuskey; + LONG ret; + + if (!pvData || !pcbData) return ERROR_INVALID_FUNCTION; /* FIXME:wrong*/ + TRACE("key '%s', value '%s', datalen %ld, %s\n", + debugstr_w(pSubKey), debugstr_w(pValue), *pcbData, + (flagIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM"); + + ret = SHRegOpenUSKeyW(pSubKey, 0x1, 0, &myhuskey, flagIgnoreHKCU); + if (ret == ERROR_SUCCESS) { + ret = SHRegQueryUSValueW(myhuskey, pValue, pwType, pvData, + pcbData, flagIgnoreHKCU, pDefaultData, + wDefaultDataSize); + SHRegCloseUSKey(myhuskey); + } + return ret; +} + +/************************************************************************* + * SHRegSetUSValueA [SHLWAPI.@] + * + * Set a user-specific registry value. + * + * PARAMS + * pszSubKey [I] Name of key to set the value in + * pszValue [I] Name of value under pszSubKey to set the value in + * dwType [I] Type of the value + * pvData [I] Data to set as the value + * cbData [I] length of pvData + * dwFlags [I] SHREGSET_ flags from "shlwapi.h" + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: An error code from SHRegOpenUSKeyA() or SHRegWriteUSValueA(), or + * ERROR_INVALID_FUNCTION if pvData is NULL. + * + * NOTES + * This function opens pszSubKey, sets the value, and then closes the key. + */ +LONG WINAPI SHRegSetUSValueA(LPCSTR pszSubKey, LPCSTR pszValue, DWORD dwType, + LPVOID pvData, DWORD cbData, DWORD dwFlags) +{ + BOOL ignoreHKCU = TRUE; + HUSKEY hkey; + LONG ret; + + TRACE("(%s,%s,%ld,%p,%ld,0x%08lx\n", debugstr_a(pszSubKey), debugstr_a(pszValue), + dwType, pvData, cbData, dwFlags); + + if (!pvData) + return ERROR_INVALID_FUNCTION; + + if (dwFlags & SHREGSET_HKCU || dwFlags & SHREGSET_FORCE_HKCU) + ignoreHKCU = FALSE; + + ret = SHRegOpenUSKeyA(pszSubKey, KEY_ALL_ACCESS, 0, &hkey, ignoreHKCU); + if (ret == ERROR_SUCCESS) + { + ret = SHRegWriteUSValueA(hkey, pszValue, dwType, pvData, cbData, dwFlags); + SHRegCloseUSKey(hkey); + } + return ret; +} + +/************************************************************************* + * SHRegSetUSValueW [SHLWAPI.@] + * + * See SHRegSetUSValueA. + */ +LONG WINAPI SHRegSetUSValueW(LPCWSTR pszSubKey, LPCWSTR pszValue, DWORD dwType, + LPVOID pvData, DWORD cbData, DWORD dwFlags) +{ + BOOL ignoreHKCU = TRUE; + HUSKEY hkey; + LONG ret; + + TRACE("(%s,%s,%ld,%p,%ld,0x%08lx\n", debugstr_w(pszSubKey), debugstr_w(pszValue), + dwType, pvData, cbData, dwFlags); + + if (!pvData) + return ERROR_INVALID_FUNCTION; + + if (dwFlags & SHREGSET_HKCU || dwFlags & SHREGSET_FORCE_HKCU) + ignoreHKCU = FALSE; + + ret = SHRegOpenUSKeyW(pszSubKey, KEY_ALL_ACCESS, 0, &hkey, ignoreHKCU); + if (ret == ERROR_SUCCESS) + { + ret = SHRegWriteUSValueW(hkey, pszValue, dwType, pvData, cbData, dwFlags); + SHRegCloseUSKey(hkey); + } + return ret; +} + +/************************************************************************* + * SHRegGetBoolUSValueA [SHLWAPI.@] + * + * Get a user-specific registry boolean value. + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: An error code from SHRegOpenUSKeyA() or SHRegQueryUSValueA(). + * + * NOTES + * This function opens pszSubKey, queries the value, and then closes the key. + * + * Boolean values are one of the following: + * True: YES,TRUE,non-zero + * False: NO,FALSE,0 + */ +BOOL WINAPI SHRegGetBoolUSValueA( + LPCSTR pszSubKey, /* [I] Key name to open */ + LPCSTR pszValue, /* [I] Value name to open */ + BOOL fIgnoreHKCU, /* [I] TRUE=Don't check HKEY_CURRENT_USER */ + BOOL fDefault) /* [I] Default value to use if pszValue is not present */ +{ + LONG retvalue; + DWORD type, datalen, work; + BOOL ret = fDefault; + CHAR data[10]; + + TRACE("key '%s', value '%s', %s\n", + debugstr_a(pszSubKey), debugstr_a(pszValue), + (fIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM"); + + datalen = sizeof(data)-1; + if (!(retvalue = SHRegGetUSValueA( pszSubKey, pszValue, &type, + data, &datalen, + fIgnoreHKCU, 0, 0))) { + /* process returned data via type into bool */ + switch (type) { + case REG_SZ: + data[9] = '\0'; /* set end of string */ + if (lstrcmpiA(data, "YES") == 0) ret = TRUE; + if (lstrcmpiA(data, "TRUE") == 0) ret = TRUE; + if (lstrcmpiA(data, "NO") == 0) ret = FALSE; + if (lstrcmpiA(data, "FALSE") == 0) ret = FALSE; + break; + case REG_DWORD: + work = *(LPDWORD)data; + ret = (work != 0); + break; + case REG_BINARY: + if (datalen == 1) { + ret = (data[0] != '\0'); + break; + } + default: + FIXME("Unsupported registry data type %ld\n", type); + ret = FALSE; + } + TRACE("got value (type=%ld), returing <%s>\n", type, + (ret) ? "TRUE" : "FALSE"); + } + else { + ret = fDefault; + TRACE("returning default data <%s>\n", + (ret) ? "TRUE" : "FALSE"); + } + return ret; +} + +/************************************************************************* + * SHRegGetBoolUSValueW [SHLWAPI.@] + * + * See SHRegGetBoolUSValueA. + */ +BOOL WINAPI SHRegGetBoolUSValueW( + LPCWSTR pszSubKey, + LPCWSTR pszValue, + BOOL fIgnoreHKCU, + BOOL fDefault) +{ + static const WCHAR wYES[]= {'Y','E','S','\0'}; + static const WCHAR wTRUE[]= {'T','R','U','E','\0'}; + static const WCHAR wNO[]= {'N','O','\0'}; + static const WCHAR wFALSE[]={'F','A','L','S','E','\0'}; + LONG retvalue; + DWORD type, datalen, work; + BOOL ret = fDefault; + WCHAR data[10]; + + TRACE("key '%s', value '%s', %s\n", + debugstr_w(pszSubKey), debugstr_w(pszValue), + (fIgnoreHKCU) ? "Ignoring HKCU" : "Tries HKCU then HKLM"); + + datalen = (sizeof(data)-1) * sizeof(WCHAR); + if (!(retvalue = SHRegGetUSValueW( pszSubKey, pszValue, &type, + data, &datalen, + fIgnoreHKCU, 0, 0))) { + /* process returned data via type into bool */ + switch (type) { + case REG_SZ: + data[9] = L'\0'; /* set end of string */ + if (lstrcmpiW(data, wYES)==0 || lstrcmpiW(data, wTRUE)==0) + ret = TRUE; + else if (lstrcmpiW(data, wNO)==0 || lstrcmpiW(data, wFALSE)==0) + ret = FALSE; + break; + case REG_DWORD: + work = *(LPDWORD)data; + ret = (work != 0); + break; + case REG_BINARY: + if (datalen == 1) { + ret = (data[0] != L'\0'); + break; + } + default: + FIXME("Unsupported registry data type %ld\n", type); + ret = FALSE; + } + TRACE("got value (type=%ld), returing <%s>\n", type, + (ret) ? "TRUE" : "FALSE"); + } + else { + ret = fDefault; + TRACE("returning default data <%s>\n", + (ret) ? "TRUE" : "FALSE"); + } + return ret; +} + +/************************************************************************* + * SHRegQueryInfoUSKeyA [SHLWAPI.@] + * + * Get information about a user-specific registry key. + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: An error code from RegQueryInfoKeyA(). + */ +LONG WINAPI SHRegQueryInfoUSKeyA( + HUSKEY hUSKey, /* [I] Key to query */ + LPDWORD pcSubKeys, /* [O] Destination for number of sub keys */ + LPDWORD pcchMaxSubKeyLen, /* [O] Destination for the length of the biggest sub key name */ + LPDWORD pcValues, /* [O] Destination for number of values */ + LPDWORD pcchMaxValueNameLen,/* [O] Destination for the length of the biggest value */ + SHREGENUM_FLAGS enumRegFlags) /* [in] SHREGENUM_ flags from "shlwapi.h" */ +{ + HKEY dokey; + LONG ret; + + TRACE("(%p,%p,%p,%p,%p,%d)\n", + hUSKey,pcSubKeys,pcchMaxSubKeyLen,pcValues, + pcchMaxValueNameLen,enumRegFlags); + + /* if user wants HKCU, and it exists, then try it */ + if (((enumRegFlags == SHREGENUM_HKCU) || + (enumRegFlags == SHREGENUM_DEFAULT)) && + (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) { + ret = RegQueryInfoKeyA(dokey, 0, 0, 0, + pcSubKeys, pcchMaxSubKeyLen, 0, + pcValues, pcchMaxValueNameLen, 0, 0, 0); + if ((ret == ERROR_SUCCESS) || + (enumRegFlags == SHREGENUM_HKCU)) + return ret; + } + if (((enumRegFlags == SHREGENUM_HKLM) || + (enumRegFlags == SHREGENUM_DEFAULT)) && + (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) { + return RegQueryInfoKeyA(dokey, 0, 0, 0, + pcSubKeys, pcchMaxSubKeyLen, 0, + pcValues, pcchMaxValueNameLen, 0, 0, 0); + } + return ERROR_INVALID_FUNCTION; +} + +/************************************************************************* + * SHRegQueryInfoUSKeyW [SHLWAPI.@] + * + * See SHRegQueryInfoUSKeyA. + */ +LONG WINAPI SHRegQueryInfoUSKeyW( + HUSKEY hUSKey, + LPDWORD pcSubKeys, + LPDWORD pcchMaxSubKeyLen, + LPDWORD pcValues, + LPDWORD pcchMaxValueNameLen, + SHREGENUM_FLAGS enumRegFlags) +{ + HKEY dokey; + LONG ret; + + TRACE("(%p,%p,%p,%p,%p,%d)\n", + hUSKey,pcSubKeys,pcchMaxSubKeyLen,pcValues, + pcchMaxValueNameLen,enumRegFlags); + + /* if user wants HKCU, and it exists, then try it */ + if (((enumRegFlags == SHREGENUM_HKCU) || + (enumRegFlags == SHREGENUM_DEFAULT)) && + (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) { + ret = RegQueryInfoKeyW(dokey, 0, 0, 0, + pcSubKeys, pcchMaxSubKeyLen, 0, + pcValues, pcchMaxValueNameLen, 0, 0, 0); + if ((ret == ERROR_SUCCESS) || + (enumRegFlags == SHREGENUM_HKCU)) + return ret; + } + if (((enumRegFlags == SHREGENUM_HKLM) || + (enumRegFlags == SHREGENUM_DEFAULT)) && + (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) { + return RegQueryInfoKeyW(dokey, 0, 0, 0, + pcSubKeys, pcchMaxSubKeyLen, 0, + pcValues, pcchMaxValueNameLen, 0, 0, 0); + } + return ERROR_INVALID_FUNCTION; +} + +/************************************************************************* + * SHRegEnumUSKeyA [SHLWAPI.@] + * + * Enumerate a user-specific registry key. + * + * RETURNS + * Success: ERROR_SUCCESS + * Failure: An error code from RegEnumKeyExA(). + */ +LONG WINAPI SHRegEnumUSKeyA( + HUSKEY hUSKey, /* [in] Key to enumerate */ + DWORD dwIndex, /* [in] Index within hUSKey */ + LPSTR pszName, /* [out] Name of the enumerated value */ + LPDWORD pcchValueNameLen, /* [in/out] Length of pszName */ + SHREGENUM_FLAGS enumRegFlags) /* [in] SHREGENUM_ flags from "shlwapi.h" */ +{ + HKEY dokey; + + TRACE("(%p,%ld,%p,%p(%ld),%d)\n", + hUSKey, dwIndex, pszName, pcchValueNameLen, + *pcchValueNameLen, enumRegFlags); + + if (((enumRegFlags == SHREGENUM_HKCU) || + (enumRegFlags == SHREGENUM_DEFAULT)) && + (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) { + return RegEnumKeyExA(dokey, dwIndex, pszName, pcchValueNameLen, + 0, 0, 0, 0); + } + + if (((enumRegFlags == SHREGENUM_HKLM) || + (enumRegFlags == SHREGENUM_DEFAULT)) && + (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) { + return RegEnumKeyExA(dokey, dwIndex, pszName, pcchValueNameLen, + 0, 0, 0, 0); + } + FIXME("no support for SHREGENUM_BOTH\n"); + return ERROR_INVALID_FUNCTION; +} + +/************************************************************************* + * SHRegEnumUSKeyW [SHLWAPI.@] + * + * See SHRegEnumUSKeyA. + */ +LONG WINAPI SHRegEnumUSKeyW( + HUSKEY hUSKey, + DWORD dwIndex, + LPWSTR pszName, + LPDWORD pcchValueNameLen, + SHREGENUM_FLAGS enumRegFlags) +{ + HKEY dokey; + + TRACE("(%p,%ld,%p,%p(%ld),%d)\n", + hUSKey, dwIndex, pszName, pcchValueNameLen, + *pcchValueNameLen, enumRegFlags); + + if (((enumRegFlags == SHREGENUM_HKCU) || + (enumRegFlags == SHREGENUM_DEFAULT)) && + (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKCU))) { + return RegEnumKeyExW(dokey, dwIndex, pszName, pcchValueNameLen, + 0, 0, 0, 0); + } + + if (((enumRegFlags == SHREGENUM_HKLM) || + (enumRegFlags == SHREGENUM_DEFAULT)) && + (dokey = REG_GetHKEYFromHUSKEY(hUSKey,REG_HKLM))) { + return RegEnumKeyExW(dokey, dwIndex, pszName, pcchValueNameLen, + 0, 0, 0, 0); + } + FIXME("no support for SHREGENUM_BOTH\n"); + return ERROR_INVALID_FUNCTION; +} + + +/************************************************************************* + * SHRegWriteUSValueA [SHLWAPI.@] + * + * Write a user-specific registry value. + * + * PARAMS + * hUSKey [I] Key to write the value to + * pszValue [I] Name of value under hUSKey to write the value as + * dwType [I] Type of the value + * pvData [I] Data to set as the value + * cbData [I] length of pvData + * dwFlags [I] SHREGSET_ flags from "shlwapi.h" + * + * RETURNS + * Success: ERROR_SUCCESS. + * Failure: ERROR_INVALID_PARAMETER, if any parameter is invalid, otherwise + * an error code from RegSetValueExA(). + * + * NOTES + * dwFlags must have at least SHREGSET_FORCE_HKCU or SHREGSET_FORCE_HKLM set. + */ +LONG WINAPI SHRegWriteUSValueA(HUSKEY hUSKey, LPCSTR pszValue, DWORD dwType, + LPVOID pvData, DWORD cbData, DWORD dwFlags) +{ + WCHAR szValue[MAX_PATH]; + + if (pszValue) + MultiByteToWideChar(CP_ACP, 0, pszValue, -1, szValue, MAX_PATH); + + return SHRegWriteUSValueW(hUSKey, pszValue ? szValue : NULL, dwType, + pvData, cbData, dwFlags); +} + +/************************************************************************* + * SHRegWriteUSValueW [SHLWAPI.@] + * + * See SHRegWriteUSValueA. + */ +LONG WINAPI SHRegWriteUSValueW(HUSKEY hUSKey, LPCWSTR pszValue, DWORD dwType, + LPVOID pvData, DWORD cbData, DWORD dwFlags) +{ + LONG dummy; + LPSHUSKEY hKey = (LPSHUSKEY)hUSKey; + LONG ret = ERROR_SUCCESS; + + TRACE("(%p,%s,%ld,%p,%ld,%ld)\n", hUSKey, debugstr_w(pszValue), + dwType, pvData, cbData, dwFlags); + + if (!hUSKey || IsBadWritePtr(hUSKey, sizeof(SHUSKEY)) || + !(dwFlags & (SHREGSET_FORCE_HKCU|SHREGSET_FORCE_HKLM))) + return ERROR_INVALID_PARAMETER; + + if (dwFlags & (SHREGSET_FORCE_HKCU|SHREGSET_HKCU)) + { + if (!hKey->HKCUkey) + { + /* Create the key */ + ret = RegCreateKeyW(hKey->HKCUstart, hKey->lpszPath, &hKey->HKCUkey); + TRACE("Creating HKCU key, ret = %ld\n", ret); + if (ret && (dwFlags & (SHREGSET_FORCE_HKCU))) + { + hKey->HKCUkey = 0; + return ret; + } + } + + if (!ret) + { + if ((dwFlags & SHREGSET_FORCE_HKCU) || + RegQueryValueExW(hKey->HKCUkey, pszValue, NULL, NULL, NULL, &dummy)) + { + /* Doesn't exist or we are forcing: Write value */ + ret = RegSetValueExW(hKey->HKCUkey, pszValue, 0, dwType, pvData, cbData); + TRACE("Writing HKCU value, ret = %ld\n", ret); + } + } + } + + if (dwFlags & (SHREGSET_FORCE_HKLM|SHREGSET_HKLM)) + { + if (!hKey->HKLMkey) + { + /* Create the key */ + ret = RegCreateKeyW(hKey->HKLMstart, hKey->lpszPath, &hKey->HKLMkey); + TRACE("Creating HKLM key, ret = %ld\n", ret); + if (ret && (dwFlags & (SHREGSET_FORCE_HKLM))) + { + hKey->HKLMkey = 0; + return ret; + } + } + + if (!ret) + { + if ((dwFlags & SHREGSET_FORCE_HKLM) || + RegQueryValueExW(hKey->HKLMkey, pszValue, NULL, NULL, NULL, &dummy)) + { + /* Doesn't exist or we are forcing: Write value */ + ret = RegSetValueExW(hKey->HKLMkey, pszValue, 0, dwType, pvData, cbData); + TRACE("Writing HKLM value, ret = %ld\n", ret); + } + } + } + + return ret; +} + +/************************************************************************* + * SHRegGetPathA [SHLWAPI.@] + * + * Get a path from the registry. + * + * PARAMS + * hKey [I] Handle to registry key + * lpszSubKey [I] Name of sub key containing path to get + * lpszValue [I] Name of value containing path to get + * lpszPath [O] Buffer for returned path + * dwFlags [I] Reserved + * + * RETURNS + * Success: ERROR_SUCCESS. lpszPath contains the path. + * Failure: An error code from RegOpenKeyExA() or SHQueryValueExA(). + */ +DWORD WINAPI SHRegGetPathA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue, + LPSTR lpszPath, DWORD dwFlags) +{ + DWORD dwSize = MAX_PATH; + + TRACE("(hkey=%p,%s,%s,%p,%ld)\n", hKey, debugstr_a(lpszSubKey), + debugstr_a(lpszValue), lpszPath, dwFlags); + + return SHGetValueA(hKey, lpszSubKey, lpszValue, 0, lpszPath, &dwSize); +} + +/************************************************************************* + * SHRegGetPathW [SHLWAPI.@] + * + * See SHRegGetPathA. + */ +DWORD WINAPI SHRegGetPathW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue, + LPWSTR lpszPath, DWORD dwFlags) +{ + DWORD dwSize = MAX_PATH; + + TRACE("(hkey=%p,%s,%s,%p,%ld)\n", hKey, debugstr_w(lpszSubKey), + debugstr_w(lpszValue), lpszPath, dwFlags); + + return SHGetValueW(hKey, lpszSubKey, lpszValue, 0, lpszPath, &dwSize); +} + + +/************************************************************************* + * SHRegSetPathA [SHLWAPI.@] + * + * Write a path to the registry. + * + * PARAMS + * hKey [I] Handle to registry key + * lpszSubKey [I] Name of sub key containing path to set + * lpszValue [I] Name of value containing path to set + * lpszPath [O] Path to write + * dwFlags [I] Reserved, must be 0. + * + * RETURNS + * Success: ERROR_SUCCESS. + * Failure: An error code from SHSetValueA(). + */ +DWORD WINAPI SHRegSetPathA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue, + LPCSTR lpszPath, DWORD dwFlags) +{ + char szBuff[MAX_PATH]; + + FIXME("(hkey=%p,%s,%s,%p,%ld) - semi-stub\n",hKey, debugstr_a(lpszSubKey), + debugstr_a(lpszValue), lpszPath, dwFlags); + + lstrcpyA(szBuff, lpszPath); + + /* FIXME: PathUnExpandEnvStringsA(szBuff); */ + + return SHSetValueA(hKey,lpszSubKey, lpszValue, REG_SZ, szBuff, + lstrlenA(szBuff)); +} + +/************************************************************************* + * SHRegSetPathW [SHLWAPI.@] + * + * See SHRegSetPathA. + */ +DWORD WINAPI SHRegSetPathW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue, + LPCWSTR lpszPath, DWORD dwFlags) +{ + WCHAR szBuff[MAX_PATH]; + + FIXME("(hkey=%p,%s,%s,%p,%ld) - semi-stub\n",hKey, debugstr_w(lpszSubKey), + debugstr_w(lpszValue), lpszPath, dwFlags); + + lstrcpyW(szBuff, lpszPath); + + /* FIXME: PathUnExpandEnvStringsW(szBuff); */ + + return SHSetValueW(hKey,lpszSubKey, lpszValue, REG_SZ, szBuff, + lstrlenW(szBuff)); +} + +/************************************************************************* + * SHGetValueA [SHLWAPI.@] + * + * Get a value from the registry. + * + * PARAMS + * hKey [I] Handle to registry key + * lpszSubKey [I] Name of sub key containing value to get + * lpszValue [I] Name of value to get + * pwType [O] Pointer to the values type + * pvData [O] Pointer to the values data + * pcbData [O] Pointer to the values size + * + * RETURNS + * Success: ERROR_SUCCESS. Output parameters contain the details read. + * Failure: An error code from RegOpenKeyExA() or SHQueryValueExA(). + */ +DWORD WINAPI SHGetValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue, + LPDWORD pwType, LPVOID pvData, LPDWORD pcbData) +{ + DWORD dwRet = 0; + HKEY hSubKey = 0; + + TRACE("(hkey=%p,%s,%s,%p,%p,%p)\n", hKey, debugstr_a(lpszSubKey), + debugstr_a(lpszValue), pwType, pvData, pcbData); + + /* lpszSubKey can be 0. In this case the value is taken from the + * current key. + */ + if(lpszSubKey) + dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_QUERY_VALUE, &hSubKey); + + if (! dwRet) + { + /* SHQueryValueEx expands Environment strings */ + dwRet = SHQueryValueExA(hSubKey ? hSubKey : hKey, lpszValue, 0, pwType, pvData, pcbData); + if (hSubKey) RegCloseKey(hSubKey); + } + return dwRet; +} + +/************************************************************************* + * SHGetValueW [SHLWAPI.@] + * + * See SHGetValueA. + */ +DWORD WINAPI SHGetValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue, + LPDWORD pwType, LPVOID pvData, LPDWORD pcbData) +{ + DWORD dwRet = 0; + HKEY hSubKey = 0; + + TRACE("(hkey=%p,%s,%s,%p,%p,%p)\n", hKey, debugstr_w(lpszSubKey), + debugstr_w(lpszValue), pwType, pvData, pcbData); + + if(lpszSubKey) + dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_QUERY_VALUE, &hSubKey); + + if (! dwRet) + { + dwRet = SHQueryValueExW(hSubKey ? hSubKey : hKey, lpszValue, 0, pwType, pvData, pcbData); + if (hSubKey) RegCloseKey(hSubKey); + } + return dwRet; +} + +/************************************************************************* + * SHSetValueA [SHLWAPI.@] + * + * Set a value in the registry. + * + * PARAMS + * hKey [I] Handle to registry key + * lpszSubKey [I] Name of sub key under hKey + * lpszValue [I] Name of value to set + * dwType [I] Type of the value + * pvData [I] Data of the value + * cbData [I] Size of the value + * + * RETURNS + * Success: ERROR_SUCCESS. The value is set with the data given. + * Failure: An error code from RegCreateKeyExA() or RegSetValueExA() + * + * NOTES + * If lpszSubKey does not exist, it is created before the value is set. If + * lpszSubKey is NULL or an empty string, then the value is added directly + * to hKey instead. + */ +DWORD WINAPI SHSetValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue, + DWORD dwType, LPCVOID pvData, DWORD cbData) +{ + DWORD dwRet = ERROR_SUCCESS, dwDummy; + HKEY hSubKey; + static const char szEmpty[] = { '\0' }; + + TRACE("(hkey=%p,%s,%s,%ld,%p,%ld)\n", hKey, debugstr_a(lpszSubKey), + debugstr_a(lpszValue), dwType, pvData, cbData); + + if (lpszSubKey && *lpszSubKey) + dwRet = RegCreateKeyExA(hKey, lpszSubKey, 0, (LPSTR)szEmpty, + 0, KEY_SET_VALUE, NULL, &hSubKey, &dwDummy); + else + hSubKey = hKey; + if (!dwRet) + { + dwRet = RegSetValueExA(hSubKey, lpszValue, 0, dwType, pvData, cbData); + if (hSubKey != hKey) + RegCloseKey(hSubKey); + } + return dwRet; +} + +/************************************************************************* + * SHSetValueW [SHLWAPI.@] + * + * See SHSetValueA. + */ +DWORD WINAPI SHSetValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue, + DWORD dwType, LPCVOID pvData, DWORD cbData) +{ + DWORD dwRet = ERROR_SUCCESS, dwDummy; + HKEY hSubKey; + static const WCHAR szEmpty[] = { '\0' }; + + TRACE("(hkey=%p,%s,%s,%ld,%p,%ld)\n", hKey, debugstr_w(lpszSubKey), + debugstr_w(lpszValue), dwType, pvData, cbData); + + if (lpszSubKey && *lpszSubKey) + dwRet = RegCreateKeyExW(hKey, lpszSubKey, 0, (LPWSTR)szEmpty, + 0, KEY_SET_VALUE, NULL, &hSubKey, &dwDummy); + else + hSubKey = hKey; + if (!dwRet) + { + dwRet = RegSetValueExW(hSubKey, lpszValue, 0, dwType, pvData, cbData); + if (hSubKey != hKey) + RegCloseKey(hSubKey); + } + return dwRet; +} + +/************************************************************************* + * SHQueryInfoKeyA [SHLWAPI.@] + * + * Get information about a registry key. See RegQueryInfoKeyA(). + * + * RETURNS + * The result of calling RegQueryInfoKeyA(). + */ +LONG WINAPI SHQueryInfoKeyA(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax, + LPDWORD pwValues, LPDWORD pwValueMax) +{ + TRACE("(hkey=%p,%p,%p,%p,%p)\n", hKey, pwSubKeys, pwSubKeyMax, + pwValues, pwValueMax); + return RegQueryInfoKeyA(hKey, NULL, NULL, NULL, pwSubKeys, pwSubKeyMax, + NULL, pwValues, pwValueMax, NULL, NULL, NULL); +} + +/************************************************************************* + * SHQueryInfoKeyW [SHLWAPI.@] + * + * See SHQueryInfoKeyA. + */ +LONG WINAPI SHQueryInfoKeyW(HKEY hKey, LPDWORD pwSubKeys, LPDWORD pwSubKeyMax, + LPDWORD pwValues, LPDWORD pwValueMax) +{ + TRACE("(hkey=%p,%p,%p,%p,%p)\n", hKey, pwSubKeys, pwSubKeyMax, + pwValues, pwValueMax); + return RegQueryInfoKeyW(hKey, NULL, NULL, NULL, pwSubKeys, pwSubKeyMax, + NULL, pwValues, pwValueMax, NULL, NULL, NULL); +} + +/************************************************************************* + * SHQueryValueExA [SHLWAPI.@] + * + * Get a value from the registry, expanding environment variable strings. + * + * PARAMS + * hKey [I] Handle to registry key + * lpszValue [I] Name of value to query + * lpReserved [O] Reserved for future use; must be NULL + * pwType [O] Optional pointer updated with the values type + * pvData [O] Optional pointer updated with the values data + * pcbData [O] Optional pointer updated with the values size + * + * RETURNS + * Success: ERROR_SUCCESS. Any non NULL output parameters are updated with + * information about the value. + * Failure: ERROR_OUTOFMEMORY if memory allocation fails, or the type of the + * data is REG_EXPAND_SZ and pcbData is NULL. Otherwise an error + * code from RegQueryValueExA() or ExpandEnvironmentStringsA(). + * + * NOTES + * Either pwType, pvData or pcbData may be NULL if the caller doesn't want + * the type, data or size information for the value. + * + * If the type of the data is REG_EXPAND_SZ, it is expanded to REG_SZ. The + * value returned will be truncated if it is of type REG_SZ and bigger than + * the buffer given to store it. + * + * REG_EXPAND_SZ: + * case-1: the unexpanded string is smaller than the expanded one + * subcase-1: the buffer is too small to hold the unexpanded string: + * function fails and returns the size of the unexpanded string. + * + * subcase-2: buffer is too small to hold the expanded string: + * the function return success (!!) and the result is truncated + * *** This is clearly an error in the native implementation. *** + * + * case-2: the unexpanded string is bigger than the expanded one + * The buffer must have enough space to hold the unexpanded + * string even if the result is smaller. + * + */ +DWORD WINAPI SHQueryValueExA( HKEY hKey, LPCSTR lpszValue, + LPDWORD lpReserved, LPDWORD pwType, + LPVOID pvData, LPDWORD pcbData) +{ + DWORD dwRet, dwType, dwUnExpDataLen = 0, dwExpDataLen; + + TRACE("(hkey=%p,%s,%p,%p,%p,%p=%ld)\n", hKey, debugstr_a(lpszValue), + lpReserved, pwType, pvData, pcbData, pcbData ? *pcbData : 0); + + if (pcbData) dwUnExpDataLen = *pcbData; + + dwRet = RegQueryValueExA(hKey, lpszValue, lpReserved, &dwType, pvData, &dwUnExpDataLen); + + if (pcbData && (dwType == REG_EXPAND_SZ)) + { + DWORD nBytesToAlloc; + + /* Expand type REG_EXPAND_SZ into REG_SZ */ + LPSTR szData; + + /* If the caller didn't supply a buffer or the buffer is too small we have + * to allocate our own + */ + if ((!pvData) || (dwRet == ERROR_MORE_DATA) ) + { + char cNull = '\0'; + nBytesToAlloc = (!pvData || (dwRet == ERROR_MORE_DATA)) ? dwUnExpDataLen : *pcbData; + + szData = (LPSTR) LocalAlloc(LMEM_ZEROINIT, nBytesToAlloc); + RegQueryValueExA (hKey, lpszValue, lpReserved, NULL, (LPBYTE)szData, &nBytesToAlloc); + dwExpDataLen = ExpandEnvironmentStringsA(szData, &cNull, 1); + dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen); + LocalFree((HLOCAL) szData); + } + else + { + nBytesToAlloc = (lstrlenA(pvData)+1) * sizeof (CHAR); + szData = (LPSTR) LocalAlloc(LMEM_ZEROINIT, nBytesToAlloc ); + lstrcpyA(szData, pvData); + dwExpDataLen = ExpandEnvironmentStringsA(szData, pvData, *pcbData / sizeof(CHAR)); + if (dwExpDataLen > *pcbData) dwRet = ERROR_MORE_DATA; + dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen); + LocalFree((HLOCAL) szData); + } + } + + /* Update the type and data size if the caller wanted them */ + if ( dwType == REG_EXPAND_SZ ) dwType = REG_SZ; + if ( pwType ) *pwType = dwType; + if ( pcbData ) *pcbData = dwUnExpDataLen; + return dwRet; +} + + +/************************************************************************* + * SHQueryValueExW [SHLWAPI.@] + * + * See SHQueryValueExA. + */ +DWORD WINAPI SHQueryValueExW(HKEY hKey, LPCWSTR lpszValue, + LPDWORD lpReserved, LPDWORD pwType, + LPVOID pvData, LPDWORD pcbData) +{ + DWORD dwRet, dwType, dwUnExpDataLen = 0, dwExpDataLen; + + TRACE("(hkey=%p,%s,%p,%p,%p,%p=%ld)\n", hKey, debugstr_w(lpszValue), + lpReserved, pwType, pvData, pcbData, pcbData ? *pcbData : 0); + + if (pcbData) dwUnExpDataLen = *pcbData; + + dwRet = RegQueryValueExW(hKey, lpszValue, lpReserved, &dwType, pvData, &dwUnExpDataLen); + if (dwRet!=ERROR_SUCCESS && dwRet!=ERROR_MORE_DATA) + return dwRet; + + if (pcbData && (dwType == REG_EXPAND_SZ)) + { + DWORD nBytesToAlloc; + + /* Expand type REG_EXPAND_SZ into REG_SZ */ + LPWSTR szData; + + /* If the caller didn't supply a buffer or the buffer is too small we have + * to allocate our own + */ + if ((!pvData) || (dwRet == ERROR_MORE_DATA) ) + { + WCHAR cNull = '\0'; + nBytesToAlloc = (!pvData || (dwRet == ERROR_MORE_DATA)) ? dwUnExpDataLen : *pcbData; + + szData = (LPWSTR) LocalAlloc(LMEM_ZEROINIT, nBytesToAlloc); + RegQueryValueExW (hKey, lpszValue, lpReserved, NULL, (LPBYTE)szData, &nBytesToAlloc); + dwExpDataLen = ExpandEnvironmentStringsW(szData, &cNull, 1); + dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen); + LocalFree((HLOCAL) szData); + } + else + { + nBytesToAlloc = (lstrlenW(pvData) + 1) * sizeof(WCHAR); + szData = (LPWSTR) LocalAlloc(LMEM_ZEROINIT, nBytesToAlloc ); + lstrcpyW(szData, pvData); + dwExpDataLen = ExpandEnvironmentStringsW(szData, pvData, *pcbData/sizeof(WCHAR) ); + if (dwExpDataLen > *pcbData) dwRet = ERROR_MORE_DATA; + dwUnExpDataLen = max(nBytesToAlloc, dwExpDataLen); + LocalFree((HLOCAL) szData); + } + } + + /* Update the type and data size if the caller wanted them */ + if ( dwType == REG_EXPAND_SZ ) dwType = REG_SZ; + if ( pwType ) *pwType = dwType; + if ( pcbData ) *pcbData = dwUnExpDataLen; + return dwRet; +} + +/************************************************************************* + * SHDeleteKeyA [SHLWAPI.@] + * + * Delete a registry key and any sub keys/values present + * + * PARAMS + * hKey [I] Handle to registry key + * lpszSubKey [I] Name of sub key to delete + * + * RETURNS + * Success: ERROR_SUCCESS. The key is deleted. + * Failure: An error code from RegOpenKeyExA(), RegQueryInfoKeyA(), + * RegEnumKeyExA() or RegDeleteKeyA(). + */ +DWORD WINAPI SHDeleteKeyA(HKEY hKey, LPCSTR lpszSubKey) +{ + DWORD dwRet, dwMaxSubkeyLen = 0, dwSize; + CHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf; + HKEY hSubKey = 0; + + TRACE("(hkey=%p,%s)\n", hKey, debugstr_a(lpszSubKey)); + + dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); + if(!dwRet) + { + /* Find the maximum subkey length so that we can allocate a buffer */ + dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, NULL, + &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL); + if(!dwRet) + { + dwMaxSubkeyLen++; + if (dwMaxSubkeyLen > sizeof(szNameBuf)) + /* Name too big: alloc a buffer for it */ + lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(CHAR)); + + if(!lpszName) + dwRet = ERROR_NOT_ENOUGH_MEMORY; + else + { + while (dwRet == ERROR_SUCCESS) + { + dwSize = dwMaxSubkeyLen; + dwRet = RegEnumKeyExA(hSubKey, 0, lpszName, &dwSize, NULL, NULL, NULL, NULL); + if (dwRet == ERROR_SUCCESS || dwRet == ERROR_MORE_DATA) + dwRet = SHDeleteKeyA(hSubKey, lpszName); + } + if (dwRet == ERROR_NO_MORE_ITEMS) + dwRet = ERROR_SUCCESS; + if (lpszName != szNameBuf) + HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */ + } + } + + RegCloseKey(hSubKey); + if(!dwRet) + dwRet = RegDeleteKeyA(hKey, lpszSubKey); + } + return dwRet; +} + +/************************************************************************* + * SHDeleteKeyW [SHLWAPI.@] + * + * See SHDeleteKeyA. + */ +DWORD WINAPI SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey) +{ + DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i; + WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf; + HKEY hSubKey = 0; + + TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey)); + + dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); + if(!dwRet) + { + /* Find how many subkeys there are */ + dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount, + &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL); + if(!dwRet) + { + dwMaxSubkeyLen++; + if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR)) + /* Name too big: alloc a buffer for it */ + lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR)); + + if(!lpszName) + dwRet = ERROR_NOT_ENOUGH_MEMORY; + else + { + /* Recursively delete all the subkeys */ + for(i = 0; i < dwKeyCount && !dwRet; i++) + { + dwSize = dwMaxSubkeyLen; + dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL); + if(!dwRet) + dwRet = SHDeleteKeyW(hSubKey, lpszName); + } + + if (lpszName != szNameBuf) + HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */ + } + } + + RegCloseKey(hSubKey); + if(!dwRet) + dwRet = RegDeleteKeyW(hKey, lpszSubKey); + } + return dwRet; +} + +/************************************************************************* + * SHDeleteEmptyKeyA [SHLWAPI.@] + * + * Delete a registry key with no sub keys. + * + * PARAMS + * hKey [I] Handle to registry key + * lpszSubKey [I] Name of sub key to delete + * + * RETURNS + * Success: ERROR_SUCCESS. The key is deleted. + * Failure: If the key is not empty, returns ERROR_KEY_HAS_CHILDREN. Otherwise + * returns an error code from RegOpenKeyExA(), RegQueryInfoKeyA() or + * RegDeleteKeyA(). + */ +DWORD WINAPI SHDeleteEmptyKeyA(HKEY hKey, LPCSTR lpszSubKey) +{ + DWORD dwRet, dwKeyCount = 0; + HKEY hSubKey = 0; + + TRACE("(hkey=%p,%s)\n", hKey, debugstr_a(lpszSubKey)); + + dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); + if(!dwRet) + { + dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount, + NULL, NULL, NULL, NULL, NULL, NULL, NULL); + RegCloseKey(hSubKey); + if(!dwRet) + { + if (!dwKeyCount) + dwRet = RegDeleteKeyA(hKey, lpszSubKey); + else + dwRet = ERROR_KEY_HAS_CHILDREN; + } + } + return dwRet; +} + +/************************************************************************* + * SHDeleteEmptyKeyW [SHLWAPI.@] + * + * See SHDeleteEmptyKeyA. + */ +DWORD WINAPI SHDeleteEmptyKeyW(HKEY hKey, LPCWSTR lpszSubKey) +{ + DWORD dwRet, dwKeyCount = 0; + HKEY hSubKey = 0; + + TRACE("(hkey=%p, %s)\n", hKey, debugstr_w(lpszSubKey)); + + dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); + if(!dwRet) + { + dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount, + NULL, NULL, NULL, NULL, NULL, NULL, NULL); + RegCloseKey(hSubKey); + if(!dwRet) + { + if (!dwKeyCount) + dwRet = RegDeleteKeyW(hKey, lpszSubKey); + else + dwRet = ERROR_KEY_HAS_CHILDREN; + } + } + return dwRet; +} + +/************************************************************************* + * SHDeleteOrphanKeyA [SHLWAPI.@] + * + * Delete a registry key with no sub keys or values. + * + * PARAMS + * hKey [I] Handle to registry key + * lpszSubKey [I] Name of sub key to possibly delete + * + * RETURNS + * Success: ERROR_SUCCESS. The key has been deleted if it was an orphan. + * Failure: An error from RegOpenKeyExA(), RegQueryValueExA(), or RegDeleteKeyA(). + */ +DWORD WINAPI SHDeleteOrphanKeyA(HKEY hKey, LPCSTR lpszSubKey) +{ + HKEY hSubKey; + DWORD dwKeyCount = 0, dwValueCount = 0, dwRet; + + TRACE("(hkey=%p,%s)\n", hKey, debugstr_a(lpszSubKey)); + + dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); + + if(!dwRet) + { + /* Get subkey and value count */ + dwRet = RegQueryInfoKeyA(hSubKey, NULL, NULL, NULL, &dwKeyCount, + NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL); + + if(!dwRet && !dwKeyCount && !dwValueCount) + { + dwRet = RegDeleteKeyA(hKey, lpszSubKey); + } + RegCloseKey(hSubKey); + } + return dwRet; +} + +/************************************************************************* + * SHDeleteOrphanKeyW [SHLWAPI.@] + * + * See SHDeleteOrphanKeyA. + */ +DWORD WINAPI SHDeleteOrphanKeyW(HKEY hKey, LPCWSTR lpszSubKey) +{ + HKEY hSubKey; + DWORD dwKeyCount = 0, dwValueCount = 0, dwRet; + + TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey)); + + dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); + + if(!dwRet) + { + /* Get subkey and value count */ + dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount, + NULL, NULL, &dwValueCount, NULL, NULL, NULL, NULL); + + if(!dwRet && !dwKeyCount && !dwValueCount) + { + dwRet = RegDeleteKeyW(hKey, lpszSubKey); + } + RegCloseKey(hSubKey); + } + return dwRet; +} + +/************************************************************************* + * SHDeleteValueA [SHLWAPI.@] + * + * Delete a value from the registry. + * + * PARAMS + * hKey [I] Handle to registry key + * lpszSubKey [I] Name of sub key containing value to delete + * lpszValue [I] Name of value to delete + * + * RETURNS + * Success: ERROR_SUCCESS. The value is deleted. + * Failure: An error code from RegOpenKeyExA() or RegDeleteValueA(). + */ +DWORD WINAPI SHDeleteValueA(HKEY hKey, LPCSTR lpszSubKey, LPCSTR lpszValue) +{ + DWORD dwRet; + HKEY hSubKey; + + TRACE("(hkey=%p,%s,%s)\n", hKey, debugstr_a(lpszSubKey), debugstr_a(lpszValue)); + + dwRet = RegOpenKeyExA(hKey, lpszSubKey, 0, KEY_SET_VALUE, &hSubKey); + if (!dwRet) + { + dwRet = RegDeleteValueA(hSubKey, lpszValue); + RegCloseKey(hSubKey); + } + return dwRet; +} + +/************************************************************************* + * SHDeleteValueW [SHLWAPI.@] + * + * See SHDeleteValueA. + */ +DWORD WINAPI SHDeleteValueW(HKEY hKey, LPCWSTR lpszSubKey, LPCWSTR lpszValue) +{ + DWORD dwRet; + HKEY hSubKey; + + TRACE("(hkey=%p,%s,%s)\n", hKey, debugstr_w(lpszSubKey), debugstr_w(lpszValue)); + + dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_SET_VALUE, &hSubKey); + if (!dwRet) + { + dwRet = RegDeleteValueW(hSubKey, lpszValue); + RegCloseKey(hSubKey); + } + return dwRet; +} + +/************************************************************************* + * SHEnumKeyExA [SHLWAPI.@] + * + * Enumerate sub keys in a registry key. + * + * PARAMS + * hKey [I] Handle to registry key + * dwIndex [I] Index of key to enumerate + * lpszSubKey [O] Pointer updated with the subkey name + * pwLen [O] Pointer updated with the subkey length + * + * RETURNS + * Success: ERROR_SUCCESS. lpszSubKey and pwLen are updated. + * Failure: An error code from RegEnumKeyExA(). + */ +LONG WINAPI SHEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpszSubKey, + LPDWORD pwLen) +{ + TRACE("(hkey=%p,%ld,%s,%p)\n", hKey, dwIndex, debugstr_a(lpszSubKey), pwLen); + + return RegEnumKeyExA(hKey, dwIndex, lpszSubKey, pwLen, NULL, NULL, NULL, NULL); +} + +/************************************************************************* + * SHEnumKeyExW [SHLWAPI.@] + * + * See SHEnumKeyExA. + */ +LONG WINAPI SHEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpszSubKey, + LPDWORD pwLen) +{ + TRACE("(hkey=%p,%ld,%s,%p)\n", hKey, dwIndex, debugstr_w(lpszSubKey), pwLen); + + return RegEnumKeyExW(hKey, dwIndex, lpszSubKey, pwLen, NULL, NULL, NULL, NULL); +} + +/************************************************************************* + * SHEnumValueA [SHLWAPI.@] + * + * Enumerate values in a registry key. + * + * PARAMS + * hKey [I] Handle to registry key + * dwIndex [I] Index of key to enumerate + * lpszValue [O] Pointer updated with the values name + * pwLen [O] Pointer updated with the values length + * pwType [O] Pointer updated with the values type + * pvData [O] Pointer updated with the values data + * pcbData [O] Pointer updated with the values size + * + * RETURNS + * Success: ERROR_SUCCESS. Output parameters are updated. + * Failure: An error code from RegEnumValueA(). + */ +LONG WINAPI SHEnumValueA(HKEY hKey, DWORD dwIndex, LPSTR lpszValue, + LPDWORD pwLen, LPDWORD pwType, + LPVOID pvData, LPDWORD pcbData) +{ + TRACE("(hkey=%p,%ld,%s,%p,%p,%p,%p)\n", hKey, dwIndex, + debugstr_a(lpszValue), pwLen, pwType, pvData, pcbData); + + return RegEnumValueA(hKey, dwIndex, lpszValue, pwLen, NULL, + pwType, pvData, pcbData); +} + +/************************************************************************* + * SHEnumValueW [SHLWAPI.@] + * + * See SHEnumValueA. + */ +LONG WINAPI SHEnumValueW(HKEY hKey, DWORD dwIndex, LPWSTR lpszValue, + LPDWORD pwLen, LPDWORD pwType, + LPVOID pvData, LPDWORD pcbData) +{ + TRACE("(hkey=%p,%ld,%s,%p,%p,%p,%p)\n", hKey, dwIndex, + debugstr_w(lpszValue), pwLen, pwType, pvData, pcbData); + + return RegEnumValueW(hKey, dwIndex, lpszValue, pwLen, NULL, + pwType, pvData, pcbData); +} + +/************************************************************************* + * @ [SHLWAPI.205] + * + * Get a value from the registry. + * + * PARAMS + * hKey [I] Handle to registry key + * pSubKey [I] Name of sub key containing value to get + * pValue [I] Name of value to get + * pwType [O] Destination for the values type + * pvData [O] Destination for the values data + * pbData [O] Destination for the values size + * + * RETURNS + * Success: ERROR_SUCCESS. Output parameters contain the details read. + * Failure: An error code from RegOpenKeyExA() or SHQueryValueExA(), + * or ERROR_INVALID_FUNCTION in the machine is in safe mode. + */ +DWORD WINAPI SHGetValueGoodBootA(HKEY hkey, LPCSTR pSubKey, LPCSTR pValue, + LPDWORD pwType, LPVOID pvData, LPDWORD pbData) +{ + if (GetSystemMetrics(SM_CLEANBOOT)) + return ERROR_INVALID_FUNCTION; + return SHGetValueA(hkey, pSubKey, pValue, pwType, pvData, pbData); +} + +/************************************************************************* + * @ [SHLWAPI.206] + * + * Unicode version of SHGetValueGoodBootW. + */ +DWORD WINAPI SHGetValueGoodBootW(HKEY hkey, LPCWSTR pSubKey, LPCWSTR pValue, + LPDWORD pwType, LPVOID pvData, LPDWORD pbData) +{ + if (GetSystemMetrics(SM_CLEANBOOT)) + return ERROR_INVALID_FUNCTION; + return SHGetValueW(hkey, pSubKey, pValue, pwType, pvData, pbData); +} + +/************************************************************************* + * @ [SHLWAPI.320] + * + * Set a MIME content type in the registry. + * + * PARAMS + * lpszSubKey [I] Name of key under HKEY_CLASSES_ROOT. + * lpszValue [I] Value to set + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI RegisterMIMETypeForExtensionA(LPCSTR lpszSubKey, LPCSTR lpszValue) +{ + DWORD dwRet; + + if (!lpszValue) + { + WARN("Invalid lpszValue would crash under Win32!\n"); + return FALSE; + } + + dwRet = SHSetValueA(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeA, + REG_SZ, lpszValue, strlen(lpszValue)); + return dwRet ? FALSE : TRUE; +} + +/************************************************************************* + * @ [SHLWAPI.321] + * + * Unicode version of RegisterMIMETypeForExtensionA. + */ +BOOL WINAPI RegisterMIMETypeForExtensionW(LPCWSTR lpszSubKey, LPCWSTR lpszValue) +{ + DWORD dwRet; + + if (!lpszValue) + { + WARN("Invalid lpszValue would crash under Win32!\n"); + return FALSE; + } + + dwRet = SHSetValueW(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeW, + REG_SZ, lpszValue, strlenW(lpszValue)); + return dwRet ? FALSE : TRUE; +} + +/************************************************************************* + * @ [SHLWAPI.322] + * + * Delete a MIME content type from the registry. + * + * PARAMS + * lpszSubKey [I] Name of sub key + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ +BOOL WINAPI UnregisterMIMETypeForExtensionA(LPCSTR lpszSubKey) +{ + HRESULT ret = SHDeleteValueA(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeA); + return ret ? FALSE : TRUE; +} + +/************************************************************************* + * @ [SHLWAPI.323] + * + * Unicode version of UnregisterMIMETypeForExtensionA. + */ +BOOL WINAPI UnregisterMIMETypeForExtensionW(LPCWSTR lpszSubKey) +{ + HRESULT ret = SHDeleteValueW(HKEY_CLASSES_ROOT, lpszSubKey, lpszContentTypeW); + return ret ? FALSE : TRUE; +} + +/************************************************************************* + * @ [SHLWAPI.328] + * + * Get the registry path to a MIME content key. + * + * PARAMS + * lpszType [I] Content type to get the path for + * lpszBuffer [O] Destination for path + * dwLen [I] Length of lpszBuffer + * + * RETURNS + * Success: TRUE. lpszBuffer contains the full path. + * Failure: FALSE. + * + * NOTES + * The base path for the key is "MIME\Database\Content Type\" + */ +BOOL WINAPI GetMIMETypeSubKeyA(LPCSTR lpszType, LPSTR lpszBuffer, DWORD dwLen) +{ + TRACE("(%s,%p,%ld)\n", debugstr_a(lpszType), lpszBuffer, dwLen); + + if (dwLen > dwLenMimeDbContent && lpszType && lpszBuffer) + { + size_t dwStrLen = strlen(lpszType); + + if (dwStrLen < dwLen - dwLenMimeDbContent) + { + memcpy(lpszBuffer, szMimeDbContentA, dwLenMimeDbContent); + memcpy(lpszBuffer + dwLenMimeDbContent, lpszType, dwStrLen + 1); + return TRUE; + } + } + return FALSE; +} + +/************************************************************************* + * @ [SHLWAPI.329] + * + * Unicode version of GetMIMETypeSubKeyA. + */ +BOOL WINAPI GetMIMETypeSubKeyW(LPCWSTR lpszType, LPWSTR lpszBuffer, DWORD dwLen) +{ + TRACE("(%s,%p,%ld)\n", debugstr_w(lpszType), lpszBuffer, dwLen); + + if (dwLen > dwLenMimeDbContent && lpszType && lpszBuffer) + { + DWORD dwStrLen = strlenW(lpszType); + + if (dwStrLen < dwLen - dwLenMimeDbContent) + { + memcpy(lpszBuffer, szMimeDbContentW, dwLenMimeDbContent * sizeof(WCHAR)); + memcpy(lpszBuffer + dwLenMimeDbContent, lpszType, (dwStrLen + 1) * sizeof(WCHAR)); + return TRUE; + } + } + return FALSE; +} + +/************************************************************************* + * @ [SHLWAPI.330] + * + * Get the file extension for a given Mime type. + * + * PARAMS + * lpszType [I] Mime type to get the file extension for + * lpExt [O] Destination for the resulting extension + * iLen [I] Length of lpExt in characters + * + * RETURNS + * Success: TRUE. lpExt contains the file extension. + * Failure: FALSE, if any parameter is invalid or the extension cannot be + * retrieved. If iLen > 0, lpExt is set to an empty string. + * + * NOTES + * - The extension returned in lpExt always has a leading '.' character, even + * if the registry Mime database entry does not. + * - iLen must be long enough for the file extension for this function to succeed. + */ +BOOL WINAPI MIME_GetExtensionA(LPCSTR lpszType, LPSTR lpExt, INT iLen) +{ + char szSubKey[MAX_PATH]; + DWORD dwlen = iLen - 1, dwType; + BOOL bRet = FALSE; + + if (iLen > 0 && lpExt) + *lpExt = '\0'; + + if (lpszType && lpExt && iLen > 2 && + GetMIMETypeSubKeyA(lpszType, szSubKey, MAX_PATH) && + !SHGetValueA(HKEY_CLASSES_ROOT, szSubKey, szExtensionA, &dwType, lpExt + 1, &dwlen) && + lpExt[1]) + { + if (lpExt[1] == '.') + memmove(lpExt, lpExt + 1, strlen(lpExt + 1) + 1); + else + *lpExt = '.'; /* Supply a '.' */ + bRet = TRUE; + } + return bRet; +} + +/************************************************************************* + * @ [SHLWAPI.331] + * + * Unicode version of MIME_GetExtensionA. + */ +BOOL WINAPI MIME_GetExtensionW(LPCWSTR lpszType, LPWSTR lpExt, INT iLen) +{ + WCHAR szSubKey[MAX_PATH]; + DWORD dwlen = iLen - 1, dwType; + BOOL bRet = FALSE; + + if (iLen > 0 && lpExt) + *lpExt = '\0'; + + if (lpszType && lpExt && iLen > 2 && + GetMIMETypeSubKeyW(lpszType, szSubKey, MAX_PATH) && + !SHGetValueW(HKEY_CLASSES_ROOT, szSubKey, szExtensionW, &dwType, lpExt + 1, &dwlen) && + lpExt[1]) + { + if (lpExt[1] == '.') + memmove(lpExt, lpExt + 1, (strlenW(lpExt + 1) + 1) * sizeof(WCHAR)); + else + *lpExt = '.'; /* Supply a '.' */ + bRet = TRUE; + } + return bRet; +} + +/************************************************************************* + * @ [SHLWAPI.324] + * + * Set the file extension for a MIME content key. + * + * PARAMS + * lpszExt [I] File extension to set + * lpszType [I] Content type to set the extension for + * + * RETURNS + * Success: TRUE. The file extension is set in the registry. + * Failure: FALSE. + */ +BOOL WINAPI RegisterExtensionForMIMETypeA(LPCSTR lpszExt, LPCSTR lpszType) +{ + DWORD dwLen; + char szKey[MAX_PATH]; + + TRACE("(%s,%s)\n", debugstr_a(lpszExt), debugstr_a(lpszType)); + + if (!GetMIMETypeSubKeyA(lpszType, szKey, MAX_PATH)) /* Get full path to the key */ + return FALSE; + + dwLen = strlen(lpszExt) + 1; + + if (SHSetValueA(HKEY_CLASSES_ROOT, szKey, szExtensionA, REG_SZ, lpszExt, dwLen)) + return FALSE; + return TRUE; +} + +/************************************************************************* + * @ [SHLWAPI.325] + * + * Unicode version of RegisterExtensionForMIMETypeA. + */ +BOOL WINAPI RegisterExtensionForMIMETypeW(LPCWSTR lpszExt, LPCWSTR lpszType) +{ + DWORD dwLen; + WCHAR szKey[MAX_PATH]; + + TRACE("(%s,%s)\n", debugstr_w(lpszExt), debugstr_w(lpszType)); + + /* Get the full path to the key */ + if (!GetMIMETypeSubKeyW(lpszType, szKey, MAX_PATH)) /* Get full path to the key */ + return FALSE; + + dwLen = (lstrlenW(lpszExt) + 1) * sizeof(WCHAR); + + if (SHSetValueW(HKEY_CLASSES_ROOT, szKey, szExtensionW, REG_SZ, lpszExt, dwLen)) + return FALSE; + return TRUE; +} + +/************************************************************************* + * @ [SHLWAPI.326] + * + * Delete a file extension from a MIME content type. + * + * PARAMS + * lpszType [I] Content type to delete the extension for + * + * RETURNS + * Success: TRUE. The file extension is deleted from the registry. + * Failure: FALSE. The extension may have been removed but the key remains. + * + * NOTES + * If deleting the extension leaves an orphan key, the key is removed also. + */ +BOOL WINAPI UnregisterExtensionForMIMETypeA(LPCSTR lpszType) +{ + char szKey[MAX_PATH]; + + TRACE("(%s)\n", debugstr_a(lpszType)); + + if (!GetMIMETypeSubKeyA(lpszType, szKey, MAX_PATH)) /* Get full path to the key */ + return FALSE; + + if (!SHDeleteValueA(HKEY_CLASSES_ROOT, szKey, szExtensionA)) + return FALSE; + + if (!SHDeleteOrphanKeyA(HKEY_CLASSES_ROOT, szKey)) + return FALSE; + return TRUE; +} + +/************************************************************************* + * @ [SHLWAPI.327] + * + * Unicode version of UnregisterExtensionForMIMETypeA. + */ +BOOL WINAPI UnregisterExtensionForMIMETypeW(LPCWSTR lpszType) +{ + WCHAR szKey[MAX_PATH]; + + TRACE("(%s)\n", debugstr_w(lpszType)); + + if (!GetMIMETypeSubKeyW(lpszType, szKey, MAX_PATH)) /* Get full path to the key */ + return FALSE; + + if (!SHDeleteValueW(HKEY_CLASSES_ROOT, szKey, szExtensionW)) + return FALSE; + + if (!SHDeleteOrphanKeyW(HKEY_CLASSES_ROOT, szKey)) + return FALSE; + return TRUE; +} + +/************************************************************************* + * SHRegDuplicateHKey [SHLWAPI.@] + * + * Create a duplicate of a registry handle. + * + * PARAMS + * hKey [I] key to duplicate. + * + * RETURNS + * A new handle pointing to the same key as hKey. + */ +HKEY WINAPI SHRegDuplicateHKey(HKEY hKey) +{ + HKEY newKey = 0; + + RegOpenKeyExA(hKey, 0, 0, MAXIMUM_ALLOWED, &newKey); + TRACE("new key is %p\n", newKey); + return newKey; +} + + +/************************************************************************* + * SHCopyKeyA [SHLWAPI.@] + * + * Copy a key and its values/sub keys to another location. + * + * PARAMS + * hKeySrc [I] Source key to copy from + * lpszSrcSubKey [I] Sub key under hKeySrc, or NULL to use hKeySrc directly + * hKeyDst [I] Destination key + * dwReserved [I] Reserved, must be 0 + * + * RETURNS + * Success: ERROR_SUCCESS. The key is copied to the destination key. + * Failure: A standard windows error code. + * + * NOTES + * If hKeyDst is a key under hKeySrc, this function will misbehave + * (It will loop until out of stack, or the registry is full). This + * bug is present in Win32 also. + */ +DWORD WINAPI SHCopyKeyA(HKEY hKeySrc, LPCSTR lpszSrcSubKey, HKEY hKeyDst, DWORD dwReserved) +{ + WCHAR szSubKeyW[MAX_PATH]; + + TRACE("(hkey=%p,%s,%p08x,%ld)\n", hKeySrc, debugstr_a(lpszSrcSubKey), hKeyDst, dwReserved); + + if (lpszSrcSubKey) + MultiByteToWideChar(0, 0, lpszSrcSubKey, -1, szSubKeyW, MAX_PATH); + + return SHCopyKeyW(hKeySrc, lpszSrcSubKey ? szSubKeyW : NULL, hKeyDst, dwReserved); +} + +/************************************************************************* + * SHCopyKeyW [SHLWAPI.@] + * + * See SHCopyKeyA. + */ +DWORD WINAPI SHCopyKeyW(HKEY hKeySrc, LPCWSTR lpszSrcSubKey, HKEY hKeyDst, DWORD dwReserved) +{ + DWORD dwKeyCount = 0, dwValueCount = 0, dwMaxKeyLen = 0; + DWORD dwMaxValueLen = 0, dwMaxDataLen = 0, i; + BYTE buff[1024]; + LPVOID lpBuff = (LPVOID)buff; + WCHAR szName[MAX_PATH], *lpszName = szName; + DWORD dwRet = S_OK; + + TRACE("hkey=%p,%s,%p08x,%ld)\n", hKeySrc, debugstr_w(lpszSrcSubKey), hKeyDst, dwReserved); + + if(!hKeyDst || !hKeySrc) + dwRet = ERROR_INVALID_PARAMETER; + else + { + /* Open source key */ + if(lpszSrcSubKey) + dwRet = RegOpenKeyExW(hKeySrc, lpszSrcSubKey, 0, KEY_ALL_ACCESS, &hKeySrc); + + if(dwRet) + hKeyDst = NULL; /* Don't close this key since we didn't open it */ + else + { + /* Get details about sub keys and values */ + dwRet = RegQueryInfoKeyW(hKeySrc, NULL, NULL, NULL, &dwKeyCount, &dwMaxKeyLen, + NULL, &dwValueCount, &dwMaxValueLen, &dwMaxDataLen, + NULL, NULL); + if(!dwRet) + { + if (dwMaxValueLen > dwMaxKeyLen) + dwMaxKeyLen = dwMaxValueLen; /* Get max size for key/value names */ + + if (dwMaxKeyLen++ > MAX_PATH - 1) + lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxKeyLen * sizeof(WCHAR)); + + if (dwMaxDataLen > sizeof(buff)) + lpBuff = HeapAlloc(GetProcessHeap(), 0, dwMaxDataLen); + + if (!lpszName || !lpBuff) + dwRet = ERROR_NOT_ENOUGH_MEMORY; + } + } + } + + /* Copy all the sub keys */ + for(i = 0; i < dwKeyCount && !dwRet; i++) + { + HKEY hSubKeySrc, hSubKeyDst; + DWORD dwSize = dwMaxKeyLen; + + dwRet = RegEnumKeyExW(hKeySrc, i, lpszName, &dwSize, NULL, NULL, NULL, NULL); + + if(!dwRet) + { + /* Open source sub key */ + dwRet = RegOpenKeyExW(hKeySrc, lpszName, 0, KEY_READ, &hSubKeySrc); + + if(!dwRet) + { + /* Create destination sub key */ + dwRet = RegCreateKeyW(hKeyDst, lpszName, &hSubKeyDst); + + if(!dwRet) + { + /* Recursively copy keys and values from the sub key */ + dwRet = SHCopyKeyW(hSubKeySrc, NULL, hSubKeyDst, 0); + RegCloseKey(hSubKeyDst); + } + } + RegCloseKey(hSubKeySrc); + } + } + + /* Copy all the values in this key */ + for (i = 0; i < dwValueCount && !dwRet; i++) + { + DWORD dwNameSize = dwMaxKeyLen, dwType, dwLen = dwMaxDataLen; + + dwRet = RegEnumValueW(hKeySrc, i, lpszName, &dwNameSize, NULL, &dwType, buff, &dwLen); + + if (!dwRet) + dwRet = SHSetValueW(hKeyDst, NULL, lpszName, dwType, lpBuff, dwLen); + } + + /* Free buffers if allocated */ + if (lpszName != szName) + HeapFree(GetProcessHeap(), 0, lpszName); + if (lpBuff != buff) + HeapFree(GetProcessHeap(), 0, lpBuff); + + if (lpszSrcSubKey && hKeyDst) + RegCloseKey(hKeyDst); + return dwRet; +} + +/* + * The following functions are ORDINAL ONLY: + */ + +/************************************************************************* + * @ [SHLWAPI.280] + * + * Read an integer value from the registry, falling back to a default. + * + * PARAMS + * hKey [I] Registry key to read from + * lpszValue [I] Value name to read + * iDefault [I] Default value to return + * + * RETURNS + * The value contained in the given registry value if present, otherwise + * iDefault. + */ +int WINAPI SHRegGetIntW(HKEY hKey, LPCWSTR lpszValue, int iDefault) +{ + TRACE("(%p,%s,%d)\n", hKey, debugstr_w(lpszValue), iDefault); + + if (hKey) + { + WCHAR szBuff[32]; + DWORD dwSize = sizeof(szBuff); + szBuff[0] = '\0'; + SHQueryValueExW(hKey, lpszValue, 0, 0, szBuff, &dwSize); + + if(*szBuff >= '0' && *szBuff <= '9') + return StrToIntW(szBuff); + } + return iDefault; +} + +/************************************************************************* + * @ [SHLWAPI.343] + * + * Create or open an explorer ClassId Key. + * + * PARAMS + * guid [I] Explorer ClassId key to open + * lpszValue [I] Value name under the ClassId Key + * bUseHKCU [I] TRUE=Use HKEY_CURRENT_USER, FALSE=Use HKEY_CLASSES_ROOT + * bCreate [I] TRUE=Create the key if it doesn't exist, FALSE=Don't + * phKey [O] Destination for the resulting key handle + * + * RETURNS + * Success: S_OK. phKey contains the resulting registry handle. + * Failure: An HRESULT error code indicating the problem. + */ +HRESULT WINAPI SHRegGetCLSIDKeyA(REFGUID guid, LPCSTR lpszValue, BOOL bUseHKCU, BOOL bCreate, PHKEY phKey) +{ + WCHAR szValue[MAX_PATH]; + + if (lpszValue) + MultiByteToWideChar(CP_ACP, 0, lpszValue, -1, szValue, sizeof(szValue)/sizeof(WCHAR)); + + return SHRegGetCLSIDKeyW(guid, lpszValue ? szValue : NULL, bUseHKCU, bCreate, phKey); +} + +/************************************************************************* + * @ [SHLWAPI.344] + * + * Unicode version of SHRegGetCLSIDKeyA. + */ +HRESULT WINAPI SHRegGetCLSIDKeyW(REFGUID guid, LPCWSTR lpszValue, BOOL bUseHKCU, + BOOL bCreate, PHKEY phKey) +{ + static const WCHAR szClassIdKey[] = { 'S','o','f','t','w','a','r','e','\\', + 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\', + 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'E','x','p','l','o','r','e','r','\\','C','L','S','I','D','\\' }; +#define szClassIdKeyLen (sizeof(szClassIdKey)/sizeof(WCHAR)) + WCHAR szKey[MAX_PATH]; + DWORD dwRet; + HKEY hkey; + + /* Create the key string */ + memcpy(szKey, szClassIdKey, sizeof(szClassIdKey)); + SHStringFromGUIDW(guid, szKey + szClassIdKeyLen, 39); /* Append guid */ + + if(lpszValue) + { + szKey[szClassIdKeyLen + 39] = '\\'; + strcpyW(szKey + szClassIdKeyLen + 40, lpszValue); /* Append value name */ + } + + hkey = bUseHKCU ? HKEY_CURRENT_USER : HKEY_CLASSES_ROOT; + + if(bCreate) + dwRet = RegCreateKeyW(hkey, szKey, phKey); + else + dwRet = RegOpenKeyExW(hkey, szKey, 0, KEY_READ, phKey); + + return dwRet ? HRESULT_FROM_WIN32(dwRet) : S_OK; +} + +/************************************************************************* + * SHRegisterValidateTemplate [SHLWAPI.@] + * + * observed from the ie 5.5 installer: + * - allocates a buffer with the size of the given file + * - read the file content into the buffer + * - creates the key szTemplateKey + * - sets "205523652929647911071668590831910975402"=dword:00002e37 at + * the key + * + * PARAMS + * filename [I] An existing file its content is read into an allocated + * buffer + * unknown [I] + * + * RETURNS + * Success: ERROR_SUCCESS. + */ +HRESULT WINAPI SHRegisterValidateTemplate(LPCWSTR filename, BOOL unknown) +{ +/* static const WCHAR szTemplateKey[] = { 'S','o','f','t','w','a','r','e','\\', + * 'M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\', + * 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + * 'E','x','p','l','o','r','e','r','\\', + * 'T','e','m','p','l','a','t','e','R','e','g','i','s','t','r','y',0 }; + */ + FIXME("stub: %s, %08x\n", debugstr_w(filename), unknown); + + return S_OK; +} diff --git a/reactos/lib/shlwapi/regstream.c b/reactos/lib/shlwapi/regstream.c index 894176c2c85..e86590ebd20 100644 --- a/reactos/lib/shlwapi/regstream.c +++ b/reactos/lib/shlwapi/regstream.c @@ -1,548 +1,548 @@ -/* - * SHLWAPI Registry Stream functions - * - * Copyright 1999 Juergen Schmied - * Copyright 2002 Jon Griffiths - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> -#include <string.h> - -#define COBJMACROS - -#include "winerror.h" -#include "windef.h" -#include "winbase.h" -#include "objbase.h" -#include "winreg.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(shell); - -typedef struct -{ IStreamVtbl *lpVtbl; - DWORD ref; - HKEY hKey; - LPBYTE pbBuffer; - DWORD dwLength; - DWORD dwPos; -} ISHRegStream; - -/************************************************************************** -* IStream_fnQueryInterface -*/ -static HRESULT WINAPI IStream_fnQueryInterface(IStream *iface, REFIID riid, LPVOID *ppvObj) -{ - ISHRegStream *This = (ISHRegStream *)iface; - - TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj); - - *ppvObj = NULL; - - if(IsEqualIID(riid, &IID_IUnknown)) /*IUnknown*/ - *ppvObj = This; - else if(IsEqualIID(riid, &IID_IStream)) /*IStream*/ - *ppvObj = This; - - if(*ppvObj) - { - IStream_AddRef((IStream*)*ppvObj); - TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj); - return S_OK; - } - TRACE("-- Interface: E_NOINTERFACE\n"); - return E_NOINTERFACE; -} - -/************************************************************************** -* IStream_fnAddRef -*/ -static ULONG WINAPI IStream_fnAddRef(IStream *iface) -{ - ISHRegStream *This = (ISHRegStream *)iface; - ULONG refCount = InterlockedIncrement(&This->ref); - - TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1); - - return refCount; -} - -/************************************************************************** -* IStream_fnRelease -*/ -static ULONG WINAPI IStream_fnRelease(IStream *iface) -{ - ISHRegStream *This = (ISHRegStream *)iface; - ULONG refCount = InterlockedDecrement(&This->ref); - - TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1); - - if (!refCount) - { - TRACE(" destroying SHReg IStream (%p)\n",This); - - HeapFree(GetProcessHeap(),0,This->pbBuffer); - - if (This->hKey) - RegCloseKey(This->hKey); - - HeapFree(GetProcessHeap(),0,This); - return 0; - } - - return refCount; -} - -/************************************************************************** - * IStream_fnRead - */ -static HRESULT WINAPI IStream_fnRead (IStream * iface, void* pv, ULONG cb, ULONG* pcbRead) -{ - ISHRegStream *This = (ISHRegStream *)iface; - - DWORD dwBytesToRead, dwBytesLeft; - - TRACE("(%p)->(%p,0x%08lx,%p)\n",This, pv, cb, pcbRead); - - if (!pv) - return STG_E_INVALIDPOINTER; - - dwBytesLeft = This->dwLength - This->dwPos; - - if ( 0 >= dwBytesLeft ) /* end of buffer */ - return S_FALSE; - - dwBytesToRead = ( cb > dwBytesLeft) ? dwBytesLeft : cb; - - memmove ( pv, (This->pbBuffer) + (This->dwPos), dwBytesToRead); - - This->dwPos += dwBytesToRead; /* adjust pointer */ - - if (pcbRead) - *pcbRead = dwBytesToRead; - - return S_OK; -} - -/************************************************************************** - * IStream_fnWrite - */ -static HRESULT WINAPI IStream_fnWrite (IStream * iface, const void* pv, ULONG cb, ULONG* pcbWritten) -{ - ISHRegStream *This = (ISHRegStream *)iface; - - TRACE("(%p)\n",This); - - if (pcbWritten) - *pcbWritten = 0; - - return E_NOTIMPL; -} - -/************************************************************************** - * IStream_fnSeek - */ -static HRESULT WINAPI IStream_fnSeek (IStream * iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) -{ - ISHRegStream *This = (ISHRegStream *)iface; - - TRACE("(%p)\n",This); - - if (plibNewPosition) - plibNewPosition->QuadPart = 0; - return E_NOTIMPL; -} - -/************************************************************************** - * IStream_fnSetSize - */ -static HRESULT WINAPI IStream_fnSetSize (IStream * iface, ULARGE_INTEGER libNewSize) -{ - ISHRegStream *This = (ISHRegStream *)iface; - - TRACE("(%p)\n",This); - return E_NOTIMPL; -} - -/************************************************************************** - * IStream_fnCopyTo - */ -static HRESULT WINAPI IStream_fnCopyTo (IStream * iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) -{ - ISHRegStream *This = (ISHRegStream *)iface; - - TRACE("(%p)\n",This); - if (pcbRead) - pcbRead->QuadPart = 0; - if (pcbWritten) - pcbWritten->QuadPart = 0; - return E_NOTIMPL; -} - -/************************************************************************** - * IStream_fnCommit - */ -static HRESULT WINAPI IStream_fnCommit (IStream * iface, DWORD grfCommitFlags) -{ - ISHRegStream *This = (ISHRegStream *)iface; - - TRACE("(%p)\n",This); - - return E_NOTIMPL; -} - -/************************************************************************** - * IStream_fnRevert - */ -static HRESULT WINAPI IStream_fnRevert (IStream * iface) -{ - ISHRegStream *This = (ISHRegStream *)iface; - - TRACE("(%p)\n",This); - - return E_NOTIMPL; -} - -/************************************************************************** - * IStream_fnLockUnlockRegion - */ -static HRESULT WINAPI IStream_fnLockUnlockRegion (IStream * iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) -{ - ISHRegStream *This = (ISHRegStream *)iface; - - TRACE("(%p)\n",This); - - return E_NOTIMPL; -} - -/************************************************************************* - * IStream_fnStat - */ -static HRESULT WINAPI IStream_fnStat (IStream * iface, STATSTG* pstatstg, DWORD grfStatFlag) -{ - ISHRegStream *This = (ISHRegStream *)iface; - - TRACE("(%p)\n",This); - - return E_NOTIMPL; -} - -/************************************************************************* - * IStream_fnClone - */ -static HRESULT WINAPI IStream_fnClone (IStream * iface, IStream** ppstm) -{ - ISHRegStream *This = (ISHRegStream *)iface; - - TRACE("(%p)\n",This); - if (ppstm) - *ppstm = NULL; - return E_NOTIMPL; -} - -static struct IStreamVtbl rstvt = -{ - IStream_fnQueryInterface, - IStream_fnAddRef, - IStream_fnRelease, - IStream_fnRead, - IStream_fnWrite, - IStream_fnSeek, - IStream_fnSetSize, - IStream_fnCopyTo, - IStream_fnCommit, - IStream_fnRevert, - IStream_fnLockUnlockRegion, - IStream_fnLockUnlockRegion, - IStream_fnStat, - IStream_fnClone -}; - -/* Methods overridden by the dummy stream */ - -/************************************************************************** - * IStream_fnAddRefDummy - */ -static ULONG WINAPI IStream_fnAddRefDummy(IStream *iface) -{ - ISHRegStream *This = (ISHRegStream *)iface; - TRACE("(%p)\n", This); - return 2; -} - -/************************************************************************** - * IStream_fnReleaseDummy - */ -static ULONG WINAPI IStream_fnReleaseDummy(IStream *iface) -{ - ISHRegStream *This = (ISHRegStream *)iface; - TRACE("(%p)\n", This); - return 1; -} - -/************************************************************************** - * IStream_fnReadDummy - */ -static HRESULT WINAPI IStream_fnReadDummy(IStream *iface, LPVOID pv, ULONG cb, ULONG* pcbRead) -{ - if (pcbRead) - *pcbRead = 0; - return E_NOTIMPL; -} - -static struct IStreamVtbl DummyRegStreamVTable = -{ - IStream_fnQueryInterface, - IStream_fnAddRefDummy, /* Overridden */ - IStream_fnReleaseDummy, /* Overridden */ - IStream_fnReadDummy, /* Overridden */ - IStream_fnWrite, - IStream_fnSeek, - IStream_fnSetSize, - IStream_fnCopyTo, - IStream_fnCommit, - IStream_fnRevert, - IStream_fnLockUnlockRegion, - IStream_fnLockUnlockRegion, - IStream_fnStat, - IStream_fnClone -}; - -/* Dummy registry stream object */ -static ISHRegStream rsDummyRegStream = -{ - &DummyRegStreamVTable, - 1, - NULL, - NULL, - 0, - 0 -}; - -/************************************************************************** - * IStream_Create - * - * Internal helper: Create and initialise a new registry stream object. - */ -static IStream *IStream_Create(HKEY hKey, LPBYTE pbBuffer, DWORD dwLength) -{ - ISHRegStream* regStream; - - regStream = HeapAlloc(GetProcessHeap(), 0, sizeof(ISHRegStream)); - - if (regStream) - { - regStream->lpVtbl = &rstvt; - regStream->ref = 1; - regStream->hKey = hKey; - regStream->pbBuffer = pbBuffer; - regStream->dwLength = dwLength; - regStream->dwPos = 0; - } - TRACE ("Returning %p\n", regStream); - return (IStream *)regStream; -} - -/************************************************************************* - * SHOpenRegStream2A [SHLWAPI.@] - * - * Create a stream to read binary registry data. - * - * PARAMS - * hKey [I] Registry handle - * pszSubkey [I] The sub key name - * pszValue [I] The value name under the sub key - * dwMode [I] Unused - * - * RETURNS - * Success: An IStream interface referring to the registry data - * Failure: NULL, if the registry key could not be opened or is not binary. - */ -IStream * WINAPI SHOpenRegStream2A(HKEY hKey, LPCSTR pszSubkey, - LPCSTR pszValue,DWORD dwMode) -{ - HKEY hStrKey = NULL; - LPBYTE lpBuff = NULL; - DWORD dwLength, dwType; - - TRACE("(%p,%s,%s,0x%08lx)\n", hKey, pszSubkey, pszValue, dwMode); - - /* Open the key, read in binary data and create stream */ - if (!RegOpenKeyExA (hKey, pszSubkey, 0, KEY_READ, &hStrKey) && - !RegQueryValueExA (hStrKey, pszValue, 0, 0, 0, &dwLength) && - (lpBuff = HeapAlloc (GetProcessHeap(), 0, dwLength)) && - !RegQueryValueExA (hStrKey, pszValue, 0, &dwType, lpBuff, &dwLength) && - dwType == REG_BINARY) - return IStream_Create(hStrKey, lpBuff, dwLength); - - HeapFree (GetProcessHeap(), 0, lpBuff); - if (hStrKey) - RegCloseKey(hStrKey); - return NULL; -} - -/************************************************************************* - * SHOpenRegStream2W [SHLWAPI.@] - * - * See SHOpenRegStream2A. - */ -IStream * WINAPI SHOpenRegStream2W(HKEY hKey, LPCWSTR pszSubkey, - LPCWSTR pszValue, DWORD dwMode) -{ - HKEY hStrKey = NULL; - LPBYTE lpBuff = NULL; - DWORD dwLength, dwType; - - TRACE("(%p,%s,%s,0x%08lx)\n", hKey, debugstr_w(pszSubkey), - debugstr_w(pszValue), dwMode); - - /* Open the key, read in binary data and create stream */ - if (!RegOpenKeyExW (hKey, pszSubkey, 0, KEY_READ, &hStrKey) && - !RegQueryValueExW (hStrKey, pszValue, 0, 0, 0, &dwLength) && - (lpBuff = HeapAlloc (GetProcessHeap(), 0, dwLength)) && - !RegQueryValueExW (hStrKey, pszValue, 0, &dwType, lpBuff, &dwLength) && - dwType == REG_BINARY) - return IStream_Create(hStrKey, lpBuff, dwLength); - - HeapFree (GetProcessHeap(), 0, lpBuff); - if (hStrKey) - RegCloseKey(hStrKey); - return NULL; -} - -/************************************************************************* - * SHOpenRegStreamA [SHLWAPI.@] - * - * Create a stream to read binary registry data. - * - * PARAMS - * hKey [I] Registry handle - * pszSubkey [I] The sub key name - * pszValue [I] The value name under the sub key - * dwMode [I] STGM mode for opening the file - * - * RETURNS - * Success: An IStream interface referring to the registry data - * Failure: If the registry key could not be opened or is not binary, - * A dummy (empty) IStream object is returned. - */ -IStream * WINAPI SHOpenRegStreamA(HKEY hkey, LPCSTR pszSubkey, - LPCSTR pszValue, DWORD dwMode) -{ - IStream *iStream; - - TRACE("(%p,%s,%s,0x%08lx)\n", hkey, pszSubkey, pszValue, dwMode); - - iStream = SHOpenRegStream2A(hkey, pszSubkey, pszValue, dwMode); - return iStream ? iStream : (IStream *)&rsDummyRegStream; -} - -/************************************************************************* - * SHOpenRegStreamW [SHLWAPI.@] - * - * See SHOpenRegStreamA. - */ -IStream * WINAPI SHOpenRegStreamW(HKEY hkey, LPCWSTR pszSubkey, - LPCWSTR pszValue, DWORD dwMode) -{ - IStream *iStream; - - TRACE("(%p,%s,%s,0x%08lx)\n", hkey, debugstr_w(pszSubkey), - debugstr_w(pszValue), dwMode); - iStream = SHOpenRegStream2W(hkey, pszSubkey, pszValue, dwMode); - return iStream ? iStream : (IStream *)&rsDummyRegStream; -} - -/************************************************************************* - * @ [SHLWAPI.12] - * - * Create an IStream object on a block of memory. - * - * PARAMS - * lpbData [I] Memory block to create the IStream object on - * dwDataLen [I] Length of data block - * - * RETURNS - * Success: A pointer to the IStream object. - * Failure: NULL, if any parameters are invalid or an error occurs. - * - * NOTES - * A copy of the memory pointed to by lpbData is made, and is freed - * when the stream is released. - */ -IStream * WINAPI SHCreateMemStream(LPBYTE lpbData, DWORD dwDataLen) -{ - IStream *iStrmRet = NULL; - - TRACE("(%p,%ld)\n", lpbData, dwDataLen); - - if (lpbData) - { - LPBYTE lpbDup = HeapAlloc(GetProcessHeap(), 0, dwDataLen); - - if (lpbDup) - { - memcpy(lpbDup, lpbData, dwDataLen); - iStrmRet = IStream_Create(NULL, lpbDup, dwDataLen); - - if (!iStrmRet) - HeapFree(GetProcessHeap(), 0, lpbDup); - } - } - return iStrmRet; -} - -/************************************************************************* - * SHCreateStreamWrapper [SHLWAPI.@] - * - * Create an IStream object on a block of memory. - * - * PARAMS - * lpbData [I] Memory block to create the IStream object on - * dwDataLen [I] Length of data block - * dwReserved [I] Reserved, Must be 0. - * lppStream [O] Destination for IStream object - * - * RETURNS - * Success: S_OK. lppStream contains the new IStream object. - * Failure: E_INVALIDARG, if any parameters are invalid, - * E_OUTOFMEMORY if memory allocation fails. - * - * NOTES - * The stream assumes ownership of the memory passed to it. - */ -HRESULT WINAPI SHCreateStreamWrapper(LPBYTE lpbData, DWORD dwDataLen, - DWORD dwReserved, IStream **lppStream) -{ - IStream* lpStream; - - if (lppStream) - *lppStream = NULL; - - if(dwReserved || !lppStream) - return E_INVALIDARG; - - lpStream = IStream_Create(NULL, lpbData, dwDataLen); - - if(!lpStream) - return E_OUTOFMEMORY; - - IStream_QueryInterface(lpStream, &IID_IStream, (void**)lppStream); - IStream_Release(lpStream); - return S_OK; -} +/* + * SHLWAPI Registry Stream functions + * + * Copyright 1999 Juergen Schmied + * Copyright 2002 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> +#include <string.h> + +#define COBJMACROS + +#include "winerror.h" +#include "windef.h" +#include "winbase.h" +#include "objbase.h" +#include "winreg.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +typedef struct +{ IStreamVtbl *lpVtbl; + DWORD ref; + HKEY hKey; + LPBYTE pbBuffer; + DWORD dwLength; + DWORD dwPos; +} ISHRegStream; + +/************************************************************************** +* IStream_fnQueryInterface +*/ +static HRESULT WINAPI IStream_fnQueryInterface(IStream *iface, REFIID riid, LPVOID *ppvObj) +{ + ISHRegStream *This = (ISHRegStream *)iface; + + TRACE("(%p)->(\n\tIID:\t%s,%p)\n",This,debugstr_guid(riid),ppvObj); + + *ppvObj = NULL; + + if(IsEqualIID(riid, &IID_IUnknown)) /*IUnknown*/ + *ppvObj = This; + else if(IsEqualIID(riid, &IID_IStream)) /*IStream*/ + *ppvObj = This; + + if(*ppvObj) + { + IStream_AddRef((IStream*)*ppvObj); + TRACE("-- Interface: (%p)->(%p)\n",ppvObj,*ppvObj); + return S_OK; + } + TRACE("-- Interface: E_NOINTERFACE\n"); + return E_NOINTERFACE; +} + +/************************************************************************** +* IStream_fnAddRef +*/ +static ULONG WINAPI IStream_fnAddRef(IStream *iface) +{ + ISHRegStream *This = (ISHRegStream *)iface; + ULONG refCount = InterlockedIncrement(&This->ref); + + TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1); + + return refCount; +} + +/************************************************************************** +* IStream_fnRelease +*/ +static ULONG WINAPI IStream_fnRelease(IStream *iface) +{ + ISHRegStream *This = (ISHRegStream *)iface; + ULONG refCount = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1); + + if (!refCount) + { + TRACE(" destroying SHReg IStream (%p)\n",This); + + HeapFree(GetProcessHeap(),0,This->pbBuffer); + + if (This->hKey) + RegCloseKey(This->hKey); + + HeapFree(GetProcessHeap(),0,This); + return 0; + } + + return refCount; +} + +/************************************************************************** + * IStream_fnRead + */ +static HRESULT WINAPI IStream_fnRead (IStream * iface, void* pv, ULONG cb, ULONG* pcbRead) +{ + ISHRegStream *This = (ISHRegStream *)iface; + + DWORD dwBytesToRead, dwBytesLeft; + + TRACE("(%p)->(%p,0x%08lx,%p)\n",This, pv, cb, pcbRead); + + if (!pv) + return STG_E_INVALIDPOINTER; + + dwBytesLeft = This->dwLength - This->dwPos; + + if ( 0 >= dwBytesLeft ) /* end of buffer */ + return S_FALSE; + + dwBytesToRead = ( cb > dwBytesLeft) ? dwBytesLeft : cb; + + memmove ( pv, (This->pbBuffer) + (This->dwPos), dwBytesToRead); + + This->dwPos += dwBytesToRead; /* adjust pointer */ + + if (pcbRead) + *pcbRead = dwBytesToRead; + + return S_OK; +} + +/************************************************************************** + * IStream_fnWrite + */ +static HRESULT WINAPI IStream_fnWrite (IStream * iface, const void* pv, ULONG cb, ULONG* pcbWritten) +{ + ISHRegStream *This = (ISHRegStream *)iface; + + TRACE("(%p)\n",This); + + if (pcbWritten) + *pcbWritten = 0; + + return E_NOTIMPL; +} + +/************************************************************************** + * IStream_fnSeek + */ +static HRESULT WINAPI IStream_fnSeek (IStream * iface, LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) +{ + ISHRegStream *This = (ISHRegStream *)iface; + + TRACE("(%p)\n",This); + + if (plibNewPosition) + plibNewPosition->QuadPart = 0; + return E_NOTIMPL; +} + +/************************************************************************** + * IStream_fnSetSize + */ +static HRESULT WINAPI IStream_fnSetSize (IStream * iface, ULARGE_INTEGER libNewSize) +{ + ISHRegStream *This = (ISHRegStream *)iface; + + TRACE("(%p)\n",This); + return E_NOTIMPL; +} + +/************************************************************************** + * IStream_fnCopyTo + */ +static HRESULT WINAPI IStream_fnCopyTo (IStream * iface, IStream* pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) +{ + ISHRegStream *This = (ISHRegStream *)iface; + + TRACE("(%p)\n",This); + if (pcbRead) + pcbRead->QuadPart = 0; + if (pcbWritten) + pcbWritten->QuadPart = 0; + return E_NOTIMPL; +} + +/************************************************************************** + * IStream_fnCommit + */ +static HRESULT WINAPI IStream_fnCommit (IStream * iface, DWORD grfCommitFlags) +{ + ISHRegStream *This = (ISHRegStream *)iface; + + TRACE("(%p)\n",This); + + return E_NOTIMPL; +} + +/************************************************************************** + * IStream_fnRevert + */ +static HRESULT WINAPI IStream_fnRevert (IStream * iface) +{ + ISHRegStream *This = (ISHRegStream *)iface; + + TRACE("(%p)\n",This); + + return E_NOTIMPL; +} + +/************************************************************************** + * IStream_fnLockUnlockRegion + */ +static HRESULT WINAPI IStream_fnLockUnlockRegion (IStream * iface, ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) +{ + ISHRegStream *This = (ISHRegStream *)iface; + + TRACE("(%p)\n",This); + + return E_NOTIMPL; +} + +/************************************************************************* + * IStream_fnStat + */ +static HRESULT WINAPI IStream_fnStat (IStream * iface, STATSTG* pstatstg, DWORD grfStatFlag) +{ + ISHRegStream *This = (ISHRegStream *)iface; + + TRACE("(%p)\n",This); + + return E_NOTIMPL; +} + +/************************************************************************* + * IStream_fnClone + */ +static HRESULT WINAPI IStream_fnClone (IStream * iface, IStream** ppstm) +{ + ISHRegStream *This = (ISHRegStream *)iface; + + TRACE("(%p)\n",This); + if (ppstm) + *ppstm = NULL; + return E_NOTIMPL; +} + +static struct IStreamVtbl rstvt = +{ + IStream_fnQueryInterface, + IStream_fnAddRef, + IStream_fnRelease, + IStream_fnRead, + IStream_fnWrite, + IStream_fnSeek, + IStream_fnSetSize, + IStream_fnCopyTo, + IStream_fnCommit, + IStream_fnRevert, + IStream_fnLockUnlockRegion, + IStream_fnLockUnlockRegion, + IStream_fnStat, + IStream_fnClone +}; + +/* Methods overridden by the dummy stream */ + +/************************************************************************** + * IStream_fnAddRefDummy + */ +static ULONG WINAPI IStream_fnAddRefDummy(IStream *iface) +{ + ISHRegStream *This = (ISHRegStream *)iface; + TRACE("(%p)\n", This); + return 2; +} + +/************************************************************************** + * IStream_fnReleaseDummy + */ +static ULONG WINAPI IStream_fnReleaseDummy(IStream *iface) +{ + ISHRegStream *This = (ISHRegStream *)iface; + TRACE("(%p)\n", This); + return 1; +} + +/************************************************************************** + * IStream_fnReadDummy + */ +static HRESULT WINAPI IStream_fnReadDummy(IStream *iface, LPVOID pv, ULONG cb, ULONG* pcbRead) +{ + if (pcbRead) + *pcbRead = 0; + return E_NOTIMPL; +} + +static struct IStreamVtbl DummyRegStreamVTable = +{ + IStream_fnQueryInterface, + IStream_fnAddRefDummy, /* Overridden */ + IStream_fnReleaseDummy, /* Overridden */ + IStream_fnReadDummy, /* Overridden */ + IStream_fnWrite, + IStream_fnSeek, + IStream_fnSetSize, + IStream_fnCopyTo, + IStream_fnCommit, + IStream_fnRevert, + IStream_fnLockUnlockRegion, + IStream_fnLockUnlockRegion, + IStream_fnStat, + IStream_fnClone +}; + +/* Dummy registry stream object */ +static ISHRegStream rsDummyRegStream = +{ + &DummyRegStreamVTable, + 1, + NULL, + NULL, + 0, + 0 +}; + +/************************************************************************** + * IStream_Create + * + * Internal helper: Create and initialise a new registry stream object. + */ +static IStream *IStream_Create(HKEY hKey, LPBYTE pbBuffer, DWORD dwLength) +{ + ISHRegStream* regStream; + + regStream = HeapAlloc(GetProcessHeap(), 0, sizeof(ISHRegStream)); + + if (regStream) + { + regStream->lpVtbl = &rstvt; + regStream->ref = 1; + regStream->hKey = hKey; + regStream->pbBuffer = pbBuffer; + regStream->dwLength = dwLength; + regStream->dwPos = 0; + } + TRACE ("Returning %p\n", regStream); + return (IStream *)regStream; +} + +/************************************************************************* + * SHOpenRegStream2A [SHLWAPI.@] + * + * Create a stream to read binary registry data. + * + * PARAMS + * hKey [I] Registry handle + * pszSubkey [I] The sub key name + * pszValue [I] The value name under the sub key + * dwMode [I] Unused + * + * RETURNS + * Success: An IStream interface referring to the registry data + * Failure: NULL, if the registry key could not be opened or is not binary. + */ +IStream * WINAPI SHOpenRegStream2A(HKEY hKey, LPCSTR pszSubkey, + LPCSTR pszValue,DWORD dwMode) +{ + HKEY hStrKey = NULL; + LPBYTE lpBuff = NULL; + DWORD dwLength, dwType; + + TRACE("(%p,%s,%s,0x%08lx)\n", hKey, pszSubkey, pszValue, dwMode); + + /* Open the key, read in binary data and create stream */ + if (!RegOpenKeyExA (hKey, pszSubkey, 0, KEY_READ, &hStrKey) && + !RegQueryValueExA (hStrKey, pszValue, 0, 0, 0, &dwLength) && + (lpBuff = HeapAlloc (GetProcessHeap(), 0, dwLength)) && + !RegQueryValueExA (hStrKey, pszValue, 0, &dwType, lpBuff, &dwLength) && + dwType == REG_BINARY) + return IStream_Create(hStrKey, lpBuff, dwLength); + + HeapFree (GetProcessHeap(), 0, lpBuff); + if (hStrKey) + RegCloseKey(hStrKey); + return NULL; +} + +/************************************************************************* + * SHOpenRegStream2W [SHLWAPI.@] + * + * See SHOpenRegStream2A. + */ +IStream * WINAPI SHOpenRegStream2W(HKEY hKey, LPCWSTR pszSubkey, + LPCWSTR pszValue, DWORD dwMode) +{ + HKEY hStrKey = NULL; + LPBYTE lpBuff = NULL; + DWORD dwLength, dwType; + + TRACE("(%p,%s,%s,0x%08lx)\n", hKey, debugstr_w(pszSubkey), + debugstr_w(pszValue), dwMode); + + /* Open the key, read in binary data and create stream */ + if (!RegOpenKeyExW (hKey, pszSubkey, 0, KEY_READ, &hStrKey) && + !RegQueryValueExW (hStrKey, pszValue, 0, 0, 0, &dwLength) && + (lpBuff = HeapAlloc (GetProcessHeap(), 0, dwLength)) && + !RegQueryValueExW (hStrKey, pszValue, 0, &dwType, lpBuff, &dwLength) && + dwType == REG_BINARY) + return IStream_Create(hStrKey, lpBuff, dwLength); + + HeapFree (GetProcessHeap(), 0, lpBuff); + if (hStrKey) + RegCloseKey(hStrKey); + return NULL; +} + +/************************************************************************* + * SHOpenRegStreamA [SHLWAPI.@] + * + * Create a stream to read binary registry data. + * + * PARAMS + * hKey [I] Registry handle + * pszSubkey [I] The sub key name + * pszValue [I] The value name under the sub key + * dwMode [I] STGM mode for opening the file + * + * RETURNS + * Success: An IStream interface referring to the registry data + * Failure: If the registry key could not be opened or is not binary, + * A dummy (empty) IStream object is returned. + */ +IStream * WINAPI SHOpenRegStreamA(HKEY hkey, LPCSTR pszSubkey, + LPCSTR pszValue, DWORD dwMode) +{ + IStream *iStream; + + TRACE("(%p,%s,%s,0x%08lx)\n", hkey, pszSubkey, pszValue, dwMode); + + iStream = SHOpenRegStream2A(hkey, pszSubkey, pszValue, dwMode); + return iStream ? iStream : (IStream *)&rsDummyRegStream; +} + +/************************************************************************* + * SHOpenRegStreamW [SHLWAPI.@] + * + * See SHOpenRegStreamA. + */ +IStream * WINAPI SHOpenRegStreamW(HKEY hkey, LPCWSTR pszSubkey, + LPCWSTR pszValue, DWORD dwMode) +{ + IStream *iStream; + + TRACE("(%p,%s,%s,0x%08lx)\n", hkey, debugstr_w(pszSubkey), + debugstr_w(pszValue), dwMode); + iStream = SHOpenRegStream2W(hkey, pszSubkey, pszValue, dwMode); + return iStream ? iStream : (IStream *)&rsDummyRegStream; +} + +/************************************************************************* + * @ [SHLWAPI.12] + * + * Create an IStream object on a block of memory. + * + * PARAMS + * lpbData [I] Memory block to create the IStream object on + * dwDataLen [I] Length of data block + * + * RETURNS + * Success: A pointer to the IStream object. + * Failure: NULL, if any parameters are invalid or an error occurs. + * + * NOTES + * A copy of the memory pointed to by lpbData is made, and is freed + * when the stream is released. + */ +IStream * WINAPI SHCreateMemStream(LPBYTE lpbData, DWORD dwDataLen) +{ + IStream *iStrmRet = NULL; + + TRACE("(%p,%ld)\n", lpbData, dwDataLen); + + if (lpbData) + { + LPBYTE lpbDup = HeapAlloc(GetProcessHeap(), 0, dwDataLen); + + if (lpbDup) + { + memcpy(lpbDup, lpbData, dwDataLen); + iStrmRet = IStream_Create(NULL, lpbDup, dwDataLen); + + if (!iStrmRet) + HeapFree(GetProcessHeap(), 0, lpbDup); + } + } + return iStrmRet; +} + +/************************************************************************* + * SHCreateStreamWrapper [SHLWAPI.@] + * + * Create an IStream object on a block of memory. + * + * PARAMS + * lpbData [I] Memory block to create the IStream object on + * dwDataLen [I] Length of data block + * dwReserved [I] Reserved, Must be 0. + * lppStream [O] Destination for IStream object + * + * RETURNS + * Success: S_OK. lppStream contains the new IStream object. + * Failure: E_INVALIDARG, if any parameters are invalid, + * E_OUTOFMEMORY if memory allocation fails. + * + * NOTES + * The stream assumes ownership of the memory passed to it. + */ +HRESULT WINAPI SHCreateStreamWrapper(LPBYTE lpbData, DWORD dwDataLen, + DWORD dwReserved, IStream **lppStream) +{ + IStream* lpStream; + + if (lppStream) + *lppStream = NULL; + + if(dwReserved || !lppStream) + return E_INVALIDARG; + + lpStream = IStream_Create(NULL, lpbData, dwDataLen); + + if(!lpStream) + return E_OUTOFMEMORY; + + IStream_QueryInterface(lpStream, &IID_IStream, (void**)lppStream); + IStream_Release(lpStream); + return S_OK; +} diff --git a/reactos/lib/shlwapi/resource.h b/reactos/lib/shlwapi/resource.h index c971b246ff9..d922ceb3e08 100644 --- a/reactos/lib/shlwapi/resource.h +++ b/reactos/lib/shlwapi/resource.h @@ -1,29 +1,29 @@ -/* - * Resource defines for shlwapi - * - * Copyright 2004 Jon Griffiths - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef WINE_SHLWAPI_RESOURCE_H -#define WINE_SHLWAPI_RESOURCE_H - -/* These numbers match native ID's and shouldn't be abitrarily changed */ -#define IDD_ERR_DIALOG 0x1200 -#define IDS_ERR_USER_MSG 0x1201 -#define IDC_ERR_DONT_SHOW 0x1202 -#define IDS_ERR_USER_MSG2 0x1203 - -#endif /* WINE_SHLWAPI_RESOURCE_H */ +/* + * Resource defines for shlwapi + * + * Copyright 2004 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef WINE_SHLWAPI_RESOURCE_H +#define WINE_SHLWAPI_RESOURCE_H + +/* These numbers match native ID's and shouldn't be abitrarily changed */ +#define IDD_ERR_DIALOG 0x1200 +#define IDS_ERR_USER_MSG 0x1201 +#define IDC_ERR_DONT_SHOW 0x1202 +#define IDS_ERR_USER_MSG2 0x1203 + +#endif /* WINE_SHLWAPI_RESOURCE_H */ diff --git a/reactos/lib/shlwapi/shlwapi_main.c b/reactos/lib/shlwapi/shlwapi_main.c index 44e5f87e4d3..5d68bb71971 100644 --- a/reactos/lib/shlwapi/shlwapi_main.c +++ b/reactos/lib/shlwapi/shlwapi_main.c @@ -1,130 +1,130 @@ -/* - * SHLWAPI initialisation - * - * Copyright 1998 Marcus Meissner - * Copyright 1998 Juergen Schmied (jsch) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "wine/debug.h" -#define NO_SHLWAPI_REG -#define NO_SHLWAPI_STREAM -#include "shlwapi.h" - -WINE_DEFAULT_DEBUG_CHANNEL(shell); - -HINSTANCE shlwapi_hInstance = 0; -HMODULE SHLWAPI_hshell32 = 0; -HMODULE SHLWAPI_hwinmm = 0; -HMODULE SHLWAPI_hcomdlg32 = 0; -HMODULE SHLWAPI_hcomctl32 = 0; -HMODULE SHLWAPI_hmpr = 0; -HMODULE SHLWAPI_hmlang = 0; -HMODULE SHLWAPI_hurlmon = 0; -HMODULE SHLWAPI_hversion = 0; - -DWORD SHLWAPI_ThreadRef_index = TLS_OUT_OF_INDEXES; - -/************************************************************************* - * SHLWAPI {SHLWAPI} - * - * The Shell Light-Weight Api dll provides a large number of utility functions - * which are commonly required by Win32 programs. Originally distributed with - * Internet Explorer as a free download, it became a core part of Windows when - * Internet Explorer was 'integrated' into the O/S with the release of Win98. - * - * All functions exported by ordinal are undocumented by MS. The vast majority - * of these are wrappers for Unicode functions that may not exist on early 16 - * bit platforms. The remainder perform various small tasks and presumably were - * added to facilitate code reuse amongst the MS developers. - */ - -/************************************************************************* - * SHLWAPI DllMain - * - * NOTES - * calling oleinitialize here breaks sone apps. - */ -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad) -{ - TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad); - switch (fdwReason) - { - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(hinstDLL); - shlwapi_hInstance = hinstDLL; - SHLWAPI_ThreadRef_index = TlsAlloc(); - break; - case DLL_PROCESS_DETACH: - if (SHLWAPI_hshell32) FreeLibrary(SHLWAPI_hshell32); - if (SHLWAPI_hwinmm) FreeLibrary(SHLWAPI_hwinmm); - if (SHLWAPI_hcomdlg32) FreeLibrary(SHLWAPI_hcomdlg32); - if (SHLWAPI_hcomctl32) FreeLibrary(SHLWAPI_hcomctl32); - if (SHLWAPI_hmpr) FreeLibrary(SHLWAPI_hmpr); - if (SHLWAPI_hmlang) FreeLibrary(SHLWAPI_hmlang); - if (SHLWAPI_hurlmon) FreeLibrary(SHLWAPI_hurlmon); - if (SHLWAPI_hversion) FreeLibrary(SHLWAPI_hversion); - if (SHLWAPI_ThreadRef_index != TLS_OUT_OF_INDEXES) TlsFree(SHLWAPI_ThreadRef_index); - break; - } - return TRUE; -} - -/*********************************************************************** - * DllGetVersion [SHLWAPI.@] - * - * Retrieve "shlwapi.dll" version information. - * - * PARAMS - * pdvi [O] pointer to version information structure. - * - * RETURNS - * Success: S_OK. pdvi is updated with the version information - * Failure: E_INVALIDARG, if pdvi->cbSize is not set correctly. - * - * NOTES - * You may pass either a DLLVERSIONINFO of DLLVERSIONINFO2 structure - * as pdvi, provided that the size is set correctly. - * Returns version as shlwapi.dll from IE5.01. - */ -HRESULT WINAPI SHLWAPI_DllGetVersion (DLLVERSIONINFO *pdvi) -{ - DLLVERSIONINFO2 *pdvi2 = (DLLVERSIONINFO2*)pdvi; - - TRACE("(%p)\n",pdvi); - - switch (pdvi2->info1.cbSize) - { - case sizeof(DLLVERSIONINFO2): - pdvi2->dwFlags = 0; - pdvi2->ullVersion = MAKEDLLVERULL(5, 0, 2314, 0); - /* Fall through */ - case sizeof(DLLVERSIONINFO): - pdvi2->info1.dwMajorVersion = 5; - pdvi2->info1.dwMinorVersion = 0; - pdvi2->info1.dwBuildNumber = 2314; - pdvi2->info1.dwPlatformID = 1000; - return S_OK; - } - if (pdvi) - WARN("pdvi->cbSize = %ld, unhandled\n", pdvi2->info1.cbSize); - return E_INVALIDARG; -} +/* + * SHLWAPI initialisation + * + * Copyright 1998 Marcus Meissner + * Copyright 1998 Juergen Schmied (jsch) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wine/debug.h" +#define NO_SHLWAPI_REG +#define NO_SHLWAPI_STREAM +#include "shlwapi.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +HINSTANCE shlwapi_hInstance = 0; +HMODULE SHLWAPI_hshell32 = 0; +HMODULE SHLWAPI_hwinmm = 0; +HMODULE SHLWAPI_hcomdlg32 = 0; +HMODULE SHLWAPI_hcomctl32 = 0; +HMODULE SHLWAPI_hmpr = 0; +HMODULE SHLWAPI_hmlang = 0; +HMODULE SHLWAPI_hurlmon = 0; +HMODULE SHLWAPI_hversion = 0; + +DWORD SHLWAPI_ThreadRef_index = TLS_OUT_OF_INDEXES; + +/************************************************************************* + * SHLWAPI {SHLWAPI} + * + * The Shell Light-Weight Api dll provides a large number of utility functions + * which are commonly required by Win32 programs. Originally distributed with + * Internet Explorer as a free download, it became a core part of Windows when + * Internet Explorer was 'integrated' into the O/S with the release of Win98. + * + * All functions exported by ordinal are undocumented by MS. The vast majority + * of these are wrappers for Unicode functions that may not exist on early 16 + * bit platforms. The remainder perform various small tasks and presumably were + * added to facilitate code reuse amongst the MS developers. + */ + +/************************************************************************* + * SHLWAPI DllMain + * + * NOTES + * calling oleinitialize here breaks sone apps. + */ +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad) +{ + TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad); + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDLL); + shlwapi_hInstance = hinstDLL; + SHLWAPI_ThreadRef_index = TlsAlloc(); + break; + case DLL_PROCESS_DETACH: + if (SHLWAPI_hshell32) FreeLibrary(SHLWAPI_hshell32); + if (SHLWAPI_hwinmm) FreeLibrary(SHLWAPI_hwinmm); + if (SHLWAPI_hcomdlg32) FreeLibrary(SHLWAPI_hcomdlg32); + if (SHLWAPI_hcomctl32) FreeLibrary(SHLWAPI_hcomctl32); + if (SHLWAPI_hmpr) FreeLibrary(SHLWAPI_hmpr); + if (SHLWAPI_hmlang) FreeLibrary(SHLWAPI_hmlang); + if (SHLWAPI_hurlmon) FreeLibrary(SHLWAPI_hurlmon); + if (SHLWAPI_hversion) FreeLibrary(SHLWAPI_hversion); + if (SHLWAPI_ThreadRef_index != TLS_OUT_OF_INDEXES) TlsFree(SHLWAPI_ThreadRef_index); + break; + } + return TRUE; +} + +/*********************************************************************** + * DllGetVersion [SHLWAPI.@] + * + * Retrieve "shlwapi.dll" version information. + * + * PARAMS + * pdvi [O] pointer to version information structure. + * + * RETURNS + * Success: S_OK. pdvi is updated with the version information + * Failure: E_INVALIDARG, if pdvi->cbSize is not set correctly. + * + * NOTES + * You may pass either a DLLVERSIONINFO of DLLVERSIONINFO2 structure + * as pdvi, provided that the size is set correctly. + * Returns version as shlwapi.dll from IE5.01. + */ +HRESULT WINAPI SHLWAPI_DllGetVersion (DLLVERSIONINFO *pdvi) +{ + DLLVERSIONINFO2 *pdvi2 = (DLLVERSIONINFO2*)pdvi; + + TRACE("(%p)\n",pdvi); + + switch (pdvi2->info1.cbSize) + { + case sizeof(DLLVERSIONINFO2): + pdvi2->dwFlags = 0; + pdvi2->ullVersion = MAKEDLLVERULL(5, 0, 2314, 0); + /* Fall through */ + case sizeof(DLLVERSIONINFO): + pdvi2->info1.dwMajorVersion = 5; + pdvi2->info1.dwMinorVersion = 0; + pdvi2->info1.dwBuildNumber = 2314; + pdvi2->info1.dwPlatformID = 1000; + return S_OK; + } + if (pdvi) + WARN("pdvi->cbSize = %ld, unhandled\n", pdvi2->info1.cbSize); + return E_INVALIDARG; +} diff --git a/reactos/lib/shlwapi/stopwatch.c b/reactos/lib/shlwapi/stopwatch.c index 406c0821ed8..4e092a45050 100644 --- a/reactos/lib/shlwapi/stopwatch.c +++ b/reactos/lib/shlwapi/stopwatch.c @@ -1,226 +1,226 @@ -/* - * Stopwatch Functions - * - * Copyright 2004 Jon Griffiths - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTES - * These functions probably never need to be implemented unless we - * A) Rewrite explorer from scratch, and - * B) Want to use a substandard API to tune its performance. - */ - -#include "config.h" -#include "wine/port.h" - -#include <stdarg.h> -#include <string.h> -#include <stdlib.h> - -#define NONAMELESSUNION -#define NONAMELESSSTRUCT -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "winternl.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(shell); - -/************************************************************************* - * @ [SHLWAPI.241] - * - * Get the current performance monitoring mode. - * - * PARAMS - * None. - * - * RETURNS - * The current performance monitoring mode. This is zero if monitoring - * is disabled (the default). - * - * NOTES - * If this function returns 0, no further StopWatch functions should be called. - */ -DWORD WINAPI StopWatchMode() -{ - FIXME("() stub!\n"); - return 0; -} - -/************************************************************************* - * @ [SHLWAPI.242] - * - * Write captured performance nodes to a log file. - * - * PARAMS - * None. - * - * RETURNS - * Nothing. - */ -void WINAPI StopWatchFlush() -{ - FIXME("() stub!\n"); -} - -/************************************************************************* - * @ [SHLWAPI.244] - * - * Write a performance event to a log file - * - * PARAMS - * dwClass [I] Class of event - * lpszStr [I] Text of event to log - * dwUnknown [I] Unknown - * dwMode [I] Mode flags - * dwTimeStamp [I] Timestamp - * - * RETURNS - * Success: ERROR_SUCCESS. - * Failure: A standard Win32 error code indicating the failure. - */ -DWORD WINAPI StopWatchW(DWORD dwClass, LPCWSTR lpszStr, DWORD dwUnknown, - DWORD dwMode, DWORD dwTimeStamp) -{ - FIXME("(%ld,%s,%ld,%ld,%ld) stub!\n", dwClass, debugstr_w(lpszStr), - dwUnknown, dwMode, dwTimeStamp); - return ERROR_SUCCESS; -} - -/************************************************************************* - * @ [SHLWAPI.243] - * - * See StopWatchW. - */ -DWORD WINAPI StopWatchA(DWORD dwClass, LPCSTR lpszStr, DWORD dwUnknown, - DWORD dwMode, DWORD dwTimeStamp) -{ DWORD retval; - UNICODE_STRING szStrW; - - if(lpszStr) RtlCreateUnicodeStringFromAsciiz(&szStrW, lpszStr); - else szStrW.Buffer = NULL; - - retval = StopWatchW(dwClass, szStrW.Buffer, dwUnknown, dwMode, dwTimeStamp); - - RtlFreeUnicodeString(&szStrW); - return retval; -} - -/************************************************************************* - * @ [SHLWAPI.245] - * - * Log a shell frame event. - * - * PARAMS - * hWnd [I] Window having the event - * pvUnknown1 [I] Unknown - * bUnknown2 [I] Unknown - * pClassWnd [I] Window of class to log - * - * RETURNS - * Nothing. - */ -void WINAPI StopWatch_TimerHandler(HWND hWnd, PVOID pvUnknown1, BOOL bUnknown2, HWND *pClassWnd) -{ - FIXME("(%p,%p,%d,%p) stub!\n", hWnd, pvUnknown1, bUnknown2 ,pClassWnd); -} - -/* FIXME: Parameters for @246:StopWatch_CheckMsg unknown */ - -/************************************************************************* - * @ [SHLWAPI.247] - * - * Log the start of an applet. - * - * PARAMS - * lpszName [I] Name of the applet - * - * RETURNS - * Nothing. - */ -void WINAPI StopWatch_MarkFrameStart(LPCSTR lpszName) -{ - FIXME("(%s) stub!\n", debugstr_a(lpszName)); -} - -/* FIXME: Parameters for @248:StopWatch_MarkSameFrameStart unknown */ - -/************************************************************************* - * @ [SHLWAPI.249] - * - * Log a java applet stopping. - * - * PARAMS - * lpszEvent [I] Name of the event (applet) - * hWnd [I] Window running the applet - * dwReserved [I] Unused - * - * RETURNS - * Nothing. - */ -void WINAPI StopWatch_MarkJavaStop(LPCWSTR lpszEvent, HWND hWnd, DWORD dwReserved) -{ - FIXME("(%s,%p,0x%08lx) stub!\n", debugstr_w(lpszEvent), hWnd, dwReserved); -} - -/************************************************************************* - * @ [SHLWAPI.250] - * - * Read the performance counter. - * - * PARAMS - * None. - * - * RETURNS - * The low 32 bits of the current performance counter reading. - */ -DWORD WINAPI GetPerfTime() -{ - static LONG64 iCounterFreq = 0; - LARGE_INTEGER iCounter; - - TRACE("()\n"); - - if (!iCounterFreq) - QueryPerformanceFrequency((LARGE_INTEGER*)&iCounterFreq); - - QueryPerformanceCounter(&iCounter); - iCounter.QuadPart = iCounter.QuadPart * 1000 / iCounterFreq; - return iCounter.u.LowPart; -} - -/* FIXME: Parameters for @251:StopWatch_DispatchTime unknown */ - -/************************************************************************* - * @ [SHLWAPI.252] - * - * Set an as yet unidentified performance value. - * - * PARAMS - * dwUnknown [I] Value to set - * - * RETURNS - * dwUnknown. - */ -DWORD WINAPI StopWatch_SetMsgLastLocation(DWORD dwUnknown) -{ - FIXME("(%ld) stub!\n", dwUnknown); - - return dwUnknown; -} - -/* FIXME: Parameters for @253:StopWatchExA, 254:StopWatchExW unknown */ +/* + * Stopwatch Functions + * + * Copyright 2004 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTES + * These functions probably never need to be implemented unless we + * A) Rewrite explorer from scratch, and + * B) Want to use a substandard API to tune its performance. + */ + +#include "config.h" +#include "wine/port.h" + +#include <stdarg.h> +#include <string.h> +#include <stdlib.h> + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winternl.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/************************************************************************* + * @ [SHLWAPI.241] + * + * Get the current performance monitoring mode. + * + * PARAMS + * None. + * + * RETURNS + * The current performance monitoring mode. This is zero if monitoring + * is disabled (the default). + * + * NOTES + * If this function returns 0, no further StopWatch functions should be called. + */ +DWORD WINAPI StopWatchMode() +{ + FIXME("() stub!\n"); + return 0; +} + +/************************************************************************* + * @ [SHLWAPI.242] + * + * Write captured performance nodes to a log file. + * + * PARAMS + * None. + * + * RETURNS + * Nothing. + */ +void WINAPI StopWatchFlush() +{ + FIXME("() stub!\n"); +} + +/************************************************************************* + * @ [SHLWAPI.244] + * + * Write a performance event to a log file + * + * PARAMS + * dwClass [I] Class of event + * lpszStr [I] Text of event to log + * dwUnknown [I] Unknown + * dwMode [I] Mode flags + * dwTimeStamp [I] Timestamp + * + * RETURNS + * Success: ERROR_SUCCESS. + * Failure: A standard Win32 error code indicating the failure. + */ +DWORD WINAPI StopWatchW(DWORD dwClass, LPCWSTR lpszStr, DWORD dwUnknown, + DWORD dwMode, DWORD dwTimeStamp) +{ + FIXME("(%ld,%s,%ld,%ld,%ld) stub!\n", dwClass, debugstr_w(lpszStr), + dwUnknown, dwMode, dwTimeStamp); + return ERROR_SUCCESS; +} + +/************************************************************************* + * @ [SHLWAPI.243] + * + * See StopWatchW. + */ +DWORD WINAPI StopWatchA(DWORD dwClass, LPCSTR lpszStr, DWORD dwUnknown, + DWORD dwMode, DWORD dwTimeStamp) +{ DWORD retval; + UNICODE_STRING szStrW; + + if(lpszStr) RtlCreateUnicodeStringFromAsciiz(&szStrW, lpszStr); + else szStrW.Buffer = NULL; + + retval = StopWatchW(dwClass, szStrW.Buffer, dwUnknown, dwMode, dwTimeStamp); + + RtlFreeUnicodeString(&szStrW); + return retval; +} + +/************************************************************************* + * @ [SHLWAPI.245] + * + * Log a shell frame event. + * + * PARAMS + * hWnd [I] Window having the event + * pvUnknown1 [I] Unknown + * bUnknown2 [I] Unknown + * pClassWnd [I] Window of class to log + * + * RETURNS + * Nothing. + */ +void WINAPI StopWatch_TimerHandler(HWND hWnd, PVOID pvUnknown1, BOOL bUnknown2, HWND *pClassWnd) +{ + FIXME("(%p,%p,%d,%p) stub!\n", hWnd, pvUnknown1, bUnknown2 ,pClassWnd); +} + +/* FIXME: Parameters for @246:StopWatch_CheckMsg unknown */ + +/************************************************************************* + * @ [SHLWAPI.247] + * + * Log the start of an applet. + * + * PARAMS + * lpszName [I] Name of the applet + * + * RETURNS + * Nothing. + */ +void WINAPI StopWatch_MarkFrameStart(LPCSTR lpszName) +{ + FIXME("(%s) stub!\n", debugstr_a(lpszName)); +} + +/* FIXME: Parameters for @248:StopWatch_MarkSameFrameStart unknown */ + +/************************************************************************* + * @ [SHLWAPI.249] + * + * Log a java applet stopping. + * + * PARAMS + * lpszEvent [I] Name of the event (applet) + * hWnd [I] Window running the applet + * dwReserved [I] Unused + * + * RETURNS + * Nothing. + */ +void WINAPI StopWatch_MarkJavaStop(LPCWSTR lpszEvent, HWND hWnd, DWORD dwReserved) +{ + FIXME("(%s,%p,0x%08lx) stub!\n", debugstr_w(lpszEvent), hWnd, dwReserved); +} + +/************************************************************************* + * @ [SHLWAPI.250] + * + * Read the performance counter. + * + * PARAMS + * None. + * + * RETURNS + * The low 32 bits of the current performance counter reading. + */ +DWORD WINAPI GetPerfTime() +{ + static LONG64 iCounterFreq = 0; + LARGE_INTEGER iCounter; + + TRACE("()\n"); + + if (!iCounterFreq) + QueryPerformanceFrequency((LARGE_INTEGER*)&iCounterFreq); + + QueryPerformanceCounter(&iCounter); + iCounter.QuadPart = iCounter.QuadPart * 1000 / iCounterFreq; + return iCounter.u.LowPart; +} + +/* FIXME: Parameters for @251:StopWatch_DispatchTime unknown */ + +/************************************************************************* + * @ [SHLWAPI.252] + * + * Set an as yet unidentified performance value. + * + * PARAMS + * dwUnknown [I] Value to set + * + * RETURNS + * dwUnknown. + */ +DWORD WINAPI StopWatch_SetMsgLastLocation(DWORD dwUnknown) +{ + FIXME("(%ld) stub!\n", dwUnknown); + + return dwUnknown; +} + +/* FIXME: Parameters for @253:StopWatchExA, 254:StopWatchExW unknown */ diff --git a/reactos/lib/shlwapi/string.c b/reactos/lib/shlwapi/string.c index ae270452769..4e634f27f95 100644 --- a/reactos/lib/shlwapi/string.c +++ b/reactos/lib/shlwapi/string.c @@ -1,2701 +1,2701 @@ -/* - * Shlwapi string functions - * - * Copyright 1998 Juergen Schmied - * Copyright 2002 Jon Griffiths - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define COM_NO_WINDOWS_H -#include "config.h" -#include "wine/port.h" - -#include <math.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> -#include <ctype.h> - -#define NONAMELESSUNION -#define NONAMELESSSTRUCT -#include "windef.h" -#include "winbase.h" -#define NO_SHLWAPI_REG -#define NO_SHLWAPI_STREAM -#include "shlwapi.h" -#include "wingdi.h" -#include "winuser.h" -#include "shlobj.h" -#include "ddeml.h" -#include "wine/unicode.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(shell); - -/* Get a function pointer from a DLL handle */ -#define GET_FUNC(func, module, name, fail) \ - do { \ - if (!func) { \ - if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \ - func = (fn##func)GetProcAddress(SHLWAPI_h##module, name); \ - if (!func) return fail; \ - } \ - } while (0) - -extern HMODULE SHLWAPI_hmlang; - -typedef HRESULT (WINAPI *fnpConvertINetUnicodeToMultiByte)(LPDWORD,DWORD,LPCWSTR,LPINT,LPSTR,LPINT); -static fnpConvertINetUnicodeToMultiByte pConvertINetUnicodeToMultiByte; - -static HRESULT WINAPI _SHStrDupAA(LPCSTR,LPSTR*); -static HRESULT WINAPI _SHStrDupAW(LPCWSTR,LPSTR*); - -/************************************************************************* - * SHLWAPI_ChrCmpHelperA - * - * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA. - * - * NOTES - * Both this function and its Unicode counterpart are very inneficient. To - * fix this, CompareString must be completely implemented and optimised - * first. Then the core character test can be taken out of that function and - * placed here, so that it need never be called at all. Until then, do not - * attempt to optimise this code unless you are willing to test that it - * still performs correctly. - */ -static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags) -{ - char str1[3], str2[3]; - - str1[0] = LOBYTE(ch1); - if (IsDBCSLeadByte(str1[0])) - { - str1[1] = HIBYTE(ch1); - str1[2] = '\0'; - } - else - str1[1] = '\0'; - - str2[0] = LOBYTE(ch2); - if (IsDBCSLeadByte(str2[0])) - { - str2[1] = HIBYTE(ch2); - str2[2] = '\0'; - } - else - str2[1] = '\0'; - - return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2; -} - -/************************************************************************* - * SHLWAPI_ChrCmpHelperW - * - * Internal helper for SHLWAPI_ChrCmpW/ChrCmpIW. - */ -static BOOL WINAPI SHLWAPI_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags) -{ - WCHAR str1[2], str2[2]; - - str1[0] = ch1; - str1[1] = '\0'; - str2[0] = ch2; - str2[1] = '\0'; - return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2; -} - -/************************************************************************* - * SHLWAPI_ChrCmpA - * - * Internal helper function. - */ -static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2) -{ - return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0); -} - -/************************************************************************* - * ChrCmpIA (SHLWAPI.385) - * - * Compare two characters, ignoring case. - * - * PARAMS - * ch1 [I] First character to compare - * ch2 [I] Second character to compare - * - * RETURNS - * FALSE, if the characters are equal. - * Non-zero otherwise. - */ -BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2) -{ - TRACE("(%d,%d)\n", ch1, ch2); - - return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE); -} - -/************************************************************************* - * SHLWAPI_ChrCmpW - * - * Internal helper function. - */ -static BOOL WINAPI SHLWAPI_ChrCmpW(WCHAR ch1, WCHAR ch2) -{ - return SHLWAPI_ChrCmpHelperW(ch1, ch2, 0); -} - -/************************************************************************* - * ChrCmpIW [SHLWAPI.386] - * - * See ChrCmpIA. - */ -BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2) -{ - return SHLWAPI_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE); -} - -/************************************************************************* - * StrChrA [SHLWAPI.@] - * - * Find a given character in a string. - * - * PARAMS - * lpszStr [I] String to search in. - * ch [I] Character to search for. - * - * RETURNS - * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if - * not found. - * Failure: NULL, if any arguments are invalid. - */ -LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch) -{ - TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch); - - if (lpszStr) - { - while (*lpszStr) - { - if (!SHLWAPI_ChrCmpA(*lpszStr, ch)) - return (LPSTR)lpszStr; - lpszStr = CharNextA(lpszStr); - } - } - return NULL; -} - -/************************************************************************* - * StrChrW [SHLWAPI.@] - * - * See StrChrA. - */ -LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch) -{ - LPWSTR lpszRet = NULL; - - TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch); - - if (lpszStr) - lpszRet = strchrW(lpszStr, ch); - return lpszRet; -} - -/************************************************************************* - * StrChrIA [SHLWAPI.@] - * - * Find a given character in a string, ignoring case. - * - * PARAMS - * lpszStr [I] String to search in. - * ch [I] Character to search for. - * - * RETURNS - * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if - * not found. - * Failure: NULL, if any arguments are invalid. - */ -LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch) -{ - TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch); - - if (lpszStr) - { - while (*lpszStr) - { - if (!ChrCmpIA(*lpszStr, ch)) - return (LPSTR)lpszStr; - lpszStr = CharNextA(lpszStr); - } - } - return NULL; -} - -/************************************************************************* - * StrChrIW [SHLWAPI.@] - * - * See StrChrA. - */ -LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch) -{ - TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch); - - if (lpszStr) - { - ch = toupperW(ch); - while (*lpszStr) - { - if (toupperW(*lpszStr) == ch) - return (LPWSTR)lpszStr; - lpszStr = CharNextW(lpszStr); - } - lpszStr = NULL; - } - return (LPWSTR)lpszStr; -} - -/************************************************************************* - * StrCmpIW [SHLWAPI.@] - * - * Compare two strings, ignoring case. - * - * PARAMS - * lpszStr [I] First string to compare - * lpszComp [I] Second string to compare - * - * RETURNS - * An integer less than, equal to or greater than 0, indicating that - * lpszStr is less than, the same, or greater than lpszComp. - */ -int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp) -{ - int iRet; - - TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp)); - - iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, -1, lpszComp, -1); - return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; -} - -/************************************************************************* - * StrCmpNA [SHLWAPI.@] - * - * Compare two strings, up to a maximum length. - * - * PARAMS - * lpszStr [I] First string to compare - * lpszComp [I] Second string to compare - * iLen [I] Maximum number of chars to compare. - * - * RETURNS - * An integer less than, equal to or greater than 0, indicating that - * lpszStr is less than, the same, or greater than lpszComp. - */ -INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen) -{ - INT iRet; - - TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen); - - iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen); - return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; -} - -/************************************************************************* - * StrCmpNW [SHLWAPI.@] - * - * See StrCmpNA. - */ -INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen) -{ - INT iRet; - - TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen); - - iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen); - return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; -} - -/************************************************************************* - * StrCmpNIA [SHLWAPI.@] - * - * Compare two strings, up to a maximum length, ignoring case. - * - * PARAMS - * lpszStr [I] First string to compare - * lpszComp [I] Second string to compare - * iLen [I] Maximum number of chars to compare. - * - * RETURNS - * An integer less than, equal to or greater than 0, indicating that - * lpszStr is less than, the same, or greater than lpszComp. - */ -int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen) -{ - INT iRet; - - TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen); - - iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen); - return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; -} - -/************************************************************************* - * StrCmpNIW [SHLWAPI.@] - * - * See StrCmpNIA. - */ -INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen) -{ - INT iRet; - - TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen); - - iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen); - return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; -} - -/************************************************************************* - * StrCmpW [SHLWAPI.@] - * - * Compare two strings. - * - * PARAMS - * lpszStr [I] First string to compare - * lpszComp [I] Second string to compare - * - * RETURNS - * An integer less than, equal to or greater than 0, indicating that - * lpszStr is less than, the same, or greater than lpszComp. - */ -int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp) -{ - INT iRet; - - TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp)); - - iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, -1, lpszComp, -1); - return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; -} - -/************************************************************************* - * StrCatW [SHLWAPI.@] - * - * Concatanate two strings. - * - * PARAMS - * lpszStr [O] Initial string - * lpszSrc [I] String to concatanate - * - * RETURNS - * lpszStr. - */ -LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc) -{ - TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc)); - - strcatW(lpszStr, lpszSrc); - return lpszStr; -} - -/************************************************************************* - * StrCpyW [SHLWAPI.@] - * - * Copy a string to another string. - * - * PARAMS - * lpszStr [O] Destination string - * lpszSrc [I] Source string - * - * RETURNS - * lpszStr. - */ -LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc) -{ - TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc)); - - strcpyW(lpszStr, lpszSrc); - return lpszStr; -} - -/************************************************************************* - * StrCpyNW [SHLWAPI.@] - * - * Copy a string to another string, up to a maximum number of characters. - * - * PARAMS - * lpszStr [O] Destination string - * lpszSrc [I] Source string - * iLen [I] Maximum number of chars to copy - * - * RETURNS - * lpszStr. - */ -LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen) -{ - TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen); - - lstrcpynW(lpszStr, lpszSrc, iLen); - return lpszStr; -} - - - -/************************************************************************* - * SHLWAPI_StrStrHelperA - * - * Internal implementation of StrStrA/StrStrIA - */ -static LPSTR WINAPI SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch, - int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t)) -{ - size_t iLen; - - if (!lpszStr || !lpszSearch || !*lpszSearch) - return NULL; - - iLen = strlen(lpszSearch); - - while (*lpszStr) - { - if (!pStrCmpFn(lpszStr, lpszSearch, iLen)) - return (LPSTR)lpszStr; - lpszStr = CharNextA(lpszStr); - } - return NULL; -} - -/************************************************************************* - * SHLWAPI_StrStrHelperW - * - * Internal implementation of StrStrW/StrStrIW - */ -static LPWSTR WINAPI SHLWAPI_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch, - int (*pStrCmpFn)(LPCWSTR,LPCWSTR,int)) -{ - int iLen; - - if (!lpszStr || !lpszSearch || !*lpszSearch) - return NULL; - - iLen = strlenW(lpszSearch); - - while (*lpszStr) - { - if (!pStrCmpFn(lpszStr, lpszSearch, iLen)) - return (LPWSTR)lpszStr; - lpszStr = CharNextW(lpszStr); - } - return NULL; -} - -/************************************************************************* - * StrStrA [SHLWAPI.@] - * - * Find a substring within a string. - * - * PARAMS - * lpszStr [I] String to search in - * lpszSearch [I] String to look for - * - * RETURNS - * The start of lpszSearch within lpszStr, or NULL if not found. - */ -LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch) -{ - TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch)); - - return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncmp); -} - -/************************************************************************* - * StrStrW [SHLWAPI.@] - * - * See StrStrA. - */ -LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch) -{ - TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch)); - - return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, (int (*)(LPCWSTR,LPCWSTR,int))wcsncmp); -} - -/************************************************************************* - * StrRStrIA [SHLWAPI.@] - * - * Find the last occurrence of a substring within a string. - * - * PARAMS - * lpszStr [I] String to search in - * lpszEnd [I] End of lpszStr - * lpszSearch [I] String to look for - * - * RETURNS - * The last occurrence lpszSearch within lpszStr, or NULL if not found. - */ -LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch) -{ - LPSTR lpszRet = NULL; - WORD ch1, ch2; - INT iLen; - - TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch)); - - if (!lpszStr || !lpszSearch || !*lpszSearch) - return NULL; - - if (!lpszEnd) - lpszEnd = lpszStr + lstrlenA(lpszStr); - - if (IsDBCSLeadByte(*lpszSearch)) - ch1 = *lpszSearch << 8 | lpszSearch[1]; - else - ch1 = *lpszSearch; - iLen = lstrlenA(lpszSearch); - - while (lpszStr <= lpszEnd && *lpszStr) - { - ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr; - if (!ChrCmpIA(ch1, ch2)) - { - if (!StrCmpNIA(lpszStr, lpszSearch, iLen)) - lpszRet = (LPSTR)lpszStr; - } - lpszStr = CharNextA(lpszStr); - } - return lpszRet; -} - -/************************************************************************* - * StrRStrIW [SHLWAPI.@] - * - * See StrRStrIA. - */ -LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch) -{ - LPWSTR lpszRet = NULL; - INT iLen; - - TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch)); - - if (!lpszStr || !lpszSearch || !*lpszSearch) - return NULL; - - if (!lpszEnd) - lpszEnd = lpszStr + strlenW(lpszStr); - - iLen = strlenW(lpszSearch); - - while (lpszStr <= lpszEnd && *lpszStr) - { - if (!ChrCmpIW(*lpszSearch, *lpszStr)) - { - if (!StrCmpNIW(lpszStr, lpszSearch, iLen)) - lpszRet = (LPWSTR)lpszStr; - } - lpszStr = CharNextW(lpszStr); - } - return lpszRet; -} - -/************************************************************************* - * StrStrIA [SHLWAPI.@] - * - * Find a substring within a string, ignoring case. - * - * PARAMS - * lpszStr [I] String to search in - * lpszSearch [I] String to look for - * - * RETURNS - * The start of lpszSearch within lpszStr, or NULL if not found. - */ -LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch) -{ - TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch)); - - return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncasecmp); -} - -/************************************************************************* - * StrStrIW [SHLWAPI.@] - * - * See StrStrIA. - */ -LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch) -{ - TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch)); - - return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, (int (*)(LPCWSTR,LPCWSTR,int))_wcsnicmp); -} - -/************************************************************************* - * StrToIntA [SHLWAPI.@] - * - * Read a signed integer from a string. - * - * PARAMS - * lpszStr [I] String to read integer from - * - * RETURNS - * The signed integer value represented by the string, or 0 if no integer is - * present. - * - * NOTES - * No leading space is allowed before the number, although a leading '-' is. - */ -int WINAPI StrToIntA(LPCSTR lpszStr) -{ - int iRet = 0; - - TRACE("(%s)\n", debugstr_a(lpszStr)); - - if (!lpszStr) - { - WARN("Invalid lpszStr would crash under Win32!\n"); - return 0; - } - - if (*lpszStr == '-' || isdigit(*lpszStr)) - StrToIntExA(lpszStr, 0, &iRet); - return iRet; -} - -/************************************************************************* - * StrToIntW [SHLWAPI.@] - * - * See StrToIntA. - */ -int WINAPI StrToIntW(LPCWSTR lpszStr) -{ - int iRet = 0; - - TRACE("(%s)\n", debugstr_w(lpszStr)); - - if (!lpszStr) - { - WARN("Invalid lpszStr would crash under Win32!\n"); - return 0; - } - - if (*lpszStr == '-' || isdigitW(*lpszStr)) - StrToIntExW(lpszStr, 0, &iRet); - return iRet; -} - -/************************************************************************* - * StrToIntExA [SHLWAPI.@] - * - * Read an integer from a string. - * - * PARAMS - * lpszStr [I] String to read integer from - * dwFlags [I] Flags controlling the conversion - * lpiRet [O] Destination for read integer. - * - * RETURNS - * Success: TRUE. lpiRet contains the integer value represented by the string. - * Failure: FALSE, if the string is invalid, or no number is present. - * - * NOTES - * Leading whitespace, '-' and '+' are allowed before the number. If - * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if - * preceded by '0x'. If this flag is not set, or there is no '0x' prefix, - * the string is treated as a decimal string. A leading '-' is ignored for - * hexadecimal numbers. - */ -BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet) -{ - BOOL bNegative = FALSE; - int iRet = 0; - - TRACE("(%s,%08lX,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet); - - if (!lpszStr || !lpiRet) - { - WARN("Invalid parameter would crash under Win32!\n"); - return FALSE; - } - if (dwFlags > STIF_SUPPORT_HEX) - { - WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX); - } - - /* Skip leading space, '+', '-' */ - while (isspace(*lpszStr)) - lpszStr = CharNextA(lpszStr); - - if (*lpszStr == '-') - { - bNegative = TRUE; - lpszStr++; - } - else if (*lpszStr == '+') - lpszStr++; - - if (dwFlags & STIF_SUPPORT_HEX && - *lpszStr == '0' && tolower(lpszStr[1]) == 'x') - { - /* Read hex number */ - lpszStr += 2; - - if (!isxdigit(*lpszStr)) - return FALSE; - - while (isxdigit(*lpszStr)) - { - iRet = iRet * 16; - if (isdigit(*lpszStr)) - iRet += (*lpszStr - '0'); - else - iRet += 10 + (tolower(*lpszStr) - 'a'); - lpszStr++; - } - *lpiRet = iRet; - return TRUE; - } - - /* Read decimal number */ - if (!isdigit(*lpszStr)) - return FALSE; - - while (isdigit(*lpszStr)) - { - iRet = iRet * 10; - iRet += (*lpszStr - '0'); - lpszStr++; - } - *lpiRet = bNegative ? -iRet : iRet; - return TRUE; -} - -/************************************************************************* - * StrToIntExW [SHLWAPI.@] - * - * See StrToIntExA. - */ -BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet) -{ - BOOL bNegative = FALSE; - int iRet = 0; - - TRACE("(%s,%08lX,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet); - - if (!lpszStr || !lpiRet) - { - WARN("Invalid parameter would crash under Win32!\n"); - return FALSE; - } - if (dwFlags > STIF_SUPPORT_HEX) - { - WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX); - } - - /* Skip leading space, '+', '-' */ - while (isspaceW(*lpszStr)) - lpszStr = CharNextW(lpszStr); - - if (*lpszStr == '-') - { - bNegative = TRUE; - lpszStr++; - } - else if (*lpszStr == '+') - lpszStr++; - - if (dwFlags & STIF_SUPPORT_HEX && - *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x') - { - /* Read hex number */ - lpszStr += 2; - - if (!isxdigitW(*lpszStr)) - return FALSE; - - while (isxdigitW(*lpszStr)) - { - iRet = iRet * 16; - if (isdigitW(*lpszStr)) - iRet += (*lpszStr - '0'); - else - iRet += 10 + (tolowerW(*lpszStr) - 'a'); - lpszStr++; - } - *lpiRet = iRet; - return TRUE; - } - - /* Read decimal number */ - if (!isdigitW(*lpszStr)) - return FALSE; - - while (isdigitW(*lpszStr)) - { - iRet = iRet * 10; - iRet += (*lpszStr - '0'); - lpszStr++; - } - *lpiRet = bNegative ? -iRet : iRet; - return TRUE; -} - -/************************************************************************* - * StrDupA [SHLWAPI.@] - * - * Duplicate a string. - * - * PARAMS - * lpszStr [I] String to duplicate. - * - * RETURNS - * Success: A pointer to a new string containing the contents of lpszStr - * Failure: NULL, if memory cannot be allocated - * - * NOTES - * The string memory is allocated with LocalAlloc(), and so should be released - * by calling LocalFree(). - */ -LPSTR WINAPI StrDupA(LPCSTR lpszStr) -{ - int iLen; - LPSTR lpszRet; - - TRACE("(%s)\n",debugstr_a(lpszStr)); - - iLen = lpszStr ? strlen(lpszStr) + 1 : 1; - lpszRet = (LPSTR)LocalAlloc(LMEM_FIXED, iLen); - - if (lpszRet) - { - if (lpszStr) - memcpy(lpszRet, lpszStr, iLen); - else - *lpszRet = '\0'; - } - return lpszRet; -} - -/************************************************************************* - * StrDupW [SHLWAPI.@] - * - * See StrDupA. - */ -LPWSTR WINAPI StrDupW(LPCWSTR lpszStr) -{ - int iLen; - LPWSTR lpszRet; - - TRACE("(%s)\n",debugstr_w(lpszStr)); - - iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR); - lpszRet = (LPWSTR)LocalAlloc(LMEM_FIXED, iLen); - - if (lpszRet) - { - if (lpszStr) - memcpy(lpszRet, lpszStr, iLen); - else - *lpszRet = '\0'; - } - return lpszRet; -} - -/************************************************************************* - * SHLWAPI_StrSpnHelperA - * - * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA - */ -static int WINAPI SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch, - LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD), - BOOL bInvert) -{ - LPCSTR lpszRead = lpszStr; - if (lpszStr && *lpszStr && lpszMatch) - { - while (*lpszRead) - { - LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead); - - if (!bInvert && !lpszTest) - break; - if (bInvert && lpszTest) - break; - lpszRead = CharNextA(lpszRead); - }; - } - return lpszRead - lpszStr; -} - -/************************************************************************* - * SHLWAPI_StrSpnHelperW - * - * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW - */ -static int WINAPI SHLWAPI_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch, - LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR), - BOOL bInvert) -{ - LPCWSTR lpszRead = lpszStr; - if (lpszStr && *lpszStr && lpszMatch) - { - while (*lpszRead) - { - LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead); - - if (!bInvert && !lpszTest) - break; - if (bInvert && lpszTest) - break; - lpszRead = CharNextW(lpszRead); - }; - } - return lpszRead - lpszStr; -} - -/************************************************************************* - * StrSpnA [SHLWAPI.@] - * - * Find the length of the start of a string that contains only certain - * characters. - * - * PARAMS - * lpszStr [I] String to search - * lpszMatch [I] Characters that can be in the substring - * - * RETURNS - * The length of the part of lpszStr containing only chars from lpszMatch, - * or 0 if any parameter is invalid. - */ -int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch) -{ - TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); - - return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE); -} - -/************************************************************************* - * StrSpnW [SHLWAPI.@] - * - * See StrSpnA. - */ -int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch) -{ - TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch)); - - return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, FALSE); -} - -/************************************************************************* - * StrCSpnA [SHLWAPI.@] - * - * Find the length of the start of a string that does not contain certain - * characters. - * - * PARAMS - * lpszStr [I] String to search - * lpszMatch [I] Characters that cannot be in the substring - * - * RETURNS - * The length of the part of lpszStr containing only chars not in lpszMatch, - * or 0 if any parameter is invalid. - */ -int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch) -{ - TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); - - return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE); -} - -/************************************************************************* - * StrCSpnW [SHLWAPI.@] - * - * See StrCSpnA. - */ -int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch) -{ - TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch)); - - return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE); -} - -/************************************************************************* - * StrCSpnIA [SHLWAPI.@] - * - * Find the length of the start of a string that does not contain certain - * characters, ignoring case. - * - * PARAMS - * lpszStr [I] String to search - * lpszMatch [I] Characters that cannot be in the substring - * - * RETURNS - * The length of the part of lpszStr containing only chars not in lpszMatch, - * or 0 if any parameter is invalid. - */ -int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch) -{ - TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); - - return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE); -} - -/************************************************************************* - * StrCSpnIW [SHLWAPI.@] - * - * See StrCSpnIA. - */ -int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch) -{ - TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch)); - - return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE); -} - -/************************************************************************* - * StrPBrkA [SHLWAPI.@] - * - * Search a string for any of a group of characters. - * - * PARAMS - * lpszStr [I] String to search - * lpszMatch [I] Characters to match - * - * RETURNS - * A pointer to the first matching character in lpszStr, or NULL if no - * match was found. - */ -LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch) -{ - TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); - - if (lpszStr && lpszMatch && *lpszMatch) - { - while (*lpszStr) - { - if (StrChrA(lpszMatch, *lpszStr)) - return (LPSTR)lpszStr; - lpszStr = CharNextA(lpszStr); - } - } - return NULL; -} - -/************************************************************************* - * StrPBrkW [SHLWAPI.@] - * - * See StrPBrkA. - */ -LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch) -{ - TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch)); - - if (lpszStr && lpszMatch && *lpszMatch) - { - while (*lpszStr) - { - if (StrChrW(lpszMatch, *lpszStr)) - return (LPWSTR)lpszStr; - lpszStr = CharNextW(lpszStr); - } - } - return NULL; -} - -/************************************************************************* - * SHLWAPI_StrRChrHelperA - * - * Internal implementation of StrRChrA/StrRChrIA. - */ -static LPSTR WINAPI SHLWAPI_StrRChrHelperA(LPCSTR lpszStr, - LPCSTR lpszEnd, WORD ch, - BOOL (WINAPI *pChrCmpFn)(WORD,WORD)) -{ - LPCSTR lpszRet = NULL; - - if (lpszStr) - { - WORD ch2; - - if (!lpszEnd) - lpszEnd = lpszStr + lstrlenA(lpszStr); - - while (*lpszStr && lpszStr <= lpszEnd) - { - ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr; - - if (!pChrCmpFn(ch, ch2)) - lpszRet = lpszStr; - lpszStr = CharNextA(lpszStr); - } - } - return (LPSTR)lpszRet; -} - -/************************************************************************* - * SHLWAPI_StrRChrHelperW - * - * Internal implementation of StrRChrW/StrRChrIW. - */ -static LPWSTR WINAPI SHLWAPI_StrRChrHelperW(LPCWSTR lpszStr, - LPCWSTR lpszEnd, WCHAR ch, - BOOL (WINAPI *pChrCmpFn)(WCHAR,WCHAR)) -{ - LPCWSTR lpszRet = NULL; - - if (lpszStr) - { - if (!lpszEnd) - lpszEnd = lpszStr + strlenW(lpszStr); - - while (*lpszStr && lpszStr <= lpszEnd) - { - if (!pChrCmpFn(ch, *lpszStr)) - lpszRet = lpszStr; - lpszStr = CharNextW(lpszStr); - } - } - return (LPWSTR)lpszRet; -} - -/************************************************************************** - * StrRChrA [SHLWAPI.@] - * - * Find the last occurrence of a character in string. - * - * PARAMS - * lpszStr [I] String to search in - * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr - * ch [I] Character to search for. - * - * RETURNS - * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd, - * or NULL if not found. - * Failure: NULL, if any arguments are invalid. - */ -LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch) -{ - TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch); - - return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA); -} - -/************************************************************************** - * StrRChrW [SHLWAPI.@] - * - * See StrRChrA. - */ -LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch) -{ - TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch); - - return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpW); -} - -/************************************************************************** - * StrRChrIA [SHLWAPI.@] - * - * Find the last occurrence of a character in string, ignoring case. - * - * PARAMS - * lpszStr [I] String to search in - * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr - * ch [I] Character to search for. - * - * RETURNS - * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd, - * or NULL if not found. - * Failure: NULL, if any arguments are invalid. - */ -LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch) -{ - TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch); - - return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA); -} - -/************************************************************************** - * StrRChrIW [SHLWAPI.@] - * - * See StrRChrIA. - */ -LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch) -{ - TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch); - - return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, ChrCmpIW); -} - -/************************************************************************* - * StrCatBuffA [SHLWAPI.@] - * - * Concatenate two strings together. - * - * PARAMS - * lpszStr [O] String to concatenate to - * lpszCat [I] String to add to lpszCat - * cchMax [I] Maximum number of characters for the whole string - * - * RETURNS - * lpszStr. - * - * NOTES - * cchMax determines the number of characters in the final length of the - * string, not the number appended to lpszStr from lpszCat. - */ -LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax) -{ - INT iLen; - - TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax); - - if (!lpszStr) - { - WARN("Invalid lpszStr would crash under Win32!\n"); - return NULL; - } - - iLen = strlen(lpszStr); - cchMax -= iLen; - - if (cchMax > 0) - StrCpyNA(lpszStr + iLen, lpszCat, cchMax); - return lpszStr; -} - -/************************************************************************* - * StrCatBuffW [SHLWAPI.@] - * - * See StrCatBuffA. - */ -LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax) -{ - INT iLen; - - TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax); - - if (!lpszStr) - { - WARN("Invalid lpszStr would crash under Win32!\n"); - return NULL; - } - - iLen = strlenW(lpszStr); - cchMax -= iLen; - - if (cchMax > 0) - StrCpyNW(lpszStr + iLen, lpszCat, cchMax); - return lpszStr; -} - -/************************************************************************* - * StrRetToBufA [SHLWAPI.@] - * - * Convert a STRRET to a normal string. - * - * PARAMS - * lpStrRet [O] STRRET to convert - * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET - * lpszDest [O] Destination for normal string - * dwLen [I] Length of lpszDest - * - * RETURNS - * Success: S_OK. lpszDest contains up to dwLen characters of the string. - * If lpStrRet is of type STRRET_WSTR, its memory is freed with - * CoTaskMemFree() and its type set to STRRET_CSTRA. - * Failure: E_FAIL, if any parameters are invalid. - */ -HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len) -{ - /* NOTE: - * This routine is identical to that in dlls/shell32/shellstring.c. - * It was duplicated because not every version of Shlwapi.dll exports - * StrRetToBufA. If you change one routine, change them both. - */ - TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl); - - if (!src) - { - WARN("Invalid lpStrRet would crash under Win32!\n"); - if (dest) - *dest = '\0'; - return E_FAIL; - } - - if (!dest || !len) - return E_FAIL; - - *dest = '\0'; - - switch (src->uType) - { - case STRRET_WSTR: - WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL); - CoTaskMemFree(src->u.pOleStr); - break; - - case STRRET_CSTR: - lstrcpynA((LPSTR)dest, src->u.cStr, len); - break; - - case STRRET_OFFSET: - lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len); - break; - - default: - FIXME("unknown type!\n"); - return FALSE; - } - return S_OK; -} - -/************************************************************************* - * StrRetToBufW [SHLWAPI.@] - * - * See StrRetToBufA. - */ -HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len) -{ - TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl); - - if (!src) - { - WARN("Invalid lpStrRet would crash under Win32!\n"); - if (dest) - *dest = '\0'; - return E_FAIL; - } - - if (!dest || !len) - return E_FAIL; - - *dest = '\0'; - - switch (src->uType) - { - case STRRET_WSTR: - lstrcpynW((LPWSTR)dest, src->u.pOleStr, len); - CoTaskMemFree(src->u.pOleStr); - break; - - case STRRET_CSTR: - if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len) - dest[len-1] = 0; - break; - - case STRRET_OFFSET: - if (pidl) - { - if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, - dest, len ) && len) - dest[len-1] = 0; - } - break; - - default: - FIXME("unknown type!\n"); - return FALSE; - } - return S_OK; -} - -/************************************************************************* - * StrRetToStrA [SHLWAPI.@] - * - * Converts a STRRET to a normal string. - * - * PARAMS - * lpStrRet [O] STRRET to convert - * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET - * ppszName [O] Destination for converted string - * - * RETURNS - * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc(). - * Failure: E_FAIL, if any parameters are invalid. - */ -HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName) -{ - HRESULT hRet = E_FAIL; - - switch (lpStrRet->uType) - { - case STRRET_WSTR: - hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName); - CoTaskMemFree(lpStrRet->u.pOleStr); - break; - - case STRRET_CSTR: - hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName); - break; - - case STRRET_OFFSET: - hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName); - break; - - default: - *ppszName = NULL; - } - - return hRet; -} - -/************************************************************************* - * StrRetToStrW [SHLWAPI.@] - * - * See StrRetToStrA. - */ -HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName) -{ - HRESULT hRet = E_FAIL; - - switch (lpStrRet->uType) - { - case STRRET_WSTR: - hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName); - CoTaskMemFree(lpStrRet->u.pOleStr); - break; - - case STRRET_CSTR: - hRet = SHStrDupA(lpStrRet->u.cStr, ppszName); - break; - - case STRRET_OFFSET: - hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName); - break; - - default: - *ppszName = NULL; - } - - return hRet; -} - -/* Create an ASCII string copy using SysAllocString() */ -static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut) -{ - *pBstrOut = NULL; - - if (src) - { - INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0); - WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); - - if (szTemp) - { - MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len); - *pBstrOut = SysAllocString(szTemp); - HeapFree(GetProcessHeap(), 0, szTemp); - - if (*pBstrOut) - return S_OK; - } - } - return E_OUTOFMEMORY; -} - -/************************************************************************* - * StrRetToBSTR [SHLWAPI.@] - * - * Converts a STRRET to a BSTR. - * - * PARAMS - * lpStrRet [O] STRRET to convert - * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET - * pBstrOut [O] Destination for converted BSTR - * - * RETURNS - * Success: S_OK. pBstrOut contains the new string. - * Failure: E_FAIL, if any parameters are invalid. - */ -HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut) -{ - HRESULT hRet = E_FAIL; - - switch (lpStrRet->uType) - { - case STRRET_WSTR: - *pBstrOut = SysAllocString(lpStrRet->u.pOleStr); - if (*pBstrOut) - hRet = S_OK; - CoTaskMemFree(lpStrRet->u.pOleStr); - break; - - case STRRET_CSTR: - hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut); - break; - - case STRRET_OFFSET: - hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut); - break; - - default: - *pBstrOut = NULL; - } - - return hRet; -} - -/************************************************************************* - * StrFormatKBSizeA [SHLWAPI.@] - * - * Create a formatted string containing a byte count in Kilobytes. - * - * PARAMS - * llBytes [I] Byte size to format - * lpszDest [I] Destination for formatted string - * cchMax [I] Size of lpszDest - * - * RETURNS - * lpszDest. - */ -LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax) -{ - char szBuff[256], *szOut = szBuff + sizeof(szBuff) - 1; - LONGLONG ulKB = (llBytes + 1023) >> 10; - - TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax); - - *szOut-- = '\0'; - *szOut-- = 'B'; - *szOut-- = 'K'; - *szOut-- = ' '; - - do - { - LONGLONG ulNextDigit = ulKB % 10; - *szOut-- = '0' + ulNextDigit; - ulKB = (ulKB - ulNextDigit) / 10; - } while (ulKB > 0); - - lstrcpynA(lpszDest, szOut + 1, cchMax); - return lpszDest; -} - -/************************************************************************* - * StrFormatKBSizeW [SHLWAPI.@] - * - * See StrFormatKBSizeA. - */ -LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax) -{ - WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1; - LONGLONG ulKB = (llBytes + 1023) >> 10; - - TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax); - - *szOut-- = '\0'; - *szOut-- = 'B'; - *szOut-- = 'K'; - *szOut-- = ' '; - - do - { - LONGLONG ulNextDigit = ulKB % 10; - *szOut-- = '0' + ulNextDigit; - ulKB = (ulKB - ulNextDigit) / 10; - } while (ulKB > 0); - - lstrcpynW(lpszDest, szOut + 1, cchMax); - return lpszDest; -} - -/************************************************************************* - * StrNCatA [SHLWAPI.@] - * - * Concatenate two strings together. - * - * PARAMS - * lpszStr [O] String to concatenate to - * lpszCat [I] String to add to lpszCat - * cchMax [I] Maximum number of characters to concatenate - * - * RETURNS - * lpszStr. - * - * NOTES - * cchMax determines the number of characters that are appended to lpszStr, - * not the total length of the string. - */ -LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax) -{ - LPSTR lpszRet = lpszStr; - - TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax); - - if (!lpszStr) - { - WARN("Invalid lpszStr would crash under Win32!\n"); - return NULL; - } - - StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax); - return lpszRet; -} - -/************************************************************************* - * StrNCatW [SHLWAPI.@] - * - * See StrNCatA. - */ -LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax) -{ - LPWSTR lpszRet = lpszStr; - - TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax); - - if (!lpszStr) - { - WARN("Invalid lpszStr would crash under Win32\n"); - return NULL; - } - - StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax); - return lpszRet; -} - -/************************************************************************* - * StrTrimA [SHLWAPI.@] - * - * Remove characters from the start and end of a string. - * - * PARAMS - * lpszStr [O] String to remove characters from - * lpszTrim [I] Characters to remove from lpszStr - * - * RETURNS - * TRUE If lpszStr was valid and modified - * FALSE Otherwise - */ -BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim) -{ - DWORD dwLen; - LPSTR lpszRead = lpszStr; - BOOL bRet = FALSE; - - TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim)); - - if (lpszRead && *lpszRead) - { - while (*lpszRead && StrChrA(lpszTrim, *lpszRead)) - lpszRead = CharNextA(lpszRead); /* Skip leading matches */ - - dwLen = strlen(lpszRead); - - if (lpszRead != lpszStr) - { - memmove(lpszStr, lpszRead, dwLen + 1); - bRet = TRUE; - } - if (dwLen > 0) - { - lpszRead = lpszStr + dwLen; - while (StrChrA(lpszTrim, lpszRead[-1])) - lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */ - - if (lpszRead != lpszStr + dwLen) - { - *lpszRead = '\0'; - bRet = TRUE; - } - } - } - return bRet; -} - -/************************************************************************* - * StrTrimW [SHLWAPI.@] - * - * See StrTrimA. - */ -BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim) -{ - DWORD dwLen; - LPWSTR lpszRead = lpszStr; - BOOL bRet = FALSE; - - TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim)); - - if (lpszRead && *lpszRead) - { - while (*lpszRead && StrChrW(lpszTrim, *lpszRead)) - lpszRead = CharNextW(lpszRead); /* Skip leading matches */ - - dwLen = strlenW(lpszRead); - - if (lpszRead != lpszStr) - { - memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR)); - bRet = TRUE; - } - if (dwLen > 0) - { - lpszRead = lpszStr + dwLen; - while (StrChrW(lpszTrim, lpszRead[-1])) - lpszRead = CharPrevW(lpszStr, lpszRead); /* Skip trailing matches */ - - if (lpszRead != lpszStr + dwLen) - { - *lpszRead = '\0'; - bRet = TRUE; - } - } - } - return bRet; -} - -/************************************************************************* - * _SHStrDupAA [INTERNAL] - * - * Duplicates a ASCII string to ASCII. The destination buffer is allocated. - */ -static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest) -{ - HRESULT hr; - int len = 0; - - if (src) { - len = lstrlenA(src) + 1; - *dest = CoTaskMemAlloc(len); - } else { - *dest = NULL; - } - - if (*dest) { - lstrcpynA(*dest,src, len); - hr = S_OK; - } else { - hr = E_OUTOFMEMORY; - } - - TRACE("%s->(%p)\n", debugstr_a(src), *dest); - return hr; -} - -/************************************************************************* - * SHStrDupA [SHLWAPI.@] - * - * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc(). - * - * PARAMS - * lpszStr [I] String to copy - * lppszDest [O] Destination for the new string copy - * - * RETURNS - * Success: S_OK. lppszDest contains the new string in Unicode format. - * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation - * fails. - */ -HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest) -{ - HRESULT hRet; - int len = 0; - - if (lpszStr) - { - len = MultiByteToWideChar(0, 0, lpszStr, -1, 0, 0) * sizeof(WCHAR); - *lppszDest = CoTaskMemAlloc(len); - } - else - *lppszDest = NULL; - - if (*lppszDest) - { - MultiByteToWideChar(0, 0, lpszStr, -1, *lppszDest, len); - hRet = S_OK; - } - else - hRet = E_OUTOFMEMORY; - - TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest); - return hRet; -} - -/************************************************************************* - * _SHStrDupAW [INTERNAL] - * - * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated. - */ -static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest) -{ - HRESULT hr; - int len = 0; - - if (src) { - len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL); - *dest = CoTaskMemAlloc(len); - } else { - *dest = NULL; - } - - if (*dest) { - WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL); - hr = S_OK; - } else { - hr = E_OUTOFMEMORY; - } - - TRACE("%s->(%p)\n", debugstr_w(src), *dest); - return hr; -} - -/************************************************************************* - * SHStrDupW [SHLWAPI.@] - * - * See SHStrDupA. - */ -HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest) -{ - HRESULT hr; - int len = 0; - - if (src) { - len = (lstrlenW(src) + 1) * sizeof(WCHAR); - *dest = CoTaskMemAlloc(len); - } else { - *dest = NULL; - } - - if (*dest) { - memcpy(*dest, src, len); - hr = S_OK; - } else { - hr = E_OUTOFMEMORY; - } - - TRACE("%s->(%p)\n", debugstr_w(src), *dest); - return hr; -} - -/************************************************************************* - * SHLWAPI_WriteReverseNum - * - * Internal helper for SHLWAPI_WriteTimeClass. - */ -inline static LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum) -{ - *lpszOut-- = '\0'; - - /* Write a decimal number to a string, backwards */ - do - { - DWORD dwNextDigit = dwNum % 10; - *lpszOut-- = '0' + dwNextDigit; - dwNum = (dwNum - dwNextDigit) / 10; - } while (dwNum > 0); - - return lpszOut; -} - -/************************************************************************* - * SHLWAPI_FormatSignificant - * - * Internal helper for SHLWAPI_WriteTimeClass. - */ -inline static int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits) -{ - /* Zero non significant digits, return remaining significant digits */ - while (*lpszNum) - { - lpszNum++; - if (--dwDigits == 0) - { - while (*lpszNum) - *lpszNum++ = '0'; - return 0; - } - } - return dwDigits; -} - -/************************************************************************* - * SHLWAPI_WriteTimeClass - * - * Internal helper for StrFromTimeIntervalW. - */ -static int WINAPI SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue, - LPCWSTR lpszClass, int iDigits) -{ - WCHAR szBuff[64], *szOut = szBuff + 32; - - szOut = SHLWAPI_WriteReverseNum(szOut, dwValue); - iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits); - *szOut = ' '; - strcpyW(szBuff + 32, lpszClass); - strcatW(lpszOut, szOut); - return iDigits; -} - -/************************************************************************* - * StrFromTimeIntervalA [SHLWAPI.@] - * - * Format a millisecond time interval into a string - * - * PARAMS - * lpszStr [O] Output buffer for formatted time interval - * cchMax [I] Size of lpszStr - * dwMS [I] Number of milliseconds - * iDigits [I] Number of digits to print - * - * RETURNS - * The length of the formatted string, or 0 if any parameter is invalid. - * - * NOTES - * This implementation mimics the Win32 behaviour of always writing a leading - * space before the time interval begins. - * - * iDigits is used to provide approximate times if accuracy is not important. - * This number of digits will be written of the first non-zero time class - * (hours/minutes/seconds). If this does not complete the time classification, - * the remaining digits are changed to zeros (i.e. The time is _not_ rounded). - * If there are digits remaining following the writing of a time class, the - * next time class will be written. - * - * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the - * following will result from the given values of iDigits: - * - *| iDigits 1 2 3 4 5 ... - *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ... - */ -INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS, - int iDigits) -{ - INT iRet = 0; - - TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits); - - if (lpszStr && cchMax) - { - WCHAR szBuff[128]; - StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits); - WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0); - } - return iRet; -} - - -/************************************************************************* - * StrFromTimeIntervalW [SHLWAPI.@] - * - * See StrFromTimeIntervalA. - */ -INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS, - int iDigits) -{ - static const WCHAR szHr[] = {' ','h','r','\0'}; - static const WCHAR szMin[] = {' ','m','i','n','\0'}; - static const WCHAR szSec[] = {' ','s','e','c','\0'}; - INT iRet = 0; - - TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits); - - if (lpszStr && cchMax) - { - WCHAR szCopy[128]; - DWORD dwHours, dwMinutes; - - if (!iDigits || cchMax == 1) - { - *lpszStr = '\0'; - return 0; - } - - /* Calculate the time classes */ - dwMS = (dwMS + 500) / 1000; - dwHours = dwMS / 3600; - dwMS -= dwHours * 3600; - dwMinutes = dwMS / 60; - dwMS -= dwMinutes * 60; - - szCopy[0] = '\0'; - - if (dwHours) - iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, szHr, iDigits); - - if (dwMinutes && iDigits) - iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, szMin, iDigits); - - if (iDigits) /* Always write seconds if we have significant digits */ - SHLWAPI_WriteTimeClass(szCopy, dwMS, szSec, iDigits); - - lstrcpynW(lpszStr, szCopy, cchMax); - iRet = strlenW(lpszStr); - } - return iRet; -} - -/************************************************************************* - * StrIsIntlEqualA [SHLWAPI.@] - * - * Compare two strings. - * - * PARAMS - * bCase [I] Whether to compare case sensitively - * lpszStr [I] First string to compare - * lpszComp [I] Second string to compare - * iLen [I] Length to compare - * - * RETURNS - * TRUE If the strings are equal. - * FALSE Otherwise. - */ -BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp, - int iLen) -{ - DWORD dwFlags; - - TRACE("(%d,%s,%s,%d)\n", bCase, - debugstr_a(lpszStr), debugstr_a(lpszComp), iLen); - - /* FIXME: This flag is undocumented and unknown by our CompareString. - * We need a define for it. - */ - dwFlags = 0x10000000; - if (!bCase) dwFlags |= NORM_IGNORECASE; - - return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL); -} - -/************************************************************************* - * StrIsIntlEqualW [SHLWAPI.@] - * - * See StrIsIntlEqualA. - */ -BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp, - int iLen) -{ - DWORD dwFlags; - - TRACE("(%d,%s,%s,%d)\n", bCase, - debugstr_w(lpszStr),debugstr_w(lpszComp), iLen); - - /* FIXME: This flag is undocumented and unknown by our CompareString. - * We need a define for it. - */ - dwFlags = 0x10000000; - if (!bCase) dwFlags |= NORM_IGNORECASE; - - return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL); -} - -/************************************************************************* - * @ [SHLWAPI.399] - * - * Copy a string to another string, up to a maximum number of characters. - * - * PARAMS - * lpszDest [O] Destination string - * lpszSrc [I] Source string - * iLen [I] Maximum number of chars to copy - * - * RETURNS - * Success: A pointer to the last character written to lpszDest.. - * Failure: lpszDest, if any arguments are invalid. - */ -LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen) -{ - TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen); - - if (lpszDest && lpszSrc && iLen > 0) - { - while ((iLen-- > 1) && *lpszSrc) - *lpszDest++ = *lpszSrc++; - if (iLen >= 0) - *lpszDest = '\0'; - } - return lpszDest; -} - -/************************************************************************* - * @ [SHLWAPI.400] - * - * Unicode version of StrCpyNXA. - */ -LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen) -{ - TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen); - - if (lpszDest && lpszSrc && iLen > 0) - { - while ((iLen-- > 1) && *lpszSrc) - *lpszDest++ = *lpszSrc++; - if (iLen >= 0) - *lpszDest = '\0'; - } - return lpszDest; -} - -/************************************************************************* - * StrCmpLogicalW [SHLWAPI.@] - * - * Compare two strings, ignoring case and comparing digits as numbers. - * - * PARAMS - * lpszStr [I] First string to compare - * lpszComp [I] Second string to compare - * iLen [I] Length to compare - * - * RETURNS - * TRUE If the strings are equal. - * FALSE Otherwise. - */ -INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp) -{ - INT iDiff; - - TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp)); - - if (lpszStr && lpszComp) - { - while (*lpszStr) - { - if (!*lpszComp) - return 1; - else if (isdigitW(*lpszStr)) - { - int iStr, iComp; - - if (!isdigitW(*lpszComp)) - return -1; - - /* Compare the numbers */ - StrToIntExW(lpszStr, 0, &iStr); - StrToIntExW(lpszComp, 0, &iComp); - - if (iStr < iComp) - return -1; - else if (iStr > iComp) - return 1; - - /* Skip */ - while (isdigitW(*lpszStr)) - lpszStr++; - while (isdigitW(*lpszComp)) - lpszComp++; - } - else if (isdigitW(*lpszComp)) - return 1; - else - { - iDiff = SHLWAPI_ChrCmpHelperW(*lpszStr,*lpszComp,NORM_IGNORECASE); - if (iDiff > 0) - return 1; - else if (iDiff < 0) - return -1; - - lpszStr++; - lpszComp++; - } - } - if (*lpszComp) - return -1; - } - return 0; -} - -/* Structure for formatting byte strings */ -typedef struct tagSHLWAPI_BYTEFORMATS -{ - LONGLONG dLimit; - double dDivisor; - double dNormaliser; - LPCWSTR lpwszFormat; - WCHAR wPrefix; -} SHLWAPI_BYTEFORMATS; - -/************************************************************************* - * StrFormatByteSizeW [SHLWAPI.@] - * - * Create a string containing an abbreviated byte count of up to 2^63-1. - * - * PARAMS - * llBytes [I] Byte size to format - * lpszDest [I] Destination for formatted string - * cchMax [I] Size of lpszDest - * - * RETURNS - * lpszDest. - * - * NOTES - * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW(). - */ -LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax) -{ - static const WCHAR wszBytes[] = {'%','l','d',' ','b','y','t','e','s',0}; - static const WCHAR wsz3_0[] = {'%','3','.','0','f',0}; - static const WCHAR wsz3_1[] = {'%','3','.','1','f',0}; - static const WCHAR wsz3_2[] = {'%','3','.','2','f',0}; - -#define KB ((ULONGLONG)1024) -#define MB (KB*KB) -#define GB (KB*KB*KB) -#define TB (KB*KB*KB*KB) -#define PB (KB*KB*KB*KB*KB) - - static const SHLWAPI_BYTEFORMATS bfFormats[] = - { - { 10*KB, 10.24, 100.0, wsz3_2, 'K' }, /* 10 KB */ - { 100*KB, 102.4, 10.0, wsz3_1, 'K' }, /* 100 KB */ - { 1000*KB, 1024.0, 1.0, wsz3_0, 'K' }, /* 1000 KB */ - { 10*MB, 10485.76, 100.0, wsz3_2, 'M' }, /* 10 MB */ - { 100*MB, 104857.6, 10.0, wsz3_1, 'M' }, /* 100 MB */ - { 1000*MB, 1048576.0, 1.0, wsz3_0, 'M' }, /* 1000 MB */ - { 10*GB, 10737418.24, 100.0, wsz3_2, 'G' }, /* 10 GB */ - { 100*GB, 107374182.4, 10.0, wsz3_1, 'G' }, /* 100 GB */ - { 1000*GB, 1073741824.0, 1.0, wsz3_0, 'G' }, /* 1000 GB */ - { 10*TB, 10485.76, 100.0, wsz3_2, 'T' }, /* 10 TB */ - { 100*TB, 104857.6, 10.0, wsz3_1, 'T' }, /* 100 TB */ - { 1000*TB, 1048576.0, 1.0, wsz3_0, 'T' }, /* 1000 TB */ - { 10*PB, 10737418.24, 100.00, wsz3_2, 'P' }, /* 10 PB */ - { 100*PB, 107374182.4, 10.00, wsz3_1, 'P' }, /* 100 PB */ - { 1000*PB, 1073741824.0, 1.00, wsz3_0, 'P' }, /* 1000 PB */ - { 0, 10995116277.76, 100.00, wsz3_2, 'E' } /* EB's, catch all */ - }; - WCHAR wszBuff[32]; - WCHAR wszAdd[] = {' ','?','B',0}; - double dBytes; - UINT i = 0; - - TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax); - - if (!lpszDest || !cchMax) - return lpszDest; - - if (llBytes < 1024) /* 1K */ - { - snprintfW(lpszDest, cchMax, wszBytes, (long)llBytes); - return lpszDest; - } - - /* Note that if this loop completes without finding a match, i will be - * pointing at the last entry, which is a catch all for > 1000 PB - */ - while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1) - { - if (llBytes < bfFormats[i].dLimit) - break; - i++; - } - /* Above 1 TB we encounter problems with FP accuracy. So for amounts above - * this number we integer shift down by 1 MB first. The table above has - * the divisors scaled down from the '< 10 TB' entry onwards, to account - * for this. We also add a small fudge factor to get the correct result for - * counts that lie exactly on a 1024 byte boundary. - */ - if (i > 8) - dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */ - else - dBytes = (double)llBytes + 0.00001; - - dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser; - - sprintfW(wszBuff, bfFormats[i].lpwszFormat, dBytes); - wszAdd[1] = bfFormats[i].wPrefix; - strcatW(wszBuff, wszAdd); - lstrcpynW(lpszDest, wszBuff, cchMax); - return lpszDest; -} - -/************************************************************************* - * StrFormatByteSize64A [SHLWAPI.@] - * - * See StrFormatByteSizeW. - */ -LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax) -{ - WCHAR wszBuff[32]; - - StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR)); - - if (lpszDest) - WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0); - return lpszDest; -} - -/************************************************************************* - * StrFormatByteSizeA [SHLWAPI.@] - * - * Create a string containing an abbreviated byte count of up to 2^31-1. - * - * PARAMS - * dwBytes [I] Byte size to format - * lpszDest [I] Destination for formatted string - * cchMax [I] Size of lpszDest - * - * RETURNS - * lpszDest. - * - * NOTES - * The Ascii and Unicode versions of this function accept a different - * integer type for dwBytes. See StrFormatByteSize64A(). - */ -LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax) -{ - TRACE("(%ld,%p,%d)\n", dwBytes, lpszDest, cchMax); - - return StrFormatByteSize64A(dwBytes, lpszDest, cchMax); -} - -/************************************************************************* - * @ [SHLWAPI.162] - * - * Remove a hanging lead byte from the end of a string, if present. - * - * PARAMS - * lpStr [I] String to check for a hanging lead byte - * size [I] Length of lpStr - * - * RETURNS - * Success: The new length of the string. Any hanging lead bytes are removed. - * Failure: 0, if any parameters are invalid. - */ -DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size) -{ - if (lpStr && size) - { - LPSTR lastByte = lpStr + size - 1; - - while(lpStr < lastByte) - lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1; - - if(lpStr == lastByte && IsDBCSLeadByte(*lpStr)) - { - *lpStr = '\0'; - size--; - } - return size; - } - return 0; -} - -/************************************************************************* - * @ [SHLWAPI.203] - * - * Remove a single non-trailing ampersand ('&') from a string. - * - * PARAMS - * lpszStr [I/O] String to remove ampersand from. - * - * RETURNS - * The character after the first ampersand in lpszStr, or the first character - * in lpszStr if there is no ampersand in the string. - */ -char WINAPI SHStripMneumonicA(LPCSTR lpszStr) -{ - LPSTR lpszIter, lpszTmp; - char ch; - - TRACE("(%s)\n", debugstr_a(lpszStr)); - - ch = *lpszStr; - - if ((lpszIter = StrChrA(lpszStr, '&'))) - { - lpszTmp = CharNextA(lpszIter); - if (lpszTmp && *lpszTmp) - { - if (*lpszTmp != '&') - ch = *lpszTmp; - - while (lpszIter && *lpszIter) - { - lpszTmp = CharNextA(lpszIter); - *lpszIter = *lpszTmp; - lpszIter = lpszTmp; - } - } - } - - return ch; -} - -/************************************************************************* - * @ [SHLWAPI.225] - * - * Unicode version of SHStripMneumonicA. - */ -WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr) -{ - LPWSTR lpszIter, lpszTmp; - WCHAR ch; - - TRACE("(%s)\n", debugstr_w(lpszStr)); - - ch = *lpszStr; - - if ((lpszIter = StrChrW(lpszStr, '&'))) - { - lpszTmp = CharNextW(lpszIter); - if (lpszTmp && *lpszTmp) - { - if (*lpszTmp != '&') - ch = *lpszTmp; - - while (lpszIter && *lpszIter) - { - lpszTmp = CharNextW(lpszIter); - *lpszIter = *lpszTmp; - lpszIter = lpszTmp; - } - } - } - - return ch; -} - -/************************************************************************* - * @ [SHLWAPI.216] - * - * Convert an Ascii string to Unicode. - * - * PARAMS - * dwCp [I] Code page for the conversion - * lpSrcStr [I] Source Ascii string to convert - * lpDstStr [O] Destination for converted Unicode string - * iLen [I] Length of lpDstStr - * - * RETURNS - * The return value of the MultiByteToWideChar() function called on lpSrcStr. - */ -DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen) -{ - DWORD dwRet; - - dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen); - TRACE("%s->%s,ret=%ld\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet); - return dwRet; -} - -/************************************************************************* - * @ [SHLWAPI.215] - * - * Convert an Ascii string to Unicode. - * - * PARAMS - * lpSrcStr [I] Source Ascii string to convert - * lpDstStr [O] Destination for converted Unicode string - * iLen [I] Length of lpDstStr - * - * RETURNS - * The return value of the MultiByteToWideChar() function called on lpSrcStr. - * - * NOTES - * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP. - */ -DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen) -{ - return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen); -} - -/************************************************************************* - * @ [SHLWAPI.218] - * - * Convert a Unicode string to Ascii. - * - * PARAMS - * CodePage [I] Code page to use for the conversion - * lpSrcStr [I] Source Unicode string to convert - * lpDstStr [O] Destination for converted Ascii string - * lpiLen [I/O] Input length of lpDstStr/destination for length of lpDstStr - * - * RETURNS - * Success: The number of characters that result from the conversion. - * Failure: 0. - */ -INT WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr, - LPINT lpiLen) -{ - static const WCHAR emptyW[] = { '\0' }; - int len , reqLen; - LPSTR mem; - - if (!lpDstStr || !lpiLen) - return 0; - - if (!lpSrcStr) - lpSrcStr = emptyW; - - *lpDstStr = '\0'; - - len = strlenW(lpSrcStr) + 1; - - switch (CodePage) - { - case CP_WINUNICODE: - CodePage = CP_UTF8; /* Fall through... */ - case 0x0000C350: /* FIXME: CP_ #define */ - case CP_UTF7: - case CP_UTF8: - { - DWORD dwMode = 0; - INT nWideCharCount = len - 1; - - GET_FUNC(pConvertINetUnicodeToMultiByte, mlang, "ConvertINetUnicodeToMultiByte", 0); - if (!pConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &nWideCharCount, lpDstStr, - lpiLen)) - return 0; - - if (nWideCharCount < len - 1) - { - mem = HeapAlloc(GetProcessHeap(), 0, *lpiLen); - if (!mem) - return 0; - - *lpiLen = 0; - - if (pConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, lpiLen)) - { - SHTruncateString(mem, *lpiLen); - lstrcpynA(lpDstStr, mem, *lpiLen + 1); - HeapFree(GetProcessHeap(), 0, mem); - return *lpiLen + 1; - } - HeapFree(GetProcessHeap(), 0, mem); - return *lpiLen; - } - lpDstStr[*lpiLen] = '\0'; - return *lpiLen; - } - default: - break; - } - - reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr, - *lpiLen, NULL, NULL); - - if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL); - if (reqLen) - { - mem = HeapAlloc(GetProcessHeap(), 0, reqLen); - if (mem) - { - reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem, - reqLen, NULL, NULL); - - reqLen = SHTruncateString(mem, *lpiLen); - reqLen++; - - lstrcpynA(lpDstStr, mem, *lpiLen); - - HeapFree(GetProcessHeap(), 0, mem); - } - } - } - return reqLen; -} - -/************************************************************************* - * @ [SHLWAPI.217] - * - * Convert a Unicode string to Ascii. - * - * PARAMS - * lpSrcStr [I] Source Unicode string to convert - * lpDstStr [O] Destination for converted Ascii string - * iLen [O] Length of lpDstStr in characters - * - * RETURNS - * See SHUnicodeToAnsiCP - - * NOTES - * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP. - */ -INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen) -{ - INT myint = iLen; - - return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, &myint); -} - -/************************************************************************* - * @ [SHLWAPI.345] - * - * Copy one string to another. - * - * PARAMS - * lpszSrc [I] Source string to copy - * lpszDst [O] Destination for copy - * iLen [I] Length of lpszDst in characters - * - * RETURNS - * The length of the copied string, including the terminating NUL. lpszDst - * contains iLen characters of lpszSrc. - */ -DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen) -{ - LPSTR lpszRet; - - TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen); - - lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen); - return lpszRet - lpszDst + 1; -} - -/************************************************************************* - * @ [SHLWAPI.346] - * - * Unicode version of SSHAnsiToAnsi. - */ -DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen) -{ - LPWSTR lpszRet; - - TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen); - - lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen); - return lpszRet - lpszDst + 1; -} - -/************************************************************************* - * @ [SHLWAPI.364] - * - * Determine if an Ascii string converts to Unicode and back identically. - * - * PARAMS - * lpSrcStr [I] Source Unicode string to convert - * lpDst [O] Destination for resulting Ascii string - * iLen [I] Length of lpDst in characters - * - * RETURNS - * TRUE, since Ascii strings always convert identically. - */ -BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen) -{ - lstrcpynA(lpDst, lpSrcStr, iLen); - return TRUE; -} - -/************************************************************************* - * @ [SHLWAPI.365] - * - * Determine if a Unicode string converts to Ascii and back identically. - * - * PARAMS - * lpSrcStr [I] Source Unicode string to convert - * lpDst [O] Destination for resulting Ascii string - * iLen [I] Length of lpDst in characters - * - * RETURNS - * TRUE, if lpSrcStr converts to Ascii and back identically, - * FALSE otherwise. - */ -BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen) -{ - WCHAR szBuff[MAX_PATH]; - - SHUnicodeToAnsi(lpSrcStr, lpDst, iLen); - SHAnsiToUnicode(lpDst, szBuff, MAX_PATH); - return !strcmpW(lpSrcStr, szBuff); -} +/* + * Shlwapi string functions + * + * Copyright 1998 Juergen Schmied + * Copyright 2002 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define COM_NO_WINDOWS_H +#include "config.h" +#include "wine/port.h" + +#include <math.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winbase.h" +#define NO_SHLWAPI_REG +#define NO_SHLWAPI_STREAM +#include "shlwapi.h" +#include "wingdi.h" +#include "winuser.h" +#include "shlobj.h" +#include "ddeml.h" +#include "wine/unicode.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/* Get a function pointer from a DLL handle */ +#define GET_FUNC(func, module, name, fail) \ + do { \ + if (!func) { \ + if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \ + func = (fn##func)GetProcAddress(SHLWAPI_h##module, name); \ + if (!func) return fail; \ + } \ + } while (0) + +extern HMODULE SHLWAPI_hmlang; + +typedef HRESULT (WINAPI *fnpConvertINetUnicodeToMultiByte)(LPDWORD,DWORD,LPCWSTR,LPINT,LPSTR,LPINT); +static fnpConvertINetUnicodeToMultiByte pConvertINetUnicodeToMultiByte; + +static HRESULT WINAPI _SHStrDupAA(LPCSTR,LPSTR*); +static HRESULT WINAPI _SHStrDupAW(LPCWSTR,LPSTR*); + +/************************************************************************* + * SHLWAPI_ChrCmpHelperA + * + * Internal helper for SHLWAPI_ChrCmpA/ChrCMPIA. + * + * NOTES + * Both this function and its Unicode counterpart are very inneficient. To + * fix this, CompareString must be completely implemented and optimised + * first. Then the core character test can be taken out of that function and + * placed here, so that it need never be called at all. Until then, do not + * attempt to optimise this code unless you are willing to test that it + * still performs correctly. + */ +static BOOL WINAPI SHLWAPI_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags) +{ + char str1[3], str2[3]; + + str1[0] = LOBYTE(ch1); + if (IsDBCSLeadByte(str1[0])) + { + str1[1] = HIBYTE(ch1); + str1[2] = '\0'; + } + else + str1[1] = '\0'; + + str2[0] = LOBYTE(ch2); + if (IsDBCSLeadByte(str2[0])) + { + str2[1] = HIBYTE(ch2); + str2[2] = '\0'; + } + else + str2[1] = '\0'; + + return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2; +} + +/************************************************************************* + * SHLWAPI_ChrCmpHelperW + * + * Internal helper for SHLWAPI_ChrCmpW/ChrCmpIW. + */ +static BOOL WINAPI SHLWAPI_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags) +{ + WCHAR str1[2], str2[2]; + + str1[0] = ch1; + str1[1] = '\0'; + str2[0] = ch2; + str2[1] = '\0'; + return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2; +} + +/************************************************************************* + * SHLWAPI_ChrCmpA + * + * Internal helper function. + */ +static BOOL WINAPI SHLWAPI_ChrCmpA(WORD ch1, WORD ch2) +{ + return SHLWAPI_ChrCmpHelperA(ch1, ch2, 0); +} + +/************************************************************************* + * ChrCmpIA (SHLWAPI.385) + * + * Compare two characters, ignoring case. + * + * PARAMS + * ch1 [I] First character to compare + * ch2 [I] Second character to compare + * + * RETURNS + * FALSE, if the characters are equal. + * Non-zero otherwise. + */ +BOOL WINAPI ChrCmpIA(WORD ch1, WORD ch2) +{ + TRACE("(%d,%d)\n", ch1, ch2); + + return SHLWAPI_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE); +} + +/************************************************************************* + * SHLWAPI_ChrCmpW + * + * Internal helper function. + */ +static BOOL WINAPI SHLWAPI_ChrCmpW(WCHAR ch1, WCHAR ch2) +{ + return SHLWAPI_ChrCmpHelperW(ch1, ch2, 0); +} + +/************************************************************************* + * ChrCmpIW [SHLWAPI.386] + * + * See ChrCmpIA. + */ +BOOL WINAPI ChrCmpIW(WCHAR ch1, WCHAR ch2) +{ + return SHLWAPI_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE); +} + +/************************************************************************* + * StrChrA [SHLWAPI.@] + * + * Find a given character in a string. + * + * PARAMS + * lpszStr [I] String to search in. + * ch [I] Character to search for. + * + * RETURNS + * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if + * not found. + * Failure: NULL, if any arguments are invalid. + */ +LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch) +{ + TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch); + + if (lpszStr) + { + while (*lpszStr) + { + if (!SHLWAPI_ChrCmpA(*lpszStr, ch)) + return (LPSTR)lpszStr; + lpszStr = CharNextA(lpszStr); + } + } + return NULL; +} + +/************************************************************************* + * StrChrW [SHLWAPI.@] + * + * See StrChrA. + */ +LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch) +{ + LPWSTR lpszRet = NULL; + + TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch); + + if (lpszStr) + lpszRet = strchrW(lpszStr, ch); + return lpszRet; +} + +/************************************************************************* + * StrChrIA [SHLWAPI.@] + * + * Find a given character in a string, ignoring case. + * + * PARAMS + * lpszStr [I] String to search in. + * ch [I] Character to search for. + * + * RETURNS + * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if + * not found. + * Failure: NULL, if any arguments are invalid. + */ +LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch) +{ + TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch); + + if (lpszStr) + { + while (*lpszStr) + { + if (!ChrCmpIA(*lpszStr, ch)) + return (LPSTR)lpszStr; + lpszStr = CharNextA(lpszStr); + } + } + return NULL; +} + +/************************************************************************* + * StrChrIW [SHLWAPI.@] + * + * See StrChrA. + */ +LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch) +{ + TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch); + + if (lpszStr) + { + ch = toupperW(ch); + while (*lpszStr) + { + if (toupperW(*lpszStr) == ch) + return (LPWSTR)lpszStr; + lpszStr = CharNextW(lpszStr); + } + lpszStr = NULL; + } + return (LPWSTR)lpszStr; +} + +/************************************************************************* + * StrCmpIW [SHLWAPI.@] + * + * Compare two strings, ignoring case. + * + * PARAMS + * lpszStr [I] First string to compare + * lpszComp [I] Second string to compare + * + * RETURNS + * An integer less than, equal to or greater than 0, indicating that + * lpszStr is less than, the same, or greater than lpszComp. + */ +int WINAPI StrCmpIW(LPCWSTR lpszStr, LPCWSTR lpszComp) +{ + int iRet; + + TRACE("(%s,%s)\n", debugstr_w(lpszStr),debugstr_w(lpszComp)); + + iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, -1, lpszComp, -1); + return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; +} + +/************************************************************************* + * StrCmpNA [SHLWAPI.@] + * + * Compare two strings, up to a maximum length. + * + * PARAMS + * lpszStr [I] First string to compare + * lpszComp [I] Second string to compare + * iLen [I] Maximum number of chars to compare. + * + * RETURNS + * An integer less than, equal to or greater than 0, indicating that + * lpszStr is less than, the same, or greater than lpszComp. + */ +INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen) +{ + INT iRet; + + TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen); + + iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen); + return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; +} + +/************************************************************************* + * StrCmpNW [SHLWAPI.@] + * + * See StrCmpNA. + */ +INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen) +{ + INT iRet; + + TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen); + + iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen); + return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; +} + +/************************************************************************* + * StrCmpNIA [SHLWAPI.@] + * + * Compare two strings, up to a maximum length, ignoring case. + * + * PARAMS + * lpszStr [I] First string to compare + * lpszComp [I] Second string to compare + * iLen [I] Maximum number of chars to compare. + * + * RETURNS + * An integer less than, equal to or greater than 0, indicating that + * lpszStr is less than, the same, or greater than lpszComp. + */ +int WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, int iLen) +{ + INT iRet; + + TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen); + + iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen); + return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; +} + +/************************************************************************* + * StrCmpNIW [SHLWAPI.@] + * + * See StrCmpNIA. + */ +INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, int iLen) +{ + INT iRet; + + TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen); + + iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen); + return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; +} + +/************************************************************************* + * StrCmpW [SHLWAPI.@] + * + * Compare two strings. + * + * PARAMS + * lpszStr [I] First string to compare + * lpszComp [I] Second string to compare + * + * RETURNS + * An integer less than, equal to or greater than 0, indicating that + * lpszStr is less than, the same, or greater than lpszComp. + */ +int WINAPI StrCmpW(LPCWSTR lpszStr, LPCWSTR lpszComp) +{ + INT iRet; + + TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp)); + + iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, -1, lpszComp, -1); + return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0; +} + +/************************************************************************* + * StrCatW [SHLWAPI.@] + * + * Concatanate two strings. + * + * PARAMS + * lpszStr [O] Initial string + * lpszSrc [I] String to concatanate + * + * RETURNS + * lpszStr. + */ +LPWSTR WINAPI StrCatW(LPWSTR lpszStr, LPCWSTR lpszSrc) +{ + TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSrc)); + + strcatW(lpszStr, lpszSrc); + return lpszStr; +} + +/************************************************************************* + * StrCpyW [SHLWAPI.@] + * + * Copy a string to another string. + * + * PARAMS + * lpszStr [O] Destination string + * lpszSrc [I] Source string + * + * RETURNS + * lpszStr. + */ +LPWSTR WINAPI StrCpyW(LPWSTR lpszStr, LPCWSTR lpszSrc) +{ + TRACE("(%p,%s)\n", lpszStr, debugstr_w(lpszSrc)); + + strcpyW(lpszStr, lpszSrc); + return lpszStr; +} + +/************************************************************************* + * StrCpyNW [SHLWAPI.@] + * + * Copy a string to another string, up to a maximum number of characters. + * + * PARAMS + * lpszStr [O] Destination string + * lpszSrc [I] Source string + * iLen [I] Maximum number of chars to copy + * + * RETURNS + * lpszStr. + */ +LPWSTR WINAPI StrCpyNW(LPWSTR lpszStr, LPCWSTR lpszSrc, int iLen) +{ + TRACE("(%p,%s,%i)\n", lpszStr, debugstr_w(lpszSrc), iLen); + + lstrcpynW(lpszStr, lpszSrc, iLen); + return lpszStr; +} + + + +/************************************************************************* + * SHLWAPI_StrStrHelperA + * + * Internal implementation of StrStrA/StrStrIA + */ +static LPSTR WINAPI SHLWAPI_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch, + int (*pStrCmpFn)(LPCSTR,LPCSTR,size_t)) +{ + size_t iLen; + + if (!lpszStr || !lpszSearch || !*lpszSearch) + return NULL; + + iLen = strlen(lpszSearch); + + while (*lpszStr) + { + if (!pStrCmpFn(lpszStr, lpszSearch, iLen)) + return (LPSTR)lpszStr; + lpszStr = CharNextA(lpszStr); + } + return NULL; +} + +/************************************************************************* + * SHLWAPI_StrStrHelperW + * + * Internal implementation of StrStrW/StrStrIW + */ +static LPWSTR WINAPI SHLWAPI_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch, + int (*pStrCmpFn)(LPCWSTR,LPCWSTR,int)) +{ + int iLen; + + if (!lpszStr || !lpszSearch || !*lpszSearch) + return NULL; + + iLen = strlenW(lpszSearch); + + while (*lpszStr) + { + if (!pStrCmpFn(lpszStr, lpszSearch, iLen)) + return (LPWSTR)lpszStr; + lpszStr = CharNextW(lpszStr); + } + return NULL; +} + +/************************************************************************* + * StrStrA [SHLWAPI.@] + * + * Find a substring within a string. + * + * PARAMS + * lpszStr [I] String to search in + * lpszSearch [I] String to look for + * + * RETURNS + * The start of lpszSearch within lpszStr, or NULL if not found. + */ +LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch) +{ + TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch)); + + return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncmp); +} + +/************************************************************************* + * StrStrW [SHLWAPI.@] + * + * See StrStrA. + */ +LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch) +{ + TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch)); + + return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, (int (*)(LPCWSTR,LPCWSTR,int))wcsncmp); +} + +/************************************************************************* + * StrRStrIA [SHLWAPI.@] + * + * Find the last occurrence of a substring within a string. + * + * PARAMS + * lpszStr [I] String to search in + * lpszEnd [I] End of lpszStr + * lpszSearch [I] String to look for + * + * RETURNS + * The last occurrence lpszSearch within lpszStr, or NULL if not found. + */ +LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch) +{ + LPSTR lpszRet = NULL; + WORD ch1, ch2; + INT iLen; + + TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch)); + + if (!lpszStr || !lpszSearch || !*lpszSearch) + return NULL; + + if (!lpszEnd) + lpszEnd = lpszStr + lstrlenA(lpszStr); + + if (IsDBCSLeadByte(*lpszSearch)) + ch1 = *lpszSearch << 8 | lpszSearch[1]; + else + ch1 = *lpszSearch; + iLen = lstrlenA(lpszSearch); + + while (lpszStr <= lpszEnd && *lpszStr) + { + ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr; + if (!ChrCmpIA(ch1, ch2)) + { + if (!StrCmpNIA(lpszStr, lpszSearch, iLen)) + lpszRet = (LPSTR)lpszStr; + } + lpszStr = CharNextA(lpszStr); + } + return lpszRet; +} + +/************************************************************************* + * StrRStrIW [SHLWAPI.@] + * + * See StrRStrIA. + */ +LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch) +{ + LPWSTR lpszRet = NULL; + INT iLen; + + TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch)); + + if (!lpszStr || !lpszSearch || !*lpszSearch) + return NULL; + + if (!lpszEnd) + lpszEnd = lpszStr + strlenW(lpszStr); + + iLen = strlenW(lpszSearch); + + while (lpszStr <= lpszEnd && *lpszStr) + { + if (!ChrCmpIW(*lpszSearch, *lpszStr)) + { + if (!StrCmpNIW(lpszStr, lpszSearch, iLen)) + lpszRet = (LPWSTR)lpszStr; + } + lpszStr = CharNextW(lpszStr); + } + return lpszRet; +} + +/************************************************************************* + * StrStrIA [SHLWAPI.@] + * + * Find a substring within a string, ignoring case. + * + * PARAMS + * lpszStr [I] String to search in + * lpszSearch [I] String to look for + * + * RETURNS + * The start of lpszSearch within lpszStr, or NULL if not found. + */ +LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch) +{ + TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch)); + + return SHLWAPI_StrStrHelperA(lpszStr, lpszSearch, strncasecmp); +} + +/************************************************************************* + * StrStrIW [SHLWAPI.@] + * + * See StrStrIA. + */ +LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch) +{ + TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch)); + + return SHLWAPI_StrStrHelperW(lpszStr, lpszSearch, (int (*)(LPCWSTR,LPCWSTR,int))_wcsnicmp); +} + +/************************************************************************* + * StrToIntA [SHLWAPI.@] + * + * Read a signed integer from a string. + * + * PARAMS + * lpszStr [I] String to read integer from + * + * RETURNS + * The signed integer value represented by the string, or 0 if no integer is + * present. + * + * NOTES + * No leading space is allowed before the number, although a leading '-' is. + */ +int WINAPI StrToIntA(LPCSTR lpszStr) +{ + int iRet = 0; + + TRACE("(%s)\n", debugstr_a(lpszStr)); + + if (!lpszStr) + { + WARN("Invalid lpszStr would crash under Win32!\n"); + return 0; + } + + if (*lpszStr == '-' || isdigit(*lpszStr)) + StrToIntExA(lpszStr, 0, &iRet); + return iRet; +} + +/************************************************************************* + * StrToIntW [SHLWAPI.@] + * + * See StrToIntA. + */ +int WINAPI StrToIntW(LPCWSTR lpszStr) +{ + int iRet = 0; + + TRACE("(%s)\n", debugstr_w(lpszStr)); + + if (!lpszStr) + { + WARN("Invalid lpszStr would crash under Win32!\n"); + return 0; + } + + if (*lpszStr == '-' || isdigitW(*lpszStr)) + StrToIntExW(lpszStr, 0, &iRet); + return iRet; +} + +/************************************************************************* + * StrToIntExA [SHLWAPI.@] + * + * Read an integer from a string. + * + * PARAMS + * lpszStr [I] String to read integer from + * dwFlags [I] Flags controlling the conversion + * lpiRet [O] Destination for read integer. + * + * RETURNS + * Success: TRUE. lpiRet contains the integer value represented by the string. + * Failure: FALSE, if the string is invalid, or no number is present. + * + * NOTES + * Leading whitespace, '-' and '+' are allowed before the number. If + * dwFlags includes STIF_SUPPORT_HEX, hexadecimal numbers are allowed, if + * preceded by '0x'. If this flag is not set, or there is no '0x' prefix, + * the string is treated as a decimal string. A leading '-' is ignored for + * hexadecimal numbers. + */ +BOOL WINAPI StrToIntExA(LPCSTR lpszStr, DWORD dwFlags, LPINT lpiRet) +{ + BOOL bNegative = FALSE; + int iRet = 0; + + TRACE("(%s,%08lX,%p)\n", debugstr_a(lpszStr), dwFlags, lpiRet); + + if (!lpszStr || !lpiRet) + { + WARN("Invalid parameter would crash under Win32!\n"); + return FALSE; + } + if (dwFlags > STIF_SUPPORT_HEX) + { + WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX); + } + + /* Skip leading space, '+', '-' */ + while (isspace(*lpszStr)) + lpszStr = CharNextA(lpszStr); + + if (*lpszStr == '-') + { + bNegative = TRUE; + lpszStr++; + } + else if (*lpszStr == '+') + lpszStr++; + + if (dwFlags & STIF_SUPPORT_HEX && + *lpszStr == '0' && tolower(lpszStr[1]) == 'x') + { + /* Read hex number */ + lpszStr += 2; + + if (!isxdigit(*lpszStr)) + return FALSE; + + while (isxdigit(*lpszStr)) + { + iRet = iRet * 16; + if (isdigit(*lpszStr)) + iRet += (*lpszStr - '0'); + else + iRet += 10 + (tolower(*lpszStr) - 'a'); + lpszStr++; + } + *lpiRet = iRet; + return TRUE; + } + + /* Read decimal number */ + if (!isdigit(*lpszStr)) + return FALSE; + + while (isdigit(*lpszStr)) + { + iRet = iRet * 10; + iRet += (*lpszStr - '0'); + lpszStr++; + } + *lpiRet = bNegative ? -iRet : iRet; + return TRUE; +} + +/************************************************************************* + * StrToIntExW [SHLWAPI.@] + * + * See StrToIntExA. + */ +BOOL WINAPI StrToIntExW(LPCWSTR lpszStr, DWORD dwFlags, LPINT lpiRet) +{ + BOOL bNegative = FALSE; + int iRet = 0; + + TRACE("(%s,%08lX,%p)\n", debugstr_w(lpszStr), dwFlags, lpiRet); + + if (!lpszStr || !lpiRet) + { + WARN("Invalid parameter would crash under Win32!\n"); + return FALSE; + } + if (dwFlags > STIF_SUPPORT_HEX) + { + WARN("Unknown flags (%08lX)!\n", dwFlags & ~STIF_SUPPORT_HEX); + } + + /* Skip leading space, '+', '-' */ + while (isspaceW(*lpszStr)) + lpszStr = CharNextW(lpszStr); + + if (*lpszStr == '-') + { + bNegative = TRUE; + lpszStr++; + } + else if (*lpszStr == '+') + lpszStr++; + + if (dwFlags & STIF_SUPPORT_HEX && + *lpszStr == '0' && tolowerW(lpszStr[1]) == 'x') + { + /* Read hex number */ + lpszStr += 2; + + if (!isxdigitW(*lpszStr)) + return FALSE; + + while (isxdigitW(*lpszStr)) + { + iRet = iRet * 16; + if (isdigitW(*lpszStr)) + iRet += (*lpszStr - '0'); + else + iRet += 10 + (tolowerW(*lpszStr) - 'a'); + lpszStr++; + } + *lpiRet = iRet; + return TRUE; + } + + /* Read decimal number */ + if (!isdigitW(*lpszStr)) + return FALSE; + + while (isdigitW(*lpszStr)) + { + iRet = iRet * 10; + iRet += (*lpszStr - '0'); + lpszStr++; + } + *lpiRet = bNegative ? -iRet : iRet; + return TRUE; +} + +/************************************************************************* + * StrDupA [SHLWAPI.@] + * + * Duplicate a string. + * + * PARAMS + * lpszStr [I] String to duplicate. + * + * RETURNS + * Success: A pointer to a new string containing the contents of lpszStr + * Failure: NULL, if memory cannot be allocated + * + * NOTES + * The string memory is allocated with LocalAlloc(), and so should be released + * by calling LocalFree(). + */ +LPSTR WINAPI StrDupA(LPCSTR lpszStr) +{ + int iLen; + LPSTR lpszRet; + + TRACE("(%s)\n",debugstr_a(lpszStr)); + + iLen = lpszStr ? strlen(lpszStr) + 1 : 1; + lpszRet = (LPSTR)LocalAlloc(LMEM_FIXED, iLen); + + if (lpszRet) + { + if (lpszStr) + memcpy(lpszRet, lpszStr, iLen); + else + *lpszRet = '\0'; + } + return lpszRet; +} + +/************************************************************************* + * StrDupW [SHLWAPI.@] + * + * See StrDupA. + */ +LPWSTR WINAPI StrDupW(LPCWSTR lpszStr) +{ + int iLen; + LPWSTR lpszRet; + + TRACE("(%s)\n",debugstr_w(lpszStr)); + + iLen = (lpszStr ? strlenW(lpszStr) + 1 : 1) * sizeof(WCHAR); + lpszRet = (LPWSTR)LocalAlloc(LMEM_FIXED, iLen); + + if (lpszRet) + { + if (lpszStr) + memcpy(lpszRet, lpszStr, iLen); + else + *lpszRet = '\0'; + } + return lpszRet; +} + +/************************************************************************* + * SHLWAPI_StrSpnHelperA + * + * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA + */ +static int WINAPI SHLWAPI_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch, + LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD), + BOOL bInvert) +{ + LPCSTR lpszRead = lpszStr; + if (lpszStr && *lpszStr && lpszMatch) + { + while (*lpszRead) + { + LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead); + + if (!bInvert && !lpszTest) + break; + if (bInvert && lpszTest) + break; + lpszRead = CharNextA(lpszRead); + }; + } + return lpszRead - lpszStr; +} + +/************************************************************************* + * SHLWAPI_StrSpnHelperW + * + * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW + */ +static int WINAPI SHLWAPI_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch, + LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR), + BOOL bInvert) +{ + LPCWSTR lpszRead = lpszStr; + if (lpszStr && *lpszStr && lpszMatch) + { + while (*lpszRead) + { + LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead); + + if (!bInvert && !lpszTest) + break; + if (bInvert && lpszTest) + break; + lpszRead = CharNextW(lpszRead); + }; + } + return lpszRead - lpszStr; +} + +/************************************************************************* + * StrSpnA [SHLWAPI.@] + * + * Find the length of the start of a string that contains only certain + * characters. + * + * PARAMS + * lpszStr [I] String to search + * lpszMatch [I] Characters that can be in the substring + * + * RETURNS + * The length of the part of lpszStr containing only chars from lpszMatch, + * or 0 if any parameter is invalid. + */ +int WINAPI StrSpnA(LPCSTR lpszStr, LPCSTR lpszMatch) +{ + TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); + + return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, FALSE); +} + +/************************************************************************* + * StrSpnW [SHLWAPI.@] + * + * See StrSpnA. + */ +int WINAPI StrSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch) +{ + TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch)); + + return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, FALSE); +} + +/************************************************************************* + * StrCSpnA [SHLWAPI.@] + * + * Find the length of the start of a string that does not contain certain + * characters. + * + * PARAMS + * lpszStr [I] String to search + * lpszMatch [I] Characters that cannot be in the substring + * + * RETURNS + * The length of the part of lpszStr containing only chars not in lpszMatch, + * or 0 if any parameter is invalid. + */ +int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch) +{ + TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); + + return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE); +} + +/************************************************************************* + * StrCSpnW [SHLWAPI.@] + * + * See StrCSpnA. + */ +int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch) +{ + TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch)); + + return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE); +} + +/************************************************************************* + * StrCSpnIA [SHLWAPI.@] + * + * Find the length of the start of a string that does not contain certain + * characters, ignoring case. + * + * PARAMS + * lpszStr [I] String to search + * lpszMatch [I] Characters that cannot be in the substring + * + * RETURNS + * The length of the part of lpszStr containing only chars not in lpszMatch, + * or 0 if any parameter is invalid. + */ +int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch) +{ + TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); + + return SHLWAPI_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE); +} + +/************************************************************************* + * StrCSpnIW [SHLWAPI.@] + * + * See StrCSpnIA. + */ +int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch) +{ + TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch)); + + return SHLWAPI_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE); +} + +/************************************************************************* + * StrPBrkA [SHLWAPI.@] + * + * Search a string for any of a group of characters. + * + * PARAMS + * lpszStr [I] String to search + * lpszMatch [I] Characters to match + * + * RETURNS + * A pointer to the first matching character in lpszStr, or NULL if no + * match was found. + */ +LPSTR WINAPI StrPBrkA(LPCSTR lpszStr, LPCSTR lpszMatch) +{ + TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch)); + + if (lpszStr && lpszMatch && *lpszMatch) + { + while (*lpszStr) + { + if (StrChrA(lpszMatch, *lpszStr)) + return (LPSTR)lpszStr; + lpszStr = CharNextA(lpszStr); + } + } + return NULL; +} + +/************************************************************************* + * StrPBrkW [SHLWAPI.@] + * + * See StrPBrkA. + */ +LPWSTR WINAPI StrPBrkW(LPCWSTR lpszStr, LPCWSTR lpszMatch) +{ + TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch)); + + if (lpszStr && lpszMatch && *lpszMatch) + { + while (*lpszStr) + { + if (StrChrW(lpszMatch, *lpszStr)) + return (LPWSTR)lpszStr; + lpszStr = CharNextW(lpszStr); + } + } + return NULL; +} + +/************************************************************************* + * SHLWAPI_StrRChrHelperA + * + * Internal implementation of StrRChrA/StrRChrIA. + */ +static LPSTR WINAPI SHLWAPI_StrRChrHelperA(LPCSTR lpszStr, + LPCSTR lpszEnd, WORD ch, + BOOL (WINAPI *pChrCmpFn)(WORD,WORD)) +{ + LPCSTR lpszRet = NULL; + + if (lpszStr) + { + WORD ch2; + + if (!lpszEnd) + lpszEnd = lpszStr + lstrlenA(lpszStr); + + while (*lpszStr && lpszStr <= lpszEnd) + { + ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr; + + if (!pChrCmpFn(ch, ch2)) + lpszRet = lpszStr; + lpszStr = CharNextA(lpszStr); + } + } + return (LPSTR)lpszRet; +} + +/************************************************************************* + * SHLWAPI_StrRChrHelperW + * + * Internal implementation of StrRChrW/StrRChrIW. + */ +static LPWSTR WINAPI SHLWAPI_StrRChrHelperW(LPCWSTR lpszStr, + LPCWSTR lpszEnd, WCHAR ch, + BOOL (WINAPI *pChrCmpFn)(WCHAR,WCHAR)) +{ + LPCWSTR lpszRet = NULL; + + if (lpszStr) + { + if (!lpszEnd) + lpszEnd = lpszStr + strlenW(lpszStr); + + while (*lpszStr && lpszStr <= lpszEnd) + { + if (!pChrCmpFn(ch, *lpszStr)) + lpszRet = lpszStr; + lpszStr = CharNextW(lpszStr); + } + } + return (LPWSTR)lpszRet; +} + +/************************************************************************** + * StrRChrA [SHLWAPI.@] + * + * Find the last occurrence of a character in string. + * + * PARAMS + * lpszStr [I] String to search in + * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr + * ch [I] Character to search for. + * + * RETURNS + * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd, + * or NULL if not found. + * Failure: NULL, if any arguments are invalid. + */ +LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch) +{ + TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch); + + return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpA); +} + +/************************************************************************** + * StrRChrW [SHLWAPI.@] + * + * See StrRChrA. + */ +LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch) +{ + TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch); + + return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, SHLWAPI_ChrCmpW); +} + +/************************************************************************** + * StrRChrIA [SHLWAPI.@] + * + * Find the last occurrence of a character in string, ignoring case. + * + * PARAMS + * lpszStr [I] String to search in + * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr + * ch [I] Character to search for. + * + * RETURNS + * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd, + * or NULL if not found. + * Failure: NULL, if any arguments are invalid. + */ +LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch) +{ + TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch); + + return SHLWAPI_StrRChrHelperA(lpszStr, lpszEnd, ch, ChrCmpIA); +} + +/************************************************************************** + * StrRChrIW [SHLWAPI.@] + * + * See StrRChrIA. + */ +LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch) +{ + TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch); + + return SHLWAPI_StrRChrHelperW(lpszStr, lpszEnd, ch, ChrCmpIW); +} + +/************************************************************************* + * StrCatBuffA [SHLWAPI.@] + * + * Concatenate two strings together. + * + * PARAMS + * lpszStr [O] String to concatenate to + * lpszCat [I] String to add to lpszCat + * cchMax [I] Maximum number of characters for the whole string + * + * RETURNS + * lpszStr. + * + * NOTES + * cchMax determines the number of characters in the final length of the + * string, not the number appended to lpszStr from lpszCat. + */ +LPSTR WINAPI StrCatBuffA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax) +{ + INT iLen; + + TRACE("(%p,%s,%d)\n", lpszStr, debugstr_a(lpszCat), cchMax); + + if (!lpszStr) + { + WARN("Invalid lpszStr would crash under Win32!\n"); + return NULL; + } + + iLen = strlen(lpszStr); + cchMax -= iLen; + + if (cchMax > 0) + StrCpyNA(lpszStr + iLen, lpszCat, cchMax); + return lpszStr; +} + +/************************************************************************* + * StrCatBuffW [SHLWAPI.@] + * + * See StrCatBuffA. + */ +LPWSTR WINAPI StrCatBuffW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax) +{ + INT iLen; + + TRACE("(%p,%s,%d)\n", lpszStr, debugstr_w(lpszCat), cchMax); + + if (!lpszStr) + { + WARN("Invalid lpszStr would crash under Win32!\n"); + return NULL; + } + + iLen = strlenW(lpszStr); + cchMax -= iLen; + + if (cchMax > 0) + StrCpyNW(lpszStr + iLen, lpszCat, cchMax); + return lpszStr; +} + +/************************************************************************* + * StrRetToBufA [SHLWAPI.@] + * + * Convert a STRRET to a normal string. + * + * PARAMS + * lpStrRet [O] STRRET to convert + * pIdl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET + * lpszDest [O] Destination for normal string + * dwLen [I] Length of lpszDest + * + * RETURNS + * Success: S_OK. lpszDest contains up to dwLen characters of the string. + * If lpStrRet is of type STRRET_WSTR, its memory is freed with + * CoTaskMemFree() and its type set to STRRET_CSTRA. + * Failure: E_FAIL, if any parameters are invalid. + */ +HRESULT WINAPI StrRetToBufA (LPSTRRET src, const ITEMIDLIST *pidl, LPSTR dest, UINT len) +{ + /* NOTE: + * This routine is identical to that in dlls/shell32/shellstring.c. + * It was duplicated because not every version of Shlwapi.dll exports + * StrRetToBufA. If you change one routine, change them both. + */ + TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl); + + if (!src) + { + WARN("Invalid lpStrRet would crash under Win32!\n"); + if (dest) + *dest = '\0'; + return E_FAIL; + } + + if (!dest || !len) + return E_FAIL; + + *dest = '\0'; + + switch (src->uType) + { + case STRRET_WSTR: + WideCharToMultiByte(CP_ACP, 0, src->u.pOleStr, -1, dest, len, NULL, NULL); + CoTaskMemFree(src->u.pOleStr); + break; + + case STRRET_CSTR: + lstrcpynA((LPSTR)dest, src->u.cStr, len); + break; + + case STRRET_OFFSET: + lstrcpynA((LPSTR)dest, ((LPCSTR)&pidl->mkid)+src->u.uOffset, len); + break; + + default: + FIXME("unknown type!\n"); + return FALSE; + } + return S_OK; +} + +/************************************************************************* + * StrRetToBufW [SHLWAPI.@] + * + * See StrRetToBufA. + */ +HRESULT WINAPI StrRetToBufW (LPSTRRET src, const ITEMIDLIST *pidl, LPWSTR dest, UINT len) +{ + TRACE("dest=%p len=0x%x strret=%p pidl=%p stub\n",dest,len,src,pidl); + + if (!src) + { + WARN("Invalid lpStrRet would crash under Win32!\n"); + if (dest) + *dest = '\0'; + return E_FAIL; + } + + if (!dest || !len) + return E_FAIL; + + *dest = '\0'; + + switch (src->uType) + { + case STRRET_WSTR: + lstrcpynW((LPWSTR)dest, src->u.pOleStr, len); + CoTaskMemFree(src->u.pOleStr); + break; + + case STRRET_CSTR: + if (!MultiByteToWideChar( CP_ACP, 0, src->u.cStr, -1, dest, len ) && len) + dest[len-1] = 0; + break; + + case STRRET_OFFSET: + if (pidl) + { + if (!MultiByteToWideChar( CP_ACP, 0, ((LPCSTR)&pidl->mkid)+src->u.uOffset, -1, + dest, len ) && len) + dest[len-1] = 0; + } + break; + + default: + FIXME("unknown type!\n"); + return FALSE; + } + return S_OK; +} + +/************************************************************************* + * StrRetToStrA [SHLWAPI.@] + * + * Converts a STRRET to a normal string. + * + * PARAMS + * lpStrRet [O] STRRET to convert + * pidl [I] ITEMIDLIST for lpStrRet->uType == STRRET_OFFSET + * ppszName [O] Destination for converted string + * + * RETURNS + * Success: S_OK. ppszName contains the new string, allocated with CoTaskMemAlloc(). + * Failure: E_FAIL, if any parameters are invalid. + */ +HRESULT WINAPI StrRetToStrA(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPSTR *ppszName) +{ + HRESULT hRet = E_FAIL; + + switch (lpStrRet->uType) + { + case STRRET_WSTR: + hRet = _SHStrDupAW(lpStrRet->u.pOleStr, ppszName); + CoTaskMemFree(lpStrRet->u.pOleStr); + break; + + case STRRET_CSTR: + hRet = _SHStrDupAA(lpStrRet->u.cStr, ppszName); + break; + + case STRRET_OFFSET: + hRet = _SHStrDupAA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName); + break; + + default: + *ppszName = NULL; + } + + return hRet; +} + +/************************************************************************* + * StrRetToStrW [SHLWAPI.@] + * + * See StrRetToStrA. + */ +HRESULT WINAPI StrRetToStrW(LPSTRRET lpStrRet, const ITEMIDLIST *pidl, LPWSTR *ppszName) +{ + HRESULT hRet = E_FAIL; + + switch (lpStrRet->uType) + { + case STRRET_WSTR: + hRet = SHStrDupW(lpStrRet->u.pOleStr, ppszName); + CoTaskMemFree(lpStrRet->u.pOleStr); + break; + + case STRRET_CSTR: + hRet = SHStrDupA(lpStrRet->u.cStr, ppszName); + break; + + case STRRET_OFFSET: + hRet = SHStrDupA(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, ppszName); + break; + + default: + *ppszName = NULL; + } + + return hRet; +} + +/* Create an ASCII string copy using SysAllocString() */ +static HRESULT _SHStrDupAToBSTR(LPCSTR src, BSTR *pBstrOut) +{ + *pBstrOut = NULL; + + if (src) + { + INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0); + WCHAR* szTemp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + + if (szTemp) + { + MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len); + *pBstrOut = SysAllocString(szTemp); + HeapFree(GetProcessHeap(), 0, szTemp); + + if (*pBstrOut) + return S_OK; + } + } + return E_OUTOFMEMORY; +} + +/************************************************************************* + * StrRetToBSTR [SHLWAPI.@] + * + * Converts a STRRET to a BSTR. + * + * PARAMS + * lpStrRet [O] STRRET to convert + * pidl [I] ITEMIDLIST for lpStrRet->uType = STRRET_OFFSET + * pBstrOut [O] Destination for converted BSTR + * + * RETURNS + * Success: S_OK. pBstrOut contains the new string. + * Failure: E_FAIL, if any parameters are invalid. + */ +HRESULT WINAPI StrRetToBSTR(STRRET *lpStrRet, LPCITEMIDLIST pidl, BSTR* pBstrOut) +{ + HRESULT hRet = E_FAIL; + + switch (lpStrRet->uType) + { + case STRRET_WSTR: + *pBstrOut = SysAllocString(lpStrRet->u.pOleStr); + if (*pBstrOut) + hRet = S_OK; + CoTaskMemFree(lpStrRet->u.pOleStr); + break; + + case STRRET_CSTR: + hRet = _SHStrDupAToBSTR(lpStrRet->u.cStr, pBstrOut); + break; + + case STRRET_OFFSET: + hRet = _SHStrDupAToBSTR(((LPCSTR)&pidl->mkid) + lpStrRet->u.uOffset, pBstrOut); + break; + + default: + *pBstrOut = NULL; + } + + return hRet; +} + +/************************************************************************* + * StrFormatKBSizeA [SHLWAPI.@] + * + * Create a formatted string containing a byte count in Kilobytes. + * + * PARAMS + * llBytes [I] Byte size to format + * lpszDest [I] Destination for formatted string + * cchMax [I] Size of lpszDest + * + * RETURNS + * lpszDest. + */ +LPSTR WINAPI StrFormatKBSizeA(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax) +{ + char szBuff[256], *szOut = szBuff + sizeof(szBuff) - 1; + LONGLONG ulKB = (llBytes + 1023) >> 10; + + TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax); + + *szOut-- = '\0'; + *szOut-- = 'B'; + *szOut-- = 'K'; + *szOut-- = ' '; + + do + { + LONGLONG ulNextDigit = ulKB % 10; + *szOut-- = '0' + ulNextDigit; + ulKB = (ulKB - ulNextDigit) / 10; + } while (ulKB > 0); + + lstrcpynA(lpszDest, szOut + 1, cchMax); + return lpszDest; +} + +/************************************************************************* + * StrFormatKBSizeW [SHLWAPI.@] + * + * See StrFormatKBSizeA. + */ +LPWSTR WINAPI StrFormatKBSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax) +{ + WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1; + LONGLONG ulKB = (llBytes + 1023) >> 10; + + TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax); + + *szOut-- = '\0'; + *szOut-- = 'B'; + *szOut-- = 'K'; + *szOut-- = ' '; + + do + { + LONGLONG ulNextDigit = ulKB % 10; + *szOut-- = '0' + ulNextDigit; + ulKB = (ulKB - ulNextDigit) / 10; + } while (ulKB > 0); + + lstrcpynW(lpszDest, szOut + 1, cchMax); + return lpszDest; +} + +/************************************************************************* + * StrNCatA [SHLWAPI.@] + * + * Concatenate two strings together. + * + * PARAMS + * lpszStr [O] String to concatenate to + * lpszCat [I] String to add to lpszCat + * cchMax [I] Maximum number of characters to concatenate + * + * RETURNS + * lpszStr. + * + * NOTES + * cchMax determines the number of characters that are appended to lpszStr, + * not the total length of the string. + */ +LPSTR WINAPI StrNCatA(LPSTR lpszStr, LPCSTR lpszCat, INT cchMax) +{ + LPSTR lpszRet = lpszStr; + + TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszCat), cchMax); + + if (!lpszStr) + { + WARN("Invalid lpszStr would crash under Win32!\n"); + return NULL; + } + + StrCpyNA(lpszStr + strlen(lpszStr), lpszCat, cchMax); + return lpszRet; +} + +/************************************************************************* + * StrNCatW [SHLWAPI.@] + * + * See StrNCatA. + */ +LPWSTR WINAPI StrNCatW(LPWSTR lpszStr, LPCWSTR lpszCat, INT cchMax) +{ + LPWSTR lpszRet = lpszStr; + + TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszCat), cchMax); + + if (!lpszStr) + { + WARN("Invalid lpszStr would crash under Win32\n"); + return NULL; + } + + StrCpyNW(lpszStr + strlenW(lpszStr), lpszCat, cchMax); + return lpszRet; +} + +/************************************************************************* + * StrTrimA [SHLWAPI.@] + * + * Remove characters from the start and end of a string. + * + * PARAMS + * lpszStr [O] String to remove characters from + * lpszTrim [I] Characters to remove from lpszStr + * + * RETURNS + * TRUE If lpszStr was valid and modified + * FALSE Otherwise + */ +BOOL WINAPI StrTrimA(LPSTR lpszStr, LPCSTR lpszTrim) +{ + DWORD dwLen; + LPSTR lpszRead = lpszStr; + BOOL bRet = FALSE; + + TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszTrim)); + + if (lpszRead && *lpszRead) + { + while (*lpszRead && StrChrA(lpszTrim, *lpszRead)) + lpszRead = CharNextA(lpszRead); /* Skip leading matches */ + + dwLen = strlen(lpszRead); + + if (lpszRead != lpszStr) + { + memmove(lpszStr, lpszRead, dwLen + 1); + bRet = TRUE; + } + if (dwLen > 0) + { + lpszRead = lpszStr + dwLen; + while (StrChrA(lpszTrim, lpszRead[-1])) + lpszRead = CharPrevA(lpszStr, lpszRead); /* Skip trailing matches */ + + if (lpszRead != lpszStr + dwLen) + { + *lpszRead = '\0'; + bRet = TRUE; + } + } + } + return bRet; +} + +/************************************************************************* + * StrTrimW [SHLWAPI.@] + * + * See StrTrimA. + */ +BOOL WINAPI StrTrimW(LPWSTR lpszStr, LPCWSTR lpszTrim) +{ + DWORD dwLen; + LPWSTR lpszRead = lpszStr; + BOOL bRet = FALSE; + + TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszTrim)); + + if (lpszRead && *lpszRead) + { + while (*lpszRead && StrChrW(lpszTrim, *lpszRead)) + lpszRead = CharNextW(lpszRead); /* Skip leading matches */ + + dwLen = strlenW(lpszRead); + + if (lpszRead != lpszStr) + { + memmove(lpszStr, lpszRead, (dwLen + 1) * sizeof(WCHAR)); + bRet = TRUE; + } + if (dwLen > 0) + { + lpszRead = lpszStr + dwLen; + while (StrChrW(lpszTrim, lpszRead[-1])) + lpszRead = CharPrevW(lpszStr, lpszRead); /* Skip trailing matches */ + + if (lpszRead != lpszStr + dwLen) + { + *lpszRead = '\0'; + bRet = TRUE; + } + } + } + return bRet; +} + +/************************************************************************* + * _SHStrDupAA [INTERNAL] + * + * Duplicates a ASCII string to ASCII. The destination buffer is allocated. + */ +static HRESULT WINAPI _SHStrDupAA(LPCSTR src, LPSTR * dest) +{ + HRESULT hr; + int len = 0; + + if (src) { + len = lstrlenA(src) + 1; + *dest = CoTaskMemAlloc(len); + } else { + *dest = NULL; + } + + if (*dest) { + lstrcpynA(*dest,src, len); + hr = S_OK; + } else { + hr = E_OUTOFMEMORY; + } + + TRACE("%s->(%p)\n", debugstr_a(src), *dest); + return hr; +} + +/************************************************************************* + * SHStrDupA [SHLWAPI.@] + * + * Return a Unicode copy of a string, in memory allocated by CoTaskMemAlloc(). + * + * PARAMS + * lpszStr [I] String to copy + * lppszDest [O] Destination for the new string copy + * + * RETURNS + * Success: S_OK. lppszDest contains the new string in Unicode format. + * Failure: E_OUTOFMEMORY, If any arguments are invalid or memory allocation + * fails. + */ +HRESULT WINAPI SHStrDupA(LPCSTR lpszStr, LPWSTR * lppszDest) +{ + HRESULT hRet; + int len = 0; + + if (lpszStr) + { + len = MultiByteToWideChar(0, 0, lpszStr, -1, 0, 0) * sizeof(WCHAR); + *lppszDest = CoTaskMemAlloc(len); + } + else + *lppszDest = NULL; + + if (*lppszDest) + { + MultiByteToWideChar(0, 0, lpszStr, -1, *lppszDest, len); + hRet = S_OK; + } + else + hRet = E_OUTOFMEMORY; + + TRACE("%s->(%p)\n", debugstr_a(lpszStr), *lppszDest); + return hRet; +} + +/************************************************************************* + * _SHStrDupAW [INTERNAL] + * + * Duplicates a UNICODE to a ASCII string. The destination buffer is allocated. + */ +static HRESULT WINAPI _SHStrDupAW(LPCWSTR src, LPSTR * dest) +{ + HRESULT hr; + int len = 0; + + if (src) { + len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL); + *dest = CoTaskMemAlloc(len); + } else { + *dest = NULL; + } + + if (*dest) { + WideCharToMultiByte(CP_ACP, 0, src, -1, *dest, len, NULL, NULL); + hr = S_OK; + } else { + hr = E_OUTOFMEMORY; + } + + TRACE("%s->(%p)\n", debugstr_w(src), *dest); + return hr; +} + +/************************************************************************* + * SHStrDupW [SHLWAPI.@] + * + * See SHStrDupA. + */ +HRESULT WINAPI SHStrDupW(LPCWSTR src, LPWSTR * dest) +{ + HRESULT hr; + int len = 0; + + if (src) { + len = (lstrlenW(src) + 1) * sizeof(WCHAR); + *dest = CoTaskMemAlloc(len); + } else { + *dest = NULL; + } + + if (*dest) { + memcpy(*dest, src, len); + hr = S_OK; + } else { + hr = E_OUTOFMEMORY; + } + + TRACE("%s->(%p)\n", debugstr_w(src), *dest); + return hr; +} + +/************************************************************************* + * SHLWAPI_WriteReverseNum + * + * Internal helper for SHLWAPI_WriteTimeClass. + */ +inline static LPWSTR SHLWAPI_WriteReverseNum(LPWSTR lpszOut, DWORD dwNum) +{ + *lpszOut-- = '\0'; + + /* Write a decimal number to a string, backwards */ + do + { + DWORD dwNextDigit = dwNum % 10; + *lpszOut-- = '0' + dwNextDigit; + dwNum = (dwNum - dwNextDigit) / 10; + } while (dwNum > 0); + + return lpszOut; +} + +/************************************************************************* + * SHLWAPI_FormatSignificant + * + * Internal helper for SHLWAPI_WriteTimeClass. + */ +inline static int SHLWAPI_FormatSignificant(LPWSTR lpszNum, int dwDigits) +{ + /* Zero non significant digits, return remaining significant digits */ + while (*lpszNum) + { + lpszNum++; + if (--dwDigits == 0) + { + while (*lpszNum) + *lpszNum++ = '0'; + return 0; + } + } + return dwDigits; +} + +/************************************************************************* + * SHLWAPI_WriteTimeClass + * + * Internal helper for StrFromTimeIntervalW. + */ +static int WINAPI SHLWAPI_WriteTimeClass(LPWSTR lpszOut, DWORD dwValue, + LPCWSTR lpszClass, int iDigits) +{ + WCHAR szBuff[64], *szOut = szBuff + 32; + + szOut = SHLWAPI_WriteReverseNum(szOut, dwValue); + iDigits = SHLWAPI_FormatSignificant(szOut + 1, iDigits); + *szOut = ' '; + strcpyW(szBuff + 32, lpszClass); + strcatW(lpszOut, szOut); + return iDigits; +} + +/************************************************************************* + * StrFromTimeIntervalA [SHLWAPI.@] + * + * Format a millisecond time interval into a string + * + * PARAMS + * lpszStr [O] Output buffer for formatted time interval + * cchMax [I] Size of lpszStr + * dwMS [I] Number of milliseconds + * iDigits [I] Number of digits to print + * + * RETURNS + * The length of the formatted string, or 0 if any parameter is invalid. + * + * NOTES + * This implementation mimics the Win32 behaviour of always writing a leading + * space before the time interval begins. + * + * iDigits is used to provide approximate times if accuracy is not important. + * This number of digits will be written of the first non-zero time class + * (hours/minutes/seconds). If this does not complete the time classification, + * the remaining digits are changed to zeros (i.e. The time is _not_ rounded). + * If there are digits remaining following the writing of a time class, the + * next time class will be written. + * + * For example, given dwMS represents 138 hours,43 minutes and 15 seconds, the + * following will result from the given values of iDigits: + * + *| iDigits 1 2 3 4 5 ... + *| lpszStr "100 hr" "130 hr" "138 hr" "138 hr 40 min" "138 hr 43 min" ... + */ +INT WINAPI StrFromTimeIntervalA(LPSTR lpszStr, UINT cchMax, DWORD dwMS, + int iDigits) +{ + INT iRet = 0; + + TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits); + + if (lpszStr && cchMax) + { + WCHAR szBuff[128]; + StrFromTimeIntervalW(szBuff, sizeof(szBuff)/sizeof(WCHAR), dwMS, iDigits); + WideCharToMultiByte(CP_ACP,0,szBuff,-1,lpszStr,cchMax,0,0); + } + return iRet; +} + + +/************************************************************************* + * StrFromTimeIntervalW [SHLWAPI.@] + * + * See StrFromTimeIntervalA. + */ +INT WINAPI StrFromTimeIntervalW(LPWSTR lpszStr, UINT cchMax, DWORD dwMS, + int iDigits) +{ + static const WCHAR szHr[] = {' ','h','r','\0'}; + static const WCHAR szMin[] = {' ','m','i','n','\0'}; + static const WCHAR szSec[] = {' ','s','e','c','\0'}; + INT iRet = 0; + + TRACE("(%p,%d,%ld,%d)\n", lpszStr, cchMax, dwMS, iDigits); + + if (lpszStr && cchMax) + { + WCHAR szCopy[128]; + DWORD dwHours, dwMinutes; + + if (!iDigits || cchMax == 1) + { + *lpszStr = '\0'; + return 0; + } + + /* Calculate the time classes */ + dwMS = (dwMS + 500) / 1000; + dwHours = dwMS / 3600; + dwMS -= dwHours * 3600; + dwMinutes = dwMS / 60; + dwMS -= dwMinutes * 60; + + szCopy[0] = '\0'; + + if (dwHours) + iDigits = SHLWAPI_WriteTimeClass(szCopy, dwHours, szHr, iDigits); + + if (dwMinutes && iDigits) + iDigits = SHLWAPI_WriteTimeClass(szCopy, dwMinutes, szMin, iDigits); + + if (iDigits) /* Always write seconds if we have significant digits */ + SHLWAPI_WriteTimeClass(szCopy, dwMS, szSec, iDigits); + + lstrcpynW(lpszStr, szCopy, cchMax); + iRet = strlenW(lpszStr); + } + return iRet; +} + +/************************************************************************* + * StrIsIntlEqualA [SHLWAPI.@] + * + * Compare two strings. + * + * PARAMS + * bCase [I] Whether to compare case sensitively + * lpszStr [I] First string to compare + * lpszComp [I] Second string to compare + * iLen [I] Length to compare + * + * RETURNS + * TRUE If the strings are equal. + * FALSE Otherwise. + */ +BOOL WINAPI StrIsIntlEqualA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp, + int iLen) +{ + DWORD dwFlags; + + TRACE("(%d,%s,%s,%d)\n", bCase, + debugstr_a(lpszStr), debugstr_a(lpszComp), iLen); + + /* FIXME: This flag is undocumented and unknown by our CompareString. + * We need a define for it. + */ + dwFlags = 0x10000000; + if (!bCase) dwFlags |= NORM_IGNORECASE; + + return (CompareStringA(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL); +} + +/************************************************************************* + * StrIsIntlEqualW [SHLWAPI.@] + * + * See StrIsIntlEqualA. + */ +BOOL WINAPI StrIsIntlEqualW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp, + int iLen) +{ + DWORD dwFlags; + + TRACE("(%d,%s,%s,%d)\n", bCase, + debugstr_w(lpszStr),debugstr_w(lpszComp), iLen); + + /* FIXME: This flag is undocumented and unknown by our CompareString. + * We need a define for it. + */ + dwFlags = 0x10000000; + if (!bCase) dwFlags |= NORM_IGNORECASE; + + return (CompareStringW(GetThreadLocale(), dwFlags, lpszStr, iLen, lpszComp, iLen) == CSTR_EQUAL); +} + +/************************************************************************* + * @ [SHLWAPI.399] + * + * Copy a string to another string, up to a maximum number of characters. + * + * PARAMS + * lpszDest [O] Destination string + * lpszSrc [I] Source string + * iLen [I] Maximum number of chars to copy + * + * RETURNS + * Success: A pointer to the last character written to lpszDest.. + * Failure: lpszDest, if any arguments are invalid. + */ +LPSTR WINAPI StrCpyNXA(LPSTR lpszDest, LPCSTR lpszSrc, int iLen) +{ + TRACE("(%p,%s,%i)\n", lpszDest, debugstr_a(lpszSrc), iLen); + + if (lpszDest && lpszSrc && iLen > 0) + { + while ((iLen-- > 1) && *lpszSrc) + *lpszDest++ = *lpszSrc++; + if (iLen >= 0) + *lpszDest = '\0'; + } + return lpszDest; +} + +/************************************************************************* + * @ [SHLWAPI.400] + * + * Unicode version of StrCpyNXA. + */ +LPWSTR WINAPI StrCpyNXW(LPWSTR lpszDest, LPCWSTR lpszSrc, int iLen) +{ + TRACE("(%p,%s,%i)\n", lpszDest, debugstr_w(lpszSrc), iLen); + + if (lpszDest && lpszSrc && iLen > 0) + { + while ((iLen-- > 1) && *lpszSrc) + *lpszDest++ = *lpszSrc++; + if (iLen >= 0) + *lpszDest = '\0'; + } + return lpszDest; +} + +/************************************************************************* + * StrCmpLogicalW [SHLWAPI.@] + * + * Compare two strings, ignoring case and comparing digits as numbers. + * + * PARAMS + * lpszStr [I] First string to compare + * lpszComp [I] Second string to compare + * iLen [I] Length to compare + * + * RETURNS + * TRUE If the strings are equal. + * FALSE Otherwise. + */ +INT WINAPI StrCmpLogicalW(LPCWSTR lpszStr, LPCWSTR lpszComp) +{ + INT iDiff; + + TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszComp)); + + if (lpszStr && lpszComp) + { + while (*lpszStr) + { + if (!*lpszComp) + return 1; + else if (isdigitW(*lpszStr)) + { + int iStr, iComp; + + if (!isdigitW(*lpszComp)) + return -1; + + /* Compare the numbers */ + StrToIntExW(lpszStr, 0, &iStr); + StrToIntExW(lpszComp, 0, &iComp); + + if (iStr < iComp) + return -1; + else if (iStr > iComp) + return 1; + + /* Skip */ + while (isdigitW(*lpszStr)) + lpszStr++; + while (isdigitW(*lpszComp)) + lpszComp++; + } + else if (isdigitW(*lpszComp)) + return 1; + else + { + iDiff = SHLWAPI_ChrCmpHelperW(*lpszStr,*lpszComp,NORM_IGNORECASE); + if (iDiff > 0) + return 1; + else if (iDiff < 0) + return -1; + + lpszStr++; + lpszComp++; + } + } + if (*lpszComp) + return -1; + } + return 0; +} + +/* Structure for formatting byte strings */ +typedef struct tagSHLWAPI_BYTEFORMATS +{ + LONGLONG dLimit; + double dDivisor; + double dNormaliser; + LPCWSTR lpwszFormat; + WCHAR wPrefix; +} SHLWAPI_BYTEFORMATS; + +/************************************************************************* + * StrFormatByteSizeW [SHLWAPI.@] + * + * Create a string containing an abbreviated byte count of up to 2^63-1. + * + * PARAMS + * llBytes [I] Byte size to format + * lpszDest [I] Destination for formatted string + * cchMax [I] Size of lpszDest + * + * RETURNS + * lpszDest. + * + * NOTES + * There is no StrFormatByteSize64W function, it is called StrFormatByteSizeW(). + */ +LPWSTR WINAPI StrFormatByteSizeW(LONGLONG llBytes, LPWSTR lpszDest, UINT cchMax) +{ + static const WCHAR wszBytes[] = {'%','l','d',' ','b','y','t','e','s',0}; + static const WCHAR wsz3_0[] = {'%','3','.','0','f',0}; + static const WCHAR wsz3_1[] = {'%','3','.','1','f',0}; + static const WCHAR wsz3_2[] = {'%','3','.','2','f',0}; + +#define KB ((ULONGLONG)1024) +#define MB (KB*KB) +#define GB (KB*KB*KB) +#define TB (KB*KB*KB*KB) +#define PB (KB*KB*KB*KB*KB) + + static const SHLWAPI_BYTEFORMATS bfFormats[] = + { + { 10*KB, 10.24, 100.0, wsz3_2, 'K' }, /* 10 KB */ + { 100*KB, 102.4, 10.0, wsz3_1, 'K' }, /* 100 KB */ + { 1000*KB, 1024.0, 1.0, wsz3_0, 'K' }, /* 1000 KB */ + { 10*MB, 10485.76, 100.0, wsz3_2, 'M' }, /* 10 MB */ + { 100*MB, 104857.6, 10.0, wsz3_1, 'M' }, /* 100 MB */ + { 1000*MB, 1048576.0, 1.0, wsz3_0, 'M' }, /* 1000 MB */ + { 10*GB, 10737418.24, 100.0, wsz3_2, 'G' }, /* 10 GB */ + { 100*GB, 107374182.4, 10.0, wsz3_1, 'G' }, /* 100 GB */ + { 1000*GB, 1073741824.0, 1.0, wsz3_0, 'G' }, /* 1000 GB */ + { 10*TB, 10485.76, 100.0, wsz3_2, 'T' }, /* 10 TB */ + { 100*TB, 104857.6, 10.0, wsz3_1, 'T' }, /* 100 TB */ + { 1000*TB, 1048576.0, 1.0, wsz3_0, 'T' }, /* 1000 TB */ + { 10*PB, 10737418.24, 100.00, wsz3_2, 'P' }, /* 10 PB */ + { 100*PB, 107374182.4, 10.00, wsz3_1, 'P' }, /* 100 PB */ + { 1000*PB, 1073741824.0, 1.00, wsz3_0, 'P' }, /* 1000 PB */ + { 0, 10995116277.76, 100.00, wsz3_2, 'E' } /* EB's, catch all */ + }; + WCHAR wszBuff[32]; + WCHAR wszAdd[] = {' ','?','B',0}; + double dBytes; + UINT i = 0; + + TRACE("(%lld,%p,%d)\n", llBytes, lpszDest, cchMax); + + if (!lpszDest || !cchMax) + return lpszDest; + + if (llBytes < 1024) /* 1K */ + { + snprintfW(lpszDest, cchMax, wszBytes, (long)llBytes); + return lpszDest; + } + + /* Note that if this loop completes without finding a match, i will be + * pointing at the last entry, which is a catch all for > 1000 PB + */ + while (i < sizeof(bfFormats) / sizeof(SHLWAPI_BYTEFORMATS) - 1) + { + if (llBytes < bfFormats[i].dLimit) + break; + i++; + } + /* Above 1 TB we encounter problems with FP accuracy. So for amounts above + * this number we integer shift down by 1 MB first. The table above has + * the divisors scaled down from the '< 10 TB' entry onwards, to account + * for this. We also add a small fudge factor to get the correct result for + * counts that lie exactly on a 1024 byte boundary. + */ + if (i > 8) + dBytes = (double)(llBytes >> 20) + 0.001; /* Scale down by I MB */ + else + dBytes = (double)llBytes + 0.00001; + + dBytes = floor(dBytes / bfFormats[i].dDivisor) / bfFormats[i].dNormaliser; + + sprintfW(wszBuff, bfFormats[i].lpwszFormat, dBytes); + wszAdd[1] = bfFormats[i].wPrefix; + strcatW(wszBuff, wszAdd); + lstrcpynW(lpszDest, wszBuff, cchMax); + return lpszDest; +} + +/************************************************************************* + * StrFormatByteSize64A [SHLWAPI.@] + * + * See StrFormatByteSizeW. + */ +LPSTR WINAPI StrFormatByteSize64A(LONGLONG llBytes, LPSTR lpszDest, UINT cchMax) +{ + WCHAR wszBuff[32]; + + StrFormatByteSizeW(llBytes, wszBuff, sizeof(wszBuff)/sizeof(WCHAR)); + + if (lpszDest) + WideCharToMultiByte(CP_ACP, 0, wszBuff, -1, lpszDest, cchMax, 0, 0); + return lpszDest; +} + +/************************************************************************* + * StrFormatByteSizeA [SHLWAPI.@] + * + * Create a string containing an abbreviated byte count of up to 2^31-1. + * + * PARAMS + * dwBytes [I] Byte size to format + * lpszDest [I] Destination for formatted string + * cchMax [I] Size of lpszDest + * + * RETURNS + * lpszDest. + * + * NOTES + * The Ascii and Unicode versions of this function accept a different + * integer type for dwBytes. See StrFormatByteSize64A(). + */ +LPSTR WINAPI StrFormatByteSizeA(DWORD dwBytes, LPSTR lpszDest, UINT cchMax) +{ + TRACE("(%ld,%p,%d)\n", dwBytes, lpszDest, cchMax); + + return StrFormatByteSize64A(dwBytes, lpszDest, cchMax); +} + +/************************************************************************* + * @ [SHLWAPI.162] + * + * Remove a hanging lead byte from the end of a string, if present. + * + * PARAMS + * lpStr [I] String to check for a hanging lead byte + * size [I] Length of lpStr + * + * RETURNS + * Success: The new length of the string. Any hanging lead bytes are removed. + * Failure: 0, if any parameters are invalid. + */ +DWORD WINAPI SHTruncateString(LPSTR lpStr, DWORD size) +{ + if (lpStr && size) + { + LPSTR lastByte = lpStr + size - 1; + + while(lpStr < lastByte) + lpStr += IsDBCSLeadByte(*lpStr) ? 2 : 1; + + if(lpStr == lastByte && IsDBCSLeadByte(*lpStr)) + { + *lpStr = '\0'; + size--; + } + return size; + } + return 0; +} + +/************************************************************************* + * @ [SHLWAPI.203] + * + * Remove a single non-trailing ampersand ('&') from a string. + * + * PARAMS + * lpszStr [I/O] String to remove ampersand from. + * + * RETURNS + * The character after the first ampersand in lpszStr, or the first character + * in lpszStr if there is no ampersand in the string. + */ +char WINAPI SHStripMneumonicA(LPCSTR lpszStr) +{ + LPSTR lpszIter, lpszTmp; + char ch; + + TRACE("(%s)\n", debugstr_a(lpszStr)); + + ch = *lpszStr; + + if ((lpszIter = StrChrA(lpszStr, '&'))) + { + lpszTmp = CharNextA(lpszIter); + if (lpszTmp && *lpszTmp) + { + if (*lpszTmp != '&') + ch = *lpszTmp; + + while (lpszIter && *lpszIter) + { + lpszTmp = CharNextA(lpszIter); + *lpszIter = *lpszTmp; + lpszIter = lpszTmp; + } + } + } + + return ch; +} + +/************************************************************************* + * @ [SHLWAPI.225] + * + * Unicode version of SHStripMneumonicA. + */ +WCHAR WINAPI SHStripMneumonicW(LPCWSTR lpszStr) +{ + LPWSTR lpszIter, lpszTmp; + WCHAR ch; + + TRACE("(%s)\n", debugstr_w(lpszStr)); + + ch = *lpszStr; + + if ((lpszIter = StrChrW(lpszStr, '&'))) + { + lpszTmp = CharNextW(lpszIter); + if (lpszTmp && *lpszTmp) + { + if (*lpszTmp != '&') + ch = *lpszTmp; + + while (lpszIter && *lpszIter) + { + lpszTmp = CharNextW(lpszIter); + *lpszIter = *lpszTmp; + lpszIter = lpszTmp; + } + } + } + + return ch; +} + +/************************************************************************* + * @ [SHLWAPI.216] + * + * Convert an Ascii string to Unicode. + * + * PARAMS + * dwCp [I] Code page for the conversion + * lpSrcStr [I] Source Ascii string to convert + * lpDstStr [O] Destination for converted Unicode string + * iLen [I] Length of lpDstStr + * + * RETURNS + * The return value of the MultiByteToWideChar() function called on lpSrcStr. + */ +DWORD WINAPI SHAnsiToUnicodeCP(DWORD dwCp, LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen) +{ + DWORD dwRet; + + dwRet = MultiByteToWideChar(dwCp, 0, lpSrcStr, -1, lpDstStr, iLen); + TRACE("%s->%s,ret=%ld\n", debugstr_a(lpSrcStr), debugstr_w(lpDstStr), dwRet); + return dwRet; +} + +/************************************************************************* + * @ [SHLWAPI.215] + * + * Convert an Ascii string to Unicode. + * + * PARAMS + * lpSrcStr [I] Source Ascii string to convert + * lpDstStr [O] Destination for converted Unicode string + * iLen [I] Length of lpDstStr + * + * RETURNS + * The return value of the MultiByteToWideChar() function called on lpSrcStr. + * + * NOTES + * This function simply calls SHAnsiToUnicodeCP with code page CP_ACP. + */ +DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen) +{ + return SHAnsiToUnicodeCP(CP_ACP, lpSrcStr, lpDstStr, iLen); +} + +/************************************************************************* + * @ [SHLWAPI.218] + * + * Convert a Unicode string to Ascii. + * + * PARAMS + * CodePage [I] Code page to use for the conversion + * lpSrcStr [I] Source Unicode string to convert + * lpDstStr [O] Destination for converted Ascii string + * lpiLen [I/O] Input length of lpDstStr/destination for length of lpDstStr + * + * RETURNS + * Success: The number of characters that result from the conversion. + * Failure: 0. + */ +INT WINAPI SHUnicodeToAnsiCP(UINT CodePage, LPCWSTR lpSrcStr, LPSTR lpDstStr, + LPINT lpiLen) +{ + static const WCHAR emptyW[] = { '\0' }; + int len , reqLen; + LPSTR mem; + + if (!lpDstStr || !lpiLen) + return 0; + + if (!lpSrcStr) + lpSrcStr = emptyW; + + *lpDstStr = '\0'; + + len = strlenW(lpSrcStr) + 1; + + switch (CodePage) + { + case CP_WINUNICODE: + CodePage = CP_UTF8; /* Fall through... */ + case 0x0000C350: /* FIXME: CP_ #define */ + case CP_UTF7: + case CP_UTF8: + { + DWORD dwMode = 0; + INT nWideCharCount = len - 1; + + GET_FUNC(pConvertINetUnicodeToMultiByte, mlang, "ConvertINetUnicodeToMultiByte", 0); + if (!pConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &nWideCharCount, lpDstStr, + lpiLen)) + return 0; + + if (nWideCharCount < len - 1) + { + mem = HeapAlloc(GetProcessHeap(), 0, *lpiLen); + if (!mem) + return 0; + + *lpiLen = 0; + + if (pConvertINetUnicodeToMultiByte(&dwMode, CodePage, lpSrcStr, &len, mem, lpiLen)) + { + SHTruncateString(mem, *lpiLen); + lstrcpynA(lpDstStr, mem, *lpiLen + 1); + HeapFree(GetProcessHeap(), 0, mem); + return *lpiLen + 1; + } + HeapFree(GetProcessHeap(), 0, mem); + return *lpiLen; + } + lpDstStr[*lpiLen] = '\0'; + return *lpiLen; + } + default: + break; + } + + reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, lpDstStr, + *lpiLen, NULL, NULL); + + if (!reqLen && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, NULL, 0, NULL, NULL); + if (reqLen) + { + mem = HeapAlloc(GetProcessHeap(), 0, reqLen); + if (mem) + { + reqLen = WideCharToMultiByte(CodePage, 0, lpSrcStr, len, mem, + reqLen, NULL, NULL); + + reqLen = SHTruncateString(mem, *lpiLen); + reqLen++; + + lstrcpynA(lpDstStr, mem, *lpiLen); + + HeapFree(GetProcessHeap(), 0, mem); + } + } + } + return reqLen; +} + +/************************************************************************* + * @ [SHLWAPI.217] + * + * Convert a Unicode string to Ascii. + * + * PARAMS + * lpSrcStr [I] Source Unicode string to convert + * lpDstStr [O] Destination for converted Ascii string + * iLen [O] Length of lpDstStr in characters + * + * RETURNS + * See SHUnicodeToAnsiCP + + * NOTES + * This function simply calls SHUnicodeToAnsiCP() with CodePage = CP_ACP. + */ +INT WINAPI SHUnicodeToAnsi(LPCWSTR lpSrcStr, LPSTR lpDstStr, INT iLen) +{ + INT myint = iLen; + + return SHUnicodeToAnsiCP(CP_ACP, lpSrcStr, lpDstStr, &myint); +} + +/************************************************************************* + * @ [SHLWAPI.345] + * + * Copy one string to another. + * + * PARAMS + * lpszSrc [I] Source string to copy + * lpszDst [O] Destination for copy + * iLen [I] Length of lpszDst in characters + * + * RETURNS + * The length of the copied string, including the terminating NUL. lpszDst + * contains iLen characters of lpszSrc. + */ +DWORD WINAPI SHAnsiToAnsi(LPCSTR lpszSrc, LPSTR lpszDst, int iLen) +{ + LPSTR lpszRet; + + TRACE("(%s,%p,0x%08x)\n", debugstr_a(lpszSrc), lpszDst, iLen); + + lpszRet = StrCpyNXA(lpszDst, lpszSrc, iLen); + return lpszRet - lpszDst + 1; +} + +/************************************************************************* + * @ [SHLWAPI.346] + * + * Unicode version of SSHAnsiToAnsi. + */ +DWORD WINAPI SHUnicodeToUnicode(LPCWSTR lpszSrc, LPWSTR lpszDst, int iLen) +{ + LPWSTR lpszRet; + + TRACE("(%s,%p,0x%08x)\n", debugstr_w(lpszSrc), lpszDst, iLen); + + lpszRet = StrCpyNXW(lpszDst, lpszSrc, iLen); + return lpszRet - lpszDst + 1; +} + +/************************************************************************* + * @ [SHLWAPI.364] + * + * Determine if an Ascii string converts to Unicode and back identically. + * + * PARAMS + * lpSrcStr [I] Source Unicode string to convert + * lpDst [O] Destination for resulting Ascii string + * iLen [I] Length of lpDst in characters + * + * RETURNS + * TRUE, since Ascii strings always convert identically. + */ +BOOL WINAPI DoesStringRoundTripA(LPCSTR lpSrcStr, LPSTR lpDst, INT iLen) +{ + lstrcpynA(lpDst, lpSrcStr, iLen); + return TRUE; +} + +/************************************************************************* + * @ [SHLWAPI.365] + * + * Determine if a Unicode string converts to Ascii and back identically. + * + * PARAMS + * lpSrcStr [I] Source Unicode string to convert + * lpDst [O] Destination for resulting Ascii string + * iLen [I] Length of lpDst in characters + * + * RETURNS + * TRUE, if lpSrcStr converts to Ascii and back identically, + * FALSE otherwise. + */ +BOOL WINAPI DoesStringRoundTripW(LPCWSTR lpSrcStr, LPSTR lpDst, INT iLen) +{ + WCHAR szBuff[MAX_PATH]; + + SHUnicodeToAnsi(lpSrcStr, lpDst, iLen); + SHAnsiToUnicode(lpDst, szBuff, MAX_PATH); + return !strcmpW(lpSrcStr, szBuff); +} diff --git a/reactos/lib/shlwapi/thread.c b/reactos/lib/shlwapi/thread.c index 8edbd9da02c..ae482df3572 100644 --- a/reactos/lib/shlwapi/thread.c +++ b/reactos/lib/shlwapi/thread.c @@ -1,482 +1,482 @@ -/* - * SHLWAPI thread and MT synchronisation functions - * - * Copyright 2002 Juergen Schmied - * Copyright 2002 Jon Griffiths - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include <stdarg.h> -#include <string.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "wine/debug.h" -#define NO_SHLWAPI_REG -#define NO_SHLWAPI_PATH -#define NO_SHLWAPI_GDI -#define NO_SHLWAPI_STREAM -#define NO_SHLWAPI_USER -#include "shlwapi.h" - -WINE_DEFAULT_DEBUG_CHANNEL(shell); - -/* Get a function pointer from a DLL handle */ -#define GET_FUNC(func, module, name, fail) \ - do { \ - if (!func) { \ - if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \ - if (!(func = (void*)GetProcAddress(SHLWAPI_h##module, name))) return fail; \ - } \ - } while (0) - -/* DLL handles for late bound calls */ -extern HMODULE SHLWAPI_hshell32; - -/* Function pointers for GET_FUNC macro; these need to be global because of gcc bug */ -static HRESULT (WINAPI *pSHGetInstanceExplorer)(IUnknown**); - -extern DWORD SHLWAPI_ThreadRef_index; /* Initialised in shlwapi_main.c */ - -DWORD WINAPI SHStringFromGUIDA(REFGUID,LPSTR,INT); - -/************************************************************************** - * _CreateAllAccessSecurityAttributes [SHLWAPI.356] - * - * Initialise security attributes from a security descriptor. - * - * PARAMS - * lpAttr [O] Security attributes - * lpSec [I] Security descriptor - * - * RETURNS - * Success: lpAttr, initialised using lpSec. - * Failure: NULL, if any parameters are invalid. - * - * NOTES - * This function always returns NULL if the underlying OS version - * Wine is impersonating does not use security descriptors (i.e. anything - * before Windows NT). - */ -LPSECURITY_ATTRIBUTES WINAPI _CreateAllAccessSecurityAttributes( - LPSECURITY_ATTRIBUTES lpAttr, - PSECURITY_DESCRIPTOR lpSec) -{ - /* This function is used within SHLWAPI only to create security attributes - * for shell semaphores. */ - - TRACE("(%p,%p)\n", lpAttr, lpSec); - - if (!(GetVersion() & 0x80000000)) /* NT */ - { - if (!lpSec || !lpAttr) - return NULL; - - if (InitializeSecurityDescriptor(lpSec, 1)) - { - if (SetSecurityDescriptorDacl(lpSec, TRUE, NULL, FALSE)) - { - lpAttr->nLength = sizeof(SECURITY_ATTRIBUTES); - lpAttr->lpSecurityDescriptor = lpSec; - lpAttr->bInheritHandle = FALSE; - return lpAttr; - } - } - } - return NULL; -} - -/************************************************************************* - * _SHGetInstanceExplorer [SHLWAPI.@] - * - * Get an interface to the shell explorer. - * - * PARAMS - * lppUnknown [O] Destination for explorers IUnknown interface. - * - * RETURNS - * Success: S_OK. lppUnknown contains the explorer interface. - * Failure: An HRESULT error code. - */ -HRESULT WINAPI _SHGetInstanceExplorer(IUnknown **lppUnknown) -{ - /* This function is used within SHLWAPI only to hold the IE reference - * for threads created with the CTF_PROCESS_REF flag set. */ - - GET_FUNC(pSHGetInstanceExplorer, shell32, "SHGetInstanceExplorer", E_FAIL); - return pSHGetInstanceExplorer(lppUnknown); -} - -/* Internal thread information structure */ -typedef struct tagSHLWAPI_THREAD_INFO -{ - LPTHREAD_START_ROUTINE pfnThreadProc; /* Thread start */ - LPTHREAD_START_ROUTINE pfnCallback; /* Thread initialisation */ - PVOID pData; /* Application specific data */ - BOOL bInitCom; /* Initialise COM for the thread? */ - HANDLE hEvent; /* Signal for creator to continue */ - IUnknown *refThread; /* Reference to thread creator */ - IUnknown *refIE; /* Reference to the IE process */ -} SHLWAPI_THREAD_INFO, *LPSHLWAPI_THREAD_INFO; - - -/************************************************************************* - * SHGetThreadRef [SHLWAPI.@] - * - * Get a per-thread object reference set by SHSetThreadRef(). - * - * PARAMS - * lppUnknown [O] Destination to receive object reference - * - * RETURNS - * Success: S_OK. lppUnknown is set to the object reference. - * Failure: E_NOINTERFACE, if an error occurs or lppUnknown is NULL. - */ -HRESULT WINAPI SHGetThreadRef(IUnknown **lppUnknown) -{ - TRACE("(%p)\n", lppUnknown); - - if (!lppUnknown || SHLWAPI_ThreadRef_index == TLS_OUT_OF_INDEXES) - return E_NOINTERFACE; - - *lppUnknown = (IUnknown*)TlsGetValue(SHLWAPI_ThreadRef_index); - if (!*lppUnknown) - return E_NOINTERFACE; - - /* Add a reference. Caller will Release() us when finished */ - IUnknown_AddRef(*lppUnknown); - return S_OK; -} - -/************************************************************************* - * SHSetThreadRef [SHLWAPI.@] - * - * Store a per-thread object reference. - * - * PARAMS - * lpUnknown [I] Object reference to store - * - * RETURNS - * Success: S_OK. lpUnknown is stored and can be retrieved by SHGetThreadRef() - * Failure: E_NOINTERFACE, if an error occurs or lpUnknown is NULL. - */ -HRESULT WINAPI SHSetThreadRef(IUnknown *lpUnknown) -{ - TRACE("(%p)\n", lpUnknown); - - if (!lpUnknown || SHLWAPI_ThreadRef_index == 0xffffffff) - return E_NOINTERFACE; - - TlsSetValue(SHLWAPI_ThreadRef_index, lpUnknown); - return S_OK; -} - -/************************************************************************* - * SHReleaseThreadRef [SHLWAPI.@] - * - * Release a per-thread object reference. - * - * PARAMS - * None. - * - * RETURNS - * Success: S_OK. The threads object reference is released. - * Failure: An HRESULT error code. - */ -HRESULT WINAPI SHReleaseThreadRef() -{ - FIXME("() - stub!\n"); - return S_OK; -} - -/************************************************************************* - * SHLWAPI_ThreadWrapper - * - * Internal wrapper for executing user thread functions from SHCreateThread. - */ -static DWORD WINAPI SHLWAPI_ThreadWrapper(PVOID pTi) -{ - SHLWAPI_THREAD_INFO ti; - HRESULT hCom = E_FAIL; - DWORD dwRet; - - TRACE("(%p)\n", pTi); - - /* We are now executing in the context of the newly created thread. - * So we copy the data passed to us (it is on the stack of the function - * that called us, which is waiting for us to signal an event before - * returning). */ - memcpy(&ti, pTi, sizeof(SHLWAPI_THREAD_INFO)); - - /* Initialise COM for the thread, if desired */ - if (ti.bInitCom) - { - hCom = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED|COINIT_DISABLE_OLE1DDE); - - if (FAILED(hCom)) - hCom = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE); - } - - /* Execute the callback function before returning */ - if (ti.pfnCallback) - ti.pfnCallback(ti.pData); - - /* Signal the thread that created us; it can return now */ - SetEvent(ti.hEvent); - - /* Execute the callers start code */ - dwRet = ti.pfnThreadProc(ti.pData); - - /* Release references to the caller and IE process, if held */ - if (ti.refThread) - IUnknown_Release(ti.refThread); - - if (ti.refIE) - IUnknown_Release(ti.refIE); - - if (SUCCEEDED(hCom)) - CoUninitialize(); - - /* Return the users thread return value */ - return dwRet; -} - -/************************************************************************* - * SHCreateThread [SHLWAPI.16] - * - * Create a new thread. - * - * PARAMS - * pfnThreadProc [I] Function to execute in new thread - * pData [I] Application specific data passed to pfnThreadProc - * dwFlags [I] CTF_ flags from "shlwapi.h" - * pfnCallback [I] Function to execute before pfnThreadProc - * - * RETURNS - * Success: TRUE. pfnThreadProc was executed. - * Failure: FALSE. pfnThreadProc was not executed. - * - * NOTES - * If the thread cannot be created, pfnCallback is NULL, and dwFlags - * has bit CTF_INSIST set, pfnThreadProc will be executed synchronously. - */ -BOOL WINAPI SHCreateThread(LPTHREAD_START_ROUTINE pfnThreadProc, VOID *pData, - DWORD dwFlags, LPTHREAD_START_ROUTINE pfnCallback) -{ - SHLWAPI_THREAD_INFO ti; - BOOL bCalled = FALSE; - - TRACE("(%p,%p,0x%lX,%p)\n", pfnThreadProc, pData, dwFlags, pfnCallback); - - /* Set up data to pass to the new thread (On our stack) */ - ti.pfnThreadProc = pfnThreadProc; - ti.pfnCallback = pfnCallback; - ti.pData = pData; - ti.bInitCom = dwFlags & CTF_COINIT ? TRUE : FALSE; - ti.hEvent = CreateEventW(NULL,FALSE,FALSE,NULL); - - /* Hold references to the current thread and IE process, if desired */ - if(dwFlags & CTF_THREAD_REF) - SHGetThreadRef(&ti.refThread); - else - ti.refThread = NULL; - - if(dwFlags & CTF_PROCESS_REF) - _SHGetInstanceExplorer(&ti.refIE); - else - ti.refIE = NULL; - - /* Create the thread */ - if(ti.hEvent) - { - DWORD dwRetVal; - HANDLE hThread; - - hThread = CreateThread(NULL, 0, SHLWAPI_ThreadWrapper, &ti, 0, &dwRetVal); - - if(hThread) - { - /* Wait for the thread to signal us to continue */ - WaitForSingleObject(ti.hEvent, INFINITE); - CloseHandle(hThread); - bCalled = TRUE; - } - CloseHandle(ti.hEvent); - } - - if (!bCalled) - { - if (!ti.pfnCallback && dwFlags & CTF_INSIST) - { - /* Couldn't call, call synchronously */ - pfnThreadProc(pData); - bCalled = TRUE; - } - else - { - /* Free references, since thread hasn't run to do so */ - if(ti.refThread) - IUnknown_Release(ti.refThread); - - if(ti.refIE) - IUnknown_Release(ti.refIE); - } - } - return bCalled; -} - -/************************************************************************* - * _SHGlobalCounterGetValue [SHLWAPI.223] - * - * Get the current count of a semaphore. - * - * PARAMS - * hSem [I] Semaphore handle - * - * RETURNS - * The current count of the semaphore. - */ -LONG WINAPI _SHGlobalCounterGetValue(HANDLE hSem) -{ - LONG dwOldCount = 0; - - TRACE("(%p)\n", hSem); - ReleaseSemaphore(hSem, 1, &dwOldCount); /* +1 */ - WaitForSingleObject(hSem, 0); /* -1 */ - return dwOldCount; -} - -/************************************************************************* - * _SHGlobalCounterIncrement [SHLWAPI.224] - * - * Claim a semaphore. - * - * PARAMS - * hSem [I] Semaphore handle - * - * RETURNS - * The new count of the semaphore. - */ -LONG WINAPI _SHGlobalCounterIncrement(HANDLE hSem) -{ - LONG dwOldCount = 0; - - TRACE("(%p)\n", hSem); - ReleaseSemaphore(hSem, 1, &dwOldCount); - return dwOldCount + 1; -} - -/************************************************************************* - * _SHGlobalCounterDecrement [SHLWAPI.424] - * - * Release a semaphore. - * - * PARAMS - * hSem [I] Semaphore handle - * - * RETURNS - * The new count of the semaphore. - */ -DWORD WINAPI _SHGlobalCounterDecrement(HANDLE hSem) -{ - DWORD dwOldCount = 0; - - TRACE("(%p)\n", hSem); - - dwOldCount = _SHGlobalCounterGetValue(hSem); - WaitForSingleObject(hSem, 0); - return dwOldCount - 1; -} - -/************************************************************************* - * _SHGlobalCounterCreateNamedW [SHLWAPI.423] - * - * Unicode version of _SHGlobalCounterCreateNamedA. - */ -HANDLE WINAPI _SHGlobalCounterCreateNamedW(LPCWSTR lpszName, DWORD iInitial) -{ - static const WCHAR szPrefix[] = { 's', 'h', 'e', 'l', 'l', '.', '\0' }; - const int iPrefixLen = 6; - WCHAR szBuff[MAX_PATH]; - const int iBuffLen = sizeof(szBuff)/sizeof(WCHAR); - SECURITY_DESCRIPTOR sd; - SECURITY_ATTRIBUTES sAttr, *pSecAttr; - HANDLE hRet; - - TRACE("(%s,%ld)\n", debugstr_w(lpszName), iInitial); - - /* Create Semaphore name */ - memcpy(szBuff, szPrefix, (iPrefixLen + 1) * sizeof(WCHAR)); - if (lpszName) - StrCpyNW(szBuff + iPrefixLen, lpszName, iBuffLen - iPrefixLen); - - /* Initialise security attributes */ - pSecAttr = _CreateAllAccessSecurityAttributes(&sAttr, &sd); - - if (!(hRet = CreateSemaphoreW(pSecAttr , iInitial, MAXLONG, szBuff))) - hRet = OpenSemaphoreW(SYNCHRONIZE|SEMAPHORE_MODIFY_STATE, 0, szBuff); - return hRet; -} - -/************************************************************************* - * _SHGlobalCounterCreateNamedA [SHLWAPI.422] - * - * Create a semaphore. - * - * PARAMS - * lpszName [I] Name of semaphore - * iInitial [I] Initial count for semaphore - * - * RETURNS - * A new semaphore handle. - */ -HANDLE WINAPI _SHGlobalCounterCreateNamedA(LPCSTR lpszName, DWORD iInitial) -{ - WCHAR szBuff[MAX_PATH]; - - TRACE("(%s,%ld)\n", debugstr_a(lpszName), iInitial); - - if (lpszName) - MultiByteToWideChar(0, 0, lpszName, -1, szBuff, MAX_PATH); - return _SHGlobalCounterCreateNamedW(lpszName ? szBuff : NULL, iInitial); -} - -/************************************************************************* - * _SHGlobalCounterCreate [SHLWAPI.222] - * - * Create a semaphore using the name of a GUID. - * - * PARAMS - * guid [I] GUID to use as semaphore name - * - * RETURNS - * A handle to the semaphore. - * - * NOTES - * The initial count of the semaphore is set to 0. - */ -HANDLE WINAPI _SHGlobalCounterCreate (REFGUID guid) -{ - char szName[40]; - - TRACE("(%s)\n", debugstr_guid(guid)); - - /* Create a named semaphore using the GUID string */ - SHStringFromGUIDA(guid, szName, sizeof(szName) - 1); - return _SHGlobalCounterCreateNamedA(szName, 0); -} +/* + * SHLWAPI thread and MT synchronisation functions + * + * Copyright 2002 Juergen Schmied + * Copyright 2002 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <stdarg.h> +#include <string.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "wine/debug.h" +#define NO_SHLWAPI_REG +#define NO_SHLWAPI_PATH +#define NO_SHLWAPI_GDI +#define NO_SHLWAPI_STREAM +#define NO_SHLWAPI_USER +#include "shlwapi.h" + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/* Get a function pointer from a DLL handle */ +#define GET_FUNC(func, module, name, fail) \ + do { \ + if (!func) { \ + if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \ + if (!(func = (void*)GetProcAddress(SHLWAPI_h##module, name))) return fail; \ + } \ + } while (0) + +/* DLL handles for late bound calls */ +extern HMODULE SHLWAPI_hshell32; + +/* Function pointers for GET_FUNC macro; these need to be global because of gcc bug */ +static HRESULT (WINAPI *pSHGetInstanceExplorer)(IUnknown**); + +extern DWORD SHLWAPI_ThreadRef_index; /* Initialised in shlwapi_main.c */ + +DWORD WINAPI SHStringFromGUIDA(REFGUID,LPSTR,INT); + +/************************************************************************** + * _CreateAllAccessSecurityAttributes [SHLWAPI.356] + * + * Initialise security attributes from a security descriptor. + * + * PARAMS + * lpAttr [O] Security attributes + * lpSec [I] Security descriptor + * + * RETURNS + * Success: lpAttr, initialised using lpSec. + * Failure: NULL, if any parameters are invalid. + * + * NOTES + * This function always returns NULL if the underlying OS version + * Wine is impersonating does not use security descriptors (i.e. anything + * before Windows NT). + */ +LPSECURITY_ATTRIBUTES WINAPI _CreateAllAccessSecurityAttributes( + LPSECURITY_ATTRIBUTES lpAttr, + PSECURITY_DESCRIPTOR lpSec) +{ + /* This function is used within SHLWAPI only to create security attributes + * for shell semaphores. */ + + TRACE("(%p,%p)\n", lpAttr, lpSec); + + if (!(GetVersion() & 0x80000000)) /* NT */ + { + if (!lpSec || !lpAttr) + return NULL; + + if (InitializeSecurityDescriptor(lpSec, 1)) + { + if (SetSecurityDescriptorDacl(lpSec, TRUE, NULL, FALSE)) + { + lpAttr->nLength = sizeof(SECURITY_ATTRIBUTES); + lpAttr->lpSecurityDescriptor = lpSec; + lpAttr->bInheritHandle = FALSE; + return lpAttr; + } + } + } + return NULL; +} + +/************************************************************************* + * _SHGetInstanceExplorer [SHLWAPI.@] + * + * Get an interface to the shell explorer. + * + * PARAMS + * lppUnknown [O] Destination for explorers IUnknown interface. + * + * RETURNS + * Success: S_OK. lppUnknown contains the explorer interface. + * Failure: An HRESULT error code. + */ +HRESULT WINAPI _SHGetInstanceExplorer(IUnknown **lppUnknown) +{ + /* This function is used within SHLWAPI only to hold the IE reference + * for threads created with the CTF_PROCESS_REF flag set. */ + + GET_FUNC(pSHGetInstanceExplorer, shell32, "SHGetInstanceExplorer", E_FAIL); + return pSHGetInstanceExplorer(lppUnknown); +} + +/* Internal thread information structure */ +typedef struct tagSHLWAPI_THREAD_INFO +{ + LPTHREAD_START_ROUTINE pfnThreadProc; /* Thread start */ + LPTHREAD_START_ROUTINE pfnCallback; /* Thread initialisation */ + PVOID pData; /* Application specific data */ + BOOL bInitCom; /* Initialise COM for the thread? */ + HANDLE hEvent; /* Signal for creator to continue */ + IUnknown *refThread; /* Reference to thread creator */ + IUnknown *refIE; /* Reference to the IE process */ +} SHLWAPI_THREAD_INFO, *LPSHLWAPI_THREAD_INFO; + + +/************************************************************************* + * SHGetThreadRef [SHLWAPI.@] + * + * Get a per-thread object reference set by SHSetThreadRef(). + * + * PARAMS + * lppUnknown [O] Destination to receive object reference + * + * RETURNS + * Success: S_OK. lppUnknown is set to the object reference. + * Failure: E_NOINTERFACE, if an error occurs or lppUnknown is NULL. + */ +HRESULT WINAPI SHGetThreadRef(IUnknown **lppUnknown) +{ + TRACE("(%p)\n", lppUnknown); + + if (!lppUnknown || SHLWAPI_ThreadRef_index == TLS_OUT_OF_INDEXES) + return E_NOINTERFACE; + + *lppUnknown = (IUnknown*)TlsGetValue(SHLWAPI_ThreadRef_index); + if (!*lppUnknown) + return E_NOINTERFACE; + + /* Add a reference. Caller will Release() us when finished */ + IUnknown_AddRef(*lppUnknown); + return S_OK; +} + +/************************************************************************* + * SHSetThreadRef [SHLWAPI.@] + * + * Store a per-thread object reference. + * + * PARAMS + * lpUnknown [I] Object reference to store + * + * RETURNS + * Success: S_OK. lpUnknown is stored and can be retrieved by SHGetThreadRef() + * Failure: E_NOINTERFACE, if an error occurs or lpUnknown is NULL. + */ +HRESULT WINAPI SHSetThreadRef(IUnknown *lpUnknown) +{ + TRACE("(%p)\n", lpUnknown); + + if (!lpUnknown || SHLWAPI_ThreadRef_index == 0xffffffff) + return E_NOINTERFACE; + + TlsSetValue(SHLWAPI_ThreadRef_index, lpUnknown); + return S_OK; +} + +/************************************************************************* + * SHReleaseThreadRef [SHLWAPI.@] + * + * Release a per-thread object reference. + * + * PARAMS + * None. + * + * RETURNS + * Success: S_OK. The threads object reference is released. + * Failure: An HRESULT error code. + */ +HRESULT WINAPI SHReleaseThreadRef() +{ + FIXME("() - stub!\n"); + return S_OK; +} + +/************************************************************************* + * SHLWAPI_ThreadWrapper + * + * Internal wrapper for executing user thread functions from SHCreateThread. + */ +static DWORD WINAPI SHLWAPI_ThreadWrapper(PVOID pTi) +{ + SHLWAPI_THREAD_INFO ti; + HRESULT hCom = E_FAIL; + DWORD dwRet; + + TRACE("(%p)\n", pTi); + + /* We are now executing in the context of the newly created thread. + * So we copy the data passed to us (it is on the stack of the function + * that called us, which is waiting for us to signal an event before + * returning). */ + memcpy(&ti, pTi, sizeof(SHLWAPI_THREAD_INFO)); + + /* Initialise COM for the thread, if desired */ + if (ti.bInitCom) + { + hCom = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED|COINIT_DISABLE_OLE1DDE); + + if (FAILED(hCom)) + hCom = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE); + } + + /* Execute the callback function before returning */ + if (ti.pfnCallback) + ti.pfnCallback(ti.pData); + + /* Signal the thread that created us; it can return now */ + SetEvent(ti.hEvent); + + /* Execute the callers start code */ + dwRet = ti.pfnThreadProc(ti.pData); + + /* Release references to the caller and IE process, if held */ + if (ti.refThread) + IUnknown_Release(ti.refThread); + + if (ti.refIE) + IUnknown_Release(ti.refIE); + + if (SUCCEEDED(hCom)) + CoUninitialize(); + + /* Return the users thread return value */ + return dwRet; +} + +/************************************************************************* + * SHCreateThread [SHLWAPI.16] + * + * Create a new thread. + * + * PARAMS + * pfnThreadProc [I] Function to execute in new thread + * pData [I] Application specific data passed to pfnThreadProc + * dwFlags [I] CTF_ flags from "shlwapi.h" + * pfnCallback [I] Function to execute before pfnThreadProc + * + * RETURNS + * Success: TRUE. pfnThreadProc was executed. + * Failure: FALSE. pfnThreadProc was not executed. + * + * NOTES + * If the thread cannot be created, pfnCallback is NULL, and dwFlags + * has bit CTF_INSIST set, pfnThreadProc will be executed synchronously. + */ +BOOL WINAPI SHCreateThread(LPTHREAD_START_ROUTINE pfnThreadProc, VOID *pData, + DWORD dwFlags, LPTHREAD_START_ROUTINE pfnCallback) +{ + SHLWAPI_THREAD_INFO ti; + BOOL bCalled = FALSE; + + TRACE("(%p,%p,0x%lX,%p)\n", pfnThreadProc, pData, dwFlags, pfnCallback); + + /* Set up data to pass to the new thread (On our stack) */ + ti.pfnThreadProc = pfnThreadProc; + ti.pfnCallback = pfnCallback; + ti.pData = pData; + ti.bInitCom = dwFlags & CTF_COINIT ? TRUE : FALSE; + ti.hEvent = CreateEventW(NULL,FALSE,FALSE,NULL); + + /* Hold references to the current thread and IE process, if desired */ + if(dwFlags & CTF_THREAD_REF) + SHGetThreadRef(&ti.refThread); + else + ti.refThread = NULL; + + if(dwFlags & CTF_PROCESS_REF) + _SHGetInstanceExplorer(&ti.refIE); + else + ti.refIE = NULL; + + /* Create the thread */ + if(ti.hEvent) + { + DWORD dwRetVal; + HANDLE hThread; + + hThread = CreateThread(NULL, 0, SHLWAPI_ThreadWrapper, &ti, 0, &dwRetVal); + + if(hThread) + { + /* Wait for the thread to signal us to continue */ + WaitForSingleObject(ti.hEvent, INFINITE); + CloseHandle(hThread); + bCalled = TRUE; + } + CloseHandle(ti.hEvent); + } + + if (!bCalled) + { + if (!ti.pfnCallback && dwFlags & CTF_INSIST) + { + /* Couldn't call, call synchronously */ + pfnThreadProc(pData); + bCalled = TRUE; + } + else + { + /* Free references, since thread hasn't run to do so */ + if(ti.refThread) + IUnknown_Release(ti.refThread); + + if(ti.refIE) + IUnknown_Release(ti.refIE); + } + } + return bCalled; +} + +/************************************************************************* + * _SHGlobalCounterGetValue [SHLWAPI.223] + * + * Get the current count of a semaphore. + * + * PARAMS + * hSem [I] Semaphore handle + * + * RETURNS + * The current count of the semaphore. + */ +LONG WINAPI _SHGlobalCounterGetValue(HANDLE hSem) +{ + LONG dwOldCount = 0; + + TRACE("(%p)\n", hSem); + ReleaseSemaphore(hSem, 1, &dwOldCount); /* +1 */ + WaitForSingleObject(hSem, 0); /* -1 */ + return dwOldCount; +} + +/************************************************************************* + * _SHGlobalCounterIncrement [SHLWAPI.224] + * + * Claim a semaphore. + * + * PARAMS + * hSem [I] Semaphore handle + * + * RETURNS + * The new count of the semaphore. + */ +LONG WINAPI _SHGlobalCounterIncrement(HANDLE hSem) +{ + LONG dwOldCount = 0; + + TRACE("(%p)\n", hSem); + ReleaseSemaphore(hSem, 1, &dwOldCount); + return dwOldCount + 1; +} + +/************************************************************************* + * _SHGlobalCounterDecrement [SHLWAPI.424] + * + * Release a semaphore. + * + * PARAMS + * hSem [I] Semaphore handle + * + * RETURNS + * The new count of the semaphore. + */ +DWORD WINAPI _SHGlobalCounterDecrement(HANDLE hSem) +{ + DWORD dwOldCount = 0; + + TRACE("(%p)\n", hSem); + + dwOldCount = _SHGlobalCounterGetValue(hSem); + WaitForSingleObject(hSem, 0); + return dwOldCount - 1; +} + +/************************************************************************* + * _SHGlobalCounterCreateNamedW [SHLWAPI.423] + * + * Unicode version of _SHGlobalCounterCreateNamedA. + */ +HANDLE WINAPI _SHGlobalCounterCreateNamedW(LPCWSTR lpszName, DWORD iInitial) +{ + static const WCHAR szPrefix[] = { 's', 'h', 'e', 'l', 'l', '.', '\0' }; + const int iPrefixLen = 6; + WCHAR szBuff[MAX_PATH]; + const int iBuffLen = sizeof(szBuff)/sizeof(WCHAR); + SECURITY_DESCRIPTOR sd; + SECURITY_ATTRIBUTES sAttr, *pSecAttr; + HANDLE hRet; + + TRACE("(%s,%ld)\n", debugstr_w(lpszName), iInitial); + + /* Create Semaphore name */ + memcpy(szBuff, szPrefix, (iPrefixLen + 1) * sizeof(WCHAR)); + if (lpszName) + StrCpyNW(szBuff + iPrefixLen, lpszName, iBuffLen - iPrefixLen); + + /* Initialise security attributes */ + pSecAttr = _CreateAllAccessSecurityAttributes(&sAttr, &sd); + + if (!(hRet = CreateSemaphoreW(pSecAttr , iInitial, MAXLONG, szBuff))) + hRet = OpenSemaphoreW(SYNCHRONIZE|SEMAPHORE_MODIFY_STATE, 0, szBuff); + return hRet; +} + +/************************************************************************* + * _SHGlobalCounterCreateNamedA [SHLWAPI.422] + * + * Create a semaphore. + * + * PARAMS + * lpszName [I] Name of semaphore + * iInitial [I] Initial count for semaphore + * + * RETURNS + * A new semaphore handle. + */ +HANDLE WINAPI _SHGlobalCounterCreateNamedA(LPCSTR lpszName, DWORD iInitial) +{ + WCHAR szBuff[MAX_PATH]; + + TRACE("(%s,%ld)\n", debugstr_a(lpszName), iInitial); + + if (lpszName) + MultiByteToWideChar(0, 0, lpszName, -1, szBuff, MAX_PATH); + return _SHGlobalCounterCreateNamedW(lpszName ? szBuff : NULL, iInitial); +} + +/************************************************************************* + * _SHGlobalCounterCreate [SHLWAPI.222] + * + * Create a semaphore using the name of a GUID. + * + * PARAMS + * guid [I] GUID to use as semaphore name + * + * RETURNS + * A handle to the semaphore. + * + * NOTES + * The initial count of the semaphore is set to 0. + */ +HANDLE WINAPI _SHGlobalCounterCreate (REFGUID guid) +{ + char szName[40]; + + TRACE("(%s)\n", debugstr_guid(guid)); + + /* Create a named semaphore using the GUID string */ + SHStringFromGUIDA(guid, szName, sizeof(szName) - 1); + return _SHGlobalCounterCreateNamedA(szName, 0); +} diff --git a/reactos/lib/shlwapi/url.c b/reactos/lib/shlwapi/url.c index f10959964e0..56b770d2cae 100644 --- a/reactos/lib/shlwapi/url.c +++ b/reactos/lib/shlwapi/url.c @@ -1,2335 +1,2335 @@ -/* - * Url functions - * - * Copyright 2000 Huw D M Davies for CodeWeavers. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" -#include "wine/port.h" -#include <stdarg.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "winerror.h" -#include "wine/unicode.h" -#include "wininet.h" -#include "winreg.h" -#include "winternl.h" -#define NO_SHLWAPI_STREAM -#include "shlwapi.h" -#include "wine/debug.h" - -HMODULE WINAPI MLLoadLibraryW(LPCWSTR,HMODULE,DWORD); -BOOL WINAPI MLFreeLibrary(HMODULE); -HRESULT WINAPI MLBuildResURLW(LPCWSTR,HMODULE,DWORD,LPCWSTR,LPWSTR,DWORD); - -WINE_DEFAULT_DEBUG_CHANNEL(shell); - -/* The following schemes were identified in the native version of - * SHLWAPI.DLL version 5.50 - */ -typedef struct { - URL_SCHEME scheme_number; - LPCSTR scheme_name; -} SHL_2_inet_scheme; - -static const SHL_2_inet_scheme shlwapi_schemes[] = { - {URL_SCHEME_FTP, "ftp"}, - {URL_SCHEME_HTTP, "http"}, - {URL_SCHEME_GOPHER, "gopher"}, - {URL_SCHEME_MAILTO, "mailto"}, - {URL_SCHEME_NEWS, "news"}, - {URL_SCHEME_NNTP, "nntp"}, - {URL_SCHEME_TELNET, "telnet"}, - {URL_SCHEME_WAIS, "wais"}, - {URL_SCHEME_FILE, "file"}, - {URL_SCHEME_MK, "mk"}, - {URL_SCHEME_HTTPS, "https"}, - {URL_SCHEME_SHELL, "shell"}, - {URL_SCHEME_SNEWS, "snews"}, - {URL_SCHEME_LOCAL, "local"}, - {URL_SCHEME_JAVASCRIPT, "javascript"}, - {URL_SCHEME_VBSCRIPT, "vbscript"}, - {URL_SCHEME_ABOUT, "about"}, - {URL_SCHEME_RES, "res"}, - {0, 0} -}; - -typedef struct { - LPCWSTR pScheme; /* [out] start of scheme */ - DWORD szScheme; /* [out] size of scheme (until colon) */ - LPCWSTR pUserName; /* [out] start of Username */ - DWORD szUserName; /* [out] size of Username (until ":" or "@") */ - LPCWSTR pPassword; /* [out] start of Password */ - DWORD szPassword; /* [out] size of Password (until "@") */ - LPCWSTR pHostName; /* [out] start of Hostname */ - DWORD szHostName; /* [out] size of Hostname (until ":" or "/") */ - LPCWSTR pPort; /* [out] start of Port */ - DWORD szPort; /* [out] size of Port (until "/" or eos) */ - LPCWSTR pQuery; /* [out] start of Query */ - DWORD szQuery; /* [out] size of Query (until eos) */ -} WINE_PARSE_URL; - -typedef enum { - SCHEME, - HOST, - PORT, - USERPASS, -} WINE_URL_SCAN_TYPE; - -static const CHAR hexDigits[] = "0123456789ABCDEF"; - -static const WCHAR fileW[] = {'f','i','l','e','\0'}; - -static const unsigned char HashDataLookup[256] = { - 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77, 0x8A, 0xAA, 0x7D, 0x76, 0x1B, - 0xE9, 0x8C, 0x33, 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44, 0x1E, 0x07, - 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41, 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, - 0xDF, 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C, 0x0C, 0xB5, 0x67, 0x46, - 0x16, 0x3A, 0x4B, 0x4E, 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90, 0xB0, - 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53, 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, - 0x29, 0xFE, 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58, 0x23, 0xCE, 0x5F, - 0x74, 0xFC, 0xC0, 0x36, 0xDD, 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9, - 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D, 0xA6, 0x50, 0x32, 0x22, 0xAF, - 0xC3, 0x64, 0x63, 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD, 0x79, 0x40, - 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A, 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, - 0xC2, 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B, 0x4A, 0x3B, 0x89, 0xE4, - 0x6C, 0xBF, 0xE8, 0x8B, 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C, 0xFB, - 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70, 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, - 0x0D, 0x20, 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B, 0xF9, 0xEC, 0x2D, - 0xF4, 0x6F, 0xB6, 0x99, 0x88, 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47, - 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72, 0xA2, 0x35, 0xA0, 0xD7, 0xCD, - 0xB4, 0x2F, 0x6D, 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34, 0x3F, 0x17, - 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8, 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, - 0x0A, 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1 }; - -static BOOL URL_JustLocation(LPCWSTR str) -{ - while(*str && (*str == L'/')) str++; - if (*str) { - while (*str && ((*str == L'-') || - (*str == L'.') || - isalnumW(*str))) str++; - if (*str == L'/') return FALSE; - } - return TRUE; -} - - -/************************************************************************* - * @ [SHLWAPI.1] - * - * Parse a Url into its constituent parts. - * - * PARAMS - * x [I] Url to parse - * y [O] Undocumented structure holding the parsed information - * - * RETURNS - * Success: S_OK. y contains the parsed Url details. - * Failure: An HRESULT error code. - */ -HRESULT WINAPI ParseURLA(LPCSTR x, PARSEDURLA *y) -{ - DWORD cnt; - const SHL_2_inet_scheme *inet_pro; - - y->nScheme = URL_SCHEME_INVALID; - if (y->cbSize != sizeof(*y)) return E_INVALIDARG; - /* FIXME: leading white space generates error of 0x80041001 which - * is undefined - */ - if (*x <= ' ') return 0x80041001; - cnt = 0; - y->cchProtocol = 0; - y->pszProtocol = x; - while (*x) { - if (*x == ':') { - y->cchProtocol = cnt; - cnt = -1; - y->pszSuffix = x+1; - break; - } - x++; - cnt++; - } - - /* check for no scheme in string start */ - /* (apparently schemes *must* be larger than a single character) */ - if ((*x == '\0') || (y->cchProtocol <= 1)) { - y->pszProtocol = NULL; - return 0x80041001; - } - - /* found scheme, set length of remainder */ - y->cchSuffix = lstrlenA(y->pszSuffix); - - /* see if known scheme and return indicator number */ - y->nScheme = URL_SCHEME_UNKNOWN; - inet_pro = shlwapi_schemes; - while (inet_pro->scheme_name) { - if (!strncasecmp(inet_pro->scheme_name, y->pszProtocol, - min(y->cchProtocol, lstrlenA(inet_pro->scheme_name)))) { - y->nScheme = inet_pro->scheme_number; - break; - } - inet_pro++; - } - return S_OK; -} - -/************************************************************************* - * @ [SHLWAPI.2] - * - * Unicode version of ParseURLA. - */ -HRESULT WINAPI ParseURLW(LPCWSTR x, PARSEDURLW *y) -{ - DWORD cnt; - const SHL_2_inet_scheme *inet_pro; - LPSTR cmpstr; - INT len; - - y->nScheme = URL_SCHEME_INVALID; - if (y->cbSize != sizeof(*y)) return E_INVALIDARG; - /* FIXME: leading white space generates error of 0x80041001 which - * is undefined - */ - if (*x <= L' ') return 0x80041001; - cnt = 0; - y->cchProtocol = 0; - y->pszProtocol = x; - while (*x) { - if (*x == L':') { - y->cchProtocol = cnt; - cnt = -1; - y->pszSuffix = x+1; - break; - } - x++; - cnt++; - } - - /* check for no scheme in string start */ - /* (apparently schemes *must* be larger than a single character) */ - if ((*x == L'\0') || (y->cchProtocol <= 1)) { - y->pszProtocol = NULL; - return 0x80041001; - } - - /* found scheme, set length of remainder */ - y->cchSuffix = lstrlenW(y->pszSuffix); - - /* see if known scheme and return indicator number */ - len = WideCharToMultiByte(0, 0, y->pszProtocol, y->cchProtocol, 0, 0, 0, 0); - cmpstr = HeapAlloc(GetProcessHeap(), 0, len); - WideCharToMultiByte(0, 0, y->pszProtocol, y->cchProtocol, cmpstr, len, 0, 0); - y->nScheme = URL_SCHEME_UNKNOWN; - inet_pro = shlwapi_schemes; - while (inet_pro->scheme_name) { - if (!strncasecmp(inet_pro->scheme_name, cmpstr, - min(len, lstrlenA(inet_pro->scheme_name)))) { - y->nScheme = inet_pro->scheme_number; - break; - } - inet_pro++; - } - HeapFree(GetProcessHeap(), 0, cmpstr); - return S_OK; -} - -/************************************************************************* - * UrlCanonicalizeA [SHLWAPI.@] - * - * Canonicalize a Url. - * - * PARAMS - * pszUrl [I] Url to cCanonicalize - * pszCanonicalized [O] Destination for converted Url. - * pcchCanonicalized [I/O] Length of pszUrl, destination for length of pszCanonicalized - * dwFlags [I] Flags controlling the conversion. - * - * RETURNS - * Success: S_OK. The pszCanonicalized contains the converted Url. - * Failure: E_POINTER, if *pcchCanonicalized is too small. - * - * MSDN incorrectly describes the flags for this function. They should be: - *| URL_DONT_ESCAPE_EXTRA_INFO 0x02000000 - *| URL_ESCAPE_SPACES_ONLY 0x04000000 - *| URL_ESCAPE_PERCENT 0x00001000 - *| URL_ESCAPE_UNSAFE 0x10000000 - *| URL_UNESCAPE 0x10000000 - *| URL_DONT_SIMPLIFY 0x08000000 - *| URL_ESCAPE_SEGMENT_ONLY 0x00002000 - */ -HRESULT WINAPI UrlCanonicalizeA(LPCSTR pszUrl, LPSTR pszCanonicalized, - LPDWORD pcchCanonicalized, DWORD dwFlags) -{ - LPWSTR base, canonical; - DWORD ret, len, len2; - - TRACE("(%s %p %p 0x%08lx) using W version\n", - debugstr_a(pszUrl), pszCanonicalized, - pcchCanonicalized, dwFlags); - - if(!pszUrl || !pszCanonicalized || !pcchCanonicalized) - return E_INVALIDARG; - - base = HeapAlloc(GetProcessHeap(), 0, - (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR)); - canonical = base + INTERNET_MAX_URL_LENGTH; - - MultiByteToWideChar(0, 0, pszUrl, -1, base, INTERNET_MAX_URL_LENGTH); - len = INTERNET_MAX_URL_LENGTH; - - ret = UrlCanonicalizeW(base, canonical, &len, dwFlags); - if (ret != S_OK) { - HeapFree(GetProcessHeap(), 0, base); - return ret; - } - - len2 = WideCharToMultiByte(0, 0, canonical, len, 0, 0, 0, 0); - if (len2 > *pcchCanonicalized) { - *pcchCanonicalized = len; - HeapFree(GetProcessHeap(), 0, base); - return E_POINTER; - } - WideCharToMultiByte(0, 0, canonical, len+1, pszCanonicalized, - *pcchCanonicalized, 0, 0); - *pcchCanonicalized = len2; - HeapFree(GetProcessHeap(), 0, base); - return S_OK; -} - -/************************************************************************* - * UrlCanonicalizeW [SHLWAPI.@] - * - * See UrlCanonicalizeA. - */ -HRESULT WINAPI UrlCanonicalizeW(LPCWSTR pszUrl, LPWSTR pszCanonicalized, - LPDWORD pcchCanonicalized, DWORD dwFlags) -{ - HRESULT hr = S_OK; - DWORD EscapeFlags; - LPWSTR lpszUrlCpy, wk1, wk2, mp, root; - INT nByteLen, state; - DWORD nLen, nWkLen; - - TRACE("(%s %p %p 0x%08lx)\n", debugstr_w(pszUrl), pszCanonicalized, - pcchCanonicalized, dwFlags); - - if(!pszUrl || !pszCanonicalized || !pcchCanonicalized) - return E_INVALIDARG; - - nByteLen = (lstrlenW(pszUrl) + 1) * sizeof(WCHAR); /* length in bytes */ - lpszUrlCpy = HeapAlloc(GetProcessHeap(), 0, nByteLen); - - if (dwFlags & URL_DONT_SIMPLIFY) - memcpy(lpszUrlCpy, pszUrl, nByteLen); - else { - - /* - * state = - * 0 initial 1,3 - * 1 have 2[+] alnum 2,3 - * 2 have scheme (found :) 4,6,3 - * 3 failed (no location) - * 4 have // 5,3 - * 5 have 1[+] alnum 6,3 - * 6 have location (found /) save root location - */ - - wk1 = (LPWSTR)pszUrl; - wk2 = lpszUrlCpy; - state = 0; - while (*wk1) { - switch (state) { - case 0: - if (!isalnumW(*wk1)) {state = 3; break;} - *wk2++ = *wk1++; - if (!isalnumW(*wk1)) {state = 3; break;} - *wk2++ = *wk1++; - state = 1; - break; - case 1: - *wk2++ = *wk1; - if (*wk1++ == L':') state = 2; - break; - case 2: - if (*wk1 != L'/') {state = 3; break;} - *wk2++ = *wk1++; - if (*wk1 != L'/') {state = 6; break;} - *wk2++ = *wk1++; - state = 4; - break; - case 3: - nWkLen = strlenW(wk1); - memcpy(wk2, wk1, (nWkLen + 1) * sizeof(WCHAR)); - wk1 += nWkLen; - wk2 += nWkLen; - break; - case 4: - if (!isalnumW(*wk1) && (*wk1 != L'-') && (*wk1 != L'.')) {state = 3; break;} - while(isalnumW(*wk1) || (*wk1 == L'-') || (*wk1 == L'.')) *wk2++ = *wk1++; - state = 5; - break; - case 5: - if (*wk1 != L'/') {state = 3; break;} - *wk2++ = *wk1++; - state = 6; - break; - case 6: - /* Now at root location, cannot back up any more. */ - /* "root" will point at the '/' */ - root = wk2-1; - while (*wk1) { - TRACE("wk1=%c\n", (CHAR)*wk1); - mp = strchrW(wk1, L'/'); - if (!mp) { - nWkLen = strlenW(wk1); - memcpy(wk2, wk1, (nWkLen + 1) * sizeof(WCHAR)); - wk1 += nWkLen; - wk2 += nWkLen; - continue; - } - nLen = mp - wk1 + 1; - memcpy(wk2, wk1, nLen * sizeof(WCHAR)); - wk2 += nLen; - wk1 += nLen; - if (*wk1 == L'.') { - TRACE("found '/.'\n"); - if (*(wk1+1) == L'/') { - /* case of /./ -> skip the ./ */ - wk1 += 2; - } - else if (*(wk1+1) == L'.') { - /* found /.. look for next / */ - TRACE("found '/..'\n"); - if (*(wk1+2) == L'/' || *(wk1+2) == L'?' || *(wk1+2) == L'#' || *(wk1+2) == 0) { - /* case /../ -> need to backup wk2 */ - TRACE("found '/../'\n"); - *(wk2-1) = L'\0'; /* set end of string */ - mp = strrchrW(root, L'/'); - if (mp && (mp >= root)) { - /* found valid backup point */ - wk2 = mp + 1; - if(*(wk1+2) != L'/') - wk1 += 2; - else - wk1 += 3; - } - else { - /* did not find point, restore '/' */ - *(wk2-1) = L'/'; - } - } - } - } - } - *wk2 = L'\0'; - break; - default: - FIXME("how did we get here - state=%d\n", state); - HeapFree(GetProcessHeap(), 0, lpszUrlCpy); - return E_INVALIDARG; - } - } - *wk2 = L'\0'; - TRACE("Simplified, orig <%s>, simple <%s>\n", - debugstr_w(pszUrl), debugstr_w(lpszUrlCpy)); - } - nLen = lstrlenW(lpszUrlCpy); - while ((nLen > 0) && ((lpszUrlCpy[nLen-1] == '\r')||(lpszUrlCpy[nLen-1] == '\n'))) - lpszUrlCpy[--nLen]=0; - - if(dwFlags & URL_UNESCAPE) - UrlUnescapeW(lpszUrlCpy, NULL, &nLen, URL_UNESCAPE_INPLACE); - - if((EscapeFlags = dwFlags & (URL_ESCAPE_UNSAFE | - URL_ESCAPE_SPACES_ONLY | - URL_ESCAPE_PERCENT | - URL_DONT_ESCAPE_EXTRA_INFO | - URL_ESCAPE_SEGMENT_ONLY ))) { - EscapeFlags &= ~URL_ESCAPE_UNSAFE; - hr = UrlEscapeW(lpszUrlCpy, pszCanonicalized, pcchCanonicalized, - EscapeFlags); - } else { /* No escaping needed, just copy the string */ - nLen = lstrlenW(lpszUrlCpy); - if(nLen < *pcchCanonicalized) - memcpy(pszCanonicalized, lpszUrlCpy, (nLen + 1)*sizeof(WCHAR)); - else { - hr = E_POINTER; - nLen++; - } - *pcchCanonicalized = nLen; - } - - HeapFree(GetProcessHeap(), 0, lpszUrlCpy); - - if (hr == S_OK) - TRACE("result %s\n", debugstr_w(pszCanonicalized)); - - return hr; -} - -/************************************************************************* - * UrlCombineA [SHLWAPI.@] - * - * Combine two Urls. - * - * PARAMS - * pszBase [I] Base Url - * pszRelative [I] Url to combine with pszBase - * pszCombined [O] Destination for combined Url - * pcchCombined [O] Destination for length of pszCombined - * dwFlags [I] URL_ flags from "shlwapi.h" - * - * RETURNS - * Success: S_OK. pszCombined contains the combined Url, pcchCombined - * contains its length. - * Failure: An HRESULT error code indicating the error. - */ -HRESULT WINAPI UrlCombineA(LPCSTR pszBase, LPCSTR pszRelative, - LPSTR pszCombined, LPDWORD pcchCombined, - DWORD dwFlags) -{ - LPWSTR base, relative, combined; - DWORD ret, len, len2; - - TRACE("(base %s, Relative %s, Combine size %ld, flags %08lx) using W version\n", - debugstr_a(pszBase),debugstr_a(pszRelative), - pcchCombined?*pcchCombined:0,dwFlags); - - if(!pszBase || !pszRelative || !pcchCombined) - return E_INVALIDARG; - - base = HeapAlloc(GetProcessHeap(), 0, - (3*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR)); - relative = base + INTERNET_MAX_URL_LENGTH; - combined = relative + INTERNET_MAX_URL_LENGTH; - - MultiByteToWideChar(0, 0, pszBase, -1, base, INTERNET_MAX_URL_LENGTH); - MultiByteToWideChar(0, 0, pszRelative, -1, relative, INTERNET_MAX_URL_LENGTH); - len = *pcchCombined; - - ret = UrlCombineW(base, relative, pszCombined?combined:NULL, &len, dwFlags); - if (ret != S_OK) { - *pcchCombined = len; - HeapFree(GetProcessHeap(), 0, base); - return ret; - } - - len2 = WideCharToMultiByte(0, 0, combined, len, 0, 0, 0, 0); - if (len2 > *pcchCombined) { - *pcchCombined = len2; - HeapFree(GetProcessHeap(), 0, base); - return E_POINTER; - } - WideCharToMultiByte(0, 0, combined, len+1, pszCombined, (*pcchCombined)+1, - 0, 0); - *pcchCombined = len2; - HeapFree(GetProcessHeap(), 0, base); - return S_OK; -} - -/************************************************************************* - * UrlCombineW [SHLWAPI.@] - * - * See UrlCombineA. - */ -HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative, - LPWSTR pszCombined, LPDWORD pcchCombined, - DWORD dwFlags) -{ - PARSEDURLW base, relative; - DWORD myflags, sizeloc = 0; - DWORD len, res1, res2, process_case = 0; - LPWSTR work, preliminary, mbase, mrelative; - static const WCHAR myfilestr[] = {'f','i','l','e',':','/','/','/','\0'}; - static const WCHAR single_slash[] = {'/','\0'}; - HRESULT ret; - - TRACE("(base %s, Relative %s, Combine size %ld, flags %08lx)\n", - debugstr_w(pszBase),debugstr_w(pszRelative), - pcchCombined?*pcchCombined:0,dwFlags); - - if(!pszBase || !pszRelative || !pcchCombined) - return E_INVALIDARG; - - base.cbSize = sizeof(base); - relative.cbSize = sizeof(relative); - - /* Get space for duplicates of the input and the output */ - preliminary = HeapAlloc(GetProcessHeap(), 0, (3*INTERNET_MAX_URL_LENGTH) * - sizeof(WCHAR)); - mbase = preliminary + INTERNET_MAX_URL_LENGTH; - mrelative = mbase + INTERNET_MAX_URL_LENGTH; - *preliminary = L'\0'; - - /* Canonicalize the base input prior to looking for the scheme */ - myflags = dwFlags & (URL_DONT_SIMPLIFY | URL_UNESCAPE); - len = INTERNET_MAX_URL_LENGTH; - ret = UrlCanonicalizeW(pszBase, mbase, &len, myflags); - - /* Canonicalize the relative input prior to looking for the scheme */ - len = INTERNET_MAX_URL_LENGTH; - ret = UrlCanonicalizeW(pszRelative, mrelative, &len, myflags); - - /* See if the base has a scheme */ - res1 = ParseURLW(mbase, &base); - if (res1) { - /* if pszBase has no scheme, then return pszRelative */ - TRACE("no scheme detected in Base\n"); - process_case = 1; - } - else do { - - /* get size of location field (if it exists) */ - work = (LPWSTR)base.pszSuffix; - sizeloc = 0; - if (*work++ == L'/') { - if (*work++ == L'/') { - /* At this point have start of location and - * it ends at next '/' or end of string. - */ - while(*work && (*work != L'/')) work++; - sizeloc = (DWORD)(work - base.pszSuffix); - } - } - - /* Change .sizep2 to not have the last leaf in it, - * Note: we need to start after the location (if it exists) - */ - work = strrchrW((base.pszSuffix+sizeloc), L'/'); - if (work) { - len = (DWORD)(work - base.pszSuffix + 1); - base.cchSuffix = len; - } - /* - * At this point: - * .pszSuffix points to location (starting with '//') - * .cchSuffix length of location (above) and rest less the last - * leaf (if any) - * sizeloc length of location (above) up to but not including - * the last '/' - */ - - res2 = ParseURLW(mrelative, &relative); - if (res2) { - /* no scheme in pszRelative */ - TRACE("no scheme detected in Relative\n"); - relative.pszSuffix = mrelative; /* case 3,4,5 depends on this */ - relative.cchSuffix = strlenW(mrelative); - if (*pszRelative == L':') { - /* case that is either left alone or uses pszBase */ - if (dwFlags & URL_PLUGGABLE_PROTOCOL) { - process_case = 5; - break; - } - process_case = 1; - break; - } - if (isalnum(*mrelative) && (*(mrelative + 1) == L':')) { - /* case that becomes "file:///" */ - strcpyW(preliminary, myfilestr); - process_case = 1; - break; - } - if ((*mrelative == L'/') && (*(mrelative+1) == L'/')) { - /* pszRelative has location and rest */ - process_case = 3; - break; - } - if (*mrelative == L'/') { - /* case where pszRelative is root to location */ - process_case = 4; - break; - } - process_case = (*base.pszSuffix == L'/') ? 5 : 3; - break; - } - - /* handle cases where pszRelative has scheme */ - if ((base.cchProtocol == relative.cchProtocol) && - (strncmpW(base.pszProtocol, relative.pszProtocol, base.cchProtocol) == 0)) { - - /* since the schemes are the same */ - if ((*relative.pszSuffix == L'/') && (*(relative.pszSuffix+1) == L'/')) { - /* case where pszRelative replaces location and following */ - process_case = 3; - break; - } - if (*relative.pszSuffix == L'/') { - /* case where pszRelative is root to location */ - process_case = 4; - break; - } - /* case where scheme is followed by document path */ - process_case = 5; - break; - } - if ((*relative.pszSuffix == L'/') && (*(relative.pszSuffix+1) == L'/')) { - /* case where pszRelative replaces scheme, location, - * and following and handles PLUGGABLE - */ - process_case = 2; - break; - } - process_case = 1; - break; - } while(FALSE); /* a litte trick to allow easy exit from nested if's */ - - - ret = S_OK; - switch (process_case) { - - case 1: /* - * Return pszRelative appended to what ever is in pszCombined, - * (which may the string "file:///" - */ - strcatW(preliminary, mrelative); - break; - - case 2: /* - * Same as case 1, but if URL_PLUGGABLE_PROTOCOL was specified - * and pszRelative starts with "//", then append a "/" - */ - strcpyW(preliminary, mrelative); - if (!(dwFlags & URL_PLUGGABLE_PROTOCOL) && - URL_JustLocation(relative.pszSuffix)) - strcatW(preliminary, single_slash); - break; - - case 3: /* - * Return the pszBase scheme with pszRelative. Basically - * keeps the scheme and replaces the domain and following. - */ - memcpy(preliminary, base.pszProtocol, (base.cchProtocol + 1)*sizeof(WCHAR)); - work = preliminary + base.cchProtocol + 1; - strcpyW(work, relative.pszSuffix); - if (!(dwFlags & URL_PLUGGABLE_PROTOCOL) && - URL_JustLocation(relative.pszSuffix)) - strcatW(work, single_slash); - break; - - case 4: /* - * Return the pszBase scheme and location but everything - * after the location is pszRelative. (Replace document - * from root on.) - */ - memcpy(preliminary, base.pszProtocol, (base.cchProtocol+1+sizeloc)*sizeof(WCHAR)); - work = preliminary + base.cchProtocol + 1 + sizeloc; - if (dwFlags & URL_PLUGGABLE_PROTOCOL) - *(work++) = L'/'; - strcpyW(work, relative.pszSuffix); - break; - - case 5: /* - * Return the pszBase without its document (if any) and - * append pszRelative after its scheme. - */ - memcpy(preliminary, base.pszProtocol, - (base.cchProtocol+1+base.cchSuffix)*sizeof(WCHAR)); - work = preliminary + base.cchProtocol+1+base.cchSuffix - 1; - if (*work++ != L'/') - *(work++) = L'/'; - strcpyW(work, relative.pszSuffix); - break; - - default: - FIXME("How did we get here????? process_case=%ld\n", process_case); - ret = E_INVALIDARG; - } - - if (ret == S_OK) { - /* Reuse mrelative as temp storage as its already allocated and not needed anymore */ - ret = UrlCanonicalizeW(preliminary, mrelative, pcchCombined, dwFlags); - if(SUCCEEDED(ret) && pszCombined) { - lstrcpyW(pszCombined, mrelative); - } - TRACE("return-%ld len=%ld, %s\n", - process_case, *pcchCombined, debugstr_w(pszCombined)); - } - HeapFree(GetProcessHeap(), 0, preliminary); - return ret; -} - -/************************************************************************* - * UrlEscapeA [SHLWAPI.@] - */ - -HRESULT WINAPI UrlEscapeA( - LPCSTR pszUrl, - LPSTR pszEscaped, - LPDWORD pcchEscaped, - DWORD dwFlags) -{ - WCHAR bufW[INTERNET_MAX_URL_LENGTH]; - WCHAR *escapedW = bufW; - UNICODE_STRING urlW; - HRESULT ret; - DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA; - - if(!RtlCreateUnicodeStringFromAsciiz(&urlW, pszUrl)) - return E_INVALIDARG; - if((ret = UrlEscapeW(urlW.Buffer, escapedW, &lenW, dwFlags)) == E_POINTER) { - escapedW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR)); - ret = UrlEscapeW(urlW.Buffer, escapedW, &lenW, dwFlags); - } - if(ret == S_OK) { - RtlUnicodeToMultiByteSize(&lenA, escapedW, lenW * sizeof(WCHAR)); - if(*pcchEscaped > lenA) { - RtlUnicodeToMultiByteN(pszEscaped, *pcchEscaped - 1, &lenA, escapedW, lenW * sizeof(WCHAR)); - pszEscaped[lenA] = 0; - *pcchEscaped = lenA; - } else { - *pcchEscaped = lenA + 1; - ret = E_POINTER; - } - } - if(escapedW != bufW) HeapFree(GetProcessHeap(), 0, escapedW); - RtlFreeUnicodeString(&urlW); - return ret; -} - -#define WINE_URL_BASH_AS_SLASH 0x01 -#define WINE_URL_COLLAPSE_SLASHES 0x02 -#define WINE_URL_ESCAPE_SLASH 0x04 -#define WINE_URL_ESCAPE_HASH 0x08 -#define WINE_URL_ESCAPE_QUESTION 0x10 -#define WINE_URL_STOP_ON_HASH 0x20 -#define WINE_URL_STOP_ON_QUESTION 0x40 - -static inline BOOL URL_NeedEscapeW(WCHAR ch, DWORD dwFlags, DWORD int_flags) -{ - - if (isalnumW(ch)) - return FALSE; - - if(dwFlags & URL_ESCAPE_SPACES_ONLY) { - if(ch == ' ') - return TRUE; - else - return FALSE; - } - - if ((dwFlags & URL_ESCAPE_PERCENT) && (ch == '%')) - return TRUE; - - if (ch <= 31 || ch >= 127) - return TRUE; - - else { - switch (ch) { - case ' ': - case '<': - case '>': - case '\"': - case '{': - case '}': - case '|': - case '\\': - case '^': - case ']': - case '[': - case '`': - case '&': - return TRUE; - - case '/': - if (int_flags & WINE_URL_ESCAPE_SLASH) return TRUE; - return FALSE; - - case '?': - if (int_flags & WINE_URL_ESCAPE_QUESTION) return TRUE; - return FALSE; - - case '#': - if (int_flags & WINE_URL_ESCAPE_HASH) return TRUE; - return FALSE; - - default: - return FALSE; - } - } -} - - -/************************************************************************* - * UrlEscapeW [SHLWAPI.@] - * - * Converts unsafe characters in a Url into escape sequences. - * - * PARAMS - * pszUrl [I] Url to modify - * pszEscaped [O] Destination for modified Url - * pcchEscaped [I/O] Length of pszUrl, destination for length of pszEscaped - * dwFlags [I] URL_ flags from "shlwapi.h" - * - * RETURNS - * Success: S_OK. pszEscaped contains the escaped Url, pcchEscaped - * contains its length. - * Failure: E_POINTER, if pszEscaped is not large enough. In this case - * pcchEscaped is set to the required length. - * - * Converts unsafe characters into their escape sequences. - * - * NOTES - * - By default this function stops converting at the first '?' or - * '#' character. - * - If dwFlags contains URL_ESCAPE_SPACES_ONLY then only spaces are - * converted, but the conversion continues past a '?' or '#'. - * - Note that this function did not work well (or at all) in shlwapi version 4. - * - * BUGS - * Only the following flags are implemented: - *| URL_ESCAPE_SPACES_ONLY - *| URL_DONT_ESCAPE_EXTRA_INFO - *| URL_ESCAPE_SEGMENT_ONLY - *| URL_ESCAPE_PERCENT - */ -HRESULT WINAPI UrlEscapeW( - LPCWSTR pszUrl, - LPWSTR pszEscaped, - LPDWORD pcchEscaped, - DWORD dwFlags) -{ - LPCWSTR src; - DWORD needed = 0, ret; - BOOL stop_escaping = FALSE; - WCHAR next[5], *dst = pszEscaped; - INT len; - PARSEDURLW parsed_url; - DWORD int_flags; - DWORD slashes = 0; - static const WCHAR localhost[] = {'l','o','c','a','l','h','o','s','t',0}; - - TRACE("(%s %p %p 0x%08lx)\n", debugstr_w(pszUrl), pszEscaped, - pcchEscaped, dwFlags); - - if(!pszUrl || !pszEscaped || !pcchEscaped) - return E_INVALIDARG; - - if(dwFlags & ~(URL_ESCAPE_SPACES_ONLY | - URL_ESCAPE_SEGMENT_ONLY | - URL_DONT_ESCAPE_EXTRA_INFO | - URL_ESCAPE_PERCENT)) - FIXME("Unimplemented flags: %08lx\n", dwFlags); - - /* fix up flags */ - if (dwFlags & URL_ESCAPE_SPACES_ONLY) - /* if SPACES_ONLY specified, reset the other controls */ - dwFlags &= ~(URL_DONT_ESCAPE_EXTRA_INFO | - URL_ESCAPE_PERCENT | - URL_ESCAPE_SEGMENT_ONLY); - - else - /* if SPACES_ONLY *not* specified the assume DONT_ESCAPE_EXTRA_INFO */ - dwFlags |= URL_DONT_ESCAPE_EXTRA_INFO; - - - int_flags = 0; - if(dwFlags & URL_ESCAPE_SEGMENT_ONLY) { - int_flags = WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH | WINE_URL_ESCAPE_SLASH; - } else { - parsed_url.cbSize = sizeof(parsed_url); - if(ParseURLW(pszUrl, &parsed_url) != S_OK) - parsed_url.nScheme = URL_SCHEME_INVALID; - - TRACE("scheme = %d (%s)\n", parsed_url.nScheme, debugstr_wn(parsed_url.pszProtocol, parsed_url.cchProtocol)); - - if(dwFlags & URL_DONT_ESCAPE_EXTRA_INFO) - int_flags = WINE_URL_STOP_ON_HASH | WINE_URL_STOP_ON_QUESTION; - - switch(parsed_url.nScheme) { - case URL_SCHEME_FILE: - int_flags |= WINE_URL_BASH_AS_SLASH | WINE_URL_COLLAPSE_SLASHES | WINE_URL_ESCAPE_HASH; - int_flags &= ~WINE_URL_STOP_ON_HASH; - break; - - case URL_SCHEME_HTTP: - case URL_SCHEME_HTTPS: - int_flags |= WINE_URL_BASH_AS_SLASH; - if(parsed_url.pszSuffix[0] != '/' && parsed_url.pszSuffix[0] != '\\') - int_flags |= WINE_URL_ESCAPE_SLASH; - break; - - case URL_SCHEME_MAILTO: - int_flags |= WINE_URL_ESCAPE_SLASH | WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH; - int_flags &= ~(WINE_URL_STOP_ON_QUESTION | WINE_URL_STOP_ON_HASH); - break; - - case URL_SCHEME_INVALID: - break; - - case URL_SCHEME_FTP: - default: - if(parsed_url.pszSuffix[0] != '/') - int_flags |= WINE_URL_ESCAPE_SLASH; - break; - } - } - - for(src = pszUrl; *src; ) { - WCHAR cur = *src; - len = 0; - - if((int_flags & WINE_URL_COLLAPSE_SLASHES) && src == pszUrl + parsed_url.cchProtocol + 1) { - int localhost_len = sizeof(localhost)/sizeof(WCHAR) - 1; - while(cur == '/' || cur == '\\') { - slashes++; - cur = *++src; - } - if(slashes == 2 && !strncmpiW(src, localhost, localhost_len)) { /* file://localhost/ -> file:/// */ - if(*(src + localhost_len) == '/' || *(src + localhost_len) == '\\') - src += localhost_len + 1; - slashes = 3; - } - - switch(slashes) { - case 1: - case 3: - next[0] = next[1] = next[2] = '/'; - len = 3; - break; - case 0: - len = 0; - break; - default: - next[0] = next[1] = '/'; - len = 2; - break; - } - } - if(len == 0) { - - if(cur == '#' && (int_flags & WINE_URL_STOP_ON_HASH)) - stop_escaping = TRUE; - - if(cur == '?' && (int_flags & WINE_URL_STOP_ON_QUESTION)) - stop_escaping = TRUE; - - if(cur == '\\' && (int_flags & WINE_URL_BASH_AS_SLASH) && !stop_escaping) cur = '/'; - - if(URL_NeedEscapeW(cur, dwFlags, int_flags) && stop_escaping == FALSE) { - next[0] = L'%'; - next[1] = hexDigits[(cur >> 4) & 0xf]; - next[2] = hexDigits[cur & 0xf]; - len = 3; - } else { - next[0] = cur; - len = 1; - } - src++; - } - - if(needed + len <= *pcchEscaped) { - memcpy(dst, next, len*sizeof(WCHAR)); - dst += len; - } - needed += len; - } - - if(needed < *pcchEscaped) { - *dst = '\0'; - ret = S_OK; - } else { - needed++; /* add one for the '\0' */ - ret = E_POINTER; - } - *pcchEscaped = needed; - return ret; -} - - -/************************************************************************* - * UrlUnescapeA [SHLWAPI.@] - * - * Converts Url escape sequences back to ordinary characters. - * - * PARAMS - * pszUrl [I/O] Url to convert - * pszUnescaped [O] Destination for converted Url - * pcchUnescaped [I/O] Size of output string - * dwFlags [I] URL_ESCAPE_ Flags from "shlwapi.h" - * - * RETURNS - * Success: S_OK. The converted value is in pszUnescaped, or in pszUrl if - * dwFlags includes URL_ESCAPE_INPLACE. - * Failure: E_POINTER if the converted Url is bigger than pcchUnescaped. In - * this case pcchUnescaped is set to the size required. - * NOTES - * If dwFlags includes URL_DONT_ESCAPE_EXTRA_INFO, the conversion stops at - * the first occurrence of either a '?' or '#' character. - */ -HRESULT WINAPI UrlUnescapeA( - LPSTR pszUrl, - LPSTR pszUnescaped, - LPDWORD pcchUnescaped, - DWORD dwFlags) -{ - char *dst, next; - LPCSTR src; - HRESULT ret; - DWORD needed; - BOOL stop_unescaping = FALSE; - - TRACE("(%s, %p, %p, 0x%08lx)\n", debugstr_a(pszUrl), pszUnescaped, - pcchUnescaped, dwFlags); - - if(!pszUrl || !pszUnescaped || !pcchUnescaped) - return E_INVALIDARG; - - if(dwFlags & URL_UNESCAPE_INPLACE) - dst = pszUrl; - else - dst = pszUnescaped; - - for(src = pszUrl, needed = 0; *src; src++, needed++) { - if(dwFlags & URL_DONT_UNESCAPE_EXTRA_INFO && - (*src == '#' || *src == '?')) { - stop_unescaping = TRUE; - next = *src; - } else if(*src == '%' && isxdigit(*(src + 1)) && isxdigit(*(src + 2)) - && stop_unescaping == FALSE) { - INT ih; - char buf[3]; - memcpy(buf, src + 1, 2); - buf[2] = '\0'; - ih = strtol(buf, NULL, 16); - next = (CHAR) ih; - src += 2; /* Advance to end of escape */ - } else - next = *src; - - if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) - *dst++ = next; - } - - if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) { - *dst = '\0'; - ret = S_OK; - } else { - needed++; /* add one for the '\0' */ - ret = E_POINTER; - } - if(!(dwFlags & URL_UNESCAPE_INPLACE)) - *pcchUnescaped = needed; - - if (ret == S_OK) { - TRACE("result %s\n", (dwFlags & URL_UNESCAPE_INPLACE) ? - debugstr_a(pszUrl) : debugstr_a(pszUnescaped)); - } - - return ret; -} - -/************************************************************************* - * UrlUnescapeW [SHLWAPI.@] - * - * See UrlUnescapeA. - */ -HRESULT WINAPI UrlUnescapeW( - LPWSTR pszUrl, - LPWSTR pszUnescaped, - LPDWORD pcchUnescaped, - DWORD dwFlags) -{ - WCHAR *dst, next; - LPCWSTR src; - HRESULT ret; - DWORD needed; - BOOL stop_unescaping = FALSE; - - TRACE("(%s, %p, %p, 0x%08lx)\n", debugstr_w(pszUrl), pszUnescaped, - pcchUnescaped, dwFlags); - - if(!pszUrl || (!pszUnescaped && !(dwFlags & URL_UNESCAPE_INPLACE))|| !pcchUnescaped) - return E_INVALIDARG; - - if(dwFlags & URL_UNESCAPE_INPLACE) - dst = pszUrl; - else - dst = pszUnescaped; - - for(src = pszUrl, needed = 0; *src; src++, needed++) { - if(dwFlags & URL_DONT_UNESCAPE_EXTRA_INFO && - (*src == L'#' || *src == L'?')) { - stop_unescaping = TRUE; - next = *src; - } else if(*src == L'%' && isxdigitW(*(src + 1)) && isxdigitW(*(src + 2)) - && stop_unescaping == FALSE) { - INT ih; - WCHAR buf[5] = {'0','x',0}; - memcpy(buf + 2, src + 1, 2*sizeof(WCHAR)); - buf[4] = 0; - StrToIntExW(buf, STIF_SUPPORT_HEX, &ih); - next = (WCHAR) ih; - src += 2; /* Advance to end of escape */ - } else - next = *src; - - if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) - *dst++ = next; - } - - if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) { - *dst = L'\0'; - ret = S_OK; - } else { - needed++; /* add one for the '\0' */ - ret = E_POINTER; - } - if(!(dwFlags & URL_UNESCAPE_INPLACE)) - *pcchUnescaped = needed; - - if (ret == S_OK) { - TRACE("result %s\n", (dwFlags & URL_UNESCAPE_INPLACE) ? - debugstr_w(pszUrl) : debugstr_w(pszUnescaped)); - } - - return ret; -} - -/************************************************************************* - * UrlGetLocationA [SHLWAPI.@] - * - * Get the location from a Url. - * - * PARAMS - * pszUrl [I] Url to get the location from - * - * RETURNS - * A pointer to the start of the location in pszUrl, or NULL if there is - * no location. - * - * NOTES - * - MSDN erroneously states that "The location is the segment of the Url - * starting with a '?' or '#' character". Neither V4 nor V5 of shlwapi.dll - * stop at '?' and always return a NULL in this case. - * - MSDN also erroneously states that "If a file URL has a query string, - * the returned string is the query string". In all tested cases, if the - * Url starts with "fi" then a NULL is returned. V5 gives the following results: - *| Result Url - *| ------ --- - *| NULL file://aa/b/cd#hohoh - *| #hohoh http://aa/b/cd#hohoh - *| NULL fi://aa/b/cd#hohoh - *| #hohoh ff://aa/b/cd#hohoh - */ -LPCSTR WINAPI UrlGetLocationA( - LPCSTR pszUrl) -{ - PARSEDURLA base; - DWORD res1; - - base.cbSize = sizeof(base); - res1 = ParseURLA(pszUrl, &base); - if (res1) return NULL; /* invalid scheme */ - - /* if scheme is file: then never return pointer */ - if (strncmp(base.pszProtocol, "file", min(4,base.cchProtocol)) == 0) return NULL; - - /* Look for '#' and return its addr */ - return strchr(base.pszSuffix, '#'); -} - -/************************************************************************* - * UrlGetLocationW [SHLWAPI.@] - * - * See UrlGetLocationA. - */ -LPCWSTR WINAPI UrlGetLocationW( - LPCWSTR pszUrl) -{ - PARSEDURLW base; - DWORD res1; - - base.cbSize = sizeof(base); - res1 = ParseURLW(pszUrl, &base); - if (res1) return NULL; /* invalid scheme */ - - /* if scheme is file: then never return pointer */ - if (strncmpW(base.pszProtocol, fileW, min(4,base.cchProtocol)) == 0) return NULL; - - /* Look for '#' and return its addr */ - return strchrW(base.pszSuffix, L'#'); -} - -/************************************************************************* - * UrlCompareA [SHLWAPI.@] - * - * Compare two Urls. - * - * PARAMS - * pszUrl1 [I] First Url to compare - * pszUrl2 [I] Url to compare to pszUrl1 - * fIgnoreSlash [I] TRUE = compare only up to a final slash - * - * RETURNS - * less than zero, zero, or greater than zero indicating pszUrl2 is greater - * than, equal to, or less than pszUrl1 respectively. - */ -INT WINAPI UrlCompareA( - LPCSTR pszUrl1, - LPCSTR pszUrl2, - BOOL fIgnoreSlash) -{ - INT ret, len, len1, len2; - - if (!fIgnoreSlash) - return strcmp(pszUrl1, pszUrl2); - len1 = strlen(pszUrl1); - if (pszUrl1[len1-1] == '/') len1--; - len2 = strlen(pszUrl2); - if (pszUrl2[len2-1] == '/') len2--; - if (len1 == len2) - return strncmp(pszUrl1, pszUrl2, len1); - len = min(len1, len2); - ret = strncmp(pszUrl1, pszUrl2, len); - if (ret) return ret; - if (len1 > len2) return 1; - return -1; -} - -/************************************************************************* - * UrlCompareW [SHLWAPI.@] - * - * See UrlCompareA. - */ -INT WINAPI UrlCompareW( - LPCWSTR pszUrl1, - LPCWSTR pszUrl2, - BOOL fIgnoreSlash) -{ - INT ret; - size_t len, len1, len2; - - if (!fIgnoreSlash) - return strcmpW(pszUrl1, pszUrl2); - len1 = strlenW(pszUrl1); - if (pszUrl1[len1-1] == '/') len1--; - len2 = strlenW(pszUrl2); - if (pszUrl2[len2-1] == '/') len2--; - if (len1 == len2) - return strncmpW(pszUrl1, pszUrl2, len1); - len = min(len1, len2); - ret = strncmpW(pszUrl1, pszUrl2, len); - if (ret) return ret; - if (len1 > len2) return 1; - return -1; -} - -/************************************************************************* - * HashData [SHLWAPI.@] - * - * Hash an input block into a variable sized digest. - * - * PARAMS - * lpSrc [I] Input block - * nSrcLen [I] Length of lpSrc - * lpDest [I] Output for hash digest - * nDestLen [I] Length of lpDest - * - * RETURNS - * Success: TRUE. lpDest is filled with the computed hash value. - * Failure: FALSE, if any argument is invalid. - */ -HRESULT WINAPI HashData(LPBYTE lpSrc, DWORD nSrcLen, - LPBYTE lpDest, DWORD nDestLen) -{ - INT srcCount = nSrcLen - 1, destCount = nDestLen - 1; - - if (IsBadReadPtr(lpSrc, nSrcLen) || - IsBadWritePtr(lpDest, nDestLen)) - return E_INVALIDARG; - - while (destCount >= 0) - { - lpDest[destCount] = (destCount & 0xff); - destCount--; - } - - while (srcCount >= 0) - { - destCount = nDestLen - 1; - while (destCount >= 0) - { - lpDest[destCount] = HashDataLookup[lpSrc[srcCount] ^ lpDest[destCount]]; - destCount--; - } - srcCount--; - } - return S_OK; -} - -/************************************************************************* - * UrlHashA [SHLWAPI.@] - * - * Produce a Hash from a Url. - * - * PARAMS - * pszUrl [I] Url to hash - * lpDest [O] Destinationh for hash - * nDestLen [I] Length of lpDest - * - * RETURNS - * Success: S_OK. lpDest is filled with the computed hash value. - * Failure: E_INVALIDARG, if any argument is invalid. - */ -HRESULT WINAPI UrlHashA(LPCSTR pszUrl, unsigned char *lpDest, DWORD nDestLen) -{ - if (IsBadStringPtrA(pszUrl, -1) || IsBadWritePtr(lpDest, nDestLen)) - return E_INVALIDARG; - - HashData((LPSTR)pszUrl, (int)strlen(pszUrl), lpDest, nDestLen); - return S_OK; -} - -/************************************************************************* - * UrlHashW [SHLWAPI.@] - * - * See UrlHashA. - */ -HRESULT WINAPI UrlHashW(LPCWSTR pszUrl, unsigned char *lpDest, DWORD nDestLen) -{ - char szUrl[MAX_PATH]; - - TRACE("(%s,%p,%ld)\n",debugstr_w(pszUrl), lpDest, nDestLen); - - if (IsBadStringPtrW(pszUrl, -1) || IsBadWritePtr(lpDest, nDestLen)) - return E_INVALIDARG; - - /* Win32 hashes the data as an ASCII string, presumably so that both A+W - * return the same digests for the same URL. - */ - WideCharToMultiByte(0, 0, pszUrl, -1, szUrl, MAX_PATH, 0, 0); - HashData((BYTE*)szUrl, (int)strlen(szUrl), lpDest, nDestLen); - return S_OK; -} - -/************************************************************************* - * UrlApplySchemeA [SHLWAPI.@] - * - * Apply a scheme to a Url. - * - * PARAMS - * pszIn [I] Url to apply scheme to - * pszOut [O] Destination for modified Url - * pcchOut [I/O] Length of pszOut/destination for length of pszOut - * dwFlags [I] URL_ flags from "shlwapi.h" - * - * RETURNS - * Success: S_OK: pszOut contains the modified Url, pcchOut contains its length. - * Failure: An HRESULT error code describing the error. - */ -HRESULT WINAPI UrlApplySchemeA(LPCSTR pszIn, LPSTR pszOut, LPDWORD pcchOut, DWORD dwFlags) -{ - LPWSTR in, out; - DWORD ret, len, len2; - - TRACE("(in %s, out size %ld, flags %08lx) using W version\n", - debugstr_a(pszIn), *pcchOut, dwFlags); - - in = HeapAlloc(GetProcessHeap(), 0, - (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR)); - out = in + INTERNET_MAX_URL_LENGTH; - - MultiByteToWideChar(0, 0, pszIn, -1, in, INTERNET_MAX_URL_LENGTH); - len = INTERNET_MAX_URL_LENGTH; - - ret = UrlApplySchemeW(in, out, &len, dwFlags); - if ((ret != S_OK) && (ret != S_FALSE)) { - HeapFree(GetProcessHeap(), 0, in); - return ret; - } - - len2 = WideCharToMultiByte(0, 0, out, len+1, 0, 0, 0, 0); - if (len2 > *pcchOut) { - *pcchOut = len2; - HeapFree(GetProcessHeap(), 0, in); - return E_POINTER; - } - WideCharToMultiByte(0, 0, out, len+1, pszOut, *pcchOut, 0, 0); - *pcchOut = len2; - HeapFree(GetProcessHeap(), 0, in); - return ret; -} - -static HRESULT URL_GuessScheme(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut) -{ - HKEY newkey; - BOOL j; - INT index; - DWORD value_len, data_len, dwType, i; - WCHAR reg_path[MAX_PATH]; - WCHAR value[MAX_PATH], data[MAX_PATH]; - WCHAR Wxx, Wyy; - - MultiByteToWideChar(0, 0, - "Software\\Microsoft\\Windows\\CurrentVersion\\URL\\Prefixes", - -1, reg_path, MAX_PATH); - RegOpenKeyExW(HKEY_LOCAL_MACHINE, reg_path, 0, 1, &newkey); - index = 0; - while(value_len = data_len = MAX_PATH, - RegEnumValueW(newkey, index, value, &value_len, - 0, &dwType, (LPVOID)data, &data_len) == 0) { - TRACE("guess %d %s is %s\n", - index, debugstr_w(value), debugstr_w(data)); - - j = FALSE; - for(i=0; i<value_len; i++) { - Wxx = pszIn[i]; - Wyy = value[i]; - /* remember that TRUE is not-equal */ - j = ChrCmpIW(Wxx, Wyy); - if (j) break; - } - if ((i == value_len) && !j) { - if (strlenW(data) + strlenW(pszIn) + 1 > *pcchOut) { - *pcchOut = strlenW(data) + strlenW(pszIn) + 1; - RegCloseKey(newkey); - return E_POINTER; - } - strcpyW(pszOut, data); - strcatW(pszOut, pszIn); - *pcchOut = strlenW(pszOut); - TRACE("matched and set to %s\n", debugstr_w(pszOut)); - RegCloseKey(newkey); - return S_OK; - } - index++; - } - RegCloseKey(newkey); - return -1; -} - -static HRESULT URL_ApplyDefault(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut) -{ - HKEY newkey; - DWORD data_len, dwType; - WCHAR reg_path[MAX_PATH]; - WCHAR value[MAX_PATH], data[MAX_PATH]; - - /* get and prepend default */ - MultiByteToWideChar(0, 0, - "Software\\Microsoft\\Windows\\CurrentVersion\\URL\\DefaultPrefix", - -1, reg_path, MAX_PATH); - RegOpenKeyExW(HKEY_LOCAL_MACHINE, reg_path, 0, 1, &newkey); - data_len = MAX_PATH; - value[0] = L'@'; - value[1] = L'\0'; - RegQueryValueExW(newkey, value, 0, &dwType, (LPBYTE)data, &data_len); - RegCloseKey(newkey); - if (strlenW(data) + strlenW(pszIn) + 1 > *pcchOut) { - *pcchOut = strlenW(data) + strlenW(pszIn) + 1; - return E_POINTER; - } - strcpyW(pszOut, data); - strcatW(pszOut, pszIn); - *pcchOut = strlenW(pszOut); - TRACE("used default %s\n", debugstr_w(pszOut)); - return S_OK; -} - -/************************************************************************* - * UrlApplySchemeW [SHLWAPI.@] - * - * See UrlApplySchemeA. - */ -HRESULT WINAPI UrlApplySchemeW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, DWORD dwFlags) -{ - PARSEDURLW in_scheme; - DWORD res1; - HRESULT ret; - - TRACE("(in %s, out size %ld, flags %08lx)\n", - debugstr_w(pszIn), *pcchOut, dwFlags); - - if (dwFlags & URL_APPLY_GUESSFILE) { - FIXME("(%s %p %p(%ld) 0x%08lx): stub URL_APPLY_GUESSFILE not implemented\n", - debugstr_w(pszIn), pszOut, pcchOut, *pcchOut, dwFlags); - strcpyW(pszOut, pszIn); - *pcchOut = strlenW(pszOut); - return S_FALSE; - } - - in_scheme.cbSize = sizeof(in_scheme); - /* See if the base has a scheme */ - res1 = ParseURLW(pszIn, &in_scheme); - if (res1) { - /* no scheme in input, need to see if we need to guess */ - if (dwFlags & URL_APPLY_GUESSSCHEME) { - if ((ret = URL_GuessScheme(pszIn, pszOut, pcchOut)) != -1) - return ret; - } - } - else { - /* we have a scheme, see if valid (known scheme) */ - if (in_scheme.nScheme) { - /* have valid scheme, so just copy and exit */ - if (strlenW(pszIn) + 1 > *pcchOut) { - *pcchOut = strlenW(pszIn) + 1; - return E_POINTER; - } - strcpyW(pszOut, pszIn); - *pcchOut = strlenW(pszOut); - TRACE("valid scheme, returing copy\n"); - return S_OK; - } - } - - /* If we are here, then either invalid scheme, - * or no scheme and can't/failed guess. - */ - if ( ( ((res1 == 0) && (dwFlags & URL_APPLY_FORCEAPPLY)) || - ((res1 != 0)) ) && - (dwFlags & URL_APPLY_DEFAULT)) { - /* find and apply default scheme */ - return URL_ApplyDefault(pszIn, pszOut, pcchOut); - } - - /* just copy and give proper return code */ - if (strlenW(pszIn) + 1 > *pcchOut) { - *pcchOut = strlenW(pszIn) + 1; - return E_POINTER; - } - strcpyW(pszOut, pszIn); - *pcchOut = strlenW(pszOut); - TRACE("returning copy, left alone\n"); - return S_FALSE; -} - -/************************************************************************* - * UrlIsA [SHLWAPI.@] - * - * Determine if a Url is of a certain class. - * - * PARAMS - * pszUrl [I] Url to check - * Urlis [I] URLIS_ constant from "shlwapi.h" - * - * RETURNS - * TRUE if pszUrl belongs to the class type in Urlis. - * FALSE Otherwise. - */ -BOOL WINAPI UrlIsA(LPCSTR pszUrl, URLIS Urlis) -{ - PARSEDURLA base; - DWORD res1; - LPCSTR last; - - TRACE("(%s %d)\n", debugstr_a(pszUrl), Urlis); - - switch (Urlis) { - - case URLIS_OPAQUE: - base.cbSize = sizeof(base); - res1 = ParseURLA(pszUrl, &base); - if (res1) return FALSE; /* invalid scheme */ - switch (base.nScheme) - { - case URL_SCHEME_MAILTO: - case URL_SCHEME_SHELL: - case URL_SCHEME_JAVASCRIPT: - case URL_SCHEME_VBSCRIPT: - case URL_SCHEME_ABOUT: - return TRUE; - } - return FALSE; - - case URLIS_FILEURL: - return !StrCmpNA("file:", pszUrl, 5); - - case URLIS_DIRECTORY: - last = pszUrl + strlen(pszUrl) - 1; - return (last >= pszUrl && (*last == '/' || *last == '\\' )); - - case URLIS_URL: - return PathIsURLA(pszUrl); - - case URLIS_NOHISTORY: - case URLIS_APPLIABLE: - case URLIS_HASQUERY: - default: - FIXME("(%s %d): stub\n", debugstr_a(pszUrl), Urlis); - } - return FALSE; -} - -/************************************************************************* - * UrlIsW [SHLWAPI.@] - * - * See UrlIsA. - */ -BOOL WINAPI UrlIsW(LPCWSTR pszUrl, URLIS Urlis) -{ - static const WCHAR stemp[] = { 'f','i','l','e',':',0 }; - PARSEDURLW base; - DWORD res1; - LPCWSTR last; - - TRACE("(%s %d)\n", debugstr_w(pszUrl), Urlis); - - switch (Urlis) { - - case URLIS_OPAQUE: - base.cbSize = sizeof(base); - res1 = ParseURLW(pszUrl, &base); - if (res1) return FALSE; /* invalid scheme */ - switch (base.nScheme) - { - case URL_SCHEME_MAILTO: - case URL_SCHEME_SHELL: - case URL_SCHEME_JAVASCRIPT: - case URL_SCHEME_VBSCRIPT: - case URL_SCHEME_ABOUT: - return TRUE; - } - return FALSE; - - case URLIS_FILEURL: - return !strncmpW(stemp, pszUrl, 5); - - case URLIS_DIRECTORY: - last = pszUrl + strlenW(pszUrl) - 1; - return (last >= pszUrl && (*last == '/' || *last == '\\')); - - case URLIS_URL: - return PathIsURLW(pszUrl); - - case URLIS_NOHISTORY: - case URLIS_APPLIABLE: - case URLIS_HASQUERY: - default: - FIXME("(%s %d): stub\n", debugstr_w(pszUrl), Urlis); - } - return FALSE; -} - -/************************************************************************* - * UrlIsNoHistoryA [SHLWAPI.@] - * - * Determine if a Url should not be stored in the users history list. - * - * PARAMS - * pszUrl [I] Url to check - * - * RETURNS - * TRUE, if pszUrl should be excluded from the history list, - * FALSE otherwise. - */ -BOOL WINAPI UrlIsNoHistoryA(LPCSTR pszUrl) -{ - return UrlIsA(pszUrl, URLIS_NOHISTORY); -} - -/************************************************************************* - * UrlIsNoHistoryW [SHLWAPI.@] - * - * See UrlIsNoHistoryA. - */ -BOOL WINAPI UrlIsNoHistoryW(LPCWSTR pszUrl) -{ - return UrlIsW(pszUrl, URLIS_NOHISTORY); -} - -/************************************************************************* - * UrlIsOpaqueA [SHLWAPI.@] - * - * Determine if a Url is opaque. - * - * PARAMS - * pszUrl [I] Url to check - * - * RETURNS - * TRUE if pszUrl is opaque, - * FALSE Otherwise. - * - * NOTES - * An opaque Url is one that does not start with "<protocol>://". - */ -BOOL WINAPI UrlIsOpaqueA(LPCSTR pszUrl) -{ - return UrlIsA(pszUrl, URLIS_OPAQUE); -} - -/************************************************************************* - * UrlIsOpaqueW [SHLWAPI.@] - * - * See UrlIsOpaqueA. - */ -BOOL WINAPI UrlIsOpaqueW(LPCWSTR pszUrl) -{ - return UrlIsW(pszUrl, URLIS_OPAQUE); -} - -/************************************************************************* - * Scans for characters of type "type" and when not matching found, - * returns pointer to it and length in size. - * - * Characters tested based on RFC 1738 - */ -static LPCWSTR URL_ScanID(LPCWSTR start, LPDWORD size, WINE_URL_SCAN_TYPE type) -{ - static DWORD alwayszero = 0; - BOOL cont = TRUE; - - *size = 0; - - switch(type){ - - case SCHEME: - while (cont) { - if ( (islowerW(*start) && isalphaW(*start)) || - isdigitW(*start) || - (*start == L'+') || - (*start == L'-') || - (*start == L'.')) { - start++; - (*size)++; - } - else - cont = FALSE; - } - break; - - case USERPASS: - while (cont) { - if ( isalphaW(*start) || - isdigitW(*start) || - /* user/password only characters */ - (*start == L';') || - (*start == L'?') || - (*start == L'&') || - (*start == L'=') || - /* *extra* characters */ - (*start == L'!') || - (*start == L'*') || - (*start == L'\'') || - (*start == L'(') || - (*start == L')') || - (*start == L',') || - /* *safe* characters */ - (*start == L'$') || - (*start == L'_') || - (*start == L'+') || - (*start == L'-') || - (*start == L'.')) { - start++; - (*size)++; - } else if (*start == L'%') { - if (isxdigitW(*(start+1)) && - isxdigitW(*(start+2))) { - start += 3; - *size += 3; - } else - cont = FALSE; - } else - cont = FALSE; - } - break; - - case PORT: - while (cont) { - if (isdigitW(*start)) { - start++; - (*size)++; - } - else - cont = FALSE; - } - break; - - case HOST: - while (cont) { - if (isalnumW(*start) || - (*start == L'-') || - (*start == L'.') ) { - start++; - (*size)++; - } - else - cont = FALSE; - } - break; - default: - FIXME("unknown type %d\n", type); - return (LPWSTR)&alwayszero; - } - /* TRACE("scanned %ld characters next char %p<%c>\n", - *size, start, *start); */ - return start; -} - -/************************************************************************* - * Attempt to parse URL into pieces. - */ -static LONG URL_ParseUrl(LPCWSTR pszUrl, WINE_PARSE_URL *pl) -{ - LPCWSTR work; - - memset(pl, 0, sizeof(WINE_PARSE_URL)); - pl->pScheme = pszUrl; - work = URL_ScanID(pl->pScheme, &pl->szScheme, SCHEME); - if (!*work || (*work != L':')) goto ErrorExit; - work++; - if ((*work != L'/') || (*(work+1) != L'/')) goto ErrorExit; - pl->pUserName = work + 2; - work = URL_ScanID(pl->pUserName, &pl->szUserName, USERPASS); - if (*work == L':' ) { - /* parse password */ - work++; - pl->pPassword = work; - work = URL_ScanID(pl->pPassword, &pl->szPassword, USERPASS); - if (*work != L'@') { - /* what we just parsed must be the hostname and port - * so reset pointers and clear then let it parse */ - pl->szUserName = pl->szPassword = 0; - work = pl->pUserName - 1; - pl->pUserName = pl->pPassword = 0; - } - } else if (*work == L'@') { - /* no password */ - pl->szPassword = 0; - pl->pPassword = 0; - } else if (!*work || (*work == L'/') || (*work == L'.')) { - /* what was parsed was hostname, so reset pointers and let it parse */ - pl->szUserName = pl->szPassword = 0; - work = pl->pUserName - 1; - pl->pUserName = pl->pPassword = 0; - } else goto ErrorExit; - - /* now start parsing hostname or hostnumber */ - work++; - pl->pHostName = work; - work = URL_ScanID(pl->pHostName, &pl->szHostName, HOST); - if (*work == L':') { - /* parse port */ - work++; - pl->pPort = work; - work = URL_ScanID(pl->pPort, &pl->szPort, PORT); - } - if (*work == L'/') { - /* see if query string */ - pl->pQuery = strchrW(work, L'?'); - if (pl->pQuery) pl->szQuery = strlenW(pl->pQuery); - } - TRACE("parse successful: scheme=%p(%ld), user=%p(%ld), pass=%p(%ld), host=%p(%ld), port=%p(%ld), query=%p(%ld)\n", - pl->pScheme, pl->szScheme, - pl->pUserName, pl->szUserName, - pl->pPassword, pl->szPassword, - pl->pHostName, pl->szHostName, - pl->pPort, pl->szPort, - pl->pQuery, pl->szQuery); - return S_OK; - ErrorExit: - FIXME("failed to parse %s\n", debugstr_w(pszUrl)); - return E_INVALIDARG; -} - -/************************************************************************* - * UrlGetPartA [SHLWAPI.@] - * - * Retrieve part of a Url. - * - * PARAMS - * pszIn [I] Url to parse - * pszOut [O] Destination for part of pszIn requested - * pcchOut [I] Size of pszOut - * [O] length of pszOut string EXLUDING '\0' if S_OK, otherwise - * needed size of pszOut INCLUDING '\0'. - * dwPart [I] URL_PART_ enum from "shlwapi.h" - * dwFlags [I] URL_ flags from "shlwapi.h" - * - * RETURNS - * Success: S_OK. pszOut contains the part requested, pcchOut contains its length. - * Failure: An HRESULT error code describing the error. - */ -HRESULT WINAPI UrlGetPartA(LPCSTR pszIn, LPSTR pszOut, LPDWORD pcchOut, - DWORD dwPart, DWORD dwFlags) -{ - LPWSTR in, out; - DWORD ret, len, len2; - - in = HeapAlloc(GetProcessHeap(), 0, - (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR)); - out = in + INTERNET_MAX_URL_LENGTH; - - MultiByteToWideChar(0, 0, pszIn, -1, in, INTERNET_MAX_URL_LENGTH); - - len = INTERNET_MAX_URL_LENGTH; - ret = UrlGetPartW(in, out, &len, dwPart, dwFlags); - - if (ret != S_OK) { - HeapFree(GetProcessHeap(), 0, in); - return ret; - } - - len2 = WideCharToMultiByte(0, 0, out, len, 0, 0, 0, 0); - if (len2 > *pcchOut) { - *pcchOut = len2; - HeapFree(GetProcessHeap(), 0, in); - return E_POINTER; - } - WideCharToMultiByte(0, 0, out, len+1, pszOut, *pcchOut, 0, 0); - *pcchOut = len2; - HeapFree(GetProcessHeap(), 0, in); - return S_OK; -} - -/************************************************************************* - * UrlGetPartW [SHLWAPI.@] - * - * See UrlGetPartA. - */ -HRESULT WINAPI UrlGetPartW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, - DWORD dwPart, DWORD dwFlags) -{ - WINE_PARSE_URL pl; - HRESULT ret; - DWORD size, schsize; - LPCWSTR addr, schaddr; - - TRACE("(%s %p %p(%ld) %08lx %08lx)\n", - debugstr_w(pszIn), pszOut, pcchOut, *pcchOut, dwPart, dwFlags); - - ret = URL_ParseUrl(pszIn, &pl); - if (!ret) { - schaddr = pl.pScheme; - schsize = pl.szScheme; - - switch (dwPart) { - case URL_PART_SCHEME: - if (!pl.szScheme) return E_INVALIDARG; - addr = pl.pScheme; - size = pl.szScheme; - break; - - case URL_PART_HOSTNAME: - if (!pl.szHostName) return E_INVALIDARG; - addr = pl.pHostName; - size = pl.szHostName; - break; - - case URL_PART_USERNAME: - if (!pl.szUserName) return E_INVALIDARG; - addr = pl.pUserName; - size = pl.szUserName; - break; - - case URL_PART_PASSWORD: - if (!pl.szPassword) return E_INVALIDARG; - addr = pl.pPassword; - size = pl.szPassword; - break; - - case URL_PART_PORT: - if (!pl.szPort) return E_INVALIDARG; - addr = pl.pPort; - size = pl.szPort; - break; - - case URL_PART_QUERY: - if (!pl.szQuery) return E_INVALIDARG; - addr = pl.pQuery; - size = pl.szQuery; - break; - - default: - return E_INVALIDARG; - } - - if (dwFlags == URL_PARTFLAG_KEEPSCHEME) { - if (*pcchOut < schsize + size + 2) { - *pcchOut = schsize + size + 2; - return E_POINTER; - } - memcpy(pszOut, schaddr, schsize*sizeof(WCHAR)); - pszOut[schsize] = ':'; - memcpy(pszOut+schsize+1, addr, size*sizeof(WCHAR)); - pszOut[schsize+1+size] = 0; - *pcchOut = schsize + 1 + size; - } - else { - if (*pcchOut < size + 1) {*pcchOut = size+1; return E_POINTER;} - memcpy(pszOut, addr, size*sizeof(WCHAR)); - pszOut[size] = 0; - *pcchOut = size; - } - TRACE("len=%ld %s\n", *pcchOut, debugstr_w(pszOut)); - } - return ret; -} - -/************************************************************************* - * PathIsURLA [SHLWAPI.@] - * - * Check if the given path is a Url. - * - * PARAMS - * lpszPath [I] Path to check. - * - * RETURNS - * TRUE if lpszPath is a Url. - * FALSE if lpszPath is NULL or not a Url. - */ -BOOL WINAPI PathIsURLA(LPCSTR lpstrPath) -{ - PARSEDURLA base; - DWORD res1; - - if (!lpstrPath || !*lpstrPath) return FALSE; - - /* get protocol */ - base.cbSize = sizeof(base); - res1 = ParseURLA(lpstrPath, &base); - return (base.nScheme != URL_SCHEME_INVALID); -} - -/************************************************************************* - * PathIsURLW [SHLWAPI.@] - * - * See PathIsURLA. - */ -BOOL WINAPI PathIsURLW(LPCWSTR lpstrPath) -{ - PARSEDURLW base; - DWORD res1; - - if (!lpstrPath || !*lpstrPath) return FALSE; - - /* get protocol */ - base.cbSize = sizeof(base); - res1 = ParseURLW(lpstrPath, &base); - return (base.nScheme != URL_SCHEME_INVALID); -} - -/************************************************************************* - * UrlCreateFromPathA [SHLWAPI.@] - * - * See UrlCreateFromPathW - */ -HRESULT WINAPI UrlCreateFromPathA(LPCSTR pszPath, LPSTR pszUrl, LPDWORD pcchUrl, DWORD dwReserved) -{ - WCHAR bufW[INTERNET_MAX_URL_LENGTH]; - WCHAR *urlW = bufW; - UNICODE_STRING pathW; - HRESULT ret; - DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA; - - if(!RtlCreateUnicodeStringFromAsciiz(&pathW, pszPath)) - return E_INVALIDARG; - if((ret = UrlCreateFromPathW(pathW.Buffer, urlW, &lenW, dwReserved)) == E_POINTER) { - urlW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR)); - ret = UrlCreateFromPathW(pathW.Buffer, urlW, &lenW, dwReserved); - } - if(ret == S_OK || ret == S_FALSE) { - RtlUnicodeToMultiByteSize(&lenA, urlW, lenW * sizeof(WCHAR)); - if(*pcchUrl > lenA) { - RtlUnicodeToMultiByteN(pszUrl, *pcchUrl - 1, &lenA, urlW, lenW * sizeof(WCHAR)); - pszUrl[lenA] = 0; - *pcchUrl = lenA; - } else { - *pcchUrl = lenA + 1; - ret = E_POINTER; - } - } - if(urlW != bufW) HeapFree(GetProcessHeap(), 0, urlW); - RtlFreeUnicodeString(&pathW); - return ret; -} - -/************************************************************************* - * UrlCreateFromPathW [SHLWAPI.@] - * - * Create a Url from a file path. - * - * PARAMS - * pszPath [I] Path to convert - * pszUrl [O] Destination for the converted Url - * pcchUrl [I/O] Length of pszUrl - * dwReserved [I] Reserved, must be 0 - * - * RETURNS - * Success: S_OK pszUrl contains the converted path, S_FALSE if the path is already a Url - * Failure: An HRESULT error code. - */ -HRESULT WINAPI UrlCreateFromPathW(LPCWSTR pszPath, LPWSTR pszUrl, LPDWORD pcchUrl, DWORD dwReserved) -{ - DWORD needed; - HRESULT ret; - WCHAR *pszNewUrl; - WCHAR file_colonW[] = {'f','i','l','e',':',0}; - WCHAR three_slashesW[] = {'/','/','/',0}; - PARSEDURLW parsed_url; - - TRACE("(%s, %p, %p, 0x%08lx)\n", debugstr_w(pszPath), pszUrl, pcchUrl, dwReserved); - - /* Validate arguments */ - if (dwReserved != 0) - return E_INVALIDARG; - if (!pszUrl || !pcchUrl) - return E_INVALIDARG; - - - parsed_url.cbSize = sizeof(parsed_url); - if(ParseURLW(pszPath, &parsed_url) == S_OK) { - if(parsed_url.nScheme != URL_SCHEME_INVALID && parsed_url.cchProtocol > 1) { - needed = strlenW(pszPath); - if (needed >= *pcchUrl) { - *pcchUrl = needed + 1; - return E_POINTER; - } else { - *pcchUrl = needed; - strcpyW(pszUrl, pszPath); - return S_FALSE; - } - } - } - - pszNewUrl = HeapAlloc(GetProcessHeap(), 0, (strlenW(pszPath) + 9) * sizeof(WCHAR)); /* "file:///" + pszPath_len + 1 */ - strcpyW(pszNewUrl, file_colonW); - if(isalphaW(pszPath[0]) && pszPath[1] == ':') - strcatW(pszNewUrl, three_slashesW); - strcatW(pszNewUrl, pszPath); - ret = UrlEscapeW(pszNewUrl, pszUrl, pcchUrl, URL_ESCAPE_PERCENT); - - HeapFree(GetProcessHeap(), 0, pszNewUrl); - return ret; -} - -/************************************************************************* - * SHAutoComplete [SHLWAPI.@] - * - * Enable auto-completion for an edit control. - * - * PARAMS - * hwndEdit [I] Handle of control to enable auto-completion for - * dwFlags [I] SHACF_ flags from "shlwapi.h" - * - * RETURNS - * Success: S_OK. Auto-completion is enabled for the control. - * Failure: An HRESULT error code indicating the error. - */ -HRESULT WINAPI SHAutoComplete(HWND hwndEdit, DWORD dwFlags) -{ - FIXME("SHAutoComplete stub\n"); - return S_FALSE; -} - -/************************************************************************* - * MLBuildResURLA [SHLWAPI.405] - * - * Create a Url pointing to a resource in a module. - * - * PARAMS - * lpszLibName [I] Name of the module containing the resource - * hMod [I] Callers module handle - * dwFlags [I] Undocumented flags for loading the module - * lpszRes [I] Resource name - * lpszDest [O] Destination for resulting Url - * dwDestLen [I] Length of lpszDest - * - * RETURNS - * Success: S_OK. lpszDest constains the resource Url. - * Failure: E_INVALIDARG, if any argument is invalid, or - * E_FAIL if dwDestLen is too small. - */ -HRESULT WINAPI MLBuildResURLA(LPCSTR lpszLibName, HMODULE hMod, DWORD dwFlags, - LPCSTR lpszRes, LPSTR lpszDest, DWORD dwDestLen) -{ - WCHAR szLibName[MAX_PATH], szRes[MAX_PATH], szDest[MAX_PATH]; - HRESULT hRet; - - if (lpszLibName) - MultiByteToWideChar(CP_ACP, 0, lpszLibName, -1, szLibName, sizeof(szLibName)/sizeof(WCHAR)); - - if (lpszRes) - MultiByteToWideChar(CP_ACP, 0, lpszRes, -1, szRes, sizeof(szRes)/sizeof(WCHAR)); - - if (dwDestLen > sizeof(szLibName)/sizeof(WCHAR)) - dwDestLen = sizeof(szLibName)/sizeof(WCHAR); - - hRet = MLBuildResURLW(lpszLibName ? szLibName : NULL, hMod, dwFlags, - lpszRes ? szRes : NULL, lpszDest ? szDest : NULL, dwDestLen); - if (SUCCEEDED(hRet) && lpszDest) - WideCharToMultiByte(CP_ACP, 0, szDest, -1, lpszDest, dwDestLen, 0, 0); - - return hRet; -} - -/************************************************************************* - * MLBuildResURLA [SHLWAPI.406] - * - * See MLBuildResURLA. - */ -HRESULT WINAPI MLBuildResURLW(LPCWSTR lpszLibName, HMODULE hMod, DWORD dwFlags, - LPCWSTR lpszRes, LPWSTR lpszDest, DWORD dwDestLen) -{ - static const WCHAR szRes[] = { 'r','e','s',':','/','/','\0' }; -#define szResLen ((sizeof(szRes) - sizeof(WCHAR))/sizeof(WCHAR)) - HRESULT hRet = E_FAIL; - - TRACE("(%s,%p,0x%08lx,%s,%p,%ld)\n", debugstr_w(lpszLibName), hMod, dwFlags, - debugstr_w(lpszRes), lpszDest, dwDestLen); - - if (!lpszLibName || !hMod || hMod == INVALID_HANDLE_VALUE || !lpszRes || - !lpszDest || (dwFlags && dwFlags != 2)) - return E_INVALIDARG; - - if (dwDestLen >= szResLen + 1) - { - dwDestLen -= (szResLen + 1); - memcpy(lpszDest, szRes, sizeof(szRes)); - - hMod = MLLoadLibraryW(lpszLibName, hMod, dwFlags); - - if (hMod) - { - WCHAR szBuff[MAX_PATH]; - DWORD len; - - len = GetModuleFileNameW(hMod, szBuff, sizeof(szBuff)/sizeof(WCHAR)); - if (len && len < sizeof(szBuff)/sizeof(WCHAR)) - { - DWORD dwPathLen = strlenW(szBuff) + 1; - - if (dwDestLen >= dwPathLen) - { - DWORD dwResLen; - - dwDestLen -= dwPathLen; - memcpy(lpszDest + szResLen, szBuff, dwPathLen * sizeof(WCHAR)); - - dwResLen = strlenW(lpszRes) + 1; - if (dwDestLen >= dwResLen + 1) - { - lpszDest[szResLen + dwPathLen + dwResLen] = '/'; - memcpy(lpszDest + szResLen + dwPathLen, lpszRes, dwResLen * sizeof(WCHAR)); - hRet = S_OK; - } - } - } - MLFreeLibrary(hMod); - } - } - return hRet; -} +/* + * Url functions + * + * Copyright 2000 Huw D M Davies for CodeWeavers. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "wine/port.h" +#include <stdarg.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winerror.h" +#include "wine/unicode.h" +#include "wininet.h" +#include "winreg.h" +#include "winternl.h" +#define NO_SHLWAPI_STREAM +#include "shlwapi.h" +#include "wine/debug.h" + +HMODULE WINAPI MLLoadLibraryW(LPCWSTR,HMODULE,DWORD); +BOOL WINAPI MLFreeLibrary(HMODULE); +HRESULT WINAPI MLBuildResURLW(LPCWSTR,HMODULE,DWORD,LPCWSTR,LPWSTR,DWORD); + +WINE_DEFAULT_DEBUG_CHANNEL(shell); + +/* The following schemes were identified in the native version of + * SHLWAPI.DLL version 5.50 + */ +typedef struct { + URL_SCHEME scheme_number; + LPCSTR scheme_name; +} SHL_2_inet_scheme; + +static const SHL_2_inet_scheme shlwapi_schemes[] = { + {URL_SCHEME_FTP, "ftp"}, + {URL_SCHEME_HTTP, "http"}, + {URL_SCHEME_GOPHER, "gopher"}, + {URL_SCHEME_MAILTO, "mailto"}, + {URL_SCHEME_NEWS, "news"}, + {URL_SCHEME_NNTP, "nntp"}, + {URL_SCHEME_TELNET, "telnet"}, + {URL_SCHEME_WAIS, "wais"}, + {URL_SCHEME_FILE, "file"}, + {URL_SCHEME_MK, "mk"}, + {URL_SCHEME_HTTPS, "https"}, + {URL_SCHEME_SHELL, "shell"}, + {URL_SCHEME_SNEWS, "snews"}, + {URL_SCHEME_LOCAL, "local"}, + {URL_SCHEME_JAVASCRIPT, "javascript"}, + {URL_SCHEME_VBSCRIPT, "vbscript"}, + {URL_SCHEME_ABOUT, "about"}, + {URL_SCHEME_RES, "res"}, + {0, 0} +}; + +typedef struct { + LPCWSTR pScheme; /* [out] start of scheme */ + DWORD szScheme; /* [out] size of scheme (until colon) */ + LPCWSTR pUserName; /* [out] start of Username */ + DWORD szUserName; /* [out] size of Username (until ":" or "@") */ + LPCWSTR pPassword; /* [out] start of Password */ + DWORD szPassword; /* [out] size of Password (until "@") */ + LPCWSTR pHostName; /* [out] start of Hostname */ + DWORD szHostName; /* [out] size of Hostname (until ":" or "/") */ + LPCWSTR pPort; /* [out] start of Port */ + DWORD szPort; /* [out] size of Port (until "/" or eos) */ + LPCWSTR pQuery; /* [out] start of Query */ + DWORD szQuery; /* [out] size of Query (until eos) */ +} WINE_PARSE_URL; + +typedef enum { + SCHEME, + HOST, + PORT, + USERPASS, +} WINE_URL_SCAN_TYPE; + +static const CHAR hexDigits[] = "0123456789ABCDEF"; + +static const WCHAR fileW[] = {'f','i','l','e','\0'}; + +static const unsigned char HashDataLookup[256] = { + 0x01, 0x0E, 0x6E, 0x19, 0x61, 0xAE, 0x84, 0x77, 0x8A, 0xAA, 0x7D, 0x76, 0x1B, + 0xE9, 0x8C, 0x33, 0x57, 0xC5, 0xB1, 0x6B, 0xEA, 0xA9, 0x38, 0x44, 0x1E, 0x07, + 0xAD, 0x49, 0xBC, 0x28, 0x24, 0x41, 0x31, 0xD5, 0x68, 0xBE, 0x39, 0xD3, 0x94, + 0xDF, 0x30, 0x73, 0x0F, 0x02, 0x43, 0xBA, 0xD2, 0x1C, 0x0C, 0xB5, 0x67, 0x46, + 0x16, 0x3A, 0x4B, 0x4E, 0xB7, 0xA7, 0xEE, 0x9D, 0x7C, 0x93, 0xAC, 0x90, 0xB0, + 0xA1, 0x8D, 0x56, 0x3C, 0x42, 0x80, 0x53, 0x9C, 0xF1, 0x4F, 0x2E, 0xA8, 0xC6, + 0x29, 0xFE, 0xB2, 0x55, 0xFD, 0xED, 0xFA, 0x9A, 0x85, 0x58, 0x23, 0xCE, 0x5F, + 0x74, 0xFC, 0xC0, 0x36, 0xDD, 0x66, 0xDA, 0xFF, 0xF0, 0x52, 0x6A, 0x9E, 0xC9, + 0x3D, 0x03, 0x59, 0x09, 0x2A, 0x9B, 0x9F, 0x5D, 0xA6, 0x50, 0x32, 0x22, 0xAF, + 0xC3, 0x64, 0x63, 0x1A, 0x96, 0x10, 0x91, 0x04, 0x21, 0x08, 0xBD, 0x79, 0x40, + 0x4D, 0x48, 0xD0, 0xF5, 0x82, 0x7A, 0x8F, 0x37, 0x69, 0x86, 0x1D, 0xA4, 0xB9, + 0xC2, 0xC1, 0xEF, 0x65, 0xF2, 0x05, 0xAB, 0x7E, 0x0B, 0x4A, 0x3B, 0x89, 0xE4, + 0x6C, 0xBF, 0xE8, 0x8B, 0x06, 0x18, 0x51, 0x14, 0x7F, 0x11, 0x5B, 0x5C, 0xFB, + 0x97, 0xE1, 0xCF, 0x15, 0x62, 0x71, 0x70, 0x54, 0xE2, 0x12, 0xD6, 0xC7, 0xBB, + 0x0D, 0x20, 0x5E, 0xDC, 0xE0, 0xD4, 0xF7, 0xCC, 0xC4, 0x2B, 0xF9, 0xEC, 0x2D, + 0xF4, 0x6F, 0xB6, 0x99, 0x88, 0x81, 0x5A, 0xD9, 0xCA, 0x13, 0xA5, 0xE7, 0x47, + 0xE6, 0x8E, 0x60, 0xE3, 0x3E, 0xB3, 0xF6, 0x72, 0xA2, 0x35, 0xA0, 0xD7, 0xCD, + 0xB4, 0x2F, 0x6D, 0x2C, 0x26, 0x1F, 0x95, 0x87, 0x00, 0xD8, 0x34, 0x3F, 0x17, + 0x25, 0x45, 0x27, 0x75, 0x92, 0xB8, 0xA3, 0xC8, 0xDE, 0xEB, 0xF8, 0xF3, 0xDB, + 0x0A, 0x98, 0x83, 0x7B, 0xE5, 0xCB, 0x4C, 0x78, 0xD1 }; + +static BOOL URL_JustLocation(LPCWSTR str) +{ + while(*str && (*str == L'/')) str++; + if (*str) { + while (*str && ((*str == L'-') || + (*str == L'.') || + isalnumW(*str))) str++; + if (*str == L'/') return FALSE; + } + return TRUE; +} + + +/************************************************************************* + * @ [SHLWAPI.1] + * + * Parse a Url into its constituent parts. + * + * PARAMS + * x [I] Url to parse + * y [O] Undocumented structure holding the parsed information + * + * RETURNS + * Success: S_OK. y contains the parsed Url details. + * Failure: An HRESULT error code. + */ +HRESULT WINAPI ParseURLA(LPCSTR x, PARSEDURLA *y) +{ + DWORD cnt; + const SHL_2_inet_scheme *inet_pro; + + y->nScheme = URL_SCHEME_INVALID; + if (y->cbSize != sizeof(*y)) return E_INVALIDARG; + /* FIXME: leading white space generates error of 0x80041001 which + * is undefined + */ + if (*x <= ' ') return 0x80041001; + cnt = 0; + y->cchProtocol = 0; + y->pszProtocol = x; + while (*x) { + if (*x == ':') { + y->cchProtocol = cnt; + cnt = -1; + y->pszSuffix = x+1; + break; + } + x++; + cnt++; + } + + /* check for no scheme in string start */ + /* (apparently schemes *must* be larger than a single character) */ + if ((*x == '\0') || (y->cchProtocol <= 1)) { + y->pszProtocol = NULL; + return 0x80041001; + } + + /* found scheme, set length of remainder */ + y->cchSuffix = lstrlenA(y->pszSuffix); + + /* see if known scheme and return indicator number */ + y->nScheme = URL_SCHEME_UNKNOWN; + inet_pro = shlwapi_schemes; + while (inet_pro->scheme_name) { + if (!strncasecmp(inet_pro->scheme_name, y->pszProtocol, + min(y->cchProtocol, lstrlenA(inet_pro->scheme_name)))) { + y->nScheme = inet_pro->scheme_number; + break; + } + inet_pro++; + } + return S_OK; +} + +/************************************************************************* + * @ [SHLWAPI.2] + * + * Unicode version of ParseURLA. + */ +HRESULT WINAPI ParseURLW(LPCWSTR x, PARSEDURLW *y) +{ + DWORD cnt; + const SHL_2_inet_scheme *inet_pro; + LPSTR cmpstr; + INT len; + + y->nScheme = URL_SCHEME_INVALID; + if (y->cbSize != sizeof(*y)) return E_INVALIDARG; + /* FIXME: leading white space generates error of 0x80041001 which + * is undefined + */ + if (*x <= L' ') return 0x80041001; + cnt = 0; + y->cchProtocol = 0; + y->pszProtocol = x; + while (*x) { + if (*x == L':') { + y->cchProtocol = cnt; + cnt = -1; + y->pszSuffix = x+1; + break; + } + x++; + cnt++; + } + + /* check for no scheme in string start */ + /* (apparently schemes *must* be larger than a single character) */ + if ((*x == L'\0') || (y->cchProtocol <= 1)) { + y->pszProtocol = NULL; + return 0x80041001; + } + + /* found scheme, set length of remainder */ + y->cchSuffix = lstrlenW(y->pszSuffix); + + /* see if known scheme and return indicator number */ + len = WideCharToMultiByte(0, 0, y->pszProtocol, y->cchProtocol, 0, 0, 0, 0); + cmpstr = HeapAlloc(GetProcessHeap(), 0, len); + WideCharToMultiByte(0, 0, y->pszProtocol, y->cchProtocol, cmpstr, len, 0, 0); + y->nScheme = URL_SCHEME_UNKNOWN; + inet_pro = shlwapi_schemes; + while (inet_pro->scheme_name) { + if (!strncasecmp(inet_pro->scheme_name, cmpstr, + min(len, lstrlenA(inet_pro->scheme_name)))) { + y->nScheme = inet_pro->scheme_number; + break; + } + inet_pro++; + } + HeapFree(GetProcessHeap(), 0, cmpstr); + return S_OK; +} + +/************************************************************************* + * UrlCanonicalizeA [SHLWAPI.@] + * + * Canonicalize a Url. + * + * PARAMS + * pszUrl [I] Url to cCanonicalize + * pszCanonicalized [O] Destination for converted Url. + * pcchCanonicalized [I/O] Length of pszUrl, destination for length of pszCanonicalized + * dwFlags [I] Flags controlling the conversion. + * + * RETURNS + * Success: S_OK. The pszCanonicalized contains the converted Url. + * Failure: E_POINTER, if *pcchCanonicalized is too small. + * + * MSDN incorrectly describes the flags for this function. They should be: + *| URL_DONT_ESCAPE_EXTRA_INFO 0x02000000 + *| URL_ESCAPE_SPACES_ONLY 0x04000000 + *| URL_ESCAPE_PERCENT 0x00001000 + *| URL_ESCAPE_UNSAFE 0x10000000 + *| URL_UNESCAPE 0x10000000 + *| URL_DONT_SIMPLIFY 0x08000000 + *| URL_ESCAPE_SEGMENT_ONLY 0x00002000 + */ +HRESULT WINAPI UrlCanonicalizeA(LPCSTR pszUrl, LPSTR pszCanonicalized, + LPDWORD pcchCanonicalized, DWORD dwFlags) +{ + LPWSTR base, canonical; + DWORD ret, len, len2; + + TRACE("(%s %p %p 0x%08lx) using W version\n", + debugstr_a(pszUrl), pszCanonicalized, + pcchCanonicalized, dwFlags); + + if(!pszUrl || !pszCanonicalized || !pcchCanonicalized) + return E_INVALIDARG; + + base = HeapAlloc(GetProcessHeap(), 0, + (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR)); + canonical = base + INTERNET_MAX_URL_LENGTH; + + MultiByteToWideChar(0, 0, pszUrl, -1, base, INTERNET_MAX_URL_LENGTH); + len = INTERNET_MAX_URL_LENGTH; + + ret = UrlCanonicalizeW(base, canonical, &len, dwFlags); + if (ret != S_OK) { + HeapFree(GetProcessHeap(), 0, base); + return ret; + } + + len2 = WideCharToMultiByte(0, 0, canonical, len, 0, 0, 0, 0); + if (len2 > *pcchCanonicalized) { + *pcchCanonicalized = len; + HeapFree(GetProcessHeap(), 0, base); + return E_POINTER; + } + WideCharToMultiByte(0, 0, canonical, len+1, pszCanonicalized, + *pcchCanonicalized, 0, 0); + *pcchCanonicalized = len2; + HeapFree(GetProcessHeap(), 0, base); + return S_OK; +} + +/************************************************************************* + * UrlCanonicalizeW [SHLWAPI.@] + * + * See UrlCanonicalizeA. + */ +HRESULT WINAPI UrlCanonicalizeW(LPCWSTR pszUrl, LPWSTR pszCanonicalized, + LPDWORD pcchCanonicalized, DWORD dwFlags) +{ + HRESULT hr = S_OK; + DWORD EscapeFlags; + LPWSTR lpszUrlCpy, wk1, wk2, mp, root; + INT nByteLen, state; + DWORD nLen, nWkLen; + + TRACE("(%s %p %p 0x%08lx)\n", debugstr_w(pszUrl), pszCanonicalized, + pcchCanonicalized, dwFlags); + + if(!pszUrl || !pszCanonicalized || !pcchCanonicalized) + return E_INVALIDARG; + + nByteLen = (lstrlenW(pszUrl) + 1) * sizeof(WCHAR); /* length in bytes */ + lpszUrlCpy = HeapAlloc(GetProcessHeap(), 0, nByteLen); + + if (dwFlags & URL_DONT_SIMPLIFY) + memcpy(lpszUrlCpy, pszUrl, nByteLen); + else { + + /* + * state = + * 0 initial 1,3 + * 1 have 2[+] alnum 2,3 + * 2 have scheme (found :) 4,6,3 + * 3 failed (no location) + * 4 have // 5,3 + * 5 have 1[+] alnum 6,3 + * 6 have location (found /) save root location + */ + + wk1 = (LPWSTR)pszUrl; + wk2 = lpszUrlCpy; + state = 0; + while (*wk1) { + switch (state) { + case 0: + if (!isalnumW(*wk1)) {state = 3; break;} + *wk2++ = *wk1++; + if (!isalnumW(*wk1)) {state = 3; break;} + *wk2++ = *wk1++; + state = 1; + break; + case 1: + *wk2++ = *wk1; + if (*wk1++ == L':') state = 2; + break; + case 2: + if (*wk1 != L'/') {state = 3; break;} + *wk2++ = *wk1++; + if (*wk1 != L'/') {state = 6; break;} + *wk2++ = *wk1++; + state = 4; + break; + case 3: + nWkLen = strlenW(wk1); + memcpy(wk2, wk1, (nWkLen + 1) * sizeof(WCHAR)); + wk1 += nWkLen; + wk2 += nWkLen; + break; + case 4: + if (!isalnumW(*wk1) && (*wk1 != L'-') && (*wk1 != L'.')) {state = 3; break;} + while(isalnumW(*wk1) || (*wk1 == L'-') || (*wk1 == L'.')) *wk2++ = *wk1++; + state = 5; + break; + case 5: + if (*wk1 != L'/') {state = 3; break;} + *wk2++ = *wk1++; + state = 6; + break; + case 6: + /* Now at root location, cannot back up any more. */ + /* "root" will point at the '/' */ + root = wk2-1; + while (*wk1) { + TRACE("wk1=%c\n", (CHAR)*wk1); + mp = strchrW(wk1, L'/'); + if (!mp) { + nWkLen = strlenW(wk1); + memcpy(wk2, wk1, (nWkLen + 1) * sizeof(WCHAR)); + wk1 += nWkLen; + wk2 += nWkLen; + continue; + } + nLen = mp - wk1 + 1; + memcpy(wk2, wk1, nLen * sizeof(WCHAR)); + wk2 += nLen; + wk1 += nLen; + if (*wk1 == L'.') { + TRACE("found '/.'\n"); + if (*(wk1+1) == L'/') { + /* case of /./ -> skip the ./ */ + wk1 += 2; + } + else if (*(wk1+1) == L'.') { + /* found /.. look for next / */ + TRACE("found '/..'\n"); + if (*(wk1+2) == L'/' || *(wk1+2) == L'?' || *(wk1+2) == L'#' || *(wk1+2) == 0) { + /* case /../ -> need to backup wk2 */ + TRACE("found '/../'\n"); + *(wk2-1) = L'\0'; /* set end of string */ + mp = strrchrW(root, L'/'); + if (mp && (mp >= root)) { + /* found valid backup point */ + wk2 = mp + 1; + if(*(wk1+2) != L'/') + wk1 += 2; + else + wk1 += 3; + } + else { + /* did not find point, restore '/' */ + *(wk2-1) = L'/'; + } + } + } + } + } + *wk2 = L'\0'; + break; + default: + FIXME("how did we get here - state=%d\n", state); + HeapFree(GetProcessHeap(), 0, lpszUrlCpy); + return E_INVALIDARG; + } + } + *wk2 = L'\0'; + TRACE("Simplified, orig <%s>, simple <%s>\n", + debugstr_w(pszUrl), debugstr_w(lpszUrlCpy)); + } + nLen = lstrlenW(lpszUrlCpy); + while ((nLen > 0) && ((lpszUrlCpy[nLen-1] == '\r')||(lpszUrlCpy[nLen-1] == '\n'))) + lpszUrlCpy[--nLen]=0; + + if(dwFlags & URL_UNESCAPE) + UrlUnescapeW(lpszUrlCpy, NULL, &nLen, URL_UNESCAPE_INPLACE); + + if((EscapeFlags = dwFlags & (URL_ESCAPE_UNSAFE | + URL_ESCAPE_SPACES_ONLY | + URL_ESCAPE_PERCENT | + URL_DONT_ESCAPE_EXTRA_INFO | + URL_ESCAPE_SEGMENT_ONLY ))) { + EscapeFlags &= ~URL_ESCAPE_UNSAFE; + hr = UrlEscapeW(lpszUrlCpy, pszCanonicalized, pcchCanonicalized, + EscapeFlags); + } else { /* No escaping needed, just copy the string */ + nLen = lstrlenW(lpszUrlCpy); + if(nLen < *pcchCanonicalized) + memcpy(pszCanonicalized, lpszUrlCpy, (nLen + 1)*sizeof(WCHAR)); + else { + hr = E_POINTER; + nLen++; + } + *pcchCanonicalized = nLen; + } + + HeapFree(GetProcessHeap(), 0, lpszUrlCpy); + + if (hr == S_OK) + TRACE("result %s\n", debugstr_w(pszCanonicalized)); + + return hr; +} + +/************************************************************************* + * UrlCombineA [SHLWAPI.@] + * + * Combine two Urls. + * + * PARAMS + * pszBase [I] Base Url + * pszRelative [I] Url to combine with pszBase + * pszCombined [O] Destination for combined Url + * pcchCombined [O] Destination for length of pszCombined + * dwFlags [I] URL_ flags from "shlwapi.h" + * + * RETURNS + * Success: S_OK. pszCombined contains the combined Url, pcchCombined + * contains its length. + * Failure: An HRESULT error code indicating the error. + */ +HRESULT WINAPI UrlCombineA(LPCSTR pszBase, LPCSTR pszRelative, + LPSTR pszCombined, LPDWORD pcchCombined, + DWORD dwFlags) +{ + LPWSTR base, relative, combined; + DWORD ret, len, len2; + + TRACE("(base %s, Relative %s, Combine size %ld, flags %08lx) using W version\n", + debugstr_a(pszBase),debugstr_a(pszRelative), + pcchCombined?*pcchCombined:0,dwFlags); + + if(!pszBase || !pszRelative || !pcchCombined) + return E_INVALIDARG; + + base = HeapAlloc(GetProcessHeap(), 0, + (3*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR)); + relative = base + INTERNET_MAX_URL_LENGTH; + combined = relative + INTERNET_MAX_URL_LENGTH; + + MultiByteToWideChar(0, 0, pszBase, -1, base, INTERNET_MAX_URL_LENGTH); + MultiByteToWideChar(0, 0, pszRelative, -1, relative, INTERNET_MAX_URL_LENGTH); + len = *pcchCombined; + + ret = UrlCombineW(base, relative, pszCombined?combined:NULL, &len, dwFlags); + if (ret != S_OK) { + *pcchCombined = len; + HeapFree(GetProcessHeap(), 0, base); + return ret; + } + + len2 = WideCharToMultiByte(0, 0, combined, len, 0, 0, 0, 0); + if (len2 > *pcchCombined) { + *pcchCombined = len2; + HeapFree(GetProcessHeap(), 0, base); + return E_POINTER; + } + WideCharToMultiByte(0, 0, combined, len+1, pszCombined, (*pcchCombined)+1, + 0, 0); + *pcchCombined = len2; + HeapFree(GetProcessHeap(), 0, base); + return S_OK; +} + +/************************************************************************* + * UrlCombineW [SHLWAPI.@] + * + * See UrlCombineA. + */ +HRESULT WINAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative, + LPWSTR pszCombined, LPDWORD pcchCombined, + DWORD dwFlags) +{ + PARSEDURLW base, relative; + DWORD myflags, sizeloc = 0; + DWORD len, res1, res2, process_case = 0; + LPWSTR work, preliminary, mbase, mrelative; + static const WCHAR myfilestr[] = {'f','i','l','e',':','/','/','/','\0'}; + static const WCHAR single_slash[] = {'/','\0'}; + HRESULT ret; + + TRACE("(base %s, Relative %s, Combine size %ld, flags %08lx)\n", + debugstr_w(pszBase),debugstr_w(pszRelative), + pcchCombined?*pcchCombined:0,dwFlags); + + if(!pszBase || !pszRelative || !pcchCombined) + return E_INVALIDARG; + + base.cbSize = sizeof(base); + relative.cbSize = sizeof(relative); + + /* Get space for duplicates of the input and the output */ + preliminary = HeapAlloc(GetProcessHeap(), 0, (3*INTERNET_MAX_URL_LENGTH) * + sizeof(WCHAR)); + mbase = preliminary + INTERNET_MAX_URL_LENGTH; + mrelative = mbase + INTERNET_MAX_URL_LENGTH; + *preliminary = L'\0'; + + /* Canonicalize the base input prior to looking for the scheme */ + myflags = dwFlags & (URL_DONT_SIMPLIFY | URL_UNESCAPE); + len = INTERNET_MAX_URL_LENGTH; + ret = UrlCanonicalizeW(pszBase, mbase, &len, myflags); + + /* Canonicalize the relative input prior to looking for the scheme */ + len = INTERNET_MAX_URL_LENGTH; + ret = UrlCanonicalizeW(pszRelative, mrelative, &len, myflags); + + /* See if the base has a scheme */ + res1 = ParseURLW(mbase, &base); + if (res1) { + /* if pszBase has no scheme, then return pszRelative */ + TRACE("no scheme detected in Base\n"); + process_case = 1; + } + else do { + + /* get size of location field (if it exists) */ + work = (LPWSTR)base.pszSuffix; + sizeloc = 0; + if (*work++ == L'/') { + if (*work++ == L'/') { + /* At this point have start of location and + * it ends at next '/' or end of string. + */ + while(*work && (*work != L'/')) work++; + sizeloc = (DWORD)(work - base.pszSuffix); + } + } + + /* Change .sizep2 to not have the last leaf in it, + * Note: we need to start after the location (if it exists) + */ + work = strrchrW((base.pszSuffix+sizeloc), L'/'); + if (work) { + len = (DWORD)(work - base.pszSuffix + 1); + base.cchSuffix = len; + } + /* + * At this point: + * .pszSuffix points to location (starting with '//') + * .cchSuffix length of location (above) and rest less the last + * leaf (if any) + * sizeloc length of location (above) up to but not including + * the last '/' + */ + + res2 = ParseURLW(mrelative, &relative); + if (res2) { + /* no scheme in pszRelative */ + TRACE("no scheme detected in Relative\n"); + relative.pszSuffix = mrelative; /* case 3,4,5 depends on this */ + relative.cchSuffix = strlenW(mrelative); + if (*pszRelative == L':') { + /* case that is either left alone or uses pszBase */ + if (dwFlags & URL_PLUGGABLE_PROTOCOL) { + process_case = 5; + break; + } + process_case = 1; + break; + } + if (isalnum(*mrelative) && (*(mrelative + 1) == L':')) { + /* case that becomes "file:///" */ + strcpyW(preliminary, myfilestr); + process_case = 1; + break; + } + if ((*mrelative == L'/') && (*(mrelative+1) == L'/')) { + /* pszRelative has location and rest */ + process_case = 3; + break; + } + if (*mrelative == L'/') { + /* case where pszRelative is root to location */ + process_case = 4; + break; + } + process_case = (*base.pszSuffix == L'/') ? 5 : 3; + break; + } + + /* handle cases where pszRelative has scheme */ + if ((base.cchProtocol == relative.cchProtocol) && + (strncmpW(base.pszProtocol, relative.pszProtocol, base.cchProtocol) == 0)) { + + /* since the schemes are the same */ + if ((*relative.pszSuffix == L'/') && (*(relative.pszSuffix+1) == L'/')) { + /* case where pszRelative replaces location and following */ + process_case = 3; + break; + } + if (*relative.pszSuffix == L'/') { + /* case where pszRelative is root to location */ + process_case = 4; + break; + } + /* case where scheme is followed by document path */ + process_case = 5; + break; + } + if ((*relative.pszSuffix == L'/') && (*(relative.pszSuffix+1) == L'/')) { + /* case where pszRelative replaces scheme, location, + * and following and handles PLUGGABLE + */ + process_case = 2; + break; + } + process_case = 1; + break; + } while(FALSE); /* a litte trick to allow easy exit from nested if's */ + + + ret = S_OK; + switch (process_case) { + + case 1: /* + * Return pszRelative appended to what ever is in pszCombined, + * (which may the string "file:///" + */ + strcatW(preliminary, mrelative); + break; + + case 2: /* + * Same as case 1, but if URL_PLUGGABLE_PROTOCOL was specified + * and pszRelative starts with "//", then append a "/" + */ + strcpyW(preliminary, mrelative); + if (!(dwFlags & URL_PLUGGABLE_PROTOCOL) && + URL_JustLocation(relative.pszSuffix)) + strcatW(preliminary, single_slash); + break; + + case 3: /* + * Return the pszBase scheme with pszRelative. Basically + * keeps the scheme and replaces the domain and following. + */ + memcpy(preliminary, base.pszProtocol, (base.cchProtocol + 1)*sizeof(WCHAR)); + work = preliminary + base.cchProtocol + 1; + strcpyW(work, relative.pszSuffix); + if (!(dwFlags & URL_PLUGGABLE_PROTOCOL) && + URL_JustLocation(relative.pszSuffix)) + strcatW(work, single_slash); + break; + + case 4: /* + * Return the pszBase scheme and location but everything + * after the location is pszRelative. (Replace document + * from root on.) + */ + memcpy(preliminary, base.pszProtocol, (base.cchProtocol+1+sizeloc)*sizeof(WCHAR)); + work = preliminary + base.cchProtocol + 1 + sizeloc; + if (dwFlags & URL_PLUGGABLE_PROTOCOL) + *(work++) = L'/'; + strcpyW(work, relative.pszSuffix); + break; + + case 5: /* + * Return the pszBase without its document (if any) and + * append pszRelative after its scheme. + */ + memcpy(preliminary, base.pszProtocol, + (base.cchProtocol+1+base.cchSuffix)*sizeof(WCHAR)); + work = preliminary + base.cchProtocol+1+base.cchSuffix - 1; + if (*work++ != L'/') + *(work++) = L'/'; + strcpyW(work, relative.pszSuffix); + break; + + default: + FIXME("How did we get here????? process_case=%ld\n", process_case); + ret = E_INVALIDARG; + } + + if (ret == S_OK) { + /* Reuse mrelative as temp storage as its already allocated and not needed anymore */ + ret = UrlCanonicalizeW(preliminary, mrelative, pcchCombined, dwFlags); + if(SUCCEEDED(ret) && pszCombined) { + lstrcpyW(pszCombined, mrelative); + } + TRACE("return-%ld len=%ld, %s\n", + process_case, *pcchCombined, debugstr_w(pszCombined)); + } + HeapFree(GetProcessHeap(), 0, preliminary); + return ret; +} + +/************************************************************************* + * UrlEscapeA [SHLWAPI.@] + */ + +HRESULT WINAPI UrlEscapeA( + LPCSTR pszUrl, + LPSTR pszEscaped, + LPDWORD pcchEscaped, + DWORD dwFlags) +{ + WCHAR bufW[INTERNET_MAX_URL_LENGTH]; + WCHAR *escapedW = bufW; + UNICODE_STRING urlW; + HRESULT ret; + DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA; + + if(!RtlCreateUnicodeStringFromAsciiz(&urlW, pszUrl)) + return E_INVALIDARG; + if((ret = UrlEscapeW(urlW.Buffer, escapedW, &lenW, dwFlags)) == E_POINTER) { + escapedW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR)); + ret = UrlEscapeW(urlW.Buffer, escapedW, &lenW, dwFlags); + } + if(ret == S_OK) { + RtlUnicodeToMultiByteSize(&lenA, escapedW, lenW * sizeof(WCHAR)); + if(*pcchEscaped > lenA) { + RtlUnicodeToMultiByteN(pszEscaped, *pcchEscaped - 1, &lenA, escapedW, lenW * sizeof(WCHAR)); + pszEscaped[lenA] = 0; + *pcchEscaped = lenA; + } else { + *pcchEscaped = lenA + 1; + ret = E_POINTER; + } + } + if(escapedW != bufW) HeapFree(GetProcessHeap(), 0, escapedW); + RtlFreeUnicodeString(&urlW); + return ret; +} + +#define WINE_URL_BASH_AS_SLASH 0x01 +#define WINE_URL_COLLAPSE_SLASHES 0x02 +#define WINE_URL_ESCAPE_SLASH 0x04 +#define WINE_URL_ESCAPE_HASH 0x08 +#define WINE_URL_ESCAPE_QUESTION 0x10 +#define WINE_URL_STOP_ON_HASH 0x20 +#define WINE_URL_STOP_ON_QUESTION 0x40 + +static inline BOOL URL_NeedEscapeW(WCHAR ch, DWORD dwFlags, DWORD int_flags) +{ + + if (isalnumW(ch)) + return FALSE; + + if(dwFlags & URL_ESCAPE_SPACES_ONLY) { + if(ch == ' ') + return TRUE; + else + return FALSE; + } + + if ((dwFlags & URL_ESCAPE_PERCENT) && (ch == '%')) + return TRUE; + + if (ch <= 31 || ch >= 127) + return TRUE; + + else { + switch (ch) { + case ' ': + case '<': + case '>': + case '\"': + case '{': + case '}': + case '|': + case '\\': + case '^': + case ']': + case '[': + case '`': + case '&': + return TRUE; + + case '/': + if (int_flags & WINE_URL_ESCAPE_SLASH) return TRUE; + return FALSE; + + case '?': + if (int_flags & WINE_URL_ESCAPE_QUESTION) return TRUE; + return FALSE; + + case '#': + if (int_flags & WINE_URL_ESCAPE_HASH) return TRUE; + return FALSE; + + default: + return FALSE; + } + } +} + + +/************************************************************************* + * UrlEscapeW [SHLWAPI.@] + * + * Converts unsafe characters in a Url into escape sequences. + * + * PARAMS + * pszUrl [I] Url to modify + * pszEscaped [O] Destination for modified Url + * pcchEscaped [I/O] Length of pszUrl, destination for length of pszEscaped + * dwFlags [I] URL_ flags from "shlwapi.h" + * + * RETURNS + * Success: S_OK. pszEscaped contains the escaped Url, pcchEscaped + * contains its length. + * Failure: E_POINTER, if pszEscaped is not large enough. In this case + * pcchEscaped is set to the required length. + * + * Converts unsafe characters into their escape sequences. + * + * NOTES + * - By default this function stops converting at the first '?' or + * '#' character. + * - If dwFlags contains URL_ESCAPE_SPACES_ONLY then only spaces are + * converted, but the conversion continues past a '?' or '#'. + * - Note that this function did not work well (or at all) in shlwapi version 4. + * + * BUGS + * Only the following flags are implemented: + *| URL_ESCAPE_SPACES_ONLY + *| URL_DONT_ESCAPE_EXTRA_INFO + *| URL_ESCAPE_SEGMENT_ONLY + *| URL_ESCAPE_PERCENT + */ +HRESULT WINAPI UrlEscapeW( + LPCWSTR pszUrl, + LPWSTR pszEscaped, + LPDWORD pcchEscaped, + DWORD dwFlags) +{ + LPCWSTR src; + DWORD needed = 0, ret; + BOOL stop_escaping = FALSE; + WCHAR next[5], *dst = pszEscaped; + INT len; + PARSEDURLW parsed_url; + DWORD int_flags; + DWORD slashes = 0; + static const WCHAR localhost[] = {'l','o','c','a','l','h','o','s','t',0}; + + TRACE("(%s %p %p 0x%08lx)\n", debugstr_w(pszUrl), pszEscaped, + pcchEscaped, dwFlags); + + if(!pszUrl || !pszEscaped || !pcchEscaped) + return E_INVALIDARG; + + if(dwFlags & ~(URL_ESCAPE_SPACES_ONLY | + URL_ESCAPE_SEGMENT_ONLY | + URL_DONT_ESCAPE_EXTRA_INFO | + URL_ESCAPE_PERCENT)) + FIXME("Unimplemented flags: %08lx\n", dwFlags); + + /* fix up flags */ + if (dwFlags & URL_ESCAPE_SPACES_ONLY) + /* if SPACES_ONLY specified, reset the other controls */ + dwFlags &= ~(URL_DONT_ESCAPE_EXTRA_INFO | + URL_ESCAPE_PERCENT | + URL_ESCAPE_SEGMENT_ONLY); + + else + /* if SPACES_ONLY *not* specified the assume DONT_ESCAPE_EXTRA_INFO */ + dwFlags |= URL_DONT_ESCAPE_EXTRA_INFO; + + + int_flags = 0; + if(dwFlags & URL_ESCAPE_SEGMENT_ONLY) { + int_flags = WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH | WINE_URL_ESCAPE_SLASH; + } else { + parsed_url.cbSize = sizeof(parsed_url); + if(ParseURLW(pszUrl, &parsed_url) != S_OK) + parsed_url.nScheme = URL_SCHEME_INVALID; + + TRACE("scheme = %d (%s)\n", parsed_url.nScheme, debugstr_wn(parsed_url.pszProtocol, parsed_url.cchProtocol)); + + if(dwFlags & URL_DONT_ESCAPE_EXTRA_INFO) + int_flags = WINE_URL_STOP_ON_HASH | WINE_URL_STOP_ON_QUESTION; + + switch(parsed_url.nScheme) { + case URL_SCHEME_FILE: + int_flags |= WINE_URL_BASH_AS_SLASH | WINE_URL_COLLAPSE_SLASHES | WINE_URL_ESCAPE_HASH; + int_flags &= ~WINE_URL_STOP_ON_HASH; + break; + + case URL_SCHEME_HTTP: + case URL_SCHEME_HTTPS: + int_flags |= WINE_URL_BASH_AS_SLASH; + if(parsed_url.pszSuffix[0] != '/' && parsed_url.pszSuffix[0] != '\\') + int_flags |= WINE_URL_ESCAPE_SLASH; + break; + + case URL_SCHEME_MAILTO: + int_flags |= WINE_URL_ESCAPE_SLASH | WINE_URL_ESCAPE_QUESTION | WINE_URL_ESCAPE_HASH; + int_flags &= ~(WINE_URL_STOP_ON_QUESTION | WINE_URL_STOP_ON_HASH); + break; + + case URL_SCHEME_INVALID: + break; + + case URL_SCHEME_FTP: + default: + if(parsed_url.pszSuffix[0] != '/') + int_flags |= WINE_URL_ESCAPE_SLASH; + break; + } + } + + for(src = pszUrl; *src; ) { + WCHAR cur = *src; + len = 0; + + if((int_flags & WINE_URL_COLLAPSE_SLASHES) && src == pszUrl + parsed_url.cchProtocol + 1) { + int localhost_len = sizeof(localhost)/sizeof(WCHAR) - 1; + while(cur == '/' || cur == '\\') { + slashes++; + cur = *++src; + } + if(slashes == 2 && !strncmpiW(src, localhost, localhost_len)) { /* file://localhost/ -> file:/// */ + if(*(src + localhost_len) == '/' || *(src + localhost_len) == '\\') + src += localhost_len + 1; + slashes = 3; + } + + switch(slashes) { + case 1: + case 3: + next[0] = next[1] = next[2] = '/'; + len = 3; + break; + case 0: + len = 0; + break; + default: + next[0] = next[1] = '/'; + len = 2; + break; + } + } + if(len == 0) { + + if(cur == '#' && (int_flags & WINE_URL_STOP_ON_HASH)) + stop_escaping = TRUE; + + if(cur == '?' && (int_flags & WINE_URL_STOP_ON_QUESTION)) + stop_escaping = TRUE; + + if(cur == '\\' && (int_flags & WINE_URL_BASH_AS_SLASH) && !stop_escaping) cur = '/'; + + if(URL_NeedEscapeW(cur, dwFlags, int_flags) && stop_escaping == FALSE) { + next[0] = L'%'; + next[1] = hexDigits[(cur >> 4) & 0xf]; + next[2] = hexDigits[cur & 0xf]; + len = 3; + } else { + next[0] = cur; + len = 1; + } + src++; + } + + if(needed + len <= *pcchEscaped) { + memcpy(dst, next, len*sizeof(WCHAR)); + dst += len; + } + needed += len; + } + + if(needed < *pcchEscaped) { + *dst = '\0'; + ret = S_OK; + } else { + needed++; /* add one for the '\0' */ + ret = E_POINTER; + } + *pcchEscaped = needed; + return ret; +} + + +/************************************************************************* + * UrlUnescapeA [SHLWAPI.@] + * + * Converts Url escape sequences back to ordinary characters. + * + * PARAMS + * pszUrl [I/O] Url to convert + * pszUnescaped [O] Destination for converted Url + * pcchUnescaped [I/O] Size of output string + * dwFlags [I] URL_ESCAPE_ Flags from "shlwapi.h" + * + * RETURNS + * Success: S_OK. The converted value is in pszUnescaped, or in pszUrl if + * dwFlags includes URL_ESCAPE_INPLACE. + * Failure: E_POINTER if the converted Url is bigger than pcchUnescaped. In + * this case pcchUnescaped is set to the size required. + * NOTES + * If dwFlags includes URL_DONT_ESCAPE_EXTRA_INFO, the conversion stops at + * the first occurrence of either a '?' or '#' character. + */ +HRESULT WINAPI UrlUnescapeA( + LPSTR pszUrl, + LPSTR pszUnescaped, + LPDWORD pcchUnescaped, + DWORD dwFlags) +{ + char *dst, next; + LPCSTR src; + HRESULT ret; + DWORD needed; + BOOL stop_unescaping = FALSE; + + TRACE("(%s, %p, %p, 0x%08lx)\n", debugstr_a(pszUrl), pszUnescaped, + pcchUnescaped, dwFlags); + + if(!pszUrl || !pszUnescaped || !pcchUnescaped) + return E_INVALIDARG; + + if(dwFlags & URL_UNESCAPE_INPLACE) + dst = pszUrl; + else + dst = pszUnescaped; + + for(src = pszUrl, needed = 0; *src; src++, needed++) { + if(dwFlags & URL_DONT_UNESCAPE_EXTRA_INFO && + (*src == '#' || *src == '?')) { + stop_unescaping = TRUE; + next = *src; + } else if(*src == '%' && isxdigit(*(src + 1)) && isxdigit(*(src + 2)) + && stop_unescaping == FALSE) { + INT ih; + char buf[3]; + memcpy(buf, src + 1, 2); + buf[2] = '\0'; + ih = strtol(buf, NULL, 16); + next = (CHAR) ih; + src += 2; /* Advance to end of escape */ + } else + next = *src; + + if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) + *dst++ = next; + } + + if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) { + *dst = '\0'; + ret = S_OK; + } else { + needed++; /* add one for the '\0' */ + ret = E_POINTER; + } + if(!(dwFlags & URL_UNESCAPE_INPLACE)) + *pcchUnescaped = needed; + + if (ret == S_OK) { + TRACE("result %s\n", (dwFlags & URL_UNESCAPE_INPLACE) ? + debugstr_a(pszUrl) : debugstr_a(pszUnescaped)); + } + + return ret; +} + +/************************************************************************* + * UrlUnescapeW [SHLWAPI.@] + * + * See UrlUnescapeA. + */ +HRESULT WINAPI UrlUnescapeW( + LPWSTR pszUrl, + LPWSTR pszUnescaped, + LPDWORD pcchUnescaped, + DWORD dwFlags) +{ + WCHAR *dst, next; + LPCWSTR src; + HRESULT ret; + DWORD needed; + BOOL stop_unescaping = FALSE; + + TRACE("(%s, %p, %p, 0x%08lx)\n", debugstr_w(pszUrl), pszUnescaped, + pcchUnescaped, dwFlags); + + if(!pszUrl || (!pszUnescaped && !(dwFlags & URL_UNESCAPE_INPLACE))|| !pcchUnescaped) + return E_INVALIDARG; + + if(dwFlags & URL_UNESCAPE_INPLACE) + dst = pszUrl; + else + dst = pszUnescaped; + + for(src = pszUrl, needed = 0; *src; src++, needed++) { + if(dwFlags & URL_DONT_UNESCAPE_EXTRA_INFO && + (*src == L'#' || *src == L'?')) { + stop_unescaping = TRUE; + next = *src; + } else if(*src == L'%' && isxdigitW(*(src + 1)) && isxdigitW(*(src + 2)) + && stop_unescaping == FALSE) { + INT ih; + WCHAR buf[5] = {'0','x',0}; + memcpy(buf + 2, src + 1, 2*sizeof(WCHAR)); + buf[4] = 0; + StrToIntExW(buf, STIF_SUPPORT_HEX, &ih); + next = (WCHAR) ih; + src += 2; /* Advance to end of escape */ + } else + next = *src; + + if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) + *dst++ = next; + } + + if(dwFlags & URL_UNESCAPE_INPLACE || needed < *pcchUnescaped) { + *dst = L'\0'; + ret = S_OK; + } else { + needed++; /* add one for the '\0' */ + ret = E_POINTER; + } + if(!(dwFlags & URL_UNESCAPE_INPLACE)) + *pcchUnescaped = needed; + + if (ret == S_OK) { + TRACE("result %s\n", (dwFlags & URL_UNESCAPE_INPLACE) ? + debugstr_w(pszUrl) : debugstr_w(pszUnescaped)); + } + + return ret; +} + +/************************************************************************* + * UrlGetLocationA [SHLWAPI.@] + * + * Get the location from a Url. + * + * PARAMS + * pszUrl [I] Url to get the location from + * + * RETURNS + * A pointer to the start of the location in pszUrl, or NULL if there is + * no location. + * + * NOTES + * - MSDN erroneously states that "The location is the segment of the Url + * starting with a '?' or '#' character". Neither V4 nor V5 of shlwapi.dll + * stop at '?' and always return a NULL in this case. + * - MSDN also erroneously states that "If a file URL has a query string, + * the returned string is the query string". In all tested cases, if the + * Url starts with "fi" then a NULL is returned. V5 gives the following results: + *| Result Url + *| ------ --- + *| NULL file://aa/b/cd#hohoh + *| #hohoh http://aa/b/cd#hohoh + *| NULL fi://aa/b/cd#hohoh + *| #hohoh ff://aa/b/cd#hohoh + */ +LPCSTR WINAPI UrlGetLocationA( + LPCSTR pszUrl) +{ + PARSEDURLA base; + DWORD res1; + + base.cbSize = sizeof(base); + res1 = ParseURLA(pszUrl, &base); + if (res1) return NULL; /* invalid scheme */ + + /* if scheme is file: then never return pointer */ + if (strncmp(base.pszProtocol, "file", min(4,base.cchProtocol)) == 0) return NULL; + + /* Look for '#' and return its addr */ + return strchr(base.pszSuffix, '#'); +} + +/************************************************************************* + * UrlGetLocationW [SHLWAPI.@] + * + * See UrlGetLocationA. + */ +LPCWSTR WINAPI UrlGetLocationW( + LPCWSTR pszUrl) +{ + PARSEDURLW base; + DWORD res1; + + base.cbSize = sizeof(base); + res1 = ParseURLW(pszUrl, &base); + if (res1) return NULL; /* invalid scheme */ + + /* if scheme is file: then never return pointer */ + if (strncmpW(base.pszProtocol, fileW, min(4,base.cchProtocol)) == 0) return NULL; + + /* Look for '#' and return its addr */ + return strchrW(base.pszSuffix, L'#'); +} + +/************************************************************************* + * UrlCompareA [SHLWAPI.@] + * + * Compare two Urls. + * + * PARAMS + * pszUrl1 [I] First Url to compare + * pszUrl2 [I] Url to compare to pszUrl1 + * fIgnoreSlash [I] TRUE = compare only up to a final slash + * + * RETURNS + * less than zero, zero, or greater than zero indicating pszUrl2 is greater + * than, equal to, or less than pszUrl1 respectively. + */ +INT WINAPI UrlCompareA( + LPCSTR pszUrl1, + LPCSTR pszUrl2, + BOOL fIgnoreSlash) +{ + INT ret, len, len1, len2; + + if (!fIgnoreSlash) + return strcmp(pszUrl1, pszUrl2); + len1 = strlen(pszUrl1); + if (pszUrl1[len1-1] == '/') len1--; + len2 = strlen(pszUrl2); + if (pszUrl2[len2-1] == '/') len2--; + if (len1 == len2) + return strncmp(pszUrl1, pszUrl2, len1); + len = min(len1, len2); + ret = strncmp(pszUrl1, pszUrl2, len); + if (ret) return ret; + if (len1 > len2) return 1; + return -1; +} + +/************************************************************************* + * UrlCompareW [SHLWAPI.@] + * + * See UrlCompareA. + */ +INT WINAPI UrlCompareW( + LPCWSTR pszUrl1, + LPCWSTR pszUrl2, + BOOL fIgnoreSlash) +{ + INT ret; + size_t len, len1, len2; + + if (!fIgnoreSlash) + return strcmpW(pszUrl1, pszUrl2); + len1 = strlenW(pszUrl1); + if (pszUrl1[len1-1] == '/') len1--; + len2 = strlenW(pszUrl2); + if (pszUrl2[len2-1] == '/') len2--; + if (len1 == len2) + return strncmpW(pszUrl1, pszUrl2, len1); + len = min(len1, len2); + ret = strncmpW(pszUrl1, pszUrl2, len); + if (ret) return ret; + if (len1 > len2) return 1; + return -1; +} + +/************************************************************************* + * HashData [SHLWAPI.@] + * + * Hash an input block into a variable sized digest. + * + * PARAMS + * lpSrc [I] Input block + * nSrcLen [I] Length of lpSrc + * lpDest [I] Output for hash digest + * nDestLen [I] Length of lpDest + * + * RETURNS + * Success: TRUE. lpDest is filled with the computed hash value. + * Failure: FALSE, if any argument is invalid. + */ +HRESULT WINAPI HashData(LPBYTE lpSrc, DWORD nSrcLen, + LPBYTE lpDest, DWORD nDestLen) +{ + INT srcCount = nSrcLen - 1, destCount = nDestLen - 1; + + if (IsBadReadPtr(lpSrc, nSrcLen) || + IsBadWritePtr(lpDest, nDestLen)) + return E_INVALIDARG; + + while (destCount >= 0) + { + lpDest[destCount] = (destCount & 0xff); + destCount--; + } + + while (srcCount >= 0) + { + destCount = nDestLen - 1; + while (destCount >= 0) + { + lpDest[destCount] = HashDataLookup[lpSrc[srcCount] ^ lpDest[destCount]]; + destCount--; + } + srcCount--; + } + return S_OK; +} + +/************************************************************************* + * UrlHashA [SHLWAPI.@] + * + * Produce a Hash from a Url. + * + * PARAMS + * pszUrl [I] Url to hash + * lpDest [O] Destinationh for hash + * nDestLen [I] Length of lpDest + * + * RETURNS + * Success: S_OK. lpDest is filled with the computed hash value. + * Failure: E_INVALIDARG, if any argument is invalid. + */ +HRESULT WINAPI UrlHashA(LPCSTR pszUrl, unsigned char *lpDest, DWORD nDestLen) +{ + if (IsBadStringPtrA(pszUrl, -1) || IsBadWritePtr(lpDest, nDestLen)) + return E_INVALIDARG; + + HashData((LPSTR)pszUrl, (int)strlen(pszUrl), lpDest, nDestLen); + return S_OK; +} + +/************************************************************************* + * UrlHashW [SHLWAPI.@] + * + * See UrlHashA. + */ +HRESULT WINAPI UrlHashW(LPCWSTR pszUrl, unsigned char *lpDest, DWORD nDestLen) +{ + char szUrl[MAX_PATH]; + + TRACE("(%s,%p,%ld)\n",debugstr_w(pszUrl), lpDest, nDestLen); + + if (IsBadStringPtrW(pszUrl, -1) || IsBadWritePtr(lpDest, nDestLen)) + return E_INVALIDARG; + + /* Win32 hashes the data as an ASCII string, presumably so that both A+W + * return the same digests for the same URL. + */ + WideCharToMultiByte(0, 0, pszUrl, -1, szUrl, MAX_PATH, 0, 0); + HashData((BYTE*)szUrl, (int)strlen(szUrl), lpDest, nDestLen); + return S_OK; +} + +/************************************************************************* + * UrlApplySchemeA [SHLWAPI.@] + * + * Apply a scheme to a Url. + * + * PARAMS + * pszIn [I] Url to apply scheme to + * pszOut [O] Destination for modified Url + * pcchOut [I/O] Length of pszOut/destination for length of pszOut + * dwFlags [I] URL_ flags from "shlwapi.h" + * + * RETURNS + * Success: S_OK: pszOut contains the modified Url, pcchOut contains its length. + * Failure: An HRESULT error code describing the error. + */ +HRESULT WINAPI UrlApplySchemeA(LPCSTR pszIn, LPSTR pszOut, LPDWORD pcchOut, DWORD dwFlags) +{ + LPWSTR in, out; + DWORD ret, len, len2; + + TRACE("(in %s, out size %ld, flags %08lx) using W version\n", + debugstr_a(pszIn), *pcchOut, dwFlags); + + in = HeapAlloc(GetProcessHeap(), 0, + (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR)); + out = in + INTERNET_MAX_URL_LENGTH; + + MultiByteToWideChar(0, 0, pszIn, -1, in, INTERNET_MAX_URL_LENGTH); + len = INTERNET_MAX_URL_LENGTH; + + ret = UrlApplySchemeW(in, out, &len, dwFlags); + if ((ret != S_OK) && (ret != S_FALSE)) { + HeapFree(GetProcessHeap(), 0, in); + return ret; + } + + len2 = WideCharToMultiByte(0, 0, out, len+1, 0, 0, 0, 0); + if (len2 > *pcchOut) { + *pcchOut = len2; + HeapFree(GetProcessHeap(), 0, in); + return E_POINTER; + } + WideCharToMultiByte(0, 0, out, len+1, pszOut, *pcchOut, 0, 0); + *pcchOut = len2; + HeapFree(GetProcessHeap(), 0, in); + return ret; +} + +static HRESULT URL_GuessScheme(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut) +{ + HKEY newkey; + BOOL j; + INT index; + DWORD value_len, data_len, dwType, i; + WCHAR reg_path[MAX_PATH]; + WCHAR value[MAX_PATH], data[MAX_PATH]; + WCHAR Wxx, Wyy; + + MultiByteToWideChar(0, 0, + "Software\\Microsoft\\Windows\\CurrentVersion\\URL\\Prefixes", + -1, reg_path, MAX_PATH); + RegOpenKeyExW(HKEY_LOCAL_MACHINE, reg_path, 0, 1, &newkey); + index = 0; + while(value_len = data_len = MAX_PATH, + RegEnumValueW(newkey, index, value, &value_len, + 0, &dwType, (LPVOID)data, &data_len) == 0) { + TRACE("guess %d %s is %s\n", + index, debugstr_w(value), debugstr_w(data)); + + j = FALSE; + for(i=0; i<value_len; i++) { + Wxx = pszIn[i]; + Wyy = value[i]; + /* remember that TRUE is not-equal */ + j = ChrCmpIW(Wxx, Wyy); + if (j) break; + } + if ((i == value_len) && !j) { + if (strlenW(data) + strlenW(pszIn) + 1 > *pcchOut) { + *pcchOut = strlenW(data) + strlenW(pszIn) + 1; + RegCloseKey(newkey); + return E_POINTER; + } + strcpyW(pszOut, data); + strcatW(pszOut, pszIn); + *pcchOut = strlenW(pszOut); + TRACE("matched and set to %s\n", debugstr_w(pszOut)); + RegCloseKey(newkey); + return S_OK; + } + index++; + } + RegCloseKey(newkey); + return -1; +} + +static HRESULT URL_ApplyDefault(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut) +{ + HKEY newkey; + DWORD data_len, dwType; + WCHAR reg_path[MAX_PATH]; + WCHAR value[MAX_PATH], data[MAX_PATH]; + + /* get and prepend default */ + MultiByteToWideChar(0, 0, + "Software\\Microsoft\\Windows\\CurrentVersion\\URL\\DefaultPrefix", + -1, reg_path, MAX_PATH); + RegOpenKeyExW(HKEY_LOCAL_MACHINE, reg_path, 0, 1, &newkey); + data_len = MAX_PATH; + value[0] = L'@'; + value[1] = L'\0'; + RegQueryValueExW(newkey, value, 0, &dwType, (LPBYTE)data, &data_len); + RegCloseKey(newkey); + if (strlenW(data) + strlenW(pszIn) + 1 > *pcchOut) { + *pcchOut = strlenW(data) + strlenW(pszIn) + 1; + return E_POINTER; + } + strcpyW(pszOut, data); + strcatW(pszOut, pszIn); + *pcchOut = strlenW(pszOut); + TRACE("used default %s\n", debugstr_w(pszOut)); + return S_OK; +} + +/************************************************************************* + * UrlApplySchemeW [SHLWAPI.@] + * + * See UrlApplySchemeA. + */ +HRESULT WINAPI UrlApplySchemeW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, DWORD dwFlags) +{ + PARSEDURLW in_scheme; + DWORD res1; + HRESULT ret; + + TRACE("(in %s, out size %ld, flags %08lx)\n", + debugstr_w(pszIn), *pcchOut, dwFlags); + + if (dwFlags & URL_APPLY_GUESSFILE) { + FIXME("(%s %p %p(%ld) 0x%08lx): stub URL_APPLY_GUESSFILE not implemented\n", + debugstr_w(pszIn), pszOut, pcchOut, *pcchOut, dwFlags); + strcpyW(pszOut, pszIn); + *pcchOut = strlenW(pszOut); + return S_FALSE; + } + + in_scheme.cbSize = sizeof(in_scheme); + /* See if the base has a scheme */ + res1 = ParseURLW(pszIn, &in_scheme); + if (res1) { + /* no scheme in input, need to see if we need to guess */ + if (dwFlags & URL_APPLY_GUESSSCHEME) { + if ((ret = URL_GuessScheme(pszIn, pszOut, pcchOut)) != -1) + return ret; + } + } + else { + /* we have a scheme, see if valid (known scheme) */ + if (in_scheme.nScheme) { + /* have valid scheme, so just copy and exit */ + if (strlenW(pszIn) + 1 > *pcchOut) { + *pcchOut = strlenW(pszIn) + 1; + return E_POINTER; + } + strcpyW(pszOut, pszIn); + *pcchOut = strlenW(pszOut); + TRACE("valid scheme, returing copy\n"); + return S_OK; + } + } + + /* If we are here, then either invalid scheme, + * or no scheme and can't/failed guess. + */ + if ( ( ((res1 == 0) && (dwFlags & URL_APPLY_FORCEAPPLY)) || + ((res1 != 0)) ) && + (dwFlags & URL_APPLY_DEFAULT)) { + /* find and apply default scheme */ + return URL_ApplyDefault(pszIn, pszOut, pcchOut); + } + + /* just copy and give proper return code */ + if (strlenW(pszIn) + 1 > *pcchOut) { + *pcchOut = strlenW(pszIn) + 1; + return E_POINTER; + } + strcpyW(pszOut, pszIn); + *pcchOut = strlenW(pszOut); + TRACE("returning copy, left alone\n"); + return S_FALSE; +} + +/************************************************************************* + * UrlIsA [SHLWAPI.@] + * + * Determine if a Url is of a certain class. + * + * PARAMS + * pszUrl [I] Url to check + * Urlis [I] URLIS_ constant from "shlwapi.h" + * + * RETURNS + * TRUE if pszUrl belongs to the class type in Urlis. + * FALSE Otherwise. + */ +BOOL WINAPI UrlIsA(LPCSTR pszUrl, URLIS Urlis) +{ + PARSEDURLA base; + DWORD res1; + LPCSTR last; + + TRACE("(%s %d)\n", debugstr_a(pszUrl), Urlis); + + switch (Urlis) { + + case URLIS_OPAQUE: + base.cbSize = sizeof(base); + res1 = ParseURLA(pszUrl, &base); + if (res1) return FALSE; /* invalid scheme */ + switch (base.nScheme) + { + case URL_SCHEME_MAILTO: + case URL_SCHEME_SHELL: + case URL_SCHEME_JAVASCRIPT: + case URL_SCHEME_VBSCRIPT: + case URL_SCHEME_ABOUT: + return TRUE; + } + return FALSE; + + case URLIS_FILEURL: + return !StrCmpNA("file:", pszUrl, 5); + + case URLIS_DIRECTORY: + last = pszUrl + strlen(pszUrl) - 1; + return (last >= pszUrl && (*last == '/' || *last == '\\' )); + + case URLIS_URL: + return PathIsURLA(pszUrl); + + case URLIS_NOHISTORY: + case URLIS_APPLIABLE: + case URLIS_HASQUERY: + default: + FIXME("(%s %d): stub\n", debugstr_a(pszUrl), Urlis); + } + return FALSE; +} + +/************************************************************************* + * UrlIsW [SHLWAPI.@] + * + * See UrlIsA. + */ +BOOL WINAPI UrlIsW(LPCWSTR pszUrl, URLIS Urlis) +{ + static const WCHAR stemp[] = { 'f','i','l','e',':',0 }; + PARSEDURLW base; + DWORD res1; + LPCWSTR last; + + TRACE("(%s %d)\n", debugstr_w(pszUrl), Urlis); + + switch (Urlis) { + + case URLIS_OPAQUE: + base.cbSize = sizeof(base); + res1 = ParseURLW(pszUrl, &base); + if (res1) return FALSE; /* invalid scheme */ + switch (base.nScheme) + { + case URL_SCHEME_MAILTO: + case URL_SCHEME_SHELL: + case URL_SCHEME_JAVASCRIPT: + case URL_SCHEME_VBSCRIPT: + case URL_SCHEME_ABOUT: + return TRUE; + } + return FALSE; + + case URLIS_FILEURL: + return !strncmpW(stemp, pszUrl, 5); + + case URLIS_DIRECTORY: + last = pszUrl + strlenW(pszUrl) - 1; + return (last >= pszUrl && (*last == '/' || *last == '\\')); + + case URLIS_URL: + return PathIsURLW(pszUrl); + + case URLIS_NOHISTORY: + case URLIS_APPLIABLE: + case URLIS_HASQUERY: + default: + FIXME("(%s %d): stub\n", debugstr_w(pszUrl), Urlis); + } + return FALSE; +} + +/************************************************************************* + * UrlIsNoHistoryA [SHLWAPI.@] + * + * Determine if a Url should not be stored in the users history list. + * + * PARAMS + * pszUrl [I] Url to check + * + * RETURNS + * TRUE, if pszUrl should be excluded from the history list, + * FALSE otherwise. + */ +BOOL WINAPI UrlIsNoHistoryA(LPCSTR pszUrl) +{ + return UrlIsA(pszUrl, URLIS_NOHISTORY); +} + +/************************************************************************* + * UrlIsNoHistoryW [SHLWAPI.@] + * + * See UrlIsNoHistoryA. + */ +BOOL WINAPI UrlIsNoHistoryW(LPCWSTR pszUrl) +{ + return UrlIsW(pszUrl, URLIS_NOHISTORY); +} + +/************************************************************************* + * UrlIsOpaqueA [SHLWAPI.@] + * + * Determine if a Url is opaque. + * + * PARAMS + * pszUrl [I] Url to check + * + * RETURNS + * TRUE if pszUrl is opaque, + * FALSE Otherwise. + * + * NOTES + * An opaque Url is one that does not start with "<protocol>://". + */ +BOOL WINAPI UrlIsOpaqueA(LPCSTR pszUrl) +{ + return UrlIsA(pszUrl, URLIS_OPAQUE); +} + +/************************************************************************* + * UrlIsOpaqueW [SHLWAPI.@] + * + * See UrlIsOpaqueA. + */ +BOOL WINAPI UrlIsOpaqueW(LPCWSTR pszUrl) +{ + return UrlIsW(pszUrl, URLIS_OPAQUE); +} + +/************************************************************************* + * Scans for characters of type "type" and when not matching found, + * returns pointer to it and length in size. + * + * Characters tested based on RFC 1738 + */ +static LPCWSTR URL_ScanID(LPCWSTR start, LPDWORD size, WINE_URL_SCAN_TYPE type) +{ + static DWORD alwayszero = 0; + BOOL cont = TRUE; + + *size = 0; + + switch(type){ + + case SCHEME: + while (cont) { + if ( (islowerW(*start) && isalphaW(*start)) || + isdigitW(*start) || + (*start == L'+') || + (*start == L'-') || + (*start == L'.')) { + start++; + (*size)++; + } + else + cont = FALSE; + } + break; + + case USERPASS: + while (cont) { + if ( isalphaW(*start) || + isdigitW(*start) || + /* user/password only characters */ + (*start == L';') || + (*start == L'?') || + (*start == L'&') || + (*start == L'=') || + /* *extra* characters */ + (*start == L'!') || + (*start == L'*') || + (*start == L'\'') || + (*start == L'(') || + (*start == L')') || + (*start == L',') || + /* *safe* characters */ + (*start == L'$') || + (*start == L'_') || + (*start == L'+') || + (*start == L'-') || + (*start == L'.')) { + start++; + (*size)++; + } else if (*start == L'%') { + if (isxdigitW(*(start+1)) && + isxdigitW(*(start+2))) { + start += 3; + *size += 3; + } else + cont = FALSE; + } else + cont = FALSE; + } + break; + + case PORT: + while (cont) { + if (isdigitW(*start)) { + start++; + (*size)++; + } + else + cont = FALSE; + } + break; + + case HOST: + while (cont) { + if (isalnumW(*start) || + (*start == L'-') || + (*start == L'.') ) { + start++; + (*size)++; + } + else + cont = FALSE; + } + break; + default: + FIXME("unknown type %d\n", type); + return (LPWSTR)&alwayszero; + } + /* TRACE("scanned %ld characters next char %p<%c>\n", + *size, start, *start); */ + return start; +} + +/************************************************************************* + * Attempt to parse URL into pieces. + */ +static LONG URL_ParseUrl(LPCWSTR pszUrl, WINE_PARSE_URL *pl) +{ + LPCWSTR work; + + memset(pl, 0, sizeof(WINE_PARSE_URL)); + pl->pScheme = pszUrl; + work = URL_ScanID(pl->pScheme, &pl->szScheme, SCHEME); + if (!*work || (*work != L':')) goto ErrorExit; + work++; + if ((*work != L'/') || (*(work+1) != L'/')) goto ErrorExit; + pl->pUserName = work + 2; + work = URL_ScanID(pl->pUserName, &pl->szUserName, USERPASS); + if (*work == L':' ) { + /* parse password */ + work++; + pl->pPassword = work; + work = URL_ScanID(pl->pPassword, &pl->szPassword, USERPASS); + if (*work != L'@') { + /* what we just parsed must be the hostname and port + * so reset pointers and clear then let it parse */ + pl->szUserName = pl->szPassword = 0; + work = pl->pUserName - 1; + pl->pUserName = pl->pPassword = 0; + } + } else if (*work == L'@') { + /* no password */ + pl->szPassword = 0; + pl->pPassword = 0; + } else if (!*work || (*work == L'/') || (*work == L'.')) { + /* what was parsed was hostname, so reset pointers and let it parse */ + pl->szUserName = pl->szPassword = 0; + work = pl->pUserName - 1; + pl->pUserName = pl->pPassword = 0; + } else goto ErrorExit; + + /* now start parsing hostname or hostnumber */ + work++; + pl->pHostName = work; + work = URL_ScanID(pl->pHostName, &pl->szHostName, HOST); + if (*work == L':') { + /* parse port */ + work++; + pl->pPort = work; + work = URL_ScanID(pl->pPort, &pl->szPort, PORT); + } + if (*work == L'/') { + /* see if query string */ + pl->pQuery = strchrW(work, L'?'); + if (pl->pQuery) pl->szQuery = strlenW(pl->pQuery); + } + TRACE("parse successful: scheme=%p(%ld), user=%p(%ld), pass=%p(%ld), host=%p(%ld), port=%p(%ld), query=%p(%ld)\n", + pl->pScheme, pl->szScheme, + pl->pUserName, pl->szUserName, + pl->pPassword, pl->szPassword, + pl->pHostName, pl->szHostName, + pl->pPort, pl->szPort, + pl->pQuery, pl->szQuery); + return S_OK; + ErrorExit: + FIXME("failed to parse %s\n", debugstr_w(pszUrl)); + return E_INVALIDARG; +} + +/************************************************************************* + * UrlGetPartA [SHLWAPI.@] + * + * Retrieve part of a Url. + * + * PARAMS + * pszIn [I] Url to parse + * pszOut [O] Destination for part of pszIn requested + * pcchOut [I] Size of pszOut + * [O] length of pszOut string EXLUDING '\0' if S_OK, otherwise + * needed size of pszOut INCLUDING '\0'. + * dwPart [I] URL_PART_ enum from "shlwapi.h" + * dwFlags [I] URL_ flags from "shlwapi.h" + * + * RETURNS + * Success: S_OK. pszOut contains the part requested, pcchOut contains its length. + * Failure: An HRESULT error code describing the error. + */ +HRESULT WINAPI UrlGetPartA(LPCSTR pszIn, LPSTR pszOut, LPDWORD pcchOut, + DWORD dwPart, DWORD dwFlags) +{ + LPWSTR in, out; + DWORD ret, len, len2; + + in = HeapAlloc(GetProcessHeap(), 0, + (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR)); + out = in + INTERNET_MAX_URL_LENGTH; + + MultiByteToWideChar(0, 0, pszIn, -1, in, INTERNET_MAX_URL_LENGTH); + + len = INTERNET_MAX_URL_LENGTH; + ret = UrlGetPartW(in, out, &len, dwPart, dwFlags); + + if (ret != S_OK) { + HeapFree(GetProcessHeap(), 0, in); + return ret; + } + + len2 = WideCharToMultiByte(0, 0, out, len, 0, 0, 0, 0); + if (len2 > *pcchOut) { + *pcchOut = len2; + HeapFree(GetProcessHeap(), 0, in); + return E_POINTER; + } + WideCharToMultiByte(0, 0, out, len+1, pszOut, *pcchOut, 0, 0); + *pcchOut = len2; + HeapFree(GetProcessHeap(), 0, in); + return S_OK; +} + +/************************************************************************* + * UrlGetPartW [SHLWAPI.@] + * + * See UrlGetPartA. + */ +HRESULT WINAPI UrlGetPartW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, + DWORD dwPart, DWORD dwFlags) +{ + WINE_PARSE_URL pl; + HRESULT ret; + DWORD size, schsize; + LPCWSTR addr, schaddr; + + TRACE("(%s %p %p(%ld) %08lx %08lx)\n", + debugstr_w(pszIn), pszOut, pcchOut, *pcchOut, dwPart, dwFlags); + + ret = URL_ParseUrl(pszIn, &pl); + if (!ret) { + schaddr = pl.pScheme; + schsize = pl.szScheme; + + switch (dwPart) { + case URL_PART_SCHEME: + if (!pl.szScheme) return E_INVALIDARG; + addr = pl.pScheme; + size = pl.szScheme; + break; + + case URL_PART_HOSTNAME: + if (!pl.szHostName) return E_INVALIDARG; + addr = pl.pHostName; + size = pl.szHostName; + break; + + case URL_PART_USERNAME: + if (!pl.szUserName) return E_INVALIDARG; + addr = pl.pUserName; + size = pl.szUserName; + break; + + case URL_PART_PASSWORD: + if (!pl.szPassword) return E_INVALIDARG; + addr = pl.pPassword; + size = pl.szPassword; + break; + + case URL_PART_PORT: + if (!pl.szPort) return E_INVALIDARG; + addr = pl.pPort; + size = pl.szPort; + break; + + case URL_PART_QUERY: + if (!pl.szQuery) return E_INVALIDARG; + addr = pl.pQuery; + size = pl.szQuery; + break; + + default: + return E_INVALIDARG; + } + + if (dwFlags == URL_PARTFLAG_KEEPSCHEME) { + if (*pcchOut < schsize + size + 2) { + *pcchOut = schsize + size + 2; + return E_POINTER; + } + memcpy(pszOut, schaddr, schsize*sizeof(WCHAR)); + pszOut[schsize] = ':'; + memcpy(pszOut+schsize+1, addr, size*sizeof(WCHAR)); + pszOut[schsize+1+size] = 0; + *pcchOut = schsize + 1 + size; + } + else { + if (*pcchOut < size + 1) {*pcchOut = size+1; return E_POINTER;} + memcpy(pszOut, addr, size*sizeof(WCHAR)); + pszOut[size] = 0; + *pcchOut = size; + } + TRACE("len=%ld %s\n", *pcchOut, debugstr_w(pszOut)); + } + return ret; +} + +/************************************************************************* + * PathIsURLA [SHLWAPI.@] + * + * Check if the given path is a Url. + * + * PARAMS + * lpszPath [I] Path to check. + * + * RETURNS + * TRUE if lpszPath is a Url. + * FALSE if lpszPath is NULL or not a Url. + */ +BOOL WINAPI PathIsURLA(LPCSTR lpstrPath) +{ + PARSEDURLA base; + DWORD res1; + + if (!lpstrPath || !*lpstrPath) return FALSE; + + /* get protocol */ + base.cbSize = sizeof(base); + res1 = ParseURLA(lpstrPath, &base); + return (base.nScheme != URL_SCHEME_INVALID); +} + +/************************************************************************* + * PathIsURLW [SHLWAPI.@] + * + * See PathIsURLA. + */ +BOOL WINAPI PathIsURLW(LPCWSTR lpstrPath) +{ + PARSEDURLW base; + DWORD res1; + + if (!lpstrPath || !*lpstrPath) return FALSE; + + /* get protocol */ + base.cbSize = sizeof(base); + res1 = ParseURLW(lpstrPath, &base); + return (base.nScheme != URL_SCHEME_INVALID); +} + +/************************************************************************* + * UrlCreateFromPathA [SHLWAPI.@] + * + * See UrlCreateFromPathW + */ +HRESULT WINAPI UrlCreateFromPathA(LPCSTR pszPath, LPSTR pszUrl, LPDWORD pcchUrl, DWORD dwReserved) +{ + WCHAR bufW[INTERNET_MAX_URL_LENGTH]; + WCHAR *urlW = bufW; + UNICODE_STRING pathW; + HRESULT ret; + DWORD lenW = sizeof(bufW)/sizeof(WCHAR), lenA; + + if(!RtlCreateUnicodeStringFromAsciiz(&pathW, pszPath)) + return E_INVALIDARG; + if((ret = UrlCreateFromPathW(pathW.Buffer, urlW, &lenW, dwReserved)) == E_POINTER) { + urlW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR)); + ret = UrlCreateFromPathW(pathW.Buffer, urlW, &lenW, dwReserved); + } + if(ret == S_OK || ret == S_FALSE) { + RtlUnicodeToMultiByteSize(&lenA, urlW, lenW * sizeof(WCHAR)); + if(*pcchUrl > lenA) { + RtlUnicodeToMultiByteN(pszUrl, *pcchUrl - 1, &lenA, urlW, lenW * sizeof(WCHAR)); + pszUrl[lenA] = 0; + *pcchUrl = lenA; + } else { + *pcchUrl = lenA + 1; + ret = E_POINTER; + } + } + if(urlW != bufW) HeapFree(GetProcessHeap(), 0, urlW); + RtlFreeUnicodeString(&pathW); + return ret; +} + +/************************************************************************* + * UrlCreateFromPathW [SHLWAPI.@] + * + * Create a Url from a file path. + * + * PARAMS + * pszPath [I] Path to convert + * pszUrl [O] Destination for the converted Url + * pcchUrl [I/O] Length of pszUrl + * dwReserved [I] Reserved, must be 0 + * + * RETURNS + * Success: S_OK pszUrl contains the converted path, S_FALSE if the path is already a Url + * Failure: An HRESULT error code. + */ +HRESULT WINAPI UrlCreateFromPathW(LPCWSTR pszPath, LPWSTR pszUrl, LPDWORD pcchUrl, DWORD dwReserved) +{ + DWORD needed; + HRESULT ret; + WCHAR *pszNewUrl; + WCHAR file_colonW[] = {'f','i','l','e',':',0}; + WCHAR three_slashesW[] = {'/','/','/',0}; + PARSEDURLW parsed_url; + + TRACE("(%s, %p, %p, 0x%08lx)\n", debugstr_w(pszPath), pszUrl, pcchUrl, dwReserved); + + /* Validate arguments */ + if (dwReserved != 0) + return E_INVALIDARG; + if (!pszUrl || !pcchUrl) + return E_INVALIDARG; + + + parsed_url.cbSize = sizeof(parsed_url); + if(ParseURLW(pszPath, &parsed_url) == S_OK) { + if(parsed_url.nScheme != URL_SCHEME_INVALID && parsed_url.cchProtocol > 1) { + needed = strlenW(pszPath); + if (needed >= *pcchUrl) { + *pcchUrl = needed + 1; + return E_POINTER; + } else { + *pcchUrl = needed; + strcpyW(pszUrl, pszPath); + return S_FALSE; + } + } + } + + pszNewUrl = HeapAlloc(GetProcessHeap(), 0, (strlenW(pszPath) + 9) * sizeof(WCHAR)); /* "file:///" + pszPath_len + 1 */ + strcpyW(pszNewUrl, file_colonW); + if(isalphaW(pszPath[0]) && pszPath[1] == ':') + strcatW(pszNewUrl, three_slashesW); + strcatW(pszNewUrl, pszPath); + ret = UrlEscapeW(pszNewUrl, pszUrl, pcchUrl, URL_ESCAPE_PERCENT); + + HeapFree(GetProcessHeap(), 0, pszNewUrl); + return ret; +} + +/************************************************************************* + * SHAutoComplete [SHLWAPI.@] + * + * Enable auto-completion for an edit control. + * + * PARAMS + * hwndEdit [I] Handle of control to enable auto-completion for + * dwFlags [I] SHACF_ flags from "shlwapi.h" + * + * RETURNS + * Success: S_OK. Auto-completion is enabled for the control. + * Failure: An HRESULT error code indicating the error. + */ +HRESULT WINAPI SHAutoComplete(HWND hwndEdit, DWORD dwFlags) +{ + FIXME("SHAutoComplete stub\n"); + return S_FALSE; +} + +/************************************************************************* + * MLBuildResURLA [SHLWAPI.405] + * + * Create a Url pointing to a resource in a module. + * + * PARAMS + * lpszLibName [I] Name of the module containing the resource + * hMod [I] Callers module handle + * dwFlags [I] Undocumented flags for loading the module + * lpszRes [I] Resource name + * lpszDest [O] Destination for resulting Url + * dwDestLen [I] Length of lpszDest + * + * RETURNS + * Success: S_OK. lpszDest constains the resource Url. + * Failure: E_INVALIDARG, if any argument is invalid, or + * E_FAIL if dwDestLen is too small. + */ +HRESULT WINAPI MLBuildResURLA(LPCSTR lpszLibName, HMODULE hMod, DWORD dwFlags, + LPCSTR lpszRes, LPSTR lpszDest, DWORD dwDestLen) +{ + WCHAR szLibName[MAX_PATH], szRes[MAX_PATH], szDest[MAX_PATH]; + HRESULT hRet; + + if (lpszLibName) + MultiByteToWideChar(CP_ACP, 0, lpszLibName, -1, szLibName, sizeof(szLibName)/sizeof(WCHAR)); + + if (lpszRes) + MultiByteToWideChar(CP_ACP, 0, lpszRes, -1, szRes, sizeof(szRes)/sizeof(WCHAR)); + + if (dwDestLen > sizeof(szLibName)/sizeof(WCHAR)) + dwDestLen = sizeof(szLibName)/sizeof(WCHAR); + + hRet = MLBuildResURLW(lpszLibName ? szLibName : NULL, hMod, dwFlags, + lpszRes ? szRes : NULL, lpszDest ? szDest : NULL, dwDestLen); + if (SUCCEEDED(hRet) && lpszDest) + WideCharToMultiByte(CP_ACP, 0, szDest, -1, lpszDest, dwDestLen, 0, 0); + + return hRet; +} + +/************************************************************************* + * MLBuildResURLA [SHLWAPI.406] + * + * See MLBuildResURLA. + */ +HRESULT WINAPI MLBuildResURLW(LPCWSTR lpszLibName, HMODULE hMod, DWORD dwFlags, + LPCWSTR lpszRes, LPWSTR lpszDest, DWORD dwDestLen) +{ + static const WCHAR szRes[] = { 'r','e','s',':','/','/','\0' }; +#define szResLen ((sizeof(szRes) - sizeof(WCHAR))/sizeof(WCHAR)) + HRESULT hRet = E_FAIL; + + TRACE("(%s,%p,0x%08lx,%s,%p,%ld)\n", debugstr_w(lpszLibName), hMod, dwFlags, + debugstr_w(lpszRes), lpszDest, dwDestLen); + + if (!lpszLibName || !hMod || hMod == INVALID_HANDLE_VALUE || !lpszRes || + !lpszDest || (dwFlags && dwFlags != 2)) + return E_INVALIDARG; + + if (dwDestLen >= szResLen + 1) + { + dwDestLen -= (szResLen + 1); + memcpy(lpszDest, szRes, sizeof(szRes)); + + hMod = MLLoadLibraryW(lpszLibName, hMod, dwFlags); + + if (hMod) + { + WCHAR szBuff[MAX_PATH]; + DWORD len; + + len = GetModuleFileNameW(hMod, szBuff, sizeof(szBuff)/sizeof(WCHAR)); + if (len && len < sizeof(szBuff)/sizeof(WCHAR)) + { + DWORD dwPathLen = strlenW(szBuff) + 1; + + if (dwDestLen >= dwPathLen) + { + DWORD dwResLen; + + dwDestLen -= dwPathLen; + memcpy(lpszDest + szResLen, szBuff, dwPathLen * sizeof(WCHAR)); + + dwResLen = strlenW(lpszRes) + 1; + if (dwDestLen >= dwResLen + 1) + { + lpszDest[szResLen + dwPathLen + dwResLen] = '/'; + memcpy(lpszDest + szResLen + dwPathLen, lpszRes, dwResLen * sizeof(WCHAR)); + hRet = S_OK; + } + } + } + MLFreeLibrary(hMod); + } + } + return hRet; +} diff --git a/reactos/lib/shlwapi/wsprintf.c b/reactos/lib/shlwapi/wsprintf.c index 61fb5effc39..e198e8ddf6e 100644 --- a/reactos/lib/shlwapi/wsprintf.c +++ b/reactos/lib/shlwapi/wsprintf.c @@ -1,531 +1,531 @@ -/* - * wsprintf functions - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * NOTE: - * This code is duplicated in user32. If you change something here make sure - * to change it in user32 too. - */ - -#include <stdarg.h> -#include <string.h> -#include <stdio.h> - -#include "windef.h" -#include "winbase.h" -#define NO_SHLWAPI_REG -#include "shlwapi.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(string); - - -#define WPRINTF_LEFTALIGN 0x0001 /* Align output on the left ('-' prefix) */ -#define WPRINTF_PREFIX_HEX 0x0002 /* Prefix hex with 0x ('#' prefix) */ -#define WPRINTF_ZEROPAD 0x0004 /* Pad with zeros ('0' prefix) */ -#define WPRINTF_LONG 0x0008 /* Long arg ('l' prefix) */ -#define WPRINTF_SHORT 0x0010 /* Short arg ('h' prefix) */ -#define WPRINTF_UPPER_HEX 0x0020 /* Upper-case hex ('X' specifier) */ -#define WPRINTF_WIDE 0x0040 /* Wide arg ('w' prefix) */ - -typedef enum -{ - WPR_UNKNOWN, - WPR_CHAR, - WPR_WCHAR, - WPR_STRING, - WPR_WSTRING, - WPR_SIGNED, - WPR_UNSIGNED, - WPR_HEXA -} WPRINTF_TYPE; - -typedef struct -{ - UINT flags; - UINT width; - UINT precision; - WPRINTF_TYPE type; -} WPRINTF_FORMAT; - -typedef union { - WCHAR wchar_view; - CHAR char_view; - LPCSTR lpcstr_view; - LPCWSTR lpcwstr_view; - INT int_view; -} WPRINTF_DATA; - -static const CHAR null_stringA[] = "(null)"; -static const WCHAR null_stringW[] = { '(', 'n', 'u', 'l', 'l', ')', 0 }; - -/*********************************************************************** - * WPRINTF_ParseFormatA - * - * Parse a format specification. A format specification has the form: - * - * [-][#][0][width][.precision]type - * - * Return value is the length of the format specification in characters. - */ -static INT WPRINTF_ParseFormatA( LPCSTR format, WPRINTF_FORMAT *res ) -{ - LPCSTR p = format; - - res->flags = 0; - res->width = 0; - res->precision = 0; - if (*p == '-') { res->flags |= WPRINTF_LEFTALIGN; p++; } - if (*p == '#') { res->flags |= WPRINTF_PREFIX_HEX; p++; } - if (*p == '0') { res->flags |= WPRINTF_ZEROPAD; p++; } - while ((*p >= '0') && (*p <= '9')) /* width field */ - { - res->width = res->width * 10 + *p - '0'; - p++; - } - if (*p == '.') /* precision field */ - { - p++; - while ((*p >= '0') && (*p <= '9')) - { - res->precision = res->precision * 10 + *p - '0'; - p++; - } - } - if (*p == 'l') { res->flags |= WPRINTF_LONG; p++; } - else if (*p == 'h') { res->flags |= WPRINTF_SHORT; p++; } - else if (*p == 'w') { res->flags |= WPRINTF_WIDE; p++; } - switch(*p) - { - case 'c': - res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR; - break; - case 'C': - res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR; - break; - case 'd': - case 'i': - res->type = WPR_SIGNED; - break; - case 's': - res->type = (res->flags & (WPRINTF_LONG |WPRINTF_WIDE)) ? WPR_WSTRING : WPR_STRING; - break; - case 'S': - res->type = (res->flags & (WPRINTF_SHORT|WPRINTF_WIDE)) ? WPR_STRING : WPR_WSTRING; - break; - case 'u': - res->type = WPR_UNSIGNED; - break; - case 'X': - res->flags |= WPRINTF_UPPER_HEX; - /* fall through */ - case 'x': - res->type = WPR_HEXA; - break; - default: /* unknown format char */ - res->type = WPR_UNKNOWN; - p--; /* print format as normal char */ - break; - } - return (INT)(p - format) + 1; -} - - -/*********************************************************************** - * WPRINTF_ParseFormatW - * - * Parse a format specification. A format specification has the form: - * - * [-][#][0][width][.precision]type - * - * Return value is the length of the format specification in characters. - */ -static INT WPRINTF_ParseFormatW( LPCWSTR format, WPRINTF_FORMAT *res ) -{ - LPCWSTR p = format; - - res->flags = 0; - res->width = 0; - res->precision = 0; - if (*p == '-') { res->flags |= WPRINTF_LEFTALIGN; p++; } - if (*p == '#') { res->flags |= WPRINTF_PREFIX_HEX; p++; } - if (*p == '0') { res->flags |= WPRINTF_ZEROPAD; p++; } - while ((*p >= '0') && (*p <= '9')) /* width field */ - { - res->width = res->width * 10 + *p - '0'; - p++; - } - if (*p == '.') /* precision field */ - { - p++; - while ((*p >= '0') && (*p <= '9')) - { - res->precision = res->precision * 10 + *p - '0'; - p++; - } - } - if (*p == 'l') { res->flags |= WPRINTF_LONG; p++; } - else if (*p == 'h') { res->flags |= WPRINTF_SHORT; p++; } - else if (*p == 'w') { res->flags |= WPRINTF_WIDE; p++; } - switch((CHAR)*p) - { - case 'c': - res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR; - break; - case 'C': - res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR; - break; - case 'd': - case 'i': - res->type = WPR_SIGNED; - break; - case 's': - res->type = ((res->flags & WPRINTF_SHORT) && !(res->flags & WPRINTF_WIDE)) ? WPR_STRING : WPR_WSTRING; - break; - case 'S': - res->type = (res->flags & (WPRINTF_LONG|WPRINTF_WIDE)) ? WPR_WSTRING : WPR_STRING; - break; - case 'u': - res->type = WPR_UNSIGNED; - break; - case 'X': - res->flags |= WPRINTF_UPPER_HEX; - /* fall through */ - case 'x': - res->type = WPR_HEXA; - break; - default: - res->type = WPR_UNKNOWN; - p--; /* print format as normal char */ - break; - } - return (INT)(p - format) + 1; -} - - -/*********************************************************************** - * WPRINTF_GetLen - */ -static UINT WPRINTF_GetLen( WPRINTF_FORMAT *format, WPRINTF_DATA *arg, - LPSTR number, UINT maxlen ) -{ - UINT len; - - if (format->flags & WPRINTF_LEFTALIGN) format->flags &= ~WPRINTF_ZEROPAD; - if (format->width > maxlen) format->width = maxlen; - switch(format->type) - { - case WPR_CHAR: - case WPR_WCHAR: - return (format->precision = 1); - case WPR_STRING: - if (!arg->lpcstr_view) arg->lpcstr_view = null_stringA; - for (len = 0; !format->precision || (len < format->precision); len++) - if (!*(arg->lpcstr_view + len)) break; - if (len > maxlen) len = maxlen; - return (format->precision = len); - case WPR_WSTRING: - if (!arg->lpcwstr_view) arg->lpcwstr_view = null_stringW; - for (len = 0; !format->precision || (len < format->precision); len++) - if (!*(arg->lpcwstr_view + len)) break; - if (len > maxlen) len = maxlen; - return (format->precision = len); - case WPR_SIGNED: - len = sprintf( number, "%d", arg->int_view ); - break; - case WPR_UNSIGNED: - len = sprintf( number, "%u", (UINT)arg->int_view ); - break; - case WPR_HEXA: - len = sprintf( number, - (format->flags & WPRINTF_UPPER_HEX) ? "%X" : "%x", - (UINT)arg->int_view); - break; - default: - return 0; - } - if (len > maxlen) len = maxlen; - if (format->precision < len) format->precision = len; - if (format->precision > maxlen) format->precision = maxlen; - if ((format->flags & WPRINTF_ZEROPAD) && (format->width > format->precision)) - format->precision = format->width; - if (format->flags & WPRINTF_PREFIX_HEX) len += 2; - return len; -} - - -/*********************************************************************** - * wvnsprintfA (SHLWAPI.@) - * - * Print formatted output to a string, up to a maximum number of chars. - * - * PARAMS - * buffer [O] Destination for output string - * maxlen [I] Maximum number of characters to write - * spec [I] Format string - * - * RETURNS - * Success: The number of characters written. - * Failure: -1. - */ -INT WINAPI wvnsprintfA( LPSTR buffer, INT maxlen, LPCSTR spec, va_list args ) -{ - WPRINTF_FORMAT format; - LPSTR p = buffer; - UINT i, len, sign; - CHAR number[20]; - WPRINTF_DATA argData; - - TRACE("%p %u %s\n", buffer, maxlen, debugstr_a(spec)); - - while (*spec && (maxlen > 1)) - { - if (*spec != '%') { *p++ = *spec++; maxlen--; continue; } - spec++; - if (*spec == '%') { *p++ = *spec++; maxlen--; continue; } - spec += WPRINTF_ParseFormatA( spec, &format ); - - switch(format.type) - { - case WPR_WCHAR: - argData.wchar_view = (WCHAR)va_arg( args, int ); - break; - case WPR_CHAR: - argData.char_view = (CHAR)va_arg( args, int ); - break; - case WPR_STRING: - argData.lpcstr_view = va_arg( args, LPCSTR ); - break; - case WPR_WSTRING: - argData.lpcwstr_view = va_arg( args, LPCWSTR ); - break; - case WPR_HEXA: - case WPR_SIGNED: - case WPR_UNSIGNED: - argData.int_view = va_arg( args, INT ); - break; - default: - argData.wchar_view = 0; - break; - } - - len = WPRINTF_GetLen( &format, &argData, number, maxlen - 1 ); - sign = 0; - if (!(format.flags & WPRINTF_LEFTALIGN)) - for (i = format.precision; i < format.width; i++, maxlen--) - *p++ = ' '; - switch(format.type) - { - case WPR_WCHAR: - *p++ = argData.wchar_view; - break; - case WPR_CHAR: - *p++ = argData.char_view; - break; - case WPR_STRING: - memcpy( p, argData.lpcstr_view, len ); - p += len; - break; - case WPR_WSTRING: - { - LPCWSTR ptr = argData.lpcwstr_view; - for (i = 0; i < len; i++) *p++ = (CHAR)*ptr++; - } - break; - case WPR_HEXA: - if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3)) - { - *p++ = '0'; - *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x'; - maxlen -= 2; - len -= 2; - } - /* fall through */ - case WPR_SIGNED: - /* Transfer the sign now, just in case it will be zero-padded*/ - if (number[0] == '-') - { - *p++ = '-'; - sign = 1; - } - /* fall through */ - case WPR_UNSIGNED: - for (i = len; i < format.precision; i++, maxlen--) *p++ = '0'; - memcpy( p, number + sign, len - sign ); - p += len - sign; - break; - case WPR_UNKNOWN: - continue; - } - if (format.flags & WPRINTF_LEFTALIGN) - for (i = format.precision; i < format.width; i++, maxlen--) - *p++ = ' '; - maxlen -= len; - } - *p = 0; - TRACE("%s\n",debugstr_a(buffer)); - return (maxlen > 1) ? (INT)(p - buffer) : -1; -} - - -/*********************************************************************** - * wvnsprintfW (SHLWAPI.@) - * - * See wvnsprintfA. - */ -INT WINAPI wvnsprintfW( LPWSTR buffer, INT maxlen, LPCWSTR spec, va_list args ) -{ - WPRINTF_FORMAT format; - LPWSTR p = buffer; - UINT i, len, sign; - CHAR number[20]; - WPRINTF_DATA argData; - - TRACE("%p %u %s\n", buffer, maxlen, debugstr_w(spec)); - - while (*spec && (maxlen > 1)) - { - if (*spec != '%') { *p++ = *spec++; maxlen--; continue; } - spec++; - if (*spec == '%') { *p++ = *spec++; maxlen--; continue; } - spec += WPRINTF_ParseFormatW( spec, &format ); - - switch(format.type) - { - case WPR_WCHAR: - argData.wchar_view = (WCHAR)va_arg( args, int ); - break; - case WPR_CHAR: - argData.char_view = (CHAR)va_arg( args, int ); - break; - case WPR_STRING: - argData.lpcstr_view = va_arg( args, LPCSTR ); - break; - case WPR_WSTRING: - argData.lpcwstr_view = va_arg( args, LPCWSTR ); - break; - case WPR_HEXA: - case WPR_SIGNED: - case WPR_UNSIGNED: - argData.int_view = va_arg( args, INT ); - break; - default: - argData.wchar_view = 0; - break; - } - - len = WPRINTF_GetLen( &format, &argData, number, maxlen - 1 ); - sign = 0; - if (!(format.flags & WPRINTF_LEFTALIGN)) - for (i = format.precision; i < format.width; i++, maxlen--) - *p++ = ' '; - switch(format.type) - { - case WPR_WCHAR: - *p++ = argData.wchar_view; - break; - case WPR_CHAR: - *p++ = argData.char_view; - break; - case WPR_STRING: - { - LPCSTR ptr = argData.lpcstr_view; - for (i = 0; i < len; i++) *p++ = (WCHAR)*ptr++; - } - break; - case WPR_WSTRING: - if (len) memcpy( p, argData.lpcwstr_view, len * sizeof(WCHAR) ); - p += len; - break; - case WPR_HEXA: - if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3)) - { - *p++ = '0'; - *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x'; - maxlen -= 2; - len -= 2; - } - /* fall through */ - case WPR_SIGNED: - /* Transfer the sign now, just in case it will be zero-padded*/ - if (number[0] == '-') - { - *p++ = '-'; - sign = 1; - } - /* fall through */ - case WPR_UNSIGNED: - for (i = len; i < format.precision; i++, maxlen--) *p++ = '0'; - for (i = sign; i < len; i++) *p++ = (WCHAR)number[i]; - break; - case WPR_UNKNOWN: - continue; - } - if (format.flags & WPRINTF_LEFTALIGN) - for (i = format.precision; i < format.width; i++, maxlen--) - *p++ = ' '; - maxlen -= len; - } - *p = 0; - TRACE("%s\n",debugstr_w(buffer)); - return (maxlen > 1) ? (INT)(p - buffer) : -1; -} - - -/************************************************************************* - * wnsprintfA (SHLWAPI.@) - * - * Print formatted output to a string, up to a maximum number of chars. - * - * PARAMS - * lpOut [O] Destination for output string - * cchLimitIn [I] Maximum number of characters to write - * lpFmt [I] Format string - * - * RETURNS - * Success: The number of characters written. - * Failure: -1. - */ -int WINAPIV wnsprintfA(LPSTR lpOut, int cchLimitIn, LPCSTR lpFmt, ...) -{ - va_list valist; - INT res; - - va_start( valist, lpFmt ); - res = wvnsprintfA( lpOut, cchLimitIn, lpFmt, valist ); - va_end( valist ); - return res; -} - - -/************************************************************************* - * wnsprintfW (SHLWAPI.@) - * - * See wnsprintfA. - */ -int WINAPIV wnsprintfW(LPWSTR lpOut, int cchLimitIn, LPCWSTR lpFmt, ...) -{ - va_list valist; - INT res; - - va_start( valist, lpFmt ); - res = wvnsprintfW( lpOut, cchLimitIn, lpFmt, valist ); - va_end( valist ); - return res; -} +/* + * wsprintf functions + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * NOTE: + * This code is duplicated in user32. If you change something here make sure + * to change it in user32 too. + */ + +#include <stdarg.h> +#include <string.h> +#include <stdio.h> + +#include "windef.h" +#include "winbase.h" +#define NO_SHLWAPI_REG +#include "shlwapi.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(string); + + +#define WPRINTF_LEFTALIGN 0x0001 /* Align output on the left ('-' prefix) */ +#define WPRINTF_PREFIX_HEX 0x0002 /* Prefix hex with 0x ('#' prefix) */ +#define WPRINTF_ZEROPAD 0x0004 /* Pad with zeros ('0' prefix) */ +#define WPRINTF_LONG 0x0008 /* Long arg ('l' prefix) */ +#define WPRINTF_SHORT 0x0010 /* Short arg ('h' prefix) */ +#define WPRINTF_UPPER_HEX 0x0020 /* Upper-case hex ('X' specifier) */ +#define WPRINTF_WIDE 0x0040 /* Wide arg ('w' prefix) */ + +typedef enum +{ + WPR_UNKNOWN, + WPR_CHAR, + WPR_WCHAR, + WPR_STRING, + WPR_WSTRING, + WPR_SIGNED, + WPR_UNSIGNED, + WPR_HEXA +} WPRINTF_TYPE; + +typedef struct +{ + UINT flags; + UINT width; + UINT precision; + WPRINTF_TYPE type; +} WPRINTF_FORMAT; + +typedef union { + WCHAR wchar_view; + CHAR char_view; + LPCSTR lpcstr_view; + LPCWSTR lpcwstr_view; + INT int_view; +} WPRINTF_DATA; + +static const CHAR null_stringA[] = "(null)"; +static const WCHAR null_stringW[] = { '(', 'n', 'u', 'l', 'l', ')', 0 }; + +/*********************************************************************** + * WPRINTF_ParseFormatA + * + * Parse a format specification. A format specification has the form: + * + * [-][#][0][width][.precision]type + * + * Return value is the length of the format specification in characters. + */ +static INT WPRINTF_ParseFormatA( LPCSTR format, WPRINTF_FORMAT *res ) +{ + LPCSTR p = format; + + res->flags = 0; + res->width = 0; + res->precision = 0; + if (*p == '-') { res->flags |= WPRINTF_LEFTALIGN; p++; } + if (*p == '#') { res->flags |= WPRINTF_PREFIX_HEX; p++; } + if (*p == '0') { res->flags |= WPRINTF_ZEROPAD; p++; } + while ((*p >= '0') && (*p <= '9')) /* width field */ + { + res->width = res->width * 10 + *p - '0'; + p++; + } + if (*p == '.') /* precision field */ + { + p++; + while ((*p >= '0') && (*p <= '9')) + { + res->precision = res->precision * 10 + *p - '0'; + p++; + } + } + if (*p == 'l') { res->flags |= WPRINTF_LONG; p++; } + else if (*p == 'h') { res->flags |= WPRINTF_SHORT; p++; } + else if (*p == 'w') { res->flags |= WPRINTF_WIDE; p++; } + switch(*p) + { + case 'c': + res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR; + break; + case 'C': + res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR; + break; + case 'd': + case 'i': + res->type = WPR_SIGNED; + break; + case 's': + res->type = (res->flags & (WPRINTF_LONG |WPRINTF_WIDE)) ? WPR_WSTRING : WPR_STRING; + break; + case 'S': + res->type = (res->flags & (WPRINTF_SHORT|WPRINTF_WIDE)) ? WPR_STRING : WPR_WSTRING; + break; + case 'u': + res->type = WPR_UNSIGNED; + break; + case 'X': + res->flags |= WPRINTF_UPPER_HEX; + /* fall through */ + case 'x': + res->type = WPR_HEXA; + break; + default: /* unknown format char */ + res->type = WPR_UNKNOWN; + p--; /* print format as normal char */ + break; + } + return (INT)(p - format) + 1; +} + + +/*********************************************************************** + * WPRINTF_ParseFormatW + * + * Parse a format specification. A format specification has the form: + * + * [-][#][0][width][.precision]type + * + * Return value is the length of the format specification in characters. + */ +static INT WPRINTF_ParseFormatW( LPCWSTR format, WPRINTF_FORMAT *res ) +{ + LPCWSTR p = format; + + res->flags = 0; + res->width = 0; + res->precision = 0; + if (*p == '-') { res->flags |= WPRINTF_LEFTALIGN; p++; } + if (*p == '#') { res->flags |= WPRINTF_PREFIX_HEX; p++; } + if (*p == '0') { res->flags |= WPRINTF_ZEROPAD; p++; } + while ((*p >= '0') && (*p <= '9')) /* width field */ + { + res->width = res->width * 10 + *p - '0'; + p++; + } + if (*p == '.') /* precision field */ + { + p++; + while ((*p >= '0') && (*p <= '9')) + { + res->precision = res->precision * 10 + *p - '0'; + p++; + } + } + if (*p == 'l') { res->flags |= WPRINTF_LONG; p++; } + else if (*p == 'h') { res->flags |= WPRINTF_SHORT; p++; } + else if (*p == 'w') { res->flags |= WPRINTF_WIDE; p++; } + switch((CHAR)*p) + { + case 'c': + res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR; + break; + case 'C': + res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR; + break; + case 'd': + case 'i': + res->type = WPR_SIGNED; + break; + case 's': + res->type = ((res->flags & WPRINTF_SHORT) && !(res->flags & WPRINTF_WIDE)) ? WPR_STRING : WPR_WSTRING; + break; + case 'S': + res->type = (res->flags & (WPRINTF_LONG|WPRINTF_WIDE)) ? WPR_WSTRING : WPR_STRING; + break; + case 'u': + res->type = WPR_UNSIGNED; + break; + case 'X': + res->flags |= WPRINTF_UPPER_HEX; + /* fall through */ + case 'x': + res->type = WPR_HEXA; + break; + default: + res->type = WPR_UNKNOWN; + p--; /* print format as normal char */ + break; + } + return (INT)(p - format) + 1; +} + + +/*********************************************************************** + * WPRINTF_GetLen + */ +static UINT WPRINTF_GetLen( WPRINTF_FORMAT *format, WPRINTF_DATA *arg, + LPSTR number, UINT maxlen ) +{ + UINT len; + + if (format->flags & WPRINTF_LEFTALIGN) format->flags &= ~WPRINTF_ZEROPAD; + if (format->width > maxlen) format->width = maxlen; + switch(format->type) + { + case WPR_CHAR: + case WPR_WCHAR: + return (format->precision = 1); + case WPR_STRING: + if (!arg->lpcstr_view) arg->lpcstr_view = null_stringA; + for (len = 0; !format->precision || (len < format->precision); len++) + if (!*(arg->lpcstr_view + len)) break; + if (len > maxlen) len = maxlen; + return (format->precision = len); + case WPR_WSTRING: + if (!arg->lpcwstr_view) arg->lpcwstr_view = null_stringW; + for (len = 0; !format->precision || (len < format->precision); len++) + if (!*(arg->lpcwstr_view + len)) break; + if (len > maxlen) len = maxlen; + return (format->precision = len); + case WPR_SIGNED: + len = sprintf( number, "%d", arg->int_view ); + break; + case WPR_UNSIGNED: + len = sprintf( number, "%u", (UINT)arg->int_view ); + break; + case WPR_HEXA: + len = sprintf( number, + (format->flags & WPRINTF_UPPER_HEX) ? "%X" : "%x", + (UINT)arg->int_view); + break; + default: + return 0; + } + if (len > maxlen) len = maxlen; + if (format->precision < len) format->precision = len; + if (format->precision > maxlen) format->precision = maxlen; + if ((format->flags & WPRINTF_ZEROPAD) && (format->width > format->precision)) + format->precision = format->width; + if (format->flags & WPRINTF_PREFIX_HEX) len += 2; + return len; +} + + +/*********************************************************************** + * wvnsprintfA (SHLWAPI.@) + * + * Print formatted output to a string, up to a maximum number of chars. + * + * PARAMS + * buffer [O] Destination for output string + * maxlen [I] Maximum number of characters to write + * spec [I] Format string + * + * RETURNS + * Success: The number of characters written. + * Failure: -1. + */ +INT WINAPI wvnsprintfA( LPSTR buffer, INT maxlen, LPCSTR spec, va_list args ) +{ + WPRINTF_FORMAT format; + LPSTR p = buffer; + UINT i, len, sign; + CHAR number[20]; + WPRINTF_DATA argData; + + TRACE("%p %u %s\n", buffer, maxlen, debugstr_a(spec)); + + while (*spec && (maxlen > 1)) + { + if (*spec != '%') { *p++ = *spec++; maxlen--; continue; } + spec++; + if (*spec == '%') { *p++ = *spec++; maxlen--; continue; } + spec += WPRINTF_ParseFormatA( spec, &format ); + + switch(format.type) + { + case WPR_WCHAR: + argData.wchar_view = (WCHAR)va_arg( args, int ); + break; + case WPR_CHAR: + argData.char_view = (CHAR)va_arg( args, int ); + break; + case WPR_STRING: + argData.lpcstr_view = va_arg( args, LPCSTR ); + break; + case WPR_WSTRING: + argData.lpcwstr_view = va_arg( args, LPCWSTR ); + break; + case WPR_HEXA: + case WPR_SIGNED: + case WPR_UNSIGNED: + argData.int_view = va_arg( args, INT ); + break; + default: + argData.wchar_view = 0; + break; + } + + len = WPRINTF_GetLen( &format, &argData, number, maxlen - 1 ); + sign = 0; + if (!(format.flags & WPRINTF_LEFTALIGN)) + for (i = format.precision; i < format.width; i++, maxlen--) + *p++ = ' '; + switch(format.type) + { + case WPR_WCHAR: + *p++ = argData.wchar_view; + break; + case WPR_CHAR: + *p++ = argData.char_view; + break; + case WPR_STRING: + memcpy( p, argData.lpcstr_view, len ); + p += len; + break; + case WPR_WSTRING: + { + LPCWSTR ptr = argData.lpcwstr_view; + for (i = 0; i < len; i++) *p++ = (CHAR)*ptr++; + } + break; + case WPR_HEXA: + if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3)) + { + *p++ = '0'; + *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x'; + maxlen -= 2; + len -= 2; + } + /* fall through */ + case WPR_SIGNED: + /* Transfer the sign now, just in case it will be zero-padded*/ + if (number[0] == '-') + { + *p++ = '-'; + sign = 1; + } + /* fall through */ + case WPR_UNSIGNED: + for (i = len; i < format.precision; i++, maxlen--) *p++ = '0'; + memcpy( p, number + sign, len - sign ); + p += len - sign; + break; + case WPR_UNKNOWN: + continue; + } + if (format.flags & WPRINTF_LEFTALIGN) + for (i = format.precision; i < format.width; i++, maxlen--) + *p++ = ' '; + maxlen -= len; + } + *p = 0; + TRACE("%s\n",debugstr_a(buffer)); + return (maxlen > 1) ? (INT)(p - buffer) : -1; +} + + +/*********************************************************************** + * wvnsprintfW (SHLWAPI.@) + * + * See wvnsprintfA. + */ +INT WINAPI wvnsprintfW( LPWSTR buffer, INT maxlen, LPCWSTR spec, va_list args ) +{ + WPRINTF_FORMAT format; + LPWSTR p = buffer; + UINT i, len, sign; + CHAR number[20]; + WPRINTF_DATA argData; + + TRACE("%p %u %s\n", buffer, maxlen, debugstr_w(spec)); + + while (*spec && (maxlen > 1)) + { + if (*spec != '%') { *p++ = *spec++; maxlen--; continue; } + spec++; + if (*spec == '%') { *p++ = *spec++; maxlen--; continue; } + spec += WPRINTF_ParseFormatW( spec, &format ); + + switch(format.type) + { + case WPR_WCHAR: + argData.wchar_view = (WCHAR)va_arg( args, int ); + break; + case WPR_CHAR: + argData.char_view = (CHAR)va_arg( args, int ); + break; + case WPR_STRING: + argData.lpcstr_view = va_arg( args, LPCSTR ); + break; + case WPR_WSTRING: + argData.lpcwstr_view = va_arg( args, LPCWSTR ); + break; + case WPR_HEXA: + case WPR_SIGNED: + case WPR_UNSIGNED: + argData.int_view = va_arg( args, INT ); + break; + default: + argData.wchar_view = 0; + break; + } + + len = WPRINTF_GetLen( &format, &argData, number, maxlen - 1 ); + sign = 0; + if (!(format.flags & WPRINTF_LEFTALIGN)) + for (i = format.precision; i < format.width; i++, maxlen--) + *p++ = ' '; + switch(format.type) + { + case WPR_WCHAR: + *p++ = argData.wchar_view; + break; + case WPR_CHAR: + *p++ = argData.char_view; + break; + case WPR_STRING: + { + LPCSTR ptr = argData.lpcstr_view; + for (i = 0; i < len; i++) *p++ = (WCHAR)*ptr++; + } + break; + case WPR_WSTRING: + if (len) memcpy( p, argData.lpcwstr_view, len * sizeof(WCHAR) ); + p += len; + break; + case WPR_HEXA: + if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3)) + { + *p++ = '0'; + *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x'; + maxlen -= 2; + len -= 2; + } + /* fall through */ + case WPR_SIGNED: + /* Transfer the sign now, just in case it will be zero-padded*/ + if (number[0] == '-') + { + *p++ = '-'; + sign = 1; + } + /* fall through */ + case WPR_UNSIGNED: + for (i = len; i < format.precision; i++, maxlen--) *p++ = '0'; + for (i = sign; i < len; i++) *p++ = (WCHAR)number[i]; + break; + case WPR_UNKNOWN: + continue; + } + if (format.flags & WPRINTF_LEFTALIGN) + for (i = format.precision; i < format.width; i++, maxlen--) + *p++ = ' '; + maxlen -= len; + } + *p = 0; + TRACE("%s\n",debugstr_w(buffer)); + return (maxlen > 1) ? (INT)(p - buffer) : -1; +} + + +/************************************************************************* + * wnsprintfA (SHLWAPI.@) + * + * Print formatted output to a string, up to a maximum number of chars. + * + * PARAMS + * lpOut [O] Destination for output string + * cchLimitIn [I] Maximum number of characters to write + * lpFmt [I] Format string + * + * RETURNS + * Success: The number of characters written. + * Failure: -1. + */ +int WINAPIV wnsprintfA(LPSTR lpOut, int cchLimitIn, LPCSTR lpFmt, ...) +{ + va_list valist; + INT res; + + va_start( valist, lpFmt ); + res = wvnsprintfA( lpOut, cchLimitIn, lpFmt, valist ); + va_end( valist ); + return res; +} + + +/************************************************************************* + * wnsprintfW (SHLWAPI.@) + * + * See wnsprintfA. + */ +int WINAPIV wnsprintfW(LPWSTR lpOut, int cchLimitIn, LPCWSTR lpFmt, ...) +{ + va_list valist; + INT res; + + va_start( valist, lpFmt ); + res = wvnsprintfW( lpOut, cchLimitIn, lpFmt, valist ); + va_end( valist ); + return res; +} diff --git a/reactos/lib/smdll/query.c b/reactos/lib/smdll/query.c index 7459305f7f0..558d5e76cef 100644 --- a/reactos/lib/smdll/query.c +++ b/reactos/lib/smdll/query.c @@ -1,106 +1,106 @@ -/* $Id$ - * - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS system libraries - * FILE: lib/smdll/query.c - * PURPOSE: Call SM API SM_API_QUERY_INFORMATION (not in NT) - */ -#include <windows.h> -#define NTOS_MODE_USER -#include <ndk/ntndk.h> -#include <sm/helper.h> - -#define NDEBUG -#include <debug.h> - - -/********************************************************************** - * NAME EXPORTED - * SmQueryInformation/5 - * - * DESCRIPTION - * Ask the SM to collect some data from its internal data - * structures and send it back. - * - * ARGUMENTS - * hSmApiPort: handle returned by SmConnectApiPort; - * SmInformationClass: an SM information class ID: - * SM_BASIC_INFORMATION: the number of registered subsystems - * Data: pointer to storage for the information to request; - * DataLength: length in bytes of the Data buffer; it must be - * set and must match the SmInformationClass info size; - * ReturnedDataLength: optional pointer to storage to receive - * the size of the returnede data. - * - * RETURN VALUE - * STATUS_SUCCESS: OK you get what you asked for; - * STATUS_INFO_LENGTH_MISMATCH: you set DataLength to 0 or to a - * value that does not match whet the SmInformationClass - * requires; - * STATUS_INVALID_PARAMETER_2: bad information class; - * A port error. - * - */ -NTSTATUS STDCALL -SmQueryInformation (IN HANDLE hSmApiPort, - IN SM_INFORMATION_CLASS SmInformationClass, - IN OUT PVOID Data, - IN ULONG DataLength, - IN OUT PULONG ReturnedDataLength OPTIONAL) -{ - NTSTATUS Status = STATUS_SUCCESS; - SM_PORT_MESSAGE SmReqMsg; - - - if(0 == DataLength) - { - return STATUS_INFO_LENGTH_MISMATCH; - } - /* Marshal data in the port message */ - switch (SmInformationClass) - { - case SmBasicInformation: - if(DataLength != sizeof (SM_BASIC_INFORMATION)) - { - return STATUS_INFO_LENGTH_MISMATCH; - } - SmReqMsg.Request.QryInfo.SmInformationClass = SmBasicInformation; - SmReqMsg.Request.QryInfo.DataLength = DataLength; - SmReqMsg.Request.QryInfo.BasicInformation.SubSystemCount = 0; - break; - case SmSubSystemInformation: - if(DataLength != sizeof (SM_SUBSYSTEM_INFORMATION)) - { - return STATUS_INFO_LENGTH_MISMATCH; - } - SmReqMsg.Request.QryInfo.SmInformationClass = SmSubSystemInformation; - SmReqMsg.Request.QryInfo.DataLength = DataLength; - SmReqMsg.Request.QryInfo.SubSystemInformation.SubSystemId = - ((PSM_SUBSYSTEM_INFORMATION)Data)->SubSystemId; - break; - default: - return STATUS_INVALID_PARAMETER_2; - } - /* SM API to invoke */ - SmReqMsg.SmHeader.ApiIndex = SM_API_QUERY_INFORMATION; - - /* Prepare the port request message */ - SmReqMsg.Header.MessageType = LPC_NEW_MESSAGE; - SmReqMsg.Header.DataSize = SM_PORT_DATA_SIZE(SmReqMsg.Request); - SmReqMsg.Header.MessageSize = SM_PORT_MESSAGE_SIZE; - Status = NtRequestWaitReplyPort (hSmApiPort, (PLPC_MESSAGE) & SmReqMsg, (PLPC_MESSAGE) & SmReqMsg); - if (NT_SUCCESS(Status)) - { - /* Unmarshal data */ - RtlCopyMemory (Data, & SmReqMsg.Reply.QryInfo.BasicInformation, SmReqMsg.Reply.QryInfo.DataLength); - /* Use caller provided storage to store data size */ - if(NULL != ReturnedDataLength) - { - *ReturnedDataLength = SmReqMsg.Reply.QryInfo.DataLength; - } - return SmReqMsg.SmHeader.Status; - } - DPRINT("SMLIB: %s failed (Status=0x%08lx)\n", __FUNCTION__, Status); - return Status; -} -/* EOF */ +/* $Id$ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS system libraries + * FILE: lib/smdll/query.c + * PURPOSE: Call SM API SM_API_QUERY_INFORMATION (not in NT) + */ +#include <windows.h> +#define NTOS_MODE_USER +#include <ndk/ntndk.h> +#include <sm/helper.h> + +#define NDEBUG +#include <debug.h> + + +/********************************************************************** + * NAME EXPORTED + * SmQueryInformation/5 + * + * DESCRIPTION + * Ask the SM to collect some data from its internal data + * structures and send it back. + * + * ARGUMENTS + * hSmApiPort: handle returned by SmConnectApiPort; + * SmInformationClass: an SM information class ID: + * SM_BASIC_INFORMATION: the number of registered subsystems + * Data: pointer to storage for the information to request; + * DataLength: length in bytes of the Data buffer; it must be + * set and must match the SmInformationClass info size; + * ReturnedDataLength: optional pointer to storage to receive + * the size of the returnede data. + * + * RETURN VALUE + * STATUS_SUCCESS: OK you get what you asked for; + * STATUS_INFO_LENGTH_MISMATCH: you set DataLength to 0 or to a + * value that does not match whet the SmInformationClass + * requires; + * STATUS_INVALID_PARAMETER_2: bad information class; + * A port error. + * + */ +NTSTATUS STDCALL +SmQueryInformation (IN HANDLE hSmApiPort, + IN SM_INFORMATION_CLASS SmInformationClass, + IN OUT PVOID Data, + IN ULONG DataLength, + IN OUT PULONG ReturnedDataLength OPTIONAL) +{ + NTSTATUS Status = STATUS_SUCCESS; + SM_PORT_MESSAGE SmReqMsg; + + + if(0 == DataLength) + { + return STATUS_INFO_LENGTH_MISMATCH; + } + /* Marshal data in the port message */ + switch (SmInformationClass) + { + case SmBasicInformation: + if(DataLength != sizeof (SM_BASIC_INFORMATION)) + { + return STATUS_INFO_LENGTH_MISMATCH; + } + SmReqMsg.Request.QryInfo.SmInformationClass = SmBasicInformation; + SmReqMsg.Request.QryInfo.DataLength = DataLength; + SmReqMsg.Request.QryInfo.BasicInformation.SubSystemCount = 0; + break; + case SmSubSystemInformation: + if(DataLength != sizeof (SM_SUBSYSTEM_INFORMATION)) + { + return STATUS_INFO_LENGTH_MISMATCH; + } + SmReqMsg.Request.QryInfo.SmInformationClass = SmSubSystemInformation; + SmReqMsg.Request.QryInfo.DataLength = DataLength; + SmReqMsg.Request.QryInfo.SubSystemInformation.SubSystemId = + ((PSM_SUBSYSTEM_INFORMATION)Data)->SubSystemId; + break; + default: + return STATUS_INVALID_PARAMETER_2; + } + /* SM API to invoke */ + SmReqMsg.SmHeader.ApiIndex = SM_API_QUERY_INFORMATION; + + /* Prepare the port request message */ + SmReqMsg.Header.MessageType = LPC_NEW_MESSAGE; + SmReqMsg.Header.DataSize = SM_PORT_DATA_SIZE(SmReqMsg.Request); + SmReqMsg.Header.MessageSize = SM_PORT_MESSAGE_SIZE; + Status = NtRequestWaitReplyPort (hSmApiPort, (PLPC_MESSAGE) & SmReqMsg, (PLPC_MESSAGE) & SmReqMsg); + if (NT_SUCCESS(Status)) + { + /* Unmarshal data */ + RtlCopyMemory (Data, & SmReqMsg.Reply.QryInfo.BasicInformation, SmReqMsg.Reply.QryInfo.DataLength); + /* Use caller provided storage to store data size */ + if(NULL != ReturnedDataLength) + { + *ReturnedDataLength = SmReqMsg.Reply.QryInfo.DataLength; + } + return SmReqMsg.SmHeader.Status; + } + DPRINT("SMLIB: %s failed (Status=0x%08lx)\n", __FUNCTION__, Status); + return Status; +} +/* EOF */ diff --git a/reactos/lib/string/strpbrk.c b/reactos/lib/string/strpbrk.c index 178b3a8901f..d61f1304f56 100644 --- a/reactos/lib/string/strpbrk.c +++ b/reactos/lib/string/strpbrk.c @@ -1,54 +1,54 @@ -/* - * $Id$ - */ -#include <limits.h> -#include <string.h> - -#define BIT_SIZE (CHAR_BIT * sizeof(unsigned long) / sizeof(char)) - -char* strpbrk(const char *s1, const char *s2) -{ - if (*s2 == 0) - { - return 0; - } - if (*(s2+1) == 0) - { - return strchr(s1, *s2); - } - else if (*(s2+2) == 0) - { - char *s3, *s4; - s3 = strchr(s1, *s2); - s4 = strchr(s1, *(s2+1)); - if (s3 == 0) - { - return s4; - } - else if (s4 == 0) - { - return s3; - } - return s3 < s4 ? s3 : s4; - } - else - { - unsigned long char_map[(1 << CHAR_BIT) / BIT_SIZE] = {0, }; - register unsigned char* str = (unsigned char*)s1; - while (*s2) - { - char_map[*(unsigned char*)s2 / BIT_SIZE] |= (1 << (*(unsigned char*)s2 % BIT_SIZE)); - s2++; - } - while (*str) - { - if (char_map[*str / BIT_SIZE] & (1 << (*str % BIT_SIZE))) - { - return (char*)str; - } - str++; - } - } - return 0; -} - +/* + * $Id$ + */ +#include <limits.h> +#include <string.h> + +#define BIT_SIZE (CHAR_BIT * sizeof(unsigned long) / sizeof(char)) + +char* strpbrk(const char *s1, const char *s2) +{ + if (*s2 == 0) + { + return 0; + } + if (*(s2+1) == 0) + { + return strchr(s1, *s2); + } + else if (*(s2+2) == 0) + { + char *s3, *s4; + s3 = strchr(s1, *s2); + s4 = strchr(s1, *(s2+1)); + if (s3 == 0) + { + return s4; + } + else if (s4 == 0) + { + return s3; + } + return s3 < s4 ? s3 : s4; + } + else + { + unsigned long char_map[(1 << CHAR_BIT) / BIT_SIZE] = {0, }; + register unsigned char* str = (unsigned char*)s1; + while (*s2) + { + char_map[*(unsigned char*)s2 / BIT_SIZE] |= (1 << (*(unsigned char*)s2 % BIT_SIZE)); + s2++; + } + while (*str) + { + if (char_map[*str / BIT_SIZE] & (1 << (*str % BIT_SIZE))) + { + return (char*)str; + } + str++; + } + } + return 0; +} + diff --git a/reactos/lib/urlmon/regsvr.c b/reactos/lib/urlmon/regsvr.c index 050f580f700..bacd892c13f 100644 --- a/reactos/lib/urlmon/regsvr.c +++ b/reactos/lib/urlmon/regsvr.c @@ -1,553 +1,553 @@ -/* - * self-registerable dll functions for urlmon.dll - * - * Copyright (C) 2003 John K. Hohm - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define COM_NO_WINDOWS_H -#include <stdarg.h> -#include <string.h> - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "wingdi.h" -#include "winreg.h" -#include "winerror.h" - -#include "objbase.h" - -#include "urlmon.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(urlmon); - -/* - * Near the bottom of this file are the exported DllRegisterServer and - * DllUnregisterServer, which make all this worthwhile. - */ - -/*********************************************************************** - * interface for self-registering - */ -struct regsvr_interface -{ - IID const *iid; /* NULL for end of list */ - LPCSTR name; /* can be NULL to omit */ - IID const *base_iid; /* can be NULL to omit */ - int num_methods; /* can be <0 to omit */ - CLSID const *ps_clsid; /* can be NULL to omit */ - CLSID const *ps_clsid32; /* can be NULL to omit */ -}; - -static HRESULT register_interfaces(struct regsvr_interface const *list); -static HRESULT unregister_interfaces(struct regsvr_interface const *list); - -struct regsvr_coclass -{ - CLSID const *clsid; /* NULL for end of list */ - LPCSTR name; /* can be NULL to omit */ - LPCSTR ips; /* can be NULL to omit */ - LPCSTR ips32; /* can be NULL to omit */ - LPCSTR ips32_tmodel; /* can be NULL to omit */ - LPCSTR progid; /* can be NULL to omit */ - LPCSTR viprogid; /* can be NULL to omit */ - LPCSTR progid_extra; /* can be NULL to omit */ -}; - -static HRESULT register_coclasses(struct regsvr_coclass const *list); -static HRESULT unregister_coclasses(struct regsvr_coclass const *list); - -/*********************************************************************** - * static string constants - */ -static WCHAR const interface_keyname[10] = { - 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 }; -static WCHAR const base_ifa_keyname[14] = { - 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', - 'e', 0 }; -static WCHAR const num_methods_keyname[11] = { - 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 }; -static WCHAR const ps_clsid_keyname[15] = { - 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', - 'i', 'd', 0 }; -static WCHAR const ps_clsid32_keyname[17] = { - 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', - 'i', 'd', '3', '2', 0 }; -static WCHAR const clsid_keyname[6] = { - 'C', 'L', 'S', 'I', 'D', 0 }; -static WCHAR const curver_keyname[7] = { - 'C', 'u', 'r', 'V', 'e', 'r', 0 }; -static WCHAR const ips_keyname[13] = { - 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', - 0 }; -static WCHAR const ips32_keyname[15] = { - 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', - '3', '2', 0 }; -static WCHAR const progid_keyname[7] = { - 'P', 'r', 'o', 'g', 'I', 'D', 0 }; -static WCHAR const viprogid_keyname[25] = { - 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p', - 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D', - 0 }; -static char const tmodel_valuename[] = "ThreadingModel"; - -/*********************************************************************** - * static helper functions - */ -static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid); -static LONG register_key_defvalueW(HKEY base, WCHAR const *name, - WCHAR const *value); -static LONG register_key_defvalueA(HKEY base, WCHAR const *name, - char const *value); -static LONG register_progid(WCHAR const *clsid, - char const *progid, char const *curver_progid, - char const *name, char const *extra); -static LONG recursive_delete_key(HKEY key); -static LONG recursive_delete_keyA(HKEY base, char const *name); -static LONG recursive_delete_keyW(HKEY base, WCHAR const *name); - -/*********************************************************************** - * register_interfaces - */ -static HRESULT register_interfaces(struct regsvr_interface const *list) -{ - LONG res = ERROR_SUCCESS; - HKEY interface_key; - - res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &interface_key, NULL); - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->iid; ++list) { - WCHAR buf[39]; - HKEY iid_key; - - StringFromGUID2(list->iid, buf, 39); - res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &iid_key, NULL); - if (res != ERROR_SUCCESS) goto error_close_interface_key; - - if (list->name) { - res = RegSetValueExA(iid_key, NULL, 0, REG_SZ, - (CONST BYTE*)(list->name), - strlen(list->name) + 1); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (list->base_iid) { - register_key_guid(iid_key, base_ifa_keyname, list->base_iid); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (0 <= list->num_methods) { - static WCHAR const fmt[3] = { '%', 'd', 0 }; - HKEY key; - - res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &key, NULL); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - - wsprintfW(buf, fmt, list->num_methods); - res = RegSetValueExW(key, NULL, 0, REG_SZ, - (CONST BYTE*)buf, - (lstrlenW(buf) + 1) * sizeof(WCHAR)); - RegCloseKey(key); - - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (list->ps_clsid) { - register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - if (list->ps_clsid32) { - register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32); - if (res != ERROR_SUCCESS) goto error_close_iid_key; - } - - error_close_iid_key: - RegCloseKey(iid_key); - } - -error_close_interface_key: - RegCloseKey(interface_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * unregister_interfaces - */ -static HRESULT unregister_interfaces(struct regsvr_interface const *list) -{ - LONG res = ERROR_SUCCESS; - HKEY interface_key; - - res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, - KEY_READ | KEY_WRITE, &interface_key); - if (res == ERROR_FILE_NOT_FOUND) return S_OK; - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->iid; ++list) { - WCHAR buf[39]; - - StringFromGUID2(list->iid, buf, 39); - res = recursive_delete_keyW(interface_key, buf); - } - - RegCloseKey(interface_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * register_coclasses - */ -static HRESULT register_coclasses(struct regsvr_coclass const *list) -{ - LONG res = ERROR_SUCCESS; - HKEY coclass_key; - - res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL); - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->clsid; ++list) { - WCHAR buf[39]; - HKEY clsid_key; - - StringFromGUID2(list->clsid, buf, 39); - res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL); - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - - if (list->name) { - res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ, - (CONST BYTE*)(list->name), - strlen(list->name) + 1); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->ips) { - res = register_key_defvalueA(clsid_key, ips_keyname, list->ips); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->ips32) { - HKEY ips32_key; - - res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, - &ips32_key, NULL); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - - res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ, - (CONST BYTE*)list->ips32, - lstrlenA(list->ips32) + 1); - if (res == ERROR_SUCCESS && list->ips32_tmodel) - res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ, - (CONST BYTE*)list->ips32_tmodel, - strlen(list->ips32_tmodel) + 1); - RegCloseKey(ips32_key); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->progid) { - res = register_key_defvalueA(clsid_key, progid_keyname, - list->progid); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - - res = register_progid(buf, list->progid, NULL, - list->name, list->progid_extra); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - if (list->viprogid) { - res = register_key_defvalueA(clsid_key, viprogid_keyname, - list->viprogid); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - - res = register_progid(buf, list->viprogid, list->progid, - list->name, list->progid_extra); - if (res != ERROR_SUCCESS) goto error_close_clsid_key; - } - - error_close_clsid_key: - RegCloseKey(clsid_key); - } - -error_close_coclass_key: - RegCloseKey(coclass_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * unregister_coclasses - */ -static HRESULT unregister_coclasses(struct regsvr_coclass const *list) -{ - LONG res = ERROR_SUCCESS; - HKEY coclass_key; - - res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, - KEY_READ | KEY_WRITE, &coclass_key); - if (res == ERROR_FILE_NOT_FOUND) return S_OK; - if (res != ERROR_SUCCESS) goto error_return; - - for (; res == ERROR_SUCCESS && list->clsid; ++list) { - WCHAR buf[39]; - - StringFromGUID2(list->clsid, buf, 39); - res = recursive_delete_keyW(coclass_key, buf); - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - - if (list->progid) { - res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid); - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - } - - if (list->viprogid) { - res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid); - if (res != ERROR_SUCCESS) goto error_close_coclass_key; - } - } - -error_close_coclass_key: - RegCloseKey(coclass_key); -error_return: - return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; -} - -/*********************************************************************** - * regsvr_key_guid - */ -static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) -{ - WCHAR buf[39]; - - StringFromGUID2(guid, buf, 39); - return register_key_defvalueW(base, name, buf); -} - -/*********************************************************************** - * regsvr_key_defvalueW - */ -static LONG register_key_defvalueW( - HKEY base, - WCHAR const *name, - WCHAR const *value) -{ - LONG res; - HKEY key; - - res = RegCreateKeyExW(base, name, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &key, NULL); - if (res != ERROR_SUCCESS) return res; - res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value, - (lstrlenW(value) + 1) * sizeof(WCHAR)); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * regsvr_key_defvalueA - */ -static LONG register_key_defvalueA( - HKEY base, - WCHAR const *name, - char const *value) -{ - LONG res; - HKEY key; - - res = RegCreateKeyExW(base, name, 0, NULL, 0, - KEY_READ | KEY_WRITE, NULL, &key, NULL); - if (res != ERROR_SUCCESS) return res; - res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value, - lstrlenA(value) + 1); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * regsvr_progid - */ -static LONG register_progid( - WCHAR const *clsid, - char const *progid, - char const *curver_progid, - char const *name, - char const *extra) -{ - LONG res; - HKEY progid_key; - - res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0, - NULL, 0, KEY_READ | KEY_WRITE, NULL, - &progid_key, NULL); - if (res != ERROR_SUCCESS) return res; - - if (name) { - res = RegSetValueExA(progid_key, NULL, 0, REG_SZ, - (CONST BYTE*)name, strlen(name) + 1); - if (res != ERROR_SUCCESS) goto error_close_progid_key; - } - - if (clsid) { - res = register_key_defvalueW(progid_key, clsid_keyname, clsid); - if (res != ERROR_SUCCESS) goto error_close_progid_key; - } - - if (curver_progid) { - res = register_key_defvalueA(progid_key, curver_keyname, - curver_progid); - if (res != ERROR_SUCCESS) goto error_close_progid_key; - } - - if (extra) { - HKEY extra_key; - - res = RegCreateKeyExA(progid_key, extra, 0, - NULL, 0, KEY_READ | KEY_WRITE, NULL, - &extra_key, NULL); - if (res == ERROR_SUCCESS) - RegCloseKey(extra_key); - } - -error_close_progid_key: - RegCloseKey(progid_key); - return res; -} - -/*********************************************************************** - * recursive_delete_key - */ -static LONG recursive_delete_key(HKEY key) -{ - LONG res; - WCHAR subkey_name[MAX_PATH]; - DWORD cName; - HKEY subkey; - - for (;;) { - cName = sizeof(subkey_name) / sizeof(WCHAR); - res = RegEnumKeyExW(key, 0, subkey_name, &cName, - NULL, NULL, NULL, NULL); - if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) { - res = ERROR_SUCCESS; /* presumably we're done enumerating */ - break; - } - res = RegOpenKeyExW(key, subkey_name, 0, - KEY_READ | KEY_WRITE, &subkey); - if (res == ERROR_FILE_NOT_FOUND) continue; - if (res != ERROR_SUCCESS) break; - - res = recursive_delete_key(subkey); - RegCloseKey(subkey); - if (res != ERROR_SUCCESS) break; - } - - if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0); - return res; -} - -/*********************************************************************** - * recursive_delete_keyA - */ -static LONG recursive_delete_keyA(HKEY base, char const *name) -{ - LONG res; - HKEY key; - - res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key); - if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; - if (res != ERROR_SUCCESS) return res; - res = recursive_delete_key(key); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * recursive_delete_keyW - */ -static LONG recursive_delete_keyW(HKEY base, WCHAR const *name) -{ - LONG res; - HKEY key; - - res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key); - if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; - if (res != ERROR_SUCCESS) return res; - res = recursive_delete_key(key); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * coclass list - */ -static struct regsvr_coclass const coclass_list[] = { - { &CLSID_StdURLMoniker, - "URL Moniker", - NULL, - "urlmon.dll", - "Apartment" - }, - { NULL } /* list terminator */ -}; - -/*********************************************************************** - * interface list - */ - -static struct regsvr_interface const interface_list[] = { - { NULL } /* list terminator */ -}; - -/*********************************************************************** - * DllRegisterServer (URLMON.@) - */ -HRESULT WINAPI URLMON_DllRegisterServer(void) -{ - HRESULT hr; - - TRACE("\n"); - - hr = register_coclasses(coclass_list); - if (SUCCEEDED(hr)) - hr = register_interfaces(interface_list); - return hr; -} - -/*********************************************************************** - * DllUnregisterServer (URLMON.@) - */ -HRESULT WINAPI URLMON_DllUnregisterServer(void) -{ - HRESULT hr; - - TRACE("\n"); - - hr = unregister_coclasses(coclass_list); - if (SUCCEEDED(hr)) - hr = unregister_interfaces(interface_list); - return hr; -} +/* + * self-registerable dll functions for urlmon.dll + * + * Copyright (C) 2003 John K. Hohm + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define COM_NO_WINDOWS_H +#include <stdarg.h> +#include <string.h> + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "wingdi.h" +#include "winreg.h" +#include "winerror.h" + +#include "objbase.h" + +#include "urlmon.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(urlmon); + +/* + * Near the bottom of this file are the exported DllRegisterServer and + * DllUnregisterServer, which make all this worthwhile. + */ + +/*********************************************************************** + * interface for self-registering + */ +struct regsvr_interface +{ + IID const *iid; /* NULL for end of list */ + LPCSTR name; /* can be NULL to omit */ + IID const *base_iid; /* can be NULL to omit */ + int num_methods; /* can be <0 to omit */ + CLSID const *ps_clsid; /* can be NULL to omit */ + CLSID const *ps_clsid32; /* can be NULL to omit */ +}; + +static HRESULT register_interfaces(struct regsvr_interface const *list); +static HRESULT unregister_interfaces(struct regsvr_interface const *list); + +struct regsvr_coclass +{ + CLSID const *clsid; /* NULL for end of list */ + LPCSTR name; /* can be NULL to omit */ + LPCSTR ips; /* can be NULL to omit */ + LPCSTR ips32; /* can be NULL to omit */ + LPCSTR ips32_tmodel; /* can be NULL to omit */ + LPCSTR progid; /* can be NULL to omit */ + LPCSTR viprogid; /* can be NULL to omit */ + LPCSTR progid_extra; /* can be NULL to omit */ +}; + +static HRESULT register_coclasses(struct regsvr_coclass const *list); +static HRESULT unregister_coclasses(struct regsvr_coclass const *list); + +/*********************************************************************** + * static string constants + */ +static WCHAR const interface_keyname[10] = { + 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 }; +static WCHAR const base_ifa_keyname[14] = { + 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', + 'e', 0 }; +static WCHAR const num_methods_keyname[11] = { + 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 }; +static WCHAR const ps_clsid_keyname[15] = { + 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', + 'i', 'd', 0 }; +static WCHAR const ps_clsid32_keyname[17] = { + 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's', + 'i', 'd', '3', '2', 0 }; +static WCHAR const clsid_keyname[6] = { + 'C', 'L', 'S', 'I', 'D', 0 }; +static WCHAR const curver_keyname[7] = { + 'C', 'u', 'r', 'V', 'e', 'r', 0 }; +static WCHAR const ips_keyname[13] = { + 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', + 0 }; +static WCHAR const ips32_keyname[15] = { + 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r', + '3', '2', 0 }; +static WCHAR const progid_keyname[7] = { + 'P', 'r', 'o', 'g', 'I', 'D', 0 }; +static WCHAR const viprogid_keyname[25] = { + 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p', + 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D', + 0 }; +static char const tmodel_valuename[] = "ThreadingModel"; + +/*********************************************************************** + * static helper functions + */ +static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid); +static LONG register_key_defvalueW(HKEY base, WCHAR const *name, + WCHAR const *value); +static LONG register_key_defvalueA(HKEY base, WCHAR const *name, + char const *value); +static LONG register_progid(WCHAR const *clsid, + char const *progid, char const *curver_progid, + char const *name, char const *extra); +static LONG recursive_delete_key(HKEY key); +static LONG recursive_delete_keyA(HKEY base, char const *name); +static LONG recursive_delete_keyW(HKEY base, WCHAR const *name); + +/*********************************************************************** + * register_interfaces + */ +static HRESULT register_interfaces(struct regsvr_interface const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY interface_key; + + res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &interface_key, NULL); + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->iid; ++list) { + WCHAR buf[39]; + HKEY iid_key; + + StringFromGUID2(list->iid, buf, 39); + res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &iid_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_interface_key; + + if (list->name) { + res = RegSetValueExA(iid_key, NULL, 0, REG_SZ, + (CONST BYTE*)(list->name), + strlen(list->name) + 1); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->base_iid) { + register_key_guid(iid_key, base_ifa_keyname, list->base_iid); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (0 <= list->num_methods) { + static WCHAR const fmt[3] = { '%', 'd', 0 }; + HKEY key; + + res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + + wsprintfW(buf, fmt, list->num_methods); + res = RegSetValueExW(key, NULL, 0, REG_SZ, + (CONST BYTE*)buf, + (lstrlenW(buf) + 1) * sizeof(WCHAR)); + RegCloseKey(key); + + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->ps_clsid) { + register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + if (list->ps_clsid32) { + register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32); + if (res != ERROR_SUCCESS) goto error_close_iid_key; + } + + error_close_iid_key: + RegCloseKey(iid_key); + } + +error_close_interface_key: + RegCloseKey(interface_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * unregister_interfaces + */ +static HRESULT unregister_interfaces(struct regsvr_interface const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY interface_key; + + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, + KEY_READ | KEY_WRITE, &interface_key); + if (res == ERROR_FILE_NOT_FOUND) return S_OK; + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->iid; ++list) { + WCHAR buf[39]; + + StringFromGUID2(list->iid, buf, 39); + res = recursive_delete_keyW(interface_key, buf); + } + + RegCloseKey(interface_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * register_coclasses + */ +static HRESULT register_coclasses(struct regsvr_coclass const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY coclass_key; + + res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL); + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->clsid; ++list) { + WCHAR buf[39]; + HKEY clsid_key; + + StringFromGUID2(list->clsid, buf, 39); + res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + + if (list->name) { + res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ, + (CONST BYTE*)(list->name), + strlen(list->name) + 1); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->ips) { + res = register_key_defvalueA(clsid_key, ips_keyname, list->ips); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->ips32) { + HKEY ips32_key; + + res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, + &ips32_key, NULL); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ, + (CONST BYTE*)list->ips32, + lstrlenA(list->ips32) + 1); + if (res == ERROR_SUCCESS && list->ips32_tmodel) + res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ, + (CONST BYTE*)list->ips32_tmodel, + strlen(list->ips32_tmodel) + 1); + RegCloseKey(ips32_key); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->progid) { + res = register_key_defvalueA(clsid_key, progid_keyname, + list->progid); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = register_progid(buf, list->progid, NULL, + list->name, list->progid_extra); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + if (list->viprogid) { + res = register_key_defvalueA(clsid_key, viprogid_keyname, + list->viprogid); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + + res = register_progid(buf, list->viprogid, list->progid, + list->name, list->progid_extra); + if (res != ERROR_SUCCESS) goto error_close_clsid_key; + } + + error_close_clsid_key: + RegCloseKey(clsid_key); + } + +error_close_coclass_key: + RegCloseKey(coclass_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * unregister_coclasses + */ +static HRESULT unregister_coclasses(struct regsvr_coclass const *list) +{ + LONG res = ERROR_SUCCESS; + HKEY coclass_key; + + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, + KEY_READ | KEY_WRITE, &coclass_key); + if (res == ERROR_FILE_NOT_FOUND) return S_OK; + if (res != ERROR_SUCCESS) goto error_return; + + for (; res == ERROR_SUCCESS && list->clsid; ++list) { + WCHAR buf[39]; + + StringFromGUID2(list->clsid, buf, 39); + res = recursive_delete_keyW(coclass_key, buf); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + + if (list->progid) { + res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + } + + if (list->viprogid) { + res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid); + if (res != ERROR_SUCCESS) goto error_close_coclass_key; + } + } + +error_close_coclass_key: + RegCloseKey(coclass_key); +error_return: + return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK; +} + +/*********************************************************************** + * regsvr_key_guid + */ +static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) +{ + WCHAR buf[39]; + + StringFromGUID2(guid, buf, 39); + return register_key_defvalueW(base, name, buf); +} + +/*********************************************************************** + * regsvr_key_defvalueW + */ +static LONG register_key_defvalueW( + HKEY base, + WCHAR const *name, + WCHAR const *value) +{ + LONG res; + HKEY key; + + res = RegCreateKeyExW(base, name, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) return res; + res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value, + (lstrlenW(value) + 1) * sizeof(WCHAR)); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * regsvr_key_defvalueA + */ +static LONG register_key_defvalueA( + HKEY base, + WCHAR const *name, + char const *value) +{ + LONG res; + HKEY key; + + res = RegCreateKeyExW(base, name, 0, NULL, 0, + KEY_READ | KEY_WRITE, NULL, &key, NULL); + if (res != ERROR_SUCCESS) return res; + res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value, + lstrlenA(value) + 1); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * regsvr_progid + */ +static LONG register_progid( + WCHAR const *clsid, + char const *progid, + char const *curver_progid, + char const *name, + char const *extra) +{ + LONG res; + HKEY progid_key; + + res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0, + NULL, 0, KEY_READ | KEY_WRITE, NULL, + &progid_key, NULL); + if (res != ERROR_SUCCESS) return res; + + if (name) { + res = RegSetValueExA(progid_key, NULL, 0, REG_SZ, + (CONST BYTE*)name, strlen(name) + 1); + if (res != ERROR_SUCCESS) goto error_close_progid_key; + } + + if (clsid) { + res = register_key_defvalueW(progid_key, clsid_keyname, clsid); + if (res != ERROR_SUCCESS) goto error_close_progid_key; + } + + if (curver_progid) { + res = register_key_defvalueA(progid_key, curver_keyname, + curver_progid); + if (res != ERROR_SUCCESS) goto error_close_progid_key; + } + + if (extra) { + HKEY extra_key; + + res = RegCreateKeyExA(progid_key, extra, 0, + NULL, 0, KEY_READ | KEY_WRITE, NULL, + &extra_key, NULL); + if (res == ERROR_SUCCESS) + RegCloseKey(extra_key); + } + +error_close_progid_key: + RegCloseKey(progid_key); + return res; +} + +/*********************************************************************** + * recursive_delete_key + */ +static LONG recursive_delete_key(HKEY key) +{ + LONG res; + WCHAR subkey_name[MAX_PATH]; + DWORD cName; + HKEY subkey; + + for (;;) { + cName = sizeof(subkey_name) / sizeof(WCHAR); + res = RegEnumKeyExW(key, 0, subkey_name, &cName, + NULL, NULL, NULL, NULL); + if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) { + res = ERROR_SUCCESS; /* presumably we're done enumerating */ + break; + } + res = RegOpenKeyExW(key, subkey_name, 0, + KEY_READ | KEY_WRITE, &subkey); + if (res == ERROR_FILE_NOT_FOUND) continue; + if (res != ERROR_SUCCESS) break; + + res = recursive_delete_key(subkey); + RegCloseKey(subkey); + if (res != ERROR_SUCCESS) break; + } + + if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0); + return res; +} + +/*********************************************************************** + * recursive_delete_keyA + */ +static LONG recursive_delete_keyA(HKEY base, char const *name) +{ + LONG res; + HKEY key; + + res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key); + if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; + if (res != ERROR_SUCCESS) return res; + res = recursive_delete_key(key); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * recursive_delete_keyW + */ +static LONG recursive_delete_keyW(HKEY base, WCHAR const *name) +{ + LONG res; + HKEY key; + + res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key); + if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; + if (res != ERROR_SUCCESS) return res; + res = recursive_delete_key(key); + RegCloseKey(key); + return res; +} + +/*********************************************************************** + * coclass list + */ +static struct regsvr_coclass const coclass_list[] = { + { &CLSID_StdURLMoniker, + "URL Moniker", + NULL, + "urlmon.dll", + "Apartment" + }, + { NULL } /* list terminator */ +}; + +/*********************************************************************** + * interface list + */ + +static struct regsvr_interface const interface_list[] = { + { NULL } /* list terminator */ +}; + +/*********************************************************************** + * DllRegisterServer (URLMON.@) + */ +HRESULT WINAPI URLMON_DllRegisterServer(void) +{ + HRESULT hr; + + TRACE("\n"); + + hr = register_coclasses(coclass_list); + if (SUCCEEDED(hr)) + hr = register_interfaces(interface_list); + return hr; +} + +/*********************************************************************** + * DllUnregisterServer (URLMON.@) + */ +HRESULT WINAPI URLMON_DllUnregisterServer(void) +{ + HRESULT hr; + + TRACE("\n"); + + hr = unregister_coclasses(coclass_list); + if (SUCCEEDED(hr)) + hr = unregister_interfaces(interface_list); + return hr; +} diff --git a/reactos/lib/urlmon/sec_mgr.c b/reactos/lib/urlmon/sec_mgr.c index ed5577300b4..9bfe0a886ee 100644 --- a/reactos/lib/urlmon/sec_mgr.c +++ b/reactos/lib/urlmon/sec_mgr.c @@ -1,481 +1,481 @@ -/* - * Internet Security and Zone Manager - * - * Copyright (c) 2004 Huw D M Davies - * Copyright 2004 Jacek Caban - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> -#include <stdio.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "wine/debug.h" -#include "ole2.h" -#include "wine/unicode.h" -#include "urlmon.h" -#include "urlmon_main.h" - -WINE_DEFAULT_DEBUG_CHANNEL(urlmon); - -/*********************************************************************** - * InternetSecurityManager implementation - * - */ -typedef struct SecManagerImpl{ - - IInternetSecurityManagerVtbl* lpvtbl1; /* VTable relative to the IInternetSecurityManager interface.*/ - - ULONG ref; /* reference counter for this object */ - -} SecManagerImpl; - -static HRESULT WINAPI SecManagerImpl_QueryInterface(IInternetSecurityManager* iface,REFIID riid,void** ppvObject) -{ - SecManagerImpl *This = (SecManagerImpl *)iface; - - TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject); - - /* Perform a sanity check on the parameters.*/ - if ( (This==0) || (ppvObject==0) ) - return E_INVALIDARG; - - /* Initialize the return parameter */ - *ppvObject = 0; - - /* Compare the riid with the interface IDs implemented by this object.*/ - if (IsEqualIID(&IID_IUnknown, riid) || - IsEqualIID(&IID_IInternetSecurityManager, riid)) - *ppvObject = iface; - - /* Check that we obtained an interface.*/ - if ((*ppvObject)==0) - return E_NOINTERFACE; - - /* Query Interface always increases the reference count by one when it is successful */ - IInternetSecurityManager_AddRef(iface); - - return S_OK; -} - -static ULONG WINAPI SecManagerImpl_AddRef(IInternetSecurityManager* iface) -{ - SecManagerImpl *This = (SecManagerImpl *)iface; - ULONG refCount = InterlockedIncrement(&This->ref); - - TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1); - - URLMON_LockModule(); - - return refCount; -} - -static ULONG WINAPI SecManagerImpl_Release(IInternetSecurityManager* iface) -{ - SecManagerImpl *This = (SecManagerImpl *)iface; - ULONG refCount = InterlockedDecrement(&This->ref); - - TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1); - - /* destroy the object if there's no more reference on it */ - if (!refCount){ - HeapFree(GetProcessHeap(),0,This); - } - - URLMON_UnlockModule(); - - return refCount; -} - -static HRESULT WINAPI SecManagerImpl_SetSecuritySite(IInternetSecurityManager *iface, - IInternetSecurityMgrSite *pSite) -{ - FIXME("(%p)->(%p)\n", iface, pSite); - return E_NOTIMPL; -} - -static HRESULT WINAPI SecManagerImpl_GetSecuritySite(IInternetSecurityManager *iface, - IInternetSecurityMgrSite **ppSite) -{ - FIXME("(%p)->( %p)\n", iface, ppSite); - return E_NOTIMPL; -} - -static HRESULT WINAPI SecManagerImpl_MapUrlToZone(IInternetSecurityManager *iface, - LPCWSTR pwszUrl, DWORD *pdwZone, - DWORD dwFlags) -{ - FIXME("(%p)->(%s %p %08lx)\n", iface, debugstr_w(pwszUrl), pdwZone, dwFlags); - return E_NOTIMPL; -} - -static HRESULT WINAPI SecManagerImpl_GetSecurityId(IInternetSecurityManager *iface, - LPCWSTR pwszUrl, - BYTE *pbSecurityId, DWORD *pcbSecurityId, - DWORD dwReserved) -{ - FIXME("(%p)->(%s %p %p %08lx)\n", iface, debugstr_w(pwszUrl), pbSecurityId, pcbSecurityId, - dwReserved); - return E_NOTIMPL; -} - - -static HRESULT WINAPI SecManagerImpl_ProcessUrlAction(IInternetSecurityManager *iface, - LPCWSTR pwszUrl, DWORD dwAction, - BYTE *pPolicy, DWORD cbPolicy, - BYTE *pContext, DWORD cbContext, - DWORD dwFlags, DWORD dwReserved) -{ - FIXME("(%p)->(%s %08lx %p %08lx %p %08lx %08lx %08lx)\n", iface, debugstr_w(pwszUrl), dwAction, - pPolicy, cbPolicy, pContext, cbContext, dwFlags, dwReserved); - return E_NOTIMPL; -} - - -static HRESULT WINAPI SecManagerImpl_QueryCustomPolicy(IInternetSecurityManager *iface, - LPCWSTR pwszUrl, REFGUID guidKey, - BYTE **ppPolicy, DWORD *pcbPolicy, - BYTE *pContext, DWORD cbContext, - DWORD dwReserved) -{ - FIXME("(%p)->(%s %s %p %p %p %08lx %08lx )\n", iface, debugstr_w(pwszUrl), debugstr_guid(guidKey), - ppPolicy, pcbPolicy, pContext, cbContext, dwReserved); - return E_NOTIMPL; -} - -static HRESULT WINAPI SecManagerImpl_SetZoneMapping(IInternetSecurityManager *iface, - DWORD dwZone, LPCWSTR pwszPattern, DWORD dwFlags) -{ - FIXME("(%p)->(%08lx %s %08lx)\n", iface, dwZone, debugstr_w(pwszPattern),dwFlags); - return E_NOTIMPL; -} - -static HRESULT WINAPI SecManagerImpl_GetZoneMappings(IInternetSecurityManager *iface, - DWORD dwZone, IEnumString **ppenumString, DWORD dwFlags) -{ - FIXME("(%p)->(%08lx %p %08lx)\n", iface, dwZone, ppenumString,dwFlags); - return E_NOTIMPL; -} - -static IInternetSecurityManagerVtbl VT_SecManagerImpl = -{ - SecManagerImpl_QueryInterface, - SecManagerImpl_AddRef, - SecManagerImpl_Release, - SecManagerImpl_SetSecuritySite, - SecManagerImpl_GetSecuritySite, - SecManagerImpl_MapUrlToZone, - SecManagerImpl_GetSecurityId, - SecManagerImpl_ProcessUrlAction, - SecManagerImpl_QueryCustomPolicy, - SecManagerImpl_SetZoneMapping, - SecManagerImpl_GetZoneMappings -}; - -HRESULT SecManagerImpl_Construct(IUnknown *pUnkOuter, LPVOID *ppobj) -{ - SecManagerImpl *This; - - TRACE("(%p,%p)\n",pUnkOuter,ppobj); - This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); - - /* Initialize the virtual function table. */ - This->lpvtbl1 = &VT_SecManagerImpl; - This->ref = 1; - - *ppobj = This; - return S_OK; -} - -/*********************************************************************** - * InternetZoneManager implementation - * - */ -typedef struct { - IInternetZoneManagerVtbl* lpVtbl; - ULONG ref; -} ZoneMgrImpl; - -/******************************************************************** - * IInternetZoneManager_QueryInterface - */ -static HRESULT WINAPI ZoneMgrImpl_QueryInterface(IInternetZoneManager* iface, REFIID riid, void** ppvObject) -{ - ZoneMgrImpl* This = (ZoneMgrImpl*)iface; - - TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppvObject); - - if(!This || !ppvObject) - return E_INVALIDARG; - - if(!IsEqualIID(&IID_IUnknown, riid) && !IsEqualIID(&IID_IInternetZoneManager, riid)) { - FIXME("Unknown interface: %s\n", debugstr_guid(riid)); - *ppvObject = NULL; - return E_NOINTERFACE; - } - - *ppvObject = iface; - IInternetZoneManager_AddRef(iface); - - return S_OK; -} - -/******************************************************************** - * IInternetZoneManager_AddRef - */ -static ULONG WINAPI ZoneMgrImpl_AddRef(IInternetZoneManager* iface) -{ - ZoneMgrImpl* This = (ZoneMgrImpl*)iface; - ULONG refCount = InterlockedIncrement(&This->ref); - - TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1); - - URLMON_LockModule(); - - return refCount; -} - -/******************************************************************** - * IInternetZoneManager_Release - */ -static ULONG WINAPI ZoneMgrImpl_Release(IInternetZoneManager* iface) -{ - ZoneMgrImpl* This = (ZoneMgrImpl*)iface; - ULONG refCount = InterlockedDecrement(&This->ref); - - TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1); - - if(!refCount) - HeapFree(GetProcessHeap(), 0, This); - - URLMON_UnlockModule(); - - return refCount; -} - -/******************************************************************** - * IInternetZoneManager_GetZoneAttributes - */ -static HRESULT WINAPI ZoneMgrImpl_GetZoneAttributes(IInternetZoneManager* iface, - DWORD dwZone, - ZONEATTRIBUTES* pZoneAttributes) -{ - FIXME("(%p)->(%ld %p) stub\n", iface, dwZone, pZoneAttributes); - return E_NOTIMPL; -} - -/******************************************************************** - * IInternetZoneManager_SetZoneAttributes - */ -static HRESULT WINAPI ZoneMgrImpl_SetZoneAttributes(IInternetZoneManager* iface, - DWORD dwZone, - ZONEATTRIBUTES* pZoneAttributes) -{ - FIXME("(%p)->(%08lx %p) stub\n", iface, dwZone, pZoneAttributes); - return E_NOTIMPL; -} - -/******************************************************************** - * IInternetZoneManager_GetZoneCustomPolicy - */ -static HRESULT WINAPI ZoneMgrImpl_GetZoneCustomPolicy(IInternetZoneManager* iface, - DWORD dwZone, - REFGUID guidKey, - BYTE** ppPolicy, - DWORD* pcbPolicy, - URLZONEREG ulrZoneReg) -{ - FIXME("(%p)->(%08lx %s %p %p %08x) stub\n", iface, dwZone, debugstr_guid(guidKey), - ppPolicy, pcbPolicy, ulrZoneReg); - return E_NOTIMPL; -} - -/******************************************************************** - * IInternetZoneManager_SetZoneCustomPolicy - */ -static HRESULT WINAPI ZoneMgrImpl_SetZoneCustomPolicy(IInternetZoneManager* iface, - DWORD dwZone, - REFGUID guidKey, - BYTE* ppPolicy, - DWORD cbPolicy, - URLZONEREG ulrZoneReg) -{ - FIXME("(%p)->(%08lx %s %p %08lx %08x) stub\n", iface, dwZone, debugstr_guid(guidKey), - ppPolicy, cbPolicy, ulrZoneReg); - return E_NOTIMPL; -} - -/******************************************************************** - * IInternetZoneManager_GetZoneActionPolicy - */ -static HRESULT WINAPI ZoneMgrImpl_GetZoneActionPolicy(IInternetZoneManager* iface, - DWORD dwZone, - DWORD dwAction, - BYTE* pPolicy, - DWORD cbPolicy, - URLZONEREG urlZoneReg) -{ - FIXME("(%p)->(%08lx %08lx %p %08lx %08x) stub\n", iface, dwZone, dwAction, pPolicy, - cbPolicy, urlZoneReg); - return E_NOTIMPL; -} - -/******************************************************************** - * IInternetZoneManager_SetZoneActionPolicy - */ -static HRESULT WINAPI ZoneMgrImpl_SetZoneActionPolicy(IInternetZoneManager* iface, - DWORD dwZone, - DWORD dwAction, - BYTE* pPolicy, - DWORD cbPolicy, - URLZONEREG urlZoneReg) -{ - FIXME("(%p)->(%08lx %08lx %p %08lx %08x) stub\n", iface, dwZone, dwAction, pPolicy, - cbPolicy, urlZoneReg); - return E_NOTIMPL; -} - -/******************************************************************** - * IInternetZoneManager_PromptAction - */ -static HRESULT WINAPI ZoneMgrImpl_PromptAction(IInternetZoneManager* iface, - DWORD dwAction, - HWND hwndParent, - LPCWSTR pwszUrl, - LPCWSTR pwszText, - DWORD dwPromptFlags) -{ - FIXME("%p %08lx %p %s %s %08lx\n", iface, dwAction, hwndParent, - debugstr_w(pwszUrl), debugstr_w(pwszText), dwPromptFlags ); - return E_NOTIMPL; -} - -/******************************************************************** - * IInternetZoneManager_LogAction - */ -static HRESULT WINAPI ZoneMgrImpl_LogAction(IInternetZoneManager* iface, - DWORD dwAction, - LPCWSTR pwszUrl, - LPCWSTR pwszText, - DWORD dwLogFlags) -{ - FIXME("(%p)->(%08lx %s %s %08lx) stub\n", iface, dwAction, debugstr_w(pwszUrl), - debugstr_w(pwszText), dwLogFlags); - return E_NOTIMPL; -} - -/******************************************************************** - * IInternetZoneManager_CreateZoneEnumerator - */ -static HRESULT WINAPI ZoneMgrImpl_CreateZoneEnumerator(IInternetZoneManager* iface, - DWORD* pdwEnum, - DWORD* pdwCount, - DWORD dwFlags) -{ - FIXME("(%p)->(%p %p %08lx) stub\n", iface, pdwEnum, pdwCount, dwFlags); - return E_NOTIMPL; -} - -/******************************************************************** - * IInternetZoneManager_GetZoneAt - */ -static HRESULT WINAPI ZoneMgrImpl_GetZoneAt(IInternetZoneManager* iface, - DWORD dwEnum, - DWORD dwIndex, - DWORD* pdwZone) -{ - FIXME("(%p)->(%08lx %08lx %p) stub\n", iface, dwEnum, dwIndex, pdwZone); - return E_NOTIMPL; -} - -/******************************************************************** - * IInternetZoneManager_DestroyZoneEnumerator - */ -static HRESULT WINAPI ZoneMgrImpl_DestroyZoneEnumerator(IInternetZoneManager* iface, - DWORD dwEnum) -{ - FIXME("(%p)->(%08lx) stub\n", iface, dwEnum); - return E_NOTIMPL; -} - -/******************************************************************** - * IInternetZoneManager_CopyTemplatePoliciesToZone - */ -static HRESULT WINAPI ZoneMgrImpl_CopyTemplatePoliciesToZone(IInternetZoneManager* iface, - DWORD dwTemplate, - DWORD dwZone, - DWORD dwReserved) -{ - FIXME("(%p)->(%08lx %08lx %08lx) stub\n", iface, dwTemplate, dwZone, dwReserved); - return E_NOTIMPL; -} - -/******************************************************************** - * IInternetZoneManager_Construct - */ -static IInternetZoneManagerVtbl ZoneMgrImplVtbl = { - ZoneMgrImpl_QueryInterface, - ZoneMgrImpl_AddRef, - ZoneMgrImpl_Release, - ZoneMgrImpl_GetZoneAttributes, - ZoneMgrImpl_SetZoneAttributes, - ZoneMgrImpl_GetZoneCustomPolicy, - ZoneMgrImpl_SetZoneCustomPolicy, - ZoneMgrImpl_GetZoneActionPolicy, - ZoneMgrImpl_SetZoneActionPolicy, - ZoneMgrImpl_PromptAction, - ZoneMgrImpl_LogAction, - ZoneMgrImpl_CreateZoneEnumerator, - ZoneMgrImpl_GetZoneAt, - ZoneMgrImpl_DestroyZoneEnumerator, - ZoneMgrImpl_CopyTemplatePoliciesToZone, -}; - -HRESULT ZoneMgrImpl_Construct(IUnknown *pUnkOuter, LPVOID *ppobj) -{ - ZoneMgrImpl* ret = HeapAlloc(GetProcessHeap(), 0, sizeof(ZoneMgrImpl)); - - TRACE("(%p %p)\n", pUnkOuter, ppobj); - ret->lpVtbl = &ZoneMgrImplVtbl; - ret->ref = 1; - *ppobj = (IInternetZoneManager*)ret; - - return S_OK; -} - -/*********************************************************************** - * CoInternetCreateSecurityManager (URLMON.@) - * - */ -HRESULT WINAPI CoInternetCreateSecurityManager( IServiceProvider *pSP, - IInternetSecurityManager **ppSM, DWORD dwReserved ) -{ - TRACE("%p %p %ld\n", pSP, ppSM, dwReserved ); - return SecManagerImpl_Construct(NULL, (void**) ppSM); -} - -/******************************************************************** - * CoInternetCreateZoneManager (URLMON.@) - */ -HRESULT WINAPI CoInternetCreateZoneManager(IServiceProvider* pSP, IInternetZoneManager** ppZM, DWORD dwReserved) -{ - TRACE("(%p %p %lx)\n", pSP, ppZM, dwReserved); - return ZoneMgrImpl_Construct(NULL, (void**)ppZM); -} +/* + * Internet Security and Zone Manager + * + * Copyright (c) 2004 Huw D M Davies + * Copyright 2004 Jacek Caban + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> +#include <stdio.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "wine/debug.h" +#include "ole2.h" +#include "wine/unicode.h" +#include "urlmon.h" +#include "urlmon_main.h" + +WINE_DEFAULT_DEBUG_CHANNEL(urlmon); + +/*********************************************************************** + * InternetSecurityManager implementation + * + */ +typedef struct SecManagerImpl{ + + IInternetSecurityManagerVtbl* lpvtbl1; /* VTable relative to the IInternetSecurityManager interface.*/ + + ULONG ref; /* reference counter for this object */ + +} SecManagerImpl; + +static HRESULT WINAPI SecManagerImpl_QueryInterface(IInternetSecurityManager* iface,REFIID riid,void** ppvObject) +{ + SecManagerImpl *This = (SecManagerImpl *)iface; + + TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject); + + /* Perform a sanity check on the parameters.*/ + if ( (This==0) || (ppvObject==0) ) + return E_INVALIDARG; + + /* Initialize the return parameter */ + *ppvObject = 0; + + /* Compare the riid with the interface IDs implemented by this object.*/ + if (IsEqualIID(&IID_IUnknown, riid) || + IsEqualIID(&IID_IInternetSecurityManager, riid)) + *ppvObject = iface; + + /* Check that we obtained an interface.*/ + if ((*ppvObject)==0) + return E_NOINTERFACE; + + /* Query Interface always increases the reference count by one when it is successful */ + IInternetSecurityManager_AddRef(iface); + + return S_OK; +} + +static ULONG WINAPI SecManagerImpl_AddRef(IInternetSecurityManager* iface) +{ + SecManagerImpl *This = (SecManagerImpl *)iface; + ULONG refCount = InterlockedIncrement(&This->ref); + + TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1); + + URLMON_LockModule(); + + return refCount; +} + +static ULONG WINAPI SecManagerImpl_Release(IInternetSecurityManager* iface) +{ + SecManagerImpl *This = (SecManagerImpl *)iface; + ULONG refCount = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1); + + /* destroy the object if there's no more reference on it */ + if (!refCount){ + HeapFree(GetProcessHeap(),0,This); + } + + URLMON_UnlockModule(); + + return refCount; +} + +static HRESULT WINAPI SecManagerImpl_SetSecuritySite(IInternetSecurityManager *iface, + IInternetSecurityMgrSite *pSite) +{ + FIXME("(%p)->(%p)\n", iface, pSite); + return E_NOTIMPL; +} + +static HRESULT WINAPI SecManagerImpl_GetSecuritySite(IInternetSecurityManager *iface, + IInternetSecurityMgrSite **ppSite) +{ + FIXME("(%p)->( %p)\n", iface, ppSite); + return E_NOTIMPL; +} + +static HRESULT WINAPI SecManagerImpl_MapUrlToZone(IInternetSecurityManager *iface, + LPCWSTR pwszUrl, DWORD *pdwZone, + DWORD dwFlags) +{ + FIXME("(%p)->(%s %p %08lx)\n", iface, debugstr_w(pwszUrl), pdwZone, dwFlags); + return E_NOTIMPL; +} + +static HRESULT WINAPI SecManagerImpl_GetSecurityId(IInternetSecurityManager *iface, + LPCWSTR pwszUrl, + BYTE *pbSecurityId, DWORD *pcbSecurityId, + DWORD dwReserved) +{ + FIXME("(%p)->(%s %p %p %08lx)\n", iface, debugstr_w(pwszUrl), pbSecurityId, pcbSecurityId, + dwReserved); + return E_NOTIMPL; +} + + +static HRESULT WINAPI SecManagerImpl_ProcessUrlAction(IInternetSecurityManager *iface, + LPCWSTR pwszUrl, DWORD dwAction, + BYTE *pPolicy, DWORD cbPolicy, + BYTE *pContext, DWORD cbContext, + DWORD dwFlags, DWORD dwReserved) +{ + FIXME("(%p)->(%s %08lx %p %08lx %p %08lx %08lx %08lx)\n", iface, debugstr_w(pwszUrl), dwAction, + pPolicy, cbPolicy, pContext, cbContext, dwFlags, dwReserved); + return E_NOTIMPL; +} + + +static HRESULT WINAPI SecManagerImpl_QueryCustomPolicy(IInternetSecurityManager *iface, + LPCWSTR pwszUrl, REFGUID guidKey, + BYTE **ppPolicy, DWORD *pcbPolicy, + BYTE *pContext, DWORD cbContext, + DWORD dwReserved) +{ + FIXME("(%p)->(%s %s %p %p %p %08lx %08lx )\n", iface, debugstr_w(pwszUrl), debugstr_guid(guidKey), + ppPolicy, pcbPolicy, pContext, cbContext, dwReserved); + return E_NOTIMPL; +} + +static HRESULT WINAPI SecManagerImpl_SetZoneMapping(IInternetSecurityManager *iface, + DWORD dwZone, LPCWSTR pwszPattern, DWORD dwFlags) +{ + FIXME("(%p)->(%08lx %s %08lx)\n", iface, dwZone, debugstr_w(pwszPattern),dwFlags); + return E_NOTIMPL; +} + +static HRESULT WINAPI SecManagerImpl_GetZoneMappings(IInternetSecurityManager *iface, + DWORD dwZone, IEnumString **ppenumString, DWORD dwFlags) +{ + FIXME("(%p)->(%08lx %p %08lx)\n", iface, dwZone, ppenumString,dwFlags); + return E_NOTIMPL; +} + +static IInternetSecurityManagerVtbl VT_SecManagerImpl = +{ + SecManagerImpl_QueryInterface, + SecManagerImpl_AddRef, + SecManagerImpl_Release, + SecManagerImpl_SetSecuritySite, + SecManagerImpl_GetSecuritySite, + SecManagerImpl_MapUrlToZone, + SecManagerImpl_GetSecurityId, + SecManagerImpl_ProcessUrlAction, + SecManagerImpl_QueryCustomPolicy, + SecManagerImpl_SetZoneMapping, + SecManagerImpl_GetZoneMappings +}; + +HRESULT SecManagerImpl_Construct(IUnknown *pUnkOuter, LPVOID *ppobj) +{ + SecManagerImpl *This; + + TRACE("(%p,%p)\n",pUnkOuter,ppobj); + This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + + /* Initialize the virtual function table. */ + This->lpvtbl1 = &VT_SecManagerImpl; + This->ref = 1; + + *ppobj = This; + return S_OK; +} + +/*********************************************************************** + * InternetZoneManager implementation + * + */ +typedef struct { + IInternetZoneManagerVtbl* lpVtbl; + ULONG ref; +} ZoneMgrImpl; + +/******************************************************************** + * IInternetZoneManager_QueryInterface + */ +static HRESULT WINAPI ZoneMgrImpl_QueryInterface(IInternetZoneManager* iface, REFIID riid, void** ppvObject) +{ + ZoneMgrImpl* This = (ZoneMgrImpl*)iface; + + TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppvObject); + + if(!This || !ppvObject) + return E_INVALIDARG; + + if(!IsEqualIID(&IID_IUnknown, riid) && !IsEqualIID(&IID_IInternetZoneManager, riid)) { + FIXME("Unknown interface: %s\n", debugstr_guid(riid)); + *ppvObject = NULL; + return E_NOINTERFACE; + } + + *ppvObject = iface; + IInternetZoneManager_AddRef(iface); + + return S_OK; +} + +/******************************************************************** + * IInternetZoneManager_AddRef + */ +static ULONG WINAPI ZoneMgrImpl_AddRef(IInternetZoneManager* iface) +{ + ZoneMgrImpl* This = (ZoneMgrImpl*)iface; + ULONG refCount = InterlockedIncrement(&This->ref); + + TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1); + + URLMON_LockModule(); + + return refCount; +} + +/******************************************************************** + * IInternetZoneManager_Release + */ +static ULONG WINAPI ZoneMgrImpl_Release(IInternetZoneManager* iface) +{ + ZoneMgrImpl* This = (ZoneMgrImpl*)iface; + ULONG refCount = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1); + + if(!refCount) + HeapFree(GetProcessHeap(), 0, This); + + URLMON_UnlockModule(); + + return refCount; +} + +/******************************************************************** + * IInternetZoneManager_GetZoneAttributes + */ +static HRESULT WINAPI ZoneMgrImpl_GetZoneAttributes(IInternetZoneManager* iface, + DWORD dwZone, + ZONEATTRIBUTES* pZoneAttributes) +{ + FIXME("(%p)->(%ld %p) stub\n", iface, dwZone, pZoneAttributes); + return E_NOTIMPL; +} + +/******************************************************************** + * IInternetZoneManager_SetZoneAttributes + */ +static HRESULT WINAPI ZoneMgrImpl_SetZoneAttributes(IInternetZoneManager* iface, + DWORD dwZone, + ZONEATTRIBUTES* pZoneAttributes) +{ + FIXME("(%p)->(%08lx %p) stub\n", iface, dwZone, pZoneAttributes); + return E_NOTIMPL; +} + +/******************************************************************** + * IInternetZoneManager_GetZoneCustomPolicy + */ +static HRESULT WINAPI ZoneMgrImpl_GetZoneCustomPolicy(IInternetZoneManager* iface, + DWORD dwZone, + REFGUID guidKey, + BYTE** ppPolicy, + DWORD* pcbPolicy, + URLZONEREG ulrZoneReg) +{ + FIXME("(%p)->(%08lx %s %p %p %08x) stub\n", iface, dwZone, debugstr_guid(guidKey), + ppPolicy, pcbPolicy, ulrZoneReg); + return E_NOTIMPL; +} + +/******************************************************************** + * IInternetZoneManager_SetZoneCustomPolicy + */ +static HRESULT WINAPI ZoneMgrImpl_SetZoneCustomPolicy(IInternetZoneManager* iface, + DWORD dwZone, + REFGUID guidKey, + BYTE* ppPolicy, + DWORD cbPolicy, + URLZONEREG ulrZoneReg) +{ + FIXME("(%p)->(%08lx %s %p %08lx %08x) stub\n", iface, dwZone, debugstr_guid(guidKey), + ppPolicy, cbPolicy, ulrZoneReg); + return E_NOTIMPL; +} + +/******************************************************************** + * IInternetZoneManager_GetZoneActionPolicy + */ +static HRESULT WINAPI ZoneMgrImpl_GetZoneActionPolicy(IInternetZoneManager* iface, + DWORD dwZone, + DWORD dwAction, + BYTE* pPolicy, + DWORD cbPolicy, + URLZONEREG urlZoneReg) +{ + FIXME("(%p)->(%08lx %08lx %p %08lx %08x) stub\n", iface, dwZone, dwAction, pPolicy, + cbPolicy, urlZoneReg); + return E_NOTIMPL; +} + +/******************************************************************** + * IInternetZoneManager_SetZoneActionPolicy + */ +static HRESULT WINAPI ZoneMgrImpl_SetZoneActionPolicy(IInternetZoneManager* iface, + DWORD dwZone, + DWORD dwAction, + BYTE* pPolicy, + DWORD cbPolicy, + URLZONEREG urlZoneReg) +{ + FIXME("(%p)->(%08lx %08lx %p %08lx %08x) stub\n", iface, dwZone, dwAction, pPolicy, + cbPolicy, urlZoneReg); + return E_NOTIMPL; +} + +/******************************************************************** + * IInternetZoneManager_PromptAction + */ +static HRESULT WINAPI ZoneMgrImpl_PromptAction(IInternetZoneManager* iface, + DWORD dwAction, + HWND hwndParent, + LPCWSTR pwszUrl, + LPCWSTR pwszText, + DWORD dwPromptFlags) +{ + FIXME("%p %08lx %p %s %s %08lx\n", iface, dwAction, hwndParent, + debugstr_w(pwszUrl), debugstr_w(pwszText), dwPromptFlags ); + return E_NOTIMPL; +} + +/******************************************************************** + * IInternetZoneManager_LogAction + */ +static HRESULT WINAPI ZoneMgrImpl_LogAction(IInternetZoneManager* iface, + DWORD dwAction, + LPCWSTR pwszUrl, + LPCWSTR pwszText, + DWORD dwLogFlags) +{ + FIXME("(%p)->(%08lx %s %s %08lx) stub\n", iface, dwAction, debugstr_w(pwszUrl), + debugstr_w(pwszText), dwLogFlags); + return E_NOTIMPL; +} + +/******************************************************************** + * IInternetZoneManager_CreateZoneEnumerator + */ +static HRESULT WINAPI ZoneMgrImpl_CreateZoneEnumerator(IInternetZoneManager* iface, + DWORD* pdwEnum, + DWORD* pdwCount, + DWORD dwFlags) +{ + FIXME("(%p)->(%p %p %08lx) stub\n", iface, pdwEnum, pdwCount, dwFlags); + return E_NOTIMPL; +} + +/******************************************************************** + * IInternetZoneManager_GetZoneAt + */ +static HRESULT WINAPI ZoneMgrImpl_GetZoneAt(IInternetZoneManager* iface, + DWORD dwEnum, + DWORD dwIndex, + DWORD* pdwZone) +{ + FIXME("(%p)->(%08lx %08lx %p) stub\n", iface, dwEnum, dwIndex, pdwZone); + return E_NOTIMPL; +} + +/******************************************************************** + * IInternetZoneManager_DestroyZoneEnumerator + */ +static HRESULT WINAPI ZoneMgrImpl_DestroyZoneEnumerator(IInternetZoneManager* iface, + DWORD dwEnum) +{ + FIXME("(%p)->(%08lx) stub\n", iface, dwEnum); + return E_NOTIMPL; +} + +/******************************************************************** + * IInternetZoneManager_CopyTemplatePoliciesToZone + */ +static HRESULT WINAPI ZoneMgrImpl_CopyTemplatePoliciesToZone(IInternetZoneManager* iface, + DWORD dwTemplate, + DWORD dwZone, + DWORD dwReserved) +{ + FIXME("(%p)->(%08lx %08lx %08lx) stub\n", iface, dwTemplate, dwZone, dwReserved); + return E_NOTIMPL; +} + +/******************************************************************** + * IInternetZoneManager_Construct + */ +static IInternetZoneManagerVtbl ZoneMgrImplVtbl = { + ZoneMgrImpl_QueryInterface, + ZoneMgrImpl_AddRef, + ZoneMgrImpl_Release, + ZoneMgrImpl_GetZoneAttributes, + ZoneMgrImpl_SetZoneAttributes, + ZoneMgrImpl_GetZoneCustomPolicy, + ZoneMgrImpl_SetZoneCustomPolicy, + ZoneMgrImpl_GetZoneActionPolicy, + ZoneMgrImpl_SetZoneActionPolicy, + ZoneMgrImpl_PromptAction, + ZoneMgrImpl_LogAction, + ZoneMgrImpl_CreateZoneEnumerator, + ZoneMgrImpl_GetZoneAt, + ZoneMgrImpl_DestroyZoneEnumerator, + ZoneMgrImpl_CopyTemplatePoliciesToZone, +}; + +HRESULT ZoneMgrImpl_Construct(IUnknown *pUnkOuter, LPVOID *ppobj) +{ + ZoneMgrImpl* ret = HeapAlloc(GetProcessHeap(), 0, sizeof(ZoneMgrImpl)); + + TRACE("(%p %p)\n", pUnkOuter, ppobj); + ret->lpVtbl = &ZoneMgrImplVtbl; + ret->ref = 1; + *ppobj = (IInternetZoneManager*)ret; + + return S_OK; +} + +/*********************************************************************** + * CoInternetCreateSecurityManager (URLMON.@) + * + */ +HRESULT WINAPI CoInternetCreateSecurityManager( IServiceProvider *pSP, + IInternetSecurityManager **ppSM, DWORD dwReserved ) +{ + TRACE("%p %p %ld\n", pSP, ppSM, dwReserved ); + return SecManagerImpl_Construct(NULL, (void**) ppSM); +} + +/******************************************************************** + * CoInternetCreateZoneManager (URLMON.@) + */ +HRESULT WINAPI CoInternetCreateZoneManager(IServiceProvider* pSP, IInternetZoneManager** ppZM, DWORD dwReserved) +{ + TRACE("(%p %p %lx)\n", pSP, ppZM, dwReserved); + return ZoneMgrImpl_Construct(NULL, (void**)ppZM); +} diff --git a/reactos/lib/urlmon/umon.c b/reactos/lib/urlmon/umon.c index d8d85e39c03..8d6709ed5d5 100644 --- a/reactos/lib/urlmon/umon.c +++ b/reactos/lib/urlmon/umon.c @@ -1,1737 +1,1737 @@ -/* - * UrlMon - * - * Copyright 1999 Ulrich Czekalla for Corel Corporation - * Copyright 2002 Huw D M Davies for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define COM_NO_WINDOWS_H -#include <stdarg.h> -#include <stdio.h> - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "winternl.h" -#include "winuser.h" -#include "objbase.h" -#include "wine/debug.h" -#include "wine/unicode.h" -#include "ole2.h" -#include "urlmon.h" -#include "wininet.h" -#include "shlwapi.h" -#include "urlmon_main.h" - -WINE_DEFAULT_DEBUG_CHANNEL(urlmon); - -/* native urlmon.dll uses this key, too */ -static const WCHAR BSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 }; - -/*static BOOL registered_wndclass = FALSE;*/ - -typedef struct { - IBindingVtbl *lpVtbl; - - ULONG ref; - - LPWSTR URLName; - - HWND hwndCallback; - IBindCtx *pBC; - HINTERNET hinternet, hconnect, hrequest; - HANDLE hCacheFile; - IUMCacheStream *pstrCache; - IBindStatusCallback *pbscb; - DWORD total_read, expected_size; -} Binding; - -static HRESULT WINAPI Binding_QueryInterface(IBinding* iface, REFIID riid, void **ppvObject) -{ - Binding *This = (Binding*)iface; - - TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppvObject); - - if((This == NULL) || (ppvObject == NULL)) - return E_INVALIDARG; - - if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IBinding, riid)) { - *ppvObject = iface; - IBinding_AddRef(iface); - return S_OK; - } - - *ppvObject = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI Binding_AddRef(IBinding* iface) -{ - Binding *This = (Binding*)iface; - ULONG ref = InterlockedIncrement(&This->ref); - - TRACE("(%p) ref=%ld\n", This, ref); - - return ref; -} - -static ULONG WINAPI Binding_Release(IBinding* iface) -{ - Binding *This = (Binding*)iface; - ULONG ref = InterlockedDecrement(&This->ref); - - TRACE("(%p) ref=%ld\n",This, ref); - - if(!ref) { - HeapFree(GetProcessHeap(), 0, This->URLName); - if (This->hCacheFile) - CloseHandle(This->hCacheFile); - if (This->pstrCache) - { - UMCloseCacheFileStream(This->pstrCache); - IStream_Release((IStream *)This->pstrCache); - } - if (This->pbscb) - IBindStatusCallback_Release(This->pbscb); - - HeapFree(GetProcessHeap(), 0, This); - - URLMON_UnlockModule(); - } - - return ref; -} - -static HRESULT WINAPI Binding_Abort(IBinding* iface) -{ - Binding *This = (Binding*)iface; - - FIXME("(%p): stub\n", This); - - return E_NOTIMPL; -} - -static HRESULT WINAPI Binding_GetBindResult(IBinding* iface, CLSID* pclsidProtocol, DWORD* pdwResult, LPOLESTR* pszResult, DWORD* pdwReserved) -{ - Binding *This = (Binding*)iface; - - FIXME("(%p)->(%p, %p, %p, %p): stub\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved); - - return E_NOTIMPL; -} - -static HRESULT WINAPI Binding_GetPriority(IBinding* iface, LONG* pnPriority) -{ - Binding *This = (Binding*)iface; - - FIXME("(%p)->(%p): stub\n", This, pnPriority); - - return E_NOTIMPL; -} - -static HRESULT WINAPI Binding_Resume(IBinding* iface) -{ - Binding *This = (Binding*)iface; - - FIXME("(%p): stub\n", This); - - return E_NOTIMPL; -} - -static HRESULT WINAPI Binding_SetPriority(IBinding* iface, LONG nPriority) -{ - Binding *This = (Binding*)iface; - - FIXME("(%p)->(%ld): stub\n", This, nPriority); - - return E_NOTIMPL; -} - -static HRESULT WINAPI Binding_Suspend(IBinding* iface) -{ - Binding *This = (Binding*)iface; - - FIXME("(%p): stub\n", This); - - return E_NOTIMPL; -} - -static void Binding_CloseCacheDownload(Binding *This) -{ - CloseHandle(This->hCacheFile); - This->hCacheFile = 0; - UMCloseCacheFileStream(This->pstrCache); - IStream_Release((IStream *)This->pstrCache); - This->pstrCache = 0; -} - -static HRESULT Binding_MoreCacheData(Binding *This, char *buf, DWORD dwBytes) -{ - DWORD written; - - if (WriteFile(This->hCacheFile, buf, dwBytes, &written, NULL) && written == dwBytes) - { - HRESULT hr; - - This->total_read += written; - hr = IBindStatusCallback_OnProgress(This->pbscb, - This->total_read + written, - This->expected_size, - (This->total_read == written) ? - BINDSTATUS_BEGINDOWNLOADDATA : - BINDSTATUS_DOWNLOADINGDATA, - NULL); - if (!hr) - { - STGMEDIUM stg; - FORMATETC fmt; - - fmt.cfFormat = 0; - fmt.ptd = NULL; - fmt.dwAspect = 0; - fmt.lindex = -1; - fmt.tymed = TYMED_ISTREAM; - - stg.tymed = TYMED_ISTREAM; - stg.u.pstm = (IStream *)This->pstrCache; - stg.pUnkForRelease = NULL; - - hr = IBindStatusCallback_OnDataAvailable(This->pbscb, - (This->total_read == written) ? - BSCF_FIRSTDATANOTIFICATION : - BSCF_INTERMEDIATEDATANOTIFICATION, - This->total_read + written, - &fmt, - &stg); - } - if (written < dwBytes) - return STG_E_MEDIUMFULL; - else - return hr; - } - return HRESULT_FROM_WIN32(GetLastError()); -} - -static void Binding_FinishedDownload(Binding *This, HRESULT hr) -{ - STGMEDIUM stg; - FORMATETC fmt; - - fmt.ptd = NULL; - fmt.dwAspect = 0; - fmt.lindex = -1; - fmt.tymed = TYMED_ISTREAM; - - stg.tymed = TYMED_ISTREAM; - stg.u.pstm = (IStream *)This->pstrCache; - stg.pUnkForRelease = NULL; - - IBindStatusCallback_OnProgress(This->pbscb, This->total_read, This->expected_size, BINDSTATUS_ENDDOWNLOADDATA, NULL); - IBindStatusCallback_OnDataAvailable(This->pbscb, BSCF_LASTDATANOTIFICATION, This->total_read, &fmt, &stg); - if (hr) - { - WCHAR *pwchError = 0; - - FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_ALLOCATE_BUFFER, - NULL, (DWORD) hr, - 0, (LPWSTR) &pwchError, - 0, NULL); - if (!pwchError) - { - static WCHAR achFormat[] = { '%', '0', '8', 'x', 0 }; - - pwchError =(WCHAR *) LocalAlloc(LMEM_FIXED, sizeof(WCHAR) * 9); - wsprintfW(pwchError, achFormat, hr); - } - IBindStatusCallback_OnStopBinding(This->pbscb, hr, pwchError); - LocalFree(pwchError); - } - else - { - IBindStatusCallback_OnStopBinding(This->pbscb, hr, NULL); - } - IBindStatusCallback_Release(This->pbscb); - This->pbscb = 0; -} - -static IBindingVtbl BindingVtbl = -{ - Binding_QueryInterface, - Binding_AddRef, - Binding_Release, - Binding_Abort, - Binding_Suspend, - Binding_Resume, - Binding_SetPriority, - Binding_GetPriority, - Binding_GetBindResult -}; - -/* filemoniker data structure */ -typedef struct { - - IMonikerVtbl* lpvtbl; /* VTable relative to the IMoniker interface.*/ - - ULONG ref; /* reference counter for this object */ - - LPOLESTR URLName; /* URL string identified by this URLmoniker */ -} URLMonikerImpl; - -/******************************************************************************* - * URLMoniker_QueryInterface - *******************************************************************************/ -static HRESULT WINAPI URLMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject) -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - - TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject); - - /* Perform a sanity check on the parameters.*/ - if ( (This==0) || (ppvObject==0) ) - return E_INVALIDARG; - - /* Initialize the return parameter */ - *ppvObject = 0; - - /* Compare the riid with the interface IDs implemented by this object.*/ - if (IsEqualIID(&IID_IUnknown, riid) || - IsEqualIID(&IID_IPersist, riid) || - IsEqualIID(&IID_IPersistStream,riid) || - IsEqualIID(&IID_IMoniker, riid) - ) - *ppvObject = iface; - - /* Check that we obtained an interface.*/ - if ((*ppvObject)==0) - return E_NOINTERFACE; - - /* Query Interface always increases the reference count by one when it is successful */ - IMoniker_AddRef(iface); - - return S_OK; -} - -/****************************************************************************** - * URLMoniker_AddRef - ******************************************************************************/ -static ULONG WINAPI URLMonikerImpl_AddRef(IMoniker* iface) -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - ULONG refCount = InterlockedIncrement(&This->ref); - - TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1); - - URLMON_LockModule(); - - return refCount; -} - -/****************************************************************************** - * URLMoniker_Release - ******************************************************************************/ -static ULONG WINAPI URLMonikerImpl_Release(IMoniker* iface) -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - ULONG refCount = InterlockedDecrement(&This->ref); - - TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1); - - /* destroy the object if there's no more reference on it */ - if (!refCount) { - HeapFree(GetProcessHeap(),0,This->URLName); - HeapFree(GetProcessHeap(),0,This); - } - - URLMON_UnlockModule(); - - return refCount; -} - - -/****************************************************************************** - * URLMoniker_GetClassID - ******************************************************************************/ -static HRESULT WINAPI URLMonikerImpl_GetClassID(IMoniker* iface, - CLSID *pClassID)/* Pointer to CLSID of object */ -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - - TRACE("(%p,%p)\n",This,pClassID); - - if (pClassID==NULL) - return E_POINTER; - /* Windows always returns CLSID_StdURLMoniker */ - *pClassID = CLSID_StdURLMoniker; - return S_OK; -} - -/****************************************************************************** - * URLMoniker_IsDirty - ******************************************************************************/ -static HRESULT WINAPI URLMonikerImpl_IsDirty(IMoniker* iface) -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - /* Note that the OLE-provided implementations of the IPersistStream::IsDirty - method in the OLE-provided moniker interfaces always return S_FALSE because - their internal state never changes. */ - - TRACE("(%p)\n",This); - - return S_FALSE; -} - -/****************************************************************************** - * URLMoniker_Load - * - * NOTE - * Writes a ULONG containing length of unicode string, followed - * by that many unicode characters - ******************************************************************************/ -static HRESULT WINAPI URLMonikerImpl_Load(IMoniker* iface,IStream* pStm) -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - - HRESULT res; - ULONG len; - ULONG got; - TRACE("(%p,%p)\n",This,pStm); - - if(!pStm) - return E_INVALIDARG; - - res = IStream_Read(pStm, &len, sizeof(ULONG), &got); - if(SUCCEEDED(res)) { - if(got == sizeof(ULONG)) { - HeapFree(GetProcessHeap(), 0, This->URLName); - This->URLName=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(len+1)); - if(!This->URLName) - res = E_OUTOFMEMORY; - else { - res = IStream_Read(pStm, This->URLName, len, NULL); - This->URLName[len] = 0; - } - } - else - res = E_FAIL; - } - return res; -} - -/****************************************************************************** - * URLMoniker_Save - ******************************************************************************/ -static HRESULT WINAPI URLMonikerImpl_Save(IMoniker* iface, - IStream* pStm,/* pointer to the stream where the object is to be saved */ - BOOL fClearDirty)/* Specifies whether to clear the dirty flag */ -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - - HRESULT res; - ULONG len; - TRACE("(%p,%p,%d)\n",This,pStm,fClearDirty); - - if(!pStm) - return E_INVALIDARG; - - len = strlenW(This->URLName); - res=IStream_Write(pStm,&len,sizeof(ULONG),NULL); - if(SUCCEEDED(res)) - res=IStream_Write(pStm,&This->URLName,len*sizeof(WCHAR),NULL); - return res; - -} - -/****************************************************************************** - * URLMoniker_GetSizeMax - ******************************************************************************/ -static HRESULT WINAPI URLMonikerImpl_GetSizeMax(IMoniker* iface, - ULARGE_INTEGER* pcbSize)/* Pointer to size of stream needed to save object */ -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - - TRACE("(%p,%p)\n",This,pcbSize); - - if(!pcbSize) - return E_INVALIDARG; - - pcbSize->u.LowPart = sizeof(ULONG) + (strlenW(This->URLName) * sizeof(WCHAR)); - pcbSize->u.HighPart = 0; - return S_OK; -} - -/****************************************************************************** - * URLMoniker_BindToObject - ******************************************************************************/ -static HRESULT WINAPI URLMonikerImpl_BindToObject(IMoniker* iface, - IBindCtx* pbc, - IMoniker* pmkToLeft, - REFIID riid, - VOID** ppvResult) -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - - *ppvResult=0; - - FIXME("(%p)->(%p,%p,%s,%p): stub\n",This,pbc,pmkToLeft,debugstr_guid(riid), - ppvResult); - - return E_NOTIMPL; -} - -typedef struct { - enum {OnProgress, OnDataAvailable} callback; -} URLMON_CallbackData; - - -#if 0 -static LRESULT CALLBACK URLMON_WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -{ - return DefWindowProcA(hwnd, msg, wparam, lparam); -} - -static void PostOnProgress(URLMonikerImpl *This, UINT progress, UINT maxprogress, DWORD status, LPCWSTR *str) -{ -} - -static void CALLBACK URLMON_InternetCallback(HINTERNET hinet, /*DWORD_PTR*/ DWORD context, DWORD status, - void *status_info, DWORD status_info_len) -{ - URLMonikerImpl *This = (URLMonikerImpl *)context; - TRACE("handle %p this %p status %08lx\n", hinet, This, status); - - if(This->filesize == -1) { - switch(status) { - case INTERNET_STATUS_RESOLVING_NAME: - PostOnProgess(This, 0, 0, BINDSTATUS_FINDINGRESOURCE, status_info); - break; - case INTERNET_STATUS_CONNECTING_TO_SERVER: - PostOnProgress(This, 0, 0, BINDSTATUS_CONNECTING, NULL); - break; - case INTERNET_STATUS_SENDING_REQUEST: - PostOnProgress(This, 0, 0, BINDSTATUS_SENDINGREQUEST, NULL); - break; - case INTERNET_REQUEST_COMPLETE: - { - DWORD len, lensz = sizeof(len); - - HttpQueryInfoW(hrequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &len, &lensz, NULL); - TRACE("res = %ld gle = %08lx url len = %ld\n", hres, GetLastError(), len); - This->filesize = len; - break; - } - } - } - - return; -} -#endif - - -/****************************************************************************** - * URLMoniker_BindToStorage - ******************************************************************************/ -static HRESULT WINAPI URLMonikerImpl_BindToStorage(IMoniker* iface, - IBindCtx* pbc, - IMoniker* pmkToLeft, - REFIID riid, - VOID** ppvObject) -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - HRESULT hres; - BINDINFO bi; - DWORD bindf; - WCHAR szFileName[MAX_PATH + 1]; - Binding *bind; - int len; - - if(pmkToLeft) { - FIXME("pmkToLeft != NULL\n"); - return E_NOTIMPL; - } - if(!IsEqualIID(&IID_IStream, riid)) { - FIXME("unsupported iid\n"); - return E_NOTIMPL; - } - - bind = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Binding)); - bind->lpVtbl = &BindingVtbl; - bind->ref = 1; - URLMON_LockModule(); - - len = lstrlenW(This->URLName)+1; - bind->URLName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); - memcpy(bind->URLName, This->URLName, len*sizeof(WCHAR)); - - hres = UMCreateStreamOnCacheFile(bind->URLName, 0, szFileName, &bind->hCacheFile, &bind->pstrCache); - - if(SUCCEEDED(hres)) { - TRACE("Created stream...\n"); - - *ppvObject = (void *) bind->pstrCache; - IStream_AddRef((IStream *) bind->pstrCache); - - hres = IBindCtx_GetObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown**)&bind->pbscb); - if(SUCCEEDED(hres)) { - TRACE("Got IBindStatusCallback...\n"); - - memset(&bi, 0, sizeof(bi)); - bi.cbSize = sizeof(bi); - bindf = 0; - hres = IBindStatusCallback_GetBindInfo(bind->pbscb, &bindf, &bi); - if(SUCCEEDED(hres)) { - WCHAR *urlcopy, *tmpwc; - URL_COMPONENTSW url; - WCHAR *host, *path, *user, *pass; - DWORD lensz = sizeof(bind->expected_size); - DWORD dwService = 0; - BOOL bSuccess; - - TRACE("got bindinfo. bindf = %08lx extrainfo = %s bindinfof = %08lx bindverb = %08lx iid %s\n", - bindf, debugstr_w(bi.szExtraInfo), bi.grfBindInfoF, bi.dwBindVerb, debugstr_guid(&bi.iid)); - hres = IBindStatusCallback_OnStartBinding(bind->pbscb, 0, (IBinding*)bind); - TRACE("OnStartBinding rets %08lx\n", hres); - - /* This class will accept URLs with the backslash in them. But InternetCrackURL will not - it - * requires forward slashes (this is the behaviour of Microsoft's INETAPI). So we need to make - * a copy of the URL here and change the backslash to a forward slash everywhere it appears - - * but only before any '#' or '?', after which backslash should be left alone. - */ - urlcopy = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (lstrlenW(bind->URLName) + 1)); - lstrcpyW(urlcopy, bind->URLName); - for (tmpwc = urlcopy; *tmpwc && *tmpwc != '#' && *tmpwc != '?'; ++tmpwc) - if (*tmpwc == '\\') - *tmpwc = '/'; - -#if 0 - if(!registered_wndclass) { - WNDCLASSA urlmon_wndclass = {0, URLMON_WndProc,0, 0, URLMON_hInstance, 0, 0, 0, NULL, "URLMON_Callback_Window_Class"}; - RegisterClassA(&urlmon_wndclass); - registered_wndclass = TRUE; - } - - This->hwndCallback = CreateWindowA("URLMON_Callback_Window_Class", NULL, 0, 0, 0, 0, 0, 0, 0, - URLMON_hInstance, NULL); - -#endif - bind->expected_size = 0; - bind->total_read = 0; - - memset(&url, 0, sizeof(url)); - url.dwStructSize = sizeof(url); - url.dwSchemeLength = url.dwHostNameLength = url.dwUrlPathLength = url.dwUserNameLength = url.dwPasswordLength = 1; - InternetCrackUrlW(urlcopy, 0, 0, &url); - host = HeapAlloc(GetProcessHeap(), 0, (url.dwHostNameLength + 1) * sizeof(WCHAR)); - memcpy(host, url.lpszHostName, url.dwHostNameLength * sizeof(WCHAR)); - host[url.dwHostNameLength] = '\0'; - path = HeapAlloc(GetProcessHeap(), 0, (url.dwUrlPathLength + 1) * sizeof(WCHAR)); - memcpy(path, url.lpszUrlPath, url.dwUrlPathLength * sizeof(WCHAR)); - path[url.dwUrlPathLength] = '\0'; - if (url.dwUserNameLength) - { - user = HeapAlloc(GetProcessHeap(), 0, ((url.dwUserNameLength + 1) * sizeof(WCHAR))); - memcpy(user, url.lpszUserName, url.dwUserNameLength * sizeof(WCHAR)); - user[url.dwUserNameLength] = 0; - } - else - { - user = 0; - } - if (url.dwPasswordLength) - { - pass = HeapAlloc(GetProcessHeap(), 0, ((url.dwPasswordLength + 1) * sizeof(WCHAR))); - memcpy(pass, url.lpszPassword, url.dwPasswordLength * sizeof(WCHAR)); - pass[url.dwPasswordLength] = 0; - } - else - { - pass = 0; - } - - switch ((DWORD) url.nScheme) - { - case INTERNET_SCHEME_FTP: - case INTERNET_SCHEME_GOPHER: - case INTERNET_SCHEME_HTTP: - case INTERNET_SCHEME_HTTPS: - - bind->hinternet = InternetOpenA("User Agent", 0, NULL, NULL, 0 /*INTERNET_FLAG_ASYNC*/); -/* InternetSetStatusCallback(bind->hinternet, URLMON_InternetCallback);*/ - if (!bind->hinternet) - { - hres = HRESULT_FROM_WIN32(GetLastError()); - break; - } - - switch ((DWORD) url.nScheme) - { - case INTERNET_SCHEME_FTP: - if (!url.nPort) - url.nPort = INTERNET_DEFAULT_FTP_PORT; - dwService = INTERNET_SERVICE_FTP; - break; - - case INTERNET_SCHEME_GOPHER: - if (!url.nPort) - url.nPort = INTERNET_DEFAULT_GOPHER_PORT; - dwService = INTERNET_SERVICE_GOPHER; - break; - - case INTERNET_SCHEME_HTTP: - if (!url.nPort) - url.nPort = INTERNET_DEFAULT_HTTP_PORT; - dwService = INTERNET_SERVICE_HTTP; - break; - - case INTERNET_SCHEME_HTTPS: - if (!url.nPort) - url.nPort = INTERNET_DEFAULT_HTTPS_PORT; - dwService = INTERNET_SERVICE_HTTP; - break; - } - - bind->hconnect = InternetConnectW(bind->hinternet, host, url.nPort, user, pass, - dwService, 0, (DWORD)bind); - if (!bind->hconnect) - { - hres = HRESULT_FROM_WIN32(GetLastError()); - CloseHandle(bind->hinternet); - break; - } - - hres = IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, 0x22, NULL); - hres = IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_FINDINGRESOURCE, NULL); - hres = IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_CONNECTING, NULL); - hres = IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_SENDINGREQUEST, NULL); - - bSuccess = FALSE; - - switch (dwService) - { - case INTERNET_SERVICE_GOPHER: - bind->hrequest = GopherOpenFileW(bind->hconnect, - path, - 0, - INTERNET_FLAG_RELOAD, - 0); - if (bind->hrequest) - bSuccess = TRUE; - else - hres = HRESULT_FROM_WIN32(GetLastError()); - break; - - case INTERNET_SERVICE_FTP: - bind->hrequest = FtpOpenFileW(bind->hconnect, - path, - GENERIC_READ, - FTP_TRANSFER_TYPE_BINARY | - INTERNET_FLAG_TRANSFER_BINARY | - INTERNET_FLAG_RELOAD, - 0); - if (bind->hrequest) - bSuccess = TRUE; - else - hres = HRESULT_FROM_WIN32(GetLastError()); - break; - - case INTERNET_SERVICE_HTTP: - bind->hrequest = HttpOpenRequestW(bind->hconnect, NULL, path, NULL, NULL, NULL, 0, (DWORD)bind); - if (!bind->hrequest) - { - hres = HRESULT_FROM_WIN32(GetLastError()); - } - else if (!HttpSendRequestW(bind->hrequest, NULL, 0, NULL, 0)) - { - hres = HRESULT_FROM_WIN32(GetLastError()); - InternetCloseHandle(bind->hrequest); - } - else - { - HttpQueryInfoW(bind->hrequest, - HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, - &bind->expected_size, - &lensz, - NULL); - bSuccess = TRUE; - } - break; - } - if(bSuccess) - { - TRACE("res = %ld gle = %08lx url len = %ld\n", hres, GetLastError(), bind->expected_size); - - IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_CACHEFILENAMEAVAILABLE, szFileName); - - while(1) { - char buf[4096]; - DWORD bufread; - if(InternetReadFile(bind->hrequest, buf, sizeof(buf), &bufread)) { - TRACE("read %ld bytes %s...\n", bufread, debugstr_an(buf, 10)); - if(bufread == 0) break; - hres = Binding_MoreCacheData(bind, buf, bufread); - } else - break; - } - InternetCloseHandle(bind->hrequest); - hres = S_OK; - } - - InternetCloseHandle(bind->hconnect); - InternetCloseHandle(bind->hinternet); - break; - - case INTERNET_SCHEME_FILE: - path = bind->URLName + 5; /* Skip the "file:" part */ - if ((path[0] != '/' && path[0] != '\\') || - (path[1] != '/' && path[1] != '\\')) - { - hres = E_FAIL; - } - else - { - HANDLE h; - - path += 2; - if (path[0] == '/' || path[0] == '\\') - ++path; - h = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); - if (h == (HANDLE) HFILE_ERROR) - { - hres = HRESULT_FROM_WIN32(GetLastError()); - } - else - { - char buf[4096]; - DWORD bufread; - - IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_CACHEFILENAMEAVAILABLE, szFileName); - - while (ReadFile(h, buf, sizeof(buf), &bufread, NULL) && bufread > 0) - hres = Binding_MoreCacheData(bind, buf, bufread); - - CloseHandle(h); - hres = S_OK; - } - } - - break; - - default: - FIXME("Unsupported URI scheme"); - break; - } - Binding_CloseCacheDownload(bind); - Binding_FinishedDownload(bind, hres); - - if (user) - HeapFree(GetProcessHeap(), 0, user); - if (pass) - HeapFree(GetProcessHeap(), 0, pass); - HeapFree(GetProcessHeap(), 0, path); - HeapFree(GetProcessHeap(), 0, host); - HeapFree(GetProcessHeap(), 0, urlcopy); - } - } - } - - IBinding_Release((IBinding*)bind); - - return hres; -} - -/****************************************************************************** - * URLMoniker_Reduce - ******************************************************************************/ -static HRESULT WINAPI URLMonikerImpl_Reduce(IMoniker* iface, - IBindCtx* pbc, - DWORD dwReduceHowFar, - IMoniker** ppmkToLeft, - IMoniker** ppmkReduced) -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - - TRACE("(%p,%p,%ld,%p,%p)\n",This,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); - - if(!ppmkReduced) - return E_INVALIDARG; - - URLMonikerImpl_AddRef(iface); - *ppmkReduced = iface; - return MK_S_REDUCED_TO_SELF; -} - -/****************************************************************************** - * URLMoniker_ComposeWith - ******************************************************************************/ -static HRESULT WINAPI URLMonikerImpl_ComposeWith(IMoniker* iface, - IMoniker* pmkRight, - BOOL fOnlyIfNotGeneric, - IMoniker** ppmkComposite) -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - FIXME("(%p)->(%p,%d,%p): stub\n",This,pmkRight,fOnlyIfNotGeneric,ppmkComposite); - - return E_NOTIMPL; -} - -/****************************************************************************** - * URLMoniker_Enum - ******************************************************************************/ -static HRESULT WINAPI URLMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker) -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - TRACE("(%p,%d,%p)\n",This,fForward,ppenumMoniker); - - if(!ppenumMoniker) - return E_INVALIDARG; - - /* Does not support sub-monikers */ - *ppenumMoniker = NULL; - return S_OK; -} - -/****************************************************************************** - * URLMoniker_IsEqual - ******************************************************************************/ -static HRESULT WINAPI URLMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker) -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - CLSID clsid; - LPOLESTR urlPath; - IBindCtx* bind; - HRESULT res; - - TRACE("(%p,%p)\n",This,pmkOtherMoniker); - - if(pmkOtherMoniker==NULL) - return E_INVALIDARG; - - IMoniker_GetClassID(pmkOtherMoniker,&clsid); - - if(!IsEqualCLSID(&clsid,&CLSID_StdURLMoniker)) - return S_FALSE; - - res = CreateBindCtx(0,&bind); - if(FAILED(res)) - return res; - - res = S_FALSE; - if(SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&urlPath))) { - int result = lstrcmpiW(urlPath, This->URLName); - CoTaskMemFree(urlPath); - if(result == 0) - res = S_OK; - } - IUnknown_Release(bind); - return res; -} - - -/****************************************************************************** - * URLMoniker_Hash - ******************************************************************************/ -static HRESULT WINAPI URLMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash) -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - - int h = 0,i,skip,len; - int off = 0; - LPOLESTR val; - - TRACE("(%p,%p)\n",This,pdwHash); - - if(!pdwHash) - return E_INVALIDARG; - - val = This->URLName; - len = lstrlenW(val); - - if(len < 16) { - for(i = len ; i > 0; i--) { - h = (h * 37) + val[off++]; - } - } - else { - /* only sample some characters */ - skip = len / 8; - for(i = len; i > 0; i -= skip, off += skip) { - h = (h * 39) + val[off]; - } - } - *pdwHash = h; - return S_OK; -} - -/****************************************************************************** - * URLMoniker_IsRunning - ******************************************************************************/ -static HRESULT WINAPI URLMonikerImpl_IsRunning(IMoniker* iface, - IBindCtx* pbc, - IMoniker* pmkToLeft, - IMoniker* pmkNewlyRunning) -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - FIXME("(%p)->(%p,%p,%p): stub\n",This,pbc,pmkToLeft,pmkNewlyRunning); - - return E_NOTIMPL; -} - -/****************************************************************************** - * URLMoniker_GetTimeOfLastChange - ******************************************************************************/ -static HRESULT WINAPI URLMonikerImpl_GetTimeOfLastChange(IMoniker* iface, - IBindCtx* pbc, - IMoniker* pmkToLeft, - FILETIME* pFileTime) -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - FIXME("(%p)->(%p,%p,%p): stub\n",This,pbc,pmkToLeft,pFileTime); - - return E_NOTIMPL; -} - -/****************************************************************************** - * URLMoniker_Inverse - ******************************************************************************/ -static HRESULT WINAPI URLMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk) -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - TRACE("(%p,%p)\n",This,ppmk); - - return MK_E_NOINVERSE; -} - -/****************************************************************************** - * URLMoniker_CommonPrefixWith - ******************************************************************************/ -static HRESULT WINAPI URLMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix) -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - FIXME("(%p)->(%p,%p): stub\n",This,pmkOther,ppmkPrefix); - - return E_NOTIMPL; -} - -/****************************************************************************** - * URLMoniker_RelativePathTo - ******************************************************************************/ -static HRESULT WINAPI URLMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath) -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - FIXME("(%p)->(%p,%p): stub\n",This,pmOther,ppmkRelPath); - - return E_NOTIMPL; -} - -/****************************************************************************** - * URLMoniker_GetDisplayName - ******************************************************************************/ -static HRESULT WINAPI URLMonikerImpl_GetDisplayName(IMoniker* iface, - IBindCtx* pbc, - IMoniker* pmkToLeft, - LPOLESTR *ppszDisplayName) -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - - int len; - - TRACE("(%p,%p,%p,%p)\n",This,pbc,pmkToLeft,ppszDisplayName); - - if(!ppszDisplayName) - return E_INVALIDARG; - - /* FIXME: If this is a partial URL, try and get a URL moniker from SZ_URLCONTEXT in the bind context, - then look at pmkToLeft to try and complete the URL - */ - len = lstrlenW(This->URLName)+1; - *ppszDisplayName = CoTaskMemAlloc(len*sizeof(WCHAR)); - if(!*ppszDisplayName) - return E_OUTOFMEMORY; - lstrcpyW(*ppszDisplayName, This->URLName); - return S_OK; -} - -/****************************************************************************** - * URLMoniker_ParseDisplayName - ******************************************************************************/ -static HRESULT WINAPI URLMonikerImpl_ParseDisplayName(IMoniker* iface, - IBindCtx* pbc, - IMoniker* pmkToLeft, - LPOLESTR pszDisplayName, - ULONG* pchEaten, - IMoniker** ppmkOut) -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - FIXME("(%p)->(%p,%p,%p,%p,%p): stub\n",This,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut); - - return E_NOTIMPL; -} - -/****************************************************************************** - * URLMoniker_IsSystemMoniker - ******************************************************************************/ -static HRESULT WINAPI URLMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys) -{ - URLMonikerImpl *This = (URLMonikerImpl *)iface; - TRACE("(%p,%p)\n",This,pwdMksys); - - if(!pwdMksys) - return E_INVALIDARG; - - *pwdMksys = MKSYS_URLMONIKER; - return S_OK; -} - -/********************************************************************************/ -/* Virtual function table for the URLMonikerImpl class which include IPersist,*/ -/* IPersistStream and IMoniker functions. */ -static IMonikerVtbl VT_URLMonikerImpl = -{ - URLMonikerImpl_QueryInterface, - URLMonikerImpl_AddRef, - URLMonikerImpl_Release, - URLMonikerImpl_GetClassID, - URLMonikerImpl_IsDirty, - URLMonikerImpl_Load, - URLMonikerImpl_Save, - URLMonikerImpl_GetSizeMax, - URLMonikerImpl_BindToObject, - URLMonikerImpl_BindToStorage, - URLMonikerImpl_Reduce, - URLMonikerImpl_ComposeWith, - URLMonikerImpl_Enum, - URLMonikerImpl_IsEqual, - URLMonikerImpl_Hash, - URLMonikerImpl_IsRunning, - URLMonikerImpl_GetTimeOfLastChange, - URLMonikerImpl_Inverse, - URLMonikerImpl_CommonPrefixWith, - URLMonikerImpl_RelativePathTo, - URLMonikerImpl_GetDisplayName, - URLMonikerImpl_ParseDisplayName, - URLMonikerImpl_IsSystemMoniker -}; - -/****************************************************************************** - * URLMoniker_Construct (local function) - *******************************************************************************/ -static HRESULT URLMonikerImpl_Construct(URLMonikerImpl* This, LPCOLESTR lpszLeftURLName, LPCOLESTR lpszURLName) -{ - HRESULT hres; - DWORD sizeStr; - - TRACE("(%p,%s,%s)\n",This,debugstr_w(lpszLeftURLName),debugstr_w(lpszURLName)); - memset(This, 0, sizeof(*This)); - - /* Initialize the virtual function table. */ - This->lpvtbl = &VT_URLMonikerImpl; - This->ref = 0; - - if(lpszLeftURLName) { - hres = UrlCombineW(lpszLeftURLName, lpszURLName, NULL, &sizeStr, 0); - if(FAILED(hres)) { - return hres; - } - sizeStr++; - } - else - sizeStr = lstrlenW(lpszURLName)+1; - - This->URLName=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr)); - - if (This->URLName==NULL) - return E_OUTOFMEMORY; - - if(lpszLeftURLName) { - hres = UrlCombineW(lpszLeftURLName, lpszURLName, This->URLName, &sizeStr, 0); - if(FAILED(hres)) { - HeapFree(GetProcessHeap(), 0, This->URLName); - return hres; - } - } - else - strcpyW(This->URLName,lpszURLName); - - return S_OK; -} - -/*********************************************************************** - * CreateAsyncBindCtx (URLMON.@) - */ -HRESULT WINAPI CreateAsyncBindCtx(DWORD reserved, IBindStatusCallback *callback, - IEnumFORMATETC *format, IBindCtx **pbind) -{ - HRESULT hres; - BIND_OPTS bindopts; - IBindCtx *bctx; - - TRACE("(%08lx %p %p %p)\n", reserved, callback, format, pbind); - - if(!callback) - return E_INVALIDARG; - if(format) - FIXME("format is not supported yet\n"); - - hres = CreateBindCtx(0, &bctx); - if(FAILED(hres)) - return hres; - - bindopts.cbStruct = sizeof(BIND_OPTS); - bindopts.grfFlags = BIND_MAYBOTHERUSER; - bindopts.grfMode = STGM_READWRITE | STGM_SHARE_EXCLUSIVE; - bindopts.dwTickCountDeadline = 0; - IBindCtx_SetBindOptions(bctx, &bindopts); - - hres = IBindCtx_RegisterObjectParam(bctx, (LPOLESTR)BSCBHolder, (IUnknown*)callback); - if(FAILED(hres)) { - IBindCtx_Release(bctx); - return hres; - } - - *pbind = bctx; - - return S_OK; -} -/*********************************************************************** - * CreateAsyncBindCtxEx (URLMON.@) - * - * Create an asynchronous bind context. - * - * FIXME - * Not implemented. - */ -HRESULT WINAPI CreateAsyncBindCtxEx(IBindCtx *ibind, DWORD options, - IBindStatusCallback *callback, IEnumFORMATETC *format, IBindCtx** pbind, - DWORD reserved) -{ - FIXME("stub, returns failure\n"); - return E_INVALIDARG; -} - - -/*********************************************************************** - * CreateURLMoniker (URLMON.@) - * - * Create a url moniker. - * - * PARAMS - * pmkContext [I] Context - * szURL [I] Url to create the moniker for - * ppmk [O] Destination for created moniker. - * - * RETURNS - * Success: S_OK. ppmk contains the created IMoniker object. - * Failure: MK_E_SYNTAX if szURL is not a valid url, or - * E_OUTOFMEMORY if memory allocation fails. - */ -HRESULT WINAPI CreateURLMoniker(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk) -{ - URLMonikerImpl *obj; - HRESULT hres; - IID iid = IID_IMoniker; - LPOLESTR lefturl = NULL; - - TRACE("(%p, %s, %p)\n", pmkContext, debugstr_w(szURL), ppmk); - - if(!(obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj)))) - return E_OUTOFMEMORY; - - if(pmkContext) { - CLSID clsid; - IBindCtx* bind; - IMoniker_GetClassID(pmkContext, &clsid); - if(IsEqualCLSID(&clsid, &CLSID_StdURLMoniker) && SUCCEEDED(CreateBindCtx(0, &bind))) { - URLMonikerImpl_GetDisplayName(pmkContext, bind, NULL, &lefturl); - IBindCtx_Release(bind); - } - } - - hres = URLMonikerImpl_Construct(obj, lefturl, szURL); - CoTaskMemFree(lefturl); - if(SUCCEEDED(hres)) - hres = URLMonikerImpl_QueryInterface((IMoniker*)obj, &iid, (void**)ppmk); - else - HeapFree(GetProcessHeap(), 0, obj); - return hres; -} - - -/*********************************************************************** - * CoInternetGetSession (URLMON.@) - * - * Create a new internet session and return an IInternetSession interface - * representing it. - * - * PARAMS - * dwSessionMode [I] Mode for the internet session - * ppIInternetSession [O] Destination for creates IInternetSession object - * dwReserved [I] Reserved, must be 0. - * - * RETURNS - * Success: S_OK. ppIInternetSession contains the IInternetSession interface. - * Failure: E_INVALIDARG, if any argument is invalid, or - * E_OUTOFMEMORY if memory allocation fails. - */ -HRESULT WINAPI CoInternetGetSession(DWORD dwSessionMode, IInternetSession **ppIInternetSession, DWORD dwReserved) -{ - FIXME("(%ld, %p, %ld): stub\n", dwSessionMode, ppIInternetSession, dwReserved); - - if(dwSessionMode) { - ERR("dwSessionMode: %ld, must be zero\n", dwSessionMode); - } - - if(dwReserved) { - ERR("dwReserved: %ld, must be zero\n", dwReserved); - } - - *ppIInternetSession=NULL; - return E_OUTOFMEMORY; -} - -/*********************************************************************** - * CoInternetQueryInfo (URLMON.@) - * - * Retrieves information relevant to a specified URL - * - * RETURNS - * S_OK success - * S_FALSE buffer too small - * INET_E_QUERYOPTIONUNKNOWN invalid option - * - */ -HRESULT WINAPI CoInternetQueryInfo(LPCWSTR pwzUrl, QUERYOPTION QueryOption, - DWORD dwQueryFlags, LPVOID pvBuffer, DWORD cbBuffer, DWORD * pcbBuffer, - DWORD dwReserved) -{ - FIXME("(%s, %x, %lx, %p, %lx, %p, %lx): stub\n", debugstr_w(pwzUrl), - QueryOption, dwQueryFlags, pvBuffer, cbBuffer, pcbBuffer, dwReserved); - return S_OK; -} - -static BOOL URLMON_IsBinary(LPVOID pBuffer, DWORD cbSize) -{ - unsigned int i, binarycount = 0; - unsigned char *buff = pBuffer; - for(i=0; i<cbSize; i++) { - if(buff[i] < 32) - binarycount++; - } - return binarycount > (cbSize-binarycount); -} - -/*********************************************************************** - * FindMimeFromData (URLMON.@) - * - * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided. - * - * NOTE - * See http://msdn.microsoft.com/workshop/networking/moniker/overview/appendix_a.asp - */ -HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer, - DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags, - LPWSTR* ppwzMimeOut, DWORD dwReserved) -{ - static const WCHAR szBinaryMime[] = {'a','p','p','l','i','c','a','t','i','o','n','/','o','c','t','e','t','-','s','t','r','e','a','m','\0'}; - static const WCHAR szTextMime[] = {'t','e','x','t','/','p','l','a','i','n','\0'}; - static const WCHAR szContentType[] = {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'}; - WCHAR szTmpMime[256]; - LPCWSTR mimeType = NULL; - HKEY hKey = NULL; - - TRACE("(%p,%s,%p,%ld,%s,0x%lx,%p,0x%lx)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize, - debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved); - - if((!pwzUrl && (!pBuffer || cbSize <= 0)) || !ppwzMimeOut) - return E_INVALIDARG; - - if(pwzMimeProposed) - mimeType = pwzMimeProposed; - else { - /* Try and find the mime type in the registry */ - if(pwzUrl) { - LPWSTR ext = strrchrW(pwzUrl, '.'); - if(ext) { - DWORD dwSize; - if(!RegOpenKeyExW(HKEY_CLASSES_ROOT, ext, 0, 0, &hKey)) { - if(!RegQueryValueExW(hKey, szContentType, NULL, NULL, (LPBYTE)szTmpMime, &dwSize)) { - mimeType = szTmpMime; - } - RegCloseKey(hKey); - } - } - } - } - if(!mimeType && pBuffer && cbSize > 0) - mimeType = URLMON_IsBinary(pBuffer, cbSize)?szBinaryMime:szTextMime; - - TRACE("Using %s\n", debugstr_w(mimeType)); - *ppwzMimeOut = CoTaskMemAlloc((lstrlenW(mimeType)+1)*sizeof(WCHAR)); - if(!*ppwzMimeOut) return E_OUTOFMEMORY; - lstrcpyW(*ppwzMimeOut, mimeType); - return S_OK; -} - -/*********************************************************************** - * IsAsyncMoniker (URLMON.@) - */ -HRESULT WINAPI IsAsyncMoniker(IMoniker *pmk) -{ - IUnknown *am; - - TRACE("(%p)\n", pmk); - if(!pmk) - return E_INVALIDARG; - if(SUCCEEDED(IMoniker_QueryInterface(pmk, &IID_IAsyncMoniker, (void**)&am))) { - IUnknown_Release(am); - return S_OK; - } - return S_FALSE; -} - -/*********************************************************************** - * RegisterBindStatusCallback (URLMON.@) - * - * Register a bind status callback. - * - * PARAMS - * pbc [I] Binding context - * pbsc [I] Callback to register - * ppbscPrevious [O] Destination for previous callback - * dwReserved [I] Reserved, must be 0. - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if any argument is invalid, or - * E_OUTOFMEMORY if memory allocation fails. - */ -HRESULT WINAPI RegisterBindStatusCallback( - IBindCtx *pbc, - IBindStatusCallback *pbsc, - IBindStatusCallback **ppbscPrevious, - DWORD dwReserved) -{ - IBindStatusCallback *prev; - - TRACE("(%p,%p,%p,%lu)\n", pbc, pbsc, ppbscPrevious, dwReserved); - - if (pbc == NULL || pbsc == NULL) - return E_INVALIDARG; - - if (SUCCEEDED(IBindCtx_GetObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown **)&prev))) - { - IBindCtx_RevokeObjectParam(pbc, (LPOLESTR)BSCBHolder); - if (ppbscPrevious) - *ppbscPrevious = prev; - else - IBindStatusCallback_Release(prev); - } - - return IBindCtx_RegisterObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown *)pbsc); -} - -/*********************************************************************** - * RevokeBindStatusCallback (URLMON.@) - * - * Unregister a bind status callback. - * - * pbc [I] Binding context - * pbsc [I] Callback to unregister - * - * RETURNS - * Success: S_OK. - * Failure: E_INVALIDARG, if any argument is invalid, or - * E_FAIL if pbsc wasn't registered with pbc. - */ -HRESULT WINAPI RevokeBindStatusCallback( - IBindCtx *pbc, - IBindStatusCallback *pbsc) -{ - IBindStatusCallback *callback; - HRESULT hr = E_FAIL; - - TRACE("(%p,%p)\n", pbc, pbsc); - - if (pbc == NULL || pbsc == NULL) - return E_INVALIDARG; - - if (SUCCEEDED(IBindCtx_GetObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown **)&callback))) - { - if (callback == pbsc) - { - IBindCtx_RevokeObjectParam(pbc, (LPOLESTR)BSCBHolder); - hr = S_OK; - } - IBindStatusCallback_Release(pbsc); - } - - return hr; -} - -/*********************************************************************** - * ReleaseBindInfo (URLMON.@) - * - * Release the resources used by the specified BINDINFO structure. - * - * PARAMS - * pbindinfo [I] BINDINFO to release. - * - * RETURNS - * Nothing. - */ -void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo) -{ - FIXME("(%p)stub!\n", pbindinfo); -} - -/*********************************************************************** - * URLDownloadToFileA (URLMON.@) - * - * Downloads URL szURL to rile szFileName and call lpfnCB callback to - * report progress. - * - * PARAMS - * pCaller [I] controlling IUnknown interface. - * szURL [I] URL of the file to download - * szFileName [I] file name to store the content of the URL - * dwReserved [I] reserved - set to 0 - * lpfnCB [I] callback for progress report - * - * RETURNS - * S_OK on success - * E_OUTOFMEMORY when going out of memory - */ -HRESULT WINAPI URLDownloadToFileA(LPUNKNOWN pCaller, - LPCSTR szURL, - LPCSTR szFileName, - DWORD dwReserved, - LPBINDSTATUSCALLBACK lpfnCB) -{ - UNICODE_STRING szURL_w, szFileName_w; - - if ((szURL == NULL) || (szFileName == NULL)) { - FIXME("(%p,%s,%s,%08lx,%p) cannot accept NULL strings !\n", pCaller, debugstr_a(szURL), debugstr_a(szFileName), dwReserved, lpfnCB); - return E_INVALIDARG; /* The error code is not specified in this case... */ - } - - if (RtlCreateUnicodeStringFromAsciiz(&szURL_w, szURL)) { - if (RtlCreateUnicodeStringFromAsciiz(&szFileName_w, szFileName)) { - HRESULT ret = URLDownloadToFileW(pCaller, szURL_w.Buffer, szFileName_w.Buffer, dwReserved, lpfnCB); - - RtlFreeUnicodeString(&szURL_w); - RtlFreeUnicodeString(&szFileName_w); - - return ret; - } else { - RtlFreeUnicodeString(&szURL_w); - } - } - - FIXME("(%p,%s,%s,%08lx,%p) could not allocate W strings !\n", pCaller, szURL, szFileName, dwReserved, lpfnCB); - return E_OUTOFMEMORY; -} - -/*********************************************************************** - * URLDownloadToFileW (URLMON.@) - * - * Downloads URL szURL to rile szFileName and call lpfnCB callback to - * report progress. - * - * PARAMS - * pCaller [I] controlling IUnknown interface. - * szURL [I] URL of the file to download - * szFileName [I] file name to store the content of the URL - * dwReserved [I] reserved - set to 0 - * lpfnCB [I] callback for progress report - * - * RETURNS - * S_OK on success - * E_OUTOFMEMORY when going out of memory - */ -HRESULT WINAPI URLDownloadToFileW(LPUNKNOWN pCaller, - LPCWSTR szURL, - LPCWSTR szFileName, - DWORD dwReserved, - LPBINDSTATUSCALLBACK lpfnCB) -{ - HINTERNET hinternet, hcon, hreq; - BOOL r; - CHAR buffer[0x1000]; - DWORD sz, total, written; - DWORD total_size = 0xFFFFFFFF, arg_size = sizeof(total_size); - URL_COMPONENTSW url; - WCHAR host[0x80], path[0x100]; - HANDLE hfile; - static const WCHAR wszAppName[]={'u','r','l','m','o','n','.','d','l','l',0}; - - /* Note: all error codes would need to be checked agains real Windows behaviour... */ - TRACE("(%p,%s,%s,%08lx,%p) stub!\n", pCaller, debugstr_w(szURL), debugstr_w(szFileName), dwReserved, lpfnCB); - - if ((szURL == NULL) || (szFileName == NULL)) { - FIXME(" cannot accept NULL strings !\n"); - return E_INVALIDARG; - } - - /* Would be better to use the application name here rather than 'urlmon' :-/ */ - hinternet = InternetOpenW(wszAppName, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); - if (hinternet == NULL) { - return E_OUTOFMEMORY; - } - - memset(&url, 0, sizeof(url)); - url.dwStructSize = sizeof(url); - url.lpszHostName = host; - url.dwHostNameLength = sizeof(host); - url.lpszUrlPath = path; - url.dwUrlPathLength = sizeof(path); - - if (!InternetCrackUrlW(szURL, 0, 0, &url)) { - InternetCloseHandle(hinternet); - return E_OUTOFMEMORY; - } - - if (lpfnCB) { - if (IBindStatusCallback_OnProgress(lpfnCB, 0, 0, BINDSTATUS_CONNECTING, url.lpszHostName) == E_ABORT) { - InternetCloseHandle(hinternet); - return S_OK; - } - } - - hcon = InternetConnectW(hinternet, url.lpszHostName, url.nPort, - url.lpszUserName, url.lpszPassword, - INTERNET_SERVICE_HTTP, 0, 0); - if (!hcon) { - InternetCloseHandle(hinternet); - return E_OUTOFMEMORY; - } - - hreq = HttpOpenRequestW(hcon, NULL, url.lpszUrlPath, NULL, NULL, NULL, 0, 0); - if (!hreq) { - InternetCloseHandle(hinternet); - InternetCloseHandle(hcon); - return E_OUTOFMEMORY; - } - - if (!HttpSendRequestW(hreq, NULL, 0, NULL, 0)) { - InternetCloseHandle(hinternet); - InternetCloseHandle(hcon); - InternetCloseHandle(hreq); - return E_OUTOFMEMORY; - } - - if (HttpQueryInfoW(hreq, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, - &total_size, &arg_size, NULL)) { - TRACE(" total size : %ld\n", total_size); - } - - hfile = CreateFileW(szFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL ); - if (hfile == INVALID_HANDLE_VALUE) { - return E_ACCESSDENIED; - } - - if (lpfnCB) { - if (IBindStatusCallback_OnProgress(lpfnCB, 0, total_size != 0xFFFFFFFF ? total_size : 0, - BINDSTATUS_BEGINDOWNLOADDATA, szURL) == E_ABORT) { - InternetCloseHandle(hreq); - InternetCloseHandle(hcon); - InternetCloseHandle(hinternet); - CloseHandle(hfile); - return S_OK; - } - } - - total = 0; - while (1) { - r = InternetReadFile(hreq, buffer, sizeof(buffer), &sz); - if (!r) { - InternetCloseHandle(hreq); - InternetCloseHandle(hcon); - InternetCloseHandle(hinternet); - - CloseHandle(hfile); - return E_OUTOFMEMORY; - } - if (!sz) - break; - - total += sz; - - if (lpfnCB) { - if (IBindStatusCallback_OnProgress(lpfnCB, total, total_size != 0xFFFFFFFF ? total_size : 0, - BINDSTATUS_DOWNLOADINGDATA, szURL) == E_ABORT) { - InternetCloseHandle(hreq); - InternetCloseHandle(hcon); - InternetCloseHandle(hinternet); - CloseHandle(hfile); - return S_OK; - } - } - - if (!WriteFile(hfile, buffer, sz, &written, NULL)) { - InternetCloseHandle(hreq); - InternetCloseHandle(hcon); - InternetCloseHandle(hinternet); - - CloseHandle(hfile); - return E_OUTOFMEMORY; - } - } - - if (lpfnCB) { - if (IBindStatusCallback_OnProgress(lpfnCB, total, total_size != 0xFFFFFFFF ? total_size : 0, - BINDSTATUS_ENDDOWNLOADDATA, szURL) == E_ABORT) { - InternetCloseHandle(hreq); - InternetCloseHandle(hcon); - InternetCloseHandle(hinternet); - CloseHandle(hfile); - return S_OK; - } - } - - InternetCloseHandle(hreq); - InternetCloseHandle(hcon); - InternetCloseHandle(hinternet); - - CloseHandle(hfile); - - return S_OK; -} - -/*********************************************************************** - * HlinkSimpleNavigateToString (URLMON.@) - */ -HRESULT WINAPI HlinkSimpleNavigateToString( LPCWSTR szTarget, - LPCWSTR szLocation, LPCWSTR szTargetFrameName, IUnknown *pUnk, - IBindCtx *pbc, IBindStatusCallback *pbsc, DWORD grfHLNF, DWORD dwReserved) -{ - FIXME("%s\n", debugstr_w( szTarget ) ); - return E_NOTIMPL; -} - -/*********************************************************************** - * HlinkNavigateString (URLMON.@) - */ -HRESULT WINAPI HlinkNavigateString( IUnknown *pUnk, LPCWSTR szTarget ) -{ - TRACE("%p %s\n", pUnk, debugstr_w( szTarget ) ); - return HlinkSimpleNavigateToString( - szTarget, NULL, NULL, pUnk, NULL, NULL, 0, 0 ); -} +/* + * UrlMon + * + * Copyright 1999 Ulrich Czekalla for Corel Corporation + * Copyright 2002 Huw D M Davies for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define COM_NO_WINDOWS_H +#include <stdarg.h> +#include <stdio.h> + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winternl.h" +#include "winuser.h" +#include "objbase.h" +#include "wine/debug.h" +#include "wine/unicode.h" +#include "ole2.h" +#include "urlmon.h" +#include "wininet.h" +#include "shlwapi.h" +#include "urlmon_main.h" + +WINE_DEFAULT_DEBUG_CHANNEL(urlmon); + +/* native urlmon.dll uses this key, too */ +static const WCHAR BSCBHolder[] = { '_','B','S','C','B','_','H','o','l','d','e','r','_',0 }; + +/*static BOOL registered_wndclass = FALSE;*/ + +typedef struct { + IBindingVtbl *lpVtbl; + + ULONG ref; + + LPWSTR URLName; + + HWND hwndCallback; + IBindCtx *pBC; + HINTERNET hinternet, hconnect, hrequest; + HANDLE hCacheFile; + IUMCacheStream *pstrCache; + IBindStatusCallback *pbscb; + DWORD total_read, expected_size; +} Binding; + +static HRESULT WINAPI Binding_QueryInterface(IBinding* iface, REFIID riid, void **ppvObject) +{ + Binding *This = (Binding*)iface; + + TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppvObject); + + if((This == NULL) || (ppvObject == NULL)) + return E_INVALIDARG; + + if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IBinding, riid)) { + *ppvObject = iface; + IBinding_AddRef(iface); + return S_OK; + } + + *ppvObject = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI Binding_AddRef(IBinding* iface) +{ + Binding *This = (Binding*)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%ld\n", This, ref); + + return ref; +} + +static ULONG WINAPI Binding_Release(IBinding* iface) +{ + Binding *This = (Binding*)iface; + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%ld\n",This, ref); + + if(!ref) { + HeapFree(GetProcessHeap(), 0, This->URLName); + if (This->hCacheFile) + CloseHandle(This->hCacheFile); + if (This->pstrCache) + { + UMCloseCacheFileStream(This->pstrCache); + IStream_Release((IStream *)This->pstrCache); + } + if (This->pbscb) + IBindStatusCallback_Release(This->pbscb); + + HeapFree(GetProcessHeap(), 0, This); + + URLMON_UnlockModule(); + } + + return ref; +} + +static HRESULT WINAPI Binding_Abort(IBinding* iface) +{ + Binding *This = (Binding*)iface; + + FIXME("(%p): stub\n", This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI Binding_GetBindResult(IBinding* iface, CLSID* pclsidProtocol, DWORD* pdwResult, LPOLESTR* pszResult, DWORD* pdwReserved) +{ + Binding *This = (Binding*)iface; + + FIXME("(%p)->(%p, %p, %p, %p): stub\n", This, pclsidProtocol, pdwResult, pszResult, pdwReserved); + + return E_NOTIMPL; +} + +static HRESULT WINAPI Binding_GetPriority(IBinding* iface, LONG* pnPriority) +{ + Binding *This = (Binding*)iface; + + FIXME("(%p)->(%p): stub\n", This, pnPriority); + + return E_NOTIMPL; +} + +static HRESULT WINAPI Binding_Resume(IBinding* iface) +{ + Binding *This = (Binding*)iface; + + FIXME("(%p): stub\n", This); + + return E_NOTIMPL; +} + +static HRESULT WINAPI Binding_SetPriority(IBinding* iface, LONG nPriority) +{ + Binding *This = (Binding*)iface; + + FIXME("(%p)->(%ld): stub\n", This, nPriority); + + return E_NOTIMPL; +} + +static HRESULT WINAPI Binding_Suspend(IBinding* iface) +{ + Binding *This = (Binding*)iface; + + FIXME("(%p): stub\n", This); + + return E_NOTIMPL; +} + +static void Binding_CloseCacheDownload(Binding *This) +{ + CloseHandle(This->hCacheFile); + This->hCacheFile = 0; + UMCloseCacheFileStream(This->pstrCache); + IStream_Release((IStream *)This->pstrCache); + This->pstrCache = 0; +} + +static HRESULT Binding_MoreCacheData(Binding *This, char *buf, DWORD dwBytes) +{ + DWORD written; + + if (WriteFile(This->hCacheFile, buf, dwBytes, &written, NULL) && written == dwBytes) + { + HRESULT hr; + + This->total_read += written; + hr = IBindStatusCallback_OnProgress(This->pbscb, + This->total_read + written, + This->expected_size, + (This->total_read == written) ? + BINDSTATUS_BEGINDOWNLOADDATA : + BINDSTATUS_DOWNLOADINGDATA, + NULL); + if (!hr) + { + STGMEDIUM stg; + FORMATETC fmt; + + fmt.cfFormat = 0; + fmt.ptd = NULL; + fmt.dwAspect = 0; + fmt.lindex = -1; + fmt.tymed = TYMED_ISTREAM; + + stg.tymed = TYMED_ISTREAM; + stg.u.pstm = (IStream *)This->pstrCache; + stg.pUnkForRelease = NULL; + + hr = IBindStatusCallback_OnDataAvailable(This->pbscb, + (This->total_read == written) ? + BSCF_FIRSTDATANOTIFICATION : + BSCF_INTERMEDIATEDATANOTIFICATION, + This->total_read + written, + &fmt, + &stg); + } + if (written < dwBytes) + return STG_E_MEDIUMFULL; + else + return hr; + } + return HRESULT_FROM_WIN32(GetLastError()); +} + +static void Binding_FinishedDownload(Binding *This, HRESULT hr) +{ + STGMEDIUM stg; + FORMATETC fmt; + + fmt.ptd = NULL; + fmt.dwAspect = 0; + fmt.lindex = -1; + fmt.tymed = TYMED_ISTREAM; + + stg.tymed = TYMED_ISTREAM; + stg.u.pstm = (IStream *)This->pstrCache; + stg.pUnkForRelease = NULL; + + IBindStatusCallback_OnProgress(This->pbscb, This->total_read, This->expected_size, BINDSTATUS_ENDDOWNLOADDATA, NULL); + IBindStatusCallback_OnDataAvailable(This->pbscb, BSCF_LASTDATANOTIFICATION, This->total_read, &fmt, &stg); + if (hr) + { + WCHAR *pwchError = 0; + + FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, (DWORD) hr, + 0, (LPWSTR) &pwchError, + 0, NULL); + if (!pwchError) + { + static WCHAR achFormat[] = { '%', '0', '8', 'x', 0 }; + + pwchError =(WCHAR *) LocalAlloc(LMEM_FIXED, sizeof(WCHAR) * 9); + wsprintfW(pwchError, achFormat, hr); + } + IBindStatusCallback_OnStopBinding(This->pbscb, hr, pwchError); + LocalFree(pwchError); + } + else + { + IBindStatusCallback_OnStopBinding(This->pbscb, hr, NULL); + } + IBindStatusCallback_Release(This->pbscb); + This->pbscb = 0; +} + +static IBindingVtbl BindingVtbl = +{ + Binding_QueryInterface, + Binding_AddRef, + Binding_Release, + Binding_Abort, + Binding_Suspend, + Binding_Resume, + Binding_SetPriority, + Binding_GetPriority, + Binding_GetBindResult +}; + +/* filemoniker data structure */ +typedef struct { + + IMonikerVtbl* lpvtbl; /* VTable relative to the IMoniker interface.*/ + + ULONG ref; /* reference counter for this object */ + + LPOLESTR URLName; /* URL string identified by this URLmoniker */ +} URLMonikerImpl; + +/******************************************************************************* + * URLMoniker_QueryInterface + *******************************************************************************/ +static HRESULT WINAPI URLMonikerImpl_QueryInterface(IMoniker* iface,REFIID riid,void** ppvObject) +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + + TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppvObject); + + /* Perform a sanity check on the parameters.*/ + if ( (This==0) || (ppvObject==0) ) + return E_INVALIDARG; + + /* Initialize the return parameter */ + *ppvObject = 0; + + /* Compare the riid with the interface IDs implemented by this object.*/ + if (IsEqualIID(&IID_IUnknown, riid) || + IsEqualIID(&IID_IPersist, riid) || + IsEqualIID(&IID_IPersistStream,riid) || + IsEqualIID(&IID_IMoniker, riid) + ) + *ppvObject = iface; + + /* Check that we obtained an interface.*/ + if ((*ppvObject)==0) + return E_NOINTERFACE; + + /* Query Interface always increases the reference count by one when it is successful */ + IMoniker_AddRef(iface); + + return S_OK; +} + +/****************************************************************************** + * URLMoniker_AddRef + ******************************************************************************/ +static ULONG WINAPI URLMonikerImpl_AddRef(IMoniker* iface) +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + ULONG refCount = InterlockedIncrement(&This->ref); + + TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1); + + URLMON_LockModule(); + + return refCount; +} + +/****************************************************************************** + * URLMoniker_Release + ******************************************************************************/ +static ULONG WINAPI URLMonikerImpl_Release(IMoniker* iface) +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + ULONG refCount = InterlockedDecrement(&This->ref); + + TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1); + + /* destroy the object if there's no more reference on it */ + if (!refCount) { + HeapFree(GetProcessHeap(),0,This->URLName); + HeapFree(GetProcessHeap(),0,This); + } + + URLMON_UnlockModule(); + + return refCount; +} + + +/****************************************************************************** + * URLMoniker_GetClassID + ******************************************************************************/ +static HRESULT WINAPI URLMonikerImpl_GetClassID(IMoniker* iface, + CLSID *pClassID)/* Pointer to CLSID of object */ +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + + TRACE("(%p,%p)\n",This,pClassID); + + if (pClassID==NULL) + return E_POINTER; + /* Windows always returns CLSID_StdURLMoniker */ + *pClassID = CLSID_StdURLMoniker; + return S_OK; +} + +/****************************************************************************** + * URLMoniker_IsDirty + ******************************************************************************/ +static HRESULT WINAPI URLMonikerImpl_IsDirty(IMoniker* iface) +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + /* Note that the OLE-provided implementations of the IPersistStream::IsDirty + method in the OLE-provided moniker interfaces always return S_FALSE because + their internal state never changes. */ + + TRACE("(%p)\n",This); + + return S_FALSE; +} + +/****************************************************************************** + * URLMoniker_Load + * + * NOTE + * Writes a ULONG containing length of unicode string, followed + * by that many unicode characters + ******************************************************************************/ +static HRESULT WINAPI URLMonikerImpl_Load(IMoniker* iface,IStream* pStm) +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + + HRESULT res; + ULONG len; + ULONG got; + TRACE("(%p,%p)\n",This,pStm); + + if(!pStm) + return E_INVALIDARG; + + res = IStream_Read(pStm, &len, sizeof(ULONG), &got); + if(SUCCEEDED(res)) { + if(got == sizeof(ULONG)) { + HeapFree(GetProcessHeap(), 0, This->URLName); + This->URLName=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(len+1)); + if(!This->URLName) + res = E_OUTOFMEMORY; + else { + res = IStream_Read(pStm, This->URLName, len, NULL); + This->URLName[len] = 0; + } + } + else + res = E_FAIL; + } + return res; +} + +/****************************************************************************** + * URLMoniker_Save + ******************************************************************************/ +static HRESULT WINAPI URLMonikerImpl_Save(IMoniker* iface, + IStream* pStm,/* pointer to the stream where the object is to be saved */ + BOOL fClearDirty)/* Specifies whether to clear the dirty flag */ +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + + HRESULT res; + ULONG len; + TRACE("(%p,%p,%d)\n",This,pStm,fClearDirty); + + if(!pStm) + return E_INVALIDARG; + + len = strlenW(This->URLName); + res=IStream_Write(pStm,&len,sizeof(ULONG),NULL); + if(SUCCEEDED(res)) + res=IStream_Write(pStm,&This->URLName,len*sizeof(WCHAR),NULL); + return res; + +} + +/****************************************************************************** + * URLMoniker_GetSizeMax + ******************************************************************************/ +static HRESULT WINAPI URLMonikerImpl_GetSizeMax(IMoniker* iface, + ULARGE_INTEGER* pcbSize)/* Pointer to size of stream needed to save object */ +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + + TRACE("(%p,%p)\n",This,pcbSize); + + if(!pcbSize) + return E_INVALIDARG; + + pcbSize->u.LowPart = sizeof(ULONG) + (strlenW(This->URLName) * sizeof(WCHAR)); + pcbSize->u.HighPart = 0; + return S_OK; +} + +/****************************************************************************** + * URLMoniker_BindToObject + ******************************************************************************/ +static HRESULT WINAPI URLMonikerImpl_BindToObject(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + REFIID riid, + VOID** ppvResult) +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + + *ppvResult=0; + + FIXME("(%p)->(%p,%p,%s,%p): stub\n",This,pbc,pmkToLeft,debugstr_guid(riid), + ppvResult); + + return E_NOTIMPL; +} + +typedef struct { + enum {OnProgress, OnDataAvailable} callback; +} URLMON_CallbackData; + + +#if 0 +static LRESULT CALLBACK URLMON_WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + return DefWindowProcA(hwnd, msg, wparam, lparam); +} + +static void PostOnProgress(URLMonikerImpl *This, UINT progress, UINT maxprogress, DWORD status, LPCWSTR *str) +{ +} + +static void CALLBACK URLMON_InternetCallback(HINTERNET hinet, /*DWORD_PTR*/ DWORD context, DWORD status, + void *status_info, DWORD status_info_len) +{ + URLMonikerImpl *This = (URLMonikerImpl *)context; + TRACE("handle %p this %p status %08lx\n", hinet, This, status); + + if(This->filesize == -1) { + switch(status) { + case INTERNET_STATUS_RESOLVING_NAME: + PostOnProgess(This, 0, 0, BINDSTATUS_FINDINGRESOURCE, status_info); + break; + case INTERNET_STATUS_CONNECTING_TO_SERVER: + PostOnProgress(This, 0, 0, BINDSTATUS_CONNECTING, NULL); + break; + case INTERNET_STATUS_SENDING_REQUEST: + PostOnProgress(This, 0, 0, BINDSTATUS_SENDINGREQUEST, NULL); + break; + case INTERNET_REQUEST_COMPLETE: + { + DWORD len, lensz = sizeof(len); + + HttpQueryInfoW(hrequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &len, &lensz, NULL); + TRACE("res = %ld gle = %08lx url len = %ld\n", hres, GetLastError(), len); + This->filesize = len; + break; + } + } + } + + return; +} +#endif + + +/****************************************************************************** + * URLMoniker_BindToStorage + ******************************************************************************/ +static HRESULT WINAPI URLMonikerImpl_BindToStorage(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + REFIID riid, + VOID** ppvObject) +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + HRESULT hres; + BINDINFO bi; + DWORD bindf; + WCHAR szFileName[MAX_PATH + 1]; + Binding *bind; + int len; + + if(pmkToLeft) { + FIXME("pmkToLeft != NULL\n"); + return E_NOTIMPL; + } + if(!IsEqualIID(&IID_IStream, riid)) { + FIXME("unsupported iid\n"); + return E_NOTIMPL; + } + + bind = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(Binding)); + bind->lpVtbl = &BindingVtbl; + bind->ref = 1; + URLMON_LockModule(); + + len = lstrlenW(This->URLName)+1; + bind->URLName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); + memcpy(bind->URLName, This->URLName, len*sizeof(WCHAR)); + + hres = UMCreateStreamOnCacheFile(bind->URLName, 0, szFileName, &bind->hCacheFile, &bind->pstrCache); + + if(SUCCEEDED(hres)) { + TRACE("Created stream...\n"); + + *ppvObject = (void *) bind->pstrCache; + IStream_AddRef((IStream *) bind->pstrCache); + + hres = IBindCtx_GetObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown**)&bind->pbscb); + if(SUCCEEDED(hres)) { + TRACE("Got IBindStatusCallback...\n"); + + memset(&bi, 0, sizeof(bi)); + bi.cbSize = sizeof(bi); + bindf = 0; + hres = IBindStatusCallback_GetBindInfo(bind->pbscb, &bindf, &bi); + if(SUCCEEDED(hres)) { + WCHAR *urlcopy, *tmpwc; + URL_COMPONENTSW url; + WCHAR *host, *path, *user, *pass; + DWORD lensz = sizeof(bind->expected_size); + DWORD dwService = 0; + BOOL bSuccess; + + TRACE("got bindinfo. bindf = %08lx extrainfo = %s bindinfof = %08lx bindverb = %08lx iid %s\n", + bindf, debugstr_w(bi.szExtraInfo), bi.grfBindInfoF, bi.dwBindVerb, debugstr_guid(&bi.iid)); + hres = IBindStatusCallback_OnStartBinding(bind->pbscb, 0, (IBinding*)bind); + TRACE("OnStartBinding rets %08lx\n", hres); + + /* This class will accept URLs with the backslash in them. But InternetCrackURL will not - it + * requires forward slashes (this is the behaviour of Microsoft's INETAPI). So we need to make + * a copy of the URL here and change the backslash to a forward slash everywhere it appears - + * but only before any '#' or '?', after which backslash should be left alone. + */ + urlcopy = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (lstrlenW(bind->URLName) + 1)); + lstrcpyW(urlcopy, bind->URLName); + for (tmpwc = urlcopy; *tmpwc && *tmpwc != '#' && *tmpwc != '?'; ++tmpwc) + if (*tmpwc == '\\') + *tmpwc = '/'; + +#if 0 + if(!registered_wndclass) { + WNDCLASSA urlmon_wndclass = {0, URLMON_WndProc,0, 0, URLMON_hInstance, 0, 0, 0, NULL, "URLMON_Callback_Window_Class"}; + RegisterClassA(&urlmon_wndclass); + registered_wndclass = TRUE; + } + + This->hwndCallback = CreateWindowA("URLMON_Callback_Window_Class", NULL, 0, 0, 0, 0, 0, 0, 0, + URLMON_hInstance, NULL); + +#endif + bind->expected_size = 0; + bind->total_read = 0; + + memset(&url, 0, sizeof(url)); + url.dwStructSize = sizeof(url); + url.dwSchemeLength = url.dwHostNameLength = url.dwUrlPathLength = url.dwUserNameLength = url.dwPasswordLength = 1; + InternetCrackUrlW(urlcopy, 0, 0, &url); + host = HeapAlloc(GetProcessHeap(), 0, (url.dwHostNameLength + 1) * sizeof(WCHAR)); + memcpy(host, url.lpszHostName, url.dwHostNameLength * sizeof(WCHAR)); + host[url.dwHostNameLength] = '\0'; + path = HeapAlloc(GetProcessHeap(), 0, (url.dwUrlPathLength + 1) * sizeof(WCHAR)); + memcpy(path, url.lpszUrlPath, url.dwUrlPathLength * sizeof(WCHAR)); + path[url.dwUrlPathLength] = '\0'; + if (url.dwUserNameLength) + { + user = HeapAlloc(GetProcessHeap(), 0, ((url.dwUserNameLength + 1) * sizeof(WCHAR))); + memcpy(user, url.lpszUserName, url.dwUserNameLength * sizeof(WCHAR)); + user[url.dwUserNameLength] = 0; + } + else + { + user = 0; + } + if (url.dwPasswordLength) + { + pass = HeapAlloc(GetProcessHeap(), 0, ((url.dwPasswordLength + 1) * sizeof(WCHAR))); + memcpy(pass, url.lpszPassword, url.dwPasswordLength * sizeof(WCHAR)); + pass[url.dwPasswordLength] = 0; + } + else + { + pass = 0; + } + + switch ((DWORD) url.nScheme) + { + case INTERNET_SCHEME_FTP: + case INTERNET_SCHEME_GOPHER: + case INTERNET_SCHEME_HTTP: + case INTERNET_SCHEME_HTTPS: + + bind->hinternet = InternetOpenA("User Agent", 0, NULL, NULL, 0 /*INTERNET_FLAG_ASYNC*/); +/* InternetSetStatusCallback(bind->hinternet, URLMON_InternetCallback);*/ + if (!bind->hinternet) + { + hres = HRESULT_FROM_WIN32(GetLastError()); + break; + } + + switch ((DWORD) url.nScheme) + { + case INTERNET_SCHEME_FTP: + if (!url.nPort) + url.nPort = INTERNET_DEFAULT_FTP_PORT; + dwService = INTERNET_SERVICE_FTP; + break; + + case INTERNET_SCHEME_GOPHER: + if (!url.nPort) + url.nPort = INTERNET_DEFAULT_GOPHER_PORT; + dwService = INTERNET_SERVICE_GOPHER; + break; + + case INTERNET_SCHEME_HTTP: + if (!url.nPort) + url.nPort = INTERNET_DEFAULT_HTTP_PORT; + dwService = INTERNET_SERVICE_HTTP; + break; + + case INTERNET_SCHEME_HTTPS: + if (!url.nPort) + url.nPort = INTERNET_DEFAULT_HTTPS_PORT; + dwService = INTERNET_SERVICE_HTTP; + break; + } + + bind->hconnect = InternetConnectW(bind->hinternet, host, url.nPort, user, pass, + dwService, 0, (DWORD)bind); + if (!bind->hconnect) + { + hres = HRESULT_FROM_WIN32(GetLastError()); + CloseHandle(bind->hinternet); + break; + } + + hres = IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, 0x22, NULL); + hres = IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_FINDINGRESOURCE, NULL); + hres = IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_CONNECTING, NULL); + hres = IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_SENDINGREQUEST, NULL); + + bSuccess = FALSE; + + switch (dwService) + { + case INTERNET_SERVICE_GOPHER: + bind->hrequest = GopherOpenFileW(bind->hconnect, + path, + 0, + INTERNET_FLAG_RELOAD, + 0); + if (bind->hrequest) + bSuccess = TRUE; + else + hres = HRESULT_FROM_WIN32(GetLastError()); + break; + + case INTERNET_SERVICE_FTP: + bind->hrequest = FtpOpenFileW(bind->hconnect, + path, + GENERIC_READ, + FTP_TRANSFER_TYPE_BINARY | + INTERNET_FLAG_TRANSFER_BINARY | + INTERNET_FLAG_RELOAD, + 0); + if (bind->hrequest) + bSuccess = TRUE; + else + hres = HRESULT_FROM_WIN32(GetLastError()); + break; + + case INTERNET_SERVICE_HTTP: + bind->hrequest = HttpOpenRequestW(bind->hconnect, NULL, path, NULL, NULL, NULL, 0, (DWORD)bind); + if (!bind->hrequest) + { + hres = HRESULT_FROM_WIN32(GetLastError()); + } + else if (!HttpSendRequestW(bind->hrequest, NULL, 0, NULL, 0)) + { + hres = HRESULT_FROM_WIN32(GetLastError()); + InternetCloseHandle(bind->hrequest); + } + else + { + HttpQueryInfoW(bind->hrequest, + HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, + &bind->expected_size, + &lensz, + NULL); + bSuccess = TRUE; + } + break; + } + if(bSuccess) + { + TRACE("res = %ld gle = %08lx url len = %ld\n", hres, GetLastError(), bind->expected_size); + + IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_CACHEFILENAMEAVAILABLE, szFileName); + + while(1) { + char buf[4096]; + DWORD bufread; + if(InternetReadFile(bind->hrequest, buf, sizeof(buf), &bufread)) { + TRACE("read %ld bytes %s...\n", bufread, debugstr_an(buf, 10)); + if(bufread == 0) break; + hres = Binding_MoreCacheData(bind, buf, bufread); + } else + break; + } + InternetCloseHandle(bind->hrequest); + hres = S_OK; + } + + InternetCloseHandle(bind->hconnect); + InternetCloseHandle(bind->hinternet); + break; + + case INTERNET_SCHEME_FILE: + path = bind->URLName + 5; /* Skip the "file:" part */ + if ((path[0] != '/' && path[0] != '\\') || + (path[1] != '/' && path[1] != '\\')) + { + hres = E_FAIL; + } + else + { + HANDLE h; + + path += 2; + if (path[0] == '/' || path[0] == '\\') + ++path; + h = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); + if (h == (HANDLE) HFILE_ERROR) + { + hres = HRESULT_FROM_WIN32(GetLastError()); + } + else + { + char buf[4096]; + DWORD bufread; + + IBindStatusCallback_OnProgress(bind->pbscb, 0, 0, BINDSTATUS_CACHEFILENAMEAVAILABLE, szFileName); + + while (ReadFile(h, buf, sizeof(buf), &bufread, NULL) && bufread > 0) + hres = Binding_MoreCacheData(bind, buf, bufread); + + CloseHandle(h); + hres = S_OK; + } + } + + break; + + default: + FIXME("Unsupported URI scheme"); + break; + } + Binding_CloseCacheDownload(bind); + Binding_FinishedDownload(bind, hres); + + if (user) + HeapFree(GetProcessHeap(), 0, user); + if (pass) + HeapFree(GetProcessHeap(), 0, pass); + HeapFree(GetProcessHeap(), 0, path); + HeapFree(GetProcessHeap(), 0, host); + HeapFree(GetProcessHeap(), 0, urlcopy); + } + } + } + + IBinding_Release((IBinding*)bind); + + return hres; +} + +/****************************************************************************** + * URLMoniker_Reduce + ******************************************************************************/ +static HRESULT WINAPI URLMonikerImpl_Reduce(IMoniker* iface, + IBindCtx* pbc, + DWORD dwReduceHowFar, + IMoniker** ppmkToLeft, + IMoniker** ppmkReduced) +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + + TRACE("(%p,%p,%ld,%p,%p)\n",This,pbc,dwReduceHowFar,ppmkToLeft,ppmkReduced); + + if(!ppmkReduced) + return E_INVALIDARG; + + URLMonikerImpl_AddRef(iface); + *ppmkReduced = iface; + return MK_S_REDUCED_TO_SELF; +} + +/****************************************************************************** + * URLMoniker_ComposeWith + ******************************************************************************/ +static HRESULT WINAPI URLMonikerImpl_ComposeWith(IMoniker* iface, + IMoniker* pmkRight, + BOOL fOnlyIfNotGeneric, + IMoniker** ppmkComposite) +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + FIXME("(%p)->(%p,%d,%p): stub\n",This,pmkRight,fOnlyIfNotGeneric,ppmkComposite); + + return E_NOTIMPL; +} + +/****************************************************************************** + * URLMoniker_Enum + ******************************************************************************/ +static HRESULT WINAPI URLMonikerImpl_Enum(IMoniker* iface,BOOL fForward, IEnumMoniker** ppenumMoniker) +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + TRACE("(%p,%d,%p)\n",This,fForward,ppenumMoniker); + + if(!ppenumMoniker) + return E_INVALIDARG; + + /* Does not support sub-monikers */ + *ppenumMoniker = NULL; + return S_OK; +} + +/****************************************************************************** + * URLMoniker_IsEqual + ******************************************************************************/ +static HRESULT WINAPI URLMonikerImpl_IsEqual(IMoniker* iface,IMoniker* pmkOtherMoniker) +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + CLSID clsid; + LPOLESTR urlPath; + IBindCtx* bind; + HRESULT res; + + TRACE("(%p,%p)\n",This,pmkOtherMoniker); + + if(pmkOtherMoniker==NULL) + return E_INVALIDARG; + + IMoniker_GetClassID(pmkOtherMoniker,&clsid); + + if(!IsEqualCLSID(&clsid,&CLSID_StdURLMoniker)) + return S_FALSE; + + res = CreateBindCtx(0,&bind); + if(FAILED(res)) + return res; + + res = S_FALSE; + if(SUCCEEDED(IMoniker_GetDisplayName(pmkOtherMoniker,bind,NULL,&urlPath))) { + int result = lstrcmpiW(urlPath, This->URLName); + CoTaskMemFree(urlPath); + if(result == 0) + res = S_OK; + } + IUnknown_Release(bind); + return res; +} + + +/****************************************************************************** + * URLMoniker_Hash + ******************************************************************************/ +static HRESULT WINAPI URLMonikerImpl_Hash(IMoniker* iface,DWORD* pdwHash) +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + + int h = 0,i,skip,len; + int off = 0; + LPOLESTR val; + + TRACE("(%p,%p)\n",This,pdwHash); + + if(!pdwHash) + return E_INVALIDARG; + + val = This->URLName; + len = lstrlenW(val); + + if(len < 16) { + for(i = len ; i > 0; i--) { + h = (h * 37) + val[off++]; + } + } + else { + /* only sample some characters */ + skip = len / 8; + for(i = len; i > 0; i -= skip, off += skip) { + h = (h * 39) + val[off]; + } + } + *pdwHash = h; + return S_OK; +} + +/****************************************************************************** + * URLMoniker_IsRunning + ******************************************************************************/ +static HRESULT WINAPI URLMonikerImpl_IsRunning(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + IMoniker* pmkNewlyRunning) +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + FIXME("(%p)->(%p,%p,%p): stub\n",This,pbc,pmkToLeft,pmkNewlyRunning); + + return E_NOTIMPL; +} + +/****************************************************************************** + * URLMoniker_GetTimeOfLastChange + ******************************************************************************/ +static HRESULT WINAPI URLMonikerImpl_GetTimeOfLastChange(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + FILETIME* pFileTime) +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + FIXME("(%p)->(%p,%p,%p): stub\n",This,pbc,pmkToLeft,pFileTime); + + return E_NOTIMPL; +} + +/****************************************************************************** + * URLMoniker_Inverse + ******************************************************************************/ +static HRESULT WINAPI URLMonikerImpl_Inverse(IMoniker* iface,IMoniker** ppmk) +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + TRACE("(%p,%p)\n",This,ppmk); + + return MK_E_NOINVERSE; +} + +/****************************************************************************** + * URLMoniker_CommonPrefixWith + ******************************************************************************/ +static HRESULT WINAPI URLMonikerImpl_CommonPrefixWith(IMoniker* iface,IMoniker* pmkOther,IMoniker** ppmkPrefix) +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + FIXME("(%p)->(%p,%p): stub\n",This,pmkOther,ppmkPrefix); + + return E_NOTIMPL; +} + +/****************************************************************************** + * URLMoniker_RelativePathTo + ******************************************************************************/ +static HRESULT WINAPI URLMonikerImpl_RelativePathTo(IMoniker* iface,IMoniker* pmOther, IMoniker** ppmkRelPath) +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + FIXME("(%p)->(%p,%p): stub\n",This,pmOther,ppmkRelPath); + + return E_NOTIMPL; +} + +/****************************************************************************** + * URLMoniker_GetDisplayName + ******************************************************************************/ +static HRESULT WINAPI URLMonikerImpl_GetDisplayName(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + LPOLESTR *ppszDisplayName) +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + + int len; + + TRACE("(%p,%p,%p,%p)\n",This,pbc,pmkToLeft,ppszDisplayName); + + if(!ppszDisplayName) + return E_INVALIDARG; + + /* FIXME: If this is a partial URL, try and get a URL moniker from SZ_URLCONTEXT in the bind context, + then look at pmkToLeft to try and complete the URL + */ + len = lstrlenW(This->URLName)+1; + *ppszDisplayName = CoTaskMemAlloc(len*sizeof(WCHAR)); + if(!*ppszDisplayName) + return E_OUTOFMEMORY; + lstrcpyW(*ppszDisplayName, This->URLName); + return S_OK; +} + +/****************************************************************************** + * URLMoniker_ParseDisplayName + ******************************************************************************/ +static HRESULT WINAPI URLMonikerImpl_ParseDisplayName(IMoniker* iface, + IBindCtx* pbc, + IMoniker* pmkToLeft, + LPOLESTR pszDisplayName, + ULONG* pchEaten, + IMoniker** ppmkOut) +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + FIXME("(%p)->(%p,%p,%p,%p,%p): stub\n",This,pbc,pmkToLeft,pszDisplayName,pchEaten,ppmkOut); + + return E_NOTIMPL; +} + +/****************************************************************************** + * URLMoniker_IsSystemMoniker + ******************************************************************************/ +static HRESULT WINAPI URLMonikerImpl_IsSystemMoniker(IMoniker* iface,DWORD* pwdMksys) +{ + URLMonikerImpl *This = (URLMonikerImpl *)iface; + TRACE("(%p,%p)\n",This,pwdMksys); + + if(!pwdMksys) + return E_INVALIDARG; + + *pwdMksys = MKSYS_URLMONIKER; + return S_OK; +} + +/********************************************************************************/ +/* Virtual function table for the URLMonikerImpl class which include IPersist,*/ +/* IPersistStream and IMoniker functions. */ +static IMonikerVtbl VT_URLMonikerImpl = +{ + URLMonikerImpl_QueryInterface, + URLMonikerImpl_AddRef, + URLMonikerImpl_Release, + URLMonikerImpl_GetClassID, + URLMonikerImpl_IsDirty, + URLMonikerImpl_Load, + URLMonikerImpl_Save, + URLMonikerImpl_GetSizeMax, + URLMonikerImpl_BindToObject, + URLMonikerImpl_BindToStorage, + URLMonikerImpl_Reduce, + URLMonikerImpl_ComposeWith, + URLMonikerImpl_Enum, + URLMonikerImpl_IsEqual, + URLMonikerImpl_Hash, + URLMonikerImpl_IsRunning, + URLMonikerImpl_GetTimeOfLastChange, + URLMonikerImpl_Inverse, + URLMonikerImpl_CommonPrefixWith, + URLMonikerImpl_RelativePathTo, + URLMonikerImpl_GetDisplayName, + URLMonikerImpl_ParseDisplayName, + URLMonikerImpl_IsSystemMoniker +}; + +/****************************************************************************** + * URLMoniker_Construct (local function) + *******************************************************************************/ +static HRESULT URLMonikerImpl_Construct(URLMonikerImpl* This, LPCOLESTR lpszLeftURLName, LPCOLESTR lpszURLName) +{ + HRESULT hres; + DWORD sizeStr; + + TRACE("(%p,%s,%s)\n",This,debugstr_w(lpszLeftURLName),debugstr_w(lpszURLName)); + memset(This, 0, sizeof(*This)); + + /* Initialize the virtual function table. */ + This->lpvtbl = &VT_URLMonikerImpl; + This->ref = 0; + + if(lpszLeftURLName) { + hres = UrlCombineW(lpszLeftURLName, lpszURLName, NULL, &sizeStr, 0); + if(FAILED(hres)) { + return hres; + } + sizeStr++; + } + else + sizeStr = lstrlenW(lpszURLName)+1; + + This->URLName=HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*(sizeStr)); + + if (This->URLName==NULL) + return E_OUTOFMEMORY; + + if(lpszLeftURLName) { + hres = UrlCombineW(lpszLeftURLName, lpszURLName, This->URLName, &sizeStr, 0); + if(FAILED(hres)) { + HeapFree(GetProcessHeap(), 0, This->URLName); + return hres; + } + } + else + strcpyW(This->URLName,lpszURLName); + + return S_OK; +} + +/*********************************************************************** + * CreateAsyncBindCtx (URLMON.@) + */ +HRESULT WINAPI CreateAsyncBindCtx(DWORD reserved, IBindStatusCallback *callback, + IEnumFORMATETC *format, IBindCtx **pbind) +{ + HRESULT hres; + BIND_OPTS bindopts; + IBindCtx *bctx; + + TRACE("(%08lx %p %p %p)\n", reserved, callback, format, pbind); + + if(!callback) + return E_INVALIDARG; + if(format) + FIXME("format is not supported yet\n"); + + hres = CreateBindCtx(0, &bctx); + if(FAILED(hres)) + return hres; + + bindopts.cbStruct = sizeof(BIND_OPTS); + bindopts.grfFlags = BIND_MAYBOTHERUSER; + bindopts.grfMode = STGM_READWRITE | STGM_SHARE_EXCLUSIVE; + bindopts.dwTickCountDeadline = 0; + IBindCtx_SetBindOptions(bctx, &bindopts); + + hres = IBindCtx_RegisterObjectParam(bctx, (LPOLESTR)BSCBHolder, (IUnknown*)callback); + if(FAILED(hres)) { + IBindCtx_Release(bctx); + return hres; + } + + *pbind = bctx; + + return S_OK; +} +/*********************************************************************** + * CreateAsyncBindCtxEx (URLMON.@) + * + * Create an asynchronous bind context. + * + * FIXME + * Not implemented. + */ +HRESULT WINAPI CreateAsyncBindCtxEx(IBindCtx *ibind, DWORD options, + IBindStatusCallback *callback, IEnumFORMATETC *format, IBindCtx** pbind, + DWORD reserved) +{ + FIXME("stub, returns failure\n"); + return E_INVALIDARG; +} + + +/*********************************************************************** + * CreateURLMoniker (URLMON.@) + * + * Create a url moniker. + * + * PARAMS + * pmkContext [I] Context + * szURL [I] Url to create the moniker for + * ppmk [O] Destination for created moniker. + * + * RETURNS + * Success: S_OK. ppmk contains the created IMoniker object. + * Failure: MK_E_SYNTAX if szURL is not a valid url, or + * E_OUTOFMEMORY if memory allocation fails. + */ +HRESULT WINAPI CreateURLMoniker(IMoniker *pmkContext, LPCWSTR szURL, IMoniker **ppmk) +{ + URLMonikerImpl *obj; + HRESULT hres; + IID iid = IID_IMoniker; + LPOLESTR lefturl = NULL; + + TRACE("(%p, %s, %p)\n", pmkContext, debugstr_w(szURL), ppmk); + + if(!(obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj)))) + return E_OUTOFMEMORY; + + if(pmkContext) { + CLSID clsid; + IBindCtx* bind; + IMoniker_GetClassID(pmkContext, &clsid); + if(IsEqualCLSID(&clsid, &CLSID_StdURLMoniker) && SUCCEEDED(CreateBindCtx(0, &bind))) { + URLMonikerImpl_GetDisplayName(pmkContext, bind, NULL, &lefturl); + IBindCtx_Release(bind); + } + } + + hres = URLMonikerImpl_Construct(obj, lefturl, szURL); + CoTaskMemFree(lefturl); + if(SUCCEEDED(hres)) + hres = URLMonikerImpl_QueryInterface((IMoniker*)obj, &iid, (void**)ppmk); + else + HeapFree(GetProcessHeap(), 0, obj); + return hres; +} + + +/*********************************************************************** + * CoInternetGetSession (URLMON.@) + * + * Create a new internet session and return an IInternetSession interface + * representing it. + * + * PARAMS + * dwSessionMode [I] Mode for the internet session + * ppIInternetSession [O] Destination for creates IInternetSession object + * dwReserved [I] Reserved, must be 0. + * + * RETURNS + * Success: S_OK. ppIInternetSession contains the IInternetSession interface. + * Failure: E_INVALIDARG, if any argument is invalid, or + * E_OUTOFMEMORY if memory allocation fails. + */ +HRESULT WINAPI CoInternetGetSession(DWORD dwSessionMode, IInternetSession **ppIInternetSession, DWORD dwReserved) +{ + FIXME("(%ld, %p, %ld): stub\n", dwSessionMode, ppIInternetSession, dwReserved); + + if(dwSessionMode) { + ERR("dwSessionMode: %ld, must be zero\n", dwSessionMode); + } + + if(dwReserved) { + ERR("dwReserved: %ld, must be zero\n", dwReserved); + } + + *ppIInternetSession=NULL; + return E_OUTOFMEMORY; +} + +/*********************************************************************** + * CoInternetQueryInfo (URLMON.@) + * + * Retrieves information relevant to a specified URL + * + * RETURNS + * S_OK success + * S_FALSE buffer too small + * INET_E_QUERYOPTIONUNKNOWN invalid option + * + */ +HRESULT WINAPI CoInternetQueryInfo(LPCWSTR pwzUrl, QUERYOPTION QueryOption, + DWORD dwQueryFlags, LPVOID pvBuffer, DWORD cbBuffer, DWORD * pcbBuffer, + DWORD dwReserved) +{ + FIXME("(%s, %x, %lx, %p, %lx, %p, %lx): stub\n", debugstr_w(pwzUrl), + QueryOption, dwQueryFlags, pvBuffer, cbBuffer, pcbBuffer, dwReserved); + return S_OK; +} + +static BOOL URLMON_IsBinary(LPVOID pBuffer, DWORD cbSize) +{ + unsigned int i, binarycount = 0; + unsigned char *buff = pBuffer; + for(i=0; i<cbSize; i++) { + if(buff[i] < 32) + binarycount++; + } + return binarycount > (cbSize-binarycount); +} + +/*********************************************************************** + * FindMimeFromData (URLMON.@) + * + * Determines the Multipurpose Internet Mail Extensions (MIME) type from the data provided. + * + * NOTE + * See http://msdn.microsoft.com/workshop/networking/moniker/overview/appendix_a.asp + */ +HRESULT WINAPI FindMimeFromData(LPBC pBC, LPCWSTR pwzUrl, LPVOID pBuffer, + DWORD cbSize, LPCWSTR pwzMimeProposed, DWORD dwMimeFlags, + LPWSTR* ppwzMimeOut, DWORD dwReserved) +{ + static const WCHAR szBinaryMime[] = {'a','p','p','l','i','c','a','t','i','o','n','/','o','c','t','e','t','-','s','t','r','e','a','m','\0'}; + static const WCHAR szTextMime[] = {'t','e','x','t','/','p','l','a','i','n','\0'}; + static const WCHAR szContentType[] = {'C','o','n','t','e','n','t',' ','T','y','p','e','\0'}; + WCHAR szTmpMime[256]; + LPCWSTR mimeType = NULL; + HKEY hKey = NULL; + + TRACE("(%p,%s,%p,%ld,%s,0x%lx,%p,0x%lx)\n", pBC, debugstr_w(pwzUrl), pBuffer, cbSize, + debugstr_w(pwzMimeProposed), dwMimeFlags, ppwzMimeOut, dwReserved); + + if((!pwzUrl && (!pBuffer || cbSize <= 0)) || !ppwzMimeOut) + return E_INVALIDARG; + + if(pwzMimeProposed) + mimeType = pwzMimeProposed; + else { + /* Try and find the mime type in the registry */ + if(pwzUrl) { + LPWSTR ext = strrchrW(pwzUrl, '.'); + if(ext) { + DWORD dwSize; + if(!RegOpenKeyExW(HKEY_CLASSES_ROOT, ext, 0, 0, &hKey)) { + if(!RegQueryValueExW(hKey, szContentType, NULL, NULL, (LPBYTE)szTmpMime, &dwSize)) { + mimeType = szTmpMime; + } + RegCloseKey(hKey); + } + } + } + } + if(!mimeType && pBuffer && cbSize > 0) + mimeType = URLMON_IsBinary(pBuffer, cbSize)?szBinaryMime:szTextMime; + + TRACE("Using %s\n", debugstr_w(mimeType)); + *ppwzMimeOut = CoTaskMemAlloc((lstrlenW(mimeType)+1)*sizeof(WCHAR)); + if(!*ppwzMimeOut) return E_OUTOFMEMORY; + lstrcpyW(*ppwzMimeOut, mimeType); + return S_OK; +} + +/*********************************************************************** + * IsAsyncMoniker (URLMON.@) + */ +HRESULT WINAPI IsAsyncMoniker(IMoniker *pmk) +{ + IUnknown *am; + + TRACE("(%p)\n", pmk); + if(!pmk) + return E_INVALIDARG; + if(SUCCEEDED(IMoniker_QueryInterface(pmk, &IID_IAsyncMoniker, (void**)&am))) { + IUnknown_Release(am); + return S_OK; + } + return S_FALSE; +} + +/*********************************************************************** + * RegisterBindStatusCallback (URLMON.@) + * + * Register a bind status callback. + * + * PARAMS + * pbc [I] Binding context + * pbsc [I] Callback to register + * ppbscPrevious [O] Destination for previous callback + * dwReserved [I] Reserved, must be 0. + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if any argument is invalid, or + * E_OUTOFMEMORY if memory allocation fails. + */ +HRESULT WINAPI RegisterBindStatusCallback( + IBindCtx *pbc, + IBindStatusCallback *pbsc, + IBindStatusCallback **ppbscPrevious, + DWORD dwReserved) +{ + IBindStatusCallback *prev; + + TRACE("(%p,%p,%p,%lu)\n", pbc, pbsc, ppbscPrevious, dwReserved); + + if (pbc == NULL || pbsc == NULL) + return E_INVALIDARG; + + if (SUCCEEDED(IBindCtx_GetObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown **)&prev))) + { + IBindCtx_RevokeObjectParam(pbc, (LPOLESTR)BSCBHolder); + if (ppbscPrevious) + *ppbscPrevious = prev; + else + IBindStatusCallback_Release(prev); + } + + return IBindCtx_RegisterObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown *)pbsc); +} + +/*********************************************************************** + * RevokeBindStatusCallback (URLMON.@) + * + * Unregister a bind status callback. + * + * pbc [I] Binding context + * pbsc [I] Callback to unregister + * + * RETURNS + * Success: S_OK. + * Failure: E_INVALIDARG, if any argument is invalid, or + * E_FAIL if pbsc wasn't registered with pbc. + */ +HRESULT WINAPI RevokeBindStatusCallback( + IBindCtx *pbc, + IBindStatusCallback *pbsc) +{ + IBindStatusCallback *callback; + HRESULT hr = E_FAIL; + + TRACE("(%p,%p)\n", pbc, pbsc); + + if (pbc == NULL || pbsc == NULL) + return E_INVALIDARG; + + if (SUCCEEDED(IBindCtx_GetObjectParam(pbc, (LPOLESTR)BSCBHolder, (IUnknown **)&callback))) + { + if (callback == pbsc) + { + IBindCtx_RevokeObjectParam(pbc, (LPOLESTR)BSCBHolder); + hr = S_OK; + } + IBindStatusCallback_Release(pbsc); + } + + return hr; +} + +/*********************************************************************** + * ReleaseBindInfo (URLMON.@) + * + * Release the resources used by the specified BINDINFO structure. + * + * PARAMS + * pbindinfo [I] BINDINFO to release. + * + * RETURNS + * Nothing. + */ +void WINAPI ReleaseBindInfo(BINDINFO* pbindinfo) +{ + FIXME("(%p)stub!\n", pbindinfo); +} + +/*********************************************************************** + * URLDownloadToFileA (URLMON.@) + * + * Downloads URL szURL to rile szFileName and call lpfnCB callback to + * report progress. + * + * PARAMS + * pCaller [I] controlling IUnknown interface. + * szURL [I] URL of the file to download + * szFileName [I] file name to store the content of the URL + * dwReserved [I] reserved - set to 0 + * lpfnCB [I] callback for progress report + * + * RETURNS + * S_OK on success + * E_OUTOFMEMORY when going out of memory + */ +HRESULT WINAPI URLDownloadToFileA(LPUNKNOWN pCaller, + LPCSTR szURL, + LPCSTR szFileName, + DWORD dwReserved, + LPBINDSTATUSCALLBACK lpfnCB) +{ + UNICODE_STRING szURL_w, szFileName_w; + + if ((szURL == NULL) || (szFileName == NULL)) { + FIXME("(%p,%s,%s,%08lx,%p) cannot accept NULL strings !\n", pCaller, debugstr_a(szURL), debugstr_a(szFileName), dwReserved, lpfnCB); + return E_INVALIDARG; /* The error code is not specified in this case... */ + } + + if (RtlCreateUnicodeStringFromAsciiz(&szURL_w, szURL)) { + if (RtlCreateUnicodeStringFromAsciiz(&szFileName_w, szFileName)) { + HRESULT ret = URLDownloadToFileW(pCaller, szURL_w.Buffer, szFileName_w.Buffer, dwReserved, lpfnCB); + + RtlFreeUnicodeString(&szURL_w); + RtlFreeUnicodeString(&szFileName_w); + + return ret; + } else { + RtlFreeUnicodeString(&szURL_w); + } + } + + FIXME("(%p,%s,%s,%08lx,%p) could not allocate W strings !\n", pCaller, szURL, szFileName, dwReserved, lpfnCB); + return E_OUTOFMEMORY; +} + +/*********************************************************************** + * URLDownloadToFileW (URLMON.@) + * + * Downloads URL szURL to rile szFileName and call lpfnCB callback to + * report progress. + * + * PARAMS + * pCaller [I] controlling IUnknown interface. + * szURL [I] URL of the file to download + * szFileName [I] file name to store the content of the URL + * dwReserved [I] reserved - set to 0 + * lpfnCB [I] callback for progress report + * + * RETURNS + * S_OK on success + * E_OUTOFMEMORY when going out of memory + */ +HRESULT WINAPI URLDownloadToFileW(LPUNKNOWN pCaller, + LPCWSTR szURL, + LPCWSTR szFileName, + DWORD dwReserved, + LPBINDSTATUSCALLBACK lpfnCB) +{ + HINTERNET hinternet, hcon, hreq; + BOOL r; + CHAR buffer[0x1000]; + DWORD sz, total, written; + DWORD total_size = 0xFFFFFFFF, arg_size = sizeof(total_size); + URL_COMPONENTSW url; + WCHAR host[0x80], path[0x100]; + HANDLE hfile; + static const WCHAR wszAppName[]={'u','r','l','m','o','n','.','d','l','l',0}; + + /* Note: all error codes would need to be checked agains real Windows behaviour... */ + TRACE("(%p,%s,%s,%08lx,%p) stub!\n", pCaller, debugstr_w(szURL), debugstr_w(szFileName), dwReserved, lpfnCB); + + if ((szURL == NULL) || (szFileName == NULL)) { + FIXME(" cannot accept NULL strings !\n"); + return E_INVALIDARG; + } + + /* Would be better to use the application name here rather than 'urlmon' :-/ */ + hinternet = InternetOpenW(wszAppName, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); + if (hinternet == NULL) { + return E_OUTOFMEMORY; + } + + memset(&url, 0, sizeof(url)); + url.dwStructSize = sizeof(url); + url.lpszHostName = host; + url.dwHostNameLength = sizeof(host); + url.lpszUrlPath = path; + url.dwUrlPathLength = sizeof(path); + + if (!InternetCrackUrlW(szURL, 0, 0, &url)) { + InternetCloseHandle(hinternet); + return E_OUTOFMEMORY; + } + + if (lpfnCB) { + if (IBindStatusCallback_OnProgress(lpfnCB, 0, 0, BINDSTATUS_CONNECTING, url.lpszHostName) == E_ABORT) { + InternetCloseHandle(hinternet); + return S_OK; + } + } + + hcon = InternetConnectW(hinternet, url.lpszHostName, url.nPort, + url.lpszUserName, url.lpszPassword, + INTERNET_SERVICE_HTTP, 0, 0); + if (!hcon) { + InternetCloseHandle(hinternet); + return E_OUTOFMEMORY; + } + + hreq = HttpOpenRequestW(hcon, NULL, url.lpszUrlPath, NULL, NULL, NULL, 0, 0); + if (!hreq) { + InternetCloseHandle(hinternet); + InternetCloseHandle(hcon); + return E_OUTOFMEMORY; + } + + if (!HttpSendRequestW(hreq, NULL, 0, NULL, 0)) { + InternetCloseHandle(hinternet); + InternetCloseHandle(hcon); + InternetCloseHandle(hreq); + return E_OUTOFMEMORY; + } + + if (HttpQueryInfoW(hreq, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, + &total_size, &arg_size, NULL)) { + TRACE(" total size : %ld\n", total_size); + } + + hfile = CreateFileW(szFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL ); + if (hfile == INVALID_HANDLE_VALUE) { + return E_ACCESSDENIED; + } + + if (lpfnCB) { + if (IBindStatusCallback_OnProgress(lpfnCB, 0, total_size != 0xFFFFFFFF ? total_size : 0, + BINDSTATUS_BEGINDOWNLOADDATA, szURL) == E_ABORT) { + InternetCloseHandle(hreq); + InternetCloseHandle(hcon); + InternetCloseHandle(hinternet); + CloseHandle(hfile); + return S_OK; + } + } + + total = 0; + while (1) { + r = InternetReadFile(hreq, buffer, sizeof(buffer), &sz); + if (!r) { + InternetCloseHandle(hreq); + InternetCloseHandle(hcon); + InternetCloseHandle(hinternet); + + CloseHandle(hfile); + return E_OUTOFMEMORY; + } + if (!sz) + break; + + total += sz; + + if (lpfnCB) { + if (IBindStatusCallback_OnProgress(lpfnCB, total, total_size != 0xFFFFFFFF ? total_size : 0, + BINDSTATUS_DOWNLOADINGDATA, szURL) == E_ABORT) { + InternetCloseHandle(hreq); + InternetCloseHandle(hcon); + InternetCloseHandle(hinternet); + CloseHandle(hfile); + return S_OK; + } + } + + if (!WriteFile(hfile, buffer, sz, &written, NULL)) { + InternetCloseHandle(hreq); + InternetCloseHandle(hcon); + InternetCloseHandle(hinternet); + + CloseHandle(hfile); + return E_OUTOFMEMORY; + } + } + + if (lpfnCB) { + if (IBindStatusCallback_OnProgress(lpfnCB, total, total_size != 0xFFFFFFFF ? total_size : 0, + BINDSTATUS_ENDDOWNLOADDATA, szURL) == E_ABORT) { + InternetCloseHandle(hreq); + InternetCloseHandle(hcon); + InternetCloseHandle(hinternet); + CloseHandle(hfile); + return S_OK; + } + } + + InternetCloseHandle(hreq); + InternetCloseHandle(hcon); + InternetCloseHandle(hinternet); + + CloseHandle(hfile); + + return S_OK; +} + +/*********************************************************************** + * HlinkSimpleNavigateToString (URLMON.@) + */ +HRESULT WINAPI HlinkSimpleNavigateToString( LPCWSTR szTarget, + LPCWSTR szLocation, LPCWSTR szTargetFrameName, IUnknown *pUnk, + IBindCtx *pbc, IBindStatusCallback *pbsc, DWORD grfHLNF, DWORD dwReserved) +{ + FIXME("%s\n", debugstr_w( szTarget ) ); + return E_NOTIMPL; +} + +/*********************************************************************** + * HlinkNavigateString (URLMON.@) + */ +HRESULT WINAPI HlinkNavigateString( IUnknown *pUnk, LPCWSTR szTarget ) +{ + TRACE("%p %s\n", pUnk, debugstr_w( szTarget ) ); + return HlinkSimpleNavigateToString( + szTarget, NULL, NULL, pUnk, NULL, NULL, 0, 0 ); +} diff --git a/reactos/lib/urlmon/urlmon_main.c b/reactos/lib/urlmon/urlmon_main.c index 641df1c837b..d584142ea13 100644 --- a/reactos/lib/urlmon/urlmon_main.c +++ b/reactos/lib/urlmon/urlmon_main.c @@ -1,357 +1,357 @@ -/* - * UrlMon - * - * Copyright (c) 2000 Patrik Stridvall - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> - -#define COBJMACROS - -#include "windef.h" -#include "winbase.h" -#include "winerror.h" -#include "wtypes.h" -#define NO_SHLWAPI_REG -#include "shlwapi.h" - -#include "wine/debug.h" - -#include "winuser.h" -#include "urlmon.h" -#include "urlmon_main.h" - -WINE_DEFAULT_DEBUG_CHANNEL(urlmon); - -LONG URLMON_refCount = 0; - -HINSTANCE URLMON_hInstance = 0; - -/*********************************************************************** - * DllMain (URLMON.init) - */ -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad) -{ - TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad); - - switch(fdwReason) { - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(hinstDLL); - URLMON_hInstance = hinstDLL; - break; - - case DLL_PROCESS_DETACH: - URLMON_hInstance = 0; - break; - } - return TRUE; -} - - -/*********************************************************************** - * DllInstall (URLMON.@) - */ -HRESULT WINAPI URLMON_DllInstall(BOOL bInstall, LPCWSTR cmdline) -{ - FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE", - debugstr_w(cmdline)); - - return S_OK; -} - -/*********************************************************************** - * DllCanUnloadNow (URLMON.@) - */ -HRESULT WINAPI URLMON_DllCanUnloadNow(void) -{ - return URLMON_refCount != 0 ? S_FALSE : S_OK; -} - - - -/****************************************************************************** - * Urlmon ClassFactory - */ -typedef struct { - IClassFactory ITF_IClassFactory; - - DWORD ref; - HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj); -} IClassFactoryImpl; - -struct object_creation_info -{ - const CLSID *clsid; - HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj); -}; - -static const struct object_creation_info object_creation[] = -{ - { &CLSID_InternetSecurityManager, &SecManagerImpl_Construct }, - { &CLSID_InternetZoneManager, ZoneMgrImpl_Construct } -}; - -static HRESULT WINAPI -CF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) -{ - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - - if (IsEqualGUID(riid, &IID_IUnknown) - || IsEqualGUID(riid, &IID_IClassFactory)) - { - IClassFactory_AddRef(iface); - *ppobj = This; - return S_OK; - } - - WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj); - return E_NOINTERFACE; -} - -static ULONG WINAPI CF_AddRef(LPCLASSFACTORY iface) -{ - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - URLMON_LockModule(); - - return InterlockedIncrement(&This->ref); -} - -static ULONG WINAPI CF_Release(LPCLASSFACTORY iface) -{ - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - - ULONG ref = InterlockedDecrement(&This->ref); - - if (ref == 0) - HeapFree(GetProcessHeap(), 0, This); - - URLMON_UnlockModule(); - - return ref; -} - - -static HRESULT WINAPI CF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter, - REFIID riid, LPVOID *ppobj) -{ - IClassFactoryImpl *This = (IClassFactoryImpl *)iface; - HRESULT hres; - LPUNKNOWN punk; - - TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj); - - *ppobj = NULL; - if(SUCCEEDED(hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk))) { - hres = IUnknown_QueryInterface(punk, riid, ppobj); - IUnknown_Release(punk); - } - return hres; -} - -static HRESULT WINAPI CF_LockServer(LPCLASSFACTORY iface,BOOL dolock) -{ - TRACE("(%d)\n", dolock); - - if (dolock) - URLMON_LockModule(); - else - URLMON_UnlockModule(); - - return S_OK; -} - -static IClassFactoryVtbl CF_Vtbl = -{ - CF_QueryInterface, - CF_AddRef, - CF_Release, - CF_CreateInstance, - CF_LockServer -}; - -/******************************************************************************* - * DllGetClassObject [URLMON.@] - * Retrieves class object from a DLL object - * - * NOTES - * Docs say returns STDAPI - * - * PARAMS - * rclsid [I] CLSID for the class object - * riid [I] Reference to identifier of interface for class object - * ppv [O] Address of variable to receive interface pointer for riid - * - * RETURNS - * Success: S_OK - * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG, - * E_UNEXPECTED - */ - -DWORD WINAPI URLMON_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) -{ - int i; - IClassFactoryImpl *factory; - - TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); - - if ( !IsEqualGUID( &IID_IClassFactory, riid ) - && ! IsEqualGUID( &IID_IUnknown, riid) ) - return E_NOINTERFACE; - - for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++) - { - if (IsEqualGUID(object_creation[i].clsid, rclsid)) - break; - } - - if (i == sizeof(object_creation)/sizeof(object_creation[0])) - { - FIXME("%s: no class found.\n", debugstr_guid(rclsid)); - return CLASS_E_CLASSNOTAVAILABLE; - } - - factory = HeapAlloc(GetProcessHeap(), 0, sizeof(*factory)); - if (factory == NULL) return E_OUTOFMEMORY; - - factory->ITF_IClassFactory.lpVtbl = &CF_Vtbl; - factory->ref = 1; - - factory->pfnCreateInstance = object_creation[i].pfnCreateInstance; - - *ppv = &(factory->ITF_IClassFactory); - return S_OK; -} - - -/*********************************************************************** - * DllRegisterServerEx (URLMON.@) - */ -HRESULT WINAPI URLMON_DllRegisterServerEx(void) -{ - FIXME("(void): stub\n"); - - return E_FAIL; -} - -/************************************************************************** - * UrlMkSetSessionOption (URLMON.@) - */ -HRESULT WINAPI UrlMkSetSessionOption(DWORD dwOption, LPVOID *pBuffer, DWORD dwBufferLength, - DWORD Reserved) -{ - FIXME("(%#lx, %p, %#lx): stub\n", dwOption, pBuffer, dwBufferLength); - - return S_OK; -} - -/************************************************************************** - * UrlMkGetSessionOption (URLMON.@) - */ -HRESULT WINAPI UrlMkGetSessionOption(DWORD dwOption, LPVOID *pBuffer, DWORD dwBufferLength, - DWORD* pdwBufferLength, DWORD dwReserved) -{ - FIXME("(%#lx, %p, %#lx, %p): stub\n", dwOption, pBuffer, dwBufferLength, pdwBufferLength); - - return S_OK; -} - -/************************************************************************** - * ObtainUserAgentString (URLMON.@) - */ -HRESULT WINAPI ObtainUserAgentString(DWORD dwOption, LPCSTR pcszUAOut, DWORD *cbSize) -{ - FIXME("(%ld, %p, %p): stub\n", dwOption, pcszUAOut, cbSize); - - if(dwOption) { - ERR("dwOption: %ld, must be zero\n", dwOption); - } - - return S_OK; -} - -HRESULT WINAPI CoInternetCombineUrl(LPCWSTR pwzBaseUrl, LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, - LPWSTR pwzResult, DWORD cchResult, DWORD *pcchResult, DWORD dwReserved) -{ - HRESULT hres; - DWORD size = cchResult; - - TRACE("(%s,%s,0x%08lx,%p,%ld,%p,%ld)\n", debugstr_w(pwzBaseUrl), debugstr_w(pwzRelativeUrl), dwCombineFlags, - pwzResult, cchResult, pcchResult, dwReserved); - hres = UrlCombineW(pwzBaseUrl, pwzRelativeUrl, pwzResult, &size, dwCombineFlags); - if(pcchResult) *pcchResult = size; - return hres; -} - -HRESULT WINAPI CoInternetCompareUrl(LPCWSTR pwzUrl1, LPCWSTR pwzUrl2, DWORD dwCompareFlags) -{ - TRACE("(%s,%s,%08lx)\n", debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags); - return UrlCompareW(pwzUrl1, pwzUrl2, dwCompareFlags)==0?S_OK:S_FALSE; -} - -/************************************************************************** - * IsValidURL (URLMON.@) - * - * Determines if a specified string is a valid URL. - * - * PARAMS - * pBC [I] ignored, must be NULL. - * szURL [I] string that represents the URL in question. - * dwReserved [I] reserved and must be zero. - * - * RETURNS - * Success: S_OK. - * Failure: S_FALSE. - * returns E_INVALIDARG if one or more of the args is invalid. - * - * TODO: - * test functionality against windows to see what a valid URL is. - */ -HRESULT WINAPI IsValidURL(LPBC pBC, LPCWSTR szURL, DWORD dwReserved) -{ - FIXME("(%p, %s, %ld): stub\n", pBC, debugstr_w(szURL), dwReserved); - - if (pBC != NULL || dwReserved != 0) - return E_INVALIDARG; - - return S_OK; -} - -/************************************************************************** - * FaultInIEFeature (URLMON.@) - * - * Undocumented. Appears to be used by native shdocvw.dll. - */ -HRESULT WINAPI FaultInIEFeature( HWND hwnd, uCLSSPEC * pClassSpec, - QUERYCONTEXT *pQuery, DWORD flags ) -{ - FIXME("%p %p %p %08lx\n", hwnd, pClassSpec, pQuery, flags); - return E_NOTIMPL; -} - -/************************************************************************** - * CoGetClassObjectFromURL (URLMON.@) - */ -HRESULT WINAPI CoGetClassObjectFromURL( REFCLSID rclsid, LPCWSTR szCodeURL, DWORD dwFileVersionMS, - DWORD dwFileVersionLS, LPCWSTR szContentType, - LPBINDCTX pBindCtx, DWORD dwClsContext, LPVOID pvReserved, - REFIID riid, LPVOID *ppv ) -{ - FIXME("(%s %s %ld %ld %s %p %ld %p %s %p) Stub!\n", debugstr_guid(rclsid), debugstr_w(szCodeURL), - dwFileVersionMS, dwFileVersionLS, debugstr_w(szContentType), pBindCtx, dwClsContext, pvReserved, - debugstr_guid(riid), ppv); - return E_NOINTERFACE; -} +/* + * UrlMon + * + * Copyright (c) 2000 Patrik Stridvall + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "wtypes.h" +#define NO_SHLWAPI_REG +#include "shlwapi.h" + +#include "wine/debug.h" + +#include "winuser.h" +#include "urlmon.h" +#include "urlmon_main.h" + +WINE_DEFAULT_DEBUG_CHANNEL(urlmon); + +LONG URLMON_refCount = 0; + +HINSTANCE URLMON_hInstance = 0; + +/*********************************************************************** + * DllMain (URLMON.init) + */ +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad) +{ + TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad); + + switch(fdwReason) { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDLL); + URLMON_hInstance = hinstDLL; + break; + + case DLL_PROCESS_DETACH: + URLMON_hInstance = 0; + break; + } + return TRUE; +} + + +/*********************************************************************** + * DllInstall (URLMON.@) + */ +HRESULT WINAPI URLMON_DllInstall(BOOL bInstall, LPCWSTR cmdline) +{ + FIXME("(%s, %s): stub\n", bInstall?"TRUE":"FALSE", + debugstr_w(cmdline)); + + return S_OK; +} + +/*********************************************************************** + * DllCanUnloadNow (URLMON.@) + */ +HRESULT WINAPI URLMON_DllCanUnloadNow(void) +{ + return URLMON_refCount != 0 ? S_FALSE : S_OK; +} + + + +/****************************************************************************** + * Urlmon ClassFactory + */ +typedef struct { + IClassFactory ITF_IClassFactory; + + DWORD ref; + HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj); +} IClassFactoryImpl; + +struct object_creation_info +{ + const CLSID *clsid; + HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj); +}; + +static const struct object_creation_info object_creation[] = +{ + { &CLSID_InternetSecurityManager, &SecManagerImpl_Construct }, + { &CLSID_InternetZoneManager, ZoneMgrImpl_Construct } +}; + +static HRESULT WINAPI +CF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + + if (IsEqualGUID(riid, &IID_IUnknown) + || IsEqualGUID(riid, &IID_IClassFactory)) + { + IClassFactory_AddRef(iface); + *ppobj = This; + return S_OK; + } + + WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj); + return E_NOINTERFACE; +} + +static ULONG WINAPI CF_AddRef(LPCLASSFACTORY iface) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + URLMON_LockModule(); + + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI CF_Release(LPCLASSFACTORY iface) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + + ULONG ref = InterlockedDecrement(&This->ref); + + if (ref == 0) + HeapFree(GetProcessHeap(), 0, This); + + URLMON_UnlockModule(); + + return ref; +} + + +static HRESULT WINAPI CF_CreateInstance(LPCLASSFACTORY iface, LPUNKNOWN pOuter, + REFIID riid, LPVOID *ppobj) +{ + IClassFactoryImpl *This = (IClassFactoryImpl *)iface; + HRESULT hres; + LPUNKNOWN punk; + + TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj); + + *ppobj = NULL; + if(SUCCEEDED(hres = This->pfnCreateInstance(pOuter, (LPVOID *) &punk))) { + hres = IUnknown_QueryInterface(punk, riid, ppobj); + IUnknown_Release(punk); + } + return hres; +} + +static HRESULT WINAPI CF_LockServer(LPCLASSFACTORY iface,BOOL dolock) +{ + TRACE("(%d)\n", dolock); + + if (dolock) + URLMON_LockModule(); + else + URLMON_UnlockModule(); + + return S_OK; +} + +static IClassFactoryVtbl CF_Vtbl = +{ + CF_QueryInterface, + CF_AddRef, + CF_Release, + CF_CreateInstance, + CF_LockServer +}; + +/******************************************************************************* + * DllGetClassObject [URLMON.@] + * Retrieves class object from a DLL object + * + * NOTES + * Docs say returns STDAPI + * + * PARAMS + * rclsid [I] CLSID for the class object + * riid [I] Reference to identifier of interface for class object + * ppv [O] Address of variable to receive interface pointer for riid + * + * RETURNS + * Success: S_OK + * Failure: CLASS_E_CLASSNOTAVAILABLE, E_OUTOFMEMORY, E_INVALIDARG, + * E_UNEXPECTED + */ + +DWORD WINAPI URLMON_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) +{ + int i; + IClassFactoryImpl *factory; + + TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); + + if ( !IsEqualGUID( &IID_IClassFactory, riid ) + && ! IsEqualGUID( &IID_IUnknown, riid) ) + return E_NOINTERFACE; + + for (i=0; i < sizeof(object_creation)/sizeof(object_creation[0]); i++) + { + if (IsEqualGUID(object_creation[i].clsid, rclsid)) + break; + } + + if (i == sizeof(object_creation)/sizeof(object_creation[0])) + { + FIXME("%s: no class found.\n", debugstr_guid(rclsid)); + return CLASS_E_CLASSNOTAVAILABLE; + } + + factory = HeapAlloc(GetProcessHeap(), 0, sizeof(*factory)); + if (factory == NULL) return E_OUTOFMEMORY; + + factory->ITF_IClassFactory.lpVtbl = &CF_Vtbl; + factory->ref = 1; + + factory->pfnCreateInstance = object_creation[i].pfnCreateInstance; + + *ppv = &(factory->ITF_IClassFactory); + return S_OK; +} + + +/*********************************************************************** + * DllRegisterServerEx (URLMON.@) + */ +HRESULT WINAPI URLMON_DllRegisterServerEx(void) +{ + FIXME("(void): stub\n"); + + return E_FAIL; +} + +/************************************************************************** + * UrlMkSetSessionOption (URLMON.@) + */ +HRESULT WINAPI UrlMkSetSessionOption(DWORD dwOption, LPVOID *pBuffer, DWORD dwBufferLength, + DWORD Reserved) +{ + FIXME("(%#lx, %p, %#lx): stub\n", dwOption, pBuffer, dwBufferLength); + + return S_OK; +} + +/************************************************************************** + * UrlMkGetSessionOption (URLMON.@) + */ +HRESULT WINAPI UrlMkGetSessionOption(DWORD dwOption, LPVOID *pBuffer, DWORD dwBufferLength, + DWORD* pdwBufferLength, DWORD dwReserved) +{ + FIXME("(%#lx, %p, %#lx, %p): stub\n", dwOption, pBuffer, dwBufferLength, pdwBufferLength); + + return S_OK; +} + +/************************************************************************** + * ObtainUserAgentString (URLMON.@) + */ +HRESULT WINAPI ObtainUserAgentString(DWORD dwOption, LPCSTR pcszUAOut, DWORD *cbSize) +{ + FIXME("(%ld, %p, %p): stub\n", dwOption, pcszUAOut, cbSize); + + if(dwOption) { + ERR("dwOption: %ld, must be zero\n", dwOption); + } + + return S_OK; +} + +HRESULT WINAPI CoInternetCombineUrl(LPCWSTR pwzBaseUrl, LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags, + LPWSTR pwzResult, DWORD cchResult, DWORD *pcchResult, DWORD dwReserved) +{ + HRESULT hres; + DWORD size = cchResult; + + TRACE("(%s,%s,0x%08lx,%p,%ld,%p,%ld)\n", debugstr_w(pwzBaseUrl), debugstr_w(pwzRelativeUrl), dwCombineFlags, + pwzResult, cchResult, pcchResult, dwReserved); + hres = UrlCombineW(pwzBaseUrl, pwzRelativeUrl, pwzResult, &size, dwCombineFlags); + if(pcchResult) *pcchResult = size; + return hres; +} + +HRESULT WINAPI CoInternetCompareUrl(LPCWSTR pwzUrl1, LPCWSTR pwzUrl2, DWORD dwCompareFlags) +{ + TRACE("(%s,%s,%08lx)\n", debugstr_w(pwzUrl1), debugstr_w(pwzUrl2), dwCompareFlags); + return UrlCompareW(pwzUrl1, pwzUrl2, dwCompareFlags)==0?S_OK:S_FALSE; +} + +/************************************************************************** + * IsValidURL (URLMON.@) + * + * Determines if a specified string is a valid URL. + * + * PARAMS + * pBC [I] ignored, must be NULL. + * szURL [I] string that represents the URL in question. + * dwReserved [I] reserved and must be zero. + * + * RETURNS + * Success: S_OK. + * Failure: S_FALSE. + * returns E_INVALIDARG if one or more of the args is invalid. + * + * TODO: + * test functionality against windows to see what a valid URL is. + */ +HRESULT WINAPI IsValidURL(LPBC pBC, LPCWSTR szURL, DWORD dwReserved) +{ + FIXME("(%p, %s, %ld): stub\n", pBC, debugstr_w(szURL), dwReserved); + + if (pBC != NULL || dwReserved != 0) + return E_INVALIDARG; + + return S_OK; +} + +/************************************************************************** + * FaultInIEFeature (URLMON.@) + * + * Undocumented. Appears to be used by native shdocvw.dll. + */ +HRESULT WINAPI FaultInIEFeature( HWND hwnd, uCLSSPEC * pClassSpec, + QUERYCONTEXT *pQuery, DWORD flags ) +{ + FIXME("%p %p %p %08lx\n", hwnd, pClassSpec, pQuery, flags); + return E_NOTIMPL; +} + +/************************************************************************** + * CoGetClassObjectFromURL (URLMON.@) + */ +HRESULT WINAPI CoGetClassObjectFromURL( REFCLSID rclsid, LPCWSTR szCodeURL, DWORD dwFileVersionMS, + DWORD dwFileVersionLS, LPCWSTR szContentType, + LPBINDCTX pBindCtx, DWORD dwClsContext, LPVOID pvReserved, + REFIID riid, LPVOID *ppv ) +{ + FIXME("(%s %s %ld %ld %s %p %ld %p %s %p) Stub!\n", debugstr_guid(rclsid), debugstr_w(szCodeURL), + dwFileVersionMS, dwFileVersionLS, debugstr_w(szContentType), pBindCtx, dwClsContext, pvReserved, + debugstr_guid(riid), ppv); + return E_NOINTERFACE; +} diff --git a/reactos/lib/urlmon/urlmon_main.h b/reactos/lib/urlmon/urlmon_main.h index 5e01edb6985..f65e2d63a6e 100644 --- a/reactos/lib/urlmon/urlmon_main.h +++ b/reactos/lib/urlmon/urlmon_main.h @@ -1,53 +1,53 @@ -/* - * Copyright 2002 Huw D M Davies for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __WINE_URLMON_MAIN_H -#define __WINE_URLMON_MAIN_H - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" - -extern HINSTANCE URLMON_hInstance; -extern HRESULT SecManagerImpl_Construct(IUnknown *pUnkOuter, LPVOID *ppobj); -extern HRESULT ZoneMgrImpl_Construct(IUnknown *pUnkOuter, LPVOID *ppobj); - -/********************************************************************** - * Dll lifetime tracking declaration for urlmon.dll - */ -extern LONG URLMON_refCount; -static inline void URLMON_LockModule() { InterlockedIncrement( &URLMON_refCount ); } -static inline void URLMON_UnlockModule() { InterlockedDecrement( &URLMON_refCount ); } - -#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) - -typedef struct -{ - const IStreamVtbl *lpVtbl; - DWORD ref; - HANDLE handle; - BOOL closed; - WCHAR *pszFileName; - WCHAR *pszURL; -} IUMCacheStream; - -HRESULT UMCreateStreamOnCacheFile(LPCWSTR pszURL, DWORD dwSize, LPWSTR pszFileName, HANDLE *phfile, IUMCacheStream **ppstr); -void UMCloseCacheFileStream(IUMCacheStream *pstr); - -#endif /* __WINE_URLMON_MAIN_H */ +/* + * Copyright 2002 Huw D M Davies for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_URLMON_MAIN_H +#define __WINE_URLMON_MAIN_H + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" + +extern HINSTANCE URLMON_hInstance; +extern HRESULT SecManagerImpl_Construct(IUnknown *pUnkOuter, LPVOID *ppobj); +extern HRESULT ZoneMgrImpl_Construct(IUnknown *pUnkOuter, LPVOID *ppobj); + +/********************************************************************** + * Dll lifetime tracking declaration for urlmon.dll + */ +extern LONG URLMON_refCount; +static inline void URLMON_LockModule() { InterlockedIncrement( &URLMON_refCount ); } +static inline void URLMON_UnlockModule() { InterlockedDecrement( &URLMON_refCount ); } + +#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) + +typedef struct +{ + const IStreamVtbl *lpVtbl; + DWORD ref; + HANDLE handle; + BOOL closed; + WCHAR *pszFileName; + WCHAR *pszURL; +} IUMCacheStream; + +HRESULT UMCreateStreamOnCacheFile(LPCWSTR pszURL, DWORD dwSize, LPWSTR pszFileName, HANDLE *phfile, IUMCacheStream **ppstr); +void UMCloseCacheFileStream(IUMCacheStream *pstr); + +#endif /* __WINE_URLMON_MAIN_H */ diff --git a/reactos/lib/wdmguid/wdmguid.c b/reactos/lib/wdmguid/wdmguid.c index 919c4fd6814..724b87dcbe1 100644 --- a/reactos/lib/wdmguid/wdmguid.c +++ b/reactos/lib/wdmguid/wdmguid.c @@ -1,10 +1,10 @@ - -#include <stdarg.h> - -#define COM_NO_WINDOWS_H -#include "initguid.h" - -#include <ddk/wdmguid.h> -#include <ndk/sysguid.h> - -/* EOF */ + +#include <stdarg.h> + +#define COM_NO_WINDOWS_H +#include "initguid.h" + +#include <ddk/wdmguid.h> +#include <ndk/sysguid.h> + +/* EOF */ diff --git a/reactos/lib/winmm/driver.c b/reactos/lib/winmm/driver.c index d13a2b967ab..ce3e74677f0 100644 --- a/reactos/lib/winmm/driver.c +++ b/reactos/lib/winmm/driver.c @@ -1,573 +1,573 @@ -/* - * WINE Drivers functions - * - * Copyright 1994 Martin Ayotte - * Copyright 1998 Marcus Meissner - * Copyright 1999 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <string.h> -#include <stdarg.h> -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "winreg.h" -#include "mmddk.h" -#include "winemm.h" -#include "wine/debug.h" -#include "wine/unicode.h" - -WINE_DEFAULT_DEBUG_CHANNEL(driver); - -static LPWINE_DRIVER lpDrvItemList /* = NULL */; -static const WCHAR HKLM_BASE[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\', - 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',0}; - -WINE_MMTHREAD* (*pFnGetMMThread16)(UINT16 h) /* = NULL */; -LPWINE_DRIVER (*pFnOpenDriver16)(LPCWSTR,LPCWSTR,LPARAM) /* = NULL */; -LRESULT (*pFnCloseDriver16)(UINT16,LPARAM,LPARAM) /* = NULL */; -LRESULT (*pFnSendMessage16)(UINT16,UINT,LPARAM,LPARAM) /* = NULL */; - -/************************************************************************** - * DRIVER_GetNumberOfModuleRefs [internal] - * - * Returns the number of open drivers which share the same module. - */ -static unsigned DRIVER_GetNumberOfModuleRefs(HMODULE hModule, WINE_DRIVER** found) -{ - LPWINE_DRIVER lpDrv; - unsigned count = 0; - - if (found) *found = NULL; - for (lpDrv = lpDrvItemList; lpDrv; lpDrv = lpDrv->lpNextItem) - { - if (!(lpDrv->dwFlags & WINE_GDF_16BIT) && lpDrv->d.d32.hModule == hModule) - { - if (found && !*found) *found = lpDrv; - count++; - } - } - return count; -} - -/************************************************************************** - * DRIVER_FindFromHDrvr [internal] - * - * From a hDrvr being 32 bits, returns the WINE internal structure. - */ -LPWINE_DRIVER DRIVER_FindFromHDrvr(HDRVR hDrvr) -{ - LPWINE_DRIVER d = (LPWINE_DRIVER)hDrvr; - - if (hDrvr && HeapValidate(GetProcessHeap(), 0, d) && d->dwMagic == WINE_DI_MAGIC) { - return d; - } - return NULL; -} - -/************************************************************************** - * DRIVER_SendMessage [internal] - */ -static LRESULT inline DRIVER_SendMessage(LPWINE_DRIVER lpDrv, UINT msg, - LPARAM lParam1, LPARAM lParam2) -{ - LRESULT ret = 0; - - if (lpDrv->dwFlags & WINE_GDF_16BIT) { - /* no need to check mmsystem presence: the driver must have been opened as a 16 bit one, - */ - if (pFnSendMessage16) - ret = pFnSendMessage16(lpDrv->d.d16.hDriver16, msg, lParam1, lParam2); - } else { - TRACE("Before call32 proc=%p drvrID=%08lx hDrv=%p wMsg=%04x p1=%08lx p2=%08lx\n", - lpDrv->d.d32.lpDrvProc, lpDrv->d.d32.dwDriverID, (HDRVR)lpDrv, msg, lParam1, lParam2); - ret = lpDrv->d.d32.lpDrvProc(lpDrv->d.d32.dwDriverID, (HDRVR)lpDrv, msg, lParam1, lParam2); - TRACE("After call32 proc=%p drvrID=%08lx hDrv=%p wMsg=%04x p1=%08lx p2=%08lx => %08lx\n", - lpDrv->d.d32.lpDrvProc, lpDrv->d.d32.dwDriverID, (HDRVR)lpDrv, msg, lParam1, lParam2, ret); - } - return ret; -} - -/************************************************************************** - * SendDriverMessage [WINMM.@] - * DrvSendMessage [WINMM.@] - */ -LRESULT WINAPI SendDriverMessage(HDRVR hDriver, UINT msg, LPARAM lParam1, - LPARAM lParam2) -{ - LPWINE_DRIVER lpDrv; - LRESULT retval = 0; - - TRACE("(%p, %04X, %08lX, %08lX)\n", hDriver, msg, lParam1, lParam2); - - if ((lpDrv = DRIVER_FindFromHDrvr(hDriver)) != NULL) { - retval = DRIVER_SendMessage(lpDrv, msg, lParam1, lParam2); - } else { - WARN("Bad driver handle %p\n", hDriver); - } - TRACE("retval = %ld\n", retval); - - return retval; -} - -/************************************************************************** - * DRIVER_RemoveFromList [internal] - * - * Generates all the logic to handle driver closure / deletion - * Removes a driver struct to the list of open drivers. - */ -static BOOL DRIVER_RemoveFromList(LPWINE_DRIVER lpDrv) -{ - if (!(lpDrv->dwFlags & WINE_GDF_16BIT)) { - /* last of this driver in list ? */ - if (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, NULL) == 1) { - DRIVER_SendMessage(lpDrv, DRV_DISABLE, 0L, 0L); - DRIVER_SendMessage(lpDrv, DRV_FREE, 0L, 0L); - } - } - - if (lpDrv->lpPrevItem) - lpDrv->lpPrevItem->lpNextItem = lpDrv->lpNextItem; - else - lpDrvItemList = lpDrv->lpNextItem; - if (lpDrv->lpNextItem) - lpDrv->lpNextItem->lpPrevItem = lpDrv->lpPrevItem; - /* trash magic number */ - lpDrv->dwMagic ^= 0xa5a5a5a5; - - return TRUE; -} - -/************************************************************************** - * DRIVER_AddToList [internal] - * - * Adds a driver struct to the list of open drivers. - * Generates all the logic to handle driver creation / open. - */ -static BOOL DRIVER_AddToList(LPWINE_DRIVER lpNewDrv, LPARAM lParam1, LPARAM lParam2) -{ - lpNewDrv->dwMagic = WINE_DI_MAGIC; - /* First driver to be loaded for this module, need to load correctly the module */ - if (!(lpNewDrv->dwFlags & WINE_GDF_16BIT)) { - /* first of this driver in list ? */ - if (DRIVER_GetNumberOfModuleRefs(lpNewDrv->d.d32.hModule, NULL) == 0) { - if (DRIVER_SendMessage(lpNewDrv, DRV_LOAD, 0L, 0L) != DRV_SUCCESS) { - TRACE("DRV_LOAD failed on driver 0x%08lx\n", (DWORD)lpNewDrv); - return FALSE; - } - /* returned value is not checked */ - DRIVER_SendMessage(lpNewDrv, DRV_ENABLE, 0L, 0L); - } - } - - lpNewDrv->lpNextItem = NULL; - if (lpDrvItemList == NULL) { - lpDrvItemList = lpNewDrv; - lpNewDrv->lpPrevItem = NULL; - } else { - LPWINE_DRIVER lpDrv = lpDrvItemList; /* find end of list */ - while (lpDrv->lpNextItem != NULL) - lpDrv = lpDrv->lpNextItem; - - lpDrv->lpNextItem = lpNewDrv; - lpNewDrv->lpPrevItem = lpDrv; - } - - if (!(lpNewDrv->dwFlags & WINE_GDF_16BIT)) { - /* Now just open a new instance of a driver on this module */ - lpNewDrv->d.d32.dwDriverID = DRIVER_SendMessage(lpNewDrv, DRV_OPEN, lParam1, lParam2); - - if (lpNewDrv->d.d32.dwDriverID == 0) { - TRACE("DRV_OPEN failed on driver 0x%08lx\n", (DWORD)lpNewDrv); - DRIVER_RemoveFromList(lpNewDrv); - return FALSE; - } - } - return TRUE; -} - -/************************************************************************** - * DRIVER_GetLibName [internal] - * - */ -BOOL DRIVER_GetLibName(LPCWSTR keyName, LPCWSTR sectName, LPWSTR buf, int sz) -{ - HKEY hKey, hSecKey; - DWORD bufLen, lRet; - static const WCHAR wszSystemIni[] = {'S','Y','S','T','E','M','.','I','N','I',0}; - WCHAR wsznull = '\0'; - - lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, HKLM_BASE, 0, KEY_QUERY_VALUE, &hKey); - if (lRet == ERROR_SUCCESS) { - lRet = RegOpenKeyExW(hKey, sectName, 0, KEY_QUERY_VALUE, &hSecKey); - if (lRet == ERROR_SUCCESS) { - bufLen = sz; - lRet = RegQueryValueExW(hSecKey, keyName, 0, 0, (void*)buf, &bufLen); - RegCloseKey( hSecKey ); - } - RegCloseKey( hKey ); - } - if (lRet == ERROR_SUCCESS) return TRUE; - /* default to system.ini if we can't find it in the registry, - * to support native installations where system.ini is still used */ - return GetPrivateProfileStringW(sectName, keyName, &wsznull, buf, sz / sizeof(WCHAR), wszSystemIni); -} - -/************************************************************************** - * DRIVER_TryOpenDriver32 [internal] - * - * Tries to load a 32 bit driver whose DLL's (module) name is fn - */ -LPWINE_DRIVER DRIVER_TryOpenDriver32(LPCWSTR fn, LPARAM lParam2) -{ - LPWINE_DRIVER lpDrv = NULL; - HMODULE hModule = 0; - LPWSTR ptr; - LPCSTR cause = 0; - - TRACE("(%s, %08lX);\n", debugstr_w(fn), lParam2); - - if ((ptr = strchrW(fn, ' ')) != NULL) { - *ptr++ = '\0'; - while (*ptr == ' ') ptr++; - if (*ptr == '\0') ptr = NULL; - } - - lpDrv = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_DRIVER)); - if (lpDrv == NULL) {cause = "OOM"; goto exit;} - - if ((hModule = LoadLibraryW(fn)) == 0) {cause = "Not a 32 bit lib"; goto exit;} - - lpDrv->d.d32.lpDrvProc = (DRIVERPROC)GetProcAddress(hModule, "DriverProc"); - if (lpDrv->d.d32.lpDrvProc == NULL) {cause = "no DriverProc"; goto exit;} - - lpDrv->dwFlags = 0; - lpDrv->d.d32.hModule = hModule; - lpDrv->d.d32.dwDriverID = 0; - - /* Win32 installable drivers must support a two phase opening scheme: - * + first open with NULL as lParam2 (session instance), - * + then do a second open with the real non null lParam2) - */ - if (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, NULL) == 0 && lParam2) - { - LPWINE_DRIVER ret; - - if (!DRIVER_AddToList(lpDrv, (LPARAM)ptr, 0L)) - { - cause = "load0 failed"; - goto exit; - } - ret = DRIVER_TryOpenDriver32(fn, lParam2); - if (!ret) - { - CloseDriver((HDRVR)lpDrv, 0L, 0L); - cause = "load1 failed"; - goto exit; - } - return ret; - } - - if (!DRIVER_AddToList(lpDrv, (LPARAM)ptr, lParam2)) - {cause = "load failed"; goto exit;} - - TRACE("=> %p\n", lpDrv); - return lpDrv; - exit: - FreeLibrary(hModule); - HeapFree(GetProcessHeap(), 0, lpDrv); - TRACE("Unable to load 32 bit module %s: %s\n", debugstr_w(fn), cause); - return NULL; -} - -/************************************************************************** - * OpenDriverA [WINMM.@] - * DrvOpenA [WINMM.@] - * (0,1,DRV_LOAD ,0 ,0) - * (0,1,DRV_ENABLE,0 ,0) - * (0,1,DRV_OPEN ,buf[256],0) - */ -HDRVR WINAPI OpenDriverA(LPCSTR lpDriverName, LPCSTR lpSectionName, LPARAM lParam) -{ - INT len; - LPWSTR dn = NULL; - LPWSTR sn = NULL; - HDRVR ret = 0; - - if (lpDriverName) - { - len = MultiByteToWideChar( CP_ACP, 0, lpDriverName, -1, NULL, 0 ); - dn = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - if (!dn) goto done; - MultiByteToWideChar( CP_ACP, 0, lpDriverName, -1, dn, len ); - } - - if (lpSectionName) - { - len = MultiByteToWideChar( CP_ACP, 0, lpSectionName, -1, NULL, 0 ); - sn = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - if (!sn) goto done; - MultiByteToWideChar( CP_ACP, 0, lpSectionName, -1, sn, len ); - } - - ret = OpenDriver(dn, sn, lParam); - -done: - HeapFree(GetProcessHeap(), 0, dn); - HeapFree(GetProcessHeap(), 0, sn); - return ret; -} - -/************************************************************************** - * OpenDriver [WINMM.@] - * DrvOpen [WINMM.@] - */ -HDRVR WINAPI OpenDriver(LPCWSTR lpDriverName, LPCWSTR lpSectionName, LPARAM lParam) -{ - LPWINE_DRIVER lpDrv = NULL; - WCHAR libName[128]; - LPCWSTR lsn = lpSectionName; - - TRACE("(%s, %s, 0x%08lx);\n", - debugstr_w(lpDriverName), debugstr_w(lpSectionName), lParam); - - if (lsn == NULL) { - static const WCHAR wszDrivers32[] = {'D','r','i','v','e','r','s','3','2',0}; - lstrcpynW(libName, lpDriverName, sizeof(libName) / sizeof(WCHAR)); - - if ((lpDrv = DRIVER_TryOpenDriver32(libName, lParam))) - goto the_end; - lsn = wszDrivers32; - } - if (DRIVER_GetLibName(lpDriverName, lsn, libName, sizeof(libName)) && - (lpDrv = DRIVER_TryOpenDriver32(libName, lParam))) - goto the_end; - - /* now we will try a 16 bit driver (and add all the glue to make it work... which - * is located in our mmsystem implementation) - * so ensure, we can load our mmsystem, otherwise just fail - */ - WINMM_CheckForMMSystem(); - if (pFnOpenDriver16 && - (lpDrv = pFnOpenDriver16(lpDriverName, lpSectionName, lParam))) - { - if (DRIVER_AddToList(lpDrv, 0, lParam)) goto the_end; - HeapFree(GetProcessHeap(), 0, lpDrv); - } - TRACE("Failed to open driver %s from system.ini file, section %s\n", - debugstr_w(lpDriverName), debugstr_w(lpSectionName)); - return 0; - - the_end: - if (lpDrv) TRACE("=> %08lx\n", (DWORD)lpDrv); - return (HDRVR)lpDrv; -} - -/************************************************************************** - * CloseDriver [WINMM.@] - * DrvClose [WINMM.@] - */ -LRESULT WINAPI CloseDriver(HDRVR hDrvr, LPARAM lParam1, LPARAM lParam2) -{ - LPWINE_DRIVER lpDrv; - - TRACE("(%p, %08lX, %08lX);\n", hDrvr, lParam1, lParam2); - - if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL) - { - if (lpDrv->dwFlags & WINE_GDF_16BIT) - { - if (pFnCloseDriver16) - pFnCloseDriver16(lpDrv->d.d16.hDriver16, lParam1, lParam2); - } - else - { - DRIVER_SendMessage(lpDrv, DRV_CLOSE, lParam1, lParam2); - lpDrv->d.d32.dwDriverID = 0; - } - if (DRIVER_RemoveFromList(lpDrv)) { - if (!(lpDrv->dwFlags & WINE_GDF_16BIT)) - { - LPWINE_DRIVER lpDrv0; - - /* if driver has an opened session instance, we have to close it too */ - if (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, &lpDrv0) == 1) - { - DRIVER_SendMessage(lpDrv0, DRV_CLOSE, 0L, 0L); - lpDrv0->d.d32.dwDriverID = 0; - DRIVER_RemoveFromList(lpDrv0); - FreeLibrary(lpDrv0->d.d32.hModule); - HeapFree(GetProcessHeap(), 0, lpDrv0); - } - FreeLibrary(lpDrv->d.d32.hModule); - } - HeapFree(GetProcessHeap(), 0, lpDrv); - return TRUE; - } - } - WARN("Failed to close driver\n"); - return FALSE; -} - -/************************************************************************** - * GetDriverFlags [WINMM.@] - * [in] hDrvr handle to the driver - * - * Returns: - * 0x00000000 if hDrvr is an invalid handle - * 0x80000000 if hDrvr is a valid 32 bit driver - * 0x90000000 if hDrvr is a valid 16 bit driver - * - * native WINMM doesn't return those flags - * 0x80000000 for a valid 32 bit driver and that's it - * (I may have mixed up the two flags :-( - */ -DWORD WINAPI GetDriverFlags(HDRVR hDrvr) -{ - LPWINE_DRIVER lpDrv; - DWORD ret = 0; - - TRACE("(%p)\n", hDrvr); - - if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL) { - ret = WINE_GDF_EXIST | lpDrv->dwFlags; - } - return ret; -} - -/************************************************************************** - * GetDriverModuleHandle [WINMM.@] - * DrvGetModuleHandle [WINMM.@] - */ -HMODULE WINAPI GetDriverModuleHandle(HDRVR hDrvr) -{ - LPWINE_DRIVER lpDrv; - HMODULE hModule = 0; - - TRACE("(%p);\n", hDrvr); - - if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL) { - if (!(lpDrv->dwFlags & WINE_GDF_16BIT)) - hModule = lpDrv->d.d32.hModule; - } - TRACE("=> %p\n", hModule); - return hModule; -} - -/************************************************************************** - * DefDriverProc [WINMM.@] - * DrvDefDriverProc [WINMM.@] - */ -LRESULT WINAPI DefDriverProc(DWORD_PTR dwDriverIdentifier, HDRVR hDrv, - UINT Msg, LPARAM lParam1, LPARAM lParam2) -{ - switch (Msg) { - case DRV_LOAD: - case DRV_FREE: - case DRV_ENABLE: - case DRV_DISABLE: - return 1; - case DRV_INSTALL: - case DRV_REMOVE: - return DRV_SUCCESS; - default: - return 0; - } -} - -/************************************************************************** - * DriverCallback [WINMM.@] - */ -BOOL WINAPI DriverCallback(DWORD dwCallBack, UINT uFlags, HDRVR hDev, - UINT wMsg, DWORD dwUser, DWORD dwParam1, - DWORD dwParam2) -{ - TRACE("(%08lX, %04X, %p, %04X, %08lX, %08lX, %08lX); !\n", - dwCallBack, uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2); - - switch (uFlags & DCB_TYPEMASK) { - case DCB_NULL: - TRACE("Null !\n"); - if (dwCallBack) - WARN("uFlags=%04X has null DCB value, but dwCallBack=%08lX is not null !\n", uFlags, dwCallBack); - break; - case DCB_WINDOW: - TRACE("Window(%04lX) handle=%p!\n", dwCallBack, hDev); - PostMessageA((HWND)dwCallBack, wMsg, (WPARAM)hDev, dwParam1); - break; - case DCB_TASK: /* aka DCB_THREAD */ - TRACE("Task(%04lx) !\n", dwCallBack); - PostThreadMessageA(dwCallBack, wMsg, (WPARAM)hDev, dwParam1); - break; - case DCB_FUNCTION: - TRACE("Function (32 bit) !\n"); - ((LPDRVCALLBACK)dwCallBack)(hDev, wMsg, dwUser, dwParam1, dwParam2); - break; - case DCB_EVENT: - TRACE("Event(%08lx) !\n", dwCallBack); - SetEvent((HANDLE)dwCallBack); - break; - case 6: /* I would dub it DCB_MMTHREADSIGNAL */ - /* this is an undocumented DCB_ value used for mmThreads - * loword of dwCallBack contains the handle of the lpMMThd block - * which dwSignalCount has to be incremented - */ - if (pFnGetMMThread16) - { - WINE_MMTHREAD* lpMMThd = pFnGetMMThread16(LOWORD(dwCallBack)); - - TRACE("mmThread (%04x, %p) !\n", LOWORD(dwCallBack), lpMMThd); - /* same as mmThreadSignal16 */ - InterlockedIncrement(&lpMMThd->dwSignalCount); - SetEvent(lpMMThd->hEvent); - /* some other stuff on lpMMThd->hVxD */ - } - break; -#if 0 - case 4: - /* this is an undocumented DCB_ value for... I don't know */ - break; -#endif - default: - WARN("Unknown callback type %d\n", uFlags & DCB_TYPEMASK); - return FALSE; - } - TRACE("Done\n"); - return TRUE; -} - -/****************************************************************** - * DRIVER_UnloadAll - * - * - */ -void DRIVER_UnloadAll(void) -{ - LPWINE_DRIVER lpDrv; - LPWINE_DRIVER lpNextDrv = NULL; - unsigned count = 0; - - for (lpDrv = lpDrvItemList; lpDrv != NULL; lpDrv = lpNextDrv) - { - lpNextDrv = lpDrv->lpNextItem; - CloseDriver((HDRVR)lpDrv, 0, 0); - count++; - } - TRACE("Unloaded %u drivers\n", count); -} +/* + * WINE Drivers functions + * + * Copyright 1994 Martin Ayotte + * Copyright 1998 Marcus Meissner + * Copyright 1999 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <string.h> +#include <stdarg.h> +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "winreg.h" +#include "mmddk.h" +#include "winemm.h" +#include "wine/debug.h" +#include "wine/unicode.h" + +WINE_DEFAULT_DEBUG_CHANNEL(driver); + +static LPWINE_DRIVER lpDrvItemList /* = NULL */; +static const WCHAR HKLM_BASE[] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n',0}; + +WINE_MMTHREAD* (*pFnGetMMThread16)(UINT16 h) /* = NULL */; +LPWINE_DRIVER (*pFnOpenDriver16)(LPCWSTR,LPCWSTR,LPARAM) /* = NULL */; +LRESULT (*pFnCloseDriver16)(UINT16,LPARAM,LPARAM) /* = NULL */; +LRESULT (*pFnSendMessage16)(UINT16,UINT,LPARAM,LPARAM) /* = NULL */; + +/************************************************************************** + * DRIVER_GetNumberOfModuleRefs [internal] + * + * Returns the number of open drivers which share the same module. + */ +static unsigned DRIVER_GetNumberOfModuleRefs(HMODULE hModule, WINE_DRIVER** found) +{ + LPWINE_DRIVER lpDrv; + unsigned count = 0; + + if (found) *found = NULL; + for (lpDrv = lpDrvItemList; lpDrv; lpDrv = lpDrv->lpNextItem) + { + if (!(lpDrv->dwFlags & WINE_GDF_16BIT) && lpDrv->d.d32.hModule == hModule) + { + if (found && !*found) *found = lpDrv; + count++; + } + } + return count; +} + +/************************************************************************** + * DRIVER_FindFromHDrvr [internal] + * + * From a hDrvr being 32 bits, returns the WINE internal structure. + */ +LPWINE_DRIVER DRIVER_FindFromHDrvr(HDRVR hDrvr) +{ + LPWINE_DRIVER d = (LPWINE_DRIVER)hDrvr; + + if (hDrvr && HeapValidate(GetProcessHeap(), 0, d) && d->dwMagic == WINE_DI_MAGIC) { + return d; + } + return NULL; +} + +/************************************************************************** + * DRIVER_SendMessage [internal] + */ +static LRESULT inline DRIVER_SendMessage(LPWINE_DRIVER lpDrv, UINT msg, + LPARAM lParam1, LPARAM lParam2) +{ + LRESULT ret = 0; + + if (lpDrv->dwFlags & WINE_GDF_16BIT) { + /* no need to check mmsystem presence: the driver must have been opened as a 16 bit one, + */ + if (pFnSendMessage16) + ret = pFnSendMessage16(lpDrv->d.d16.hDriver16, msg, lParam1, lParam2); + } else { + TRACE("Before call32 proc=%p drvrID=%08lx hDrv=%p wMsg=%04x p1=%08lx p2=%08lx\n", + lpDrv->d.d32.lpDrvProc, lpDrv->d.d32.dwDriverID, (HDRVR)lpDrv, msg, lParam1, lParam2); + ret = lpDrv->d.d32.lpDrvProc(lpDrv->d.d32.dwDriverID, (HDRVR)lpDrv, msg, lParam1, lParam2); + TRACE("After call32 proc=%p drvrID=%08lx hDrv=%p wMsg=%04x p1=%08lx p2=%08lx => %08lx\n", + lpDrv->d.d32.lpDrvProc, lpDrv->d.d32.dwDriverID, (HDRVR)lpDrv, msg, lParam1, lParam2, ret); + } + return ret; +} + +/************************************************************************** + * SendDriverMessage [WINMM.@] + * DrvSendMessage [WINMM.@] + */ +LRESULT WINAPI SendDriverMessage(HDRVR hDriver, UINT msg, LPARAM lParam1, + LPARAM lParam2) +{ + LPWINE_DRIVER lpDrv; + LRESULT retval = 0; + + TRACE("(%p, %04X, %08lX, %08lX)\n", hDriver, msg, lParam1, lParam2); + + if ((lpDrv = DRIVER_FindFromHDrvr(hDriver)) != NULL) { + retval = DRIVER_SendMessage(lpDrv, msg, lParam1, lParam2); + } else { + WARN("Bad driver handle %p\n", hDriver); + } + TRACE("retval = %ld\n", retval); + + return retval; +} + +/************************************************************************** + * DRIVER_RemoveFromList [internal] + * + * Generates all the logic to handle driver closure / deletion + * Removes a driver struct to the list of open drivers. + */ +static BOOL DRIVER_RemoveFromList(LPWINE_DRIVER lpDrv) +{ + if (!(lpDrv->dwFlags & WINE_GDF_16BIT)) { + /* last of this driver in list ? */ + if (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, NULL) == 1) { + DRIVER_SendMessage(lpDrv, DRV_DISABLE, 0L, 0L); + DRIVER_SendMessage(lpDrv, DRV_FREE, 0L, 0L); + } + } + + if (lpDrv->lpPrevItem) + lpDrv->lpPrevItem->lpNextItem = lpDrv->lpNextItem; + else + lpDrvItemList = lpDrv->lpNextItem; + if (lpDrv->lpNextItem) + lpDrv->lpNextItem->lpPrevItem = lpDrv->lpPrevItem; + /* trash magic number */ + lpDrv->dwMagic ^= 0xa5a5a5a5; + + return TRUE; +} + +/************************************************************************** + * DRIVER_AddToList [internal] + * + * Adds a driver struct to the list of open drivers. + * Generates all the logic to handle driver creation / open. + */ +static BOOL DRIVER_AddToList(LPWINE_DRIVER lpNewDrv, LPARAM lParam1, LPARAM lParam2) +{ + lpNewDrv->dwMagic = WINE_DI_MAGIC; + /* First driver to be loaded for this module, need to load correctly the module */ + if (!(lpNewDrv->dwFlags & WINE_GDF_16BIT)) { + /* first of this driver in list ? */ + if (DRIVER_GetNumberOfModuleRefs(lpNewDrv->d.d32.hModule, NULL) == 0) { + if (DRIVER_SendMessage(lpNewDrv, DRV_LOAD, 0L, 0L) != DRV_SUCCESS) { + TRACE("DRV_LOAD failed on driver 0x%08lx\n", (DWORD)lpNewDrv); + return FALSE; + } + /* returned value is not checked */ + DRIVER_SendMessage(lpNewDrv, DRV_ENABLE, 0L, 0L); + } + } + + lpNewDrv->lpNextItem = NULL; + if (lpDrvItemList == NULL) { + lpDrvItemList = lpNewDrv; + lpNewDrv->lpPrevItem = NULL; + } else { + LPWINE_DRIVER lpDrv = lpDrvItemList; /* find end of list */ + while (lpDrv->lpNextItem != NULL) + lpDrv = lpDrv->lpNextItem; + + lpDrv->lpNextItem = lpNewDrv; + lpNewDrv->lpPrevItem = lpDrv; + } + + if (!(lpNewDrv->dwFlags & WINE_GDF_16BIT)) { + /* Now just open a new instance of a driver on this module */ + lpNewDrv->d.d32.dwDriverID = DRIVER_SendMessage(lpNewDrv, DRV_OPEN, lParam1, lParam2); + + if (lpNewDrv->d.d32.dwDriverID == 0) { + TRACE("DRV_OPEN failed on driver 0x%08lx\n", (DWORD)lpNewDrv); + DRIVER_RemoveFromList(lpNewDrv); + return FALSE; + } + } + return TRUE; +} + +/************************************************************************** + * DRIVER_GetLibName [internal] + * + */ +BOOL DRIVER_GetLibName(LPCWSTR keyName, LPCWSTR sectName, LPWSTR buf, int sz) +{ + HKEY hKey, hSecKey; + DWORD bufLen, lRet; + static const WCHAR wszSystemIni[] = {'S','Y','S','T','E','M','.','I','N','I',0}; + WCHAR wsznull = '\0'; + + lRet = RegOpenKeyExW(HKEY_LOCAL_MACHINE, HKLM_BASE, 0, KEY_QUERY_VALUE, &hKey); + if (lRet == ERROR_SUCCESS) { + lRet = RegOpenKeyExW(hKey, sectName, 0, KEY_QUERY_VALUE, &hSecKey); + if (lRet == ERROR_SUCCESS) { + bufLen = sz; + lRet = RegQueryValueExW(hSecKey, keyName, 0, 0, (void*)buf, &bufLen); + RegCloseKey( hSecKey ); + } + RegCloseKey( hKey ); + } + if (lRet == ERROR_SUCCESS) return TRUE; + /* default to system.ini if we can't find it in the registry, + * to support native installations where system.ini is still used */ + return GetPrivateProfileStringW(sectName, keyName, &wsznull, buf, sz / sizeof(WCHAR), wszSystemIni); +} + +/************************************************************************** + * DRIVER_TryOpenDriver32 [internal] + * + * Tries to load a 32 bit driver whose DLL's (module) name is fn + */ +LPWINE_DRIVER DRIVER_TryOpenDriver32(LPCWSTR fn, LPARAM lParam2) +{ + LPWINE_DRIVER lpDrv = NULL; + HMODULE hModule = 0; + LPWSTR ptr; + LPCSTR cause = 0; + + TRACE("(%s, %08lX);\n", debugstr_w(fn), lParam2); + + if ((ptr = strchrW(fn, ' ')) != NULL) { + *ptr++ = '\0'; + while (*ptr == ' ') ptr++; + if (*ptr == '\0') ptr = NULL; + } + + lpDrv = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_DRIVER)); + if (lpDrv == NULL) {cause = "OOM"; goto exit;} + + if ((hModule = LoadLibraryW(fn)) == 0) {cause = "Not a 32 bit lib"; goto exit;} + + lpDrv->d.d32.lpDrvProc = (DRIVERPROC)GetProcAddress(hModule, "DriverProc"); + if (lpDrv->d.d32.lpDrvProc == NULL) {cause = "no DriverProc"; goto exit;} + + lpDrv->dwFlags = 0; + lpDrv->d.d32.hModule = hModule; + lpDrv->d.d32.dwDriverID = 0; + + /* Win32 installable drivers must support a two phase opening scheme: + * + first open with NULL as lParam2 (session instance), + * + then do a second open with the real non null lParam2) + */ + if (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, NULL) == 0 && lParam2) + { + LPWINE_DRIVER ret; + + if (!DRIVER_AddToList(lpDrv, (LPARAM)ptr, 0L)) + { + cause = "load0 failed"; + goto exit; + } + ret = DRIVER_TryOpenDriver32(fn, lParam2); + if (!ret) + { + CloseDriver((HDRVR)lpDrv, 0L, 0L); + cause = "load1 failed"; + goto exit; + } + return ret; + } + + if (!DRIVER_AddToList(lpDrv, (LPARAM)ptr, lParam2)) + {cause = "load failed"; goto exit;} + + TRACE("=> %p\n", lpDrv); + return lpDrv; + exit: + FreeLibrary(hModule); + HeapFree(GetProcessHeap(), 0, lpDrv); + TRACE("Unable to load 32 bit module %s: %s\n", debugstr_w(fn), cause); + return NULL; +} + +/************************************************************************** + * OpenDriverA [WINMM.@] + * DrvOpenA [WINMM.@] + * (0,1,DRV_LOAD ,0 ,0) + * (0,1,DRV_ENABLE,0 ,0) + * (0,1,DRV_OPEN ,buf[256],0) + */ +HDRVR WINAPI OpenDriverA(LPCSTR lpDriverName, LPCSTR lpSectionName, LPARAM lParam) +{ + INT len; + LPWSTR dn = NULL; + LPWSTR sn = NULL; + HDRVR ret = 0; + + if (lpDriverName) + { + len = MultiByteToWideChar( CP_ACP, 0, lpDriverName, -1, NULL, 0 ); + dn = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); + if (!dn) goto done; + MultiByteToWideChar( CP_ACP, 0, lpDriverName, -1, dn, len ); + } + + if (lpSectionName) + { + len = MultiByteToWideChar( CP_ACP, 0, lpSectionName, -1, NULL, 0 ); + sn = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); + if (!sn) goto done; + MultiByteToWideChar( CP_ACP, 0, lpSectionName, -1, sn, len ); + } + + ret = OpenDriver(dn, sn, lParam); + +done: + HeapFree(GetProcessHeap(), 0, dn); + HeapFree(GetProcessHeap(), 0, sn); + return ret; +} + +/************************************************************************** + * OpenDriver [WINMM.@] + * DrvOpen [WINMM.@] + */ +HDRVR WINAPI OpenDriver(LPCWSTR lpDriverName, LPCWSTR lpSectionName, LPARAM lParam) +{ + LPWINE_DRIVER lpDrv = NULL; + WCHAR libName[128]; + LPCWSTR lsn = lpSectionName; + + TRACE("(%s, %s, 0x%08lx);\n", + debugstr_w(lpDriverName), debugstr_w(lpSectionName), lParam); + + if (lsn == NULL) { + static const WCHAR wszDrivers32[] = {'D','r','i','v','e','r','s','3','2',0}; + lstrcpynW(libName, lpDriverName, sizeof(libName) / sizeof(WCHAR)); + + if ((lpDrv = DRIVER_TryOpenDriver32(libName, lParam))) + goto the_end; + lsn = wszDrivers32; + } + if (DRIVER_GetLibName(lpDriverName, lsn, libName, sizeof(libName)) && + (lpDrv = DRIVER_TryOpenDriver32(libName, lParam))) + goto the_end; + + /* now we will try a 16 bit driver (and add all the glue to make it work... which + * is located in our mmsystem implementation) + * so ensure, we can load our mmsystem, otherwise just fail + */ + WINMM_CheckForMMSystem(); + if (pFnOpenDriver16 && + (lpDrv = pFnOpenDriver16(lpDriverName, lpSectionName, lParam))) + { + if (DRIVER_AddToList(lpDrv, 0, lParam)) goto the_end; + HeapFree(GetProcessHeap(), 0, lpDrv); + } + TRACE("Failed to open driver %s from system.ini file, section %s\n", + debugstr_w(lpDriverName), debugstr_w(lpSectionName)); + return 0; + + the_end: + if (lpDrv) TRACE("=> %08lx\n", (DWORD)lpDrv); + return (HDRVR)lpDrv; +} + +/************************************************************************** + * CloseDriver [WINMM.@] + * DrvClose [WINMM.@] + */ +LRESULT WINAPI CloseDriver(HDRVR hDrvr, LPARAM lParam1, LPARAM lParam2) +{ + LPWINE_DRIVER lpDrv; + + TRACE("(%p, %08lX, %08lX);\n", hDrvr, lParam1, lParam2); + + if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL) + { + if (lpDrv->dwFlags & WINE_GDF_16BIT) + { + if (pFnCloseDriver16) + pFnCloseDriver16(lpDrv->d.d16.hDriver16, lParam1, lParam2); + } + else + { + DRIVER_SendMessage(lpDrv, DRV_CLOSE, lParam1, lParam2); + lpDrv->d.d32.dwDriverID = 0; + } + if (DRIVER_RemoveFromList(lpDrv)) { + if (!(lpDrv->dwFlags & WINE_GDF_16BIT)) + { + LPWINE_DRIVER lpDrv0; + + /* if driver has an opened session instance, we have to close it too */ + if (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, &lpDrv0) == 1) + { + DRIVER_SendMessage(lpDrv0, DRV_CLOSE, 0L, 0L); + lpDrv0->d.d32.dwDriverID = 0; + DRIVER_RemoveFromList(lpDrv0); + FreeLibrary(lpDrv0->d.d32.hModule); + HeapFree(GetProcessHeap(), 0, lpDrv0); + } + FreeLibrary(lpDrv->d.d32.hModule); + } + HeapFree(GetProcessHeap(), 0, lpDrv); + return TRUE; + } + } + WARN("Failed to close driver\n"); + return FALSE; +} + +/************************************************************************** + * GetDriverFlags [WINMM.@] + * [in] hDrvr handle to the driver + * + * Returns: + * 0x00000000 if hDrvr is an invalid handle + * 0x80000000 if hDrvr is a valid 32 bit driver + * 0x90000000 if hDrvr is a valid 16 bit driver + * + * native WINMM doesn't return those flags + * 0x80000000 for a valid 32 bit driver and that's it + * (I may have mixed up the two flags :-( + */ +DWORD WINAPI GetDriverFlags(HDRVR hDrvr) +{ + LPWINE_DRIVER lpDrv; + DWORD ret = 0; + + TRACE("(%p)\n", hDrvr); + + if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL) { + ret = WINE_GDF_EXIST | lpDrv->dwFlags; + } + return ret; +} + +/************************************************************************** + * GetDriverModuleHandle [WINMM.@] + * DrvGetModuleHandle [WINMM.@] + */ +HMODULE WINAPI GetDriverModuleHandle(HDRVR hDrvr) +{ + LPWINE_DRIVER lpDrv; + HMODULE hModule = 0; + + TRACE("(%p);\n", hDrvr); + + if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL) { + if (!(lpDrv->dwFlags & WINE_GDF_16BIT)) + hModule = lpDrv->d.d32.hModule; + } + TRACE("=> %p\n", hModule); + return hModule; +} + +/************************************************************************** + * DefDriverProc [WINMM.@] + * DrvDefDriverProc [WINMM.@] + */ +LRESULT WINAPI DefDriverProc(DWORD_PTR dwDriverIdentifier, HDRVR hDrv, + UINT Msg, LPARAM lParam1, LPARAM lParam2) +{ + switch (Msg) { + case DRV_LOAD: + case DRV_FREE: + case DRV_ENABLE: + case DRV_DISABLE: + return 1; + case DRV_INSTALL: + case DRV_REMOVE: + return DRV_SUCCESS; + default: + return 0; + } +} + +/************************************************************************** + * DriverCallback [WINMM.@] + */ +BOOL WINAPI DriverCallback(DWORD dwCallBack, UINT uFlags, HDRVR hDev, + UINT wMsg, DWORD dwUser, DWORD dwParam1, + DWORD dwParam2) +{ + TRACE("(%08lX, %04X, %p, %04X, %08lX, %08lX, %08lX); !\n", + dwCallBack, uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2); + + switch (uFlags & DCB_TYPEMASK) { + case DCB_NULL: + TRACE("Null !\n"); + if (dwCallBack) + WARN("uFlags=%04X has null DCB value, but dwCallBack=%08lX is not null !\n", uFlags, dwCallBack); + break; + case DCB_WINDOW: + TRACE("Window(%04lX) handle=%p!\n", dwCallBack, hDev); + PostMessageA((HWND)dwCallBack, wMsg, (WPARAM)hDev, dwParam1); + break; + case DCB_TASK: /* aka DCB_THREAD */ + TRACE("Task(%04lx) !\n", dwCallBack); + PostThreadMessageA(dwCallBack, wMsg, (WPARAM)hDev, dwParam1); + break; + case DCB_FUNCTION: + TRACE("Function (32 bit) !\n"); + ((LPDRVCALLBACK)dwCallBack)(hDev, wMsg, dwUser, dwParam1, dwParam2); + break; + case DCB_EVENT: + TRACE("Event(%08lx) !\n", dwCallBack); + SetEvent((HANDLE)dwCallBack); + break; + case 6: /* I would dub it DCB_MMTHREADSIGNAL */ + /* this is an undocumented DCB_ value used for mmThreads + * loword of dwCallBack contains the handle of the lpMMThd block + * which dwSignalCount has to be incremented + */ + if (pFnGetMMThread16) + { + WINE_MMTHREAD* lpMMThd = pFnGetMMThread16(LOWORD(dwCallBack)); + + TRACE("mmThread (%04x, %p) !\n", LOWORD(dwCallBack), lpMMThd); + /* same as mmThreadSignal16 */ + InterlockedIncrement(&lpMMThd->dwSignalCount); + SetEvent(lpMMThd->hEvent); + /* some other stuff on lpMMThd->hVxD */ + } + break; +#if 0 + case 4: + /* this is an undocumented DCB_ value for... I don't know */ + break; +#endif + default: + WARN("Unknown callback type %d\n", uFlags & DCB_TYPEMASK); + return FALSE; + } + TRACE("Done\n"); + return TRUE; +} + +/****************************************************************** + * DRIVER_UnloadAll + * + * + */ +void DRIVER_UnloadAll(void) +{ + LPWINE_DRIVER lpDrv; + LPWINE_DRIVER lpNextDrv = NULL; + unsigned count = 0; + + for (lpDrv = lpDrvItemList; lpDrv != NULL; lpDrv = lpNextDrv) + { + lpNextDrv = lpDrv->lpNextItem; + CloseDriver((HDRVR)lpDrv, 0, 0); + count++; + } + TRACE("Unloaded %u drivers\n", count); +} diff --git a/reactos/lib/winmm/joystick.c b/reactos/lib/winmm/joystick.c index 293a0e79ca4..490fd501127 100644 --- a/reactos/lib/winmm/joystick.c +++ b/reactos/lib/winmm/joystick.c @@ -1,315 +1,315 @@ -/* -*- tab-width: 8; c-basic-offset: 4 -*- */ -/* - * joystick functions - * - * Copyright 1997 Andreas Mohr - * 2000 Wolfgang Schwotzer - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#endif -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <fcntl.h> -#ifdef HAVE_SYS_IOCTL_H -#include <sys/ioctl.h> -#endif - -#include "windef.h" -#include "winbase.h" -#include "mmsystem.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "winemm.h" - -#include "mmddk.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(winmm); - -#define MAXJOYSTICK (JOYSTICKID2 + 1) -#define JOY_PERIOD_MIN (10) /* min Capture time period */ -#define JOY_PERIOD_MAX (1000) /* max Capture time period */ - -typedef struct tagWINE_JOYSTICK { - JOYINFO ji; - HWND hCapture; - UINT wTimer; - DWORD threshold; - BOOL bChanged; - HDRVR hDriver; -} WINE_JOYSTICK; - -static WINE_JOYSTICK JOY_Sticks[MAXJOYSTICK]; - -/************************************************************************** - * JOY_LoadDriver [internal] - */ -static BOOL JOY_LoadDriver(DWORD dwJoyID) -{ - if (dwJoyID >= MAXJOYSTICK) - return FALSE; - if (JOY_Sticks[dwJoyID].hDriver) - return TRUE; - - JOY_Sticks[dwJoyID].hDriver = OpenDriverA("joystick.drv", 0, dwJoyID); - return (JOY_Sticks[dwJoyID].hDriver != 0); -} - -/************************************************************************** - * JOY_Timer [internal] - */ -static void CALLBACK JOY_Timer(HWND hWnd, UINT wMsg, UINT wTimer, DWORD dwTime) -{ - int i; - WINE_JOYSTICK* joy; - JOYINFO ji; - LONG pos; - unsigned buttonChange; - - for (i = 0; i < MAXJOYSTICK; i++) { - joy = &JOY_Sticks[i]; - - if (joy->hCapture != hWnd) continue; - - joyGetPos(i, &ji); - pos = MAKELONG(ji.wXpos, ji.wYpos); - - if (!joy->bChanged || - abs(joy->ji.wXpos - ji.wXpos) > joy->threshold || - abs(joy->ji.wYpos - ji.wYpos) > joy->threshold) { - SendMessageA(joy->hCapture, MM_JOY1MOVE + i, ji.wButtons, pos); - joy->ji.wXpos = ji.wXpos; - joy->ji.wYpos = ji.wYpos; - } - if (!joy->bChanged || - abs(joy->ji.wZpos - ji.wZpos) > joy->threshold) { - SendMessageA(joy->hCapture, MM_JOY1ZMOVE + i, ji.wButtons, pos); - joy->ji.wZpos = ji.wZpos; - } - if ((buttonChange = joy->ji.wButtons ^ ji.wButtons) != 0) { - if (ji.wButtons & buttonChange) - SendMessageA(joy->hCapture, MM_JOY1BUTTONDOWN + i, - (buttonChange << 8) | (ji.wButtons & buttonChange), pos); - if (joy->ji.wButtons & buttonChange) - SendMessageA(joy->hCapture, MM_JOY1BUTTONUP + i, - (buttonChange << 8) | (joy->ji.wButtons & buttonChange), pos); - joy->ji.wButtons = ji.wButtons; - } - } -} - -/************************************************************************** - * joyGetNumDevs [WINMM.@] - */ -UINT WINAPI joyGetNumDevs(void) -{ - UINT ret = 0; - int i; - - for (i = 0; i < MAXJOYSTICK; i++) { - if (JOY_LoadDriver(i)) { - ret += SendDriverMessage(JOY_Sticks[i].hDriver, JDD_GETNUMDEVS, 0L, 0L); - } - } - return ret; -} - -/************************************************************************** - * joyGetDevCapsW [WINMM.@] - */ -MMRESULT WINAPI joyGetDevCapsW(UINT_PTR wID, LPJOYCAPSW lpCaps, UINT wSize) -{ - if (wID >= MAXJOYSTICK) return JOYERR_PARMS; - if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; - - lpCaps->wPeriodMin = JOY_PERIOD_MIN; /* FIXME */ - lpCaps->wPeriodMax = JOY_PERIOD_MAX; /* FIXME (same as MS Joystick Driver) */ - - return SendDriverMessage(JOY_Sticks[wID].hDriver, JDD_GETDEVCAPS, (DWORD)lpCaps, wSize); -} - -/************************************************************************** - * joyGetDevCapsA [WINMM.@] - */ -MMRESULT WINAPI joyGetDevCapsA(UINT_PTR wID, LPJOYCAPSA lpCaps, UINT wSize) -{ - JOYCAPSW jcw; - MMRESULT ret; - - if (lpCaps == NULL) return MMSYSERR_INVALPARAM; - - ret = joyGetDevCapsW(wID, &jcw, sizeof(jcw)); - - if (ret == JOYERR_NOERROR) - { - lpCaps->wMid = jcw.wMid; - lpCaps->wPid = jcw.wPid; - WideCharToMultiByte( CP_ACP, 0, jcw.szPname, -1, lpCaps->szPname, - sizeof(lpCaps->szPname), NULL, NULL ); - lpCaps->wXmin = jcw.wXmin; - lpCaps->wXmax = jcw.wXmax; - lpCaps->wYmin = jcw.wYmin; - lpCaps->wYmax = jcw.wYmax; - lpCaps->wZmin = jcw.wZmin; - lpCaps->wZmax = jcw.wZmax; - lpCaps->wNumButtons = jcw.wNumButtons; - lpCaps->wPeriodMin = jcw.wPeriodMin; - lpCaps->wPeriodMax = jcw.wPeriodMax; - - if (wSize >= sizeof(JOYCAPSA)) { /* Win95 extensions ? */ - lpCaps->wRmin = jcw.wRmin; - lpCaps->wRmax = jcw.wRmax; - lpCaps->wUmin = jcw.wUmin; - lpCaps->wUmax = jcw.wUmax; - lpCaps->wVmin = jcw.wVmin; - lpCaps->wVmax = jcw.wVmax; - lpCaps->wCaps = jcw.wCaps; - lpCaps->wMaxAxes = jcw.wMaxAxes; - lpCaps->wNumAxes = jcw.wNumAxes; - lpCaps->wMaxButtons = jcw.wMaxButtons; - WideCharToMultiByte( CP_ACP, 0, jcw.szRegKey, -1, lpCaps->szRegKey, - sizeof(lpCaps->szRegKey), NULL, NULL ); - WideCharToMultiByte( CP_ACP, 0, jcw.szOEMVxD, -1, lpCaps->szOEMVxD, - sizeof(lpCaps->szOEMVxD), NULL, NULL ); - } - } - - return ret; -} - -/************************************************************************** - * joyGetPosEx [WINMM.@] - */ -MMRESULT WINAPI joyGetPosEx(UINT wID, LPJOYINFOEX lpInfo) -{ - TRACE("(%d, %p);\n", wID, lpInfo); - - if (wID >= MAXJOYSTICK) return JOYERR_PARMS; - if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; - - lpInfo->dwXpos = 0; - lpInfo->dwYpos = 0; - lpInfo->dwZpos = 0; - lpInfo->dwRpos = 0; - lpInfo->dwUpos = 0; - lpInfo->dwVpos = 0; - lpInfo->dwButtons = 0; - lpInfo->dwButtonNumber = 0; - lpInfo->dwPOV = 0; - lpInfo->dwReserved1 = 0; - lpInfo->dwReserved2 = 0; - - return SendDriverMessage(JOY_Sticks[wID].hDriver, JDD_GETPOSEX, (DWORD)lpInfo, 0L); -} - -/************************************************************************** - * joyGetPos [WINMM.@] - */ -MMRESULT WINAPI joyGetPos(UINT wID, LPJOYINFO lpInfo) -{ - TRACE("(%d, %p);\n", wID, lpInfo); - - if (wID >= MAXJOYSTICK) return JOYERR_PARMS; - if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; - - lpInfo->wXpos = 0; - lpInfo->wYpos = 0; - lpInfo->wZpos = 0; - lpInfo->wButtons = 0; - - return SendDriverMessage(JOY_Sticks[wID].hDriver, JDD_GETPOS, (DWORD)lpInfo, 0L); -} - -/************************************************************************** - * joyGetThreshold [WINMM.@] - */ -MMRESULT WINAPI joyGetThreshold(UINT wID, LPUINT lpThreshold) -{ - TRACE("(%04X, %p);\n", wID, lpThreshold); - - if (wID >= MAXJOYSTICK) return JOYERR_PARMS; - - *lpThreshold = JOY_Sticks[wID].threshold; - return JOYERR_NOERROR; -} - -/************************************************************************** - * joyReleaseCapture [WINMM.@] - */ -MMRESULT WINAPI joyReleaseCapture(UINT wID) -{ - TRACE("(%04X);\n", wID); - - if (wID >= MAXJOYSTICK) return JOYERR_PARMS; - if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; - if (!JOY_Sticks[wID].hCapture) return JOYERR_NOCANDO; - - KillTimer(JOY_Sticks[wID].hCapture, JOY_Sticks[wID].wTimer); - JOY_Sticks[wID].hCapture = 0; - JOY_Sticks[wID].wTimer = 0; - - return JOYERR_NOERROR; -} - -/************************************************************************** - * joySetCapture [WINMM.@] - */ -MMRESULT WINAPI joySetCapture(HWND hWnd, UINT wID, UINT wPeriod, BOOL bChanged) -{ - TRACE("(%p, %04X, %d, %d);\n", hWnd, wID, wPeriod, bChanged); - - if (wID >= MAXJOYSTICK || hWnd == 0) return JOYERR_PARMS; - if (wPeriod<JOY_PERIOD_MIN || wPeriod>JOY_PERIOD_MAX) return JOYERR_PARMS; - if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; - - if (JOY_Sticks[wID].hCapture || !IsWindow(hWnd)) - return JOYERR_NOCANDO; /* FIXME: what should be returned ? */ - - if (joyGetPos(wID, &JOY_Sticks[wID].ji) != JOYERR_NOERROR) - return JOYERR_UNPLUGGED; - - if ((JOY_Sticks[wID].wTimer = SetTimer(hWnd, 0, wPeriod, JOY_Timer)) == 0) - return JOYERR_NOCANDO; - - JOY_Sticks[wID].hCapture = hWnd; - JOY_Sticks[wID].bChanged = bChanged; - - return JOYERR_NOERROR; -} - -/************************************************************************** - * joySetThreshold [WINMM.@] - */ -MMRESULT WINAPI joySetThreshold(UINT wID, UINT wThreshold) -{ - TRACE("(%04X, %d);\n", wID, wThreshold); - - if (wID >= MAXJOYSTICK) return MMSYSERR_INVALPARAM; - - JOY_Sticks[wID].threshold = wThreshold; - - return JOYERR_NOERROR; -} +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ +/* + * joystick functions + * + * Copyright 1997 Andreas Mohr + * 2000 Wolfgang Schwotzer + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#include "windef.h" +#include "winbase.h" +#include "mmsystem.h" +#include "wingdi.h" +#include "winuser.h" +#include "winnls.h" +#include "winemm.h" + +#include "mmddk.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winmm); + +#define MAXJOYSTICK (JOYSTICKID2 + 1) +#define JOY_PERIOD_MIN (10) /* min Capture time period */ +#define JOY_PERIOD_MAX (1000) /* max Capture time period */ + +typedef struct tagWINE_JOYSTICK { + JOYINFO ji; + HWND hCapture; + UINT wTimer; + DWORD threshold; + BOOL bChanged; + HDRVR hDriver; +} WINE_JOYSTICK; + +static WINE_JOYSTICK JOY_Sticks[MAXJOYSTICK]; + +/************************************************************************** + * JOY_LoadDriver [internal] + */ +static BOOL JOY_LoadDriver(DWORD dwJoyID) +{ + if (dwJoyID >= MAXJOYSTICK) + return FALSE; + if (JOY_Sticks[dwJoyID].hDriver) + return TRUE; + + JOY_Sticks[dwJoyID].hDriver = OpenDriverA("joystick.drv", 0, dwJoyID); + return (JOY_Sticks[dwJoyID].hDriver != 0); +} + +/************************************************************************** + * JOY_Timer [internal] + */ +static void CALLBACK JOY_Timer(HWND hWnd, UINT wMsg, UINT wTimer, DWORD dwTime) +{ + int i; + WINE_JOYSTICK* joy; + JOYINFO ji; + LONG pos; + unsigned buttonChange; + + for (i = 0; i < MAXJOYSTICK; i++) { + joy = &JOY_Sticks[i]; + + if (joy->hCapture != hWnd) continue; + + joyGetPos(i, &ji); + pos = MAKELONG(ji.wXpos, ji.wYpos); + + if (!joy->bChanged || + abs(joy->ji.wXpos - ji.wXpos) > joy->threshold || + abs(joy->ji.wYpos - ji.wYpos) > joy->threshold) { + SendMessageA(joy->hCapture, MM_JOY1MOVE + i, ji.wButtons, pos); + joy->ji.wXpos = ji.wXpos; + joy->ji.wYpos = ji.wYpos; + } + if (!joy->bChanged || + abs(joy->ji.wZpos - ji.wZpos) > joy->threshold) { + SendMessageA(joy->hCapture, MM_JOY1ZMOVE + i, ji.wButtons, pos); + joy->ji.wZpos = ji.wZpos; + } + if ((buttonChange = joy->ji.wButtons ^ ji.wButtons) != 0) { + if (ji.wButtons & buttonChange) + SendMessageA(joy->hCapture, MM_JOY1BUTTONDOWN + i, + (buttonChange << 8) | (ji.wButtons & buttonChange), pos); + if (joy->ji.wButtons & buttonChange) + SendMessageA(joy->hCapture, MM_JOY1BUTTONUP + i, + (buttonChange << 8) | (joy->ji.wButtons & buttonChange), pos); + joy->ji.wButtons = ji.wButtons; + } + } +} + +/************************************************************************** + * joyGetNumDevs [WINMM.@] + */ +UINT WINAPI joyGetNumDevs(void) +{ + UINT ret = 0; + int i; + + for (i = 0; i < MAXJOYSTICK; i++) { + if (JOY_LoadDriver(i)) { + ret += SendDriverMessage(JOY_Sticks[i].hDriver, JDD_GETNUMDEVS, 0L, 0L); + } + } + return ret; +} + +/************************************************************************** + * joyGetDevCapsW [WINMM.@] + */ +MMRESULT WINAPI joyGetDevCapsW(UINT_PTR wID, LPJOYCAPSW lpCaps, UINT wSize) +{ + if (wID >= MAXJOYSTICK) return JOYERR_PARMS; + if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; + + lpCaps->wPeriodMin = JOY_PERIOD_MIN; /* FIXME */ + lpCaps->wPeriodMax = JOY_PERIOD_MAX; /* FIXME (same as MS Joystick Driver) */ + + return SendDriverMessage(JOY_Sticks[wID].hDriver, JDD_GETDEVCAPS, (DWORD)lpCaps, wSize); +} + +/************************************************************************** + * joyGetDevCapsA [WINMM.@] + */ +MMRESULT WINAPI joyGetDevCapsA(UINT_PTR wID, LPJOYCAPSA lpCaps, UINT wSize) +{ + JOYCAPSW jcw; + MMRESULT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = joyGetDevCapsW(wID, &jcw, sizeof(jcw)); + + if (ret == JOYERR_NOERROR) + { + lpCaps->wMid = jcw.wMid; + lpCaps->wPid = jcw.wPid; + WideCharToMultiByte( CP_ACP, 0, jcw.szPname, -1, lpCaps->szPname, + sizeof(lpCaps->szPname), NULL, NULL ); + lpCaps->wXmin = jcw.wXmin; + lpCaps->wXmax = jcw.wXmax; + lpCaps->wYmin = jcw.wYmin; + lpCaps->wYmax = jcw.wYmax; + lpCaps->wZmin = jcw.wZmin; + lpCaps->wZmax = jcw.wZmax; + lpCaps->wNumButtons = jcw.wNumButtons; + lpCaps->wPeriodMin = jcw.wPeriodMin; + lpCaps->wPeriodMax = jcw.wPeriodMax; + + if (wSize >= sizeof(JOYCAPSA)) { /* Win95 extensions ? */ + lpCaps->wRmin = jcw.wRmin; + lpCaps->wRmax = jcw.wRmax; + lpCaps->wUmin = jcw.wUmin; + lpCaps->wUmax = jcw.wUmax; + lpCaps->wVmin = jcw.wVmin; + lpCaps->wVmax = jcw.wVmax; + lpCaps->wCaps = jcw.wCaps; + lpCaps->wMaxAxes = jcw.wMaxAxes; + lpCaps->wNumAxes = jcw.wNumAxes; + lpCaps->wMaxButtons = jcw.wMaxButtons; + WideCharToMultiByte( CP_ACP, 0, jcw.szRegKey, -1, lpCaps->szRegKey, + sizeof(lpCaps->szRegKey), NULL, NULL ); + WideCharToMultiByte( CP_ACP, 0, jcw.szOEMVxD, -1, lpCaps->szOEMVxD, + sizeof(lpCaps->szOEMVxD), NULL, NULL ); + } + } + + return ret; +} + +/************************************************************************** + * joyGetPosEx [WINMM.@] + */ +MMRESULT WINAPI joyGetPosEx(UINT wID, LPJOYINFOEX lpInfo) +{ + TRACE("(%d, %p);\n", wID, lpInfo); + + if (wID >= MAXJOYSTICK) return JOYERR_PARMS; + if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; + + lpInfo->dwXpos = 0; + lpInfo->dwYpos = 0; + lpInfo->dwZpos = 0; + lpInfo->dwRpos = 0; + lpInfo->dwUpos = 0; + lpInfo->dwVpos = 0; + lpInfo->dwButtons = 0; + lpInfo->dwButtonNumber = 0; + lpInfo->dwPOV = 0; + lpInfo->dwReserved1 = 0; + lpInfo->dwReserved2 = 0; + + return SendDriverMessage(JOY_Sticks[wID].hDriver, JDD_GETPOSEX, (DWORD)lpInfo, 0L); +} + +/************************************************************************** + * joyGetPos [WINMM.@] + */ +MMRESULT WINAPI joyGetPos(UINT wID, LPJOYINFO lpInfo) +{ + TRACE("(%d, %p);\n", wID, lpInfo); + + if (wID >= MAXJOYSTICK) return JOYERR_PARMS; + if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; + + lpInfo->wXpos = 0; + lpInfo->wYpos = 0; + lpInfo->wZpos = 0; + lpInfo->wButtons = 0; + + return SendDriverMessage(JOY_Sticks[wID].hDriver, JDD_GETPOS, (DWORD)lpInfo, 0L); +} + +/************************************************************************** + * joyGetThreshold [WINMM.@] + */ +MMRESULT WINAPI joyGetThreshold(UINT wID, LPUINT lpThreshold) +{ + TRACE("(%04X, %p);\n", wID, lpThreshold); + + if (wID >= MAXJOYSTICK) return JOYERR_PARMS; + + *lpThreshold = JOY_Sticks[wID].threshold; + return JOYERR_NOERROR; +} + +/************************************************************************** + * joyReleaseCapture [WINMM.@] + */ +MMRESULT WINAPI joyReleaseCapture(UINT wID) +{ + TRACE("(%04X);\n", wID); + + if (wID >= MAXJOYSTICK) return JOYERR_PARMS; + if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; + if (!JOY_Sticks[wID].hCapture) return JOYERR_NOCANDO; + + KillTimer(JOY_Sticks[wID].hCapture, JOY_Sticks[wID].wTimer); + JOY_Sticks[wID].hCapture = 0; + JOY_Sticks[wID].wTimer = 0; + + return JOYERR_NOERROR; +} + +/************************************************************************** + * joySetCapture [WINMM.@] + */ +MMRESULT WINAPI joySetCapture(HWND hWnd, UINT wID, UINT wPeriod, BOOL bChanged) +{ + TRACE("(%p, %04X, %d, %d);\n", hWnd, wID, wPeriod, bChanged); + + if (wID >= MAXJOYSTICK || hWnd == 0) return JOYERR_PARMS; + if (wPeriod<JOY_PERIOD_MIN || wPeriod>JOY_PERIOD_MAX) return JOYERR_PARMS; + if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; + + if (JOY_Sticks[wID].hCapture || !IsWindow(hWnd)) + return JOYERR_NOCANDO; /* FIXME: what should be returned ? */ + + if (joyGetPos(wID, &JOY_Sticks[wID].ji) != JOYERR_NOERROR) + return JOYERR_UNPLUGGED; + + if ((JOY_Sticks[wID].wTimer = SetTimer(hWnd, 0, wPeriod, JOY_Timer)) == 0) + return JOYERR_NOCANDO; + + JOY_Sticks[wID].hCapture = hWnd; + JOY_Sticks[wID].bChanged = bChanged; + + return JOYERR_NOERROR; +} + +/************************************************************************** + * joySetThreshold [WINMM.@] + */ +MMRESULT WINAPI joySetThreshold(UINT wID, UINT wThreshold) +{ + TRACE("(%04X, %d);\n", wID, wThreshold); + + if (wID >= MAXJOYSTICK) return MMSYSERR_INVALPARAM; + + JOY_Sticks[wID].threshold = wThreshold; + + return JOYERR_NOERROR; +} diff --git a/reactos/lib/winmm/lolvldrv.c b/reactos/lib/winmm/lolvldrv.c index a69cf56f10f..59a8e45ffc8 100644 --- a/reactos/lib/winmm/lolvldrv.c +++ b/reactos/lib/winmm/lolvldrv.c @@ -1,842 +1,842 @@ -/* -*- tab-width: 8; c-basic-offset: 4 -*- */ - -/* - * MMSYTEM low level drivers handling functions - * - * Copyright 1999 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <string.h> -#include <stdarg.h> -#include <stdio.h> -#include <assert.h> -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "winver.h" -#include "winemm.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(winmm); - -LRESULT (*pFnCallMMDrvFunc16)(DWORD,WORD,WORD,LONG,LONG,LONG) /* = NULL */; -unsigned (*pFnLoadMMDrvFunc16)(LPCSTR,LPWINE_DRIVER, LPWINE_MM_DRIVER) /* = NULL */; - -/* each known type of driver has an instance of this structure */ -typedef struct tagWINE_LLTYPE { - /* those attributes depend on the specification of the type */ - LPCSTR typestr; /* name (for debugging) */ - BOOL bSupportMapper; /* if type is allowed to support mapper */ - MMDRV_MAPFUNC Map16To32A; /* those are function pointers to handle */ - MMDRV_UNMAPFUNC UnMap16To32A; /* the parameter conversion (16 vs 32 bit) */ - MMDRV_MAPFUNC Map32ATo16; /* when hi-func (in mmsystem or winmm) and */ - MMDRV_UNMAPFUNC UnMap32ATo16; /* low-func (in .drv) do not match */ - LPDRVCALLBACK Callback; /* handles callback for a specified type */ - /* those attributes reflect the loaded/current situation for the type */ - UINT wMaxId; /* number of loaded devices (sum across all loaded drivers */ - LPWINE_MLD lpMlds; /* "static" mlds to access the part though device IDs */ - int nMapper; /* index to mapper */ -} WINE_LLTYPE; - -static int MMDrvsHi /* = 0 */; -static WINE_MM_DRIVER MMDrvs[8]; -static LPWINE_MLD MM_MLDrvs[40]; -#define MAX_MM_MLDRVS (sizeof(MM_MLDrvs) / sizeof(MM_MLDrvs[0])) - -#define A(_x,_y) {#_y, _x, NULL, NULL, NULL, NULL, NULL, 0, NULL, -1} -/* Note: the indices of this array must match the definitions - * of the MMDRV_???? manifest constants - */ -static WINE_LLTYPE llTypes[MMDRV_MAX] = { - A(TRUE, Aux), - A(FALSE, Mixer), - A(TRUE, MidiIn), - A(TRUE, MidiOut), - A(TRUE, WaveIn), - A(TRUE, WaveOut), -}; -#undef A - -/****************************************************************** - * MMDRV_InstallMap - * - * - */ -void MMDRV_InstallMap(unsigned int drv, - MMDRV_MAPFUNC mp1632, MMDRV_UNMAPFUNC um1632, - MMDRV_MAPFUNC mp3216, MMDRV_UNMAPFUNC um3216, - LPDRVCALLBACK cb) -{ - assert(drv < MMDRV_MAX); - llTypes[drv].Map16To32A = mp1632; - llTypes[drv].UnMap16To32A = um1632; - llTypes[drv].Map32ATo16 = mp3216; - llTypes[drv].UnMap32ATo16 = um3216; - llTypes[drv].Callback = cb; -} - -/****************************************************************** - * MMDRV_Is32 - * - */ -BOOL MMDRV_Is32(unsigned int idx) -{ - TRACE("(%d)\n", idx); - return MMDrvs[idx].bIs32; -} - -/************************************************************************** - * MMDRV_GetDescription32 [internal] - */ -static BOOL MMDRV_GetDescription32(const char* fname, char* buf, int buflen) -{ - OFSTRUCT ofs; - DWORD h; - LPVOID ptr = 0; - LPVOID val; - DWORD dw; - BOOL ret = FALSE; - UINT u; - FARPROC pGetFileVersionInfoSizeA; - FARPROC pGetFileVersionInfoA; - FARPROC pVerQueryValueA; - HMODULE hmodule = 0; - TRACE("(%p, %p, %d)\n", fname, buf, buflen); - -#define E(_x) do {TRACE _x;goto theEnd;} while(0) - - if (OpenFile(fname, &ofs, OF_EXIST)==HFILE_ERROR) E(("Can't find file %s\n", fname)); - - if (!(hmodule = LoadLibraryA( "version.dll" ))) goto theEnd; - if (!(pGetFileVersionInfoSizeA = GetProcAddress( hmodule, "GetFileVersionInfoSizeA" ))) - goto theEnd; - if (!(pGetFileVersionInfoA = GetProcAddress( hmodule, "GetFileVersionInfoA" ))) - goto theEnd; - if (!(pVerQueryValueA = GetProcAddress( hmodule, "VerQueryValueA" ))) - goto theEnd; - - if (!(dw = pGetFileVersionInfoSizeA(ofs.szPathName, &h))) E(("Can't get FVIS\n")); - if (!(ptr = HeapAlloc(GetProcessHeap(), 0, dw))) E(("OOM\n")); - if (!pGetFileVersionInfoA(ofs.szPathName, h, dw, ptr)) E(("Can't get FVI\n")); - -#define A(_x) if (pVerQueryValueA(ptr, "\\StringFileInfo\\040904B0\\" #_x, &val, &u)) \ - TRACE(#_x " => %s\n", (LPSTR)val); else TRACE(#_x " @\n") - - A(CompanyName); - A(FileDescription); - A(FileVersion); - A(InternalName); - A(LegalCopyright); - A(OriginalFilename); - A(ProductName); - A(ProductVersion); - A(Comments); - A(LegalTrademarks); - A(PrivateBuild); - A(SpecialBuild); -#undef A - - if (!pVerQueryValueA(ptr, "\\StringFileInfo\\040904B0\\ProductName", &val, &u)) E(("Can't get product name\n")); - lstrcpynA(buf, val, buflen); - -#undef E - ret = TRUE; -theEnd: - HeapFree(GetProcessHeap(), 0, ptr); - if (hmodule) FreeLibrary( hmodule ); - return ret; -} - -/************************************************************************** - * MMDRV_GetNum [internal] - */ -UINT MMDRV_GetNum(UINT type) -{ - TRACE("(%04x)\n", type); - assert(type < MMDRV_MAX); - return llTypes[type].wMaxId; -} - -/************************************************************************** - * MMDRV_Message [internal] - */ -DWORD MMDRV_Message(LPWINE_MLD mld, UINT wMsg, DWORD_PTR dwParam1, - DWORD_PTR dwParam2, BOOL bFrom32) -{ - LPWINE_MM_DRIVER lpDrv; - DWORD ret; - WINE_MM_DRIVER_PART* part; - WINE_LLTYPE* llType = &llTypes[mld->type]; - WINMM_MapType map; - int devID; - - TRACE("(%s %u %u 0x%08lx 0x%08lx 0x%08lx %c)\n", - llTypes[mld->type].typestr, mld->uDeviceID, wMsg, - mld->dwDriverInstance, dwParam1, dwParam2, bFrom32?'Y':'N'); - - if (mld->uDeviceID == (UINT16)-1) { - if (!llType->bSupportMapper) { - WARN("uDev=-1 requested on non-mappable ll type %s\n", - llTypes[mld->type].typestr); - return MMSYSERR_BADDEVICEID; - } - devID = -1; - } else { - if (mld->uDeviceID >= llType->wMaxId) { - WARN("uDev(%u) requested >= max (%d)\n", mld->uDeviceID, llType->wMaxId); - return MMSYSERR_BADDEVICEID; - } - devID = mld->uDeviceID; - } - - lpDrv = &MMDrvs[mld->mmdIndex]; - part = &lpDrv->parts[mld->type]; - -#if 0 - /* some sanity checks */ - if (!(part->nIDMin <= devID)) - ERR("!(part->nIDMin(%d) <= devID(%d))\n", part->nIDMin, devID); - if (!(devID < part->nIDMax)) - ERR("!(devID(%d) < part->nIDMax(%d))\n", devID, part->nIDMax); -#endif - - if (lpDrv->bIs32) { - assert(part->u.fnMessage32); - - if (bFrom32) { - TRACE("Calling message(dev=%u msg=%u usr=0x%08lx p1=0x%08lx p2=0x%08lx)\n", - mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2); - ret = part->u.fnMessage32(mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2); - TRACE("=> %s\n", WINMM_ErrorToString(ret)); - } else { - map = llType->Map16To32A(wMsg, &mld->dwDriverInstance, &dwParam1, &dwParam2); - switch (map) { - case WINMM_MAP_NOMEM: - ret = MMSYSERR_NOMEM; - break; - case WINMM_MAP_MSGERROR: - FIXME("NIY: no conversion yet 16->32 (%u)\n", wMsg); - ret = MMSYSERR_ERROR; - break; - case WINMM_MAP_OK: - case WINMM_MAP_OKMEM: - TRACE("Calling message(dev=%u msg=%u usr=0x%08lx p1=0x%08lx p2=0x%08lx)\n", - mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2); - ret = part->u.fnMessage32(mld->uDeviceID, wMsg, mld->dwDriverInstance, - dwParam1, dwParam2); - TRACE("=> %s\n", WINMM_ErrorToString(ret)); - if (map == WINMM_MAP_OKMEM) - llType->UnMap16To32A(wMsg, &mld->dwDriverInstance, &dwParam1, &dwParam2, ret); - break; - default: - FIXME("NIY\n"); - ret = MMSYSERR_NOTSUPPORTED; - break; - } - } - } else { - assert(part->u.fnMessage16 && pFnCallMMDrvFunc16); - - if (bFrom32) { - map = llType->Map32ATo16(wMsg, &mld->dwDriverInstance, &dwParam1, &dwParam2); - switch (map) { - case WINMM_MAP_NOMEM: - ret = MMSYSERR_NOMEM; - break; - case WINMM_MAP_MSGERROR: - FIXME("NIY: no conversion yet 32->16 (%u)\n", wMsg); - ret = MMSYSERR_ERROR; - break; - case WINMM_MAP_OK: - case WINMM_MAP_OKMEM: - TRACE("Calling message(dev=%u msg=%u usr=0x%08lx p1=0x%08lx p2=0x%08lx)\n", - mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2); - ret = pFnCallMMDrvFunc16((DWORD)part->u.fnMessage16, - mld->uDeviceID, wMsg, mld->dwDriverInstance, - dwParam1, dwParam2); - TRACE("=> %s\n", WINMM_ErrorToString(ret)); - if (map == WINMM_MAP_OKMEM) - llType->UnMap32ATo16(wMsg, &mld->dwDriverInstance, &dwParam1, &dwParam2, ret); - break; - default: - FIXME("NIY\n"); - ret = MMSYSERR_NOTSUPPORTED; - break; - } - } else { - TRACE("Calling message(dev=%u msg=%u usr=0x%08lx p1=0x%08lx p2=0x%08lx)\n", - mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2); - ret = pFnCallMMDrvFunc16((DWORD)part->u.fnMessage16, - mld->uDeviceID, wMsg, mld->dwDriverInstance, - dwParam1, dwParam2); - TRACE("=> %s\n", WINMM_ErrorToString(ret)); - } - } - return ret; -} - -/************************************************************************** - * MMDRV_Alloc [internal] - */ -LPWINE_MLD MMDRV_Alloc(UINT size, UINT type, LPHANDLE hndl, DWORD* dwFlags, - DWORD* dwCallback, DWORD* dwInstance, BOOL bFrom32) -{ - LPWINE_MLD mld; - UINT i; - TRACE("(%d, %04x, %p, %p, %p, %p, %c)\n", - size, type, hndl, dwFlags, dwCallback, dwInstance, bFrom32?'Y':'N'); - - mld = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); - if (!mld) return NULL; - - /* find an empty slot in MM_MLDrvs table */ - for (i = 0; i < MAX_MM_MLDRVS; i++) if (!MM_MLDrvs[i]) break; - - if (i == MAX_MM_MLDRVS) { - /* the MM_MLDrvs table could be made growable in the future if needed */ - ERR("Too many open drivers\n"); - HeapFree(GetProcessHeap(), 0, mld); - return NULL; - } - MM_MLDrvs[i] = mld; - *hndl = (HANDLE)(i | 0x8000); - - mld->type = type; - if ((UINT)*hndl < MMDRV_GetNum(type) || HIWORD(*hndl) != 0) { - /* FIXME: those conditions must be fulfilled so that: - * - we can distinguish between device IDs and handles - * - we can use handles as 16 or 32 bit entities - */ - ERR("Shouldn't happen. Bad allocation scheme\n"); - } - - mld->bFrom32 = bFrom32; - mld->dwFlags = HIWORD(*dwFlags); - mld->dwCallback = *dwCallback; - mld->dwClientInstance = *dwInstance; - - if (llTypes[type].Callback) - { - *dwFlags = LOWORD(*dwFlags) | CALLBACK_FUNCTION; - *dwCallback = (DWORD)llTypes[type].Callback; - *dwInstance = (DWORD)mld; /* FIXME: wouldn't some 16 bit drivers only use the loword ? */ - } - - return mld; -} - -/************************************************************************** - * MMDRV_Free [internal] - */ -void MMDRV_Free(HANDLE hndl, LPWINE_MLD mld) -{ - TRACE("(%p, %p)\n", hndl, mld); - - if ((UINT)hndl & 0x8000) { - unsigned idx = (UINT)hndl & ~0x8000; - if (idx < sizeof(MM_MLDrvs) / sizeof(MM_MLDrvs[0])) { - MM_MLDrvs[idx] = NULL; - HeapFree(GetProcessHeap(), 0, mld); - return; - } - } - ERR("Bad Handle %p at %p (not freed)\n", hndl, mld); -} - -/************************************************************************** - * MMDRV_Open [internal] - */ -DWORD MMDRV_Open(LPWINE_MLD mld, UINT wMsg, DWORD dwParam1, DWORD dwFlags) -{ - DWORD dwRet = MMSYSERR_BADDEVICEID; - DWORD dwInstance; - WINE_LLTYPE* llType = &llTypes[mld->type]; - TRACE("(%p, %04x, 0x%08lx, 0x%08lx)\n", mld, wMsg, dwParam1, dwFlags); - - mld->dwDriverInstance = (DWORD)&dwInstance; - - if (mld->uDeviceID == (UINT)-1 || mld->uDeviceID == (UINT16)-1) { - TRACE("MAPPER mode requested !\n"); - /* check if mapper is supported by type */ - if (llType->bSupportMapper) { - if (llType->nMapper == -1) { - /* no driver for mapper has been loaded, try a dumb implementation */ - TRACE("No mapper loaded, doing it by hand\n"); - for (mld->uDeviceID = 0; mld->uDeviceID < llType->wMaxId; mld->uDeviceID++) { - if ((dwRet = MMDRV_Open(mld, wMsg, dwParam1, dwFlags)) == MMSYSERR_NOERROR) { - /* to share this function epilog */ - dwInstance = mld->dwDriverInstance; - break; - } - } - } else { - mld->uDeviceID = (UINT16)-1; - mld->mmdIndex = llType->lpMlds[-1].mmdIndex; - TRACE("Setting mmdIndex to %u\n", mld->mmdIndex); - dwRet = MMDRV_Message(mld, wMsg, dwParam1, dwFlags, TRUE); - } - } - } else { - if (mld->uDeviceID < llType->wMaxId) { - mld->mmdIndex = llType->lpMlds[mld->uDeviceID].mmdIndex; - TRACE("Setting mmdIndex to %u\n", mld->mmdIndex); - dwRet = MMDRV_Message(mld, wMsg, dwParam1, dwFlags, TRUE); - } - } - if (dwRet == MMSYSERR_NOERROR) - mld->dwDriverInstance = dwInstance; - return dwRet; -} - -/************************************************************************** - * MMDRV_Close [internal] - */ -DWORD MMDRV_Close(LPWINE_MLD mld, UINT wMsg) -{ - TRACE("(%p, %04x)\n", mld, wMsg); - return MMDRV_Message(mld, wMsg, 0L, 0L, TRUE); -} - -/************************************************************************** - * MMDRV_GetByID [internal] - */ -LPWINE_MLD MMDRV_GetByID(UINT uDevID, UINT type) -{ - TRACE("(%04x, %04x)\n", uDevID, type); - if (uDevID < llTypes[type].wMaxId) - return &llTypes[type].lpMlds[uDevID]; - if ((uDevID == (UINT16)-1 || uDevID == (UINT)-1) && llTypes[type].nMapper != -1) - return &llTypes[type].lpMlds[-1]; - return NULL; -} - -/************************************************************************** - * MMDRV_Get [internal] - */ -LPWINE_MLD MMDRV_Get(HANDLE _hndl, UINT type, BOOL bCanBeID) -{ - LPWINE_MLD mld = NULL; - UINT hndl = (UINT)_hndl; - TRACE("(%p, %04x, %c)\n", _hndl, type, bCanBeID ? 'Y' : 'N'); - - assert(type < MMDRV_MAX); - - if (hndl >= llTypes[type].wMaxId && - hndl != (UINT16)-1 && hndl != (UINT)-1) { - if (hndl & 0x8000) { - hndl = hndl & ~0x8000; - if (hndl < sizeof(MM_MLDrvs) / sizeof(MM_MLDrvs[0])) { - mld = MM_MLDrvs[hndl]; - if (!mld || !HeapValidate(GetProcessHeap(), 0, mld) || mld->type != type) - mld = NULL; - } - hndl = hndl | 0x8000; - } - } - if (mld == NULL && bCanBeID) { - mld = MMDRV_GetByID(hndl, type); - } - return mld; -} - -/************************************************************************** - * MMDRV_GetRelated [internal] - */ -LPWINE_MLD MMDRV_GetRelated(HANDLE hndl, UINT srcType, - BOOL bSrcCanBeID, UINT dstType) -{ - LPWINE_MLD mld; - TRACE("(%p, %04x, %c, %04x)\n", - hndl, srcType, bSrcCanBeID ? 'Y' : 'N', dstType); - - if ((mld = MMDRV_Get(hndl, srcType, bSrcCanBeID)) != NULL) { - WINE_MM_DRIVER_PART* part = &MMDrvs[mld->mmdIndex].parts[dstType]; - if (part->nIDMin < part->nIDMax) - return MMDRV_GetByID(part->nIDMin, dstType); - } - return NULL; -} - -/************************************************************************** - * MMDRV_PhysicalFeatures [internal] - */ -UINT MMDRV_PhysicalFeatures(LPWINE_MLD mld, UINT uMsg, DWORD dwParam1, - DWORD dwParam2) -{ - WINE_MM_DRIVER* lpDrv = &MMDrvs[mld->mmdIndex]; - - TRACE("(%p, %04x, %08lx, %08lx)\n", mld, uMsg, dwParam1, dwParam2); - - /* all those function calls are undocumented */ - switch (uMsg) { - case DRV_QUERYDRVENTRY: - lstrcpynA((LPSTR)dwParam1, lpDrv->drvname, LOWORD(dwParam2)); - break; - case DRV_QUERYDEVNODE: - *(LPDWORD)dwParam1 = 0L; /* should be DevNode */ - break; - case DRV_QUERYNAME: - WARN("NIY QueryName\n"); - break; - case DRV_QUERYDRIVERIDS: - WARN("NIY call VxD\n"); - /* should call VxD MMDEVLDR with (DevNode, dwParam1 and dwParam2) as pmts - * dwParam1 is buffer and dwParam2 is sizeof(buffer) - * I don't know where the result is stored though - */ - break; - case DRV_QUERYMAPPABLE: - return (lpDrv->bIsMapper) ? 2 : 0; - - case DRVM_MAPPER_PREFERRED_GET: - /* FIXME: get from registry someday */ - *((LPDWORD)dwParam1) = -1; /* No preferred device */ - *((LPDWORD)dwParam2) = 0; - break; - - case DRV_QUERYDEVICEINTERFACE: - case DRV_QUERYDEVICEINTERFACESIZE: - return MMDRV_Message(mld, uMsg, dwParam1, dwParam2, TRUE); - - case DRV_QUERYDSOUNDIFACE: /* Wine-specific: Retrieve DirectSound interface */ - case DRV_QUERYDSOUNDDESC: /* Wine-specific: Retrieve DirectSound driver description*/ - return MMDRV_Message(mld, uMsg, dwParam1, dwParam2, TRUE); - - default: - WARN("Unknown call %04x\n", uMsg); - return MMSYSERR_INVALPARAM; - } - return 0L; -} - -/************************************************************************** - * MMDRV_InitPerType [internal] - */ -static BOOL MMDRV_InitPerType(LPWINE_MM_DRIVER lpDrv, UINT type, UINT wMsg) -{ - WINE_MM_DRIVER_PART* part = &lpDrv->parts[type]; - DWORD ret; - UINT count = 0; - int i, k; - TRACE("(%p, %04x, %04x)\n", lpDrv, type, wMsg); - - part->nIDMin = part->nIDMax = 0; - - /* for DRVM_INIT and DRVM_ENABLE, dwParam2 should be PnP node */ - /* the DRVM_ENABLE is only required when the PnP node is non zero */ - - if (lpDrv->bIs32 && part->u.fnMessage32) { - ret = part->u.fnMessage32(0, DRVM_INIT, 0L, 0L, 0L); - TRACE("DRVM_INIT => %s\n", WINMM_ErrorToString(ret)); -#if 0 - ret = part->u.fnMessage32(0, DRVM_ENABLE, 0L, 0L, 0L); - TRACE("DRVM_ENABLE => %08lx\n", ret); -#endif - count = part->u.fnMessage32(0, wMsg, 0L, 0L, 0L); - } else if (!lpDrv->bIs32 && part->u.fnMessage16 && pFnCallMMDrvFunc16) { - ret = pFnCallMMDrvFunc16((DWORD)part->u.fnMessage16, - 0, DRVM_INIT, 0L, 0L, 0L); - TRACE("DRVM_INIT => %s\n", WINMM_ErrorToString(ret)); -#if 0 - ret = pFnCallMMDrvFunc16((DWORD)part->u.fnMessage16, - 0, DRVM_ENABLE, 0L, 0L, 0L); - TRACE("DRVM_ENABLE => %08lx\n", ret); -#endif - count = pFnCallMMDrvFunc16((DWORD)part->u.fnMessage16, - 0, wMsg, 0L, 0L, 0L); - } else { - return FALSE; - } - - TRACE("Got %u dev for (%s:%s)\n", count, lpDrv->drvname, llTypes[type].typestr); - - if (HIWORD(count)) - return FALSE; - - /* got some drivers */ - if (lpDrv->bIsMapper) { - /* it seems native mappers return 0 devices :-( */ - if (llTypes[type].nMapper != -1) - ERR("Two mappers for type %s (%d, %s)\n", - llTypes[type].typestr, llTypes[type].nMapper, lpDrv->drvname); - if (count > 1) - ERR("Strange: mapper with %d > 1 devices\n", count); - llTypes[type].nMapper = MMDrvsHi; - } else { - if (count == 0) - return FALSE; - part->nIDMin = llTypes[type].wMaxId; - llTypes[type].wMaxId += count; - part->nIDMax = llTypes[type].wMaxId; - } - TRACE("Setting min=%d max=%d (ttop=%d) for (%s:%s)\n", - part->nIDMin, part->nIDMax, llTypes[type].wMaxId, - lpDrv->drvname, llTypes[type].typestr); - /* realloc translation table */ - if (llTypes[type].lpMlds) - llTypes[type].lpMlds = (LPWINE_MLD) - HeapReAlloc(GetProcessHeap(), 0, llTypes[type].lpMlds - 1, - sizeof(WINE_MLD) * (llTypes[type].wMaxId + 1)) + 1; - else - llTypes[type].lpMlds = (LPWINE_MLD) - HeapAlloc(GetProcessHeap(), 0, - sizeof(WINE_MLD) * (llTypes[type].wMaxId + 1)) + 1; - - /* re-build the translation table */ - if (llTypes[type].nMapper != -1) { - TRACE("%s:Trans[%d] -> %s\n", llTypes[type].typestr, -1, MMDrvs[llTypes[type].nMapper].drvname); - llTypes[type].lpMlds[-1].uDeviceID = (UINT16)-1; - llTypes[type].lpMlds[-1].type = type; - llTypes[type].lpMlds[-1].mmdIndex = llTypes[type].nMapper; - llTypes[type].lpMlds[-1].dwDriverInstance = 0; - } - for (i = k = 0; i <= MMDrvsHi; i++) { - while (MMDrvs[i].parts[type].nIDMin <= k && k < MMDrvs[i].parts[type].nIDMax) { - TRACE("%s:Trans[%d] -> %s\n", llTypes[type].typestr, k, MMDrvs[i].drvname); - llTypes[type].lpMlds[k].uDeviceID = k; - llTypes[type].lpMlds[k].type = type; - llTypes[type].lpMlds[k].mmdIndex = i; - llTypes[type].lpMlds[k].dwDriverInstance = 0; - k++; - } - } - return TRUE; -} - -/************************************************************************** - * MMDRV_Install [internal] - */ -static BOOL MMDRV_Install(LPCSTR drvRegName, LPCSTR drvFileName, BOOL bIsMapper) -{ - int i, count = 0; - LPWINE_MM_DRIVER lpDrv = &MMDrvs[MMDrvsHi]; - LPWINE_DRIVER d; - - TRACE("('%s', '%s', mapper=%c);\n", drvRegName, drvFileName, bIsMapper ? 'Y' : 'N'); - - for (i = 0; i < MMDrvsHi; i++) { - if (!strcmp(drvRegName, MMDrvs[i].drvname)) return FALSE; - } - - /* Be sure that size of MMDrvs matches the max number of loadable - * drivers !! - * If not just increase size of MMDrvs - */ - assert(MMDrvsHi <= sizeof(MMDrvs)/sizeof(MMDrvs[0])); - - memset(lpDrv, 0, sizeof(*lpDrv)); - - if (!(lpDrv->hDriver = OpenDriverA(drvFileName, 0, 0))) { - WARN("Couldn't open driver '%s'\n", drvFileName); - return FALSE; - } - - d = DRIVER_FindFromHDrvr(lpDrv->hDriver); - lpDrv->bIs32 = (d->dwFlags & WINE_GDF_16BIT) ? FALSE : TRUE; - - /* Then look for xxxMessage functions */ -#define AA(_h,_w,_x,_y,_z) \ - func = (WINEMM_msgFunc##_y) _z ((_h), #_x); \ - if (func != NULL) \ - { lpDrv->parts[_w].u.fnMessage##_y = func; count++; \ - TRACE("Got %d bit func '%s'\n", _y, #_x); } - - if (lpDrv->bIs32) { - WINEMM_msgFunc32 func; - char buffer[128]; - - if (d->d.d32.hModule) { -#define A(_x,_y) AA(d->d.d32.hModule,_x,_y,32,GetProcAddress) - A(MMDRV_AUX, auxMessage); - A(MMDRV_MIXER, mxdMessage); - A(MMDRV_MIDIIN, midMessage); - A(MMDRV_MIDIOUT, modMessage); - A(MMDRV_WAVEIN, widMessage); - A(MMDRV_WAVEOUT, wodMessage); -#undef A - } - if (TRACE_ON(winmm)) { - if (MMDRV_GetDescription32(drvFileName, buffer, sizeof(buffer))) - TRACE("%s => %s\n", drvFileName, buffer); - else - TRACE("%s => No description\n", drvFileName); - } - } else if (WINMM_CheckForMMSystem() && pFnLoadMMDrvFunc16) { - count += pFnLoadMMDrvFunc16(drvFileName, d, lpDrv); - } -#undef AA - - if (!count) { - CloseDriver(lpDrv->hDriver, 0, 0); - WARN("No message functions found\n"); - return FALSE; - } - - /* FIXME: being a mapper or not should be known by another way */ - /* it's known for NE drvs (the description is of the form '*mapper: *' - * I don't have any clue for PE drvs - */ - lpDrv->bIsMapper = bIsMapper; - lpDrv->drvname = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(drvRegName) + 1), drvRegName); - - /* Finish init and get the count of the devices */ - i = 0; - if (MMDRV_InitPerType(lpDrv, MMDRV_AUX, AUXDM_GETNUMDEVS)) i = 1; - if (MMDRV_InitPerType(lpDrv, MMDRV_MIXER, MXDM_GETNUMDEVS)) i = 1; - if (MMDRV_InitPerType(lpDrv, MMDRV_MIDIIN, MIDM_GETNUMDEVS)) i = 1; - if (MMDRV_InitPerType(lpDrv, MMDRV_MIDIOUT, MODM_GETNUMDEVS)) i = 1; - if (MMDRV_InitPerType(lpDrv, MMDRV_WAVEIN, WIDM_GETNUMDEVS)) i = 1; - if (MMDRV_InitPerType(lpDrv, MMDRV_WAVEOUT, WODM_GETNUMDEVS)) i = 1; - /* if all those func calls return FALSE, then the driver must be unloaded */ - if (!i) { - CloseDriver(lpDrv->hDriver, 0, 0); - HeapFree(GetProcessHeap(), 0, lpDrv->drvname); - WARN("Driver initialization failed\n"); - return FALSE; - } - - MMDrvsHi++; - - return TRUE; -} - -/************************************************************************** - * MMDRV_Init - */ -BOOL MMDRV_Init(void) -{ - HKEY hKey; - char driver_buffer[256]; - char mapper_buffer[256]; - char midi_buffer[256]; - DWORD type, size; - BOOL ret = FALSE; - TRACE("()\n"); - - strcpy(driver_buffer, WINE_DEFAULT_WINMM_DRIVER); - strcpy(mapper_buffer, WINE_DEFAULT_WINMM_MAPPER); - strcpy(midi_buffer, WINE_DEFAULT_WINMM_MIDI); - - if (! RegCreateKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\WinMM", &hKey)) { - size = sizeof(driver_buffer); - if (RegQueryValueExA(hKey, "Drivers", 0, &type, (LPVOID)driver_buffer, &size)) - strcpy(driver_buffer, WINE_DEFAULT_WINMM_DRIVER); - - /* finish with mappers */ - size = sizeof(mapper_buffer); - if (RegQueryValueExA(hKey, "WaveMapper", 0, &type, (LPVOID)mapper_buffer, &size)) - strcpy(mapper_buffer, WINE_DEFAULT_WINMM_MAPPER); - - size = sizeof(midi_buffer); - if (RegQueryValueExA(hKey, "MidiMapper", 0, &type, (LPVOID)midi_buffer, &size)) - strcpy(midi_buffer, WINE_DEFAULT_WINMM_MIDI); - - RegCloseKey(hKey); - } - -#ifndef __REACTOS__ - char* p1; - char* p2; - - p1 = driver_buffer; - while (p1) { - p2 = strchr(p1, ';'); - if (p2) *p2++ = '\0'; - ret |= MMDRV_Install(p1, p1, FALSE); - p1 = p2; - } -#endif - -#ifdef __REACTOS__ - // AG: TESTING: - ret |= MMDRV_Install("mmdrv.dll", "mmdrv.dll", FALSE); -#endif - - ret |= MMDRV_Install("wavemapper", mapper_buffer, TRUE); - ret |= MMDRV_Install("midimapper", midi_buffer, TRUE); - return ret; - -} - -/****************************************************************** - * ExitPerType - * - * - */ -static BOOL MMDRV_ExitPerType(LPWINE_MM_DRIVER lpDrv, UINT type) -{ - WINE_MM_DRIVER_PART* part = &lpDrv->parts[type]; - DWORD ret; - TRACE("(%p, %04x)\n", lpDrv, type); - - if (lpDrv->bIs32 && part->u.fnMessage32) { -#if 0 - ret = part->u.fnMessage32(0, DRVM_DISABLE, 0L, 0L, 0L); - TRACE("DRVM_DISABLE => %08lx\n", ret); -#endif - ret = part->u.fnMessage32(0, DRVM_EXIT, 0L, 0L, 0L); - TRACE("DRVM_EXIT => %s\n", WINMM_ErrorToString(ret)); - } else if (!lpDrv->bIs32 && part->u.fnMessage16 && pFnCallMMDrvFunc16) { -#if 0 - ret = pFnCallMMDrvFunc16((DWORD)part->u.fnMessage16, - 0, DRVM_DISABLE, 0L, 0L, 0L); - TRACE("DRVM_DISABLE => %08lx\n", ret); -#endif - ret = pFnCallMMDrvFunc16((DWORD)part->u.fnMessage16, - 0, DRVM_EXIT, 0L, 0L, 0L); - TRACE("DRVM_EXIT => %s\n", WINMM_ErrorToString(ret)); - } else { - return FALSE; - } - - return TRUE; -} - -/****************************************************************** - * Exit - * - * - */ -void MMDRV_Exit(void) -{ - int i; - TRACE("()\n"); - - for (i = 0; i < sizeof(MM_MLDrvs) / sizeof(MM_MLDrvs[0]); i++) - { - if (MM_MLDrvs[i] != NULL) - { - FIXME("Closing while ll-driver open\n"); -#if 0 - /* FIXME: should generate a message depending on type */ - MMDRV_Free((HANDLE)(i | 0x8000), MM_MLDrvs[i]); -#endif - } - } - - /* unload driver, in reverse order of loading */ - for (i = sizeof(MMDrvs) / sizeof(MMDrvs[0]) - 1; i >= 0; i--) - { - MMDRV_ExitPerType(&MMDrvs[i], MMDRV_AUX); - MMDRV_ExitPerType(&MMDrvs[i], MMDRV_MIXER); - MMDRV_ExitPerType(&MMDrvs[i], MMDRV_MIDIIN); - MMDRV_ExitPerType(&MMDrvs[i], MMDRV_MIDIOUT); - MMDRV_ExitPerType(&MMDrvs[i], MMDRV_WAVEIN); - MMDRV_ExitPerType(&MMDrvs[i], MMDRV_WAVEOUT); - CloseDriver(MMDrvs[i].hDriver, 0, 0); - } -} +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ + +/* + * MMSYTEM low level drivers handling functions + * + * Copyright 1999 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <string.h> +#include <stdarg.h> +#include <stdio.h> +#include <assert.h> +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winver.h" +#include "winemm.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winmm); + +LRESULT (*pFnCallMMDrvFunc16)(DWORD,WORD,WORD,LONG,LONG,LONG) /* = NULL */; +unsigned (*pFnLoadMMDrvFunc16)(LPCSTR,LPWINE_DRIVER, LPWINE_MM_DRIVER) /* = NULL */; + +/* each known type of driver has an instance of this structure */ +typedef struct tagWINE_LLTYPE { + /* those attributes depend on the specification of the type */ + LPCSTR typestr; /* name (for debugging) */ + BOOL bSupportMapper; /* if type is allowed to support mapper */ + MMDRV_MAPFUNC Map16To32A; /* those are function pointers to handle */ + MMDRV_UNMAPFUNC UnMap16To32A; /* the parameter conversion (16 vs 32 bit) */ + MMDRV_MAPFUNC Map32ATo16; /* when hi-func (in mmsystem or winmm) and */ + MMDRV_UNMAPFUNC UnMap32ATo16; /* low-func (in .drv) do not match */ + LPDRVCALLBACK Callback; /* handles callback for a specified type */ + /* those attributes reflect the loaded/current situation for the type */ + UINT wMaxId; /* number of loaded devices (sum across all loaded drivers */ + LPWINE_MLD lpMlds; /* "static" mlds to access the part though device IDs */ + int nMapper; /* index to mapper */ +} WINE_LLTYPE; + +static int MMDrvsHi /* = 0 */; +static WINE_MM_DRIVER MMDrvs[8]; +static LPWINE_MLD MM_MLDrvs[40]; +#define MAX_MM_MLDRVS (sizeof(MM_MLDrvs) / sizeof(MM_MLDrvs[0])) + +#define A(_x,_y) {#_y, _x, NULL, NULL, NULL, NULL, NULL, 0, NULL, -1} +/* Note: the indices of this array must match the definitions + * of the MMDRV_???? manifest constants + */ +static WINE_LLTYPE llTypes[MMDRV_MAX] = { + A(TRUE, Aux), + A(FALSE, Mixer), + A(TRUE, MidiIn), + A(TRUE, MidiOut), + A(TRUE, WaveIn), + A(TRUE, WaveOut), +}; +#undef A + +/****************************************************************** + * MMDRV_InstallMap + * + * + */ +void MMDRV_InstallMap(unsigned int drv, + MMDRV_MAPFUNC mp1632, MMDRV_UNMAPFUNC um1632, + MMDRV_MAPFUNC mp3216, MMDRV_UNMAPFUNC um3216, + LPDRVCALLBACK cb) +{ + assert(drv < MMDRV_MAX); + llTypes[drv].Map16To32A = mp1632; + llTypes[drv].UnMap16To32A = um1632; + llTypes[drv].Map32ATo16 = mp3216; + llTypes[drv].UnMap32ATo16 = um3216; + llTypes[drv].Callback = cb; +} + +/****************************************************************** + * MMDRV_Is32 + * + */ +BOOL MMDRV_Is32(unsigned int idx) +{ + TRACE("(%d)\n", idx); + return MMDrvs[idx].bIs32; +} + +/************************************************************************** + * MMDRV_GetDescription32 [internal] + */ +static BOOL MMDRV_GetDescription32(const char* fname, char* buf, int buflen) +{ + OFSTRUCT ofs; + DWORD h; + LPVOID ptr = 0; + LPVOID val; + DWORD dw; + BOOL ret = FALSE; + UINT u; + FARPROC pGetFileVersionInfoSizeA; + FARPROC pGetFileVersionInfoA; + FARPROC pVerQueryValueA; + HMODULE hmodule = 0; + TRACE("(%p, %p, %d)\n", fname, buf, buflen); + +#define E(_x) do {TRACE _x;goto theEnd;} while(0) + + if (OpenFile(fname, &ofs, OF_EXIST)==HFILE_ERROR) E(("Can't find file %s\n", fname)); + + if (!(hmodule = LoadLibraryA( "version.dll" ))) goto theEnd; + if (!(pGetFileVersionInfoSizeA = GetProcAddress( hmodule, "GetFileVersionInfoSizeA" ))) + goto theEnd; + if (!(pGetFileVersionInfoA = GetProcAddress( hmodule, "GetFileVersionInfoA" ))) + goto theEnd; + if (!(pVerQueryValueA = GetProcAddress( hmodule, "VerQueryValueA" ))) + goto theEnd; + + if (!(dw = pGetFileVersionInfoSizeA(ofs.szPathName, &h))) E(("Can't get FVIS\n")); + if (!(ptr = HeapAlloc(GetProcessHeap(), 0, dw))) E(("OOM\n")); + if (!pGetFileVersionInfoA(ofs.szPathName, h, dw, ptr)) E(("Can't get FVI\n")); + +#define A(_x) if (pVerQueryValueA(ptr, "\\StringFileInfo\\040904B0\\" #_x, &val, &u)) \ + TRACE(#_x " => %s\n", (LPSTR)val); else TRACE(#_x " @\n") + + A(CompanyName); + A(FileDescription); + A(FileVersion); + A(InternalName); + A(LegalCopyright); + A(OriginalFilename); + A(ProductName); + A(ProductVersion); + A(Comments); + A(LegalTrademarks); + A(PrivateBuild); + A(SpecialBuild); +#undef A + + if (!pVerQueryValueA(ptr, "\\StringFileInfo\\040904B0\\ProductName", &val, &u)) E(("Can't get product name\n")); + lstrcpynA(buf, val, buflen); + +#undef E + ret = TRUE; +theEnd: + HeapFree(GetProcessHeap(), 0, ptr); + if (hmodule) FreeLibrary( hmodule ); + return ret; +} + +/************************************************************************** + * MMDRV_GetNum [internal] + */ +UINT MMDRV_GetNum(UINT type) +{ + TRACE("(%04x)\n", type); + assert(type < MMDRV_MAX); + return llTypes[type].wMaxId; +} + +/************************************************************************** + * MMDRV_Message [internal] + */ +DWORD MMDRV_Message(LPWINE_MLD mld, UINT wMsg, DWORD_PTR dwParam1, + DWORD_PTR dwParam2, BOOL bFrom32) +{ + LPWINE_MM_DRIVER lpDrv; + DWORD ret; + WINE_MM_DRIVER_PART* part; + WINE_LLTYPE* llType = &llTypes[mld->type]; + WINMM_MapType map; + int devID; + + TRACE("(%s %u %u 0x%08lx 0x%08lx 0x%08lx %c)\n", + llTypes[mld->type].typestr, mld->uDeviceID, wMsg, + mld->dwDriverInstance, dwParam1, dwParam2, bFrom32?'Y':'N'); + + if (mld->uDeviceID == (UINT16)-1) { + if (!llType->bSupportMapper) { + WARN("uDev=-1 requested on non-mappable ll type %s\n", + llTypes[mld->type].typestr); + return MMSYSERR_BADDEVICEID; + } + devID = -1; + } else { + if (mld->uDeviceID >= llType->wMaxId) { + WARN("uDev(%u) requested >= max (%d)\n", mld->uDeviceID, llType->wMaxId); + return MMSYSERR_BADDEVICEID; + } + devID = mld->uDeviceID; + } + + lpDrv = &MMDrvs[mld->mmdIndex]; + part = &lpDrv->parts[mld->type]; + +#if 0 + /* some sanity checks */ + if (!(part->nIDMin <= devID)) + ERR("!(part->nIDMin(%d) <= devID(%d))\n", part->nIDMin, devID); + if (!(devID < part->nIDMax)) + ERR("!(devID(%d) < part->nIDMax(%d))\n", devID, part->nIDMax); +#endif + + if (lpDrv->bIs32) { + assert(part->u.fnMessage32); + + if (bFrom32) { + TRACE("Calling message(dev=%u msg=%u usr=0x%08lx p1=0x%08lx p2=0x%08lx)\n", + mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2); + ret = part->u.fnMessage32(mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2); + TRACE("=> %s\n", WINMM_ErrorToString(ret)); + } else { + map = llType->Map16To32A(wMsg, &mld->dwDriverInstance, &dwParam1, &dwParam2); + switch (map) { + case WINMM_MAP_NOMEM: + ret = MMSYSERR_NOMEM; + break; + case WINMM_MAP_MSGERROR: + FIXME("NIY: no conversion yet 16->32 (%u)\n", wMsg); + ret = MMSYSERR_ERROR; + break; + case WINMM_MAP_OK: + case WINMM_MAP_OKMEM: + TRACE("Calling message(dev=%u msg=%u usr=0x%08lx p1=0x%08lx p2=0x%08lx)\n", + mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2); + ret = part->u.fnMessage32(mld->uDeviceID, wMsg, mld->dwDriverInstance, + dwParam1, dwParam2); + TRACE("=> %s\n", WINMM_ErrorToString(ret)); + if (map == WINMM_MAP_OKMEM) + llType->UnMap16To32A(wMsg, &mld->dwDriverInstance, &dwParam1, &dwParam2, ret); + break; + default: + FIXME("NIY\n"); + ret = MMSYSERR_NOTSUPPORTED; + break; + } + } + } else { + assert(part->u.fnMessage16 && pFnCallMMDrvFunc16); + + if (bFrom32) { + map = llType->Map32ATo16(wMsg, &mld->dwDriverInstance, &dwParam1, &dwParam2); + switch (map) { + case WINMM_MAP_NOMEM: + ret = MMSYSERR_NOMEM; + break; + case WINMM_MAP_MSGERROR: + FIXME("NIY: no conversion yet 32->16 (%u)\n", wMsg); + ret = MMSYSERR_ERROR; + break; + case WINMM_MAP_OK: + case WINMM_MAP_OKMEM: + TRACE("Calling message(dev=%u msg=%u usr=0x%08lx p1=0x%08lx p2=0x%08lx)\n", + mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2); + ret = pFnCallMMDrvFunc16((DWORD)part->u.fnMessage16, + mld->uDeviceID, wMsg, mld->dwDriverInstance, + dwParam1, dwParam2); + TRACE("=> %s\n", WINMM_ErrorToString(ret)); + if (map == WINMM_MAP_OKMEM) + llType->UnMap32ATo16(wMsg, &mld->dwDriverInstance, &dwParam1, &dwParam2, ret); + break; + default: + FIXME("NIY\n"); + ret = MMSYSERR_NOTSUPPORTED; + break; + } + } else { + TRACE("Calling message(dev=%u msg=%u usr=0x%08lx p1=0x%08lx p2=0x%08lx)\n", + mld->uDeviceID, wMsg, mld->dwDriverInstance, dwParam1, dwParam2); + ret = pFnCallMMDrvFunc16((DWORD)part->u.fnMessage16, + mld->uDeviceID, wMsg, mld->dwDriverInstance, + dwParam1, dwParam2); + TRACE("=> %s\n", WINMM_ErrorToString(ret)); + } + } + return ret; +} + +/************************************************************************** + * MMDRV_Alloc [internal] + */ +LPWINE_MLD MMDRV_Alloc(UINT size, UINT type, LPHANDLE hndl, DWORD* dwFlags, + DWORD* dwCallback, DWORD* dwInstance, BOOL bFrom32) +{ + LPWINE_MLD mld; + UINT i; + TRACE("(%d, %04x, %p, %p, %p, %p, %c)\n", + size, type, hndl, dwFlags, dwCallback, dwInstance, bFrom32?'Y':'N'); + + mld = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); + if (!mld) return NULL; + + /* find an empty slot in MM_MLDrvs table */ + for (i = 0; i < MAX_MM_MLDRVS; i++) if (!MM_MLDrvs[i]) break; + + if (i == MAX_MM_MLDRVS) { + /* the MM_MLDrvs table could be made growable in the future if needed */ + ERR("Too many open drivers\n"); + HeapFree(GetProcessHeap(), 0, mld); + return NULL; + } + MM_MLDrvs[i] = mld; + *hndl = (HANDLE)(i | 0x8000); + + mld->type = type; + if ((UINT)*hndl < MMDRV_GetNum(type) || HIWORD(*hndl) != 0) { + /* FIXME: those conditions must be fulfilled so that: + * - we can distinguish between device IDs and handles + * - we can use handles as 16 or 32 bit entities + */ + ERR("Shouldn't happen. Bad allocation scheme\n"); + } + + mld->bFrom32 = bFrom32; + mld->dwFlags = HIWORD(*dwFlags); + mld->dwCallback = *dwCallback; + mld->dwClientInstance = *dwInstance; + + if (llTypes[type].Callback) + { + *dwFlags = LOWORD(*dwFlags) | CALLBACK_FUNCTION; + *dwCallback = (DWORD)llTypes[type].Callback; + *dwInstance = (DWORD)mld; /* FIXME: wouldn't some 16 bit drivers only use the loword ? */ + } + + return mld; +} + +/************************************************************************** + * MMDRV_Free [internal] + */ +void MMDRV_Free(HANDLE hndl, LPWINE_MLD mld) +{ + TRACE("(%p, %p)\n", hndl, mld); + + if ((UINT)hndl & 0x8000) { + unsigned idx = (UINT)hndl & ~0x8000; + if (idx < sizeof(MM_MLDrvs) / sizeof(MM_MLDrvs[0])) { + MM_MLDrvs[idx] = NULL; + HeapFree(GetProcessHeap(), 0, mld); + return; + } + } + ERR("Bad Handle %p at %p (not freed)\n", hndl, mld); +} + +/************************************************************************** + * MMDRV_Open [internal] + */ +DWORD MMDRV_Open(LPWINE_MLD mld, UINT wMsg, DWORD dwParam1, DWORD dwFlags) +{ + DWORD dwRet = MMSYSERR_BADDEVICEID; + DWORD dwInstance; + WINE_LLTYPE* llType = &llTypes[mld->type]; + TRACE("(%p, %04x, 0x%08lx, 0x%08lx)\n", mld, wMsg, dwParam1, dwFlags); + + mld->dwDriverInstance = (DWORD)&dwInstance; + + if (mld->uDeviceID == (UINT)-1 || mld->uDeviceID == (UINT16)-1) { + TRACE("MAPPER mode requested !\n"); + /* check if mapper is supported by type */ + if (llType->bSupportMapper) { + if (llType->nMapper == -1) { + /* no driver for mapper has been loaded, try a dumb implementation */ + TRACE("No mapper loaded, doing it by hand\n"); + for (mld->uDeviceID = 0; mld->uDeviceID < llType->wMaxId; mld->uDeviceID++) { + if ((dwRet = MMDRV_Open(mld, wMsg, dwParam1, dwFlags)) == MMSYSERR_NOERROR) { + /* to share this function epilog */ + dwInstance = mld->dwDriverInstance; + break; + } + } + } else { + mld->uDeviceID = (UINT16)-1; + mld->mmdIndex = llType->lpMlds[-1].mmdIndex; + TRACE("Setting mmdIndex to %u\n", mld->mmdIndex); + dwRet = MMDRV_Message(mld, wMsg, dwParam1, dwFlags, TRUE); + } + } + } else { + if (mld->uDeviceID < llType->wMaxId) { + mld->mmdIndex = llType->lpMlds[mld->uDeviceID].mmdIndex; + TRACE("Setting mmdIndex to %u\n", mld->mmdIndex); + dwRet = MMDRV_Message(mld, wMsg, dwParam1, dwFlags, TRUE); + } + } + if (dwRet == MMSYSERR_NOERROR) + mld->dwDriverInstance = dwInstance; + return dwRet; +} + +/************************************************************************** + * MMDRV_Close [internal] + */ +DWORD MMDRV_Close(LPWINE_MLD mld, UINT wMsg) +{ + TRACE("(%p, %04x)\n", mld, wMsg); + return MMDRV_Message(mld, wMsg, 0L, 0L, TRUE); +} + +/************************************************************************** + * MMDRV_GetByID [internal] + */ +LPWINE_MLD MMDRV_GetByID(UINT uDevID, UINT type) +{ + TRACE("(%04x, %04x)\n", uDevID, type); + if (uDevID < llTypes[type].wMaxId) + return &llTypes[type].lpMlds[uDevID]; + if ((uDevID == (UINT16)-1 || uDevID == (UINT)-1) && llTypes[type].nMapper != -1) + return &llTypes[type].lpMlds[-1]; + return NULL; +} + +/************************************************************************** + * MMDRV_Get [internal] + */ +LPWINE_MLD MMDRV_Get(HANDLE _hndl, UINT type, BOOL bCanBeID) +{ + LPWINE_MLD mld = NULL; + UINT hndl = (UINT)_hndl; + TRACE("(%p, %04x, %c)\n", _hndl, type, bCanBeID ? 'Y' : 'N'); + + assert(type < MMDRV_MAX); + + if (hndl >= llTypes[type].wMaxId && + hndl != (UINT16)-1 && hndl != (UINT)-1) { + if (hndl & 0x8000) { + hndl = hndl & ~0x8000; + if (hndl < sizeof(MM_MLDrvs) / sizeof(MM_MLDrvs[0])) { + mld = MM_MLDrvs[hndl]; + if (!mld || !HeapValidate(GetProcessHeap(), 0, mld) || mld->type != type) + mld = NULL; + } + hndl = hndl | 0x8000; + } + } + if (mld == NULL && bCanBeID) { + mld = MMDRV_GetByID(hndl, type); + } + return mld; +} + +/************************************************************************** + * MMDRV_GetRelated [internal] + */ +LPWINE_MLD MMDRV_GetRelated(HANDLE hndl, UINT srcType, + BOOL bSrcCanBeID, UINT dstType) +{ + LPWINE_MLD mld; + TRACE("(%p, %04x, %c, %04x)\n", + hndl, srcType, bSrcCanBeID ? 'Y' : 'N', dstType); + + if ((mld = MMDRV_Get(hndl, srcType, bSrcCanBeID)) != NULL) { + WINE_MM_DRIVER_PART* part = &MMDrvs[mld->mmdIndex].parts[dstType]; + if (part->nIDMin < part->nIDMax) + return MMDRV_GetByID(part->nIDMin, dstType); + } + return NULL; +} + +/************************************************************************** + * MMDRV_PhysicalFeatures [internal] + */ +UINT MMDRV_PhysicalFeatures(LPWINE_MLD mld, UINT uMsg, DWORD dwParam1, + DWORD dwParam2) +{ + WINE_MM_DRIVER* lpDrv = &MMDrvs[mld->mmdIndex]; + + TRACE("(%p, %04x, %08lx, %08lx)\n", mld, uMsg, dwParam1, dwParam2); + + /* all those function calls are undocumented */ + switch (uMsg) { + case DRV_QUERYDRVENTRY: + lstrcpynA((LPSTR)dwParam1, lpDrv->drvname, LOWORD(dwParam2)); + break; + case DRV_QUERYDEVNODE: + *(LPDWORD)dwParam1 = 0L; /* should be DevNode */ + break; + case DRV_QUERYNAME: + WARN("NIY QueryName\n"); + break; + case DRV_QUERYDRIVERIDS: + WARN("NIY call VxD\n"); + /* should call VxD MMDEVLDR with (DevNode, dwParam1 and dwParam2) as pmts + * dwParam1 is buffer and dwParam2 is sizeof(buffer) + * I don't know where the result is stored though + */ + break; + case DRV_QUERYMAPPABLE: + return (lpDrv->bIsMapper) ? 2 : 0; + + case DRVM_MAPPER_PREFERRED_GET: + /* FIXME: get from registry someday */ + *((LPDWORD)dwParam1) = -1; /* No preferred device */ + *((LPDWORD)dwParam2) = 0; + break; + + case DRV_QUERYDEVICEINTERFACE: + case DRV_QUERYDEVICEINTERFACESIZE: + return MMDRV_Message(mld, uMsg, dwParam1, dwParam2, TRUE); + + case DRV_QUERYDSOUNDIFACE: /* Wine-specific: Retrieve DirectSound interface */ + case DRV_QUERYDSOUNDDESC: /* Wine-specific: Retrieve DirectSound driver description*/ + return MMDRV_Message(mld, uMsg, dwParam1, dwParam2, TRUE); + + default: + WARN("Unknown call %04x\n", uMsg); + return MMSYSERR_INVALPARAM; + } + return 0L; +} + +/************************************************************************** + * MMDRV_InitPerType [internal] + */ +static BOOL MMDRV_InitPerType(LPWINE_MM_DRIVER lpDrv, UINT type, UINT wMsg) +{ + WINE_MM_DRIVER_PART* part = &lpDrv->parts[type]; + DWORD ret; + UINT count = 0; + int i, k; + TRACE("(%p, %04x, %04x)\n", lpDrv, type, wMsg); + + part->nIDMin = part->nIDMax = 0; + + /* for DRVM_INIT and DRVM_ENABLE, dwParam2 should be PnP node */ + /* the DRVM_ENABLE is only required when the PnP node is non zero */ + + if (lpDrv->bIs32 && part->u.fnMessage32) { + ret = part->u.fnMessage32(0, DRVM_INIT, 0L, 0L, 0L); + TRACE("DRVM_INIT => %s\n", WINMM_ErrorToString(ret)); +#if 0 + ret = part->u.fnMessage32(0, DRVM_ENABLE, 0L, 0L, 0L); + TRACE("DRVM_ENABLE => %08lx\n", ret); +#endif + count = part->u.fnMessage32(0, wMsg, 0L, 0L, 0L); + } else if (!lpDrv->bIs32 && part->u.fnMessage16 && pFnCallMMDrvFunc16) { + ret = pFnCallMMDrvFunc16((DWORD)part->u.fnMessage16, + 0, DRVM_INIT, 0L, 0L, 0L); + TRACE("DRVM_INIT => %s\n", WINMM_ErrorToString(ret)); +#if 0 + ret = pFnCallMMDrvFunc16((DWORD)part->u.fnMessage16, + 0, DRVM_ENABLE, 0L, 0L, 0L); + TRACE("DRVM_ENABLE => %08lx\n", ret); +#endif + count = pFnCallMMDrvFunc16((DWORD)part->u.fnMessage16, + 0, wMsg, 0L, 0L, 0L); + } else { + return FALSE; + } + + TRACE("Got %u dev for (%s:%s)\n", count, lpDrv->drvname, llTypes[type].typestr); + + if (HIWORD(count)) + return FALSE; + + /* got some drivers */ + if (lpDrv->bIsMapper) { + /* it seems native mappers return 0 devices :-( */ + if (llTypes[type].nMapper != -1) + ERR("Two mappers for type %s (%d, %s)\n", + llTypes[type].typestr, llTypes[type].nMapper, lpDrv->drvname); + if (count > 1) + ERR("Strange: mapper with %d > 1 devices\n", count); + llTypes[type].nMapper = MMDrvsHi; + } else { + if (count == 0) + return FALSE; + part->nIDMin = llTypes[type].wMaxId; + llTypes[type].wMaxId += count; + part->nIDMax = llTypes[type].wMaxId; + } + TRACE("Setting min=%d max=%d (ttop=%d) for (%s:%s)\n", + part->nIDMin, part->nIDMax, llTypes[type].wMaxId, + lpDrv->drvname, llTypes[type].typestr); + /* realloc translation table */ + if (llTypes[type].lpMlds) + llTypes[type].lpMlds = (LPWINE_MLD) + HeapReAlloc(GetProcessHeap(), 0, llTypes[type].lpMlds - 1, + sizeof(WINE_MLD) * (llTypes[type].wMaxId + 1)) + 1; + else + llTypes[type].lpMlds = (LPWINE_MLD) + HeapAlloc(GetProcessHeap(), 0, + sizeof(WINE_MLD) * (llTypes[type].wMaxId + 1)) + 1; + + /* re-build the translation table */ + if (llTypes[type].nMapper != -1) { + TRACE("%s:Trans[%d] -> %s\n", llTypes[type].typestr, -1, MMDrvs[llTypes[type].nMapper].drvname); + llTypes[type].lpMlds[-1].uDeviceID = (UINT16)-1; + llTypes[type].lpMlds[-1].type = type; + llTypes[type].lpMlds[-1].mmdIndex = llTypes[type].nMapper; + llTypes[type].lpMlds[-1].dwDriverInstance = 0; + } + for (i = k = 0; i <= MMDrvsHi; i++) { + while (MMDrvs[i].parts[type].nIDMin <= k && k < MMDrvs[i].parts[type].nIDMax) { + TRACE("%s:Trans[%d] -> %s\n", llTypes[type].typestr, k, MMDrvs[i].drvname); + llTypes[type].lpMlds[k].uDeviceID = k; + llTypes[type].lpMlds[k].type = type; + llTypes[type].lpMlds[k].mmdIndex = i; + llTypes[type].lpMlds[k].dwDriverInstance = 0; + k++; + } + } + return TRUE; +} + +/************************************************************************** + * MMDRV_Install [internal] + */ +static BOOL MMDRV_Install(LPCSTR drvRegName, LPCSTR drvFileName, BOOL bIsMapper) +{ + int i, count = 0; + LPWINE_MM_DRIVER lpDrv = &MMDrvs[MMDrvsHi]; + LPWINE_DRIVER d; + + TRACE("('%s', '%s', mapper=%c);\n", drvRegName, drvFileName, bIsMapper ? 'Y' : 'N'); + + for (i = 0; i < MMDrvsHi; i++) { + if (!strcmp(drvRegName, MMDrvs[i].drvname)) return FALSE; + } + + /* Be sure that size of MMDrvs matches the max number of loadable + * drivers !! + * If not just increase size of MMDrvs + */ + assert(MMDrvsHi <= sizeof(MMDrvs)/sizeof(MMDrvs[0])); + + memset(lpDrv, 0, sizeof(*lpDrv)); + + if (!(lpDrv->hDriver = OpenDriverA(drvFileName, 0, 0))) { + WARN("Couldn't open driver '%s'\n", drvFileName); + return FALSE; + } + + d = DRIVER_FindFromHDrvr(lpDrv->hDriver); + lpDrv->bIs32 = (d->dwFlags & WINE_GDF_16BIT) ? FALSE : TRUE; + + /* Then look for xxxMessage functions */ +#define AA(_h,_w,_x,_y,_z) \ + func = (WINEMM_msgFunc##_y) _z ((_h), #_x); \ + if (func != NULL) \ + { lpDrv->parts[_w].u.fnMessage##_y = func; count++; \ + TRACE("Got %d bit func '%s'\n", _y, #_x); } + + if (lpDrv->bIs32) { + WINEMM_msgFunc32 func; + char buffer[128]; + + if (d->d.d32.hModule) { +#define A(_x,_y) AA(d->d.d32.hModule,_x,_y,32,GetProcAddress) + A(MMDRV_AUX, auxMessage); + A(MMDRV_MIXER, mxdMessage); + A(MMDRV_MIDIIN, midMessage); + A(MMDRV_MIDIOUT, modMessage); + A(MMDRV_WAVEIN, widMessage); + A(MMDRV_WAVEOUT, wodMessage); +#undef A + } + if (TRACE_ON(winmm)) { + if (MMDRV_GetDescription32(drvFileName, buffer, sizeof(buffer))) + TRACE("%s => %s\n", drvFileName, buffer); + else + TRACE("%s => No description\n", drvFileName); + } + } else if (WINMM_CheckForMMSystem() && pFnLoadMMDrvFunc16) { + count += pFnLoadMMDrvFunc16(drvFileName, d, lpDrv); + } +#undef AA + + if (!count) { + CloseDriver(lpDrv->hDriver, 0, 0); + WARN("No message functions found\n"); + return FALSE; + } + + /* FIXME: being a mapper or not should be known by another way */ + /* it's known for NE drvs (the description is of the form '*mapper: *' + * I don't have any clue for PE drvs + */ + lpDrv->bIsMapper = bIsMapper; + lpDrv->drvname = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(drvRegName) + 1), drvRegName); + + /* Finish init and get the count of the devices */ + i = 0; + if (MMDRV_InitPerType(lpDrv, MMDRV_AUX, AUXDM_GETNUMDEVS)) i = 1; + if (MMDRV_InitPerType(lpDrv, MMDRV_MIXER, MXDM_GETNUMDEVS)) i = 1; + if (MMDRV_InitPerType(lpDrv, MMDRV_MIDIIN, MIDM_GETNUMDEVS)) i = 1; + if (MMDRV_InitPerType(lpDrv, MMDRV_MIDIOUT, MODM_GETNUMDEVS)) i = 1; + if (MMDRV_InitPerType(lpDrv, MMDRV_WAVEIN, WIDM_GETNUMDEVS)) i = 1; + if (MMDRV_InitPerType(lpDrv, MMDRV_WAVEOUT, WODM_GETNUMDEVS)) i = 1; + /* if all those func calls return FALSE, then the driver must be unloaded */ + if (!i) { + CloseDriver(lpDrv->hDriver, 0, 0); + HeapFree(GetProcessHeap(), 0, lpDrv->drvname); + WARN("Driver initialization failed\n"); + return FALSE; + } + + MMDrvsHi++; + + return TRUE; +} + +/************************************************************************** + * MMDRV_Init + */ +BOOL MMDRV_Init(void) +{ + HKEY hKey; + char driver_buffer[256]; + char mapper_buffer[256]; + char midi_buffer[256]; + DWORD type, size; + BOOL ret = FALSE; + TRACE("()\n"); + + strcpy(driver_buffer, WINE_DEFAULT_WINMM_DRIVER); + strcpy(mapper_buffer, WINE_DEFAULT_WINMM_MAPPER); + strcpy(midi_buffer, WINE_DEFAULT_WINMM_MIDI); + + if (! RegCreateKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\WinMM", &hKey)) { + size = sizeof(driver_buffer); + if (RegQueryValueExA(hKey, "Drivers", 0, &type, (LPVOID)driver_buffer, &size)) + strcpy(driver_buffer, WINE_DEFAULT_WINMM_DRIVER); + + /* finish with mappers */ + size = sizeof(mapper_buffer); + if (RegQueryValueExA(hKey, "WaveMapper", 0, &type, (LPVOID)mapper_buffer, &size)) + strcpy(mapper_buffer, WINE_DEFAULT_WINMM_MAPPER); + + size = sizeof(midi_buffer); + if (RegQueryValueExA(hKey, "MidiMapper", 0, &type, (LPVOID)midi_buffer, &size)) + strcpy(midi_buffer, WINE_DEFAULT_WINMM_MIDI); + + RegCloseKey(hKey); + } + +#ifndef __REACTOS__ + char* p1; + char* p2; + + p1 = driver_buffer; + while (p1) { + p2 = strchr(p1, ';'); + if (p2) *p2++ = '\0'; + ret |= MMDRV_Install(p1, p1, FALSE); + p1 = p2; + } +#endif + +#ifdef __REACTOS__ + // AG: TESTING: + ret |= MMDRV_Install("mmdrv.dll", "mmdrv.dll", FALSE); +#endif + + ret |= MMDRV_Install("wavemapper", mapper_buffer, TRUE); + ret |= MMDRV_Install("midimapper", midi_buffer, TRUE); + return ret; + +} + +/****************************************************************** + * ExitPerType + * + * + */ +static BOOL MMDRV_ExitPerType(LPWINE_MM_DRIVER lpDrv, UINT type) +{ + WINE_MM_DRIVER_PART* part = &lpDrv->parts[type]; + DWORD ret; + TRACE("(%p, %04x)\n", lpDrv, type); + + if (lpDrv->bIs32 && part->u.fnMessage32) { +#if 0 + ret = part->u.fnMessage32(0, DRVM_DISABLE, 0L, 0L, 0L); + TRACE("DRVM_DISABLE => %08lx\n", ret); +#endif + ret = part->u.fnMessage32(0, DRVM_EXIT, 0L, 0L, 0L); + TRACE("DRVM_EXIT => %s\n", WINMM_ErrorToString(ret)); + } else if (!lpDrv->bIs32 && part->u.fnMessage16 && pFnCallMMDrvFunc16) { +#if 0 + ret = pFnCallMMDrvFunc16((DWORD)part->u.fnMessage16, + 0, DRVM_DISABLE, 0L, 0L, 0L); + TRACE("DRVM_DISABLE => %08lx\n", ret); +#endif + ret = pFnCallMMDrvFunc16((DWORD)part->u.fnMessage16, + 0, DRVM_EXIT, 0L, 0L, 0L); + TRACE("DRVM_EXIT => %s\n", WINMM_ErrorToString(ret)); + } else { + return FALSE; + } + + return TRUE; +} + +/****************************************************************** + * Exit + * + * + */ +void MMDRV_Exit(void) +{ + int i; + TRACE("()\n"); + + for (i = 0; i < sizeof(MM_MLDrvs) / sizeof(MM_MLDrvs[0]); i++) + { + if (MM_MLDrvs[i] != NULL) + { + FIXME("Closing while ll-driver open\n"); +#if 0 + /* FIXME: should generate a message depending on type */ + MMDRV_Free((HANDLE)(i | 0x8000), MM_MLDrvs[i]); +#endif + } + } + + /* unload driver, in reverse order of loading */ + for (i = sizeof(MMDrvs) / sizeof(MMDrvs[0]) - 1; i >= 0; i--) + { + MMDRV_ExitPerType(&MMDrvs[i], MMDRV_AUX); + MMDRV_ExitPerType(&MMDrvs[i], MMDRV_MIXER); + MMDRV_ExitPerType(&MMDrvs[i], MMDRV_MIDIIN); + MMDRV_ExitPerType(&MMDrvs[i], MMDRV_MIDIOUT); + MMDRV_ExitPerType(&MMDrvs[i], MMDRV_WAVEIN); + MMDRV_ExitPerType(&MMDrvs[i], MMDRV_WAVEOUT); + CloseDriver(MMDrvs[i].hDriver, 0, 0); + } +} diff --git a/reactos/lib/winmm/mci.c b/reactos/lib/winmm/mci.c index 5faa40da09d..45c5c3a6297 100644 --- a/reactos/lib/winmm/mci.c +++ b/reactos/lib/winmm/mci.c @@ -1,2419 +1,2419 @@ -/* - * MCI internal functions - * - * Copyright 1998/1999 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* TODO: - * - implement WINMM (32bit) multitasking and use it in all MCI drivers - * instead of the home grown one - * - 16bit mmTaskXXX functions are currently broken because the 16 - * loader does not support binary command lines => provide Wine's - * own mmtask.tsk not using binary command line. - * - correctly handle the MCI_ALL_DEVICE_ID in functions. - * - finish mapping 16 <=> 32 of MCI structures and commands - * - implement auto-open feature (ie, when a string command is issued - * for a not yet opened device, MCI automatically opens it) - * - use a default registry setting to replace the [mci] section in - * configuration file (layout of info in registry should be compatible - * with all Windows' version - which use different layouts of course) - * - implement automatic open - * + only works on string interface, on regular devices (don't work on all - * nor custom devices) - * - command table handling isn't thread safe - */ - -/* to be cross checked: - * - heapalloc for *sizeof(WCHAR) when needed - * - size of string in WCHAR or bytes? (#chars for MCI_INFO, #bytes for MCI_SYSINFO) - */ - -#include "config.h" -#include "wine/port.h" - -#include <stdlib.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winreg.h" -#include "mmsystem.h" -#include "winuser.h" -#include "winnls.h" -#include "winreg.h" -#include "wownt32.h" - -#include "digitalv.h" -#include "winemm.h" - -#include "wine/debug.h" -#include "wine/unicode.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mci); - -WINMM_MapType (*pFnMciMapMsg16To32W) (WORD,WORD,DWORD*) /* = NULL */; -WINMM_MapType (*pFnMciUnMapMsg16To32W)(WORD,WORD,DWORD) /* = NULL */; -WINMM_MapType (*pFnMciMapMsg32WTo16) (WORD,WORD,DWORD,DWORD*) /* = NULL */; -WINMM_MapType (*pFnMciUnMapMsg32WTo16)(WORD,WORD,DWORD,DWORD) /* = NULL */; - -/* First MCI valid device ID (0 means error) */ -#define MCI_MAGIC 0x0001 - -/* MCI settings */ -static const WCHAR wszHklmMci [] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','M','C','I',0}; -static const WCHAR wszNull [] = {0}; -static const WCHAR wszAll [] = {'A','L','L',0}; -static const WCHAR wszMci [] = {'M','C','I',0}; -static const WCHAR wszOpen [] = {'o','p','e','n',0}; -static const WCHAR wszSystemIni[] = {'s','y','s','t','e','m','.','i','n','i',0}; - -/* dup a string and uppercase it */ -inline static LPWSTR str_dup_upper( LPCWSTR str ) -{ - INT len = (strlenW(str) + 1) * sizeof(WCHAR); - LPWSTR p = HeapAlloc( GetProcessHeap(), 0, len ); - if (p) - { - memcpy( p, str, len ); - CharUpperW( p ); - } - return p; -} - -/************************************************************************** - * MCI_GetDriver [internal] - */ -LPWINE_MCIDRIVER MCI_GetDriver(UINT16 wDevID) -{ - LPWINE_MCIDRIVER wmd = 0; - - EnterCriticalSection(&WINMM_IData.cs); - for (wmd = WINMM_IData.lpMciDrvs; wmd; wmd = wmd->lpNext) { - if (wmd->wDeviceID == wDevID) - break; - } - LeaveCriticalSection(&WINMM_IData.cs); - return wmd; -} - -/************************************************************************** - * MCI_GetDriverFromString [internal] - */ -UINT MCI_GetDriverFromString(LPCWSTR lpstrName) -{ - LPWINE_MCIDRIVER wmd; - UINT ret = 0; - - if (!lpstrName) - return 0; - - if (!strcmpiW(lpstrName, wszAll)) - return MCI_ALL_DEVICE_ID; - - EnterCriticalSection(&WINMM_IData.cs); - for (wmd = WINMM_IData.lpMciDrvs; wmd; wmd = wmd->lpNext) { - if (wmd->lpstrElementName && strcmpW(wmd->lpstrElementName, lpstrName) == 0) { - ret = wmd->wDeviceID; - break; - } - if (wmd->lpstrDeviceType && strcmpiW(wmd->lpstrDeviceType, lpstrName) == 0) { - ret = wmd->wDeviceID; - break; - } - if (wmd->lpstrAlias && strcmpiW(wmd->lpstrAlias, lpstrName) == 0) { - ret = wmd->wDeviceID; - break; - } - } - LeaveCriticalSection(&WINMM_IData.cs); - - return ret; -} - -/************************************************************************** - * MCI_MessageToString [internal] - */ -const char* MCI_MessageToString(UINT wMsg) -{ - static char buffer[100]; - -#define CASE(s) case (s): return #s - - switch (wMsg) { - CASE(DRV_LOAD); - CASE(DRV_ENABLE); - CASE(DRV_OPEN); - CASE(DRV_CLOSE); - CASE(DRV_DISABLE); - CASE(DRV_FREE); - CASE(DRV_CONFIGURE); - CASE(DRV_QUERYCONFIGURE); - CASE(DRV_INSTALL); - CASE(DRV_REMOVE); - CASE(DRV_EXITSESSION); - CASE(DRV_EXITAPPLICATION); - CASE(DRV_POWER); - CASE(MCI_BREAK); - CASE(MCI_CLOSE); - CASE(MCI_CLOSE_DRIVER); - CASE(MCI_COPY); - CASE(MCI_CUE); - CASE(MCI_CUT); - CASE(MCI_DELETE); - CASE(MCI_ESCAPE); - CASE(MCI_FREEZE); - CASE(MCI_PAUSE); - CASE(MCI_PLAY); - CASE(MCI_GETDEVCAPS); - CASE(MCI_INFO); - CASE(MCI_LOAD); - CASE(MCI_OPEN); - CASE(MCI_OPEN_DRIVER); - CASE(MCI_PASTE); - CASE(MCI_PUT); - CASE(MCI_REALIZE); - CASE(MCI_RECORD); - CASE(MCI_RESUME); - CASE(MCI_SAVE); - CASE(MCI_SEEK); - CASE(MCI_SET); - CASE(MCI_SPIN); - CASE(MCI_STATUS); - CASE(MCI_STEP); - CASE(MCI_STOP); - CASE(MCI_SYSINFO); - CASE(MCI_UNFREEZE); - CASE(MCI_UPDATE); - CASE(MCI_WHERE); - CASE(MCI_WINDOW); - /* constants for digital video */ - CASE(MCI_CAPTURE); - CASE(MCI_MONITOR); - CASE(MCI_RESERVE); - CASE(MCI_SETAUDIO); - CASE(MCI_SIGNAL); - CASE(MCI_SETVIDEO); - CASE(MCI_QUALITY); - CASE(MCI_LIST); - CASE(MCI_UNDO); - CASE(MCI_CONFIGURE); - CASE(MCI_RESTORE); -#undef CASE - default: - sprintf(buffer, "MCI_<<%04X>>", wMsg); - return buffer; - } -} - -LPWSTR MCI_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; -} - -LPSTR MCI_strdupWtoA( LPCWSTR str ) -{ - LPSTR ret; - INT len; - - if (!str) return NULL; - len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL ); - ret = HeapAlloc( GetProcessHeap(), 0, len ); - if (ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL ); - return ret; -} - -static int MCI_MapMsgAtoW(UINT msg, DWORD_PTR dwParam1, DWORD_PTR *dwParam2) -{ - if (msg < DRV_RESERVED) return 0; - - switch (msg) - { - case MCI_CLOSE: - case MCI_CONFIGURE: - case MCI_PLAY: - case MCI_SEEK: - case MCI_STOP: - case MCI_PAUSE: - case MCI_GETDEVCAPS: - case MCI_SPIN: - case MCI_SET: - case MCI_STEP: - case MCI_RECORD: - case MCI_BREAK: - case MCI_SOUND: - case MCI_STATUS: - case MCI_CUE: - case MCI_REALIZE: - case MCI_PUT: - case MCI_WHERE: - case MCI_FREEZE: - case MCI_UNFREEZE: - case MCI_CUT: - case MCI_COPY: - case MCI_PASTE: - case MCI_UPDATE: - case MCI_RESUME: - case MCI_DELETE: - case MCI_MONITOR: - case MCI_SETAUDIO: - case MCI_SIGNAL: - case MCI_SETVIDEO: - case MCI_LIST: - return 0; - - case MCI_OPEN: - { - MCI_OPEN_PARMSA *mci_openA = (MCI_OPEN_PARMSA*)*dwParam2; - MCI_OPEN_PARMSW *mci_openW; - DWORD_PTR *ptr; - - ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD_PTR) + sizeof(*mci_openW) + 2 * sizeof(DWORD)); - if (!ptr) return -1; - - *ptr++ = *dwParam2; /* save the previous pointer */ - *dwParam2 = (DWORD_PTR)ptr; - mci_openW = (MCI_OPEN_PARMSW *)ptr; - - if (dwParam1 & MCI_NOTIFY) - mci_openW->dwCallback = mci_openA->dwCallback; - - if (dwParam1 & MCI_OPEN_TYPE) - { - if (dwParam1 & MCI_OPEN_TYPE_ID) - mci_openW->lpstrDeviceType = (LPWSTR)mci_openA->lpstrDeviceType; - else - mci_openW->lpstrDeviceType = MCI_strdupAtoW(mci_openA->lpstrDeviceType); - } - if (dwParam1 & MCI_OPEN_ELEMENT) - { - if (dwParam1 & MCI_OPEN_ELEMENT_ID) - mci_openW->lpstrElementName = (LPWSTR)mci_openA->lpstrElementName; - else - mci_openW->lpstrElementName = MCI_strdupAtoW(mci_openA->lpstrElementName); - } - if (dwParam1 & MCI_OPEN_ALIAS) - mci_openW->lpstrAlias = MCI_strdupAtoW(mci_openA->lpstrAlias); - /* FIXME: this is only needed for specific types of MCI devices, and - * may cause a segfault if the two DWORD:s don't exist at the end of - * mci_openA - */ - memcpy(mci_openW + 1, mci_openA + 1, 2 * sizeof(DWORD)); - } - return 1; - - case MCI_WINDOW: - if (dwParam1 & MCI_ANIM_WINDOW_TEXT) - { - MCI_ANIM_WINDOW_PARMSA *mci_windowA = (MCI_ANIM_WINDOW_PARMSA *)*dwParam2; - MCI_ANIM_WINDOW_PARMSW *mci_windowW; - - mci_windowW = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_windowW)); - if (!mci_windowW) return -1; - - *dwParam2 = (DWORD_PTR)mci_windowW; - - mci_windowW->lpstrText = MCI_strdupAtoW(mci_windowA->lpstrText); - - if (dwParam1 & MCI_NOTIFY) - mci_windowW->dwCallback = mci_windowA->dwCallback; - if (dwParam1 & MCI_ANIM_WINDOW_HWND) - mci_windowW->hWnd = mci_windowA->hWnd; - if (dwParam1 & MCI_ANIM_WINDOW_STATE) - mci_windowW->nCmdShow = mci_windowA->nCmdShow; - - return 1; - } - return 0; - - case MCI_SYSINFO: - { - MCI_SYSINFO_PARMSA *mci_sysinfoA = (MCI_SYSINFO_PARMSA *)*dwParam2; - MCI_SYSINFO_PARMSW *mci_sysinfoW; - DWORD_PTR *ptr; - - ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_sysinfoW) + sizeof(DWORD_PTR)); - if (!ptr) return -1; - - *ptr++ = *dwParam2; /* save the previous pointer */ - *dwParam2 = (DWORD_PTR)ptr; - mci_sysinfoW = (MCI_SYSINFO_PARMSW *)ptr; - - if (dwParam1 & MCI_NOTIFY) - mci_sysinfoW->dwCallback = mci_sysinfoA->dwCallback; - - mci_sysinfoW->dwRetSize = mci_sysinfoA->dwRetSize; - mci_sysinfoW->lpstrReturn = HeapAlloc(GetProcessHeap(), 0, mci_sysinfoW->dwRetSize); - mci_sysinfoW->dwNumber = mci_sysinfoA->dwNumber; - mci_sysinfoW->wDeviceType = mci_sysinfoA->wDeviceType; - return 1; - } - case MCI_INFO: - { - MCI_INFO_PARMSA *mci_infoA = (MCI_INFO_PARMSA *)*dwParam2; - MCI_INFO_PARMSW *mci_infoW; - DWORD_PTR *ptr; - - ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_infoW) + sizeof(DWORD_PTR)); - if (!ptr) return -1; - - *ptr++ = *dwParam2; /* save the previous pointer */ - *dwParam2 = (DWORD_PTR)ptr; - mci_infoW = (MCI_INFO_PARMSW *)ptr; - - if (dwParam1 & MCI_NOTIFY) - mci_infoW->dwCallback = mci_infoA->dwCallback; - - mci_infoW->dwRetSize = mci_infoA->dwRetSize * sizeof(WCHAR); /* it's not the same as SYSINFO !!! */ - mci_infoW->lpstrReturn = HeapAlloc(GetProcessHeap(), 0, mci_infoW->dwRetSize); - return 1; - } - case MCI_SAVE: - { - MCI_SAVE_PARMSA *mci_saveA = (MCI_SAVE_PARMSA *)*dwParam2; - MCI_SAVE_PARMSW *mci_saveW; - - mci_saveW = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_saveW)); - if (!mci_saveW) return -1; - - *dwParam2 = (DWORD_PTR)mci_saveW; - if (dwParam1 & MCI_NOTIFY) - mci_saveW->dwCallback = mci_saveA->dwCallback; - mci_saveW->lpfilename = MCI_strdupAtoW(mci_saveA->lpfilename); - return 1; - } - case MCI_LOAD: - { - MCI_LOAD_PARMSA *mci_loadA = (MCI_LOAD_PARMSA *)*dwParam2; - MCI_LOAD_PARMSW *mci_loadW; - - mci_loadW = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_loadW)); - if (!mci_loadW) return -1; - - *dwParam2 = (DWORD_PTR)mci_loadW; - if (dwParam1 & MCI_NOTIFY) - mci_loadW->dwCallback = mci_loadA->dwCallback; - mci_loadW->lpfilename = MCI_strdupAtoW(mci_loadA->lpfilename); - return 1; - } - - case MCI_ESCAPE: - { - MCI_VD_ESCAPE_PARMSA *mci_vd_escapeA = (MCI_VD_ESCAPE_PARMSA *)*dwParam2; - MCI_VD_ESCAPE_PARMSW *mci_vd_escapeW; - - mci_vd_escapeW = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_vd_escapeW)); - if (!mci_vd_escapeW) return -1; - - *dwParam2 = (DWORD_PTR)mci_vd_escapeW; - if (dwParam1 & MCI_NOTIFY) - mci_vd_escapeW->dwCallback = mci_vd_escapeA->dwCallback; - mci_vd_escapeW->lpstrCommand = MCI_strdupAtoW(mci_vd_escapeA->lpstrCommand); - return 1; - } - default: - FIXME("Message %s needs translation\n", MCI_MessageToString(msg)); - return -1; - } -} - -static DWORD MCI_UnmapMsgAtoW(UINT msg, DWORD_PTR dwParam1, DWORD_PTR dwParam2, - DWORD result) -{ - switch (msg) - { - case MCI_OPEN: - { - DWORD_PTR *ptr = (DWORD_PTR *)dwParam2 - 1; - MCI_OPEN_PARMSA *mci_openA = (MCI_OPEN_PARMSA *)*ptr; - MCI_OPEN_PARMSW *mci_openW = (MCI_OPEN_PARMSW *)(ptr + 1); - - mci_openA->wDeviceID = mci_openW->wDeviceID; - - if (dwParam1 & MCI_OPEN_TYPE) - { - if (!(dwParam1 & MCI_OPEN_TYPE_ID)) - HeapFree(GetProcessHeap(), 0, (PVOID)mci_openW->lpstrDeviceType); - } - if (dwParam1 & MCI_OPEN_ELEMENT) - { - if (!(dwParam1 & MCI_OPEN_ELEMENT_ID)) - HeapFree(GetProcessHeap(), 0, (PVOID)mci_openW->lpstrElementName); - } - if (dwParam1 & MCI_OPEN_ALIAS) - HeapFree(GetProcessHeap(), 0, (PVOID)mci_openW->lpstrAlias); - HeapFree(GetProcessHeap(), 0, ptr); - } - break; - case MCI_WINDOW: - if (dwParam1 & MCI_ANIM_WINDOW_TEXT) - { - MCI_ANIM_WINDOW_PARMSW *mci_windowW = (MCI_ANIM_WINDOW_PARMSW *)dwParam2; - - HeapFree(GetProcessHeap(), 0, (void*)mci_windowW->lpstrText); - HeapFree(GetProcessHeap(), 0, mci_windowW); - } - break; - - case MCI_SYSINFO: - { - DWORD_PTR *ptr = (DWORD_PTR *)dwParam2 - 1; - MCI_SYSINFO_PARMSA *mci_sysinfoA = (MCI_SYSINFO_PARMSA *)*ptr; - MCI_SYSINFO_PARMSW *mci_sysinfoW = (MCI_SYSINFO_PARMSW *)(ptr + 1); - - if (!result) - { - mci_sysinfoA->dwNumber = mci_sysinfoW->dwNumber; - mci_sysinfoA->wDeviceType = mci_sysinfoW->wDeviceType; - if (dwParam1 & MCI_SYSINFO_QUANTITY) - *(DWORD*)mci_sysinfoA->lpstrReturn = *(DWORD*)mci_sysinfoW->lpstrReturn; - else - WideCharToMultiByte(CP_ACP, 0, - mci_sysinfoW->lpstrReturn, mci_sysinfoW->dwRetSize, - mci_sysinfoA->lpstrReturn, mci_sysinfoA->dwRetSize, - NULL, NULL); - } - - HeapFree(GetProcessHeap(), 0, mci_sysinfoW->lpstrReturn); - HeapFree(GetProcessHeap(), 0, ptr); - } - break; - case MCI_INFO: - { - DWORD_PTR *ptr = (DWORD_PTR *)dwParam2 - 1; - MCI_INFO_PARMSA *mci_infoA = (MCI_INFO_PARMSA *)*ptr; - MCI_INFO_PARMSW *mci_infoW = (MCI_INFO_PARMSW *)(ptr + 1); - - if (!result) - { - WideCharToMultiByte(CP_ACP, 0, - mci_infoW->lpstrReturn, mci_infoW->dwRetSize / sizeof(WCHAR), - mci_infoA->lpstrReturn, mci_infoA->dwRetSize, - NULL, NULL); - } - - HeapFree(GetProcessHeap(), 0, mci_infoW->lpstrReturn); - HeapFree(GetProcessHeap(), 0, ptr); - } - break; - case MCI_SAVE: - { - MCI_SAVE_PARMSW *mci_saveW = (MCI_SAVE_PARMSW *)dwParam2; - - HeapFree(GetProcessHeap(), 0, (void*)mci_saveW->lpfilename); - HeapFree(GetProcessHeap(), 0, mci_saveW); - } - break; - case MCI_LOAD: - { - MCI_LOAD_PARMSW *mci_loadW = (MCI_LOAD_PARMSW *)dwParam2; - - HeapFree(GetProcessHeap(), 0, (void*)mci_loadW->lpfilename); - HeapFree(GetProcessHeap(), 0, mci_loadW); - } - break; - case MCI_ESCAPE: - { - MCI_VD_ESCAPE_PARMSW *mci_vd_escapeW = (MCI_VD_ESCAPE_PARMSW *)dwParam2; - - HeapFree(GetProcessHeap(), 0, (void*)mci_vd_escapeW->lpstrCommand); - HeapFree(GetProcessHeap(), 0, mci_vd_escapeW); - } - break; - - default: - FIXME("Message %s needs unmapping\n", MCI_MessageToString(msg)); - break; - } - - return result; -} - -/************************************************************************** - * MCI_GetDevTypeFromFileName [internal] - */ -static DWORD MCI_GetDevTypeFromFileName(LPCWSTR fileName, LPCWSTR buf, UINT len) -{ - LPCWSTR tmp; - HKEY hKey; - static const WCHAR keyW[] = {'S','O','F','T','W','A','R','E','\\','M','i','c','r','o','s','o','f','t','\\', - 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', - 'M','C','I',' ','E','x','t','e','n','s','i','o','n','s',0}; - if ((tmp = strrchrW(fileName, '.'))) { - if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, keyW, - 0, KEY_QUERY_VALUE, &hKey ) == ERROR_SUCCESS) { - DWORD dwLen = len; - LONG lRet = RegQueryValueExW( hKey, tmp + 1, 0, 0, (void*)buf, &dwLen ); - RegCloseKey( hKey ); - if (lRet == ERROR_SUCCESS) return 0; - } - TRACE("No ...\\MCI Extensions entry for %s found.\n", debugstr_w(tmp)); - } - return MCIERR_EXTENSION_NOT_FOUND; -} - -#define MAX_MCICMDTABLE 20 -#define MCI_COMMAND_TABLE_NOT_LOADED 0xFFFE - -typedef struct tagWINE_MCICMDTABLE { - UINT uDevType; - const BYTE* lpTable; - UINT nVerbs; /* number of verbs in command table */ - LPCWSTR* aVerbs; /* array of verbs to speed up the verb look up process */ -} WINE_MCICMDTABLE, *LPWINE_MCICMDTABLE; - -static WINE_MCICMDTABLE S_MciCmdTable[MAX_MCICMDTABLE]; - -/************************************************************************** - * MCI_IsCommandTableValid [internal] - */ -static BOOL MCI_IsCommandTableValid(UINT uTbl) -{ - const BYTE* lmem; - LPCWSTR str; - DWORD flg; - WORD eid; - int idx = 0; - BOOL inCst = FALSE; - - TRACE("Dumping cmdTbl=%d [lpTable=%p devType=%d]\n", - uTbl, S_MciCmdTable[uTbl].lpTable, S_MciCmdTable[uTbl].uDevType); - - if (uTbl >= MAX_MCICMDTABLE || !S_MciCmdTable[uTbl].lpTable) - return FALSE; - - lmem = S_MciCmdTable[uTbl].lpTable; - do { - str = (LPCWSTR)lmem; - lmem += (strlenW(str) + 1) * sizeof(WCHAR); - flg = *(const DWORD*)lmem; - eid = *(const WORD*)(lmem + sizeof(DWORD)); - lmem += sizeof(DWORD) + sizeof(WORD); - idx ++; - /* TRACE("cmd=%s %08lx %04x\n", debugstr_w(str), flg, eid); */ - switch (eid) { - case MCI_COMMAND_HEAD: if (!*str || !flg) return FALSE; idx = 0; break; /* check unicity of str in table */ - case MCI_STRING: if (inCst) return FALSE; break; - case MCI_INTEGER: if (!*str) return FALSE; break; - case MCI_END_COMMAND: if (*str || flg || idx == 0) return FALSE; idx = 0; break; - case MCI_RETURN: if (*str || idx != 1) return FALSE; break; - case MCI_FLAG: if (!*str) return FALSE; break; - case MCI_END_COMMAND_LIST: if (*str || flg) return FALSE; idx = 0; break; - case MCI_RECT: if (!*str || inCst) return FALSE; break; - case MCI_CONSTANT: if (inCst) return FALSE; inCst = TRUE; break; - case MCI_END_CONSTANT: if (*str || flg || !inCst) return FALSE; inCst = FALSE; break; - default: return FALSE; - } - } while (eid != MCI_END_COMMAND_LIST); - return TRUE; -} - -/************************************************************************** - * MCI_DumpCommandTable [internal] - */ -static BOOL MCI_DumpCommandTable(UINT uTbl) -{ - const BYTE* lmem; - LPCWSTR str; - DWORD flg; - WORD eid; - - if (!MCI_IsCommandTableValid(uTbl)) { - ERR("Ooops: %d is not valid\n", uTbl); - return FALSE; - } - - lmem = S_MciCmdTable[uTbl].lpTable; - do { - do { - str = (LPCWSTR)lmem; - lmem += (strlenW(str) + 1) * sizeof(WCHAR); - flg = *(const DWORD*)lmem; - eid = *(const WORD*)(lmem + sizeof(DWORD)); - /* TRACE("cmd=%s %08lx %04x\n", debugstr_w(str), flg, eid); */ - lmem += sizeof(DWORD) + sizeof(WORD); - } while (eid != MCI_END_COMMAND && eid != MCI_END_COMMAND_LIST); - /* EPP TRACE(" => end of command%s\n", (eid == MCI_END_COMMAND_LIST) ? " list" : ""); */ - } while (eid != MCI_END_COMMAND_LIST); - return TRUE; -} - - -/************************************************************************** - * MCI_GetCommandTable [internal] - */ -static UINT MCI_GetCommandTable(UINT uDevType) -{ - UINT uTbl; - WCHAR buf[32]; - LPCWSTR str = NULL; - - /* first look up existing for existing devType */ - for (uTbl = 0; uTbl < MAX_MCICMDTABLE; uTbl++) { - if (S_MciCmdTable[uTbl].lpTable && S_MciCmdTable[uTbl].uDevType == uDevType) - return uTbl; - } - - /* well try to load id */ - if (uDevType >= MCI_DEVTYPE_FIRST && uDevType <= MCI_DEVTYPE_LAST) { - if (LoadStringW(WINMM_IData.hWinMM32Instance, uDevType, buf, sizeof(buf) / sizeof(WCHAR))) { - str = buf; - } - } else if (uDevType == 0) { - static const WCHAR wszCore[] = {'C','O','R','E',0}; - str = wszCore; - } - uTbl = MCI_NO_COMMAND_TABLE; - if (str) { - HRSRC hRsrc = FindResourceW(WINMM_IData.hWinMM32Instance, str, (LPCWSTR)RT_RCDATA); - HANDLE hMem = 0; - - if (hRsrc) hMem = LoadResource(WINMM_IData.hWinMM32Instance, hRsrc); - if (hMem) { - uTbl = MCI_SetCommandTable(LockResource(hMem), uDevType); - } else { - WARN("No command table found in resource %p[%s]\n", - WINMM_IData.hWinMM32Instance, debugstr_w(str)); - } - } - TRACE("=> %d\n", uTbl); - return uTbl; -} - -/************************************************************************** - * MCI_SetCommandTable [internal] - */ -UINT MCI_SetCommandTable(void *table, UINT uDevType) -{ - int uTbl; - static BOOL bInitDone = FALSE; - - /* <HACK> - * The CORE command table must be loaded first, so that MCI_GetCommandTable() - * can be called with 0 as a uDevType to retrieve it. - * </HACK> - */ - if (!bInitDone) { - bInitDone = TRUE; - MCI_GetCommandTable(0); - } - TRACE("(%p, %u)\n", table, uDevType); - for (uTbl = 0; uTbl < MAX_MCICMDTABLE; uTbl++) { - if (!S_MciCmdTable[uTbl].lpTable) { - const BYTE* lmem; - LPCWSTR str; - WORD eid; - WORD count; - - S_MciCmdTable[uTbl].uDevType = uDevType; - S_MciCmdTable[uTbl].lpTable = table; - - if (TRACE_ON(mci)) { - MCI_DumpCommandTable(uTbl); - } - - /* create the verbs table */ - /* get # of entries */ - lmem = S_MciCmdTable[uTbl].lpTable; - count = 0; - do { - str = (LPCWSTR)lmem; - lmem += (strlenW(str) + 1) * sizeof(WCHAR); - eid = *(const WORD*)(lmem + sizeof(DWORD)); - lmem += sizeof(DWORD) + sizeof(WORD); - if (eid == MCI_COMMAND_HEAD) - count++; - } while (eid != MCI_END_COMMAND_LIST); - - S_MciCmdTable[uTbl].aVerbs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(LPCWSTR)); - S_MciCmdTable[uTbl].nVerbs = count; - - lmem = S_MciCmdTable[uTbl].lpTable; - count = 0; - do { - str = (LPCWSTR)lmem; - lmem += (strlenW(str) + 1) * sizeof(WCHAR); - eid = *(const WORD*)(lmem + sizeof(DWORD)); - lmem += sizeof(DWORD) + sizeof(WORD); - if (eid == MCI_COMMAND_HEAD) - S_MciCmdTable[uTbl].aVerbs[count++] = str; - } while (eid != MCI_END_COMMAND_LIST); - /* assert(count == S_MciCmdTable[uTbl].nVerbs); */ - return uTbl; - } - } - - return MCI_NO_COMMAND_TABLE; -} - -/************************************************************************** - * MCI_DeleteCommandTable [internal] - */ -BOOL MCI_DeleteCommandTable(UINT uTbl, BOOL delete) -{ - if (uTbl >= MAX_MCICMDTABLE || !S_MciCmdTable[uTbl].lpTable) - return FALSE; - - if (delete) HeapFree(GetProcessHeap(), 0, (void*)S_MciCmdTable[uTbl].lpTable); - S_MciCmdTable[uTbl].lpTable = NULL; - HeapFree(GetProcessHeap(), 0, S_MciCmdTable[uTbl].aVerbs); - S_MciCmdTable[uTbl].aVerbs = 0; - return TRUE; -} - -/************************************************************************** - * MCI_UnLoadMciDriver [internal] - */ -static BOOL MCI_UnLoadMciDriver(LPWINE_MCIDRIVER wmd) -{ - LPWINE_MCIDRIVER* tmp; - - if (!wmd) - return TRUE; - - CloseDriver(wmd->hDriver, 0, 0); - - if (wmd->dwPrivate != 0) - WARN("Unloading mci driver with non nul dwPrivate field\n"); - - EnterCriticalSection(&WINMM_IData.cs); - for (tmp = &WINMM_IData.lpMciDrvs; *tmp; tmp = &(*tmp)->lpNext) { - if (*tmp == wmd) { - *tmp = wmd->lpNext; - break; - } - } - LeaveCriticalSection(&WINMM_IData.cs); - - HeapFree(GetProcessHeap(), 0, wmd->lpstrDeviceType); - HeapFree(GetProcessHeap(), 0, wmd->lpstrAlias); - HeapFree(GetProcessHeap(), 0, wmd->lpstrElementName); - - HeapFree(GetProcessHeap(), 0, wmd); - return TRUE; -} - -/************************************************************************** - * MCI_OpenMciDriver [internal] - */ -static BOOL MCI_OpenMciDriver(LPWINE_MCIDRIVER wmd, LPCWSTR drvTyp, LPARAM lp) -{ - WCHAR libName[128]; - - if (!DRIVER_GetLibName(drvTyp, wszMci, libName, sizeof(libName))) - return FALSE; - - wmd->bIs32 = 0xFFFF; - /* First load driver */ - if ((wmd->hDriver = (HDRVR)DRIVER_TryOpenDriver32(libName, lp))) { - wmd->bIs32 = TRUE; - } else if (WINMM_CheckForMMSystem() && pFnMciMapMsg32WTo16) { - WINMM_MapType res; - - switch (res = pFnMciMapMsg32WTo16(0, DRV_OPEN, 0, &lp)) { - case WINMM_MAP_MSGERROR: - TRACE("Not handled yet (DRV_OPEN)\n"); - break; - case WINMM_MAP_NOMEM: - TRACE("Problem mapping msg=DRV_OPEN from 32W to 16\n"); - break; - case WINMM_MAP_OK: - case WINMM_MAP_OKMEM: - if ((wmd->hDriver = OpenDriver(drvTyp, wszMci, lp))) - wmd->bIs32 = FALSE; - if (res == WINMM_MAP_OKMEM) - pFnMciUnMapMsg32WTo16(0, DRV_OPEN, 0, lp); - break; - } - } - return (wmd->bIs32 == 0xFFFF) ? FALSE : TRUE; -} - -/************************************************************************** - * MCI_LoadMciDriver [internal] - */ -static DWORD MCI_LoadMciDriver(LPCWSTR _strDevTyp, LPWINE_MCIDRIVER* lpwmd) -{ - LPWSTR strDevTyp = str_dup_upper(_strDevTyp); - LPWINE_MCIDRIVER wmd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wmd)); - MCI_OPEN_DRIVER_PARMSW modp; - DWORD dwRet = 0; - - if (!wmd || !strDevTyp) { - dwRet = MCIERR_OUT_OF_MEMORY; - goto errCleanUp; - } - - wmd->lpfnYieldProc = MCI_DefYieldProc; - wmd->dwYieldData = VK_CANCEL; - wmd->CreatorThread = GetCurrentThreadId(); - - EnterCriticalSection(&WINMM_IData.cs); - /* wmd must be inserted in list before sending opening the driver, coz' it - * may want to lookup at wDevID - */ - wmd->lpNext = WINMM_IData.lpMciDrvs; - WINMM_IData.lpMciDrvs = wmd; - - for (modp.wDeviceID = MCI_MAGIC; - MCI_GetDriver(modp.wDeviceID) != 0; - modp.wDeviceID++); - - wmd->wDeviceID = modp.wDeviceID; - - LeaveCriticalSection(&WINMM_IData.cs); - - TRACE("wDevID=%04X \n", modp.wDeviceID); - - modp.lpstrParams = NULL; - - if (!MCI_OpenMciDriver(wmd, strDevTyp, (LPARAM)&modp)) { - /* silence warning if all is used... some bogus program use commands like - * 'open all'... - */ - if (strcmpiW(strDevTyp, wszAll) == 0) { - dwRet = MCIERR_CANNOT_USE_ALL; - } else { - FIXME("Couldn't load driver for type %s.\n" - "If you don't have a windows installation accessible from Wine,\n" - "you perhaps forgot to create a [mci] section in system.ini\n", - debugstr_w(strDevTyp)); - dwRet = MCIERR_DEVICE_NOT_INSTALLED; - } - goto errCleanUp; - } - - /* FIXME: should also check that module's description is of the form - * MODULENAME:[MCI] comment - */ - - /* some drivers will return 0x0000FFFF, some others 0xFFFFFFFF */ - wmd->uSpecificCmdTable = LOWORD(modp.wCustomCommandTable); - wmd->uTypeCmdTable = MCI_COMMAND_TABLE_NOT_LOADED; - - TRACE("Loaded driver %p (%s), type is %d, cmdTable=%08x\n", - wmd->hDriver, debugstr_w(strDevTyp), modp.wType, modp.wCustomCommandTable); - - wmd->lpstrDeviceType = strDevTyp; - wmd->wType = modp.wType; - - TRACE("mcidev=%d, uDevTyp=%04X wDeviceID=%04X !\n", - modp.wDeviceID, modp.wType, modp.wDeviceID); - *lpwmd = wmd; - return 0; -errCleanUp: - MCI_UnLoadMciDriver(wmd); - HeapFree(GetProcessHeap(), 0, strDevTyp); - *lpwmd = 0; - return dwRet; -} - -/************************************************************************** - * MCI_FinishOpen [internal] - */ -static DWORD MCI_FinishOpen(LPWINE_MCIDRIVER wmd, LPMCI_OPEN_PARMSW lpParms, - DWORD dwParam) -{ - if (dwParam & MCI_OPEN_ELEMENT) - { - wmd->lpstrElementName = HeapAlloc(GetProcessHeap(),0,(strlenW(lpParms->lpstrElementName)+1) * sizeof(WCHAR)); - strcpyW( wmd->lpstrElementName, lpParms->lpstrElementName ); - } - if (dwParam & MCI_OPEN_ALIAS) - { - wmd->lpstrAlias = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpParms->lpstrAlias)+1) * sizeof(WCHAR)); - strcpyW( wmd->lpstrAlias, lpParms->lpstrAlias); - } - lpParms->wDeviceID = wmd->wDeviceID; - - return MCI_SendCommandFrom32(wmd->wDeviceID, MCI_OPEN_DRIVER, dwParam, - (DWORD)lpParms); -} - -/************************************************************************** - * MCI_FindCommand [internal] - */ -static LPCWSTR MCI_FindCommand(UINT uTbl, LPCWSTR verb) -{ - UINT idx; - - if (uTbl >= MAX_MCICMDTABLE || !S_MciCmdTable[uTbl].lpTable) - return NULL; - - /* another improvement would be to have the aVerbs array sorted, - * so that we could use a dichotomic search on it, rather than this dumb - * array look up - */ - for (idx = 0; idx < S_MciCmdTable[uTbl].nVerbs; idx++) { - if (strcmpiW(S_MciCmdTable[uTbl].aVerbs[idx], verb) == 0) - return S_MciCmdTable[uTbl].aVerbs[idx]; - } - - return NULL; -} - -/************************************************************************** - * MCI_GetReturnType [internal] - */ -static DWORD MCI_GetReturnType(LPCWSTR lpCmd) -{ - lpCmd = (LPCWSTR)((BYTE*)(lpCmd + strlenW(lpCmd) + 1) + sizeof(DWORD) + sizeof(WORD)); - if (*lpCmd == '\0' && *(const WORD*)((BYTE*)(lpCmd + 1) + sizeof(DWORD)) == MCI_RETURN) { - return *(const DWORD*)(lpCmd + 1); - } - return 0L; -} - -/************************************************************************** - * MCI_GetMessage [internal] - */ -static WORD MCI_GetMessage(LPCWSTR lpCmd) -{ - return (WORD)*(const DWORD*)(lpCmd + strlenW(lpCmd) + 1); -} - -/************************************************************************** - * MCI_GetDWord [internal] - */ -static BOOL MCI_GetDWord(LPDWORD data, LPWSTR* ptr) -{ - DWORD val; - LPWSTR ret; - - val = strtoulW(*ptr, &ret, 0); - - switch (*ret) { - case '\0': break; - case ' ': ret++; break; - default: return FALSE; - } - - *data |= val; - *ptr = ret; - return TRUE; -} - -/************************************************************************** - * MCI_GetString [internal] - */ -static DWORD MCI_GetString(LPWSTR* str, LPWSTR* args) -{ - LPWSTR ptr = *args; - - /* see if we have a quoted string */ - if (*ptr == '"') { - ptr = strchrW(*str = ptr + 1, '"'); - if (!ptr) return MCIERR_NO_CLOSING_QUOTE; - /* FIXME: shall we escape \" from string ?? */ - if (ptr[-1] == '\\') TRACE("Ooops: un-escaped \"\n"); - *ptr++ = '\0'; /* remove trailing " */ - if (*ptr != ' ' && *ptr != '\0') return MCIERR_EXTRA_CHARACTERS; - *ptr++ = '\0'; - } else { - ptr = strchrW(ptr, ' '); - - if (ptr) { - *ptr++ = '\0'; - } else { - ptr = *args + strlenW(*args); - } - *str = *args; - } - - *args = ptr; - return 0; -} - -#define MCI_DATA_SIZE 16 - -/************************************************************************** - * MCI_ParseOptArgs [internal] - */ -static DWORD MCI_ParseOptArgs(LPDWORD data, int _offset, LPCWSTR lpCmd, - LPWSTR args, LPDWORD dwFlags) -{ - int len, offset; - const char* lmem; - LPCWSTR str; - DWORD dwRet, flg, cflg = 0; - WORD eid; - BOOL inCst, found; - - /* loop on arguments */ - while (*args) { - lmem = (const char*)lpCmd; - found = inCst = FALSE; - offset = _offset; - - /* skip any leading white space(s) */ - while (*args == ' ') args++; - TRACE("args=%s offset=%d\n", debugstr_w(args), offset); - - do { /* loop on options for command table for the requested verb */ - str = (LPCWSTR)lmem; - lmem += ((len = strlenW(str)) + 1) * sizeof(WCHAR); - flg = *(const DWORD*)lmem; - eid = *(const WORD*)(lmem + sizeof(DWORD)); - lmem += sizeof(DWORD) + sizeof(WORD); - /* TRACE("\tcmd=%s inCst=%c eid=%04x\n", debugstr_w(str), inCst ? 'Y' : 'N', eid); */ - - switch (eid) { - case MCI_CONSTANT: - inCst = TRUE; cflg = flg; break; - case MCI_END_CONSTANT: - /* there may be additional integral values after flag in constant */ - if (inCst && MCI_GetDWord(&(data[offset]), &args)) { - *dwFlags |= cflg; - } - inCst = FALSE; cflg = 0; - break; - } - - if (strncmpiW(args, str, len) == 0 && - (args[len] == 0 || args[len] == ' ')) { - /* store good values into data[] */ - args += len; - while (*args == ' ') args++; - found = TRUE; - - switch (eid) { - case MCI_COMMAND_HEAD: - case MCI_RETURN: - case MCI_END_COMMAND: - case MCI_END_COMMAND_LIST: - case MCI_CONSTANT: /* done above */ - case MCI_END_CONSTANT: /* done above */ - break; - case MCI_FLAG: - *dwFlags |= flg; - break; - case MCI_INTEGER: - if (inCst) { - data[offset] |= flg; - *dwFlags |= cflg; - inCst = FALSE; - } else { - *dwFlags |= flg; - if (!MCI_GetDWord(&(data[offset]), &args)) { - return MCIERR_BAD_INTEGER; - } - } - break; - case MCI_RECT: - /* store rect in data (offset...offset+3) */ - *dwFlags |= flg; - if (!MCI_GetDWord(&(data[offset+0]), &args) || - !MCI_GetDWord(&(data[offset+1]), &args) || - !MCI_GetDWord(&(data[offset+2]), &args) || - !MCI_GetDWord(&(data[offset+3]), &args)) { - ERR("Bad rect %s\n", debugstr_w(args)); - return MCIERR_BAD_INTEGER; - } - break; - case MCI_STRING: - *dwFlags |= flg; - if ((dwRet = MCI_GetString((LPWSTR*)&data[offset], &args))) - return dwRet; - break; - default: ERR("oops\n"); - } - /* exit inside while loop, except if just entered in constant area definition */ - if (!inCst || eid != MCI_CONSTANT) eid = MCI_END_COMMAND; - } else { - /* have offset incremented if needed */ - switch (eid) { - case MCI_COMMAND_HEAD: - case MCI_RETURN: - case MCI_END_COMMAND: - case MCI_END_COMMAND_LIST: - case MCI_CONSTANT: - case MCI_FLAG: break; - case MCI_INTEGER: if (!inCst) offset++; break; - case MCI_END_CONSTANT: - case MCI_STRING: offset++; break; - case MCI_RECT: offset += 4; break; - default: ERR("oops\n"); - } - } - } while (eid != MCI_END_COMMAND); - if (!found) { - WARN("Optarg %s not found\n", debugstr_w(args)); - return MCIERR_UNRECOGNIZED_COMMAND; - } - if (offset == MCI_DATA_SIZE) { - ERR("Internal data[] buffer overflow\n"); - return MCIERR_PARSER_INTERNAL; - } - } - return 0; -} - -/************************************************************************** - * MCI_HandleReturnValues [internal] - */ -static DWORD MCI_HandleReturnValues(DWORD dwRet, LPWINE_MCIDRIVER wmd, DWORD retType, - LPDWORD data, LPWSTR lpstrRet, UINT uRetLen) -{ - static const WCHAR wszLd [] = {'%','l','d',0}; - static const WCHAR wszLd4 [] = {'%','l','d',' ','%','l','d',' ','%','l','d',' ','%','l','d',0}; - static const WCHAR wszCol3[] = {'%','d',':','%','d',':','%','d',0}; - static const WCHAR wszCol4[] = {'%','d',':','%','d',':','%','d',':','%','d',0}; - - if (lpstrRet) { - switch (retType) { - case 0: /* nothing to return */ - break; - case MCI_INTEGER: - switch (dwRet & 0xFFFF0000ul) { - case 0: - case MCI_INTEGER_RETURNED: - snprintfW(lpstrRet, uRetLen, wszLd, data[1]); - break; - case MCI_RESOURCE_RETURNED: - /* return string which ID is HIWORD(data[1]), - * string is loaded from mmsystem.dll */ - LoadStringW(WINMM_IData.hWinMM32Instance, HIWORD(data[1]), - lpstrRet, uRetLen); - break; - case MCI_RESOURCE_RETURNED|MCI_RESOURCE_DRIVER: - /* return string which ID is HIWORD(data[1]), - * string is loaded from driver */ - /* FIXME: this is wrong for a 16 bit handle */ - LoadStringW(GetDriverModuleHandle(wmd->hDriver), - HIWORD(data[1]), lpstrRet, uRetLen); - break; - case MCI_COLONIZED3_RETURN: - snprintfW(lpstrRet, uRetLen, wszCol3, - LOBYTE(LOWORD(data[1])), HIBYTE(LOWORD(data[1])), - LOBYTE(HIWORD(data[1]))); - break; - case MCI_COLONIZED4_RETURN: - snprintfW(lpstrRet, uRetLen, wszCol4, - LOBYTE(LOWORD(data[1])), HIBYTE(LOWORD(data[1])), - LOBYTE(HIWORD(data[1])), HIBYTE(HIWORD(data[1]))); - break; - default: ERR("Ooops (%04X)\n", HIWORD(dwRet)); - } - break; - case MCI_STRING: - switch (dwRet & 0xFFFF0000ul) { - case 0: - /* nothing to do data[1] == lpstrRet */ - break; - case MCI_INTEGER_RETURNED: - data[1] = *(LPDWORD)lpstrRet; - snprintfW(lpstrRet, uRetLen, wszLd, data[1]); - break; - default: - WARN("Oooch. MCI_STRING and HIWORD(dwRet)=%04x\n", HIWORD(dwRet)); - break; - } - break; - case MCI_RECT: - if (dwRet & 0xFFFF0000ul) - WARN("Oooch. MCI_STRING and HIWORD(dwRet)=%04x\n", HIWORD(dwRet)); - snprintfW(lpstrRet, uRetLen, wszLd4, - data[1], data[2], data[3], data[4]); - break; - default: ERR("oops\n"); - } - } - return LOWORD(dwRet); -} - -/************************************************************************** - * mciSendStringW [WINMM.@] - */ -DWORD WINAPI mciSendStringW(LPCWSTR lpstrCommand, LPWSTR lpstrRet, - UINT uRetLen, HWND hwndCallback) -{ - LPWSTR verb, dev, args; - LPWINE_MCIDRIVER wmd = 0; - DWORD dwFlags = 0, dwRet = 0; - int offset = 0; - DWORD data[MCI_DATA_SIZE]; - DWORD retType; - LPCWSTR lpCmd = 0; - LPWSTR devAlias = NULL; - BOOL bAutoOpen = FALSE; - static const WCHAR wszNew[] = {'n','e','w',0}; - static const WCHAR wszSAliasS[] = {' ','a','l','i','a','s',' ',0}; - - TRACE("(%s, %p, %d, %p)\n", - debugstr_w(lpstrCommand), lpstrRet, uRetLen, hwndCallback); - - /* format is <command> <device> <optargs> */ - if (!(verb = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpstrCommand)+1) * sizeof(WCHAR)))) - return MCIERR_OUT_OF_MEMORY; - strcpyW( verb, lpstrCommand ); - CharLowerW(verb); - - memset(data, 0, sizeof(data)); - - if (!(args = strchrW(verb, ' '))) { - dwRet = MCIERR_MISSING_DEVICE_NAME; - goto errCleanUp; - } - *args++ = '\0'; - if ((dwRet = MCI_GetString(&dev, &args))) { - goto errCleanUp; - } - - /* case dev == 'new' has to be handled */ - if (!strcmpW(dev, wszNew)) { - FIXME("'new': NIY as device name\n"); - dwRet = MCIERR_MISSING_DEVICE_NAME; - goto errCleanUp; - } - - /* otherwise, try to grab devType from open */ - if (!strcmpW(verb, wszOpen)) { - LPWSTR devType, tmp; - - if ((devType = strchrW(dev, '!')) != NULL) { - *devType++ = '\0'; - tmp = devType; devType = dev; dev = tmp; - - dwFlags |= MCI_OPEN_TYPE; - data[2] = (DWORD)devType; - devType = str_dup_upper(devType); - dwFlags |= MCI_OPEN_ELEMENT; - data[3] = (DWORD)dev; - } else if (strchrW(dev, '.') == NULL) { - tmp = strchrW(dev,' '); - if (tmp) *tmp = '\0'; - data[2] = (DWORD)dev; - devType = str_dup_upper(dev); - if (tmp) *tmp = ' '; - dwFlags |= MCI_OPEN_TYPE; - } else { - static const WCHAR wszTypeS[] = {'t','y','p','e',' ',0}; - if ((devType = strstrW(args, wszTypeS)) != NULL) { - devType += 5; - tmp = strchrW(devType, ' '); - if (tmp) *tmp = '\0'; - devType = str_dup_upper(devType); - if (tmp) *tmp = ' '; - /* dwFlags and data[2] will be correctly set in ParseOpt loop */ - } else { - WCHAR buf[32]; - if ((dwRet = MCI_GetDevTypeFromFileName(dev, buf, sizeof(buf)))) - goto errCleanUp; - - devType = str_dup_upper(buf); - } - dwFlags |= MCI_OPEN_ELEMENT; - data[3] = (DWORD)dev; - } - if ((devAlias = strstrW(args, wszSAliasS))) { - WCHAR* tmp2; - devAlias += 7; - if (!(tmp = strchrW(devAlias,' '))) tmp = devAlias + strlenW(devAlias); - if (tmp) *tmp = '\0'; - tmp2 = HeapAlloc(GetProcessHeap(), 0, (tmp - devAlias + 1) * sizeof(WCHAR) ); - memcpy( tmp2, devAlias, (tmp - devAlias) * sizeof(WCHAR) ); - tmp2[tmp - devAlias] = 0; - data[4] = (DWORD)tmp2; - /* should be done in regular options parsing */ - /* dwFlags |= MCI_OPEN_ALIAS; */ - } - - dwRet = MCI_LoadMciDriver(devType, &wmd); - if (dwRet == MCIERR_DEVICE_NOT_INSTALLED) - dwRet = MCIERR_INVALID_DEVICE_NAME; - HeapFree(GetProcessHeap(), 0, devType); - if (dwRet) { - MCI_UnLoadMciDriver(wmd); - goto errCleanUp; - } - } else if (!(wmd = MCI_GetDriver(mciGetDeviceIDW(dev)))) { - /* auto open */ - static WCHAR wszOpenWait[] = {'o','p','e','n',' ','%','s',' ','w','a','i','t',0}; - WCHAR buf[128]; - sprintfW(buf, wszOpenWait, dev); - - if ((dwRet = mciSendStringW(buf, NULL, 0, 0)) != 0) - goto errCleanUp; - - wmd = MCI_GetDriver(mciGetDeviceIDW(dev)); - if (!wmd) { - /* FIXME: memory leak, MCI driver is not closed */ - dwRet = MCIERR_INVALID_DEVICE_ID; - goto errCleanUp; - } - } - - /* get the verb in the different command tables */ - if (wmd) { - /* try the device specific command table */ - lpCmd = MCI_FindCommand(wmd->uSpecificCmdTable, verb); - if (!lpCmd) { - /* try the type specific command table */ - if (wmd->uTypeCmdTable == MCI_COMMAND_TABLE_NOT_LOADED) - wmd->uTypeCmdTable = MCI_GetCommandTable(wmd->wType); - if (wmd->uTypeCmdTable != MCI_NO_COMMAND_TABLE) - lpCmd = MCI_FindCommand(wmd->uTypeCmdTable, verb); - } - } - /* try core command table */ - if (!lpCmd) lpCmd = MCI_FindCommand(MCI_GetCommandTable(0), verb); - - if (!lpCmd) { - TRACE("Command %s not found!\n", debugstr_w(verb)); - dwRet = MCIERR_UNRECOGNIZED_COMMAND; - goto errCleanUp; - } - - /* set up call back */ - if (hwndCallback != 0) { - dwFlags |= MCI_NOTIFY; - data[0] = (DWORD)hwndCallback; - } - - /* set return information */ - switch (retType = MCI_GetReturnType(lpCmd)) { - case 0: offset = 1; break; - case MCI_INTEGER: offset = 2; break; - case MCI_STRING: data[1] = (DWORD)lpstrRet; data[2] = uRetLen; offset = 3; break; - case MCI_RECT: offset = 5; break; - default: ERR("oops\n"); - } - - TRACE("verb=%s on dev=%s; offset=%d\n", - debugstr_w(verb), debugstr_w(dev), offset); - - if ((dwRet = MCI_ParseOptArgs(data, offset, lpCmd, args, &dwFlags))) - goto errCleanUp; - - if (bAutoOpen && (dwFlags & MCI_NOTIFY)) { - dwRet = MCIERR_NOTIFY_ON_AUTO_OPEN; - goto errCleanUp; - } - /* FIXME: the command should get it's own notification window set up and - * ask for device closing while processing the notification mechanism - */ - if (lpstrRet && uRetLen) *lpstrRet = '\0'; - - TRACE("[%d, %s, %08lx, %08lx/%s %08lx/%s %08lx/%s %08lx/%s %08lx/%s %08lx/%s]\n", - wmd->wDeviceID, MCI_MessageToString(MCI_GetMessage(lpCmd)), dwFlags, - data[0], debugstr_w((WCHAR *)data[0]), data[1], debugstr_w((WCHAR *)data[1]), - data[2], debugstr_w((WCHAR *)data[2]), data[3], debugstr_w((WCHAR *)data[3]), - data[4], debugstr_w((WCHAR *)data[4]), data[5], debugstr_w((WCHAR *)data[5])); - - if (strcmpW(verb, wszOpen) == 0) { - if ((dwRet = MCI_FinishOpen(wmd, (LPMCI_OPEN_PARMSW)data, dwFlags))) - MCI_UnLoadMciDriver(wmd); - /* FIXME: notification is not properly shared across two opens */ - } else { - dwRet = MCI_SendCommand(wmd->wDeviceID, MCI_GetMessage(lpCmd), dwFlags, (DWORD)data, TRUE); - } - TRACE("=> 1/ %lx (%s)\n", dwRet, debugstr_w(lpstrRet)); - dwRet = MCI_HandleReturnValues(dwRet, wmd, retType, data, lpstrRet, uRetLen); - TRACE("=> 2/ %lx (%s)\n", dwRet, debugstr_w(lpstrRet)); - -errCleanUp: - HeapFree(GetProcessHeap(), 0, verb); - HeapFree(GetProcessHeap(), 0, devAlias); - return dwRet; -} - -/************************************************************************** - * mciSendStringA [WINMM.@] - */ -DWORD WINAPI mciSendStringA(LPCSTR lpstrCommand, LPSTR lpstrRet, - UINT uRetLen, HWND hwndCallback) -{ - LPWSTR lpwstrCommand; - LPWSTR lpwstrRet = NULL; - UINT ret; - INT len; - - /* FIXME: is there something to do with lpstrReturnString ? */ - len = MultiByteToWideChar( CP_ACP, 0, lpstrCommand, -1, NULL, 0 ); - lpwstrCommand = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, lpstrCommand, -1, lpwstrCommand, len ); - if (lpstrRet) - { - lpwstrRet = HeapAlloc(GetProcessHeap(), 0, uRetLen * sizeof(WCHAR)); - if (!lpwstrRet) { - WARN("no memory\n"); - HeapFree( GetProcessHeap(), 0, lpwstrCommand ); - return MCIERR_OUT_OF_MEMORY; - } - } - ret = mciSendStringW(lpwstrCommand, lpwstrRet, uRetLen, hwndCallback); - if (lpwstrRet) - WideCharToMultiByte( CP_ACP, 0, lpwstrRet, -1, lpstrRet, uRetLen, NULL, NULL ); - HeapFree(GetProcessHeap(), 0, lpwstrCommand); - HeapFree(GetProcessHeap(), 0, lpwstrRet); - return ret; -} - -/************************************************************************** - * mciExecute [WINMM.@] - * mciExecute [MMSYSTEM.712] - */ -BOOL WINAPI mciExecute(LPCSTR lpstrCommand) -{ - char strRet[256]; - DWORD ret; - - TRACE("(%s)!\n", lpstrCommand); - - ret = mciSendStringA(lpstrCommand, strRet, sizeof(strRet), 0); - if (ret != 0) { - if (!mciGetErrorStringA(ret, strRet, sizeof(strRet))) { - sprintf(strRet, "Unknown MCI error (%ld)", ret); - } - MessageBoxA(0, strRet, "Error in mciExecute()", MB_OK); - } - /* FIXME: what shall I return ? */ - return TRUE; -} - -/************************************************************************** - * mciLoadCommandResource [WINMM.@] - * - * Strangely, this function only exists as an UNICODE one. - */ -UINT WINAPI mciLoadCommandResource(HINSTANCE hInst, LPCWSTR resNameW, UINT type) -{ - HRSRC hRsrc = 0; - HGLOBAL hMem; - UINT16 ret = MCI_NO_COMMAND_TABLE; - - TRACE("(%p, %s, %d)!\n", hInst, debugstr_w(resNameW), type); - - /* if a file named "resname.mci" exits, then load resource "resname" from it - * otherwise directly from driver - * We don't support it (who uses this feature ?), but we check anyway - */ - if (!type) { -#if 0 - /* FIXME: we should put this back into order, but I never found a program - * actually using this feature, so we may not need it - */ - char buf[128]; - OFSTRUCT ofs; - - strcat(strcpy(buf, resname), ".mci"); - if (OpenFile(buf, &ofs, OF_EXIST) != HFILE_ERROR) { - FIXME("NIY: command table to be loaded from '%s'\n", ofs.szPathName); - } -#endif - } - if (!(hRsrc = FindResourceW(hInst, resNameW, (LPWSTR)RT_RCDATA))) { - WARN("No command table found in resource\n"); - } else if ((hMem = LoadResource(hInst, hRsrc))) { - ret = MCI_SetCommandTable(LockResource(hMem), type); - } else { - WARN("Couldn't load resource.\n"); - } - TRACE("=> %04x\n", ret); - return ret; -} - -/************************************************************************** - * mciFreeCommandResource [WINMM.@] - */ -BOOL WINAPI mciFreeCommandResource(UINT uTable) -{ - TRACE("(%08x)!\n", uTable); - - return MCI_DeleteCommandTable(uTable, FALSE); -} - -/************************************************************************** - * MCI_SendCommandFrom32 [internal] - */ -DWORD MCI_SendCommandFrom32(MCIDEVICEID wDevID, UINT16 wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2) -{ - DWORD dwRet = MCIERR_INVALID_DEVICE_ID; - LPWINE_MCIDRIVER wmd = MCI_GetDriver(wDevID); - - if (wmd) { - if (wmd->bIs32) { - dwRet = SendDriverMessage(wmd->hDriver, wMsg, dwParam1, dwParam2); - } else if (pFnMciMapMsg32WTo16) { - WINMM_MapType res; - - switch (res = pFnMciMapMsg32WTo16(wmd->wType, wMsg, dwParam1, &dwParam2)) { - case WINMM_MAP_MSGERROR: - TRACE("Not handled yet (%s)\n", MCI_MessageToString(wMsg)); - dwRet = MCIERR_DRIVER_INTERNAL; - break; - case WINMM_MAP_NOMEM: - TRACE("Problem mapping msg=%s from 32a to 16\n", MCI_MessageToString(wMsg)); - dwRet = MCIERR_OUT_OF_MEMORY; - break; - case WINMM_MAP_OK: - case WINMM_MAP_OKMEM: - dwRet = SendDriverMessage(wmd->hDriver, wMsg, dwParam1, dwParam2); - if (res == WINMM_MAP_OKMEM) - pFnMciUnMapMsg32WTo16(wmd->wType, wMsg, dwParam1, dwParam2); - break; - } - } - } - return dwRet; -} - -/************************************************************************** - * MCI_SendCommandFrom16 [internal] - */ -DWORD MCI_SendCommandFrom16(MCIDEVICEID wDevID, UINT16 wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2) -{ - DWORD dwRet = MCIERR_INVALID_DEVICE_ID; - LPWINE_MCIDRIVER wmd = MCI_GetDriver(wDevID); - - if (wmd) { - dwRet = MCIERR_INVALID_DEVICE_ID; - - if (wmd->bIs32 && pFnMciMapMsg16To32W) { - WINMM_MapType res; - - switch (res = pFnMciMapMsg16To32W(wmd->wType, wMsg, &dwParam2)) { - case WINMM_MAP_MSGERROR: - TRACE("Not handled yet (%s)\n", MCI_MessageToString(wMsg)); - dwRet = MCIERR_DRIVER_INTERNAL; - break; - case WINMM_MAP_NOMEM: - TRACE("Problem mapping msg=%s from 16 to 32a\n", MCI_MessageToString(wMsg)); - dwRet = MCIERR_OUT_OF_MEMORY; - break; - case WINMM_MAP_OK: - case WINMM_MAP_OKMEM: - dwRet = SendDriverMessage(wmd->hDriver, wMsg, dwParam1, dwParam2); - if (res == WINMM_MAP_OKMEM) - pFnMciUnMapMsg16To32W(wmd->wType, wMsg, dwParam2); - break; - } - } else { - dwRet = SendDriverMessage(wmd->hDriver, wMsg, dwParam1, dwParam2); - } - } - return dwRet; -} - -/************************************************************************** - * MCI_Open [internal] - */ -static DWORD MCI_Open(DWORD dwParam, LPMCI_OPEN_PARMSW lpParms) -{ - WCHAR strDevTyp[128]; - DWORD dwRet; - LPWINE_MCIDRIVER wmd = NULL; - - TRACE("(%08lX, %p)\n", dwParam, lpParms); - if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK; - - /* only two low bytes are generic, the other ones are dev type specific */ -#define WINE_MCIDRIVER_SUPP (0xFFFF0000|MCI_OPEN_SHAREABLE|MCI_OPEN_ELEMENT| \ - MCI_OPEN_ALIAS|MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID| \ - MCI_NOTIFY|MCI_WAIT) - if ((dwParam & ~WINE_MCIDRIVER_SUPP) != 0) { - FIXME("Unsupported yet dwFlags=%08lX\n", dwParam & ~WINE_MCIDRIVER_SUPP); - } -#undef WINE_MCIDRIVER_SUPP - - strDevTyp[0] = 0; - - if (dwParam & MCI_OPEN_TYPE) { - if (dwParam & MCI_OPEN_TYPE_ID) { - WORD uDevType = LOWORD((DWORD)lpParms->lpstrDeviceType); - - if (uDevType < MCI_DEVTYPE_FIRST || - uDevType > MCI_DEVTYPE_LAST || - !LoadStringW(WINMM_IData.hWinMM32Instance, uDevType, - strDevTyp, sizeof(strDevTyp) / sizeof(WCHAR))) { - dwRet = MCIERR_BAD_INTEGER; - goto errCleanUp; - } - } else { - LPWSTR ptr; - if (lpParms->lpstrDeviceType == NULL) { - dwRet = MCIERR_NULL_PARAMETER_BLOCK; - goto errCleanUp; - } - strcpyW(strDevTyp, lpParms->lpstrDeviceType); - ptr = strchrW(strDevTyp, '!'); - if (ptr) { - /* this behavior is not documented in windows. However, since, in - * some occasions, MCI_OPEN handling is translated by WinMM into - * a call to mciSendString("open <type>"); this code shall be correct - */ - if (dwParam & MCI_OPEN_ELEMENT) { - ERR("Both MCI_OPEN_ELEMENT(%s) and %s are used\n", - debugstr_w(lpParms->lpstrElementName), - debugstr_w(strDevTyp)); - dwRet = MCIERR_UNRECOGNIZED_KEYWORD; - goto errCleanUp; - } - dwParam |= MCI_OPEN_ELEMENT; - *ptr++ = 0; - /* FIXME: not a good idea to write in user supplied buffer */ - lpParms->lpstrElementName = ptr; - } - - } - TRACE("devType=%s !\n", debugstr_w(strDevTyp)); - } - - if (dwParam & MCI_OPEN_ELEMENT) { - TRACE("lpstrElementName=%s\n", debugstr_w(lpParms->lpstrElementName)); - - if (dwParam & MCI_OPEN_ELEMENT_ID) { - FIXME("Unsupported yet flag MCI_OPEN_ELEMENT_ID\n"); - dwRet = MCIERR_UNRECOGNIZED_KEYWORD; - goto errCleanUp; - } - - if (!lpParms->lpstrElementName) { - dwRet = MCIERR_NULL_PARAMETER_BLOCK; - goto errCleanUp; - } - - /* type, if given as a parameter, supersedes file extension */ - if (!strDevTyp[0] && - MCI_GetDevTypeFromFileName(lpParms->lpstrElementName, - strDevTyp, sizeof(strDevTyp))) { - static const WCHAR wszCdAudio[] = {'C','D','A','U','D','I','O',0}; - if (GetDriveTypeW(lpParms->lpstrElementName) != DRIVE_CDROM) { - dwRet = MCIERR_EXTENSION_NOT_FOUND; - goto errCleanUp; - } - /* FIXME: this will not work if several CDROM drives are installed on the machine */ - strcpyW(strDevTyp, wszCdAudio); - } - } - - if (strDevTyp[0] == 0) { - FIXME("Couldn't load driver\n"); - dwRet = MCIERR_INVALID_DEVICE_NAME; - goto errCleanUp; - } - - if (dwParam & MCI_OPEN_ALIAS) { - TRACE("Alias=%s !\n", debugstr_w(lpParms->lpstrAlias)); - if (!lpParms->lpstrAlias) { - dwRet = MCIERR_NULL_PARAMETER_BLOCK; - goto errCleanUp; - } - } - - if ((dwRet = MCI_LoadMciDriver(strDevTyp, &wmd))) { - goto errCleanUp; - } - - if ((dwRet = MCI_FinishOpen(wmd, lpParms, dwParam))) { - TRACE("Failed to open driver (MCI_OPEN_DRIVER) [%08lx], closing\n", dwRet); - /* FIXME: is dwRet the correct ret code ? */ - goto errCleanUp; - } - - /* only handled devices fall through */ - TRACE("wDevID=%04X wDeviceID=%d dwRet=%ld\n", wmd->wDeviceID, lpParms->wDeviceID, dwRet); - - if (dwParam & MCI_NOTIFY) - mciDriverNotify((HWND)lpParms->dwCallback, wmd->wDeviceID, MCI_NOTIFY_SUCCESSFUL); - - return 0; -errCleanUp: - if (wmd) MCI_UnLoadMciDriver(wmd); - - if (dwParam & MCI_NOTIFY) - mciDriverNotify((HWND)lpParms->dwCallback, 0, MCI_NOTIFY_FAILURE); - return dwRet; -} - -/************************************************************************** - * MCI_Close [internal] - */ -static DWORD MCI_Close(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms) -{ - DWORD dwRet; - LPWINE_MCIDRIVER wmd; - - TRACE("(%04x, %08lX, %p)\n", wDevID, dwParam, lpParms); - - if (wDevID == MCI_ALL_DEVICE_ID) { - LPWINE_MCIDRIVER next; - - EnterCriticalSection(&WINMM_IData.cs); - /* FIXME: shall I notify once after all is done, or for - * each of the open drivers ? if the latest, which notif - * to return when only one fails ? - */ - for (wmd = WINMM_IData.lpMciDrvs; wmd; ) { - next = wmd->lpNext; - MCI_Close(wmd->wDeviceID, dwParam, lpParms); - wmd = next; - } - LeaveCriticalSection(&WINMM_IData.cs); - return 0; - } - - if (!(wmd = MCI_GetDriver(wDevID))) { - return MCIERR_INVALID_DEVICE_ID; - } - - dwRet = MCI_SendCommandFrom32(wDevID, MCI_CLOSE_DRIVER, dwParam, (DWORD)lpParms); - - MCI_UnLoadMciDriver(wmd); - - if (dwParam & MCI_NOTIFY) - mciDriverNotify((HWND)lpParms->dwCallback, wDevID, - (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE); - - return dwRet; -} - -/************************************************************************** - * MCI_WriteString [internal] - */ -DWORD MCI_WriteString(LPWSTR lpDstStr, DWORD dstSize, LPCWSTR lpSrcStr) -{ - DWORD ret = 0; - - if (lpSrcStr) { - dstSize /= sizeof(WCHAR); - if (dstSize <= strlenW(lpSrcStr)) { - lstrcpynW(lpDstStr, lpSrcStr, dstSize - 1); - ret = MCIERR_PARAM_OVERFLOW; - } else { - strcpyW(lpDstStr, lpSrcStr); - } - } else { - *lpDstStr = 0; - } - return ret; -} - -/************************************************************************** - * MCI_Sysinfo [internal] - */ -static DWORD MCI_SysInfo(UINT uDevID, DWORD dwFlags, LPMCI_SYSINFO_PARMSW lpParms) -{ - DWORD ret = MCIERR_INVALID_DEVICE_ID, cnt = 0; - WCHAR buf[2048], *s = buf, *p; - LPWINE_MCIDRIVER wmd; - HKEY hKey; - - if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK; - - TRACE("(%08x, %08lX, %08lX[num=%ld, wDevTyp=%u])\n", - uDevID, dwFlags, (DWORD)lpParms, lpParms->dwNumber, lpParms->wDeviceType); - - switch (dwFlags & ~MCI_SYSINFO_OPEN) { - case MCI_SYSINFO_QUANTITY: - if (lpParms->wDeviceType < MCI_DEVTYPE_FIRST || lpParms->wDeviceType > MCI_DEVTYPE_LAST) { - if (dwFlags & MCI_SYSINFO_OPEN) { - TRACE("MCI_SYSINFO_QUANTITY: # of open MCI drivers\n"); - EnterCriticalSection(&WINMM_IData.cs); - for (wmd = WINMM_IData.lpMciDrvs; wmd; wmd = wmd->lpNext) { - cnt++; - } - LeaveCriticalSection(&WINMM_IData.cs); - } else { - TRACE("MCI_SYSINFO_QUANTITY: # of installed MCI drivers\n"); - if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, wszHklmMci, - 0, KEY_QUERY_VALUE, &hKey ) == ERROR_SUCCESS) { - RegQueryInfoKeyW( hKey, 0, 0, 0, &cnt, 0, 0, 0, 0, 0, 0, 0); - RegCloseKey( hKey ); - } - if (GetPrivateProfileStringW(wszMci, 0, wszNull, buf, sizeof(buf) / sizeof(buf[0]), wszSystemIni)) - for (s = buf; *s; s += strlenW(s) + 1) cnt++; - } - } else { - if (dwFlags & MCI_SYSINFO_OPEN) { - TRACE("MCI_SYSINFO_QUANTITY: # of open MCI drivers of type %u\n", lpParms->wDeviceType); - EnterCriticalSection(&WINMM_IData.cs); - for (wmd = WINMM_IData.lpMciDrvs; wmd; wmd = wmd->lpNext) { - if (wmd->wType == lpParms->wDeviceType) cnt++; - } - LeaveCriticalSection(&WINMM_IData.cs); - } else { - TRACE("MCI_SYSINFO_QUANTITY: # of installed MCI drivers of type %u\n", lpParms->wDeviceType); - FIXME("Don't know how to get # of MCI devices of a given type\n"); - cnt = 1; - } - } - *(DWORD*)lpParms->lpstrReturn = cnt; - TRACE("(%ld) => '%ld'\n", lpParms->dwNumber, *(DWORD*)lpParms->lpstrReturn); - ret = MCI_INTEGER_RETURNED; - break; - case MCI_SYSINFO_INSTALLNAME: - TRACE("MCI_SYSINFO_INSTALLNAME \n"); - if ((wmd = MCI_GetDriver(uDevID))) { - ret = MCI_WriteString(lpParms->lpstrReturn, lpParms->dwRetSize, - wmd->lpstrDeviceType); - } else { - *lpParms->lpstrReturn = 0; - ret = MCIERR_INVALID_DEVICE_ID; - } - TRACE("(%ld) => %s\n", lpParms->dwNumber, debugstr_w(lpParms->lpstrReturn)); - break; - case MCI_SYSINFO_NAME: - TRACE("MCI_SYSINFO_NAME\n"); - if (dwFlags & MCI_SYSINFO_OPEN) { - FIXME("Don't handle MCI_SYSINFO_NAME|MCI_SYSINFO_OPEN (yet)\n"); - ret = MCIERR_UNRECOGNIZED_COMMAND; - } else { - s = NULL; - if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, wszHklmMci, 0, - KEY_QUERY_VALUE, &hKey ) == ERROR_SUCCESS) { - if (RegQueryInfoKeyW( hKey, 0, 0, 0, &cnt, - 0, 0, 0, 0, 0, 0, 0) == ERROR_SUCCESS && - lpParms->dwNumber <= cnt) { - DWORD bufLen = sizeof(buf); - if (RegEnumKeyExW(hKey, lpParms->dwNumber - 1, - buf, &bufLen, 0, 0, 0, 0) == ERROR_SUCCESS) - s = buf; - } - RegCloseKey( hKey ); - } - if (!s) { - if (GetPrivateProfileStringW(wszMci, 0, wszNull, buf, sizeof(buf) / sizeof(buf[0]), wszSystemIni)) { - for (p = buf; *p; p += strlenW(p) + 1, cnt++) { - TRACE("%ld: %s\n", cnt, debugstr_w(p)); - if (cnt == lpParms->dwNumber - 1) { - s = p; - break; - } - } - } - } - ret = s ? MCI_WriteString(lpParms->lpstrReturn, lpParms->dwRetSize / sizeof(WCHAR), s) : MCIERR_OUTOFRANGE; - } - TRACE("(%ld) => %s\n", lpParms->dwNumber, debugstr_w(lpParms->lpstrReturn)); - break; - default: - TRACE("Unsupported flag value=%08lx\n", dwFlags); - ret = MCIERR_UNRECOGNIZED_COMMAND; - } - return ret; -} - -/************************************************************************** - * MCI_Break [internal] - */ -static DWORD MCI_Break(UINT wDevID, DWORD dwFlags, LPMCI_BREAK_PARMS lpParms) -{ - DWORD dwRet = 0; - - if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK; - - if (dwFlags & MCI_NOTIFY) - mciDriverNotify((HWND)lpParms->dwCallback, wDevID, - (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE); - - return dwRet; -} - -/************************************************************************** - * MCI_Sound [internal] - */ -static DWORD MCI_Sound(UINT wDevID, DWORD dwFlags, LPMCI_SOUND_PARMSW lpParms) -{ - DWORD dwRet = 0; - - if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK; - - if (dwFlags & MCI_SOUND_NAME) - dwRet = sndPlaySoundW(lpParms->lpstrSoundName, SND_SYNC) ? MMSYSERR_NOERROR : MMSYSERR_ERROR; - else - dwRet = MMSYSERR_ERROR; /* what should be done ??? */ - if (dwFlags & MCI_NOTIFY) - mciDriverNotify((HWND)lpParms->dwCallback, wDevID, - (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE); - - return dwRet; -} - -/************************************************************************** - * MCI_SendCommand [internal] - */ -DWORD MCI_SendCommand(UINT wDevID, UINT16 wMsg, DWORD dwParam1, - DWORD dwParam2, BOOL bFrom32) -{ - DWORD dwRet = MCIERR_UNRECOGNIZED_COMMAND; - - switch (wMsg) { - case MCI_OPEN: - if (bFrom32) { - dwRet = MCI_Open(dwParam1, (LPMCI_OPEN_PARMSW)dwParam2); - } else if (pFnMciMapMsg16To32W) { - switch (pFnMciMapMsg16To32W(0, wMsg, &dwParam2)) { - case WINMM_MAP_OK: - case WINMM_MAP_OKMEM: - dwRet = MCI_Open(dwParam1, (LPMCI_OPEN_PARMSW)dwParam2); - pFnMciUnMapMsg16To32W(0, wMsg, dwParam2); - break; - default: break; /* so that gcc does not bark */ - } - } - break; - case MCI_CLOSE: - if (bFrom32) { - dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2); - } else if (pFnMciMapMsg16To32W) { - switch (pFnMciMapMsg16To32W(0, wMsg, &dwParam2)) { - case WINMM_MAP_OK: - case WINMM_MAP_OKMEM: - dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2); - pFnMciUnMapMsg16To32W(0, wMsg, dwParam2); - break; - default: break; /* so that gcc does not bark */ - } - } - break; - case MCI_SYSINFO: - if (bFrom32) { - dwRet = MCI_SysInfo(wDevID, dwParam1, (LPMCI_SYSINFO_PARMSW)dwParam2); - } else if (pFnMciMapMsg16To32W) { - switch (pFnMciMapMsg16To32W(0, wMsg, &dwParam2)) { - case WINMM_MAP_OK: - case WINMM_MAP_OKMEM: - dwRet = MCI_SysInfo(wDevID, dwParam1, (LPMCI_SYSINFO_PARMSW)dwParam2); - pFnMciUnMapMsg16To32W(0, wMsg, dwParam2); - break; - default: break; /* so that gcc does not bark */ - } - } - break; - case MCI_BREAK: - if (bFrom32) { - dwRet = MCI_Break(wDevID, dwParam1, (LPMCI_BREAK_PARMS)dwParam2); - } else if (pFnMciMapMsg16To32W) { - switch (pFnMciMapMsg16To32W(0, wMsg, &dwParam2)) { - case WINMM_MAP_OK: - case WINMM_MAP_OKMEM: - dwRet = MCI_Break(wDevID, dwParam1, (LPMCI_BREAK_PARMS)dwParam2); - pFnMciUnMapMsg16To32W(0, wMsg, dwParam2); - break; - default: break; /* so that gcc does not bark */ - } - } - break; - case MCI_SOUND: - if (bFrom32) { - dwRet = MCI_Sound(wDevID, dwParam1, (LPMCI_SOUND_PARMSW)dwParam2); - } else if (pFnMciMapMsg16To32W) { - switch (pFnMciMapMsg16To32W(0, wMsg, &dwParam2)) { - case WINMM_MAP_OK: - case WINMM_MAP_OKMEM: - dwRet = MCI_Sound(wDevID, dwParam1, (LPMCI_SOUND_PARMSW)dwParam2); - pFnMciUnMapMsg16To32W(0, wMsg, dwParam2); - break; - default: break; /* so that gcc does not bark */ - } - } - break; - default: - if (wDevID == MCI_ALL_DEVICE_ID) { - FIXME("unhandled MCI_ALL_DEVICE_ID\n"); - dwRet = MCIERR_CANNOT_USE_ALL; - } else { - dwRet = (bFrom32) ? - MCI_SendCommandFrom32(wDevID, wMsg, dwParam1, dwParam2) : - MCI_SendCommandFrom16(wDevID, wMsg, dwParam1, dwParam2); - } - break; - } - return dwRet; -} - -/************************************************************************** - * MCI_CleanUp [internal] - * - * Some MCI commands need to be cleaned-up (when not called from - * mciSendString), because MCI drivers return extra information for string - * transformation. This function gets rid of them. - */ -LRESULT MCI_CleanUp(LRESULT dwRet, UINT wMsg, DWORD dwParam2) -{ - if (LOWORD(dwRet)) - return LOWORD(dwRet); - - switch (wMsg) { - case MCI_GETDEVCAPS: - switch (dwRet & 0xFFFF0000ul) { - case 0: - case MCI_COLONIZED3_RETURN: - case MCI_COLONIZED4_RETURN: - case MCI_INTEGER_RETURNED: - /* nothing to do */ - break; - case MCI_RESOURCE_RETURNED: - case MCI_RESOURCE_RETURNED|MCI_RESOURCE_DRIVER: - { - LPMCI_GETDEVCAPS_PARMS lmgp; - - lmgp = (LPMCI_GETDEVCAPS_PARMS)(void*)dwParam2; - TRACE("Changing %08lx to %08lx\n", lmgp->dwReturn, (DWORD)LOWORD(lmgp->dwReturn)); - lmgp->dwReturn = LOWORD(lmgp->dwReturn); - } - break; - default: - FIXME("Unsupported value for hiword (%04x) returned by DriverProc(%s)\n", - HIWORD(dwRet), MCI_MessageToString(wMsg)); - } - break; - case MCI_STATUS: - switch (dwRet & 0xFFFF0000ul) { - case 0: - case MCI_COLONIZED3_RETURN: - case MCI_COLONIZED4_RETURN: - case MCI_INTEGER_RETURNED: - /* nothing to do */ - break; - case MCI_RESOURCE_RETURNED: - case MCI_RESOURCE_RETURNED|MCI_RESOURCE_DRIVER: - { - LPMCI_STATUS_PARMS lsp; - - lsp = (LPMCI_STATUS_PARMS)(void*)dwParam2; - TRACE("Changing %08lx to %08lx\n", lsp->dwReturn, (DWORD)LOWORD(lsp->dwReturn)); - lsp->dwReturn = LOWORD(lsp->dwReturn); - } - break; - default: - FIXME("Unsupported value for hiword (%04x) returned by DriverProc(%s)\n", - HIWORD(dwRet), MCI_MessageToString(wMsg)); - } - break; - case MCI_SYSINFO: - switch (dwRet & 0xFFFF0000ul) { - case 0: - case MCI_INTEGER_RETURNED: - /* nothing to do */ - break; - default: - FIXME("Unsupported value for hiword (%04x)\n", HIWORD(dwRet)); - } - break; - default: - if (HIWORD(dwRet)) { - FIXME("Got non null hiword for dwRet=0x%08lx for command %s\n", - dwRet, MCI_MessageToString(wMsg)); - } - break; - } - return LOWORD(dwRet); -} - -/************************************************************************** - * mciGetErrorStringW [WINMM.@] - */ -BOOL WINAPI mciGetErrorStringW(MCIERROR wError, LPWSTR lpstrBuffer, UINT uLength) -{ - BOOL ret = FALSE; - - if (lpstrBuffer != NULL && uLength > 0 && - wError >= MCIERR_BASE && wError <= MCIERR_CUSTOM_DRIVER_BASE) { - - if (LoadStringW(WINMM_IData.hWinMM32Instance, - wError, lpstrBuffer, uLength) > 0) { - ret = TRUE; - } - } - return ret; -} - -/************************************************************************** - * mciGetErrorStringA [WINMM.@] - */ -BOOL WINAPI mciGetErrorStringA(MCIERROR dwError, LPSTR lpstrBuffer, UINT uLength) -{ - BOOL ret = FALSE; - - if (lpstrBuffer != NULL && uLength > 0 && - dwError >= MCIERR_BASE && dwError <= MCIERR_CUSTOM_DRIVER_BASE) { - - if (LoadStringA(WINMM_IData.hWinMM32Instance, - dwError, lpstrBuffer, uLength) > 0) { - ret = TRUE; - } - } - return ret; -} - -/************************************************************************** - * mciDriverNotify [WINMM.@] - */ -BOOL WINAPI mciDriverNotify(HWND hWndCallBack, MCIDEVICEID wDevID, UINT wStatus) -{ - TRACE("(%p, %04x, %04X)\n", hWndCallBack, wDevID, wStatus); - - return PostMessageW(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID); -} - -/************************************************************************** - * mciGetDriverData [WINMM.@] - */ -DWORD WINAPI mciGetDriverData(MCIDEVICEID uDeviceID) -{ - LPWINE_MCIDRIVER wmd; - - TRACE("(%04x)\n", uDeviceID); - - wmd = MCI_GetDriver(uDeviceID); - - if (!wmd) { - WARN("Bad uDeviceID\n"); - return 0L; - } - - return wmd->dwPrivate; -} - -/************************************************************************** - * mciSetDriverData [WINMM.@] - */ -BOOL WINAPI mciSetDriverData(MCIDEVICEID uDeviceID, DWORD data) -{ - LPWINE_MCIDRIVER wmd; - - TRACE("(%04x, %08lx)\n", uDeviceID, data); - - wmd = MCI_GetDriver(uDeviceID); - - if (!wmd) { - WARN("Bad uDeviceID\n"); - return FALSE; - } - - wmd->dwPrivate = data; - return TRUE; -} - -/************************************************************************** - * mciSendCommandW [WINMM.@] - * - */ -DWORD WINAPI mciSendCommandW(MCIDEVICEID wDevID, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2) -{ - DWORD dwRet; - - TRACE("(%08x, %s, %08lx, %08lx)\n", - wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2); - - dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, TRUE); - dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2); - TRACE("=> %08lx\n", dwRet); - return dwRet; -} - -/************************************************************************** - * mciSendCommandA [WINMM.@] - */ -DWORD WINAPI mciSendCommandA(MCIDEVICEID wDevID, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2) -{ - DWORD ret; - int mapped; - - TRACE("(%08x, %s, %08lx, %08lx)\n", - wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2); - - mapped = MCI_MapMsgAtoW(wMsg, dwParam1, &dwParam2); - if (mapped == -1) - { - FIXME("message %04x mapping failed\n", wMsg); - return MMSYSERR_NOMEM; - } - ret = mciSendCommandW(wDevID, wMsg, dwParam1, dwParam2); - if (mapped) - MCI_UnmapMsgAtoW(wMsg, dwParam1, dwParam2, ret); - return ret; -} - -/************************************************************************** - * mciGetDeviceIDA [WINMM.@] - */ -UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName) -{ - LPWSTR w = MCI_strdupAtoW(lpstrName); - UINT ret = MCIERR_OUT_OF_MEMORY; - - if (w) - { - ret = mciGetDeviceIDW(w); - HeapFree(GetProcessHeap(), 0, w); - } - return ret; -} - -/************************************************************************** - * mciGetDeviceIDW [WINMM.@] - */ -UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName) -{ - return MCI_GetDriverFromString(lpwstrName); -} - -/****************************************************************** - * MyUserYield - * - * Internal wrapper to call USER.UserYield16 (in fact through a Wine only export from USER32). - */ -static void MyUserYield(void) -{ - HMODULE mod = GetModuleHandleA( "user32.dll" ); - if (mod) - { - FARPROC proc = GetProcAddress( mod, "UserYield16" ); - if (proc) proc(); - } -} - -/************************************************************************** - * MCI_DefYieldProc [internal] - */ -UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data) -{ - INT16 ret; - - TRACE("(0x%04x, 0x%08lx)\n", wDevID, data); - - if ((HIWORD(data) != 0 && HWND_16(GetActiveWindow()) != HIWORD(data)) || - (GetAsyncKeyState(LOWORD(data)) & 1) == 0) { - MyUserYield(); - ret = 0; - } else { - MSG msg; - - msg.hwnd = HWND_32(HIWORD(data)); - while (!PeekMessageW(&msg, msg.hwnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)); - ret = -1; - } - return ret; -} - -/************************************************************************** - * mciSetYieldProc [WINMM.@] - */ -BOOL WINAPI mciSetYieldProc(MCIDEVICEID uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData) -{ - LPWINE_MCIDRIVER wmd; - - TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData); - - if (!(wmd = MCI_GetDriver(uDeviceID))) { - WARN("Bad uDeviceID\n"); - return FALSE; - } - - wmd->lpfnYieldProc = fpYieldProc; - wmd->dwYieldData = dwYieldData; - wmd->bIs32 = TRUE; - - return TRUE; -} - -/************************************************************************** - * mciGetDeviceIDFromElementIDA [WINMM.@] - */ -UINT WINAPI mciGetDeviceIDFromElementIDA(DWORD dwElementID, LPCSTR lpstrType) -{ - LPWSTR w = MCI_strdupAtoW(lpstrType); - UINT ret = 0; - - if (w) - { - ret = mciGetDeviceIDFromElementIDW(dwElementID, w); - HeapFree(GetProcessHeap(), 0, w); - } - return ret; -} - -/************************************************************************** - * mciGetDeviceIDFromElementIDW [WINMM.@] - */ -UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType) -{ - /* FIXME: that's rather strange, there is no - * mciGetDeviceIDFromElementID32A in winmm.spec - */ - FIXME("(%lu, %s) stub\n", dwElementID, debugstr_w(lpstrType)); - return 0; -} - -/************************************************************************** - * mciGetYieldProc [WINMM.@] - */ -YIELDPROC WINAPI mciGetYieldProc(MCIDEVICEID uDeviceID, DWORD* lpdwYieldData) -{ - LPWINE_MCIDRIVER wmd; - - TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData); - - if (!(wmd = MCI_GetDriver(uDeviceID))) { - WARN("Bad uDeviceID\n"); - return NULL; - } - if (!wmd->lpfnYieldProc) { - WARN("No proc set\n"); - return NULL; - } - if (!wmd->bIs32) { - WARN("Proc is 32 bit\n"); - return NULL; - } - return wmd->lpfnYieldProc; -} - -/************************************************************************** - * mciGetCreatorTask [WINMM.@] - */ -HTASK WINAPI mciGetCreatorTask(MCIDEVICEID uDeviceID) -{ - LPWINE_MCIDRIVER wmd; - HTASK ret = 0; - - if ((wmd = MCI_GetDriver(uDeviceID))) ret = (HTASK)wmd->CreatorThread; - - TRACE("(%u) => %p\n", uDeviceID, ret); - return ret; -} - -/************************************************************************** - * mciDriverYield [WINMM.@] - */ -UINT WINAPI mciDriverYield(MCIDEVICEID uDeviceID) -{ - LPWINE_MCIDRIVER wmd; - UINT ret = 0; - - TRACE("(%04x)\n", uDeviceID); - - if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || !wmd->bIs32) { - MyUserYield(); - } else { - ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData); - } - - return ret; -} +/* + * MCI internal functions + * + * Copyright 1998/1999 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* TODO: + * - implement WINMM (32bit) multitasking and use it in all MCI drivers + * instead of the home grown one + * - 16bit mmTaskXXX functions are currently broken because the 16 + * loader does not support binary command lines => provide Wine's + * own mmtask.tsk not using binary command line. + * - correctly handle the MCI_ALL_DEVICE_ID in functions. + * - finish mapping 16 <=> 32 of MCI structures and commands + * - implement auto-open feature (ie, when a string command is issued + * for a not yet opened device, MCI automatically opens it) + * - use a default registry setting to replace the [mci] section in + * configuration file (layout of info in registry should be compatible + * with all Windows' version - which use different layouts of course) + * - implement automatic open + * + only works on string interface, on regular devices (don't work on all + * nor custom devices) + * - command table handling isn't thread safe + */ + +/* to be cross checked: + * - heapalloc for *sizeof(WCHAR) when needed + * - size of string in WCHAR or bytes? (#chars for MCI_INFO, #bytes for MCI_SYSINFO) + */ + +#include "config.h" +#include "wine/port.h" + +#include <stdlib.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winreg.h" +#include "mmsystem.h" +#include "winuser.h" +#include "winnls.h" +#include "winreg.h" +#include "wownt32.h" + +#include "digitalv.h" +#include "winemm.h" + +#include "wine/debug.h" +#include "wine/unicode.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mci); + +WINMM_MapType (*pFnMciMapMsg16To32W) (WORD,WORD,DWORD*) /* = NULL */; +WINMM_MapType (*pFnMciUnMapMsg16To32W)(WORD,WORD,DWORD) /* = NULL */; +WINMM_MapType (*pFnMciMapMsg32WTo16) (WORD,WORD,DWORD,DWORD*) /* = NULL */; +WINMM_MapType (*pFnMciUnMapMsg32WTo16)(WORD,WORD,DWORD,DWORD) /* = NULL */; + +/* First MCI valid device ID (0 means error) */ +#define MCI_MAGIC 0x0001 + +/* MCI settings */ +static const WCHAR wszHklmMci [] = {'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','M','C','I',0}; +static const WCHAR wszNull [] = {0}; +static const WCHAR wszAll [] = {'A','L','L',0}; +static const WCHAR wszMci [] = {'M','C','I',0}; +static const WCHAR wszOpen [] = {'o','p','e','n',0}; +static const WCHAR wszSystemIni[] = {'s','y','s','t','e','m','.','i','n','i',0}; + +/* dup a string and uppercase it */ +inline static LPWSTR str_dup_upper( LPCWSTR str ) +{ + INT len = (strlenW(str) + 1) * sizeof(WCHAR); + LPWSTR p = HeapAlloc( GetProcessHeap(), 0, len ); + if (p) + { + memcpy( p, str, len ); + CharUpperW( p ); + } + return p; +} + +/************************************************************************** + * MCI_GetDriver [internal] + */ +LPWINE_MCIDRIVER MCI_GetDriver(UINT16 wDevID) +{ + LPWINE_MCIDRIVER wmd = 0; + + EnterCriticalSection(&WINMM_IData.cs); + for (wmd = WINMM_IData.lpMciDrvs; wmd; wmd = wmd->lpNext) { + if (wmd->wDeviceID == wDevID) + break; + } + LeaveCriticalSection(&WINMM_IData.cs); + return wmd; +} + +/************************************************************************** + * MCI_GetDriverFromString [internal] + */ +UINT MCI_GetDriverFromString(LPCWSTR lpstrName) +{ + LPWINE_MCIDRIVER wmd; + UINT ret = 0; + + if (!lpstrName) + return 0; + + if (!strcmpiW(lpstrName, wszAll)) + return MCI_ALL_DEVICE_ID; + + EnterCriticalSection(&WINMM_IData.cs); + for (wmd = WINMM_IData.lpMciDrvs; wmd; wmd = wmd->lpNext) { + if (wmd->lpstrElementName && strcmpW(wmd->lpstrElementName, lpstrName) == 0) { + ret = wmd->wDeviceID; + break; + } + if (wmd->lpstrDeviceType && strcmpiW(wmd->lpstrDeviceType, lpstrName) == 0) { + ret = wmd->wDeviceID; + break; + } + if (wmd->lpstrAlias && strcmpiW(wmd->lpstrAlias, lpstrName) == 0) { + ret = wmd->wDeviceID; + break; + } + } + LeaveCriticalSection(&WINMM_IData.cs); + + return ret; +} + +/************************************************************************** + * MCI_MessageToString [internal] + */ +const char* MCI_MessageToString(UINT wMsg) +{ + static char buffer[100]; + +#define CASE(s) case (s): return #s + + switch (wMsg) { + CASE(DRV_LOAD); + CASE(DRV_ENABLE); + CASE(DRV_OPEN); + CASE(DRV_CLOSE); + CASE(DRV_DISABLE); + CASE(DRV_FREE); + CASE(DRV_CONFIGURE); + CASE(DRV_QUERYCONFIGURE); + CASE(DRV_INSTALL); + CASE(DRV_REMOVE); + CASE(DRV_EXITSESSION); + CASE(DRV_EXITAPPLICATION); + CASE(DRV_POWER); + CASE(MCI_BREAK); + CASE(MCI_CLOSE); + CASE(MCI_CLOSE_DRIVER); + CASE(MCI_COPY); + CASE(MCI_CUE); + CASE(MCI_CUT); + CASE(MCI_DELETE); + CASE(MCI_ESCAPE); + CASE(MCI_FREEZE); + CASE(MCI_PAUSE); + CASE(MCI_PLAY); + CASE(MCI_GETDEVCAPS); + CASE(MCI_INFO); + CASE(MCI_LOAD); + CASE(MCI_OPEN); + CASE(MCI_OPEN_DRIVER); + CASE(MCI_PASTE); + CASE(MCI_PUT); + CASE(MCI_REALIZE); + CASE(MCI_RECORD); + CASE(MCI_RESUME); + CASE(MCI_SAVE); + CASE(MCI_SEEK); + CASE(MCI_SET); + CASE(MCI_SPIN); + CASE(MCI_STATUS); + CASE(MCI_STEP); + CASE(MCI_STOP); + CASE(MCI_SYSINFO); + CASE(MCI_UNFREEZE); + CASE(MCI_UPDATE); + CASE(MCI_WHERE); + CASE(MCI_WINDOW); + /* constants for digital video */ + CASE(MCI_CAPTURE); + CASE(MCI_MONITOR); + CASE(MCI_RESERVE); + CASE(MCI_SETAUDIO); + CASE(MCI_SIGNAL); + CASE(MCI_SETVIDEO); + CASE(MCI_QUALITY); + CASE(MCI_LIST); + CASE(MCI_UNDO); + CASE(MCI_CONFIGURE); + CASE(MCI_RESTORE); +#undef CASE + default: + sprintf(buffer, "MCI_<<%04X>>", wMsg); + return buffer; + } +} + +LPWSTR MCI_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; +} + +LPSTR MCI_strdupWtoA( LPCWSTR str ) +{ + LPSTR ret; + INT len; + + if (!str) return NULL; + len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL ); + ret = HeapAlloc( GetProcessHeap(), 0, len ); + if (ret) WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL ); + return ret; +} + +static int MCI_MapMsgAtoW(UINT msg, DWORD_PTR dwParam1, DWORD_PTR *dwParam2) +{ + if (msg < DRV_RESERVED) return 0; + + switch (msg) + { + case MCI_CLOSE: + case MCI_CONFIGURE: + case MCI_PLAY: + case MCI_SEEK: + case MCI_STOP: + case MCI_PAUSE: + case MCI_GETDEVCAPS: + case MCI_SPIN: + case MCI_SET: + case MCI_STEP: + case MCI_RECORD: + case MCI_BREAK: + case MCI_SOUND: + case MCI_STATUS: + case MCI_CUE: + case MCI_REALIZE: + case MCI_PUT: + case MCI_WHERE: + case MCI_FREEZE: + case MCI_UNFREEZE: + case MCI_CUT: + case MCI_COPY: + case MCI_PASTE: + case MCI_UPDATE: + case MCI_RESUME: + case MCI_DELETE: + case MCI_MONITOR: + case MCI_SETAUDIO: + case MCI_SIGNAL: + case MCI_SETVIDEO: + case MCI_LIST: + return 0; + + case MCI_OPEN: + { + MCI_OPEN_PARMSA *mci_openA = (MCI_OPEN_PARMSA*)*dwParam2; + MCI_OPEN_PARMSW *mci_openW; + DWORD_PTR *ptr; + + ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD_PTR) + sizeof(*mci_openW) + 2 * sizeof(DWORD)); + if (!ptr) return -1; + + *ptr++ = *dwParam2; /* save the previous pointer */ + *dwParam2 = (DWORD_PTR)ptr; + mci_openW = (MCI_OPEN_PARMSW *)ptr; + + if (dwParam1 & MCI_NOTIFY) + mci_openW->dwCallback = mci_openA->dwCallback; + + if (dwParam1 & MCI_OPEN_TYPE) + { + if (dwParam1 & MCI_OPEN_TYPE_ID) + mci_openW->lpstrDeviceType = (LPWSTR)mci_openA->lpstrDeviceType; + else + mci_openW->lpstrDeviceType = MCI_strdupAtoW(mci_openA->lpstrDeviceType); + } + if (dwParam1 & MCI_OPEN_ELEMENT) + { + if (dwParam1 & MCI_OPEN_ELEMENT_ID) + mci_openW->lpstrElementName = (LPWSTR)mci_openA->lpstrElementName; + else + mci_openW->lpstrElementName = MCI_strdupAtoW(mci_openA->lpstrElementName); + } + if (dwParam1 & MCI_OPEN_ALIAS) + mci_openW->lpstrAlias = MCI_strdupAtoW(mci_openA->lpstrAlias); + /* FIXME: this is only needed for specific types of MCI devices, and + * may cause a segfault if the two DWORD:s don't exist at the end of + * mci_openA + */ + memcpy(mci_openW + 1, mci_openA + 1, 2 * sizeof(DWORD)); + } + return 1; + + case MCI_WINDOW: + if (dwParam1 & MCI_ANIM_WINDOW_TEXT) + { + MCI_ANIM_WINDOW_PARMSA *mci_windowA = (MCI_ANIM_WINDOW_PARMSA *)*dwParam2; + MCI_ANIM_WINDOW_PARMSW *mci_windowW; + + mci_windowW = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_windowW)); + if (!mci_windowW) return -1; + + *dwParam2 = (DWORD_PTR)mci_windowW; + + mci_windowW->lpstrText = MCI_strdupAtoW(mci_windowA->lpstrText); + + if (dwParam1 & MCI_NOTIFY) + mci_windowW->dwCallback = mci_windowA->dwCallback; + if (dwParam1 & MCI_ANIM_WINDOW_HWND) + mci_windowW->hWnd = mci_windowA->hWnd; + if (dwParam1 & MCI_ANIM_WINDOW_STATE) + mci_windowW->nCmdShow = mci_windowA->nCmdShow; + + return 1; + } + return 0; + + case MCI_SYSINFO: + { + MCI_SYSINFO_PARMSA *mci_sysinfoA = (MCI_SYSINFO_PARMSA *)*dwParam2; + MCI_SYSINFO_PARMSW *mci_sysinfoW; + DWORD_PTR *ptr; + + ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_sysinfoW) + sizeof(DWORD_PTR)); + if (!ptr) return -1; + + *ptr++ = *dwParam2; /* save the previous pointer */ + *dwParam2 = (DWORD_PTR)ptr; + mci_sysinfoW = (MCI_SYSINFO_PARMSW *)ptr; + + if (dwParam1 & MCI_NOTIFY) + mci_sysinfoW->dwCallback = mci_sysinfoA->dwCallback; + + mci_sysinfoW->dwRetSize = mci_sysinfoA->dwRetSize; + mci_sysinfoW->lpstrReturn = HeapAlloc(GetProcessHeap(), 0, mci_sysinfoW->dwRetSize); + mci_sysinfoW->dwNumber = mci_sysinfoA->dwNumber; + mci_sysinfoW->wDeviceType = mci_sysinfoA->wDeviceType; + return 1; + } + case MCI_INFO: + { + MCI_INFO_PARMSA *mci_infoA = (MCI_INFO_PARMSA *)*dwParam2; + MCI_INFO_PARMSW *mci_infoW; + DWORD_PTR *ptr; + + ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_infoW) + sizeof(DWORD_PTR)); + if (!ptr) return -1; + + *ptr++ = *dwParam2; /* save the previous pointer */ + *dwParam2 = (DWORD_PTR)ptr; + mci_infoW = (MCI_INFO_PARMSW *)ptr; + + if (dwParam1 & MCI_NOTIFY) + mci_infoW->dwCallback = mci_infoA->dwCallback; + + mci_infoW->dwRetSize = mci_infoA->dwRetSize * sizeof(WCHAR); /* it's not the same as SYSINFO !!! */ + mci_infoW->lpstrReturn = HeapAlloc(GetProcessHeap(), 0, mci_infoW->dwRetSize); + return 1; + } + case MCI_SAVE: + { + MCI_SAVE_PARMSA *mci_saveA = (MCI_SAVE_PARMSA *)*dwParam2; + MCI_SAVE_PARMSW *mci_saveW; + + mci_saveW = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_saveW)); + if (!mci_saveW) return -1; + + *dwParam2 = (DWORD_PTR)mci_saveW; + if (dwParam1 & MCI_NOTIFY) + mci_saveW->dwCallback = mci_saveA->dwCallback; + mci_saveW->lpfilename = MCI_strdupAtoW(mci_saveA->lpfilename); + return 1; + } + case MCI_LOAD: + { + MCI_LOAD_PARMSA *mci_loadA = (MCI_LOAD_PARMSA *)*dwParam2; + MCI_LOAD_PARMSW *mci_loadW; + + mci_loadW = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_loadW)); + if (!mci_loadW) return -1; + + *dwParam2 = (DWORD_PTR)mci_loadW; + if (dwParam1 & MCI_NOTIFY) + mci_loadW->dwCallback = mci_loadA->dwCallback; + mci_loadW->lpfilename = MCI_strdupAtoW(mci_loadA->lpfilename); + return 1; + } + + case MCI_ESCAPE: + { + MCI_VD_ESCAPE_PARMSA *mci_vd_escapeA = (MCI_VD_ESCAPE_PARMSA *)*dwParam2; + MCI_VD_ESCAPE_PARMSW *mci_vd_escapeW; + + mci_vd_escapeW = HeapAlloc(GetProcessHeap(), 0, sizeof(*mci_vd_escapeW)); + if (!mci_vd_escapeW) return -1; + + *dwParam2 = (DWORD_PTR)mci_vd_escapeW; + if (dwParam1 & MCI_NOTIFY) + mci_vd_escapeW->dwCallback = mci_vd_escapeA->dwCallback; + mci_vd_escapeW->lpstrCommand = MCI_strdupAtoW(mci_vd_escapeA->lpstrCommand); + return 1; + } + default: + FIXME("Message %s needs translation\n", MCI_MessageToString(msg)); + return -1; + } +} + +static DWORD MCI_UnmapMsgAtoW(UINT msg, DWORD_PTR dwParam1, DWORD_PTR dwParam2, + DWORD result) +{ + switch (msg) + { + case MCI_OPEN: + { + DWORD_PTR *ptr = (DWORD_PTR *)dwParam2 - 1; + MCI_OPEN_PARMSA *mci_openA = (MCI_OPEN_PARMSA *)*ptr; + MCI_OPEN_PARMSW *mci_openW = (MCI_OPEN_PARMSW *)(ptr + 1); + + mci_openA->wDeviceID = mci_openW->wDeviceID; + + if (dwParam1 & MCI_OPEN_TYPE) + { + if (!(dwParam1 & MCI_OPEN_TYPE_ID)) + HeapFree(GetProcessHeap(), 0, (PVOID)mci_openW->lpstrDeviceType); + } + if (dwParam1 & MCI_OPEN_ELEMENT) + { + if (!(dwParam1 & MCI_OPEN_ELEMENT_ID)) + HeapFree(GetProcessHeap(), 0, (PVOID)mci_openW->lpstrElementName); + } + if (dwParam1 & MCI_OPEN_ALIAS) + HeapFree(GetProcessHeap(), 0, (PVOID)mci_openW->lpstrAlias); + HeapFree(GetProcessHeap(), 0, ptr); + } + break; + case MCI_WINDOW: + if (dwParam1 & MCI_ANIM_WINDOW_TEXT) + { + MCI_ANIM_WINDOW_PARMSW *mci_windowW = (MCI_ANIM_WINDOW_PARMSW *)dwParam2; + + HeapFree(GetProcessHeap(), 0, (void*)mci_windowW->lpstrText); + HeapFree(GetProcessHeap(), 0, mci_windowW); + } + break; + + case MCI_SYSINFO: + { + DWORD_PTR *ptr = (DWORD_PTR *)dwParam2 - 1; + MCI_SYSINFO_PARMSA *mci_sysinfoA = (MCI_SYSINFO_PARMSA *)*ptr; + MCI_SYSINFO_PARMSW *mci_sysinfoW = (MCI_SYSINFO_PARMSW *)(ptr + 1); + + if (!result) + { + mci_sysinfoA->dwNumber = mci_sysinfoW->dwNumber; + mci_sysinfoA->wDeviceType = mci_sysinfoW->wDeviceType; + if (dwParam1 & MCI_SYSINFO_QUANTITY) + *(DWORD*)mci_sysinfoA->lpstrReturn = *(DWORD*)mci_sysinfoW->lpstrReturn; + else + WideCharToMultiByte(CP_ACP, 0, + mci_sysinfoW->lpstrReturn, mci_sysinfoW->dwRetSize, + mci_sysinfoA->lpstrReturn, mci_sysinfoA->dwRetSize, + NULL, NULL); + } + + HeapFree(GetProcessHeap(), 0, mci_sysinfoW->lpstrReturn); + HeapFree(GetProcessHeap(), 0, ptr); + } + break; + case MCI_INFO: + { + DWORD_PTR *ptr = (DWORD_PTR *)dwParam2 - 1; + MCI_INFO_PARMSA *mci_infoA = (MCI_INFO_PARMSA *)*ptr; + MCI_INFO_PARMSW *mci_infoW = (MCI_INFO_PARMSW *)(ptr + 1); + + if (!result) + { + WideCharToMultiByte(CP_ACP, 0, + mci_infoW->lpstrReturn, mci_infoW->dwRetSize / sizeof(WCHAR), + mci_infoA->lpstrReturn, mci_infoA->dwRetSize, + NULL, NULL); + } + + HeapFree(GetProcessHeap(), 0, mci_infoW->lpstrReturn); + HeapFree(GetProcessHeap(), 0, ptr); + } + break; + case MCI_SAVE: + { + MCI_SAVE_PARMSW *mci_saveW = (MCI_SAVE_PARMSW *)dwParam2; + + HeapFree(GetProcessHeap(), 0, (void*)mci_saveW->lpfilename); + HeapFree(GetProcessHeap(), 0, mci_saveW); + } + break; + case MCI_LOAD: + { + MCI_LOAD_PARMSW *mci_loadW = (MCI_LOAD_PARMSW *)dwParam2; + + HeapFree(GetProcessHeap(), 0, (void*)mci_loadW->lpfilename); + HeapFree(GetProcessHeap(), 0, mci_loadW); + } + break; + case MCI_ESCAPE: + { + MCI_VD_ESCAPE_PARMSW *mci_vd_escapeW = (MCI_VD_ESCAPE_PARMSW *)dwParam2; + + HeapFree(GetProcessHeap(), 0, (void*)mci_vd_escapeW->lpstrCommand); + HeapFree(GetProcessHeap(), 0, mci_vd_escapeW); + } + break; + + default: + FIXME("Message %s needs unmapping\n", MCI_MessageToString(msg)); + break; + } + + return result; +} + +/************************************************************************** + * MCI_GetDevTypeFromFileName [internal] + */ +static DWORD MCI_GetDevTypeFromFileName(LPCWSTR fileName, LPCWSTR buf, UINT len) +{ + LPCWSTR tmp; + HKEY hKey; + static const WCHAR keyW[] = {'S','O','F','T','W','A','R','E','\\','M','i','c','r','o','s','o','f','t','\\', + 'W','i','n','d','o','w','s',' ','N','T','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', + 'M','C','I',' ','E','x','t','e','n','s','i','o','n','s',0}; + if ((tmp = strrchrW(fileName, '.'))) { + if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, keyW, + 0, KEY_QUERY_VALUE, &hKey ) == ERROR_SUCCESS) { + DWORD dwLen = len; + LONG lRet = RegQueryValueExW( hKey, tmp + 1, 0, 0, (void*)buf, &dwLen ); + RegCloseKey( hKey ); + if (lRet == ERROR_SUCCESS) return 0; + } + TRACE("No ...\\MCI Extensions entry for %s found.\n", debugstr_w(tmp)); + } + return MCIERR_EXTENSION_NOT_FOUND; +} + +#define MAX_MCICMDTABLE 20 +#define MCI_COMMAND_TABLE_NOT_LOADED 0xFFFE + +typedef struct tagWINE_MCICMDTABLE { + UINT uDevType; + const BYTE* lpTable; + UINT nVerbs; /* number of verbs in command table */ + LPCWSTR* aVerbs; /* array of verbs to speed up the verb look up process */ +} WINE_MCICMDTABLE, *LPWINE_MCICMDTABLE; + +static WINE_MCICMDTABLE S_MciCmdTable[MAX_MCICMDTABLE]; + +/************************************************************************** + * MCI_IsCommandTableValid [internal] + */ +static BOOL MCI_IsCommandTableValid(UINT uTbl) +{ + const BYTE* lmem; + LPCWSTR str; + DWORD flg; + WORD eid; + int idx = 0; + BOOL inCst = FALSE; + + TRACE("Dumping cmdTbl=%d [lpTable=%p devType=%d]\n", + uTbl, S_MciCmdTable[uTbl].lpTable, S_MciCmdTable[uTbl].uDevType); + + if (uTbl >= MAX_MCICMDTABLE || !S_MciCmdTable[uTbl].lpTable) + return FALSE; + + lmem = S_MciCmdTable[uTbl].lpTable; + do { + str = (LPCWSTR)lmem; + lmem += (strlenW(str) + 1) * sizeof(WCHAR); + flg = *(const DWORD*)lmem; + eid = *(const WORD*)(lmem + sizeof(DWORD)); + lmem += sizeof(DWORD) + sizeof(WORD); + idx ++; + /* TRACE("cmd=%s %08lx %04x\n", debugstr_w(str), flg, eid); */ + switch (eid) { + case MCI_COMMAND_HEAD: if (!*str || !flg) return FALSE; idx = 0; break; /* check unicity of str in table */ + case MCI_STRING: if (inCst) return FALSE; break; + case MCI_INTEGER: if (!*str) return FALSE; break; + case MCI_END_COMMAND: if (*str || flg || idx == 0) return FALSE; idx = 0; break; + case MCI_RETURN: if (*str || idx != 1) return FALSE; break; + case MCI_FLAG: if (!*str) return FALSE; break; + case MCI_END_COMMAND_LIST: if (*str || flg) return FALSE; idx = 0; break; + case MCI_RECT: if (!*str || inCst) return FALSE; break; + case MCI_CONSTANT: if (inCst) return FALSE; inCst = TRUE; break; + case MCI_END_CONSTANT: if (*str || flg || !inCst) return FALSE; inCst = FALSE; break; + default: return FALSE; + } + } while (eid != MCI_END_COMMAND_LIST); + return TRUE; +} + +/************************************************************************** + * MCI_DumpCommandTable [internal] + */ +static BOOL MCI_DumpCommandTable(UINT uTbl) +{ + const BYTE* lmem; + LPCWSTR str; + DWORD flg; + WORD eid; + + if (!MCI_IsCommandTableValid(uTbl)) { + ERR("Ooops: %d is not valid\n", uTbl); + return FALSE; + } + + lmem = S_MciCmdTable[uTbl].lpTable; + do { + do { + str = (LPCWSTR)lmem; + lmem += (strlenW(str) + 1) * sizeof(WCHAR); + flg = *(const DWORD*)lmem; + eid = *(const WORD*)(lmem + sizeof(DWORD)); + /* TRACE("cmd=%s %08lx %04x\n", debugstr_w(str), flg, eid); */ + lmem += sizeof(DWORD) + sizeof(WORD); + } while (eid != MCI_END_COMMAND && eid != MCI_END_COMMAND_LIST); + /* EPP TRACE(" => end of command%s\n", (eid == MCI_END_COMMAND_LIST) ? " list" : ""); */ + } while (eid != MCI_END_COMMAND_LIST); + return TRUE; +} + + +/************************************************************************** + * MCI_GetCommandTable [internal] + */ +static UINT MCI_GetCommandTable(UINT uDevType) +{ + UINT uTbl; + WCHAR buf[32]; + LPCWSTR str = NULL; + + /* first look up existing for existing devType */ + for (uTbl = 0; uTbl < MAX_MCICMDTABLE; uTbl++) { + if (S_MciCmdTable[uTbl].lpTable && S_MciCmdTable[uTbl].uDevType == uDevType) + return uTbl; + } + + /* well try to load id */ + if (uDevType >= MCI_DEVTYPE_FIRST && uDevType <= MCI_DEVTYPE_LAST) { + if (LoadStringW(WINMM_IData.hWinMM32Instance, uDevType, buf, sizeof(buf) / sizeof(WCHAR))) { + str = buf; + } + } else if (uDevType == 0) { + static const WCHAR wszCore[] = {'C','O','R','E',0}; + str = wszCore; + } + uTbl = MCI_NO_COMMAND_TABLE; + if (str) { + HRSRC hRsrc = FindResourceW(WINMM_IData.hWinMM32Instance, str, (LPCWSTR)RT_RCDATA); + HANDLE hMem = 0; + + if (hRsrc) hMem = LoadResource(WINMM_IData.hWinMM32Instance, hRsrc); + if (hMem) { + uTbl = MCI_SetCommandTable(LockResource(hMem), uDevType); + } else { + WARN("No command table found in resource %p[%s]\n", + WINMM_IData.hWinMM32Instance, debugstr_w(str)); + } + } + TRACE("=> %d\n", uTbl); + return uTbl; +} + +/************************************************************************** + * MCI_SetCommandTable [internal] + */ +UINT MCI_SetCommandTable(void *table, UINT uDevType) +{ + int uTbl; + static BOOL bInitDone = FALSE; + + /* <HACK> + * The CORE command table must be loaded first, so that MCI_GetCommandTable() + * can be called with 0 as a uDevType to retrieve it. + * </HACK> + */ + if (!bInitDone) { + bInitDone = TRUE; + MCI_GetCommandTable(0); + } + TRACE("(%p, %u)\n", table, uDevType); + for (uTbl = 0; uTbl < MAX_MCICMDTABLE; uTbl++) { + if (!S_MciCmdTable[uTbl].lpTable) { + const BYTE* lmem; + LPCWSTR str; + WORD eid; + WORD count; + + S_MciCmdTable[uTbl].uDevType = uDevType; + S_MciCmdTable[uTbl].lpTable = table; + + if (TRACE_ON(mci)) { + MCI_DumpCommandTable(uTbl); + } + + /* create the verbs table */ + /* get # of entries */ + lmem = S_MciCmdTable[uTbl].lpTable; + count = 0; + do { + str = (LPCWSTR)lmem; + lmem += (strlenW(str) + 1) * sizeof(WCHAR); + eid = *(const WORD*)(lmem + sizeof(DWORD)); + lmem += sizeof(DWORD) + sizeof(WORD); + if (eid == MCI_COMMAND_HEAD) + count++; + } while (eid != MCI_END_COMMAND_LIST); + + S_MciCmdTable[uTbl].aVerbs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(LPCWSTR)); + S_MciCmdTable[uTbl].nVerbs = count; + + lmem = S_MciCmdTable[uTbl].lpTable; + count = 0; + do { + str = (LPCWSTR)lmem; + lmem += (strlenW(str) + 1) * sizeof(WCHAR); + eid = *(const WORD*)(lmem + sizeof(DWORD)); + lmem += sizeof(DWORD) + sizeof(WORD); + if (eid == MCI_COMMAND_HEAD) + S_MciCmdTable[uTbl].aVerbs[count++] = str; + } while (eid != MCI_END_COMMAND_LIST); + /* assert(count == S_MciCmdTable[uTbl].nVerbs); */ + return uTbl; + } + } + + return MCI_NO_COMMAND_TABLE; +} + +/************************************************************************** + * MCI_DeleteCommandTable [internal] + */ +BOOL MCI_DeleteCommandTable(UINT uTbl, BOOL delete) +{ + if (uTbl >= MAX_MCICMDTABLE || !S_MciCmdTable[uTbl].lpTable) + return FALSE; + + if (delete) HeapFree(GetProcessHeap(), 0, (void*)S_MciCmdTable[uTbl].lpTable); + S_MciCmdTable[uTbl].lpTable = NULL; + HeapFree(GetProcessHeap(), 0, S_MciCmdTable[uTbl].aVerbs); + S_MciCmdTable[uTbl].aVerbs = 0; + return TRUE; +} + +/************************************************************************** + * MCI_UnLoadMciDriver [internal] + */ +static BOOL MCI_UnLoadMciDriver(LPWINE_MCIDRIVER wmd) +{ + LPWINE_MCIDRIVER* tmp; + + if (!wmd) + return TRUE; + + CloseDriver(wmd->hDriver, 0, 0); + + if (wmd->dwPrivate != 0) + WARN("Unloading mci driver with non nul dwPrivate field\n"); + + EnterCriticalSection(&WINMM_IData.cs); + for (tmp = &WINMM_IData.lpMciDrvs; *tmp; tmp = &(*tmp)->lpNext) { + if (*tmp == wmd) { + *tmp = wmd->lpNext; + break; + } + } + LeaveCriticalSection(&WINMM_IData.cs); + + HeapFree(GetProcessHeap(), 0, wmd->lpstrDeviceType); + HeapFree(GetProcessHeap(), 0, wmd->lpstrAlias); + HeapFree(GetProcessHeap(), 0, wmd->lpstrElementName); + + HeapFree(GetProcessHeap(), 0, wmd); + return TRUE; +} + +/************************************************************************** + * MCI_OpenMciDriver [internal] + */ +static BOOL MCI_OpenMciDriver(LPWINE_MCIDRIVER wmd, LPCWSTR drvTyp, LPARAM lp) +{ + WCHAR libName[128]; + + if (!DRIVER_GetLibName(drvTyp, wszMci, libName, sizeof(libName))) + return FALSE; + + wmd->bIs32 = 0xFFFF; + /* First load driver */ + if ((wmd->hDriver = (HDRVR)DRIVER_TryOpenDriver32(libName, lp))) { + wmd->bIs32 = TRUE; + } else if (WINMM_CheckForMMSystem() && pFnMciMapMsg32WTo16) { + WINMM_MapType res; + + switch (res = pFnMciMapMsg32WTo16(0, DRV_OPEN, 0, &lp)) { + case WINMM_MAP_MSGERROR: + TRACE("Not handled yet (DRV_OPEN)\n"); + break; + case WINMM_MAP_NOMEM: + TRACE("Problem mapping msg=DRV_OPEN from 32W to 16\n"); + break; + case WINMM_MAP_OK: + case WINMM_MAP_OKMEM: + if ((wmd->hDriver = OpenDriver(drvTyp, wszMci, lp))) + wmd->bIs32 = FALSE; + if (res == WINMM_MAP_OKMEM) + pFnMciUnMapMsg32WTo16(0, DRV_OPEN, 0, lp); + break; + } + } + return (wmd->bIs32 == 0xFFFF) ? FALSE : TRUE; +} + +/************************************************************************** + * MCI_LoadMciDriver [internal] + */ +static DWORD MCI_LoadMciDriver(LPCWSTR _strDevTyp, LPWINE_MCIDRIVER* lpwmd) +{ + LPWSTR strDevTyp = str_dup_upper(_strDevTyp); + LPWINE_MCIDRIVER wmd = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wmd)); + MCI_OPEN_DRIVER_PARMSW modp; + DWORD dwRet = 0; + + if (!wmd || !strDevTyp) { + dwRet = MCIERR_OUT_OF_MEMORY; + goto errCleanUp; + } + + wmd->lpfnYieldProc = MCI_DefYieldProc; + wmd->dwYieldData = VK_CANCEL; + wmd->CreatorThread = GetCurrentThreadId(); + + EnterCriticalSection(&WINMM_IData.cs); + /* wmd must be inserted in list before sending opening the driver, coz' it + * may want to lookup at wDevID + */ + wmd->lpNext = WINMM_IData.lpMciDrvs; + WINMM_IData.lpMciDrvs = wmd; + + for (modp.wDeviceID = MCI_MAGIC; + MCI_GetDriver(modp.wDeviceID) != 0; + modp.wDeviceID++); + + wmd->wDeviceID = modp.wDeviceID; + + LeaveCriticalSection(&WINMM_IData.cs); + + TRACE("wDevID=%04X \n", modp.wDeviceID); + + modp.lpstrParams = NULL; + + if (!MCI_OpenMciDriver(wmd, strDevTyp, (LPARAM)&modp)) { + /* silence warning if all is used... some bogus program use commands like + * 'open all'... + */ + if (strcmpiW(strDevTyp, wszAll) == 0) { + dwRet = MCIERR_CANNOT_USE_ALL; + } else { + FIXME("Couldn't load driver for type %s.\n" + "If you don't have a windows installation accessible from Wine,\n" + "you perhaps forgot to create a [mci] section in system.ini\n", + debugstr_w(strDevTyp)); + dwRet = MCIERR_DEVICE_NOT_INSTALLED; + } + goto errCleanUp; + } + + /* FIXME: should also check that module's description is of the form + * MODULENAME:[MCI] comment + */ + + /* some drivers will return 0x0000FFFF, some others 0xFFFFFFFF */ + wmd->uSpecificCmdTable = LOWORD(modp.wCustomCommandTable); + wmd->uTypeCmdTable = MCI_COMMAND_TABLE_NOT_LOADED; + + TRACE("Loaded driver %p (%s), type is %d, cmdTable=%08x\n", + wmd->hDriver, debugstr_w(strDevTyp), modp.wType, modp.wCustomCommandTable); + + wmd->lpstrDeviceType = strDevTyp; + wmd->wType = modp.wType; + + TRACE("mcidev=%d, uDevTyp=%04X wDeviceID=%04X !\n", + modp.wDeviceID, modp.wType, modp.wDeviceID); + *lpwmd = wmd; + return 0; +errCleanUp: + MCI_UnLoadMciDriver(wmd); + HeapFree(GetProcessHeap(), 0, strDevTyp); + *lpwmd = 0; + return dwRet; +} + +/************************************************************************** + * MCI_FinishOpen [internal] + */ +static DWORD MCI_FinishOpen(LPWINE_MCIDRIVER wmd, LPMCI_OPEN_PARMSW lpParms, + DWORD dwParam) +{ + if (dwParam & MCI_OPEN_ELEMENT) + { + wmd->lpstrElementName = HeapAlloc(GetProcessHeap(),0,(strlenW(lpParms->lpstrElementName)+1) * sizeof(WCHAR)); + strcpyW( wmd->lpstrElementName, lpParms->lpstrElementName ); + } + if (dwParam & MCI_OPEN_ALIAS) + { + wmd->lpstrAlias = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpParms->lpstrAlias)+1) * sizeof(WCHAR)); + strcpyW( wmd->lpstrAlias, lpParms->lpstrAlias); + } + lpParms->wDeviceID = wmd->wDeviceID; + + return MCI_SendCommandFrom32(wmd->wDeviceID, MCI_OPEN_DRIVER, dwParam, + (DWORD)lpParms); +} + +/************************************************************************** + * MCI_FindCommand [internal] + */ +static LPCWSTR MCI_FindCommand(UINT uTbl, LPCWSTR verb) +{ + UINT idx; + + if (uTbl >= MAX_MCICMDTABLE || !S_MciCmdTable[uTbl].lpTable) + return NULL; + + /* another improvement would be to have the aVerbs array sorted, + * so that we could use a dichotomic search on it, rather than this dumb + * array look up + */ + for (idx = 0; idx < S_MciCmdTable[uTbl].nVerbs; idx++) { + if (strcmpiW(S_MciCmdTable[uTbl].aVerbs[idx], verb) == 0) + return S_MciCmdTable[uTbl].aVerbs[idx]; + } + + return NULL; +} + +/************************************************************************** + * MCI_GetReturnType [internal] + */ +static DWORD MCI_GetReturnType(LPCWSTR lpCmd) +{ + lpCmd = (LPCWSTR)((BYTE*)(lpCmd + strlenW(lpCmd) + 1) + sizeof(DWORD) + sizeof(WORD)); + if (*lpCmd == '\0' && *(const WORD*)((BYTE*)(lpCmd + 1) + sizeof(DWORD)) == MCI_RETURN) { + return *(const DWORD*)(lpCmd + 1); + } + return 0L; +} + +/************************************************************************** + * MCI_GetMessage [internal] + */ +static WORD MCI_GetMessage(LPCWSTR lpCmd) +{ + return (WORD)*(const DWORD*)(lpCmd + strlenW(lpCmd) + 1); +} + +/************************************************************************** + * MCI_GetDWord [internal] + */ +static BOOL MCI_GetDWord(LPDWORD data, LPWSTR* ptr) +{ + DWORD val; + LPWSTR ret; + + val = strtoulW(*ptr, &ret, 0); + + switch (*ret) { + case '\0': break; + case ' ': ret++; break; + default: return FALSE; + } + + *data |= val; + *ptr = ret; + return TRUE; +} + +/************************************************************************** + * MCI_GetString [internal] + */ +static DWORD MCI_GetString(LPWSTR* str, LPWSTR* args) +{ + LPWSTR ptr = *args; + + /* see if we have a quoted string */ + if (*ptr == '"') { + ptr = strchrW(*str = ptr + 1, '"'); + if (!ptr) return MCIERR_NO_CLOSING_QUOTE; + /* FIXME: shall we escape \" from string ?? */ + if (ptr[-1] == '\\') TRACE("Ooops: un-escaped \"\n"); + *ptr++ = '\0'; /* remove trailing " */ + if (*ptr != ' ' && *ptr != '\0') return MCIERR_EXTRA_CHARACTERS; + *ptr++ = '\0'; + } else { + ptr = strchrW(ptr, ' '); + + if (ptr) { + *ptr++ = '\0'; + } else { + ptr = *args + strlenW(*args); + } + *str = *args; + } + + *args = ptr; + return 0; +} + +#define MCI_DATA_SIZE 16 + +/************************************************************************** + * MCI_ParseOptArgs [internal] + */ +static DWORD MCI_ParseOptArgs(LPDWORD data, int _offset, LPCWSTR lpCmd, + LPWSTR args, LPDWORD dwFlags) +{ + int len, offset; + const char* lmem; + LPCWSTR str; + DWORD dwRet, flg, cflg = 0; + WORD eid; + BOOL inCst, found; + + /* loop on arguments */ + while (*args) { + lmem = (const char*)lpCmd; + found = inCst = FALSE; + offset = _offset; + + /* skip any leading white space(s) */ + while (*args == ' ') args++; + TRACE("args=%s offset=%d\n", debugstr_w(args), offset); + + do { /* loop on options for command table for the requested verb */ + str = (LPCWSTR)lmem; + lmem += ((len = strlenW(str)) + 1) * sizeof(WCHAR); + flg = *(const DWORD*)lmem; + eid = *(const WORD*)(lmem + sizeof(DWORD)); + lmem += sizeof(DWORD) + sizeof(WORD); + /* TRACE("\tcmd=%s inCst=%c eid=%04x\n", debugstr_w(str), inCst ? 'Y' : 'N', eid); */ + + switch (eid) { + case MCI_CONSTANT: + inCst = TRUE; cflg = flg; break; + case MCI_END_CONSTANT: + /* there may be additional integral values after flag in constant */ + if (inCst && MCI_GetDWord(&(data[offset]), &args)) { + *dwFlags |= cflg; + } + inCst = FALSE; cflg = 0; + break; + } + + if (strncmpiW(args, str, len) == 0 && + (args[len] == 0 || args[len] == ' ')) { + /* store good values into data[] */ + args += len; + while (*args == ' ') args++; + found = TRUE; + + switch (eid) { + case MCI_COMMAND_HEAD: + case MCI_RETURN: + case MCI_END_COMMAND: + case MCI_END_COMMAND_LIST: + case MCI_CONSTANT: /* done above */ + case MCI_END_CONSTANT: /* done above */ + break; + case MCI_FLAG: + *dwFlags |= flg; + break; + case MCI_INTEGER: + if (inCst) { + data[offset] |= flg; + *dwFlags |= cflg; + inCst = FALSE; + } else { + *dwFlags |= flg; + if (!MCI_GetDWord(&(data[offset]), &args)) { + return MCIERR_BAD_INTEGER; + } + } + break; + case MCI_RECT: + /* store rect in data (offset...offset+3) */ + *dwFlags |= flg; + if (!MCI_GetDWord(&(data[offset+0]), &args) || + !MCI_GetDWord(&(data[offset+1]), &args) || + !MCI_GetDWord(&(data[offset+2]), &args) || + !MCI_GetDWord(&(data[offset+3]), &args)) { + ERR("Bad rect %s\n", debugstr_w(args)); + return MCIERR_BAD_INTEGER; + } + break; + case MCI_STRING: + *dwFlags |= flg; + if ((dwRet = MCI_GetString((LPWSTR*)&data[offset], &args))) + return dwRet; + break; + default: ERR("oops\n"); + } + /* exit inside while loop, except if just entered in constant area definition */ + if (!inCst || eid != MCI_CONSTANT) eid = MCI_END_COMMAND; + } else { + /* have offset incremented if needed */ + switch (eid) { + case MCI_COMMAND_HEAD: + case MCI_RETURN: + case MCI_END_COMMAND: + case MCI_END_COMMAND_LIST: + case MCI_CONSTANT: + case MCI_FLAG: break; + case MCI_INTEGER: if (!inCst) offset++; break; + case MCI_END_CONSTANT: + case MCI_STRING: offset++; break; + case MCI_RECT: offset += 4; break; + default: ERR("oops\n"); + } + } + } while (eid != MCI_END_COMMAND); + if (!found) { + WARN("Optarg %s not found\n", debugstr_w(args)); + return MCIERR_UNRECOGNIZED_COMMAND; + } + if (offset == MCI_DATA_SIZE) { + ERR("Internal data[] buffer overflow\n"); + return MCIERR_PARSER_INTERNAL; + } + } + return 0; +} + +/************************************************************************** + * MCI_HandleReturnValues [internal] + */ +static DWORD MCI_HandleReturnValues(DWORD dwRet, LPWINE_MCIDRIVER wmd, DWORD retType, + LPDWORD data, LPWSTR lpstrRet, UINT uRetLen) +{ + static const WCHAR wszLd [] = {'%','l','d',0}; + static const WCHAR wszLd4 [] = {'%','l','d',' ','%','l','d',' ','%','l','d',' ','%','l','d',0}; + static const WCHAR wszCol3[] = {'%','d',':','%','d',':','%','d',0}; + static const WCHAR wszCol4[] = {'%','d',':','%','d',':','%','d',':','%','d',0}; + + if (lpstrRet) { + switch (retType) { + case 0: /* nothing to return */ + break; + case MCI_INTEGER: + switch (dwRet & 0xFFFF0000ul) { + case 0: + case MCI_INTEGER_RETURNED: + snprintfW(lpstrRet, uRetLen, wszLd, data[1]); + break; + case MCI_RESOURCE_RETURNED: + /* return string which ID is HIWORD(data[1]), + * string is loaded from mmsystem.dll */ + LoadStringW(WINMM_IData.hWinMM32Instance, HIWORD(data[1]), + lpstrRet, uRetLen); + break; + case MCI_RESOURCE_RETURNED|MCI_RESOURCE_DRIVER: + /* return string which ID is HIWORD(data[1]), + * string is loaded from driver */ + /* FIXME: this is wrong for a 16 bit handle */ + LoadStringW(GetDriverModuleHandle(wmd->hDriver), + HIWORD(data[1]), lpstrRet, uRetLen); + break; + case MCI_COLONIZED3_RETURN: + snprintfW(lpstrRet, uRetLen, wszCol3, + LOBYTE(LOWORD(data[1])), HIBYTE(LOWORD(data[1])), + LOBYTE(HIWORD(data[1]))); + break; + case MCI_COLONIZED4_RETURN: + snprintfW(lpstrRet, uRetLen, wszCol4, + LOBYTE(LOWORD(data[1])), HIBYTE(LOWORD(data[1])), + LOBYTE(HIWORD(data[1])), HIBYTE(HIWORD(data[1]))); + break; + default: ERR("Ooops (%04X)\n", HIWORD(dwRet)); + } + break; + case MCI_STRING: + switch (dwRet & 0xFFFF0000ul) { + case 0: + /* nothing to do data[1] == lpstrRet */ + break; + case MCI_INTEGER_RETURNED: + data[1] = *(LPDWORD)lpstrRet; + snprintfW(lpstrRet, uRetLen, wszLd, data[1]); + break; + default: + WARN("Oooch. MCI_STRING and HIWORD(dwRet)=%04x\n", HIWORD(dwRet)); + break; + } + break; + case MCI_RECT: + if (dwRet & 0xFFFF0000ul) + WARN("Oooch. MCI_STRING and HIWORD(dwRet)=%04x\n", HIWORD(dwRet)); + snprintfW(lpstrRet, uRetLen, wszLd4, + data[1], data[2], data[3], data[4]); + break; + default: ERR("oops\n"); + } + } + return LOWORD(dwRet); +} + +/************************************************************************** + * mciSendStringW [WINMM.@] + */ +DWORD WINAPI mciSendStringW(LPCWSTR lpstrCommand, LPWSTR lpstrRet, + UINT uRetLen, HWND hwndCallback) +{ + LPWSTR verb, dev, args; + LPWINE_MCIDRIVER wmd = 0; + DWORD dwFlags = 0, dwRet = 0; + int offset = 0; + DWORD data[MCI_DATA_SIZE]; + DWORD retType; + LPCWSTR lpCmd = 0; + LPWSTR devAlias = NULL; + BOOL bAutoOpen = FALSE; + static const WCHAR wszNew[] = {'n','e','w',0}; + static const WCHAR wszSAliasS[] = {' ','a','l','i','a','s',' ',0}; + + TRACE("(%s, %p, %d, %p)\n", + debugstr_w(lpstrCommand), lpstrRet, uRetLen, hwndCallback); + + /* format is <command> <device> <optargs> */ + if (!(verb = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpstrCommand)+1) * sizeof(WCHAR)))) + return MCIERR_OUT_OF_MEMORY; + strcpyW( verb, lpstrCommand ); + CharLowerW(verb); + + memset(data, 0, sizeof(data)); + + if (!(args = strchrW(verb, ' '))) { + dwRet = MCIERR_MISSING_DEVICE_NAME; + goto errCleanUp; + } + *args++ = '\0'; + if ((dwRet = MCI_GetString(&dev, &args))) { + goto errCleanUp; + } + + /* case dev == 'new' has to be handled */ + if (!strcmpW(dev, wszNew)) { + FIXME("'new': NIY as device name\n"); + dwRet = MCIERR_MISSING_DEVICE_NAME; + goto errCleanUp; + } + + /* otherwise, try to grab devType from open */ + if (!strcmpW(verb, wszOpen)) { + LPWSTR devType, tmp; + + if ((devType = strchrW(dev, '!')) != NULL) { + *devType++ = '\0'; + tmp = devType; devType = dev; dev = tmp; + + dwFlags |= MCI_OPEN_TYPE; + data[2] = (DWORD)devType; + devType = str_dup_upper(devType); + dwFlags |= MCI_OPEN_ELEMENT; + data[3] = (DWORD)dev; + } else if (strchrW(dev, '.') == NULL) { + tmp = strchrW(dev,' '); + if (tmp) *tmp = '\0'; + data[2] = (DWORD)dev; + devType = str_dup_upper(dev); + if (tmp) *tmp = ' '; + dwFlags |= MCI_OPEN_TYPE; + } else { + static const WCHAR wszTypeS[] = {'t','y','p','e',' ',0}; + if ((devType = strstrW(args, wszTypeS)) != NULL) { + devType += 5; + tmp = strchrW(devType, ' '); + if (tmp) *tmp = '\0'; + devType = str_dup_upper(devType); + if (tmp) *tmp = ' '; + /* dwFlags and data[2] will be correctly set in ParseOpt loop */ + } else { + WCHAR buf[32]; + if ((dwRet = MCI_GetDevTypeFromFileName(dev, buf, sizeof(buf)))) + goto errCleanUp; + + devType = str_dup_upper(buf); + } + dwFlags |= MCI_OPEN_ELEMENT; + data[3] = (DWORD)dev; + } + if ((devAlias = strstrW(args, wszSAliasS))) { + WCHAR* tmp2; + devAlias += 7; + if (!(tmp = strchrW(devAlias,' '))) tmp = devAlias + strlenW(devAlias); + if (tmp) *tmp = '\0'; + tmp2 = HeapAlloc(GetProcessHeap(), 0, (tmp - devAlias + 1) * sizeof(WCHAR) ); + memcpy( tmp2, devAlias, (tmp - devAlias) * sizeof(WCHAR) ); + tmp2[tmp - devAlias] = 0; + data[4] = (DWORD)tmp2; + /* should be done in regular options parsing */ + /* dwFlags |= MCI_OPEN_ALIAS; */ + } + + dwRet = MCI_LoadMciDriver(devType, &wmd); + if (dwRet == MCIERR_DEVICE_NOT_INSTALLED) + dwRet = MCIERR_INVALID_DEVICE_NAME; + HeapFree(GetProcessHeap(), 0, devType); + if (dwRet) { + MCI_UnLoadMciDriver(wmd); + goto errCleanUp; + } + } else if (!(wmd = MCI_GetDriver(mciGetDeviceIDW(dev)))) { + /* auto open */ + static WCHAR wszOpenWait[] = {'o','p','e','n',' ','%','s',' ','w','a','i','t',0}; + WCHAR buf[128]; + sprintfW(buf, wszOpenWait, dev); + + if ((dwRet = mciSendStringW(buf, NULL, 0, 0)) != 0) + goto errCleanUp; + + wmd = MCI_GetDriver(mciGetDeviceIDW(dev)); + if (!wmd) { + /* FIXME: memory leak, MCI driver is not closed */ + dwRet = MCIERR_INVALID_DEVICE_ID; + goto errCleanUp; + } + } + + /* get the verb in the different command tables */ + if (wmd) { + /* try the device specific command table */ + lpCmd = MCI_FindCommand(wmd->uSpecificCmdTable, verb); + if (!lpCmd) { + /* try the type specific command table */ + if (wmd->uTypeCmdTable == MCI_COMMAND_TABLE_NOT_LOADED) + wmd->uTypeCmdTable = MCI_GetCommandTable(wmd->wType); + if (wmd->uTypeCmdTable != MCI_NO_COMMAND_TABLE) + lpCmd = MCI_FindCommand(wmd->uTypeCmdTable, verb); + } + } + /* try core command table */ + if (!lpCmd) lpCmd = MCI_FindCommand(MCI_GetCommandTable(0), verb); + + if (!lpCmd) { + TRACE("Command %s not found!\n", debugstr_w(verb)); + dwRet = MCIERR_UNRECOGNIZED_COMMAND; + goto errCleanUp; + } + + /* set up call back */ + if (hwndCallback != 0) { + dwFlags |= MCI_NOTIFY; + data[0] = (DWORD)hwndCallback; + } + + /* set return information */ + switch (retType = MCI_GetReturnType(lpCmd)) { + case 0: offset = 1; break; + case MCI_INTEGER: offset = 2; break; + case MCI_STRING: data[1] = (DWORD)lpstrRet; data[2] = uRetLen; offset = 3; break; + case MCI_RECT: offset = 5; break; + default: ERR("oops\n"); + } + + TRACE("verb=%s on dev=%s; offset=%d\n", + debugstr_w(verb), debugstr_w(dev), offset); + + if ((dwRet = MCI_ParseOptArgs(data, offset, lpCmd, args, &dwFlags))) + goto errCleanUp; + + if (bAutoOpen && (dwFlags & MCI_NOTIFY)) { + dwRet = MCIERR_NOTIFY_ON_AUTO_OPEN; + goto errCleanUp; + } + /* FIXME: the command should get it's own notification window set up and + * ask for device closing while processing the notification mechanism + */ + if (lpstrRet && uRetLen) *lpstrRet = '\0'; + + TRACE("[%d, %s, %08lx, %08lx/%s %08lx/%s %08lx/%s %08lx/%s %08lx/%s %08lx/%s]\n", + wmd->wDeviceID, MCI_MessageToString(MCI_GetMessage(lpCmd)), dwFlags, + data[0], debugstr_w((WCHAR *)data[0]), data[1], debugstr_w((WCHAR *)data[1]), + data[2], debugstr_w((WCHAR *)data[2]), data[3], debugstr_w((WCHAR *)data[3]), + data[4], debugstr_w((WCHAR *)data[4]), data[5], debugstr_w((WCHAR *)data[5])); + + if (strcmpW(verb, wszOpen) == 0) { + if ((dwRet = MCI_FinishOpen(wmd, (LPMCI_OPEN_PARMSW)data, dwFlags))) + MCI_UnLoadMciDriver(wmd); + /* FIXME: notification is not properly shared across two opens */ + } else { + dwRet = MCI_SendCommand(wmd->wDeviceID, MCI_GetMessage(lpCmd), dwFlags, (DWORD)data, TRUE); + } + TRACE("=> 1/ %lx (%s)\n", dwRet, debugstr_w(lpstrRet)); + dwRet = MCI_HandleReturnValues(dwRet, wmd, retType, data, lpstrRet, uRetLen); + TRACE("=> 2/ %lx (%s)\n", dwRet, debugstr_w(lpstrRet)); + +errCleanUp: + HeapFree(GetProcessHeap(), 0, verb); + HeapFree(GetProcessHeap(), 0, devAlias); + return dwRet; +} + +/************************************************************************** + * mciSendStringA [WINMM.@] + */ +DWORD WINAPI mciSendStringA(LPCSTR lpstrCommand, LPSTR lpstrRet, + UINT uRetLen, HWND hwndCallback) +{ + LPWSTR lpwstrCommand; + LPWSTR lpwstrRet = NULL; + UINT ret; + INT len; + + /* FIXME: is there something to do with lpstrReturnString ? */ + len = MultiByteToWideChar( CP_ACP, 0, lpstrCommand, -1, NULL, 0 ); + lpwstrCommand = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); + MultiByteToWideChar( CP_ACP, 0, lpstrCommand, -1, lpwstrCommand, len ); + if (lpstrRet) + { + lpwstrRet = HeapAlloc(GetProcessHeap(), 0, uRetLen * sizeof(WCHAR)); + if (!lpwstrRet) { + WARN("no memory\n"); + HeapFree( GetProcessHeap(), 0, lpwstrCommand ); + return MCIERR_OUT_OF_MEMORY; + } + } + ret = mciSendStringW(lpwstrCommand, lpwstrRet, uRetLen, hwndCallback); + if (lpwstrRet) + WideCharToMultiByte( CP_ACP, 0, lpwstrRet, -1, lpstrRet, uRetLen, NULL, NULL ); + HeapFree(GetProcessHeap(), 0, lpwstrCommand); + HeapFree(GetProcessHeap(), 0, lpwstrRet); + return ret; +} + +/************************************************************************** + * mciExecute [WINMM.@] + * mciExecute [MMSYSTEM.712] + */ +BOOL WINAPI mciExecute(LPCSTR lpstrCommand) +{ + char strRet[256]; + DWORD ret; + + TRACE("(%s)!\n", lpstrCommand); + + ret = mciSendStringA(lpstrCommand, strRet, sizeof(strRet), 0); + if (ret != 0) { + if (!mciGetErrorStringA(ret, strRet, sizeof(strRet))) { + sprintf(strRet, "Unknown MCI error (%ld)", ret); + } + MessageBoxA(0, strRet, "Error in mciExecute()", MB_OK); + } + /* FIXME: what shall I return ? */ + return TRUE; +} + +/************************************************************************** + * mciLoadCommandResource [WINMM.@] + * + * Strangely, this function only exists as an UNICODE one. + */ +UINT WINAPI mciLoadCommandResource(HINSTANCE hInst, LPCWSTR resNameW, UINT type) +{ + HRSRC hRsrc = 0; + HGLOBAL hMem; + UINT16 ret = MCI_NO_COMMAND_TABLE; + + TRACE("(%p, %s, %d)!\n", hInst, debugstr_w(resNameW), type); + + /* if a file named "resname.mci" exits, then load resource "resname" from it + * otherwise directly from driver + * We don't support it (who uses this feature ?), but we check anyway + */ + if (!type) { +#if 0 + /* FIXME: we should put this back into order, but I never found a program + * actually using this feature, so we may not need it + */ + char buf[128]; + OFSTRUCT ofs; + + strcat(strcpy(buf, resname), ".mci"); + if (OpenFile(buf, &ofs, OF_EXIST) != HFILE_ERROR) { + FIXME("NIY: command table to be loaded from '%s'\n", ofs.szPathName); + } +#endif + } + if (!(hRsrc = FindResourceW(hInst, resNameW, (LPWSTR)RT_RCDATA))) { + WARN("No command table found in resource\n"); + } else if ((hMem = LoadResource(hInst, hRsrc))) { + ret = MCI_SetCommandTable(LockResource(hMem), type); + } else { + WARN("Couldn't load resource.\n"); + } + TRACE("=> %04x\n", ret); + return ret; +} + +/************************************************************************** + * mciFreeCommandResource [WINMM.@] + */ +BOOL WINAPI mciFreeCommandResource(UINT uTable) +{ + TRACE("(%08x)!\n", uTable); + + return MCI_DeleteCommandTable(uTable, FALSE); +} + +/************************************************************************** + * MCI_SendCommandFrom32 [internal] + */ +DWORD MCI_SendCommandFrom32(MCIDEVICEID wDevID, UINT16 wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2) +{ + DWORD dwRet = MCIERR_INVALID_DEVICE_ID; + LPWINE_MCIDRIVER wmd = MCI_GetDriver(wDevID); + + if (wmd) { + if (wmd->bIs32) { + dwRet = SendDriverMessage(wmd->hDriver, wMsg, dwParam1, dwParam2); + } else if (pFnMciMapMsg32WTo16) { + WINMM_MapType res; + + switch (res = pFnMciMapMsg32WTo16(wmd->wType, wMsg, dwParam1, &dwParam2)) { + case WINMM_MAP_MSGERROR: + TRACE("Not handled yet (%s)\n", MCI_MessageToString(wMsg)); + dwRet = MCIERR_DRIVER_INTERNAL; + break; + case WINMM_MAP_NOMEM: + TRACE("Problem mapping msg=%s from 32a to 16\n", MCI_MessageToString(wMsg)); + dwRet = MCIERR_OUT_OF_MEMORY; + break; + case WINMM_MAP_OK: + case WINMM_MAP_OKMEM: + dwRet = SendDriverMessage(wmd->hDriver, wMsg, dwParam1, dwParam2); + if (res == WINMM_MAP_OKMEM) + pFnMciUnMapMsg32WTo16(wmd->wType, wMsg, dwParam1, dwParam2); + break; + } + } + } + return dwRet; +} + +/************************************************************************** + * MCI_SendCommandFrom16 [internal] + */ +DWORD MCI_SendCommandFrom16(MCIDEVICEID wDevID, UINT16 wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2) +{ + DWORD dwRet = MCIERR_INVALID_DEVICE_ID; + LPWINE_MCIDRIVER wmd = MCI_GetDriver(wDevID); + + if (wmd) { + dwRet = MCIERR_INVALID_DEVICE_ID; + + if (wmd->bIs32 && pFnMciMapMsg16To32W) { + WINMM_MapType res; + + switch (res = pFnMciMapMsg16To32W(wmd->wType, wMsg, &dwParam2)) { + case WINMM_MAP_MSGERROR: + TRACE("Not handled yet (%s)\n", MCI_MessageToString(wMsg)); + dwRet = MCIERR_DRIVER_INTERNAL; + break; + case WINMM_MAP_NOMEM: + TRACE("Problem mapping msg=%s from 16 to 32a\n", MCI_MessageToString(wMsg)); + dwRet = MCIERR_OUT_OF_MEMORY; + break; + case WINMM_MAP_OK: + case WINMM_MAP_OKMEM: + dwRet = SendDriverMessage(wmd->hDriver, wMsg, dwParam1, dwParam2); + if (res == WINMM_MAP_OKMEM) + pFnMciUnMapMsg16To32W(wmd->wType, wMsg, dwParam2); + break; + } + } else { + dwRet = SendDriverMessage(wmd->hDriver, wMsg, dwParam1, dwParam2); + } + } + return dwRet; +} + +/************************************************************************** + * MCI_Open [internal] + */ +static DWORD MCI_Open(DWORD dwParam, LPMCI_OPEN_PARMSW lpParms) +{ + WCHAR strDevTyp[128]; + DWORD dwRet; + LPWINE_MCIDRIVER wmd = NULL; + + TRACE("(%08lX, %p)\n", dwParam, lpParms); + if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK; + + /* only two low bytes are generic, the other ones are dev type specific */ +#define WINE_MCIDRIVER_SUPP (0xFFFF0000|MCI_OPEN_SHAREABLE|MCI_OPEN_ELEMENT| \ + MCI_OPEN_ALIAS|MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID| \ + MCI_NOTIFY|MCI_WAIT) + if ((dwParam & ~WINE_MCIDRIVER_SUPP) != 0) { + FIXME("Unsupported yet dwFlags=%08lX\n", dwParam & ~WINE_MCIDRIVER_SUPP); + } +#undef WINE_MCIDRIVER_SUPP + + strDevTyp[0] = 0; + + if (dwParam & MCI_OPEN_TYPE) { + if (dwParam & MCI_OPEN_TYPE_ID) { + WORD uDevType = LOWORD((DWORD)lpParms->lpstrDeviceType); + + if (uDevType < MCI_DEVTYPE_FIRST || + uDevType > MCI_DEVTYPE_LAST || + !LoadStringW(WINMM_IData.hWinMM32Instance, uDevType, + strDevTyp, sizeof(strDevTyp) / sizeof(WCHAR))) { + dwRet = MCIERR_BAD_INTEGER; + goto errCleanUp; + } + } else { + LPWSTR ptr; + if (lpParms->lpstrDeviceType == NULL) { + dwRet = MCIERR_NULL_PARAMETER_BLOCK; + goto errCleanUp; + } + strcpyW(strDevTyp, lpParms->lpstrDeviceType); + ptr = strchrW(strDevTyp, '!'); + if (ptr) { + /* this behavior is not documented in windows. However, since, in + * some occasions, MCI_OPEN handling is translated by WinMM into + * a call to mciSendString("open <type>"); this code shall be correct + */ + if (dwParam & MCI_OPEN_ELEMENT) { + ERR("Both MCI_OPEN_ELEMENT(%s) and %s are used\n", + debugstr_w(lpParms->lpstrElementName), + debugstr_w(strDevTyp)); + dwRet = MCIERR_UNRECOGNIZED_KEYWORD; + goto errCleanUp; + } + dwParam |= MCI_OPEN_ELEMENT; + *ptr++ = 0; + /* FIXME: not a good idea to write in user supplied buffer */ + lpParms->lpstrElementName = ptr; + } + + } + TRACE("devType=%s !\n", debugstr_w(strDevTyp)); + } + + if (dwParam & MCI_OPEN_ELEMENT) { + TRACE("lpstrElementName=%s\n", debugstr_w(lpParms->lpstrElementName)); + + if (dwParam & MCI_OPEN_ELEMENT_ID) { + FIXME("Unsupported yet flag MCI_OPEN_ELEMENT_ID\n"); + dwRet = MCIERR_UNRECOGNIZED_KEYWORD; + goto errCleanUp; + } + + if (!lpParms->lpstrElementName) { + dwRet = MCIERR_NULL_PARAMETER_BLOCK; + goto errCleanUp; + } + + /* type, if given as a parameter, supersedes file extension */ + if (!strDevTyp[0] && + MCI_GetDevTypeFromFileName(lpParms->lpstrElementName, + strDevTyp, sizeof(strDevTyp))) { + static const WCHAR wszCdAudio[] = {'C','D','A','U','D','I','O',0}; + if (GetDriveTypeW(lpParms->lpstrElementName) != DRIVE_CDROM) { + dwRet = MCIERR_EXTENSION_NOT_FOUND; + goto errCleanUp; + } + /* FIXME: this will not work if several CDROM drives are installed on the machine */ + strcpyW(strDevTyp, wszCdAudio); + } + } + + if (strDevTyp[0] == 0) { + FIXME("Couldn't load driver\n"); + dwRet = MCIERR_INVALID_DEVICE_NAME; + goto errCleanUp; + } + + if (dwParam & MCI_OPEN_ALIAS) { + TRACE("Alias=%s !\n", debugstr_w(lpParms->lpstrAlias)); + if (!lpParms->lpstrAlias) { + dwRet = MCIERR_NULL_PARAMETER_BLOCK; + goto errCleanUp; + } + } + + if ((dwRet = MCI_LoadMciDriver(strDevTyp, &wmd))) { + goto errCleanUp; + } + + if ((dwRet = MCI_FinishOpen(wmd, lpParms, dwParam))) { + TRACE("Failed to open driver (MCI_OPEN_DRIVER) [%08lx], closing\n", dwRet); + /* FIXME: is dwRet the correct ret code ? */ + goto errCleanUp; + } + + /* only handled devices fall through */ + TRACE("wDevID=%04X wDeviceID=%d dwRet=%ld\n", wmd->wDeviceID, lpParms->wDeviceID, dwRet); + + if (dwParam & MCI_NOTIFY) + mciDriverNotify((HWND)lpParms->dwCallback, wmd->wDeviceID, MCI_NOTIFY_SUCCESSFUL); + + return 0; +errCleanUp: + if (wmd) MCI_UnLoadMciDriver(wmd); + + if (dwParam & MCI_NOTIFY) + mciDriverNotify((HWND)lpParms->dwCallback, 0, MCI_NOTIFY_FAILURE); + return dwRet; +} + +/************************************************************************** + * MCI_Close [internal] + */ +static DWORD MCI_Close(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms) +{ + DWORD dwRet; + LPWINE_MCIDRIVER wmd; + + TRACE("(%04x, %08lX, %p)\n", wDevID, dwParam, lpParms); + + if (wDevID == MCI_ALL_DEVICE_ID) { + LPWINE_MCIDRIVER next; + + EnterCriticalSection(&WINMM_IData.cs); + /* FIXME: shall I notify once after all is done, or for + * each of the open drivers ? if the latest, which notif + * to return when only one fails ? + */ + for (wmd = WINMM_IData.lpMciDrvs; wmd; ) { + next = wmd->lpNext; + MCI_Close(wmd->wDeviceID, dwParam, lpParms); + wmd = next; + } + LeaveCriticalSection(&WINMM_IData.cs); + return 0; + } + + if (!(wmd = MCI_GetDriver(wDevID))) { + return MCIERR_INVALID_DEVICE_ID; + } + + dwRet = MCI_SendCommandFrom32(wDevID, MCI_CLOSE_DRIVER, dwParam, (DWORD)lpParms); + + MCI_UnLoadMciDriver(wmd); + + if (dwParam & MCI_NOTIFY) + mciDriverNotify((HWND)lpParms->dwCallback, wDevID, + (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE); + + return dwRet; +} + +/************************************************************************** + * MCI_WriteString [internal] + */ +DWORD MCI_WriteString(LPWSTR lpDstStr, DWORD dstSize, LPCWSTR lpSrcStr) +{ + DWORD ret = 0; + + if (lpSrcStr) { + dstSize /= sizeof(WCHAR); + if (dstSize <= strlenW(lpSrcStr)) { + lstrcpynW(lpDstStr, lpSrcStr, dstSize - 1); + ret = MCIERR_PARAM_OVERFLOW; + } else { + strcpyW(lpDstStr, lpSrcStr); + } + } else { + *lpDstStr = 0; + } + return ret; +} + +/************************************************************************** + * MCI_Sysinfo [internal] + */ +static DWORD MCI_SysInfo(UINT uDevID, DWORD dwFlags, LPMCI_SYSINFO_PARMSW lpParms) +{ + DWORD ret = MCIERR_INVALID_DEVICE_ID, cnt = 0; + WCHAR buf[2048], *s = buf, *p; + LPWINE_MCIDRIVER wmd; + HKEY hKey; + + if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK; + + TRACE("(%08x, %08lX, %08lX[num=%ld, wDevTyp=%u])\n", + uDevID, dwFlags, (DWORD)lpParms, lpParms->dwNumber, lpParms->wDeviceType); + + switch (dwFlags & ~MCI_SYSINFO_OPEN) { + case MCI_SYSINFO_QUANTITY: + if (lpParms->wDeviceType < MCI_DEVTYPE_FIRST || lpParms->wDeviceType > MCI_DEVTYPE_LAST) { + if (dwFlags & MCI_SYSINFO_OPEN) { + TRACE("MCI_SYSINFO_QUANTITY: # of open MCI drivers\n"); + EnterCriticalSection(&WINMM_IData.cs); + for (wmd = WINMM_IData.lpMciDrvs; wmd; wmd = wmd->lpNext) { + cnt++; + } + LeaveCriticalSection(&WINMM_IData.cs); + } else { + TRACE("MCI_SYSINFO_QUANTITY: # of installed MCI drivers\n"); + if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, wszHklmMci, + 0, KEY_QUERY_VALUE, &hKey ) == ERROR_SUCCESS) { + RegQueryInfoKeyW( hKey, 0, 0, 0, &cnt, 0, 0, 0, 0, 0, 0, 0); + RegCloseKey( hKey ); + } + if (GetPrivateProfileStringW(wszMci, 0, wszNull, buf, sizeof(buf) / sizeof(buf[0]), wszSystemIni)) + for (s = buf; *s; s += strlenW(s) + 1) cnt++; + } + } else { + if (dwFlags & MCI_SYSINFO_OPEN) { + TRACE("MCI_SYSINFO_QUANTITY: # of open MCI drivers of type %u\n", lpParms->wDeviceType); + EnterCriticalSection(&WINMM_IData.cs); + for (wmd = WINMM_IData.lpMciDrvs; wmd; wmd = wmd->lpNext) { + if (wmd->wType == lpParms->wDeviceType) cnt++; + } + LeaveCriticalSection(&WINMM_IData.cs); + } else { + TRACE("MCI_SYSINFO_QUANTITY: # of installed MCI drivers of type %u\n", lpParms->wDeviceType); + FIXME("Don't know how to get # of MCI devices of a given type\n"); + cnt = 1; + } + } + *(DWORD*)lpParms->lpstrReturn = cnt; + TRACE("(%ld) => '%ld'\n", lpParms->dwNumber, *(DWORD*)lpParms->lpstrReturn); + ret = MCI_INTEGER_RETURNED; + break; + case MCI_SYSINFO_INSTALLNAME: + TRACE("MCI_SYSINFO_INSTALLNAME \n"); + if ((wmd = MCI_GetDriver(uDevID))) { + ret = MCI_WriteString(lpParms->lpstrReturn, lpParms->dwRetSize, + wmd->lpstrDeviceType); + } else { + *lpParms->lpstrReturn = 0; + ret = MCIERR_INVALID_DEVICE_ID; + } + TRACE("(%ld) => %s\n", lpParms->dwNumber, debugstr_w(lpParms->lpstrReturn)); + break; + case MCI_SYSINFO_NAME: + TRACE("MCI_SYSINFO_NAME\n"); + if (dwFlags & MCI_SYSINFO_OPEN) { + FIXME("Don't handle MCI_SYSINFO_NAME|MCI_SYSINFO_OPEN (yet)\n"); + ret = MCIERR_UNRECOGNIZED_COMMAND; + } else { + s = NULL; + if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, wszHklmMci, 0, + KEY_QUERY_VALUE, &hKey ) == ERROR_SUCCESS) { + if (RegQueryInfoKeyW( hKey, 0, 0, 0, &cnt, + 0, 0, 0, 0, 0, 0, 0) == ERROR_SUCCESS && + lpParms->dwNumber <= cnt) { + DWORD bufLen = sizeof(buf); + if (RegEnumKeyExW(hKey, lpParms->dwNumber - 1, + buf, &bufLen, 0, 0, 0, 0) == ERROR_SUCCESS) + s = buf; + } + RegCloseKey( hKey ); + } + if (!s) { + if (GetPrivateProfileStringW(wszMci, 0, wszNull, buf, sizeof(buf) / sizeof(buf[0]), wszSystemIni)) { + for (p = buf; *p; p += strlenW(p) + 1, cnt++) { + TRACE("%ld: %s\n", cnt, debugstr_w(p)); + if (cnt == lpParms->dwNumber - 1) { + s = p; + break; + } + } + } + } + ret = s ? MCI_WriteString(lpParms->lpstrReturn, lpParms->dwRetSize / sizeof(WCHAR), s) : MCIERR_OUTOFRANGE; + } + TRACE("(%ld) => %s\n", lpParms->dwNumber, debugstr_w(lpParms->lpstrReturn)); + break; + default: + TRACE("Unsupported flag value=%08lx\n", dwFlags); + ret = MCIERR_UNRECOGNIZED_COMMAND; + } + return ret; +} + +/************************************************************************** + * MCI_Break [internal] + */ +static DWORD MCI_Break(UINT wDevID, DWORD dwFlags, LPMCI_BREAK_PARMS lpParms) +{ + DWORD dwRet = 0; + + if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK; + + if (dwFlags & MCI_NOTIFY) + mciDriverNotify((HWND)lpParms->dwCallback, wDevID, + (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE); + + return dwRet; +} + +/************************************************************************** + * MCI_Sound [internal] + */ +static DWORD MCI_Sound(UINT wDevID, DWORD dwFlags, LPMCI_SOUND_PARMSW lpParms) +{ + DWORD dwRet = 0; + + if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK; + + if (dwFlags & MCI_SOUND_NAME) + dwRet = sndPlaySoundW(lpParms->lpstrSoundName, SND_SYNC) ? MMSYSERR_NOERROR : MMSYSERR_ERROR; + else + dwRet = MMSYSERR_ERROR; /* what should be done ??? */ + if (dwFlags & MCI_NOTIFY) + mciDriverNotify((HWND)lpParms->dwCallback, wDevID, + (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE); + + return dwRet; +} + +/************************************************************************** + * MCI_SendCommand [internal] + */ +DWORD MCI_SendCommand(UINT wDevID, UINT16 wMsg, DWORD dwParam1, + DWORD dwParam2, BOOL bFrom32) +{ + DWORD dwRet = MCIERR_UNRECOGNIZED_COMMAND; + + switch (wMsg) { + case MCI_OPEN: + if (bFrom32) { + dwRet = MCI_Open(dwParam1, (LPMCI_OPEN_PARMSW)dwParam2); + } else if (pFnMciMapMsg16To32W) { + switch (pFnMciMapMsg16To32W(0, wMsg, &dwParam2)) { + case WINMM_MAP_OK: + case WINMM_MAP_OKMEM: + dwRet = MCI_Open(dwParam1, (LPMCI_OPEN_PARMSW)dwParam2); + pFnMciUnMapMsg16To32W(0, wMsg, dwParam2); + break; + default: break; /* so that gcc does not bark */ + } + } + break; + case MCI_CLOSE: + if (bFrom32) { + dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2); + } else if (pFnMciMapMsg16To32W) { + switch (pFnMciMapMsg16To32W(0, wMsg, &dwParam2)) { + case WINMM_MAP_OK: + case WINMM_MAP_OKMEM: + dwRet = MCI_Close(wDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2); + pFnMciUnMapMsg16To32W(0, wMsg, dwParam2); + break; + default: break; /* so that gcc does not bark */ + } + } + break; + case MCI_SYSINFO: + if (bFrom32) { + dwRet = MCI_SysInfo(wDevID, dwParam1, (LPMCI_SYSINFO_PARMSW)dwParam2); + } else if (pFnMciMapMsg16To32W) { + switch (pFnMciMapMsg16To32W(0, wMsg, &dwParam2)) { + case WINMM_MAP_OK: + case WINMM_MAP_OKMEM: + dwRet = MCI_SysInfo(wDevID, dwParam1, (LPMCI_SYSINFO_PARMSW)dwParam2); + pFnMciUnMapMsg16To32W(0, wMsg, dwParam2); + break; + default: break; /* so that gcc does not bark */ + } + } + break; + case MCI_BREAK: + if (bFrom32) { + dwRet = MCI_Break(wDevID, dwParam1, (LPMCI_BREAK_PARMS)dwParam2); + } else if (pFnMciMapMsg16To32W) { + switch (pFnMciMapMsg16To32W(0, wMsg, &dwParam2)) { + case WINMM_MAP_OK: + case WINMM_MAP_OKMEM: + dwRet = MCI_Break(wDevID, dwParam1, (LPMCI_BREAK_PARMS)dwParam2); + pFnMciUnMapMsg16To32W(0, wMsg, dwParam2); + break; + default: break; /* so that gcc does not bark */ + } + } + break; + case MCI_SOUND: + if (bFrom32) { + dwRet = MCI_Sound(wDevID, dwParam1, (LPMCI_SOUND_PARMSW)dwParam2); + } else if (pFnMciMapMsg16To32W) { + switch (pFnMciMapMsg16To32W(0, wMsg, &dwParam2)) { + case WINMM_MAP_OK: + case WINMM_MAP_OKMEM: + dwRet = MCI_Sound(wDevID, dwParam1, (LPMCI_SOUND_PARMSW)dwParam2); + pFnMciUnMapMsg16To32W(0, wMsg, dwParam2); + break; + default: break; /* so that gcc does not bark */ + } + } + break; + default: + if (wDevID == MCI_ALL_DEVICE_ID) { + FIXME("unhandled MCI_ALL_DEVICE_ID\n"); + dwRet = MCIERR_CANNOT_USE_ALL; + } else { + dwRet = (bFrom32) ? + MCI_SendCommandFrom32(wDevID, wMsg, dwParam1, dwParam2) : + MCI_SendCommandFrom16(wDevID, wMsg, dwParam1, dwParam2); + } + break; + } + return dwRet; +} + +/************************************************************************** + * MCI_CleanUp [internal] + * + * Some MCI commands need to be cleaned-up (when not called from + * mciSendString), because MCI drivers return extra information for string + * transformation. This function gets rid of them. + */ +LRESULT MCI_CleanUp(LRESULT dwRet, UINT wMsg, DWORD dwParam2) +{ + if (LOWORD(dwRet)) + return LOWORD(dwRet); + + switch (wMsg) { + case MCI_GETDEVCAPS: + switch (dwRet & 0xFFFF0000ul) { + case 0: + case MCI_COLONIZED3_RETURN: + case MCI_COLONIZED4_RETURN: + case MCI_INTEGER_RETURNED: + /* nothing to do */ + break; + case MCI_RESOURCE_RETURNED: + case MCI_RESOURCE_RETURNED|MCI_RESOURCE_DRIVER: + { + LPMCI_GETDEVCAPS_PARMS lmgp; + + lmgp = (LPMCI_GETDEVCAPS_PARMS)(void*)dwParam2; + TRACE("Changing %08lx to %08lx\n", lmgp->dwReturn, (DWORD)LOWORD(lmgp->dwReturn)); + lmgp->dwReturn = LOWORD(lmgp->dwReturn); + } + break; + default: + FIXME("Unsupported value for hiword (%04x) returned by DriverProc(%s)\n", + HIWORD(dwRet), MCI_MessageToString(wMsg)); + } + break; + case MCI_STATUS: + switch (dwRet & 0xFFFF0000ul) { + case 0: + case MCI_COLONIZED3_RETURN: + case MCI_COLONIZED4_RETURN: + case MCI_INTEGER_RETURNED: + /* nothing to do */ + break; + case MCI_RESOURCE_RETURNED: + case MCI_RESOURCE_RETURNED|MCI_RESOURCE_DRIVER: + { + LPMCI_STATUS_PARMS lsp; + + lsp = (LPMCI_STATUS_PARMS)(void*)dwParam2; + TRACE("Changing %08lx to %08lx\n", lsp->dwReturn, (DWORD)LOWORD(lsp->dwReturn)); + lsp->dwReturn = LOWORD(lsp->dwReturn); + } + break; + default: + FIXME("Unsupported value for hiword (%04x) returned by DriverProc(%s)\n", + HIWORD(dwRet), MCI_MessageToString(wMsg)); + } + break; + case MCI_SYSINFO: + switch (dwRet & 0xFFFF0000ul) { + case 0: + case MCI_INTEGER_RETURNED: + /* nothing to do */ + break; + default: + FIXME("Unsupported value for hiword (%04x)\n", HIWORD(dwRet)); + } + break; + default: + if (HIWORD(dwRet)) { + FIXME("Got non null hiword for dwRet=0x%08lx for command %s\n", + dwRet, MCI_MessageToString(wMsg)); + } + break; + } + return LOWORD(dwRet); +} + +/************************************************************************** + * mciGetErrorStringW [WINMM.@] + */ +BOOL WINAPI mciGetErrorStringW(MCIERROR wError, LPWSTR lpstrBuffer, UINT uLength) +{ + BOOL ret = FALSE; + + if (lpstrBuffer != NULL && uLength > 0 && + wError >= MCIERR_BASE && wError <= MCIERR_CUSTOM_DRIVER_BASE) { + + if (LoadStringW(WINMM_IData.hWinMM32Instance, + wError, lpstrBuffer, uLength) > 0) { + ret = TRUE; + } + } + return ret; +} + +/************************************************************************** + * mciGetErrorStringA [WINMM.@] + */ +BOOL WINAPI mciGetErrorStringA(MCIERROR dwError, LPSTR lpstrBuffer, UINT uLength) +{ + BOOL ret = FALSE; + + if (lpstrBuffer != NULL && uLength > 0 && + dwError >= MCIERR_BASE && dwError <= MCIERR_CUSTOM_DRIVER_BASE) { + + if (LoadStringA(WINMM_IData.hWinMM32Instance, + dwError, lpstrBuffer, uLength) > 0) { + ret = TRUE; + } + } + return ret; +} + +/************************************************************************** + * mciDriverNotify [WINMM.@] + */ +BOOL WINAPI mciDriverNotify(HWND hWndCallBack, MCIDEVICEID wDevID, UINT wStatus) +{ + TRACE("(%p, %04x, %04X)\n", hWndCallBack, wDevID, wStatus); + + return PostMessageW(hWndCallBack, MM_MCINOTIFY, wStatus, wDevID); +} + +/************************************************************************** + * mciGetDriverData [WINMM.@] + */ +DWORD WINAPI mciGetDriverData(MCIDEVICEID uDeviceID) +{ + LPWINE_MCIDRIVER wmd; + + TRACE("(%04x)\n", uDeviceID); + + wmd = MCI_GetDriver(uDeviceID); + + if (!wmd) { + WARN("Bad uDeviceID\n"); + return 0L; + } + + return wmd->dwPrivate; +} + +/************************************************************************** + * mciSetDriverData [WINMM.@] + */ +BOOL WINAPI mciSetDriverData(MCIDEVICEID uDeviceID, DWORD data) +{ + LPWINE_MCIDRIVER wmd; + + TRACE("(%04x, %08lx)\n", uDeviceID, data); + + wmd = MCI_GetDriver(uDeviceID); + + if (!wmd) { + WARN("Bad uDeviceID\n"); + return FALSE; + } + + wmd->dwPrivate = data; + return TRUE; +} + +/************************************************************************** + * mciSendCommandW [WINMM.@] + * + */ +DWORD WINAPI mciSendCommandW(MCIDEVICEID wDevID, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2) +{ + DWORD dwRet; + + TRACE("(%08x, %s, %08lx, %08lx)\n", + wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2); + + dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, TRUE); + dwRet = MCI_CleanUp(dwRet, wMsg, dwParam2); + TRACE("=> %08lx\n", dwRet); + return dwRet; +} + +/************************************************************************** + * mciSendCommandA [WINMM.@] + */ +DWORD WINAPI mciSendCommandA(MCIDEVICEID wDevID, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2) +{ + DWORD ret; + int mapped; + + TRACE("(%08x, %s, %08lx, %08lx)\n", + wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2); + + mapped = MCI_MapMsgAtoW(wMsg, dwParam1, &dwParam2); + if (mapped == -1) + { + FIXME("message %04x mapping failed\n", wMsg); + return MMSYSERR_NOMEM; + } + ret = mciSendCommandW(wDevID, wMsg, dwParam1, dwParam2); + if (mapped) + MCI_UnmapMsgAtoW(wMsg, dwParam1, dwParam2, ret); + return ret; +} + +/************************************************************************** + * mciGetDeviceIDA [WINMM.@] + */ +UINT WINAPI mciGetDeviceIDA(LPCSTR lpstrName) +{ + LPWSTR w = MCI_strdupAtoW(lpstrName); + UINT ret = MCIERR_OUT_OF_MEMORY; + + if (w) + { + ret = mciGetDeviceIDW(w); + HeapFree(GetProcessHeap(), 0, w); + } + return ret; +} + +/************************************************************************** + * mciGetDeviceIDW [WINMM.@] + */ +UINT WINAPI mciGetDeviceIDW(LPCWSTR lpwstrName) +{ + return MCI_GetDriverFromString(lpwstrName); +} + +/****************************************************************** + * MyUserYield + * + * Internal wrapper to call USER.UserYield16 (in fact through a Wine only export from USER32). + */ +static void MyUserYield(void) +{ + HMODULE mod = GetModuleHandleA( "user32.dll" ); + if (mod) + { + FARPROC proc = GetProcAddress( mod, "UserYield16" ); + if (proc) proc(); + } +} + +/************************************************************************** + * MCI_DefYieldProc [internal] + */ +UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data) +{ + INT16 ret; + + TRACE("(0x%04x, 0x%08lx)\n", wDevID, data); + + if ((HIWORD(data) != 0 && HWND_16(GetActiveWindow()) != HIWORD(data)) || + (GetAsyncKeyState(LOWORD(data)) & 1) == 0) { + MyUserYield(); + ret = 0; + } else { + MSG msg; + + msg.hwnd = HWND_32(HIWORD(data)); + while (!PeekMessageW(&msg, msg.hwnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)); + ret = -1; + } + return ret; +} + +/************************************************************************** + * mciSetYieldProc [WINMM.@] + */ +BOOL WINAPI mciSetYieldProc(MCIDEVICEID uDeviceID, YIELDPROC fpYieldProc, DWORD dwYieldData) +{ + LPWINE_MCIDRIVER wmd; + + TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData); + + if (!(wmd = MCI_GetDriver(uDeviceID))) { + WARN("Bad uDeviceID\n"); + return FALSE; + } + + wmd->lpfnYieldProc = fpYieldProc; + wmd->dwYieldData = dwYieldData; + wmd->bIs32 = TRUE; + + return TRUE; +} + +/************************************************************************** + * mciGetDeviceIDFromElementIDA [WINMM.@] + */ +UINT WINAPI mciGetDeviceIDFromElementIDA(DWORD dwElementID, LPCSTR lpstrType) +{ + LPWSTR w = MCI_strdupAtoW(lpstrType); + UINT ret = 0; + + if (w) + { + ret = mciGetDeviceIDFromElementIDW(dwElementID, w); + HeapFree(GetProcessHeap(), 0, w); + } + return ret; +} + +/************************************************************************** + * mciGetDeviceIDFromElementIDW [WINMM.@] + */ +UINT WINAPI mciGetDeviceIDFromElementIDW(DWORD dwElementID, LPCWSTR lpstrType) +{ + /* FIXME: that's rather strange, there is no + * mciGetDeviceIDFromElementID32A in winmm.spec + */ + FIXME("(%lu, %s) stub\n", dwElementID, debugstr_w(lpstrType)); + return 0; +} + +/************************************************************************** + * mciGetYieldProc [WINMM.@] + */ +YIELDPROC WINAPI mciGetYieldProc(MCIDEVICEID uDeviceID, DWORD* lpdwYieldData) +{ + LPWINE_MCIDRIVER wmd; + + TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData); + + if (!(wmd = MCI_GetDriver(uDeviceID))) { + WARN("Bad uDeviceID\n"); + return NULL; + } + if (!wmd->lpfnYieldProc) { + WARN("No proc set\n"); + return NULL; + } + if (!wmd->bIs32) { + WARN("Proc is 32 bit\n"); + return NULL; + } + return wmd->lpfnYieldProc; +} + +/************************************************************************** + * mciGetCreatorTask [WINMM.@] + */ +HTASK WINAPI mciGetCreatorTask(MCIDEVICEID uDeviceID) +{ + LPWINE_MCIDRIVER wmd; + HTASK ret = 0; + + if ((wmd = MCI_GetDriver(uDeviceID))) ret = (HTASK)wmd->CreatorThread; + + TRACE("(%u) => %p\n", uDeviceID, ret); + return ret; +} + +/************************************************************************** + * mciDriverYield [WINMM.@] + */ +UINT WINAPI mciDriverYield(MCIDEVICEID uDeviceID) +{ + LPWINE_MCIDRIVER wmd; + UINT ret = 0; + + TRACE("(%04x)\n", uDeviceID); + + if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || !wmd->bIs32) { + MyUserYield(); + } else { + ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData); + } + + return ret; +} diff --git a/reactos/lib/winmm/message16.c b/reactos/lib/winmm/message16.c index edeb65e77c9..f95de2ed975 100644 --- a/reactos/lib/winmm/message16.c +++ b/reactos/lib/winmm/message16.c @@ -1,3528 +1,3528 @@ -/* - * MMSYSTEM MCI and low level mapping functions - * - * Copyright 1999 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <string.h> -#include <stdarg.h> -#include <stdio.h> -#include <assert.h> -#include "wine/winbase16.h" -#include "windef.h" -#include "winbase.h" -#include "winreg.h" -#include "winver.h" -#include "wownt32.h" -#include "winemm16.h" -#include "digitalv.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(winmm); - -/************************************************************************** - * MMDRV_Callback [internal] - */ -static void MMDRV_Callback(LPWINE_MLD mld, HDRVR hDev, UINT uMsg, DWORD dwParam1, DWORD dwParam2) -{ - TRACE("CB (*%08lx)(%p %08x %08lx %08lx %08lx\n", - mld->dwCallback, hDev, uMsg, mld->dwClientInstance, dwParam1, dwParam2); - - if (!mld->bFrom32 && (mld->dwFlags & DCB_TYPEMASK) == DCB_FUNCTION) - { - WORD args[8]; - /* 16 bit func, call it */ - TRACE("Function (16 bit) !\n"); - - args[7] = HDRVR_16(hDev); - args[6] = uMsg; - args[5] = HIWORD(mld->dwClientInstance); - args[4] = LOWORD(mld->dwClientInstance); - args[3] = HIWORD(dwParam1); - args[2] = LOWORD(dwParam1); - args[1] = HIWORD(dwParam2); - args[0] = LOWORD(dwParam2); - WOWCallback16Ex( mld->dwCallback, WCB16_PASCAL, sizeof(args), args, NULL ); - } else { - DriverCallback(mld->dwCallback, mld->dwFlags, hDev, uMsg, - mld->dwClientInstance, dwParam1, dwParam2); - } -} - -/* ================================= - * A U X M A P P E R S - * ================================= */ - -/************************************************************************** - * MMDRV_Aux_Map16To32W [internal] - */ -static WINMM_MapType MMDRV_Aux_Map16To32W (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) -{ - return WINMM_MAP_MSGERROR; -} - -/************************************************************************** - * MMDRV_Aux_UnMap16To32W [internal] - */ -static WINMM_MapType MMDRV_Aux_UnMap16To32W(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) -{ - return WINMM_MAP_MSGERROR; -} - -/************************************************************************** - * MMDRV_Aux_Map32WTo16 [internal] - */ -static WINMM_MapType MMDRV_Aux_Map32WTo16 (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) -{ - return WINMM_MAP_MSGERROR; -} - -/************************************************************************** - * MMDRV_Aux_UnMap32WTo16 [internal] - */ -static WINMM_MapType MMDRV_Aux_UnMap32WTo16(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) -{ -#if 0 - case AUXDM_GETDEVCAPS: - lpCaps->wMid = ac16.wMid; - lpCaps->wPid = ac16.wPid; - lpCaps->vDriverVersion = ac16.vDriverVersion; - strcpy(lpCaps->szPname, ac16.szPname); - lpCaps->wTechnology = ac16.wTechnology; - lpCaps->dwSupport = ac16.dwSupport; -#endif - return WINMM_MAP_MSGERROR; -} - -/************************************************************************** - * MMDRV_Aux_Callback [internal] - */ -static void CALLBACK MMDRV_Aux_Callback(HDRVR hDev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) -{ - LPWINE_MLD mld = (LPWINE_MLD)dwInstance; - - FIXME("NIY\n"); - MMDRV_Callback(mld, hDev, uMsg, dwParam1, dwParam2); -} - -/* ================================= - * M I X E R M A P P E R S - * ================================= */ - -/************************************************************************** - * xMMDRV_Mixer_Map16To32W [internal] - */ -static WINMM_MapType MMDRV_Mixer_Map16To32W (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) -{ - return WINMM_MAP_MSGERROR; -} - -/************************************************************************** - * MMDRV_Mixer_UnMap16To32W [internal] - */ -static WINMM_MapType MMDRV_Mixer_UnMap16To32W(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) -{ -#if 0 - MIXERCAPSA micA; - UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA)); - - if (ret == MMSYSERR_NOERROR) { - mixcaps->wMid = micA.wMid; - mixcaps->wPid = micA.wPid; - mixcaps->vDriverVersion = micA.vDriverVersion; - strcpy(mixcaps->szPname, micA.szPname); - mixcaps->fdwSupport = micA.fdwSupport; - mixcaps->cDestinations = micA.cDestinations; - } - return ret; -#endif - return WINMM_MAP_MSGERROR; -} - -/************************************************************************** - * MMDRV_Mixer_Map32WTo16 [internal] - */ -static WINMM_MapType MMDRV_Mixer_Map32WTo16 (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) -{ - return WINMM_MAP_MSGERROR; -} - -/************************************************************************** - * MMDRV_Mixer_UnMap32WTo16 [internal] - */ -static WINMM_MapType MMDRV_Mixer_UnMap32WTo16(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) -{ - return WINMM_MAP_MSGERROR; -} - -/************************************************************************** - * MMDRV_Mixer_Callback [internal] - */ -static void CALLBACK MMDRV_Mixer_Callback(HDRVR hDev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) -{ - LPWINE_MLD mld = (LPWINE_MLD)dwInstance; - - FIXME("NIY\n"); - MMDRV_Callback(mld, hDev, uMsg, dwParam1, dwParam2); -} - -/* ================================= - * M I D I I N M A P P E R S - * ================================= */ - -/************************************************************************** - * MMDRV_MidiIn_Map16To32W [internal] - */ -static WINMM_MapType MMDRV_MidiIn_Map16To32W (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) -{ - return WINMM_MAP_MSGERROR; -} - -/************************************************************************** - * MMDRV_MidiIn_UnMap16To32W [internal] - */ -static WINMM_MapType MMDRV_MidiIn_UnMap16To32W(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) -{ - return WINMM_MAP_MSGERROR; -} - -/************************************************************************** - * MMDRV_MidiIn_Map32WTo16 [internal] - */ -static WINMM_MapType MMDRV_MidiIn_Map32WTo16 (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) -{ - return WINMM_MAP_MSGERROR; -} - -/************************************************************************** - * MMDRV_MidiIn_UnMap32WTo16 [internal] - */ -static WINMM_MapType MMDRV_MidiIn_UnMap32WTo16(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) -{ - return WINMM_MAP_MSGERROR; -} - -/************************************************************************** - * MMDRV_MidiIn_Callback [internal] - */ -static void CALLBACK MMDRV_MidiIn_Callback(HDRVR hDev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) -{ - LPWINE_MLD mld = (LPWINE_MLD)dwInstance; - - switch (uMsg) { - case MIM_OPEN: - case MIM_CLOSE: - /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ - - case MIM_DATA: - case MIM_MOREDATA: - case MIM_ERROR: - /* dwParam1 & dwParam2 are are data, nothing to do */ - break; - case MIM_LONGDATA: - case MIM_LONGERROR: - /* dwParam1 points to a MidiHdr, work to be done !!! */ - if (mld->bFrom32 && !MMDRV_Is32(mld->mmdIndex)) { - /* initial map is: 32 => 16 */ - LPMIDIHDR mh16 = MapSL(dwParam1); - LPMIDIHDR mh32 = *(LPMIDIHDR*)((LPSTR)mh16 - sizeof(LPMIDIHDR)); - - dwParam1 = (DWORD)mh32; - mh32->dwFlags = mh16->dwFlags; - mh32->dwBytesRecorded = mh16->dwBytesRecorded; - if (mh32->reserved >= sizeof(MIDIHDR)) - mh32->dwOffset = mh16->dwOffset; - } else if (!mld->bFrom32 && MMDRV_Is32(mld->mmdIndex)) { - /* initial map is: 16 => 32 */ - LPMIDIHDR mh32 = (LPMIDIHDR)(dwParam1); - SEGPTR segmh16 = *(SEGPTR*)((LPSTR)mh32 - sizeof(LPMIDIHDR)); - LPMIDIHDR mh16 = MapSL(segmh16); - - dwParam1 = (DWORD)segmh16; - mh16->dwFlags = mh32->dwFlags; - mh16->dwBytesRecorded = mh32->dwBytesRecorded; - if (mh16->reserved >= sizeof(MIDIHDR)) - mh16->dwOffset = mh32->dwOffset; - } - /* else { 16 => 16 or 32 => 32, nothing to do, same struct is kept }*/ - break; - /* case MOM_POSITIONCB: */ - default: - ERR("Unknown msg %u\n", uMsg); - } - - MMDRV_Callback(mld, hDev, uMsg, dwParam1, dwParam2); -} - -/* ================================= - * M I D I O U T M A P P E R S - * ================================= */ - -/************************************************************************** - * MMDRV_MidiOut_Map16To32W [internal] - */ -static WINMM_MapType MMDRV_MidiOut_Map16To32W (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) -{ - WINMM_MapType ret = WINMM_MAP_MSGERROR; - - switch (wMsg) { - case MODM_GETNUMDEVS: - case MODM_DATA: - case MODM_RESET: - case MODM_SETVOLUME: - ret = WINMM_MAP_OK; - break; - - case MODM_OPEN: - case MODM_CLOSE: - case MODM_GETVOLUME: - FIXME("Shouldn't be used: the corresponding 16 bit functions use the 32 bit interface\n"); - break; - - case MODM_GETDEVCAPS: - { - LPMIDIOUTCAPSW moc32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPMIDIOUTCAPS16) + sizeof(MIDIOUTCAPSW)); - LPMIDIOUTCAPS16 moc16 = MapSL(*lpParam1); - - if (moc32) { - *(LPMIDIOUTCAPS16*)moc32 = moc16; - moc32 = (LPMIDIOUTCAPSW)((LPSTR)moc32 + sizeof(LPMIDIOUTCAPS16)); - *lpParam1 = (DWORD)moc32; - *lpParam2 = sizeof(MIDIOUTCAPSW); - - ret = WINMM_MAP_OKMEM; - } else { - ret = WINMM_MAP_NOMEM; - } - } - break; - case MODM_PREPARE: - { - LPMIDIHDR mh32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPMIDIHDR) + sizeof(MIDIHDR)); - LPMIDIHDR mh16 = MapSL(*lpParam1); - - if (mh32) { - *(LPMIDIHDR*)mh32 = (LPMIDIHDR)*lpParam1; - mh32 = (LPMIDIHDR)((LPSTR)mh32 + sizeof(LPMIDIHDR)); - mh32->lpData = MapSL((SEGPTR)mh16->lpData); - mh32->dwBufferLength = mh16->dwBufferLength; - mh32->dwBytesRecorded = mh16->dwBytesRecorded; - mh32->dwUser = mh16->dwUser; - mh32->dwFlags = mh16->dwFlags; - /* FIXME: nothing on mh32->lpNext */ - /* could link the mh32->lpNext at this level for memory house keeping */ - mh32->dwOffset = (*lpParam2 >= sizeof(MIDIHDR)) ? ((LPMIDIHDR)mh16)->dwOffset : 0; - mh16->lpNext = mh32; /* for reuse in unprepare and write */ - /* store size of passed MIDIHDR?? structure to know if dwOffset is available or not */ - mh16->reserved = *lpParam2; - *lpParam1 = (DWORD)mh32; - *lpParam2 = sizeof(MIDIHDR); - - ret = WINMM_MAP_OKMEM; - } else { - ret = WINMM_MAP_NOMEM; - } - } - break; - case MODM_UNPREPARE: - case MODM_LONGDATA: - { - LPMIDIHDR mh16 = MapSL(*lpParam1); - LPMIDIHDR mh32 = (LPMIDIHDR)mh16->lpNext; - - *lpParam1 = (DWORD)mh32; - *lpParam2 = sizeof(MIDIHDR); - /* dwBufferLength can be reduced between prepare & write */ - if (wMsg == MODM_LONGDATA && mh32->dwBufferLength < mh16->dwBufferLength) { - ERR("Size of buffer has been increased from %ld to %ld, keeping initial value\n", - mh32->dwBufferLength, mh16->dwBufferLength); - } else - mh32->dwBufferLength = mh16->dwBufferLength; - ret = WINMM_MAP_OKMEM; - } - break; - - case MODM_CACHEPATCHES: - case MODM_CACHEDRUMPATCHES: - default: - FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); - break; - } - return ret; -} - -/************************************************************************** - * MMDRV_MidiOut_UnMap16To32W [internal] - */ -static WINMM_MapType MMDRV_MidiOut_UnMap16To32W(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) -{ - WINMM_MapType ret = WINMM_MAP_MSGERROR; - - switch (wMsg) { - case MODM_GETNUMDEVS: - case MODM_DATA: - case MODM_RESET: - case MODM_SETVOLUME: - ret = WINMM_MAP_OK; - break; - - case MODM_OPEN: - case MODM_CLOSE: - case MODM_GETVOLUME: - FIXME("Shouldn't be used: the corresponding 16 bit functions use the 32 bit interface\n"); - break; - - case MODM_GETDEVCAPS: - { - LPMIDIOUTCAPSW moc32 = (LPMIDIOUTCAPSW)(*lpParam1); - LPMIDIOUTCAPS16 moc16 = *(LPMIDIOUTCAPS16*)((LPSTR)moc32 - sizeof(LPMIDIOUTCAPS16)); - - moc16->wMid = moc32->wMid; - moc16->wPid = moc32->wPid; - moc16->vDriverVersion = moc32->vDriverVersion; - WideCharToMultiByte( CP_ACP, 0, moc32->szPname, -1, moc16->szPname, - sizeof(moc16->szPname), NULL, NULL ); - moc16->wTechnology = moc32->wTechnology; - moc16->wVoices = moc32->wVoices; - moc16->wNotes = moc32->wNotes; - moc16->wChannelMask = moc32->wChannelMask; - moc16->dwSupport = moc32->dwSupport; - HeapFree(GetProcessHeap(), 0, (LPSTR)moc32 - sizeof(LPMIDIOUTCAPS16)); - ret = WINMM_MAP_OK; - } - break; - case MODM_PREPARE: - case MODM_UNPREPARE: - case MODM_LONGDATA: - { - LPMIDIHDR mh32 = (LPMIDIHDR)(*lpParam1); - LPMIDIHDR mh16 = MapSL(*(SEGPTR*)((LPSTR)mh32 - sizeof(LPMIDIHDR))); - - assert(mh16->lpNext == mh32); - mh16->dwBufferLength = mh32->dwBufferLength; - mh16->dwBytesRecorded = mh32->dwBytesRecorded; - mh16->dwUser = mh32->dwUser; - mh16->dwFlags = mh32->dwFlags; - if (mh16->reserved >= sizeof(MIDIHDR)) - mh16->dwOffset = mh32->dwOffset; - - if (wMsg == MODM_UNPREPARE && fn_ret == MMSYSERR_NOERROR) { - HeapFree(GetProcessHeap(), 0, (LPSTR)mh32 - sizeof(LPMIDIHDR)); - mh16->lpNext = 0; - } - ret = WINMM_MAP_OK; - } - break; - - case MODM_CACHEPATCHES: - case MODM_CACHEDRUMPATCHES: - default: - FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); - break; - } - return ret; -} - -/************************************************************************** - * MMDRV_MidiOut_Map32WTo16 [internal] - */ -static WINMM_MapType MMDRV_MidiOut_Map32WTo16 (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) -{ - WINMM_MapType ret = WINMM_MAP_MSGERROR; - - switch (wMsg) { - case MODM_CLOSE: - case MODM_GETNUMDEVS: - case MODM_DATA: - case MODM_RESET: - case MODM_SETVOLUME: - ret = WINMM_MAP_OK; - break; - case MODM_GETDEVCAPS: - { - LPMIDIOUTCAPSW moc32 = (LPMIDIOUTCAPSW)*lpParam1; - LPSTR ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(LPMIDIOUTCAPSW)+sizeof(MIDIOUTCAPS16)); - - if (ptr) { - *(LPMIDIOUTCAPSW*)ptr = moc32; - ret = WINMM_MAP_OKMEM; - } else { - ret = WINMM_MAP_NOMEM; - } - *lpParam1 = (DWORD)MapLS(ptr) + sizeof(LPMIDIOUTCAPSW); - *lpParam2 = sizeof(MIDIOUTCAPS16); - } - break; - case MODM_PREPARE: - { - LPMIDIHDR mh32 = (LPMIDIHDR)*lpParam1; - LPMIDIHDR mh16; - LPVOID ptr = HeapAlloc( GetProcessHeap(), 0, - sizeof(LPMIDIHDR) + sizeof(MIDIHDR) + mh32->dwBufferLength); - - if (ptr) { - *(LPMIDIHDR*)ptr = mh32; - mh16 = (LPMIDIHDR)((LPSTR)ptr + sizeof(LPMIDIHDR)); - *lpParam1 = MapLS(mh16); - mh16->lpData = (LPSTR)*lpParam1 + sizeof(MIDIHDR); - /* data will be copied on WODM_WRITE */ - mh16->dwBufferLength = mh32->dwBufferLength; - mh16->dwBytesRecorded = mh32->dwBytesRecorded; - mh16->dwUser = mh32->dwUser; - mh16->dwFlags = mh32->dwFlags; - /* FIXME: nothing on mh32->lpNext */ - /* could link the mh32->lpNext at this level for memory house keeping */ - mh16->dwOffset = (*lpParam2 >= sizeof(MIDIHDR)) ? mh32->dwOffset : 0; - - mh32->lpNext = (LPMIDIHDR)mh16; /* for reuse in unprepare and write */ - mh32->reserved = *lpParam2; - - TRACE("mh16=%08lx mh16->lpData=%08lx mh32->buflen=%lu mh32->lpData=%08lx\n", - *lpParam1, (DWORD)mh16->lpData, - mh32->dwBufferLength, (DWORD)mh32->lpData); - *lpParam2 = sizeof(MIDIHDR); - - ret = WINMM_MAP_OKMEM; - } else { - ret = WINMM_MAP_NOMEM; - } - } - break; - case MODM_UNPREPARE: - case MODM_LONGDATA: - { - LPMIDIHDR mh32 = (LPMIDIHDR)(*lpParam1); - LPMIDIHDR mh16 = (LPMIDIHDR)mh32->lpNext; - LPSTR ptr = (LPSTR)mh16 - sizeof(LPMIDIHDR); - - assert(*(LPMIDIHDR*)ptr == mh32); - - if (wMsg == MODM_LONGDATA) - memcpy((LPSTR)mh16 + sizeof(MIDIHDR), mh32->lpData, mh32->dwBufferLength); - - *lpParam1 = MapLS(mh16); - *lpParam2 = sizeof(MIDIHDR); - TRACE("mh16=%08lx mh16->lpData=%08lx mh32->buflen=%lu mh32->lpData=%08lx\n", - *lpParam1, (DWORD)mh16->lpData, mh32->dwBufferLength, (DWORD)mh32->lpData); - - /* dwBufferLength can be reduced between prepare & write */ - if (wMsg == MODM_LONGDATA && mh16->dwBufferLength < mh32->dwBufferLength) { - ERR("Size of buffer has been increased from %ld to %ld, keeping initial value\n", - mh16->dwBufferLength, mh32->dwBufferLength); - } else - mh16->dwBufferLength = mh32->dwBufferLength; - ret = WINMM_MAP_OKMEM; - } - break; - case MODM_OPEN: - { - LPMIDIOPENDESC mod32 = (LPMIDIOPENDESC)*lpParam1; - LPVOID ptr; - LPMIDIOPENDESC16 mod16; - - /* allocated data are mapped as follows: - LPMIDIOPENDESC ptr to orig lParam1 - DWORD orig dwUser, which is a pointer to DWORD:driver dwInstance - DWORD dwUser passed to driver - MIDIOPENDESC16 mod16: openDesc passed to driver - MIDIOPENSTRMID cIds - */ - ptr = HeapAlloc( GetProcessHeap(), 0, - sizeof(LPMIDIOPENDESC) + 2*sizeof(DWORD) + sizeof(MIDIOPENDESC16) + - mod32->cIds ? (mod32->cIds - 1) * sizeof(MIDIOPENSTRMID) : 0); - - if (ptr) { - SEGPTR segptr = MapLS(ptr); - *(LPMIDIOPENDESC*)ptr = mod32; - *(LPDWORD)((char*)ptr + sizeof(LPMIDIOPENDESC)) = *lpdwUser; - mod16 = (LPMIDIOPENDESC16)((LPSTR)ptr + sizeof(LPMIDIOPENDESC) + 2*sizeof(DWORD)); - - mod16->hMidi = HMIDI_16(mod32->hMidi); - mod16->dwCallback = mod32->dwCallback; - mod16->dwInstance = mod32->dwInstance; - mod16->dnDevNode = mod32->dnDevNode; - mod16->cIds = mod32->cIds; - memcpy(&mod16->rgIds, &mod32->rgIds, mod32->cIds * sizeof(MIDIOPENSTRMID)); - - *lpParam1 = (DWORD)segptr + sizeof(LPMIDIOPENDESC) + 2*sizeof(DWORD); - *lpdwUser = (DWORD)segptr + sizeof(LPMIDIOPENDESC) + sizeof(DWORD); - - ret = WINMM_MAP_OKMEM; - } else { - ret = WINMM_MAP_NOMEM; - } - } - break; - case MODM_GETVOLUME: - case MODM_CACHEPATCHES: - case MODM_CACHEDRUMPATCHES: - default: - FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); - break; - } - return ret; -} - -/************************************************************************** - * MMDRV_MidiOut_UnMap32WTo16 [internal] - */ -static WINMM_MapType MMDRV_MidiOut_UnMap32WTo16(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) -{ - WINMM_MapType ret = WINMM_MAP_MSGERROR; - - switch (wMsg) { - case MODM_CLOSE: - case MODM_GETNUMDEVS: - case MODM_DATA: - case MODM_RESET: - case MODM_SETVOLUME: - ret = WINMM_MAP_OK; - break; - case MODM_GETDEVCAPS: - { - LPMIDIOUTCAPS16 moc16 = MapSL(*lpParam1); - LPSTR ptr = (LPSTR)moc16 - sizeof(LPMIDIOUTCAPSW); - LPMIDIOUTCAPSW moc32 = *(LPMIDIOUTCAPSW*)ptr; - - moc32->wMid = moc16->wMid; - moc32->wPid = moc16->wPid; - moc32->vDriverVersion = moc16->vDriverVersion; - WideCharToMultiByte( CP_ACP, 0, moc32->szPname, -1, moc16->szPname, - sizeof(moc16->szPname), NULL, NULL ); - moc32->wTechnology = moc16->wTechnology; - moc32->wVoices = moc16->wVoices; - moc32->wNotes = moc16->wNotes; - moc32->wChannelMask = moc16->wChannelMask; - moc32->dwSupport = moc16->dwSupport; - UnMapLS( *lpParam1 ); - HeapFree( GetProcessHeap(), 0, ptr ); - ret = WINMM_MAP_OK; - } - break; - case MODM_PREPARE: - case MODM_UNPREPARE: - case MODM_LONGDATA: - { - LPMIDIHDR mh16 = MapSL(*lpParam1); - LPSTR ptr = (LPSTR)mh16 - sizeof(LPMIDIHDR); - LPMIDIHDR mh32 = *(LPMIDIHDR*)ptr; - - assert(mh32->lpNext == (LPMIDIHDR)mh16); - UnMapLS( *lpParam1 ); - mh32->dwBytesRecorded = mh16->dwBytesRecorded; - mh32->dwUser = mh16->dwUser; - mh32->dwFlags = mh16->dwFlags; - - if (wMsg == MODM_UNPREPARE && fn_ret == MMSYSERR_NOERROR) { - HeapFree( GetProcessHeap(), 0, ptr ); - mh32->lpNext = 0; - } - ret = WINMM_MAP_OK; - } - break; - case MODM_OPEN: - { - LPMIDIOPENDESC16 mod16 = MapSL(*lpParam1); - LPSTR ptr = (LPSTR)mod16 - sizeof(LPMIDIOPENDESC) - 2*sizeof(DWORD); - UnMapLS( *lpParam1 ); - **(DWORD**)(ptr + sizeof(LPMIDIOPENDESC)) = *(LPDWORD)(ptr + sizeof(LPMIDIOPENDESC) + sizeof(DWORD)); - - HeapFree( GetProcessHeap(), 0, ptr ); - ret = WINMM_MAP_OK; - } - break; - case MODM_GETVOLUME: - case MODM_CACHEPATCHES: - case MODM_CACHEDRUMPATCHES: - default: - FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); - break; - } - return ret; -} - -/************************************************************************** - * MMDRV_MidiOut_Callback [internal] - */ -static void CALLBACK MMDRV_MidiOut_Callback(HDRVR hDev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) -{ - LPWINE_MLD mld = (LPWINE_MLD)dwInstance; - - switch (uMsg) { - case MOM_OPEN: - case MOM_CLOSE: - /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ - break; - case MOM_DONE: - if (mld->bFrom32 && !MMDRV_Is32(mld->mmdIndex)) { - /* initial map is: 32 => 16 */ - LPMIDIHDR mh16 = MapSL(dwParam1); - LPMIDIHDR mh32 = *(LPMIDIHDR*)((LPSTR)mh16 - sizeof(LPMIDIHDR)); - - dwParam1 = (DWORD)mh32; - mh32->dwFlags = mh16->dwFlags; - mh32->dwOffset = mh16->dwOffset; - if (mh32->reserved >= sizeof(MIDIHDR)) - mh32->dwOffset = mh16->dwOffset; - } else if (!mld->bFrom32 && MMDRV_Is32(mld->mmdIndex)) { - /* initial map is: 16 => 32 */ - LPMIDIHDR mh32 = (LPMIDIHDR)(dwParam1); - SEGPTR segmh16 = *(SEGPTR*)((LPSTR)mh32 - sizeof(LPMIDIHDR)); - LPMIDIHDR mh16 = MapSL(segmh16); - - dwParam1 = (DWORD)segmh16; - mh16->dwFlags = mh32->dwFlags; - if (mh16->reserved >= sizeof(MIDIHDR)) - mh16->dwOffset = mh32->dwOffset; - } - /* else { 16 => 16 or 32 => 32, nothing to do, same struct is kept }*/ - break; - /* case MOM_POSITIONCB: */ - default: - ERR("Unknown msg %u\n", uMsg); - } - - MMDRV_Callback(mld, hDev, uMsg, dwParam1, dwParam2); -} - -/* ================================= - * W A V E I N M A P P E R S - * ================================= */ - -/************************************************************************** - * MMDRV_WaveIn_Map16To32W [internal] - */ -static WINMM_MapType MMDRV_WaveIn_Map16To32W (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) -{ - WINMM_MapType ret = WINMM_MAP_MSGERROR; - - switch (wMsg) { - case WIDM_GETNUMDEVS: - case WIDM_RESET: - case WIDM_START: - case WIDM_STOP: - ret = WINMM_MAP_OK; - break; - case WIDM_OPEN: - case WIDM_CLOSE: - FIXME("Shouldn't be used: the corresponding 16 bit functions use the 32 bit interface\n"); - break; - case WIDM_GETDEVCAPS: - { - LPWAVEINCAPSW wic32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPWAVEINCAPS16) + sizeof(WAVEINCAPSW)); - LPWAVEINCAPS16 wic16 = MapSL(*lpParam1); - - if (wic32) { - *(LPWAVEINCAPS16*)wic32 = wic16; - wic32 = (LPWAVEINCAPSW)((LPSTR)wic32 + sizeof(LPWAVEINCAPS16)); - *lpParam1 = (DWORD)wic32; - *lpParam2 = sizeof(WAVEINCAPSW); - - ret = WINMM_MAP_OKMEM; - } else { - ret = WINMM_MAP_NOMEM; - } - } - break; - case WIDM_GETPOS: - { - LPMMTIME mmt32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPMMTIME16) + sizeof(MMTIME)); - LPMMTIME16 mmt16 = MapSL(*lpParam1); - - if (mmt32) { - *(LPMMTIME16*)mmt32 = mmt16; - mmt32 = (LPMMTIME)((LPSTR)mmt32 + sizeof(LPMMTIME16)); - - mmt32->wType = mmt16->wType; - *lpParam1 = (DWORD)mmt32; - *lpParam2 = sizeof(MMTIME); - - ret = WINMM_MAP_OKMEM; - } else { - ret = WINMM_MAP_NOMEM; - } - } - break; - case WIDM_PREPARE: - { - LPWAVEHDR wh32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPWAVEHDR) + sizeof(WAVEHDR)); - LPWAVEHDR wh16 = MapSL(*lpParam1); - - if (wh32) { - *(LPWAVEHDR*)wh32 = (LPWAVEHDR)*lpParam1; - wh32 = (LPWAVEHDR)((LPSTR)wh32 + sizeof(LPWAVEHDR)); - wh32->lpData = MapSL((SEGPTR)wh16->lpData); - wh32->dwBufferLength = wh16->dwBufferLength; - wh32->dwBytesRecorded = wh16->dwBytesRecorded; - wh32->dwUser = wh16->dwUser; - wh32->dwFlags = wh16->dwFlags; - wh32->dwLoops = wh16->dwLoops; - /* FIXME: nothing on wh32->lpNext */ - /* could link the wh32->lpNext at this level for memory house keeping */ - wh16->lpNext = wh32; /* for reuse in unprepare and write */ - *lpParam1 = (DWORD)wh32; - *lpParam2 = sizeof(WAVEHDR); - - ret = WINMM_MAP_OKMEM; - } else { - ret = WINMM_MAP_NOMEM; - } - } - break; - case WIDM_ADDBUFFER: - case WIDM_UNPREPARE: - { - LPWAVEHDR wh16 = MapSL(*lpParam1); - LPWAVEHDR wh32 = (LPWAVEHDR)wh16->lpNext; - - *lpParam1 = (DWORD)wh32; - *lpParam2 = sizeof(WAVEHDR); - /* dwBufferLength can be reduced between prepare & write */ - if (wMsg == WIDM_ADDBUFFER && wh32->dwBufferLength < wh16->dwBufferLength) { - ERR("Size of buffer has been increased from %ld to %ld, keeping initial value\n", - wh32->dwBufferLength, wh16->dwBufferLength); - } else - wh32->dwBufferLength = wh16->dwBufferLength; - ret = WINMM_MAP_OKMEM; - } - break; - case WIDM_MAPPER_STATUS: - /* just a single DWORD */ - *lpParam2 = (DWORD)MapSL(*lpParam2); - ret = WINMM_MAP_OK; - break; - default: - FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); - break; - } - return ret; -} - -/************************************************************************** - * MMDRV_WaveIn_UnMap16To32W [internal] - */ -static WINMM_MapType MMDRV_WaveIn_UnMap16To32W(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) -{ - WINMM_MapType ret = WINMM_MAP_MSGERROR; - - switch (wMsg) { - case WIDM_GETNUMDEVS: - case WIDM_RESET: - case WIDM_START: - case WIDM_STOP: - case WIDM_MAPPER_STATUS: - ret = WINMM_MAP_OK; - break; - case WIDM_OPEN: - case WIDM_CLOSE: - FIXME("Shouldn't be used: the corresponding 16 bit functions use the 32 bit interface\n"); - break; - case WIDM_GETDEVCAPS: - { - LPWAVEINCAPSW wic32 = (LPWAVEINCAPSW)(*lpParam1); - LPWAVEINCAPS16 wic16 = *(LPWAVEINCAPS16*)((LPSTR)wic32 - sizeof(LPWAVEINCAPS16)); - - wic16->wMid = wic32->wMid; - wic16->wPid = wic32->wPid; - wic16->vDriverVersion = wic32->vDriverVersion; - WideCharToMultiByte( CP_ACP, 0, wic32->szPname, -1, wic16->szPname, - sizeof(wic16->szPname), NULL, NULL ); - wic16->dwFormats = wic32->dwFormats; - wic16->wChannels = wic32->wChannels; - HeapFree(GetProcessHeap(), 0, (LPSTR)wic32 - sizeof(LPWAVEINCAPS16)); - ret = WINMM_MAP_OK; - } - break; - case WIDM_GETPOS: - { - LPMMTIME mmt32 = (LPMMTIME)(*lpParam1); - LPMMTIME16 mmt16 = *(LPMMTIME16*)((LPSTR)mmt32 - sizeof(LPMMTIME16)); - - MMSYSTEM_MMTIME32to16(mmt16, mmt32); - HeapFree(GetProcessHeap(), 0, (LPSTR)mmt32 - sizeof(LPMMTIME16)); - ret = WINMM_MAP_OK; - } - break; - case WIDM_ADDBUFFER: - case WIDM_PREPARE: - case WIDM_UNPREPARE: - { - LPWAVEHDR wh32 = (LPWAVEHDR)(*lpParam1); - LPWAVEHDR wh16 = MapSL(*(SEGPTR*)((LPSTR)wh32 - sizeof(LPWAVEHDR))); - - assert(wh16->lpNext == wh32); - wh16->dwBufferLength = wh32->dwBufferLength; - wh16->dwBytesRecorded = wh32->dwBytesRecorded; - wh16->dwUser = wh32->dwUser; - wh16->dwFlags = wh32->dwFlags; - wh16->dwLoops = wh32->dwLoops; - - if (wMsg == WIDM_UNPREPARE && fn_ret == MMSYSERR_NOERROR) { - HeapFree(GetProcessHeap(), 0, (LPSTR)wh32 - sizeof(LPWAVEHDR)); - wh16->lpNext = 0; - } - ret = WINMM_MAP_OK; - } - break; - default: - FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); - break; - } - return ret; -} - -/************************************************************************** - * MMDRV_WaveIn_Map32WTo16 [internal] - */ -static WINMM_MapType MMDRV_WaveIn_Map32WTo16 (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) -{ - WINMM_MapType ret = WINMM_MAP_MSGERROR; - - switch (wMsg) { - case WIDM_CLOSE: - case WIDM_GETNUMDEVS: - case WIDM_RESET: - case WIDM_START: - case WIDM_STOP: - ret = WINMM_MAP_OK; - break; - - case WIDM_OPEN: - { - LPWAVEOPENDESC wod32 = (LPWAVEOPENDESC)*lpParam1; - int sz = sizeof(WAVEFORMATEX); - LPVOID ptr; - LPWAVEOPENDESC16 wod16; - - /* allocated data are mapped as follows: - LPWAVEOPENDESC ptr to orig lParam1 - DWORD orig dwUser, which is a pointer to DWORD:driver dwInstance - DWORD dwUser passed to driver - WAVEOPENDESC16 wod16: openDesc passed to driver - WAVEFORMATEX openDesc->lpFormat passed to driver - xxx extra bytes to WAVEFORMATEX - */ - if (wod32->lpFormat->wFormatTag != WAVE_FORMAT_PCM) { - TRACE("Allocating %u extra bytes (%d)\n", ((LPWAVEFORMATEX)wod32->lpFormat)->cbSize, wod32->lpFormat->wFormatTag); - sz += ((LPWAVEFORMATEX)wod32->lpFormat)->cbSize; - } - - ptr = HeapAlloc( GetProcessHeap(), 0, - sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD) + sizeof(WAVEOPENDESC16) + sz); - - if (ptr) { - SEGPTR seg_ptr = MapLS( ptr ); - *(LPWAVEOPENDESC*)ptr = wod32; - *(LPDWORD)((char*)ptr + sizeof(LPWAVEOPENDESC)) = *lpdwUser; - wod16 = (LPWAVEOPENDESC16)((LPSTR)ptr + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD)); - - wod16->hWave = HWAVE_16(wod32->hWave); - wod16->lpFormat = (LPWAVEFORMATEX)(seg_ptr + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD) + sizeof(WAVEOPENDESC16)); - memcpy(wod16 + 1, wod32->lpFormat, sz); - - wod16->dwCallback = wod32->dwCallback; - wod16->dwInstance = wod32->dwInstance; - wod16->uMappedDeviceID = wod32->uMappedDeviceID; - wod16->dnDevNode = wod32->dnDevNode; - - *lpParam1 = seg_ptr + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD); - *lpdwUser = seg_ptr + sizeof(LPWAVEOPENDESC) + sizeof(DWORD); - - ret = WINMM_MAP_OKMEM; - } else { - ret = WINMM_MAP_NOMEM; - } - } - break; - case WIDM_PREPARE: - { - LPWAVEHDR wh32 = (LPWAVEHDR)*lpParam1; - LPWAVEHDR wh16; - LPVOID ptr = HeapAlloc( GetProcessHeap(), 0, - sizeof(LPWAVEHDR) + sizeof(WAVEHDR) + wh32->dwBufferLength); - - if (ptr) { - SEGPTR seg_ptr = MapLS( ptr ); - *(LPWAVEHDR*)ptr = wh32; - wh16 = (LPWAVEHDR)((LPSTR)ptr + sizeof(LPWAVEHDR)); - wh16->lpData = (LPSTR)seg_ptr + sizeof(LPWAVEHDR) + sizeof(WAVEHDR); - /* data will be copied on WODM_WRITE */ - wh16->dwBufferLength = wh32->dwBufferLength; - wh16->dwBytesRecorded = wh32->dwBytesRecorded; - wh16->dwUser = wh32->dwUser; - wh16->dwFlags = wh32->dwFlags; - wh16->dwLoops = wh32->dwLoops; - /* FIXME: nothing on wh32->lpNext */ - /* could link the wh32->lpNext at this level for memory house keeping */ - wh32->lpNext = wh16; /* for reuse in unprepare and write */ - TRACE("wh16=%08lx wh16->lpData=%08lx wh32->buflen=%lu wh32->lpData=%08lx\n", - seg_ptr + sizeof(LPWAVEHDR), (DWORD)wh16->lpData, - wh32->dwBufferLength, (DWORD)wh32->lpData); - *lpParam1 = seg_ptr + sizeof(LPWAVEHDR); - *lpParam2 = sizeof(WAVEHDR); - - ret = WINMM_MAP_OKMEM; - } else { - ret = WINMM_MAP_NOMEM; - } - } - break; - case WIDM_ADDBUFFER: - case WIDM_UNPREPARE: - { - LPWAVEHDR wh32 = (LPWAVEHDR)(*lpParam1); - LPWAVEHDR wh16 = wh32->lpNext; - LPSTR ptr = (LPSTR)wh16 - sizeof(LPWAVEHDR); - SEGPTR seg_ptr = MapLS( ptr ); - - assert(*(LPWAVEHDR*)ptr == wh32); - - TRACE("wh16=%08lx wh16->lpData=%08lx wh32->buflen=%lu wh32->lpData=%08lx\n", - seg_ptr + sizeof(LPWAVEHDR), (DWORD)wh16->lpData, - wh32->dwBufferLength, (DWORD)wh32->lpData); - - if (wMsg == WIDM_ADDBUFFER) - memcpy((LPSTR)wh16 + sizeof(WAVEHDR), wh32->lpData, wh32->dwBufferLength); - - *lpParam1 = seg_ptr + sizeof(LPWAVEHDR); - *lpParam2 = sizeof(WAVEHDR); - /* dwBufferLength can be reduced between prepare & write */ - if (wMsg == WIDM_ADDBUFFER && wh16->dwBufferLength < wh32->dwBufferLength) { - ERR("Size of buffer has been increased from %ld to %ld, keeping initial value\n", - wh16->dwBufferLength, wh32->dwBufferLength); - } else - wh16->dwBufferLength = wh32->dwBufferLength; - ret = WINMM_MAP_OKMEM; - } - break; - case WIDM_GETDEVCAPS: - { - LPWAVEINCAPSW wic32 = (LPWAVEINCAPSW)*lpParam1; - LPSTR ptr = HeapAlloc( GetProcessHeap(), 0 ,sizeof(LPWAVEINCAPSW) + sizeof(WAVEINCAPS16)); - - if (ptr) { - *(LPWAVEINCAPSW*)ptr = wic32; - ret = WINMM_MAP_OKMEM; - } else { - ret = WINMM_MAP_NOMEM; - } - *lpParam1 = MapLS(ptr) + sizeof(LPWAVEINCAPSW); - *lpParam2 = sizeof(WAVEINCAPS16); - } - break; - case WIDM_GETPOS: - { - LPMMTIME mmt32 = (LPMMTIME)*lpParam1; - LPSTR ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(LPMMTIME) + sizeof(MMTIME16)); - LPMMTIME16 mmt16 = (LPMMTIME16)(ptr + sizeof(LPMMTIME)); - - if (ptr) { - *(LPMMTIME*)ptr = mmt32; - mmt16->wType = mmt32->wType; - ret = WINMM_MAP_OKMEM; - } else { - ret = WINMM_MAP_NOMEM; - } - *lpParam1 = MapLS(ptr) + sizeof(LPMMTIME); - *lpParam2 = sizeof(MMTIME16); - } - break; - case DRVM_MAPPER_STATUS: - { - LPDWORD p32 = (LPDWORD)*lpParam2; - *lpParam2 = MapLS(p32); - ret = WINMM_MAP_OKMEM; - } - break; - default: - FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); - break; - } - return ret; -} - -/************************************************************************** - * MMDRV_WaveIn_UnMap32WTo16 [internal] - */ -static WINMM_MapType MMDRV_WaveIn_UnMap32WTo16(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) -{ - WINMM_MapType ret = WINMM_MAP_MSGERROR; - - switch (wMsg) { - case WIDM_CLOSE: - case WIDM_GETNUMDEVS: - case WIDM_RESET: - case WIDM_START: - case WIDM_STOP: - ret = WINMM_MAP_OK; - break; - - case WIDM_OPEN: - { - LPWAVEOPENDESC16 wod16 = MapSL(*lpParam1); - LPSTR ptr = (LPSTR)wod16 - sizeof(LPWAVEOPENDESC) - 2*sizeof(DWORD); - LPWAVEOPENDESC wod32 = *(LPWAVEOPENDESC*)ptr; - - UnMapLS( *lpParam1 ); - wod32->uMappedDeviceID = wod16->uMappedDeviceID; - **(DWORD**)(ptr + sizeof(LPWAVEOPENDESC)) = *(LPDWORD)(ptr + sizeof(LPWAVEOPENDESC) + sizeof(DWORD)); - HeapFree( GetProcessHeap(), 0, ptr ); - ret = WINMM_MAP_OK; - } - break; - - case WIDM_ADDBUFFER: - case WIDM_PREPARE: - case WIDM_UNPREPARE: - { - LPWAVEHDR wh16 = MapSL(*lpParam1); - LPSTR ptr = (LPSTR)wh16 - sizeof(LPWAVEHDR); - LPWAVEHDR wh32 = *(LPWAVEHDR*)ptr; - - assert(wh32->lpNext == wh16); - wh32->dwBytesRecorded = wh16->dwBytesRecorded; - wh32->dwUser = wh16->dwUser; - wh32->dwFlags = wh16->dwFlags; - wh32->dwLoops = wh16->dwLoops; - UnMapLS( *lpParam1 ); - - if (wMsg == WIDM_UNPREPARE && fn_ret == MMSYSERR_NOERROR) { - HeapFree( GetProcessHeap(), 0, ptr ); - wh32->lpNext = 0; - } - ret = WINMM_MAP_OK; - } - break; - case WIDM_GETDEVCAPS: - { - LPWAVEINCAPS16 wic16 = MapSL(*lpParam1); - LPSTR ptr = (LPSTR)wic16 - sizeof(LPWAVEINCAPSW); - LPWAVEINCAPSW wic32 = *(LPWAVEINCAPSW*)ptr; - - wic32->wMid = wic16->wMid; - wic32->wPid = wic16->wPid; - wic32->vDriverVersion = wic16->vDriverVersion; - WideCharToMultiByte( CP_ACP, 0, wic32->szPname, -1, wic16->szPname, - sizeof(wic16->szPname), NULL, NULL ); - wic32->dwFormats = wic16->dwFormats; - wic32->wChannels = wic16->wChannels; - UnMapLS( *lpParam1 ); - HeapFree( GetProcessHeap(), 0, ptr ); - ret = WINMM_MAP_OK; - } - break; - case WIDM_GETPOS: - { - LPMMTIME16 mmt16 = MapSL(*lpParam1); - LPSTR ptr = (LPSTR)mmt16 - sizeof(LPMMTIME); - LPMMTIME mmt32 = *(LPMMTIME*)ptr; - - MMSYSTEM_MMTIME16to32(mmt32, mmt16); - UnMapLS( *lpParam1 ); - HeapFree( GetProcessHeap(), 0, ptr ); - ret = WINMM_MAP_OK; - } - break; - case DRVM_MAPPER_STATUS: - { - UnMapLS( *lpParam2 ); - ret = WINMM_MAP_OK; - } - break; - default: - FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); - break; - } - return ret; -} - -/************************************************************************** - * MMDRV_WaveIn_Callback [internal] - */ -static void CALLBACK MMDRV_WaveIn_Callback(HDRVR hDev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) -{ - LPWINE_MLD mld = (LPWINE_MLD)dwInstance; - - switch (uMsg) { - case WIM_OPEN: - case WIM_CLOSE: - /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ - break; - case WIM_DATA: - if (mld->bFrom32 && !MMDRV_Is32(mld->mmdIndex)) { - /* initial map is: 32 => 16 */ - LPWAVEHDR wh16 = MapSL(dwParam1); - LPWAVEHDR wh32 = *(LPWAVEHDR*)((LPSTR)wh16 - sizeof(LPWAVEHDR)); - - dwParam1 = (DWORD)wh32; - wh32->dwFlags = wh16->dwFlags; - wh32->dwBytesRecorded = wh16->dwBytesRecorded; - } else if (!mld->bFrom32 && MMDRV_Is32(mld->mmdIndex)) { - /* initial map is: 16 => 32 */ - LPWAVEHDR wh32 = (LPWAVEHDR)(dwParam1); - SEGPTR segwh16 = *(SEGPTR*)((LPSTR)wh32 - sizeof(LPWAVEHDR)); - LPWAVEHDR wh16 = MapSL(segwh16); - - dwParam1 = (DWORD)segwh16; - wh16->dwFlags = wh32->dwFlags; - wh16->dwBytesRecorded = wh32->dwBytesRecorded; - } - /* else { 16 => 16 or 32 => 32, nothing to do, same struct is kept }*/ - break; - default: - ERR("Unknown msg %u\n", uMsg); - } - - MMDRV_Callback(mld, hDev, uMsg, dwParam1, dwParam2); -} - -/* ================================= - * W A V E O U T M A P P E R S - * ================================= */ - -/************************************************************************** - * MMDRV_WaveOut_Map16To32W [internal] - */ -static WINMM_MapType MMDRV_WaveOut_Map16To32W (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) -{ - WINMM_MapType ret = WINMM_MAP_MSGERROR; - - switch (wMsg) { - /* nothing to do */ - case WODM_BREAKLOOP: - case WODM_CLOSE: - case WODM_GETNUMDEVS: - case WODM_PAUSE: - case WODM_RESET: - case WODM_RESTART: - case WODM_SETPITCH: - case WODM_SETPLAYBACKRATE: - case WODM_SETVOLUME: - ret = WINMM_MAP_OK; - break; - - case WODM_GETPITCH: - case WODM_GETPLAYBACKRATE: - case WODM_GETVOLUME: - case WODM_OPEN: - FIXME("Shouldn't be used: the corresponding 16 bit functions use the 32 bit interface\n"); - break; - - case WODM_GETDEVCAPS: - { - LPWAVEOUTCAPSW woc32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPWAVEOUTCAPS16) + sizeof(WAVEOUTCAPSW)); - LPWAVEOUTCAPS16 woc16 = MapSL(*lpParam1); - - if (woc32) { - *(LPWAVEOUTCAPS16*)woc32 = woc16; - woc32 = (LPWAVEOUTCAPSW)((LPSTR)woc32 + sizeof(LPWAVEOUTCAPS16)); - *lpParam1 = (DWORD)woc32; - *lpParam2 = sizeof(WAVEOUTCAPSW); - - ret = WINMM_MAP_OKMEM; - } else { - ret = WINMM_MAP_NOMEM; - } - } - break; - case WODM_GETPOS: - { - LPMMTIME mmt32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPMMTIME16) + sizeof(MMTIME)); - LPMMTIME16 mmt16 = MapSL(*lpParam1); - - if (mmt32) { - *(LPMMTIME16*)mmt32 = mmt16; - mmt32 = (LPMMTIME)((LPSTR)mmt32 + sizeof(LPMMTIME16)); - - mmt32->wType = mmt16->wType; - *lpParam1 = (DWORD)mmt32; - *lpParam2 = sizeof(MMTIME); - - ret = WINMM_MAP_OKMEM; - } else { - ret = WINMM_MAP_NOMEM; - } - } - break; - case WODM_PREPARE: - { - LPWAVEHDR wh32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPWAVEHDR) + sizeof(WAVEHDR)); - LPWAVEHDR wh16 = MapSL(*lpParam1); - - if (wh32) { - *(LPWAVEHDR*)wh32 = (LPWAVEHDR)*lpParam1; - wh32 = (LPWAVEHDR)((LPSTR)wh32 + sizeof(LPWAVEHDR)); - wh32->lpData = MapSL((SEGPTR)wh16->lpData); - wh32->dwBufferLength = wh16->dwBufferLength; - wh32->dwBytesRecorded = wh16->dwBytesRecorded; - wh32->dwUser = wh16->dwUser; - wh32->dwFlags = wh16->dwFlags; - wh32->dwLoops = wh16->dwLoops; - /* FIXME: nothing on wh32->lpNext */ - /* could link the wh32->lpNext at this level for memory house keeping */ - wh16->lpNext = wh32; /* for reuse in unprepare and write */ - *lpParam1 = (DWORD)wh32; - *lpParam2 = sizeof(WAVEHDR); - - ret = WINMM_MAP_OKMEM; - } else { - ret = WINMM_MAP_NOMEM; - } - } - break; - case WODM_UNPREPARE: - case WODM_WRITE: - { - LPWAVEHDR wh16 = MapSL(*lpParam1); - LPWAVEHDR wh32 = (LPWAVEHDR)wh16->lpNext; - - *lpParam1 = (DWORD)wh32; - *lpParam2 = sizeof(WAVEHDR); - /* dwBufferLength can be reduced between prepare & write */ - if (wMsg == WODM_WRITE && wh32->dwBufferLength < wh16->dwBufferLength) { - ERR("Size of buffer has been increased from %ld to %ld, keeping initial value\n", - wh32->dwBufferLength, wh16->dwBufferLength); - } else - wh32->dwBufferLength = wh16->dwBufferLength; - ret = WINMM_MAP_OKMEM; - } - break; - case WODM_MAPPER_STATUS: - *lpParam2 = (DWORD)MapSL(*lpParam2); - ret = WINMM_MAP_OK; - break; - default: - FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); - break; - } - return ret; -} - -/************************************************************************** - * MMDRV_WaveOut_UnMap16To32W [internal] - */ -static WINMM_MapType MMDRV_WaveOut_UnMap16To32W(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) -{ - WINMM_MapType ret = WINMM_MAP_MSGERROR; - - switch (wMsg) { - /* nothing to do */ - case WODM_BREAKLOOP: - case WODM_CLOSE: - case WODM_GETNUMDEVS: - case WODM_PAUSE: - case WODM_RESET: - case WODM_RESTART: - case WODM_SETPITCH: - case WODM_SETPLAYBACKRATE: - case WODM_SETVOLUME: - case WODM_MAPPER_STATUS: - ret = WINMM_MAP_OK; - break; - - case WODM_GETPITCH: - case WODM_GETPLAYBACKRATE: - case WODM_GETVOLUME: - case WODM_OPEN: - FIXME("Shouldn't be used: those 16 bit functions use the 32 bit interface\n"); - break; - - case WODM_GETDEVCAPS: - { - LPWAVEOUTCAPSW woc32 = (LPWAVEOUTCAPSW)(*lpParam1); - LPWAVEOUTCAPS16 woc16 = *(LPWAVEOUTCAPS16*)((LPSTR)woc32 - sizeof(LPWAVEOUTCAPS16)); - - woc16->wMid = woc32->wMid; - woc16->wPid = woc32->wPid; - woc16->vDriverVersion = woc32->vDriverVersion; - WideCharToMultiByte( CP_ACP, 0, woc32->szPname, -1, woc16->szPname, - sizeof(woc16->szPname), NULL, NULL ); - woc16->dwFormats = woc32->dwFormats; - woc16->wChannels = woc32->wChannels; - woc16->dwSupport = woc32->dwSupport; - HeapFree(GetProcessHeap(), 0, (LPSTR)woc32 - sizeof(LPWAVEOUTCAPS16)); - ret = WINMM_MAP_OK; - } - break; - case WODM_GETPOS: - { - LPMMTIME mmt32 = (LPMMTIME)(*lpParam1); - LPMMTIME16 mmt16 = *(LPMMTIME16*)((LPSTR)mmt32 - sizeof(LPMMTIME16)); - - MMSYSTEM_MMTIME32to16(mmt16, mmt32); - HeapFree(GetProcessHeap(), 0, (LPSTR)mmt32 - sizeof(LPMMTIME16)); - ret = WINMM_MAP_OK; - } - break; - case WODM_PREPARE: - case WODM_UNPREPARE: - case WODM_WRITE: - { - LPWAVEHDR wh32 = (LPWAVEHDR)(*lpParam1); - LPWAVEHDR wh16 = MapSL(*(SEGPTR*)((LPSTR)wh32 - sizeof(LPWAVEHDR))); - - assert(wh16->lpNext == wh32); - wh16->dwBufferLength = wh32->dwBufferLength; - wh16->dwBytesRecorded = wh32->dwBytesRecorded; - wh16->dwUser = wh32->dwUser; - wh16->dwFlags = wh32->dwFlags; - wh16->dwLoops = wh32->dwLoops; - - if (wMsg == WODM_UNPREPARE && fn_ret == MMSYSERR_NOERROR) { - HeapFree(GetProcessHeap(), 0, (LPSTR)wh32 - sizeof(LPWAVEHDR)); - wh16->lpNext = 0; - } - ret = WINMM_MAP_OK; - } - break; - default: - FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); - break; - } - return ret; -} - -/************************************************************************** - * MMDRV_WaveOut_Map32WTo16 [internal] - */ -static WINMM_MapType MMDRV_WaveOut_Map32WTo16 (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) -{ - WINMM_MapType ret; - - switch (wMsg) { - /* nothing to do */ - case WODM_BREAKLOOP: - case WODM_CLOSE: - case WODM_GETNUMDEVS: - case WODM_PAUSE: - case WODM_RESET: - case WODM_RESTART: - case WODM_SETPITCH: - case WODM_SETPLAYBACKRATE: - case WODM_SETVOLUME: - ret = WINMM_MAP_OK; - break; - - case WODM_GETDEVCAPS: - { - LPWAVEOUTCAPSW woc32 = (LPWAVEOUTCAPSW)*lpParam1; - LPSTR ptr = HeapAlloc( GetProcessHeap(), 0, - sizeof(LPWAVEOUTCAPSW) + sizeof(WAVEOUTCAPS16)); - - if (ptr) { - *(LPWAVEOUTCAPSW*)ptr = woc32; - ret = WINMM_MAP_OKMEM; - } else { - ret = WINMM_MAP_NOMEM; - } - *lpParam1 = MapLS(ptr) + sizeof(LPWAVEOUTCAPSW); - *lpParam2 = sizeof(WAVEOUTCAPS16); - } - break; - case WODM_GETPITCH: - FIXME("NIY: no conversion yet\n"); - ret = WINMM_MAP_MSGERROR; - break; - case WODM_GETPLAYBACKRATE: - FIXME("NIY: no conversion yet\n"); - ret = WINMM_MAP_MSGERROR; - break; - case WODM_GETPOS: - { - LPMMTIME mmt32 = (LPMMTIME)*lpParam1; - LPSTR ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(LPMMTIME) + sizeof(MMTIME16)); - LPMMTIME16 mmt16 = (LPMMTIME16)(ptr + sizeof(LPMMTIME)); - - if (ptr) { - *(LPMMTIME*)ptr = mmt32; - mmt16->wType = mmt32->wType; - ret = WINMM_MAP_OKMEM; - } else { - ret = WINMM_MAP_NOMEM; - } - *lpParam1 = MapLS(ptr) + sizeof(LPMMTIME); - *lpParam2 = sizeof(MMTIME16); - } - break; - case WODM_GETVOLUME: - FIXME("NIY: no conversion yet\n"); - ret = WINMM_MAP_MSGERROR; - break; - case WODM_OPEN: - { - LPWAVEOPENDESC wod32 = (LPWAVEOPENDESC)*lpParam1; - int sz = sizeof(WAVEFORMATEX); - LPVOID ptr; - LPWAVEOPENDESC16 wod16; - - /* allocated data are mapped as follows: - LPWAVEOPENDESC ptr to orig lParam1 - DWORD orig dwUser, which is a pointer to DWORD:driver dwInstance - DWORD dwUser passed to driver - WAVEOPENDESC16 wod16: openDesc passed to driver - WAVEFORMATEX openDesc->lpFormat passed to driver - xxx extra bytes to WAVEFORMATEX - */ - if (wod32->lpFormat->wFormatTag != WAVE_FORMAT_PCM) { - TRACE("Allocating %u extra bytes (%d)\n", ((LPWAVEFORMATEX)wod32->lpFormat)->cbSize, wod32->lpFormat->wFormatTag); - sz += ((LPWAVEFORMATEX)wod32->lpFormat)->cbSize; - } - - ptr = HeapAlloc( GetProcessHeap(), 0, - sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD) + sizeof(WAVEOPENDESC16) + sz); - - if (ptr) { - SEGPTR seg_ptr = MapLS( ptr ); - *(LPWAVEOPENDESC*)ptr = wod32; - *(LPDWORD)((char*)ptr + sizeof(LPWAVEOPENDESC)) = *lpdwUser; - wod16 = (LPWAVEOPENDESC16)((LPSTR)ptr + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD)); - - wod16->hWave = HWAVE_16(wod32->hWave); - wod16->lpFormat = (LPWAVEFORMATEX)(seg_ptr + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD) + sizeof(WAVEOPENDESC16)); - memcpy(wod16 + 1, wod32->lpFormat, sz); - - wod16->dwCallback = wod32->dwCallback; - wod16->dwInstance = wod32->dwInstance; - wod16->uMappedDeviceID = wod32->uMappedDeviceID; - wod16->dnDevNode = wod32->dnDevNode; - - *lpParam1 = seg_ptr + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD); - *lpdwUser = seg_ptr + sizeof(LPWAVEOPENDESC) + sizeof(DWORD); - - ret = WINMM_MAP_OKMEM; - } else { - ret = WINMM_MAP_NOMEM; - } - } - break; - case WODM_PREPARE: - { - LPWAVEHDR wh32 = (LPWAVEHDR)*lpParam1; - LPWAVEHDR wh16; - LPVOID ptr = HeapAlloc( GetProcessHeap(), 0, - sizeof(LPWAVEHDR) + sizeof(WAVEHDR) + wh32->dwBufferLength); - - if (ptr) { - SEGPTR seg_ptr = MapLS( ptr ); - *(LPWAVEHDR*)ptr = wh32; - wh16 = (LPWAVEHDR)((LPSTR)ptr + sizeof(LPWAVEHDR)); - wh16->lpData = (LPSTR)seg_ptr + sizeof(LPWAVEHDR) + sizeof(WAVEHDR); - /* data will be copied on WODM_WRITE */ - wh16->dwBufferLength = wh32->dwBufferLength; - wh16->dwBytesRecorded = wh32->dwBytesRecorded; - wh16->dwUser = wh32->dwUser; - wh16->dwFlags = wh32->dwFlags; - wh16->dwLoops = wh32->dwLoops; - /* FIXME: nothing on wh32->lpNext */ - /* could link the wh32->lpNext at this level for memory house keeping */ - wh32->lpNext = wh16; /* for reuse in unprepare and write */ - TRACE("wh16=%08lx wh16->lpData=%08lx wh32->buflen=%lu wh32->lpData=%08lx\n", - seg_ptr + sizeof(LPWAVEHDR), (DWORD)wh16->lpData, - wh32->dwBufferLength, (DWORD)wh32->lpData); - *lpParam1 = seg_ptr + sizeof(LPWAVEHDR); - *lpParam2 = sizeof(WAVEHDR); - - ret = WINMM_MAP_OKMEM; - } else { - ret = WINMM_MAP_NOMEM; - } - } - break; - case WODM_UNPREPARE: - case WODM_WRITE: - { - LPWAVEHDR wh32 = (LPWAVEHDR)(*lpParam1); - LPWAVEHDR wh16 = wh32->lpNext; - LPSTR ptr = (LPSTR)wh16 - sizeof(LPWAVEHDR); - SEGPTR seg_ptr = MapLS( ptr ); - - assert(*(LPWAVEHDR*)ptr == wh32); - - TRACE("wh16=%08lx wh16->lpData=%08lx wh32->buflen=%lu wh32->lpData=%08lx\n", - seg_ptr + sizeof(LPWAVEHDR), (DWORD)wh16->lpData, - wh32->dwBufferLength, (DWORD)wh32->lpData); - - if (wMsg == WODM_WRITE) - memcpy((LPSTR)wh16 + sizeof(WAVEHDR), wh32->lpData, wh32->dwBufferLength); - - *lpParam1 = seg_ptr + sizeof(LPWAVEHDR); - *lpParam2 = sizeof(WAVEHDR); - /* dwBufferLength can be reduced between prepare & write */ - if (wMsg == WODM_WRITE && wh16->dwBufferLength < wh32->dwBufferLength) { - ERR("Size of buffer has been increased from %ld to %ld, keeping initial value\n", - wh16->dwBufferLength, wh32->dwBufferLength); - } else - wh16->dwBufferLength = wh32->dwBufferLength; - ret = WINMM_MAP_OKMEM; - } - break; - case DRVM_MAPPER_STATUS: - { - LPDWORD p32 = (LPDWORD)*lpParam2; - *lpParam2 = MapLS(p32); - ret = WINMM_MAP_OKMEM; - } - break; - default: - FIXME("NIY: no conversion yet\n"); - ret = WINMM_MAP_MSGERROR; - break; - } - return ret; -} - -/************************************************************************** - * MMDRV_WaveOut_UnMap32WTo16 [internal] - */ -static WINMM_MapType MMDRV_WaveOut_UnMap32WTo16(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) -{ - WINMM_MapType ret; - - switch (wMsg) { - /* nothing to do */ - case WODM_BREAKLOOP: - case WODM_CLOSE: - case WODM_GETNUMDEVS: - case WODM_PAUSE: - case WODM_RESET: - case WODM_RESTART: - case WODM_SETPITCH: - case WODM_SETPLAYBACKRATE: - case WODM_SETVOLUME: - ret = WINMM_MAP_OK; - break; - - case WODM_GETDEVCAPS: - { - LPWAVEOUTCAPS16 woc16 = MapSL(*lpParam1); - LPSTR ptr = (LPSTR)woc16 - sizeof(LPWAVEOUTCAPSW); - LPWAVEOUTCAPSW woc32 = *(LPWAVEOUTCAPSW*)ptr; - - woc32->wMid = woc16->wMid; - woc32->wPid = woc16->wPid; - woc32->vDriverVersion = woc16->vDriverVersion; - WideCharToMultiByte( CP_ACP, 0, woc32->szPname, -1, woc16->szPname, - sizeof(woc16->szPname), NULL, NULL ); - woc32->dwFormats = woc16->dwFormats; - woc32->wChannels = woc16->wChannels; - woc32->dwSupport = woc16->dwSupport; - UnMapLS( *lpParam1 ); - HeapFree( GetProcessHeap(), 0, ptr ); - ret = WINMM_MAP_OK; - } - break; - case WODM_GETPITCH: - FIXME("NIY: no conversion yet\n"); - ret = WINMM_MAP_MSGERROR; - break; - case WODM_GETPLAYBACKRATE: - FIXME("NIY: no conversion yet\n"); - ret = WINMM_MAP_MSGERROR; - break; - case WODM_GETPOS: - { - LPMMTIME16 mmt16 = MapSL(*lpParam1); - LPSTR ptr = (LPSTR)mmt16 - sizeof(LPMMTIME); - LPMMTIME mmt32 = *(LPMMTIME*)ptr; - - MMSYSTEM_MMTIME16to32(mmt32, mmt16); - UnMapLS( *lpParam1 ); - HeapFree( GetProcessHeap(), 0, ptr ); - ret = WINMM_MAP_OK; - } - break; - case WODM_OPEN: - { - LPWAVEOPENDESC16 wod16 = MapSL(*lpParam1); - LPSTR ptr = (LPSTR)wod16 - sizeof(LPWAVEOPENDESC) - 2*sizeof(DWORD); - LPWAVEOPENDESC wod32 = *(LPWAVEOPENDESC*)ptr; - - wod32->uMappedDeviceID = wod16->uMappedDeviceID; - **(DWORD**)(ptr + sizeof(LPWAVEOPENDESC)) = *(LPDWORD)(ptr + sizeof(LPWAVEOPENDESC) + sizeof(DWORD)); - UnMapLS( *lpParam1 ); - HeapFree( GetProcessHeap(), 0, ptr ); - ret = WINMM_MAP_OK; - } - break; - case WODM_PREPARE: - case WODM_UNPREPARE: - case WODM_WRITE: - { - LPWAVEHDR wh16 = MapSL(*lpParam1); - LPSTR ptr = (LPSTR)wh16 - sizeof(LPWAVEHDR); - LPWAVEHDR wh32 = *(LPWAVEHDR*)ptr; - - assert(wh32->lpNext == wh16); - wh32->dwBytesRecorded = wh16->dwBytesRecorded; - wh32->dwUser = wh16->dwUser; - wh32->dwFlags = wh16->dwFlags; - wh32->dwLoops = wh16->dwLoops; - - UnMapLS( *lpParam1 ); - if (wMsg == WODM_UNPREPARE && fn_ret == MMSYSERR_NOERROR) { - HeapFree( GetProcessHeap(), 0, ptr ); - wh32->lpNext = 0; - } - ret = WINMM_MAP_OK; - } - break; - case WODM_GETVOLUME: - FIXME("NIY: no conversion yet\n"); - ret = WINMM_MAP_MSGERROR; - break; - case DRVM_MAPPER_STATUS: - { - UnMapLS( *lpParam2 ); - ret = WINMM_MAP_OK; - } - break; - default: - FIXME("NIY: no conversion yet\n"); - ret = WINMM_MAP_MSGERROR; - break; - } - return ret; -} - -/************************************************************************** - * MMDRV_WaveOut_Callback [internal] - */ -static void CALLBACK MMDRV_WaveOut_Callback(HDRVR hDev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) -{ - LPWINE_MLD mld = (LPWINE_MLD)dwInstance; - - switch (uMsg) { - case WOM_OPEN: - case WOM_CLOSE: - /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ - break; - case WOM_DONE: - if (mld->bFrom32 && !MMDRV_Is32(mld->mmdIndex)) { - /* initial map is: 32 => 16 */ - LPWAVEHDR wh16 = MapSL(dwParam1); - LPWAVEHDR wh32 = *(LPWAVEHDR*)((LPSTR)wh16 - sizeof(LPWAVEHDR)); - - dwParam1 = (DWORD)wh32; - wh32->dwFlags = wh16->dwFlags; - } else if (!mld->bFrom32 && MMDRV_Is32(mld->mmdIndex)) { - /* initial map is: 16 => 32 */ - LPWAVEHDR wh32 = (LPWAVEHDR)(dwParam1); - SEGPTR segwh16 = *(SEGPTR*)((LPSTR)wh32 - sizeof(LPWAVEHDR)); - LPWAVEHDR wh16 = MapSL(segwh16); - - dwParam1 = (DWORD)segwh16; - wh16->dwFlags = wh32->dwFlags; - } - /* else { 16 => 16 or 32 => 32, nothing to do, same struct is kept }*/ - break; - default: - ERR("Unknown msg %u\n", uMsg); - } - - MMDRV_Callback(mld, hDev, uMsg, dwParam1, dwParam2); -} - -/* ================================= - * M A P P E R S H A N D L I N G - * ================================= */ - -static LRESULT MMDRV_CallMMDrvFunc16(DWORD fp16, WORD dev, WORD msg, LONG instance, - LONG lp1, LONG lp2) -{ - WORD args[8]; - DWORD ret; - - args[7] = dev; - args[6] = msg; - args[5] = HIWORD(instance); - args[4] = LOWORD(instance); - args[3] = HIWORD(lp1); - args[2] = LOWORD(lp1); - args[1] = HIWORD(lp2); - args[0] = LOWORD(lp2); - WOWCallback16Ex( fp16, WCB16_PASCAL, sizeof(args), args, &ret ); - return LOWORD(ret); -} - -/************************************************************************** - * MMDRV_GetDescription16 [internal] - */ -static BOOL MMDRV_GetDescription16(const char* fname, char* buf, int buflen) -{ - OFSTRUCT ofs; - HFILE hFile; - WORD w; - DWORD dw; - BOOL ret = FALSE; - - if ((hFile = OpenFile(fname, &ofs, OF_READ | OF_SHARE_DENY_WRITE)) == HFILE_ERROR) { - ERR("Can't open file %s (builtin driver ?)\n", fname); - return FALSE; - } - -#define E(_x) do {TRACE _x;goto theEnd;} while(0) - - if (_lread(hFile, &w, 2) != 2) E(("Can't read sig\n")); - if (w != ('Z' * 256 + 'M')) E(("Bad sig %04x\n", w)); - if (_llseek(hFile, 0x3C, SEEK_SET) < 0) E(("Can't seek to ext header offset\n")); - if (_lread(hFile, &dw, 4) != 4) E(("Can't read ext header offset\n")); - if (_llseek(hFile, dw + 0x2C, SEEK_SET) < 0) E(("Can't seek to ext header.nr table %lu\n", dw+0x2C)); - if (_lread(hFile, &dw, 4) != 4) E(("Can't read nr table offset\n")); - if (_llseek(hFile, dw, SEEK_SET) < 0) E(("Can't seek to nr table %lu\n", dw)); - if (_lread(hFile, buf, 1) != 1) E(("Can't read descr length\n")); - buflen = min((int)(unsigned)(BYTE)buf[0], buflen - 1); - if (_lread(hFile, buf, buflen) != buflen) E(("Can't read descr (%d)\n", buflen)); - buf[buflen] = '\0'; - ret = TRUE; - TRACE("Got '%s' [%d]\n", buf, buflen); -theEnd: - _lclose(hFile); - return ret; -} - -/****************************************************************** - * MMDRV_LoadMMDrvFunc16 - * - */ -unsigned MMDRV_LoadMMDrvFunc16(LPCSTR drvName, LPWINE_DRIVER d, - LPWINE_MM_DRIVER lpDrv) -{ - WINEMM_msgFunc16 func; - unsigned count = 0; - char buffer[128]; - /* - * DESCRIPTION 'wave,aux,mixer:Creative Labs Sound Blaster 16 Driver' - * The beginning of the module description indicates the driver supports - * waveform, auxiliary, and mixer devices. Use one of the following - * device-type names, followed by a colon (:) to indicate the type of - * device your driver supports. If the driver supports more than one - * type of device, separate each device-type name with a comma (,). - * - * wave for waveform audio devices - * wavemapper for wave mappers - * midi for MIDI audio devices - * midimapper for midi mappers - * aux for auxiliary audio devices - * mixer for mixer devices - */ - - if (d->d.d16.hDriver16) { - HMODULE16 hMod16 = GetDriverModuleHandle16(d->d.d16.hDriver16); - -#define AA(_h,_w,_x,_y,_z) \ - func = (WINEMM_msgFunc##_y) _z ((_h), #_x); \ - if (func != NULL) \ - { lpDrv->parts[_w].u.fnMessage##_y = func; count++; \ - TRACE("Got %d bit func '%s'\n", _y, #_x); } - -#define A(_x,_y) AA(hMod16,_x,_y,16,GetProcAddress16) - A(MMDRV_AUX, auxMessage); - A(MMDRV_MIXER, mxdMessage); - A(MMDRV_MIDIIN, midMessage); - A(MMDRV_MIDIOUT,modMessage); - A(MMDRV_WAVEIN, widMessage); - A(MMDRV_WAVEOUT,wodMessage); -#undef A -#undef AA - } - if (TRACE_ON(winmm)) { - if (MMDRV_GetDescription16(drvName, buffer, sizeof(buffer))) - TRACE("%s => %s\n", drvName, buffer); - else - TRACE("%s => No description\n", drvName); - } - - return count; -} - -/* ================================= - * M C I - * ================================= */ - -#if 0 -/* FIXME: this code is kept for not yet implemented optimisation for an application - * using the 32A MCI interface and calling a 16 bit driver. - * For now, we're doing two conversions: - * - 32A => 32W (in 32 bit MCI code) - * - 32W => 16 in this file - */ - -/* - * 0000 stop - * 0001 squeeze signed 4 bytes to 2 bytes *( LPINT16)D = ( INT16)*( LPINT16)S; D += 2; S += 4 - * 0010 squeeze unsigned 4 bytes to 2 bytes *(LPUINT16)D = (UINT16)*(LPUINT16)S; D += 2; S += 4 - * 0100 - * 0101 - * 0110 zero 4 bytes *(DWORD)D = 0 D += 4; S += 4 - * 0111 copy string *(LPSTR*)D = seg dup(*(LPSTR*)S) D += 4; S += 4 - * 1xxx copy xxx + 1 bytes memcpy(D, S, xxx + 1); D += xxx+1; S += xxx+1 - */ - -/************************************************************************** - * MCI_MsgMapper32ATo16_Create [internal] - * - * Helper for MCI_MapMsg32ATo16. - * Maps the 32 bit pointer (*ptr), of size bytes, to an allocated 16 bit - * segmented pointer. - * map contains a list of action to be performed for the mapping (see list - * above) - * if keep is TRUE, keeps track of in 32 bit ptr in allocated 16 bit area. - */ -static WINMM_MapType MCI_MsgMapper32ATo16_Create(void** ptr, int size16, DWORD map, BOOLEAN keep) -{ - void* lp = HeapAlloc( GetProcessHeap(), 0, (keep ? sizeof(void**) : 0) + size16 ); - LPBYTE p16, p32; - - if (!lp) { - return WINMM_MAP_NOMEM; - } - p32 = (LPBYTE)(*ptr); - if (keep) { - *(void**)lp = *ptr; - p16 = (LPBYTE)lp + sizeof(void**); - *ptr = (char*)MapLS(lp) + sizeof(void**); - } else { - p16 = lp; - *ptr = (void*)MapLS(lp); - } - - if (map == 0) { - memcpy(p16, p32, size16); - } else { - unsigned nibble; - unsigned sz; - - while (map & 0xF) { - nibble = map & 0xF; - if (nibble & 0x8) { - sz = (nibble & 7) + 1; - memcpy(p16, p32, sz); - p16 += sz; - p32 += sz; - size16 -= sz; /* DEBUG only */ - } else { - switch (nibble) { - case 0x1: - *(LPINT16)p16 = *(LPINT)p32; - p16 += sizeof(INT16); - p32 += sizeof(INT); - size16 -= sizeof(INT16); - break; - case 0x2: - *(LPUINT16)p16 = *(LPUINT)p32; - p16 += sizeof(UINT16); - p32 += sizeof(UINT); - size16 -= sizeof(UINT16); - break; - case 0x6: - *(LPDWORD)p16 = 0; - p16 += sizeof(DWORD); - p32 += sizeof(DWORD); - size16 -= sizeof(DWORD); - break; - case 0x7: - *(SEGPTR *)p16 = MapLS( *(LPSTR *)p32 ); - p16 += sizeof(SEGPTR); - p32 += sizeof(LPSTR); - size16 -= sizeof(SEGPTR); - break; - default: - FIXME("Unknown nibble for mapping (%x)\n", nibble); - } - } - map >>= 4; - } - if (size16 != 0) /* DEBUG only */ - FIXME("Mismatch between 16 bit struct size and map nibbles serie\n"); - } - return WINMM_MAP_OKMEM; -} - -/************************************************************************** - * MCI_MsgMapper32ATo16_Destroy [internal] - * - * Helper for MCI_UnMapMsg32ATo16. - */ -static WINMM_MapType MCI_MsgMapper32ATo16_Destroy(void* ptr, int size16, DWORD map, BOOLEAN kept) -{ - if (ptr) { - void* msg16 = MapSL((SEGPTR)ptr); - void* alloc; - LPBYTE p32, p16; - unsigned nibble; - - UnMapLS( (SEGPTR)ptr ); - if (kept) { - alloc = (char*)msg16 - sizeof(void**); - p32 = *(void**)alloc; - p16 = msg16; - - if (map == 0) { - memcpy(p32, p16, size16); - } else { - while (map & 0xF) { - nibble = map & 0xF; - if (nibble & 0x8) { - memcpy(p32, p16, (nibble & 7) + 1); - p16 += (nibble & 7) + 1; - p32 += (nibble & 7) + 1; - size16 -= (nibble & 7) + 1; - } else { - switch (nibble) { - case 0x1: - *(LPINT)p32 = *(LPINT16)p16; - p16 += sizeof(INT16); - p32 += sizeof(INT); - size16 -= sizeof(INT16); - break; - case 0x2: - *(LPUINT)p32 = *(LPUINT16)p16; - p16 += sizeof(UINT16); - p32 += sizeof(UINT); - size16 -= sizeof(UINT16); - break; - case 0x6: - p16 += sizeof(UINT); - p32 += sizeof(UINT); - size16 -= sizeof(UINT); - break; - case 0x7: - UnMapLS( *(SEGPTR *)p16 ); - p16 += sizeof(SEGPTR); - p32 += sizeof(char*); - size16 -= sizeof(SEGPTR); - break; - default: - FIXME("Unknown nibble for mapping (%x)\n", nibble); - } - } - map >>= 4; - } - if (size16 != 0) /* DEBUG only */ - FIXME("Mismatch between 16 bit struct size and map nibbles serie\n"); - } - } else { - alloc = msg16; - } - - HeapFree( GetProcessHeap(), 0, alloc ); - } - return WINMM_MAP_OK; -} - -/************************************************************************** - * MCI_MapMsg32ATo16 [internal] - * - * Map a 32-A bit MCI message to a 16 bit MCI message. - */ -static WINMM_MapType MCI_MapMsg32ATo16(WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD* lParam) -{ - int size; - BOOLEAN keep = FALSE; - DWORD map = 0; - - if (*lParam == 0) - return WINMM_MAP_OK; - - /* FIXME: to add also (with seg/linear modifications to do): - * MCI_LIST, MCI_LOAD, MCI_QUALITY, MCI_RESERVE, MCI_RESTORE, MCI_SAVE - * MCI_SETAUDIO, MCI_SETTUNER, MCI_SETVIDEO - */ - switch (wMsg) { - case MCI_BREAK: - size = sizeof(MCI_BREAK_PARMS); - break; - /* case MCI_CAPTURE */ - case MCI_CLOSE: - case MCI_CLOSE_DRIVER: - case MCI_CONFIGURE: - size = sizeof(MCI_GENERIC_PARMS); - break; - /* case MCI_COPY: */ - case MCI_CUE: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_CUE_PARMS); break; - case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_CUE_PARMS); break;*/ FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; - default: size = sizeof(MCI_GENERIC_PARMS); break; - } - break; - /* case MCI_CUT:*/ - case MCI_DELETE: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_DELETE_PARMS16); map = 0x0F1111FB; break; - case MCI_DEVTYPE_WAVEFORM_AUDIO:size = sizeof(MCI_WAVE_DELETE_PARMS); break; - default: size = sizeof(MCI_GENERIC_PARMS); break; - } - break; - /* case MCI_ESCAPE: */ - case MCI_FREEZE: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_FREEZE_PARMS); map = 0x0001111B; break; - case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS); map = 0x0001111B; break; - default: size = sizeof(MCI_GENERIC_PARMS); break; - } - break; - case MCI_GETDEVCAPS: - keep = TRUE; - size = sizeof(MCI_GETDEVCAPS_PARMS); - break; - /* case MCI_INDEX: */ - case MCI_INFO: - { - LPMCI_INFO_PARMSA mip32a = (LPMCI_INFO_PARMSA)(*lParam); - LPMCI_INFO_PARMS16 mip16; - - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_INFO_PARMS16); break; - default: size = sizeof(MCI_INFO_PARMS16); break; - } - mip16 = HeapAlloc( GetProcessHeap(), 0, size); - if (mip16) - { - mip16->dwCallback = mip32a->dwCallback; - mip16->lpstrReturn = MapLS( mip32a->lpstrReturn ); - mip16->dwRetSize = mip32a->dwRetSize; - if (uDevType == MCI_DEVTYPE_DIGITAL_VIDEO) { - ((LPMCI_DGV_INFO_PARMS16)mip16)->dwItem = ((LPMCI_DGV_INFO_PARMSA)mip32a)->dwItem; - } - } else { - return WINMM_MAP_NOMEM; - } - *lParam = MapLS(mip16); - } - return WINMM_MAP_OKMEM; - /* case MCI_MARK: */ - /* case MCI_MONITOR: */ - case MCI_OPEN: - case MCI_OPEN_DRIVER: - { - LPMCI_OPEN_PARMSA mop32a = (LPMCI_OPEN_PARMSA)(*lParam); - char* ptr = HeapAlloc( GetProcessHeap(), 0, - sizeof(LPMCI_OPEN_PARMSA) + sizeof(MCI_OPEN_PARMS16) + 2 * sizeof(DWORD)); - LPMCI_OPEN_PARMS16 mop16; - - - if (ptr) { - *(LPMCI_OPEN_PARMSA*)(ptr) = mop32a; - mop16 = (LPMCI_OPEN_PARMS16)(ptr + sizeof(LPMCI_OPEN_PARMSA)); - mop16->dwCallback = mop32a->dwCallback; - mop16->wDeviceID = mop32a->wDeviceID; - if (dwFlags & MCI_OPEN_TYPE) { - if (dwFlags & MCI_OPEN_TYPE_ID) { - /* dword "transparent" value */ - mop16->lpstrDeviceType = (SEGPTR)mop32a->lpstrDeviceType; - } else { - /* string */ - mop16->lpstrDeviceType = MapLS( mop32a->lpstrDeviceType ); - } - } else { - /* nuthin' */ - mop16->lpstrDeviceType = 0; - } - if (dwFlags & MCI_OPEN_ELEMENT) { - if (dwFlags & MCI_OPEN_ELEMENT_ID) { - mop16->lpstrElementName = (SEGPTR)mop32a->lpstrElementName; - } else { - mop16->lpstrElementName = MapLS( mop32a->lpstrElementName ); - } - } else { - mop16->lpstrElementName = 0; - } - if (dwFlags & MCI_OPEN_ALIAS) { - mop16->lpstrAlias = MapLS( mop32a->lpstrAlias ); - } else { - mop16->lpstrAlias = 0; - } - /* copy extended information if any... - * FIXME: this may seg fault if initial structure does not contain them and - * the reads after msip16 fail under LDT limits... - * NOTE: this should be split in two. First pass, while calling MCI_OPEN, and - * should not take care of extended parameters, and should be used by MCI_Open - * to fetch uDevType. When, this is known, the mapping for sending the - * MCI_OPEN_DRIVER shall be done depending on uDevType. - */ - memcpy(mop16 + 1, mop32a + 1, 2 * sizeof(DWORD)); - } else { - return WINMM_MAP_NOMEM; - } - *lParam = (LPARAM)MapLS(ptr) + sizeof(LPMCI_OPEN_PARMSA); - } - return WINMM_MAP_OKMEM; - /* case MCI_PASTE:*/ - case MCI_PAUSE: - size = sizeof(MCI_GENERIC_PARMS); - break; - case MCI_PLAY: - size = sizeof(MCI_PLAY_PARMS); - break; - case MCI_PUT: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16); map = 0x0001111B; break; - case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS); map = 0x0001111B; break; - default: size = sizeof(MCI_GENERIC_PARMS); break; - } - break; - case MCI_REALIZE: - size = sizeof(MCI_GENERIC_PARMS); - break; - case MCI_RECORD: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECORD_PARMS16); map = 0x0F1111FB; break; - case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_RECORD_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; - default: size = sizeof(MCI_RECORD_PARMS); break; - } - break; - case MCI_RESUME: - size = sizeof(MCI_GENERIC_PARMS); - break; - case MCI_SEEK: - switch (uDevType) { - case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_SEEK_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; - default: size = sizeof(MCI_SEEK_PARMS); break; - } - break; - case MCI_SET: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_SET_PARMS); break; - case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_SET_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; - case MCI_DEVTYPE_SEQUENCER: size = sizeof(MCI_SEQ_SET_PARMS); break; - /* FIXME: normally the 16 and 32 bit structures are byte by byte aligned, - * so not doing anything should work... - */ - case MCI_DEVTYPE_WAVEFORM_AUDIO:size = sizeof(MCI_WAVE_SET_PARMS); break; - default: size = sizeof(MCI_SET_PARMS); break; - } - break; - case MCI_SETAUDIO: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_SETAUDIO_PARMS16);map = 0x0000077FF; break; - case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_SETAUDIO_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; - default: size = sizeof(MCI_GENERIC_PARMS); break; - } - break; - /* case MCI_SETTIMECODE:*/ - /* case MCI_SIGNAL:*/ - /* case MCI_SOUND:*/ - case MCI_SPIN: - size = sizeof(MCI_SET_PARMS); - break; - case MCI_STATUS: - keep = TRUE; - switch (uDevType) { - /* FIXME: - * don't know if buffer for value is the one passed through lpstrDevice - * or is provided by MCI driver. - * Assuming solution 2: provided by MCI driver, so zeroing on entry - */ - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_STATUS_PARMS16); map = 0x0B6FF; break; - case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_STATUS_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; - default: size = sizeof(MCI_STATUS_PARMS); break; - } - break; - case MCI_STEP: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_STEP_PARMS); break; - case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_STEP_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; - case MCI_DEVTYPE_VIDEODISC: size = sizeof(MCI_VD_STEP_PARMS); break; - default: size = sizeof(MCI_GENERIC_PARMS); break; - } - break; - case MCI_STOP: - size = sizeof(MCI_SET_PARMS); - break; - case MCI_SYSINFO: - { - LPMCI_SYSINFO_PARMSA msip32a = (LPMCI_SYSINFO_PARMSA)(*lParam); - LPMCI_SYSINFO_PARMS16 msip16; - char* ptr = HeapAlloc( GetProcessHeap(), 0, - sizeof(LPMCI_SYSINFO_PARMSA) + sizeof(MCI_SYSINFO_PARMS16) ); - - if (ptr) { - *(LPMCI_SYSINFO_PARMSA*)(ptr) = msip32a; - msip16 = (LPMCI_SYSINFO_PARMS16)(ptr + sizeof(LPMCI_SYSINFO_PARMSA)); - - msip16->dwCallback = msip32a->dwCallback; - msip16->lpstrReturn = MapLS( msip32a->lpstrReturn ); - msip16->dwRetSize = msip32a->dwRetSize; - msip16->dwNumber = msip32a->dwNumber; - msip16->wDeviceType = msip32a->wDeviceType; - } else { - return WINMM_MAP_NOMEM; - } - *lParam = (LPARAM)MapLS(ptr) + sizeof(LPMCI_SYSINFO_PARMSA); - } - return WINMM_MAP_OKMEM; - /* case MCI_UNDO: */ - case MCI_UNFREEZE: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16); map = 0x0001111B; break; - case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS16); map = 0x0001111B; break; - default: size = sizeof(MCI_GENERIC_PARMS); break; - } - break; - case MCI_UPDATE: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_UPDATE_PARMS16); map = 0x000B1111B; break; - default: size = sizeof(MCI_GENERIC_PARMS); break; - } - break; - case MCI_WHERE: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16); map = 0x0001111B; keep = TRUE; break; - case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS16); map = 0x0001111B; keep = TRUE; break; - default: size = sizeof(MCI_GENERIC_PARMS); break; - } - break; - case MCI_WINDOW: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_WINDOW_PARMS16); if (dwFlags & MCI_DGV_WINDOW_TEXT) map = 0x7FB; break; - case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_WINDOW_PARMS16); if (dwFlags & MCI_OVLY_WINDOW_TEXT) map = 0x7FB; break; - default: size = sizeof(MCI_GENERIC_PARMS); break; - } - break; - case DRV_OPEN: - { - LPMCI_OPEN_DRIVER_PARMSA modp32a = (LPMCI_OPEN_DRIVER_PARMSA)(*lParam); - LPMCI_OPEN_DRIVER_PARMS16 modp16; - char *ptr = HeapAlloc( GetProcessHeap(), 0, - sizeof(LPMCI_OPEN_DRIVER_PARMSA) + sizeof(MCI_OPEN_DRIVER_PARMS16)); - - if (ptr) { - *(LPMCI_OPEN_DRIVER_PARMSA*)(ptr) = modp32a; - modp16 = (LPMCI_OPEN_DRIVER_PARMS16)(ptr + sizeof(LPMCI_OPEN_DRIVER_PARMSA)); - modp16->wDeviceID = modp32a->wDeviceID; - modp16->lpstrParams = MapLS( modp32a->lpstrParams ); - /* other fields are gonna be filled by the driver, don't copy them */ - } else { - return WINMM_MAP_NOMEM; - } - *lParam = (LPARAM)MapLS(ptr) + sizeof(LPMCI_OPEN_DRIVER_PARMSA); - } - return WINMM_MAP_OKMEM; - case DRV_LOAD: - case DRV_ENABLE: - case DRV_CLOSE: - case DRV_DISABLE: - case DRV_FREE: - case DRV_CONFIGURE: - case DRV_QUERYCONFIGURE: - case DRV_INSTALL: - case DRV_REMOVE: - case DRV_EXITSESSION: - case DRV_EXITAPPLICATION: - case DRV_POWER: - return WINMM_MAP_OK; - - default: - FIXME("Don't know how to map msg=%s\n", MCI_MessageToString(wMsg)); - return WINMM_MAP_MSGERROR; - } - return MCI_MsgMapper32ATo16_Create((void**)lParam, size, map, keep); -} - -/************************************************************************** - * MCI_UnMapMsg32ATo16 [internal] - */ -static WINMM_MapType MCI_UnMapMsg32ATo16(WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD lParam) -{ - int size = 0; - BOOLEAN kept = FALSE; /* there is no need to compute size when kept is FALSE */ - DWORD map = 0; - - switch (wMsg) { - case MCI_BREAK: - break; - /* case MCI_CAPTURE */ - case MCI_CLOSE: - case MCI_CLOSE_DRIVER: - case MCI_CONFIGURE: - break; - /* case MCI_COPY: */ - case MCI_CUE: - break; - /* case MCI_CUT: */ - case MCI_DELETE: - break; - /* case MCI_ESCAPE: */ - case MCI_FREEZE: - break; - case MCI_GETDEVCAPS: - kept = TRUE; - size = sizeof(MCI_GETDEVCAPS_PARMS); - break; - /* case MCI_INDEX: */ - case MCI_INFO: - { - LPMCI_INFO_PARMS16 mip16 = (LPMCI_INFO_PARMS16)MapSL(lParam); - UnMapLS( lParam ); - UnMapLS( mip16->lpstrReturn ); - HeapFree( GetProcessHeap(), 0, mip16 ); - } - return WINMM_MAP_OK; - /* case MCI_MARK: */ - /* case MCI_MONITOR: */ - case MCI_OPEN: - case MCI_OPEN_DRIVER: - if (lParam) { - LPMCI_OPEN_PARMS16 mop16 = (LPMCI_OPEN_PARMS16)MapSL(lParam); - LPMCI_OPEN_PARMSA mop32a = *(LPMCI_OPEN_PARMSA*)((char*)mop16 - sizeof(LPMCI_OPEN_PARMSA)); - UnMapLS( lParam ); - mop32a->wDeviceID = mop16->wDeviceID; - if ((dwFlags & MCI_OPEN_TYPE) && !(dwFlags & MCI_OPEN_TYPE_ID)) - UnMapLS( mop16->lpstrDeviceType ); - if ((dwFlags & MCI_OPEN_ELEMENT) && !(dwFlags & MCI_OPEN_ELEMENT_ID)) - UnMapLS( mop16->lpstrElementName ); - if (dwFlags & MCI_OPEN_ALIAS) - UnMapLS( mop16->lpstrAlias ); - HeapFree( GetProcessHeap(), 0, (char*)mop16 - sizeof(LPMCI_OPEN_PARMSA) ); - } - return WINMM_MAP_OK; - /* case MCI_PASTE:*/ - case MCI_PAUSE: - break; - case MCI_PLAY: - break; - case MCI_PUT: - break; - case MCI_REALIZE: - break; - case MCI_RECORD: - break; - case MCI_RESUME: - break; - case MCI_SEEK: - break; - case MCI_SET: - break; - case MCI_SETAUDIO: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: map = 0x0000077FF; break; - case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_SETAUDIO_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; - } - break; - /* case MCI_SETTIMECODE:*/ - /* case MCI_SIGNAL:*/ - /* case MCI_SOUND:*/ - case MCI_SPIN: - break; - case MCI_STATUS: - kept = TRUE; - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: - if (lParam) { - LPMCI_DGV_STATUS_PARMS16 mdsp16 = (LPMCI_DGV_STATUS_PARMS16)MapSL(lParam); - LPMCI_DGV_STATUS_PARMSA mdsp32a = *(LPMCI_DGV_STATUS_PARMSA*)((char*)mdsp16 - sizeof(LPMCI_DGV_STATUS_PARMSA)); - - UnMapLS( lParam ); - if (mdsp16) { - mdsp32a->dwReturn = mdsp16->dwReturn; - if (dwFlags & MCI_DGV_STATUS_DISKSPACE) { - TRACE("MCI_STATUS (DGV) lpstrDrive=%08lx\n", mdsp16->lpstrDrive); - TRACE("MCI_STATUS (DGV) lpstrDrive=%s\n", (LPSTR)MapSL(mdsp16->lpstrDrive)); - UnMapLS( mdsp16->lpstrDrive ); - } - HeapFree( GetProcessHeap(), 0, (char*)mdsp16 - sizeof(LPMCI_DGV_STATUS_PARMSA) ); - } else { - return WINMM_MAP_NOMEM; - } - } - return WINMM_MAP_OKMEM; - case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_STATUS_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; - default: size = sizeof(MCI_STATUS_PARMS); break; - } - break; - case MCI_STEP: - break; - case MCI_STOP: - break; - case MCI_SYSINFO: - if (lParam) { - LPMCI_SYSINFO_PARMS16 msip16 = (LPMCI_SYSINFO_PARMS16)MapSL(lParam); - LPMCI_SYSINFO_PARMSA msip32a = *(LPMCI_SYSINFO_PARMSA*)((char*)msip16 - sizeof(LPMCI_SYSINFO_PARMSA)); - - UnMapLS( lParam ); - if (msip16) { - msip16->dwCallback = msip32a->dwCallback; - UnMapLS( msip16->lpstrReturn ); - HeapFree( GetProcessHeap(), 0, (char*)msip16 - sizeof(LPMCI_SYSINFO_PARMSA) ); - } else { - return WINMM_MAP_NOMEM; - } - } - return WINMM_MAP_OKMEM; - /* case MCI_UNDO: */ - case MCI_UNFREEZE: - break; - case MCI_UPDATE: - break; - case MCI_WHERE: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16); map = 0x0001111B; kept = TRUE; break; - case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS16); map = 0x0001111B; kept = TRUE; break; - default: break; - } - break; - case MCI_WINDOW: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_WINDOW_PARMS16); if (dwFlags & MCI_DGV_WINDOW_TEXT) map = 0x7666; break; - case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_WINDOW_PARMS16); if (dwFlags & MCI_OVLY_WINDOW_TEXT) map = 0x7666; break; - default: break; - } - /* FIXME: see map function */ - break; - - case DRV_OPEN: - if (lParam) { - LPMCI_OPEN_DRIVER_PARMS16 modp16 = (LPMCI_OPEN_DRIVER_PARMS16)MapSL(lParam); - LPMCI_OPEN_DRIVER_PARMSA modp32a = *(LPMCI_OPEN_DRIVER_PARMSA*)((char*)modp16 - sizeof(LPMCI_OPEN_DRIVER_PARMSA)); - - UnMapLS( lParam ); - modp32a->wCustomCommandTable = modp16->wCustomCommandTable; - modp32a->wType = modp16->wType; - UnMapLS( modp16->lpstrParams ); - HeapFree( GetProcessHeap(), 0, (char *)modp16 - sizeof(LPMCI_OPEN_DRIVER_PARMSA) ); - } - return WINMM_MAP_OK; - case DRV_LOAD: - case DRV_ENABLE: - case DRV_CLOSE: - case DRV_DISABLE: - case DRV_FREE: - case DRV_CONFIGURE: - case DRV_QUERYCONFIGURE: - case DRV_INSTALL: - case DRV_REMOVE: - case DRV_EXITSESSION: - case DRV_EXITAPPLICATION: - case DRV_POWER: - FIXME("This is a hack\n"); - return WINMM_MAP_OK; - default: - FIXME("Map/Unmap internal error on msg=%s\n", MCI_MessageToString(wMsg)); - return WINMM_MAP_MSGERROR; - } - return MCI_MsgMapper32ATo16_Destroy((void*)lParam, size, map, kept); -} -#endif - -/************************************************************************** - * MCI_MapMsg16To32W [internal] - */ -static WINMM_MapType MCI_MapMsg16To32W(WORD uDevType, WORD wMsg, DWORD* lParam) -{ - if (*lParam == 0) - return WINMM_MAP_OK; - /* FIXME: to add also (with seg/linear modifications to do): - * MCI_LIST, MCI_LOAD, MCI_QUALITY, MCI_RESERVE, MCI_RESTORE, MCI_SAVE - * MCI_SETAUDIO, MCI_SETTUNER, MCI_SETVIDEO - */ - switch (wMsg) { - /* case MCI_CAPTURE */ - case MCI_CLOSE: - case MCI_CLOSE_DRIVER: - case MCI_CONFIGURE: - case MCI_COPY: - case MCI_CUE: - case MCI_CUT: - case MCI_DELETE: - case MCI_FREEZE: - case MCI_GETDEVCAPS: - /* case MCI_INDEX: */ - /* case MCI_MARK: */ - /* case MCI_MONITOR: */ - case MCI_PASTE: - case MCI_PAUSE: - case MCI_PLAY: - case MCI_PUT: - case MCI_REALIZE: - case MCI_RECORD: - case MCI_RESUME: - case MCI_SEEK: - case MCI_SET: - /* case MCI_SETTIMECODE:*/ - /* case MCI_SIGNAL:*/ - case MCI_SPIN: - case MCI_STATUS: /* FIXME: is wrong for digital video */ - case MCI_STEP: - case MCI_STOP: - /* case MCI_UNDO: */ - case MCI_UNFREEZE: - case MCI_UPDATE: - case MCI_WHERE: - *lParam = (DWORD)MapSL(*lParam); - return WINMM_MAP_OK; - case MCI_WINDOW: - /* in fact, I would also need the dwFlags... to see - * which members of lParam are effectively used - */ - *lParam = (DWORD)MapSL(*lParam); - FIXME("Current mapping may be wrong\n"); - break; - case MCI_BREAK: - { - LPMCI_BREAK_PARMS mbp32 = HeapAlloc(GetProcessHeap(), 0, sizeof(MCI_BREAK_PARMS)); - LPMCI_BREAK_PARMS16 mbp16 = MapSL(*lParam); - - if (mbp32) { - mbp32->dwCallback = mbp16->dwCallback; - mbp32->nVirtKey = mbp16->nVirtKey; - mbp32->hwndBreak = HWND_32(mbp16->hwndBreak); - } else { - return WINMM_MAP_NOMEM; - } - *lParam = (DWORD)mbp32; - } - return WINMM_MAP_OKMEM; - case MCI_ESCAPE: - { - LPMCI_VD_ESCAPE_PARMSW mvep32w = HeapAlloc(GetProcessHeap(), 0, sizeof(MCI_VD_ESCAPE_PARMSW)); - LPMCI_VD_ESCAPE_PARMS16 mvep16 = MapSL(*lParam); - - if (mvep32w) { - mvep32w->dwCallback = mvep16->dwCallback; - mvep32w->lpstrCommand = MCI_strdupAtoW(MapSL(mvep16->lpstrCommand)); - } else { - return WINMM_MAP_NOMEM; - } - *lParam = (DWORD)mvep32w; - } - return WINMM_MAP_OKMEM; - case MCI_INFO: - { - LPMCI_INFO_PARMSW mip32w = HeapAlloc(GetProcessHeap(), 0, sizeof(LPMCI_OPEN_PARMS16) + sizeof(MCI_INFO_PARMSW)); - LPMCI_INFO_PARMS16 mip16 = MapSL(*lParam); - - /* FIXME this is wrong if device is of type - * MCI_DEVTYPE_DIGITAL_VIDEO, some members are not mapped - */ - if (mip32w) { - *(LPMCI_INFO_PARMS16*)(mip32w) = mip16; - mip32w = (LPMCI_INFO_PARMSW)((char*)mip32w + sizeof(LPMCI_INFO_PARMS16)); - mip32w->dwCallback = mip16->dwCallback; - mip32w->lpstrReturn = HeapAlloc(GetProcessHeap(), 0, mip16->dwRetSize * sizeof(WCHAR)); - mip32w->dwRetSize = mip16->dwRetSize * sizeof(WCHAR); - } else { - return WINMM_MAP_NOMEM; - } - *lParam = (DWORD)mip32w; - } - return WINMM_MAP_OKMEM; - case MCI_OPEN: - case MCI_OPEN_DRIVER: - { - LPMCI_OPEN_PARMSW mop32w = HeapAlloc(GetProcessHeap(), 0, sizeof(LPMCI_OPEN_PARMS16) + sizeof(MCI_OPEN_PARMSW) + 2 * sizeof(DWORD)); - LPMCI_OPEN_PARMS16 mop16 = MapSL(*lParam); - - if (mop32w) { - *(LPMCI_OPEN_PARMS16*)(mop32w) = mop16; - mop32w = (LPMCI_OPEN_PARMSW)((char*)mop32w + sizeof(LPMCI_OPEN_PARMS16)); - mop32w->dwCallback = mop16->dwCallback; - mop32w->wDeviceID = mop16->wDeviceID; - mop32w->lpstrDeviceType = MCI_strdupAtoW(MapSL(mop16->lpstrDeviceType)); - mop32w->lpstrElementName = MCI_strdupAtoW(MapSL(mop16->lpstrElementName)); - mop32w->lpstrAlias = MCI_strdupAtoW(MapSL(mop16->lpstrAlias)); - /* copy extended information if any... - * FIXME: this may seg fault if initial structure does not contain them and - * the reads after msip16 fail under LDT limits... - * NOTE: this should be split in two. First pass, while calling MCI_OPEN, and - * should not take care of extended parameters, and should be used by MCI_Open - * to fetch uDevType. When, this is known, the mapping for sending the - * MCI_OPEN_DRIVER shall be done depending on uDevType. - */ - memcpy(mop32w + 1, mop16 + 1, 2 * sizeof(DWORD)); - } else { - return WINMM_MAP_NOMEM; - } - *lParam = (DWORD)mop32w; - } - return WINMM_MAP_OKMEM; - case MCI_SYSINFO: - { - LPMCI_SYSINFO_PARMSW msip32w = HeapAlloc(GetProcessHeap(), 0, sizeof(LPMCI_OPEN_PARMS16) + sizeof(MCI_SYSINFO_PARMSW)); - LPMCI_SYSINFO_PARMS16 msip16 = MapSL(*lParam); - - if (msip32w) { - *(LPMCI_SYSINFO_PARMS16*)(msip32w) = msip16; - msip32w = (LPMCI_SYSINFO_PARMSW)((char*)msip32w + sizeof(LPMCI_OPEN_PARMS16)); - msip32w->dwCallback = msip16->dwCallback; - msip32w->lpstrReturn = HeapAlloc(GetProcessHeap(), 0, msip16->dwRetSize * sizeof(WCHAR)); - msip32w->dwRetSize = msip16->dwRetSize; - msip32w->dwNumber = msip16->dwNumber; - msip32w->wDeviceType = msip16->wDeviceType; - } else { - return WINMM_MAP_NOMEM; - } - *lParam = (DWORD)msip32w; - } - return WINMM_MAP_OKMEM; - case MCI_SOUND: - { - LPMCI_SOUND_PARMSW mbp32 = HeapAlloc(GetProcessHeap(), 0, sizeof(MCI_SOUND_PARMSW)); - LPMCI_SOUND_PARMS16 mbp16 = MapSL(*lParam); - - if (mbp32) { - mbp32->dwCallback = mbp16->dwCallback; - mbp32->lpstrSoundName = MCI_strdupAtoW(MapSL(mbp16->lpstrSoundName)); - } else { - return WINMM_MAP_NOMEM; - } - *lParam = (DWORD)mbp32; - } - return WINMM_MAP_OKMEM; - case DRV_LOAD: - case DRV_ENABLE: - case DRV_OPEN: - case DRV_CLOSE: - case DRV_DISABLE: - case DRV_FREE: - case DRV_CONFIGURE: - case DRV_QUERYCONFIGURE: - case DRV_INSTALL: - case DRV_REMOVE: - case DRV_EXITSESSION: - case DRV_EXITAPPLICATION: - case DRV_POWER: - FIXME("This is a hack\n"); - return WINMM_MAP_OK; - default: - FIXME("Don't know how to map msg=%s\n", MCI_MessageToString(wMsg)); - } - return WINMM_MAP_MSGERROR; -} - -/************************************************************************** - * MCI_UnMapMsg16To32W [internal] - */ -static WINMM_MapType MCI_UnMapMsg16To32W(WORD uDevType, WORD wMsg, DWORD lParam) -{ - switch (wMsg) { - /* case MCI_CAPTURE */ - case MCI_CLOSE: - case MCI_CLOSE_DRIVER: - case MCI_CONFIGURE: - case MCI_COPY: - case MCI_CUE: - case MCI_CUT: - case MCI_DELETE: - case MCI_FREEZE: - case MCI_GETDEVCAPS: - /* case MCI_INDEX: */ - /* case MCI_MARK: */ - /* case MCI_MONITOR: */ - case MCI_PASTE: - case MCI_PAUSE: - case MCI_PLAY: - case MCI_PUT: - case MCI_REALIZE: - case MCI_RECORD: - case MCI_RESUME: - case MCI_SEEK: - case MCI_SET: - /* case MCI_SETTIMECODE:*/ - /* case MCI_SIGNAL:*/ - case MCI_SPIN: - case MCI_STATUS: - case MCI_STEP: - case MCI_STOP: - /* case MCI_UNDO: */ - case MCI_UNFREEZE: - case MCI_UPDATE: - case MCI_WHERE: - return WINMM_MAP_OK; - - case MCI_WINDOW: - /* FIXME ?? see Map function */ - return WINMM_MAP_OK; - - case MCI_BREAK: - HeapFree(GetProcessHeap(), 0, (LPVOID)lParam); - return WINMM_MAP_OK; - case MCI_ESCAPE: - if (lParam) { - LPMCI_VD_ESCAPE_PARMSW mvep32W = (LPMCI_VD_ESCAPE_PARMSW)lParam; - HeapFree(GetProcessHeap(), 0, (LPVOID)mvep32W->lpstrCommand); - HeapFree(GetProcessHeap(), 0, (LPVOID)lParam); - } - return WINMM_MAP_OK; - case MCI_INFO: - if (lParam) { - LPMCI_INFO_PARMSW mip32w = (LPMCI_INFO_PARMSW)lParam; - LPMCI_INFO_PARMS16 mip16 = *(LPMCI_INFO_PARMS16*)((char*)mip32w - sizeof(LPMCI_INFO_PARMS16)); - - WideCharToMultiByte(CP_ACP, 0, - mip32w->lpstrReturn, mip32w->dwRetSize / sizeof(WCHAR), - MapSL(mip16->lpstrReturn), mip16->dwRetSize, - NULL, NULL); - HeapFree(GetProcessHeap(), 0, (LPVOID)mip32w->lpstrReturn); - HeapFree(GetProcessHeap(), 0, (LPVOID)lParam); - } - return WINMM_MAP_OK; - case MCI_SYSINFO: - if (lParam) { - LPMCI_SYSINFO_PARMSW msip32w = (LPMCI_SYSINFO_PARMSW)lParam; - LPMCI_SYSINFO_PARMS16 msip16 = *(LPMCI_SYSINFO_PARMS16*)((char*)msip32w - sizeof(LPMCI_SYSINFO_PARMS16)); - - WideCharToMultiByte(CP_ACP, 0, - msip32w->lpstrReturn, msip32w->dwRetSize, - MapSL(msip16->lpstrReturn), msip16->dwRetSize, - NULL, NULL); - HeapFree(GetProcessHeap(), 0, (LPVOID)msip32w->lpstrReturn); - HeapFree(GetProcessHeap(), 0, (LPVOID)lParam); - } - return WINMM_MAP_OK; - case MCI_SOUND: - if (lParam) { - LPMCI_SOUND_PARMSW msp32W = (LPMCI_SOUND_PARMSW)lParam; - HeapFree(GetProcessHeap(), 0, (LPVOID)msp32W->lpstrSoundName); - HeapFree(GetProcessHeap(), 0, (LPVOID)lParam); - } - return WINMM_MAP_OK; - case MCI_OPEN: - case MCI_OPEN_DRIVER: - if (lParam) { - LPMCI_OPEN_PARMSW mop32w = (LPMCI_OPEN_PARMSW)lParam; - LPMCI_OPEN_PARMS16 mop16 = *(LPMCI_OPEN_PARMS16*)((char*)mop32w - sizeof(LPMCI_OPEN_PARMS16)); - - mop16->wDeviceID = mop32w->wDeviceID; - HeapFree(GetProcessHeap(), 0, mop32w->lpstrDeviceType); - HeapFree(GetProcessHeap(), 0, mop32w->lpstrElementName); - HeapFree(GetProcessHeap(), 0, mop32w->lpstrAlias); - if (!HeapFree(GetProcessHeap(), 0, (LPVOID)(lParam - sizeof(LPMCI_OPEN_PARMS16)))) - FIXME("bad free line=%d\n", __LINE__); - } - return WINMM_MAP_OK; - case DRV_LOAD: - case DRV_ENABLE: - case DRV_OPEN: - case DRV_CLOSE: - case DRV_DISABLE: - case DRV_FREE: - case DRV_CONFIGURE: - case DRV_QUERYCONFIGURE: - case DRV_INSTALL: - case DRV_REMOVE: - case DRV_EXITSESSION: - case DRV_EXITAPPLICATION: - case DRV_POWER: - FIXME("This is a hack\n"); - return WINMM_MAP_OK; - default: - FIXME("Map/Unmap internal error on msg=%s\n", MCI_MessageToString(wMsg)); - } - return WINMM_MAP_MSGERROR; -} - -/* - * 0000 stop - * 0001 squeeze signed 4 bytes to 2 bytes *( LPINT16)D = ( INT16)*( LPINT16)S; D += 2; S += 4 - * 0010 squeeze unsigned 4 bytes to 2 bytes *(LPUINT16)D = (UINT16)*(LPUINT16)S; D += 2; S += 4 - * 0100 - * 0101 - * 0110 zero 4 bytes *(DWORD)D = 0 D += 4; S += 4 - * 0111 copy string *(LPSTR*)D = seg dup(*(LPSTR*)S) D += 4; S += 4 - * 1xxx copy xxx + 1 bytes memcpy(D, S, xxx + 1); D += xxx+1; S += xxx+1 - */ - -/************************************************************************** - * MCI_MsgMapper32WTo16_Create [internal] - * - * Helper for MCI_MapMsg32WTo16. - * Maps the 32 bit pointer (*ptr), of size bytes, to an allocated 16 bit - * segmented pointer. - * map contains a list of action to be performed for the mapping (see list - * above) - * if keep is TRUE, keeps track of in 32 bit ptr in allocated 16 bit area. - */ -static WINMM_MapType MCI_MsgMapper32WTo16_Create(void** ptr, int size16, DWORD map, BOOLEAN keep) -{ - void* lp = HeapAlloc( GetProcessHeap(), 0, (keep ? sizeof(void**) : 0) + size16 ); - LPBYTE p16, p32; - - if (!lp) { - return WINMM_MAP_NOMEM; - } - p32 = (LPBYTE)(*ptr); - if (keep) { - *(void**)lp = *ptr; - p16 = (LPBYTE)lp + sizeof(void**); - *ptr = (char*)MapLS(lp) + sizeof(void**); - } else { - p16 = lp; - *ptr = (void*)MapLS(lp); - } - - if (map == 0) { - memcpy(p16, p32, size16); - } else { - unsigned nibble; - unsigned sz; - - while (map & 0xF) { - nibble = map & 0xF; - if (nibble & 0x8) { - sz = (nibble & 7) + 1; - memcpy(p16, p32, sz); - p16 += sz; - p32 += sz; - size16 -= sz; /* DEBUG only */ - } else { - switch (nibble) { - case 0x1: - *(LPINT16)p16 = *(LPINT)p32; - p16 += sizeof(INT16); - p32 += sizeof(INT); - size16 -= sizeof(INT16); - break; - case 0x2: - *(LPUINT16)p16 = *(LPUINT)p32; - p16 += sizeof(UINT16); - p32 += sizeof(UINT); - size16 -= sizeof(UINT16); - break; - case 0x6: - *(LPDWORD)p16 = 0; - p16 += sizeof(DWORD); - p32 += sizeof(DWORD); - size16 -= sizeof(DWORD); - break; - case 0x7: - *(SEGPTR *)p16 = MapLS( MCI_strdupWtoA( *(LPCWSTR *)p32 ) ); - p16 += sizeof(SEGPTR); - p32 += sizeof(LPSTR); - size16 -= sizeof(SEGPTR); - break; - default: - FIXME("Unknown nibble for mapping (%x)\n", nibble); - } - } - map >>= 4; - } - if (size16 != 0) /* DEBUG only */ - FIXME("Mismatch between 16 bit struct size and map nibbles serie\n"); - } - return WINMM_MAP_OKMEM; -} - -/************************************************************************** - * MCI_MsgMapper32WTo16_Destroy [internal] - * - * Helper for MCI_UnMapMsg32WTo16. - */ -static WINMM_MapType MCI_MsgMapper32WTo16_Destroy(void* ptr, int size16, DWORD map, BOOLEAN kept) -{ - if (ptr) { - void* msg16 = MapSL((SEGPTR)ptr); - void* alloc; - LPBYTE p32, p16; - unsigned nibble; - - UnMapLS( (SEGPTR)ptr ); - if (kept) { - alloc = (char*)msg16 - sizeof(void**); - p32 = *(void**)alloc; - p16 = msg16; - - if (map == 0) { - memcpy(p32, p16, size16); - } else { - while (map & 0xF) { - nibble = map & 0xF; - if (nibble & 0x8) { - memcpy(p32, p16, (nibble & 7) + 1); - p16 += (nibble & 7) + 1; - p32 += (nibble & 7) + 1; - size16 -= (nibble & 7) + 1; - } else { - switch (nibble) { - case 0x1: - *(LPINT)p32 = *(LPINT16)p16; - p16 += sizeof(INT16); - p32 += sizeof(INT); - size16 -= sizeof(INT16); - break; - case 0x2: - *(LPUINT)p32 = *(LPUINT16)p16; - p16 += sizeof(UINT16); - p32 += sizeof(UINT); - size16 -= sizeof(UINT16); - break; - case 0x6: - p16 += sizeof(UINT); - p32 += sizeof(UINT); - size16 -= sizeof(UINT); - break; - case 0x7: - HeapFree(GetProcessHeap(), 0, MapSL(*(SEGPTR *)p16)); - UnMapLS( *(SEGPTR *)p16 ); - p16 += sizeof(SEGPTR); - p32 += sizeof(char*); - size16 -= sizeof(SEGPTR); - break; - default: - FIXME("Unknown nibble for mapping (%x)\n", nibble); - } - } - map >>= 4; - } - if (size16 != 0) /* DEBUG only */ - FIXME("Mismatch between 16 bit struct size and map nibbles serie\n"); - } - } else { - alloc = msg16; - } - - HeapFree( GetProcessHeap(), 0, alloc ); - } - return WINMM_MAP_OK; -} - -/************************************************************************** - * MCI_MapMsg32WTo16 [internal] - * - * Map a 32W bit MCI message to a 16 bit MCI message. - */ -static WINMM_MapType MCI_MapMsg32WTo16(WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD* lParam) -{ - int size; - BOOLEAN keep = FALSE; - DWORD map = 0; - - if (*lParam == 0) - return WINMM_MAP_OK; - - /* FIXME: to add also (with seg/linear modifications to do): - * MCI_LIST, MCI_LOAD, MCI_QUALITY, MCI_RESERVE, MCI_RESTORE, MCI_SAVE - * MCI_SETAUDIO, MCI_SETTUNER, MCI_SETVIDEO - */ - switch (wMsg) { - case MCI_BREAK: - size = sizeof(MCI_BREAK_PARMS); - break; - /* case MCI_CAPTURE */ - case MCI_CLOSE: - case MCI_CLOSE_DRIVER: - case MCI_CONFIGURE: - size = sizeof(MCI_GENERIC_PARMS); - break; - /* case MCI_COPY: */ - case MCI_CUE: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_CUE_PARMS); break; - case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_CUE_PARMS); break;*/ FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; - default: size = sizeof(MCI_GENERIC_PARMS); break; - } - break; - /* case MCI_CUT:*/ - case MCI_DELETE: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_DELETE_PARMS16); map = 0x0F1111FB; break; - case MCI_DEVTYPE_WAVEFORM_AUDIO:size = sizeof(MCI_WAVE_DELETE_PARMS); break; - default: size = sizeof(MCI_GENERIC_PARMS); break; - } - break; - /* case MCI_ESCAPE: */ - case MCI_FREEZE: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_FREEZE_PARMS); map = 0x0001111B; break; - case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS); map = 0x0001111B; break; - default: size = sizeof(MCI_GENERIC_PARMS); break; - } - break; - case MCI_GETDEVCAPS: - keep = TRUE; - size = sizeof(MCI_GETDEVCAPS_PARMS); - break; - /* case MCI_INDEX: */ - case MCI_INFO: - { - LPMCI_INFO_PARMSW mip32w = (LPMCI_INFO_PARMSW)(*lParam); - char* ptr; - LPMCI_INFO_PARMS16 mip16; - - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_INFO_PARMS16); break; - default: size = sizeof(MCI_INFO_PARMS16); break; - } - ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(LPMCI_INFO_PARMSW) + size); - if (ptr) - { - *(LPMCI_INFO_PARMSW*)ptr = mip32w; - mip16 = (LPMCI_INFO_PARMS16)(ptr + sizeof(LPMCI_INFO_PARMSW)); - mip16->dwCallback = mip32w->dwCallback; - mip16->lpstrReturn = MapLS( HeapAlloc(GetProcessHeap(), 0, mip32w->dwRetSize / sizeof(WCHAR)) ); - mip16->dwRetSize = mip32w->dwRetSize / sizeof(WCHAR); - if (uDevType == MCI_DEVTYPE_DIGITAL_VIDEO) { - ((LPMCI_DGV_INFO_PARMS16)mip16)->dwItem = ((LPMCI_DGV_INFO_PARMSW)mip32w)->dwItem; - } - } else { - return WINMM_MAP_NOMEM; - } - *lParam = (LPARAM)MapLS(ptr) + sizeof(LPMCI_INFO_PARMSW); - } - return WINMM_MAP_OKMEM; - /* case MCI_MARK: */ - /* case MCI_MONITOR: */ - case MCI_OPEN: - case MCI_OPEN_DRIVER: - { - LPMCI_OPEN_PARMSW mop32w = (LPMCI_OPEN_PARMSW)(*lParam); - char* ptr = HeapAlloc( GetProcessHeap(), 0, - sizeof(LPMCI_OPEN_PARMSW) + sizeof(MCI_OPEN_PARMS16) + 2 * sizeof(DWORD)); - LPMCI_OPEN_PARMS16 mop16; - - - if (ptr) { - *(LPMCI_OPEN_PARMSW*)(ptr) = mop32w; - mop16 = (LPMCI_OPEN_PARMS16)(ptr + sizeof(LPMCI_OPEN_PARMSW)); - mop16->dwCallback = mop32w->dwCallback; - mop16->wDeviceID = mop32w->wDeviceID; - if (dwFlags & MCI_OPEN_TYPE) { - if (dwFlags & MCI_OPEN_TYPE_ID) { - /* dword "transparent" value */ - mop16->lpstrDeviceType = (SEGPTR)mop32w->lpstrDeviceType; - } else { - /* string */ - mop16->lpstrDeviceType = MapLS( MCI_strdupWtoA(mop32w->lpstrDeviceType) ); - } - } else { - /* nuthin' */ - mop16->lpstrDeviceType = 0; - } - if (dwFlags & MCI_OPEN_ELEMENT) { - if (dwFlags & MCI_OPEN_ELEMENT_ID) { - mop16->lpstrElementName = (SEGPTR)mop32w->lpstrElementName; - } else { - mop16->lpstrElementName = MapLS( MCI_strdupWtoA(mop32w->lpstrElementName) ); - } - } else { - mop16->lpstrElementName = 0; - } - if (dwFlags & MCI_OPEN_ALIAS) { - mop16->lpstrAlias = MapLS( MCI_strdupWtoA(mop32w->lpstrAlias) ); - } else { - mop16->lpstrAlias = 0; - } - /* copy extended information if any... - * FIXME: this may seg fault if initial structure does not contain them and - * the reads after msip16 fail under LDT limits... - * NOTE: this should be split in two. First pass, while calling MCI_OPEN, and - * should not take care of extended parameters, and should be used by MCI_Open - * to fetch uDevType. When, this is known, the mapping for sending the - * MCI_OPEN_DRIVER shall be done depending on uDevType. - */ - memcpy(mop16 + 1, mop32w + 1, 2 * sizeof(DWORD)); - } else { - return WINMM_MAP_NOMEM; - } - *lParam = (LPARAM)MapLS(ptr) + sizeof(LPMCI_OPEN_PARMSW); - } - return WINMM_MAP_OKMEM; - /* case MCI_PASTE:*/ - case MCI_PAUSE: - size = sizeof(MCI_GENERIC_PARMS); - break; - case MCI_PLAY: - size = sizeof(MCI_PLAY_PARMS); - break; - case MCI_PUT: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16); map = 0x0001111B; break; - case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS); map = 0x0001111B; break; - default: size = sizeof(MCI_GENERIC_PARMS); break; - } - break; - case MCI_REALIZE: - size = sizeof(MCI_GENERIC_PARMS); - break; - case MCI_RECORD: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECORD_PARMS16); map = 0x0F1111FB; break; - case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_RECORD_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; - default: size = sizeof(MCI_RECORD_PARMS); break; - } - break; - case MCI_RESUME: - size = sizeof(MCI_GENERIC_PARMS); - break; - case MCI_SEEK: - switch (uDevType) { - case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_SEEK_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; - default: size = sizeof(MCI_SEEK_PARMS); break; - } - break; - case MCI_SET: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_SET_PARMS); break; - case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_SET_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; - case MCI_DEVTYPE_SEQUENCER: size = sizeof(MCI_SEQ_SET_PARMS); break; - /* FIXME: normally the 16 and 32 bit structures are byte by byte aligned, - * so not doing anything should work... - */ - case MCI_DEVTYPE_WAVEFORM_AUDIO:size = sizeof(MCI_WAVE_SET_PARMS); break; - default: size = sizeof(MCI_SET_PARMS); break; - } - break; - case MCI_SETAUDIO: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_SETAUDIO_PARMS16);map = 0x0000077FF; break; - case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_SETAUDIO_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; - default: size = sizeof(MCI_GENERIC_PARMS); break; - } - break; - /* case MCI_SETTIMECODE:*/ - /* case MCI_SIGNAL:*/ - /* case MCI_SOUND:*/ - case MCI_SPIN: - size = sizeof(MCI_SET_PARMS); - break; - case MCI_STATUS: - keep = TRUE; - switch (uDevType) { - /* FIXME: - * don't know if buffer for value is the one passed through lpstrDevice - * or is provided by MCI driver. - * Assuming solution 2: provided by MCI driver, so zeroing on entry - */ - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_STATUS_PARMS16); map = 0x0B6FF; break; - case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_STATUS_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; - default: size = sizeof(MCI_STATUS_PARMS); break; - } - break; - case MCI_STEP: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_STEP_PARMS); break; - case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_STEP_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; - case MCI_DEVTYPE_VIDEODISC: size = sizeof(MCI_VD_STEP_PARMS); break; - default: size = sizeof(MCI_GENERIC_PARMS); break; - } - break; - case MCI_STOP: - size = sizeof(MCI_SET_PARMS); - break; - case MCI_SYSINFO: - { - LPMCI_SYSINFO_PARMSW msip32w = (LPMCI_SYSINFO_PARMSW)(*lParam); - LPMCI_SYSINFO_PARMS16 msip16; - char* ptr = HeapAlloc( GetProcessHeap(), 0, - sizeof(LPMCI_SYSINFO_PARMSW) + sizeof(MCI_SYSINFO_PARMS16) ); - - if (ptr) { - *(LPMCI_SYSINFO_PARMSW*)(ptr) = msip32w; - msip16 = (LPMCI_SYSINFO_PARMS16)(ptr + sizeof(LPMCI_SYSINFO_PARMSW)); - - msip16->dwCallback = msip32w->dwCallback; - msip16->lpstrReturn = MapLS( HeapAlloc(GetProcessHeap(), 0, msip32w->dwRetSize) ); - msip16->dwRetSize = msip32w->dwRetSize; - msip16->dwNumber = msip32w->dwNumber; - msip16->wDeviceType = msip32w->wDeviceType; - } else { - return WINMM_MAP_NOMEM; - } - *lParam = (LPARAM)MapLS(ptr) + sizeof(LPMCI_SYSINFO_PARMSW); - } - return WINMM_MAP_OKMEM; - /* case MCI_UNDO: */ - case MCI_UNFREEZE: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16); map = 0x0001111B; break; - case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS16); map = 0x0001111B; break; - default: size = sizeof(MCI_GENERIC_PARMS); break; - } - break; - case MCI_UPDATE: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_UPDATE_PARMS16); map = 0x000B1111B; break; - default: size = sizeof(MCI_GENERIC_PARMS); break; - } - break; - case MCI_WHERE: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16); map = 0x0001111B; keep = TRUE; break; - case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS16); map = 0x0001111B; keep = TRUE; break; - default: size = sizeof(MCI_GENERIC_PARMS); break; - } - break; - case MCI_WINDOW: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_WINDOW_PARMS16); if (dwFlags & MCI_DGV_WINDOW_TEXT) map = 0x7FB; break; - case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_WINDOW_PARMS16); if (dwFlags & MCI_OVLY_WINDOW_TEXT) map = 0x7FB; break; - default: size = sizeof(MCI_GENERIC_PARMS); break; - } - break; - case DRV_OPEN: - { - LPMCI_OPEN_DRIVER_PARMSW modp32w = (LPMCI_OPEN_DRIVER_PARMSW)(*lParam); - LPMCI_OPEN_DRIVER_PARMS16 modp16; - char *ptr = HeapAlloc( GetProcessHeap(), 0, - sizeof(LPMCI_OPEN_DRIVER_PARMSW) + sizeof(MCI_OPEN_DRIVER_PARMS16)); - - if (ptr) { - *(LPMCI_OPEN_DRIVER_PARMSW*)(ptr) = modp32w; - modp16 = (LPMCI_OPEN_DRIVER_PARMS16)(ptr + sizeof(LPMCI_OPEN_DRIVER_PARMSW)); - modp16->wDeviceID = modp32w->wDeviceID; - modp16->lpstrParams = MapLS( MCI_strdupWtoA(modp32w->lpstrParams) ); - /* other fields are gonna be filled by the driver, don't copy them */ - } else { - return WINMM_MAP_NOMEM; - } - *lParam = (LPARAM)MapLS(ptr) + sizeof(LPMCI_OPEN_DRIVER_PARMSW); - } - return WINMM_MAP_OKMEM; - case DRV_LOAD: - case DRV_ENABLE: - case DRV_CLOSE: - case DRV_DISABLE: - case DRV_FREE: - case DRV_CONFIGURE: - case DRV_QUERYCONFIGURE: - case DRV_INSTALL: - case DRV_REMOVE: - case DRV_EXITSESSION: - case DRV_EXITAPPLICATION: - case DRV_POWER: - return WINMM_MAP_OK; - - default: - FIXME("Don't know how to map msg=%s\n", MCI_MessageToString(wMsg)); - return WINMM_MAP_MSGERROR; - } - return MCI_MsgMapper32WTo16_Create((void**)lParam, size, map, keep); -} - -/************************************************************************** - * MCI_UnMapMsg32WTo16 [internal] - */ -static WINMM_MapType MCI_UnMapMsg32WTo16(WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD lParam) -{ - int size = 0; - BOOLEAN kept = FALSE; /* there is no need to compute size when kept is FALSE */ - DWORD map = 0; - - switch (wMsg) { - case MCI_BREAK: - break; - /* case MCI_CAPTURE */ - case MCI_CLOSE: - case MCI_CLOSE_DRIVER: - case MCI_CONFIGURE: - break; - /* case MCI_COPY: */ - case MCI_CUE: - break; - /* case MCI_CUT: */ - case MCI_DELETE: - break; - /* case MCI_ESCAPE: */ - case MCI_FREEZE: - break; - case MCI_GETDEVCAPS: - kept = TRUE; - size = sizeof(MCI_GETDEVCAPS_PARMS); - break; - /* case MCI_INDEX: */ - case MCI_INFO: - if (lParam) { - LPMCI_INFO_PARMS16 mip16 = (LPMCI_INFO_PARMS16)MapSL(lParam); - LPMCI_INFO_PARMSW mip32w = *(LPMCI_INFO_PARMSW*)((char*)mip16 - sizeof(LPMCI_INFO_PARMSW)); - - MultiByteToWideChar(CP_ACP, 0, MapSL(mip16->lpstrReturn), mip16->dwRetSize, - mip32w->lpstrReturn, mip32w->dwRetSize / sizeof(WCHAR)); - UnMapLS( lParam ); - UnMapLS( mip16->lpstrReturn ); - HeapFree( GetProcessHeap(), 0, (void*)MapSL(mip16->lpstrReturn) ); - HeapFree( GetProcessHeap(), 0, (char*)mip16 - sizeof(LPMCI_OPEN_PARMSW) ); - } - return WINMM_MAP_OK; - /* case MCI_MARK: */ - /* case MCI_MONITOR: */ - case MCI_OPEN: - case MCI_OPEN_DRIVER: - if (lParam) { - LPMCI_OPEN_PARMS16 mop16 = (LPMCI_OPEN_PARMS16)MapSL(lParam); - LPMCI_OPEN_PARMSW mop32w = *(LPMCI_OPEN_PARMSW*)((char*)mop16 - sizeof(LPMCI_OPEN_PARMSW)); - UnMapLS( lParam ); - mop32w->wDeviceID = mop16->wDeviceID; - if ((dwFlags & MCI_OPEN_TYPE) && !(dwFlags & MCI_OPEN_TYPE_ID)) - { - HeapFree(GetProcessHeap(), 0, MapSL(mop16->lpstrDeviceType)); - UnMapLS( mop16->lpstrDeviceType ); - } - if ((dwFlags & MCI_OPEN_ELEMENT) && !(dwFlags & MCI_OPEN_ELEMENT_ID)) - { - HeapFree(GetProcessHeap(), 0, MapSL(mop16->lpstrElementName)); - UnMapLS( mop16->lpstrElementName ); - } - if (dwFlags & MCI_OPEN_ALIAS) - { - HeapFree(GetProcessHeap(), 0, MapSL(mop16->lpstrAlias)); - UnMapLS( mop16->lpstrAlias ); - } - HeapFree( GetProcessHeap(), 0, (char*)mop16 - sizeof(LPMCI_OPEN_PARMSW) ); - } - return WINMM_MAP_OK; - /* case MCI_PASTE:*/ - case MCI_PAUSE: - break; - case MCI_PLAY: - break; - case MCI_PUT: - break; - case MCI_REALIZE: - break; - case MCI_RECORD: - break; - case MCI_RESUME: - break; - case MCI_SEEK: - break; - case MCI_SET: - break; - case MCI_SETAUDIO: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: map = 0x0000077FF; break; - case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_SETAUDIO_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; - } - break; - /* case MCI_SETTIMECODE:*/ - /* case MCI_SIGNAL:*/ - /* case MCI_SOUND:*/ - case MCI_SPIN: - break; - case MCI_STATUS: - kept = TRUE; - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: - if (lParam) { - LPMCI_DGV_STATUS_PARMS16 mdsp16 = (LPMCI_DGV_STATUS_PARMS16)MapSL(lParam); - LPMCI_DGV_STATUS_PARMSA mdsp32a = *(LPMCI_DGV_STATUS_PARMSA*)((char*)mdsp16 - sizeof(LPMCI_DGV_STATUS_PARMSA)); - - UnMapLS( lParam ); - if (mdsp16) { - mdsp32a->dwReturn = mdsp16->dwReturn; - if (dwFlags & MCI_DGV_STATUS_DISKSPACE) { - TRACE("MCI_STATUS (DGV) lpstrDrive=%08lx\n", mdsp16->lpstrDrive); - TRACE("MCI_STATUS (DGV) lpstrDrive=%s\n", (LPSTR)MapSL(mdsp16->lpstrDrive)); - UnMapLS( mdsp16->lpstrDrive ); - } - HeapFree( GetProcessHeap(), 0, (char*)mdsp16 - sizeof(LPMCI_DGV_STATUS_PARMSA) ); - } else { - return WINMM_MAP_NOMEM; - } - } - return WINMM_MAP_OKMEM; - case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_STATUS_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; - default: size = sizeof(MCI_STATUS_PARMS); break; - } - break; - case MCI_STEP: - break; - case MCI_STOP: - break; - case MCI_SYSINFO: - if (lParam) { - LPMCI_SYSINFO_PARMS16 msip16 = (LPMCI_SYSINFO_PARMS16)MapSL(lParam); - LPMCI_SYSINFO_PARMSW msip32w = *(LPMCI_SYSINFO_PARMSW*)((char*)msip16 - sizeof(LPMCI_SYSINFO_PARMSW)); - - UnMapLS( lParam ); - if (msip16) { - MultiByteToWideChar(CP_ACP, 0, MapSL(msip16->lpstrReturn), msip16->dwRetSize, - msip32w->lpstrReturn, msip32w->dwRetSize); - UnMapLS( msip16->lpstrReturn ); - HeapFree( GetProcessHeap(), 0, MapSL(msip16->lpstrReturn) ); - HeapFree( GetProcessHeap(), 0, (char*)msip16 - sizeof(LPMCI_SYSINFO_PARMSW) ); - } else { - return WINMM_MAP_NOMEM; - } - } - return WINMM_MAP_OKMEM; - /* case MCI_UNDO: */ - case MCI_UNFREEZE: - break; - case MCI_UPDATE: - break; - case MCI_WHERE: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16); map = 0x0001111B; kept = TRUE; break; - case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS16); map = 0x0001111B; kept = TRUE; break; - default: break; - } - break; - case MCI_WINDOW: - switch (uDevType) { - case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_WINDOW_PARMS16); if (dwFlags & MCI_DGV_WINDOW_TEXT) map = 0x7666; break; - case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_WINDOW_PARMS16); if (dwFlags & MCI_OVLY_WINDOW_TEXT) map = 0x7666; break; - default: break; - } - /* FIXME: see map function */ - break; - case DRV_OPEN: - if (lParam) { - LPMCI_OPEN_DRIVER_PARMS16 modp16 = (LPMCI_OPEN_DRIVER_PARMS16)MapSL(lParam); - LPMCI_OPEN_DRIVER_PARMSW modp32w = *(LPMCI_OPEN_DRIVER_PARMSW*)((char*)modp16 - sizeof(LPMCI_OPEN_DRIVER_PARMSW)); - - UnMapLS( lParam ); - modp32w->wCustomCommandTable = modp16->wCustomCommandTable; - modp32w->wType = modp16->wType; - HeapFree(GetProcessHeap(), 0, MapSL(modp16->lpstrParams)); - UnMapLS( modp16->lpstrParams ); - HeapFree( GetProcessHeap(), 0, (char *)modp16 - sizeof(LPMCI_OPEN_DRIVER_PARMSW) ); - } - return WINMM_MAP_OK; - case DRV_LOAD: - case DRV_ENABLE: - case DRV_CLOSE: - case DRV_DISABLE: - case DRV_FREE: - case DRV_CONFIGURE: - case DRV_QUERYCONFIGURE: - case DRV_INSTALL: - case DRV_REMOVE: - case DRV_EXITSESSION: - case DRV_EXITAPPLICATION: - case DRV_POWER: - FIXME("This is a hack\n"); - return WINMM_MAP_OK; - - default: - FIXME("Map/Unmap internal error on msg=%s\n", MCI_MessageToString(wMsg)); - return WINMM_MAP_MSGERROR; - } - return MCI_MsgMapper32WTo16_Destroy((void*)lParam, size, map, kept); -} - -void MMDRV_Init16(void) -{ -#define A(_x,_y) MMDRV_InstallMap(_x, \ -MMDRV_##_y##_Map16To32W, MMDRV_##_y##_UnMap16To32W, \ -MMDRV_##_y##_Map32WTo16, MMDRV_##_y##_UnMap32WTo16, \ -MMDRV_##_y##_Callback) - A(MMDRV_AUX, Aux); - A(MMDRV_MIXER, Mixer); - A(MMDRV_MIDIIN, MidiIn); - A(MMDRV_MIDIOUT, MidiOut); - A(MMDRV_WAVEIN, WaveIn); - A(MMDRV_WAVEOUT, WaveOut); -#undef A - - pFnCallMMDrvFunc16 = MMDRV_CallMMDrvFunc16; - pFnLoadMMDrvFunc16 = MMDRV_LoadMMDrvFunc16; - - pFnMciMapMsg16To32W = MCI_MapMsg16To32W; - pFnMciUnMapMsg16To32W = MCI_UnMapMsg16To32W; - pFnMciMapMsg32WTo16 = MCI_MapMsg32WTo16; - pFnMciUnMapMsg32WTo16 = MCI_UnMapMsg32WTo16; -} +/* + * MMSYSTEM MCI and low level mapping functions + * + * Copyright 1999 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <string.h> +#include <stdarg.h> +#include <stdio.h> +#include <assert.h> +#include "wine/winbase16.h" +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winver.h" +#include "wownt32.h" +#include "winemm16.h" +#include "digitalv.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winmm); + +/************************************************************************** + * MMDRV_Callback [internal] + */ +static void MMDRV_Callback(LPWINE_MLD mld, HDRVR hDev, UINT uMsg, DWORD dwParam1, DWORD dwParam2) +{ + TRACE("CB (*%08lx)(%p %08x %08lx %08lx %08lx\n", + mld->dwCallback, hDev, uMsg, mld->dwClientInstance, dwParam1, dwParam2); + + if (!mld->bFrom32 && (mld->dwFlags & DCB_TYPEMASK) == DCB_FUNCTION) + { + WORD args[8]; + /* 16 bit func, call it */ + TRACE("Function (16 bit) !\n"); + + args[7] = HDRVR_16(hDev); + args[6] = uMsg; + args[5] = HIWORD(mld->dwClientInstance); + args[4] = LOWORD(mld->dwClientInstance); + args[3] = HIWORD(dwParam1); + args[2] = LOWORD(dwParam1); + args[1] = HIWORD(dwParam2); + args[0] = LOWORD(dwParam2); + WOWCallback16Ex( mld->dwCallback, WCB16_PASCAL, sizeof(args), args, NULL ); + } else { + DriverCallback(mld->dwCallback, mld->dwFlags, hDev, uMsg, + mld->dwClientInstance, dwParam1, dwParam2); + } +} + +/* ================================= + * A U X M A P P E R S + * ================================= */ + +/************************************************************************** + * MMDRV_Aux_Map16To32W [internal] + */ +static WINMM_MapType MMDRV_Aux_Map16To32W (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_Aux_UnMap16To32W [internal] + */ +static WINMM_MapType MMDRV_Aux_UnMap16To32W(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_Aux_Map32WTo16 [internal] + */ +static WINMM_MapType MMDRV_Aux_Map32WTo16 (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_Aux_UnMap32WTo16 [internal] + */ +static WINMM_MapType MMDRV_Aux_UnMap32WTo16(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ +#if 0 + case AUXDM_GETDEVCAPS: + lpCaps->wMid = ac16.wMid; + lpCaps->wPid = ac16.wPid; + lpCaps->vDriverVersion = ac16.vDriverVersion; + strcpy(lpCaps->szPname, ac16.szPname); + lpCaps->wTechnology = ac16.wTechnology; + lpCaps->dwSupport = ac16.dwSupport; +#endif + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_Aux_Callback [internal] + */ +static void CALLBACK MMDRV_Aux_Callback(HDRVR hDev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD mld = (LPWINE_MLD)dwInstance; + + FIXME("NIY\n"); + MMDRV_Callback(mld, hDev, uMsg, dwParam1, dwParam2); +} + +/* ================================= + * M I X E R M A P P E R S + * ================================= */ + +/************************************************************************** + * xMMDRV_Mixer_Map16To32W [internal] + */ +static WINMM_MapType MMDRV_Mixer_Map16To32W (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_Mixer_UnMap16To32W [internal] + */ +static WINMM_MapType MMDRV_Mixer_UnMap16To32W(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ +#if 0 + MIXERCAPSA micA; + UINT ret = mixerGetDevCapsA(devid, &micA, sizeof(micA)); + + if (ret == MMSYSERR_NOERROR) { + mixcaps->wMid = micA.wMid; + mixcaps->wPid = micA.wPid; + mixcaps->vDriverVersion = micA.vDriverVersion; + strcpy(mixcaps->szPname, micA.szPname); + mixcaps->fdwSupport = micA.fdwSupport; + mixcaps->cDestinations = micA.cDestinations; + } + return ret; +#endif + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_Mixer_Map32WTo16 [internal] + */ +static WINMM_MapType MMDRV_Mixer_Map32WTo16 (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_Mixer_UnMap32WTo16 [internal] + */ +static WINMM_MapType MMDRV_Mixer_UnMap32WTo16(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_Mixer_Callback [internal] + */ +static void CALLBACK MMDRV_Mixer_Callback(HDRVR hDev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD mld = (LPWINE_MLD)dwInstance; + + FIXME("NIY\n"); + MMDRV_Callback(mld, hDev, uMsg, dwParam1, dwParam2); +} + +/* ================================= + * M I D I I N M A P P E R S + * ================================= */ + +/************************************************************************** + * MMDRV_MidiIn_Map16To32W [internal] + */ +static WINMM_MapType MMDRV_MidiIn_Map16To32W (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_MidiIn_UnMap16To32W [internal] + */ +static WINMM_MapType MMDRV_MidiIn_UnMap16To32W(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_MidiIn_Map32WTo16 [internal] + */ +static WINMM_MapType MMDRV_MidiIn_Map32WTo16 (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_MidiIn_UnMap32WTo16 [internal] + */ +static WINMM_MapType MMDRV_MidiIn_UnMap32WTo16(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MMDRV_MidiIn_Callback [internal] + */ +static void CALLBACK MMDRV_MidiIn_Callback(HDRVR hDev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD mld = (LPWINE_MLD)dwInstance; + + switch (uMsg) { + case MIM_OPEN: + case MIM_CLOSE: + /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ + + case MIM_DATA: + case MIM_MOREDATA: + case MIM_ERROR: + /* dwParam1 & dwParam2 are are data, nothing to do */ + break; + case MIM_LONGDATA: + case MIM_LONGERROR: + /* dwParam1 points to a MidiHdr, work to be done !!! */ + if (mld->bFrom32 && !MMDRV_Is32(mld->mmdIndex)) { + /* initial map is: 32 => 16 */ + LPMIDIHDR mh16 = MapSL(dwParam1); + LPMIDIHDR mh32 = *(LPMIDIHDR*)((LPSTR)mh16 - sizeof(LPMIDIHDR)); + + dwParam1 = (DWORD)mh32; + mh32->dwFlags = mh16->dwFlags; + mh32->dwBytesRecorded = mh16->dwBytesRecorded; + if (mh32->reserved >= sizeof(MIDIHDR)) + mh32->dwOffset = mh16->dwOffset; + } else if (!mld->bFrom32 && MMDRV_Is32(mld->mmdIndex)) { + /* initial map is: 16 => 32 */ + LPMIDIHDR mh32 = (LPMIDIHDR)(dwParam1); + SEGPTR segmh16 = *(SEGPTR*)((LPSTR)mh32 - sizeof(LPMIDIHDR)); + LPMIDIHDR mh16 = MapSL(segmh16); + + dwParam1 = (DWORD)segmh16; + mh16->dwFlags = mh32->dwFlags; + mh16->dwBytesRecorded = mh32->dwBytesRecorded; + if (mh16->reserved >= sizeof(MIDIHDR)) + mh16->dwOffset = mh32->dwOffset; + } + /* else { 16 => 16 or 32 => 32, nothing to do, same struct is kept }*/ + break; + /* case MOM_POSITIONCB: */ + default: + ERR("Unknown msg %u\n", uMsg); + } + + MMDRV_Callback(mld, hDev, uMsg, dwParam1, dwParam2); +} + +/* ================================= + * M I D I O U T M A P P E R S + * ================================= */ + +/************************************************************************** + * MMDRV_MidiOut_Map16To32W [internal] + */ +static WINMM_MapType MMDRV_MidiOut_Map16To32W (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + case MODM_GETNUMDEVS: + case MODM_DATA: + case MODM_RESET: + case MODM_SETVOLUME: + ret = WINMM_MAP_OK; + break; + + case MODM_OPEN: + case MODM_CLOSE: + case MODM_GETVOLUME: + FIXME("Shouldn't be used: the corresponding 16 bit functions use the 32 bit interface\n"); + break; + + case MODM_GETDEVCAPS: + { + LPMIDIOUTCAPSW moc32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPMIDIOUTCAPS16) + sizeof(MIDIOUTCAPSW)); + LPMIDIOUTCAPS16 moc16 = MapSL(*lpParam1); + + if (moc32) { + *(LPMIDIOUTCAPS16*)moc32 = moc16; + moc32 = (LPMIDIOUTCAPSW)((LPSTR)moc32 + sizeof(LPMIDIOUTCAPS16)); + *lpParam1 = (DWORD)moc32; + *lpParam2 = sizeof(MIDIOUTCAPSW); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case MODM_PREPARE: + { + LPMIDIHDR mh32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPMIDIHDR) + sizeof(MIDIHDR)); + LPMIDIHDR mh16 = MapSL(*lpParam1); + + if (mh32) { + *(LPMIDIHDR*)mh32 = (LPMIDIHDR)*lpParam1; + mh32 = (LPMIDIHDR)((LPSTR)mh32 + sizeof(LPMIDIHDR)); + mh32->lpData = MapSL((SEGPTR)mh16->lpData); + mh32->dwBufferLength = mh16->dwBufferLength; + mh32->dwBytesRecorded = mh16->dwBytesRecorded; + mh32->dwUser = mh16->dwUser; + mh32->dwFlags = mh16->dwFlags; + /* FIXME: nothing on mh32->lpNext */ + /* could link the mh32->lpNext at this level for memory house keeping */ + mh32->dwOffset = (*lpParam2 >= sizeof(MIDIHDR)) ? ((LPMIDIHDR)mh16)->dwOffset : 0; + mh16->lpNext = mh32; /* for reuse in unprepare and write */ + /* store size of passed MIDIHDR?? structure to know if dwOffset is available or not */ + mh16->reserved = *lpParam2; + *lpParam1 = (DWORD)mh32; + *lpParam2 = sizeof(MIDIHDR); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case MODM_UNPREPARE: + case MODM_LONGDATA: + { + LPMIDIHDR mh16 = MapSL(*lpParam1); + LPMIDIHDR mh32 = (LPMIDIHDR)mh16->lpNext; + + *lpParam1 = (DWORD)mh32; + *lpParam2 = sizeof(MIDIHDR); + /* dwBufferLength can be reduced between prepare & write */ + if (wMsg == MODM_LONGDATA && mh32->dwBufferLength < mh16->dwBufferLength) { + ERR("Size of buffer has been increased from %ld to %ld, keeping initial value\n", + mh32->dwBufferLength, mh16->dwBufferLength); + } else + mh32->dwBufferLength = mh16->dwBufferLength; + ret = WINMM_MAP_OKMEM; + } + break; + + case MODM_CACHEPATCHES: + case MODM_CACHEDRUMPATCHES: + default: + FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_MidiOut_UnMap16To32W [internal] + */ +static WINMM_MapType MMDRV_MidiOut_UnMap16To32W(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + case MODM_GETNUMDEVS: + case MODM_DATA: + case MODM_RESET: + case MODM_SETVOLUME: + ret = WINMM_MAP_OK; + break; + + case MODM_OPEN: + case MODM_CLOSE: + case MODM_GETVOLUME: + FIXME("Shouldn't be used: the corresponding 16 bit functions use the 32 bit interface\n"); + break; + + case MODM_GETDEVCAPS: + { + LPMIDIOUTCAPSW moc32 = (LPMIDIOUTCAPSW)(*lpParam1); + LPMIDIOUTCAPS16 moc16 = *(LPMIDIOUTCAPS16*)((LPSTR)moc32 - sizeof(LPMIDIOUTCAPS16)); + + moc16->wMid = moc32->wMid; + moc16->wPid = moc32->wPid; + moc16->vDriverVersion = moc32->vDriverVersion; + WideCharToMultiByte( CP_ACP, 0, moc32->szPname, -1, moc16->szPname, + sizeof(moc16->szPname), NULL, NULL ); + moc16->wTechnology = moc32->wTechnology; + moc16->wVoices = moc32->wVoices; + moc16->wNotes = moc32->wNotes; + moc16->wChannelMask = moc32->wChannelMask; + moc16->dwSupport = moc32->dwSupport; + HeapFree(GetProcessHeap(), 0, (LPSTR)moc32 - sizeof(LPMIDIOUTCAPS16)); + ret = WINMM_MAP_OK; + } + break; + case MODM_PREPARE: + case MODM_UNPREPARE: + case MODM_LONGDATA: + { + LPMIDIHDR mh32 = (LPMIDIHDR)(*lpParam1); + LPMIDIHDR mh16 = MapSL(*(SEGPTR*)((LPSTR)mh32 - sizeof(LPMIDIHDR))); + + assert(mh16->lpNext == mh32); + mh16->dwBufferLength = mh32->dwBufferLength; + mh16->dwBytesRecorded = mh32->dwBytesRecorded; + mh16->dwUser = mh32->dwUser; + mh16->dwFlags = mh32->dwFlags; + if (mh16->reserved >= sizeof(MIDIHDR)) + mh16->dwOffset = mh32->dwOffset; + + if (wMsg == MODM_UNPREPARE && fn_ret == MMSYSERR_NOERROR) { + HeapFree(GetProcessHeap(), 0, (LPSTR)mh32 - sizeof(LPMIDIHDR)); + mh16->lpNext = 0; + } + ret = WINMM_MAP_OK; + } + break; + + case MODM_CACHEPATCHES: + case MODM_CACHEDRUMPATCHES: + default: + FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_MidiOut_Map32WTo16 [internal] + */ +static WINMM_MapType MMDRV_MidiOut_Map32WTo16 (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + case MODM_CLOSE: + case MODM_GETNUMDEVS: + case MODM_DATA: + case MODM_RESET: + case MODM_SETVOLUME: + ret = WINMM_MAP_OK; + break; + case MODM_GETDEVCAPS: + { + LPMIDIOUTCAPSW moc32 = (LPMIDIOUTCAPSW)*lpParam1; + LPSTR ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(LPMIDIOUTCAPSW)+sizeof(MIDIOUTCAPS16)); + + if (ptr) { + *(LPMIDIOUTCAPSW*)ptr = moc32; + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + *lpParam1 = (DWORD)MapLS(ptr) + sizeof(LPMIDIOUTCAPSW); + *lpParam2 = sizeof(MIDIOUTCAPS16); + } + break; + case MODM_PREPARE: + { + LPMIDIHDR mh32 = (LPMIDIHDR)*lpParam1; + LPMIDIHDR mh16; + LPVOID ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPMIDIHDR) + sizeof(MIDIHDR) + mh32->dwBufferLength); + + if (ptr) { + *(LPMIDIHDR*)ptr = mh32; + mh16 = (LPMIDIHDR)((LPSTR)ptr + sizeof(LPMIDIHDR)); + *lpParam1 = MapLS(mh16); + mh16->lpData = (LPSTR)*lpParam1 + sizeof(MIDIHDR); + /* data will be copied on WODM_WRITE */ + mh16->dwBufferLength = mh32->dwBufferLength; + mh16->dwBytesRecorded = mh32->dwBytesRecorded; + mh16->dwUser = mh32->dwUser; + mh16->dwFlags = mh32->dwFlags; + /* FIXME: nothing on mh32->lpNext */ + /* could link the mh32->lpNext at this level for memory house keeping */ + mh16->dwOffset = (*lpParam2 >= sizeof(MIDIHDR)) ? mh32->dwOffset : 0; + + mh32->lpNext = (LPMIDIHDR)mh16; /* for reuse in unprepare and write */ + mh32->reserved = *lpParam2; + + TRACE("mh16=%08lx mh16->lpData=%08lx mh32->buflen=%lu mh32->lpData=%08lx\n", + *lpParam1, (DWORD)mh16->lpData, + mh32->dwBufferLength, (DWORD)mh32->lpData); + *lpParam2 = sizeof(MIDIHDR); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case MODM_UNPREPARE: + case MODM_LONGDATA: + { + LPMIDIHDR mh32 = (LPMIDIHDR)(*lpParam1); + LPMIDIHDR mh16 = (LPMIDIHDR)mh32->lpNext; + LPSTR ptr = (LPSTR)mh16 - sizeof(LPMIDIHDR); + + assert(*(LPMIDIHDR*)ptr == mh32); + + if (wMsg == MODM_LONGDATA) + memcpy((LPSTR)mh16 + sizeof(MIDIHDR), mh32->lpData, mh32->dwBufferLength); + + *lpParam1 = MapLS(mh16); + *lpParam2 = sizeof(MIDIHDR); + TRACE("mh16=%08lx mh16->lpData=%08lx mh32->buflen=%lu mh32->lpData=%08lx\n", + *lpParam1, (DWORD)mh16->lpData, mh32->dwBufferLength, (DWORD)mh32->lpData); + + /* dwBufferLength can be reduced between prepare & write */ + if (wMsg == MODM_LONGDATA && mh16->dwBufferLength < mh32->dwBufferLength) { + ERR("Size of buffer has been increased from %ld to %ld, keeping initial value\n", + mh16->dwBufferLength, mh32->dwBufferLength); + } else + mh16->dwBufferLength = mh32->dwBufferLength; + ret = WINMM_MAP_OKMEM; + } + break; + case MODM_OPEN: + { + LPMIDIOPENDESC mod32 = (LPMIDIOPENDESC)*lpParam1; + LPVOID ptr; + LPMIDIOPENDESC16 mod16; + + /* allocated data are mapped as follows: + LPMIDIOPENDESC ptr to orig lParam1 + DWORD orig dwUser, which is a pointer to DWORD:driver dwInstance + DWORD dwUser passed to driver + MIDIOPENDESC16 mod16: openDesc passed to driver + MIDIOPENSTRMID cIds + */ + ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPMIDIOPENDESC) + 2*sizeof(DWORD) + sizeof(MIDIOPENDESC16) + + mod32->cIds ? (mod32->cIds - 1) * sizeof(MIDIOPENSTRMID) : 0); + + if (ptr) { + SEGPTR segptr = MapLS(ptr); + *(LPMIDIOPENDESC*)ptr = mod32; + *(LPDWORD)((char*)ptr + sizeof(LPMIDIOPENDESC)) = *lpdwUser; + mod16 = (LPMIDIOPENDESC16)((LPSTR)ptr + sizeof(LPMIDIOPENDESC) + 2*sizeof(DWORD)); + + mod16->hMidi = HMIDI_16(mod32->hMidi); + mod16->dwCallback = mod32->dwCallback; + mod16->dwInstance = mod32->dwInstance; + mod16->dnDevNode = mod32->dnDevNode; + mod16->cIds = mod32->cIds; + memcpy(&mod16->rgIds, &mod32->rgIds, mod32->cIds * sizeof(MIDIOPENSTRMID)); + + *lpParam1 = (DWORD)segptr + sizeof(LPMIDIOPENDESC) + 2*sizeof(DWORD); + *lpdwUser = (DWORD)segptr + sizeof(LPMIDIOPENDESC) + sizeof(DWORD); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case MODM_GETVOLUME: + case MODM_CACHEPATCHES: + case MODM_CACHEDRUMPATCHES: + default: + FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_MidiOut_UnMap32WTo16 [internal] + */ +static WINMM_MapType MMDRV_MidiOut_UnMap32WTo16(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + case MODM_CLOSE: + case MODM_GETNUMDEVS: + case MODM_DATA: + case MODM_RESET: + case MODM_SETVOLUME: + ret = WINMM_MAP_OK; + break; + case MODM_GETDEVCAPS: + { + LPMIDIOUTCAPS16 moc16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)moc16 - sizeof(LPMIDIOUTCAPSW); + LPMIDIOUTCAPSW moc32 = *(LPMIDIOUTCAPSW*)ptr; + + moc32->wMid = moc16->wMid; + moc32->wPid = moc16->wPid; + moc32->vDriverVersion = moc16->vDriverVersion; + WideCharToMultiByte( CP_ACP, 0, moc32->szPname, -1, moc16->szPname, + sizeof(moc16->szPname), NULL, NULL ); + moc32->wTechnology = moc16->wTechnology; + moc32->wVoices = moc16->wVoices; + moc32->wNotes = moc16->wNotes; + moc32->wChannelMask = moc16->wChannelMask; + moc32->dwSupport = moc16->dwSupport; + UnMapLS( *lpParam1 ); + HeapFree( GetProcessHeap(), 0, ptr ); + ret = WINMM_MAP_OK; + } + break; + case MODM_PREPARE: + case MODM_UNPREPARE: + case MODM_LONGDATA: + { + LPMIDIHDR mh16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)mh16 - sizeof(LPMIDIHDR); + LPMIDIHDR mh32 = *(LPMIDIHDR*)ptr; + + assert(mh32->lpNext == (LPMIDIHDR)mh16); + UnMapLS( *lpParam1 ); + mh32->dwBytesRecorded = mh16->dwBytesRecorded; + mh32->dwUser = mh16->dwUser; + mh32->dwFlags = mh16->dwFlags; + + if (wMsg == MODM_UNPREPARE && fn_ret == MMSYSERR_NOERROR) { + HeapFree( GetProcessHeap(), 0, ptr ); + mh32->lpNext = 0; + } + ret = WINMM_MAP_OK; + } + break; + case MODM_OPEN: + { + LPMIDIOPENDESC16 mod16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)mod16 - sizeof(LPMIDIOPENDESC) - 2*sizeof(DWORD); + UnMapLS( *lpParam1 ); + **(DWORD**)(ptr + sizeof(LPMIDIOPENDESC)) = *(LPDWORD)(ptr + sizeof(LPMIDIOPENDESC) + sizeof(DWORD)); + + HeapFree( GetProcessHeap(), 0, ptr ); + ret = WINMM_MAP_OK; + } + break; + case MODM_GETVOLUME: + case MODM_CACHEPATCHES: + case MODM_CACHEDRUMPATCHES: + default: + FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_MidiOut_Callback [internal] + */ +static void CALLBACK MMDRV_MidiOut_Callback(HDRVR hDev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD mld = (LPWINE_MLD)dwInstance; + + switch (uMsg) { + case MOM_OPEN: + case MOM_CLOSE: + /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ + break; + case MOM_DONE: + if (mld->bFrom32 && !MMDRV_Is32(mld->mmdIndex)) { + /* initial map is: 32 => 16 */ + LPMIDIHDR mh16 = MapSL(dwParam1); + LPMIDIHDR mh32 = *(LPMIDIHDR*)((LPSTR)mh16 - sizeof(LPMIDIHDR)); + + dwParam1 = (DWORD)mh32; + mh32->dwFlags = mh16->dwFlags; + mh32->dwOffset = mh16->dwOffset; + if (mh32->reserved >= sizeof(MIDIHDR)) + mh32->dwOffset = mh16->dwOffset; + } else if (!mld->bFrom32 && MMDRV_Is32(mld->mmdIndex)) { + /* initial map is: 16 => 32 */ + LPMIDIHDR mh32 = (LPMIDIHDR)(dwParam1); + SEGPTR segmh16 = *(SEGPTR*)((LPSTR)mh32 - sizeof(LPMIDIHDR)); + LPMIDIHDR mh16 = MapSL(segmh16); + + dwParam1 = (DWORD)segmh16; + mh16->dwFlags = mh32->dwFlags; + if (mh16->reserved >= sizeof(MIDIHDR)) + mh16->dwOffset = mh32->dwOffset; + } + /* else { 16 => 16 or 32 => 32, nothing to do, same struct is kept }*/ + break; + /* case MOM_POSITIONCB: */ + default: + ERR("Unknown msg %u\n", uMsg); + } + + MMDRV_Callback(mld, hDev, uMsg, dwParam1, dwParam2); +} + +/* ================================= + * W A V E I N M A P P E R S + * ================================= */ + +/************************************************************************** + * MMDRV_WaveIn_Map16To32W [internal] + */ +static WINMM_MapType MMDRV_WaveIn_Map16To32W (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + case WIDM_GETNUMDEVS: + case WIDM_RESET: + case WIDM_START: + case WIDM_STOP: + ret = WINMM_MAP_OK; + break; + case WIDM_OPEN: + case WIDM_CLOSE: + FIXME("Shouldn't be used: the corresponding 16 bit functions use the 32 bit interface\n"); + break; + case WIDM_GETDEVCAPS: + { + LPWAVEINCAPSW wic32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPWAVEINCAPS16) + sizeof(WAVEINCAPSW)); + LPWAVEINCAPS16 wic16 = MapSL(*lpParam1); + + if (wic32) { + *(LPWAVEINCAPS16*)wic32 = wic16; + wic32 = (LPWAVEINCAPSW)((LPSTR)wic32 + sizeof(LPWAVEINCAPS16)); + *lpParam1 = (DWORD)wic32; + *lpParam2 = sizeof(WAVEINCAPSW); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case WIDM_GETPOS: + { + LPMMTIME mmt32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPMMTIME16) + sizeof(MMTIME)); + LPMMTIME16 mmt16 = MapSL(*lpParam1); + + if (mmt32) { + *(LPMMTIME16*)mmt32 = mmt16; + mmt32 = (LPMMTIME)((LPSTR)mmt32 + sizeof(LPMMTIME16)); + + mmt32->wType = mmt16->wType; + *lpParam1 = (DWORD)mmt32; + *lpParam2 = sizeof(MMTIME); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case WIDM_PREPARE: + { + LPWAVEHDR wh32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPWAVEHDR) + sizeof(WAVEHDR)); + LPWAVEHDR wh16 = MapSL(*lpParam1); + + if (wh32) { + *(LPWAVEHDR*)wh32 = (LPWAVEHDR)*lpParam1; + wh32 = (LPWAVEHDR)((LPSTR)wh32 + sizeof(LPWAVEHDR)); + wh32->lpData = MapSL((SEGPTR)wh16->lpData); + wh32->dwBufferLength = wh16->dwBufferLength; + wh32->dwBytesRecorded = wh16->dwBytesRecorded; + wh32->dwUser = wh16->dwUser; + wh32->dwFlags = wh16->dwFlags; + wh32->dwLoops = wh16->dwLoops; + /* FIXME: nothing on wh32->lpNext */ + /* could link the wh32->lpNext at this level for memory house keeping */ + wh16->lpNext = wh32; /* for reuse in unprepare and write */ + *lpParam1 = (DWORD)wh32; + *lpParam2 = sizeof(WAVEHDR); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case WIDM_ADDBUFFER: + case WIDM_UNPREPARE: + { + LPWAVEHDR wh16 = MapSL(*lpParam1); + LPWAVEHDR wh32 = (LPWAVEHDR)wh16->lpNext; + + *lpParam1 = (DWORD)wh32; + *lpParam2 = sizeof(WAVEHDR); + /* dwBufferLength can be reduced between prepare & write */ + if (wMsg == WIDM_ADDBUFFER && wh32->dwBufferLength < wh16->dwBufferLength) { + ERR("Size of buffer has been increased from %ld to %ld, keeping initial value\n", + wh32->dwBufferLength, wh16->dwBufferLength); + } else + wh32->dwBufferLength = wh16->dwBufferLength; + ret = WINMM_MAP_OKMEM; + } + break; + case WIDM_MAPPER_STATUS: + /* just a single DWORD */ + *lpParam2 = (DWORD)MapSL(*lpParam2); + ret = WINMM_MAP_OK; + break; + default: + FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_WaveIn_UnMap16To32W [internal] + */ +static WINMM_MapType MMDRV_WaveIn_UnMap16To32W(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + case WIDM_GETNUMDEVS: + case WIDM_RESET: + case WIDM_START: + case WIDM_STOP: + case WIDM_MAPPER_STATUS: + ret = WINMM_MAP_OK; + break; + case WIDM_OPEN: + case WIDM_CLOSE: + FIXME("Shouldn't be used: the corresponding 16 bit functions use the 32 bit interface\n"); + break; + case WIDM_GETDEVCAPS: + { + LPWAVEINCAPSW wic32 = (LPWAVEINCAPSW)(*lpParam1); + LPWAVEINCAPS16 wic16 = *(LPWAVEINCAPS16*)((LPSTR)wic32 - sizeof(LPWAVEINCAPS16)); + + wic16->wMid = wic32->wMid; + wic16->wPid = wic32->wPid; + wic16->vDriverVersion = wic32->vDriverVersion; + WideCharToMultiByte( CP_ACP, 0, wic32->szPname, -1, wic16->szPname, + sizeof(wic16->szPname), NULL, NULL ); + wic16->dwFormats = wic32->dwFormats; + wic16->wChannels = wic32->wChannels; + HeapFree(GetProcessHeap(), 0, (LPSTR)wic32 - sizeof(LPWAVEINCAPS16)); + ret = WINMM_MAP_OK; + } + break; + case WIDM_GETPOS: + { + LPMMTIME mmt32 = (LPMMTIME)(*lpParam1); + LPMMTIME16 mmt16 = *(LPMMTIME16*)((LPSTR)mmt32 - sizeof(LPMMTIME16)); + + MMSYSTEM_MMTIME32to16(mmt16, mmt32); + HeapFree(GetProcessHeap(), 0, (LPSTR)mmt32 - sizeof(LPMMTIME16)); + ret = WINMM_MAP_OK; + } + break; + case WIDM_ADDBUFFER: + case WIDM_PREPARE: + case WIDM_UNPREPARE: + { + LPWAVEHDR wh32 = (LPWAVEHDR)(*lpParam1); + LPWAVEHDR wh16 = MapSL(*(SEGPTR*)((LPSTR)wh32 - sizeof(LPWAVEHDR))); + + assert(wh16->lpNext == wh32); + wh16->dwBufferLength = wh32->dwBufferLength; + wh16->dwBytesRecorded = wh32->dwBytesRecorded; + wh16->dwUser = wh32->dwUser; + wh16->dwFlags = wh32->dwFlags; + wh16->dwLoops = wh32->dwLoops; + + if (wMsg == WIDM_UNPREPARE && fn_ret == MMSYSERR_NOERROR) { + HeapFree(GetProcessHeap(), 0, (LPSTR)wh32 - sizeof(LPWAVEHDR)); + wh16->lpNext = 0; + } + ret = WINMM_MAP_OK; + } + break; + default: + FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_WaveIn_Map32WTo16 [internal] + */ +static WINMM_MapType MMDRV_WaveIn_Map32WTo16 (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + case WIDM_CLOSE: + case WIDM_GETNUMDEVS: + case WIDM_RESET: + case WIDM_START: + case WIDM_STOP: + ret = WINMM_MAP_OK; + break; + + case WIDM_OPEN: + { + LPWAVEOPENDESC wod32 = (LPWAVEOPENDESC)*lpParam1; + int sz = sizeof(WAVEFORMATEX); + LPVOID ptr; + LPWAVEOPENDESC16 wod16; + + /* allocated data are mapped as follows: + LPWAVEOPENDESC ptr to orig lParam1 + DWORD orig dwUser, which is a pointer to DWORD:driver dwInstance + DWORD dwUser passed to driver + WAVEOPENDESC16 wod16: openDesc passed to driver + WAVEFORMATEX openDesc->lpFormat passed to driver + xxx extra bytes to WAVEFORMATEX + */ + if (wod32->lpFormat->wFormatTag != WAVE_FORMAT_PCM) { + TRACE("Allocating %u extra bytes (%d)\n", ((LPWAVEFORMATEX)wod32->lpFormat)->cbSize, wod32->lpFormat->wFormatTag); + sz += ((LPWAVEFORMATEX)wod32->lpFormat)->cbSize; + } + + ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD) + sizeof(WAVEOPENDESC16) + sz); + + if (ptr) { + SEGPTR seg_ptr = MapLS( ptr ); + *(LPWAVEOPENDESC*)ptr = wod32; + *(LPDWORD)((char*)ptr + sizeof(LPWAVEOPENDESC)) = *lpdwUser; + wod16 = (LPWAVEOPENDESC16)((LPSTR)ptr + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD)); + + wod16->hWave = HWAVE_16(wod32->hWave); + wod16->lpFormat = (LPWAVEFORMATEX)(seg_ptr + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD) + sizeof(WAVEOPENDESC16)); + memcpy(wod16 + 1, wod32->lpFormat, sz); + + wod16->dwCallback = wod32->dwCallback; + wod16->dwInstance = wod32->dwInstance; + wod16->uMappedDeviceID = wod32->uMappedDeviceID; + wod16->dnDevNode = wod32->dnDevNode; + + *lpParam1 = seg_ptr + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD); + *lpdwUser = seg_ptr + sizeof(LPWAVEOPENDESC) + sizeof(DWORD); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case WIDM_PREPARE: + { + LPWAVEHDR wh32 = (LPWAVEHDR)*lpParam1; + LPWAVEHDR wh16; + LPVOID ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPWAVEHDR) + sizeof(WAVEHDR) + wh32->dwBufferLength); + + if (ptr) { + SEGPTR seg_ptr = MapLS( ptr ); + *(LPWAVEHDR*)ptr = wh32; + wh16 = (LPWAVEHDR)((LPSTR)ptr + sizeof(LPWAVEHDR)); + wh16->lpData = (LPSTR)seg_ptr + sizeof(LPWAVEHDR) + sizeof(WAVEHDR); + /* data will be copied on WODM_WRITE */ + wh16->dwBufferLength = wh32->dwBufferLength; + wh16->dwBytesRecorded = wh32->dwBytesRecorded; + wh16->dwUser = wh32->dwUser; + wh16->dwFlags = wh32->dwFlags; + wh16->dwLoops = wh32->dwLoops; + /* FIXME: nothing on wh32->lpNext */ + /* could link the wh32->lpNext at this level for memory house keeping */ + wh32->lpNext = wh16; /* for reuse in unprepare and write */ + TRACE("wh16=%08lx wh16->lpData=%08lx wh32->buflen=%lu wh32->lpData=%08lx\n", + seg_ptr + sizeof(LPWAVEHDR), (DWORD)wh16->lpData, + wh32->dwBufferLength, (DWORD)wh32->lpData); + *lpParam1 = seg_ptr + sizeof(LPWAVEHDR); + *lpParam2 = sizeof(WAVEHDR); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case WIDM_ADDBUFFER: + case WIDM_UNPREPARE: + { + LPWAVEHDR wh32 = (LPWAVEHDR)(*lpParam1); + LPWAVEHDR wh16 = wh32->lpNext; + LPSTR ptr = (LPSTR)wh16 - sizeof(LPWAVEHDR); + SEGPTR seg_ptr = MapLS( ptr ); + + assert(*(LPWAVEHDR*)ptr == wh32); + + TRACE("wh16=%08lx wh16->lpData=%08lx wh32->buflen=%lu wh32->lpData=%08lx\n", + seg_ptr + sizeof(LPWAVEHDR), (DWORD)wh16->lpData, + wh32->dwBufferLength, (DWORD)wh32->lpData); + + if (wMsg == WIDM_ADDBUFFER) + memcpy((LPSTR)wh16 + sizeof(WAVEHDR), wh32->lpData, wh32->dwBufferLength); + + *lpParam1 = seg_ptr + sizeof(LPWAVEHDR); + *lpParam2 = sizeof(WAVEHDR); + /* dwBufferLength can be reduced between prepare & write */ + if (wMsg == WIDM_ADDBUFFER && wh16->dwBufferLength < wh32->dwBufferLength) { + ERR("Size of buffer has been increased from %ld to %ld, keeping initial value\n", + wh16->dwBufferLength, wh32->dwBufferLength); + } else + wh16->dwBufferLength = wh32->dwBufferLength; + ret = WINMM_MAP_OKMEM; + } + break; + case WIDM_GETDEVCAPS: + { + LPWAVEINCAPSW wic32 = (LPWAVEINCAPSW)*lpParam1; + LPSTR ptr = HeapAlloc( GetProcessHeap(), 0 ,sizeof(LPWAVEINCAPSW) + sizeof(WAVEINCAPS16)); + + if (ptr) { + *(LPWAVEINCAPSW*)ptr = wic32; + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + *lpParam1 = MapLS(ptr) + sizeof(LPWAVEINCAPSW); + *lpParam2 = sizeof(WAVEINCAPS16); + } + break; + case WIDM_GETPOS: + { + LPMMTIME mmt32 = (LPMMTIME)*lpParam1; + LPSTR ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(LPMMTIME) + sizeof(MMTIME16)); + LPMMTIME16 mmt16 = (LPMMTIME16)(ptr + sizeof(LPMMTIME)); + + if (ptr) { + *(LPMMTIME*)ptr = mmt32; + mmt16->wType = mmt32->wType; + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + *lpParam1 = MapLS(ptr) + sizeof(LPMMTIME); + *lpParam2 = sizeof(MMTIME16); + } + break; + case DRVM_MAPPER_STATUS: + { + LPDWORD p32 = (LPDWORD)*lpParam2; + *lpParam2 = MapLS(p32); + ret = WINMM_MAP_OKMEM; + } + break; + default: + FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_WaveIn_UnMap32WTo16 [internal] + */ +static WINMM_MapType MMDRV_WaveIn_UnMap32WTo16(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + case WIDM_CLOSE: + case WIDM_GETNUMDEVS: + case WIDM_RESET: + case WIDM_START: + case WIDM_STOP: + ret = WINMM_MAP_OK; + break; + + case WIDM_OPEN: + { + LPWAVEOPENDESC16 wod16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)wod16 - sizeof(LPWAVEOPENDESC) - 2*sizeof(DWORD); + LPWAVEOPENDESC wod32 = *(LPWAVEOPENDESC*)ptr; + + UnMapLS( *lpParam1 ); + wod32->uMappedDeviceID = wod16->uMappedDeviceID; + **(DWORD**)(ptr + sizeof(LPWAVEOPENDESC)) = *(LPDWORD)(ptr + sizeof(LPWAVEOPENDESC) + sizeof(DWORD)); + HeapFree( GetProcessHeap(), 0, ptr ); + ret = WINMM_MAP_OK; + } + break; + + case WIDM_ADDBUFFER: + case WIDM_PREPARE: + case WIDM_UNPREPARE: + { + LPWAVEHDR wh16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)wh16 - sizeof(LPWAVEHDR); + LPWAVEHDR wh32 = *(LPWAVEHDR*)ptr; + + assert(wh32->lpNext == wh16); + wh32->dwBytesRecorded = wh16->dwBytesRecorded; + wh32->dwUser = wh16->dwUser; + wh32->dwFlags = wh16->dwFlags; + wh32->dwLoops = wh16->dwLoops; + UnMapLS( *lpParam1 ); + + if (wMsg == WIDM_UNPREPARE && fn_ret == MMSYSERR_NOERROR) { + HeapFree( GetProcessHeap(), 0, ptr ); + wh32->lpNext = 0; + } + ret = WINMM_MAP_OK; + } + break; + case WIDM_GETDEVCAPS: + { + LPWAVEINCAPS16 wic16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)wic16 - sizeof(LPWAVEINCAPSW); + LPWAVEINCAPSW wic32 = *(LPWAVEINCAPSW*)ptr; + + wic32->wMid = wic16->wMid; + wic32->wPid = wic16->wPid; + wic32->vDriverVersion = wic16->vDriverVersion; + WideCharToMultiByte( CP_ACP, 0, wic32->szPname, -1, wic16->szPname, + sizeof(wic16->szPname), NULL, NULL ); + wic32->dwFormats = wic16->dwFormats; + wic32->wChannels = wic16->wChannels; + UnMapLS( *lpParam1 ); + HeapFree( GetProcessHeap(), 0, ptr ); + ret = WINMM_MAP_OK; + } + break; + case WIDM_GETPOS: + { + LPMMTIME16 mmt16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)mmt16 - sizeof(LPMMTIME); + LPMMTIME mmt32 = *(LPMMTIME*)ptr; + + MMSYSTEM_MMTIME16to32(mmt32, mmt16); + UnMapLS( *lpParam1 ); + HeapFree( GetProcessHeap(), 0, ptr ); + ret = WINMM_MAP_OK; + } + break; + case DRVM_MAPPER_STATUS: + { + UnMapLS( *lpParam2 ); + ret = WINMM_MAP_OK; + } + break; + default: + FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_WaveIn_Callback [internal] + */ +static void CALLBACK MMDRV_WaveIn_Callback(HDRVR hDev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD mld = (LPWINE_MLD)dwInstance; + + switch (uMsg) { + case WIM_OPEN: + case WIM_CLOSE: + /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ + break; + case WIM_DATA: + if (mld->bFrom32 && !MMDRV_Is32(mld->mmdIndex)) { + /* initial map is: 32 => 16 */ + LPWAVEHDR wh16 = MapSL(dwParam1); + LPWAVEHDR wh32 = *(LPWAVEHDR*)((LPSTR)wh16 - sizeof(LPWAVEHDR)); + + dwParam1 = (DWORD)wh32; + wh32->dwFlags = wh16->dwFlags; + wh32->dwBytesRecorded = wh16->dwBytesRecorded; + } else if (!mld->bFrom32 && MMDRV_Is32(mld->mmdIndex)) { + /* initial map is: 16 => 32 */ + LPWAVEHDR wh32 = (LPWAVEHDR)(dwParam1); + SEGPTR segwh16 = *(SEGPTR*)((LPSTR)wh32 - sizeof(LPWAVEHDR)); + LPWAVEHDR wh16 = MapSL(segwh16); + + dwParam1 = (DWORD)segwh16; + wh16->dwFlags = wh32->dwFlags; + wh16->dwBytesRecorded = wh32->dwBytesRecorded; + } + /* else { 16 => 16 or 32 => 32, nothing to do, same struct is kept }*/ + break; + default: + ERR("Unknown msg %u\n", uMsg); + } + + MMDRV_Callback(mld, hDev, uMsg, dwParam1, dwParam2); +} + +/* ================================= + * W A V E O U T M A P P E R S + * ================================= */ + +/************************************************************************** + * MMDRV_WaveOut_Map16To32W [internal] + */ +static WINMM_MapType MMDRV_WaveOut_Map16To32W (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + /* nothing to do */ + case WODM_BREAKLOOP: + case WODM_CLOSE: + case WODM_GETNUMDEVS: + case WODM_PAUSE: + case WODM_RESET: + case WODM_RESTART: + case WODM_SETPITCH: + case WODM_SETPLAYBACKRATE: + case WODM_SETVOLUME: + ret = WINMM_MAP_OK; + break; + + case WODM_GETPITCH: + case WODM_GETPLAYBACKRATE: + case WODM_GETVOLUME: + case WODM_OPEN: + FIXME("Shouldn't be used: the corresponding 16 bit functions use the 32 bit interface\n"); + break; + + case WODM_GETDEVCAPS: + { + LPWAVEOUTCAPSW woc32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPWAVEOUTCAPS16) + sizeof(WAVEOUTCAPSW)); + LPWAVEOUTCAPS16 woc16 = MapSL(*lpParam1); + + if (woc32) { + *(LPWAVEOUTCAPS16*)woc32 = woc16; + woc32 = (LPWAVEOUTCAPSW)((LPSTR)woc32 + sizeof(LPWAVEOUTCAPS16)); + *lpParam1 = (DWORD)woc32; + *lpParam2 = sizeof(WAVEOUTCAPSW); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case WODM_GETPOS: + { + LPMMTIME mmt32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPMMTIME16) + sizeof(MMTIME)); + LPMMTIME16 mmt16 = MapSL(*lpParam1); + + if (mmt32) { + *(LPMMTIME16*)mmt32 = mmt16; + mmt32 = (LPMMTIME)((LPSTR)mmt32 + sizeof(LPMMTIME16)); + + mmt32->wType = mmt16->wType; + *lpParam1 = (DWORD)mmt32; + *lpParam2 = sizeof(MMTIME); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case WODM_PREPARE: + { + LPWAVEHDR wh32 = HeapAlloc(GetProcessHeap(), 0, sizeof(LPWAVEHDR) + sizeof(WAVEHDR)); + LPWAVEHDR wh16 = MapSL(*lpParam1); + + if (wh32) { + *(LPWAVEHDR*)wh32 = (LPWAVEHDR)*lpParam1; + wh32 = (LPWAVEHDR)((LPSTR)wh32 + sizeof(LPWAVEHDR)); + wh32->lpData = MapSL((SEGPTR)wh16->lpData); + wh32->dwBufferLength = wh16->dwBufferLength; + wh32->dwBytesRecorded = wh16->dwBytesRecorded; + wh32->dwUser = wh16->dwUser; + wh32->dwFlags = wh16->dwFlags; + wh32->dwLoops = wh16->dwLoops; + /* FIXME: nothing on wh32->lpNext */ + /* could link the wh32->lpNext at this level for memory house keeping */ + wh16->lpNext = wh32; /* for reuse in unprepare and write */ + *lpParam1 = (DWORD)wh32; + *lpParam2 = sizeof(WAVEHDR); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case WODM_UNPREPARE: + case WODM_WRITE: + { + LPWAVEHDR wh16 = MapSL(*lpParam1); + LPWAVEHDR wh32 = (LPWAVEHDR)wh16->lpNext; + + *lpParam1 = (DWORD)wh32; + *lpParam2 = sizeof(WAVEHDR); + /* dwBufferLength can be reduced between prepare & write */ + if (wMsg == WODM_WRITE && wh32->dwBufferLength < wh16->dwBufferLength) { + ERR("Size of buffer has been increased from %ld to %ld, keeping initial value\n", + wh32->dwBufferLength, wh16->dwBufferLength); + } else + wh32->dwBufferLength = wh16->dwBufferLength; + ret = WINMM_MAP_OKMEM; + } + break; + case WODM_MAPPER_STATUS: + *lpParam2 = (DWORD)MapSL(*lpParam2); + ret = WINMM_MAP_OK; + break; + default: + FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_WaveOut_UnMap16To32W [internal] + */ +static WINMM_MapType MMDRV_WaveOut_UnMap16To32W(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + /* nothing to do */ + case WODM_BREAKLOOP: + case WODM_CLOSE: + case WODM_GETNUMDEVS: + case WODM_PAUSE: + case WODM_RESET: + case WODM_RESTART: + case WODM_SETPITCH: + case WODM_SETPLAYBACKRATE: + case WODM_SETVOLUME: + case WODM_MAPPER_STATUS: + ret = WINMM_MAP_OK; + break; + + case WODM_GETPITCH: + case WODM_GETPLAYBACKRATE: + case WODM_GETVOLUME: + case WODM_OPEN: + FIXME("Shouldn't be used: those 16 bit functions use the 32 bit interface\n"); + break; + + case WODM_GETDEVCAPS: + { + LPWAVEOUTCAPSW woc32 = (LPWAVEOUTCAPSW)(*lpParam1); + LPWAVEOUTCAPS16 woc16 = *(LPWAVEOUTCAPS16*)((LPSTR)woc32 - sizeof(LPWAVEOUTCAPS16)); + + woc16->wMid = woc32->wMid; + woc16->wPid = woc32->wPid; + woc16->vDriverVersion = woc32->vDriverVersion; + WideCharToMultiByte( CP_ACP, 0, woc32->szPname, -1, woc16->szPname, + sizeof(woc16->szPname), NULL, NULL ); + woc16->dwFormats = woc32->dwFormats; + woc16->wChannels = woc32->wChannels; + woc16->dwSupport = woc32->dwSupport; + HeapFree(GetProcessHeap(), 0, (LPSTR)woc32 - sizeof(LPWAVEOUTCAPS16)); + ret = WINMM_MAP_OK; + } + break; + case WODM_GETPOS: + { + LPMMTIME mmt32 = (LPMMTIME)(*lpParam1); + LPMMTIME16 mmt16 = *(LPMMTIME16*)((LPSTR)mmt32 - sizeof(LPMMTIME16)); + + MMSYSTEM_MMTIME32to16(mmt16, mmt32); + HeapFree(GetProcessHeap(), 0, (LPSTR)mmt32 - sizeof(LPMMTIME16)); + ret = WINMM_MAP_OK; + } + break; + case WODM_PREPARE: + case WODM_UNPREPARE: + case WODM_WRITE: + { + LPWAVEHDR wh32 = (LPWAVEHDR)(*lpParam1); + LPWAVEHDR wh16 = MapSL(*(SEGPTR*)((LPSTR)wh32 - sizeof(LPWAVEHDR))); + + assert(wh16->lpNext == wh32); + wh16->dwBufferLength = wh32->dwBufferLength; + wh16->dwBytesRecorded = wh32->dwBytesRecorded; + wh16->dwUser = wh32->dwUser; + wh16->dwFlags = wh32->dwFlags; + wh16->dwLoops = wh32->dwLoops; + + if (wMsg == WODM_UNPREPARE && fn_ret == MMSYSERR_NOERROR) { + HeapFree(GetProcessHeap(), 0, (LPSTR)wh32 - sizeof(LPWAVEHDR)); + wh16->lpNext = 0; + } + ret = WINMM_MAP_OK; + } + break; + default: + FIXME("NIY: no conversion yet for %u [%lx,%lx]\n", wMsg, *lpParam1, *lpParam2); + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_WaveOut_Map32WTo16 [internal] + */ +static WINMM_MapType MMDRV_WaveOut_Map32WTo16 (UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2) +{ + WINMM_MapType ret; + + switch (wMsg) { + /* nothing to do */ + case WODM_BREAKLOOP: + case WODM_CLOSE: + case WODM_GETNUMDEVS: + case WODM_PAUSE: + case WODM_RESET: + case WODM_RESTART: + case WODM_SETPITCH: + case WODM_SETPLAYBACKRATE: + case WODM_SETVOLUME: + ret = WINMM_MAP_OK; + break; + + case WODM_GETDEVCAPS: + { + LPWAVEOUTCAPSW woc32 = (LPWAVEOUTCAPSW)*lpParam1; + LPSTR ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPWAVEOUTCAPSW) + sizeof(WAVEOUTCAPS16)); + + if (ptr) { + *(LPWAVEOUTCAPSW*)ptr = woc32; + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + *lpParam1 = MapLS(ptr) + sizeof(LPWAVEOUTCAPSW); + *lpParam2 = sizeof(WAVEOUTCAPS16); + } + break; + case WODM_GETPITCH: + FIXME("NIY: no conversion yet\n"); + ret = WINMM_MAP_MSGERROR; + break; + case WODM_GETPLAYBACKRATE: + FIXME("NIY: no conversion yet\n"); + ret = WINMM_MAP_MSGERROR; + break; + case WODM_GETPOS: + { + LPMMTIME mmt32 = (LPMMTIME)*lpParam1; + LPSTR ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(LPMMTIME) + sizeof(MMTIME16)); + LPMMTIME16 mmt16 = (LPMMTIME16)(ptr + sizeof(LPMMTIME)); + + if (ptr) { + *(LPMMTIME*)ptr = mmt32; + mmt16->wType = mmt32->wType; + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + *lpParam1 = MapLS(ptr) + sizeof(LPMMTIME); + *lpParam2 = sizeof(MMTIME16); + } + break; + case WODM_GETVOLUME: + FIXME("NIY: no conversion yet\n"); + ret = WINMM_MAP_MSGERROR; + break; + case WODM_OPEN: + { + LPWAVEOPENDESC wod32 = (LPWAVEOPENDESC)*lpParam1; + int sz = sizeof(WAVEFORMATEX); + LPVOID ptr; + LPWAVEOPENDESC16 wod16; + + /* allocated data are mapped as follows: + LPWAVEOPENDESC ptr to orig lParam1 + DWORD orig dwUser, which is a pointer to DWORD:driver dwInstance + DWORD dwUser passed to driver + WAVEOPENDESC16 wod16: openDesc passed to driver + WAVEFORMATEX openDesc->lpFormat passed to driver + xxx extra bytes to WAVEFORMATEX + */ + if (wod32->lpFormat->wFormatTag != WAVE_FORMAT_PCM) { + TRACE("Allocating %u extra bytes (%d)\n", ((LPWAVEFORMATEX)wod32->lpFormat)->cbSize, wod32->lpFormat->wFormatTag); + sz += ((LPWAVEFORMATEX)wod32->lpFormat)->cbSize; + } + + ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD) + sizeof(WAVEOPENDESC16) + sz); + + if (ptr) { + SEGPTR seg_ptr = MapLS( ptr ); + *(LPWAVEOPENDESC*)ptr = wod32; + *(LPDWORD)((char*)ptr + sizeof(LPWAVEOPENDESC)) = *lpdwUser; + wod16 = (LPWAVEOPENDESC16)((LPSTR)ptr + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD)); + + wod16->hWave = HWAVE_16(wod32->hWave); + wod16->lpFormat = (LPWAVEFORMATEX)(seg_ptr + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD) + sizeof(WAVEOPENDESC16)); + memcpy(wod16 + 1, wod32->lpFormat, sz); + + wod16->dwCallback = wod32->dwCallback; + wod16->dwInstance = wod32->dwInstance; + wod16->uMappedDeviceID = wod32->uMappedDeviceID; + wod16->dnDevNode = wod32->dnDevNode; + + *lpParam1 = seg_ptr + sizeof(LPWAVEOPENDESC) + 2*sizeof(DWORD); + *lpdwUser = seg_ptr + sizeof(LPWAVEOPENDESC) + sizeof(DWORD); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case WODM_PREPARE: + { + LPWAVEHDR wh32 = (LPWAVEHDR)*lpParam1; + LPWAVEHDR wh16; + LPVOID ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPWAVEHDR) + sizeof(WAVEHDR) + wh32->dwBufferLength); + + if (ptr) { + SEGPTR seg_ptr = MapLS( ptr ); + *(LPWAVEHDR*)ptr = wh32; + wh16 = (LPWAVEHDR)((LPSTR)ptr + sizeof(LPWAVEHDR)); + wh16->lpData = (LPSTR)seg_ptr + sizeof(LPWAVEHDR) + sizeof(WAVEHDR); + /* data will be copied on WODM_WRITE */ + wh16->dwBufferLength = wh32->dwBufferLength; + wh16->dwBytesRecorded = wh32->dwBytesRecorded; + wh16->dwUser = wh32->dwUser; + wh16->dwFlags = wh32->dwFlags; + wh16->dwLoops = wh32->dwLoops; + /* FIXME: nothing on wh32->lpNext */ + /* could link the wh32->lpNext at this level for memory house keeping */ + wh32->lpNext = wh16; /* for reuse in unprepare and write */ + TRACE("wh16=%08lx wh16->lpData=%08lx wh32->buflen=%lu wh32->lpData=%08lx\n", + seg_ptr + sizeof(LPWAVEHDR), (DWORD)wh16->lpData, + wh32->dwBufferLength, (DWORD)wh32->lpData); + *lpParam1 = seg_ptr + sizeof(LPWAVEHDR); + *lpParam2 = sizeof(WAVEHDR); + + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_NOMEM; + } + } + break; + case WODM_UNPREPARE: + case WODM_WRITE: + { + LPWAVEHDR wh32 = (LPWAVEHDR)(*lpParam1); + LPWAVEHDR wh16 = wh32->lpNext; + LPSTR ptr = (LPSTR)wh16 - sizeof(LPWAVEHDR); + SEGPTR seg_ptr = MapLS( ptr ); + + assert(*(LPWAVEHDR*)ptr == wh32); + + TRACE("wh16=%08lx wh16->lpData=%08lx wh32->buflen=%lu wh32->lpData=%08lx\n", + seg_ptr + sizeof(LPWAVEHDR), (DWORD)wh16->lpData, + wh32->dwBufferLength, (DWORD)wh32->lpData); + + if (wMsg == WODM_WRITE) + memcpy((LPSTR)wh16 + sizeof(WAVEHDR), wh32->lpData, wh32->dwBufferLength); + + *lpParam1 = seg_ptr + sizeof(LPWAVEHDR); + *lpParam2 = sizeof(WAVEHDR); + /* dwBufferLength can be reduced between prepare & write */ + if (wMsg == WODM_WRITE && wh16->dwBufferLength < wh32->dwBufferLength) { + ERR("Size of buffer has been increased from %ld to %ld, keeping initial value\n", + wh16->dwBufferLength, wh32->dwBufferLength); + } else + wh16->dwBufferLength = wh32->dwBufferLength; + ret = WINMM_MAP_OKMEM; + } + break; + case DRVM_MAPPER_STATUS: + { + LPDWORD p32 = (LPDWORD)*lpParam2; + *lpParam2 = MapLS(p32); + ret = WINMM_MAP_OKMEM; + } + break; + default: + FIXME("NIY: no conversion yet\n"); + ret = WINMM_MAP_MSGERROR; + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_WaveOut_UnMap32WTo16 [internal] + */ +static WINMM_MapType MMDRV_WaveOut_UnMap32WTo16(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT fn_ret) +{ + WINMM_MapType ret; + + switch (wMsg) { + /* nothing to do */ + case WODM_BREAKLOOP: + case WODM_CLOSE: + case WODM_GETNUMDEVS: + case WODM_PAUSE: + case WODM_RESET: + case WODM_RESTART: + case WODM_SETPITCH: + case WODM_SETPLAYBACKRATE: + case WODM_SETVOLUME: + ret = WINMM_MAP_OK; + break; + + case WODM_GETDEVCAPS: + { + LPWAVEOUTCAPS16 woc16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)woc16 - sizeof(LPWAVEOUTCAPSW); + LPWAVEOUTCAPSW woc32 = *(LPWAVEOUTCAPSW*)ptr; + + woc32->wMid = woc16->wMid; + woc32->wPid = woc16->wPid; + woc32->vDriverVersion = woc16->vDriverVersion; + WideCharToMultiByte( CP_ACP, 0, woc32->szPname, -1, woc16->szPname, + sizeof(woc16->szPname), NULL, NULL ); + woc32->dwFormats = woc16->dwFormats; + woc32->wChannels = woc16->wChannels; + woc32->dwSupport = woc16->dwSupport; + UnMapLS( *lpParam1 ); + HeapFree( GetProcessHeap(), 0, ptr ); + ret = WINMM_MAP_OK; + } + break; + case WODM_GETPITCH: + FIXME("NIY: no conversion yet\n"); + ret = WINMM_MAP_MSGERROR; + break; + case WODM_GETPLAYBACKRATE: + FIXME("NIY: no conversion yet\n"); + ret = WINMM_MAP_MSGERROR; + break; + case WODM_GETPOS: + { + LPMMTIME16 mmt16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)mmt16 - sizeof(LPMMTIME); + LPMMTIME mmt32 = *(LPMMTIME*)ptr; + + MMSYSTEM_MMTIME16to32(mmt32, mmt16); + UnMapLS( *lpParam1 ); + HeapFree( GetProcessHeap(), 0, ptr ); + ret = WINMM_MAP_OK; + } + break; + case WODM_OPEN: + { + LPWAVEOPENDESC16 wod16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)wod16 - sizeof(LPWAVEOPENDESC) - 2*sizeof(DWORD); + LPWAVEOPENDESC wod32 = *(LPWAVEOPENDESC*)ptr; + + wod32->uMappedDeviceID = wod16->uMappedDeviceID; + **(DWORD**)(ptr + sizeof(LPWAVEOPENDESC)) = *(LPDWORD)(ptr + sizeof(LPWAVEOPENDESC) + sizeof(DWORD)); + UnMapLS( *lpParam1 ); + HeapFree( GetProcessHeap(), 0, ptr ); + ret = WINMM_MAP_OK; + } + break; + case WODM_PREPARE: + case WODM_UNPREPARE: + case WODM_WRITE: + { + LPWAVEHDR wh16 = MapSL(*lpParam1); + LPSTR ptr = (LPSTR)wh16 - sizeof(LPWAVEHDR); + LPWAVEHDR wh32 = *(LPWAVEHDR*)ptr; + + assert(wh32->lpNext == wh16); + wh32->dwBytesRecorded = wh16->dwBytesRecorded; + wh32->dwUser = wh16->dwUser; + wh32->dwFlags = wh16->dwFlags; + wh32->dwLoops = wh16->dwLoops; + + UnMapLS( *lpParam1 ); + if (wMsg == WODM_UNPREPARE && fn_ret == MMSYSERR_NOERROR) { + HeapFree( GetProcessHeap(), 0, ptr ); + wh32->lpNext = 0; + } + ret = WINMM_MAP_OK; + } + break; + case WODM_GETVOLUME: + FIXME("NIY: no conversion yet\n"); + ret = WINMM_MAP_MSGERROR; + break; + case DRVM_MAPPER_STATUS: + { + UnMapLS( *lpParam2 ); + ret = WINMM_MAP_OK; + } + break; + default: + FIXME("NIY: no conversion yet\n"); + ret = WINMM_MAP_MSGERROR; + break; + } + return ret; +} + +/************************************************************************** + * MMDRV_WaveOut_Callback [internal] + */ +static void CALLBACK MMDRV_WaveOut_Callback(HDRVR hDev, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD mld = (LPWINE_MLD)dwInstance; + + switch (uMsg) { + case WOM_OPEN: + case WOM_CLOSE: + /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ + break; + case WOM_DONE: + if (mld->bFrom32 && !MMDRV_Is32(mld->mmdIndex)) { + /* initial map is: 32 => 16 */ + LPWAVEHDR wh16 = MapSL(dwParam1); + LPWAVEHDR wh32 = *(LPWAVEHDR*)((LPSTR)wh16 - sizeof(LPWAVEHDR)); + + dwParam1 = (DWORD)wh32; + wh32->dwFlags = wh16->dwFlags; + } else if (!mld->bFrom32 && MMDRV_Is32(mld->mmdIndex)) { + /* initial map is: 16 => 32 */ + LPWAVEHDR wh32 = (LPWAVEHDR)(dwParam1); + SEGPTR segwh16 = *(SEGPTR*)((LPSTR)wh32 - sizeof(LPWAVEHDR)); + LPWAVEHDR wh16 = MapSL(segwh16); + + dwParam1 = (DWORD)segwh16; + wh16->dwFlags = wh32->dwFlags; + } + /* else { 16 => 16 or 32 => 32, nothing to do, same struct is kept }*/ + break; + default: + ERR("Unknown msg %u\n", uMsg); + } + + MMDRV_Callback(mld, hDev, uMsg, dwParam1, dwParam2); +} + +/* ================================= + * M A P P E R S H A N D L I N G + * ================================= */ + +static LRESULT MMDRV_CallMMDrvFunc16(DWORD fp16, WORD dev, WORD msg, LONG instance, + LONG lp1, LONG lp2) +{ + WORD args[8]; + DWORD ret; + + args[7] = dev; + args[6] = msg; + args[5] = HIWORD(instance); + args[4] = LOWORD(instance); + args[3] = HIWORD(lp1); + args[2] = LOWORD(lp1); + args[1] = HIWORD(lp2); + args[0] = LOWORD(lp2); + WOWCallback16Ex( fp16, WCB16_PASCAL, sizeof(args), args, &ret ); + return LOWORD(ret); +} + +/************************************************************************** + * MMDRV_GetDescription16 [internal] + */ +static BOOL MMDRV_GetDescription16(const char* fname, char* buf, int buflen) +{ + OFSTRUCT ofs; + HFILE hFile; + WORD w; + DWORD dw; + BOOL ret = FALSE; + + if ((hFile = OpenFile(fname, &ofs, OF_READ | OF_SHARE_DENY_WRITE)) == HFILE_ERROR) { + ERR("Can't open file %s (builtin driver ?)\n", fname); + return FALSE; + } + +#define E(_x) do {TRACE _x;goto theEnd;} while(0) + + if (_lread(hFile, &w, 2) != 2) E(("Can't read sig\n")); + if (w != ('Z' * 256 + 'M')) E(("Bad sig %04x\n", w)); + if (_llseek(hFile, 0x3C, SEEK_SET) < 0) E(("Can't seek to ext header offset\n")); + if (_lread(hFile, &dw, 4) != 4) E(("Can't read ext header offset\n")); + if (_llseek(hFile, dw + 0x2C, SEEK_SET) < 0) E(("Can't seek to ext header.nr table %lu\n", dw+0x2C)); + if (_lread(hFile, &dw, 4) != 4) E(("Can't read nr table offset\n")); + if (_llseek(hFile, dw, SEEK_SET) < 0) E(("Can't seek to nr table %lu\n", dw)); + if (_lread(hFile, buf, 1) != 1) E(("Can't read descr length\n")); + buflen = min((int)(unsigned)(BYTE)buf[0], buflen - 1); + if (_lread(hFile, buf, buflen) != buflen) E(("Can't read descr (%d)\n", buflen)); + buf[buflen] = '\0'; + ret = TRUE; + TRACE("Got '%s' [%d]\n", buf, buflen); +theEnd: + _lclose(hFile); + return ret; +} + +/****************************************************************** + * MMDRV_LoadMMDrvFunc16 + * + */ +unsigned MMDRV_LoadMMDrvFunc16(LPCSTR drvName, LPWINE_DRIVER d, + LPWINE_MM_DRIVER lpDrv) +{ + WINEMM_msgFunc16 func; + unsigned count = 0; + char buffer[128]; + /* + * DESCRIPTION 'wave,aux,mixer:Creative Labs Sound Blaster 16 Driver' + * The beginning of the module description indicates the driver supports + * waveform, auxiliary, and mixer devices. Use one of the following + * device-type names, followed by a colon (:) to indicate the type of + * device your driver supports. If the driver supports more than one + * type of device, separate each device-type name with a comma (,). + * + * wave for waveform audio devices + * wavemapper for wave mappers + * midi for MIDI audio devices + * midimapper for midi mappers + * aux for auxiliary audio devices + * mixer for mixer devices + */ + + if (d->d.d16.hDriver16) { + HMODULE16 hMod16 = GetDriverModuleHandle16(d->d.d16.hDriver16); + +#define AA(_h,_w,_x,_y,_z) \ + func = (WINEMM_msgFunc##_y) _z ((_h), #_x); \ + if (func != NULL) \ + { lpDrv->parts[_w].u.fnMessage##_y = func; count++; \ + TRACE("Got %d bit func '%s'\n", _y, #_x); } + +#define A(_x,_y) AA(hMod16,_x,_y,16,GetProcAddress16) + A(MMDRV_AUX, auxMessage); + A(MMDRV_MIXER, mxdMessage); + A(MMDRV_MIDIIN, midMessage); + A(MMDRV_MIDIOUT,modMessage); + A(MMDRV_WAVEIN, widMessage); + A(MMDRV_WAVEOUT,wodMessage); +#undef A +#undef AA + } + if (TRACE_ON(winmm)) { + if (MMDRV_GetDescription16(drvName, buffer, sizeof(buffer))) + TRACE("%s => %s\n", drvName, buffer); + else + TRACE("%s => No description\n", drvName); + } + + return count; +} + +/* ================================= + * M C I + * ================================= */ + +#if 0 +/* FIXME: this code is kept for not yet implemented optimisation for an application + * using the 32A MCI interface and calling a 16 bit driver. + * For now, we're doing two conversions: + * - 32A => 32W (in 32 bit MCI code) + * - 32W => 16 in this file + */ + +/* + * 0000 stop + * 0001 squeeze signed 4 bytes to 2 bytes *( LPINT16)D = ( INT16)*( LPINT16)S; D += 2; S += 4 + * 0010 squeeze unsigned 4 bytes to 2 bytes *(LPUINT16)D = (UINT16)*(LPUINT16)S; D += 2; S += 4 + * 0100 + * 0101 + * 0110 zero 4 bytes *(DWORD)D = 0 D += 4; S += 4 + * 0111 copy string *(LPSTR*)D = seg dup(*(LPSTR*)S) D += 4; S += 4 + * 1xxx copy xxx + 1 bytes memcpy(D, S, xxx + 1); D += xxx+1; S += xxx+1 + */ + +/************************************************************************** + * MCI_MsgMapper32ATo16_Create [internal] + * + * Helper for MCI_MapMsg32ATo16. + * Maps the 32 bit pointer (*ptr), of size bytes, to an allocated 16 bit + * segmented pointer. + * map contains a list of action to be performed for the mapping (see list + * above) + * if keep is TRUE, keeps track of in 32 bit ptr in allocated 16 bit area. + */ +static WINMM_MapType MCI_MsgMapper32ATo16_Create(void** ptr, int size16, DWORD map, BOOLEAN keep) +{ + void* lp = HeapAlloc( GetProcessHeap(), 0, (keep ? sizeof(void**) : 0) + size16 ); + LPBYTE p16, p32; + + if (!lp) { + return WINMM_MAP_NOMEM; + } + p32 = (LPBYTE)(*ptr); + if (keep) { + *(void**)lp = *ptr; + p16 = (LPBYTE)lp + sizeof(void**); + *ptr = (char*)MapLS(lp) + sizeof(void**); + } else { + p16 = lp; + *ptr = (void*)MapLS(lp); + } + + if (map == 0) { + memcpy(p16, p32, size16); + } else { + unsigned nibble; + unsigned sz; + + while (map & 0xF) { + nibble = map & 0xF; + if (nibble & 0x8) { + sz = (nibble & 7) + 1; + memcpy(p16, p32, sz); + p16 += sz; + p32 += sz; + size16 -= sz; /* DEBUG only */ + } else { + switch (nibble) { + case 0x1: + *(LPINT16)p16 = *(LPINT)p32; + p16 += sizeof(INT16); + p32 += sizeof(INT); + size16 -= sizeof(INT16); + break; + case 0x2: + *(LPUINT16)p16 = *(LPUINT)p32; + p16 += sizeof(UINT16); + p32 += sizeof(UINT); + size16 -= sizeof(UINT16); + break; + case 0x6: + *(LPDWORD)p16 = 0; + p16 += sizeof(DWORD); + p32 += sizeof(DWORD); + size16 -= sizeof(DWORD); + break; + case 0x7: + *(SEGPTR *)p16 = MapLS( *(LPSTR *)p32 ); + p16 += sizeof(SEGPTR); + p32 += sizeof(LPSTR); + size16 -= sizeof(SEGPTR); + break; + default: + FIXME("Unknown nibble for mapping (%x)\n", nibble); + } + } + map >>= 4; + } + if (size16 != 0) /* DEBUG only */ + FIXME("Mismatch between 16 bit struct size and map nibbles serie\n"); + } + return WINMM_MAP_OKMEM; +} + +/************************************************************************** + * MCI_MsgMapper32ATo16_Destroy [internal] + * + * Helper for MCI_UnMapMsg32ATo16. + */ +static WINMM_MapType MCI_MsgMapper32ATo16_Destroy(void* ptr, int size16, DWORD map, BOOLEAN kept) +{ + if (ptr) { + void* msg16 = MapSL((SEGPTR)ptr); + void* alloc; + LPBYTE p32, p16; + unsigned nibble; + + UnMapLS( (SEGPTR)ptr ); + if (kept) { + alloc = (char*)msg16 - sizeof(void**); + p32 = *(void**)alloc; + p16 = msg16; + + if (map == 0) { + memcpy(p32, p16, size16); + } else { + while (map & 0xF) { + nibble = map & 0xF; + if (nibble & 0x8) { + memcpy(p32, p16, (nibble & 7) + 1); + p16 += (nibble & 7) + 1; + p32 += (nibble & 7) + 1; + size16 -= (nibble & 7) + 1; + } else { + switch (nibble) { + case 0x1: + *(LPINT)p32 = *(LPINT16)p16; + p16 += sizeof(INT16); + p32 += sizeof(INT); + size16 -= sizeof(INT16); + break; + case 0x2: + *(LPUINT)p32 = *(LPUINT16)p16; + p16 += sizeof(UINT16); + p32 += sizeof(UINT); + size16 -= sizeof(UINT16); + break; + case 0x6: + p16 += sizeof(UINT); + p32 += sizeof(UINT); + size16 -= sizeof(UINT); + break; + case 0x7: + UnMapLS( *(SEGPTR *)p16 ); + p16 += sizeof(SEGPTR); + p32 += sizeof(char*); + size16 -= sizeof(SEGPTR); + break; + default: + FIXME("Unknown nibble for mapping (%x)\n", nibble); + } + } + map >>= 4; + } + if (size16 != 0) /* DEBUG only */ + FIXME("Mismatch between 16 bit struct size and map nibbles serie\n"); + } + } else { + alloc = msg16; + } + + HeapFree( GetProcessHeap(), 0, alloc ); + } + return WINMM_MAP_OK; +} + +/************************************************************************** + * MCI_MapMsg32ATo16 [internal] + * + * Map a 32-A bit MCI message to a 16 bit MCI message. + */ +static WINMM_MapType MCI_MapMsg32ATo16(WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD* lParam) +{ + int size; + BOOLEAN keep = FALSE; + DWORD map = 0; + + if (*lParam == 0) + return WINMM_MAP_OK; + + /* FIXME: to add also (with seg/linear modifications to do): + * MCI_LIST, MCI_LOAD, MCI_QUALITY, MCI_RESERVE, MCI_RESTORE, MCI_SAVE + * MCI_SETAUDIO, MCI_SETTUNER, MCI_SETVIDEO + */ + switch (wMsg) { + case MCI_BREAK: + size = sizeof(MCI_BREAK_PARMS); + break; + /* case MCI_CAPTURE */ + case MCI_CLOSE: + case MCI_CLOSE_DRIVER: + case MCI_CONFIGURE: + size = sizeof(MCI_GENERIC_PARMS); + break; + /* case MCI_COPY: */ + case MCI_CUE: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_CUE_PARMS); break; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_CUE_PARMS); break;*/ FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + /* case MCI_CUT:*/ + case MCI_DELETE: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_DELETE_PARMS16); map = 0x0F1111FB; break; + case MCI_DEVTYPE_WAVEFORM_AUDIO:size = sizeof(MCI_WAVE_DELETE_PARMS); break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + /* case MCI_ESCAPE: */ + case MCI_FREEZE: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_FREEZE_PARMS); map = 0x0001111B; break; + case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS); map = 0x0001111B; break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + case MCI_GETDEVCAPS: + keep = TRUE; + size = sizeof(MCI_GETDEVCAPS_PARMS); + break; + /* case MCI_INDEX: */ + case MCI_INFO: + { + LPMCI_INFO_PARMSA mip32a = (LPMCI_INFO_PARMSA)(*lParam); + LPMCI_INFO_PARMS16 mip16; + + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_INFO_PARMS16); break; + default: size = sizeof(MCI_INFO_PARMS16); break; + } + mip16 = HeapAlloc( GetProcessHeap(), 0, size); + if (mip16) + { + mip16->dwCallback = mip32a->dwCallback; + mip16->lpstrReturn = MapLS( mip32a->lpstrReturn ); + mip16->dwRetSize = mip32a->dwRetSize; + if (uDevType == MCI_DEVTYPE_DIGITAL_VIDEO) { + ((LPMCI_DGV_INFO_PARMS16)mip16)->dwItem = ((LPMCI_DGV_INFO_PARMSA)mip32a)->dwItem; + } + } else { + return WINMM_MAP_NOMEM; + } + *lParam = MapLS(mip16); + } + return WINMM_MAP_OKMEM; + /* case MCI_MARK: */ + /* case MCI_MONITOR: */ + case MCI_OPEN: + case MCI_OPEN_DRIVER: + { + LPMCI_OPEN_PARMSA mop32a = (LPMCI_OPEN_PARMSA)(*lParam); + char* ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPMCI_OPEN_PARMSA) + sizeof(MCI_OPEN_PARMS16) + 2 * sizeof(DWORD)); + LPMCI_OPEN_PARMS16 mop16; + + + if (ptr) { + *(LPMCI_OPEN_PARMSA*)(ptr) = mop32a; + mop16 = (LPMCI_OPEN_PARMS16)(ptr + sizeof(LPMCI_OPEN_PARMSA)); + mop16->dwCallback = mop32a->dwCallback; + mop16->wDeviceID = mop32a->wDeviceID; + if (dwFlags & MCI_OPEN_TYPE) { + if (dwFlags & MCI_OPEN_TYPE_ID) { + /* dword "transparent" value */ + mop16->lpstrDeviceType = (SEGPTR)mop32a->lpstrDeviceType; + } else { + /* string */ + mop16->lpstrDeviceType = MapLS( mop32a->lpstrDeviceType ); + } + } else { + /* nuthin' */ + mop16->lpstrDeviceType = 0; + } + if (dwFlags & MCI_OPEN_ELEMENT) { + if (dwFlags & MCI_OPEN_ELEMENT_ID) { + mop16->lpstrElementName = (SEGPTR)mop32a->lpstrElementName; + } else { + mop16->lpstrElementName = MapLS( mop32a->lpstrElementName ); + } + } else { + mop16->lpstrElementName = 0; + } + if (dwFlags & MCI_OPEN_ALIAS) { + mop16->lpstrAlias = MapLS( mop32a->lpstrAlias ); + } else { + mop16->lpstrAlias = 0; + } + /* copy extended information if any... + * FIXME: this may seg fault if initial structure does not contain them and + * the reads after msip16 fail under LDT limits... + * NOTE: this should be split in two. First pass, while calling MCI_OPEN, and + * should not take care of extended parameters, and should be used by MCI_Open + * to fetch uDevType. When, this is known, the mapping for sending the + * MCI_OPEN_DRIVER shall be done depending on uDevType. + */ + memcpy(mop16 + 1, mop32a + 1, 2 * sizeof(DWORD)); + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (LPARAM)MapLS(ptr) + sizeof(LPMCI_OPEN_PARMSA); + } + return WINMM_MAP_OKMEM; + /* case MCI_PASTE:*/ + case MCI_PAUSE: + size = sizeof(MCI_GENERIC_PARMS); + break; + case MCI_PLAY: + size = sizeof(MCI_PLAY_PARMS); + break; + case MCI_PUT: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16); map = 0x0001111B; break; + case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS); map = 0x0001111B; break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + case MCI_REALIZE: + size = sizeof(MCI_GENERIC_PARMS); + break; + case MCI_RECORD: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECORD_PARMS16); map = 0x0F1111FB; break; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_RECORD_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + default: size = sizeof(MCI_RECORD_PARMS); break; + } + break; + case MCI_RESUME: + size = sizeof(MCI_GENERIC_PARMS); + break; + case MCI_SEEK: + switch (uDevType) { + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_SEEK_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + default: size = sizeof(MCI_SEEK_PARMS); break; + } + break; + case MCI_SET: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_SET_PARMS); break; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_SET_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + case MCI_DEVTYPE_SEQUENCER: size = sizeof(MCI_SEQ_SET_PARMS); break; + /* FIXME: normally the 16 and 32 bit structures are byte by byte aligned, + * so not doing anything should work... + */ + case MCI_DEVTYPE_WAVEFORM_AUDIO:size = sizeof(MCI_WAVE_SET_PARMS); break; + default: size = sizeof(MCI_SET_PARMS); break; + } + break; + case MCI_SETAUDIO: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_SETAUDIO_PARMS16);map = 0x0000077FF; break; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_SETAUDIO_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + /* case MCI_SETTIMECODE:*/ + /* case MCI_SIGNAL:*/ + /* case MCI_SOUND:*/ + case MCI_SPIN: + size = sizeof(MCI_SET_PARMS); + break; + case MCI_STATUS: + keep = TRUE; + switch (uDevType) { + /* FIXME: + * don't know if buffer for value is the one passed through lpstrDevice + * or is provided by MCI driver. + * Assuming solution 2: provided by MCI driver, so zeroing on entry + */ + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_STATUS_PARMS16); map = 0x0B6FF; break; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_STATUS_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + default: size = sizeof(MCI_STATUS_PARMS); break; + } + break; + case MCI_STEP: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_STEP_PARMS); break; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_STEP_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + case MCI_DEVTYPE_VIDEODISC: size = sizeof(MCI_VD_STEP_PARMS); break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + case MCI_STOP: + size = sizeof(MCI_SET_PARMS); + break; + case MCI_SYSINFO: + { + LPMCI_SYSINFO_PARMSA msip32a = (LPMCI_SYSINFO_PARMSA)(*lParam); + LPMCI_SYSINFO_PARMS16 msip16; + char* ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPMCI_SYSINFO_PARMSA) + sizeof(MCI_SYSINFO_PARMS16) ); + + if (ptr) { + *(LPMCI_SYSINFO_PARMSA*)(ptr) = msip32a; + msip16 = (LPMCI_SYSINFO_PARMS16)(ptr + sizeof(LPMCI_SYSINFO_PARMSA)); + + msip16->dwCallback = msip32a->dwCallback; + msip16->lpstrReturn = MapLS( msip32a->lpstrReturn ); + msip16->dwRetSize = msip32a->dwRetSize; + msip16->dwNumber = msip32a->dwNumber; + msip16->wDeviceType = msip32a->wDeviceType; + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (LPARAM)MapLS(ptr) + sizeof(LPMCI_SYSINFO_PARMSA); + } + return WINMM_MAP_OKMEM; + /* case MCI_UNDO: */ + case MCI_UNFREEZE: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16); map = 0x0001111B; break; + case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS16); map = 0x0001111B; break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + case MCI_UPDATE: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_UPDATE_PARMS16); map = 0x000B1111B; break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + case MCI_WHERE: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16); map = 0x0001111B; keep = TRUE; break; + case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS16); map = 0x0001111B; keep = TRUE; break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + case MCI_WINDOW: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_WINDOW_PARMS16); if (dwFlags & MCI_DGV_WINDOW_TEXT) map = 0x7FB; break; + case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_WINDOW_PARMS16); if (dwFlags & MCI_OVLY_WINDOW_TEXT) map = 0x7FB; break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + case DRV_OPEN: + { + LPMCI_OPEN_DRIVER_PARMSA modp32a = (LPMCI_OPEN_DRIVER_PARMSA)(*lParam); + LPMCI_OPEN_DRIVER_PARMS16 modp16; + char *ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPMCI_OPEN_DRIVER_PARMSA) + sizeof(MCI_OPEN_DRIVER_PARMS16)); + + if (ptr) { + *(LPMCI_OPEN_DRIVER_PARMSA*)(ptr) = modp32a; + modp16 = (LPMCI_OPEN_DRIVER_PARMS16)(ptr + sizeof(LPMCI_OPEN_DRIVER_PARMSA)); + modp16->wDeviceID = modp32a->wDeviceID; + modp16->lpstrParams = MapLS( modp32a->lpstrParams ); + /* other fields are gonna be filled by the driver, don't copy them */ + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (LPARAM)MapLS(ptr) + sizeof(LPMCI_OPEN_DRIVER_PARMSA); + } + return WINMM_MAP_OKMEM; + case DRV_LOAD: + case DRV_ENABLE: + case DRV_CLOSE: + case DRV_DISABLE: + case DRV_FREE: + case DRV_CONFIGURE: + case DRV_QUERYCONFIGURE: + case DRV_INSTALL: + case DRV_REMOVE: + case DRV_EXITSESSION: + case DRV_EXITAPPLICATION: + case DRV_POWER: + return WINMM_MAP_OK; + + default: + FIXME("Don't know how to map msg=%s\n", MCI_MessageToString(wMsg)); + return WINMM_MAP_MSGERROR; + } + return MCI_MsgMapper32ATo16_Create((void**)lParam, size, map, keep); +} + +/************************************************************************** + * MCI_UnMapMsg32ATo16 [internal] + */ +static WINMM_MapType MCI_UnMapMsg32ATo16(WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD lParam) +{ + int size = 0; + BOOLEAN kept = FALSE; /* there is no need to compute size when kept is FALSE */ + DWORD map = 0; + + switch (wMsg) { + case MCI_BREAK: + break; + /* case MCI_CAPTURE */ + case MCI_CLOSE: + case MCI_CLOSE_DRIVER: + case MCI_CONFIGURE: + break; + /* case MCI_COPY: */ + case MCI_CUE: + break; + /* case MCI_CUT: */ + case MCI_DELETE: + break; + /* case MCI_ESCAPE: */ + case MCI_FREEZE: + break; + case MCI_GETDEVCAPS: + kept = TRUE; + size = sizeof(MCI_GETDEVCAPS_PARMS); + break; + /* case MCI_INDEX: */ + case MCI_INFO: + { + LPMCI_INFO_PARMS16 mip16 = (LPMCI_INFO_PARMS16)MapSL(lParam); + UnMapLS( lParam ); + UnMapLS( mip16->lpstrReturn ); + HeapFree( GetProcessHeap(), 0, mip16 ); + } + return WINMM_MAP_OK; + /* case MCI_MARK: */ + /* case MCI_MONITOR: */ + case MCI_OPEN: + case MCI_OPEN_DRIVER: + if (lParam) { + LPMCI_OPEN_PARMS16 mop16 = (LPMCI_OPEN_PARMS16)MapSL(lParam); + LPMCI_OPEN_PARMSA mop32a = *(LPMCI_OPEN_PARMSA*)((char*)mop16 - sizeof(LPMCI_OPEN_PARMSA)); + UnMapLS( lParam ); + mop32a->wDeviceID = mop16->wDeviceID; + if ((dwFlags & MCI_OPEN_TYPE) && !(dwFlags & MCI_OPEN_TYPE_ID)) + UnMapLS( mop16->lpstrDeviceType ); + if ((dwFlags & MCI_OPEN_ELEMENT) && !(dwFlags & MCI_OPEN_ELEMENT_ID)) + UnMapLS( mop16->lpstrElementName ); + if (dwFlags & MCI_OPEN_ALIAS) + UnMapLS( mop16->lpstrAlias ); + HeapFree( GetProcessHeap(), 0, (char*)mop16 - sizeof(LPMCI_OPEN_PARMSA) ); + } + return WINMM_MAP_OK; + /* case MCI_PASTE:*/ + case MCI_PAUSE: + break; + case MCI_PLAY: + break; + case MCI_PUT: + break; + case MCI_REALIZE: + break; + case MCI_RECORD: + break; + case MCI_RESUME: + break; + case MCI_SEEK: + break; + case MCI_SET: + break; + case MCI_SETAUDIO: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: map = 0x0000077FF; break; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_SETAUDIO_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + } + break; + /* case MCI_SETTIMECODE:*/ + /* case MCI_SIGNAL:*/ + /* case MCI_SOUND:*/ + case MCI_SPIN: + break; + case MCI_STATUS: + kept = TRUE; + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: + if (lParam) { + LPMCI_DGV_STATUS_PARMS16 mdsp16 = (LPMCI_DGV_STATUS_PARMS16)MapSL(lParam); + LPMCI_DGV_STATUS_PARMSA mdsp32a = *(LPMCI_DGV_STATUS_PARMSA*)((char*)mdsp16 - sizeof(LPMCI_DGV_STATUS_PARMSA)); + + UnMapLS( lParam ); + if (mdsp16) { + mdsp32a->dwReturn = mdsp16->dwReturn; + if (dwFlags & MCI_DGV_STATUS_DISKSPACE) { + TRACE("MCI_STATUS (DGV) lpstrDrive=%08lx\n", mdsp16->lpstrDrive); + TRACE("MCI_STATUS (DGV) lpstrDrive=%s\n", (LPSTR)MapSL(mdsp16->lpstrDrive)); + UnMapLS( mdsp16->lpstrDrive ); + } + HeapFree( GetProcessHeap(), 0, (char*)mdsp16 - sizeof(LPMCI_DGV_STATUS_PARMSA) ); + } else { + return WINMM_MAP_NOMEM; + } + } + return WINMM_MAP_OKMEM; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_STATUS_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + default: size = sizeof(MCI_STATUS_PARMS); break; + } + break; + case MCI_STEP: + break; + case MCI_STOP: + break; + case MCI_SYSINFO: + if (lParam) { + LPMCI_SYSINFO_PARMS16 msip16 = (LPMCI_SYSINFO_PARMS16)MapSL(lParam); + LPMCI_SYSINFO_PARMSA msip32a = *(LPMCI_SYSINFO_PARMSA*)((char*)msip16 - sizeof(LPMCI_SYSINFO_PARMSA)); + + UnMapLS( lParam ); + if (msip16) { + msip16->dwCallback = msip32a->dwCallback; + UnMapLS( msip16->lpstrReturn ); + HeapFree( GetProcessHeap(), 0, (char*)msip16 - sizeof(LPMCI_SYSINFO_PARMSA) ); + } else { + return WINMM_MAP_NOMEM; + } + } + return WINMM_MAP_OKMEM; + /* case MCI_UNDO: */ + case MCI_UNFREEZE: + break; + case MCI_UPDATE: + break; + case MCI_WHERE: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16); map = 0x0001111B; kept = TRUE; break; + case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS16); map = 0x0001111B; kept = TRUE; break; + default: break; + } + break; + case MCI_WINDOW: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_WINDOW_PARMS16); if (dwFlags & MCI_DGV_WINDOW_TEXT) map = 0x7666; break; + case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_WINDOW_PARMS16); if (dwFlags & MCI_OVLY_WINDOW_TEXT) map = 0x7666; break; + default: break; + } + /* FIXME: see map function */ + break; + + case DRV_OPEN: + if (lParam) { + LPMCI_OPEN_DRIVER_PARMS16 modp16 = (LPMCI_OPEN_DRIVER_PARMS16)MapSL(lParam); + LPMCI_OPEN_DRIVER_PARMSA modp32a = *(LPMCI_OPEN_DRIVER_PARMSA*)((char*)modp16 - sizeof(LPMCI_OPEN_DRIVER_PARMSA)); + + UnMapLS( lParam ); + modp32a->wCustomCommandTable = modp16->wCustomCommandTable; + modp32a->wType = modp16->wType; + UnMapLS( modp16->lpstrParams ); + HeapFree( GetProcessHeap(), 0, (char *)modp16 - sizeof(LPMCI_OPEN_DRIVER_PARMSA) ); + } + return WINMM_MAP_OK; + case DRV_LOAD: + case DRV_ENABLE: + case DRV_CLOSE: + case DRV_DISABLE: + case DRV_FREE: + case DRV_CONFIGURE: + case DRV_QUERYCONFIGURE: + case DRV_INSTALL: + case DRV_REMOVE: + case DRV_EXITSESSION: + case DRV_EXITAPPLICATION: + case DRV_POWER: + FIXME("This is a hack\n"); + return WINMM_MAP_OK; + default: + FIXME("Map/Unmap internal error on msg=%s\n", MCI_MessageToString(wMsg)); + return WINMM_MAP_MSGERROR; + } + return MCI_MsgMapper32ATo16_Destroy((void*)lParam, size, map, kept); +} +#endif + +/************************************************************************** + * MCI_MapMsg16To32W [internal] + */ +static WINMM_MapType MCI_MapMsg16To32W(WORD uDevType, WORD wMsg, DWORD* lParam) +{ + if (*lParam == 0) + return WINMM_MAP_OK; + /* FIXME: to add also (with seg/linear modifications to do): + * MCI_LIST, MCI_LOAD, MCI_QUALITY, MCI_RESERVE, MCI_RESTORE, MCI_SAVE + * MCI_SETAUDIO, MCI_SETTUNER, MCI_SETVIDEO + */ + switch (wMsg) { + /* case MCI_CAPTURE */ + case MCI_CLOSE: + case MCI_CLOSE_DRIVER: + case MCI_CONFIGURE: + case MCI_COPY: + case MCI_CUE: + case MCI_CUT: + case MCI_DELETE: + case MCI_FREEZE: + case MCI_GETDEVCAPS: + /* case MCI_INDEX: */ + /* case MCI_MARK: */ + /* case MCI_MONITOR: */ + case MCI_PASTE: + case MCI_PAUSE: + case MCI_PLAY: + case MCI_PUT: + case MCI_REALIZE: + case MCI_RECORD: + case MCI_RESUME: + case MCI_SEEK: + case MCI_SET: + /* case MCI_SETTIMECODE:*/ + /* case MCI_SIGNAL:*/ + case MCI_SPIN: + case MCI_STATUS: /* FIXME: is wrong for digital video */ + case MCI_STEP: + case MCI_STOP: + /* case MCI_UNDO: */ + case MCI_UNFREEZE: + case MCI_UPDATE: + case MCI_WHERE: + *lParam = (DWORD)MapSL(*lParam); + return WINMM_MAP_OK; + case MCI_WINDOW: + /* in fact, I would also need the dwFlags... to see + * which members of lParam are effectively used + */ + *lParam = (DWORD)MapSL(*lParam); + FIXME("Current mapping may be wrong\n"); + break; + case MCI_BREAK: + { + LPMCI_BREAK_PARMS mbp32 = HeapAlloc(GetProcessHeap(), 0, sizeof(MCI_BREAK_PARMS)); + LPMCI_BREAK_PARMS16 mbp16 = MapSL(*lParam); + + if (mbp32) { + mbp32->dwCallback = mbp16->dwCallback; + mbp32->nVirtKey = mbp16->nVirtKey; + mbp32->hwndBreak = HWND_32(mbp16->hwndBreak); + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (DWORD)mbp32; + } + return WINMM_MAP_OKMEM; + case MCI_ESCAPE: + { + LPMCI_VD_ESCAPE_PARMSW mvep32w = HeapAlloc(GetProcessHeap(), 0, sizeof(MCI_VD_ESCAPE_PARMSW)); + LPMCI_VD_ESCAPE_PARMS16 mvep16 = MapSL(*lParam); + + if (mvep32w) { + mvep32w->dwCallback = mvep16->dwCallback; + mvep32w->lpstrCommand = MCI_strdupAtoW(MapSL(mvep16->lpstrCommand)); + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (DWORD)mvep32w; + } + return WINMM_MAP_OKMEM; + case MCI_INFO: + { + LPMCI_INFO_PARMSW mip32w = HeapAlloc(GetProcessHeap(), 0, sizeof(LPMCI_OPEN_PARMS16) + sizeof(MCI_INFO_PARMSW)); + LPMCI_INFO_PARMS16 mip16 = MapSL(*lParam); + + /* FIXME this is wrong if device is of type + * MCI_DEVTYPE_DIGITAL_VIDEO, some members are not mapped + */ + if (mip32w) { + *(LPMCI_INFO_PARMS16*)(mip32w) = mip16; + mip32w = (LPMCI_INFO_PARMSW)((char*)mip32w + sizeof(LPMCI_INFO_PARMS16)); + mip32w->dwCallback = mip16->dwCallback; + mip32w->lpstrReturn = HeapAlloc(GetProcessHeap(), 0, mip16->dwRetSize * sizeof(WCHAR)); + mip32w->dwRetSize = mip16->dwRetSize * sizeof(WCHAR); + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (DWORD)mip32w; + } + return WINMM_MAP_OKMEM; + case MCI_OPEN: + case MCI_OPEN_DRIVER: + { + LPMCI_OPEN_PARMSW mop32w = HeapAlloc(GetProcessHeap(), 0, sizeof(LPMCI_OPEN_PARMS16) + sizeof(MCI_OPEN_PARMSW) + 2 * sizeof(DWORD)); + LPMCI_OPEN_PARMS16 mop16 = MapSL(*lParam); + + if (mop32w) { + *(LPMCI_OPEN_PARMS16*)(mop32w) = mop16; + mop32w = (LPMCI_OPEN_PARMSW)((char*)mop32w + sizeof(LPMCI_OPEN_PARMS16)); + mop32w->dwCallback = mop16->dwCallback; + mop32w->wDeviceID = mop16->wDeviceID; + mop32w->lpstrDeviceType = MCI_strdupAtoW(MapSL(mop16->lpstrDeviceType)); + mop32w->lpstrElementName = MCI_strdupAtoW(MapSL(mop16->lpstrElementName)); + mop32w->lpstrAlias = MCI_strdupAtoW(MapSL(mop16->lpstrAlias)); + /* copy extended information if any... + * FIXME: this may seg fault if initial structure does not contain them and + * the reads after msip16 fail under LDT limits... + * NOTE: this should be split in two. First pass, while calling MCI_OPEN, and + * should not take care of extended parameters, and should be used by MCI_Open + * to fetch uDevType. When, this is known, the mapping for sending the + * MCI_OPEN_DRIVER shall be done depending on uDevType. + */ + memcpy(mop32w + 1, mop16 + 1, 2 * sizeof(DWORD)); + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (DWORD)mop32w; + } + return WINMM_MAP_OKMEM; + case MCI_SYSINFO: + { + LPMCI_SYSINFO_PARMSW msip32w = HeapAlloc(GetProcessHeap(), 0, sizeof(LPMCI_OPEN_PARMS16) + sizeof(MCI_SYSINFO_PARMSW)); + LPMCI_SYSINFO_PARMS16 msip16 = MapSL(*lParam); + + if (msip32w) { + *(LPMCI_SYSINFO_PARMS16*)(msip32w) = msip16; + msip32w = (LPMCI_SYSINFO_PARMSW)((char*)msip32w + sizeof(LPMCI_OPEN_PARMS16)); + msip32w->dwCallback = msip16->dwCallback; + msip32w->lpstrReturn = HeapAlloc(GetProcessHeap(), 0, msip16->dwRetSize * sizeof(WCHAR)); + msip32w->dwRetSize = msip16->dwRetSize; + msip32w->dwNumber = msip16->dwNumber; + msip32w->wDeviceType = msip16->wDeviceType; + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (DWORD)msip32w; + } + return WINMM_MAP_OKMEM; + case MCI_SOUND: + { + LPMCI_SOUND_PARMSW mbp32 = HeapAlloc(GetProcessHeap(), 0, sizeof(MCI_SOUND_PARMSW)); + LPMCI_SOUND_PARMS16 mbp16 = MapSL(*lParam); + + if (mbp32) { + mbp32->dwCallback = mbp16->dwCallback; + mbp32->lpstrSoundName = MCI_strdupAtoW(MapSL(mbp16->lpstrSoundName)); + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (DWORD)mbp32; + } + return WINMM_MAP_OKMEM; + case DRV_LOAD: + case DRV_ENABLE: + case DRV_OPEN: + case DRV_CLOSE: + case DRV_DISABLE: + case DRV_FREE: + case DRV_CONFIGURE: + case DRV_QUERYCONFIGURE: + case DRV_INSTALL: + case DRV_REMOVE: + case DRV_EXITSESSION: + case DRV_EXITAPPLICATION: + case DRV_POWER: + FIXME("This is a hack\n"); + return WINMM_MAP_OK; + default: + FIXME("Don't know how to map msg=%s\n", MCI_MessageToString(wMsg)); + } + return WINMM_MAP_MSGERROR; +} + +/************************************************************************** + * MCI_UnMapMsg16To32W [internal] + */ +static WINMM_MapType MCI_UnMapMsg16To32W(WORD uDevType, WORD wMsg, DWORD lParam) +{ + switch (wMsg) { + /* case MCI_CAPTURE */ + case MCI_CLOSE: + case MCI_CLOSE_DRIVER: + case MCI_CONFIGURE: + case MCI_COPY: + case MCI_CUE: + case MCI_CUT: + case MCI_DELETE: + case MCI_FREEZE: + case MCI_GETDEVCAPS: + /* case MCI_INDEX: */ + /* case MCI_MARK: */ + /* case MCI_MONITOR: */ + case MCI_PASTE: + case MCI_PAUSE: + case MCI_PLAY: + case MCI_PUT: + case MCI_REALIZE: + case MCI_RECORD: + case MCI_RESUME: + case MCI_SEEK: + case MCI_SET: + /* case MCI_SETTIMECODE:*/ + /* case MCI_SIGNAL:*/ + case MCI_SPIN: + case MCI_STATUS: + case MCI_STEP: + case MCI_STOP: + /* case MCI_UNDO: */ + case MCI_UNFREEZE: + case MCI_UPDATE: + case MCI_WHERE: + return WINMM_MAP_OK; + + case MCI_WINDOW: + /* FIXME ?? see Map function */ + return WINMM_MAP_OK; + + case MCI_BREAK: + HeapFree(GetProcessHeap(), 0, (LPVOID)lParam); + return WINMM_MAP_OK; + case MCI_ESCAPE: + if (lParam) { + LPMCI_VD_ESCAPE_PARMSW mvep32W = (LPMCI_VD_ESCAPE_PARMSW)lParam; + HeapFree(GetProcessHeap(), 0, (LPVOID)mvep32W->lpstrCommand); + HeapFree(GetProcessHeap(), 0, (LPVOID)lParam); + } + return WINMM_MAP_OK; + case MCI_INFO: + if (lParam) { + LPMCI_INFO_PARMSW mip32w = (LPMCI_INFO_PARMSW)lParam; + LPMCI_INFO_PARMS16 mip16 = *(LPMCI_INFO_PARMS16*)((char*)mip32w - sizeof(LPMCI_INFO_PARMS16)); + + WideCharToMultiByte(CP_ACP, 0, + mip32w->lpstrReturn, mip32w->dwRetSize / sizeof(WCHAR), + MapSL(mip16->lpstrReturn), mip16->dwRetSize, + NULL, NULL); + HeapFree(GetProcessHeap(), 0, (LPVOID)mip32w->lpstrReturn); + HeapFree(GetProcessHeap(), 0, (LPVOID)lParam); + } + return WINMM_MAP_OK; + case MCI_SYSINFO: + if (lParam) { + LPMCI_SYSINFO_PARMSW msip32w = (LPMCI_SYSINFO_PARMSW)lParam; + LPMCI_SYSINFO_PARMS16 msip16 = *(LPMCI_SYSINFO_PARMS16*)((char*)msip32w - sizeof(LPMCI_SYSINFO_PARMS16)); + + WideCharToMultiByte(CP_ACP, 0, + msip32w->lpstrReturn, msip32w->dwRetSize, + MapSL(msip16->lpstrReturn), msip16->dwRetSize, + NULL, NULL); + HeapFree(GetProcessHeap(), 0, (LPVOID)msip32w->lpstrReturn); + HeapFree(GetProcessHeap(), 0, (LPVOID)lParam); + } + return WINMM_MAP_OK; + case MCI_SOUND: + if (lParam) { + LPMCI_SOUND_PARMSW msp32W = (LPMCI_SOUND_PARMSW)lParam; + HeapFree(GetProcessHeap(), 0, (LPVOID)msp32W->lpstrSoundName); + HeapFree(GetProcessHeap(), 0, (LPVOID)lParam); + } + return WINMM_MAP_OK; + case MCI_OPEN: + case MCI_OPEN_DRIVER: + if (lParam) { + LPMCI_OPEN_PARMSW mop32w = (LPMCI_OPEN_PARMSW)lParam; + LPMCI_OPEN_PARMS16 mop16 = *(LPMCI_OPEN_PARMS16*)((char*)mop32w - sizeof(LPMCI_OPEN_PARMS16)); + + mop16->wDeviceID = mop32w->wDeviceID; + HeapFree(GetProcessHeap(), 0, mop32w->lpstrDeviceType); + HeapFree(GetProcessHeap(), 0, mop32w->lpstrElementName); + HeapFree(GetProcessHeap(), 0, mop32w->lpstrAlias); + if (!HeapFree(GetProcessHeap(), 0, (LPVOID)(lParam - sizeof(LPMCI_OPEN_PARMS16)))) + FIXME("bad free line=%d\n", __LINE__); + } + return WINMM_MAP_OK; + case DRV_LOAD: + case DRV_ENABLE: + case DRV_OPEN: + case DRV_CLOSE: + case DRV_DISABLE: + case DRV_FREE: + case DRV_CONFIGURE: + case DRV_QUERYCONFIGURE: + case DRV_INSTALL: + case DRV_REMOVE: + case DRV_EXITSESSION: + case DRV_EXITAPPLICATION: + case DRV_POWER: + FIXME("This is a hack\n"); + return WINMM_MAP_OK; + default: + FIXME("Map/Unmap internal error on msg=%s\n", MCI_MessageToString(wMsg)); + } + return WINMM_MAP_MSGERROR; +} + +/* + * 0000 stop + * 0001 squeeze signed 4 bytes to 2 bytes *( LPINT16)D = ( INT16)*( LPINT16)S; D += 2; S += 4 + * 0010 squeeze unsigned 4 bytes to 2 bytes *(LPUINT16)D = (UINT16)*(LPUINT16)S; D += 2; S += 4 + * 0100 + * 0101 + * 0110 zero 4 bytes *(DWORD)D = 0 D += 4; S += 4 + * 0111 copy string *(LPSTR*)D = seg dup(*(LPSTR*)S) D += 4; S += 4 + * 1xxx copy xxx + 1 bytes memcpy(D, S, xxx + 1); D += xxx+1; S += xxx+1 + */ + +/************************************************************************** + * MCI_MsgMapper32WTo16_Create [internal] + * + * Helper for MCI_MapMsg32WTo16. + * Maps the 32 bit pointer (*ptr), of size bytes, to an allocated 16 bit + * segmented pointer. + * map contains a list of action to be performed for the mapping (see list + * above) + * if keep is TRUE, keeps track of in 32 bit ptr in allocated 16 bit area. + */ +static WINMM_MapType MCI_MsgMapper32WTo16_Create(void** ptr, int size16, DWORD map, BOOLEAN keep) +{ + void* lp = HeapAlloc( GetProcessHeap(), 0, (keep ? sizeof(void**) : 0) + size16 ); + LPBYTE p16, p32; + + if (!lp) { + return WINMM_MAP_NOMEM; + } + p32 = (LPBYTE)(*ptr); + if (keep) { + *(void**)lp = *ptr; + p16 = (LPBYTE)lp + sizeof(void**); + *ptr = (char*)MapLS(lp) + sizeof(void**); + } else { + p16 = lp; + *ptr = (void*)MapLS(lp); + } + + if (map == 0) { + memcpy(p16, p32, size16); + } else { + unsigned nibble; + unsigned sz; + + while (map & 0xF) { + nibble = map & 0xF; + if (nibble & 0x8) { + sz = (nibble & 7) + 1; + memcpy(p16, p32, sz); + p16 += sz; + p32 += sz; + size16 -= sz; /* DEBUG only */ + } else { + switch (nibble) { + case 0x1: + *(LPINT16)p16 = *(LPINT)p32; + p16 += sizeof(INT16); + p32 += sizeof(INT); + size16 -= sizeof(INT16); + break; + case 0x2: + *(LPUINT16)p16 = *(LPUINT)p32; + p16 += sizeof(UINT16); + p32 += sizeof(UINT); + size16 -= sizeof(UINT16); + break; + case 0x6: + *(LPDWORD)p16 = 0; + p16 += sizeof(DWORD); + p32 += sizeof(DWORD); + size16 -= sizeof(DWORD); + break; + case 0x7: + *(SEGPTR *)p16 = MapLS( MCI_strdupWtoA( *(LPCWSTR *)p32 ) ); + p16 += sizeof(SEGPTR); + p32 += sizeof(LPSTR); + size16 -= sizeof(SEGPTR); + break; + default: + FIXME("Unknown nibble for mapping (%x)\n", nibble); + } + } + map >>= 4; + } + if (size16 != 0) /* DEBUG only */ + FIXME("Mismatch between 16 bit struct size and map nibbles serie\n"); + } + return WINMM_MAP_OKMEM; +} + +/************************************************************************** + * MCI_MsgMapper32WTo16_Destroy [internal] + * + * Helper for MCI_UnMapMsg32WTo16. + */ +static WINMM_MapType MCI_MsgMapper32WTo16_Destroy(void* ptr, int size16, DWORD map, BOOLEAN kept) +{ + if (ptr) { + void* msg16 = MapSL((SEGPTR)ptr); + void* alloc; + LPBYTE p32, p16; + unsigned nibble; + + UnMapLS( (SEGPTR)ptr ); + if (kept) { + alloc = (char*)msg16 - sizeof(void**); + p32 = *(void**)alloc; + p16 = msg16; + + if (map == 0) { + memcpy(p32, p16, size16); + } else { + while (map & 0xF) { + nibble = map & 0xF; + if (nibble & 0x8) { + memcpy(p32, p16, (nibble & 7) + 1); + p16 += (nibble & 7) + 1; + p32 += (nibble & 7) + 1; + size16 -= (nibble & 7) + 1; + } else { + switch (nibble) { + case 0x1: + *(LPINT)p32 = *(LPINT16)p16; + p16 += sizeof(INT16); + p32 += sizeof(INT); + size16 -= sizeof(INT16); + break; + case 0x2: + *(LPUINT)p32 = *(LPUINT16)p16; + p16 += sizeof(UINT16); + p32 += sizeof(UINT); + size16 -= sizeof(UINT16); + break; + case 0x6: + p16 += sizeof(UINT); + p32 += sizeof(UINT); + size16 -= sizeof(UINT); + break; + case 0x7: + HeapFree(GetProcessHeap(), 0, MapSL(*(SEGPTR *)p16)); + UnMapLS( *(SEGPTR *)p16 ); + p16 += sizeof(SEGPTR); + p32 += sizeof(char*); + size16 -= sizeof(SEGPTR); + break; + default: + FIXME("Unknown nibble for mapping (%x)\n", nibble); + } + } + map >>= 4; + } + if (size16 != 0) /* DEBUG only */ + FIXME("Mismatch between 16 bit struct size and map nibbles serie\n"); + } + } else { + alloc = msg16; + } + + HeapFree( GetProcessHeap(), 0, alloc ); + } + return WINMM_MAP_OK; +} + +/************************************************************************** + * MCI_MapMsg32WTo16 [internal] + * + * Map a 32W bit MCI message to a 16 bit MCI message. + */ +static WINMM_MapType MCI_MapMsg32WTo16(WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD* lParam) +{ + int size; + BOOLEAN keep = FALSE; + DWORD map = 0; + + if (*lParam == 0) + return WINMM_MAP_OK; + + /* FIXME: to add also (with seg/linear modifications to do): + * MCI_LIST, MCI_LOAD, MCI_QUALITY, MCI_RESERVE, MCI_RESTORE, MCI_SAVE + * MCI_SETAUDIO, MCI_SETTUNER, MCI_SETVIDEO + */ + switch (wMsg) { + case MCI_BREAK: + size = sizeof(MCI_BREAK_PARMS); + break; + /* case MCI_CAPTURE */ + case MCI_CLOSE: + case MCI_CLOSE_DRIVER: + case MCI_CONFIGURE: + size = sizeof(MCI_GENERIC_PARMS); + break; + /* case MCI_COPY: */ + case MCI_CUE: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_CUE_PARMS); break; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_CUE_PARMS); break;*/ FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + /* case MCI_CUT:*/ + case MCI_DELETE: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_DELETE_PARMS16); map = 0x0F1111FB; break; + case MCI_DEVTYPE_WAVEFORM_AUDIO:size = sizeof(MCI_WAVE_DELETE_PARMS); break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + /* case MCI_ESCAPE: */ + case MCI_FREEZE: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_FREEZE_PARMS); map = 0x0001111B; break; + case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS); map = 0x0001111B; break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + case MCI_GETDEVCAPS: + keep = TRUE; + size = sizeof(MCI_GETDEVCAPS_PARMS); + break; + /* case MCI_INDEX: */ + case MCI_INFO: + { + LPMCI_INFO_PARMSW mip32w = (LPMCI_INFO_PARMSW)(*lParam); + char* ptr; + LPMCI_INFO_PARMS16 mip16; + + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_INFO_PARMS16); break; + default: size = sizeof(MCI_INFO_PARMS16); break; + } + ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(LPMCI_INFO_PARMSW) + size); + if (ptr) + { + *(LPMCI_INFO_PARMSW*)ptr = mip32w; + mip16 = (LPMCI_INFO_PARMS16)(ptr + sizeof(LPMCI_INFO_PARMSW)); + mip16->dwCallback = mip32w->dwCallback; + mip16->lpstrReturn = MapLS( HeapAlloc(GetProcessHeap(), 0, mip32w->dwRetSize / sizeof(WCHAR)) ); + mip16->dwRetSize = mip32w->dwRetSize / sizeof(WCHAR); + if (uDevType == MCI_DEVTYPE_DIGITAL_VIDEO) { + ((LPMCI_DGV_INFO_PARMS16)mip16)->dwItem = ((LPMCI_DGV_INFO_PARMSW)mip32w)->dwItem; + } + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (LPARAM)MapLS(ptr) + sizeof(LPMCI_INFO_PARMSW); + } + return WINMM_MAP_OKMEM; + /* case MCI_MARK: */ + /* case MCI_MONITOR: */ + case MCI_OPEN: + case MCI_OPEN_DRIVER: + { + LPMCI_OPEN_PARMSW mop32w = (LPMCI_OPEN_PARMSW)(*lParam); + char* ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPMCI_OPEN_PARMSW) + sizeof(MCI_OPEN_PARMS16) + 2 * sizeof(DWORD)); + LPMCI_OPEN_PARMS16 mop16; + + + if (ptr) { + *(LPMCI_OPEN_PARMSW*)(ptr) = mop32w; + mop16 = (LPMCI_OPEN_PARMS16)(ptr + sizeof(LPMCI_OPEN_PARMSW)); + mop16->dwCallback = mop32w->dwCallback; + mop16->wDeviceID = mop32w->wDeviceID; + if (dwFlags & MCI_OPEN_TYPE) { + if (dwFlags & MCI_OPEN_TYPE_ID) { + /* dword "transparent" value */ + mop16->lpstrDeviceType = (SEGPTR)mop32w->lpstrDeviceType; + } else { + /* string */ + mop16->lpstrDeviceType = MapLS( MCI_strdupWtoA(mop32w->lpstrDeviceType) ); + } + } else { + /* nuthin' */ + mop16->lpstrDeviceType = 0; + } + if (dwFlags & MCI_OPEN_ELEMENT) { + if (dwFlags & MCI_OPEN_ELEMENT_ID) { + mop16->lpstrElementName = (SEGPTR)mop32w->lpstrElementName; + } else { + mop16->lpstrElementName = MapLS( MCI_strdupWtoA(mop32w->lpstrElementName) ); + } + } else { + mop16->lpstrElementName = 0; + } + if (dwFlags & MCI_OPEN_ALIAS) { + mop16->lpstrAlias = MapLS( MCI_strdupWtoA(mop32w->lpstrAlias) ); + } else { + mop16->lpstrAlias = 0; + } + /* copy extended information if any... + * FIXME: this may seg fault if initial structure does not contain them and + * the reads after msip16 fail under LDT limits... + * NOTE: this should be split in two. First pass, while calling MCI_OPEN, and + * should not take care of extended parameters, and should be used by MCI_Open + * to fetch uDevType. When, this is known, the mapping for sending the + * MCI_OPEN_DRIVER shall be done depending on uDevType. + */ + memcpy(mop16 + 1, mop32w + 1, 2 * sizeof(DWORD)); + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (LPARAM)MapLS(ptr) + sizeof(LPMCI_OPEN_PARMSW); + } + return WINMM_MAP_OKMEM; + /* case MCI_PASTE:*/ + case MCI_PAUSE: + size = sizeof(MCI_GENERIC_PARMS); + break; + case MCI_PLAY: + size = sizeof(MCI_PLAY_PARMS); + break; + case MCI_PUT: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16); map = 0x0001111B; break; + case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS); map = 0x0001111B; break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + case MCI_REALIZE: + size = sizeof(MCI_GENERIC_PARMS); + break; + case MCI_RECORD: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECORD_PARMS16); map = 0x0F1111FB; break; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_RECORD_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + default: size = sizeof(MCI_RECORD_PARMS); break; + } + break; + case MCI_RESUME: + size = sizeof(MCI_GENERIC_PARMS); + break; + case MCI_SEEK: + switch (uDevType) { + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_SEEK_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + default: size = sizeof(MCI_SEEK_PARMS); break; + } + break; + case MCI_SET: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_SET_PARMS); break; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_SET_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + case MCI_DEVTYPE_SEQUENCER: size = sizeof(MCI_SEQ_SET_PARMS); break; + /* FIXME: normally the 16 and 32 bit structures are byte by byte aligned, + * so not doing anything should work... + */ + case MCI_DEVTYPE_WAVEFORM_AUDIO:size = sizeof(MCI_WAVE_SET_PARMS); break; + default: size = sizeof(MCI_SET_PARMS); break; + } + break; + case MCI_SETAUDIO: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_SETAUDIO_PARMS16);map = 0x0000077FF; break; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_SETAUDIO_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + /* case MCI_SETTIMECODE:*/ + /* case MCI_SIGNAL:*/ + /* case MCI_SOUND:*/ + case MCI_SPIN: + size = sizeof(MCI_SET_PARMS); + break; + case MCI_STATUS: + keep = TRUE; + switch (uDevType) { + /* FIXME: + * don't know if buffer for value is the one passed through lpstrDevice + * or is provided by MCI driver. + * Assuming solution 2: provided by MCI driver, so zeroing on entry + */ + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_STATUS_PARMS16); map = 0x0B6FF; break; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_STATUS_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + default: size = sizeof(MCI_STATUS_PARMS); break; + } + break; + case MCI_STEP: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_STEP_PARMS); break; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_STEP_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + case MCI_DEVTYPE_VIDEODISC: size = sizeof(MCI_VD_STEP_PARMS); break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + case MCI_STOP: + size = sizeof(MCI_SET_PARMS); + break; + case MCI_SYSINFO: + { + LPMCI_SYSINFO_PARMSW msip32w = (LPMCI_SYSINFO_PARMSW)(*lParam); + LPMCI_SYSINFO_PARMS16 msip16; + char* ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPMCI_SYSINFO_PARMSW) + sizeof(MCI_SYSINFO_PARMS16) ); + + if (ptr) { + *(LPMCI_SYSINFO_PARMSW*)(ptr) = msip32w; + msip16 = (LPMCI_SYSINFO_PARMS16)(ptr + sizeof(LPMCI_SYSINFO_PARMSW)); + + msip16->dwCallback = msip32w->dwCallback; + msip16->lpstrReturn = MapLS( HeapAlloc(GetProcessHeap(), 0, msip32w->dwRetSize) ); + msip16->dwRetSize = msip32w->dwRetSize; + msip16->dwNumber = msip32w->dwNumber; + msip16->wDeviceType = msip32w->wDeviceType; + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (LPARAM)MapLS(ptr) + sizeof(LPMCI_SYSINFO_PARMSW); + } + return WINMM_MAP_OKMEM; + /* case MCI_UNDO: */ + case MCI_UNFREEZE: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16); map = 0x0001111B; break; + case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS16); map = 0x0001111B; break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + case MCI_UPDATE: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_UPDATE_PARMS16); map = 0x000B1111B; break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + case MCI_WHERE: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16); map = 0x0001111B; keep = TRUE; break; + case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS16); map = 0x0001111B; keep = TRUE; break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + case MCI_WINDOW: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_WINDOW_PARMS16); if (dwFlags & MCI_DGV_WINDOW_TEXT) map = 0x7FB; break; + case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_WINDOW_PARMS16); if (dwFlags & MCI_OVLY_WINDOW_TEXT) map = 0x7FB; break; + default: size = sizeof(MCI_GENERIC_PARMS); break; + } + break; + case DRV_OPEN: + { + LPMCI_OPEN_DRIVER_PARMSW modp32w = (LPMCI_OPEN_DRIVER_PARMSW)(*lParam); + LPMCI_OPEN_DRIVER_PARMS16 modp16; + char *ptr = HeapAlloc( GetProcessHeap(), 0, + sizeof(LPMCI_OPEN_DRIVER_PARMSW) + sizeof(MCI_OPEN_DRIVER_PARMS16)); + + if (ptr) { + *(LPMCI_OPEN_DRIVER_PARMSW*)(ptr) = modp32w; + modp16 = (LPMCI_OPEN_DRIVER_PARMS16)(ptr + sizeof(LPMCI_OPEN_DRIVER_PARMSW)); + modp16->wDeviceID = modp32w->wDeviceID; + modp16->lpstrParams = MapLS( MCI_strdupWtoA(modp32w->lpstrParams) ); + /* other fields are gonna be filled by the driver, don't copy them */ + } else { + return WINMM_MAP_NOMEM; + } + *lParam = (LPARAM)MapLS(ptr) + sizeof(LPMCI_OPEN_DRIVER_PARMSW); + } + return WINMM_MAP_OKMEM; + case DRV_LOAD: + case DRV_ENABLE: + case DRV_CLOSE: + case DRV_DISABLE: + case DRV_FREE: + case DRV_CONFIGURE: + case DRV_QUERYCONFIGURE: + case DRV_INSTALL: + case DRV_REMOVE: + case DRV_EXITSESSION: + case DRV_EXITAPPLICATION: + case DRV_POWER: + return WINMM_MAP_OK; + + default: + FIXME("Don't know how to map msg=%s\n", MCI_MessageToString(wMsg)); + return WINMM_MAP_MSGERROR; + } + return MCI_MsgMapper32WTo16_Create((void**)lParam, size, map, keep); +} + +/************************************************************************** + * MCI_UnMapMsg32WTo16 [internal] + */ +static WINMM_MapType MCI_UnMapMsg32WTo16(WORD uDevType, WORD wMsg, DWORD dwFlags, DWORD lParam) +{ + int size = 0; + BOOLEAN kept = FALSE; /* there is no need to compute size when kept is FALSE */ + DWORD map = 0; + + switch (wMsg) { + case MCI_BREAK: + break; + /* case MCI_CAPTURE */ + case MCI_CLOSE: + case MCI_CLOSE_DRIVER: + case MCI_CONFIGURE: + break; + /* case MCI_COPY: */ + case MCI_CUE: + break; + /* case MCI_CUT: */ + case MCI_DELETE: + break; + /* case MCI_ESCAPE: */ + case MCI_FREEZE: + break; + case MCI_GETDEVCAPS: + kept = TRUE; + size = sizeof(MCI_GETDEVCAPS_PARMS); + break; + /* case MCI_INDEX: */ + case MCI_INFO: + if (lParam) { + LPMCI_INFO_PARMS16 mip16 = (LPMCI_INFO_PARMS16)MapSL(lParam); + LPMCI_INFO_PARMSW mip32w = *(LPMCI_INFO_PARMSW*)((char*)mip16 - sizeof(LPMCI_INFO_PARMSW)); + + MultiByteToWideChar(CP_ACP, 0, MapSL(mip16->lpstrReturn), mip16->dwRetSize, + mip32w->lpstrReturn, mip32w->dwRetSize / sizeof(WCHAR)); + UnMapLS( lParam ); + UnMapLS( mip16->lpstrReturn ); + HeapFree( GetProcessHeap(), 0, (void*)MapSL(mip16->lpstrReturn) ); + HeapFree( GetProcessHeap(), 0, (char*)mip16 - sizeof(LPMCI_OPEN_PARMSW) ); + } + return WINMM_MAP_OK; + /* case MCI_MARK: */ + /* case MCI_MONITOR: */ + case MCI_OPEN: + case MCI_OPEN_DRIVER: + if (lParam) { + LPMCI_OPEN_PARMS16 mop16 = (LPMCI_OPEN_PARMS16)MapSL(lParam); + LPMCI_OPEN_PARMSW mop32w = *(LPMCI_OPEN_PARMSW*)((char*)mop16 - sizeof(LPMCI_OPEN_PARMSW)); + UnMapLS( lParam ); + mop32w->wDeviceID = mop16->wDeviceID; + if ((dwFlags & MCI_OPEN_TYPE) && !(dwFlags & MCI_OPEN_TYPE_ID)) + { + HeapFree(GetProcessHeap(), 0, MapSL(mop16->lpstrDeviceType)); + UnMapLS( mop16->lpstrDeviceType ); + } + if ((dwFlags & MCI_OPEN_ELEMENT) && !(dwFlags & MCI_OPEN_ELEMENT_ID)) + { + HeapFree(GetProcessHeap(), 0, MapSL(mop16->lpstrElementName)); + UnMapLS( mop16->lpstrElementName ); + } + if (dwFlags & MCI_OPEN_ALIAS) + { + HeapFree(GetProcessHeap(), 0, MapSL(mop16->lpstrAlias)); + UnMapLS( mop16->lpstrAlias ); + } + HeapFree( GetProcessHeap(), 0, (char*)mop16 - sizeof(LPMCI_OPEN_PARMSW) ); + } + return WINMM_MAP_OK; + /* case MCI_PASTE:*/ + case MCI_PAUSE: + break; + case MCI_PLAY: + break; + case MCI_PUT: + break; + case MCI_REALIZE: + break; + case MCI_RECORD: + break; + case MCI_RESUME: + break; + case MCI_SEEK: + break; + case MCI_SET: + break; + case MCI_SETAUDIO: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: map = 0x0000077FF; break; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_SETAUDIO_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + } + break; + /* case MCI_SETTIMECODE:*/ + /* case MCI_SIGNAL:*/ + /* case MCI_SOUND:*/ + case MCI_SPIN: + break; + case MCI_STATUS: + kept = TRUE; + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: + if (lParam) { + LPMCI_DGV_STATUS_PARMS16 mdsp16 = (LPMCI_DGV_STATUS_PARMS16)MapSL(lParam); + LPMCI_DGV_STATUS_PARMSA mdsp32a = *(LPMCI_DGV_STATUS_PARMSA*)((char*)mdsp16 - sizeof(LPMCI_DGV_STATUS_PARMSA)); + + UnMapLS( lParam ); + if (mdsp16) { + mdsp32a->dwReturn = mdsp16->dwReturn; + if (dwFlags & MCI_DGV_STATUS_DISKSPACE) { + TRACE("MCI_STATUS (DGV) lpstrDrive=%08lx\n", mdsp16->lpstrDrive); + TRACE("MCI_STATUS (DGV) lpstrDrive=%s\n", (LPSTR)MapSL(mdsp16->lpstrDrive)); + UnMapLS( mdsp16->lpstrDrive ); + } + HeapFree( GetProcessHeap(), 0, (char*)mdsp16 - sizeof(LPMCI_DGV_STATUS_PARMSA) ); + } else { + return WINMM_MAP_NOMEM; + } + } + return WINMM_MAP_OKMEM; + case MCI_DEVTYPE_VCR: /*size = sizeof(MCI_VCR_STATUS_PARMS); break;*/FIXME("NIY vcr\n"); return WINMM_MAP_NOMEM; + default: size = sizeof(MCI_STATUS_PARMS); break; + } + break; + case MCI_STEP: + break; + case MCI_STOP: + break; + case MCI_SYSINFO: + if (lParam) { + LPMCI_SYSINFO_PARMS16 msip16 = (LPMCI_SYSINFO_PARMS16)MapSL(lParam); + LPMCI_SYSINFO_PARMSW msip32w = *(LPMCI_SYSINFO_PARMSW*)((char*)msip16 - sizeof(LPMCI_SYSINFO_PARMSW)); + + UnMapLS( lParam ); + if (msip16) { + MultiByteToWideChar(CP_ACP, 0, MapSL(msip16->lpstrReturn), msip16->dwRetSize, + msip32w->lpstrReturn, msip32w->dwRetSize); + UnMapLS( msip16->lpstrReturn ); + HeapFree( GetProcessHeap(), 0, MapSL(msip16->lpstrReturn) ); + HeapFree( GetProcessHeap(), 0, (char*)msip16 - sizeof(LPMCI_SYSINFO_PARMSW) ); + } else { + return WINMM_MAP_NOMEM; + } + } + return WINMM_MAP_OKMEM; + /* case MCI_UNDO: */ + case MCI_UNFREEZE: + break; + case MCI_UPDATE: + break; + case MCI_WHERE: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_RECT_PARMS16); map = 0x0001111B; kept = TRUE; break; + case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_RECT_PARMS16); map = 0x0001111B; kept = TRUE; break; + default: break; + } + break; + case MCI_WINDOW: + switch (uDevType) { + case MCI_DEVTYPE_DIGITAL_VIDEO: size = sizeof(MCI_DGV_WINDOW_PARMS16); if (dwFlags & MCI_DGV_WINDOW_TEXT) map = 0x7666; break; + case MCI_DEVTYPE_OVERLAY: size = sizeof(MCI_OVLY_WINDOW_PARMS16); if (dwFlags & MCI_OVLY_WINDOW_TEXT) map = 0x7666; break; + default: break; + } + /* FIXME: see map function */ + break; + case DRV_OPEN: + if (lParam) { + LPMCI_OPEN_DRIVER_PARMS16 modp16 = (LPMCI_OPEN_DRIVER_PARMS16)MapSL(lParam); + LPMCI_OPEN_DRIVER_PARMSW modp32w = *(LPMCI_OPEN_DRIVER_PARMSW*)((char*)modp16 - sizeof(LPMCI_OPEN_DRIVER_PARMSW)); + + UnMapLS( lParam ); + modp32w->wCustomCommandTable = modp16->wCustomCommandTable; + modp32w->wType = modp16->wType; + HeapFree(GetProcessHeap(), 0, MapSL(modp16->lpstrParams)); + UnMapLS( modp16->lpstrParams ); + HeapFree( GetProcessHeap(), 0, (char *)modp16 - sizeof(LPMCI_OPEN_DRIVER_PARMSW) ); + } + return WINMM_MAP_OK; + case DRV_LOAD: + case DRV_ENABLE: + case DRV_CLOSE: + case DRV_DISABLE: + case DRV_FREE: + case DRV_CONFIGURE: + case DRV_QUERYCONFIGURE: + case DRV_INSTALL: + case DRV_REMOVE: + case DRV_EXITSESSION: + case DRV_EXITAPPLICATION: + case DRV_POWER: + FIXME("This is a hack\n"); + return WINMM_MAP_OK; + + default: + FIXME("Map/Unmap internal error on msg=%s\n", MCI_MessageToString(wMsg)); + return WINMM_MAP_MSGERROR; + } + return MCI_MsgMapper32WTo16_Destroy((void*)lParam, size, map, kept); +} + +void MMDRV_Init16(void) +{ +#define A(_x,_y) MMDRV_InstallMap(_x, \ +MMDRV_##_y##_Map16To32W, MMDRV_##_y##_UnMap16To32W, \ +MMDRV_##_y##_Map32WTo16, MMDRV_##_y##_UnMap32WTo16, \ +MMDRV_##_y##_Callback) + A(MMDRV_AUX, Aux); + A(MMDRV_MIXER, Mixer); + A(MMDRV_MIDIIN, MidiIn); + A(MMDRV_MIDIOUT, MidiOut); + A(MMDRV_WAVEIN, WaveIn); + A(MMDRV_WAVEOUT, WaveOut); +#undef A + + pFnCallMMDrvFunc16 = MMDRV_CallMMDrvFunc16; + pFnLoadMMDrvFunc16 = MMDRV_LoadMMDrvFunc16; + + pFnMciMapMsg16To32W = MCI_MapMsg16To32W; + pFnMciUnMapMsg16To32W = MCI_UnMapMsg16To32W; + pFnMciMapMsg32WTo16 = MCI_MapMsg32WTo16; + pFnMciUnMapMsg32WTo16 = MCI_UnMapMsg32WTo16; +} diff --git a/reactos/lib/winmm/midimap/midimap.c b/reactos/lib/winmm/midimap/midimap.c index 4c8a4a07ccc..6bfdef36107 100644 --- a/reactos/lib/winmm/midimap/midimap.c +++ b/reactos/lib/winmm/midimap/midimap.c @@ -1,565 +1,565 @@ -/* -*- tab-width: 8; c-basic-offset: 4 -*- */ -/* - * Wine MIDI mapper driver - * - * Copyright 1999, 2000, 2001 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * TODO: - * notification has to be implemented - * IDF file loading - */ - -#include <stdarg.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "mmddk.h" -#include "winreg.h" -#include "wine/unicode.h" -#include "wine/debug.h" - -/* - * Here's how Windows stores the midiOut mapping information. - * - * Full form (in HKU) is: - * - * [Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia\\MIDIMap] 988836060 - * "AutoScheme"=dword:00000000 - * "ConfigureCount"=dword:00000004 - * "CurrentInstrument"="Wine OSS midi" - * "CurrentScheme"="epp" - * "DriverList"="" - * "UseScheme"=dword:00000000 - * - * AutoScheme: ? - * CurrentInstrument: name of midiOut device to use when UseScheme is 0. Wine uses an extension - * of the form #n to link to n'th midiOut device of the system - * CurrentScheme: when UseScheme is non null, it's the scheme to use (see below) - * DriverList: ? - * UseScheme: trigger for simple/complex mapping - * - * A scheme is defined (in HKLM) as: - * - * [System\\CurrentControlSet\\Control\\MediaProperties\\PrivateProperties\\Midi\\Schemes\\<nameScheme>] - * <nameScheme>: one key for each defined scheme (system wide) - * under each one of these <nameScheme> keys, there's: - * [...\\<nameScheme>\\<idxDevice>] - * "Channels"="<bitMask>" - * (the default value of this key also refers to the name of the device). - * - * this defines, for each midiOut device (identified by its index in <idxDevice>), which - * channels have to be mapped onto it. The <bitMask> defines the channels (from 0 to 15) - * will be mapped (mapping occurs for channel <ch> if bit <ch> is set in <bitMask> - * - * Further mapping information can also be defined in: - * [System\\CurrentControlSet\\Control\\MediaProperties\\PrivateProperties\\Midi\\Ports\\<nameDevice>\\Instruments\\<idx>] - * "Definition"="<.idf file>" - * "FriendlyName"="#for .idx file#" - * "Port"="<idxPort>" - * - * This last part isn't implemented (.idf file support). - */ - -WINE_DEFAULT_DEBUG_CHANNEL(msacm); - -typedef struct tagMIDIOUTPORT -{ - WCHAR name[MAXPNAMELEN]; - int loaded; - HMIDIOUT hMidi; - unsigned short uDevID; - LPBYTE lpbPatch; - unsigned int aChn[16]; -} MIDIOUTPORT; - -typedef struct tagMIDIMAPDATA -{ - struct tagMIDIMAPDATA* self; - MIDIOUTPORT* ChannelMap[16]; -} MIDIMAPDATA; - -static MIDIOUTPORT* midiOutPorts; -static unsigned numMidiOutPorts; - -static BOOL MIDIMAP_IsBadData(MIDIMAPDATA* mm) -{ - if (!IsBadReadPtr(mm, sizeof(MIDIMAPDATA)) && mm->self == mm) - return FALSE; - TRACE("Bad midimap data (%p)\n", mm); - return TRUE; -} - -static BOOL MIDIMAP_FindPort(const WCHAR* name, unsigned* dev) -{ - for (*dev = 0; *dev < numMidiOutPorts; (*dev)++) - { - TRACE("%s\n", wine_dbgstr_w(midiOutPorts[*dev].name)); - if (strcmpW(midiOutPorts[*dev].name, name) == 0) - return TRUE; - } - /* try the form #nnn */ - if (*name == '#' && isdigit(name[1])) - { - const WCHAR* ptr = name + 1; - *dev = 0; - do - { - *dev = *dev * 10 + *ptr - '0'; - } while (isdigit(*++ptr)); - if (*dev < numMidiOutPorts) - return TRUE; - } - return FALSE; -} - -static BOOL MIDIMAP_LoadSettingsDefault(MIDIMAPDATA* mom, const WCHAR* port) -{ - unsigned i, dev = 0; - - if (port != NULL && !MIDIMAP_FindPort(port, &dev)) - { - ERR("Registry glitch: couldn't find midi out (%s)\n", wine_dbgstr_w(port)); - dev = 0; - } - - /* this is necessary when no midi out ports are present */ - if (dev >= numMidiOutPorts) - return FALSE; - /* sets default */ - for (i = 0; i < 16; i++) mom->ChannelMap[i] = &midiOutPorts[dev]; - - return TRUE; -} - -static BOOL MIDIMAP_LoadSettingsScheme(MIDIMAPDATA* mom, const WCHAR* scheme) -{ - HKEY hSchemesKey, hKey, hPortKey; - unsigned i, idx, dev; - WCHAR buffer[256], port[256]; - DWORD type, size, mask; - - for (i = 0; i < 16; i++) mom->ChannelMap[i] = NULL; - - if (RegOpenKeyA(HKEY_LOCAL_MACHINE, - "System\\CurrentControlSet\\Control\\MediaProperties\\PrivateProperties\\Midi\\Schemes", - &hSchemesKey)) - { - return FALSE; - } - if (RegOpenKeyW(hSchemesKey, scheme, &hKey)) - { - RegCloseKey(hSchemesKey); - return FALSE; - } - - for (idx = 0; !RegEnumKeyW(hKey, idx, buffer, sizeof(buffer)); idx++) - { - if (RegOpenKeyW(hKey, buffer, &hPortKey)) continue; - - size = sizeof(port); - if (RegQueryValueExW(hPortKey, NULL, 0, &type, (void*)port, &size)) continue; - - if (!MIDIMAP_FindPort(port, &dev)) continue; - - size = sizeof(mask); - if (RegQueryValueExA(hPortKey, "Channels", 0, &type, (void*)&mask, &size)) - continue; - - for (i = 0; i < 16; i++) - { - if (mask & (1 << i)) - { - if (mom->ChannelMap[i]) - ERR("Quirks in registry, channel %u is mapped twice\n", i); - mom->ChannelMap[i] = &midiOutPorts[dev]; - } - } - } - - RegCloseKey(hSchemesKey); - RegCloseKey(hKey); - - return TRUE; -} - -static BOOL MIDIMAP_LoadSettings(MIDIMAPDATA* mom) -{ - HKEY hKey; - BOOL ret; - - if (RegOpenKeyA(HKEY_CURRENT_USER, - "Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia\\MIDIMap", &hKey)) - { - ret = MIDIMAP_LoadSettingsDefault(mom, NULL); - } - else - { - DWORD type, size, out; - WCHAR buffer[256]; - - ret = 2; - size = sizeof(out); - if (!RegQueryValueExA(hKey, "UseScheme", 0, &type, (void*)&out, &size) && out) - { - static const WCHAR cs[] = {'C','u','r','r','e','n','t','S','c','h','e','m','e',0}; - size = sizeof(buffer); - if (!RegQueryValueExW(hKey, cs, 0, &type, (void*)buffer, &size)) - { - if (!(ret = MIDIMAP_LoadSettingsScheme(mom, buffer))) - ret = MIDIMAP_LoadSettingsDefault(mom, NULL); - } - else - { - ERR("Wrong registry: UseScheme is active, but no CurrentScheme found\n"); - } - } - if (ret == 2) - { - static const WCHAR ci[] = {'C','u','r','r','e','n','t','I','n','s','t','r','u','m','e','n','t',0}; - size = sizeof(buffer); - if (!RegQueryValueExW(hKey, ci, 0, &type, (void*)buffer, &size) && *buffer) - { - ret = MIDIMAP_LoadSettingsDefault(mom, buffer); - } - else - { - ret = MIDIMAP_LoadSettingsDefault(mom, NULL); - } - } - } - RegCloseKey(hKey); - - if (ret && TRACE_ON(msacm)) - { - unsigned i; - - for (i = 0; i < 16; i++) - { - TRACE("chnMap[%2d] => %d\n", - i, mom->ChannelMap[i] ? mom->ChannelMap[i]->uDevID : -1); - } - } - return ret; -} - -static DWORD modOpen(LPDWORD lpdwUser, LPMIDIOPENDESC lpDesc, DWORD dwFlags) -{ - MIDIMAPDATA* mom = HeapAlloc(GetProcessHeap(), 0, sizeof(MIDIMAPDATA)); - - TRACE("(%p %p %08lx)\n", lpdwUser, lpDesc, dwFlags); - - if (!mom) return MMSYSERR_NOMEM; - - if (MIDIMAP_LoadSettings(mom)) - { - *lpdwUser = (DWORD)mom; - mom->self = mom; - - return MMSYSERR_NOERROR; - } - HeapFree(GetProcessHeap(), 0, mom); - return MIDIERR_INVALIDSETUP; -} - -static DWORD modClose(MIDIMAPDATA* mom) -{ - UINT i; - DWORD ret = MMSYSERR_NOERROR; - - if (MIDIMAP_IsBadData(mom)) return MMSYSERR_ERROR; - - for (i = 0; i < 16; i++) - { - DWORD t; - if (mom->ChannelMap[i] && mom->ChannelMap[i]->loaded > 0) - { - t = midiOutClose(mom->ChannelMap[i]->hMidi); - if (t == MMSYSERR_NOERROR) - { - mom->ChannelMap[i]->loaded = 0; - mom->ChannelMap[i]->hMidi = 0; - } - else if (ret == MMSYSERR_NOERROR) - ret = t; - } - } - if (ret == MMSYSERR_NOERROR) - HeapFree(GetProcessHeap(), 0, mom); - return ret; -} - -static DWORD modLongData(MIDIMAPDATA* mom, LPMIDIHDR lpMidiHdr, DWORD dwParam2) -{ - WORD chn; - DWORD ret = MMSYSERR_NOERROR; - MIDIHDR mh; - - if (MIDIMAP_IsBadData(mom)) - return MMSYSERR_ERROR; - - mh = *lpMidiHdr; - for (chn = 0; chn < 16; chn++) - { - if (mom->ChannelMap[chn] && mom->ChannelMap[chn]->loaded > 0) - { - mh.dwFlags = 0; - midiOutPrepareHeader(mom->ChannelMap[chn]->hMidi, &mh, sizeof(mh)); - ret = midiOutLongMsg(mom->ChannelMap[chn]->hMidi, &mh, sizeof(mh)); - midiOutUnprepareHeader(mom->ChannelMap[chn]->hMidi, &mh, sizeof(mh)); - if (ret != MMSYSERR_NOERROR) break; - } - } - return ret; -} - -static DWORD modData(MIDIMAPDATA* mom, DWORD dwParam) -{ - BYTE lb = LOBYTE(LOWORD(dwParam)); - WORD chn = lb & 0x0F; - DWORD ret = MMSYSERR_NOERROR; - - if (MIDIMAP_IsBadData(mom)) - return MMSYSERR_ERROR; - - if (!mom->ChannelMap[chn]) return MMSYSERR_NOERROR; - - switch (lb & 0xF0) - { - case 0x80: - case 0x90: - case 0xA0: - case 0xB0: - case 0xC0: - case 0xD0: - case 0xE0: - if (mom->ChannelMap[chn]->loaded == 0) - { - if (midiOutOpen(&mom->ChannelMap[chn]->hMidi, mom->ChannelMap[chn]->uDevID, - 0L, 0L, CALLBACK_NULL) == MMSYSERR_NOERROR) - mom->ChannelMap[chn]->loaded = 1; - else - mom->ChannelMap[chn]->loaded = -1; - /* FIXME: should load here the IDF midi data... and allow channel and - * patch mappings - */ - } - if (mom->ChannelMap[chn]->loaded > 0) - { - /* change channel */ - dwParam &= ~0x0F; - dwParam |= mom->ChannelMap[chn]->aChn[chn]; - - if ((LOBYTE(LOWORD(dwParam)) & 0xF0) == 0xC0 /* program change */ && - mom->ChannelMap[chn]->lpbPatch) - { - BYTE patch = HIBYTE(LOWORD(dwParam)); - - /* change patch */ - dwParam &= ~0x0000FF00; - dwParam |= mom->ChannelMap[chn]->lpbPatch[patch]; - } - ret = midiOutShortMsg(mom->ChannelMap[chn]->hMidi, dwParam); - } - break; - case 0xF0: - for (chn = 0; chn < 16; chn++) - { - if (mom->ChannelMap[chn]->loaded > 0) - ret = midiOutShortMsg(mom->ChannelMap[chn]->hMidi, dwParam); - } - break; - default: - FIXME("ooch %lu\n", dwParam); - } - - return ret; -} - -static DWORD modPrepare(MIDIMAPDATA* mom, LPMIDIHDR lpMidiHdr, DWORD dwParam2) -{ - if (MIDIMAP_IsBadData(mom)) return MMSYSERR_ERROR; - if (lpMidiHdr->dwFlags & (MHDR_ISSTRM|MHDR_PREPARED)) - return MMSYSERR_INVALPARAM; - - lpMidiHdr->dwFlags |= MHDR_PREPARED; - return MMSYSERR_NOERROR; -} - -static DWORD modUnprepare(MIDIMAPDATA* mom, LPMIDIHDR lpMidiHdr, DWORD dwParam2) -{ - if (MIDIMAP_IsBadData(mom)) return MMSYSERR_ERROR; - if ((lpMidiHdr->dwFlags & MHDR_ISSTRM) || !(lpMidiHdr->dwFlags & MHDR_PREPARED)) - return MMSYSERR_INVALPARAM; - - lpMidiHdr->dwFlags &= ~MHDR_PREPARED; - return MMSYSERR_NOERROR; -} - -static DWORD modGetDevCaps(UINT wDevID, MIDIMAPDATA* mom, LPMIDIOUTCAPSW lpMidiCaps, DWORD size) -{ - static const WCHAR name[] = {'W','i','n','e',' ','m','i','d','i',' ','m','a','p','p','e','r',0}; - lpMidiCaps->wMid = 0x00FF; - lpMidiCaps->wPid = 0x0001; - lpMidiCaps->vDriverVersion = 0x0100; - lstrcpyW(lpMidiCaps->szPname, name); - lpMidiCaps->wTechnology = MOD_MAPPER; - lpMidiCaps->wVoices = 0; - lpMidiCaps->wNotes = 0; - lpMidiCaps->wChannelMask = 0xFFFF; - lpMidiCaps->dwSupport = 0L; - - return MMSYSERR_NOERROR; -} - -static DWORD modReset(MIDIMAPDATA* mom) -{ - WORD chn; - DWORD ret = MMSYSERR_NOERROR; - - if (MIDIMAP_IsBadData(mom)) - return MMSYSERR_ERROR; - - for (chn = 0; chn < 16; chn++) - { - if (mom->ChannelMap[chn] && mom->ChannelMap[chn]->loaded > 0) - { - ret = midiOutReset(mom->ChannelMap[chn]->hMidi); - if (ret != MMSYSERR_NOERROR) break; - } - } - return ret; -} - -/************************************************************************** - * modMessage (MIDIMAP.@) - */ -DWORD WINAPI MIDIMAP_modMessage(UINT wDevID, UINT wMsg, DWORD dwUser, - DWORD dwParam1, DWORD dwParam2) -{ - TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n", - wDevID, wMsg, dwUser, dwParam1, dwParam2); - - switch (wMsg) - { - case DRVM_INIT: - case DRVM_EXIT: - case DRVM_ENABLE: - case DRVM_DISABLE: - /* FIXME: Pretend this is supported */ - return 0; - - case MODM_OPEN: return modOpen ((LPDWORD)dwUser, (LPMIDIOPENDESC)dwParam1,dwParam2); - case MODM_CLOSE: return modClose ((MIDIMAPDATA*)dwUser); - - case MODM_DATA: return modData ((MIDIMAPDATA*)dwUser, dwParam1); - case MODM_LONGDATA: return modLongData ((MIDIMAPDATA*)dwUser, (LPMIDIHDR)dwParam1, dwParam2); - case MODM_PREPARE: return modPrepare ((MIDIMAPDATA*)dwUser, (LPMIDIHDR)dwParam1, dwParam2); - case MODM_UNPREPARE: return modUnprepare ((MIDIMAPDATA*)dwUser, (LPMIDIHDR)dwParam1, dwParam2); - case MODM_RESET: return modReset ((MIDIMAPDATA*)dwUser); - - case MODM_GETDEVCAPS: return modGetDevCaps (wDevID, (MIDIMAPDATA*)dwUser, (LPMIDIOUTCAPSW)dwParam1,dwParam2); - case MODM_GETNUMDEVS: return 1; - case MODM_GETVOLUME: return MMSYSERR_NOTSUPPORTED; - case MODM_SETVOLUME: return MMSYSERR_NOTSUPPORTED; - default: - FIXME("unknown message %d!\n", wMsg); - } - return MMSYSERR_NOTSUPPORTED; -} - -/*======================================================================* - * Driver part * - *======================================================================*/ - -/************************************************************************** - * MIDIMAP_drvOpen [internal] - */ -static DWORD MIDIMAP_drvOpen(LPSTR str) -{ - MIDIOUTCAPSW moc; - unsigned dev, i; - - if (midiOutPorts) - return 0; - - numMidiOutPorts = midiOutGetNumDevs(); - midiOutPorts = HeapAlloc(GetProcessHeap(), 0, - numMidiOutPorts * sizeof(MIDIOUTPORT)); - for (dev = 0; dev < numMidiOutPorts; dev++) - { - if (midiOutGetDevCapsW(dev, &moc, sizeof(moc)) == 0L) - { - strcpyW(midiOutPorts[dev].name, moc.szPname); - midiOutPorts[dev].loaded = 0; - midiOutPorts[dev].hMidi = 0; - midiOutPorts[dev].uDevID = dev; - midiOutPorts[dev].lpbPatch = NULL; - for (i = 0; i < 16; i++) - midiOutPorts[dev].aChn[i] = i; - } - else - { - midiOutPorts[dev].loaded = -1; - } - } - - return 1; -} - -/************************************************************************** - * MIDIMAP_drvClose [internal] - */ -static DWORD MIDIMAP_drvClose(DWORD dwDevID) -{ - if (midiOutPorts) - { - HeapFree(GetProcessHeap(), 0, midiOutPorts); - midiOutPorts = NULL; - return 1; - } - return 0; -} - -/************************************************************************** - * DriverProc (MIDIMAP.@) - */ -LONG CALLBACK MIDIMAP_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, - DWORD dwParam1, DWORD dwParam2) -{ -/* EPP TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n", */ -/* EPP dwDevID, hDriv, wMsg, dwParam1, dwParam2); */ - - switch (wMsg) - { - case DRV_LOAD: return 1; - case DRV_FREE: return 1; - case DRV_OPEN: return MIDIMAP_drvOpen((LPSTR)dwParam1); - case DRV_CLOSE: return MIDIMAP_drvClose(dwDevID); - case DRV_ENABLE: return 1; - case DRV_DISABLE: return 1; - case DRV_QUERYCONFIGURE: return 1; - case DRV_CONFIGURE: MessageBoxA(0, "MIDIMAP MultiMedia Driver !", "OSS Driver", MB_OK); return 1; - case DRV_INSTALL: return DRVCNF_RESTART; - case DRV_REMOVE: return DRVCNF_RESTART; - default: - return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2); - } -} +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ +/* + * Wine MIDI mapper driver + * + * Copyright 1999, 2000, 2001 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * TODO: + * notification has to be implemented + * IDF file loading + */ + +#include <stdarg.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "mmddk.h" +#include "winreg.h" +#include "wine/unicode.h" +#include "wine/debug.h" + +/* + * Here's how Windows stores the midiOut mapping information. + * + * Full form (in HKU) is: + * + * [Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia\\MIDIMap] 988836060 + * "AutoScheme"=dword:00000000 + * "ConfigureCount"=dword:00000004 + * "CurrentInstrument"="Wine OSS midi" + * "CurrentScheme"="epp" + * "DriverList"="" + * "UseScheme"=dword:00000000 + * + * AutoScheme: ? + * CurrentInstrument: name of midiOut device to use when UseScheme is 0. Wine uses an extension + * of the form #n to link to n'th midiOut device of the system + * CurrentScheme: when UseScheme is non null, it's the scheme to use (see below) + * DriverList: ? + * UseScheme: trigger for simple/complex mapping + * + * A scheme is defined (in HKLM) as: + * + * [System\\CurrentControlSet\\Control\\MediaProperties\\PrivateProperties\\Midi\\Schemes\\<nameScheme>] + * <nameScheme>: one key for each defined scheme (system wide) + * under each one of these <nameScheme> keys, there's: + * [...\\<nameScheme>\\<idxDevice>] + * "Channels"="<bitMask>" + * (the default value of this key also refers to the name of the device). + * + * this defines, for each midiOut device (identified by its index in <idxDevice>), which + * channels have to be mapped onto it. The <bitMask> defines the channels (from 0 to 15) + * will be mapped (mapping occurs for channel <ch> if bit <ch> is set in <bitMask> + * + * Further mapping information can also be defined in: + * [System\\CurrentControlSet\\Control\\MediaProperties\\PrivateProperties\\Midi\\Ports\\<nameDevice>\\Instruments\\<idx>] + * "Definition"="<.idf file>" + * "FriendlyName"="#for .idx file#" + * "Port"="<idxPort>" + * + * This last part isn't implemented (.idf file support). + */ + +WINE_DEFAULT_DEBUG_CHANNEL(msacm); + +typedef struct tagMIDIOUTPORT +{ + WCHAR name[MAXPNAMELEN]; + int loaded; + HMIDIOUT hMidi; + unsigned short uDevID; + LPBYTE lpbPatch; + unsigned int aChn[16]; +} MIDIOUTPORT; + +typedef struct tagMIDIMAPDATA +{ + struct tagMIDIMAPDATA* self; + MIDIOUTPORT* ChannelMap[16]; +} MIDIMAPDATA; + +static MIDIOUTPORT* midiOutPorts; +static unsigned numMidiOutPorts; + +static BOOL MIDIMAP_IsBadData(MIDIMAPDATA* mm) +{ + if (!IsBadReadPtr(mm, sizeof(MIDIMAPDATA)) && mm->self == mm) + return FALSE; + TRACE("Bad midimap data (%p)\n", mm); + return TRUE; +} + +static BOOL MIDIMAP_FindPort(const WCHAR* name, unsigned* dev) +{ + for (*dev = 0; *dev < numMidiOutPorts; (*dev)++) + { + TRACE("%s\n", wine_dbgstr_w(midiOutPorts[*dev].name)); + if (strcmpW(midiOutPorts[*dev].name, name) == 0) + return TRUE; + } + /* try the form #nnn */ + if (*name == '#' && isdigit(name[1])) + { + const WCHAR* ptr = name + 1; + *dev = 0; + do + { + *dev = *dev * 10 + *ptr - '0'; + } while (isdigit(*++ptr)); + if (*dev < numMidiOutPorts) + return TRUE; + } + return FALSE; +} + +static BOOL MIDIMAP_LoadSettingsDefault(MIDIMAPDATA* mom, const WCHAR* port) +{ + unsigned i, dev = 0; + + if (port != NULL && !MIDIMAP_FindPort(port, &dev)) + { + ERR("Registry glitch: couldn't find midi out (%s)\n", wine_dbgstr_w(port)); + dev = 0; + } + + /* this is necessary when no midi out ports are present */ + if (dev >= numMidiOutPorts) + return FALSE; + /* sets default */ + for (i = 0; i < 16; i++) mom->ChannelMap[i] = &midiOutPorts[dev]; + + return TRUE; +} + +static BOOL MIDIMAP_LoadSettingsScheme(MIDIMAPDATA* mom, const WCHAR* scheme) +{ + HKEY hSchemesKey, hKey, hPortKey; + unsigned i, idx, dev; + WCHAR buffer[256], port[256]; + DWORD type, size, mask; + + for (i = 0; i < 16; i++) mom->ChannelMap[i] = NULL; + + if (RegOpenKeyA(HKEY_LOCAL_MACHINE, + "System\\CurrentControlSet\\Control\\MediaProperties\\PrivateProperties\\Midi\\Schemes", + &hSchemesKey)) + { + return FALSE; + } + if (RegOpenKeyW(hSchemesKey, scheme, &hKey)) + { + RegCloseKey(hSchemesKey); + return FALSE; + } + + for (idx = 0; !RegEnumKeyW(hKey, idx, buffer, sizeof(buffer)); idx++) + { + if (RegOpenKeyW(hKey, buffer, &hPortKey)) continue; + + size = sizeof(port); + if (RegQueryValueExW(hPortKey, NULL, 0, &type, (void*)port, &size)) continue; + + if (!MIDIMAP_FindPort(port, &dev)) continue; + + size = sizeof(mask); + if (RegQueryValueExA(hPortKey, "Channels", 0, &type, (void*)&mask, &size)) + continue; + + for (i = 0; i < 16; i++) + { + if (mask & (1 << i)) + { + if (mom->ChannelMap[i]) + ERR("Quirks in registry, channel %u is mapped twice\n", i); + mom->ChannelMap[i] = &midiOutPorts[dev]; + } + } + } + + RegCloseKey(hSchemesKey); + RegCloseKey(hKey); + + return TRUE; +} + +static BOOL MIDIMAP_LoadSettings(MIDIMAPDATA* mom) +{ + HKEY hKey; + BOOL ret; + + if (RegOpenKeyA(HKEY_CURRENT_USER, + "Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia\\MIDIMap", &hKey)) + { + ret = MIDIMAP_LoadSettingsDefault(mom, NULL); + } + else + { + DWORD type, size, out; + WCHAR buffer[256]; + + ret = 2; + size = sizeof(out); + if (!RegQueryValueExA(hKey, "UseScheme", 0, &type, (void*)&out, &size) && out) + { + static const WCHAR cs[] = {'C','u','r','r','e','n','t','S','c','h','e','m','e',0}; + size = sizeof(buffer); + if (!RegQueryValueExW(hKey, cs, 0, &type, (void*)buffer, &size)) + { + if (!(ret = MIDIMAP_LoadSettingsScheme(mom, buffer))) + ret = MIDIMAP_LoadSettingsDefault(mom, NULL); + } + else + { + ERR("Wrong registry: UseScheme is active, but no CurrentScheme found\n"); + } + } + if (ret == 2) + { + static const WCHAR ci[] = {'C','u','r','r','e','n','t','I','n','s','t','r','u','m','e','n','t',0}; + size = sizeof(buffer); + if (!RegQueryValueExW(hKey, ci, 0, &type, (void*)buffer, &size) && *buffer) + { + ret = MIDIMAP_LoadSettingsDefault(mom, buffer); + } + else + { + ret = MIDIMAP_LoadSettingsDefault(mom, NULL); + } + } + } + RegCloseKey(hKey); + + if (ret && TRACE_ON(msacm)) + { + unsigned i; + + for (i = 0; i < 16; i++) + { + TRACE("chnMap[%2d] => %d\n", + i, mom->ChannelMap[i] ? mom->ChannelMap[i]->uDevID : -1); + } + } + return ret; +} + +static DWORD modOpen(LPDWORD lpdwUser, LPMIDIOPENDESC lpDesc, DWORD dwFlags) +{ + MIDIMAPDATA* mom = HeapAlloc(GetProcessHeap(), 0, sizeof(MIDIMAPDATA)); + + TRACE("(%p %p %08lx)\n", lpdwUser, lpDesc, dwFlags); + + if (!mom) return MMSYSERR_NOMEM; + + if (MIDIMAP_LoadSettings(mom)) + { + *lpdwUser = (DWORD)mom; + mom->self = mom; + + return MMSYSERR_NOERROR; + } + HeapFree(GetProcessHeap(), 0, mom); + return MIDIERR_INVALIDSETUP; +} + +static DWORD modClose(MIDIMAPDATA* mom) +{ + UINT i; + DWORD ret = MMSYSERR_NOERROR; + + if (MIDIMAP_IsBadData(mom)) return MMSYSERR_ERROR; + + for (i = 0; i < 16; i++) + { + DWORD t; + if (mom->ChannelMap[i] && mom->ChannelMap[i]->loaded > 0) + { + t = midiOutClose(mom->ChannelMap[i]->hMidi); + if (t == MMSYSERR_NOERROR) + { + mom->ChannelMap[i]->loaded = 0; + mom->ChannelMap[i]->hMidi = 0; + } + else if (ret == MMSYSERR_NOERROR) + ret = t; + } + } + if (ret == MMSYSERR_NOERROR) + HeapFree(GetProcessHeap(), 0, mom); + return ret; +} + +static DWORD modLongData(MIDIMAPDATA* mom, LPMIDIHDR lpMidiHdr, DWORD dwParam2) +{ + WORD chn; + DWORD ret = MMSYSERR_NOERROR; + MIDIHDR mh; + + if (MIDIMAP_IsBadData(mom)) + return MMSYSERR_ERROR; + + mh = *lpMidiHdr; + for (chn = 0; chn < 16; chn++) + { + if (mom->ChannelMap[chn] && mom->ChannelMap[chn]->loaded > 0) + { + mh.dwFlags = 0; + midiOutPrepareHeader(mom->ChannelMap[chn]->hMidi, &mh, sizeof(mh)); + ret = midiOutLongMsg(mom->ChannelMap[chn]->hMidi, &mh, sizeof(mh)); + midiOutUnprepareHeader(mom->ChannelMap[chn]->hMidi, &mh, sizeof(mh)); + if (ret != MMSYSERR_NOERROR) break; + } + } + return ret; +} + +static DWORD modData(MIDIMAPDATA* mom, DWORD dwParam) +{ + BYTE lb = LOBYTE(LOWORD(dwParam)); + WORD chn = lb & 0x0F; + DWORD ret = MMSYSERR_NOERROR; + + if (MIDIMAP_IsBadData(mom)) + return MMSYSERR_ERROR; + + if (!mom->ChannelMap[chn]) return MMSYSERR_NOERROR; + + switch (lb & 0xF0) + { + case 0x80: + case 0x90: + case 0xA0: + case 0xB0: + case 0xC0: + case 0xD0: + case 0xE0: + if (mom->ChannelMap[chn]->loaded == 0) + { + if (midiOutOpen(&mom->ChannelMap[chn]->hMidi, mom->ChannelMap[chn]->uDevID, + 0L, 0L, CALLBACK_NULL) == MMSYSERR_NOERROR) + mom->ChannelMap[chn]->loaded = 1; + else + mom->ChannelMap[chn]->loaded = -1; + /* FIXME: should load here the IDF midi data... and allow channel and + * patch mappings + */ + } + if (mom->ChannelMap[chn]->loaded > 0) + { + /* change channel */ + dwParam &= ~0x0F; + dwParam |= mom->ChannelMap[chn]->aChn[chn]; + + if ((LOBYTE(LOWORD(dwParam)) & 0xF0) == 0xC0 /* program change */ && + mom->ChannelMap[chn]->lpbPatch) + { + BYTE patch = HIBYTE(LOWORD(dwParam)); + + /* change patch */ + dwParam &= ~0x0000FF00; + dwParam |= mom->ChannelMap[chn]->lpbPatch[patch]; + } + ret = midiOutShortMsg(mom->ChannelMap[chn]->hMidi, dwParam); + } + break; + case 0xF0: + for (chn = 0; chn < 16; chn++) + { + if (mom->ChannelMap[chn]->loaded > 0) + ret = midiOutShortMsg(mom->ChannelMap[chn]->hMidi, dwParam); + } + break; + default: + FIXME("ooch %lu\n", dwParam); + } + + return ret; +} + +static DWORD modPrepare(MIDIMAPDATA* mom, LPMIDIHDR lpMidiHdr, DWORD dwParam2) +{ + if (MIDIMAP_IsBadData(mom)) return MMSYSERR_ERROR; + if (lpMidiHdr->dwFlags & (MHDR_ISSTRM|MHDR_PREPARED)) + return MMSYSERR_INVALPARAM; + + lpMidiHdr->dwFlags |= MHDR_PREPARED; + return MMSYSERR_NOERROR; +} + +static DWORD modUnprepare(MIDIMAPDATA* mom, LPMIDIHDR lpMidiHdr, DWORD dwParam2) +{ + if (MIDIMAP_IsBadData(mom)) return MMSYSERR_ERROR; + if ((lpMidiHdr->dwFlags & MHDR_ISSTRM) || !(lpMidiHdr->dwFlags & MHDR_PREPARED)) + return MMSYSERR_INVALPARAM; + + lpMidiHdr->dwFlags &= ~MHDR_PREPARED; + return MMSYSERR_NOERROR; +} + +static DWORD modGetDevCaps(UINT wDevID, MIDIMAPDATA* mom, LPMIDIOUTCAPSW lpMidiCaps, DWORD size) +{ + static const WCHAR name[] = {'W','i','n','e',' ','m','i','d','i',' ','m','a','p','p','e','r',0}; + lpMidiCaps->wMid = 0x00FF; + lpMidiCaps->wPid = 0x0001; + lpMidiCaps->vDriverVersion = 0x0100; + lstrcpyW(lpMidiCaps->szPname, name); + lpMidiCaps->wTechnology = MOD_MAPPER; + lpMidiCaps->wVoices = 0; + lpMidiCaps->wNotes = 0; + lpMidiCaps->wChannelMask = 0xFFFF; + lpMidiCaps->dwSupport = 0L; + + return MMSYSERR_NOERROR; +} + +static DWORD modReset(MIDIMAPDATA* mom) +{ + WORD chn; + DWORD ret = MMSYSERR_NOERROR; + + if (MIDIMAP_IsBadData(mom)) + return MMSYSERR_ERROR; + + for (chn = 0; chn < 16; chn++) + { + if (mom->ChannelMap[chn] && mom->ChannelMap[chn]->loaded > 0) + { + ret = midiOutReset(mom->ChannelMap[chn]->hMidi); + if (ret != MMSYSERR_NOERROR) break; + } + } + return ret; +} + +/************************************************************************** + * modMessage (MIDIMAP.@) + */ +DWORD WINAPI MIDIMAP_modMessage(UINT wDevID, UINT wMsg, DWORD dwUser, + DWORD dwParam1, DWORD dwParam2) +{ + TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n", + wDevID, wMsg, dwUser, dwParam1, dwParam2); + + switch (wMsg) + { + case DRVM_INIT: + case DRVM_EXIT: + case DRVM_ENABLE: + case DRVM_DISABLE: + /* FIXME: Pretend this is supported */ + return 0; + + case MODM_OPEN: return modOpen ((LPDWORD)dwUser, (LPMIDIOPENDESC)dwParam1,dwParam2); + case MODM_CLOSE: return modClose ((MIDIMAPDATA*)dwUser); + + case MODM_DATA: return modData ((MIDIMAPDATA*)dwUser, dwParam1); + case MODM_LONGDATA: return modLongData ((MIDIMAPDATA*)dwUser, (LPMIDIHDR)dwParam1, dwParam2); + case MODM_PREPARE: return modPrepare ((MIDIMAPDATA*)dwUser, (LPMIDIHDR)dwParam1, dwParam2); + case MODM_UNPREPARE: return modUnprepare ((MIDIMAPDATA*)dwUser, (LPMIDIHDR)dwParam1, dwParam2); + case MODM_RESET: return modReset ((MIDIMAPDATA*)dwUser); + + case MODM_GETDEVCAPS: return modGetDevCaps (wDevID, (MIDIMAPDATA*)dwUser, (LPMIDIOUTCAPSW)dwParam1,dwParam2); + case MODM_GETNUMDEVS: return 1; + case MODM_GETVOLUME: return MMSYSERR_NOTSUPPORTED; + case MODM_SETVOLUME: return MMSYSERR_NOTSUPPORTED; + default: + FIXME("unknown message %d!\n", wMsg); + } + return MMSYSERR_NOTSUPPORTED; +} + +/*======================================================================* + * Driver part * + *======================================================================*/ + +/************************************************************************** + * MIDIMAP_drvOpen [internal] + */ +static DWORD MIDIMAP_drvOpen(LPSTR str) +{ + MIDIOUTCAPSW moc; + unsigned dev, i; + + if (midiOutPorts) + return 0; + + numMidiOutPorts = midiOutGetNumDevs(); + midiOutPorts = HeapAlloc(GetProcessHeap(), 0, + numMidiOutPorts * sizeof(MIDIOUTPORT)); + for (dev = 0; dev < numMidiOutPorts; dev++) + { + if (midiOutGetDevCapsW(dev, &moc, sizeof(moc)) == 0L) + { + strcpyW(midiOutPorts[dev].name, moc.szPname); + midiOutPorts[dev].loaded = 0; + midiOutPorts[dev].hMidi = 0; + midiOutPorts[dev].uDevID = dev; + midiOutPorts[dev].lpbPatch = NULL; + for (i = 0; i < 16; i++) + midiOutPorts[dev].aChn[i] = i; + } + else + { + midiOutPorts[dev].loaded = -1; + } + } + + return 1; +} + +/************************************************************************** + * MIDIMAP_drvClose [internal] + */ +static DWORD MIDIMAP_drvClose(DWORD dwDevID) +{ + if (midiOutPorts) + { + HeapFree(GetProcessHeap(), 0, midiOutPorts); + midiOutPorts = NULL; + return 1; + } + return 0; +} + +/************************************************************************** + * DriverProc (MIDIMAP.@) + */ +LONG CALLBACK MIDIMAP_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, + DWORD dwParam1, DWORD dwParam2) +{ +/* EPP TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n", */ +/* EPP dwDevID, hDriv, wMsg, dwParam1, dwParam2); */ + + switch (wMsg) + { + case DRV_LOAD: return 1; + case DRV_FREE: return 1; + case DRV_OPEN: return MIDIMAP_drvOpen((LPSTR)dwParam1); + case DRV_CLOSE: return MIDIMAP_drvClose(dwDevID); + case DRV_ENABLE: return 1; + case DRV_DISABLE: return 1; + case DRV_QUERYCONFIGURE: return 1; + case DRV_CONFIGURE: MessageBoxA(0, "MIDIMAP MultiMedia Driver !", "OSS Driver", MB_OK); return 1; + case DRV_INSTALL: return DRVCNF_RESTART; + case DRV_REMOVE: return DRVCNF_RESTART; + default: + return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2); + } +} diff --git a/reactos/lib/winmm/mmio.c b/reactos/lib/winmm/mmio.c index ab136490b1b..8cf05e99528 100644 --- a/reactos/lib/winmm/mmio.c +++ b/reactos/lib/winmm/mmio.c @@ -1,1387 +1,1387 @@ -/* - * MMIO functions - * - * Copyright 1998 Andrew Taylor - * Copyright 1998 Ove KÃ¥ven - * Copyright 2000,2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* Still to be done: - * + correct handling of global/local IOProcs (and temporary IOProcs) - * + mode of mmio objects is not used (read vs write vs readwrite) - * + thread safeness - * + 32 A <=> W message mapping - */ - - -#include <ctype.h> -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <assert.h> - -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "mmsystem.h" -#include "winemm.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mmio); - -LRESULT (*pFnMmioCallback16)(DWORD,LPMMIOINFO,UINT,LPARAM,LPARAM) /* = NULL */; - -/************************************************************************** - * mmioDosIOProc [internal] - */ -static LRESULT CALLBACK mmioDosIOProc(LPMMIOINFO lpmmioinfo, UINT uMessage, - LPARAM lParam1, LPARAM lParam2) -{ - LRESULT ret = MMSYSERR_NOERROR; - - TRACE("(%p, %X, 0x%lx, 0x%lx);\n", lpmmioinfo, uMessage, lParam1, lParam2); - - switch (uMessage) { - case MMIOM_OPEN: - { - /* Parameters: - * lParam1 = szFileName parameter from mmioOpen - * lParam2 = reserved - * Returns: zero on success, error code on error - * NOTE: lDiskOffset automatically set to zero - */ - LPCSTR szFileName = (LPCSTR)lParam1; - - if (lpmmioinfo->dwFlags & MMIO_GETTEMP) { - FIXME("MMIO_GETTEMP not implemented\n"); - return MMIOERR_CANNOTOPEN; - } - - /* if filename NULL, assume open file handle in adwInfo[0] */ - if (szFileName) { - OFSTRUCT ofs; - lpmmioinfo->adwInfo[0] = (DWORD)OpenFile(szFileName, &ofs, lpmmioinfo->dwFlags & 0xFFFF); - } - if (lpmmioinfo->adwInfo[0] == (DWORD)HFILE_ERROR) - ret = MMIOERR_CANNOTOPEN; - } - break; - - case MMIOM_CLOSE: - /* Parameters: - * lParam1 = wFlags parameter from mmioClose - * lParam2 = unused - * Returns: zero on success, error code on error - */ - if (!(lParam1 & MMIO_FHOPEN)) - _lclose((HFILE)lpmmioinfo->adwInfo[0]); - break; - - case MMIOM_READ: - /* Parameters: - * lParam1 = huge pointer to read buffer - * lParam2 = number of bytes to read - * Returns: number of bytes read, 0 for EOF, -1 for error (error code - * in wErrorRet) - */ - ret = _lread((HFILE)lpmmioinfo->adwInfo[0], (HPSTR)lParam1, (LONG)lParam2); - if (ret != -1) - lpmmioinfo->lDiskOffset += ret; - - break; - - case MMIOM_WRITE: - case MMIOM_WRITEFLUSH: - /* no internal buffering, so WRITEFLUSH handled same as WRITE */ - - /* Parameters: - * lParam1 = huge pointer to write buffer - * lParam2 = number of bytes to write - * Returns: number of bytes written, -1 for error (error code in - * wErrorRet) - */ - ret = _hwrite((HFILE)lpmmioinfo->adwInfo[0], (HPSTR)lParam1, (LONG)lParam2); - if (ret != -1) - lpmmioinfo->lDiskOffset += ret; - break; - - case MMIOM_SEEK: - /* Parameters: - * lParam1 = new position - * lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END) - * Returns: new file postion, -1 on error - */ - ret = _llseek((HFILE)lpmmioinfo->adwInfo[0], (LONG)lParam1, (LONG)lParam2); - if (ret != -1) - lpmmioinfo->lDiskOffset = ret; - return ret; - - case MMIOM_RENAME: - /* Parameters: - * lParam1 = old name - * lParam2 = new name - * Returns: zero on success, non-zero on failure - */ - if (!MoveFileA((const char*)lParam1, (const char*)lParam2)) - ret = MMIOERR_FILENOTFOUND; - break; - - default: - FIXME("unexpected message %u\n", uMessage); - return 0; - } - - return ret; -} - -/************************************************************************** - * mmioMemIOProc [internal] - */ -static LRESULT CALLBACK mmioMemIOProc(LPMMIOINFO lpmmioinfo, UINT uMessage, - LPARAM lParam1, LPARAM lParam2) -{ - TRACE("(%p,0x%04x,0x%08lx,0x%08lx)\n", lpmmioinfo, uMessage, lParam1, lParam2); - - switch (uMessage) { - - case MMIOM_OPEN: - /* Parameters: - * lParam1 = filename (must be NULL) - * lParam2 = reserved - * Returns: zero on success, error code on error - * NOTE: lDiskOffset automatically set to zero - */ - /* FIXME: io proc shouldn't change it */ - if (!(lpmmioinfo->dwFlags & MMIO_CREATE)) - lpmmioinfo->pchEndRead = lpmmioinfo->pchEndWrite; - lpmmioinfo->adwInfo[0] = HFILE_ERROR; - return 0; - - case MMIOM_CLOSE: - /* Parameters: - * lParam1 = wFlags parameter from mmioClose - * lParam2 = unused - * Returns: zero on success, error code on error - */ - return 0; - - case MMIOM_READ: - /* Parameters: - * lParam1 = huge pointer to read buffer - * lParam2 = number of bytes to read - * Returns: number of bytes read, 0 for EOF, -1 for error (error code - * in wErrorRet) - * NOTE: lDiskOffset should be updated - */ - FIXME("MMIOM_READ on memory files should not occur, buffer may be lost!\n"); - return 0; - - case MMIOM_WRITE: - case MMIOM_WRITEFLUSH: - /* no internal buffering, so WRITEFLUSH handled same as WRITE */ - - /* Parameters: - * lParam1 = huge pointer to write buffer - * lParam2 = number of bytes to write - * Returns: number of bytes written, -1 for error (error code in - * wErrorRet) - * NOTE: lDiskOffset should be updated - */ - FIXME("MMIOM_WRITE on memory files should not occur, buffer may be lost!\n"); - return 0; - - case MMIOM_SEEK: - /* Parameters: - * lParam1 = new position - * lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END) - * Returns: new file postion, -1 on error - * NOTE: lDiskOffset should be updated - */ - FIXME("MMIOM_SEEK on memory files should not occur, buffer may be lost!\n"); - return -1; - - default: - FIXME("unexpected message %u\n", uMessage); - return 0; - } -} - -/* This array will be the entire list for most apps - * Note that temporary ioProcs will be stored with a 0 fourCC code - */ - -static struct IOProcList defaultProcs[] = { - {&defaultProcs[1], FOURCC_DOS, (LPMMIOPROC)mmioDosIOProc, MMIO_PROC_32A, 0}, - {NULL, FOURCC_MEM, (LPMMIOPROC)mmioMemIOProc, MMIO_PROC_32A, 0}, -}; - -static struct IOProcList* pIOProcListAnchor = &defaultProcs[0]; - -/**************************************************************** - * MMIO_FindProcNode [INTERNAL] - * - * Finds the ProcList node associated with a given FOURCC code. - */ -static struct IOProcList* MMIO_FindProcNode(FOURCC fccIOProc) -{ - struct IOProcList* pListNode; - - for (pListNode = pIOProcListAnchor; pListNode; pListNode = pListNode->pNext) { - if (pListNode->fourCC == fccIOProc) { - return pListNode; - } - } - return NULL; -} - -/**************************************************************** - * MMIO_InstallIOProc [INTERNAL] - */ -LPMMIOPROC MMIO_InstallIOProc(FOURCC fccIOProc, LPMMIOPROC pIOProc, - DWORD dwFlags, enum mmioProcType type) -{ - LPMMIOPROC lpProc = NULL; - struct IOProcList* pListNode; - struct IOProcList** ppListNode; - - TRACE("(%08lx, %p, %08lX, %i)\n", fccIOProc, pIOProc, dwFlags, type); - - if (dwFlags & MMIO_GLOBALPROC) - FIXME("Global procedures not implemented\n"); - - /* just handle the known procedures for now */ - switch (dwFlags & (MMIO_INSTALLPROC|MMIO_REMOVEPROC|MMIO_FINDPROC)) { - case MMIO_INSTALLPROC: - /* Create new entry for the IOProc list */ - pListNode = HeapAlloc(GetProcessHeap(), 0, sizeof(*pListNode)); - if (pListNode) { - /* Fill in this node */ - pListNode->fourCC = fccIOProc; - pListNode->pIOProc = pIOProc; - pListNode->type = type; - pListNode->count = 0; - - /* Stick it on the end of the list */ - pListNode->pNext = pIOProcListAnchor; - pIOProcListAnchor = pListNode; - - /* Return this IOProc - that's how the caller knows we succeeded */ - lpProc = pIOProc; - } - break; - - case MMIO_REMOVEPROC: - /* - * Search for the node that we're trying to remove - * We search for a matching fourCC code if it's non null, or the proc - * address otherwise - * note that this method won't find the first item on the list, but - * since the first two items on this list are ones we won't - * let the user delete anyway, that's okay - */ - ppListNode = &pIOProcListAnchor; - while ((*ppListNode) && - ((fccIOProc != 0) ? - (*ppListNode)->fourCC != fccIOProc : - (*ppListNode)->pIOProc != pIOProc)) - ppListNode = &((*ppListNode)->pNext); - - if (*ppListNode) { /* found it */ - /* FIXME: what should be done if an open mmio object uses this proc ? - * shall we return an error, nuke the mmio object ? - */ - if ((*ppListNode)->count) { - ERR("Cannot remove a mmIOProc while in use\n"); - break; - } - /* remove it, but only if it isn't builtin */ - if ((*ppListNode) >= defaultProcs && - (*ppListNode) < defaultProcs + sizeof(defaultProcs)) { - WARN("Tried to remove built-in mmio proc. Skipping\n"); - } else { - /* Okay, nuke it */ - struct IOProcList* ptmpNode = *ppListNode; - lpProc = (*ppListNode)->pIOProc; - *ppListNode = (*ppListNode)->pNext; - HeapFree(GetProcessHeap(), 0, ptmpNode); - } - } - break; - - case MMIO_FINDPROC: - if ((pListNode = MMIO_FindProcNode(fccIOProc))) { - lpProc = pListNode->pIOProc; - } - break; - } - - return lpProc; -} - -/**************************************************************** - * send_message [INTERNAL] - */ -static LRESULT send_message(struct IOProcList* ioProc, LPMMIOINFO mmioinfo, - DWORD wMsg, LPARAM lParam1, - LPARAM lParam2, enum mmioProcType type) -{ - LRESULT result = MMSYSERR_ERROR; - LPARAM lp1 = lParam1, lp2 = lParam2; - - if (!ioProc) { - ERR("brrr\n"); - result = MMSYSERR_INVALPARAM; - } - - switch (ioProc->type) { - case MMIO_PROC_16: - if (pFnMmioCallback16) - result = pFnMmioCallback16((DWORD)ioProc->pIOProc, - mmioinfo, wMsg, lp1, lp2); - break; - case MMIO_PROC_32A: - case MMIO_PROC_32W: - if (ioProc->type != type) { - /* map (lParam1, lParam2) into (lp1, lp2) 32 A<=>W */ - FIXME("NIY 32 A<=>W mapping\n"); - } - result = (ioProc->pIOProc)((LPSTR)mmioinfo, wMsg, lp1, lp2); - -#if 0 - if (ioProc->type != type) { - /* unmap (lParam1, lParam2) into (lp1, lp2) 32 A<=>W */ - } -#endif - break; - default: - FIXME("Internal error\n"); - } - - return result; -} - -/************************************************************************** - * MMIO_ParseExtA [internal] - * - * Parses a filename for the extension. - * - * RETURNS - * The FOURCC code for the extension if found, else 0. - */ -static FOURCC MMIO_ParseExtA(LPCSTR szFileName) -{ - /* Filenames are of the form file.ext{+ABC} - For now, we take the last '+' if present */ - - FOURCC ret = 0; - - /* Note that ext{Start,End} point to the . and + respectively */ - LPSTR extEnd; - LPSTR extStart; - - TRACE("(%s)\n", debugstr_a(szFileName)); - - if (!szFileName) - return ret; - - /* Find the last '.' */ - extStart = strrchr(szFileName,'.'); - - if (!extStart) { - ERR("No . in szFileName: %s\n", debugstr_a(szFileName)); - } else { - CHAR ext[5]; - - /* Find the '+' afterwards */ - extEnd = strchr(extStart,'+'); - if (extEnd) { - - if (extEnd - extStart - 1 > 4) - WARN("Extension length > 4\n"); - lstrcpynA(ext, extStart + 1, min(extEnd-extStart,5)); - - } else { - /* No + so just an extension */ - if (strlen(extStart) > 4) { - WARN("Extension length > 4\n"); - } - lstrcpynA(ext, extStart + 1, 5); - } - TRACE("Got extension: %s\n", debugstr_a(ext)); - - /* FOURCC codes identifying file-extensions must be uppercase */ - ret = mmioStringToFOURCCA(ext, MMIO_TOUPPER); - } - return ret; -} - -/************************************************************************** - * MMIO_Get [internal] - * - * Retrieves the mmio object from current process - */ -LPWINE_MMIO MMIO_Get(HMMIO h) -{ - LPWINE_MMIO wm = NULL; - - EnterCriticalSection(&WINMM_IData.cs); - for (wm = WINMM_IData.lpMMIO; wm; wm = wm->lpNext) { - if (wm->info.hmmio == h) - break; - } - LeaveCriticalSection(&WINMM_IData.cs); - return wm; -} - -/************************************************************************** - * MMIO_Create [internal] - * - * Creates an internal representation for a mmio instance - */ -static LPWINE_MMIO MMIO_Create(void) -{ - static WORD MMIO_counter = 0; - LPWINE_MMIO wm; - - wm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MMIO)); - if (wm) { - EnterCriticalSection(&WINMM_IData.cs); - /* lookup next unallocated WORD handle, with a non NULL value */ - while (++MMIO_counter == 0 || MMIO_Get((HMMIO)(ULONG_PTR)MMIO_counter)); - wm->info.hmmio = (HMMIO)(ULONG_PTR)MMIO_counter; - wm->lpNext = WINMM_IData.lpMMIO; - WINMM_IData.lpMMIO = wm; - LeaveCriticalSection(&WINMM_IData.cs); - } - return wm; -} - -/************************************************************************** - * MMIO_Destroy [internal] - *- - * Destroys an internal representation for a mmio instance - */ -static BOOL MMIO_Destroy(LPWINE_MMIO wm) -{ - LPWINE_MMIO* m; - - EnterCriticalSection(&WINMM_IData.cs); - /* search for the matching one... */ - m = &(WINMM_IData.lpMMIO); - while (*m && *m != wm) m = &(*m)->lpNext; - /* ...and destroy */ - if (*m) { - *m = (*m)->lpNext; - HeapFree(GetProcessHeap(), 0, wm); - wm = NULL; - } - LeaveCriticalSection(&WINMM_IData.cs); - return wm ? FALSE : TRUE; -} - -/**************************************************************** - * MMIO_Flush [INTERNAL] - */ -static MMRESULT MMIO_Flush(WINE_MMIO* wm, UINT uFlags) -{ - if (wm->info.cchBuffer && (wm->info.fccIOProc != FOURCC_MEM)) { - /* not quite sure what to do here, but I'll guess */ - if (wm->info.dwFlags & MMIO_DIRTY) { - /* FIXME: error handling */ - send_message(wm->ioProc, &wm->info, MMIOM_SEEK, - wm->info.lBufOffset, SEEK_SET, MMIO_PROC_32A); - send_message(wm->ioProc, &wm->info, MMIOM_WRITE, - (LPARAM)wm->info.pchBuffer, - wm->info.pchNext - wm->info.pchBuffer, MMIO_PROC_32A); - } - if (uFlags & MMIO_EMPTYBUF) - wm->info.pchNext = wm->info.pchEndRead = wm->info.pchBuffer; - } - wm->info.dwFlags &= ~MMIO_DIRTY; - - return MMSYSERR_NOERROR; -} - -/*************************************************************************** - * MMIO_GrabNextBuffer [INTERNAL] - */ -static LONG MMIO_GrabNextBuffer(LPWINE_MMIO wm, int for_read) -{ - LONG size = wm->info.cchBuffer; - - TRACE("bo=%lx do=%lx of=%lx\n", - wm->info.lBufOffset, wm->info.lDiskOffset, - send_message(wm->ioProc, &wm->info, MMIOM_SEEK, 0, SEEK_CUR, MMIO_PROC_32A)); - - wm->info.lBufOffset = wm->info.lDiskOffset; - wm->info.pchNext = wm->info.pchBuffer; - wm->info.pchEndRead = wm->info.pchBuffer; - wm->info.pchEndWrite = wm->info.pchBuffer + wm->info.cchBuffer; - - wm->bBufferLoaded = TRUE; - if (for_read) { - size = send_message(wm->ioProc, &wm->info, MMIOM_READ, - (LPARAM)wm->info.pchBuffer, size, MMIO_PROC_32A); - if (size > 0) - wm->info.pchEndRead += size; - else - wm->bBufferLoaded = FALSE; - } - - return size; -} - -/*************************************************************************** - * MMIO_SetBuffer [INTERNAL] - */ -static MMRESULT MMIO_SetBuffer(WINE_MMIO* wm, void* pchBuffer, LONG cchBuffer, - UINT uFlags) -{ - TRACE("(%p %p %ld %u)\n", wm, pchBuffer, cchBuffer, uFlags); - - if (uFlags) return MMSYSERR_INVALPARAM; - if (cchBuffer > 0xFFFF) - WARN("Untested handling of huge mmio buffers (%ld >= 64k)\n", cchBuffer); - - if (MMIO_Flush(wm, 0) != MMSYSERR_NOERROR) - return MMIOERR_CANNOTWRITE; - - /* free previous buffer if allocated */ - if (wm->info.dwFlags & MMIO_ALLOCBUF) { - HeapFree(GetProcessHeap(), 0, wm->info.pchBuffer); - wm->info.pchBuffer = NULL; - wm->info.dwFlags &= ~MMIO_ALLOCBUF; - } - - if (pchBuffer) { - wm->info.pchBuffer = pchBuffer; - } else if (cchBuffer) { - if (!(wm->info.pchBuffer = HeapAlloc(GetProcessHeap(), 0, cchBuffer))) - return MMIOERR_OUTOFMEMORY; - wm->info.dwFlags |= MMIO_ALLOCBUF; - } else { - wm->info.pchBuffer = NULL; - } - - wm->info.cchBuffer = cchBuffer; - wm->info.pchNext = wm->info.pchBuffer; - wm->info.pchEndRead = wm->info.pchBuffer; - wm->info.pchEndWrite = wm->info.pchBuffer + cchBuffer; - wm->info.lBufOffset = 0; - wm->bBufferLoaded = FALSE; - - return MMSYSERR_NOERROR; -} - -/************************************************************************** - * MMIO_Open [internal] - */ -HMMIO MMIO_Open(LPSTR szFileName, MMIOINFO* refmminfo, DWORD dwOpenFlags, - enum mmioProcType type) -{ - LPWINE_MMIO wm; - MMIOINFO mmioinfo; - - TRACE("('%s', %p, %08lX, %d);\n", szFileName, refmminfo, dwOpenFlags, type); - - if (!refmminfo) { - refmminfo = &mmioinfo; - - mmioinfo.fccIOProc = 0; - mmioinfo.pIOProc = NULL; - mmioinfo.pchBuffer = NULL; - mmioinfo.cchBuffer = 0; - type = MMIO_PROC_32A; - } - - if (dwOpenFlags & (MMIO_PARSE|MMIO_EXIST)) { - char buffer[MAX_PATH]; - - if (GetFullPathNameA(szFileName, sizeof(buffer), buffer, NULL) >= sizeof(buffer)) - return (HMMIO)FALSE; - if ((dwOpenFlags & MMIO_EXIST) && (GetFileAttributesA(buffer) == INVALID_FILE_ATTRIBUTES)) - return (HMMIO)FALSE; - strcpy(szFileName, buffer); - return (HMMIO)TRUE; - } - - if ((wm = MMIO_Create()) == NULL) - return 0; - - /* If both params are NULL, then parse the file name if available */ - if (refmminfo->fccIOProc == 0 && refmminfo->pIOProc == NULL) { - wm->info.fccIOProc = MMIO_ParseExtA(szFileName); - /* Handle any unhandled/error case. Assume DOS file */ - if (wm->info.fccIOProc == 0) - wm->info.fccIOProc = FOURCC_DOS; - if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) { - /* If not found, retry with FOURCC_DOS */ - wm->info.fccIOProc = FOURCC_DOS; - if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) - goto error2; - } - wm->bTmpIOProc = FALSE; - } - /* if just the four character code is present, look up IO proc */ - else if (refmminfo->pIOProc == NULL) { - wm->info.fccIOProc = refmminfo->fccIOProc; - if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) goto error2; - wm->bTmpIOProc = FALSE; - } - /* if IO proc specified, use it and specified four character code */ - else { - wm->info.fccIOProc = refmminfo->fccIOProc; - MMIO_InstallIOProc(wm->info.fccIOProc, refmminfo->pIOProc, - MMIO_INSTALLPROC, type); - if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) goto error2; - assert(wm->ioProc->pIOProc == refmminfo->pIOProc); - wm->bTmpIOProc = TRUE; - } - - wm->bBufferLoaded = FALSE; - wm->ioProc->count++; - - if (dwOpenFlags & MMIO_ALLOCBUF) { - if ((refmminfo->wErrorRet = MMIO_SetBuffer(wm, NULL, MMIO_DEFAULTBUFFER, 0))) - goto error1; - } else if (wm->info.fccIOProc == FOURCC_MEM) { - refmminfo->wErrorRet = MMIO_SetBuffer(wm, refmminfo->pchBuffer, refmminfo->cchBuffer, 0); - if (refmminfo->wErrorRet != MMSYSERR_NOERROR) - goto error1; - wm->bBufferLoaded = TRUE; - } /* else => unbuffered, wm->info.pchBuffer == NULL */ - - /* see mmioDosIOProc for that one */ - wm->info.adwInfo[0] = refmminfo->adwInfo[0]; - wm->info.dwFlags = dwOpenFlags; - - /* call IO proc to actually open file */ - refmminfo->wErrorRet = send_message(wm->ioProc, &wm->info, MMIOM_OPEN, - (LPARAM)szFileName, 0, MMIO_PROC_32A); - - /* grab file size, when possible */ - wm->dwFileSize = GetFileSize((HANDLE)wm->info.adwInfo[0], NULL); - - if (refmminfo->wErrorRet == 0) - return wm->info.hmmio; - error1: - if (wm->ioProc) wm->ioProc->count--; - error2: - MMIO_Destroy(wm); - return 0; -} - -/************************************************************************** - * mmioOpenW [WINMM.@] - */ -HMMIO WINAPI mmioOpenW(LPWSTR szFileName, MMIOINFO* lpmmioinfo, - DWORD dwOpenFlags) -{ - HMMIO ret; - LPSTR szFn = NULL; - - if (szFileName) - { - INT len = WideCharToMultiByte( CP_ACP, 0, szFileName, -1, NULL, 0, NULL, NULL ); - szFn = HeapAlloc( GetProcessHeap(), 0, len ); - if (!szFn) return NULL; - WideCharToMultiByte( CP_ACP, 0, szFileName, -1, szFn, len, NULL, NULL ); - } - - ret = MMIO_Open(szFn, lpmmioinfo, dwOpenFlags, MMIO_PROC_32W); - - HeapFree(GetProcessHeap(), 0, szFn); - return ret; -} - -/************************************************************************** - * mmioOpenA [WINMM.@] - */ -HMMIO WINAPI mmioOpenA(LPSTR szFileName, MMIOINFO* lpmmioinfo, - DWORD dwOpenFlags) -{ - return MMIO_Open(szFileName, lpmmioinfo, dwOpenFlags, MMIO_PROC_32A); -} - -/************************************************************************** - * mmioClose [WINMM.@] - */ -MMRESULT WINAPI mmioClose(HMMIO hmmio, UINT uFlags) -{ - LPWINE_MMIO wm; - MMRESULT result; - - TRACE("(%p, %04X);\n", hmmio, uFlags); - - if ((wm = MMIO_Get(hmmio)) == NULL) - return MMSYSERR_INVALHANDLE; - - if ((result = MMIO_Flush(wm, 0)) != MMSYSERR_NOERROR) - return result; - - result = send_message(wm->ioProc, &wm->info, MMIOM_CLOSE, - uFlags, 0, MMIO_PROC_32A); - - MMIO_SetBuffer(wm, NULL, 0, 0); - - wm->ioProc->count--; - - if (wm->bTmpIOProc) - MMIO_InstallIOProc(wm->info.fccIOProc, wm->ioProc->pIOProc, - MMIO_REMOVEPROC, wm->ioProc->type); - - MMIO_Destroy(wm); - - return result; -} - -/************************************************************************** - * mmioRead [WINMM.@] - */ -LONG WINAPI mmioRead(HMMIO hmmio, HPSTR pch, LONG cch) -{ - LPWINE_MMIO wm; - LONG count; - - TRACE("(%p, %p, %ld);\n", hmmio, pch, cch); - - if ((wm = MMIO_Get(hmmio)) == NULL) - return -1; - - /* unbuffered case first */ - if (!wm->info.pchBuffer) - return send_message(wm->ioProc, &wm->info, MMIOM_READ, - (LPARAM)pch, cch, MMIO_PROC_32A); - - /* first try from current buffer */ - if (wm->info.pchNext != wm->info.pchEndRead) { - count = wm->info.pchEndRead - wm->info.pchNext; - if (count > cch || count < 0) count = cch; - memcpy(pch, wm->info.pchNext, count); - wm->info.pchNext += count; - pch += count; - cch -= count; - } else - count = 0; - - if (cch && (wm->info.fccIOProc != FOURCC_MEM)) { - assert(wm->info.cchBuffer); - - while (cch) { - LONG size; - - size = MMIO_GrabNextBuffer(wm, TRUE); - if (size <= 0) break; - if (size > cch) size = cch; - memcpy(pch, wm->info.pchBuffer, size); - wm->info.pchNext += size; - pch += size; - cch -= size; - count += size; - } - } - - TRACE("count=%ld\n", count); - return count; -} - -/************************************************************************** - * mmioWrite [WINMM.@] - */ -LONG WINAPI mmioWrite(HMMIO hmmio, HPCSTR pch, LONG cch) -{ - LPWINE_MMIO wm; - LONG count; - - TRACE("(%p, %p, %ld);\n", hmmio, pch, cch); - - if ((wm = MMIO_Get(hmmio)) == NULL) - return -1; - - if (wm->info.cchBuffer) { - LONG bytesW = 0; - - count = 0; - while (cch) { - if (wm->info.pchNext != wm->info.pchEndWrite) { - count = wm->info.pchEndWrite - wm->info.pchNext; - if (count > cch || count < 0) count = cch; - memcpy(wm->info.pchNext, pch, count); - wm->info.pchNext += count; - pch += count; - cch -= count; - bytesW += count; - wm->info.dwFlags |= MMIO_DIRTY; - } else { - if (wm->info.fccIOProc == FOURCC_MEM) { - if (wm->info.adwInfo[0]) { - /* from where would we get the memory handle? */ - FIXME("memory file expansion not implemented!\n"); - break; - } else break; - } - } - - if (wm->info.pchNext == wm->info.pchEndWrite) - { - MMIO_Flush(wm, MMIO_EMPTYBUF); - MMIO_GrabNextBuffer(wm, FALSE); - } - else break; - } - count = bytesW; - } else { - count = send_message(wm->ioProc, &wm->info, MMIOM_WRITE, - (LPARAM)pch, cch, MMIO_PROC_32A); - wm->info.lBufOffset = wm->info.lDiskOffset; - } - - TRACE("bytes written=%ld\n", count); - return count; -} - -/************************************************************************** - * mmioSeek [WINMM.@] - */ -LONG WINAPI mmioSeek(HMMIO hmmio, LONG lOffset, INT iOrigin) -{ - LPWINE_MMIO wm; - LONG offset; - - TRACE("(%p, %08lX, %d);\n", hmmio, lOffset, iOrigin); - - if ((wm = MMIO_Get(hmmio)) == NULL) - return MMSYSERR_INVALHANDLE; - - /* not buffered, direct seek on file */ - if (!wm->info.pchBuffer) - return send_message(wm->ioProc, &wm->info, MMIOM_SEEK, - lOffset, iOrigin, MMIO_PROC_32A); - - switch (iOrigin) { - case SEEK_SET: - offset = lOffset; - break; - case SEEK_CUR: - offset = wm->info.lBufOffset + (wm->info.pchNext - wm->info.pchBuffer) + lOffset; - break; - case SEEK_END: - offset = ((wm->info.fccIOProc == FOURCC_MEM)? wm->info.cchBuffer : wm->dwFileSize) - lOffset; - break; - default: - return -1; - } - - if (offset && offset >= wm->dwFileSize && wm->info.fccIOProc != FOURCC_MEM) { - /* should check that write mode exists */ - if (MMIO_Flush(wm, 0) != MMSYSERR_NOERROR) - return -1; - wm->info.lBufOffset = offset; - wm->info.pchEndRead = wm->info.pchBuffer; - wm->info.pchEndWrite = wm->info.pchBuffer + wm->info.cchBuffer; - if ((wm->info.dwFlags & MMIO_RWMODE) == MMIO_READ) { - wm->info.lDiskOffset = wm->dwFileSize; - } - } else if ((wm->info.cchBuffer > 0) && - ((offset < wm->info.lBufOffset) || - (offset >= wm->info.lBufOffset + wm->info.cchBuffer) || - !wm->bBufferLoaded)) { - /* stay in same buffer ? */ - /* some memory mapped buffers are defined with -1 as a size */ - - /* condition to change buffer */ - if ((wm->info.fccIOProc == FOURCC_MEM) || - MMIO_Flush(wm, 0) != MMSYSERR_NOERROR || - /* this also sets the wm->info.lDiskOffset field */ - send_message(wm->ioProc, &wm->info, MMIOM_SEEK, - (offset / wm->info.cchBuffer) * wm->info.cchBuffer, - SEEK_SET, MMIO_PROC_32A) == -1) - return -1; - MMIO_GrabNextBuffer(wm, TRUE); - } - - wm->info.pchNext = wm->info.pchBuffer + (offset - wm->info.lBufOffset); - - TRACE("=> %ld\n", offset); - return offset; -} - -/************************************************************************** - * mmioGetInfo [WINMM.@] - */ -MMRESULT WINAPI mmioGetInfo(HMMIO hmmio, MMIOINFO* lpmmioinfo, UINT uFlags) -{ - LPWINE_MMIO wm; - - TRACE("(%p,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags); - - if ((wm = MMIO_Get(hmmio)) == NULL) - return MMSYSERR_INVALHANDLE; - - memcpy(lpmmioinfo, &wm->info, sizeof(MMIOINFO)); - /* don't expose 16 bit ioproc:s */ - if (wm->ioProc->type != MMIO_PROC_16) - lpmmioinfo->pIOProc = wm->ioProc->pIOProc; - - return MMSYSERR_NOERROR; -} - -/************************************************************************** - * mmioSetInfo [WINMM.@] - */ -MMRESULT WINAPI mmioSetInfo(HMMIO hmmio, const MMIOINFO* lpmmioinfo, UINT uFlags) -{ - LPWINE_MMIO wm; - - TRACE("(%p,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags); - - if ((wm = MMIO_Get(hmmio)) == NULL) - return MMSYSERR_INVALHANDLE; - - /* check pointers coherence */ - if (lpmmioinfo->pchNext < wm->info.pchBuffer || - lpmmioinfo->pchNext > wm->info.pchBuffer + wm->info.cchBuffer || - lpmmioinfo->pchEndRead < wm->info.pchBuffer || - lpmmioinfo->pchEndRead > wm->info.pchBuffer + wm->info.cchBuffer || - lpmmioinfo->pchEndWrite < wm->info.pchBuffer || - lpmmioinfo->pchEndWrite > wm->info.pchBuffer + wm->info.cchBuffer) - return MMSYSERR_INVALPARAM; - - wm->info.pchNext = lpmmioinfo->pchNext; - wm->info.pchEndRead = lpmmioinfo->pchEndRead; - - return MMSYSERR_NOERROR; -} - -/************************************************************************** -* mmioSetBuffer [WINMM.@] -*/ -MMRESULT WINAPI mmioSetBuffer(HMMIO hmmio, LPSTR pchBuffer, LONG cchBuffer, UINT uFlags) -{ - LPWINE_MMIO wm; - - TRACE("(hmmio=%p, pchBuf=%p, cchBuf=%ld, uFlags=%#08x)\n", - hmmio, pchBuffer, cchBuffer, uFlags); - - if ((wm = MMIO_Get(hmmio)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMIO_SetBuffer(wm, pchBuffer, cchBuffer, uFlags); -} - -/************************************************************************** - * mmioFlush [WINMM.@] - */ -MMRESULT WINAPI mmioFlush(HMMIO hmmio, UINT uFlags) -{ - LPWINE_MMIO wm; - - TRACE("(%p, %04X)\n", hmmio, uFlags); - - if ((wm = MMIO_Get(hmmio)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMIO_Flush(wm, uFlags); -} - -/************************************************************************** - * mmioAdvance [WINMM.@] - */ -MMRESULT WINAPI mmioAdvance(HMMIO hmmio, MMIOINFO* lpmmioinfo, UINT uFlags) -{ - LPWINE_MMIO wm; - - TRACE("hmmio=%p, lpmmioinfo=%p, uFlags=%04X\n", hmmio, lpmmioinfo, uFlags); - - /* NOTE: mmioAdvance16 heavily relies on parameters from lpmmioinfo we're using - * here. be sure if you change something here to check mmioAdvance16 as well - */ - if ((wm = MMIO_Get(hmmio)) == NULL) - return MMSYSERR_INVALHANDLE; - - if (!wm->info.cchBuffer) - return MMIOERR_UNBUFFERED; - - if (uFlags != MMIO_READ && uFlags != MMIO_WRITE) - return MMSYSERR_INVALPARAM; - - if (uFlags == MMIO_WRITE && (lpmmioinfo->dwFlags & MMIO_DIRTY)) - { - send_message(wm->ioProc, &wm->info, MMIOM_SEEK, - lpmmioinfo->lBufOffset, SEEK_SET, MMIO_PROC_32A); - send_message(wm->ioProc, &wm->info, MMIOM_WRITE, - (LPARAM)lpmmioinfo->pchBuffer, - lpmmioinfo->pchNext - lpmmioinfo->pchBuffer, MMIO_PROC_32A); - lpmmioinfo->dwFlags &= ~MMIO_DIRTY; - } - if (MMIO_Flush(wm, 0) != MMSYSERR_NOERROR) - return MMIOERR_CANNOTWRITE; - - if (lpmmioinfo) { - wm->dwFileSize = max(wm->dwFileSize, lpmmioinfo->lBufOffset + - (lpmmioinfo->pchNext - lpmmioinfo->pchBuffer)); - } - MMIO_GrabNextBuffer(wm, uFlags == MMIO_READ); - - if (lpmmioinfo) { - lpmmioinfo->pchNext = lpmmioinfo->pchBuffer; - lpmmioinfo->pchEndRead = lpmmioinfo->pchBuffer + - (wm->info.pchEndRead - wm->info.pchBuffer); - lpmmioinfo->pchEndWrite = lpmmioinfo->pchBuffer + - (wm->info.pchEndWrite - wm->info.pchBuffer); - lpmmioinfo->lDiskOffset = wm->info.lDiskOffset; - lpmmioinfo->lBufOffset = wm->info.lBufOffset; - } - return MMSYSERR_NOERROR; -} - -/************************************************************************** - * mmioStringToFOURCCA [WINMM.@] - */ -FOURCC WINAPI mmioStringToFOURCCA(LPCSTR sz, UINT uFlags) -{ - CHAR cc[4]; - int i = 0; - - for (i = 0; i < 4 && sz[i]; i++) { - if (uFlags & MMIO_TOUPPER) { - cc[i] = toupper(sz[i]); - } else { - cc[i] = sz[i]; - } - } - - /* Pad with spaces */ - while (i < 4) cc[i++] = ' '; - - TRACE("Got '%.4s'\n",cc); - return mmioFOURCC(cc[0],cc[1],cc[2],cc[3]); -} - -/************************************************************************** - * mmioStringToFOURCCW [WINMM.@] - */ -FOURCC WINAPI mmioStringToFOURCCW(LPCWSTR sz, UINT uFlags) -{ - char szA[4]; - - WideCharToMultiByte( CP_ACP, 0, sz, 4, szA, sizeof(szA), NULL, NULL ); - return mmioStringToFOURCCA(szA,uFlags); -} - -/************************************************************************** - * mmioInstallIOProcA [WINMM.@] - */ -LPMMIOPROC WINAPI mmioInstallIOProcA(FOURCC fccIOProc, - LPMMIOPROC pIOProc, DWORD dwFlags) -{ - return MMIO_InstallIOProc(fccIOProc, pIOProc, dwFlags, MMIO_PROC_32A); -} - -/************************************************************************** - * mmioInstallIOProcW [WINMM.@] - */ -LPMMIOPROC WINAPI mmioInstallIOProcW(FOURCC fccIOProc, - LPMMIOPROC pIOProc, DWORD dwFlags) -{ - return MMIO_InstallIOProc(fccIOProc, pIOProc, dwFlags, MMIO_PROC_32W); -} - -/****************************************************************** - * MMIO_SendMessage - * - * - */ -LRESULT MMIO_SendMessage(HMMIO hmmio, UINT uMessage, LPARAM lParam1, - LPARAM lParam2, enum mmioProcType type) -{ - LPWINE_MMIO wm; - - TRACE("(%p, %u, %ld, %ld, %d)\n", hmmio, uMessage, lParam1, lParam2, type); - - if (uMessage < MMIOM_USER) - return MMSYSERR_INVALPARAM; - - if ((wm = MMIO_Get(hmmio)) == NULL) - return MMSYSERR_INVALHANDLE; - - return send_message(wm->ioProc, &wm->info, uMessage, lParam1, lParam2, type); -} - -/************************************************************************** - * mmioSendMessage [WINMM.@] - */ -LRESULT WINAPI mmioSendMessage(HMMIO hmmio, UINT uMessage, - LPARAM lParam1, LPARAM lParam2) -{ - return MMIO_SendMessage(hmmio, uMessage, lParam1, lParam2, MMIO_PROC_32A); -} - -/************************************************************************** - * mmioDescend [WINMM.@] - */ -MMRESULT WINAPI mmioDescend(HMMIO hmmio, LPMMCKINFO lpck, - const MMCKINFO* lpckParent, UINT uFlags) -{ - DWORD dwOldPos; - FOURCC srchCkId; - FOURCC srchType; - - - TRACE("(%p, %p, %p, %04X);\n", hmmio, lpck, lpckParent, uFlags); - - if (lpck == NULL) - return MMSYSERR_INVALPARAM; - - dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR); - TRACE("dwOldPos=%ld\n", dwOldPos); - - if (lpckParent != NULL) { - TRACE("seek inside parent at %ld !\n", lpckParent->dwDataOffset); - /* EPP: was dwOldPos = mmioSeek(hmmio,lpckParent->dwDataOffset,SEEK_SET); */ - if (dwOldPos < lpckParent->dwDataOffset || - dwOldPos >= lpckParent->dwDataOffset + lpckParent->cksize) { - WARN("outside parent chunk\n"); - return MMIOERR_CHUNKNOTFOUND; - } - } - - /* The SDK docu says 'ckid' is used for all cases. Real World - * examples disagree -Marcus,990216. - */ - - srchType = 0; - /* find_chunk looks for 'ckid' */ - if (uFlags & MMIO_FINDCHUNK) - srchCkId = lpck->ckid; - /* find_riff and find_list look for 'fccType' */ - if (uFlags & MMIO_FINDLIST) { - srchCkId = FOURCC_LIST; - srchType = lpck->fccType; - } - if (uFlags & MMIO_FINDRIFF) { - srchCkId = FOURCC_RIFF; - srchType = lpck->fccType; - } - - if (uFlags & (MMIO_FINDCHUNK|MMIO_FINDLIST|MMIO_FINDRIFF)) { - TRACE("searching for %.4s.%.4s\n", - (LPSTR)&srchCkId, - srchType?(LPSTR)&srchType:"any "); - - while (TRUE) { - LONG ix; - - ix = mmioRead(hmmio, (LPSTR)lpck, 3 * sizeof(DWORD)); - if (ix < 2*sizeof(DWORD)) { - mmioSeek(hmmio, dwOldPos, SEEK_SET); - WARN("return ChunkNotFound\n"); - return MMIOERR_CHUNKNOTFOUND; - } - lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD); - if (ix < lpck->dwDataOffset - dwOldPos) { - mmioSeek(hmmio, dwOldPos, SEEK_SET); - WARN("return ChunkNotFound\n"); - return MMIOERR_CHUNKNOTFOUND; - } - TRACE("ckid=%.4s fcc=%.4s cksize=%08lX !\n", - (LPSTR)&lpck->ckid, - srchType?(LPSTR)&lpck->fccType:"<na>", - lpck->cksize); - if ((srchCkId == lpck->ckid) && - (!srchType || (srchType == lpck->fccType)) - ) - break; - - dwOldPos = lpck->dwDataOffset + ((lpck->cksize + 1) & ~1); - mmioSeek(hmmio, dwOldPos, SEEK_SET); - } - } else { - /* FIXME: unverified, does it do this? */ - /* NB: This part is used by WAVE_mciOpen, among others */ - if (mmioRead(hmmio, (LPSTR)lpck, 3 * sizeof(DWORD)) < 3 * sizeof(DWORD)) { - mmioSeek(hmmio, dwOldPos, SEEK_SET); - WARN("return ChunkNotFound 2nd\n"); - return MMIOERR_CHUNKNOTFOUND; - } - lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD); - } - lpck->dwFlags = 0; - /* If we were looking for RIFF/LIST chunks, the final file position - * is after the chunkid. If we were just looking for the chunk - * it is after the cksize. So add 4 in RIFF/LIST case. - */ - if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST) - mmioSeek(hmmio, lpck->dwDataOffset + sizeof(DWORD), SEEK_SET); - else - mmioSeek(hmmio, lpck->dwDataOffset, SEEK_SET); - TRACE("lpck: ckid=%.4s, cksize=%ld, dwDataOffset=%ld fccType=%08lX (%.4s)!\n", - (LPSTR)&lpck->ckid, lpck->cksize, lpck->dwDataOffset, - lpck->fccType, srchType?(LPSTR)&lpck->fccType:""); - return MMSYSERR_NOERROR; -} - -/************************************************************************** - * mmioAscend [WINMM.@] - */ -MMRESULT WINAPI mmioAscend(HMMIO hmmio, LPMMCKINFO lpck, UINT uFlags) -{ - TRACE("(%p, %p, %04X);\n", hmmio, lpck, uFlags); - - if (lpck->dwFlags & MMIO_DIRTY) { - DWORD dwOldPos, dwNewSize; - - TRACE("Chunk is dirty, checking if chunk's size is correct\n"); - dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR); - TRACE("dwOldPos=%ld lpck->dwDataOffset = %ld\n", dwOldPos, lpck->dwDataOffset); - dwNewSize = dwOldPos - lpck->dwDataOffset; - if (dwNewSize != lpck->cksize) { - TRACE("Nope: lpck->cksize=%ld dwNewSize=%ld\n", lpck->cksize, dwNewSize); - lpck->cksize = dwNewSize; - - /* pad odd size with 0 */ - if (dwNewSize & 1) { - char ch = 0; - mmioWrite(hmmio, &ch, 1); - } - mmioSeek(hmmio, lpck->dwDataOffset - sizeof(DWORD), SEEK_SET); - mmioWrite(hmmio, (LPSTR)&dwNewSize, sizeof(DWORD)); - } - lpck->dwFlags = 0; - } - - mmioSeek(hmmio, lpck->dwDataOffset + ((lpck->cksize + 1) & ~1), SEEK_SET); - - return MMSYSERR_NOERROR; -} - -/************************************************************************** - * mmioCreateChunk [WINMM.@] - */ -MMRESULT WINAPI mmioCreateChunk(HMMIO hmmio, MMCKINFO* lpck, UINT uFlags) -{ - DWORD dwOldPos; - LONG size; - LONG ix; - - TRACE("(%p, %p, %04X);\n", hmmio, lpck, uFlags); - - dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR); - TRACE("dwOldPos=%ld\n", dwOldPos); - - if (uFlags == MMIO_CREATELIST) - lpck->ckid = FOURCC_LIST; - else if (uFlags == MMIO_CREATERIFF) - lpck->ckid = FOURCC_RIFF; - - TRACE("ckid=%.4s\n", (LPSTR)&lpck->ckid); - - size = 2 * sizeof(DWORD); - lpck->dwDataOffset = dwOldPos + size; - - if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST) - size += sizeof(DWORD); - lpck->dwFlags = MMIO_DIRTY; - - ix = mmioWrite(hmmio, (LPSTR)lpck, size); - TRACE("after mmioWrite ix = %ld req = %ld, errno = %d\n",ix, size, errno); - if (ix < size) { - mmioSeek(hmmio, dwOldPos, SEEK_SET); - WARN("return CannotWrite\n"); - return MMIOERR_CANNOTWRITE; - } - - return MMSYSERR_NOERROR; -} - -/************************************************************************** - * mmioRenameA [WINMM.@] - */ -MMRESULT WINAPI mmioRenameA(LPCSTR szFileName, LPCSTR szNewFileName, - const MMIOINFO* lpmmioinfo, DWORD dwFlags) -{ - struct IOProcList* ioProc = NULL; - struct IOProcList tmp; - FOURCC fcc; - - TRACE("('%s', '%s', %p, %08lX);\n", - debugstr_a(szFileName), debugstr_a(szNewFileName), lpmmioinfo, dwFlags); - - /* If both params are NULL, then parse the file name */ - if (lpmmioinfo && lpmmioinfo->fccIOProc == 0 && lpmmioinfo->pIOProc == NULL) - { - fcc = MMIO_ParseExtA(szFileName); - if (fcc) ioProc = MMIO_FindProcNode(fcc); - } - - /* Handle any unhandled/error case from above. Assume DOS file */ - if (!lpmmioinfo || (lpmmioinfo->fccIOProc == 0 && lpmmioinfo->pIOProc == NULL && ioProc == NULL)) - ioProc = MMIO_FindProcNode(FOURCC_DOS); - /* if just the four character code is present, look up IO proc */ - else if (lpmmioinfo->pIOProc == NULL) - ioProc = MMIO_FindProcNode(lpmmioinfo->fccIOProc); - else /* use relevant ioProc */ - { - ioProc = &tmp; - tmp.fourCC = lpmmioinfo->fccIOProc; - tmp.pIOProc = lpmmioinfo->pIOProc; - tmp.type = MMIO_PROC_32A; - tmp.count = 1; - } - - /* FIXME: should we actually pass lpmmioinfo down the drain ??? - * or make a copy of it because it's const ??? - */ - return send_message(ioProc, (MMIOINFO*)lpmmioinfo, MMIOM_RENAME, - (LPARAM)szFileName, (LPARAM)szNewFileName, MMIO_PROC_32A); -} - -/************************************************************************** - * mmioRenameW [WINMM.@] - */ -MMRESULT WINAPI mmioRenameW(LPCWSTR szFileName, LPCWSTR szNewFileName, - const MMIOINFO* lpmmioinfo, DWORD dwFlags) -{ - LPSTR szFn = NULL; - LPSTR sznFn = NULL; - UINT ret = MMSYSERR_NOMEM; - INT len; - - if (szFileName) - { - len = WideCharToMultiByte( CP_ACP, 0, szFileName, -1, NULL, 0, NULL, NULL ); - szFn = HeapAlloc( GetProcessHeap(), 0, len ); - if (!szFn) goto done; - WideCharToMultiByte( CP_ACP, 0, szFileName, -1, szFn, len, NULL, NULL ); - } - if (szNewFileName) - { - len = WideCharToMultiByte( CP_ACP, 0, szNewFileName, -1, NULL, 0, NULL, NULL ); - sznFn = HeapAlloc( GetProcessHeap(), 0, len ); - if (!sznFn) goto done; - WideCharToMultiByte( CP_ACP, 0, szNewFileName, -1, sznFn, len, NULL, NULL ); - } - - ret = mmioRenameA(szFn, sznFn, lpmmioinfo, dwFlags); - -done: - HeapFree(GetProcessHeap(),0,szFn); - HeapFree(GetProcessHeap(),0,sznFn); - return ret; -} +/* + * MMIO functions + * + * Copyright 1998 Andrew Taylor + * Copyright 1998 Ove KÃ¥ven + * Copyright 2000,2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Still to be done: + * + correct handling of global/local IOProcs (and temporary IOProcs) + * + mode of mmio objects is not used (read vs write vs readwrite) + * + thread safeness + * + 32 A <=> W message mapping + */ + + +#include <ctype.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <assert.h> + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "mmsystem.h" +#include "winemm.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mmio); + +LRESULT (*pFnMmioCallback16)(DWORD,LPMMIOINFO,UINT,LPARAM,LPARAM) /* = NULL */; + +/************************************************************************** + * mmioDosIOProc [internal] + */ +static LRESULT CALLBACK mmioDosIOProc(LPMMIOINFO lpmmioinfo, UINT uMessage, + LPARAM lParam1, LPARAM lParam2) +{ + LRESULT ret = MMSYSERR_NOERROR; + + TRACE("(%p, %X, 0x%lx, 0x%lx);\n", lpmmioinfo, uMessage, lParam1, lParam2); + + switch (uMessage) { + case MMIOM_OPEN: + { + /* Parameters: + * lParam1 = szFileName parameter from mmioOpen + * lParam2 = reserved + * Returns: zero on success, error code on error + * NOTE: lDiskOffset automatically set to zero + */ + LPCSTR szFileName = (LPCSTR)lParam1; + + if (lpmmioinfo->dwFlags & MMIO_GETTEMP) { + FIXME("MMIO_GETTEMP not implemented\n"); + return MMIOERR_CANNOTOPEN; + } + + /* if filename NULL, assume open file handle in adwInfo[0] */ + if (szFileName) { + OFSTRUCT ofs; + lpmmioinfo->adwInfo[0] = (DWORD)OpenFile(szFileName, &ofs, lpmmioinfo->dwFlags & 0xFFFF); + } + if (lpmmioinfo->adwInfo[0] == (DWORD)HFILE_ERROR) + ret = MMIOERR_CANNOTOPEN; + } + break; + + case MMIOM_CLOSE: + /* Parameters: + * lParam1 = wFlags parameter from mmioClose + * lParam2 = unused + * Returns: zero on success, error code on error + */ + if (!(lParam1 & MMIO_FHOPEN)) + _lclose((HFILE)lpmmioinfo->adwInfo[0]); + break; + + case MMIOM_READ: + /* Parameters: + * lParam1 = huge pointer to read buffer + * lParam2 = number of bytes to read + * Returns: number of bytes read, 0 for EOF, -1 for error (error code + * in wErrorRet) + */ + ret = _lread((HFILE)lpmmioinfo->adwInfo[0], (HPSTR)lParam1, (LONG)lParam2); + if (ret != -1) + lpmmioinfo->lDiskOffset += ret; + + break; + + case MMIOM_WRITE: + case MMIOM_WRITEFLUSH: + /* no internal buffering, so WRITEFLUSH handled same as WRITE */ + + /* Parameters: + * lParam1 = huge pointer to write buffer + * lParam2 = number of bytes to write + * Returns: number of bytes written, -1 for error (error code in + * wErrorRet) + */ + ret = _hwrite((HFILE)lpmmioinfo->adwInfo[0], (HPSTR)lParam1, (LONG)lParam2); + if (ret != -1) + lpmmioinfo->lDiskOffset += ret; + break; + + case MMIOM_SEEK: + /* Parameters: + * lParam1 = new position + * lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END) + * Returns: new file postion, -1 on error + */ + ret = _llseek((HFILE)lpmmioinfo->adwInfo[0], (LONG)lParam1, (LONG)lParam2); + if (ret != -1) + lpmmioinfo->lDiskOffset = ret; + return ret; + + case MMIOM_RENAME: + /* Parameters: + * lParam1 = old name + * lParam2 = new name + * Returns: zero on success, non-zero on failure + */ + if (!MoveFileA((const char*)lParam1, (const char*)lParam2)) + ret = MMIOERR_FILENOTFOUND; + break; + + default: + FIXME("unexpected message %u\n", uMessage); + return 0; + } + + return ret; +} + +/************************************************************************** + * mmioMemIOProc [internal] + */ +static LRESULT CALLBACK mmioMemIOProc(LPMMIOINFO lpmmioinfo, UINT uMessage, + LPARAM lParam1, LPARAM lParam2) +{ + TRACE("(%p,0x%04x,0x%08lx,0x%08lx)\n", lpmmioinfo, uMessage, lParam1, lParam2); + + switch (uMessage) { + + case MMIOM_OPEN: + /* Parameters: + * lParam1 = filename (must be NULL) + * lParam2 = reserved + * Returns: zero on success, error code on error + * NOTE: lDiskOffset automatically set to zero + */ + /* FIXME: io proc shouldn't change it */ + if (!(lpmmioinfo->dwFlags & MMIO_CREATE)) + lpmmioinfo->pchEndRead = lpmmioinfo->pchEndWrite; + lpmmioinfo->adwInfo[0] = HFILE_ERROR; + return 0; + + case MMIOM_CLOSE: + /* Parameters: + * lParam1 = wFlags parameter from mmioClose + * lParam2 = unused + * Returns: zero on success, error code on error + */ + return 0; + + case MMIOM_READ: + /* Parameters: + * lParam1 = huge pointer to read buffer + * lParam2 = number of bytes to read + * Returns: number of bytes read, 0 for EOF, -1 for error (error code + * in wErrorRet) + * NOTE: lDiskOffset should be updated + */ + FIXME("MMIOM_READ on memory files should not occur, buffer may be lost!\n"); + return 0; + + case MMIOM_WRITE: + case MMIOM_WRITEFLUSH: + /* no internal buffering, so WRITEFLUSH handled same as WRITE */ + + /* Parameters: + * lParam1 = huge pointer to write buffer + * lParam2 = number of bytes to write + * Returns: number of bytes written, -1 for error (error code in + * wErrorRet) + * NOTE: lDiskOffset should be updated + */ + FIXME("MMIOM_WRITE on memory files should not occur, buffer may be lost!\n"); + return 0; + + case MMIOM_SEEK: + /* Parameters: + * lParam1 = new position + * lParam2 = from whence to seek (SEEK_SET, SEEK_CUR, SEEK_END) + * Returns: new file postion, -1 on error + * NOTE: lDiskOffset should be updated + */ + FIXME("MMIOM_SEEK on memory files should not occur, buffer may be lost!\n"); + return -1; + + default: + FIXME("unexpected message %u\n", uMessage); + return 0; + } +} + +/* This array will be the entire list for most apps + * Note that temporary ioProcs will be stored with a 0 fourCC code + */ + +static struct IOProcList defaultProcs[] = { + {&defaultProcs[1], FOURCC_DOS, (LPMMIOPROC)mmioDosIOProc, MMIO_PROC_32A, 0}, + {NULL, FOURCC_MEM, (LPMMIOPROC)mmioMemIOProc, MMIO_PROC_32A, 0}, +}; + +static struct IOProcList* pIOProcListAnchor = &defaultProcs[0]; + +/**************************************************************** + * MMIO_FindProcNode [INTERNAL] + * + * Finds the ProcList node associated with a given FOURCC code. + */ +static struct IOProcList* MMIO_FindProcNode(FOURCC fccIOProc) +{ + struct IOProcList* pListNode; + + for (pListNode = pIOProcListAnchor; pListNode; pListNode = pListNode->pNext) { + if (pListNode->fourCC == fccIOProc) { + return pListNode; + } + } + return NULL; +} + +/**************************************************************** + * MMIO_InstallIOProc [INTERNAL] + */ +LPMMIOPROC MMIO_InstallIOProc(FOURCC fccIOProc, LPMMIOPROC pIOProc, + DWORD dwFlags, enum mmioProcType type) +{ + LPMMIOPROC lpProc = NULL; + struct IOProcList* pListNode; + struct IOProcList** ppListNode; + + TRACE("(%08lx, %p, %08lX, %i)\n", fccIOProc, pIOProc, dwFlags, type); + + if (dwFlags & MMIO_GLOBALPROC) + FIXME("Global procedures not implemented\n"); + + /* just handle the known procedures for now */ + switch (dwFlags & (MMIO_INSTALLPROC|MMIO_REMOVEPROC|MMIO_FINDPROC)) { + case MMIO_INSTALLPROC: + /* Create new entry for the IOProc list */ + pListNode = HeapAlloc(GetProcessHeap(), 0, sizeof(*pListNode)); + if (pListNode) { + /* Fill in this node */ + pListNode->fourCC = fccIOProc; + pListNode->pIOProc = pIOProc; + pListNode->type = type; + pListNode->count = 0; + + /* Stick it on the end of the list */ + pListNode->pNext = pIOProcListAnchor; + pIOProcListAnchor = pListNode; + + /* Return this IOProc - that's how the caller knows we succeeded */ + lpProc = pIOProc; + } + break; + + case MMIO_REMOVEPROC: + /* + * Search for the node that we're trying to remove + * We search for a matching fourCC code if it's non null, or the proc + * address otherwise + * note that this method won't find the first item on the list, but + * since the first two items on this list are ones we won't + * let the user delete anyway, that's okay + */ + ppListNode = &pIOProcListAnchor; + while ((*ppListNode) && + ((fccIOProc != 0) ? + (*ppListNode)->fourCC != fccIOProc : + (*ppListNode)->pIOProc != pIOProc)) + ppListNode = &((*ppListNode)->pNext); + + if (*ppListNode) { /* found it */ + /* FIXME: what should be done if an open mmio object uses this proc ? + * shall we return an error, nuke the mmio object ? + */ + if ((*ppListNode)->count) { + ERR("Cannot remove a mmIOProc while in use\n"); + break; + } + /* remove it, but only if it isn't builtin */ + if ((*ppListNode) >= defaultProcs && + (*ppListNode) < defaultProcs + sizeof(defaultProcs)) { + WARN("Tried to remove built-in mmio proc. Skipping\n"); + } else { + /* Okay, nuke it */ + struct IOProcList* ptmpNode = *ppListNode; + lpProc = (*ppListNode)->pIOProc; + *ppListNode = (*ppListNode)->pNext; + HeapFree(GetProcessHeap(), 0, ptmpNode); + } + } + break; + + case MMIO_FINDPROC: + if ((pListNode = MMIO_FindProcNode(fccIOProc))) { + lpProc = pListNode->pIOProc; + } + break; + } + + return lpProc; +} + +/**************************************************************** + * send_message [INTERNAL] + */ +static LRESULT send_message(struct IOProcList* ioProc, LPMMIOINFO mmioinfo, + DWORD wMsg, LPARAM lParam1, + LPARAM lParam2, enum mmioProcType type) +{ + LRESULT result = MMSYSERR_ERROR; + LPARAM lp1 = lParam1, lp2 = lParam2; + + if (!ioProc) { + ERR("brrr\n"); + result = MMSYSERR_INVALPARAM; + } + + switch (ioProc->type) { + case MMIO_PROC_16: + if (pFnMmioCallback16) + result = pFnMmioCallback16((DWORD)ioProc->pIOProc, + mmioinfo, wMsg, lp1, lp2); + break; + case MMIO_PROC_32A: + case MMIO_PROC_32W: + if (ioProc->type != type) { + /* map (lParam1, lParam2) into (lp1, lp2) 32 A<=>W */ + FIXME("NIY 32 A<=>W mapping\n"); + } + result = (ioProc->pIOProc)((LPSTR)mmioinfo, wMsg, lp1, lp2); + +#if 0 + if (ioProc->type != type) { + /* unmap (lParam1, lParam2) into (lp1, lp2) 32 A<=>W */ + } +#endif + break; + default: + FIXME("Internal error\n"); + } + + return result; +} + +/************************************************************************** + * MMIO_ParseExtA [internal] + * + * Parses a filename for the extension. + * + * RETURNS + * The FOURCC code for the extension if found, else 0. + */ +static FOURCC MMIO_ParseExtA(LPCSTR szFileName) +{ + /* Filenames are of the form file.ext{+ABC} + For now, we take the last '+' if present */ + + FOURCC ret = 0; + + /* Note that ext{Start,End} point to the . and + respectively */ + LPSTR extEnd; + LPSTR extStart; + + TRACE("(%s)\n", debugstr_a(szFileName)); + + if (!szFileName) + return ret; + + /* Find the last '.' */ + extStart = strrchr(szFileName,'.'); + + if (!extStart) { + ERR("No . in szFileName: %s\n", debugstr_a(szFileName)); + } else { + CHAR ext[5]; + + /* Find the '+' afterwards */ + extEnd = strchr(extStart,'+'); + if (extEnd) { + + if (extEnd - extStart - 1 > 4) + WARN("Extension length > 4\n"); + lstrcpynA(ext, extStart + 1, min(extEnd-extStart,5)); + + } else { + /* No + so just an extension */ + if (strlen(extStart) > 4) { + WARN("Extension length > 4\n"); + } + lstrcpynA(ext, extStart + 1, 5); + } + TRACE("Got extension: %s\n", debugstr_a(ext)); + + /* FOURCC codes identifying file-extensions must be uppercase */ + ret = mmioStringToFOURCCA(ext, MMIO_TOUPPER); + } + return ret; +} + +/************************************************************************** + * MMIO_Get [internal] + * + * Retrieves the mmio object from current process + */ +LPWINE_MMIO MMIO_Get(HMMIO h) +{ + LPWINE_MMIO wm = NULL; + + EnterCriticalSection(&WINMM_IData.cs); + for (wm = WINMM_IData.lpMMIO; wm; wm = wm->lpNext) { + if (wm->info.hmmio == h) + break; + } + LeaveCriticalSection(&WINMM_IData.cs); + return wm; +} + +/************************************************************************** + * MMIO_Create [internal] + * + * Creates an internal representation for a mmio instance + */ +static LPWINE_MMIO MMIO_Create(void) +{ + static WORD MMIO_counter = 0; + LPWINE_MMIO wm; + + wm = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MMIO)); + if (wm) { + EnterCriticalSection(&WINMM_IData.cs); + /* lookup next unallocated WORD handle, with a non NULL value */ + while (++MMIO_counter == 0 || MMIO_Get((HMMIO)(ULONG_PTR)MMIO_counter)); + wm->info.hmmio = (HMMIO)(ULONG_PTR)MMIO_counter; + wm->lpNext = WINMM_IData.lpMMIO; + WINMM_IData.lpMMIO = wm; + LeaveCriticalSection(&WINMM_IData.cs); + } + return wm; +} + +/************************************************************************** + * MMIO_Destroy [internal] + *- + * Destroys an internal representation for a mmio instance + */ +static BOOL MMIO_Destroy(LPWINE_MMIO wm) +{ + LPWINE_MMIO* m; + + EnterCriticalSection(&WINMM_IData.cs); + /* search for the matching one... */ + m = &(WINMM_IData.lpMMIO); + while (*m && *m != wm) m = &(*m)->lpNext; + /* ...and destroy */ + if (*m) { + *m = (*m)->lpNext; + HeapFree(GetProcessHeap(), 0, wm); + wm = NULL; + } + LeaveCriticalSection(&WINMM_IData.cs); + return wm ? FALSE : TRUE; +} + +/**************************************************************** + * MMIO_Flush [INTERNAL] + */ +static MMRESULT MMIO_Flush(WINE_MMIO* wm, UINT uFlags) +{ + if (wm->info.cchBuffer && (wm->info.fccIOProc != FOURCC_MEM)) { + /* not quite sure what to do here, but I'll guess */ + if (wm->info.dwFlags & MMIO_DIRTY) { + /* FIXME: error handling */ + send_message(wm->ioProc, &wm->info, MMIOM_SEEK, + wm->info.lBufOffset, SEEK_SET, MMIO_PROC_32A); + send_message(wm->ioProc, &wm->info, MMIOM_WRITE, + (LPARAM)wm->info.pchBuffer, + wm->info.pchNext - wm->info.pchBuffer, MMIO_PROC_32A); + } + if (uFlags & MMIO_EMPTYBUF) + wm->info.pchNext = wm->info.pchEndRead = wm->info.pchBuffer; + } + wm->info.dwFlags &= ~MMIO_DIRTY; + + return MMSYSERR_NOERROR; +} + +/*************************************************************************** + * MMIO_GrabNextBuffer [INTERNAL] + */ +static LONG MMIO_GrabNextBuffer(LPWINE_MMIO wm, int for_read) +{ + LONG size = wm->info.cchBuffer; + + TRACE("bo=%lx do=%lx of=%lx\n", + wm->info.lBufOffset, wm->info.lDiskOffset, + send_message(wm->ioProc, &wm->info, MMIOM_SEEK, 0, SEEK_CUR, MMIO_PROC_32A)); + + wm->info.lBufOffset = wm->info.lDiskOffset; + wm->info.pchNext = wm->info.pchBuffer; + wm->info.pchEndRead = wm->info.pchBuffer; + wm->info.pchEndWrite = wm->info.pchBuffer + wm->info.cchBuffer; + + wm->bBufferLoaded = TRUE; + if (for_read) { + size = send_message(wm->ioProc, &wm->info, MMIOM_READ, + (LPARAM)wm->info.pchBuffer, size, MMIO_PROC_32A); + if (size > 0) + wm->info.pchEndRead += size; + else + wm->bBufferLoaded = FALSE; + } + + return size; +} + +/*************************************************************************** + * MMIO_SetBuffer [INTERNAL] + */ +static MMRESULT MMIO_SetBuffer(WINE_MMIO* wm, void* pchBuffer, LONG cchBuffer, + UINT uFlags) +{ + TRACE("(%p %p %ld %u)\n", wm, pchBuffer, cchBuffer, uFlags); + + if (uFlags) return MMSYSERR_INVALPARAM; + if (cchBuffer > 0xFFFF) + WARN("Untested handling of huge mmio buffers (%ld >= 64k)\n", cchBuffer); + + if (MMIO_Flush(wm, 0) != MMSYSERR_NOERROR) + return MMIOERR_CANNOTWRITE; + + /* free previous buffer if allocated */ + if (wm->info.dwFlags & MMIO_ALLOCBUF) { + HeapFree(GetProcessHeap(), 0, wm->info.pchBuffer); + wm->info.pchBuffer = NULL; + wm->info.dwFlags &= ~MMIO_ALLOCBUF; + } + + if (pchBuffer) { + wm->info.pchBuffer = pchBuffer; + } else if (cchBuffer) { + if (!(wm->info.pchBuffer = HeapAlloc(GetProcessHeap(), 0, cchBuffer))) + return MMIOERR_OUTOFMEMORY; + wm->info.dwFlags |= MMIO_ALLOCBUF; + } else { + wm->info.pchBuffer = NULL; + } + + wm->info.cchBuffer = cchBuffer; + wm->info.pchNext = wm->info.pchBuffer; + wm->info.pchEndRead = wm->info.pchBuffer; + wm->info.pchEndWrite = wm->info.pchBuffer + cchBuffer; + wm->info.lBufOffset = 0; + wm->bBufferLoaded = FALSE; + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * MMIO_Open [internal] + */ +HMMIO MMIO_Open(LPSTR szFileName, MMIOINFO* refmminfo, DWORD dwOpenFlags, + enum mmioProcType type) +{ + LPWINE_MMIO wm; + MMIOINFO mmioinfo; + + TRACE("('%s', %p, %08lX, %d);\n", szFileName, refmminfo, dwOpenFlags, type); + + if (!refmminfo) { + refmminfo = &mmioinfo; + + mmioinfo.fccIOProc = 0; + mmioinfo.pIOProc = NULL; + mmioinfo.pchBuffer = NULL; + mmioinfo.cchBuffer = 0; + type = MMIO_PROC_32A; + } + + if (dwOpenFlags & (MMIO_PARSE|MMIO_EXIST)) { + char buffer[MAX_PATH]; + + if (GetFullPathNameA(szFileName, sizeof(buffer), buffer, NULL) >= sizeof(buffer)) + return (HMMIO)FALSE; + if ((dwOpenFlags & MMIO_EXIST) && (GetFileAttributesA(buffer) == INVALID_FILE_ATTRIBUTES)) + return (HMMIO)FALSE; + strcpy(szFileName, buffer); + return (HMMIO)TRUE; + } + + if ((wm = MMIO_Create()) == NULL) + return 0; + + /* If both params are NULL, then parse the file name if available */ + if (refmminfo->fccIOProc == 0 && refmminfo->pIOProc == NULL) { + wm->info.fccIOProc = MMIO_ParseExtA(szFileName); + /* Handle any unhandled/error case. Assume DOS file */ + if (wm->info.fccIOProc == 0) + wm->info.fccIOProc = FOURCC_DOS; + if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) { + /* If not found, retry with FOURCC_DOS */ + wm->info.fccIOProc = FOURCC_DOS; + if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) + goto error2; + } + wm->bTmpIOProc = FALSE; + } + /* if just the four character code is present, look up IO proc */ + else if (refmminfo->pIOProc == NULL) { + wm->info.fccIOProc = refmminfo->fccIOProc; + if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) goto error2; + wm->bTmpIOProc = FALSE; + } + /* if IO proc specified, use it and specified four character code */ + else { + wm->info.fccIOProc = refmminfo->fccIOProc; + MMIO_InstallIOProc(wm->info.fccIOProc, refmminfo->pIOProc, + MMIO_INSTALLPROC, type); + if (!(wm->ioProc = MMIO_FindProcNode(wm->info.fccIOProc))) goto error2; + assert(wm->ioProc->pIOProc == refmminfo->pIOProc); + wm->bTmpIOProc = TRUE; + } + + wm->bBufferLoaded = FALSE; + wm->ioProc->count++; + + if (dwOpenFlags & MMIO_ALLOCBUF) { + if ((refmminfo->wErrorRet = MMIO_SetBuffer(wm, NULL, MMIO_DEFAULTBUFFER, 0))) + goto error1; + } else if (wm->info.fccIOProc == FOURCC_MEM) { + refmminfo->wErrorRet = MMIO_SetBuffer(wm, refmminfo->pchBuffer, refmminfo->cchBuffer, 0); + if (refmminfo->wErrorRet != MMSYSERR_NOERROR) + goto error1; + wm->bBufferLoaded = TRUE; + } /* else => unbuffered, wm->info.pchBuffer == NULL */ + + /* see mmioDosIOProc for that one */ + wm->info.adwInfo[0] = refmminfo->adwInfo[0]; + wm->info.dwFlags = dwOpenFlags; + + /* call IO proc to actually open file */ + refmminfo->wErrorRet = send_message(wm->ioProc, &wm->info, MMIOM_OPEN, + (LPARAM)szFileName, 0, MMIO_PROC_32A); + + /* grab file size, when possible */ + wm->dwFileSize = GetFileSize((HANDLE)wm->info.adwInfo[0], NULL); + + if (refmminfo->wErrorRet == 0) + return wm->info.hmmio; + error1: + if (wm->ioProc) wm->ioProc->count--; + error2: + MMIO_Destroy(wm); + return 0; +} + +/************************************************************************** + * mmioOpenW [WINMM.@] + */ +HMMIO WINAPI mmioOpenW(LPWSTR szFileName, MMIOINFO* lpmmioinfo, + DWORD dwOpenFlags) +{ + HMMIO ret; + LPSTR szFn = NULL; + + if (szFileName) + { + INT len = WideCharToMultiByte( CP_ACP, 0, szFileName, -1, NULL, 0, NULL, NULL ); + szFn = HeapAlloc( GetProcessHeap(), 0, len ); + if (!szFn) return NULL; + WideCharToMultiByte( CP_ACP, 0, szFileName, -1, szFn, len, NULL, NULL ); + } + + ret = MMIO_Open(szFn, lpmmioinfo, dwOpenFlags, MMIO_PROC_32W); + + HeapFree(GetProcessHeap(), 0, szFn); + return ret; +} + +/************************************************************************** + * mmioOpenA [WINMM.@] + */ +HMMIO WINAPI mmioOpenA(LPSTR szFileName, MMIOINFO* lpmmioinfo, + DWORD dwOpenFlags) +{ + return MMIO_Open(szFileName, lpmmioinfo, dwOpenFlags, MMIO_PROC_32A); +} + +/************************************************************************** + * mmioClose [WINMM.@] + */ +MMRESULT WINAPI mmioClose(HMMIO hmmio, UINT uFlags) +{ + LPWINE_MMIO wm; + MMRESULT result; + + TRACE("(%p, %04X);\n", hmmio, uFlags); + + if ((wm = MMIO_Get(hmmio)) == NULL) + return MMSYSERR_INVALHANDLE; + + if ((result = MMIO_Flush(wm, 0)) != MMSYSERR_NOERROR) + return result; + + result = send_message(wm->ioProc, &wm->info, MMIOM_CLOSE, + uFlags, 0, MMIO_PROC_32A); + + MMIO_SetBuffer(wm, NULL, 0, 0); + + wm->ioProc->count--; + + if (wm->bTmpIOProc) + MMIO_InstallIOProc(wm->info.fccIOProc, wm->ioProc->pIOProc, + MMIO_REMOVEPROC, wm->ioProc->type); + + MMIO_Destroy(wm); + + return result; +} + +/************************************************************************** + * mmioRead [WINMM.@] + */ +LONG WINAPI mmioRead(HMMIO hmmio, HPSTR pch, LONG cch) +{ + LPWINE_MMIO wm; + LONG count; + + TRACE("(%p, %p, %ld);\n", hmmio, pch, cch); + + if ((wm = MMIO_Get(hmmio)) == NULL) + return -1; + + /* unbuffered case first */ + if (!wm->info.pchBuffer) + return send_message(wm->ioProc, &wm->info, MMIOM_READ, + (LPARAM)pch, cch, MMIO_PROC_32A); + + /* first try from current buffer */ + if (wm->info.pchNext != wm->info.pchEndRead) { + count = wm->info.pchEndRead - wm->info.pchNext; + if (count > cch || count < 0) count = cch; + memcpy(pch, wm->info.pchNext, count); + wm->info.pchNext += count; + pch += count; + cch -= count; + } else + count = 0; + + if (cch && (wm->info.fccIOProc != FOURCC_MEM)) { + assert(wm->info.cchBuffer); + + while (cch) { + LONG size; + + size = MMIO_GrabNextBuffer(wm, TRUE); + if (size <= 0) break; + if (size > cch) size = cch; + memcpy(pch, wm->info.pchBuffer, size); + wm->info.pchNext += size; + pch += size; + cch -= size; + count += size; + } + } + + TRACE("count=%ld\n", count); + return count; +} + +/************************************************************************** + * mmioWrite [WINMM.@] + */ +LONG WINAPI mmioWrite(HMMIO hmmio, HPCSTR pch, LONG cch) +{ + LPWINE_MMIO wm; + LONG count; + + TRACE("(%p, %p, %ld);\n", hmmio, pch, cch); + + if ((wm = MMIO_Get(hmmio)) == NULL) + return -1; + + if (wm->info.cchBuffer) { + LONG bytesW = 0; + + count = 0; + while (cch) { + if (wm->info.pchNext != wm->info.pchEndWrite) { + count = wm->info.pchEndWrite - wm->info.pchNext; + if (count > cch || count < 0) count = cch; + memcpy(wm->info.pchNext, pch, count); + wm->info.pchNext += count; + pch += count; + cch -= count; + bytesW += count; + wm->info.dwFlags |= MMIO_DIRTY; + } else { + if (wm->info.fccIOProc == FOURCC_MEM) { + if (wm->info.adwInfo[0]) { + /* from where would we get the memory handle? */ + FIXME("memory file expansion not implemented!\n"); + break; + } else break; + } + } + + if (wm->info.pchNext == wm->info.pchEndWrite) + { + MMIO_Flush(wm, MMIO_EMPTYBUF); + MMIO_GrabNextBuffer(wm, FALSE); + } + else break; + } + count = bytesW; + } else { + count = send_message(wm->ioProc, &wm->info, MMIOM_WRITE, + (LPARAM)pch, cch, MMIO_PROC_32A); + wm->info.lBufOffset = wm->info.lDiskOffset; + } + + TRACE("bytes written=%ld\n", count); + return count; +} + +/************************************************************************** + * mmioSeek [WINMM.@] + */ +LONG WINAPI mmioSeek(HMMIO hmmio, LONG lOffset, INT iOrigin) +{ + LPWINE_MMIO wm; + LONG offset; + + TRACE("(%p, %08lX, %d);\n", hmmio, lOffset, iOrigin); + + if ((wm = MMIO_Get(hmmio)) == NULL) + return MMSYSERR_INVALHANDLE; + + /* not buffered, direct seek on file */ + if (!wm->info.pchBuffer) + return send_message(wm->ioProc, &wm->info, MMIOM_SEEK, + lOffset, iOrigin, MMIO_PROC_32A); + + switch (iOrigin) { + case SEEK_SET: + offset = lOffset; + break; + case SEEK_CUR: + offset = wm->info.lBufOffset + (wm->info.pchNext - wm->info.pchBuffer) + lOffset; + break; + case SEEK_END: + offset = ((wm->info.fccIOProc == FOURCC_MEM)? wm->info.cchBuffer : wm->dwFileSize) - lOffset; + break; + default: + return -1; + } + + if (offset && offset >= wm->dwFileSize && wm->info.fccIOProc != FOURCC_MEM) { + /* should check that write mode exists */ + if (MMIO_Flush(wm, 0) != MMSYSERR_NOERROR) + return -1; + wm->info.lBufOffset = offset; + wm->info.pchEndRead = wm->info.pchBuffer; + wm->info.pchEndWrite = wm->info.pchBuffer + wm->info.cchBuffer; + if ((wm->info.dwFlags & MMIO_RWMODE) == MMIO_READ) { + wm->info.lDiskOffset = wm->dwFileSize; + } + } else if ((wm->info.cchBuffer > 0) && + ((offset < wm->info.lBufOffset) || + (offset >= wm->info.lBufOffset + wm->info.cchBuffer) || + !wm->bBufferLoaded)) { + /* stay in same buffer ? */ + /* some memory mapped buffers are defined with -1 as a size */ + + /* condition to change buffer */ + if ((wm->info.fccIOProc == FOURCC_MEM) || + MMIO_Flush(wm, 0) != MMSYSERR_NOERROR || + /* this also sets the wm->info.lDiskOffset field */ + send_message(wm->ioProc, &wm->info, MMIOM_SEEK, + (offset / wm->info.cchBuffer) * wm->info.cchBuffer, + SEEK_SET, MMIO_PROC_32A) == -1) + return -1; + MMIO_GrabNextBuffer(wm, TRUE); + } + + wm->info.pchNext = wm->info.pchBuffer + (offset - wm->info.lBufOffset); + + TRACE("=> %ld\n", offset); + return offset; +} + +/************************************************************************** + * mmioGetInfo [WINMM.@] + */ +MMRESULT WINAPI mmioGetInfo(HMMIO hmmio, MMIOINFO* lpmmioinfo, UINT uFlags) +{ + LPWINE_MMIO wm; + + TRACE("(%p,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags); + + if ((wm = MMIO_Get(hmmio)) == NULL) + return MMSYSERR_INVALHANDLE; + + memcpy(lpmmioinfo, &wm->info, sizeof(MMIOINFO)); + /* don't expose 16 bit ioproc:s */ + if (wm->ioProc->type != MMIO_PROC_16) + lpmmioinfo->pIOProc = wm->ioProc->pIOProc; + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * mmioSetInfo [WINMM.@] + */ +MMRESULT WINAPI mmioSetInfo(HMMIO hmmio, const MMIOINFO* lpmmioinfo, UINT uFlags) +{ + LPWINE_MMIO wm; + + TRACE("(%p,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags); + + if ((wm = MMIO_Get(hmmio)) == NULL) + return MMSYSERR_INVALHANDLE; + + /* check pointers coherence */ + if (lpmmioinfo->pchNext < wm->info.pchBuffer || + lpmmioinfo->pchNext > wm->info.pchBuffer + wm->info.cchBuffer || + lpmmioinfo->pchEndRead < wm->info.pchBuffer || + lpmmioinfo->pchEndRead > wm->info.pchBuffer + wm->info.cchBuffer || + lpmmioinfo->pchEndWrite < wm->info.pchBuffer || + lpmmioinfo->pchEndWrite > wm->info.pchBuffer + wm->info.cchBuffer) + return MMSYSERR_INVALPARAM; + + wm->info.pchNext = lpmmioinfo->pchNext; + wm->info.pchEndRead = lpmmioinfo->pchEndRead; + + return MMSYSERR_NOERROR; +} + +/************************************************************************** +* mmioSetBuffer [WINMM.@] +*/ +MMRESULT WINAPI mmioSetBuffer(HMMIO hmmio, LPSTR pchBuffer, LONG cchBuffer, UINT uFlags) +{ + LPWINE_MMIO wm; + + TRACE("(hmmio=%p, pchBuf=%p, cchBuf=%ld, uFlags=%#08x)\n", + hmmio, pchBuffer, cchBuffer, uFlags); + + if ((wm = MMIO_Get(hmmio)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMIO_SetBuffer(wm, pchBuffer, cchBuffer, uFlags); +} + +/************************************************************************** + * mmioFlush [WINMM.@] + */ +MMRESULT WINAPI mmioFlush(HMMIO hmmio, UINT uFlags) +{ + LPWINE_MMIO wm; + + TRACE("(%p, %04X)\n", hmmio, uFlags); + + if ((wm = MMIO_Get(hmmio)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMIO_Flush(wm, uFlags); +} + +/************************************************************************** + * mmioAdvance [WINMM.@] + */ +MMRESULT WINAPI mmioAdvance(HMMIO hmmio, MMIOINFO* lpmmioinfo, UINT uFlags) +{ + LPWINE_MMIO wm; + + TRACE("hmmio=%p, lpmmioinfo=%p, uFlags=%04X\n", hmmio, lpmmioinfo, uFlags); + + /* NOTE: mmioAdvance16 heavily relies on parameters from lpmmioinfo we're using + * here. be sure if you change something here to check mmioAdvance16 as well + */ + if ((wm = MMIO_Get(hmmio)) == NULL) + return MMSYSERR_INVALHANDLE; + + if (!wm->info.cchBuffer) + return MMIOERR_UNBUFFERED; + + if (uFlags != MMIO_READ && uFlags != MMIO_WRITE) + return MMSYSERR_INVALPARAM; + + if (uFlags == MMIO_WRITE && (lpmmioinfo->dwFlags & MMIO_DIRTY)) + { + send_message(wm->ioProc, &wm->info, MMIOM_SEEK, + lpmmioinfo->lBufOffset, SEEK_SET, MMIO_PROC_32A); + send_message(wm->ioProc, &wm->info, MMIOM_WRITE, + (LPARAM)lpmmioinfo->pchBuffer, + lpmmioinfo->pchNext - lpmmioinfo->pchBuffer, MMIO_PROC_32A); + lpmmioinfo->dwFlags &= ~MMIO_DIRTY; + } + if (MMIO_Flush(wm, 0) != MMSYSERR_NOERROR) + return MMIOERR_CANNOTWRITE; + + if (lpmmioinfo) { + wm->dwFileSize = max(wm->dwFileSize, lpmmioinfo->lBufOffset + + (lpmmioinfo->pchNext - lpmmioinfo->pchBuffer)); + } + MMIO_GrabNextBuffer(wm, uFlags == MMIO_READ); + + if (lpmmioinfo) { + lpmmioinfo->pchNext = lpmmioinfo->pchBuffer; + lpmmioinfo->pchEndRead = lpmmioinfo->pchBuffer + + (wm->info.pchEndRead - wm->info.pchBuffer); + lpmmioinfo->pchEndWrite = lpmmioinfo->pchBuffer + + (wm->info.pchEndWrite - wm->info.pchBuffer); + lpmmioinfo->lDiskOffset = wm->info.lDiskOffset; + lpmmioinfo->lBufOffset = wm->info.lBufOffset; + } + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * mmioStringToFOURCCA [WINMM.@] + */ +FOURCC WINAPI mmioStringToFOURCCA(LPCSTR sz, UINT uFlags) +{ + CHAR cc[4]; + int i = 0; + + for (i = 0; i < 4 && sz[i]; i++) { + if (uFlags & MMIO_TOUPPER) { + cc[i] = toupper(sz[i]); + } else { + cc[i] = sz[i]; + } + } + + /* Pad with spaces */ + while (i < 4) cc[i++] = ' '; + + TRACE("Got '%.4s'\n",cc); + return mmioFOURCC(cc[0],cc[1],cc[2],cc[3]); +} + +/************************************************************************** + * mmioStringToFOURCCW [WINMM.@] + */ +FOURCC WINAPI mmioStringToFOURCCW(LPCWSTR sz, UINT uFlags) +{ + char szA[4]; + + WideCharToMultiByte( CP_ACP, 0, sz, 4, szA, sizeof(szA), NULL, NULL ); + return mmioStringToFOURCCA(szA,uFlags); +} + +/************************************************************************** + * mmioInstallIOProcA [WINMM.@] + */ +LPMMIOPROC WINAPI mmioInstallIOProcA(FOURCC fccIOProc, + LPMMIOPROC pIOProc, DWORD dwFlags) +{ + return MMIO_InstallIOProc(fccIOProc, pIOProc, dwFlags, MMIO_PROC_32A); +} + +/************************************************************************** + * mmioInstallIOProcW [WINMM.@] + */ +LPMMIOPROC WINAPI mmioInstallIOProcW(FOURCC fccIOProc, + LPMMIOPROC pIOProc, DWORD dwFlags) +{ + return MMIO_InstallIOProc(fccIOProc, pIOProc, dwFlags, MMIO_PROC_32W); +} + +/****************************************************************** + * MMIO_SendMessage + * + * + */ +LRESULT MMIO_SendMessage(HMMIO hmmio, UINT uMessage, LPARAM lParam1, + LPARAM lParam2, enum mmioProcType type) +{ + LPWINE_MMIO wm; + + TRACE("(%p, %u, %ld, %ld, %d)\n", hmmio, uMessage, lParam1, lParam2, type); + + if (uMessage < MMIOM_USER) + return MMSYSERR_INVALPARAM; + + if ((wm = MMIO_Get(hmmio)) == NULL) + return MMSYSERR_INVALHANDLE; + + return send_message(wm->ioProc, &wm->info, uMessage, lParam1, lParam2, type); +} + +/************************************************************************** + * mmioSendMessage [WINMM.@] + */ +LRESULT WINAPI mmioSendMessage(HMMIO hmmio, UINT uMessage, + LPARAM lParam1, LPARAM lParam2) +{ + return MMIO_SendMessage(hmmio, uMessage, lParam1, lParam2, MMIO_PROC_32A); +} + +/************************************************************************** + * mmioDescend [WINMM.@] + */ +MMRESULT WINAPI mmioDescend(HMMIO hmmio, LPMMCKINFO lpck, + const MMCKINFO* lpckParent, UINT uFlags) +{ + DWORD dwOldPos; + FOURCC srchCkId; + FOURCC srchType; + + + TRACE("(%p, %p, %p, %04X);\n", hmmio, lpck, lpckParent, uFlags); + + if (lpck == NULL) + return MMSYSERR_INVALPARAM; + + dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR); + TRACE("dwOldPos=%ld\n", dwOldPos); + + if (lpckParent != NULL) { + TRACE("seek inside parent at %ld !\n", lpckParent->dwDataOffset); + /* EPP: was dwOldPos = mmioSeek(hmmio,lpckParent->dwDataOffset,SEEK_SET); */ + if (dwOldPos < lpckParent->dwDataOffset || + dwOldPos >= lpckParent->dwDataOffset + lpckParent->cksize) { + WARN("outside parent chunk\n"); + return MMIOERR_CHUNKNOTFOUND; + } + } + + /* The SDK docu says 'ckid' is used for all cases. Real World + * examples disagree -Marcus,990216. + */ + + srchType = 0; + /* find_chunk looks for 'ckid' */ + if (uFlags & MMIO_FINDCHUNK) + srchCkId = lpck->ckid; + /* find_riff and find_list look for 'fccType' */ + if (uFlags & MMIO_FINDLIST) { + srchCkId = FOURCC_LIST; + srchType = lpck->fccType; + } + if (uFlags & MMIO_FINDRIFF) { + srchCkId = FOURCC_RIFF; + srchType = lpck->fccType; + } + + if (uFlags & (MMIO_FINDCHUNK|MMIO_FINDLIST|MMIO_FINDRIFF)) { + TRACE("searching for %.4s.%.4s\n", + (LPSTR)&srchCkId, + srchType?(LPSTR)&srchType:"any "); + + while (TRUE) { + LONG ix; + + ix = mmioRead(hmmio, (LPSTR)lpck, 3 * sizeof(DWORD)); + if (ix < 2*sizeof(DWORD)) { + mmioSeek(hmmio, dwOldPos, SEEK_SET); + WARN("return ChunkNotFound\n"); + return MMIOERR_CHUNKNOTFOUND; + } + lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD); + if (ix < lpck->dwDataOffset - dwOldPos) { + mmioSeek(hmmio, dwOldPos, SEEK_SET); + WARN("return ChunkNotFound\n"); + return MMIOERR_CHUNKNOTFOUND; + } + TRACE("ckid=%.4s fcc=%.4s cksize=%08lX !\n", + (LPSTR)&lpck->ckid, + srchType?(LPSTR)&lpck->fccType:"<na>", + lpck->cksize); + if ((srchCkId == lpck->ckid) && + (!srchType || (srchType == lpck->fccType)) + ) + break; + + dwOldPos = lpck->dwDataOffset + ((lpck->cksize + 1) & ~1); + mmioSeek(hmmio, dwOldPos, SEEK_SET); + } + } else { + /* FIXME: unverified, does it do this? */ + /* NB: This part is used by WAVE_mciOpen, among others */ + if (mmioRead(hmmio, (LPSTR)lpck, 3 * sizeof(DWORD)) < 3 * sizeof(DWORD)) { + mmioSeek(hmmio, dwOldPos, SEEK_SET); + WARN("return ChunkNotFound 2nd\n"); + return MMIOERR_CHUNKNOTFOUND; + } + lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD); + } + lpck->dwFlags = 0; + /* If we were looking for RIFF/LIST chunks, the final file position + * is after the chunkid. If we were just looking for the chunk + * it is after the cksize. So add 4 in RIFF/LIST case. + */ + if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST) + mmioSeek(hmmio, lpck->dwDataOffset + sizeof(DWORD), SEEK_SET); + else + mmioSeek(hmmio, lpck->dwDataOffset, SEEK_SET); + TRACE("lpck: ckid=%.4s, cksize=%ld, dwDataOffset=%ld fccType=%08lX (%.4s)!\n", + (LPSTR)&lpck->ckid, lpck->cksize, lpck->dwDataOffset, + lpck->fccType, srchType?(LPSTR)&lpck->fccType:""); + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * mmioAscend [WINMM.@] + */ +MMRESULT WINAPI mmioAscend(HMMIO hmmio, LPMMCKINFO lpck, UINT uFlags) +{ + TRACE("(%p, %p, %04X);\n", hmmio, lpck, uFlags); + + if (lpck->dwFlags & MMIO_DIRTY) { + DWORD dwOldPos, dwNewSize; + + TRACE("Chunk is dirty, checking if chunk's size is correct\n"); + dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR); + TRACE("dwOldPos=%ld lpck->dwDataOffset = %ld\n", dwOldPos, lpck->dwDataOffset); + dwNewSize = dwOldPos - lpck->dwDataOffset; + if (dwNewSize != lpck->cksize) { + TRACE("Nope: lpck->cksize=%ld dwNewSize=%ld\n", lpck->cksize, dwNewSize); + lpck->cksize = dwNewSize; + + /* pad odd size with 0 */ + if (dwNewSize & 1) { + char ch = 0; + mmioWrite(hmmio, &ch, 1); + } + mmioSeek(hmmio, lpck->dwDataOffset - sizeof(DWORD), SEEK_SET); + mmioWrite(hmmio, (LPSTR)&dwNewSize, sizeof(DWORD)); + } + lpck->dwFlags = 0; + } + + mmioSeek(hmmio, lpck->dwDataOffset + ((lpck->cksize + 1) & ~1), SEEK_SET); + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * mmioCreateChunk [WINMM.@] + */ +MMRESULT WINAPI mmioCreateChunk(HMMIO hmmio, MMCKINFO* lpck, UINT uFlags) +{ + DWORD dwOldPos; + LONG size; + LONG ix; + + TRACE("(%p, %p, %04X);\n", hmmio, lpck, uFlags); + + dwOldPos = mmioSeek(hmmio, 0, SEEK_CUR); + TRACE("dwOldPos=%ld\n", dwOldPos); + + if (uFlags == MMIO_CREATELIST) + lpck->ckid = FOURCC_LIST; + else if (uFlags == MMIO_CREATERIFF) + lpck->ckid = FOURCC_RIFF; + + TRACE("ckid=%.4s\n", (LPSTR)&lpck->ckid); + + size = 2 * sizeof(DWORD); + lpck->dwDataOffset = dwOldPos + size; + + if (lpck->ckid == FOURCC_RIFF || lpck->ckid == FOURCC_LIST) + size += sizeof(DWORD); + lpck->dwFlags = MMIO_DIRTY; + + ix = mmioWrite(hmmio, (LPSTR)lpck, size); + TRACE("after mmioWrite ix = %ld req = %ld, errno = %d\n",ix, size, errno); + if (ix < size) { + mmioSeek(hmmio, dwOldPos, SEEK_SET); + WARN("return CannotWrite\n"); + return MMIOERR_CANNOTWRITE; + } + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * mmioRenameA [WINMM.@] + */ +MMRESULT WINAPI mmioRenameA(LPCSTR szFileName, LPCSTR szNewFileName, + const MMIOINFO* lpmmioinfo, DWORD dwFlags) +{ + struct IOProcList* ioProc = NULL; + struct IOProcList tmp; + FOURCC fcc; + + TRACE("('%s', '%s', %p, %08lX);\n", + debugstr_a(szFileName), debugstr_a(szNewFileName), lpmmioinfo, dwFlags); + + /* If both params are NULL, then parse the file name */ + if (lpmmioinfo && lpmmioinfo->fccIOProc == 0 && lpmmioinfo->pIOProc == NULL) + { + fcc = MMIO_ParseExtA(szFileName); + if (fcc) ioProc = MMIO_FindProcNode(fcc); + } + + /* Handle any unhandled/error case from above. Assume DOS file */ + if (!lpmmioinfo || (lpmmioinfo->fccIOProc == 0 && lpmmioinfo->pIOProc == NULL && ioProc == NULL)) + ioProc = MMIO_FindProcNode(FOURCC_DOS); + /* if just the four character code is present, look up IO proc */ + else if (lpmmioinfo->pIOProc == NULL) + ioProc = MMIO_FindProcNode(lpmmioinfo->fccIOProc); + else /* use relevant ioProc */ + { + ioProc = &tmp; + tmp.fourCC = lpmmioinfo->fccIOProc; + tmp.pIOProc = lpmmioinfo->pIOProc; + tmp.type = MMIO_PROC_32A; + tmp.count = 1; + } + + /* FIXME: should we actually pass lpmmioinfo down the drain ??? + * or make a copy of it because it's const ??? + */ + return send_message(ioProc, (MMIOINFO*)lpmmioinfo, MMIOM_RENAME, + (LPARAM)szFileName, (LPARAM)szNewFileName, MMIO_PROC_32A); +} + +/************************************************************************** + * mmioRenameW [WINMM.@] + */ +MMRESULT WINAPI mmioRenameW(LPCWSTR szFileName, LPCWSTR szNewFileName, + const MMIOINFO* lpmmioinfo, DWORD dwFlags) +{ + LPSTR szFn = NULL; + LPSTR sznFn = NULL; + UINT ret = MMSYSERR_NOMEM; + INT len; + + if (szFileName) + { + len = WideCharToMultiByte( CP_ACP, 0, szFileName, -1, NULL, 0, NULL, NULL ); + szFn = HeapAlloc( GetProcessHeap(), 0, len ); + if (!szFn) goto done; + WideCharToMultiByte( CP_ACP, 0, szFileName, -1, szFn, len, NULL, NULL ); + } + if (szNewFileName) + { + len = WideCharToMultiByte( CP_ACP, 0, szNewFileName, -1, NULL, 0, NULL, NULL ); + sznFn = HeapAlloc( GetProcessHeap(), 0, len ); + if (!sznFn) goto done; + WideCharToMultiByte( CP_ACP, 0, szNewFileName, -1, sznFn, len, NULL, NULL ); + } + + ret = mmioRenameA(szFn, sznFn, lpmmioinfo, dwFlags); + +done: + HeapFree(GetProcessHeap(),0,szFn); + HeapFree(GetProcessHeap(),0,sznFn); + return ret; +} diff --git a/reactos/lib/winmm/mmsystem.c b/reactos/lib/winmm/mmsystem.c index 04a85fe3696..d831d536c07 100644 --- a/reactos/lib/winmm/mmsystem.c +++ b/reactos/lib/winmm/mmsystem.c @@ -1,3216 +1,3216 @@ -/* -*- tab-width: 8; c-basic-offset: 4 -*- */ - -/* - * MMSYTEM functions - * - * Copyright 1993 Martin Ayotte - * 1998-2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * Eric POUECH : - * 99/4 added mmTask and mmThread functions support - */ - -#include <stdarg.h> -#include <string.h> - -#define NONAMELESSUNION -#define NONAMELESSSTRUCT -#include "windef.h" -#include "winbase.h" -#include "mmsystem.h" -#include "winreg.h" -#include "ntstatus.h" -#include "winternl.h" -#include "wownt32.h" -#include "winnls.h" - -#include "wine/winuser16.h" -#include "winemm16.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mmsys); - -static WINE_MMTHREAD* WINMM_GetmmThread(HANDLE16); -static LPWINE_DRIVER DRIVER_OpenDriver16(LPCWSTR, LPCWSTR, LPARAM); -static LRESULT DRIVER_CloseDriver16(HDRVR16, LPARAM, LPARAM); -static LRESULT DRIVER_SendMessage16(HDRVR16, UINT, LPARAM, LPARAM); -static LRESULT MMIO_Callback16(SEGPTR, LPMMIOINFO, UINT, LPARAM, LPARAM); - -/* ################################################### - * # LIBRARY # - * ################################################### - */ - -/************************************************************************** - * DllEntryPoint (MMSYSTEM.4) - * - * MMSYSTEM DLL entry point - * - */ -BOOL WINAPI MMSYSTEM_LibMain(DWORD fdwReason, HINSTANCE hinstDLL, WORD ds, - WORD wHeapSize, DWORD dwReserved1, WORD wReserved2) -{ - TRACE("%p 0x%lx\n", hinstDLL, fdwReason); - - switch (fdwReason) { - case DLL_PROCESS_ATTACH: - /* need to load WinMM in order to: - * - initiate correctly shared variables (WINMM_Init()) - */ - if (!GetModuleHandleA("WINMM.DLL")) - { - ERR("Could not load sibling WinMM.dll\n"); - return FALSE; - } - WINMM_IData.hWinMM16Instance = hinstDLL; - /* hook in our 16 bit function pointers */ - pFnGetMMThread16 = WINMM_GetmmThread; - pFnOpenDriver16 = DRIVER_OpenDriver16; - pFnCloseDriver16 = DRIVER_CloseDriver16; - pFnSendMessage16 = DRIVER_SendMessage16; - pFnMmioCallback16 = MMIO_Callback16; - pFnReleaseThunkLock = ReleaseThunkLock; - pFnRestoreThunkLock = RestoreThunkLock; - MMDRV_Init16(); - break; - case DLL_PROCESS_DETACH: - WINMM_IData.hWinMM16Instance = 0; - pFnGetMMThread16 = NULL; - pFnOpenDriver16 = NULL; - pFnCloseDriver16 = NULL; - pFnSendMessage16 = NULL; - pFnMmioCallback16 = NULL; - pFnReleaseThunkLock = NULL; - pFnRestoreThunkLock = NULL; - /* FIXME: add equivalent for MMDRV_Init16() */ - break; - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - break; - } - return TRUE; -} - -/************************************************************************** - * MMSYSTEM_WEP [MMSYSTEM.1] - */ -int WINAPI MMSYSTEM_WEP(HINSTANCE16 hInstance, WORD wDataSeg, - WORD cbHeapSize, LPSTR lpCmdLine) -{ - TRACE("STUB: Unloading MMSystem DLL ... hInst=%04X \n", hInstance); - return TRUE; -} - -/* ################################################### - * # PlaySound # - * ################################################### - */ - -/************************************************************************** - * PlaySound [MMSYSTEM.3] - */ -BOOL16 WINAPI PlaySound16(LPCSTR pszSound, HMODULE16 hmod, DWORD fdwSound) -{ - BOOL16 retv; - DWORD lc; - - if ((fdwSound & SND_RESOURCE) == SND_RESOURCE) - { - HGLOBAL16 handle; - HRSRC16 res; - - if (!(res = FindResource16( hmod, pszSound, "WAVE" ))) return FALSE; - if (!(handle = LoadResource16( hmod, res ))) return FALSE; - pszSound = LockResource16(handle); - fdwSound = (fdwSound & ~SND_RESOURCE) | SND_MEMORY; - /* FIXME: FreeResource16 */ - } - - ReleaseThunkLock(&lc); - retv = PlaySoundA(pszSound, 0, fdwSound); - RestoreThunkLock(lc); - - return retv; -} - -/************************************************************************** - * sndPlaySound [MMSYSTEM.2] - */ -BOOL16 WINAPI sndPlaySound16(LPCSTR lpszSoundName, UINT16 uFlags) -{ - BOOL16 retv; - DWORD lc; - - ReleaseThunkLock(&lc); - retv = sndPlaySoundA(lpszSoundName, uFlags); - RestoreThunkLock(lc); - - return retv; -} - -/* ################################################### - * # MISC # - * ################################################### - */ - -/************************************************************************** - * mmsystemGetVersion [MMSYSTEM.5] - * - */ -UINT16 WINAPI mmsystemGetVersion16(void) -{ - return mmsystemGetVersion(); -} - -/************************************************************************** - * DriverCallback [MMSYSTEM.31] - */ -BOOL16 WINAPI DriverCallback16(DWORD dwCallBack, UINT16 uFlags, HDRVR16 hDev, - WORD wMsg, DWORD dwUser, DWORD dwParam1, - DWORD dwParam2) -{ - return DriverCallback(dwCallBack, uFlags, HDRVR_32(hDev), wMsg, dwUser, dwParam1, dwParam2); -} - -/************************************************************************** - * OutputDebugStr [MMSYSTEM.30] - */ -void WINAPI OutputDebugStr16(LPCSTR str) -{ - OutputDebugStringA( str ); -} - - -/* ################################################### - * # MIXER # - * ################################################### - */ - -/************************************************************************** - * Mixer devices. New to Win95 - */ - -/************************************************************************** - * mixerGetNumDevs [MMSYSTEM.800] - */ -UINT16 WINAPI mixerGetNumDevs16(void) -{ - return MMDRV_GetNum(MMDRV_MIXER); -} - -/************************************************************************** - * mixerGetDevCaps [MMSYSTEM.801] - */ -UINT16 WINAPI mixerGetDevCaps16(UINT16 uDeviceID, LPMIXERCAPS16 lpCaps, - UINT16 uSize) -{ - MIXERCAPSA micA; - UINT ret; - - if (lpCaps == NULL) return MMSYSERR_INVALPARAM; - - ret = mixerGetDevCapsA(uDeviceID, &micA, sizeof(micA)); - if (ret == MMSYSERR_NOERROR) { - MIXERCAPS16 mic16; - mic16.wMid = micA.wMid; - mic16.wPid = micA.wPid; - mic16.vDriverVersion = micA.vDriverVersion; - strcpy(mic16.szPname, micA.szPname); - mic16.fdwSupport = micA.fdwSupport; - mic16.cDestinations = micA.cDestinations; - memcpy(lpCaps, &mic16, min(uSize, sizeof(mic16))); - } - return ret; -} - -/************************************************************************** - * mixerOpen [MMSYSTEM.802] - */ -UINT16 WINAPI mixerOpen16(LPHMIXER16 lphmix, UINT16 uDeviceID, DWORD dwCallback, - DWORD dwInstance, DWORD fdwOpen) -{ - HMIXER hmix; - UINT ret; - - ret = MIXER_Open(&hmix, uDeviceID, dwCallback, dwInstance, fdwOpen, FALSE); - if (lphmix) *lphmix = HMIXER_16(hmix); - return ret; -} - -/************************************************************************** - * mixerClose [MMSYSTEM.803] - */ -UINT16 WINAPI mixerClose16(HMIXER16 hMix) -{ - return mixerClose(HMIXER_32(hMix)); -} - -/************************************************************************** - * mixerGetID (MMSYSTEM.806) - */ -UINT16 WINAPI mixerGetID16(HMIXEROBJ16 hmix, LPUINT16 lpid, DWORD fdwID) -{ - UINT xid; - UINT ret = mixerGetID(HMIXEROBJ_32(hmix), &xid, fdwID); - - if (lpid) - *lpid = xid; - return ret; -} - -/************************************************************************** - * mixerGetControlDetails [MMSYSTEM.808] - */ -UINT16 WINAPI mixerGetControlDetails16(HMIXEROBJ16 hmix, - LPMIXERCONTROLDETAILS16 lpmcd, - DWORD fdwDetails) -{ - DWORD ret = MMSYSERR_NOTENABLED; - SEGPTR sppaDetails; - - TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails); - - if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd)) - return MMSYSERR_INVALPARAM; - - sppaDetails = (SEGPTR)lpmcd->paDetails; - lpmcd->paDetails = MapSL(sppaDetails); - ret = mixerGetControlDetailsA(HMIXEROBJ_32(hmix), - (LPMIXERCONTROLDETAILS)lpmcd, fdwDetails); - lpmcd->paDetails = (LPVOID)sppaDetails; - - return ret; -} - -/************************************************************************** - * mixerGetLineControls [MMSYSTEM.807] - */ -UINT16 WINAPI mixerGetLineControls16(HMIXEROBJ16 hmix, - LPMIXERLINECONTROLS16 lpmlc16, - DWORD fdwControls) -{ - MIXERLINECONTROLSA mlcA; - DWORD ret; - unsigned int i; - LPMIXERCONTROL16 lpmc16; - - TRACE("(%04x, %p, %08lx)\n", hmix, lpmlc16, fdwControls); - - if (lpmlc16 == NULL || lpmlc16->cbStruct != sizeof(*lpmlc16) || - lpmlc16->cbmxctrl != sizeof(MIXERCONTROL16)) - return MMSYSERR_INVALPARAM; - - mlcA.cbStruct = sizeof(mlcA); - mlcA.dwLineID = lpmlc16->dwLineID; - mlcA.u.dwControlID = lpmlc16->u.dwControlID; - mlcA.u.dwControlType = lpmlc16->u.dwControlType; - mlcA.cControls = lpmlc16->cControls; - mlcA.cbmxctrl = sizeof(MIXERCONTROLA); - mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0, - mlcA.cControls * mlcA.cbmxctrl); - - ret = mixerGetLineControlsA(HMIXEROBJ_32(hmix), &mlcA, fdwControls); - - if (ret == MMSYSERR_NOERROR) { - lpmlc16->dwLineID = mlcA.dwLineID; - lpmlc16->u.dwControlID = mlcA.u.dwControlID; - lpmlc16->u.dwControlType = mlcA.u.dwControlType; - lpmlc16->cControls = mlcA.cControls; - - lpmc16 = MapSL(lpmlc16->pamxctrl); - - for (i = 0; i < mlcA.cControls; i++) { - lpmc16[i].cbStruct = sizeof(MIXERCONTROL16); - lpmc16[i].dwControlID = mlcA.pamxctrl[i].dwControlID; - lpmc16[i].dwControlType = mlcA.pamxctrl[i].dwControlType; - lpmc16[i].fdwControl = mlcA.pamxctrl[i].fdwControl; - lpmc16[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems; - strcpy(lpmc16[i].szShortName, mlcA.pamxctrl[i].szShortName); - strcpy(lpmc16[i].szName, mlcA.pamxctrl[i].szName); - /* sizeof(lpmc16[i].Bounds) == sizeof(mlcA.pamxctrl[i].Bounds) */ - memcpy(&lpmc16[i].Bounds, &mlcA.pamxctrl[i].Bounds, - sizeof(mlcA.pamxctrl[i].Bounds)); - /* sizeof(lpmc16[i].Metrics) == sizeof(mlcA.pamxctrl[i].Metrics) */ - memcpy(&lpmc16[i].Metrics, &mlcA.pamxctrl[i].Metrics, - sizeof(mlcA.pamxctrl[i].Metrics)); - } - } - - HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl); - - return ret; -} - -/************************************************************************** - * mixerGetLineInfo [MMSYSTEM.805] - */ -UINT16 WINAPI mixerGetLineInfo16(HMIXEROBJ16 hmix, LPMIXERLINE16 lpmli16, - DWORD fdwInfo) -{ - MIXERLINEA mliA; - UINT ret; - - TRACE("(%04x, %p, %08lx)\n", hmix, lpmli16, fdwInfo); - - if (lpmli16 == NULL || lpmli16->cbStruct != sizeof(*lpmli16)) - return MMSYSERR_INVALPARAM; - - mliA.cbStruct = sizeof(mliA); - switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) { - case MIXER_GETLINEINFOF_COMPONENTTYPE: - mliA.dwComponentType = lpmli16->dwComponentType; - break; - case MIXER_GETLINEINFOF_DESTINATION: - mliA.dwDestination = lpmli16->dwDestination; - break; - case MIXER_GETLINEINFOF_LINEID: - mliA.dwLineID = lpmli16->dwLineID; - break; - case MIXER_GETLINEINFOF_SOURCE: - mliA.dwDestination = lpmli16->dwDestination; - mliA.dwSource = lpmli16->dwSource; - break; - case MIXER_GETLINEINFOF_TARGETTYPE: - mliA.Target.dwType = lpmli16->Target.dwType; - mliA.Target.wMid = lpmli16->Target.wMid; - mliA.Target.wPid = lpmli16->Target.wPid; - mliA.Target.vDriverVersion = lpmli16->Target.vDriverVersion; - strcpy(mliA.Target.szPname, lpmli16->Target.szPname); - break; - default: - FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo); - } - - ret = mixerGetLineInfoA(HMIXEROBJ_32(hmix), &mliA, fdwInfo); - - lpmli16->dwDestination = mliA.dwDestination; - lpmli16->dwSource = mliA.dwSource; - lpmli16->dwLineID = mliA.dwLineID; - lpmli16->fdwLine = mliA.fdwLine; - lpmli16->dwUser = mliA.dwUser; - lpmli16->dwComponentType = mliA.dwComponentType; - lpmli16->cChannels = mliA.cChannels; - lpmli16->cConnections = mliA.cConnections; - lpmli16->cControls = mliA.cControls; - strcpy(lpmli16->szShortName, mliA.szShortName); - strcpy(lpmli16->szName, mliA.szName); - lpmli16->Target.dwType = mliA.Target.dwType; - lpmli16->Target.dwDeviceID = mliA.Target.dwDeviceID; - lpmli16->Target.wMid = mliA.Target.wMid; - lpmli16->Target.wPid = mliA.Target.wPid; - lpmli16->Target.vDriverVersion = mliA.Target.vDriverVersion; - strcpy(lpmli16->Target.szPname, mliA.Target.szPname); - - return ret; -} - -/************************************************************************** - * mixerSetControlDetails [MMSYSTEM.809] - */ -UINT16 WINAPI mixerSetControlDetails16(HMIXEROBJ16 hmix, - LPMIXERCONTROLDETAILS16 lpmcd, - DWORD fdwDetails) -{ - TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails); - return MMSYSERR_NOTENABLED; -} - -/************************************************************************** - * mixerMessage [MMSYSTEM.804] - */ -DWORD WINAPI mixerMessage16(HMIXER16 hmix, UINT16 uMsg, DWORD dwParam1, - DWORD dwParam2) -{ - return mixerMessage(HMIXER_32(hmix), uMsg, dwParam1, dwParam2); -} - -/************************************************************************** - * auxGetNumDevs [MMSYSTEM.350] - */ -UINT16 WINAPI auxGetNumDevs16(void) -{ - return MMDRV_GetNum(MMDRV_AUX); -} - -/* ################################################### - * # AUX # - * ################################################### - */ - -/************************************************************************** - * auxGetDevCaps [MMSYSTEM.351] - */ -UINT16 WINAPI auxGetDevCaps16(UINT16 uDeviceID, LPAUXCAPS16 lpCaps, UINT16 uSize) -{ - AUXCAPSA acA; - UINT ret; - - if (lpCaps == NULL) return MMSYSERR_INVALPARAM; - - ret = auxGetDevCapsA(uDeviceID, &acA, sizeof(acA)); - if (ret == MMSYSERR_NOERROR) { - AUXCAPS16 ac16; - ac16.wMid = acA.wMid; - ac16.wPid = acA.wPid; - ac16.vDriverVersion = acA.vDriverVersion; - strcpy(ac16.szPname, acA.szPname); - ac16.wTechnology = acA.wTechnology; - ac16.dwSupport = acA.dwSupport; - memcpy(lpCaps, &ac16, min(uSize, sizeof(ac16))); - } - return ret; -} - -/************************************************************************** - * auxGetVolume [MMSYSTEM.352] - */ -UINT16 WINAPI auxGetVolume16(UINT16 uDeviceID, LPDWORD lpdwVolume) -{ - LPWINE_MLD wmld; - - TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume); - - if ((wmld = MMDRV_Get((HANDLE)(ULONG_PTR)uDeviceID, MMDRV_AUX, TRUE)) == NULL) - return MMSYSERR_INVALHANDLE; - return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD_PTR)lpdwVolume, 0L, TRUE); -} - -/************************************************************************** - * auxSetVolume [MMSYSTEM.353] - */ -UINT16 WINAPI auxSetVolume16(UINT16 uDeviceID, DWORD dwVolume) -{ - LPWINE_MLD wmld; - - TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume); - - if ((wmld = MMDRV_Get((HANDLE)(ULONG_PTR)uDeviceID, MMDRV_AUX, TRUE)) == NULL) - return MMSYSERR_INVALHANDLE; - return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE); -} - -/************************************************************************** - * auxOutMessage [MMSYSTEM.354] - */ -DWORD WINAPI auxOutMessage16(UINT16 uDeviceID, UINT16 uMessage, DWORD dw1, DWORD dw2) -{ - LPWINE_MLD wmld; - - TRACE("(%04X, %04X, %08lX, %08lX)\n", uDeviceID, uMessage, dw1, dw2); - - switch (uMessage) { - case AUXDM_GETNUMDEVS: - case AUXDM_SETVOLUME: - /* no argument conversion needed */ - break; - case AUXDM_GETVOLUME: - return auxGetVolume16(uDeviceID, MapSL(dw1)); - case AUXDM_GETDEVCAPS: - return auxGetDevCaps16(uDeviceID, MapSL(dw1), dw2); - default: - TRACE("(%04x, %04x, %08lx, %08lx): unhandled message\n", - uDeviceID, uMessage, dw1, dw2); - break; - } - if ((wmld = MMDRV_Get((HANDLE)(ULONG_PTR)uDeviceID, MMDRV_AUX, TRUE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE); -} - -/* ################################################### - * # MCI # - * ################################################### - */ - -/************************************************************************** - * mciGetErrorString [MMSYSTEM.706] - */ -BOOL16 WINAPI mciGetErrorString16(DWORD wError, LPSTR lpstrBuffer, UINT16 uLength) -{ - return mciGetErrorStringA(wError, lpstrBuffer, uLength); -} - -/************************************************************************** - * mciDriverNotify [MMSYSTEM.711] - */ -BOOL16 WINAPI mciDriverNotify16(HWND16 hWndCallBack, UINT16 wDevID, UINT16 wStatus) -{ - TRACE("(%04X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus); - - return PostMessageA(HWND_32(hWndCallBack), MM_MCINOTIFY, wStatus, wDevID); -} - -/************************************************************************** - * mciGetDriverData [MMSYSTEM.708] - */ -DWORD WINAPI mciGetDriverData16(UINT16 uDeviceID) -{ - return mciGetDriverData(uDeviceID); -} - -/************************************************************************** - * mciSetDriverData [MMSYSTEM.707] - */ -BOOL16 WINAPI mciSetDriverData16(UINT16 uDeviceID, DWORD data) -{ - return mciSetDriverData(uDeviceID, data); -} - -/************************************************************************** - * mciSendCommand [MMSYSTEM.701] - */ -DWORD WINAPI mciSendCommand16(UINT16 wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2) -{ - DWORD dwRet; - - TRACE("(%04X, %s, %08lX, %08lX)\n", - wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2); - - dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, FALSE); - dwRet = MCI_CleanUp(dwRet, wMsg, (DWORD)MapSL(dwParam2)); - TRACE("=> %ld\n", dwRet); - return dwRet; -} - -/************************************************************************** - * mciGetDeviceID [MMSYSTEM.703] - */ -UINT16 WINAPI mciGetDeviceID16(LPCSTR lpstrName) -{ - TRACE("(\"%s\")\n", lpstrName); - - return mciGetDeviceIDA(lpstrName); -} - -/************************************************************************** - * mciSetYieldProc [MMSYSTEM.714] - */ -BOOL16 WINAPI mciSetYieldProc16(UINT16 uDeviceID, YIELDPROC16 fpYieldProc, DWORD dwYieldData) -{ - LPWINE_MCIDRIVER wmd; - - TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData); - - if (!(wmd = MCI_GetDriver(uDeviceID))) { - WARN("Bad uDeviceID\n"); - return FALSE; - } - - wmd->lpfnYieldProc = (YIELDPROC)fpYieldProc; - wmd->dwYieldData = dwYieldData; - wmd->bIs32 = FALSE; - - return TRUE; -} - -/************************************************************************** - * mciGetDeviceIDFromElementID [MMSYSTEM.715] - */ -UINT16 WINAPI mciGetDeviceIDFromElementID16(DWORD dwElementID, LPCSTR lpstrType) -{ - FIXME("(%lu, %s) stub\n", dwElementID, lpstrType); - return 0; -} - -/************************************************************************** - * mciGetYieldProc [MMSYSTEM.716] - */ -YIELDPROC16 WINAPI mciGetYieldProc16(UINT16 uDeviceID, DWORD* lpdwYieldData) -{ - LPWINE_MCIDRIVER wmd; - - TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData); - - if (!(wmd = MCI_GetDriver(uDeviceID))) { - WARN("Bad uDeviceID\n"); - return NULL; - } - if (!wmd->lpfnYieldProc) { - WARN("No proc set\n"); - return NULL; - } - if (wmd->bIs32) { - WARN("Proc is 32 bit\n"); - return NULL; - } - return (YIELDPROC16)wmd->lpfnYieldProc; -} - -/************************************************************************** - * mciGetCreatorTask [MMSYSTEM.717] - */ -HTASK16 WINAPI mciGetCreatorTask16(UINT16 uDeviceID) -{ - LPWINE_MCIDRIVER wmd; - HTASK16 ret = 0; - - if ((wmd = MCI_GetDriver(uDeviceID))) - ret = HTASK_16(wmd->CreatorThread); - - TRACE("(%u) => %04x\n", uDeviceID, ret); - return ret; -} - -/************************************************************************** - * mciDriverYield [MMSYSTEM.710] - */ -UINT16 WINAPI mciDriverYield16(UINT16 uDeviceID) -{ - LPWINE_MCIDRIVER wmd; - UINT16 ret = 0; - - /* TRACE("(%04x)\n", uDeviceID); */ - - if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || wmd->bIs32) { - UserYield16(); - } else { - ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData); - } - - return ret; -} - -/* ################################################### - * # MIDI # - * ################################################### - */ - -/************************************************************************** - * midiOutGetNumDevs [MMSYSTEM.201] - */ -UINT16 WINAPI midiOutGetNumDevs16(void) -{ - return MMDRV_GetNum(MMDRV_MIDIOUT); -} - -/************************************************************************** - * midiOutGetDevCaps [MMSYSTEM.202] - */ -UINT16 WINAPI midiOutGetDevCaps16(UINT16 uDeviceID, LPMIDIOUTCAPS16 lpCaps, - UINT16 uSize) -{ - MIDIOUTCAPSA mocA; - UINT ret; - - if (lpCaps == NULL) return MMSYSERR_INVALPARAM; - - ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA)); - if (ret == MMSYSERR_NOERROR) { - MIDIOUTCAPS16 moc16; - moc16.wMid = mocA.wMid; - moc16.wPid = mocA.wPid; - moc16.vDriverVersion = mocA.vDriverVersion; - strcpy(moc16.szPname, mocA.szPname); - moc16.wTechnology = mocA.wTechnology; - moc16.wVoices = mocA.wVoices; - moc16.wNotes = mocA.wNotes; - moc16.wChannelMask = mocA.wChannelMask; - moc16.dwSupport = mocA.dwSupport; - memcpy(lpCaps, &moc16, min(uSize, sizeof(moc16))); - } - return ret; - } - -/************************************************************************** - * midiOutGetErrorText [MMSYSTEM.203] - * midiInGetErrorText [MMSYSTEM.303] - */ -UINT16 WINAPI midiOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize) -{ - return midiOutGetErrorTextA(uError, lpText, uSize); -} - -/************************************************************************** - * midiOutOpen [MMSYSTEM.204] - */ -UINT16 WINAPI midiOutOpen16(HMIDIOUT16* lphMidiOut, UINT16 uDeviceID, - DWORD dwCallback, DWORD dwInstance, DWORD dwFlags) -{ - HMIDIOUT hmo; - UINT ret; - - ret = MIDI_OutOpen(&hmo, uDeviceID, dwCallback, dwInstance, dwFlags, FALSE); - - if (lphMidiOut != NULL) *lphMidiOut = HMIDIOUT_16(hmo); - return ret; -} - -/************************************************************************** - * midiOutClose [MMSYSTEM.205] - */ -UINT16 WINAPI midiOutClose16(HMIDIOUT16 hMidiOut) -{ - return midiOutClose(HMIDIOUT_32(hMidiOut)); -} - -/************************************************************************** - * midiOutPrepareHeader [MMSYSTEM.206] - */ -UINT16 WINAPI midiOutPrepareHeader16(HMIDIOUT16 hMidiOut, /* [in] */ - SEGPTR lpsegMidiOutHdr, /* [???] */ - UINT16 uSize) /* [in] */ -{ - LPWINE_MLD wmld; - - TRACE("(%04X, %08lx, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize); - - if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, MODM_PREPARE, lpsegMidiOutHdr, uSize, FALSE); -} - -/************************************************************************** - * midiOutUnprepareHeader [MMSYSTEM.207] - */ -UINT16 WINAPI midiOutUnprepareHeader16(HMIDIOUT16 hMidiOut, /* [in] */ - SEGPTR lpsegMidiOutHdr, /* [???] */ - UINT16 uSize) /* [in] */ -{ - LPWINE_MLD wmld; - LPMIDIHDR16 lpMidiOutHdr = MapSL(lpsegMidiOutHdr); - - TRACE("(%04X, %08lx, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize); - - if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) { - return MMSYSERR_NOERROR; - } - - if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, MODM_UNPREPARE, lpsegMidiOutHdr, uSize, FALSE); -} - -/************************************************************************** - * midiOutShortMsg [MMSYSTEM.208] - */ -UINT16 WINAPI midiOutShortMsg16(HMIDIOUT16 hMidiOut, DWORD dwMsg) -{ - return midiOutShortMsg(HMIDIOUT_32(hMidiOut), dwMsg); -} - -/************************************************************************** - * midiOutLongMsg [MMSYSTEM.209] - */ -UINT16 WINAPI midiOutLongMsg16(HMIDIOUT16 hMidiOut, /* [in] */ - LPMIDIHDR16 lpsegMidiOutHdr, /* [???] NOTE: SEGPTR */ - UINT16 uSize) /* [in] */ -{ - LPWINE_MLD wmld; - - TRACE("(%04X, %p, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize); - - if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD_PTR)lpsegMidiOutHdr, uSize, FALSE); -} - -/************************************************************************** - * midiOutReset [MMSYSTEM.210] - */ -UINT16 WINAPI midiOutReset16(HMIDIOUT16 hMidiOut) -{ - return midiOutReset(HMIDIOUT_32(hMidiOut)); -} - -/************************************************************************** - * midiOutGetVolume [MMSYSTEM.211] - */ -UINT16 WINAPI midiOutGetVolume16(UINT16 uDeviceID, DWORD* lpdwVolume) -{ - return midiOutGetVolume(HMIDIOUT_32(uDeviceID), lpdwVolume); -} - -/************************************************************************** - * midiOutSetVolume [MMSYSTEM.212] - */ -UINT16 WINAPI midiOutSetVolume16(UINT16 uDeviceID, DWORD dwVolume) -{ - return midiOutSetVolume(HMIDIOUT_32(uDeviceID), dwVolume); -} - -/************************************************************************** - * midiOutCachePatches [MMSYSTEM.213] - */ -UINT16 WINAPI midiOutCachePatches16(HMIDIOUT16 hMidiOut, UINT16 uBank, - WORD* lpwPatchArray, UINT16 uFlags) -{ - return midiOutCachePatches(HMIDIOUT_32(hMidiOut), uBank, lpwPatchArray, - uFlags); -} - -/************************************************************************** - * midiOutCacheDrumPatches [MMSYSTEM.214] - */ -UINT16 WINAPI midiOutCacheDrumPatches16(HMIDIOUT16 hMidiOut, UINT16 uPatch, - WORD* lpwKeyArray, UINT16 uFlags) -{ - return midiOutCacheDrumPatches(HMIDIOUT_32(hMidiOut), uPatch, lpwKeyArray, uFlags); -} - -/************************************************************************** - * midiOutGetID [MMSYSTEM.215] - */ -UINT16 WINAPI midiOutGetID16(HMIDIOUT16 hMidiOut, UINT16* lpuDeviceID) -{ - LPWINE_MLD wmld; - - TRACE("(%04X, %p)\n", hMidiOut, lpuDeviceID); - - if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM; - if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - *lpuDeviceID = wmld->uDeviceID; - return MMSYSERR_NOERROR; -} - -/************************************************************************** - * midiOutMessage [MMSYSTEM.216] - */ -DWORD WINAPI midiOutMessage16(HMIDIOUT16 hMidiOut, UINT16 uMessage, - DWORD dwParam1, DWORD dwParam2) -{ - LPWINE_MLD wmld; - - TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2); - - if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - switch (uMessage) { - case MODM_OPEN: - case MODM_CLOSE: - FIXME("can't handle OPEN or CLOSE message!\n"); - return MMSYSERR_NOTSUPPORTED; - - case MODM_GETVOLUME: - return midiOutGetVolume16(hMidiOut, MapSL(dwParam1)); - case MODM_LONGDATA: - return midiOutLongMsg16(hMidiOut, MapSL(dwParam1), dwParam2); - case MODM_PREPARE: - /* lpMidiOutHdr is still a segmented pointer for this function */ - return midiOutPrepareHeader16(hMidiOut, dwParam1, dwParam2); - case MODM_UNPREPARE: - return midiOutUnprepareHeader16(hMidiOut, dwParam1, dwParam2); - } - return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE); -} - -/************************************************************************** - * midiInGetNumDevs [MMSYSTEM.301] - */ -UINT16 WINAPI midiInGetNumDevs16(void) -{ - return MMDRV_GetNum(MMDRV_MIDIIN); -} - -/************************************************************************** - * midiInGetDevCaps [MMSYSTEM.302] - */ -UINT16 WINAPI midiInGetDevCaps16(UINT16 uDeviceID, LPMIDIINCAPS16 lpCaps, - UINT16 uSize) -{ - MIDIINCAPSA micA; - UINT ret; - - if (lpCaps == NULL) return MMSYSERR_INVALPARAM; - - ret = midiInGetDevCapsA(uDeviceID, &micA, uSize); - if (ret == MMSYSERR_NOERROR) { - MIDIINCAPS16 mic16; - mic16.wMid = micA.wMid; - mic16.wPid = micA.wPid; - mic16.vDriverVersion = micA.vDriverVersion; - strcpy(mic16.szPname, micA.szPname); - mic16.dwSupport = micA.dwSupport; - memcpy(lpCaps, &mic16, min(uSize, sizeof(mic16))); - } - return ret; -} - -/************************************************************************** - * midiInOpen [MMSYSTEM.304] - */ -UINT16 WINAPI midiInOpen16(HMIDIIN16* lphMidiIn, UINT16 uDeviceID, - DWORD dwCallback, DWORD dwInstance, DWORD dwFlags) -{ - HMIDIIN xhmid; - UINT ret; - - ret = MIDI_InOpen(&xhmid, uDeviceID, dwCallback, dwInstance, dwFlags, FALSE); - - if (lphMidiIn) *lphMidiIn = HMIDIIN_16(xhmid); - return ret; -} - -/************************************************************************** - * midiInClose [MMSYSTEM.305] - */ -UINT16 WINAPI midiInClose16(HMIDIIN16 hMidiIn) -{ - return midiInClose(HMIDIIN_32(hMidiIn)); -} - -/************************************************************************** - * midiInPrepareHeader [MMSYSTEM.306] - */ -UINT16 WINAPI midiInPrepareHeader16(HMIDIIN16 hMidiIn, /* [in] */ - SEGPTR lpsegMidiInHdr, /* [???] */ - UINT16 uSize) /* [in] */ -{ - LPWINE_MLD wmld; - - TRACE("(%04X, %08lx, %d)\n", hMidiIn, lpsegMidiInHdr, uSize); - - if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, MIDM_PREPARE, lpsegMidiInHdr, uSize, FALSE); -} - -/************************************************************************** - * midiInUnprepareHeader [MMSYSTEM.307] - */ -UINT16 WINAPI midiInUnprepareHeader16(HMIDIIN16 hMidiIn, /* [in] */ - SEGPTR lpsegMidiInHdr, /* [???] */ - UINT16 uSize) /* [in] */ -{ - LPWINE_MLD wmld; - LPMIDIHDR16 lpMidiInHdr = MapSL(lpsegMidiInHdr); - - TRACE("(%04X, %08lx, %d)\n", hMidiIn, lpsegMidiInHdr, uSize); - - if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) { - return MMSYSERR_NOERROR; - } - - if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, MIDM_UNPREPARE, lpsegMidiInHdr, uSize, FALSE); -} - -/************************************************************************** - * midiInAddBuffer [MMSYSTEM.308] - */ -UINT16 WINAPI midiInAddBuffer16(HMIDIIN16 hMidiIn, /* [in] */ - MIDIHDR16* lpsegMidiInHdr, /* [???] NOTE: SEGPTR */ - UINT16 uSize) /* [in] */ -{ - LPWINE_MLD wmld; - - TRACE("(%04X, %p, %d)\n", hMidiIn, lpsegMidiInHdr, uSize); - - if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD_PTR)lpsegMidiInHdr, uSize, FALSE); -} - -/************************************************************************** - * midiInStart [MMSYSTEM.309] - */ -UINT16 WINAPI midiInStart16(HMIDIIN16 hMidiIn) -{ - return midiInStart(HMIDIIN_32(hMidiIn)); -} - -/************************************************************************** - * midiInStop [MMSYSTEM.310] - */ -UINT16 WINAPI midiInStop16(HMIDIIN16 hMidiIn) -{ - return midiInStop(HMIDIIN_32(hMidiIn)); -} - -/************************************************************************** - * midiInReset [MMSYSTEM.311] - */ -UINT16 WINAPI midiInReset16(HMIDIIN16 hMidiIn) -{ - return midiInReset(HMIDIIN_32(hMidiIn)); -} - -/************************************************************************** - * midiInGetID [MMSYSTEM.312] - */ -UINT16 WINAPI midiInGetID16(HMIDIIN16 hMidiIn, UINT16* lpuDeviceID) -{ - LPWINE_MLD wmld; - - TRACE("(%04X, %p)\n", hMidiIn, lpuDeviceID); - - if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM; - - if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, TRUE)) == NULL) - return MMSYSERR_INVALHANDLE; - - *lpuDeviceID = wmld->uDeviceID; - - return MMSYSERR_NOERROR; -} - -/************************************************************************** - * midiInMessage [MMSYSTEM.313] - */ -DWORD WINAPI midiInMessage16(HMIDIIN16 hMidiIn, UINT16 uMessage, - DWORD dwParam1, DWORD dwParam2) -{ - LPWINE_MLD wmld; - - TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2); - - switch (uMessage) { - case MIDM_OPEN: - case MIDM_CLOSE: - FIXME("can't handle OPEN or CLOSE message!\n"); - return MMSYSERR_NOTSUPPORTED; - - case MIDM_GETDEVCAPS: - return midiInGetDevCaps16(hMidiIn, MapSL(dwParam1), dwParam2); - case MIDM_PREPARE: - return midiInPrepareHeader16(hMidiIn, dwParam1, dwParam2); - case MIDM_UNPREPARE: - return midiInUnprepareHeader16(hMidiIn, dwParam1, dwParam2); - case MIDM_ADDBUFFER: - return midiInAddBuffer16(hMidiIn, MapSL(dwParam1), dwParam2); - } - - if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, FALSE); -} - -/************************************************************************** - * midiStreamClose [MMSYSTEM.252] - */ -MMRESULT16 WINAPI midiStreamClose16(HMIDISTRM16 hMidiStrm) -{ - return midiStreamClose(HMIDISTRM_32(hMidiStrm)); -} - -/************************************************************************** - * midiStreamOpen [MMSYSTEM.251] - */ -MMRESULT16 WINAPI midiStreamOpen16(HMIDISTRM16* phMidiStrm, LPUINT16 devid, - DWORD cMidi, DWORD dwCallback, - DWORD dwInstance, DWORD fdwOpen) -{ - HMIDISTRM hMidiStrm32; - MMRESULT ret; - UINT devid32; - - if (!phMidiStrm || !devid) - return MMSYSERR_INVALPARAM; - devid32 = *devid; - ret = MIDI_StreamOpen(&hMidiStrm32, &devid32, cMidi, dwCallback, - dwInstance, fdwOpen, FALSE); - *phMidiStrm = HMIDISTRM_16(hMidiStrm32); - *devid = devid32; - return ret; -} - -/************************************************************************** - * midiStreamOut [MMSYSTEM.254] - */ -MMRESULT16 WINAPI midiStreamOut16(HMIDISTRM16 hMidiStrm, LPMIDIHDR16 lpMidiHdr, UINT16 cbMidiHdr) -{ - return midiStreamOut(HMIDISTRM_32(hMidiStrm), (LPMIDIHDR)lpMidiHdr, - cbMidiHdr); -} - -/************************************************************************** - * midiStreamPause [MMSYSTEM.255] - */ -MMRESULT16 WINAPI midiStreamPause16(HMIDISTRM16 hMidiStrm) -{ - return midiStreamPause(HMIDISTRM_32(hMidiStrm)); -} - -/************************************************************************** - * midiStreamPosition [MMSYSTEM.253] - */ -MMRESULT16 WINAPI midiStreamPosition16(HMIDISTRM16 hMidiStrm, LPMMTIME16 lpmmt16, UINT16 cbmmt) -{ - MMTIME mmt32; - MMRESULT ret; - - if (!lpmmt16) - return MMSYSERR_INVALPARAM; - MMSYSTEM_MMTIME16to32(&mmt32, lpmmt16); - ret = midiStreamPosition(HMIDISTRM_32(hMidiStrm), &mmt32, sizeof(MMTIME)); - MMSYSTEM_MMTIME32to16(lpmmt16, &mmt32); - return ret; -} - -/************************************************************************** - * midiStreamProperty [MMSYSTEM.250] - */ -MMRESULT16 WINAPI midiStreamProperty16(HMIDISTRM16 hMidiStrm, LPBYTE lpPropData, DWORD dwProperty) -{ - return midiStreamProperty(HMIDISTRM_32(hMidiStrm), lpPropData, dwProperty); -} - -/************************************************************************** - * midiStreamRestart [MMSYSTEM.256] - */ -MMRESULT16 WINAPI midiStreamRestart16(HMIDISTRM16 hMidiStrm) -{ - return midiStreamRestart(HMIDISTRM_32(hMidiStrm)); -} - -/************************************************************************** - * midiStreamStop [MMSYSTEM.257] - */ -MMRESULT16 WINAPI midiStreamStop16(HMIDISTRM16 hMidiStrm) -{ - return midiStreamStop(HMIDISTRM_32(hMidiStrm)); -} - -/* ################################################### - * # WAVE # - * ################################################### - */ - -/************************************************************************** - * waveOutGetNumDevs [MMSYSTEM.401] - */ -UINT16 WINAPI waveOutGetNumDevs16(void) -{ - return MMDRV_GetNum(MMDRV_WAVEOUT); -} - -/************************************************************************** - * waveOutGetDevCaps [MMSYSTEM.402] - */ -UINT16 WINAPI waveOutGetDevCaps16(UINT16 uDeviceID, - LPWAVEOUTCAPS16 lpCaps, UINT16 uSize) -{ - WAVEOUTCAPSA wocA; - UINT ret; - TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize); - - if (lpCaps == NULL) return MMSYSERR_INVALPARAM; - - ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA)); - if (ret == MMSYSERR_NOERROR) { - WAVEOUTCAPS16 woc16; - woc16.wMid = wocA.wMid; - woc16.wPid = wocA.wPid; - woc16.vDriverVersion = wocA.vDriverVersion; - strcpy(woc16.szPname, wocA.szPname); - woc16.dwFormats = wocA.dwFormats; - woc16.wChannels = wocA.wChannels; - woc16.dwSupport = wocA.dwSupport; - memcpy(lpCaps, &woc16, min(uSize, sizeof(woc16))); - } - return ret; -} - -/************************************************************************** - * waveOutGetErrorText [MMSYSTEM.403] - * waveInGetErrorText [MMSYSTEM.503] - */ -UINT16 WINAPI waveOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize) -{ - return waveOutGetErrorTextA(uError, lpText, uSize); -} - -/************************************************************************** - * waveOutOpen [MMSYSTEM.404] - */ -UINT16 WINAPI waveOutOpen16(HWAVEOUT16* lphWaveOut, UINT16 uDeviceID, - const LPWAVEFORMATEX lpFormat, DWORD dwCallback, - DWORD dwInstance, DWORD dwFlags) -{ - HANDLE hWaveOut; - UINT ret; - - /* since layout of WAVEFORMATEX is the same for 16/32 bits, we directly - * call the 32 bit version - * however, we need to promote correctly the wave mapper id - * (0xFFFFFFFF and not 0x0000FFFF) - */ - ret = WAVE_Open(&hWaveOut, (uDeviceID == (UINT16)-1) ? (UINT)-1 : uDeviceID, - MMDRV_WAVEOUT, lpFormat, dwCallback, dwInstance, dwFlags, FALSE); - - if (lphWaveOut != NULL) *lphWaveOut = HWAVEOUT_16(hWaveOut); - return ret; -} - -/************************************************************************** - * waveOutClose [MMSYSTEM.405] - */ -UINT16 WINAPI waveOutClose16(HWAVEOUT16 hWaveOut) -{ - DWORD level; - UINT16 ret; - - ReleaseThunkLock(&level); - ret = waveOutClose(HWAVEOUT_32(hWaveOut)); - RestoreThunkLock(level); - return ret; -} - -/************************************************************************** - * waveOutPrepareHeader [MMSYSTEM.406] - */ -UINT16 WINAPI waveOutPrepareHeader16(HWAVEOUT16 hWaveOut, /* [in] */ - SEGPTR lpsegWaveOutHdr, /* [???] */ - UINT16 uSize) /* [in] */ -{ - LPWINE_MLD wmld; - LPWAVEHDR lpWaveOutHdr = MapSL(lpsegWaveOutHdr); - - TRACE("(%04X, %08lx, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize); - - if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM; - - if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, WODM_PREPARE, lpsegWaveOutHdr, uSize, FALSE); -} - -/************************************************************************** - * waveOutUnprepareHeader [MMSYSTEM.407] - */ -UINT16 WINAPI waveOutUnprepareHeader16(HWAVEOUT16 hWaveOut, /* [in] */ - SEGPTR lpsegWaveOutHdr, /* [???] */ - UINT16 uSize) /* [in] */ -{ - LPWINE_MLD wmld; - LPWAVEHDR lpWaveOutHdr = MapSL(lpsegWaveOutHdr); - - TRACE("(%04X, %08lx, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize); - - if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) { - return MMSYSERR_NOERROR; - } - - if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, WODM_UNPREPARE, lpsegWaveOutHdr, uSize, FALSE); -} - -/************************************************************************** - * waveOutWrite [MMSYSTEM.408] - */ -UINT16 WINAPI waveOutWrite16(HWAVEOUT16 hWaveOut, /* [in] */ - LPWAVEHDR lpsegWaveOutHdr, /* [???] NOTE: SEGPTR */ - UINT16 uSize) /* [in] */ -{ - LPWINE_MLD wmld; - - TRACE("(%04X, %p, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize); - - if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, WODM_WRITE, (DWORD_PTR)lpsegWaveOutHdr, uSize, FALSE); -} - -/************************************************************************** - * waveOutBreakLoop [MMSYSTEM.419] - */ -UINT16 WINAPI waveOutBreakLoop16(HWAVEOUT16 hWaveOut16) -{ - DWORD level; - UINT16 ret; - - ReleaseThunkLock(&level); - ret = waveOutBreakLoop(HWAVEOUT_32(hWaveOut16)); - RestoreThunkLock(level); - return ret; -} - -/************************************************************************** - * waveOutPause [MMSYSTEM.409] - */ -UINT16 WINAPI waveOutPause16(HWAVEOUT16 hWaveOut16) -{ - DWORD level; - UINT16 ret; - - ReleaseThunkLock(&level); - ret = waveOutPause(HWAVEOUT_32(hWaveOut16)); - RestoreThunkLock(level); - return ret; -} - -/************************************************************************** - * waveOutReset [MMSYSTEM.411] - */ -UINT16 WINAPI waveOutReset16(HWAVEOUT16 hWaveOut16) -{ - DWORD level; - UINT16 ret; - - ReleaseThunkLock(&level); - ret = waveOutReset(HWAVEOUT_32(hWaveOut16)); - RestoreThunkLock(level); - return ret; -} - -/************************************************************************** - * waveOutRestart [MMSYSTEM.410] - */ -UINT16 WINAPI waveOutRestart16(HWAVEOUT16 hWaveOut16) -{ - DWORD level; - UINT16 ret; - - ReleaseThunkLock(&level); - ret = waveOutRestart(HWAVEOUT_32(hWaveOut16)); - RestoreThunkLock(level); - return ret; -} - -/************************************************************************** - * waveOutGetPosition [MMSYSTEM.412] - */ -UINT16 WINAPI waveOutGetPosition16(HWAVEOUT16 hWaveOut, LPMMTIME16 lpTime, - UINT16 uSize) -{ - UINT ret; - MMTIME mmt; - - mmt.wType = lpTime->wType; - ret = waveOutGetPosition(HWAVEOUT_32(hWaveOut), &mmt, sizeof(mmt)); - MMSYSTEM_MMTIME32to16(lpTime, &mmt); - return ret; -} - -/************************************************************************** - * waveOutGetPitch [MMSYSTEM.413] - */ -UINT16 WINAPI waveOutGetPitch16(HWAVEOUT16 hWaveOut16, LPDWORD lpdw) -{ - return waveOutGetPitch(HWAVEOUT_32(hWaveOut16), lpdw); -} - -/************************************************************************** - * waveOutSetPitch [MMSYSTEM.414] - */ -UINT16 WINAPI waveOutSetPitch16(HWAVEOUT16 hWaveOut16, DWORD dw) -{ - return waveOutSetPitch(HWAVEOUT_32(hWaveOut16), dw); -} - -/************************************************************************** - * waveOutGetPlaybackRate [MMSYSTEM.417] - */ -UINT16 WINAPI waveOutGetPlaybackRate16(HWAVEOUT16 hWaveOut16, LPDWORD lpdw) -{ - return waveOutGetPlaybackRate(HWAVEOUT_32(hWaveOut16), lpdw); -} - -/************************************************************************** - * waveOutSetPlaybackRate [MMSYSTEM.418] - */ -UINT16 WINAPI waveOutSetPlaybackRate16(HWAVEOUT16 hWaveOut16, DWORD dw) -{ - return waveOutSetPlaybackRate(HWAVEOUT_32(hWaveOut16), dw); -} - -/************************************************************************** - * waveOutGetVolume [MMSYSTEM.415] - */ -UINT16 WINAPI waveOutGetVolume16(UINT16 devid, LPDWORD lpdw) -{ - return waveOutGetVolume(HWAVEOUT_32(devid), lpdw); -} - -/************************************************************************** - * waveOutSetVolume [MMSYSTEM.416] - */ -UINT16 WINAPI waveOutSetVolume16(UINT16 devid, DWORD dw) -{ - return waveOutSetVolume(HWAVEOUT_32(devid), dw); -} - -/************************************************************************** - * waveOutGetID [MMSYSTEM.420] - */ -UINT16 WINAPI waveOutGetID16(HWAVEOUT16 hWaveOut, UINT16* lpuDeviceID) -{ - LPWINE_MLD wmld; - - TRACE("(%04X, %p);\n", hWaveOut, lpuDeviceID); - - if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE; - - if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - *lpuDeviceID = wmld->uDeviceID; - return 0; -} - -/************************************************************************** - * waveOutMessage [MMSYSTEM.421] - */ -DWORD WINAPI waveOutMessage16(HWAVEOUT16 hWaveOut, UINT16 uMessage, - DWORD dwParam1, DWORD dwParam2) -{ - LPWINE_MLD wmld; - - TRACE("(%04x, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2); - - if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL) { - if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, TRUE)) != NULL) { - if (uMessage == DRV_QUERYDRVENTRY || uMessage == DRV_QUERYDEVNODE) - dwParam1 = (DWORD)MapSL(dwParam1); - return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2); - } - return MMSYSERR_INVALHANDLE; - } - - /* from M$ KB */ - if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) - return MMSYSERR_INVALPARAM; - - return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, FALSE); -} - -/************************************************************************** - * waveInGetNumDevs [MMSYSTEM.501] - */ -UINT16 WINAPI waveInGetNumDevs16(void) -{ - return MMDRV_GetNum(MMDRV_WAVEIN); -} - -/************************************************************************** - * waveInGetDevCaps [MMSYSTEM.502] - */ -UINT16 WINAPI waveInGetDevCaps16(UINT16 uDeviceID, LPWAVEINCAPS16 lpCaps, - UINT16 uSize) -{ - WAVEINCAPSA wicA; - UINT ret; - - if (lpCaps == NULL) return MMSYSERR_INVALPARAM; - - ret = waveInGetDevCapsA(uDeviceID, &wicA, sizeof(wicA)); - if (ret == MMSYSERR_NOERROR) { - WAVEINCAPS16 wic16; - wic16.wMid = wicA.wMid; - wic16.wPid = wicA.wPid; - wic16.vDriverVersion = wicA.vDriverVersion; - strcpy(wic16.szPname, wicA.szPname); - wic16.dwFormats = wicA.dwFormats; - wic16.wChannels = wicA.wChannels; - memcpy(lpCaps, &wic16, min(uSize, sizeof(wic16))); - } - return ret; -} - -/************************************************************************** - * waveInOpen [MMSYSTEM.504] - */ -UINT16 WINAPI waveInOpen16(HWAVEIN16* lphWaveIn, UINT16 uDeviceID, - const LPWAVEFORMATEX lpFormat, DWORD dwCallback, - DWORD dwInstance, DWORD dwFlags) -{ - HANDLE hWaveIn; - UINT ret; - - /* since layout of WAVEFORMATEX is the same for 16/32 bits, we directly - * call the 32 bit version - * however, we need to promote correctly the wave mapper id - * (0xFFFFFFFF and not 0x0000FFFF) - */ - ret = WAVE_Open(&hWaveIn, (uDeviceID == (UINT16)-1) ? (UINT)-1 : uDeviceID, - MMDRV_WAVEIN, lpFormat, dwCallback, dwInstance, dwFlags, FALSE); - - if (lphWaveIn != NULL) *lphWaveIn = HWAVEIN_16(hWaveIn); - return ret; -} - -/************************************************************************** - * waveInClose [MMSYSTEM.505] - */ -UINT16 WINAPI waveInClose16(HWAVEIN16 hWaveIn) -{ - DWORD level; - UINT16 ret; - - ReleaseThunkLock(&level); - ret = waveInClose(HWAVEIN_32(hWaveIn)); - RestoreThunkLock(level); - return ret; -} - -/************************************************************************** - * waveInPrepareHeader [MMSYSTEM.506] - */ -UINT16 WINAPI waveInPrepareHeader16(HWAVEIN16 hWaveIn, /* [in] */ - SEGPTR lpsegWaveInHdr, /* [???] */ - UINT16 uSize) /* [in] */ -{ - LPWINE_MLD wmld; - LPWAVEHDR lpWaveInHdr = MapSL(lpsegWaveInHdr); - UINT16 ret; - - TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize); - - if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE; - if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - lpWaveInHdr->dwBytesRecorded = 0; - - ret = MMDRV_Message(wmld, WIDM_PREPARE, lpsegWaveInHdr, uSize, FALSE); - return ret; -} - -/************************************************************************** - * waveInUnprepareHeader [MMSYSTEM.507] - */ -UINT16 WINAPI waveInUnprepareHeader16(HWAVEIN16 hWaveIn, /* [in] */ - SEGPTR lpsegWaveInHdr, /* [???] */ - UINT16 uSize) /* [in] */ -{ - LPWINE_MLD wmld; - LPWAVEHDR lpWaveInHdr = MapSL(lpsegWaveInHdr); - - TRACE("(%04X, %08lx, %u);\n", hWaveIn, lpsegWaveInHdr, uSize); - - if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM; - - if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) { - return MMSYSERR_NOERROR; - } - - if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, WIDM_UNPREPARE, lpsegWaveInHdr, uSize, FALSE); -} - -/************************************************************************** - * waveInAddBuffer [MMSYSTEM.508] - */ -UINT16 WINAPI waveInAddBuffer16(HWAVEIN16 hWaveIn, /* [in] */ - WAVEHDR* lpsegWaveInHdr, /* [???] NOTE: SEGPTR */ - UINT16 uSize) /* [in] */ -{ - LPWINE_MLD wmld; - - TRACE("(%04X, %p, %u);\n", hWaveIn, lpsegWaveInHdr, uSize); - - if (lpsegWaveInHdr == NULL) return MMSYSERR_INVALPARAM; - if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD_PTR)lpsegWaveInHdr, uSize, FALSE); -} - -/************************************************************************** - * waveInReset [MMSYSTEM.511] - */ -UINT16 WINAPI waveInReset16(HWAVEIN16 hWaveIn16) -{ - DWORD level; - UINT16 ret; - - ReleaseThunkLock(&level); - ret = waveInReset(HWAVEIN_32(hWaveIn16)); - RestoreThunkLock(level); - return ret; -} - -/************************************************************************** - * waveInStart [MMSYSTEM.509] - */ -UINT16 WINAPI waveInStart16(HWAVEIN16 hWaveIn16) -{ - DWORD level; - UINT16 ret; - - ReleaseThunkLock(&level); - ret = waveInStart(HWAVEIN_32(hWaveIn16)); - RestoreThunkLock(level); - return ret; -} - -/************************************************************************** - * waveInStop [MMSYSTEM.510] - */ -UINT16 WINAPI waveInStop16(HWAVEIN16 hWaveIn16) -{ - DWORD level; - UINT16 ret; - - ReleaseThunkLock(&level); - ret = waveInStop(HWAVEIN_32(hWaveIn16)); - RestoreThunkLock(level); - return ret; -} - -/************************************************************************** - * waveInGetPosition [MMSYSTEM.512] - */ -UINT16 WINAPI waveInGetPosition16(HWAVEIN16 hWaveIn, LPMMTIME16 lpTime, - UINT16 uSize) -{ - UINT ret; - MMTIME mmt; - - mmt.wType = lpTime->wType; - ret = waveInGetPosition(HWAVEIN_32(hWaveIn), &mmt, sizeof(mmt)); - MMSYSTEM_MMTIME32to16(lpTime, &mmt); - return ret; -} - -/************************************************************************** - * waveInGetID [MMSYSTEM.513] - */ -UINT16 WINAPI waveInGetID16(HWAVEIN16 hWaveIn, UINT16* lpuDeviceID) -{ - LPWINE_MLD wmld; - - TRACE("(%04X, %p);\n", hWaveIn, lpuDeviceID); - - if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE; - - if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - *lpuDeviceID = wmld->uDeviceID; - return MMSYSERR_NOERROR; -} - -/************************************************************************** - * waveInMessage [MMSYSTEM.514] - */ -DWORD WINAPI waveInMessage16(HWAVEIN16 hWaveIn, UINT16 uMessage, - DWORD dwParam1, DWORD dwParam2) -{ - LPWINE_MLD wmld; - - TRACE("(%04x, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2); - - if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL) { - if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, TRUE)) != NULL) { - if (uMessage == DRV_QUERYDRVENTRY || uMessage == DRV_QUERYDEVNODE) - dwParam1 = (DWORD)MapSL(dwParam1); - return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2); - } - return MMSYSERR_INVALHANDLE; - } - - /* from M$ KB */ - if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) - return MMSYSERR_INVALPARAM; - - return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, FALSE); -} - -/* ################################################### - * # TASK # - * ################################################### - */ - -/*#define USE_MM_TSK_WINE*/ - -/************************************************************************** - * mmTaskCreate [MMSYSTEM.900] - * - * Creates a 16 bit MM task. It's entry point is lpFunc, and it should be - * called upon creation with dwPmt as parameter. - */ -HINSTANCE16 WINAPI mmTaskCreate16(SEGPTR spProc, HINSTANCE16 *lphMmTask, DWORD dwPmt) -{ - HINSTANCE16 ret; - HINSTANCE16 handle; - char cmdline[16]; - DWORD showCmd = 0x40002; - LOADPARAMS16 lp; - - TRACE("(%08lx, %p, %08lx);\n", spProc, lphMmTask, dwPmt); - /* This to work requires NE modules to be started with a binary command line - * which is not currently the case. A patch exists but has never been committed. - * A workaround would be to integrate code for mmtask.tsk into Wine, but - * this requires tremendous work (starting with patching tools/build to - * create NE executables (and not only DLLs) for builtins modules. - * EP 99/04/25 - */ - FIXME("This is currently broken. It will fail\n"); - - cmdline[0] = 0x0d; - *(LPDWORD)(cmdline + 1) = (DWORD)spProc; - *(LPDWORD)(cmdline + 5) = dwPmt; - *(LPDWORD)(cmdline + 9) = 0; - - lp.hEnvironment = 0; - lp.cmdLine = MapLS(cmdline); - lp.showCmd = MapLS(&showCmd); - lp.reserved = 0; - -#ifndef USE_MM_TSK_WINE - handle = LoadModule16("c:\\windows\\system\\mmtask.tsk", &lp); -#else - handle = LoadModule16("mmtask.tsk", &lp); -#endif - if (handle < 32) { - ret = (handle) ? 1 : 2; - handle = 0; - } else { - ret = 0; - } - if (lphMmTask) - *lphMmTask = handle; - - UnMapLS( lp.cmdLine ); - UnMapLS( lp.showCmd ); - TRACE("=> 0x%04x/%d\n", handle, ret); - return ret; -} - -#ifdef USE_MM_TSK_WINE -/* C equivalent to mmtask.tsk binary content */ -void mmTaskEntryPoint16(LPSTR cmdLine, WORD di, WORD si) -{ - int len = cmdLine[0x80]; - - if (len / 2 == 6) { - void (*fpProc)(DWORD) = MapSL(*((DWORD*)(cmdLine + 1))); - DWORD dwPmt = *((DWORD*)(cmdLine + 5)); - -#if 0 - InitTask16(); /* FIXME: pmts / from context ? */ - InitApp(di); -#endif - if (SetMessageQueue16(0x40)) { - WaitEvent16(0); - if (HIWORD(fpProc)) { - OldYield16(); -/* EPP StackEnter16(); */ - (fpProc)(dwPmt); - } - } - } - OldYield16(); - OldYield16(); - OldYield16(); - ExitProcess(0); -} -#endif - -/************************************************************************** - * mmTaskBlock [MMSYSTEM.902] - */ -void WINAPI mmTaskBlock16(HINSTANCE16 hInst) -{ - MSG msg; - - do { - GetMessageA(&msg, 0, 0, 0); - if (msg.hwnd) { - TranslateMessage(&msg); - DispatchMessageA(&msg); - } - } while (msg.message < 0x3A0); -} - -/************************************************************************** - * mmTaskSignal [MMSYSTEM.903] - */ -LRESULT WINAPI mmTaskSignal16(HTASK16 ht) -{ - TRACE("(%04x);\n", ht); - return PostThreadMessageW( HTASK_32(ht), WM_USER, 0, 0 ); -} - -/************************************************************************** - * mmGetCurrentTask [MMSYSTEM.904] - */ -HTASK16 WINAPI mmGetCurrentTask16(void) -{ - return GetCurrentTask(); -} - -/************************************************************************** - * mmTaskYield [MMSYSTEM.905] - */ -void WINAPI mmTaskYield16(void) -{ - MSG msg; - - if (PeekMessageA(&msg, 0, 0, 0, 0)) { - K32WOWYield16(); - } -} - -extern DWORD WINAPI GetProcessFlags(DWORD); - -/****************************************************************** - * WINMM_GetmmThread - * - * - */ -static WINE_MMTHREAD* WINMM_GetmmThread(HANDLE16 h) -{ - return (WINE_MMTHREAD*)MapSL( MAKESEGPTR(h, 0) ); -} - -DWORD WINAPI WINE_mmThreadEntryPoint(LPVOID); - -/************************************************************************** - * mmThreadCreate [MMSYSTEM.1120] - * - * undocumented - * Creates a MM thread, calling fpThreadAddr(dwPmt). - * dwFlags: - * bit.0 set means create a 16 bit task instead of thread calling a 16 bit proc - * bit.1 set means to open a VxD for this thread (unsupported) - */ -LRESULT WINAPI mmThreadCreate16(FARPROC16 fpThreadAddr, LPHANDLE16 lpHndl, DWORD dwPmt, DWORD dwFlags) -{ - HANDLE16 hndl; - LRESULT ret; - - TRACE("(%p, %p, %08lx, %08lx)!\n", fpThreadAddr, lpHndl, dwPmt, dwFlags); - - hndl = GlobalAlloc16(sizeof(WINE_MMTHREAD), GMEM_SHARE|GMEM_ZEROINIT); - - if (hndl == 0) { - ret = 2; - } else { - WINE_MMTHREAD* lpMMThd = WINMM_GetmmThread(hndl); - -#if 0 - /* force mmtask routines even if mmthread is required */ - /* this will work only if the patch about binary cmd line and NE tasks - * is committed - */ - dwFlags |= 1; -#endif - - lpMMThd->dwSignature = WINE_MMTHREAD_CREATED; - lpMMThd->dwCounter = 0; - lpMMThd->hThread = 0; - lpMMThd->dwThreadID = 0; - lpMMThd->fpThread = (DWORD)fpThreadAddr; - lpMMThd->dwThreadPmt = dwPmt; - lpMMThd->dwSignalCount = 0; - lpMMThd->hEvent = 0; - lpMMThd->hVxD = 0; - lpMMThd->dwStatus = 0; - lpMMThd->dwFlags = dwFlags; - lpMMThd->hTask = 0; - - if ((dwFlags & 1) == 0 && (GetProcessFlags(GetCurrentThreadId()) & 8) == 0) { - lpMMThd->hEvent = CreateEventW(NULL, FALSE, TRUE, NULL); - - TRACE("Let's go crazy... trying new MM thread. lpMMThd=%p\n", lpMMThd); - if (lpMMThd->dwFlags & 2) { - /* as long as we don't support MM VxD in wine, we don't need - * to care about this flag - */ - /* FIXME("Don't know how to properly open VxD handles\n"); */ - /* lpMMThd->hVxD = OpenVxDHandle(lpMMThd->hEvent); */ - } - - lpMMThd->hThread = CreateThread(0, 0, WINE_mmThreadEntryPoint, - (LPVOID)(DWORD_PTR)hndl, CREATE_SUSPENDED, &lpMMThd->dwThreadID); - if (lpMMThd->hThread == 0) { - WARN("Couldn't create thread\n"); - /* clean-up(VxDhandle...); devicedirectio... */ - if (lpMMThd->hEvent != 0) - CloseHandle(lpMMThd->hEvent); - ret = 2; - } else { - SetThreadPriority(lpMMThd->hThread, THREAD_PRIORITY_TIME_CRITICAL); - TRACE("Got a nice thread hndl=%p id=0x%08lx\n", lpMMThd->hThread, lpMMThd->dwThreadID); - ret = 0; - } - } else { - /* get WINE_mmThreadEntryPoint() - * 2047 is its ordinal in mmsystem.spec - */ - FARPROC16 fp = GetProcAddress16(GetModuleHandle16("MMSYSTEM"), (LPCSTR)2047); - - TRACE("farproc seg=0x%08lx lin=%p\n", (DWORD)fp, MapSL((SEGPTR)fp)); - - ret = (fp == 0) ? 2 : mmTaskCreate16((DWORD)fp, 0, hndl); - } - - if (ret == 0) { - if (lpMMThd->hThread && !ResumeThread(lpMMThd->hThread)) - WARN("Couldn't resume thread\n"); - - while (lpMMThd->dwStatus != 0x10) { /* test also HIWORD of dwStatus */ - UserYield16(); - } - } - } - - if (ret != 0) { - GlobalFree16(hndl); - hndl = 0; - } - - if (lpHndl) - *lpHndl = hndl; - - TRACE("ok => %ld\n", ret); - return ret; -} - -/************************************************************************** - * mmThreadSignal [MMSYSTEM.1121] - */ -void WINAPI mmThreadSignal16(HANDLE16 hndl) -{ - TRACE("(%04x)!\n", hndl); - - if (hndl) { - WINE_MMTHREAD* lpMMThd = WINMM_GetmmThread(hndl); - - lpMMThd->dwCounter++; - if (lpMMThd->hThread != 0) { - InterlockedIncrement(&lpMMThd->dwSignalCount); - SetEvent(lpMMThd->hEvent); - } else { - mmTaskSignal16(lpMMThd->hTask); - } - lpMMThd->dwCounter--; - } -} - -static void MMSYSTEM_ThreadBlock(WINE_MMTHREAD* lpMMThd) -{ - MSG msg; - DWORD ret; - - if (lpMMThd->dwThreadID != GetCurrentThreadId()) - ERR("Not called by thread itself\n"); - - for (;;) { - ResetEvent(lpMMThd->hEvent); - if (InterlockedDecrement(&lpMMThd->dwSignalCount) >= 0) - break; - InterlockedIncrement(&lpMMThd->dwSignalCount); - - TRACE("S1\n"); - - ret = MsgWaitForMultipleObjects(1, &lpMMThd->hEvent, FALSE, INFINITE, QS_ALLINPUT); - switch (ret) { - case WAIT_OBJECT_0: /* Event */ - TRACE("S2.1\n"); - break; - case WAIT_OBJECT_0 + 1: /* Msg */ - TRACE("S2.2\n"); - if (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessageA(&msg); - } - break; - default: - WARN("S2.x unsupported ret val 0x%08lx\n", ret); - } - TRACE("S3\n"); - } -} - -/************************************************************************** - * mmThreadBlock [MMSYSTEM.1122] - */ -void WINAPI mmThreadBlock16(HANDLE16 hndl) -{ - TRACE("(%04x)!\n", hndl); - - if (hndl) { - WINE_MMTHREAD* lpMMThd = WINMM_GetmmThread(hndl); - - if (lpMMThd->hThread != 0) { - DWORD lc; - - ReleaseThunkLock(&lc); - MMSYSTEM_ThreadBlock(lpMMThd); - RestoreThunkLock(lc); - } else { - mmTaskBlock16(lpMMThd->hTask); - } - } - TRACE("done\n"); -} - -/************************************************************************** - * mmThreadIsCurrent [MMSYSTEM.1123] - */ -BOOL16 WINAPI mmThreadIsCurrent16(HANDLE16 hndl) -{ - BOOL16 ret = FALSE; - - TRACE("(%04x)!\n", hndl); - - if (hndl && mmThreadIsValid16(hndl)) { - WINE_MMTHREAD* lpMMThd = WINMM_GetmmThread(hndl); - ret = (GetCurrentThreadId() == lpMMThd->dwThreadID); - } - TRACE("=> %d\n", ret); - return ret; -} - -/************************************************************************** - * mmThreadIsValid [MMSYSTEM.1124] - */ -BOOL16 WINAPI mmThreadIsValid16(HANDLE16 hndl) -{ - BOOL16 ret = FALSE; - - TRACE("(%04x)!\n", hndl); - - if (hndl) { - WINE_MMTHREAD* lpMMThd = WINMM_GetmmThread(hndl); - - if (!IsBadWritePtr(lpMMThd, sizeof(WINE_MMTHREAD)) && - lpMMThd->dwSignature == WINE_MMTHREAD_CREATED && - IsTask16(lpMMThd->hTask)) { - lpMMThd->dwCounter++; - if (lpMMThd->hThread != 0) { - DWORD dwThreadRet; - if (GetExitCodeThread(lpMMThd->hThread, &dwThreadRet) && - dwThreadRet == STATUS_PENDING) { - ret = TRUE; - } - } else { - ret = TRUE; - } - lpMMThd->dwCounter--; - } - } - TRACE("=> %d\n", ret); - return ret; -} - -/************************************************************************** - * mmThreadGetTask [MMSYSTEM.1125] - */ -HANDLE16 WINAPI mmThreadGetTask16(HANDLE16 hndl) -{ - HANDLE16 ret = 0; - - TRACE("(%04x)\n", hndl); - - if (mmThreadIsValid16(hndl)) { - WINE_MMTHREAD* lpMMThd = WINMM_GetmmThread(hndl); - ret = lpMMThd->hTask; - } - return ret; -} - -/************************************************************************** - * __wine_mmThreadEntryPoint (MMSYSTEM.2047) - */ -DWORD WINAPI WINE_mmThreadEntryPoint(LPVOID p) -{ - HANDLE16 hndl = (HANDLE16)(DWORD_PTR)p; - WINE_MMTHREAD* lpMMThd = WINMM_GetmmThread(hndl); - - TRACE("(%04x %p)\n", hndl, lpMMThd); - - lpMMThd->hTask = LOWORD(GetCurrentTask()); - TRACE("[10-%p] setting hTask to 0x%08x\n", lpMMThd->hThread, lpMMThd->hTask); - lpMMThd->dwStatus = 0x10; - MMSYSTEM_ThreadBlock(lpMMThd); - TRACE("[20-%p]\n", lpMMThd->hThread); - lpMMThd->dwStatus = 0x20; - if (lpMMThd->fpThread) { - WOWCallback16(lpMMThd->fpThread, lpMMThd->dwThreadPmt); - } - lpMMThd->dwStatus = 0x30; - TRACE("[30-%p]\n", lpMMThd->hThread); - while (lpMMThd->dwCounter) { - Sleep(1); - /* K32WOWYield16();*/ - } - TRACE("[XX-%p]\n", lpMMThd->hThread); - /* paranoia */ - lpMMThd->dwSignature = WINE_MMTHREAD_DELETED; - /* close lpMMThread->hVxD directIO */ - if (lpMMThd->hEvent) - CloseHandle(lpMMThd->hEvent); - GlobalFree16(hndl); - TRACE("done\n"); - - return 0; -} - -typedef BOOL16 (WINAPI *MMCPLCALLBACK)(HWND, LPCSTR, LPCSTR, LPCSTR); - -/************************************************************************** - * mmShowMMCPLPropertySheet [MMSYSTEM.1150] - */ -BOOL16 WINAPI mmShowMMCPLPropertySheet16(HWND hWnd, LPCSTR lpStrDevice, - LPCSTR lpStrTab, LPCSTR lpStrTitle) -{ - HANDLE hndl; - BOOL16 ret = FALSE; - - TRACE("(%p \"%s\" \"%s\" \"%s\")\n", hWnd, lpStrDevice, lpStrTab, lpStrTitle); - - hndl = LoadLibraryA("MMSYS.CPL"); - if (hndl != 0) { - MMCPLCALLBACK fp = (MMCPLCALLBACK)GetProcAddress(hndl, "ShowMMCPLPropertySheet"); - if (fp != NULL) { - DWORD lc; - ReleaseThunkLock(&lc); - ret = (fp)(hWnd, lpStrDevice, lpStrTab, lpStrTitle); - RestoreThunkLock(lc); - } - FreeLibrary(hndl); - } - - return ret; -} - -/************************************************************************** - * StackEnter [MMSYSTEM.32] - */ -void WINAPI StackEnter16(void) -{ -#ifdef __i386__ - /* mmsystem.dll from Win 95 does only this: so does Wine */ - __asm__("stc"); -#endif -} - -/************************************************************************** - * StackLeave [MMSYSTEM.33] - */ -void WINAPI StackLeave16(void) -{ -#ifdef __i386__ - /* mmsystem.dll from Win 95 does only this: so does Wine */ - __asm__("stc"); -#endif -} - -/************************************************************************** - * WMMMidiRunOnce [MMSYSTEM.8] - */ -void WINAPI WMMMidiRunOnce16(void) -{ - FIXME("(), stub!\n"); -} - -/* ################################################### - * # DRIVER # - * ################################################### - */ - -/************************************************************************** - * DRIVER_MapMsg32To16 [internal] - * - * Map a 32 bit driver message to a 16 bit driver message. - */ -static WINMM_MapType DRIVER_MapMsg32To16(WORD wMsg, DWORD* lParam1, DWORD* lParam2) -{ - WINMM_MapType ret = WINMM_MAP_MSGERROR; - - switch (wMsg) { - case DRV_LOAD: - case DRV_ENABLE: - case DRV_DISABLE: - case DRV_FREE: - case DRV_QUERYCONFIGURE: - case DRV_REMOVE: - case DRV_EXITSESSION: - case DRV_EXITAPPLICATION: - case DRV_POWER: - case DRV_CLOSE: /* should be 0/0 */ - case DRV_OPEN: /* pass through */ - /* lParam1 and lParam2 are not used */ - ret = WINMM_MAP_OK; - break; - case DRV_CONFIGURE: - case DRV_INSTALL: - /* lParam1 is a handle to a window (conf) or to a driver (inst) or not used, - * lParam2 is a pointer to DRVCONFIGINFO - */ - if (*lParam2) { - LPDRVCONFIGINFO16 dci16 = HeapAlloc( GetProcessHeap(), 0, sizeof(*dci16) ); - LPDRVCONFIGINFO dci32 = (LPDRVCONFIGINFO)(*lParam2); - - if (dci16) { - LPSTR str1 = NULL,str2; - INT len; - dci16->dwDCISize = sizeof(DRVCONFIGINFO16); - - if (dci32->lpszDCISectionName) { - len = WideCharToMultiByte( CP_ACP, 0, dci32->lpszDCISectionName, -1, NULL, 0, NULL, NULL ); - str1 = HeapAlloc( GetProcessHeap(), 0, len ); - if (str1) { - WideCharToMultiByte( CP_ACP, 0, dci32->lpszDCISectionName, -1, str1, len, NULL, NULL ); - dci16->lpszDCISectionName = MapLS( str1 ); - } else { - HeapFree( GetProcessHeap(), 0, dci16); - return WINMM_MAP_NOMEM; - } - } else { - dci16->lpszDCISectionName = 0L; - } - if (dci32->lpszDCIAliasName) { - len = WideCharToMultiByte( CP_ACP, 0, dci32->lpszDCIAliasName, -1, NULL, 0, NULL, NULL ); - str2 = HeapAlloc( GetProcessHeap(), 0, len ); - if (str2) { - WideCharToMultiByte( CP_ACP, 0, dci32->lpszDCIAliasName, -1, str2, len, NULL, NULL ); - dci16->lpszDCIAliasName = MapLS( str2 ); - } else { - HeapFree( GetProcessHeap(), 0, str1); - HeapFree( GetProcessHeap(), 0, dci16); - return WINMM_MAP_NOMEM; - } - } else { - dci16->lpszDCISectionName = 0L; - } - } else { - return WINMM_MAP_NOMEM; - } - *lParam2 = MapLS( dci16 ); - ret = WINMM_MAP_OKMEM; - } else { - ret = WINMM_MAP_OK; - } - break; - default: - if (!((wMsg >= 0x800 && wMsg < 0x900) || (wMsg >= 0x4000 && wMsg < 0x4100))) { - FIXME("Unknown message 0x%04x\n", wMsg); - } - ret = WINMM_MAP_OK; - } - return ret; -} - -/************************************************************************** - * DRIVER_UnMapMsg32To16 [internal] - * - * UnMap a 32 bit driver message to a 16 bit driver message. - */ -static WINMM_MapType DRIVER_UnMapMsg32To16(WORD wMsg, DWORD lParam1, DWORD lParam2) -{ - WINMM_MapType ret = WINMM_MAP_MSGERROR; - - switch (wMsg) { - case DRV_LOAD: - case DRV_ENABLE: - case DRV_DISABLE: - case DRV_FREE: - case DRV_QUERYCONFIGURE: - case DRV_REMOVE: - case DRV_EXITSESSION: - case DRV_EXITAPPLICATION: - case DRV_POWER: - case DRV_OPEN: - case DRV_CLOSE: - /* lParam1 and lParam2 are not used */ - break; - case DRV_CONFIGURE: - case DRV_INSTALL: - /* lParam1 is a handle to a window (or not used), lParam2 is a pointer to DRVCONFIGINFO, lParam2 */ - if (lParam2) { - LPDRVCONFIGINFO16 dci16 = MapSL(lParam2); - HeapFree( GetProcessHeap(), 0, MapSL(dci16->lpszDCISectionName) ); - HeapFree( GetProcessHeap(), 0, MapSL(dci16->lpszDCIAliasName) ); - UnMapLS( lParam2 ); - UnMapLS( dci16->lpszDCISectionName ); - UnMapLS( dci16->lpszDCIAliasName ); - HeapFree( GetProcessHeap(), 0, dci16 ); - } - ret = WINMM_MAP_OK; - break; - default: - if (!((wMsg >= 0x800 && wMsg < 0x900) || (wMsg >= 0x4000 && wMsg < 0x4100))) { - FIXME("Unknown message 0x%04x\n", wMsg); - } - ret = WINMM_MAP_OK; - } - return ret; -} - -/************************************************************************** - * DRIVER_TryOpenDriver16 [internal] - * - * Tries to load a 16 bit driver whose DLL's (module) name is lpFileName. - */ -static LPWINE_DRIVER DRIVER_OpenDriver16(LPCWSTR fn, LPCWSTR sn, LPARAM lParam2) -{ - LPWINE_DRIVER lpDrv = NULL; - LPCSTR cause = NULL; - LPSTR fnA = NULL, snA = NULL; - unsigned len; - - TRACE("(%s, %s, %08lX);\n", debugstr_w(fn), debugstr_w(sn), lParam2); - - lpDrv = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_DRIVER)); - if (lpDrv == NULL) {cause = "OOM"; goto exit;} - - if (fn) - { - len = WideCharToMultiByte( CP_ACP, 0, fn, -1, NULL, 0, NULL, NULL ); - fnA = HeapAlloc(GetProcessHeap(), 0, len); - if (fnA == NULL) {cause = "OOM"; goto exit;} - WideCharToMultiByte( CP_ACP, 0, fn, -1, fnA, len, NULL, NULL ); - } - - if (sn) - { - len = WideCharToMultiByte( CP_ACP, 0, sn, -1, NULL, 0, NULL, NULL ); - snA = HeapAlloc(GetProcessHeap(), 0, len); - if (snA == NULL) {cause = "OOM"; goto exit;} - WideCharToMultiByte( CP_ACP, 0, sn, -1, snA, len, NULL, NULL ); - } - - /* FIXME: shall we do some black magic here on sn ? - * drivers32 => drivers - * mci32 => mci - * ... - */ - lpDrv->d.d16.hDriver16 = OpenDriver16(fnA, snA, lParam2); - if (lpDrv->d.d16.hDriver16 == 0) {cause = "Not a 16 bit driver"; goto exit;} - lpDrv->dwFlags = WINE_GDF_16BIT; - - TRACE("=> %p\n", lpDrv); - return lpDrv; - -exit: - HeapFree(GetProcessHeap(), 0, lpDrv); - HeapFree(GetProcessHeap(), 0, fnA); - HeapFree(GetProcessHeap(), 0, snA); - TRACE("Unable to load 16 bit module %s[%s]: %s\n", - debugstr_w(fn), debugstr_w(sn), cause); - return NULL; -} - -/****************************************************************** - * DRIVER_SendMessage16 - * - * - */ -static LRESULT DRIVER_SendMessage16(HDRVR16 hDrv16, UINT msg, - LPARAM lParam1, LPARAM lParam2) -{ - LRESULT ret = 0; - WINMM_MapType map; - - TRACE("Before sdm16 call hDrv=%04x wMsg=%04x p1=%08lx p2=%08lx\n", - hDrv16, msg, lParam1, lParam2); - - switch (map = DRIVER_MapMsg32To16(msg, &lParam1, &lParam2)) { - case WINMM_MAP_OKMEM: - case WINMM_MAP_OK: - ret = SendDriverMessage16(hDrv16, msg, lParam1, lParam2); - if (map == WINMM_MAP_OKMEM) - DRIVER_UnMapMsg32To16(msg, lParam1, lParam2); - default: - break; - } - return ret; -} - -/****************************************************************** - * DRIVER_CloseDriver16 - * - * - */ -static LRESULT DRIVER_CloseDriver16(HDRVR16 hDrv16, LPARAM lParam1, LPARAM lParam2) -{ - return CloseDriver16(hDrv16, lParam1, lParam2); -} - -/************************************************************************** - * DrvOpen [MMSYSTEM.1100] - */ -HDRVR16 WINAPI DrvOpen16(LPSTR lpDriverName, LPSTR lpSectionName, LPARAM lParam) -{ - return OpenDriver16(lpDriverName, lpSectionName, lParam); -} - -/************************************************************************** - * DrvClose [MMSYSTEM.1101] - */ -LRESULT WINAPI DrvClose16(HDRVR16 hDrv, LPARAM lParam1, LPARAM lParam2) -{ - return CloseDriver16(hDrv, lParam1, lParam2); -} - -/************************************************************************** - * DrvSendMessage [MMSYSTEM.1102] - */ -LRESULT WINAPI DrvSendMessage16(HDRVR16 hDrv, WORD msg, LPARAM lParam1, - LPARAM lParam2) -{ - return SendDriverMessage16(hDrv, msg, lParam1, lParam2); -} - -/************************************************************************** - * DrvGetModuleHandle [MMSYSTEM.1103] - */ -HANDLE16 WINAPI DrvGetModuleHandle16(HDRVR16 hDrv) -{ - return GetDriverModuleHandle16(hDrv); -} - -/************************************************************************** - * DrvDefDriverProc [MMSYSTEM.1104] - */ -LRESULT WINAPI DrvDefDriverProc16(DWORD dwDriverID, HDRVR16 hDrv, WORD wMsg, - DWORD dwParam1, DWORD dwParam2) -{ - return DefDriverProc16(dwDriverID, hDrv, wMsg, dwParam1, dwParam2); -} - -/************************************************************************** - * DriverProc [MMSYSTEM.6] - */ -LRESULT WINAPI DriverProc16(DWORD dwDevID, HDRVR16 hDrv, WORD wMsg, - DWORD dwParam1, DWORD dwParam2) -{ - TRACE("dwDevID=%08lx hDrv=%04x wMsg=%04x dwParam1=%08lx dwParam2=%08lx\n", - dwDevID, hDrv, wMsg, dwParam1, dwParam2); - - return DrvDefDriverProc16(dwDevID, hDrv, wMsg, dwParam1, dwParam2); -} - -/* ################################################### - * # TIME # - * ################################################### - */ - -/****************************************************************** - * MMSYSTEM_MMTIME32to16 - * - * - */ -void MMSYSTEM_MMTIME32to16(LPMMTIME16 mmt16, const MMTIME* mmt32) -{ - mmt16->wType = mmt32->wType; - /* layout of rest is the same for 32/16, - * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding - */ - memcpy(&(mmt16->u), &(mmt32->u), sizeof(mmt16->u)); -} - -/****************************************************************** - * MMSYSTEM_MMTIME16to32 - * - * - */ -void MMSYSTEM_MMTIME16to32(LPMMTIME mmt32, const MMTIME16* mmt16) -{ - mmt32->wType = mmt16->wType; - /* layout of rest is the same for 32/16, - * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding - */ - memcpy(&(mmt32->u), &(mmt16->u), sizeof(mmt16->u)); -} - -/************************************************************************** - * timeGetSystemTime [MMSYSTEM.601] - */ -MMRESULT16 WINAPI timeGetSystemTime16(LPMMTIME16 lpTime, UINT16 wSize) -{ - if (wSize >= sizeof(*lpTime)) { - lpTime->wType = TIME_MS; - lpTime->u.ms = GetTickCount(); - - TRACE("=> %lu\n", lpTime->u.ms); - } - - return 0; -} - -/************************************************************************** - * timeSetEvent [MMSYSTEM.602] - */ -MMRESULT16 WINAPI timeSetEvent16(UINT16 wDelay, UINT16 wResol, LPTIMECALLBACK16 lpFunc, - DWORD dwUser, UINT16 wFlags) -{ - if (wFlags & WINE_TIMER_IS32) - WARN("Unknown windows flag... wine internally used.. ooch\n"); - - return TIME_SetEventInternal(wDelay, wResol, (LPTIMECALLBACK)lpFunc, - dwUser, wFlags & ~WINE_TIMER_IS32); -} - -/************************************************************************** - * timeKillEvent [MMSYSTEM.603] - */ -MMRESULT16 WINAPI timeKillEvent16(UINT16 wID) -{ - return timeKillEvent(wID); -} - -/************************************************************************** - * timeGetDevCaps [MMSYSTEM.604] - */ -MMRESULT16 WINAPI timeGetDevCaps16(LPTIMECAPS16 lpCaps, UINT16 wSize) -{ - TIMECAPS caps; - MMRESULT ret; - TRACE("(%p, %u) !\n", lpCaps, wSize); - - if (lpCaps == NULL) return MMSYSERR_INVALPARAM; - - ret = timeGetDevCaps(&caps, sizeof(caps)); - if (ret == MMSYSERR_NOERROR) { - TIMECAPS16 tc16; - tc16.wPeriodMin = caps.wPeriodMin; - tc16.wPeriodMax = caps.wPeriodMax; - memcpy(lpCaps, &tc16, min(wSize, sizeof(tc16))); - } - return ret; -} - -/************************************************************************** - * timeBeginPeriod [MMSYSTEM.605] - */ -MMRESULT16 WINAPI timeBeginPeriod16(UINT16 wPeriod) -{ - TRACE("(%u) !\n", wPeriod); - - return timeBeginPeriod(wPeriod); -} - -/************************************************************************** - * timeEndPeriod [MMSYSTEM.606] - */ -MMRESULT16 WINAPI timeEndPeriod16(UINT16 wPeriod) -{ - TRACE("(%u) !\n", wPeriod); - - return timeEndPeriod(wPeriod); -} - -/************************************************************************** - * mciSendString [MMSYSTEM.702] - */ -DWORD WINAPI mciSendString16(LPCSTR lpstrCommand, LPSTR lpstrRet, - UINT16 uRetLen, HWND16 hwndCallback) -{ - return mciSendStringA(lpstrCommand, lpstrRet, uRetLen, HWND_32(hwndCallback)); -} - -/************************************************************************** - * mciLoadCommandResource [MMSYSTEM.705] - */ -UINT16 WINAPI mciLoadCommandResource16(HINSTANCE16 hInst, LPCSTR resname, UINT16 type) -{ - HRSRC16 res; - HGLOBAL16 handle; - const BYTE* ptr16; - BYTE* ptr32; - unsigned pos = 0, size = 1024, len; - const char* str; - DWORD flg; - WORD eid; - UINT16 ret = MCIERR_OUT_OF_MEMORY; - - if (!(res = FindResource16( hInst, resname, (LPSTR)RT_RCDATA))) return MCI_NO_COMMAND_TABLE; - if (!(handle = LoadResource16( hInst, res ))) return MCI_NO_COMMAND_TABLE; - ptr16 = LockResource16(handle); - /* converting the 16 bit resource table into a 32W one */ - if ((ptr32 = HeapAlloc(GetProcessHeap(), 0, size))) - { - do { - str = (LPCSTR)ptr16; - ptr16 += strlen(str) + 1; - flg = *(const DWORD*)ptr16; - eid = *(const WORD*)(ptr16 + sizeof(DWORD)); - ptr16 += sizeof(DWORD) + sizeof(WORD); - len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0) * sizeof(WCHAR); - if (pos + len + sizeof(DWORD) + sizeof(WORD) > size) - { - while (pos + len * sizeof(WCHAR) + sizeof(DWORD) + sizeof(WORD) > size) size += 1024; - ptr32 = HeapReAlloc(GetProcessHeap(), 0, ptr32, size); - if (!ptr32) goto the_end; - } - MultiByteToWideChar(CP_ACP, 0, str, -1, (LPWSTR)(ptr32 + pos), len / sizeof(WCHAR)); - *(DWORD*)(ptr32 + pos + len) = flg; - *(WORD*)(ptr32 + pos + len + sizeof(DWORD)) = eid; - pos += len + sizeof(DWORD) + sizeof(WORD); - } while (eid != MCI_END_COMMAND_LIST); - } -the_end: - FreeResource16( handle ); - if (ptr32) ret = MCI_SetCommandTable(ptr32, type); - return ret; -} - -/************************************************************************** - * mciFreeCommandResource [MMSYSTEM.713] - */ -BOOL16 WINAPI mciFreeCommandResource16(UINT16 uTable) -{ - TRACE("(%04x)!\n", uTable); - - return MCI_DeleteCommandTable(uTable, TRUE); -} - -/* ################################################### - * # MMIO # - * ################################################### - */ - -/**************************************************************** - * MMIO_Map32To16 [INTERNAL] - */ -static LRESULT MMIO_Map32To16(DWORD wMsg, LPARAM* lp1, LPARAM* lp2) -{ - switch (wMsg) { - case MMIOM_CLOSE: - case MMIOM_SEEK: - /* nothing to do */ - break; - case MMIOM_OPEN: - case MMIOM_READ: - case MMIOM_WRITE: - case MMIOM_WRITEFLUSH: - *lp1 = MapLS( (void *)*lp1 ); - break; - case MMIOM_RENAME: - *lp1 = MapLS( (void *)*lp1 ); - *lp2 = MapLS( (void *)*lp2 ); - break; - default: - if (wMsg < MMIOM_USER) - TRACE("Not a mappable message (%ld)\n", wMsg); - } - return MMSYSERR_NOERROR; -} - -/**************************************************************** - * MMIO_UnMap32To16 [INTERNAL] - */ -static LRESULT MMIO_UnMap32To16(DWORD wMsg, LPARAM lParam1, LPARAM lParam2, - LPARAM lp1, LPARAM lp2) -{ - switch (wMsg) { - case MMIOM_CLOSE: - case MMIOM_SEEK: - /* nothing to do */ - break; - case MMIOM_OPEN: - case MMIOM_READ: - case MMIOM_WRITE: - case MMIOM_WRITEFLUSH: - UnMapLS( lp1 ); - break; - case MMIOM_RENAME: - UnMapLS( lp1 ); - UnMapLS( lp2 ); - break; - default: - if (wMsg < MMIOM_USER) - TRACE("Not a mappable message (%ld)\n", wMsg); - } - return MMSYSERR_NOERROR; -} - -/****************************************************************** - * MMIO_Callback16 - * - * - */ -static LRESULT MMIO_Callback16(SEGPTR cb16, LPMMIOINFO lpmmioinfo, UINT uMessage, - LPARAM lParam1, LPARAM lParam2) -{ - LRESULT result; - MMIOINFO16 mmioInfo16; - SEGPTR segmmioInfo16; - LPARAM lp1 = lParam1, lp2 = lParam2; - WORD args[7]; - - memset(&mmioInfo16, 0, sizeof(MMIOINFO16)); - mmioInfo16.lDiskOffset = lpmmioinfo->lDiskOffset; - mmioInfo16.adwInfo[0] = lpmmioinfo->adwInfo[0]; - mmioInfo16.adwInfo[1] = lpmmioinfo->adwInfo[1]; - mmioInfo16.adwInfo[2] = lpmmioinfo->adwInfo[2]; - /* map (lParam1, lParam2) into (lp1, lp2) 32=>16 */ - if ((result = MMIO_Map32To16(uMessage, &lp1, &lp2)) != MMSYSERR_NOERROR) - return result; - - segmmioInfo16 = MapLS(&mmioInfo16); - args[6] = HIWORD(segmmioInfo16); - args[5] = LOWORD(segmmioInfo16); - args[4] = uMessage; - args[3] = HIWORD(lp1); - args[2] = LOWORD(lp1); - args[1] = HIWORD(lp2); - args[0] = LOWORD(lp2); - WOWCallback16Ex( cb16, WCB16_PASCAL, sizeof(args), args, &result ); - UnMapLS(segmmioInfo16); - MMIO_UnMap32To16(uMessage, lParam1, lParam2, lp1, lp2); - - lpmmioinfo->lDiskOffset = mmioInfo16.lDiskOffset; - lpmmioinfo->adwInfo[0] = mmioInfo16.adwInfo[0]; - lpmmioinfo->adwInfo[1] = mmioInfo16.adwInfo[1]; - lpmmioinfo->adwInfo[2] = mmioInfo16.adwInfo[2]; - - return result; -} - -/****************************************************************** - * MMIO_ResetSegmentedData - * - */ -static LRESULT MMIO_SetSegmentedBuffer(HMMIO hmmio, SEGPTR ptr, BOOL release) -{ - LPWINE_MMIO wm; - - if ((wm = MMIO_Get(hmmio)) == NULL) - return MMSYSERR_INVALHANDLE; - if (release) UnMapLS(wm->segBuffer16); - wm->segBuffer16 = ptr; - return MMSYSERR_NOERROR; -} - -/************************************************************************** - * mmioOpen [MMSYSTEM.1210] - */ -HMMIO16 WINAPI mmioOpen16(LPSTR szFileName, MMIOINFO16* lpmmioinfo16, - DWORD dwOpenFlags) -{ - HMMIO ret; - - if (lpmmioinfo16) { - MMIOINFO mmioinfo; - - memset(&mmioinfo, 0, sizeof(mmioinfo)); - - mmioinfo.dwFlags = lpmmioinfo16->dwFlags; - mmioinfo.fccIOProc = lpmmioinfo16->fccIOProc; - mmioinfo.pIOProc = (LPMMIOPROC)lpmmioinfo16->pIOProc; - mmioinfo.cchBuffer = lpmmioinfo16->cchBuffer; - mmioinfo.pchBuffer = MapSL((DWORD)lpmmioinfo16->pchBuffer); - mmioinfo.adwInfo[0] = lpmmioinfo16->adwInfo[0]; - /* if we don't have a file name, it's likely a passed open file descriptor */ - if (!szFileName) - mmioinfo.adwInfo[0] = (DWORD)DosFileHandleToWin32Handle(mmioinfo.adwInfo[0]); - mmioinfo.adwInfo[1] = lpmmioinfo16->adwInfo[1]; - mmioinfo.adwInfo[2] = lpmmioinfo16->adwInfo[2]; - - ret = MMIO_Open(szFileName, &mmioinfo, dwOpenFlags, MMIO_PROC_16); - MMIO_SetSegmentedBuffer(mmioinfo.hmmio, (SEGPTR)lpmmioinfo16->pchBuffer, FALSE); - - lpmmioinfo16->wErrorRet = mmioinfo.wErrorRet; - lpmmioinfo16->hmmio = HMMIO_16(mmioinfo.hmmio); - } else { - ret = MMIO_Open(szFileName, NULL, dwOpenFlags, MMIO_PROC_32A); - } - return HMMIO_16(ret); -} - -/************************************************************************** - * mmioClose [MMSYSTEM.1211] - */ -MMRESULT16 WINAPI mmioClose16(HMMIO16 hmmio, UINT16 uFlags) -{ - MMIO_SetSegmentedBuffer(HMMIO_32(hmmio), (SEGPTR)NULL, TRUE); - return mmioClose(HMMIO_32(hmmio), uFlags); -} - -/************************************************************************** - * mmioRead [MMSYSTEM.1212] - */ -LONG WINAPI mmioRead16(HMMIO16 hmmio, HPSTR pch, LONG cch) -{ - return mmioRead(HMMIO_32(hmmio), pch, cch); -} - -/************************************************************************** - * mmioWrite [MMSYSTEM.1213] - */ -LONG WINAPI mmioWrite16(HMMIO16 hmmio, HPCSTR pch, LONG cch) -{ - return mmioWrite(HMMIO_32(hmmio),pch,cch); -} - -/************************************************************************** - * mmioSeek [MMSYSTEM.1214] - */ -LONG WINAPI mmioSeek16(HMMIO16 hmmio, LONG lOffset, INT16 iOrigin) -{ - return mmioSeek(HMMIO_32(hmmio), lOffset, iOrigin); -} - -/************************************************************************** - * mmioGetInfo [MMSYSTEM.1215] - */ -MMRESULT16 WINAPI mmioGetInfo16(HMMIO16 hmmio, MMIOINFO16* lpmmioinfo, UINT16 uFlags) -{ - MMIOINFO mmioinfo; - MMRESULT ret; - LPWINE_MMIO wm; - - TRACE("(0x%04x,%p,0x%08x)\n", hmmio, lpmmioinfo, uFlags); - - if ((wm = MMIO_Get(HMMIO_32(hmmio))) == NULL) - return MMSYSERR_INVALHANDLE; - - ret = mmioGetInfo(HMMIO_32(hmmio), &mmioinfo, uFlags); - if (ret != MMSYSERR_NOERROR) return ret; - - lpmmioinfo->dwFlags = mmioinfo.dwFlags; - lpmmioinfo->fccIOProc = mmioinfo.fccIOProc; - lpmmioinfo->pIOProc = (wm->ioProc->type == MMIO_PROC_16) ? - (LPMMIOPROC16)wm->ioProc->pIOProc : NULL; - lpmmioinfo->wErrorRet = mmioinfo.wErrorRet; - lpmmioinfo->hTask = HTASK_16(mmioinfo.hTask); - lpmmioinfo->cchBuffer = mmioinfo.cchBuffer; - lpmmioinfo->pchBuffer = (void*)wm->segBuffer16; - lpmmioinfo->pchNext = (void*)(wm->segBuffer16 + (mmioinfo.pchNext - mmioinfo.pchBuffer)); - lpmmioinfo->pchEndRead = (void*)(wm->segBuffer16 + (mmioinfo.pchEndRead - mmioinfo.pchBuffer)); - lpmmioinfo->pchEndWrite = (void*)(wm->segBuffer16 + (mmioinfo.pchEndWrite - mmioinfo.pchBuffer)); - lpmmioinfo->lBufOffset = mmioinfo.lBufOffset; - lpmmioinfo->lDiskOffset = mmioinfo.lDiskOffset; - lpmmioinfo->adwInfo[0] = mmioinfo.adwInfo[0]; - lpmmioinfo->adwInfo[1] = mmioinfo.adwInfo[1]; - lpmmioinfo->adwInfo[2] = mmioinfo.adwInfo[2]; - lpmmioinfo->dwReserved1 = 0; - lpmmioinfo->dwReserved2 = 0; - lpmmioinfo->hmmio = HMMIO_16(mmioinfo.hmmio); - - return MMSYSERR_NOERROR; -} - -/************************************************************************** - * mmioSetInfo [MMSYSTEM.1216] - */ -MMRESULT16 WINAPI mmioSetInfo16(HMMIO16 hmmio, const MMIOINFO16* lpmmioinfo, UINT16 uFlags) -{ - MMIOINFO mmioinfo; - MMRESULT ret; - - TRACE("(0x%04x,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags); - - ret = mmioGetInfo(HMMIO_32(hmmio), &mmioinfo, 0); - if (ret != MMSYSERR_NOERROR) return ret; - - /* check if seg and lin buffers are the same */ - if (mmioinfo.cchBuffer != lpmmioinfo->cchBuffer || - mmioinfo.pchBuffer != MapSL((DWORD)lpmmioinfo->pchBuffer)) - return MMSYSERR_INVALPARAM; - - /* check pointers coherence */ - if (lpmmioinfo->pchNext < lpmmioinfo->pchBuffer || - lpmmioinfo->pchNext > lpmmioinfo->pchBuffer + lpmmioinfo->cchBuffer || - lpmmioinfo->pchEndRead < lpmmioinfo->pchBuffer || - lpmmioinfo->pchEndRead > lpmmioinfo->pchBuffer + lpmmioinfo->cchBuffer || - lpmmioinfo->pchEndWrite < lpmmioinfo->pchBuffer || - lpmmioinfo->pchEndWrite > lpmmioinfo->pchBuffer + lpmmioinfo->cchBuffer) - return MMSYSERR_INVALPARAM; - - mmioinfo.pchNext = mmioinfo.pchBuffer + (lpmmioinfo->pchNext - lpmmioinfo->pchBuffer); - mmioinfo.pchEndRead = mmioinfo.pchBuffer + (lpmmioinfo->pchEndRead - lpmmioinfo->pchBuffer); - mmioinfo.pchEndWrite = mmioinfo.pchBuffer + (lpmmioinfo->pchEndWrite - lpmmioinfo->pchBuffer); - - return mmioSetInfo(HMMIO_32(hmmio), &mmioinfo, uFlags); -} - -/************************************************************************** - * mmioSetBuffer [MMSYSTEM.1217] - */ -MMRESULT16 WINAPI mmioSetBuffer16(HMMIO16 hmmio, LPSTR pchBuffer, - LONG cchBuffer, UINT16 uFlags) -{ - MMRESULT ret = mmioSetBuffer(HMMIO_32(hmmio), MapSL((DWORD)pchBuffer), - cchBuffer, uFlags); - - if (ret == MMSYSERR_NOERROR) - MMIO_SetSegmentedBuffer(HMMIO_32(hmmio), (DWORD)pchBuffer, TRUE); - else - UnMapLS((DWORD)pchBuffer); - return ret; -} - -/************************************************************************** - * mmioFlush [MMSYSTEM.1218] - */ -MMRESULT16 WINAPI mmioFlush16(HMMIO16 hmmio, UINT16 uFlags) -{ - return mmioFlush(HMMIO_32(hmmio), uFlags); -} - -/*********************************************************************** - * mmioAdvance [MMSYSTEM.1219] - */ -MMRESULT16 WINAPI mmioAdvance16(HMMIO16 hmmio, MMIOINFO16* lpmmioinfo, UINT16 uFlags) -{ - MMIOINFO mmioinfo; - LRESULT ret; - - /* WARNING: this heavily relies on mmioAdvance implementation (for choosing which - * fields to init - */ - if (lpmmioinfo) - { - mmioinfo.pchBuffer = MapSL((DWORD)lpmmioinfo->pchBuffer); - mmioinfo.pchNext = MapSL((DWORD)lpmmioinfo->pchNext); - mmioinfo.dwFlags = lpmmioinfo->dwFlags; - mmioinfo.lBufOffset = lpmmioinfo->lBufOffset; - ret = mmioAdvance(HMMIO_32(hmmio), &mmioinfo, uFlags); - } - else - ret = mmioAdvance(HMMIO_32(hmmio), NULL, uFlags); - - if (ret != MMSYSERR_NOERROR) return ret; - - if (lpmmioinfo) - { - lpmmioinfo->dwFlags = mmioinfo.dwFlags; - lpmmioinfo->pchNext = (void*)(lpmmioinfo->pchBuffer + (mmioinfo.pchNext - mmioinfo.pchBuffer)); - lpmmioinfo->pchEndRead = (void*)(lpmmioinfo->pchBuffer + (mmioinfo.pchEndRead - mmioinfo.pchBuffer)); - lpmmioinfo->pchEndWrite = (void*)(lpmmioinfo->pchBuffer + (mmioinfo.pchEndWrite - mmioinfo.pchBuffer)); - lpmmioinfo->lBufOffset = mmioinfo.lBufOffset; - lpmmioinfo->lDiskOffset = mmioinfo.lDiskOffset; - } - - return MMSYSERR_NOERROR; -} - -/************************************************************************** - * mmioStringToFOURCC [MMSYSTEM.1220] - */ -FOURCC WINAPI mmioStringToFOURCC16(LPCSTR sz, UINT16 uFlags) -{ - return mmioStringToFOURCCA(sz, uFlags); -} - -/************************************************************************** - * mmioInstallIOProc [MMSYSTEM.1221] - */ -LPMMIOPROC16 WINAPI mmioInstallIOProc16(FOURCC fccIOProc, LPMMIOPROC16 pIOProc, - DWORD dwFlags) -{ - return (LPMMIOPROC16)MMIO_InstallIOProc(fccIOProc, (LPMMIOPROC)pIOProc, - dwFlags, MMIO_PROC_16); -} - -/************************************************************************** - * mmioSendMessage [MMSYSTEM.1222] - */ -LRESULT WINAPI mmioSendMessage16(HMMIO16 hmmio, UINT16 uMessage, - LPARAM lParam1, LPARAM lParam2) -{ - return MMIO_SendMessage(HMMIO_32(hmmio), uMessage, - lParam1, lParam2, MMIO_PROC_16); -} - -/************************************************************************** - * mmioDescend [MMSYSTEM.1223] - */ -MMRESULT16 WINAPI mmioDescend16(HMMIO16 hmmio, LPMMCKINFO lpck, - const MMCKINFO* lpckParent, UINT16 uFlags) -{ - return mmioDescend(HMMIO_32(hmmio), lpck, lpckParent, uFlags); -} - -/************************************************************************** - * mmioAscend [MMSYSTEM.1224] - */ -MMRESULT16 WINAPI mmioAscend16(HMMIO16 hmmio, MMCKINFO* lpck, UINT16 uFlags) -{ - return mmioAscend(HMMIO_32(hmmio),lpck,uFlags); -} - -/************************************************************************** - * mmioCreateChunk [MMSYSTEM.1225] - */ -MMRESULT16 WINAPI mmioCreateChunk16(HMMIO16 hmmio, MMCKINFO* lpck, UINT16 uFlags) -{ - return mmioCreateChunk(HMMIO_32(hmmio), lpck, uFlags); -} - -/************************************************************************** - * mmioRename [MMSYSTEM.1226] - */ -MMRESULT16 WINAPI mmioRename16(LPCSTR szFileName, LPCSTR szNewFileName, - MMIOINFO16* lpmmioinfo, DWORD dwRenameFlags) -{ - BOOL inst = FALSE; - MMRESULT ret; - MMIOINFO mmioinfo; - - if (lpmmioinfo != NULL && lpmmioinfo->pIOProc != NULL && - lpmmioinfo->fccIOProc == 0) { - FIXME("Can't handle this case yet\n"); - return MMSYSERR_ERROR; - } - - /* this is a bit hacky, but it'll work if we get a fourCC code or nothing. - * but a non installed ioproc without a fourcc won't do - */ - if (lpmmioinfo && lpmmioinfo->fccIOProc && lpmmioinfo->pIOProc) { - MMIO_InstallIOProc(lpmmioinfo->fccIOProc, (LPMMIOPROC)lpmmioinfo->pIOProc, - MMIO_INSTALLPROC, MMIO_PROC_16); - inst = TRUE; - } - memset(&mmioinfo, 0, sizeof(mmioinfo)); - mmioinfo.fccIOProc = lpmmioinfo->fccIOProc; - ret = mmioRenameA(szFileName, szNewFileName, &mmioinfo, dwRenameFlags); - if (inst) { - MMIO_InstallIOProc(lpmmioinfo->fccIOProc, NULL, - MMIO_REMOVEPROC, MMIO_PROC_16); - } - return ret; -} - -/* ################################################### - * # JOYSTICK # - * ################################################### - */ - -/************************************************************************** - * joyGetNumDevs [MMSYSTEM.101] - */ -UINT16 WINAPI joyGetNumDevs16(void) -{ - return joyGetNumDevs(); -} - -/************************************************************************** - * joyGetDevCaps [MMSYSTEM.102] - */ -MMRESULT16 WINAPI joyGetDevCaps16(UINT16 wID, LPJOYCAPS16 lpCaps, UINT16 wSize) -{ - JOYCAPSA jca; - MMRESULT ret; - - if (lpCaps == NULL) return MMSYSERR_INVALPARAM; - - ret = joyGetDevCapsA(wID, &jca, sizeof(jca)); - - if (ret != JOYERR_NOERROR) return ret; - lpCaps->wMid = jca.wMid; - lpCaps->wPid = jca.wPid; - strcpy(lpCaps->szPname, jca.szPname); - lpCaps->wXmin = jca.wXmin; - lpCaps->wXmax = jca.wXmax; - lpCaps->wYmin = jca.wYmin; - lpCaps->wYmax = jca.wYmax; - lpCaps->wZmin = jca.wZmin; - lpCaps->wZmax = jca.wZmax; - lpCaps->wNumButtons = jca.wNumButtons; - lpCaps->wPeriodMin = jca.wPeriodMin; - lpCaps->wPeriodMax = jca.wPeriodMax; - - if (wSize >= sizeof(JOYCAPS16)) { /* Win95 extensions ? */ - lpCaps->wRmin = jca.wRmin; - lpCaps->wRmax = jca.wRmax; - lpCaps->wUmin = jca.wUmin; - lpCaps->wUmax = jca.wUmax; - lpCaps->wVmin = jca.wVmin; - lpCaps->wVmax = jca.wVmax; - lpCaps->wCaps = jca.wCaps; - lpCaps->wMaxAxes = jca.wMaxAxes; - lpCaps->wNumAxes = jca.wNumAxes; - lpCaps->wMaxButtons = jca.wMaxButtons; - strcpy(lpCaps->szRegKey, jca.szRegKey); - strcpy(lpCaps->szOEMVxD, jca.szOEMVxD); - } - - return ret; -} - -/************************************************************************** - * joyGetPosEx [MMSYSTEM.110] - */ -MMRESULT16 WINAPI joyGetPosEx16(UINT16 wID, LPJOYINFOEX lpInfo) -{ - return joyGetPosEx(wID, lpInfo); -} - -/************************************************************************** - * joyGetPos [MMSYSTEM.103] - */ -MMRESULT16 WINAPI joyGetPos16(UINT16 wID, LPJOYINFO16 lpInfo) -{ - JOYINFO ji; - MMRESULT ret; - - TRACE("(%d, %p);\n", wID, lpInfo); - - if ((ret = joyGetPos(wID, &ji)) == JOYERR_NOERROR) { - lpInfo->wXpos = ji.wXpos; - lpInfo->wYpos = ji.wYpos; - lpInfo->wZpos = ji.wZpos; - lpInfo->wButtons = ji.wButtons; - } - return ret; -} - -/************************************************************************** - * joyGetThreshold [MMSYSTEM.104] - */ -MMRESULT16 WINAPI joyGetThreshold16(UINT16 wID, LPUINT16 lpThreshold) -{ - UINT t; - MMRESULT ret; - - ret = joyGetThreshold(wID, &t); - if (ret == JOYERR_NOERROR) - *lpThreshold = t; - return ret; -} - -/************************************************************************** - * joyReleaseCapture [MMSYSTEM.105] - */ -MMRESULT16 WINAPI joyReleaseCapture16(UINT16 wID) -{ - return joyReleaseCapture(wID); -} - -/************************************************************************** - * joySetCapture [MMSYSTEM.106] - */ -MMRESULT16 WINAPI joySetCapture16(HWND16 hWnd, UINT16 wID, UINT16 wPeriod, BOOL16 bChanged) -{ - return joySetCapture16(hWnd, wID, wPeriod, bChanged); -} - -/************************************************************************** - * joySetThreshold [MMSYSTEM.107] - */ -MMRESULT16 WINAPI joySetThreshold16(UINT16 wID, UINT16 wThreshold) -{ - return joySetThreshold16(wID,wThreshold); -} - -/************************************************************************** - * joySetCalibration [MMSYSTEM.109] - */ -MMRESULT16 WINAPI joySetCalibration16(UINT16 wID) -{ - FIXME("(%04X): stub.\n", wID); - return JOYERR_NOCANDO; -} +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ + +/* + * MMSYTEM functions + * + * Copyright 1993 Martin Ayotte + * 1998-2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Eric POUECH : + * 99/4 added mmTask and mmThread functions support + */ + +#include <stdarg.h> +#include <string.h> + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winbase.h" +#include "mmsystem.h" +#include "winreg.h" +#include "ntstatus.h" +#include "winternl.h" +#include "wownt32.h" +#include "winnls.h" + +#include "wine/winuser16.h" +#include "winemm16.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mmsys); + +static WINE_MMTHREAD* WINMM_GetmmThread(HANDLE16); +static LPWINE_DRIVER DRIVER_OpenDriver16(LPCWSTR, LPCWSTR, LPARAM); +static LRESULT DRIVER_CloseDriver16(HDRVR16, LPARAM, LPARAM); +static LRESULT DRIVER_SendMessage16(HDRVR16, UINT, LPARAM, LPARAM); +static LRESULT MMIO_Callback16(SEGPTR, LPMMIOINFO, UINT, LPARAM, LPARAM); + +/* ################################################### + * # LIBRARY # + * ################################################### + */ + +/************************************************************************** + * DllEntryPoint (MMSYSTEM.4) + * + * MMSYSTEM DLL entry point + * + */ +BOOL WINAPI MMSYSTEM_LibMain(DWORD fdwReason, HINSTANCE hinstDLL, WORD ds, + WORD wHeapSize, DWORD dwReserved1, WORD wReserved2) +{ + TRACE("%p 0x%lx\n", hinstDLL, fdwReason); + + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + /* need to load WinMM in order to: + * - initiate correctly shared variables (WINMM_Init()) + */ + if (!GetModuleHandleA("WINMM.DLL")) + { + ERR("Could not load sibling WinMM.dll\n"); + return FALSE; + } + WINMM_IData.hWinMM16Instance = hinstDLL; + /* hook in our 16 bit function pointers */ + pFnGetMMThread16 = WINMM_GetmmThread; + pFnOpenDriver16 = DRIVER_OpenDriver16; + pFnCloseDriver16 = DRIVER_CloseDriver16; + pFnSendMessage16 = DRIVER_SendMessage16; + pFnMmioCallback16 = MMIO_Callback16; + pFnReleaseThunkLock = ReleaseThunkLock; + pFnRestoreThunkLock = RestoreThunkLock; + MMDRV_Init16(); + break; + case DLL_PROCESS_DETACH: + WINMM_IData.hWinMM16Instance = 0; + pFnGetMMThread16 = NULL; + pFnOpenDriver16 = NULL; + pFnCloseDriver16 = NULL; + pFnSendMessage16 = NULL; + pFnMmioCallback16 = NULL; + pFnReleaseThunkLock = NULL; + pFnRestoreThunkLock = NULL; + /* FIXME: add equivalent for MMDRV_Init16() */ + break; + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + } + return TRUE; +} + +/************************************************************************** + * MMSYSTEM_WEP [MMSYSTEM.1] + */ +int WINAPI MMSYSTEM_WEP(HINSTANCE16 hInstance, WORD wDataSeg, + WORD cbHeapSize, LPSTR lpCmdLine) +{ + TRACE("STUB: Unloading MMSystem DLL ... hInst=%04X \n", hInstance); + return TRUE; +} + +/* ################################################### + * # PlaySound # + * ################################################### + */ + +/************************************************************************** + * PlaySound [MMSYSTEM.3] + */ +BOOL16 WINAPI PlaySound16(LPCSTR pszSound, HMODULE16 hmod, DWORD fdwSound) +{ + BOOL16 retv; + DWORD lc; + + if ((fdwSound & SND_RESOURCE) == SND_RESOURCE) + { + HGLOBAL16 handle; + HRSRC16 res; + + if (!(res = FindResource16( hmod, pszSound, "WAVE" ))) return FALSE; + if (!(handle = LoadResource16( hmod, res ))) return FALSE; + pszSound = LockResource16(handle); + fdwSound = (fdwSound & ~SND_RESOURCE) | SND_MEMORY; + /* FIXME: FreeResource16 */ + } + + ReleaseThunkLock(&lc); + retv = PlaySoundA(pszSound, 0, fdwSound); + RestoreThunkLock(lc); + + return retv; +} + +/************************************************************************** + * sndPlaySound [MMSYSTEM.2] + */ +BOOL16 WINAPI sndPlaySound16(LPCSTR lpszSoundName, UINT16 uFlags) +{ + BOOL16 retv; + DWORD lc; + + ReleaseThunkLock(&lc); + retv = sndPlaySoundA(lpszSoundName, uFlags); + RestoreThunkLock(lc); + + return retv; +} + +/* ################################################### + * # MISC # + * ################################################### + */ + +/************************************************************************** + * mmsystemGetVersion [MMSYSTEM.5] + * + */ +UINT16 WINAPI mmsystemGetVersion16(void) +{ + return mmsystemGetVersion(); +} + +/************************************************************************** + * DriverCallback [MMSYSTEM.31] + */ +BOOL16 WINAPI DriverCallback16(DWORD dwCallBack, UINT16 uFlags, HDRVR16 hDev, + WORD wMsg, DWORD dwUser, DWORD dwParam1, + DWORD dwParam2) +{ + return DriverCallback(dwCallBack, uFlags, HDRVR_32(hDev), wMsg, dwUser, dwParam1, dwParam2); +} + +/************************************************************************** + * OutputDebugStr [MMSYSTEM.30] + */ +void WINAPI OutputDebugStr16(LPCSTR str) +{ + OutputDebugStringA( str ); +} + + +/* ################################################### + * # MIXER # + * ################################################### + */ + +/************************************************************************** + * Mixer devices. New to Win95 + */ + +/************************************************************************** + * mixerGetNumDevs [MMSYSTEM.800] + */ +UINT16 WINAPI mixerGetNumDevs16(void) +{ + return MMDRV_GetNum(MMDRV_MIXER); +} + +/************************************************************************** + * mixerGetDevCaps [MMSYSTEM.801] + */ +UINT16 WINAPI mixerGetDevCaps16(UINT16 uDeviceID, LPMIXERCAPS16 lpCaps, + UINT16 uSize) +{ + MIXERCAPSA micA; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = mixerGetDevCapsA(uDeviceID, &micA, sizeof(micA)); + if (ret == MMSYSERR_NOERROR) { + MIXERCAPS16 mic16; + mic16.wMid = micA.wMid; + mic16.wPid = micA.wPid; + mic16.vDriverVersion = micA.vDriverVersion; + strcpy(mic16.szPname, micA.szPname); + mic16.fdwSupport = micA.fdwSupport; + mic16.cDestinations = micA.cDestinations; + memcpy(lpCaps, &mic16, min(uSize, sizeof(mic16))); + } + return ret; +} + +/************************************************************************** + * mixerOpen [MMSYSTEM.802] + */ +UINT16 WINAPI mixerOpen16(LPHMIXER16 lphmix, UINT16 uDeviceID, DWORD dwCallback, + DWORD dwInstance, DWORD fdwOpen) +{ + HMIXER hmix; + UINT ret; + + ret = MIXER_Open(&hmix, uDeviceID, dwCallback, dwInstance, fdwOpen, FALSE); + if (lphmix) *lphmix = HMIXER_16(hmix); + return ret; +} + +/************************************************************************** + * mixerClose [MMSYSTEM.803] + */ +UINT16 WINAPI mixerClose16(HMIXER16 hMix) +{ + return mixerClose(HMIXER_32(hMix)); +} + +/************************************************************************** + * mixerGetID (MMSYSTEM.806) + */ +UINT16 WINAPI mixerGetID16(HMIXEROBJ16 hmix, LPUINT16 lpid, DWORD fdwID) +{ + UINT xid; + UINT ret = mixerGetID(HMIXEROBJ_32(hmix), &xid, fdwID); + + if (lpid) + *lpid = xid; + return ret; +} + +/************************************************************************** + * mixerGetControlDetails [MMSYSTEM.808] + */ +UINT16 WINAPI mixerGetControlDetails16(HMIXEROBJ16 hmix, + LPMIXERCONTROLDETAILS16 lpmcd, + DWORD fdwDetails) +{ + DWORD ret = MMSYSERR_NOTENABLED; + SEGPTR sppaDetails; + + TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails); + + if (lpmcd == NULL || lpmcd->cbStruct != sizeof(*lpmcd)) + return MMSYSERR_INVALPARAM; + + sppaDetails = (SEGPTR)lpmcd->paDetails; + lpmcd->paDetails = MapSL(sppaDetails); + ret = mixerGetControlDetailsA(HMIXEROBJ_32(hmix), + (LPMIXERCONTROLDETAILS)lpmcd, fdwDetails); + lpmcd->paDetails = (LPVOID)sppaDetails; + + return ret; +} + +/************************************************************************** + * mixerGetLineControls [MMSYSTEM.807] + */ +UINT16 WINAPI mixerGetLineControls16(HMIXEROBJ16 hmix, + LPMIXERLINECONTROLS16 lpmlc16, + DWORD fdwControls) +{ + MIXERLINECONTROLSA mlcA; + DWORD ret; + unsigned int i; + LPMIXERCONTROL16 lpmc16; + + TRACE("(%04x, %p, %08lx)\n", hmix, lpmlc16, fdwControls); + + if (lpmlc16 == NULL || lpmlc16->cbStruct != sizeof(*lpmlc16) || + lpmlc16->cbmxctrl != sizeof(MIXERCONTROL16)) + return MMSYSERR_INVALPARAM; + + mlcA.cbStruct = sizeof(mlcA); + mlcA.dwLineID = lpmlc16->dwLineID; + mlcA.u.dwControlID = lpmlc16->u.dwControlID; + mlcA.u.dwControlType = lpmlc16->u.dwControlType; + mlcA.cControls = lpmlc16->cControls; + mlcA.cbmxctrl = sizeof(MIXERCONTROLA); + mlcA.pamxctrl = HeapAlloc(GetProcessHeap(), 0, + mlcA.cControls * mlcA.cbmxctrl); + + ret = mixerGetLineControlsA(HMIXEROBJ_32(hmix), &mlcA, fdwControls); + + if (ret == MMSYSERR_NOERROR) { + lpmlc16->dwLineID = mlcA.dwLineID; + lpmlc16->u.dwControlID = mlcA.u.dwControlID; + lpmlc16->u.dwControlType = mlcA.u.dwControlType; + lpmlc16->cControls = mlcA.cControls; + + lpmc16 = MapSL(lpmlc16->pamxctrl); + + for (i = 0; i < mlcA.cControls; i++) { + lpmc16[i].cbStruct = sizeof(MIXERCONTROL16); + lpmc16[i].dwControlID = mlcA.pamxctrl[i].dwControlID; + lpmc16[i].dwControlType = mlcA.pamxctrl[i].dwControlType; + lpmc16[i].fdwControl = mlcA.pamxctrl[i].fdwControl; + lpmc16[i].cMultipleItems = mlcA.pamxctrl[i].cMultipleItems; + strcpy(lpmc16[i].szShortName, mlcA.pamxctrl[i].szShortName); + strcpy(lpmc16[i].szName, mlcA.pamxctrl[i].szName); + /* sizeof(lpmc16[i].Bounds) == sizeof(mlcA.pamxctrl[i].Bounds) */ + memcpy(&lpmc16[i].Bounds, &mlcA.pamxctrl[i].Bounds, + sizeof(mlcA.pamxctrl[i].Bounds)); + /* sizeof(lpmc16[i].Metrics) == sizeof(mlcA.pamxctrl[i].Metrics) */ + memcpy(&lpmc16[i].Metrics, &mlcA.pamxctrl[i].Metrics, + sizeof(mlcA.pamxctrl[i].Metrics)); + } + } + + HeapFree(GetProcessHeap(), 0, mlcA.pamxctrl); + + return ret; +} + +/************************************************************************** + * mixerGetLineInfo [MMSYSTEM.805] + */ +UINT16 WINAPI mixerGetLineInfo16(HMIXEROBJ16 hmix, LPMIXERLINE16 lpmli16, + DWORD fdwInfo) +{ + MIXERLINEA mliA; + UINT ret; + + TRACE("(%04x, %p, %08lx)\n", hmix, lpmli16, fdwInfo); + + if (lpmli16 == NULL || lpmli16->cbStruct != sizeof(*lpmli16)) + return MMSYSERR_INVALPARAM; + + mliA.cbStruct = sizeof(mliA); + switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) { + case MIXER_GETLINEINFOF_COMPONENTTYPE: + mliA.dwComponentType = lpmli16->dwComponentType; + break; + case MIXER_GETLINEINFOF_DESTINATION: + mliA.dwDestination = lpmli16->dwDestination; + break; + case MIXER_GETLINEINFOF_LINEID: + mliA.dwLineID = lpmli16->dwLineID; + break; + case MIXER_GETLINEINFOF_SOURCE: + mliA.dwDestination = lpmli16->dwDestination; + mliA.dwSource = lpmli16->dwSource; + break; + case MIXER_GETLINEINFOF_TARGETTYPE: + mliA.Target.dwType = lpmli16->Target.dwType; + mliA.Target.wMid = lpmli16->Target.wMid; + mliA.Target.wPid = lpmli16->Target.wPid; + mliA.Target.vDriverVersion = lpmli16->Target.vDriverVersion; + strcpy(mliA.Target.szPname, lpmli16->Target.szPname); + break; + default: + FIXME("Unsupported fdwControls=0x%08lx\n", fdwInfo); + } + + ret = mixerGetLineInfoA(HMIXEROBJ_32(hmix), &mliA, fdwInfo); + + lpmli16->dwDestination = mliA.dwDestination; + lpmli16->dwSource = mliA.dwSource; + lpmli16->dwLineID = mliA.dwLineID; + lpmli16->fdwLine = mliA.fdwLine; + lpmli16->dwUser = mliA.dwUser; + lpmli16->dwComponentType = mliA.dwComponentType; + lpmli16->cChannels = mliA.cChannels; + lpmli16->cConnections = mliA.cConnections; + lpmli16->cControls = mliA.cControls; + strcpy(lpmli16->szShortName, mliA.szShortName); + strcpy(lpmli16->szName, mliA.szName); + lpmli16->Target.dwType = mliA.Target.dwType; + lpmli16->Target.dwDeviceID = mliA.Target.dwDeviceID; + lpmli16->Target.wMid = mliA.Target.wMid; + lpmli16->Target.wPid = mliA.Target.wPid; + lpmli16->Target.vDriverVersion = mliA.Target.vDriverVersion; + strcpy(lpmli16->Target.szPname, mliA.Target.szPname); + + return ret; +} + +/************************************************************************** + * mixerSetControlDetails [MMSYSTEM.809] + */ +UINT16 WINAPI mixerSetControlDetails16(HMIXEROBJ16 hmix, + LPMIXERCONTROLDETAILS16 lpmcd, + DWORD fdwDetails) +{ + TRACE("(%04x, %p, %08lx)\n", hmix, lpmcd, fdwDetails); + return MMSYSERR_NOTENABLED; +} + +/************************************************************************** + * mixerMessage [MMSYSTEM.804] + */ +DWORD WINAPI mixerMessage16(HMIXER16 hmix, UINT16 uMsg, DWORD dwParam1, + DWORD dwParam2) +{ + return mixerMessage(HMIXER_32(hmix), uMsg, dwParam1, dwParam2); +} + +/************************************************************************** + * auxGetNumDevs [MMSYSTEM.350] + */ +UINT16 WINAPI auxGetNumDevs16(void) +{ + return MMDRV_GetNum(MMDRV_AUX); +} + +/* ################################################### + * # AUX # + * ################################################### + */ + +/************************************************************************** + * auxGetDevCaps [MMSYSTEM.351] + */ +UINT16 WINAPI auxGetDevCaps16(UINT16 uDeviceID, LPAUXCAPS16 lpCaps, UINT16 uSize) +{ + AUXCAPSA acA; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = auxGetDevCapsA(uDeviceID, &acA, sizeof(acA)); + if (ret == MMSYSERR_NOERROR) { + AUXCAPS16 ac16; + ac16.wMid = acA.wMid; + ac16.wPid = acA.wPid; + ac16.vDriverVersion = acA.vDriverVersion; + strcpy(ac16.szPname, acA.szPname); + ac16.wTechnology = acA.wTechnology; + ac16.dwSupport = acA.dwSupport; + memcpy(lpCaps, &ac16, min(uSize, sizeof(ac16))); + } + return ret; +} + +/************************************************************************** + * auxGetVolume [MMSYSTEM.352] + */ +UINT16 WINAPI auxGetVolume16(UINT16 uDeviceID, LPDWORD lpdwVolume) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume); + + if ((wmld = MMDRV_Get((HANDLE)(ULONG_PTR)uDeviceID, MMDRV_AUX, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD_PTR)lpdwVolume, 0L, TRUE); +} + +/************************************************************************** + * auxSetVolume [MMSYSTEM.353] + */ +UINT16 WINAPI auxSetVolume16(UINT16 uDeviceID, DWORD dwVolume) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume); + + if ((wmld = MMDRV_Get((HANDLE)(ULONG_PTR)uDeviceID, MMDRV_AUX, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE); +} + +/************************************************************************** + * auxOutMessage [MMSYSTEM.354] + */ +DWORD WINAPI auxOutMessage16(UINT16 uDeviceID, UINT16 uMessage, DWORD dw1, DWORD dw2) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %04X, %08lX, %08lX)\n", uDeviceID, uMessage, dw1, dw2); + + switch (uMessage) { + case AUXDM_GETNUMDEVS: + case AUXDM_SETVOLUME: + /* no argument conversion needed */ + break; + case AUXDM_GETVOLUME: + return auxGetVolume16(uDeviceID, MapSL(dw1)); + case AUXDM_GETDEVCAPS: + return auxGetDevCaps16(uDeviceID, MapSL(dw1), dw2); + default: + TRACE("(%04x, %04x, %08lx, %08lx): unhandled message\n", + uDeviceID, uMessage, dw1, dw2); + break; + } + if ((wmld = MMDRV_Get((HANDLE)(ULONG_PTR)uDeviceID, MMDRV_AUX, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE); +} + +/* ################################################### + * # MCI # + * ################################################### + */ + +/************************************************************************** + * mciGetErrorString [MMSYSTEM.706] + */ +BOOL16 WINAPI mciGetErrorString16(DWORD wError, LPSTR lpstrBuffer, UINT16 uLength) +{ + return mciGetErrorStringA(wError, lpstrBuffer, uLength); +} + +/************************************************************************** + * mciDriverNotify [MMSYSTEM.711] + */ +BOOL16 WINAPI mciDriverNotify16(HWND16 hWndCallBack, UINT16 wDevID, UINT16 wStatus) +{ + TRACE("(%04X, %04x, %04X)\n", hWndCallBack, wDevID, wStatus); + + return PostMessageA(HWND_32(hWndCallBack), MM_MCINOTIFY, wStatus, wDevID); +} + +/************************************************************************** + * mciGetDriverData [MMSYSTEM.708] + */ +DWORD WINAPI mciGetDriverData16(UINT16 uDeviceID) +{ + return mciGetDriverData(uDeviceID); +} + +/************************************************************************** + * mciSetDriverData [MMSYSTEM.707] + */ +BOOL16 WINAPI mciSetDriverData16(UINT16 uDeviceID, DWORD data) +{ + return mciSetDriverData(uDeviceID, data); +} + +/************************************************************************** + * mciSendCommand [MMSYSTEM.701] + */ +DWORD WINAPI mciSendCommand16(UINT16 wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2) +{ + DWORD dwRet; + + TRACE("(%04X, %s, %08lX, %08lX)\n", + wDevID, MCI_MessageToString(wMsg), dwParam1, dwParam2); + + dwRet = MCI_SendCommand(wDevID, wMsg, dwParam1, dwParam2, FALSE); + dwRet = MCI_CleanUp(dwRet, wMsg, (DWORD)MapSL(dwParam2)); + TRACE("=> %ld\n", dwRet); + return dwRet; +} + +/************************************************************************** + * mciGetDeviceID [MMSYSTEM.703] + */ +UINT16 WINAPI mciGetDeviceID16(LPCSTR lpstrName) +{ + TRACE("(\"%s\")\n", lpstrName); + + return mciGetDeviceIDA(lpstrName); +} + +/************************************************************************** + * mciSetYieldProc [MMSYSTEM.714] + */ +BOOL16 WINAPI mciSetYieldProc16(UINT16 uDeviceID, YIELDPROC16 fpYieldProc, DWORD dwYieldData) +{ + LPWINE_MCIDRIVER wmd; + + TRACE("(%u, %p, %08lx)\n", uDeviceID, fpYieldProc, dwYieldData); + + if (!(wmd = MCI_GetDriver(uDeviceID))) { + WARN("Bad uDeviceID\n"); + return FALSE; + } + + wmd->lpfnYieldProc = (YIELDPROC)fpYieldProc; + wmd->dwYieldData = dwYieldData; + wmd->bIs32 = FALSE; + + return TRUE; +} + +/************************************************************************** + * mciGetDeviceIDFromElementID [MMSYSTEM.715] + */ +UINT16 WINAPI mciGetDeviceIDFromElementID16(DWORD dwElementID, LPCSTR lpstrType) +{ + FIXME("(%lu, %s) stub\n", dwElementID, lpstrType); + return 0; +} + +/************************************************************************** + * mciGetYieldProc [MMSYSTEM.716] + */ +YIELDPROC16 WINAPI mciGetYieldProc16(UINT16 uDeviceID, DWORD* lpdwYieldData) +{ + LPWINE_MCIDRIVER wmd; + + TRACE("(%u, %p)\n", uDeviceID, lpdwYieldData); + + if (!(wmd = MCI_GetDriver(uDeviceID))) { + WARN("Bad uDeviceID\n"); + return NULL; + } + if (!wmd->lpfnYieldProc) { + WARN("No proc set\n"); + return NULL; + } + if (wmd->bIs32) { + WARN("Proc is 32 bit\n"); + return NULL; + } + return (YIELDPROC16)wmd->lpfnYieldProc; +} + +/************************************************************************** + * mciGetCreatorTask [MMSYSTEM.717] + */ +HTASK16 WINAPI mciGetCreatorTask16(UINT16 uDeviceID) +{ + LPWINE_MCIDRIVER wmd; + HTASK16 ret = 0; + + if ((wmd = MCI_GetDriver(uDeviceID))) + ret = HTASK_16(wmd->CreatorThread); + + TRACE("(%u) => %04x\n", uDeviceID, ret); + return ret; +} + +/************************************************************************** + * mciDriverYield [MMSYSTEM.710] + */ +UINT16 WINAPI mciDriverYield16(UINT16 uDeviceID) +{ + LPWINE_MCIDRIVER wmd; + UINT16 ret = 0; + + /* TRACE("(%04x)\n", uDeviceID); */ + + if (!(wmd = MCI_GetDriver(uDeviceID)) || !wmd->lpfnYieldProc || wmd->bIs32) { + UserYield16(); + } else { + ret = wmd->lpfnYieldProc(uDeviceID, wmd->dwYieldData); + } + + return ret; +} + +/* ################################################### + * # MIDI # + * ################################################### + */ + +/************************************************************************** + * midiOutGetNumDevs [MMSYSTEM.201] + */ +UINT16 WINAPI midiOutGetNumDevs16(void) +{ + return MMDRV_GetNum(MMDRV_MIDIOUT); +} + +/************************************************************************** + * midiOutGetDevCaps [MMSYSTEM.202] + */ +UINT16 WINAPI midiOutGetDevCaps16(UINT16 uDeviceID, LPMIDIOUTCAPS16 lpCaps, + UINT16 uSize) +{ + MIDIOUTCAPSA mocA; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = midiOutGetDevCapsA(uDeviceID, &mocA, sizeof(mocA)); + if (ret == MMSYSERR_NOERROR) { + MIDIOUTCAPS16 moc16; + moc16.wMid = mocA.wMid; + moc16.wPid = mocA.wPid; + moc16.vDriverVersion = mocA.vDriverVersion; + strcpy(moc16.szPname, mocA.szPname); + moc16.wTechnology = mocA.wTechnology; + moc16.wVoices = mocA.wVoices; + moc16.wNotes = mocA.wNotes; + moc16.wChannelMask = mocA.wChannelMask; + moc16.dwSupport = mocA.dwSupport; + memcpy(lpCaps, &moc16, min(uSize, sizeof(moc16))); + } + return ret; + } + +/************************************************************************** + * midiOutGetErrorText [MMSYSTEM.203] + * midiInGetErrorText [MMSYSTEM.303] + */ +UINT16 WINAPI midiOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize) +{ + return midiOutGetErrorTextA(uError, lpText, uSize); +} + +/************************************************************************** + * midiOutOpen [MMSYSTEM.204] + */ +UINT16 WINAPI midiOutOpen16(HMIDIOUT16* lphMidiOut, UINT16 uDeviceID, + DWORD dwCallback, DWORD dwInstance, DWORD dwFlags) +{ + HMIDIOUT hmo; + UINT ret; + + ret = MIDI_OutOpen(&hmo, uDeviceID, dwCallback, dwInstance, dwFlags, FALSE); + + if (lphMidiOut != NULL) *lphMidiOut = HMIDIOUT_16(hmo); + return ret; +} + +/************************************************************************** + * midiOutClose [MMSYSTEM.205] + */ +UINT16 WINAPI midiOutClose16(HMIDIOUT16 hMidiOut) +{ + return midiOutClose(HMIDIOUT_32(hMidiOut)); +} + +/************************************************************************** + * midiOutPrepareHeader [MMSYSTEM.206] + */ +UINT16 WINAPI midiOutPrepareHeader16(HMIDIOUT16 hMidiOut, /* [in] */ + SEGPTR lpsegMidiOutHdr, /* [???] */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %08lx, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize); + + if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_PREPARE, lpsegMidiOutHdr, uSize, FALSE); +} + +/************************************************************************** + * midiOutUnprepareHeader [MMSYSTEM.207] + */ +UINT16 WINAPI midiOutUnprepareHeader16(HMIDIOUT16 hMidiOut, /* [in] */ + SEGPTR lpsegMidiOutHdr, /* [???] */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + LPMIDIHDR16 lpMidiOutHdr = MapSL(lpsegMidiOutHdr); + + TRACE("(%04X, %08lx, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize); + + if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) { + return MMSYSERR_NOERROR; + } + + if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_UNPREPARE, lpsegMidiOutHdr, uSize, FALSE); +} + +/************************************************************************** + * midiOutShortMsg [MMSYSTEM.208] + */ +UINT16 WINAPI midiOutShortMsg16(HMIDIOUT16 hMidiOut, DWORD dwMsg) +{ + return midiOutShortMsg(HMIDIOUT_32(hMidiOut), dwMsg); +} + +/************************************************************************** + * midiOutLongMsg [MMSYSTEM.209] + */ +UINT16 WINAPI midiOutLongMsg16(HMIDIOUT16 hMidiOut, /* [in] */ + LPMIDIHDR16 lpsegMidiOutHdr, /* [???] NOTE: SEGPTR */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p, %d)\n", hMidiOut, lpsegMidiOutHdr, uSize); + + if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD_PTR)lpsegMidiOutHdr, uSize, FALSE); +} + +/************************************************************************** + * midiOutReset [MMSYSTEM.210] + */ +UINT16 WINAPI midiOutReset16(HMIDIOUT16 hMidiOut) +{ + return midiOutReset(HMIDIOUT_32(hMidiOut)); +} + +/************************************************************************** + * midiOutGetVolume [MMSYSTEM.211] + */ +UINT16 WINAPI midiOutGetVolume16(UINT16 uDeviceID, DWORD* lpdwVolume) +{ + return midiOutGetVolume(HMIDIOUT_32(uDeviceID), lpdwVolume); +} + +/************************************************************************** + * midiOutSetVolume [MMSYSTEM.212] + */ +UINT16 WINAPI midiOutSetVolume16(UINT16 uDeviceID, DWORD dwVolume) +{ + return midiOutSetVolume(HMIDIOUT_32(uDeviceID), dwVolume); +} + +/************************************************************************** + * midiOutCachePatches [MMSYSTEM.213] + */ +UINT16 WINAPI midiOutCachePatches16(HMIDIOUT16 hMidiOut, UINT16 uBank, + WORD* lpwPatchArray, UINT16 uFlags) +{ + return midiOutCachePatches(HMIDIOUT_32(hMidiOut), uBank, lpwPatchArray, + uFlags); +} + +/************************************************************************** + * midiOutCacheDrumPatches [MMSYSTEM.214] + */ +UINT16 WINAPI midiOutCacheDrumPatches16(HMIDIOUT16 hMidiOut, UINT16 uPatch, + WORD* lpwKeyArray, UINT16 uFlags) +{ + return midiOutCacheDrumPatches(HMIDIOUT_32(hMidiOut), uPatch, lpwKeyArray, uFlags); +} + +/************************************************************************** + * midiOutGetID [MMSYSTEM.215] + */ +UINT16 WINAPI midiOutGetID16(HMIDIOUT16 hMidiOut, UINT16* lpuDeviceID) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p)\n", hMidiOut, lpuDeviceID); + + if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM; + if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + *lpuDeviceID = wmld->uDeviceID; + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * midiOutMessage [MMSYSTEM.216] + */ +DWORD WINAPI midiOutMessage16(HMIDIOUT16 hMidiOut, UINT16 uMessage, + DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2); + + if ((wmld = MMDRV_Get(HMIDIOUT_32(hMidiOut), MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + switch (uMessage) { + case MODM_OPEN: + case MODM_CLOSE: + FIXME("can't handle OPEN or CLOSE message!\n"); + return MMSYSERR_NOTSUPPORTED; + + case MODM_GETVOLUME: + return midiOutGetVolume16(hMidiOut, MapSL(dwParam1)); + case MODM_LONGDATA: + return midiOutLongMsg16(hMidiOut, MapSL(dwParam1), dwParam2); + case MODM_PREPARE: + /* lpMidiOutHdr is still a segmented pointer for this function */ + return midiOutPrepareHeader16(hMidiOut, dwParam1, dwParam2); + case MODM_UNPREPARE: + return midiOutUnprepareHeader16(hMidiOut, dwParam1, dwParam2); + } + return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE); +} + +/************************************************************************** + * midiInGetNumDevs [MMSYSTEM.301] + */ +UINT16 WINAPI midiInGetNumDevs16(void) +{ + return MMDRV_GetNum(MMDRV_MIDIIN); +} + +/************************************************************************** + * midiInGetDevCaps [MMSYSTEM.302] + */ +UINT16 WINAPI midiInGetDevCaps16(UINT16 uDeviceID, LPMIDIINCAPS16 lpCaps, + UINT16 uSize) +{ + MIDIINCAPSA micA; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = midiInGetDevCapsA(uDeviceID, &micA, uSize); + if (ret == MMSYSERR_NOERROR) { + MIDIINCAPS16 mic16; + mic16.wMid = micA.wMid; + mic16.wPid = micA.wPid; + mic16.vDriverVersion = micA.vDriverVersion; + strcpy(mic16.szPname, micA.szPname); + mic16.dwSupport = micA.dwSupport; + memcpy(lpCaps, &mic16, min(uSize, sizeof(mic16))); + } + return ret; +} + +/************************************************************************** + * midiInOpen [MMSYSTEM.304] + */ +UINT16 WINAPI midiInOpen16(HMIDIIN16* lphMidiIn, UINT16 uDeviceID, + DWORD dwCallback, DWORD dwInstance, DWORD dwFlags) +{ + HMIDIIN xhmid; + UINT ret; + + ret = MIDI_InOpen(&xhmid, uDeviceID, dwCallback, dwInstance, dwFlags, FALSE); + + if (lphMidiIn) *lphMidiIn = HMIDIIN_16(xhmid); + return ret; +} + +/************************************************************************** + * midiInClose [MMSYSTEM.305] + */ +UINT16 WINAPI midiInClose16(HMIDIIN16 hMidiIn) +{ + return midiInClose(HMIDIIN_32(hMidiIn)); +} + +/************************************************************************** + * midiInPrepareHeader [MMSYSTEM.306] + */ +UINT16 WINAPI midiInPrepareHeader16(HMIDIIN16 hMidiIn, /* [in] */ + SEGPTR lpsegMidiInHdr, /* [???] */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %08lx, %d)\n", hMidiIn, lpsegMidiInHdr, uSize); + + if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_PREPARE, lpsegMidiInHdr, uSize, FALSE); +} + +/************************************************************************** + * midiInUnprepareHeader [MMSYSTEM.307] + */ +UINT16 WINAPI midiInUnprepareHeader16(HMIDIIN16 hMidiIn, /* [in] */ + SEGPTR lpsegMidiInHdr, /* [???] */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + LPMIDIHDR16 lpMidiInHdr = MapSL(lpsegMidiInHdr); + + TRACE("(%04X, %08lx, %d)\n", hMidiIn, lpsegMidiInHdr, uSize); + + if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) { + return MMSYSERR_NOERROR; + } + + if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_UNPREPARE, lpsegMidiInHdr, uSize, FALSE); +} + +/************************************************************************** + * midiInAddBuffer [MMSYSTEM.308] + */ +UINT16 WINAPI midiInAddBuffer16(HMIDIIN16 hMidiIn, /* [in] */ + MIDIHDR16* lpsegMidiInHdr, /* [???] NOTE: SEGPTR */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p, %d)\n", hMidiIn, lpsegMidiInHdr, uSize); + + if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD_PTR)lpsegMidiInHdr, uSize, FALSE); +} + +/************************************************************************** + * midiInStart [MMSYSTEM.309] + */ +UINT16 WINAPI midiInStart16(HMIDIIN16 hMidiIn) +{ + return midiInStart(HMIDIIN_32(hMidiIn)); +} + +/************************************************************************** + * midiInStop [MMSYSTEM.310] + */ +UINT16 WINAPI midiInStop16(HMIDIIN16 hMidiIn) +{ + return midiInStop(HMIDIIN_32(hMidiIn)); +} + +/************************************************************************** + * midiInReset [MMSYSTEM.311] + */ +UINT16 WINAPI midiInReset16(HMIDIIN16 hMidiIn) +{ + return midiInReset(HMIDIIN_32(hMidiIn)); +} + +/************************************************************************** + * midiInGetID [MMSYSTEM.312] + */ +UINT16 WINAPI midiInGetID16(HMIDIIN16 hMidiIn, UINT16* lpuDeviceID) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p)\n", hMidiIn, lpuDeviceID); + + if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + + *lpuDeviceID = wmld->uDeviceID; + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * midiInMessage [MMSYSTEM.313] + */ +DWORD WINAPI midiInMessage16(HMIDIIN16 hMidiIn, UINT16 uMessage, + DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2); + + switch (uMessage) { + case MIDM_OPEN: + case MIDM_CLOSE: + FIXME("can't handle OPEN or CLOSE message!\n"); + return MMSYSERR_NOTSUPPORTED; + + case MIDM_GETDEVCAPS: + return midiInGetDevCaps16(hMidiIn, MapSL(dwParam1), dwParam2); + case MIDM_PREPARE: + return midiInPrepareHeader16(hMidiIn, dwParam1, dwParam2); + case MIDM_UNPREPARE: + return midiInUnprepareHeader16(hMidiIn, dwParam1, dwParam2); + case MIDM_ADDBUFFER: + return midiInAddBuffer16(hMidiIn, MapSL(dwParam1), dwParam2); + } + + if ((wmld = MMDRV_Get(HMIDIIN_32(hMidiIn), MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, FALSE); +} + +/************************************************************************** + * midiStreamClose [MMSYSTEM.252] + */ +MMRESULT16 WINAPI midiStreamClose16(HMIDISTRM16 hMidiStrm) +{ + return midiStreamClose(HMIDISTRM_32(hMidiStrm)); +} + +/************************************************************************** + * midiStreamOpen [MMSYSTEM.251] + */ +MMRESULT16 WINAPI midiStreamOpen16(HMIDISTRM16* phMidiStrm, LPUINT16 devid, + DWORD cMidi, DWORD dwCallback, + DWORD dwInstance, DWORD fdwOpen) +{ + HMIDISTRM hMidiStrm32; + MMRESULT ret; + UINT devid32; + + if (!phMidiStrm || !devid) + return MMSYSERR_INVALPARAM; + devid32 = *devid; + ret = MIDI_StreamOpen(&hMidiStrm32, &devid32, cMidi, dwCallback, + dwInstance, fdwOpen, FALSE); + *phMidiStrm = HMIDISTRM_16(hMidiStrm32); + *devid = devid32; + return ret; +} + +/************************************************************************** + * midiStreamOut [MMSYSTEM.254] + */ +MMRESULT16 WINAPI midiStreamOut16(HMIDISTRM16 hMidiStrm, LPMIDIHDR16 lpMidiHdr, UINT16 cbMidiHdr) +{ + return midiStreamOut(HMIDISTRM_32(hMidiStrm), (LPMIDIHDR)lpMidiHdr, + cbMidiHdr); +} + +/************************************************************************** + * midiStreamPause [MMSYSTEM.255] + */ +MMRESULT16 WINAPI midiStreamPause16(HMIDISTRM16 hMidiStrm) +{ + return midiStreamPause(HMIDISTRM_32(hMidiStrm)); +} + +/************************************************************************** + * midiStreamPosition [MMSYSTEM.253] + */ +MMRESULT16 WINAPI midiStreamPosition16(HMIDISTRM16 hMidiStrm, LPMMTIME16 lpmmt16, UINT16 cbmmt) +{ + MMTIME mmt32; + MMRESULT ret; + + if (!lpmmt16) + return MMSYSERR_INVALPARAM; + MMSYSTEM_MMTIME16to32(&mmt32, lpmmt16); + ret = midiStreamPosition(HMIDISTRM_32(hMidiStrm), &mmt32, sizeof(MMTIME)); + MMSYSTEM_MMTIME32to16(lpmmt16, &mmt32); + return ret; +} + +/************************************************************************** + * midiStreamProperty [MMSYSTEM.250] + */ +MMRESULT16 WINAPI midiStreamProperty16(HMIDISTRM16 hMidiStrm, LPBYTE lpPropData, DWORD dwProperty) +{ + return midiStreamProperty(HMIDISTRM_32(hMidiStrm), lpPropData, dwProperty); +} + +/************************************************************************** + * midiStreamRestart [MMSYSTEM.256] + */ +MMRESULT16 WINAPI midiStreamRestart16(HMIDISTRM16 hMidiStrm) +{ + return midiStreamRestart(HMIDISTRM_32(hMidiStrm)); +} + +/************************************************************************** + * midiStreamStop [MMSYSTEM.257] + */ +MMRESULT16 WINAPI midiStreamStop16(HMIDISTRM16 hMidiStrm) +{ + return midiStreamStop(HMIDISTRM_32(hMidiStrm)); +} + +/* ################################################### + * # WAVE # + * ################################################### + */ + +/************************************************************************** + * waveOutGetNumDevs [MMSYSTEM.401] + */ +UINT16 WINAPI waveOutGetNumDevs16(void) +{ + return MMDRV_GetNum(MMDRV_WAVEOUT); +} + +/************************************************************************** + * waveOutGetDevCaps [MMSYSTEM.402] + */ +UINT16 WINAPI waveOutGetDevCaps16(UINT16 uDeviceID, + LPWAVEOUTCAPS16 lpCaps, UINT16 uSize) +{ + WAVEOUTCAPSA wocA; + UINT ret; + TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize); + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = waveOutGetDevCapsA(uDeviceID, &wocA, sizeof(wocA)); + if (ret == MMSYSERR_NOERROR) { + WAVEOUTCAPS16 woc16; + woc16.wMid = wocA.wMid; + woc16.wPid = wocA.wPid; + woc16.vDriverVersion = wocA.vDriverVersion; + strcpy(woc16.szPname, wocA.szPname); + woc16.dwFormats = wocA.dwFormats; + woc16.wChannels = wocA.wChannels; + woc16.dwSupport = wocA.dwSupport; + memcpy(lpCaps, &woc16, min(uSize, sizeof(woc16))); + } + return ret; +} + +/************************************************************************** + * waveOutGetErrorText [MMSYSTEM.403] + * waveInGetErrorText [MMSYSTEM.503] + */ +UINT16 WINAPI waveOutGetErrorText16(UINT16 uError, LPSTR lpText, UINT16 uSize) +{ + return waveOutGetErrorTextA(uError, lpText, uSize); +} + +/************************************************************************** + * waveOutOpen [MMSYSTEM.404] + */ +UINT16 WINAPI waveOutOpen16(HWAVEOUT16* lphWaveOut, UINT16 uDeviceID, + const LPWAVEFORMATEX lpFormat, DWORD dwCallback, + DWORD dwInstance, DWORD dwFlags) +{ + HANDLE hWaveOut; + UINT ret; + + /* since layout of WAVEFORMATEX is the same for 16/32 bits, we directly + * call the 32 bit version + * however, we need to promote correctly the wave mapper id + * (0xFFFFFFFF and not 0x0000FFFF) + */ + ret = WAVE_Open(&hWaveOut, (uDeviceID == (UINT16)-1) ? (UINT)-1 : uDeviceID, + MMDRV_WAVEOUT, lpFormat, dwCallback, dwInstance, dwFlags, FALSE); + + if (lphWaveOut != NULL) *lphWaveOut = HWAVEOUT_16(hWaveOut); + return ret; +} + +/************************************************************************** + * waveOutClose [MMSYSTEM.405] + */ +UINT16 WINAPI waveOutClose16(HWAVEOUT16 hWaveOut) +{ + DWORD level; + UINT16 ret; + + ReleaseThunkLock(&level); + ret = waveOutClose(HWAVEOUT_32(hWaveOut)); + RestoreThunkLock(level); + return ret; +} + +/************************************************************************** + * waveOutPrepareHeader [MMSYSTEM.406] + */ +UINT16 WINAPI waveOutPrepareHeader16(HWAVEOUT16 hWaveOut, /* [in] */ + SEGPTR lpsegWaveOutHdr, /* [???] */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + LPWAVEHDR lpWaveOutHdr = MapSL(lpsegWaveOutHdr); + + TRACE("(%04X, %08lx, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize); + + if (lpWaveOutHdr == NULL) return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WODM_PREPARE, lpsegWaveOutHdr, uSize, FALSE); +} + +/************************************************************************** + * waveOutUnprepareHeader [MMSYSTEM.407] + */ +UINT16 WINAPI waveOutUnprepareHeader16(HWAVEOUT16 hWaveOut, /* [in] */ + SEGPTR lpsegWaveOutHdr, /* [???] */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + LPWAVEHDR lpWaveOutHdr = MapSL(lpsegWaveOutHdr); + + TRACE("(%04X, %08lx, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize); + + if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) { + return MMSYSERR_NOERROR; + } + + if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WODM_UNPREPARE, lpsegWaveOutHdr, uSize, FALSE); +} + +/************************************************************************** + * waveOutWrite [MMSYSTEM.408] + */ +UINT16 WINAPI waveOutWrite16(HWAVEOUT16 hWaveOut, /* [in] */ + LPWAVEHDR lpsegWaveOutHdr, /* [???] NOTE: SEGPTR */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p, %u);\n", hWaveOut, lpsegWaveOutHdr, uSize); + + if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WODM_WRITE, (DWORD_PTR)lpsegWaveOutHdr, uSize, FALSE); +} + +/************************************************************************** + * waveOutBreakLoop [MMSYSTEM.419] + */ +UINT16 WINAPI waveOutBreakLoop16(HWAVEOUT16 hWaveOut16) +{ + DWORD level; + UINT16 ret; + + ReleaseThunkLock(&level); + ret = waveOutBreakLoop(HWAVEOUT_32(hWaveOut16)); + RestoreThunkLock(level); + return ret; +} + +/************************************************************************** + * waveOutPause [MMSYSTEM.409] + */ +UINT16 WINAPI waveOutPause16(HWAVEOUT16 hWaveOut16) +{ + DWORD level; + UINT16 ret; + + ReleaseThunkLock(&level); + ret = waveOutPause(HWAVEOUT_32(hWaveOut16)); + RestoreThunkLock(level); + return ret; +} + +/************************************************************************** + * waveOutReset [MMSYSTEM.411] + */ +UINT16 WINAPI waveOutReset16(HWAVEOUT16 hWaveOut16) +{ + DWORD level; + UINT16 ret; + + ReleaseThunkLock(&level); + ret = waveOutReset(HWAVEOUT_32(hWaveOut16)); + RestoreThunkLock(level); + return ret; +} + +/************************************************************************** + * waveOutRestart [MMSYSTEM.410] + */ +UINT16 WINAPI waveOutRestart16(HWAVEOUT16 hWaveOut16) +{ + DWORD level; + UINT16 ret; + + ReleaseThunkLock(&level); + ret = waveOutRestart(HWAVEOUT_32(hWaveOut16)); + RestoreThunkLock(level); + return ret; +} + +/************************************************************************** + * waveOutGetPosition [MMSYSTEM.412] + */ +UINT16 WINAPI waveOutGetPosition16(HWAVEOUT16 hWaveOut, LPMMTIME16 lpTime, + UINT16 uSize) +{ + UINT ret; + MMTIME mmt; + + mmt.wType = lpTime->wType; + ret = waveOutGetPosition(HWAVEOUT_32(hWaveOut), &mmt, sizeof(mmt)); + MMSYSTEM_MMTIME32to16(lpTime, &mmt); + return ret; +} + +/************************************************************************** + * waveOutGetPitch [MMSYSTEM.413] + */ +UINT16 WINAPI waveOutGetPitch16(HWAVEOUT16 hWaveOut16, LPDWORD lpdw) +{ + return waveOutGetPitch(HWAVEOUT_32(hWaveOut16), lpdw); +} + +/************************************************************************** + * waveOutSetPitch [MMSYSTEM.414] + */ +UINT16 WINAPI waveOutSetPitch16(HWAVEOUT16 hWaveOut16, DWORD dw) +{ + return waveOutSetPitch(HWAVEOUT_32(hWaveOut16), dw); +} + +/************************************************************************** + * waveOutGetPlaybackRate [MMSYSTEM.417] + */ +UINT16 WINAPI waveOutGetPlaybackRate16(HWAVEOUT16 hWaveOut16, LPDWORD lpdw) +{ + return waveOutGetPlaybackRate(HWAVEOUT_32(hWaveOut16), lpdw); +} + +/************************************************************************** + * waveOutSetPlaybackRate [MMSYSTEM.418] + */ +UINT16 WINAPI waveOutSetPlaybackRate16(HWAVEOUT16 hWaveOut16, DWORD dw) +{ + return waveOutSetPlaybackRate(HWAVEOUT_32(hWaveOut16), dw); +} + +/************************************************************************** + * waveOutGetVolume [MMSYSTEM.415] + */ +UINT16 WINAPI waveOutGetVolume16(UINT16 devid, LPDWORD lpdw) +{ + return waveOutGetVolume(HWAVEOUT_32(devid), lpdw); +} + +/************************************************************************** + * waveOutSetVolume [MMSYSTEM.416] + */ +UINT16 WINAPI waveOutSetVolume16(UINT16 devid, DWORD dw) +{ + return waveOutSetVolume(HWAVEOUT_32(devid), dw); +} + +/************************************************************************** + * waveOutGetID [MMSYSTEM.420] + */ +UINT16 WINAPI waveOutGetID16(HWAVEOUT16 hWaveOut, UINT16* lpuDeviceID) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p);\n", hWaveOut, lpuDeviceID); + + if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE; + + if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + *lpuDeviceID = wmld->uDeviceID; + return 0; +} + +/************************************************************************** + * waveOutMessage [MMSYSTEM.421] + */ +DWORD WINAPI waveOutMessage16(HWAVEOUT16 hWaveOut, UINT16 uMessage, + DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD wmld; + + TRACE("(%04x, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2); + + if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, FALSE)) == NULL) { + if ((wmld = MMDRV_Get(HWAVEOUT_32(hWaveOut), MMDRV_WAVEOUT, TRUE)) != NULL) { + if (uMessage == DRV_QUERYDRVENTRY || uMessage == DRV_QUERYDEVNODE) + dwParam1 = (DWORD)MapSL(dwParam1); + return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2); + } + return MMSYSERR_INVALHANDLE; + } + + /* from M$ KB */ + if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) + return MMSYSERR_INVALPARAM; + + return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, FALSE); +} + +/************************************************************************** + * waveInGetNumDevs [MMSYSTEM.501] + */ +UINT16 WINAPI waveInGetNumDevs16(void) +{ + return MMDRV_GetNum(MMDRV_WAVEIN); +} + +/************************************************************************** + * waveInGetDevCaps [MMSYSTEM.502] + */ +UINT16 WINAPI waveInGetDevCaps16(UINT16 uDeviceID, LPWAVEINCAPS16 lpCaps, + UINT16 uSize) +{ + WAVEINCAPSA wicA; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = waveInGetDevCapsA(uDeviceID, &wicA, sizeof(wicA)); + if (ret == MMSYSERR_NOERROR) { + WAVEINCAPS16 wic16; + wic16.wMid = wicA.wMid; + wic16.wPid = wicA.wPid; + wic16.vDriverVersion = wicA.vDriverVersion; + strcpy(wic16.szPname, wicA.szPname); + wic16.dwFormats = wicA.dwFormats; + wic16.wChannels = wicA.wChannels; + memcpy(lpCaps, &wic16, min(uSize, sizeof(wic16))); + } + return ret; +} + +/************************************************************************** + * waveInOpen [MMSYSTEM.504] + */ +UINT16 WINAPI waveInOpen16(HWAVEIN16* lphWaveIn, UINT16 uDeviceID, + const LPWAVEFORMATEX lpFormat, DWORD dwCallback, + DWORD dwInstance, DWORD dwFlags) +{ + HANDLE hWaveIn; + UINT ret; + + /* since layout of WAVEFORMATEX is the same for 16/32 bits, we directly + * call the 32 bit version + * however, we need to promote correctly the wave mapper id + * (0xFFFFFFFF and not 0x0000FFFF) + */ + ret = WAVE_Open(&hWaveIn, (uDeviceID == (UINT16)-1) ? (UINT)-1 : uDeviceID, + MMDRV_WAVEIN, lpFormat, dwCallback, dwInstance, dwFlags, FALSE); + + if (lphWaveIn != NULL) *lphWaveIn = HWAVEIN_16(hWaveIn); + return ret; +} + +/************************************************************************** + * waveInClose [MMSYSTEM.505] + */ +UINT16 WINAPI waveInClose16(HWAVEIN16 hWaveIn) +{ + DWORD level; + UINT16 ret; + + ReleaseThunkLock(&level); + ret = waveInClose(HWAVEIN_32(hWaveIn)); + RestoreThunkLock(level); + return ret; +} + +/************************************************************************** + * waveInPrepareHeader [MMSYSTEM.506] + */ +UINT16 WINAPI waveInPrepareHeader16(HWAVEIN16 hWaveIn, /* [in] */ + SEGPTR lpsegWaveInHdr, /* [???] */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + LPWAVEHDR lpWaveInHdr = MapSL(lpsegWaveInHdr); + UINT16 ret; + + TRACE("(%04X, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize); + + if (lpWaveInHdr == NULL) return MMSYSERR_INVALHANDLE; + if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + lpWaveInHdr->dwBytesRecorded = 0; + + ret = MMDRV_Message(wmld, WIDM_PREPARE, lpsegWaveInHdr, uSize, FALSE); + return ret; +} + +/************************************************************************** + * waveInUnprepareHeader [MMSYSTEM.507] + */ +UINT16 WINAPI waveInUnprepareHeader16(HWAVEIN16 hWaveIn, /* [in] */ + SEGPTR lpsegWaveInHdr, /* [???] */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + LPWAVEHDR lpWaveInHdr = MapSL(lpsegWaveInHdr); + + TRACE("(%04X, %08lx, %u);\n", hWaveIn, lpsegWaveInHdr, uSize); + + if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM; + + if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) { + return MMSYSERR_NOERROR; + } + + if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WIDM_UNPREPARE, lpsegWaveInHdr, uSize, FALSE); +} + +/************************************************************************** + * waveInAddBuffer [MMSYSTEM.508] + */ +UINT16 WINAPI waveInAddBuffer16(HWAVEIN16 hWaveIn, /* [in] */ + WAVEHDR* lpsegWaveInHdr, /* [???] NOTE: SEGPTR */ + UINT16 uSize) /* [in] */ +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p, %u);\n", hWaveIn, lpsegWaveInHdr, uSize); + + if (lpsegWaveInHdr == NULL) return MMSYSERR_INVALPARAM; + if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD_PTR)lpsegWaveInHdr, uSize, FALSE); +} + +/************************************************************************** + * waveInReset [MMSYSTEM.511] + */ +UINT16 WINAPI waveInReset16(HWAVEIN16 hWaveIn16) +{ + DWORD level; + UINT16 ret; + + ReleaseThunkLock(&level); + ret = waveInReset(HWAVEIN_32(hWaveIn16)); + RestoreThunkLock(level); + return ret; +} + +/************************************************************************** + * waveInStart [MMSYSTEM.509] + */ +UINT16 WINAPI waveInStart16(HWAVEIN16 hWaveIn16) +{ + DWORD level; + UINT16 ret; + + ReleaseThunkLock(&level); + ret = waveInStart(HWAVEIN_32(hWaveIn16)); + RestoreThunkLock(level); + return ret; +} + +/************************************************************************** + * waveInStop [MMSYSTEM.510] + */ +UINT16 WINAPI waveInStop16(HWAVEIN16 hWaveIn16) +{ + DWORD level; + UINT16 ret; + + ReleaseThunkLock(&level); + ret = waveInStop(HWAVEIN_32(hWaveIn16)); + RestoreThunkLock(level); + return ret; +} + +/************************************************************************** + * waveInGetPosition [MMSYSTEM.512] + */ +UINT16 WINAPI waveInGetPosition16(HWAVEIN16 hWaveIn, LPMMTIME16 lpTime, + UINT16 uSize) +{ + UINT ret; + MMTIME mmt; + + mmt.wType = lpTime->wType; + ret = waveInGetPosition(HWAVEIN_32(hWaveIn), &mmt, sizeof(mmt)); + MMSYSTEM_MMTIME32to16(lpTime, &mmt); + return ret; +} + +/************************************************************************** + * waveInGetID [MMSYSTEM.513] + */ +UINT16 WINAPI waveInGetID16(HWAVEIN16 hWaveIn, UINT16* lpuDeviceID) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p);\n", hWaveIn, lpuDeviceID); + + if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE; + + if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + *lpuDeviceID = wmld->uDeviceID; + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * waveInMessage [MMSYSTEM.514] + */ +DWORD WINAPI waveInMessage16(HWAVEIN16 hWaveIn, UINT16 uMessage, + DWORD dwParam1, DWORD dwParam2) +{ + LPWINE_MLD wmld; + + TRACE("(%04x, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2); + + if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, FALSE)) == NULL) { + if ((wmld = MMDRV_Get(HWAVEIN_32(hWaveIn), MMDRV_WAVEIN, TRUE)) != NULL) { + if (uMessage == DRV_QUERYDRVENTRY || uMessage == DRV_QUERYDEVNODE) + dwParam1 = (DWORD)MapSL(dwParam1); + return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2); + } + return MMSYSERR_INVALHANDLE; + } + + /* from M$ KB */ + if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) + return MMSYSERR_INVALPARAM; + + return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, FALSE); +} + +/* ################################################### + * # TASK # + * ################################################### + */ + +/*#define USE_MM_TSK_WINE*/ + +/************************************************************************** + * mmTaskCreate [MMSYSTEM.900] + * + * Creates a 16 bit MM task. It's entry point is lpFunc, and it should be + * called upon creation with dwPmt as parameter. + */ +HINSTANCE16 WINAPI mmTaskCreate16(SEGPTR spProc, HINSTANCE16 *lphMmTask, DWORD dwPmt) +{ + HINSTANCE16 ret; + HINSTANCE16 handle; + char cmdline[16]; + DWORD showCmd = 0x40002; + LOADPARAMS16 lp; + + TRACE("(%08lx, %p, %08lx);\n", spProc, lphMmTask, dwPmt); + /* This to work requires NE modules to be started with a binary command line + * which is not currently the case. A patch exists but has never been committed. + * A workaround would be to integrate code for mmtask.tsk into Wine, but + * this requires tremendous work (starting with patching tools/build to + * create NE executables (and not only DLLs) for builtins modules. + * EP 99/04/25 + */ + FIXME("This is currently broken. It will fail\n"); + + cmdline[0] = 0x0d; + *(LPDWORD)(cmdline + 1) = (DWORD)spProc; + *(LPDWORD)(cmdline + 5) = dwPmt; + *(LPDWORD)(cmdline + 9) = 0; + + lp.hEnvironment = 0; + lp.cmdLine = MapLS(cmdline); + lp.showCmd = MapLS(&showCmd); + lp.reserved = 0; + +#ifndef USE_MM_TSK_WINE + handle = LoadModule16("c:\\windows\\system\\mmtask.tsk", &lp); +#else + handle = LoadModule16("mmtask.tsk", &lp); +#endif + if (handle < 32) { + ret = (handle) ? 1 : 2; + handle = 0; + } else { + ret = 0; + } + if (lphMmTask) + *lphMmTask = handle; + + UnMapLS( lp.cmdLine ); + UnMapLS( lp.showCmd ); + TRACE("=> 0x%04x/%d\n", handle, ret); + return ret; +} + +#ifdef USE_MM_TSK_WINE +/* C equivalent to mmtask.tsk binary content */ +void mmTaskEntryPoint16(LPSTR cmdLine, WORD di, WORD si) +{ + int len = cmdLine[0x80]; + + if (len / 2 == 6) { + void (*fpProc)(DWORD) = MapSL(*((DWORD*)(cmdLine + 1))); + DWORD dwPmt = *((DWORD*)(cmdLine + 5)); + +#if 0 + InitTask16(); /* FIXME: pmts / from context ? */ + InitApp(di); +#endif + if (SetMessageQueue16(0x40)) { + WaitEvent16(0); + if (HIWORD(fpProc)) { + OldYield16(); +/* EPP StackEnter16(); */ + (fpProc)(dwPmt); + } + } + } + OldYield16(); + OldYield16(); + OldYield16(); + ExitProcess(0); +} +#endif + +/************************************************************************** + * mmTaskBlock [MMSYSTEM.902] + */ +void WINAPI mmTaskBlock16(HINSTANCE16 hInst) +{ + MSG msg; + + do { + GetMessageA(&msg, 0, 0, 0); + if (msg.hwnd) { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + } while (msg.message < 0x3A0); +} + +/************************************************************************** + * mmTaskSignal [MMSYSTEM.903] + */ +LRESULT WINAPI mmTaskSignal16(HTASK16 ht) +{ + TRACE("(%04x);\n", ht); + return PostThreadMessageW( HTASK_32(ht), WM_USER, 0, 0 ); +} + +/************************************************************************** + * mmGetCurrentTask [MMSYSTEM.904] + */ +HTASK16 WINAPI mmGetCurrentTask16(void) +{ + return GetCurrentTask(); +} + +/************************************************************************** + * mmTaskYield [MMSYSTEM.905] + */ +void WINAPI mmTaskYield16(void) +{ + MSG msg; + + if (PeekMessageA(&msg, 0, 0, 0, 0)) { + K32WOWYield16(); + } +} + +extern DWORD WINAPI GetProcessFlags(DWORD); + +/****************************************************************** + * WINMM_GetmmThread + * + * + */ +static WINE_MMTHREAD* WINMM_GetmmThread(HANDLE16 h) +{ + return (WINE_MMTHREAD*)MapSL( MAKESEGPTR(h, 0) ); +} + +DWORD WINAPI WINE_mmThreadEntryPoint(LPVOID); + +/************************************************************************** + * mmThreadCreate [MMSYSTEM.1120] + * + * undocumented + * Creates a MM thread, calling fpThreadAddr(dwPmt). + * dwFlags: + * bit.0 set means create a 16 bit task instead of thread calling a 16 bit proc + * bit.1 set means to open a VxD for this thread (unsupported) + */ +LRESULT WINAPI mmThreadCreate16(FARPROC16 fpThreadAddr, LPHANDLE16 lpHndl, DWORD dwPmt, DWORD dwFlags) +{ + HANDLE16 hndl; + LRESULT ret; + + TRACE("(%p, %p, %08lx, %08lx)!\n", fpThreadAddr, lpHndl, dwPmt, dwFlags); + + hndl = GlobalAlloc16(sizeof(WINE_MMTHREAD), GMEM_SHARE|GMEM_ZEROINIT); + + if (hndl == 0) { + ret = 2; + } else { + WINE_MMTHREAD* lpMMThd = WINMM_GetmmThread(hndl); + +#if 0 + /* force mmtask routines even if mmthread is required */ + /* this will work only if the patch about binary cmd line and NE tasks + * is committed + */ + dwFlags |= 1; +#endif + + lpMMThd->dwSignature = WINE_MMTHREAD_CREATED; + lpMMThd->dwCounter = 0; + lpMMThd->hThread = 0; + lpMMThd->dwThreadID = 0; + lpMMThd->fpThread = (DWORD)fpThreadAddr; + lpMMThd->dwThreadPmt = dwPmt; + lpMMThd->dwSignalCount = 0; + lpMMThd->hEvent = 0; + lpMMThd->hVxD = 0; + lpMMThd->dwStatus = 0; + lpMMThd->dwFlags = dwFlags; + lpMMThd->hTask = 0; + + if ((dwFlags & 1) == 0 && (GetProcessFlags(GetCurrentThreadId()) & 8) == 0) { + lpMMThd->hEvent = CreateEventW(NULL, FALSE, TRUE, NULL); + + TRACE("Let's go crazy... trying new MM thread. lpMMThd=%p\n", lpMMThd); + if (lpMMThd->dwFlags & 2) { + /* as long as we don't support MM VxD in wine, we don't need + * to care about this flag + */ + /* FIXME("Don't know how to properly open VxD handles\n"); */ + /* lpMMThd->hVxD = OpenVxDHandle(lpMMThd->hEvent); */ + } + + lpMMThd->hThread = CreateThread(0, 0, WINE_mmThreadEntryPoint, + (LPVOID)(DWORD_PTR)hndl, CREATE_SUSPENDED, &lpMMThd->dwThreadID); + if (lpMMThd->hThread == 0) { + WARN("Couldn't create thread\n"); + /* clean-up(VxDhandle...); devicedirectio... */ + if (lpMMThd->hEvent != 0) + CloseHandle(lpMMThd->hEvent); + ret = 2; + } else { + SetThreadPriority(lpMMThd->hThread, THREAD_PRIORITY_TIME_CRITICAL); + TRACE("Got a nice thread hndl=%p id=0x%08lx\n", lpMMThd->hThread, lpMMThd->dwThreadID); + ret = 0; + } + } else { + /* get WINE_mmThreadEntryPoint() + * 2047 is its ordinal in mmsystem.spec + */ + FARPROC16 fp = GetProcAddress16(GetModuleHandle16("MMSYSTEM"), (LPCSTR)2047); + + TRACE("farproc seg=0x%08lx lin=%p\n", (DWORD)fp, MapSL((SEGPTR)fp)); + + ret = (fp == 0) ? 2 : mmTaskCreate16((DWORD)fp, 0, hndl); + } + + if (ret == 0) { + if (lpMMThd->hThread && !ResumeThread(lpMMThd->hThread)) + WARN("Couldn't resume thread\n"); + + while (lpMMThd->dwStatus != 0x10) { /* test also HIWORD of dwStatus */ + UserYield16(); + } + } + } + + if (ret != 0) { + GlobalFree16(hndl); + hndl = 0; + } + + if (lpHndl) + *lpHndl = hndl; + + TRACE("ok => %ld\n", ret); + return ret; +} + +/************************************************************************** + * mmThreadSignal [MMSYSTEM.1121] + */ +void WINAPI mmThreadSignal16(HANDLE16 hndl) +{ + TRACE("(%04x)!\n", hndl); + + if (hndl) { + WINE_MMTHREAD* lpMMThd = WINMM_GetmmThread(hndl); + + lpMMThd->dwCounter++; + if (lpMMThd->hThread != 0) { + InterlockedIncrement(&lpMMThd->dwSignalCount); + SetEvent(lpMMThd->hEvent); + } else { + mmTaskSignal16(lpMMThd->hTask); + } + lpMMThd->dwCounter--; + } +} + +static void MMSYSTEM_ThreadBlock(WINE_MMTHREAD* lpMMThd) +{ + MSG msg; + DWORD ret; + + if (lpMMThd->dwThreadID != GetCurrentThreadId()) + ERR("Not called by thread itself\n"); + + for (;;) { + ResetEvent(lpMMThd->hEvent); + if (InterlockedDecrement(&lpMMThd->dwSignalCount) >= 0) + break; + InterlockedIncrement(&lpMMThd->dwSignalCount); + + TRACE("S1\n"); + + ret = MsgWaitForMultipleObjects(1, &lpMMThd->hEvent, FALSE, INFINITE, QS_ALLINPUT); + switch (ret) { + case WAIT_OBJECT_0: /* Event */ + TRACE("S2.1\n"); + break; + case WAIT_OBJECT_0 + 1: /* Msg */ + TRACE("S2.2\n"); + if (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + break; + default: + WARN("S2.x unsupported ret val 0x%08lx\n", ret); + } + TRACE("S3\n"); + } +} + +/************************************************************************** + * mmThreadBlock [MMSYSTEM.1122] + */ +void WINAPI mmThreadBlock16(HANDLE16 hndl) +{ + TRACE("(%04x)!\n", hndl); + + if (hndl) { + WINE_MMTHREAD* lpMMThd = WINMM_GetmmThread(hndl); + + if (lpMMThd->hThread != 0) { + DWORD lc; + + ReleaseThunkLock(&lc); + MMSYSTEM_ThreadBlock(lpMMThd); + RestoreThunkLock(lc); + } else { + mmTaskBlock16(lpMMThd->hTask); + } + } + TRACE("done\n"); +} + +/************************************************************************** + * mmThreadIsCurrent [MMSYSTEM.1123] + */ +BOOL16 WINAPI mmThreadIsCurrent16(HANDLE16 hndl) +{ + BOOL16 ret = FALSE; + + TRACE("(%04x)!\n", hndl); + + if (hndl && mmThreadIsValid16(hndl)) { + WINE_MMTHREAD* lpMMThd = WINMM_GetmmThread(hndl); + ret = (GetCurrentThreadId() == lpMMThd->dwThreadID); + } + TRACE("=> %d\n", ret); + return ret; +} + +/************************************************************************** + * mmThreadIsValid [MMSYSTEM.1124] + */ +BOOL16 WINAPI mmThreadIsValid16(HANDLE16 hndl) +{ + BOOL16 ret = FALSE; + + TRACE("(%04x)!\n", hndl); + + if (hndl) { + WINE_MMTHREAD* lpMMThd = WINMM_GetmmThread(hndl); + + if (!IsBadWritePtr(lpMMThd, sizeof(WINE_MMTHREAD)) && + lpMMThd->dwSignature == WINE_MMTHREAD_CREATED && + IsTask16(lpMMThd->hTask)) { + lpMMThd->dwCounter++; + if (lpMMThd->hThread != 0) { + DWORD dwThreadRet; + if (GetExitCodeThread(lpMMThd->hThread, &dwThreadRet) && + dwThreadRet == STATUS_PENDING) { + ret = TRUE; + } + } else { + ret = TRUE; + } + lpMMThd->dwCounter--; + } + } + TRACE("=> %d\n", ret); + return ret; +} + +/************************************************************************** + * mmThreadGetTask [MMSYSTEM.1125] + */ +HANDLE16 WINAPI mmThreadGetTask16(HANDLE16 hndl) +{ + HANDLE16 ret = 0; + + TRACE("(%04x)\n", hndl); + + if (mmThreadIsValid16(hndl)) { + WINE_MMTHREAD* lpMMThd = WINMM_GetmmThread(hndl); + ret = lpMMThd->hTask; + } + return ret; +} + +/************************************************************************** + * __wine_mmThreadEntryPoint (MMSYSTEM.2047) + */ +DWORD WINAPI WINE_mmThreadEntryPoint(LPVOID p) +{ + HANDLE16 hndl = (HANDLE16)(DWORD_PTR)p; + WINE_MMTHREAD* lpMMThd = WINMM_GetmmThread(hndl); + + TRACE("(%04x %p)\n", hndl, lpMMThd); + + lpMMThd->hTask = LOWORD(GetCurrentTask()); + TRACE("[10-%p] setting hTask to 0x%08x\n", lpMMThd->hThread, lpMMThd->hTask); + lpMMThd->dwStatus = 0x10; + MMSYSTEM_ThreadBlock(lpMMThd); + TRACE("[20-%p]\n", lpMMThd->hThread); + lpMMThd->dwStatus = 0x20; + if (lpMMThd->fpThread) { + WOWCallback16(lpMMThd->fpThread, lpMMThd->dwThreadPmt); + } + lpMMThd->dwStatus = 0x30; + TRACE("[30-%p]\n", lpMMThd->hThread); + while (lpMMThd->dwCounter) { + Sleep(1); + /* K32WOWYield16();*/ + } + TRACE("[XX-%p]\n", lpMMThd->hThread); + /* paranoia */ + lpMMThd->dwSignature = WINE_MMTHREAD_DELETED; + /* close lpMMThread->hVxD directIO */ + if (lpMMThd->hEvent) + CloseHandle(lpMMThd->hEvent); + GlobalFree16(hndl); + TRACE("done\n"); + + return 0; +} + +typedef BOOL16 (WINAPI *MMCPLCALLBACK)(HWND, LPCSTR, LPCSTR, LPCSTR); + +/************************************************************************** + * mmShowMMCPLPropertySheet [MMSYSTEM.1150] + */ +BOOL16 WINAPI mmShowMMCPLPropertySheet16(HWND hWnd, LPCSTR lpStrDevice, + LPCSTR lpStrTab, LPCSTR lpStrTitle) +{ + HANDLE hndl; + BOOL16 ret = FALSE; + + TRACE("(%p \"%s\" \"%s\" \"%s\")\n", hWnd, lpStrDevice, lpStrTab, lpStrTitle); + + hndl = LoadLibraryA("MMSYS.CPL"); + if (hndl != 0) { + MMCPLCALLBACK fp = (MMCPLCALLBACK)GetProcAddress(hndl, "ShowMMCPLPropertySheet"); + if (fp != NULL) { + DWORD lc; + ReleaseThunkLock(&lc); + ret = (fp)(hWnd, lpStrDevice, lpStrTab, lpStrTitle); + RestoreThunkLock(lc); + } + FreeLibrary(hndl); + } + + return ret; +} + +/************************************************************************** + * StackEnter [MMSYSTEM.32] + */ +void WINAPI StackEnter16(void) +{ +#ifdef __i386__ + /* mmsystem.dll from Win 95 does only this: so does Wine */ + __asm__("stc"); +#endif +} + +/************************************************************************** + * StackLeave [MMSYSTEM.33] + */ +void WINAPI StackLeave16(void) +{ +#ifdef __i386__ + /* mmsystem.dll from Win 95 does only this: so does Wine */ + __asm__("stc"); +#endif +} + +/************************************************************************** + * WMMMidiRunOnce [MMSYSTEM.8] + */ +void WINAPI WMMMidiRunOnce16(void) +{ + FIXME("(), stub!\n"); +} + +/* ################################################### + * # DRIVER # + * ################################################### + */ + +/************************************************************************** + * DRIVER_MapMsg32To16 [internal] + * + * Map a 32 bit driver message to a 16 bit driver message. + */ +static WINMM_MapType DRIVER_MapMsg32To16(WORD wMsg, DWORD* lParam1, DWORD* lParam2) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + case DRV_LOAD: + case DRV_ENABLE: + case DRV_DISABLE: + case DRV_FREE: + case DRV_QUERYCONFIGURE: + case DRV_REMOVE: + case DRV_EXITSESSION: + case DRV_EXITAPPLICATION: + case DRV_POWER: + case DRV_CLOSE: /* should be 0/0 */ + case DRV_OPEN: /* pass through */ + /* lParam1 and lParam2 are not used */ + ret = WINMM_MAP_OK; + break; + case DRV_CONFIGURE: + case DRV_INSTALL: + /* lParam1 is a handle to a window (conf) or to a driver (inst) or not used, + * lParam2 is a pointer to DRVCONFIGINFO + */ + if (*lParam2) { + LPDRVCONFIGINFO16 dci16 = HeapAlloc( GetProcessHeap(), 0, sizeof(*dci16) ); + LPDRVCONFIGINFO dci32 = (LPDRVCONFIGINFO)(*lParam2); + + if (dci16) { + LPSTR str1 = NULL,str2; + INT len; + dci16->dwDCISize = sizeof(DRVCONFIGINFO16); + + if (dci32->lpszDCISectionName) { + len = WideCharToMultiByte( CP_ACP, 0, dci32->lpszDCISectionName, -1, NULL, 0, NULL, NULL ); + str1 = HeapAlloc( GetProcessHeap(), 0, len ); + if (str1) { + WideCharToMultiByte( CP_ACP, 0, dci32->lpszDCISectionName, -1, str1, len, NULL, NULL ); + dci16->lpszDCISectionName = MapLS( str1 ); + } else { + HeapFree( GetProcessHeap(), 0, dci16); + return WINMM_MAP_NOMEM; + } + } else { + dci16->lpszDCISectionName = 0L; + } + if (dci32->lpszDCIAliasName) { + len = WideCharToMultiByte( CP_ACP, 0, dci32->lpszDCIAliasName, -1, NULL, 0, NULL, NULL ); + str2 = HeapAlloc( GetProcessHeap(), 0, len ); + if (str2) { + WideCharToMultiByte( CP_ACP, 0, dci32->lpszDCIAliasName, -1, str2, len, NULL, NULL ); + dci16->lpszDCIAliasName = MapLS( str2 ); + } else { + HeapFree( GetProcessHeap(), 0, str1); + HeapFree( GetProcessHeap(), 0, dci16); + return WINMM_MAP_NOMEM; + } + } else { + dci16->lpszDCISectionName = 0L; + } + } else { + return WINMM_MAP_NOMEM; + } + *lParam2 = MapLS( dci16 ); + ret = WINMM_MAP_OKMEM; + } else { + ret = WINMM_MAP_OK; + } + break; + default: + if (!((wMsg >= 0x800 && wMsg < 0x900) || (wMsg >= 0x4000 && wMsg < 0x4100))) { + FIXME("Unknown message 0x%04x\n", wMsg); + } + ret = WINMM_MAP_OK; + } + return ret; +} + +/************************************************************************** + * DRIVER_UnMapMsg32To16 [internal] + * + * UnMap a 32 bit driver message to a 16 bit driver message. + */ +static WINMM_MapType DRIVER_UnMapMsg32To16(WORD wMsg, DWORD lParam1, DWORD lParam2) +{ + WINMM_MapType ret = WINMM_MAP_MSGERROR; + + switch (wMsg) { + case DRV_LOAD: + case DRV_ENABLE: + case DRV_DISABLE: + case DRV_FREE: + case DRV_QUERYCONFIGURE: + case DRV_REMOVE: + case DRV_EXITSESSION: + case DRV_EXITAPPLICATION: + case DRV_POWER: + case DRV_OPEN: + case DRV_CLOSE: + /* lParam1 and lParam2 are not used */ + break; + case DRV_CONFIGURE: + case DRV_INSTALL: + /* lParam1 is a handle to a window (or not used), lParam2 is a pointer to DRVCONFIGINFO, lParam2 */ + if (lParam2) { + LPDRVCONFIGINFO16 dci16 = MapSL(lParam2); + HeapFree( GetProcessHeap(), 0, MapSL(dci16->lpszDCISectionName) ); + HeapFree( GetProcessHeap(), 0, MapSL(dci16->lpszDCIAliasName) ); + UnMapLS( lParam2 ); + UnMapLS( dci16->lpszDCISectionName ); + UnMapLS( dci16->lpszDCIAliasName ); + HeapFree( GetProcessHeap(), 0, dci16 ); + } + ret = WINMM_MAP_OK; + break; + default: + if (!((wMsg >= 0x800 && wMsg < 0x900) || (wMsg >= 0x4000 && wMsg < 0x4100))) { + FIXME("Unknown message 0x%04x\n", wMsg); + } + ret = WINMM_MAP_OK; + } + return ret; +} + +/************************************************************************** + * DRIVER_TryOpenDriver16 [internal] + * + * Tries to load a 16 bit driver whose DLL's (module) name is lpFileName. + */ +static LPWINE_DRIVER DRIVER_OpenDriver16(LPCWSTR fn, LPCWSTR sn, LPARAM lParam2) +{ + LPWINE_DRIVER lpDrv = NULL; + LPCSTR cause = NULL; + LPSTR fnA = NULL, snA = NULL; + unsigned len; + + TRACE("(%s, %s, %08lX);\n", debugstr_w(fn), debugstr_w(sn), lParam2); + + lpDrv = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_DRIVER)); + if (lpDrv == NULL) {cause = "OOM"; goto exit;} + + if (fn) + { + len = WideCharToMultiByte( CP_ACP, 0, fn, -1, NULL, 0, NULL, NULL ); + fnA = HeapAlloc(GetProcessHeap(), 0, len); + if (fnA == NULL) {cause = "OOM"; goto exit;} + WideCharToMultiByte( CP_ACP, 0, fn, -1, fnA, len, NULL, NULL ); + } + + if (sn) + { + len = WideCharToMultiByte( CP_ACP, 0, sn, -1, NULL, 0, NULL, NULL ); + snA = HeapAlloc(GetProcessHeap(), 0, len); + if (snA == NULL) {cause = "OOM"; goto exit;} + WideCharToMultiByte( CP_ACP, 0, sn, -1, snA, len, NULL, NULL ); + } + + /* FIXME: shall we do some black magic here on sn ? + * drivers32 => drivers + * mci32 => mci + * ... + */ + lpDrv->d.d16.hDriver16 = OpenDriver16(fnA, snA, lParam2); + if (lpDrv->d.d16.hDriver16 == 0) {cause = "Not a 16 bit driver"; goto exit;} + lpDrv->dwFlags = WINE_GDF_16BIT; + + TRACE("=> %p\n", lpDrv); + return lpDrv; + +exit: + HeapFree(GetProcessHeap(), 0, lpDrv); + HeapFree(GetProcessHeap(), 0, fnA); + HeapFree(GetProcessHeap(), 0, snA); + TRACE("Unable to load 16 bit module %s[%s]: %s\n", + debugstr_w(fn), debugstr_w(sn), cause); + return NULL; +} + +/****************************************************************** + * DRIVER_SendMessage16 + * + * + */ +static LRESULT DRIVER_SendMessage16(HDRVR16 hDrv16, UINT msg, + LPARAM lParam1, LPARAM lParam2) +{ + LRESULT ret = 0; + WINMM_MapType map; + + TRACE("Before sdm16 call hDrv=%04x wMsg=%04x p1=%08lx p2=%08lx\n", + hDrv16, msg, lParam1, lParam2); + + switch (map = DRIVER_MapMsg32To16(msg, &lParam1, &lParam2)) { + case WINMM_MAP_OKMEM: + case WINMM_MAP_OK: + ret = SendDriverMessage16(hDrv16, msg, lParam1, lParam2); + if (map == WINMM_MAP_OKMEM) + DRIVER_UnMapMsg32To16(msg, lParam1, lParam2); + default: + break; + } + return ret; +} + +/****************************************************************** + * DRIVER_CloseDriver16 + * + * + */ +static LRESULT DRIVER_CloseDriver16(HDRVR16 hDrv16, LPARAM lParam1, LPARAM lParam2) +{ + return CloseDriver16(hDrv16, lParam1, lParam2); +} + +/************************************************************************** + * DrvOpen [MMSYSTEM.1100] + */ +HDRVR16 WINAPI DrvOpen16(LPSTR lpDriverName, LPSTR lpSectionName, LPARAM lParam) +{ + return OpenDriver16(lpDriverName, lpSectionName, lParam); +} + +/************************************************************************** + * DrvClose [MMSYSTEM.1101] + */ +LRESULT WINAPI DrvClose16(HDRVR16 hDrv, LPARAM lParam1, LPARAM lParam2) +{ + return CloseDriver16(hDrv, lParam1, lParam2); +} + +/************************************************************************** + * DrvSendMessage [MMSYSTEM.1102] + */ +LRESULT WINAPI DrvSendMessage16(HDRVR16 hDrv, WORD msg, LPARAM lParam1, + LPARAM lParam2) +{ + return SendDriverMessage16(hDrv, msg, lParam1, lParam2); +} + +/************************************************************************** + * DrvGetModuleHandle [MMSYSTEM.1103] + */ +HANDLE16 WINAPI DrvGetModuleHandle16(HDRVR16 hDrv) +{ + return GetDriverModuleHandle16(hDrv); +} + +/************************************************************************** + * DrvDefDriverProc [MMSYSTEM.1104] + */ +LRESULT WINAPI DrvDefDriverProc16(DWORD dwDriverID, HDRVR16 hDrv, WORD wMsg, + DWORD dwParam1, DWORD dwParam2) +{ + return DefDriverProc16(dwDriverID, hDrv, wMsg, dwParam1, dwParam2); +} + +/************************************************************************** + * DriverProc [MMSYSTEM.6] + */ +LRESULT WINAPI DriverProc16(DWORD dwDevID, HDRVR16 hDrv, WORD wMsg, + DWORD dwParam1, DWORD dwParam2) +{ + TRACE("dwDevID=%08lx hDrv=%04x wMsg=%04x dwParam1=%08lx dwParam2=%08lx\n", + dwDevID, hDrv, wMsg, dwParam1, dwParam2); + + return DrvDefDriverProc16(dwDevID, hDrv, wMsg, dwParam1, dwParam2); +} + +/* ################################################### + * # TIME # + * ################################################### + */ + +/****************************************************************** + * MMSYSTEM_MMTIME32to16 + * + * + */ +void MMSYSTEM_MMTIME32to16(LPMMTIME16 mmt16, const MMTIME* mmt32) +{ + mmt16->wType = mmt32->wType; + /* layout of rest is the same for 32/16, + * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding + */ + memcpy(&(mmt16->u), &(mmt32->u), sizeof(mmt16->u)); +} + +/****************************************************************** + * MMSYSTEM_MMTIME16to32 + * + * + */ +void MMSYSTEM_MMTIME16to32(LPMMTIME mmt32, const MMTIME16* mmt16) +{ + mmt32->wType = mmt16->wType; + /* layout of rest is the same for 32/16, + * Note: mmt16->u is 2 bytes smaller than mmt32->u, which has padding + */ + memcpy(&(mmt32->u), &(mmt16->u), sizeof(mmt16->u)); +} + +/************************************************************************** + * timeGetSystemTime [MMSYSTEM.601] + */ +MMRESULT16 WINAPI timeGetSystemTime16(LPMMTIME16 lpTime, UINT16 wSize) +{ + if (wSize >= sizeof(*lpTime)) { + lpTime->wType = TIME_MS; + lpTime->u.ms = GetTickCount(); + + TRACE("=> %lu\n", lpTime->u.ms); + } + + return 0; +} + +/************************************************************************** + * timeSetEvent [MMSYSTEM.602] + */ +MMRESULT16 WINAPI timeSetEvent16(UINT16 wDelay, UINT16 wResol, LPTIMECALLBACK16 lpFunc, + DWORD dwUser, UINT16 wFlags) +{ + if (wFlags & WINE_TIMER_IS32) + WARN("Unknown windows flag... wine internally used.. ooch\n"); + + return TIME_SetEventInternal(wDelay, wResol, (LPTIMECALLBACK)lpFunc, + dwUser, wFlags & ~WINE_TIMER_IS32); +} + +/************************************************************************** + * timeKillEvent [MMSYSTEM.603] + */ +MMRESULT16 WINAPI timeKillEvent16(UINT16 wID) +{ + return timeKillEvent(wID); +} + +/************************************************************************** + * timeGetDevCaps [MMSYSTEM.604] + */ +MMRESULT16 WINAPI timeGetDevCaps16(LPTIMECAPS16 lpCaps, UINT16 wSize) +{ + TIMECAPS caps; + MMRESULT ret; + TRACE("(%p, %u) !\n", lpCaps, wSize); + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = timeGetDevCaps(&caps, sizeof(caps)); + if (ret == MMSYSERR_NOERROR) { + TIMECAPS16 tc16; + tc16.wPeriodMin = caps.wPeriodMin; + tc16.wPeriodMax = caps.wPeriodMax; + memcpy(lpCaps, &tc16, min(wSize, sizeof(tc16))); + } + return ret; +} + +/************************************************************************** + * timeBeginPeriod [MMSYSTEM.605] + */ +MMRESULT16 WINAPI timeBeginPeriod16(UINT16 wPeriod) +{ + TRACE("(%u) !\n", wPeriod); + + return timeBeginPeriod(wPeriod); +} + +/************************************************************************** + * timeEndPeriod [MMSYSTEM.606] + */ +MMRESULT16 WINAPI timeEndPeriod16(UINT16 wPeriod) +{ + TRACE("(%u) !\n", wPeriod); + + return timeEndPeriod(wPeriod); +} + +/************************************************************************** + * mciSendString [MMSYSTEM.702] + */ +DWORD WINAPI mciSendString16(LPCSTR lpstrCommand, LPSTR lpstrRet, + UINT16 uRetLen, HWND16 hwndCallback) +{ + return mciSendStringA(lpstrCommand, lpstrRet, uRetLen, HWND_32(hwndCallback)); +} + +/************************************************************************** + * mciLoadCommandResource [MMSYSTEM.705] + */ +UINT16 WINAPI mciLoadCommandResource16(HINSTANCE16 hInst, LPCSTR resname, UINT16 type) +{ + HRSRC16 res; + HGLOBAL16 handle; + const BYTE* ptr16; + BYTE* ptr32; + unsigned pos = 0, size = 1024, len; + const char* str; + DWORD flg; + WORD eid; + UINT16 ret = MCIERR_OUT_OF_MEMORY; + + if (!(res = FindResource16( hInst, resname, (LPSTR)RT_RCDATA))) return MCI_NO_COMMAND_TABLE; + if (!(handle = LoadResource16( hInst, res ))) return MCI_NO_COMMAND_TABLE; + ptr16 = LockResource16(handle); + /* converting the 16 bit resource table into a 32W one */ + if ((ptr32 = HeapAlloc(GetProcessHeap(), 0, size))) + { + do { + str = (LPCSTR)ptr16; + ptr16 += strlen(str) + 1; + flg = *(const DWORD*)ptr16; + eid = *(const WORD*)(ptr16 + sizeof(DWORD)); + ptr16 += sizeof(DWORD) + sizeof(WORD); + len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0) * sizeof(WCHAR); + if (pos + len + sizeof(DWORD) + sizeof(WORD) > size) + { + while (pos + len * sizeof(WCHAR) + sizeof(DWORD) + sizeof(WORD) > size) size += 1024; + ptr32 = HeapReAlloc(GetProcessHeap(), 0, ptr32, size); + if (!ptr32) goto the_end; + } + MultiByteToWideChar(CP_ACP, 0, str, -1, (LPWSTR)(ptr32 + pos), len / sizeof(WCHAR)); + *(DWORD*)(ptr32 + pos + len) = flg; + *(WORD*)(ptr32 + pos + len + sizeof(DWORD)) = eid; + pos += len + sizeof(DWORD) + sizeof(WORD); + } while (eid != MCI_END_COMMAND_LIST); + } +the_end: + FreeResource16( handle ); + if (ptr32) ret = MCI_SetCommandTable(ptr32, type); + return ret; +} + +/************************************************************************** + * mciFreeCommandResource [MMSYSTEM.713] + */ +BOOL16 WINAPI mciFreeCommandResource16(UINT16 uTable) +{ + TRACE("(%04x)!\n", uTable); + + return MCI_DeleteCommandTable(uTable, TRUE); +} + +/* ################################################### + * # MMIO # + * ################################################### + */ + +/**************************************************************** + * MMIO_Map32To16 [INTERNAL] + */ +static LRESULT MMIO_Map32To16(DWORD wMsg, LPARAM* lp1, LPARAM* lp2) +{ + switch (wMsg) { + case MMIOM_CLOSE: + case MMIOM_SEEK: + /* nothing to do */ + break; + case MMIOM_OPEN: + case MMIOM_READ: + case MMIOM_WRITE: + case MMIOM_WRITEFLUSH: + *lp1 = MapLS( (void *)*lp1 ); + break; + case MMIOM_RENAME: + *lp1 = MapLS( (void *)*lp1 ); + *lp2 = MapLS( (void *)*lp2 ); + break; + default: + if (wMsg < MMIOM_USER) + TRACE("Not a mappable message (%ld)\n", wMsg); + } + return MMSYSERR_NOERROR; +} + +/**************************************************************** + * MMIO_UnMap32To16 [INTERNAL] + */ +static LRESULT MMIO_UnMap32To16(DWORD wMsg, LPARAM lParam1, LPARAM lParam2, + LPARAM lp1, LPARAM lp2) +{ + switch (wMsg) { + case MMIOM_CLOSE: + case MMIOM_SEEK: + /* nothing to do */ + break; + case MMIOM_OPEN: + case MMIOM_READ: + case MMIOM_WRITE: + case MMIOM_WRITEFLUSH: + UnMapLS( lp1 ); + break; + case MMIOM_RENAME: + UnMapLS( lp1 ); + UnMapLS( lp2 ); + break; + default: + if (wMsg < MMIOM_USER) + TRACE("Not a mappable message (%ld)\n", wMsg); + } + return MMSYSERR_NOERROR; +} + +/****************************************************************** + * MMIO_Callback16 + * + * + */ +static LRESULT MMIO_Callback16(SEGPTR cb16, LPMMIOINFO lpmmioinfo, UINT uMessage, + LPARAM lParam1, LPARAM lParam2) +{ + LRESULT result; + MMIOINFO16 mmioInfo16; + SEGPTR segmmioInfo16; + LPARAM lp1 = lParam1, lp2 = lParam2; + WORD args[7]; + + memset(&mmioInfo16, 0, sizeof(MMIOINFO16)); + mmioInfo16.lDiskOffset = lpmmioinfo->lDiskOffset; + mmioInfo16.adwInfo[0] = lpmmioinfo->adwInfo[0]; + mmioInfo16.adwInfo[1] = lpmmioinfo->adwInfo[1]; + mmioInfo16.adwInfo[2] = lpmmioinfo->adwInfo[2]; + /* map (lParam1, lParam2) into (lp1, lp2) 32=>16 */ + if ((result = MMIO_Map32To16(uMessage, &lp1, &lp2)) != MMSYSERR_NOERROR) + return result; + + segmmioInfo16 = MapLS(&mmioInfo16); + args[6] = HIWORD(segmmioInfo16); + args[5] = LOWORD(segmmioInfo16); + args[4] = uMessage; + args[3] = HIWORD(lp1); + args[2] = LOWORD(lp1); + args[1] = HIWORD(lp2); + args[0] = LOWORD(lp2); + WOWCallback16Ex( cb16, WCB16_PASCAL, sizeof(args), args, &result ); + UnMapLS(segmmioInfo16); + MMIO_UnMap32To16(uMessage, lParam1, lParam2, lp1, lp2); + + lpmmioinfo->lDiskOffset = mmioInfo16.lDiskOffset; + lpmmioinfo->adwInfo[0] = mmioInfo16.adwInfo[0]; + lpmmioinfo->adwInfo[1] = mmioInfo16.adwInfo[1]; + lpmmioinfo->adwInfo[2] = mmioInfo16.adwInfo[2]; + + return result; +} + +/****************************************************************** + * MMIO_ResetSegmentedData + * + */ +static LRESULT MMIO_SetSegmentedBuffer(HMMIO hmmio, SEGPTR ptr, BOOL release) +{ + LPWINE_MMIO wm; + + if ((wm = MMIO_Get(hmmio)) == NULL) + return MMSYSERR_INVALHANDLE; + if (release) UnMapLS(wm->segBuffer16); + wm->segBuffer16 = ptr; + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * mmioOpen [MMSYSTEM.1210] + */ +HMMIO16 WINAPI mmioOpen16(LPSTR szFileName, MMIOINFO16* lpmmioinfo16, + DWORD dwOpenFlags) +{ + HMMIO ret; + + if (lpmmioinfo16) { + MMIOINFO mmioinfo; + + memset(&mmioinfo, 0, sizeof(mmioinfo)); + + mmioinfo.dwFlags = lpmmioinfo16->dwFlags; + mmioinfo.fccIOProc = lpmmioinfo16->fccIOProc; + mmioinfo.pIOProc = (LPMMIOPROC)lpmmioinfo16->pIOProc; + mmioinfo.cchBuffer = lpmmioinfo16->cchBuffer; + mmioinfo.pchBuffer = MapSL((DWORD)lpmmioinfo16->pchBuffer); + mmioinfo.adwInfo[0] = lpmmioinfo16->adwInfo[0]; + /* if we don't have a file name, it's likely a passed open file descriptor */ + if (!szFileName) + mmioinfo.adwInfo[0] = (DWORD)DosFileHandleToWin32Handle(mmioinfo.adwInfo[0]); + mmioinfo.adwInfo[1] = lpmmioinfo16->adwInfo[1]; + mmioinfo.adwInfo[2] = lpmmioinfo16->adwInfo[2]; + + ret = MMIO_Open(szFileName, &mmioinfo, dwOpenFlags, MMIO_PROC_16); + MMIO_SetSegmentedBuffer(mmioinfo.hmmio, (SEGPTR)lpmmioinfo16->pchBuffer, FALSE); + + lpmmioinfo16->wErrorRet = mmioinfo.wErrorRet; + lpmmioinfo16->hmmio = HMMIO_16(mmioinfo.hmmio); + } else { + ret = MMIO_Open(szFileName, NULL, dwOpenFlags, MMIO_PROC_32A); + } + return HMMIO_16(ret); +} + +/************************************************************************** + * mmioClose [MMSYSTEM.1211] + */ +MMRESULT16 WINAPI mmioClose16(HMMIO16 hmmio, UINT16 uFlags) +{ + MMIO_SetSegmentedBuffer(HMMIO_32(hmmio), (SEGPTR)NULL, TRUE); + return mmioClose(HMMIO_32(hmmio), uFlags); +} + +/************************************************************************** + * mmioRead [MMSYSTEM.1212] + */ +LONG WINAPI mmioRead16(HMMIO16 hmmio, HPSTR pch, LONG cch) +{ + return mmioRead(HMMIO_32(hmmio), pch, cch); +} + +/************************************************************************** + * mmioWrite [MMSYSTEM.1213] + */ +LONG WINAPI mmioWrite16(HMMIO16 hmmio, HPCSTR pch, LONG cch) +{ + return mmioWrite(HMMIO_32(hmmio),pch,cch); +} + +/************************************************************************** + * mmioSeek [MMSYSTEM.1214] + */ +LONG WINAPI mmioSeek16(HMMIO16 hmmio, LONG lOffset, INT16 iOrigin) +{ + return mmioSeek(HMMIO_32(hmmio), lOffset, iOrigin); +} + +/************************************************************************** + * mmioGetInfo [MMSYSTEM.1215] + */ +MMRESULT16 WINAPI mmioGetInfo16(HMMIO16 hmmio, MMIOINFO16* lpmmioinfo, UINT16 uFlags) +{ + MMIOINFO mmioinfo; + MMRESULT ret; + LPWINE_MMIO wm; + + TRACE("(0x%04x,%p,0x%08x)\n", hmmio, lpmmioinfo, uFlags); + + if ((wm = MMIO_Get(HMMIO_32(hmmio))) == NULL) + return MMSYSERR_INVALHANDLE; + + ret = mmioGetInfo(HMMIO_32(hmmio), &mmioinfo, uFlags); + if (ret != MMSYSERR_NOERROR) return ret; + + lpmmioinfo->dwFlags = mmioinfo.dwFlags; + lpmmioinfo->fccIOProc = mmioinfo.fccIOProc; + lpmmioinfo->pIOProc = (wm->ioProc->type == MMIO_PROC_16) ? + (LPMMIOPROC16)wm->ioProc->pIOProc : NULL; + lpmmioinfo->wErrorRet = mmioinfo.wErrorRet; + lpmmioinfo->hTask = HTASK_16(mmioinfo.hTask); + lpmmioinfo->cchBuffer = mmioinfo.cchBuffer; + lpmmioinfo->pchBuffer = (void*)wm->segBuffer16; + lpmmioinfo->pchNext = (void*)(wm->segBuffer16 + (mmioinfo.pchNext - mmioinfo.pchBuffer)); + lpmmioinfo->pchEndRead = (void*)(wm->segBuffer16 + (mmioinfo.pchEndRead - mmioinfo.pchBuffer)); + lpmmioinfo->pchEndWrite = (void*)(wm->segBuffer16 + (mmioinfo.pchEndWrite - mmioinfo.pchBuffer)); + lpmmioinfo->lBufOffset = mmioinfo.lBufOffset; + lpmmioinfo->lDiskOffset = mmioinfo.lDiskOffset; + lpmmioinfo->adwInfo[0] = mmioinfo.adwInfo[0]; + lpmmioinfo->adwInfo[1] = mmioinfo.adwInfo[1]; + lpmmioinfo->adwInfo[2] = mmioinfo.adwInfo[2]; + lpmmioinfo->dwReserved1 = 0; + lpmmioinfo->dwReserved2 = 0; + lpmmioinfo->hmmio = HMMIO_16(mmioinfo.hmmio); + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * mmioSetInfo [MMSYSTEM.1216] + */ +MMRESULT16 WINAPI mmioSetInfo16(HMMIO16 hmmio, const MMIOINFO16* lpmmioinfo, UINT16 uFlags) +{ + MMIOINFO mmioinfo; + MMRESULT ret; + + TRACE("(0x%04x,%p,0x%08x)\n",hmmio,lpmmioinfo,uFlags); + + ret = mmioGetInfo(HMMIO_32(hmmio), &mmioinfo, 0); + if (ret != MMSYSERR_NOERROR) return ret; + + /* check if seg and lin buffers are the same */ + if (mmioinfo.cchBuffer != lpmmioinfo->cchBuffer || + mmioinfo.pchBuffer != MapSL((DWORD)lpmmioinfo->pchBuffer)) + return MMSYSERR_INVALPARAM; + + /* check pointers coherence */ + if (lpmmioinfo->pchNext < lpmmioinfo->pchBuffer || + lpmmioinfo->pchNext > lpmmioinfo->pchBuffer + lpmmioinfo->cchBuffer || + lpmmioinfo->pchEndRead < lpmmioinfo->pchBuffer || + lpmmioinfo->pchEndRead > lpmmioinfo->pchBuffer + lpmmioinfo->cchBuffer || + lpmmioinfo->pchEndWrite < lpmmioinfo->pchBuffer || + lpmmioinfo->pchEndWrite > lpmmioinfo->pchBuffer + lpmmioinfo->cchBuffer) + return MMSYSERR_INVALPARAM; + + mmioinfo.pchNext = mmioinfo.pchBuffer + (lpmmioinfo->pchNext - lpmmioinfo->pchBuffer); + mmioinfo.pchEndRead = mmioinfo.pchBuffer + (lpmmioinfo->pchEndRead - lpmmioinfo->pchBuffer); + mmioinfo.pchEndWrite = mmioinfo.pchBuffer + (lpmmioinfo->pchEndWrite - lpmmioinfo->pchBuffer); + + return mmioSetInfo(HMMIO_32(hmmio), &mmioinfo, uFlags); +} + +/************************************************************************** + * mmioSetBuffer [MMSYSTEM.1217] + */ +MMRESULT16 WINAPI mmioSetBuffer16(HMMIO16 hmmio, LPSTR pchBuffer, + LONG cchBuffer, UINT16 uFlags) +{ + MMRESULT ret = mmioSetBuffer(HMMIO_32(hmmio), MapSL((DWORD)pchBuffer), + cchBuffer, uFlags); + + if (ret == MMSYSERR_NOERROR) + MMIO_SetSegmentedBuffer(HMMIO_32(hmmio), (DWORD)pchBuffer, TRUE); + else + UnMapLS((DWORD)pchBuffer); + return ret; +} + +/************************************************************************** + * mmioFlush [MMSYSTEM.1218] + */ +MMRESULT16 WINAPI mmioFlush16(HMMIO16 hmmio, UINT16 uFlags) +{ + return mmioFlush(HMMIO_32(hmmio), uFlags); +} + +/*********************************************************************** + * mmioAdvance [MMSYSTEM.1219] + */ +MMRESULT16 WINAPI mmioAdvance16(HMMIO16 hmmio, MMIOINFO16* lpmmioinfo, UINT16 uFlags) +{ + MMIOINFO mmioinfo; + LRESULT ret; + + /* WARNING: this heavily relies on mmioAdvance implementation (for choosing which + * fields to init + */ + if (lpmmioinfo) + { + mmioinfo.pchBuffer = MapSL((DWORD)lpmmioinfo->pchBuffer); + mmioinfo.pchNext = MapSL((DWORD)lpmmioinfo->pchNext); + mmioinfo.dwFlags = lpmmioinfo->dwFlags; + mmioinfo.lBufOffset = lpmmioinfo->lBufOffset; + ret = mmioAdvance(HMMIO_32(hmmio), &mmioinfo, uFlags); + } + else + ret = mmioAdvance(HMMIO_32(hmmio), NULL, uFlags); + + if (ret != MMSYSERR_NOERROR) return ret; + + if (lpmmioinfo) + { + lpmmioinfo->dwFlags = mmioinfo.dwFlags; + lpmmioinfo->pchNext = (void*)(lpmmioinfo->pchBuffer + (mmioinfo.pchNext - mmioinfo.pchBuffer)); + lpmmioinfo->pchEndRead = (void*)(lpmmioinfo->pchBuffer + (mmioinfo.pchEndRead - mmioinfo.pchBuffer)); + lpmmioinfo->pchEndWrite = (void*)(lpmmioinfo->pchBuffer + (mmioinfo.pchEndWrite - mmioinfo.pchBuffer)); + lpmmioinfo->lBufOffset = mmioinfo.lBufOffset; + lpmmioinfo->lDiskOffset = mmioinfo.lDiskOffset; + } + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * mmioStringToFOURCC [MMSYSTEM.1220] + */ +FOURCC WINAPI mmioStringToFOURCC16(LPCSTR sz, UINT16 uFlags) +{ + return mmioStringToFOURCCA(sz, uFlags); +} + +/************************************************************************** + * mmioInstallIOProc [MMSYSTEM.1221] + */ +LPMMIOPROC16 WINAPI mmioInstallIOProc16(FOURCC fccIOProc, LPMMIOPROC16 pIOProc, + DWORD dwFlags) +{ + return (LPMMIOPROC16)MMIO_InstallIOProc(fccIOProc, (LPMMIOPROC)pIOProc, + dwFlags, MMIO_PROC_16); +} + +/************************************************************************** + * mmioSendMessage [MMSYSTEM.1222] + */ +LRESULT WINAPI mmioSendMessage16(HMMIO16 hmmio, UINT16 uMessage, + LPARAM lParam1, LPARAM lParam2) +{ + return MMIO_SendMessage(HMMIO_32(hmmio), uMessage, + lParam1, lParam2, MMIO_PROC_16); +} + +/************************************************************************** + * mmioDescend [MMSYSTEM.1223] + */ +MMRESULT16 WINAPI mmioDescend16(HMMIO16 hmmio, LPMMCKINFO lpck, + const MMCKINFO* lpckParent, UINT16 uFlags) +{ + return mmioDescend(HMMIO_32(hmmio), lpck, lpckParent, uFlags); +} + +/************************************************************************** + * mmioAscend [MMSYSTEM.1224] + */ +MMRESULT16 WINAPI mmioAscend16(HMMIO16 hmmio, MMCKINFO* lpck, UINT16 uFlags) +{ + return mmioAscend(HMMIO_32(hmmio),lpck,uFlags); +} + +/************************************************************************** + * mmioCreateChunk [MMSYSTEM.1225] + */ +MMRESULT16 WINAPI mmioCreateChunk16(HMMIO16 hmmio, MMCKINFO* lpck, UINT16 uFlags) +{ + return mmioCreateChunk(HMMIO_32(hmmio), lpck, uFlags); +} + +/************************************************************************** + * mmioRename [MMSYSTEM.1226] + */ +MMRESULT16 WINAPI mmioRename16(LPCSTR szFileName, LPCSTR szNewFileName, + MMIOINFO16* lpmmioinfo, DWORD dwRenameFlags) +{ + BOOL inst = FALSE; + MMRESULT ret; + MMIOINFO mmioinfo; + + if (lpmmioinfo != NULL && lpmmioinfo->pIOProc != NULL && + lpmmioinfo->fccIOProc == 0) { + FIXME("Can't handle this case yet\n"); + return MMSYSERR_ERROR; + } + + /* this is a bit hacky, but it'll work if we get a fourCC code or nothing. + * but a non installed ioproc without a fourcc won't do + */ + if (lpmmioinfo && lpmmioinfo->fccIOProc && lpmmioinfo->pIOProc) { + MMIO_InstallIOProc(lpmmioinfo->fccIOProc, (LPMMIOPROC)lpmmioinfo->pIOProc, + MMIO_INSTALLPROC, MMIO_PROC_16); + inst = TRUE; + } + memset(&mmioinfo, 0, sizeof(mmioinfo)); + mmioinfo.fccIOProc = lpmmioinfo->fccIOProc; + ret = mmioRenameA(szFileName, szNewFileName, &mmioinfo, dwRenameFlags); + if (inst) { + MMIO_InstallIOProc(lpmmioinfo->fccIOProc, NULL, + MMIO_REMOVEPROC, MMIO_PROC_16); + } + return ret; +} + +/* ################################################### + * # JOYSTICK # + * ################################################### + */ + +/************************************************************************** + * joyGetNumDevs [MMSYSTEM.101] + */ +UINT16 WINAPI joyGetNumDevs16(void) +{ + return joyGetNumDevs(); +} + +/************************************************************************** + * joyGetDevCaps [MMSYSTEM.102] + */ +MMRESULT16 WINAPI joyGetDevCaps16(UINT16 wID, LPJOYCAPS16 lpCaps, UINT16 wSize) +{ + JOYCAPSA jca; + MMRESULT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = joyGetDevCapsA(wID, &jca, sizeof(jca)); + + if (ret != JOYERR_NOERROR) return ret; + lpCaps->wMid = jca.wMid; + lpCaps->wPid = jca.wPid; + strcpy(lpCaps->szPname, jca.szPname); + lpCaps->wXmin = jca.wXmin; + lpCaps->wXmax = jca.wXmax; + lpCaps->wYmin = jca.wYmin; + lpCaps->wYmax = jca.wYmax; + lpCaps->wZmin = jca.wZmin; + lpCaps->wZmax = jca.wZmax; + lpCaps->wNumButtons = jca.wNumButtons; + lpCaps->wPeriodMin = jca.wPeriodMin; + lpCaps->wPeriodMax = jca.wPeriodMax; + + if (wSize >= sizeof(JOYCAPS16)) { /* Win95 extensions ? */ + lpCaps->wRmin = jca.wRmin; + lpCaps->wRmax = jca.wRmax; + lpCaps->wUmin = jca.wUmin; + lpCaps->wUmax = jca.wUmax; + lpCaps->wVmin = jca.wVmin; + lpCaps->wVmax = jca.wVmax; + lpCaps->wCaps = jca.wCaps; + lpCaps->wMaxAxes = jca.wMaxAxes; + lpCaps->wNumAxes = jca.wNumAxes; + lpCaps->wMaxButtons = jca.wMaxButtons; + strcpy(lpCaps->szRegKey, jca.szRegKey); + strcpy(lpCaps->szOEMVxD, jca.szOEMVxD); + } + + return ret; +} + +/************************************************************************** + * joyGetPosEx [MMSYSTEM.110] + */ +MMRESULT16 WINAPI joyGetPosEx16(UINT16 wID, LPJOYINFOEX lpInfo) +{ + return joyGetPosEx(wID, lpInfo); +} + +/************************************************************************** + * joyGetPos [MMSYSTEM.103] + */ +MMRESULT16 WINAPI joyGetPos16(UINT16 wID, LPJOYINFO16 lpInfo) +{ + JOYINFO ji; + MMRESULT ret; + + TRACE("(%d, %p);\n", wID, lpInfo); + + if ((ret = joyGetPos(wID, &ji)) == JOYERR_NOERROR) { + lpInfo->wXpos = ji.wXpos; + lpInfo->wYpos = ji.wYpos; + lpInfo->wZpos = ji.wZpos; + lpInfo->wButtons = ji.wButtons; + } + return ret; +} + +/************************************************************************** + * joyGetThreshold [MMSYSTEM.104] + */ +MMRESULT16 WINAPI joyGetThreshold16(UINT16 wID, LPUINT16 lpThreshold) +{ + UINT t; + MMRESULT ret; + + ret = joyGetThreshold(wID, &t); + if (ret == JOYERR_NOERROR) + *lpThreshold = t; + return ret; +} + +/************************************************************************** + * joyReleaseCapture [MMSYSTEM.105] + */ +MMRESULT16 WINAPI joyReleaseCapture16(UINT16 wID) +{ + return joyReleaseCapture(wID); +} + +/************************************************************************** + * joySetCapture [MMSYSTEM.106] + */ +MMRESULT16 WINAPI joySetCapture16(HWND16 hWnd, UINT16 wID, UINT16 wPeriod, BOOL16 bChanged) +{ + return joySetCapture16(hWnd, wID, wPeriod, bChanged); +} + +/************************************************************************** + * joySetThreshold [MMSYSTEM.107] + */ +MMRESULT16 WINAPI joySetThreshold16(UINT16 wID, UINT16 wThreshold) +{ + return joySetThreshold16(wID,wThreshold); +} + +/************************************************************************** + * joySetCalibration [MMSYSTEM.109] + */ +MMRESULT16 WINAPI joySetCalibration16(UINT16 wID) +{ + FIXME("(%04X): stub.\n", wID); + return JOYERR_NOCANDO; +} diff --git a/reactos/lib/winmm/playsound.c b/reactos/lib/winmm/playsound.c index b82b55dc399..a97e9967feb 100644 --- a/reactos/lib/winmm/playsound.c +++ b/reactos/lib/winmm/playsound.c @@ -1,526 +1,526 @@ -/* -*- tab-width: 8; c-basic-offset: 4 -*- */ - -/* - * MMSYTEM functions - * - * Copyright 1993 Martin Ayotte - * 1998-2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> -#include <string.h> - -#include "windef.h" -#include "winbase.h" -#include "mmsystem.h" -#include "wingdi.h" -#include "winuser.h" -#include "winreg.h" -#include "winemm.h" -#include "winternl.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(winmm); - -static HMMIO get_mmioFromFile(LPCWSTR lpszName) -{ - HMMIO ret; - WCHAR buf[256]; - LPWSTR dummy; - - ret = mmioOpenW((LPWSTR)lpszName, NULL, - MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE); - if (ret != 0) return ret; - if (SearchPathW(NULL, lpszName, NULL, sizeof(buf)/sizeof(buf[0]), buf, &dummy)) - { - return mmioOpenW(buf, NULL, - MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE); - } - return 0; -} - -static HMMIO get_mmioFromProfile(UINT uFlags, LPCWSTR lpszName) -{ - WCHAR str[128]; - LPWSTR ptr; - HMMIO hmmio; - HKEY hRegSnd, hRegApp, hScheme, hSnd; - DWORD err, type, count; - - static const WCHAR wszSounds[] = {'S','o','u','n','d','s',0}; - static const WCHAR wszDefault[] = {'D','e','f','a','u','l','t',0}; - static const WCHAR wszKey[] = {'A','p','p','E','v','e','n','t','s','\\', - 'S','c','h','e','m','e','s','\\', - 'A','p','p','s',0}; - static const WCHAR wszDotDefault[] = {'.','D','e','f','a','u','l','t',0}; - static const WCHAR wszDotCurrent[] = {'.','C','u','r','r','e','n','t',0}; - static const WCHAR wszNull[] = {0}; - - TRACE("searching in SystemSound list for %s\n", debugstr_w(lpszName)); - GetProfileStringW(wszSounds, lpszName, wszNull, str, sizeof(str)/sizeof(str[0])); - if (lstrlenW(str) == 0) - { - if (uFlags & SND_NODEFAULT) goto next; - GetProfileStringW(wszSounds, wszDefault, wszNull, str, sizeof(str)/sizeof(str[0])); - if (lstrlenW(str) == 0) goto next; - } - for (ptr = str; *ptr && *ptr != ','; ptr++); - if (*ptr) *ptr = 0; - hmmio = mmioOpenW(str, NULL, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE); - if (hmmio != 0) return hmmio; - next: - /* we look up the registry under - * HKCU\AppEvents\Schemes\Apps\.Default - * HKCU\AppEvents\Schemes\Apps\<AppName> - */ - if (RegOpenKeyW(HKEY_CURRENT_USER, wszKey, &hRegSnd) != 0) goto none; - if (uFlags & SND_APPLICATION) - { - DWORD len; - - err = 1; /* error */ - len = GetModuleFileNameW(0, str, sizeof(str)/sizeof(str[0])); - if (len > 0 && len < sizeof(str)/sizeof(str[0])) - { - for (ptr = str + lstrlenW(str) - 1; ptr >= str; ptr--) - { - if (*ptr == '.') *ptr = 0; - if (*ptr == '\\') - { - err = RegOpenKeyW(hRegSnd, ptr+1, &hRegApp); - break; - } - } - } - } - else - { - err = RegOpenKeyW(hRegSnd, wszDotDefault, &hRegApp); - } - RegCloseKey(hRegSnd); - if (err != 0) goto none; - err = RegOpenKeyW(hRegApp, lpszName, &hScheme); - RegCloseKey(hRegApp); - if (err != 0) goto none; - /* what's the difference between .Current and .Default ? */ - err = RegOpenKeyW(hScheme, wszDotDefault, &hSnd); - if (err != 0) - { - err = RegOpenKeyW(hScheme, wszDotCurrent, &hSnd); - RegCloseKey(hScheme); - if (err != 0) - goto none; - } - count = sizeof(str)/sizeof(str[0]); - err = RegQueryValueExW(hSnd, NULL, 0, &type, (LPBYTE)str, &count); - RegCloseKey(hSnd); - if (err != 0 || !*str) goto none; - hmmio = mmioOpenW(str, NULL, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE); - if (hmmio) return hmmio; - none: - WARN("can't find SystemSound='%s' !\n", debugstr_w(lpszName)); - return 0; -} - -struct playsound_data -{ - HANDLE hEvent; - DWORD dwEventCount; -}; - -static void CALLBACK PlaySound_Callback(HWAVEOUT hwo, UINT uMsg, - DWORD dwInstance, - DWORD dwParam1, DWORD dwParam2) -{ - struct playsound_data* s = (struct playsound_data*)dwInstance; - - switch (uMsg) { - case WOM_OPEN: - case WOM_CLOSE: - break; - case WOM_DONE: - InterlockedIncrement(&s->dwEventCount); - TRACE("Returning waveHdr=%lx\n", dwParam1); - SetEvent(s->hEvent); - break; - default: - ERR("Unknown uMsg=%d\n", uMsg); - } -} - -static void PlaySound_WaitDone(struct playsound_data* s) -{ - for (;;) { - ResetEvent(s->hEvent); - if (InterlockedDecrement(&s->dwEventCount) >= 0) break; - InterlockedIncrement(&s->dwEventCount); - - WaitForSingleObject(s->hEvent, INFINITE); - } -} - -static BOOL PlaySound_IsString(DWORD fdwSound, const void* psz) -{ - /* SND_RESOURCE is 0x40004 while - * SND_MEMORY is 0x00004 - */ - switch (fdwSound & (SND_RESOURCE|SND_ALIAS|SND_FILENAME)) - { - case SND_RESOURCE: return HIWORD(psz) != 0; /* by name or by ID ? */ - case SND_MEMORY: return FALSE; - case SND_ALIAS: /* what about ALIAS_ID ??? */ - case SND_FILENAME: - case 0: return TRUE; - default: FIXME("WTF\n"); return FALSE; - } -} - -static void PlaySound_Free(WINE_PLAYSOUND* wps) -{ - WINE_PLAYSOUND** p; - - EnterCriticalSection(&WINMM_IData.cs); - for (p = &WINMM_IData.lpPlaySound; *p && *p != wps; p = &((*p)->lpNext)); - if (*p) *p = (*p)->lpNext; - if (WINMM_IData.lpPlaySound == NULL) SetEvent(WINMM_IData.psLastEvent); - LeaveCriticalSection(&WINMM_IData.cs); - if (wps->bAlloc) HeapFree(GetProcessHeap(), 0, (void*)wps->pszSound); - if (wps->hThread) CloseHandle(wps->hThread); - HeapFree(GetProcessHeap(), 0, wps); -} - -static WINE_PLAYSOUND* PlaySound_Alloc(const void* pszSound, HMODULE hmod, - DWORD fdwSound, BOOL bUnicode) -{ - WINE_PLAYSOUND* wps; - - wps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wps)); - if (!wps) return NULL; - - wps->hMod = hmod; - wps->fdwSound = fdwSound; - if (PlaySound_IsString(fdwSound, pszSound)) - { - if (bUnicode) - { - if (fdwSound & SND_ASYNC) - { - wps->pszSound = HeapAlloc(GetProcessHeap(), 0, - (lstrlenW(pszSound)+1) * sizeof(WCHAR)); - if (!wps->pszSound) goto oom_error; - lstrcpyW((LPWSTR)wps->pszSound, pszSound); - wps->bAlloc = TRUE; - } - else - wps->pszSound = pszSound; - } - else - { - UNICODE_STRING usBuffer; - RtlCreateUnicodeStringFromAsciiz(&usBuffer, pszSound); - wps->pszSound = usBuffer.Buffer; - if (!wps->pszSound) goto oom_error; - wps->bAlloc = TRUE; - } - } - else - wps->pszSound = pszSound; - - return wps; - oom_error: - PlaySound_Free(wps); - return NULL; -} - -static DWORD WINAPI proc_PlaySound(LPVOID arg) -{ - WINE_PLAYSOUND* wps = (WINE_PLAYSOUND*)arg; - BOOL bRet = FALSE; - HMMIO hmmio = 0; - MMCKINFO ckMainRIFF; - MMCKINFO mmckInfo; - LPWAVEFORMATEX lpWaveFormat = NULL; - HWAVEOUT hWave = 0; - LPWAVEHDR waveHdr = NULL; - INT count, bufsize, left, index; - struct playsound_data s; - void* data; - - s.hEvent = 0; - - TRACE("SoundName='%s' !\n", debugstr_w(wps->pszSound)); - - /* if resource, grab it */ - if ((wps->fdwSound & SND_RESOURCE) == SND_RESOURCE) { - static const WCHAR wszWave[] = {'W','A','V','E',0}; - HRSRC hRes; - HGLOBAL hGlob; - - if ((hRes = FindResourceW(wps->hMod, wps->pszSound, wszWave)) == 0 || - (hGlob = LoadResource(wps->hMod, hRes)) == 0) - goto errCleanUp; - if ((data = LockResource(hGlob)) == NULL) { - FreeResource(hGlob); - goto errCleanUp; - } - FreeResource(hGlob); - } else - data = (void*)wps->pszSound; - - /* construct an MMIO stream (either in memory, or from a file */ - if (wps->fdwSound & SND_MEMORY) - { /* NOTE: SND_RESOURCE has the SND_MEMORY bit set */ - MMIOINFO mminfo; - - memset(&mminfo, 0, sizeof(mminfo)); - mminfo.fccIOProc = FOURCC_MEM; - mminfo.pchBuffer = (LPSTR)data; - mminfo.cchBuffer = -1; /* FIXME: when a resource, could grab real size */ - TRACE("Memory sound %p\n", data); - hmmio = mmioOpenW(NULL, &mminfo, MMIO_READ); - } - else if (wps->fdwSound & SND_ALIAS) - { - hmmio = get_mmioFromProfile(wps->fdwSound, wps->pszSound); - } - else if (wps->fdwSound & SND_FILENAME) - { - hmmio = get_mmioFromFile(wps->pszSound); - } - else - { - if ((hmmio = get_mmioFromProfile(wps->fdwSound | SND_NODEFAULT, wps->pszSound)) == 0) - { - if ((hmmio = get_mmioFromFile(wps->pszSound)) == 0) - { - hmmio = get_mmioFromProfile(wps->fdwSound, wps->pszSound); - } - } - } - if (hmmio == 0) goto errCleanUp; - - if (mmioDescend(hmmio, &ckMainRIFF, NULL, 0)) - goto errCleanUp; - - TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n", - (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, ckMainRIFF.cksize); - - if ((ckMainRIFF.ckid != FOURCC_RIFF) || - (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E'))) - goto errCleanUp; - - mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' '); - if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK)) - goto errCleanUp; - - TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n", - (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize); - - lpWaveFormat = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize); - if (mmioRead(hmmio, (HPSTR)lpWaveFormat, mmckInfo.cksize) < sizeof(WAVEFORMAT)) - goto errCleanUp; - - TRACE("wFormatTag=%04X !\n", lpWaveFormat->wFormatTag); - TRACE("nChannels=%d \n", lpWaveFormat->nChannels); - TRACE("nSamplesPerSec=%ld\n", lpWaveFormat->nSamplesPerSec); - TRACE("nAvgBytesPerSec=%ld\n", lpWaveFormat->nAvgBytesPerSec); - TRACE("nBlockAlign=%d \n", lpWaveFormat->nBlockAlign); - TRACE("wBitsPerSample=%u !\n", lpWaveFormat->wBitsPerSample); - - /* move to end of 'fmt ' chunk */ - mmioAscend(hmmio, &mmckInfo, 0); - - mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a'); - if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK)) - goto errCleanUp; - - TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX\n", - (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize); - - s.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); - - if (waveOutOpen(&hWave, WAVE_MAPPER, lpWaveFormat, (DWORD)PlaySound_Callback, - (DWORD)&s, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) - goto errCleanUp; - - /* make it so that 3 buffers per second are needed */ - bufsize = (((lpWaveFormat->nAvgBytesPerSec / 3) - 1) / lpWaveFormat->nBlockAlign + 1) * - lpWaveFormat->nBlockAlign; - waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize); - waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR); - waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize; - waveHdr[0].dwUser = waveHdr[1].dwUser = 0L; - waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L; - waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L; - waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize; - if (waveOutPrepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR)) || - waveOutPrepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR))) { - goto errCleanUp; - } - - s.dwEventCount = 1L; /* for first buffer */ - index = 0; - - do { - left = mmckInfo.cksize; - - mmioSeek(hmmio, mmckInfo.dwDataOffset, SEEK_SET); - while (left) - { - if (WaitForSingleObject(WINMM_IData.psStopEvent, 0) == WAIT_OBJECT_0) - { - wps->bLoop = FALSE; - break; - } - count = mmioRead(hmmio, waveHdr[index].lpData, min(bufsize, left)); - if (count < 1) break; - left -= count; - waveHdr[index].dwBufferLength = count; - waveHdr[index].dwFlags &= ~WHDR_DONE; - if (waveOutWrite(hWave, &waveHdr[index], sizeof(WAVEHDR)) == MMSYSERR_NOERROR) { - index ^= 1; - PlaySound_WaitDone(&s); - } - else FIXME("Couldn't play header\n"); - } - bRet = TRUE; - } while (wps->bLoop); - - PlaySound_WaitDone(&s); /* for last buffer */ - waveOutReset(hWave); - - waveOutUnprepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR)); - waveOutUnprepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR)); - -errCleanUp: - TRACE("Done playing='%s' => %s!\n", debugstr_w(wps->pszSound), bRet ? "ok" : "ko"); - CloseHandle(s.hEvent); - HeapFree(GetProcessHeap(), 0, waveHdr); - HeapFree(GetProcessHeap(), 0, lpWaveFormat); - if (hWave) while (waveOutClose(hWave) == WAVERR_STILLPLAYING) Sleep(100); - if (hmmio) mmioClose(hmmio, 0); - - PlaySound_Free(wps); - - return bRet; -} - -static BOOL MULTIMEDIA_PlaySound(const void* pszSound, HMODULE hmod, DWORD fdwSound, BOOL bUnicode) -{ - WINE_PLAYSOUND* wps = NULL; - - TRACE("pszSound='%p' hmod=%p fdwSound=%08lX\n", - pszSound, hmod, fdwSound); - - /* FIXME? I see no difference between SND_NOWAIT and SND_NOSTOP ! - * there could be one if several sounds can be played at once... - */ - if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && WINMM_IData.lpPlaySound != NULL) - return FALSE; - - /* alloc internal structure, if we need to play something */ - if (pszSound && !(fdwSound & SND_PURGE)) - { - if (!(wps = PlaySound_Alloc(pszSound, hmod, fdwSound, bUnicode))) - return FALSE; - } - - EnterCriticalSection(&WINMM_IData.cs); - /* since several threads can enter PlaySound in parallel, we're not - * sure, at this point, that another thread didn't start a new playsound - */ - while (WINMM_IData.lpPlaySound != NULL) - { - ResetEvent(WINMM_IData.psLastEvent); - /* FIXME: doc says we have to stop all instances of pszSound if it's non - * NULL... as of today, we stop all playing instances */ - SetEvent(WINMM_IData.psStopEvent); - - LeaveCriticalSection(&WINMM_IData.cs); - WaitForSingleObject(WINMM_IData.psLastEvent, INFINITE); - EnterCriticalSection(&WINMM_IData.cs); - - ResetEvent(WINMM_IData.psStopEvent); - } - - if (wps) wps->lpNext = WINMM_IData.lpPlaySound; - WINMM_IData.lpPlaySound = wps; - LeaveCriticalSection(&WINMM_IData.cs); - - if (!pszSound || (fdwSound & SND_PURGE)) return TRUE; - - if (fdwSound & SND_ASYNC) - { - DWORD id; - HANDLE handle; - wps->bLoop = (fdwSound & SND_LOOP) ? TRUE : FALSE; - if ((handle = CreateThread(NULL, 0, proc_PlaySound, wps, 0, &id)) != 0) { - wps->hThread = handle; - SetThreadPriority(handle, THREAD_PRIORITY_TIME_CRITICAL); - return TRUE; - } - } - else return proc_PlaySound(wps); - - /* error cases */ - PlaySound_Free(wps); - return FALSE; -} - -/************************************************************************** - * PlaySoundA [WINMM.@] - */ -BOOL WINAPI PlaySoundA(LPCSTR pszSoundA, HMODULE hmod, DWORD fdwSound) -{ - return MULTIMEDIA_PlaySound(pszSoundA, hmod, fdwSound, FALSE); -} - -/************************************************************************** - * PlaySoundW [WINMM.@] - */ -BOOL WINAPI PlaySoundW(LPCWSTR pszSoundW, HMODULE hmod, DWORD fdwSound) -{ - return MULTIMEDIA_PlaySound(pszSoundW, hmod, fdwSound, TRUE); -} - -/************************************************************************** - * sndPlaySoundA [WINMM.@] - */ -BOOL WINAPI sndPlaySoundA(LPCSTR pszSoundA, UINT uFlags) -{ - uFlags &= SND_ASYNC|SND_LOOP|SND_MEMORY|SND_NODEFAULT|SND_NOSTOP|SND_SYNC; - return MULTIMEDIA_PlaySound(pszSoundA, 0, uFlags, FALSE); -} - -/************************************************************************** - * sndPlaySoundW [WINMM.@] - */ -BOOL WINAPI sndPlaySoundW(LPCWSTR pszSound, UINT uFlags) -{ - uFlags &= SND_ASYNC|SND_LOOP|SND_MEMORY|SND_NODEFAULT|SND_NOSTOP|SND_SYNC; - return MULTIMEDIA_PlaySound(pszSound, 0, uFlags, TRUE); -} - -/************************************************************************** - * mmsystemGetVersion [WINMM.@] - */ -UINT WINAPI mmsystemGetVersion(void) -{ - TRACE("3.10 (Win95?)\n"); - return 0x030a; -} +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ + +/* + * MMSYTEM functions + * + * Copyright 1993 Martin Ayotte + * 1998-2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> +#include <string.h> + +#include "windef.h" +#include "winbase.h" +#include "mmsystem.h" +#include "wingdi.h" +#include "winuser.h" +#include "winreg.h" +#include "winemm.h" +#include "winternl.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winmm); + +static HMMIO get_mmioFromFile(LPCWSTR lpszName) +{ + HMMIO ret; + WCHAR buf[256]; + LPWSTR dummy; + + ret = mmioOpenW((LPWSTR)lpszName, NULL, + MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE); + if (ret != 0) return ret; + if (SearchPathW(NULL, lpszName, NULL, sizeof(buf)/sizeof(buf[0]), buf, &dummy)) + { + return mmioOpenW(buf, NULL, + MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE); + } + return 0; +} + +static HMMIO get_mmioFromProfile(UINT uFlags, LPCWSTR lpszName) +{ + WCHAR str[128]; + LPWSTR ptr; + HMMIO hmmio; + HKEY hRegSnd, hRegApp, hScheme, hSnd; + DWORD err, type, count; + + static const WCHAR wszSounds[] = {'S','o','u','n','d','s',0}; + static const WCHAR wszDefault[] = {'D','e','f','a','u','l','t',0}; + static const WCHAR wszKey[] = {'A','p','p','E','v','e','n','t','s','\\', + 'S','c','h','e','m','e','s','\\', + 'A','p','p','s',0}; + static const WCHAR wszDotDefault[] = {'.','D','e','f','a','u','l','t',0}; + static const WCHAR wszDotCurrent[] = {'.','C','u','r','r','e','n','t',0}; + static const WCHAR wszNull[] = {0}; + + TRACE("searching in SystemSound list for %s\n", debugstr_w(lpszName)); + GetProfileStringW(wszSounds, lpszName, wszNull, str, sizeof(str)/sizeof(str[0])); + if (lstrlenW(str) == 0) + { + if (uFlags & SND_NODEFAULT) goto next; + GetProfileStringW(wszSounds, wszDefault, wszNull, str, sizeof(str)/sizeof(str[0])); + if (lstrlenW(str) == 0) goto next; + } + for (ptr = str; *ptr && *ptr != ','; ptr++); + if (*ptr) *ptr = 0; + hmmio = mmioOpenW(str, NULL, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE); + if (hmmio != 0) return hmmio; + next: + /* we look up the registry under + * HKCU\AppEvents\Schemes\Apps\.Default + * HKCU\AppEvents\Schemes\Apps\<AppName> + */ + if (RegOpenKeyW(HKEY_CURRENT_USER, wszKey, &hRegSnd) != 0) goto none; + if (uFlags & SND_APPLICATION) + { + DWORD len; + + err = 1; /* error */ + len = GetModuleFileNameW(0, str, sizeof(str)/sizeof(str[0])); + if (len > 0 && len < sizeof(str)/sizeof(str[0])) + { + for (ptr = str + lstrlenW(str) - 1; ptr >= str; ptr--) + { + if (*ptr == '.') *ptr = 0; + if (*ptr == '\\') + { + err = RegOpenKeyW(hRegSnd, ptr+1, &hRegApp); + break; + } + } + } + } + else + { + err = RegOpenKeyW(hRegSnd, wszDotDefault, &hRegApp); + } + RegCloseKey(hRegSnd); + if (err != 0) goto none; + err = RegOpenKeyW(hRegApp, lpszName, &hScheme); + RegCloseKey(hRegApp); + if (err != 0) goto none; + /* what's the difference between .Current and .Default ? */ + err = RegOpenKeyW(hScheme, wszDotDefault, &hSnd); + if (err != 0) + { + err = RegOpenKeyW(hScheme, wszDotCurrent, &hSnd); + RegCloseKey(hScheme); + if (err != 0) + goto none; + } + count = sizeof(str)/sizeof(str[0]); + err = RegQueryValueExW(hSnd, NULL, 0, &type, (LPBYTE)str, &count); + RegCloseKey(hSnd); + if (err != 0 || !*str) goto none; + hmmio = mmioOpenW(str, NULL, MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE); + if (hmmio) return hmmio; + none: + WARN("can't find SystemSound='%s' !\n", debugstr_w(lpszName)); + return 0; +} + +struct playsound_data +{ + HANDLE hEvent; + DWORD dwEventCount; +}; + +static void CALLBACK PlaySound_Callback(HWAVEOUT hwo, UINT uMsg, + DWORD dwInstance, + DWORD dwParam1, DWORD dwParam2) +{ + struct playsound_data* s = (struct playsound_data*)dwInstance; + + switch (uMsg) { + case WOM_OPEN: + case WOM_CLOSE: + break; + case WOM_DONE: + InterlockedIncrement(&s->dwEventCount); + TRACE("Returning waveHdr=%lx\n", dwParam1); + SetEvent(s->hEvent); + break; + default: + ERR("Unknown uMsg=%d\n", uMsg); + } +} + +static void PlaySound_WaitDone(struct playsound_data* s) +{ + for (;;) { + ResetEvent(s->hEvent); + if (InterlockedDecrement(&s->dwEventCount) >= 0) break; + InterlockedIncrement(&s->dwEventCount); + + WaitForSingleObject(s->hEvent, INFINITE); + } +} + +static BOOL PlaySound_IsString(DWORD fdwSound, const void* psz) +{ + /* SND_RESOURCE is 0x40004 while + * SND_MEMORY is 0x00004 + */ + switch (fdwSound & (SND_RESOURCE|SND_ALIAS|SND_FILENAME)) + { + case SND_RESOURCE: return HIWORD(psz) != 0; /* by name or by ID ? */ + case SND_MEMORY: return FALSE; + case SND_ALIAS: /* what about ALIAS_ID ??? */ + case SND_FILENAME: + case 0: return TRUE; + default: FIXME("WTF\n"); return FALSE; + } +} + +static void PlaySound_Free(WINE_PLAYSOUND* wps) +{ + WINE_PLAYSOUND** p; + + EnterCriticalSection(&WINMM_IData.cs); + for (p = &WINMM_IData.lpPlaySound; *p && *p != wps; p = &((*p)->lpNext)); + if (*p) *p = (*p)->lpNext; + if (WINMM_IData.lpPlaySound == NULL) SetEvent(WINMM_IData.psLastEvent); + LeaveCriticalSection(&WINMM_IData.cs); + if (wps->bAlloc) HeapFree(GetProcessHeap(), 0, (void*)wps->pszSound); + if (wps->hThread) CloseHandle(wps->hThread); + HeapFree(GetProcessHeap(), 0, wps); +} + +static WINE_PLAYSOUND* PlaySound_Alloc(const void* pszSound, HMODULE hmod, + DWORD fdwSound, BOOL bUnicode) +{ + WINE_PLAYSOUND* wps; + + wps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wps)); + if (!wps) return NULL; + + wps->hMod = hmod; + wps->fdwSound = fdwSound; + if (PlaySound_IsString(fdwSound, pszSound)) + { + if (bUnicode) + { + if (fdwSound & SND_ASYNC) + { + wps->pszSound = HeapAlloc(GetProcessHeap(), 0, + (lstrlenW(pszSound)+1) * sizeof(WCHAR)); + if (!wps->pszSound) goto oom_error; + lstrcpyW((LPWSTR)wps->pszSound, pszSound); + wps->bAlloc = TRUE; + } + else + wps->pszSound = pszSound; + } + else + { + UNICODE_STRING usBuffer; + RtlCreateUnicodeStringFromAsciiz(&usBuffer, pszSound); + wps->pszSound = usBuffer.Buffer; + if (!wps->pszSound) goto oom_error; + wps->bAlloc = TRUE; + } + } + else + wps->pszSound = pszSound; + + return wps; + oom_error: + PlaySound_Free(wps); + return NULL; +} + +static DWORD WINAPI proc_PlaySound(LPVOID arg) +{ + WINE_PLAYSOUND* wps = (WINE_PLAYSOUND*)arg; + BOOL bRet = FALSE; + HMMIO hmmio = 0; + MMCKINFO ckMainRIFF; + MMCKINFO mmckInfo; + LPWAVEFORMATEX lpWaveFormat = NULL; + HWAVEOUT hWave = 0; + LPWAVEHDR waveHdr = NULL; + INT count, bufsize, left, index; + struct playsound_data s; + void* data; + + s.hEvent = 0; + + TRACE("SoundName='%s' !\n", debugstr_w(wps->pszSound)); + + /* if resource, grab it */ + if ((wps->fdwSound & SND_RESOURCE) == SND_RESOURCE) { + static const WCHAR wszWave[] = {'W','A','V','E',0}; + HRSRC hRes; + HGLOBAL hGlob; + + if ((hRes = FindResourceW(wps->hMod, wps->pszSound, wszWave)) == 0 || + (hGlob = LoadResource(wps->hMod, hRes)) == 0) + goto errCleanUp; + if ((data = LockResource(hGlob)) == NULL) { + FreeResource(hGlob); + goto errCleanUp; + } + FreeResource(hGlob); + } else + data = (void*)wps->pszSound; + + /* construct an MMIO stream (either in memory, or from a file */ + if (wps->fdwSound & SND_MEMORY) + { /* NOTE: SND_RESOURCE has the SND_MEMORY bit set */ + MMIOINFO mminfo; + + memset(&mminfo, 0, sizeof(mminfo)); + mminfo.fccIOProc = FOURCC_MEM; + mminfo.pchBuffer = (LPSTR)data; + mminfo.cchBuffer = -1; /* FIXME: when a resource, could grab real size */ + TRACE("Memory sound %p\n", data); + hmmio = mmioOpenW(NULL, &mminfo, MMIO_READ); + } + else if (wps->fdwSound & SND_ALIAS) + { + hmmio = get_mmioFromProfile(wps->fdwSound, wps->pszSound); + } + else if (wps->fdwSound & SND_FILENAME) + { + hmmio = get_mmioFromFile(wps->pszSound); + } + else + { + if ((hmmio = get_mmioFromProfile(wps->fdwSound | SND_NODEFAULT, wps->pszSound)) == 0) + { + if ((hmmio = get_mmioFromFile(wps->pszSound)) == 0) + { + hmmio = get_mmioFromProfile(wps->fdwSound, wps->pszSound); + } + } + } + if (hmmio == 0) goto errCleanUp; + + if (mmioDescend(hmmio, &ckMainRIFF, NULL, 0)) + goto errCleanUp; + + TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n", + (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, ckMainRIFF.cksize); + + if ((ckMainRIFF.ckid != FOURCC_RIFF) || + (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E'))) + goto errCleanUp; + + mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' '); + if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK)) + goto errCleanUp; + + TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n", + (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize); + + lpWaveFormat = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize); + if (mmioRead(hmmio, (HPSTR)lpWaveFormat, mmckInfo.cksize) < sizeof(WAVEFORMAT)) + goto errCleanUp; + + TRACE("wFormatTag=%04X !\n", lpWaveFormat->wFormatTag); + TRACE("nChannels=%d \n", lpWaveFormat->nChannels); + TRACE("nSamplesPerSec=%ld\n", lpWaveFormat->nSamplesPerSec); + TRACE("nAvgBytesPerSec=%ld\n", lpWaveFormat->nAvgBytesPerSec); + TRACE("nBlockAlign=%d \n", lpWaveFormat->nBlockAlign); + TRACE("wBitsPerSample=%u !\n", lpWaveFormat->wBitsPerSample); + + /* move to end of 'fmt ' chunk */ + mmioAscend(hmmio, &mmckInfo, 0); + + mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a'); + if (mmioDescend(hmmio, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK)) + goto errCleanUp; + + TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX\n", + (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize); + + s.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + + if (waveOutOpen(&hWave, WAVE_MAPPER, lpWaveFormat, (DWORD)PlaySound_Callback, + (DWORD)&s, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) + goto errCleanUp; + + /* make it so that 3 buffers per second are needed */ + bufsize = (((lpWaveFormat->nAvgBytesPerSec / 3) - 1) / lpWaveFormat->nBlockAlign + 1) * + lpWaveFormat->nBlockAlign; + waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize); + waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR); + waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize; + waveHdr[0].dwUser = waveHdr[1].dwUser = 0L; + waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L; + waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L; + waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize; + if (waveOutPrepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR)) || + waveOutPrepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR))) { + goto errCleanUp; + } + + s.dwEventCount = 1L; /* for first buffer */ + index = 0; + + do { + left = mmckInfo.cksize; + + mmioSeek(hmmio, mmckInfo.dwDataOffset, SEEK_SET); + while (left) + { + if (WaitForSingleObject(WINMM_IData.psStopEvent, 0) == WAIT_OBJECT_0) + { + wps->bLoop = FALSE; + break; + } + count = mmioRead(hmmio, waveHdr[index].lpData, min(bufsize, left)); + if (count < 1) break; + left -= count; + waveHdr[index].dwBufferLength = count; + waveHdr[index].dwFlags &= ~WHDR_DONE; + if (waveOutWrite(hWave, &waveHdr[index], sizeof(WAVEHDR)) == MMSYSERR_NOERROR) { + index ^= 1; + PlaySound_WaitDone(&s); + } + else FIXME("Couldn't play header\n"); + } + bRet = TRUE; + } while (wps->bLoop); + + PlaySound_WaitDone(&s); /* for last buffer */ + waveOutReset(hWave); + + waveOutUnprepareHeader(hWave, &waveHdr[0], sizeof(WAVEHDR)); + waveOutUnprepareHeader(hWave, &waveHdr[1], sizeof(WAVEHDR)); + +errCleanUp: + TRACE("Done playing='%s' => %s!\n", debugstr_w(wps->pszSound), bRet ? "ok" : "ko"); + CloseHandle(s.hEvent); + HeapFree(GetProcessHeap(), 0, waveHdr); + HeapFree(GetProcessHeap(), 0, lpWaveFormat); + if (hWave) while (waveOutClose(hWave) == WAVERR_STILLPLAYING) Sleep(100); + if (hmmio) mmioClose(hmmio, 0); + + PlaySound_Free(wps); + + return bRet; +} + +static BOOL MULTIMEDIA_PlaySound(const void* pszSound, HMODULE hmod, DWORD fdwSound, BOOL bUnicode) +{ + WINE_PLAYSOUND* wps = NULL; + + TRACE("pszSound='%p' hmod=%p fdwSound=%08lX\n", + pszSound, hmod, fdwSound); + + /* FIXME? I see no difference between SND_NOWAIT and SND_NOSTOP ! + * there could be one if several sounds can be played at once... + */ + if ((fdwSound & (SND_NOWAIT | SND_NOSTOP)) && WINMM_IData.lpPlaySound != NULL) + return FALSE; + + /* alloc internal structure, if we need to play something */ + if (pszSound && !(fdwSound & SND_PURGE)) + { + if (!(wps = PlaySound_Alloc(pszSound, hmod, fdwSound, bUnicode))) + return FALSE; + } + + EnterCriticalSection(&WINMM_IData.cs); + /* since several threads can enter PlaySound in parallel, we're not + * sure, at this point, that another thread didn't start a new playsound + */ + while (WINMM_IData.lpPlaySound != NULL) + { + ResetEvent(WINMM_IData.psLastEvent); + /* FIXME: doc says we have to stop all instances of pszSound if it's non + * NULL... as of today, we stop all playing instances */ + SetEvent(WINMM_IData.psStopEvent); + + LeaveCriticalSection(&WINMM_IData.cs); + WaitForSingleObject(WINMM_IData.psLastEvent, INFINITE); + EnterCriticalSection(&WINMM_IData.cs); + + ResetEvent(WINMM_IData.psStopEvent); + } + + if (wps) wps->lpNext = WINMM_IData.lpPlaySound; + WINMM_IData.lpPlaySound = wps; + LeaveCriticalSection(&WINMM_IData.cs); + + if (!pszSound || (fdwSound & SND_PURGE)) return TRUE; + + if (fdwSound & SND_ASYNC) + { + DWORD id; + HANDLE handle; + wps->bLoop = (fdwSound & SND_LOOP) ? TRUE : FALSE; + if ((handle = CreateThread(NULL, 0, proc_PlaySound, wps, 0, &id)) != 0) { + wps->hThread = handle; + SetThreadPriority(handle, THREAD_PRIORITY_TIME_CRITICAL); + return TRUE; + } + } + else return proc_PlaySound(wps); + + /* error cases */ + PlaySound_Free(wps); + return FALSE; +} + +/************************************************************************** + * PlaySoundA [WINMM.@] + */ +BOOL WINAPI PlaySoundA(LPCSTR pszSoundA, HMODULE hmod, DWORD fdwSound) +{ + return MULTIMEDIA_PlaySound(pszSoundA, hmod, fdwSound, FALSE); +} + +/************************************************************************** + * PlaySoundW [WINMM.@] + */ +BOOL WINAPI PlaySoundW(LPCWSTR pszSoundW, HMODULE hmod, DWORD fdwSound) +{ + return MULTIMEDIA_PlaySound(pszSoundW, hmod, fdwSound, TRUE); +} + +/************************************************************************** + * sndPlaySoundA [WINMM.@] + */ +BOOL WINAPI sndPlaySoundA(LPCSTR pszSoundA, UINT uFlags) +{ + uFlags &= SND_ASYNC|SND_LOOP|SND_MEMORY|SND_NODEFAULT|SND_NOSTOP|SND_SYNC; + return MULTIMEDIA_PlaySound(pszSoundA, 0, uFlags, FALSE); +} + +/************************************************************************** + * sndPlaySoundW [WINMM.@] + */ +BOOL WINAPI sndPlaySoundW(LPCWSTR pszSound, UINT uFlags) +{ + uFlags &= SND_ASYNC|SND_LOOP|SND_MEMORY|SND_NODEFAULT|SND_NOSTOP|SND_SYNC; + return MULTIMEDIA_PlaySound(pszSound, 0, uFlags, TRUE); +} + +/************************************************************************** + * mmsystemGetVersion [WINMM.@] + */ +UINT WINAPI mmsystemGetVersion(void) +{ + TRACE("3.10 (Win95?)\n"); + return 0x030a; +} diff --git a/reactos/lib/winmm/sound16.c b/reactos/lib/winmm/sound16.c index 1a670c92763..46306d8b1f0 100644 --- a/reactos/lib/winmm/sound16.c +++ b/reactos/lib/winmm/sound16.c @@ -1,184 +1,184 @@ -/* - * 16-bit sound support - * - * Copyright Robert J. Amstadt, 1993 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdarg.h> -#include <stdlib.h> -#include "windef.h" -#include "winbase.h" -#include "wine/windef16.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(sound); - -/*********************************************************************** - * OpenSound (SOUND.1) - */ -INT16 WINAPI OpenSound16(void) -{ - FIXME("(void): stub\n"); - return -1; -} - -/*********************************************************************** - * CloseSound (SOUND.2) - */ -void WINAPI CloseSound16(void) -{ - FIXME("(void): stub\n"); -} - -/*********************************************************************** - * SetVoiceQueueSize (SOUND.3) - */ -INT16 WINAPI SetVoiceQueueSize16(INT16 nVoice, INT16 nBytes) -{ - FIXME("(%d,%d): stub\n",nVoice,nBytes); - return 0; -} - -/*********************************************************************** - * SetVoiceNote (SOUND.4) - */ -INT16 WINAPI SetVoiceNote16(INT16 nVoice, INT16 nValue, INT16 nLength, - INT16 nCdots) -{ - FIXME("(%d,%d,%d,%d): stub\n",nVoice,nValue,nLength,nCdots); - return 0; -} - -/*********************************************************************** - * SetVoiceAccent (SOUND.5) - */ -INT16 WINAPI SetVoiceAccent16(INT16 nVoice, INT16 nTempo, INT16 nVolume, - INT16 nMode, INT16 nPitch) -{ - FIXME("(%d,%d,%d,%d,%d): stub\n", nVoice, nTempo, - nVolume, nMode, nPitch); - return 0; -} - -/*********************************************************************** - * SetVoiceEnvelope (SOUND.6) - */ -INT16 WINAPI SetVoiceEnvelope16(INT16 nVoice, INT16 nShape, INT16 nRepeat) -{ - FIXME("(%d,%d,%d): stub\n",nVoice,nShape,nRepeat); - return 0; -} - -/*********************************************************************** - * SetSoundNoise (SOUND.7) - */ -INT16 WINAPI SetSoundNoise16(INT16 nSource, INT16 nDuration) -{ - FIXME("(%d,%d): stub\n",nSource,nDuration); - return 0; -} - -/*********************************************************************** - * SetVoiceSound (SOUND.8) - */ -INT16 WINAPI SetVoiceSound16(INT16 nVoice, DWORD lFrequency, INT16 nDuration) -{ - FIXME("(%d, %ld, %d): stub\n",nVoice,lFrequency, nDuration); - return 0; -} - -/*********************************************************************** - * StartSound (SOUND.9) - */ -INT16 WINAPI StartSound16(void) -{ - return 0; -} - -/*********************************************************************** - * StopSound (SOUND.10) - */ -INT16 WINAPI StopSound16(void) -{ - return 0; -} - -/*********************************************************************** - * WaitSoundState (SOUND.11) - */ -INT16 WINAPI WaitSoundState16(INT16 x) -{ - FIXME("(%d): stub\n", x); - return 0; -} - -/*********************************************************************** - * SyncAllVoices (SOUND.12) - */ -INT16 WINAPI SyncAllVoices16(void) -{ - FIXME("(void): stub\n"); - return 0; -} - -/*********************************************************************** - * CountVoiceNotes (SOUND.13) - */ -INT16 WINAPI CountVoiceNotes16(INT16 x) -{ - FIXME("(%d): stub\n", x); - return 0; -} - -/*********************************************************************** - * GetThresholdEvent (SOUND.14) - */ -LPINT16 WINAPI GetThresholdEvent16(void) -{ - FIXME("(void): stub\n"); - return NULL; -} - -/*********************************************************************** - * GetThresholdStatus (SOUND.15) - */ -INT16 WINAPI GetThresholdStatus16(void) -{ - FIXME("(void): stub\n"); - return 0; -} - -/*********************************************************************** - * SetVoiceThreshold (SOUND.16) - */ -INT16 WINAPI SetVoiceThreshold16(INT16 a, INT16 b) -{ - FIXME("(%d,%d): stub\n", a, b); - return 0; -} - -/*********************************************************************** - * DoBeep (SOUND.17) - */ -void WINAPI DoBeep16(void) -{ - FIXME("(void): stub!\n"); -} - - - - +/* + * 16-bit sound support + * + * Copyright Robert J. Amstadt, 1993 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdarg.h> +#include <stdlib.h> +#include "windef.h" +#include "winbase.h" +#include "wine/windef16.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(sound); + +/*********************************************************************** + * OpenSound (SOUND.1) + */ +INT16 WINAPI OpenSound16(void) +{ + FIXME("(void): stub\n"); + return -1; +} + +/*********************************************************************** + * CloseSound (SOUND.2) + */ +void WINAPI CloseSound16(void) +{ + FIXME("(void): stub\n"); +} + +/*********************************************************************** + * SetVoiceQueueSize (SOUND.3) + */ +INT16 WINAPI SetVoiceQueueSize16(INT16 nVoice, INT16 nBytes) +{ + FIXME("(%d,%d): stub\n",nVoice,nBytes); + return 0; +} + +/*********************************************************************** + * SetVoiceNote (SOUND.4) + */ +INT16 WINAPI SetVoiceNote16(INT16 nVoice, INT16 nValue, INT16 nLength, + INT16 nCdots) +{ + FIXME("(%d,%d,%d,%d): stub\n",nVoice,nValue,nLength,nCdots); + return 0; +} + +/*********************************************************************** + * SetVoiceAccent (SOUND.5) + */ +INT16 WINAPI SetVoiceAccent16(INT16 nVoice, INT16 nTempo, INT16 nVolume, + INT16 nMode, INT16 nPitch) +{ + FIXME("(%d,%d,%d,%d,%d): stub\n", nVoice, nTempo, + nVolume, nMode, nPitch); + return 0; +} + +/*********************************************************************** + * SetVoiceEnvelope (SOUND.6) + */ +INT16 WINAPI SetVoiceEnvelope16(INT16 nVoice, INT16 nShape, INT16 nRepeat) +{ + FIXME("(%d,%d,%d): stub\n",nVoice,nShape,nRepeat); + return 0; +} + +/*********************************************************************** + * SetSoundNoise (SOUND.7) + */ +INT16 WINAPI SetSoundNoise16(INT16 nSource, INT16 nDuration) +{ + FIXME("(%d,%d): stub\n",nSource,nDuration); + return 0; +} + +/*********************************************************************** + * SetVoiceSound (SOUND.8) + */ +INT16 WINAPI SetVoiceSound16(INT16 nVoice, DWORD lFrequency, INT16 nDuration) +{ + FIXME("(%d, %ld, %d): stub\n",nVoice,lFrequency, nDuration); + return 0; +} + +/*********************************************************************** + * StartSound (SOUND.9) + */ +INT16 WINAPI StartSound16(void) +{ + return 0; +} + +/*********************************************************************** + * StopSound (SOUND.10) + */ +INT16 WINAPI StopSound16(void) +{ + return 0; +} + +/*********************************************************************** + * WaitSoundState (SOUND.11) + */ +INT16 WINAPI WaitSoundState16(INT16 x) +{ + FIXME("(%d): stub\n", x); + return 0; +} + +/*********************************************************************** + * SyncAllVoices (SOUND.12) + */ +INT16 WINAPI SyncAllVoices16(void) +{ + FIXME("(void): stub\n"); + return 0; +} + +/*********************************************************************** + * CountVoiceNotes (SOUND.13) + */ +INT16 WINAPI CountVoiceNotes16(INT16 x) +{ + FIXME("(%d): stub\n", x); + return 0; +} + +/*********************************************************************** + * GetThresholdEvent (SOUND.14) + */ +LPINT16 WINAPI GetThresholdEvent16(void) +{ + FIXME("(void): stub\n"); + return NULL; +} + +/*********************************************************************** + * GetThresholdStatus (SOUND.15) + */ +INT16 WINAPI GetThresholdStatus16(void) +{ + FIXME("(void): stub\n"); + return 0; +} + +/*********************************************************************** + * SetVoiceThreshold (SOUND.16) + */ +INT16 WINAPI SetVoiceThreshold16(INT16 a, INT16 b) +{ + FIXME("(%d,%d): stub\n", a, b); + return 0; +} + +/*********************************************************************** + * DoBeep (SOUND.17) + */ +void WINAPI DoBeep16(void) +{ + FIXME("(void): stub!\n"); +} + + + + diff --git a/reactos/lib/winmm/time.c b/reactos/lib/winmm/time.c index 4b5162e9a2c..a4609146c72 100644 --- a/reactos/lib/winmm/time.c +++ b/reactos/lib/winmm/time.c @@ -1,475 +1,475 @@ -/* -*- tab-width: 8; c-basic-offset: 4 -*- */ - -/* - * MMSYSTEM time functions - * - * Copyright 1993 Martin Ayotte - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" -#include "wine/port.h" - -#include <stdarg.h> -#include <time.h> -#ifdef HAVE_SYS_TIME_H -# include <sys/time.h> -#endif -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#endif - -#include "windef.h" -#include "winbase.h" -#include "mmsystem.h" - -#include "winemm.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mmtime); - -static HANDLE TIME_hMMTimer; -static LPWINE_TIMERENTRY TIME_TimersList; -static HANDLE TIME_hKillEvent; -static HANDLE TIME_hWakeEvent; -static BOOL TIME_TimeToDie = TRUE; - -/* - * Some observations on the behavior of winmm on Windows. - * First, the call to timeBeginPeriod(xx) can never be used - * to raise the timer resolution, only lower it. - * - * Second, a brief survey of a variety of Win 2k and Win X - * machines showed that a 'standard' (aka default) timer - * resolution was 1 ms (Win9x is documented as being 1). However, one - * machine had a standard timer resolution of 10 ms. - * - * Further, if we set our default resolution to 1, - * the implementation of timeGetTime becomes GetTickCount(), - * and we can optimize the code to reduce overhead. - * - * Additionally, a survey of Event behaviors shows that - * if we request a Periodic event every 50 ms, then Windows - * makes sure to trigger that event 20 times in the next - * second. If delays prevent that from happening on exact - * schedule, Windows will trigger the events as close - * to the original schedule as is possible, and will eventually - * bring the event triggers back onto a schedule that is - * consistent with what would have happened if there were - * no delays. - * - * Jeremy White, October 2004 - */ -#define MMSYSTIME_MININTERVAL (1) -#define MMSYSTIME_MAXINTERVAL (65535) - - -static void TIME_TriggerCallBack(LPWINE_TIMERENTRY lpTimer) -{ - TRACE("%04lx:CallBack => lpFunc=%p wTimerID=%04X dwUser=%08lX dwTriggerTime %ld(delta %ld)\n", - GetCurrentThreadId(), lpTimer->lpFunc, lpTimer->wTimerID, lpTimer->dwUser, - lpTimer->dwTriggerTime, GetTickCount() - lpTimer->dwTriggerTime); - - /* - TimeProc callback that is called here is something strange, under Windows 3.1x it is called - * during interrupt time, is allowed to execute very limited number of API calls (like - * PostMessage), and must reside in DLL (therefore uses stack of active application). So I - * guess current implementation via SetTimer has to be improved upon. - */ - switch (lpTimer->wFlags & 0x30) { - case TIME_CALLBACK_FUNCTION: - if (lpTimer->wFlags & WINE_TIMER_IS32) - (lpTimer->lpFunc)(lpTimer->wTimerID, 0, lpTimer->dwUser, 0, 0); - else if (pFnCallMMDrvFunc16) - pFnCallMMDrvFunc16((DWORD)lpTimer->lpFunc, lpTimer->wTimerID, 0, - lpTimer->dwUser, 0, 0); - break; - case TIME_CALLBACK_EVENT_SET: - SetEvent((HANDLE)lpTimer->lpFunc); - break; - case TIME_CALLBACK_EVENT_PULSE: - PulseEvent((HANDLE)lpTimer->lpFunc); - break; - default: - FIXME("Unknown callback type 0x%04x for mmtime callback (%p), ignored.\n", - lpTimer->wFlags, lpTimer->lpFunc); - break; - } -} - -/************************************************************************** - * TIME_MMSysTimeCallback - */ -static DWORD CALLBACK TIME_MMSysTimeCallback(LPWINE_MM_IDATA iData) -{ -static int nSizeLpTimers; -static LPWINE_TIMERENTRY lpTimers; - - LPWINE_TIMERENTRY timer, *ptimer, *next_ptimer; - int idx; - DWORD cur_time; - DWORD delta_time; - DWORD ret_time = INFINITE; - DWORD adjust_time; - - - /* optimize for the most frequent case - no events */ - if (! TIME_TimersList) - return(ret_time); - - /* since timeSetEvent() and timeKillEvent() can be called - * from 16 bit code, there are cases where win16 lock is - * locked upon entering timeSetEvent(), and then the mm timer - * critical section is locked. This function cannot call the - * timer callback with the crit sect locked (because callback - * may need to acquire Win16 lock, thus providing a deadlock - * situation). - * To cope with that, we just copy the WINE_TIMERENTRY struct - * that need to trigger the callback, and call it without the - * mm timer crit sect locked. - * the hKillTimeEvent is used to mark the section where we - * handle the callbacks so we can do synchronous kills. - * EPP 99/07/13, updated 04/01/10 - */ - idx = 0; - cur_time = GetTickCount(); - - EnterCriticalSection(&iData->cs); - for (ptimer = &TIME_TimersList; *ptimer != NULL; ) { - timer = *ptimer; - next_ptimer = &timer->lpNext; - if (cur_time >= timer->dwTriggerTime) - { - if (timer->lpFunc) { - if (idx == nSizeLpTimers) { - if (lpTimers) - lpTimers = (LPWINE_TIMERENTRY) - HeapReAlloc(GetProcessHeap(), 0, lpTimers, - ++nSizeLpTimers * sizeof(WINE_TIMERENTRY)); - else - lpTimers = (LPWINE_TIMERENTRY) - HeapAlloc(GetProcessHeap(), 0, - ++nSizeLpTimers * sizeof(WINE_TIMERENTRY)); - } - lpTimers[idx++] = *timer; - - } - - /* Update the time after we make the copy to preserve - the original trigger time */ - timer->dwTriggerTime += timer->wDelay; - - /* TIME_ONESHOT is defined as 0 */ - if (!(timer->wFlags & TIME_PERIODIC)) - { - /* unlink timer from timers list */ - *ptimer = *next_ptimer; - HeapFree(GetProcessHeap(), 0, timer); - - /* We don't need to trigger oneshots again */ - delta_time = INFINITE; - } - else - { - /* Compute when this event needs this function - to be called again */ - if (timer->dwTriggerTime <= cur_time) - delta_time = 0; - else - delta_time = timer->dwTriggerTime - cur_time; - } - } - else - delta_time = timer->dwTriggerTime - cur_time; - - /* Determine when we need to return to this function */ - ret_time = min(ret_time, delta_time); - - ptimer = next_ptimer; - } - if (TIME_hKillEvent) ResetEvent(TIME_hKillEvent); - LeaveCriticalSection(&iData->cs); - - while (idx > 0) TIME_TriggerCallBack(&lpTimers[--idx]); - if (TIME_hKillEvent) SetEvent(TIME_hKillEvent); - - /* Finally, adjust the recommended wait time downward - by the amount of time the processing routines - actually took */ - adjust_time = GetTickCount() - cur_time; - if (adjust_time > ret_time) - ret_time = 0; - else - ret_time -= adjust_time; - - /* We return the amount of time our caller should sleep - before needing to check in on us again */ - return(ret_time); -} - -/************************************************************************** - * TIME_MMSysTimeThread - */ -static DWORD CALLBACK TIME_MMSysTimeThread(LPVOID arg) -{ - LPWINE_MM_IDATA iData = (LPWINE_MM_IDATA)arg; - DWORD sleep_time; - DWORD rc; - - TRACE("Starting main winmm thread\n"); - - /* FIXME: As an optimization, we could have - this thread die when there are no more requests - pending, and then get recreated on the first - new event; it's not clear if that would be worth - it or not. */ - - while (! TIME_TimeToDie) - { - sleep_time = TIME_MMSysTimeCallback(iData); - - if (sleep_time == 0) - continue; - - rc = WaitForSingleObject(TIME_hWakeEvent, sleep_time); - if (rc != WAIT_TIMEOUT && rc != WAIT_OBJECT_0) - { - FIXME("Unexpected error %ld(%ld) in timer thread\n", rc, GetLastError()); - break; - } - } - TRACE("Exiting main winmm thread\n"); - return 0; -} - -/************************************************************************** - * TIME_MMTimeStart - */ -void TIME_MMTimeStart(void) -{ - if (!TIME_hMMTimer) { - TIME_TimersList = NULL; - TIME_hWakeEvent = CreateEventW(NULL, FALSE, FALSE, NULL); - TIME_TimeToDie = FALSE; - TIME_hMMTimer = CreateThread(NULL, 0, TIME_MMSysTimeThread, &WINMM_IData, 0, NULL); - SetThreadPriority(TIME_hMMTimer, THREAD_PRIORITY_TIME_CRITICAL); - } -} - -/************************************************************************** - * TIME_MMTimeStop - */ -void TIME_MMTimeStop(void) -{ - if (TIME_hMMTimer) { - - TIME_TimeToDie = TRUE; - SetEvent(TIME_hWakeEvent); - - /* FIXME: in the worst case, we're going to wait 65 seconds here :-( */ - WaitForSingleObject(TIME_hMMTimer, INFINITE); - - CloseHandle(TIME_hMMTimer); - CloseHandle(TIME_hWakeEvent); - TIME_hMMTimer = 0; - TIME_TimersList = NULL; - } -} - -/************************************************************************** - * timeGetSystemTime [WINMM.@] - */ -MMRESULT WINAPI timeGetSystemTime(LPMMTIME lpTime, UINT wSize) -{ - - if (wSize >= sizeof(*lpTime)) { - lpTime->wType = TIME_MS; - lpTime->u.ms = GetTickCount(); - - } - - return 0; -} - -/************************************************************************** - * TIME_SetEventInternal [internal] - */ -WORD TIME_SetEventInternal(UINT wDelay, UINT wResol, - LPTIMECALLBACK lpFunc, DWORD dwUser, UINT wFlags) -{ - WORD wNewID = 0; - LPWINE_TIMERENTRY lpNewTimer; - LPWINE_TIMERENTRY lpTimer; - - TRACE("(%u, %u, %p, %08lX, %04X);\n", wDelay, wResol, lpFunc, dwUser, wFlags); - - if (wDelay < MMSYSTIME_MININTERVAL || wDelay > MMSYSTIME_MAXINTERVAL) - return 0; - - lpNewTimer = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_TIMERENTRY)); - if (lpNewTimer == NULL) - return 0; - - TIME_MMTimeStart(); - - lpNewTimer->wDelay = wDelay; - lpNewTimer->dwTriggerTime = GetTickCount() + wDelay; - - /* FIXME - wResol is not respected, although it is not clear - that we could change our precision meaningfully */ - lpNewTimer->wResol = wResol; - lpNewTimer->lpFunc = lpFunc; - lpNewTimer->dwUser = dwUser; - lpNewTimer->wFlags = wFlags; - - EnterCriticalSection(&WINMM_IData.cs); - - if ((wFlags & TIME_KILL_SYNCHRONOUS) && !TIME_hKillEvent) - TIME_hKillEvent = CreateEventW(NULL, TRUE, TRUE, NULL); - - for (lpTimer = TIME_TimersList; lpTimer != NULL; lpTimer = lpTimer->lpNext) { - wNewID = max(wNewID, lpTimer->wTimerID); - } - - lpNewTimer->lpNext = TIME_TimersList; - TIME_TimersList = lpNewTimer; - lpNewTimer->wTimerID = wNewID + 1; - - LeaveCriticalSection(&WINMM_IData.cs); - - /* Wake the service thread in case there is work to be done */ - SetEvent(TIME_hWakeEvent); - - TRACE("=> %u\n", wNewID + 1); - - return wNewID + 1; -} - -/************************************************************************** - * timeSetEvent [WINMM.@] - */ -MMRESULT WINAPI timeSetEvent(UINT wDelay, UINT wResol, LPTIMECALLBACK lpFunc, - DWORD_PTR dwUser, UINT wFlags) -{ - if (wFlags & WINE_TIMER_IS32) - WARN("Unknown windows flag... wine internally used.. ooch\n"); - - return TIME_SetEventInternal(wDelay, wResol, lpFunc, - dwUser, wFlags|WINE_TIMER_IS32); -} - -/************************************************************************** - * timeKillEvent [WINMM.@] - */ -MMRESULT WINAPI timeKillEvent(UINT wID) -{ - LPWINE_TIMERENTRY lpSelf = NULL, *lpTimer; - - TRACE("(%u)\n", wID); - EnterCriticalSection(&WINMM_IData.cs); - /* remove WINE_TIMERENTRY from list */ - for (lpTimer = &TIME_TimersList; *lpTimer; lpTimer = &(*lpTimer)->lpNext) { - if (wID == (*lpTimer)->wTimerID) { - lpSelf = *lpTimer; - /* unlink timer of id 'wID' */ - *lpTimer = (*lpTimer)->lpNext; - break; - } - } - LeaveCriticalSection(&WINMM_IData.cs); - - if (!lpSelf) - { - WARN("wID=%u is not a valid timer ID\n", wID); - return MMSYSERR_INVALPARAM; - } - if (lpSelf->wFlags & TIME_KILL_SYNCHRONOUS) - WaitForSingleObject(TIME_hKillEvent, INFINITE); - HeapFree(GetProcessHeap(), 0, lpSelf); - return TIMERR_NOERROR; -} - -/************************************************************************** - * timeGetDevCaps [WINMM.@] - */ -MMRESULT WINAPI timeGetDevCaps(LPTIMECAPS lpCaps, UINT wSize) -{ - TRACE("(%p, %u)\n", lpCaps, wSize); - - if (lpCaps == 0) { - WARN("invalid lpCaps\n"); - return TIMERR_NOCANDO; - } - - if (wSize < sizeof(TIMECAPS)) { - WARN("invalid wSize\n"); - return TIMERR_NOCANDO; - } - - lpCaps->wPeriodMin = MMSYSTIME_MININTERVAL; - lpCaps->wPeriodMax = MMSYSTIME_MAXINTERVAL; - return TIMERR_NOERROR; -} - -/************************************************************************** - * timeBeginPeriod [WINMM.@] - */ -MMRESULT WINAPI timeBeginPeriod(UINT wPeriod) -{ - if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL) - return TIMERR_NOCANDO; - - if (wPeriod > MMSYSTIME_MININTERVAL) - { - WARN("Stub; we set our timer resolution at minimum\n"); - } - - return 0; -} - -/************************************************************************** - * timeEndPeriod [WINMM.@] - */ -MMRESULT WINAPI timeEndPeriod(UINT wPeriod) -{ - if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL) - return TIMERR_NOCANDO; - - if (wPeriod > MMSYSTIME_MININTERVAL) - { - WARN("Stub; we set our timer resolution at minimum\n"); - } - return 0; -} - -/************************************************************************** - * timeGetTime [MMSYSTEM.607] - * timeGetTime [WINMM.@] - */ -DWORD WINAPI timeGetTime(void) -{ -#if defined(COMMENTOUTPRIORTODELETING) - DWORD count; - - /* FIXME: releasing the win16 lock here is a temporary hack (I hope) - * that lets mciavi.drv run correctly - */ - if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count); - if (pFnRestoreThunkLock) pFnRestoreThunkLock(count); -#endif - - return GetTickCount(); -} +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ + +/* + * MMSYSTEM time functions + * + * Copyright 1993 Martin Ayotte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "wine/port.h" + +#include <stdarg.h> +#include <time.h> +#ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#include "windef.h" +#include "winbase.h" +#include "mmsystem.h" + +#include "winemm.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mmtime); + +static HANDLE TIME_hMMTimer; +static LPWINE_TIMERENTRY TIME_TimersList; +static HANDLE TIME_hKillEvent; +static HANDLE TIME_hWakeEvent; +static BOOL TIME_TimeToDie = TRUE; + +/* + * Some observations on the behavior of winmm on Windows. + * First, the call to timeBeginPeriod(xx) can never be used + * to raise the timer resolution, only lower it. + * + * Second, a brief survey of a variety of Win 2k and Win X + * machines showed that a 'standard' (aka default) timer + * resolution was 1 ms (Win9x is documented as being 1). However, one + * machine had a standard timer resolution of 10 ms. + * + * Further, if we set our default resolution to 1, + * the implementation of timeGetTime becomes GetTickCount(), + * and we can optimize the code to reduce overhead. + * + * Additionally, a survey of Event behaviors shows that + * if we request a Periodic event every 50 ms, then Windows + * makes sure to trigger that event 20 times in the next + * second. If delays prevent that from happening on exact + * schedule, Windows will trigger the events as close + * to the original schedule as is possible, and will eventually + * bring the event triggers back onto a schedule that is + * consistent with what would have happened if there were + * no delays. + * + * Jeremy White, October 2004 + */ +#define MMSYSTIME_MININTERVAL (1) +#define MMSYSTIME_MAXINTERVAL (65535) + + +static void TIME_TriggerCallBack(LPWINE_TIMERENTRY lpTimer) +{ + TRACE("%04lx:CallBack => lpFunc=%p wTimerID=%04X dwUser=%08lX dwTriggerTime %ld(delta %ld)\n", + GetCurrentThreadId(), lpTimer->lpFunc, lpTimer->wTimerID, lpTimer->dwUser, + lpTimer->dwTriggerTime, GetTickCount() - lpTimer->dwTriggerTime); + + /* - TimeProc callback that is called here is something strange, under Windows 3.1x it is called + * during interrupt time, is allowed to execute very limited number of API calls (like + * PostMessage), and must reside in DLL (therefore uses stack of active application). So I + * guess current implementation via SetTimer has to be improved upon. + */ + switch (lpTimer->wFlags & 0x30) { + case TIME_CALLBACK_FUNCTION: + if (lpTimer->wFlags & WINE_TIMER_IS32) + (lpTimer->lpFunc)(lpTimer->wTimerID, 0, lpTimer->dwUser, 0, 0); + else if (pFnCallMMDrvFunc16) + pFnCallMMDrvFunc16((DWORD)lpTimer->lpFunc, lpTimer->wTimerID, 0, + lpTimer->dwUser, 0, 0); + break; + case TIME_CALLBACK_EVENT_SET: + SetEvent((HANDLE)lpTimer->lpFunc); + break; + case TIME_CALLBACK_EVENT_PULSE: + PulseEvent((HANDLE)lpTimer->lpFunc); + break; + default: + FIXME("Unknown callback type 0x%04x for mmtime callback (%p), ignored.\n", + lpTimer->wFlags, lpTimer->lpFunc); + break; + } +} + +/************************************************************************** + * TIME_MMSysTimeCallback + */ +static DWORD CALLBACK TIME_MMSysTimeCallback(LPWINE_MM_IDATA iData) +{ +static int nSizeLpTimers; +static LPWINE_TIMERENTRY lpTimers; + + LPWINE_TIMERENTRY timer, *ptimer, *next_ptimer; + int idx; + DWORD cur_time; + DWORD delta_time; + DWORD ret_time = INFINITE; + DWORD adjust_time; + + + /* optimize for the most frequent case - no events */ + if (! TIME_TimersList) + return(ret_time); + + /* since timeSetEvent() and timeKillEvent() can be called + * from 16 bit code, there are cases where win16 lock is + * locked upon entering timeSetEvent(), and then the mm timer + * critical section is locked. This function cannot call the + * timer callback with the crit sect locked (because callback + * may need to acquire Win16 lock, thus providing a deadlock + * situation). + * To cope with that, we just copy the WINE_TIMERENTRY struct + * that need to trigger the callback, and call it without the + * mm timer crit sect locked. + * the hKillTimeEvent is used to mark the section where we + * handle the callbacks so we can do synchronous kills. + * EPP 99/07/13, updated 04/01/10 + */ + idx = 0; + cur_time = GetTickCount(); + + EnterCriticalSection(&iData->cs); + for (ptimer = &TIME_TimersList; *ptimer != NULL; ) { + timer = *ptimer; + next_ptimer = &timer->lpNext; + if (cur_time >= timer->dwTriggerTime) + { + if (timer->lpFunc) { + if (idx == nSizeLpTimers) { + if (lpTimers) + lpTimers = (LPWINE_TIMERENTRY) + HeapReAlloc(GetProcessHeap(), 0, lpTimers, + ++nSizeLpTimers * sizeof(WINE_TIMERENTRY)); + else + lpTimers = (LPWINE_TIMERENTRY) + HeapAlloc(GetProcessHeap(), 0, + ++nSizeLpTimers * sizeof(WINE_TIMERENTRY)); + } + lpTimers[idx++] = *timer; + + } + + /* Update the time after we make the copy to preserve + the original trigger time */ + timer->dwTriggerTime += timer->wDelay; + + /* TIME_ONESHOT is defined as 0 */ + if (!(timer->wFlags & TIME_PERIODIC)) + { + /* unlink timer from timers list */ + *ptimer = *next_ptimer; + HeapFree(GetProcessHeap(), 0, timer); + + /* We don't need to trigger oneshots again */ + delta_time = INFINITE; + } + else + { + /* Compute when this event needs this function + to be called again */ + if (timer->dwTriggerTime <= cur_time) + delta_time = 0; + else + delta_time = timer->dwTriggerTime - cur_time; + } + } + else + delta_time = timer->dwTriggerTime - cur_time; + + /* Determine when we need to return to this function */ + ret_time = min(ret_time, delta_time); + + ptimer = next_ptimer; + } + if (TIME_hKillEvent) ResetEvent(TIME_hKillEvent); + LeaveCriticalSection(&iData->cs); + + while (idx > 0) TIME_TriggerCallBack(&lpTimers[--idx]); + if (TIME_hKillEvent) SetEvent(TIME_hKillEvent); + + /* Finally, adjust the recommended wait time downward + by the amount of time the processing routines + actually took */ + adjust_time = GetTickCount() - cur_time; + if (adjust_time > ret_time) + ret_time = 0; + else + ret_time -= adjust_time; + + /* We return the amount of time our caller should sleep + before needing to check in on us again */ + return(ret_time); +} + +/************************************************************************** + * TIME_MMSysTimeThread + */ +static DWORD CALLBACK TIME_MMSysTimeThread(LPVOID arg) +{ + LPWINE_MM_IDATA iData = (LPWINE_MM_IDATA)arg; + DWORD sleep_time; + DWORD rc; + + TRACE("Starting main winmm thread\n"); + + /* FIXME: As an optimization, we could have + this thread die when there are no more requests + pending, and then get recreated on the first + new event; it's not clear if that would be worth + it or not. */ + + while (! TIME_TimeToDie) + { + sleep_time = TIME_MMSysTimeCallback(iData); + + if (sleep_time == 0) + continue; + + rc = WaitForSingleObject(TIME_hWakeEvent, sleep_time); + if (rc != WAIT_TIMEOUT && rc != WAIT_OBJECT_0) + { + FIXME("Unexpected error %ld(%ld) in timer thread\n", rc, GetLastError()); + break; + } + } + TRACE("Exiting main winmm thread\n"); + return 0; +} + +/************************************************************************** + * TIME_MMTimeStart + */ +void TIME_MMTimeStart(void) +{ + if (!TIME_hMMTimer) { + TIME_TimersList = NULL; + TIME_hWakeEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + TIME_TimeToDie = FALSE; + TIME_hMMTimer = CreateThread(NULL, 0, TIME_MMSysTimeThread, &WINMM_IData, 0, NULL); + SetThreadPriority(TIME_hMMTimer, THREAD_PRIORITY_TIME_CRITICAL); + } +} + +/************************************************************************** + * TIME_MMTimeStop + */ +void TIME_MMTimeStop(void) +{ + if (TIME_hMMTimer) { + + TIME_TimeToDie = TRUE; + SetEvent(TIME_hWakeEvent); + + /* FIXME: in the worst case, we're going to wait 65 seconds here :-( */ + WaitForSingleObject(TIME_hMMTimer, INFINITE); + + CloseHandle(TIME_hMMTimer); + CloseHandle(TIME_hWakeEvent); + TIME_hMMTimer = 0; + TIME_TimersList = NULL; + } +} + +/************************************************************************** + * timeGetSystemTime [WINMM.@] + */ +MMRESULT WINAPI timeGetSystemTime(LPMMTIME lpTime, UINT wSize) +{ + + if (wSize >= sizeof(*lpTime)) { + lpTime->wType = TIME_MS; + lpTime->u.ms = GetTickCount(); + + } + + return 0; +} + +/************************************************************************** + * TIME_SetEventInternal [internal] + */ +WORD TIME_SetEventInternal(UINT wDelay, UINT wResol, + LPTIMECALLBACK lpFunc, DWORD dwUser, UINT wFlags) +{ + WORD wNewID = 0; + LPWINE_TIMERENTRY lpNewTimer; + LPWINE_TIMERENTRY lpTimer; + + TRACE("(%u, %u, %p, %08lX, %04X);\n", wDelay, wResol, lpFunc, dwUser, wFlags); + + if (wDelay < MMSYSTIME_MININTERVAL || wDelay > MMSYSTIME_MAXINTERVAL) + return 0; + + lpNewTimer = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_TIMERENTRY)); + if (lpNewTimer == NULL) + return 0; + + TIME_MMTimeStart(); + + lpNewTimer->wDelay = wDelay; + lpNewTimer->dwTriggerTime = GetTickCount() + wDelay; + + /* FIXME - wResol is not respected, although it is not clear + that we could change our precision meaningfully */ + lpNewTimer->wResol = wResol; + lpNewTimer->lpFunc = lpFunc; + lpNewTimer->dwUser = dwUser; + lpNewTimer->wFlags = wFlags; + + EnterCriticalSection(&WINMM_IData.cs); + + if ((wFlags & TIME_KILL_SYNCHRONOUS) && !TIME_hKillEvent) + TIME_hKillEvent = CreateEventW(NULL, TRUE, TRUE, NULL); + + for (lpTimer = TIME_TimersList; lpTimer != NULL; lpTimer = lpTimer->lpNext) { + wNewID = max(wNewID, lpTimer->wTimerID); + } + + lpNewTimer->lpNext = TIME_TimersList; + TIME_TimersList = lpNewTimer; + lpNewTimer->wTimerID = wNewID + 1; + + LeaveCriticalSection(&WINMM_IData.cs); + + /* Wake the service thread in case there is work to be done */ + SetEvent(TIME_hWakeEvent); + + TRACE("=> %u\n", wNewID + 1); + + return wNewID + 1; +} + +/************************************************************************** + * timeSetEvent [WINMM.@] + */ +MMRESULT WINAPI timeSetEvent(UINT wDelay, UINT wResol, LPTIMECALLBACK lpFunc, + DWORD_PTR dwUser, UINT wFlags) +{ + if (wFlags & WINE_TIMER_IS32) + WARN("Unknown windows flag... wine internally used.. ooch\n"); + + return TIME_SetEventInternal(wDelay, wResol, lpFunc, + dwUser, wFlags|WINE_TIMER_IS32); +} + +/************************************************************************** + * timeKillEvent [WINMM.@] + */ +MMRESULT WINAPI timeKillEvent(UINT wID) +{ + LPWINE_TIMERENTRY lpSelf = NULL, *lpTimer; + + TRACE("(%u)\n", wID); + EnterCriticalSection(&WINMM_IData.cs); + /* remove WINE_TIMERENTRY from list */ + for (lpTimer = &TIME_TimersList; *lpTimer; lpTimer = &(*lpTimer)->lpNext) { + if (wID == (*lpTimer)->wTimerID) { + lpSelf = *lpTimer; + /* unlink timer of id 'wID' */ + *lpTimer = (*lpTimer)->lpNext; + break; + } + } + LeaveCriticalSection(&WINMM_IData.cs); + + if (!lpSelf) + { + WARN("wID=%u is not a valid timer ID\n", wID); + return MMSYSERR_INVALPARAM; + } + if (lpSelf->wFlags & TIME_KILL_SYNCHRONOUS) + WaitForSingleObject(TIME_hKillEvent, INFINITE); + HeapFree(GetProcessHeap(), 0, lpSelf); + return TIMERR_NOERROR; +} + +/************************************************************************** + * timeGetDevCaps [WINMM.@] + */ +MMRESULT WINAPI timeGetDevCaps(LPTIMECAPS lpCaps, UINT wSize) +{ + TRACE("(%p, %u)\n", lpCaps, wSize); + + if (lpCaps == 0) { + WARN("invalid lpCaps\n"); + return TIMERR_NOCANDO; + } + + if (wSize < sizeof(TIMECAPS)) { + WARN("invalid wSize\n"); + return TIMERR_NOCANDO; + } + + lpCaps->wPeriodMin = MMSYSTIME_MININTERVAL; + lpCaps->wPeriodMax = MMSYSTIME_MAXINTERVAL; + return TIMERR_NOERROR; +} + +/************************************************************************** + * timeBeginPeriod [WINMM.@] + */ +MMRESULT WINAPI timeBeginPeriod(UINT wPeriod) +{ + if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL) + return TIMERR_NOCANDO; + + if (wPeriod > MMSYSTIME_MININTERVAL) + { + WARN("Stub; we set our timer resolution at minimum\n"); + } + + return 0; +} + +/************************************************************************** + * timeEndPeriod [WINMM.@] + */ +MMRESULT WINAPI timeEndPeriod(UINT wPeriod) +{ + if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL) + return TIMERR_NOCANDO; + + if (wPeriod > MMSYSTIME_MININTERVAL) + { + WARN("Stub; we set our timer resolution at minimum\n"); + } + return 0; +} + +/************************************************************************** + * timeGetTime [MMSYSTEM.607] + * timeGetTime [WINMM.@] + */ +DWORD WINAPI timeGetTime(void) +{ +#if defined(COMMENTOUTPRIORTODELETING) + DWORD count; + + /* FIXME: releasing the win16 lock here is a temporary hack (I hope) + * that lets mciavi.drv run correctly + */ + if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count); + if (pFnRestoreThunkLock) pFnRestoreThunkLock(count); +#endif + + return GetTickCount(); +} diff --git a/reactos/lib/winmm/wavemap/wavemap.c b/reactos/lib/winmm/wavemap/wavemap.c index 5a3a72dd3f2..9fb8a7ed925 100644 --- a/reactos/lib/winmm/wavemap/wavemap.c +++ b/reactos/lib/winmm/wavemap/wavemap.c @@ -1,1226 +1,1226 @@ -/* -*- tab-width: 8; c-basic-offset: 4 -*- */ -/* - * Wine Wave mapper driver - * - * Copyright 1999,2001 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* TODOs - * + better protection against evilish dwUser parameters - * + use asynchronous ACM conversion - * + don't use callback functions when none is required in open - * + the buffer sizes may not be accurate, so there may be some - * remaining bytes in src and dst buffers after ACM conversions... - * those should be taken care of... - */ - -#include <stdarg.h> -#include <string.h> -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "mmddk.h" -#include "mmreg.h" -#include "msacm.h" -#include "wine/unicode.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(wavemap); - -typedef struct tagWAVEMAPDATA { - struct tagWAVEMAPDATA* self; - union { - struct { - HWAVEOUT hOuterWave; - HWAVEOUT hInnerWave; - } out; - struct { - HWAVEIN hOuterWave; - HWAVEIN hInnerWave; - } in; - } u; - HACMSTREAM hAcmStream; - /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */ - DWORD dwCallback; - DWORD dwClientInstance; - DWORD dwFlags; - /* ratio to compute position from a PCM playback to any format */ - DWORD avgSpeedOuter; - DWORD avgSpeedInner; - /* channel size of inner and outer */ - DWORD nSamplesPerSecOuter; - DWORD nSamplesPerSecInner; -} WAVEMAPDATA; - -static BOOL WAVEMAP_IsData(WAVEMAPDATA* wm) -{ - return (!IsBadReadPtr(wm, sizeof(WAVEMAPDATA)) && wm->self == wm); -} - -/*======================================================================* - * WAVE OUT part * - *======================================================================*/ - -static void CALLBACK wodCallback(HWAVEOUT hWave, UINT uMsg, DWORD dwInstance, - DWORD dwParam1, DWORD dwParam2) -{ - WAVEMAPDATA* wom = (WAVEMAPDATA*)dwInstance; - - TRACE("(%p %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2); - - if (!WAVEMAP_IsData(wom)) { - ERR("Bad data\n"); - return; - } - - if (hWave != wom->u.out.hInnerWave && uMsg != WOM_OPEN) - ERR("Shouldn't happen (%p %p)\n", hWave, wom->u.out.hInnerWave); - - switch (uMsg) { - case WOM_OPEN: - case WOM_CLOSE: - /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ - break; - case WOM_DONE: - if (wom->hAcmStream) { - LPWAVEHDR lpWaveHdrDst = (LPWAVEHDR)dwParam1; - PACMSTREAMHEADER ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrDst - sizeof(ACMSTREAMHEADER)); - LPWAVEHDR lpWaveHdrSrc = (LPWAVEHDR)ash->dwUser; - - lpWaveHdrSrc->dwFlags &= ~WHDR_INQUEUE; - lpWaveHdrSrc->dwFlags |= WHDR_DONE; - dwParam1 = (DWORD)lpWaveHdrSrc; - } - break; - default: - ERR("Unknown msg %u\n", uMsg); - } - - DriverCallback(wom->dwCallback, HIWORD(wom->dwFlags), (HDRVR)wom->u.out.hOuterWave, - uMsg, wom->dwClientInstance, dwParam1, dwParam2); -} - -/****************************************************************** - * wodOpenHelper - * - * - */ -static DWORD wodOpenHelper(WAVEMAPDATA* wom, UINT idx, - LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx, - DWORD dwFlags) -{ - DWORD ret; - - TRACE("(%p %04x %p %p %08lx)\n", wom, idx, lpDesc, lpwfx, dwFlags); - - /* destination is always PCM, so the formulas below apply */ - lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8; - lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign; - if (dwFlags & WAVE_FORMAT_QUERY) { - ret = acmStreamOpen(NULL, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY); - } else { - ret = acmStreamOpen(&wom->hAcmStream, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, 0L); - } - if (ret == MMSYSERR_NOERROR) { - ret = waveOutOpen(&wom->u.out.hInnerWave, idx, lpwfx, (DWORD)wodCallback, - (DWORD)wom, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION); - if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) { - acmStreamClose(wom->hAcmStream, 0); - wom->hAcmStream = 0; - } - } - TRACE("ret = %08lx\n", ret); - return ret; -} - -static DWORD wodOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags) -{ - UINT ndlo, ndhi; - UINT i; - WAVEMAPDATA* wom = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA)); - DWORD res; - - TRACE("(%p %p %08lx)\n", lpdwUser, lpDesc, dwFlags); - - if (!wom) { - WARN("no memory\n"); - return MMSYSERR_NOMEM; - } - - ndhi = waveOutGetNumDevs(); - if (dwFlags & WAVE_MAPPED) { - if (lpDesc->uMappedDeviceID >= ndhi) { - WARN("invalid parameter: dwFlags WAVE_MAPPED\n"); - HeapFree(GetProcessHeap(), 0, wom); - return MMSYSERR_INVALPARAM; - } - ndlo = lpDesc->uMappedDeviceID; - ndhi = ndlo + 1; - dwFlags &= ~WAVE_MAPPED; - } else { - ndlo = 0; - } - wom->self = wom; - wom->dwCallback = lpDesc->dwCallback; - wom->dwFlags = dwFlags; - wom->dwClientInstance = lpDesc->dwInstance; - wom->u.out.hOuterWave = (HWAVEOUT)lpDesc->hWave; - wom->avgSpeedOuter = wom->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec; - wom->nSamplesPerSecOuter = wom->nSamplesPerSecInner = lpDesc->lpFormat->nSamplesPerSec; - - for (i = ndlo; i < ndhi; i++) { - /* if no ACM stuff is involved, no need to handle callbacks at this - * level, this will be done transparently - */ - if (waveOutOpen(&wom->u.out.hInnerWave, i, lpDesc->lpFormat, (DWORD)wodCallback, - (DWORD)wom, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) { - wom->hAcmStream = 0; - goto found; - } - } - - if ((dwFlags & WAVE_FORMAT_DIRECT) == 0 && lpDesc->lpFormat->wFormatTag == WAVE_FORMAT_PCM) { - WAVEFORMATEX wfx; - - wfx.wFormatTag = WAVE_FORMAT_PCM; - wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */ - /* try some ACM stuff */ - -#define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \ - switch (res=wodOpenHelper(wom, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \ - case MMSYSERR_NOERROR: wom->avgSpeedInner = wfx.nAvgBytesPerSec; wom->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \ - case WAVERR_BADFORMAT: break; \ - default: goto error; \ - } - - /* Our resampling algorithm is quite primitive so first try - * to just change the bit depth and number of channels - */ - for (i = ndlo; i < ndhi; i++) { - wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec; - wfx.nChannels = lpDesc->lpFormat->nChannels; - TRY(wfx.nSamplesPerSec, 16); - TRY(wfx.nSamplesPerSec, 8); - wfx.nChannels ^= 3; - TRY(wfx.nSamplesPerSec, 16); - TRY(wfx.nSamplesPerSec, 8); - } - - for (i = ndlo; i < ndhi; i++) { - /* first try with same stereo/mono option as source */ - wfx.nChannels = lpDesc->lpFormat->nChannels; - TRY(96000, 16); - TRY(48000, 16); - TRY(44100, 16); - TRY(22050, 16); - TRY(11025, 16); - - /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */ - wfx.nChannels ^= 3; - TRY(96000, 16); - TRY(48000, 16); - TRY(44100, 16); - TRY(22050, 16); - TRY(11025, 16); - - /* first try with same stereo/mono option as source */ - wfx.nChannels = lpDesc->lpFormat->nChannels; - TRY(96000, 8); - TRY(48000, 8); - TRY(44100, 8); - TRY(22050, 8); - TRY(11025, 8); - - /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */ - wfx.nChannels ^= 3; - TRY(96000, 8); - TRY(48000, 8); - TRY(44100, 8); - TRY(22050, 8); - TRY(11025, 8); - } -#undef TRY - } - - HeapFree(GetProcessHeap(), 0, wom); - WARN("ret = WAVERR_BADFORMAT\n"); - return WAVERR_BADFORMAT; - -found: - if (dwFlags & WAVE_FORMAT_QUERY) { - *lpdwUser = 0L; - HeapFree(GetProcessHeap(), 0, wom); - } else { - *lpdwUser = (DWORD)wom; - } - return MMSYSERR_NOERROR; -error: - HeapFree(GetProcessHeap(), 0, wom); - if (res==ACMERR_NOTPOSSIBLE) { - WARN("ret = WAVERR_BADFORMAT\n"); - return WAVERR_BADFORMAT; - } - WARN("ret = 0x%08lx\n", res); - return res; -} - -static DWORD wodClose(WAVEMAPDATA* wom) -{ - DWORD ret; - - TRACE("(%p)\n", wom); - - ret = waveOutClose(wom->u.out.hInnerWave); - if (ret == MMSYSERR_NOERROR) { - if (wom->hAcmStream) { - ret = acmStreamClose(wom->hAcmStream, 0); - } - if (ret == MMSYSERR_NOERROR) { - HeapFree(GetProcessHeap(), 0, wom); - } - } - return ret; -} - -static DWORD wodWrite(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2) -{ - PACMSTREAMHEADER ash; - LPWAVEHDR lpWaveHdrDst; - - TRACE("(%p %p %08lx)\n", wom, lpWaveHdrSrc, dwParam2); - - if (!wom->hAcmStream) { - return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2); - } - - lpWaveHdrSrc->dwFlags |= WHDR_INQUEUE; - ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved; - /* acmStreamConvert will actually check that the new size is less than initial size */ - ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength; - if (acmStreamConvert(wom->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) { - WARN("acmStreamConvert failed\n"); - return MMSYSERR_ERROR; - } - - lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); - if (ash->cbSrcLength > ash->cbSrcLengthUsed) - FIXME("Not all src buffer has been written, expect bogus sound\n"); - else if (ash->cbSrcLength < ash->cbSrcLengthUsed) - ERR("CoDec has read more data than it is allowed to\n"); - - if (ash->cbDstLengthUsed == 0) { - /* something went wrong in decoding */ - FIXME("Got 0 length\n"); - return MMSYSERR_ERROR; - } - lpWaveHdrDst->dwBufferLength = ash->cbDstLengthUsed; - return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst)); -} - -static DWORD wodPrepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2) -{ - PACMSTREAMHEADER ash; - DWORD size; - DWORD dwRet; - LPWAVEHDR lpWaveHdrDst; - - TRACE("(%p %p %08lx)\n", wom, lpWaveHdrSrc, dwParam2); - - if (!wom->hAcmStream) - return waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2); - - if (acmStreamSize(wom->hAcmStream, lpWaveHdrSrc->dwBufferLength, &size, ACM_STREAMSIZEF_SOURCE) != MMSYSERR_NOERROR) { - WARN("acmStreamSize failed\n"); - return MMSYSERR_ERROR; - } - - ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size); - if (ash == NULL) { - WARN("no memory\n"); - return MMSYSERR_NOMEM; - } - - ash->cbStruct = sizeof(*ash); - ash->fdwStatus = 0L; - ash->dwUser = (DWORD)lpWaveHdrSrc; - ash->pbSrc = lpWaveHdrSrc->lpData; - ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength; - /* ash->cbSrcLengthUsed */ - ash->dwSrcUser = lpWaveHdrSrc->dwUser; /* FIXME ? */ - ash->pbDst = (LPSTR)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR); - ash->cbDstLength = size; - /* ash->cbDstLengthUsed */ - ash->dwDstUser = 0; /* FIXME ? */ - dwRet = acmStreamPrepareHeader(wom->hAcmStream, ash, 0L); - if (dwRet != MMSYSERR_NOERROR) { - WARN("acmStreamPrepareHeader failed\n"); - goto errCleanUp; - } - - lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); - lpWaveHdrDst->lpData = ash->pbDst; - lpWaveHdrDst->dwBufferLength = size; /* conversion is not done yet */ - lpWaveHdrDst->dwFlags = 0; - lpWaveHdrDst->dwLoops = 0; - dwRet = waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst)); - if (dwRet != MMSYSERR_NOERROR) { - WARN("waveOutPrepareHeader failed\n"); - goto errCleanUp; - } - - lpWaveHdrSrc->reserved = (DWORD)ash; - lpWaveHdrSrc->dwFlags = WHDR_PREPARED; - TRACE("=> (0)\n"); - return MMSYSERR_NOERROR; -errCleanUp: - TRACE("=> (%ld)\n", dwRet); - HeapFree(GetProcessHeap(), 0, ash); - return dwRet; -} - -static DWORD wodUnprepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2) -{ - PACMSTREAMHEADER ash; - LPWAVEHDR lpWaveHdrDst; - DWORD dwRet1, dwRet2; - - TRACE("(%p %p %08lx)\n", wom, lpWaveHdrSrc, dwParam2); - - if (!wom->hAcmStream) { - return waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2); - } - ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved; - dwRet1 = acmStreamUnprepareHeader(wom->hAcmStream, ash, 0L); - - lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); - dwRet2 = waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst)); - - HeapFree(GetProcessHeap(), 0, ash); - - lpWaveHdrSrc->dwFlags &= ~WHDR_PREPARED; - return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1; -} - -static DWORD wodGetPosition(WAVEMAPDATA* wom, LPMMTIME lpTime, DWORD dwParam2) -{ - DWORD val; - MMTIME timepos; - TRACE("(%p %p %08lx)\n", wom, lpTime, dwParam2); - - memcpy(&timepos, lpTime, sizeof(timepos)); - - /* For TIME_MS, we're going to recalculate using TIME_BYTES */ - if (lpTime->wType == TIME_MS) - timepos.wType = TIME_BYTES; - - /* This can change timepos.wType if the requested type is not supported */ - val = waveOutGetPosition(wom->u.out.hInnerWave, &timepos, dwParam2); - - if (timepos.wType == TIME_BYTES) - { - DWORD dwInnerSamplesPerOuter = wom->nSamplesPerSecInner / wom->nSamplesPerSecOuter; - if (dwInnerSamplesPerOuter > 0) - { - DWORD dwInnerBytesPerSample = wom->avgSpeedInner / wom->nSamplesPerSecInner; - DWORD dwInnerBytesPerOuterSample = dwInnerBytesPerSample * dwInnerSamplesPerOuter; - DWORD remainder = 0; - - /* If we are up sampling (going from lower sample rate to higher), - ** we need to make a special accomodation for times when we've - ** written a partial output sample. This happens frequently - ** to us because we use msacm to do our up sampling, and it - ** will up sample on an unaligned basis. - ** For example, if you convert a 2 byte wide 8,000 'outer' - ** buffer to a 2 byte wide 48,000 inner device, you would - ** expect 2 bytes of input to produce 12 bytes of output. - ** Instead, msacm will produce 8 bytes of output. - ** But reporting our position as 1 byte of output is - ** nonsensical; the output buffer position needs to be - ** aligned on outer sample size, and aggressively rounded up. - */ - remainder = timepos.u.cb % dwInnerBytesPerOuterSample; - if (remainder > 0) - { - timepos.u.cb -= remainder; - timepos.u.cb += dwInnerBytesPerOuterSample; - } - } - - lpTime->u.cb = MulDiv(timepos.u.cb, wom->avgSpeedOuter, wom->avgSpeedInner); - - /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */ - if (lpTime->wType == TIME_MS) - lpTime->u.ms = MulDiv(lpTime->u.cb, 1000, wom->avgSpeedOuter); - else - lpTime->wType = TIME_BYTES; - } - else if (lpTime->wType == TIME_SAMPLES && timepos.wType == TIME_SAMPLES) - lpTime->u.sample = MulDiv(timepos.u.sample, wom->nSamplesPerSecOuter, wom->nSamplesPerSecInner); - else - /* other time types don't require conversion */ - lpTime->u = timepos.u; - - return val; -} - -static DWORD wodGetDevCaps(UINT wDevID, WAVEMAPDATA* wom, LPWAVEOUTCAPSW lpWaveCaps, DWORD dwParam2) -{ - static const WCHAR name[] = {'W','i','n','e',' ','w','a','v','e',' ','o','u','t',' ','m','a','p','p','e','r',0}; - - TRACE("(%04x %p %p %08lx)\n",wDevID, wom, lpWaveCaps, dwParam2); - - /* if opened low driver, forward message */ - if (WAVEMAP_IsData(wom)) - return waveOutGetDevCapsW((UINT)wom->u.out.hInnerWave, lpWaveCaps, dwParam2); - /* else if no drivers, nothing to map so return bad device */ - if (waveOutGetNumDevs() == 0) { - WARN("bad device id\n"); - return MMSYSERR_BADDEVICEID; - } - /* otherwise, return caps of mapper itself */ - if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) { - WAVEOUTCAPSW woc; - woc.wMid = 0x00FF; - woc.wPid = 0x0001; - woc.vDriverVersion = 0x0100; - lstrcpyW(woc.szPname, name); - woc.dwFormats = - WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 | - WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 | - WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 | - WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 | - WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16; - woc.wChannels = 2; - woc.dwSupport = WAVECAPS_VOLUME | WAVECAPS_LRVOLUME; - memcpy(lpWaveCaps, &woc, min(dwParam2, sizeof(woc))); - - return MMSYSERR_NOERROR; - } - ERR("This shouldn't happen\n"); - return MMSYSERR_ERROR; -} - -static DWORD wodGetVolume(UINT wDevID, WAVEMAPDATA* wom, LPDWORD lpVol) -{ - TRACE("(%04x %p %p)\n",wDevID, wom, lpVol); - - if (WAVEMAP_IsData(wom)) - return waveOutGetVolume(wom->u.out.hInnerWave, lpVol); - return MMSYSERR_NOERROR; -} - -static DWORD wodSetVolume(UINT wDevID, WAVEMAPDATA* wom, DWORD vol) -{ - TRACE("(%04x %p %08lx)\n",wDevID, wom, vol); - - if (WAVEMAP_IsData(wom)) - return waveOutSetVolume(wom->u.out.hInnerWave, vol); - return MMSYSERR_NOERROR; -} - -static DWORD wodPause(WAVEMAPDATA* wom) -{ - TRACE("(%p)\n",wom); - - return waveOutPause(wom->u.out.hInnerWave); -} - -static DWORD wodRestart(WAVEMAPDATA* wom) -{ - TRACE("(%p)\n",wom); - - return waveOutRestart(wom->u.out.hInnerWave); -} - -static DWORD wodReset(WAVEMAPDATA* wom) -{ - TRACE("(%p)\n",wom); - - return waveOutReset(wom->u.out.hInnerWave); -} - -static DWORD wodBreakLoop(WAVEMAPDATA* wom) -{ - TRACE("(%p)\n",wom); - - return waveOutBreakLoop(wom->u.out.hInnerWave); -} - -static DWORD wodMapperStatus(WAVEMAPDATA* wom, DWORD flags, LPVOID ptr) -{ - UINT id; - DWORD ret = MMSYSERR_NOTSUPPORTED; - - TRACE("(%p %08lx %p)\n",wom, flags, ptr); - - switch (flags) { - case WAVEOUT_MAPPER_STATUS_DEVICE: - ret = waveOutGetID(wom->u.out.hInnerWave, &id); - *(LPDWORD)ptr = id; - break; - case WAVEOUT_MAPPER_STATUS_MAPPED: - FIXME("Unsupported flag=%ld\n", flags); - *(LPDWORD)ptr = 0; /* FIXME ?? */ - break; - case WAVEOUT_MAPPER_STATUS_FORMAT: - FIXME("Unsupported flag=%ld\n", flags); - /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */ - *(LPDWORD)ptr = 0; - break; - default: - FIXME("Unsupported flag=%ld\n", flags); - *(LPDWORD)ptr = 0; - break; - } - return ret; -} - -static DWORD wodMapperReconfigure(WAVEMAPDATA* wom, DWORD dwParam1, DWORD dwParam2) -{ - FIXME("(%p %08lx %08lx) stub!\n", wom, dwParam1, dwParam2); - - return MMSYSERR_NOERROR; -} - -/************************************************************************** - * wodMessage (MSACM.@) - */ -DWORD WINAPI WAVEMAP_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser, - DWORD dwParam1, DWORD dwParam2) -{ - TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n", - wDevID, wMsg, dwUser, dwParam1, dwParam2); - - switch (wMsg) { - case DRVM_INIT: - case DRVM_EXIT: - case DRVM_ENABLE: - case DRVM_DISABLE: - /* FIXME: Pretend this is supported */ - return 0; - case WODM_OPEN: return wodOpen ((LPDWORD)dwUser, (LPWAVEOPENDESC)dwParam1,dwParam2); - case WODM_CLOSE: return wodClose ((WAVEMAPDATA*)dwUser); - case WODM_WRITE: return wodWrite ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); - case WODM_PAUSE: return wodPause ((WAVEMAPDATA*)dwUser); - case WODM_GETPOS: return wodGetPosition ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, dwParam2); - case WODM_BREAKLOOP: return wodBreakLoop ((WAVEMAPDATA*)dwUser); - case WODM_PREPARE: return wodPrepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); - case WODM_UNPREPARE: return wodUnprepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); - case WODM_GETDEVCAPS: return wodGetDevCaps (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEOUTCAPSW)dwParam1,dwParam2); - case WODM_GETNUMDEVS: return 1; - case WODM_GETPITCH: return MMSYSERR_NOTSUPPORTED; - case WODM_SETPITCH: return MMSYSERR_NOTSUPPORTED; - case WODM_GETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED; - case WODM_SETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED; - case WODM_GETVOLUME: return wodGetVolume (wDevID, (WAVEMAPDATA*)dwUser, (LPDWORD)dwParam1); - case WODM_SETVOLUME: return wodSetVolume (wDevID, (WAVEMAPDATA*)dwUser, dwParam1); - case WODM_RESTART: return wodRestart ((WAVEMAPDATA*)dwUser); - case WODM_RESET: return wodReset ((WAVEMAPDATA*)dwUser); - case WODM_MAPPER_STATUS: return wodMapperStatus ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2); - case DRVM_MAPPER_RECONFIGURE: return wodMapperReconfigure((WAVEMAPDATA*)dwUser, dwParam1, dwParam2); - /* known but not supported */ - case DRV_QUERYDEVICEINTERFACESIZE: - case DRV_QUERYDEVICEINTERFACE: - return MMSYSERR_NOTSUPPORTED; - default: - FIXME("unknown message %d!\n", wMsg); - } - return MMSYSERR_NOTSUPPORTED; -} - -/*======================================================================* - * WAVE IN part * - *======================================================================*/ - -static void CALLBACK widCallback(HWAVEIN hWave, UINT uMsg, DWORD dwInstance, - DWORD dwParam1, DWORD dwParam2) -{ - WAVEMAPDATA* wim = (WAVEMAPDATA*)dwInstance; - - TRACE("(%p %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2); - - if (!WAVEMAP_IsData(wim)) { - ERR("Bad data\n"); - return; - } - - if (hWave != wim->u.in.hInnerWave && uMsg != WIM_OPEN) - ERR("Shouldn't happen (%p %p)\n", hWave, wim->u.in.hInnerWave); - - switch (uMsg) { - case WIM_OPEN: - case WIM_CLOSE: - /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ - break; - case WIM_DATA: - if (wim->hAcmStream) { - LPWAVEHDR lpWaveHdrSrc = (LPWAVEHDR)dwParam1; - PACMSTREAMHEADER ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrSrc - sizeof(ACMSTREAMHEADER)); - LPWAVEHDR lpWaveHdrDst = (LPWAVEHDR)ash->dwUser; - - /* convert data just gotten from waveIn into requested format */ - if (acmStreamConvert(wim->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) { - ERR("ACM conversion failed\n"); - return; - } else { - TRACE("Converted %ld bytes into %ld\n", ash->cbSrcLengthUsed, ash->cbDstLengthUsed); - } - /* and setup the wavehdr to return accordingly */ - lpWaveHdrDst->dwFlags &= ~WHDR_INQUEUE; - lpWaveHdrDst->dwFlags |= WHDR_DONE; - lpWaveHdrDst->dwBytesRecorded = ash->cbDstLengthUsed; - dwParam1 = (DWORD)lpWaveHdrDst; - } - break; - default: - ERR("Unknown msg %u\n", uMsg); - } - - DriverCallback(wim->dwCallback, HIWORD(wim->dwFlags), (HDRVR)wim->u.in.hOuterWave, - uMsg, wim->dwClientInstance, dwParam1, dwParam2); -} - -static DWORD widOpenHelper(WAVEMAPDATA* wim, UINT idx, - LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx, - DWORD dwFlags) -{ - DWORD ret; - - TRACE("(%p %04x %p %p %08lx)\n", wim, idx, lpDesc, lpwfx, dwFlags); - - /* source is always PCM, so the formulas below apply */ - lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8; - lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign; - if (dwFlags & WAVE_FORMAT_QUERY) { - ret = acmStreamOpen(NULL, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY); - } else { - ret = acmStreamOpen(&wim->hAcmStream, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, 0L); - } - if (ret == MMSYSERR_NOERROR) { - ret = waveInOpen(&wim->u.in.hInnerWave, idx, lpwfx, (DWORD)widCallback, - (DWORD)wim, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION); - if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) { - acmStreamClose(wim->hAcmStream, 0); - wim->hAcmStream = 0; - } - } - TRACE("ret = %08lx\n", ret); - return ret; -} - -static DWORD widOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags) -{ - UINT ndlo, ndhi; - UINT i; - WAVEMAPDATA* wim = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA)); - DWORD res; - - TRACE("(%p %p %08lx)\n", lpdwUser, lpDesc, dwFlags); - - if (!wim) { - WARN("no memory\n"); - return MMSYSERR_NOMEM; - } - - wim->self = wim; - wim->dwCallback = lpDesc->dwCallback; - wim->dwFlags = dwFlags; - wim->dwClientInstance = lpDesc->dwInstance; - wim->u.in.hOuterWave = (HWAVEIN)lpDesc->hWave; - - ndhi = waveInGetNumDevs(); - if (dwFlags & WAVE_MAPPED) { - if (lpDesc->uMappedDeviceID >= ndhi) return MMSYSERR_INVALPARAM; - ndlo = lpDesc->uMappedDeviceID; - ndhi = ndlo + 1; - dwFlags &= ~WAVE_MAPPED; - } else { - ndlo = 0; - } - - wim->avgSpeedOuter = wim->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec; - wim->nSamplesPerSecOuter = wim->nSamplesPerSecInner = lpDesc->lpFormat->nSamplesPerSec; - - for (i = ndlo; i < ndhi; i++) { - if (waveInOpen(&wim->u.in.hInnerWave, i, lpDesc->lpFormat, (DWORD)widCallback, - (DWORD)wim, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) { - wim->hAcmStream = 0; - goto found; - } - } - - if ((dwFlags & WAVE_FORMAT_DIRECT) == 0) - { - WAVEFORMATEX wfx; - - wfx.wFormatTag = WAVE_FORMAT_PCM; - wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */ - /* try some ACM stuff */ - -#define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \ - switch (res=widOpenHelper(wim, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \ - case MMSYSERR_NOERROR: wim->avgSpeedInner = wfx.nAvgBytesPerSec; wim->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \ - case WAVERR_BADFORMAT: break; \ - default: goto error; \ - } - - for (i = ndlo; i < ndhi; i++) { - wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec; - /* first try with same stereo/mono option as source */ - wfx.nChannels = lpDesc->lpFormat->nChannels; - TRY(wfx.nSamplesPerSec, 16); - TRY(wfx.nSamplesPerSec, 8); - wfx.nChannels ^= 3; - TRY(wfx.nSamplesPerSec, 16); - TRY(wfx.nSamplesPerSec, 8); - } - - for (i = ndlo; i < ndhi; i++) { - wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec; - /* first try with same stereo/mono option as source */ - wfx.nChannels = lpDesc->lpFormat->nChannels; - TRY(96000, 16); - TRY(48000, 16); - TRY(44100, 16); - TRY(22050, 16); - TRY(11025, 16); - - /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */ - wfx.nChannels ^= 3; - TRY(96000, 16); - TRY(48000, 16); - TRY(44100, 16); - TRY(22050, 16); - TRY(11025, 16); - - /* first try with same stereo/mono option as source */ - wfx.nChannels = lpDesc->lpFormat->nChannels; - TRY(96000, 8); - TRY(48000, 8); - TRY(44100, 8); - TRY(22050, 8); - TRY(11025, 8); - - /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */ - wfx.nChannels ^= 3; - TRY(96000, 8); - TRY(48000, 8); - TRY(44100, 8); - TRY(22050, 8); - TRY(11025, 8); - } -#undef TRY - } - - HeapFree(GetProcessHeap(), 0, wim); - WARN("ret = WAVERR_BADFORMAT\n"); - return WAVERR_BADFORMAT; -found: - if (dwFlags & WAVE_FORMAT_QUERY) { - *lpdwUser = 0L; - HeapFree(GetProcessHeap(), 0, wim); - } else { - *lpdwUser = (DWORD)wim; - } - TRACE("Ok (stream=%08lx)\n", (DWORD)wim->hAcmStream); - return MMSYSERR_NOERROR; -error: - HeapFree(GetProcessHeap(), 0, wim); - if (res==ACMERR_NOTPOSSIBLE) { - WARN("ret = WAVERR_BADFORMAT\n"); - return WAVERR_BADFORMAT; - } - WARN("ret = 0x%08lx\n", res); - return res; -} - -static DWORD widClose(WAVEMAPDATA* wim) -{ - DWORD ret; - - TRACE("(%p)\n", wim); - - ret = waveInClose(wim->u.in.hInnerWave); - if (ret == MMSYSERR_NOERROR) { - if (wim->hAcmStream) { - ret = acmStreamClose(wim->hAcmStream, 0); - } - if (ret == MMSYSERR_NOERROR) { - HeapFree(GetProcessHeap(), 0, wim); - } - } - return ret; -} - -static DWORD widAddBuffer(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2) -{ - PACMSTREAMHEADER ash; - LPWAVEHDR lpWaveHdrSrc; - - TRACE("(%p %p %08lx)\n", wim, lpWaveHdrDst, dwParam2); - - if (!wim->hAcmStream) { - return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2); - } - - lpWaveHdrDst->dwFlags |= WHDR_INQUEUE; - ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved; - - lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); - return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc)); -} - -static DWORD widPrepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2) -{ - PACMSTREAMHEADER ash; - DWORD size; - DWORD dwRet; - LPWAVEHDR lpWaveHdrSrc; - - TRACE("(%p %p %08lx)\n", wim, lpWaveHdrDst, dwParam2); - - if (!wim->hAcmStream) { - return waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2); - } - if (acmStreamSize(wim->hAcmStream, lpWaveHdrDst->dwBufferLength, &size, - ACM_STREAMSIZEF_DESTINATION) != MMSYSERR_NOERROR) { - WARN("acmStreamSize failed\n"); - return MMSYSERR_ERROR; - } - - ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size); - if (ash == NULL) { - WARN("no memory\n"); - return MMSYSERR_NOMEM; - } - - ash->cbStruct = sizeof(*ash); - ash->fdwStatus = 0L; - ash->dwUser = (DWORD)lpWaveHdrDst; - ash->pbSrc = (LPSTR)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR); - ash->cbSrcLength = size; - /* ash->cbSrcLengthUsed */ - ash->dwSrcUser = 0L; /* FIXME ? */ - ash->pbDst = lpWaveHdrDst->lpData; - ash->cbDstLength = lpWaveHdrDst->dwBufferLength; - /* ash->cbDstLengthUsed */ - ash->dwDstUser = lpWaveHdrDst->dwUser; /* FIXME ? */ - dwRet = acmStreamPrepareHeader(wim->hAcmStream, ash, 0L); - if (dwRet != MMSYSERR_NOERROR) { - WARN("acmStreamPrepareHeader failed\n"); - goto errCleanUp; - } - - lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); - lpWaveHdrSrc->lpData = ash->pbSrc; - lpWaveHdrSrc->dwBufferLength = size; /* conversion is not done yet */ - lpWaveHdrSrc->dwFlags = 0; - lpWaveHdrSrc->dwLoops = 0; - dwRet = waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc)); - if (dwRet != MMSYSERR_NOERROR) { - WARN("waveInPrepareHeader failed\n"); - goto errCleanUp; - } - - lpWaveHdrDst->reserved = (DWORD)ash; - lpWaveHdrDst->dwFlags = WHDR_PREPARED; - TRACE("=> (0)\n"); - return MMSYSERR_NOERROR; -errCleanUp: - TRACE("=> (%ld)\n", dwRet); - HeapFree(GetProcessHeap(), 0, ash); - return dwRet; -} - -static DWORD widUnprepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2) -{ - PACMSTREAMHEADER ash; - LPWAVEHDR lpWaveHdrSrc; - DWORD dwRet1, dwRet2; - - TRACE("(%p %p %08lx)\n", wim, lpWaveHdrDst, dwParam2); - - if (!wim->hAcmStream) { - return waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2); - } - ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved; - dwRet1 = acmStreamUnprepareHeader(wim->hAcmStream, ash, 0L); - - lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); - dwRet2 = waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc)); - - HeapFree(GetProcessHeap(), 0, ash); - - lpWaveHdrDst->dwFlags &= ~WHDR_PREPARED; - return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1; -} - -static DWORD widGetPosition(WAVEMAPDATA* wim, LPMMTIME lpTime, DWORD dwParam2) -{ - DWORD val; - MMTIME timepos; - TRACE("(%p %p %08lx)\n", wim, lpTime, dwParam2); - - memcpy(&timepos, lpTime, sizeof(timepos)); - - /* For TIME_MS, we're going to recalculate using TIME_BYTES */ - if (lpTime->wType == TIME_MS) - timepos.wType = TIME_BYTES; - - /* This can change timepos.wType if the requested type is not supported */ - val = waveInGetPosition(wim->u.in.hInnerWave, &timepos, dwParam2); - - if (timepos.wType == TIME_BYTES) - { - DWORD dwInnerSamplesPerOuter = wim->nSamplesPerSecInner / wim->nSamplesPerSecOuter; - if (dwInnerSamplesPerOuter > 0) - { - DWORD dwInnerBytesPerSample = wim->avgSpeedInner / wim->nSamplesPerSecInner; - DWORD dwInnerBytesPerOuterSample = dwInnerBytesPerSample * dwInnerSamplesPerOuter; - DWORD remainder = 0; - - /* If we are up sampling (going from lower sample rate to higher), - ** we need to make a special accomodation for times when we've - ** written a partial output sample. This happens frequently - ** to us because we use msacm to do our up sampling, and it - ** will up sample on an unaligned basis. - ** For example, if you convert a 2 byte wide 8,000 'outer' - ** buffer to a 2 byte wide 48,000 inner device, you would - ** expect 2 bytes of input to produce 12 bytes of output. - ** Instead, msacm will produce 8 bytes of output. - ** But reporting our position as 1 byte of output is - ** nonsensical; the output buffer position needs to be - ** aligned on outer sample size, and aggressively rounded up. - */ - remainder = timepos.u.cb % dwInnerBytesPerOuterSample; - if (remainder > 0) - { - timepos.u.cb -= remainder; - timepos.u.cb += dwInnerBytesPerOuterSample; - } - } - - lpTime->u.cb = MulDiv(timepos.u.cb, wim->avgSpeedOuter, wim->avgSpeedInner); - - /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */ - if (lpTime->wType == TIME_MS) - lpTime->u.ms = MulDiv(lpTime->u.cb, 1000, wim->avgSpeedOuter); - else - lpTime->wType = TIME_BYTES; - } - else if (lpTime->wType == TIME_SAMPLES && timepos.wType == TIME_SAMPLES) - lpTime->u.sample = MulDiv(timepos.u.sample, wim->nSamplesPerSecOuter, wim->nSamplesPerSecInner); - else - /* other time types don't require conversion */ - lpTime->u = timepos.u; - - return val; -} - -static DWORD widGetDevCaps(UINT wDevID, WAVEMAPDATA* wim, LPWAVEINCAPSW lpWaveCaps, DWORD dwParam2) -{ - TRACE("(%04x, %p %p %08lx)\n", wDevID, wim, lpWaveCaps, dwParam2); - - /* if opened low driver, forward message */ - if (WAVEMAP_IsData(wim)) - return waveInGetDevCapsW((UINT)wim->u.in.hInnerWave, lpWaveCaps, dwParam2); - /* else if no drivers, nothing to map so return bad device */ - if (waveInGetNumDevs() == 0) { - WARN("bad device id\n"); - return MMSYSERR_BADDEVICEID; - } - /* otherwise, return caps of mapper itself */ - if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) { - WAVEINCAPSW wic; - static const WCHAR init[] = {'W','i','n','e',' ','w','a','v','e',' ','i','n',' ','m','a','p','p','e','r',0}; - wic.wMid = 0x00FF; - wic.wPid = 0x0001; - wic.vDriverVersion = 0x0001; - strcpyW(wic.szPname, init); - wic.dwFormats = - WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 | - WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 | - WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 | - WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 | - WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16; - wic.wChannels = 2; - memcpy(lpWaveCaps, &wic, min(dwParam2, sizeof(wic))); - - return MMSYSERR_NOERROR; - } - ERR("This shouldn't happen\n"); - return MMSYSERR_ERROR; -} - -static DWORD widStop(WAVEMAPDATA* wim) -{ - TRACE("(%p)\n", wim); - - return waveInStop(wim->u.in.hInnerWave); -} - -static DWORD widStart(WAVEMAPDATA* wim) -{ - TRACE("(%p)\n", wim); - - return waveInStart(wim->u.in.hInnerWave); -} - -static DWORD widReset(WAVEMAPDATA* wim) -{ - TRACE("(%p)\n", wim); - - return waveInReset(wim->u.in.hInnerWave); -} - -static DWORD widMapperStatus(WAVEMAPDATA* wim, DWORD flags, LPVOID ptr) -{ - UINT id; - DWORD ret = MMSYSERR_NOTSUPPORTED; - - TRACE("(%p %08lx %p)\n", wim, flags, ptr); - - switch (flags) { - case WAVEIN_MAPPER_STATUS_DEVICE: - ret = waveInGetID(wim->u.in.hInnerWave, &id); - *(LPDWORD)ptr = id; - break; - case WAVEIN_MAPPER_STATUS_MAPPED: - FIXME("Unsupported yet flag=%ld\n", flags); - *(LPDWORD)ptr = 0; /* FIXME ?? */ - break; - case WAVEIN_MAPPER_STATUS_FORMAT: - FIXME("Unsupported flag=%ld\n", flags); - /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */ - *(LPDWORD)ptr = 0; /* FIXME ?? */ - break; - default: - FIXME("Unsupported flag=%ld\n", flags); - *(LPDWORD)ptr = 0; - break; - } - return ret; -} - -static DWORD widMapperReconfigure(WAVEMAPDATA* wim, DWORD dwParam1, DWORD dwParam2) -{ - FIXME("(%p %08lx %08lx) stub!\n", wim, dwParam1, dwParam2); - - return MMSYSERR_NOERROR; -} - -/************************************************************************** - * widMessage (MSACM.@) - */ -DWORD WINAPI WAVEMAP_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser, - DWORD dwParam1, DWORD dwParam2) -{ - TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n", - wDevID, wMsg, dwUser, dwParam1, dwParam2); - - switch (wMsg) { - case DRVM_INIT: - case DRVM_EXIT: - case DRVM_ENABLE: - case DRVM_DISABLE: - /* FIXME: Pretend this is supported */ - return 0; - - case WIDM_OPEN: return widOpen ((LPDWORD)dwUser, (LPWAVEOPENDESC)dwParam1, dwParam2); - case WIDM_CLOSE: return widClose ((WAVEMAPDATA*)dwUser); - - case WIDM_ADDBUFFER: return widAddBuffer ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); - case WIDM_PREPARE: return widPrepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); - case WIDM_UNPREPARE: return widUnprepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); - case WIDM_GETDEVCAPS: return widGetDevCaps (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEINCAPSW)dwParam1, dwParam2); - case WIDM_GETNUMDEVS: return 1; - case WIDM_GETPOS: return widGetPosition ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, dwParam2); - case WIDM_RESET: return widReset ((WAVEMAPDATA*)dwUser); - case WIDM_START: return widStart ((WAVEMAPDATA*)dwUser); - case WIDM_STOP: return widStop ((WAVEMAPDATA*)dwUser); - case WIDM_MAPPER_STATUS: return widMapperStatus ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2); - case DRVM_MAPPER_RECONFIGURE: return widMapperReconfigure((WAVEMAPDATA*)dwUser, dwParam1, dwParam2); - /* known but not supported */ - case DRV_QUERYDEVICEINTERFACESIZE: - case DRV_QUERYDEVICEINTERFACE: - return MMSYSERR_NOTSUPPORTED; - default: - FIXME("unknown message %u!\n", wMsg); - } - return MMSYSERR_NOTSUPPORTED; -} - -/*======================================================================* - * Driver part * - *======================================================================*/ - -static struct WINE_WAVEMAP* oss = NULL; - -/************************************************************************** - * WAVEMAP_drvOpen [internal] - */ -static DWORD WAVEMAP_drvOpen(LPSTR str) -{ - TRACE("(%p)\n", str); - - if (oss) - return 0; - - /* I know, this is ugly, but who cares... */ - oss = (struct WINE_WAVEMAP*)1; - return 1; -} - -/************************************************************************** - * WAVEMAP_drvClose [internal] - */ -static DWORD WAVEMAP_drvClose(DWORD dwDevID) -{ - TRACE("(%08lx)\n", dwDevID); - - if (oss) { - oss = NULL; - return 1; - } - return 0; -} - -/************************************************************************** - * DriverProc (MSACM.@) - */ -LONG CALLBACK WAVEMAP_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, - DWORD dwParam1, DWORD dwParam2) -{ - TRACE("(%08lX, %p, %08lX, %08lX, %08lX)\n", - dwDevID, hDriv, wMsg, dwParam1, dwParam2); - - switch(wMsg) { - case DRV_LOAD: return 1; - case DRV_FREE: return 1; - case DRV_OPEN: return WAVEMAP_drvOpen((LPSTR)dwParam1); - case DRV_CLOSE: return WAVEMAP_drvClose(dwDevID); - case DRV_ENABLE: return 1; - case DRV_DISABLE: return 1; - case DRV_QUERYCONFIGURE: return 1; - case DRV_CONFIGURE: MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "Wave mapper Driver", MB_OK); return 1; - case DRV_INSTALL: return DRVCNF_RESTART; - case DRV_REMOVE: return DRVCNF_RESTART; - default: - return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2); - } -} +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ +/* + * Wine Wave mapper driver + * + * Copyright 1999,2001 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* TODOs + * + better protection against evilish dwUser parameters + * + use asynchronous ACM conversion + * + don't use callback functions when none is required in open + * + the buffer sizes may not be accurate, so there may be some + * remaining bytes in src and dst buffers after ACM conversions... + * those should be taken care of... + */ + +#include <stdarg.h> +#include <string.h> +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "mmddk.h" +#include "mmreg.h" +#include "msacm.h" +#include "wine/unicode.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wavemap); + +typedef struct tagWAVEMAPDATA { + struct tagWAVEMAPDATA* self; + union { + struct { + HWAVEOUT hOuterWave; + HWAVEOUT hInnerWave; + } out; + struct { + HWAVEIN hOuterWave; + HWAVEIN hInnerWave; + } in; + } u; + HACMSTREAM hAcmStream; + /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */ + DWORD dwCallback; + DWORD dwClientInstance; + DWORD dwFlags; + /* ratio to compute position from a PCM playback to any format */ + DWORD avgSpeedOuter; + DWORD avgSpeedInner; + /* channel size of inner and outer */ + DWORD nSamplesPerSecOuter; + DWORD nSamplesPerSecInner; +} WAVEMAPDATA; + +static BOOL WAVEMAP_IsData(WAVEMAPDATA* wm) +{ + return (!IsBadReadPtr(wm, sizeof(WAVEMAPDATA)) && wm->self == wm); +} + +/*======================================================================* + * WAVE OUT part * + *======================================================================*/ + +static void CALLBACK wodCallback(HWAVEOUT hWave, UINT uMsg, DWORD dwInstance, + DWORD dwParam1, DWORD dwParam2) +{ + WAVEMAPDATA* wom = (WAVEMAPDATA*)dwInstance; + + TRACE("(%p %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2); + + if (!WAVEMAP_IsData(wom)) { + ERR("Bad data\n"); + return; + } + + if (hWave != wom->u.out.hInnerWave && uMsg != WOM_OPEN) + ERR("Shouldn't happen (%p %p)\n", hWave, wom->u.out.hInnerWave); + + switch (uMsg) { + case WOM_OPEN: + case WOM_CLOSE: + /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ + break; + case WOM_DONE: + if (wom->hAcmStream) { + LPWAVEHDR lpWaveHdrDst = (LPWAVEHDR)dwParam1; + PACMSTREAMHEADER ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrDst - sizeof(ACMSTREAMHEADER)); + LPWAVEHDR lpWaveHdrSrc = (LPWAVEHDR)ash->dwUser; + + lpWaveHdrSrc->dwFlags &= ~WHDR_INQUEUE; + lpWaveHdrSrc->dwFlags |= WHDR_DONE; + dwParam1 = (DWORD)lpWaveHdrSrc; + } + break; + default: + ERR("Unknown msg %u\n", uMsg); + } + + DriverCallback(wom->dwCallback, HIWORD(wom->dwFlags), (HDRVR)wom->u.out.hOuterWave, + uMsg, wom->dwClientInstance, dwParam1, dwParam2); +} + +/****************************************************************** + * wodOpenHelper + * + * + */ +static DWORD wodOpenHelper(WAVEMAPDATA* wom, UINT idx, + LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx, + DWORD dwFlags) +{ + DWORD ret; + + TRACE("(%p %04x %p %p %08lx)\n", wom, idx, lpDesc, lpwfx, dwFlags); + + /* destination is always PCM, so the formulas below apply */ + lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8; + lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign; + if (dwFlags & WAVE_FORMAT_QUERY) { + ret = acmStreamOpen(NULL, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY); + } else { + ret = acmStreamOpen(&wom->hAcmStream, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, 0L); + } + if (ret == MMSYSERR_NOERROR) { + ret = waveOutOpen(&wom->u.out.hInnerWave, idx, lpwfx, (DWORD)wodCallback, + (DWORD)wom, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION); + if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) { + acmStreamClose(wom->hAcmStream, 0); + wom->hAcmStream = 0; + } + } + TRACE("ret = %08lx\n", ret); + return ret; +} + +static DWORD wodOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags) +{ + UINT ndlo, ndhi; + UINT i; + WAVEMAPDATA* wom = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA)); + DWORD res; + + TRACE("(%p %p %08lx)\n", lpdwUser, lpDesc, dwFlags); + + if (!wom) { + WARN("no memory\n"); + return MMSYSERR_NOMEM; + } + + ndhi = waveOutGetNumDevs(); + if (dwFlags & WAVE_MAPPED) { + if (lpDesc->uMappedDeviceID >= ndhi) { + WARN("invalid parameter: dwFlags WAVE_MAPPED\n"); + HeapFree(GetProcessHeap(), 0, wom); + return MMSYSERR_INVALPARAM; + } + ndlo = lpDesc->uMappedDeviceID; + ndhi = ndlo + 1; + dwFlags &= ~WAVE_MAPPED; + } else { + ndlo = 0; + } + wom->self = wom; + wom->dwCallback = lpDesc->dwCallback; + wom->dwFlags = dwFlags; + wom->dwClientInstance = lpDesc->dwInstance; + wom->u.out.hOuterWave = (HWAVEOUT)lpDesc->hWave; + wom->avgSpeedOuter = wom->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec; + wom->nSamplesPerSecOuter = wom->nSamplesPerSecInner = lpDesc->lpFormat->nSamplesPerSec; + + for (i = ndlo; i < ndhi; i++) { + /* if no ACM stuff is involved, no need to handle callbacks at this + * level, this will be done transparently + */ + if (waveOutOpen(&wom->u.out.hInnerWave, i, lpDesc->lpFormat, (DWORD)wodCallback, + (DWORD)wom, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) { + wom->hAcmStream = 0; + goto found; + } + } + + if ((dwFlags & WAVE_FORMAT_DIRECT) == 0 && lpDesc->lpFormat->wFormatTag == WAVE_FORMAT_PCM) { + WAVEFORMATEX wfx; + + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */ + /* try some ACM stuff */ + +#define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \ + switch (res=wodOpenHelper(wom, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \ + case MMSYSERR_NOERROR: wom->avgSpeedInner = wfx.nAvgBytesPerSec; wom->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \ + case WAVERR_BADFORMAT: break; \ + default: goto error; \ + } + + /* Our resampling algorithm is quite primitive so first try + * to just change the bit depth and number of channels + */ + for (i = ndlo; i < ndhi; i++) { + wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec; + wfx.nChannels = lpDesc->lpFormat->nChannels; + TRY(wfx.nSamplesPerSec, 16); + TRY(wfx.nSamplesPerSec, 8); + wfx.nChannels ^= 3; + TRY(wfx.nSamplesPerSec, 16); + TRY(wfx.nSamplesPerSec, 8); + } + + for (i = ndlo; i < ndhi; i++) { + /* first try with same stereo/mono option as source */ + wfx.nChannels = lpDesc->lpFormat->nChannels; + TRY(96000, 16); + TRY(48000, 16); + TRY(44100, 16); + TRY(22050, 16); + TRY(11025, 16); + + /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */ + wfx.nChannels ^= 3; + TRY(96000, 16); + TRY(48000, 16); + TRY(44100, 16); + TRY(22050, 16); + TRY(11025, 16); + + /* first try with same stereo/mono option as source */ + wfx.nChannels = lpDesc->lpFormat->nChannels; + TRY(96000, 8); + TRY(48000, 8); + TRY(44100, 8); + TRY(22050, 8); + TRY(11025, 8); + + /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */ + wfx.nChannels ^= 3; + TRY(96000, 8); + TRY(48000, 8); + TRY(44100, 8); + TRY(22050, 8); + TRY(11025, 8); + } +#undef TRY + } + + HeapFree(GetProcessHeap(), 0, wom); + WARN("ret = WAVERR_BADFORMAT\n"); + return WAVERR_BADFORMAT; + +found: + if (dwFlags & WAVE_FORMAT_QUERY) { + *lpdwUser = 0L; + HeapFree(GetProcessHeap(), 0, wom); + } else { + *lpdwUser = (DWORD)wom; + } + return MMSYSERR_NOERROR; +error: + HeapFree(GetProcessHeap(), 0, wom); + if (res==ACMERR_NOTPOSSIBLE) { + WARN("ret = WAVERR_BADFORMAT\n"); + return WAVERR_BADFORMAT; + } + WARN("ret = 0x%08lx\n", res); + return res; +} + +static DWORD wodClose(WAVEMAPDATA* wom) +{ + DWORD ret; + + TRACE("(%p)\n", wom); + + ret = waveOutClose(wom->u.out.hInnerWave); + if (ret == MMSYSERR_NOERROR) { + if (wom->hAcmStream) { + ret = acmStreamClose(wom->hAcmStream, 0); + } + if (ret == MMSYSERR_NOERROR) { + HeapFree(GetProcessHeap(), 0, wom); + } + } + return ret; +} + +static DWORD wodWrite(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2) +{ + PACMSTREAMHEADER ash; + LPWAVEHDR lpWaveHdrDst; + + TRACE("(%p %p %08lx)\n", wom, lpWaveHdrSrc, dwParam2); + + if (!wom->hAcmStream) { + return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2); + } + + lpWaveHdrSrc->dwFlags |= WHDR_INQUEUE; + ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved; + /* acmStreamConvert will actually check that the new size is less than initial size */ + ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength; + if (acmStreamConvert(wom->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) { + WARN("acmStreamConvert failed\n"); + return MMSYSERR_ERROR; + } + + lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); + if (ash->cbSrcLength > ash->cbSrcLengthUsed) + FIXME("Not all src buffer has been written, expect bogus sound\n"); + else if (ash->cbSrcLength < ash->cbSrcLengthUsed) + ERR("CoDec has read more data than it is allowed to\n"); + + if (ash->cbDstLengthUsed == 0) { + /* something went wrong in decoding */ + FIXME("Got 0 length\n"); + return MMSYSERR_ERROR; + } + lpWaveHdrDst->dwBufferLength = ash->cbDstLengthUsed; + return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst)); +} + +static DWORD wodPrepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2) +{ + PACMSTREAMHEADER ash; + DWORD size; + DWORD dwRet; + LPWAVEHDR lpWaveHdrDst; + + TRACE("(%p %p %08lx)\n", wom, lpWaveHdrSrc, dwParam2); + + if (!wom->hAcmStream) + return waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2); + + if (acmStreamSize(wom->hAcmStream, lpWaveHdrSrc->dwBufferLength, &size, ACM_STREAMSIZEF_SOURCE) != MMSYSERR_NOERROR) { + WARN("acmStreamSize failed\n"); + return MMSYSERR_ERROR; + } + + ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size); + if (ash == NULL) { + WARN("no memory\n"); + return MMSYSERR_NOMEM; + } + + ash->cbStruct = sizeof(*ash); + ash->fdwStatus = 0L; + ash->dwUser = (DWORD)lpWaveHdrSrc; + ash->pbSrc = lpWaveHdrSrc->lpData; + ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength; + /* ash->cbSrcLengthUsed */ + ash->dwSrcUser = lpWaveHdrSrc->dwUser; /* FIXME ? */ + ash->pbDst = (LPSTR)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR); + ash->cbDstLength = size; + /* ash->cbDstLengthUsed */ + ash->dwDstUser = 0; /* FIXME ? */ + dwRet = acmStreamPrepareHeader(wom->hAcmStream, ash, 0L); + if (dwRet != MMSYSERR_NOERROR) { + WARN("acmStreamPrepareHeader failed\n"); + goto errCleanUp; + } + + lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); + lpWaveHdrDst->lpData = ash->pbDst; + lpWaveHdrDst->dwBufferLength = size; /* conversion is not done yet */ + lpWaveHdrDst->dwFlags = 0; + lpWaveHdrDst->dwLoops = 0; + dwRet = waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst)); + if (dwRet != MMSYSERR_NOERROR) { + WARN("waveOutPrepareHeader failed\n"); + goto errCleanUp; + } + + lpWaveHdrSrc->reserved = (DWORD)ash; + lpWaveHdrSrc->dwFlags = WHDR_PREPARED; + TRACE("=> (0)\n"); + return MMSYSERR_NOERROR; +errCleanUp: + TRACE("=> (%ld)\n", dwRet); + HeapFree(GetProcessHeap(), 0, ash); + return dwRet; +} + +static DWORD wodUnprepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2) +{ + PACMSTREAMHEADER ash; + LPWAVEHDR lpWaveHdrDst; + DWORD dwRet1, dwRet2; + + TRACE("(%p %p %08lx)\n", wom, lpWaveHdrSrc, dwParam2); + + if (!wom->hAcmStream) { + return waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2); + } + ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved; + dwRet1 = acmStreamUnprepareHeader(wom->hAcmStream, ash, 0L); + + lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); + dwRet2 = waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst)); + + HeapFree(GetProcessHeap(), 0, ash); + + lpWaveHdrSrc->dwFlags &= ~WHDR_PREPARED; + return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1; +} + +static DWORD wodGetPosition(WAVEMAPDATA* wom, LPMMTIME lpTime, DWORD dwParam2) +{ + DWORD val; + MMTIME timepos; + TRACE("(%p %p %08lx)\n", wom, lpTime, dwParam2); + + memcpy(&timepos, lpTime, sizeof(timepos)); + + /* For TIME_MS, we're going to recalculate using TIME_BYTES */ + if (lpTime->wType == TIME_MS) + timepos.wType = TIME_BYTES; + + /* This can change timepos.wType if the requested type is not supported */ + val = waveOutGetPosition(wom->u.out.hInnerWave, &timepos, dwParam2); + + if (timepos.wType == TIME_BYTES) + { + DWORD dwInnerSamplesPerOuter = wom->nSamplesPerSecInner / wom->nSamplesPerSecOuter; + if (dwInnerSamplesPerOuter > 0) + { + DWORD dwInnerBytesPerSample = wom->avgSpeedInner / wom->nSamplesPerSecInner; + DWORD dwInnerBytesPerOuterSample = dwInnerBytesPerSample * dwInnerSamplesPerOuter; + DWORD remainder = 0; + + /* If we are up sampling (going from lower sample rate to higher), + ** we need to make a special accomodation for times when we've + ** written a partial output sample. This happens frequently + ** to us because we use msacm to do our up sampling, and it + ** will up sample on an unaligned basis. + ** For example, if you convert a 2 byte wide 8,000 'outer' + ** buffer to a 2 byte wide 48,000 inner device, you would + ** expect 2 bytes of input to produce 12 bytes of output. + ** Instead, msacm will produce 8 bytes of output. + ** But reporting our position as 1 byte of output is + ** nonsensical; the output buffer position needs to be + ** aligned on outer sample size, and aggressively rounded up. + */ + remainder = timepos.u.cb % dwInnerBytesPerOuterSample; + if (remainder > 0) + { + timepos.u.cb -= remainder; + timepos.u.cb += dwInnerBytesPerOuterSample; + } + } + + lpTime->u.cb = MulDiv(timepos.u.cb, wom->avgSpeedOuter, wom->avgSpeedInner); + + /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */ + if (lpTime->wType == TIME_MS) + lpTime->u.ms = MulDiv(lpTime->u.cb, 1000, wom->avgSpeedOuter); + else + lpTime->wType = TIME_BYTES; + } + else if (lpTime->wType == TIME_SAMPLES && timepos.wType == TIME_SAMPLES) + lpTime->u.sample = MulDiv(timepos.u.sample, wom->nSamplesPerSecOuter, wom->nSamplesPerSecInner); + else + /* other time types don't require conversion */ + lpTime->u = timepos.u; + + return val; +} + +static DWORD wodGetDevCaps(UINT wDevID, WAVEMAPDATA* wom, LPWAVEOUTCAPSW lpWaveCaps, DWORD dwParam2) +{ + static const WCHAR name[] = {'W','i','n','e',' ','w','a','v','e',' ','o','u','t',' ','m','a','p','p','e','r',0}; + + TRACE("(%04x %p %p %08lx)\n",wDevID, wom, lpWaveCaps, dwParam2); + + /* if opened low driver, forward message */ + if (WAVEMAP_IsData(wom)) + return waveOutGetDevCapsW((UINT)wom->u.out.hInnerWave, lpWaveCaps, dwParam2); + /* else if no drivers, nothing to map so return bad device */ + if (waveOutGetNumDevs() == 0) { + WARN("bad device id\n"); + return MMSYSERR_BADDEVICEID; + } + /* otherwise, return caps of mapper itself */ + if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) { + WAVEOUTCAPSW woc; + woc.wMid = 0x00FF; + woc.wPid = 0x0001; + woc.vDriverVersion = 0x0100; + lstrcpyW(woc.szPname, name); + woc.dwFormats = + WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 | + WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 | + WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 | + WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 | + WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16; + woc.wChannels = 2; + woc.dwSupport = WAVECAPS_VOLUME | WAVECAPS_LRVOLUME; + memcpy(lpWaveCaps, &woc, min(dwParam2, sizeof(woc))); + + return MMSYSERR_NOERROR; + } + ERR("This shouldn't happen\n"); + return MMSYSERR_ERROR; +} + +static DWORD wodGetVolume(UINT wDevID, WAVEMAPDATA* wom, LPDWORD lpVol) +{ + TRACE("(%04x %p %p)\n",wDevID, wom, lpVol); + + if (WAVEMAP_IsData(wom)) + return waveOutGetVolume(wom->u.out.hInnerWave, lpVol); + return MMSYSERR_NOERROR; +} + +static DWORD wodSetVolume(UINT wDevID, WAVEMAPDATA* wom, DWORD vol) +{ + TRACE("(%04x %p %08lx)\n",wDevID, wom, vol); + + if (WAVEMAP_IsData(wom)) + return waveOutSetVolume(wom->u.out.hInnerWave, vol); + return MMSYSERR_NOERROR; +} + +static DWORD wodPause(WAVEMAPDATA* wom) +{ + TRACE("(%p)\n",wom); + + return waveOutPause(wom->u.out.hInnerWave); +} + +static DWORD wodRestart(WAVEMAPDATA* wom) +{ + TRACE("(%p)\n",wom); + + return waveOutRestart(wom->u.out.hInnerWave); +} + +static DWORD wodReset(WAVEMAPDATA* wom) +{ + TRACE("(%p)\n",wom); + + return waveOutReset(wom->u.out.hInnerWave); +} + +static DWORD wodBreakLoop(WAVEMAPDATA* wom) +{ + TRACE("(%p)\n",wom); + + return waveOutBreakLoop(wom->u.out.hInnerWave); +} + +static DWORD wodMapperStatus(WAVEMAPDATA* wom, DWORD flags, LPVOID ptr) +{ + UINT id; + DWORD ret = MMSYSERR_NOTSUPPORTED; + + TRACE("(%p %08lx %p)\n",wom, flags, ptr); + + switch (flags) { + case WAVEOUT_MAPPER_STATUS_DEVICE: + ret = waveOutGetID(wom->u.out.hInnerWave, &id); + *(LPDWORD)ptr = id; + break; + case WAVEOUT_MAPPER_STATUS_MAPPED: + FIXME("Unsupported flag=%ld\n", flags); + *(LPDWORD)ptr = 0; /* FIXME ?? */ + break; + case WAVEOUT_MAPPER_STATUS_FORMAT: + FIXME("Unsupported flag=%ld\n", flags); + /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */ + *(LPDWORD)ptr = 0; + break; + default: + FIXME("Unsupported flag=%ld\n", flags); + *(LPDWORD)ptr = 0; + break; + } + return ret; +} + +static DWORD wodMapperReconfigure(WAVEMAPDATA* wom, DWORD dwParam1, DWORD dwParam2) +{ + FIXME("(%p %08lx %08lx) stub!\n", wom, dwParam1, dwParam2); + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * wodMessage (MSACM.@) + */ +DWORD WINAPI WAVEMAP_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser, + DWORD dwParam1, DWORD dwParam2) +{ + TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n", + wDevID, wMsg, dwUser, dwParam1, dwParam2); + + switch (wMsg) { + case DRVM_INIT: + case DRVM_EXIT: + case DRVM_ENABLE: + case DRVM_DISABLE: + /* FIXME: Pretend this is supported */ + return 0; + case WODM_OPEN: return wodOpen ((LPDWORD)dwUser, (LPWAVEOPENDESC)dwParam1,dwParam2); + case WODM_CLOSE: return wodClose ((WAVEMAPDATA*)dwUser); + case WODM_WRITE: return wodWrite ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); + case WODM_PAUSE: return wodPause ((WAVEMAPDATA*)dwUser); + case WODM_GETPOS: return wodGetPosition ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, dwParam2); + case WODM_BREAKLOOP: return wodBreakLoop ((WAVEMAPDATA*)dwUser); + case WODM_PREPARE: return wodPrepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); + case WODM_UNPREPARE: return wodUnprepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); + case WODM_GETDEVCAPS: return wodGetDevCaps (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEOUTCAPSW)dwParam1,dwParam2); + case WODM_GETNUMDEVS: return 1; + case WODM_GETPITCH: return MMSYSERR_NOTSUPPORTED; + case WODM_SETPITCH: return MMSYSERR_NOTSUPPORTED; + case WODM_GETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED; + case WODM_SETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED; + case WODM_GETVOLUME: return wodGetVolume (wDevID, (WAVEMAPDATA*)dwUser, (LPDWORD)dwParam1); + case WODM_SETVOLUME: return wodSetVolume (wDevID, (WAVEMAPDATA*)dwUser, dwParam1); + case WODM_RESTART: return wodRestart ((WAVEMAPDATA*)dwUser); + case WODM_RESET: return wodReset ((WAVEMAPDATA*)dwUser); + case WODM_MAPPER_STATUS: return wodMapperStatus ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2); + case DRVM_MAPPER_RECONFIGURE: return wodMapperReconfigure((WAVEMAPDATA*)dwUser, dwParam1, dwParam2); + /* known but not supported */ + case DRV_QUERYDEVICEINTERFACESIZE: + case DRV_QUERYDEVICEINTERFACE: + return MMSYSERR_NOTSUPPORTED; + default: + FIXME("unknown message %d!\n", wMsg); + } + return MMSYSERR_NOTSUPPORTED; +} + +/*======================================================================* + * WAVE IN part * + *======================================================================*/ + +static void CALLBACK widCallback(HWAVEIN hWave, UINT uMsg, DWORD dwInstance, + DWORD dwParam1, DWORD dwParam2) +{ + WAVEMAPDATA* wim = (WAVEMAPDATA*)dwInstance; + + TRACE("(%p %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2); + + if (!WAVEMAP_IsData(wim)) { + ERR("Bad data\n"); + return; + } + + if (hWave != wim->u.in.hInnerWave && uMsg != WIM_OPEN) + ERR("Shouldn't happen (%p %p)\n", hWave, wim->u.in.hInnerWave); + + switch (uMsg) { + case WIM_OPEN: + case WIM_CLOSE: + /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */ + break; + case WIM_DATA: + if (wim->hAcmStream) { + LPWAVEHDR lpWaveHdrSrc = (LPWAVEHDR)dwParam1; + PACMSTREAMHEADER ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrSrc - sizeof(ACMSTREAMHEADER)); + LPWAVEHDR lpWaveHdrDst = (LPWAVEHDR)ash->dwUser; + + /* convert data just gotten from waveIn into requested format */ + if (acmStreamConvert(wim->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) { + ERR("ACM conversion failed\n"); + return; + } else { + TRACE("Converted %ld bytes into %ld\n", ash->cbSrcLengthUsed, ash->cbDstLengthUsed); + } + /* and setup the wavehdr to return accordingly */ + lpWaveHdrDst->dwFlags &= ~WHDR_INQUEUE; + lpWaveHdrDst->dwFlags |= WHDR_DONE; + lpWaveHdrDst->dwBytesRecorded = ash->cbDstLengthUsed; + dwParam1 = (DWORD)lpWaveHdrDst; + } + break; + default: + ERR("Unknown msg %u\n", uMsg); + } + + DriverCallback(wim->dwCallback, HIWORD(wim->dwFlags), (HDRVR)wim->u.in.hOuterWave, + uMsg, wim->dwClientInstance, dwParam1, dwParam2); +} + +static DWORD widOpenHelper(WAVEMAPDATA* wim, UINT idx, + LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx, + DWORD dwFlags) +{ + DWORD ret; + + TRACE("(%p %04x %p %p %08lx)\n", wim, idx, lpDesc, lpwfx, dwFlags); + + /* source is always PCM, so the formulas below apply */ + lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8; + lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign; + if (dwFlags & WAVE_FORMAT_QUERY) { + ret = acmStreamOpen(NULL, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY); + } else { + ret = acmStreamOpen(&wim->hAcmStream, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, 0L); + } + if (ret == MMSYSERR_NOERROR) { + ret = waveInOpen(&wim->u.in.hInnerWave, idx, lpwfx, (DWORD)widCallback, + (DWORD)wim, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION); + if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) { + acmStreamClose(wim->hAcmStream, 0); + wim->hAcmStream = 0; + } + } + TRACE("ret = %08lx\n", ret); + return ret; +} + +static DWORD widOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags) +{ + UINT ndlo, ndhi; + UINT i; + WAVEMAPDATA* wim = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA)); + DWORD res; + + TRACE("(%p %p %08lx)\n", lpdwUser, lpDesc, dwFlags); + + if (!wim) { + WARN("no memory\n"); + return MMSYSERR_NOMEM; + } + + wim->self = wim; + wim->dwCallback = lpDesc->dwCallback; + wim->dwFlags = dwFlags; + wim->dwClientInstance = lpDesc->dwInstance; + wim->u.in.hOuterWave = (HWAVEIN)lpDesc->hWave; + + ndhi = waveInGetNumDevs(); + if (dwFlags & WAVE_MAPPED) { + if (lpDesc->uMappedDeviceID >= ndhi) return MMSYSERR_INVALPARAM; + ndlo = lpDesc->uMappedDeviceID; + ndhi = ndlo + 1; + dwFlags &= ~WAVE_MAPPED; + } else { + ndlo = 0; + } + + wim->avgSpeedOuter = wim->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec; + wim->nSamplesPerSecOuter = wim->nSamplesPerSecInner = lpDesc->lpFormat->nSamplesPerSec; + + for (i = ndlo; i < ndhi; i++) { + if (waveInOpen(&wim->u.in.hInnerWave, i, lpDesc->lpFormat, (DWORD)widCallback, + (DWORD)wim, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) { + wim->hAcmStream = 0; + goto found; + } + } + + if ((dwFlags & WAVE_FORMAT_DIRECT) == 0) + { + WAVEFORMATEX wfx; + + wfx.wFormatTag = WAVE_FORMAT_PCM; + wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */ + /* try some ACM stuff */ + +#define TRY(sps,bps) wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \ + switch (res=widOpenHelper(wim, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \ + case MMSYSERR_NOERROR: wim->avgSpeedInner = wfx.nAvgBytesPerSec; wim->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \ + case WAVERR_BADFORMAT: break; \ + default: goto error; \ + } + + for (i = ndlo; i < ndhi; i++) { + wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec; + /* first try with same stereo/mono option as source */ + wfx.nChannels = lpDesc->lpFormat->nChannels; + TRY(wfx.nSamplesPerSec, 16); + TRY(wfx.nSamplesPerSec, 8); + wfx.nChannels ^= 3; + TRY(wfx.nSamplesPerSec, 16); + TRY(wfx.nSamplesPerSec, 8); + } + + for (i = ndlo; i < ndhi; i++) { + wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec; + /* first try with same stereo/mono option as source */ + wfx.nChannels = lpDesc->lpFormat->nChannels; + TRY(96000, 16); + TRY(48000, 16); + TRY(44100, 16); + TRY(22050, 16); + TRY(11025, 16); + + /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */ + wfx.nChannels ^= 3; + TRY(96000, 16); + TRY(48000, 16); + TRY(44100, 16); + TRY(22050, 16); + TRY(11025, 16); + + /* first try with same stereo/mono option as source */ + wfx.nChannels = lpDesc->lpFormat->nChannels; + TRY(96000, 8); + TRY(48000, 8); + TRY(44100, 8); + TRY(22050, 8); + TRY(11025, 8); + + /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */ + wfx.nChannels ^= 3; + TRY(96000, 8); + TRY(48000, 8); + TRY(44100, 8); + TRY(22050, 8); + TRY(11025, 8); + } +#undef TRY + } + + HeapFree(GetProcessHeap(), 0, wim); + WARN("ret = WAVERR_BADFORMAT\n"); + return WAVERR_BADFORMAT; +found: + if (dwFlags & WAVE_FORMAT_QUERY) { + *lpdwUser = 0L; + HeapFree(GetProcessHeap(), 0, wim); + } else { + *lpdwUser = (DWORD)wim; + } + TRACE("Ok (stream=%08lx)\n", (DWORD)wim->hAcmStream); + return MMSYSERR_NOERROR; +error: + HeapFree(GetProcessHeap(), 0, wim); + if (res==ACMERR_NOTPOSSIBLE) { + WARN("ret = WAVERR_BADFORMAT\n"); + return WAVERR_BADFORMAT; + } + WARN("ret = 0x%08lx\n", res); + return res; +} + +static DWORD widClose(WAVEMAPDATA* wim) +{ + DWORD ret; + + TRACE("(%p)\n", wim); + + ret = waveInClose(wim->u.in.hInnerWave); + if (ret == MMSYSERR_NOERROR) { + if (wim->hAcmStream) { + ret = acmStreamClose(wim->hAcmStream, 0); + } + if (ret == MMSYSERR_NOERROR) { + HeapFree(GetProcessHeap(), 0, wim); + } + } + return ret; +} + +static DWORD widAddBuffer(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2) +{ + PACMSTREAMHEADER ash; + LPWAVEHDR lpWaveHdrSrc; + + TRACE("(%p %p %08lx)\n", wim, lpWaveHdrDst, dwParam2); + + if (!wim->hAcmStream) { + return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2); + } + + lpWaveHdrDst->dwFlags |= WHDR_INQUEUE; + ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved; + + lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); + return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc)); +} + +static DWORD widPrepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2) +{ + PACMSTREAMHEADER ash; + DWORD size; + DWORD dwRet; + LPWAVEHDR lpWaveHdrSrc; + + TRACE("(%p %p %08lx)\n", wim, lpWaveHdrDst, dwParam2); + + if (!wim->hAcmStream) { + return waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2); + } + if (acmStreamSize(wim->hAcmStream, lpWaveHdrDst->dwBufferLength, &size, + ACM_STREAMSIZEF_DESTINATION) != MMSYSERR_NOERROR) { + WARN("acmStreamSize failed\n"); + return MMSYSERR_ERROR; + } + + ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size); + if (ash == NULL) { + WARN("no memory\n"); + return MMSYSERR_NOMEM; + } + + ash->cbStruct = sizeof(*ash); + ash->fdwStatus = 0L; + ash->dwUser = (DWORD)lpWaveHdrDst; + ash->pbSrc = (LPSTR)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR); + ash->cbSrcLength = size; + /* ash->cbSrcLengthUsed */ + ash->dwSrcUser = 0L; /* FIXME ? */ + ash->pbDst = lpWaveHdrDst->lpData; + ash->cbDstLength = lpWaveHdrDst->dwBufferLength; + /* ash->cbDstLengthUsed */ + ash->dwDstUser = lpWaveHdrDst->dwUser; /* FIXME ? */ + dwRet = acmStreamPrepareHeader(wim->hAcmStream, ash, 0L); + if (dwRet != MMSYSERR_NOERROR) { + WARN("acmStreamPrepareHeader failed\n"); + goto errCleanUp; + } + + lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); + lpWaveHdrSrc->lpData = ash->pbSrc; + lpWaveHdrSrc->dwBufferLength = size; /* conversion is not done yet */ + lpWaveHdrSrc->dwFlags = 0; + lpWaveHdrSrc->dwLoops = 0; + dwRet = waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc)); + if (dwRet != MMSYSERR_NOERROR) { + WARN("waveInPrepareHeader failed\n"); + goto errCleanUp; + } + + lpWaveHdrDst->reserved = (DWORD)ash; + lpWaveHdrDst->dwFlags = WHDR_PREPARED; + TRACE("=> (0)\n"); + return MMSYSERR_NOERROR; +errCleanUp: + TRACE("=> (%ld)\n", dwRet); + HeapFree(GetProcessHeap(), 0, ash); + return dwRet; +} + +static DWORD widUnprepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2) +{ + PACMSTREAMHEADER ash; + LPWAVEHDR lpWaveHdrSrc; + DWORD dwRet1, dwRet2; + + TRACE("(%p %p %08lx)\n", wim, lpWaveHdrDst, dwParam2); + + if (!wim->hAcmStream) { + return waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2); + } + ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved; + dwRet1 = acmStreamUnprepareHeader(wim->hAcmStream, ash, 0L); + + lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER)); + dwRet2 = waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc)); + + HeapFree(GetProcessHeap(), 0, ash); + + lpWaveHdrDst->dwFlags &= ~WHDR_PREPARED; + return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1; +} + +static DWORD widGetPosition(WAVEMAPDATA* wim, LPMMTIME lpTime, DWORD dwParam2) +{ + DWORD val; + MMTIME timepos; + TRACE("(%p %p %08lx)\n", wim, lpTime, dwParam2); + + memcpy(&timepos, lpTime, sizeof(timepos)); + + /* For TIME_MS, we're going to recalculate using TIME_BYTES */ + if (lpTime->wType == TIME_MS) + timepos.wType = TIME_BYTES; + + /* This can change timepos.wType if the requested type is not supported */ + val = waveInGetPosition(wim->u.in.hInnerWave, &timepos, dwParam2); + + if (timepos.wType == TIME_BYTES) + { + DWORD dwInnerSamplesPerOuter = wim->nSamplesPerSecInner / wim->nSamplesPerSecOuter; + if (dwInnerSamplesPerOuter > 0) + { + DWORD dwInnerBytesPerSample = wim->avgSpeedInner / wim->nSamplesPerSecInner; + DWORD dwInnerBytesPerOuterSample = dwInnerBytesPerSample * dwInnerSamplesPerOuter; + DWORD remainder = 0; + + /* If we are up sampling (going from lower sample rate to higher), + ** we need to make a special accomodation for times when we've + ** written a partial output sample. This happens frequently + ** to us because we use msacm to do our up sampling, and it + ** will up sample on an unaligned basis. + ** For example, if you convert a 2 byte wide 8,000 'outer' + ** buffer to a 2 byte wide 48,000 inner device, you would + ** expect 2 bytes of input to produce 12 bytes of output. + ** Instead, msacm will produce 8 bytes of output. + ** But reporting our position as 1 byte of output is + ** nonsensical; the output buffer position needs to be + ** aligned on outer sample size, and aggressively rounded up. + */ + remainder = timepos.u.cb % dwInnerBytesPerOuterSample; + if (remainder > 0) + { + timepos.u.cb -= remainder; + timepos.u.cb += dwInnerBytesPerOuterSample; + } + } + + lpTime->u.cb = MulDiv(timepos.u.cb, wim->avgSpeedOuter, wim->avgSpeedInner); + + /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */ + if (lpTime->wType == TIME_MS) + lpTime->u.ms = MulDiv(lpTime->u.cb, 1000, wim->avgSpeedOuter); + else + lpTime->wType = TIME_BYTES; + } + else if (lpTime->wType == TIME_SAMPLES && timepos.wType == TIME_SAMPLES) + lpTime->u.sample = MulDiv(timepos.u.sample, wim->nSamplesPerSecOuter, wim->nSamplesPerSecInner); + else + /* other time types don't require conversion */ + lpTime->u = timepos.u; + + return val; +} + +static DWORD widGetDevCaps(UINT wDevID, WAVEMAPDATA* wim, LPWAVEINCAPSW lpWaveCaps, DWORD dwParam2) +{ + TRACE("(%04x, %p %p %08lx)\n", wDevID, wim, lpWaveCaps, dwParam2); + + /* if opened low driver, forward message */ + if (WAVEMAP_IsData(wim)) + return waveInGetDevCapsW((UINT)wim->u.in.hInnerWave, lpWaveCaps, dwParam2); + /* else if no drivers, nothing to map so return bad device */ + if (waveInGetNumDevs() == 0) { + WARN("bad device id\n"); + return MMSYSERR_BADDEVICEID; + } + /* otherwise, return caps of mapper itself */ + if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) { + WAVEINCAPSW wic; + static const WCHAR init[] = {'W','i','n','e',' ','w','a','v','e',' ','i','n',' ','m','a','p','p','e','r',0}; + wic.wMid = 0x00FF; + wic.wPid = 0x0001; + wic.vDriverVersion = 0x0001; + strcpyW(wic.szPname, init); + wic.dwFormats = + WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 | + WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 | + WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 | + WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 | + WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16; + wic.wChannels = 2; + memcpy(lpWaveCaps, &wic, min(dwParam2, sizeof(wic))); + + return MMSYSERR_NOERROR; + } + ERR("This shouldn't happen\n"); + return MMSYSERR_ERROR; +} + +static DWORD widStop(WAVEMAPDATA* wim) +{ + TRACE("(%p)\n", wim); + + return waveInStop(wim->u.in.hInnerWave); +} + +static DWORD widStart(WAVEMAPDATA* wim) +{ + TRACE("(%p)\n", wim); + + return waveInStart(wim->u.in.hInnerWave); +} + +static DWORD widReset(WAVEMAPDATA* wim) +{ + TRACE("(%p)\n", wim); + + return waveInReset(wim->u.in.hInnerWave); +} + +static DWORD widMapperStatus(WAVEMAPDATA* wim, DWORD flags, LPVOID ptr) +{ + UINT id; + DWORD ret = MMSYSERR_NOTSUPPORTED; + + TRACE("(%p %08lx %p)\n", wim, flags, ptr); + + switch (flags) { + case WAVEIN_MAPPER_STATUS_DEVICE: + ret = waveInGetID(wim->u.in.hInnerWave, &id); + *(LPDWORD)ptr = id; + break; + case WAVEIN_MAPPER_STATUS_MAPPED: + FIXME("Unsupported yet flag=%ld\n", flags); + *(LPDWORD)ptr = 0; /* FIXME ?? */ + break; + case WAVEIN_MAPPER_STATUS_FORMAT: + FIXME("Unsupported flag=%ld\n", flags); + /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */ + *(LPDWORD)ptr = 0; /* FIXME ?? */ + break; + default: + FIXME("Unsupported flag=%ld\n", flags); + *(LPDWORD)ptr = 0; + break; + } + return ret; +} + +static DWORD widMapperReconfigure(WAVEMAPDATA* wim, DWORD dwParam1, DWORD dwParam2) +{ + FIXME("(%p %08lx %08lx) stub!\n", wim, dwParam1, dwParam2); + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * widMessage (MSACM.@) + */ +DWORD WINAPI WAVEMAP_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser, + DWORD dwParam1, DWORD dwParam2) +{ + TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n", + wDevID, wMsg, dwUser, dwParam1, dwParam2); + + switch (wMsg) { + case DRVM_INIT: + case DRVM_EXIT: + case DRVM_ENABLE: + case DRVM_DISABLE: + /* FIXME: Pretend this is supported */ + return 0; + + case WIDM_OPEN: return widOpen ((LPDWORD)dwUser, (LPWAVEOPENDESC)dwParam1, dwParam2); + case WIDM_CLOSE: return widClose ((WAVEMAPDATA*)dwUser); + + case WIDM_ADDBUFFER: return widAddBuffer ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); + case WIDM_PREPARE: return widPrepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); + case WIDM_UNPREPARE: return widUnprepare ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1, dwParam2); + case WIDM_GETDEVCAPS: return widGetDevCaps (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEINCAPSW)dwParam1, dwParam2); + case WIDM_GETNUMDEVS: return 1; + case WIDM_GETPOS: return widGetPosition ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1, dwParam2); + case WIDM_RESET: return widReset ((WAVEMAPDATA*)dwUser); + case WIDM_START: return widStart ((WAVEMAPDATA*)dwUser); + case WIDM_STOP: return widStop ((WAVEMAPDATA*)dwUser); + case WIDM_MAPPER_STATUS: return widMapperStatus ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2); + case DRVM_MAPPER_RECONFIGURE: return widMapperReconfigure((WAVEMAPDATA*)dwUser, dwParam1, dwParam2); + /* known but not supported */ + case DRV_QUERYDEVICEINTERFACESIZE: + case DRV_QUERYDEVICEINTERFACE: + return MMSYSERR_NOTSUPPORTED; + default: + FIXME("unknown message %u!\n", wMsg); + } + return MMSYSERR_NOTSUPPORTED; +} + +/*======================================================================* + * Driver part * + *======================================================================*/ + +static struct WINE_WAVEMAP* oss = NULL; + +/************************************************************************** + * WAVEMAP_drvOpen [internal] + */ +static DWORD WAVEMAP_drvOpen(LPSTR str) +{ + TRACE("(%p)\n", str); + + if (oss) + return 0; + + /* I know, this is ugly, but who cares... */ + oss = (struct WINE_WAVEMAP*)1; + return 1; +} + +/************************************************************************** + * WAVEMAP_drvClose [internal] + */ +static DWORD WAVEMAP_drvClose(DWORD dwDevID) +{ + TRACE("(%08lx)\n", dwDevID); + + if (oss) { + oss = NULL; + return 1; + } + return 0; +} + +/************************************************************************** + * DriverProc (MSACM.@) + */ +LONG CALLBACK WAVEMAP_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, + DWORD dwParam1, DWORD dwParam2) +{ + TRACE("(%08lX, %p, %08lX, %08lX, %08lX)\n", + dwDevID, hDriv, wMsg, dwParam1, dwParam2); + + switch(wMsg) { + case DRV_LOAD: return 1; + case DRV_FREE: return 1; + case DRV_OPEN: return WAVEMAP_drvOpen((LPSTR)dwParam1); + case DRV_CLOSE: return WAVEMAP_drvClose(dwDevID); + case DRV_ENABLE: return 1; + case DRV_DISABLE: return 1; + case DRV_QUERYCONFIGURE: return 1; + case DRV_CONFIGURE: MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "Wave mapper Driver", MB_OK); return 1; + case DRV_INSTALL: return DRVCNF_RESTART; + case DRV_REMOVE: return DRVCNF_RESTART; + default: + return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2); + } +} diff --git a/reactos/lib/winmm/winemm.h b/reactos/lib/winmm/winemm.h index 237307c9018..b370ab3a12d 100644 --- a/reactos/lib/winmm/winemm.h +++ b/reactos/lib/winmm/winemm.h @@ -1,317 +1,317 @@ -/* -*- tab-width: 8; c-basic-offset: 4 -*- */ - -/***************************************************************************** - * Copyright 1998, Luiz Otavio L. Zorzella - * 1999, Eric Pouech - * - * Purpose: multimedia declarations (internal to WINMM & MMSYSTEM DLLs) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - ***************************************************************************** - */ - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "mmddk.h" - -#define WINE_DEFAULT_WINMM_DRIVER "wineoss.drv" -#define WINE_DEFAULT_WINMM_MAPPER "msacm.drv" -#define WINE_DEFAULT_WINMM_MIDI "midimap.drv" - -typedef DWORD (WINAPI *MessageProc16)(UINT16 wDevID, UINT16 wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2); -typedef DWORD (WINAPI *MessageProc32)(UINT wDevID, UINT wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2); - -typedef enum { - WINMM_MAP_NOMEM, /* ko, memory problem */ - WINMM_MAP_MSGERROR, /* ko, unknown message */ - WINMM_MAP_OK, /* ok, no memory allocated. to be sent to the proc. */ - WINMM_MAP_OKMEM, /* ok, some memory allocated, need to call UnMapMsg. to be sent to the proc. */ -} WINMM_MapType; - -/* Who said goofy boy ? */ -#define WINE_DI_MAGIC 0x900F1B01 - -typedef struct tagWINE_DRIVER -{ - DWORD dwMagic; - /* as usual LPWINE_DRIVER == hDriver32 */ - DWORD dwFlags; - union { - struct { - HMODULE hModule; - DRIVERPROC lpDrvProc; - DWORD dwDriverID; - } d32; - struct { - UINT16 hDriver16; - } d16; - } d; - struct tagWINE_DRIVER* lpPrevItem; - struct tagWINE_DRIVER* lpNextItem; -} WINE_DRIVER, *LPWINE_DRIVER; - -typedef DWORD (CALLBACK *WINEMM_msgFunc16)(UINT16, WORD, DWORD, DWORD, DWORD); -typedef DWORD (CALLBACK *WINEMM_msgFunc32)(UINT , UINT, DWORD, DWORD, DWORD); - -/* for each loaded driver and each known type of driver, this structure contains - * the information needed to access it - */ -typedef struct tagWINE_MM_DRIVER_PART { - int nIDMin; /* lower bound of global indexes for this type */ - int nIDMax; /* hhigher bound of global indexes for this type */ - union { - WINEMM_msgFunc32 fnMessage32; /* pointer to function */ - WINEMM_msgFunc16 fnMessage16; - } u; -} WINE_MM_DRIVER_PART; - -#define MMDRV_AUX 0 -#define MMDRV_MIXER 1 -#define MMDRV_MIDIIN 2 -#define MMDRV_MIDIOUT 3 -#define MMDRV_WAVEIN 4 -#define MMDRV_WAVEOUT 5 -#define MMDRV_MAX 6 - -/* each low-level .drv will be associated with an instance of this structure */ -typedef struct tagWINE_MM_DRIVER { - HDRVR hDriver; - LPSTR drvname; /* name of the driver */ - unsigned bIs32 : 1, /* TRUE if 32 bit driver, FALSE for 16 */ - bIsMapper : 1; /* TRUE if mapper */ - WINE_MM_DRIVER_PART parts[MMDRV_MAX];/* Information for all known types */ -} WINE_MM_DRIVER, *LPWINE_MM_DRIVER; - -typedef struct tagWINE_MLD { -/* EPP struct tagWINE_MLD* lpNext; */ /* not used so far */ - UINT uDeviceID; - UINT type; - UINT mmdIndex; /* index to low-level driver in MMDrvs table */ - DWORD dwDriverInstance; /* this value is driver related, as opposed to - * opendesc.dwInstance which is client (callback) related */ - WORD bFrom32; - WORD dwFlags; - DWORD dwCallback; - DWORD dwClientInstance; -} WINE_MLD, *LPWINE_MLD; - -typedef struct { - WINE_MLD mld; -} WINE_WAVE, *LPWINE_WAVE; - -typedef struct { - WINE_MLD mld; - MIDIOPENDESC mod; /* FIXME: should be removed */ -} WINE_MIDI, *LPWINE_MIDI; - -typedef struct { - WINE_MLD mld; -} WINE_MIXER, *LPWINE_MIXER; - -#define WINE_MMTHREAD_CREATED 0x4153494C /* "BSIL" */ -#define WINE_MMTHREAD_DELETED 0xDEADDEAD - -typedef struct { - DWORD dwSignature; /* 00 "BSIL" when ok, 0xDEADDEAD when being deleted */ - DWORD dwCounter; /* 04 > 1 when in mmThread functions */ - HANDLE hThread; /* 08 hThread */ - DWORD dwThreadID; /* 0C */ - DWORD fpThread; /* 10 address of thread proc (segptr or lin depending on dwFlags) */ - DWORD dwThreadPmt; /* 14 parameter to be passed upon thread creation to fpThread */ - DWORD dwSignalCount; /* 18 counter used for signaling */ - HANDLE hEvent; /* 1C event */ - HANDLE hVxD; /* 20 return from OpenVxDHandle */ - DWORD dwStatus; /* 24 0x00, 0x10, 0x20, 0x30 */ - DWORD dwFlags; /* 28 dwFlags upon creation */ - UINT16 hTask; /* 2C handle to created task */ -} WINE_MMTHREAD; - -typedef struct tagWINE_MCIDRIVER { - UINT wDeviceID; - UINT wType; - LPWSTR lpstrElementName; - LPWSTR lpstrDeviceType; - LPWSTR lpstrAlias; - HDRVR hDriver; - DWORD dwPrivate; - YIELDPROC lpfnYieldProc; - DWORD dwYieldData; - BOOL bIs32; - DWORD CreatorThread; - UINT uTypeCmdTable; - UINT uSpecificCmdTable; - struct tagWINE_MCIDRIVER*lpNext; -} WINE_MCIDRIVER, *LPWINE_MCIDRIVER; - -#define WINE_TIMER_IS32 0x80 - -typedef struct tagWINE_TIMERENTRY { - UINT wDelay; - UINT wResol; - LPTIMECALLBACK lpFunc; /* can be lots of things */ - DWORD dwUser; - UINT16 wFlags; - UINT16 wTimerID; - DWORD dwTriggerTime; - struct tagWINE_TIMERENTRY* lpNext; -} WINE_TIMERENTRY, *LPWINE_TIMERENTRY; - -enum mmioProcType {MMIO_PROC_16,MMIO_PROC_32A,MMIO_PROC_32W}; - -struct IOProcList -{ - struct IOProcList*pNext; /* Next item in linked list */ - FOURCC fourCC; /* four-character code identifying IOProc */ - LPMMIOPROC pIOProc; /* pointer to IProc */ - enum mmioProcType type; /* 16, 32A or 32W */ - int count; /* number of objects linked to it */ -}; - -typedef struct tagWINE_MMIO { - MMIOINFO info; - struct tagWINE_MMIO* lpNext; - struct IOProcList* ioProc; - unsigned bTmpIOProc : 1, - bBufferLoaded : 1; - DWORD segBuffer16; - DWORD dwFileSize; -} WINE_MMIO, *LPWINE_MMIO; - -typedef struct tagWINE_PLAYSOUND { - unsigned bLoop : 1, - bAlloc : 1; - LPCWSTR pszSound; - HMODULE hMod; - DWORD fdwSound; - HANDLE hThread; - struct tagWINE_PLAYSOUND* lpNext; -} WINE_PLAYSOUND, *LPWINE_PLAYSOUND; - -typedef struct tagWINE_MM_IDATA { - /* winmm part */ - HANDLE hWinMM32Instance; - HANDLE hWinMM16Instance; - CRITICAL_SECTION cs; - /* mci part */ - LPWINE_MCIDRIVER lpMciDrvs; - /* low level drivers (unused yet) */ - /* LPWINE_WAVE lpWave; */ - /* LPWINE_MIDI lpMidi; */ - /* LPWINE_MIXER lpMixer; */ - /* mmio part */ - LPWINE_MMIO lpMMIO; - /* playsound and sndPlaySound */ - WINE_PLAYSOUND* lpPlaySound; - HANDLE psLastEvent; - HANDLE psStopEvent; -} WINE_MM_IDATA, *LPWINE_MM_IDATA; - -/* function prototypes */ - -typedef LONG (*MCIPROC)(DWORD, HDRVR, DWORD, DWORD, DWORD); -typedef WINMM_MapType (*MMDRV_MAPFUNC)(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2); -typedef WINMM_MapType (*MMDRV_UNMAPFUNC)(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT ret); - -HDRVR WINAPI OpenDriverA(LPCSTR lpDriverName, LPCSTR lpSectionName, LPARAM lParam2); -LPWINE_DRIVER DRIVER_FindFromHDrvr(HDRVR hDrvr); -BOOL DRIVER_GetLibName(LPCWSTR keyName, LPCWSTR sectName, LPWSTR buf, int sz); -LPWINE_DRIVER DRIVER_TryOpenDriver32(LPCWSTR fn, LPARAM lParam2); -void DRIVER_UnloadAll(void); - -BOOL MMDRV_Init(void); -void MMDRV_Exit(void); -UINT MMDRV_GetNum(UINT); -LPWINE_MLD MMDRV_Alloc(UINT size, UINT type, LPHANDLE hndl, DWORD* dwFlags, - DWORD* dwCallback, DWORD* dwInstance, BOOL bFrom32); -void MMDRV_Free(HANDLE hndl, LPWINE_MLD mld); -DWORD MMDRV_Open(LPWINE_MLD mld, UINT wMsg, DWORD dwParam1, DWORD dwParam2); -DWORD MMDRV_Close(LPWINE_MLD mld, UINT wMsg); -LPWINE_MLD MMDRV_Get(HANDLE hndl, UINT type, BOOL bCanBeID); -LPWINE_MLD MMDRV_GetRelated(HANDLE hndl, UINT srcType, BOOL bSrcCanBeID, UINT dstTyped); -DWORD MMDRV_Message(LPWINE_MLD mld, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2, BOOL bFrom32); -UINT MMDRV_PhysicalFeatures(LPWINE_MLD mld, UINT uMsg, DWORD dwParam1, DWORD dwParam2); -BOOL MMDRV_Is32(unsigned int); -void MMDRV_InstallMap(unsigned int, MMDRV_MAPFUNC, MMDRV_UNMAPFUNC, - MMDRV_MAPFUNC, MMDRV_UNMAPFUNC, LPDRVCALLBACK); - -WINE_MCIDRIVER* MCI_GetDriver(UINT16 uDevID); -UINT MCI_GetDriverFromString(LPCWSTR str); -DWORD MCI_WriteString(LPWSTR lpDstStr, DWORD dstSize, LPCWSTR lpSrcStr); -const char* MCI_MessageToString(UINT wMsg); -UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data); -LRESULT MCI_CleanUp(LRESULT dwRet, UINT wMsg, DWORD dwParam2); -DWORD MCI_SendCommand(UINT wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2, BOOL bFrom32); -DWORD MCI_SendCommandFrom32(UINT wDevID, UINT16 wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2); -DWORD MCI_SendCommandFrom16(UINT wDevID, UINT16 wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2); -UINT MCI_SetCommandTable(void *table, UINT uDevType); -BOOL MCI_DeleteCommandTable(UINT uTbl, BOOL delete); -LPWSTR MCI_strdupAtoW(LPCSTR str); -LPSTR MCI_strdupWtoA(LPCWSTR str); - -BOOL WINMM_CheckForMMSystem(void); -const char* WINMM_ErrorToString(MMRESULT error); - -UINT MIXER_Open(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback, - DWORD_PTR dwInstance, DWORD fdwOpen, BOOL bFrom32); -UINT MIDI_OutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID, DWORD_PTR dwCallback, - DWORD_PTR dwInstance, DWORD dwFlags, BOOL bFrom32); -UINT MIDI_InOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD_PTR dwCallback, - DWORD_PTR dwInstance, DWORD dwFlags, BOOL bFrom32); -MMRESULT MIDI_StreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, - DWORD cMidi, DWORD_PTR dwCallback, - DWORD_PTR dwInstance, DWORD fdwOpen, BOOL bFrom32); -UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType, - LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, - DWORD_PTR dwInstance, DWORD dwFlags, BOOL bFrom32); - -HMMIO MMIO_Open(LPSTR szFileName, MMIOINFO* refmminfo, - DWORD dwOpenFlags, enum mmioProcType type); -LPMMIOPROC MMIO_InstallIOProc(FOURCC fccIOProc, LPMMIOPROC pIOProc, - DWORD dwFlags, enum mmioProcType type); -LRESULT MMIO_SendMessage(HMMIO hmmio, UINT uMessage, LPARAM lParam1, - LPARAM lParam2, enum mmioProcType type); -LPWINE_MMIO MMIO_Get(HMMIO h); - -WORD TIME_SetEventInternal(UINT wDelay, UINT wResol, LPTIMECALLBACK lpFunc, - DWORD dwUser, UINT wFlags); -void TIME_MMTimeStart(void); -void TIME_MMTimeStop(void); - -/* Global variables */ -extern WINE_MM_IDATA WINMM_IData; - -/* pointers to 16 bit functions (if sibling MMSYSTEM.DLL is loaded - * NULL otherwise - */ -extern WINE_MMTHREAD* (*pFnGetMMThread16)(UINT16); -extern LPWINE_DRIVER (*pFnOpenDriver16)(LPCWSTR,LPCWSTR,LPARAM); -extern LRESULT (*pFnCloseDriver16)(UINT16,LPARAM,LPARAM); -extern LRESULT (*pFnSendMessage16)(UINT16,UINT,LPARAM,LPARAM); -extern WINMM_MapType (*pFnMciMapMsg16To32W)(WORD,WORD,DWORD*); -extern WINMM_MapType (*pFnMciUnMapMsg16To32W)(WORD,WORD,DWORD); -extern WINMM_MapType (*pFnMciMapMsg32WTo16)(WORD,WORD,DWORD,DWORD*); -extern WINMM_MapType (*pFnMciUnMapMsg32WTo16)(WORD,WORD,DWORD,DWORD); -extern LRESULT (*pFnCallMMDrvFunc16)(DWORD /* in fact FARPROC16 */,WORD,WORD,LONG,LONG,LONG); -extern unsigned (*pFnLoadMMDrvFunc16)(LPCSTR,LPWINE_DRIVER, LPWINE_MM_DRIVER); -extern LRESULT (*pFnMmioCallback16)(DWORD,LPMMIOINFO,UINT,LPARAM,LPARAM); -extern void (WINAPI *pFnReleaseThunkLock)(DWORD*); -extern void (WINAPI *pFnRestoreThunkLock)(DWORD); -/* GetDriverFlags() returned bits is not documented (nor the call itself) - * Here are Wine only definitions of the bits - */ -#define WINE_GDF_EXIST 0x80000000 -#define WINE_GDF_16BIT 0x10000000 +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ + +/***************************************************************************** + * Copyright 1998, Luiz Otavio L. Zorzella + * 1999, Eric Pouech + * + * Purpose: multimedia declarations (internal to WINMM & MMSYSTEM DLLs) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + ***************************************************************************** + */ + +#include <stdarg.h> + +#include "windef.h" +#include "winbase.h" +#include "mmddk.h" + +#define WINE_DEFAULT_WINMM_DRIVER "wineoss.drv" +#define WINE_DEFAULT_WINMM_MAPPER "msacm.drv" +#define WINE_DEFAULT_WINMM_MIDI "midimap.drv" + +typedef DWORD (WINAPI *MessageProc16)(UINT16 wDevID, UINT16 wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2); +typedef DWORD (WINAPI *MessageProc32)(UINT wDevID, UINT wMsg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2); + +typedef enum { + WINMM_MAP_NOMEM, /* ko, memory problem */ + WINMM_MAP_MSGERROR, /* ko, unknown message */ + WINMM_MAP_OK, /* ok, no memory allocated. to be sent to the proc. */ + WINMM_MAP_OKMEM, /* ok, some memory allocated, need to call UnMapMsg. to be sent to the proc. */ +} WINMM_MapType; + +/* Who said goofy boy ? */ +#define WINE_DI_MAGIC 0x900F1B01 + +typedef struct tagWINE_DRIVER +{ + DWORD dwMagic; + /* as usual LPWINE_DRIVER == hDriver32 */ + DWORD dwFlags; + union { + struct { + HMODULE hModule; + DRIVERPROC lpDrvProc; + DWORD dwDriverID; + } d32; + struct { + UINT16 hDriver16; + } d16; + } d; + struct tagWINE_DRIVER* lpPrevItem; + struct tagWINE_DRIVER* lpNextItem; +} WINE_DRIVER, *LPWINE_DRIVER; + +typedef DWORD (CALLBACK *WINEMM_msgFunc16)(UINT16, WORD, DWORD, DWORD, DWORD); +typedef DWORD (CALLBACK *WINEMM_msgFunc32)(UINT , UINT, DWORD, DWORD, DWORD); + +/* for each loaded driver and each known type of driver, this structure contains + * the information needed to access it + */ +typedef struct tagWINE_MM_DRIVER_PART { + int nIDMin; /* lower bound of global indexes for this type */ + int nIDMax; /* hhigher bound of global indexes for this type */ + union { + WINEMM_msgFunc32 fnMessage32; /* pointer to function */ + WINEMM_msgFunc16 fnMessage16; + } u; +} WINE_MM_DRIVER_PART; + +#define MMDRV_AUX 0 +#define MMDRV_MIXER 1 +#define MMDRV_MIDIIN 2 +#define MMDRV_MIDIOUT 3 +#define MMDRV_WAVEIN 4 +#define MMDRV_WAVEOUT 5 +#define MMDRV_MAX 6 + +/* each low-level .drv will be associated with an instance of this structure */ +typedef struct tagWINE_MM_DRIVER { + HDRVR hDriver; + LPSTR drvname; /* name of the driver */ + unsigned bIs32 : 1, /* TRUE if 32 bit driver, FALSE for 16 */ + bIsMapper : 1; /* TRUE if mapper */ + WINE_MM_DRIVER_PART parts[MMDRV_MAX];/* Information for all known types */ +} WINE_MM_DRIVER, *LPWINE_MM_DRIVER; + +typedef struct tagWINE_MLD { +/* EPP struct tagWINE_MLD* lpNext; */ /* not used so far */ + UINT uDeviceID; + UINT type; + UINT mmdIndex; /* index to low-level driver in MMDrvs table */ + DWORD dwDriverInstance; /* this value is driver related, as opposed to + * opendesc.dwInstance which is client (callback) related */ + WORD bFrom32; + WORD dwFlags; + DWORD dwCallback; + DWORD dwClientInstance; +} WINE_MLD, *LPWINE_MLD; + +typedef struct { + WINE_MLD mld; +} WINE_WAVE, *LPWINE_WAVE; + +typedef struct { + WINE_MLD mld; + MIDIOPENDESC mod; /* FIXME: should be removed */ +} WINE_MIDI, *LPWINE_MIDI; + +typedef struct { + WINE_MLD mld; +} WINE_MIXER, *LPWINE_MIXER; + +#define WINE_MMTHREAD_CREATED 0x4153494C /* "BSIL" */ +#define WINE_MMTHREAD_DELETED 0xDEADDEAD + +typedef struct { + DWORD dwSignature; /* 00 "BSIL" when ok, 0xDEADDEAD when being deleted */ + DWORD dwCounter; /* 04 > 1 when in mmThread functions */ + HANDLE hThread; /* 08 hThread */ + DWORD dwThreadID; /* 0C */ + DWORD fpThread; /* 10 address of thread proc (segptr or lin depending on dwFlags) */ + DWORD dwThreadPmt; /* 14 parameter to be passed upon thread creation to fpThread */ + DWORD dwSignalCount; /* 18 counter used for signaling */ + HANDLE hEvent; /* 1C event */ + HANDLE hVxD; /* 20 return from OpenVxDHandle */ + DWORD dwStatus; /* 24 0x00, 0x10, 0x20, 0x30 */ + DWORD dwFlags; /* 28 dwFlags upon creation */ + UINT16 hTask; /* 2C handle to created task */ +} WINE_MMTHREAD; + +typedef struct tagWINE_MCIDRIVER { + UINT wDeviceID; + UINT wType; + LPWSTR lpstrElementName; + LPWSTR lpstrDeviceType; + LPWSTR lpstrAlias; + HDRVR hDriver; + DWORD dwPrivate; + YIELDPROC lpfnYieldProc; + DWORD dwYieldData; + BOOL bIs32; + DWORD CreatorThread; + UINT uTypeCmdTable; + UINT uSpecificCmdTable; + struct tagWINE_MCIDRIVER*lpNext; +} WINE_MCIDRIVER, *LPWINE_MCIDRIVER; + +#define WINE_TIMER_IS32 0x80 + +typedef struct tagWINE_TIMERENTRY { + UINT wDelay; + UINT wResol; + LPTIMECALLBACK lpFunc; /* can be lots of things */ + DWORD dwUser; + UINT16 wFlags; + UINT16 wTimerID; + DWORD dwTriggerTime; + struct tagWINE_TIMERENTRY* lpNext; +} WINE_TIMERENTRY, *LPWINE_TIMERENTRY; + +enum mmioProcType {MMIO_PROC_16,MMIO_PROC_32A,MMIO_PROC_32W}; + +struct IOProcList +{ + struct IOProcList*pNext; /* Next item in linked list */ + FOURCC fourCC; /* four-character code identifying IOProc */ + LPMMIOPROC pIOProc; /* pointer to IProc */ + enum mmioProcType type; /* 16, 32A or 32W */ + int count; /* number of objects linked to it */ +}; + +typedef struct tagWINE_MMIO { + MMIOINFO info; + struct tagWINE_MMIO* lpNext; + struct IOProcList* ioProc; + unsigned bTmpIOProc : 1, + bBufferLoaded : 1; + DWORD segBuffer16; + DWORD dwFileSize; +} WINE_MMIO, *LPWINE_MMIO; + +typedef struct tagWINE_PLAYSOUND { + unsigned bLoop : 1, + bAlloc : 1; + LPCWSTR pszSound; + HMODULE hMod; + DWORD fdwSound; + HANDLE hThread; + struct tagWINE_PLAYSOUND* lpNext; +} WINE_PLAYSOUND, *LPWINE_PLAYSOUND; + +typedef struct tagWINE_MM_IDATA { + /* winmm part */ + HANDLE hWinMM32Instance; + HANDLE hWinMM16Instance; + CRITICAL_SECTION cs; + /* mci part */ + LPWINE_MCIDRIVER lpMciDrvs; + /* low level drivers (unused yet) */ + /* LPWINE_WAVE lpWave; */ + /* LPWINE_MIDI lpMidi; */ + /* LPWINE_MIXER lpMixer; */ + /* mmio part */ + LPWINE_MMIO lpMMIO; + /* playsound and sndPlaySound */ + WINE_PLAYSOUND* lpPlaySound; + HANDLE psLastEvent; + HANDLE psStopEvent; +} WINE_MM_IDATA, *LPWINE_MM_IDATA; + +/* function prototypes */ + +typedef LONG (*MCIPROC)(DWORD, HDRVR, DWORD, DWORD, DWORD); +typedef WINMM_MapType (*MMDRV_MAPFUNC)(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2); +typedef WINMM_MapType (*MMDRV_UNMAPFUNC)(UINT wMsg, LPDWORD lpdwUser, LPDWORD lpParam1, LPDWORD lpParam2, MMRESULT ret); + +HDRVR WINAPI OpenDriverA(LPCSTR lpDriverName, LPCSTR lpSectionName, LPARAM lParam2); +LPWINE_DRIVER DRIVER_FindFromHDrvr(HDRVR hDrvr); +BOOL DRIVER_GetLibName(LPCWSTR keyName, LPCWSTR sectName, LPWSTR buf, int sz); +LPWINE_DRIVER DRIVER_TryOpenDriver32(LPCWSTR fn, LPARAM lParam2); +void DRIVER_UnloadAll(void); + +BOOL MMDRV_Init(void); +void MMDRV_Exit(void); +UINT MMDRV_GetNum(UINT); +LPWINE_MLD MMDRV_Alloc(UINT size, UINT type, LPHANDLE hndl, DWORD* dwFlags, + DWORD* dwCallback, DWORD* dwInstance, BOOL bFrom32); +void MMDRV_Free(HANDLE hndl, LPWINE_MLD mld); +DWORD MMDRV_Open(LPWINE_MLD mld, UINT wMsg, DWORD dwParam1, DWORD dwParam2); +DWORD MMDRV_Close(LPWINE_MLD mld, UINT wMsg); +LPWINE_MLD MMDRV_Get(HANDLE hndl, UINT type, BOOL bCanBeID); +LPWINE_MLD MMDRV_GetRelated(HANDLE hndl, UINT srcType, BOOL bSrcCanBeID, UINT dstTyped); +DWORD MMDRV_Message(LPWINE_MLD mld, UINT wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2, BOOL bFrom32); +UINT MMDRV_PhysicalFeatures(LPWINE_MLD mld, UINT uMsg, DWORD dwParam1, DWORD dwParam2); +BOOL MMDRV_Is32(unsigned int); +void MMDRV_InstallMap(unsigned int, MMDRV_MAPFUNC, MMDRV_UNMAPFUNC, + MMDRV_MAPFUNC, MMDRV_UNMAPFUNC, LPDRVCALLBACK); + +WINE_MCIDRIVER* MCI_GetDriver(UINT16 uDevID); +UINT MCI_GetDriverFromString(LPCWSTR str); +DWORD MCI_WriteString(LPWSTR lpDstStr, DWORD dstSize, LPCWSTR lpSrcStr); +const char* MCI_MessageToString(UINT wMsg); +UINT WINAPI MCI_DefYieldProc(MCIDEVICEID wDevID, DWORD data); +LRESULT MCI_CleanUp(LRESULT dwRet, UINT wMsg, DWORD dwParam2); +DWORD MCI_SendCommand(UINT wDevID, UINT16 wMsg, DWORD dwParam1, DWORD dwParam2, BOOL bFrom32); +DWORD MCI_SendCommandFrom32(UINT wDevID, UINT16 wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2); +DWORD MCI_SendCommandFrom16(UINT wDevID, UINT16 wMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2); +UINT MCI_SetCommandTable(void *table, UINT uDevType); +BOOL MCI_DeleteCommandTable(UINT uTbl, BOOL delete); +LPWSTR MCI_strdupAtoW(LPCSTR str); +LPSTR MCI_strdupWtoA(LPCWSTR str); + +BOOL WINMM_CheckForMMSystem(void); +const char* WINMM_ErrorToString(MMRESULT error); + +UINT MIXER_Open(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback, + DWORD_PTR dwInstance, DWORD fdwOpen, BOOL bFrom32); +UINT MIDI_OutOpen(HMIDIOUT* lphMidiOut, UINT uDeviceID, DWORD_PTR dwCallback, + DWORD_PTR dwInstance, DWORD dwFlags, BOOL bFrom32); +UINT MIDI_InOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD_PTR dwCallback, + DWORD_PTR dwInstance, DWORD dwFlags, BOOL bFrom32); +MMRESULT MIDI_StreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, + DWORD cMidi, DWORD_PTR dwCallback, + DWORD_PTR dwInstance, DWORD fdwOpen, BOOL bFrom32); +UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType, + LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, + DWORD_PTR dwInstance, DWORD dwFlags, BOOL bFrom32); + +HMMIO MMIO_Open(LPSTR szFileName, MMIOINFO* refmminfo, + DWORD dwOpenFlags, enum mmioProcType type); +LPMMIOPROC MMIO_InstallIOProc(FOURCC fccIOProc, LPMMIOPROC pIOProc, + DWORD dwFlags, enum mmioProcType type); +LRESULT MMIO_SendMessage(HMMIO hmmio, UINT uMessage, LPARAM lParam1, + LPARAM lParam2, enum mmioProcType type); +LPWINE_MMIO MMIO_Get(HMMIO h); + +WORD TIME_SetEventInternal(UINT wDelay, UINT wResol, LPTIMECALLBACK lpFunc, + DWORD dwUser, UINT wFlags); +void TIME_MMTimeStart(void); +void TIME_MMTimeStop(void); + +/* Global variables */ +extern WINE_MM_IDATA WINMM_IData; + +/* pointers to 16 bit functions (if sibling MMSYSTEM.DLL is loaded + * NULL otherwise + */ +extern WINE_MMTHREAD* (*pFnGetMMThread16)(UINT16); +extern LPWINE_DRIVER (*pFnOpenDriver16)(LPCWSTR,LPCWSTR,LPARAM); +extern LRESULT (*pFnCloseDriver16)(UINT16,LPARAM,LPARAM); +extern LRESULT (*pFnSendMessage16)(UINT16,UINT,LPARAM,LPARAM); +extern WINMM_MapType (*pFnMciMapMsg16To32W)(WORD,WORD,DWORD*); +extern WINMM_MapType (*pFnMciUnMapMsg16To32W)(WORD,WORD,DWORD); +extern WINMM_MapType (*pFnMciMapMsg32WTo16)(WORD,WORD,DWORD,DWORD*); +extern WINMM_MapType (*pFnMciUnMapMsg32WTo16)(WORD,WORD,DWORD,DWORD); +extern LRESULT (*pFnCallMMDrvFunc16)(DWORD /* in fact FARPROC16 */,WORD,WORD,LONG,LONG,LONG); +extern unsigned (*pFnLoadMMDrvFunc16)(LPCSTR,LPWINE_DRIVER, LPWINE_MM_DRIVER); +extern LRESULT (*pFnMmioCallback16)(DWORD,LPMMIOINFO,UINT,LPARAM,LPARAM); +extern void (WINAPI *pFnReleaseThunkLock)(DWORD*); +extern void (WINAPI *pFnRestoreThunkLock)(DWORD); +/* GetDriverFlags() returned bits is not documented (nor the call itself) + * Here are Wine only definitions of the bits + */ +#define WINE_GDF_EXIST 0x80000000 +#define WINE_GDF_16BIT 0x10000000 diff --git a/reactos/lib/winmm/winemm16.h b/reactos/lib/winmm/winemm16.h index 9f0920e62ca..3bb1780fecf 100644 --- a/reactos/lib/winmm/winemm16.h +++ b/reactos/lib/winmm/winemm16.h @@ -1,59 +1,59 @@ -/* -*- tab-width: 8; c-basic-offset: 4 -*- */ - -/***************************************************************************** - * Copyright 1998, Luiz Otavio L. Zorzella - * 1999, Eric Pouech - * - * Purpose: multimedia declarations (internal to WINMM & MMSYSTEM DLLs) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - ***************************************************************************** - */ -#include "winemm.h" -#include "wine/mmsystem16.h" -#include "wownt32.h" - -/* mmsystem (16 bit files) only functions */ -void MMDRV_Init16(void); -void MMSYSTEM_MMTIME16to32(LPMMTIME mmt32, const MMTIME16* mmt16); -void MMSYSTEM_MMTIME32to16(LPMMTIME16 mmt16, const MMTIME* mmt32); - -typedef LONG (*MCIPROC16)(DWORD, HDRVR16, WORD, DWORD, DWORD); - -/* HANDLE16 -> HANDLE conversions */ -#define HDRVR_32(h16) ((HDRVR)(ULONG_PTR)(h16)) -#define HMIDI_32(h16) ((HMIDI)(ULONG_PTR)(h16)) -#define HMIDIIN_32(h16) ((HMIDIIN)(ULONG_PTR)(h16)) -#define HMIDIOUT_32(h16) ((HMIDIOUT)(ULONG_PTR)(h16)) -#define HMIDISTRM_32(h16) ((HMIDISTRM)(ULONG_PTR)(h16)) -#define HMIXER_32(h16) ((HMIXER)(ULONG_PTR)(h16)) -#define HMIXEROBJ_32(h16) ((HMIXEROBJ)(ULONG_PTR)(h16)) -#define HMMIO_32(h16) ((HMMIO)(ULONG_PTR)(h16)) -#define HWAVE_32(h16) ((HWAVE)(ULONG_PTR)(h16)) -#define HWAVEIN_32(h16) ((HWAVEIN)(ULONG_PTR)(h16)) -#define HWAVEOUT_32(h16) ((HWAVEOUT)(ULONG_PTR)(h16)) - -/* HANDLE -> HANDLE16 conversions */ -#define HDRVR_16(h32) (LOWORD(h32)) -#define HMIDI_16(h32) (LOWORD(h32)) -#define HMIDIIN_16(h32) (LOWORD(h32)) -#define HMIDIOUT_16(h32) (LOWORD(h32)) -#define HMIDISTRM_16(h32) (LOWORD(h32)) -#define HMIXER_16(h32) (LOWORD(h32)) -#define HMIXEROBJ_16(h32) (LOWORD(h32)) -#define HMMIO_16(h32) (LOWORD(h32)) -#define HWAVE_16(h32) (LOWORD(h32)) -#define HWAVEIN_16(h32) (LOWORD(h32)) -#define HWAVEOUT_16(h32) (LOWORD(h32)) +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ + +/***************************************************************************** + * Copyright 1998, Luiz Otavio L. Zorzella + * 1999, Eric Pouech + * + * Purpose: multimedia declarations (internal to WINMM & MMSYSTEM DLLs) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + ***************************************************************************** + */ +#include "winemm.h" +#include "wine/mmsystem16.h" +#include "wownt32.h" + +/* mmsystem (16 bit files) only functions */ +void MMDRV_Init16(void); +void MMSYSTEM_MMTIME16to32(LPMMTIME mmt32, const MMTIME16* mmt16); +void MMSYSTEM_MMTIME32to16(LPMMTIME16 mmt16, const MMTIME* mmt32); + +typedef LONG (*MCIPROC16)(DWORD, HDRVR16, WORD, DWORD, DWORD); + +/* HANDLE16 -> HANDLE conversions */ +#define HDRVR_32(h16) ((HDRVR)(ULONG_PTR)(h16)) +#define HMIDI_32(h16) ((HMIDI)(ULONG_PTR)(h16)) +#define HMIDIIN_32(h16) ((HMIDIIN)(ULONG_PTR)(h16)) +#define HMIDIOUT_32(h16) ((HMIDIOUT)(ULONG_PTR)(h16)) +#define HMIDISTRM_32(h16) ((HMIDISTRM)(ULONG_PTR)(h16)) +#define HMIXER_32(h16) ((HMIXER)(ULONG_PTR)(h16)) +#define HMIXEROBJ_32(h16) ((HMIXEROBJ)(ULONG_PTR)(h16)) +#define HMMIO_32(h16) ((HMMIO)(ULONG_PTR)(h16)) +#define HWAVE_32(h16) ((HWAVE)(ULONG_PTR)(h16)) +#define HWAVEIN_32(h16) ((HWAVEIN)(ULONG_PTR)(h16)) +#define HWAVEOUT_32(h16) ((HWAVEOUT)(ULONG_PTR)(h16)) + +/* HANDLE -> HANDLE16 conversions */ +#define HDRVR_16(h32) (LOWORD(h32)) +#define HMIDI_16(h32) (LOWORD(h32)) +#define HMIDIIN_16(h32) (LOWORD(h32)) +#define HMIDIOUT_16(h32) (LOWORD(h32)) +#define HMIDISTRM_16(h32) (LOWORD(h32)) +#define HMIXER_16(h32) (LOWORD(h32)) +#define HMIXEROBJ_16(h32) (LOWORD(h32)) +#define HMMIO_16(h32) (LOWORD(h32)) +#define HWAVE_16(h32) (LOWORD(h32)) +#define HWAVEIN_16(h32) (LOWORD(h32)) +#define HWAVEOUT_16(h32) (LOWORD(h32)) diff --git a/reactos/lib/winmm/winmm.c b/reactos/lib/winmm/winmm.c index ed5614e6ba1..7cc2ff9ea0b 100644 --- a/reactos/lib/winmm/winmm.c +++ b/reactos/lib/winmm/winmm.c @@ -1,2846 +1,2846 @@ -/* -*- tab-width: 8; c-basic-offset: 4 -*- */ - -/* - * WINMM functions - * - * Copyright 1993 Martin Ayotte - * 1998-2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * Eric POUECH : - * 98/9 added Win32 MCI support - * 99/4 added midiStream support - * 99/9 added support for loadable low level drivers - */ - -/* TODO - * + it seems that some programs check what's installed in - * registry against the value returned by drivers. Wine is - * currently broken regarding this point. - * + check thread-safeness for MMSYSTEM and WINMM entry points - * + unicode entry points are badly supported (would require - * moving 32 bit drivers as Unicode as they are supposed to be) - * + allow joystick and timer external calls as we do for wave, - * midi, mixer and aux - */ - -#include <stdio.h> -#include <stdarg.h> -#include <string.h> - -#define NONAMELESSUNION -#define NONAMELESSSTRUCT -#include "windef.h" -#include "winbase.h" -#include "mmsystem.h" -#include "winuser.h" -#include "winnls.h" -#include "winreg.h" -#include "winternl.h" -#include "winemm.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(winmm); - -void (WINAPI *pFnReleaseThunkLock)(DWORD*); -void (WINAPI *pFnRestoreThunkLock)(DWORD); - -/* ======================================================================== - * G L O B A L S E T T I N G S - * ========================================================================*/ - -WINE_MM_IDATA WINMM_IData; - -/************************************************************************** - * WINMM_CreateIData [internal] - */ -static BOOL WINMM_CreateIData(HINSTANCE hInstDLL) -{ - memset( &WINMM_IData, 0, sizeof WINMM_IData ); - - WINMM_IData.hWinMM32Instance = hInstDLL; - InitializeCriticalSection(&WINMM_IData.cs); -/* FIXME crashes in ReactOS - WINMM_IData.cs.DebugInfo->Spare[1] = (DWORD)"WINMM_IData"; -*/ - WINMM_IData.psStopEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - WINMM_IData.psLastEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - TRACE("Initialized IData (%p)\n", &WINMM_IData); - return TRUE; -} - -/************************************************************************** - * WINMM_DeleteIData [internal] - */ -static void WINMM_DeleteIData(void) -{ - TIME_MMTimeStop(); - - /* FIXME: should also free content and resources allocated - * inside WINMM_IData */ - CloseHandle(WINMM_IData.psStopEvent); - CloseHandle(WINMM_IData.psLastEvent); - DeleteCriticalSection(&WINMM_IData.cs); -} - -/****************************************************************** - * WINMM_LoadMMSystem - * - */ -#ifndef __REACTOS__ -static HANDLE (WINAPI *pGetModuleHandle16)(LPCSTR); -static DWORD (WINAPI *pLoadLibrary16)(LPCSTR); -#endif - -BOOL WINMM_CheckForMMSystem(void) -{ - /* 0 is not checked yet, -1 is not present, 1 is present */ - static int loaded /* = 0 */; - - if (loaded == 0) - { - HANDLE h = GetModuleHandleA("kernel32"); - loaded = -1; - if (h) - { -#ifndef __REACTOS__ - pGetModuleHandle16 = (void*)GetProcAddress(h, "GetModuleHandle16"); - pLoadLibrary16 = (void*)GetProcAddress(h, "LoadLibrary16"); - if (pGetModuleHandle16 && pLoadLibrary16 && - (pGetModuleHandle16("MMSYSTEM.DLL") || pLoadLibrary16("MMSYSTEM.DLL"))) -#endif /* __REACTOS__ */ - loaded = 1; - } - } - return loaded > 0; -} - -/****************************************************************** - * WINMM_ErrorToString - */ -const char* WINMM_ErrorToString(MMRESULT error) -{ -#define ERR_TO_STR(dev) case dev: return #dev - static char unknown[32]; - switch (error) { - ERR_TO_STR(MMSYSERR_NOERROR); - ERR_TO_STR(MMSYSERR_ERROR); - ERR_TO_STR(MMSYSERR_BADDEVICEID); - ERR_TO_STR(MMSYSERR_NOTENABLED); - ERR_TO_STR(MMSYSERR_ALLOCATED); - ERR_TO_STR(MMSYSERR_INVALHANDLE); - ERR_TO_STR(MMSYSERR_NODRIVER); - ERR_TO_STR(MMSYSERR_NOMEM); - ERR_TO_STR(MMSYSERR_NOTSUPPORTED); - ERR_TO_STR(MMSYSERR_BADERRNUM); - ERR_TO_STR(MMSYSERR_INVALFLAG); - ERR_TO_STR(MMSYSERR_INVALPARAM); - ERR_TO_STR(MMSYSERR_HANDLEBUSY); - ERR_TO_STR(MMSYSERR_INVALIDALIAS); - ERR_TO_STR(MMSYSERR_BADDB); - ERR_TO_STR(MMSYSERR_KEYNOTFOUND); - ERR_TO_STR(MMSYSERR_READERROR); - ERR_TO_STR(MMSYSERR_WRITEERROR); - ERR_TO_STR(MMSYSERR_DELETEERROR); - ERR_TO_STR(MMSYSERR_VALNOTFOUND); - ERR_TO_STR(MMSYSERR_NODRIVERCB); - ERR_TO_STR(WAVERR_BADFORMAT); - ERR_TO_STR(WAVERR_STILLPLAYING); - ERR_TO_STR(WAVERR_UNPREPARED); - ERR_TO_STR(WAVERR_SYNC); - } - sprintf(unknown, "Unknown(0x%08x)", error); - return unknown; -#undef ERR_TO_STR -} - -/************************************************************************** - * DllMain (WINMM.init) - * - * WINMM DLL entry point - * - */ -BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad) -{ - TRACE("%p 0x%lx %p\n", hInstDLL, fdwReason, fImpLoad); - - switch (fdwReason) { - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(hInstDLL); - - if (!WINMM_CreateIData(hInstDLL)) - return FALSE; - if (!MMDRV_Init()) { - WINMM_DeleteIData(); - return FALSE; - } - break; - case DLL_PROCESS_DETACH: - /* close all opened MCI drivers */ - MCI_SendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, MCI_WAIT, 0L, TRUE); - MMDRV_Exit(); - /* now unload all remaining drivers... */ - DRIVER_UnloadAll(); - - WINMM_DeleteIData(); - break; - } - return TRUE; -} - -/************************************************************************** - * Mixer devices. New to Win95 - */ - -/************************************************************************** - * find out the real mixer ID depending on hmix (depends on dwFlags) - */ -static UINT MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags, LPWINE_MIXER * lplpwm) -{ - LPWINE_MIXER lpwm = NULL; - UINT uRet = MMSYSERR_NOERROR; - - switch (dwFlags & 0xF0000000ul) { - case MIXER_OBJECTF_MIXER: - lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE); - break; - case MIXER_OBJECTF_HMIXER: - lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE); - break; - case MIXER_OBJECTF_WAVEOUT: - lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE, MMDRV_MIXER); - break; - case MIXER_OBJECTF_HWAVEOUT: - lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER); - break; - case MIXER_OBJECTF_WAVEIN: - lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, TRUE, MMDRV_MIXER); - break; - case MIXER_OBJECTF_HWAVEIN: - lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, FALSE, MMDRV_MIXER); - break; - case MIXER_OBJECTF_MIDIOUT: - lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE, MMDRV_MIXER); - break; - case MIXER_OBJECTF_HMIDIOUT: - lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER); - break; - case MIXER_OBJECTF_MIDIIN: - lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, TRUE, MMDRV_MIXER); - break; - case MIXER_OBJECTF_HMIDIIN: - lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, FALSE, MMDRV_MIXER); - break; - case MIXER_OBJECTF_AUX: - lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX, TRUE, MMDRV_MIXER); - break; - default: - WARN("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul); - lpwm = 0; - uRet = MMSYSERR_INVALFLAG; - break; - } - *lplpwm = lpwm; - if (lpwm == 0 && uRet == MMSYSERR_NOERROR) - uRet = MMSYSERR_INVALPARAM; - return uRet; -} - -/************************************************************************** - * mixerGetNumDevs [WINMM.@] - */ -UINT WINAPI mixerGetNumDevs(void) -{ - return MMDRV_GetNum(MMDRV_MIXER); -} - -/************************************************************************** - * mixerGetDevCapsA [WINMM.@] - */ -UINT WINAPI mixerGetDevCapsA(UINT_PTR uDeviceID, LPMIXERCAPSA lpCaps, UINT uSize) -{ - MIXERCAPSW micW; - UINT ret; - - if (lpCaps == NULL) return MMSYSERR_INVALPARAM; - - ret = mixerGetDevCapsW(uDeviceID, &micW, sizeof(micW)); - - if (ret == MMSYSERR_NOERROR) { - MIXERCAPSA micA; - micA.wMid = micW.wMid; - micA.wPid = micW.wPid; - micA.vDriverVersion = micW.vDriverVersion; - WideCharToMultiByte( CP_ACP, 0, micW.szPname, -1, micA.szPname, - sizeof(micA.szPname), NULL, NULL ); - micA.fdwSupport = micW.fdwSupport; - micA.cDestinations = micW.cDestinations; - memcpy(lpCaps, &micA, min(uSize, sizeof(micA))); - } - return ret; -} - -/************************************************************************** - * mixerGetDevCapsW [WINMM.@] - */ -UINT WINAPI mixerGetDevCapsW(UINT_PTR uDeviceID, LPMIXERCAPSW lpCaps, UINT uSize) -{ - LPWINE_MLD wmld; - - if (lpCaps == NULL) return MMSYSERR_INVALPARAM; - - if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIXER, TRUE)) == NULL) - return MMSYSERR_BADDEVICEID; - - return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE); -} - -UINT MIXER_Open(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback, - DWORD_PTR dwInstance, DWORD fdwOpen, BOOL bFrom32) -{ - HANDLE hMix; - LPWINE_MLD wmld; - DWORD dwRet = 0; - MIXEROPENDESC mod; - - TRACE("(%p, %d, %08lx, %08lx, %08lx)\n", - lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen); - - wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen, - &dwCallback, &dwInstance, bFrom32); - - wmld->uDeviceID = uDeviceID; - mod.hmx = (HMIXEROBJ)hMix; - mod.dwCallback = dwCallback; - mod.dwInstance = dwInstance; - - dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD)&mod, fdwOpen); - - if (dwRet != MMSYSERR_NOERROR) { - MMDRV_Free(hMix, wmld); - hMix = 0; - } - if (lphMix) *lphMix = hMix; - TRACE("=> %ld hMixer=%p\n", dwRet, hMix); - - return dwRet; -} - -/************************************************************************** - * mixerOpen [WINMM.@] - */ -UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback, - DWORD_PTR dwInstance, DWORD fdwOpen) -{ - return MIXER_Open(lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen, TRUE); -} - -/************************************************************************** - * mixerClose [WINMM.@] - */ -UINT WINAPI mixerClose(HMIXER hMix) -{ - LPWINE_MLD wmld; - DWORD dwRet; - - TRACE("(%p)\n", hMix); - - if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE; - - dwRet = MMDRV_Close(wmld, MXDM_CLOSE); - MMDRV_Free(hMix, wmld); - - return dwRet; -} - -/************************************************************************** - * mixerGetID [WINMM.@] - */ -UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID) -{ - LPWINE_MIXER lpwm; - UINT uRet = MMSYSERR_NOERROR; - - TRACE("(%p %p %08lx)\n", hmix, lpid, fdwID); - - if ((uRet = MIXER_GetDev(hmix, fdwID, &lpwm)) != MMSYSERR_NOERROR) - return uRet; - - if (lpid) - *lpid = lpwm->mld.uDeviceID; - - return uRet; -} - -/************************************************************************** - * mixerGetControlDetailsW [WINMM.@] - */ -UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdW, - DWORD fdwDetails) -{ - LPWINE_MIXER lpwm; - UINT uRet = MMSYSERR_NOERROR; - - TRACE("(%p, %p, %08lx)\n", hmix, lpmcdW, fdwDetails); - - if ((uRet = MIXER_GetDev(hmix, fdwDetails, &lpwm)) != MMSYSERR_NOERROR) - return uRet; - - if (lpmcdW == NULL || lpmcdW->cbStruct != sizeof(*lpmcdW)) - return MMSYSERR_INVALPARAM; - - return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD_PTR)lpmcdW, - fdwDetails, TRUE); -} - -/************************************************************************** - * mixerGetControlDetailsA [WINMM.@] - */ -UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA, - DWORD fdwDetails) -{ - DWORD ret = MMSYSERR_NOTENABLED; - - TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails); - - if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA)) - return MMSYSERR_INVALPARAM; - - switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) { - case MIXER_GETCONTROLDETAILSF_VALUE: - /* can savely use A structure as it is, no string inside */ - ret = mixerGetControlDetailsW(hmix, lpmcdA, fdwDetails); - break; - case MIXER_GETCONTROLDETAILSF_LISTTEXT: - { - MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA = (MIXERCONTROLDETAILS_LISTTEXTA *)lpmcdA->paDetails; - MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW; - int size = max(1, lpmcdA->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTW); - unsigned int i; - - if (lpmcdA->u.cMultipleItems != 0) { - size *= lpmcdA->u.cMultipleItems; - } - pDetailsW = HeapAlloc(GetProcessHeap(), 0, size); - lpmcdA->paDetails = pDetailsW; - lpmcdA->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW); - /* set up lpmcd->paDetails */ - ret = mixerGetControlDetailsW(hmix, lpmcdA, fdwDetails); - /* copy from lpmcd->paDetails back to paDetailsW; */ - if (ret == MMSYSERR_NOERROR) { - for (i = 0; i < lpmcdA->u.cMultipleItems * lpmcdA->cChannels; i++) { - pDetailsA->dwParam1 = pDetailsW->dwParam1; - pDetailsA->dwParam2 = pDetailsW->dwParam2; - WideCharToMultiByte( CP_ACP, 0, pDetailsW->szName, -1, - pDetailsA->szName, - sizeof(pDetailsA->szName), NULL, NULL ); - pDetailsA++; - pDetailsW++; - } - pDetailsA -= lpmcdA->u.cMultipleItems * lpmcdA->cChannels; - pDetailsW -= lpmcdA->u.cMultipleItems * lpmcdA->cChannels; - } - HeapFree(GetProcessHeap(), 0, pDetailsW); - lpmcdA->paDetails = pDetailsA; - lpmcdA->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA); - } - break; - default: - ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails); - } - - return ret; -} - -/************************************************************************** - * mixerGetLineControlsA [WINMM.@] - */ -UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA, - DWORD fdwControls) -{ - MIXERLINECONTROLSW mlcW; - DWORD ret; - unsigned int i; - - TRACE("(%p, %p, %08lx)\n", hmix, lpmlcA, fdwControls); - - if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA) || - lpmlcA->cbmxctrl != sizeof(MIXERCONTROLA)) - return MMSYSERR_INVALPARAM; - - mlcW.cbStruct = sizeof(mlcW); - mlcW.dwLineID = lpmlcA->dwLineID; - mlcW.u.dwControlID = lpmlcA->u.dwControlID; - mlcW.u.dwControlType = lpmlcA->u.dwControlType; - - /* Debugging on Windows shows for MIXER_GETLINECONTROLSF_ONEBYTYPE only, - the control count is assumed to be 1 - This is relied upon by a game, - "Dynomite Deluze" */ - if (MIXER_GETLINECONTROLSF_ONEBYTYPE == fdwControls) { - mlcW.cControls = 1; - } else { - mlcW.cControls = lpmlcA->cControls; - } - mlcW.cbmxctrl = sizeof(MIXERCONTROLW); - mlcW.pamxctrl = HeapAlloc(GetProcessHeap(), 0, - mlcW.cControls * mlcW.cbmxctrl); - - ret = mixerGetLineControlsW(hmix, &mlcW, fdwControls); - - if (ret == MMSYSERR_NOERROR) { - lpmlcA->dwLineID = mlcW.dwLineID; - lpmlcA->u.dwControlID = mlcW.u.dwControlID; - lpmlcA->u.dwControlType = mlcW.u.dwControlType; - lpmlcA->cControls = mlcW.cControls; - - for (i = 0; i < mlcW.cControls; i++) { - lpmlcA->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLA); - lpmlcA->pamxctrl[i].dwControlID = mlcW.pamxctrl[i].dwControlID; - lpmlcA->pamxctrl[i].dwControlType = mlcW.pamxctrl[i].dwControlType; - lpmlcA->pamxctrl[i].fdwControl = mlcW.pamxctrl[i].fdwControl; - lpmlcA->pamxctrl[i].cMultipleItems = mlcW.pamxctrl[i].cMultipleItems; - WideCharToMultiByte( CP_ACP, 0, mlcW.pamxctrl[i].szShortName, -1, - lpmlcA->pamxctrl[i].szShortName, - sizeof(lpmlcA->pamxctrl[i].szShortName), NULL, NULL ); - WideCharToMultiByte( CP_ACP, 0, mlcW.pamxctrl[i].szName, -1, - lpmlcA->pamxctrl[i].szName, - sizeof(lpmlcA->pamxctrl[i].szName), NULL, NULL ); - /* sizeof(lpmlcA->pamxctrl[i].Bounds) == - * sizeof(mlcW.pamxctrl[i].Bounds) */ - memcpy(&lpmlcA->pamxctrl[i].Bounds, &mlcW.pamxctrl[i].Bounds, - sizeof(mlcW.pamxctrl[i].Bounds)); - /* sizeof(lpmlcA->pamxctrl[i].Metrics) == - * sizeof(mlcW.pamxctrl[i].Metrics) */ - memcpy(&lpmlcA->pamxctrl[i].Metrics, &mlcW.pamxctrl[i].Metrics, - sizeof(mlcW.pamxctrl[i].Metrics)); - } - } - - HeapFree(GetProcessHeap(), 0, mlcW.pamxctrl); - - return ret; -} - -/************************************************************************** - * mixerGetLineControlsW [WINMM.@] - */ -UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW, - DWORD fdwControls) -{ - LPWINE_MIXER lpwm; - UINT uRet = MMSYSERR_NOERROR; - - TRACE("(%p, %p, %08lx)\n", hmix, lpmlcW, fdwControls); - - if ((uRet = MIXER_GetDev(hmix, fdwControls, &lpwm)) != MMSYSERR_NOERROR) - return uRet; - - if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW)) - return MMSYSERR_INVALPARAM; - - return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD_PTR)lpmlcW, - fdwControls, TRUE); -} - -/************************************************************************** - * mixerGetLineInfoW [WINMM.@] - */ -UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW, DWORD fdwInfo) -{ - LPWINE_MIXER lpwm; - UINT uRet = MMSYSERR_NOERROR; - - TRACE("(%p, %p, %08lx)\n", hmix, lpmliW, fdwInfo); - - if ((uRet = MIXER_GetDev(hmix, fdwInfo, &lpwm)) != MMSYSERR_NOERROR) - return uRet; - - return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD_PTR)lpmliW, - fdwInfo, TRUE); -} - -/************************************************************************** - * mixerGetLineInfoA [WINMM.@] - */ -UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliA, - DWORD fdwInfo) -{ - MIXERLINEW mliW; - UINT ret; - - TRACE("(%p, %p, %08lx)\n", hmix, lpmliA, fdwInfo); - - if (lpmliA == NULL || lpmliA->cbStruct != sizeof(*lpmliA)) - return MMSYSERR_INVALPARAM; - - mliW.cbStruct = sizeof(mliW); - switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) { - case MIXER_GETLINEINFOF_COMPONENTTYPE: - mliW.dwComponentType = lpmliA->dwComponentType; - break; - case MIXER_GETLINEINFOF_DESTINATION: - mliW.dwDestination = lpmliA->dwDestination; - break; - case MIXER_GETLINEINFOF_LINEID: - mliW.dwLineID = lpmliA->dwLineID; - break; - case MIXER_GETLINEINFOF_SOURCE: - mliW.dwDestination = lpmliA->dwDestination; - mliW.dwSource = lpmliA->dwSource; - break; - case MIXER_GETLINEINFOF_TARGETTYPE: - mliW.Target.dwType = lpmliA->Target.dwType; - mliW.Target.wMid = lpmliA->Target.wMid; - mliW.Target.wPid = lpmliA->Target.wPid; - mliW.Target.vDriverVersion = lpmliA->Target.vDriverVersion; - MultiByteToWideChar( CP_ACP, 0, lpmliA->Target.szPname, -1, mliW.Target.szPname, sizeof(mliW.Target.szPname)); - break; - default: - WARN("Unsupported fdwControls=0x%08lx\n", fdwInfo); - return MMSYSERR_INVALFLAG; - } - - ret = mixerGetLineInfoW(hmix, &mliW, fdwInfo); - - lpmliA->dwDestination = mliW.dwDestination; - lpmliA->dwSource = mliW.dwSource; - lpmliA->dwLineID = mliW.dwLineID; - lpmliA->fdwLine = mliW.fdwLine; - lpmliA->dwUser = mliW.dwUser; - lpmliA->dwComponentType = mliW.dwComponentType; - lpmliA->cChannels = mliW.cChannels; - lpmliA->cConnections = mliW.cConnections; - lpmliA->cControls = mliW.cControls; - WideCharToMultiByte( CP_ACP, 0, mliW.szShortName, -1, lpmliA->szShortName, - sizeof(lpmliA->szShortName), NULL, NULL); - WideCharToMultiByte( CP_ACP, 0, mliW.szName, -1, lpmliA->szName, - sizeof(lpmliA->szName), NULL, NULL ); - lpmliA->Target.dwType = mliW.Target.dwType; - lpmliA->Target.dwDeviceID = mliW.Target.dwDeviceID; - lpmliA->Target.wMid = mliW.Target.wMid; - lpmliA->Target.wPid = mliW.Target.wPid; - lpmliA->Target.vDriverVersion = mliW.Target.vDriverVersion; - WideCharToMultiByte( CP_ACP, 0, mliW.Target.szPname, -1, lpmliA->Target.szPname, - sizeof(lpmliA->Target.szPname), NULL, NULL ); - - return ret; -} - -/************************************************************************** - * mixerSetControlDetails [WINMM.@] - */ -UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, - DWORD fdwDetails) -{ - LPWINE_MIXER lpwm; - UINT uRet = MMSYSERR_NOERROR; - - TRACE("(%p, %p, %08lx)\n", hmix, lpmcd, fdwDetails); - - if ((uRet = MIXER_GetDev(hmix, fdwDetails, &lpwm)) != MMSYSERR_NOERROR) - return uRet; - - return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD_PTR)lpmcd, - fdwDetails, TRUE); -} - -/************************************************************************** - * mixerMessage [WINMM.@] - */ -DWORD WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2) -{ - LPWINE_MLD wmld; - - TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n", - (DWORD)hmix, uMsg, dwParam1, dwParam2); - - if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2, TRUE); -} - -/************************************************************************** - * auxGetNumDevs [WINMM.@] - */ -UINT WINAPI auxGetNumDevs(void) -{ - return MMDRV_GetNum(MMDRV_AUX); -} - -/************************************************************************** - * auxGetDevCapsW [WINMM.@] - */ -UINT WINAPI auxGetDevCapsW(UINT_PTR uDeviceID, LPAUXCAPSW lpCaps, UINT uSize) -{ - LPWINE_MLD wmld; - - TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize); - - if (lpCaps == NULL) return MMSYSERR_INVALPARAM; - - if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL) - return MMSYSERR_INVALHANDLE; - return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE); -} - -/************************************************************************** - * auxGetDevCapsA [WINMM.@] - */ -UINT WINAPI auxGetDevCapsA(UINT_PTR uDeviceID, LPAUXCAPSA lpCaps, UINT uSize) -{ - AUXCAPSW acW; - UINT ret; - - if (lpCaps == NULL) return MMSYSERR_INVALPARAM; - - ret = auxGetDevCapsW(uDeviceID, &acW, sizeof(acW)); - - if (ret == MMSYSERR_NOERROR) { - AUXCAPSA acA; - acA.wMid = acW.wMid; - acA.wPid = acW.wPid; - acA.vDriverVersion = acW.vDriverVersion; - WideCharToMultiByte( CP_ACP, 0, acW.szPname, -1, acA.szPname, - sizeof(acA.szPname), NULL, NULL ); - acA.wTechnology = acW.wTechnology; - acA.dwSupport = acW.dwSupport; - memcpy(lpCaps, &acA, min(uSize, sizeof(acA))); - } - return ret; -} - -/************************************************************************** - * auxGetVolume [WINMM.@] - */ -UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume) -{ - LPWINE_MLD wmld; - - TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume); - - if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL) - return MMSYSERR_INVALHANDLE; - return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD_PTR)lpdwVolume, 0L, TRUE); -} - -/************************************************************************** - * auxSetVolume [WINMM.@] - */ -UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume) -{ - LPWINE_MLD wmld; - - TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume); - - if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL) - return MMSYSERR_INVALHANDLE; - return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE); -} - -/************************************************************************** - * auxOutMessage [WINMM.@] - */ -UINT WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD_PTR dw1, DWORD_PTR dw2) -{ - LPWINE_MLD wmld; - - if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE); -} - -/************************************************************************** - * midiOutGetNumDevs [WINMM.@] - */ -UINT WINAPI midiOutGetNumDevs(void) -{ - return MMDRV_GetNum(MMDRV_MIDIOUT); -} - -/************************************************************************** - * midiOutGetDevCapsW [WINMM.@] - */ -UINT WINAPI midiOutGetDevCapsW(UINT_PTR uDeviceID, LPMIDIOUTCAPSW lpCaps, - UINT uSize) -{ - LPWINE_MLD wmld; - - TRACE("(%u, %p, %u);\n", uDeviceID, lpCaps, uSize); - - if (lpCaps == NULL) return MMSYSERR_INVALPARAM; - - if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE); -} - -/************************************************************************** - * midiOutGetDevCapsA [WINMM.@] - */ -UINT WINAPI midiOutGetDevCapsA(UINT_PTR uDeviceID, LPMIDIOUTCAPSA lpCaps, - UINT uSize) -{ - MIDIOUTCAPSW mocW; - UINT ret; - - if (lpCaps == NULL) return MMSYSERR_INVALPARAM; - - ret = midiOutGetDevCapsW(uDeviceID, &mocW, sizeof(mocW)); - - if (ret == MMSYSERR_NOERROR) { - MIDIOUTCAPSA mocA; - mocA.wMid = mocW.wMid; - mocA.wPid = mocW.wPid; - mocA.vDriverVersion = mocW.vDriverVersion; - WideCharToMultiByte( CP_ACP, 0, mocW.szPname, -1, mocA.szPname, - sizeof(mocA.szPname), NULL, NULL ); - mocA.wTechnology = mocW.wTechnology; - mocA.wVoices = mocW.wVoices; - mocA.wNotes = mocW.wNotes; - mocA.wChannelMask = mocW.wChannelMask; - mocA.dwSupport = mocW.dwSupport; - memcpy(lpCaps, &mocA, min(uSize, sizeof(mocA))); - } - return ret; -} - -/************************************************************************** - * midiOutGetErrorTextA [WINMM.@] - * midiInGetErrorTextA [WINMM.@] - */ -UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize) -{ - UINT ret; - - if (lpText == NULL) ret = MMSYSERR_INVALPARAM; - else if (uSize == 0) ret = MMSYSERR_NOERROR; - else - { - LPWSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize * sizeof(WCHAR)); - if (!xstr) ret = MMSYSERR_NOMEM; - else - { - ret = midiOutGetErrorTextW(uError, xstr, uSize); - if (ret == MMSYSERR_NOERROR) - WideCharToMultiByte(CP_ACP, 0, xstr, -1, lpText, uSize, NULL, NULL); - HeapFree(GetProcessHeap(), 0, xstr); - } - } - return ret; -} - -/************************************************************************** - * midiOutGetErrorTextW [WINMM.@] - * midiInGetErrorTextW [WINMM.@] - */ -UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize) -{ - UINT ret = MMSYSERR_BADERRNUM; - - if (lpText == NULL) ret = MMSYSERR_INVALPARAM; - else if (uSize == 0) ret = MMSYSERR_NOERROR; - else if ( - /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit - * a warning for the test was always true */ - (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) || - (uError >= MIDIERR_BASE && uError <= MIDIERR_LASTERROR)) { - if (LoadStringW(WINMM_IData.hWinMM32Instance, - uError, lpText, uSize) > 0) { - ret = MMSYSERR_NOERROR; - } - } - return ret; -} - -/************************************************************************** - * MIDI_OutAlloc [internal] - */ -static LPWINE_MIDI MIDI_OutAlloc(HMIDIOUT* lphMidiOut, LPDWORD lpdwCallback, - LPDWORD lpdwInstance, LPDWORD lpdwFlags, - DWORD cIDs, MIDIOPENSTRMID* lpIDs, BOOL bFrom32) -{ - HANDLE hMidiOut; - LPWINE_MIDI lpwm; - UINT size; - - size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID); - - lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags, - lpdwCallback, lpdwInstance, bFrom32); - - if (lphMidiOut != NULL) - *lphMidiOut = hMidiOut; - - if (lpwm) { - lpwm->mod.hMidi = (HMIDI) hMidiOut; - lpwm->mod.dwCallback = *lpdwCallback; - lpwm->mod.dwInstance = *lpdwInstance; - lpwm->mod.dnDevNode = 0; - lpwm->mod.cIds = cIDs; - if (cIDs) - memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID)); - } - return lpwm; -} - -UINT MIDI_OutOpen(LPHMIDIOUT lphMidiOut, UINT uDeviceID, DWORD_PTR dwCallback, - DWORD_PTR dwInstance, DWORD dwFlags, BOOL bFrom32) -{ - HMIDIOUT hMidiOut; - LPWINE_MIDI lpwm; - UINT dwRet = 0; - - TRACE("(%p, %d, %08lX, %08lX, %08lX);\n", - lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags); - - if (lphMidiOut != NULL) *lphMidiOut = 0; - - lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags, - 0, NULL, bFrom32); - - if (lpwm == NULL) - return MMSYSERR_NOMEM; - - lpwm->mld.uDeviceID = uDeviceID; - - dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD)&lpwm->mod, dwFlags); - - if (dwRet != MMSYSERR_NOERROR) { - MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm); - hMidiOut = 0; - } - - if (lphMidiOut) *lphMidiOut = hMidiOut; - TRACE("=> %d hMidi=%p\n", dwRet, hMidiOut); - - return dwRet; -} - -/************************************************************************** - * midiOutOpen [WINMM.@] - */ -UINT WINAPI midiOutOpen(LPHMIDIOUT lphMidiOut, UINT uDeviceID, - DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags) -{ - return MIDI_OutOpen(lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE); -} - -/************************************************************************** - * midiOutClose [WINMM.@] - */ -UINT WINAPI midiOutClose(HMIDIOUT hMidiOut) -{ - LPWINE_MLD wmld; - DWORD dwRet; - - TRACE("(%p)\n", hMidiOut); - - if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - dwRet = MMDRV_Close(wmld, MODM_CLOSE); - MMDRV_Free(hMidiOut, wmld); - - return dwRet; -} - -/************************************************************************** - * midiOutPrepareHeader [WINMM.@] - */ -UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut, - MIDIHDR* lpMidiOutHdr, UINT uSize) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize); - - if (lpMidiOutHdr == NULL || uSize < sizeof (MIDIHDR)) - return MMSYSERR_INVALPARAM; - - if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, MODM_PREPARE, (DWORD_PTR)lpMidiOutHdr, uSize, TRUE); -} - -/************************************************************************** - * midiOutUnprepareHeader [WINMM.@] - */ -UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut, - MIDIHDR* lpMidiOutHdr, UINT uSize) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize); - - if (lpMidiOutHdr == NULL || uSize < sizeof (MIDIHDR)) - return MMSYSERR_INVALPARAM; - - if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) { - return MMSYSERR_NOERROR; - } - - if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD_PTR)lpMidiOutHdr, uSize, TRUE); -} - -/************************************************************************** - * midiOutShortMsg [WINMM.@] - */ -UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %08lX)\n", hMidiOut, dwMsg); - - if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L, TRUE); -} - -/************************************************************************** - * midiOutLongMsg [WINMM.@] - */ -UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut, - MIDIHDR* lpMidiOutHdr, UINT uSize) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize); - - if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD_PTR)lpMidiOutHdr, uSize, TRUE); -} - -/************************************************************************** - * midiOutReset [WINMM.@] - */ -UINT WINAPI midiOutReset(HMIDIOUT hMidiOut) -{ - LPWINE_MLD wmld; - - TRACE("(%p)\n", hMidiOut); - - if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, MODM_RESET, 0L, 0L, TRUE); -} - -/************************************************************************** - * midiOutGetVolume [WINMM.@] - */ -UINT WINAPI midiOutGetVolume(HMIDIOUT hMidiOut, DWORD* lpdwVolume) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %p);\n", hMidiOut, lpdwVolume); - - if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD_PTR)lpdwVolume, 0L, TRUE); -} - -/************************************************************************** - * midiOutSetVolume [WINMM.@] - */ -UINT WINAPI midiOutSetVolume(HMIDIOUT hMidiOut, DWORD dwVolume) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %ld);\n", hMidiOut, dwVolume); - - if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L, TRUE); -} - -/************************************************************************** - * midiOutCachePatches [WINMM.@] - */ -UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank, - WORD* lpwPatchArray, UINT uFlags) -{ - /* not really necessary to support this */ - FIXME("not supported yet\n"); - return MMSYSERR_NOTSUPPORTED; -} - -/************************************************************************** - * midiOutCacheDrumPatches [WINMM.@] - */ -UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch, - WORD* lpwKeyArray, UINT uFlags) -{ - FIXME("not supported yet\n"); - return MMSYSERR_NOTSUPPORTED; -} - -/************************************************************************** - * midiOutGetID [WINMM.@] - */ -UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %p)\n", hMidiOut, lpuDeviceID); - - if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM; - if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - *lpuDeviceID = wmld->uDeviceID; - return MMSYSERR_NOERROR; -} - -/************************************************************************** - * midiOutMessage [WINMM.@] - */ -UINT WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage, - DWORD_PTR dwParam1, DWORD_PTR dwParam2) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2); - - if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) { - /* HACK... */ - if (uMessage == 0x0001) { - *(LPDWORD)dwParam1 = 1; - return 0; - } - if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) != NULL) { - return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2); - } - return MMSYSERR_INVALHANDLE; - } - - switch (uMessage) { - case MODM_OPEN: - case MODM_CLOSE: - FIXME("can't handle OPEN or CLOSE message!\n"); - return MMSYSERR_NOTSUPPORTED; - } - return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE); -} - -/************************************************************************** - * midiInGetNumDevs [WINMM.@] - */ -UINT WINAPI midiInGetNumDevs(void) -{ - return MMDRV_GetNum(MMDRV_MIDIIN); -} - -/************************************************************************** - * midiInGetDevCapsW [WINMM.@] - */ -UINT WINAPI midiInGetDevCapsW(UINT_PTR uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize) -{ - LPWINE_MLD wmld; - - TRACE("(%d, %p, %d);\n", uDeviceID, lpCaps, uSize); - - if (lpCaps == NULL) return MMSYSERR_INVALPARAM; - - if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE); -} - -/************************************************************************** - * midiInGetDevCapsA [WINMM.@] - */ -UINT WINAPI midiInGetDevCapsA(UINT_PTR uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize) -{ - MIDIINCAPSW micW; - UINT ret; - - if (lpCaps == NULL) return MMSYSERR_INVALPARAM; - - ret = midiInGetDevCapsW(uDeviceID, &micW, sizeof(micW)); - - if (ret == MMSYSERR_NOERROR) { - MIDIINCAPSA micA; - micA.wMid = micW.wMid; - micA.wPid = micW.wPid; - micA.vDriverVersion = micW.vDriverVersion; - WideCharToMultiByte( CP_ACP, 0, micW.szPname, -1, micA.szPname, - sizeof(micA.szPname), NULL, NULL ); - micA.dwSupport = micW.dwSupport; - memcpy(lpCaps, &micA, min(uSize, sizeof(micA))); - } - return ret; -} - -UINT MIDI_InOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD_PTR dwCallback, - DWORD_PTR dwInstance, DWORD dwFlags, BOOL bFrom32) -{ - HANDLE hMidiIn; - LPWINE_MIDI lpwm; - DWORD dwRet = 0; - - TRACE("(%p, %d, %08lX, %08lX, %08lX);\n", - lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags); - - if (lphMidiIn != NULL) *lphMidiIn = 0; - - lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn, - &dwFlags, &dwCallback, &dwInstance, bFrom32); - - if (lpwm == NULL) - return MMSYSERR_NOMEM; - - lpwm->mod.hMidi = (HMIDI) hMidiIn; - lpwm->mod.dwCallback = dwCallback; - lpwm->mod.dwInstance = dwInstance; - - lpwm->mld.uDeviceID = uDeviceID; - dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD)&lpwm->mod, dwFlags); - - if (dwRet != MMSYSERR_NOERROR) { - MMDRV_Free(hMidiIn, &lpwm->mld); - hMidiIn = 0; - } - if (lphMidiIn != NULL) *lphMidiIn = hMidiIn; - TRACE("=> %ld hMidi=%p\n", dwRet, hMidiIn); - - return dwRet; -} - -/************************************************************************** - * midiInOpen [WINMM.@] - */ -UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, - DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags) -{ - return MIDI_InOpen(lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE); -} - -/************************************************************************** - * midiInClose [WINMM.@] - */ -UINT WINAPI midiInClose(HMIDIIN hMidiIn) -{ - LPWINE_MLD wmld; - DWORD dwRet; - - TRACE("(%p)\n", hMidiIn); - - if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - dwRet = MMDRV_Close(wmld, MIDM_CLOSE); - MMDRV_Free(hMidiIn, wmld); - return dwRet; -} - -/************************************************************************** - * midiInPrepareHeader [WINMM.@] - */ -UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn, - MIDIHDR* lpMidiInHdr, UINT uSize) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize); - - if (lpMidiInHdr == NULL || uSize < sizeof (MIDIHDR)) - return MMSYSERR_INVALPARAM; - - if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD_PTR)lpMidiInHdr, uSize, TRUE); -} - -/************************************************************************** - * midiInUnprepareHeader [WINMM.@] - */ -UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn, - MIDIHDR* lpMidiInHdr, UINT uSize) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize); - - if (lpMidiInHdr == NULL || uSize < sizeof (MIDIHDR)) - return MMSYSERR_INVALPARAM; - - if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) { - return MMSYSERR_NOERROR; - } - - if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD_PTR)lpMidiInHdr, uSize, TRUE); -} - -/************************************************************************** - * midiInAddBuffer [WINMM.@] - */ -UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn, - MIDIHDR* lpMidiInHdr, UINT uSize) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize); - - if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD_PTR)lpMidiInHdr, uSize, TRUE); -} - -/************************************************************************** - * midiInStart [WINMM.@] - */ -UINT WINAPI midiInStart(HMIDIIN hMidiIn) -{ - LPWINE_MLD wmld; - - TRACE("(%p)\n", hMidiIn); - - if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, MIDM_START, 0L, 0L, TRUE); -} - -/************************************************************************** - * midiInStop [WINMM.@] - */ -UINT WINAPI midiInStop(HMIDIIN hMidiIn) -{ - LPWINE_MLD wmld; - - TRACE("(%p)\n", hMidiIn); - - if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L, TRUE); -} - -/************************************************************************** - * midiInReset [WINMM.@] - */ -UINT WINAPI midiInReset(HMIDIIN hMidiIn) -{ - LPWINE_MLD wmld; - - TRACE("(%p)\n", hMidiIn); - - if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L, TRUE); -} - -/************************************************************************** - * midiInGetID [WINMM.@] - */ -UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %p)\n", hMidiIn, lpuDeviceID); - - if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM; - - if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL) - return MMSYSERR_INVALHANDLE; - - *lpuDeviceID = wmld->uDeviceID; - - return MMSYSERR_NOERROR; -} - -/************************************************************************** - * midiInMessage [WINMM.@] - */ -UINT WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage, - DWORD_PTR dwParam1, DWORD_PTR dwParam2) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2); - - if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - switch (uMessage) { - case MIDM_OPEN: - case MIDM_CLOSE: - FIXME("can't handle OPEN or CLOSE message!\n"); - return MMSYSERR_NOTSUPPORTED; - } - return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE); -} - -typedef struct WINE_MIDIStream { - HMIDIOUT hDevice; - HANDLE hThread; - DWORD dwThreadID; - DWORD dwTempo; - DWORD dwTimeDiv; - DWORD dwPositionMS; - DWORD dwPulses; - DWORD dwStartTicks; - WORD wFlags; - HANDLE hEvent; - LPMIDIHDR lpMidiHdr; -} WINE_MIDIStream; - -#define WINE_MSM_HEADER (WM_USER+0) -#define WINE_MSM_STOP (WM_USER+1) - -/************************************************************************** - * MMSYSTEM_GetMidiStream [internal] - */ -static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm) -{ - WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE); - - if (lplpwm) - *lplpwm = lpwm; - - if (lpwm == NULL) { - return FALSE; - } - - *lpMidiStrm = (WINE_MIDIStream*)lpwm->mod.rgIds.dwStreamID; - - return *lpMidiStrm != NULL; -} - -/************************************************************************** - * MMSYSTEM_MidiStream_Convert [internal] - */ -static DWORD MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse) -{ - DWORD ret = 0; - - if (lpMidiStrm->dwTimeDiv == 0) { - FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n"); - } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */ - int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */ - int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */ - ret = (pulse * 1000) / (nf * nsf); - } else { - ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) / - (double)lpMidiStrm->dwTimeDiv); - } - - return ret; -} - -/************************************************************************** - * MMSYSTEM_MidiStream_MessageHandler [internal] - */ -static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg) -{ - LPMIDIHDR lpMidiHdr; - LPMIDIHDR* lpmh; - LPBYTE lpData; - - switch (msg->message) { - case WM_QUIT: - SetEvent(lpMidiStrm->hEvent); - return FALSE; - case WINE_MSM_STOP: - TRACE("STOP\n"); - /* this is not quite what MS doc says... */ - midiOutReset(lpMidiStrm->hDevice); - /* empty list of already submitted buffers */ - for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext) { - lpMidiHdr->dwFlags |= MHDR_DONE; - lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; - - DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, - (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE, - lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L); - } - lpMidiStrm->lpMidiHdr = 0; - SetEvent(lpMidiStrm->hEvent); - break; - case WINE_MSM_HEADER: - /* sets initial tick count for first MIDIHDR */ - if (!lpMidiStrm->dwStartTicks) - lpMidiStrm->dwStartTicks = GetTickCount(); - - /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent - * by native mcimidi, it doesn't look like a correct one". - * this trick allows to throw it away... but I don't like it. - * It looks like part of the file I'm trying to play and definitively looks - * like raw midi content - * I'd really like to understand why native mcimidi sends it. Perhaps a bad - * synchronization issue where native mcimidi is still processing raw MIDI - * content before generating MIDIEVENTs ? - * - * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^.. - * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b.. - * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^. - * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x. - * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^ - * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b - * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..# - * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L.. - * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H.. - * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?. - * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E. - * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F - * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H - * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.; - * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.; - * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|. - * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|. - */ - lpMidiHdr = (LPMIDIHDR)msg->lParam; - lpData = lpMidiHdr->lpData; - TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n", - (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr, - (DWORD)lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded, - lpMidiHdr->dwFlags, msg->wParam); -#if 0 - /* dumps content of lpMidiHdr->lpData - * FIXME: there should be a debug routine somewhere that already does this - * I hate spreading this type of shit all around the code - */ - for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) { - DWORD i; - BYTE ch; - - for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) - printf("%02x ", lpData[dwToGo + i]); - for (; i < 16; i++) - printf(" "); - for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) { - ch = lpData[dwToGo + i]; - printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.'); - } - printf("\n"); - } -#endif - if (((LPMIDIEVENT)lpData)->dwStreamID != 0 && - ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF && - ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) { - FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n", - (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", - ((LPMIDIEVENT)lpData)->dwStreamID); - lpMidiHdr->dwFlags |= MHDR_DONE; - lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; - - DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, - (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE, - lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L); - break; - } - - for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = (LPMIDIHDR*)&((*lpmh)->lpNext)); - *lpmh = lpMidiHdr; - lpMidiHdr = (LPMIDIHDR)msg->lParam; - lpMidiHdr->lpNext = 0; - lpMidiHdr->dwFlags |= MHDR_INQUEUE; - lpMidiHdr->dwFlags &= ~MHDR_DONE; - lpMidiHdr->dwOffset = 0; - - break; - default: - FIXME("Unknown message %d\n", msg->message); - break; - } - return TRUE; -} - -/************************************************************************** - * MMSYSTEM_MidiStream_Player [internal] - */ -static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt) -{ - WINE_MIDIStream* lpMidiStrm = pmt; - WINE_MIDI* lpwm; - MSG msg; - DWORD dwToGo; - DWORD dwCurrTC; - LPMIDIHDR lpMidiHdr; - LPMIDIEVENT me; - LPBYTE lpData = 0; - - TRACE("(%p)!\n", lpMidiStrm); - - if (!lpMidiStrm || - (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL) - goto the_end; - - /* force thread's queue creation */ - /* Used to be InitThreadInput16(0, 5); */ - /* but following works also with hack in midiStreamOpen */ - PeekMessageA(&msg, 0, 0, 0, 0); - - /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */ - SetEvent(lpMidiStrm->hEvent); - TRACE("Ready to go 1\n"); - /* thread is started in paused mode */ - SuspendThread(lpMidiStrm->hThread); - TRACE("Ready to go 2\n"); - - lpMidiStrm->dwStartTicks = 0; - lpMidiStrm->dwPulses = 0; - - lpMidiStrm->lpMidiHdr = 0; - - for (;;) { - lpMidiHdr = lpMidiStrm->lpMidiHdr; - if (!lpMidiHdr) { - /* for first message, block until one arrives, then process all that are available */ - GetMessageA(&msg, 0, 0, 0); - do { - if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg)) - goto the_end; - } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)); - lpData = 0; - continue; - } - - if (!lpData) - lpData = lpMidiHdr->lpData; - - me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset); - - /* do we have to wait ? */ - if (me->dwDeltaTime) { - lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime); - lpMidiStrm->dwPulses += me->dwDeltaTime; - - dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS; - - TRACE("%ld/%ld/%ld\n", dwToGo, GetTickCount(), me->dwDeltaTime); - while ((dwCurrTC = GetTickCount()) < dwToGo) { - if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) { - /* got a message, handle it */ - while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) { - if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg)) - goto the_end; - } - lpData = 0; - } else { - /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */ - break; - } - } - } - switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) { - case MEVT_COMMENT: - FIXME("NIY: MEVT_COMMENT\n"); - /* do nothing, skip bytes */ - break; - case MEVT_LONGMSG: - FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n"); - break; - case MEVT_NOP: - break; - case MEVT_SHORTMSG: - midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent)); - break; - case MEVT_TEMPO: - lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent); - break; - case MEVT_VERSION: - break; - default: - FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)); - break; - } - if (me->dwEvent & MEVT_F_CALLBACK) { - DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, - (HDRVR)lpMidiStrm->hDevice, MM_MOM_POSITIONCB, - lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L); - } - lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms); - if (me->dwEvent & MEVT_F_LONG) - lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3; - if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) { - /* done with this header */ - lpMidiHdr->dwFlags |= MHDR_DONE; - lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; - - lpMidiStrm->lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext; - DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, - (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE, - lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L); - lpData = 0; - } - } -the_end: - TRACE("End of thread\n"); - ExitThread(0); - return 0; /* for removing the warning, never executed */ -} - -/************************************************************************** - * MMSYSTEM_MidiStream_PostMessage [internal] - */ -static BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2) -{ - if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) { - DWORD count; - - if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count); - WaitForSingleObject(lpMidiStrm->hEvent, INFINITE); - if (pFnRestoreThunkLock) pFnRestoreThunkLock(count); - } else { - WARN("bad PostThreadMessageA\n"); - return FALSE; - } - return TRUE; -} - -/************************************************************************** - * midiStreamClose [WINMM.@] - */ -MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm) -{ - WINE_MIDIStream* lpMidiStrm; - - TRACE("(%p)!\n", hMidiStrm); - - if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) - return MMSYSERR_INVALHANDLE; - - midiStreamStop(hMidiStrm); - MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0); - HeapFree(GetProcessHeap(), 0, lpMidiStrm); - CloseHandle(lpMidiStrm->hEvent); - - return midiOutClose((HMIDIOUT)hMidiStrm); -} - -/************************************************************************** - * MMSYSTEM_MidiStream_Open [internal] - */ -MMRESULT MIDI_StreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, DWORD cMidi, - DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen, - BOOL bFrom32) -{ - WINE_MIDIStream* lpMidiStrm; - MMRESULT ret; - MIDIOPENSTRMID mosm; - LPWINE_MIDI lpwm; - HMIDIOUT hMidiOut; - - TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n", - lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen); - - if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL) - return MMSYSERR_INVALPARAM; - - lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream)); - if (!lpMidiStrm) - return MMSYSERR_NOMEM; - - lpMidiStrm->dwTempo = 500000; - lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/ - lpMidiStrm->dwPositionMS = 0; - - mosm.dwStreamID = (DWORD)lpMidiStrm; - /* FIXME: the correct value is not allocated yet for MAPPER */ - mosm.wDeviceID = *lpuDeviceID; - lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm, bFrom32); - lpMidiStrm->hDevice = hMidiOut; - if (lphMidiStrm) - *lphMidiStrm = (HMIDISTRM)hMidiOut; - - lpwm->mld.uDeviceID = *lpuDeviceID; - - ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD)&lpwm->mod, fdwOpen); - lpMidiStrm->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); - lpMidiStrm->wFlags = HIWORD(fdwOpen); - - lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player, - lpMidiStrm, 0, &(lpMidiStrm->dwThreadID)); - - if (!lpMidiStrm->hThread) { - midiStreamClose((HMIDISTRM)hMidiOut); - return MMSYSERR_NOMEM; - } - SetThreadPriority(lpMidiStrm->hThread, THREAD_PRIORITY_TIME_CRITICAL); - - /* wait for thread to have started, and for its queue to be created */ - { - DWORD count; - - /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code, - * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running - * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue. - */ - if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count); - WaitForSingleObject(lpMidiStrm->hEvent, INFINITE); - if (pFnRestoreThunkLock) pFnRestoreThunkLock(count); - } - - TRACE("=> (%u/%d) hMidi=%p ret=%d lpMidiStrm=%p\n", - *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm); - return ret; -} - -/************************************************************************** - * midiStreamOpen [WINMM.@] - */ -MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, - DWORD cMidi, DWORD_PTR dwCallback, - DWORD_PTR dwInstance, DWORD fdwOpen) -{ - return MIDI_StreamOpen(lphMidiStrm, lpuDeviceID, cMidi, dwCallback, - dwInstance, fdwOpen, TRUE); -} - -/************************************************************************** - * midiStreamOut [WINMM.@] - */ -MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr, - UINT cbMidiHdr) -{ - WINE_MIDIStream* lpMidiStrm; - DWORD ret = MMSYSERR_NOERROR; - - TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr); - - if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { - ret = MMSYSERR_INVALHANDLE; - } else if (!lpMidiHdr) { - ret = MMSYSERR_INVALPARAM; - } else { - if (!PostThreadMessageA(lpMidiStrm->dwThreadID, - WINE_MSM_HEADER, cbMidiHdr, - (DWORD)lpMidiHdr)) { - WARN("bad PostThreadMessageA\n"); - ret = MMSYSERR_ERROR; - } - } - return ret; -} - -/************************************************************************** - * midiStreamPause [WINMM.@] - */ -MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm) -{ - WINE_MIDIStream* lpMidiStrm; - DWORD ret = MMSYSERR_NOERROR; - - TRACE("(%p)!\n", hMidiStrm); - - if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { - ret = MMSYSERR_INVALHANDLE; - } else { - if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) { - WARN("bad Suspend (%ld)\n", GetLastError()); - ret = MMSYSERR_ERROR; - } - } - return ret; -} - -/************************************************************************** - * midiStreamPosition [WINMM.@] - */ -MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt) -{ - WINE_MIDIStream* lpMidiStrm; - DWORD ret = MMSYSERR_NOERROR; - - TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt); - - if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { - ret = MMSYSERR_INVALHANDLE; - } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) { - ret = MMSYSERR_INVALPARAM; - } else { - switch (lpMMT->wType) { - case TIME_MS: - lpMMT->u.ms = lpMidiStrm->dwPositionMS; - TRACE("=> %ld ms\n", lpMMT->u.ms); - break; - case TIME_TICKS: - lpMMT->u.ticks = lpMidiStrm->dwPulses; - TRACE("=> %ld ticks\n", lpMMT->u.ticks); - break; - default: - WARN("Unsupported time type %d\n", lpMMT->wType); - lpMMT->wType = TIME_MS; - ret = MMSYSERR_INVALPARAM; - break; - } - } - return ret; -} - -/************************************************************************** - * midiStreamProperty [WINMM.@] - */ -MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty) -{ - WINE_MIDIStream* lpMidiStrm; - MMRESULT ret = MMSYSERR_NOERROR; - - TRACE("(%p, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty); - - if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { - ret = MMSYSERR_INVALHANDLE; - } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) { - ret = MMSYSERR_INVALPARAM; - } else if (dwProperty & MIDIPROP_TEMPO) { - MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData; - - if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) { - ret = MMSYSERR_INVALPARAM; - } else if (dwProperty & MIDIPROP_SET) { - lpMidiStrm->dwTempo = mpt->dwTempo; - TRACE("Setting tempo to %ld\n", mpt->dwTempo); - } else if (dwProperty & MIDIPROP_GET) { - mpt->dwTempo = lpMidiStrm->dwTempo; - TRACE("Getting tempo <= %ld\n", mpt->dwTempo); - } - } else if (dwProperty & MIDIPROP_TIMEDIV) { - MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData; - - if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) { - ret = MMSYSERR_INVALPARAM; - } else if (dwProperty & MIDIPROP_SET) { - lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv; - TRACE("Setting time div to %ld\n", mptd->dwTimeDiv); - } else if (dwProperty & MIDIPROP_GET) { - mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv; - TRACE("Getting time div <= %ld\n", mptd->dwTimeDiv); - } - } else { - ret = MMSYSERR_INVALPARAM; - } - - return ret; -} - -/************************************************************************** - * midiStreamRestart [WINMM.@] - */ -MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm) -{ - WINE_MIDIStream* lpMidiStrm; - MMRESULT ret = MMSYSERR_NOERROR; - - TRACE("(%p)!\n", hMidiStrm); - - if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { - ret = MMSYSERR_INVALHANDLE; - } else { - DWORD ret; - - /* since we increase the thread suspend count on each midiStreamPause - * there may be a need for several midiStreamResume - */ - do { - ret = ResumeThread(lpMidiStrm->hThread); - } while (ret != 0xFFFFFFFF && ret != 0); - if (ret == 0xFFFFFFFF) { - WARN("bad Resume (%ld)\n", GetLastError()); - ret = MMSYSERR_ERROR; - } else { - lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS; - } - } - return ret; -} - -/************************************************************************** - * midiStreamStop [WINMM.@] - */ -MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm) -{ - WINE_MIDIStream* lpMidiStrm; - MMRESULT ret = MMSYSERR_NOERROR; - - TRACE("(%p)!\n", hMidiStrm); - - if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { - ret = MMSYSERR_INVALHANDLE; - } else { - /* in case stream has been paused... FIXME is the current state correct ? */ - midiStreamRestart(hMidiStrm); - MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0); - } - return ret; -} - -UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType, - LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, - DWORD_PTR dwInstance, DWORD dwFlags, BOOL bFrom32) -{ - HANDLE handle; - LPWINE_MLD wmld; - DWORD dwRet = MMSYSERR_NOERROR; - WAVEOPENDESC wod; - - TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n", - lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback, - dwInstance, dwFlags, bFrom32?32:16); - - if (dwFlags & WAVE_FORMAT_QUERY) - TRACE("WAVE_FORMAT_QUERY requested !\n"); - - if (lpFormat == NULL) { - WARN("bad format\n"); - return WAVERR_BADFORMAT; - } - - if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1)) { - WARN("invalid parameter\n"); - return MMSYSERR_INVALPARAM; - } - - /* may have a PCMWAVEFORMAT rather than a WAVEFORMATEX so don't read cbSize */ - TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u\n", - lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec, - lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample); - - if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle, - &dwFlags, &dwCallback, &dwInstance, bFrom32)) == NULL) { - WARN("no memory\n"); - return MMSYSERR_NOMEM; - } - - wod.hWave = handle; - wod.lpFormat = (LPWAVEFORMATEX)lpFormat; /* should the struct be copied iso pointer? */ - wod.dwCallback = dwCallback; - wod.dwInstance = dwInstance; - wod.dnDevNode = 0L; - - TRACE("cb=%08lx\n", wod.dwCallback); - - for (;;) { - if (dwFlags & WAVE_MAPPED) { - wod.uMappedDeviceID = uDeviceID; - uDeviceID = WAVE_MAPPER; - } else { - wod.uMappedDeviceID = -1; - } - wmld->uDeviceID = uDeviceID; - - dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN, - (DWORD)&wod, dwFlags); - - TRACE("dwRet = %s\n", WINMM_ErrorToString(dwRet)); - if (dwRet != WAVERR_BADFORMAT || - ((dwFlags & (WAVE_MAPPED|WAVE_FORMAT_DIRECT)) != 0) || (uDeviceID == WAVE_MAPPER)) break; - /* if we ask for a format which isn't supported by the physical driver, - * let's try to map it through the wave mapper (except, if we already tried - * or user didn't allow us to use acm codecs or the device is already the mapper) - */ - dwFlags |= WAVE_MAPPED; - /* we shall loop only one */ - } - - if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) { - MMDRV_Free(handle, wmld); - handle = 0; - } - - if (lphndl != NULL) *lphndl = handle; - TRACE("=> %s hWave=%p\n", WINMM_ErrorToString(dwRet), handle); - - return dwRet; -} - -/************************************************************************** - * waveOutGetNumDevs [WINMM.@] - */ -UINT WINAPI waveOutGetNumDevs(void) -{ - return MMDRV_GetNum(MMDRV_WAVEOUT); -} - -/************************************************************************** - * waveOutGetDevCapsA [WINMM.@] - */ -UINT WINAPI waveOutGetDevCapsA(UINT_PTR uDeviceID, LPWAVEOUTCAPSA lpCaps, - UINT uSize) -{ - WAVEOUTCAPSW wocW; - UINT ret; - - if (lpCaps == NULL) return MMSYSERR_INVALPARAM; - - ret = waveOutGetDevCapsW(uDeviceID, &wocW, sizeof(wocW)); - - if (ret == MMSYSERR_NOERROR) { - WAVEOUTCAPSA wocA; - wocA.wMid = wocW.wMid; - wocA.wPid = wocW.wPid; - wocA.vDriverVersion = wocW.vDriverVersion; - WideCharToMultiByte( CP_ACP, 0, wocW.szPname, -1, wocA.szPname, - sizeof(wocA.szPname), NULL, NULL ); - wocA.dwFormats = wocW.dwFormats; - wocA.wChannels = wocW.wChannels; - wocA.dwSupport = wocW.dwSupport; - memcpy(lpCaps, &wocA, min(uSize, sizeof(wocA))); - } - return ret; -} - -/************************************************************************** - * waveOutGetDevCapsW [WINMM.@] - */ -UINT WINAPI waveOutGetDevCapsW(UINT_PTR uDeviceID, LPWAVEOUTCAPSW lpCaps, - UINT uSize) -{ - LPWINE_MLD wmld; - - TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize); - - if (lpCaps == NULL) return MMSYSERR_INVALPARAM; - - if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL) - return MMSYSERR_BADDEVICEID; - - return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE); - -} - -/************************************************************************** - * waveOutGetErrorTextA [WINMM.@] - * waveInGetErrorTextA [WINMM.@] - */ -UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize) -{ - UINT ret; - - if (lpText == NULL) ret = MMSYSERR_INVALPARAM; - else if (uSize == 0) ret = MMSYSERR_NOERROR; - else - { - LPWSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize * sizeof(WCHAR)); - if (!xstr) ret = MMSYSERR_NOMEM; - else - { - ret = waveOutGetErrorTextW(uError, xstr, uSize); - if (ret == MMSYSERR_NOERROR) - WideCharToMultiByte(CP_ACP, 0, xstr, -1, lpText, uSize, NULL, NULL); - HeapFree(GetProcessHeap(), 0, xstr); - } - } - return ret; -} - -/************************************************************************** - * waveOutGetErrorTextW [WINMM.@] - * waveInGetErrorTextW [WINMM.@] - */ -UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize) -{ - UINT ret = MMSYSERR_BADERRNUM; - - if (lpText == NULL) ret = MMSYSERR_INVALPARAM; - else if (uSize == 0) ret = MMSYSERR_NOERROR; - else if ( - /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit - * a warning for the test was always true */ - (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) || - (uError >= WAVERR_BASE && uError <= WAVERR_LASTERROR)) { - if (LoadStringW(WINMM_IData.hWinMM32Instance, - uError, lpText, uSize) > 0) { - ret = MMSYSERR_NOERROR; - } - } - return ret; -} - -/************************************************************************** - * waveOutOpen [WINMM.@] - * All the args/structs have the same layout as the win16 equivalents - */ -MMRESULT WINAPI waveOutOpen(LPHWAVEOUT lphWaveOut, UINT uDeviceID, - LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, - DWORD_PTR dwInstance, DWORD dwFlags) -{ - return WAVE_Open((HANDLE*)lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat, - dwCallback, dwInstance, dwFlags, TRUE); -} - -/************************************************************************** - * waveOutClose [WINMM.@] - */ -UINT WINAPI waveOutClose(HWAVEOUT hWaveOut) -{ - LPWINE_MLD wmld; - DWORD dwRet; - - TRACE("(%p)\n", hWaveOut); - - if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - dwRet = MMDRV_Close(wmld, WODM_CLOSE); - if (dwRet != WAVERR_STILLPLAYING) - MMDRV_Free(hWaveOut, wmld); - - return dwRet; -} - -/************************************************************************** - * waveOutPrepareHeader [WINMM.@] - */ -UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut, - WAVEHDR* lpWaveOutHdr, UINT uSize) -{ - LPWINE_MLD wmld; - UINT result; - - TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize); - - if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR)) - return MMSYSERR_INVALPARAM; - - if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - if ((result = MMDRV_Message(wmld, WODM_PREPARE, (DWORD_PTR)lpWaveOutHdr, - uSize, TRUE)) != MMSYSERR_NOTSUPPORTED) - return result; - - if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE) - return WAVERR_STILLPLAYING; - - lpWaveOutHdr->dwFlags |= WHDR_PREPARED; - lpWaveOutHdr->dwFlags &= ~WHDR_DONE; - - return MMSYSERR_NOERROR; -} - -/************************************************************************** - * waveOutUnprepareHeader [WINMM.@] - */ -UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut, - LPWAVEHDR lpWaveOutHdr, UINT uSize) -{ - LPWINE_MLD wmld; - UINT result; - - TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize); - - if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR)) - return MMSYSERR_INVALPARAM; - - if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) { - return MMSYSERR_NOERROR; - } - - if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - if ((result = MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD_PTR)lpWaveOutHdr, - uSize, TRUE)) != MMSYSERR_NOTSUPPORTED) - return result; - - if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE) - return WAVERR_STILLPLAYING; - - lpWaveOutHdr->dwFlags &= ~WHDR_PREPARED; - lpWaveOutHdr->dwFlags |= WHDR_DONE; - - return MMSYSERR_NOERROR; -} - -/************************************************************************** - * waveOutWrite [WINMM.@] - */ -UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr, - UINT uSize) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize); - - if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, WODM_WRITE, (DWORD_PTR)lpWaveOutHdr, uSize, TRUE); -} - -/************************************************************************** - * waveOutBreakLoop [WINMM.@] - */ -UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut) -{ - LPWINE_MLD wmld; - - TRACE("(%p);\n", hWaveOut); - - if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L, TRUE); -} - -/************************************************************************** - * waveOutPause [WINMM.@] - */ -UINT WINAPI waveOutPause(HWAVEOUT hWaveOut) -{ - LPWINE_MLD wmld; - - TRACE("(%p);\n", hWaveOut); - - if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L, TRUE); -} - -/************************************************************************** - * waveOutReset [WINMM.@] - */ -UINT WINAPI waveOutReset(HWAVEOUT hWaveOut) -{ - LPWINE_MLD wmld; - - TRACE("(%p);\n", hWaveOut); - - if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - return MMDRV_Message(wmld, WODM_RESET, 0L, 0L, TRUE); -} - -/************************************************************************** - * waveOutRestart [WINMM.@] - */ -UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut) -{ - LPWINE_MLD wmld; - - TRACE("(%p);\n", hWaveOut); - - if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L, TRUE); -} - -/************************************************************************** - * waveOutGetPosition [WINMM.@] - */ -UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime, - UINT uSize) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %p, %u);\n", hWaveOut, lpTime, uSize); - - if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, WODM_GETPOS, (DWORD_PTR)lpTime, uSize, TRUE); -} - -/************************************************************************** - * waveOutGetPitch [WINMM.@] - */ -UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw); - - if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD_PTR)lpdw, 0L, TRUE); -} - -/************************************************************************** - * waveOutSetPitch [WINMM.@] - */ -UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw); - - if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L, TRUE); -} - -/************************************************************************** - * waveOutGetPlaybackRate [WINMM.@] - */ -UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw); - - if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD_PTR)lpdw, 0L, TRUE); -} - -/************************************************************************** - * waveOutSetPlaybackRate [WINMM.@] - */ -UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw); - - if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L, TRUE); -} - -/************************************************************************** - * waveOutGetVolume [WINMM.@] - */ -UINT WINAPI waveOutGetVolume(HWAVEOUT hWaveOut, LPDWORD lpdw) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw); - - if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD_PTR)lpdw, 0L, TRUE); -} - -/************************************************************************** - * waveOutSetVolume [WINMM.@] - */ -UINT WINAPI waveOutSetVolume(HWAVEOUT hWaveOut, DWORD dw) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %08lx);\n", hWaveOut, dw); - - if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L, TRUE); -} - -/************************************************************************** - * waveOutGetID [WINMM.@] - */ -UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %p);\n", hWaveOut, lpuDeviceID); - - if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE; - - if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - *lpuDeviceID = wmld->uDeviceID; - return 0; -} - -/************************************************************************** - * waveOutMessage [WINMM.@] - */ -UINT WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage, - DWORD_PTR dwParam1, DWORD_PTR dwParam2) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2); - - if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) { - if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) { - return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2); - } - WARN("invalid handle\n"); - return MMSYSERR_INVALHANDLE; - } - - /* from M$ KB */ - if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) { - WARN("invalid parameter\n"); - return MMSYSERR_INVALPARAM; - } - - return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE); -} - -/************************************************************************** - * waveInGetNumDevs [WINMM.@] - */ -UINT WINAPI waveInGetNumDevs(void) -{ - return MMDRV_GetNum(MMDRV_WAVEIN); -} - -/************************************************************************** - * waveInGetDevCapsW [WINMM.@] - */ -UINT WINAPI waveInGetDevCapsW(UINT_PTR uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize) -{ - LPWINE_MLD wmld; - - TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize); - - if (lpCaps == NULL) return MMSYSERR_INVALPARAM; - - if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL) - return MMSYSERR_BADDEVICEID; - - return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE); -} - -/************************************************************************** - * waveInGetDevCapsA [WINMM.@] - */ -UINT WINAPI waveInGetDevCapsA(UINT_PTR uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize) -{ - WAVEINCAPSW wicW; - UINT ret; - - if (lpCaps == NULL) return MMSYSERR_INVALPARAM; - - ret = waveInGetDevCapsW(uDeviceID, &wicW, sizeof(wicW)); - - if (ret == MMSYSERR_NOERROR) { - WAVEINCAPSA wicA; - wicA.wMid = wicW.wMid; - wicA.wPid = wicW.wPid; - wicA.vDriverVersion = wicW.vDriverVersion; - WideCharToMultiByte( CP_ACP, 0, wicW.szPname, -1, wicA.szPname, - sizeof(wicA.szPname), NULL, NULL ); - wicA.dwFormats = wicW.dwFormats; - wicA.wChannels = wicW.wChannels; - memcpy(lpCaps, &wicA, min(uSize, sizeof(wicA))); - } - return ret; -} - -/************************************************************************** - * waveInOpen [WINMM.@] - */ -MMRESULT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID, - LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, - DWORD_PTR dwInstance, DWORD dwFlags) -{ - return WAVE_Open((HANDLE*)lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat, - dwCallback, dwInstance, dwFlags, TRUE); -} - -/************************************************************************** - * waveInClose [WINMM.@] - */ -UINT WINAPI waveInClose(HWAVEIN hWaveIn) -{ - LPWINE_MLD wmld; - DWORD dwRet; - - TRACE("(%p)\n", hWaveIn); - - if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L, TRUE); - if (dwRet != WAVERR_STILLPLAYING) - MMDRV_Free(hWaveIn, wmld); - return dwRet; -} - -/************************************************************************** - * waveInPrepareHeader [WINMM.@] - */ -UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr, - UINT uSize) -{ - LPWINE_MLD wmld; - UINT result; - - TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize); - - if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR)) - return MMSYSERR_INVALPARAM; - - if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - if ((result = MMDRV_Message(wmld, WIDM_PREPARE, (DWORD_PTR)lpWaveInHdr, - uSize, TRUE)) != MMSYSERR_NOTSUPPORTED) - return result; - - if (lpWaveInHdr->dwFlags & WHDR_INQUEUE) - return WAVERR_STILLPLAYING; - - lpWaveInHdr->dwFlags |= WHDR_PREPARED; - lpWaveInHdr->dwFlags &= ~WHDR_DONE; - lpWaveInHdr->dwBytesRecorded = 0; - - return MMSYSERR_NOERROR; -} - -/************************************************************************** - * waveInUnprepareHeader [WINMM.@] - */ -UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr, - UINT uSize) -{ - LPWINE_MLD wmld; - UINT result; - - TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize); - - if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR)) - return MMSYSERR_INVALPARAM; - - if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) - return MMSYSERR_NOERROR; - - if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - if ((result = MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD_PTR)lpWaveInHdr, - uSize, TRUE)) != MMSYSERR_NOTSUPPORTED) - return result; - - if (lpWaveInHdr->dwFlags & WHDR_INQUEUE) - return WAVERR_STILLPLAYING; - - lpWaveInHdr->dwFlags &= ~WHDR_PREPARED; - lpWaveInHdr->dwFlags |= WHDR_DONE; - - return MMSYSERR_NOERROR; -} - -/************************************************************************** - * waveInAddBuffer [WINMM.@] - */ -UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn, - WAVEHDR* lpWaveInHdr, UINT uSize) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize); - - if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM; - if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD_PTR)lpWaveInHdr, uSize, TRUE); -} - -/************************************************************************** - * waveInReset [WINMM.@] - */ -UINT WINAPI waveInReset(HWAVEIN hWaveIn) -{ - LPWINE_MLD wmld; - - TRACE("(%p);\n", hWaveIn); - - if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L, TRUE); -} - -/************************************************************************** - * waveInStart [WINMM.@] - */ -UINT WINAPI waveInStart(HWAVEIN hWaveIn) -{ - LPWINE_MLD wmld; - - TRACE("(%p);\n", hWaveIn); - - if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, WIDM_START, 0L, 0L, TRUE); -} - -/************************************************************************** - * waveInStop [WINMM.@] - */ -UINT WINAPI waveInStop(HWAVEIN hWaveIn) -{ - LPWINE_MLD wmld; - - TRACE("(%p);\n", hWaveIn); - - if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L, TRUE); -} - -/************************************************************************** - * waveInGetPosition [WINMM.@] - */ -UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime, - UINT uSize) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %p, %u);\n", hWaveIn, lpTime, uSize); - - if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD_PTR)lpTime, uSize, TRUE); -} - -/************************************************************************** - * waveInGetID [WINMM.@] - */ -UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %p);\n", hWaveIn, lpuDeviceID); - - if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE; - - if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) - return MMSYSERR_INVALHANDLE; - - *lpuDeviceID = wmld->uDeviceID; - return MMSYSERR_NOERROR; -} - -/************************************************************************** - * waveInMessage [WINMM.@] - */ -UINT WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage, - DWORD_PTR dwParam1, DWORD_PTR dwParam2) -{ - LPWINE_MLD wmld; - - TRACE("(%p, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2); - - if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) { - if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, TRUE)) != NULL) { - return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2); - } - return MMSYSERR_INVALHANDLE; - } - - /* from M$ KB */ - if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) - return MMSYSERR_INVALPARAM; - - - return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE); -} - -struct mm_starter -{ - LPTASKCALLBACK cb; - DWORD client; - HANDLE event; -}; - -static DWORD WINAPI mmTaskRun(void* pmt) -{ - struct mm_starter mms; - - memcpy(&mms, pmt, sizeof(struct mm_starter)); - HeapFree(GetProcessHeap(), 0, pmt); - mms.cb(mms.client); - if (mms.event) SetEvent(mms.event); - return 0; -} - -/****************************************************************** - * mmTaskCreate (WINMM.@) - */ -MMRESULT WINAPI mmTaskCreate(LPTASKCALLBACK cb, HANDLE* ph, DWORD client) -{ - HANDLE hThread; - HANDLE hEvent = 0; - struct mm_starter *mms; - - mms = HeapAlloc(GetProcessHeap(), 0, sizeof(struct mm_starter)); - if (mms == NULL) return TASKERR_OUTOFMEMORY; - - mms->cb = cb; - mms->client = client; - if (ph) hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); - mms->event = hEvent; - - hThread = CreateThread(0, 0, mmTaskRun, mms, 0, NULL); - if (!hThread) { - HeapFree(GetProcessHeap(), 0, mms); - if (hEvent) CloseHandle(hEvent); - return TASKERR_OUTOFMEMORY; - } - SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL); - if (ph) *ph = hEvent; - CloseHandle(hThread); - return 0; -} - -/****************************************************************** - * mmTaskBlock (WINMM.@) - */ -void WINAPI mmTaskBlock(HANDLE tid) -{ - MSG msg; - - do - { - GetMessageA(&msg, 0, 0, 0); - if (msg.hwnd) DispatchMessageA(&msg); - } while (msg.message != WM_USER); -} - -/****************************************************************** - * mmTaskSignal (WINMM.@) - */ -BOOL WINAPI mmTaskSignal(HANDLE tid) -{ - return PostThreadMessageW((DWORD)tid, WM_USER, 0, 0); -} - -/****************************************************************** - * mmTaskYield (WINMM.@) - */ -void WINAPI mmTaskYield(void) {} - -/****************************************************************** - * mmGetCurrentTask (WINMM.@) - */ -HANDLE WINAPI mmGetCurrentTask(void) -{ - return (HANDLE)GetCurrentThreadId(); -} +/* -*- tab-width: 8; c-basic-offset: 4 -*- */ + +/* + * WINMM functions + * + * Copyright 1993 Martin Ayotte + * 1998-2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Eric POUECH : + * 98/9 added Win32 MCI support + * 99/4 added midiStream support + * 99/9 added support for loadable low level drivers + */ + +/* TODO + * + it seems that some programs check what's installed in + * registry against the value returned by drivers. Wine is + * currently broken regarding this point. + * + check thread-safeness for MMSYSTEM and WINMM entry points + * + unicode entry points are badly supported (would require + * moving 32 bit drivers as Unicode as they are supposed to be) + * + allow joystick and timer external calls as we do for wave, + * midi, mixer and aux + */ + +#include <stdio.h> +#include <stdarg.h> +#include <string.h> + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "windef.h" +#include "winbase.h" +#include "mmsystem.h" +#include "winuser.h" +#include "winnls.h" +#include "winreg.h" +#include "winternl.h" +#include "winemm.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winmm); + +void (WINAPI *pFnReleaseThunkLock)(DWORD*); +void (WINAPI *pFnRestoreThunkLock)(DWORD); + +/* ======================================================================== + * G L O B A L S E T T I N G S + * ========================================================================*/ + +WINE_MM_IDATA WINMM_IData; + +/************************************************************************** + * WINMM_CreateIData [internal] + */ +static BOOL WINMM_CreateIData(HINSTANCE hInstDLL) +{ + memset( &WINMM_IData, 0, sizeof WINMM_IData ); + + WINMM_IData.hWinMM32Instance = hInstDLL; + InitializeCriticalSection(&WINMM_IData.cs); +/* FIXME crashes in ReactOS + WINMM_IData.cs.DebugInfo->Spare[1] = (DWORD)"WINMM_IData"; +*/ + WINMM_IData.psStopEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + WINMM_IData.psLastEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + TRACE("Initialized IData (%p)\n", &WINMM_IData); + return TRUE; +} + +/************************************************************************** + * WINMM_DeleteIData [internal] + */ +static void WINMM_DeleteIData(void) +{ + TIME_MMTimeStop(); + + /* FIXME: should also free content and resources allocated + * inside WINMM_IData */ + CloseHandle(WINMM_IData.psStopEvent); + CloseHandle(WINMM_IData.psLastEvent); + DeleteCriticalSection(&WINMM_IData.cs); +} + +/****************************************************************** + * WINMM_LoadMMSystem + * + */ +#ifndef __REACTOS__ +static HANDLE (WINAPI *pGetModuleHandle16)(LPCSTR); +static DWORD (WINAPI *pLoadLibrary16)(LPCSTR); +#endif + +BOOL WINMM_CheckForMMSystem(void) +{ + /* 0 is not checked yet, -1 is not present, 1 is present */ + static int loaded /* = 0 */; + + if (loaded == 0) + { + HANDLE h = GetModuleHandleA("kernel32"); + loaded = -1; + if (h) + { +#ifndef __REACTOS__ + pGetModuleHandle16 = (void*)GetProcAddress(h, "GetModuleHandle16"); + pLoadLibrary16 = (void*)GetProcAddress(h, "LoadLibrary16"); + if (pGetModuleHandle16 && pLoadLibrary16 && + (pGetModuleHandle16("MMSYSTEM.DLL") || pLoadLibrary16("MMSYSTEM.DLL"))) +#endif /* __REACTOS__ */ + loaded = 1; + } + } + return loaded > 0; +} + +/****************************************************************** + * WINMM_ErrorToString + */ +const char* WINMM_ErrorToString(MMRESULT error) +{ +#define ERR_TO_STR(dev) case dev: return #dev + static char unknown[32]; + switch (error) { + ERR_TO_STR(MMSYSERR_NOERROR); + ERR_TO_STR(MMSYSERR_ERROR); + ERR_TO_STR(MMSYSERR_BADDEVICEID); + ERR_TO_STR(MMSYSERR_NOTENABLED); + ERR_TO_STR(MMSYSERR_ALLOCATED); + ERR_TO_STR(MMSYSERR_INVALHANDLE); + ERR_TO_STR(MMSYSERR_NODRIVER); + ERR_TO_STR(MMSYSERR_NOMEM); + ERR_TO_STR(MMSYSERR_NOTSUPPORTED); + ERR_TO_STR(MMSYSERR_BADERRNUM); + ERR_TO_STR(MMSYSERR_INVALFLAG); + ERR_TO_STR(MMSYSERR_INVALPARAM); + ERR_TO_STR(MMSYSERR_HANDLEBUSY); + ERR_TO_STR(MMSYSERR_INVALIDALIAS); + ERR_TO_STR(MMSYSERR_BADDB); + ERR_TO_STR(MMSYSERR_KEYNOTFOUND); + ERR_TO_STR(MMSYSERR_READERROR); + ERR_TO_STR(MMSYSERR_WRITEERROR); + ERR_TO_STR(MMSYSERR_DELETEERROR); + ERR_TO_STR(MMSYSERR_VALNOTFOUND); + ERR_TO_STR(MMSYSERR_NODRIVERCB); + ERR_TO_STR(WAVERR_BADFORMAT); + ERR_TO_STR(WAVERR_STILLPLAYING); + ERR_TO_STR(WAVERR_UNPREPARED); + ERR_TO_STR(WAVERR_SYNC); + } + sprintf(unknown, "Unknown(0x%08x)", error); + return unknown; +#undef ERR_TO_STR +} + +/************************************************************************** + * DllMain (WINMM.init) + * + * WINMM DLL entry point + * + */ +BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad) +{ + TRACE("%p 0x%lx %p\n", hInstDLL, fdwReason, fImpLoad); + + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hInstDLL); + + if (!WINMM_CreateIData(hInstDLL)) + return FALSE; + if (!MMDRV_Init()) { + WINMM_DeleteIData(); + return FALSE; + } + break; + case DLL_PROCESS_DETACH: + /* close all opened MCI drivers */ + MCI_SendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, MCI_WAIT, 0L, TRUE); + MMDRV_Exit(); + /* now unload all remaining drivers... */ + DRIVER_UnloadAll(); + + WINMM_DeleteIData(); + break; + } + return TRUE; +} + +/************************************************************************** + * Mixer devices. New to Win95 + */ + +/************************************************************************** + * find out the real mixer ID depending on hmix (depends on dwFlags) + */ +static UINT MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags, LPWINE_MIXER * lplpwm) +{ + LPWINE_MIXER lpwm = NULL; + UINT uRet = MMSYSERR_NOERROR; + + switch (dwFlags & 0xF0000000ul) { + case MIXER_OBJECTF_MIXER: + lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE); + break; + case MIXER_OBJECTF_HMIXER: + lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE); + break; + case MIXER_OBJECTF_WAVEOUT: + lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE, MMDRV_MIXER); + break; + case MIXER_OBJECTF_HWAVEOUT: + lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER); + break; + case MIXER_OBJECTF_WAVEIN: + lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, TRUE, MMDRV_MIXER); + break; + case MIXER_OBJECTF_HWAVEIN: + lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN, FALSE, MMDRV_MIXER); + break; + case MIXER_OBJECTF_MIDIOUT: + lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE, MMDRV_MIXER); + break; + case MIXER_OBJECTF_HMIDIOUT: + lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER); + break; + case MIXER_OBJECTF_MIDIIN: + lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, TRUE, MMDRV_MIXER); + break; + case MIXER_OBJECTF_HMIDIIN: + lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN, FALSE, MMDRV_MIXER); + break; + case MIXER_OBJECTF_AUX: + lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX, TRUE, MMDRV_MIXER); + break; + default: + WARN("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul); + lpwm = 0; + uRet = MMSYSERR_INVALFLAG; + break; + } + *lplpwm = lpwm; + if (lpwm == 0 && uRet == MMSYSERR_NOERROR) + uRet = MMSYSERR_INVALPARAM; + return uRet; +} + +/************************************************************************** + * mixerGetNumDevs [WINMM.@] + */ +UINT WINAPI mixerGetNumDevs(void) +{ + return MMDRV_GetNum(MMDRV_MIXER); +} + +/************************************************************************** + * mixerGetDevCapsA [WINMM.@] + */ +UINT WINAPI mixerGetDevCapsA(UINT_PTR uDeviceID, LPMIXERCAPSA lpCaps, UINT uSize) +{ + MIXERCAPSW micW; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = mixerGetDevCapsW(uDeviceID, &micW, sizeof(micW)); + + if (ret == MMSYSERR_NOERROR) { + MIXERCAPSA micA; + micA.wMid = micW.wMid; + micA.wPid = micW.wPid; + micA.vDriverVersion = micW.vDriverVersion; + WideCharToMultiByte( CP_ACP, 0, micW.szPname, -1, micA.szPname, + sizeof(micA.szPname), NULL, NULL ); + micA.fdwSupport = micW.fdwSupport; + micA.cDestinations = micW.cDestinations; + memcpy(lpCaps, &micA, min(uSize, sizeof(micA))); + } + return ret; +} + +/************************************************************************** + * mixerGetDevCapsW [WINMM.@] + */ +UINT WINAPI mixerGetDevCapsW(UINT_PTR uDeviceID, LPMIXERCAPSW lpCaps, UINT uSize) +{ + LPWINE_MLD wmld; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIXER, TRUE)) == NULL) + return MMSYSERR_BADDEVICEID; + + return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE); +} + +UINT MIXER_Open(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback, + DWORD_PTR dwInstance, DWORD fdwOpen, BOOL bFrom32) +{ + HANDLE hMix; + LPWINE_MLD wmld; + DWORD dwRet = 0; + MIXEROPENDESC mod; + + TRACE("(%p, %d, %08lx, %08lx, %08lx)\n", + lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen); + + wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen, + &dwCallback, &dwInstance, bFrom32); + + wmld->uDeviceID = uDeviceID; + mod.hmx = (HMIXEROBJ)hMix; + mod.dwCallback = dwCallback; + mod.dwInstance = dwInstance; + + dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD)&mod, fdwOpen); + + if (dwRet != MMSYSERR_NOERROR) { + MMDRV_Free(hMix, wmld); + hMix = 0; + } + if (lphMix) *lphMix = hMix; + TRACE("=> %ld hMixer=%p\n", dwRet, hMix); + + return dwRet; +} + +/************************************************************************** + * mixerOpen [WINMM.@] + */ +UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback, + DWORD_PTR dwInstance, DWORD fdwOpen) +{ + return MIXER_Open(lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen, TRUE); +} + +/************************************************************************** + * mixerClose [WINMM.@] + */ +UINT WINAPI mixerClose(HMIXER hMix) +{ + LPWINE_MLD wmld; + DWORD dwRet; + + TRACE("(%p)\n", hMix); + + if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE; + + dwRet = MMDRV_Close(wmld, MXDM_CLOSE); + MMDRV_Free(hMix, wmld); + + return dwRet; +} + +/************************************************************************** + * mixerGetID [WINMM.@] + */ +UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID) +{ + LPWINE_MIXER lpwm; + UINT uRet = MMSYSERR_NOERROR; + + TRACE("(%p %p %08lx)\n", hmix, lpid, fdwID); + + if ((uRet = MIXER_GetDev(hmix, fdwID, &lpwm)) != MMSYSERR_NOERROR) + return uRet; + + if (lpid) + *lpid = lpwm->mld.uDeviceID; + + return uRet; +} + +/************************************************************************** + * mixerGetControlDetailsW [WINMM.@] + */ +UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdW, + DWORD fdwDetails) +{ + LPWINE_MIXER lpwm; + UINT uRet = MMSYSERR_NOERROR; + + TRACE("(%p, %p, %08lx)\n", hmix, lpmcdW, fdwDetails); + + if ((uRet = MIXER_GetDev(hmix, fdwDetails, &lpwm)) != MMSYSERR_NOERROR) + return uRet; + + if (lpmcdW == NULL || lpmcdW->cbStruct != sizeof(*lpmcdW)) + return MMSYSERR_INVALPARAM; + + return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD_PTR)lpmcdW, + fdwDetails, TRUE); +} + +/************************************************************************** + * mixerGetControlDetailsA [WINMM.@] + */ +UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA, + DWORD fdwDetails) +{ + DWORD ret = MMSYSERR_NOTENABLED; + + TRACE("(%p, %p, %08lx)\n", hmix, lpmcdA, fdwDetails); + + if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA)) + return MMSYSERR_INVALPARAM; + + switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) { + case MIXER_GETCONTROLDETAILSF_VALUE: + /* can savely use A structure as it is, no string inside */ + ret = mixerGetControlDetailsW(hmix, lpmcdA, fdwDetails); + break; + case MIXER_GETCONTROLDETAILSF_LISTTEXT: + { + MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA = (MIXERCONTROLDETAILS_LISTTEXTA *)lpmcdA->paDetails; + MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW; + int size = max(1, lpmcdA->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTW); + unsigned int i; + + if (lpmcdA->u.cMultipleItems != 0) { + size *= lpmcdA->u.cMultipleItems; + } + pDetailsW = HeapAlloc(GetProcessHeap(), 0, size); + lpmcdA->paDetails = pDetailsW; + lpmcdA->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW); + /* set up lpmcd->paDetails */ + ret = mixerGetControlDetailsW(hmix, lpmcdA, fdwDetails); + /* copy from lpmcd->paDetails back to paDetailsW; */ + if (ret == MMSYSERR_NOERROR) { + for (i = 0; i < lpmcdA->u.cMultipleItems * lpmcdA->cChannels; i++) { + pDetailsA->dwParam1 = pDetailsW->dwParam1; + pDetailsA->dwParam2 = pDetailsW->dwParam2; + WideCharToMultiByte( CP_ACP, 0, pDetailsW->szName, -1, + pDetailsA->szName, + sizeof(pDetailsA->szName), NULL, NULL ); + pDetailsA++; + pDetailsW++; + } + pDetailsA -= lpmcdA->u.cMultipleItems * lpmcdA->cChannels; + pDetailsW -= lpmcdA->u.cMultipleItems * lpmcdA->cChannels; + } + HeapFree(GetProcessHeap(), 0, pDetailsW); + lpmcdA->paDetails = pDetailsA; + lpmcdA->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA); + } + break; + default: + ERR("Unsupported fdwDetails=0x%08lx\n", fdwDetails); + } + + return ret; +} + +/************************************************************************** + * mixerGetLineControlsA [WINMM.@] + */ +UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA, + DWORD fdwControls) +{ + MIXERLINECONTROLSW mlcW; + DWORD ret; + unsigned int i; + + TRACE("(%p, %p, %08lx)\n", hmix, lpmlcA, fdwControls); + + if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA) || + lpmlcA->cbmxctrl != sizeof(MIXERCONTROLA)) + return MMSYSERR_INVALPARAM; + + mlcW.cbStruct = sizeof(mlcW); + mlcW.dwLineID = lpmlcA->dwLineID; + mlcW.u.dwControlID = lpmlcA->u.dwControlID; + mlcW.u.dwControlType = lpmlcA->u.dwControlType; + + /* Debugging on Windows shows for MIXER_GETLINECONTROLSF_ONEBYTYPE only, + the control count is assumed to be 1 - This is relied upon by a game, + "Dynomite Deluze" */ + if (MIXER_GETLINECONTROLSF_ONEBYTYPE == fdwControls) { + mlcW.cControls = 1; + } else { + mlcW.cControls = lpmlcA->cControls; + } + mlcW.cbmxctrl = sizeof(MIXERCONTROLW); + mlcW.pamxctrl = HeapAlloc(GetProcessHeap(), 0, + mlcW.cControls * mlcW.cbmxctrl); + + ret = mixerGetLineControlsW(hmix, &mlcW, fdwControls); + + if (ret == MMSYSERR_NOERROR) { + lpmlcA->dwLineID = mlcW.dwLineID; + lpmlcA->u.dwControlID = mlcW.u.dwControlID; + lpmlcA->u.dwControlType = mlcW.u.dwControlType; + lpmlcA->cControls = mlcW.cControls; + + for (i = 0; i < mlcW.cControls; i++) { + lpmlcA->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLA); + lpmlcA->pamxctrl[i].dwControlID = mlcW.pamxctrl[i].dwControlID; + lpmlcA->pamxctrl[i].dwControlType = mlcW.pamxctrl[i].dwControlType; + lpmlcA->pamxctrl[i].fdwControl = mlcW.pamxctrl[i].fdwControl; + lpmlcA->pamxctrl[i].cMultipleItems = mlcW.pamxctrl[i].cMultipleItems; + WideCharToMultiByte( CP_ACP, 0, mlcW.pamxctrl[i].szShortName, -1, + lpmlcA->pamxctrl[i].szShortName, + sizeof(lpmlcA->pamxctrl[i].szShortName), NULL, NULL ); + WideCharToMultiByte( CP_ACP, 0, mlcW.pamxctrl[i].szName, -1, + lpmlcA->pamxctrl[i].szName, + sizeof(lpmlcA->pamxctrl[i].szName), NULL, NULL ); + /* sizeof(lpmlcA->pamxctrl[i].Bounds) == + * sizeof(mlcW.pamxctrl[i].Bounds) */ + memcpy(&lpmlcA->pamxctrl[i].Bounds, &mlcW.pamxctrl[i].Bounds, + sizeof(mlcW.pamxctrl[i].Bounds)); + /* sizeof(lpmlcA->pamxctrl[i].Metrics) == + * sizeof(mlcW.pamxctrl[i].Metrics) */ + memcpy(&lpmlcA->pamxctrl[i].Metrics, &mlcW.pamxctrl[i].Metrics, + sizeof(mlcW.pamxctrl[i].Metrics)); + } + } + + HeapFree(GetProcessHeap(), 0, mlcW.pamxctrl); + + return ret; +} + +/************************************************************************** + * mixerGetLineControlsW [WINMM.@] + */ +UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW, + DWORD fdwControls) +{ + LPWINE_MIXER lpwm; + UINT uRet = MMSYSERR_NOERROR; + + TRACE("(%p, %p, %08lx)\n", hmix, lpmlcW, fdwControls); + + if ((uRet = MIXER_GetDev(hmix, fdwControls, &lpwm)) != MMSYSERR_NOERROR) + return uRet; + + if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW)) + return MMSYSERR_INVALPARAM; + + return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD_PTR)lpmlcW, + fdwControls, TRUE); +} + +/************************************************************************** + * mixerGetLineInfoW [WINMM.@] + */ +UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW, DWORD fdwInfo) +{ + LPWINE_MIXER lpwm; + UINT uRet = MMSYSERR_NOERROR; + + TRACE("(%p, %p, %08lx)\n", hmix, lpmliW, fdwInfo); + + if ((uRet = MIXER_GetDev(hmix, fdwInfo, &lpwm)) != MMSYSERR_NOERROR) + return uRet; + + return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD_PTR)lpmliW, + fdwInfo, TRUE); +} + +/************************************************************************** + * mixerGetLineInfoA [WINMM.@] + */ +UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliA, + DWORD fdwInfo) +{ + MIXERLINEW mliW; + UINT ret; + + TRACE("(%p, %p, %08lx)\n", hmix, lpmliA, fdwInfo); + + if (lpmliA == NULL || lpmliA->cbStruct != sizeof(*lpmliA)) + return MMSYSERR_INVALPARAM; + + mliW.cbStruct = sizeof(mliW); + switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) { + case MIXER_GETLINEINFOF_COMPONENTTYPE: + mliW.dwComponentType = lpmliA->dwComponentType; + break; + case MIXER_GETLINEINFOF_DESTINATION: + mliW.dwDestination = lpmliA->dwDestination; + break; + case MIXER_GETLINEINFOF_LINEID: + mliW.dwLineID = lpmliA->dwLineID; + break; + case MIXER_GETLINEINFOF_SOURCE: + mliW.dwDestination = lpmliA->dwDestination; + mliW.dwSource = lpmliA->dwSource; + break; + case MIXER_GETLINEINFOF_TARGETTYPE: + mliW.Target.dwType = lpmliA->Target.dwType; + mliW.Target.wMid = lpmliA->Target.wMid; + mliW.Target.wPid = lpmliA->Target.wPid; + mliW.Target.vDriverVersion = lpmliA->Target.vDriverVersion; + MultiByteToWideChar( CP_ACP, 0, lpmliA->Target.szPname, -1, mliW.Target.szPname, sizeof(mliW.Target.szPname)); + break; + default: + WARN("Unsupported fdwControls=0x%08lx\n", fdwInfo); + return MMSYSERR_INVALFLAG; + } + + ret = mixerGetLineInfoW(hmix, &mliW, fdwInfo); + + lpmliA->dwDestination = mliW.dwDestination; + lpmliA->dwSource = mliW.dwSource; + lpmliA->dwLineID = mliW.dwLineID; + lpmliA->fdwLine = mliW.fdwLine; + lpmliA->dwUser = mliW.dwUser; + lpmliA->dwComponentType = mliW.dwComponentType; + lpmliA->cChannels = mliW.cChannels; + lpmliA->cConnections = mliW.cConnections; + lpmliA->cControls = mliW.cControls; + WideCharToMultiByte( CP_ACP, 0, mliW.szShortName, -1, lpmliA->szShortName, + sizeof(lpmliA->szShortName), NULL, NULL); + WideCharToMultiByte( CP_ACP, 0, mliW.szName, -1, lpmliA->szName, + sizeof(lpmliA->szName), NULL, NULL ); + lpmliA->Target.dwType = mliW.Target.dwType; + lpmliA->Target.dwDeviceID = mliW.Target.dwDeviceID; + lpmliA->Target.wMid = mliW.Target.wMid; + lpmliA->Target.wPid = mliW.Target.wPid; + lpmliA->Target.vDriverVersion = mliW.Target.vDriverVersion; + WideCharToMultiByte( CP_ACP, 0, mliW.Target.szPname, -1, lpmliA->Target.szPname, + sizeof(lpmliA->Target.szPname), NULL, NULL ); + + return ret; +} + +/************************************************************************** + * mixerSetControlDetails [WINMM.@] + */ +UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, + DWORD fdwDetails) +{ + LPWINE_MIXER lpwm; + UINT uRet = MMSYSERR_NOERROR; + + TRACE("(%p, %p, %08lx)\n", hmix, lpmcd, fdwDetails); + + if ((uRet = MIXER_GetDev(hmix, fdwDetails, &lpwm)) != MMSYSERR_NOERROR) + return uRet; + + return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD_PTR)lpmcd, + fdwDetails, TRUE); +} + +/************************************************************************** + * mixerMessage [WINMM.@] + */ +DWORD WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2) +{ + LPWINE_MLD wmld; + + TRACE("(%04lx, %d, %08lx, %08lx): semi-stub?\n", + (DWORD)hmix, uMsg, dwParam1, dwParam2); + + if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2, TRUE); +} + +/************************************************************************** + * auxGetNumDevs [WINMM.@] + */ +UINT WINAPI auxGetNumDevs(void) +{ + return MMDRV_GetNum(MMDRV_AUX); +} + +/************************************************************************** + * auxGetDevCapsW [WINMM.@] + */ +UINT WINAPI auxGetDevCapsW(UINT_PTR uDeviceID, LPAUXCAPSW lpCaps, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p, %d) !\n", uDeviceID, lpCaps, uSize); + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, AUXDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE); +} + +/************************************************************************** + * auxGetDevCapsA [WINMM.@] + */ +UINT WINAPI auxGetDevCapsA(UINT_PTR uDeviceID, LPAUXCAPSA lpCaps, UINT uSize) +{ + AUXCAPSW acW; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = auxGetDevCapsW(uDeviceID, &acW, sizeof(acW)); + + if (ret == MMSYSERR_NOERROR) { + AUXCAPSA acA; + acA.wMid = acW.wMid; + acA.wPid = acW.wPid; + acA.vDriverVersion = acW.vDriverVersion; + WideCharToMultiByte( CP_ACP, 0, acW.szPname, -1, acA.szPname, + sizeof(acA.szPname), NULL, NULL ); + acA.wTechnology = acW.wTechnology; + acA.dwSupport = acW.dwSupport; + memcpy(lpCaps, &acA, min(uSize, sizeof(acA))); + } + return ret; +} + +/************************************************************************** + * auxGetVolume [WINMM.@] + */ +UINT WINAPI auxGetVolume(UINT uDeviceID, DWORD* lpdwVolume) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %p) !\n", uDeviceID, lpdwVolume); + + if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, AUXDM_GETVOLUME, (DWORD_PTR)lpdwVolume, 0L, TRUE); +} + +/************************************************************************** + * auxSetVolume [WINMM.@] + */ +UINT WINAPI auxSetVolume(UINT uDeviceID, DWORD dwVolume) +{ + LPWINE_MLD wmld; + + TRACE("(%04X, %lu) !\n", uDeviceID, dwVolume); + + if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, AUXDM_SETVOLUME, dwVolume, 0L, TRUE); +} + +/************************************************************************** + * auxOutMessage [WINMM.@] + */ +UINT WINAPI auxOutMessage(UINT uDeviceID, UINT uMessage, DWORD_PTR dw1, DWORD_PTR dw2) +{ + LPWINE_MLD wmld; + + if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_AUX, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, uMessage, dw1, dw2, TRUE); +} + +/************************************************************************** + * midiOutGetNumDevs [WINMM.@] + */ +UINT WINAPI midiOutGetNumDevs(void) +{ + return MMDRV_GetNum(MMDRV_MIDIOUT); +} + +/************************************************************************** + * midiOutGetDevCapsW [WINMM.@] + */ +UINT WINAPI midiOutGetDevCapsW(UINT_PTR uDeviceID, LPMIDIOUTCAPSW lpCaps, + UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%u, %p, %u);\n", uDeviceID, lpCaps, uSize); + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIOUT, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE); +} + +/************************************************************************** + * midiOutGetDevCapsA [WINMM.@] + */ +UINT WINAPI midiOutGetDevCapsA(UINT_PTR uDeviceID, LPMIDIOUTCAPSA lpCaps, + UINT uSize) +{ + MIDIOUTCAPSW mocW; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = midiOutGetDevCapsW(uDeviceID, &mocW, sizeof(mocW)); + + if (ret == MMSYSERR_NOERROR) { + MIDIOUTCAPSA mocA; + mocA.wMid = mocW.wMid; + mocA.wPid = mocW.wPid; + mocA.vDriverVersion = mocW.vDriverVersion; + WideCharToMultiByte( CP_ACP, 0, mocW.szPname, -1, mocA.szPname, + sizeof(mocA.szPname), NULL, NULL ); + mocA.wTechnology = mocW.wTechnology; + mocA.wVoices = mocW.wVoices; + mocA.wNotes = mocW.wNotes; + mocA.wChannelMask = mocW.wChannelMask; + mocA.dwSupport = mocW.dwSupport; + memcpy(lpCaps, &mocA, min(uSize, sizeof(mocA))); + } + return ret; +} + +/************************************************************************** + * midiOutGetErrorTextA [WINMM.@] + * midiInGetErrorTextA [WINMM.@] + */ +UINT WINAPI midiOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize) +{ + UINT ret; + + if (lpText == NULL) ret = MMSYSERR_INVALPARAM; + else if (uSize == 0) ret = MMSYSERR_NOERROR; + else + { + LPWSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize * sizeof(WCHAR)); + if (!xstr) ret = MMSYSERR_NOMEM; + else + { + ret = midiOutGetErrorTextW(uError, xstr, uSize); + if (ret == MMSYSERR_NOERROR) + WideCharToMultiByte(CP_ACP, 0, xstr, -1, lpText, uSize, NULL, NULL); + HeapFree(GetProcessHeap(), 0, xstr); + } + } + return ret; +} + +/************************************************************************** + * midiOutGetErrorTextW [WINMM.@] + * midiInGetErrorTextW [WINMM.@] + */ +UINT WINAPI midiOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize) +{ + UINT ret = MMSYSERR_BADERRNUM; + + if (lpText == NULL) ret = MMSYSERR_INVALPARAM; + else if (uSize == 0) ret = MMSYSERR_NOERROR; + else if ( + /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit + * a warning for the test was always true */ + (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) || + (uError >= MIDIERR_BASE && uError <= MIDIERR_LASTERROR)) { + if (LoadStringW(WINMM_IData.hWinMM32Instance, + uError, lpText, uSize) > 0) { + ret = MMSYSERR_NOERROR; + } + } + return ret; +} + +/************************************************************************** + * MIDI_OutAlloc [internal] + */ +static LPWINE_MIDI MIDI_OutAlloc(HMIDIOUT* lphMidiOut, LPDWORD lpdwCallback, + LPDWORD lpdwInstance, LPDWORD lpdwFlags, + DWORD cIDs, MIDIOPENSTRMID* lpIDs, BOOL bFrom32) +{ + HANDLE hMidiOut; + LPWINE_MIDI lpwm; + UINT size; + + size = sizeof(WINE_MIDI) + (cIDs ? (cIDs-1) : 0) * sizeof(MIDIOPENSTRMID); + + lpwm = (LPWINE_MIDI)MMDRV_Alloc(size, MMDRV_MIDIOUT, &hMidiOut, lpdwFlags, + lpdwCallback, lpdwInstance, bFrom32); + + if (lphMidiOut != NULL) + *lphMidiOut = hMidiOut; + + if (lpwm) { + lpwm->mod.hMidi = (HMIDI) hMidiOut; + lpwm->mod.dwCallback = *lpdwCallback; + lpwm->mod.dwInstance = *lpdwInstance; + lpwm->mod.dnDevNode = 0; + lpwm->mod.cIds = cIDs; + if (cIDs) + memcpy(&(lpwm->mod.rgIds), lpIDs, cIDs * sizeof(MIDIOPENSTRMID)); + } + return lpwm; +} + +UINT MIDI_OutOpen(LPHMIDIOUT lphMidiOut, UINT uDeviceID, DWORD_PTR dwCallback, + DWORD_PTR dwInstance, DWORD dwFlags, BOOL bFrom32) +{ + HMIDIOUT hMidiOut; + LPWINE_MIDI lpwm; + UINT dwRet = 0; + + TRACE("(%p, %d, %08lX, %08lX, %08lX);\n", + lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags); + + if (lphMidiOut != NULL) *lphMidiOut = 0; + + lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &dwFlags, + 0, NULL, bFrom32); + + if (lpwm == NULL) + return MMSYSERR_NOMEM; + + lpwm->mld.uDeviceID = uDeviceID; + + dwRet = MMDRV_Open((LPWINE_MLD)lpwm, MODM_OPEN, (DWORD)&lpwm->mod, dwFlags); + + if (dwRet != MMSYSERR_NOERROR) { + MMDRV_Free(hMidiOut, (LPWINE_MLD)lpwm); + hMidiOut = 0; + } + + if (lphMidiOut) *lphMidiOut = hMidiOut; + TRACE("=> %d hMidi=%p\n", dwRet, hMidiOut); + + return dwRet; +} + +/************************************************************************** + * midiOutOpen [WINMM.@] + */ +UINT WINAPI midiOutOpen(LPHMIDIOUT lphMidiOut, UINT uDeviceID, + DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags) +{ + return MIDI_OutOpen(lphMidiOut, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE); +} + +/************************************************************************** + * midiOutClose [WINMM.@] + */ +UINT WINAPI midiOutClose(HMIDIOUT hMidiOut) +{ + LPWINE_MLD wmld; + DWORD dwRet; + + TRACE("(%p)\n", hMidiOut); + + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + dwRet = MMDRV_Close(wmld, MODM_CLOSE); + MMDRV_Free(hMidiOut, wmld); + + return dwRet; +} + +/************************************************************************** + * midiOutPrepareHeader [WINMM.@] + */ +UINT WINAPI midiOutPrepareHeader(HMIDIOUT hMidiOut, + MIDIHDR* lpMidiOutHdr, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize); + + if (lpMidiOutHdr == NULL || uSize < sizeof (MIDIHDR)) + return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_PREPARE, (DWORD_PTR)lpMidiOutHdr, uSize, TRUE); +} + +/************************************************************************** + * midiOutUnprepareHeader [WINMM.@] + */ +UINT WINAPI midiOutUnprepareHeader(HMIDIOUT hMidiOut, + MIDIHDR* lpMidiOutHdr, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize); + + if (lpMidiOutHdr == NULL || uSize < sizeof (MIDIHDR)) + return MMSYSERR_INVALPARAM; + + if (!(lpMidiOutHdr->dwFlags & MHDR_PREPARED)) { + return MMSYSERR_NOERROR; + } + + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_UNPREPARE, (DWORD_PTR)lpMidiOutHdr, uSize, TRUE); +} + +/************************************************************************** + * midiOutShortMsg [WINMM.@] + */ +UINT WINAPI midiOutShortMsg(HMIDIOUT hMidiOut, DWORD dwMsg) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %08lX)\n", hMidiOut, dwMsg); + + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_DATA, dwMsg, 0L, TRUE); +} + +/************************************************************************** + * midiOutLongMsg [WINMM.@] + */ +UINT WINAPI midiOutLongMsg(HMIDIOUT hMidiOut, + MIDIHDR* lpMidiOutHdr, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %d)\n", hMidiOut, lpMidiOutHdr, uSize); + + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_LONGDATA, (DWORD_PTR)lpMidiOutHdr, uSize, TRUE); +} + +/************************************************************************** + * midiOutReset [WINMM.@] + */ +UINT WINAPI midiOutReset(HMIDIOUT hMidiOut) +{ + LPWINE_MLD wmld; + + TRACE("(%p)\n", hMidiOut); + + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_RESET, 0L, 0L, TRUE); +} + +/************************************************************************** + * midiOutGetVolume [WINMM.@] + */ +UINT WINAPI midiOutGetVolume(HMIDIOUT hMidiOut, DWORD* lpdwVolume) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p);\n", hMidiOut, lpdwVolume); + + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_GETVOLUME, (DWORD_PTR)lpdwVolume, 0L, TRUE); +} + +/************************************************************************** + * midiOutSetVolume [WINMM.@] + */ +UINT WINAPI midiOutSetVolume(HMIDIOUT hMidiOut, DWORD dwVolume) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %ld);\n", hMidiOut, dwVolume); + + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MODM_SETVOLUME, dwVolume, 0L, TRUE); +} + +/************************************************************************** + * midiOutCachePatches [WINMM.@] + */ +UINT WINAPI midiOutCachePatches(HMIDIOUT hMidiOut, UINT uBank, + WORD* lpwPatchArray, UINT uFlags) +{ + /* not really necessary to support this */ + FIXME("not supported yet\n"); + return MMSYSERR_NOTSUPPORTED; +} + +/************************************************************************** + * midiOutCacheDrumPatches [WINMM.@] + */ +UINT WINAPI midiOutCacheDrumPatches(HMIDIOUT hMidiOut, UINT uPatch, + WORD* lpwKeyArray, UINT uFlags) +{ + FIXME("not supported yet\n"); + return MMSYSERR_NOTSUPPORTED; +} + +/************************************************************************** + * midiOutGetID [WINMM.@] + */ +UINT WINAPI midiOutGetID(HMIDIOUT hMidiOut, UINT* lpuDeviceID) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p)\n", hMidiOut, lpuDeviceID); + + if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM; + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + *lpuDeviceID = wmld->uDeviceID; + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * midiOutMessage [WINMM.@] + */ +UINT WINAPI midiOutMessage(HMIDIOUT hMidiOut, UINT uMessage, + DWORD_PTR dwParam1, DWORD_PTR dwParam2) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiOut, uMessage, dwParam1, dwParam2); + + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, FALSE)) == NULL) { + /* HACK... */ + if (uMessage == 0x0001) { + *(LPDWORD)dwParam1 = 1; + return 0; + } + if ((wmld = MMDRV_Get(hMidiOut, MMDRV_MIDIOUT, TRUE)) != NULL) { + return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2); + } + return MMSYSERR_INVALHANDLE; + } + + switch (uMessage) { + case MODM_OPEN: + case MODM_CLOSE: + FIXME("can't handle OPEN or CLOSE message!\n"); + return MMSYSERR_NOTSUPPORTED; + } + return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE); +} + +/************************************************************************** + * midiInGetNumDevs [WINMM.@] + */ +UINT WINAPI midiInGetNumDevs(void) +{ + return MMDRV_GetNum(MMDRV_MIDIIN); +} + +/************************************************************************** + * midiInGetDevCapsW [WINMM.@] + */ +UINT WINAPI midiInGetDevCapsW(UINT_PTR uDeviceID, LPMIDIINCAPSW lpCaps, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%d, %p, %d);\n", uDeviceID, lpCaps, uSize); + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIDIIN, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE); +} + +/************************************************************************** + * midiInGetDevCapsA [WINMM.@] + */ +UINT WINAPI midiInGetDevCapsA(UINT_PTR uDeviceID, LPMIDIINCAPSA lpCaps, UINT uSize) +{ + MIDIINCAPSW micW; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = midiInGetDevCapsW(uDeviceID, &micW, sizeof(micW)); + + if (ret == MMSYSERR_NOERROR) { + MIDIINCAPSA micA; + micA.wMid = micW.wMid; + micA.wPid = micW.wPid; + micA.vDriverVersion = micW.vDriverVersion; + WideCharToMultiByte( CP_ACP, 0, micW.szPname, -1, micA.szPname, + sizeof(micA.szPname), NULL, NULL ); + micA.dwSupport = micW.dwSupport; + memcpy(lpCaps, &micA, min(uSize, sizeof(micA))); + } + return ret; +} + +UINT MIDI_InOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, DWORD_PTR dwCallback, + DWORD_PTR dwInstance, DWORD dwFlags, BOOL bFrom32) +{ + HANDLE hMidiIn; + LPWINE_MIDI lpwm; + DWORD dwRet = 0; + + TRACE("(%p, %d, %08lX, %08lX, %08lX);\n", + lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags); + + if (lphMidiIn != NULL) *lphMidiIn = 0; + + lpwm = (LPWINE_MIDI)MMDRV_Alloc(sizeof(WINE_MIDI), MMDRV_MIDIIN, &hMidiIn, + &dwFlags, &dwCallback, &dwInstance, bFrom32); + + if (lpwm == NULL) + return MMSYSERR_NOMEM; + + lpwm->mod.hMidi = (HMIDI) hMidiIn; + lpwm->mod.dwCallback = dwCallback; + lpwm->mod.dwInstance = dwInstance; + + lpwm->mld.uDeviceID = uDeviceID; + dwRet = MMDRV_Open(&lpwm->mld, MIDM_OPEN, (DWORD)&lpwm->mod, dwFlags); + + if (dwRet != MMSYSERR_NOERROR) { + MMDRV_Free(hMidiIn, &lpwm->mld); + hMidiIn = 0; + } + if (lphMidiIn != NULL) *lphMidiIn = hMidiIn; + TRACE("=> %ld hMidi=%p\n", dwRet, hMidiIn); + + return dwRet; +} + +/************************************************************************** + * midiInOpen [WINMM.@] + */ +UINT WINAPI midiInOpen(HMIDIIN* lphMidiIn, UINT uDeviceID, + DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD dwFlags) +{ + return MIDI_InOpen(lphMidiIn, uDeviceID, dwCallback, dwInstance, dwFlags, TRUE); +} + +/************************************************************************** + * midiInClose [WINMM.@] + */ +UINT WINAPI midiInClose(HMIDIIN hMidiIn) +{ + LPWINE_MLD wmld; + DWORD dwRet; + + TRACE("(%p)\n", hMidiIn); + + if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + dwRet = MMDRV_Close(wmld, MIDM_CLOSE); + MMDRV_Free(hMidiIn, wmld); + return dwRet; +} + +/************************************************************************** + * midiInPrepareHeader [WINMM.@] + */ +UINT WINAPI midiInPrepareHeader(HMIDIIN hMidiIn, + MIDIHDR* lpMidiInHdr, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize); + + if (lpMidiInHdr == NULL || uSize < sizeof (MIDIHDR)) + return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_PREPARE, (DWORD_PTR)lpMidiInHdr, uSize, TRUE); +} + +/************************************************************************** + * midiInUnprepareHeader [WINMM.@] + */ +UINT WINAPI midiInUnprepareHeader(HMIDIIN hMidiIn, + MIDIHDR* lpMidiInHdr, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize); + + if (lpMidiInHdr == NULL || uSize < sizeof (MIDIHDR)) + return MMSYSERR_INVALPARAM; + + if (!(lpMidiInHdr->dwFlags & MHDR_PREPARED)) { + return MMSYSERR_NOERROR; + } + + if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_UNPREPARE, (DWORD_PTR)lpMidiInHdr, uSize, TRUE); +} + +/************************************************************************** + * midiInAddBuffer [WINMM.@] + */ +UINT WINAPI midiInAddBuffer(HMIDIIN hMidiIn, + MIDIHDR* lpMidiInHdr, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %d)\n", hMidiIn, lpMidiInHdr, uSize); + + if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_ADDBUFFER, (DWORD_PTR)lpMidiInHdr, uSize, TRUE); +} + +/************************************************************************** + * midiInStart [WINMM.@] + */ +UINT WINAPI midiInStart(HMIDIIN hMidiIn) +{ + LPWINE_MLD wmld; + + TRACE("(%p)\n", hMidiIn); + + if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_START, 0L, 0L, TRUE); +} + +/************************************************************************** + * midiInStop [WINMM.@] + */ +UINT WINAPI midiInStop(HMIDIIN hMidiIn) +{ + LPWINE_MLD wmld; + + TRACE("(%p)\n", hMidiIn); + + if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_STOP, 0L, 0L, TRUE); +} + +/************************************************************************** + * midiInReset [WINMM.@] + */ +UINT WINAPI midiInReset(HMIDIIN hMidiIn) +{ + LPWINE_MLD wmld; + + TRACE("(%p)\n", hMidiIn); + + if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, MIDM_RESET, 0L, 0L, TRUE); +} + +/************************************************************************** + * midiInGetID [WINMM.@] + */ +UINT WINAPI midiInGetID(HMIDIIN hMidiIn, UINT* lpuDeviceID) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p)\n", hMidiIn, lpuDeviceID); + + if (lpuDeviceID == NULL) return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + + *lpuDeviceID = wmld->uDeviceID; + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * midiInMessage [WINMM.@] + */ +UINT WINAPI midiInMessage(HMIDIIN hMidiIn, UINT uMessage, + DWORD_PTR dwParam1, DWORD_PTR dwParam2) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %04X, %08lX, %08lX)\n", hMidiIn, uMessage, dwParam1, dwParam2); + + if ((wmld = MMDRV_Get(hMidiIn, MMDRV_MIDIIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + switch (uMessage) { + case MIDM_OPEN: + case MIDM_CLOSE: + FIXME("can't handle OPEN or CLOSE message!\n"); + return MMSYSERR_NOTSUPPORTED; + } + return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE); +} + +typedef struct WINE_MIDIStream { + HMIDIOUT hDevice; + HANDLE hThread; + DWORD dwThreadID; + DWORD dwTempo; + DWORD dwTimeDiv; + DWORD dwPositionMS; + DWORD dwPulses; + DWORD dwStartTicks; + WORD wFlags; + HANDLE hEvent; + LPMIDIHDR lpMidiHdr; +} WINE_MIDIStream; + +#define WINE_MSM_HEADER (WM_USER+0) +#define WINE_MSM_STOP (WM_USER+1) + +/************************************************************************** + * MMSYSTEM_GetMidiStream [internal] + */ +static BOOL MMSYSTEM_GetMidiStream(HMIDISTRM hMidiStrm, WINE_MIDIStream** lpMidiStrm, WINE_MIDI** lplpwm) +{ + WINE_MIDI* lpwm = (LPWINE_MIDI)MMDRV_Get(hMidiStrm, MMDRV_MIDIOUT, FALSE); + + if (lplpwm) + *lplpwm = lpwm; + + if (lpwm == NULL) { + return FALSE; + } + + *lpMidiStrm = (WINE_MIDIStream*)lpwm->mod.rgIds.dwStreamID; + + return *lpMidiStrm != NULL; +} + +/************************************************************************** + * MMSYSTEM_MidiStream_Convert [internal] + */ +static DWORD MMSYSTEM_MidiStream_Convert(WINE_MIDIStream* lpMidiStrm, DWORD pulse) +{ + DWORD ret = 0; + + if (lpMidiStrm->dwTimeDiv == 0) { + FIXME("Shouldn't happen. lpMidiStrm->dwTimeDiv = 0\n"); + } else if (lpMidiStrm->dwTimeDiv > 0x8000) { /* SMPTE, unchecked FIXME? */ + int nf = -(char)HIBYTE(lpMidiStrm->dwTimeDiv); /* number of frames */ + int nsf = LOBYTE(lpMidiStrm->dwTimeDiv); /* number of sub-frames */ + ret = (pulse * 1000) / (nf * nsf); + } else { + ret = (DWORD)((double)pulse * ((double)lpMidiStrm->dwTempo / 1000) / + (double)lpMidiStrm->dwTimeDiv); + } + + return ret; +} + +/************************************************************************** + * MMSYSTEM_MidiStream_MessageHandler [internal] + */ +static BOOL MMSYSTEM_MidiStream_MessageHandler(WINE_MIDIStream* lpMidiStrm, LPWINE_MIDI lpwm, LPMSG msg) +{ + LPMIDIHDR lpMidiHdr; + LPMIDIHDR* lpmh; + LPBYTE lpData; + + switch (msg->message) { + case WM_QUIT: + SetEvent(lpMidiStrm->hEvent); + return FALSE; + case WINE_MSM_STOP: + TRACE("STOP\n"); + /* this is not quite what MS doc says... */ + midiOutReset(lpMidiStrm->hDevice); + /* empty list of already submitted buffers */ + for (lpMidiHdr = lpMidiStrm->lpMidiHdr; lpMidiHdr; lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext) { + lpMidiHdr->dwFlags |= MHDR_DONE; + lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; + + DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, + (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE, + lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L); + } + lpMidiStrm->lpMidiHdr = 0; + SetEvent(lpMidiStrm->hEvent); + break; + case WINE_MSM_HEADER: + /* sets initial tick count for first MIDIHDR */ + if (!lpMidiStrm->dwStartTicks) + lpMidiStrm->dwStartTicks = GetTickCount(); + + /* FIXME(EPP): "I don't understand the content of the first MIDIHDR sent + * by native mcimidi, it doesn't look like a correct one". + * this trick allows to throw it away... but I don't like it. + * It looks like part of the file I'm trying to play and definitively looks + * like raw midi content + * I'd really like to understand why native mcimidi sends it. Perhaps a bad + * synchronization issue where native mcimidi is still processing raw MIDI + * content before generating MIDIEVENTs ? + * + * 4c 04 89 3b 00 81 7c 99 3b 43 00 99 23 5e 04 89 L..;..|.;C..#^.. + * 3b 00 00 89 23 00 7c 99 3b 45 00 99 28 62 04 89 ;...#.|.;E..(b.. + * 3b 00 00 89 28 00 81 7c 99 3b 4e 00 99 23 5e 04 ;...(..|.;N..#^. + * 89 3b 00 00 89 23 00 7c 99 3b 45 00 99 23 78 04 .;...#.|.;E..#x. + * 89 3b 00 00 89 23 00 81 7c 99 3b 48 00 99 23 5e .;...#..|.;H..#^ + * 04 89 3b 00 00 89 23 00 7c 99 3b 4e 00 99 28 62 ..;...#.|.;N..(b + * 04 89 3b 00 00 89 28 00 81 7c 99 39 4c 00 99 23 ..;...(..|.9L..# + * 5e 04 89 39 00 00 89 23 00 82 7c 99 3b 4c 00 99 ^..9...#..|.;L.. + * 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 00 99 #^..;...#.|.;H.. + * 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b 3f 04 (b..;...(..|.;?. + * 89 3b 00 1c 99 23 5e 04 89 23 00 5c 99 3b 45 00 .;...#^..#.\.;E. + * 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 3b 46 .#x..;...#..|.;F + * 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b 48 ..#^..;...#.|.;H + * 00 99 28 62 04 89 3b 00 00 89 28 00 81 7c 99 3b ..(b..;...(..|.; + * 46 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 3b F..#^..;...#.|.; + * 48 00 99 23 78 04 89 3b 00 00 89 23 00 81 7c 99 H..#x..;...#..|. + * 3b 4c 00 99 23 5e 04 89 3b 00 00 89 23 00 7c 99 ;L..#^..;...#.|. + */ + lpMidiHdr = (LPMIDIHDR)msg->lParam; + lpData = lpMidiHdr->lpData; + TRACE("Adding %s lpMidiHdr=%p [lpData=0x%08lx dwBufferLength=%lu/%lu dwFlags=0x%08lx size=%u]\n", + (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", lpMidiHdr, + (DWORD)lpMidiHdr, lpMidiHdr->dwBufferLength, lpMidiHdr->dwBytesRecorded, + lpMidiHdr->dwFlags, msg->wParam); +#if 0 + /* dumps content of lpMidiHdr->lpData + * FIXME: there should be a debug routine somewhere that already does this + * I hate spreading this type of shit all around the code + */ + for (dwToGo = 0; dwToGo < lpMidiHdr->dwBufferLength; dwToGo += 16) { + DWORD i; + BYTE ch; + + for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) + printf("%02x ", lpData[dwToGo + i]); + for (; i < 16; i++) + printf(" "); + for (i = 0; i < min(16, lpMidiHdr->dwBufferLength - dwToGo); i++) { + ch = lpData[dwToGo + i]; + printf("%c", (ch >= 0x20 && ch <= 0x7F) ? ch : '.'); + } + printf("\n"); + } +#endif + if (((LPMIDIEVENT)lpData)->dwStreamID != 0 && + ((LPMIDIEVENT)lpData)->dwStreamID != 0xFFFFFFFF && + ((LPMIDIEVENT)lpData)->dwStreamID != (DWORD)lpMidiStrm) { + FIXME("Dropping bad %s lpMidiHdr (streamID=%08lx)\n", + (lpMidiHdr->dwFlags & MHDR_ISSTRM) ? "stream" : "regular", + ((LPMIDIEVENT)lpData)->dwStreamID); + lpMidiHdr->dwFlags |= MHDR_DONE; + lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; + + DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, + (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE, + lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L); + break; + } + + for (lpmh = &lpMidiStrm->lpMidiHdr; *lpmh; lpmh = (LPMIDIHDR*)&((*lpmh)->lpNext)); + *lpmh = lpMidiHdr; + lpMidiHdr = (LPMIDIHDR)msg->lParam; + lpMidiHdr->lpNext = 0; + lpMidiHdr->dwFlags |= MHDR_INQUEUE; + lpMidiHdr->dwFlags &= ~MHDR_DONE; + lpMidiHdr->dwOffset = 0; + + break; + default: + FIXME("Unknown message %d\n", msg->message); + break; + } + return TRUE; +} + +/************************************************************************** + * MMSYSTEM_MidiStream_Player [internal] + */ +static DWORD CALLBACK MMSYSTEM_MidiStream_Player(LPVOID pmt) +{ + WINE_MIDIStream* lpMidiStrm = pmt; + WINE_MIDI* lpwm; + MSG msg; + DWORD dwToGo; + DWORD dwCurrTC; + LPMIDIHDR lpMidiHdr; + LPMIDIEVENT me; + LPBYTE lpData = 0; + + TRACE("(%p)!\n", lpMidiStrm); + + if (!lpMidiStrm || + (lpwm = (LPWINE_MIDI)MMDRV_Get(lpMidiStrm->hDevice, MMDRV_MIDIOUT, FALSE)) == NULL) + goto the_end; + + /* force thread's queue creation */ + /* Used to be InitThreadInput16(0, 5); */ + /* but following works also with hack in midiStreamOpen */ + PeekMessageA(&msg, 0, 0, 0, 0); + + /* FIXME: this next line must be called before midiStreamOut or midiStreamRestart are called */ + SetEvent(lpMidiStrm->hEvent); + TRACE("Ready to go 1\n"); + /* thread is started in paused mode */ + SuspendThread(lpMidiStrm->hThread); + TRACE("Ready to go 2\n"); + + lpMidiStrm->dwStartTicks = 0; + lpMidiStrm->dwPulses = 0; + + lpMidiStrm->lpMidiHdr = 0; + + for (;;) { + lpMidiHdr = lpMidiStrm->lpMidiHdr; + if (!lpMidiHdr) { + /* for first message, block until one arrives, then process all that are available */ + GetMessageA(&msg, 0, 0, 0); + do { + if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg)) + goto the_end; + } while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)); + lpData = 0; + continue; + } + + if (!lpData) + lpData = lpMidiHdr->lpData; + + me = (LPMIDIEVENT)(lpData + lpMidiHdr->dwOffset); + + /* do we have to wait ? */ + if (me->dwDeltaTime) { + lpMidiStrm->dwPositionMS += MMSYSTEM_MidiStream_Convert(lpMidiStrm, me->dwDeltaTime); + lpMidiStrm->dwPulses += me->dwDeltaTime; + + dwToGo = lpMidiStrm->dwStartTicks + lpMidiStrm->dwPositionMS; + + TRACE("%ld/%ld/%ld\n", dwToGo, GetTickCount(), me->dwDeltaTime); + while ((dwCurrTC = GetTickCount()) < dwToGo) { + if (MsgWaitForMultipleObjects(0, NULL, FALSE, dwToGo - dwCurrTC, QS_ALLINPUT) == WAIT_OBJECT_0) { + /* got a message, handle it */ + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) { + if (!MMSYSTEM_MidiStream_MessageHandler(lpMidiStrm, lpwm, &msg)) + goto the_end; + } + lpData = 0; + } else { + /* timeout, so me->dwDeltaTime is elapsed, can break the while loop */ + break; + } + } + } + switch (MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)) { + case MEVT_COMMENT: + FIXME("NIY: MEVT_COMMENT\n"); + /* do nothing, skip bytes */ + break; + case MEVT_LONGMSG: + FIXME("NIY: MEVT_LONGMSG, aka sending Sysex event\n"); + break; + case MEVT_NOP: + break; + case MEVT_SHORTMSG: + midiOutShortMsg(lpMidiStrm->hDevice, MEVT_EVENTPARM(me->dwEvent)); + break; + case MEVT_TEMPO: + lpMidiStrm->dwTempo = MEVT_EVENTPARM(me->dwEvent); + break; + case MEVT_VERSION: + break; + default: + FIXME("Unknown MEVT (0x%02x)\n", MEVT_EVENTTYPE(me->dwEvent & ~MEVT_F_CALLBACK)); + break; + } + if (me->dwEvent & MEVT_F_CALLBACK) { + DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, + (HDRVR)lpMidiStrm->hDevice, MM_MOM_POSITIONCB, + lpwm->mod.dwInstance, (LPARAM)lpMidiHdr, 0L); + } + lpMidiHdr->dwOffset += sizeof(MIDIEVENT) - sizeof(me->dwParms); + if (me->dwEvent & MEVT_F_LONG) + lpMidiHdr->dwOffset += (MEVT_EVENTPARM(me->dwEvent) + 3) & ~3; + if (lpMidiHdr->dwOffset >= lpMidiHdr->dwBufferLength) { + /* done with this header */ + lpMidiHdr->dwFlags |= MHDR_DONE; + lpMidiHdr->dwFlags &= ~MHDR_INQUEUE; + + lpMidiStrm->lpMidiHdr = (LPMIDIHDR)lpMidiHdr->lpNext; + DriverCallback(lpwm->mod.dwCallback, lpMidiStrm->wFlags, + (HDRVR)lpMidiStrm->hDevice, MM_MOM_DONE, + lpwm->mod.dwInstance, (DWORD)lpMidiHdr, 0L); + lpData = 0; + } + } +the_end: + TRACE("End of thread\n"); + ExitThread(0); + return 0; /* for removing the warning, never executed */ +} + +/************************************************************************** + * MMSYSTEM_MidiStream_PostMessage [internal] + */ +static BOOL MMSYSTEM_MidiStream_PostMessage(WINE_MIDIStream* lpMidiStrm, WORD msg, DWORD pmt1, DWORD pmt2) +{ + if (PostThreadMessageA(lpMidiStrm->dwThreadID, msg, pmt1, pmt2)) { + DWORD count; + + if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count); + WaitForSingleObject(lpMidiStrm->hEvent, INFINITE); + if (pFnRestoreThunkLock) pFnRestoreThunkLock(count); + } else { + WARN("bad PostThreadMessageA\n"); + return FALSE; + } + return TRUE; +} + +/************************************************************************** + * midiStreamClose [WINMM.@] + */ +MMRESULT WINAPI midiStreamClose(HMIDISTRM hMidiStrm) +{ + WINE_MIDIStream* lpMidiStrm; + + TRACE("(%p)!\n", hMidiStrm); + + if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) + return MMSYSERR_INVALHANDLE; + + midiStreamStop(hMidiStrm); + MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WM_QUIT, 0, 0); + HeapFree(GetProcessHeap(), 0, lpMidiStrm); + CloseHandle(lpMidiStrm->hEvent); + + return midiOutClose((HMIDIOUT)hMidiStrm); +} + +/************************************************************************** + * MMSYSTEM_MidiStream_Open [internal] + */ +MMRESULT MIDI_StreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, DWORD cMidi, + DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen, + BOOL bFrom32) +{ + WINE_MIDIStream* lpMidiStrm; + MMRESULT ret; + MIDIOPENSTRMID mosm; + LPWINE_MIDI lpwm; + HMIDIOUT hMidiOut; + + TRACE("(%p, %p, %ld, 0x%08lx, 0x%08lx, 0x%08lx)!\n", + lphMidiStrm, lpuDeviceID, cMidi, dwCallback, dwInstance, fdwOpen); + + if (cMidi != 1 || lphMidiStrm == NULL || lpuDeviceID == NULL) + return MMSYSERR_INVALPARAM; + + lpMidiStrm = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_MIDIStream)); + if (!lpMidiStrm) + return MMSYSERR_NOMEM; + + lpMidiStrm->dwTempo = 500000; + lpMidiStrm->dwTimeDiv = 480; /* 480 is 120 quater notes per minute *//* FIXME ??*/ + lpMidiStrm->dwPositionMS = 0; + + mosm.dwStreamID = (DWORD)lpMidiStrm; + /* FIXME: the correct value is not allocated yet for MAPPER */ + mosm.wDeviceID = *lpuDeviceID; + lpwm = MIDI_OutAlloc(&hMidiOut, &dwCallback, &dwInstance, &fdwOpen, 1, &mosm, bFrom32); + lpMidiStrm->hDevice = hMidiOut; + if (lphMidiStrm) + *lphMidiStrm = (HMIDISTRM)hMidiOut; + + lpwm->mld.uDeviceID = *lpuDeviceID; + + ret = MMDRV_Open(&lpwm->mld, MODM_OPEN, (DWORD)&lpwm->mod, fdwOpen); + lpMidiStrm->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + lpMidiStrm->wFlags = HIWORD(fdwOpen); + + lpMidiStrm->hThread = CreateThread(NULL, 0, MMSYSTEM_MidiStream_Player, + lpMidiStrm, 0, &(lpMidiStrm->dwThreadID)); + + if (!lpMidiStrm->hThread) { + midiStreamClose((HMIDISTRM)hMidiOut); + return MMSYSERR_NOMEM; + } + SetThreadPriority(lpMidiStrm->hThread, THREAD_PRIORITY_TIME_CRITICAL); + + /* wait for thread to have started, and for its queue to be created */ + { + DWORD count; + + /* (Release|Restore)ThunkLock() is needed when this method is called from 16 bit code, + * (meaning the Win16Lock is set), so that it's released and the 32 bit thread running + * MMSYSTEM_MidiStreamPlayer can acquire Win16Lock to create its queue. + */ + if (pFnReleaseThunkLock) pFnReleaseThunkLock(&count); + WaitForSingleObject(lpMidiStrm->hEvent, INFINITE); + if (pFnRestoreThunkLock) pFnRestoreThunkLock(count); + } + + TRACE("=> (%u/%d) hMidi=%p ret=%d lpMidiStrm=%p\n", + *lpuDeviceID, lpwm->mld.uDeviceID, *lphMidiStrm, ret, lpMidiStrm); + return ret; +} + +/************************************************************************** + * midiStreamOpen [WINMM.@] + */ +MMRESULT WINAPI midiStreamOpen(HMIDISTRM* lphMidiStrm, LPUINT lpuDeviceID, + DWORD cMidi, DWORD_PTR dwCallback, + DWORD_PTR dwInstance, DWORD fdwOpen) +{ + return MIDI_StreamOpen(lphMidiStrm, lpuDeviceID, cMidi, dwCallback, + dwInstance, fdwOpen, TRUE); +} + +/************************************************************************** + * midiStreamOut [WINMM.@] + */ +MMRESULT WINAPI midiStreamOut(HMIDISTRM hMidiStrm, LPMIDIHDR lpMidiHdr, + UINT cbMidiHdr) +{ + WINE_MIDIStream* lpMidiStrm; + DWORD ret = MMSYSERR_NOERROR; + + TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMidiHdr, cbMidiHdr); + + if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { + ret = MMSYSERR_INVALHANDLE; + } else if (!lpMidiHdr) { + ret = MMSYSERR_INVALPARAM; + } else { + if (!PostThreadMessageA(lpMidiStrm->dwThreadID, + WINE_MSM_HEADER, cbMidiHdr, + (DWORD)lpMidiHdr)) { + WARN("bad PostThreadMessageA\n"); + ret = MMSYSERR_ERROR; + } + } + return ret; +} + +/************************************************************************** + * midiStreamPause [WINMM.@] + */ +MMRESULT WINAPI midiStreamPause(HMIDISTRM hMidiStrm) +{ + WINE_MIDIStream* lpMidiStrm; + DWORD ret = MMSYSERR_NOERROR; + + TRACE("(%p)!\n", hMidiStrm); + + if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { + ret = MMSYSERR_INVALHANDLE; + } else { + if (SuspendThread(lpMidiStrm->hThread) == 0xFFFFFFFF) { + WARN("bad Suspend (%ld)\n", GetLastError()); + ret = MMSYSERR_ERROR; + } + } + return ret; +} + +/************************************************************************** + * midiStreamPosition [WINMM.@] + */ +MMRESULT WINAPI midiStreamPosition(HMIDISTRM hMidiStrm, LPMMTIME lpMMT, UINT cbmmt) +{ + WINE_MIDIStream* lpMidiStrm; + DWORD ret = MMSYSERR_NOERROR; + + TRACE("(%p, %p, %u)!\n", hMidiStrm, lpMMT, cbmmt); + + if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { + ret = MMSYSERR_INVALHANDLE; + } else if (lpMMT == NULL || cbmmt != sizeof(MMTIME)) { + ret = MMSYSERR_INVALPARAM; + } else { + switch (lpMMT->wType) { + case TIME_MS: + lpMMT->u.ms = lpMidiStrm->dwPositionMS; + TRACE("=> %ld ms\n", lpMMT->u.ms); + break; + case TIME_TICKS: + lpMMT->u.ticks = lpMidiStrm->dwPulses; + TRACE("=> %ld ticks\n", lpMMT->u.ticks); + break; + default: + WARN("Unsupported time type %d\n", lpMMT->wType); + lpMMT->wType = TIME_MS; + ret = MMSYSERR_INVALPARAM; + break; + } + } + return ret; +} + +/************************************************************************** + * midiStreamProperty [WINMM.@] + */ +MMRESULT WINAPI midiStreamProperty(HMIDISTRM hMidiStrm, LPBYTE lpPropData, DWORD dwProperty) +{ + WINE_MIDIStream* lpMidiStrm; + MMRESULT ret = MMSYSERR_NOERROR; + + TRACE("(%p, %p, %lx)\n", hMidiStrm, lpPropData, dwProperty); + + if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { + ret = MMSYSERR_INVALHANDLE; + } else if ((dwProperty & (MIDIPROP_GET|MIDIPROP_SET)) == 0) { + ret = MMSYSERR_INVALPARAM; + } else if (dwProperty & MIDIPROP_TEMPO) { + MIDIPROPTEMPO* mpt = (MIDIPROPTEMPO*)lpPropData; + + if (sizeof(MIDIPROPTEMPO) != mpt->cbStruct) { + ret = MMSYSERR_INVALPARAM; + } else if (dwProperty & MIDIPROP_SET) { + lpMidiStrm->dwTempo = mpt->dwTempo; + TRACE("Setting tempo to %ld\n", mpt->dwTempo); + } else if (dwProperty & MIDIPROP_GET) { + mpt->dwTempo = lpMidiStrm->dwTempo; + TRACE("Getting tempo <= %ld\n", mpt->dwTempo); + } + } else if (dwProperty & MIDIPROP_TIMEDIV) { + MIDIPROPTIMEDIV* mptd = (MIDIPROPTIMEDIV*)lpPropData; + + if (sizeof(MIDIPROPTIMEDIV) != mptd->cbStruct) { + ret = MMSYSERR_INVALPARAM; + } else if (dwProperty & MIDIPROP_SET) { + lpMidiStrm->dwTimeDiv = mptd->dwTimeDiv; + TRACE("Setting time div to %ld\n", mptd->dwTimeDiv); + } else if (dwProperty & MIDIPROP_GET) { + mptd->dwTimeDiv = lpMidiStrm->dwTimeDiv; + TRACE("Getting time div <= %ld\n", mptd->dwTimeDiv); + } + } else { + ret = MMSYSERR_INVALPARAM; + } + + return ret; +} + +/************************************************************************** + * midiStreamRestart [WINMM.@] + */ +MMRESULT WINAPI midiStreamRestart(HMIDISTRM hMidiStrm) +{ + WINE_MIDIStream* lpMidiStrm; + MMRESULT ret = MMSYSERR_NOERROR; + + TRACE("(%p)!\n", hMidiStrm); + + if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { + ret = MMSYSERR_INVALHANDLE; + } else { + DWORD ret; + + /* since we increase the thread suspend count on each midiStreamPause + * there may be a need for several midiStreamResume + */ + do { + ret = ResumeThread(lpMidiStrm->hThread); + } while (ret != 0xFFFFFFFF && ret != 0); + if (ret == 0xFFFFFFFF) { + WARN("bad Resume (%ld)\n", GetLastError()); + ret = MMSYSERR_ERROR; + } else { + lpMidiStrm->dwStartTicks = GetTickCount() - lpMidiStrm->dwPositionMS; + } + } + return ret; +} + +/************************************************************************** + * midiStreamStop [WINMM.@] + */ +MMRESULT WINAPI midiStreamStop(HMIDISTRM hMidiStrm) +{ + WINE_MIDIStream* lpMidiStrm; + MMRESULT ret = MMSYSERR_NOERROR; + + TRACE("(%p)!\n", hMidiStrm); + + if (!MMSYSTEM_GetMidiStream(hMidiStrm, &lpMidiStrm, NULL)) { + ret = MMSYSERR_INVALHANDLE; + } else { + /* in case stream has been paused... FIXME is the current state correct ? */ + midiStreamRestart(hMidiStrm); + MMSYSTEM_MidiStream_PostMessage(lpMidiStrm, WINE_MSM_STOP, 0, 0); + } + return ret; +} + +UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType, + LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, + DWORD_PTR dwInstance, DWORD dwFlags, BOOL bFrom32) +{ + HANDLE handle; + LPWINE_MLD wmld; + DWORD dwRet = MMSYSERR_NOERROR; + WAVEOPENDESC wod; + + TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08lX, %d);\n", + lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback, + dwInstance, dwFlags, bFrom32?32:16); + + if (dwFlags & WAVE_FORMAT_QUERY) + TRACE("WAVE_FORMAT_QUERY requested !\n"); + + if (lpFormat == NULL) { + WARN("bad format\n"); + return WAVERR_BADFORMAT; + } + + if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1)) { + WARN("invalid parameter\n"); + return MMSYSERR_INVALPARAM; + } + + /* may have a PCMWAVEFORMAT rather than a WAVEFORMATEX so don't read cbSize */ + TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u\n", + lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec, + lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample); + + if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle, + &dwFlags, &dwCallback, &dwInstance, bFrom32)) == NULL) { + WARN("no memory\n"); + return MMSYSERR_NOMEM; + } + + wod.hWave = handle; + wod.lpFormat = (LPWAVEFORMATEX)lpFormat; /* should the struct be copied iso pointer? */ + wod.dwCallback = dwCallback; + wod.dwInstance = dwInstance; + wod.dnDevNode = 0L; + + TRACE("cb=%08lx\n", wod.dwCallback); + + for (;;) { + if (dwFlags & WAVE_MAPPED) { + wod.uMappedDeviceID = uDeviceID; + uDeviceID = WAVE_MAPPER; + } else { + wod.uMappedDeviceID = -1; + } + wmld->uDeviceID = uDeviceID; + + dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN, + (DWORD)&wod, dwFlags); + + TRACE("dwRet = %s\n", WINMM_ErrorToString(dwRet)); + if (dwRet != WAVERR_BADFORMAT || + ((dwFlags & (WAVE_MAPPED|WAVE_FORMAT_DIRECT)) != 0) || (uDeviceID == WAVE_MAPPER)) break; + /* if we ask for a format which isn't supported by the physical driver, + * let's try to map it through the wave mapper (except, if we already tried + * or user didn't allow us to use acm codecs or the device is already the mapper) + */ + dwFlags |= WAVE_MAPPED; + /* we shall loop only one */ + } + + if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) { + MMDRV_Free(handle, wmld); + handle = 0; + } + + if (lphndl != NULL) *lphndl = handle; + TRACE("=> %s hWave=%p\n", WINMM_ErrorToString(dwRet), handle); + + return dwRet; +} + +/************************************************************************** + * waveOutGetNumDevs [WINMM.@] + */ +UINT WINAPI waveOutGetNumDevs(void) +{ + return MMDRV_GetNum(MMDRV_WAVEOUT); +} + +/************************************************************************** + * waveOutGetDevCapsA [WINMM.@] + */ +UINT WINAPI waveOutGetDevCapsA(UINT_PTR uDeviceID, LPWAVEOUTCAPSA lpCaps, + UINT uSize) +{ + WAVEOUTCAPSW wocW; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = waveOutGetDevCapsW(uDeviceID, &wocW, sizeof(wocW)); + + if (ret == MMSYSERR_NOERROR) { + WAVEOUTCAPSA wocA; + wocA.wMid = wocW.wMid; + wocA.wPid = wocW.wPid; + wocA.vDriverVersion = wocW.vDriverVersion; + WideCharToMultiByte( CP_ACP, 0, wocW.szPname, -1, wocA.szPname, + sizeof(wocA.szPname), NULL, NULL ); + wocA.dwFormats = wocW.dwFormats; + wocA.wChannels = wocW.wChannels; + wocA.dwSupport = wocW.dwSupport; + memcpy(lpCaps, &wocA, min(uSize, sizeof(wocA))); + } + return ret; +} + +/************************************************************************** + * waveOutGetDevCapsW [WINMM.@] + */ +UINT WINAPI waveOutGetDevCapsW(UINT_PTR uDeviceID, LPWAVEOUTCAPSW lpCaps, + UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize); + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL) + return MMSYSERR_BADDEVICEID; + + return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE); + +} + +/************************************************************************** + * waveOutGetErrorTextA [WINMM.@] + * waveInGetErrorTextA [WINMM.@] + */ +UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize) +{ + UINT ret; + + if (lpText == NULL) ret = MMSYSERR_INVALPARAM; + else if (uSize == 0) ret = MMSYSERR_NOERROR; + else + { + LPWSTR xstr = HeapAlloc(GetProcessHeap(), 0, uSize * sizeof(WCHAR)); + if (!xstr) ret = MMSYSERR_NOMEM; + else + { + ret = waveOutGetErrorTextW(uError, xstr, uSize); + if (ret == MMSYSERR_NOERROR) + WideCharToMultiByte(CP_ACP, 0, xstr, -1, lpText, uSize, NULL, NULL); + HeapFree(GetProcessHeap(), 0, xstr); + } + } + return ret; +} + +/************************************************************************** + * waveOutGetErrorTextW [WINMM.@] + * waveInGetErrorTextW [WINMM.@] + */ +UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize) +{ + UINT ret = MMSYSERR_BADERRNUM; + + if (lpText == NULL) ret = MMSYSERR_INVALPARAM; + else if (uSize == 0) ret = MMSYSERR_NOERROR; + else if ( + /* test has been removed 'coz MMSYSERR_BASE is 0, and gcc did emit + * a warning for the test was always true */ + (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) || + (uError >= WAVERR_BASE && uError <= WAVERR_LASTERROR)) { + if (LoadStringW(WINMM_IData.hWinMM32Instance, + uError, lpText, uSize) > 0) { + ret = MMSYSERR_NOERROR; + } + } + return ret; +} + +/************************************************************************** + * waveOutOpen [WINMM.@] + * All the args/structs have the same layout as the win16 equivalents + */ +MMRESULT WINAPI waveOutOpen(LPHWAVEOUT lphWaveOut, UINT uDeviceID, + LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, + DWORD_PTR dwInstance, DWORD dwFlags) +{ + return WAVE_Open((HANDLE*)lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat, + dwCallback, dwInstance, dwFlags, TRUE); +} + +/************************************************************************** + * waveOutClose [WINMM.@] + */ +UINT WINAPI waveOutClose(HWAVEOUT hWaveOut) +{ + LPWINE_MLD wmld; + DWORD dwRet; + + TRACE("(%p)\n", hWaveOut); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + dwRet = MMDRV_Close(wmld, WODM_CLOSE); + if (dwRet != WAVERR_STILLPLAYING) + MMDRV_Free(hWaveOut, wmld); + + return dwRet; +} + +/************************************************************************** + * waveOutPrepareHeader [WINMM.@] + */ +UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut, + WAVEHDR* lpWaveOutHdr, UINT uSize) +{ + LPWINE_MLD wmld; + UINT result; + + TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize); + + if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR)) + return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + if ((result = MMDRV_Message(wmld, WODM_PREPARE, (DWORD_PTR)lpWaveOutHdr, + uSize, TRUE)) != MMSYSERR_NOTSUPPORTED) + return result; + + if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE) + return WAVERR_STILLPLAYING; + + lpWaveOutHdr->dwFlags |= WHDR_PREPARED; + lpWaveOutHdr->dwFlags &= ~WHDR_DONE; + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * waveOutUnprepareHeader [WINMM.@] + */ +UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut, + LPWAVEHDR lpWaveOutHdr, UINT uSize) +{ + LPWINE_MLD wmld; + UINT result; + + TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize); + + if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR)) + return MMSYSERR_INVALPARAM; + + if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) { + return MMSYSERR_NOERROR; + } + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + if ((result = MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD_PTR)lpWaveOutHdr, + uSize, TRUE)) != MMSYSERR_NOTSUPPORTED) + return result; + + if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE) + return WAVERR_STILLPLAYING; + + lpWaveOutHdr->dwFlags &= ~WHDR_PREPARED; + lpWaveOutHdr->dwFlags |= WHDR_DONE; + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * waveOutWrite [WINMM.@] + */ +UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr, + UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WODM_WRITE, (DWORD_PTR)lpWaveOutHdr, uSize, TRUE); +} + +/************************************************************************** + * waveOutBreakLoop [WINMM.@] + */ +UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut) +{ + LPWINE_MLD wmld; + + TRACE("(%p);\n", hWaveOut); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L, TRUE); +} + +/************************************************************************** + * waveOutPause [WINMM.@] + */ +UINT WINAPI waveOutPause(HWAVEOUT hWaveOut) +{ + LPWINE_MLD wmld; + + TRACE("(%p);\n", hWaveOut); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L, TRUE); +} + +/************************************************************************** + * waveOutReset [WINMM.@] + */ +UINT WINAPI waveOutReset(HWAVEOUT hWaveOut) +{ + LPWINE_MLD wmld; + + TRACE("(%p);\n", hWaveOut); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, WODM_RESET, 0L, 0L, TRUE); +} + +/************************************************************************** + * waveOutRestart [WINMM.@] + */ +UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut) +{ + LPWINE_MLD wmld; + + TRACE("(%p);\n", hWaveOut); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L, TRUE); +} + +/************************************************************************** + * waveOutGetPosition [WINMM.@] + */ +UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime, + UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %u);\n", hWaveOut, lpTime, uSize); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WODM_GETPOS, (DWORD_PTR)lpTime, uSize, TRUE); +} + +/************************************************************************** + * waveOutGetPitch [WINMM.@] + */ +UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD_PTR)lpdw, 0L, TRUE); +} + +/************************************************************************** + * waveOutSetPitch [WINMM.@] + */ +UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L, TRUE); +} + +/************************************************************************** + * waveOutGetPlaybackRate [WINMM.@] + */ +UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD_PTR)lpdw, 0L, TRUE); +} + +/************************************************************************** + * waveOutSetPlaybackRate [WINMM.@] + */ +UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)dw); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L, TRUE); +} + +/************************************************************************** + * waveOutGetVolume [WINMM.@] + */ +UINT WINAPI waveOutGetVolume(HWAVEOUT hWaveOut, LPDWORD lpdw) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %08lx);\n", hWaveOut, (DWORD)lpdw); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD_PTR)lpdw, 0L, TRUE); +} + +/************************************************************************** + * waveOutSetVolume [WINMM.@] + */ +UINT WINAPI waveOutSetVolume(HWAVEOUT hWaveOut, DWORD dw) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %08lx);\n", hWaveOut, dw); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L, TRUE); +} + +/************************************************************************** + * waveOutGetID [WINMM.@] + */ +UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p);\n", hWaveOut, lpuDeviceID); + + if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE; + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + *lpuDeviceID = wmld->uDeviceID; + return 0; +} + +/************************************************************************** + * waveOutMessage [WINMM.@] + */ +UINT WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage, + DWORD_PTR dwParam1, DWORD_PTR dwParam2) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2); + + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) { + if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) { + return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2); + } + WARN("invalid handle\n"); + return MMSYSERR_INVALHANDLE; + } + + /* from M$ KB */ + if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) { + WARN("invalid parameter\n"); + return MMSYSERR_INVALPARAM; + } + + return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE); +} + +/************************************************************************** + * waveInGetNumDevs [WINMM.@] + */ +UINT WINAPI waveInGetNumDevs(void) +{ + return MMDRV_GetNum(MMDRV_WAVEIN); +} + +/************************************************************************** + * waveInGetDevCapsW [WINMM.@] + */ +UINT WINAPI waveInGetDevCapsW(UINT_PTR uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%u %p %u)!\n", uDeviceID, lpCaps, uSize); + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL) + return MMSYSERR_BADDEVICEID; + + return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize, TRUE); +} + +/************************************************************************** + * waveInGetDevCapsA [WINMM.@] + */ +UINT WINAPI waveInGetDevCapsA(UINT_PTR uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize) +{ + WAVEINCAPSW wicW; + UINT ret; + + if (lpCaps == NULL) return MMSYSERR_INVALPARAM; + + ret = waveInGetDevCapsW(uDeviceID, &wicW, sizeof(wicW)); + + if (ret == MMSYSERR_NOERROR) { + WAVEINCAPSA wicA; + wicA.wMid = wicW.wMid; + wicA.wPid = wicW.wPid; + wicA.vDriverVersion = wicW.vDriverVersion; + WideCharToMultiByte( CP_ACP, 0, wicW.szPname, -1, wicA.szPname, + sizeof(wicA.szPname), NULL, NULL ); + wicA.dwFormats = wicW.dwFormats; + wicA.wChannels = wicW.wChannels; + memcpy(lpCaps, &wicA, min(uSize, sizeof(wicA))); + } + return ret; +} + +/************************************************************************** + * waveInOpen [WINMM.@] + */ +MMRESULT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID, + LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback, + DWORD_PTR dwInstance, DWORD dwFlags) +{ + return WAVE_Open((HANDLE*)lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat, + dwCallback, dwInstance, dwFlags, TRUE); +} + +/************************************************************************** + * waveInClose [WINMM.@] + */ +UINT WINAPI waveInClose(HWAVEIN hWaveIn) +{ + LPWINE_MLD wmld; + DWORD dwRet; + + TRACE("(%p)\n", hWaveIn); + + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L, TRUE); + if (dwRet != WAVERR_STILLPLAYING) + MMDRV_Free(hWaveIn, wmld); + return dwRet; +} + +/************************************************************************** + * waveInPrepareHeader [WINMM.@] + */ +UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr, + UINT uSize) +{ + LPWINE_MLD wmld; + UINT result; + + TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize); + + if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR)) + return MMSYSERR_INVALPARAM; + + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + if ((result = MMDRV_Message(wmld, WIDM_PREPARE, (DWORD_PTR)lpWaveInHdr, + uSize, TRUE)) != MMSYSERR_NOTSUPPORTED) + return result; + + if (lpWaveInHdr->dwFlags & WHDR_INQUEUE) + return WAVERR_STILLPLAYING; + + lpWaveInHdr->dwFlags |= WHDR_PREPARED; + lpWaveInHdr->dwFlags &= ~WHDR_DONE; + lpWaveInHdr->dwBytesRecorded = 0; + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * waveInUnprepareHeader [WINMM.@] + */ +UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr, + UINT uSize) +{ + LPWINE_MLD wmld; + UINT result; + + TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize); + + if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR)) + return MMSYSERR_INVALPARAM; + + if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED)) + return MMSYSERR_NOERROR; + + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + if ((result = MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD_PTR)lpWaveInHdr, + uSize, TRUE)) != MMSYSERR_NOTSUPPORTED) + return result; + + if (lpWaveInHdr->dwFlags & WHDR_INQUEUE) + return WAVERR_STILLPLAYING; + + lpWaveInHdr->dwFlags &= ~WHDR_PREPARED; + lpWaveInHdr->dwFlags |= WHDR_DONE; + + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * waveInAddBuffer [WINMM.@] + */ +UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn, + WAVEHDR* lpWaveInHdr, UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize); + + if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM; + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD_PTR)lpWaveInHdr, uSize, TRUE); +} + +/************************************************************************** + * waveInReset [WINMM.@] + */ +UINT WINAPI waveInReset(HWAVEIN hWaveIn) +{ + LPWINE_MLD wmld; + + TRACE("(%p);\n", hWaveIn); + + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L, TRUE); +} + +/************************************************************************** + * waveInStart [WINMM.@] + */ +UINT WINAPI waveInStart(HWAVEIN hWaveIn) +{ + LPWINE_MLD wmld; + + TRACE("(%p);\n", hWaveIn); + + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WIDM_START, 0L, 0L, TRUE); +} + +/************************************************************************** + * waveInStop [WINMM.@] + */ +UINT WINAPI waveInStop(HWAVEIN hWaveIn) +{ + LPWINE_MLD wmld; + + TRACE("(%p);\n", hWaveIn); + + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L, TRUE); +} + +/************************************************************************** + * waveInGetPosition [WINMM.@] + */ +UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime, + UINT uSize) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p, %u);\n", hWaveIn, lpTime, uSize); + + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD_PTR)lpTime, uSize, TRUE); +} + +/************************************************************************** + * waveInGetID [WINMM.@] + */ +UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %p);\n", hWaveIn, lpuDeviceID); + + if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE; + + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) + return MMSYSERR_INVALHANDLE; + + *lpuDeviceID = wmld->uDeviceID; + return MMSYSERR_NOERROR; +} + +/************************************************************************** + * waveInMessage [WINMM.@] + */ +UINT WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage, + DWORD_PTR dwParam1, DWORD_PTR dwParam2) +{ + LPWINE_MLD wmld; + + TRACE("(%p, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2); + + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) { + if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, TRUE)) != NULL) { + return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2); + } + return MMSYSERR_INVALHANDLE; + } + + /* from M$ KB */ + if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) + return MMSYSERR_INVALPARAM; + + + return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2, TRUE); +} + +struct mm_starter +{ + LPTASKCALLBACK cb; + DWORD client; + HANDLE event; +}; + +static DWORD WINAPI mmTaskRun(void* pmt) +{ + struct mm_starter mms; + + memcpy(&mms, pmt, sizeof(struct mm_starter)); + HeapFree(GetProcessHeap(), 0, pmt); + mms.cb(mms.client); + if (mms.event) SetEvent(mms.event); + return 0; +} + +/****************************************************************** + * mmTaskCreate (WINMM.@) + */ +MMRESULT WINAPI mmTaskCreate(LPTASKCALLBACK cb, HANDLE* ph, DWORD client) +{ + HANDLE hThread; + HANDLE hEvent = 0; + struct mm_starter *mms; + + mms = HeapAlloc(GetProcessHeap(), 0, sizeof(struct mm_starter)); + if (mms == NULL) return TASKERR_OUTOFMEMORY; + + mms->cb = cb; + mms->client = client; + if (ph) hEvent = CreateEventW(NULL, FALSE, FALSE, NULL); + mms->event = hEvent; + + hThread = CreateThread(0, 0, mmTaskRun, mms, 0, NULL); + if (!hThread) { + HeapFree(GetProcessHeap(), 0, mms); + if (hEvent) CloseHandle(hEvent); + return TASKERR_OUTOFMEMORY; + } + SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL); + if (ph) *ph = hEvent; + CloseHandle(hThread); + return 0; +} + +/****************************************************************** + * mmTaskBlock (WINMM.@) + */ +void WINAPI mmTaskBlock(HANDLE tid) +{ + MSG msg; + + do + { + GetMessageA(&msg, 0, 0, 0); + if (msg.hwnd) DispatchMessageA(&msg); + } while (msg.message != WM_USER); +} + +/****************************************************************** + * mmTaskSignal (WINMM.@) + */ +BOOL WINAPI mmTaskSignal(HANDLE tid) +{ + return PostThreadMessageW((DWORD)tid, WM_USER, 0, 0); +} + +/****************************************************************** + * mmTaskYield (WINMM.@) + */ +void WINAPI mmTaskYield(void) {} + +/****************************************************************** + * mmGetCurrentTask (WINMM.@) + */ +HANDLE WINAPI mmGetCurrentTask(void) +{ + return (HANDLE)GetCurrentThreadId(); +} diff --git a/reactos/lib/winsta/main.c b/reactos/lib/winsta/main.c index b9d235df8a5..20d9dee69dd 100644 --- a/reactos/lib/winsta/main.c +++ b/reactos/lib/winsta/main.c @@ -1,50 +1,50 @@ -/* - * ReactOS WinStation - * Copyright (C) 2005 ReactOS Team - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -/* $Id$ - * - * PROJECT: ReactOS winsta.dll - * FILE: lib/winsta/main.c - * PURPOSE: WinStation - * PROGRAMMER: Emanuele Aliberti <ea@reactos.com> - */ -#include <windows.h> - -HINSTANCE hDllInstance; - - -BOOL STDCALL -DllMain(HINSTANCE hinstDLL, - DWORD dwReason, - LPVOID lpvReserved) -{ - switch (dwReason) - { - case DLL_PROCESS_ATTACH: - hDllInstance = hinstDLL; - break; - case DLL_THREAD_ATTACH: - break; - case DLL_THREAD_DETACH: - break; - case DLL_PROCESS_DETACH: - break; - } - return TRUE; -} -/* EOF */ +/* + * ReactOS WinStation + * Copyright (C) 2005 ReactOS Team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* $Id$ + * + * PROJECT: ReactOS winsta.dll + * FILE: lib/winsta/main.c + * PURPOSE: WinStation + * PROGRAMMER: Emanuele Aliberti <ea@reactos.com> + */ +#include <windows.h> + +HINSTANCE hDllInstance; + + +BOOL STDCALL +DllMain(HINSTANCE hinstDLL, + DWORD dwReason, + LPVOID lpvReserved) +{ + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + hDllInstance = hinstDLL; + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + break; + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} +/* EOF */ diff --git a/reactos/lib/winsta/misc.c b/reactos/lib/winsta/misc.c index 9c030ab7cd5..88fb80923a4 100644 --- a/reactos/lib/winsta/misc.c +++ b/reactos/lib/winsta/misc.c @@ -1,12 +1,12 @@ -/* $Id$ */ -#include <windows.h> -#include "winsta.h" - -WINSTASTUB(LogonIdFromWinStationNameA) -WINSTASTUB(LogonIdFromWinStationNameW) -WINSTASTUB(RemoteAssistancePrepareSystemRestore) -WINSTASTUB(_NWLogonQueryAdmin) -WINSTASTUB(_NWLogonSetAdmin) -/* EOF */ - - +/* $Id$ */ +#include <windows.h> +#include "winsta.h" + +WINSTASTUB(LogonIdFromWinStationNameA) +WINSTASTUB(LogonIdFromWinStationNameW) +WINSTASTUB(RemoteAssistancePrepareSystemRestore) +WINSTASTUB(_NWLogonQueryAdmin) +WINSTASTUB(_NWLogonSetAdmin) +/* EOF */ + + diff --git a/reactos/lib/winsta/server.c b/reactos/lib/winsta/server.c index d54107537b3..9db26ffe8a3 100644 --- a/reactos/lib/winsta/server.c +++ b/reactos/lib/winsta/server.c @@ -1,21 +1,21 @@ -/* $Id$ */ -#include <windows.h> -#include "winsta.h" - -WINSTASTUB(ServerGetInternetConnectorStatus) -WINSTASTUB(ServerLicensingClose) -WINSTASTUB(ServerLicensingDeactivateCurrentPolicy) -WINSTASTUB(ServerLicensingFreePolicyInformation) -WINSTASTUB(ServerLicensingGetAvailablePolicyIds) -WINSTASTUB(ServerLicensingGetPolicy) -WINSTASTUB(ServerLicensingGetPolicyInformationA) -WINSTASTUB(ServerLicensingGetPolicyInformationW) -WINSTASTUB(ServerLicensingLoadPolicy) -WINSTASTUB(ServerLicensingOpenA) -WINSTASTUB(ServerLicensingOpenW) -WINSTASTUB(ServerLicensingSetPolicy) -WINSTASTUB(ServerLicensingUnloadPolicy) -WINSTASTUB(ServerQueryInetConnectorInformationA) -WINSTASTUB(ServerQueryInetConnectorInformationW) -WINSTASTUB(ServerSetInternetConnectorStatus) -/* EOF */ +/* $Id$ */ +#include <windows.h> +#include "winsta.h" + +WINSTASTUB(ServerGetInternetConnectorStatus) +WINSTASTUB(ServerLicensingClose) +WINSTASTUB(ServerLicensingDeactivateCurrentPolicy) +WINSTASTUB(ServerLicensingFreePolicyInformation) +WINSTASTUB(ServerLicensingGetAvailablePolicyIds) +WINSTASTUB(ServerLicensingGetPolicy) +WINSTASTUB(ServerLicensingGetPolicyInformationA) +WINSTASTUB(ServerLicensingGetPolicyInformationW) +WINSTASTUB(ServerLicensingLoadPolicy) +WINSTASTUB(ServerLicensingOpenA) +WINSTASTUB(ServerLicensingOpenW) +WINSTASTUB(ServerLicensingSetPolicy) +WINSTASTUB(ServerLicensingUnloadPolicy) +WINSTASTUB(ServerQueryInetConnectorInformationA) +WINSTASTUB(ServerQueryInetConnectorInformationW) +WINSTASTUB(ServerSetInternetConnectorStatus) +/* EOF */ diff --git a/reactos/lib/winsta/winsta.h b/reactos/lib/winsta/winsta.h index 86e74ea2ab0..2870d726af9 100644 --- a/reactos/lib/winsta/winsta.h +++ b/reactos/lib/winsta/winsta.h @@ -1,7 +1,7 @@ -#if !defined(_WINSTA_H) -#define _WINSTA_H - -#define WINSTASTUB(n) VOID STDCALL n (VOID) { } - -#endif /* !def _WINSTA_H */ - +#if !defined(_WINSTA_H) +#define _WINSTA_H + +#define WINSTASTUB(n) VOID STDCALL n (VOID) { } + +#endif /* !def _WINSTA_H */ + diff --git a/reactos/lib/winsta/ws.c b/reactos/lib/winsta/ws.c index fd574959dc4..78f6d4b332d 100644 --- a/reactos/lib/winsta/ws.c +++ b/reactos/lib/winsta/ws.c @@ -1,80 +1,80 @@ -/* $Id$ */ -#include <windows.h> -#include "winsta.h" - -WINSTASTUB(WinStationActivateLicense) -WINSTASTUB(WinStationAutoReconnect) -WINSTASTUB(WinStationBroadcastSystemMessage) -WINSTASTUB(WinStationCheckLoopBack) -WINSTASTUB(WinStationCloseServer) -WINSTASTUB(WinStationConnectA) -WINSTASTUB(WinStationConnectCallback) -WINSTASTUB(WinStationConnectW) -WINSTASTUB(WinStationDisconnect) -WINSTASTUB(WinStationEnumerateA) -WINSTASTUB(WinStationEnumerateLicenses) -WINSTASTUB(WinStationEnumerateProcesses) -WINSTASTUB(WinStationEnumerateW) -WINSTASTUB(WinStationEnumerate_IndexedA) -WINSTASTUB(WinStationEnumerate_IndexedW) -WINSTASTUB(WinStationFreeGAPMemory) -WINSTASTUB(WinStationFreeMemory) -WINSTASTUB(WinStationGenerateLicense) -WINSTASTUB(WinStationGetAllProcesses) -WINSTASTUB(WinStationGetLanAdapterNameA) -WINSTASTUB(WinStationGetLanAdapterNameW) -WINSTASTUB(WinStationGetMachinePolicy) -WINSTASTUB(WinStationGetProcessSid) -WINSTASTUB(WinStationGetTermSrvCountersValue) -WINSTASTUB(WinStationInstallLicense) -WINSTASTUB(WinStationIsHelpAssistantSession) -WINSTASTUB(WinStationNameFromLogonIdA) -WINSTASTUB(WinStationNameFromLogonIdW) -WINSTASTUB(WinStationNtsdDebug) -WINSTASTUB(WinStationOpenServerA) -WINSTASTUB(WinStationOpenServerW) -WINSTASTUB(WinStationQueryInformationA) -WINSTASTUB(WinStationQueryInformationW) -WINSTASTUB(WinStationQueryLicense) -WINSTASTUB(WinStationQueryLogonCredentialsW) -WINSTASTUB(WinStationQueryUpdateRequired) -WINSTASTUB(WinStationRegisterConsoleNotification) -WINSTASTUB(WinStationRemoveLicense) -WINSTASTUB(WinStationRenameA) -WINSTASTUB(WinStationRenameW) -WINSTASTUB(WinStationRequestSessionsList) -WINSTASTUB(WinStationReset) -WINSTASTUB(WinStationSendMessageA) -WINSTASTUB(WinStationSendMessageW) -WINSTASTUB(WinStationSendWindowMessage) -WINSTASTUB(WinStationServerPing) -WINSTASTUB(WinStationSetInformationA) -WINSTASTUB(WinStationSetInformationW) -WINSTASTUB(WinStationSetPoolCount) -WINSTASTUB(WinStationShadow) -WINSTASTUB(WinStationShadowStop) -WINSTASTUB(WinStationShutdownSystem) -WINSTASTUB(WinStationTerminateProcess) -WINSTASTUB(WinStationUnRegisterConsoleNotification) -WINSTASTUB(WinStationVirtualOpen) -WINSTASTUB(WinStationWaitSystemEvent) -WINSTASTUB(_WinStationAnnoyancePopup) -WINSTASTUB(_WinStationBeepOpen) -WINSTASTUB(_WinStationBreakPoint) -WINSTASTUB(_WinStationCallback) -WINSTASTUB(_WinStationCheckForApplicationName) -WINSTASTUB(_WinStationFUSCanRemoteUserDisconnect) -WINSTASTUB(_WinStationGetApplicationInfo) -WINSTASTUB(_WinStationNotifyDisconnectPipe) -WINSTASTUB(_WinStationNotifyLogoff) -WINSTASTUB(_WinStationNotifyLogon) -WINSTASTUB(_WinStationNotifyNewSession) -WINSTASTUB(_WinStationReInitializeSecurity) -WINSTASTUB(_WinStationReadRegistry) -WINSTASTUB(_WinStationShadowTarget) -WINSTASTUB(_WinStationShadowTargetSetup) -WINSTASTUB(_WinStationUpdateClientCachedCredentials) -WINSTASTUB(_WinStationUpdateSettings) -WINSTASTUB(_WinStationUpdateUserConfig) -WINSTASTUB(_WinStationWaitForConnect) -/* EOF */ +/* $Id$ */ +#include <windows.h> +#include "winsta.h" + +WINSTASTUB(WinStationActivateLicense) +WINSTASTUB(WinStationAutoReconnect) +WINSTASTUB(WinStationBroadcastSystemMessage) +WINSTASTUB(WinStationCheckLoopBack) +WINSTASTUB(WinStationCloseServer) +WINSTASTUB(WinStationConnectA) +WINSTASTUB(WinStationConnectCallback) +WINSTASTUB(WinStationConnectW) +WINSTASTUB(WinStationDisconnect) +WINSTASTUB(WinStationEnumerateA) +WINSTASTUB(WinStationEnumerateLicenses) +WINSTASTUB(WinStationEnumerateProcesses) +WINSTASTUB(WinStationEnumerateW) +WINSTASTUB(WinStationEnumerate_IndexedA) +WINSTASTUB(WinStationEnumerate_IndexedW) +WINSTASTUB(WinStationFreeGAPMemory) +WINSTASTUB(WinStationFreeMemory) +WINSTASTUB(WinStationGenerateLicense) +WINSTASTUB(WinStationGetAllProcesses) +WINSTASTUB(WinStationGetLanAdapterNameA) +WINSTASTUB(WinStationGetLanAdapterNameW) +WINSTASTUB(WinStationGetMachinePolicy) +WINSTASTUB(WinStationGetProcessSid) +WINSTASTUB(WinStationGetTermSrvCountersValue) +WINSTASTUB(WinStationInstallLicense) +WINSTASTUB(WinStationIsHelpAssistantSession) +WINSTASTUB(WinStationNameFromLogonIdA) +WINSTASTUB(WinStationNameFromLogonIdW) +WINSTASTUB(WinStationNtsdDebug) +WINSTASTUB(WinStationOpenServerA) +WINSTASTUB(WinStationOpenServerW) +WINSTASTUB(WinStationQueryInformationA) +WINSTASTUB(WinStationQueryInformationW) +WINSTASTUB(WinStationQueryLicense) +WINSTASTUB(WinStationQueryLogonCredentialsW) +WINSTASTUB(WinStationQueryUpdateRequired) +WINSTASTUB(WinStationRegisterConsoleNotification) +WINSTASTUB(WinStationRemoveLicense) +WINSTASTUB(WinStationRenameA) +WINSTASTUB(WinStationRenameW) +WINSTASTUB(WinStationRequestSessionsList) +WINSTASTUB(WinStationReset) +WINSTASTUB(WinStationSendMessageA) +WINSTASTUB(WinStationSendMessageW) +WINSTASTUB(WinStationSendWindowMessage) +WINSTASTUB(WinStationServerPing) +WINSTASTUB(WinStationSetInformationA) +WINSTASTUB(WinStationSetInformationW) +WINSTASTUB(WinStationSetPoolCount) +WINSTASTUB(WinStationShadow) +WINSTASTUB(WinStationShadowStop) +WINSTASTUB(WinStationShutdownSystem) +WINSTASTUB(WinStationTerminateProcess) +WINSTASTUB(WinStationUnRegisterConsoleNotification) +WINSTASTUB(WinStationVirtualOpen) +WINSTASTUB(WinStationWaitSystemEvent) +WINSTASTUB(_WinStationAnnoyancePopup) +WINSTASTUB(_WinStationBeepOpen) +WINSTASTUB(_WinStationBreakPoint) +WINSTASTUB(_WinStationCallback) +WINSTASTUB(_WinStationCheckForApplicationName) +WINSTASTUB(_WinStationFUSCanRemoteUserDisconnect) +WINSTASTUB(_WinStationGetApplicationInfo) +WINSTASTUB(_WinStationNotifyDisconnectPipe) +WINSTASTUB(_WinStationNotifyLogoff) +WINSTASTUB(_WinStationNotifyLogon) +WINSTASTUB(_WinStationNotifyNewSession) +WINSTASTUB(_WinStationReInitializeSecurity) +WINSTASTUB(_WinStationReadRegistry) +WINSTASTUB(_WinStationShadowTarget) +WINSTASTUB(_WinStationShadowTargetSetup) +WINSTASTUB(_WinStationUpdateClientCachedCredentials) +WINSTASTUB(_WinStationUpdateSettings) +WINSTASTUB(_WinStationUpdateUserConfig) +WINSTASTUB(_WinStationWaitForConnect) +/* EOF */ diff --git a/reactos/ntoskrnl/mm/process.c b/reactos/ntoskrnl/mm/process.c index 788d7a59789..d7c987e6994 100644 --- a/reactos/ntoskrnl/mm/process.c +++ b/reactos/ntoskrnl/mm/process.c @@ -1,546 +1,546 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: ntoskrnl/mm/process.c - * PURPOSE: Memory functions related to Processes - * - * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - */ - -/* INCLUDES *****************************************************************/ - -#include <ntoskrnl.h> -#define NDEBUG -#include <internal/debug.h> - -extern ULONG NtMajorVersion; -extern ULONG NtMinorVersion; -extern ULONG NtOSCSDVersion; -extern ULONG NtGlobalFlag; - -/* FUNCTIONS *****************************************************************/ - -PVOID -STDCALL -MiCreatePebOrTeb(PEPROCESS Process, - PVOID BaseAddress) -{ - NTSTATUS Status; - PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace; - PMEMORY_AREA MemoryArea; - PHYSICAL_ADDRESS BoundaryAddressMultiple; - PVOID AllocatedBase = BaseAddress; - BoundaryAddressMultiple.QuadPart = 0; - - /* Acquire the Lock */ - MmLockAddressSpace(ProcessAddressSpace); - - /* - * Create a Peb or Teb. - * Loop until it works, decreasing by PAGE_SIZE each time. The logic here - * is that a PEB allocation should never fail since the address is free, - * while TEB allocation can fail, and we should simply try the address - * below. Is there a nicer way of doing this automagically? (ie: findning) - * a gap region? -- Alex - */ - do { - DPRINT("Trying to allocate: %x\n", AllocatedBase); - Status = MmCreateMemoryArea(Process, - ProcessAddressSpace, - MEMORY_AREA_PEB_OR_TEB, - &AllocatedBase, - PAGE_SIZE, - PAGE_READWRITE, - &MemoryArea, - TRUE, - FALSE, - BoundaryAddressMultiple); - AllocatedBase = RVA(AllocatedBase, -PAGE_SIZE); - } while (Status != STATUS_SUCCESS); - - /* Initialize the Region */ - MmInitialiseRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead, - PAGE_SIZE, - MEM_COMMIT, - PAGE_READWRITE); - - /* Reserve the pages */ - MmReserveSwapPages(PAGE_SIZE); - - /* Unlock Address Space */ - DPRINT("Returning\n"); - MmUnlockAddressSpace(ProcessAddressSpace); - return RVA(AllocatedBase, PAGE_SIZE); -} - -VOID -MiFreeStackPage(PVOID Context, - MEMORY_AREA* MemoryArea, - PVOID Address, - PFN_TYPE Page, - SWAPENTRY SwapEntry, - BOOLEAN Dirty) -{ - ASSERT(SwapEntry == 0); - if (Page) MmReleasePageMemoryConsumer(MC_NPPOOL, Page); -} - -VOID -STDCALL -MmDeleteKernelStack(PVOID Stack, - BOOLEAN GuiStack) -{ - /* Lock the Address Space */ - MmLockAddressSpace(MmGetKernelAddressSpace()); - - /* Delete the Stack */ - MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(), - Stack, - MiFreeStackPage, - NULL); - - /* Unlock the Address Space */ - MmUnlockAddressSpace(MmGetKernelAddressSpace()); -} - -VOID -MiFreePebPage(PVOID Context, - MEMORY_AREA* MemoryArea, - PVOID Address, - PFN_TYPE Page, - SWAPENTRY SwapEntry, - BOOLEAN Dirty) -{ - PEPROCESS Process = (PEPROCESS)Context; - - if (Page != 0) - { - SWAPENTRY SavedSwapEntry; - SavedSwapEntry = MmGetSavedSwapEntryPage(Page); - if (SavedSwapEntry != 0) - { - MmFreeSwapPage(SavedSwapEntry); - MmSetSavedSwapEntryPage(Page, 0); - } - MmDeleteRmap(Page, Process, Address); - MmReleasePageMemoryConsumer(MC_USER, Page); - } - else if (SwapEntry != 0) - { - MmFreeSwapPage(SwapEntry); - } -} - -VOID -STDCALL -MmDeleteTeb(PEPROCESS Process, - PTEB Teb) -{ - PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace; - - /* Lock the Address Space */ - MmLockAddressSpace(ProcessAddressSpace); - - /* Delete the Stack */ - MmFreeMemoryAreaByPtr(ProcessAddressSpace, - Teb, - MiFreePebPage, - Process); - - /* Unlock the Address Space */ - MmUnlockAddressSpace(ProcessAddressSpace); -} - -PVOID -STDCALL -MmCreateKernelStack(BOOLEAN GuiStack) -{ - PMEMORY_AREA StackArea; - ULONG i; - PHYSICAL_ADDRESS BoundaryAddressMultiple; - PFN_TYPE Page[MM_STACK_SIZE / PAGE_SIZE]; - PVOID KernelStack = NULL; - NTSTATUS Status; - - /* Initialize the Boundary Address */ - BoundaryAddressMultiple.QuadPart = 0; - - /* Lock the Kernel Address Space */ - MmLockAddressSpace(MmGetKernelAddressSpace()); - - /* Create a MAREA for the Kernel Stack */ - Status = MmCreateMemoryArea(NULL, - MmGetKernelAddressSpace(), - MEMORY_AREA_KERNEL_STACK, - &KernelStack, - MM_STACK_SIZE, - 0, - &StackArea, - FALSE, - FALSE, - BoundaryAddressMultiple); - - /* Unlock the Address Space */ - MmUnlockAddressSpace(MmGetKernelAddressSpace()); - - /* Check for Success */ - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to create thread stack\n"); - KEBUGCHECK(0); - } - - /* Mark the Stack in use */ - for (i = 0; i < (MM_STACK_SIZE / PAGE_SIZE); i++) - { - Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page[i]); - } - - /* Create a Virtual Mapping for it */ - Status = MmCreateVirtualMapping(NULL, - KernelStack, - PAGE_READWRITE, - Page, - MM_STACK_SIZE / PAGE_SIZE); - - /* Check for success */ - if (!NT_SUCCESS(Status)) - { - DPRINT1("Could not create Virtual Mapping for Kernel Stack\n"); - KEBUGCHECK(0); - } - - return KernelStack; -} - -NTSTATUS -STDCALL -MmCreatePeb(PEPROCESS Process) -{ - PPEB Peb = NULL; - LARGE_INTEGER SectionOffset; - ULONG ViewSize = 0; - PVOID TableBase = NULL; - PIMAGE_NT_HEADERS NtHeaders; - PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData; - NTSTATUS Status; - KAFFINITY ProcessAffinityMask = 0; - SectionOffset.QuadPart = (ULONGLONG)0; - - DPRINT("MmCreatePeb\n"); - - /* Map NLS Tables */ - DPRINT("Mapping NLS\n"); - Status = MmMapViewOfSection(NlsSectionObject, - Process, - &TableBase, - 0, - 0, - &SectionOffset, - &ViewSize, - ViewShare, - MEM_TOP_DOWN, - PAGE_READONLY); - if (!NT_SUCCESS(Status)) - { - DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status); - return(Status); - } - DPRINT("TableBase %p ViewSize %lx\n", TableBase, ViewSize); - - /* Attach to Process */ - KeAttachProcess(&Process->Pcb); - - /* Allocate the PEB */ - Peb = MiCreatePebOrTeb(Process, (PVOID)PEB_BASE); - - /* Initialize the PEB */ - DPRINT("Allocated: %x\n", Peb); - RtlZeroMemory(Peb, sizeof(PEB)); - - /* Set up data */ - DPRINT("Setting up PEB\n"); - Peb->ImageBaseAddress = Process->SectionBaseAddress; - Peb->InheritedAddressSpace = 0; - Peb->Mutant = NULL; - - /* NLS */ - Peb->AnsiCodePageData = (char*)TableBase + NlsAnsiTableOffset; - Peb->OemCodePageData = (char*)TableBase + NlsOemTableOffset; - Peb->UnicodeCaseTableData = (char*)TableBase + NlsUnicodeTableOffset; - - /* Default Version Data (could get changed below) */ - Peb->OSMajorVersion = NtMajorVersion; - Peb->OSMinorVersion = NtMinorVersion; - Peb->OSBuildNumber = 2195; - Peb->OSPlatformId = 2; /* VER_PLATFORM_WIN32_NT */ - Peb->OSCSDVersion = NtOSCSDVersion; - - /* Heap and Debug Data */ - Peb->NumberOfProcessors = KeNumberProcessors; - Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL ? TRUE : FALSE); - Peb->NtGlobalFlag = NtGlobalFlag; - /*Peb->HeapSegmentReserve = MmHeapSegmentReserve; - Peb->HeapSegmentCommit = MmHeapSegmentCommit; - Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold; - Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;*/ - Peb->NumberOfHeaps = 0; - Peb->MaximumNumberOfHeaps = (PAGE_SIZE - sizeof(PEB)) / sizeof(PVOID); - Peb->ProcessHeaps = (PVOID*)Peb + 1; - - /* Image Data */ - if ((NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress))) - { - /* Get the Image Config Data too */ - ImageConfigData = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress, - TRUE, - IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, - &ViewSize); - - /* Write subsystem data */ - Peb->ImageSubSystem = NtHeaders->OptionalHeader.Subsystem; - Peb->ImageSubSystemMajorVersion = NtHeaders->OptionalHeader.MajorSubsystemVersion; - Peb->ImageSubSystemMinorVersion = NtHeaders->OptionalHeader.MinorSubsystemVersion; - - /* Write Version Data */ - if (NtHeaders->OptionalHeader.Win32VersionValue) - { - Peb->OSMajorVersion = NtHeaders->OptionalHeader.Win32VersionValue & 0xFF; - Peb->OSMinorVersion = (NtHeaders->OptionalHeader.Win32VersionValue >> 8) & 0xFF; - Peb->OSBuildNumber = (NtHeaders->OptionalHeader.Win32VersionValue >> 16) & 0x3FFF; - - /* Lie about the version if requested */ - if (ImageConfigData && ImageConfigData->CSDVersion) - { - Peb->OSCSDVersion = ImageConfigData->CSDVersion; - } - - /* Set the Platform ID */ - Peb->OSPlatformId = (NtHeaders->OptionalHeader.Win32VersionValue >> 30) ^ 2; - } - - /* Check for affinity override */ - if (ImageConfigData && ImageConfigData->ProcessAffinityMask) - { - ProcessAffinityMask = ImageConfigData->ProcessAffinityMask; - } - - /* Check if the image is not safe for SMP */ - if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY) - { - /* FIXME: Choose one randomly */ - Peb->ImageProcessAffinityMask = 1; - } - else - { - /* Use affinity from Image Header */ - Peb->ImageProcessAffinityMask = ProcessAffinityMask; - } - } - - /* Misc data */ - Peb->SessionId = Process->Session; - Process->Peb = Peb; - - /* Detach from the Process */ - KeDetachProcess(); - - DPRINT("MmCreatePeb: Peb created at %p\n", Peb); - return STATUS_SUCCESS; -} - -PTEB -STDCALL -MmCreateTeb(PEPROCESS Process, - PCLIENT_ID ClientId, - PINITIAL_TEB InitialTeb) -{ - PTEB Teb; - BOOLEAN Attached = FALSE; - - /* Attach to the process */ - DPRINT("MmCreateTeb\n"); - if (Process != PsGetCurrentProcess()) - { - /* Attach to Target */ - KeAttachProcess(&Process->Pcb); - Attached = TRUE; - } - - /* Allocate the TEB */ - Teb = MiCreatePebOrTeb(Process, (PVOID)TEB_BASE); - - /* Initialize the PEB */ - RtlZeroMemory(Teb, sizeof(TEB)); - - /* Set TIB Data */ - Teb->Tib.ExceptionList = (PVOID)0xFFFFFFFF; - Teb->Tib.Version = 1; - Teb->Tib.Self = (PNT_TIB)Teb; - - /* Set TEB Data */ - Teb->Cid = *ClientId; - Teb->RealClientId = *ClientId; - Teb->ProcessEnvironmentBlock = Process->Peb; - Teb->CurrentLocale = PsDefaultThreadLocaleId; - - /* Store stack information from InitialTeb */ - if(InitialTeb != NULL) - { - Teb->Tib.StackBase = InitialTeb->StackBase; - Teb->Tib.StackLimit = InitialTeb->StackLimit; - Teb->DeallocationStack = InitialTeb->AllocatedStackBase; - } - - /* Return TEB Address */ - DPRINT("Allocated: %x\n", Teb); - if (Attached) KeDetachProcess(); - return Teb; -} - -NTSTATUS -STDCALL -MmCreateProcessAddressSpace(IN PEPROCESS Process, - IN PSECTION_OBJECT Section OPTIONAL) -{ - NTSTATUS Status; - PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace; - PVOID BaseAddress; - PMEMORY_AREA MemoryArea; - PHYSICAL_ADDRESS BoundaryAddressMultiple; - ULONG ViewSize = 0; - PVOID ImageBase = 0; - BoundaryAddressMultiple.QuadPart = 0; - - /* Initialize the Addresss Space */ - MmInitializeAddressSpace(Process, ProcessAddressSpace); - - /* Acquire the Lock */ - MmLockAddressSpace(ProcessAddressSpace); - - /* Protect the highest 64KB of the process address space */ - BaseAddress = (PVOID)MmUserProbeAddress; - Status = MmCreateMemoryArea(Process, - ProcessAddressSpace, - MEMORY_AREA_NO_ACCESS, - &BaseAddress, - 0x10000, - PAGE_NOACCESS, - &MemoryArea, - FALSE, - FALSE, - BoundaryAddressMultiple); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to protect last 64KB\n"); - goto exit; - } - - /* Protect the 60KB above the shared user page */ - BaseAddress = (char*)USER_SHARED_DATA + PAGE_SIZE; - Status = MmCreateMemoryArea(Process, - ProcessAddressSpace, - MEMORY_AREA_NO_ACCESS, - &BaseAddress, - 0x10000 - PAGE_SIZE, - PAGE_NOACCESS, - &MemoryArea, - FALSE, - FALSE, - BoundaryAddressMultiple); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to protect the memory above the shared user page\n"); - goto exit; - } - - /* Create the shared data page */ - BaseAddress = (PVOID)USER_SHARED_DATA; - Status = MmCreateMemoryArea(Process, - ProcessAddressSpace, - MEMORY_AREA_SHARED_DATA, - &BaseAddress, - PAGE_SIZE, - PAGE_READONLY, - &MemoryArea, - FALSE, - FALSE, - BoundaryAddressMultiple); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to create Shared User Data\n"); - goto exit; - } - - /* Check if there's a Section Object */ - if (Section) - { - UNICODE_STRING FileName; - PWCHAR szSrc; - PCHAR szDest; - USHORT lnFName = 0; - - /* Unlock the Address Space */ - DPRINT("Unlocking\n"); - MmUnlockAddressSpace(ProcessAddressSpace); - - DPRINT("Mapping process image. Section: %p, Process: %p, ImageBase: %p\n", - Section, Process, &ImageBase); - Status = MmMapViewOfSection(Section, - Process, - (PVOID*)&ImageBase, - 0, - 0, - NULL, - &ViewSize, - 0, - MEM_COMMIT, - PAGE_READWRITE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to map process Image\n"); - ObDereferenceObject(Section); - goto exit; - } - ObDereferenceObject(Section); - - /* Save the pointer */ - Process->SectionBaseAddress = ImageBase; - - /* Determine the image file name and save it to EPROCESS */ - DPRINT("Getting Image name\n"); - FileName = Section->FileObject->FileName; - szSrc = (PWCHAR)(FileName.Buffer + (FileName.Length / sizeof(WCHAR)) - 1); - - while(szSrc >= FileName.Buffer) - { - if(*szSrc == L'\\') - { - szSrc++; - break; - } - else - { - szSrc--; - lnFName++; - } - } - - /* Copy the to the process and truncate it to 15 characters if necessary */ - DPRINT("Copying and truncating\n"); - szDest = Process->ImageFileName; - lnFName = min(lnFName, sizeof(Process->ImageFileName) - 1); - while(lnFName-- > 0) *(szDest++) = (UCHAR)*(szSrc++); - - /* Return status to caller */ - return Status; - } - -exit: - /* Unlock the Address Space */ - DPRINT("Unlocking\n"); - MmUnlockAddressSpace(ProcessAddressSpace); - - /* Return status to caller */ - return Status; -} +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/mm/process.c + * PURPOSE: Memory functions related to Processes + * + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) + */ + +/* INCLUDES *****************************************************************/ + +#include <ntoskrnl.h> +#define NDEBUG +#include <internal/debug.h> + +extern ULONG NtMajorVersion; +extern ULONG NtMinorVersion; +extern ULONG NtOSCSDVersion; +extern ULONG NtGlobalFlag; + +/* FUNCTIONS *****************************************************************/ + +PVOID +STDCALL +MiCreatePebOrTeb(PEPROCESS Process, + PVOID BaseAddress) +{ + NTSTATUS Status; + PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace; + PMEMORY_AREA MemoryArea; + PHYSICAL_ADDRESS BoundaryAddressMultiple; + PVOID AllocatedBase = BaseAddress; + BoundaryAddressMultiple.QuadPart = 0; + + /* Acquire the Lock */ + MmLockAddressSpace(ProcessAddressSpace); + + /* + * Create a Peb or Teb. + * Loop until it works, decreasing by PAGE_SIZE each time. The logic here + * is that a PEB allocation should never fail since the address is free, + * while TEB allocation can fail, and we should simply try the address + * below. Is there a nicer way of doing this automagically? (ie: findning) + * a gap region? -- Alex + */ + do { + DPRINT("Trying to allocate: %x\n", AllocatedBase); + Status = MmCreateMemoryArea(Process, + ProcessAddressSpace, + MEMORY_AREA_PEB_OR_TEB, + &AllocatedBase, + PAGE_SIZE, + PAGE_READWRITE, + &MemoryArea, + TRUE, + FALSE, + BoundaryAddressMultiple); + AllocatedBase = RVA(AllocatedBase, -PAGE_SIZE); + } while (Status != STATUS_SUCCESS); + + /* Initialize the Region */ + MmInitialiseRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead, + PAGE_SIZE, + MEM_COMMIT, + PAGE_READWRITE); + + /* Reserve the pages */ + MmReserveSwapPages(PAGE_SIZE); + + /* Unlock Address Space */ + DPRINT("Returning\n"); + MmUnlockAddressSpace(ProcessAddressSpace); + return RVA(AllocatedBase, PAGE_SIZE); +} + +VOID +MiFreeStackPage(PVOID Context, + MEMORY_AREA* MemoryArea, + PVOID Address, + PFN_TYPE Page, + SWAPENTRY SwapEntry, + BOOLEAN Dirty) +{ + ASSERT(SwapEntry == 0); + if (Page) MmReleasePageMemoryConsumer(MC_NPPOOL, Page); +} + +VOID +STDCALL +MmDeleteKernelStack(PVOID Stack, + BOOLEAN GuiStack) +{ + /* Lock the Address Space */ + MmLockAddressSpace(MmGetKernelAddressSpace()); + + /* Delete the Stack */ + MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(), + Stack, + MiFreeStackPage, + NULL); + + /* Unlock the Address Space */ + MmUnlockAddressSpace(MmGetKernelAddressSpace()); +} + +VOID +MiFreePebPage(PVOID Context, + MEMORY_AREA* MemoryArea, + PVOID Address, + PFN_TYPE Page, + SWAPENTRY SwapEntry, + BOOLEAN Dirty) +{ + PEPROCESS Process = (PEPROCESS)Context; + + if (Page != 0) + { + SWAPENTRY SavedSwapEntry; + SavedSwapEntry = MmGetSavedSwapEntryPage(Page); + if (SavedSwapEntry != 0) + { + MmFreeSwapPage(SavedSwapEntry); + MmSetSavedSwapEntryPage(Page, 0); + } + MmDeleteRmap(Page, Process, Address); + MmReleasePageMemoryConsumer(MC_USER, Page); + } + else if (SwapEntry != 0) + { + MmFreeSwapPage(SwapEntry); + } +} + +VOID +STDCALL +MmDeleteTeb(PEPROCESS Process, + PTEB Teb) +{ + PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace; + + /* Lock the Address Space */ + MmLockAddressSpace(ProcessAddressSpace); + + /* Delete the Stack */ + MmFreeMemoryAreaByPtr(ProcessAddressSpace, + Teb, + MiFreePebPage, + Process); + + /* Unlock the Address Space */ + MmUnlockAddressSpace(ProcessAddressSpace); +} + +PVOID +STDCALL +MmCreateKernelStack(BOOLEAN GuiStack) +{ + PMEMORY_AREA StackArea; + ULONG i; + PHYSICAL_ADDRESS BoundaryAddressMultiple; + PFN_TYPE Page[MM_STACK_SIZE / PAGE_SIZE]; + PVOID KernelStack = NULL; + NTSTATUS Status; + + /* Initialize the Boundary Address */ + BoundaryAddressMultiple.QuadPart = 0; + + /* Lock the Kernel Address Space */ + MmLockAddressSpace(MmGetKernelAddressSpace()); + + /* Create a MAREA for the Kernel Stack */ + Status = MmCreateMemoryArea(NULL, + MmGetKernelAddressSpace(), + MEMORY_AREA_KERNEL_STACK, + &KernelStack, + MM_STACK_SIZE, + 0, + &StackArea, + FALSE, + FALSE, + BoundaryAddressMultiple); + + /* Unlock the Address Space */ + MmUnlockAddressSpace(MmGetKernelAddressSpace()); + + /* Check for Success */ + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to create thread stack\n"); + KEBUGCHECK(0); + } + + /* Mark the Stack in use */ + for (i = 0; i < (MM_STACK_SIZE / PAGE_SIZE); i++) + { + Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Page[i]); + } + + /* Create a Virtual Mapping for it */ + Status = MmCreateVirtualMapping(NULL, + KernelStack, + PAGE_READWRITE, + Page, + MM_STACK_SIZE / PAGE_SIZE); + + /* Check for success */ + if (!NT_SUCCESS(Status)) + { + DPRINT1("Could not create Virtual Mapping for Kernel Stack\n"); + KEBUGCHECK(0); + } + + return KernelStack; +} + +NTSTATUS +STDCALL +MmCreatePeb(PEPROCESS Process) +{ + PPEB Peb = NULL; + LARGE_INTEGER SectionOffset; + ULONG ViewSize = 0; + PVOID TableBase = NULL; + PIMAGE_NT_HEADERS NtHeaders; + PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData; + NTSTATUS Status; + KAFFINITY ProcessAffinityMask = 0; + SectionOffset.QuadPart = (ULONGLONG)0; + + DPRINT("MmCreatePeb\n"); + + /* Map NLS Tables */ + DPRINT("Mapping NLS\n"); + Status = MmMapViewOfSection(NlsSectionObject, + Process, + &TableBase, + 0, + 0, + &SectionOffset, + &ViewSize, + ViewShare, + MEM_TOP_DOWN, + PAGE_READONLY); + if (!NT_SUCCESS(Status)) + { + DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status); + return(Status); + } + DPRINT("TableBase %p ViewSize %lx\n", TableBase, ViewSize); + + /* Attach to Process */ + KeAttachProcess(&Process->Pcb); + + /* Allocate the PEB */ + Peb = MiCreatePebOrTeb(Process, (PVOID)PEB_BASE); + + /* Initialize the PEB */ + DPRINT("Allocated: %x\n", Peb); + RtlZeroMemory(Peb, sizeof(PEB)); + + /* Set up data */ + DPRINT("Setting up PEB\n"); + Peb->ImageBaseAddress = Process->SectionBaseAddress; + Peb->InheritedAddressSpace = 0; + Peb->Mutant = NULL; + + /* NLS */ + Peb->AnsiCodePageData = (char*)TableBase + NlsAnsiTableOffset; + Peb->OemCodePageData = (char*)TableBase + NlsOemTableOffset; + Peb->UnicodeCaseTableData = (char*)TableBase + NlsUnicodeTableOffset; + + /* Default Version Data (could get changed below) */ + Peb->OSMajorVersion = NtMajorVersion; + Peb->OSMinorVersion = NtMinorVersion; + Peb->OSBuildNumber = 2195; + Peb->OSPlatformId = 2; /* VER_PLATFORM_WIN32_NT */ + Peb->OSCSDVersion = NtOSCSDVersion; + + /* Heap and Debug Data */ + Peb->NumberOfProcessors = KeNumberProcessors; + Peb->BeingDebugged = (BOOLEAN)(Process->DebugPort != NULL ? TRUE : FALSE); + Peb->NtGlobalFlag = NtGlobalFlag; + /*Peb->HeapSegmentReserve = MmHeapSegmentReserve; + Peb->HeapSegmentCommit = MmHeapSegmentCommit; + Peb->HeapDeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold; + Peb->HeapDeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;*/ + Peb->NumberOfHeaps = 0; + Peb->MaximumNumberOfHeaps = (PAGE_SIZE - sizeof(PEB)) / sizeof(PVOID); + Peb->ProcessHeaps = (PVOID*)Peb + 1; + + /* Image Data */ + if ((NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress))) + { + /* Get the Image Config Data too */ + ImageConfigData = RtlImageDirectoryEntryToData(Peb->ImageBaseAddress, + TRUE, + IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, + &ViewSize); + + /* Write subsystem data */ + Peb->ImageSubSystem = NtHeaders->OptionalHeader.Subsystem; + Peb->ImageSubSystemMajorVersion = NtHeaders->OptionalHeader.MajorSubsystemVersion; + Peb->ImageSubSystemMinorVersion = NtHeaders->OptionalHeader.MinorSubsystemVersion; + + /* Write Version Data */ + if (NtHeaders->OptionalHeader.Win32VersionValue) + { + Peb->OSMajorVersion = NtHeaders->OptionalHeader.Win32VersionValue & 0xFF; + Peb->OSMinorVersion = (NtHeaders->OptionalHeader.Win32VersionValue >> 8) & 0xFF; + Peb->OSBuildNumber = (NtHeaders->OptionalHeader.Win32VersionValue >> 16) & 0x3FFF; + + /* Lie about the version if requested */ + if (ImageConfigData && ImageConfigData->CSDVersion) + { + Peb->OSCSDVersion = ImageConfigData->CSDVersion; + } + + /* Set the Platform ID */ + Peb->OSPlatformId = (NtHeaders->OptionalHeader.Win32VersionValue >> 30) ^ 2; + } + + /* Check for affinity override */ + if (ImageConfigData && ImageConfigData->ProcessAffinityMask) + { + ProcessAffinityMask = ImageConfigData->ProcessAffinityMask; + } + + /* Check if the image is not safe for SMP */ + if (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY) + { + /* FIXME: Choose one randomly */ + Peb->ImageProcessAffinityMask = 1; + } + else + { + /* Use affinity from Image Header */ + Peb->ImageProcessAffinityMask = ProcessAffinityMask; + } + } + + /* Misc data */ + Peb->SessionId = Process->Session; + Process->Peb = Peb; + + /* Detach from the Process */ + KeDetachProcess(); + + DPRINT("MmCreatePeb: Peb created at %p\n", Peb); + return STATUS_SUCCESS; +} + +PTEB +STDCALL +MmCreateTeb(PEPROCESS Process, + PCLIENT_ID ClientId, + PINITIAL_TEB InitialTeb) +{ + PTEB Teb; + BOOLEAN Attached = FALSE; + + /* Attach to the process */ + DPRINT("MmCreateTeb\n"); + if (Process != PsGetCurrentProcess()) + { + /* Attach to Target */ + KeAttachProcess(&Process->Pcb); + Attached = TRUE; + } + + /* Allocate the TEB */ + Teb = MiCreatePebOrTeb(Process, (PVOID)TEB_BASE); + + /* Initialize the PEB */ + RtlZeroMemory(Teb, sizeof(TEB)); + + /* Set TIB Data */ + Teb->Tib.ExceptionList = (PVOID)0xFFFFFFFF; + Teb->Tib.Version = 1; + Teb->Tib.Self = (PNT_TIB)Teb; + + /* Set TEB Data */ + Teb->Cid = *ClientId; + Teb->RealClientId = *ClientId; + Teb->ProcessEnvironmentBlock = Process->Peb; + Teb->CurrentLocale = PsDefaultThreadLocaleId; + + /* Store stack information from InitialTeb */ + if(InitialTeb != NULL) + { + Teb->Tib.StackBase = InitialTeb->StackBase; + Teb->Tib.StackLimit = InitialTeb->StackLimit; + Teb->DeallocationStack = InitialTeb->AllocatedStackBase; + } + + /* Return TEB Address */ + DPRINT("Allocated: %x\n", Teb); + if (Attached) KeDetachProcess(); + return Teb; +} + +NTSTATUS +STDCALL +MmCreateProcessAddressSpace(IN PEPROCESS Process, + IN PSECTION_OBJECT Section OPTIONAL) +{ + NTSTATUS Status; + PMADDRESS_SPACE ProcessAddressSpace = &Process->AddressSpace; + PVOID BaseAddress; + PMEMORY_AREA MemoryArea; + PHYSICAL_ADDRESS BoundaryAddressMultiple; + ULONG ViewSize = 0; + PVOID ImageBase = 0; + BoundaryAddressMultiple.QuadPart = 0; + + /* Initialize the Addresss Space */ + MmInitializeAddressSpace(Process, ProcessAddressSpace); + + /* Acquire the Lock */ + MmLockAddressSpace(ProcessAddressSpace); + + /* Protect the highest 64KB of the process address space */ + BaseAddress = (PVOID)MmUserProbeAddress; + Status = MmCreateMemoryArea(Process, + ProcessAddressSpace, + MEMORY_AREA_NO_ACCESS, + &BaseAddress, + 0x10000, + PAGE_NOACCESS, + &MemoryArea, + FALSE, + FALSE, + BoundaryAddressMultiple); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to protect last 64KB\n"); + goto exit; + } + + /* Protect the 60KB above the shared user page */ + BaseAddress = (char*)USER_SHARED_DATA + PAGE_SIZE; + Status = MmCreateMemoryArea(Process, + ProcessAddressSpace, + MEMORY_AREA_NO_ACCESS, + &BaseAddress, + 0x10000 - PAGE_SIZE, + PAGE_NOACCESS, + &MemoryArea, + FALSE, + FALSE, + BoundaryAddressMultiple); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to protect the memory above the shared user page\n"); + goto exit; + } + + /* Create the shared data page */ + BaseAddress = (PVOID)USER_SHARED_DATA; + Status = MmCreateMemoryArea(Process, + ProcessAddressSpace, + MEMORY_AREA_SHARED_DATA, + &BaseAddress, + PAGE_SIZE, + PAGE_READONLY, + &MemoryArea, + FALSE, + FALSE, + BoundaryAddressMultiple); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to create Shared User Data\n"); + goto exit; + } + + /* Check if there's a Section Object */ + if (Section) + { + UNICODE_STRING FileName; + PWCHAR szSrc; + PCHAR szDest; + USHORT lnFName = 0; + + /* Unlock the Address Space */ + DPRINT("Unlocking\n"); + MmUnlockAddressSpace(ProcessAddressSpace); + + DPRINT("Mapping process image. Section: %p, Process: %p, ImageBase: %p\n", + Section, Process, &ImageBase); + Status = MmMapViewOfSection(Section, + Process, + (PVOID*)&ImageBase, + 0, + 0, + NULL, + &ViewSize, + 0, + MEM_COMMIT, + PAGE_READWRITE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to map process Image\n"); + ObDereferenceObject(Section); + goto exit; + } + ObDereferenceObject(Section); + + /* Save the pointer */ + Process->SectionBaseAddress = ImageBase; + + /* Determine the image file name and save it to EPROCESS */ + DPRINT("Getting Image name\n"); + FileName = Section->FileObject->FileName; + szSrc = (PWCHAR)(FileName.Buffer + (FileName.Length / sizeof(WCHAR)) - 1); + + while(szSrc >= FileName.Buffer) + { + if(*szSrc == L'\\') + { + szSrc++; + break; + } + else + { + szSrc--; + lnFName++; + } + } + + /* Copy the to the process and truncate it to 15 characters if necessary */ + DPRINT("Copying and truncating\n"); + szDest = Process->ImageFileName; + lnFName = min(lnFName, sizeof(Process->ImageFileName) - 1); + while(lnFName-- > 0) *(szDest++) = (UCHAR)*(szSrc++); + + /* Return status to caller */ + return Status; + } + +exit: + /* Unlock the Address Space */ + DPRINT("Unlocking\n"); + MmUnlockAddressSpace(ProcessAddressSpace); + + /* Return status to caller */ + return Status; +} diff --git a/reactos/ntoskrnl/ps/notify.c b/reactos/ntoskrnl/ps/notify.c index 46ac36ee31c..7ffd3fe5be6 100644 --- a/reactos/ntoskrnl/ps/notify.c +++ b/reactos/ntoskrnl/ps/notify.c @@ -26,8 +26,8 @@ PspProcessNotifyRoutine[MAX_PROCESS_NOTIFY_ROUTINE_COUNT]; static PLOAD_IMAGE_NOTIFY_ROUTINE PspLoadImageNotifyRoutine[MAX_LOAD_IMAGE_NOTIFY_ROUTINE_COUNT]; - -typedef VOID (STDCALL *PLEGO_NOTIFY_ROUTINE)(IN PKTHREAD Thread); + +typedef VOID (STDCALL *PLEGO_NOTIFY_ROUTINE)(IN PKTHREAD Thread); static PLEGO_NOTIFY_ROUTINE PspLegoNotifyRoutine; /* FUNCTIONS ***************************************************************/ diff --git a/reactos/services/umpnpmgr/umpnpmgr.c b/reactos/services/umpnpmgr/umpnpmgr.c index 8c2256889b0..ce1ad19b7a1 100644 --- a/reactos/services/umpnpmgr/umpnpmgr.c +++ b/reactos/services/umpnpmgr/umpnpmgr.c @@ -1,438 +1,438 @@ -/* - * ReactOS kernel - * Copyright (C) 2005 ReactOS Team - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: services/umpnpmgr/umpnpmgr.c - * PURPOSE: User-mode Plug and Play manager - * PROGRAMMER: Eric Kohl - */ - -/* INCLUDES *****************************************************************/ - -#include <windows.h> -#define NTOS_MODE_USER -#include <ndk/ntndk.h> -#include <ndk/sysguid.h> -#include <ddk/wdmguid.h> -#include <ddk/cfgmgr32.h> - -#include <rpc.h> -#include <rpcdce.h> - -#include "pnp_c.h" - -#define NDEBUG -#include <debug.h> - -/* GLOBALS ******************************************************************/ - -static VOID CALLBACK -ServiceMain(DWORD argc, LPTSTR *argv); - -static SERVICE_TABLE_ENTRY ServiceTable[2] = -{ - {TEXT("PlugPlay"), ServiceMain}, - {NULL, NULL} -}; - -static WCHAR szRootDeviceId[] = L"HTREE\\ROOT\\0"; - -/* FUNCTIONS *****************************************************************/ - -static DWORD WINAPI -RpcServerThread(LPVOID lpParameter) -{ - RPC_STATUS Status; - - DPRINT("RpcServerThread() called\n"); - - Status = RpcServerUseProtseqEpW(L"ncacn_np", - 20, - L"\\pipe\\umpnpmgr", - NULL); // Security descriptor - if (Status != RPC_S_OK) - { - DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status); - return 0; - } - - Status = RpcServerRegisterIf(pnp_v1_0_s_ifspec, - NULL, - NULL); - if (Status != RPC_S_OK) - { - DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status); - return 0; - } - - Status = RpcServerListen(1, - 20, - FALSE); - if (Status != RPC_S_OK) - { - DPRINT1("RpcServerListen() failed (Status %lx)\n", Status); - return 0; - } - - DPRINT("RpcServerThread() done\n"); - - return 0; -} - - -void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len) -{ - return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len); -} - - -void __RPC_USER midl_user_free(void __RPC_FAR * ptr) -{ - HeapFree(GetProcessHeap(), 0, ptr); -} - - -CONFIGRET -PNP_GetVersion(handle_t BindingHandle, - unsigned short *Version) -{ - *Version = 0x0400; - return CR_SUCCESS; -} - - -CONFIGRET -PNP_GetGlobalState(handle_t BindingHandle, - unsigned long *State, - unsigned long Flags) -{ - *State = CM_GLOBAL_STATE_CAN_DO_UI | CM_GLOBAL_STATE_SERVICES_AVAILABLE; - return CR_SUCCESS; -} - - -CONFIGRET -PNP_ValidateDeviceInstance(handle_t BindingHandle, - wchar_t *DeviceInstance, - unsigned long Flags) -{ - CONFIGRET ret = CR_SUCCESS; - HKEY hEnumKey = NULL; - HKEY hDeviceKey = NULL; - - DPRINT("PNP_ValidateDeviceInstance(%S %lx) called\n", - DeviceInstance, Flags); - - if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"System\\CurrentControlSet\\Enum", - 0, - KEY_ALL_ACCESS, - &hEnumKey)) - { - DPRINT("Could not open the Enum Key!\n"); - ret = CR_FAILURE; - goto Done; - } - - if (RegOpenKeyExW(hEnumKey, - DeviceInstance, - 0, - KEY_READ, - &hDeviceKey)) - { - DPRINT("Could not open the Device Key!\n"); - ret = CR_NO_SUCH_DEVNODE; - goto Done; - } - - /* FIXME: add more tests */ - -Done: - if (hDeviceKey != NULL) - RegCloseKey(hDeviceKey); - - if (hEnumKey != NULL) - RegCloseKey(hEnumKey); - - DPRINT("PNP_ValidateDeviceInstance() done (returns %lx)\n", ret); - - return ret; -} - - -CONFIGRET -PNP_GetRootDeviceInstance(handle_t BindingHandle, - wchar_t *DeviceInstance, - unsigned long Length) -{ - CONFIGRET ret = CR_SUCCESS; - - DPRINT("PNP_GetRootDeviceInstance() called\n"); - - if (Length < lstrlenW(szRootDeviceId) + 1) - { - ret = CR_BUFFER_SMALL; - goto Done; - } - - lstrcpyW(DeviceInstance, - szRootDeviceId); - -Done: - DPRINT("PNP_GetRootDeviceInstance() done (returns %lx)\n", ret); - - return ret; -} - - -CONFIGRET -PNP_GetRelatedDeviceInstance(handle_t BindingHandle, - unsigned long Relationship, - wchar_t *DeviceId, - wchar_t *RelatedDeviceId, - unsigned long Length, - unsigned long Flags) -{ - PLUGPLAY_CONTROL_RELATED_DEVICE_DATA PlugPlayData; - CONFIGRET ret = CR_SUCCESS; - NTSTATUS Status; - - DPRINT("PNP_GetRelatedDeviceInstance() called\n"); - DPRINT(" Relationship %ld\n", Relationship); - DPRINT(" DeviceId %S\n", DeviceId); - - RtlInitUnicodeString(&PlugPlayData.TargetDeviceInstance, - DeviceId); - - PlugPlayData.Relation = Relationship; - - PlugPlayData.RelatedDeviceInstance.Length = 0; - PlugPlayData.RelatedDeviceInstance.MaximumLength = Length; - PlugPlayData.RelatedDeviceInstance.Buffer = RelatedDeviceId; - - Status = NtPlugPlayControl(PlugPlayControlGetRelatedDevice, - (PVOID)&PlugPlayData, - sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA)); - if (!NT_SUCCESS(Status)) - { - /* FIXME: Map Status to ret */ - ret = CR_FAILURE; - } - - DPRINT("PNP_GetRelatedDeviceInstance() done (returns %lx)\n", ret); - if (ret == 0) - { - DPRINT("RelatedDevice: %wZ\n", &PlugPlayData.RelatedDeviceInstance); - } - - return ret; -} - - -CONFIGRET -PNP_GetDepth(handle_t BindingHandle, - wchar_t *DeviceInstance, - unsigned long *Depth, - DWORD Flags) -{ - PLUGPLAY_CONTROL_DEPTH_DATA PlugPlayData; - CONFIGRET ret = CR_SUCCESS; - NTSTATUS Status; - - DPRINT1("PNP_GetDepth() called\n"); - - RtlInitUnicodeString(&PlugPlayData.DeviceInstance, - DeviceInstance); - - Status = NtPlugPlayControl(PlugPlayControlGetDeviceDepth, - (PVOID)&PlugPlayData, - sizeof(PLUGPLAY_CONTROL_DEPTH_DATA)); - if (NT_SUCCESS(Status)) - { - *Depth = PlugPlayData.Depth; - } - else - { - ret = CR_FAILURE; /* FIXME */ - } - - DPRINT1("PNP_GetDepth() done (returns %lx)\n", ret); - - return ret; -} - - -CONFIGRET -PNP_GetDeviceStatus(handle_t BindingHandle, - wchar_t *DeviceInstance, - unsigned long *pStatus, - unsigned long *pProblem, - DWORD Flags) -{ - PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData; - CONFIGRET ret = CR_SUCCESS; - NTSTATUS Status; - - DPRINT1("PNP_GetDeviceStatus() called\n"); - - RtlInitUnicodeString(&PlugPlayData.DeviceInstance, - DeviceInstance); - PlugPlayData.Operation = 0; /* Get status */ - - Status = NtPlugPlayControl(PlugPlayControlDeviceStatus, - (PVOID)&PlugPlayData, - sizeof(PLUGPLAY_CONTROL_STATUS_DATA)); - if (NT_SUCCESS(Status)) - { - *pStatus = PlugPlayData.DeviceStatus; - *pProblem = PlugPlayData.DeviceProblem; - } - else - { - ret = CR_FAILURE; /* FIXME */ - } - - DPRINT1("PNP_GetDeviceStatus() done (returns %lx)\n", ret); - - return ret; -} - - -CONFIGRET -PNP_SetDeviceProblem(handle_t BindingHandle, - wchar_t *DeviceInstance, - unsigned long Problem, - DWORD Flags) -{ - CONFIGRET ret = CR_SUCCESS; - - DPRINT1("PNP_SetDeviceProblem() called\n"); - - /* FIXME */ - - DPRINT1("PNP_SetDeviceProblem() done (returns %lx)\n", ret); - - return ret; -} - - -static DWORD WINAPI -PnpEventThread(LPVOID lpParameter) -{ - PPLUGPLAY_EVENT_BLOCK PnpEvent; - ULONG PnpEventSize; - NTSTATUS Status; - RPC_STATUS RpcStatus; - - PnpEventSize = 0x1000; - PnpEvent = HeapAlloc(GetProcessHeap(), 0, PnpEventSize); - if (PnpEvent == NULL) - return ERROR_OUTOFMEMORY; - - for (;;) - { - DPRINT("Calling NtGetPlugPlayEvent()\n"); - - /* Wait for the next pnp event */ - Status = NtGetPlugPlayEvent(0, 0, PnpEvent, PnpEventSize); - - /* Resize the buffer for the PnP event if it's too small. */ - if (Status == STATUS_BUFFER_TOO_SMALL) - { - PnpEventSize += 0x400; - PnpEvent = HeapReAlloc(GetProcessHeap(), 0, PnpEvent, PnpEventSize); - if (PnpEvent == NULL) - return ERROR_OUTOFMEMORY; - continue; - } - - if (!NT_SUCCESS(Status)) - { - DPRINT("NtPlugPlayEvent() failed (Status %lx)\n", Status); - break; - } - - DPRINT("Received PnP Event\n"); - if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_ARRIVAL, &RpcStatus)) - { - DPRINT1("Device arrival event: %S\n", PnpEvent->TargetDevice.DeviceIds); - } - else - { - DPRINT1("Unknown event\n"); - } - - /* FIXME: Process the pnp event */ - - /* Dequeue the current pnp event and signal the next one */ - NtPlugPlayControl(PlugPlayControlUserResponse, NULL, 0); - } - - HeapFree(GetProcessHeap(), 0, PnpEvent); - - return ERROR_SUCCESS; -} - - -static VOID CALLBACK -ServiceMain(DWORD argc, LPTSTR *argv) -{ - HANDLE hThread; - DWORD dwThreadId; - - DPRINT("ServiceMain() called\n"); - - hThread = CreateThread(NULL, - 0, - PnpEventThread, - NULL, - 0, - &dwThreadId); - if (hThread != NULL) - CloseHandle(hThread); - - hThread = CreateThread(NULL, - 0, - RpcServerThread, - NULL, - 0, - &dwThreadId); - if (hThread != NULL) - CloseHandle(hThread); - - DPRINT("ServiceMain() done\n"); -} - - -int -main(int argc, char *argv[]) -{ - DPRINT("Umpnpmgr: main() started\n"); - - StartServiceCtrlDispatcher(ServiceTable); - - DPRINT("Umpnpmgr: main() done\n"); - - ExitThread(0); - - return 0; -} - -/* EOF */ +/* + * ReactOS kernel + * Copyright (C) 2005 ReactOS Team + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: services/umpnpmgr/umpnpmgr.c + * PURPOSE: User-mode Plug and Play manager + * PROGRAMMER: Eric Kohl + */ + +/* INCLUDES *****************************************************************/ + +#include <windows.h> +#define NTOS_MODE_USER +#include <ndk/ntndk.h> +#include <ndk/sysguid.h> +#include <ddk/wdmguid.h> +#include <ddk/cfgmgr32.h> + +#include <rpc.h> +#include <rpcdce.h> + +#include "pnp_c.h" + +#define NDEBUG +#include <debug.h> + +/* GLOBALS ******************************************************************/ + +static VOID CALLBACK +ServiceMain(DWORD argc, LPTSTR *argv); + +static SERVICE_TABLE_ENTRY ServiceTable[2] = +{ + {TEXT("PlugPlay"), ServiceMain}, + {NULL, NULL} +}; + +static WCHAR szRootDeviceId[] = L"HTREE\\ROOT\\0"; + +/* FUNCTIONS *****************************************************************/ + +static DWORD WINAPI +RpcServerThread(LPVOID lpParameter) +{ + RPC_STATUS Status; + + DPRINT("RpcServerThread() called\n"); + + Status = RpcServerUseProtseqEpW(L"ncacn_np", + 20, + L"\\pipe\\umpnpmgr", + NULL); // Security descriptor + if (Status != RPC_S_OK) + { + DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status); + return 0; + } + + Status = RpcServerRegisterIf(pnp_v1_0_s_ifspec, + NULL, + NULL); + if (Status != RPC_S_OK) + { + DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status); + return 0; + } + + Status = RpcServerListen(1, + 20, + FALSE); + if (Status != RPC_S_OK) + { + DPRINT1("RpcServerListen() failed (Status %lx)\n", Status); + return 0; + } + + DPRINT("RpcServerThread() done\n"); + + return 0; +} + + +void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len) +{ + return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len); +} + + +void __RPC_USER midl_user_free(void __RPC_FAR * ptr) +{ + HeapFree(GetProcessHeap(), 0, ptr); +} + + +CONFIGRET +PNP_GetVersion(handle_t BindingHandle, + unsigned short *Version) +{ + *Version = 0x0400; + return CR_SUCCESS; +} + + +CONFIGRET +PNP_GetGlobalState(handle_t BindingHandle, + unsigned long *State, + unsigned long Flags) +{ + *State = CM_GLOBAL_STATE_CAN_DO_UI | CM_GLOBAL_STATE_SERVICES_AVAILABLE; + return CR_SUCCESS; +} + + +CONFIGRET +PNP_ValidateDeviceInstance(handle_t BindingHandle, + wchar_t *DeviceInstance, + unsigned long Flags) +{ + CONFIGRET ret = CR_SUCCESS; + HKEY hEnumKey = NULL; + HKEY hDeviceKey = NULL; + + DPRINT("PNP_ValidateDeviceInstance(%S %lx) called\n", + DeviceInstance, Flags); + + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, + L"System\\CurrentControlSet\\Enum", + 0, + KEY_ALL_ACCESS, + &hEnumKey)) + { + DPRINT("Could not open the Enum Key!\n"); + ret = CR_FAILURE; + goto Done; + } + + if (RegOpenKeyExW(hEnumKey, + DeviceInstance, + 0, + KEY_READ, + &hDeviceKey)) + { + DPRINT("Could not open the Device Key!\n"); + ret = CR_NO_SUCH_DEVNODE; + goto Done; + } + + /* FIXME: add more tests */ + +Done: + if (hDeviceKey != NULL) + RegCloseKey(hDeviceKey); + + if (hEnumKey != NULL) + RegCloseKey(hEnumKey); + + DPRINT("PNP_ValidateDeviceInstance() done (returns %lx)\n", ret); + + return ret; +} + + +CONFIGRET +PNP_GetRootDeviceInstance(handle_t BindingHandle, + wchar_t *DeviceInstance, + unsigned long Length) +{ + CONFIGRET ret = CR_SUCCESS; + + DPRINT("PNP_GetRootDeviceInstance() called\n"); + + if (Length < lstrlenW(szRootDeviceId) + 1) + { + ret = CR_BUFFER_SMALL; + goto Done; + } + + lstrcpyW(DeviceInstance, + szRootDeviceId); + +Done: + DPRINT("PNP_GetRootDeviceInstance() done (returns %lx)\n", ret); + + return ret; +} + + +CONFIGRET +PNP_GetRelatedDeviceInstance(handle_t BindingHandle, + unsigned long Relationship, + wchar_t *DeviceId, + wchar_t *RelatedDeviceId, + unsigned long Length, + unsigned long Flags) +{ + PLUGPLAY_CONTROL_RELATED_DEVICE_DATA PlugPlayData; + CONFIGRET ret = CR_SUCCESS; + NTSTATUS Status; + + DPRINT("PNP_GetRelatedDeviceInstance() called\n"); + DPRINT(" Relationship %ld\n", Relationship); + DPRINT(" DeviceId %S\n", DeviceId); + + RtlInitUnicodeString(&PlugPlayData.TargetDeviceInstance, + DeviceId); + + PlugPlayData.Relation = Relationship; + + PlugPlayData.RelatedDeviceInstance.Length = 0; + PlugPlayData.RelatedDeviceInstance.MaximumLength = Length; + PlugPlayData.RelatedDeviceInstance.Buffer = RelatedDeviceId; + + Status = NtPlugPlayControl(PlugPlayControlGetRelatedDevice, + (PVOID)&PlugPlayData, + sizeof(PLUGPLAY_CONTROL_RELATED_DEVICE_DATA)); + if (!NT_SUCCESS(Status)) + { + /* FIXME: Map Status to ret */ + ret = CR_FAILURE; + } + + DPRINT("PNP_GetRelatedDeviceInstance() done (returns %lx)\n", ret); + if (ret == 0) + { + DPRINT("RelatedDevice: %wZ\n", &PlugPlayData.RelatedDeviceInstance); + } + + return ret; +} + + +CONFIGRET +PNP_GetDepth(handle_t BindingHandle, + wchar_t *DeviceInstance, + unsigned long *Depth, + DWORD Flags) +{ + PLUGPLAY_CONTROL_DEPTH_DATA PlugPlayData; + CONFIGRET ret = CR_SUCCESS; + NTSTATUS Status; + + DPRINT1("PNP_GetDepth() called\n"); + + RtlInitUnicodeString(&PlugPlayData.DeviceInstance, + DeviceInstance); + + Status = NtPlugPlayControl(PlugPlayControlGetDeviceDepth, + (PVOID)&PlugPlayData, + sizeof(PLUGPLAY_CONTROL_DEPTH_DATA)); + if (NT_SUCCESS(Status)) + { + *Depth = PlugPlayData.Depth; + } + else + { + ret = CR_FAILURE; /* FIXME */ + } + + DPRINT1("PNP_GetDepth() done (returns %lx)\n", ret); + + return ret; +} + + +CONFIGRET +PNP_GetDeviceStatus(handle_t BindingHandle, + wchar_t *DeviceInstance, + unsigned long *pStatus, + unsigned long *pProblem, + DWORD Flags) +{ + PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData; + CONFIGRET ret = CR_SUCCESS; + NTSTATUS Status; + + DPRINT1("PNP_GetDeviceStatus() called\n"); + + RtlInitUnicodeString(&PlugPlayData.DeviceInstance, + DeviceInstance); + PlugPlayData.Operation = 0; /* Get status */ + + Status = NtPlugPlayControl(PlugPlayControlDeviceStatus, + (PVOID)&PlugPlayData, + sizeof(PLUGPLAY_CONTROL_STATUS_DATA)); + if (NT_SUCCESS(Status)) + { + *pStatus = PlugPlayData.DeviceStatus; + *pProblem = PlugPlayData.DeviceProblem; + } + else + { + ret = CR_FAILURE; /* FIXME */ + } + + DPRINT1("PNP_GetDeviceStatus() done (returns %lx)\n", ret); + + return ret; +} + + +CONFIGRET +PNP_SetDeviceProblem(handle_t BindingHandle, + wchar_t *DeviceInstance, + unsigned long Problem, + DWORD Flags) +{ + CONFIGRET ret = CR_SUCCESS; + + DPRINT1("PNP_SetDeviceProblem() called\n"); + + /* FIXME */ + + DPRINT1("PNP_SetDeviceProblem() done (returns %lx)\n", ret); + + return ret; +} + + +static DWORD WINAPI +PnpEventThread(LPVOID lpParameter) +{ + PPLUGPLAY_EVENT_BLOCK PnpEvent; + ULONG PnpEventSize; + NTSTATUS Status; + RPC_STATUS RpcStatus; + + PnpEventSize = 0x1000; + PnpEvent = HeapAlloc(GetProcessHeap(), 0, PnpEventSize); + if (PnpEvent == NULL) + return ERROR_OUTOFMEMORY; + + for (;;) + { + DPRINT("Calling NtGetPlugPlayEvent()\n"); + + /* Wait for the next pnp event */ + Status = NtGetPlugPlayEvent(0, 0, PnpEvent, PnpEventSize); + + /* Resize the buffer for the PnP event if it's too small. */ + if (Status == STATUS_BUFFER_TOO_SMALL) + { + PnpEventSize += 0x400; + PnpEvent = HeapReAlloc(GetProcessHeap(), 0, PnpEvent, PnpEventSize); + if (PnpEvent == NULL) + return ERROR_OUTOFMEMORY; + continue; + } + + if (!NT_SUCCESS(Status)) + { + DPRINT("NtPlugPlayEvent() failed (Status %lx)\n", Status); + break; + } + + DPRINT("Received PnP Event\n"); + if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_ARRIVAL, &RpcStatus)) + { + DPRINT1("Device arrival event: %S\n", PnpEvent->TargetDevice.DeviceIds); + } + else + { + DPRINT1("Unknown event\n"); + } + + /* FIXME: Process the pnp event */ + + /* Dequeue the current pnp event and signal the next one */ + NtPlugPlayControl(PlugPlayControlUserResponse, NULL, 0); + } + + HeapFree(GetProcessHeap(), 0, PnpEvent); + + return ERROR_SUCCESS; +} + + +static VOID CALLBACK +ServiceMain(DWORD argc, LPTSTR *argv) +{ + HANDLE hThread; + DWORD dwThreadId; + + DPRINT("ServiceMain() called\n"); + + hThread = CreateThread(NULL, + 0, + PnpEventThread, + NULL, + 0, + &dwThreadId); + if (hThread != NULL) + CloseHandle(hThread); + + hThread = CreateThread(NULL, + 0, + RpcServerThread, + NULL, + 0, + &dwThreadId); + if (hThread != NULL) + CloseHandle(hThread); + + DPRINT("ServiceMain() done\n"); +} + + +int +main(int argc, char *argv[]) +{ + DPRINT("Umpnpmgr: main() started\n"); + + StartServiceCtrlDispatcher(ServiceTable); + + DPRINT("Umpnpmgr: main() done\n"); + + ExitThread(0); + + return 0; +} + +/* EOF */ diff --git a/reactos/subsys/ntvdm/resource.h b/reactos/subsys/ntvdm/resource.h index 0600fe4030d..b2d010f81f9 100644 --- a/reactos/subsys/ntvdm/resource.h +++ b/reactos/subsys/ntvdm/resource.h @@ -1,6 +1,6 @@ -#define RC_STRING_MAX_SIZE 2048 -#define STRING_WelcomeMsg 100 -#define STRING_PromptMsg 101 - - -/* EOF */ +#define RC_STRING_MAX_SIZE 2048 +#define STRING_WelcomeMsg 100 +#define STRING_PromptMsg 101 + + +/* EOF */ diff --git a/reactos/subsys/system/expand/resource.h b/reactos/subsys/system/expand/resource.h index e4a149921a9..4cab40382e9 100644 --- a/reactos/subsys/system/expand/resource.h +++ b/reactos/subsys/system/expand/resource.h @@ -1,8 +1,8 @@ - - -#define RC_STRING_MAX_SIZE 4096 -#define IDS_Copy 100 -#define IDS_FAILS 101 - - -/* EOF */ + + +#define RC_STRING_MAX_SIZE 4096 +#define IDS_Copy 100 +#define IDS_FAILS 101 + + +/* EOF */ diff --git a/reactos/subsys/system/ibrowser/ibrowser.cpp b/reactos/subsys/system/ibrowser/ibrowser.cpp index 2b27d979ec6..fbec628ea8d 100644 --- a/reactos/subsys/system/ibrowser/ibrowser.cpp +++ b/reactos/subsys/system/ibrowser/ibrowser.cpp @@ -1,550 +1,550 @@ -/* - * Copyright 2005 Martin Fuchs - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - - // - // ROS Internet Web Browser - // - // ibrowser.cpp - // - // Martin Fuchs, 24.01.2005 - // - - -#include "precomp.h" - -#include "ibrowser_intres.h" - -#include <locale.h> // for setlocale() - -#ifndef __WINE__ -#include <io.h> // for dup2() -#include <fcntl.h> // for _O_RDONLY -#endif - - - // globals - -HINSTANCE g_hInstance; -IconCache g_icon_cache; -ATOM g_hframeClass; - - -/*@@ -void ExplorerGlobals::read_persistent() -{ - // read configuration file - _cfg_dir.printf(TEXT("%s\\ReactOS"), (LPCTSTR)SpecialFolderFSPath(CSIDL_APPDATA,0)); - _cfg_path.printf(TEXT("%s\\ros-ibrowser-cfg.xml"), _cfg_dir.c_str()); - - if (!_cfg.read(_cfg_path)) { - if (_cfg._last_error != XML_ERROR_NO_ELEMENTS) - MessageBox(g_Globals._hwndDesktop, String(_cfg._last_error_msg.c_str()), - TEXT("ROS Explorer - reading user settings"), MB_OK); - - _cfg.read(TEXT("ibrowser-cfg-template.xml")); - } - - // read bookmarks - _favorites_path.printf(TEXT("%s\\ros-ibrowser-bookmarks.xml"), _cfg_dir.c_str()); - - if (!_favorites.read(_favorites_path)) { - _favorites.import_IE_favorites(0); - _favorites.write(_favorites_path); - } -} - -void ExplorerGlobals::write_persistent() -{ - // write configuration file - RecursiveCreateDirectory(_cfg_dir); - - _cfg.write(_cfg_path); - _favorites.write(_favorites_path); -} - - -XMLPos ExplorerGlobals::get_cfg() -{ - XMLPos cfg_pos(&_cfg); - - cfg_pos.smart_create("ibrowser-cfg"); - - return cfg_pos; -} - -XMLPos ExplorerGlobals::get_cfg(const char* path) -{ - XMLPos cfg_pos(&_cfg); - - cfg_pos.smart_create("ibrowser-cfg"); - cfg_pos.create_relative(path); - - return cfg_pos; -} -*/ - - -Icon::Icon() - : _id(ICID_UNKNOWN), - _itype(IT_STATIC), - _hicon(0) -{ -} - -Icon::Icon(ICON_ID id, UINT nid) - : _id(id), - _itype(IT_STATIC), - _hicon(SmallIcon(nid)) -{ -} - -Icon::Icon(ICON_TYPE itype, int id, HICON hIcon) - : _id((ICON_ID)id), - _itype(itype), - _hicon(hIcon) -{ -} - -Icon::Icon(ICON_TYPE itype, int id, int sys_idx) - : _id((ICON_ID)id), - _itype(itype), - _sys_idx(sys_idx) -{ -} - -void Icon::draw(HDC hdc, int x, int y, int cx, int cy, COLORREF bk_color, HBRUSH bk_brush) const -{ - if (_itype == IT_SYSCACHE) - ImageList_DrawEx(g_icon_cache.get_sys_imagelist(), _sys_idx, hdc, x, y, cx, cy, bk_color, CLR_DEFAULT, ILD_NORMAL); - else - DrawIconEx(hdc, x, y, _hicon, cx, cy, 0, bk_brush, DI_NORMAL); -} - -HBITMAP Icon::create_bitmap(COLORREF bk_color, HBRUSH hbrBkgnd, HDC hdc_wnd) const -{ - if (_itype == IT_SYSCACHE) { - HIMAGELIST himl = g_icon_cache.get_sys_imagelist(); - - int cx, cy; - ImageList_GetIconSize(himl, &cx, &cy); - - HBITMAP hbmp = CreateCompatibleBitmap(hdc_wnd, cx, cy); - HDC hdc = CreateCompatibleDC(hdc_wnd); - HBITMAP hbmp_old = SelectBitmap(hdc, hbmp); - ImageList_DrawEx(himl, _sys_idx, hdc, 0, 0, cx, cy, bk_color, CLR_DEFAULT, ILD_NORMAL); - SelectBitmap(hdc, hbmp_old); - DeleteDC(hdc); - - return hbmp; - } else - return create_bitmap_from_icon(_hicon, hbrBkgnd, hdc_wnd); -} - - -int Icon::add_to_imagelist(HIMAGELIST himl, HDC hdc_wnd, COLORREF bk_color, HBRUSH bk_brush) const -{ - int ret; - - if (_itype == IT_SYSCACHE) { - HIMAGELIST himl = g_icon_cache.get_sys_imagelist(); - - int cx, cy; - ImageList_GetIconSize(himl, &cx, &cy); - - HBITMAP hbmp = CreateCompatibleBitmap(hdc_wnd, cx, cy); - HDC hdc = CreateCompatibleDC(hdc_wnd); - HBITMAP hbmp_old = SelectBitmap(hdc, hbmp); - ImageList_DrawEx(himl, _sys_idx, hdc, 0, 0, cx, cy, bk_color, CLR_DEFAULT, ILD_NORMAL); - SelectBitmap(hdc, hbmp_old); - DeleteDC(hdc); - - ret = ImageList_Add(himl, hbmp, 0); - - DeleteObject(hbmp); - } else - ret = ImageList_AddAlphaIcon(himl, _hicon, bk_brush, hdc_wnd); - - return ret; -} - -HBITMAP create_bitmap_from_icon(HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd) -{ - int cx = GetSystemMetrics(SM_CXSMICON); - int cy = GetSystemMetrics(SM_CYSMICON); - HBITMAP hbmp = CreateCompatibleBitmap(hdc_wnd, cx, cy); - - MemCanvas canvas; - BitmapSelection sel(canvas, hbmp); - - RECT rect = {0, 0, cx, cy}; - FillRect(canvas, &rect, hbrush_bkgnd); - - DrawIconEx(canvas, 0, 0, hIcon, cx, cy, 0, hbrush_bkgnd, DI_NORMAL); - - return hbmp; -} - -int ImageList_AddAlphaIcon(HIMAGELIST himl, HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd) -{ - HBITMAP hbmp = create_bitmap_from_icon(hIcon, hbrush_bkgnd, hdc_wnd); - - int ret = ImageList_Add(himl, hbmp, 0); - - DeleteObject(hbmp); - - return ret; -} - - -int IconCache::s_next_id = ICID_DYNAMIC; - - -void IconCache::init() -{ - _icons[ICID_NONE] = Icon(IT_STATIC, ICID_NONE, (HICON)0); - - _icons[ICID_IBROWSER] = Icon(ICID_IBROWSER, IDI_IBROWSER); - _icons[ICID_BOOKMARK] = Icon(ICID_BOOKMARK, IDI_DOT_TRANS); -} - - -const Icon& IconCache::extract(const String& path) -{ - PathMap::iterator found = _pathMap.find(path); - - if (found != _pathMap.end()) - return _icons[found->second]; - - SHFILEINFO sfi; - -#if 1 // use system image list - HIMAGELIST himlSys = (HIMAGELIST) SHGetFileInfo(path, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX|SHGFI_SMALLICON); - - if (himlSys) { - _himlSys = himlSys; - - const Icon& icon = add(sfi.iIcon/*, IT_SYSCACHE*/); -#else - if (SHGetFileInfo(path, 0, &sfi, sizeof(sfi), SHGFI_ICON|SHGFI_SMALLICON)) { - const Icon& icon = add(sfi.hIcon, IT_CACHED); -#endif - - ///@todo limit cache size - _pathMap[path] = icon; - - return icon; - } else - return _icons[ICID_NONE]; -} - -const Icon& IconCache::extract(LPCTSTR path, int idx) -{ - CachePair key(path, idx); - -#ifndef __WINE__ ///@todo _tcslwr() for Wine - _tcslwr((LPTSTR)key.first.c_str()); -#endif - - PathIdxMap::iterator found = _pathIdxMap.find(key); - - if (found != _pathIdxMap.end()) - return _icons[found->second]; - - HICON hIcon; - - if ((int)ExtractIconEx(path, idx, NULL, &hIcon, 1) > 0) { - const Icon& icon = add(hIcon, IT_CACHED); - - _pathIdxMap[key] = icon; - - return icon; - } else { - - ///@todo retreive "http://.../favicon.ico" format icons - - return _icons[ICID_NONE]; - } -} - - -const Icon& IconCache::add(HICON hIcon, ICON_TYPE type) -{ - int id = ++s_next_id; - - return _icons[id] = Icon(type, id, hIcon); -} - -const Icon& IconCache::add(int sys_idx/*, ICON_TYPE type=IT_SYSCACHE*/) -{ - int id = ++s_next_id; - - return _icons[id] = SysCacheIcon(id, sys_idx); -} - -const Icon& IconCache::get_icon(int id) -{ - return _icons[id]; -} - -void IconCache::free_icon(int icon_id) -{ - IconMap::iterator found = _icons.find(icon_id); - - if (found != _icons.end()) { - Icon& icon = found->second; - - if (icon.destroy()) - _icons.erase(found); - } -} - - -ResString::ResString(UINT nid) -{ - TCHAR buffer[BUFFER_LEN]; - - int len = LoadString(g_hInstance, nid, buffer, sizeof(buffer)/sizeof(TCHAR)); - - super::assign(buffer, len); -} - - -ResIcon::ResIcon(UINT nid) -{ - _hicon = LoadIcon(g_hInstance, MAKEINTRESOURCE(nid)); -} - -SmallIcon::SmallIcon(UINT nid) -{ - _hicon = (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(nid), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED); -} - -ResIconEx::ResIconEx(UINT nid, int w, int h) -{ - _hicon = (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(nid), IMAGE_ICON, w, h, LR_SHARED); -} - - -void SetWindowIcon(HWND hwnd, UINT nid) -{ - HICON hIcon = ResIcon(nid); - (void)Window_SetIcon(hwnd, ICON_BIG, hIcon); - - HICON hIconSmall = SmallIcon(nid); - (void)Window_SetIcon(hwnd, ICON_SMALL, hIconSmall); -} - - -ResBitmap::ResBitmap(UINT nid) -{ - _hBmp = LoadBitmap(g_hInstance, MAKEINTRESOURCE(nid)); -} - - -void ibrowser_show_frame(int cmdshow, LPTSTR lpCmdLine) -{ - MainFrameBase::Create(lpCmdLine, cmdshow); -} - - -PopupMenu::PopupMenu(UINT nid) -{ - HMENU hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(nid)); - _hmenu = GetSubMenu(hMenu, 0); -} - - - /// "About" Dialog -struct ExplorerAboutDlg : public - CtlColorParent< - OwnerDrawParent<Dialog> - > -{ - typedef CtlColorParent< - OwnerDrawParent<Dialog> - > super; - - ExplorerAboutDlg(HWND hwnd) - : super(hwnd) - { - SetWindowIcon(hwnd, IDI_REACTOS); - - new FlatButton(hwnd, IDOK); - - _hfont = CreateFont(20, 0, 0, 0, FW_BOLD, TRUE, 0, 0, 0, 0, 0, 0, 0, TEXT("Sans Serif")); - new ColorStatic(hwnd, IDC_ROS_IBROWSER, RGB(32,32,128), 0, _hfont); - - new HyperlinkCtrl(hwnd, IDC_WWW); - - FmtString ver_txt(ResString(IDS_IBROWSER_VERSION_STR), (LPCTSTR)ResString(IDS_VERSION_STR)); - SetWindowText(GetDlgItem(hwnd, IDC_VERSION_TXT), ver_txt); - - /*@@ - HWND hwnd_winver = GetDlgItem(hwnd, IDC_WIN_VERSION); - SetWindowText(hwnd_winver, get_windows_version_str()); - SetWindowFont(hwnd_winver, GetStockFont(DEFAULT_GUI_FONT), FALSE); - */ - - CenterWindow(hwnd); - } - - ~ExplorerAboutDlg() - { - DeleteObject(_hfont); - } - -protected: - HFONT _hfont; -}; - -void ibrowser_about(HWND hwndParent) -{ - Dialog::DoModal(IDD_ABOUT_IBROWSER, WINDOW_CREATOR(ExplorerAboutDlg), hwndParent); -} -void ibrowser_open(HWND hwndParent) -{ - HMODULE hShell32; - RUNFILEDLG RunFileDlg; - OSVERSIONINFO versionInfo; - WCHAR wTitle[40]; - WCHAR wText[256]; - char szTitle[40] = "Open"; - char szText[256] = "Type the Internet Address of a document or folder and IBrowser will open it for you."; - - hShell32 = LoadLibrary(_T("SHELL32.DLL")); - RunFileDlg = (RUNFILEDLG)(FARPROC)GetProcAddress(hShell32, (char*)((long)0x3D)); - - /* Show "Run..." dialog */ - if (RunFileDlg) - { - versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&versionInfo); - - if (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szTitle, -1, wTitle, 40); - MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szText, -1, wText, 256); - RunFileDlg(hwndParent, 0, NULL, (LPCSTR)wTitle, (LPCSTR)wText, RFF_CALCDIRECTORY); - } - else - RunFileDlg(hwndParent, 0, NULL, szTitle, szText, RFF_CALCDIRECTORY); - } - - FreeLibrary(hShell32); -} - -static void InitInstance(HINSTANCE hInstance) -{ - CONTEXT("InitInstance"); - - // register frame window class - g_hframeClass = IconWindowClass(CLASSNAME_FRAME,IDI_IBROWSER); - - // register child window class - WindowClass(CLASSNAME_CHILDWND, CS_CLASSDC|CS_VREDRAW).Register(); -} - - -int ibrowser_main(HINSTANCE hInstance, LPTSTR lpCmdLine, int cmdshow) -{ - CONTEXT("ibrowser_main"); - - // initialize Common Controls library - CommonControlInit usingCmnCtrl; - - try { - InitInstance(hInstance); - } catch(COMException& e) { - HandleException(e, GetDesktopWindow()); - return -1; - } - - if (cmdshow != SW_HIDE) { -/* // don't maximize if being called from the ROS desktop - if (cmdshow == SW_SHOWNORMAL) - ///@todo read window placement from registry - cmdshow = SW_MAXIMIZE; -*/ - - ibrowser_show_frame(cmdshow, lpCmdLine); - } - - return Window::MessageLoop(); -} - - - // MinGW does not provide a Unicode startup routine, so we have to implement an own. -#if defined(__MINGW32__) && defined(UNICODE) - -#define _tWinMain wWinMain -int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int); - -int main(int argc, char* argv[]) -{ - CONTEXT("main"); - - STARTUPINFO startupinfo; - int nShowCmd = SW_SHOWNORMAL; - - GetStartupInfo(&startupinfo); - - if (startupinfo.dwFlags & STARTF_USESHOWWINDOW) - nShowCmd = startupinfo.wShowWindow; - - LPWSTR cmdline = GetCommandLineW(); - - while(*cmdline && !_istspace(*cmdline)) - ++cmdline; - - while(_istspace(*cmdline)) - ++cmdline; - - return wWinMain(GetModuleHandle(NULL), 0, cmdline, nShowCmd); -} - -#endif // __MINGW && UNICODE - - -int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd) -{ - CONTEXT("WinMain()"); - - g_hInstance = hInstance; - - // initialize COM and OLE before creating the desktop window - OleInit usingCOM; - - // init common controls library - CommonControlInit usingCmnCtrl; - -//@@ g_Globals.read_persistent(); - - /**TODO fix command line handling */ - if (*lpCmdLine=='"' && lpCmdLine[_tcslen(lpCmdLine)-1]=='"') { - ++lpCmdLine; - lpCmdLine[_tcslen(lpCmdLine)-1] = '\0'; - } - - int ret = ibrowser_main(hInstance, lpCmdLine, nShowCmd); - - // write configuration file -//@@ g_Globals.write_persistent(); - - return ret; -} +/* + * Copyright 2005 Martin Fuchs + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + + // + // ROS Internet Web Browser + // + // ibrowser.cpp + // + // Martin Fuchs, 24.01.2005 + // + + +#include "precomp.h" + +#include "ibrowser_intres.h" + +#include <locale.h> // for setlocale() + +#ifndef __WINE__ +#include <io.h> // for dup2() +#include <fcntl.h> // for _O_RDONLY +#endif + + + // globals + +HINSTANCE g_hInstance; +IconCache g_icon_cache; +ATOM g_hframeClass; + + +/*@@ +void ExplorerGlobals::read_persistent() +{ + // read configuration file + _cfg_dir.printf(TEXT("%s\\ReactOS"), (LPCTSTR)SpecialFolderFSPath(CSIDL_APPDATA,0)); + _cfg_path.printf(TEXT("%s\\ros-ibrowser-cfg.xml"), _cfg_dir.c_str()); + + if (!_cfg.read(_cfg_path)) { + if (_cfg._last_error != XML_ERROR_NO_ELEMENTS) + MessageBox(g_Globals._hwndDesktop, String(_cfg._last_error_msg.c_str()), + TEXT("ROS Explorer - reading user settings"), MB_OK); + + _cfg.read(TEXT("ibrowser-cfg-template.xml")); + } + + // read bookmarks + _favorites_path.printf(TEXT("%s\\ros-ibrowser-bookmarks.xml"), _cfg_dir.c_str()); + + if (!_favorites.read(_favorites_path)) { + _favorites.import_IE_favorites(0); + _favorites.write(_favorites_path); + } +} + +void ExplorerGlobals::write_persistent() +{ + // write configuration file + RecursiveCreateDirectory(_cfg_dir); + + _cfg.write(_cfg_path); + _favorites.write(_favorites_path); +} + + +XMLPos ExplorerGlobals::get_cfg() +{ + XMLPos cfg_pos(&_cfg); + + cfg_pos.smart_create("ibrowser-cfg"); + + return cfg_pos; +} + +XMLPos ExplorerGlobals::get_cfg(const char* path) +{ + XMLPos cfg_pos(&_cfg); + + cfg_pos.smart_create("ibrowser-cfg"); + cfg_pos.create_relative(path); + + return cfg_pos; +} +*/ + + +Icon::Icon() + : _id(ICID_UNKNOWN), + _itype(IT_STATIC), + _hicon(0) +{ +} + +Icon::Icon(ICON_ID id, UINT nid) + : _id(id), + _itype(IT_STATIC), + _hicon(SmallIcon(nid)) +{ +} + +Icon::Icon(ICON_TYPE itype, int id, HICON hIcon) + : _id((ICON_ID)id), + _itype(itype), + _hicon(hIcon) +{ +} + +Icon::Icon(ICON_TYPE itype, int id, int sys_idx) + : _id((ICON_ID)id), + _itype(itype), + _sys_idx(sys_idx) +{ +} + +void Icon::draw(HDC hdc, int x, int y, int cx, int cy, COLORREF bk_color, HBRUSH bk_brush) const +{ + if (_itype == IT_SYSCACHE) + ImageList_DrawEx(g_icon_cache.get_sys_imagelist(), _sys_idx, hdc, x, y, cx, cy, bk_color, CLR_DEFAULT, ILD_NORMAL); + else + DrawIconEx(hdc, x, y, _hicon, cx, cy, 0, bk_brush, DI_NORMAL); +} + +HBITMAP Icon::create_bitmap(COLORREF bk_color, HBRUSH hbrBkgnd, HDC hdc_wnd) const +{ + if (_itype == IT_SYSCACHE) { + HIMAGELIST himl = g_icon_cache.get_sys_imagelist(); + + int cx, cy; + ImageList_GetIconSize(himl, &cx, &cy); + + HBITMAP hbmp = CreateCompatibleBitmap(hdc_wnd, cx, cy); + HDC hdc = CreateCompatibleDC(hdc_wnd); + HBITMAP hbmp_old = SelectBitmap(hdc, hbmp); + ImageList_DrawEx(himl, _sys_idx, hdc, 0, 0, cx, cy, bk_color, CLR_DEFAULT, ILD_NORMAL); + SelectBitmap(hdc, hbmp_old); + DeleteDC(hdc); + + return hbmp; + } else + return create_bitmap_from_icon(_hicon, hbrBkgnd, hdc_wnd); +} + + +int Icon::add_to_imagelist(HIMAGELIST himl, HDC hdc_wnd, COLORREF bk_color, HBRUSH bk_brush) const +{ + int ret; + + if (_itype == IT_SYSCACHE) { + HIMAGELIST himl = g_icon_cache.get_sys_imagelist(); + + int cx, cy; + ImageList_GetIconSize(himl, &cx, &cy); + + HBITMAP hbmp = CreateCompatibleBitmap(hdc_wnd, cx, cy); + HDC hdc = CreateCompatibleDC(hdc_wnd); + HBITMAP hbmp_old = SelectBitmap(hdc, hbmp); + ImageList_DrawEx(himl, _sys_idx, hdc, 0, 0, cx, cy, bk_color, CLR_DEFAULT, ILD_NORMAL); + SelectBitmap(hdc, hbmp_old); + DeleteDC(hdc); + + ret = ImageList_Add(himl, hbmp, 0); + + DeleteObject(hbmp); + } else + ret = ImageList_AddAlphaIcon(himl, _hicon, bk_brush, hdc_wnd); + + return ret; +} + +HBITMAP create_bitmap_from_icon(HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd) +{ + int cx = GetSystemMetrics(SM_CXSMICON); + int cy = GetSystemMetrics(SM_CYSMICON); + HBITMAP hbmp = CreateCompatibleBitmap(hdc_wnd, cx, cy); + + MemCanvas canvas; + BitmapSelection sel(canvas, hbmp); + + RECT rect = {0, 0, cx, cy}; + FillRect(canvas, &rect, hbrush_bkgnd); + + DrawIconEx(canvas, 0, 0, hIcon, cx, cy, 0, hbrush_bkgnd, DI_NORMAL); + + return hbmp; +} + +int ImageList_AddAlphaIcon(HIMAGELIST himl, HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd) +{ + HBITMAP hbmp = create_bitmap_from_icon(hIcon, hbrush_bkgnd, hdc_wnd); + + int ret = ImageList_Add(himl, hbmp, 0); + + DeleteObject(hbmp); + + return ret; +} + + +int IconCache::s_next_id = ICID_DYNAMIC; + + +void IconCache::init() +{ + _icons[ICID_NONE] = Icon(IT_STATIC, ICID_NONE, (HICON)0); + + _icons[ICID_IBROWSER] = Icon(ICID_IBROWSER, IDI_IBROWSER); + _icons[ICID_BOOKMARK] = Icon(ICID_BOOKMARK, IDI_DOT_TRANS); +} + + +const Icon& IconCache::extract(const String& path) +{ + PathMap::iterator found = _pathMap.find(path); + + if (found != _pathMap.end()) + return _icons[found->second]; + + SHFILEINFO sfi; + +#if 1 // use system image list + HIMAGELIST himlSys = (HIMAGELIST) SHGetFileInfo(path, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX|SHGFI_SMALLICON); + + if (himlSys) { + _himlSys = himlSys; + + const Icon& icon = add(sfi.iIcon/*, IT_SYSCACHE*/); +#else + if (SHGetFileInfo(path, 0, &sfi, sizeof(sfi), SHGFI_ICON|SHGFI_SMALLICON)) { + const Icon& icon = add(sfi.hIcon, IT_CACHED); +#endif + + ///@todo limit cache size + _pathMap[path] = icon; + + return icon; + } else + return _icons[ICID_NONE]; +} + +const Icon& IconCache::extract(LPCTSTR path, int idx) +{ + CachePair key(path, idx); + +#ifndef __WINE__ ///@todo _tcslwr() for Wine + _tcslwr((LPTSTR)key.first.c_str()); +#endif + + PathIdxMap::iterator found = _pathIdxMap.find(key); + + if (found != _pathIdxMap.end()) + return _icons[found->second]; + + HICON hIcon; + + if ((int)ExtractIconEx(path, idx, NULL, &hIcon, 1) > 0) { + const Icon& icon = add(hIcon, IT_CACHED); + + _pathIdxMap[key] = icon; + + return icon; + } else { + + ///@todo retreive "http://.../favicon.ico" format icons + + return _icons[ICID_NONE]; + } +} + + +const Icon& IconCache::add(HICON hIcon, ICON_TYPE type) +{ + int id = ++s_next_id; + + return _icons[id] = Icon(type, id, hIcon); +} + +const Icon& IconCache::add(int sys_idx/*, ICON_TYPE type=IT_SYSCACHE*/) +{ + int id = ++s_next_id; + + return _icons[id] = SysCacheIcon(id, sys_idx); +} + +const Icon& IconCache::get_icon(int id) +{ + return _icons[id]; +} + +void IconCache::free_icon(int icon_id) +{ + IconMap::iterator found = _icons.find(icon_id); + + if (found != _icons.end()) { + Icon& icon = found->second; + + if (icon.destroy()) + _icons.erase(found); + } +} + + +ResString::ResString(UINT nid) +{ + TCHAR buffer[BUFFER_LEN]; + + int len = LoadString(g_hInstance, nid, buffer, sizeof(buffer)/sizeof(TCHAR)); + + super::assign(buffer, len); +} + + +ResIcon::ResIcon(UINT nid) +{ + _hicon = LoadIcon(g_hInstance, MAKEINTRESOURCE(nid)); +} + +SmallIcon::SmallIcon(UINT nid) +{ + _hicon = (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(nid), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED); +} + +ResIconEx::ResIconEx(UINT nid, int w, int h) +{ + _hicon = (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(nid), IMAGE_ICON, w, h, LR_SHARED); +} + + +void SetWindowIcon(HWND hwnd, UINT nid) +{ + HICON hIcon = ResIcon(nid); + (void)Window_SetIcon(hwnd, ICON_BIG, hIcon); + + HICON hIconSmall = SmallIcon(nid); + (void)Window_SetIcon(hwnd, ICON_SMALL, hIconSmall); +} + + +ResBitmap::ResBitmap(UINT nid) +{ + _hBmp = LoadBitmap(g_hInstance, MAKEINTRESOURCE(nid)); +} + + +void ibrowser_show_frame(int cmdshow, LPTSTR lpCmdLine) +{ + MainFrameBase::Create(lpCmdLine, cmdshow); +} + + +PopupMenu::PopupMenu(UINT nid) +{ + HMENU hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(nid)); + _hmenu = GetSubMenu(hMenu, 0); +} + + + /// "About" Dialog +struct ExplorerAboutDlg : public + CtlColorParent< + OwnerDrawParent<Dialog> + > +{ + typedef CtlColorParent< + OwnerDrawParent<Dialog> + > super; + + ExplorerAboutDlg(HWND hwnd) + : super(hwnd) + { + SetWindowIcon(hwnd, IDI_REACTOS); + + new FlatButton(hwnd, IDOK); + + _hfont = CreateFont(20, 0, 0, 0, FW_BOLD, TRUE, 0, 0, 0, 0, 0, 0, 0, TEXT("Sans Serif")); + new ColorStatic(hwnd, IDC_ROS_IBROWSER, RGB(32,32,128), 0, _hfont); + + new HyperlinkCtrl(hwnd, IDC_WWW); + + FmtString ver_txt(ResString(IDS_IBROWSER_VERSION_STR), (LPCTSTR)ResString(IDS_VERSION_STR)); + SetWindowText(GetDlgItem(hwnd, IDC_VERSION_TXT), ver_txt); + + /*@@ + HWND hwnd_winver = GetDlgItem(hwnd, IDC_WIN_VERSION); + SetWindowText(hwnd_winver, get_windows_version_str()); + SetWindowFont(hwnd_winver, GetStockFont(DEFAULT_GUI_FONT), FALSE); + */ + + CenterWindow(hwnd); + } + + ~ExplorerAboutDlg() + { + DeleteObject(_hfont); + } + +protected: + HFONT _hfont; +}; + +void ibrowser_about(HWND hwndParent) +{ + Dialog::DoModal(IDD_ABOUT_IBROWSER, WINDOW_CREATOR(ExplorerAboutDlg), hwndParent); +} +void ibrowser_open(HWND hwndParent) +{ + HMODULE hShell32; + RUNFILEDLG RunFileDlg; + OSVERSIONINFO versionInfo; + WCHAR wTitle[40]; + WCHAR wText[256]; + char szTitle[40] = "Open"; + char szText[256] = "Type the Internet Address of a document or folder and IBrowser will open it for you."; + + hShell32 = LoadLibrary(_T("SHELL32.DLL")); + RunFileDlg = (RUNFILEDLG)(FARPROC)GetProcAddress(hShell32, (char*)((long)0x3D)); + + /* Show "Run..." dialog */ + if (RunFileDlg) + { + versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&versionInfo); + + if (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) + { + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szTitle, -1, wTitle, 40); + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szText, -1, wText, 256); + RunFileDlg(hwndParent, 0, NULL, (LPCSTR)wTitle, (LPCSTR)wText, RFF_CALCDIRECTORY); + } + else + RunFileDlg(hwndParent, 0, NULL, szTitle, szText, RFF_CALCDIRECTORY); + } + + FreeLibrary(hShell32); +} + +static void InitInstance(HINSTANCE hInstance) +{ + CONTEXT("InitInstance"); + + // register frame window class + g_hframeClass = IconWindowClass(CLASSNAME_FRAME,IDI_IBROWSER); + + // register child window class + WindowClass(CLASSNAME_CHILDWND, CS_CLASSDC|CS_VREDRAW).Register(); +} + + +int ibrowser_main(HINSTANCE hInstance, LPTSTR lpCmdLine, int cmdshow) +{ + CONTEXT("ibrowser_main"); + + // initialize Common Controls library + CommonControlInit usingCmnCtrl; + + try { + InitInstance(hInstance); + } catch(COMException& e) { + HandleException(e, GetDesktopWindow()); + return -1; + } + + if (cmdshow != SW_HIDE) { +/* // don't maximize if being called from the ROS desktop + if (cmdshow == SW_SHOWNORMAL) + ///@todo read window placement from registry + cmdshow = SW_MAXIMIZE; +*/ + + ibrowser_show_frame(cmdshow, lpCmdLine); + } + + return Window::MessageLoop(); +} + + + // MinGW does not provide a Unicode startup routine, so we have to implement an own. +#if defined(__MINGW32__) && defined(UNICODE) + +#define _tWinMain wWinMain +int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int); + +int main(int argc, char* argv[]) +{ + CONTEXT("main"); + + STARTUPINFO startupinfo; + int nShowCmd = SW_SHOWNORMAL; + + GetStartupInfo(&startupinfo); + + if (startupinfo.dwFlags & STARTF_USESHOWWINDOW) + nShowCmd = startupinfo.wShowWindow; + + LPWSTR cmdline = GetCommandLineW(); + + while(*cmdline && !_istspace(*cmdline)) + ++cmdline; + + while(_istspace(*cmdline)) + ++cmdline; + + return wWinMain(GetModuleHandle(NULL), 0, cmdline, nShowCmd); +} + +#endif // __MINGW && UNICODE + + +int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd) +{ + CONTEXT("WinMain()"); + + g_hInstance = hInstance; + + // initialize COM and OLE before creating the desktop window + OleInit usingCOM; + + // init common controls library + CommonControlInit usingCmnCtrl; + +//@@ g_Globals.read_persistent(); + + /**TODO fix command line handling */ + if (*lpCmdLine=='"' && lpCmdLine[_tcslen(lpCmdLine)-1]=='"') { + ++lpCmdLine; + lpCmdLine[_tcslen(lpCmdLine)-1] = '\0'; + } + + int ret = ibrowser_main(hInstance, lpCmdLine, nShowCmd); + + // write configuration file +//@@ g_Globals.write_persistent(); + + return ret; +} diff --git a/reactos/subsys/system/ibrowser/ibrowser.h b/reactos/subsys/system/ibrowser/ibrowser.h index 48aff170270..f1e3b260552 100644 --- a/reactos/subsys/system/ibrowser/ibrowser.h +++ b/reactos/subsys/system/ibrowser/ibrowser.h @@ -1,231 +1,231 @@ -/* - * Copyright 2005 Martin Fuchs - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - - // - // ROS Internet Web Browser - // - // ibrowser.h - // - // Martin Fuchs, 25.01.2005 - // - - -#include "utility/window.h" - - -#define IDW_STATUSBAR 0x100 -#define IDW_TOOLBAR 0x101 -#define IDW_EXTRABAR 0x102 -#define IDW_ADDRESSBAR 0x104 -#define IDW_SIDEBAR 0x106 -#define IDW_FIRST_CHILD 0xC000 /*0x200*/ - - -#define PM_GET_FILEWND_PTR (WM_APP+0x05) -#define PM_GET_SHELLBROWSER_PTR (WM_APP+0x06) - -#define PM_GET_CONTROLWINDOW (WM_APP+0x16) - -#define PM_RESIZE_CHILDREN (WM_APP+0x17) -#define PM_GET_WIDTH (WM_APP+0x18) - -#define PM_REFRESH (WM_APP+0x1B) -#define PM_REFRESH_CONFIG (WM_APP+0x1C) - - -#define CLASSNAME_FRAME TEXT("IBrowserFrameWClass") - -#define CLASSNAME_CHILDWND TEXT("IBrowserChildWClass") - - -#include "mainframe.h" - - - /// convenient loading of string resources -struct ResString : public String -{ - ResString(UINT nid); -}; - - /// convenient loading of standard (32x32) icon resources -struct ResIcon -{ - ResIcon(UINT nid); - - operator HICON() const {return _hicon;} - -protected: - HICON _hicon; -}; - - /// convenient loading of small (16x16) icon resources -struct SmallIcon -{ - SmallIcon(UINT nid); - - operator HICON() const {return _hicon;} - -protected: - HICON _hicon; -}; - - /// convenient loading of icon resources with specified sizes -struct ResIconEx -{ - ResIconEx(UINT nid, int w, int h); - - operator HICON() const {return _hicon;} - -protected: - HICON _hicon; -}; - - /// set big and small icons out of the resources for a window -extern void SetWindowIcon(HWND hwnd, UINT nid); - - /// convenient loading of bitmap resources -struct ResBitmap -{ - ResBitmap(UINT nid); - ~ResBitmap() {DeleteObject(_hBmp);} - - operator HBITMAP() const {return _hBmp;} - -protected: - HBITMAP _hBmp; -}; - - -enum ICON_TYPE { - IT_STATIC, - IT_CACHED, - IT_DYNAMIC, - IT_SYSCACHE -}; - -enum ICON_ID { - ICID_UNKNOWN, - ICID_NONE, - - ICID_IBROWSER, - ICID_BOOKMARK, - - ICID_DYNAMIC -}; - -struct Icon { - Icon(); - Icon(ICON_ID id, UINT nid); - Icon(ICON_TYPE itype, int id, HICON hIcon); - Icon(ICON_TYPE itype, int id, int sys_idx); - - operator ICON_ID() const {return _id;} - - void draw(HDC hdc, int x, int y, int cx, int cy, COLORREF bk_color, HBRUSH bk_brush) const; - HBITMAP create_bitmap(COLORREF bk_color, HBRUSH hbrBkgnd, HDC hdc_wnd) const; - int add_to_imagelist(HIMAGELIST himl, HDC hdc_wnd, COLORREF bk_color=GetSysColor(COLOR_WINDOW), HBRUSH bk_brush=GetSysColorBrush(COLOR_WINDOW)) const; - - int get_sysiml_idx() const {return _itype==IT_SYSCACHE? _sys_idx: -1;} - - bool destroy() {if (_itype == IT_DYNAMIC) {DestroyIcon(_hicon); return true;} else return false;} - -protected: - ICON_ID _id; - ICON_TYPE _itype; - HICON _hicon; - int _sys_idx; -}; - -struct SysCacheIcon : public Icon { - SysCacheIcon(int id, int sys_idx) - : Icon(IT_SYSCACHE, id, sys_idx) {} -}; - -struct IconCache { - IconCache() : _himlSys(0) {} - - void init(); - - const Icon& extract(const String& path); - const Icon& extract(LPCTSTR path, int idx); - const Icon& extract(IExtractIcon* pExtract, LPCTSTR path, int idx); - - const Icon& add(HICON hIcon, ICON_TYPE type=IT_DYNAMIC); - const Icon& add(int sys_idx/*, ICON_TYPE type=IT_SYSCACHE*/); - - const Icon& get_icon(int icon_id); - HIMAGELIST get_sys_imagelist() const {return _himlSys;} - - void free_icon(int icon_id); - -protected: - static int s_next_id; - - typedef map<int, Icon> IconMap; - IconMap _icons; - - typedef map<String, ICON_ID> PathMap; - PathMap _pathMap; - - typedef pair<String, int> CachePair; - typedef map<CachePair, ICON_ID> PathIdxMap; - PathIdxMap _pathIdxMap; - - HIMAGELIST _himlSys; -}; - - - /// create a bitmap from an icon -extern HBITMAP create_bitmap_from_icon(HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd); - - /// add icon with alpha channel to imagelist using the specified background color -extern int ImageList_AddAlphaIcon(HIMAGELIST himl, HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd); - - -#include "utility/xmlstorage.h" - -using namespace XMLStorage; - -#include "favorites.h" - - - // globals -extern HINSTANCE g_hInstance; -extern IconCache g_icon_cache; -extern ATOM g_hframeClass; - - - // display explorer "About" dialog -extern void ibrowser_about(HWND hwndParent); - - // display explorer "open" dialog -extern void ibrowser_open(HWND hwndParent); - - // declare shell32's "Run..." dialog export function -typedef void (WINAPI* RUNFILEDLG)(HWND hwndOwner, HICON hIcon, LPCSTR lpstrDirectory, LPCSTR lpstrTitle, LPCSTR lpstrDescription, UINT uFlags); - - // - // Flags for RunFileDlg - // - -#define RFF_NOBROWSE 0x01 // Removes the browse button. -#define RFF_NODEFAULT 0x02 // No default item selected. -#define RFF_CALCDIRECTORY 0x04 // Calculates the working directory from the file name. -#define RFF_NOLABEL 0x08 // Removes the edit box label. -#define RFF_NOSEPARATEMEM 0x20 // Removes the Separate Memory Space check box (Windows NT only). +/* + * Copyright 2005 Martin Fuchs + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + + // + // ROS Internet Web Browser + // + // ibrowser.h + // + // Martin Fuchs, 25.01.2005 + // + + +#include "utility/window.h" + + +#define IDW_STATUSBAR 0x100 +#define IDW_TOOLBAR 0x101 +#define IDW_EXTRABAR 0x102 +#define IDW_ADDRESSBAR 0x104 +#define IDW_SIDEBAR 0x106 +#define IDW_FIRST_CHILD 0xC000 /*0x200*/ + + +#define PM_GET_FILEWND_PTR (WM_APP+0x05) +#define PM_GET_SHELLBROWSER_PTR (WM_APP+0x06) + +#define PM_GET_CONTROLWINDOW (WM_APP+0x16) + +#define PM_RESIZE_CHILDREN (WM_APP+0x17) +#define PM_GET_WIDTH (WM_APP+0x18) + +#define PM_REFRESH (WM_APP+0x1B) +#define PM_REFRESH_CONFIG (WM_APP+0x1C) + + +#define CLASSNAME_FRAME TEXT("IBrowserFrameWClass") + +#define CLASSNAME_CHILDWND TEXT("IBrowserChildWClass") + + +#include "mainframe.h" + + + /// convenient loading of string resources +struct ResString : public String +{ + ResString(UINT nid); +}; + + /// convenient loading of standard (32x32) icon resources +struct ResIcon +{ + ResIcon(UINT nid); + + operator HICON() const {return _hicon;} + +protected: + HICON _hicon; +}; + + /// convenient loading of small (16x16) icon resources +struct SmallIcon +{ + SmallIcon(UINT nid); + + operator HICON() const {return _hicon;} + +protected: + HICON _hicon; +}; + + /// convenient loading of icon resources with specified sizes +struct ResIconEx +{ + ResIconEx(UINT nid, int w, int h); + + operator HICON() const {return _hicon;} + +protected: + HICON _hicon; +}; + + /// set big and small icons out of the resources for a window +extern void SetWindowIcon(HWND hwnd, UINT nid); + + /// convenient loading of bitmap resources +struct ResBitmap +{ + ResBitmap(UINT nid); + ~ResBitmap() {DeleteObject(_hBmp);} + + operator HBITMAP() const {return _hBmp;} + +protected: + HBITMAP _hBmp; +}; + + +enum ICON_TYPE { + IT_STATIC, + IT_CACHED, + IT_DYNAMIC, + IT_SYSCACHE +}; + +enum ICON_ID { + ICID_UNKNOWN, + ICID_NONE, + + ICID_IBROWSER, + ICID_BOOKMARK, + + ICID_DYNAMIC +}; + +struct Icon { + Icon(); + Icon(ICON_ID id, UINT nid); + Icon(ICON_TYPE itype, int id, HICON hIcon); + Icon(ICON_TYPE itype, int id, int sys_idx); + + operator ICON_ID() const {return _id;} + + void draw(HDC hdc, int x, int y, int cx, int cy, COLORREF bk_color, HBRUSH bk_brush) const; + HBITMAP create_bitmap(COLORREF bk_color, HBRUSH hbrBkgnd, HDC hdc_wnd) const; + int add_to_imagelist(HIMAGELIST himl, HDC hdc_wnd, COLORREF bk_color=GetSysColor(COLOR_WINDOW), HBRUSH bk_brush=GetSysColorBrush(COLOR_WINDOW)) const; + + int get_sysiml_idx() const {return _itype==IT_SYSCACHE? _sys_idx: -1;} + + bool destroy() {if (_itype == IT_DYNAMIC) {DestroyIcon(_hicon); return true;} else return false;} + +protected: + ICON_ID _id; + ICON_TYPE _itype; + HICON _hicon; + int _sys_idx; +}; + +struct SysCacheIcon : public Icon { + SysCacheIcon(int id, int sys_idx) + : Icon(IT_SYSCACHE, id, sys_idx) {} +}; + +struct IconCache { + IconCache() : _himlSys(0) {} + + void init(); + + const Icon& extract(const String& path); + const Icon& extract(LPCTSTR path, int idx); + const Icon& extract(IExtractIcon* pExtract, LPCTSTR path, int idx); + + const Icon& add(HICON hIcon, ICON_TYPE type=IT_DYNAMIC); + const Icon& add(int sys_idx/*, ICON_TYPE type=IT_SYSCACHE*/); + + const Icon& get_icon(int icon_id); + HIMAGELIST get_sys_imagelist() const {return _himlSys;} + + void free_icon(int icon_id); + +protected: + static int s_next_id; + + typedef map<int, Icon> IconMap; + IconMap _icons; + + typedef map<String, ICON_ID> PathMap; + PathMap _pathMap; + + typedef pair<String, int> CachePair; + typedef map<CachePair, ICON_ID> PathIdxMap; + PathIdxMap _pathIdxMap; + + HIMAGELIST _himlSys; +}; + + + /// create a bitmap from an icon +extern HBITMAP create_bitmap_from_icon(HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd); + + /// add icon with alpha channel to imagelist using the specified background color +extern int ImageList_AddAlphaIcon(HIMAGELIST himl, HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd); + + +#include "utility/xmlstorage.h" + +using namespace XMLStorage; + +#include "favorites.h" + + + // globals +extern HINSTANCE g_hInstance; +extern IconCache g_icon_cache; +extern ATOM g_hframeClass; + + + // display explorer "About" dialog +extern void ibrowser_about(HWND hwndParent); + + // display explorer "open" dialog +extern void ibrowser_open(HWND hwndParent); + + // declare shell32's "Run..." dialog export function +typedef void (WINAPI* RUNFILEDLG)(HWND hwndOwner, HICON hIcon, LPCSTR lpstrDirectory, LPCSTR lpstrTitle, LPCSTR lpstrDescription, UINT uFlags); + + // + // Flags for RunFileDlg + // + +#define RFF_NOBROWSE 0x01 // Removes the browse button. +#define RFF_NODEFAULT 0x02 // No default item selected. +#define RFF_CALCDIRECTORY 0x04 // Calculates the working directory from the file name. +#define RFF_NOLABEL 0x08 // Removes the edit box label. +#define RFF_NOSEPARATEMEM 0x20 // Removes the Separate Memory Space check box (Windows NT only). diff --git a/reactos/subsys/system/ibrowser/ibrowser_intres.h b/reactos/subsys/system/ibrowser/ibrowser_intres.h index 5561e456f3d..c80ddc7f548 100644 --- a/reactos/subsys/system/ibrowser/ibrowser_intres.h +++ b/reactos/subsys/system/ibrowser/ibrowser_intres.h @@ -1,52 +1,52 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by ibrowser_intres.rc -// -#define IDS_TITLE 1 -#define IDS_EMPTY 13 -#define IDS_ABOUT_IBROWSER 27 -#define IDI_REACTOS 100 -#define IDB_TOOLBAR 103 -#define IDA_IBROWSER 104 -#define IDM_SDIFRAME 113 -#define IDD_ABOUT_IBROWSER 135 -#define IDI_FAVORITES 140 -#define IDI_DOT 163 -#define IDI_DOT_TRANS 164 -#define IDI_DOT_RED 165 -#define IDI_IBROWSER 169 -#define ID_VIEW_STATUSBAR 503 -#define ID_VIEW_TOOL_BAR 508 -#define ID_VIEW_SIDE_BAR 510 -#define IDC_ROS_IBROWSER 1000 -#define IDC_WWW 1012 -#define IDC_VERSION_TXT 1029 -#define IDC_WIN_VERSION 1030 -#define ID_REFRESH 1704 -#define IDS_VERSION_STR 5000 -#define IDS_IBROWSER_VERSION_STR 5001 -#define ID_IBROWSER_FAQ 10002 -#define ID_VIEW_FULLSCREEN 0x8004 -#define ID_ABOUT_WINDOWS 40002 -#define ID_ABOUT_IBROWSER 40003 -#define ID_GO_BACK 40005 -#define ID_GO_FORWARD 40006 -#define ID_GO_HOME 40007 -#define ID_GO_SEARCH 40008 -#define ID_GO_UP 40009 -#define ID_STOP 40010 -#define ID_FILE_OPEN 0xE140 -#define ID_FILE_EXIT 0xE141 -#define ID_HELP 0xE146 -#define IDC_STATIC -1 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 170 -#define _APS_NEXT_COMMAND_VALUE 40024 -#define _APS_NEXT_CONTROL_VALUE 1033 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by ibrowser_intres.rc +// +#define IDS_TITLE 1 +#define IDS_EMPTY 13 +#define IDS_ABOUT_IBROWSER 27 +#define IDI_REACTOS 100 +#define IDB_TOOLBAR 103 +#define IDA_IBROWSER 104 +#define IDM_SDIFRAME 113 +#define IDD_ABOUT_IBROWSER 135 +#define IDI_FAVORITES 140 +#define IDI_DOT 163 +#define IDI_DOT_TRANS 164 +#define IDI_DOT_RED 165 +#define IDI_IBROWSER 169 +#define ID_VIEW_STATUSBAR 503 +#define ID_VIEW_TOOL_BAR 508 +#define ID_VIEW_SIDE_BAR 510 +#define IDC_ROS_IBROWSER 1000 +#define IDC_WWW 1012 +#define IDC_VERSION_TXT 1029 +#define IDC_WIN_VERSION 1030 +#define ID_REFRESH 1704 +#define IDS_VERSION_STR 5000 +#define IDS_IBROWSER_VERSION_STR 5001 +#define ID_IBROWSER_FAQ 10002 +#define ID_VIEW_FULLSCREEN 0x8004 +#define ID_ABOUT_WINDOWS 40002 +#define ID_ABOUT_IBROWSER 40003 +#define ID_GO_BACK 40005 +#define ID_GO_FORWARD 40006 +#define ID_GO_HOME 40007 +#define ID_GO_SEARCH 40008 +#define ID_GO_UP 40009 +#define ID_STOP 40010 +#define ID_FILE_OPEN 0xE140 +#define ID_FILE_EXIT 0xE141 +#define ID_HELP 0xE146 +#define IDC_STATIC -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 170 +#define _APS_NEXT_COMMAND_VALUE 40024 +#define _APS_NEXT_CONTROL_VALUE 1033 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/reactos/subsys/system/ibrowser/utility/comutil.h b/reactos/subsys/system/ibrowser/utility/comutil.h index d73b7b42327..fc2655e00c2 100644 --- a/reactos/subsys/system/ibrowser/utility/comutil.h +++ b/reactos/subsys/system/ibrowser/utility/comutil.h @@ -1,321 +1,321 @@ -/* - * Copyright 2005 Martin Fuchs - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - - // - // ROS Internet Web Browser - // - // comutil.h - // - // C++ wrapper classes for COM interfaces - // - // Martin Fuchs, 25.01.2005 - // - - - // windows shell headers -#include <shellapi.h> -#include <shlobj.h> - -/*@@ -#if _MSC_VER>=1300 // VS.Net -#include <comdefsp.h> -using namespace _com_util; -#endif -*/ - -#ifndef _INC_COMUTIL // is comutil.h of MS headers not available? -#ifndef _NO_COMUTIL -#define _NO_COMUTIL -#endif -#endif - - - // Exception Handling - -#ifndef _NO_COMUTIL - -#define COMExceptionBase _com_error - -#else - - /// COM ExceptionBase class as replacement for _com_error -struct COMExceptionBase -{ - COMExceptionBase(HRESULT hr) - : _hr(hr) - { - } - - HRESULT Error() const - { - return _hr; - } - - LPCTSTR ErrorMessage() const - { - if (_msg.empty()) { - LPTSTR pBuf; - - if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, - 0, _hr, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (LPTSTR)&pBuf, 0, NULL)) { - _msg = pBuf; - LocalFree(pBuf); - } else { - TCHAR buffer[128]; - _stprintf(buffer, TEXT("unknown Exception: 0x%08lX"), _hr); - _msg = buffer; - } - } - - return _msg; - } - -protected: - HRESULT _hr; - mutable String _msg; -}; - -#endif - - - /// Exception with context information - -struct COMException : public COMExceptionBase -{ - typedef COMExceptionBase super; - - COMException(HRESULT hr) - : super(hr), - _context(CURRENT_CONTEXT), - _file(NULL), _line(0) - { - LOG(toString()); - LOG(CURRENT_CONTEXT.getStackTrace()); - } - - COMException(HRESULT hr, const char* file, int line) - : super(hr), - _context(CURRENT_CONTEXT), - _file(file), _line(line) - { - LOG(toString()); - LOG(CURRENT_CONTEXT.getStackTrace()); - } - - COMException(HRESULT hr, const String& obj) - : super(hr), - _context(CURRENT_CONTEXT), - _file(NULL), _line(0) - { - LOG(toString()); - LOG(CURRENT_CONTEXT.getStackTrace()); - } - - COMException(HRESULT hr, const String& obj, const char* file, int line) - : super(hr), - _context(CURRENT_CONTEXT), - _file(file), _line(line) - { - LOG(toString()); - LOG(CURRENT_CONTEXT.getStackTrace()); - } - - String toString() const; - - Context _context; - - const char* _file; - int _line; -}; - -#define THROW_EXCEPTION(hr) throw COMException(hr, __FILE__, __LINE__) -#define CHECKERROR(hr) ((void)(FAILED(hr)? THROW_EXCEPTION(hr): 0)) - - -#ifdef _NO_COMUTIL - -inline void CheckError(HRESULT hr) -{ - if (FAILED(hr)) - throw COMException(hr); -} - -#endif - - - /// COM Initialisation - -struct ComInit -{ - ComInit() - { - CHECKERROR(CoInitialize(0)); - } - -#if (_WIN32_WINNT>=0x0400) || defined(_WIN32_DCOM) - ComInit(DWORD flag) - { - CHECKERROR(CoInitializeEx(0, flag)); - } -#endif - - ~ComInit() - { - CoUninitialize(); - } -}; - - - /// OLE initialisation for drag drop support - -struct OleInit -{ - OleInit() - { - CHECKERROR(OleInitialize(0)); - } - - ~OleInit() - { - OleUninitialize(); - } -}; - - - /// Exception Handler for COM exceptions - -extern void HandleException(COMException& e, HWND hwnd); - - - /// wrapper class for COM interface pointers - -template<typename T> struct SIfacePtr -{ - SIfacePtr() - : _p(0) - { - } - - SIfacePtr(T* p) - : _p(p) - { - if (p) - p->AddRef(); - } - - SIfacePtr(IUnknown* unknown, REFIID riid) - { - CHECKERROR(unknown->QueryInterface(riid, (LPVOID*)&_p)); - } - - ~SIfacePtr() - { - Free(); - } - - T* operator->() - { - return _p; - } - - const T* operator->() const - { - return _p; - } - -/* not GCC compatible - operator const T*() const - { - return _p; - } */ - - operator T*() - { - return _p; - } - - T** operator&() - { - return &_p; - } - - bool empty() const //NOTE: GCC seems not to work correctly when defining operator bool() AND operator T*() at one time - { - return !_p; - } - - SIfacePtr& operator=(T* p) - { - Free(); - - if (p) { - p->AddRef(); - _p = p; - } - - return *this; - } - - void operator=(SIfacePtr const& o) - { - T* h = _p; - - if (o._p) - o._p->AddRef(); - - _p = o._p; - - if (h) - h->Release(); - } - - HRESULT CreateInstance(REFIID clsid, REFIID riid) - { - return CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, riid, (LPVOID*)&_p); - } - - template<typename I> HRESULT QueryInterface(REFIID riid, I* p) - { - return _p->QueryInterface(riid, (LPVOID*)p); - } - - T* get() - { - return _p; - } - - void Free() - { - T* h = _p; - _p = NULL; - - if (h) - h->Release(); - } - -protected: - SIfacePtr(const SIfacePtr& o) - : _p(o._p) - { - if (_p) - _p->AddRef(); - } - - T* _p; -}; +/* + * Copyright 2005 Martin Fuchs + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + + // + // ROS Internet Web Browser + // + // comutil.h + // + // C++ wrapper classes for COM interfaces + // + // Martin Fuchs, 25.01.2005 + // + + + // windows shell headers +#include <shellapi.h> +#include <shlobj.h> + +/*@@ +#if _MSC_VER>=1300 // VS.Net +#include <comdefsp.h> +using namespace _com_util; +#endif +*/ + +#ifndef _INC_COMUTIL // is comutil.h of MS headers not available? +#ifndef _NO_COMUTIL +#define _NO_COMUTIL +#endif +#endif + + + // Exception Handling + +#ifndef _NO_COMUTIL + +#define COMExceptionBase _com_error + +#else + + /// COM ExceptionBase class as replacement for _com_error +struct COMExceptionBase +{ + COMExceptionBase(HRESULT hr) + : _hr(hr) + { + } + + HRESULT Error() const + { + return _hr; + } + + LPCTSTR ErrorMessage() const + { + if (_msg.empty()) { + LPTSTR pBuf; + + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, + 0, _hr, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (LPTSTR)&pBuf, 0, NULL)) { + _msg = pBuf; + LocalFree(pBuf); + } else { + TCHAR buffer[128]; + _stprintf(buffer, TEXT("unknown Exception: 0x%08lX"), _hr); + _msg = buffer; + } + } + + return _msg; + } + +protected: + HRESULT _hr; + mutable String _msg; +}; + +#endif + + + /// Exception with context information + +struct COMException : public COMExceptionBase +{ + typedef COMExceptionBase super; + + COMException(HRESULT hr) + : super(hr), + _context(CURRENT_CONTEXT), + _file(NULL), _line(0) + { + LOG(toString()); + LOG(CURRENT_CONTEXT.getStackTrace()); + } + + COMException(HRESULT hr, const char* file, int line) + : super(hr), + _context(CURRENT_CONTEXT), + _file(file), _line(line) + { + LOG(toString()); + LOG(CURRENT_CONTEXT.getStackTrace()); + } + + COMException(HRESULT hr, const String& obj) + : super(hr), + _context(CURRENT_CONTEXT), + _file(NULL), _line(0) + { + LOG(toString()); + LOG(CURRENT_CONTEXT.getStackTrace()); + } + + COMException(HRESULT hr, const String& obj, const char* file, int line) + : super(hr), + _context(CURRENT_CONTEXT), + _file(file), _line(line) + { + LOG(toString()); + LOG(CURRENT_CONTEXT.getStackTrace()); + } + + String toString() const; + + Context _context; + + const char* _file; + int _line; +}; + +#define THROW_EXCEPTION(hr) throw COMException(hr, __FILE__, __LINE__) +#define CHECKERROR(hr) ((void)(FAILED(hr)? THROW_EXCEPTION(hr): 0)) + + +#ifdef _NO_COMUTIL + +inline void CheckError(HRESULT hr) +{ + if (FAILED(hr)) + throw COMException(hr); +} + +#endif + + + /// COM Initialisation + +struct ComInit +{ + ComInit() + { + CHECKERROR(CoInitialize(0)); + } + +#if (_WIN32_WINNT>=0x0400) || defined(_WIN32_DCOM) + ComInit(DWORD flag) + { + CHECKERROR(CoInitializeEx(0, flag)); + } +#endif + + ~ComInit() + { + CoUninitialize(); + } +}; + + + /// OLE initialisation for drag drop support + +struct OleInit +{ + OleInit() + { + CHECKERROR(OleInitialize(0)); + } + + ~OleInit() + { + OleUninitialize(); + } +}; + + + /// Exception Handler for COM exceptions + +extern void HandleException(COMException& e, HWND hwnd); + + + /// wrapper class for COM interface pointers + +template<typename T> struct SIfacePtr +{ + SIfacePtr() + : _p(0) + { + } + + SIfacePtr(T* p) + : _p(p) + { + if (p) + p->AddRef(); + } + + SIfacePtr(IUnknown* unknown, REFIID riid) + { + CHECKERROR(unknown->QueryInterface(riid, (LPVOID*)&_p)); + } + + ~SIfacePtr() + { + Free(); + } + + T* operator->() + { + return _p; + } + + const T* operator->() const + { + return _p; + } + +/* not GCC compatible + operator const T*() const + { + return _p; + } */ + + operator T*() + { + return _p; + } + + T** operator&() + { + return &_p; + } + + bool empty() const //NOTE: GCC seems not to work correctly when defining operator bool() AND operator T*() at one time + { + return !_p; + } + + SIfacePtr& operator=(T* p) + { + Free(); + + if (p) { + p->AddRef(); + _p = p; + } + + return *this; + } + + void operator=(SIfacePtr const& o) + { + T* h = _p; + + if (o._p) + o._p->AddRef(); + + _p = o._p; + + if (h) + h->Release(); + } + + HRESULT CreateInstance(REFIID clsid, REFIID riid) + { + return CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, riid, (LPVOID*)&_p); + } + + template<typename I> HRESULT QueryInterface(REFIID riid, I* p) + { + return _p->QueryInterface(riid, (LPVOID*)p); + } + + T* get() + { + return _p; + } + + void Free() + { + T* h = _p; + _p = NULL; + + if (h) + h->Release(); + } + +protected: + SIfacePtr(const SIfacePtr& o) + : _p(o._p) + { + if (_p) + _p->AddRef(); + } + + T* _p; +}; diff --git a/reactos/subsys/system/regsvr32/resource.h b/reactos/subsys/system/regsvr32/resource.h index c4a86729b2f..75c6bbb87af 100644 --- a/reactos/subsys/system/regsvr32/resource.h +++ b/reactos/subsys/system/regsvr32/resource.h @@ -1,13 +1,13 @@ - - -#define RC_STRING_MAX_SIZE 4096 -#define IDS_UsageMessage 100 -#define IDS_NoDllSpecified 101 -#define IDS_InvalidFlag 102 -#define IDS_SwitchN_NoI 103 -#define IDS_DllNotLoaded 104 -#define IDS_MissingEntry 105 -#define IDS_FailureMessage 106 -#define IDS_SuccessMessage 107 - -/* EOF */ + + +#define RC_STRING_MAX_SIZE 4096 +#define IDS_UsageMessage 100 +#define IDS_NoDllSpecified 101 +#define IDS_InvalidFlag 102 +#define IDS_SwitchN_NoI 103 +#define IDS_DllNotLoaded 104 +#define IDS_MissingEntry 105 +#define IDS_FailureMessage 106 +#define IDS_SuccessMessage 107 + +/* EOF */ diff --git a/reactos/subsys/system/reporterror/reporterror.c b/reactos/subsys/system/reporterror/reporterror.c index 4968e912ae6..fd08bd89875 100644 --- a/reactos/subsys/system/reporterror/reporterror.c +++ b/reactos/subsys/system/reporterror/reporterror.c @@ -1,625 +1,625 @@ -/* - * ReactOS Error Reporting Assistant - * Copyright (C) 2004-2005 Casper S. Hornstrup <chorns@users.sourceforge.net> - * Copyright (C) 2003-2004 Peter Willis <psyphreak@phreaker.net> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS Error Reporting Assistant - * FILE: subsys/system/reporterror/reporterror.c - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * Thomas Weidenmueller (w3seek@users.sourceforge.net) - */ -#include <windows.h> -#include <commctrl.h> -#include <stdio.h> -#include <string.h> -#include "reporterror.h" - -static LPSTR ErrorReportingServerName = "errors.reactos.com"; -static HINSTANCE hAppInstance; -static HANDLE hSubmissionThread = NULL; -static HWND hSubmissionNotifyWnd = NULL; -static LONG AbortSubmission = 0; -static LPERROR_REPORT ErrorReport = NULL; - -#define WM_ABORT_SUBMISSION (WM_USER + 2) -#define WM_CONTACTING_SERVER (WM_USER + 3) -#define WM_SUBMISSION_COMPLETE (WM_USER + 4) - -#define MAX_REQUEST_BUFFER_SIZE 20480 - -LPSTR -UrlEncode(LPSTR in, LPSTR out) -{ - CHAR buffer[4]; - UCHAR iu; - size_t i; - - for (i = 0; i < strlen(in); i++) - { - iu = (UCHAR)in[i]; - memset(buffer, '\0', sizeof(buffer)); - if ((iu < 33 || iu > 126)) - sprintf(buffer, "%%%02x", iu); - else - sprintf(buffer, "%c", iu); - strcat(out, buffer); - } - return out; -} - -LPERROR_REPORT -FillErrorReport(HWND hwndDlg) -{ - INT size; - LPERROR_REPORT errorReport = malloc(sizeof(ERROR_REPORT)); - - size = 300; - errorReport->YourEmail = malloc(size); - GetDlgItemTextA(hwndDlg, - IDE_SUBMIT_REPORT_YOUR_EMAIL, - errorReport->YourEmail, - size); - - size = 10240; - errorReport->ProblemDescription = malloc(size); - GetDlgItemTextA(hwndDlg, - IDE_SUBMIT_REPORT_PROBLEM_DESCRIPTION, - errorReport->ProblemDescription, - size); - - return errorReport; -} - -VOID -ReleaseErrorReport(LPERROR_REPORT errorReport) -{ - if (errorReport->YourEmail) - free(errorReport->YourEmail); - if (errorReport->ProblemDescription) - free(errorReport->ProblemDescription); - free(errorReport); -} - -BOOL -ProcessMessage(VOID) -{ - MSG msg; - if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - return TRUE; - } - return FALSE; -} - -VOID -ProcessMessages(VOID) -{ - while (ProcessMessage()); -} - -VOID -InitPropSheetPage(PROPSHEETPAGE *psp, WORD idDlg, DWORD Flags, DLGPROC DlgProc) -{ - ZeroMemory(psp, sizeof(PROPSHEETPAGE)); - psp->dwSize = sizeof(PROPSHEETPAGE); - psp->dwFlags = PSP_DEFAULT | Flags; - psp->hInstance = hAppInstance; - psp->pszTemplate = MAKEINTRESOURCE(idDlg); - psp->pfnDlgProc = DlgProc; -} - -INT_PTR CALLBACK -PageFirstPageProc( - HWND hwndDlg, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) -{ - switch(uMsg) - { - case WM_NOTIFY: - { - LPNMHDR pnmh = (LPNMHDR)lParam; - switch (pnmh->code) - { - case PSN_SETACTIVE: - { - PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT); - break; - } - case PSN_WIZNEXT: - { - SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_SUBMIT_REPORT); - return TRUE; - } - } - break; - } - } - return FALSE; -} - -INT_PTR CALLBACK -PageSubmitReportProc( - HWND hwndDlg, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) -{ - switch (uMsg) - { - case WM_NOTIFY: - { - LPNMHDR pnmh = (LPNMHDR)lParam; - switch (pnmh->code) - { - case PSN_SETACTIVE: - { - PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT); - break; - } - case PSN_WIZNEXT: - { - ErrorReport = FillErrorReport(hwndDlg); - SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_SUBMITTING_REPORT); - break; - } - } - break; - } - } - return FALSE; -} - -VOID -TerminateSubmission(BOOL Wait) -{ - if (hSubmissionThread != NULL) - { - if (Wait) - { - InterlockedExchange((LONG*)&AbortSubmission, 2); - WaitForSingleObject(hSubmissionThread, INFINITE); - } - else - InterlockedExchange((LONG*)&AbortSubmission, 1); - } -} - -INT -ConnectToServer(LPSTR host, - SOCKET *clientSocket, - LPWSTR errorMessage) -{ - struct sockaddr_in sin; - struct hostent *hp; - struct servent *sp; - INT error; - WCHAR szMsg[1024]; - SOCKET s; - - *clientSocket = 0; - - hp = gethostbyname(host); - if (hp == NULL) - { - error = WSAGetLastError(); - - //L"Could not resolve DNS for %S (windows error code %d) - LoadString( GetModuleHandle(NULL), IDS_DNS_ERROR, (LPTSTR) szMsg, sizeof(szMsg) / sizeof(WCHAR)); - wsprintf(errorMessage, L"Could not resolve DNS for %S (windows error code %d)", host, error); - return error; - } - - s = socket(hp->h_addrtype, SOCK_STREAM, 0); - if (s < 0) - { - error = WSAGetLastError(); - - // L"Could not create socket (windows error code %d) - LoadString( GetModuleHandle(NULL), IDS_SOCKET_ERROR, (LPTSTR) szMsg, sizeof(szMsg) / sizeof(WCHAR)); - wsprintf(errorMessage, szMsg, error); - return error; - } - - memset(&sin, 0, sizeof(sin)); - sin.sin_family = hp->h_addrtype; - if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) - { - error = WSAGetLastError(); - - //L"Could not resolve DNS for %S (windows error code %d) - LoadString( GetModuleHandle(NULL), IDS_DNS_ERROR, (LPTSTR) szMsg, sizeof(szMsg) / sizeof(WCHAR)); - wsprintf(errorMessage, L"Could not resolve DNS for %S (windows error code %d)", host, error); - closesocket(s); - return error; - } - - memcpy((char *)&sin.sin_addr, hp->h_addr, hp->h_length); - sp = getservbyname("www", "tcp"); - if (sp == NULL) - { - error = WSAGetLastError(); - - //L"Could not get service (windows error code %d)" - - LoadString( GetModuleHandle(NULL), IDS_GET_SRV_ERROR, (LPTSTR) szMsg, sizeof(szMsg) / sizeof(WCHAR)); - wsprintf(errorMessage, szMsg, error); - closesocket(s); - return error; - } - - sin.sin_port = sp->s_port; - - if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) - { - error = WSAGetLastError(); - - //L"Could not connect to server (windows error code %d)" - LoadString( GetModuleHandle(NULL), IDS_CON_SRV_ERROR, (LPTSTR) szMsg, sizeof(szMsg) / sizeof(WCHAR)); - wsprintf(errorMessage,szMsg , error); - closesocket(s); - return error; - } - - *clientSocket = s; - return NO_ERROR; -} - -VOID -CreateHTTPPostRequest(LPSTR requestBuffer, - LPSTR hostname, - LPERROR_REPORT errorReport) -{ - LPSTR parameterBuffer; - LPSTR urlencodeBuffer; - - parameterBuffer = malloc(MAX_REQUEST_BUFFER_SIZE); - memset(parameterBuffer, '\0', MAX_REQUEST_BUFFER_SIZE); - - strcat(parameterBuffer, "errorReport="); - strcat(parameterBuffer, "<ErrorReportRequest>"); - strcat(parameterBuffer, "<YourEmail>"); - strcat(parameterBuffer, errorReport->YourEmail); - strcat(parameterBuffer, "</YourEmail>"); - strcat(parameterBuffer, "<ProblemDescription>"); - strcat(parameterBuffer, errorReport->ProblemDescription); - strcat(parameterBuffer, "</ProblemDescription>"); - strcat(parameterBuffer, "</ErrorReportRequest>"); - strcat(parameterBuffer, "\r\n"); - - urlencodeBuffer = malloc(MAX_REQUEST_BUFFER_SIZE); - memset(urlencodeBuffer, '\0', MAX_REQUEST_BUFFER_SIZE); - - UrlEncode(parameterBuffer, urlencodeBuffer); - sprintf(requestBuffer, "POST /Report.asmx/SubmitErrorReport HTTP/1.1\r\n" - "Host: %s\r\n" - "Content-Type: application/x-www-form-urlencoded\r\n" - "Content-Length: %d\r\n" - "\r\n" - "%s", - hostname, - strlen(urlencodeBuffer), - urlencodeBuffer); - - free(urlencodeBuffer); - free(parameterBuffer); -} - -#define CONTENT_LENGTH "Content-Length:" - -BOOL -WasErrorReportDelivered(LPSTR httpResponse) -{ - return strstr(httpResponse, "</ErrorReportResponse>") != NULL; -} - -BOOL -ReceiveResponse(SOCKET socket, LPSTR responseBuffer, PULONG responseBufferSize) -{ - PCHAR pch = (PCHAR)responseBuffer; - ULONG length = 0; - fd_set fdset[1]; - struct timeval timeout; - - FD_ZERO(&fdset); - FD_SET(socket, &fdset); - timeout.tv_sec = 5; - timeout.tv_usec = 0; - while (select(1, fdset, NULL, NULL, &timeout) > 0) - { - if (recv(socket, pch, 1, 0) == 1) - { - pch++; - length++; - if (WasErrorReportDelivered(responseBuffer)) - { - *responseBufferSize = length; - return TRUE; - } - } - else - break; - } - *responseBufferSize = 0; - return FALSE; -} - -BOOL -SubmitErrorReport(SOCKET socket, LPERROR_REPORT errorReport) -{ - BOOL wasErrorReportDelivered; - LPSTR requestBuffer; - LPSTR responseBuffer; - ULONG requestBufferSize = MAX_REQUEST_BUFFER_SIZE; - - requestBuffer = malloc(requestBufferSize); - memset(requestBuffer, '\0', requestBufferSize); - CreateHTTPPostRequest(requestBuffer, ErrorReportingServerName, errorReport); - send(socket, requestBuffer, strlen(requestBuffer), 0); - responseBuffer = malloc(requestBufferSize); - wasErrorReportDelivered = ReceiveResponse(socket, responseBuffer, IN OUT &requestBufferSize); - free(responseBuffer); - free(requestBuffer); - return wasErrorReportDelivered; -} - -VOID -DisconnectFromServer(SOCKET socket) -{ - closesocket(socket); -} - -DWORD STDCALL -SubmissionThread(LPVOID lpParameter) -{ - WCHAR errorMessage[1024]; - SOCKET socket; - HANDLE hThread; - INT error; - - if (AbortSubmission != 0) - goto done; - - PostMessage(hSubmissionNotifyWnd, WM_CONTACTING_SERVER, IDS_CONTACTING_SERVER, 0); - - error = ConnectToServer(ErrorReportingServerName, &socket, errorMessage); - if (error != NO_ERROR) - { - MessageBox(NULL, errorMessage, NULL, MB_ICONWARNING); - - PostMessage(hSubmissionNotifyWnd, WM_ABORT_SUBMISSION, IDS_FAILED_TO_LOCATE_SERVER, 0); - goto cleanup; - } - - if (!SubmitErrorReport(socket, ErrorReport)) - { - PostMessage(hSubmissionNotifyWnd, WM_ABORT_SUBMISSION, IDS_FAILED_TO_DELIVER_ERROR_REPORT, 0); - goto cleanup; - } - - DisconnectFromServer(socket); -done: - switch (AbortSubmission) - { - case 0: - SendMessage(hSubmissionNotifyWnd, WM_SUBMISSION_COMPLETE, 0, 0); - break; - case 1: - SendMessage(hSubmissionNotifyWnd, WM_ABORT_SUBMISSION, 0, 0); - break; - } - -cleanup: - hThread = (HANDLE)InterlockedExchange((LONG*)&hSubmissionThread, 0); - if (hThread != NULL) - CloseHandle(hThread); - ReleaseErrorReport(ErrorReport); - ErrorReport = NULL; - return 0; -} - -BOOL -StartSubmissionThread(HWND hWndNotify) -{ - if (hSubmissionThread == NULL) - { - DWORD ThreadId; - hSubmissionNotifyWnd = hWndNotify; - AbortSubmission = 0; - hSubmissionThread = CreateThread(NULL, - 0, - SubmissionThread, - NULL, - CREATE_SUSPENDED, - &ThreadId); - if (hSubmissionThread == NULL) - return FALSE; - - ResumeThread(hSubmissionThread); - return TRUE; - } - - return FALSE; -} - -INT_PTR CALLBACK -PageSubmittingReportProc( - HWND hwndDlg, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) -{ - switch (uMsg) - { - case WM_NOTIFY: - { - LPNMHDR pnmh = (LPNMHDR)lParam; - switch (pnmh->code) - { - case PSN_SETACTIVE: - { - SetDlgItemText(hwndDlg, IDC_SUBMISSION_STATUS, NULL); - SendDlgItemMessage(hwndDlg, IDC_SUBMITTING_IN_PROGRESS, PBM_SETMARQUEE, TRUE, 50); - PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK); - StartSubmissionThread(hwndDlg); - break; - } - case PSN_RESET: - { - TerminateSubmission(TRUE); - break; - } - case PSN_WIZBACK: - if (hSubmissionThread != NULL) - { - PropSheet_SetWizButtons(GetParent(hwndDlg), 0); - TerminateSubmission(FALSE); - SetWindowLong(hwndDlg, DWL_MSGRESULT, -1); - return -1; - } - else - { - SendDlgItemMessage(hwndDlg, IDC_SUBMITTING_IN_PROGRESS, PBM_SETMARQUEE, FALSE, 0); - SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_SUBMIT_REPORT); - } - break; - } - break; - } - case WM_CONTACTING_SERVER: - { - WCHAR Msg[1024]; - LoadString(hAppInstance, wParam, Msg, sizeof(Msg) / sizeof(WCHAR)); - SetDlgItemText(hwndDlg, IDC_SUBMISSION_STATUS, Msg); - break; - } - case WM_SUBMISSION_COMPLETE: - { - SendDlgItemMessage(hwndDlg, IDC_SUBMITTING_IN_PROGRESS, PBM_SETMARQUEE, FALSE, 0); - PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT); - PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_SUBMITTED_REPORT); - break; - } - case WM_ABORT_SUBMISSION: - { - /* Go back in case we aborted the submission thread */ - SendDlgItemMessage(hwndDlg, IDC_SUBMITTING_IN_PROGRESS, PBM_SETMARQUEE, FALSE, 0); - PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_SUBMIT_REPORT); - if (wParam != 0) - { - WCHAR Msg[1024]; - LoadString(hAppInstance, wParam, Msg, sizeof(Msg) / sizeof(WCHAR)); - MessageBox(GetParent(hwndDlg), Msg, NULL, MB_ICONWARNING); - } - break; - } - } - return FALSE; -} - -INT_PTR CALLBACK -PageSubmittedReportProc( - HWND hwndDlg, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) -{ - switch(uMsg) - { - case WM_NOTIFY: - { - LPNMHDR pnmh = (LPNMHDR)lParam; - switch (pnmh->code) - { - case PSN_SETACTIVE: - { - EnableWindow(GetDlgItem(GetParent(hwndDlg), IDCANCEL), FALSE); - PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_FINISH); - break; - } - } - break; - } - } - return FALSE; -} - -static LONG -CreateWizard(VOID) -{ - PROPSHEETPAGE psp[8]; - PROPSHEETHEADER psh; - WCHAR Caption[1024]; - - LoadString(hAppInstance, IDS_WIZARD_NAME, Caption, sizeof(Caption) / sizeof(TCHAR)); - - ZeroMemory(&psh, sizeof(PROPSHEETHEADER)); - psh.dwSize = sizeof(PROPSHEETHEADER); - psh.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD97 | PSH_WATERMARK | PSH_HEADER; - psh.hwndParent = NULL; - psh.hInstance = hAppInstance; - psh.hIcon = 0; - psh.pszCaption = Caption; - psh.nPages = 4; - psh.nStartPage = 0; - psh.ppsp = psp; - psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK); - psh.pszbmHeader = MAKEINTRESOURCE(IDB_HEADER); - - InitPropSheetPage(&psp[0], IDD_FIRSTPAGE, PSP_HIDEHEADER, PageFirstPageProc); - InitPropSheetPage(&psp[1], IDD_SUBMIT_REPORT, PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE, PageSubmitReportProc); - InitPropSheetPage(&psp[2], IDD_SUBMITTING_REPORT, PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE, PageSubmittingReportProc); - InitPropSheetPage(&psp[3], IDD_SUBMITTED_REPORT, PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE, PageSubmittedReportProc); - - return (LONG)(PropertySheet(&psh) != -1); -} - -int WINAPI -WinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpszCmdLine, - int nCmdShow) -{ - WORD wVersionRequested; - WSADATA wsaData; - INT error; - - hAppInstance = hInstance; - - wVersionRequested = MAKEWORD(1, 1); - error = WSAStartup(wVersionRequested, &wsaData); - if (error != NO_ERROR) - { - WCHAR format[1024]; - WCHAR message[1024]; - LoadString(hAppInstance, IDS_FAILED_TO_INITIALIZE_WINSOCK, format, sizeof(format) / sizeof(WCHAR)); - wsprintf(message, format, error); - MessageBox(NULL, message, NULL, MB_ICONWARNING); - return 0; - } - - CreateWizard(); - - WSACleanup(); - - return 0; -} +/* + * ReactOS Error Reporting Assistant + * Copyright (C) 2004-2005 Casper S. Hornstrup <chorns@users.sourceforge.net> + * Copyright (C) 2003-2004 Peter Willis <psyphreak@phreaker.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Error Reporting Assistant + * FILE: subsys/system/reporterror/reporterror.c + * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) + * Thomas Weidenmueller (w3seek@users.sourceforge.net) + */ +#include <windows.h> +#include <commctrl.h> +#include <stdio.h> +#include <string.h> +#include "reporterror.h" + +static LPSTR ErrorReportingServerName = "errors.reactos.com"; +static HINSTANCE hAppInstance; +static HANDLE hSubmissionThread = NULL; +static HWND hSubmissionNotifyWnd = NULL; +static LONG AbortSubmission = 0; +static LPERROR_REPORT ErrorReport = NULL; + +#define WM_ABORT_SUBMISSION (WM_USER + 2) +#define WM_CONTACTING_SERVER (WM_USER + 3) +#define WM_SUBMISSION_COMPLETE (WM_USER + 4) + +#define MAX_REQUEST_BUFFER_SIZE 20480 + +LPSTR +UrlEncode(LPSTR in, LPSTR out) +{ + CHAR buffer[4]; + UCHAR iu; + size_t i; + + for (i = 0; i < strlen(in); i++) + { + iu = (UCHAR)in[i]; + memset(buffer, '\0', sizeof(buffer)); + if ((iu < 33 || iu > 126)) + sprintf(buffer, "%%%02x", iu); + else + sprintf(buffer, "%c", iu); + strcat(out, buffer); + } + return out; +} + +LPERROR_REPORT +FillErrorReport(HWND hwndDlg) +{ + INT size; + LPERROR_REPORT errorReport = malloc(sizeof(ERROR_REPORT)); + + size = 300; + errorReport->YourEmail = malloc(size); + GetDlgItemTextA(hwndDlg, + IDE_SUBMIT_REPORT_YOUR_EMAIL, + errorReport->YourEmail, + size); + + size = 10240; + errorReport->ProblemDescription = malloc(size); + GetDlgItemTextA(hwndDlg, + IDE_SUBMIT_REPORT_PROBLEM_DESCRIPTION, + errorReport->ProblemDescription, + size); + + return errorReport; +} + +VOID +ReleaseErrorReport(LPERROR_REPORT errorReport) +{ + if (errorReport->YourEmail) + free(errorReport->YourEmail); + if (errorReport->ProblemDescription) + free(errorReport->ProblemDescription); + free(errorReport); +} + +BOOL +ProcessMessage(VOID) +{ + MSG msg; + if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + return TRUE; + } + return FALSE; +} + +VOID +ProcessMessages(VOID) +{ + while (ProcessMessage()); +} + +VOID +InitPropSheetPage(PROPSHEETPAGE *psp, WORD idDlg, DWORD Flags, DLGPROC DlgProc) +{ + ZeroMemory(psp, sizeof(PROPSHEETPAGE)); + psp->dwSize = sizeof(PROPSHEETPAGE); + psp->dwFlags = PSP_DEFAULT | Flags; + psp->hInstance = hAppInstance; + psp->pszTemplate = MAKEINTRESOURCE(idDlg); + psp->pfnDlgProc = DlgProc; +} + +INT_PTR CALLBACK +PageFirstPageProc( + HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch(uMsg) + { + case WM_NOTIFY: + { + LPNMHDR pnmh = (LPNMHDR)lParam; + switch (pnmh->code) + { + case PSN_SETACTIVE: + { + PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT); + break; + } + case PSN_WIZNEXT: + { + SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_SUBMIT_REPORT); + return TRUE; + } + } + break; + } + } + return FALSE; +} + +INT_PTR CALLBACK +PageSubmitReportProc( + HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch (uMsg) + { + case WM_NOTIFY: + { + LPNMHDR pnmh = (LPNMHDR)lParam; + switch (pnmh->code) + { + case PSN_SETACTIVE: + { + PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT); + break; + } + case PSN_WIZNEXT: + { + ErrorReport = FillErrorReport(hwndDlg); + SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_SUBMITTING_REPORT); + break; + } + } + break; + } + } + return FALSE; +} + +VOID +TerminateSubmission(BOOL Wait) +{ + if (hSubmissionThread != NULL) + { + if (Wait) + { + InterlockedExchange((LONG*)&AbortSubmission, 2); + WaitForSingleObject(hSubmissionThread, INFINITE); + } + else + InterlockedExchange((LONG*)&AbortSubmission, 1); + } +} + +INT +ConnectToServer(LPSTR host, + SOCKET *clientSocket, + LPWSTR errorMessage) +{ + struct sockaddr_in sin; + struct hostent *hp; + struct servent *sp; + INT error; + WCHAR szMsg[1024]; + SOCKET s; + + *clientSocket = 0; + + hp = gethostbyname(host); + if (hp == NULL) + { + error = WSAGetLastError(); + + //L"Could not resolve DNS for %S (windows error code %d) + LoadString( GetModuleHandle(NULL), IDS_DNS_ERROR, (LPTSTR) szMsg, sizeof(szMsg) / sizeof(WCHAR)); + wsprintf(errorMessage, L"Could not resolve DNS for %S (windows error code %d)", host, error); + return error; + } + + s = socket(hp->h_addrtype, SOCK_STREAM, 0); + if (s < 0) + { + error = WSAGetLastError(); + + // L"Could not create socket (windows error code %d) + LoadString( GetModuleHandle(NULL), IDS_SOCKET_ERROR, (LPTSTR) szMsg, sizeof(szMsg) / sizeof(WCHAR)); + wsprintf(errorMessage, szMsg, error); + return error; + } + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = hp->h_addrtype; + if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) + { + error = WSAGetLastError(); + + //L"Could not resolve DNS for %S (windows error code %d) + LoadString( GetModuleHandle(NULL), IDS_DNS_ERROR, (LPTSTR) szMsg, sizeof(szMsg) / sizeof(WCHAR)); + wsprintf(errorMessage, L"Could not resolve DNS for %S (windows error code %d)", host, error); + closesocket(s); + return error; + } + + memcpy((char *)&sin.sin_addr, hp->h_addr, hp->h_length); + sp = getservbyname("www", "tcp"); + if (sp == NULL) + { + error = WSAGetLastError(); + + //L"Could not get service (windows error code %d)" + + LoadString( GetModuleHandle(NULL), IDS_GET_SRV_ERROR, (LPTSTR) szMsg, sizeof(szMsg) / sizeof(WCHAR)); + wsprintf(errorMessage, szMsg, error); + closesocket(s); + return error; + } + + sin.sin_port = sp->s_port; + + if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) + { + error = WSAGetLastError(); + + //L"Could not connect to server (windows error code %d)" + LoadString( GetModuleHandle(NULL), IDS_CON_SRV_ERROR, (LPTSTR) szMsg, sizeof(szMsg) / sizeof(WCHAR)); + wsprintf(errorMessage,szMsg , error); + closesocket(s); + return error; + } + + *clientSocket = s; + return NO_ERROR; +} + +VOID +CreateHTTPPostRequest(LPSTR requestBuffer, + LPSTR hostname, + LPERROR_REPORT errorReport) +{ + LPSTR parameterBuffer; + LPSTR urlencodeBuffer; + + parameterBuffer = malloc(MAX_REQUEST_BUFFER_SIZE); + memset(parameterBuffer, '\0', MAX_REQUEST_BUFFER_SIZE); + + strcat(parameterBuffer, "errorReport="); + strcat(parameterBuffer, "<ErrorReportRequest>"); + strcat(parameterBuffer, "<YourEmail>"); + strcat(parameterBuffer, errorReport->YourEmail); + strcat(parameterBuffer, "</YourEmail>"); + strcat(parameterBuffer, "<ProblemDescription>"); + strcat(parameterBuffer, errorReport->ProblemDescription); + strcat(parameterBuffer, "</ProblemDescription>"); + strcat(parameterBuffer, "</ErrorReportRequest>"); + strcat(parameterBuffer, "\r\n"); + + urlencodeBuffer = malloc(MAX_REQUEST_BUFFER_SIZE); + memset(urlencodeBuffer, '\0', MAX_REQUEST_BUFFER_SIZE); + + UrlEncode(parameterBuffer, urlencodeBuffer); + sprintf(requestBuffer, "POST /Report.asmx/SubmitErrorReport HTTP/1.1\r\n" + "Host: %s\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Content-Length: %d\r\n" + "\r\n" + "%s", + hostname, + strlen(urlencodeBuffer), + urlencodeBuffer); + + free(urlencodeBuffer); + free(parameterBuffer); +} + +#define CONTENT_LENGTH "Content-Length:" + +BOOL +WasErrorReportDelivered(LPSTR httpResponse) +{ + return strstr(httpResponse, "</ErrorReportResponse>") != NULL; +} + +BOOL +ReceiveResponse(SOCKET socket, LPSTR responseBuffer, PULONG responseBufferSize) +{ + PCHAR pch = (PCHAR)responseBuffer; + ULONG length = 0; + fd_set fdset[1]; + struct timeval timeout; + + FD_ZERO(&fdset); + FD_SET(socket, &fdset); + timeout.tv_sec = 5; + timeout.tv_usec = 0; + while (select(1, fdset, NULL, NULL, &timeout) > 0) + { + if (recv(socket, pch, 1, 0) == 1) + { + pch++; + length++; + if (WasErrorReportDelivered(responseBuffer)) + { + *responseBufferSize = length; + return TRUE; + } + } + else + break; + } + *responseBufferSize = 0; + return FALSE; +} + +BOOL +SubmitErrorReport(SOCKET socket, LPERROR_REPORT errorReport) +{ + BOOL wasErrorReportDelivered; + LPSTR requestBuffer; + LPSTR responseBuffer; + ULONG requestBufferSize = MAX_REQUEST_BUFFER_SIZE; + + requestBuffer = malloc(requestBufferSize); + memset(requestBuffer, '\0', requestBufferSize); + CreateHTTPPostRequest(requestBuffer, ErrorReportingServerName, errorReport); + send(socket, requestBuffer, strlen(requestBuffer), 0); + responseBuffer = malloc(requestBufferSize); + wasErrorReportDelivered = ReceiveResponse(socket, responseBuffer, IN OUT &requestBufferSize); + free(responseBuffer); + free(requestBuffer); + return wasErrorReportDelivered; +} + +VOID +DisconnectFromServer(SOCKET socket) +{ + closesocket(socket); +} + +DWORD STDCALL +SubmissionThread(LPVOID lpParameter) +{ + WCHAR errorMessage[1024]; + SOCKET socket; + HANDLE hThread; + INT error; + + if (AbortSubmission != 0) + goto done; + + PostMessage(hSubmissionNotifyWnd, WM_CONTACTING_SERVER, IDS_CONTACTING_SERVER, 0); + + error = ConnectToServer(ErrorReportingServerName, &socket, errorMessage); + if (error != NO_ERROR) + { + MessageBox(NULL, errorMessage, NULL, MB_ICONWARNING); + + PostMessage(hSubmissionNotifyWnd, WM_ABORT_SUBMISSION, IDS_FAILED_TO_LOCATE_SERVER, 0); + goto cleanup; + } + + if (!SubmitErrorReport(socket, ErrorReport)) + { + PostMessage(hSubmissionNotifyWnd, WM_ABORT_SUBMISSION, IDS_FAILED_TO_DELIVER_ERROR_REPORT, 0); + goto cleanup; + } + + DisconnectFromServer(socket); +done: + switch (AbortSubmission) + { + case 0: + SendMessage(hSubmissionNotifyWnd, WM_SUBMISSION_COMPLETE, 0, 0); + break; + case 1: + SendMessage(hSubmissionNotifyWnd, WM_ABORT_SUBMISSION, 0, 0); + break; + } + +cleanup: + hThread = (HANDLE)InterlockedExchange((LONG*)&hSubmissionThread, 0); + if (hThread != NULL) + CloseHandle(hThread); + ReleaseErrorReport(ErrorReport); + ErrorReport = NULL; + return 0; +} + +BOOL +StartSubmissionThread(HWND hWndNotify) +{ + if (hSubmissionThread == NULL) + { + DWORD ThreadId; + hSubmissionNotifyWnd = hWndNotify; + AbortSubmission = 0; + hSubmissionThread = CreateThread(NULL, + 0, + SubmissionThread, + NULL, + CREATE_SUSPENDED, + &ThreadId); + if (hSubmissionThread == NULL) + return FALSE; + + ResumeThread(hSubmissionThread); + return TRUE; + } + + return FALSE; +} + +INT_PTR CALLBACK +PageSubmittingReportProc( + HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch (uMsg) + { + case WM_NOTIFY: + { + LPNMHDR pnmh = (LPNMHDR)lParam; + switch (pnmh->code) + { + case PSN_SETACTIVE: + { + SetDlgItemText(hwndDlg, IDC_SUBMISSION_STATUS, NULL); + SendDlgItemMessage(hwndDlg, IDC_SUBMITTING_IN_PROGRESS, PBM_SETMARQUEE, TRUE, 50); + PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK); + StartSubmissionThread(hwndDlg); + break; + } + case PSN_RESET: + { + TerminateSubmission(TRUE); + break; + } + case PSN_WIZBACK: + if (hSubmissionThread != NULL) + { + PropSheet_SetWizButtons(GetParent(hwndDlg), 0); + TerminateSubmission(FALSE); + SetWindowLong(hwndDlg, DWL_MSGRESULT, -1); + return -1; + } + else + { + SendDlgItemMessage(hwndDlg, IDC_SUBMITTING_IN_PROGRESS, PBM_SETMARQUEE, FALSE, 0); + SetWindowLong(hwndDlg, DWL_MSGRESULT, IDD_SUBMIT_REPORT); + } + break; + } + break; + } + case WM_CONTACTING_SERVER: + { + WCHAR Msg[1024]; + LoadString(hAppInstance, wParam, Msg, sizeof(Msg) / sizeof(WCHAR)); + SetDlgItemText(hwndDlg, IDC_SUBMISSION_STATUS, Msg); + break; + } + case WM_SUBMISSION_COMPLETE: + { + SendDlgItemMessage(hwndDlg, IDC_SUBMITTING_IN_PROGRESS, PBM_SETMARQUEE, FALSE, 0); + PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT); + PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_SUBMITTED_REPORT); + break; + } + case WM_ABORT_SUBMISSION: + { + /* Go back in case we aborted the submission thread */ + SendDlgItemMessage(hwndDlg, IDC_SUBMITTING_IN_PROGRESS, PBM_SETMARQUEE, FALSE, 0); + PropSheet_SetCurSelByID(GetParent(hwndDlg), IDD_SUBMIT_REPORT); + if (wParam != 0) + { + WCHAR Msg[1024]; + LoadString(hAppInstance, wParam, Msg, sizeof(Msg) / sizeof(WCHAR)); + MessageBox(GetParent(hwndDlg), Msg, NULL, MB_ICONWARNING); + } + break; + } + } + return FALSE; +} + +INT_PTR CALLBACK +PageSubmittedReportProc( + HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch(uMsg) + { + case WM_NOTIFY: + { + LPNMHDR pnmh = (LPNMHDR)lParam; + switch (pnmh->code) + { + case PSN_SETACTIVE: + { + EnableWindow(GetDlgItem(GetParent(hwndDlg), IDCANCEL), FALSE); + PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_FINISH); + break; + } + } + break; + } + } + return FALSE; +} + +static LONG +CreateWizard(VOID) +{ + PROPSHEETPAGE psp[8]; + PROPSHEETHEADER psh; + WCHAR Caption[1024]; + + LoadString(hAppInstance, IDS_WIZARD_NAME, Caption, sizeof(Caption) / sizeof(TCHAR)); + + ZeroMemory(&psh, sizeof(PROPSHEETHEADER)); + psh.dwSize = sizeof(PROPSHEETHEADER); + psh.dwFlags = PSH_PROPSHEETPAGE | PSH_WIZARD97 | PSH_WATERMARK | PSH_HEADER; + psh.hwndParent = NULL; + psh.hInstance = hAppInstance; + psh.hIcon = 0; + psh.pszCaption = Caption; + psh.nPages = 4; + psh.nStartPage = 0; + psh.ppsp = psp; + psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK); + psh.pszbmHeader = MAKEINTRESOURCE(IDB_HEADER); + + InitPropSheetPage(&psp[0], IDD_FIRSTPAGE, PSP_HIDEHEADER, PageFirstPageProc); + InitPropSheetPage(&psp[1], IDD_SUBMIT_REPORT, PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE, PageSubmitReportProc); + InitPropSheetPage(&psp[2], IDD_SUBMITTING_REPORT, PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE, PageSubmittingReportProc); + InitPropSheetPage(&psp[3], IDD_SUBMITTED_REPORT, PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE, PageSubmittedReportProc); + + return (LONG)(PropertySheet(&psh) != -1); +} + +int WINAPI +WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpszCmdLine, + int nCmdShow) +{ + WORD wVersionRequested; + WSADATA wsaData; + INT error; + + hAppInstance = hInstance; + + wVersionRequested = MAKEWORD(1, 1); + error = WSAStartup(wVersionRequested, &wsaData); + if (error != NO_ERROR) + { + WCHAR format[1024]; + WCHAR message[1024]; + LoadString(hAppInstance, IDS_FAILED_TO_INITIALIZE_WINSOCK, format, sizeof(format) / sizeof(WCHAR)); + wsprintf(message, format, error); + MessageBox(NULL, message, NULL, MB_ICONWARNING); + return 0; + } + + CreateWizard(); + + WSACleanup(); + + return 0; +} diff --git a/reactos/subsys/system/reporterror/reporterror.h b/reactos/subsys/system/reporterror/reporterror.h index 3c79314483d..827c75d3cf9 100644 --- a/reactos/subsys/system/reporterror/reporterror.h +++ b/reactos/subsys/system/reporterror/reporterror.h @@ -1,56 +1,56 @@ -#ifndef __REPORTERROR_H -#define __REPORTERROR_H - -#ifndef PSCB_BUTTONPRESSED -#define PSCB_BUTTONPRESSED (3) -#endif - -#ifndef PBS_MARQUEE -#define PBS_MARQUEE (8) -#endif - -/* metrics */ -#define PROPSHEETWIDTH 250 -#define PROPSHEETHEIGHT 120 -#define PROPSHEETPADDING 6 -#define SYSTEM_COLUMN (18 * PROPSHEETPADDING) -#define LABELLINE(x) (((PROPSHEETPADDING + 2) * x) + (x + 2)) -#define ICONSIZE 16 - -/* Resource IDs */ - -#define IDS_WIZARD_NAME 100 -#define IDS_FAILED_TO_CONTACT_SERVER 101 - -#define IDS_CONTACTING_SERVER 201 -#define IDS_FAILED_TO_INITIALIZE_WINSOCK 202 -#define IDS_FAILED_TO_LOCATE_SERVER 203 -#define IDS_FAILED_TO_DELIVER_ERROR_REPORT 204 - -#define IDD_FIRSTPAGE 100 -#define IDD_SUBMIT_REPORT 101 -#define IDD_SUBMITTING_REPORT 102 -#define IDD_SUBMITTED_REPORT 103 - -#define IDC_SUBMISSION_STATUS 200 -#define IDC_SUBMITTING_IN_PROGRESS 201 - -#define IDE_SUBMIT_REPORT_YOUR_EMAIL 300 -#define IDE_SUBMIT_REPORT_PROBLEM_DESCRIPTION 301 - -#define IDB_WATERMARK 100 -#define IDB_HEADER 101 - - -#define IDS_DNS_ERROR 600 -#define IDS_SOCKET_ERROR 601 -#define IDS_GET_SRV_ERROR 602 -#define IDS_CON_SRV_ERROR 603 - -typedef struct _ERROR_REPORT -{ - LPSTR YourEmail; - LPSTR ProblemDescription; -} ERROR_REPORT, *LPERROR_REPORT; - -#endif /* __REPORTERROR_H */ +#ifndef __REPORTERROR_H +#define __REPORTERROR_H + +#ifndef PSCB_BUTTONPRESSED +#define PSCB_BUTTONPRESSED (3) +#endif + +#ifndef PBS_MARQUEE +#define PBS_MARQUEE (8) +#endif + +/* metrics */ +#define PROPSHEETWIDTH 250 +#define PROPSHEETHEIGHT 120 +#define PROPSHEETPADDING 6 +#define SYSTEM_COLUMN (18 * PROPSHEETPADDING) +#define LABELLINE(x) (((PROPSHEETPADDING + 2) * x) + (x + 2)) +#define ICONSIZE 16 + +/* Resource IDs */ + +#define IDS_WIZARD_NAME 100 +#define IDS_FAILED_TO_CONTACT_SERVER 101 + +#define IDS_CONTACTING_SERVER 201 +#define IDS_FAILED_TO_INITIALIZE_WINSOCK 202 +#define IDS_FAILED_TO_LOCATE_SERVER 203 +#define IDS_FAILED_TO_DELIVER_ERROR_REPORT 204 + +#define IDD_FIRSTPAGE 100 +#define IDD_SUBMIT_REPORT 101 +#define IDD_SUBMITTING_REPORT 102 +#define IDD_SUBMITTED_REPORT 103 + +#define IDC_SUBMISSION_STATUS 200 +#define IDC_SUBMITTING_IN_PROGRESS 201 + +#define IDE_SUBMIT_REPORT_YOUR_EMAIL 300 +#define IDE_SUBMIT_REPORT_PROBLEM_DESCRIPTION 301 + +#define IDB_WATERMARK 100 +#define IDB_HEADER 101 + + +#define IDS_DNS_ERROR 600 +#define IDS_SOCKET_ERROR 601 +#define IDS_GET_SRV_ERROR 602 +#define IDS_CON_SRV_ERROR 603 + +typedef struct _ERROR_REPORT +{ + LPSTR YourEmail; + LPSTR ProblemDescription; +} ERROR_REPORT, *LPERROR_REPORT; + +#endif /* __REPORTERROR_H */ diff --git a/reactos/subsys/system/rundll32/resource.h b/reactos/subsys/system/rundll32/resource.h index 303964ded0e..83c4a596ad0 100644 --- a/reactos/subsys/system/rundll32/resource.h +++ b/reactos/subsys/system/rundll32/resource.h @@ -1,7 +1,7 @@ - - -#define RC_STRING_MAX_SIZE 200 -#define IDS_DllNotLoaded 100 -#define IDS_MissingEntry 101 - -/* EOF */ + + +#define RC_STRING_MAX_SIZE 200 +#define IDS_DllNotLoaded 100 +#define IDS_MissingEntry 101 + +/* EOF */ diff --git a/reactos/subsys/system/services/rpcserver.c b/reactos/subsys/system/services/rpcserver.c index 58dd2029335..5edd4e05fb2 100644 --- a/reactos/subsys/system/services/rpcserver.c +++ b/reactos/subsys/system/services/rpcserver.c @@ -1,693 +1,693 @@ -/* - - */ - -/* INCLUDES ****************************************************************/ - -#include "services.h" -#include "svcctl_s.h" - -#define NDEBUG -#include <debug.h> - - -/* GLOBALS *****************************************************************/ - -#define MANAGER_TAG 0x72674D68 /* 'hMgr' */ -#define SERVICE_TAG 0x63765368 /* 'hSvc' */ - -typedef struct _SCMGR_HANDLE -{ - DWORD Tag; - DWORD RefCount; - DWORD DesiredAccess; -} SCMGR_HANDLE; - - -typedef struct _MANAGER_HANDLE -{ - SCMGR_HANDLE Handle; - - /* FIXME: Insert more data here */ - - WCHAR DatabaseName[1]; -} MANAGER_HANDLE, *PMANAGER_HANDLE; - - -typedef struct _SERVICE_HANDLE -{ - SCMGR_HANDLE Handle; - - DWORD DesiredAccess; - PSERVICE ServiceEntry; - - /* FIXME: Insert more data here */ - -} SERVICE_HANDLE, *PSERVICE_HANDLE; - - -#define SC_MANAGER_READ \ - (STANDARD_RIGHTS_READ | \ - SC_MANAGER_QUERY_LOCK_STATUS | \ - SC_MANAGER_ENUMERATE_SERVICE) - -#define SC_MANAGER_WRITE \ - (STANDARD_RIGHTS_WRITE | \ - SC_MANAGER_MODIFY_BOOT_CONFIG | \ - SC_MANAGER_CREATE_SERVICE) - -#define SC_MANAGER_EXECUTE \ - (STANDARD_RIGHTS_EXECUTE | \ - SC_MANAGER_LOCK | \ - SC_MANAGER_ENUMERATE_SERVICE | \ - SC_MANAGER_CONNECT | \ - SC_MANAGER_CREATE_SERVICE) - - -#define SERVICE_READ \ - (STANDARD_RIGHTS_READ | \ - SERVICE_INTERROGATE | \ - SERVICE_ENUMERATE_DEPENDENTS | \ - SERVICE_QUERY_STATUS | \ - SERVICE_QUERY_CONFIG) - -#define SERVICE_WRITE \ - (STANDARD_RIGHTS_WRITE | \ - SERVICE_CHANGE_CONFIG) - -#define SERVICE_EXECUTE \ - (STANDARD_RIGHTS_EXECUTE | \ - SERVICE_USER_DEFINED_CONTROL | \ - SERVICE_PAUSE_CONTINUE | \ - SERVICE_STOP | \ - SERVICE_START) - - -/* VARIABLES ***************************************************************/ - -static GENERIC_MAPPING -ScmManagerMapping = {SC_MANAGER_READ, - SC_MANAGER_WRITE, - SC_MANAGER_EXECUTE, - SC_MANAGER_ALL_ACCESS}; - -static GENERIC_MAPPING -ScmServiceMapping = {SERVICE_READ, - SERVICE_WRITE, - SERVICE_EXECUTE, - SC_MANAGER_ALL_ACCESS}; - - -/* FUNCTIONS ***************************************************************/ - -VOID -ScmStartRpcServer(VOID) -{ - RPC_STATUS Status; - - DPRINT("ScmStartRpcServer() called"); - - Status = RpcServerUseProtseqEp(L"ncacn_np", - 10, - L"\\pipe\\ntsvcs", - NULL); - if (Status != RPC_S_OK) - { - DPRINT1("RpcServerUseProtseqEp() failed (Status %lx)\n", Status); - return; - } - - Status = RpcServerRegisterIf(svcctl_ServerIfHandle, - NULL, - NULL); - if (Status != RPC_S_OK) - { - DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status); - return; - } - - Status = RpcServerListen(1, 20, TRUE); - if (Status != RPC_S_OK) - { - DPRINT1("RpcServerListen() failed (Status %lx)\n", Status); - return; - } - - DPRINT("ScmStartRpcServer() done"); -} - - -static DWORD -ScmCreateManagerHandle(LPWSTR lpDatabaseName, - SC_HANDLE *Handle) -{ - PMANAGER_HANDLE Ptr; - - if (lpDatabaseName == NULL) - lpDatabaseName = SERVICES_ACTIVE_DATABASEW; - - Ptr = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - sizeof(MANAGER_HANDLE) + wcslen(lpDatabaseName) * sizeof(WCHAR)); - if (Ptr == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - Ptr->Handle.Tag = MANAGER_TAG; - Ptr->Handle.RefCount = 1; - - /* FIXME: initialize more data here */ - - wcscpy(Ptr->DatabaseName, lpDatabaseName); - - *Handle = (SC_HANDLE)Ptr; - - return ERROR_SUCCESS; -} - - -static DWORD -ScmCreateServiceHandle(PSERVICE lpServiceEntry, - SC_HANDLE *Handle) -{ - PSERVICE_HANDLE Ptr; - - Ptr = HeapAlloc(GetProcessHeap(), - HEAP_ZERO_MEMORY, - sizeof(SERVICE_HANDLE)); - if (Ptr == NULL) - return ERROR_NOT_ENOUGH_MEMORY; - - Ptr->Handle.Tag = SERVICE_TAG; - Ptr->Handle.RefCount = 1; - - /* FIXME: initialize more data here */ - Ptr->ServiceEntry = lpServiceEntry; - - *Handle = (SC_HANDLE)Ptr; - - return ERROR_SUCCESS; -} - - -static DWORD -ScmCheckAccess(SC_HANDLE Handle, - DWORD dwDesiredAccess) -{ - PMANAGER_HANDLE hMgr; - - hMgr = (PMANAGER_HANDLE)Handle; - if (hMgr->Handle.Tag == MANAGER_TAG) - { - RtlMapGenericMask(&dwDesiredAccess, - &ScmManagerMapping); - - hMgr->Handle.DesiredAccess = dwDesiredAccess; - - return ERROR_SUCCESS; - } - else if (hMgr->Handle.Tag == SERVICE_TAG) - { - RtlMapGenericMask(&dwDesiredAccess, - &ScmServiceMapping); - - hMgr->Handle.DesiredAccess = dwDesiredAccess; - - return ERROR_SUCCESS; - } - - return ERROR_INVALID_HANDLE; -} - - -/* Function 0 */ -unsigned long -ScmrCloseServiceHandle(handle_t BindingHandle, - unsigned int hScObject) -{ - PMANAGER_HANDLE hManager; - - DPRINT("ScmrCloseServiceHandle() called\n"); - - DPRINT("hScObject = %X\n", hScObject); - - if (hScObject == 0) - return ERROR_INVALID_HANDLE; - - hManager = (PMANAGER_HANDLE)hScObject; - if (hManager->Handle.Tag == MANAGER_TAG) - { - DPRINT("Found manager handle\n"); - - hManager->Handle.RefCount--; - if (hManager->Handle.RefCount == 0) - { - /* FIXME: add cleanup code */ - - HeapFree(GetProcessHeap(), 0, hManager); - } - - DPRINT("ScmrCloseServiceHandle() done\n"); - return ERROR_SUCCESS; - } - else if (hManager->Handle.Tag == SERVICE_TAG) - { - DPRINT("Found service handle\n"); - - hManager->Handle.RefCount--; - if (hManager->Handle.RefCount == 0) - { - /* FIXME: add cleanup code */ - - HeapFree(GetProcessHeap(), 0, hManager); - } - - DPRINT("ScmrCloseServiceHandle() done\n"); - return ERROR_SUCCESS; - } - - DPRINT1("Invalid handle tag (Tag %lx)\n", hManager->Handle.Tag); - - return ERROR_INVALID_HANDLE; -} - - -/* Function 1 */ -unsigned long -ScmrControlService(handle_t BindingHandle, - unsigned int hService, - unsigned long dwControl, - LPSERVICE_STATUS lpServiceStatus) -{ - PSERVICE_HANDLE hSvc; - PSERVICE lpService; - - DPRINT1("ScmrControlService() called\n"); - - hSvc = (PSERVICE_HANDLE)hService; - if (hSvc->Handle.Tag != SERVICE_TAG) - { - DPRINT1("Invalid handle tag!\n"); - return ERROR_INVALID_HANDLE; - } - - - /* FIXME: Check access rights */ - - - lpService = hSvc->ServiceEntry; - if (lpService == NULL) - { - DPRINT1("lpService == NULL!\n"); - return ERROR_INVALID_HANDLE; - } - - - /* FIXME: Send control code to the service */ - - - /* Return service status information */ - lpServiceStatus->dwServiceType = lpService->Type; - lpServiceStatus->dwCurrentState = lpService->CurrentState; - lpServiceStatus->dwControlsAccepted = lpService->ControlsAccepted; - lpServiceStatus->dwWin32ExitCode = lpService->Win32ExitCode; - lpServiceStatus->dwServiceSpecificExitCode = lpService->ServiceSpecificExitCode; - lpServiceStatus->dwCheckPoint = lpService->CheckPoint; - lpServiceStatus->dwWaitHint = lpService->WaitHint; - - return ERROR_SUCCESS; -} - - -/* Function 2 */ -unsigned long -ScmrDeleteService(handle_t BindingHandle, - unsigned int hService) -{ - PSERVICE_HANDLE hSvc; - PSERVICE lpService; - - DPRINT1("ScmrDeleteService() called\n"); - - hSvc = (PSERVICE_HANDLE)hService; - if (hSvc->Handle.Tag != SERVICE_TAG) - return ERROR_INVALID_HANDLE; - - if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, - STANDARD_RIGHTS_REQUIRED)) - return ERROR_ACCESS_DENIED; - - lpService = hSvc->ServiceEntry; - if (lpService == NULL) - { - DPRINT1("lpService == NULL!\n"); - return ERROR_INVALID_HANDLE; - } - - /* FIXME: Mark service for delete */ - - return ERROR_SUCCESS; -} - - -/* Function 3 */ -unsigned long -ScmrLockServiceDatabase(handle_t BindingHandle, - unsigned int hSCManager, - unsigned int *hLock) -{ - PMANAGER_HANDLE hMgr; - - DPRINT("ScmrLockServiceDatabase() called\n"); - - *hLock = 0; - - hMgr = (PMANAGER_HANDLE)hSCManager; - if (hMgr->Handle.Tag != MANAGER_TAG) - return ERROR_INVALID_HANDLE; - - if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess, - SC_MANAGER_LOCK)) - return ERROR_ACCESS_DENIED; - - /* FIXME: Lock the database */ - *hLock = 0x12345678; /* Dummy! */ - - return ERROR_SUCCESS; -} - - -/* Function 4 */ -unsigned long -ScmrQueryServiceObjectSecurity(handle_t BindingHandle) -{ - DPRINT1("ScmrQueryServiceSecurity() is unimplemented\n"); - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -/* Function 5 */ -unsigned long -ScmrSetServiceObjectSecurity(handle_t BindingHandle) -{ - DPRINT1("ScmrSetServiceSecurity() is unimplemented\n"); - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -/* Function 6 */ -unsigned long -ScmrQueryServiceStatus(handle_t BindingHandle, - unsigned int hService, - LPSERVICE_STATUS lpServiceStatus) -{ - PSERVICE_HANDLE hSvc; - PSERVICE lpService; - - DPRINT("ScmrQueryServiceStatus() called\n"); - - hSvc = (PSERVICE_HANDLE)hService; - if (hSvc->Handle.Tag != SERVICE_TAG) - { - DPRINT1("Invalid handle tag!\n"); - return ERROR_INVALID_HANDLE; - } - - if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, - SERVICE_QUERY_STATUS)) - { - DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); - return ERROR_ACCESS_DENIED; - } - - lpService = hSvc->ServiceEntry; - if (lpService == NULL) - { - DPRINT1("lpService == NULL!\n"); - return ERROR_INVALID_HANDLE; - } - - /* Return service status information */ - lpServiceStatus->dwServiceType = lpService->Type; - lpServiceStatus->dwCurrentState = lpService->CurrentState; - lpServiceStatus->dwControlsAccepted = lpService->ControlsAccepted; - lpServiceStatus->dwWin32ExitCode = lpService->Win32ExitCode; - lpServiceStatus->dwServiceSpecificExitCode = lpService->ServiceSpecificExitCode; - lpServiceStatus->dwCheckPoint = lpService->CheckPoint; - lpServiceStatus->dwWaitHint = lpService->WaitHint; - - return ERROR_SUCCESS; -} - - -/* Function 7 */ -unsigned long -ScmrSetServiceStatus(handle_t BindingHandle) -{ - DPRINT1("ScmrSetServiceStatus() is unimplemented\n"); - /* FIXME */ - return ERROR_CALL_NOT_IMPLEMENTED; -} - - -/* Function 8 */ -unsigned long -ScmrUnlockServiceDatabase(handle_t BindingHandle, - unsigned int hLock) -{ - DPRINT1("ScmrUnlockServiceDatabase() called\n"); - /* FIXME */ - return ERROR_SUCCESS; -} - - -/* Function 9 */ -unsigned long -ScmrNotifyBootConfigStatus(handle_t BindingHandle, - unsigned long BootAcceptable) -{ - DPRINT1("ScmrNotifyBootConfigStatus() called\n"); - /* FIXME */ - return ERROR_SUCCESS; -} - - - -/* Function 12 */ -#if 0 -unsigned long -ScmrCreateServiceW(handle_t BindingHandle, - unsigned int hSCManager, - wchar_t *lpServiceName, - wchar_t *lpDisplayName, - unsigned long dwDesiredAccess, - unsigned long dwServiceType, - unsigned long dwStartType, - unsigned long dwErrorControl, - wchar_t *lpBinaryPathName, - wchar_t *lpLoadOrderGroup, - unsigned long *lpdwTagId, - wchar_t *lpDependencies, - wchar_t *lpServiceStartName, - wchar_t *lpPassword) -{ - DPRINT1("ScmrCreateServiceW() called\n"); - if (lpdwTagId != NULL) - *lpdwTagId = 0; - return ERROR_SUCCESS; -} -#endif - - -/* Function 15 */ -unsigned long -ScmrOpenSCManagerW(handle_t BindingHandle, - wchar_t *lpMachineName, - wchar_t *lpDatabaseName, - unsigned long dwDesiredAccess, - unsigned int *hScm) -{ - DWORD dwError; - SC_HANDLE hHandle; - - DPRINT("ScmrOpenSCManagerW() called\n"); - DPRINT("lpMachineName = %p\n", lpMachineName); - DPRINT("lpMachineName: %S\n", lpMachineName); - DPRINT("lpDataBaseName = %p\n", lpDatabaseName); - DPRINT("lpDataBaseName: %S\n", lpDatabaseName); - DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess); - - dwError = ScmCreateManagerHandle(lpDatabaseName, - &hHandle); - if (dwError != ERROR_SUCCESS) - { - DPRINT1("ScmCreateManagerHandle() failed (Error %lu)\n", dwError); - return dwError; - } - - /* Check the desired access */ - dwError = ScmCheckAccess(hHandle, - dwDesiredAccess | SC_MANAGER_CONNECT); - if (dwError != ERROR_SUCCESS) - { - DPRINT1("ScmCheckAccess() failed (Error %lu)\n", dwError); - HeapFree(GetProcessHeap(), 0, hHandle); - return dwError; - } - - *hScm = (unsigned int)hHandle; - DPRINT("*hScm = %x\n", *hScm); - - DPRINT("ScmrOpenSCManagerW() done\n"); - - return ERROR_SUCCESS; -} - - -/* Function 16 */ -unsigned int -ScmrOpenServiceW(handle_t BindingHandle, - unsigned int hSCManager, - wchar_t *lpServiceName, - unsigned long dwDesiredAccess, - unsigned int *hService) -{ - UNICODE_STRING ServiceName; - PSERVICE lpService; - PMANAGER_HANDLE hManager; - SC_HANDLE hHandle; - DWORD dwError; - - DPRINT("ScmrOpenServiceW() called\n"); - DPRINT("hSCManager = %x\n", hSCManager); - DPRINT("lpServiceName = %p\n", lpServiceName); - DPRINT("lpServiceName: %S\n", lpServiceName); - DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess); - - hManager = (PMANAGER_HANDLE)hSCManager; - if (hManager->Handle.Tag != MANAGER_TAG) - { - DPRINT1("Invalid manager handle!\n"); - return ERROR_INVALID_HANDLE; - } - - /* FIXME: Lock the service list */ - - /* Get service database entry */ - RtlInitUnicodeString(&ServiceName, - lpServiceName); - - lpService = ScmGetServiceEntryByName(&ServiceName); - if (lpService == NULL) - { - DPRINT1("Could not find a service!\n"); - return ERROR_SERVICE_DOES_NOT_EXIST; - } - - /* Create a service handle */ - dwError = ScmCreateServiceHandle(lpService, - &hHandle); - if (dwError != ERROR_SUCCESS) - { - DPRINT1("ScmCreateServiceHandle() failed (Error %lu)\n", dwError); - return dwError; - } - - /* Check the desired access */ - dwError = ScmCheckAccess(hHandle, - dwDesiredAccess); - if (dwError != ERROR_SUCCESS) - { - DPRINT1("ScmCheckAccess() failed (Error %lu)\n", dwError); - HeapFree(GetProcessHeap(), 0, hHandle); - return dwError; - } - - *hService = (unsigned int)hHandle; - DPRINT("*hService = %x\n", *hService); - - DPRINT("ScmrOpenServiceW() done\n"); - - return ERROR_SUCCESS; -} - - - -/* Function 27 */ -unsigned long -ScmrOpenSCManagerA(handle_t BindingHandle, - char *lpMachineName, - char *lpDatabaseName, - unsigned long dwDesiredAccess, - unsigned int *hScm) -{ - UNICODE_STRING MachineName; - UNICODE_STRING DatabaseName; - DWORD dwError; - - DPRINT("ScmrOpenSCManagerA() called\n"); - - if (lpMachineName) - RtlCreateUnicodeStringFromAsciiz(&MachineName, - lpMachineName); - - if (lpDatabaseName) - RtlCreateUnicodeStringFromAsciiz(&DatabaseName, - lpDatabaseName); - - dwError = ScmrOpenSCManagerW(BindingHandle, - lpMachineName ? MachineName.Buffer : NULL, - lpDatabaseName ? DatabaseName.Buffer : NULL, - dwDesiredAccess, - hScm); - - if (lpMachineName) - RtlFreeUnicodeString(&MachineName); - - if (lpDatabaseName) - RtlFreeUnicodeString(&DatabaseName); - - return dwError; -} - - -/* Function 28 */ -unsigned int -ScmrOpenServiceA(handle_t BindingHandle, - unsigned int hSCManager, - char *lpServiceName, - unsigned long dwDesiredAccess, - unsigned int *hService) -{ - UNICODE_STRING ServiceName; - DWORD dwError; - - DPRINT("ScmrOpenServiceA() called\n"); - - RtlCreateUnicodeStringFromAsciiz(&ServiceName, - lpServiceName); - - dwError = ScmrOpenServiceW(BindingHandle, - hSCManager, - ServiceName.Buffer, - dwDesiredAccess, - hService); - - RtlFreeUnicodeString(&ServiceName); - - return dwError; -} - - - -void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len) -{ - return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len); -} - - -void __RPC_USER midl_user_free(void __RPC_FAR * ptr) -{ - HeapFree(GetProcessHeap(), 0, ptr); -} - -/* EOF */ +/* + + */ + +/* INCLUDES ****************************************************************/ + +#include "services.h" +#include "svcctl_s.h" + +#define NDEBUG +#include <debug.h> + + +/* GLOBALS *****************************************************************/ + +#define MANAGER_TAG 0x72674D68 /* 'hMgr' */ +#define SERVICE_TAG 0x63765368 /* 'hSvc' */ + +typedef struct _SCMGR_HANDLE +{ + DWORD Tag; + DWORD RefCount; + DWORD DesiredAccess; +} SCMGR_HANDLE; + + +typedef struct _MANAGER_HANDLE +{ + SCMGR_HANDLE Handle; + + /* FIXME: Insert more data here */ + + WCHAR DatabaseName[1]; +} MANAGER_HANDLE, *PMANAGER_HANDLE; + + +typedef struct _SERVICE_HANDLE +{ + SCMGR_HANDLE Handle; + + DWORD DesiredAccess; + PSERVICE ServiceEntry; + + /* FIXME: Insert more data here */ + +} SERVICE_HANDLE, *PSERVICE_HANDLE; + + +#define SC_MANAGER_READ \ + (STANDARD_RIGHTS_READ | \ + SC_MANAGER_QUERY_LOCK_STATUS | \ + SC_MANAGER_ENUMERATE_SERVICE) + +#define SC_MANAGER_WRITE \ + (STANDARD_RIGHTS_WRITE | \ + SC_MANAGER_MODIFY_BOOT_CONFIG | \ + SC_MANAGER_CREATE_SERVICE) + +#define SC_MANAGER_EXECUTE \ + (STANDARD_RIGHTS_EXECUTE | \ + SC_MANAGER_LOCK | \ + SC_MANAGER_ENUMERATE_SERVICE | \ + SC_MANAGER_CONNECT | \ + SC_MANAGER_CREATE_SERVICE) + + +#define SERVICE_READ \ + (STANDARD_RIGHTS_READ | \ + SERVICE_INTERROGATE | \ + SERVICE_ENUMERATE_DEPENDENTS | \ + SERVICE_QUERY_STATUS | \ + SERVICE_QUERY_CONFIG) + +#define SERVICE_WRITE \ + (STANDARD_RIGHTS_WRITE | \ + SERVICE_CHANGE_CONFIG) + +#define SERVICE_EXECUTE \ + (STANDARD_RIGHTS_EXECUTE | \ + SERVICE_USER_DEFINED_CONTROL | \ + SERVICE_PAUSE_CONTINUE | \ + SERVICE_STOP | \ + SERVICE_START) + + +/* VARIABLES ***************************************************************/ + +static GENERIC_MAPPING +ScmManagerMapping = {SC_MANAGER_READ, + SC_MANAGER_WRITE, + SC_MANAGER_EXECUTE, + SC_MANAGER_ALL_ACCESS}; + +static GENERIC_MAPPING +ScmServiceMapping = {SERVICE_READ, + SERVICE_WRITE, + SERVICE_EXECUTE, + SC_MANAGER_ALL_ACCESS}; + + +/* FUNCTIONS ***************************************************************/ + +VOID +ScmStartRpcServer(VOID) +{ + RPC_STATUS Status; + + DPRINT("ScmStartRpcServer() called"); + + Status = RpcServerUseProtseqEp(L"ncacn_np", + 10, + L"\\pipe\\ntsvcs", + NULL); + if (Status != RPC_S_OK) + { + DPRINT1("RpcServerUseProtseqEp() failed (Status %lx)\n", Status); + return; + } + + Status = RpcServerRegisterIf(svcctl_ServerIfHandle, + NULL, + NULL); + if (Status != RPC_S_OK) + { + DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status); + return; + } + + Status = RpcServerListen(1, 20, TRUE); + if (Status != RPC_S_OK) + { + DPRINT1("RpcServerListen() failed (Status %lx)\n", Status); + return; + } + + DPRINT("ScmStartRpcServer() done"); +} + + +static DWORD +ScmCreateManagerHandle(LPWSTR lpDatabaseName, + SC_HANDLE *Handle) +{ + PMANAGER_HANDLE Ptr; + + if (lpDatabaseName == NULL) + lpDatabaseName = SERVICES_ACTIVE_DATABASEW; + + Ptr = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(MANAGER_HANDLE) + wcslen(lpDatabaseName) * sizeof(WCHAR)); + if (Ptr == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + Ptr->Handle.Tag = MANAGER_TAG; + Ptr->Handle.RefCount = 1; + + /* FIXME: initialize more data here */ + + wcscpy(Ptr->DatabaseName, lpDatabaseName); + + *Handle = (SC_HANDLE)Ptr; + + return ERROR_SUCCESS; +} + + +static DWORD +ScmCreateServiceHandle(PSERVICE lpServiceEntry, + SC_HANDLE *Handle) +{ + PSERVICE_HANDLE Ptr; + + Ptr = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(SERVICE_HANDLE)); + if (Ptr == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + Ptr->Handle.Tag = SERVICE_TAG; + Ptr->Handle.RefCount = 1; + + /* FIXME: initialize more data here */ + Ptr->ServiceEntry = lpServiceEntry; + + *Handle = (SC_HANDLE)Ptr; + + return ERROR_SUCCESS; +} + + +static DWORD +ScmCheckAccess(SC_HANDLE Handle, + DWORD dwDesiredAccess) +{ + PMANAGER_HANDLE hMgr; + + hMgr = (PMANAGER_HANDLE)Handle; + if (hMgr->Handle.Tag == MANAGER_TAG) + { + RtlMapGenericMask(&dwDesiredAccess, + &ScmManagerMapping); + + hMgr->Handle.DesiredAccess = dwDesiredAccess; + + return ERROR_SUCCESS; + } + else if (hMgr->Handle.Tag == SERVICE_TAG) + { + RtlMapGenericMask(&dwDesiredAccess, + &ScmServiceMapping); + + hMgr->Handle.DesiredAccess = dwDesiredAccess; + + return ERROR_SUCCESS; + } + + return ERROR_INVALID_HANDLE; +} + + +/* Function 0 */ +unsigned long +ScmrCloseServiceHandle(handle_t BindingHandle, + unsigned int hScObject) +{ + PMANAGER_HANDLE hManager; + + DPRINT("ScmrCloseServiceHandle() called\n"); + + DPRINT("hScObject = %X\n", hScObject); + + if (hScObject == 0) + return ERROR_INVALID_HANDLE; + + hManager = (PMANAGER_HANDLE)hScObject; + if (hManager->Handle.Tag == MANAGER_TAG) + { + DPRINT("Found manager handle\n"); + + hManager->Handle.RefCount--; + if (hManager->Handle.RefCount == 0) + { + /* FIXME: add cleanup code */ + + HeapFree(GetProcessHeap(), 0, hManager); + } + + DPRINT("ScmrCloseServiceHandle() done\n"); + return ERROR_SUCCESS; + } + else if (hManager->Handle.Tag == SERVICE_TAG) + { + DPRINT("Found service handle\n"); + + hManager->Handle.RefCount--; + if (hManager->Handle.RefCount == 0) + { + /* FIXME: add cleanup code */ + + HeapFree(GetProcessHeap(), 0, hManager); + } + + DPRINT("ScmrCloseServiceHandle() done\n"); + return ERROR_SUCCESS; + } + + DPRINT1("Invalid handle tag (Tag %lx)\n", hManager->Handle.Tag); + + return ERROR_INVALID_HANDLE; +} + + +/* Function 1 */ +unsigned long +ScmrControlService(handle_t BindingHandle, + unsigned int hService, + unsigned long dwControl, + LPSERVICE_STATUS lpServiceStatus) +{ + PSERVICE_HANDLE hSvc; + PSERVICE lpService; + + DPRINT1("ScmrControlService() called\n"); + + hSvc = (PSERVICE_HANDLE)hService; + if (hSvc->Handle.Tag != SERVICE_TAG) + { + DPRINT1("Invalid handle tag!\n"); + return ERROR_INVALID_HANDLE; + } + + + /* FIXME: Check access rights */ + + + lpService = hSvc->ServiceEntry; + if (lpService == NULL) + { + DPRINT1("lpService == NULL!\n"); + return ERROR_INVALID_HANDLE; + } + + + /* FIXME: Send control code to the service */ + + + /* Return service status information */ + lpServiceStatus->dwServiceType = lpService->Type; + lpServiceStatus->dwCurrentState = lpService->CurrentState; + lpServiceStatus->dwControlsAccepted = lpService->ControlsAccepted; + lpServiceStatus->dwWin32ExitCode = lpService->Win32ExitCode; + lpServiceStatus->dwServiceSpecificExitCode = lpService->ServiceSpecificExitCode; + lpServiceStatus->dwCheckPoint = lpService->CheckPoint; + lpServiceStatus->dwWaitHint = lpService->WaitHint; + + return ERROR_SUCCESS; +} + + +/* Function 2 */ +unsigned long +ScmrDeleteService(handle_t BindingHandle, + unsigned int hService) +{ + PSERVICE_HANDLE hSvc; + PSERVICE lpService; + + DPRINT1("ScmrDeleteService() called\n"); + + hSvc = (PSERVICE_HANDLE)hService; + if (hSvc->Handle.Tag != SERVICE_TAG) + return ERROR_INVALID_HANDLE; + + if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, + STANDARD_RIGHTS_REQUIRED)) + return ERROR_ACCESS_DENIED; + + lpService = hSvc->ServiceEntry; + if (lpService == NULL) + { + DPRINT1("lpService == NULL!\n"); + return ERROR_INVALID_HANDLE; + } + + /* FIXME: Mark service for delete */ + + return ERROR_SUCCESS; +} + + +/* Function 3 */ +unsigned long +ScmrLockServiceDatabase(handle_t BindingHandle, + unsigned int hSCManager, + unsigned int *hLock) +{ + PMANAGER_HANDLE hMgr; + + DPRINT("ScmrLockServiceDatabase() called\n"); + + *hLock = 0; + + hMgr = (PMANAGER_HANDLE)hSCManager; + if (hMgr->Handle.Tag != MANAGER_TAG) + return ERROR_INVALID_HANDLE; + + if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess, + SC_MANAGER_LOCK)) + return ERROR_ACCESS_DENIED; + + /* FIXME: Lock the database */ + *hLock = 0x12345678; /* Dummy! */ + + return ERROR_SUCCESS; +} + + +/* Function 4 */ +unsigned long +ScmrQueryServiceObjectSecurity(handle_t BindingHandle) +{ + DPRINT1("ScmrQueryServiceSecurity() is unimplemented\n"); + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/* Function 5 */ +unsigned long +ScmrSetServiceObjectSecurity(handle_t BindingHandle) +{ + DPRINT1("ScmrSetServiceSecurity() is unimplemented\n"); + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/* Function 6 */ +unsigned long +ScmrQueryServiceStatus(handle_t BindingHandle, + unsigned int hService, + LPSERVICE_STATUS lpServiceStatus) +{ + PSERVICE_HANDLE hSvc; + PSERVICE lpService; + + DPRINT("ScmrQueryServiceStatus() called\n"); + + hSvc = (PSERVICE_HANDLE)hService; + if (hSvc->Handle.Tag != SERVICE_TAG) + { + DPRINT1("Invalid handle tag!\n"); + return ERROR_INVALID_HANDLE; + } + + if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, + SERVICE_QUERY_STATUS)) + { + DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + lpService = hSvc->ServiceEntry; + if (lpService == NULL) + { + DPRINT1("lpService == NULL!\n"); + return ERROR_INVALID_HANDLE; + } + + /* Return service status information */ + lpServiceStatus->dwServiceType = lpService->Type; + lpServiceStatus->dwCurrentState = lpService->CurrentState; + lpServiceStatus->dwControlsAccepted = lpService->ControlsAccepted; + lpServiceStatus->dwWin32ExitCode = lpService->Win32ExitCode; + lpServiceStatus->dwServiceSpecificExitCode = lpService->ServiceSpecificExitCode; + lpServiceStatus->dwCheckPoint = lpService->CheckPoint; + lpServiceStatus->dwWaitHint = lpService->WaitHint; + + return ERROR_SUCCESS; +} + + +/* Function 7 */ +unsigned long +ScmrSetServiceStatus(handle_t BindingHandle) +{ + DPRINT1("ScmrSetServiceStatus() is unimplemented\n"); + /* FIXME */ + return ERROR_CALL_NOT_IMPLEMENTED; +} + + +/* Function 8 */ +unsigned long +ScmrUnlockServiceDatabase(handle_t BindingHandle, + unsigned int hLock) +{ + DPRINT1("ScmrUnlockServiceDatabase() called\n"); + /* FIXME */ + return ERROR_SUCCESS; +} + + +/* Function 9 */ +unsigned long +ScmrNotifyBootConfigStatus(handle_t BindingHandle, + unsigned long BootAcceptable) +{ + DPRINT1("ScmrNotifyBootConfigStatus() called\n"); + /* FIXME */ + return ERROR_SUCCESS; +} + + + +/* Function 12 */ +#if 0 +unsigned long +ScmrCreateServiceW(handle_t BindingHandle, + unsigned int hSCManager, + wchar_t *lpServiceName, + wchar_t *lpDisplayName, + unsigned long dwDesiredAccess, + unsigned long dwServiceType, + unsigned long dwStartType, + unsigned long dwErrorControl, + wchar_t *lpBinaryPathName, + wchar_t *lpLoadOrderGroup, + unsigned long *lpdwTagId, + wchar_t *lpDependencies, + wchar_t *lpServiceStartName, + wchar_t *lpPassword) +{ + DPRINT1("ScmrCreateServiceW() called\n"); + if (lpdwTagId != NULL) + *lpdwTagId = 0; + return ERROR_SUCCESS; +} +#endif + + +/* Function 15 */ +unsigned long +ScmrOpenSCManagerW(handle_t BindingHandle, + wchar_t *lpMachineName, + wchar_t *lpDatabaseName, + unsigned long dwDesiredAccess, + unsigned int *hScm) +{ + DWORD dwError; + SC_HANDLE hHandle; + + DPRINT("ScmrOpenSCManagerW() called\n"); + DPRINT("lpMachineName = %p\n", lpMachineName); + DPRINT("lpMachineName: %S\n", lpMachineName); + DPRINT("lpDataBaseName = %p\n", lpDatabaseName); + DPRINT("lpDataBaseName: %S\n", lpDatabaseName); + DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess); + + dwError = ScmCreateManagerHandle(lpDatabaseName, + &hHandle); + if (dwError != ERROR_SUCCESS) + { + DPRINT1("ScmCreateManagerHandle() failed (Error %lu)\n", dwError); + return dwError; + } + + /* Check the desired access */ + dwError = ScmCheckAccess(hHandle, + dwDesiredAccess | SC_MANAGER_CONNECT); + if (dwError != ERROR_SUCCESS) + { + DPRINT1("ScmCheckAccess() failed (Error %lu)\n", dwError); + HeapFree(GetProcessHeap(), 0, hHandle); + return dwError; + } + + *hScm = (unsigned int)hHandle; + DPRINT("*hScm = %x\n", *hScm); + + DPRINT("ScmrOpenSCManagerW() done\n"); + + return ERROR_SUCCESS; +} + + +/* Function 16 */ +unsigned int +ScmrOpenServiceW(handle_t BindingHandle, + unsigned int hSCManager, + wchar_t *lpServiceName, + unsigned long dwDesiredAccess, + unsigned int *hService) +{ + UNICODE_STRING ServiceName; + PSERVICE lpService; + PMANAGER_HANDLE hManager; + SC_HANDLE hHandle; + DWORD dwError; + + DPRINT("ScmrOpenServiceW() called\n"); + DPRINT("hSCManager = %x\n", hSCManager); + DPRINT("lpServiceName = %p\n", lpServiceName); + DPRINT("lpServiceName: %S\n", lpServiceName); + DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess); + + hManager = (PMANAGER_HANDLE)hSCManager; + if (hManager->Handle.Tag != MANAGER_TAG) + { + DPRINT1("Invalid manager handle!\n"); + return ERROR_INVALID_HANDLE; + } + + /* FIXME: Lock the service list */ + + /* Get service database entry */ + RtlInitUnicodeString(&ServiceName, + lpServiceName); + + lpService = ScmGetServiceEntryByName(&ServiceName); + if (lpService == NULL) + { + DPRINT1("Could not find a service!\n"); + return ERROR_SERVICE_DOES_NOT_EXIST; + } + + /* Create a service handle */ + dwError = ScmCreateServiceHandle(lpService, + &hHandle); + if (dwError != ERROR_SUCCESS) + { + DPRINT1("ScmCreateServiceHandle() failed (Error %lu)\n", dwError); + return dwError; + } + + /* Check the desired access */ + dwError = ScmCheckAccess(hHandle, + dwDesiredAccess); + if (dwError != ERROR_SUCCESS) + { + DPRINT1("ScmCheckAccess() failed (Error %lu)\n", dwError); + HeapFree(GetProcessHeap(), 0, hHandle); + return dwError; + } + + *hService = (unsigned int)hHandle; + DPRINT("*hService = %x\n", *hService); + + DPRINT("ScmrOpenServiceW() done\n"); + + return ERROR_SUCCESS; +} + + + +/* Function 27 */ +unsigned long +ScmrOpenSCManagerA(handle_t BindingHandle, + char *lpMachineName, + char *lpDatabaseName, + unsigned long dwDesiredAccess, + unsigned int *hScm) +{ + UNICODE_STRING MachineName; + UNICODE_STRING DatabaseName; + DWORD dwError; + + DPRINT("ScmrOpenSCManagerA() called\n"); + + if (lpMachineName) + RtlCreateUnicodeStringFromAsciiz(&MachineName, + lpMachineName); + + if (lpDatabaseName) + RtlCreateUnicodeStringFromAsciiz(&DatabaseName, + lpDatabaseName); + + dwError = ScmrOpenSCManagerW(BindingHandle, + lpMachineName ? MachineName.Buffer : NULL, + lpDatabaseName ? DatabaseName.Buffer : NULL, + dwDesiredAccess, + hScm); + + if (lpMachineName) + RtlFreeUnicodeString(&MachineName); + + if (lpDatabaseName) + RtlFreeUnicodeString(&DatabaseName); + + return dwError; +} + + +/* Function 28 */ +unsigned int +ScmrOpenServiceA(handle_t BindingHandle, + unsigned int hSCManager, + char *lpServiceName, + unsigned long dwDesiredAccess, + unsigned int *hService) +{ + UNICODE_STRING ServiceName; + DWORD dwError; + + DPRINT("ScmrOpenServiceA() called\n"); + + RtlCreateUnicodeStringFromAsciiz(&ServiceName, + lpServiceName); + + dwError = ScmrOpenServiceW(BindingHandle, + hSCManager, + ServiceName.Buffer, + dwDesiredAccess, + hService); + + RtlFreeUnicodeString(&ServiceName); + + return dwError; +} + + + +void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len) +{ + return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len); +} + + +void __RPC_USER midl_user_free(void __RPC_FAR * ptr) +{ + HeapFree(GetProcessHeap(), 0, ptr); +} + +/* EOF */ diff --git a/reactos/subsys/system/sm/resource.h b/reactos/subsys/system/sm/resource.h index 382cf52f9d7..81630929f67 100644 --- a/reactos/subsys/system/sm/resource.h +++ b/reactos/subsys/system/sm/resource.h @@ -1,27 +1,27 @@ - - - -#define RC_STRING_MAX_SIZE 200 -#define IDS_boot 100 -#define IDS_help 101 -#define IDS_info 102 -#define IDS_reboot 103 -#define IDS_shutdown 104 -#define IDS_boot_msg 205 -#define IDS_help_msg 206 -#define IDS_info_msg 207 -#define IDS_reboot_msg 208 -#define IDS_shutdown_msg 209 - -#define IDS_Unknown 300 -#define IDS_Not_Imp 301 -#define IDS_ID 302 -#define IDS_SM2 303 -#define IDS_SM1 304 -#define IDS_Status 305 -#define IDS_Mangers 306 -#define IDS_USING 307 -#define IDS_FAILS_MNG 308 - - -/* EOF */ + + + +#define RC_STRING_MAX_SIZE 200 +#define IDS_boot 100 +#define IDS_help 101 +#define IDS_info 102 +#define IDS_reboot 103 +#define IDS_shutdown 104 +#define IDS_boot_msg 205 +#define IDS_help_msg 206 +#define IDS_info_msg 207 +#define IDS_reboot_msg 208 +#define IDS_shutdown_msg 209 + +#define IDS_Unknown 300 +#define IDS_Not_Imp 301 +#define IDS_ID 302 +#define IDS_SM2 303 +#define IDS_SM1 304 +#define IDS_Status 305 +#define IDS_Mangers 306 +#define IDS_USING 307 +#define IDS_FAILS_MNG 308 + + +/* EOF */ diff --git a/reactos/subsys/system/sm/sm.c b/reactos/subsys/system/sm/sm.c index 54b71bb2578..1238763497b 100644 --- a/reactos/subsys/system/sm/sm.c +++ b/reactos/subsys/system/sm/sm.c @@ -1,305 +1,305 @@ -/* - * ReactOS Win32 Applications - * Copyright (C) 2005 ReactOS Team - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -/* $Id$ - * - * COPYRIGHT : See COPYING in the top level directory - * PROJECT : ReactOS/Win32 Session Manager Control Tool - * FILE : subsys/system/sm/sm.c - * PROGRAMMER: Emanuele Aliberti (ea@reactos.com) - */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <tchar.h> -#include "resource.h" - -#include <windows.h> -#define NTOS_MODE_USER -#include <ndk/ntndk.h> - -#include <sm/helper.h> - -#define SM_CMD(n) cmd_##n -#define SM_CMD_DECL(n) int SM_CMD(n)(int argc, char * argv[]) -#define SM_CMD_CALL(n,c,v) SM_CMD(n)((c),(v)) - -HANDLE hSmApiPort = (HANDLE) 0; - -typedef struct _SM_CMD_DESCRIPTOR -{ - TCHAR Name[RC_STRING_MAX_SIZE]; - int (*EntryPoint)(int,TCHAR**); - TCHAR Synopsis[RC_STRING_MAX_SIZE]; - TCHAR Description[RC_STRING_MAX_SIZE]; - -} SM_CMD_DESCRIPTOR, *PSM_CMD_DESCRIPTOR; - -SM_CMD_DECL(boot); -SM_CMD_DECL(help); -SM_CMD_DECL(info); -SM_CMD_DECL(reboot); -SM_CMD_DECL(shutdown); - -/* internal commands directory */ -SM_CMD_DESCRIPTOR Command [] = -{ - {"boot", SM_CMD(boot), _T("boot subsystem_name"), _T("bootstrap an optional environment subsystem;")}, - {"help", SM_CMD(help), _T("help [command]"), _T("print help for command;")}, - {"info", SM_CMD(info), _T("info [subsystem_id]"), _T("print information about a booted subsystem\n" - "if subsystem_id is omitted, a list of booted\n" - "environment subsystems is printed.")}, - {"reboot", SM_CMD(reboot), _T("reboot subsystem_id"), _T("reboot an optional environment subsystem;")}, - {"shutdown", SM_CMD(shutdown), _T("shutdown subsystem_id"), _T("shutdown an optional environment subsystem;")}, -}; - -TCHAR UsageMessage[RC_STRING_MAX_SIZE]; -void loadlang(PSM_CMD_DESCRIPTOR ); - -PSM_CMD_DESCRIPTOR LookupCommand (const TCHAR * CommandName) -{ - int i; - const int command_count = (sizeof Command / sizeof Command[0]); - - /* parse the command... */ - - for (i=0; (i < command_count); i ++) - { - if (0 == _tcscmp(CommandName, Command[i].Name)) - { - break; - } - } - if (i == command_count) - { - LoadString( GetModuleHandle(NULL), IDS_Unknown, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); - - _ftprintf(stderr, _T("%s '%s'.\n"), UsageMessage, CommandName); - return NULL; - } - return & Command [i]; -} - -/* user commands */ - -SM_CMD_DECL(boot) -{ - int rc = EXIT_SUCCESS; - ANSI_STRING ProgramA; - UNICODE_STRING ProgramW; - NTSTATUS Status = STATUS_SUCCESS; - - if (3 == argc) - { -#ifndef _UNICODE - RtlInitAnsiString (& ProgramA, argv[2]); - RtlAnsiStringToUnicodeString (& ProgramW, & ProgramA, TRUE); - Status = SmExecuteProgram (hSmApiPort, & ProgramW); - RtlFreeUnicodeString (& ProgramW); -#else - ProgramW = &argv[2]; - Status = SmExecuteProgram (hSmApiPort, & ProgramW); -#endif - if (STATUS_SUCCESS != Status) - { - LoadString( GetModuleHandle(NULL), IDS_Status, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); - - _tprintf(UsageMessage, Status); - } - - } - else - { - argv[2]=_T("boot"); - return SM_CMD_CALL(help,3,argv); - } - return rc; -} - -SM_CMD_DECL(help) -{ - unsigned int i = 0; - PSM_CMD_DESCRIPTOR cmd = NULL; - int rc = EXIT_SUCCESS; - - switch (argc) - { - case 2: - for (i=0; (i < (sizeof Command / sizeof Command[0])); i ++) - { - _tprintf(_T("%s\n"), Command[i].Synopsis); - } - break; - case 3: - cmd = LookupCommand (argv[2]); - if (NULL == cmd) - { - rc = EXIT_FAILURE; - break; - } - _tprintf(_T("%s\n%s\n\n%s\n"), - cmd->Name, - cmd->Synopsis, - cmd->Description); - break; - } - return rc; -} - -SM_CMD_DECL(info) -{ - int rc = EXIT_SUCCESS; - NTSTATUS Status = STATUS_SUCCESS; - SM_INFORMATION_CLASS InformationClass = SmBasicInformation; - union { - SM_BASIC_INFORMATION bi; - SM_SUBSYSTEM_INFORMATION ssi; - } Info; - ULONG DataLength = 0; - ULONG ReturnDataLength = 0; - INT i = 0; - - RtlZeroMemory (& Info, sizeof Info); - switch (argc) - { - case 2: /* sm info */ - InformationClass = SmBasicInformation; - DataLength = sizeof Info.bi; - break; - case 3: /* sm info id */ - InformationClass = SmSubSystemInformation; - DataLength = sizeof Info.ssi; - Info.ssi.SubSystemId = atol(argv[2]); - break; - default: - return EXIT_FAILURE; - break; - } - Status = SmQueryInformation (hSmApiPort, - InformationClass, - & Info, - DataLength, - & ReturnDataLength); - if (STATUS_SUCCESS != Status) - { - LoadString( GetModuleHandle(NULL), IDS_Status, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); - _tprintf(UsageMessage, Status); - return EXIT_FAILURE; - } - switch (argc) - { - case 2: - LoadString( GetModuleHandle(NULL), IDS_SM1, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); - _tprintf(UsageMessage); - - LoadString( GetModuleHandle(NULL), IDS_SM2, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); - for (i = 0; i < Info.bi.SubSystemCount; i ++) - { - _tprintf(UsageMessage, - Info.bi.SubSystem[i].Id, - Info.bi.SubSystem[i].ProcessId, - Info.bi.SubSystem[i].Flags); - } - break; - case 3: - LoadString( GetModuleHandle(NULL), IDS_ID, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); - - _tprintf (UsageMessage, Info.ssi.SubSystemId, Info.ssi.Flags, Info.ssi.ProcessId); - wprintf(L" NSRootNode: '%s'\n", Info.ssi.NameSpaceRootNode); - break; - default: - break; - } - return rc; -} - -SM_CMD_DECL(shutdown) -{ - int rc = EXIT_SUCCESS; - - LoadString( GetModuleHandle(NULL), IDS_Not_Imp, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); - - _ftprintf(stderr,UsageMessage); - return rc; -} - -SM_CMD_DECL(reboot) -{ - int rc = SM_CMD(shutdown)(argc,argv); - if(EXIT_SUCCESS == rc) - { - rc = SM_CMD(boot)(argc,argv); - } - return rc; -} - -/* print command's synopsys */ -int print_synopsys (int argc, TCHAR *argv[]) -{ - LoadString( GetModuleHandle(NULL), IDS_Mangers, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); - _ftprintf (stderr, UsageMessage); - - LoadString( GetModuleHandle(NULL), IDS_USING, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); - _tprintf (UsageMessage); - return EXIT_SUCCESS; -} - -/* parse and execute */ -int pande (int argc, TCHAR *argv[]) -{ - PSM_CMD_DESCRIPTOR Command = NULL; - NTSTATUS Status = STATUS_SUCCESS; - - /* Lookup the user command... */ - Command = LookupCommand (argv[1]); - if (NULL == Command) - { - return EXIT_FAILURE; - } - /* Connect to the SM in non-registering mode. */ - Status = SmConnectApiPort (0, 0, 0, & hSmApiPort); - if (STATUS_SUCCESS == Status) - { - /* ...and execute it */ - return Command->EntryPoint (argc, argv); - } - LoadString( GetModuleHandle(NULL), IDS_FAILS_MNG, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); - _ftprintf (stderr, UsageMessage, Status); - - return EXIT_FAILURE; -} - -void loadlang(PSM_CMD_DESCRIPTOR cmd) -{ - int i=0; - if (cmd==NULL) return; - for (i=0;i < 5; i++) - { - LoadString( GetModuleHandle(NULL), IDS_boot+i, (LPTSTR) &cmd->Synopsis[i],RC_STRING_MAX_SIZE); - } -} - -int _tmain (int argc, TCHAR *argv[]) -{ - loadlang(Command); - - return (1==argc) - ? print_synopsys (argc, argv) - : pande (argc, argv); -} -/* EOF */ +/* + * ReactOS Win32 Applications + * Copyright (C) 2005 ReactOS Team + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id$ + * + * COPYRIGHT : See COPYING in the top level directory + * PROJECT : ReactOS/Win32 Session Manager Control Tool + * FILE : subsys/system/sm/sm.c + * PROGRAMMER: Emanuele Aliberti (ea@reactos.com) + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <tchar.h> +#include "resource.h" + +#include <windows.h> +#define NTOS_MODE_USER +#include <ndk/ntndk.h> + +#include <sm/helper.h> + +#define SM_CMD(n) cmd_##n +#define SM_CMD_DECL(n) int SM_CMD(n)(int argc, char * argv[]) +#define SM_CMD_CALL(n,c,v) SM_CMD(n)((c),(v)) + +HANDLE hSmApiPort = (HANDLE) 0; + +typedef struct _SM_CMD_DESCRIPTOR +{ + TCHAR Name[RC_STRING_MAX_SIZE]; + int (*EntryPoint)(int,TCHAR**); + TCHAR Synopsis[RC_STRING_MAX_SIZE]; + TCHAR Description[RC_STRING_MAX_SIZE]; + +} SM_CMD_DESCRIPTOR, *PSM_CMD_DESCRIPTOR; + +SM_CMD_DECL(boot); +SM_CMD_DECL(help); +SM_CMD_DECL(info); +SM_CMD_DECL(reboot); +SM_CMD_DECL(shutdown); + +/* internal commands directory */ +SM_CMD_DESCRIPTOR Command [] = +{ + {"boot", SM_CMD(boot), _T("boot subsystem_name"), _T("bootstrap an optional environment subsystem;")}, + {"help", SM_CMD(help), _T("help [command]"), _T("print help for command;")}, + {"info", SM_CMD(info), _T("info [subsystem_id]"), _T("print information about a booted subsystem\n" + "if subsystem_id is omitted, a list of booted\n" + "environment subsystems is printed.")}, + {"reboot", SM_CMD(reboot), _T("reboot subsystem_id"), _T("reboot an optional environment subsystem;")}, + {"shutdown", SM_CMD(shutdown), _T("shutdown subsystem_id"), _T("shutdown an optional environment subsystem;")}, +}; + +TCHAR UsageMessage[RC_STRING_MAX_SIZE]; +void loadlang(PSM_CMD_DESCRIPTOR ); + +PSM_CMD_DESCRIPTOR LookupCommand (const TCHAR * CommandName) +{ + int i; + const int command_count = (sizeof Command / sizeof Command[0]); + + /* parse the command... */ + + for (i=0; (i < command_count); i ++) + { + if (0 == _tcscmp(CommandName, Command[i].Name)) + { + break; + } + } + if (i == command_count) + { + LoadString( GetModuleHandle(NULL), IDS_Unknown, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); + + _ftprintf(stderr, _T("%s '%s'.\n"), UsageMessage, CommandName); + return NULL; + } + return & Command [i]; +} + +/* user commands */ + +SM_CMD_DECL(boot) +{ + int rc = EXIT_SUCCESS; + ANSI_STRING ProgramA; + UNICODE_STRING ProgramW; + NTSTATUS Status = STATUS_SUCCESS; + + if (3 == argc) + { +#ifndef _UNICODE + RtlInitAnsiString (& ProgramA, argv[2]); + RtlAnsiStringToUnicodeString (& ProgramW, & ProgramA, TRUE); + Status = SmExecuteProgram (hSmApiPort, & ProgramW); + RtlFreeUnicodeString (& ProgramW); +#else + ProgramW = &argv[2]; + Status = SmExecuteProgram (hSmApiPort, & ProgramW); +#endif + if (STATUS_SUCCESS != Status) + { + LoadString( GetModuleHandle(NULL), IDS_Status, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); + + _tprintf(UsageMessage, Status); + } + + } + else + { + argv[2]=_T("boot"); + return SM_CMD_CALL(help,3,argv); + } + return rc; +} + +SM_CMD_DECL(help) +{ + unsigned int i = 0; + PSM_CMD_DESCRIPTOR cmd = NULL; + int rc = EXIT_SUCCESS; + + switch (argc) + { + case 2: + for (i=0; (i < (sizeof Command / sizeof Command[0])); i ++) + { + _tprintf(_T("%s\n"), Command[i].Synopsis); + } + break; + case 3: + cmd = LookupCommand (argv[2]); + if (NULL == cmd) + { + rc = EXIT_FAILURE; + break; + } + _tprintf(_T("%s\n%s\n\n%s\n"), + cmd->Name, + cmd->Synopsis, + cmd->Description); + break; + } + return rc; +} + +SM_CMD_DECL(info) +{ + int rc = EXIT_SUCCESS; + NTSTATUS Status = STATUS_SUCCESS; + SM_INFORMATION_CLASS InformationClass = SmBasicInformation; + union { + SM_BASIC_INFORMATION bi; + SM_SUBSYSTEM_INFORMATION ssi; + } Info; + ULONG DataLength = 0; + ULONG ReturnDataLength = 0; + INT i = 0; + + RtlZeroMemory (& Info, sizeof Info); + switch (argc) + { + case 2: /* sm info */ + InformationClass = SmBasicInformation; + DataLength = sizeof Info.bi; + break; + case 3: /* sm info id */ + InformationClass = SmSubSystemInformation; + DataLength = sizeof Info.ssi; + Info.ssi.SubSystemId = atol(argv[2]); + break; + default: + return EXIT_FAILURE; + break; + } + Status = SmQueryInformation (hSmApiPort, + InformationClass, + & Info, + DataLength, + & ReturnDataLength); + if (STATUS_SUCCESS != Status) + { + LoadString( GetModuleHandle(NULL), IDS_Status, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); + _tprintf(UsageMessage, Status); + return EXIT_FAILURE; + } + switch (argc) + { + case 2: + LoadString( GetModuleHandle(NULL), IDS_SM1, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); + _tprintf(UsageMessage); + + LoadString( GetModuleHandle(NULL), IDS_SM2, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); + for (i = 0; i < Info.bi.SubSystemCount; i ++) + { + _tprintf(UsageMessage, + Info.bi.SubSystem[i].Id, + Info.bi.SubSystem[i].ProcessId, + Info.bi.SubSystem[i].Flags); + } + break; + case 3: + LoadString( GetModuleHandle(NULL), IDS_ID, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); + + _tprintf (UsageMessage, Info.ssi.SubSystemId, Info.ssi.Flags, Info.ssi.ProcessId); + wprintf(L" NSRootNode: '%s'\n", Info.ssi.NameSpaceRootNode); + break; + default: + break; + } + return rc; +} + +SM_CMD_DECL(shutdown) +{ + int rc = EXIT_SUCCESS; + + LoadString( GetModuleHandle(NULL), IDS_Not_Imp, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); + + _ftprintf(stderr,UsageMessage); + return rc; +} + +SM_CMD_DECL(reboot) +{ + int rc = SM_CMD(shutdown)(argc,argv); + if(EXIT_SUCCESS == rc) + { + rc = SM_CMD(boot)(argc,argv); + } + return rc; +} + +/* print command's synopsys */ +int print_synopsys (int argc, TCHAR *argv[]) +{ + LoadString( GetModuleHandle(NULL), IDS_Mangers, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); + _ftprintf (stderr, UsageMessage); + + LoadString( GetModuleHandle(NULL), IDS_USING, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); + _tprintf (UsageMessage); + return EXIT_SUCCESS; +} + +/* parse and execute */ +int pande (int argc, TCHAR *argv[]) +{ + PSM_CMD_DESCRIPTOR Command = NULL; + NTSTATUS Status = STATUS_SUCCESS; + + /* Lookup the user command... */ + Command = LookupCommand (argv[1]); + if (NULL == Command) + { + return EXIT_FAILURE; + } + /* Connect to the SM in non-registering mode. */ + Status = SmConnectApiPort (0, 0, 0, & hSmApiPort); + if (STATUS_SUCCESS == Status) + { + /* ...and execute it */ + return Command->EntryPoint (argc, argv); + } + LoadString( GetModuleHandle(NULL), IDS_FAILS_MNG, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); + _ftprintf (stderr, UsageMessage, Status); + + return EXIT_FAILURE; +} + +void loadlang(PSM_CMD_DESCRIPTOR cmd) +{ + int i=0; + if (cmd==NULL) return; + for (i=0;i < 5; i++) + { + LoadString( GetModuleHandle(NULL), IDS_boot+i, (LPTSTR) &cmd->Synopsis[i],RC_STRING_MAX_SIZE); + } +} + +int _tmain (int argc, TCHAR *argv[]) +{ + loadlang(Command); + + return (1==argc) + ? print_synopsys (argc, argv) + : pande (argc, argv); +} +/* EOF */ diff --git a/reactos/subsys/system/userinit/resource.h b/reactos/subsys/system/userinit/resource.h index 66e54ef96e5..d19ca24ced2 100644 --- a/reactos/subsys/system/userinit/resource.h +++ b/reactos/subsys/system/userinit/resource.h @@ -1,12 +1,12 @@ -#define RC_STRING_MAX_SIZE 2048 -#define STRING_USERINIT_FAIL 100 - - - - - - - - - - +#define RC_STRING_MAX_SIZE 2048 +#define STRING_USERINIT_FAIL 100 + + + + + + + + + + diff --git a/reactos/subsys/win32k/eng/window.c b/reactos/subsys/win32k/eng/window.c index 370c0d02b71..2b13c486137 100644 --- a/reactos/subsys/win32k/eng/window.c +++ b/reactos/subsys/win32k/eng/window.c @@ -1,378 +1,378 @@ -/* - * ReactOS W32 Subsystem - * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 ReactOS Team - * - * 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., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -/* $Id$ - * - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * PURPOSE: GDI WNDOBJ Functions - * FILE: subsys/win32k/eng/window.c - * PROGRAMER: Gregor Anich - * REVISION HISTORY: - * 16/11/2004: Created - */ - -/* TODO: Check how the WNDOBJ implementation should behave with a driver on windows. */ - -#include <w32k.h> - -#define NDEBUG -#include <debug.h> - -/* - * Calls the WNDOBJCHANGEPROC of the given WNDOBJ - */ -VOID -FASTCALL -IntEngWndCallChangeProc( - IN WNDOBJ *pwo, - IN FLONG flChanged) -{ - WNDGDI *WndObjInt = ObjToGDI(pwo, WND); - - if (WndObjInt->ChangeProc == NULL) - { - return; - } - - /* check flags of the WNDOBJ */ - flChanged &= WndObjInt->Flags; - if (flChanged == 0) - { - return; - } - - /* Call the WNDOBJCHANGEPROC */ - if (flChanged == WOC_CHANGED) - { - pwo = NULL; - } - - DPRINT("Calling WNDOBJCHANGEPROC (0x%x), Changed = 0x%x\n", - WndObjInt->ChangeProc, flChanged); - WndObjInt->ChangeProc(pwo, flChanged); -} - -/* - * Fills the CLIPOBJ and client rect of the WNDOBJ with the data from the given WINDOW_OBJECT - */ -BOOLEAN -FASTCALL -IntEngWndUpdateClipObj( - WNDGDI *WndObjInt, - PWINDOW_OBJECT Window) -{ - HRGN hVisRgn; - PROSRGNDATA visRgn; - CLIPOBJ *ClipObj = NULL; - CLIPOBJ *OldClipObj; - - hVisRgn = VIS_ComputeVisibleRegion(Window, TRUE, TRUE, TRUE); - if (hVisRgn != NULL) - { - NtGdiOffsetRgn(hVisRgn, Window->ClientRect.left, Window->ClientRect.top); - visRgn = RGNDATA_LockRgn(hVisRgn); - if (visRgn != NULL) - { - if (visRgn->rdh.nCount > 0) - { - ClipObj = IntEngCreateClipRegion(visRgn->rdh.nCount, (PRECTL)visRgn->Buffer, - (PRECTL)&visRgn->rdh.rcBound); - DPRINT("Created visible region with %d rects\n", visRgn->rdh.nCount); - DPRINT(" BoundingRect: %d, %d %d, %d\n", - visRgn->rdh.rcBound.left, visRgn->rdh.rcBound.top, - visRgn->rdh.rcBound.right, visRgn->rdh.rcBound.bottom); - { - INT i; - for (i = 0; i < visRgn->rdh.nCount; i++) - { - DPRINT(" Rect #%d: %d,%d %d,%d\n", i+1, - visRgn->Buffer[i].left, visRgn->Buffer[i].top, - visRgn->Buffer[i].right, visRgn->Buffer[i].bottom); - } - } - } - RGNDATA_UnlockRgn(visRgn); - } - else - { - DPRINT1("Warning: Couldn't lock visible region of window DC\n"); - } - } - else - { - DPRINT1("Warning: VIS_ComputeVisibleRegion failed!\n"); - } - - if (ClipObj == NULL) - { - /* Fall back to client rect */ - ClipObj = IntEngCreateClipRegion(1, (PRECTL)&Window->ClientRect, - (PRECTL)&Window->ClientRect); - } - - if (ClipObj == NULL) - { - DPRINT1("Warning: IntEngCreateClipRegion() failed!\n"); - return FALSE; - } - - RtlCopyMemory(&WndObjInt->WndObj.coClient, ClipObj, sizeof (CLIPOBJ)); - RtlCopyMemory(&WndObjInt->WndObj.rclClient, &Window->ClientRect, sizeof (RECT)); - OldClipObj = InterlockedExchangePointer(&WndObjInt->ClientClipObj, ClipObj); - if (OldClipObj != NULL) - IntEngDeleteClipRegion(OldClipObj); - - return TRUE; -} - -/* - * Updates all WNDOBJs of the given WINDOW_OBJECT and calls the change-procs. - */ -VOID -FASTCALL -IntEngWindowChanged( - PWINDOW_OBJECT Window, - FLONG flChanged) -{ - PLIST_ENTRY CurrentEntry; - WNDGDI *Current; - - ASSERT_IRQL(PASSIVE_LEVEL); - - ExAcquireFastMutex(&Window->WndObjListLock); - CurrentEntry = Window->WndObjListHead.Flink; - while (CurrentEntry != &Window->WndObjListHead) - { - Current = CONTAINING_RECORD(CurrentEntry, WNDGDI, ListEntry); - - if (Current->WndObj.pvConsumer != NULL) - { - /* Update the WNDOBJ */ - switch (flChanged) - { - case WOC_RGN_CLIENT: - /* Update the clipobj and client rect of the WNDOBJ */ - IntEngWndUpdateClipObj(Current, Window); - break; - - case WOC_DELETE: - /* FIXME: Should the WNDOBJs be deleted by win32k or by the driver? */ - break; - } - - /* Call the change proc */ - IntEngWndCallChangeProc(&Current->WndObj, flChanged); - - /* HACK: Send WOC_CHANGED after WOC_RGN_CLIENT */ - if (flChanged == WOC_RGN_CLIENT) - { - IntEngWndCallChangeProc(&Current->WndObj, WOC_CHANGED); - } - - CurrentEntry = CurrentEntry->Flink; - } - } - - ExReleaseFastMutex(&Window->WndObjListLock); -} - -/* - * @implemented - */ -WNDOBJ* -STDCALL -EngCreateWnd( - SURFOBJ *pso, - HWND hwnd, - WNDOBJCHANGEPROC pfn, - FLONG fl, - int iPixelFormat) -{ - WNDGDI *WndObjInt = NULL; - WNDOBJ *WndObjUser = NULL; - PWINDOW_OBJECT Window; - - DPRINT("EngCreateWnd: pso = 0x%x, hwnd = 0x%x, pfn = 0x%x, fl = 0x%x, pixfmt = %d\n", - pso, hwnd, pfn, fl, iPixelFormat); - - /* Get window object */ - Window = IntGetWindowObject(hwnd); - if (Window == NULL) - { - return NULL; - } - - /* Create WNDOBJ */ - WndObjInt = EngAllocMem(0, sizeof (WNDGDI), TAG_WNDOBJ); - if (WndObjInt == NULL) - { - IntReleaseWindowObject(Window); - DPRINT1("Failed to allocate memory for a WND structure!\n"); - return NULL; - } - - /* Fill the clipobj */ - WndObjInt->ClientClipObj = NULL; - if (!IntEngWndUpdateClipObj(WndObjInt, Window)) - { - IntReleaseWindowObject(Window); - EngFreeMem(WndObjInt); - return NULL; - } - - /* Fill user object */ - WndObjUser = GDIToObj(WndObjInt, WND); - WndObjUser->psoOwner = pso; - WndObjUser->pvConsumer = NULL; - - /* Fill internal object */ - WndObjInt->Hwnd = hwnd; - WndObjInt->ChangeProc = pfn; - WndObjInt->Flags = fl; - WndObjInt->PixelFormat = iPixelFormat; - - /* associate object with window */ - ExAcquireFastMutex(&Window->WndObjListLock); - InsertTailList(&Window->WndObjListHead, &WndObjInt->ListEntry); - ExReleaseFastMutex(&Window->WndObjListLock); - - /* release resources */ - IntReleaseWindowObject(Window); - - DPRINT("EngCreateWnd: SUCCESS!\n"); - - return WndObjUser; -} - - -/* - * @implemented - */ -VOID -STDCALL -EngDeleteWnd( - IN WNDOBJ *pwo) -{ - WNDGDI *WndObjInt = ObjToGDI(pwo, WND); - PWINDOW_OBJECT Window; - - DPRINT("EngDeleteWnd: pwo = 0x%x\n", pwo); - - /* Get window object */ - Window = IntGetWindowObject(WndObjInt->Hwnd); - if (Window == NULL) - { - DPRINT1("Warning: Couldnt get window object for WndObjInt->Hwnd!!!\n"); - RemoveEntryList(&WndObjInt->ListEntry); - } - else - { - /* Remove object from window */ - ExAcquireFastMutex(&Window->WndObjListLock); - RemoveEntryList(&WndObjInt->ListEntry); - ExReleaseFastMutex(&Window->WndObjListLock); - IntReleaseWindowObject(Window); - } - - /* Free resources */ - IntEngDeleteClipRegion(WndObjInt->ClientClipObj); - EngFreeMem(WndObjInt); -} - - -/* - * @implemented - */ -BOOL -STDCALL -WNDOBJ_bEnum( - IN WNDOBJ *pwo, - IN ULONG cj, - OUT ULONG *pul) -{ - WNDGDI *WndObjInt = ObjToGDI(pwo, WND); - BOOL Ret; - - DPRINT("WNDOBJ_bEnum: pwo = 0x%x, cj = %d, pul = 0x%x\n", pwo, cj, pul); - Ret = CLIPOBJ_bEnum(WndObjInt->ClientClipObj, cj, pul); - - DPRINT("WNDOBJ_bEnum: Returning %s\n", Ret ? "True" : "False"); - return Ret; -} - - -/* - * @implemented - */ -ULONG -STDCALL -WNDOBJ_cEnumStart( - IN WNDOBJ *pwo, - IN ULONG iType, - IN ULONG iDirection, - IN ULONG cLimit) -{ - WNDGDI *WndObjInt = ObjToGDI(pwo, WND); - ULONG Ret; - - DPRINT("WNDOBJ_cEnumStart: pwo = 0x%x, iType = %d, iDirection = %d, cLimit = %d\n", - pwo, iType, iDirection, cLimit); - - /* FIXME: Should we enumerate all rectangles or not? */ - Ret = CLIPOBJ_cEnumStart(WndObjInt->ClientClipObj, FALSE, iType, iDirection, cLimit); - - DPRINT("WNDOBJ_cEnumStart: Returning 0x%x\n", Ret); - return Ret; -} - - -/* - * @implemented - */ -VOID -STDCALL -WNDOBJ_vSetConsumer( - IN WNDOBJ *pwo, - IN PVOID pvConsumer) -{ - BOOL Hack; - - DPRINT("WNDOBJ_vSetConsumer: pwo = 0x%x, pvConsumer = 0x%x\n", pwo, pvConsumer); - - Hack = (pwo->pvConsumer == NULL); - pwo->pvConsumer = pvConsumer; - - /* HACKHACKHACK - * - * MSDN says that the WNDOBJCHANGEPROC will be called with the most recent state - * when a WNDOBJ is created - we do it here because most drivers will need pvConsumer - * in the callback to identify the WNDOBJ I think. - * - * - blight - */ - if (Hack) - { - IntEngWndCallChangeProc(pwo, WOC_RGN_CLIENT); - IntEngWndCallChangeProc(pwo, WOC_CHANGED); - IntEngWndCallChangeProc(pwo, WOC_DRAWN); - } -} - -/* EOF */ - +/* + * ReactOS W32 Subsystem + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 ReactOS Team + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id$ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * PURPOSE: GDI WNDOBJ Functions + * FILE: subsys/win32k/eng/window.c + * PROGRAMER: Gregor Anich + * REVISION HISTORY: + * 16/11/2004: Created + */ + +/* TODO: Check how the WNDOBJ implementation should behave with a driver on windows. */ + +#include <w32k.h> + +#define NDEBUG +#include <debug.h> + +/* + * Calls the WNDOBJCHANGEPROC of the given WNDOBJ + */ +VOID +FASTCALL +IntEngWndCallChangeProc( + IN WNDOBJ *pwo, + IN FLONG flChanged) +{ + WNDGDI *WndObjInt = ObjToGDI(pwo, WND); + + if (WndObjInt->ChangeProc == NULL) + { + return; + } + + /* check flags of the WNDOBJ */ + flChanged &= WndObjInt->Flags; + if (flChanged == 0) + { + return; + } + + /* Call the WNDOBJCHANGEPROC */ + if (flChanged == WOC_CHANGED) + { + pwo = NULL; + } + + DPRINT("Calling WNDOBJCHANGEPROC (0x%x), Changed = 0x%x\n", + WndObjInt->ChangeProc, flChanged); + WndObjInt->ChangeProc(pwo, flChanged); +} + +/* + * Fills the CLIPOBJ and client rect of the WNDOBJ with the data from the given WINDOW_OBJECT + */ +BOOLEAN +FASTCALL +IntEngWndUpdateClipObj( + WNDGDI *WndObjInt, + PWINDOW_OBJECT Window) +{ + HRGN hVisRgn; + PROSRGNDATA visRgn; + CLIPOBJ *ClipObj = NULL; + CLIPOBJ *OldClipObj; + + hVisRgn = VIS_ComputeVisibleRegion(Window, TRUE, TRUE, TRUE); + if (hVisRgn != NULL) + { + NtGdiOffsetRgn(hVisRgn, Window->ClientRect.left, Window->ClientRect.top); + visRgn = RGNDATA_LockRgn(hVisRgn); + if (visRgn != NULL) + { + if (visRgn->rdh.nCount > 0) + { + ClipObj = IntEngCreateClipRegion(visRgn->rdh.nCount, (PRECTL)visRgn->Buffer, + (PRECTL)&visRgn->rdh.rcBound); + DPRINT("Created visible region with %d rects\n", visRgn->rdh.nCount); + DPRINT(" BoundingRect: %d, %d %d, %d\n", + visRgn->rdh.rcBound.left, visRgn->rdh.rcBound.top, + visRgn->rdh.rcBound.right, visRgn->rdh.rcBound.bottom); + { + INT i; + for (i = 0; i < visRgn->rdh.nCount; i++) + { + DPRINT(" Rect #%d: %d,%d %d,%d\n", i+1, + visRgn->Buffer[i].left, visRgn->Buffer[i].top, + visRgn->Buffer[i].right, visRgn->Buffer[i].bottom); + } + } + } + RGNDATA_UnlockRgn(visRgn); + } + else + { + DPRINT1("Warning: Couldn't lock visible region of window DC\n"); + } + } + else + { + DPRINT1("Warning: VIS_ComputeVisibleRegion failed!\n"); + } + + if (ClipObj == NULL) + { + /* Fall back to client rect */ + ClipObj = IntEngCreateClipRegion(1, (PRECTL)&Window->ClientRect, + (PRECTL)&Window->ClientRect); + } + + if (ClipObj == NULL) + { + DPRINT1("Warning: IntEngCreateClipRegion() failed!\n"); + return FALSE; + } + + RtlCopyMemory(&WndObjInt->WndObj.coClient, ClipObj, sizeof (CLIPOBJ)); + RtlCopyMemory(&WndObjInt->WndObj.rclClient, &Window->ClientRect, sizeof (RECT)); + OldClipObj = InterlockedExchangePointer(&WndObjInt->ClientClipObj, ClipObj); + if (OldClipObj != NULL) + IntEngDeleteClipRegion(OldClipObj); + + return TRUE; +} + +/* + * Updates all WNDOBJs of the given WINDOW_OBJECT and calls the change-procs. + */ +VOID +FASTCALL +IntEngWindowChanged( + PWINDOW_OBJECT Window, + FLONG flChanged) +{ + PLIST_ENTRY CurrentEntry; + WNDGDI *Current; + + ASSERT_IRQL(PASSIVE_LEVEL); + + ExAcquireFastMutex(&Window->WndObjListLock); + CurrentEntry = Window->WndObjListHead.Flink; + while (CurrentEntry != &Window->WndObjListHead) + { + Current = CONTAINING_RECORD(CurrentEntry, WNDGDI, ListEntry); + + if (Current->WndObj.pvConsumer != NULL) + { + /* Update the WNDOBJ */ + switch (flChanged) + { + case WOC_RGN_CLIENT: + /* Update the clipobj and client rect of the WNDOBJ */ + IntEngWndUpdateClipObj(Current, Window); + break; + + case WOC_DELETE: + /* FIXME: Should the WNDOBJs be deleted by win32k or by the driver? */ + break; + } + + /* Call the change proc */ + IntEngWndCallChangeProc(&Current->WndObj, flChanged); + + /* HACK: Send WOC_CHANGED after WOC_RGN_CLIENT */ + if (flChanged == WOC_RGN_CLIENT) + { + IntEngWndCallChangeProc(&Current->WndObj, WOC_CHANGED); + } + + CurrentEntry = CurrentEntry->Flink; + } + } + + ExReleaseFastMutex(&Window->WndObjListLock); +} + +/* + * @implemented + */ +WNDOBJ* +STDCALL +EngCreateWnd( + SURFOBJ *pso, + HWND hwnd, + WNDOBJCHANGEPROC pfn, + FLONG fl, + int iPixelFormat) +{ + WNDGDI *WndObjInt = NULL; + WNDOBJ *WndObjUser = NULL; + PWINDOW_OBJECT Window; + + DPRINT("EngCreateWnd: pso = 0x%x, hwnd = 0x%x, pfn = 0x%x, fl = 0x%x, pixfmt = %d\n", + pso, hwnd, pfn, fl, iPixelFormat); + + /* Get window object */ + Window = IntGetWindowObject(hwnd); + if (Window == NULL) + { + return NULL; + } + + /* Create WNDOBJ */ + WndObjInt = EngAllocMem(0, sizeof (WNDGDI), TAG_WNDOBJ); + if (WndObjInt == NULL) + { + IntReleaseWindowObject(Window); + DPRINT1("Failed to allocate memory for a WND structure!\n"); + return NULL; + } + + /* Fill the clipobj */ + WndObjInt->ClientClipObj = NULL; + if (!IntEngWndUpdateClipObj(WndObjInt, Window)) + { + IntReleaseWindowObject(Window); + EngFreeMem(WndObjInt); + return NULL; + } + + /* Fill user object */ + WndObjUser = GDIToObj(WndObjInt, WND); + WndObjUser->psoOwner = pso; + WndObjUser->pvConsumer = NULL; + + /* Fill internal object */ + WndObjInt->Hwnd = hwnd; + WndObjInt->ChangeProc = pfn; + WndObjInt->Flags = fl; + WndObjInt->PixelFormat = iPixelFormat; + + /* associate object with window */ + ExAcquireFastMutex(&Window->WndObjListLock); + InsertTailList(&Window->WndObjListHead, &WndObjInt->ListEntry); + ExReleaseFastMutex(&Window->WndObjListLock); + + /* release resources */ + IntReleaseWindowObject(Window); + + DPRINT("EngCreateWnd: SUCCESS!\n"); + + return WndObjUser; +} + + +/* + * @implemented + */ +VOID +STDCALL +EngDeleteWnd( + IN WNDOBJ *pwo) +{ + WNDGDI *WndObjInt = ObjToGDI(pwo, WND); + PWINDOW_OBJECT Window; + + DPRINT("EngDeleteWnd: pwo = 0x%x\n", pwo); + + /* Get window object */ + Window = IntGetWindowObject(WndObjInt->Hwnd); + if (Window == NULL) + { + DPRINT1("Warning: Couldnt get window object for WndObjInt->Hwnd!!!\n"); + RemoveEntryList(&WndObjInt->ListEntry); + } + else + { + /* Remove object from window */ + ExAcquireFastMutex(&Window->WndObjListLock); + RemoveEntryList(&WndObjInt->ListEntry); + ExReleaseFastMutex(&Window->WndObjListLock); + IntReleaseWindowObject(Window); + } + + /* Free resources */ + IntEngDeleteClipRegion(WndObjInt->ClientClipObj); + EngFreeMem(WndObjInt); +} + + +/* + * @implemented + */ +BOOL +STDCALL +WNDOBJ_bEnum( + IN WNDOBJ *pwo, + IN ULONG cj, + OUT ULONG *pul) +{ + WNDGDI *WndObjInt = ObjToGDI(pwo, WND); + BOOL Ret; + + DPRINT("WNDOBJ_bEnum: pwo = 0x%x, cj = %d, pul = 0x%x\n", pwo, cj, pul); + Ret = CLIPOBJ_bEnum(WndObjInt->ClientClipObj, cj, pul); + + DPRINT("WNDOBJ_bEnum: Returning %s\n", Ret ? "True" : "False"); + return Ret; +} + + +/* + * @implemented + */ +ULONG +STDCALL +WNDOBJ_cEnumStart( + IN WNDOBJ *pwo, + IN ULONG iType, + IN ULONG iDirection, + IN ULONG cLimit) +{ + WNDGDI *WndObjInt = ObjToGDI(pwo, WND); + ULONG Ret; + + DPRINT("WNDOBJ_cEnumStart: pwo = 0x%x, iType = %d, iDirection = %d, cLimit = %d\n", + pwo, iType, iDirection, cLimit); + + /* FIXME: Should we enumerate all rectangles or not? */ + Ret = CLIPOBJ_cEnumStart(WndObjInt->ClientClipObj, FALSE, iType, iDirection, cLimit); + + DPRINT("WNDOBJ_cEnumStart: Returning 0x%x\n", Ret); + return Ret; +} + + +/* + * @implemented + */ +VOID +STDCALL +WNDOBJ_vSetConsumer( + IN WNDOBJ *pwo, + IN PVOID pvConsumer) +{ + BOOL Hack; + + DPRINT("WNDOBJ_vSetConsumer: pwo = 0x%x, pvConsumer = 0x%x\n", pwo, pvConsumer); + + Hack = (pwo->pvConsumer == NULL); + pwo->pvConsumer = pvConsumer; + + /* HACKHACKHACK + * + * MSDN says that the WNDOBJCHANGEPROC will be called with the most recent state + * when a WNDOBJ is created - we do it here because most drivers will need pvConsumer + * in the callback to identify the WNDOBJ I think. + * + * - blight + */ + if (Hack) + { + IntEngWndCallChangeProc(pwo, WOC_RGN_CLIENT); + IntEngWndCallChangeProc(pwo, WOC_CHANGED); + IntEngWndCallChangeProc(pwo, WOC_DRAWN); + } +} + +/* EOF */ + diff --git a/reactos/tools/tools-check.c b/reactos/tools/tools-check.c index 8452a2632c5..31c11258732 100644 --- a/reactos/tools/tools-check.c +++ b/reactos/tools/tools-check.c @@ -1,32 +1,32 @@ -#include "tools-check.h" - -/* - * - Binutils older than 2003/10/01 have broken windres which can't handle - * icons with alpha channel. - * - Binutils between 2004/09/02 and 2004/10/08 have broken handling of - * forward exports in dlltool. - */ - -#if (BINUTILS_VERSION_DATE >= 20040902 && BINUTILS_VERSION_DATE <= 20041008) || \ - (BINUTILS_VERSION_DATE < 20031001) -#error "Due to technical reasons your binutils version can't be used to" \ - "build ReactOS. Please consider upgrading to newer version. See" \ - "www.mingw.org for details." -#endif - -/* - * GCC 3.3.1 is lowest allowed version. Older versions have various problems - * with C++ code. - */ - -#if (__GNUC__ == 3 && __GNUC_MINOR__ < 3) || \ - (__GNUC__ < 3) -#error "Due to technical reasons your GCC version can't be used to" \ - "build ReactOS. Please consider upgrading to newer version. See" \ - "www.mingw.org for details." -#endif - -/* - * FIXME: GCC 3.4.1 has broken headers which cause Explorer to not build. - * We should warn in this case...maybe add check for the broken headers? - */ +#include "tools-check.h" + +/* + * - Binutils older than 2003/10/01 have broken windres which can't handle + * icons with alpha channel. + * - Binutils between 2004/09/02 and 2004/10/08 have broken handling of + * forward exports in dlltool. + */ + +#if (BINUTILS_VERSION_DATE >= 20040902 && BINUTILS_VERSION_DATE <= 20041008) || \ + (BINUTILS_VERSION_DATE < 20031001) +#error "Due to technical reasons your binutils version can't be used to" \ + "build ReactOS. Please consider upgrading to newer version. See" \ + "www.mingw.org for details." +#endif + +/* + * GCC 3.3.1 is lowest allowed version. Older versions have various problems + * with C++ code. + */ + +#if (__GNUC__ == 3 && __GNUC_MINOR__ < 3) || \ + (__GNUC__ < 3) +#error "Due to technical reasons your GCC version can't be used to" \ + "build ReactOS. Please consider upgrading to newer version. See" \ + "www.mingw.org for details." +#endif + +/* + * FIXME: GCC 3.4.1 has broken headers which cause Explorer to not build. + * We should warn in this case...maybe add check for the broken headers? + */ diff --git a/reactos/tools/widl/client.c b/reactos/tools/widl/client.c index 0eba384e5a4..ec95a63f5ed 100644 --- a/reactos/tools/widl/client.c +++ b/reactos/tools/widl/client.c @@ -1,1957 +1,1957 @@ -/* - * IDL Compiler - * - * Copyright 2005 Eric Kohl - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <assert.h> -#include <ctype.h> -#include <signal.h> - -#include "widl.h" -#include "utils.h" -#include "parser.h" -#include "header.h" - -#define END_OF_LIST(list) \ - do { \ - if (list) { \ - while (NEXT_LINK(list)) \ - list = NEXT_LINK(list); \ - } \ - } while(0) - -static FILE* client; -static int indent = 0; - -static int print_client( const char *format, ... ) -{ - va_list va; - int i, r; - - va_start(va, format); - for (i = 0; i < indent; i++) - fprintf(client, " "); - r = vfprintf(client, format, va); - va_end(va); - return r; -} - - -static unsigned int -get_var_stack_offset_32(func_t *func, char *name) -{ - unsigned int offset = 0; - var_t *var; - - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - if (!strcmp(var->name, name)) - return offset; - - if (var->type->type == RPC_FC_DOUBLE || - var->type->type == RPC_FC_HYPER) - offset += 8; - else - offset += 4; - - var = PREV_LINK(var); - } - - return 0; -} - - -static unsigned int -get_var_stack_offset_64(func_t *func, char *name) -{ - unsigned int offset = 0; - var_t *var; - - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - if (!strcmp(var->name, name)) - return offset; - - offset += 8; - - var = PREV_LINK(var); - } - - return 0; -} - - -static unsigned int -get_var_type_offset(var_t *var) -{ - unsigned int toffset = 0; - void *sizeis_attr; - int string_attr; - - if (var->ptr_level == 0) - { - if ((var->type->type == RPC_FC_RP) && - (var->type->ref->ref->type == RPC_FC_STRUCT)) - { - var_t *field = var->type->ref->ref->fields; - int tsize = 9; - - while (NEXT_LINK(field)) field = NEXT_LINK(field); - while (field) - { - tsize++; - field = PREV_LINK(field); - } - if (tsize % 2) - tsize++; - - toffset += tsize; - } - } - else if (var->ptr_level == 1) - { - sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); - string_attr = is_attr(var->attrs, ATTR_STRING); - - if (sizeis_attr) - { - if (string_attr) - { - if (var->type->type == RPC_FC_BYTE || - var->type->type == RPC_FC_CHAR || - var->type->type == RPC_FC_WCHAR) - toffset += 10; - } - else - { - if (is_base_type(var->type)) - toffset += 14; - } - } - else - { - if (is_base_type(var->type)) - toffset += 4; - } - } - - return toffset; -} - - -static type_t *get_type_by_name(func_t *func, char *name) -{ - var_t *var; - - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - if (!strcmp(var->name, name)) - return var->type; - - var = PREV_LINK(var); - } - - return NULL; -} - - -static unsigned char -get_base_type(unsigned char type) -{ - - switch (type) - { - case RPC_FC_USHORT: - type = RPC_FC_SHORT; - break; - - case RPC_FC_ULONG: - type = RPC_FC_LONG; - break; - } - - return type; -} - - -static int get_type_size(type_t *type, int alignment) -{ - int size; - var_t *field; - - switch(type->type) - { - case RPC_FC_BYTE: - case RPC_FC_CHAR: - case RPC_FC_SMALL: - size = 1; - size = ((size + alignment - 1) & ~(alignment -1)); - break; - - case RPC_FC_WCHAR: - case RPC_FC_USHORT: - case RPC_FC_SHORT: - size = 2; - size = ((size + alignment - 1) & ~(alignment -1)); - break; - - case RPC_FC_ULONG: - case RPC_FC_LONG: - case RPC_FC_FLOAT: - size = 4; - size = ((size + alignment - 1) & ~(alignment -1)); - break; - - case RPC_FC_HYPER: - case RPC_FC_DOUBLE: - size = 8; - size = ((size + alignment - 1) & ~(alignment -1)); - break; - - case RPC_FC_IGNORE: - size = 0; - break; - - case RPC_FC_STRUCT: - field = type->fields; - size = 0; - while (NEXT_LINK(field)) field = NEXT_LINK(field); - while (field) - { - size += get_type_size(field->type, alignment); - field = PREV_LINK(field); - } - break; - - default: - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, type->type); - return 0; - } - - return size; -} - - -static int get_type_alignment(type_t *type) -{ - int size; - - switch(type->type) - { - case RPC_FC_BYTE: - case RPC_FC_CHAR: - case RPC_FC_SMALL: - size = 1; - break; - - case RPC_FC_WCHAR: - case RPC_FC_USHORT: - case RPC_FC_SHORT: - size = 2; - break; - - case RPC_FC_ULONG: - case RPC_FC_LONG: - case RPC_FC_FLOAT: - size = 4; - break; - - case RPC_FC_HYPER: - case RPC_FC_DOUBLE: - size = 8; - break; - - default: - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, type->type); - return 0; - } - - return size; -} - - -static void write_procformatstring(type_t *iface) -{ - func_t *func = iface->funcs; - var_t *var; - unsigned int type_offset = 2; - int in_attr, out_attr; - - print_client("const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n"); - print_client("{\n"); - indent++; - print_client("0,\n"); - print_client("{\n"); - indent++; - - while (NEXT_LINK(func)) func = NEXT_LINK(func); - while (func) - { - /* emit argument data */ - if (func->args) - { - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - out_attr = is_attr(var->attrs, ATTR_OUT); - in_attr = is_attr(var->attrs, ATTR_IN); - - /* set 'in' attribute if neither 'in' nor 'out' is set */ - if (!out_attr && !in_attr) - in_attr = 1; - - if (var->ptr_level == 0) - { - if (is_base_type(var->type)) - { - print_client("0x4e, /* FC_IN_PARAM_BASETYPE */\n"); - print_client("0x%02x, /* FC_<type> */\n", get_base_type(var->type->type)); - } - else if (var->type->type == RPC_FC_RP) - { - if (in_attr & !out_attr) - print_client("0x4d, /* FC_IN_PARAM */\n"); - else if (!in_attr & out_attr) - print_client("0x51, /* FC_OUT_PARAM */\n"); - else if (in_attr & out_attr) - print_client("0x50, /* FC_IN_OUT_PARAM */\n"); - fprintf(client, "#ifndef _ALPHA_\n"); - print_client("0x01,\n"); - fprintf(client, "#else\n"); - print_client("0x02,\n"); - fprintf(client, "#endif\n"); - print_client("NdrFcShort(0x%x),\n", type_offset); - } - else - { - print_client("0x4d, /* FC_IN_PARAM */\n"); - - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, var->type->type); - return; - } - } - else if (var->ptr_level == 1) - { -// if (is_base_type(var->type)) -// { - if (in_attr & !out_attr) - print_client("0x4d, /* FC_IN_PARAM */\n"); - else if (!in_attr & out_attr) - print_client("0x51, /* FC_OUT_PARAM */\n"); - else if (in_attr & out_attr) - print_client("0x50, /* FC_IN_OUT_PARAM */\n"); - fprintf(client, "#ifndef _ALPHA_\n"); - print_client("0x01,\n"); - fprintf(client, "#else\n"); - print_client("0x02,\n"); - fprintf(client, "#endif\n"); - print_client("NdrFcShort(0x%x),\n", type_offset); -// } -// else -// { -// error("%s:%d Unknown/unsupported type 0x%x\n", -// __FUNCTION__,__LINE__, var->type->type); -// return; -// } - } - else - { - error("%s:%d Pointer level %d is not supported!\n", - __FUNCTION__,__LINE__, var->ptr_level); - return; - } - - type_offset += get_var_type_offset(var); - - var = PREV_LINK(var); - } - } - - /* emit return value data */ - var = func->def; - if (is_void(var->type, NULL)) - { - print_client("0x5b, /* FC_END */\n"); - print_client("0x5c, /* FC_PAD */\n"); - } - else if (is_base_type(var->type)) - { - print_client("0x53, /* FC_RETURN_PARAM_BASETYPE */\n"); - print_client("0x%02x, /* FC_<type> */\n", get_base_type(var->type->type)); - } - else - { - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, var->type->type); - return; - } - - func = PREV_LINK(func); - } - - print_client("0x0\n"); - indent--; - print_client("}\n"); - indent--; - print_client("};\n"); - print_client("\n"); -} - - -static void write_typeformatstring(type_t *iface) -{ - func_t *func = iface->funcs; - var_t *var; - type_t *type; - int in_attr, out_attr; - int string_attr; - int ptr_attr, ref_attr, unique_attr; - void *sizeis_attr; - - print_client("const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =\n"); - print_client("{\n"); - indent++; - print_client("0,\n"); - print_client("{\n"); - indent++; - print_client("NdrFcShort(0x00),\n"); - - while (NEXT_LINK(func)) func = NEXT_LINK(func); - while (func) - { - if (func->args) - { - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - in_attr = is_attr(var->attrs, ATTR_IN); - out_attr = is_attr(var->attrs, ATTR_OUT); - string_attr = is_attr(var->attrs, ATTR_STRING); - - if (var->ptr_level > 1) - { - error("Function '%s' argument '%s': Pointer level %d not supported!\n", - func->def->name, var->name, var->ptr_level); - return; - } - - if (var->ptr_level == 0) - { - if (!is_base_type(var->type)) - { - if (var->type->type == RPC_FC_RP) - { - var_t *field; - int tsize = 9; - unsigned char flags = 0; - - if (!in_attr && out_attr) - flags |= RPC_FC_P_ONSTACK; - - print_client("0x11, 0x%02X, /* FC_RP, [flags] */\n", flags); - print_client("NdrFcShort(0x%02X),\n", 0x02); - print_client("0x%02X,\n", var->type->ref->ref->type); - print_client("0x%02X,\n", 3); /* alignment -1 */ - print_client("NdrFcShort(0x%02X),\n", get_type_size(var->type->ref->ref, 4)); - - field = var->type->ref->ref->fields; - while (NEXT_LINK(field)) field = NEXT_LINK(field); - while (field) - { - print_client("0x%02X,\n", get_base_type(field->type->type)); - tsize++; - field = PREV_LINK(field); - } - if (tsize % 2) - { - print_client("0x5c, /* FC_PAD */\n"); - tsize++; - } - print_client("0x5b, /* FC_END */\n"); - } - else - { - - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, var->type->type); - return; - } - } - } - else if (var->ptr_level == 1) - { - ptr_attr = is_attr(var->attrs, ATTR_PTR); - ref_attr = is_attr(var->attrs, ATTR_REF); - unique_attr = is_attr(var->attrs, ATTR_UNIQUE); - sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); - - if (ptr_attr + ref_attr + unique_attr == 0) - ref_attr = 1; - - if (sizeis_attr) - { - unsigned char type_type = 0; - - type = get_type_by_name(func, ((var_t *)sizeis_attr)->name); - if (type != NULL) - type_type = type->type; - - print_client("0x11, 0x00, /* FC_RP */\n"); - print_client("NdrFcShort(0x02),\n"); - - if (string_attr) - { - if (var->type->type == RPC_FC_WCHAR) - print_client("0x25, /* FC_C_WSTRING */\n"); - else - print_client("0x22, /* FC_C_CSTRING */\n"); - print_client("0x44, /* FC_STRING_SIZED */\n"); - print_client("0x%02x,\n", 0x20 + type_type); - print_client("0x00,\n"); - - fprintf(client, "#ifndef _ALPHA_\n"); - print_client("NdrFcShort(0x%02X),\n", - get_var_stack_offset_32(func, ((var_t *)sizeis_attr)->name)); - fprintf(client, "#else\n"); - print_client("NdrFcShort(0x%02X),\n", - get_var_stack_offset_64(func, ((var_t *)sizeis_attr)->name)); - fprintf(client, "#endif\n"); - } - else - { - print_client("0x1b, /* FC_CARRAY */\n"); - print_client("0x%02x,\n", get_type_alignment(var->type) - 1); - print_client("NdrFcShort(0x%02x),\n", get_type_size(var->type, 1)); - print_client("0x%02x,\n", 0x20 + type_type); - if (out_attr) - print_client("0x54, /* FC_DEREFERENCE */\n"); - else - print_client("0x00, /* */\n"); - - fprintf(client, "#ifndef _ALPHA_\n"); - print_client("NdrFcShort(0x%02X),\n", - get_var_stack_offset_32(func, ((var_t *)sizeis_attr)->name)); - fprintf(client, "#else\n"); - print_client("NdrFcShort(0x%02X),\n", - get_var_stack_offset_64(func, ((var_t *)sizeis_attr)->name)); - fprintf(client, "#endif\n"); - print_client("0x%02x,\n", get_base_type(var->type->type)); - print_client("0x5b, /* FC_END */\n"); - } - } - else if (is_base_type(var->type)) - { - if (out_attr && !in_attr) - { - if (ref_attr) - print_client("0x11, 0x0c, /* FC_RP [allocated_on_stack] [simple_pointer] */\n"); - else if (unique_attr) - print_client("0x12, 0x0c, /* FC_FP [allocated_on_stack] [simple_pointer] */\n"); - else if (ptr_attr) - print_client("0x14, 0x0c, /* FC_FP [allocated_on_stack] [simple_pointer] */\n"); - } - else - { - if (ref_attr) - print_client("0x11, 0x08, /* FC_RP [simple_pointer] */\n"); - else if (unique_attr) - print_client("0x12, 0x08, /* FC_UP [simple_pointer] */\n"); - else if (ptr_attr) - print_client("0x14, 0x08, /* FC_FP [simple_pointer] */\n"); - } - - if (string_attr) - { - if (var->type->type == RPC_FC_CHAR) - print_client("0x%02x, /* FC_C_CSTRING */\n", RPC_FC_C_CSTRING); - else if (var->type->type == RPC_FC_WCHAR) - print_client("0x%02x, /* FC_C_WSTRING */\n", RPC_FC_C_WSTRING); - else - { - error("%s: Invalid type!\n", __FUNCTION__); - return; - } - } - else - print_client("0x%02x, /* FC_<type> */\n", get_base_type(var->type->type)); - print_client("0x5c, /* FC_PAD */\n"); - } - } - - var = PREV_LINK(var); - } - } - - func = PREV_LINK(func); - } - - print_client("0x0\n"); - indent--; - print_client("}\n"); - indent--; - print_client("};\n"); - print_client("\n"); -} - - -static void print_message_buffer_size(func_t *func, unsigned int *type_offset) -{ - unsigned int local_type_offset = *type_offset; - unsigned int alignment; - int size; - int last_size = -1; - int in_attr; - int out_attr; - int string_attr; - int nothing_printed = 1; - int ptr_attr, ref_attr, unique_attr; - int padding = 0, first_padding = 0; - void *sizeis_attr; - var_t *var; - - print_client("_StubMsg.BufferLength ="); - if (func->args) - { - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - for (; var; var = PREV_LINK(var)) - { - out_attr = is_attr(var->attrs, ATTR_OUT); - in_attr = is_attr(var->attrs, ATTR_IN); - - /* set 'in' attribute if neither 'in' nor 'out' is found */ - if (!out_attr && !in_attr) - in_attr = 1; - - ptr_attr = is_attr(var->attrs, ATTR_PTR); - ref_attr = is_attr(var->attrs, ATTR_REF); - unique_attr = is_attr(var->attrs, ATTR_UNIQUE); - - /* default to 'ref' attribute */ - if (ptr_attr + ref_attr + unique_attr == 0) - ref_attr = 1; - - if (!in_attr) - continue; - - string_attr = is_attr(var->attrs, ATTR_STRING); - sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); - - if (var->ptr_level == 1) - { - if (string_attr && !sizeis_attr) - { - /* non-sized conformant string */ - if (var->type->type == RPC_FC_CHAR || var->type->type == RPC_FC_WCHAR) - { - size = (unique_attr) ? 16 : 12; - alignment = 0; - } - } - else if (sizeis_attr && !string_attr) - { - /* conformant arrays */ - size = 4; - alignment = 0; - if (padding != 0) - padding = 1; - } - else if (!sizeis_attr && !string_attr) - { - /* simple pointers */ - if (is_base_type(var->type)) - { - alignment = 0; - switch (var->type->type) - { - case RPC_FC_BYTE: - case RPC_FC_CHAR: - case RPC_FC_SMALL: - size = 1; - alignment = 0; - break; - - case RPC_FC_WCHAR: - case RPC_FC_USHORT: - case RPC_FC_SHORT: - size = 2; - if (last_size > 0 && last_size < 2) - alignment += (2 - last_size); - break; - - case RPC_FC_ULONG: - case RPC_FC_LONG: - case RPC_FC_FLOAT: - size = 4; - if (last_size > 0 && last_size < 4) - alignment += (4 - last_size); - break; - - case RPC_FC_HYPER: - case RPC_FC_DOUBLE: - size = 8; - if (last_size > 0 && last_size < 4) - alignment += (4 - last_size); - break; - - case RPC_FC_IGNORE: - size = 0; - break; - - default: - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, var->type->type); - return; - } - } - else - { - /* simple pointer to a struct */ - size = 8; - alignment = 0; - } - } - } - else - { - alignment = 0; - switch (var->type->type) - { - case RPC_FC_BYTE: - case RPC_FC_CHAR: - case RPC_FC_SMALL: - size = 1; - alignment = 0; - break; - - case RPC_FC_WCHAR: - case RPC_FC_USHORT: - case RPC_FC_SHORT: - size = 2; - if (last_size > 0 && last_size < 2) - alignment += (2 - last_size); - break; - - case RPC_FC_ULONG: - case RPC_FC_LONG: - case RPC_FC_FLOAT: - size = 4; - if (last_size > 0 && last_size < 4) - alignment += (4 - last_size); - break; - - case RPC_FC_HYPER: - case RPC_FC_DOUBLE: - size = 8; - if (last_size > 0 && last_size < 4) - alignment += (4 - last_size); - break; - - case RPC_FC_IGNORE: - size = 0; - break; - - case RPC_FC_RP: - case RPC_FC_UP: - case RPC_FC_FP: - size = 0; - break; - - default: - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, var->type->type); - return; - } - } - - if (last_size != -1) - fprintf(client, " +"); - fprintf(client, " %dU", (size == 0) ? 0 : size + alignment + first_padding + padding); - nothing_printed = 0; - if (first_padding != 0) - first_padding = 0; - - /* set paddings */ - if (var->ptr_level == 1) - { - if (string_attr && !sizeis_attr) - { - /* non-sized conformant string */ - if (var->type->type == RPC_FC_CHAR || var->type->type == RPC_FC_WCHAR) - { - first_padding = 3; - padding = 3; - } - } - else if (sizeis_attr && !string_attr) - { - /* conformant arrays */ - first_padding = 4; - padding = 3; - } - } - - last_size = size; - } - } - - if (nothing_printed) - { - fprintf(client, " 0U"); - } - fprintf(client, ";\n"); - - /* get string size */ - if (func->args) - { - nothing_printed = 0; - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - for (; var; var = PREV_LINK(var)) - { - out_attr = is_attr(var->attrs, ATTR_OUT); - in_attr = is_attr(var->attrs, ATTR_IN); - - /* default to 'in' attribute */ - if (!out_attr && !in_attr) - in_attr = 1; - - ptr_attr = is_attr(var->attrs, ATTR_PTR); - ref_attr = is_attr(var->attrs, ATTR_REF); - unique_attr = is_attr(var->attrs, ATTR_UNIQUE); - - /* default to 'ref' attribute */ - if (ptr_attr + ref_attr + unique_attr == 0) - ref_attr = 1; - - string_attr = is_attr(var->attrs, ATTR_STRING); - sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); - - if (in_attr) - { - if (var->ptr_level == 0) - { - if (var->type->type == RPC_FC_RP && - var->type->ref->ref->type == RPC_FC_STRUCT) - { - print_client("NdrSimpleStructBufferSize(\n"); - indent++; - print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_client("(unsigned char __RPC_FAR *)%s,\n", var->name); - print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", - local_type_offset + 4); - nothing_printed = 1; - indent--; - } - } - else if (var->ptr_level == 1) - { - if (string_attr) - { - if ((var->type->type == RPC_FC_CHAR || - var->type->type == RPC_FC_WCHAR)) - { - if (ptr_attr) - { - /* FIXME: not supported yet */ - } - if (ref_attr) - { - print_client("NdrConformantStringBufferSize(\n"); - indent++; - print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_client("(unsigned char __RPC_FAR *)%s,\n", var->name); - print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", - local_type_offset + 2); - nothing_printed = 1; - indent--; - } - else if (unique_attr) - { - print_client("NdrPointerBufferSize(\n"); - indent++; - print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_client("(unsigned char __RPC_FAR *)%s,\n", var->name); - print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", - local_type_offset); - nothing_printed = 1; - indent--; - } - } - } - else - { - if (sizeis_attr) - { - fprintf(client, "\n"); - print_client("_StubMsg.MaxCount = %s;\n", - ((var_t *)sizeis_attr)->name); - fprintf(client, "\n"); - - print_client("NdrConformantArrayBufferSize(\n"); - indent++; - print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_client("(unsigned char __RPC_FAR *)%s,\n", var->name); - print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", - local_type_offset + 4); - indent--; - nothing_printed = 1; - } - } - } - } - - /* calculate the next type offset */ - local_type_offset += get_var_type_offset(var); - } - - if (nothing_printed) - fprintf(client, "\n"); - } -} - - -static void marshall_in_arguments(func_t *func, unsigned int *type_offset) -{ - unsigned int local_type_offset = *type_offset; - unsigned int alignment; - unsigned int size; - unsigned int last_size = 0; - int in_attr; - int out_attr; - int string_attr; - int ptr_attr, ref_attr, unique_attr; - void *sizeis_attr; - var_t *var; - - if (!func->args) - return; - - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - for (; var; var = PREV_LINK(var)) - { - out_attr = is_attr(var->attrs, ATTR_OUT); - in_attr = is_attr(var->attrs, ATTR_IN); - - /* set 'in' attribute if neither 'in' nor 'out' is set */ - if (!out_attr && !in_attr) - in_attr = 1; - - if (in_attr) - { - if (var->ptr_level > 1) - { - error("Function '%s' argument '%s': Pointer level %d not supported!\n", - func->def->name, var->name, var->ptr_level); - return; - } - - if (var->ptr_level == 1) - { - ptr_attr = is_attr(var->attrs, ATTR_PTR); - ref_attr = is_attr(var->attrs, ATTR_REF); - unique_attr = is_attr(var->attrs, ATTR_UNIQUE); - if (ptr_attr + ref_attr + unique_attr == 0) - ref_attr = 1; - - string_attr = is_attr(var->attrs, ATTR_STRING); - sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); - - if (sizeis_attr) - { - print_client("_StubMsg.MaxCount = %s;\n", - ((var_t *)sizeis_attr)->name); - fprintf(client, "\n"); - - print_client("NdrConformantArrayMarshall(\n"); - indent++; - print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_client("(unsigned char __RPC_FAR *)%s,\n", var->name); - print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", - local_type_offset + 4); - indent--; - fprintf(client, "\n"); - print_client("_StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~0x3);\n"); - fprintf(client, "\n"); - } - else if (ref_attr) - { - if (string_attr && - (var->type->type == RPC_FC_CHAR || var->type->type == RPC_FC_WCHAR)) - { - print_client("NdrConformantStringMarshall(\n"); - indent++; - print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_client("(unsigned char __RPC_FAR *)%s,\n", var->name); - print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", - local_type_offset + 2); - indent--; - fprintf(client, "\n"); - print_client("_StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~0x3);\n"); - fprintf(client, "\n"); - } - else - { - alignment = 0; - switch (var->type->type) - { - case RPC_FC_BYTE: - case RPC_FC_CHAR: - case RPC_FC_SMALL: - size = 1; - alignment = 0; - break; - - case RPC_FC_WCHAR: - case RPC_FC_USHORT: - case RPC_FC_SHORT: - size = 2; - if (last_size > 0 && last_size < 2) - alignment = (2 - last_size); - break; - - case RPC_FC_ULONG: - case RPC_FC_LONG: - case RPC_FC_FLOAT: - size = 4; - if (last_size > 0 && last_size < 4) - alignment = (4 - last_size); - break; - - case RPC_FC_HYPER: - case RPC_FC_DOUBLE: - size = 8; - if (last_size > 0 && last_size < 4) - alignment = (4 - last_size); - break; - - case RPC_FC_IGNORE: - size = 0; - break; - - default: - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, var->type->type); - return; - } - - if (size != 0) - { - if (alignment != 0) - print_client("_StubMsg.Buffer += %u;\n", alignment); - - print_client("*(("); - write_type(client, var->type, NULL, var->tname); - fprintf(client, " __RPC_FAR*)_StubMsg.Buffer) = "); - if (var->ptr_level == 1) - fprintf(client, "*"); - write_name(client, var); - fprintf(client, ";\n"); - print_client("_StubMsg.Buffer += sizeof("); - write_type(client, var->type, NULL, var->tname); - fprintf(client, ");\n"); - fprintf(client, "\n"); - - last_size = size; - } - } - } - else if (unique_attr) - { - print_client("NdrPointerMarshall(\n"); - indent++; - print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_client("(unsigned char __RPC_FAR *)%s,\n", var->name); - print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", - local_type_offset); - indent--; - fprintf(client, "\n"); - } - } - else - { - if (is_base_type(var->type)) - { - alignment = 0; - switch (var->type->type) - { - case RPC_FC_BYTE: - case RPC_FC_CHAR: - case RPC_FC_SMALL: - size = 1; - alignment = 0; - break; - - case RPC_FC_WCHAR: - case RPC_FC_USHORT: - case RPC_FC_SHORT: - size = 2; - if (last_size > 0 && last_size < 2) - alignment = (2 - last_size); - break; - - case RPC_FC_ULONG: - case RPC_FC_LONG: - case RPC_FC_FLOAT: - size = 4; - if (last_size > 0 && last_size < 4) - alignment = (4 - last_size); - break; - - case RPC_FC_HYPER: - case RPC_FC_DOUBLE: - size = 8; - if (last_size > 0 && last_size < 4) - alignment = (4 - last_size); - break; - - case RPC_FC_IGNORE: - size = 0; - break; - - default: - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, var->type->type); - return; - } - - if (size != 0) - { - if (alignment != 0) - print_client("_StubMsg.Buffer += %u;\n", alignment); - - print_client("*(("); - write_type(client, var->type, NULL, var->tname); - fprintf(client, " __RPC_FAR*)_StubMsg.Buffer) = "); - if (var->ptr_level == 1) - fprintf(client, "*"); - write_name(client, var); - fprintf(client, ";\n"); - print_client("_StubMsg.Buffer += sizeof("); - write_type(client, var->type, NULL, var->tname); - fprintf(client, ");\n"); - fprintf(client, "\n"); - - last_size = size; - } - } - else if (var->type->type == RPC_FC_RP) - { - if (var->type->ref->ref->type == RPC_FC_STRUCT) - { - print_client("NdrSimpleStructMarshall(\n"); - indent++; - print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_client("(unsigned char __RPC_FAR *)%s,\n", var->name); - print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", - local_type_offset + 4); - indent--; - fprintf(client, "\n"); - } - } - } - } - - /* calculate the next type offset */ - local_type_offset += get_var_type_offset(var); - } -} - - -static void unmarshall_out_arguments(func_t *func, unsigned int *type_offset) -{ - unsigned int alignment; - unsigned int size; - unsigned int last_size = 0; - int out_attr; - int string_attr; - void *sizeis_attr; - var_t *var; - var_t *def; - unsigned int local_type_offset = *type_offset; - - def = func->def; - - /* unmarshall the out arguments */ - if (func->args) - { - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - for (; var; var = PREV_LINK(var)) - { - out_attr = is_attr(var->attrs, ATTR_OUT); - sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); - string_attr = is_attr(var->attrs, ATTR_STRING); - - if (out_attr) - { - if (var->ptr_level > 1) - { - error("Function '%s' argument '%s': Pointer level %d not supported!\n", - func->def->name, var->name, var->ptr_level); - return; - } - - if (sizeis_attr != NULL) - { - if (string_attr) - { - fprintf(client, "\n"); - print_client("NdrConformantStringUnmarshall(\n"); - indent++; - print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_client("(unsigned char __RPC_FAR * __RPC_FAR *)&%s,\n", var->name); - print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u],\n", - local_type_offset + 4); - print_client("(unsigned char)0);\n"); - indent--; - fprintf(client, "\n"); - print_client("_StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~0x3);\n"); - fprintf(client, "\n"); - } - else - { - fprintf(client, "\n"); - print_client("NdrConformantArrayUnmarshall(\n"); - indent++; - print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_client("(unsigned char __RPC_FAR * __RPC_FAR *)&%s,\n", var->name); - print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u],\n", - local_type_offset + 4); - print_client("(unsigned char)0);\n"); - indent--; - fprintf(client, "\n"); - print_client("_StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~0x3);\n"); - fprintf(client, "\n"); - } - } - else if (is_base_type(var->type)) - { - alignment = 0; - switch (var->type->type) - { - case RPC_FC_BYTE: - case RPC_FC_CHAR: - case RPC_FC_SMALL: - size = 1; - alignment = 0; - break; - - case RPC_FC_WCHAR: - case RPC_FC_USHORT: - case RPC_FC_SHORT: - size = 2; - if (last_size > 0 && last_size < 2) - alignment = (2 - last_size); - break; - - case RPC_FC_ULONG: - case RPC_FC_LONG: - case RPC_FC_FLOAT: - size = 4; - if (last_size > 0 && last_size < 4) - alignment = (4 - last_size); - break; - - case RPC_FC_HYPER: - case RPC_FC_DOUBLE: - size = 8; - if (last_size > 0 && last_size < 4) - alignment = (4 - last_size); - break; - - case RPC_FC_IGNORE: - size = 0; - break; - - default: - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, var->type->type); - return; - } - - if (size != 0) - { - if (var->ptr_level == 1) - { - fprintf(client, "\n"); - if (alignment != 0) - print_client("_StubMsg.Buffer += %u;\n", alignment); - - print_client("*"); - write_name(client, var); - fprintf(client, " = *(("); - write_type(client, var->type, NULL, var->tname); - fprintf(client, " __RPC_FAR *)_StubMsg.Buffer);\n"); - - print_client("_StubMsg.Buffer += sizeof("); - write_type(client, var->type, NULL, var->tname); - fprintf(client, ");\n"); - } - - last_size = size; - } - } - else if (var->type->type == RPC_FC_RP) - { - if (var->type->ref->ref->type == RPC_FC_STRUCT) - { - fprintf(client, "\n"); - print_client("NdrSimpleStructUnmarshall(\n"); - indent++; - print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_client("(unsigned char __RPC_FAR * __RPC_FAR *)&%s,\n", var->name); - print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u],\n", - local_type_offset + 4); - print_client("(unsigned char)0);\n"); - indent--; - fprintf(client, "\n"); - } - } - else - { - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, var->type->type); - return; - } - } - - /* calculate the next type offset */ - local_type_offset += get_var_type_offset(var); - } - } - - /* unmarshall return value */ - if (!is_void(def->type, NULL)) - { - alignment = 0; - switch (def->type->type) - { - case RPC_FC_BYTE: - case RPC_FC_CHAR: - case RPC_FC_SMALL: - case RPC_FC_WCHAR: - case RPC_FC_USHORT: - case RPC_FC_SHORT: - case RPC_FC_ULONG: - case RPC_FC_LONG: - case RPC_FC_FLOAT: - size = 4; - if (last_size > 0 && last_size < 4) - alignment = (4 - last_size); - break; - - case RPC_FC_HYPER: - case RPC_FC_DOUBLE: - size = 8; - if (last_size > 0 && last_size < 4) - alignment = (4 - last_size); - break; - - default: - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, var->type->type); - return; - } - - fprintf(client, "\n"); - if (alignment != 0) - print_client("_StubMsg.Buffer += %u;\n", alignment); - print_client("_RetVal = *(("); - write_type(client, def->type, def, def->tname); - fprintf(client, " __RPC_FAR *)_StubMsg.Buffer);\n"); - - print_client("_StubMsg.Buffer += sizeof("); - write_type(client, def->type, def, def->tname); - fprintf(client, ");\n"); - } -} - - -static void check_pointers(func_t *func) -{ - var_t *var; - int ptr_attr; - int ref_attr; - int unique_attr; - - if (!func->args) - return; - - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - ptr_attr = is_attr(var->attrs, ATTR_PTR); - ref_attr = is_attr(var->attrs, ATTR_REF); - unique_attr = is_attr(var->attrs, ATTR_UNIQUE); - - if (var->ptr_level == 0) - { - if (ptr_attr + ref_attr + unique_attr != 0) - { - error("The attributes [ptr], [ref] and [unique] can only be used for pointers!\n"); - return; - } - } - else - { - /* default to 'ref' attribute */ - if (ptr_attr + ref_attr + unique_attr == 0) - { - ref_attr = 1; - } - - if (ptr_attr + ref_attr + unique_attr > 1) - { - error("The attributes [ptr], [ref] and [unique] are mutually exclusive!\n"); - return; - } - - if (var->ptr_level == 1) - { - if (ref_attr) - { - print_client("if (!%s)\n", var->name); - print_client("{\n"); - indent++; - print_client("RpcRaiseException(RPC_X_NULL_REF_POINTER);\n"); - indent--; - print_client("}\n"); - fprintf(client, "\n"); - } - } - else if (var->ptr_level > 1) - { - error("Pointer level %d not supported!\n", var->ptr_level); - return; - } - } - - var = PREV_LINK(var); - } -} - - -static int use_return_buffer(func_t *func) -{ - var_t *var; - - if (!is_void(func->def->type, NULL)) - return 1; - - if (!func->args) - return 0; - - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - if (is_attr(var->attrs, ATTR_OUT)) - return 1; - - var = PREV_LINK(var); - } - - return 0; -} - - -static void write_function_stubs(type_t *iface) -{ - char *implicit_handle = get_attrp(iface->attrs, ATTR_IMPLICIT_HANDLE); - int explicit_handle = is_attr(iface->attrs, ATTR_EXPLICIT_HANDLE); - func_t *func = iface->funcs; - var_t* var; - var_t* explicit_handle_var; - int method_count = 0; - unsigned int proc_offset = 0; - unsigned int type_offset = 2; - - while (NEXT_LINK(func)) func = NEXT_LINK(func); - while (func) - { - var_t *def = func->def; - - /* check for a defined binding handle */ - explicit_handle_var = get_explicit_handle_var(func); - if (explicit_handle) - { - if (!explicit_handle_var) - { - error("%s() does not define an explicit binding handle!\n", def->name); - return; - } - } - else - { - if (explicit_handle_var) - { - error("%s() must not define a binding handle!\n", def->name); - return; - } - } - - write_type(client, def->type, def, def->tname); - fprintf(client, " "); - write_name(client, def); - fprintf(client, "(\n"); - indent++; - write_args(client, func->args, iface->name, 0, TRUE); - fprintf(client, ")\n"); - indent--; - - /* write the functions body */ - fprintf(client, "{\n"); - indent++; - - /* declare return value '_RetVal' */ - if (!is_void(def->type, NULL)) - { - print_client(""); - write_type(client, def->type, def, def->tname); - fprintf(client, " _RetVal;\n"); - } - - if (implicit_handle || explicit_handle) - print_client("RPC_BINDING_HANDLE _Handle = 0;\n"); - print_client("RPC_MESSAGE _RpcMessage;\n"); - print_client("MIDL_STUB_MESSAGE _StubMsg;\n"); - fprintf(client, "\n"); - - /* check pointers */ - check_pointers(func); - - print_client("RpcTryFinally\n"); - print_client("{\n"); - indent++; - - print_client("NdrClientInitializeNew(\n"); - indent++; - print_client("(PRPC_MESSAGE)&_RpcMessage,\n"); - print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_client("(PMIDL_STUB_DESC)&%s_StubDesc,\n", iface->name); - print_client("%d);\n", method_count); - indent--; - fprintf(client, "\n"); - - if (implicit_handle) - { - print_client("_Handle = %s;\n", implicit_handle); - fprintf(client, "\n"); - } - else if (explicit_handle) - { - print_client("_Handle = %s;\n", explicit_handle_var->name); - fprintf(client, "\n"); - } - - /* emit the message buffer size */ - print_message_buffer_size(func, &type_offset); - - print_client("NdrGetBuffer(\n"); - indent++; - print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_client("_StubMsg.BufferLength,\n"); - if (implicit_handle || explicit_handle) - print_client("_Handle);\n"); - else - print_client("%s__MIDL_AutoBindHandle);\n", iface->name); - indent--; - fprintf(client, "\n"); - - /* marshal in arguments */ - marshall_in_arguments(func, &type_offset); - - /* send/recieve message */ - print_client("NdrSendReceive(\n"); - indent++; - print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_client("(unsigned char __RPC_FAR *)_StubMsg.Buffer);\n"); - indent--; - - if (use_return_buffer(func)) - { - /* convert data representation */ - fprintf(client, "\n"); - print_client("if ((_RpcMessage.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)\n"); - indent++; - print_client("NdrConvert(\n"); - indent++; - print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_client("(PFORMAT_STRING)&__MIDL_ProcFormatString.Format[%u]);\n", proc_offset); - indent -= 2; - - /* unmarshal out arguments */ - unmarshall_out_arguments(func, &type_offset); - } - - /* update type_offset */ - if (func->args) - { - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - type_offset += get_var_type_offset(var); - - var = PREV_LINK(var); - } - } - - /* update proc_offset */ - if (func->args) - { - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - switch (var->ptr_level) - { - case 0: - if (is_base_type(var->type)) - proc_offset += 2; - break; - - case 1: - if (is_base_type(var->type)) - proc_offset += 4; - break; - } - - var = PREV_LINK(var); - } - } - proc_offset += 2; /* FIXME */ - - indent--; - print_client("}\n"); - print_client("RpcFinally\n"); - print_client("{\n"); - indent++; - - - /* FIXME: emit client finally code */ - - print_client("NdrFreeBuffer((PMIDL_STUB_MESSAGE)&_StubMsg);\n"); - - indent--; - print_client("}\n"); - print_client("RpcEndFinally\n"); - - - /* emit return code */ - if (!is_void(def->type, NULL)) - { - fprintf(client, "\n"); - print_client("return _RetVal;\n"); - } - - indent--; - fprintf(client, "}\n"); - fprintf(client, "\n"); - - method_count++; - func = PREV_LINK(func); - } -} - - -static void write_bindinghandledecl(type_t *iface) -{ - if (!get_attrp(iface->attrs, ATTR_IMPLICIT_HANDLE)) - { - print_client("static RPC_BINDING_HANDLE %s__MIDL_AutoBindHandle;\n", iface->name); - fprintf(client, "\n"); - } -} - - -static void write_stubdescdecl(type_t *iface) -{ - print_client("extern const MIDL_STUB_DESC %s_StubDesc;\n", iface->name); - fprintf(client, "\n"); -} - - -static void write_stubdescriptor(type_t *iface) -{ - char *implicit_handle = get_attrp(iface->attrs, ATTR_IMPLICIT_HANDLE); - - print_client("const MIDL_STUB_DESC %s_StubDesc =\n", iface->name); - print_client("{\n"); - indent++; - print_client("(void __RPC_FAR *)& %s___RpcClientInterface,\n", iface->name); - print_client("MIDL_user_allocate,\n"); - print_client("MIDL_user_free,\n"); - if (implicit_handle) - print_client("{&%s},\n", implicit_handle); - else - print_client("{&%s__MIDL_AutoBindHandle},\n", iface->name); - print_client("0,\n"); - print_client("0,\n"); - print_client("0,\n"); - print_client("0,\n"); - print_client("__MIDL_TypeFormatString.Format,\n"); - print_client("1, /* -error bounds_check flag */\n"); - print_client("0x10001, /* Ndr library version */\n"); - print_client("0,\n"); - print_client("0x50100a4, /* MIDL Version 5.1.164 */\n"); - print_client("0,\n"); - print_client("0,\n"); - print_client("0, /* notify & notify_flag routine table */\n"); - print_client("1, /* Flags */\n"); - print_client("0, /* Reserved3 */\n"); - print_client("0, /* Reserved4 */\n"); - print_client("0 /* Reserved5 */\n"); - indent--; - print_client("};\n"); - fprintf(client, "\n"); -} - - -static void write_clientinterfacedecl(type_t *iface) -{ - unsigned long ver = get_attrv(iface->attrs, ATTR_VERSION); - UUID *uuid = get_attrp(iface->attrs, ATTR_UUID); - - print_client("static const RPC_CLIENT_INTERFACE %s___RpcClientInterface =\n", iface->name ); - print_client("{\n"); - indent++; - print_client("sizeof(RPC_CLIENT_INTERFACE),\n"); - print_client("{{0x%08lx,0x%04x,0x%04x,{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x}},{%d,%d}},\n", - uuid->Data1, uuid->Data2, uuid->Data3, uuid->Data4[0], uuid->Data4[1], - uuid->Data4[2], uuid->Data4[3], uuid->Data4[4], uuid->Data4[5], uuid->Data4[6], - uuid->Data4[7], LOWORD(ver), HIWORD(ver)); - print_client("{{0x8a885d04,0x1ceb,0x11c9,{0x9f,0xe8,0x08,0x00,0x2b,0x10,0x48,0x60}},{2,0}},\n"); /* FIXME */ - print_client("0,\n"); - print_client("0,\n"); - print_client("0,\n"); - print_client("0,\n"); - print_client("0,\n"); - print_client("0,\n"); - indent--; - print_client("};\n"); - if (old_names) - print_client("RPC_IF_HANDLE %s_ClientIfHandle = (RPC_IF_HANDLE)& %s___RpcClientInterface;\n", - iface->name, iface->name); - else - print_client("RPC_IF_HANDLE %s_v%d_%d_c_ifspec = (RPC_IF_HANDLE)& %s___RpcClientInterface;\n", - iface->name, LOWORD(ver), HIWORD(ver), iface->name); - fprintf(client, "\n"); -} - - -static void write_formatdesc( const char *str ) -{ - print_client("typedef struct _MIDL_%s_FORMAT_STRING\n", str ); - print_client("{\n"); - indent++; - print_client("short Pad;\n"); - print_client("unsigned char Format[%s_FORMAT_STRING_SIZE];\n", str); - indent--; - print_client("} MIDL_%s_FORMAT_STRING;\n", str); - print_client("\n"); -} - - -static int get_type_format_string_size(type_t *iface) -{ - int size = 3; - func_t *func; - var_t *var; - - /* determine the type format string size */ - func = iface->funcs; - while (NEXT_LINK(func)) func = NEXT_LINK(func); - while (func) - { - /* argument list size */ - if (func->args) - { - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - size += get_var_type_offset(var); - var = PREV_LINK(var); - } - } - - func = PREV_LINK(func); - } - - return size; -} - - -static int get_proc_format_string_size(type_t *iface) -{ - int size = 1; - func_t *func; - var_t *var; - - /* determine the proc format string size */ - func = iface->funcs; - while (NEXT_LINK(func)) func = NEXT_LINK(func); - while (func) - { - /* argument list size */ - if (func->args) - { - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - switch (var->ptr_level) - { - case 0: - if (is_base_type(var->type)) - size += 2; - else if (var->type->type == RPC_FC_RP) - size += 4; - break; - - case 1: - if (is_base_type(var->type)) - size += 4; - break; - } - - var = PREV_LINK(var); - } - } - - /* return value size */ - size += 2; - func = PREV_LINK(func); - } - - return size; -} - - -static void write_formatstringsdecl(type_t *iface) -{ - print_client("#define TYPE_FORMAT_STRING_SIZE %d\n", - get_type_format_string_size(iface)); - - print_client("#define PROC_FORMAT_STRING_SIZE %d\n", - get_proc_format_string_size(iface)); - - fprintf(client, "\n"); - write_formatdesc("TYPE"); - write_formatdesc("PROC"); - fprintf(client, "\n"); - print_client("extern const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString;\n"); - print_client("extern const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString;\n"); - print_client("\n"); -} - - -static void write_implicithandledecl(type_t *iface) -{ - char *implicit_handle = get_attrp(iface->attrs, ATTR_IMPLICIT_HANDLE); - - if (implicit_handle) - { - fprintf(client, "handle_t %s;\n", implicit_handle); - fprintf(client, "\n"); - } -} - - -static void init_client(void) -{ - if (client) return; - if (!(client = fopen(client_name, "w"))) - error("Could not open %s for output\n", client_name); - - print_client("/*** Autogenerated by WIDL %s from %s - Do not edit ***/\n", WIDL_FULLVERSION, input_name); - print_client("#include <string.h>\n"); - print_client("#ifdef _ALPHA_\n"); - print_client("#include <stdarg.h>\n"); - print_client("#endif\n"); - fprintf(client, "\n"); - print_client("#include \"%s\"\n", header_name); - fprintf(client, "\n"); -} - - -void write_client(ifref_t *ifaces) -{ - ifref_t *iface = ifaces; - - if (!do_client) - return; - if (!iface) - return; - END_OF_LIST(iface); - - init_client(); - if (!client) - return; - - while (iface) - { - fprintf(client, "/*****************************************************************************\n"); - fprintf(client, " * %s interface\n", iface->iface->name); - fprintf(client, " */\n"); - fprintf(client, "\n"); - - write_formatstringsdecl(iface->iface); - write_implicithandledecl(iface->iface); - - write_clientinterfacedecl(iface->iface); - write_stubdescdecl(iface->iface); - write_bindinghandledecl(iface->iface); - - write_function_stubs(iface->iface); - write_stubdescriptor(iface->iface); - - print_client("#if !defined(__RPC_WIN32__)\n"); - print_client("#error Invalid build platform for this stub.\n"); - print_client("#endif\n"); - fprintf(client, "\n"); - - write_procformatstring(iface->iface); - write_typeformatstring(iface->iface); - - fprintf(client, "\n"); - - iface = PREV_LINK(iface); - } - - fclose(client); -} +/* + * IDL Compiler + * + * Copyright 2005 Eric Kohl + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <assert.h> +#include <ctype.h> +#include <signal.h> + +#include "widl.h" +#include "utils.h" +#include "parser.h" +#include "header.h" + +#define END_OF_LIST(list) \ + do { \ + if (list) { \ + while (NEXT_LINK(list)) \ + list = NEXT_LINK(list); \ + } \ + } while(0) + +static FILE* client; +static int indent = 0; + +static int print_client( const char *format, ... ) +{ + va_list va; + int i, r; + + va_start(va, format); + for (i = 0; i < indent; i++) + fprintf(client, " "); + r = vfprintf(client, format, va); + va_end(va); + return r; +} + + +static unsigned int +get_var_stack_offset_32(func_t *func, char *name) +{ + unsigned int offset = 0; + var_t *var; + + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + if (!strcmp(var->name, name)) + return offset; + + if (var->type->type == RPC_FC_DOUBLE || + var->type->type == RPC_FC_HYPER) + offset += 8; + else + offset += 4; + + var = PREV_LINK(var); + } + + return 0; +} + + +static unsigned int +get_var_stack_offset_64(func_t *func, char *name) +{ + unsigned int offset = 0; + var_t *var; + + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + if (!strcmp(var->name, name)) + return offset; + + offset += 8; + + var = PREV_LINK(var); + } + + return 0; +} + + +static unsigned int +get_var_type_offset(var_t *var) +{ + unsigned int toffset = 0; + void *sizeis_attr; + int string_attr; + + if (var->ptr_level == 0) + { + if ((var->type->type == RPC_FC_RP) && + (var->type->ref->ref->type == RPC_FC_STRUCT)) + { + var_t *field = var->type->ref->ref->fields; + int tsize = 9; + + while (NEXT_LINK(field)) field = NEXT_LINK(field); + while (field) + { + tsize++; + field = PREV_LINK(field); + } + if (tsize % 2) + tsize++; + + toffset += tsize; + } + } + else if (var->ptr_level == 1) + { + sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); + string_attr = is_attr(var->attrs, ATTR_STRING); + + if (sizeis_attr) + { + if (string_attr) + { + if (var->type->type == RPC_FC_BYTE || + var->type->type == RPC_FC_CHAR || + var->type->type == RPC_FC_WCHAR) + toffset += 10; + } + else + { + if (is_base_type(var->type)) + toffset += 14; + } + } + else + { + if (is_base_type(var->type)) + toffset += 4; + } + } + + return toffset; +} + + +static type_t *get_type_by_name(func_t *func, char *name) +{ + var_t *var; + + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + if (!strcmp(var->name, name)) + return var->type; + + var = PREV_LINK(var); + } + + return NULL; +} + + +static unsigned char +get_base_type(unsigned char type) +{ + + switch (type) + { + case RPC_FC_USHORT: + type = RPC_FC_SHORT; + break; + + case RPC_FC_ULONG: + type = RPC_FC_LONG; + break; + } + + return type; +} + + +static int get_type_size(type_t *type, int alignment) +{ + int size; + var_t *field; + + switch(type->type) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + size = 1; + size = ((size + alignment - 1) & ~(alignment -1)); + break; + + case RPC_FC_WCHAR: + case RPC_FC_USHORT: + case RPC_FC_SHORT: + size = 2; + size = ((size + alignment - 1) & ~(alignment -1)); + break; + + case RPC_FC_ULONG: + case RPC_FC_LONG: + case RPC_FC_FLOAT: + size = 4; + size = ((size + alignment - 1) & ~(alignment -1)); + break; + + case RPC_FC_HYPER: + case RPC_FC_DOUBLE: + size = 8; + size = ((size + alignment - 1) & ~(alignment -1)); + break; + + case RPC_FC_IGNORE: + size = 0; + break; + + case RPC_FC_STRUCT: + field = type->fields; + size = 0; + while (NEXT_LINK(field)) field = NEXT_LINK(field); + while (field) + { + size += get_type_size(field->type, alignment); + field = PREV_LINK(field); + } + break; + + default: + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, type->type); + return 0; + } + + return size; +} + + +static int get_type_alignment(type_t *type) +{ + int size; + + switch(type->type) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + size = 1; + break; + + case RPC_FC_WCHAR: + case RPC_FC_USHORT: + case RPC_FC_SHORT: + size = 2; + break; + + case RPC_FC_ULONG: + case RPC_FC_LONG: + case RPC_FC_FLOAT: + size = 4; + break; + + case RPC_FC_HYPER: + case RPC_FC_DOUBLE: + size = 8; + break; + + default: + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, type->type); + return 0; + } + + return size; +} + + +static void write_procformatstring(type_t *iface) +{ + func_t *func = iface->funcs; + var_t *var; + unsigned int type_offset = 2; + int in_attr, out_attr; + + print_client("const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n"); + print_client("{\n"); + indent++; + print_client("0,\n"); + print_client("{\n"); + indent++; + + while (NEXT_LINK(func)) func = NEXT_LINK(func); + while (func) + { + /* emit argument data */ + if (func->args) + { + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + out_attr = is_attr(var->attrs, ATTR_OUT); + in_attr = is_attr(var->attrs, ATTR_IN); + + /* set 'in' attribute if neither 'in' nor 'out' is set */ + if (!out_attr && !in_attr) + in_attr = 1; + + if (var->ptr_level == 0) + { + if (is_base_type(var->type)) + { + print_client("0x4e, /* FC_IN_PARAM_BASETYPE */\n"); + print_client("0x%02x, /* FC_<type> */\n", get_base_type(var->type->type)); + } + else if (var->type->type == RPC_FC_RP) + { + if (in_attr & !out_attr) + print_client("0x4d, /* FC_IN_PARAM */\n"); + else if (!in_attr & out_attr) + print_client("0x51, /* FC_OUT_PARAM */\n"); + else if (in_attr & out_attr) + print_client("0x50, /* FC_IN_OUT_PARAM */\n"); + fprintf(client, "#ifndef _ALPHA_\n"); + print_client("0x01,\n"); + fprintf(client, "#else\n"); + print_client("0x02,\n"); + fprintf(client, "#endif\n"); + print_client("NdrFcShort(0x%x),\n", type_offset); + } + else + { + print_client("0x4d, /* FC_IN_PARAM */\n"); + + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, var->type->type); + return; + } + } + else if (var->ptr_level == 1) + { +// if (is_base_type(var->type)) +// { + if (in_attr & !out_attr) + print_client("0x4d, /* FC_IN_PARAM */\n"); + else if (!in_attr & out_attr) + print_client("0x51, /* FC_OUT_PARAM */\n"); + else if (in_attr & out_attr) + print_client("0x50, /* FC_IN_OUT_PARAM */\n"); + fprintf(client, "#ifndef _ALPHA_\n"); + print_client("0x01,\n"); + fprintf(client, "#else\n"); + print_client("0x02,\n"); + fprintf(client, "#endif\n"); + print_client("NdrFcShort(0x%x),\n", type_offset); +// } +// else +// { +// error("%s:%d Unknown/unsupported type 0x%x\n", +// __FUNCTION__,__LINE__, var->type->type); +// return; +// } + } + else + { + error("%s:%d Pointer level %d is not supported!\n", + __FUNCTION__,__LINE__, var->ptr_level); + return; + } + + type_offset += get_var_type_offset(var); + + var = PREV_LINK(var); + } + } + + /* emit return value data */ + var = func->def; + if (is_void(var->type, NULL)) + { + print_client("0x5b, /* FC_END */\n"); + print_client("0x5c, /* FC_PAD */\n"); + } + else if (is_base_type(var->type)) + { + print_client("0x53, /* FC_RETURN_PARAM_BASETYPE */\n"); + print_client("0x%02x, /* FC_<type> */\n", get_base_type(var->type->type)); + } + else + { + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, var->type->type); + return; + } + + func = PREV_LINK(func); + } + + print_client("0x0\n"); + indent--; + print_client("}\n"); + indent--; + print_client("};\n"); + print_client("\n"); +} + + +static void write_typeformatstring(type_t *iface) +{ + func_t *func = iface->funcs; + var_t *var; + type_t *type; + int in_attr, out_attr; + int string_attr; + int ptr_attr, ref_attr, unique_attr; + void *sizeis_attr; + + print_client("const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =\n"); + print_client("{\n"); + indent++; + print_client("0,\n"); + print_client("{\n"); + indent++; + print_client("NdrFcShort(0x00),\n"); + + while (NEXT_LINK(func)) func = NEXT_LINK(func); + while (func) + { + if (func->args) + { + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + in_attr = is_attr(var->attrs, ATTR_IN); + out_attr = is_attr(var->attrs, ATTR_OUT); + string_attr = is_attr(var->attrs, ATTR_STRING); + + if (var->ptr_level > 1) + { + error("Function '%s' argument '%s': Pointer level %d not supported!\n", + func->def->name, var->name, var->ptr_level); + return; + } + + if (var->ptr_level == 0) + { + if (!is_base_type(var->type)) + { + if (var->type->type == RPC_FC_RP) + { + var_t *field; + int tsize = 9; + unsigned char flags = 0; + + if (!in_attr && out_attr) + flags |= RPC_FC_P_ONSTACK; + + print_client("0x11, 0x%02X, /* FC_RP, [flags] */\n", flags); + print_client("NdrFcShort(0x%02X),\n", 0x02); + print_client("0x%02X,\n", var->type->ref->ref->type); + print_client("0x%02X,\n", 3); /* alignment -1 */ + print_client("NdrFcShort(0x%02X),\n", get_type_size(var->type->ref->ref, 4)); + + field = var->type->ref->ref->fields; + while (NEXT_LINK(field)) field = NEXT_LINK(field); + while (field) + { + print_client("0x%02X,\n", get_base_type(field->type->type)); + tsize++; + field = PREV_LINK(field); + } + if (tsize % 2) + { + print_client("0x5c, /* FC_PAD */\n"); + tsize++; + } + print_client("0x5b, /* FC_END */\n"); + } + else + { + + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, var->type->type); + return; + } + } + } + else if (var->ptr_level == 1) + { + ptr_attr = is_attr(var->attrs, ATTR_PTR); + ref_attr = is_attr(var->attrs, ATTR_REF); + unique_attr = is_attr(var->attrs, ATTR_UNIQUE); + sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); + + if (ptr_attr + ref_attr + unique_attr == 0) + ref_attr = 1; + + if (sizeis_attr) + { + unsigned char type_type = 0; + + type = get_type_by_name(func, ((var_t *)sizeis_attr)->name); + if (type != NULL) + type_type = type->type; + + print_client("0x11, 0x00, /* FC_RP */\n"); + print_client("NdrFcShort(0x02),\n"); + + if (string_attr) + { + if (var->type->type == RPC_FC_WCHAR) + print_client("0x25, /* FC_C_WSTRING */\n"); + else + print_client("0x22, /* FC_C_CSTRING */\n"); + print_client("0x44, /* FC_STRING_SIZED */\n"); + print_client("0x%02x,\n", 0x20 + type_type); + print_client("0x00,\n"); + + fprintf(client, "#ifndef _ALPHA_\n"); + print_client("NdrFcShort(0x%02X),\n", + get_var_stack_offset_32(func, ((var_t *)sizeis_attr)->name)); + fprintf(client, "#else\n"); + print_client("NdrFcShort(0x%02X),\n", + get_var_stack_offset_64(func, ((var_t *)sizeis_attr)->name)); + fprintf(client, "#endif\n"); + } + else + { + print_client("0x1b, /* FC_CARRAY */\n"); + print_client("0x%02x,\n", get_type_alignment(var->type) - 1); + print_client("NdrFcShort(0x%02x),\n", get_type_size(var->type, 1)); + print_client("0x%02x,\n", 0x20 + type_type); + if (out_attr) + print_client("0x54, /* FC_DEREFERENCE */\n"); + else + print_client("0x00, /* */\n"); + + fprintf(client, "#ifndef _ALPHA_\n"); + print_client("NdrFcShort(0x%02X),\n", + get_var_stack_offset_32(func, ((var_t *)sizeis_attr)->name)); + fprintf(client, "#else\n"); + print_client("NdrFcShort(0x%02X),\n", + get_var_stack_offset_64(func, ((var_t *)sizeis_attr)->name)); + fprintf(client, "#endif\n"); + print_client("0x%02x,\n", get_base_type(var->type->type)); + print_client("0x5b, /* FC_END */\n"); + } + } + else if (is_base_type(var->type)) + { + if (out_attr && !in_attr) + { + if (ref_attr) + print_client("0x11, 0x0c, /* FC_RP [allocated_on_stack] [simple_pointer] */\n"); + else if (unique_attr) + print_client("0x12, 0x0c, /* FC_FP [allocated_on_stack] [simple_pointer] */\n"); + else if (ptr_attr) + print_client("0x14, 0x0c, /* FC_FP [allocated_on_stack] [simple_pointer] */\n"); + } + else + { + if (ref_attr) + print_client("0x11, 0x08, /* FC_RP [simple_pointer] */\n"); + else if (unique_attr) + print_client("0x12, 0x08, /* FC_UP [simple_pointer] */\n"); + else if (ptr_attr) + print_client("0x14, 0x08, /* FC_FP [simple_pointer] */\n"); + } + + if (string_attr) + { + if (var->type->type == RPC_FC_CHAR) + print_client("0x%02x, /* FC_C_CSTRING */\n", RPC_FC_C_CSTRING); + else if (var->type->type == RPC_FC_WCHAR) + print_client("0x%02x, /* FC_C_WSTRING */\n", RPC_FC_C_WSTRING); + else + { + error("%s: Invalid type!\n", __FUNCTION__); + return; + } + } + else + print_client("0x%02x, /* FC_<type> */\n", get_base_type(var->type->type)); + print_client("0x5c, /* FC_PAD */\n"); + } + } + + var = PREV_LINK(var); + } + } + + func = PREV_LINK(func); + } + + print_client("0x0\n"); + indent--; + print_client("}\n"); + indent--; + print_client("};\n"); + print_client("\n"); +} + + +static void print_message_buffer_size(func_t *func, unsigned int *type_offset) +{ + unsigned int local_type_offset = *type_offset; + unsigned int alignment; + int size; + int last_size = -1; + int in_attr; + int out_attr; + int string_attr; + int nothing_printed = 1; + int ptr_attr, ref_attr, unique_attr; + int padding = 0, first_padding = 0; + void *sizeis_attr; + var_t *var; + + print_client("_StubMsg.BufferLength ="); + if (func->args) + { + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + for (; var; var = PREV_LINK(var)) + { + out_attr = is_attr(var->attrs, ATTR_OUT); + in_attr = is_attr(var->attrs, ATTR_IN); + + /* set 'in' attribute if neither 'in' nor 'out' is found */ + if (!out_attr && !in_attr) + in_attr = 1; + + ptr_attr = is_attr(var->attrs, ATTR_PTR); + ref_attr = is_attr(var->attrs, ATTR_REF); + unique_attr = is_attr(var->attrs, ATTR_UNIQUE); + + /* default to 'ref' attribute */ + if (ptr_attr + ref_attr + unique_attr == 0) + ref_attr = 1; + + if (!in_attr) + continue; + + string_attr = is_attr(var->attrs, ATTR_STRING); + sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); + + if (var->ptr_level == 1) + { + if (string_attr && !sizeis_attr) + { + /* non-sized conformant string */ + if (var->type->type == RPC_FC_CHAR || var->type->type == RPC_FC_WCHAR) + { + size = (unique_attr) ? 16 : 12; + alignment = 0; + } + } + else if (sizeis_attr && !string_attr) + { + /* conformant arrays */ + size = 4; + alignment = 0; + if (padding != 0) + padding = 1; + } + else if (!sizeis_attr && !string_attr) + { + /* simple pointers */ + if (is_base_type(var->type)) + { + alignment = 0; + switch (var->type->type) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + size = 1; + alignment = 0; + break; + + case RPC_FC_WCHAR: + case RPC_FC_USHORT: + case RPC_FC_SHORT: + size = 2; + if (last_size > 0 && last_size < 2) + alignment += (2 - last_size); + break; + + case RPC_FC_ULONG: + case RPC_FC_LONG: + case RPC_FC_FLOAT: + size = 4; + if (last_size > 0 && last_size < 4) + alignment += (4 - last_size); + break; + + case RPC_FC_HYPER: + case RPC_FC_DOUBLE: + size = 8; + if (last_size > 0 && last_size < 4) + alignment += (4 - last_size); + break; + + case RPC_FC_IGNORE: + size = 0; + break; + + default: + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, var->type->type); + return; + } + } + else + { + /* simple pointer to a struct */ + size = 8; + alignment = 0; + } + } + } + else + { + alignment = 0; + switch (var->type->type) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + size = 1; + alignment = 0; + break; + + case RPC_FC_WCHAR: + case RPC_FC_USHORT: + case RPC_FC_SHORT: + size = 2; + if (last_size > 0 && last_size < 2) + alignment += (2 - last_size); + break; + + case RPC_FC_ULONG: + case RPC_FC_LONG: + case RPC_FC_FLOAT: + size = 4; + if (last_size > 0 && last_size < 4) + alignment += (4 - last_size); + break; + + case RPC_FC_HYPER: + case RPC_FC_DOUBLE: + size = 8; + if (last_size > 0 && last_size < 4) + alignment += (4 - last_size); + break; + + case RPC_FC_IGNORE: + size = 0; + break; + + case RPC_FC_RP: + case RPC_FC_UP: + case RPC_FC_FP: + size = 0; + break; + + default: + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, var->type->type); + return; + } + } + + if (last_size != -1) + fprintf(client, " +"); + fprintf(client, " %dU", (size == 0) ? 0 : size + alignment + first_padding + padding); + nothing_printed = 0; + if (first_padding != 0) + first_padding = 0; + + /* set paddings */ + if (var->ptr_level == 1) + { + if (string_attr && !sizeis_attr) + { + /* non-sized conformant string */ + if (var->type->type == RPC_FC_CHAR || var->type->type == RPC_FC_WCHAR) + { + first_padding = 3; + padding = 3; + } + } + else if (sizeis_attr && !string_attr) + { + /* conformant arrays */ + first_padding = 4; + padding = 3; + } + } + + last_size = size; + } + } + + if (nothing_printed) + { + fprintf(client, " 0U"); + } + fprintf(client, ";\n"); + + /* get string size */ + if (func->args) + { + nothing_printed = 0; + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + for (; var; var = PREV_LINK(var)) + { + out_attr = is_attr(var->attrs, ATTR_OUT); + in_attr = is_attr(var->attrs, ATTR_IN); + + /* default to 'in' attribute */ + if (!out_attr && !in_attr) + in_attr = 1; + + ptr_attr = is_attr(var->attrs, ATTR_PTR); + ref_attr = is_attr(var->attrs, ATTR_REF); + unique_attr = is_attr(var->attrs, ATTR_UNIQUE); + + /* default to 'ref' attribute */ + if (ptr_attr + ref_attr + unique_attr == 0) + ref_attr = 1; + + string_attr = is_attr(var->attrs, ATTR_STRING); + sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); + + if (in_attr) + { + if (var->ptr_level == 0) + { + if (var->type->type == RPC_FC_RP && + var->type->ref->ref->type == RPC_FC_STRUCT) + { + print_client("NdrSimpleStructBufferSize(\n"); + indent++; + print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_client("(unsigned char __RPC_FAR *)%s,\n", var->name); + print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", + local_type_offset + 4); + nothing_printed = 1; + indent--; + } + } + else if (var->ptr_level == 1) + { + if (string_attr) + { + if ((var->type->type == RPC_FC_CHAR || + var->type->type == RPC_FC_WCHAR)) + { + if (ptr_attr) + { + /* FIXME: not supported yet */ + } + if (ref_attr) + { + print_client("NdrConformantStringBufferSize(\n"); + indent++; + print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_client("(unsigned char __RPC_FAR *)%s,\n", var->name); + print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", + local_type_offset + 2); + nothing_printed = 1; + indent--; + } + else if (unique_attr) + { + print_client("NdrPointerBufferSize(\n"); + indent++; + print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_client("(unsigned char __RPC_FAR *)%s,\n", var->name); + print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", + local_type_offset); + nothing_printed = 1; + indent--; + } + } + } + else + { + if (sizeis_attr) + { + fprintf(client, "\n"); + print_client("_StubMsg.MaxCount = %s;\n", + ((var_t *)sizeis_attr)->name); + fprintf(client, "\n"); + + print_client("NdrConformantArrayBufferSize(\n"); + indent++; + print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_client("(unsigned char __RPC_FAR *)%s,\n", var->name); + print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", + local_type_offset + 4); + indent--; + nothing_printed = 1; + } + } + } + } + + /* calculate the next type offset */ + local_type_offset += get_var_type_offset(var); + } + + if (nothing_printed) + fprintf(client, "\n"); + } +} + + +static void marshall_in_arguments(func_t *func, unsigned int *type_offset) +{ + unsigned int local_type_offset = *type_offset; + unsigned int alignment; + unsigned int size; + unsigned int last_size = 0; + int in_attr; + int out_attr; + int string_attr; + int ptr_attr, ref_attr, unique_attr; + void *sizeis_attr; + var_t *var; + + if (!func->args) + return; + + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + for (; var; var = PREV_LINK(var)) + { + out_attr = is_attr(var->attrs, ATTR_OUT); + in_attr = is_attr(var->attrs, ATTR_IN); + + /* set 'in' attribute if neither 'in' nor 'out' is set */ + if (!out_attr && !in_attr) + in_attr = 1; + + if (in_attr) + { + if (var->ptr_level > 1) + { + error("Function '%s' argument '%s': Pointer level %d not supported!\n", + func->def->name, var->name, var->ptr_level); + return; + } + + if (var->ptr_level == 1) + { + ptr_attr = is_attr(var->attrs, ATTR_PTR); + ref_attr = is_attr(var->attrs, ATTR_REF); + unique_attr = is_attr(var->attrs, ATTR_UNIQUE); + if (ptr_attr + ref_attr + unique_attr == 0) + ref_attr = 1; + + string_attr = is_attr(var->attrs, ATTR_STRING); + sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); + + if (sizeis_attr) + { + print_client("_StubMsg.MaxCount = %s;\n", + ((var_t *)sizeis_attr)->name); + fprintf(client, "\n"); + + print_client("NdrConformantArrayMarshall(\n"); + indent++; + print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_client("(unsigned char __RPC_FAR *)%s,\n", var->name); + print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", + local_type_offset + 4); + indent--; + fprintf(client, "\n"); + print_client("_StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~0x3);\n"); + fprintf(client, "\n"); + } + else if (ref_attr) + { + if (string_attr && + (var->type->type == RPC_FC_CHAR || var->type->type == RPC_FC_WCHAR)) + { + print_client("NdrConformantStringMarshall(\n"); + indent++; + print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_client("(unsigned char __RPC_FAR *)%s,\n", var->name); + print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", + local_type_offset + 2); + indent--; + fprintf(client, "\n"); + print_client("_StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~0x3);\n"); + fprintf(client, "\n"); + } + else + { + alignment = 0; + switch (var->type->type) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + size = 1; + alignment = 0; + break; + + case RPC_FC_WCHAR: + case RPC_FC_USHORT: + case RPC_FC_SHORT: + size = 2; + if (last_size > 0 && last_size < 2) + alignment = (2 - last_size); + break; + + case RPC_FC_ULONG: + case RPC_FC_LONG: + case RPC_FC_FLOAT: + size = 4; + if (last_size > 0 && last_size < 4) + alignment = (4 - last_size); + break; + + case RPC_FC_HYPER: + case RPC_FC_DOUBLE: + size = 8; + if (last_size > 0 && last_size < 4) + alignment = (4 - last_size); + break; + + case RPC_FC_IGNORE: + size = 0; + break; + + default: + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, var->type->type); + return; + } + + if (size != 0) + { + if (alignment != 0) + print_client("_StubMsg.Buffer += %u;\n", alignment); + + print_client("*(("); + write_type(client, var->type, NULL, var->tname); + fprintf(client, " __RPC_FAR*)_StubMsg.Buffer) = "); + if (var->ptr_level == 1) + fprintf(client, "*"); + write_name(client, var); + fprintf(client, ";\n"); + print_client("_StubMsg.Buffer += sizeof("); + write_type(client, var->type, NULL, var->tname); + fprintf(client, ");\n"); + fprintf(client, "\n"); + + last_size = size; + } + } + } + else if (unique_attr) + { + print_client("NdrPointerMarshall(\n"); + indent++; + print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_client("(unsigned char __RPC_FAR *)%s,\n", var->name); + print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", + local_type_offset); + indent--; + fprintf(client, "\n"); + } + } + else + { + if (is_base_type(var->type)) + { + alignment = 0; + switch (var->type->type) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + size = 1; + alignment = 0; + break; + + case RPC_FC_WCHAR: + case RPC_FC_USHORT: + case RPC_FC_SHORT: + size = 2; + if (last_size > 0 && last_size < 2) + alignment = (2 - last_size); + break; + + case RPC_FC_ULONG: + case RPC_FC_LONG: + case RPC_FC_FLOAT: + size = 4; + if (last_size > 0 && last_size < 4) + alignment = (4 - last_size); + break; + + case RPC_FC_HYPER: + case RPC_FC_DOUBLE: + size = 8; + if (last_size > 0 && last_size < 4) + alignment = (4 - last_size); + break; + + case RPC_FC_IGNORE: + size = 0; + break; + + default: + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, var->type->type); + return; + } + + if (size != 0) + { + if (alignment != 0) + print_client("_StubMsg.Buffer += %u;\n", alignment); + + print_client("*(("); + write_type(client, var->type, NULL, var->tname); + fprintf(client, " __RPC_FAR*)_StubMsg.Buffer) = "); + if (var->ptr_level == 1) + fprintf(client, "*"); + write_name(client, var); + fprintf(client, ";\n"); + print_client("_StubMsg.Buffer += sizeof("); + write_type(client, var->type, NULL, var->tname); + fprintf(client, ");\n"); + fprintf(client, "\n"); + + last_size = size; + } + } + else if (var->type->type == RPC_FC_RP) + { + if (var->type->ref->ref->type == RPC_FC_STRUCT) + { + print_client("NdrSimpleStructMarshall(\n"); + indent++; + print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_client("(unsigned char __RPC_FAR *)%s,\n", var->name); + print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", + local_type_offset + 4); + indent--; + fprintf(client, "\n"); + } + } + } + } + + /* calculate the next type offset */ + local_type_offset += get_var_type_offset(var); + } +} + + +static void unmarshall_out_arguments(func_t *func, unsigned int *type_offset) +{ + unsigned int alignment; + unsigned int size; + unsigned int last_size = 0; + int out_attr; + int string_attr; + void *sizeis_attr; + var_t *var; + var_t *def; + unsigned int local_type_offset = *type_offset; + + def = func->def; + + /* unmarshall the out arguments */ + if (func->args) + { + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + for (; var; var = PREV_LINK(var)) + { + out_attr = is_attr(var->attrs, ATTR_OUT); + sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); + string_attr = is_attr(var->attrs, ATTR_STRING); + + if (out_attr) + { + if (var->ptr_level > 1) + { + error("Function '%s' argument '%s': Pointer level %d not supported!\n", + func->def->name, var->name, var->ptr_level); + return; + } + + if (sizeis_attr != NULL) + { + if (string_attr) + { + fprintf(client, "\n"); + print_client("NdrConformantStringUnmarshall(\n"); + indent++; + print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_client("(unsigned char __RPC_FAR * __RPC_FAR *)&%s,\n", var->name); + print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u],\n", + local_type_offset + 4); + print_client("(unsigned char)0);\n"); + indent--; + fprintf(client, "\n"); + print_client("_StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~0x3);\n"); + fprintf(client, "\n"); + } + else + { + fprintf(client, "\n"); + print_client("NdrConformantArrayUnmarshall(\n"); + indent++; + print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_client("(unsigned char __RPC_FAR * __RPC_FAR *)&%s,\n", var->name); + print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u],\n", + local_type_offset + 4); + print_client("(unsigned char)0);\n"); + indent--; + fprintf(client, "\n"); + print_client("_StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~0x3);\n"); + fprintf(client, "\n"); + } + } + else if (is_base_type(var->type)) + { + alignment = 0; + switch (var->type->type) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + size = 1; + alignment = 0; + break; + + case RPC_FC_WCHAR: + case RPC_FC_USHORT: + case RPC_FC_SHORT: + size = 2; + if (last_size > 0 && last_size < 2) + alignment = (2 - last_size); + break; + + case RPC_FC_ULONG: + case RPC_FC_LONG: + case RPC_FC_FLOAT: + size = 4; + if (last_size > 0 && last_size < 4) + alignment = (4 - last_size); + break; + + case RPC_FC_HYPER: + case RPC_FC_DOUBLE: + size = 8; + if (last_size > 0 && last_size < 4) + alignment = (4 - last_size); + break; + + case RPC_FC_IGNORE: + size = 0; + break; + + default: + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, var->type->type); + return; + } + + if (size != 0) + { + if (var->ptr_level == 1) + { + fprintf(client, "\n"); + if (alignment != 0) + print_client("_StubMsg.Buffer += %u;\n", alignment); + + print_client("*"); + write_name(client, var); + fprintf(client, " = *(("); + write_type(client, var->type, NULL, var->tname); + fprintf(client, " __RPC_FAR *)_StubMsg.Buffer);\n"); + + print_client("_StubMsg.Buffer += sizeof("); + write_type(client, var->type, NULL, var->tname); + fprintf(client, ");\n"); + } + + last_size = size; + } + } + else if (var->type->type == RPC_FC_RP) + { + if (var->type->ref->ref->type == RPC_FC_STRUCT) + { + fprintf(client, "\n"); + print_client("NdrSimpleStructUnmarshall(\n"); + indent++; + print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_client("(unsigned char __RPC_FAR * __RPC_FAR *)&%s,\n", var->name); + print_client("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u],\n", + local_type_offset + 4); + print_client("(unsigned char)0);\n"); + indent--; + fprintf(client, "\n"); + } + } + else + { + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, var->type->type); + return; + } + } + + /* calculate the next type offset */ + local_type_offset += get_var_type_offset(var); + } + } + + /* unmarshall return value */ + if (!is_void(def->type, NULL)) + { + alignment = 0; + switch (def->type->type) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + case RPC_FC_WCHAR: + case RPC_FC_USHORT: + case RPC_FC_SHORT: + case RPC_FC_ULONG: + case RPC_FC_LONG: + case RPC_FC_FLOAT: + size = 4; + if (last_size > 0 && last_size < 4) + alignment = (4 - last_size); + break; + + case RPC_FC_HYPER: + case RPC_FC_DOUBLE: + size = 8; + if (last_size > 0 && last_size < 4) + alignment = (4 - last_size); + break; + + default: + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, var->type->type); + return; + } + + fprintf(client, "\n"); + if (alignment != 0) + print_client("_StubMsg.Buffer += %u;\n", alignment); + print_client("_RetVal = *(("); + write_type(client, def->type, def, def->tname); + fprintf(client, " __RPC_FAR *)_StubMsg.Buffer);\n"); + + print_client("_StubMsg.Buffer += sizeof("); + write_type(client, def->type, def, def->tname); + fprintf(client, ");\n"); + } +} + + +static void check_pointers(func_t *func) +{ + var_t *var; + int ptr_attr; + int ref_attr; + int unique_attr; + + if (!func->args) + return; + + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + ptr_attr = is_attr(var->attrs, ATTR_PTR); + ref_attr = is_attr(var->attrs, ATTR_REF); + unique_attr = is_attr(var->attrs, ATTR_UNIQUE); + + if (var->ptr_level == 0) + { + if (ptr_attr + ref_attr + unique_attr != 0) + { + error("The attributes [ptr], [ref] and [unique] can only be used for pointers!\n"); + return; + } + } + else + { + /* default to 'ref' attribute */ + if (ptr_attr + ref_attr + unique_attr == 0) + { + ref_attr = 1; + } + + if (ptr_attr + ref_attr + unique_attr > 1) + { + error("The attributes [ptr], [ref] and [unique] are mutually exclusive!\n"); + return; + } + + if (var->ptr_level == 1) + { + if (ref_attr) + { + print_client("if (!%s)\n", var->name); + print_client("{\n"); + indent++; + print_client("RpcRaiseException(RPC_X_NULL_REF_POINTER);\n"); + indent--; + print_client("}\n"); + fprintf(client, "\n"); + } + } + else if (var->ptr_level > 1) + { + error("Pointer level %d not supported!\n", var->ptr_level); + return; + } + } + + var = PREV_LINK(var); + } +} + + +static int use_return_buffer(func_t *func) +{ + var_t *var; + + if (!is_void(func->def->type, NULL)) + return 1; + + if (!func->args) + return 0; + + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + if (is_attr(var->attrs, ATTR_OUT)) + return 1; + + var = PREV_LINK(var); + } + + return 0; +} + + +static void write_function_stubs(type_t *iface) +{ + char *implicit_handle = get_attrp(iface->attrs, ATTR_IMPLICIT_HANDLE); + int explicit_handle = is_attr(iface->attrs, ATTR_EXPLICIT_HANDLE); + func_t *func = iface->funcs; + var_t* var; + var_t* explicit_handle_var; + int method_count = 0; + unsigned int proc_offset = 0; + unsigned int type_offset = 2; + + while (NEXT_LINK(func)) func = NEXT_LINK(func); + while (func) + { + var_t *def = func->def; + + /* check for a defined binding handle */ + explicit_handle_var = get_explicit_handle_var(func); + if (explicit_handle) + { + if (!explicit_handle_var) + { + error("%s() does not define an explicit binding handle!\n", def->name); + return; + } + } + else + { + if (explicit_handle_var) + { + error("%s() must not define a binding handle!\n", def->name); + return; + } + } + + write_type(client, def->type, def, def->tname); + fprintf(client, " "); + write_name(client, def); + fprintf(client, "(\n"); + indent++; + write_args(client, func->args, iface->name, 0, TRUE); + fprintf(client, ")\n"); + indent--; + + /* write the functions body */ + fprintf(client, "{\n"); + indent++; + + /* declare return value '_RetVal' */ + if (!is_void(def->type, NULL)) + { + print_client(""); + write_type(client, def->type, def, def->tname); + fprintf(client, " _RetVal;\n"); + } + + if (implicit_handle || explicit_handle) + print_client("RPC_BINDING_HANDLE _Handle = 0;\n"); + print_client("RPC_MESSAGE _RpcMessage;\n"); + print_client("MIDL_STUB_MESSAGE _StubMsg;\n"); + fprintf(client, "\n"); + + /* check pointers */ + check_pointers(func); + + print_client("RpcTryFinally\n"); + print_client("{\n"); + indent++; + + print_client("NdrClientInitializeNew(\n"); + indent++; + print_client("(PRPC_MESSAGE)&_RpcMessage,\n"); + print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_client("(PMIDL_STUB_DESC)&%s_StubDesc,\n", iface->name); + print_client("%d);\n", method_count); + indent--; + fprintf(client, "\n"); + + if (implicit_handle) + { + print_client("_Handle = %s;\n", implicit_handle); + fprintf(client, "\n"); + } + else if (explicit_handle) + { + print_client("_Handle = %s;\n", explicit_handle_var->name); + fprintf(client, "\n"); + } + + /* emit the message buffer size */ + print_message_buffer_size(func, &type_offset); + + print_client("NdrGetBuffer(\n"); + indent++; + print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_client("_StubMsg.BufferLength,\n"); + if (implicit_handle || explicit_handle) + print_client("_Handle);\n"); + else + print_client("%s__MIDL_AutoBindHandle);\n", iface->name); + indent--; + fprintf(client, "\n"); + + /* marshal in arguments */ + marshall_in_arguments(func, &type_offset); + + /* send/recieve message */ + print_client("NdrSendReceive(\n"); + indent++; + print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_client("(unsigned char __RPC_FAR *)_StubMsg.Buffer);\n"); + indent--; + + if (use_return_buffer(func)) + { + /* convert data representation */ + fprintf(client, "\n"); + print_client("if ((_RpcMessage.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)\n"); + indent++; + print_client("NdrConvert(\n"); + indent++; + print_client("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_client("(PFORMAT_STRING)&__MIDL_ProcFormatString.Format[%u]);\n", proc_offset); + indent -= 2; + + /* unmarshal out arguments */ + unmarshall_out_arguments(func, &type_offset); + } + + /* update type_offset */ + if (func->args) + { + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + type_offset += get_var_type_offset(var); + + var = PREV_LINK(var); + } + } + + /* update proc_offset */ + if (func->args) + { + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + switch (var->ptr_level) + { + case 0: + if (is_base_type(var->type)) + proc_offset += 2; + break; + + case 1: + if (is_base_type(var->type)) + proc_offset += 4; + break; + } + + var = PREV_LINK(var); + } + } + proc_offset += 2; /* FIXME */ + + indent--; + print_client("}\n"); + print_client("RpcFinally\n"); + print_client("{\n"); + indent++; + + + /* FIXME: emit client finally code */ + + print_client("NdrFreeBuffer((PMIDL_STUB_MESSAGE)&_StubMsg);\n"); + + indent--; + print_client("}\n"); + print_client("RpcEndFinally\n"); + + + /* emit return code */ + if (!is_void(def->type, NULL)) + { + fprintf(client, "\n"); + print_client("return _RetVal;\n"); + } + + indent--; + fprintf(client, "}\n"); + fprintf(client, "\n"); + + method_count++; + func = PREV_LINK(func); + } +} + + +static void write_bindinghandledecl(type_t *iface) +{ + if (!get_attrp(iface->attrs, ATTR_IMPLICIT_HANDLE)) + { + print_client("static RPC_BINDING_HANDLE %s__MIDL_AutoBindHandle;\n", iface->name); + fprintf(client, "\n"); + } +} + + +static void write_stubdescdecl(type_t *iface) +{ + print_client("extern const MIDL_STUB_DESC %s_StubDesc;\n", iface->name); + fprintf(client, "\n"); +} + + +static void write_stubdescriptor(type_t *iface) +{ + char *implicit_handle = get_attrp(iface->attrs, ATTR_IMPLICIT_HANDLE); + + print_client("const MIDL_STUB_DESC %s_StubDesc =\n", iface->name); + print_client("{\n"); + indent++; + print_client("(void __RPC_FAR *)& %s___RpcClientInterface,\n", iface->name); + print_client("MIDL_user_allocate,\n"); + print_client("MIDL_user_free,\n"); + if (implicit_handle) + print_client("{&%s},\n", implicit_handle); + else + print_client("{&%s__MIDL_AutoBindHandle},\n", iface->name); + print_client("0,\n"); + print_client("0,\n"); + print_client("0,\n"); + print_client("0,\n"); + print_client("__MIDL_TypeFormatString.Format,\n"); + print_client("1, /* -error bounds_check flag */\n"); + print_client("0x10001, /* Ndr library version */\n"); + print_client("0,\n"); + print_client("0x50100a4, /* MIDL Version 5.1.164 */\n"); + print_client("0,\n"); + print_client("0,\n"); + print_client("0, /* notify & notify_flag routine table */\n"); + print_client("1, /* Flags */\n"); + print_client("0, /* Reserved3 */\n"); + print_client("0, /* Reserved4 */\n"); + print_client("0 /* Reserved5 */\n"); + indent--; + print_client("};\n"); + fprintf(client, "\n"); +} + + +static void write_clientinterfacedecl(type_t *iface) +{ + unsigned long ver = get_attrv(iface->attrs, ATTR_VERSION); + UUID *uuid = get_attrp(iface->attrs, ATTR_UUID); + + print_client("static const RPC_CLIENT_INTERFACE %s___RpcClientInterface =\n", iface->name ); + print_client("{\n"); + indent++; + print_client("sizeof(RPC_CLIENT_INTERFACE),\n"); + print_client("{{0x%08lx,0x%04x,0x%04x,{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x}},{%d,%d}},\n", + uuid->Data1, uuid->Data2, uuid->Data3, uuid->Data4[0], uuid->Data4[1], + uuid->Data4[2], uuid->Data4[3], uuid->Data4[4], uuid->Data4[5], uuid->Data4[6], + uuid->Data4[7], LOWORD(ver), HIWORD(ver)); + print_client("{{0x8a885d04,0x1ceb,0x11c9,{0x9f,0xe8,0x08,0x00,0x2b,0x10,0x48,0x60}},{2,0}},\n"); /* FIXME */ + print_client("0,\n"); + print_client("0,\n"); + print_client("0,\n"); + print_client("0,\n"); + print_client("0,\n"); + print_client("0,\n"); + indent--; + print_client("};\n"); + if (old_names) + print_client("RPC_IF_HANDLE %s_ClientIfHandle = (RPC_IF_HANDLE)& %s___RpcClientInterface;\n", + iface->name, iface->name); + else + print_client("RPC_IF_HANDLE %s_v%d_%d_c_ifspec = (RPC_IF_HANDLE)& %s___RpcClientInterface;\n", + iface->name, LOWORD(ver), HIWORD(ver), iface->name); + fprintf(client, "\n"); +} + + +static void write_formatdesc( const char *str ) +{ + print_client("typedef struct _MIDL_%s_FORMAT_STRING\n", str ); + print_client("{\n"); + indent++; + print_client("short Pad;\n"); + print_client("unsigned char Format[%s_FORMAT_STRING_SIZE];\n", str); + indent--; + print_client("} MIDL_%s_FORMAT_STRING;\n", str); + print_client("\n"); +} + + +static int get_type_format_string_size(type_t *iface) +{ + int size = 3; + func_t *func; + var_t *var; + + /* determine the type format string size */ + func = iface->funcs; + while (NEXT_LINK(func)) func = NEXT_LINK(func); + while (func) + { + /* argument list size */ + if (func->args) + { + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + size += get_var_type_offset(var); + var = PREV_LINK(var); + } + } + + func = PREV_LINK(func); + } + + return size; +} + + +static int get_proc_format_string_size(type_t *iface) +{ + int size = 1; + func_t *func; + var_t *var; + + /* determine the proc format string size */ + func = iface->funcs; + while (NEXT_LINK(func)) func = NEXT_LINK(func); + while (func) + { + /* argument list size */ + if (func->args) + { + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + switch (var->ptr_level) + { + case 0: + if (is_base_type(var->type)) + size += 2; + else if (var->type->type == RPC_FC_RP) + size += 4; + break; + + case 1: + if (is_base_type(var->type)) + size += 4; + break; + } + + var = PREV_LINK(var); + } + } + + /* return value size */ + size += 2; + func = PREV_LINK(func); + } + + return size; +} + + +static void write_formatstringsdecl(type_t *iface) +{ + print_client("#define TYPE_FORMAT_STRING_SIZE %d\n", + get_type_format_string_size(iface)); + + print_client("#define PROC_FORMAT_STRING_SIZE %d\n", + get_proc_format_string_size(iface)); + + fprintf(client, "\n"); + write_formatdesc("TYPE"); + write_formatdesc("PROC"); + fprintf(client, "\n"); + print_client("extern const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString;\n"); + print_client("extern const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString;\n"); + print_client("\n"); +} + + +static void write_implicithandledecl(type_t *iface) +{ + char *implicit_handle = get_attrp(iface->attrs, ATTR_IMPLICIT_HANDLE); + + if (implicit_handle) + { + fprintf(client, "handle_t %s;\n", implicit_handle); + fprintf(client, "\n"); + } +} + + +static void init_client(void) +{ + if (client) return; + if (!(client = fopen(client_name, "w"))) + error("Could not open %s for output\n", client_name); + + print_client("/*** Autogenerated by WIDL %s from %s - Do not edit ***/\n", WIDL_FULLVERSION, input_name); + print_client("#include <string.h>\n"); + print_client("#ifdef _ALPHA_\n"); + print_client("#include <stdarg.h>\n"); + print_client("#endif\n"); + fprintf(client, "\n"); + print_client("#include \"%s\"\n", header_name); + fprintf(client, "\n"); +} + + +void write_client(ifref_t *ifaces) +{ + ifref_t *iface = ifaces; + + if (!do_client) + return; + if (!iface) + return; + END_OF_LIST(iface); + + init_client(); + if (!client) + return; + + while (iface) + { + fprintf(client, "/*****************************************************************************\n"); + fprintf(client, " * %s interface\n", iface->iface->name); + fprintf(client, " */\n"); + fprintf(client, "\n"); + + write_formatstringsdecl(iface->iface); + write_implicithandledecl(iface->iface); + + write_clientinterfacedecl(iface->iface); + write_stubdescdecl(iface->iface); + write_bindinghandledecl(iface->iface); + + write_function_stubs(iface->iface); + write_stubdescriptor(iface->iface); + + print_client("#if !defined(__RPC_WIN32__)\n"); + print_client("#error Invalid build platform for this stub.\n"); + print_client("#endif\n"); + fprintf(client, "\n"); + + write_procformatstring(iface->iface); + write_typeformatstring(iface->iface); + + fprintf(client, "\n"); + + iface = PREV_LINK(iface); + } + + fclose(client); +} diff --git a/reactos/tools/widl/lex.yy.c b/reactos/tools/widl/lex.yy.c index 1003fb4a036..d6120ace03a 100644 --- a/reactos/tools/widl/lex.yy.c +++ b/reactos/tools/widl/lex.yy.c @@ -1,4726 +1,4726 @@ -#line 2 "lex.yy.c" -/* A lexical scanner generated by flex */ - -/* Scanner skeleton version: - * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $ - */ - -#define FLEX_SCANNER -#define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 5 - -#include <stdio.h> - - -/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ -#ifdef c_plusplus -#ifndef __cplusplus -#define __cplusplus -#endif -#endif - - -#ifdef __cplusplus - -#include <stdlib.h> -#include <unistd.h> - -/* Use prototypes in function declarations. */ -#define YY_USE_PROTOS - -/* The "const" storage-class-modifier is valid. */ -#define YY_USE_CONST - -#else /* ! __cplusplus */ - -#if __STDC__ - -#define YY_USE_PROTOS -#define YY_USE_CONST - -#endif /* __STDC__ */ -#endif /* ! __cplusplus */ - -#ifdef __TURBOC__ - #pragma warn -rch - #pragma warn -use -#include <io.h> -#include <stdlib.h> -#define YY_USE_CONST -#define YY_USE_PROTOS -#endif - -#ifdef YY_USE_CONST -#define yyconst const -#else -#define yyconst -#endif - - -#ifdef YY_USE_PROTOS -#define YY_PROTO(proto) proto -#else -#define YY_PROTO(proto) () -#endif - -/* Returned upon end-of-file. */ -#define YY_NULL 0 - -/* Promotes a possibly negative, possibly signed char to an unsigned - * integer for use as an array index. If the signed char is negative, - * we want to instead treat it as an 8-bit unsigned char, hence the - * double cast. - */ -#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) - -/* Enter a start condition. This macro really ought to take a parameter, - * but we do it the disgusting crufty way forced on us by the ()-less - * definition of BEGIN. - */ -#define BEGIN yy_start = 1 + 2 * - -/* Translate the current start state into a value that can be later handed - * to BEGIN to return to the state. The YYSTATE alias is for lex - * compatibility. - */ -#define YY_START ((yy_start - 1) / 2) -#define YYSTATE YY_START - -/* Action number for EOF rule of a given start state. */ -#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) - -/* Special action meaning "start processing a new file". */ -#define YY_NEW_FILE yyrestart( yyin ) - -#define YY_END_OF_BUFFER_CHAR 0 - -/* Size of default input buffer. */ -#define YY_BUF_SIZE 16384 - -typedef struct yy_buffer_state *YY_BUFFER_STATE; - -extern int yyleng; -extern FILE *yyin, *yyout; - -#define EOB_ACT_CONTINUE_SCAN 0 -#define EOB_ACT_END_OF_FILE 1 -#define EOB_ACT_LAST_MATCH 2 - -/* The funky do-while in the following #define is used to turn the definition - * int a single C statement (which needs a semi-colon terminator). This - * avoids problems with code like: - * - * if ( condition_holds ) - * yyless( 5 ); - * else - * do_something_else(); - * - * Prior to using the do-while the compiler would get upset at the - * "else" because it interpreted the "if" statement as being all - * done when it reached the ';' after the yyless() call. - */ - -/* Return all but the first 'n' matched characters back to the input stream. */ - -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - *yy_cp = yy_hold_char; \ - YY_RESTORE_YY_MORE_OFFSET \ - yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ - YY_DO_BEFORE_ACTION; /* set up yytext again */ \ - } \ - while ( 0 ) - -#define unput(c) yyunput( c, yytext_ptr ) - -/* The following is because we cannot portably get our hands on size_t - * (without autoconf's help, which isn't available because we want - * flex-generated scanners to compile on their own). - */ -typedef unsigned int yy_size_t; - - -struct yy_buffer_state - { - FILE *yy_input_file; - - char *yy_ch_buf; /* input buffer */ - char *yy_buf_pos; /* current position in input buffer */ - - /* Size of input buffer in bytes, not including room for EOB - * characters. - */ - yy_size_t yy_buf_size; - - /* Number of characters read into yy_ch_buf, not including EOB - * characters. - */ - int yy_n_chars; - - /* Whether we "own" the buffer - i.e., we know we created it, - * and can realloc() it to grow it, and should free() it to - * delete it. - */ - int yy_is_our_buffer; - - /* Whether this is an "interactive" input source; if so, and - * if we're using stdio for input, then we want to use getc() - * instead of fread(), to make sure we stop fetching input after - * each newline. - */ - int yy_is_interactive; - - /* Whether we're considered to be at the beginning of a line. - * If so, '^' rules will be active on the next match, otherwise - * not. - */ - int yy_at_bol; - - /* Whether to try to fill the input buffer when we reach the - * end of it. - */ - int yy_fill_buffer; - - int yy_buffer_status; -#define YY_BUFFER_NEW 0 -#define YY_BUFFER_NORMAL 1 - /* When an EOF's been seen but there's still some text to process - * then we mark the buffer as YY_EOF_PENDING, to indicate that we - * shouldn't try reading from the input source any more. We might - * still have a bunch of tokens to match, though, because of - * possible backing-up. - * - * When we actually see the EOF, we change the status to "new" - * (via yyrestart()), so that the user can continue scanning by - * just pointing yyin at a new input file. - */ -#define YY_BUFFER_EOF_PENDING 2 - }; - -static YY_BUFFER_STATE yy_current_buffer = 0; - -/* We provide macros for accessing buffer states in case in the - * future we want to put the buffer states in a more general - * "scanner state". - */ -#define YY_CURRENT_BUFFER yy_current_buffer - - -/* yy_hold_char holds the character lost when yytext is formed. */ -static char yy_hold_char; - -static int yy_n_chars; /* number of characters read into yy_ch_buf */ - - -int yyleng; - -/* Points to current character in buffer. */ -static char *yy_c_buf_p = (char *) 0; -static int yy_init = 1; /* whether we need to initialize */ -static int yy_start = 0; /* start state number */ - -/* Flag which is used to allow yywrap()'s to do buffer switches - * instead of setting up a fresh yyin. A bit of a hack ... - */ -static int yy_did_buffer_switch_on_eof; - -void yyrestart YY_PROTO(( FILE *input_file )); - -void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); -void yy_load_buffer_state YY_PROTO(( void )); -YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); -void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); -void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); -void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); -#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) - -YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); -YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); -YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); - -static void *yy_flex_alloc YY_PROTO(( yy_size_t )); -static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); -static void yy_flex_free YY_PROTO(( void * )); - -#define yy_new_buffer yy_create_buffer - -#define yy_set_interactive(is_interactive) \ - { \ - if ( ! yy_current_buffer ) \ - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ - yy_current_buffer->yy_is_interactive = is_interactive; \ - } - -#define yy_set_bol(at_bol) \ - { \ - if ( ! yy_current_buffer ) \ - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ - yy_current_buffer->yy_at_bol = at_bol; \ - } - -#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) - - -#define FLEX_DEBUG -typedef unsigned char YY_CHAR; -FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; -typedef int yy_state_type; - -#define FLEX_DEBUG -extern char *yytext; -#define yytext_ptr yytext -static yyconst short yy_nxt[][256] = - { - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0 - }, - - { - 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, - 10, 8, 9, 9, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 9, 8, 11, 8, 8, 8, 8, 8, - - 8, 8, 8, 8, 8, 8, 8, 8, 12, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 8, 8, - 14, 8, 15, 8, 8, 16, 16, 16, 16, 16, - 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 8, 8, 8, 8, 17, 8, 16, 16, 16, - 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8 - }, - - { - 7, 8, 8, 8, 8, 8, 8, 8, 8, 18, - 10, 8, 18, 18, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 18, 8, 11, 19, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 12, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 8, 8, - 14, 8, 15, 8, 8, 16, 16, 16, 16, 16, - 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, - - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 8, 8, 8, 8, 17, 8, 16, 16, 16, - 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8 - }, - - { - 7, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, - - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 22, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 23, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20 - }, - - { - 7, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 22, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 23, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20 - - }, - - { - 7, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 21, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24 - }, - - { - 7, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 21, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24 - }, - - { - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, - -7, -7, -7, -7, -7, -7 - }, - - { - 7, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -8, -8, -8, -8 - }, - - { - 7, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, - -9, -9, -9, -9, -9, -9 - - }, - - { - 7, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, - -10, -10, -10, -10, -10, -10 - }, - - { - 7, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11 - }, - - { - 7, -12, -12, -12, -12, -12, -12, -12, -12, -12, - -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, - -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, - -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, - -12, -12, -12, -12, -12, -12, -12, -12, 25, 25, - 25, 25, 25, 25, 25, 25, 25, 25, -12, -12, - -12, -12, -12, -12, -12, 26, 26, 26, 26, 26, - 26, -12, -12, -12, -12, -12, -12, -12, -12, -12, - - -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, - -12, -12, -12, -12, -12, -12, -12, 26, 26, 26, - 26, 26, 26, -12, -12, -12, -12, -12, -12, -12, - -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, - 27, -12, -12, -12, -12, -12, -12, -12, -12, -12, - -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, - -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, - -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, - -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, - -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, - - -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, - -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, - -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, - -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, - -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, - -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, - -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, - -12, -12, -12, -12, -12, -12 - }, - - { - 7, -13, -13, -13, -13, -13, -13, -13, -13, -13, - -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, - - -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, - -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, - -13, -13, -13, -13, -13, -13, -13, -13, 25, 25, - 25, 25, 25, 25, 25, 25, 25, 25, -13, -13, - -13, -13, -13, -13, -13, 26, 26, 26, 26, 26, - 26, -13, -13, -13, -13, -13, -13, -13, -13, -13, - -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, - -13, -13, -13, -13, -13, -13, -13, 26, 26, 26, - 26, 26, 26, -13, -13, -13, -13, -13, -13, -13, - -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, - - -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, - -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, - -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, - -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, - -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, - -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, - -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, - -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, - -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, - -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, - - -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, - -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, - -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, - -13, -13, -13, -13, -13, -13 - }, - - { - 7, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - - 28, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14 - - }, - - { - 7, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, 29, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, - -15, -15, -15, -15, -15, -15 - }, - - { - 7, -16, -16, -16, -16, -16, -16, -16, -16, -16, - -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, - -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, - -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, - - -16, -16, -16, -16, -16, -16, -16, -16, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, -16, -16, - -16, -16, -16, -16, -16, 30, 30, 30, 30, 30, - 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, -16, -16, -16, -16, 31, -16, 30, 30, 30, - 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, -16, -16, -16, -16, -16, -16, -16, - -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, - - -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, - -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, - -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, - -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, - -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, - -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, - -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, - -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, - -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, - -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, - - -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, - -16, -16, -16, -16, -16, -16 - }, - - { - 7, -17, -17, -17, -17, -17, -17, -17, -17, -17, - -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, - -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, - -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, - -17, -17, -17, -17, -17, -17, -17, -17, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, -17, -17, - -17, -17, -17, -17, -17, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, -17, -17, -17, -17, 31, -17, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, -17, -17, -17, -17, -17, -17, -17, - -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, - -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, - -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, - -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, - -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, - - -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, - -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, - -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, - -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, - -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, - -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, - -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, - -17, -17, -17, -17, -17, -17 - }, - - { - 7, -18, -18, -18, -18, -18, -18, -18, -18, 32, - -18, -18, 32, 32, -18, -18, -18, -18, -18, -18, - - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, -18, 32, -18, -18, 33, -18, -18, -18, -18, - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, -18, -18, -18, -18, -18 - }, - - { - 7, -19, -19, -19, -19, -19, -19, -19, -19, 34, - -19, -19, 34, 34, -19, -19, -19, -19, -19, -19, - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - -19, -19, 34, -19, -19, -19, -19, -19, -19, -19, - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, - -19, -19, -19, -19, -19, -19 - - }, - - { - 7, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20 - }, - - { - 7, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - - -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, - -21, -21, -21, -21, -21, -21 - }, - - { - 7, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, - -22, -22, -22, -22, -22, -22 - }, - - { - 7, 35, 35, 35, 35, 35, 35, 35, 35, 35, - -23, 35, 35, 35, 35, 35, 35, 35, 35, 35, - - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 36, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 37, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35 - }, - - { - 7, 38, 38, 38, 38, 38, 38, 38, 38, 38, - -24, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38 - - }, - - { - 7, -25, -25, -25, -25, -25, -25, -25, -25, -25, - -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, - -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, - -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, - -25, -25, -25, -25, -25, -25, -25, -25, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, -25, -25, - -25, -25, -25, -25, -25, 40, 40, 40, 40, 40, - 40, -25, -25, -25, -25, -25, -25, -25, -25, -25, - -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, - -25, -25, -25, -25, -25, -25, -25, 40, 40, 40, - - 40, 40, 40, -25, -25, -25, -25, -25, -25, -25, - -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, - -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, - -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, - -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, - -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, - -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, - -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, - -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, - -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, - - -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, - -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, - -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, - -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, - -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, - -25, -25, -25, -25, -25, -25 - }, - - { - 7, -26, -26, -26, -26, -26, -26, -26, -26, -26, - -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, - -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, - -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, - - -26, -26, -26, -26, -26, -26, -26, -26, 40, 40, - 40, 40, 40, 40, 40, 40, 40, 40, -26, -26, - -26, -26, -26, -26, -26, 40, 40, 40, 40, 40, - 40, -26, -26, -26, -26, -26, -26, -26, -26, -26, - -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, - -26, -26, -26, -26, -26, -26, -26, 40, 40, 40, - 40, 40, 40, -26, -26, -26, -26, -26, -26, -26, - -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, - -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, - -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, - - -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, - -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, - -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, - -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, - -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, - -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, - -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, - -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, - -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, - -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, - - -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, - -26, -26, -26, -26, -26, -26 - }, - - { - 7, -27, -27, -27, -27, -27, -27, -27, -27, -27, - -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, - -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, - -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, - -27, -27, -27, -27, -27, -27, -27, -27, 41, 41, - 41, 41, 41, 41, 41, 41, 41, 41, -27, -27, - -27, -27, -27, -27, -27, 41, 41, 41, 41, 41, - 41, -27, -27, -27, -27, -27, -27, -27, -27, -27, - - -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, - -27, -27, -27, -27, -27, -27, -27, 41, 41, 41, - 41, 41, 41, -27, -27, -27, -27, -27, -27, -27, - -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, - -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, - -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, - -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, - -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, - -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, - -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, - - -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, - -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, - -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, - -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, - -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, - -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, - -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, - -27, -27, -27, -27, -27, -27 - }, - - { - 7, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28 - }, - - { - 7, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, -29, -29 - - }, - - { - 7, -30, -30, -30, -30, -30, -30, -30, -30, -30, - -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, - -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, - -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, - -30, -30, -30, -30, -30, -30, -30, -30, 42, 42, - 42, 42, 42, 42, 42, 42, 42, 42, -30, -30, - -30, -30, -30, -30, -30, 42, 42, 42, 42, 42, - 42, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, -30, -30, -30, -30, 31, -30, 42, 42, 42, - - 42, 42, 42, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, -30, -30, -30, -30, -30, -30, -30, - -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, - -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, - -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, - -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, - -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, - -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, - -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, - - -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, - -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, - -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, - -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, - -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, - -30, -30, -30, -30, -30, -30 - }, - - { - 7, -31, -31, -31, -31, -31, -31, -31, -31, -31, - -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, - -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, - -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, - - -31, -31, -31, -31, -31, -31, -31, -31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, -31, -31, - -31, -31, -31, -31, -31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, -31, -31, -31, -31, 31, -31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, -31, -31, -31, -31, -31, -31, -31, - -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, - - -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, - -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, - -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, - -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, - -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, - -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, - -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, - -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, - -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, - -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, - - -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, - -31, -31, -31, -31, -31, -31 - }, - - { - 7, -32, -32, -32, -32, -32, -32, -32, -32, 32, - -32, -32, 32, 32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, 32, -32, -32, 33, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32 - }, - - { - 7, -33, -33, -33, -33, -33, -33, -33, -33, 34, - -33, -33, 34, 34, -33, -33, -33, -33, -33, -33, - - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - -33, -33, 34, -33, -33, -33, -33, -33, -33, -33, - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, - -33, -33, -33, -33, -33, -33 - }, - - { - 7, -34, -34, -34, -34, -34, -34, -34, -34, 34, - -34, -34, 34, 34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, 34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34 - - }, - - { - 7, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35 - }, - - { - 7, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - - -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36 - }, - - { - 7, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37 - }, - - { - 7, 38, 38, 38, 38, 38, 38, 38, 38, 38, - -38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 38, 38, 38 - }, - - { - 7, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39, -39, 43, 43, - 43, 43, 43, 43, 43, 43, 43, 43, -39, -39, - - -39, -39, -39, -39, -39, 44, 44, 44, 44, 44, - 44, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39, 44, 44, 44, - 44, 44, 44, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, - - -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39 - - }, - - { - 7, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40, -40, -40, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, -40, -40, - -40, -40, -40, -40, -40, 44, 44, 44, 44, 44, - 44, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40, -40, 44, 44, 44, - - 44, 44, 44, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, - - -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40 - }, - - { - 7, -41, -41, -41, -41, -41, -41, -41, -41, -41, - -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, - -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, - -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, - - -41, -41, -41, -41, -41, -41, -41, -41, 41, 41, - 41, 41, 41, 41, 41, 41, 41, 41, -41, -41, - -41, -41, -41, -41, -41, 41, 41, 41, 41, 41, - 41, -41, -41, -41, -41, -41, -41, -41, -41, -41, - -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, - -41, -41, -41, -41, -41, -41, -41, 41, 41, 41, - 41, 41, 41, -41, -41, -41, -41, -41, -41, -41, - -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, - -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, - -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, - - -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, - -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, - -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, - -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, - -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, - -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, - -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, - -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, - -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, - -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, - - -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, - -41, -41, -41, -41, -41, -41 - }, - - { - 7, -42, -42, -42, -42, -42, -42, -42, -42, -42, - -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, - -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, - -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, - -42, -42, -42, -42, -42, -42, -42, -42, 45, 45, - 45, 45, 45, 45, 45, 45, 45, 45, -42, -42, - -42, -42, -42, -42, -42, 45, 45, 45, 45, 45, - 45, 31, 31, 31, 31, 31, 31, 31, 31, 31, - - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, -42, -42, -42, -42, 31, -42, 45, 45, 45, - 45, 45, 45, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, -42, -42, -42, -42, -42, -42, -42, - -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, - -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, - -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, - -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, - -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, - - -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, - -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, - -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, - -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, - -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, - -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, - -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, - -42, -42, -42, -42, -42, -42 - }, - - { - 7, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, -43, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, -43, -43, - -43, -43, -43, -43, -43, 47, 47, 47, 47, 47, - 47, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, 47, 47, 47, - 47, 47, 47, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43 - }, - - { - 7, -44, -44, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44, -44, -44, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47, -44, -44, - - -44, -44, -44, -44, -44, 47, 47, 47, 47, 47, - 47, -44, -44, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44, -44, 47, 47, 47, - 47, 47, 47, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, - - -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44 - - }, - - { - 7, -45, -45, -45, -45, -45, -45, -45, -45, -45, - -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, - -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, - -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, - -45, -45, -45, -45, -45, -45, -45, -45, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, -45, -45, - -45, -45, -45, -45, -45, 48, 48, 48, 48, 48, - 48, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, -45, -45, -45, -45, 31, -45, 48, 48, 48, - - 48, 48, 48, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, -45, -45, -45, -45, -45, -45, -45, - -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, - -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, - -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, - -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, - -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, - -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, - -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, - - -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, - -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, - -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, - -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, - -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, - -45, -45, -45, -45, -45, -45 - }, - - { - 7, -46, -46, -46, -46, -46, -46, -46, -46, -46, - -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, - -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, - -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, - - -46, -46, -46, -46, -46, -46, -46, -46, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 49, -46, -46, - -46, -46, -46, -46, -46, 50, 50, 50, 50, 50, - 50, -46, -46, -46, -46, -46, -46, -46, -46, -46, - -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, - -46, -46, -46, -46, -46, -46, -46, 50, 50, 50, - 50, 50, 50, -46, -46, -46, -46, -46, -46, -46, - -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, - -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, - -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, - - -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, - -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, - -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, - -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, - -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, - -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, - -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, - -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, - -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, - -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, - - -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, - -46, -46, -46, -46, -46, -46 - }, - - { - 7, -47, -47, -47, -47, -47, -47, -47, -47, -47, - -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, - -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, - -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, - -47, -47, -47, -47, -47, -47, -47, -47, 50, 50, - 50, 50, 50, 50, 50, 50, 50, 50, -47, -47, - -47, -47, -47, -47, -47, 50, 50, 50, 50, 50, - 50, -47, -47, -47, -47, -47, -47, -47, -47, -47, - - -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, - -47, -47, -47, -47, -47, -47, -47, 50, 50, 50, - 50, 50, 50, -47, -47, -47, -47, -47, -47, -47, - -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, - -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, - -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, - -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, - -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, - -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, - -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, - - -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, - -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, - -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, - -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, - -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, - -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, - -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, - -47, -47, -47, -47, -47, -47 - }, - - { - 7, -48, -48, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, - - -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -48, -48, -48, 51, 51, - 51, 51, 51, 51, 51, 51, 51, 51, -48, -48, - -48, -48, -48, -48, -48, 51, 51, 51, 51, 51, - 51, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, -48, -48, -48, -48, 31, -48, 51, 51, 51, - 51, 51, 51, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - - 31, 31, 31, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, - - -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -48 - }, - - { - 7, -49, -49, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, -49, -49, -49, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, -49, -49, - - -49, -49, -49, -49, -49, 53, 53, 53, 53, 53, - 53, -49, -49, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, -49, -49, 53, 53, 53, - 53, 53, 53, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, - - -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, -49 - - }, - - { - 7, -50, -50, -50, -50, -50, -50, -50, -50, -50, - -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, - -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, - -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, - -50, -50, -50, -50, -50, -50, -50, -50, 53, 53, - 53, 53, 53, 53, 53, 53, 53, 53, -50, -50, - -50, -50, -50, -50, -50, 53, 53, 53, 53, 53, - 53, -50, -50, -50, -50, -50, -50, -50, -50, -50, - -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, - -50, -50, -50, -50, -50, -50, -50, 53, 53, 53, - - 53, 53, 53, -50, -50, -50, -50, -50, -50, -50, - -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, - -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, - -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, - -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, - -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, - -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, - -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, - -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, - -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, - - -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, - -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, - -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, - -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, - -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, - -50, -50, -50, -50, -50, -50 - }, - - { - 7, -51, -51, -51, -51, -51, -51, -51, -51, -51, - -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, - -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, - -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, - - -51, -51, -51, -51, -51, -51, -51, -51, 54, 54, - 54, 54, 54, 54, 54, 54, 54, 54, -51, -51, - -51, -51, -51, -51, -51, 54, 54, 54, 54, 54, - 54, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, -51, -51, -51, -51, 31, -51, 54, 54, 54, - 54, 54, 54, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, -51, -51, -51, -51, -51, -51, -51, - -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, - - -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, - -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, - -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, - -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, - -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, - -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, - -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, - -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, - -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, - -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, - - -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, - -51, -51, -51, -51, -51, -51 - }, - - { - 7, -52, -52, -52, -52, -52, -52, -52, -52, -52, - -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, - -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, - -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, - -52, -52, -52, -52, -52, -52, -52, -52, 55, 55, - 55, 55, 55, 55, 55, 55, 55, 55, -52, -52, - -52, -52, -52, -52, -52, 56, 56, 56, 56, 56, - 56, -52, -52, -52, -52, -52, -52, -52, -52, -52, - - -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, - -52, -52, -52, -52, -52, -52, -52, 56, 56, 56, - 56, 56, 56, -52, -52, -52, -52, -52, -52, -52, - -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, - -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, - -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, - -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, - -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, - -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, - -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, - - -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, - -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, - -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, - -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, - -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, - -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, - -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, - -52, -52, -52, -52, -52, -52 - }, - - { - 7, -53, -53, -53, -53, -53, -53, -53, -53, -53, - -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, - - -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, - -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, - -53, -53, -53, -53, -53, -53, -53, -53, 56, 56, - 56, 56, 56, 56, 56, 56, 56, 56, -53, -53, - -53, -53, -53, -53, -53, 56, 56, 56, 56, 56, - 56, -53, -53, -53, -53, -53, -53, -53, -53, -53, - -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, - -53, -53, -53, -53, -53, -53, -53, 56, 56, 56, - 56, 56, 56, -53, -53, -53, -53, -53, -53, -53, - -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, - - -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, - -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, - -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, - -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, - -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, - -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, - -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, - -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, - -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, - -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, - - -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, - -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, - -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, - -53, -53, -53, -53, -53, -53 - }, - - { - 7, -54, -54, -54, -54, -54, -54, -54, -54, -54, - -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, - -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, - -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, - -54, -54, -54, -54, -54, -54, -54, -54, 57, 57, - 57, 57, 57, 57, 57, 57, 57, 57, -54, -54, - - -54, -54, -54, -54, -54, 57, 57, 57, 57, 57, - 57, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, -54, -54, -54, -54, 31, -54, 57, 57, 57, - 57, 57, 57, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, -54, -54, -54, -54, -54, -54, -54, - -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, - -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, - -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, - - -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, - -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, - -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, - -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, - -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, - -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, - -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, - -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, - -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, - -54, -54, -54, -54, -54, -54 - - }, - - { - 7, -55, -55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, 58, -55, -55, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59, -55, -55, - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, -55 - }, - - { - 7, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - - -56, -56, -56, -56, -56, 58, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - - -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56 - }, - - { - 7, -57, -57, -57, -57, -57, -57, -57, -57, -57, - -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, - -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, - -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, - -57, -57, -57, -57, -57, 58, -57, -57, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, -57, -57, - -57, -57, -57, -57, -57, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, -57, -57, -57, -57, 31, -57, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, -57, -57, -57, -57, -57, -57, -57, - -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, - -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, - -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, - -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, - -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, - - -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, - -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, - -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, - -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, - -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, - -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, - -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, - -57, -57, -57, -57, -57, -57 - }, - - { - 7, -58, -58, -58, -58, -58, -58, -58, -58, -58, - -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, - - -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, - -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, - -58, -58, -58, -58, -58, -58, -58, -58, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, -58, -58, - -58, -58, -58, -58, -58, 60, 60, 60, 60, 60, - 60, -58, -58, -58, -58, -58, -58, -58, -58, -58, - -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, - -58, -58, -58, -58, -58, -58, -58, 60, 60, 60, - 60, 60, 60, -58, -58, -58, -58, -58, -58, -58, - -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, - - -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, - -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, - -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, - -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, - -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, - -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, - -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, - -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, - -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, - -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, - - -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, - -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, - -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, - -58, -58, -58, -58, -58, -58 - }, - - { - 7, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59, -59, -59, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59, -59, -59, - - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -59, -59, -59 - - }, - - { - 7, -60, -60, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -60, -60, -60, -60, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 61, -60, -60, - -60, -60, -60, -60, -60, 61, 61, 61, 61, 61, - 61, -60, -60, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -60, -60, -60, 61, 61, 61, - - 61, 61, 61, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, - - -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -60, -60 - }, - - { - 7, -61, -61, -61, -61, -61, -61, -61, -61, -61, - -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, - -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, - -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, - - -61, -61, -61, -61, -61, -61, -61, -61, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, -61, -61, - -61, -61, -61, -61, -61, 62, 62, 62, 62, 62, - 62, -61, -61, -61, -61, -61, -61, -61, -61, -61, - -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, - -61, -61, -61, -61, -61, -61, -61, 62, 62, 62, - 62, 62, 62, -61, -61, -61, -61, -61, -61, -61, - -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, - -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, - -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, - - -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, - -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, - -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, - -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, - -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, - -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, - -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, - -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, - -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, - -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, - - -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, - -61, -61, -61, -61, -61, -61 - }, - - { - 7, -62, -62, -62, -62, -62, -62, -62, -62, -62, - -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, - -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, - -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, - -62, -62, -62, -62, -62, -62, -62, -62, 63, 63, - 63, 63, 63, 63, 63, 63, 63, 63, -62, -62, - -62, -62, -62, -62, -62, 63, 63, 63, 63, 63, - 63, -62, -62, -62, -62, -62, -62, -62, -62, -62, - - -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, - -62, -62, -62, -62, -62, -62, -62, 63, 63, 63, - 63, 63, 63, -62, -62, -62, -62, -62, -62, -62, - -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, - -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, - -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, - -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, - -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, - -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, - -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, - - -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, - -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, - -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, - -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, - -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, - -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, - -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, - -62, -62, -62, -62, -62, -62 - }, - - { - 7, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, 64, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63 - }, - - { - 7, -64, -64, -64, -64, -64, -64, -64, -64, -64, - -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, - -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, - -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, - -64, -64, -64, -64, -64, -64, -64, -64, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, -64, -64, - - -64, -64, -64, -64, -64, 65, 65, 65, 65, 65, - 65, -64, -64, -64, -64, -64, -64, -64, -64, -64, - -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, - -64, -64, -64, -64, -64, -64, -64, 65, 65, 65, - 65, 65, 65, -64, -64, -64, -64, -64, -64, -64, - -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, - -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, - -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, - -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, - -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, - - -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, - -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, - -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, - -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, - -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, - -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, - -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, - -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, - -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, - -64, -64, -64, -64, -64, -64 - - }, - - { - 7, -65, -65, -65, -65, -65, -65, -65, -65, -65, - -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, - -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, - -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, - -65, -65, -65, -65, -65, -65, -65, -65, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, -65, -65, - -65, -65, -65, -65, -65, 66, 66, 66, 66, 66, - 66, -65, -65, -65, -65, -65, -65, -65, -65, -65, - -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, - -65, -65, -65, -65, -65, -65, -65, 66, 66, 66, - - 66, 66, 66, -65, -65, -65, -65, -65, -65, -65, - -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, - -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, - -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, - -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, - -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, - -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, - -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, - -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, - -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, - - -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, - -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, - -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, - -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, - -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, - -65, -65, -65, -65, -65, -65 - }, - - { - 7, -66, -66, -66, -66, -66, -66, -66, -66, -66, - -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, - -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, - -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, - - -66, -66, -66, -66, -66, -66, -66, -66, 67, 67, - 67, 67, 67, 67, 67, 67, 67, 67, -66, -66, - -66, -66, -66, -66, -66, 67, 67, 67, 67, 67, - 67, -66, -66, -66, -66, -66, -66, -66, -66, -66, - -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, - -66, -66, -66, -66, -66, -66, -66, 67, 67, 67, - 67, 67, 67, -66, -66, -66, -66, -66, -66, -66, - -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, - -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, - -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, - - -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, - -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, - -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, - -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, - -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, - -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, - -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, - -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, - -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, - -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, - - -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, - -66, -66, -66, -66, -66, -66 - }, - - { - 7, -67, -67, -67, -67, -67, -67, -67, -67, -67, - -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, - -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, - -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, - -67, -67, -67, -67, -67, -67, -67, -67, 68, 68, - 68, 68, 68, 68, 68, 68, 68, 68, -67, -67, - -67, -67, -67, -67, -67, 68, 68, 68, 68, 68, - 68, -67, -67, -67, -67, -67, -67, -67, -67, -67, - - -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, - -67, -67, -67, -67, -67, -67, -67, 68, 68, 68, - 68, 68, 68, -67, -67, -67, -67, -67, -67, -67, - -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, - -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, - -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, - -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, - -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, - -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, - -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, - - -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, - -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, - -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, - -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, - -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, - -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, - -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, - -67, -67, -67, -67, -67, -67 - }, - - { - 7, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, 69, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, - -68, -68, -68, -68, -68, -68 - }, - - { - 7, -69, -69, -69, -69, -69, -69, -69, -69, -69, - -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, - -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, - -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, - -69, -69, -69, -69, -69, -69, -69, -69, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 70, -69, -69, - - -69, -69, -69, -69, -69, 70, 70, 70, 70, 70, - 70, -69, -69, -69, -69, -69, -69, -69, -69, -69, - -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, - -69, -69, -69, -69, -69, -69, -69, 70, 70, 70, - 70, 70, 70, -69, -69, -69, -69, -69, -69, -69, - -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, - -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, - -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, - -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, - -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, - - -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, - -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, - -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, - -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, - -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, - -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, - -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, - -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, - -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, - -69, -69, -69, -69, -69, -69 - - }, - - { - 7, -70, -70, -70, -70, -70, -70, -70, -70, -70, - -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, - -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, - -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, - -70, -70, -70, -70, -70, -70, -70, -70, 71, 71, - 71, 71, 71, 71, 71, 71, 71, 71, -70, -70, - -70, -70, -70, -70, -70, 71, 71, 71, 71, 71, - 71, -70, -70, -70, -70, -70, -70, -70, -70, -70, - -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, - -70, -70, -70, -70, -70, -70, -70, 71, 71, 71, - - 71, 71, 71, -70, -70, -70, -70, -70, -70, -70, - -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, - -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, - -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, - -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, - -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, - -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, - -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, - -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, - -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, - - -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, - -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, - -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, - -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, - -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, - -70, -70, -70, -70, -70, -70 - }, - - { - 7, -71, -71, -71, -71, -71, -71, -71, -71, -71, - -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, - -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, - -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, - - -71, -71, -71, -71, -71, -71, -71, -71, 72, 72, - 72, 72, 72, 72, 72, 72, 72, 72, -71, -71, - -71, -71, -71, -71, -71, 72, 72, 72, 72, 72, - 72, -71, -71, -71, -71, -71, -71, -71, -71, -71, - -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, - -71, -71, -71, -71, -71, -71, -71, 72, 72, 72, - 72, 72, 72, -71, -71, -71, -71, -71, -71, -71, - -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, - -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, - -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, - - -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, - -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, - -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, - -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, - -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, - -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, - -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, - -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, - -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, - -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, - - -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, - -71, -71, -71, -71, -71, -71 - }, - - { - 7, -72, -72, -72, -72, -72, -72, -72, -72, -72, - -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, - -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, - -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, - -72, -72, -72, -72, -72, -72, -72, -72, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, -72, -72, - -72, -72, -72, -72, -72, 73, 73, 73, 73, 73, - 73, -72, -72, -72, -72, -72, -72, -72, -72, -72, - - -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, - -72, -72, -72, -72, -72, -72, -72, 73, 73, 73, - 73, 73, 73, -72, -72, -72, -72, -72, -72, -72, - -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, - -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, - -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, - -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, - -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, - -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, - -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, - - -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, - -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, - -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, - -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, - -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, - -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, - -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, - -72, -72, -72, -72, -72, -72 - }, - - { - 7, -73, -73, -73, -73, -73, -73, -73, -73, -73, - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - -73, -73, -73, -73, -73, 74, -73, -73, -73, -73, - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, - -73, -73, -73, -73, -73, -73 - }, - - { - 7, -74, -74, -74, -74, -74, -74, -74, -74, -74, - -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, - -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, - -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, - -74, -74, -74, -74, -74, -74, -74, -74, 75, 75, - 75, 75, 75, 75, 75, 75, 75, 75, -74, -74, - - -74, -74, -74, -74, -74, 75, 75, 75, 75, 75, - 75, -74, -74, -74, -74, -74, -74, -74, -74, -74, - -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, - -74, -74, -74, -74, -74, -74, -74, 75, 75, 75, - 75, 75, 75, -74, -74, -74, -74, -74, -74, -74, - -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, - -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, - -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, - -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, - -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, - - -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, - -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, - -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, - -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, - -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, - -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, - -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, - -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, - -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, - -74, -74, -74, -74, -74, -74 - - }, - - { - 7, -75, -75, -75, -75, -75, -75, -75, -75, -75, - -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, - -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, - -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, - -75, -75, -75, -75, -75, -75, -75, -75, 76, 76, - 76, 76, 76, 76, 76, 76, 76, 76, -75, -75, - -75, -75, -75, -75, -75, 76, 76, 76, 76, 76, - 76, -75, -75, -75, -75, -75, -75, -75, -75, -75, - -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, - -75, -75, -75, -75, -75, -75, -75, 76, 76, 76, - - 76, 76, 76, -75, -75, -75, -75, -75, -75, -75, - -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, - -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, - -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, - -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, - -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, - -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, - -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, - -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, - -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, - - -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, - -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, - -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, - -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, - -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, - -75, -75, -75, -75, -75, -75 - }, - - { - 7, -76, -76, -76, -76, -76, -76, -76, -76, -76, - -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, - -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, - -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, - - -76, -76, -76, -76, -76, -76, -76, -76, 77, 77, - 77, 77, 77, 77, 77, 77, 77, 77, -76, -76, - -76, -76, -76, -76, -76, 77, 77, 77, 77, 77, - 77, -76, -76, -76, -76, -76, -76, -76, -76, -76, - -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, - -76, -76, -76, -76, -76, -76, -76, 77, 77, 77, - 77, 77, 77, -76, -76, -76, -76, -76, -76, -76, - -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, - -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, - -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, - - -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, - -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, - -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, - -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, - -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, - -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, - -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, - -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, - -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, - -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, - - -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, - -76, -76, -76, -76, -76, -76 - }, - - { - 7, -77, -77, -77, -77, -77, -77, -77, -77, -77, - -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, - -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, - -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, - -77, -77, -77, -77, -77, -77, -77, -77, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, -77, -77, - -77, -77, -77, -77, -77, 78, 78, 78, 78, 78, - 78, -77, -77, -77, -77, -77, -77, -77, -77, -77, - - -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, - -77, -77, -77, -77, -77, -77, -77, 78, 78, 78, - 78, 78, 78, -77, -77, -77, -77, -77, -77, -77, - -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, - -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, - -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, - -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, - -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, - -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, - -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, - - -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, - -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, - -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, - -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, - -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, - -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, - -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, - -77, -77, -77, -77, -77, -77 - }, - - { - 7, -78, -78, -78, -78, -78, -78, -78, -78, -78, - -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, - - -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, - -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, - -78, -78, -78, -78, -78, -78, -78, -78, 79, 79, - 79, 79, 79, 79, 79, 79, 79, 79, -78, -78, - -78, -78, -78, -78, -78, 79, 79, 79, 79, 79, - 79, -78, -78, -78, -78, -78, -78, -78, -78, -78, - -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, - -78, -78, -78, -78, -78, -78, -78, 79, 79, 79, - 79, 79, 79, -78, -78, -78, -78, -78, -78, -78, - -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, - - -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, - -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, - -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, - -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, - -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, - -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, - -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, - -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, - -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, - -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, - - -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, - -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, - -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, - -78, -78, -78, -78, -78, -78 - }, - - { - 7, -79, -79, -79, -79, -79, -79, -79, -79, -79, - -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, - -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, - -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, - -79, -79, -79, -79, -79, -79, -79, -79, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, -79, -79, - - -79, -79, -79, -79, -79, 80, 80, 80, 80, 80, - 80, -79, -79, -79, -79, -79, -79, -79, -79, -79, - -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, - -79, -79, -79, -79, -79, -79, -79, 80, 80, 80, - 80, 80, 80, -79, -79, -79, -79, -79, -79, -79, - -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, - -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, - -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, - -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, - -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, - - -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, - -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, - -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, - -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, - -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, - -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, - -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, - -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, - -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, - -79, -79, -79, -79, -79, -79 - - }, - - { - 7, -80, -80, -80, -80, -80, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80, -80, -80, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, -80, -80, - -80, -80, -80, -80, -80, 81, 81, 81, 81, 81, - 81, -80, -80, -80, -80, -80, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80, -80, 81, 81, 81, - - 81, 81, 81, -80, -80, -80, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, - - -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80 - }, - - { - 7, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - - -81, -81, -81, -81, -81, -81, -81, -81, 82, 82, - 82, 82, 82, 82, 82, 82, 82, 82, -81, -81, - -81, -81, -81, -81, -81, 82, 82, 82, 82, 82, - 82, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81, 82, 82, 82, - 82, 82, 82, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - - -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - - -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81 - }, - - { - 7, -82, -82, -82, -82, -82, -82, -82, -82, -82, - -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, - -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, - -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, - -82, -82, -82, -82, -82, -82, -82, -82, 83, 83, - 83, 83, 83, 83, 83, 83, 83, 83, -82, -82, - -82, -82, -82, -82, -82, 83, 83, 83, 83, 83, - 83, -82, -82, -82, -82, -82, -82, -82, -82, -82, - - -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, - -82, -82, -82, -82, -82, -82, -82, 83, 83, 83, - 83, 83, 83, -82, -82, -82, -82, -82, -82, -82, - -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, - -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, - -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, - -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, - -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, - -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, - -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, - - -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, - -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, - -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, - -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, - -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, - -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, - -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, - -82, -82, -82, -82, -82, -82 - }, - - { - 7, -83, -83, -83, -83, -83, -83, -83, -83, -83, - -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, - - -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, - -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, - -83, -83, -83, -83, -83, -83, -83, -83, 84, 84, - 84, 84, 84, 84, 84, 84, 84, 84, -83, -83, - -83, -83, -83, -83, -83, 84, 84, 84, 84, 84, - 84, -83, -83, -83, -83, -83, -83, -83, -83, -83, - -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, - -83, -83, -83, -83, -83, -83, -83, 84, 84, 84, - 84, 84, 84, -83, -83, -83, -83, -83, -83, -83, - -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, - - -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, - -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, - -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, - -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, - -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, - -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, - -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, - -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, - -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, - -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, - - -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, - -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, - -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, - -83, -83, -83, -83, -83, -83 - }, - - { - 7, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, -84, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, -84, -84, - - -84, -84, -84, -84, -84, 85, 85, 85, 85, 85, - 85, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, 85, 85, 85, - 85, 85, 85, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, - - -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, - -84, -84, -84, -84, -84, -84 - - }, - - { - 7, -85, -85, -85, -85, -85, -85, -85, -85, -85, - -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, - -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, - -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, - -85, -85, -85, -85, -85, -85, -85, -85, 86, 86, - 86, 86, 86, 86, 86, 86, 86, 86, -85, -85, - -85, -85, -85, -85, -85, 86, 86, 86, 86, 86, - 86, -85, -85, -85, -85, -85, -85, -85, -85, -85, - -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, - -85, -85, -85, -85, -85, -85, -85, 86, 86, 86, - - 86, 86, 86, -85, -85, -85, -85, -85, -85, -85, - -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, - -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, - -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, - -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, - -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, - -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, - -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, - -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, - -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, - - -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, - -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, - -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, - -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, - -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, - -85, -85, -85, -85, -85, -85 - }, - - { - 7, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - - -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, -86, -86, -86, -86, -86 - }, - - } ; - - -static yy_state_type yy_get_previous_state YY_PROTO(( void )); -static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); -static int yy_get_next_buffer YY_PROTO(( void )); -static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); - -/* Done after the current pattern has been matched and before the - * corresponding action - sets up yytext. - */ -#define YY_DO_BEFORE_ACTION \ - yytext_ptr = yy_bp; \ - yyleng = (int) (yy_cp - yy_bp); \ - yy_hold_char = *yy_cp; \ - *yy_cp = '\0'; \ - yy_c_buf_p = yy_cp; - -#define YY_NUM_RULES 18 -#define YY_END_OF_BUFFER 19 -static yyconst short int yy_accept[87] = - { 0, - 0, 0, 0, 0, 2, 2, 19, 17, 14, 13, - 3, 11, 11, 17, 17, 12, 12, 14, 1, 8, - 18, 4, 8, 2, 11, 0, 0, 15, 16, 12, - 12, 0, 1, 1, 7, 6, 5, 2, 11, 0, - 10, 12, 11, 0, 12, 11, 0, 12, 11, 0, - 12, 11, 0, 12, 11, 0, 12, 0, 11, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 9 - } ; - -static yy_state_type yy_last_accepting_state; -static char *yy_last_accepting_cpos; - -static yyconst yy_state_type yy_NUL_trans[87] = - { 0, - 8, 8, 20, 20, 24, 24, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 35, 38, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0 - } ; - -extern int yy_flex_debug; -int yy_flex_debug = 1; - -static yyconst short int yy_rule_linenum[18] = - { 0, - 109, 110, 129, 130, 135, 136, 137, 138, 139, 143, - 147, 151, 152, 153, 154, 155, 156 - } ; - -/* The intent behind this definition is that it'll catch - * any uses of REJECT which flex missed. - */ -#define REJECT reject_used_but_not_detected -#define yymore() yymore_used_but_not_detected -#define YY_MORE_ADJ 0 -#define YY_RESTORE_YY_MORE_OFFSET -char *yytext; -#line 1 "parser.l" -#define INITIAL 0 -/* - * IDL Compiler - * - * Copyright 2002 Ove Kaaven - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#define YY_STACK_USED 1 -#define YY_NEVER_INTERACTIVE 1 -#define QUOTE 1 - -#define pp_line 2 - -#line 36 "parser.l" - -#include "config.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <assert.h> -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#endif - -#include "widl.h" -#include "utils.h" -#include "parser.h" -#include "wine/wpp.h" - -#include "y.tab.h" - -#define YY_USE_PROTOS -#define YY_NO_UNPUT -#define YY_NO_TOP_STATE - -extern char *temp_name; - -static void addcchar(char c); -static char *get_buffered_cstring(void); - -static char *cbuffer; -static int cbufidx; -static int cbufalloc = 0; - -static int kw_token(const char *kw); - -#define MAX_IMPORT_DEPTH 10 -struct { - YY_BUFFER_STATE state; - char *input_name; - int line_number; - char *temp_name; -} import_stack[MAX_IMPORT_DEPTH]; -int import_stack_ptr = 0; - -static void pop_import(void); - -static UUID* parse_uuid(const char*u) -{ - UUID* uuid = xmalloc(sizeof(UUID)); - char b[3]; - /* it would be nice to use UuidFromStringA */ - uuid->Data1 = strtoul(u, NULL, 16); - uuid->Data2 = strtoul(u+9, NULL, 16); - uuid->Data3 = strtoul(u+14, NULL, 16); - b[2] = 0; - memcpy(b, u+19, 2); uuid->Data4[0] = strtoul(b, NULL, 16); - memcpy(b, u+21, 2); uuid->Data4[1] = strtoul(b, NULL, 16); - memcpy(b, u+24, 2); uuid->Data4[2] = strtoul(b, NULL, 16); - memcpy(b, u+26, 2); uuid->Data4[3] = strtoul(b, NULL, 16); - memcpy(b, u+28, 2); uuid->Data4[4] = strtoul(b, NULL, 16); - memcpy(b, u+30, 2); uuid->Data4[5] = strtoul(b, NULL, 16); - memcpy(b, u+32, 2); uuid->Data4[6] = strtoul(b, NULL, 16); - memcpy(b, u+34, 2); uuid->Data4[7] = strtoul(b, NULL, 16); - return uuid; -} - -/* - ************************************************************************** - * The flexer starts here - ************************************************************************** - */ -#line 3190 "lex.yy.c" - -/* Macros after this point can all be overridden by user definitions in - * section 1. - */ - -#ifndef YY_SKIP_YYWRAP -#ifdef __cplusplus -extern "C" int yywrap YY_PROTO(( void )); -#else -extern int yywrap YY_PROTO(( void )); -#endif -#endif - -#ifndef YY_NO_UNPUT -static void yyunput YY_PROTO(( int c, char *buf_ptr )); -#endif - -#ifndef yytext_ptr -static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen YY_PROTO(( yyconst char * )); -#endif - -#ifndef YY_NO_INPUT -#ifdef __cplusplus -static int yyinput YY_PROTO(( void )); -#else -static int input YY_PROTO(( void )); -#endif -#endif - -#if YY_STACK_USED -static int yy_start_stack_ptr = 0; -static int yy_start_stack_depth = 0; -static int *yy_start_stack = 0; -#ifndef YY_NO_PUSH_STATE -static void yy_push_state YY_PROTO(( int new_state )); -#endif -#ifndef YY_NO_POP_STATE -static void yy_pop_state YY_PROTO(( void )); -#endif -#ifndef YY_NO_TOP_STATE -static int yy_top_state YY_PROTO(( void )); -#endif - -#else -#define YY_NO_PUSH_STATE 1 -#define YY_NO_POP_STATE 1 -#define YY_NO_TOP_STATE 1 -#endif - -#ifdef YY_MALLOC_DECL -YY_MALLOC_DECL -#else -#if __STDC__ -#ifndef __cplusplus -#include <stdlib.h> -#endif -#else -/* Just try to get by without declaring the routines. This will fail - * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) - * or sizeof(void*) != sizeof(int). - */ -#endif -#endif - -/* Amount of stuff to slurp up with each read. */ -#ifndef YY_READ_BUF_SIZE -#define YY_READ_BUF_SIZE 8192 -#endif - -/* Copy whatever the last rule matched to the standard output. */ - -#ifndef ECHO -/* This used to be an fputs(), but since the string might contain NUL's, - * we now use fwrite(). - */ -#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) -#endif - -/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, - * is returned in "result". - */ -#ifndef YY_INPUT -#define YY_INPUT(buf,result,max_size) \ - if ( yy_current_buffer->yy_is_interactive ) \ - { \ - int c = '*', n; \ - for ( n = 0; n < max_size && \ - (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ - buf[n] = (char) c; \ - if ( c == '\n' ) \ - buf[n++] = (char) c; \ - if ( c == EOF && ferror( yyin ) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); \ - result = n; \ - } \ - else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ - && ferror( yyin ) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); -#endif - -/* No semi-colon after return; correct usage is to write "yyterminate();" - - * we don't want an extra ';' after the "return" because that will cause - * some compilers to complain about unreachable statements. - */ -#ifndef yyterminate -#define yyterminate() return YY_NULL -#endif - -/* Number of entries by which start-condition stack grows. */ -#ifndef YY_START_STACK_INCR -#define YY_START_STACK_INCR 25 -#endif - -/* Report a fatal error. */ -#ifndef YY_FATAL_ERROR -#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) -#endif - -/* Default declaration of generated scanner - a define so the user can - * easily add parameters. - */ -#ifndef YY_DECL -#define YY_DECL int yylex YY_PROTO(( void )) -#endif - -/* Code executed at the beginning of each rule, after yytext and yyleng - * have been set up. - */ -#ifndef YY_USER_ACTION -#define YY_USER_ACTION -#endif - -/* Code executed at the end of each rule. */ -#ifndef YY_BREAK -#define YY_BREAK break; -#endif - -#define YY_RULE_SETUP \ - if ( yyleng > 0 ) \ - yy_current_buffer->yy_at_bol = \ - (yytext[yyleng - 1] == '\n'); \ - YY_USER_ACTION - -YY_DECL - { - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; - -#line 108 "parser.l" - -#line 3346 "lex.yy.c" - - if ( yy_init ) - { - yy_init = 0; - -#ifdef YY_USER_INIT - YY_USER_INIT; -#endif - - if ( ! yy_start ) - yy_start = 1; /* first start state */ - - if ( ! yyin ) - yyin = stdin; - - if ( ! yyout ) - yyout = stdout; - - if ( ! yy_current_buffer ) - yy_current_buffer = - yy_create_buffer( yyin, YY_BUF_SIZE ); - - yy_load_buffer_state(); - } - - while ( 1 ) /* loops until end-of-file is reached */ - { - yy_cp = yy_c_buf_p; - - /* Support of yytext. */ - *yy_cp = yy_hold_char; - - /* yy_bp points to the position in yy_ch_buf of the start of - * the current run. - */ - yy_bp = yy_cp; - - yy_current_state = yy_start; - yy_current_state += YY_AT_BOL(); -yy_match: - while ( (yy_current_state = yy_nxt[yy_current_state][YY_SC_TO_UI(*yy_cp)]) > 0 ) - { - if ( yy_accept[yy_current_state] ) - { - yy_last_accepting_state = yy_current_state; - yy_last_accepting_cpos = yy_cp; - } - - ++yy_cp; - } - - yy_current_state = -yy_current_state; - -yy_find_action: - yy_act = yy_accept[yy_current_state]; - - YY_DO_BEFORE_ACTION; - - -do_action: /* This label is used only to access EOF actions. */ - - if ( yy_flex_debug ) - { - if ( yy_act == 0 ) - fprintf( stderr, "--scanner backing up\n" ); - else if ( yy_act < 18 ) - fprintf( stderr, "--accepting rule at line %d (\"%s\")\n", - yy_rule_linenum[yy_act], yytext ); - else if ( yy_act == 18 ) - fprintf( stderr, "--accepting default rule (\"%s\")\n", - yytext ); - else if ( yy_act == 19 ) - fprintf( stderr, "--(end of buffer or a NUL)\n" ); - else - fprintf( stderr, "--EOF (start condition %d)\n", YY_START ); - } - - switch ( yy_act ) - { /* beginning of action switch */ - case 0: /* must back up */ - /* undo the effects of YY_DO_BEFORE_ACTION */ - *yy_cp = yy_hold_char; - yy_cp = yy_last_accepting_cpos + 1; - yy_current_state = yy_last_accepting_state; - goto yy_find_action; - -case 1: -YY_RULE_SETUP -#line 109 "parser.l" -yy_push_state(pp_line); - YY_BREAK -case 2: -YY_RULE_SETUP -#line 110 "parser.l" -{ - int lineno; - char *cptr, *fname; - yy_pop_state(); - lineno = (int)strtol(yytext, &cptr, 10); - if(!lineno) - yyerror("Malformed '#...' line-directive; invalid linenumber"); - fname = strchr(cptr, '"'); - if(!fname) - yyerror("Malformed '#...' line-directive; missing filename"); - fname++; - cptr = strchr(fname, '"'); - if(!cptr) - yyerror("Malformed '#...' line-directive; missing terminating \""); - *cptr = '\0'; - line_number = lineno - 1; /* We didn't read the newline */ - free( input_name ); - input_name = xstrdup(fname); - } - YY_BREAK -case 3: -YY_RULE_SETUP -#line 129 "parser.l" -yy_push_state(QUOTE); cbufidx = 0; - YY_BREAK -case 4: -YY_RULE_SETUP -#line 130 "parser.l" -{ - yy_pop_state(); - yylval.str = get_buffered_cstring(); - return aSTRING; - } - YY_BREAK -case 5: -#line 136 "parser.l" -case 6: -YY_RULE_SETUP -#line 136 "parser.l" -addcchar(yytext[1]); - YY_BREAK -case 7: -YY_RULE_SETUP -#line 137 "parser.l" -addcchar('\\'); addcchar(yytext[1]); - YY_BREAK -case 8: -YY_RULE_SETUP -#line 138 "parser.l" -addcchar(yytext[0]); - YY_BREAK -case 9: -YY_RULE_SETUP -#line 139 "parser.l" -{ - yylval.uuid = parse_uuid(yytext); - return aUUID; - } - YY_BREAK -case 10: -YY_RULE_SETUP -#line 143 "parser.l" -{ - yylval.num = strtoul(yytext, NULL, 0); - return aHEXNUM; - } - YY_BREAK -case 11: -YY_RULE_SETUP -#line 147 "parser.l" -{ - yylval.num = strtoul(yytext, NULL, 0); - return aNUM; - } - YY_BREAK -case 12: -YY_RULE_SETUP -#line 151 "parser.l" -return kw_token(yytext); - YY_BREAK -case 13: -YY_RULE_SETUP -#line 152 "parser.l" -line_number++; - YY_BREAK -case 14: -YY_RULE_SETUP -#line 153 "parser.l" - - YY_BREAK -case 15: -YY_RULE_SETUP -#line 154 "parser.l" -return SHL; - YY_BREAK -case 16: -YY_RULE_SETUP -#line 155 "parser.l" -return SHR; - YY_BREAK -case 17: -YY_RULE_SETUP -#line 156 "parser.l" -return yytext[0]; - YY_BREAK -case YY_STATE_EOF(INITIAL): -case YY_STATE_EOF(QUOTE): -case YY_STATE_EOF(pp_line): -#line 157 "parser.l" -{ - if (import_stack_ptr) { - pop_import(); - return aEOF; - } - else yyterminate(); - } - YY_BREAK -case 18: -YY_RULE_SETUP -#line 164 "parser.l" -ECHO; - YY_BREAK -#line 3563 "lex.yy.c" - - case YY_END_OF_BUFFER: - { - /* Amount of text matched not including the EOB char. */ - int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; - - /* Undo the effects of YY_DO_BEFORE_ACTION. */ - *yy_cp = yy_hold_char; - YY_RESTORE_YY_MORE_OFFSET - - if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) - { - /* We're scanning a new file or input source. It's - * possible that this happened because the user - * just pointed yyin at a new source and called - * yylex(). If so, then we have to assure - * consistency between yy_current_buffer and our - * globals. Here is the right place to do so, because - * this is the first action (other than possibly a - * back-up) that will match for the new input source. - */ - yy_n_chars = yy_current_buffer->yy_n_chars; - yy_current_buffer->yy_input_file = yyin; - yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; - } - - /* Note that here we test for yy_c_buf_p "<=" to the position - * of the first EOB in the buffer, since yy_c_buf_p will - * already have been incremented past the NUL character - * (since all states make transitions on EOB to the - * end-of-buffer state). Contrast this with the test - * in input(). - */ - if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) - { /* This was really a NUL. */ - yy_state_type yy_next_state; - - yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state(); - - /* Okay, we're now positioned to make the NUL - * transition. We couldn't have - * yy_get_previous_state() go ahead and do it - * for us because it doesn't know how to deal - * with the possibility of jamming (and we don't - * want to build jamming into it because then it - * will run more slowly). - */ - - yy_next_state = yy_try_NUL_trans( yy_current_state ); - - yy_bp = yytext_ptr + YY_MORE_ADJ; - - if ( yy_next_state ) - { - /* Consume the NUL. */ - yy_cp = ++yy_c_buf_p; - yy_current_state = yy_next_state; - goto yy_match; - } - - else - { - yy_cp = yy_c_buf_p; - goto yy_find_action; - } - } - - else switch ( yy_get_next_buffer() ) - { - case EOB_ACT_END_OF_FILE: - { - yy_did_buffer_switch_on_eof = 0; - - if ( yywrap() ) - { - /* Note: because we've taken care in - * yy_get_next_buffer() to have set up - * yytext, we can now set up - * yy_c_buf_p so that if some total - * hoser (like flex itself) wants to - * call the scanner after we return the - * YY_NULL, it'll still work - another - * YY_NULL will get returned. - */ - yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; - - yy_act = YY_STATE_EOF(YY_START); - goto do_action; - } - - else - { - if ( ! yy_did_buffer_switch_on_eof ) - YY_NEW_FILE; - } - break; - } - - case EOB_ACT_CONTINUE_SCAN: - yy_c_buf_p = - yytext_ptr + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state(); - - yy_cp = yy_c_buf_p; - yy_bp = yytext_ptr + YY_MORE_ADJ; - goto yy_match; - - case EOB_ACT_LAST_MATCH: - yy_c_buf_p = - &yy_current_buffer->yy_ch_buf[yy_n_chars]; - - yy_current_state = yy_get_previous_state(); - - yy_cp = yy_c_buf_p; - yy_bp = yytext_ptr + YY_MORE_ADJ; - goto yy_find_action; - } - break; - } - - default: - YY_FATAL_ERROR( - "fatal flex scanner internal error--no action found" ); - } /* end of action switch */ - } /* end of scanning one token */ - } /* end of yylex */ - - -/* yy_get_next_buffer - try to read in a new buffer - * - * Returns a code representing an action: - * EOB_ACT_LAST_MATCH - - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position - * EOB_ACT_END_OF_FILE - end of file - */ - -static int yy_get_next_buffer() - { - register char *dest = yy_current_buffer->yy_ch_buf; - register char *source = yytext_ptr; - register int number_to_move, i; - int ret_val; - - if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) - YY_FATAL_ERROR( - "fatal flex scanner internal error--end of buffer missed" ); - - if ( yy_current_buffer->yy_fill_buffer == 0 ) - { /* Don't try to fill the buffer, so this is an EOF. */ - if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) - { - /* We matched a single character, the EOB, so - * treat this as a final EOF. - */ - return EOB_ACT_END_OF_FILE; - } - - else - { - /* We matched some text prior to the EOB, first - * process it. - */ - return EOB_ACT_LAST_MATCH; - } - } - - /* Try to read more data. */ - - /* First move last chars to start of buffer. */ - number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; - - for ( i = 0; i < number_to_move; ++i ) - *(dest++) = *(source++); - - if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) - /* don't do the read, it's not guaranteed to return an EOF, - * just force an EOF - */ - yy_current_buffer->yy_n_chars = yy_n_chars = 0; - - else - { - int num_to_read = - yy_current_buffer->yy_buf_size - number_to_move - 1; - - while ( num_to_read <= 0 ) - { /* Not enough room in the buffer - grow it. */ -#ifdef YY_USES_REJECT - YY_FATAL_ERROR( -"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); -#else - - /* just a shorter name for the current buffer */ - YY_BUFFER_STATE b = yy_current_buffer; - - int yy_c_buf_p_offset = - (int) (yy_c_buf_p - b->yy_ch_buf); - - if ( b->yy_is_our_buffer ) - { - int new_size = b->yy_buf_size * 2; - - if ( new_size <= 0 ) - b->yy_buf_size += b->yy_buf_size / 8; - else - b->yy_buf_size *= 2; - - b->yy_ch_buf = (char *) - /* Include room in for 2 EOB chars. */ - yy_flex_realloc( (void *) b->yy_ch_buf, - b->yy_buf_size + 2 ); - } - else - /* Can't grow it, we don't own it. */ - b->yy_ch_buf = 0; - - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( - "fatal error - scanner input buffer overflow" ); - - yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; - - num_to_read = yy_current_buffer->yy_buf_size - - number_to_move - 1; -#endif - } - - if ( num_to_read > YY_READ_BUF_SIZE ) - num_to_read = YY_READ_BUF_SIZE; - - /* Read in more data. */ - YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), - yy_n_chars, num_to_read ); - - yy_current_buffer->yy_n_chars = yy_n_chars; - } - - if ( yy_n_chars == 0 ) - { - if ( number_to_move == YY_MORE_ADJ ) - { - ret_val = EOB_ACT_END_OF_FILE; - yyrestart( yyin ); - } - - else - { - ret_val = EOB_ACT_LAST_MATCH; - yy_current_buffer->yy_buffer_status = - YY_BUFFER_EOF_PENDING; - } - } - - else - ret_val = EOB_ACT_CONTINUE_SCAN; - - yy_n_chars += number_to_move; - yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; - yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; - - yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; - - return ret_val; - } - - -/* yy_get_previous_state - get the state just before the EOB char was reached */ - -static yy_state_type yy_get_previous_state() - { - register yy_state_type yy_current_state; - register char *yy_cp; - - yy_current_state = yy_start; - yy_current_state += YY_AT_BOL(); - - for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) - { - if ( *yy_cp ) - { - yy_current_state = yy_nxt[yy_current_state][YY_SC_TO_UI(*yy_cp)]; - } - else - yy_current_state = yy_NUL_trans[yy_current_state]; - if ( yy_accept[yy_current_state] ) - { - yy_last_accepting_state = yy_current_state; - yy_last_accepting_cpos = yy_cp; - } - } - - return yy_current_state; - } - - -/* yy_try_NUL_trans - try to make a transition on the NUL character - * - * synopsis - * next_state = yy_try_NUL_trans( current_state ); - */ - -#ifdef YY_USE_PROTOS -static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) -#else -static yy_state_type yy_try_NUL_trans( yy_current_state ) -yy_state_type yy_current_state; -#endif - { - register int yy_is_jam; - register char *yy_cp = yy_c_buf_p; - - yy_current_state = yy_NUL_trans[yy_current_state]; - yy_is_jam = (yy_current_state == 0); - - if ( ! yy_is_jam ) - { - if ( yy_accept[yy_current_state] ) - { - yy_last_accepting_state = yy_current_state; - yy_last_accepting_cpos = yy_cp; - } - } - - return yy_is_jam ? 0 : yy_current_state; - } - - -#ifndef YY_NO_UNPUT -#ifdef YY_USE_PROTOS -static void yyunput( int c, register char *yy_bp ) -#else -static void yyunput( c, yy_bp ) -int c; -register char *yy_bp; -#endif - { - register char *yy_cp = yy_c_buf_p; - - /* undo effects of setting up yytext */ - *yy_cp = yy_hold_char; - - if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) - { /* need to shift things up to make room */ - /* +2 for EOB chars. */ - register int number_to_move = yy_n_chars + 2; - register char *dest = &yy_current_buffer->yy_ch_buf[ - yy_current_buffer->yy_buf_size + 2]; - register char *source = - &yy_current_buffer->yy_ch_buf[number_to_move]; - - while ( source > yy_current_buffer->yy_ch_buf ) - *--dest = *--source; - - yy_cp += (int) (dest - source); - yy_bp += (int) (dest - source); - yy_current_buffer->yy_n_chars = - yy_n_chars = yy_current_buffer->yy_buf_size; - - if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) - YY_FATAL_ERROR( "flex scanner push-back overflow" ); - } - - *--yy_cp = (char) c; - - - yytext_ptr = yy_bp; - yy_hold_char = *yy_cp; - yy_c_buf_p = yy_cp; - } -#endif /* ifndef YY_NO_UNPUT */ - - -#ifdef __cplusplus -static int yyinput() -#else -static int input() -#endif - { - int c; - - *yy_c_buf_p = yy_hold_char; - - if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) - { - /* yy_c_buf_p now points to the character we want to return. - * If this occurs *before* the EOB characters, then it's a - * valid NUL; if not, then we've hit the end of the buffer. - */ - if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) - /* This was really a NUL. */ - *yy_c_buf_p = '\0'; - - else - { /* need more input */ - int offset = yy_c_buf_p - yytext_ptr; - ++yy_c_buf_p; - - switch ( yy_get_next_buffer() ) - { - case EOB_ACT_LAST_MATCH: - /* This happens because yy_g_n_b() - * sees that we've accumulated a - * token and flags that we need to - * try matching the token before - * proceeding. But for input(), - * there's no matching to consider. - * So convert the EOB_ACT_LAST_MATCH - * to EOB_ACT_END_OF_FILE. - */ - - /* Reset buffer status. */ - yyrestart( yyin ); - - /* fall through */ - - case EOB_ACT_END_OF_FILE: - { - if ( yywrap() ) - return EOF; - - if ( ! yy_did_buffer_switch_on_eof ) - YY_NEW_FILE; -#ifdef __cplusplus - return yyinput(); -#else - return input(); -#endif - } - - case EOB_ACT_CONTINUE_SCAN: - yy_c_buf_p = yytext_ptr + offset; - break; - } - } - } - - c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ - *yy_c_buf_p = '\0'; /* preserve yytext */ - yy_hold_char = *++yy_c_buf_p; - - yy_current_buffer->yy_at_bol = (c == '\n'); - - return c; - } - - -#ifdef YY_USE_PROTOS -void yyrestart( FILE *input_file ) -#else -void yyrestart( input_file ) -FILE *input_file; -#endif - { - if ( ! yy_current_buffer ) - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); - - yy_init_buffer( yy_current_buffer, input_file ); - yy_load_buffer_state(); - } - - -#ifdef YY_USE_PROTOS -void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) -#else -void yy_switch_to_buffer( new_buffer ) -YY_BUFFER_STATE new_buffer; -#endif - { - if ( yy_current_buffer == new_buffer ) - return; - - if ( yy_current_buffer ) - { - /* Flush out information for old buffer. */ - *yy_c_buf_p = yy_hold_char; - yy_current_buffer->yy_buf_pos = yy_c_buf_p; - yy_current_buffer->yy_n_chars = yy_n_chars; - } - - yy_current_buffer = new_buffer; - yy_load_buffer_state(); - - /* We don't actually know whether we did this switch during - * EOF (yywrap()) processing, but the only time this flag - * is looked at is after yywrap() is called, so it's safe - * to go ahead and always set it. - */ - yy_did_buffer_switch_on_eof = 1; - } - - -#ifdef YY_USE_PROTOS -void yy_load_buffer_state( void ) -#else -void yy_load_buffer_state() -#endif - { - yy_n_chars = yy_current_buffer->yy_n_chars; - yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; - yyin = yy_current_buffer->yy_input_file; - yy_hold_char = *yy_c_buf_p; - } - - -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) -#else -YY_BUFFER_STATE yy_create_buffer( file, size ) -FILE *file; -int size; -#endif - { - YY_BUFFER_STATE b; - - b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - - b->yy_buf_size = size; - - /* yy_ch_buf has to be 2 characters longer than the size given because - * we need to put in 2 end-of-buffer characters. - */ - b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - - b->yy_is_our_buffer = 1; - - yy_init_buffer( b, file ); - - return b; - } - - -#ifdef YY_USE_PROTOS -void yy_delete_buffer( YY_BUFFER_STATE b ) -#else -void yy_delete_buffer( b ) -YY_BUFFER_STATE b; -#endif - { - if ( ! b ) - return; - - if ( b == yy_current_buffer ) - yy_current_buffer = (YY_BUFFER_STATE) 0; - - if ( b->yy_is_our_buffer ) - yy_flex_free( (void *) b->yy_ch_buf ); - - yy_flex_free( (void *) b ); - } - - -#ifndef YY_ALWAYS_INTERACTIVE -#ifndef YY_NEVER_INTERACTIVE -extern int isatty YY_PROTO(( int )); -#endif -#endif - -#ifdef YY_USE_PROTOS -void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) -#else -void yy_init_buffer( b, file ) -YY_BUFFER_STATE b; -FILE *file; -#endif - - - { - yy_flush_buffer( b ); - - b->yy_input_file = file; - b->yy_fill_buffer = 1; - -#if YY_ALWAYS_INTERACTIVE - b->yy_is_interactive = 1; -#else -#if YY_NEVER_INTERACTIVE - b->yy_is_interactive = 0; -#else - b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; -#endif -#endif - } - - -#ifdef YY_USE_PROTOS -void yy_flush_buffer( YY_BUFFER_STATE b ) -#else -void yy_flush_buffer( b ) -YY_BUFFER_STATE b; -#endif - - { - if ( ! b ) - return; - - b->yy_n_chars = 0; - - /* We always need two end-of-buffer characters. The first causes - * a transition to the end-of-buffer state. The second causes - * a jam in that state. - */ - b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; - b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; - - b->yy_buf_pos = &b->yy_ch_buf[0]; - - b->yy_at_bol = 1; - b->yy_buffer_status = YY_BUFFER_NEW; - - if ( b == yy_current_buffer ) - yy_load_buffer_state(); - } - - -#ifndef YY_NO_SCAN_BUFFER -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) -#else -YY_BUFFER_STATE yy_scan_buffer( base, size ) -char *base; -yy_size_t size; -#endif - { - YY_BUFFER_STATE b; - - if ( size < 2 || - base[size-2] != YY_END_OF_BUFFER_CHAR || - base[size-1] != YY_END_OF_BUFFER_CHAR ) - /* They forgot to leave room for the EOB's. */ - return 0; - - b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); - - b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ - b->yy_buf_pos = b->yy_ch_buf = base; - b->yy_is_our_buffer = 0; - b->yy_input_file = 0; - b->yy_n_chars = b->yy_buf_size; - b->yy_is_interactive = 0; - b->yy_at_bol = 1; - b->yy_fill_buffer = 0; - b->yy_buffer_status = YY_BUFFER_NEW; - - yy_switch_to_buffer( b ); - - return b; - } -#endif - - -#ifndef YY_NO_SCAN_STRING -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) -#else -YY_BUFFER_STATE yy_scan_string( yy_str ) -yyconst char *yy_str; -#endif - { - int len; - for ( len = 0; yy_str[len]; ++len ) - ; - - return yy_scan_bytes( yy_str, len ); - } -#endif - - -#ifndef YY_NO_SCAN_BYTES -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) -#else -YY_BUFFER_STATE yy_scan_bytes( bytes, len ) -yyconst char *bytes; -int len; -#endif - { - YY_BUFFER_STATE b; - char *buf; - yy_size_t n; - int i; - - /* Get memory for full buffer, including space for trailing EOB's. */ - n = len + 2; - buf = (char *) yy_flex_alloc( n ); - if ( ! buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); - - for ( i = 0; i < len; ++i ) - buf[i] = bytes[i]; - - buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; - - b = yy_scan_buffer( buf, n ); - if ( ! b ) - YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); - - /* It's okay to grow etc. this buffer, and we should throw it - * away when we're done. - */ - b->yy_is_our_buffer = 1; - - return b; - } -#endif - - -#ifndef YY_NO_PUSH_STATE -#ifdef YY_USE_PROTOS -static void yy_push_state( int new_state ) -#else -static void yy_push_state( new_state ) -int new_state; -#endif - { - if ( yy_start_stack_ptr >= yy_start_stack_depth ) - { - yy_size_t new_size; - - yy_start_stack_depth += YY_START_STACK_INCR; - new_size = yy_start_stack_depth * sizeof( int ); - - if ( ! yy_start_stack ) - yy_start_stack = (int *) yy_flex_alloc( new_size ); - - else - yy_start_stack = (int *) yy_flex_realloc( - (void *) yy_start_stack, new_size ); - - if ( ! yy_start_stack ) - YY_FATAL_ERROR( - "out of memory expanding start-condition stack" ); - } - - yy_start_stack[yy_start_stack_ptr++] = YY_START; - - BEGIN(new_state); - } -#endif - - -#ifndef YY_NO_POP_STATE -static void yy_pop_state() - { - if ( --yy_start_stack_ptr < 0 ) - YY_FATAL_ERROR( "start-condition stack underflow" ); - - BEGIN(yy_start_stack[yy_start_stack_ptr]); - } -#endif - - -#ifndef YY_NO_TOP_STATE -static int yy_top_state() - { - return yy_start_stack[yy_start_stack_ptr - 1]; - } -#endif - -#ifndef YY_EXIT_FAILURE -#define YY_EXIT_FAILURE 2 -#endif - -#ifdef YY_USE_PROTOS -static void yy_fatal_error( yyconst char msg[] ) -#else -static void yy_fatal_error( msg ) -char msg[]; -#endif - { - (void) fprintf( stderr, "%s\n", msg ); - exit( YY_EXIT_FAILURE ); - } - - - -/* Redefine yyless() so it works in section 3 code. */ - -#undef yyless -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - yytext[yyleng] = yy_hold_char; \ - yy_c_buf_p = yytext + n; \ - yy_hold_char = *yy_c_buf_p; \ - *yy_c_buf_p = '\0'; \ - yyleng = n; \ - } \ - while ( 0 ) - - -/* Internal utility routines. */ - -#ifndef yytext_ptr -#ifdef YY_USE_PROTOS -static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) -#else -static void yy_flex_strncpy( s1, s2, n ) -char *s1; -yyconst char *s2; -int n; -#endif - { - register int i; - for ( i = 0; i < n; ++i ) - s1[i] = s2[i]; - } -#endif - -#ifdef YY_NEED_STRLEN -#ifdef YY_USE_PROTOS -static int yy_flex_strlen( yyconst char *s ) -#else -static int yy_flex_strlen( s ) -yyconst char *s; -#endif - { - register int n; - for ( n = 0; s[n]; ++n ) - ; - - return n; - } -#endif - - -#ifdef YY_USE_PROTOS -static void *yy_flex_alloc( yy_size_t size ) -#else -static void *yy_flex_alloc( size ) -yy_size_t size; -#endif - { - return (void *) malloc( size ); - } - -#ifdef YY_USE_PROTOS -static void *yy_flex_realloc( void *ptr, yy_size_t size ) -#else -static void *yy_flex_realloc( ptr, size ) -void *ptr; -yy_size_t size; -#endif - { - /* The cast to (char *) in the following accommodates both - * implementations that use char* generic pointers, and those - * that use void* generic pointers. It works with the latter - * because both ANSI C and C++ allow castless assignment from - * any pointer type to void*, and deal with argument conversions - * as though doing an assignment. - */ - return (void *) realloc( (char *) ptr, size ); - } - -#ifdef YY_USE_PROTOS -static void yy_flex_free( void *ptr ) -#else -static void yy_flex_free( ptr ) -void *ptr; -#endif - { - free( ptr ); - } - -#if YY_MAIN -int main() - { - yylex(); - return 0; - } -#endif -#line 164 "parser.l" - - -#ifndef yywrap -int yywrap(void) -{ - return 1; -} -#endif - -static struct keyword { - const char *kw; - int token; - int val; -} keywords[] = { - {"__cdecl", tCDECL}, - {"__int64", tINT64}, - {"__stdcall", tSTDCALL}, - {"_stdcall", tSTDCALL}, - {"aggregatable", tAGGREGATABLE}, - {"allocate", tALLOCATE}, - {"appobject", tAPPOBJECT}, - {"arrays", tARRAYS}, - {"async", tASYNC}, - {"async_uuid", tASYNCUUID}, - {"auto_handle", tAUTOHANDLE}, - {"bindable", tBINDABLE}, - {"boolean", tBOOLEAN}, - {"broadcast", tBROADCAST}, - {"byte", tBYTE}, - {"byte_count", tBYTECOUNT}, - {"call_as", tCALLAS}, - {"callback", tCALLBACK}, - {"case", tCASE}, - {"char", tCHAR}, - {"coclass", tCOCLASS}, - {"code", tCODE}, - {"comm_status", tCOMMSTATUS}, - {"const", tCONST}, - {"context_handle", tCONTEXTHANDLE}, - {"context_handle_noserialize", tCONTEXTHANDLENOSERIALIZE}, - {"context_handle_serialize", tCONTEXTHANDLENOSERIALIZE}, - {"control", tCONTROL}, - {"cpp_quote", tCPPQUOTE}, -/* ... */ - {"default", tDEFAULT}, - {"defaultvalue", tDEFAULTVALUE}, -/* ... */ - {"dispinterface", tDISPINTERFACE}, -/* ... */ - {"dllname", tDLLNAME}, - {"double", tDOUBLE}, - {"dual", tDUAL}, -/* ... */ - {"endpoint", tENDPOINT}, - {"entry", tENTRY}, - {"enum", tENUM}, - {"error_status_t", tERRORSTATUST}, - {"explicit_handle", tEXPLICITHANDLE}, - {"extern", tEXTERN}, -/* ... */ - {"float", tFLOAT}, -/* ... */ - {"handle", tHANDLE}, - {"handle_t", tHANDLET}, -/* ... */ - {"helpcontext", tHELPCONTEXT}, - {"helpfile", tHELPFILE}, - {"helpstring", tHELPSTRING}, - {"helpstringcontext", tHELPSTRINGCONTEXT}, - {"helpstringdll", tHELPSTRINGDLL}, -/* ... */ - {"hidden", tHIDDEN}, - {"hyper", tHYPER}, - {"id", tID}, - {"idempotent", tIDEMPOTENT}, -/* ... */ - {"iid_is", tIIDIS}, -/* ... */ - {"implicit_handle", tIMPLICITHANDLE}, - {"import", tIMPORT}, - {"importlib", tIMPORTLIB}, - {"in", tIN}, - {"include", tINCLUDE}, - {"in_line", tINLINE}, - {"input_sync", tINPUTSYNC}, - {"int", tINT}, -/* ... */ - {"interface", tINTERFACE}, -/* ... */ - {"length_is", tLENGTHIS}, - {"library", tLIBRARY}, -/* ... */ - {"local", tLOCAL}, - {"long", tLONG}, -/* ... */ - {"methods", tMETHODS}, -/* ... */ - {"module", tMODULE}, -/* ... */ - {"noncreatable", tNONCREATABLE}, - {"object", tOBJECT}, - {"odl", tODL}, - {"oleautomation", tOLEAUTOMATION}, -/* ... */ - {"optional", tOPTIONAL}, - {"out", tOUT}, -/* ... */ - {"pointer_default", tPOINTERDEFAULT}, -/* ... */ - {"properties", tPROPERTIES}, - {"propget", tPROPGET}, - {"propput", tPROPPUT}, - {"propputref", tPROPPUTREF}, -/* ... */ - {"ptr", tPTR}, - {"public", tPUBLIC}, -/* ... */ - {"readonly", tREADONLY}, - {"ref", tREF}, -/* ... */ - {"restricted", tRESTRICTED}, - {"retval", tRETVAL}, -/* ... */ - {"short", tSHORT}, - {"signed", tSIGNED}, - {"single", tSINGLE}, - {"size_is", tSIZEIS}, - {"sizeof", tSIZEOF}, -/* ... */ - {"small", tSMALL}, - {"source", tSOURCE}, -/* ... */ - {"string", tSTRING}, - {"struct", tSTRUCT}, - {"switch", tSWITCH}, - {"switch_is", tSWITCHIS}, - {"switch_type", tSWITCHTYPE}, -/* ... */ - {"transmit_as", tTRANSMITAS}, - {"typedef", tTYPEDEF}, -/* ... */ - {"union", tUNION}, - {"unique", tUNIQUE}, - {"unsigned", tUNSIGNED}, -/* ... */ - {"uuid", tUUID}, - {"v1_enum", tV1ENUM}, -/* ... */ - {"vararg", tVARARG}, - {"version", tVERSION}, - {"void", tVOID}, - {"wchar_t", tWCHAR}, - {"wire_marshal", tWIREMARSHAL} -}; -#define NKEYWORDS (sizeof(keywords)/sizeof(keywords[0])) -#define KWP(p) ((const struct keyword *)(p)) - -static int kw_cmp_func(const void *s1, const void *s2) -{ - return strcmp(KWP(s1)->kw, KWP(s2)->kw); -} - -#define KW_BSEARCH -static int kw_token(const char *kw) -{ - struct keyword key, *kwp; - key.kw = kw; -#ifdef KW_BSEARCH - kwp = bsearch(&key, keywords, NKEYWORDS, sizeof(keywords[0]), kw_cmp_func); -#else - { - int i; - for (kwp=NULL, i=0; i < NKEYWORDS; i++) - if (!kw_cmp_func(&key, &keywords[i])) { - kwp = &keywords[i]; - break; - } - } -#endif - if (kwp) { - yylval.str = (char*)kwp->kw; - return kwp->token; - } - yylval.str = xstrdup(kw); - return is_type(kw) ? aKNOWNTYPE : aIDENTIFIER; -} - -static void addcchar(char c) -{ - if(cbufidx >= cbufalloc) - { - cbufalloc += 1024; - cbuffer = xrealloc(cbuffer, cbufalloc * sizeof(cbuffer[0])); - if(cbufalloc > 65536) - yywarning("Reallocating string buffer larger than 64kB"); - } - cbuffer[cbufidx++] = c; -} - -static char *get_buffered_cstring(void) -{ - addcchar(0); - return xstrdup(cbuffer); -} - -static void pop_import(void) -{ - int ptr = import_stack_ptr-1; - - fclose(yyin); - yy_delete_buffer( YY_CURRENT_BUFFER ); - yy_switch_to_buffer( import_stack[ptr].state ); - if (temp_name) { - unlink(temp_name); - free(temp_name); - } - temp_name = import_stack[ptr].temp_name; - free( input_name ); - input_name = import_stack[ptr].input_name; - line_number = import_stack[ptr].line_number; - import_stack_ptr--; -} - -struct imports { - char *name; - struct imports *next; -} *first_import; - -int do_import(char *fname) -{ - FILE *f; - char *hname, *path, *p; - struct imports *import; - int ptr = import_stack_ptr; - int ret; - - if (!parse_only && do_header) { - hname = dup_basename(fname, ".idl"); - p = hname + strlen(hname) - 2; - if (p <= hname || strcmp( p, ".h" )) strcat(hname, ".h"); - - fprintf(header, "#include <%s>\n", hname); - free(hname); - } - - import = first_import; - while (import && strcmp(import->name, fname)) - import = import->next; - if (import) return 0; /* already imported */ - - import = xmalloc(sizeof(struct imports)); - import->name = xstrdup(fname); - import->next = first_import; - first_import = import; - - if (!(path = wpp_find_include( fname, 1 ))) - yyerror("Unable to open include file %s", fname); - - import_stack[ptr].temp_name = temp_name; - import_stack[ptr].input_name = input_name; - import_stack[ptr].line_number = line_number; - import_stack_ptr++; - input_name = path; - line_number = 1; - - ret = wpp_parse_temp( path, NULL, &temp_name ); - if (ret) exit(1); - - if((f = fopen(temp_name, "r")) == NULL) - yyerror("Unable to open %s", temp_name); - - import_stack[ptr].state = YY_CURRENT_BUFFER; - yy_switch_to_buffer(yy_create_buffer(f, YY_BUF_SIZE)); - return 1; -} - -void abort_import(void) -{ - int ptr; - - for (ptr=0; ptr<import_stack_ptr; ptr++) - unlink(import_stack[ptr].temp_name); -} +#line 2 "lex.yy.c" +/* A lexical scanner generated by flex */ + +/* Scanner skeleton version: + * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $ + */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 + +#include <stdio.h> + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include <stdlib.h> +#include <unistd.h> + +/* Use prototypes in function declarations. */ +#define YY_USE_PROTOS + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef __TURBOC__ + #pragma warn -rch + #pragma warn -use +#include <io.h> +#include <stdlib.h> +#define YY_USE_CONST +#define YY_USE_PROTOS +#endif + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#define YY_BUF_SIZE 16384 + +typedef struct yy_buffer_state *YY_BUFFER_STATE; + +extern int yyleng; +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* The funky do-while in the following #define is used to turn the definition + * int a single C statement (which needs a semi-colon terminator). This + * avoids problems with code like: + * + * if ( condition_holds ) + * yyless( 5 ); + * else + * do_something_else(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the yyless() call. + */ + +/* Return all but the first 'n' matched characters back to the input stream. */ + +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + *yy_cp = yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yytext_ptr ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ +typedef unsigned int yy_size_t; + + +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + }; + +static YY_BUFFER_STATE yy_current_buffer = 0; + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + */ +#define YY_CURRENT_BUFFER yy_current_buffer + + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; + +static int yy_n_chars; /* number of characters read into yy_ch_buf */ + + +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 1; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart YY_PROTO(( FILE *input_file )); + +void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); +void yy_load_buffer_state YY_PROTO(( void )); +YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); +void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); +void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); +void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); +#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) + +YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); +YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); +YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); + +static void *yy_flex_alloc YY_PROTO(( yy_size_t )); +static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); +static void yy_flex_free YY_PROTO(( void * )); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) + + +#define FLEX_DEBUG +typedef unsigned char YY_CHAR; +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; +typedef int yy_state_type; + +#define FLEX_DEBUG +extern char *yytext; +#define yytext_ptr yytext +static yyconst short yy_nxt[][256] = + { + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 + }, + + { + 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, + 10, 8, 9, 9, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 9, 8, 11, 8, 8, 8, 8, 8, + + 8, 8, 8, 8, 8, 8, 8, 8, 12, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 8, 8, + 14, 8, 15, 8, 8, 16, 16, 16, 16, 16, + 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 8, 8, 8, 8, 17, 8, 16, 16, 16, + 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8 + }, + + { + 7, 8, 8, 8, 8, 8, 8, 8, 8, 18, + 10, 8, 18, 18, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 18, 8, 11, 19, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 12, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 8, 8, + 14, 8, 15, 8, 8, 16, 16, 16, 16, 16, + 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, + + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 8, 8, 8, 8, 17, 8, 16, 16, 16, + 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8 + }, + + { + 7, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, + + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 22, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 23, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20 + }, + + { + 7, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 22, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 23, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20 + + }, + + { + 7, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 21, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24 + }, + + { + 7, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 21, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24 + }, + + { + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7, -7, -7, -7, -7, + -7, -7, -7, -7, -7, -7 + }, + + { + 7, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8, -8, -8, -8, -8, + -8, -8, -8, -8, -8, -8 + }, + + { + 7, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, + -9, -9, -9, -9, -9, -9 + + }, + + { + 7, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, + -10, -10, -10, -10, -10, -10 + }, + + { + 7, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + + -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, + -11, -11, -11, -11, -11, -11 + }, + + { + 7, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12, -12, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, -12, -12, + -12, -12, -12, -12, -12, 26, 26, 26, 26, 26, + 26, -12, -12, -12, -12, -12, -12, -12, -12, -12, + + -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12, 26, 26, 26, + 26, 26, 26, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, + 27, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, + + -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, + -12, -12, -12, -12, -12, -12 + }, + + { + 7, -13, -13, -13, -13, -13, -13, -13, -13, -13, + -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, + + -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, + -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, + -13, -13, -13, -13, -13, -13, -13, -13, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, -13, -13, + -13, -13, -13, -13, -13, 26, 26, 26, 26, 26, + 26, -13, -13, -13, -13, -13, -13, -13, -13, -13, + -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, + -13, -13, -13, -13, -13, -13, -13, 26, 26, 26, + 26, 26, 26, -13, -13, -13, -13, -13, -13, -13, + -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, + + -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, + -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, + -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, + -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, + -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, + -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, + -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, + -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, + -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, + -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, + + -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, + -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, + -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, + -13, -13, -13, -13, -13, -13 + }, + + { + 7, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + + 28, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, + -14, -14, -14, -14, -14, -14 + + }, + + { + 7, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, 29, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15, -15, -15, -15, -15, + -15, -15, -15, -15, -15, -15 + }, + + { + 7, -16, -16, -16, -16, -16, -16, -16, -16, -16, + -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, + -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, + -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, + + -16, -16, -16, -16, -16, -16, -16, -16, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, -16, -16, + -16, -16, -16, -16, -16, 30, 30, 30, 30, 30, + 30, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, -16, -16, -16, -16, 31, -16, 30, 30, 30, + 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, -16, -16, -16, -16, -16, -16, -16, + -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, + + -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, + -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, + -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, + -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, + -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, + -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, + -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, + -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, + -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, + -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, + + -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, + -16, -16, -16, -16, -16, -16 + }, + + { + 7, -17, -17, -17, -17, -17, -17, -17, -17, -17, + -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, + -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, + -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, + -17, -17, -17, -17, -17, -17, -17, -17, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, -17, -17, + -17, -17, -17, -17, -17, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, -17, -17, -17, -17, 31, -17, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, -17, -17, -17, -17, -17, -17, -17, + -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, + -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, + -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, + -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, + -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, + + -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, + -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, + -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, + -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, + -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, + -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, + -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, + -17, -17, -17, -17, -17, -17 + }, + + { + 7, -18, -18, -18, -18, -18, -18, -18, -18, 32, + -18, -18, 32, 32, -18, -18, -18, -18, -18, -18, + + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, 32, -18, -18, 33, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, -18, -18, -18, -18, -18 + }, + + { + 7, -19, -19, -19, -19, -19, -19, -19, -19, 34, + -19, -19, 34, 34, -19, -19, -19, -19, -19, -19, + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + -19, -19, 34, -19, -19, -19, -19, -19, -19, -19, + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, + -19, -19, -19, -19, -19, -19 + + }, + + { + 7, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, + -20, -20, -20, -20, -20, -20 + }, + + { + 7, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + + -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, + -21, -21, -21, -21, -21, -21 + }, + + { + 7, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, + -22, -22, -22, -22, -22, -22 + }, + + { + 7, 35, 35, 35, 35, 35, 35, 35, 35, 35, + -23, 35, 35, 35, 35, 35, 35, 35, 35, 35, + + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 36, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 37, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35 + }, + + { + 7, 38, 38, 38, 38, 38, 38, 38, 38, 38, + -24, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38 + + }, + + { + 7, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, -25, -25, + -25, -25, -25, -25, -25, 40, 40, 40, 40, 40, + 40, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, 40, 40, 40, + + 40, 40, 40, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25 + }, + + { + 7, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, + + -26, -26, -26, -26, -26, -26, -26, -26, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, -26, -26, + -26, -26, -26, -26, -26, 40, 40, 40, 40, 40, + 40, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26, -26, 40, 40, 40, + 40, 40, 40, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, + + -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, + + -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -26, -26, -26, -26, -26 + }, + + { + 7, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27, -27, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, -27, -27, + -27, -27, -27, -27, -27, 41, 41, 41, 41, 41, + 41, -27, -27, -27, -27, -27, -27, -27, -27, -27, + + -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27, 41, 41, 41, + 41, 41, 41, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, + + -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27, -27, -27, -27, -27, + -27, -27, -27, -27, -27, -27 + }, + + { + 7, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28, -28, -28, -28, -28, + -28, -28, -28, -28, -28, -28 + }, + + { + 7, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, + -29, -29, -29, -29, -29, -29 + + }, + + { + 7, -30, -30, -30, -30, -30, -30, -30, -30, -30, + -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, + -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, + -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, + -30, -30, -30, -30, -30, -30, -30, -30, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, -30, -30, + -30, -30, -30, -30, -30, 42, 42, 42, 42, 42, + 42, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, -30, -30, -30, -30, 31, -30, 42, 42, 42, + + 42, 42, 42, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, -30, -30, -30, -30, -30, -30, -30, + -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, + -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, + -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, + -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, + -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, + -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, + -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, + + -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, + -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, + -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, + -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, + -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, + -30, -30, -30, -30, -30, -30 + }, + + { + 7, -31, -31, -31, -31, -31, -31, -31, -31, -31, + -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, + -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, + -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, + + -31, -31, -31, -31, -31, -31, -31, -31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, -31, -31, + -31, -31, -31, -31, -31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, -31, -31, -31, -31, 31, -31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, -31, -31, -31, -31, -31, -31, -31, + -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, + + -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, + -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, + -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, + -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, + -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, + -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, + -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, + -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, + -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, + -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, + + -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, + -31, -31, -31, -31, -31, -31 + }, + + { + 7, -32, -32, -32, -32, -32, -32, -32, -32, 32, + -32, -32, 32, 32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, 32, -32, -32, 33, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, + -32, -32, -32, -32, -32, -32 + }, + + { + 7, -33, -33, -33, -33, -33, -33, -33, -33, 34, + -33, -33, 34, 34, -33, -33, -33, -33, -33, -33, + + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, 34, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, + -33, -33, -33, -33, -33, -33 + }, + + { + 7, -34, -34, -34, -34, -34, -34, -34, -34, 34, + -34, -34, 34, 34, -34, -34, -34, -34, -34, -34, + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, -34, 34, -34, -34, -34, -34, -34, -34, -34, + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, + -34, -34, -34, -34, -34, -34 + + }, + + { + 7, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, + -35, -35, -35, -35, -35, -35 + }, + + { + 7, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + + -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, + -36, -36, -36, -36, -36, -36 + }, + + { + 7, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37, -37, -37, -37, -37, + -37, -37, -37, -37, -37, -37 + }, + + { + 7, 38, 38, 38, 38, 38, 38, 38, 38, 38, + -38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38 + }, + + { + 7, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, -39, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, -39, -39, + + -39, -39, -39, -39, -39, 44, 44, 44, 44, 44, + 44, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, 44, 44, 44, + 44, 44, 44, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39 + + }, + + { + 7, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40, -40, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, -40, -40, + -40, -40, -40, -40, -40, 44, 44, 44, 44, 44, + 44, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40, 44, 44, 44, + + 44, 44, 44, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, + + -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, + -40, -40, -40, -40, -40, -40 + }, + + { + 7, -41, -41, -41, -41, -41, -41, -41, -41, -41, + -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, + -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, + -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, + + -41, -41, -41, -41, -41, -41, -41, -41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, -41, -41, + -41, -41, -41, -41, -41, 41, 41, 41, 41, 41, + 41, -41, -41, -41, -41, -41, -41, -41, -41, -41, + -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, + -41, -41, -41, -41, -41, -41, -41, 41, 41, 41, + 41, 41, 41, -41, -41, -41, -41, -41, -41, -41, + -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, + -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, + -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, + + -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, + -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, + -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, + -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, + -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, + -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, + -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, + -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, + -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, + -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, + + -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, + -41, -41, -41, -41, -41, -41 + }, + + { + 7, -42, -42, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, -42, -42, -42, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, -42, -42, + -42, -42, -42, -42, -42, 45, 45, 45, 45, 45, + 45, 31, 31, 31, 31, 31, 31, 31, 31, 31, + + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, -42, -42, -42, -42, 31, -42, 45, 45, 45, + 45, 45, 45, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, + + -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, -42, -42, -42, -42, -42, + -42, -42, -42, -42, -42, -42 + }, + + { + 7, -43, -43, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, + + -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43, -43, -43, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, -43, -43, + -43, -43, -43, -43, -43, 47, 47, 47, 47, 47, + 47, -43, -43, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43, -43, 47, 47, 47, + 47, 47, 47, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, + + -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, + + -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, + -43, -43, -43, -43, -43, -43 + }, + + { + 7, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, -44, -44, -44, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, -44, -44, + + -44, -44, -44, -44, -44, 47, 47, 47, 47, 47, + 47, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, -44, -44, 47, 47, 47, + 47, 47, 47, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, + + -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, + -44, -44, -44, -44, -44, -44 + + }, + + { + 7, -45, -45, -45, -45, -45, -45, -45, -45, -45, + -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, + -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, + -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, + -45, -45, -45, -45, -45, -45, -45, -45, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, -45, -45, + -45, -45, -45, -45, -45, 48, 48, 48, 48, 48, + 48, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, -45, -45, -45, -45, 31, -45, 48, 48, 48, + + 48, 48, 48, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, -45, -45, -45, -45, -45, -45, -45, + -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, + -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, + -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, + -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, + -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, + -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, + -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, + + -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, + -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, + -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, + -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, + -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, + -45, -45, -45, -45, -45, -45 + }, + + { + 7, -46, -46, -46, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, + + -46, -46, -46, -46, -46, -46, -46, -46, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, -46, -46, + -46, -46, -46, -46, -46, 50, 50, 50, 50, 50, + 50, -46, -46, -46, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46, -46, 50, 50, 50, + 50, 50, 50, -46, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, + + -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, + + -46, -46, -46, -46, -46, -46, -46, -46, -46, -46, + -46, -46, -46, -46, -46, -46 + }, + + { + 7, -47, -47, -47, -47, -47, -47, -47, -47, -47, + -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, + -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, + -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, + -47, -47, -47, -47, -47, -47, -47, -47, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, -47, -47, + -47, -47, -47, -47, -47, 50, 50, 50, 50, 50, + 50, -47, -47, -47, -47, -47, -47, -47, -47, -47, + + -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, + -47, -47, -47, -47, -47, -47, -47, 50, 50, 50, + 50, 50, 50, -47, -47, -47, -47, -47, -47, -47, + -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, + -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, + -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, + -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, + -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, + -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, + -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, + + -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, + -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, + -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, + -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, + -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, + -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, + -47, -47, -47, -47, -47, -47, -47, -47, -47, -47, + -47, -47, -47, -47, -47, -47 + }, + + { + 7, -48, -48, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, + + -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -48, -48, -48, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, -48, -48, + -48, -48, -48, -48, -48, 51, 51, 51, 51, 51, + 51, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, -48, -48, -48, -48, 31, -48, 51, 51, 51, + 51, 51, 51, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + + 31, 31, 31, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, + + -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, + -48, -48, -48, -48, -48, -48 + }, + + { + 7, -49, -49, -49, -49, -49, -49, -49, -49, -49, + -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, + -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, + -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, + -49, -49, -49, -49, -49, -49, -49, -49, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, -49, -49, + + -49, -49, -49, -49, -49, 53, 53, 53, 53, 53, + 53, -49, -49, -49, -49, -49, -49, -49, -49, -49, + -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, + -49, -49, -49, -49, -49, -49, -49, 53, 53, 53, + 53, 53, 53, -49, -49, -49, -49, -49, -49, -49, + -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, + -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, + -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, + -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, + -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, + + -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, + -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, + -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, + -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, + -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, + -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, + -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, + -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, + -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, + -49, -49, -49, -49, -49, -49 + + }, + + { + 7, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50, -50, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, -50, -50, + -50, -50, -50, -50, -50, 53, 53, 53, 53, 53, + 53, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50, 53, 53, 53, + + 53, 53, 53, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, + + -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50, -50, -50, -50, -50, + -50, -50, -50, -50, -50, -50 + }, + + { + 7, -51, -51, -51, -51, -51, -51, -51, -51, -51, + -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, + -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, + -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, + + -51, -51, -51, -51, -51, -51, -51, -51, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, -51, -51, + -51, -51, -51, -51, -51, 54, 54, 54, 54, 54, + 54, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, -51, -51, -51, -51, 31, -51, 54, 54, 54, + 54, 54, 54, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, -51, -51, -51, -51, -51, -51, -51, + -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, + + -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, + -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, + -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, + -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, + -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, + -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, + -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, + -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, + -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, + -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, + + -51, -51, -51, -51, -51, -51, -51, -51, -51, -51, + -51, -51, -51, -51, -51, -51 + }, + + { + 7, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52, -52, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, -52, -52, + -52, -52, -52, -52, -52, 56, 56, 56, 56, 56, + 56, -52, -52, -52, -52, -52, -52, -52, -52, -52, + + -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52, 56, 56, 56, + 56, 56, 56, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, + + -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, + -52, -52, -52, -52, -52, -52 + }, + + { + 7, -53, -53, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, + + -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53, -53, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, -53, -53, + -53, -53, -53, -53, -53, 56, 56, 56, 56, 56, + 56, -53, -53, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53, 56, 56, 56, + 56, 56, 56, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, + + -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, + + -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, + -53, -53, -53, -53, -53, -53 + }, + + { + 7, -54, -54, -54, -54, -54, -54, -54, -54, -54, + -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, + -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, + -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, + -54, -54, -54, -54, -54, -54, -54, -54, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 57, -54, -54, + + -54, -54, -54, -54, -54, 57, 57, 57, 57, 57, + 57, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, -54, -54, -54, -54, 31, -54, 57, 57, 57, + 57, 57, 57, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, -54, -54, -54, -54, -54, -54, -54, + -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, + -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, + -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, + + -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, + -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, + -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, + -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, + -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, + -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, + -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, + -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, + -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, + -54, -54, -54, -54, -54, -54 + + }, + + { + 7, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, 58, -55, -55, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, -55, -55, + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55, -55, -55, -55, -55, + -55, -55, -55, -55, -55, -55 + }, + + { + 7, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + + -56, -56, -56, -56, -56, 58, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + + -56, -56, -56, -56, -56, -56, -56, -56, -56, -56, + -56, -56, -56, -56, -56, -56 + }, + + { + 7, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, -57, -57, -57, -57, 58, -57, -57, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, -57, -57, + -57, -57, -57, -57, -57, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, -57, -57, -57, -57, 31, -57, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, -57, -57, -57, -57, -57, -57, -57, + -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, + + -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, + -57, -57, -57, -57, -57, -57 + }, + + { + 7, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, + + -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58, -58, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, -58, -58, + -58, -58, -58, -58, -58, 60, 60, 60, 60, 60, + 60, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58, 60, 60, 60, + 60, 60, 60, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, + + -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, + + -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, + -58, -58, -58, -58, -58, -58 + }, + + { + 7, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59, -59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, -59, -59, + + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, + -59, -59, -59, -59, -59, -59 + + }, + + { + 7, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, -60, -60, -60, -60, -60, -60, -60, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61, -60, -60, + -60, -60, -60, -60, -60, 61, 61, 61, 61, 61, + 61, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, -60, -60, -60, -60, -60, -60, 61, 61, 61, + + 61, 61, 61, -60, -60, -60, -60, -60, -60, -60, + -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, + + -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, + -60, -60, -60, -60, -60, -60 + }, + + { + 7, -61, -61, -61, -61, -61, -61, -61, -61, -61, + -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, + -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, + -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, + + -61, -61, -61, -61, -61, -61, -61, -61, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, -61, -61, + -61, -61, -61, -61, -61, 62, 62, 62, 62, 62, + 62, -61, -61, -61, -61, -61, -61, -61, -61, -61, + -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, + -61, -61, -61, -61, -61, -61, -61, 62, 62, 62, + 62, 62, 62, -61, -61, -61, -61, -61, -61, -61, + -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, + -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, + -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, + + -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, + -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, + -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, + -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, + -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, + -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, + -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, + -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, + -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, + -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, + + -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, + -61, -61, -61, -61, -61, -61 + }, + + { + 7, -62, -62, -62, -62, -62, -62, -62, -62, -62, + -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, + -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, + -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, + -62, -62, -62, -62, -62, -62, -62, -62, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, -62, -62, + -62, -62, -62, -62, -62, 63, 63, 63, 63, 63, + 63, -62, -62, -62, -62, -62, -62, -62, -62, -62, + + -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, + -62, -62, -62, -62, -62, -62, -62, 63, 63, 63, + 63, 63, 63, -62, -62, -62, -62, -62, -62, -62, + -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, + -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, + -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, + -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, + -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, + -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, + -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, + + -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, + -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, + -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, + -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, + -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, + -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, + -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, + -62, -62, -62, -62, -62, -62 + }, + + { + 7, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, 64, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63 + }, + + { + 7, -64, -64, -64, -64, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64, -64, -64, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, -64, -64, + + -64, -64, -64, -64, -64, 65, 65, 65, 65, 65, + 65, -64, -64, -64, -64, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64, -64, 65, 65, 65, + 65, 65, 65, -64, -64, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, + + -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, + -64, -64, -64, -64, -64, -64 + + }, + + { + 7, -65, -65, -65, -65, -65, -65, -65, -65, -65, + -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, + -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, + -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, + -65, -65, -65, -65, -65, -65, -65, -65, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, -65, -65, + -65, -65, -65, -65, -65, 66, 66, 66, 66, 66, + 66, -65, -65, -65, -65, -65, -65, -65, -65, -65, + -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, + -65, -65, -65, -65, -65, -65, -65, 66, 66, 66, + + 66, 66, 66, -65, -65, -65, -65, -65, -65, -65, + -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, + -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, + -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, + -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, + -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, + -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, + -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, + -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, + -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, + + -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, + -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, + -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, + -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, + -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, + -65, -65, -65, -65, -65, -65 + }, + + { + 7, -66, -66, -66, -66, -66, -66, -66, -66, -66, + -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, + -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, + -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, + + -66, -66, -66, -66, -66, -66, -66, -66, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, -66, -66, + -66, -66, -66, -66, -66, 67, 67, 67, 67, 67, + 67, -66, -66, -66, -66, -66, -66, -66, -66, -66, + -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, + -66, -66, -66, -66, -66, -66, -66, 67, 67, 67, + 67, 67, 67, -66, -66, -66, -66, -66, -66, -66, + -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, + -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, + -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, + + -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, + -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, + -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, + -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, + -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, + -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, + -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, + -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, + -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, + -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, + + -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, + -66, -66, -66, -66, -66, -66 + }, + + { + 7, -67, -67, -67, -67, -67, -67, -67, -67, -67, + -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, + -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, + -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, + -67, -67, -67, -67, -67, -67, -67, -67, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, -67, -67, + -67, -67, -67, -67, -67, 68, 68, 68, 68, 68, + 68, -67, -67, -67, -67, -67, -67, -67, -67, -67, + + -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, + -67, -67, -67, -67, -67, -67, -67, 68, 68, 68, + 68, 68, 68, -67, -67, -67, -67, -67, -67, -67, + -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, + -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, + -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, + -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, + -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, + -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, + -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, + + -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, + -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, + -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, + -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, + -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, + -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, + -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, + -67, -67, -67, -67, -67, -67 + }, + + { + 7, -68, -68, -68, -68, -68, -68, -68, -68, -68, + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + -68, -68, -68, -68, -68, 69, -68, -68, -68, -68, + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, + -68, -68, -68, -68, -68, -68 + }, + + { + 7, -69, -69, -69, -69, -69, -69, -69, -69, -69, + -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, + -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, + -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, + -69, -69, -69, -69, -69, -69, -69, -69, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, -69, -69, + + -69, -69, -69, -69, -69, 70, 70, 70, 70, 70, + 70, -69, -69, -69, -69, -69, -69, -69, -69, -69, + -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, + -69, -69, -69, -69, -69, -69, -69, 70, 70, 70, + 70, 70, 70, -69, -69, -69, -69, -69, -69, -69, + -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, + -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, + -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, + -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, + -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, + + -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, + -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, + -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, + -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, + -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, + -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, + -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, + -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, + -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, + -69, -69, -69, -69, -69, -69 + + }, + + { + 7, -70, -70, -70, -70, -70, -70, -70, -70, -70, + -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, + -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, + -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, + -70, -70, -70, -70, -70, -70, -70, -70, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, -70, -70, + -70, -70, -70, -70, -70, 71, 71, 71, 71, 71, + 71, -70, -70, -70, -70, -70, -70, -70, -70, -70, + -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, + -70, -70, -70, -70, -70, -70, -70, 71, 71, 71, + + 71, 71, 71, -70, -70, -70, -70, -70, -70, -70, + -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, + -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, + -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, + -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, + -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, + -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, + -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, + -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, + -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, + + -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, + -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, + -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, + -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, + -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, + -70, -70, -70, -70, -70, -70 + }, + + { + 7, -71, -71, -71, -71, -71, -71, -71, -71, -71, + -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, + -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, + -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, + + -71, -71, -71, -71, -71, -71, -71, -71, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, -71, -71, + -71, -71, -71, -71, -71, 72, 72, 72, 72, 72, + 72, -71, -71, -71, -71, -71, -71, -71, -71, -71, + -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, + -71, -71, -71, -71, -71, -71, -71, 72, 72, 72, + 72, 72, 72, -71, -71, -71, -71, -71, -71, -71, + -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, + -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, + -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, + + -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, + -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, + -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, + -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, + -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, + -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, + -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, + -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, + -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, + -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, + + -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, + -71, -71, -71, -71, -71, -71 + }, + + { + 7, -72, -72, -72, -72, -72, -72, -72, -72, -72, + -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, + -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, + -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, + -72, -72, -72, -72, -72, -72, -72, -72, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, -72, -72, + -72, -72, -72, -72, -72, 73, 73, 73, 73, 73, + 73, -72, -72, -72, -72, -72, -72, -72, -72, -72, + + -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, + -72, -72, -72, -72, -72, -72, -72, 73, 73, 73, + 73, 73, 73, -72, -72, -72, -72, -72, -72, -72, + -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, + -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, + -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, + -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, + -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, + -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, + -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, + + -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, + -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, + -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, + -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, + -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, + -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, + -72, -72, -72, -72, -72, -72, -72, -72, -72, -72, + -72, -72, -72, -72, -72, -72 + }, + + { + 7, -73, -73, -73, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, -73, 74, -73, -73, -73, -73, + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, + -73, -73, -73, -73, -73, -73 + }, + + { + 7, -74, -74, -74, -74, -74, -74, -74, -74, -74, + -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, + -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, + -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, + -74, -74, -74, -74, -74, -74, -74, -74, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, -74, -74, + + -74, -74, -74, -74, -74, 75, 75, 75, 75, 75, + 75, -74, -74, -74, -74, -74, -74, -74, -74, -74, + -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, + -74, -74, -74, -74, -74, -74, -74, 75, 75, 75, + 75, 75, 75, -74, -74, -74, -74, -74, -74, -74, + -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, + -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, + -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, + -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, + -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, + + -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, + -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, + -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, + -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, + -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, + -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, + -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, + -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, + -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, + -74, -74, -74, -74, -74, -74 + + }, + + { + 7, -75, -75, -75, -75, -75, -75, -75, -75, -75, + -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, + -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, + -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, + -75, -75, -75, -75, -75, -75, -75, -75, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, -75, -75, + -75, -75, -75, -75, -75, 76, 76, 76, 76, 76, + 76, -75, -75, -75, -75, -75, -75, -75, -75, -75, + -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, + -75, -75, -75, -75, -75, -75, -75, 76, 76, 76, + + 76, 76, 76, -75, -75, -75, -75, -75, -75, -75, + -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, + -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, + -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, + -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, + -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, + -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, + -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, + -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, + -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, + + -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, + -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, + -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, + -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, + -75, -75, -75, -75, -75, -75, -75, -75, -75, -75, + -75, -75, -75, -75, -75, -75 + }, + + { + 7, -76, -76, -76, -76, -76, -76, -76, -76, -76, + -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, + -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, + -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, + + -76, -76, -76, -76, -76, -76, -76, -76, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, -76, -76, + -76, -76, -76, -76, -76, 77, 77, 77, 77, 77, + 77, -76, -76, -76, -76, -76, -76, -76, -76, -76, + -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, + -76, -76, -76, -76, -76, -76, -76, 77, 77, 77, + 77, 77, 77, -76, -76, -76, -76, -76, -76, -76, + -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, + -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, + -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, + + -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, + -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, + -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, + -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, + -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, + -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, + -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, + -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, + -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, + -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, + + -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, + -76, -76, -76, -76, -76, -76 + }, + + { + 7, -77, -77, -77, -77, -77, -77, -77, -77, -77, + -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, + -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, + -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, + -77, -77, -77, -77, -77, -77, -77, -77, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, -77, -77, + -77, -77, -77, -77, -77, 78, 78, 78, 78, 78, + 78, -77, -77, -77, -77, -77, -77, -77, -77, -77, + + -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, + -77, -77, -77, -77, -77, -77, -77, 78, 78, 78, + 78, 78, 78, -77, -77, -77, -77, -77, -77, -77, + -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, + -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, + -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, + -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, + -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, + -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, + -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, + + -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, + -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, + -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, + -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, + -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, + -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, + -77, -77, -77, -77, -77, -77, -77, -77, -77, -77, + -77, -77, -77, -77, -77, -77 + }, + + { + 7, -78, -78, -78, -78, -78, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, + + -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78, -78, -78, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, -78, -78, + -78, -78, -78, -78, -78, 79, 79, 79, 79, 79, + 79, -78, -78, -78, -78, -78, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78, -78, 79, 79, 79, + 79, 79, 79, -78, -78, -78, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, + + -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, + + -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, + -78, -78, -78, -78, -78, -78 + }, + + { + 7, -79, -79, -79, -79, -79, -79, -79, -79, -79, + -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, + -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, + -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, + -79, -79, -79, -79, -79, -79, -79, -79, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, -79, -79, + + -79, -79, -79, -79, -79, 80, 80, 80, 80, 80, + 80, -79, -79, -79, -79, -79, -79, -79, -79, -79, + -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, + -79, -79, -79, -79, -79, -79, -79, 80, 80, 80, + 80, 80, 80, -79, -79, -79, -79, -79, -79, -79, + -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, + -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, + -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, + -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, + -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, + + -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, + -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, + -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, + -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, + -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, + -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, + -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, + -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, + -79, -79, -79, -79, -79, -79, -79, -79, -79, -79, + -79, -79, -79, -79, -79, -79 + + }, + + { + 7, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, -80, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, -80, -80, + -80, -80, -80, -80, -80, 81, 81, 81, 81, 81, + 81, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, 81, 81, 81, + + 81, 81, 81, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, + + -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, + -80, -80, -80, -80, -80, -80 + }, + + { + 7, -81, -81, -81, -81, -81, -81, -81, -81, -81, + -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, + -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, + -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, + + -81, -81, -81, -81, -81, -81, -81, -81, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, -81, -81, + -81, -81, -81, -81, -81, 82, 82, 82, 82, 82, + 82, -81, -81, -81, -81, -81, -81, -81, -81, -81, + -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, + -81, -81, -81, -81, -81, -81, -81, 82, 82, 82, + 82, 82, 82, -81, -81, -81, -81, -81, -81, -81, + -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, + -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, + -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, + + -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, + -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, + -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, + -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, + -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, + -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, + -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, + -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, + -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, + -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, + + -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, + -81, -81, -81, -81, -81, -81 + }, + + { + 7, -82, -82, -82, -82, -82, -82, -82, -82, -82, + -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, + -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, + -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, + -82, -82, -82, -82, -82, -82, -82, -82, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, -82, -82, + -82, -82, -82, -82, -82, 83, 83, 83, 83, 83, + 83, -82, -82, -82, -82, -82, -82, -82, -82, -82, + + -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, + -82, -82, -82, -82, -82, -82, -82, 83, 83, 83, + 83, 83, 83, -82, -82, -82, -82, -82, -82, -82, + -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, + -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, + -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, + -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, + -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, + -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, + -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, + + -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, + -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, + -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, + -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, + -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, + -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, + -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, + -82, -82, -82, -82, -82, -82 + }, + + { + 7, -83, -83, -83, -83, -83, -83, -83, -83, -83, + -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, + + -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, + -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, + -83, -83, -83, -83, -83, -83, -83, -83, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, -83, -83, + -83, -83, -83, -83, -83, 84, 84, 84, 84, 84, + 84, -83, -83, -83, -83, -83, -83, -83, -83, -83, + -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, + -83, -83, -83, -83, -83, -83, -83, 84, 84, 84, + 84, 84, 84, -83, -83, -83, -83, -83, -83, -83, + -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, + + -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, + -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, + -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, + -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, + -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, + -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, + -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, + -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, + -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, + -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, + + -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, + -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, + -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, + -83, -83, -83, -83, -83, -83 + }, + + { + 7, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, -84, -84, + + -84, -84, -84, -84, -84, 85, 85, 85, 85, 85, + 85, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, 85, 85, 85, + 85, 85, 85, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84 + + }, + + { + 7, -85, -85, -85, -85, -85, -85, -85, -85, -85, + -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, + -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, + -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, + -85, -85, -85, -85, -85, -85, -85, -85, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, -85, -85, + -85, -85, -85, -85, -85, 86, 86, 86, 86, 86, + 86, -85, -85, -85, -85, -85, -85, -85, -85, -85, + -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, + -85, -85, -85, -85, -85, -85, -85, 86, 86, 86, + + 86, 86, 86, -85, -85, -85, -85, -85, -85, -85, + -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, + -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, + -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, + -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, + -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, + -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, + -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, + -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, + -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, + + -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, + -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, + -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, + -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, + -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, + -85, -85, -85, -85, -85, -85 + }, + + { + 7, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + + -86, -86, -86, -86, -86, -86, -86, -86, -86, -86, + -86, -86, -86, -86, -86, -86 + }, + + } ; + + +static yy_state_type yy_get_previous_state YY_PROTO(( void )); +static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); +static int yy_get_next_buffer YY_PROTO(( void )); +static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 18 +#define YY_END_OF_BUFFER 19 +static yyconst short int yy_accept[87] = + { 0, + 0, 0, 0, 0, 2, 2, 19, 17, 14, 13, + 3, 11, 11, 17, 17, 12, 12, 14, 1, 8, + 18, 4, 8, 2, 11, 0, 0, 15, 16, 12, + 12, 0, 1, 1, 7, 6, 5, 2, 11, 0, + 10, 12, 11, 0, 12, 11, 0, 12, 11, 0, + 12, 11, 0, 12, 11, 0, 12, 0, 11, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 9 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +static yyconst yy_state_type yy_NUL_trans[87] = + { 0, + 8, 8, 20, 20, 24, 24, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 35, 38, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 + } ; + +extern int yy_flex_debug; +int yy_flex_debug = 1; + +static yyconst short int yy_rule_linenum[18] = + { 0, + 109, 110, 129, 130, 135, 136, 137, 138, 139, 143, + 147, 151, 152, 153, 154, 155, 156 + } ; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "parser.l" +#define INITIAL 0 +/* + * IDL Compiler + * + * Copyright 2002 Ove Kaaven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#define YY_STACK_USED 1 +#define YY_NEVER_INTERACTIVE 1 +#define QUOTE 1 + +#define pp_line 2 + +#line 36 "parser.l" + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#include "widl.h" +#include "utils.h" +#include "parser.h" +#include "wine/wpp.h" + +#include "y.tab.h" + +#define YY_USE_PROTOS +#define YY_NO_UNPUT +#define YY_NO_TOP_STATE + +extern char *temp_name; + +static void addcchar(char c); +static char *get_buffered_cstring(void); + +static char *cbuffer; +static int cbufidx; +static int cbufalloc = 0; + +static int kw_token(const char *kw); + +#define MAX_IMPORT_DEPTH 10 +struct { + YY_BUFFER_STATE state; + char *input_name; + int line_number; + char *temp_name; +} import_stack[MAX_IMPORT_DEPTH]; +int import_stack_ptr = 0; + +static void pop_import(void); + +static UUID* parse_uuid(const char*u) +{ + UUID* uuid = xmalloc(sizeof(UUID)); + char b[3]; + /* it would be nice to use UuidFromStringA */ + uuid->Data1 = strtoul(u, NULL, 16); + uuid->Data2 = strtoul(u+9, NULL, 16); + uuid->Data3 = strtoul(u+14, NULL, 16); + b[2] = 0; + memcpy(b, u+19, 2); uuid->Data4[0] = strtoul(b, NULL, 16); + memcpy(b, u+21, 2); uuid->Data4[1] = strtoul(b, NULL, 16); + memcpy(b, u+24, 2); uuid->Data4[2] = strtoul(b, NULL, 16); + memcpy(b, u+26, 2); uuid->Data4[3] = strtoul(b, NULL, 16); + memcpy(b, u+28, 2); uuid->Data4[4] = strtoul(b, NULL, 16); + memcpy(b, u+30, 2); uuid->Data4[5] = strtoul(b, NULL, 16); + memcpy(b, u+32, 2); uuid->Data4[6] = strtoul(b, NULL, 16); + memcpy(b, u+34, 2); uuid->Data4[7] = strtoul(b, NULL, 16); + return uuid; +} + +/* + ************************************************************************** + * The flexer starts here + ************************************************************************** + */ +#line 3190 "lex.yy.c" + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap YY_PROTO(( void )); +#else +extern int yywrap YY_PROTO(( void )); +#endif +#endif + +#ifndef YY_NO_UNPUT +static void yyunput YY_PROTO(( int c, char *buf_ptr )); +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen YY_PROTO(( yyconst char * )); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif +#endif + +#if YY_STACK_USED +static int yy_start_stack_ptr = 0; +static int yy_start_stack_depth = 0; +static int *yy_start_stack = 0; +#ifndef YY_NO_PUSH_STATE +static void yy_push_state YY_PROTO(( int new_state )); +#endif +#ifndef YY_NO_POP_STATE +static void yy_pop_state YY_PROTO(( void )); +#endif +#ifndef YY_NO_TOP_STATE +static int yy_top_state YY_PROTO(( void )); +#endif + +#else +#define YY_NO_PUSH_STATE 1 +#define YY_NO_POP_STATE 1 +#define YY_NO_TOP_STATE 1 +#endif + +#ifdef YY_MALLOC_DECL +YY_MALLOC_DECL +#else +#if __STDC__ +#ifndef __cplusplus +#include <stdlib.h> +#endif +#else +/* Just try to get by without declaring the routines. This will fail + * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) + * or sizeof(void*) != sizeof(int). + */ +#endif +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ + +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( yy_current_buffer->yy_is_interactive ) \ + { \ + int c = '*', n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ + && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL int yylex YY_PROTO(( void )) +#endif + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + if ( yyleng > 0 ) \ + yy_current_buffer->yy_at_bol = \ + (yytext[yyleng - 1] == '\n'); \ + YY_USER_ACTION + +YY_DECL + { + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 108 "parser.l" + +#line 3346 "lex.yy.c" + + if ( yy_init ) + { + yy_init = 0; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yy_start ) + yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! yy_current_buffer ) + yy_current_buffer = + yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_load_buffer_state(); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yy_start; + yy_current_state += YY_AT_BOL(); +yy_match: + while ( (yy_current_state = yy_nxt[yy_current_state][YY_SC_TO_UI(*yy_cp)]) > 0 ) + { + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + + ++yy_cp; + } + + yy_current_state = -yy_current_state; + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + + +do_action: /* This label is used only to access EOF actions. */ + + if ( yy_flex_debug ) + { + if ( yy_act == 0 ) + fprintf( stderr, "--scanner backing up\n" ); + else if ( yy_act < 18 ) + fprintf( stderr, "--accepting rule at line %d (\"%s\")\n", + yy_rule_linenum[yy_act], yytext ); + else if ( yy_act == 18 ) + fprintf( stderr, "--accepting default rule (\"%s\")\n", + yytext ); + else if ( yy_act == 19 ) + fprintf( stderr, "--(end of buffer or a NUL)\n" ); + else + fprintf( stderr, "--EOF (start condition %d)\n", YY_START ); + } + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yy_hold_char; + yy_cp = yy_last_accepting_cpos + 1; + yy_current_state = yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 109 "parser.l" +yy_push_state(pp_line); + YY_BREAK +case 2: +YY_RULE_SETUP +#line 110 "parser.l" +{ + int lineno; + char *cptr, *fname; + yy_pop_state(); + lineno = (int)strtol(yytext, &cptr, 10); + if(!lineno) + yyerror("Malformed '#...' line-directive; invalid linenumber"); + fname = strchr(cptr, '"'); + if(!fname) + yyerror("Malformed '#...' line-directive; missing filename"); + fname++; + cptr = strchr(fname, '"'); + if(!cptr) + yyerror("Malformed '#...' line-directive; missing terminating \""); + *cptr = '\0'; + line_number = lineno - 1; /* We didn't read the newline */ + free( input_name ); + input_name = xstrdup(fname); + } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 129 "parser.l" +yy_push_state(QUOTE); cbufidx = 0; + YY_BREAK +case 4: +YY_RULE_SETUP +#line 130 "parser.l" +{ + yy_pop_state(); + yylval.str = get_buffered_cstring(); + return aSTRING; + } + YY_BREAK +case 5: +#line 136 "parser.l" +case 6: +YY_RULE_SETUP +#line 136 "parser.l" +addcchar(yytext[1]); + YY_BREAK +case 7: +YY_RULE_SETUP +#line 137 "parser.l" +addcchar('\\'); addcchar(yytext[1]); + YY_BREAK +case 8: +YY_RULE_SETUP +#line 138 "parser.l" +addcchar(yytext[0]); + YY_BREAK +case 9: +YY_RULE_SETUP +#line 139 "parser.l" +{ + yylval.uuid = parse_uuid(yytext); + return aUUID; + } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 143 "parser.l" +{ + yylval.num = strtoul(yytext, NULL, 0); + return aHEXNUM; + } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 147 "parser.l" +{ + yylval.num = strtoul(yytext, NULL, 0); + return aNUM; + } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 151 "parser.l" +return kw_token(yytext); + YY_BREAK +case 13: +YY_RULE_SETUP +#line 152 "parser.l" +line_number++; + YY_BREAK +case 14: +YY_RULE_SETUP +#line 153 "parser.l" + + YY_BREAK +case 15: +YY_RULE_SETUP +#line 154 "parser.l" +return SHL; + YY_BREAK +case 16: +YY_RULE_SETUP +#line 155 "parser.l" +return SHR; + YY_BREAK +case 17: +YY_RULE_SETUP +#line 156 "parser.l" +return yytext[0]; + YY_BREAK +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(QUOTE): +case YY_STATE_EOF(pp_line): +#line 157 "parser.l" +{ + if (import_stack_ptr) { + pop_import(); + return aEOF; + } + else yyterminate(); + } + YY_BREAK +case 18: +YY_RULE_SETUP +#line 164 "parser.l" +ECHO; + YY_BREAK +#line 3563 "lex.yy.c" + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between yy_current_buffer and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yy_n_chars = yy_current_buffer->yy_n_chars; + yy_current_buffer->yy_input_file = yyin; + yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + yy_did_buffer_switch_on_eof = 0; + + if ( yywrap() ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = + yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yy_c_buf_p = + &yy_current_buffer->yy_ch_buf[yy_n_chars]; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of yylex */ + + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ + +static int yy_get_next_buffer() + { + register char *dest = yy_current_buffer->yy_ch_buf; + register char *source = yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( yy_current_buffer->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + yy_current_buffer->yy_n_chars = yy_n_chars = 0; + + else + { + int num_to_read = + yy_current_buffer->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ +#ifdef YY_USES_REJECT + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); +#else + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = yy_current_buffer; + + int yy_c_buf_p_offset = + (int) (yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yy_flex_realloc( (void *) b->yy_ch_buf, + b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = yy_current_buffer->yy_buf_size - + number_to_move - 1; +#endif + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), + yy_n_chars, num_to_read ); + + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + if ( yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + yy_current_buffer->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yy_n_chars += number_to_move; + yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; + yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; + + return ret_val; + } + + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +static yy_state_type yy_get_previous_state() + { + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = yy_start; + yy_current_state += YY_AT_BOL(); + + for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + { + if ( *yy_cp ) + { + yy_current_state = yy_nxt[yy_current_state][YY_SC_TO_UI(*yy_cp)]; + } + else + yy_current_state = yy_NUL_trans[yy_current_state]; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + } + + return yy_current_state; + } + + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + +#ifdef YY_USE_PROTOS +static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) +#else +static yy_state_type yy_try_NUL_trans( yy_current_state ) +yy_state_type yy_current_state; +#endif + { + register int yy_is_jam; + register char *yy_cp = yy_c_buf_p; + + yy_current_state = yy_NUL_trans[yy_current_state]; + yy_is_jam = (yy_current_state == 0); + + if ( ! yy_is_jam ) + { + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + } + + return yy_is_jam ? 0 : yy_current_state; + } + + +#ifndef YY_NO_UNPUT +#ifdef YY_USE_PROTOS +static void yyunput( int c, register char *yy_bp ) +#else +static void yyunput( c, yy_bp ) +int c; +register char *yy_bp; +#endif + { + register char *yy_cp = yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yy_hold_char; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = yy_n_chars + 2; + register char *dest = &yy_current_buffer->yy_ch_buf[ + yy_current_buffer->yy_buf_size + 2]; + register char *source = + &yy_current_buffer->yy_ch_buf[number_to_move]; + + while ( source > yy_current_buffer->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + yy_current_buffer->yy_n_chars = + yy_n_chars = yy_current_buffer->yy_buf_size; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + + yytext_ptr = yy_bp; + yy_hold_char = *yy_cp; + yy_c_buf_p = yy_cp; + } +#endif /* ifndef YY_NO_UNPUT */ + + +#ifdef __cplusplus +static int yyinput() +#else +static int input() +#endif + { + int c; + + *yy_c_buf_p = yy_hold_char; + + if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* This was really a NUL. */ + *yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yy_c_buf_p - yytext_ptr; + ++yy_c_buf_p; + + switch ( yy_get_next_buffer() ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /* fall through */ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap() ) + return EOF; + + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ + *yy_c_buf_p = '\0'; /* preserve yytext */ + yy_hold_char = *++yy_c_buf_p; + + yy_current_buffer->yy_at_bol = (c == '\n'); + + return c; + } + + +#ifdef YY_USE_PROTOS +void yyrestart( FILE *input_file ) +#else +void yyrestart( input_file ) +FILE *input_file; +#endif + { + if ( ! yy_current_buffer ) + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_init_buffer( yy_current_buffer, input_file ); + yy_load_buffer_state(); + } + + +#ifdef YY_USE_PROTOS +void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +#else +void yy_switch_to_buffer( new_buffer ) +YY_BUFFER_STATE new_buffer; +#endif + { + if ( yy_current_buffer == new_buffer ) + return; + + if ( yy_current_buffer ) + { + /* Flush out information for old buffer. */ + *yy_c_buf_p = yy_hold_char; + yy_current_buffer->yy_buf_pos = yy_c_buf_p; + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + yy_current_buffer = new_buffer; + yy_load_buffer_state(); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yy_did_buffer_switch_on_eof = 1; + } + + +#ifdef YY_USE_PROTOS +void yy_load_buffer_state( void ) +#else +void yy_load_buffer_state() +#endif + { + yy_n_chars = yy_current_buffer->yy_n_chars; + yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; + yyin = yy_current_buffer->yy_input_file; + yy_hold_char = *yy_c_buf_p; + } + + +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) +#else +YY_BUFFER_STATE yy_create_buffer( file, size ) +FILE *file; +int size; +#endif + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; + } + + +#ifdef YY_USE_PROTOS +void yy_delete_buffer( YY_BUFFER_STATE b ) +#else +void yy_delete_buffer( b ) +YY_BUFFER_STATE b; +#endif + { + if ( ! b ) + return; + + if ( b == yy_current_buffer ) + yy_current_buffer = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yy_flex_free( (void *) b->yy_ch_buf ); + + yy_flex_free( (void *) b ); + } + + +#ifndef YY_ALWAYS_INTERACTIVE +#ifndef YY_NEVER_INTERACTIVE +extern int isatty YY_PROTO(( int )); +#endif +#endif + +#ifdef YY_USE_PROTOS +void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) +#else +void yy_init_buffer( b, file ) +YY_BUFFER_STATE b; +FILE *file; +#endif + + + { + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + +#if YY_ALWAYS_INTERACTIVE + b->yy_is_interactive = 1; +#else +#if YY_NEVER_INTERACTIVE + b->yy_is_interactive = 0; +#else + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; +#endif +#endif + } + + +#ifdef YY_USE_PROTOS +void yy_flush_buffer( YY_BUFFER_STATE b ) +#else +void yy_flush_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == yy_current_buffer ) + yy_load_buffer_state(); + } + + +#ifndef YY_NO_SCAN_BUFFER +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) +#else +YY_BUFFER_STATE yy_scan_buffer( base, size ) +char *base; +yy_size_t size; +#endif + { + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; + } +#endif + + +#ifndef YY_NO_SCAN_STRING +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) +#else +YY_BUFFER_STATE yy_scan_string( yy_str ) +yyconst char *yy_str; +#endif + { + int len; + for ( len = 0; yy_str[len]; ++len ) + ; + + return yy_scan_bytes( yy_str, len ); + } +#endif + + +#ifndef YY_NO_SCAN_BYTES +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) +#else +YY_BUFFER_STATE yy_scan_bytes( bytes, len ) +yyconst char *bytes; +int len; +#endif + { + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = len + 2; + buf = (char *) yy_flex_alloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < len; ++i ) + buf[i] = bytes[i]; + + buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; + } +#endif + + +#ifndef YY_NO_PUSH_STATE +#ifdef YY_USE_PROTOS +static void yy_push_state( int new_state ) +#else +static void yy_push_state( new_state ) +int new_state; +#endif + { + if ( yy_start_stack_ptr >= yy_start_stack_depth ) + { + yy_size_t new_size; + + yy_start_stack_depth += YY_START_STACK_INCR; + new_size = yy_start_stack_depth * sizeof( int ); + + if ( ! yy_start_stack ) + yy_start_stack = (int *) yy_flex_alloc( new_size ); + + else + yy_start_stack = (int *) yy_flex_realloc( + (void *) yy_start_stack, new_size ); + + if ( ! yy_start_stack ) + YY_FATAL_ERROR( + "out of memory expanding start-condition stack" ); + } + + yy_start_stack[yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); + } +#endif + + +#ifndef YY_NO_POP_STATE +static void yy_pop_state() + { + if ( --yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(yy_start_stack[yy_start_stack_ptr]); + } +#endif + + +#ifndef YY_NO_TOP_STATE +static int yy_top_state() + { + return yy_start_stack[yy_start_stack_ptr - 1]; + } +#endif + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +#ifdef YY_USE_PROTOS +static void yy_fatal_error( yyconst char msg[] ) +#else +static void yy_fatal_error( msg ) +char msg[]; +#endif + { + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); + } + + + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + yytext[yyleng] = yy_hold_char; \ + yy_c_buf_p = yytext + n; \ + yy_hold_char = *yy_c_buf_p; \ + *yy_c_buf_p = '\0'; \ + yyleng = n; \ + } \ + while ( 0 ) + + +/* Internal utility routines. */ + +#ifndef yytext_ptr +#ifdef YY_USE_PROTOS +static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) +#else +static void yy_flex_strncpy( s1, s2, n ) +char *s1; +yyconst char *s2; +int n; +#endif + { + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; + } +#endif + +#ifdef YY_NEED_STRLEN +#ifdef YY_USE_PROTOS +static int yy_flex_strlen( yyconst char *s ) +#else +static int yy_flex_strlen( s ) +yyconst char *s; +#endif + { + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; + } +#endif + + +#ifdef YY_USE_PROTOS +static void *yy_flex_alloc( yy_size_t size ) +#else +static void *yy_flex_alloc( size ) +yy_size_t size; +#endif + { + return (void *) malloc( size ); + } + +#ifdef YY_USE_PROTOS +static void *yy_flex_realloc( void *ptr, yy_size_t size ) +#else +static void *yy_flex_realloc( ptr, size ) +void *ptr; +yy_size_t size; +#endif + { + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); + } + +#ifdef YY_USE_PROTOS +static void yy_flex_free( void *ptr ) +#else +static void yy_flex_free( ptr ) +void *ptr; +#endif + { + free( ptr ); + } + +#if YY_MAIN +int main() + { + yylex(); + return 0; + } +#endif +#line 164 "parser.l" + + +#ifndef yywrap +int yywrap(void) +{ + return 1; +} +#endif + +static struct keyword { + const char *kw; + int token; + int val; +} keywords[] = { + {"__cdecl", tCDECL}, + {"__int64", tINT64}, + {"__stdcall", tSTDCALL}, + {"_stdcall", tSTDCALL}, + {"aggregatable", tAGGREGATABLE}, + {"allocate", tALLOCATE}, + {"appobject", tAPPOBJECT}, + {"arrays", tARRAYS}, + {"async", tASYNC}, + {"async_uuid", tASYNCUUID}, + {"auto_handle", tAUTOHANDLE}, + {"bindable", tBINDABLE}, + {"boolean", tBOOLEAN}, + {"broadcast", tBROADCAST}, + {"byte", tBYTE}, + {"byte_count", tBYTECOUNT}, + {"call_as", tCALLAS}, + {"callback", tCALLBACK}, + {"case", tCASE}, + {"char", tCHAR}, + {"coclass", tCOCLASS}, + {"code", tCODE}, + {"comm_status", tCOMMSTATUS}, + {"const", tCONST}, + {"context_handle", tCONTEXTHANDLE}, + {"context_handle_noserialize", tCONTEXTHANDLENOSERIALIZE}, + {"context_handle_serialize", tCONTEXTHANDLENOSERIALIZE}, + {"control", tCONTROL}, + {"cpp_quote", tCPPQUOTE}, +/* ... */ + {"default", tDEFAULT}, + {"defaultvalue", tDEFAULTVALUE}, +/* ... */ + {"dispinterface", tDISPINTERFACE}, +/* ... */ + {"dllname", tDLLNAME}, + {"double", tDOUBLE}, + {"dual", tDUAL}, +/* ... */ + {"endpoint", tENDPOINT}, + {"entry", tENTRY}, + {"enum", tENUM}, + {"error_status_t", tERRORSTATUST}, + {"explicit_handle", tEXPLICITHANDLE}, + {"extern", tEXTERN}, +/* ... */ + {"float", tFLOAT}, +/* ... */ + {"handle", tHANDLE}, + {"handle_t", tHANDLET}, +/* ... */ + {"helpcontext", tHELPCONTEXT}, + {"helpfile", tHELPFILE}, + {"helpstring", tHELPSTRING}, + {"helpstringcontext", tHELPSTRINGCONTEXT}, + {"helpstringdll", tHELPSTRINGDLL}, +/* ... */ + {"hidden", tHIDDEN}, + {"hyper", tHYPER}, + {"id", tID}, + {"idempotent", tIDEMPOTENT}, +/* ... */ + {"iid_is", tIIDIS}, +/* ... */ + {"implicit_handle", tIMPLICITHANDLE}, + {"import", tIMPORT}, + {"importlib", tIMPORTLIB}, + {"in", tIN}, + {"include", tINCLUDE}, + {"in_line", tINLINE}, + {"input_sync", tINPUTSYNC}, + {"int", tINT}, +/* ... */ + {"interface", tINTERFACE}, +/* ... */ + {"length_is", tLENGTHIS}, + {"library", tLIBRARY}, +/* ... */ + {"local", tLOCAL}, + {"long", tLONG}, +/* ... */ + {"methods", tMETHODS}, +/* ... */ + {"module", tMODULE}, +/* ... */ + {"noncreatable", tNONCREATABLE}, + {"object", tOBJECT}, + {"odl", tODL}, + {"oleautomation", tOLEAUTOMATION}, +/* ... */ + {"optional", tOPTIONAL}, + {"out", tOUT}, +/* ... */ + {"pointer_default", tPOINTERDEFAULT}, +/* ... */ + {"properties", tPROPERTIES}, + {"propget", tPROPGET}, + {"propput", tPROPPUT}, + {"propputref", tPROPPUTREF}, +/* ... */ + {"ptr", tPTR}, + {"public", tPUBLIC}, +/* ... */ + {"readonly", tREADONLY}, + {"ref", tREF}, +/* ... */ + {"restricted", tRESTRICTED}, + {"retval", tRETVAL}, +/* ... */ + {"short", tSHORT}, + {"signed", tSIGNED}, + {"single", tSINGLE}, + {"size_is", tSIZEIS}, + {"sizeof", tSIZEOF}, +/* ... */ + {"small", tSMALL}, + {"source", tSOURCE}, +/* ... */ + {"string", tSTRING}, + {"struct", tSTRUCT}, + {"switch", tSWITCH}, + {"switch_is", tSWITCHIS}, + {"switch_type", tSWITCHTYPE}, +/* ... */ + {"transmit_as", tTRANSMITAS}, + {"typedef", tTYPEDEF}, +/* ... */ + {"union", tUNION}, + {"unique", tUNIQUE}, + {"unsigned", tUNSIGNED}, +/* ... */ + {"uuid", tUUID}, + {"v1_enum", tV1ENUM}, +/* ... */ + {"vararg", tVARARG}, + {"version", tVERSION}, + {"void", tVOID}, + {"wchar_t", tWCHAR}, + {"wire_marshal", tWIREMARSHAL} +}; +#define NKEYWORDS (sizeof(keywords)/sizeof(keywords[0])) +#define KWP(p) ((const struct keyword *)(p)) + +static int kw_cmp_func(const void *s1, const void *s2) +{ + return strcmp(KWP(s1)->kw, KWP(s2)->kw); +} + +#define KW_BSEARCH +static int kw_token(const char *kw) +{ + struct keyword key, *kwp; + key.kw = kw; +#ifdef KW_BSEARCH + kwp = bsearch(&key, keywords, NKEYWORDS, sizeof(keywords[0]), kw_cmp_func); +#else + { + int i; + for (kwp=NULL, i=0; i < NKEYWORDS; i++) + if (!kw_cmp_func(&key, &keywords[i])) { + kwp = &keywords[i]; + break; + } + } +#endif + if (kwp) { + yylval.str = (char*)kwp->kw; + return kwp->token; + } + yylval.str = xstrdup(kw); + return is_type(kw) ? aKNOWNTYPE : aIDENTIFIER; +} + +static void addcchar(char c) +{ + if(cbufidx >= cbufalloc) + { + cbufalloc += 1024; + cbuffer = xrealloc(cbuffer, cbufalloc * sizeof(cbuffer[0])); + if(cbufalloc > 65536) + yywarning("Reallocating string buffer larger than 64kB"); + } + cbuffer[cbufidx++] = c; +} + +static char *get_buffered_cstring(void) +{ + addcchar(0); + return xstrdup(cbuffer); +} + +static void pop_import(void) +{ + int ptr = import_stack_ptr-1; + + fclose(yyin); + yy_delete_buffer( YY_CURRENT_BUFFER ); + yy_switch_to_buffer( import_stack[ptr].state ); + if (temp_name) { + unlink(temp_name); + free(temp_name); + } + temp_name = import_stack[ptr].temp_name; + free( input_name ); + input_name = import_stack[ptr].input_name; + line_number = import_stack[ptr].line_number; + import_stack_ptr--; +} + +struct imports { + char *name; + struct imports *next; +} *first_import; + +int do_import(char *fname) +{ + FILE *f; + char *hname, *path, *p; + struct imports *import; + int ptr = import_stack_ptr; + int ret; + + if (!parse_only && do_header) { + hname = dup_basename(fname, ".idl"); + p = hname + strlen(hname) - 2; + if (p <= hname || strcmp( p, ".h" )) strcat(hname, ".h"); + + fprintf(header, "#include <%s>\n", hname); + free(hname); + } + + import = first_import; + while (import && strcmp(import->name, fname)) + import = import->next; + if (import) return 0; /* already imported */ + + import = xmalloc(sizeof(struct imports)); + import->name = xstrdup(fname); + import->next = first_import; + first_import = import; + + if (!(path = wpp_find_include( fname, 1 ))) + yyerror("Unable to open include file %s", fname); + + import_stack[ptr].temp_name = temp_name; + import_stack[ptr].input_name = input_name; + import_stack[ptr].line_number = line_number; + import_stack_ptr++; + input_name = path; + line_number = 1; + + ret = wpp_parse_temp( path, NULL, &temp_name ); + if (ret) exit(1); + + if((f = fopen(temp_name, "r")) == NULL) + yyerror("Unable to open %s", temp_name); + + import_stack[ptr].state = YY_CURRENT_BUFFER; + yy_switch_to_buffer(yy_create_buffer(f, YY_BUF_SIZE)); + return 1; +} + +void abort_import(void) +{ + int ptr; + + for (ptr=0; ptr<import_stack_ptr; ptr++) + unlink(import_stack[ptr].temp_name); +} diff --git a/reactos/tools/widl/port/mkstemps.c b/reactos/tools/widl/port/mkstemps.c index 063afccac13..9919eac949f 100644 --- a/reactos/tools/widl/port/mkstemps.c +++ b/reactos/tools/widl/port/mkstemps.c @@ -1,138 +1,138 @@ -/* Copyright (C) 1991, 1992, 1996, 1998 Free Software Foundation, Inc. - This file is derived from mkstemp.c from the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#include "config.h" - -#include <sys/types.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <stdio.h> -#include <fcntl.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#ifdef HAVE_PROCESS_H -#include <process.h> -#endif - -/* We need to provide a type for gcc_uint64_t. */ -#ifdef __GNUC__ -__extension__ typedef unsigned long long gcc_uint64_t; -#else -typedef unsigned long gcc_uint64_t; -#endif - -#ifndef TMP_MAX -#define TMP_MAX 16384 -#endif - -/* - -@deftypefn Replacement int mkstemps (char *@var{template}, int @var{suffix_len}) - -Generate a unique temporary file name from @var{template}. -@var{template} has the form: - -@example - @var{path}/ccXXXXXX@var{suffix} -@end example - -@var{suffix_len} tells us how long @var{suffix} is (it can be zero -length). The last six characters of @var{template} before @var{suffix} -must be @samp{XXXXXX}; they are replaced with a string that makes the -filename unique. Returns a file descriptor open on the file for -reading and writing. - -@end deftypefn - -*/ - -int -mkstemps ( - char *template, - int suffix_len) -{ - static const char letters[] - = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - static gcc_uint64_t value; -#ifdef HAVE_GETTIMEOFDAY - struct timeval tv; -#endif - char *XXXXXX; - size_t len; - int count; - - len = strlen (template); - - if ((int) len < 6 + suffix_len - || strncmp (&template[len - 6 - suffix_len], "XXXXXX", 6)) - { - return -1; - } - - XXXXXX = &template[len - 6 - suffix_len]; - -#ifdef HAVE_GETTIMEOFDAY - /* Get some more or less random data. */ - gettimeofday (&tv, NULL); - value += ((gcc_uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid (); -#else - value += getpid (); -#endif - - for (count = 0; count < TMP_MAX; ++count) - { - gcc_uint64_t v = value; - int fd; - - /* Fill in the random bits. */ - XXXXXX[0] = letters[v % 62]; - v /= 62; - XXXXXX[1] = letters[v % 62]; - v /= 62; - XXXXXX[2] = letters[v % 62]; - v /= 62; - XXXXXX[3] = letters[v % 62]; - v /= 62; - XXXXXX[4] = letters[v % 62]; - v /= 62; - XXXXXX[5] = letters[v % 62]; - -#ifdef VMS - fd = open (template, O_RDWR|O_CREAT|O_EXCL, 0600, "fop=tmd"); -#else - fd = open (template, O_RDWR|O_CREAT|O_EXCL, 0600); -#endif - if (fd >= 0) - /* The file does not exist. */ - return fd; - - /* This is a random value. It is only necessary that the next - TMP_MAX values generated by adding 7777 to VALUE are different - with (module 2^32). */ - value += 7777; - } - - /* We return the null string if we can't find a unique file name. */ - template[0] = '\0'; - return -1; -} +/* Copyright (C) 1991, 1992, 1996, 1998 Free Software Foundation, Inc. + This file is derived from mkstemp.c from the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "config.h" + +#include <sys/types.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> +#include <fcntl.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#ifdef HAVE_PROCESS_H +#include <process.h> +#endif + +/* We need to provide a type for gcc_uint64_t. */ +#ifdef __GNUC__ +__extension__ typedef unsigned long long gcc_uint64_t; +#else +typedef unsigned long gcc_uint64_t; +#endif + +#ifndef TMP_MAX +#define TMP_MAX 16384 +#endif + +/* + +@deftypefn Replacement int mkstemps (char *@var{template}, int @var{suffix_len}) + +Generate a unique temporary file name from @var{template}. +@var{template} has the form: + +@example + @var{path}/ccXXXXXX@var{suffix} +@end example + +@var{suffix_len} tells us how long @var{suffix} is (it can be zero +length). The last six characters of @var{template} before @var{suffix} +must be @samp{XXXXXX}; they are replaced with a string that makes the +filename unique. Returns a file descriptor open on the file for +reading and writing. + +@end deftypefn + +*/ + +int +mkstemps ( + char *template, + int suffix_len) +{ + static const char letters[] + = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + static gcc_uint64_t value; +#ifdef HAVE_GETTIMEOFDAY + struct timeval tv; +#endif + char *XXXXXX; + size_t len; + int count; + + len = strlen (template); + + if ((int) len < 6 + suffix_len + || strncmp (&template[len - 6 - suffix_len], "XXXXXX", 6)) + { + return -1; + } + + XXXXXX = &template[len - 6 - suffix_len]; + +#ifdef HAVE_GETTIMEOFDAY + /* Get some more or less random data. */ + gettimeofday (&tv, NULL); + value += ((gcc_uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid (); +#else + value += getpid (); +#endif + + for (count = 0; count < TMP_MAX; ++count) + { + gcc_uint64_t v = value; + int fd; + + /* Fill in the random bits. */ + XXXXXX[0] = letters[v % 62]; + v /= 62; + XXXXXX[1] = letters[v % 62]; + v /= 62; + XXXXXX[2] = letters[v % 62]; + v /= 62; + XXXXXX[3] = letters[v % 62]; + v /= 62; + XXXXXX[4] = letters[v % 62]; + v /= 62; + XXXXXX[5] = letters[v % 62]; + +#ifdef VMS + fd = open (template, O_RDWR|O_CREAT|O_EXCL, 0600, "fop=tmd"); +#else + fd = open (template, O_RDWR|O_CREAT|O_EXCL, 0600); +#endif + if (fd >= 0) + /* The file does not exist. */ + return fd; + + /* This is a random value. It is only necessary that the next + TMP_MAX values generated by adding 7777 to VALUE are different + with (module 2^32). */ + value += 7777; + } + + /* We return the null string if we can't find a unique file name. */ + template[0] = '\0'; + return -1; +} diff --git a/reactos/tools/widl/server.c b/reactos/tools/widl/server.c index e586349f16c..4fed72ceb65 100644 --- a/reactos/tools/widl/server.c +++ b/reactos/tools/widl/server.c @@ -1,2092 +1,2092 @@ -/* - * IDL Compiler - * - * Copyright 2005 Eric Kohl - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <stdio.h> -#include <stdlib.h> -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#endif -#include <string.h> -#include <assert.h> -#include <ctype.h> -#include <signal.h> - -#include "widl.h" -#include "utils.h" -#include "parser.h" -#include "header.h" - -#define END_OF_LIST(list) \ - do { \ - if (list) { \ - while (NEXT_LINK(list)) \ - list = NEXT_LINK(list); \ - } \ - } while(0) - -static FILE* server; -static int indent = 0; - - -static int print_server(const char *format, ...) -{ - va_list va; - int i, r; - - va_start(va, format); - for (i = 0; i < indent; i++) - fprintf(server, " "); - r = vfprintf(server, format, va); - va_end(va); - return r; -} - - -static unsigned int -get_var_stack_offset_32(func_t *func, char *name) -{ - unsigned int offset = 0; - var_t *var; - - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - if (!strcmp(var->name, name)) - return offset; - - if (var->type->type == RPC_FC_DOUBLE || - var->type->type == RPC_FC_HYPER) - offset += 8; - else - offset += 4; - - var = PREV_LINK(var); - } - - return 0; -} - - -static unsigned int -get_var_stack_offset_64(func_t *func, char *name) -{ - unsigned int offset = 0; - var_t *var; - - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - if (!strcmp(var->name, name)) - return offset; - - offset += 8; - - var = PREV_LINK(var); - } - - return 0; -} - - -static unsigned int -get_var_type_offset(var_t *var) -{ - unsigned int toffset = 0; - void *sizeis_attr; - int string_attr; - - if (var->ptr_level == 0) - { - if ((var->type->type == RPC_FC_RP) && - (var->type->ref->ref->type == RPC_FC_STRUCT)) - { - var_t *field = var->type->ref->ref->fields; - int tsize = 9; - - while (NEXT_LINK(field)) field = NEXT_LINK(field); - while (field) - { - tsize++; - field = PREV_LINK(field); - } - if (tsize % 2) - tsize++; - - toffset += tsize; - } - } - else if (var->ptr_level == 1) - { - sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); - string_attr = is_attr(var->attrs, ATTR_STRING); - - if (sizeis_attr) - { - if (string_attr) - { - if (var->type->type == RPC_FC_BYTE || - var->type->type == RPC_FC_CHAR || - var->type->type == RPC_FC_WCHAR) - toffset += 10; - } - else - { - if (is_base_type(var->type)) - toffset += 14; - } - } - else - { - if (is_base_type(var->type)) - toffset += 4; - } - } - - return toffset; -} - - -static type_t *get_type_by_name(func_t *func, char *name) -{ - var_t *var; - - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - if (!strcmp(var->name, name)) - return var->type; - - var = PREV_LINK(var); - } - - return NULL; -} - - -static unsigned char -get_base_type(unsigned char type) -{ - - switch (type) - { - case RPC_FC_USHORT: - type = RPC_FC_SHORT; - break; - - case RPC_FC_ULONG: - type = RPC_FC_LONG; - break; - } - - return type; -} - - -static int get_type_size(type_t *type, int alignment) -{ - int size; - var_t *field; - - switch(type->type) - { - case RPC_FC_BYTE: - case RPC_FC_CHAR: - case RPC_FC_SMALL: - size = 1; - size = ((size + alignment - 1) & ~(alignment -1)); - break; - - case RPC_FC_WCHAR: - case RPC_FC_USHORT: - case RPC_FC_SHORT: - size = 2; - size = ((size + alignment - 1) & ~(alignment -1)); - break; - - case RPC_FC_ULONG: - case RPC_FC_LONG: - case RPC_FC_FLOAT: - size = 4; - size = ((size + alignment - 1) & ~(alignment -1)); - break; - - case RPC_FC_HYPER: - case RPC_FC_DOUBLE: - size = 8; - size = ((size + alignment - 1) & ~(alignment -1)); - break; - - case RPC_FC_IGNORE: - size = 0; - break; - - case RPC_FC_STRUCT: - field = type->fields; - size = 0; - while (NEXT_LINK(field)) field = NEXT_LINK(field); - while (field) - { - size += get_type_size(field->type, alignment); - field = PREV_LINK(field); - } - break; - - default: - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, type->type); - return 0; - } - - return size; -} - - -static int get_type_alignment(type_t *type) -{ - int size; - - switch(type->type) - { - case RPC_FC_BYTE: - case RPC_FC_CHAR: - case RPC_FC_SMALL: - size = 1; - break; - - case RPC_FC_WCHAR: - case RPC_FC_USHORT: - case RPC_FC_SHORT: - size = 2; - break; - - case RPC_FC_ULONG: - case RPC_FC_LONG: - case RPC_FC_FLOAT: - size = 4; - break; - - case RPC_FC_HYPER: - case RPC_FC_DOUBLE: - size = 8; - break; - - default: - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, type->type); - return 0; - } - - return size; -} - - -static void write_procformatstring(type_t *iface) -{ - func_t *func = iface->funcs; - var_t *var; - unsigned int type_offset = 2; - int in_attr, out_attr; - - print_server("const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n"); - print_server("{\n"); - indent++; - print_server("0,\n"); - print_server("{\n"); - indent++; - - while (NEXT_LINK(func)) func = NEXT_LINK(func); - while (func) - { - /* emit argument data */ - if (func->args) - { - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - out_attr = is_attr(var->attrs, ATTR_OUT); - in_attr = is_attr(var->attrs, ATTR_IN); - - /* set 'in' attribute if neither 'in' nor 'out' is set */ - if (!out_attr && !in_attr) - in_attr = 1; - - if (var->ptr_level == 0) - { - if (is_base_type(var->type)) - { - print_server("0x4e, /* FC_IN_PARAM_BASETYPE */\n"); - print_server("0x%02x, /* FC_<type> */\n", get_base_type(var->type->type)); - } - else if (var->type->type == RPC_FC_RP) - { - if (in_attr & !out_attr) - print_server("0x4d, /* FC_IN_PARAM */\n"); - else if (!in_attr & out_attr) - print_server("0x51, /* FC_OUT_PARAM */\n"); - else if (in_attr & out_attr) - print_server("0x50, /* FC_IN_OUT_PARAM */\n"); - fprintf(server, "#ifndef _ALPHA_\n"); - print_server("0x01,\n"); - fprintf(server, "#else\n"); - print_server("0x02,\n"); - fprintf(server, "#endif\n"); - print_server("NdrFcShort(0x%x),\n", type_offset); - } - else - { - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, var->type->type); - return; - } - } - else if (var->ptr_level == 1) - { -// if (is_base_type(var->type)) -// { - if (in_attr & !out_attr) - print_server("0x4d, /* FC_IN_PARAM */\n"); - else if (!in_attr & out_attr) - print_server("0x51, /* FC_OUT_PARAM */\n"); - else if (in_attr & out_attr) - print_server("0x50, /* FC_IN_OUT_PARAM */\n"); - fprintf(server, "#ifndef _ALPHA_\n"); - print_server("0x01,\n"); - fprintf(server, "#else\n"); - print_server("0x02,\n"); - fprintf(server, "#endif\n"); - print_server("NdrFcShort(0x%x),\n", type_offset); -// } -// else -// { -// error("%s:%d Unknown/unsupported type 0x%x\n", -// __FUNCTION__,__LINE__, var->type->type); -// return; -// } - } - - type_offset += get_var_type_offset(var); - - var = PREV_LINK(var); - } - } - - /* emit return value data */ - var = func->def; - if (is_void(var->type, NULL)) - { - print_server("0x5b, /* FC_END */\n"); - print_server("0x5c, /* FC_PAD */\n"); - } - else if (is_base_type(var->type)) - { - print_server("0x53, /* FC_RETURN_PARAM_BASETYPE */\n"); - print_server("0x%02x, /* FC_<type> */\n", get_base_type(var->type->type)); - } - else - { - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, var->type->type); - return; - } - - func = PREV_LINK(func); - } - - print_server("0x0\n"); - indent--; - print_server("}\n"); - indent--; - print_server("};\n"); - print_server("\n"); -} - - -static void write_typeformatstring(type_t *iface) -{ - func_t *func = iface->funcs; - var_t *var; - type_t *type; - int in_attr, out_attr; - int string_attr; - int ptr_attr, ref_attr, unique_attr; - void *sizeis_attr; - - print_server("const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =\n"); - print_server("{\n"); - indent++; - print_server("0,\n"); - print_server("{\n"); - indent++; - print_server("NdrFcShort(0x0),\n"); - - while (NEXT_LINK(func)) func = NEXT_LINK(func); - while (func) - { - if (func->args) - { - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - in_attr = is_attr(var->attrs, ATTR_IN); - out_attr = is_attr(var->attrs, ATTR_OUT); - string_attr = is_attr(var->attrs, ATTR_STRING); - - if (var->ptr_level > 1) - { - error("Function '%s' argument '%s': Pointer level %d not supported!\n", - func->def->name, var->name, var->ptr_level); - return; - } - - if (var->ptr_level == 0) - { - if (!is_base_type(var->type)) - { - if (var->type->type == RPC_FC_RP) - { - var_t *field; - int tsize = 9; - unsigned char flags = 0; - - if (!in_attr & out_attr) - flags |= RPC_FC_P_ONSTACK; - - print_server("0x11, 0x%02X, /* FC_RP, [flags] */\n", flags); - print_server("NdrFcShort(0x%02X),\n", 0x02); - print_server("0x%02X,\n", var->type->ref->ref->type); - print_server("0x%02X,\n", 3); /* alignment -1 */ - print_server("NdrFcShort(0x%02X),\n", get_type_size(var->type->ref->ref, 4)); - - field = var->type->ref->ref->fields; - while (NEXT_LINK(field)) field = NEXT_LINK(field); - while (field) - { - print_server("0x%02X,\n", get_base_type(field->type->type)); - tsize++; - field = PREV_LINK(field); - } - if (tsize % 2) - { - print_server("0x5c, /* FC_PAD */\n"); - tsize++; - } - print_server("0x5b, /* FC_END */\n"); - } - else - { - - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, var->type->type); - return; - } - } - } - else if (var->ptr_level == 1) - { - ptr_attr = is_attr(var->attrs, ATTR_PTR); - ref_attr = is_attr(var->attrs, ATTR_REF); - unique_attr = is_attr(var->attrs, ATTR_UNIQUE); - sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); - - if (ptr_attr + ref_attr + unique_attr == 0) - ref_attr = 1; - - if (sizeis_attr) - { - unsigned char type_type = 0; - - type = get_type_by_name(func, ((var_t *)sizeis_attr)->name); - if (type != NULL) - type_type = type->type; - - print_server("0x11, 0x00, /* FC_RP */\n"); - print_server("NdrFcShort(0x02),\n"); - - if (string_attr) - { - if (var->type->type == RPC_FC_WCHAR) - print_server("0x25, /* FC_C_WSTRING */\n"); - else - print_server("0x22, /* FC_C_CSTRING */\n"); - print_server("0x44, /* FC_STRING_SIZED */\n"); - print_server("0x%02x,\n", 0x20 + type_type); - print_server("0x00,\n"); - - fprintf(server, "#ifndef _ALPHA_\n"); - print_server("NdrFcShort(0x%02X),\n", - get_var_stack_offset_32(func, ((var_t *)sizeis_attr)->name)); - fprintf(server, "#else\n"); - print_server("NdrFcShort(0x%02X),\n", - get_var_stack_offset_64(func, ((var_t *)sizeis_attr)->name)); - fprintf(server, "#endif\n"); - } - else - { - print_server("0x1b, /* FC_CARRAY */\n"); - print_server("0x%02x,\n", get_type_alignment(var->type) - 1); - print_server("NdrFcShort(0x%02x),\n", get_type_size(var->type, 1)); - print_server("0x%02x,\n", 0x20 + type_type); - if (out_attr) - print_server("0x54 /* FC_DEREFERENCE */,\n"); - else - print_server("0x00 /* */,\n"); - - fprintf(server, "#ifndef _ALPHA_\n"); - print_server("NdrFcShort(0x%02X),\n", - get_var_stack_offset_32(func, ((var_t *)sizeis_attr)->name)); - fprintf(server, "#else\n"); - print_server("NdrFcShort(0x%02X),\n", - get_var_stack_offset_64(func, ((var_t *)sizeis_attr)->name)); - fprintf(server, "#endif\n"); - print_server("0x%02x,\n", get_base_type(var->type->type)); - print_server("0x5b, /* FC_END */\n"); - } - } - else if (is_base_type(var->type)) - { - if (out_attr && !in_attr) - { - if (ref_attr) - print_server("0x11, 0x0c, /* FC_RP [allocated_on_stack] [simple_pointer] */\n"); - else if (unique_attr) - print_server("0x12, 0x0c, /* FC_FP [allocated_on_stack] [simple_pointer] */\n"); - else if (ptr_attr) - print_server("0x14, 0x0c, /* FC_FP [allocated_on_stack] [simple_pointer] */\n"); - } - else - { - if (ref_attr) - print_server("0x11, 0x08, /* FC_RP [simple_pointer] */\n"); - else if (unique_attr) - print_server("0x12, 0x08, /* FC_UP [simple_pointer] */\n"); - else if (ptr_attr) - print_server("0x14, 0x08, /* FC_FP [simple_pointer] */\n"); - } - - if (string_attr) - { - if (var->type->type == RPC_FC_CHAR) - print_server("0x%02x, /* FC_C_CSTRING */\n", RPC_FC_C_CSTRING); - else if (var->type->type == RPC_FC_WCHAR) - print_server("0x%02x, /* FC_C_WSTRING */\n", RPC_FC_C_WSTRING); - else - { - error("%s: Invalid type!\n", __FUNCTION__); - return; - } - } - else - print_server("0x%02x, /* FC_<type> */\n", get_base_type(var->type->type)); - print_server("0x5c, /* FC_PAD */\n"); - } - } - - var = PREV_LINK(var); - } - } - - - - func = PREV_LINK(func); - } - - print_server("0x0\n"); - indent--; - print_server("}\n"); - indent--; - print_server("};\n"); - print_server("\n"); -} - - -static void print_message_buffer_size(func_t *func, unsigned int *type_offset) -{ - unsigned int alignment = 0; - int size = 0; - int last_size = -1; - int in_attr; - int out_attr; - int string_attr; - void *sizeis_attr; - int empty_line; - var_t *var; - - int first_padding = 0; - int padding = 0; - int add_plus = 0; - - unsigned int local_type_offset = *type_offset; - - fprintf(server, "\n"); - print_server("_StubMsg.BufferLength ="); - if (func->args) - { - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - for (; var; var = PREV_LINK(var)) - { - out_attr = is_attr(var->attrs, ATTR_OUT); - string_attr = is_attr(var->attrs, ATTR_STRING); - sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); - - if (out_attr) - { - if (var->ptr_level == 1) - { - if (sizeis_attr) - { - if (string_attr && - (var->type->type == RPC_FC_BYTE || - var->type->type == RPC_FC_CHAR || - var->type->type == RPC_FC_WCHAR)) - { - size =12; - } - else - { - size = 4; - } - } - else if (is_base_type(var->type)) - { - alignment = 0; - switch (var->type->type) - { - case RPC_FC_BYTE: - case RPC_FC_CHAR: - case RPC_FC_SMALL: - size = 1; - alignment = 0; - break; - - case RPC_FC_WCHAR: - case RPC_FC_USHORT: - case RPC_FC_SHORT: - size = 2; - if (last_size > 0 && last_size < 2) - alignment += (2 - last_size); - break; - - case RPC_FC_ULONG: - case RPC_FC_LONG: - case RPC_FC_FLOAT: - size = 4; - if (last_size > 0 && last_size < 4) - alignment += (4 - last_size); - break; - - case RPC_FC_HYPER: - case RPC_FC_DOUBLE: - size = 8; - if (last_size > 0 && last_size < 4) - alignment += (4 - last_size); - break; - - default: - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, var->type->type); - return; - } - } - } - else if (var->type->type == RPC_FC_RP) - { - size = 12; - } - - if (size != 0) - { - if (add_plus) - fprintf(server, " +"); - fprintf(server, " %dU", size + alignment + first_padding + padding); - - if (first_padding != 0) - first_padding = 0; - - last_size = size; - add_plus = 1; - } - - /* set paddings */ - if (var->ptr_level == 1) - { - if (sizeis_attr) - { - if (string_attr && - (var->type->type == RPC_FC_BYTE || - var->type->type == RPC_FC_CHAR || - var->type->type == RPC_FC_WCHAR)) - { - first_padding = 3; - if (var->type->type == RPC_FC_BYTE || - var->type->type == RPC_FC_CHAR) - first_padding++; - padding = 3; - } - else - { - first_padding = 4; - padding = 3; - } - } - } - - /* calculate the next type offset */ - local_type_offset += get_var_type_offset(var); - } - } - } - - /* return value size */ - if (!is_void(func->def->type, NULL)) - { - switch(func->def->type->type) - { - case RPC_FC_BYTE: - case RPC_FC_SMALL: - case RPC_FC_CHAR: - case RPC_FC_WCHAR: - case RPC_FC_USHORT: - case RPC_FC_SHORT: - case RPC_FC_ULONG: - case RPC_FC_LONG: - case RPC_FC_FLOAT: - size = 4; - if (last_size > 0 && last_size < 4) - alignment += (4 - last_size); - break; - - case RPC_FC_HYPER: - case RPC_FC_DOUBLE: - size = 8; - if (last_size > 0 && last_size < 4) - alignment += (4 - last_size); - break; - - default: - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, func->def->type->type); - return; - } - - if (add_plus) - fprintf(server, " +"); - - fprintf(server, " %dU", size + alignment + first_padding + padding); - } - - if (size == 0) - fprintf(server, "0U"); - - fprintf(server, ";\n"); - - - if (func->args) - { - local_type_offset = *type_offset; - - empty_line = 0; - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - for (; var; var = PREV_LINK(var)) - { - out_attr = is_attr(var->attrs, ATTR_OUT); - in_attr = is_attr(var->attrs, ATTR_IN); - string_attr = is_attr(var->attrs, ATTR_STRING); - sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); - - /* set 'in' attribute if neither 'in' nor 'out' is found */ - if (!out_attr && !in_attr) - in_attr = 1; - - if (out_attr) - { - if (var->ptr_level == 1 && sizeis_attr != NULL) - { - if (string_attr) - { - if (var->type->type == RPC_FC_BYTE || - var->type->type == RPC_FC_CHAR || - var->type->type == RPC_FC_WCHAR) - { - print_server("_StubMsg.MaxCount = %s;\n", ((var_t *)sizeis_attr)->name); - fprintf(server, "\n"); - print_server("NdrConformantStringBufferSize(\n"); - indent++; - print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_server("(unsigned char __RPC_FAR *)%s,\n", var->name); - print_server("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", - local_type_offset + 4); - indent--; - } - } - else - { - if (((var_t *)sizeis_attr)->ptr_level == 0) - print_server("_StubMsg.MaxCount = %s;\n", ((var_t *)sizeis_attr)->name); - else - print_server("_StubMsg.MaxCount = %s ? *%s : 0;\n", - ((var_t *)sizeis_attr)->name, ((var_t *)sizeis_attr)->name); - fprintf(server, "\n"); - print_server("NdrConformantArrayBufferSize(\n"); - indent++; - print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_server("(unsigned char __RPC_FAR *)%s,\n", var->name); - print_server("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", - local_type_offset + 4); - indent--; - } - - empty_line = 1; - } - else if (var->type->type == RPC_FC_RP) - { - fprintf(server,"\n"); - print_server("NdrSimpleStructBufferSize(\n"); - indent++; - print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_server("(unsigned char __RPC_FAR *)%s,\n", var->name); - print_server("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", - local_type_offset + 4); /* FIXME */ - indent--; - fprintf(server,"\n"); - } - } - - /* calculate the next type offset */ - local_type_offset += get_var_type_offset(var); - } - - if (empty_line) - fprintf(server, "\n"); - } - - /* get string size */ - if (func->args) - { - empty_line = 0; - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - for (; var; var = PREV_LINK(var)) - { - out_attr = is_attr(var->attrs, ATTR_OUT); - in_attr = is_attr(var->attrs, ATTR_IN); - string_attr = is_attr(var->attrs, ATTR_STRING); - - /* set 'in' attribute if neither 'in' nor 'out' is found */ - if (!out_attr && !in_attr) - in_attr = 1; - - if (var->ptr_level == 1 && - string_attr && - (var->type->type == RPC_FC_BYTE || - var->type->type == RPC_FC_CHAR || - var->type->type == RPC_FC_WCHAR)) - { - print_server("_StubMsg.BufferLength += 16;\n"); - empty_line = 1; - } - } - - if (empty_line) - fprintf(server, "\n"); - } -} - - -static void init_pointers (func_t *func) -{ - var_t *var; - int count = 0; - - if (!func->args) - return; - - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - if (var->ptr_level == 0) - { - if (var->type->type == RPC_FC_RP) - { - print_server("*("); - write_type(server, var->type, NULL, var->tname); - fprintf(server, "*)&%s = NULL;\n", var->name); - count++; - } - } - else if (var->ptr_level == 1) - { - print_server("%s = (", var->name); - write_type(server, var->type, NULL, var->tname); - fprintf(server, " __RPC_FAR *)0;\n"); - count++; - } - else if (var->ptr_level > 1) - { - error("Pointer level %d not supported!\n", var->ptr_level); - return; - } - - var = PREV_LINK(var); - } - - if (count > 0) - fprintf(server, "\n"); -} - - -static void unmarshall_in_arguments(func_t *func, unsigned int *type_offset) -{ - unsigned int local_type_offset = *type_offset; - unsigned int alignment; - unsigned int size; - unsigned int last_size = 0; - var_t *var; - int in_attr, out_attr; - int string_attr; - int ptr_attr, ref_attr, unique_attr; - void *sizeis_attr; - - if (!func->args) - return; - - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - for (; var; var = PREV_LINK(var)) - { - out_attr = is_attr(var->attrs, ATTR_OUT); - in_attr = is_attr(var->attrs, ATTR_IN); - - /* set 'in' attribute if neither 'in' nor 'out' is set */ - if (!out_attr && !in_attr) - in_attr = 1; - - string_attr = is_attr(var->attrs, ATTR_STRING); - sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); - - if (in_attr) - { - if (var->ptr_level == 1) - { - ptr_attr = is_attr(var->attrs, ATTR_PTR); - ref_attr = is_attr(var->attrs, ATTR_REF); - unique_attr = is_attr(var->attrs, ATTR_UNIQUE); - if (ptr_attr + ref_attr + unique_attr == 0) - ref_attr = 1; - - if (ref_attr) - { - if (string_attr) - { - if (var->type->type == RPC_FC_CHAR || var->type->type == RPC_FC_WCHAR) - { - print_server("NdrConformantStringUnmarshall(\n"); - indent++; - print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_server("(unsigned char __RPC_FAR * __RPC_FAR *)&%s,\n", var->name); - print_server("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u],\n", - local_type_offset + 2); - print_server("(unsigned char)0);\n"); - indent--; - fprintf(server, "\n"); - print_server("_StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~0x3);\n"); - fprintf(server, "\n"); - } - } - else if (sizeis_attr) - { - print_server("NdrConformantArrayUnmarshall(\n"); - indent++; - print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_server("(unsigned char __RPC_FAR * __RPC_FAR *)&%s,\n", var->name); - print_server("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u],\n", - local_type_offset + 4); - print_server("(unsigned char)0);\n"); - indent--; - fprintf(server, "\n"); - print_server("_StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~0x3);\n"); - fprintf(server, "\n"); - } - else - { - alignment = 0; - switch (var->type->type) - { - case RPC_FC_BYTE: - case RPC_FC_CHAR: - case RPC_FC_SMALL: - size = 1; - alignment = 0; - break; - - case RPC_FC_WCHAR: - case RPC_FC_USHORT: - case RPC_FC_SHORT: - size = 2; - if (last_size != 0 && last_size < 2) - alignment = (2 - last_size); - break; - - case RPC_FC_ULONG: - case RPC_FC_LONG: - case RPC_FC_FLOAT: - size = 4; - if (last_size != 0 && last_size < 4) - alignment = (4 - last_size); - break; - - case RPC_FC_HYPER: - case RPC_FC_DOUBLE: - size = 8; - if (last_size != 0 && last_size < 4) - alignment = (4 - last_size); - break; - - case RPC_FC_IGNORE: - size = 0; - break; - - default: - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, var->type->type); - return; - } - - if (size != 0) - { - if (alignment != 0) - print_server("_StubMsg.Buffer += %u;\n", alignment); - - print_server(""); - write_name(server, var); - fprintf(server, " = ("); - write_type(server, var->type, NULL, var->tname); - fprintf(server, " __RPC_FAR*)_StubMsg.Buffer;\n"); - print_server("_StubMsg.Buffer += sizeof("); - write_type(server, var->type, NULL, var->tname); - fprintf(server, ");\n"); - fprintf(server, "\n"); - - last_size = size; - } - } - } - else if (unique_attr) - { - print_server("NdrPointerUnmarshall(\n"); - indent++; - print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_server("(unsigned char __RPC_FAR * __RPC_FAR *)&%s,\n", var->name); - print_server("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u],\n", - local_type_offset); - print_server("(unsigned char)0);\n"); - indent--; - fprintf(server, "\n"); - } - - } - else - { - if (is_base_type(var->type)) - { - alignment = 0; - switch (var->type->type) - { - case RPC_FC_BYTE: - case RPC_FC_CHAR: - case RPC_FC_SMALL: - size = 1; - alignment = 0; - break; - - case RPC_FC_WCHAR: - case RPC_FC_USHORT: - case RPC_FC_SHORT: - size = 2; - if (last_size != 0 && last_size < 2) - alignment = (2 - last_size); - break; - - case RPC_FC_ULONG: - case RPC_FC_LONG: - case RPC_FC_FLOAT: - size = 4; - if (last_size != 0 && last_size < 4) - alignment = (4 - last_size); - break; - - case RPC_FC_HYPER: - case RPC_FC_DOUBLE: - size = 8; - if (last_size != 0 && last_size < 4) - alignment = (4 - last_size); - break; - - case RPC_FC_IGNORE: - size = 0; - break; - - default: - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, var->type->type); - return; - } - - if (size != 0) - { - if (alignment != 0) - print_server("_StubMsg.Buffer += %u;\n", alignment); - - print_server(""); - write_name(server, var); - fprintf(server, " = *(("); - write_type(server, var->type, NULL, var->tname); - fprintf(server, " __RPC_FAR*)_StubMsg.Buffer);\n"); - print_server("_StubMsg.Buffer += sizeof("); - write_type(server, var->type, NULL, var->tname); - fprintf(server, ");\n"); - fprintf(server, "\n"); - - last_size = size; - } - } - else if (var->type->type == RPC_FC_RP) - { - if (var->type->ref->ref->type == RPC_FC_STRUCT) - { - print_server("NdrSimpleStructUnmarshall(\n"); - indent++; - print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_server("(unsigned char __RPC_FAR * __RPC_FAR *)&%s,\n", var->name); - print_server("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u],\n", - local_type_offset + 4); - print_server("(unsigned char)0);\n"); - indent--; - fprintf(server, "\n"); - } - } - } - } - - /* calculate the next type offset */ - local_type_offset += get_var_type_offset(var); - } -} - - -static void marshall_out_arguments(func_t *func, unsigned int *type_offset) -{ - unsigned int alignment = 0; - unsigned int size = 0; - unsigned int last_size = 0; - var_t *var; - var_t *def; - int out_attr; - int string_attr; - void *sizeis_attr; - unsigned int local_type_offset = *type_offset; - - def = func->def; - - /* marshall the out arguments */ - if (func->args) - { - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - for (; var; var = PREV_LINK(var)) - { - out_attr = is_attr(var->attrs, ATTR_OUT); - if (out_attr) - { - sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); - string_attr = is_attr(var->attrs, ATTR_STRING); - - if (sizeis_attr != NULL) - { - if (string_attr) - { - fprintf(server, "\n"); - print_server("_StubMsg.MaxCount = %s;\n", ((var_t *)sizeis_attr)->name); - fprintf(server, "\n"); - print_server("NdrConformantStringMarshall(\n"); - indent++; - print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_server("(unsigned char __RPC_FAR *)%s,\n", var->name); - print_server("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", - local_type_offset + 4); - indent--; - fprintf(server, "\n"); - print_server("_StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~0x3);\n"); - fprintf(server, "\n"); - } - else - { - fprintf(server, "\n"); - if (((var_t *)sizeis_attr)->ptr_level == 0) - print_server("_StubMsg.MaxCount = %s;\n", ((var_t *)sizeis_attr)->name); - else - print_server("_StubMsg.MaxCount = %s ? *%s : 0;\n", - ((var_t *)sizeis_attr)->name, ((var_t *)sizeis_attr)->name); - fprintf(server, "\n"); - print_server("NdrConformantArrayMarshall(\n"); - indent++; - print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_server("(unsigned char __RPC_FAR *)%s,\n", var->name); - print_server("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", - local_type_offset + 4); - indent--; - fprintf(server, "\n"); - print_server("_StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~0x3);\n"); - fprintf(server, "\n"); - } - } - else if (is_base_type(var->type)) - { - alignment = 0; - switch (var->type->type) - { - case RPC_FC_BYTE: - case RPC_FC_CHAR: - case RPC_FC_SMALL: - size = 1; - alignment = 0; - break; - - case RPC_FC_WCHAR: - case RPC_FC_USHORT: - case RPC_FC_SHORT: - size = 2; - if (last_size != 0 && last_size < 2) - alignment = (2 - last_size); - break; - - case RPC_FC_ULONG: - case RPC_FC_LONG: - case RPC_FC_FLOAT: - size = 4; - if (last_size != 0 && last_size < 4) - alignment = (4 - last_size); - break; - - case RPC_FC_HYPER: - case RPC_FC_DOUBLE: - size = 8; - if (last_size != 0 && last_size < 4) - alignment = (4 - last_size); - break; - - case RPC_FC_IGNORE: - size = 0; - break; - - default: - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, var->type->type); - return; - } - - if (size != 0) - { - if (alignment != 0) - print_server("_StubMsg.Buffer += %u;\n", alignment); - - if (var->ptr_level == 1) - { - fprintf(server, "\n"); - print_server("*(("); - write_type(server, var->type, NULL, var->tname); - fprintf(server, " __RPC_FAR *)_StubMsg.Buffer) = *"); - write_name(server, var); - fprintf(server, ";\n"); - - print_server("_StubMsg.Buffer += sizeof("); - write_type(server, var->type, NULL, var->tname); - fprintf(server, ");"); - } - else - { - error("Pointer level %d is not supported!\n", var->ptr_level); - return; - } - - last_size = size; - } - } - else if (var->type->type == RPC_FC_RP) - { - fprintf(server, "\n"); - print_server("NdrSimpleStructMarshall(\n"); - indent++; - print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_server("(unsigned char __RPC_FAR *)%s,\n", var->name); - print_server("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", - local_type_offset + 4); - indent--; - } - } - - /* calculate the next type offset */ - local_type_offset += get_var_type_offset(var); - } - } - - /* marshall the return value */ - if (!is_void(def->type, NULL)) - { - alignment = 0; - switch (def->type->type) - { - case RPC_FC_BYTE: - case RPC_FC_CHAR: - case RPC_FC_SMALL: - case RPC_FC_WCHAR: - case RPC_FC_USHORT: - case RPC_FC_SHORT: - case RPC_FC_ULONG: - case RPC_FC_LONG: - case RPC_FC_FLOAT: - size = 4; - if (last_size != 0 && last_size < 4) - alignment = (4 - last_size); - break; - - case RPC_FC_HYPER: - case RPC_FC_DOUBLE: - size = 8; - if (last_size != 0 && last_size < 4) - alignment = (4 - last_size); - break; - - default: - error("%s:%d Unknown/unsupported type 0x%x\n", - __FUNCTION__,__LINE__, var->type->type); - return; - } - - fprintf(server, "\n"); - if (alignment != 0) - print_server("_StubMsg.Buffer += %u;\n", alignment); - print_server("*(("); - write_type(server, def->type, def, def->tname); - fprintf(server, " __RPC_FAR *)_StubMsg.Buffer) = _RetVal;\n"); - print_server("_StubMsg.Buffer += sizeof("); - write_type(server, def->type, def, def->tname); - fprintf(server, ");\n"); - } -} - - -static int use_return_buffer(func_t *func) -{ - var_t *var; - - if (!is_void(func->def->type, NULL)) - return 1; - - if (!func->args) - return 0; - - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - if (is_attr(var->attrs, ATTR_OUT)) - return 1; - - var = PREV_LINK(var); - } - - return 0; -} - - -static void cleanup_return_buffer(func_t *func, unsigned int *type_offset) -{ - var_t *var; - int string_attr; - void *sizeis_attr; - unsigned int local_type_offset = *type_offset; - - if (func->args) - { - int first_arg = 1; - - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); - string_attr = is_attr(var->attrs, ATTR_STRING); - - if (sizeis_attr != NULL) - { - if (first_arg == 0) - fprintf(server, "\n"); - - indent++; - if (string_attr) - { - print_server("_StubMsg.MaxCount = %s;\n", ((var_t *)sizeis_attr)->name); - fprintf(server, "\n"); - print_server("NdrPointerFree(\n"); - indent++; - print_server("&_StubMsg,\n"); - print_server("(unsigned char __RPC_FAR *)%s,\n", var->name); - print_server("&__MIDL_TypeFormatString.Format[%u]);\n", - local_type_offset); - indent--; - } - else - { - print_server("if ("); - write_name(server, var); - fprintf(server, ")\n"); - indent++; - print_server("_StubMsg.pfnFree("); - write_name(server, var); - fprintf(server, ");\n"); - indent--; - } - indent--; - - first_arg = 0; - } - - /* calculate the next type offset */ - local_type_offset += get_var_type_offset(var); - - var = PREV_LINK(var); - } - } -} - - -static void write_function_stubs(type_t *iface) -{ - int explicit_handle = is_attr(iface->attrs, ATTR_EXPLICIT_HANDLE); - func_t *func = iface->funcs; - var_t *var; - var_t* explicit_handle_var; - unsigned int proc_offset = 0; - unsigned int type_offset = 2; - unsigned int i, sep; - int in_attr; - int out_attr; - void *sizeis_attr; - - while (NEXT_LINK(func)) func = NEXT_LINK(func); - while (func) - { - var_t *def = func->def; - - /* check for a defined binding handle */ - explicit_handle_var = get_explicit_handle_var(func); - if (explicit_handle) - { - if (!explicit_handle_var) - { - error("%s() does not define an explicit binding handle!\n", def->name); - return; - } - } - else - { - if (explicit_handle_var) - { - error("%s() must not define a binding handle!\n", def->name); - return; - } - } - - fprintf(server, "void __RPC_STUB\n"); - fprintf(server, "%s_", iface->name); - write_name(server, def); - fprintf(server, "(\n"); - indent++; - print_server("PRPC_MESSAGE _pRpcMessage)\n"); - indent--; - - /* write the functions body */ - fprintf(server, "{\n"); - indent++; - - /* declare return value '_RetVal' */ - if (!is_void(def->type, NULL)) - { - print_server(""); - write_type(server, def->type, def, def->tname); - fprintf(server, " _RetVal;\n"); - } - - /* declare arguments */ - if (func->args) - { - i = 0; - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - in_attr = is_attr(var->attrs, ATTR_IN); - out_attr = is_attr(var->attrs, ATTR_OUT); - sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); - - if (!out_attr && !in_attr) - in_attr = 1; - if (!in_attr && !sizeis_attr) - { - if (var->type->type == RPC_FC_RP) - { - print_server("struct "); - write_type(server, NULL, NULL, var->type->ref->ref->name); - fprintf(server, " _%sW;\n", var->name); - } - else - { - print_server(""); - write_type(server, var->type, NULL, var->tname); - fprintf(server, " _W%u;\n", i); - i++; - } - } - - print_server(""); - write_type(server, var->type, var, var->tname); - fprintf(server, " "); - write_name(server, var); - fprintf(server, ";\n"); - - var = PREV_LINK(var); - } - } - - print_server("MIDL_STUB_MESSAGE _StubMsg;\n"); - print_server("RPC_STATUS _Status;\n"); - fprintf(server, "\n"); - - - print_server("((void)(_Status));\n"); - print_server("NdrServerInitializeNew(\n"); - indent++; - print_server("_pRpcMessage,\n"); - print_server("&_StubMsg,\n"); - print_server("&%s_StubDesc);\n", iface->name); - indent--; - fprintf(server, "\n"); - - if (explicit_handle) - { - print_server("%s = _pRpcMessage->Handle;\n", explicit_handle_var->name); - fprintf(server, "\n"); - } - - init_pointers(func); - - print_server("RpcTryFinally\n"); - print_server("{\n"); - indent++; - print_server("RpcTryExcept\n"); - print_server("{\n"); - indent++; - - if (func->args) - { - print_server("if ((_pRpcMessage->DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)\n"); - indent++; - print_server("NdrConvert(\n"); - indent++; - print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); - print_server("(PFORMAT_STRING)&__MIDL_ProcFormatString.Format[%u]);\n", proc_offset); - indent -= 2; - fprintf(server, "\n"); - - unmarshall_in_arguments(func, &type_offset); - } - - print_server("if (_StubMsg.Buffer > _StubMsg.BufferEnd)\n"); - print_server("{\n"); - indent++; - print_server("RpcRaiseException(RPC_X_BAD_STUB_DATA);\n"); - indent--; - print_server("}\n"); - indent--; - print_server("}\n"); - print_server("RpcExcept(RPC_BAD_STUB_DATA_EXCEPTION_FILTER)\n"); - print_server("{\n"); - indent++; - print_server("RpcRaiseException(RPC_X_BAD_STUB_DATA);\n"); - indent--; - print_server("}\n"); - print_server("RpcEndExcept\n"); - fprintf(server, "\n"); - - /* assign out arguments */ - if (func->args) - { - sep = 0; - i = 0; - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - in_attr = is_attr(var->attrs, ATTR_IN); - out_attr = is_attr(var->attrs, ATTR_OUT); - if (!out_attr && !in_attr) - in_attr = 1; - - sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); - - if (!in_attr) - { - if (sizeis_attr != NULL) - { - print_server(""); - write_name(server, var); - if (((var_t *)sizeis_attr)->ptr_level == 0) - fprintf(server, " = NdrAllocate(&_StubMsg, %s * %d);\n", - ((var_t *)sizeis_attr)->name, get_type_size(var->type, 1)); - else if (((var_t *)sizeis_attr)->ptr_level == 1) - fprintf(server, " = NdrAllocate(&_StubMsg, *%s * %d);\n", - ((var_t *)sizeis_attr)->name, get_type_size(var->type, 1)); - sep = 1; - } - else - { - if (var->type->type == RPC_FC_RP) - { - print_server(""); - write_name(server, var); - fprintf(server, " = &_%sW;\n", var->name); - sep = 1; - } - else - { - print_server(""); - write_name(server, var); - fprintf(server, " = &_W%u;\n", i); - i++; - sep = 1; - } - } - } - - var = PREV_LINK(var); - } - - if (sep) - fprintf(server, "\n"); - } - - /* Call the real server function */ - if (!is_void(def->type, NULL)) - print_server("_RetVal = "); - else - print_server(""); - write_name(server, def); - - if (func->args) - { - int first_arg = 1; - - fprintf(server, "(\n"); - indent++; - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - if (first_arg) - first_arg = 0; - else - fprintf(server, ",\n"); - print_server(""); - write_name(server, var); - var = PREV_LINK(var); - } - fprintf(server, ");\n"); - indent--; - } - else - { - fprintf(server, "();\n"); - } - - /* allocate and fill the return message buffer */ - if (use_return_buffer(func)) - { - print_message_buffer_size(func, &type_offset); - print_server("_pRpcMessage->BufferLength = _StubMsg.BufferLength;\n"); - fprintf(server, "\n"); - print_server("_Status = I_RpcGetBuffer(_pRpcMessage);\n"); - print_server("if (_Status)\n"); - indent++; - print_server("RpcRaiseException(_Status);\n"); - indent--; - fprintf(server, "\n"); - print_server("_StubMsg.Buffer = (unsigned char __RPC_FAR *)_pRpcMessage->Buffer;\n"); - - /* marshall the out arguments */ - marshall_out_arguments(func, &type_offset); - } - - indent--; - print_server("}\n"); - print_server("RpcFinally\n"); - print_server("{\n"); - - cleanup_return_buffer(func, &type_offset); - - print_server("}\n"); - print_server("RpcEndFinally\n"); - - /* calculate buffer length */ - fprintf(server, "\n"); - print_server("_pRpcMessage->BufferLength =\n"); - indent++; - print_server("(unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer);\n"); - indent--; - indent--; - fprintf(server, "}\n"); - fprintf(server, "\n"); - - /* update type_offset */ - if (func->args) - { - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - type_offset += get_var_type_offset(var); - - var = PREV_LINK(var); - } - } - - /* update proc_offset */ - if (func->args) - { - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - switch (var->ptr_level) - { - case 0: - if (is_base_type(var->type)) - proc_offset += 2; - break; - - case 1: - if (is_base_type(var->type)) - proc_offset += 4; - break; - } - - var = PREV_LINK(var); - } - } - proc_offset += 2; /* FIXME */ - - func = PREV_LINK(func); - } -} - - -static void write_dispatchtable(type_t *iface) -{ - unsigned long ver = get_attrv(iface->attrs, ATTR_VERSION); - unsigned long method_count = 0; - func_t *cur = iface->funcs; - - print_server("static RPC_DISPATCH_FUNCTION %s_table[] =\n", iface->name); - print_server("{\n"); - indent++; - while (NEXT_LINK(cur)) cur = NEXT_LINK(cur); - while (cur) - { - var_t *def = cur->def; - - print_server("%s_", iface->name); - write_name(server, def); - fprintf(server, ",\n"); - - method_count++; - cur = PREV_LINK(cur); - } - print_server("0\n"); - indent--; - print_server("};\n"); - print_server("RPC_DISPATCH_TABLE %s_v%d_%d_DispatchTable =\n", iface->name, LOWORD(ver), HIWORD(ver)); - print_server("{\n"); - indent++; - print_server("%u,\n", method_count); - print_server("%s_table\n", iface->name); - indent--; - print_server("};\n"); - fprintf(server, "\n"); -} - - -static void write_stubdescdecl(type_t *iface) -{ - print_server("extern const MIDL_STUB_DESC %s_StubDesc;\n", iface->name); - fprintf(server, "\n"); -} - - -static void write_stubdescriptor(type_t *iface) -{ - print_server("const MIDL_STUB_DESC %s_StubDesc =\n", iface->name); - print_server("{\n"); - indent++; - print_server("(void __RPC_FAR *)& %s___RpcServerInterface,\n", iface->name); - print_server("MIDL_user_allocate,\n"); - print_server("MIDL_user_free,\n"); - print_server("{NULL},\n"); - print_server("0,\n"); - print_server("0,\n"); - print_server("0,\n"); - print_server("0,\n"); - print_server("__MIDL_TypeFormatString.Format,\n"); - print_server("1, /* -error bounds_check flag */\n"); - print_server("0x10001, /* Ndr library version */\n"); - print_server("0,\n"); - print_server("0x50100a4, /* MIDL Version 5.1.164 */\n"); - print_server("0,\n"); - print_server("0,\n"); - print_server("0, /* notify & notify_flag routine table */\n"); - print_server("1, /* Flags */\n"); - print_server("0, /* Reserved3 */\n"); - print_server("0, /* Reserved4 */\n"); - print_server("0 /* Reserved5 */\n"); - indent--; - print_server("};\n"); - fprintf(server, "\n"); -} - - -static void write_serverinterfacedecl(type_t *iface) -{ - unsigned long ver = get_attrv(iface->attrs, ATTR_VERSION); - UUID *uuid = get_attrp(iface->attrs, ATTR_UUID); - - print_server("extern RPC_DISPATCH_TABLE %s_v%d_%d_DispatchTable;\n", iface->name, LOWORD(ver), HIWORD(ver)); - fprintf(server, "\n"); - print_server("static const RPC_SERVER_INTERFACE %s___RpcServerInterface =\n", iface->name ); - print_server("{\n"); - indent++; - print_server("sizeof(RPC_SERVER_INTERFACE),\n"); - print_server("{{0x%08lx,0x%04x,0x%04x,{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x}},{%d,%d}},\n", - uuid->Data1, uuid->Data2, uuid->Data3, uuid->Data4[0], uuid->Data4[1], - uuid->Data4[2], uuid->Data4[3], uuid->Data4[4], uuid->Data4[5], uuid->Data4[6], - uuid->Data4[7], LOWORD(ver), HIWORD(ver)); - print_server("{{0x8a885d04,0x1ceb,0x11c9,{0x9f,0xe8,0x08,0x00,0x2b,0x10,0x48,0x60}},{2,0}},\n"); /* FIXME */ - print_server("&%s_v%d_%d_DispatchTable,\n", iface->name, LOWORD(ver), HIWORD(ver)); - print_server("0,\n"); - print_server("0,\n"); - print_server("0,\n"); - print_server("0,\n"); - print_server("0,\n"); - indent--; - print_server("};\n"); - if (old_names) - print_server("RPC_IF_HANDLE %s_ServerIfHandle = (RPC_IF_HANDLE)& %s___RpcServerInterface;\n", - iface->name, iface->name); - else - print_server("RPC_IF_HANDLE %s_v%d_%d_s_ifspec = (RPC_IF_HANDLE)& %s___RpcServerInterface;\n", - iface->name, LOWORD(ver), HIWORD(ver), iface->name); - fprintf(server, "\n"); -} - - -static void write_formatdesc( const char *str ) -{ - print_server("typedef struct _MIDL_%s_FORMAT_STRING\n", str ); - print_server("{\n"); - indent++; - print_server("short Pad;\n"); - print_server("unsigned char Format[%s_FORMAT_STRING_SIZE];\n", str); - indent--; - print_server("} MIDL_%s_FORMAT_STRING;\n", str); - print_server("\n"); -} - - -static int get_type_format_string_size(type_t *iface) -{ - int size = 3; - func_t *func; - var_t *var; - - /* determine the type format string size */ - func = iface->funcs; - while (NEXT_LINK(func)) func = NEXT_LINK(func); - while (func) - { - /* argument list size */ - if (func->args) - { - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - size += get_var_type_offset(var); - var = PREV_LINK(var); - } - } - - func = PREV_LINK(func); - } - - return size; -} - - -static int get_proc_format_string_size(type_t *iface) -{ - int size = 1; - func_t *func; - var_t *var; - - /* determine the proc format string size */ - func = iface->funcs; - while (NEXT_LINK(func)) func = NEXT_LINK(func); - while (func) - { - /* argument list size */ - if (func->args) - { - var = func->args; - while (NEXT_LINK(var)) var = NEXT_LINK(var); - while (var) - { - switch (var->ptr_level) - { - case 0: - if (is_base_type(var->type)) - size += 2; - else if (var->type->type == RPC_FC_RP) - size += 4; - break; - - case 1: - if (is_base_type(var->type)) - size += 4; - break; - } - - var = PREV_LINK(var); - } - } - - /* return value size */ - size += 2; - func = PREV_LINK(func); - } - - return size; -} - - -static void write_formatstringsdecl(type_t *iface) -{ - print_server("#define TYPE_FORMAT_STRING_SIZE %d\n", - get_type_format_string_size(iface)); - - print_server("#define PROC_FORMAT_STRING_SIZE %d\n", - get_proc_format_string_size(iface)); - - fprintf(server, "\n"); - write_formatdesc("TYPE"); - write_formatdesc("PROC"); - fprintf(server, "\n"); - print_server("extern const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString;\n"); - print_server("extern const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString;\n"); - print_server("\n"); -} - - -static void init_server(void) -{ - if (server) - return; - if (!(server = fopen(server_name, "w"))) - error("Could not open %s for output\n", server_name); - - print_server("/*** Autogenerated by WIDL %s from %s - Do not edit ***/\n", WIDL_FULLVERSION, input_name); - print_server("#include <string.h>\n"); - fprintf(server, "\n"); - print_server("#include \"%s\"\n", header_name); - fprintf(server, "\n"); -} - - -void write_server(ifref_t *ifaces) -{ - ifref_t *iface = ifaces; - - if (!do_server) - return; - if (!iface) - return; - END_OF_LIST(iface); - - init_server(); - if (!server) - return; - - while (iface) - { - fprintf(server, "/*****************************************************************************\n"); - fprintf(server, " * %s interface\n", iface->iface->name); - fprintf(server, " */\n"); - fprintf(server, "\n"); - - write_formatstringsdecl(iface->iface); - write_serverinterfacedecl(iface->iface); - write_stubdescdecl(iface->iface); - - write_function_stubs(iface->iface); - - write_stubdescriptor(iface->iface); - write_dispatchtable(iface->iface); - - print_server("#if !defined(__RPC_WIN32__)\n"); - print_server("#error Invalid build platform for this stub.\n"); - print_server("#endif\n"); - fprintf(server, "\n"); - - write_procformatstring(iface->iface); - write_typeformatstring(iface->iface); - - fprintf(server, "\n"); - - iface = PREV_LINK(iface); - } - - fclose(server); -} +/* + * IDL Compiler + * + * Copyright 2005 Eric Kohl + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif +#include <string.h> +#include <assert.h> +#include <ctype.h> +#include <signal.h> + +#include "widl.h" +#include "utils.h" +#include "parser.h" +#include "header.h" + +#define END_OF_LIST(list) \ + do { \ + if (list) { \ + while (NEXT_LINK(list)) \ + list = NEXT_LINK(list); \ + } \ + } while(0) + +static FILE* server; +static int indent = 0; + + +static int print_server(const char *format, ...) +{ + va_list va; + int i, r; + + va_start(va, format); + for (i = 0; i < indent; i++) + fprintf(server, " "); + r = vfprintf(server, format, va); + va_end(va); + return r; +} + + +static unsigned int +get_var_stack_offset_32(func_t *func, char *name) +{ + unsigned int offset = 0; + var_t *var; + + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + if (!strcmp(var->name, name)) + return offset; + + if (var->type->type == RPC_FC_DOUBLE || + var->type->type == RPC_FC_HYPER) + offset += 8; + else + offset += 4; + + var = PREV_LINK(var); + } + + return 0; +} + + +static unsigned int +get_var_stack_offset_64(func_t *func, char *name) +{ + unsigned int offset = 0; + var_t *var; + + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + if (!strcmp(var->name, name)) + return offset; + + offset += 8; + + var = PREV_LINK(var); + } + + return 0; +} + + +static unsigned int +get_var_type_offset(var_t *var) +{ + unsigned int toffset = 0; + void *sizeis_attr; + int string_attr; + + if (var->ptr_level == 0) + { + if ((var->type->type == RPC_FC_RP) && + (var->type->ref->ref->type == RPC_FC_STRUCT)) + { + var_t *field = var->type->ref->ref->fields; + int tsize = 9; + + while (NEXT_LINK(field)) field = NEXT_LINK(field); + while (field) + { + tsize++; + field = PREV_LINK(field); + } + if (tsize % 2) + tsize++; + + toffset += tsize; + } + } + else if (var->ptr_level == 1) + { + sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); + string_attr = is_attr(var->attrs, ATTR_STRING); + + if (sizeis_attr) + { + if (string_attr) + { + if (var->type->type == RPC_FC_BYTE || + var->type->type == RPC_FC_CHAR || + var->type->type == RPC_FC_WCHAR) + toffset += 10; + } + else + { + if (is_base_type(var->type)) + toffset += 14; + } + } + else + { + if (is_base_type(var->type)) + toffset += 4; + } + } + + return toffset; +} + + +static type_t *get_type_by_name(func_t *func, char *name) +{ + var_t *var; + + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + if (!strcmp(var->name, name)) + return var->type; + + var = PREV_LINK(var); + } + + return NULL; +} + + +static unsigned char +get_base_type(unsigned char type) +{ + + switch (type) + { + case RPC_FC_USHORT: + type = RPC_FC_SHORT; + break; + + case RPC_FC_ULONG: + type = RPC_FC_LONG; + break; + } + + return type; +} + + +static int get_type_size(type_t *type, int alignment) +{ + int size; + var_t *field; + + switch(type->type) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + size = 1; + size = ((size + alignment - 1) & ~(alignment -1)); + break; + + case RPC_FC_WCHAR: + case RPC_FC_USHORT: + case RPC_FC_SHORT: + size = 2; + size = ((size + alignment - 1) & ~(alignment -1)); + break; + + case RPC_FC_ULONG: + case RPC_FC_LONG: + case RPC_FC_FLOAT: + size = 4; + size = ((size + alignment - 1) & ~(alignment -1)); + break; + + case RPC_FC_HYPER: + case RPC_FC_DOUBLE: + size = 8; + size = ((size + alignment - 1) & ~(alignment -1)); + break; + + case RPC_FC_IGNORE: + size = 0; + break; + + case RPC_FC_STRUCT: + field = type->fields; + size = 0; + while (NEXT_LINK(field)) field = NEXT_LINK(field); + while (field) + { + size += get_type_size(field->type, alignment); + field = PREV_LINK(field); + } + break; + + default: + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, type->type); + return 0; + } + + return size; +} + + +static int get_type_alignment(type_t *type) +{ + int size; + + switch(type->type) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + size = 1; + break; + + case RPC_FC_WCHAR: + case RPC_FC_USHORT: + case RPC_FC_SHORT: + size = 2; + break; + + case RPC_FC_ULONG: + case RPC_FC_LONG: + case RPC_FC_FLOAT: + size = 4; + break; + + case RPC_FC_HYPER: + case RPC_FC_DOUBLE: + size = 8; + break; + + default: + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, type->type); + return 0; + } + + return size; +} + + +static void write_procformatstring(type_t *iface) +{ + func_t *func = iface->funcs; + var_t *var; + unsigned int type_offset = 2; + int in_attr, out_attr; + + print_server("const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString =\n"); + print_server("{\n"); + indent++; + print_server("0,\n"); + print_server("{\n"); + indent++; + + while (NEXT_LINK(func)) func = NEXT_LINK(func); + while (func) + { + /* emit argument data */ + if (func->args) + { + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + out_attr = is_attr(var->attrs, ATTR_OUT); + in_attr = is_attr(var->attrs, ATTR_IN); + + /* set 'in' attribute if neither 'in' nor 'out' is set */ + if (!out_attr && !in_attr) + in_attr = 1; + + if (var->ptr_level == 0) + { + if (is_base_type(var->type)) + { + print_server("0x4e, /* FC_IN_PARAM_BASETYPE */\n"); + print_server("0x%02x, /* FC_<type> */\n", get_base_type(var->type->type)); + } + else if (var->type->type == RPC_FC_RP) + { + if (in_attr & !out_attr) + print_server("0x4d, /* FC_IN_PARAM */\n"); + else if (!in_attr & out_attr) + print_server("0x51, /* FC_OUT_PARAM */\n"); + else if (in_attr & out_attr) + print_server("0x50, /* FC_IN_OUT_PARAM */\n"); + fprintf(server, "#ifndef _ALPHA_\n"); + print_server("0x01,\n"); + fprintf(server, "#else\n"); + print_server("0x02,\n"); + fprintf(server, "#endif\n"); + print_server("NdrFcShort(0x%x),\n", type_offset); + } + else + { + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, var->type->type); + return; + } + } + else if (var->ptr_level == 1) + { +// if (is_base_type(var->type)) +// { + if (in_attr & !out_attr) + print_server("0x4d, /* FC_IN_PARAM */\n"); + else if (!in_attr & out_attr) + print_server("0x51, /* FC_OUT_PARAM */\n"); + else if (in_attr & out_attr) + print_server("0x50, /* FC_IN_OUT_PARAM */\n"); + fprintf(server, "#ifndef _ALPHA_\n"); + print_server("0x01,\n"); + fprintf(server, "#else\n"); + print_server("0x02,\n"); + fprintf(server, "#endif\n"); + print_server("NdrFcShort(0x%x),\n", type_offset); +// } +// else +// { +// error("%s:%d Unknown/unsupported type 0x%x\n", +// __FUNCTION__,__LINE__, var->type->type); +// return; +// } + } + + type_offset += get_var_type_offset(var); + + var = PREV_LINK(var); + } + } + + /* emit return value data */ + var = func->def; + if (is_void(var->type, NULL)) + { + print_server("0x5b, /* FC_END */\n"); + print_server("0x5c, /* FC_PAD */\n"); + } + else if (is_base_type(var->type)) + { + print_server("0x53, /* FC_RETURN_PARAM_BASETYPE */\n"); + print_server("0x%02x, /* FC_<type> */\n", get_base_type(var->type->type)); + } + else + { + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, var->type->type); + return; + } + + func = PREV_LINK(func); + } + + print_server("0x0\n"); + indent--; + print_server("}\n"); + indent--; + print_server("};\n"); + print_server("\n"); +} + + +static void write_typeformatstring(type_t *iface) +{ + func_t *func = iface->funcs; + var_t *var; + type_t *type; + int in_attr, out_attr; + int string_attr; + int ptr_attr, ref_attr, unique_attr; + void *sizeis_attr; + + print_server("const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString =\n"); + print_server("{\n"); + indent++; + print_server("0,\n"); + print_server("{\n"); + indent++; + print_server("NdrFcShort(0x0),\n"); + + while (NEXT_LINK(func)) func = NEXT_LINK(func); + while (func) + { + if (func->args) + { + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + in_attr = is_attr(var->attrs, ATTR_IN); + out_attr = is_attr(var->attrs, ATTR_OUT); + string_attr = is_attr(var->attrs, ATTR_STRING); + + if (var->ptr_level > 1) + { + error("Function '%s' argument '%s': Pointer level %d not supported!\n", + func->def->name, var->name, var->ptr_level); + return; + } + + if (var->ptr_level == 0) + { + if (!is_base_type(var->type)) + { + if (var->type->type == RPC_FC_RP) + { + var_t *field; + int tsize = 9; + unsigned char flags = 0; + + if (!in_attr & out_attr) + flags |= RPC_FC_P_ONSTACK; + + print_server("0x11, 0x%02X, /* FC_RP, [flags] */\n", flags); + print_server("NdrFcShort(0x%02X),\n", 0x02); + print_server("0x%02X,\n", var->type->ref->ref->type); + print_server("0x%02X,\n", 3); /* alignment -1 */ + print_server("NdrFcShort(0x%02X),\n", get_type_size(var->type->ref->ref, 4)); + + field = var->type->ref->ref->fields; + while (NEXT_LINK(field)) field = NEXT_LINK(field); + while (field) + { + print_server("0x%02X,\n", get_base_type(field->type->type)); + tsize++; + field = PREV_LINK(field); + } + if (tsize % 2) + { + print_server("0x5c, /* FC_PAD */\n"); + tsize++; + } + print_server("0x5b, /* FC_END */\n"); + } + else + { + + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, var->type->type); + return; + } + } + } + else if (var->ptr_level == 1) + { + ptr_attr = is_attr(var->attrs, ATTR_PTR); + ref_attr = is_attr(var->attrs, ATTR_REF); + unique_attr = is_attr(var->attrs, ATTR_UNIQUE); + sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); + + if (ptr_attr + ref_attr + unique_attr == 0) + ref_attr = 1; + + if (sizeis_attr) + { + unsigned char type_type = 0; + + type = get_type_by_name(func, ((var_t *)sizeis_attr)->name); + if (type != NULL) + type_type = type->type; + + print_server("0x11, 0x00, /* FC_RP */\n"); + print_server("NdrFcShort(0x02),\n"); + + if (string_attr) + { + if (var->type->type == RPC_FC_WCHAR) + print_server("0x25, /* FC_C_WSTRING */\n"); + else + print_server("0x22, /* FC_C_CSTRING */\n"); + print_server("0x44, /* FC_STRING_SIZED */\n"); + print_server("0x%02x,\n", 0x20 + type_type); + print_server("0x00,\n"); + + fprintf(server, "#ifndef _ALPHA_\n"); + print_server("NdrFcShort(0x%02X),\n", + get_var_stack_offset_32(func, ((var_t *)sizeis_attr)->name)); + fprintf(server, "#else\n"); + print_server("NdrFcShort(0x%02X),\n", + get_var_stack_offset_64(func, ((var_t *)sizeis_attr)->name)); + fprintf(server, "#endif\n"); + } + else + { + print_server("0x1b, /* FC_CARRAY */\n"); + print_server("0x%02x,\n", get_type_alignment(var->type) - 1); + print_server("NdrFcShort(0x%02x),\n", get_type_size(var->type, 1)); + print_server("0x%02x,\n", 0x20 + type_type); + if (out_attr) + print_server("0x54 /* FC_DEREFERENCE */,\n"); + else + print_server("0x00 /* */,\n"); + + fprintf(server, "#ifndef _ALPHA_\n"); + print_server("NdrFcShort(0x%02X),\n", + get_var_stack_offset_32(func, ((var_t *)sizeis_attr)->name)); + fprintf(server, "#else\n"); + print_server("NdrFcShort(0x%02X),\n", + get_var_stack_offset_64(func, ((var_t *)sizeis_attr)->name)); + fprintf(server, "#endif\n"); + print_server("0x%02x,\n", get_base_type(var->type->type)); + print_server("0x5b, /* FC_END */\n"); + } + } + else if (is_base_type(var->type)) + { + if (out_attr && !in_attr) + { + if (ref_attr) + print_server("0x11, 0x0c, /* FC_RP [allocated_on_stack] [simple_pointer] */\n"); + else if (unique_attr) + print_server("0x12, 0x0c, /* FC_FP [allocated_on_stack] [simple_pointer] */\n"); + else if (ptr_attr) + print_server("0x14, 0x0c, /* FC_FP [allocated_on_stack] [simple_pointer] */\n"); + } + else + { + if (ref_attr) + print_server("0x11, 0x08, /* FC_RP [simple_pointer] */\n"); + else if (unique_attr) + print_server("0x12, 0x08, /* FC_UP [simple_pointer] */\n"); + else if (ptr_attr) + print_server("0x14, 0x08, /* FC_FP [simple_pointer] */\n"); + } + + if (string_attr) + { + if (var->type->type == RPC_FC_CHAR) + print_server("0x%02x, /* FC_C_CSTRING */\n", RPC_FC_C_CSTRING); + else if (var->type->type == RPC_FC_WCHAR) + print_server("0x%02x, /* FC_C_WSTRING */\n", RPC_FC_C_WSTRING); + else + { + error("%s: Invalid type!\n", __FUNCTION__); + return; + } + } + else + print_server("0x%02x, /* FC_<type> */\n", get_base_type(var->type->type)); + print_server("0x5c, /* FC_PAD */\n"); + } + } + + var = PREV_LINK(var); + } + } + + + + func = PREV_LINK(func); + } + + print_server("0x0\n"); + indent--; + print_server("}\n"); + indent--; + print_server("};\n"); + print_server("\n"); +} + + +static void print_message_buffer_size(func_t *func, unsigned int *type_offset) +{ + unsigned int alignment = 0; + int size = 0; + int last_size = -1; + int in_attr; + int out_attr; + int string_attr; + void *sizeis_attr; + int empty_line; + var_t *var; + + int first_padding = 0; + int padding = 0; + int add_plus = 0; + + unsigned int local_type_offset = *type_offset; + + fprintf(server, "\n"); + print_server("_StubMsg.BufferLength ="); + if (func->args) + { + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + for (; var; var = PREV_LINK(var)) + { + out_attr = is_attr(var->attrs, ATTR_OUT); + string_attr = is_attr(var->attrs, ATTR_STRING); + sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); + + if (out_attr) + { + if (var->ptr_level == 1) + { + if (sizeis_attr) + { + if (string_attr && + (var->type->type == RPC_FC_BYTE || + var->type->type == RPC_FC_CHAR || + var->type->type == RPC_FC_WCHAR)) + { + size =12; + } + else + { + size = 4; + } + } + else if (is_base_type(var->type)) + { + alignment = 0; + switch (var->type->type) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + size = 1; + alignment = 0; + break; + + case RPC_FC_WCHAR: + case RPC_FC_USHORT: + case RPC_FC_SHORT: + size = 2; + if (last_size > 0 && last_size < 2) + alignment += (2 - last_size); + break; + + case RPC_FC_ULONG: + case RPC_FC_LONG: + case RPC_FC_FLOAT: + size = 4; + if (last_size > 0 && last_size < 4) + alignment += (4 - last_size); + break; + + case RPC_FC_HYPER: + case RPC_FC_DOUBLE: + size = 8; + if (last_size > 0 && last_size < 4) + alignment += (4 - last_size); + break; + + default: + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, var->type->type); + return; + } + } + } + else if (var->type->type == RPC_FC_RP) + { + size = 12; + } + + if (size != 0) + { + if (add_plus) + fprintf(server, " +"); + fprintf(server, " %dU", size + alignment + first_padding + padding); + + if (first_padding != 0) + first_padding = 0; + + last_size = size; + add_plus = 1; + } + + /* set paddings */ + if (var->ptr_level == 1) + { + if (sizeis_attr) + { + if (string_attr && + (var->type->type == RPC_FC_BYTE || + var->type->type == RPC_FC_CHAR || + var->type->type == RPC_FC_WCHAR)) + { + first_padding = 3; + if (var->type->type == RPC_FC_BYTE || + var->type->type == RPC_FC_CHAR) + first_padding++; + padding = 3; + } + else + { + first_padding = 4; + padding = 3; + } + } + } + + /* calculate the next type offset */ + local_type_offset += get_var_type_offset(var); + } + } + } + + /* return value size */ + if (!is_void(func->def->type, NULL)) + { + switch(func->def->type->type) + { + case RPC_FC_BYTE: + case RPC_FC_SMALL: + case RPC_FC_CHAR: + case RPC_FC_WCHAR: + case RPC_FC_USHORT: + case RPC_FC_SHORT: + case RPC_FC_ULONG: + case RPC_FC_LONG: + case RPC_FC_FLOAT: + size = 4; + if (last_size > 0 && last_size < 4) + alignment += (4 - last_size); + break; + + case RPC_FC_HYPER: + case RPC_FC_DOUBLE: + size = 8; + if (last_size > 0 && last_size < 4) + alignment += (4 - last_size); + break; + + default: + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, func->def->type->type); + return; + } + + if (add_plus) + fprintf(server, " +"); + + fprintf(server, " %dU", size + alignment + first_padding + padding); + } + + if (size == 0) + fprintf(server, "0U"); + + fprintf(server, ";\n"); + + + if (func->args) + { + local_type_offset = *type_offset; + + empty_line = 0; + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + for (; var; var = PREV_LINK(var)) + { + out_attr = is_attr(var->attrs, ATTR_OUT); + in_attr = is_attr(var->attrs, ATTR_IN); + string_attr = is_attr(var->attrs, ATTR_STRING); + sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); + + /* set 'in' attribute if neither 'in' nor 'out' is found */ + if (!out_attr && !in_attr) + in_attr = 1; + + if (out_attr) + { + if (var->ptr_level == 1 && sizeis_attr != NULL) + { + if (string_attr) + { + if (var->type->type == RPC_FC_BYTE || + var->type->type == RPC_FC_CHAR || + var->type->type == RPC_FC_WCHAR) + { + print_server("_StubMsg.MaxCount = %s;\n", ((var_t *)sizeis_attr)->name); + fprintf(server, "\n"); + print_server("NdrConformantStringBufferSize(\n"); + indent++; + print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_server("(unsigned char __RPC_FAR *)%s,\n", var->name); + print_server("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", + local_type_offset + 4); + indent--; + } + } + else + { + if (((var_t *)sizeis_attr)->ptr_level == 0) + print_server("_StubMsg.MaxCount = %s;\n", ((var_t *)sizeis_attr)->name); + else + print_server("_StubMsg.MaxCount = %s ? *%s : 0;\n", + ((var_t *)sizeis_attr)->name, ((var_t *)sizeis_attr)->name); + fprintf(server, "\n"); + print_server("NdrConformantArrayBufferSize(\n"); + indent++; + print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_server("(unsigned char __RPC_FAR *)%s,\n", var->name); + print_server("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", + local_type_offset + 4); + indent--; + } + + empty_line = 1; + } + else if (var->type->type == RPC_FC_RP) + { + fprintf(server,"\n"); + print_server("NdrSimpleStructBufferSize(\n"); + indent++; + print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_server("(unsigned char __RPC_FAR *)%s,\n", var->name); + print_server("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", + local_type_offset + 4); /* FIXME */ + indent--; + fprintf(server,"\n"); + } + } + + /* calculate the next type offset */ + local_type_offset += get_var_type_offset(var); + } + + if (empty_line) + fprintf(server, "\n"); + } + + /* get string size */ + if (func->args) + { + empty_line = 0; + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + for (; var; var = PREV_LINK(var)) + { + out_attr = is_attr(var->attrs, ATTR_OUT); + in_attr = is_attr(var->attrs, ATTR_IN); + string_attr = is_attr(var->attrs, ATTR_STRING); + + /* set 'in' attribute if neither 'in' nor 'out' is found */ + if (!out_attr && !in_attr) + in_attr = 1; + + if (var->ptr_level == 1 && + string_attr && + (var->type->type == RPC_FC_BYTE || + var->type->type == RPC_FC_CHAR || + var->type->type == RPC_FC_WCHAR)) + { + print_server("_StubMsg.BufferLength += 16;\n"); + empty_line = 1; + } + } + + if (empty_line) + fprintf(server, "\n"); + } +} + + +static void init_pointers (func_t *func) +{ + var_t *var; + int count = 0; + + if (!func->args) + return; + + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + if (var->ptr_level == 0) + { + if (var->type->type == RPC_FC_RP) + { + print_server("*("); + write_type(server, var->type, NULL, var->tname); + fprintf(server, "*)&%s = NULL;\n", var->name); + count++; + } + } + else if (var->ptr_level == 1) + { + print_server("%s = (", var->name); + write_type(server, var->type, NULL, var->tname); + fprintf(server, " __RPC_FAR *)0;\n"); + count++; + } + else if (var->ptr_level > 1) + { + error("Pointer level %d not supported!\n", var->ptr_level); + return; + } + + var = PREV_LINK(var); + } + + if (count > 0) + fprintf(server, "\n"); +} + + +static void unmarshall_in_arguments(func_t *func, unsigned int *type_offset) +{ + unsigned int local_type_offset = *type_offset; + unsigned int alignment; + unsigned int size; + unsigned int last_size = 0; + var_t *var; + int in_attr, out_attr; + int string_attr; + int ptr_attr, ref_attr, unique_attr; + void *sizeis_attr; + + if (!func->args) + return; + + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + for (; var; var = PREV_LINK(var)) + { + out_attr = is_attr(var->attrs, ATTR_OUT); + in_attr = is_attr(var->attrs, ATTR_IN); + + /* set 'in' attribute if neither 'in' nor 'out' is set */ + if (!out_attr && !in_attr) + in_attr = 1; + + string_attr = is_attr(var->attrs, ATTR_STRING); + sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); + + if (in_attr) + { + if (var->ptr_level == 1) + { + ptr_attr = is_attr(var->attrs, ATTR_PTR); + ref_attr = is_attr(var->attrs, ATTR_REF); + unique_attr = is_attr(var->attrs, ATTR_UNIQUE); + if (ptr_attr + ref_attr + unique_attr == 0) + ref_attr = 1; + + if (ref_attr) + { + if (string_attr) + { + if (var->type->type == RPC_FC_CHAR || var->type->type == RPC_FC_WCHAR) + { + print_server("NdrConformantStringUnmarshall(\n"); + indent++; + print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_server("(unsigned char __RPC_FAR * __RPC_FAR *)&%s,\n", var->name); + print_server("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u],\n", + local_type_offset + 2); + print_server("(unsigned char)0);\n"); + indent--; + fprintf(server, "\n"); + print_server("_StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~0x3);\n"); + fprintf(server, "\n"); + } + } + else if (sizeis_attr) + { + print_server("NdrConformantArrayUnmarshall(\n"); + indent++; + print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_server("(unsigned char __RPC_FAR * __RPC_FAR *)&%s,\n", var->name); + print_server("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u],\n", + local_type_offset + 4); + print_server("(unsigned char)0);\n"); + indent--; + fprintf(server, "\n"); + print_server("_StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~0x3);\n"); + fprintf(server, "\n"); + } + else + { + alignment = 0; + switch (var->type->type) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + size = 1; + alignment = 0; + break; + + case RPC_FC_WCHAR: + case RPC_FC_USHORT: + case RPC_FC_SHORT: + size = 2; + if (last_size != 0 && last_size < 2) + alignment = (2 - last_size); + break; + + case RPC_FC_ULONG: + case RPC_FC_LONG: + case RPC_FC_FLOAT: + size = 4; + if (last_size != 0 && last_size < 4) + alignment = (4 - last_size); + break; + + case RPC_FC_HYPER: + case RPC_FC_DOUBLE: + size = 8; + if (last_size != 0 && last_size < 4) + alignment = (4 - last_size); + break; + + case RPC_FC_IGNORE: + size = 0; + break; + + default: + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, var->type->type); + return; + } + + if (size != 0) + { + if (alignment != 0) + print_server("_StubMsg.Buffer += %u;\n", alignment); + + print_server(""); + write_name(server, var); + fprintf(server, " = ("); + write_type(server, var->type, NULL, var->tname); + fprintf(server, " __RPC_FAR*)_StubMsg.Buffer;\n"); + print_server("_StubMsg.Buffer += sizeof("); + write_type(server, var->type, NULL, var->tname); + fprintf(server, ");\n"); + fprintf(server, "\n"); + + last_size = size; + } + } + } + else if (unique_attr) + { + print_server("NdrPointerUnmarshall(\n"); + indent++; + print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_server("(unsigned char __RPC_FAR * __RPC_FAR *)&%s,\n", var->name); + print_server("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u],\n", + local_type_offset); + print_server("(unsigned char)0);\n"); + indent--; + fprintf(server, "\n"); + } + + } + else + { + if (is_base_type(var->type)) + { + alignment = 0; + switch (var->type->type) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + size = 1; + alignment = 0; + break; + + case RPC_FC_WCHAR: + case RPC_FC_USHORT: + case RPC_FC_SHORT: + size = 2; + if (last_size != 0 && last_size < 2) + alignment = (2 - last_size); + break; + + case RPC_FC_ULONG: + case RPC_FC_LONG: + case RPC_FC_FLOAT: + size = 4; + if (last_size != 0 && last_size < 4) + alignment = (4 - last_size); + break; + + case RPC_FC_HYPER: + case RPC_FC_DOUBLE: + size = 8; + if (last_size != 0 && last_size < 4) + alignment = (4 - last_size); + break; + + case RPC_FC_IGNORE: + size = 0; + break; + + default: + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, var->type->type); + return; + } + + if (size != 0) + { + if (alignment != 0) + print_server("_StubMsg.Buffer += %u;\n", alignment); + + print_server(""); + write_name(server, var); + fprintf(server, " = *(("); + write_type(server, var->type, NULL, var->tname); + fprintf(server, " __RPC_FAR*)_StubMsg.Buffer);\n"); + print_server("_StubMsg.Buffer += sizeof("); + write_type(server, var->type, NULL, var->tname); + fprintf(server, ");\n"); + fprintf(server, "\n"); + + last_size = size; + } + } + else if (var->type->type == RPC_FC_RP) + { + if (var->type->ref->ref->type == RPC_FC_STRUCT) + { + print_server("NdrSimpleStructUnmarshall(\n"); + indent++; + print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_server("(unsigned char __RPC_FAR * __RPC_FAR *)&%s,\n", var->name); + print_server("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u],\n", + local_type_offset + 4); + print_server("(unsigned char)0);\n"); + indent--; + fprintf(server, "\n"); + } + } + } + } + + /* calculate the next type offset */ + local_type_offset += get_var_type_offset(var); + } +} + + +static void marshall_out_arguments(func_t *func, unsigned int *type_offset) +{ + unsigned int alignment = 0; + unsigned int size = 0; + unsigned int last_size = 0; + var_t *var; + var_t *def; + int out_attr; + int string_attr; + void *sizeis_attr; + unsigned int local_type_offset = *type_offset; + + def = func->def; + + /* marshall the out arguments */ + if (func->args) + { + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + for (; var; var = PREV_LINK(var)) + { + out_attr = is_attr(var->attrs, ATTR_OUT); + if (out_attr) + { + sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); + string_attr = is_attr(var->attrs, ATTR_STRING); + + if (sizeis_attr != NULL) + { + if (string_attr) + { + fprintf(server, "\n"); + print_server("_StubMsg.MaxCount = %s;\n", ((var_t *)sizeis_attr)->name); + fprintf(server, "\n"); + print_server("NdrConformantStringMarshall(\n"); + indent++; + print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_server("(unsigned char __RPC_FAR *)%s,\n", var->name); + print_server("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", + local_type_offset + 4); + indent--; + fprintf(server, "\n"); + print_server("_StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~0x3);\n"); + fprintf(server, "\n"); + } + else + { + fprintf(server, "\n"); + if (((var_t *)sizeis_attr)->ptr_level == 0) + print_server("_StubMsg.MaxCount = %s;\n", ((var_t *)sizeis_attr)->name); + else + print_server("_StubMsg.MaxCount = %s ? *%s : 0;\n", + ((var_t *)sizeis_attr)->name, ((var_t *)sizeis_attr)->name); + fprintf(server, "\n"); + print_server("NdrConformantArrayMarshall(\n"); + indent++; + print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_server("(unsigned char __RPC_FAR *)%s,\n", var->name); + print_server("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", + local_type_offset + 4); + indent--; + fprintf(server, "\n"); + print_server("_StubMsg.Buffer = (unsigned char __RPC_FAR *)(((long)_StubMsg.Buffer + 3) & ~0x3);\n"); + fprintf(server, "\n"); + } + } + else if (is_base_type(var->type)) + { + alignment = 0; + switch (var->type->type) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + size = 1; + alignment = 0; + break; + + case RPC_FC_WCHAR: + case RPC_FC_USHORT: + case RPC_FC_SHORT: + size = 2; + if (last_size != 0 && last_size < 2) + alignment = (2 - last_size); + break; + + case RPC_FC_ULONG: + case RPC_FC_LONG: + case RPC_FC_FLOAT: + size = 4; + if (last_size != 0 && last_size < 4) + alignment = (4 - last_size); + break; + + case RPC_FC_HYPER: + case RPC_FC_DOUBLE: + size = 8; + if (last_size != 0 && last_size < 4) + alignment = (4 - last_size); + break; + + case RPC_FC_IGNORE: + size = 0; + break; + + default: + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, var->type->type); + return; + } + + if (size != 0) + { + if (alignment != 0) + print_server("_StubMsg.Buffer += %u;\n", alignment); + + if (var->ptr_level == 1) + { + fprintf(server, "\n"); + print_server("*(("); + write_type(server, var->type, NULL, var->tname); + fprintf(server, " __RPC_FAR *)_StubMsg.Buffer) = *"); + write_name(server, var); + fprintf(server, ";\n"); + + print_server("_StubMsg.Buffer += sizeof("); + write_type(server, var->type, NULL, var->tname); + fprintf(server, ");"); + } + else + { + error("Pointer level %d is not supported!\n", var->ptr_level); + return; + } + + last_size = size; + } + } + else if (var->type->type == RPC_FC_RP) + { + fprintf(server, "\n"); + print_server("NdrSimpleStructMarshall(\n"); + indent++; + print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_server("(unsigned char __RPC_FAR *)%s,\n", var->name); + print_server("(PFORMAT_STRING)&__MIDL_TypeFormatString.Format[%u]);\n", + local_type_offset + 4); + indent--; + } + } + + /* calculate the next type offset */ + local_type_offset += get_var_type_offset(var); + } + } + + /* marshall the return value */ + if (!is_void(def->type, NULL)) + { + alignment = 0; + switch (def->type->type) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + case RPC_FC_WCHAR: + case RPC_FC_USHORT: + case RPC_FC_SHORT: + case RPC_FC_ULONG: + case RPC_FC_LONG: + case RPC_FC_FLOAT: + size = 4; + if (last_size != 0 && last_size < 4) + alignment = (4 - last_size); + break; + + case RPC_FC_HYPER: + case RPC_FC_DOUBLE: + size = 8; + if (last_size != 0 && last_size < 4) + alignment = (4 - last_size); + break; + + default: + error("%s:%d Unknown/unsupported type 0x%x\n", + __FUNCTION__,__LINE__, var->type->type); + return; + } + + fprintf(server, "\n"); + if (alignment != 0) + print_server("_StubMsg.Buffer += %u;\n", alignment); + print_server("*(("); + write_type(server, def->type, def, def->tname); + fprintf(server, " __RPC_FAR *)_StubMsg.Buffer) = _RetVal;\n"); + print_server("_StubMsg.Buffer += sizeof("); + write_type(server, def->type, def, def->tname); + fprintf(server, ");\n"); + } +} + + +static int use_return_buffer(func_t *func) +{ + var_t *var; + + if (!is_void(func->def->type, NULL)) + return 1; + + if (!func->args) + return 0; + + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + if (is_attr(var->attrs, ATTR_OUT)) + return 1; + + var = PREV_LINK(var); + } + + return 0; +} + + +static void cleanup_return_buffer(func_t *func, unsigned int *type_offset) +{ + var_t *var; + int string_attr; + void *sizeis_attr; + unsigned int local_type_offset = *type_offset; + + if (func->args) + { + int first_arg = 1; + + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); + string_attr = is_attr(var->attrs, ATTR_STRING); + + if (sizeis_attr != NULL) + { + if (first_arg == 0) + fprintf(server, "\n"); + + indent++; + if (string_attr) + { + print_server("_StubMsg.MaxCount = %s;\n", ((var_t *)sizeis_attr)->name); + fprintf(server, "\n"); + print_server("NdrPointerFree(\n"); + indent++; + print_server("&_StubMsg,\n"); + print_server("(unsigned char __RPC_FAR *)%s,\n", var->name); + print_server("&__MIDL_TypeFormatString.Format[%u]);\n", + local_type_offset); + indent--; + } + else + { + print_server("if ("); + write_name(server, var); + fprintf(server, ")\n"); + indent++; + print_server("_StubMsg.pfnFree("); + write_name(server, var); + fprintf(server, ");\n"); + indent--; + } + indent--; + + first_arg = 0; + } + + /* calculate the next type offset */ + local_type_offset += get_var_type_offset(var); + + var = PREV_LINK(var); + } + } +} + + +static void write_function_stubs(type_t *iface) +{ + int explicit_handle = is_attr(iface->attrs, ATTR_EXPLICIT_HANDLE); + func_t *func = iface->funcs; + var_t *var; + var_t* explicit_handle_var; + unsigned int proc_offset = 0; + unsigned int type_offset = 2; + unsigned int i, sep; + int in_attr; + int out_attr; + void *sizeis_attr; + + while (NEXT_LINK(func)) func = NEXT_LINK(func); + while (func) + { + var_t *def = func->def; + + /* check for a defined binding handle */ + explicit_handle_var = get_explicit_handle_var(func); + if (explicit_handle) + { + if (!explicit_handle_var) + { + error("%s() does not define an explicit binding handle!\n", def->name); + return; + } + } + else + { + if (explicit_handle_var) + { + error("%s() must not define a binding handle!\n", def->name); + return; + } + } + + fprintf(server, "void __RPC_STUB\n"); + fprintf(server, "%s_", iface->name); + write_name(server, def); + fprintf(server, "(\n"); + indent++; + print_server("PRPC_MESSAGE _pRpcMessage)\n"); + indent--; + + /* write the functions body */ + fprintf(server, "{\n"); + indent++; + + /* declare return value '_RetVal' */ + if (!is_void(def->type, NULL)) + { + print_server(""); + write_type(server, def->type, def, def->tname); + fprintf(server, " _RetVal;\n"); + } + + /* declare arguments */ + if (func->args) + { + i = 0; + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + in_attr = is_attr(var->attrs, ATTR_IN); + out_attr = is_attr(var->attrs, ATTR_OUT); + sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); + + if (!out_attr && !in_attr) + in_attr = 1; + if (!in_attr && !sizeis_attr) + { + if (var->type->type == RPC_FC_RP) + { + print_server("struct "); + write_type(server, NULL, NULL, var->type->ref->ref->name); + fprintf(server, " _%sW;\n", var->name); + } + else + { + print_server(""); + write_type(server, var->type, NULL, var->tname); + fprintf(server, " _W%u;\n", i); + i++; + } + } + + print_server(""); + write_type(server, var->type, var, var->tname); + fprintf(server, " "); + write_name(server, var); + fprintf(server, ";\n"); + + var = PREV_LINK(var); + } + } + + print_server("MIDL_STUB_MESSAGE _StubMsg;\n"); + print_server("RPC_STATUS _Status;\n"); + fprintf(server, "\n"); + + + print_server("((void)(_Status));\n"); + print_server("NdrServerInitializeNew(\n"); + indent++; + print_server("_pRpcMessage,\n"); + print_server("&_StubMsg,\n"); + print_server("&%s_StubDesc);\n", iface->name); + indent--; + fprintf(server, "\n"); + + if (explicit_handle) + { + print_server("%s = _pRpcMessage->Handle;\n", explicit_handle_var->name); + fprintf(server, "\n"); + } + + init_pointers(func); + + print_server("RpcTryFinally\n"); + print_server("{\n"); + indent++; + print_server("RpcTryExcept\n"); + print_server("{\n"); + indent++; + + if (func->args) + { + print_server("if ((_pRpcMessage->DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION)\n"); + indent++; + print_server("NdrConvert(\n"); + indent++; + print_server("(PMIDL_STUB_MESSAGE)&_StubMsg,\n"); + print_server("(PFORMAT_STRING)&__MIDL_ProcFormatString.Format[%u]);\n", proc_offset); + indent -= 2; + fprintf(server, "\n"); + + unmarshall_in_arguments(func, &type_offset); + } + + print_server("if (_StubMsg.Buffer > _StubMsg.BufferEnd)\n"); + print_server("{\n"); + indent++; + print_server("RpcRaiseException(RPC_X_BAD_STUB_DATA);\n"); + indent--; + print_server("}\n"); + indent--; + print_server("}\n"); + print_server("RpcExcept(RPC_BAD_STUB_DATA_EXCEPTION_FILTER)\n"); + print_server("{\n"); + indent++; + print_server("RpcRaiseException(RPC_X_BAD_STUB_DATA);\n"); + indent--; + print_server("}\n"); + print_server("RpcEndExcept\n"); + fprintf(server, "\n"); + + /* assign out arguments */ + if (func->args) + { + sep = 0; + i = 0; + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + in_attr = is_attr(var->attrs, ATTR_IN); + out_attr = is_attr(var->attrs, ATTR_OUT); + if (!out_attr && !in_attr) + in_attr = 1; + + sizeis_attr = get_attrp(var->attrs, ATTR_SIZEIS); + + if (!in_attr) + { + if (sizeis_attr != NULL) + { + print_server(""); + write_name(server, var); + if (((var_t *)sizeis_attr)->ptr_level == 0) + fprintf(server, " = NdrAllocate(&_StubMsg, %s * %d);\n", + ((var_t *)sizeis_attr)->name, get_type_size(var->type, 1)); + else if (((var_t *)sizeis_attr)->ptr_level == 1) + fprintf(server, " = NdrAllocate(&_StubMsg, *%s * %d);\n", + ((var_t *)sizeis_attr)->name, get_type_size(var->type, 1)); + sep = 1; + } + else + { + if (var->type->type == RPC_FC_RP) + { + print_server(""); + write_name(server, var); + fprintf(server, " = &_%sW;\n", var->name); + sep = 1; + } + else + { + print_server(""); + write_name(server, var); + fprintf(server, " = &_W%u;\n", i); + i++; + sep = 1; + } + } + } + + var = PREV_LINK(var); + } + + if (sep) + fprintf(server, "\n"); + } + + /* Call the real server function */ + if (!is_void(def->type, NULL)) + print_server("_RetVal = "); + else + print_server(""); + write_name(server, def); + + if (func->args) + { + int first_arg = 1; + + fprintf(server, "(\n"); + indent++; + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + if (first_arg) + first_arg = 0; + else + fprintf(server, ",\n"); + print_server(""); + write_name(server, var); + var = PREV_LINK(var); + } + fprintf(server, ");\n"); + indent--; + } + else + { + fprintf(server, "();\n"); + } + + /* allocate and fill the return message buffer */ + if (use_return_buffer(func)) + { + print_message_buffer_size(func, &type_offset); + print_server("_pRpcMessage->BufferLength = _StubMsg.BufferLength;\n"); + fprintf(server, "\n"); + print_server("_Status = I_RpcGetBuffer(_pRpcMessage);\n"); + print_server("if (_Status)\n"); + indent++; + print_server("RpcRaiseException(_Status);\n"); + indent--; + fprintf(server, "\n"); + print_server("_StubMsg.Buffer = (unsigned char __RPC_FAR *)_pRpcMessage->Buffer;\n"); + + /* marshall the out arguments */ + marshall_out_arguments(func, &type_offset); + } + + indent--; + print_server("}\n"); + print_server("RpcFinally\n"); + print_server("{\n"); + + cleanup_return_buffer(func, &type_offset); + + print_server("}\n"); + print_server("RpcEndFinally\n"); + + /* calculate buffer length */ + fprintf(server, "\n"); + print_server("_pRpcMessage->BufferLength =\n"); + indent++; + print_server("(unsigned int)((long)_StubMsg.Buffer - (long)_pRpcMessage->Buffer);\n"); + indent--; + indent--; + fprintf(server, "}\n"); + fprintf(server, "\n"); + + /* update type_offset */ + if (func->args) + { + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + type_offset += get_var_type_offset(var); + + var = PREV_LINK(var); + } + } + + /* update proc_offset */ + if (func->args) + { + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + switch (var->ptr_level) + { + case 0: + if (is_base_type(var->type)) + proc_offset += 2; + break; + + case 1: + if (is_base_type(var->type)) + proc_offset += 4; + break; + } + + var = PREV_LINK(var); + } + } + proc_offset += 2; /* FIXME */ + + func = PREV_LINK(func); + } +} + + +static void write_dispatchtable(type_t *iface) +{ + unsigned long ver = get_attrv(iface->attrs, ATTR_VERSION); + unsigned long method_count = 0; + func_t *cur = iface->funcs; + + print_server("static RPC_DISPATCH_FUNCTION %s_table[] =\n", iface->name); + print_server("{\n"); + indent++; + while (NEXT_LINK(cur)) cur = NEXT_LINK(cur); + while (cur) + { + var_t *def = cur->def; + + print_server("%s_", iface->name); + write_name(server, def); + fprintf(server, ",\n"); + + method_count++; + cur = PREV_LINK(cur); + } + print_server("0\n"); + indent--; + print_server("};\n"); + print_server("RPC_DISPATCH_TABLE %s_v%d_%d_DispatchTable =\n", iface->name, LOWORD(ver), HIWORD(ver)); + print_server("{\n"); + indent++; + print_server("%u,\n", method_count); + print_server("%s_table\n", iface->name); + indent--; + print_server("};\n"); + fprintf(server, "\n"); +} + + +static void write_stubdescdecl(type_t *iface) +{ + print_server("extern const MIDL_STUB_DESC %s_StubDesc;\n", iface->name); + fprintf(server, "\n"); +} + + +static void write_stubdescriptor(type_t *iface) +{ + print_server("const MIDL_STUB_DESC %s_StubDesc =\n", iface->name); + print_server("{\n"); + indent++; + print_server("(void __RPC_FAR *)& %s___RpcServerInterface,\n", iface->name); + print_server("MIDL_user_allocate,\n"); + print_server("MIDL_user_free,\n"); + print_server("{NULL},\n"); + print_server("0,\n"); + print_server("0,\n"); + print_server("0,\n"); + print_server("0,\n"); + print_server("__MIDL_TypeFormatString.Format,\n"); + print_server("1, /* -error bounds_check flag */\n"); + print_server("0x10001, /* Ndr library version */\n"); + print_server("0,\n"); + print_server("0x50100a4, /* MIDL Version 5.1.164 */\n"); + print_server("0,\n"); + print_server("0,\n"); + print_server("0, /* notify & notify_flag routine table */\n"); + print_server("1, /* Flags */\n"); + print_server("0, /* Reserved3 */\n"); + print_server("0, /* Reserved4 */\n"); + print_server("0 /* Reserved5 */\n"); + indent--; + print_server("};\n"); + fprintf(server, "\n"); +} + + +static void write_serverinterfacedecl(type_t *iface) +{ + unsigned long ver = get_attrv(iface->attrs, ATTR_VERSION); + UUID *uuid = get_attrp(iface->attrs, ATTR_UUID); + + print_server("extern RPC_DISPATCH_TABLE %s_v%d_%d_DispatchTable;\n", iface->name, LOWORD(ver), HIWORD(ver)); + fprintf(server, "\n"); + print_server("static const RPC_SERVER_INTERFACE %s___RpcServerInterface =\n", iface->name ); + print_server("{\n"); + indent++; + print_server("sizeof(RPC_SERVER_INTERFACE),\n"); + print_server("{{0x%08lx,0x%04x,0x%04x,{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x}},{%d,%d}},\n", + uuid->Data1, uuid->Data2, uuid->Data3, uuid->Data4[0], uuid->Data4[1], + uuid->Data4[2], uuid->Data4[3], uuid->Data4[4], uuid->Data4[5], uuid->Data4[6], + uuid->Data4[7], LOWORD(ver), HIWORD(ver)); + print_server("{{0x8a885d04,0x1ceb,0x11c9,{0x9f,0xe8,0x08,0x00,0x2b,0x10,0x48,0x60}},{2,0}},\n"); /* FIXME */ + print_server("&%s_v%d_%d_DispatchTable,\n", iface->name, LOWORD(ver), HIWORD(ver)); + print_server("0,\n"); + print_server("0,\n"); + print_server("0,\n"); + print_server("0,\n"); + print_server("0,\n"); + indent--; + print_server("};\n"); + if (old_names) + print_server("RPC_IF_HANDLE %s_ServerIfHandle = (RPC_IF_HANDLE)& %s___RpcServerInterface;\n", + iface->name, iface->name); + else + print_server("RPC_IF_HANDLE %s_v%d_%d_s_ifspec = (RPC_IF_HANDLE)& %s___RpcServerInterface;\n", + iface->name, LOWORD(ver), HIWORD(ver), iface->name); + fprintf(server, "\n"); +} + + +static void write_formatdesc( const char *str ) +{ + print_server("typedef struct _MIDL_%s_FORMAT_STRING\n", str ); + print_server("{\n"); + indent++; + print_server("short Pad;\n"); + print_server("unsigned char Format[%s_FORMAT_STRING_SIZE];\n", str); + indent--; + print_server("} MIDL_%s_FORMAT_STRING;\n", str); + print_server("\n"); +} + + +static int get_type_format_string_size(type_t *iface) +{ + int size = 3; + func_t *func; + var_t *var; + + /* determine the type format string size */ + func = iface->funcs; + while (NEXT_LINK(func)) func = NEXT_LINK(func); + while (func) + { + /* argument list size */ + if (func->args) + { + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + size += get_var_type_offset(var); + var = PREV_LINK(var); + } + } + + func = PREV_LINK(func); + } + + return size; +} + + +static int get_proc_format_string_size(type_t *iface) +{ + int size = 1; + func_t *func; + var_t *var; + + /* determine the proc format string size */ + func = iface->funcs; + while (NEXT_LINK(func)) func = NEXT_LINK(func); + while (func) + { + /* argument list size */ + if (func->args) + { + var = func->args; + while (NEXT_LINK(var)) var = NEXT_LINK(var); + while (var) + { + switch (var->ptr_level) + { + case 0: + if (is_base_type(var->type)) + size += 2; + else if (var->type->type == RPC_FC_RP) + size += 4; + break; + + case 1: + if (is_base_type(var->type)) + size += 4; + break; + } + + var = PREV_LINK(var); + } + } + + /* return value size */ + size += 2; + func = PREV_LINK(func); + } + + return size; +} + + +static void write_formatstringsdecl(type_t *iface) +{ + print_server("#define TYPE_FORMAT_STRING_SIZE %d\n", + get_type_format_string_size(iface)); + + print_server("#define PROC_FORMAT_STRING_SIZE %d\n", + get_proc_format_string_size(iface)); + + fprintf(server, "\n"); + write_formatdesc("TYPE"); + write_formatdesc("PROC"); + fprintf(server, "\n"); + print_server("extern const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString;\n"); + print_server("extern const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString;\n"); + print_server("\n"); +} + + +static void init_server(void) +{ + if (server) + return; + if (!(server = fopen(server_name, "w"))) + error("Could not open %s for output\n", server_name); + + print_server("/*** Autogenerated by WIDL %s from %s - Do not edit ***/\n", WIDL_FULLVERSION, input_name); + print_server("#include <string.h>\n"); + fprintf(server, "\n"); + print_server("#include \"%s\"\n", header_name); + fprintf(server, "\n"); +} + + +void write_server(ifref_t *ifaces) +{ + ifref_t *iface = ifaces; + + if (!do_server) + return; + if (!iface) + return; + END_OF_LIST(iface); + + init_server(); + if (!server) + return; + + while (iface) + { + fprintf(server, "/*****************************************************************************\n"); + fprintf(server, " * %s interface\n", iface->iface->name); + fprintf(server, " */\n"); + fprintf(server, "\n"); + + write_formatstringsdecl(iface->iface); + write_serverinterfacedecl(iface->iface); + write_stubdescdecl(iface->iface); + + write_function_stubs(iface->iface); + + write_stubdescriptor(iface->iface); + write_dispatchtable(iface->iface); + + print_server("#if !defined(__RPC_WIN32__)\n"); + print_server("#error Invalid build platform for this stub.\n"); + print_server("#endif\n"); + fprintf(server, "\n"); + + write_procformatstring(iface->iface); + write_typeformatstring(iface->iface); + + fprintf(server, "\n"); + + iface = PREV_LINK(iface); + } + + fclose(server); +} diff --git a/reactos/tools/widl/winglue.h b/reactos/tools/widl/winglue.h index 37dbdae6ff2..7cf64273769 100644 --- a/reactos/tools/widl/winglue.h +++ b/reactos/tools/widl/winglue.h @@ -1,229 +1,229 @@ -#ifndef _WINGLUE_H -#define _WINGLUE_H - -#define LOWORD(l) ((unsigned short)(l)) -#define HIWORD(l) ((unsigned short)((unsigned long)(l) >> 16)) -#define MAKELONG(low,high) ((unsigned long)(((unsigned short)(low)) | (((unsigned long)((unsigned short)(high))) << 16))) - -typedef char CHAR; -typedef int INT; -typedef short SHORT; -typedef unsigned char BYTE; -typedef unsigned short WORD; -typedef unsigned int DWORD; -typedef unsigned int UINT; -typedef unsigned int ULONG; -typedef DWORD LCID; -typedef const unsigned char *LPCSTR; -typedef int HRESULT; -typedef GUID *REFGUID; - -#define S_OK ((HRESULT)0x00000000L) -#define S_FALSE ((HRESULT)0x00000001L) -#define E_OUTOFMEMORY ((HRESULT)0x8007000EL) -#define TYPE_E_IOERROR ((HRESULT)0x80028CA2L) - -#define LANG_NEUTRAL 0x00 -#define LANG_ARABIC 0x01 -#define LANG_BULGARIAN 0x02 -#define LANG_CATALAN 0x03 -#define LANG_CHINESE 0x04 -#define LANG_CZECH 0x05 -#define LANG_DANISH 0x06 -#define LANG_GERMAN 0x07 -#define LANG_GREEK 0x08 -#define LANG_ENGLISH 0x09 -#define LANG_SPANISH 0x0a -#define LANG_FINNISH 0x0b -#define LANG_FRENCH 0x0c -#define LANG_HEBREW 0x0d -#define LANG_HUNGARIAN 0x0e -#define LANG_ICELANDIC 0x0f -#define LANG_ITALIAN 0x10 -#define LANG_JAPANESE 0x11 -#define LANG_KOREAN 0x12 -#define LANG_DUTCH 0x13 -#define LANG_NORWEGIAN 0x14 -#define LANG_POLISH 0x15 -#define LANG_PORTUGUESE 0x16 -#define LANG_ROMANIAN 0x18 -#define LANG_RUSSIAN 0x19 -#define LANG_CROATIAN 0x1a -#define LANG_SERBIAN 0x1a -#define LANG_SLOVAK 0x1b -#define LANG_ALBANIAN 0x1c -#define LANG_SWEDISH 0x1d -#define LANG_THAI 0x1e -#define LANG_TURKISH 0x1f -#define LANG_URDU 0x20 -#define LANG_INDONESIAN 0x21 -#define LANG_UKRAINIAN 0x22 -#define LANG_BELARUSIAN 0x23 -#define LANG_SLOVENIAN 0x24 -#define LANG_ESTONIAN 0x25 -#define LANG_LATVIAN 0x26 -#define LANG_LITHUANIAN 0x27 -#define LANG_FARSI 0x29 -#define LANG_VIETNAMESE 0x2a -#define LANG_ARMENIAN 0x2b -#define LANG_AZERI 0x2c -#define LANG_BASQUE 0x2d -#define LANG_MACEDONIAN 0x2f -#define LANG_AFRIKAANS 0x36 -#define LANG_GEORGIAN 0x37 -#define LANG_FAEROESE 0x38 -#define LANG_HINDI 0x39 -#define LANG_MALAY 0x3e -#define LANG_KAZAK 0x3f -#define LANG_KYRGYZ 0x40 -#define LANG_SWAHILI 0x41 -#define LANG_UZBEK 0x43 -#define LANG_TATAR 0x44 -#define LANG_BENGALI 0x45 -#define LANG_PUNJABI 0x46 -#define LANG_GUJARATI 0x47 -#define LANG_ORIYA 0x48 -#define LANG_TAMIL 0x49 -#define LANG_TELUGU 0x4a -#define LANG_KANNADA 0x4b -#define LANG_MALAYALAM 0x4c -#define LANG_ASSAMESE 0x4d -#define LANG_MARATHI 0x4e -#define LANG_SANSKRIT 0x4f -#define LANG_MONGOLIAN 0x50 -#define LANG_GALICIAN 0x56 -#define LANG_KONKANI 0x57 -#define LANG_MANIPURI 0x58 -#define LANG_SINDHI 0x59 -#define LANG_SYRIAC 0x5a -#define LANG_KASHMIRI 0x60 -#define LANG_NEPALI 0x61 -#define LANG_DIVEHI 0x65 -#define LANG_INVARIANT 0x7f -#define SUBLANG_NEUTRAL 0x00 -#define SUBLANG_DEFAULT 0x01 -#define SUBLANG_SYS_DEFAULT 0x02 -#define SUBLANG_ARABIC_SAUDI_ARABIA 0x01 -#define SUBLANG_ARABIC_IRAQ 0x02 -#define SUBLANG_ARABIC_EGYPT 0x03 -#define SUBLANG_ARABIC_LIBYA 0x04 -#define SUBLANG_ARABIC_ALGERIA 0x05 -#define SUBLANG_ARABIC_MOROCCO 0x06 -#define SUBLANG_ARABIC_TUNISIA 0x07 -#define SUBLANG_ARABIC_OMAN 0x08 -#define SUBLANG_ARABIC_YEMEN 0x09 -#define SUBLANG_ARABIC_SYRIA 0x0a -#define SUBLANG_ARABIC_JORDAN 0x0b -#define SUBLANG_ARABIC_LEBANON 0x0c -#define SUBLANG_ARABIC_KUWAIT 0x0d -#define SUBLANG_ARABIC_UAE 0x0e -#define SUBLANG_ARABIC_BAHRAIN 0x0f -#define SUBLANG_ARABIC_QATAR 0x10 -#define SUBLANG_AZERI_LATIN 0x01 -#define SUBLANG_AZERI_CYRILLIC 0x02 -#define SUBLANG_CHINESE_TRADITIONAL 0x01 -#define SUBLANG_CHINESE_SIMPLIFIED 0x02 -#define SUBLANG_CHINESE_HONGKONG 0x03 -#define SUBLANG_CHINESE_SINGAPORE 0x04 -#define SUBLANG_CHINESE_MACAU 0x05 -#define SUBLANG_DUTCH 0x01 -#define SUBLANG_DUTCH_BELGIAN 0x02 -#define SUBLANG_ENGLISH_US 0x01 -#define SUBLANG_ENGLISH_UK 0x02 -#define SUBLANG_ENGLISH_AUS 0x03 -#define SUBLANG_ENGLISH_CAN 0x04 -#define SUBLANG_ENGLISH_NZ 0x05 -#define SUBLANG_ENGLISH_EIRE 0x06 -#define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07 -#define SUBLANG_ENGLISH_JAMAICA 0x08 -#define SUBLANG_ENGLISH_CARIBBEAN 0x09 -#define SUBLANG_ENGLISH_BELIZE 0x0a -#define SUBLANG_ENGLISH_TRINIDAD 0x0b -#define SUBLANG_ENGLISH_ZIMBABWE 0x0c -#define SUBLANG_ENGLISH_PHILIPPINES 0x0d -#define SUBLANG_FRENCH 0x01 -#define SUBLANG_FRENCH_BELGIAN 0x02 -#define SUBLANG_FRENCH_CANADIAN 0x03 -#define SUBLANG_FRENCH_SWISS 0x04 -#define SUBLANG_FRENCH_LUXEMBOURG 0x05 -#define SUBLANG_FRENCH_MONACO 0x06 -#define SUBLANG_GERMAN 0x01 -#define SUBLANG_GERMAN_SWISS 0x02 -#define SUBLANG_GERMAN_AUSTRIAN 0x03 -#define SUBLANG_GERMAN_LUXEMBOURG 0x04 -#define SUBLANG_GERMAN_LIECHTENSTEIN 0x05 -#define SUBLANG_ITALIAN 0x01 -#define SUBLANG_ITALIAN_SWISS 0x02 -#define SUBLANG_KASHMIRI_INDIA 0x02 -#define SUBLANG_KASHMIRI_SASIA 0x02 -#define SUBLANG_KOREAN 0x01 -#define SUBLANG_LITHUANIAN 0x01 -#define SUBLANG_MALAY_MALAYSIA 0x01 -#define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02 -#define SUBLANG_NEPALI_INDIA 0x02 -#define SUBLANG_NORWEGIAN_BOKMAL 0x01 -#define SUBLANG_NORWEGIAN_NYNORSK 0x02 -#define SUBLANG_PORTUGUESE 0x01 -#define SUBLANG_PORTUGUESE_BRAZILIAN 0x02 -#define SUBLANG_SERBIAN_LATIN 0x02 -#define SUBLANG_SERBIAN_CYRILLIC 0x03 -#define SUBLANG_SPANISH 0x01 -#define SUBLANG_SPANISH_MEXICAN 0x02 -#define SUBLANG_SPANISH_MODERN 0x03 -#define SUBLANG_SPANISH_GUATEMALA 0x04 -#define SUBLANG_SPANISH_COSTA_RICA 0x05 -#define SUBLANG_SPANISH_PANAMA 0x06 -#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07 -#define SUBLANG_SPANISH_VENEZUELA 0x08 -#define SUBLANG_SPANISH_COLOMBIA 0x09 -#define SUBLANG_SPANISH_PERU 0x0a -#define SUBLANG_SPANISH_ARGENTINA 0x0b -#define SUBLANG_SPANISH_ECUADOR 0x0c -#define SUBLANG_SPANISH_CHILE 0x0d -#define SUBLANG_SPANISH_URUGUAY 0x0e -#define SUBLANG_SPANISH_PARAGUAY 0x0f -#define SUBLANG_SPANISH_BOLIVIA 0x10 -#define SUBLANG_SPANISH_EL_SALVADOR 0x11 -#define SUBLANG_SPANISH_HONDURAS 0x12 -#define SUBLANG_SPANISH_NICARAGUA 0x13 -#define SUBLANG_SPANISH_PUERTO_RICO 0x14 -#define SUBLANG_SWEDISH 0x01 -#define SUBLANG_SWEDISH_FINLAND 0x02 -#define SUBLANG_URDU_PAKISTAN 0x01 -#define SUBLANG_URDU_INDIA 0x02 -#define SUBLANG_UZBEK_LATIN 0x01 -#define SUBLANG_UZBEK_CYRILLIC 0x02 - -/* non standard; keep the number high enough (but < 0xff) */ -#define LANG_ESPERANTO 0x8f -#define LANG_WALON 0x90 -#define LANG_CORNISH 0x91 -#define LANG_WELSH 0x92 -#define LANG_BRETON 0x93 - -/* FIXME: these are not in the Windows header */ -#define LANG_GAELIC 0x3c -#define LANG_MALTESE 0x3a -#define LANG_MAORI 0x28 -#define LANG_RHAETO_ROMANCE 0x17 -#define LANG_SAAMI 0x3b -#define LANG_SORBIAN 0x2e -#define LANG_SUTU 0x30 -#define LANG_TSONGA 0x31 -#define LANG_TSWANA 0x32 -#define LANG_VENDA 0x33 -#define LANG_XHOSA 0x34 -#define LANG_ZULU 0x35 - -#define PRIMARYLANGID(l) ((WORD)(l)&0x3ff) -#define LANGIDFROMLCID(l) ((WORD)(l)) -#define SUBLANGID(l) ((WORD)(l)>>10) - -#ifndef max -#define max(a,b) ((a)>(b)?(a):(b)) -#endif -#ifndef min -#define min(a,b) ((a)<(b)?(a):(b)) -#endif - -#endif /* _WINGLUE_H */ +#ifndef _WINGLUE_H +#define _WINGLUE_H + +#define LOWORD(l) ((unsigned short)(l)) +#define HIWORD(l) ((unsigned short)((unsigned long)(l) >> 16)) +#define MAKELONG(low,high) ((unsigned long)(((unsigned short)(low)) | (((unsigned long)((unsigned short)(high))) << 16))) + +typedef char CHAR; +typedef int INT; +typedef short SHORT; +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned int DWORD; +typedef unsigned int UINT; +typedef unsigned int ULONG; +typedef DWORD LCID; +typedef const unsigned char *LPCSTR; +typedef int HRESULT; +typedef GUID *REFGUID; + +#define S_OK ((HRESULT)0x00000000L) +#define S_FALSE ((HRESULT)0x00000001L) +#define E_OUTOFMEMORY ((HRESULT)0x8007000EL) +#define TYPE_E_IOERROR ((HRESULT)0x80028CA2L) + +#define LANG_NEUTRAL 0x00 +#define LANG_ARABIC 0x01 +#define LANG_BULGARIAN 0x02 +#define LANG_CATALAN 0x03 +#define LANG_CHINESE 0x04 +#define LANG_CZECH 0x05 +#define LANG_DANISH 0x06 +#define LANG_GERMAN 0x07 +#define LANG_GREEK 0x08 +#define LANG_ENGLISH 0x09 +#define LANG_SPANISH 0x0a +#define LANG_FINNISH 0x0b +#define LANG_FRENCH 0x0c +#define LANG_HEBREW 0x0d +#define LANG_HUNGARIAN 0x0e +#define LANG_ICELANDIC 0x0f +#define LANG_ITALIAN 0x10 +#define LANG_JAPANESE 0x11 +#define LANG_KOREAN 0x12 +#define LANG_DUTCH 0x13 +#define LANG_NORWEGIAN 0x14 +#define LANG_POLISH 0x15 +#define LANG_PORTUGUESE 0x16 +#define LANG_ROMANIAN 0x18 +#define LANG_RUSSIAN 0x19 +#define LANG_CROATIAN 0x1a +#define LANG_SERBIAN 0x1a +#define LANG_SLOVAK 0x1b +#define LANG_ALBANIAN 0x1c +#define LANG_SWEDISH 0x1d +#define LANG_THAI 0x1e +#define LANG_TURKISH 0x1f +#define LANG_URDU 0x20 +#define LANG_INDONESIAN 0x21 +#define LANG_UKRAINIAN 0x22 +#define LANG_BELARUSIAN 0x23 +#define LANG_SLOVENIAN 0x24 +#define LANG_ESTONIAN 0x25 +#define LANG_LATVIAN 0x26 +#define LANG_LITHUANIAN 0x27 +#define LANG_FARSI 0x29 +#define LANG_VIETNAMESE 0x2a +#define LANG_ARMENIAN 0x2b +#define LANG_AZERI 0x2c +#define LANG_BASQUE 0x2d +#define LANG_MACEDONIAN 0x2f +#define LANG_AFRIKAANS 0x36 +#define LANG_GEORGIAN 0x37 +#define LANG_FAEROESE 0x38 +#define LANG_HINDI 0x39 +#define LANG_MALAY 0x3e +#define LANG_KAZAK 0x3f +#define LANG_KYRGYZ 0x40 +#define LANG_SWAHILI 0x41 +#define LANG_UZBEK 0x43 +#define LANG_TATAR 0x44 +#define LANG_BENGALI 0x45 +#define LANG_PUNJABI 0x46 +#define LANG_GUJARATI 0x47 +#define LANG_ORIYA 0x48 +#define LANG_TAMIL 0x49 +#define LANG_TELUGU 0x4a +#define LANG_KANNADA 0x4b +#define LANG_MALAYALAM 0x4c +#define LANG_ASSAMESE 0x4d +#define LANG_MARATHI 0x4e +#define LANG_SANSKRIT 0x4f +#define LANG_MONGOLIAN 0x50 +#define LANG_GALICIAN 0x56 +#define LANG_KONKANI 0x57 +#define LANG_MANIPURI 0x58 +#define LANG_SINDHI 0x59 +#define LANG_SYRIAC 0x5a +#define LANG_KASHMIRI 0x60 +#define LANG_NEPALI 0x61 +#define LANG_DIVEHI 0x65 +#define LANG_INVARIANT 0x7f +#define SUBLANG_NEUTRAL 0x00 +#define SUBLANG_DEFAULT 0x01 +#define SUBLANG_SYS_DEFAULT 0x02 +#define SUBLANG_ARABIC_SAUDI_ARABIA 0x01 +#define SUBLANG_ARABIC_IRAQ 0x02 +#define SUBLANG_ARABIC_EGYPT 0x03 +#define SUBLANG_ARABIC_LIBYA 0x04 +#define SUBLANG_ARABIC_ALGERIA 0x05 +#define SUBLANG_ARABIC_MOROCCO 0x06 +#define SUBLANG_ARABIC_TUNISIA 0x07 +#define SUBLANG_ARABIC_OMAN 0x08 +#define SUBLANG_ARABIC_YEMEN 0x09 +#define SUBLANG_ARABIC_SYRIA 0x0a +#define SUBLANG_ARABIC_JORDAN 0x0b +#define SUBLANG_ARABIC_LEBANON 0x0c +#define SUBLANG_ARABIC_KUWAIT 0x0d +#define SUBLANG_ARABIC_UAE 0x0e +#define SUBLANG_ARABIC_BAHRAIN 0x0f +#define SUBLANG_ARABIC_QATAR 0x10 +#define SUBLANG_AZERI_LATIN 0x01 +#define SUBLANG_AZERI_CYRILLIC 0x02 +#define SUBLANG_CHINESE_TRADITIONAL 0x01 +#define SUBLANG_CHINESE_SIMPLIFIED 0x02 +#define SUBLANG_CHINESE_HONGKONG 0x03 +#define SUBLANG_CHINESE_SINGAPORE 0x04 +#define SUBLANG_CHINESE_MACAU 0x05 +#define SUBLANG_DUTCH 0x01 +#define SUBLANG_DUTCH_BELGIAN 0x02 +#define SUBLANG_ENGLISH_US 0x01 +#define SUBLANG_ENGLISH_UK 0x02 +#define SUBLANG_ENGLISH_AUS 0x03 +#define SUBLANG_ENGLISH_CAN 0x04 +#define SUBLANG_ENGLISH_NZ 0x05 +#define SUBLANG_ENGLISH_EIRE 0x06 +#define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07 +#define SUBLANG_ENGLISH_JAMAICA 0x08 +#define SUBLANG_ENGLISH_CARIBBEAN 0x09 +#define SUBLANG_ENGLISH_BELIZE 0x0a +#define SUBLANG_ENGLISH_TRINIDAD 0x0b +#define SUBLANG_ENGLISH_ZIMBABWE 0x0c +#define SUBLANG_ENGLISH_PHILIPPINES 0x0d +#define SUBLANG_FRENCH 0x01 +#define SUBLANG_FRENCH_BELGIAN 0x02 +#define SUBLANG_FRENCH_CANADIAN 0x03 +#define SUBLANG_FRENCH_SWISS 0x04 +#define SUBLANG_FRENCH_LUXEMBOURG 0x05 +#define SUBLANG_FRENCH_MONACO 0x06 +#define SUBLANG_GERMAN 0x01 +#define SUBLANG_GERMAN_SWISS 0x02 +#define SUBLANG_GERMAN_AUSTRIAN 0x03 +#define SUBLANG_GERMAN_LUXEMBOURG 0x04 +#define SUBLANG_GERMAN_LIECHTENSTEIN 0x05 +#define SUBLANG_ITALIAN 0x01 +#define SUBLANG_ITALIAN_SWISS 0x02 +#define SUBLANG_KASHMIRI_INDIA 0x02 +#define SUBLANG_KASHMIRI_SASIA 0x02 +#define SUBLANG_KOREAN 0x01 +#define SUBLANG_LITHUANIAN 0x01 +#define SUBLANG_MALAY_MALAYSIA 0x01 +#define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02 +#define SUBLANG_NEPALI_INDIA 0x02 +#define SUBLANG_NORWEGIAN_BOKMAL 0x01 +#define SUBLANG_NORWEGIAN_NYNORSK 0x02 +#define SUBLANG_PORTUGUESE 0x01 +#define SUBLANG_PORTUGUESE_BRAZILIAN 0x02 +#define SUBLANG_SERBIAN_LATIN 0x02 +#define SUBLANG_SERBIAN_CYRILLIC 0x03 +#define SUBLANG_SPANISH 0x01 +#define SUBLANG_SPANISH_MEXICAN 0x02 +#define SUBLANG_SPANISH_MODERN 0x03 +#define SUBLANG_SPANISH_GUATEMALA 0x04 +#define SUBLANG_SPANISH_COSTA_RICA 0x05 +#define SUBLANG_SPANISH_PANAMA 0x06 +#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07 +#define SUBLANG_SPANISH_VENEZUELA 0x08 +#define SUBLANG_SPANISH_COLOMBIA 0x09 +#define SUBLANG_SPANISH_PERU 0x0a +#define SUBLANG_SPANISH_ARGENTINA 0x0b +#define SUBLANG_SPANISH_ECUADOR 0x0c +#define SUBLANG_SPANISH_CHILE 0x0d +#define SUBLANG_SPANISH_URUGUAY 0x0e +#define SUBLANG_SPANISH_PARAGUAY 0x0f +#define SUBLANG_SPANISH_BOLIVIA 0x10 +#define SUBLANG_SPANISH_EL_SALVADOR 0x11 +#define SUBLANG_SPANISH_HONDURAS 0x12 +#define SUBLANG_SPANISH_NICARAGUA 0x13 +#define SUBLANG_SPANISH_PUERTO_RICO 0x14 +#define SUBLANG_SWEDISH 0x01 +#define SUBLANG_SWEDISH_FINLAND 0x02 +#define SUBLANG_URDU_PAKISTAN 0x01 +#define SUBLANG_URDU_INDIA 0x02 +#define SUBLANG_UZBEK_LATIN 0x01 +#define SUBLANG_UZBEK_CYRILLIC 0x02 + +/* non standard; keep the number high enough (but < 0xff) */ +#define LANG_ESPERANTO 0x8f +#define LANG_WALON 0x90 +#define LANG_CORNISH 0x91 +#define LANG_WELSH 0x92 +#define LANG_BRETON 0x93 + +/* FIXME: these are not in the Windows header */ +#define LANG_GAELIC 0x3c +#define LANG_MALTESE 0x3a +#define LANG_MAORI 0x28 +#define LANG_RHAETO_ROMANCE 0x17 +#define LANG_SAAMI 0x3b +#define LANG_SORBIAN 0x2e +#define LANG_SUTU 0x30 +#define LANG_TSONGA 0x31 +#define LANG_TSWANA 0x32 +#define LANG_VENDA 0x33 +#define LANG_XHOSA 0x34 +#define LANG_ZULU 0x35 + +#define PRIMARYLANGID(l) ((WORD)(l)&0x3ff) +#define LANGIDFROMLCID(l) ((WORD)(l)) +#define SUBLANGID(l) ((WORD)(l)>>10) + +#ifndef max +#define max(a,b) ((a)>(b)?(a):(b)) +#endif +#ifndef min +#define min(a,b) ((a)<(b)?(a):(b)) +#endif + +#endif /* _WINGLUE_H */ diff --git a/reactos/tools/widl/y.tab.c b/reactos/tools/widl/y.tab.c index a80706b4b1d..298767083cc 100644 --- a/reactos/tools/widl/y.tab.c +++ b/reactos/tools/widl/y.tab.c @@ -1,3979 +1,3979 @@ -/* A Bison parser, made by GNU Bison 1.875. */ - -/* Skeleton parser for Yacc-like parsing with Bison, - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc. - - 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, 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., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -/* As a special exception, when this file is copied by Bison into a - Bison output file, you may use that output file without restriction. - This special exception was added by the Free Software Foundation - in version 1.24 of Bison. */ - -/* Written by Richard Stallman by simplifying the original so called - ``semantic'' parser. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -/* Identify Bison output. */ -#define YYBISON 1 - -/* Skeleton name. */ -#define YYSKELETON_NAME "yacc.c" - -/* Pure parsers. */ -#define YYPURE 0 - -/* Using locations. */ -#define YYLSP_NEEDED 0 - - - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - aIDENTIFIER = 258, - aKNOWNTYPE = 259, - aNUM = 260, - aHEXNUM = 261, - aSTRING = 262, - aUUID = 263, - aEOF = 264, - SHL = 265, - SHR = 266, - tAGGREGATABLE = 267, - tALLOCATE = 268, - tAPPOBJECT = 269, - tARRAYS = 270, - tASYNC = 271, - tASYNCUUID = 272, - tAUTOHANDLE = 273, - tBINDABLE = 274, - tBOOLEAN = 275, - tBROADCAST = 276, - tBYTE = 277, - tBYTECOUNT = 278, - tCALLAS = 279, - tCALLBACK = 280, - tCASE = 281, - tCDECL = 282, - tCHAR = 283, - tCOCLASS = 284, - tCODE = 285, - tCOMMSTATUS = 286, - tCONST = 287, - tCONTEXTHANDLE = 288, - tCONTEXTHANDLENOSERIALIZE = 289, - tCONTEXTHANDLESERIALIZE = 290, - tCONTROL = 291, - tCPPQUOTE = 292, - tDEFAULT = 293, - tDEFAULTVALUE = 294, - tDISPINTERFACE = 295, - tDLLNAME = 296, - tDOUBLE = 297, - tDUAL = 298, - tENDPOINT = 299, - tENTRY = 300, - tENUM = 301, - tERRORSTATUST = 302, - tEXPLICITHANDLE = 303, - tEXTERN = 304, - tFLOAT = 305, - tHANDLE = 306, - tHANDLET = 307, - tHELPCONTEXT = 308, - tHELPFILE = 309, - tHELPSTRING = 310, - tHELPSTRINGCONTEXT = 311, - tHELPSTRINGDLL = 312, - tHIDDEN = 313, - tHYPER = 314, - tID = 315, - tIDEMPOTENT = 316, - tIIDIS = 317, - tIMPLICITHANDLE = 318, - tIMPORT = 319, - tIMPORTLIB = 320, - tIN = 321, - tINCLUDE = 322, - tINLINE = 323, - tINPUTSYNC = 324, - tINT = 325, - tINT64 = 326, - tINTERFACE = 327, - tLENGTHIS = 328, - tLIBRARY = 329, - tLOCAL = 330, - tLONG = 331, - tMETHODS = 332, - tMODULE = 333, - tNONCREATABLE = 334, - tOBJECT = 335, - tODL = 336, - tOLEAUTOMATION = 337, - tOPTIONAL = 338, - tOUT = 339, - tPOINTERDEFAULT = 340, - tPROPERTIES = 341, - tPROPGET = 342, - tPROPPUT = 343, - tPROPPUTREF = 344, - tPTR = 345, - tPUBLIC = 346, - tREADONLY = 347, - tREF = 348, - tRESTRICTED = 349, - tRETVAL = 350, - tSHORT = 351, - tSIGNED = 352, - tSINGLE = 353, - tSIZEIS = 354, - tSIZEOF = 355, - tSMALL = 356, - tSOURCE = 357, - tSTDCALL = 358, - tSTRING = 359, - tSTRUCT = 360, - tSWITCH = 361, - tSWITCHIS = 362, - tSWITCHTYPE = 363, - tTRANSMITAS = 364, - tTYPEDEF = 365, - tUNION = 366, - tUNIQUE = 367, - tUNSIGNED = 368, - tUUID = 369, - tV1ENUM = 370, - tVARARG = 371, - tVERSION = 372, - tVOID = 373, - tWCHAR = 374, - tWIREMARSHAL = 375, - tPOINTERTYPE = 376, - COND = 377, - CAST = 378, - PPTR = 379, - NEG = 380 - }; -#endif -#define aIDENTIFIER 258 -#define aKNOWNTYPE 259 -#define aNUM 260 -#define aHEXNUM 261 -#define aSTRING 262 -#define aUUID 263 -#define aEOF 264 -#define SHL 265 -#define SHR 266 -#define tAGGREGATABLE 267 -#define tALLOCATE 268 -#define tAPPOBJECT 269 -#define tARRAYS 270 -#define tASYNC 271 -#define tASYNCUUID 272 -#define tAUTOHANDLE 273 -#define tBINDABLE 274 -#define tBOOLEAN 275 -#define tBROADCAST 276 -#define tBYTE 277 -#define tBYTECOUNT 278 -#define tCALLAS 279 -#define tCALLBACK 280 -#define tCASE 281 -#define tCDECL 282 -#define tCHAR 283 -#define tCOCLASS 284 -#define tCODE 285 -#define tCOMMSTATUS 286 -#define tCONST 287 -#define tCONTEXTHANDLE 288 -#define tCONTEXTHANDLENOSERIALIZE 289 -#define tCONTEXTHANDLESERIALIZE 290 -#define tCONTROL 291 -#define tCPPQUOTE 292 -#define tDEFAULT 293 -#define tDEFAULTVALUE 294 -#define tDISPINTERFACE 295 -#define tDLLNAME 296 -#define tDOUBLE 297 -#define tDUAL 298 -#define tENDPOINT 299 -#define tENTRY 300 -#define tENUM 301 -#define tERRORSTATUST 302 -#define tEXPLICITHANDLE 303 -#define tEXTERN 304 -#define tFLOAT 305 -#define tHANDLE 306 -#define tHANDLET 307 -#define tHELPCONTEXT 308 -#define tHELPFILE 309 -#define tHELPSTRING 310 -#define tHELPSTRINGCONTEXT 311 -#define tHELPSTRINGDLL 312 -#define tHIDDEN 313 -#define tHYPER 314 -#define tID 315 -#define tIDEMPOTENT 316 -#define tIIDIS 317 -#define tIMPLICITHANDLE 318 -#define tIMPORT 319 -#define tIMPORTLIB 320 -#define tIN 321 -#define tINCLUDE 322 -#define tINLINE 323 -#define tINPUTSYNC 324 -#define tINT 325 -#define tINT64 326 -#define tINTERFACE 327 -#define tLENGTHIS 328 -#define tLIBRARY 329 -#define tLOCAL 330 -#define tLONG 331 -#define tMETHODS 332 -#define tMODULE 333 -#define tNONCREATABLE 334 -#define tOBJECT 335 -#define tODL 336 -#define tOLEAUTOMATION 337 -#define tOPTIONAL 338 -#define tOUT 339 -#define tPOINTERDEFAULT 340 -#define tPROPERTIES 341 -#define tPROPGET 342 -#define tPROPPUT 343 -#define tPROPPUTREF 344 -#define tPTR 345 -#define tPUBLIC 346 -#define tREADONLY 347 -#define tREF 348 -#define tRESTRICTED 349 -#define tRETVAL 350 -#define tSHORT 351 -#define tSIGNED 352 -#define tSINGLE 353 -#define tSIZEIS 354 -#define tSIZEOF 355 -#define tSMALL 356 -#define tSOURCE 357 -#define tSTDCALL 358 -#define tSTRING 359 -#define tSTRUCT 360 -#define tSWITCH 361 -#define tSWITCHIS 362 -#define tSWITCHTYPE 363 -#define tTRANSMITAS 364 -#define tTYPEDEF 365 -#define tUNION 366 -#define tUNIQUE 367 -#define tUNSIGNED 368 -#define tUUID 369 -#define tV1ENUM 370 -#define tVARARG 371 -#define tVERSION 372 -#define tVOID 373 -#define tWCHAR 374 -#define tWIREMARSHAL 375 -#define tPOINTERTYPE 376 -#define COND 377 -#define CAST 378 -#define PPTR 379 -#define NEG 380 - - - - -/* Copy the first part of user declarations. */ -#line 1 "parser.y" - -/* - * IDL Compiler - * - * Copyright 2002 Ove Kaaven - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "config.h" - -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <assert.h> -#include <ctype.h> -#include <string.h> -#ifdef HAVE_ALLOCA_H -#include <alloca.h> -#endif - -#include "widl.h" -#include "utils.h" -#include "parser.h" -#include "header.h" -#include "typelib.h" - -#if defined(YYBYACC) - /* Berkeley yacc (byacc) doesn't seem to know about these */ - /* Some *BSD supplied versions do define these though */ -# ifndef YYEMPTY -# define YYEMPTY (-1) /* Empty lookahead value of yychar */ -# endif -# ifndef YYLEX -# define YYLEX yylex() -# endif - -#elif defined(YYBISON) - /* Bison was used for original development */ - /* #define YYEMPTY -2 */ - /* #define YYLEX yylex() */ - -#else - /* No yacc we know yet */ -# if !defined(YYEMPTY) || !defined(YYLEX) -# error Yacc version/type unknown. This version needs to be verified for settings of YYEMPTY and YYLEX. -# elif defined(__GNUC__) /* gcc defines the #warning directive */ -# warning Yacc version/type unknown. It defines YYEMPTY and YYLEX, but is not tested - /* #else we just take a chance that it works... */ -# endif -#endif - -static attr_t *make_attr(enum attr_type type); -static attr_t *make_attrv(enum attr_type type, unsigned long val); -static attr_t *make_attrp(enum attr_type type, void *val); -static expr_t *make_expr(enum expr_type type); -static expr_t *make_exprl(enum expr_type type, long val); -static expr_t *make_exprs(enum expr_type type, char *val); -static expr_t *make_exprt(enum expr_type type, typeref_t *tref, expr_t *expr); -static expr_t *make_expr1(enum expr_type type, expr_t *expr); -static expr_t *make_expr2(enum expr_type type, expr_t *exp1, expr_t *exp2); -static expr_t *make_expr3(enum expr_type type, expr_t *expr1, expr_t *expr2, expr_t *expr3); -static type_t *make_type(unsigned char type, type_t *ref); -static typeref_t *make_tref(char *name, type_t *ref); -static typeref_t *uniq_tref(typeref_t *ref); -static type_t *type_ref(typeref_t *ref); -static void set_type(var_t *v, typeref_t *ref, expr_t *arr); -static ifref_t *make_ifref(type_t *iface); -static var_t *make_var(char *name); -static func_t *make_func(var_t *def, var_t *args); -static class_t *make_class(char *name); - -static type_t *reg_type(type_t *type, char *name, int t); -static type_t *reg_types(type_t *type, var_t *names, int t); -static type_t *find_type(char *name, int t); -static type_t *find_type2(char *name, int t); -static type_t *get_type(unsigned char type, char *name, int t); -static type_t *get_typev(unsigned char type, var_t *name, int t); -static int get_struct_type(var_t *fields); - -static var_t *reg_const(var_t *var); -static var_t *find_const(char *name, int f); - -#define tsENUM 1 -#define tsSTRUCT 2 -#define tsUNION 3 - -static type_t std_bool = { "boolean" }; -static type_t std_int = { "int" }; -static type_t std_int64 = { "__int64" }; -static type_t std_uhyper = { "MIDL_uhyper" }; - - - -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 0 -#endif - -#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) -#line 106 "parser.y" -typedef union YYSTYPE { - attr_t *attr; - expr_t *expr; - type_t *type; - typeref_t *tref; - var_t *var; - func_t *func; - ifref_t *ifref; - class_t *clas; - char *str; - UUID *uuid; - unsigned int num; -} YYSTYPE; -/* Line 191 of yacc.c. */ -#line 445 "y.tab.c" -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 -#endif - - - -/* Copy the second part of user declarations. */ - - -/* Line 214 of yacc.c. */ -#line 457 "y.tab.c" - -#if ! defined (yyoverflow) || YYERROR_VERBOSE - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# if YYSTACK_USE_ALLOCA -# define YYSTACK_ALLOC alloca -# else -# ifndef YYSTACK_USE_ALLOCA -# if defined (alloca) || defined (_ALLOCA_H) -# define YYSTACK_ALLOC alloca -# else -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# endif -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's `empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) -# else -# if defined (__STDC__) || defined (__cplusplus) -# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# endif -# define YYSTACK_ALLOC malloc -# define YYSTACK_FREE free -# endif -#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */ - - -#if (! defined (yyoverflow) \ - && (! defined (__cplusplus) \ - || (YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - short yyss; - YYSTYPE yyvs; - }; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ - + YYSTACK_GAP_MAXIMUM) - -/* Copy COUNT objects from FROM to TO. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) -# else -# define YYCOPY(To, From, Count) \ - do \ - { \ - register YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ - while (0) -# endif -# endif - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack, Stack, yysize); \ - Stack = &yyptr->Stack; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (0) - -#endif - -#if defined (__STDC__) || defined (__cplusplus) - typedef signed char yysigned_char; -#else - typedef short yysigned_char; -#endif - -/* YYFINAL -- State number of the termination state. */ -#define YYFINAL 3 -/* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 934 - -/* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 145 -/* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 72 -/* YYNRULES -- Number of rules. */ -#define YYNRULES 249 -/* YYNRULES -- Number of states. */ -#define YYNSTATES 461 - -/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ -#define YYUNDEFTOK 2 -#define YYMAXUTOK 380 - -#define YYTRANSLATE(YYX) \ - ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) - -/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ -static const unsigned char yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 125, 2, - 135, 136, 128, 127, 122, 126, 144, 129, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 141, 134, - 2, 142, 2, 143, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 139, 2, 140, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 137, 124, 138, 130, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - 115, 116, 117, 118, 119, 120, 121, 123, 131, 132, - 133 -}; - -#if YYDEBUG -/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in - YYRHS. */ -static const unsigned short yyprhs[] = -{ - 0, 0, 3, 5, 6, 9, 12, 15, 18, 21, - 24, 25, 28, 31, 34, 37, 40, 41, 45, 48, - 50, 53, 55, 58, 61, 63, 66, 69, 72, 77, - 81, 85, 88, 92, 96, 97, 99, 101, 103, 107, - 109, 114, 118, 125, 131, 132, 136, 140, 142, 146, - 151, 152, 154, 158, 160, 164, 169, 171, 173, 178, - 183, 185, 187, 189, 191, 193, 198, 203, 208, 210, - 215, 220, 225, 227, 229, 234, 239, 244, 249, 254, - 256, 261, 263, 268, 274, 276, 278, 283, 285, 287, - 289, 291, 293, 295, 297, 302, 304, 306, 308, 310, - 312, 314, 316, 318, 320, 325, 327, 329, 334, 339, - 344, 346, 351, 353, 355, 360, 365, 367, 368, 370, - 371, 374, 379, 383, 389, 390, 393, 395, 397, 401, - 405, 407, 413, 414, 416, 418, 420, 422, 428, 432, - 436, 440, 444, 448, 452, 456, 460, 463, 466, 469, - 474, 479, 483, 485, 489, 491, 496, 497, 500, 503, - 507, 510, 512, 517, 525, 526, 528, 529, 531, 533, - 535, 537, 539, 541, 543, 545, 547, 549, 551, 554, - 557, 559, 561, 563, 565, 567, 569, 571, 572, 574, - 576, 579, 582, 585, 588, 590, 592, 595, 598, 601, - 606, 607, 610, 613, 616, 619, 622, 625, 629, 632, - 636, 642, 643, 646, 649, 652, 655, 661, 669, 671, - 674, 677, 680, 683, 686, 691, 694, 697, 699, 701, - 705, 707, 711, 713, 715, 721, 723, 725, 727, 730, - 732, 735, 737, 740, 742, 745, 750, 756, 767, 769 -}; - -/* YYRHS -- A `-1'-separated list of the rules' RHS. */ -static const short yyrhs[] = -{ - 146, 0, -1, 147, -1, -1, 147, 204, -1, 147, - 203, -1, 147, 192, -1, 147, 207, -1, 147, 156, - -1, 147, 150, -1, -1, 148, 204, -1, 148, 203, - -1, 148, 192, -1, 148, 207, -1, 148, 150, -1, - -1, 149, 183, 134, -1, 149, 150, -1, 134, -1, - 170, 134, -1, 151, -1, 174, 134, -1, 179, 134, - -1, 153, -1, 212, 134, -1, 214, 134, -1, 215, - 134, -1, 37, 135, 7, 136, -1, 64, 7, 134, - -1, 152, 148, 9, -1, 74, 3, -1, 164, 154, - 137, -1, 155, 148, 138, -1, -1, 159, -1, 118, - -1, 160, -1, 159, 122, 160, -1, 158, -1, 164, - 213, 209, 161, -1, 213, 209, 161, -1, 164, 213, - 209, 135, 157, 136, -1, 213, 209, 135, 157, 136, - -1, -1, 139, 162, 140, -1, 139, 128, 140, -1, - 175, -1, 162, 122, 176, -1, 162, 140, 139, 176, - -1, -1, 164, -1, 139, 165, 140, -1, 166, -1, - 165, 122, 166, -1, 165, 140, 139, 166, -1, 16, - -1, 18, -1, 24, 135, 186, 136, -1, 26, 135, - 177, 136, -1, 33, -1, 34, -1, 35, -1, 36, - -1, 38, -1, 39, 135, 178, 136, -1, 39, 135, - 7, 136, -1, 41, 135, 7, 136, -1, 43, -1, - 44, 135, 7, 136, -1, 45, 135, 7, 136, -1, - 45, 135, 178, 136, -1, 48, -1, 51, -1, 53, - 135, 178, 136, -1, 54, 135, 7, 136, -1, 55, - 135, 7, 136, -1, 56, 135, 178, 136, -1, 57, - 135, 7, 136, -1, 58, -1, 60, 135, 178, 136, - -1, 61, -1, 62, 135, 186, 136, -1, 63, 135, - 52, 3, 136, -1, 66, -1, 69, -1, 73, 135, - 210, 136, -1, 75, -1, 79, -1, 80, -1, 81, - -1, 82, -1, 83, -1, 84, -1, 85, 135, 211, - 136, -1, 87, -1, 88, -1, 89, -1, 90, -1, - 91, -1, 92, -1, 93, -1, 94, -1, 95, -1, - 99, 135, 210, 136, -1, 102, -1, 104, -1, 107, - 135, 176, 136, -1, 108, 135, 213, 136, -1, 109, - 135, 213, 136, -1, 112, -1, 114, 135, 8, 136, - -1, 115, -1, 116, -1, 117, 135, 216, 136, -1, - 120, 135, 213, 136, -1, 211, -1, -1, 103, -1, - -1, 168, 169, -1, 26, 176, 141, 181, -1, 38, - 141, 181, -1, 32, 213, 186, 142, 178, -1, -1, - 172, 122, -1, 172, -1, 173, -1, 172, 122, 173, - -1, 186, 142, 178, -1, 186, -1, 46, 185, 137, - 171, 138, -1, -1, 176, -1, 5, -1, 6, -1, - 3, -1, 176, 143, 176, 141, 176, -1, 176, 124, - 176, -1, 176, 125, 176, -1, 176, 127, 176, -1, - 176, 126, 176, -1, 176, 128, 176, -1, 176, 129, - 176, -1, 176, 10, 176, -1, 176, 11, 176, -1, - 130, 176, -1, 126, 176, -1, 128, 176, -1, 135, - 213, 136, 176, -1, 100, 135, 213, 136, -1, 135, - 176, 136, -1, 178, -1, 177, 122, 178, -1, 176, - -1, 49, 32, 213, 186, -1, -1, 180, 181, -1, - 182, 134, -1, 163, 215, 134, -1, 164, 134, -1, - 134, -1, 163, 213, 209, 161, -1, 163, 213, 167, - 209, 135, 157, 136, -1, -1, 186, -1, -1, 3, - -1, 4, -1, 3, -1, 4, -1, 16, -1, 60, - -1, 95, -1, 117, -1, 22, -1, 119, -1, 189, - -1, 97, 189, -1, 113, 189, -1, 113, -1, 50, - -1, 98, -1, 42, -1, 20, -1, 47, -1, 52, - -1, -1, 70, -1, 70, -1, 101, 188, -1, 96, - 188, -1, 76, 188, -1, 59, 188, -1, 71, -1, - 28, -1, 29, 3, -1, 29, 4, -1, 164, 190, - -1, 191, 137, 193, 138, -1, -1, 193, 194, -1, - 163, 204, -1, 40, 3, -1, 40, 4, -1, 164, - 195, -1, 86, 141, -1, 197, 182, 134, -1, 77, - 141, -1, 198, 183, 134, -1, 196, 137, 197, 198, - 138, -1, -1, 141, 4, -1, 72, 3, -1, 72, - 4, -1, 164, 201, -1, 202, 200, 137, 149, 138, - -1, 202, 141, 3, 137, 153, 149, 138, -1, 199, - -1, 201, 134, -1, 195, 134, -1, 78, 3, -1, - 78, 4, -1, 164, 205, -1, 206, 137, 149, 138, - -1, 128, 209, -1, 32, 208, -1, 186, -1, 208, - -1, 135, 209, 136, -1, 209, -1, 210, 122, 209, - -1, 93, -1, 112, -1, 105, 185, 137, 180, 138, - -1, 118, -1, 4, -1, 187, -1, 32, 213, -1, - 174, -1, 46, 3, -1, 212, -1, 105, 3, -1, - 215, -1, 111, 3, -1, 110, 163, 213, 210, -1, - 111, 185, 137, 180, 138, -1, 111, 185, 106, 135, - 182, 136, 184, 137, 168, 138, -1, 5, -1, 5, - 144, 5, -1 -}; - -/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ -static const unsigned short yyrline[] = -{ - 0, 228, 228, 231, 232, 233, 234, 235, 236, 237, - 240, 241, 242, 243, 244, 245, 248, 249, 250, 253, - 254, 255, 256, 257, 258, 259, 260, 261, 264, 266, - 269, 272, 274, 276, 279, 280, 283, 286, 287, 288, - 292, 296, 299, 305, 312, 313, 314, 317, 318, 319, - 322, 323, 327, 330, 331, 332, 336, 337, 338, 339, - 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, - 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, - 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, - 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, - 390, 391, 392, 393, 394, 395, 396, 399, 400, 403, - 404, 409, 413, 419, 426, 427, 428, 431, 432, 438, - 443, 449, 471, 472, 475, 476, 477, 478, 479, 480, - 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, - 491, 492, 495, 496, 499, 505, 510, 511, 516, 517, - 518, 519, 522, 526, 536, 537, 540, 541, 542, 545, - 547, 548, 549, 550, 551, 554, 555, 556, 557, 558, - 570, 571, 572, 573, 574, 575, 576, 579, 580, 583, - 584, 585, 586, 587, 588, 589, 592, 593, 596, 603, - 608, 609, 613, 616, 617, 620, 632, 633, 636, 637, - 640, 655, 656, 659, 660, 663, 671, 679, 686, 690, - 691, 694, 695, 698, 703, 709, 710, 713, 714, 715, - 719, 720, 724, 725, 728, 738, 739, 740, 741, 742, - 743, 744, 745, 746, 747, 750, 763, 767, 781, 782 -}; -#endif - -#if YYDEBUG || YYERROR_VERBOSE -/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. - First, the terminals, then, starting at YYNTOKENS, nonterminals. */ -static const char *const yytname[] = -{ - "$end", "error", "$undefined", "aIDENTIFIER", "aKNOWNTYPE", "aNUM", - "aHEXNUM", "aSTRING", "aUUID", "aEOF", "SHL", "SHR", "tAGGREGATABLE", - "tALLOCATE", "tAPPOBJECT", "tARRAYS", "tASYNC", "tASYNCUUID", - "tAUTOHANDLE", "tBINDABLE", "tBOOLEAN", "tBROADCAST", "tBYTE", - "tBYTECOUNT", "tCALLAS", "tCALLBACK", "tCASE", "tCDECL", "tCHAR", - "tCOCLASS", "tCODE", "tCOMMSTATUS", "tCONST", "tCONTEXTHANDLE", - "tCONTEXTHANDLENOSERIALIZE", "tCONTEXTHANDLESERIALIZE", "tCONTROL", - "tCPPQUOTE", "tDEFAULT", "tDEFAULTVALUE", "tDISPINTERFACE", "tDLLNAME", - "tDOUBLE", "tDUAL", "tENDPOINT", "tENTRY", "tENUM", "tERRORSTATUST", - "tEXPLICITHANDLE", "tEXTERN", "tFLOAT", "tHANDLE", "tHANDLET", - "tHELPCONTEXT", "tHELPFILE", "tHELPSTRING", "tHELPSTRINGCONTEXT", - "tHELPSTRINGDLL", "tHIDDEN", "tHYPER", "tID", "tIDEMPOTENT", "tIIDIS", - "tIMPLICITHANDLE", "tIMPORT", "tIMPORTLIB", "tIN", "tINCLUDE", - "tINLINE", "tINPUTSYNC", "tINT", "tINT64", "tINTERFACE", "tLENGTHIS", - "tLIBRARY", "tLOCAL", "tLONG", "tMETHODS", "tMODULE", "tNONCREATABLE", - "tOBJECT", "tODL", "tOLEAUTOMATION", "tOPTIONAL", "tOUT", - "tPOINTERDEFAULT", "tPROPERTIES", "tPROPGET", "tPROPPUT", "tPROPPUTREF", - "tPTR", "tPUBLIC", "tREADONLY", "tREF", "tRESTRICTED", "tRETVAL", - "tSHORT", "tSIGNED", "tSINGLE", "tSIZEIS", "tSIZEOF", "tSMALL", - "tSOURCE", "tSTDCALL", "tSTRING", "tSTRUCT", "tSWITCH", "tSWITCHIS", - "tSWITCHTYPE", "tTRANSMITAS", "tTYPEDEF", "tUNION", "tUNIQUE", - "tUNSIGNED", "tUUID", "tV1ENUM", "tVARARG", "tVERSION", "tVOID", - "tWCHAR", "tWIREMARSHAL", "tPOINTERTYPE", "','", "COND", "'|'", "'&'", - "'-'", "'+'", "'*'", "'/'", "'~'", "CAST", "PPTR", "NEG", "';'", "'('", - "')'", "'{'", "'}'", "'['", "']'", "':'", "'='", "'?'", "'.'", - "$accept", "input", "gbl_statements", "imp_statements", - "int_statements", "statement", "cppquote", "import_start", "import", - "libraryhdr", "library_start", "librarydef", "m_args", "no_args", - "args", "arg", "array", "array_list", "m_attributes", "attributes", - "attrib_list", "attribute", "callconv", "cases", "case", "constdef", - "enums", "enum_list", "enum", "enumdef", "m_expr", "expr", - "expr_list_const", "expr_const", "externdef", "fields", "field", - "s_field", "funcdef", "m_ident", "t_ident", "ident", "base_type", - "m_int", "int_std", "coclass", "coclasshdr", "coclassdef", - "coclass_ints", "coclass_int", "dispinterface", "dispinterfacehdr", - "dispint_props", "dispint_meths", "dispinterfacedef", "inherit", - "interface", "interfacehdr", "interfacedef", "interfacedec", "module", - "modulehdr", "moduledef", "p_ident", "pident", "pident_list", - "pointer_type", "structdef", "type", "typedef", "uniondef", "version", 0 -}; -#endif - -# ifdef YYPRINT -/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to - token YYLEX-NUM. */ -static const unsigned short yytoknum[] = -{ - 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, - 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, - 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, - 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, - 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, - 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, - 375, 376, 44, 377, 124, 38, 45, 43, 42, 47, - 126, 378, 379, 380, 59, 40, 41, 123, 125, 91, - 93, 58, 61, 63, 46 -}; -# endif - -/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const unsigned char yyr1[] = -{ - 0, 145, 146, 147, 147, 147, 147, 147, 147, 147, - 148, 148, 148, 148, 148, 148, 149, 149, 149, 150, - 150, 150, 150, 150, 150, 150, 150, 150, 151, 152, - 153, 154, 155, 156, 157, 157, 158, 159, 159, 159, - 160, 160, 160, 160, 161, 161, 161, 162, 162, 162, - 163, 163, 164, 165, 165, 165, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 167, 167, 168, - 168, 169, 169, 170, 171, 171, 171, 172, 172, 173, - 173, 174, 175, 175, 176, 176, 176, 176, 176, 176, - 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, - 176, 176, 177, 177, 178, 179, 180, 180, 181, 181, - 181, 181, 182, 183, 184, 184, 185, 185, 185, 186, - 186, 186, 186, 186, 186, 187, 187, 187, 187, 187, - 187, 187, 187, 187, 187, 187, 187, 188, 188, 189, - 189, 189, 189, 189, 189, 189, 190, 190, 191, 192, - 193, 193, 194, 195, 195, 196, 197, 197, 198, 198, - 199, 200, 200, 201, 201, 202, 203, 203, 203, 204, - 204, 205, 205, 206, 207, 208, 208, 209, 209, 209, - 210, 210, 211, 211, 212, 213, 213, 213, 213, 213, - 213, 213, 213, 213, 213, 214, 215, 215, 216, 216 -}; - -/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ -static const unsigned char yyr2[] = -{ - 0, 2, 1, 0, 2, 2, 2, 2, 2, 2, - 0, 2, 2, 2, 2, 2, 0, 3, 2, 1, - 2, 1, 2, 2, 1, 2, 2, 2, 4, 3, - 3, 2, 3, 3, 0, 1, 1, 1, 3, 1, - 4, 3, 6, 5, 0, 3, 3, 1, 3, 4, - 0, 1, 3, 1, 3, 4, 1, 1, 4, 4, - 1, 1, 1, 1, 1, 4, 4, 4, 1, 4, - 4, 4, 1, 1, 4, 4, 4, 4, 4, 1, - 4, 1, 4, 5, 1, 1, 4, 1, 1, 1, - 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 4, 1, 1, 4, 4, 4, - 1, 4, 1, 1, 4, 4, 1, 0, 1, 0, - 2, 4, 3, 5, 0, 2, 1, 1, 3, 3, - 1, 5, 0, 1, 1, 1, 1, 5, 3, 3, - 3, 3, 3, 3, 3, 3, 2, 2, 2, 4, - 4, 3, 1, 3, 1, 4, 0, 2, 2, 3, - 2, 1, 4, 7, 0, 1, 0, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, - 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, - 2, 2, 2, 2, 1, 1, 2, 2, 2, 4, - 0, 2, 2, 2, 2, 2, 2, 3, 2, 3, - 5, 0, 2, 2, 2, 2, 5, 7, 1, 2, - 2, 2, 2, 2, 4, 2, 2, 1, 1, 3, - 1, 3, 1, 1, 5, 1, 1, 1, 2, 1, - 2, 1, 2, 1, 2, 4, 5, 10, 1, 3 -}; - -/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state - STATE-NUM when YYTABLE doesn't specify something else to do. Zero - means the default is an error. */ -static const unsigned char yydefact[] = -{ - 3, 0, 2, 1, 0, 0, 0, 166, 0, 0, - 0, 166, 50, 166, 19, 0, 9, 21, 10, 24, - 10, 8, 0, 0, 0, 0, 0, 6, 0, 0, - 218, 0, 211, 5, 4, 0, 7, 0, 0, 0, - 236, 184, 175, 195, 0, 183, 166, 185, 181, 186, - 187, 189, 194, 187, 187, 0, 182, 187, 166, 166, - 180, 235, 176, 239, 237, 177, 241, 0, 243, 0, - 203, 204, 167, 168, 0, 0, 0, 213, 214, 0, - 0, 51, 0, 56, 57, 0, 0, 60, 61, 62, - 63, 64, 0, 0, 68, 0, 0, 72, 73, 0, - 0, 0, 0, 0, 79, 0, 81, 0, 0, 84, - 85, 0, 87, 88, 89, 90, 91, 92, 93, 0, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 0, - 105, 106, 0, 0, 0, 110, 0, 112, 113, 0, - 0, 0, 53, 116, 0, 0, 0, 0, 0, 0, - 198, 205, 215, 223, 20, 22, 23, 200, 220, 0, - 219, 0, 0, 16, 25, 26, 27, 238, 240, 188, - 193, 192, 191, 178, 190, 242, 244, 179, 169, 170, - 171, 172, 173, 174, 0, 0, 124, 0, 29, 156, - 0, 0, 156, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 52, 30, 15, - 0, 13, 12, 11, 14, 33, 196, 197, 31, 221, - 222, 32, 50, 0, 50, 0, 212, 16, 50, 0, - 28, 0, 126, 127, 130, 155, 50, 0, 0, 0, - 227, 228, 230, 245, 50, 50, 0, 136, 134, 135, - 0, 0, 0, 0, 0, 154, 0, 152, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 232, 233, 0, 0, 0, 0, 0, - 0, 248, 0, 0, 54, 0, 199, 0, 201, 206, - 0, 0, 0, 50, 0, 50, 224, 18, 0, 0, - 123, 131, 125, 0, 161, 234, 0, 51, 157, 0, - 226, 225, 0, 0, 0, 246, 58, 0, 147, 148, - 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 59, 66, 65, 67, 69, 70, 71, - 74, 75, 76, 77, 78, 80, 82, 0, 86, 94, - 104, 107, 108, 109, 111, 0, 114, 115, 55, 202, - 208, 0, 207, 210, 0, 16, 216, 117, 17, 128, - 129, 243, 160, 158, 229, 231, 164, 0, 151, 0, - 144, 145, 138, 139, 141, 140, 142, 143, 0, 153, - 83, 249, 44, 209, 50, 118, 0, 159, 0, 165, - 150, 149, 0, 132, 162, 217, 0, 119, 137, 0, - 0, 47, 133, 34, 0, 46, 0, 45, 235, 0, - 39, 35, 37, 0, 0, 0, 0, 247, 120, 48, - 0, 163, 0, 0, 44, 0, 50, 49, 38, 44, - 34, 41, 50, 122, 34, 40, 0, 121, 0, 43, - 42 -}; - -/* YYDEFGOTO[NTERM-NUM]. */ -static const short yydefgoto[] = -{ - -1, 1, 2, 144, 238, 307, 17, 18, 19, 149, - 20, 21, 429, 430, 431, 432, 414, 420, 308, 81, - 141, 142, 406, 424, 438, 23, 241, 242, 243, 63, - 421, 265, 266, 267, 25, 246, 318, 319, 309, 408, - 74, 250, 64, 170, 65, 150, 26, 221, 232, 298, - 28, 29, 234, 303, 30, 162, 31, 32, 222, 223, - 153, 35, 224, 251, 252, 253, 143, 66, 434, 38, - 68, 292 -}; - -/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -#define YYPACT_NINF -395 -static const short yypact[] = -{ - -395, 59, 631, -395, 603, -65, 119, 134, 46, 88, - 136, 134, -34, 134, -395, 814, -395, -395, -395, -395, - -395, -395, 16, -27, 10, 34, 35, -395, 63, 38, - -395, 68, 69, -395, -395, 76, -395, 86, 93, 98, - -395, -395, -395, -395, 603, -395, 176, -395, -395, -395, - 62, -395, -395, 62, 62, -5, -395, 62, 185, 187, - -5, -395, -395, -395, -395, -395, -395, 13, -395, 127, - -395, -395, -395, -395, 87, 603, 102, -395, -395, 101, - 603, -395, -82, -395, -395, 15, 104, -395, -395, -395, - -395, -395, 116, 120, -395, 121, 123, -395, -395, 124, - 125, 128, 129, 130, -395, 131, -395, 132, 135, -395, - -395, 137, -395, -395, -395, -395, -395, -395, -395, 138, - -395, -395, -395, -395, -395, -395, -395, -395, -395, 139, - -395, -395, 140, 141, 142, -395, 143, -395, -395, 144, - 145, -79, -395, -395, 504, 620, 189, 251, 192, 146, - -395, -395, -395, -395, -395, -395, -395, -395, -395, 195, - -395, 196, 162, -395, -395, -395, -395, -395, 164, -395, - -395, -395, -395, -395, -395, 164, -70, -395, -395, -395, - -395, -395, -395, -395, 158, 166, 13, 13, -395, -395, - 485, 173, -395, 13, 470, 279, 264, 304, 458, 470, - 305, 308, 470, 309, 470, 13, 265, 485, -55, 485, - 470, 603, 603, 312, 317, 603, 814, 184, -395, -395, - 20, -395, -395, -395, -395, -395, -395, -395, -395, -395, - -395, -395, 66, 188, -57, 191, -395, -395, 656, 470, - -395, 194, 203, -395, 200, -395, -25, -22, 485, 485, - -395, -395, -395, 208, -34, -19, 197, -395, -395, -395, - 199, 470, 470, 470, 464, 239, -85, -395, 207, 212, - 214, 217, 219, 220, 221, 223, 224, 225, 226, 235, - 236, 341, -83, -395, -395, 237, -72, 58, 238, 240, - 241, 234, 244, 245, -395, 814, -395, 8, -395, -395, - 206, 603, 254, 92, 325, 686, -395, -395, 603, 256, - -395, -395, 13, 470, -395, -395, 603, 257, -395, 259, - -395, -395, 262, 485, 263, -395, -395, 603, 249, 249, - 249, 90, 266, 470, 470, 470, 470, 470, 470, 470, - 470, 470, 470, -395, -395, -395, -395, -395, -395, -395, - -395, -395, -395, -395, -395, -395, -395, 267, -395, -395, - -395, -395, -395, -395, -395, 389, -395, -395, -395, -395, - -395, 485, -395, -395, 281, -395, -395, 313, -395, -395, - -395, 285, -395, -395, -395, -395, 13, 284, -395, 470, - 249, 249, 258, 167, 100, 100, 23, 23, 163, -395, - -395, -395, 283, -395, 707, -395, 485, -395, 286, -395, - -395, 249, 470, 516, -395, -395, 289, -395, 239, 41, - -59, -395, 239, 299, -7, -395, 470, 287, -33, 292, - -395, 303, -395, 603, 485, 470, 290, -395, -395, 239, - 470, -395, 407, 485, -23, 211, -37, 239, -395, -11, - 299, -395, -37, -395, 299, -395, 296, -395, 297, -395, - -395 -}; - -/* YYPGOTO[NTERM-NUM]. */ -static const short yypgoto[] = -{ - -395, -395, -395, 414, -211, 7, -395, -395, 147, -395, - -395, -395, -325, -395, -395, -6, -370, -395, -9, -2, - -395, -202, -395, -395, -395, -395, -395, -395, 133, 4, - -395, -178, -395, -177, -395, 250, -394, -219, 152, -395, - 17, -60, -395, 64, 44, -395, -395, 439, -395, -395, - -17, -395, -395, -395, -395, -395, -14, -395, 444, 0, - -395, -395, 445, 209, -236, -167, 252, 9, -3, -395, - 2, -395 -}; - -/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule which - number is the opposite. If zero, do what YYDEFACT says. - If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -168 -static const short yytable[] = -{ - 22, 67, 34, 80, 39, 151, 24, 184, 152, 16, - 247, 37, 321, 322, 294, 302, 178, 179, 269, 435, - 300, 273, 274, 43, 191, 277, 305, 279, 79, 180, - 82, 436, 287, 333, 334, 324, -167, 342, 283, 323, - 282, 167, 286, 216, 257, 146, 258, 259, 6, 146, - 323, 343, 453, 358, 50, 192, 6, 284, 457, 3, - 6, 217, 310, 426, 360, 51, 52, -167, 333, 334, - 69, 53, 187, 181, 451, 79, 82, 190, 75, 455, - 10, 427, 15, 328, 329, 330, 331, 385, 10, -36, - 147, 54, 10, 368, 148, 76, 57, 314, 148, 173, - 333, 334, 15, -36, 177, 15, 248, 154, 182, 314, - 333, 334, 450, 315, 15, 314, 413, 171, 172, 325, - 15, 174, 70, 71, 454, 456, 244, 245, 413, 458, - 183, 437, 169, 256, 185, 402, 380, 72, 73, 77, - 78, 260, 220, 220, 155, 280, 39, 39, 24, 24, - 193, 219, 219, 37, 37, 390, 391, 392, 393, 394, - 395, 396, 397, 398, 404, 399, 341, 261, 156, 262, - 416, 263, 157, 333, 334, 159, 264, 333, 334, 168, - 73, 425, 335, 336, 337, 338, 339, 340, 175, 73, - 176, 73, 226, 227, 361, 229, 230, 158, 444, 235, - 236, 341, 160, 151, 296, 15, 152, 449, 288, 289, - 161, 411, 293, 163, 335, 336, 337, 338, 339, 340, - 164, 333, 334, 297, 186, 301, 388, 165, 339, 340, - 373, 15, 166, 341, 418, 422, 188, 316, 189, 194, - 39, 329, 24, 341, 317, 301, 316, 37, 439, 333, - 334, 195, 244, 317, 228, 196, 197, 445, 198, 199, - 200, 332, 447, 201, 202, 203, 204, 205, 333, 334, - 206, 270, 207, 208, 209, 210, 211, 212, 213, 214, - 215, 233, 257, 231, 258, 259, 268, 335, 336, 337, - 338, 339, 340, 337, 338, 339, 340, 369, 371, 237, - 239, -167, 240, 40, 412, 377, 341, 39, 254, 24, - 341, 271, 275, 371, 37, 276, 278, 281, 381, 41, - 290, 42, 291, 295, 387, 312, 409, 43, 304, 299, - 323, 44, 311, 326, 327, 335, 336, 337, 338, 339, - 340, 45, 313, 344, 357, 46, 47, 370, 345, 48, - 346, 49, 452, 347, 341, 348, 349, 350, 50, 351, - 352, 353, 354, 335, 336, 337, 338, 339, 340, 51, - 52, 355, 356, 359, 362, 53, 363, 364, 365, 260, - 366, 367, 341, 336, 337, 338, 339, 340, 372, 9, - 378, 382, 341, 383, 401, 54, 55, 56, 384, 386, - 57, 341, 389, 400, 58, 261, 39, 262, 24, 263, - 59, 40, 60, 37, 264, 403, 405, 428, 62, 407, - 410, 433, 413, 417, 423, 442, 440, 41, 441, 42, - 443, 446, 459, 460, 145, 43, 448, 316, 15, 44, - 433, 27, 255, 316, 317, 379, 33, 36, 433, 45, - 317, 375, 433, 46, 47, 374, 320, 48, 0, 49, - 285, 257, 0, 258, 259, 272, 50, 257, 40, 258, - 259, 0, 0, 257, 0, 258, 259, 51, 52, 0, - 0, 0, 0, 53, 41, 0, 42, 0, 178, 179, - 0, 0, 43, 0, 0, 0, 44, 0, 0, 0, - 0, 180, 0, 54, 55, 56, 45, 0, 57, 0, - 46, 47, 58, 218, 48, 0, 49, 247, 59, 257, - 60, 258, 259, 50, 0, 61, 62, 0, 0, 0, - 0, 0, 0, 0, 51, 52, 4, 0, 0, 0, - 53, 5, 0, 0, 6, 181, 15, 0, 0, 0, - 7, 0, 0, 8, 0, 0, 0, 0, 260, 0, - 54, 55, 56, 0, 260, 57, 0, 0, 9, 58, - 260, 0, 0, 0, 0, 59, 10, 60, 0, 0, - 182, 0, 61, 62, 261, 0, 262, 0, 263, 0, - 261, 0, 262, 264, 263, 0, 261, 0, 262, 264, - 263, 0, 183, 0, 0, 264, 0, 40, 0, 11, - 0, 0, 0, 248, 12, 13, 260, 0, 0, 0, - 249, 0, 0, 41, 0, 42, 0, 0, 0, 0, - 0, 43, 0, 0, 0, 44, 0, 0, 14, 0, - 0, 0, 261, 15, 419, 45, 263, 0, 0, 46, - 47, 264, 4, 48, 0, 49, 0, 5, 0, 0, - 6, 0, 50, 4, 0, 0, 7, 0, 5, 8, - 0, 6, 0, 51, 52, 0, 0, 7, 0, 53, - 8, 0, 0, 0, 9, 0, 0, 0, 4, 0, - 0, 0, 10, 5, 0, 9, 0, 0, 0, 54, - 55, 56, 7, 10, 57, 8, 0, 0, 58, 0, - 0, 0, 0, 0, 59, 0, 60, 0, 4, 0, - 9, 61, 62, 5, 0, 11, 0, 0, 0, 0, - 12, 13, 7, 0, 0, 8, 11, 0, 0, 4, - 0, 12, 13, 0, 5, 0, 0, 0, 0, 0, - 9, 0, 0, 7, 14, 0, 8, 0, 225, 15, - 0, 11, 0, 0, 0, 14, 12, 13, 0, 0, - 15, 9, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 14, 11, 0, 0, 306, 15, 12, 13, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 11, 0, 0, 0, 0, 12, 13, 0, - 14, 0, 0, 0, 376, 15, 0, 0, 0, 0, - 83, 0, 84, 0, 0, 0, 0, 0, 85, 0, - 86, 14, 0, 0, 0, 415, 15, 87, 88, 89, - 90, 0, 91, 92, 0, 93, 0, 94, 95, 96, - 0, 0, 97, 0, 0, 98, 0, 99, 100, 101, - 102, 103, 104, 0, 105, 106, 107, 108, 0, 0, - 109, 0, 0, 110, 0, 0, 0, 111, 0, 112, - 0, 0, 0, 113, 114, 115, 116, 117, 118, 119, - 0, 120, 121, 122, 123, 124, 125, 126, 127, 128, - 0, 0, 0, 129, 0, 0, 130, 0, 131, 0, - 0, 132, 133, 134, 0, 0, 135, 0, 136, 137, - 138, 139, 0, 0, 140 -}; - -static const short yycheck[] = -{ - 2, 4, 2, 12, 2, 22, 2, 67, 22, 2, - 32, 2, 248, 249, 216, 234, 3, 4, 195, 26, - 77, 198, 199, 28, 106, 202, 237, 204, 11, 16, - 13, 38, 210, 10, 11, 254, 106, 122, 93, 122, - 207, 44, 209, 122, 3, 29, 5, 6, 40, 29, - 122, 136, 446, 136, 59, 137, 40, 112, 452, 0, - 40, 140, 239, 122, 136, 70, 71, 137, 10, 11, - 135, 76, 75, 60, 444, 58, 59, 80, 32, 449, - 72, 140, 139, 261, 262, 263, 264, 323, 72, 122, - 74, 96, 72, 295, 78, 7, 101, 134, 78, 55, - 10, 11, 139, 136, 60, 139, 128, 134, 95, 134, - 10, 11, 135, 138, 139, 134, 139, 53, 54, 138, - 139, 57, 3, 4, 135, 450, 186, 187, 139, 454, - 117, 138, 70, 193, 7, 371, 313, 3, 4, 3, - 4, 100, 144, 145, 134, 205, 144, 145, 144, 145, - 135, 144, 145, 144, 145, 333, 334, 335, 336, 337, - 338, 339, 340, 341, 375, 342, 143, 126, 134, 128, - 406, 130, 137, 10, 11, 137, 135, 10, 11, 3, - 4, 140, 124, 125, 126, 127, 128, 129, 3, 4, - 3, 4, 3, 4, 136, 3, 4, 134, 434, 3, - 4, 143, 134, 220, 138, 139, 220, 443, 211, 212, - 141, 389, 215, 137, 124, 125, 126, 127, 128, 129, - 134, 10, 11, 232, 137, 234, 136, 134, 128, 129, - 138, 139, 134, 143, 412, 413, 134, 246, 137, 135, - 238, 419, 238, 143, 246, 254, 255, 238, 426, 10, - 11, 135, 312, 255, 3, 135, 135, 435, 135, 135, - 135, 264, 440, 135, 135, 135, 135, 135, 10, 11, - 135, 7, 135, 135, 135, 135, 135, 135, 135, 135, - 135, 86, 3, 137, 5, 6, 7, 124, 125, 126, - 127, 128, 129, 126, 127, 128, 129, 297, 301, 137, - 142, 137, 136, 4, 141, 308, 143, 305, 135, 305, - 143, 7, 7, 316, 305, 7, 7, 52, 316, 20, - 8, 22, 5, 139, 327, 122, 386, 28, 137, 141, - 122, 32, 138, 136, 135, 124, 125, 126, 127, 128, - 129, 42, 142, 136, 3, 46, 47, 141, 136, 50, - 136, 52, 141, 136, 143, 136, 136, 136, 59, 136, - 136, 136, 136, 124, 125, 126, 127, 128, 129, 70, - 71, 136, 136, 136, 136, 76, 136, 136, 144, 100, - 136, 136, 143, 125, 126, 127, 128, 129, 134, 64, - 134, 134, 143, 134, 5, 96, 97, 98, 136, 136, - 101, 143, 136, 136, 105, 126, 404, 128, 404, 130, - 111, 4, 113, 404, 135, 134, 103, 118, 119, 134, - 136, 423, 139, 137, 135, 122, 139, 20, 136, 22, - 433, 141, 136, 136, 20, 28, 442, 446, 139, 32, - 442, 2, 192, 452, 446, 312, 2, 2, 450, 42, - 452, 304, 454, 46, 47, 303, 247, 50, -1, 52, - 208, 3, -1, 5, 6, 7, 59, 3, 4, 5, - 6, -1, -1, 3, -1, 5, 6, 70, 71, -1, - -1, -1, -1, 76, 20, -1, 22, -1, 3, 4, - -1, -1, 28, -1, -1, -1, 32, -1, -1, -1, - -1, 16, -1, 96, 97, 98, 42, -1, 101, -1, - 46, 47, 105, 9, 50, -1, 52, 32, 111, 3, - 113, 5, 6, 59, -1, 118, 119, -1, -1, -1, - -1, -1, -1, -1, 70, 71, 32, -1, -1, -1, - 76, 37, -1, -1, 40, 60, 139, -1, -1, -1, - 46, -1, -1, 49, -1, -1, -1, -1, 100, -1, - 96, 97, 98, -1, 100, 101, -1, -1, 64, 105, - 100, -1, -1, -1, -1, 111, 72, 113, -1, -1, - 95, -1, 118, 119, 126, -1, 128, -1, 130, -1, - 126, -1, 128, 135, 130, -1, 126, -1, 128, 135, - 130, -1, 117, -1, -1, 135, -1, 4, -1, 105, - -1, -1, -1, 128, 110, 111, 100, -1, -1, -1, - 135, -1, -1, 20, -1, 22, -1, -1, -1, -1, - -1, 28, -1, -1, -1, 32, -1, -1, 134, -1, - -1, -1, 126, 139, 128, 42, 130, -1, -1, 46, - 47, 135, 32, 50, -1, 52, -1, 37, -1, -1, - 40, -1, 59, 32, -1, -1, 46, -1, 37, 49, - -1, 40, -1, 70, 71, -1, -1, 46, -1, 76, - 49, -1, -1, -1, 64, -1, -1, -1, 32, -1, - -1, -1, 72, 37, -1, 64, -1, -1, -1, 96, - 97, 98, 46, 72, 101, 49, -1, -1, 105, -1, - -1, -1, -1, -1, 111, -1, 113, -1, 32, -1, - 64, 118, 119, 37, -1, 105, -1, -1, -1, -1, - 110, 111, 46, -1, -1, 49, 105, -1, -1, 32, - -1, 110, 111, -1, 37, -1, -1, -1, -1, -1, - 64, -1, -1, 46, 134, -1, 49, -1, 138, 139, - -1, 105, -1, -1, -1, 134, 110, 111, -1, -1, - 139, 64, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 134, 105, -1, -1, 138, 139, 110, 111, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 105, -1, -1, -1, -1, 110, 111, -1, - 134, -1, -1, -1, 138, 139, -1, -1, -1, -1, - 16, -1, 18, -1, -1, -1, -1, -1, 24, -1, - 26, 134, -1, -1, -1, 138, 139, 33, 34, 35, - 36, -1, 38, 39, -1, 41, -1, 43, 44, 45, - -1, -1, 48, -1, -1, 51, -1, 53, 54, 55, - 56, 57, 58, -1, 60, 61, 62, 63, -1, -1, - 66, -1, -1, 69, -1, -1, -1, 73, -1, 75, - -1, -1, -1, 79, 80, 81, 82, 83, 84, 85, - -1, 87, 88, 89, 90, 91, 92, 93, 94, 95, - -1, -1, -1, 99, -1, -1, 102, -1, 104, -1, - -1, 107, 108, 109, -1, -1, 112, -1, 114, 115, - 116, 117, -1, -1, 120 -}; - -/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ -static const unsigned char yystos[] = -{ - 0, 146, 147, 0, 32, 37, 40, 46, 49, 64, - 72, 105, 110, 111, 134, 139, 150, 151, 152, 153, - 155, 156, 164, 170, 174, 179, 191, 192, 195, 196, - 199, 201, 202, 203, 204, 206, 207, 212, 214, 215, - 4, 20, 22, 28, 32, 42, 46, 47, 50, 52, - 59, 70, 71, 76, 96, 97, 98, 101, 105, 111, - 113, 118, 119, 174, 187, 189, 212, 213, 215, 135, - 3, 4, 3, 4, 185, 32, 7, 3, 4, 185, - 163, 164, 185, 16, 18, 24, 26, 33, 34, 35, - 36, 38, 39, 41, 43, 44, 45, 48, 51, 53, - 54, 55, 56, 57, 58, 60, 61, 62, 63, 66, - 69, 73, 75, 79, 80, 81, 82, 83, 84, 85, - 87, 88, 89, 90, 91, 92, 93, 94, 95, 99, - 102, 104, 107, 108, 109, 112, 114, 115, 116, 117, - 120, 165, 166, 211, 148, 148, 29, 74, 78, 154, - 190, 195, 201, 205, 134, 134, 134, 137, 134, 137, - 134, 141, 200, 137, 134, 134, 134, 213, 3, 70, - 188, 188, 188, 189, 188, 3, 3, 189, 3, 4, - 16, 60, 95, 117, 186, 7, 137, 213, 134, 137, - 213, 106, 137, 135, 135, 135, 135, 135, 135, 135, - 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, - 135, 135, 135, 135, 135, 135, 122, 140, 9, 150, - 164, 192, 203, 204, 207, 138, 3, 4, 3, 3, - 4, 137, 193, 86, 197, 3, 4, 137, 149, 142, - 136, 171, 172, 173, 186, 186, 180, 32, 128, 135, - 186, 208, 209, 210, 135, 180, 186, 3, 5, 6, - 100, 126, 128, 130, 135, 176, 177, 178, 7, 178, - 7, 7, 7, 178, 178, 7, 7, 178, 7, 178, - 186, 52, 210, 93, 112, 211, 210, 176, 213, 213, - 8, 5, 216, 213, 166, 139, 138, 163, 194, 141, - 77, 163, 182, 198, 137, 149, 138, 150, 163, 183, - 178, 138, 122, 142, 134, 138, 163, 164, 181, 182, - 208, 209, 209, 122, 182, 138, 136, 135, 176, 176, - 176, 176, 213, 10, 11, 124, 125, 126, 127, 128, - 129, 143, 122, 136, 136, 136, 136, 136, 136, 136, - 136, 136, 136, 136, 136, 136, 136, 3, 136, 136, - 136, 136, 136, 136, 136, 144, 136, 136, 166, 204, - 141, 213, 134, 138, 183, 153, 138, 213, 134, 173, - 178, 215, 134, 134, 136, 209, 136, 213, 136, 136, - 176, 176, 176, 176, 176, 176, 176, 176, 176, 178, - 136, 5, 209, 134, 149, 103, 167, 134, 184, 186, - 136, 176, 141, 139, 161, 138, 209, 137, 176, 128, - 162, 175, 176, 135, 168, 140, 122, 140, 118, 157, - 158, 159, 160, 164, 213, 26, 38, 138, 169, 176, - 139, 136, 122, 213, 209, 176, 141, 176, 160, 209, - 135, 161, 141, 181, 135, 161, 157, 181, 157, 136, - 136 -}; - -#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) -# define YYSIZE_T __SIZE_TYPE__ -#endif -#if ! defined (YYSIZE_T) && defined (size_t) -# define YYSIZE_T size_t -#endif -#if ! defined (YYSIZE_T) -# if defined (__STDC__) || defined (__cplusplus) -# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# endif -#endif -#if ! defined (YYSIZE_T) -# define YYSIZE_T unsigned int -#endif - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY (-2) -#define YYEOF 0 - -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrlab1 - -/* Like YYERROR except do call yyerror. This remains here temporarily - to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. */ - -#define YYFAIL goto yyerrlab - -#define YYRECOVERING() (!!yyerrstatus) - -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - yytoken = YYTRANSLATE (yychar); \ - YYPOPSTACK; \ - goto yybackup; \ - } \ - else \ - { \ - yyerror ("syntax error: cannot back up");\ - YYERROR; \ - } \ -while (0) - -#define YYTERROR 1 -#define YYERRCODE 256 - -/* YYLLOC_DEFAULT -- Compute the default location (before the actions - are run). */ - -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - Current.first_line = Rhs[1].first_line; \ - Current.first_column = Rhs[1].first_column; \ - Current.last_line = Rhs[N].last_line; \ - Current.last_column = Rhs[N].last_column; -#endif - -/* YYLEX -- calling `yylex' with the right arguments. */ - -#ifdef YYLEX_PARAM -# define YYLEX yylex (YYLEX_PARAM) -#else -# define YYLEX yylex () -#endif - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (0) - -# define YYDSYMPRINT(Args) \ -do { \ - if (yydebug) \ - yysymprint Args; \ -} while (0) - -# define YYDSYMPRINTF(Title, Token, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yysymprint (stderr, \ - Token, Value); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (0) - -/*------------------------------------------------------------------. -| yy_stack_print -- Print the state stack from its BOTTOM up to its | -| TOP (cinluded). | -`------------------------------------------------------------------*/ - -#if defined (__STDC__) || defined (__cplusplus) -static void -yy_stack_print (short *bottom, short *top) -#else -static void -yy_stack_print (bottom, top) - short *bottom; - short *top; -#endif -{ - YYFPRINTF (stderr, "Stack now"); - for (/* Nothing. */; bottom <= top; ++bottom) - YYFPRINTF (stderr, " %d", *bottom); - YYFPRINTF (stderr, "\n"); -} - -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (0) - - -/*------------------------------------------------. -| Report that the YYRULE is going to be reduced. | -`------------------------------------------------*/ - -#if defined (__STDC__) || defined (__cplusplus) -static void -yy_reduce_print (int yyrule) -#else -static void -yy_reduce_print (yyrule) - int yyrule; -#endif -{ - int yyi; - unsigned int yylineno = yyrline[yyrule]; - YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ", - yyrule - 1, yylineno); - /* Print the symbols being reduced, and their result. */ - for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++) - YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]); - YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]); -} - -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (Rule); \ -} while (0) - -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -# define YYDSYMPRINT(Args) -# define YYDSYMPRINTF(Title, Token, Value, Location) -# define YY_STACK_PRINT(Bottom, Top) -# define YY_REDUCE_PRINT(Rule) -#endif /* !YYDEBUG */ - - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#if YYMAXDEPTH == 0 -# undef YYMAXDEPTH -#endif - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - - - -#if YYERROR_VERBOSE - -# ifndef yystrlen -# if defined (__GLIBC__) && defined (_STRING_H) -# define yystrlen strlen -# else -/* Return the length of YYSTR. */ -static YYSIZE_T -# if defined (__STDC__) || defined (__cplusplus) -yystrlen (const char *yystr) -# else -yystrlen (yystr) - const char *yystr; -# endif -{ - register const char *yys = yystr; - - while (*yys++ != '\0') - continue; - - return yys - yystr - 1; -} -# endif -# endif - -# ifndef yystpcpy -# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) -# define yystpcpy stpcpy -# else -/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in - YYDEST. */ -static char * -# if defined (__STDC__) || defined (__cplusplus) -yystpcpy (char *yydest, const char *yysrc) -# else -yystpcpy (yydest, yysrc) - char *yydest; - const char *yysrc; -# endif -{ - register char *yyd = yydest; - register const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif - -#endif /* !YYERROR_VERBOSE */ - - - -#if YYDEBUG -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -#if defined (__STDC__) || defined (__cplusplus) -static void -yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep) -#else -static void -yysymprint (yyoutput, yytype, yyvaluep) - FILE *yyoutput; - int yytype; - YYSTYPE *yyvaluep; -#endif -{ - /* Pacify ``unused variable'' warnings. */ - (void) yyvaluep; - - if (yytype < YYNTOKENS) - { - YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); -# ifdef YYPRINT - YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); -# endif - } - else - YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); - - switch (yytype) - { - default: - break; - } - YYFPRINTF (yyoutput, ")"); -} - -#endif /* ! YYDEBUG */ -/*-----------------------------------------------. -| Release the memory associated to this symbol. | -`-----------------------------------------------*/ - -#if defined (__STDC__) || defined (__cplusplus) -static void -yydestruct (int yytype, YYSTYPE *yyvaluep) -#else -static void -yydestruct (yytype, yyvaluep) - int yytype; - YYSTYPE *yyvaluep; -#endif -{ - /* Pacify ``unused variable'' warnings. */ - (void) yyvaluep; - - switch (yytype) - { - - default: - break; - } -} - - -/* Prevent warnings from -Wmissing-prototypes. */ - -#ifdef YYPARSE_PARAM -# if defined (__STDC__) || defined (__cplusplus) -int yyparse (void *YYPARSE_PARAM); -# else -int yyparse (); -# endif -#else /* ! YYPARSE_PARAM */ -#if defined (__STDC__) || defined (__cplusplus) -int yyparse (void); -#else -int yyparse (); -#endif -#endif /* ! YYPARSE_PARAM */ - - - -/* The lookahead symbol. */ -int yychar; - -/* The semantic value of the lookahead symbol. */ -YYSTYPE yylval; - -/* Number of syntax errors so far. */ -int yynerrs; - - - -/*----------. -| yyparse. | -`----------*/ - -#ifdef YYPARSE_PARAM -# if defined (__STDC__) || defined (__cplusplus) -int yyparse (void *YYPARSE_PARAM) -# else -int yyparse (YYPARSE_PARAM) - void *YYPARSE_PARAM; -# endif -#else /* ! YYPARSE_PARAM */ -#if defined (__STDC__) || defined (__cplusplus) -int -yyparse (void) -#else -int -yyparse () - -#endif -#endif -{ - - register int yystate; - register int yyn; - int yyresult; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - /* Lookahead token as an internal (translated) token number. */ - int yytoken = 0; - - /* Three stacks and their tools: - `yyss': related to states, - `yyvs': related to semantic values, - `yyls': related to locations. - - Refer to the stacks thru separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - short yyssa[YYINITDEPTH]; - short *yyss = yyssa; - register short *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs = yyvsa; - register YYSTYPE *yyvsp; - - - -#define YYPOPSTACK (yyvsp--, yyssp--) - - YYSIZE_T yystacksize = YYINITDEPTH; - - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - - - /* When reducing, the number of symbols on the RHS of the reduced - rule. */ - int yylen; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - - yyssp = yyss; - yyvsp = yyvs; - - goto yysetstate; - -/*------------------------------------------------------------. -| yynewstate -- Push a new state, which is found in yystate. | -`------------------------------------------------------------*/ - yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. so pushing a state here evens the stacks. - */ - yyssp++; - - yysetstate: - *yyssp = yystate; - - if (yyss + yystacksize - 1 <= yyssp) - { - /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; - -#ifdef yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - short *yyss1 = yyss; - - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - conditional around just the two extra args, but that might - be undefined if yyoverflow is a macro. */ - yyoverflow ("parser stack overflow", - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - - &yystacksize); - - yyss = yyss1; - yyvs = yyvs1; - } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyoverflowlab; -# else - /* Extend the stack our own way. */ - if (YYMAXDEPTH <= yystacksize) - goto yyoverflowlab; - yystacksize *= 2; - if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; - - { - short *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyoverflowlab; - YYSTACK_RELOCATE (yyss); - YYSTACK_RELOCATE (yyvs); - -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif -#endif /* no yyoverflow */ - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; - - - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); - - if (yyss + yystacksize - 1 <= yyssp) - YYABORT; - } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - - goto yybackup; - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - -/* Do appropriate processing given the current state. */ -/* Read a lookahead token if we need one and don't already have one. */ -/* yyresume: */ - - /* First try to decide what to do without reference to lookahead token. */ - - yyn = yypact[yystate]; - if (yyn == YYPACT_NINF) - goto yydefault; - - /* Not known => get a lookahead token if don't already have one. */ - - /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = YYLEX; - } - - if (yychar <= YYEOF) - { - yychar = yytoken = YYEOF; - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yytoken = YYTRANSLATE (yychar); - YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc); - } - - /* If the proper action on seeing token YYTOKEN is to reduce or to - detect an error, take that action. */ - yyn += yytoken; - if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) - goto yydefault; - yyn = yytable[yyn]; - if (yyn <= 0) - { - if (yyn == 0 || yyn == YYTABLE_NINF) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - - if (yyn == YYFINAL) - YYACCEPT; - - /* Shift the lookahead token. */ - YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken])); - - /* Discard the token being shifted unless it is eof. */ - if (yychar != YYEOF) - yychar = YYEMPTY; - - *++yyvsp = yylval; - - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - yystate = yyn; - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- Do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - `$$ = $1'. - - Otherwise, the following line sets YYVAL to garbage. - This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - - - YY_REDUCE_PRINT (yyn); - switch (yyn) - { - case 2: -#line 228 "parser.y" - { write_proxies(yyvsp[0].ifref); write_client(yyvsp[0].ifref); write_server(yyvsp[0].ifref); ;} - break; - - case 3: -#line 231 "parser.y" - { yyval.ifref = NULL; ;} - break; - - case 4: -#line 232 "parser.y" - { yyval.ifref = yyvsp[-1].ifref; ;} - break; - - case 5: -#line 233 "parser.y" - { yyval.ifref = make_ifref(yyvsp[0].type); LINK(yyval.ifref, yyvsp[-1].ifref); ;} - break; - - case 6: -#line 234 "parser.y" - { yyval.ifref = yyvsp[-1].ifref; add_coclass(yyvsp[0].clas); ;} - break; - - case 7: -#line 235 "parser.y" - { yyval.ifref = yyvsp[-1].ifref; add_module(yyvsp[0].type); ;} - break; - - case 8: -#line 236 "parser.y" - { yyval.ifref = yyvsp[-1].ifref; ;} - break; - - case 9: -#line 237 "parser.y" - { yyval.ifref = yyvsp[-1].ifref; ;} - break; - - case 10: -#line 240 "parser.y" - {;} - break; - - case 11: -#line 241 "parser.y" - { if (!parse_only) add_interface(yyvsp[0].type); ;} - break; - - case 12: -#line 242 "parser.y" - { if (!parse_only) add_interface(yyvsp[0].type); ;} - break; - - case 13: -#line 243 "parser.y" - { if (!parse_only) add_coclass(yyvsp[0].clas); ;} - break; - - case 14: -#line 244 "parser.y" - { if (!parse_only) add_module(yyvsp[0].type); ;} - break; - - case 15: -#line 245 "parser.y" - {;} - break; - - case 16: -#line 248 "parser.y" - { yyval.func = NULL; ;} - break; - - case 17: -#line 249 "parser.y" - { yyval.func = yyvsp[-1].func; LINK(yyval.func, yyvsp[-2].func); ;} - break; - - case 18: -#line 250 "parser.y" - { yyval.func = yyvsp[-1].func; ;} - break; - - case 19: -#line 253 "parser.y" - {;} - break; - - case 20: -#line 254 "parser.y" - { if (!parse_only && do_header) { write_constdef(yyvsp[-1].var); } ;} - break; - - case 21: -#line 255 "parser.y" - {;} - break; - - case 22: -#line 256 "parser.y" - { if (!parse_only && do_header) { write_type(header, yyvsp[-1].type, NULL, NULL); fprintf(header, ";\n\n"); } ;} - break; - - case 23: -#line 257 "parser.y" - { if (!parse_only && do_header) { write_externdef(yyvsp[-1].var); } ;} - break; - - case 24: -#line 258 "parser.y" - {;} - break; - - case 25: -#line 259 "parser.y" - { if (!parse_only && do_header) { write_type(header, yyvsp[-1].type, NULL, NULL); fprintf(header, ";\n\n"); } ;} - break; - - case 26: -#line 260 "parser.y" - {;} - break; - - case 27: -#line 261 "parser.y" - { if (!parse_only && do_header) { write_type(header, yyvsp[-1].type, NULL, NULL); fprintf(header, ";\n\n"); } ;} - break; - - case 28: -#line 264 "parser.y" - { if (!parse_only && do_header) fprintf(header, "%s\n", yyvsp[-1].str); ;} - break; - - case 29: -#line 266 "parser.y" - { assert(yychar == YYEMPTY); - if (!do_import(yyvsp[-1].str)) yychar = aEOF; ;} - break; - - case 30: -#line 269 "parser.y" - {;} - break; - - case 31: -#line 272 "parser.y" - { yyval.str = yyvsp[0].str; ;} - break; - - case 32: -#line 274 "parser.y" - { start_typelib(yyvsp[-1].str, yyvsp[-2].attr); ;} - break; - - case 33: -#line 276 "parser.y" - { end_typelib(); ;} - break; - - case 34: -#line 279 "parser.y" - { yyval.var = NULL; ;} - break; - - case 36: -#line 283 "parser.y" - { yyval.var = NULL; ;} - break; - - case 38: -#line 287 "parser.y" - { LINK(yyvsp[0].var, yyvsp[-2].var); yyval.var = yyvsp[0].var; ;} - break; - - case 40: -#line 292 "parser.y" - { yyval.var = yyvsp[-1].var; - set_type(yyval.var, yyvsp[-2].tref, yyvsp[0].expr); - yyval.var->attrs = yyvsp[-3].attr; - ;} - break; - - case 41: -#line 296 "parser.y" - { yyval.var = yyvsp[-1].var; - set_type(yyval.var, yyvsp[-2].tref, yyvsp[0].expr); - ;} - break; - - case 42: -#line 299 "parser.y" - { yyval.var = yyvsp[-3].var; - yyval.var->ptr_level--; - set_type(yyval.var, yyvsp[-4].tref, NULL); - yyval.var->attrs = yyvsp[-5].attr; - yyval.var->args = yyvsp[-1].var; - ;} - break; - - case 43: -#line 305 "parser.y" - { yyval.var = yyvsp[-3].var; - yyval.var->ptr_level--; - set_type(yyval.var, yyvsp[-4].tref, NULL); - yyval.var->args = yyvsp[-1].var; - ;} - break; - - case 44: -#line 312 "parser.y" - { yyval.expr = NULL; ;} - break; - - case 45: -#line 313 "parser.y" - { yyval.expr = yyvsp[-1].expr; ;} - break; - - case 46: -#line 314 "parser.y" - { yyval.expr = make_expr(EXPR_VOID); ;} - break; - - case 48: -#line 318 "parser.y" - { LINK(yyvsp[0].expr, yyvsp[-2].expr); yyval.expr = yyvsp[0].expr; ;} - break; - - case 49: -#line 319 "parser.y" - { LINK(yyvsp[0].expr, yyvsp[-3].expr); yyval.expr = yyvsp[0].expr; ;} - break; - - case 50: -#line 322 "parser.y" - { yyval.attr = NULL; ;} - break; - - case 52: -#line 327 "parser.y" - { yyval.attr = yyvsp[-1].attr; ;} - break; - - case 54: -#line 331 "parser.y" - { LINK(yyvsp[0].attr, yyvsp[-2].attr); yyval.attr = yyvsp[0].attr; ;} - break; - - case 55: -#line 332 "parser.y" - { LINK(yyvsp[0].attr, yyvsp[-3].attr); yyval.attr = yyvsp[0].attr; ;} - break; - - case 56: -#line 336 "parser.y" - { yyval.attr = make_attr(ATTR_ASYNC); ;} - break; - - case 57: -#line 337 "parser.y" - { yyval.attr = make_attr(ATTR_AUTO_HANDLE); ;} - break; - - case 58: -#line 338 "parser.y" - { yyval.attr = make_attrp(ATTR_CALLAS, yyvsp[-1].var); ;} - break; - - case 59: -#line 339 "parser.y" - { yyval.attr = make_attrp(ATTR_CASE, yyvsp[-1].expr); ;} - break; - - case 60: -#line 340 "parser.y" - { yyval.attr = make_attrv(ATTR_CONTEXTHANDLE, 0); ;} - break; - - case 61: -#line 341 "parser.y" - { yyval.attr = make_attrv(ATTR_CONTEXTHANDLE, 0); /* RPC_CONTEXT_HANDLE_DONT_SERIALIZE */ ;} - break; - - case 62: -#line 342 "parser.y" - { yyval.attr = make_attrv(ATTR_CONTEXTHANDLE, 0); /* RPC_CONTEXT_HANDLE_SERIALIZE */ ;} - break; - - case 63: -#line 343 "parser.y" - { yyval.attr = make_attr(ATTR_CONTROL); ;} - break; - - case 64: -#line 344 "parser.y" - { yyval.attr = make_attr(ATTR_DEFAULT); ;} - break; - - case 65: -#line 345 "parser.y" - { yyval.attr = make_attrp(ATTR_DEFAULTVALUE_EXPR, yyvsp[-1].expr); ;} - break; - - case 66: -#line 346 "parser.y" - { yyval.attr = make_attrp(ATTR_DEFAULTVALUE_STRING, yyvsp[-1].str); ;} - break; - - case 67: -#line 347 "parser.y" - { yyval.attr = make_attrp(ATTR_DLLNAME, yyvsp[-1].str); ;} - break; - - case 68: -#line 348 "parser.y" - { yyval.attr = make_attr(ATTR_DUAL); ;} - break; - - case 69: -#line 349 "parser.y" - { yyval.attr = make_attrp(ATTR_ENDPOINT, yyvsp[-1].str); ;} - break; - - case 70: -#line 350 "parser.y" - { yyval.attr = make_attrp(ATTR_ENTRY_STRING, yyvsp[-1].str); ;} - break; - - case 71: -#line 351 "parser.y" - { yyval.attr = make_attrp(ATTR_ENTRY_ORDINAL, yyvsp[-1].expr); ;} - break; - - case 72: -#line 352 "parser.y" - { yyval.attr = make_attr(ATTR_EXPLICIT_HANDLE); ;} - break; - - case 73: -#line 353 "parser.y" - { yyval.attr = make_attr(ATTR_HANDLE); ;} - break; - - case 74: -#line 354 "parser.y" - { yyval.attr = make_attrp(ATTR_HELPCONTEXT, yyvsp[-1].expr); ;} - break; - - case 75: -#line 355 "parser.y" - { yyval.attr = make_attrp(ATTR_HELPFILE, yyvsp[-1].str); ;} - break; - - case 76: -#line 356 "parser.y" - { yyval.attr = make_attrp(ATTR_HELPSTRING, yyvsp[-1].str); ;} - break; - - case 77: -#line 357 "parser.y" - { yyval.attr = make_attrp(ATTR_HELPSTRINGCONTEXT, yyvsp[-1].expr); ;} - break; - - case 78: -#line 358 "parser.y" - { yyval.attr = make_attrp(ATTR_HELPSTRINGDLL, yyvsp[-1].str); ;} - break; - - case 79: -#line 359 "parser.y" - { yyval.attr = make_attr(ATTR_HIDDEN); ;} - break; - - case 80: -#line 360 "parser.y" - { yyval.attr = make_attrp(ATTR_ID, yyvsp[-1].expr); ;} - break; - - case 81: -#line 361 "parser.y" - { yyval.attr = make_attr(ATTR_IDEMPOTENT); ;} - break; - - case 82: -#line 362 "parser.y" - { yyval.attr = make_attrp(ATTR_IIDIS, yyvsp[-1].var); ;} - break; - - case 83: -#line 363 "parser.y" - { yyval.attr = make_attrp(ATTR_IMPLICIT_HANDLE, yyvsp[-1].str); ;} - break; - - case 84: -#line 364 "parser.y" - { yyval.attr = make_attr(ATTR_IN); ;} - break; - - case 85: -#line 365 "parser.y" - { yyval.attr = make_attr(ATTR_INPUTSYNC); ;} - break; - - case 86: -#line 366 "parser.y" - { yyval.attr = make_attrp(ATTR_LENGTHIS, yyvsp[-1].var); ;} - break; - - case 87: -#line 367 "parser.y" - { yyval.attr = make_attr(ATTR_LOCAL); ;} - break; - - case 88: -#line 368 "parser.y" - { yyval.attr = make_attr(ATTR_NONCREATABLE); ;} - break; - - case 89: -#line 369 "parser.y" - { yyval.attr = make_attr(ATTR_OBJECT); ;} - break; - - case 90: -#line 370 "parser.y" - { yyval.attr = make_attr(ATTR_ODL); ;} - break; - - case 91: -#line 371 "parser.y" - { yyval.attr = make_attr(ATTR_OLEAUTOMATION); ;} - break; - - case 92: -#line 372 "parser.y" - { yyval.attr = make_attr(ATTR_OPTIONAL); ;} - break; - - case 93: -#line 373 "parser.y" - { yyval.attr = make_attr(ATTR_OUT); ;} - break; - - case 94: -#line 374 "parser.y" - { yyval.attr = make_attrv(ATTR_POINTERDEFAULT, yyvsp[-1].num); ;} - break; - - case 95: -#line 375 "parser.y" - { yyval.attr = make_attr(ATTR_PROPGET); ;} - break; - - case 96: -#line 376 "parser.y" - { yyval.attr = make_attr(ATTR_PROPPUT); ;} - break; - - case 97: -#line 377 "parser.y" - { yyval.attr = make_attr(ATTR_PROPPUTREF); ;} - break; - - case 98: -#line 378 "parser.y" - { yyval.attr = make_attr(ATTR_PTR); ;} - break; - - case 99: -#line 379 "parser.y" - { yyval.attr = make_attr(ATTR_PUBLIC); ;} - break; - - case 100: -#line 380 "parser.y" - { yyval.attr = make_attr(ATTR_READONLY); ;} - break; - - case 101: -#line 381 "parser.y" - { yyval.attr = make_attr(ATTR_REF); ;} - break; - - case 102: -#line 382 "parser.y" - { yyval.attr = make_attr(ATTR_RESTRICTED); ;} - break; - - case 103: -#line 383 "parser.y" - { yyval.attr = make_attr(ATTR_RETVAL); ;} - break; - - case 104: -#line 384 "parser.y" - { yyval.attr = make_attrp(ATTR_SIZEIS, yyvsp[-1].var); ;} - break; - - case 105: -#line 385 "parser.y" - { yyval.attr = make_attr(ATTR_SOURCE); ;} - break; - - case 106: -#line 386 "parser.y" - { yyval.attr = make_attr(ATTR_STRING); ;} - break; - - case 107: -#line 387 "parser.y" - { yyval.attr = make_attrp(ATTR_SWITCHIS, yyvsp[-1].expr); ;} - break; - - case 108: -#line 388 "parser.y" - { yyval.attr = make_attrp(ATTR_SWITCHTYPE, type_ref(yyvsp[-1].tref)); ;} - break; - - case 109: -#line 389 "parser.y" - { yyval.attr = make_attrp(ATTR_TRANSMITAS, type_ref(yyvsp[-1].tref)); ;} - break; - - case 110: -#line 390 "parser.y" - { yyval.attr = make_attr(ATTR_UNIQUE); ;} - break; - - case 111: -#line 391 "parser.y" - { yyval.attr = make_attrp(ATTR_UUID, yyvsp[-1].uuid); ;} - break; - - case 112: -#line 392 "parser.y" - { yyval.attr = make_attr(ATTR_V1ENUM); ;} - break; - - case 113: -#line 393 "parser.y" - { yyval.attr = make_attr(ATTR_VARARG); ;} - break; - - case 114: -#line 394 "parser.y" - { yyval.attr = make_attrv(ATTR_VERSION, yyvsp[-1].num); ;} - break; - - case 115: -#line 395 "parser.y" - { yyval.attr = make_attrp(ATTR_WIREMARSHAL, type_ref(yyvsp[-1].tref)); ;} - break; - - case 116: -#line 396 "parser.y" - { yyval.attr = make_attrv(ATTR_POINTERTYPE, yyvsp[0].num); ;} - break; - - case 119: -#line 403 "parser.y" - { yyval.var = NULL; ;} - break; - - case 120: -#line 404 "parser.y" - { if (yyvsp[0].var) { LINK(yyvsp[0].var, yyvsp[-1].var); yyval.var = yyvsp[0].var; } - else { yyval.var = yyvsp[-1].var; } - ;} - break; - - case 121: -#line 409 "parser.y" - { attr_t *a = make_attrp(ATTR_CASE, yyvsp[-2].expr); - yyval.var = yyvsp[0].var; if (!yyval.var) yyval.var = make_var(NULL); - LINK(a, yyval.var->attrs); yyval.var->attrs = a; - ;} - break; - - case 122: -#line 413 "parser.y" - { attr_t *a = make_attr(ATTR_DEFAULT); - yyval.var = yyvsp[0].var; if (!yyval.var) yyval.var = make_var(NULL); - LINK(a, yyval.var->attrs); yyval.var->attrs = a; - ;} - break; - - case 123: -#line 419 "parser.y" - { yyval.var = reg_const(yyvsp[-2].var); - set_type(yyval.var, yyvsp[-3].tref, NULL); - yyval.var->eval = yyvsp[0].expr; - yyval.var->lval = yyvsp[0].expr->cval; - ;} - break; - - case 124: -#line 426 "parser.y" - { yyval.var = NULL; ;} - break; - - case 125: -#line 427 "parser.y" - { yyval.var = yyvsp[-1].var; ;} - break; - - case 128: -#line 432 "parser.y" - { LINK(yyvsp[0].var, yyvsp[-2].var); yyval.var = yyvsp[0].var; - if (yyvsp[-2].var && !yyvsp[0].var->eval) - yyvsp[0].var->lval = yyvsp[-2].var->lval + 1; - ;} - break; - - case 129: -#line 438 "parser.y" - { yyval.var = reg_const(yyvsp[-2].var); - yyval.var->eval = yyvsp[0].expr; - yyval.var->lval = yyvsp[0].expr->cval; - yyval.var->type = make_type(RPC_FC_LONG, &std_int); - ;} - break; - - case 130: -#line 443 "parser.y" - { yyval.var = reg_const(yyvsp[0].var); - yyval.var->lval = 0; /* default for first enum entry */ - yyval.var->type = make_type(RPC_FC_LONG, &std_int); - ;} - break; - - case 131: -#line 449 "parser.y" - { yyval.type = get_typev(RPC_FC_ENUM16, yyvsp[-3].var, tsENUM); - yyval.type->fields = yyvsp[-1].var; - yyval.type->defined = TRUE; - if(in_typelib) - add_enum(yyval.type); - ;} - break; - - case 132: -#line 471 "parser.y" - { yyval.expr = make_expr(EXPR_VOID); ;} - break; - - case 134: -#line 475 "parser.y" - { yyval.expr = make_exprl(EXPR_NUM, yyvsp[0].num); ;} - break; - - case 135: -#line 476 "parser.y" - { yyval.expr = make_exprl(EXPR_HEXNUM, yyvsp[0].num); ;} - break; - - case 136: -#line 477 "parser.y" - { yyval.expr = make_exprs(EXPR_IDENTIFIER, yyvsp[0].str); ;} - break; - - case 137: -#line 478 "parser.y" - { yyval.expr = make_expr3(EXPR_COND, yyvsp[-4].expr, yyvsp[-2].expr, yyvsp[0].expr); ;} - break; - - case 138: -#line 479 "parser.y" - { yyval.expr = make_expr2(EXPR_OR , yyvsp[-2].expr, yyvsp[0].expr); ;} - break; - - case 139: -#line 480 "parser.y" - { yyval.expr = make_expr2(EXPR_AND, yyvsp[-2].expr, yyvsp[0].expr); ;} - break; - - case 140: -#line 481 "parser.y" - { yyval.expr = make_expr2(EXPR_ADD, yyvsp[-2].expr, yyvsp[0].expr); ;} - break; - - case 141: -#line 482 "parser.y" - { yyval.expr = make_expr2(EXPR_SUB, yyvsp[-2].expr, yyvsp[0].expr); ;} - break; - - case 142: -#line 483 "parser.y" - { yyval.expr = make_expr2(EXPR_MUL, yyvsp[-2].expr, yyvsp[0].expr); ;} - break; - - case 143: -#line 484 "parser.y" - { yyval.expr = make_expr2(EXPR_DIV, yyvsp[-2].expr, yyvsp[0].expr); ;} - break; - - case 144: -#line 485 "parser.y" - { yyval.expr = make_expr2(EXPR_SHL, yyvsp[-2].expr, yyvsp[0].expr); ;} - break; - - case 145: -#line 486 "parser.y" - { yyval.expr = make_expr2(EXPR_SHR, yyvsp[-2].expr, yyvsp[0].expr); ;} - break; - - case 146: -#line 487 "parser.y" - { yyval.expr = make_expr1(EXPR_NOT, yyvsp[0].expr); ;} - break; - - case 147: -#line 488 "parser.y" - { yyval.expr = make_expr1(EXPR_NEG, yyvsp[0].expr); ;} - break; - - case 148: -#line 489 "parser.y" - { yyval.expr = make_expr1(EXPR_PPTR, yyvsp[0].expr); ;} - break; - - case 149: -#line 490 "parser.y" - { yyval.expr = make_exprt(EXPR_CAST, yyvsp[-2].tref, yyvsp[0].expr); ;} - break; - - case 150: -#line 491 "parser.y" - { yyval.expr = make_exprt(EXPR_SIZEOF, yyvsp[-1].tref, NULL); ;} - break; - - case 151: -#line 492 "parser.y" - { yyval.expr = yyvsp[-1].expr; ;} - break; - - case 153: -#line 496 "parser.y" - { LINK(yyvsp[0].expr, yyvsp[-2].expr); yyval.expr = yyvsp[0].expr; ;} - break; - - case 154: -#line 499 "parser.y" - { yyval.expr = yyvsp[0].expr; - if (!yyval.expr->is_const) - yyerror("expression is not constant\n"); - ;} - break; - - case 155: -#line 505 "parser.y" - { yyval.var = yyvsp[0].var; - set_type(yyval.var, yyvsp[-1].tref, NULL); - ;} - break; - - case 156: -#line 510 "parser.y" - { yyval.var = NULL; ;} - break; - - case 157: -#line 511 "parser.y" - { if (yyvsp[0].var) { LINK(yyvsp[0].var, yyvsp[-1].var); yyval.var = yyvsp[0].var; } - else { yyval.var = yyvsp[-1].var; } - ;} - break; - - case 158: -#line 516 "parser.y" - { yyval.var = yyvsp[-1].var; ;} - break; - - case 159: -#line 517 "parser.y" - { yyval.var = make_var(NULL); yyval.var->type = yyvsp[-1].type; yyval.var->attrs = yyvsp[-2].attr; ;} - break; - - case 160: -#line 518 "parser.y" - { yyval.var = make_var(NULL); yyval.var->attrs = yyvsp[-1].attr; ;} - break; - - case 161: -#line 519 "parser.y" - { yyval.var = NULL; ;} - break; - - case 162: -#line 522 "parser.y" - { yyval.var = yyvsp[-1].var; set_type(yyval.var, yyvsp[-2].tref, yyvsp[0].expr); yyval.var->attrs = yyvsp[-3].attr; ;} - break; - - case 163: -#line 527 "parser.y" - { set_type(yyvsp[-3].var, yyvsp[-5].tref, NULL); - yyvsp[-3].var->attrs = yyvsp[-6].attr; - yyval.func = make_func(yyvsp[-3].var, yyvsp[-1].var); - if (is_attr(yyvsp[-3].var->attrs, ATTR_IN)) { - yyerror("Inapplicable attribute"); - } - ;} - break; - - case 164: -#line 536 "parser.y" - { yyval.var = NULL; ;} - break; - - case 166: -#line 540 "parser.y" - { yyval.var = NULL; ;} - break; - - case 167: -#line 541 "parser.y" - { yyval.var = make_var(yyvsp[0].str); ;} - break; - - case 168: -#line 542 "parser.y" - { yyval.var = make_var(yyvsp[0].str); ;} - break; - - case 169: -#line 545 "parser.y" - { yyval.var = make_var(yyvsp[0].str); ;} - break; - - case 170: -#line 547 "parser.y" - { yyval.var = make_var(yyvsp[0].str); ;} - break; - - case 171: -#line 548 "parser.y" - { yyval.var = make_var(yyvsp[0].str); ;} - break; - - case 172: -#line 549 "parser.y" - { yyval.var = make_var(yyvsp[0].str); ;} - break; - - case 173: -#line 550 "parser.y" - { yyval.var = make_var(yyvsp[0].str); ;} - break; - - case 174: -#line 551 "parser.y" - { yyval.var = make_var(yyvsp[0].str); ;} - break; - - case 175: -#line 554 "parser.y" - { yyval.type = make_type(RPC_FC_BYTE, NULL); ;} - break; - - case 176: -#line 555 "parser.y" - { yyval.type = make_type(RPC_FC_WCHAR, NULL); ;} - break; - - case 178: -#line 557 "parser.y" - { yyval.type = yyvsp[0].type; yyval.type->sign = 1; ;} - break; - - case 179: -#line 558 "parser.y" - { yyval.type = yyvsp[0].type; yyval.type->sign = -1; - switch (yyval.type->type) { - case RPC_FC_CHAR: break; - case RPC_FC_SMALL: yyval.type->type = RPC_FC_USMALL; break; - case RPC_FC_SHORT: yyval.type->type = RPC_FC_USHORT; break; - case RPC_FC_LONG: yyval.type->type = RPC_FC_ULONG; break; - case RPC_FC_HYPER: - if (!yyval.type->ref) { yyval.type->ref = &std_uhyper; yyval.type->sign = 0; } - break; - default: break; - } - ;} - break; - - case 180: -#line 570 "parser.y" - { yyval.type = make_type(RPC_FC_ULONG, &std_int); yyval.type->sign = -1; ;} - break; - - case 181: -#line 571 "parser.y" - { yyval.type = make_type(RPC_FC_FLOAT, NULL); ;} - break; - - case 182: -#line 572 "parser.y" - { yyval.type = make_type(RPC_FC_FLOAT, NULL); ;} - break; - - case 183: -#line 573 "parser.y" - { yyval.type = make_type(RPC_FC_DOUBLE, NULL); ;} - break; - - case 184: -#line 574 "parser.y" - { yyval.type = make_type(RPC_FC_SMALL, &std_bool); ;} - break; - - case 185: -#line 575 "parser.y" - { yyval.type = make_type(RPC_FC_ERROR_STATUS_T, NULL); ;} - break; - - case 186: -#line 576 "parser.y" - { yyval.type = make_type(RPC_FC_IGNORE, NULL); ;} - break; - - case 189: -#line 583 "parser.y" - { yyval.type = make_type(RPC_FC_LONG, &std_int); ;} - break; - - case 190: -#line 584 "parser.y" - { yyval.type = make_type(RPC_FC_SMALL, NULL); ;} - break; - - case 191: -#line 585 "parser.y" - { yyval.type = make_type(RPC_FC_SHORT, NULL); ;} - break; - - case 192: -#line 586 "parser.y" - { yyval.type = make_type(RPC_FC_LONG, NULL); ;} - break; - - case 193: -#line 587 "parser.y" - { yyval.type = make_type(RPC_FC_HYPER, NULL); ;} - break; - - case 194: -#line 588 "parser.y" - { yyval.type = make_type(RPC_FC_HYPER, &std_int64); ;} - break; - - case 195: -#line 589 "parser.y" - { yyval.type = make_type(RPC_FC_CHAR, NULL); ;} - break; - - case 196: -#line 592 "parser.y" - { yyval.clas = make_class(yyvsp[0].str); ;} - break; - - case 197: -#line 593 "parser.y" - { yyval.clas = make_class(yyvsp[0].str); ;} - break; - - case 198: -#line 596 "parser.y" - { yyval.clas = yyvsp[0].clas; - yyval.clas->attrs = yyvsp[-1].attr; - if (!parse_only && do_header) - write_coclass(yyval.clas); - ;} - break; - - case 199: -#line 603 "parser.y" - { yyval.clas = yyvsp[-3].clas; - yyval.clas->ifaces = yyvsp[-1].ifref; - ;} - break; - - case 200: -#line 608 "parser.y" - { yyval.ifref = NULL; ;} - break; - - case 201: -#line 609 "parser.y" - { LINK(yyvsp[0].ifref, yyvsp[-1].ifref); yyval.ifref = yyvsp[0].ifref; ;} - break; - - case 202: -#line 613 "parser.y" - { yyval.ifref = make_ifref(yyvsp[0].type); yyval.ifref->attrs = yyvsp[-1].attr; ;} - break; - - case 203: -#line 616 "parser.y" - { yyval.type = get_type(0, yyvsp[0].str, 0); ;} - break; - - case 204: -#line 617 "parser.y" - { yyval.type = get_type(0, yyvsp[0].str, 0); ;} - break; - - case 205: -#line 620 "parser.y" - { yyval.type = yyvsp[0].type; - if (yyval.type->defined) yyerror("multiple definition error\n"); - yyval.type->attrs = yyvsp[-1].attr; - yyval.type->attrs = make_attr(ATTR_DISPINTERFACE); - LINK(yyval.type->attrs, yyvsp[-1].attr); - yyval.type->ref = find_type("IDispatch", 0); - if (!yyval.type->ref) yyerror("IDispatch is undefined\n"); - yyval.type->defined = TRUE; - if (!parse_only && do_header) write_forward(yyval.type); - ;} - break; - - case 206: -#line 632 "parser.y" - { yyval.var = NULL; ;} - break; - - case 207: -#line 633 "parser.y" - { LINK(yyvsp[-1].var, yyvsp[-2].var); yyval.var = yyvsp[-1].var; ;} - break; - - case 208: -#line 636 "parser.y" - { yyval.func = NULL; ;} - break; - - case 209: -#line 637 "parser.y" - { LINK(yyvsp[-1].func, yyvsp[-2].func); yyval.func = yyvsp[-1].func; ;} - break; - - case 210: -#line 643 "parser.y" - { yyval.type = yyvsp[-4].type; - yyval.type->fields = yyvsp[-2].var; - yyval.type->funcs = yyvsp[-1].func; - if (!parse_only && do_header) write_dispinterface(yyval.type); - ;} - break; - - case 211: -#line 655 "parser.y" - { yyval.type = NULL; ;} - break; - - case 212: -#line 656 "parser.y" - { yyval.type = find_type2(yyvsp[0].str, 0); ;} - break; - - case 213: -#line 659 "parser.y" - { yyval.type = get_type(RPC_FC_IP, yyvsp[0].str, 0); ;} - break; - - case 214: -#line 660 "parser.y" - { yyval.type = get_type(RPC_FC_IP, yyvsp[0].str, 0); ;} - break; - - case 215: -#line 663 "parser.y" - { yyval.type = yyvsp[0].type; - if (yyval.type->defined) yyerror("multiple definition error\n"); - yyval.type->attrs = yyvsp[-1].attr; - yyval.type->defined = TRUE; - if (!parse_only && do_header) write_forward(yyval.type); - ;} - break; - - case 216: -#line 672 "parser.y" - { yyval.type = yyvsp[-4].type; - yyval.type->ref = yyvsp[-3].type; - yyval.type->funcs = yyvsp[-1].func; - if (!parse_only && do_header) write_interface(yyval.type); - ;} - break; - - case 217: -#line 680 "parser.y" - { yyval.type = yyvsp[-6].type; - yyval.type->ref = find_type2(yyvsp[-4].str, 0); - if (!yyval.type->ref) yyerror("base class %s not found in import\n", yyvsp[-4].str); - yyval.type->funcs = yyvsp[-1].func; - if (!parse_only && do_header) write_interface(yyval.type); - ;} - break; - - case 218: -#line 686 "parser.y" - { yyval.type = yyvsp[0].type; ;} - break; - - case 219: -#line 690 "parser.y" - { yyval.type = yyvsp[-1].type; if (!parse_only && do_header) write_forward(yyval.type); ;} - break; - - case 220: -#line 691 "parser.y" - { yyval.type = yyvsp[-1].type; if (!parse_only && do_header) write_forward(yyval.type); ;} - break; - - case 221: -#line 694 "parser.y" - { yyval.type = make_type(0, NULL); yyval.type->name = yyvsp[0].str; ;} - break; - - case 222: -#line 695 "parser.y" - { yyval.type = make_type(0, NULL); yyval.type->name = yyvsp[0].str; ;} - break; - - case 223: -#line 698 "parser.y" - { yyval.type = yyvsp[0].type; - yyval.type->attrs = yyvsp[-1].attr; - ;} - break; - - case 224: -#line 703 "parser.y" - { yyval.type = yyvsp[-3].type; - yyval.type->funcs = yyvsp[-1].func; - /* FIXME: if (!parse_only && do_header) write_module($$); */ - ;} - break; - - case 225: -#line 709 "parser.y" - { yyval.var = yyvsp[0].var; yyval.var->ptr_level++; ;} - break; - - case 226: -#line 710 "parser.y" - { yyval.var = yyvsp[0].var; /* FIXME */ ;} - break; - - case 229: -#line 715 "parser.y" - { yyval.var = yyvsp[-1].var; ;} - break; - - case 231: -#line 720 "parser.y" - { LINK(yyvsp[0].var, yyvsp[-2].var); yyval.var = yyvsp[0].var; ;} - break; - - case 232: -#line 724 "parser.y" - { yyval.num = RPC_FC_RP; ;} - break; - - case 233: -#line 725 "parser.y" - { yyval.num = RPC_FC_UP; ;} - break; - - case 234: -#line 728 "parser.y" - { yyval.type = get_typev(RPC_FC_STRUCT, yyvsp[-3].var, tsSTRUCT); - /* overwrite RPC_FC_STRUCT with a more exact type */ - yyval.type->type = get_struct_type( yyvsp[-1].var ); - yyval.type->fields = yyvsp[-1].var; - yyval.type->defined = TRUE; - if(in_typelib) - add_struct(yyval.type); - ;} - break; - - case 235: -#line 738 "parser.y" - { yyval.tref = make_tref(NULL, make_type(0, NULL)); ;} - break; - - case 236: -#line 739 "parser.y" - { yyval.tref = make_tref(yyvsp[0].str, find_type(yyvsp[0].str, 0)); ;} - break; - - case 237: -#line 740 "parser.y" - { yyval.tref = make_tref(NULL, yyvsp[0].type); ;} - break; - - case 238: -#line 741 "parser.y" - { yyval.tref = uniq_tref(yyvsp[0].tref); yyval.tref->ref->is_const = TRUE; ;} - break; - - case 239: -#line 742 "parser.y" - { yyval.tref = make_tref(NULL, yyvsp[0].type); ;} - break; - - case 240: -#line 743 "parser.y" - { yyval.tref = make_tref(NULL, find_type2(yyvsp[0].str, tsENUM)); ;} - break; - - case 241: -#line 744 "parser.y" - { yyval.tref = make_tref(NULL, yyvsp[0].type); ;} - break; - - case 242: -#line 745 "parser.y" - { yyval.tref = make_tref(NULL, get_type(RPC_FC_STRUCT, yyvsp[0].str, tsSTRUCT)); ;} - break; - - case 243: -#line 746 "parser.y" - { yyval.tref = make_tref(NULL, yyvsp[0].type); ;} - break; - - case 244: -#line 747 "parser.y" - { yyval.tref = make_tref(NULL, find_type2(yyvsp[0].str, tsUNION)); ;} - break; - - case 245: -#line 750 "parser.y" - { typeref_t *tref = uniq_tref(yyvsp[-1].tref); - yyvsp[0].var->tname = tref->name; - tref->name = NULL; - yyval.type = type_ref(tref); - yyval.type->attrs = yyvsp[-2].attr; - if (!parse_only && do_header) - write_typedef(yyval.type, yyvsp[0].var); - if (in_typelib && yyval.type->attrs) - add_typedef(yyval.type, yyvsp[0].var); - reg_types(yyval.type, yyvsp[0].var, 0); - ;} - break; - - case 246: -#line 763 "parser.y" - { yyval.type = get_typev(RPC_FC_NON_ENCAPSULATED_UNION, yyvsp[-3].var, tsUNION); - yyval.type->fields = yyvsp[-1].var; - yyval.type->defined = TRUE; - ;} - break; - - case 247: -#line 769 "parser.y" - { var_t *u = yyvsp[-3].var; - yyval.type = get_typev(RPC_FC_ENCAPSULATED_UNION, yyvsp[-8].var, tsUNION); - if (!u) u = make_var("tagged_union"); - u->type = make_type(RPC_FC_NON_ENCAPSULATED_UNION, NULL); - u->type->fields = yyvsp[-1].var; - u->type->defined = TRUE; - LINK(u, yyvsp[-5].var); yyval.type->fields = u; - yyval.type->defined = TRUE; - ;} - break; - - case 248: -#line 781 "parser.y" - { yyval.num = MAKELONG(yyvsp[0].num, 0); ;} - break; - - case 249: -#line 782 "parser.y" - { yyval.num = MAKELONG(yyvsp[-2].num, yyvsp[0].num); ;} - break; - - - } - -/* Line 991 of yacc.c. */ -#line 3169 "y.tab.c" - - yyvsp -= yylen; - yyssp -= yylen; - - - YY_STACK_PRINT (yyss, yyssp); - - *++yyvsp = yyval; - - - /* Now `shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; - if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTOKENS]; - - goto yynewstate; - - -/*------------------------------------. -| yyerrlab -- here on detecting error | -`------------------------------------*/ -yyerrlab: - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; -#if YYERROR_VERBOSE - yyn = yypact[yystate]; - - if (YYPACT_NINF < yyn && yyn < YYLAST) - { - YYSIZE_T yysize = 0; - int yytype = YYTRANSLATE (yychar); - char *yymsg; - int yyx, yycount; - - yycount = 0; - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. */ - for (yyx = yyn < 0 ? -yyn : 0; - yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) - yysize += yystrlen (yytname[yyx]) + 15, yycount++; - yysize += yystrlen ("syntax error, unexpected ") + 1; - yysize += yystrlen (yytname[yytype]); - yymsg = (char *) YYSTACK_ALLOC (yysize); - if (yymsg != 0) - { - char *yyp = yystpcpy (yymsg, "syntax error, unexpected "); - yyp = yystpcpy (yyp, yytname[yytype]); - - if (yycount < 5) - { - yycount = 0; - for (yyx = yyn < 0 ? -yyn : 0; - yyx < (int) (sizeof (yytname) / sizeof (char *)); - yyx++) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) - { - const char *yyq = ! yycount ? ", expecting " : " or "; - yyp = yystpcpy (yyp, yyq); - yyp = yystpcpy (yyp, yytname[yyx]); - yycount++; - } - } - yyerror (yymsg); - YYSTACK_FREE (yymsg); - } - else - yyerror ("syntax error; also virtual memory exhausted"); - } - else -#endif /* YYERROR_VERBOSE */ - yyerror ("syntax error"); - } - - - - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse lookahead token after an - error, discard it. */ - - /* Return failure if at end of input. */ - if (yychar == YYEOF) - { - /* Pop the error token. */ - YYPOPSTACK; - /* Pop the rest of the stack. */ - while (yyss < yyssp) - { - YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); - yydestruct (yystos[*yyssp], yyvsp); - YYPOPSTACK; - } - YYABORT; - } - - YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc); - yydestruct (yytoken, &yylval); - yychar = YYEMPTY; - - } - - /* Else will try to reuse lookahead token after shifting the error - token. */ - goto yyerrlab2; - - -/*----------------------------------------------------. -| yyerrlab1 -- error raised explicitly by an action. | -`----------------------------------------------------*/ -yyerrlab1: - - /* Suppress GCC warning that yyerrlab1 is unused when no action - invokes YYERROR. */ -#if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__) - __attribute__ ((__unused__)) -#endif - - - goto yyerrlab2; - - -/*---------------------------------------------------------------. -| yyerrlab2 -- pop states until the error token can be shifted. | -`---------------------------------------------------------------*/ -yyerrlab2: - yyerrstatus = 3; /* Each real token shifted decrements this. */ - - for (;;) - { - yyn = yypact[yystate]; - if (yyn != YYPACT_NINF) - { - yyn += YYTERROR; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } - - /* Pop the current state because it cannot handle the error token. */ - if (yyssp == yyss) - YYABORT; - - YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); - yydestruct (yystos[yystate], yyvsp); - yyvsp--; - yystate = *--yyssp; - - YY_STACK_PRINT (yyss, yyssp); - } - - if (yyn == YYFINAL) - YYACCEPT; - - YYDPRINTF ((stderr, "Shifting error token, ")); - - *++yyvsp = yylval; - - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - -#ifndef yyoverflow -/*----------------------------------------------. -| yyoverflowlab -- parser overflow comes here. | -`----------------------------------------------*/ -yyoverflowlab: - yyerror ("parser stack overflow"); - yyresult = 2; - /* Fall through. */ -#endif - -yyreturn: -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif - return yyresult; -} - - -#line 785 "parser.y" - - -static attr_t *make_attr(enum attr_type type) -{ - attr_t *a = xmalloc(sizeof(attr_t)); - a->type = type; - a->u.ival = 0; - INIT_LINK(a); - return a; -} - -static attr_t *make_attrv(enum attr_type type, unsigned long val) -{ - attr_t *a = xmalloc(sizeof(attr_t)); - a->type = type; - a->u.ival = val; - INIT_LINK(a); - return a; -} - -static attr_t *make_attrp(enum attr_type type, void *val) -{ - attr_t *a = xmalloc(sizeof(attr_t)); - a->type = type; - a->u.pval = val; - INIT_LINK(a); - return a; -} - -static expr_t *make_expr(enum expr_type type) -{ - expr_t *e = xmalloc(sizeof(expr_t)); - e->type = type; - e->ref = NULL; - e->u.lval = 0; - e->is_const = FALSE; - INIT_LINK(e); - return e; -} - -static expr_t *make_exprl(enum expr_type type, long val) -{ - expr_t *e = xmalloc(sizeof(expr_t)); - e->type = type; - e->ref = NULL; - e->u.lval = val; - e->is_const = FALSE; - INIT_LINK(e); - /* check for numeric constant */ - if (type == EXPR_NUM || type == EXPR_HEXNUM) { - e->is_const = TRUE; - e->cval = val; - } - return e; -} - -static expr_t *make_exprs(enum expr_type type, char *val) -{ - expr_t *e; - e = xmalloc(sizeof(expr_t)); - e->type = type; - e->ref = NULL; - e->u.sval = val; - e->is_const = FALSE; - INIT_LINK(e); - /* check for predefined constants */ - if (type == EXPR_IDENTIFIER) { - var_t *c = find_const(val, 0); - if (c) { - e->u.sval = c->name; - free(val); - e->is_const = TRUE; - e->cval = c->lval; - } - } - return e; -} - -static expr_t *make_exprt(enum expr_type type, typeref_t *tref, expr_t *expr) -{ - expr_t *e; - e = xmalloc(sizeof(expr_t)); - e->type = type; - e->ref = expr; - e->u.tref = tref; - e->is_const = FALSE; - INIT_LINK(e); - /* check for cast of constant expression */ - if (type == EXPR_CAST && expr->is_const) { - e->is_const = TRUE; - e->cval = expr->cval; - } - return e; -} - -static expr_t *make_expr1(enum expr_type type, expr_t *expr) -{ - expr_t *e; - e = xmalloc(sizeof(expr_t)); - e->type = type; - e->ref = expr; - e->u.lval = 0; - e->is_const = FALSE; - INIT_LINK(e); - /* check for compile-time optimization */ - if (expr->is_const) { - e->is_const = TRUE; - switch (type) { - case EXPR_NEG: - e->cval = -expr->cval; - break; - case EXPR_NOT: - e->cval = ~expr->cval; - break; - default: - e->is_const = FALSE; - break; - } - } - return e; -} - -static expr_t *make_expr2(enum expr_type type, expr_t *expr1, expr_t *expr2) -{ - expr_t *e; - e = xmalloc(sizeof(expr_t)); - e->type = type; - e->ref = expr1; - e->u.ext = expr2; - e->is_const = FALSE; - INIT_LINK(e); - /* check for compile-time optimization */ - if (expr1->is_const && expr2->is_const) { - e->is_const = TRUE; - switch (type) { - case EXPR_ADD: - e->cval = expr1->cval + expr2->cval; - break; - case EXPR_SUB: - e->cval = expr1->cval - expr2->cval; - break; - case EXPR_MUL: - e->cval = expr1->cval * expr2->cval; - break; - case EXPR_DIV: - e->cval = expr1->cval / expr2->cval; - break; - case EXPR_OR: - e->cval = expr1->cval | expr2->cval; - break; - case EXPR_AND: - e->cval = expr1->cval & expr2->cval; - break; - case EXPR_SHL: - e->cval = expr1->cval << expr2->cval; - break; - case EXPR_SHR: - e->cval = expr1->cval >> expr2->cval; - break; - default: - e->is_const = FALSE; - break; - } - } - return e; -} - -static expr_t *make_expr3(enum expr_type type, expr_t *expr1, expr_t *expr2, expr_t *expr3) -{ - expr_t *e; - e = xmalloc(sizeof(expr_t)); - e->type = type; - e->ref = expr1; - e->u.ext = expr2; - e->ext2 = expr3; - e->is_const = FALSE; - INIT_LINK(e); - /* check for compile-time optimization */ - if (expr1->is_const && expr2->is_const && expr3->is_const) { - e->is_const = TRUE; - switch (type) { - case EXPR_COND: - e->cval = expr1->cval ? expr2->cval : expr3->cval; - break; - default: - e->is_const = FALSE; - break; - } - } - return e; -} - -static type_t *make_type(unsigned char type, type_t *ref) -{ - type_t *t = xmalloc(sizeof(type_t)); - t->name = NULL; - t->type = type; - t->ref = ref; - t->rname = NULL; - t->attrs = NULL; - t->funcs = NULL; - t->fields = NULL; - t->ignore = parse_only; - t->is_const = FALSE; - t->sign = 0; - t->defined = FALSE; - t->written = FALSE; - t->typelib_idx = -1; - INIT_LINK(t); - return t; -} - -static typeref_t *make_tref(char *name, type_t *ref) -{ - typeref_t *t = xmalloc(sizeof(typeref_t)); - t->name = name; - t->ref = ref; - t->uniq = ref ? 0 : 1; - return t; -} - -static typeref_t *uniq_tref(typeref_t *ref) -{ - typeref_t *t = ref; - type_t *tp; - if (t->uniq) return t; - tp = make_type(0, t->ref); - tp->name = t->name; - t->name = NULL; - t->ref = tp; - t->uniq = 1; - return t; -} - -static type_t *type_ref(typeref_t *ref) -{ - type_t *t = ref->ref; - if (ref->name) free(ref->name); - free(ref); - return t; -} - -static void set_type(var_t *v, typeref_t *ref, expr_t *arr) -{ - v->type = ref->ref; - v->tname = ref->name; - ref->name = NULL; - free(ref); - v->array = arr; -} - -static ifref_t *make_ifref(type_t *iface) -{ - ifref_t *l = xmalloc(sizeof(ifref_t)); - l->iface = iface; - l->attrs = NULL; - INIT_LINK(l); - return l; -} - -static var_t *make_var(char *name) -{ - var_t *v = xmalloc(sizeof(var_t)); - v->name = name; - v->ptr_level = 0; - v->type = NULL; - v->tname = NULL; - v->attrs = NULL; - v->array = NULL; - v->eval = NULL; - v->lval = 0; - INIT_LINK(v); - return v; -} - -static func_t *make_func(var_t *def, var_t *args) -{ - func_t *f = xmalloc(sizeof(func_t)); - f->def = def; - f->args = args; - f->ignore = parse_only; - f->idx = -1; - INIT_LINK(f); - return f; -} - -static class_t *make_class(char *name) -{ - class_t *c = xmalloc(sizeof(class_t)); - c->name = name; - c->attrs = NULL; - c->ifaces = NULL; - INIT_LINK(c); - return c; -} - -#define HASHMAX 64 - -static int hash_ident(const char *name) -{ - const char *p = name; - int sum = 0; - /* a simple sum hash is probably good enough */ - while (*p) { - sum += *p; - p++; - } - return sum & (HASHMAX-1); -} - -/***** type repository *****/ - -struct rtype { - char *name; - type_t *type; - int t; - struct rtype *next; -}; - -struct rtype *type_hash[HASHMAX]; - -static type_t *reg_type(type_t *type, char *name, int t) -{ - struct rtype *nt; - int hash; - if (!name) { - yyerror("registering named type without name\n"); - return type; - } - hash = hash_ident(name); - nt = xmalloc(sizeof(struct rtype)); - nt->name = name; - nt->type = type; - nt->t = t; - nt->next = type_hash[hash]; - type_hash[hash] = nt; - type->name = name; - return type; -} - -/* determine pointer type from attrs */ -static unsigned char get_pointer_type( type_t *type ) -{ - int t; - if (is_attr( type->attrs, ATTR_STRING )) - { - type_t *t = type; - while( t->type == 0 && t->ref ) - t = t->ref; - switch( t->type ) - { - case RPC_FC_CHAR: - return RPC_FC_C_CSTRING; - case RPC_FC_WCHAR: - return RPC_FC_C_WSTRING; - } - } - t = get_attrv( type->attrs, ATTR_POINTERTYPE ); - if (t) return t; - - if(is_attr( type->attrs, ATTR_PTR )) - return RPC_FC_FP; - - if(is_attr( type->attrs, ATTR_UNIQUE )) - return RPC_FC_UP; - - return RPC_FC_RP; -} - -static type_t *reg_types(type_t *type, var_t *names, int t) -{ - type_t *ptr = type; - int ptrc = 0; - - while (names) { - var_t *next = NEXT_LINK(names); - if (names->name) { - type_t *cur = ptr; - int cptr = names->ptr_level; - if (cptr > ptrc) { - while (cptr > ptrc) { - int t = get_pointer_type( cur ); - cur = ptr = make_type(t, cur); - ptrc++; - } - } else { - while (cptr < ptrc) { - cur = cur->ref; - cptr++; - } - } - reg_type(cur, names->name, t); - } - free(names); - names = next; - } - return type; -} - -static type_t *find_type(char *name, int t) -{ - struct rtype *cur = type_hash[hash_ident(name)]; - while (cur && (cur->t != t || strcmp(cur->name, name))) - cur = cur->next; - if (!cur) { - yyerror("type %s not found\n", name); - return NULL; - } - return cur->type; -} - -static type_t *find_type2(char *name, int t) -{ - type_t *tp = find_type(name, t); - free(name); - return tp; -} - -int is_type(const char *name) -{ - struct rtype *cur = type_hash[hash_ident(name)]; - while (cur && (cur->t || strcmp(cur->name, name))) - cur = cur->next; - if (cur) return TRUE; - return FALSE; -} - -static type_t *get_type(unsigned char type, char *name, int t) -{ - struct rtype *cur = NULL; - type_t *tp; - if (name) { - cur = type_hash[hash_ident(name)]; - while (cur && (cur->t != t || strcmp(cur->name, name))) - cur = cur->next; - } - if (cur) { - free(name); - return cur->type; - } - tp = make_type(type, NULL); - tp->name = name; - if (!name) return tp; - return reg_type(tp, name, t); -} - -static type_t *get_typev(unsigned char type, var_t *name, int t) -{ - char *sname = NULL; - if (name) { - sname = name->name; - free(name); - } - return get_type(type, sname, t); -} - -static int get_struct_type(var_t *field) -{ - int has_pointer = 0; - int has_conformant_array = 0; - int has_conformant_string = 0; - - while (field) - { - type_t *t = field->type; - - /* get the base type */ - while( (t->type == 0) && t->ref ) - t = t->ref; - - switch (t->type) - { - /* - * RPC_FC_BYTE, RPC_FC_STRUCT, etc - * Simple types don't effect the type of struct. - * A struct containing a simple struct is still a simple struct. - * So long as we can block copy the data, we return RPC_FC_STRUCT. - */ - case 0: /* void pointer */ - case RPC_FC_BYTE: - case RPC_FC_CHAR: - case RPC_FC_SMALL: - case RPC_FC_USMALL: - case RPC_FC_WCHAR: - case RPC_FC_SHORT: - case RPC_FC_USHORT: - case RPC_FC_LONG: - case RPC_FC_ULONG: - case RPC_FC_INT3264: - case RPC_FC_UINT3264: - case RPC_FC_HYPER: - case RPC_FC_FLOAT: - case RPC_FC_DOUBLE: - case RPC_FC_STRUCT: - case RPC_FC_ENUM16: - case RPC_FC_ENUM32: - break; - - case RPC_FC_UP: - case RPC_FC_FP: - has_pointer = 1; - break; - case RPC_FC_CARRAY: - has_conformant_array = 1; - break; - case RPC_FC_C_CSTRING: - case RPC_FC_C_WSTRING: - has_conformant_string = 1; - break; - - /* - * Propagate member attributes - * a struct should be at least as complex as its member - */ - case RPC_FC_CVSTRUCT: - has_conformant_string = 1; - has_pointer = 1; - break; - - case RPC_FC_CPSTRUCT: - has_conformant_array = 1; - has_pointer = 1; - break; - - case RPC_FC_CSTRUCT: - has_conformant_array = 1; - break; - - case RPC_FC_PSTRUCT: - has_pointer = 1; - break; - - default: - fprintf(stderr,"Unknown struct member %s with type (0x%02x)\n", - field->name, t->type); - /* fallthru - treat it as complex */ - - /* as soon as we see one of these these members, it's bogus... */ - case RPC_FC_IP: - case RPC_FC_ENCAPSULATED_UNION: - case RPC_FC_NON_ENCAPSULATED_UNION: - case RPC_FC_TRANSMIT_AS: - case RPC_FC_REPRESENT_AS: - case RPC_FC_PAD: - case RPC_FC_EMBEDDED_COMPLEX: - case RPC_FC_BOGUS_STRUCT: - return RPC_FC_BOGUS_STRUCT; - } - field = NEXT_LINK(field); - } - - if( has_conformant_string && has_pointer ) - return RPC_FC_CVSTRUCT; - if( has_conformant_array && has_pointer ) - return RPC_FC_CPSTRUCT; - if( has_conformant_array ) - return RPC_FC_CSTRUCT; - if( has_pointer ) - return RPC_FC_PSTRUCT; - return RPC_FC_STRUCT; -} - -/***** constant repository *****/ - -struct rconst { - char *name; - var_t *var; - struct rconst *next; -}; - -struct rconst *const_hash[HASHMAX]; - -static var_t *reg_const(var_t *var) -{ - struct rconst *nc; - int hash; - if (!var->name) { - yyerror("registering constant without name\n"); - return var; - } - hash = hash_ident(var->name); - nc = xmalloc(sizeof(struct rconst)); - nc->name = var->name; - nc->var = var; - nc->next = const_hash[hash]; - const_hash[hash] = nc; - return var; -} - -static var_t *find_const(char *name, int f) -{ - struct rconst *cur = const_hash[hash_ident(name)]; - while (cur && strcmp(cur->name, name)) - cur = cur->next; - if (!cur) { - if (f) yyerror("constant %s not found\n", name); - return NULL; - } - return cur->var; -} - +/* A Bison parser, made by GNU Bison 1.875. */ + +/* Skeleton parser for Yacc-like parsing with Bison, + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc. + + 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, 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* Written by Richard Stallman by simplifying the original so called + ``semantic'' parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + aIDENTIFIER = 258, + aKNOWNTYPE = 259, + aNUM = 260, + aHEXNUM = 261, + aSTRING = 262, + aUUID = 263, + aEOF = 264, + SHL = 265, + SHR = 266, + tAGGREGATABLE = 267, + tALLOCATE = 268, + tAPPOBJECT = 269, + tARRAYS = 270, + tASYNC = 271, + tASYNCUUID = 272, + tAUTOHANDLE = 273, + tBINDABLE = 274, + tBOOLEAN = 275, + tBROADCAST = 276, + tBYTE = 277, + tBYTECOUNT = 278, + tCALLAS = 279, + tCALLBACK = 280, + tCASE = 281, + tCDECL = 282, + tCHAR = 283, + tCOCLASS = 284, + tCODE = 285, + tCOMMSTATUS = 286, + tCONST = 287, + tCONTEXTHANDLE = 288, + tCONTEXTHANDLENOSERIALIZE = 289, + tCONTEXTHANDLESERIALIZE = 290, + tCONTROL = 291, + tCPPQUOTE = 292, + tDEFAULT = 293, + tDEFAULTVALUE = 294, + tDISPINTERFACE = 295, + tDLLNAME = 296, + tDOUBLE = 297, + tDUAL = 298, + tENDPOINT = 299, + tENTRY = 300, + tENUM = 301, + tERRORSTATUST = 302, + tEXPLICITHANDLE = 303, + tEXTERN = 304, + tFLOAT = 305, + tHANDLE = 306, + tHANDLET = 307, + tHELPCONTEXT = 308, + tHELPFILE = 309, + tHELPSTRING = 310, + tHELPSTRINGCONTEXT = 311, + tHELPSTRINGDLL = 312, + tHIDDEN = 313, + tHYPER = 314, + tID = 315, + tIDEMPOTENT = 316, + tIIDIS = 317, + tIMPLICITHANDLE = 318, + tIMPORT = 319, + tIMPORTLIB = 320, + tIN = 321, + tINCLUDE = 322, + tINLINE = 323, + tINPUTSYNC = 324, + tINT = 325, + tINT64 = 326, + tINTERFACE = 327, + tLENGTHIS = 328, + tLIBRARY = 329, + tLOCAL = 330, + tLONG = 331, + tMETHODS = 332, + tMODULE = 333, + tNONCREATABLE = 334, + tOBJECT = 335, + tODL = 336, + tOLEAUTOMATION = 337, + tOPTIONAL = 338, + tOUT = 339, + tPOINTERDEFAULT = 340, + tPROPERTIES = 341, + tPROPGET = 342, + tPROPPUT = 343, + tPROPPUTREF = 344, + tPTR = 345, + tPUBLIC = 346, + tREADONLY = 347, + tREF = 348, + tRESTRICTED = 349, + tRETVAL = 350, + tSHORT = 351, + tSIGNED = 352, + tSINGLE = 353, + tSIZEIS = 354, + tSIZEOF = 355, + tSMALL = 356, + tSOURCE = 357, + tSTDCALL = 358, + tSTRING = 359, + tSTRUCT = 360, + tSWITCH = 361, + tSWITCHIS = 362, + tSWITCHTYPE = 363, + tTRANSMITAS = 364, + tTYPEDEF = 365, + tUNION = 366, + tUNIQUE = 367, + tUNSIGNED = 368, + tUUID = 369, + tV1ENUM = 370, + tVARARG = 371, + tVERSION = 372, + tVOID = 373, + tWCHAR = 374, + tWIREMARSHAL = 375, + tPOINTERTYPE = 376, + COND = 377, + CAST = 378, + PPTR = 379, + NEG = 380 + }; +#endif +#define aIDENTIFIER 258 +#define aKNOWNTYPE 259 +#define aNUM 260 +#define aHEXNUM 261 +#define aSTRING 262 +#define aUUID 263 +#define aEOF 264 +#define SHL 265 +#define SHR 266 +#define tAGGREGATABLE 267 +#define tALLOCATE 268 +#define tAPPOBJECT 269 +#define tARRAYS 270 +#define tASYNC 271 +#define tASYNCUUID 272 +#define tAUTOHANDLE 273 +#define tBINDABLE 274 +#define tBOOLEAN 275 +#define tBROADCAST 276 +#define tBYTE 277 +#define tBYTECOUNT 278 +#define tCALLAS 279 +#define tCALLBACK 280 +#define tCASE 281 +#define tCDECL 282 +#define tCHAR 283 +#define tCOCLASS 284 +#define tCODE 285 +#define tCOMMSTATUS 286 +#define tCONST 287 +#define tCONTEXTHANDLE 288 +#define tCONTEXTHANDLENOSERIALIZE 289 +#define tCONTEXTHANDLESERIALIZE 290 +#define tCONTROL 291 +#define tCPPQUOTE 292 +#define tDEFAULT 293 +#define tDEFAULTVALUE 294 +#define tDISPINTERFACE 295 +#define tDLLNAME 296 +#define tDOUBLE 297 +#define tDUAL 298 +#define tENDPOINT 299 +#define tENTRY 300 +#define tENUM 301 +#define tERRORSTATUST 302 +#define tEXPLICITHANDLE 303 +#define tEXTERN 304 +#define tFLOAT 305 +#define tHANDLE 306 +#define tHANDLET 307 +#define tHELPCONTEXT 308 +#define tHELPFILE 309 +#define tHELPSTRING 310 +#define tHELPSTRINGCONTEXT 311 +#define tHELPSTRINGDLL 312 +#define tHIDDEN 313 +#define tHYPER 314 +#define tID 315 +#define tIDEMPOTENT 316 +#define tIIDIS 317 +#define tIMPLICITHANDLE 318 +#define tIMPORT 319 +#define tIMPORTLIB 320 +#define tIN 321 +#define tINCLUDE 322 +#define tINLINE 323 +#define tINPUTSYNC 324 +#define tINT 325 +#define tINT64 326 +#define tINTERFACE 327 +#define tLENGTHIS 328 +#define tLIBRARY 329 +#define tLOCAL 330 +#define tLONG 331 +#define tMETHODS 332 +#define tMODULE 333 +#define tNONCREATABLE 334 +#define tOBJECT 335 +#define tODL 336 +#define tOLEAUTOMATION 337 +#define tOPTIONAL 338 +#define tOUT 339 +#define tPOINTERDEFAULT 340 +#define tPROPERTIES 341 +#define tPROPGET 342 +#define tPROPPUT 343 +#define tPROPPUTREF 344 +#define tPTR 345 +#define tPUBLIC 346 +#define tREADONLY 347 +#define tREF 348 +#define tRESTRICTED 349 +#define tRETVAL 350 +#define tSHORT 351 +#define tSIGNED 352 +#define tSINGLE 353 +#define tSIZEIS 354 +#define tSIZEOF 355 +#define tSMALL 356 +#define tSOURCE 357 +#define tSTDCALL 358 +#define tSTRING 359 +#define tSTRUCT 360 +#define tSWITCH 361 +#define tSWITCHIS 362 +#define tSWITCHTYPE 363 +#define tTRANSMITAS 364 +#define tTYPEDEF 365 +#define tUNION 366 +#define tUNIQUE 367 +#define tUNSIGNED 368 +#define tUUID 369 +#define tV1ENUM 370 +#define tVARARG 371 +#define tVERSION 372 +#define tVOID 373 +#define tWCHAR 374 +#define tWIREMARSHAL 375 +#define tPOINTERTYPE 376 +#define COND 377 +#define CAST 378 +#define PPTR 379 +#define NEG 380 + + + + +/* Copy the first part of user declarations. */ +#line 1 "parser.y" + +/* + * IDL Compiler + * + * Copyright 2002 Ove Kaaven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <assert.h> +#include <ctype.h> +#include <string.h> +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#endif + +#include "widl.h" +#include "utils.h" +#include "parser.h" +#include "header.h" +#include "typelib.h" + +#if defined(YYBYACC) + /* Berkeley yacc (byacc) doesn't seem to know about these */ + /* Some *BSD supplied versions do define these though */ +# ifndef YYEMPTY +# define YYEMPTY (-1) /* Empty lookahead value of yychar */ +# endif +# ifndef YYLEX +# define YYLEX yylex() +# endif + +#elif defined(YYBISON) + /* Bison was used for original development */ + /* #define YYEMPTY -2 */ + /* #define YYLEX yylex() */ + +#else + /* No yacc we know yet */ +# if !defined(YYEMPTY) || !defined(YYLEX) +# error Yacc version/type unknown. This version needs to be verified for settings of YYEMPTY and YYLEX. +# elif defined(__GNUC__) /* gcc defines the #warning directive */ +# warning Yacc version/type unknown. It defines YYEMPTY and YYLEX, but is not tested + /* #else we just take a chance that it works... */ +# endif +#endif + +static attr_t *make_attr(enum attr_type type); +static attr_t *make_attrv(enum attr_type type, unsigned long val); +static attr_t *make_attrp(enum attr_type type, void *val); +static expr_t *make_expr(enum expr_type type); +static expr_t *make_exprl(enum expr_type type, long val); +static expr_t *make_exprs(enum expr_type type, char *val); +static expr_t *make_exprt(enum expr_type type, typeref_t *tref, expr_t *expr); +static expr_t *make_expr1(enum expr_type type, expr_t *expr); +static expr_t *make_expr2(enum expr_type type, expr_t *exp1, expr_t *exp2); +static expr_t *make_expr3(enum expr_type type, expr_t *expr1, expr_t *expr2, expr_t *expr3); +static type_t *make_type(unsigned char type, type_t *ref); +static typeref_t *make_tref(char *name, type_t *ref); +static typeref_t *uniq_tref(typeref_t *ref); +static type_t *type_ref(typeref_t *ref); +static void set_type(var_t *v, typeref_t *ref, expr_t *arr); +static ifref_t *make_ifref(type_t *iface); +static var_t *make_var(char *name); +static func_t *make_func(var_t *def, var_t *args); +static class_t *make_class(char *name); + +static type_t *reg_type(type_t *type, char *name, int t); +static type_t *reg_types(type_t *type, var_t *names, int t); +static type_t *find_type(char *name, int t); +static type_t *find_type2(char *name, int t); +static type_t *get_type(unsigned char type, char *name, int t); +static type_t *get_typev(unsigned char type, var_t *name, int t); +static int get_struct_type(var_t *fields); + +static var_t *reg_const(var_t *var); +static var_t *find_const(char *name, int f); + +#define tsENUM 1 +#define tsSTRUCT 2 +#define tsUNION 3 + +static type_t std_bool = { "boolean" }; +static type_t std_int = { "int" }; +static type_t std_int64 = { "__int64" }; +static type_t std_uhyper = { "MIDL_uhyper" }; + + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) +#line 106 "parser.y" +typedef union YYSTYPE { + attr_t *attr; + expr_t *expr; + type_t *type; + typeref_t *tref; + var_t *var; + func_t *func; + ifref_t *ifref; + class_t *clas; + char *str; + UUID *uuid; + unsigned int num; +} YYSTYPE; +/* Line 191 of yacc.c. */ +#line 445 "y.tab.c" +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + +/* Copy the second part of user declarations. */ + + +/* Line 214 of yacc.c. */ +#line 457 "y.tab.c" + +#if ! defined (yyoverflow) || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# if YYSTACK_USE_ALLOCA +# define YYSTACK_ALLOC alloca +# else +# ifndef YYSTACK_USE_ALLOCA +# if defined (alloca) || defined (_ALLOCA_H) +# define YYSTACK_ALLOC alloca +# else +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# else +# if defined (__STDC__) || defined (__cplusplus) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +# define YYSTACK_ALLOC malloc +# define YYSTACK_FREE free +# endif +#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */ + + +#if (! defined (yyoverflow) \ + && (! defined (__cplusplus) \ + || (YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + short yyss; + YYSTYPE yyvs; + }; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + register YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (0) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined (__STDC__) || defined (__cplusplus) + typedef signed char yysigned_char; +#else + typedef short yysigned_char; +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 3 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 934 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 145 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 72 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 249 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 461 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 380 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const unsigned char yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 125, 2, + 135, 136, 128, 127, 122, 126, 144, 129, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 141, 134, + 2, 142, 2, 143, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 139, 2, 140, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 137, 124, 138, 130, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 123, 131, 132, + 133 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const unsigned short yyprhs[] = +{ + 0, 0, 3, 5, 6, 9, 12, 15, 18, 21, + 24, 25, 28, 31, 34, 37, 40, 41, 45, 48, + 50, 53, 55, 58, 61, 63, 66, 69, 72, 77, + 81, 85, 88, 92, 96, 97, 99, 101, 103, 107, + 109, 114, 118, 125, 131, 132, 136, 140, 142, 146, + 151, 152, 154, 158, 160, 164, 169, 171, 173, 178, + 183, 185, 187, 189, 191, 193, 198, 203, 208, 210, + 215, 220, 225, 227, 229, 234, 239, 244, 249, 254, + 256, 261, 263, 268, 274, 276, 278, 283, 285, 287, + 289, 291, 293, 295, 297, 302, 304, 306, 308, 310, + 312, 314, 316, 318, 320, 325, 327, 329, 334, 339, + 344, 346, 351, 353, 355, 360, 365, 367, 368, 370, + 371, 374, 379, 383, 389, 390, 393, 395, 397, 401, + 405, 407, 413, 414, 416, 418, 420, 422, 428, 432, + 436, 440, 444, 448, 452, 456, 460, 463, 466, 469, + 474, 479, 483, 485, 489, 491, 496, 497, 500, 503, + 507, 510, 512, 517, 525, 526, 528, 529, 531, 533, + 535, 537, 539, 541, 543, 545, 547, 549, 551, 554, + 557, 559, 561, 563, 565, 567, 569, 571, 572, 574, + 576, 579, 582, 585, 588, 590, 592, 595, 598, 601, + 606, 607, 610, 613, 616, 619, 622, 625, 629, 632, + 636, 642, 643, 646, 649, 652, 655, 661, 669, 671, + 674, 677, 680, 683, 686, 691, 694, 697, 699, 701, + 705, 707, 711, 713, 715, 721, 723, 725, 727, 730, + 732, 735, 737, 740, 742, 745, 750, 756, 767, 769 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const short yyrhs[] = +{ + 146, 0, -1, 147, -1, -1, 147, 204, -1, 147, + 203, -1, 147, 192, -1, 147, 207, -1, 147, 156, + -1, 147, 150, -1, -1, 148, 204, -1, 148, 203, + -1, 148, 192, -1, 148, 207, -1, 148, 150, -1, + -1, 149, 183, 134, -1, 149, 150, -1, 134, -1, + 170, 134, -1, 151, -1, 174, 134, -1, 179, 134, + -1, 153, -1, 212, 134, -1, 214, 134, -1, 215, + 134, -1, 37, 135, 7, 136, -1, 64, 7, 134, + -1, 152, 148, 9, -1, 74, 3, -1, 164, 154, + 137, -1, 155, 148, 138, -1, -1, 159, -1, 118, + -1, 160, -1, 159, 122, 160, -1, 158, -1, 164, + 213, 209, 161, -1, 213, 209, 161, -1, 164, 213, + 209, 135, 157, 136, -1, 213, 209, 135, 157, 136, + -1, -1, 139, 162, 140, -1, 139, 128, 140, -1, + 175, -1, 162, 122, 176, -1, 162, 140, 139, 176, + -1, -1, 164, -1, 139, 165, 140, -1, 166, -1, + 165, 122, 166, -1, 165, 140, 139, 166, -1, 16, + -1, 18, -1, 24, 135, 186, 136, -1, 26, 135, + 177, 136, -1, 33, -1, 34, -1, 35, -1, 36, + -1, 38, -1, 39, 135, 178, 136, -1, 39, 135, + 7, 136, -1, 41, 135, 7, 136, -1, 43, -1, + 44, 135, 7, 136, -1, 45, 135, 7, 136, -1, + 45, 135, 178, 136, -1, 48, -1, 51, -1, 53, + 135, 178, 136, -1, 54, 135, 7, 136, -1, 55, + 135, 7, 136, -1, 56, 135, 178, 136, -1, 57, + 135, 7, 136, -1, 58, -1, 60, 135, 178, 136, + -1, 61, -1, 62, 135, 186, 136, -1, 63, 135, + 52, 3, 136, -1, 66, -1, 69, -1, 73, 135, + 210, 136, -1, 75, -1, 79, -1, 80, -1, 81, + -1, 82, -1, 83, -1, 84, -1, 85, 135, 211, + 136, -1, 87, -1, 88, -1, 89, -1, 90, -1, + 91, -1, 92, -1, 93, -1, 94, -1, 95, -1, + 99, 135, 210, 136, -1, 102, -1, 104, -1, 107, + 135, 176, 136, -1, 108, 135, 213, 136, -1, 109, + 135, 213, 136, -1, 112, -1, 114, 135, 8, 136, + -1, 115, -1, 116, -1, 117, 135, 216, 136, -1, + 120, 135, 213, 136, -1, 211, -1, -1, 103, -1, + -1, 168, 169, -1, 26, 176, 141, 181, -1, 38, + 141, 181, -1, 32, 213, 186, 142, 178, -1, -1, + 172, 122, -1, 172, -1, 173, -1, 172, 122, 173, + -1, 186, 142, 178, -1, 186, -1, 46, 185, 137, + 171, 138, -1, -1, 176, -1, 5, -1, 6, -1, + 3, -1, 176, 143, 176, 141, 176, -1, 176, 124, + 176, -1, 176, 125, 176, -1, 176, 127, 176, -1, + 176, 126, 176, -1, 176, 128, 176, -1, 176, 129, + 176, -1, 176, 10, 176, -1, 176, 11, 176, -1, + 130, 176, -1, 126, 176, -1, 128, 176, -1, 135, + 213, 136, 176, -1, 100, 135, 213, 136, -1, 135, + 176, 136, -1, 178, -1, 177, 122, 178, -1, 176, + -1, 49, 32, 213, 186, -1, -1, 180, 181, -1, + 182, 134, -1, 163, 215, 134, -1, 164, 134, -1, + 134, -1, 163, 213, 209, 161, -1, 163, 213, 167, + 209, 135, 157, 136, -1, -1, 186, -1, -1, 3, + -1, 4, -1, 3, -1, 4, -1, 16, -1, 60, + -1, 95, -1, 117, -1, 22, -1, 119, -1, 189, + -1, 97, 189, -1, 113, 189, -1, 113, -1, 50, + -1, 98, -1, 42, -1, 20, -1, 47, -1, 52, + -1, -1, 70, -1, 70, -1, 101, 188, -1, 96, + 188, -1, 76, 188, -1, 59, 188, -1, 71, -1, + 28, -1, 29, 3, -1, 29, 4, -1, 164, 190, + -1, 191, 137, 193, 138, -1, -1, 193, 194, -1, + 163, 204, -1, 40, 3, -1, 40, 4, -1, 164, + 195, -1, 86, 141, -1, 197, 182, 134, -1, 77, + 141, -1, 198, 183, 134, -1, 196, 137, 197, 198, + 138, -1, -1, 141, 4, -1, 72, 3, -1, 72, + 4, -1, 164, 201, -1, 202, 200, 137, 149, 138, + -1, 202, 141, 3, 137, 153, 149, 138, -1, 199, + -1, 201, 134, -1, 195, 134, -1, 78, 3, -1, + 78, 4, -1, 164, 205, -1, 206, 137, 149, 138, + -1, 128, 209, -1, 32, 208, -1, 186, -1, 208, + -1, 135, 209, 136, -1, 209, -1, 210, 122, 209, + -1, 93, -1, 112, -1, 105, 185, 137, 180, 138, + -1, 118, -1, 4, -1, 187, -1, 32, 213, -1, + 174, -1, 46, 3, -1, 212, -1, 105, 3, -1, + 215, -1, 111, 3, -1, 110, 163, 213, 210, -1, + 111, 185, 137, 180, 138, -1, 111, 185, 106, 135, + 182, 136, 184, 137, 168, 138, -1, 5, -1, 5, + 144, 5, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const unsigned short yyrline[] = +{ + 0, 228, 228, 231, 232, 233, 234, 235, 236, 237, + 240, 241, 242, 243, 244, 245, 248, 249, 250, 253, + 254, 255, 256, 257, 258, 259, 260, 261, 264, 266, + 269, 272, 274, 276, 279, 280, 283, 286, 287, 288, + 292, 296, 299, 305, 312, 313, 314, 317, 318, 319, + 322, 323, 327, 330, 331, 332, 336, 337, 338, 339, + 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, + 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, + 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, + 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, + 390, 391, 392, 393, 394, 395, 396, 399, 400, 403, + 404, 409, 413, 419, 426, 427, 428, 431, 432, 438, + 443, 449, 471, 472, 475, 476, 477, 478, 479, 480, + 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, + 491, 492, 495, 496, 499, 505, 510, 511, 516, 517, + 518, 519, 522, 526, 536, 537, 540, 541, 542, 545, + 547, 548, 549, 550, 551, 554, 555, 556, 557, 558, + 570, 571, 572, 573, 574, 575, 576, 579, 580, 583, + 584, 585, 586, 587, 588, 589, 592, 593, 596, 603, + 608, 609, 613, 616, 617, 620, 632, 633, 636, 637, + 640, 655, 656, 659, 660, 663, 671, 679, 686, 690, + 691, 694, 695, 698, 703, 709, 710, 713, 714, 715, + 719, 720, 724, 725, 728, 738, 739, 740, 741, 742, + 743, 744, 745, 746, 747, 750, 763, 767, 781, 782 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE +/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "aIDENTIFIER", "aKNOWNTYPE", "aNUM", + "aHEXNUM", "aSTRING", "aUUID", "aEOF", "SHL", "SHR", "tAGGREGATABLE", + "tALLOCATE", "tAPPOBJECT", "tARRAYS", "tASYNC", "tASYNCUUID", + "tAUTOHANDLE", "tBINDABLE", "tBOOLEAN", "tBROADCAST", "tBYTE", + "tBYTECOUNT", "tCALLAS", "tCALLBACK", "tCASE", "tCDECL", "tCHAR", + "tCOCLASS", "tCODE", "tCOMMSTATUS", "tCONST", "tCONTEXTHANDLE", + "tCONTEXTHANDLENOSERIALIZE", "tCONTEXTHANDLESERIALIZE", "tCONTROL", + "tCPPQUOTE", "tDEFAULT", "tDEFAULTVALUE", "tDISPINTERFACE", "tDLLNAME", + "tDOUBLE", "tDUAL", "tENDPOINT", "tENTRY", "tENUM", "tERRORSTATUST", + "tEXPLICITHANDLE", "tEXTERN", "tFLOAT", "tHANDLE", "tHANDLET", + "tHELPCONTEXT", "tHELPFILE", "tHELPSTRING", "tHELPSTRINGCONTEXT", + "tHELPSTRINGDLL", "tHIDDEN", "tHYPER", "tID", "tIDEMPOTENT", "tIIDIS", + "tIMPLICITHANDLE", "tIMPORT", "tIMPORTLIB", "tIN", "tINCLUDE", + "tINLINE", "tINPUTSYNC", "tINT", "tINT64", "tINTERFACE", "tLENGTHIS", + "tLIBRARY", "tLOCAL", "tLONG", "tMETHODS", "tMODULE", "tNONCREATABLE", + "tOBJECT", "tODL", "tOLEAUTOMATION", "tOPTIONAL", "tOUT", + "tPOINTERDEFAULT", "tPROPERTIES", "tPROPGET", "tPROPPUT", "tPROPPUTREF", + "tPTR", "tPUBLIC", "tREADONLY", "tREF", "tRESTRICTED", "tRETVAL", + "tSHORT", "tSIGNED", "tSINGLE", "tSIZEIS", "tSIZEOF", "tSMALL", + "tSOURCE", "tSTDCALL", "tSTRING", "tSTRUCT", "tSWITCH", "tSWITCHIS", + "tSWITCHTYPE", "tTRANSMITAS", "tTYPEDEF", "tUNION", "tUNIQUE", + "tUNSIGNED", "tUUID", "tV1ENUM", "tVARARG", "tVERSION", "tVOID", + "tWCHAR", "tWIREMARSHAL", "tPOINTERTYPE", "','", "COND", "'|'", "'&'", + "'-'", "'+'", "'*'", "'/'", "'~'", "CAST", "PPTR", "NEG", "';'", "'('", + "')'", "'{'", "'}'", "'['", "']'", "':'", "'='", "'?'", "'.'", + "$accept", "input", "gbl_statements", "imp_statements", + "int_statements", "statement", "cppquote", "import_start", "import", + "libraryhdr", "library_start", "librarydef", "m_args", "no_args", + "args", "arg", "array", "array_list", "m_attributes", "attributes", + "attrib_list", "attribute", "callconv", "cases", "case", "constdef", + "enums", "enum_list", "enum", "enumdef", "m_expr", "expr", + "expr_list_const", "expr_const", "externdef", "fields", "field", + "s_field", "funcdef", "m_ident", "t_ident", "ident", "base_type", + "m_int", "int_std", "coclass", "coclasshdr", "coclassdef", + "coclass_ints", "coclass_int", "dispinterface", "dispinterfacehdr", + "dispint_props", "dispint_meths", "dispinterfacedef", "inherit", + "interface", "interfacehdr", "interfacedef", "interfacedec", "module", + "modulehdr", "moduledef", "p_ident", "pident", "pident_list", + "pointer_type", "structdef", "type", "typedef", "uniondef", "version", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const unsigned short yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, + 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, + 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, + 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, + 375, 376, 44, 377, 124, 38, 45, 43, 42, 47, + 126, 378, 379, 380, 59, 40, 41, 123, 125, 91, + 93, 58, 61, 63, 46 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const unsigned char yyr1[] = +{ + 0, 145, 146, 147, 147, 147, 147, 147, 147, 147, + 148, 148, 148, 148, 148, 148, 149, 149, 149, 150, + 150, 150, 150, 150, 150, 150, 150, 150, 151, 152, + 153, 154, 155, 156, 157, 157, 158, 159, 159, 159, + 160, 160, 160, 160, 161, 161, 161, 162, 162, 162, + 163, 163, 164, 165, 165, 165, 166, 166, 166, 166, + 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, + 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, + 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, + 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, + 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, + 166, 166, 166, 166, 166, 166, 166, 167, 167, 168, + 168, 169, 169, 170, 171, 171, 171, 172, 172, 173, + 173, 174, 175, 175, 176, 176, 176, 176, 176, 176, + 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, + 176, 176, 177, 177, 178, 179, 180, 180, 181, 181, + 181, 181, 182, 183, 184, 184, 185, 185, 185, 186, + 186, 186, 186, 186, 186, 187, 187, 187, 187, 187, + 187, 187, 187, 187, 187, 187, 187, 188, 188, 189, + 189, 189, 189, 189, 189, 189, 190, 190, 191, 192, + 193, 193, 194, 195, 195, 196, 197, 197, 198, 198, + 199, 200, 200, 201, 201, 202, 203, 203, 203, 204, + 204, 205, 205, 206, 207, 208, 208, 209, 209, 209, + 210, 210, 211, 211, 212, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 214, 215, 215, 216, 216 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const unsigned char yyr2[] = +{ + 0, 2, 1, 0, 2, 2, 2, 2, 2, 2, + 0, 2, 2, 2, 2, 2, 0, 3, 2, 1, + 2, 1, 2, 2, 1, 2, 2, 2, 4, 3, + 3, 2, 3, 3, 0, 1, 1, 1, 3, 1, + 4, 3, 6, 5, 0, 3, 3, 1, 3, 4, + 0, 1, 3, 1, 3, 4, 1, 1, 4, 4, + 1, 1, 1, 1, 1, 4, 4, 4, 1, 4, + 4, 4, 1, 1, 4, 4, 4, 4, 4, 1, + 4, 1, 4, 5, 1, 1, 4, 1, 1, 1, + 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 4, 1, 1, 4, 4, 4, + 1, 4, 1, 1, 4, 4, 1, 0, 1, 0, + 2, 4, 3, 5, 0, 2, 1, 1, 3, 3, + 1, 5, 0, 1, 1, 1, 1, 5, 3, 3, + 3, 3, 3, 3, 3, 3, 2, 2, 2, 4, + 4, 3, 1, 3, 1, 4, 0, 2, 2, 3, + 2, 1, 4, 7, 0, 1, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, + 2, 2, 2, 2, 1, 1, 2, 2, 2, 4, + 0, 2, 2, 2, 2, 2, 2, 3, 2, 3, + 5, 0, 2, 2, 2, 2, 5, 7, 1, 2, + 2, 2, 2, 2, 4, 2, 2, 1, 1, 3, + 1, 3, 1, 1, 5, 1, 1, 1, 2, 1, + 2, 1, 2, 1, 2, 4, 5, 10, 1, 3 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const unsigned char yydefact[] = +{ + 3, 0, 2, 1, 0, 0, 0, 166, 0, 0, + 0, 166, 50, 166, 19, 0, 9, 21, 10, 24, + 10, 8, 0, 0, 0, 0, 0, 6, 0, 0, + 218, 0, 211, 5, 4, 0, 7, 0, 0, 0, + 236, 184, 175, 195, 0, 183, 166, 185, 181, 186, + 187, 189, 194, 187, 187, 0, 182, 187, 166, 166, + 180, 235, 176, 239, 237, 177, 241, 0, 243, 0, + 203, 204, 167, 168, 0, 0, 0, 213, 214, 0, + 0, 51, 0, 56, 57, 0, 0, 60, 61, 62, + 63, 64, 0, 0, 68, 0, 0, 72, 73, 0, + 0, 0, 0, 0, 79, 0, 81, 0, 0, 84, + 85, 0, 87, 88, 89, 90, 91, 92, 93, 0, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 0, + 105, 106, 0, 0, 0, 110, 0, 112, 113, 0, + 0, 0, 53, 116, 0, 0, 0, 0, 0, 0, + 198, 205, 215, 223, 20, 22, 23, 200, 220, 0, + 219, 0, 0, 16, 25, 26, 27, 238, 240, 188, + 193, 192, 191, 178, 190, 242, 244, 179, 169, 170, + 171, 172, 173, 174, 0, 0, 124, 0, 29, 156, + 0, 0, 156, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 52, 30, 15, + 0, 13, 12, 11, 14, 33, 196, 197, 31, 221, + 222, 32, 50, 0, 50, 0, 212, 16, 50, 0, + 28, 0, 126, 127, 130, 155, 50, 0, 0, 0, + 227, 228, 230, 245, 50, 50, 0, 136, 134, 135, + 0, 0, 0, 0, 0, 154, 0, 152, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 232, 233, 0, 0, 0, 0, 0, + 0, 248, 0, 0, 54, 0, 199, 0, 201, 206, + 0, 0, 0, 50, 0, 50, 224, 18, 0, 0, + 123, 131, 125, 0, 161, 234, 0, 51, 157, 0, + 226, 225, 0, 0, 0, 246, 58, 0, 147, 148, + 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 59, 66, 65, 67, 69, 70, 71, + 74, 75, 76, 77, 78, 80, 82, 0, 86, 94, + 104, 107, 108, 109, 111, 0, 114, 115, 55, 202, + 208, 0, 207, 210, 0, 16, 216, 117, 17, 128, + 129, 243, 160, 158, 229, 231, 164, 0, 151, 0, + 144, 145, 138, 139, 141, 140, 142, 143, 0, 153, + 83, 249, 44, 209, 50, 118, 0, 159, 0, 165, + 150, 149, 0, 132, 162, 217, 0, 119, 137, 0, + 0, 47, 133, 34, 0, 46, 0, 45, 235, 0, + 39, 35, 37, 0, 0, 0, 0, 247, 120, 48, + 0, 163, 0, 0, 44, 0, 50, 49, 38, 44, + 34, 41, 50, 122, 34, 40, 0, 121, 0, 43, + 42 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const short yydefgoto[] = +{ + -1, 1, 2, 144, 238, 307, 17, 18, 19, 149, + 20, 21, 429, 430, 431, 432, 414, 420, 308, 81, + 141, 142, 406, 424, 438, 23, 241, 242, 243, 63, + 421, 265, 266, 267, 25, 246, 318, 319, 309, 408, + 74, 250, 64, 170, 65, 150, 26, 221, 232, 298, + 28, 29, 234, 303, 30, 162, 31, 32, 222, 223, + 153, 35, 224, 251, 252, 253, 143, 66, 434, 38, + 68, 292 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -395 +static const short yypact[] = +{ + -395, 59, 631, -395, 603, -65, 119, 134, 46, 88, + 136, 134, -34, 134, -395, 814, -395, -395, -395, -395, + -395, -395, 16, -27, 10, 34, 35, -395, 63, 38, + -395, 68, 69, -395, -395, 76, -395, 86, 93, 98, + -395, -395, -395, -395, 603, -395, 176, -395, -395, -395, + 62, -395, -395, 62, 62, -5, -395, 62, 185, 187, + -5, -395, -395, -395, -395, -395, -395, 13, -395, 127, + -395, -395, -395, -395, 87, 603, 102, -395, -395, 101, + 603, -395, -82, -395, -395, 15, 104, -395, -395, -395, + -395, -395, 116, 120, -395, 121, 123, -395, -395, 124, + 125, 128, 129, 130, -395, 131, -395, 132, 135, -395, + -395, 137, -395, -395, -395, -395, -395, -395, -395, 138, + -395, -395, -395, -395, -395, -395, -395, -395, -395, 139, + -395, -395, 140, 141, 142, -395, 143, -395, -395, 144, + 145, -79, -395, -395, 504, 620, 189, 251, 192, 146, + -395, -395, -395, -395, -395, -395, -395, -395, -395, 195, + -395, 196, 162, -395, -395, -395, -395, -395, 164, -395, + -395, -395, -395, -395, -395, 164, -70, -395, -395, -395, + -395, -395, -395, -395, 158, 166, 13, 13, -395, -395, + 485, 173, -395, 13, 470, 279, 264, 304, 458, 470, + 305, 308, 470, 309, 470, 13, 265, 485, -55, 485, + 470, 603, 603, 312, 317, 603, 814, 184, -395, -395, + 20, -395, -395, -395, -395, -395, -395, -395, -395, -395, + -395, -395, 66, 188, -57, 191, -395, -395, 656, 470, + -395, 194, 203, -395, 200, -395, -25, -22, 485, 485, + -395, -395, -395, 208, -34, -19, 197, -395, -395, -395, + 199, 470, 470, 470, 464, 239, -85, -395, 207, 212, + 214, 217, 219, 220, 221, 223, 224, 225, 226, 235, + 236, 341, -83, -395, -395, 237, -72, 58, 238, 240, + 241, 234, 244, 245, -395, 814, -395, 8, -395, -395, + 206, 603, 254, 92, 325, 686, -395, -395, 603, 256, + -395, -395, 13, 470, -395, -395, 603, 257, -395, 259, + -395, -395, 262, 485, 263, -395, -395, 603, 249, 249, + 249, 90, 266, 470, 470, 470, 470, 470, 470, 470, + 470, 470, 470, -395, -395, -395, -395, -395, -395, -395, + -395, -395, -395, -395, -395, -395, -395, 267, -395, -395, + -395, -395, -395, -395, -395, 389, -395, -395, -395, -395, + -395, 485, -395, -395, 281, -395, -395, 313, -395, -395, + -395, 285, -395, -395, -395, -395, 13, 284, -395, 470, + 249, 249, 258, 167, 100, 100, 23, 23, 163, -395, + -395, -395, 283, -395, 707, -395, 485, -395, 286, -395, + -395, 249, 470, 516, -395, -395, 289, -395, 239, 41, + -59, -395, 239, 299, -7, -395, 470, 287, -33, 292, + -395, 303, -395, 603, 485, 470, 290, -395, -395, 239, + 470, -395, 407, 485, -23, 211, -37, 239, -395, -11, + 299, -395, -37, -395, 299, -395, 296, -395, 297, -395, + -395 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const short yypgoto[] = +{ + -395, -395, -395, 414, -211, 7, -395, -395, 147, -395, + -395, -395, -325, -395, -395, -6, -370, -395, -9, -2, + -395, -202, -395, -395, -395, -395, -395, -395, 133, 4, + -395, -178, -395, -177, -395, 250, -394, -219, 152, -395, + 17, -60, -395, 64, 44, -395, -395, 439, -395, -395, + -17, -395, -395, -395, -395, -395, -14, -395, 444, 0, + -395, -395, 445, 209, -236, -167, 252, 9, -3, -395, + 2, -395 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -168 +static const short yytable[] = +{ + 22, 67, 34, 80, 39, 151, 24, 184, 152, 16, + 247, 37, 321, 322, 294, 302, 178, 179, 269, 435, + 300, 273, 274, 43, 191, 277, 305, 279, 79, 180, + 82, 436, 287, 333, 334, 324, -167, 342, 283, 323, + 282, 167, 286, 216, 257, 146, 258, 259, 6, 146, + 323, 343, 453, 358, 50, 192, 6, 284, 457, 3, + 6, 217, 310, 426, 360, 51, 52, -167, 333, 334, + 69, 53, 187, 181, 451, 79, 82, 190, 75, 455, + 10, 427, 15, 328, 329, 330, 331, 385, 10, -36, + 147, 54, 10, 368, 148, 76, 57, 314, 148, 173, + 333, 334, 15, -36, 177, 15, 248, 154, 182, 314, + 333, 334, 450, 315, 15, 314, 413, 171, 172, 325, + 15, 174, 70, 71, 454, 456, 244, 245, 413, 458, + 183, 437, 169, 256, 185, 402, 380, 72, 73, 77, + 78, 260, 220, 220, 155, 280, 39, 39, 24, 24, + 193, 219, 219, 37, 37, 390, 391, 392, 393, 394, + 395, 396, 397, 398, 404, 399, 341, 261, 156, 262, + 416, 263, 157, 333, 334, 159, 264, 333, 334, 168, + 73, 425, 335, 336, 337, 338, 339, 340, 175, 73, + 176, 73, 226, 227, 361, 229, 230, 158, 444, 235, + 236, 341, 160, 151, 296, 15, 152, 449, 288, 289, + 161, 411, 293, 163, 335, 336, 337, 338, 339, 340, + 164, 333, 334, 297, 186, 301, 388, 165, 339, 340, + 373, 15, 166, 341, 418, 422, 188, 316, 189, 194, + 39, 329, 24, 341, 317, 301, 316, 37, 439, 333, + 334, 195, 244, 317, 228, 196, 197, 445, 198, 199, + 200, 332, 447, 201, 202, 203, 204, 205, 333, 334, + 206, 270, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 233, 257, 231, 258, 259, 268, 335, 336, 337, + 338, 339, 340, 337, 338, 339, 340, 369, 371, 237, + 239, -167, 240, 40, 412, 377, 341, 39, 254, 24, + 341, 271, 275, 371, 37, 276, 278, 281, 381, 41, + 290, 42, 291, 295, 387, 312, 409, 43, 304, 299, + 323, 44, 311, 326, 327, 335, 336, 337, 338, 339, + 340, 45, 313, 344, 357, 46, 47, 370, 345, 48, + 346, 49, 452, 347, 341, 348, 349, 350, 50, 351, + 352, 353, 354, 335, 336, 337, 338, 339, 340, 51, + 52, 355, 356, 359, 362, 53, 363, 364, 365, 260, + 366, 367, 341, 336, 337, 338, 339, 340, 372, 9, + 378, 382, 341, 383, 401, 54, 55, 56, 384, 386, + 57, 341, 389, 400, 58, 261, 39, 262, 24, 263, + 59, 40, 60, 37, 264, 403, 405, 428, 62, 407, + 410, 433, 413, 417, 423, 442, 440, 41, 441, 42, + 443, 446, 459, 460, 145, 43, 448, 316, 15, 44, + 433, 27, 255, 316, 317, 379, 33, 36, 433, 45, + 317, 375, 433, 46, 47, 374, 320, 48, 0, 49, + 285, 257, 0, 258, 259, 272, 50, 257, 40, 258, + 259, 0, 0, 257, 0, 258, 259, 51, 52, 0, + 0, 0, 0, 53, 41, 0, 42, 0, 178, 179, + 0, 0, 43, 0, 0, 0, 44, 0, 0, 0, + 0, 180, 0, 54, 55, 56, 45, 0, 57, 0, + 46, 47, 58, 218, 48, 0, 49, 247, 59, 257, + 60, 258, 259, 50, 0, 61, 62, 0, 0, 0, + 0, 0, 0, 0, 51, 52, 4, 0, 0, 0, + 53, 5, 0, 0, 6, 181, 15, 0, 0, 0, + 7, 0, 0, 8, 0, 0, 0, 0, 260, 0, + 54, 55, 56, 0, 260, 57, 0, 0, 9, 58, + 260, 0, 0, 0, 0, 59, 10, 60, 0, 0, + 182, 0, 61, 62, 261, 0, 262, 0, 263, 0, + 261, 0, 262, 264, 263, 0, 261, 0, 262, 264, + 263, 0, 183, 0, 0, 264, 0, 40, 0, 11, + 0, 0, 0, 248, 12, 13, 260, 0, 0, 0, + 249, 0, 0, 41, 0, 42, 0, 0, 0, 0, + 0, 43, 0, 0, 0, 44, 0, 0, 14, 0, + 0, 0, 261, 15, 419, 45, 263, 0, 0, 46, + 47, 264, 4, 48, 0, 49, 0, 5, 0, 0, + 6, 0, 50, 4, 0, 0, 7, 0, 5, 8, + 0, 6, 0, 51, 52, 0, 0, 7, 0, 53, + 8, 0, 0, 0, 9, 0, 0, 0, 4, 0, + 0, 0, 10, 5, 0, 9, 0, 0, 0, 54, + 55, 56, 7, 10, 57, 8, 0, 0, 58, 0, + 0, 0, 0, 0, 59, 0, 60, 0, 4, 0, + 9, 61, 62, 5, 0, 11, 0, 0, 0, 0, + 12, 13, 7, 0, 0, 8, 11, 0, 0, 4, + 0, 12, 13, 0, 5, 0, 0, 0, 0, 0, + 9, 0, 0, 7, 14, 0, 8, 0, 225, 15, + 0, 11, 0, 0, 0, 14, 12, 13, 0, 0, + 15, 9, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 14, 11, 0, 0, 306, 15, 12, 13, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 11, 0, 0, 0, 0, 12, 13, 0, + 14, 0, 0, 0, 376, 15, 0, 0, 0, 0, + 83, 0, 84, 0, 0, 0, 0, 0, 85, 0, + 86, 14, 0, 0, 0, 415, 15, 87, 88, 89, + 90, 0, 91, 92, 0, 93, 0, 94, 95, 96, + 0, 0, 97, 0, 0, 98, 0, 99, 100, 101, + 102, 103, 104, 0, 105, 106, 107, 108, 0, 0, + 109, 0, 0, 110, 0, 0, 0, 111, 0, 112, + 0, 0, 0, 113, 114, 115, 116, 117, 118, 119, + 0, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 0, 0, 0, 129, 0, 0, 130, 0, 131, 0, + 0, 132, 133, 134, 0, 0, 135, 0, 136, 137, + 138, 139, 0, 0, 140 +}; + +static const short yycheck[] = +{ + 2, 4, 2, 12, 2, 22, 2, 67, 22, 2, + 32, 2, 248, 249, 216, 234, 3, 4, 195, 26, + 77, 198, 199, 28, 106, 202, 237, 204, 11, 16, + 13, 38, 210, 10, 11, 254, 106, 122, 93, 122, + 207, 44, 209, 122, 3, 29, 5, 6, 40, 29, + 122, 136, 446, 136, 59, 137, 40, 112, 452, 0, + 40, 140, 239, 122, 136, 70, 71, 137, 10, 11, + 135, 76, 75, 60, 444, 58, 59, 80, 32, 449, + 72, 140, 139, 261, 262, 263, 264, 323, 72, 122, + 74, 96, 72, 295, 78, 7, 101, 134, 78, 55, + 10, 11, 139, 136, 60, 139, 128, 134, 95, 134, + 10, 11, 135, 138, 139, 134, 139, 53, 54, 138, + 139, 57, 3, 4, 135, 450, 186, 187, 139, 454, + 117, 138, 70, 193, 7, 371, 313, 3, 4, 3, + 4, 100, 144, 145, 134, 205, 144, 145, 144, 145, + 135, 144, 145, 144, 145, 333, 334, 335, 336, 337, + 338, 339, 340, 341, 375, 342, 143, 126, 134, 128, + 406, 130, 137, 10, 11, 137, 135, 10, 11, 3, + 4, 140, 124, 125, 126, 127, 128, 129, 3, 4, + 3, 4, 3, 4, 136, 3, 4, 134, 434, 3, + 4, 143, 134, 220, 138, 139, 220, 443, 211, 212, + 141, 389, 215, 137, 124, 125, 126, 127, 128, 129, + 134, 10, 11, 232, 137, 234, 136, 134, 128, 129, + 138, 139, 134, 143, 412, 413, 134, 246, 137, 135, + 238, 419, 238, 143, 246, 254, 255, 238, 426, 10, + 11, 135, 312, 255, 3, 135, 135, 435, 135, 135, + 135, 264, 440, 135, 135, 135, 135, 135, 10, 11, + 135, 7, 135, 135, 135, 135, 135, 135, 135, 135, + 135, 86, 3, 137, 5, 6, 7, 124, 125, 126, + 127, 128, 129, 126, 127, 128, 129, 297, 301, 137, + 142, 137, 136, 4, 141, 308, 143, 305, 135, 305, + 143, 7, 7, 316, 305, 7, 7, 52, 316, 20, + 8, 22, 5, 139, 327, 122, 386, 28, 137, 141, + 122, 32, 138, 136, 135, 124, 125, 126, 127, 128, + 129, 42, 142, 136, 3, 46, 47, 141, 136, 50, + 136, 52, 141, 136, 143, 136, 136, 136, 59, 136, + 136, 136, 136, 124, 125, 126, 127, 128, 129, 70, + 71, 136, 136, 136, 136, 76, 136, 136, 144, 100, + 136, 136, 143, 125, 126, 127, 128, 129, 134, 64, + 134, 134, 143, 134, 5, 96, 97, 98, 136, 136, + 101, 143, 136, 136, 105, 126, 404, 128, 404, 130, + 111, 4, 113, 404, 135, 134, 103, 118, 119, 134, + 136, 423, 139, 137, 135, 122, 139, 20, 136, 22, + 433, 141, 136, 136, 20, 28, 442, 446, 139, 32, + 442, 2, 192, 452, 446, 312, 2, 2, 450, 42, + 452, 304, 454, 46, 47, 303, 247, 50, -1, 52, + 208, 3, -1, 5, 6, 7, 59, 3, 4, 5, + 6, -1, -1, 3, -1, 5, 6, 70, 71, -1, + -1, -1, -1, 76, 20, -1, 22, -1, 3, 4, + -1, -1, 28, -1, -1, -1, 32, -1, -1, -1, + -1, 16, -1, 96, 97, 98, 42, -1, 101, -1, + 46, 47, 105, 9, 50, -1, 52, 32, 111, 3, + 113, 5, 6, 59, -1, 118, 119, -1, -1, -1, + -1, -1, -1, -1, 70, 71, 32, -1, -1, -1, + 76, 37, -1, -1, 40, 60, 139, -1, -1, -1, + 46, -1, -1, 49, -1, -1, -1, -1, 100, -1, + 96, 97, 98, -1, 100, 101, -1, -1, 64, 105, + 100, -1, -1, -1, -1, 111, 72, 113, -1, -1, + 95, -1, 118, 119, 126, -1, 128, -1, 130, -1, + 126, -1, 128, 135, 130, -1, 126, -1, 128, 135, + 130, -1, 117, -1, -1, 135, -1, 4, -1, 105, + -1, -1, -1, 128, 110, 111, 100, -1, -1, -1, + 135, -1, -1, 20, -1, 22, -1, -1, -1, -1, + -1, 28, -1, -1, -1, 32, -1, -1, 134, -1, + -1, -1, 126, 139, 128, 42, 130, -1, -1, 46, + 47, 135, 32, 50, -1, 52, -1, 37, -1, -1, + 40, -1, 59, 32, -1, -1, 46, -1, 37, 49, + -1, 40, -1, 70, 71, -1, -1, 46, -1, 76, + 49, -1, -1, -1, 64, -1, -1, -1, 32, -1, + -1, -1, 72, 37, -1, 64, -1, -1, -1, 96, + 97, 98, 46, 72, 101, 49, -1, -1, 105, -1, + -1, -1, -1, -1, 111, -1, 113, -1, 32, -1, + 64, 118, 119, 37, -1, 105, -1, -1, -1, -1, + 110, 111, 46, -1, -1, 49, 105, -1, -1, 32, + -1, 110, 111, -1, 37, -1, -1, -1, -1, -1, + 64, -1, -1, 46, 134, -1, 49, -1, 138, 139, + -1, 105, -1, -1, -1, 134, 110, 111, -1, -1, + 139, 64, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 134, 105, -1, -1, 138, 139, 110, 111, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 105, -1, -1, -1, -1, 110, 111, -1, + 134, -1, -1, -1, 138, 139, -1, -1, -1, -1, + 16, -1, 18, -1, -1, -1, -1, -1, 24, -1, + 26, 134, -1, -1, -1, 138, 139, 33, 34, 35, + 36, -1, 38, 39, -1, 41, -1, 43, 44, 45, + -1, -1, 48, -1, -1, 51, -1, 53, 54, 55, + 56, 57, 58, -1, 60, 61, 62, 63, -1, -1, + 66, -1, -1, 69, -1, -1, -1, 73, -1, 75, + -1, -1, -1, 79, 80, 81, 82, 83, 84, 85, + -1, 87, 88, 89, 90, 91, 92, 93, 94, 95, + -1, -1, -1, 99, -1, -1, 102, -1, 104, -1, + -1, 107, 108, 109, -1, -1, 112, -1, 114, 115, + 116, 117, -1, -1, 120 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const unsigned char yystos[] = +{ + 0, 146, 147, 0, 32, 37, 40, 46, 49, 64, + 72, 105, 110, 111, 134, 139, 150, 151, 152, 153, + 155, 156, 164, 170, 174, 179, 191, 192, 195, 196, + 199, 201, 202, 203, 204, 206, 207, 212, 214, 215, + 4, 20, 22, 28, 32, 42, 46, 47, 50, 52, + 59, 70, 71, 76, 96, 97, 98, 101, 105, 111, + 113, 118, 119, 174, 187, 189, 212, 213, 215, 135, + 3, 4, 3, 4, 185, 32, 7, 3, 4, 185, + 163, 164, 185, 16, 18, 24, 26, 33, 34, 35, + 36, 38, 39, 41, 43, 44, 45, 48, 51, 53, + 54, 55, 56, 57, 58, 60, 61, 62, 63, 66, + 69, 73, 75, 79, 80, 81, 82, 83, 84, 85, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 99, + 102, 104, 107, 108, 109, 112, 114, 115, 116, 117, + 120, 165, 166, 211, 148, 148, 29, 74, 78, 154, + 190, 195, 201, 205, 134, 134, 134, 137, 134, 137, + 134, 141, 200, 137, 134, 134, 134, 213, 3, 70, + 188, 188, 188, 189, 188, 3, 3, 189, 3, 4, + 16, 60, 95, 117, 186, 7, 137, 213, 134, 137, + 213, 106, 137, 135, 135, 135, 135, 135, 135, 135, + 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, + 135, 135, 135, 135, 135, 135, 122, 140, 9, 150, + 164, 192, 203, 204, 207, 138, 3, 4, 3, 3, + 4, 137, 193, 86, 197, 3, 4, 137, 149, 142, + 136, 171, 172, 173, 186, 186, 180, 32, 128, 135, + 186, 208, 209, 210, 135, 180, 186, 3, 5, 6, + 100, 126, 128, 130, 135, 176, 177, 178, 7, 178, + 7, 7, 7, 178, 178, 7, 7, 178, 7, 178, + 186, 52, 210, 93, 112, 211, 210, 176, 213, 213, + 8, 5, 216, 213, 166, 139, 138, 163, 194, 141, + 77, 163, 182, 198, 137, 149, 138, 150, 163, 183, + 178, 138, 122, 142, 134, 138, 163, 164, 181, 182, + 208, 209, 209, 122, 182, 138, 136, 135, 176, 176, + 176, 176, 213, 10, 11, 124, 125, 126, 127, 128, + 129, 143, 122, 136, 136, 136, 136, 136, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 3, 136, 136, + 136, 136, 136, 136, 136, 144, 136, 136, 166, 204, + 141, 213, 134, 138, 183, 153, 138, 213, 134, 173, + 178, 215, 134, 134, 136, 209, 136, 213, 136, 136, + 176, 176, 176, 176, 176, 176, 176, 176, 176, 178, + 136, 5, 209, 134, 149, 103, 167, 134, 184, 186, + 136, 176, 141, 139, 161, 138, 209, 137, 176, 128, + 162, 175, 176, 135, 168, 140, 122, 140, 118, 157, + 158, 159, 160, 164, 213, 26, 38, 138, 169, 176, + 139, 136, 122, 213, 209, 176, 141, 176, 160, 209, + 135, 161, 141, 181, 135, 161, 157, 181, 157, 136, + 136 +}; + +#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) +# define YYSIZE_T __SIZE_TYPE__ +#endif +#if ! defined (YYSIZE_T) && defined (size_t) +# define YYSIZE_T size_t +#endif +#if ! defined (YYSIZE_T) +# if defined (__STDC__) || defined (__cplusplus) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +#endif +#if ! defined (YYSIZE_T) +# define YYSIZE_T unsigned int +#endif + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrlab1 + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror ("syntax error: cannot back up");\ + YYERROR; \ + } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +/* YYLLOC_DEFAULT -- Compute the default location (before the actions + are run). */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + Current.first_line = Rhs[1].first_line; \ + Current.first_column = Rhs[1].first_column; \ + Current.last_line = Rhs[N].last_line; \ + Current.last_column = Rhs[N].last_column; +#endif + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +# define YYDSYMPRINT(Args) \ +do { \ + if (yydebug) \ + yysymprint Args; \ +} while (0) + +# define YYDSYMPRINTF(Title, Token, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yysymprint (stderr, \ + Token, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (cinluded). | +`------------------------------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yy_stack_print (short *bottom, short *top) +#else +static void +yy_stack_print (bottom, top) + short *bottom; + short *top; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (/* Nothing. */; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yy_reduce_print (int yyrule) +#else +static void +yy_reduce_print (yyrule) + int yyrule; +#endif +{ + int yyi; + unsigned int yylineno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ", + yyrule - 1, yylineno); + /* Print the symbols being reduced, and their result. */ + for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++) + YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]); + YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]); +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (Rule); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YYDSYMPRINT(Args) +# define YYDSYMPRINTF(Title, Token, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#if YYMAXDEPTH == 0 +# undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined (__GLIBC__) && defined (_STRING_H) +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +# if defined (__STDC__) || defined (__cplusplus) +yystrlen (const char *yystr) +# else +yystrlen (yystr) + const char *yystr; +# endif +{ + register const char *yys = yystr; + + while (*yys++ != '\0') + continue; + + return yys - yystr - 1; +} +# endif +# endif + +# ifndef yystpcpy +# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +# if defined (__STDC__) || defined (__cplusplus) +yystpcpy (char *yydest, const char *yysrc) +# else +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +# endif +{ + register char *yyd = yydest; + register const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +#endif /* !YYERROR_VERBOSE */ + + + +#if YYDEBUG +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep) +#else +static void +yysymprint (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + /* Pacify ``unused variable'' warnings. */ + (void) yyvaluep; + + if (yytype < YYNTOKENS) + { + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); +# ifdef YYPRINT + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + } + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + switch (yytype) + { + default: + break; + } + YYFPRINTF (yyoutput, ")"); +} + +#endif /* ! YYDEBUG */ +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yydestruct (int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yytype, yyvaluep) + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + /* Pacify ``unused variable'' warnings. */ + (void) yyvaluep; + + switch (yytype) + { + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +int yyparse (void *YYPARSE_PARAM); +# else +int yyparse (); +# endif +#else /* ! YYPARSE_PARAM */ +#if defined (__STDC__) || defined (__cplusplus) +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +int yyparse (void *YYPARSE_PARAM) +# else +int yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +# endif +#else /* ! YYPARSE_PARAM */ +#if defined (__STDC__) || defined (__cplusplus) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + + register int yystate; + register int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + short yyssa[YYINITDEPTH]; + short *yyss = yyssa; + register short *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + register YYSTYPE *yyvsp; + + + +#define YYPOPSTACK (yyvsp--, yyssp--) + + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + + /* When reducing, the number of symbols on the RHS of the reduced + rule. */ + int yylen; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. + */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; + + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyoverflowlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyoverflowlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + short *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyoverflowlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken])); + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; + + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + yystate = yyn; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: +#line 228 "parser.y" + { write_proxies(yyvsp[0].ifref); write_client(yyvsp[0].ifref); write_server(yyvsp[0].ifref); ;} + break; + + case 3: +#line 231 "parser.y" + { yyval.ifref = NULL; ;} + break; + + case 4: +#line 232 "parser.y" + { yyval.ifref = yyvsp[-1].ifref; ;} + break; + + case 5: +#line 233 "parser.y" + { yyval.ifref = make_ifref(yyvsp[0].type); LINK(yyval.ifref, yyvsp[-1].ifref); ;} + break; + + case 6: +#line 234 "parser.y" + { yyval.ifref = yyvsp[-1].ifref; add_coclass(yyvsp[0].clas); ;} + break; + + case 7: +#line 235 "parser.y" + { yyval.ifref = yyvsp[-1].ifref; add_module(yyvsp[0].type); ;} + break; + + case 8: +#line 236 "parser.y" + { yyval.ifref = yyvsp[-1].ifref; ;} + break; + + case 9: +#line 237 "parser.y" + { yyval.ifref = yyvsp[-1].ifref; ;} + break; + + case 10: +#line 240 "parser.y" + {;} + break; + + case 11: +#line 241 "parser.y" + { if (!parse_only) add_interface(yyvsp[0].type); ;} + break; + + case 12: +#line 242 "parser.y" + { if (!parse_only) add_interface(yyvsp[0].type); ;} + break; + + case 13: +#line 243 "parser.y" + { if (!parse_only) add_coclass(yyvsp[0].clas); ;} + break; + + case 14: +#line 244 "parser.y" + { if (!parse_only) add_module(yyvsp[0].type); ;} + break; + + case 15: +#line 245 "parser.y" + {;} + break; + + case 16: +#line 248 "parser.y" + { yyval.func = NULL; ;} + break; + + case 17: +#line 249 "parser.y" + { yyval.func = yyvsp[-1].func; LINK(yyval.func, yyvsp[-2].func); ;} + break; + + case 18: +#line 250 "parser.y" + { yyval.func = yyvsp[-1].func; ;} + break; + + case 19: +#line 253 "parser.y" + {;} + break; + + case 20: +#line 254 "parser.y" + { if (!parse_only && do_header) { write_constdef(yyvsp[-1].var); } ;} + break; + + case 21: +#line 255 "parser.y" + {;} + break; + + case 22: +#line 256 "parser.y" + { if (!parse_only && do_header) { write_type(header, yyvsp[-1].type, NULL, NULL); fprintf(header, ";\n\n"); } ;} + break; + + case 23: +#line 257 "parser.y" + { if (!parse_only && do_header) { write_externdef(yyvsp[-1].var); } ;} + break; + + case 24: +#line 258 "parser.y" + {;} + break; + + case 25: +#line 259 "parser.y" + { if (!parse_only && do_header) { write_type(header, yyvsp[-1].type, NULL, NULL); fprintf(header, ";\n\n"); } ;} + break; + + case 26: +#line 260 "parser.y" + {;} + break; + + case 27: +#line 261 "parser.y" + { if (!parse_only && do_header) { write_type(header, yyvsp[-1].type, NULL, NULL); fprintf(header, ";\n\n"); } ;} + break; + + case 28: +#line 264 "parser.y" + { if (!parse_only && do_header) fprintf(header, "%s\n", yyvsp[-1].str); ;} + break; + + case 29: +#line 266 "parser.y" + { assert(yychar == YYEMPTY); + if (!do_import(yyvsp[-1].str)) yychar = aEOF; ;} + break; + + case 30: +#line 269 "parser.y" + {;} + break; + + case 31: +#line 272 "parser.y" + { yyval.str = yyvsp[0].str; ;} + break; + + case 32: +#line 274 "parser.y" + { start_typelib(yyvsp[-1].str, yyvsp[-2].attr); ;} + break; + + case 33: +#line 276 "parser.y" + { end_typelib(); ;} + break; + + case 34: +#line 279 "parser.y" + { yyval.var = NULL; ;} + break; + + case 36: +#line 283 "parser.y" + { yyval.var = NULL; ;} + break; + + case 38: +#line 287 "parser.y" + { LINK(yyvsp[0].var, yyvsp[-2].var); yyval.var = yyvsp[0].var; ;} + break; + + case 40: +#line 292 "parser.y" + { yyval.var = yyvsp[-1].var; + set_type(yyval.var, yyvsp[-2].tref, yyvsp[0].expr); + yyval.var->attrs = yyvsp[-3].attr; + ;} + break; + + case 41: +#line 296 "parser.y" + { yyval.var = yyvsp[-1].var; + set_type(yyval.var, yyvsp[-2].tref, yyvsp[0].expr); + ;} + break; + + case 42: +#line 299 "parser.y" + { yyval.var = yyvsp[-3].var; + yyval.var->ptr_level--; + set_type(yyval.var, yyvsp[-4].tref, NULL); + yyval.var->attrs = yyvsp[-5].attr; + yyval.var->args = yyvsp[-1].var; + ;} + break; + + case 43: +#line 305 "parser.y" + { yyval.var = yyvsp[-3].var; + yyval.var->ptr_level--; + set_type(yyval.var, yyvsp[-4].tref, NULL); + yyval.var->args = yyvsp[-1].var; + ;} + break; + + case 44: +#line 312 "parser.y" + { yyval.expr = NULL; ;} + break; + + case 45: +#line 313 "parser.y" + { yyval.expr = yyvsp[-1].expr; ;} + break; + + case 46: +#line 314 "parser.y" + { yyval.expr = make_expr(EXPR_VOID); ;} + break; + + case 48: +#line 318 "parser.y" + { LINK(yyvsp[0].expr, yyvsp[-2].expr); yyval.expr = yyvsp[0].expr; ;} + break; + + case 49: +#line 319 "parser.y" + { LINK(yyvsp[0].expr, yyvsp[-3].expr); yyval.expr = yyvsp[0].expr; ;} + break; + + case 50: +#line 322 "parser.y" + { yyval.attr = NULL; ;} + break; + + case 52: +#line 327 "parser.y" + { yyval.attr = yyvsp[-1].attr; ;} + break; + + case 54: +#line 331 "parser.y" + { LINK(yyvsp[0].attr, yyvsp[-2].attr); yyval.attr = yyvsp[0].attr; ;} + break; + + case 55: +#line 332 "parser.y" + { LINK(yyvsp[0].attr, yyvsp[-3].attr); yyval.attr = yyvsp[0].attr; ;} + break; + + case 56: +#line 336 "parser.y" + { yyval.attr = make_attr(ATTR_ASYNC); ;} + break; + + case 57: +#line 337 "parser.y" + { yyval.attr = make_attr(ATTR_AUTO_HANDLE); ;} + break; + + case 58: +#line 338 "parser.y" + { yyval.attr = make_attrp(ATTR_CALLAS, yyvsp[-1].var); ;} + break; + + case 59: +#line 339 "parser.y" + { yyval.attr = make_attrp(ATTR_CASE, yyvsp[-1].expr); ;} + break; + + case 60: +#line 340 "parser.y" + { yyval.attr = make_attrv(ATTR_CONTEXTHANDLE, 0); ;} + break; + + case 61: +#line 341 "parser.y" + { yyval.attr = make_attrv(ATTR_CONTEXTHANDLE, 0); /* RPC_CONTEXT_HANDLE_DONT_SERIALIZE */ ;} + break; + + case 62: +#line 342 "parser.y" + { yyval.attr = make_attrv(ATTR_CONTEXTHANDLE, 0); /* RPC_CONTEXT_HANDLE_SERIALIZE */ ;} + break; + + case 63: +#line 343 "parser.y" + { yyval.attr = make_attr(ATTR_CONTROL); ;} + break; + + case 64: +#line 344 "parser.y" + { yyval.attr = make_attr(ATTR_DEFAULT); ;} + break; + + case 65: +#line 345 "parser.y" + { yyval.attr = make_attrp(ATTR_DEFAULTVALUE_EXPR, yyvsp[-1].expr); ;} + break; + + case 66: +#line 346 "parser.y" + { yyval.attr = make_attrp(ATTR_DEFAULTVALUE_STRING, yyvsp[-1].str); ;} + break; + + case 67: +#line 347 "parser.y" + { yyval.attr = make_attrp(ATTR_DLLNAME, yyvsp[-1].str); ;} + break; + + case 68: +#line 348 "parser.y" + { yyval.attr = make_attr(ATTR_DUAL); ;} + break; + + case 69: +#line 349 "parser.y" + { yyval.attr = make_attrp(ATTR_ENDPOINT, yyvsp[-1].str); ;} + break; + + case 70: +#line 350 "parser.y" + { yyval.attr = make_attrp(ATTR_ENTRY_STRING, yyvsp[-1].str); ;} + break; + + case 71: +#line 351 "parser.y" + { yyval.attr = make_attrp(ATTR_ENTRY_ORDINAL, yyvsp[-1].expr); ;} + break; + + case 72: +#line 352 "parser.y" + { yyval.attr = make_attr(ATTR_EXPLICIT_HANDLE); ;} + break; + + case 73: +#line 353 "parser.y" + { yyval.attr = make_attr(ATTR_HANDLE); ;} + break; + + case 74: +#line 354 "parser.y" + { yyval.attr = make_attrp(ATTR_HELPCONTEXT, yyvsp[-1].expr); ;} + break; + + case 75: +#line 355 "parser.y" + { yyval.attr = make_attrp(ATTR_HELPFILE, yyvsp[-1].str); ;} + break; + + case 76: +#line 356 "parser.y" + { yyval.attr = make_attrp(ATTR_HELPSTRING, yyvsp[-1].str); ;} + break; + + case 77: +#line 357 "parser.y" + { yyval.attr = make_attrp(ATTR_HELPSTRINGCONTEXT, yyvsp[-1].expr); ;} + break; + + case 78: +#line 358 "parser.y" + { yyval.attr = make_attrp(ATTR_HELPSTRINGDLL, yyvsp[-1].str); ;} + break; + + case 79: +#line 359 "parser.y" + { yyval.attr = make_attr(ATTR_HIDDEN); ;} + break; + + case 80: +#line 360 "parser.y" + { yyval.attr = make_attrp(ATTR_ID, yyvsp[-1].expr); ;} + break; + + case 81: +#line 361 "parser.y" + { yyval.attr = make_attr(ATTR_IDEMPOTENT); ;} + break; + + case 82: +#line 362 "parser.y" + { yyval.attr = make_attrp(ATTR_IIDIS, yyvsp[-1].var); ;} + break; + + case 83: +#line 363 "parser.y" + { yyval.attr = make_attrp(ATTR_IMPLICIT_HANDLE, yyvsp[-1].str); ;} + break; + + case 84: +#line 364 "parser.y" + { yyval.attr = make_attr(ATTR_IN); ;} + break; + + case 85: +#line 365 "parser.y" + { yyval.attr = make_attr(ATTR_INPUTSYNC); ;} + break; + + case 86: +#line 366 "parser.y" + { yyval.attr = make_attrp(ATTR_LENGTHIS, yyvsp[-1].var); ;} + break; + + case 87: +#line 367 "parser.y" + { yyval.attr = make_attr(ATTR_LOCAL); ;} + break; + + case 88: +#line 368 "parser.y" + { yyval.attr = make_attr(ATTR_NONCREATABLE); ;} + break; + + case 89: +#line 369 "parser.y" + { yyval.attr = make_attr(ATTR_OBJECT); ;} + break; + + case 90: +#line 370 "parser.y" + { yyval.attr = make_attr(ATTR_ODL); ;} + break; + + case 91: +#line 371 "parser.y" + { yyval.attr = make_attr(ATTR_OLEAUTOMATION); ;} + break; + + case 92: +#line 372 "parser.y" + { yyval.attr = make_attr(ATTR_OPTIONAL); ;} + break; + + case 93: +#line 373 "parser.y" + { yyval.attr = make_attr(ATTR_OUT); ;} + break; + + case 94: +#line 374 "parser.y" + { yyval.attr = make_attrv(ATTR_POINTERDEFAULT, yyvsp[-1].num); ;} + break; + + case 95: +#line 375 "parser.y" + { yyval.attr = make_attr(ATTR_PROPGET); ;} + break; + + case 96: +#line 376 "parser.y" + { yyval.attr = make_attr(ATTR_PROPPUT); ;} + break; + + case 97: +#line 377 "parser.y" + { yyval.attr = make_attr(ATTR_PROPPUTREF); ;} + break; + + case 98: +#line 378 "parser.y" + { yyval.attr = make_attr(ATTR_PTR); ;} + break; + + case 99: +#line 379 "parser.y" + { yyval.attr = make_attr(ATTR_PUBLIC); ;} + break; + + case 100: +#line 380 "parser.y" + { yyval.attr = make_attr(ATTR_READONLY); ;} + break; + + case 101: +#line 381 "parser.y" + { yyval.attr = make_attr(ATTR_REF); ;} + break; + + case 102: +#line 382 "parser.y" + { yyval.attr = make_attr(ATTR_RESTRICTED); ;} + break; + + case 103: +#line 383 "parser.y" + { yyval.attr = make_attr(ATTR_RETVAL); ;} + break; + + case 104: +#line 384 "parser.y" + { yyval.attr = make_attrp(ATTR_SIZEIS, yyvsp[-1].var); ;} + break; + + case 105: +#line 385 "parser.y" + { yyval.attr = make_attr(ATTR_SOURCE); ;} + break; + + case 106: +#line 386 "parser.y" + { yyval.attr = make_attr(ATTR_STRING); ;} + break; + + case 107: +#line 387 "parser.y" + { yyval.attr = make_attrp(ATTR_SWITCHIS, yyvsp[-1].expr); ;} + break; + + case 108: +#line 388 "parser.y" + { yyval.attr = make_attrp(ATTR_SWITCHTYPE, type_ref(yyvsp[-1].tref)); ;} + break; + + case 109: +#line 389 "parser.y" + { yyval.attr = make_attrp(ATTR_TRANSMITAS, type_ref(yyvsp[-1].tref)); ;} + break; + + case 110: +#line 390 "parser.y" + { yyval.attr = make_attr(ATTR_UNIQUE); ;} + break; + + case 111: +#line 391 "parser.y" + { yyval.attr = make_attrp(ATTR_UUID, yyvsp[-1].uuid); ;} + break; + + case 112: +#line 392 "parser.y" + { yyval.attr = make_attr(ATTR_V1ENUM); ;} + break; + + case 113: +#line 393 "parser.y" + { yyval.attr = make_attr(ATTR_VARARG); ;} + break; + + case 114: +#line 394 "parser.y" + { yyval.attr = make_attrv(ATTR_VERSION, yyvsp[-1].num); ;} + break; + + case 115: +#line 395 "parser.y" + { yyval.attr = make_attrp(ATTR_WIREMARSHAL, type_ref(yyvsp[-1].tref)); ;} + break; + + case 116: +#line 396 "parser.y" + { yyval.attr = make_attrv(ATTR_POINTERTYPE, yyvsp[0].num); ;} + break; + + case 119: +#line 403 "parser.y" + { yyval.var = NULL; ;} + break; + + case 120: +#line 404 "parser.y" + { if (yyvsp[0].var) { LINK(yyvsp[0].var, yyvsp[-1].var); yyval.var = yyvsp[0].var; } + else { yyval.var = yyvsp[-1].var; } + ;} + break; + + case 121: +#line 409 "parser.y" + { attr_t *a = make_attrp(ATTR_CASE, yyvsp[-2].expr); + yyval.var = yyvsp[0].var; if (!yyval.var) yyval.var = make_var(NULL); + LINK(a, yyval.var->attrs); yyval.var->attrs = a; + ;} + break; + + case 122: +#line 413 "parser.y" + { attr_t *a = make_attr(ATTR_DEFAULT); + yyval.var = yyvsp[0].var; if (!yyval.var) yyval.var = make_var(NULL); + LINK(a, yyval.var->attrs); yyval.var->attrs = a; + ;} + break; + + case 123: +#line 419 "parser.y" + { yyval.var = reg_const(yyvsp[-2].var); + set_type(yyval.var, yyvsp[-3].tref, NULL); + yyval.var->eval = yyvsp[0].expr; + yyval.var->lval = yyvsp[0].expr->cval; + ;} + break; + + case 124: +#line 426 "parser.y" + { yyval.var = NULL; ;} + break; + + case 125: +#line 427 "parser.y" + { yyval.var = yyvsp[-1].var; ;} + break; + + case 128: +#line 432 "parser.y" + { LINK(yyvsp[0].var, yyvsp[-2].var); yyval.var = yyvsp[0].var; + if (yyvsp[-2].var && !yyvsp[0].var->eval) + yyvsp[0].var->lval = yyvsp[-2].var->lval + 1; + ;} + break; + + case 129: +#line 438 "parser.y" + { yyval.var = reg_const(yyvsp[-2].var); + yyval.var->eval = yyvsp[0].expr; + yyval.var->lval = yyvsp[0].expr->cval; + yyval.var->type = make_type(RPC_FC_LONG, &std_int); + ;} + break; + + case 130: +#line 443 "parser.y" + { yyval.var = reg_const(yyvsp[0].var); + yyval.var->lval = 0; /* default for first enum entry */ + yyval.var->type = make_type(RPC_FC_LONG, &std_int); + ;} + break; + + case 131: +#line 449 "parser.y" + { yyval.type = get_typev(RPC_FC_ENUM16, yyvsp[-3].var, tsENUM); + yyval.type->fields = yyvsp[-1].var; + yyval.type->defined = TRUE; + if(in_typelib) + add_enum(yyval.type); + ;} + break; + + case 132: +#line 471 "parser.y" + { yyval.expr = make_expr(EXPR_VOID); ;} + break; + + case 134: +#line 475 "parser.y" + { yyval.expr = make_exprl(EXPR_NUM, yyvsp[0].num); ;} + break; + + case 135: +#line 476 "parser.y" + { yyval.expr = make_exprl(EXPR_HEXNUM, yyvsp[0].num); ;} + break; + + case 136: +#line 477 "parser.y" + { yyval.expr = make_exprs(EXPR_IDENTIFIER, yyvsp[0].str); ;} + break; + + case 137: +#line 478 "parser.y" + { yyval.expr = make_expr3(EXPR_COND, yyvsp[-4].expr, yyvsp[-2].expr, yyvsp[0].expr); ;} + break; + + case 138: +#line 479 "parser.y" + { yyval.expr = make_expr2(EXPR_OR , yyvsp[-2].expr, yyvsp[0].expr); ;} + break; + + case 139: +#line 480 "parser.y" + { yyval.expr = make_expr2(EXPR_AND, yyvsp[-2].expr, yyvsp[0].expr); ;} + break; + + case 140: +#line 481 "parser.y" + { yyval.expr = make_expr2(EXPR_ADD, yyvsp[-2].expr, yyvsp[0].expr); ;} + break; + + case 141: +#line 482 "parser.y" + { yyval.expr = make_expr2(EXPR_SUB, yyvsp[-2].expr, yyvsp[0].expr); ;} + break; + + case 142: +#line 483 "parser.y" + { yyval.expr = make_expr2(EXPR_MUL, yyvsp[-2].expr, yyvsp[0].expr); ;} + break; + + case 143: +#line 484 "parser.y" + { yyval.expr = make_expr2(EXPR_DIV, yyvsp[-2].expr, yyvsp[0].expr); ;} + break; + + case 144: +#line 485 "parser.y" + { yyval.expr = make_expr2(EXPR_SHL, yyvsp[-2].expr, yyvsp[0].expr); ;} + break; + + case 145: +#line 486 "parser.y" + { yyval.expr = make_expr2(EXPR_SHR, yyvsp[-2].expr, yyvsp[0].expr); ;} + break; + + case 146: +#line 487 "parser.y" + { yyval.expr = make_expr1(EXPR_NOT, yyvsp[0].expr); ;} + break; + + case 147: +#line 488 "parser.y" + { yyval.expr = make_expr1(EXPR_NEG, yyvsp[0].expr); ;} + break; + + case 148: +#line 489 "parser.y" + { yyval.expr = make_expr1(EXPR_PPTR, yyvsp[0].expr); ;} + break; + + case 149: +#line 490 "parser.y" + { yyval.expr = make_exprt(EXPR_CAST, yyvsp[-2].tref, yyvsp[0].expr); ;} + break; + + case 150: +#line 491 "parser.y" + { yyval.expr = make_exprt(EXPR_SIZEOF, yyvsp[-1].tref, NULL); ;} + break; + + case 151: +#line 492 "parser.y" + { yyval.expr = yyvsp[-1].expr; ;} + break; + + case 153: +#line 496 "parser.y" + { LINK(yyvsp[0].expr, yyvsp[-2].expr); yyval.expr = yyvsp[0].expr; ;} + break; + + case 154: +#line 499 "parser.y" + { yyval.expr = yyvsp[0].expr; + if (!yyval.expr->is_const) + yyerror("expression is not constant\n"); + ;} + break; + + case 155: +#line 505 "parser.y" + { yyval.var = yyvsp[0].var; + set_type(yyval.var, yyvsp[-1].tref, NULL); + ;} + break; + + case 156: +#line 510 "parser.y" + { yyval.var = NULL; ;} + break; + + case 157: +#line 511 "parser.y" + { if (yyvsp[0].var) { LINK(yyvsp[0].var, yyvsp[-1].var); yyval.var = yyvsp[0].var; } + else { yyval.var = yyvsp[-1].var; } + ;} + break; + + case 158: +#line 516 "parser.y" + { yyval.var = yyvsp[-1].var; ;} + break; + + case 159: +#line 517 "parser.y" + { yyval.var = make_var(NULL); yyval.var->type = yyvsp[-1].type; yyval.var->attrs = yyvsp[-2].attr; ;} + break; + + case 160: +#line 518 "parser.y" + { yyval.var = make_var(NULL); yyval.var->attrs = yyvsp[-1].attr; ;} + break; + + case 161: +#line 519 "parser.y" + { yyval.var = NULL; ;} + break; + + case 162: +#line 522 "parser.y" + { yyval.var = yyvsp[-1].var; set_type(yyval.var, yyvsp[-2].tref, yyvsp[0].expr); yyval.var->attrs = yyvsp[-3].attr; ;} + break; + + case 163: +#line 527 "parser.y" + { set_type(yyvsp[-3].var, yyvsp[-5].tref, NULL); + yyvsp[-3].var->attrs = yyvsp[-6].attr; + yyval.func = make_func(yyvsp[-3].var, yyvsp[-1].var); + if (is_attr(yyvsp[-3].var->attrs, ATTR_IN)) { + yyerror("Inapplicable attribute"); + } + ;} + break; + + case 164: +#line 536 "parser.y" + { yyval.var = NULL; ;} + break; + + case 166: +#line 540 "parser.y" + { yyval.var = NULL; ;} + break; + + case 167: +#line 541 "parser.y" + { yyval.var = make_var(yyvsp[0].str); ;} + break; + + case 168: +#line 542 "parser.y" + { yyval.var = make_var(yyvsp[0].str); ;} + break; + + case 169: +#line 545 "parser.y" + { yyval.var = make_var(yyvsp[0].str); ;} + break; + + case 170: +#line 547 "parser.y" + { yyval.var = make_var(yyvsp[0].str); ;} + break; + + case 171: +#line 548 "parser.y" + { yyval.var = make_var(yyvsp[0].str); ;} + break; + + case 172: +#line 549 "parser.y" + { yyval.var = make_var(yyvsp[0].str); ;} + break; + + case 173: +#line 550 "parser.y" + { yyval.var = make_var(yyvsp[0].str); ;} + break; + + case 174: +#line 551 "parser.y" + { yyval.var = make_var(yyvsp[0].str); ;} + break; + + case 175: +#line 554 "parser.y" + { yyval.type = make_type(RPC_FC_BYTE, NULL); ;} + break; + + case 176: +#line 555 "parser.y" + { yyval.type = make_type(RPC_FC_WCHAR, NULL); ;} + break; + + case 178: +#line 557 "parser.y" + { yyval.type = yyvsp[0].type; yyval.type->sign = 1; ;} + break; + + case 179: +#line 558 "parser.y" + { yyval.type = yyvsp[0].type; yyval.type->sign = -1; + switch (yyval.type->type) { + case RPC_FC_CHAR: break; + case RPC_FC_SMALL: yyval.type->type = RPC_FC_USMALL; break; + case RPC_FC_SHORT: yyval.type->type = RPC_FC_USHORT; break; + case RPC_FC_LONG: yyval.type->type = RPC_FC_ULONG; break; + case RPC_FC_HYPER: + if (!yyval.type->ref) { yyval.type->ref = &std_uhyper; yyval.type->sign = 0; } + break; + default: break; + } + ;} + break; + + case 180: +#line 570 "parser.y" + { yyval.type = make_type(RPC_FC_ULONG, &std_int); yyval.type->sign = -1; ;} + break; + + case 181: +#line 571 "parser.y" + { yyval.type = make_type(RPC_FC_FLOAT, NULL); ;} + break; + + case 182: +#line 572 "parser.y" + { yyval.type = make_type(RPC_FC_FLOAT, NULL); ;} + break; + + case 183: +#line 573 "parser.y" + { yyval.type = make_type(RPC_FC_DOUBLE, NULL); ;} + break; + + case 184: +#line 574 "parser.y" + { yyval.type = make_type(RPC_FC_SMALL, &std_bool); ;} + break; + + case 185: +#line 575 "parser.y" + { yyval.type = make_type(RPC_FC_ERROR_STATUS_T, NULL); ;} + break; + + case 186: +#line 576 "parser.y" + { yyval.type = make_type(RPC_FC_IGNORE, NULL); ;} + break; + + case 189: +#line 583 "parser.y" + { yyval.type = make_type(RPC_FC_LONG, &std_int); ;} + break; + + case 190: +#line 584 "parser.y" + { yyval.type = make_type(RPC_FC_SMALL, NULL); ;} + break; + + case 191: +#line 585 "parser.y" + { yyval.type = make_type(RPC_FC_SHORT, NULL); ;} + break; + + case 192: +#line 586 "parser.y" + { yyval.type = make_type(RPC_FC_LONG, NULL); ;} + break; + + case 193: +#line 587 "parser.y" + { yyval.type = make_type(RPC_FC_HYPER, NULL); ;} + break; + + case 194: +#line 588 "parser.y" + { yyval.type = make_type(RPC_FC_HYPER, &std_int64); ;} + break; + + case 195: +#line 589 "parser.y" + { yyval.type = make_type(RPC_FC_CHAR, NULL); ;} + break; + + case 196: +#line 592 "parser.y" + { yyval.clas = make_class(yyvsp[0].str); ;} + break; + + case 197: +#line 593 "parser.y" + { yyval.clas = make_class(yyvsp[0].str); ;} + break; + + case 198: +#line 596 "parser.y" + { yyval.clas = yyvsp[0].clas; + yyval.clas->attrs = yyvsp[-1].attr; + if (!parse_only && do_header) + write_coclass(yyval.clas); + ;} + break; + + case 199: +#line 603 "parser.y" + { yyval.clas = yyvsp[-3].clas; + yyval.clas->ifaces = yyvsp[-1].ifref; + ;} + break; + + case 200: +#line 608 "parser.y" + { yyval.ifref = NULL; ;} + break; + + case 201: +#line 609 "parser.y" + { LINK(yyvsp[0].ifref, yyvsp[-1].ifref); yyval.ifref = yyvsp[0].ifref; ;} + break; + + case 202: +#line 613 "parser.y" + { yyval.ifref = make_ifref(yyvsp[0].type); yyval.ifref->attrs = yyvsp[-1].attr; ;} + break; + + case 203: +#line 616 "parser.y" + { yyval.type = get_type(0, yyvsp[0].str, 0); ;} + break; + + case 204: +#line 617 "parser.y" + { yyval.type = get_type(0, yyvsp[0].str, 0); ;} + break; + + case 205: +#line 620 "parser.y" + { yyval.type = yyvsp[0].type; + if (yyval.type->defined) yyerror("multiple definition error\n"); + yyval.type->attrs = yyvsp[-1].attr; + yyval.type->attrs = make_attr(ATTR_DISPINTERFACE); + LINK(yyval.type->attrs, yyvsp[-1].attr); + yyval.type->ref = find_type("IDispatch", 0); + if (!yyval.type->ref) yyerror("IDispatch is undefined\n"); + yyval.type->defined = TRUE; + if (!parse_only && do_header) write_forward(yyval.type); + ;} + break; + + case 206: +#line 632 "parser.y" + { yyval.var = NULL; ;} + break; + + case 207: +#line 633 "parser.y" + { LINK(yyvsp[-1].var, yyvsp[-2].var); yyval.var = yyvsp[-1].var; ;} + break; + + case 208: +#line 636 "parser.y" + { yyval.func = NULL; ;} + break; + + case 209: +#line 637 "parser.y" + { LINK(yyvsp[-1].func, yyvsp[-2].func); yyval.func = yyvsp[-1].func; ;} + break; + + case 210: +#line 643 "parser.y" + { yyval.type = yyvsp[-4].type; + yyval.type->fields = yyvsp[-2].var; + yyval.type->funcs = yyvsp[-1].func; + if (!parse_only && do_header) write_dispinterface(yyval.type); + ;} + break; + + case 211: +#line 655 "parser.y" + { yyval.type = NULL; ;} + break; + + case 212: +#line 656 "parser.y" + { yyval.type = find_type2(yyvsp[0].str, 0); ;} + break; + + case 213: +#line 659 "parser.y" + { yyval.type = get_type(RPC_FC_IP, yyvsp[0].str, 0); ;} + break; + + case 214: +#line 660 "parser.y" + { yyval.type = get_type(RPC_FC_IP, yyvsp[0].str, 0); ;} + break; + + case 215: +#line 663 "parser.y" + { yyval.type = yyvsp[0].type; + if (yyval.type->defined) yyerror("multiple definition error\n"); + yyval.type->attrs = yyvsp[-1].attr; + yyval.type->defined = TRUE; + if (!parse_only && do_header) write_forward(yyval.type); + ;} + break; + + case 216: +#line 672 "parser.y" + { yyval.type = yyvsp[-4].type; + yyval.type->ref = yyvsp[-3].type; + yyval.type->funcs = yyvsp[-1].func; + if (!parse_only && do_header) write_interface(yyval.type); + ;} + break; + + case 217: +#line 680 "parser.y" + { yyval.type = yyvsp[-6].type; + yyval.type->ref = find_type2(yyvsp[-4].str, 0); + if (!yyval.type->ref) yyerror("base class %s not found in import\n", yyvsp[-4].str); + yyval.type->funcs = yyvsp[-1].func; + if (!parse_only && do_header) write_interface(yyval.type); + ;} + break; + + case 218: +#line 686 "parser.y" + { yyval.type = yyvsp[0].type; ;} + break; + + case 219: +#line 690 "parser.y" + { yyval.type = yyvsp[-1].type; if (!parse_only && do_header) write_forward(yyval.type); ;} + break; + + case 220: +#line 691 "parser.y" + { yyval.type = yyvsp[-1].type; if (!parse_only && do_header) write_forward(yyval.type); ;} + break; + + case 221: +#line 694 "parser.y" + { yyval.type = make_type(0, NULL); yyval.type->name = yyvsp[0].str; ;} + break; + + case 222: +#line 695 "parser.y" + { yyval.type = make_type(0, NULL); yyval.type->name = yyvsp[0].str; ;} + break; + + case 223: +#line 698 "parser.y" + { yyval.type = yyvsp[0].type; + yyval.type->attrs = yyvsp[-1].attr; + ;} + break; + + case 224: +#line 703 "parser.y" + { yyval.type = yyvsp[-3].type; + yyval.type->funcs = yyvsp[-1].func; + /* FIXME: if (!parse_only && do_header) write_module($$); */ + ;} + break; + + case 225: +#line 709 "parser.y" + { yyval.var = yyvsp[0].var; yyval.var->ptr_level++; ;} + break; + + case 226: +#line 710 "parser.y" + { yyval.var = yyvsp[0].var; /* FIXME */ ;} + break; + + case 229: +#line 715 "parser.y" + { yyval.var = yyvsp[-1].var; ;} + break; + + case 231: +#line 720 "parser.y" + { LINK(yyvsp[0].var, yyvsp[-2].var); yyval.var = yyvsp[0].var; ;} + break; + + case 232: +#line 724 "parser.y" + { yyval.num = RPC_FC_RP; ;} + break; + + case 233: +#line 725 "parser.y" + { yyval.num = RPC_FC_UP; ;} + break; + + case 234: +#line 728 "parser.y" + { yyval.type = get_typev(RPC_FC_STRUCT, yyvsp[-3].var, tsSTRUCT); + /* overwrite RPC_FC_STRUCT with a more exact type */ + yyval.type->type = get_struct_type( yyvsp[-1].var ); + yyval.type->fields = yyvsp[-1].var; + yyval.type->defined = TRUE; + if(in_typelib) + add_struct(yyval.type); + ;} + break; + + case 235: +#line 738 "parser.y" + { yyval.tref = make_tref(NULL, make_type(0, NULL)); ;} + break; + + case 236: +#line 739 "parser.y" + { yyval.tref = make_tref(yyvsp[0].str, find_type(yyvsp[0].str, 0)); ;} + break; + + case 237: +#line 740 "parser.y" + { yyval.tref = make_tref(NULL, yyvsp[0].type); ;} + break; + + case 238: +#line 741 "parser.y" + { yyval.tref = uniq_tref(yyvsp[0].tref); yyval.tref->ref->is_const = TRUE; ;} + break; + + case 239: +#line 742 "parser.y" + { yyval.tref = make_tref(NULL, yyvsp[0].type); ;} + break; + + case 240: +#line 743 "parser.y" + { yyval.tref = make_tref(NULL, find_type2(yyvsp[0].str, tsENUM)); ;} + break; + + case 241: +#line 744 "parser.y" + { yyval.tref = make_tref(NULL, yyvsp[0].type); ;} + break; + + case 242: +#line 745 "parser.y" + { yyval.tref = make_tref(NULL, get_type(RPC_FC_STRUCT, yyvsp[0].str, tsSTRUCT)); ;} + break; + + case 243: +#line 746 "parser.y" + { yyval.tref = make_tref(NULL, yyvsp[0].type); ;} + break; + + case 244: +#line 747 "parser.y" + { yyval.tref = make_tref(NULL, find_type2(yyvsp[0].str, tsUNION)); ;} + break; + + case 245: +#line 750 "parser.y" + { typeref_t *tref = uniq_tref(yyvsp[-1].tref); + yyvsp[0].var->tname = tref->name; + tref->name = NULL; + yyval.type = type_ref(tref); + yyval.type->attrs = yyvsp[-2].attr; + if (!parse_only && do_header) + write_typedef(yyval.type, yyvsp[0].var); + if (in_typelib && yyval.type->attrs) + add_typedef(yyval.type, yyvsp[0].var); + reg_types(yyval.type, yyvsp[0].var, 0); + ;} + break; + + case 246: +#line 763 "parser.y" + { yyval.type = get_typev(RPC_FC_NON_ENCAPSULATED_UNION, yyvsp[-3].var, tsUNION); + yyval.type->fields = yyvsp[-1].var; + yyval.type->defined = TRUE; + ;} + break; + + case 247: +#line 769 "parser.y" + { var_t *u = yyvsp[-3].var; + yyval.type = get_typev(RPC_FC_ENCAPSULATED_UNION, yyvsp[-8].var, tsUNION); + if (!u) u = make_var("tagged_union"); + u->type = make_type(RPC_FC_NON_ENCAPSULATED_UNION, NULL); + u->type->fields = yyvsp[-1].var; + u->type->defined = TRUE; + LINK(u, yyvsp[-5].var); yyval.type->fields = u; + yyval.type->defined = TRUE; + ;} + break; + + case 248: +#line 781 "parser.y" + { yyval.num = MAKELONG(yyvsp[0].num, 0); ;} + break; + + case 249: +#line 782 "parser.y" + { yyval.num = MAKELONG(yyvsp[-2].num, yyvsp[0].num); ;} + break; + + + } + +/* Line 991 of yacc.c. */ +#line 3169 "y.tab.c" + + yyvsp -= yylen; + yyssp -= yylen; + + + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (YYPACT_NINF < yyn && yyn < YYLAST) + { + YYSIZE_T yysize = 0; + int yytype = YYTRANSLATE (yychar); + char *yymsg; + int yyx, yycount; + + yycount = 0; + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + yysize += yystrlen (yytname[yyx]) + 15, yycount++; + yysize += yystrlen ("syntax error, unexpected ") + 1; + yysize += yystrlen (yytname[yytype]); + yymsg = (char *) YYSTACK_ALLOC (yysize); + if (yymsg != 0) + { + char *yyp = yystpcpy (yymsg, "syntax error, unexpected "); + yyp = yystpcpy (yyp, yytname[yytype]); + + if (yycount < 5) + { + yycount = 0; + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); + yyx++) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + const char *yyq = ! yycount ? ", expecting " : " or "; + yyp = yystpcpy (yyp, yyq); + yyp = yystpcpy (yyp, yytname[yyx]); + yycount++; + } + } + yyerror (yymsg); + YYSTACK_FREE (yymsg); + } + else + yyerror ("syntax error; also virtual memory exhausted"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror ("syntax error"); + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + /* Return failure if at end of input. */ + if (yychar == YYEOF) + { + /* Pop the error token. */ + YYPOPSTACK; + /* Pop the rest of the stack. */ + while (yyss < yyssp) + { + YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); + yydestruct (yystos[*yyssp], yyvsp); + YYPOPSTACK; + } + YYABORT; + } + + YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc); + yydestruct (yytoken, &yylval); + yychar = YYEMPTY; + + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab2; + + +/*----------------------------------------------------. +| yyerrlab1 -- error raised explicitly by an action. | +`----------------------------------------------------*/ +yyerrlab1: + + /* Suppress GCC warning that yyerrlab1 is unused when no action + invokes YYERROR. */ +#if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__) + __attribute__ ((__unused__)) +#endif + + + goto yyerrlab2; + + +/*---------------------------------------------------------------. +| yyerrlab2 -- pop states until the error token can be shifted. | +`---------------------------------------------------------------*/ +yyerrlab2: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); + yydestruct (yystos[yystate], yyvsp); + yyvsp--; + yystate = *--yyssp; + + YY_STACK_PRINT (yyss, yyssp); + } + + if (yyn == YYFINAL) + YYACCEPT; + + YYDPRINTF ((stderr, "Shifting error token, ")); + + *++yyvsp = yylval; + + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#ifndef yyoverflow +/*----------------------------------------------. +| yyoverflowlab -- parser overflow comes here. | +`----------------------------------------------*/ +yyoverflowlab: + yyerror ("parser stack overflow"); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + return yyresult; +} + + +#line 785 "parser.y" + + +static attr_t *make_attr(enum attr_type type) +{ + attr_t *a = xmalloc(sizeof(attr_t)); + a->type = type; + a->u.ival = 0; + INIT_LINK(a); + return a; +} + +static attr_t *make_attrv(enum attr_type type, unsigned long val) +{ + attr_t *a = xmalloc(sizeof(attr_t)); + a->type = type; + a->u.ival = val; + INIT_LINK(a); + return a; +} + +static attr_t *make_attrp(enum attr_type type, void *val) +{ + attr_t *a = xmalloc(sizeof(attr_t)); + a->type = type; + a->u.pval = val; + INIT_LINK(a); + return a; +} + +static expr_t *make_expr(enum expr_type type) +{ + expr_t *e = xmalloc(sizeof(expr_t)); + e->type = type; + e->ref = NULL; + e->u.lval = 0; + e->is_const = FALSE; + INIT_LINK(e); + return e; +} + +static expr_t *make_exprl(enum expr_type type, long val) +{ + expr_t *e = xmalloc(sizeof(expr_t)); + e->type = type; + e->ref = NULL; + e->u.lval = val; + e->is_const = FALSE; + INIT_LINK(e); + /* check for numeric constant */ + if (type == EXPR_NUM || type == EXPR_HEXNUM) { + e->is_const = TRUE; + e->cval = val; + } + return e; +} + +static expr_t *make_exprs(enum expr_type type, char *val) +{ + expr_t *e; + e = xmalloc(sizeof(expr_t)); + e->type = type; + e->ref = NULL; + e->u.sval = val; + e->is_const = FALSE; + INIT_LINK(e); + /* check for predefined constants */ + if (type == EXPR_IDENTIFIER) { + var_t *c = find_const(val, 0); + if (c) { + e->u.sval = c->name; + free(val); + e->is_const = TRUE; + e->cval = c->lval; + } + } + return e; +} + +static expr_t *make_exprt(enum expr_type type, typeref_t *tref, expr_t *expr) +{ + expr_t *e; + e = xmalloc(sizeof(expr_t)); + e->type = type; + e->ref = expr; + e->u.tref = tref; + e->is_const = FALSE; + INIT_LINK(e); + /* check for cast of constant expression */ + if (type == EXPR_CAST && expr->is_const) { + e->is_const = TRUE; + e->cval = expr->cval; + } + return e; +} + +static expr_t *make_expr1(enum expr_type type, expr_t *expr) +{ + expr_t *e; + e = xmalloc(sizeof(expr_t)); + e->type = type; + e->ref = expr; + e->u.lval = 0; + e->is_const = FALSE; + INIT_LINK(e); + /* check for compile-time optimization */ + if (expr->is_const) { + e->is_const = TRUE; + switch (type) { + case EXPR_NEG: + e->cval = -expr->cval; + break; + case EXPR_NOT: + e->cval = ~expr->cval; + break; + default: + e->is_const = FALSE; + break; + } + } + return e; +} + +static expr_t *make_expr2(enum expr_type type, expr_t *expr1, expr_t *expr2) +{ + expr_t *e; + e = xmalloc(sizeof(expr_t)); + e->type = type; + e->ref = expr1; + e->u.ext = expr2; + e->is_const = FALSE; + INIT_LINK(e); + /* check for compile-time optimization */ + if (expr1->is_const && expr2->is_const) { + e->is_const = TRUE; + switch (type) { + case EXPR_ADD: + e->cval = expr1->cval + expr2->cval; + break; + case EXPR_SUB: + e->cval = expr1->cval - expr2->cval; + break; + case EXPR_MUL: + e->cval = expr1->cval * expr2->cval; + break; + case EXPR_DIV: + e->cval = expr1->cval / expr2->cval; + break; + case EXPR_OR: + e->cval = expr1->cval | expr2->cval; + break; + case EXPR_AND: + e->cval = expr1->cval & expr2->cval; + break; + case EXPR_SHL: + e->cval = expr1->cval << expr2->cval; + break; + case EXPR_SHR: + e->cval = expr1->cval >> expr2->cval; + break; + default: + e->is_const = FALSE; + break; + } + } + return e; +} + +static expr_t *make_expr3(enum expr_type type, expr_t *expr1, expr_t *expr2, expr_t *expr3) +{ + expr_t *e; + e = xmalloc(sizeof(expr_t)); + e->type = type; + e->ref = expr1; + e->u.ext = expr2; + e->ext2 = expr3; + e->is_const = FALSE; + INIT_LINK(e); + /* check for compile-time optimization */ + if (expr1->is_const && expr2->is_const && expr3->is_const) { + e->is_const = TRUE; + switch (type) { + case EXPR_COND: + e->cval = expr1->cval ? expr2->cval : expr3->cval; + break; + default: + e->is_const = FALSE; + break; + } + } + return e; +} + +static type_t *make_type(unsigned char type, type_t *ref) +{ + type_t *t = xmalloc(sizeof(type_t)); + t->name = NULL; + t->type = type; + t->ref = ref; + t->rname = NULL; + t->attrs = NULL; + t->funcs = NULL; + t->fields = NULL; + t->ignore = parse_only; + t->is_const = FALSE; + t->sign = 0; + t->defined = FALSE; + t->written = FALSE; + t->typelib_idx = -1; + INIT_LINK(t); + return t; +} + +static typeref_t *make_tref(char *name, type_t *ref) +{ + typeref_t *t = xmalloc(sizeof(typeref_t)); + t->name = name; + t->ref = ref; + t->uniq = ref ? 0 : 1; + return t; +} + +static typeref_t *uniq_tref(typeref_t *ref) +{ + typeref_t *t = ref; + type_t *tp; + if (t->uniq) return t; + tp = make_type(0, t->ref); + tp->name = t->name; + t->name = NULL; + t->ref = tp; + t->uniq = 1; + return t; +} + +static type_t *type_ref(typeref_t *ref) +{ + type_t *t = ref->ref; + if (ref->name) free(ref->name); + free(ref); + return t; +} + +static void set_type(var_t *v, typeref_t *ref, expr_t *arr) +{ + v->type = ref->ref; + v->tname = ref->name; + ref->name = NULL; + free(ref); + v->array = arr; +} + +static ifref_t *make_ifref(type_t *iface) +{ + ifref_t *l = xmalloc(sizeof(ifref_t)); + l->iface = iface; + l->attrs = NULL; + INIT_LINK(l); + return l; +} + +static var_t *make_var(char *name) +{ + var_t *v = xmalloc(sizeof(var_t)); + v->name = name; + v->ptr_level = 0; + v->type = NULL; + v->tname = NULL; + v->attrs = NULL; + v->array = NULL; + v->eval = NULL; + v->lval = 0; + INIT_LINK(v); + return v; +} + +static func_t *make_func(var_t *def, var_t *args) +{ + func_t *f = xmalloc(sizeof(func_t)); + f->def = def; + f->args = args; + f->ignore = parse_only; + f->idx = -1; + INIT_LINK(f); + return f; +} + +static class_t *make_class(char *name) +{ + class_t *c = xmalloc(sizeof(class_t)); + c->name = name; + c->attrs = NULL; + c->ifaces = NULL; + INIT_LINK(c); + return c; +} + +#define HASHMAX 64 + +static int hash_ident(const char *name) +{ + const char *p = name; + int sum = 0; + /* a simple sum hash is probably good enough */ + while (*p) { + sum += *p; + p++; + } + return sum & (HASHMAX-1); +} + +/***** type repository *****/ + +struct rtype { + char *name; + type_t *type; + int t; + struct rtype *next; +}; + +struct rtype *type_hash[HASHMAX]; + +static type_t *reg_type(type_t *type, char *name, int t) +{ + struct rtype *nt; + int hash; + if (!name) { + yyerror("registering named type without name\n"); + return type; + } + hash = hash_ident(name); + nt = xmalloc(sizeof(struct rtype)); + nt->name = name; + nt->type = type; + nt->t = t; + nt->next = type_hash[hash]; + type_hash[hash] = nt; + type->name = name; + return type; +} + +/* determine pointer type from attrs */ +static unsigned char get_pointer_type( type_t *type ) +{ + int t; + if (is_attr( type->attrs, ATTR_STRING )) + { + type_t *t = type; + while( t->type == 0 && t->ref ) + t = t->ref; + switch( t->type ) + { + case RPC_FC_CHAR: + return RPC_FC_C_CSTRING; + case RPC_FC_WCHAR: + return RPC_FC_C_WSTRING; + } + } + t = get_attrv( type->attrs, ATTR_POINTERTYPE ); + if (t) return t; + + if(is_attr( type->attrs, ATTR_PTR )) + return RPC_FC_FP; + + if(is_attr( type->attrs, ATTR_UNIQUE )) + return RPC_FC_UP; + + return RPC_FC_RP; +} + +static type_t *reg_types(type_t *type, var_t *names, int t) +{ + type_t *ptr = type; + int ptrc = 0; + + while (names) { + var_t *next = NEXT_LINK(names); + if (names->name) { + type_t *cur = ptr; + int cptr = names->ptr_level; + if (cptr > ptrc) { + while (cptr > ptrc) { + int t = get_pointer_type( cur ); + cur = ptr = make_type(t, cur); + ptrc++; + } + } else { + while (cptr < ptrc) { + cur = cur->ref; + cptr++; + } + } + reg_type(cur, names->name, t); + } + free(names); + names = next; + } + return type; +} + +static type_t *find_type(char *name, int t) +{ + struct rtype *cur = type_hash[hash_ident(name)]; + while (cur && (cur->t != t || strcmp(cur->name, name))) + cur = cur->next; + if (!cur) { + yyerror("type %s not found\n", name); + return NULL; + } + return cur->type; +} + +static type_t *find_type2(char *name, int t) +{ + type_t *tp = find_type(name, t); + free(name); + return tp; +} + +int is_type(const char *name) +{ + struct rtype *cur = type_hash[hash_ident(name)]; + while (cur && (cur->t || strcmp(cur->name, name))) + cur = cur->next; + if (cur) return TRUE; + return FALSE; +} + +static type_t *get_type(unsigned char type, char *name, int t) +{ + struct rtype *cur = NULL; + type_t *tp; + if (name) { + cur = type_hash[hash_ident(name)]; + while (cur && (cur->t != t || strcmp(cur->name, name))) + cur = cur->next; + } + if (cur) { + free(name); + return cur->type; + } + tp = make_type(type, NULL); + tp->name = name; + if (!name) return tp; + return reg_type(tp, name, t); +} + +static type_t *get_typev(unsigned char type, var_t *name, int t) +{ + char *sname = NULL; + if (name) { + sname = name->name; + free(name); + } + return get_type(type, sname, t); +} + +static int get_struct_type(var_t *field) +{ + int has_pointer = 0; + int has_conformant_array = 0; + int has_conformant_string = 0; + + while (field) + { + type_t *t = field->type; + + /* get the base type */ + while( (t->type == 0) && t->ref ) + t = t->ref; + + switch (t->type) + { + /* + * RPC_FC_BYTE, RPC_FC_STRUCT, etc + * Simple types don't effect the type of struct. + * A struct containing a simple struct is still a simple struct. + * So long as we can block copy the data, we return RPC_FC_STRUCT. + */ + case 0: /* void pointer */ + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + case RPC_FC_USMALL: + case RPC_FC_WCHAR: + case RPC_FC_SHORT: + case RPC_FC_USHORT: + case RPC_FC_LONG: + case RPC_FC_ULONG: + case RPC_FC_INT3264: + case RPC_FC_UINT3264: + case RPC_FC_HYPER: + case RPC_FC_FLOAT: + case RPC_FC_DOUBLE: + case RPC_FC_STRUCT: + case RPC_FC_ENUM16: + case RPC_FC_ENUM32: + break; + + case RPC_FC_UP: + case RPC_FC_FP: + has_pointer = 1; + break; + case RPC_FC_CARRAY: + has_conformant_array = 1; + break; + case RPC_FC_C_CSTRING: + case RPC_FC_C_WSTRING: + has_conformant_string = 1; + break; + + /* + * Propagate member attributes + * a struct should be at least as complex as its member + */ + case RPC_FC_CVSTRUCT: + has_conformant_string = 1; + has_pointer = 1; + break; + + case RPC_FC_CPSTRUCT: + has_conformant_array = 1; + has_pointer = 1; + break; + + case RPC_FC_CSTRUCT: + has_conformant_array = 1; + break; + + case RPC_FC_PSTRUCT: + has_pointer = 1; + break; + + default: + fprintf(stderr,"Unknown struct member %s with type (0x%02x)\n", + field->name, t->type); + /* fallthru - treat it as complex */ + + /* as soon as we see one of these these members, it's bogus... */ + case RPC_FC_IP: + case RPC_FC_ENCAPSULATED_UNION: + case RPC_FC_NON_ENCAPSULATED_UNION: + case RPC_FC_TRANSMIT_AS: + case RPC_FC_REPRESENT_AS: + case RPC_FC_PAD: + case RPC_FC_EMBEDDED_COMPLEX: + case RPC_FC_BOGUS_STRUCT: + return RPC_FC_BOGUS_STRUCT; + } + field = NEXT_LINK(field); + } + + if( has_conformant_string && has_pointer ) + return RPC_FC_CVSTRUCT; + if( has_conformant_array && has_pointer ) + return RPC_FC_CPSTRUCT; + if( has_conformant_array ) + return RPC_FC_CSTRUCT; + if( has_pointer ) + return RPC_FC_PSTRUCT; + return RPC_FC_STRUCT; +} + +/***** constant repository *****/ + +struct rconst { + char *name; + var_t *var; + struct rconst *next; +}; + +struct rconst *const_hash[HASHMAX]; + +static var_t *reg_const(var_t *var) +{ + struct rconst *nc; + int hash; + if (!var->name) { + yyerror("registering constant without name\n"); + return var; + } + hash = hash_ident(var->name); + nc = xmalloc(sizeof(struct rconst)); + nc->name = var->name; + nc->var = var; + nc->next = const_hash[hash]; + const_hash[hash] = nc; + return var; +} + +static var_t *find_const(char *name, int f) +{ + struct rconst *cur = const_hash[hash_ident(name)]; + while (cur && strcmp(cur->name, name)) + cur = cur->next; + if (!cur) { + if (f) yyerror("constant %s not found\n", name); + return NULL; + } + return cur->var; +} + diff --git a/reactos/tools/widl/y.tab.h b/reactos/tools/widl/y.tab.h index 6824c035dd1..0921fdba71c 100644 --- a/reactos/tools/widl/y.tab.h +++ b/reactos/tools/widl/y.tab.h @@ -1,309 +1,309 @@ -/* A Bison parser, made by GNU Bison 1.875. */ - -/* Skeleton parser for Yacc-like parsing with Bison, - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc. - - 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, 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., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -/* As a special exception, when this file is copied by Bison into a - Bison output file, you may use that output file without restriction. - This special exception was added by the Free Software Foundation - in version 1.24 of Bison. */ - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - aIDENTIFIER = 258, - aKNOWNTYPE = 259, - aNUM = 260, - aHEXNUM = 261, - aSTRING = 262, - aUUID = 263, - aEOF = 264, - SHL = 265, - SHR = 266, - tAGGREGATABLE = 267, - tALLOCATE = 268, - tAPPOBJECT = 269, - tARRAYS = 270, - tASYNC = 271, - tASYNCUUID = 272, - tAUTOHANDLE = 273, - tBINDABLE = 274, - tBOOLEAN = 275, - tBROADCAST = 276, - tBYTE = 277, - tBYTECOUNT = 278, - tCALLAS = 279, - tCALLBACK = 280, - tCASE = 281, - tCDECL = 282, - tCHAR = 283, - tCOCLASS = 284, - tCODE = 285, - tCOMMSTATUS = 286, - tCONST = 287, - tCONTEXTHANDLE = 288, - tCONTEXTHANDLENOSERIALIZE = 289, - tCONTEXTHANDLESERIALIZE = 290, - tCONTROL = 291, - tCPPQUOTE = 292, - tDEFAULT = 293, - tDEFAULTVALUE = 294, - tDISPINTERFACE = 295, - tDLLNAME = 296, - tDOUBLE = 297, - tDUAL = 298, - tENDPOINT = 299, - tENTRY = 300, - tENUM = 301, - tERRORSTATUST = 302, - tEXPLICITHANDLE = 303, - tEXTERN = 304, - tFLOAT = 305, - tHANDLE = 306, - tHANDLET = 307, - tHELPCONTEXT = 308, - tHELPFILE = 309, - tHELPSTRING = 310, - tHELPSTRINGCONTEXT = 311, - tHELPSTRINGDLL = 312, - tHIDDEN = 313, - tHYPER = 314, - tID = 315, - tIDEMPOTENT = 316, - tIIDIS = 317, - tIMPLICITHANDLE = 318, - tIMPORT = 319, - tIMPORTLIB = 320, - tIN = 321, - tINCLUDE = 322, - tINLINE = 323, - tINPUTSYNC = 324, - tINT = 325, - tINT64 = 326, - tINTERFACE = 327, - tLENGTHIS = 328, - tLIBRARY = 329, - tLOCAL = 330, - tLONG = 331, - tMETHODS = 332, - tMODULE = 333, - tNONCREATABLE = 334, - tOBJECT = 335, - tODL = 336, - tOLEAUTOMATION = 337, - tOPTIONAL = 338, - tOUT = 339, - tPOINTERDEFAULT = 340, - tPROPERTIES = 341, - tPROPGET = 342, - tPROPPUT = 343, - tPROPPUTREF = 344, - tPTR = 345, - tPUBLIC = 346, - tREADONLY = 347, - tREF = 348, - tRESTRICTED = 349, - tRETVAL = 350, - tSHORT = 351, - tSIGNED = 352, - tSINGLE = 353, - tSIZEIS = 354, - tSIZEOF = 355, - tSMALL = 356, - tSOURCE = 357, - tSTDCALL = 358, - tSTRING = 359, - tSTRUCT = 360, - tSWITCH = 361, - tSWITCHIS = 362, - tSWITCHTYPE = 363, - tTRANSMITAS = 364, - tTYPEDEF = 365, - tUNION = 366, - tUNIQUE = 367, - tUNSIGNED = 368, - tUUID = 369, - tV1ENUM = 370, - tVARARG = 371, - tVERSION = 372, - tVOID = 373, - tWCHAR = 374, - tWIREMARSHAL = 375, - tPOINTERTYPE = 376, - COND = 377, - CAST = 378, - PPTR = 379, - NEG = 380 - }; -#endif -#define aIDENTIFIER 258 -#define aKNOWNTYPE 259 -#define aNUM 260 -#define aHEXNUM 261 -#define aSTRING 262 -#define aUUID 263 -#define aEOF 264 -#define SHL 265 -#define SHR 266 -#define tAGGREGATABLE 267 -#define tALLOCATE 268 -#define tAPPOBJECT 269 -#define tARRAYS 270 -#define tASYNC 271 -#define tASYNCUUID 272 -#define tAUTOHANDLE 273 -#define tBINDABLE 274 -#define tBOOLEAN 275 -#define tBROADCAST 276 -#define tBYTE 277 -#define tBYTECOUNT 278 -#define tCALLAS 279 -#define tCALLBACK 280 -#define tCASE 281 -#define tCDECL 282 -#define tCHAR 283 -#define tCOCLASS 284 -#define tCODE 285 -#define tCOMMSTATUS 286 -#define tCONST 287 -#define tCONTEXTHANDLE 288 -#define tCONTEXTHANDLENOSERIALIZE 289 -#define tCONTEXTHANDLESERIALIZE 290 -#define tCONTROL 291 -#define tCPPQUOTE 292 -#define tDEFAULT 293 -#define tDEFAULTVALUE 294 -#define tDISPINTERFACE 295 -#define tDLLNAME 296 -#define tDOUBLE 297 -#define tDUAL 298 -#define tENDPOINT 299 -#define tENTRY 300 -#define tENUM 301 -#define tERRORSTATUST 302 -#define tEXPLICITHANDLE 303 -#define tEXTERN 304 -#define tFLOAT 305 -#define tHANDLE 306 -#define tHANDLET 307 -#define tHELPCONTEXT 308 -#define tHELPFILE 309 -#define tHELPSTRING 310 -#define tHELPSTRINGCONTEXT 311 -#define tHELPSTRINGDLL 312 -#define tHIDDEN 313 -#define tHYPER 314 -#define tID 315 -#define tIDEMPOTENT 316 -#define tIIDIS 317 -#define tIMPLICITHANDLE 318 -#define tIMPORT 319 -#define tIMPORTLIB 320 -#define tIN 321 -#define tINCLUDE 322 -#define tINLINE 323 -#define tINPUTSYNC 324 -#define tINT 325 -#define tINT64 326 -#define tINTERFACE 327 -#define tLENGTHIS 328 -#define tLIBRARY 329 -#define tLOCAL 330 -#define tLONG 331 -#define tMETHODS 332 -#define tMODULE 333 -#define tNONCREATABLE 334 -#define tOBJECT 335 -#define tODL 336 -#define tOLEAUTOMATION 337 -#define tOPTIONAL 338 -#define tOUT 339 -#define tPOINTERDEFAULT 340 -#define tPROPERTIES 341 -#define tPROPGET 342 -#define tPROPPUT 343 -#define tPROPPUTREF 344 -#define tPTR 345 -#define tPUBLIC 346 -#define tREADONLY 347 -#define tREF 348 -#define tRESTRICTED 349 -#define tRETVAL 350 -#define tSHORT 351 -#define tSIGNED 352 -#define tSINGLE 353 -#define tSIZEIS 354 -#define tSIZEOF 355 -#define tSMALL 356 -#define tSOURCE 357 -#define tSTDCALL 358 -#define tSTRING 359 -#define tSTRUCT 360 -#define tSWITCH 361 -#define tSWITCHIS 362 -#define tSWITCHTYPE 363 -#define tTRANSMITAS 364 -#define tTYPEDEF 365 -#define tUNION 366 -#define tUNIQUE 367 -#define tUNSIGNED 368 -#define tUUID 369 -#define tV1ENUM 370 -#define tVARARG 371 -#define tVERSION 372 -#define tVOID 373 -#define tWCHAR 374 -#define tWIREMARSHAL 375 -#define tPOINTERTYPE 376 -#define COND 377 -#define CAST 378 -#define PPTR 379 -#define NEG 380 - - - - -#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) -#line 106 "parser.y" -typedef union YYSTYPE { - attr_t *attr; - expr_t *expr; - type_t *type; - typeref_t *tref; - var_t *var; - func_t *func; - ifref_t *ifref; - class_t *clas; - char *str; - UUID *uuid; - unsigned int num; -} YYSTYPE; -/* Line 1248 of yacc.c. */ -#line 300 "y.tab.h" -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 -#endif - -extern YYSTYPE yylval; - - - +/* A Bison parser, made by GNU Bison 1.875. */ + +/* Skeleton parser for Yacc-like parsing with Bison, + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc. + + 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, 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + aIDENTIFIER = 258, + aKNOWNTYPE = 259, + aNUM = 260, + aHEXNUM = 261, + aSTRING = 262, + aUUID = 263, + aEOF = 264, + SHL = 265, + SHR = 266, + tAGGREGATABLE = 267, + tALLOCATE = 268, + tAPPOBJECT = 269, + tARRAYS = 270, + tASYNC = 271, + tASYNCUUID = 272, + tAUTOHANDLE = 273, + tBINDABLE = 274, + tBOOLEAN = 275, + tBROADCAST = 276, + tBYTE = 277, + tBYTECOUNT = 278, + tCALLAS = 279, + tCALLBACK = 280, + tCASE = 281, + tCDECL = 282, + tCHAR = 283, + tCOCLASS = 284, + tCODE = 285, + tCOMMSTATUS = 286, + tCONST = 287, + tCONTEXTHANDLE = 288, + tCONTEXTHANDLENOSERIALIZE = 289, + tCONTEXTHANDLESERIALIZE = 290, + tCONTROL = 291, + tCPPQUOTE = 292, + tDEFAULT = 293, + tDEFAULTVALUE = 294, + tDISPINTERFACE = 295, + tDLLNAME = 296, + tDOUBLE = 297, + tDUAL = 298, + tENDPOINT = 299, + tENTRY = 300, + tENUM = 301, + tERRORSTATUST = 302, + tEXPLICITHANDLE = 303, + tEXTERN = 304, + tFLOAT = 305, + tHANDLE = 306, + tHANDLET = 307, + tHELPCONTEXT = 308, + tHELPFILE = 309, + tHELPSTRING = 310, + tHELPSTRINGCONTEXT = 311, + tHELPSTRINGDLL = 312, + tHIDDEN = 313, + tHYPER = 314, + tID = 315, + tIDEMPOTENT = 316, + tIIDIS = 317, + tIMPLICITHANDLE = 318, + tIMPORT = 319, + tIMPORTLIB = 320, + tIN = 321, + tINCLUDE = 322, + tINLINE = 323, + tINPUTSYNC = 324, + tINT = 325, + tINT64 = 326, + tINTERFACE = 327, + tLENGTHIS = 328, + tLIBRARY = 329, + tLOCAL = 330, + tLONG = 331, + tMETHODS = 332, + tMODULE = 333, + tNONCREATABLE = 334, + tOBJECT = 335, + tODL = 336, + tOLEAUTOMATION = 337, + tOPTIONAL = 338, + tOUT = 339, + tPOINTERDEFAULT = 340, + tPROPERTIES = 341, + tPROPGET = 342, + tPROPPUT = 343, + tPROPPUTREF = 344, + tPTR = 345, + tPUBLIC = 346, + tREADONLY = 347, + tREF = 348, + tRESTRICTED = 349, + tRETVAL = 350, + tSHORT = 351, + tSIGNED = 352, + tSINGLE = 353, + tSIZEIS = 354, + tSIZEOF = 355, + tSMALL = 356, + tSOURCE = 357, + tSTDCALL = 358, + tSTRING = 359, + tSTRUCT = 360, + tSWITCH = 361, + tSWITCHIS = 362, + tSWITCHTYPE = 363, + tTRANSMITAS = 364, + tTYPEDEF = 365, + tUNION = 366, + tUNIQUE = 367, + tUNSIGNED = 368, + tUUID = 369, + tV1ENUM = 370, + tVARARG = 371, + tVERSION = 372, + tVOID = 373, + tWCHAR = 374, + tWIREMARSHAL = 375, + tPOINTERTYPE = 376, + COND = 377, + CAST = 378, + PPTR = 379, + NEG = 380 + }; +#endif +#define aIDENTIFIER 258 +#define aKNOWNTYPE 259 +#define aNUM 260 +#define aHEXNUM 261 +#define aSTRING 262 +#define aUUID 263 +#define aEOF 264 +#define SHL 265 +#define SHR 266 +#define tAGGREGATABLE 267 +#define tALLOCATE 268 +#define tAPPOBJECT 269 +#define tARRAYS 270 +#define tASYNC 271 +#define tASYNCUUID 272 +#define tAUTOHANDLE 273 +#define tBINDABLE 274 +#define tBOOLEAN 275 +#define tBROADCAST 276 +#define tBYTE 277 +#define tBYTECOUNT 278 +#define tCALLAS 279 +#define tCALLBACK 280 +#define tCASE 281 +#define tCDECL 282 +#define tCHAR 283 +#define tCOCLASS 284 +#define tCODE 285 +#define tCOMMSTATUS 286 +#define tCONST 287 +#define tCONTEXTHANDLE 288 +#define tCONTEXTHANDLENOSERIALIZE 289 +#define tCONTEXTHANDLESERIALIZE 290 +#define tCONTROL 291 +#define tCPPQUOTE 292 +#define tDEFAULT 293 +#define tDEFAULTVALUE 294 +#define tDISPINTERFACE 295 +#define tDLLNAME 296 +#define tDOUBLE 297 +#define tDUAL 298 +#define tENDPOINT 299 +#define tENTRY 300 +#define tENUM 301 +#define tERRORSTATUST 302 +#define tEXPLICITHANDLE 303 +#define tEXTERN 304 +#define tFLOAT 305 +#define tHANDLE 306 +#define tHANDLET 307 +#define tHELPCONTEXT 308 +#define tHELPFILE 309 +#define tHELPSTRING 310 +#define tHELPSTRINGCONTEXT 311 +#define tHELPSTRINGDLL 312 +#define tHIDDEN 313 +#define tHYPER 314 +#define tID 315 +#define tIDEMPOTENT 316 +#define tIIDIS 317 +#define tIMPLICITHANDLE 318 +#define tIMPORT 319 +#define tIMPORTLIB 320 +#define tIN 321 +#define tINCLUDE 322 +#define tINLINE 323 +#define tINPUTSYNC 324 +#define tINT 325 +#define tINT64 326 +#define tINTERFACE 327 +#define tLENGTHIS 328 +#define tLIBRARY 329 +#define tLOCAL 330 +#define tLONG 331 +#define tMETHODS 332 +#define tMODULE 333 +#define tNONCREATABLE 334 +#define tOBJECT 335 +#define tODL 336 +#define tOLEAUTOMATION 337 +#define tOPTIONAL 338 +#define tOUT 339 +#define tPOINTERDEFAULT 340 +#define tPROPERTIES 341 +#define tPROPGET 342 +#define tPROPPUT 343 +#define tPROPPUTREF 344 +#define tPTR 345 +#define tPUBLIC 346 +#define tREADONLY 347 +#define tREF 348 +#define tRESTRICTED 349 +#define tRETVAL 350 +#define tSHORT 351 +#define tSIGNED 352 +#define tSINGLE 353 +#define tSIZEIS 354 +#define tSIZEOF 355 +#define tSMALL 356 +#define tSOURCE 357 +#define tSTDCALL 358 +#define tSTRING 359 +#define tSTRUCT 360 +#define tSWITCH 361 +#define tSWITCHIS 362 +#define tSWITCHTYPE 363 +#define tTRANSMITAS 364 +#define tTYPEDEF 365 +#define tUNION 366 +#define tUNIQUE 367 +#define tUNSIGNED 368 +#define tUUID 369 +#define tV1ENUM 370 +#define tVARARG 371 +#define tVERSION 372 +#define tVOID 373 +#define tWCHAR 374 +#define tWIREMARSHAL 375 +#define tPOINTERTYPE 376 +#define COND 377 +#define CAST 378 +#define PPTR 379 +#define NEG 380 + + + + +#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) +#line 106 "parser.y" +typedef union YYSTYPE { + attr_t *attr; + expr_t *expr; + type_t *type; + typeref_t *tref; + var_t *var; + func_t *func; + ifref_t *ifref; + class_t *clas; + char *str; + UUID *uuid; + unsigned int num; +} YYSTYPE; +/* Line 1248 of yacc.c. */ +#line 300 "y.tab.h" +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + +extern YYSTYPE yylval; + + + diff --git a/reactos/w32api/include/ddk/kbdmou.h b/reactos/w32api/include/ddk/kbdmou.h index 11c3d80146f..da4c37f51f4 100644 --- a/reactos/w32api/include/ddk/kbdmou.h +++ b/reactos/w32api/include/ddk/kbdmou.h @@ -1,91 +1,91 @@ -/* - * kbdmou.h - * - * Structures and definitions for Keyboard/Mouse class and port drivers. - * - * This file is part of the w32api package. - * - * Contributors: - * Created by Filip Navara <xnavara@volny.cz> - * - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -#ifndef __KBDMOU_H -#define __KBDMOU_H - -#include <ddk/ntddkbd.h> -#include <ddk/ntddmou.h> - -#define DD_KEYBOARD_PORT_DEVICE_NAME "\\Device\\KeyboardPort" -#define DD_KEYBOARD_PORT_DEVICE_NAME_U L"\\Device\\KeyboardPort" -#define DD_KEYBOARD_PORT_BASE_NAME_U L"KeyboardPort" -#define DD_POINTER_PORT_DEVICE_NAME "\\Device\\PointerPort" -#define DD_POINTER_PORT_DEVICE_NAME_U L"\\Device\\PointerPort" -#define DD_POINTER_PORT_BASE_NAME_U L"PointerPort" - -#define DD_KEYBOARD_CLASS_BASE_NAME_U L"KeyboardClass" -#define DD_POINTER_CLASS_BASE_NAME_U L"PointerClass" - -#define DD_KEYBOARD_RESOURCE_CLASS_NAME_U L"Keyboard" -#define DD_POINTER_RESOURCE_CLASS_NAME_U L"Pointer" -#define DD_KEYBOARD_MOUSE_COMBO_RESOURCE_CLASS_NAME_U L"Keyboard/Pointer" - -#define POINTER_PORTS_MAXIMUM 8 -#define KEYBOARD_PORTS_MAXIMUM 8 - -#define KBDMOU_COULD_NOT_SEND_COMMAND 0x0000 -#define KBDMOU_COULD_NOT_SEND_PARAM 0x0001 -#define KBDMOU_NO_RESPONSE 0x0002 -#define KBDMOU_INCORRECT_RESPONSE 0x0004 - -#define I8042_ERROR_VALUE_BASE 1000 -#define INPORT_ERROR_VALUE_BASE 2000 -#define SERIAL_MOUSE_ERROR_VALUE_BASE 3000 - -#define IOCTL_INTERNAL_KEYBOARD_CONNECT \ - CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0080, METHOD_NEITHER, FILE_ANY_ACCESS) - -#define IOCTL_INTERNAL_KEYBOARD_DISCONNECT \ - CTL_CODE(FILE_DEVICE_KEYBOARD,0x0100, METHOD_NEITHER, FILE_ANY_ACCESS) - -#define IOCTL_INTERNAL_KEYBOARD_ENABLE \ - CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0200, METHOD_NEITHER, FILE_ANY_ACCESS) - -#define IOCTL_INTERNAL_KEYBOARD_DISABLE \ - CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0400, METHOD_NEITHER, FILE_ANY_ACCESS) - -#define IOCTL_INTERNAL_MOUSE_CONNECT \ - CTL_CODE(FILE_DEVICE_MOUSE, 0x0080, METHOD_NEITHER, FILE_ANY_ACCESS) - -#define IOCTL_INTERNAL_MOUSE_DISCONNECT \ - CTL_CODE(FILE_DEVICE_MOUSE, 0x0100, METHOD_NEITHER, FILE_ANY_ACCESS) - -#define IOCTL_INTERNAL_MOUSE_ENABLE \ - CTL_CODE(FILE_DEVICE_MOUSE, 0x0200, METHOD_NEITHER, FILE_ANY_ACCESS) - -#define IOCTL_INTERNAL_MOUSE_DISABLE \ - CTL_CODE(FILE_DEVICE_MOUSE, 0x0400, METHOD_NEITHER, FILE_ANY_ACCESS) - -typedef struct _CONNECT_DATA { - PDEVICE_OBJECT ClassDeviceObject; - PVOID ClassService; -} CONNECT_DATA, *PCONNECT_DATA; - -typedef VOID -(STDAPICALLTYPE *PSERVICE_CALLBACK_ROUTINE)( - IN PVOID NormalContext, - IN PVOID SystemArgument1, - IN PVOID SystemArgument2, - IN OUT PVOID SystemArgument3); - -#endif /* __KBDMOU_H */ +/* + * kbdmou.h + * + * Structures and definitions for Keyboard/Mouse class and port drivers. + * + * This file is part of the w32api package. + * + * Contributors: + * Created by Filip Navara <xnavara@volny.cz> + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifndef __KBDMOU_H +#define __KBDMOU_H + +#include <ddk/ntddkbd.h> +#include <ddk/ntddmou.h> + +#define DD_KEYBOARD_PORT_DEVICE_NAME "\\Device\\KeyboardPort" +#define DD_KEYBOARD_PORT_DEVICE_NAME_U L"\\Device\\KeyboardPort" +#define DD_KEYBOARD_PORT_BASE_NAME_U L"KeyboardPort" +#define DD_POINTER_PORT_DEVICE_NAME "\\Device\\PointerPort" +#define DD_POINTER_PORT_DEVICE_NAME_U L"\\Device\\PointerPort" +#define DD_POINTER_PORT_BASE_NAME_U L"PointerPort" + +#define DD_KEYBOARD_CLASS_BASE_NAME_U L"KeyboardClass" +#define DD_POINTER_CLASS_BASE_NAME_U L"PointerClass" + +#define DD_KEYBOARD_RESOURCE_CLASS_NAME_U L"Keyboard" +#define DD_POINTER_RESOURCE_CLASS_NAME_U L"Pointer" +#define DD_KEYBOARD_MOUSE_COMBO_RESOURCE_CLASS_NAME_U L"Keyboard/Pointer" + +#define POINTER_PORTS_MAXIMUM 8 +#define KEYBOARD_PORTS_MAXIMUM 8 + +#define KBDMOU_COULD_NOT_SEND_COMMAND 0x0000 +#define KBDMOU_COULD_NOT_SEND_PARAM 0x0001 +#define KBDMOU_NO_RESPONSE 0x0002 +#define KBDMOU_INCORRECT_RESPONSE 0x0004 + +#define I8042_ERROR_VALUE_BASE 1000 +#define INPORT_ERROR_VALUE_BASE 2000 +#define SERIAL_MOUSE_ERROR_VALUE_BASE 3000 + +#define IOCTL_INTERNAL_KEYBOARD_CONNECT \ + CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0080, METHOD_NEITHER, FILE_ANY_ACCESS) + +#define IOCTL_INTERNAL_KEYBOARD_DISCONNECT \ + CTL_CODE(FILE_DEVICE_KEYBOARD,0x0100, METHOD_NEITHER, FILE_ANY_ACCESS) + +#define IOCTL_INTERNAL_KEYBOARD_ENABLE \ + CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0200, METHOD_NEITHER, FILE_ANY_ACCESS) + +#define IOCTL_INTERNAL_KEYBOARD_DISABLE \ + CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0400, METHOD_NEITHER, FILE_ANY_ACCESS) + +#define IOCTL_INTERNAL_MOUSE_CONNECT \ + CTL_CODE(FILE_DEVICE_MOUSE, 0x0080, METHOD_NEITHER, FILE_ANY_ACCESS) + +#define IOCTL_INTERNAL_MOUSE_DISCONNECT \ + CTL_CODE(FILE_DEVICE_MOUSE, 0x0100, METHOD_NEITHER, FILE_ANY_ACCESS) + +#define IOCTL_INTERNAL_MOUSE_ENABLE \ + CTL_CODE(FILE_DEVICE_MOUSE, 0x0200, METHOD_NEITHER, FILE_ANY_ACCESS) + +#define IOCTL_INTERNAL_MOUSE_DISABLE \ + CTL_CODE(FILE_DEVICE_MOUSE, 0x0400, METHOD_NEITHER, FILE_ANY_ACCESS) + +typedef struct _CONNECT_DATA { + PDEVICE_OBJECT ClassDeviceObject; + PVOID ClassService; +} CONNECT_DATA, *PCONNECT_DATA; + +typedef VOID +(STDAPICALLTYPE *PSERVICE_CALLBACK_ROUTINE)( + IN PVOID NormalContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2, + IN OUT PVOID SystemArgument3); + +#endif /* __KBDMOU_H */ diff --git a/reactos/w32api/include/ddk/ntnls.h b/reactos/w32api/include/ddk/ntnls.h index c7bafb0e20f..1c325db68c9 100644 --- a/reactos/w32api/include/ddk/ntnls.h +++ b/reactos/w32api/include/ddk/ntnls.h @@ -1,52 +1,52 @@ -/* - * ntnls.h - * - * Structures and definitions for NLS data types. - * - * This file is part of the w32api package. - * - * Contributors: - * Created by Alex Ionescu <alex@relsoft.net> - * - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -#ifndef __NTNLS_H -#define __NTNLS_H - -#define MAXIMUM_LEADBYTES 12 - -typedef struct _CPTABLEINFO -{ - USHORT CodePage; - USHORT MaximumCharacterSize; - USHORT DefaultChar; - USHORT UniDefaultChar; - USHORT TransDefaultChar; - USHORT TransUniDefaultChar; - USHORT DBCSCodePage; - UCHAR LeadByte[MAXIMUM_LEADBYTES]; - PUSHORT MultiByteTable; - PVOID WideCharTable; - PUSHORT DBCSRanges; - PUSHORT DBCSOffsets; -} CPTABLEINFO, *PCPTABLEINFO; - -typedef struct _NLSTABLEINFO -{ - CPTABLEINFO OemTableInfo; - CPTABLEINFO AnsiTableInfo; - PUSHORT UpperCaseTable; - PUSHORT LowerCaseTable; -} NLSTABLEINFO, *PNLSTABLEINFO; - -#endif /* __NTNLS_H */ +/* + * ntnls.h + * + * Structures and definitions for NLS data types. + * + * This file is part of the w32api package. + * + * Contributors: + * Created by Alex Ionescu <alex@relsoft.net> + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifndef __NTNLS_H +#define __NTNLS_H + +#define MAXIMUM_LEADBYTES 12 + +typedef struct _CPTABLEINFO +{ + USHORT CodePage; + USHORT MaximumCharacterSize; + USHORT DefaultChar; + USHORT UniDefaultChar; + USHORT TransDefaultChar; + USHORT TransUniDefaultChar; + USHORT DBCSCodePage; + UCHAR LeadByte[MAXIMUM_LEADBYTES]; + PUSHORT MultiByteTable; + PVOID WideCharTable; + PUSHORT DBCSRanges; + PUSHORT DBCSOffsets; +} CPTABLEINFO, *PCPTABLEINFO; + +typedef struct _NLSTABLEINFO +{ + CPTABLEINFO OemTableInfo; + CPTABLEINFO AnsiTableInfo; + PUSHORT UpperCaseTable; + PUSHORT LowerCaseTable; +} NLSTABLEINFO, *PNLSTABLEINFO; + +#endif /* __NTNLS_H */ diff --git a/reactos/w32api/include/evntrace.h b/reactos/w32api/include/evntrace.h index 5a782480c90..08ce3cf00f9 100644 --- a/reactos/w32api/include/evntrace.h +++ b/reactos/w32api/include/evntrace.h @@ -1,43 +1,43 @@ -#ifndef ENVTRACE_H -#define ENVTRACE_H - -typedef struct _EVENT_TRACE_HEADER -{ - USHORT Size; - union { - USHORT FieldTypeFlags; - struct { - UCHAR HeaderType; - UCHAR MarkerFlags; - }; - }; - union { - ULONG Version; - struct { - UCHAR Type; - UCHAR Level; - USHORT Version; - } Class; - }; - ULONG ThreadId; - ULONG ProcessId; - LARGE_INTEGER TimeStamp; - union { - GUID Guid; - ULONGLONG GuidPtr; - }; - union { - struct { - ULONG ClientContext; - ULONG Flags; - }; - struct { - ULONG KernelTime; - ULONG UserTime; - }; - ULONG64 ProcessorTime; - }; -} EVENT_TRACE_HEADER, *PEVENT_TRACE_HEADER; - -#endif /* ENVTRACE_H */ - +#ifndef ENVTRACE_H +#define ENVTRACE_H + +typedef struct _EVENT_TRACE_HEADER +{ + USHORT Size; + union { + USHORT FieldTypeFlags; + struct { + UCHAR HeaderType; + UCHAR MarkerFlags; + }; + }; + union { + ULONG Version; + struct { + UCHAR Type; + UCHAR Level; + USHORT Version; + } Class; + }; + ULONG ThreadId; + ULONG ProcessId; + LARGE_INTEGER TimeStamp; + union { + GUID Guid; + ULONGLONG GuidPtr; + }; + union { + struct { + ULONG ClientContext; + ULONG Flags; + }; + struct { + ULONG KernelTime; + ULONG UserTime; + }; + ULONG64 ProcessorTime; + }; +} EVENT_TRACE_HEADER, *PEVENT_TRACE_HEADER; + +#endif /* ENVTRACE_H */ + diff --git a/reactos/w32api/include/winnls32.h b/reactos/w32api/include/winnls32.h index 83f3df3ef03..685db71715d 100644 --- a/reactos/w32api/include/winnls32.h +++ b/reactos/w32api/include/winnls32.h @@ -1,74 +1,74 @@ -#ifndef _WINNLS32_ -#define _WINNLS32_ - -#if __GNUC__ >=3 -#pragma GCC system_header -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct _tagDATETIME -{ - WORD year; - WORD month; - WORD day; - WORD hour; - WORD min; - WORD sec; -} DATETIME; - -typedef struct _tagIMEPROA -{ - HWND hWnd; - DATETIME InstDate; - UINT wVersion; - BYTE szDescription[50]; - BYTE szName[80]; - BYTE szOptions[30]; -} IMEPROA,*PIMEPROA,NEAR *NPIMEPROA,FAR *LPIMEPROA; - -typedef struct _tagIMEPROW -{ - HWND hWnd; - DATETIME InstDate; - UINT wVersion; - WCHAR szDescription[50]; - WCHAR szName[80]; - WCHAR szOptions[30]; -} IMEPROW,*PIMEPROW,NEAR *NPIMEPROW,FAR *LPIMEPROW; - -#ifdef UNICODE -typedef IMEPROW IMEPRO; -typedef PIMEPROW PIMEPRO; -typedef NPIMEPROW NPIMEPRO; -typedef LPIMEPROW LPIMEPRO; -#define IMPGetIME IMPGetIMEW -#define IMPQueryIME IMPQueryIMEW -#define IMPSetIME IMPSetIMEW -#else -typedef IMEPROA IMEPRO; -typedef PIMEPROA PIMEPRO; -typedef NPIMEPROA NPIMEPRO; -typedef LPIMEPROA LPIMEPRO; -#define IMPGetIME IMPGetIMEA -#define IMPQueryIME IMPQueryIMEA -#define IMPSetIME IMPSetIMEA -#endif - -BOOL WINAPI IMPGetIMEA(HWND, LPIMEPROA); -BOOL WINAPI IMPGetIMEW(HWND, LPIMEPROW); -BOOL WINAPI IMPQueryIMEA(LPIMEPROA); -BOOL WINAPI IMPQueryIMEW(LPIMEPROW); -BOOL WINAPI IMPSetIMEA(HWND, LPIMEPROA); -BOOL WINAPI IMPSetIMEW(HWND, LPIMEPROW); -UINT WINAPI WINNLSGetIMEHotkey(HWND); -BOOL WINAPI WINNLSEnableIME(HWND, BOOL); -BOOL WINAPI WINNLSGetEnableStatus(HWND); - -#ifdef __cplusplus -} -#endif - -#endif /* _USERENV_H */ +#ifndef _WINNLS32_ +#define _WINNLS32_ + +#if __GNUC__ >=3 +#pragma GCC system_header +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _tagDATETIME +{ + WORD year; + WORD month; + WORD day; + WORD hour; + WORD min; + WORD sec; +} DATETIME; + +typedef struct _tagIMEPROA +{ + HWND hWnd; + DATETIME InstDate; + UINT wVersion; + BYTE szDescription[50]; + BYTE szName[80]; + BYTE szOptions[30]; +} IMEPROA,*PIMEPROA,NEAR *NPIMEPROA,FAR *LPIMEPROA; + +typedef struct _tagIMEPROW +{ + HWND hWnd; + DATETIME InstDate; + UINT wVersion; + WCHAR szDescription[50]; + WCHAR szName[80]; + WCHAR szOptions[30]; +} IMEPROW,*PIMEPROW,NEAR *NPIMEPROW,FAR *LPIMEPROW; + +#ifdef UNICODE +typedef IMEPROW IMEPRO; +typedef PIMEPROW PIMEPRO; +typedef NPIMEPROW NPIMEPRO; +typedef LPIMEPROW LPIMEPRO; +#define IMPGetIME IMPGetIMEW +#define IMPQueryIME IMPQueryIMEW +#define IMPSetIME IMPSetIMEW +#else +typedef IMEPROA IMEPRO; +typedef PIMEPROA PIMEPRO; +typedef NPIMEPROA NPIMEPRO; +typedef LPIMEPROA LPIMEPRO; +#define IMPGetIME IMPGetIMEA +#define IMPQueryIME IMPQueryIMEA +#define IMPSetIME IMPSetIMEA +#endif + +BOOL WINAPI IMPGetIMEA(HWND, LPIMEPROA); +BOOL WINAPI IMPGetIMEW(HWND, LPIMEPROW); +BOOL WINAPI IMPQueryIMEA(LPIMEPROA); +BOOL WINAPI IMPQueryIMEW(LPIMEPROW); +BOOL WINAPI IMPSetIMEA(HWND, LPIMEPROA); +BOOL WINAPI IMPSetIMEW(HWND, LPIMEPROW); +UINT WINAPI WINNLSGetIMEHotkey(HWND); +BOOL WINAPI WINNLSEnableIME(HWND, BOOL); +BOOL WINAPI WINNLSGetEnableStatus(HWND); + +#ifdef __cplusplus +} +#endif + +#endif /* _USERENV_H */ -- 2.17.1